pax_global_header00006660000000000000000000000064152202236760014517gustar00rootroot0000000000000052 comment=b2afd88129533997eb3112fe9b8e75e6d9e2b1b4 Solaar-1.1.20/000077500000000000000000000000001522022367600130215ustar00rootroot00000000000000Solaar-1.1.20/.coveragerc000066400000000000000000000004271522022367600151450ustar00rootroot00000000000000[run] branch = True source = hid_parser hidapi keysyms logitech_receiver solaar omit = */tests/* */setup.py */__main__.py [report] exclude_lines = pragma: no cover if __name__ == '__main__': if typing.TYPE_CHECKING fail_under = 40 Solaar-1.1.20/.git-blame-ignore-revs000066400000000000000000000004661522022367600171270ustar00rootroot00000000000000# yapf bulk change 72a8d311bce64b1536c08e754d22bb91efb66460 # isort bulk change e6369e0c3c240715a0a2daede6c3b225ed63cf60 # pre-commit bulk change 33521558ed7007c24b24127f1448c2c23ecbfb35 # flake8 bulk change 627185079f65c9cc471194b7927c833682e4a7a3 # yapf style update 27c90fa736d8a7a1ef6acda4345d3599862e185c Solaar-1.1.20/.github/000077500000000000000000000000001522022367600143615ustar00rootroot00000000000000Solaar-1.1.20/.github/ISSUE_TEMPLATE/000077500000000000000000000000001522022367600165445ustar00rootroot00000000000000Solaar-1.1.20/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000040411522022367600212350ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- **Information** - Solaar version (`solaar --version` or `git describe --tags` if cloned from this repository): - Distribution: - Kernel version (ex. `uname -srmo`): - Output of `solaar show`:
``` SOLAAR SHOW OUTPUT HERE ```
- Contents of `~/.config/solaar/config.yaml` (or `~/.config/solaar/config.json` if `~/.config/solaar/config.yaml` not present):
``` CONTENTS HERE ```
- Errors or warrnings from Solaar: **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Screenshots** If applicable, add screenshots to help explain your problem. **Additional context** Add any other context about the problem here. Solaar-1.1.20/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000017451522022367600223000ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: '' --- **Information** - Solaar version (`solaar --version` and `git describe --tags`): - Distribution: - Kernel version (ex. `uname -srmo`): - Output of `solaar show` for the target device (if applicable):
``` OUTPUT HERE ```
**Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. Solaar-1.1.20/.github/workflows/000077500000000000000000000000001522022367600164165ustar00rootroot00000000000000Solaar-1.1.20/.github/workflows/checks.yml000066400000000000000000000004271522022367600204040ustar00rootroot00000000000000name: checks on: [push, pull_request] jobs: pre-commit: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 - name: Run pre-commit uses: pre-commit/action@v3.0.0 Solaar-1.1.20/.github/workflows/gh-pages.yml000066400000000000000000000017561522022367600206450ustar00rootroot00000000000000name: Deploy to GitHub Pages on: push: branches: - master permissions: contents: read pages: write id-token: write concurrency: group: 'pages' cancel-in-progress: false jobs: build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.x' - name: Install dependencies run: | pip install mkdocs mkdocs-rtd-dropdown mkdocs-mermaid2-plugin mkdocstrings[python] - name: Build and deploy run: | mkdocs build - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: 'site' deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 Solaar-1.1.20/.github/workflows/tests.yml000066400000000000000000000043751522022367600203140ustar00rootroot00000000000000name: tests on: [push, pull_request] jobs: ubuntu-tests: runs-on: ubuntu-latest strategy: matrix: python-version: [3.13] fail-fast: false steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Install Ubuntu dependencies for python 3.8 if: matrix.python-version == '3.8' run: | make install_apt - name: Install Ubuntu dependencies for python 3.13 if: matrix.python-version == '3.13' run: | make install_apt_python3.13 - name: Install Python dependencies run: | make install_pip PIP_ARGS='.["test"]' - name: Run tests on Ubuntu run: | make test - name: Upload coverage to Codecov if: github.ref == 'refs/heads/master' uses: codecov/codecov-action@v4.5.0 with: directory: ./coverage/reports/ env_vars: OS, PYTHON files: ./coverage.xml flags: unittests name: codecov-umbrella token: ${{ secrets.CODECOV_TOKEN }} macos-tests: runs-on: macos-latest strategy: matrix: python-version: [3.13] fail-fast: false steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Set up macOS dependencies run: | make install_brew - name: Add Homebrew's library directory to dyld search path run: | echo "DYLD_FALLBACK_LIBRARY_PATH=$(brew --prefix)/lib:$DYLD_FALLBACK_LIBRARY_PATH" >> $GITHUB_ENV - name: Install Python dependencies run: | make install_pip PIP_ARGS='.["test"]' - name: Run tests on macOS run: | pytest --cov --cov-report=xml - name: Upload coverage to Codecov if: github.ref == 'refs/heads/master' uses: codecov/codecov-action@v4.5.0 with: directory: ./coverage/reports/ env_vars: OS, PYTHON files: ./coverage.xml flags: unittests name: codecov-umbrella token: ${{ secrets.CODECOV_TOKEN }} Solaar-1.1.20/.gitignore000066400000000000000000000004251522022367600150120ustar00rootroot00000000000000*.pyc *.pyo __pycache__/ *.log *.mo /lib/Solaar.egg-info/ /lib/solaar.egg-info/ /lib/solaar/commit /build/ /sdist/ /dist/ /deb_dist/ /MANIFEST .coverage /htmlcov/ /docs/captures/ /share/logitech_icons/ /share/locale/ /po/*.po~ /.idea/ .DS_Store ._* Pipfile Pipfile.lock Solaar-1.1.20/.pre-commit-config.yaml000066400000000000000000000007311522022367600173030ustar00rootroot00000000000000repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 hooks: - id: check-ast - id: check-builtin-literals - id: check-merge-conflict - id: check-yaml - id: check-toml - id: debug-statements - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.2.2 hooks: - id: ruff name: ruff lint args: [--fix, --exit-non-zero-on-fix] - id: ruff-format name: ruff format Solaar-1.1.20/.python-version000066400000000000000000000000051522022367600160210ustar00rootroot000000000000003.11 Solaar-1.1.20/CHANGELOG.md000066400000000000000000001361271522022367600146440ustar00rootroot00000000000000# 1.1.20 * Add Irish translation * Don't use old settings when reusing sboxes * Add POUND and ISO_BACKSLASH cells to MAIN_ISO key layout * Wrap argv in list for Gio.Application.run (PyGObject 3.56) * Mock libnotify to not perform notifications when doing tests * Isolate testing from real configuration file * Update handling of headset RGB controls * Update equalizer processing * Hide read-only paramaters from the UI * Better support for G522 Lightspeed headset * Use mostly full names for direct-USB codenames * Use correct icon for CENTURION devices * rgb_control: honor the off state — don't auto-claim, init, or shutdown LEDs * base: fix sw_id at 0x0B instead of rotating 0x2..0xF (#3218) * perkey/canvas: allow rect/gradient anchors in grid gaps * config_panel: don't show failed-write alert for unreadable settings * listener: share bluez-watch wiring across Centurion-direct and standard device paths * rgb_power.perkey_has_paint: gate on IGNORE only, not on != True * about: add Ken Sanislo to Additional Programming credits * Add RGB lighting persistence and software LED power management for G515 * ui: Show offline status for receiver-paired device batteries (#3217) * LEDControl / RGBControl: render as Gtk.Switch instead of a 2-option combo (#3215) * device: Fix operator precedence bug and end-of-configuration timing in device.changed() (#3173) * PerKeyLighting: drop misleading live-read output in solaar show * perkey: label G502 X LEDs by zone id, not letter * PerKey gradient swatch: align gradient endpoints to visible corners * PerKey gradient swatch: Tabler "square" outline around the gradient * PerKey dialog: one window per device, keyed by firmware unit-id * PerKey dialog: size window from measured natural size * PerKey icons: read theme fg from style-updated, not Settings notify * PerKey canvas: symmetric hash stripes for unset cells * PerKey palette: replace hashed unset swatch with palette-off icon * PerKeyEditor: rebuild tool icons on GTK theme change * PerKeyEditor: replace tool button labels with icons * common: render RGB color values as 0xrrggbb in config and solaar show * Better display of LED effects for some devices in solaar show. * Fix bug affecting using solaar config to change range-based settings. * Add regional keyboard layouts * Use per-key RGB color painter * Fix bug in notification flag handling * Fix bug in HID parser * Update Swedish, German, Polish, Chinese, and French translations * Use battery-level-N icons when available * Document haptic capabilities * Support per-slot unpair on Lightspeed receivers * Fix bugs related to integer flags in older versions of Python * Add mention of Centurion protocol support * Treat empty hidraw read as device removal (EOF) (#3174) * fix interface for K845 * support PRO X 2 LIGHTSPEED headphones Centurion features (#3150) * Fix crash in NotificationFlag.flag_names when flags is None (#3185) * Add PRO X 2 Superstrike mouse support with HITS tuning settings (#3132) * Add names for some HID++ 2.0 features and sort by ID (#3153) * Don't use Logitech for codename * Put lock around getting device name * Fix bug when showing device notification flags * Be defensive about no device features * Add feature x1b04 flag sent by M510 4004 * Remove incorrect descriptor for WPID 4004 * Better handling of missing devices * Improve RHEL installation guide and add automated install example (#3162) * Remove use of XTest and use uinput in all cases * Add installation guide for Solaar on RHEL 10 (#3158) * Use console_scripts entry point for pipx compatibility * Skip Logitech webcams to prevent them from locking up during HID++ checks on Macs * Downgrade ping no such device to informational log entry * Recover from guessing the wrong number for direct-connected HID++ 1.0 devices * Tolerate devices with no unitId * Correctly handle timeout in Bolt discovery * Update or add fr, pt_BR, sk, Ukrainian, Finnish, Bulgarian translations * Handle missing receiver_path more gracefully * Handle inaccessiable devices when determining protocol * Be defensive when showing features in solaar show # 1.1.19 * New Georgian translation * Remove test that doesn't work in older Pythons * Update help messages for CLI commands * Allow solaar config to change LED settings * Add python3-devel to install-dnf in Makefile * hidconsole can send an HID command non-interactively * Add info about new lightspeed receiver * Update Swedish and zh_TW translation * Fix bug when showing details about direct-connected device * Drop testing of Python before 3.13 * Fix crash in solaar show when showing notification flags. (#3070) # 1.1.18 * Fix crash when showing notification flags # 1.1.17 * Add dark icons * Permit onboard profiles version 5 * Update Russian and Polish translations * Add onboard profiles warning to sensitivity tooltip * Better error messages for solaar profile * Remove Solaar name for mice with WPID 4008 * Prevent lock failure when showing debug messages * Replace color picker (#3028) * Add setting for HAPTIC feature * Add setting to adjust force needed for force-sensing buttons * Expand new settings type * Add new settings type for structure-backed setting * Use PATH instead of hardcoded absolute paths (#3014) * Add scroll ratchet force setting * Fix debug messages for MouseClick rule * Improve debug message for rule evaluation * App wrapper and launch agent scripts for MacOS * Ignore hidden features * Don't pop up window in response to ADC changes * Update bug report template * Fixed malformed doc file by adding closing tag * Fix error in low-level request for device with no recevier * Update documentation files # 1.1.16 * Add new flags for reprogrammable keys feature * Correctly handle missing battery feature # 1.1.15 * Correctly re-raise permissions exception * Add several new special keys and tasks * Update several translations * Center labels and remove buggy entry resizing logic * Add shape keys from Key POP Icon * Device and Action rule conditions match on codename and name * Fix listing hidpp10 devices - bytes vs string concatenation (#2856) * Add present flag, unset when internal error occurs, set when notification appears * Pause setting up features when error occurs; use ADC message to signal connection and disconnection * Fix listing of hidpp10 peripherals * Complete DEVICE_FEATURES to DeviceFeature transition for hidpp10 devices * Fix NOTIFICATION_FLAG to NotificationFlag transition leftovers * Fix github workflow stopping all matrix jobs when one of them fails * Fix ubuntu github CI * Update index.md * Python documentation appears to be broken so don't set it up * Improve documentation on onboard profiles * Use correct LOD values for extended adjustable dpi * Better support RGB Effects - not readable * Fix crash when asking for help about config * Fix error when updating ChoiceControlBig box * Add uninstallation docs * Handle unknown power switch locations again * Correctly handle selection of [empty] in rule editor * Handle `HIDError` in `hidapi.hidapi_impl._match()` (#2804) * Give ghost devices a path * Guard against typeerror when setting the value of a control box * Recover from errors in ping * Replace spaces by underscores when looking up features * Rewrote string concatenation/format with f strings * Fix logo not showing in about dialog box * Make typing-extensions dependency mandatory * Properly ignore unsupported locale * hidapi: skip unsupported devices and handle exception on open * Ignore macOS junk files and pipenv config * Fix ui desktop notifications test * hidpp20: Remove dependency to NamedInts * Estimate accurate battery level for some rechargable devices (#2745) * Upgrade desktop notifications tests to take notifications availability into account * Update tests to run on Python 3.13 * Remove outdated logger enabled checks * Introduce GTK signal types * Introduce error types * Remove alias for SupportedFeature * Refactor process_device_notification * Refactor process_receiver_notification * Refactor receiver event handling * Introduce custom logger * Refactor notifications * Rename variable to full name notification * Test notifications * Test extraction of serial and max. devices * Refactor extraction of serial and max. devices * macOS: Fix int.from_bytes, int.to_bytes for show.py * macOS: Remove udev rule warning * macOS: Add support for Bluetooth devices * Add back and forward mouseclick actions * Speedup lookup of known receivers * Refactor device filtering * Reorder private functions and variable definitions * Turn filter_products_of_interest into a public function * Improve tests of known receivers * Refactor: Remove NamedInts and move enums where used * Add docstrings and type hints * Enforce rules on RuleComponentUI subclasses * Simplify settings UI class * Remove diversion alias * Refactor: Convert Kind to IntEnum * Split up huge settings module * Remove Python 2 specific path handling * Delete logging temp file on exit * Update Swedish translation # 1.1.14 * Handle fake feature enums in show * Fix battery entries in config.yaml * Add ratchet setting for smart shift enhanced devices * Refactor Gesture into enum * Replace ERROR NamedInts by IntEnum (#2645) * Refactor hidpp20 to use enum * Update Polish, Swedish, Norwegian Nynorsk (nn), and Norwegian Bokmål (nb) translations * Use IntEnum for firmware and cidgroup constances * Change pairing error values to intenums * Fix initialization bug for PackedRangeControl * Add tests for feature class, process_notification, and key_is_down * Check all bits for extended report rate * Add type hints * Improve about dialog * Reduce dependencies * Refactor code * Improve testing * Allow unknown keys in Key rule conditions * Improve documentation for cli actions * Cycle sw_id to better guard against duplication of messages * Handle error return on root feature * Clean up documentation * Improve github interactions * Add information about Onboard Profiles overriding some settings * Add wording to README.md that Solaar is not a device driver * Clean up imports * Handle unknown device kinds * Fix broken links to Solaar logo * Use mkdocs for public documentation * Clean up setup.py * Remove Dead links in the AppStream file * Update about.py * Remove check on driver * Improve base module * Remove unnecessary receiver info 'hid_driver' * Convert HIDPPNotification to dataclass * Be defensive when converting battery status to string * Automatically detect packages in /lib * Clean up locale code * Improve rules documentation * Refactor creation of devices * Add headings to structure rules.md * Unify imports in logitech package * Don't ping device when getting name or codename * Use dataclasses and enums where useful * Introduce Device protocol and type hints * Add typing_extensions dependency * Move hidpp10 independent functions to module level * Fix macOS compatibility and reenable CI tests * Unify imports in hidapi package * Move screenshots into dedicated folder and add high-level graph of components * Update French and Chinese translations * Drop support for end-of-life Python 3.7 # 1.1.13 * Update Polish and Russian translations. * Fix bug in suspend and resume callback * Add choices universe for backlight setting * Add simplify diversion.py and add unit tests * Get and use current host number for K375sFnSwap because of bug in firmware of MX Keys S * Fix bug with logo in about window * Don't ping device just to get logging information * Optimize write for per-key lighting * Add and initialize per-key lighting to a special no-change value * Remove some Python 2 compatibility code * Update French translation * Refactor rule loading for testability # 1.1.12 * Check for existence of keys file before opening * Perform translation for all translatable strings. * Add included hid_parser to packages installed * Improve label and description for LED zone settings * Add message about Onboard Profiles to LED Zone settings * Initialize device registers to empty list * Use bluez dbus signals to disconnect and connect bluetooth devices * Handle a different signal for onboard profiles directory in ROM * Introduce small delay in getting pairing information to let receiver settle after pairing * Improve testing for settings_templates, settings, hidpp20, and device and fix small bugs found * Add extended adjustable DPI setting * Improve and extend infrastructure for testing setting_templates * Update Greek, Polish, Russian, and Traditional Chinese translations * Implement and test per-key lighting * Refactor and test pair_window in GUI * Handle situation when read of a setting fails in GUI * Permit continuing when a read during pushing fails * Fix bug in LEDZoneSetting when effect is not implemented * Add tests for LEDEffect structures in hidpp20 * Handle BRIGHTNESS_CONTROL notifications * Add settings for BRIGHTNESS_CONTROL and RGB_EFFECTS features * Fix small bugs found from testing in settings * Use f-strings for more exceptions and log message * Tests for setting_templates * Simple change in settings to improve testability * Use feature_request from the device everywhere in hidpp20 * Fix bug in backlight 2 durations * Replace deprecated code constructs * Set up test data and classes to help test HID++ interactions * Use pytest to test code for logitech_receiver modules * Align init methods for all receiver classes * Start refactoring of code base * Allow sub-second delays in Later * Fix bug in setting configuration cookie due to bad documentation * Use ruff for code styling and linting * Upgrade string formating to f-string * Document battery-icons=solaar option * Tell devices to delay device sending first messages until configuration is done * Optimize some functions in FeaturesArray * Fix bug in creating features array * Fix bug in building battery line in show * Refactor diversion_rules * Fix bug in determining tray icon * Fix bug in getting friendly name * Move status information to Device and Receiver objects * Add tests for get_kind_from_index and base product information * Update EX100 documentation * Use object attributes instead of dictionary in status objects * Create subclasses of receiver for different variants * Add requirement for CONFIG_HIDRAW to documentation * Add some low-level tests for some hidpp20 functions, profiles, and lighting and some hidpp10 tests * Fix app name casing in UI * Add missing receiver type for Lightspeed receivers * Add new device types * Refactor device and receiver instantiation * Simplify naming of distribution files * Clean up some logging code * Remove duplicated code to read register * Introduce Hidpp20 and Hidpp10 class * Remove unnecessary calls of del * Fix bug when reading BACKLIGHT setting from device * Replace invalid hidpp10 and hidpp20 usages * Use only timer thread to save config.yaml * Improve README * Copy newer version of hid_parser * Reorder code in settings * Update installation documentation * Add missing license blocks * Clean up listener and notifications code * Add locks to prevent multiple persisters for device * Clean up configuration, device, and receiver code * Move battery constants common to HID++ 1.0 and 2.0 to common * Move mapping of device kind into hidpp20 * Move pairing information gathering to receiver * update contributors * Expand allowable profile numbers * Clean up __init__ in logitech_receiver * Modify pre-commit args to make ruff change files * Fix bug in hidpp20 get host names * Use ruff for formatting and linting * Fix bug in rule Set action * Add notify module to logitech_receiver * Implement setting_changed callback and pass in to new devices and receivers * Add callback to call when changing a setting * Move exceptions, hidpp20 and hidpp10 constants into new modules * Streamline status code * Upgrade debugging in udev * Fix deprecated GitHub actions * Extend makefile and tests * Improve features array * Move ui_async to common.py * Improve module imports * Add tests of common module # 1.1.11 * Rename light icons and install them in correct place * Setup macOS tests using GitHub action (#2284) * Better checking for setting in record_setting * Fix invalid func name set logo name * Simplify installation of udev rules * Add document on implementation * Tidy up scrolling appearance in configuration panel * Correctly handle profile button with no action * Don't unlock setting when changed by external means * Refactor code to record change to setting * Add GitHub action for tests * Introduce tests with pytest * Simplify logger instantiation * Update label and tooltip for divert-gkeys setting * Don't lock setting when an error occurs * Catch assertion errors when reading setting values from devices * Support LED Zone control feature * Dump and load device profiles * Select among profiles. * Support backlight levels and duration * Use "Report Rate" instead of "Polling" for movement report rate * Support extended report rate setting * Add stable branch to release.sh (#2236) * Fix changelog parsing in release.sh * Update installation.md with new udev rules location * Downgrade assertion on missing notification flag to warning * Write empty file if there are no rules to save * Be defensive in device error messages * Add descriptions of M650, PRO X 2, G915, MX Anywhere 2S, G305, and MX Keys S * Report hidraw node in debugging messages * Add names for new Logitech features * Update Spanish, French, and Polish translations * Defend against lightspeed receivers that contact devices for basic information * Remove incorrect feature for M325 mice * Add K845 keyboard * Add partial support for macOS and minimal support for Windows * Correctly enumerate devices on receiver * Add wording in documentation about Logitech reusing model numbers * Better handling and installation of icons * Catch errors when pinging to try to put device online * Be more cautious when creating log messages to avoid exceptions * Correctly handle NoSuchDevice exception when pinging device * Fix test in rules for device equality * Add installation instructions for pipx and add not about other GTK system packages * Fix bug in NamedInt * Add support for MK550 * Install udev rule files to correct placces * Expand expected ping responses * Update codename when device status changes # 1.1.10 * Add information about NixOS flake package * Permit bluetooth devices in hidconsole * Add descriptor for Logitech MX Revolution Mouse M-RCL 124 * Improve determination for short and long messages * Add descriptor for G500s * Fix bug in scan-registers * Add single depress and release options for rule mouse click action * Add rule condition for hostname * Update keysym generation to current list of keysyms * Allow device 0 in hidconsole * Upgrade messages when no supported device found * Documentation update for the gnome extension for better Solaar rule support * Remove udev-acl tag from udev rules * Add support for process condition in Wayland * Update French, Chinese, and German translations * Add G733 Headset * Restore tools/clean.sh * Add Bluetooth Keyboard C714 * Update several device descriptions * Update scan-registers.sh * Remove assertion on last byte of ping responses * Add symbolic version of solaar icon * Fix bug when finding name or codename * Update documentation * Put version in initial INFO logging message # 1.1.9 * Add descriptors for G535 wireless gaming headset and wireless keyboard EX110 * Update Greek translation * Fix minor issues in documentation * Remove some deprecated GTK code * Use zero exit code for kill interrupts * Add rule Test condition for battery charging * Get wpid for 28Mz devices from udev when enumerating * Add Device condition to rules * Don't show wireless link or battery information when unknown or not present * Add desccriptor for G9x and LX7 mice * Fix bug in determining kind of devices for 27Mz receivers * Set initial lock status of smooth scrolling features to ignore * Fix glitch in configuration file update when changing versions * Add more debugging output for rules * Clean up pinging code * Put initial ping of direct-connected devices inside listener thread * Read and check before write of range settings * Improve pairing determination * Cut off determination of receiver devices when all have been found * Remove derived configuration fields when Solaar version changes * Allow device descriptors without name and codename * Filter and escape technical detail fields * Add setting for ADC power managemen * Correctly determine whether to ping with a long HID++ message * Add description for K470 keyboard from the MK470 combo (#1945) * Add setting value for mouse gestures * Update German and French translations * Remove old clean.sh and monitor.py tools * Retry opening device if permissions error encountered * Better handlling of IO errors at device creation * Add KeyIsDown rule condition to check whether a diverted key is down * Clean up device and receiver creation # 1.1.8 * Add parameter to thumb wheel rule conditions * Rename Serbian translation file * Update Polish translation * Improve handling of wheel notifications * Only record changes of scroll wheel ratchet * Don't mark setting as absent if there are device errors * More robust access to keyword exception fields * Add support for config change feature * Clean up GTK code * Update documentation on mouse gestures and known issues * Get commit information from git describe and dpkg-parsechangelog * Update pre-commit tools to current versions * Update installation instructions * Add 8-character commit hash to version information * Update solaar.desktop (#1857) * Get release in setup.py by reading lib/solaar/__init__.py * Remove version number from docs/_config.yml * Update solaar.desktop * Update es.po * Clarify status of C542 receiver * Update devices directory * Add description of several devices * Show name of disconnecting receiver or device in disconnect warning * Reduce standard size of rule editor window * Remove unnecessary dependency on typing_extensions # 1.1.7 * Add dependency on typing_extension to setup.py * Don't defer saves in CLI and don't require Gtk in CLI * Be more permissive in recognizing HID++ report descriptors * Update Polish and Croatian translations * Switch scroll ratcheting in response to scroll ratchet button notification * Add setting to turn scroll ratchet on and off * Eliminate visual glitch when updating range setting * Make hid-parser an optional dependency # 1.1.6 * Only update remaining pairings after successful pairing * Check for presence of status attribute when resuming * Update Polish and Croation translations * Don't add non-existant key in raw xy processing * Add special keys from MX Mechanical Mini * Fix processing of HID++ 1.0 battery reports * Use report descriptors to determine suitable devices * Handle exceptions when processing configuration file * Add Logitech PRO Gaming Keyboard * Fix bad entries in divert-keys when found * Correctly convert old-style diversions to new style and remove old ones * Add optional save argument to write_key_value methods * Use device name in configuration entries if device modelId is zeroes * Don't show normal DJ messages in debug log * Add Later rule action * Correctly record battery feature when ADC produces error * Print feature call errors in solaar show instead of terminating * Use ADC notifications to set device inactive and active * Add one to feature count to count ROOT feature * Don't check modifiers for KeyPress actions that are not clicks * Augment comments on what Solaar cannot do * Fix bug in printing closed handle * Use only product records to determine which receivers unpair * Add conditional delay to get around race with Linux HID++ driver # 1.1.5 * Add G213 Prodigy Gaming Keyboard * Update Turkish, Croation, and zh_CN translations * Move old device descriptions to new locations and clean up * Increase minimum stopped time between mouse movements * Fix bug with non-recognized empty mouse movement * Allow config panel to scroll * Add descriptions for K360 4004, MX Master 4017, Lightspeed C541, and G915 407D * Change security tooltip for unencrypted wireless connections * Add Norwegian Bokmal translation * Update documentation on continuously running GUI, diverted keys, and changing hosts * Solaar config no longer applies settings * Add description of rule components to rule editor * Ignore first movement for mouse gestures when reprog controls version is 5 or more * Add Active rule condition to test whether a device is active * Terminate iteration over receiver devices when all have been found * Downgrade Set prolem messages from error to warning * Log informational messages and above to a temporary file * Don't produce warnings when editing rules in rule editor * Fix bug that didn't save rules file if there were no rules * Allow devices with connection number larger than max_devices * Show more registers in solaar probe * Show feature versions in solaar show * Fix problems with deleting devices on exit * Update German translation * Update device documentation directory * Add descriptors for G502 Proteus Spectrum Optical Mouse and G935 headset * Record feature versions * Add Serbian translation * Fix circular import in rules * Keep track of devices and use in rules * Update zh_CN and zh_TW translations * Convert old-style mouse gestures and sliding dpi settings to new style * Allow multiple keys for mouse gestures and sliding dpi * Defer saving configuration file for a while to cut down on the number if times it is saved * Use correct functions for unified battery and battery voltage features. * Add defensive check for missing keys array in mouse gestures setting * Better presentation of battery information * Add support for ADC MEASUREMENT battery feature * Add information on how to find divertable key names in solaar show output * Better warnings for feature call errors with reprogrammable key and gesture settings * Increase entry size for ChoiceControlBig # 1.1.4 * Update Croatian translation * Handle unanticipated values for persistent remappable action as default * Improve system tray interface documentation * Remove blank lines from system tray popup * Update Polish translation * Add depress and release options to KeyPress rule action * Only close existing devices for receiver * Differentiate debug messages for different setting types * Implement packed range setting in config panel * Only produce warning for unimplemented display of setting * Add sidetone and equalizer settings for headsets * Add packed ranges setting * Use built-ins for conversions between int and byte string * Don't add HI_RES wheel ecodes to evdev device codes * Handle null key in persistent remappable actions when device does not respond * Consult polling rate feature for polling rate * Eliminate extra file handles * Close file handles for receiver-connected devices * Access to more keys in KeyPress rule action when in other keyboard groups * Update Turkish translation * Put battery levels in tray menu labels * Reduce warnings for inaccessible keys in KeyPress rule action * Better determination of keycodes and insert needed shifts in KeyPress actions. * Be careful when processing notifications for partly set up devices. * Clear out fields for empty persistent remappable action. * Fix message generation when device is offline. * Fix bug in feature lookup. * Add support for G533 Headset and G502 Gaming Mouse * Improve device features handling. * Keep trying settings that have worked in the past. * Store None in persisters for non-persisting settings. * Only create configuration entries for off-line devices if they have a serial number. # 1.1.3 * Update documentation files * Lower remove python 3.7 constructs and lower python dependency to 3.6 * Fix bug in xtest mouse scrolling * Allow mouse gesture setting for non-mice, e.g., trackballs * Print message when there is another Solaar process running * Fix determination of whether to force read before writing boolean setting * Add recent diversion features to default list in rules UI * Add setting to divert hires scroll wheel * Don't use device kind to determine how to handle notifications * Update Polish, Russian, and zh_CN translations * Remove pggettext so as to not require Python 3.8 * Remove Python 2 unicode support * Store keys in configuration file as int instead of str * Use yaml for configuration file instead of json. * Remove process-dependent rules from built-in rules. * Handle situation where GTK application cannot be set up in CLI. * Remove obsolete upower signals. * Appinfo/metadata fixes including using correct APP_ID. * Fix bugs in solaar config. * Add full set of mouse buttons in persistent remappable actions setting. * Improve rule behaviour under Wayland and when Xtest or X11 not available. * Fix up and document dependencies (evdev, Python, ...). # 1.1.2 * Update documentation on supported devices and translations * Include evdev as a dependency * Try to use uinput for fake input if XTest extension not available * Add Nano receiver C542 for M190 mice * Broaden range of HID++ Bluetooth devices * Add setting to divert gestures * Rule editor can edit all rule components * Configuration via solaar config takes effect in Solaar UI if it is running * Add setting to disable Onboard Profiles and decouple from Polling Rate setting * Add setting for PERSISTENT_REMAPPABLE_ACTION, common keyboard and mouse cases only * Split Test rule condition into Test and TestBytes and support in rule editor * Fix bug in speed-change setting * Support Backlight3 feature * Ensure that settings are pushed in resume * Update German, Polish, and zh_CN translations * Determine device number for direct-connected devices from protocol * fix bug in add and delete button actions in rule editor * dispose of no-op notifications quickly * add rule condition for checking device settings * use local file for conversion from key names to keysyms * get keyboard group and use to get correct keycodes (X11 only) * improve how rules work under Wayland * add settings for M-Key LEDs and MR-Key LED * fix bug in unpacking M and MR key notification * add G815 keyboard and MX518 mouse * add new special keys for recent keyboards * track M and MR keys for use in rules * make sure that device is online when searching for devices in solaar show * don't check for device kind in dpi sliding setting * fix problem with devices that report 0 DPI * handle missing divert-setting in action RW for settings * add id property (unitId or serial) and don't use ? for unknown serial * fix contains for NamedInts and eliminate use of has_element * check for xtest and disable modifier checking if not available * improve determination of gesture information * add Set rules to rule GUI * add gesture params to Set rules * hide system tray when there are no devices to control * add G733 headset, G9 mouse, G502 Hero mouse * Use greyscale solaar icon in tray when using symbolic icons * Fix bugs in solaar config * Use classes for settings to hep with modularity * Accept '~' and Toggle for toggling boolean settings in cli and rules * handle errors when writing to devices * refactor config_panel.py to use classes for widgets * add rules action to set Solaar settings * decrease amount of logging at each debug level * don't stretch toggles in settings * use key structure for key remapping setting * optimize ReprogrammableKey implementation * keep track of settings that are absent from device * add G512 keyboard and G402 mouse * reformat descriptors.py * use feature numbers for reprogrammable key versions * don't use new_from_icon_set in menu as it is deprecated # 1.1.1 * Keep left pane in Solaar main window the same size * Fix crash when checking a process condition when X11 not running * Add version number to output of solaar show * Fix crash when pinging a device with unknown protocol * Display battery percentage estimates from battery voltage * Add minimal support for Logitech PRO X Wireless Gaming Headset * Push settings when device requests software reconfiguration * Fix read for key/button diversion setting * Add modalias information to Solaar metainfo * Don't do on-screen notifications when devices are powered on * Add setting to switch crown between smooth and ratchet scrolling * Add write_prefix_bytes argument to Boolean validator * Update Russian and Spanish translations * New shell script tools to help determine capabilities of receivers * Add special keys for MX Keys for Business and MX Keys Mini * Improve tray menu ordering * Add --tray-icon-size option to get around bugs in some tray implementations # 1.1.0 * Fix bug when adding receiver to tray menu * Add Catalan translation. * Add toggle command to solaar config to toggle boolean settings * Don't select windows with no PID when looking for focus window * Catch errors when applying settings so that other settings are not affected * Add support for Bolt receivers and devices, including pairing * Revise method for creating system tray menu * Remove obsolete code (mostly Python 2 compatibility code) * Add support for PRO X Wireless Mouse, G914 TKL keyboard * Ignore more notifications that come to a device listener * Handle more device connection protocols * Update usage and rules documentation * Change emojis to text in documentation * Pare down device documentation so as not to require frequent updates * Add information about M500S mouse * Reimplement MOUSE GESTURE and DPI SLIDING settings * Add setting for DPI CHANGE button to switch sensitivity * Use file name instead of icon name for tray to avoid XFCE bug * Update documentation on implemented features and mouse gestures * Update Polish, Japanese, and Spanish translations * Make Quit and About strings more translatable # 1.0.7 * Don't use time_ns so as not to require Python 3.7 * Correctly determine setting box in change_click method * Handle fake Nano connection notifications * Lock on actual handle, not just on handle number * Mark Nano receiver C52F as not unpairing * Upgrade pairing/unpairing documentation * Don't signal status change when battery changes from None to None. * Add Japanese translation * Use first word of name for code name if no other code name available. * Better determination of when to add SW ID. * Check for more HID++ feature request failing. * Fix bug with new_fn_inversion setting. * Use correct device number for directly connected devices * Add debug message when candidate device found * Update Polish, Taiwanese, and Brazilian Portuguese translations * Add MouseProcess a rule condition like Process but for the window under the mouse * Add parameters for binary settings to support prefixes * Add locks to serialize requests to devices * Fix bug when reprog key requests returns None * Fix bug for empty process name and class * Rules can now trigger on both pressing and releasing a diverted key * Upgrade mouse gestures to allow sequences of movements * Fix gkeys diversion faked read * Add support for Logitech g pro x superlight receiver * Convert HID++ 2.0 device kinds to enhanced HID++ 1.0 device kinds * Update about window, bug report templates, and supported kernels. # 1.0.6 * Update sliding DPI to look for suitable keys * Add mouse gestures that can trigger rules * Complain if receivers do not support connection notification * In polling rate setting, only modify onboard profiles when actually writing polling rate * Add ability to ignore settings. * Use symbols for receiver sub-registers * Add support for wired G700 * Do not set attention icon * Replace deprecated GTK stock menu icons * Better handling of icons in tray and tray menus * Receiver c52e does not unpair * Match active WM_CLASS as well as active process name in rules * Correctly set icon theme value when regular battery icons are not available * Handle exception when device is not available when device is being added * Perform initial activation of devices in listener threads * Keep track of serial numbers in the configuration file * Don't update settings for non-active devices * Set the current host name if not stored on the device * Add setting for SMART SHIFT ENHANCED feature * Don't unnecessarily use long messages for HID++ 1.0 commands * Correctly select choices in solaar config and use 1-origin addressing * Add quirk for G915 TKL keyboard because its host mode interferes with its Fn keys * Show command outputs both saved and on-device settings * Update documentation * Fix bug in hidconsole * Update French translation # 1.0.5 * Update documentation on devices forgetting settings. * Improve help messages * Fix bug in finding receiver to pair * Solaar config command can set keyed settings. * Add setting for polling rate * Use long HID++ messages for all 2.0 requests * Update German, Italian, and Polish translations * Solaar config command no longer selects paired but unconnected devices * Show HID++ 1.0 remaining pairings value in solaar show for devices that support it * Add option to not use battery icons in system tray. * Update Polish and Dutch translation. * Add Czech translation. * Remove information on SUSE package as it is very old. * Turn GKEY notifications into Gn key keypresses that can trigger rules. * Push device settings to devices after suspend when device is immediately active. * Reduce unnecessary saving of configuration file. * Better handling of disconnected devices. * Implement GUI to edit rules. * Implement rule-base processing of HID++ feature notifications (depends on X11). * Add settings for diversion of crown and remappable keys. * Access widgets by name instead of by index. * Implement UNIFIED_BATTERY feature and use in battery reports. * Add a clickable lock icon that determines where each setting can be changed. # 1.0.4 * Update pt_BR translation * Support USB and BT connected devices that are not in descriptors.py * Use FRIENDLY NAME for codename if needed and available. * Extract manufacturer and product ID from Udev HID information. * Add Bluetooth and USB product IDs to device descriptors records. * Support Bluetooth-connected devices. * Add model ID and unit ID to device identification. * Support changing DPI by pressing DPI Switch button and sliding horizontally * Add device-specific notification handlers. * Add MX Vertical USB information. * Udev rule adds seat permissions for all Logitech devices. * Support USB-connected devices in GUI. * Make probe and config work for USB-connected devices. * Improve strings and display for settings. * Correctly handle non-unifying connection notifications. * Update GUI strings for several settings. * Better support for EX100 and devices that connect to it. * Partial support for feature GESTURE_2. * Simplify interface for settings. * Use DJ connection notifications to set device active status * Udev rule sets seat write permissions for hidraw nodes for device as well as receivers. * Handle USB devices that use HID++ protocol in CLI. * Use device hidraw nodes where possible. * Handle receivers with serial numbers that don't provide number of pairings. * Ignore exceptions when setting locale. * Correctly discover settings that share a name. * Don't show pop-up notifications at startup. * Keep battery voltage updated in GUI. * Add Portuguese translation. * Update several translations. * Add Lightspeed receivers c545 and c541. * Reimplement REPROG_CONTROLS data structure. # 1.0.3 * Clean up documentation files. * Update documentation on installation. * Update Swedish and French translations. * Add Norwegian Nynorsk and Danish translations. * Fix bug handling DJ pairing notifications. * Add Norwegian Bokmål translation. * Remove deprecated solaar-cli application. * Don't install udev or autostart files from python (or pip). * Solaar needs Python 3.6+ and probably needs kernel 5.2+ * Handle exceptions on dynamic settings when device is not connected. * Fix infinite loop on some low-level write errors * Add support for EX100 keyboard/mouse and receiver (046d:c517) * Add two settings for THUMB_WHEEL feature - inversion and reporting via HID++ * Update German translation * Use REPORT RATE feature when available to determine polling rate. * Improve config command speed when not printing all settings * Improve config command handling and checking of arguments * Add setting for CHANGE_HOST feature * Add argument to settings for values that are not to persist * Add argument to settings to not wait for reply when writing a value to device * Add argument to not wait for reply from request to device * Add settings for MULTIPLATFORM and DUALPLATFORM features * Remove Logitech documents from documentation directory * Change config command to not read all settings when only printing or showing one * Display hosts info in 'solaar show' if device supports it * Remove non-working smooth-scroll from M510 v1 * Add yapf and flake8 code style checks * Fix feature k375s Fn inversion * Update controls (keys and buttons) and tasks (actions) * Improved way to specify feature settings. * Don't abort on device notifications with unexpected device numbers, just warn. * Keep track of non-features so as not to ask device multiple times. * Implement KEYBOARD DISABLE KEYS feature. * Don't create notifications for DJ device activity reports. * Update a few special keys and actions. * Add keyed choice settings in configuration panel. * Support remappable keys from reprogrammable keys v4 feature. * Add setting class for keyed choice. * Only check for features once per device. * Use settings interface to show feature values in `solaar show` if no special code for feature. * Remove maximum window size. * Process battery voltage notifications. * Display battery voltage information in main window if regular battery information not available. * Show next battery level where available. * Update list of implemented features and provide information on how to implement features. * Add c53d as a Lightspeed receiver. # 1.0.2 * Add usage document * Don't produce error dialog for inaccessible receivers with access control lists. * Add option --battery-icons=symbolic to use symbolic icons if available. * Update French translation * Update installation documentation * Remove packaging directory tree as it is not maintained * Pip installs udev rule and solaar autostart when doing install without --user flag * Use Solaar icon instead of a missing battery icon * Use only standard icons for battery levels. Symbolic icons do not change to white in dark themes because of problems external to Solaar. * Better reporting of battery levels when charging for some devices. * Add information on K600 TV, M350 WIPD 4080, and MX Keys * Remove assertion requiring receivers to still be in window when they are updated. * Augment long description of Solaar showing up in repositories. * Update installation directions. * Install udev rule as well as autostart file when doing system install. * Add support for Ayatana AppIndicator. * Use setuptools icon directory on system installs when not using pip. * Add receiver C517 and several older devices. * Improved translations for polish. * Bypass bug in appindicator when solaar is file in current directory. * Don't check that device kind matches feature kind. * Better determination of icons for battery levels. * Use Ayatana AppIndicator if available. * Improve error reporting when required system packages are not install. * Better tooltip description * Add release script to help when creating releases * Look up tray icon filenames to get around a bug in libappindicator. * Make the default behavior be to show the main window at startup. * Support c537 nano receiver * Add logind signals for suspend/resume. * Remove solaar-gnome3 package * Ignore features for devices that don't follow feature specification * Add probe command to command-line interface to dump receiver registers * Don't terminate on malformed or unknown messages * Create fewer internal notifications for messages from devices * Add a button to the main window to terminate (quit) Solaar * Set up nano receivers as receivers with no unpairing and with re-pairing * Set up c534 as receiver with max 2 pairings, no unpairing, re-pairing * Better support receivers that do not unpair or when pairing replace existing pairings * Add information about receiver pairing to receiver data structure * Better support devices that only allow a limited number of total re-pairings * Add --window option to control main window visibility and tray usage * Ignore receiver if USB id is not retrieved * Fix bug with double deleting when devices are disconnected * Determine some receiver information from data structure for USB ids * Treat battery level of 0 as unknown * Fix bug on devices with no serial number * Drop support for python2, and use python3 throughout * Fix bug in remembering features discovered from device reports * Show icons in main window device list * Count offline devices when determining whether pairing is possible * Update French, Dutch, German, and Croatian translations * Better icons for battery levels * Support DPI, Backlight 2, Battery Voltage features * Support M585, M590, M330, MX Master 2s and 3, new M310, new K800, craft keyboard * Documentation improvements * Clean up directory structure and remove unused files # 1.0.1 * Updated the repo url. * Fixed typo which was crashing the application. * Improved the HID write routine which was causing issues on some devices. * Fix non-unifying receivers in Linux 5.2. * Add new Lightspeed receiver (used in the G305) # 1.0.0 * Too many to track... # 0.9.3 * Merged solaar-cli functionality into main solaar. * Scrolling over the systray icon switches between multiple peripherals. * Swedish translation courtesy of Daniel Zippert and Emelie Snecker * French translation courtesy of Papoteur, David Geiger and Damien Lallement. * Fixed some untranslated strings. # 0.9.2 * Added support for hand detection on the K800. * Added support for V550 and V450 Nano. * Fixed side-scrolling with the M705 Marathon. * Fixed identification of the T650 Touchpad. * Added internationalization support and romanian translation. * Polish translation courtesy of Adrian Piotrowicz. # 0.9.1 * When devices report a battery alert, only show the alert once. * Make sure devices in the window tree are sorted by registration index. * Added an autostart .desktop file. * Replaced single-instance code with GtkApplication. * Fixed identification of the M505 mouse. * Fixed an occasional windowing layout bug with the C52F Nano Receiver. # 0.9.0 * New single-window UI. * Performance MX leds show the current battery charge. * Support the VX Nano mouse. * Faster and more accurate detection of devices. * If upower is accessible through DBus, handle suspend/resume. * Replaced Solaar icons with SVGs. * Running solaar-cli in parallel with solaar is now less likely to cause issues. * Bugfixes to saving and applying device settings. * Properly handle ^C when running in console. # 0.8.9 * Improved support for gnome-shell/Unity. * Persist devices settings between runs. * Fixed reading of MK700 keyboard battery status. * Use battery icons from the current theme instead of custom ones. * Debian/Ubuntu packages now depend on an icon theme, to make sure no missing icons appear in the application window. * Fixed missing icons under Kubuntu. * Many more bug-fixes and reliability improvements. # 0.8.8 * Partial support for some Nano receivers. * Improved support for some devices: M510, K800, Performance MX. * Improved battery support for some HID++ 1.0 devices. * Properly handle device loss on computer sleep/wake. * Better handling of receiver adding and removal at runtime. * Removed a few more unhelpful notifications. * Incipient support for multiple connected receivers. * More Python 3 fixes. # 0.8.7 * Don't show the "device disconnected" notification, it can be annoying and not very useful. * More robust detection of systray icon visibility. # 0.8.6 * Ensure the Gtk application is single-instance. * Fix identifying available dpi values. * Fixed locating application icons when installed in a custom prefix. * Fixed some icon names for the oxygen theme. * Python 3 fixes. Solaar-1.1.20/COPYRIGHT000066400000000000000000000012101522022367600143060ustar00rootroot00000000000000Copyright 2012, 2013 Daniel Pavel This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Solaar-1.1.20/LICENSE.txt000066400000000000000000000432541522022367600146540ustar00rootroot00000000000000 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. Solaar-1.1.20/MANIFEST.in000066400000000000000000000002271522022367600145600ustar00rootroot00000000000000include COPYRIGHT LICENSE.txt README.md CHANGELOG.md lib/solaar/version lib/solaar/commit recursive-include rules.d * recursive-include share/locale * Solaar-1.1.20/Makefile000066400000000000000000000040461522022367600144650ustar00rootroot00000000000000UDEV_RULE_FILE = 42-logitech-unify-permissions.rules UDEV_RULES_SOURCE := rules.d/$(UDEV_RULE_FILE) UDEV_RULES_SOURCE_UINPUT := rules.d-uinput/$(UDEV_RULE_FILE) UDEV_RULES_DEST := /etc/udev/rules.d/ PIP_ARGS ?= . .PHONY: install_ubuntu install_macos .PHONY: install_apt install_brew install_pip .PHONY: install_udev install_udev_uinput reload_udev uninstall_udev .PHONY: format lint test install_ubuntu: install_apt install_udev_uinput install_pip install_macos: install_brew install_pip install_apt: @echo "Installing Solaar dependencies via apt" sudo apt update sudo apt install libdbus-1-dev libglib2.0-dev libgtk-3-dev libgirepository1.0-dev install_apt_python3.13: @echo "Installing Solaar dependencies via apt" sudo apt update sudo apt install libdbus-1-dev libglib2.0-dev libgtk-3-dev libgirepository-2.0-dev gobject-introspection install_dnf: @echo "Installing Solaar dependencies via dnf" sudo dnf install gtk3 python3-devel python3-gobject python3-dbus python3-pyudev python3-psutil python3-xlib python3-yaml install_brew: @echo "Installing Solaar dependencies via brew" brew update brew install hidapi gtk+3 pygobject3 gobject-introspection install_pip: @echo "Installing Solaar via pip" python -m pip install --upgrade pip pip install $(PIP_ARGS) install_pipx: @echo "Installing Solaar via pipx" pipx install --system-site-packages $(PIP_ARGS) install_udev: @echo "Copying Solaar udev rule to $(UDEV_RULES_DEST)" sudo cp $(UDEV_RULES_SOURCE) $(UDEV_RULES_DEST) make reload_udev install_udev_uinput: @echo "Copying Solaar udev rule (uinput) to $(UDEV_RULES_DEST)" sudo cp $(UDEV_RULES_SOURCE_UINPUT) $(UDEV_RULES_DEST) make reload_udev reload_udev: @echo "Reloading udev rules" sudo udevadm control --reload-rules uninstall_udev: @echo "Removing Solaar udev rules from $(UDEV_RULES_DEST)" sudo rm -f $(UDEV_RULES_DEST)/$(UDEV_RULE_FILE) make reload_udev format: @echo "Formatting Solaar code" ruff format . lint: @echo "Linting Solaar code" ruff check . --fix test: @echo "Running Solaar tests" pytest --cov --cov-report=xml Solaar-1.1.20/README.md000066400000000000000000000063231522022367600143040ustar00rootroot00000000000000# Solaar Solaar is a Linux manager for many Logitech keyboards, mice, and other devices that connect wirelessly to a Unifying, Bolt, Lightspeed or Nano receiver as well as many Logitech devices that connect via a USB cable or Bluetooth. Solaar is not a device driver and responds only to special messages from devices that are otherwise ignored by the Linux input system. More Information - Usage - Capabilities - Rules - Manual Installation - Known Issues [![codecov](https://codecov.io/gh/pwr-Solaar/Solaar/graph/badge.svg?token=D7YWFEWID6)](https://codecov.io/gh/pwr-Solaar/Solaar) [![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2+-blue.svg)](../LICENSE.txt)

 

 

Solaar supports: - pairing/unpairing of devices with receivers - configuring device settings - custom button configuration - running rules in response to special messages from devices For more information see the main Solaar documentation page. - ## Installation Packages Up-to-date prebuilt packages are available for some Linux distros (e.g., Fedora) in their standard repositories. If a recent version of Solaar is not available from the standard repositories for your distribution, you can try one of these packages: - Arch solaar package in the [extra repository][arch] - Ubuntu/Kubuntu package in [Solaar stable ppa][ppa stable] - NixOS Flake package in [Svenum/Solaar-Flake][nix flake] Solaar is available from some other repositories but may be several versions behind the current version: - a [Debian package][debian], courtesy of Stephen Kitt - a Ubuntu package is available from [universe repository][ubuntu universe repository] - a [Gentoo package][gentoo], courtesy of Carlos Silva and Tim Harder - a [Mageia package][mageia], courtesy of David Geiger [ppa stable]: https://launchpad.net/~solaar-unifying/+archive/ubuntu/stable [arch]: https://www.archlinux.org/packages/extra/any/solaar/ [gentoo]: https://packages.gentoo.org/packages/app-misc/solaar [mageia]: http://mageia.madb.org/package/show/release/cauldron/application/0/name/solaar [ubuntu universe repository]: http://packages.ubuntu.com/search?keywords=solaar&searchon=names&suite=all§ion=all [nix flake]: https://github.com/Svenum/Solaar-Flake [debian]: https://packages.debian.org/search?keywords=solaar&searchon=names&suite=all§ion=all Solaar-1.1.20/RELEASE.md000066400000000000000000000012311522022367600144200ustar00rootroot00000000000000# Solaar releases ## Please read before making a release We support two type of releases: normal releases (ex. `1.0.0`) and release candidates (ex. `1.0.0rc1`). Release candidates must have a `rcX` suffix. Release routine: - Update version in `lib/solaar/version` - Add release changes to `CHANGELOG.md` - Add release information to `share/solaar/io.github.pwr_solaar.solaar.metainfo.xml` - Create a commit that starts with `release VERSION` - Push commit to Solaar repository and merge it - Invoke `./release.sh` - Git tags are signed so you must have GPG set up - You are required to have a github token with `public_repo` access in `~/.github-token` Solaar-1.1.20/RHEL.md000066400000000000000000000052631522022367600141030ustar00rootroot00000000000000# Solaar installation guide for RHEL, Rocky, AlmaLinux, and CentOS Stream This guide covers manual installation and an automated install example for RHEL-family systems using `dnf`. ## Supported distributions - Red Hat Enterprise Linux (RHEL) - Rocky Linux - AlmaLinux - Oracle Linux - CentOS Stream The commands assume a minimal CLI system with `sudo` access. ## 1) Install dependencies ```bash sudo dnf makecache --refresh sudo dnf install -y \ git \ gtk3 \ python3 \ python3-devel \ python3-dbus \ python3-gobject \ python3-pip \ python3-psutil \ python3-pyudev \ python3-setuptools \ python3-xlib \ python3-yaml ``` Optional troubleshooting helpers: ```bash sudo dnf install -y \ evemu \ libinput \ usbutils ``` ## 2) Clone Solaar ```bash git clone https://github.com/pwr-Solaar/Solaar.git cd Solaar ``` ## 3) Install Solaar Install for the current user: ```bash python3 -m pip install --user . ``` Or install system-wide: ```bash sudo python3 -m pip install . ``` ## 4) Install udev rules Install the recommended `uinput` rule: ```bash sudo make install_udev_uinput ``` Verify rule installation: ```bash ls -l /etc/udev/rules.d/42-logitech-unify-permissions.rules ``` Rollback udev rule installation: ```bash sudo make uninstall_udev ``` ## 5) Run Solaar ```bash solaar ``` or: ```bash python3 -m solaar ``` ## 6) Automated install options Use the guided installer in this repository: ```bash ./tools/install-rhel.sh ``` Minimal non-interactive example script: ```bash cat > install-rhel-solaar.sh <<'SCRIPT' #!/usr/bin/env bash set -euo pipefail if [[ "${EUID}" -eq 0 ]]; then echo "Run as a regular user with sudo access, not as root." exit 1 fi sudo dnf makecache --refresh sudo dnf install -y \ git \ gtk3 \ python3 \ python3-devel \ python3-dbus \ python3-gobject \ python3-pip \ python3-psutil \ python3-pyudev \ python3-setuptools \ python3-xlib \ python3-yaml if [[ ! -d Solaar/.git ]]; then git clone https://github.com/pwr-Solaar/Solaar.git fi cd Solaar python3 -m pip install --user . sudo make install_udev_uinput ~/.local/bin/solaar --version SCRIPT chmod +x install-rhel-solaar.sh ./install-rhel-solaar.sh ``` ## 7) Verification ```bash command -v solaar solaar --version python3 -m pip show solaar ``` If installed with `--user`, ensure `~/.local/bin` is on your `PATH`: ```bash echo "$PATH" | tr ':' '\n' | grep -Fx "$HOME/.local/bin" >/dev/null || \ echo 'Add ~/.local/bin to PATH' ``` ## 8) Troubleshooting Receiver not detected: ```bash lsusb | grep -Ei 'logitech|046d' sudo udevadm trigger ``` Check access to hidraw devices: ```bash ls -l /dev/hidraw* getfacl /dev/hidraw* 2>/dev/null | sed -n '1,80p' ``` Solaar-1.1.20/Release_Notes.md000066400000000000000000000265731522022367600161100ustar00rootroot00000000000000# Notes on Major Changes in Releases ## Version 1.1.20 * Solaar has much better support for the LEDs on some newer devices, such as the G515 Lightspeed TKL. * Solaar now supports the Centurion protocol, a variation of the HIDP++ protocol that is used by several headsets. * Solaar now uses uinput for all simulated input, even in X11. As a result there is no need for a separate udev rule for Wayland, and it may be removed in future. ## Version 1.1.18 * Solaar is only guaranteed to work in Python 3.13 or later. ## Version 1.1.17 * Several new features have been added related to the MX Master 4 * The scroll ratchet force can be adjusted * The force required to click the button under your thumb can be adjusted * The haptic force can be adjusted * Haptic feeback can be triggered by commands like `solaar config 'mx master 4' haptic-play 'HAPPY ALER'` ## Version 1.1.16 * Two bugs that were affecting users in 1.1.15 are fixed. ## Version 1.1.15 * Some key names have been changed to match Logitech names. Rules that use removed names will no longer work and will end up with a key of 0. * Device and Action rule conditions match on device codename and name * Solaar supports configuration of Bluetooth devices on macOS. ## Version 1.1.13 * Solaar will drop support for Python 3.7 immediately after version 1.1.13. * Version 1.1.12 does not push settings to many devices after a resume resulting in the device reverting to its default behaviour. This is fixed in 1.1.13. ## Version 1.1.12 * Solaar now processes DBus disconnection and connection messages from Bluez and re-initializes devices when they reconnect, to handle to a change introduced in Bluez 5.73. The HID++ driver does not re-initialize devices, which causes problems with smooth scrolling. Until the issue is resolved having Scroll Wheel Resolution set to true (and not ignored) may be helpful. * The credits for translations have not been kept up to date. Translators who are not listed can update docs/i18n.ml and lib/solaar/ui/about.py. * Solaar now has settings for features BRIGHTNESS_CONTROL, RGB_EFFECTS, and PER_KEY_LIGHTING features. The names of keys in the Per-key Lighting setting are for the standard US keyboard. Users who wish to modify these names should look at the section Keyboard Key Names and Locations in `https://pwr-solaar.github.io/Solaar/capabilities` * A unit test test suite is being constructed using pytest. * The Solaar code for communicating with receivers and devices has been significantly modified to improve testability and organization. Errors may have been introduced for uncommon hardware. * The Later rule action uses precision timing for delays of less than one second. * Solaar now indentifies supported devices by whether they support the HID protocols that Solaar needs. If a device does not show up at all when running Solaar, it almost certainly cannot be supported by Solaar. ## Version 1.1.11 * Solaar can dump device profiles in YAMLfor devices that support profiles and load profiles back from an edited file. See [the capabilities page](https://pwr-solaar.github.io/Solaar/capabilities) for more information. * Solaar has settings for each LED Zone that a device supports under feature Color LED Effects. * Solaar has settings for extended report rate, backlight levels, durations, and profile selection. * Solaar now partly works in MacOS. Please open new issues for problems. Solaar may work in Windows. Please open new issues for problems. See https://github.com/pwr-Solaar/Solaar/pull/1971 for more information. Fixing problems in MacOS or Windows may take considerable time. * Solaar works better when the Python package hid-parser is available. Distriubtions should try have this package installed. ## Version 1.1.10 * The mouse click rule action can now just simulate depressing or releasing the button. * There is a new rule condition to check the hostname. ## Version 1.1.9 * Solaar now exits with at 0 exit code when killed. * Two Solaar settings can interfere with the implementation of smooth scrolling in modern Linux HID++ drivers. These settings are initially set to ignore so that this interference does not happen. * The Device rule condition checks for the device that produced a notification. * The KeyIsDown rule condition checks whether a *diverted* rule key is down. ## Version 1.1.8 * The thumb wheel rule conditions take an optional parameter that checks for total signed thumb wheel movement. ## Version 1.1.7 * Solaar responds to scroll wheel ratchet notifications by changing its scroll wheel ratcheting. * Solaar processing of report descriptors is optional, depending on whether the package hid-parser is available. ## Version 1.1.6 * Solaar requires Python version 3.7. * Solaar uses report descriptors to recognize unknown devices that use HID++. * The Later rule action takes an integer delay in seconds and one or more rule components. The action immediately completes while also scheduling the rule components for later exection. ## Version 1.1.5 * The Active rule condition takes the serial number or unitID of a device and checks whether the device is active. A device is active if it is connected (via a receiver, USB or Bluetooth), not turned off, and not in a power-saving state. This condition can be used to check whether changing a setting on the device will have any effect, as devices respond to messages only when active. * Solaar logs warnings and errors to a file in the user's temporary file directory. This file is deleted when Solaar exists normally. If Solaar is run with `-dd` or `-ddd` informational messages are also logged in the file. * If the first element of a Mouse Gesture rule condition is a key or button name then that name must be the same as the name of the key or button that initiated the mouse gesture. * The Sliding DPI and Mouse Gestures are now set up using the Key/Button Diversion setting. Changing a key or button to Sliding DPI makes it initiate the sliding DPI changing. Changing a key or button to Mouse Gestures makes it initiate a mouse gesture. There can be multiple keys or buttons for sliding DPI and multiple keys or buttons for mouse gestures. * Solaar waits a few seconds to save settings changes to its configuration file. If you interrupt Solaar soon after changing a setting the change might not be saved. ## Version 1.1.4 * There are settings for sidetone and equalizer gains for headsets. * The KeyPress action can now either deppress, release, or click (default) keys. * The KeyPress action now inserts shift and level 3 keypresses if simulating a key symbol requires one or both of them. So producing a "B" no longer requires adding a shift keysymbol. ## Version 1.1.3 * Solaar uses yaml for configuration files, converting the json configuration file to yaml if necessary. * Solaar rules work better under Wayland but still cannot access the current process nor the current keyboard modifiers. * Solaar uses uinput for simulating input in Wayland. See https://pwr-solaar.github.io/Solaar/rules for instructions on setting up uinput correctly. ## Version 1.1.2 * Solaar now depends on Python evdev. It can be installed if needed via `pip install --user evdev` or, in most distributions, by installing the python3-evdev package. * Solaar rules partly work under Wayland. There is no access to the current process in Wayland. Simulated input uses uinput if XTest extension not available, requiring read and write permissions on /dev/uinput. * There is a setting to divert gestures so that they can trigger rules. * There is a setting to disable Onboard Profiles, which can interfere with the Polling Rate and M-Key LEDs settings. The Polling Rate setting no longer disables onboard profiles. * There is a setting for the Persistent Remappable Keys feature. * There is a new rule condition that tests device settings. * There are new settings to set M-Key LEDs and MR-Key LED. * There is a new kind of Solaar rule action to change settings for devices. ## Version 1.1.1 * There is a new setting to switch keyboard crowns between smooth and ratchet scrolling. ## Version 1.1.0 * Solaar now supports Bolt receivers and devices that connect to them, including authentication of devices when pairing. * A setting has been added for the DPI CHANGE button to switch movement sensitivity. ## Version 1.0.7 * Solaar rules can now trigger on both pressing and releasing a diverted key. * The new rule condition MouseProcess is like the Process condition except for the process of the window under the mouse. * Mouse gestures have been upgraded. A mouse gesture is now a sequence of movements separated by no movement periods while the mouse gesture button is held down. The MouseGesture rule condition matches mouse gesture sequences. The old mouse-up, etc., tests are converted to MouseGesture conditions. ## Version 1.0.6 * The sliding DPI setting now looks for suitable keys to use to trigger its effects. * If a mouse has a suitable button it can generate mouse gestures, which trigger rule processing. Mouse gestures need to be turned on and the button diverted to produce mouse gestures. * Settings can now be ignored by clicking on the icon at the right-hand edge of a setting until the dialog error icon (usually a red icon) appears. Solaar will not try to restore the value for an ignored setting. * Icon handling in the tray and the tray menu has been updated to work better with some system tray implementations. * The process rule condition also matches against the current X11 WM_CLASS. * The SMART SHIFT ENHANCED feature is supported. ## Version 1.0.5 * Solaar has rules that can perform actions such as pressing keys or scrolling when certain HID++ feature notifications happen. Users can change these rules either by editing ~/.config/solaar/rules.yaml or via a GUI. Rules depend on X11 and so are only available under X11. This is an experimental feature for Solaar and may undergo changes in the future. * Each setting has a clickable lock icon that determines whether the setting can be changed. ## Version 1.0.4 * Devices that connect directly via Bluetooth or USB are now supported. These devices show up in the GUI as separate lines, not under a receiver. A device that is directly connected and also paired to a receiver will show up twice, but the entry under the receiver will not be active. With this change identifying devices becomes more difficult so occasionally check your Solaar configuration file (at ~/.config/solaar/config.json) to see that there is only one entry for each of your devices. * There are new settings for gestures, thumb wheels, adjusting the wheel ratchet behavior, and changing DPI using a DPI Switch button. * Solaar's Udev rule now adds seat permissions for all Logitech devices. Users who install Solaar themselves will have to install the new Udev rule and activate the rule. One way to do this is to restart the user's computer. ## Version 1.0.3 * The separate deprecated solaar-cli command has been removed. * Devices can be switched between hosts using the Change Host setting. The device will try to connect to the other host. Some devices will detect that there is no active host on the other connections and reconnect back. ## Version 1.0.2 * The separate unneeded solaar-gnome3 command has been removed. The packaging directories have been removed. * Non-unifying receivers are modelled better. Many of them cannot unpair but instead new pairings replace existing pairings. * Battery icon selection has been simplified. Solaar-1.1.20/bin/000077500000000000000000000000001522022367600135715ustar00rootroot00000000000000Solaar-1.1.20/bin/solaar000077500000000000000000000026161522022367600150050ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- python-mode -*- # -*- coding: UTF-8 -*- ## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. def init_paths(): """Make the app work in the source tree.""" import os.path import sys root = os.path.join(os.path.realpath(sys.path[0]), "..") prefix = os.path.normpath(root) src_lib = os.path.join(prefix, "lib") share_lib = os.path.join(prefix, "share", "solaar", "lib") for location in src_lib, share_lib: init_py = os.path.join(location, "solaar", "__init__.py") if os.path.exists(init_py): sys.path[0] = location break if __name__ == "__main__": init_paths() import solaar.gtk solaar.gtk.main() Solaar-1.1.20/docs/000077500000000000000000000000001522022367600137515ustar00rootroot00000000000000Solaar-1.1.20/docs/.gitignore000066400000000000000000000001241522022367600157360ustar00rootroot00000000000000# ignore documentation-specific files .jekyll-metadata Gemfile Gemfile.lock _site/ Solaar-1.1.20/docs/20121210110342697.pdf000066400000000000000000005320701522022367600162640ustar00rootroot00000000000000%PDF-1.4 %âãÏÓ 4 0 obj <> stream ÿØÿàJFIF,,ÿÛC 2!=,.$2I@LKG@FEPZsbPUmVEFdˆemw{�‚�N`�—Œ}–s~�|ÿÛC;!!;|SFS||||||||||||||||||||||||||||||||||||||||||||||||||ÿÀÔ °"ÿÄ ÿĵ}!1AQa"q2�‘¡#B±ÁRÑð$3br‚ %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyzƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚáâãäåæçèéêñòóôõö÷øùúÿÄ ÿĵw!1AQaq"2�B‘¡±Á #3RðbrÑ $4á%ñ&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz‚ƒ„…†‡ˆ‰Š’“”•–—˜™š¢£¤¥¦§¨©ª²³´µ¶·¸¹ºÂÃÄÅÆÇÈÉÊÒÓÔÕÖרÙÚâãäåæçèéêòóôõö÷øùúÿÚ ?Ûð¢� [`s—Éÿ�šØ¬� ÈèÏÿ¡š× Š( Š( Š( Š( Š( Š( “´PEPEPEPEPEPc=hÅ-˜¥¢Š(¢Š(¢Š1EPEPEPEPEPEP`QŠZ(¢Š(¢Š(¢Š(¢Š(¤¥¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€€  KE&)h¤P@Á ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¤Àô¥¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€�KEQEQEQEQEQEQEQEQE&¥¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ÅPEPEPEPEPEPEPEPEPEPEPúÒÑEQEQEQEQEQEQERw¥ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( À¥¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)1KEQE˜¥¢€b–ŠLQŠZ(0=(À¥¢€Œ Z(6¯ ¤Ø¿Ý•:ŠM v`zRÑ@ اøGåFÅþèü©ÔPmƒò£ÐRÑ@)0=)h  Ÿ h±{¼Ÿú­jÉðÏü�£ÿ®’èfµ¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(+Ãc<~ï!ÿÇÍjÖW†ÿäýt“ÿC5«@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@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@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@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@Q@Q@~ÿ�DïÉÿ¡šÔ¬ÏÿÈvý «N€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¤ ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(/ßò‹ýù?ô6­JËðçü�âöy?ô6­J(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢›´“’xô QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE—á±�#êòü}«R²ü9ÿ XÞ“ÿCjÔ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  ¿ ÿÈ÷äÿÐÚµ++Ã_ò‹ýù?ô6­Z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠEÎÑ»“ß´Q@‡88ëH›¶üøÝíÒ€EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPW†¿ä ûòcþûjÕ¬Ÿ Ÿø“F=Aÿ�šÖ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š)¬áH½:Š( Š( Š( Š( Š( Š( Š)¨›Iç­:Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ŠL“Ž´½h¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢’–€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€2|21£¡õ’Cÿ�šÖ¬Ÿ çûa$€ßfµ¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¤Ü À#5RîgóŽ êGQSAˆuÉ ·F욊k’‘Ö™³©ßÔ ¶—%¢�œ žÕ”¸;N”W&ª÷Ùû9eê¼Ôëœ õïQܰ9a‘Ž”:Iâ½Ý–rqЏ¹* àÖ^ž¡î9šÔ'&„iV*2²Š­ìrMå¨?Z³A“‹ŽáEFÒ�÷~cU^öH¥EÂý(*0rؽE €GCU§œÅ*ó�O"�F.NȵEPHQETfdˆÉù�j’³nÆÛÕo¥”â¤ìiQERŽâI.Ê'ò¹\»EV[À’lE.J1rصEU{™WþX¶=h·¼YŸa=¨³•®Z¢«M;õx8ë‘RA2ʹè{ŠâÒ¹-QA!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPH-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÖ,ʹ?\RŽœÒÒ�q@ EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPG†?ä?묟ú­zÈðÇü‚×Ì“?÷Ñ­z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÏÔÂÉ<}�5j ˜çPU†}*´Ÿk�22.ß§Z®¶3!Ü©Ïniu:¹c(ÚOSUÆä wJÊ}²´Ny'Š·�D<ß½U®­°Æhø#“LÎÖ,¸FA¡ªžbÚ;ÉŸc+Ko9Á¦]Û<IJ�xû¦€ŠJ\²,Å"Ê��äq‚CT¬­æ†O›„ÇLÕêšQz2½½¨‚F`ÙÏAŽ•܎ΰÇü]qW)03œs@)ûÜÏS6kvµd’<�:Óšõ¦B¨„zàæ´zõ¤ «÷@AA~Õ?‰]™Ö×I !‰Í$¡ï[ p½+@Å9(¹õÅ8Åö©>dµ+A39ª‚Äb£ÔT€ŽN ^¦º,ŠUÆA …4¥{ÚOçGÏÞZ±YHÆÚì©è…jÐ:±åw[0¢Š(2 £¨#oGPN8â¯QAP—+¹%Ú0\`žÕ^[6óL�¶ íW( jm;¢ µ•‡ï'cÇAQ¬7ÿ«PÇ×5~ŠíLÅs'áGp*6°d`Ñ6O|Ö… U’ØŽ8‚®É#š‰lÕ%¬@ô«4PB“AEPHQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE‘áƒ�+“H?ñãZõ�ác�2Aé<ƒõ­š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*+“‹y?ÝÅ,Ò¬)¹¿ ¥qpZ¸`¿AíA¤ ÛL~™÷$ÿ{úUê­cŽÜg«sVh ŽóaEPfQEQEQES]¶©8'…V7Àð‘±>˜ ¨ÅËb¾ ž·5¡ &'®ÑT£¶’y “pj¾µåQì-QA€QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE&G¨ ¢›½¼?:\�Q@ E&E-QEQEQEQEQEQER1Ú¤ú ÔVó‰ƒtâ�ÙÚäÔQE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ LŒâ–¡¸‡ÍQ‚C)Èæ�«7©5^Öo1v¿½E-ä�[Ó®Fh+‘ór“ÑQ[Ê&„>1ž¢¥ –¬ìŠ( AL•öFÍè)ôÙèØuÈ kr;iŒÈI ⦪Zs|¬½úÕÚ ¨­&‚Н ÄÌÑ7^qV(%¦‚Š( AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP/…NtÙG¥Ã�Ö¶«˜þÏŸ®_úVÝQEQEQEQEQHsÚ€Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š*)§H.~ƒÖ�¤Û²%¢«ÚÜ›‚ß&Ð:õ«¢âìŠ( AEP{¸e]„eOCUÒÎW�4çåýkBŠ IEYQEaEPEPEPEPI�éKEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÒùI�¥�`*J((µÎxÂ/×ö²D»™÷kZ¡»@öìl,m ®é[BŒV-"+‰ÏµJ4ö&ÁúS´âv:“Àn=ªí+u&¤ÕÈ–&ÒÙ÷©´S0m°¨àÏå÷ÍOT.”Åp%ó ºqRveú)¨ÁÔK‘œgš Å¢Š(¢Š(¢Š(¢Š(ê*•š¥e­]¬ë–0]†4ÓMÞ&�0ËœôÍRÏvHŒ„QÔŠ±œQòFæõ4‚�ÄÉÁ 2)héECdÏ–ÛNZÒvbc”äö>µhô5œê˲Tþ4ÓJI¦iQMF�‡qšuAEPEÚÏò¿Š�¤ÞÄÔRŽ´´lŠ] †+žâ›f5ÁmÔï1wìÜ7zQ¼oÛAZÚè¢�Œ‚($Êšà‹�2ÿש§ßs°íÆ*¾Ð¡ê+JTßlW¾)sj6bsl äÿ:±TmnR;|9ù�ôÌg s7bÅÅ‘áXíO È(¢Š¡jv^:}E[’dˆeŽ*…Û{ÇeêÊš;3 ;OlÐtJ)ÚR+›�o¢“ÏçZ‹’x5“:ýšìycž«Ñ]†ùe’XÝ'Y¢«ÃsæÎéÆÐ85+Ȉ2̦`âÓ°ú*±½‹8PÍôg=…Ey½`ÜyìG¥F µrØ €AÈ4µB Ð"Hö’àcëHÒ^+n*H=€éA^ÉÞÆ…QÔã-È?„óô§vã�«ŸZ™bfˆ¤Í¸‘Î(þîIÜe�Øc®y¢î໚’Bg“žiÒÄ“.× š<÷{ †e‘Ü3ÞžÒ*©lðj°°Œ}Ö#Ö¦ŽÞ8Рƒï@5Œ¬n]ÎP�½êÌÍå¡Ý߬�=›•b(#‹î¯>´sÂ;ØÉ¹U5j£HQ�F u©(1›MÝQA!T¯-ܸ–/¼9>µvŠ Œœ]Ñ•5ËÎ0CÈêT¸–Øì‘ ½µs�£>¸§c4:‘µ­¡Ÿ{‹¡)Rª*ÕÄFD;N¦¢‚\îÓ]­Ä‹%ëRÑE7wr&‚6}åy©h¢€m²1 a³°géI%¼r•çÔT´PϹp$G*9õ5%P ·¸QEŠHIØd­KEí�Ïn³í,H#¡¦)µ†}ÏZ–ŠÌíb‰°!³…G¡©Ås—vojµE{Y÷±¢}Õ�EîQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEsþoô[Õôºcú è+�ð†<‹ï_´·òÑPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEQ»þÑósiäÀèùɨµ†À {õÅ;«Ee,ÃH ÝB«ÜÍOökâ»~ÚõŒÐê*¡³�Ž/' ëÆ?,SÍ®åù¦—8Á!ñš@X¢«-šCI3ƒýé Dú\e·G5ÄGý™N?ZºHHÇž(Æ^D\úš¨t‹WŒ,Áå`s½˜îÍGý…h>á•àyþtÀ´×öÁ„ÈÛz€ÔA}Ä*Ê…�@ZμÑíᵚTyr«žNj-;I$·}¢3¸ œcÖ€7袊@QMwXÔ³œ@ºÆ…˜à Ìf’þmª6Æ?J~d¾�€q5~(–$Úƒ‘ºµ%çùQ¬Q„A€)ôQLÁ»…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@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@Q@Q@Q@Q@Q@Q@Q@&-QEQEQEQE˜‚–Š(¬íALR ãwó­©©m²GB(5¤í4-Œ!bY¹ÍY 0 ŒƒU4é7ÂTõZ¹@ª_�Ü�!�U>µ%PCmîQE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9ïô{ïOµ7òÐ×?áøô½ÿ¯¦þBº (¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š) ÀÉ¥¤`H=ÅciWr\ê“aITí×üþuµ\¾†:ËÅßçAôÿ­]E6ER¢«M} 7pÚ¹>lÙÚ1X¯usªÞ<ìUTœŽ€zvqï-��óÆìXT/ªØÇ÷®SŸNkœÕ, ”ñ¡}û×9Æ9ïZ:f“ms`²Ë%bØ`O®jÁ¨Ú\6ØgFoLàժ⯬%°”,ޤõVSÍu:Lïq¦Ã,§.Aúàâ€'º­f¡Cü«Ã5ÕÁ€‹ƒõ'ü+ `H=Å`øk"{ÕÇ U"Ô¿EJ¡¶ƒ–=…!¥qd‘"RÎp*’‰/dÉùbŸöy.%Ý1‚®*„Pª0—PZn68Ö$ ƒS袃-Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ™" #dn„Sè …kKco¸“’}*ÍP9IÉÝ…Q@‚Š( ŠŒÈV@|§¥I@í`¢Š(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÏxC?e½ôûS!] sþÿ�[ßúúoä+  Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š*»�kló-°g€04ÔLj$Èä<‡ùÿ�tµËi·µ�.9–CŸlŠêi°!e�Š€X@5ÈɪêÈNÈs÷T` }î©x÷’ªÈèªÅB;ÓÓF¾nLh¹î_𨵒)R¯¼¡rœ)$f¯ÇhYãEù$µ‚ºÇ§AøV4mC'ìr�] Þ ­âl‹›fí±¿˜­ àM§¬xÃEòŸ~àÕ[4°EK7îÕAQéšè4ûe´³Ž%ç$ú“@kÃä}£PP"bz{šÛ¬M�CP„‡™  ºˆ@‚_3�ßZ–ŠCM ¢Š(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQES<Åó<¼üØÍ>ª«F÷¼�Aâ‚¢¯rÕQA"dgéj´òùWú7§“;IãkyŽ¢™@O^”ú zQ@Q@!8ëKQ\©kwÁÁÆhWv$#ŠZ«`å¢ ÿ «TQåv (¢‚BŠ( Š( Š( ŠŒJáy%jÁEP ¢Š( –ÙóÚŸ ‚Xƒ YPI!î1UlixÏ9ʼn'4]¢šÎª2Ä D‘_îóгEP ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¨.ÃˆÃÆØ*sõ©é².ôeõgq!2%~äsOªš{Ÿ(£uZ�§�z¸ r‹RiQLWßÈôú (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9ïô{ïO´·òÐ×;áþ�|=.[ù 訢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ªºšïÓ®û­Tw ºÞEõR?JætØŠ\ÙÊzI+/åšê«˜µaµƒAûI=óÆZé�CL2YÑõ™fq˜üÜãØú«Jã^r3­Îj…‹A£þ“´ÇódœÑ©^Crê–ñyq¯lc&˜]_P�±GfQÉ œ ƒN��N z3'ñãúÔ«¨=µ«[ÀŠ¢O¼{š�Nÿ�Ø�&@çHÌt攊Z@r:ãgR�ú`~•¥áûÒÛ­œ–yzzŠ©{Íy©«}è•]Oåš­¢ý¥œŸËÀì+L>V¹r™8vq�|çük~¹Ûùœ�ùìAÿ¾h@tTQE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ Ï‹åÕ_Ž¿à+B³çýÍú¿fÇøPkKªò4(¢Š Š:˜Â£¹"­)ó w\Õ}LfÜz†©­?ãÖ,ÿtQÔÙÿ 2;BûäA•j¨†1_`ôj½A5· (¢ƒ0¢Š(¤a•#Ö–Š¡`vË"µ~³îTÁr&^‡œRµä’JϽD æù‘~І›$ÊàŽÀ šƒ¬QE (¢€ ‚î_*.:šž »ˆËïEBÜÊâÛE²<žKsSU(¯h`At« qtqASŒ¯vHÌdÒ#oª×ùò7)àj+ ¥8„Žy ÑqªmÙÉÀ'Ò¨ZÜÜM)8>•|ŒŒU%’+I ±Ú1Š�šj×eÞÕJê6Ž_9?¶Ž$]çjWPêUº Œ¹YŸk¹ÎâvŽjÜò­¬Y œœIokä;6ìçŠf ¡£ìsA£q”ÒèMo0ž=ê1Û-V°]¶Ã§$š[¹šR£$œPfãyòıEG ‚XÃqœréP½ê$¥8È JnȵED."#;Å9eFèÃó Vcè¤Èõ¥ AEPEP î&’ãÉ·8ÇSRCrÊÆ9Èf¨A;$òÚ =[·5<ñ¼Ä0tf=qI3²PKÝf‘84Ñ*1ÀašƒsÅBC–#  kíd~uG:�s­0È�Â�j« ÆnÎÔs¸ó$�?)ÀÿëR§­™£EU¶º.Ù ={ÔîøŒ²œàPC‹NÌq`:šdVt{äWpã#±55•À|ÆÇ ;P\©Ù\¹EC4…:j1{Æ'ïÞ´¡&®‹TUHï‘�Þ ŸÎ¤k¸•s»>Ô„“µ‰è¨"ºŽCŒí>õ!‘Éu�qkF?¥F“Ç!¸'Ò¢º”ù@ÆAã4ËHq‡,° ¥Ëv\¢šÎª2ÌF·1¼�–'Ó¥(¶fÝîŽáÕIúUëKx–%`7ɤ½Œ¯øSìÎa#ш¢ÇD¦Ý5bÅZyÊÊ‘§RFOµY çqi\*¹‰in}©.¥1 ‚ÜgÒ ³µR¾küźAqŠ·4‹‘Ȳ eèiÔÒB)8àÕT\O&LQŒŽh�6ÅÊ* º’6xöƒÜU¥`Ê œƒ@¥Å¢Š($(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šçü#·ì÷»AÏÚIï]s¾?¹¿ôò•tTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQER�E-ÍÛ¡û–„rnXãèMt}«�·wÄ�Êo$�AÈ?κ:l2Ktk‡F}¥wý3QÙKövi¼ ø†@­{�9 Õ~Ñq,grX«�1Y·r4“¼JÄZ†ùUx¦$ÜHæëË8ÝÃã4–­'Ûâgm­æY¾¼Õ«»Öxà‚Ù C¡?xûÓ!WÔu%1 å�p:(¤Y Ì3‚a•²Ù§¼ˆŠYÝTäÖ;ø}f’Ú_,�¸è~µ^OÜȧ÷ñç=Á4[U¸‚]EÞىܻ$+Ѫ_ 'ú|…—¤gÓ‘RI£5…³N¤ÜLUzdã5C´’Þ’t)$��P(R¹ü× €f÷ãÐVI¿_̙ڲ_®(@oÑE€(¢Š(¢Š(¢Š(¢Š(¢Š(£4PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPHzqKE éÏZZ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š@00:RÐU5÷D •5n�€ÀƒÈ4r»Œ·“Ì…[¿CRU5œ�Ú3Vêèàz ”:­ˆ56ýÚSš±l¥mã‚UiJÝLª 0^õw·NÐQ)ê+…YGU8¥[õI‘Ú�Lçr\§ÊxéPIÂÁ_sœbƒXÅ4£#EœËçŒf–7 eèjŒ½�Nåj¤WÀvylG¦:Pd©ó'mËÉ0g+Œb¤<jœp4Ä»€ösb™2I= Ñ,›ÚH‰ rV®Ár“ Ò¢µ·x¤rÝ J¶Ñ¬Þ`ëéÚ‘¤Ü‚^Bf„�Ôr*–š~ÝÅjUe´ sæ«`w \Ž,/dhâN2i‚ñ~Ì?¼#§½Y–5• ·J‚5�Ë1Ýè=(\9uow$̪ï5]¤  éKAi½‚Š( �¦J¥ãeV*OqO¢€Z~ÀÍ÷¥ÏáAÓ²Öcð«Ô„€9 ×ÚϹB«”~eÆ9ªW­´¨Ñ ZUWP·Ï¡ )Éó[¹az+zŒÖeó¬³dÆÞõ«Ög6ÉíÅLUIÉŸ¥*re[ Û9Ú:Uº:QA|ÎáM‘ˆUºN¢‚v($W6¹w¯lÐÑOtãÌùQOÒ¯ÑA¯µ{ÛR�±(O—)éR¥œj„?ÎOsV( —RO©Wì1z¶=3M}=Ýb¿5rŠí'ܨ¶Xÿ–­ŽõeF¡W §QA.n[…QA!EP%¤K-ã£pnŸZÑ‚Æ(p,ÍêMTƒ÷Z¡_RGõ­Z”Žªó•ìž� ’5‘v°â«ý�q€íVèª9ÔåŠK§(921õ«jŠŠ@Ò�E)Ê[²³ÙDÌXeIô©ÕS`.1Šu“{²£X!$«²ÓÃ4oó{Õê(+ÚϹVy7î™³Ž€R½Œ.ûùÀñVh ^ÒWº!6°‘�ƒëBZć!sõ榢�s˹Zk$‘·PûR-ŒcïßZµEö’µ®1£VM„qUM‰ì”­]¢€ŒåŠi`3™·µYŽ$ˆa)Fýç$Çr)Ô§)nÆJ…ãeH⢴‰â�„˜É9â¬Q@¹�¬U¸¶ó%©!…5d¸®3îE\¢‚”ݬÊ�o$Êw¶j±yQ*�£ú(%ɵanRzD]«Œæ�E�]¦øXl,{c­2Å]c`àŽxÍZ¢‚ùýÞP¢Š( (¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šæü>]@ÿÓÁ®’¹Ï«Ôý<è袊(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(MOôˆ Œ�ó”ö;…mÖ5¢ƒqfð¦V?RzVÍ6[½>ÞñÑçRY:ÄTk¤Ù°îú±5zŠ@T]�ÿ—tüjÄqGÄh¨?Ù§Ñ@Q@Q@`ÝÚ®�2\³´ŠÓ—`G5½YZøÿEŒösùhÄC�¶ÌqêšÞ$_á·?‹V�Òìq‘k<ýÚI´›)£(aTÿi  ÿøI¢ÀÿF|÷ù…#øŒ<¨¾ó×ò©×ö@Í+ß~?•Hº€$˜Ý³ýç4Px�œR=÷ÔƒÄpòZQŽäu«K¢ië�ôe8õ$Ô˦Ù/ݵ‡þø�ÿ xÿWŽyËt4zý›F]‹ªƒŒìãó«ÂÊÔt·‹þøóEv˜Óo¦ÑŠÏÿ„ƒOÉfÎq÷ Fþ ¶ÿ–I<¼díLcó­aˆ£ð¥ £ ð yµd•¿wczÛº�Äcò¥�ê£/ö}Áÿ�èh¢àrÓ»¢¥l'�ËŸÎ’;mMzG:c¶ïéšê¨¢àsö×Z~é.â�¢#�yüMY_Ú”ÜŅ̃û»rkNx#¸ˆÇ*îCÔU%Ð씓±Î{4]¼Eû�Lß�þ´å×íÚ2J²7¡ÿ*°4kÒüxÓ×J±AŲ¯4@ø’80ÈÞëŠwü$–˜ùc��p‘Z«o ,H QN ä(…d�ÛœŸ&p£¡+Öžší¬ˆIIÐçygŸÆµ0=(À  Õ×-ŠgËŸw /–ri±ë.èÌ4ë¾?ØëZ´Pgö�Î7eÜcò»@#ÓŽ?é(¢Š(¢Škº¢r@É'µ6)¢�wE"¸õSš­«Æòi³,gœ�QžEdøuŒwr&r².GÔúé�ÑÑE€(¢Š(¢Š(¢Š(¢£’M�ã;ÛoÓ‚¥IEPEPEPEPEPEPEPEPEP\ψ†o3ÙQG󮚹�u‹_º*äá@÷8¦€ÜÒ¿äkÁº^¿J·L‰vD‹Œa@§Ò¢Š(¢Š(¢Š(¢£y£C‡p <FAÈ vbÑE(¢�œ ÐÑQEqÌÊ�’µ/JÓZ0¢š®¯÷H?Ju (¢€)Cpþ{¬‡#vµ\ª7Š«!cÆáÇÖ¬ZÉæB 9#ƒA¬Òk™ÑEQ@Ý–[w*pqÚ¢Óåi"!ÎH5bP lLUÄìpEÑW¦Í(¢ƒ¢’š’¤…‚œíë@ì>Š`•L†<üÜP±ívl“žÔ»�¢™$‹åŽ)Q·¢¶1‘œÎ×E1äXÆX✬C)È4žâÑE(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠLŒã½-!ã=©h¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠL��zZ(¦3íàÇÐPè¤=xö¥ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( IH0ê 6+x¡9EçÔÔ´P>gk\(¢ŠQEQEQEQEQEQEQEQERÔ×t+ìiú{nþ’é Û¸zÕM-¹‘}….§BÖ“ò4h¢Šg8QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÌx8þ÷Sé(9ÿ¾«§®_ÁÃý#T>²/ójê(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ŸÓ“[œ�NÂçèsŠè+E jWÃ9fb&?ã[tØcx’=Ö‘>9Y:údÙ¬?ù¿gˆ(>VǶh@SûdÇv’mr2ÊO_\Uß]´†[v%‚�ËžÞÕÎÅòçdnáyùFqZZì6· ²©Ì¸Pý…utTsϼM$¬GsYÖÚý�Ä»è³Ð¿Ò#P™mõyAÊJ ‘«wÚÌ7V�ÆÀžrHâ«k0«·<9\ûtnóD·¶³–Uy AžHªŽ�ª½œR" mÍ‘“Ò´4këÛ›·Y˜<8$�¸*{ ­¤ÚÚ±¸k•’zu§Ë∴·P‹ýî3øR£¦I"D¥¤uUÉÅ*¶åÔf¹-KP{ë†R� ¾¸=h«†x®|2+¯L©ÍIYÚe“Yiå#üçŒ`‘Ò¨hÚ¤�tö÷ \X9=1Ú€: +Ó[’{õˆ¢ˆÙŠŒ}x5¹HŠ( ³µ]Kì*5 )Áèh×?â(I•$ÇÊWþ?ýzhizµÕÝêDûJK``Ž* põÄðv±ÿ?…hè×�O�"ȃ�QëYýÂÜß*Æ2" õ9  WzÔ“+-¶c€qÍ\ÐVïÈwºg*ÄyaúãÖ“FÓ£ŠÙ&�‘¾`{(­)æŽÞ–V Š2MIEsÏâaæ~îß÷~¬Ø&µôûèïàó#àƒ†SØÒÉ�¡â¹3i·Î‘òѹ×_\ö½h‹wàcÌá±Ü�þµ4YõÛ’PJFïà^+cD‚êb.Ÿ œ¢“’¿SRÛÅ ÖŽ5RéŽk/B�¢»x^BT©àö#¿ó ŠŠÏ‡Y´šáaV9c…$pM_È= òÇ˺¯ÔÓ-î ºRÖò¬€uÚzW5¨1�U˜LÅUŸ9Æpµ»¥ÚAk6îda‹ôÀ½ER¤*23ƒ‘KEQEQEQEQEQEQEQEQEQEËêÅ¿µXõù”ÈWQ\Æ »µ‚;y©øt¦€é袊@QEQEÉ$X×,qO¨n^=¯ß¥�›Ô£mÜK!~ÜÒ,ïmp‘‚YKm#ëE”r�Þ[=êôQ`–‘6xÇ4ºS’‹wÕI"Æ»˜àUsyœùkž)o­ÞxÀCÊœãÖ©Å Ôl6ÞÇ&�ȧ8ݽK¶·h$Áa±´ç¥f—{9Ž‚*ô%¥€ ÔR {Ëb½„j¥ÙG=ÒŸ|ì±_â85 ¨xnÚ<§ŒÕ«¤ßõ!ËJ‰±¶CêÇ©^TN§ŸJ†Á·AŒ`©"�ÂË+ÈÃw÷hD´œÝË Á†Eêƒ,qT"º¼’FQmµÀ&‹¸ndPÛr} jž¶l.§Y£`ƒ%9Í;K”»:àbYY·Ìk¨¦À)’ƲÄѸX`ƒO¢�Ž�wööŽRvPûzþ•óÇ%ôÒÛ�•Û*1Žýuµs  .%–9‚ïmÁJô=êÅŽ�¬¾l�æ8 p)�Ÿ¯4¦ÞÒ7<ùysÇÿ^°6•9èk¬Öôùo<§„(+œg8ÿ ‚ÛÃÑ´Yºf{!é@Ú¬ïp–×h˜óŽÎJè.ƒÜèò|‡Ì’ò޹#¥Omi ´“ä8<óëSÐ)co5ͥ⪰e Ž1¸ƒ’*­§•opâ(Üs] P£ ÕZãO¶¸mÒF7zŽ(¸Kâk¸ãˆ� ÎO5™å˜µ‘�ÇÏ{ÿ èÓG³Iü²YNFXñVüˆ¼ß7ÊO3ûØçó¢àI\Åæ�qã}™ÑÉ`Þ™=+§¢�sÃ.�?Ì�|ºøÜI¸èÀX^!‹0IÙ”©ü+OI}ú|Yê¹_ÈÓ`\¢Š)U-RæÚ f_2·SWjŽ£¦C¨23#¦v²õ ]f6÷[vo”åIô÷¥ž)¤’!S*ï\÷µ½oáø"`d‘æøX+F[hfŒG$jÊÇJw3÷-$ÂÇ&2ú­â‰_Ì‚ ~M¥ˆ÷ϵke˜aaw“ÜÒ^YCxª%+ÐŽ´Èý–1lyy[œÂӴ빬%g‹†¥t±èöÈrÛœzSµ…« ½8  £q{,Ë6.9ô¨¦¶À 0 è)hTº°ºY!�9–<€Ê½Ö¡ðýË¬ÆØœ©‡¶+JçHµ¸�Ƀž¥3RYiðÙå‚Îz»u4nŠ(¤EPEPEPEPEPEPEPEPEPEP\Ö£òêÎs�Þ/òÒ×3y}i�<WúS@tÔQE (¢€ (¢€ «KQˆd;†*Õ! ¨Ë•ÜÍÓ�¼ÒH#šÓ¬«sä_²™ÅjÒFµ×½p¢Š)˜@=Fih¢€ B20ih ¢*c<Ó¨¢€ (¢€ (¢€ (¢€ (¢€ (¢€¨¨U>”ê( Š)¥” ž‚€EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPW ²>Õ€ýƼI¢øþço÷�Kl…¸mOÔ’Š( Ì(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šæ<�´ê„uóÿf®ž¹� ]j˜Î<ÅÿÙ«§ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( =Ãr`q»í qõØW&§É~¤]r?àX®²›¢Š)QEQEQEQEQEVˆ®ç…áŽhú±e={b·j­íŒ7ª¢Pr¿tƒÒ„§yö«[N»Ôeþ¸­]wöÌ:¹ÅBš 2ó³'÷Bãõ­X¢HcXãU˜¢“' c�ZZ@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÌÝkÿÓeþ•ÓW72ïÖ¶ŸùîMÒQE€LóŠZŽRUw/n´õ`Êï@í¥Å¢Š(QE—|¦;Å�wþ"´Õ·(aÜfªjI˜ÿtÔ–OºÙGu⑼ýêiö,QEÌŠ( Š( Š*½îá*qŠwbÅ ¬žd IÉéSP YØ(¢ŠQEQEQEQUÞàäˆÀc@Ô[رUo�ò7’_JXn‹¾ÉkTÒ®ø™}E$á%q–²y°)=zQ8ó¼¶àžžõZÁ¶ùŠzõ¦]¦9¨4äNm4Scq$jã¡�*/SA�žÃè¦ TœgšVu^§˜ê) dÓYŽÂÈ7€°ú*´7,òäM­VhfQE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¤'4Z\IrªNBö«UR×÷’»žÆ­Ð\ôÐ(¢Š (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9�gí§ýt_ýšºzæü"y©sÿ-‡õ®’€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ ( ô ZpcÔ|õã}Ïofºšäëí3ª�ŒÌH?V®¾›¢Š)QEQEQHN:Ò,ˆÇ êO 4ê(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ æïƒ.³Ç_5ý+¤®U50çQ¿ÏåMÐQE€B2ªö¬C¹ÆM�º‰iT¶¶q!–c–ì*ÝPg)9;°¢Š($(¢Š(¤ç>Ô´QEQEQEQEQEQEQEQEQEQEQEQEQER2†a‘KEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEǹö©*µó…‡¦‚ ¯$‚Éq>¦¬Ôp.ÈT{f¤ $ï&Š( �¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(œð—ÞÔOo8WG\÷„ÿæ#ÿ_Òº(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šâ¬:˜¢ÜàÿßuÚW© �RŸ·ïƒ#]€éM€´QE (¢€2¯µ¨ìî F2øêAïYSk—wü¼FŠ:/_ÄÒ d½Ö^ Y€,Ä‘Ôâ´5»xm4gHF7¨ã¿=é�� ßjA„NòêLqUÚ9ôë ® r®`Ö—…Ïútßõ˧ãW¨s[ÕƒâÄÊ;ˆÍ4ÜG1!õQO¨íÎmâ>¨?•IH«Þ¦èw«V)®»��QAQvwo'™ žý KTì2ÁãœÕÊ5i4QEQ@Q@^Õƒf'ÚjXí}ò6óéÚ¬ÑA~ÒV°RçÒÑAZ4r ($t§QEó¬+“Éì*Z†âÝgQ’A ¨ÚþöÅ[§ym·2m¦ÓÉ6Ã#œTkbÿuäÊ ¸ˆ¯AA¬å^T:Š( À†èâ>FA8¥¶„zv¤ž1¶uõ5(AAm®[ EP@QEQEQH4´QEQEQEQEQEQH̨¹bMµ8C… íôJ["íÔ`êgžiÔQFq@ yc4àr2*½ð-lÅO+ÍVŠôÇ@75±¦å£JŠ¢¿j›;þqjNHh&Qåê:Š( €¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ª‡}ÊD=ªýgA™usü9?ÒƒZZ^]�01KEQ@Q@Q@Q@Q@Q@€b–€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9ÿ 5:} ÿ*è+¿wPÿ¯“ü…oPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP'¯qª:*ä¶ÃõÏÒººå¼DJj¡‡_-~ k¤ºi|Ÿõ›ß®)�‘ªë† L6…K/Þr3ƒéU,üC4n>Ó‰#ÏÌq‚+Ee‘–@C†¨55­»]ÜÇ );ްîhºíYzÖ¡ö{WH$r@Çp=kS ®ì–¼•Ø’ Œ ЀmµÌ°N' wƒ÷�$×M+íi²GѸ/pGJÀˆXº6ï8>>^˜&µ<9Ù®¶Õ_ÔÐof JHÙH&2û8"¡Öõ¶Î<ˆcÈþ#ë[ÚÄ‹k§ÜNŠFP¡€ç$â¹HíÌ–rÜÿVê¤}hÔø~— f_œ‘ïZU‰á‹�öÒ[±Ãèúõ¹Hg5âS›¸ÔŽ‘ñùÕ�2=ÞpyÎÿæj?!ó-ÜtÃ*· €t€§Ÿ™ÁüÍ09Ÿh|Å^’.Ó9þ•½  R…†>ÐzîêµdØÁ÷âxM­ŸÂ¡&(È{iX®r¤ðEuγ¥ÞÀ?�Rðä�ö{�çäGö⡞øßhòŸ2]øG­Iáý“YÝC‘¸žG±ÿ«}¬ÜI.m�‘à’~µbÓ_•¦ sª €AõFÎáôùt`Ê>RtõÅ>X®u;�Ë q» («¢š‹µsœ3N¤?âIKjHFC¸ŒóZúk´š}»±É1Ž}x¬ÏBL�Ë�� ô5"êpÁ¤)‰ÔË î8¦ÅV¾»[(<ÖRà `W;¿y¹”¬©Ývàþµ5‰Dú:ÜGʯøÒ¶�n`IS 0è{Qs:Û@ò¿E�eøjv–Údla$ãñ«z´=‘rÊÁ±ë@¶zìóÞ¤n¨ÛÇ#ñ¤Õõ‰¢¸x-Û`BlI§xkË�\‹½X{àŠnµ¤O5ÉžÝC†ÆåAõ  ù¯mKI�1ýêñéA®V õF�#•CuÀ­­#N–ÅÏ—{>>PN€0l®…�ÛÈ ŠÈ=yÿëUý+Uº¹ÔJÀÆÀ䀼SA�¯ß•Hlò=8 èJØŽHÀ=òx Öu'’q¬„*JI¬çÔ¯pc’w#¡¯Ûh—PjQœ 8bùê>”—ÚË^Höê­¶á–Æ ê(ºV§,2¢Í!hO'8÷®ž¹ì�@¦Èê]l`¬jP4êkœ#AN¦¸%H¤­xβ™›wÞÆxúcÒ¶añ nê²DP¬@¬“¦•ÕŒlN0 Ðc9©?°ïT9òÇÊ8ÃuúSn}jÒ X¿©^@©®5;h ów‰)®fÓK»¹wÄeu/ÆM]�ÃÓ¼Let�ñò�Ïç@oµ[‹Ö`NØ�DSÛÞ¬iW“ÛÙÞbBvª˜Õ¹ÁÎ þUXÁq§»o� Ê䌎}*î�g,·Y Ãå²’G\н#P˜Ø]Ïræo(ä3Œf¬XëQÞ]y &T�I»V-Õ„“@IMÿ+`p¡Hn„‹½x`†€55Èãk±4N¬ έ�2ô]Á†À‘GÌ3úÖ3[õÎkLMùäŒ?ÏçM¿n6ÛÆ=Ò¤¤KHŠ(  Pe/OsWj¤ªVè8qVè4ž¶aMvڌރ4ê­s,Š Æ›³A1Wv%�üÈóRVM»\ÎåVM€sVÖÉ‹n’f'ÐQsIÓQz²ÝŠ6Œf–ƒ¢Š(¨çÿVO§Z{0Q’qIï± kMH­%ó#9<©ÅOY¶ ¶á× •jÚʯž~Uô:qZÜj\n™åfÂ*àZšÒàÎwPiŸ`Lä1úTVGʹd=ø mBQ|¦�QAÌQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE5ÎÔcè*žš‡99ÉÅM|ÛmÈÎ 8¥²]¶ÉïÍ«JoÌžŠ( È(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÀðŸú‹ãÿOMü…oÖ„¿ãÚ÷þ¾[ù ß Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( OÄaÿµàv†Þ8ïšê£;£R: ax�NÈ›¶ÖÊ·!ÿS:mʘo4«KÖÝ,xï)Á4ë=>ÚÈ“xb0Xœš·E )"'#¨SŠäme‚;€nSzã•ÍuÒ.øÙ}AËXÇê^Eìa±‘óÀ}í壯Ëš#ã†àZìó:ÉýC©K§Ek$p,^aÆ6.{úÔ:.§oi ‹pÅw>F=¨kTµûe„°�¼FWê9ÍiE �ôs0@у†ìFkyõ»@¤©vú.?�r“8ó¤+³3îs@rº° ~WFzô"ºÚå|?k+_$ÁXF€å±Á㮪€2üA›§3÷ˆïãÓ½VðÁ“ì÷ƒåïlãšÜ ƒÈ (Q€ÔÊY¤�ëÉo€Ä3ÿwÿ­Wn|:M£àuÏOÆ·|´ß¿jïÆ7cœS¨¸ºf–,í¥ŽV4¿1éRXipØK,‘3“&ôzŠ@1¢G ²+ê)ÀÐb–Š(¢ŠŠâÞ;˜Z)FTþ•†Þ—8!\ðMt4PbhvbGBÌ:¾H&¯ xþÏäm-»vŸJ–Š‚ÒÒ8¼¸j““êMOEVðÀXÅ!n¥F3RÑEQEQEQEQEQE&s�ŸZZ( ’–ŠBê3KE…Aê¥¢Š‚îÖ+ÈLS ©çŽ Õ(t+XÎ_t˜9ùºV¥É!ŽPˆ¬LŒÓ•U*€ v–Š(¢Š(¢Š(¢Š+œÕ¾¦@ë½ý+£®~õõ°¼äºJh‚Š(¤EP[Ï”£Ž â¬#n@Þ¢¢»Œ}jH³å.Nx ·ð¡ôQEmWeÛ¯~jÓ?UB Uf5<ü•â–+ƒ,cxn£Òƒy%'wØ|‘;+Ä0iöÒù‰ÏQÁ¨d’âL¢ÅŒñ“S[CäÇ‚rÄäÐL¾I¨¢Š Šr¹’ëÉìZ¶*„Œ`¿.AÚÕdÜÆAÃA´âì¬S¹c è*8<Õó2*«3`7J¨`k€Ò“ü5 f¸Xäè ñA£Š’ס¨¬eH"†eA–8OìóA.ë™Obj §”6&Áãµj’“Ñš1Í£ä`ßCQÞ#¶<ÕK;y ÂB (çš³}IØ2Tç!òÆ3I2(ÓÊ!щZ³2ïEaÛ‘TÖIdtA=ªûXˆA–Ša;¦¯¸Ø$Ý#u¦d<š¢c¹‘°ÊGÓ¥>K¾ç¸4ƒ’7Õ—èª?gº8ýößjš+fBKLÍšqK©bŠ@01KA˜QE^õ7Û6:Žj á–#¹A`yÍ^# ƒÞªZ[<?üóíïA´eî5rK˜‡••mç¥,Sˆm<�ÍLFF G ºÂ¬'>´¤¹lÆYÎeˆ–<ƒPÍ|c”¨¨?�?ì#qÚäØT‹g ® ÷nh4½4îEý¡`OÒ•oƒœ$NßJ”[B/åR€@·O¢rÆ=©h¢ƒ ¢Š(”’H±mlÕSmu' Ê×­hQA¤j8«"”6;s¾}€¨ZÞ(¤mï•«EÛj沄fêõ²HBsÅÔå)]·¡Ï7•*ã5¤ÈÐ »ÇñÖª\ªÁt¡F`ñZ´�U–Ílbɳœ#síZv–âñüMÉ©è§c9ÕrV”2•a�i±Æ‘ "€)ôPew°QE(¢¢žu�An§¥I·dKY×cʺ^jÌfYqš‹Q_Ü«zPkOIظ@#½-W±}öËíÅX ÊJÍ ¢Š(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE Ž9 ¢Š(¢Š(¢Š(† äËc¸Í]EÚŠ£°ÅQ—j*¸é�ýkBƒYé ¢Š(2 (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€0¼(?Ñ.�­Ë![µ‡áRM•È#¥Ëþ=+r€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€0üP›­b;°7Ç®EkÛ6ëhÉR¿(àö¬ß h ÝÐKÉü hY1{(ŽI�I?…0'¢Š)VDÚIu$ë3)�ä�¹Á­z(|>œ‰'${.*x4+(�«¡—œåûV�DéG?¸>„Ô�é¶�6èíÐR3V¨ ”´Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@GRÔVÁíÞÌzgn)±$‹÷YCÆ€EPEPEPEPEPEPE! u }ih¢Š(¢Š(¬Hyz—˜¤†Êœý+z°u¶)u�ùþtÐÔSS”_¥:�Q@]�ܨ§[œÂ¹¤¹ÿRE-¸Ä+A§Ø%¢Š(3€H$ ŠZ( Š( Š( IJ0ëš…laWÝŒŸz³E)I+& `†5”È#©( Wh)¥T�H�ju(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š†ê?2PH8ãSLùU·ðEhÕ),71+!öÅÐ’åql«rÿhº>N0+XpCoj�r9oSSÐ*“NÉl‚Š( È(¢Š(¢Š*ާ1¬ƒøx?J½HÊJ°È=h.å’d6’‰ ^Fà0EG¨°û9\òH¨ÚÁ‘³ ˜ö4ÔÓÝ›37Ç9¤j”¹®X°¶_©«4Š¡T0-3;¶ÂŠ( �¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦,jŽYxÝÔvÍ>Š(¢Š(¢Š(¢šìKÔBÜïÔ\Ÿð­ÏÓ†éeóÉ­ «|V (¢ƒ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(Ãòsë3ÿ:ج “ýšÙí3�Ö¶(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š('_8·„õL‘ø»§éöçýÚñøVwˆ.#ò¼ž²)Ý�lÑÓ×m…ºç8�•0,ÑE€(¦³RÌpÉ5ö÷É">3†-Æ(Í�.µlƒä&OuéT¥×äÏî¡@=Xæ�€Þ¢¹YµÛÆá$Dÿuƪ›íBsþ¾cžËÿÖ¢Àvd�Ô⣒â(¢2¼Šu9®Elu ¹1\6OñýjYln,­O�…lÒ‹ÕÃ4sÆ$‰Ã¡èA§ÖO‡#1Ø1=BGè?¥kR¢¡P›ƒ‘L gmM@ShÝŠ«©aÔ@¢³ou›{GÙƒ#ƒ† ü5-†©ùe‹rºóµ‡8  ´QEQEQEQX’krG«5©ˆÈÆ98çõ  º(¢€ §ªÜ5µ“º1ùA÷5r³õ¸üÍ9ñü$7ë@èHðL²ªÿ.{qÍkV7†Ïú4ëÜIýlÐEPEPˆ"á—ý’¿Ê®èÒùšt@Ë1³ò¦k±ï³ Tz®¾�O ´´”´€(¢Šæ »u× ’J¼…1žƒ¥tµË\F±ë_…óÁüÈ?ÖºšlŠ(¤EPEP?ˆ`‘àŽhò|³Èýéú ÓMnÑHÛž>ç® ^¼C%¬¨ISŠÅðûªÞHœå“ùþ½0:(¢�Q@aëøGÇT"·+šñ4¬.âOáçó?ýjh† ˜#Ï]£ùT•GE”ˤÛ1ÎBm9öãúUê@QEW¼æ½ÅIú¥úS.ùŒ f¥�î/Ò‚ßÀ‡QES¨d1îÇj}kQ@Q@Q@Ù Äu«Y]ý º�A^~¢‚”[M®…º(¢‚BŠ( Š( Š( Š( <¨Œ˜zSê­ôjÈõf�fåáòœAn+—™(¢Š (¢€ FÎÓŽ¸¥¢€)YLÅÚ9 '¶jíe»4W¤€N§¨5©AµUfšêT3\¬8È'>”ø¤YP:ô4r´®:–“4´a•D‚?âÆiô›FìàgÖ–�èRCšZQEQEQEbŠ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦º‡B§¡§Q@Û[­º� $ž¦¦¢ŠÛnì(¢ŠQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQH  ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(Ã?ò ?õÖOý ¶+#Ã_ò Ϭ²èU¯@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@¯ˆØ­ûñÿ,ÁþuÒZ.ËHWÂå\÷‰@¨[î”údæºXÈ1©_º@ÇÒ›ÔQIH®×}¤ËŒå¼V‡í¢¼µ»YÆäfPW>ƒ?Ö¥º×KH©V*KwÁÆE>ËU¶‚"$v9;W­0/�*È(Ý8¬ÇÔ4È™£ŠÑ[a#%@Sæ:–¡ó@8rv°“‡½fÝi¯ $³BûªÙ&€,ÿj»äCeýœÓ¯}#4qíWþê§5SO¸ßÛ9m¨O¡È©î.£MoωÆß0{c€­0/hú�Ì×ÍmtrJ“Êà‚*O·ú¥=0MQŠhæñKÊ™:ôþV‡ˆS0Äã± ÿŸÂ�t˜ü½2Ùé˜'ñæ®U}=üËc˜ÇO¥X¤3z¾F¸eS�Þ+Ègô«z¾®¨†W�ÞqÛéYšìÇûN`¼mÀýK£éé~L“7ȇîƒÉúûSä÷—xv a+áKwÇ<þ_ΰ,î%Žö'LîÞ:wÉ®Ÿ]ž84ÿ(Ç»ÌùTƒëžÒ£ÝªÚûIŸÐЭNµÕ%’Pd˨úúÔº »½òÌ ìLäöät«ÚåŸÛaY­Ø3Å�Ts¸Um÷Ë�Z°ù\åO¡ô  éæKxZY[j(É5™mâYå1¸x}úð¨¼HÓyq ¹lî?í•‚"Œ&wýÆ8 åX2‚¤zKY>wk&V*>ûVµ 1u�BêÒåV#µ1ž™ÍjEs¨Œ²/Ì}j–·f÷6Êñ ÉÎ=GzåÓ+ÛÒ˜QÕà]HÙ2°l…Ø’3ŠmÔ}¥ÚÞL„Jǯ'Ÿ\V¾ûÝM\cÌy’=ˆçô­ývÖ[›@a™vަ€,ÝÞ,Zæ<8À+èsYÚÅÝÍÄï<›“åô>Õ.•o,š'‘r¥IÜa‚x¬í&á­5*E9cå°ô=¨¦$Ià ¯væÊUF:YúÇÚæ>Uº9@yÛÞ«[h·R2É,ÍÞ€Ÿð  |:ø’â.‡ Øüër¹»šôÑ‘ü,¿^â©}¶îæî?2vQ¸gFs@•&G¨®^ûT¹–i<©8� ¥f \œyŒps÷�¼¢²ðàÕBòN›#Œá‡,i‘‰ld*FsúÒêi%Ï=ÇF†âb®ø•¤ˆ± U³ä·•fŒsÔ�ØÓ„·S|� ƒÁ$S"kŸg ·,ð\,‹Ðõ« rUEg>”÷‰d�csïU`¶–+€x)ëA ÆQ×t>æq ªKFqVȮÇÉíÒuÃŽ�ÅHªBŽ€b‚VVÜ©i0Vh߃ž*IæP„«gpzRÉk�¸ä×ä‚4B�F\÷ §(7rïbòÁ$摯×8D-R (A?/áš™cDûªnŸDE²ÉËŰ{ÔôQA“waEP ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š('Ã?òOúèÿú­jÉðÐÿ‰<^ìÿú­j(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Šç‡º¿Õ'û¢˜®cUžñnÞ)¥Âƒ” ÀÇjéëÄk‰b~™R?_þ½ ßÙÖ¢8åšë€;sTD.«3&ìdÕ‹h-|�ó\°cü*µâ8 }ĵ@Ž¢+5m3ìÁÙ—”à×;¨ÛÙÛB#µ�¦‘[IÍt7ÜCk‚ØÎ[€q�޵†Ö²–;l<Ž�N(˜ˆ<äÝ÷IÇ¥Ko÷ý!ØC“ÈêGj°t˲ãÖ_ÈT‘è×�÷¡#Ó$P.öð_$Öaö£ÃCÍM{­IwDñ"®r'вºÓcsÄ¿™«pxzÝ3HÒq‚½/‡§•íšbeX�ÊÄ`{VÅ @`”´€å|I[àûxtú‘š£m<–’,©•uä{Šëïla¾DI÷a[pÚqLŸK´ž4I"áj�p@¦7©_5øŠB›@]¸Ï~õB9Z –Dm®½k´ƒMµ‚ Æ Îææ…Ó,Påm!ýÁEÀäÒÎåaŽî5p�’¬„ÿJ¿£XË-ÚLA n$ŒgÚºuP Ð ZŠ{xî#òå]ËT“C³F,C¶{â´¨¤#�"@‘¨U§ÑE·ˆç÷ióuùG5-6Ð[çɉ#Ï÷F*Z( «½�»Ü­ÃD<Õ9 *ÅQE\ÙÀn…Ï–<à1º³/ô=ò-6‚z«? Û¢€2lôTKyç—�`í?t{TðŒÅ¼s.= ŠÝ¢€+XØÃcHsó±'“Vh¢€”2•=Á¬«];k¯3vøÆv¡+ZŠ£s¥Z\® ‡ûÉÁ¥m2ÝìRÑÃ4h0¤Ÿ˜~5vŠÏ²Ó-´íò†fl»ž‚²u›Ø/<± ÚO8­-~VŽÄ*ç6Ö>ÕÎùˆ! ³çRrÞ´À½ŠnlVæ)Y¤Ç@Çj]+Nº[´y¢1¢’Ýþ•­¤cû2 w\þµv€*ÞXAz€L¼ŽŒ:Š‚ÓF‚ÖãÎ ÎÃîçµhÑH~ûB•§’Kb¥\çi8Á=iÃŒÑeåU“È�t4P]®‡m'œ ²)ÉbxÏÒ¬]é¶÷gs®ûËÁ«”Pt:-¬XݹÈ9äÒ_éBêæ â—Éxˆ<.rÍiQ@Q@Q@s~#Oô؉$î��éƒÿ×®’°¼H^ÖR2~dÇä¥4½Ù£ßoçZU› œé«ìÍüëJ�WšW‰½Tô«„#"�Ťõ)Y£<Í+ãÚ¯R*…Pö¥ s—3¸„dYqâY™3€¹Ï½jÖ\‘<7,G zœPkGªÖê i1ƒNÓ§]XãÒK;H ÆH#Ô‘éë´o''¨6¹m2k†f·c9©-g2®ÖV £œŠ�@Up-?2µ¬#T€pHëY“[Ü÷7sÔV¥pØ­e±ÆD�;Ú¨j°¸cž­Š£©DYUÇAÁ¤Ö†”§û˾£í­âxcv]ÇóRÏn³x#¡¦X¶ëeœUšfr””ŠBÃwúçÞj—ì6ùÎÏÖ¬Q@:“}HÎØÓŠtVñBr‹Ï©æ¥¢‚y¥k\¦þUÔì„a“�Ô-‚ç.űҋ›R_͈áé’Þ:(R¼úÐl®ÒPa§’¯$g æ¬MiÄ1Xw „L¬Ò0ëÀÍ] š’´îŠcN�9fcRKg ±ye@ˆíV( �i'Ô¥œˆ?xÆO¯l"… m±N¢�Jr–ì:t¢Š($(¢Š)¨¥¢€`RÑ@ KEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE1ƒ\pZ}Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@RdzÐÑI‘ëFàr1@ E4È€dºã×4‚hÏIþúú)žt_óÑ?ï¡IöˆçªßB€$¢¢ûDþ[Gÿ} >Óüö�þú- »·g�þú‹ylÇ qÿ� žŠ€Þ[³Æ?àB�¶[Ïxÿï¡@ÑQ5Ì´¨tÉëLûu®p'Œ‘èhÅ\^Û“)úR‹ËsÒQ@ÑP}®HÈö4ï´Ä"i7|‹ÔàдTk‡³ÿ4¿i� |Üÿ°hj*)n¡Ã�Ý6¡?Êšn�G¿l„gœþT= ¹P�¶JA8û‡4϶©Ní™  4U3¨ ë Çýú5ëÈ@u™Iìb"‹¡EfzÈu2ß�kö$pÎà4쥕ÿ ž8ߟLQý¿mŒùrãýÚ,­“ÿ ¶p#”Ÿ@!ñ·h¥úÅ^ŠÈ_Ú¶p’çéIÿ ¶ÜùSgÓmbŠÆ!„ãý~}…5¼K 2)<¶:RnŠ©§i:I×®xÅU‰ÚOÌ %#· ô$ЭQ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@>ÿ�<8õý ÖµdøhÄšÜúïÿÐÍkPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPŠWtã9Ë*Ü�ýZýbx°bÊD˜üÔÖÔ_ê“?ÝÀ}bx�Ä•mÖ?ˆ,®.’l¥Ê±sŽëúP€¯e¤E=¤nìà°Ï ¹ÒŒ±…ÂpKÓžiÉ¥›% 8ÚOÊœš]åÓƒ.QsÉsÈü(¡Q…tÅ:™ ~T)âÛ@=M>�Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Ï OG ʰÁ¬–ðìm‘ç¸SíÍmQ@ Š5†%Ž1…Q€)ôQ@Q@Q@Q@Q@Q@Q@ax¡IŽÕ» ý+v±üH µ€Ž‚^ï“BOçû0gþz6?:Ô¬ý ¥Ã‚ 9'ŽMhPEPEPH@=ih ƒ´Q@Q@Q@5Ð:=§Q@–LÑ]´DñÈükN¢û<~w›�š¥ Ò¤”�ÐQE…Q@!Pz€ih Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( �œ ž”�“Ò±¡†]bg¹{‡K=Å8߃ԚÓ[»w}‹?Òbçýª­ý‡ië'ýõGö¦1™ÅY:�šœ˜ÿ:Oí;,gí1þuÑ-1�Þßu Ú~™k�3²ç±sÍ]:•˜3¨¤¥“Ìg>õE#Ñ�Ìbdfô2´º6ž~aœ÷ÜhOíKùù�®:Ð5KÒæ3øÒ &ËËÙä�¹ÏS@Ò,F?Ñ×�sHêÖ àܧëGöµŽ3ö…ýh:U‘90�ÌÓ—K²QÅ´gê3LÿkØÿÏÊ~ѬØ@¸S޼—û:Ï�ôh†:ajF´¶o½gþ)Xk6'¤ã®>é ëV#¬ßøé©Å… ñø¤:}£›xÉÿv˜mXñ™H¡*iN³b?å¯þ:jËZ[²í0FG¦ÑMû§èññþÍ +.·dÄ€ÎqþÁ£ûnÏ8ÌŸ÷Á«BÎÙsˆ#ÿf“ì6¿óïýò(¨×lˆÎdÿ¾ 4ëÖôÐÿÀjïØí€Ç‘ýò)ë+÷bAôQ@ÿÛöddyŸ•4x‚ÔýØænqÂf´Œ1“ß"œ¨«÷T   ÏíØ$Á:¨êY1M>!´þ•� ZÖ ‚ô‚4Gá@‡^·>[ûŒŽ?ZE× c…†F>ØÿÓ0ÆzÆœÿ²(F:"�˜o¯À‡ýT�ôÅ^ˆ¨"ÞB:uªGEð¥Ú=å@+®}‰g+œÿ ¤“Uš4,Ö`uäV–íKH a¯�ô9}OÿZ�¯H’’; ÿ…lâŒSµí¤³} `ÿ*i×›?-·æßýjÚ*P( @?*ÆäÍÊX»bœ5©ˆÏؤ_®¶(  _í©ÉÂÙ’=³þ‡]”>Ì3ŸSþ·IŠÄ:åÎý«g¸u8É?Êœ5‹¶%~¡¿Â¶¨  6Ön‡KeÏ¡Í1uÛ­Ø6™ú+…oÑ@‡V¾ïûÛë†?¥55‹ïâ´üB5nÑ@VÔ3¸[|§ òÚ�¨ê§­¶;ÿ«?ã[ôPjZšòmÏýú4¢ÿTaÄ'žƒÊ5½Ea‹­XäpÜ¥7z¨ò2G_“ÿ¯[tQp1 ư@ýÎ9ì£üi~Ó«°Ú-È>¥GøÖÕ\ E“XWÃ&î=)LšÉnþèãõ­ª(¸ÌúÆá…ã¿ M•µ„o�E­º(¸Šu¢yžÚqþØ õkfŠ. ]hž¿øòÒµ¢>þ³/øVå\ „´Õ_–»œtëý)¢ßV)›?íîá[4Qp1…¾¨Øi¯Ì´ï±j#$]¿Ð°ÿ ×¢‹�Ž-µ#€ÓIïó¯øU„Ó¥ë%õÉö ô­ (¸RY^ù‡eÌ›B_¯éN:}ÊÇ”½™Ÿ¸fãùV�\ ¤Óî�€–âE\rVSŸåO�L�‚e»¸SžÉÚ´¨¢àPgÎIº¸Ç´†”é‹·âçþþš½E˜Óaï$çë+R�:AÝ1#ÖVÿ·E+��u§¼�û§ ¾îÙþtè´¸B~óyr9"FùÕú)Ü �a–DC:v#ùÔQéi»3a¸þÃúÖ…\ ƒN¶ÎJéóñ¨N˜»Û<ü£ŸÇšÑ¢‹�V+R¢¶ï½Æ¥{(L FŠû9fŠ@eÿc'Ëó¨Ç¤b¥\@Œ•Ú;ykÍ_¢�À¬,-ȶ‹þùÿ²[Ž�Eÿ| šŠ@VK(UÙ¶!¢ìém#‘pª±œç*£úŠžŠ‚+TŒpÿï(ãò †!Ò4ðO¢€"xUÊ“ÆÞý?jÿt~Tê(¨¤ £ •:Šˆ@¡w6ç9äR¬*¸å‰§­IE4 _''ߊu„•xLd¸Ç£‘RÑ@µ-PEPH@=ih £Q€ŠÒ›öh?çŒ÷È©h ż#¤Q�ø§lP1´céN¢€ÈUÏÒ‚ŠNJ�Ê�E7bÿt~Tm_î�Ê�E& £h# Z(œÖtÙ#�î¢PБ—P1¶�Ü4ú„Œç$ŃøŠèˆFAàŠç4˜ÖßÄ—1*íM¬ª@2¦˜%QHŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  ¿cûÛ�ÿ¡Ô¬¿ÿÈÛèßú­J(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÄñRîÓ£Î?Ö�ϸ5´£  ¬Ÿ6ïQ2+\t¦ER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬¿Œéë׉?­jV~¹ÿ ×Ç÷—ùЀg‡ÿä�öÚ´ë3Ãë·Mç.Çõ­:(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠŠéKÚÌ¡¶’„gÓŠÊð´ÂM4Ä<—#> óŸÖµnPËm,`ದEcøUvÚÏÈ?8ÿÐEnÔW7 m K!¨üêZçüO#obƒ1Ƕ?Æ€3ï5‹Ë‰²’4J>ê§õõ§O¥ÜMÜ÷dó’Ù-V¥‡L|—1oàëʵcyJF€~]ÇSk;ˆ`—ý"Ù&C×#‘ô®ÆÒXæ¶�á9Œ¯ËX¶ZEœ�ô´Q@R2‡R¬‚ ƒÐÒÓ#Š8†#EAì1O Š( Š( Š( Š( Š( Š( Š( Š)’Ê‘(g8€=Éí@¢Š(¢Š(¢Š(¢ŠB@ë@ EPEPE5äHÀ.Ár@îiÔQEQEG<ÉoI!­IEAjfegŸ XåP©]Ö4.ìTd“Ú€ECk1¸�ÌÛµ ù3Ô�Zš€ *�´âúF‘Tù¶ºnnçéW(¢«%Ð–í¡ˆnT;ö°«4QEQL’UŒ¢±ùœáG­>€ (éPZÜ‹¥wAû°ØVþ÷©úPôR3RÌ@QÉ'µU´¸’íÚU]–ØÂdrþÿJ·EPE„€2N ™QK9 £’OjŽÞt¹‹ÌŒ¹ 1ŸqíUpu&Ë®,ÁÊ笧ü?�^�@ EU>eÓ""„fG= ôNôëyd�šM»a耎[ßé@)§qa‚6޾ôê‚âå-À.çîÆ¿y¨I$H£/#UêMV‡Ï¹�M&è¡SòGݽÛü)RÙ¦q-ç,V,åSüO½[ Hû°]ÍŽw>•™eÀ¹•™•¦|y¯Ô þêÖ„Œ_äNŽO÷G¯ÖŸ )a#]ª?_z`8 3šqÇZZB2Éî)^ÖénEEr#;K‘Ãø¬DvOàpR¿Ë] q¬H1…sø â092äÿß4Àè袊@QEQEQEQEQEQEQEQEQEQEQEQEghCn‘iÜyÖ´k;Bÿ�=Ÿýr£@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@^$#ûPz1QúÖ�¸Å¼`tØ?•gx�gG—ýåü9­rÞ":ô  (¢�ò(i¬Hu¬‡ÓõLà_£§$C§j…qý¡üé�¯†#“NŽ–¬<¥ò·û. :®®r Ú®:šÒ¢¨Ä5$?¼ki�R)j���jžœ1¤ú+†º[Ûê;Ò*ë㬖�ïƒNÀlÒÌ€k[[Îk]Ùàã)ML°"k`½ÆÃþ4xPj�MLpdµúíoñ§Æ—Û[Í– ãåÚ‡¯¿4n’³¾Ïªa¿ÓbéÆ"éRFºŒcçh&?Šÿ�]¢³¯eÔ£PÖðÂã<Œ’qTÄÚóçlQ€}Wýh°¢‘�Sï0_©¬o²ëM“ö”SÛŸþµV“BÔ&�´·Q’ÝIÉ ƒíçjgýáKæ'÷×ó®sþ™Êsuìñòbž<9r¥ÆË‘¸=?:è<ØñŸ1qõ¥IA”eo¡ÍsÏ J’°IGÔmQN‹@”©ay,/Ÿî�èh Èõ¦´Ñ)ÃH€û°ªgL�Ù\JÀaËgšrév€°khJžŸ.Oç@|ø° •0zÂ�"C©¹ªséö@ò5¢EÉ ™?…QžK‹ §±qü&"n_ï/ç@u'�?Zäeq)ÿ�e‹¢ÇŠl6Ðnæv‹Ýccü¨°�uXÆšg„L¨1׿ÏC¦éò1yò@:îFþ•atí3•KœãŒ« þ&‹¤u+%871gýêXõ 9 sf¬¦ÒâV š@`rfÇáLþ̕٠zU´'<–|ñøPËꑜ5Ä`ÿ½Hš�œ�Š\FBõç¥fŦHVö&÷¸æ®Em¥„eŠ8 ±ù€ÁÐÿµl‰ N¤ŽÃ­8jV…7 —ǽE%¾�üP#öP“úVmŤ²ËåÙÙáïcn:ÖþÓ´Ý·Í\qO[Ø_vÝço\!¬3¡Ü±ùB�êÍV­t›È‘�Ü*„“F€h›ø�ÆÙïÓ…9.ãpÅVN9B*�ÒgäùžÊ1�Ö”h‘Ÿ¿srÜäüýhÐ pÀœ�QŠi¸…N ¨¦áUF‘müFf†VÅ*hö(r-ÔŸrM?Û-ÏI�ñŸ½P6© ©$cýæQýjQ§Ù… öh°;lñin:Aýò(Ð ù5‚[(õyÆ?J�ûe²yjyà!g'ò®!Œt�üS‚¨èü(ë7ŽÝ�ÏO%©’k7€àG�ûbÕÐb–‹�Ïjß¶B®OlDiÉ&µ2–RWž@+~Š.jYê¿¿¿ÛžÑÆ?¿yqªnfÇñ1äÓè¤EPUä�“:q…Œ~¹ÿ ±U¶‘y3õSñî   ~mÚ`È@­ZÉðâíÓØä`ÈH·N+Z€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ Çðæ|‹œœþüóZäàX¾ÏÙ§ÝÔÉŸÌSnŠ)­’ÀsHSJ¯RÍ:³g–{Ù ¸XAÄ“g¯¨Z³ ÇŸ;¬hLIÁ�ô'ÐUšdq¤Hv§�“À ¢¢‚e¸Rñä¦p ϽK@5‘\a”0÷¥$§´Šª¿u@ú GeE,Ä’iÝ+,Hú�ÁDlâo™�üµaØ{P§Z(ª²ßÅÜvÃ/+ž‹ü#ÔЪ(¢€ (¢€ *9¥ò”`eØáG©¤‚)[,YÜîb}€%ª3¿Úî~È„ˆÔff¢æ¥»™ÁX ?¾�pq�£¹5%¼ oÄõÉ'«äЊªŠ@ ©h¬ûëÖY­§ÏpÝqÎÁêhË]B³¬³#`s�­OU,tø¬Ô°¦~]Ï$žõfI(Ùä`ª£$šR@ ÉéKU­÷ÊÆâEÚÂ)ê©÷5f€� – ÔšŽÞa<~b‚Ÿ—=Ç­VuþÐr»¿ÑTàãþZðþut -AywœI2{*ެ}-ÕÌv�4²œØu'ÐUK;WžE½½ÍÇîãíÿz½3D�"ír+è})ôUKË–B�[àÜIÓ¸QÝ�µJnWí"Ÿl÷©ª½¥ªÚÆ@bîÇs»ucV(ª–³=Ô¯0ÊÀ>TÏñsË…,È×2yA¶Â§÷„XÿwüjÈ €(i’H"BÍÛ§¹ô§3RÌ@P2IíU#�®¦ËÄHs ìÇúP¨ËÔȱ�Ú•˜"–bI¤wXл°UQ’OAYR,šË¤¥ˆ=z~žÔ¥o:\ÇæG�¹ :ûÓ¤�&VnzЪ�Ä@DAÇ  º•îX“¼½¨Ç=j8Æóæ°<�”žI 0$uç¥:š*HëíQM+åÁƒ!ê¸=MIkm_Äž§ë@¢�°H�WžwÞ°Û®]ÆwãåAê}ý¨..Š¿‘nÜÇ¢�SVJ¨ w7sêj;kd¶B©–$噹,}éòÊ�Æ^F ƒ©=¨ôTF滌Ñã×p¨e™gÀI@9y3Áö<2‰”ºýÌáO¯½IQ$°*…I# 80¥I\ì!—¡#¥IEA=í½´ˆ“ʱ³ýÐ{Ó_P´O½qÈÏÞ  ‚Œ“�KTmØßÈ. ‡÷J‹ý¯ð©.5 KYDSΑ¹èЪ*¼Ö×.R ’F@©e• ‰¥•¶¢Œ“é@¦HåFeÏÝV-ZÊb¢9Ã8É«�yÉë@‚r{šZ«}‚#\ í´¹æ¡MV+—ò¬ÁyáˆùG½_Ü ‘Ö–£‚! {rY‰Ë1êMV¿Ôá°’5™\ù™Á�@j¬`]L·$Ï•îznÿ ­àÕs !Ò1ƒ#ñÓÓñ­%T€-˜úåªJñ�û��r1ÒŸo~oÛdº(ûÎÃŒ{S°‘Ä‹¹y�­:¢¸™m­¤™”•�IÂŽMfG¯ ÕÚLN2)«,‰ lîpª3T¬’{‰MÝÖäýÔ_Ý\u>ôØ-¥¼”\ß (9ŠÑ}ϽK}y5« ŠÒK…`wíL „€ 'R)¡±×¦j½¼²Ýç[´(;1åªÕ +;í—ÆWEÓÎÀc ÁµvuRdmÌNxè=…9F¸êO4“J�DÒÊÛQFIªWW—±\†Á¤ŒËMãŸÂŸn—IzŠ�OÉ9üM0Þ3q º�H?òÉ}Áëõ5r£�¤X¡Pò%Tœk6;ÍY˜°EÏ}ü Ôf9Ú½}})ÔÕõ=i·w�ÿgÙæãåßÓ>ô€y!A$à¤Õ8Óí’Çpàˆ“&4=Ï÷�ô¢(.f\_ŠõØ€àýjÔ›ÄMåß�”™¦ë9Ðêr€Á…šsí)ÿçE¼Z„û—P0¬_Ý‹9oÇÒ´ p¤�Unƒ\–¶�Ê fFqéøÕe‡Wóœ5Ì>Y$‚�=1Wí¡0Äœ»žYÈêi€øÑcEDPª£ª^K;·Ùí‡o½)éÿg“©}¥ÏÚbò àlù”UÈbXSj÷9$õ'ÔÐ[@–ЬQôQÔõ>楪—‘^HTÚ\$C0dÎi¶–÷‹.ë«‘"�¨Ç4€¸É$ç==©—Çm K+mUýj;Èg™[Ü6I G¥E ƒoßw;\�r�”¾øõ ²ŠW‘î®2øD?òÍ}>µr£¸�å�Ò9 nÊ@p3�zÌ]"ç ²j2²¸È'ñÍO3=ü­o +ŸÞÈ;ÿ²?­]&;x¹*‘ ú)"…!„EÚ `b¡ŠÈ+fY¥Ÿœ�!È…0囿Y$�¡ÊÆxßî}½ªí ðžÈž[nžØÒR éKEV»³f2f–=‡?»m¹ö41œ*ŒúûRº,‘²:†V ÷*„\(À§P PM+1ÂFOÞî�ñ©f‰f‰£|•aƒƒŠªúU£¤(P„„å@cÏ×Ö€–ñ<)cèyøÿúÙüêÝ @`‚–€ *8íãŽW•W2?V<Ÿ§Ò¥¢€™PeˆÔšN*9àŽæ?.eÜ»ƒcÜŠ–€ é“×ÞŒŒã<Ñ�»8ç¦i6®ýرŒ÷Å:Š( ¹Ô;¼FÇf>˜\WE\Ú ž& ±æRñΔÀé(¢Š@QEQEQEQEQEQEQEQEQEQEQEQEgèò³ÿ®B¯Õ þ@öYÿžKWèh¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠËñΑ/8ù—ùÕûQ‹XGû üª‡ˆC6›µŠDó­5TAŠ`-QHŠ( Š( Š( ŠCÒ–€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ )‘éK@Q@ �éF¥-QEQEÒˆI%A'ƒÅ(U_ºú Z(¢Š(¢Š(¢Š(¢Š(¢��' ¨á¸ŠpÆ' ´àãµKEPEPEPEPEPL*w;v*ó§ÓI+žqÒ€3´TÓ”)œ’=kN³´H„>Oñ£ãÐçü+F†EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPXúvÝÞb?*×5�áóò]âcL š¯u{og³íÞp¹îjzkÆ��è­Ž™Å ‹ØÿtÌ!=\ ì*xãH£T�BªŒ; Êmu™ö{;™‚*|¬}ªí�N@|­&AÇñSÛë¶I» í´í8SÖž»µ5VdhíHÎÖàÉõöþu�5ö§ ½ŠD[Ò=ÙüiW[¿ÁP�pvÆ€5gÖ-­.ZÞd•6�†ÙòŸ¥!×mHÌbI9Çʵ˜ÚåÉÈ1DØ‚¦�¯p3åÙÄÙ  hVY®¯#hÌqŽJŽÿ�Búä"™¾«·ùÕC­ÞoÇÙ@»XñKý­s!aödeíò“@¿ÒuTzÖØõþûÿ€§\êé­²ZÌão˱r?:­ý¯tŠ3j1ì“ûbïv>Ê í€Ô!Õ®¦Ê[ØÊ®z §a¨Ãdò-żßi',¸º�ùBßcÎ=ˆ¨Íýä„n±B}ÔЋ®ùΩolÒ8ÀaZ±î( €=@íYiq¨"n[”ŸN)âöüpÖ‹ŸbMhÌí.è›ÙA!}k-bþ@âZåý9)Ôo—­¨9è9¡µ ð@û çêhå’JÙ¸¹eqÂpzU%¿ÔZîxÖÐV!wdqõ§5æ¤yµ�ý¦¢ FîpY F@HÈÏQ@ñÔ³�Ò¿,ßÓéY——÷ðß8ŠÝŒ \‚{š°n5,qk¶Zƒ6¥�‰Ç©ÅWµºÔîܦĉ{±B0=½êòÛ +Y>ËùˆÎXòíêM@³jŒØ0B¸îI朲j\æ}¾c@Eö´³�¢ÿõê嬗.²j$*¡ÊD½3êi<íP±QcßÎ�æjj¤¼p“þÎhÔdÔã•~ÁRFG;� Óa‡R™€¼–4�ø–1Ë{f�\ê,p°(÷#ÖŸUŒ|ÐÄÇ?   6B")ã qÀ¬ÅƒZWÚn dþöÜrË«0'É�Ol÷ýiUõcÁŽîM>ÚÂRâMBA;©Êz/áV®–g¶‘mØ$¥p¬zT·ê£��±öžiAÕ{ˆ>”^;mh€²ÜÆ9å—ÿÕZV–‘Ú«ËHç.ìrXÔÔ°8‡Þ£WÕ‰ù£ƒõ  ·I,–Ò%»ˆå+…cØÖZYj턚üîÈ9þUv1¨ïù;ß`sM¹]L£ w· Û ÐØÐF�G8îzŸzƹ°ÔÞòi#¹ÄL~UFF¶:ó)ß|€ŸCÿÖ¡ì/íížyïÝÚ1»h'bÏI™dY/.LìÞJŸ®jÍþœ×’Fëu4CÁ©4ë¿¶Z¬¤a³†õj€3#ÑÇš¯=ÔÓ…þ<Ñ( èÇb�E 2¬ô8mœ3M,À…sÅjÑEdË£IçK,²£HÛŽyéRÙég”K%̲¶A?)­(¬©´8æºy¼ù{dªÖ­ ­´v°ˆãÎrrMI" #d9Ã)ÔPM¾�J|ɦ”ö%ºV�µ¼v°ˆ¡]ª*Z(¨æ†;ˆZ)T20Á¤¢€2ÃÖ¨Nדo÷N1üªêØ[­¡¶Ø G³sÏ­Z¢€2£Ð-P`¼¬¾™ùV…µ´V°ˆ¡]¨qœÔ´PKÍ6ÖõÕî³(À!ˆâ£‹G²‰Ã,Y# f$~U~Š@008É`Ša‰cGí Ô”P0Ú[Û’a…#'©QŠ”€F"–Šbäh§Ô(ú( eV`÷ŠŠ¿u@ú uSYÆCqšuŠª£  }-Pf‰$Æ„ž¹iê¡F=-R`RÑ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@s²ãþ1ÔbUü~Zè«�¸ù|Lƒœ3©ÿÇúÔÐQHŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  ýþ@ö_õÅ•hV~‰ÿ {/úâ¿Ê´(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(7\Ø…S†i/×5¥YúƼ,Ýt'ó­ (¤=+>Z)µi–Ê–Þ:q@4R3RÌ@’OjDu‘C#SЃ‘@¢Šl…„lPØ8Ö€EsÚCêOª7ždòÆ|ÀÝíŠÓÕošÊc»3@¨®oJÕ§{à—I>_¡í]%QM2"°RêôòhÔQEQEQEQEQEQTõKƱ²i‘0 zrhÊ™¾´úÏѯžúÕ¤•@`äezРŠ( Š( Š( Å-V¹¾·´8š@¬FB÷542¤ñ,‘œ« ƒ@¢Š(¢�R+«çkŽ :Š( Š­y–Ï=±¼à`fŸku Ü~d\àãµMEÉ%Ž <ÇUÏLœPºîFSÜb¹�e·ÔÉ DÚCn8ÍtìIC°òG¸«kinï<•#Ì9$Ÿn´Ð<ºÕŒC&Rßî©5z7YcWC•a�}Ea¯‡AOžàƒèk[Eœ1[#}Ñ…òhÅ7?6(fUf{šŒ¸,¬­‘žÝèj@iiŠ9cêiìÒÔH~gõ-QEÜݹä, þ&•¢s)a! Ž•,‚qƒ—ØqéÖ™V]Êúæ‚y–ß3cüC�šÓ¬}�m¤…HcàûZA¥Fh‰¨¨¼ÖÎ6<ÇV‹•’ÑQ4Ä»Iç󂦋+&¢ ûRÿtÒ›˜Á žE ä—bj*!qþ,}iáÕº0?�³C¨¢ŠQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE%cèzôr'9­šÆÐÏyŸ½æçõ4ÀÙ¦ÈH�ˆêÅ:£›ýKý)OCrúL zœÿèF¯Öv…òéËòÉ_¯ëZ—;w úf˜ IøRÒÒ˜ƒò¥ìQ@ @´PQKEQE”´PEP{ä2YÌ à•85�á©Ù8Ÿ?˜ÍjÎ3€wSü«#Âî ‰AÔm'ñýj`mÑE€(¢Š(¢£šx­ã2LêŠ;“@QPÚÝEw™ %sŽEM@Q@Q@Q@Q@A|…ìnu1°ý*zd˾‘úPO†NlçÏÞórï‘[5�ác•»³ó)ǧ¿@Q@Q@Q@Q@Q@Rb€Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¹û€á#B8ýâòÝ®‚¹Ë…aâd$qæ)ü6⚣¢Š)QEQEQEQEQEQEQEQEQEQEQEQECDÿ�=—ýq_åWꆇÎ�déŠÿ*¿@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@^!8Ó�ûã¥ÝU³|B ÓøìßÐÖ�¿ü{ÇþèþTÀ'$A!vŸå\ÿ‡ý±ÉûÞ^üEtl7)_QŠæ´cö}HÄã%9 ‘•]J°HÁ½sbvÒ59!·Á·gË'�œtôë]²¬1´Žpª2k—‚6ÔuPOñ>öö€:k›¨m#ß<�ð3Þ–Þâ+˜÷Âá×Ú±dªÊ_Ø~u_ÃQùš‘|ñdþ|PVÜ Õ[û䲃Ìa–' ¾¦­ÖˆÉ?tœ5K›¤¹’b¶å²Tž{ ÝÏj©¤2¶—nW&=GZÃ{§¸ÕÕüï)D�sŒ(ÿõPQš©©k5ßÙ£rÏÏAÇy¨gÕmxÖq½� Žç‡£M µ÷™pvá èh°MÍÄv°´³6ÔZl3A}äÄ‘ž#ùÖ>³ØÅ$LÀ¹bTŠ,ëÍodÑBFñ´`RêkmæÆ¡°FAô¬$ìðKnÑl •àæµ-¢i´˜£Ÿ;Ú!»=sŠdzͼ—1B3ºA×ÐúUÓˆZãUŒ… ÇÚ€45Mm­.¾Ï +fnÙªö ‘®W�6±ÀqÆß­Æ“q-ážÞ?0IŒ€yqU$ðõöÅ+å’ÜÝ÷hO\º’(c9UrsŽõ†#1ÛÜÊxVqŒûµcPÓ%¹³Š8�|Ȇ>oâ⥴ÓÞ ,Ú³�Ì%{@äÚ­ìÒ—32z*œZ:.±+\ {©7‡û¬ÝAôªŸØ×¾c'•Ó£d`ÕŸøFç¤è ¸ ñƒž(ð  k bâÔ±‘šd?ÂíÓèi5·¿ar¨V5M˜' çúŠÛ—C³™cܬ…@¡ÆìzÕ«{ {hL1Æ6H<çë@º¤÷[”bŠ£cª[ÞFî �ËûÁøÅ[GŽUÞŒ¬?¼ 2ê#5´‘©Ã0àûÕ-gh¤ŽBK#w­%Á ×&o¥·¸¸ŽÚw²äuàÓ­¢²ôH®ãŠF¼vmí”V9 V¥ *$¹†IZ$•Eê ò*ZB2¬Ÿ H'à ¯åñþÏÿ®µë?LS—0±2´ƒ„Óöš¥µÜÞTE·m,2:�òjís–,ä›AY”bk£¤ MV;›Ù­LmÆÄz6=*ýs¬ù×CDp £§Óú֥‚92ÎFp½©�Þ®–×ËhbvfÇÌÀÍSטµ¥¿‰­4û6¡L_t‘ÊšÍÔUŸLŒ“’’ü讋pmnÂ1;e‘ïØ×O\…ÉÄ�ã¨Dµ×ÐÀ(¢Š@RÕî×O’HÎ 铊筵+Ø¥Þ%gòäßÖ×v•qŽ ?\¤.Ávûæš¶‚Q< *ðg•%g$ÿÙÚT-*œà©«6WKw˜½Žô4€±Ed뤖r$PÜFX·8­yL°Fì0Ì ‘é@ÑE‡áØü‰ïá`7£¨'׊ܬ­1umPŸº]1ùfµh¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(  QEQEQEQEQEÎjE—_�”c.}y®Ž°5F¹‚Ñgþú¦€ß¢Š)QEQEQEQEQEQEQEQEQEQEQEQEGFñ(³ÿ®+üªõRÑÿägÿ\WùUÚ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÉñ ÿF‰OBøÿÇMiÂ1 öEexŒí¶�� KÈü j[Œ[Æ3œ ç׊`I\î¹ Û] ¨¾Ulr;5tTÉbI£)*‡SÔHR[ÛÍMÖ,=•F}Mt:nž–1ñ̬ö©íí`¶‚%O ©©�Ìx¡óuƒ÷#'ó?ýj5ˆËiÖ¯"ûd?­m_ép_²´»•€ÆTö«+ ,+ PȪ3Ò€9É–y<1l@bVLà ’¹8þ•R@‘éöÆCûÆf%qÎÞÕØ€vÈë6óEzÞi$6Jj‚ø[gìËæÉl±©5Xî^8®^�*�áFpkoJŠe�F«¹FHç½\¢àqWsÀ±É0*däg­tÒÍ$ú$’(ýëBx¸¨<@»­ceÁÛ'?‘©tß§ ’pì9úÐg‡^F[äÐ}ùªšE‹]‹˜0Q–1†aѳҺԊ8ó±wœ fª_ê1X©4¤d(ï@�¥2h%nï¡guÁé“Iá•â|uêjÝ·Ûg³»’÷å‡bc¨<;þ¾ãÓjÿ3@Õ�ªécQT"Cˆ2Ö´h¤{Qggçhäúžõ—wáÿ6àÉ áÿ .q[”Pe®‘«¬ŸëdØtúR]h�\ÈL.z•ð­J)Ü VtVVÍýàrKz„Ò,’Q �w‘žƒð«´R¢Š(Ši6ÑÝý¥C ¸ ñššKYeód�ýH«PYÛÏÇ,(è½*H¢HcXâP¨£Ôú(QKHzŠZä5åòµ9‰x—ÿZº›XâHQ¢�P2ƒòŒf¹ïǶú7ìñãò'ükoIs&™lǯ–ü8¦Ê(¢�)h¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ ¡©Ie‘Çž9ô88«õ™®¶ÛhN?媜úcŸéM%’,w·C?4›d#ôþ•~±í&ݬ&öä¶Üª07VÅ Š(¤EPEPEPEPEPEP$qÈüª?³à|ŒEOE)4VS4cæïµ ûÀŠž˜Ñ£Œ2ƒ@ù“ÝÊ�÷X}V{PH1�´Â—’U· ˳.QTþÚSã9©£¹‰ñ†úá%КŠ:ÑAEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPYZ_ü„õ?úè£ô5«YzQ#PÔ”�zJÔ¢Š(?KbÒ^n<¬ÅÒ²µrmõq(ÀÊð}2­m9Oy!#l’œ~J‡VÒžúxäFQŒϦi�Ï]£DJy›Øu4ºEá´½BÒŒœ?¡·{¤Ä÷Hb;7uȨß@·bÈË�½�ê­â[3ö”¸Q••vŸ¨ÿëTZ®£q+Ä‘ÈÉD­�ÆI×JëÉåʪÊ{Pͧ[ÏÇ$*ýÜqŠã’æ{vß2°`×WªÀot¡Ÿ¾ IÇãÿ¯RE¤YB¬Šœå¹5l¨o—c @J -»Ž;Õ‹_µÃt-Óz4§fÂH»¶Š5ÄQ¢sŸ•qRl€HïŠæ­®o4»‘ Æò+�»3ÓéL»‡È×Iqò¼ �pqýk¨hÕˆ,#¡ÇJ‚âÆ ™"’U%¢9SšÆÕ¦–ÛPŠUwUÀ$ךn¥{$ÑýªÒY'(ݱZ×úlwáDŒÊW¡Z}¾ŸŸf²çwñf€0t¨ÖÅ�ìÌ?Õ�ˆ-ŸÿUX_ÊfEò“iny=*ÝÞ‡ò!‰ü¥Q´®3Åè’ˆ‚nŒ§ƒ÷‡½j …‰Â�’}«6)Õõ¤òˆdx²>«ŠÐ‘…£ •ý+ŸÐض¦›€-Dˆ"€-j–“Ep.í²yËÔTSë2ËÔM�¸àòk~¢6ÑnÜ+zŽ(¸ZVžþwÚ'Hû«ýk7\‡þ&ÌK$*>‡®© À¤1¡$”RO^(š²ûež§'”Ç ÇzÔr\Kn“ZJ¤�ÛƒÕÕâªjVÂæÖDà3.zP'§xp0±ƒL tQE (¢€ (¢€ ¥ªYý®Ñ•@2/)ŸZ»Eaøjf+=»ç1¶àlöüÅhj«3i³‹õ›xþ¿¥ZTEfePº�:Ó¨‡ûT«Ù÷~ïvìwÍušL&:a†#qZ°má-¸Ä…½vŒÔ”À+^¶”L·1‚T.�áÅoRÁ�kdÀÑܦæÚFáßëRxq•žïFÀOçSÝèPNKDæ=€ÈüªÎ›§­„r*¶âí’qŽØ¦Ê(¢�Q@Q@Q@Q@Q@Q@ih¢€0¼Q6öòc‘!\ûÀTÞ—}ƒGÿ<Ü�Ïšµ«Ú5í‹FŸ|Ëõ‡c5¤r´Ãi�Œ.zb˜”QE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ Ì××vŸœàþU§YúàK›=¶ÿ1BÓ-â’ [¿¿0¨ÝžØ­ ÎÐdó4¸†yL¡ü hÐEPEPEPEPEPEPEPEPEPEP ÔUÞÊ&è6œçгE)5±Aซ˜ß vÍ;í2Çþ±?J»H@#f‚ý¥þ$B·Q±œz˜zÔ/kãÚ£ò%ˆgÚ�Z/f[¢ª­Ã¨>bž*D¸�»í>ô Á¢j)¡–‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ²4ßù j8ÇQœV¶k'MãXÔ‡ºÿZ`kÑE€ÊšââÍÊGg$ʼù€ðj¹×.1ÿ…q×vxý+h‚d_LÓéÜqõ™œ1&G àñPÇ­O %„NíÇõ®£h#ß&?ùæŸ÷È¢àsgZ�IØ#ÜtýjOøH&~î<Ôœd×@"ŒtE…TxË^?Ù\ ×®N H€?Zwöôà‘äÆyõ"·LQ‘ƒ‘ô£É‹þy§ýò(¸?Û÷[w tÇ®M1uû–Î8û¦º0  úP‹�Îzéz¬\ûb”k×ÚV<žGУo¼Š~¢—ËLçbþT\{ûzç‚2¿îšOíÛ´#|qóÓå5ÑQÑ@ü)v�AùQp9áâ €9HÉzñHºýÉ „ˆ�Á×C±º?*6¯÷GåEÀÁþݘŸõhéÁªK4-4q6I8À´´€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)1ž´´PEPEPEPEPEPEPEPEPEPEPEPEPEPEPXw¹ÿ„‚8ù9Ϲ­ÊÂÔ°5«|’cÿÐ�4íQHŠ*&¸…>ôŠ?“{ÑUN¡nwøTmªB¹¥rÕ)¾…ê*‡öš‘‘üM7ûS' .‡ìgØÑ¢¨%üŽØò°?�^9l,DÓ¥$[¢¡—�ÎÒ¬z-Ÿ|g=�ò»\šŠ( �¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦—ÿ ËOúâ¿Ê­ÕM/þA–�ÿr¿ÈUº(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÈñ!Ùʤýéõ5sJ9Òíý2_åN¿·†âÕ’àe:çÓÞŸi·´†Ò4 ù `MER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ªZÈΕsì™ü©$Õ­b‘‘Ì€«m'Ë8ÏÖ“Qq>•pbù�CÛ¨¦/ H6O|‡üøþ•¹\¿‡%?ÚL¤Œ4Dï‘]E (¢€ (¢€ )»Ô>Îwc=)ÔQM+ó†Üxcµ:€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€€zŠŠKhä9 ƒíSQ@Ókb§Ù 1ÉùÓƒÍÃŒ�Z³Es·¹Ý!á¸5*º·Ý`i¯ o÷”T gŒ˜Ø�c@íä[¢¨³\ÂÆáÓ¦jD¼Sþ±J‘@{7ºÔµE5\eH4ê Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ?¸â²¬ÙF·}°º¹ã½ZÔ5K}=•g–W#ó¬kmRõ9î˜G69ôÅ0:PisY?ð�ZÛ¼ƒûÃ¥:ìxŽO§¦#4ìÖ/öì+ŸôwÏû–-u$?ñìàû°¢ÀlæŒÖBkÑwA"‘êE^ˆ°0zò8  z+ ëÐ�ùa/æ?Æ—ûz ¿ê¤'Ó"€5¨¬ŸíøñŸ³È®E5|C h\¹È¢ÀlQXíâ(Bä}GøÐ|E?ÔÉ“Ó$ Ù¤¬q¯¡ÿ—vüP<@˜ÏÙÛþúX Š+þ8Ç nàÿ¼)Gˆc9Å»�« @mRV8ñ’·`{üÂ�øH# †�”z–ÀØÅ‹ÿ DŒ[±Ì)[Ä+’»`ì(jŠÅ Où÷b}�¥:úà‘m'NüPÀêy¥¬E×þl5©üšCâ!ü6ÄýZ€7(¬#â9û)ÀêKRsƒn3þý+½Eb®ºN3lsÜéúTMâ 2v@„V4ìý‚ºíÃE²ûõ¥þݘ5ºäô4»Eam]dƒn öàÓNµxÿGBIþëQ`7è¬í›ÜœZ�ûá©ßÚº‡_±ñŒýÃE€Ü¢°†µwŸøõÏü…/öÕÑñèsì¬iX Ê+ u]@œý“+þãRÿkß6JÚqþëS°”Vö¦¥€~Â}@4ôÔïÙ 6d7l¡¢ÀlÑXÆûUþ5o 4‚ÿU'þ<¿ñÓþ4X ª+ouRú÷ÿ9¤–÷T ò[=6ñ¢ÀlÑXÆïW›EAŸëN:¶Üµºþ ÿ×¢ÀkÑX_lÖ"Øÿ\ÿúô­s¬Œ sè£üh°”V»ÖAæØþçÿ^�ö�gh"<ôÛ�ëE€Ú¢±DÚÛg÷1�¨ãCÍ­1 9ÀþtµEcyšØçÊŒ�Ãüh/­c„Lè2?ZÙ¢±XëDg =€Zöá>Zû`PÕ�×3ó´@~(‹XaÍÄ ÿÍjQYRG¬.6M ñÔ.)¢-e�3Ä£éš×¢±Ú-iGÄÇØý)¢=pËH�×á@TÝëœnô¬–·Ö‰8ºˆÀúÔ‚ÏWwÚâfÏ÷JÙ¢²<�d¾>Ñ_ï?›ömdI�tŒ¾§Ë³Ecý›XÎ ÚmõŸåR› üq©¿ã¤�Šlõ€Ä-à`÷• e«ukÁŸ¯ÿZ˜TV8²Õ¸ÍòûñÿÖ£û7Qδ[õ  Š+4íL�ŸPÇÓ&�§j{¿ä#òþ4³Ecfê]¢HüE;û*ó ÿ2:õÿ×¢²#Ònƒ~óR˜§·œt™ÁÂêí÷94€Õ¢±›H¼#þB2g<Ÿñ i{Nuw}N?�06h¬…Ò.�Ëj2ŸÏüiÿÙß~ö|û1  J+è÷;u ÿ�4hrŸ¿¨Mÿ¤Õ�ý†Ùæúo”è`ç7s~tÀ×¢²_BB‹²â`é,N EÐcÚCÜÌÇÔ6)¯Ed 7dÝÎG¦êFÐCþ—1ôÉÎ)�±I‘ëY+ G´‡º�¸ãæÆ(>„žn'üé­‘ê(Èõ•�lŸ~Iœc€[§Ø’D“øiî_QùÒoQÕ‡çY« Y ù�ä9êÎ¥+è6l~_1 oñ  -ËýáùÒoOïγ?°,ÀÀó@ôßHÞ³#¥ð*ÔóûëùÒcd_βLJmûócÓ}Òbãý¡MmNÉzÝEø6j!¢ØŽ�ÿãÆœt{ÔÌÐŽ«b?åå)¯`N>Õ>çŸØöYÿS�£‘tÛ%Ñß4Ïík gí)Š?µì?çå(M€ÿ—d§�:Ì‹h†zü´ÕìFsp8ö4‡Y±ÈÄ۳覜4‹ù÷Sõ&“ûÀ˲þf€ m~ÐÊ}öQý¿iýÉïŸþ½Ze�]¿fB=Æh:]‘hð}©�TëöÁr#”þüiƒÄŸùa/éþ5piV#þ]’œ4Û 0-£ÿ¾h:_¢–ÚFÿ�T^ý/u;yÕY~d]§·Íÿ×­ÖÒ¬˜mÓž¸¬‹ëK{Kø¶.Qºõ;¿úÔÑÑE€¯-¨•÷4Ž ÑVÚ1ÿ©V“îÆ‹ôQEÀÄûL!�Žþî1œ�ÑîSúTÿlI˜/ö“)_H±ŸÎµð(Àô¢àd �¼ Bvàù9þ•*Z0¿m˜åwnò0•iÑEÀËŽY”›Ù?Âöüš¶.£T]ÌKýÂ3øUš(»ˆ¶Ü°ô%Hž³#²EIE "i•T¶ã°Sš‰u÷ÇÖ6Ò­Q@Eò*b˜c¡1žj95„ÿ¢Ü0ìBu«ÕÄ"â#wLÿL…ò• !œ‚3þ¬ñíIöã…"Öà‚p~N•_û#íWÿµH48G&âäŸ_3h´¼ÐÌœãæJStlG!# ÇZª4[p�L·¾L¦”è¶�‚æf9ÎL†�´'véôîE4Ï>ß–Øî÷pE“mm†`¨ó[üjccܤíé—'úÑ .°„Ȫ¬:�0p=j8¯·+y�nð•”i²¬s“l„ûóN:m‘R¿e‡ý�@½ÄQ i¤Dã9'Š�5 93²æ#�ö…iö±}ÈqŽyâœlí›­¼Gþ(ZîÝSy™6úæª�nÁIn�öšµ¬Ç j}”U[­ÖêS#ïV=vœ 4§\±òÕ�Ñ E'ˆ­øeo¢Ôé¢X§ü²'êÄÕˆ,­­Çî¡Eü(=|GlÃ"ÿø‰X~îÊá�ûµ·€; ZÅMzF`�r÷Ú¤ÄäŒi—EOCŠÖ¢€3¿µ /Écv[Á�Ó¨_vi’x%À­:)š.õ3X¢�x (éT†½r­óÙ_X˜Ÿé[ØÆ8 Å00¥ñëÊiÓlã–ú ¶uW0£Ge;;Wiãñ­:($j:‰C�1·vù¸¡o5VR?³Ð1ü­kQ@;õ¦ ˆ­”cœ±§ŸížÂÓ§©­:()Y--±öÁâ�Ǭ’}ýkQEÀÇ6úÉcþ•Ðõ© ®±’>×½•lÑEÀÂ6úÇys�GÔo²Äƒ¼¯ e×CE˜¶Ñ¯Væ7P!*s»wJéè¢�Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@FðFç,¹©( iµ±XÚ�ŒFE0}¢Óp�\¢‚¹ß]J©z§‡R N’£ýÖ4hÿyA¨Mšç*ÄP?qùhª{."?!Ü)ËvW‰ƒŠ‘ôÔµEEñÈ8oΤ †šÜZ(¢�Q@R�œf€Šh`{Ó¨¢Š(¢Š(¢Š(¢Š(¢Š(¬ªÃ ¡‡¡¬[KxŸ^¼ @¥F8ÖådÙàk÷à ŠO½0-¶™dÌXÛG¸õ c46̨Sn˜8«tR“i6-÷­�Ò�*Äãý2;ÕÊ(£i–MÖÝ?*A¥Yqn½1Þ®Q@™dfN=EIö;sÁ‚?ûäTôPaaj½-ãÿ¾jV‚'ûÑ¡íÊŠ’Š�`‰F4Eæ�a‘H÷ê(knD1ƒþè©<´Æ6.>”ê(3M÷¢CõQH-á"$ýÑRÑ@ 0ÄNLhOû¢“É‹þy'ýò*J(1#¤H?à"�&,çËLúí%ß-ÈUÏ®)v®s�Ÿ¥-Ó’ªO®(òÓû«ùS¨ ìSÕGå@�DQøS¨ Ú=&Åþèü©ÔP`zQ�è)h Àô¥¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+ \¾µ ã¡?ƒñ­Úçü@JßZ°ôVÐQHŠ( £�KBàrqÅIENÎåkI[eG ~µ�+;Ê<òG¯« %sÉÎ=)ïH0ê{ÐÍ£QFM¤gÎðEal· ïSX\‡ÀÇO¥J¶�)ÈŒSÌç `ûPpq°ç‘Q “ÅeH]îYâæ=kT¢”ÚGËéU�—$…A T¥Þåhå¹™Œ*ØÇSNšØÀ î$žõrÞÙ`±êMJ@#‘AN­¥îìR²�‹ùlr1Á«Õ VÑBÅ‘pO½MA”Únè(¢Š (¢€ (¢€ (¢€ (¢€+Ø ¶6Ã9ÄKüªÅW°ÏØmó×Ë_åV(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¤eVûÀZ(i;FÒ}*²K&9Iö5vŠ U$Šfiã?2dR‹ä}JÕºcŃ Ð>h½ÐÔ¸ŠOºãñ©sž•U¬c'*JÔFÒhÈ1>P>X=™~Š£ç]G÷Ó?… ¨cïÆGÒ€öRèZxƒtàúÔ/4°}åܾ´å½„õ$}EH’Ç0!0î(œ~% È.¢œ�­óªzÔõŸu�·&㟥\�Ì�«½è Å%͉(¢Š Š( Š( Š( ²m9ññô�ò­jɵx†ó¬k‘ù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‘ŸLÒÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE'9ö¥ Š( Š( Š( °uæöN6¦ZÞ®wćeÔO�ùdßΚ¢¢šŸq~‚�HŠ( Š( Š( Š( ŠCÒ«ZNÏ”“ïô¢ÚlµEPHQEQEQMVÜHô§PhÙÊ+‚èÍ>±Þ6G’D?2þµ§o/� ¿BzÐkRŸ*º%¢Š(2 (¢€ ³Z@Qÿ*ž¢¶ÿ�x±ýÁüªZ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)ÆyÍ-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQERSÔKEWx­—ï*Šˆ\[@[Ê^O\ �í‘É-ž}èKX‘·÷ ÕJ6Õ²©I®�K.ÔÕäPˆtê(&SæÐ(¢Š (¢€ (¢€ (¢€ ɇ?ð“\ôÇÙ×ùÖµcÃljçëÌ#úPÅQ@!8žÔµWR›ìöJvŽ™ü(‰ªÙÈ2³/ãÅ?íöÿóÙ?:DzÑaº‰g[‰·ðàqƒWWB·IOãŠz}n¡c�"ŸÆ¤¤pÃó¬ïìKlrÒÿßT‹ Ú)$4ß÷Ý¢eN~aǽCöë~ò¨ª§B´#¬¹õÞjðúÃ�Û#&�¾—öògl‹Ç©Å¨[&wJ¿‡5E|? ¯Ë¿sÇåBèdo�Ø  f�º5R3æ­/ö…¯üö_Ω?‡à8Û4«�pi­áè�ü¼H?F€h ûsÒU©>Ñ:óïYËáûP˜g™�®üT‹¢Zùèàf�½çÅŒù‹ùÒ}¢ùè¿�S:-®NÓ"çÑê3 ZŸùi0ÿ�Q åÔma\¼Ë�nj¹×,BäHOÑMV—Ѿ6ÜÊ vÀ5øb?/乓Ìõ `Ñ [\±\eÛ“ýÓÅZžúÚÙQ¥•T?Ý÷¬ÆÑmmle33KµIÉâ²,-£p!3U\úœ€;u‘£SЃÁ¨à»‚á�a•]�á€íKovÐ$1 " PZi°YÜK4[·KÔÀç›@â€*éz’ê1»ØÈ@#9«Õ™}}o£ª$vã2d…@¿ëW­ç[›xæ�î¸È¤´QEQEQE!zÕ;yZ+†‚BHþjíPԆëÔPkOWÊú—è¦ÆÛãVÆiÔQ@Q@Q@Q@Q@Q@R Œ÷ö ¢Š(¢Š(¢Š(¡Y˜( ÝO­áÆFF=F)ÔPEP)h¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ Àñ Ý$+Æ ??•o×?âS‰a¡�¹ôäS@nÅþ¥?Ýâp ô¦ÃÌ)ßåú@GÑË÷j’³ï¬]ÆûfÚêúÒZ\ÍanTç¦OZWÔÛÙ§Åü�)¨ÁÔ2œƒÒ�LÄ*¹� ô¨ï&)¶5êÝj8í|Å,{ö Ö0V¼‹ˆë"îC‘NªˆÑ]¥Êjº·CTÅæ-ÆÑ¹Ç_Oœý¤«w‹�Qvo±­EQm@,˜Ùòç­]V¡”äEJŽâÑEUKç•YqS[Ê&…\~?Z p|¼Å)I§ÂÊrjm3>KƒýïéUï‰@)ûÀ_¶‹Éˆ)ëÔÐm7ûµæKEPsQ@ÚÿÇ´?îåSTVßñïûƒùT´QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV`Qÿ <çìÙÿÇ«N²Õñâ7Lr`þ4©EPT5²?³%¹Qÿ� ¿Tµ��2~œ óõ hŸò �ýæÿÐ�hV~ˆs¦Eõ?ÌÕÙAhØ‚AÀ¡s­Ú[±@ZF þµ5–¥oz1mî7¸åRÄ)$•àþ­¨i¯d‹slä Á÷_zéè¬íøÝÛí”æTëî=kA˜(Ë©¤ÑL–TŠ2òª:šHæŽU9�éƒ@, €HôÉëKXÚΕ5íÌRÀÊF2[稭]â(×Íp00XœdДQE™Æyô¥¢€ (¢€*j§eÑëû¶þUÎè.©'Vçò­½~_+K�gB~=LÖšy¸Ï1ËÇÔÓ°¢Š­}x–VæWç°QÔš@Y¢¹ ­Vöñ™cwU=,äÚ|qêFßíLò”êÇ#ÔÀë(¬}Rk‡0LÛ›nå>ïó­Š@S¼Ôa²‘\üÝÀè=jØ ŒŽ•—¯@¯h%Ç(zû­m®Ã¤1ºHì«´‘ŽÔÀÜYÉ êÅz€zS«žÐ¬Õ¯$½ŠlÇ–H瓞k¡¤]w)Æ{ŽÔ£§=ih Š( Š(  íb+&�õŠ8V^¹ô«6 ÙÄ¶ï¾ ¿)ö¦j6IlcnÈÞ†³<;º+‹«}Àª`íŽH?ʘÔQE (¢€ (¢€ ‚ñ7Û8î9=6A˜ØzƒAQvi�X6ë|ªqVk.8ÄÂÈ<Ôr¤ŒÁgwU'šFî—4ž¦¾G¨£#Ö³¢†' ©/N™©�€ |à{�LÍÂ+wø(ªfÒNÓRI±þ·õ4 –=Ë´UE¶•yóI?SIöyûKúš–=Ë”UO&àgÄÑäÜwçñ 9rÝLÇuÐ?ZP·C?5Éæ[¢ªŸ´ût¤ wÏñ “Ì·EWÍÇ ¤qŒ”'™f“<â«4ó(ÿW“ô£Î›÷x=èFZ¢ª‰æ?òÈþT ‰²3é@{6Z¢ªý¢OùçúR‹—Ïúº‘–hªßi|gË4϶6ÕšÙȹEUOƒ˜Ï¿i8'ËXw-c]:ŒÝÀ¿òÐ~ß°ÅŒŸÆ”YÀ?ƒ?S@¿wæm‡ûÇò¨Î£<?…XD?åšþTá/DQøP§Øª·ÅþäkļÒD ýÛu÷ÅtÕÏø™>hŸÑúP„Ü^ÈÚ³mÖp0ïÿ*š¡´R–�¡ê±¨?•JÄ($œAH$àV}Ćæ`‘týiìZñÊ¡+ïV¡…!\ ü}h6V§«ÜXcD¨;S袃&ï©Ð,Ÿ7ñÁªöÏ:nŽDéÐÕÚ()OK2"ew‘úž‚›ylg®7Z³E¦Óæ)‘v¾×¨«"<ÂC»ŒëRQ@9ÉîE¼qghäúÖEÔmëˆÁäñøÖåA%¸i–Rq·¨¤ÕÍ)Uå“lÉœºF¨ë‚+OO}ö£'�qT¯ØM&S$Ö¬ik¶99Ï"—SjºÒ»Ü¿EUDsD&ˆ£wªÖë/˜)Ž599ïWh µ6•Š:Š€c“¸¤þÐóGncëÚ“Q‰™Õ”Ç5v8Ò5/ÐR5¼Tõ/3neÆ}j’Š)˜7p¢Š(ê#ÿt*’£€bÇû#ùT”QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVFÒÈÊß›yêkfÆÜÚÙÅ>òƒÅX¢Š)�â_øò‹þºÿCXÚ|€Û̘äË Ï¯Ìkoă:zð?Ö}85� ZÇwvë! ŶEõÁ¦_X#/çBÜ*<ÖýSÔlVú¤íu9SHÙZÃm ˆQW*2Àri÷N±ÛHÍÐ)¬pš–ž¥cDí�˜~U­¨ßa 9ç¦6�õ§`3í.$²c4|²®ÒHÎ3V×Ä7[³ò;mëZ¥yZ=Äm‡™—q#¦G#‘¥ië};ÆÎP*ç#ë@ój ¡ÜÈcªá”ö¬½'M[ù_ÌfTAœ/s[ÖÚDöÓC¹œL0Ū=O–ÅeóŠ’øÆ¥&—ikeu4PO#ÈÞ¬xõ ïˆVÞwŠ(|͇ibب类ƒ]6êLr°%‡n þU�ªZ´:¤Å×÷nÛ×Ѓ×õÍn[k–òÄ^\ÆGn¹ª·Þ Ù&ËM¬¸åˆïYIi4ñÈðÆYPr§iz\·“æExâPrÅq“éÍmØjâ[®.°¾QÇÅÅToI¼•… úÍg¥½×�ö&B¢Gôî3ÍhO¦Kg¥â8–iË|ä áyéúP®�¨Å¨FÅWS†CÔUÊæ4Eš-A3¨ †%HãÓÒÇ’;IZ- S´ZÇðÒ.û© >fB�z�×ùÖÍÍÄv¶ï4§ƒ'–²E<+qJg'ë@QEQEQER7Ý?JZl‡±ö h¥¦ùŸ…^  ¥§&ß0öàUê *ülˆÛÄH;#ÓŠ–Š(3m½ÂŠ( AEPEPEPEPEPEPEPEPEPEPIŠZ(0=(Àô¥¢€hô`zRÑ@ Š0=)h Àô£ÐRÑ@ �è(À>†–ŠM£ÐQ´zÊ–ŠM£ÐQ�éKE&(Àô¥¢€ÒŒ Z(0=)qEQEQEQEQEQEQEQEQEQEQEQEQEQEV/ˆG6å¾ç͸ûq[U‹âLˆb=°ßÒšeq�Ž”Ž�ÆJH¿Õ'û¢ŸHU0 KEQEQEQEQEUKç!Bâ«uZê— „n½è.›JZ‘Ì¢+NƒqÆiÚzm€ŸïÔg¹› !Ú­hF‚4 :A¤ÚQµÇQEQ@Q@Q@Q@ÃÄ1�öGò©)‘Œ"ƒ×Ÿ@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@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@Q@Q@dÊ1âXê`9úVµdÌü$¶ä<ƒýhTRÑEWRÇöuÎzymüªÕUÔÿäsÿ\ÛùPüƒ€ôfþu£YÚΜ?ßoçZ4˜£¥¢€ (¢€¥¢Š(¢Š(¢Š(¢Š(¢ŠÍ×—v˜ù8Ã)ýk+Âу}s&9€?sü…nj±´Û„a ûŽk�Ð.–Úñ‹�¨é†'ô¦[ES�¡ÈÒÿiZc>p¥`-ÑTÿµ-1þ¸ 4ŸÚ–ŸóÓÿ4X 76òöOò®kÄ®¡´ g?¥nJÙ”€ç‘ýÓXzvË]LÌïˆÂ°sŒS©¢¨kZãï7ýóN]RØ÷aõX ´ÉaŽeÛ*+¯£ ÕFÕ­”�K¢Ó¶-±�[ò¢À^DT]¨¡@ì:¨ ZÙ¨þÕ‡û­E€¸ñ†eaÃ)ëíéOªK©Àà 7åIý©qó ,ê*‹j�ŽÌG¨¦�Z>ë~”X\Ò§öÁüˆªþŸ}¤�‘�)¸úÆ¥:Å»eJ±õsM·¼³¶$E’äô¢ÀjÑYçWƒqUù�³ kk®>Cÿ} ,•šº¼E°caøŠlÚÔ1ò1Ç|â‹©Ee.´¬?Õÿ½GöÊ‘þ¬þtX ZŠtijœViÖÀ?êO\}êxÖ81`ÿ½E†��Í"Ær{š’²¿¶`GžœÒlrA�²=h°6Û»5¨¬¿íG‘nÄ|S?¶[µ»ëE„kÑY'VùöaÆy jòųgÐæ‹­EejËœ}œþ¿áGö¤¹8ƒ {ÿ*,­—ý¥9Ïú>õÍ0j³³íÄŸ`M^ŠÉþÑ»lµ {©¤•Ñ'ýñþÉ¢ÀkÑY_o¼þ=ÿñÓB_޳ǩÇû¦‹«Ed‹ûâxµ8ÿtÒ}·P$£ûäÑ`5謖¼Ô@èÇŸE§-ƤÇ& §ÿ^‹©Efõ ?Ôþ~´©6 ßz¿P?Æ‹¥Ef¼º‰8X€÷ãühFÔ‰‚�žƒX *+9›Pp€¯cÆj0Ú¦x^=ñE€Õ¢³”j%ÏÐ)¬u"Ü�‹§Ee°Õ00GéMeÕHqî Ñ`5¨¬Á¥‘™QþѦ~ô€¨  Z+(Aª|¸ÏLÒù:‘Îf_΀5(¬µ´Ô \`�FëúRý’üƒ›‘ϽiÑY?bÔ3ÅÏï_°ßœfï¡õ4«Ee›Ü/3ïMM>ð1Ýs‘ë¸Ðµ™ö+ÞŸiÈ÷&˜të¤ ²3׿4­Ec�.õNc¼#>¤Ó¿³oï^Ö€5¨¬¦Ó. ȹ8úš™sÎ/gÜЭ&G­e*vuÈ${ñ¤:D˜8ŸúжEµ�4i3ÿ'�øÓßG.Äý¡†Ga@›‡¨£rÿx~u”4_ï\Æ>í+èÅ�•Ë@™¢‚Ê:°üë(h¼ôƒÏµØÄà5Á ³@žb}:O6?ï¯çY‹¡¢ç÷ìsþȤ: E‰óO?ìŠÔócÎ<ÅÏÖ—Ì@3½qõ¬³¡¯k‡Ÿ(¤þÂR0n�÷Eiý¢ùêŸ÷Ф70“2`´+8hP‚Ošù>Â�ý‹<Ì߀{ívã¬ñÿßB“í–ßóÞ?ûèU À|É·¿ØvÇ?3óô  ÂîÜôž?ûèR»pyž?ûèU#¡Àx.äzqKý‡m�¼ùúеý¡iÿ?Ÿ¡£ûBÓþ{§çUŽ‹nGÞ�~"‘4Ku$—�ç¶hÈÔmXàL¦6­fƒ™¿CQ®�l¤�dçýªOìK]ÀæLzn ÿlØã>wþ:iµd:;¢šA¢Ù‚NýZ‘´;2sûÁôz‚Aù!–N}…xŠ™cKy|Ö8 qÍNt;C×Ìÿ¾ª{]6ÖÑ÷ÃÜNMCý¥9'|ؼf¡“XšüÉì^4Î2Zµë'Ä‹»JaÏß_Æ€/XÜ=Õ²Ìð´;º+äzÕŠ†ÍJYÀ¤äˆÔg׊š�cø…7[Ä} ãð­ŠÇñ´B§’Hý  X¿Õ'û¢ŸL‹ýRgû¢Ÿ@Q@Q@Q@Q@8ëG^•^û?e“–û¡e'‡1vŠ( Ì*+™L03Ž¢¥¨®—u´ƒýš �¹•ÆÚOöˆw¼ OYÚS Ê€úÑ¤Š«Y´‚Š(¦fQEQEQE58U®)ÔÔÎÕ®)ÔQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVTäÿÂEj: ¯ZÕ¬»�—Ä6§ûи  J(¢€ ­¨ÿÈ>ç=<¶þUf ¾¬§±·ò  š MR?¾ßδ«3Ãÿò O÷›ùÖ�QEQEQEQEQEQEQE6DY#dq•aƒY1xvÖ>|ÉIúŠØ¢€3C¶_ã”ÿÀ¨¨}Å¥>Û¸­:(¡E)†&9hПuú(‚”`Fƒè¢�*<çË\ý>Šo–ŸÜ_Ê�ÅêŠ }ß-3�‹Ÿ¥û£ò§Q@ Ú£¢�Ê—hô•- äP�è(À¥¢€ L Z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬�>ÛÉ2=x&µë/Äñà¬$H? ]²q%”:4jJž ±]¶6ãÄkÇáSÐXÞ$PÖЂqóŸäkf±üI�²FRH‘¡­ÌHÙêd_ê“ýÑO  —÷ *¡Ã7zŠÖêA(Š~ýÍ6à5(×øpó4ýR?܉ÀãŠGTTl ú—è¬D–á€|¶TMhÅx’¨!ÈÆ(Næs¢ãæX¥¶†úS«&nƒ1 Z–öíH3‘Þ˜ÝÌ’4i Àɪk¨ @6±lR\Îïdί"‚}”¯f>æáZ)Fr1š«¥ÈGVãp¨ã‘ _? j)Ø#ƒÎ)>çLiû®ë0U$ô wQI/–­—ÆqŠ`‘®-Ï–§#×½Vލä,‘¨b:šgÕb€ bË»"¸,½@=)õÏÀZß_ ó)÷Ï4ÐQETÔnÚÎ"¨b[š·EEk8¸·IW£ Ô´QEQERdŒŠZço¤{ edÜۃ㱠tTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE„dRÑ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ w1I3Ä­ó¡Á5QEQEQEQEQEQEQE›¯ñ¦±Èeëõ­*Î×qýžAÇ.¢€,iÜiöÀö‰GéVj¶›ŸìëlóûµþUf€ Çñ'qúiÿ²šØ¬Ÿäéêyý  Oøô‡ýÅþU-Ci�²C·¦ÅÇåRäg怊( Š( ¢{ˆã�#¶ûTµñ‡N@Èæ‚£kêKEG‚DàƒŽ I@š³°QE(¢Š(¢Š(¢Š(¢Š(¢Š*¥ì$�:<†^¸ô«t„d`ÐTeÊîEm7�OÞš³í�Šñ“¾•¡AU"“ÐJZJZ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ŠŠy$Ü©»Ö–Vdܼz�JÊírJ(¢�Q@Q@Q@Q@Q@eß5­;¦~åZ•‘¨ý¹§qósøP€×¢Š(¦Mþ¦O÷M>™7ú™?Ý?Ê€3|;ÿ ÁŸïµjÖ^€1`@cV¥7#~ÞøÍ:“9ïQ\e#iUSŸ¥s7×÷ ªLÐÌ@WÂŒñ€oκ; ±yh³‚x#Ð×'¦Û}²gFoœD_žç�ñ­ÏËû™b<9ü)�°£–«½äQÝÇnć�eOcN»ºŠÎݧ�¶Æ¸ÉúœRj)¥ÕSy` çƒ4€–þá­lä™»(à ¯¢ÞË}hd™@*Åw�Ri—ßÚí)O,†*W9Å>ÖæžHál<€:ûК)²8Ž6sÑA5ƒ¤ÝÜÝê­¾RQP’½ºñ@VEÆ´#½X#Œ2ïÚìOAÞ€5è®~ã]˜LD »<šÓÓµï�àl‘~òÿZ»EPEPE%èh¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÊ׮嶷�`m�#`°ê+)cÕÛí^l¥ÏßÉ#×wÄàˆ­ÜŒGéÿÖ«ú34‹R㓘éƒ^#¤À “®;ŠÐ‘Ö4gv ª2Ií\ä-ö p¢��¾Â=�Oé[šŠ<–¤C.P€=h._ªJU`ܹàîÆi‡Ä21;tÉõj¡¦Ai<æ;Ål“ò�ØØ×Q �¼ê¡Eü($kÓ€wY“Çð“þ­e9º´ŠfCuÎÓÚ¦ÀS]RÑ®�°�ù€•èq‘ï@h¢Š@Rdg¥  ºœÆ �[kc }ÏJ‡H»’î2�»€­G¯ZÜÝZ¢Ú�̯’¹ÆF*啪Ú[,JrG$úš`X¢Š)QEQEQE7zg—>™ QEQE5ÝcBîÁUFI=¨ÔU+]VÒîs .K�žTŒŠ»@Q@Vúú+F—qÞpŽi,õ{Æ+àd« ·E”´T såɲHÜрȩTsò°4–bXõ´|Ç=ýGÿZµ$‘"Bò0U’MsúÅÓAª|„nP0}*K&Ô�ÉzÒ4yà1á©�·ñ\ÇæA"È™ÆT椨 ‚xü¸#Xк£œòÇ<ÇUÝÀÉÆiú*…ƯkÆï0ÿ³LÓõˆ¯®^���¹Iî(JŠ)¡Í-Q@Q@Q@Q@fëÜi¬sŒ:ÿ:Ò¬ít�¥ÊHG_­Z²À²ƒ<µþU=Cf»là_HÔ~•5™â�1Žqµ�­:Ëñü‚œžÌ?Ôj9Dz|OßË\~T–JÌ¥Üõ” 1rvDò²ì!ˆNÂ@&uÏ Î=é·Æ"|±éН¼;d Œœ�zÓ ~ãO©µE5H�”äu QEQEQEQEQEVV¥&5m1Ûcúbµk'Qÿ�Ö›é—þT­EPQÏÿòº•IQÜǼ¹þáþTCAÿ�xôÞØ­:Ëðñ'M9õjPMuŒ§¡§Q@5¬²ÛÜ£ÛçÌ#hf¤ióZ1¸3ü¤g©íw®F¾—,§õ«úæ�<÷H¸uÁ±õ¦w3ÚØE+ó$oëœß­M«Ý¥Öœ±‘Ę$ŸzÖ0o´òd;ŽÀ¤Ÿ\u®j+ ÉobeÁËÓè÷ÒÏy%µœNÅ<µVã-ß5§`,!å›’@þѽÑî>ÖÓZ°Ã‘œP� æE-4ª�ÈûÄþ4=¶³öb-Ã3˜ý £Ã·FHæ‰Û%Nà=�ÿ^Ÿc¢B µÆ&=‡@*Õ–“oc;Ë|¸Æ à æ€*ر2}p?š¡â É&™­Ñȉ �â>õsXI­gK¨3“Á g^ÏGšò¸žl4™nWœv  ‹Yæ¶|Å+¯°c�Ê·îæ]CJœÉùÀŽ9©ÃÖþ^I zŒ »a§ÅaGfÞrźšåN­z狇§Ë�[ºì·X¦rì¸`ÇùRÝhÍ#¢€!Õtåx¤š (`?Š™¢ê>j­¼¬LŸÂ}½ê VÎùõ– í +tü*M#H–ÚàO1h;Tuæ€4u µ´¶g$o# =Mrëo.ÃtTì/�Þõ­}gswª`©òJà?aZŸd�ì¦Ü &1ÿ×  ÖÚ¬ÈI4€2ðGs�jË¿×ä‘DvÊb«óTÐh·šPbÿg©§Üøy�·“n:†æ€3.„¶²G2\!”�ál‘].›to,£™†äzƒŠÎM–_2Eu 3šÕµ·ŽÒÝ!ˆ‹Ó45QH³õDZ�‘á¤>½ªÝÌ¢ y%<„Rk�Ò":�ã=ÁÎý†8$ž)�!ÕµuYe�|Lp7.?ZÚ³½†ò=Ñ7=Ôõ_Âg°ž$fB{ãŠÀÑí/#¿‰š�T�ņ8ÅuQE œk‰³‰µ _÷€JCH3ÜõþµÚÈ FÁN‚®Ý%K‘!¼ÀJ€:úS@tz&¤òÃ,w–…wn=H¬[½Nîæs"ÈñÊ�Œ ØÑté"=Êó`®;ÔÃÓÂÌ…3ÔƒœP 7XšÎã3ÈòÂß|’=Ålø�ËéˆèNÒêN;ŒŒøj@ Ï»¹V¥Å¢OhÖçîíÀ>˜é@žµ¬¯�æy˜'ã³u«»ƒ¨ÏžE�HTà”V¶‡a=‹Ü ‚áŠàƒÃc<Ô×Ú<²ùŒYõ+Þ€9k{Ë‹IÕã‘ð§¡bAJí¡™'‰e‰ƒ# ‚*‡ö ‰M¥Ÿïnæ®YÚCe†ÝJ $òs@>!bu8Pž?Ô“þäm¥_E=¹íœ‡ÔU½{Mž{�q´€ B«ÔžZ»s¦µí”K) 2€sלr(ßRºŽu•¤}™ç¸>Õ½c¬C}?’‘º¶ ÉÆ8¢ °6ò�ÅŽâÃ×¶)tÝ%4ó#o2;q¸Œ`zP}í˦³¸9U�Ôž1Æjíεk5y›<Sš]CHKÙ¨þ\˜Á8È55Ž› ž—“ûÇúP=ªüúŠHCÕ%­œ�…¼aš�P±[øM#ÆÎV€9ûÝJâì€ìb�º(<~4Ý&â[}B%W&9_k/cï[“èÖÓ[¤#rl9 :Ÿ­Ik¥ÛZ¸uRÎ:3”vŠ(¤EPEPEPYÚÿLÇû¿ÌV�gkË»I˜w㘠 °¨�ýÑüªJŠÔ–´…ˆÁ(¤�Â¥ ³uð?²ä'SƒßšÒ¬í{?ÙSm#΀ëºÆÝÀ*ŸÒ¬Û¶èûS-6ŸžžRÿ*Ž2ÖŽUÁ1“ÃzPh½èÛ©lô5›»K¨Ü‚ _YVLlù�ïM‚ÜBÎw»ô q—"k©F ;—!';c^ÙëR¬w®Â%óò*ý’¬ÞèÏûÌåäÄyì*Ôé�¹$õ&¦¢™2©)+t3µ0|ÈÛ¶:Ö€ä FUq†�zu”¯»QA+x¶ßHzœŸ­2íÜ]*—eR8"´)’D’ :†úÐjª{×e(bSt9É«3[$Üä«zŠ‘#HÆB�j}•FÝÑPéñ‘Ë6}jXí¢�J…ê0MMEs“Ý•–ÆÙ ·±«T.Ü zRÑ@œ›Ý�5¤ rc"ÃýÔQøSè 9›êQE�‘C£)èF* õ$z³P@»e”�š OÝhžŠ( €¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ª×…–=ËŒµf«_©kGÀÉÐ]?‰ þÐŒ"� ©!¼ŽW2 éžõ™dYØÆ€yÉ«–ö,²‰$aòœ€;ÒNæó§N7L±qr°:±è)©æÌ…™¶©èÅ2êÖI%DFq‚ ,PÎyŽôÍ4f”Tnž¢[LÂFG9µo¨â¢6è}GÒ¥è("m=QZ;–7&6g§—&6Ç'»ví£w­:�6¯tV²$£åJüÜdSnÆÖYGU«tP>zå{gš\™Wbö÷¢k8æbÍ�O\UŠ(v�Ö…xìá�¢dûóS2+®ÖPG¥:ŠäÛ»b*„Pª0AKEQEQEQEQEQE“©�ý¯¦çûÍZÕ•¨äëh®J´QEÿê$ÿtÿ*’£œ€uÚ•gø{�7>®x­JËððƘûfµ(¢Š(ëFyu%ºŠUUÞ®ÊAÎGÿª¶(¢€ (¢€ (¢€"·â<ªH©j‰[‰Pô?0©è1ž½)h¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ø…-5»S¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š( Ëquk, ÀuÅghš}Å”³Â…`³œf¶( /-#¼€Ã.v’¢™§Ø¥…¹‰¶X±'Þ­Q@Q@ ŠZ( Š( Š( Š( æ‰'…â�e`Õ];L‹O2vrøå»Ú¯Q@Q@Q@qÛÄ:¿˜06LOëÍv5Æj å_Ì1Ÿ�¿SMÙFE-Ci'›i �â@jj@QEQEQEQEQEQEQEQEQEQEQEQEQEQEGZÒ®=—?­^ªÛmÒ§'§ÌPöû¾I'Ê^¿J±PÙœÙÀzf5þU5›¯�º\ž›—?�iVv»ƒ¦²žì£õ  v`­œ zˆÔ~•5Ae“eNO–¼úñSÐAŠZ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ˜‘ífbrM>Šp¢Š(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQER0ܤã´P5‰ò/ŒgÝkf°®³¢ÍþÖEm£n@Þ£5(éÄ+Ú]ÇQEG0™©¥¬ýKpt �1Vídó`V=z -"Z(¢ƒ0¢ŠCÈ ¢‘F'4dg ¢šçjéL‚_07û' vv¹-·+Úb; H®ÒCƒòŸC@ù%kرEPHQEQEQEQEVN¤HÖ4Ò?¼Ãó­YZ—ü…tÞ‰¸ü¨@jÑESdÿVßCN¦Jq“ýÓ@Þ]ºhíµjV_‡±ýœ@í#V¥D·´­ʆEê ò*Zä>Ç=α:Æê²b[‘Z#E¼ãý7hï‚ßãL ê+h÷™ÉÔdLÿ�?û|‚u ½ñ@ôVoöSq›ë£�ö©Í¦œ^\dú½ 4(¬Ñ¤±9{ÛƒôlSÿ²Ær.®sþý[1þùd Á©+?û(ÕÉÿ¶”d¦ãæçþþSBŠ£ý˜˜#íœú½4iùopàt€Ð¤Èõª#H€õ“«š_ì¸2 yI÷sL Ô™It«uf^é¡¥þ˶$“æ顤Ì�Z2=jŸö]®Ý»_Ïß4 *×9*çë!  ™´dzЍtËr»x³šA¥Zàcõs@7/÷‡çFáê?:¤t›RÙ*ÿMæ—û*Ôœ”oûìнëýáùÒî_ïΪeÚd“~¬h]šô�3@¼Äþúþtžlyǘ™ôȪßÙv\þáy÷4¿Ù¶}àSõ  �Ä à̃þ)Dñ’§ýô*Ó,™pmÓJS§Zƒn˜úPÞtCþZ'ýô(óâÆ|ÄÇû m˜Ïú4|ñÒ”i¶j»E¼`{ —í0c>txõÜ(ûDsç&=w €évE²mКQ¦Ù�ùwOʘŽX#@†u?Wɧ«qÖxÿï¡Q�6Ìœýž?Ê�ìëñ߀3O‰-D�|©që�þ5wOÔ¡ÔC˜C�‡p¬]R¢×mcŽ5 '—�xŠé#�#]±¢ ôQŠuQHŠ( Š( Š( Š( Š( Š( Š( Š( Šl…‚ƒsv+3‚ffô  4QEQEÊø‚&‹P-ü2(#ùꪭýŒwÑrT©Ê°í@è’yšdì’¿‘­ ­§Ù­�°…X¿$’{“Vh¢Š(¢Š(¢ŠB3ŒÐÑEQEQEQEQEQEQEQEQEQEQEV~¸Ò.7tÀþb´*–°Òî3ýÜþ´5Ž>ÅoŽžZÿ*ž«iÙ:}¶NO”¼þf€ ÎׇüK\ú0þu£Yúàÿ‰\¼d¤þb€'Ó¿ämÿ\—ùUš«¦È6Ûœþí•Z Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  ­V,J²„`ÕÛ&Ýk°Å7PMöÇØƒQémû¦Oîž)u:[梼‹Ô×u�K1À§V~£! ¦cóJÂ]\Å*GN*M1÷ÀÃû­Š�­•m2ß|ŠM)ö—Œýiu:$¢éµ†–i’–1^ qTogùð„�§“V­åy—,›WÔ÷¦aÈÒRkpdBï/ëR$ÂX™“¨ìj´öÏù�tî*[(Ù‹Œ9ÅIFÜÈ’)Cü¤üÞ•ZûzÈŽ§�V„(%2 îÆ)d�d\8ÍÆJ2¹–9ÐÆKݪ´�APà)>µn(cˆ|‹�z’€çåÒ;Ãn±ï1êME5—™(e`£¸Å[¢�)É;…QAEPEÉ>Kߊ•݈ÅÖû…Ž5Êó–«5ZÊ[�ÞnjÍNײ (¢‚²u2F­¦únoéZÕ“ªŸø™i¿õÐç�¥4µQH™/ú§ÿtÓê9¿ÔIþéþTŸáìgœæCý+R²|81¦“ÜÈI�+Z€0,C·ˆ¦c÷Fð1Šß¬-9Hñ æ8Q»ñäVí0 (ª:ž©�ÝóÊßu¥ /Rd�©®Rã^º¸\F<¡œ|™'ó¨$šòS78\�†§`:–ÔlÔ�nb´*xåŽUÝ«¯ªœÖ%î‹RJ’9hÔ· `Ö µÜ¶—),9 *?ˆzb€;Ê((¤EPEeêÚ›Z%·ºnW`sX&úöáöy²¶î6�þµ0:cªY‰Ú:ï^ üjØ Œƒ�{×,4KŸ³´Ç @ÎÃÔÖ†ƒtØ6ò6GU  ªlޱ£;°UQ’OjuexˆÊ4ïÝŒ©qæAÿëÅ mvÕî·J}†6ÇZw „¡n„Õ  Iò³ Ò“Á½�¼,8QX 4À›4µ‹â°‘FŒC«o88ìE�ä$Ž[ Ò€6¨¢Š@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQErÞ'ÜšŒ. _ÝpG\†ÿëŠè4çytûi$9v‰KSŠÆñDLÓZ°.×ûñÿ×­},Ó-Cu/ò¦º(¢�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@SÕ€:eÀ=6ÕÊ©ªtÛŒÿpšvžAÓíÈéå¯ò«5OI$é–ÄŒ,UÊ*†·Æ•9ôùŠ¿T5Æ)¤ÎðÌPÚpÆŸl?éšÿ*³U4ã·L·'´CùTÐN³®GuÎ×%¢Š(QEQEQEQEQMf 9§PEPEPEÏJ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢“4´QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÉ£Äèˆb©éÑMb5LcÌ#ýk¥®_K†t×ÍeYÉ$wïB¨¤e¥X§‚ -€æõ=1¬œOlXFx<¡«ÖúÊ}ˆ¼Ç÷Ê1·ûÆ�}«AÄ–’£ýÞ[r+œ·ŠK›¨á�ï?ôÀ´ÂmBY�¥˜ö­h²ù“ûџЊ׆Å-l¤Š,³2œ“ÕŽ+ÃòÔÀÙ‚#lÿ³Ò€75MAtøUŒm!s€ÅeG¬ßÝ; [P=ÇÍúô©õûiåxäEg‰T‚ÎjŒ7×vñ�!W¨Ù@áÖn`•’ñc¨ ‚+u:+¯!†Er¯æ¡(aün+€uGäÁYÎÅ Ÿ   (¢Š@QEQEQEQEQEQEQEQEQEQEQEQEQEbø˜â qØÈ‘­5viÖËé÷ö¬ßókÿ¦‡ÿA5©d»l _HÔ~”ÀžŠ(¤EPEPEPEPEPEPEPEPEPEPUfÔm`}�2îôšžWòáwþê“\Æ‹bš‘žIË©V qœó@˪Ù7ü·Qõâ¤7Ö¡7›ˆÂúîÏ_ÁnŒÉg½Êg{g Vd²ùw S°Ôr$¨6 ‡¡ Ò<ÑF2ò*�s\:–<#HWŽ*Õ½½´Ð‰g¸d#9 ?™¢ÀtRk61ç÷á°qò‚j#¯ÙõaîÖ Û¥ÎM¼RW9vim4·¹,ÈŒÈ8àã4µÿ Ÿ¤Ÿ•/ü$6l™‹{·÷JãùÖeÞ—­»;[2œcw�ž~•‘ ´×VÞ&v8ZêWS½˜n†ÅBŒò�H5 Gp+LŸúl+* æXÁ–‡ÑØf§ŸÜ€}häšä–Ò¸·B}c�J¾$´#çŽdÿ€çùUOøF¤Û�*ÀÓdž}n?%  Ÿð�éøÿXÿO,ÓOˆ¬¶nQ!>›qP§†aî¸�çØS?áLÇÔŸ÷À  G‰ 8Ì2ÄT°ëÖ³6Ý’®{íÏòª_ðŒ‘Òë?TÿëÕ½7F63™LÛ¾\ Š×8¥¬�#T{¹¤‚}»×$ö85­HŠ( Š( Š( Š( Š( Š( Š( ©k:UÏû•vªjƒ:mÀ?Ü4i_ò ¶ÿ®b­Õ{ an äÔg׊±@RÕñý™8nr0>¤ñWk?\ÿ�\§Ð©ÿÇ…K¥ÿÈ6ß?܇췊Wî¿j—JÓ-‡û�As7£PkIûÖ}Kt×qc€(�·F§Ú«êZ±÷ÞVïâvÆ{š²a•9VÚä´MÊ ÇZ‚ö×rD 4xÈÍ#W»òô4I­E%ÊÇØŸ¥PId¼œîpн…Z!F0rOSBtùt{“Ã2L¹CøP‰±�Í×µgXÉ‹Æþ �S߆!d‰¾éÁÅ �Ó´ù{—IÀɪmy)r±Eº¦Wim7cæ+IfÛÐ�…yî:ÐLRŠm«“&â€ÈlsŠPC ƒ‘Hà” uÅVÓÕÑ\â‚Rºl´Nj›Ü\!.L`Õ©•ž&T8cÓ5pkå9É äÐ88¥vI‚XÃŽõ^î`3¶j[h À¾àOt§IHw0çqRò!°FØ9ç§¥Zª6'ȇð«ÔUïQA˜QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQER)iÍ!f––�t ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š( dœP# æ©^FÒJb™,dŽPöíA²§u£ÔÓ¢‘H`èih1 (¢€ lޱ©f8êk¨u*hßPGWPÊr :¨A7“q$OÀ'ŠšKØÐàÇÐP[¦ïdY¢š„²äŒgµ:ƒ0¢Š(¢Š(¨¥ÆFjZ‚àŒ¨¦ŠŽäôR/ÝJZD…Q@cëcý/O8Èó€ýElVF¸Œf±aÐN ~tÐôQE d¿ê_ýÓO¦Kþ©ÿÝ4›áОÄc™ ?¥jV_‡ãÁú¬?ÈV¥02,@:íÙR+b±¬ß_纂?JÙ¤Y>$rºa ygð­jÂñCâ=XŸÒ€)øTâöqÿLÿ­3Ä‘+X–\+/%º�jЦJþ\NÿÝRhôÕ�‹*(fê@äÕ&ùïc�É�ÈØî1ÿë­ )1KEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEbø•s¹ô�ÿè&´ì›u” ëŸÒ³üE!ŽÒ<ËÃZV«¶ÖôE¥0#½¼ŠÊ2\œðu5ŒÞ!¸ÎVöƒÐ“Sø‚Öæw‰ F‘pT…ì}k;W´û[D§*W,Ç»f€6ì5ˆ.ÈFýÔ‡øOCô5£\Mô�ƒÛ+"`“ÐûW]c+Me ®0΀œÐŠ)¥‚¡f 2MU±Ô­ïˈ Ê`�F8õ¤Ê(¢€ (¢€+Ü^ÛÛ0Y¤ O58 €G Önµ`.aó“ýlC?ïJM奶xŸ;¢l ú`jQE€(¢Š(¢Š(¢Š(¢Š¯~Ûl.[Ò&?¥szÜJ³Å žRy’zz{×G¨�º}É# DßʹíÍï"™|ã!ÀuQËñëL 1Åæï²Ó—d n9õ«’}šÀÅk +,ò?SO¸›ìéö=653zòÇžäÓb† *#=̆[‡g?y� râH¬ížimE$àrk"ÚHumBU˜–ˆ(1 à{æ¬^DÒYËus�þK�²gú×9§±X3F\ÔѼ«}8µ·ma?½u;AörÕÃä KdRxÝïô÷¬ë{S,+æ‘oaÎΆOv>•e êL¯—b§¯yqÿ²ÿ:«â9Á‚(ÔðÙoð¨<0 Í9ÇEþ5‰$l�‚|�Ûš›Â̦K�>öÕ?© ‡´QHŠ( Š( �𠥦Kþ©ÿÝ4Êè{Ÿ[Väe]ˆúÿúë­®gÃhþG=V?æúÕÓPEPEPEPEPEPEPEPTõbL¸$6tr©êÙþ˺Ç_,ÐÖx6pc�å®?*šªé¿ò µÿ®KüªÕC[çK›ÓŒþb¯ÕkþAsäà`gé‘@ ¥0]:ÕORœT—ÿñì~¢™¤ÿÈ.ÛÙI}ÿÇê(.ŸÄ‡ZǺ})š„f[7àŽ*u™Í²RJ3�c@ïËRþfE¤wCû’>SÈ'¥.éˆ-Ø‚©é óH=�­JKcZòjN%i,ãy<Á•näw§%²#å‰õ©è¦aÏ+ZäiœàƒíOЉv àœš’Šɵk…Ts3ªî9ä{P$®IE É#ƒÒ� ô¥¬Ô�áfµMÍÃmÎ?* ]&‹L‘˜óéQ‰¤�þíÑÜÔ7–¬ïæ§'"ˆo×\`­(.[ÇPŒ”¾Áž*õgÀMÅ癌*óZWtQEAEPEPE4œ1Ö�@Q@Q@Q@Q@Q@Q@Q@Q@Q@žÚŒ©�öŒŒgöÇûÏýñNÀiÑX“øƒÊ%~ÊÁÿÚjHµÉBfKfrN~^1E€Ü¢±×], [I:ŒÑýºÙ ÙKš,ÅŽ5·'›)ÿU/öÌ�¬¥üsþX z+'ûb_ùðš“ûfcÒÂ_×ü(°ôVIÕçÆFŸ7âøR®­9 gÍÏùô¢ÀjÑYŸÚW?ô—¯cM:µÀÎtéè°´VWö¥×ýf›Å,w:£õ³�=Ù¨°tVk\ê|m³Nœåé†çUíeâßýz,­ ¬Á>®AŬ#êô¾v­Œ}š ã®þ(NŠËó5†\ˆ­Ôÿtšr¾¯Žb¶ÏûÆ€4¨¬ÍúÁÿ–VÃêMûc¿ÙçE€Ó¢³Ö;µ¨ü &Ýg?~Ô�LÔ¢³‚êÄ’^Ø tÁ¤Ù«ž ¶ÃÜ)  *+7ÊÕ¿çæûâ�­ÿ?Vÿ÷Á  *+=aÔÂóu ?õÎ…‡TÎ ÔõòÎhBŠ  Ô»ÞB>‘õè6ú�?ñûÐÿõé~Š¢mõ q|ŸŒ#üi~Íy·þ?~úä1@hªMozz^¨8ç÷CüiÚô�¶ût9  ÔUi|:êÿ¶B”Z^wÔð�hõ@Ú^öÔ[þý-/Øï1ƒ¨?ÔF´zЦlçdÁ¾›w¨UÒš,®‚àjçÔ¢š½EP[ ÀçP¸'× þ­a+}ëûŒã`J½Egÿe¹R­tGûÀJiÑÕ¹k»¢{3  *+5´hÎ?Ò®�üÊ?±¡ÀýýÈ>¢S“@TVyÒbÀâèÛSGöL|fâè�ÿMMhQYÇG„œù÷#œÿ­4cAÆ&¹IMhÑY£E¶ÎL— }L¦œ4[EéçßÖÿ¿š Ôâ¨cYç;dÏýuoñ èÖgY;ù�þ4"‚Àu5Sû2× ìlŽûÛüi­¤Y3e¢'عÇåš`[óS¦õÏÖ—zÿx~uLhöcìËéÉ4dØò~ι=NM[2 8Ü¿�lyÆõÏÖªcéý~ʇëÍ9t«9±çé@ у"gýáHn`^³F?àB«ÿeXd±´‹'¯ËIý“`3þ‹å@›Ë`qçÇÿ} >Ûmÿ?ßb¡þʰÿŸH¿ïšqÓ,sŸ²Cÿ| ÛmyÿH‹�ö…4jVGþ^¢ÿ¾ÅÙ¶@çì°çýÁN6VÅ@6ñ: ƒŠOí03ö˜±þð ê¢›ÏŒÆ¤Àç‡O´$³EŸ÷9¬íÚ#‚=„ä�£€#þÔ±Æ~×?ÞŸÚúüýÅÿ}T¢ÊÜt‚!ÿõ·…NV(ÁöQ@�NÈ›¨¸ÿjšu{pn£üêÓC 2+}TSE´#¤1ÿß"�jX‘‘u>´Ó«Ø ÿ¤¥Xû,Jù1àõE in£ñþè  ßÛ:~qö”ýh:Öž?åå#V–Þû± ú(§y1Ï4ÿ¾ESÍ�ý ~F›ý·aœyÄŸd&¯yQãJPŠ:(…0(6¹§¡ÃOƒé°ÿ…\°*ÎlŸ#…_(§ªƒøRíP1�ùR‡öÕ†ÜùØú©¦6½b?�ÏÑ iSÕGåI±º?*Î:õ�ýïÓË4vÐ.vNí™­,AF¥eÿoÚóˆ®ý²4nFW)mpOû˜­LRÐ)×Û�¶RzŸþµ1µË£÷,ñõÉþB·qE09ÿí«âÛeã©ÚÜTm¬ß‚NÔ ?é™ÿé)0=s ®Ýì,’DHì?Ö´¬5ȧFûNØc<7½iˆ�tEAL–Ö ‡ïbWíÈ  U•Ô2°`{ƒKYsÛ>žMÅŠ’ŸòÒÐ�QïKs­Áo/±ßÍ€‡½iÑLŠTš$’3”q�}©ô€(¢Š(¢Š(¢Š(¢Š(¢Š¥:‘r­œ*Kå jç9¨µFÇJ.®Z€9ÞDS|­iÌZÛçiÅ;ý¤cVNzÒX&Ëqž¬sR‰TËå÷ ‰?yØy SL¨)a“Ðf›pÛ!gþï5NÅVYŒ­Ôt 0¼\™£P3Ÿ8p*Y!NjÍœËLŠqëLtãÌ>ùD¬^3�£æÅ?NDd.@.3V-öHVŸ£8ìj·}¿T¶DÈ ¨û�Ïò®²¹Ï YKæ5Ü«µ6â<÷ÏS]QE #šhàPÒ¸E'4ðA Öv¹mçÙî,G”wëÚ™¢Ý†³t�ÿ©ÿÐi�«P^]ÇešlíõZ½” •�FwÍÇ÷¹·¹°i” á=G¯4€u…ìwöþt@€©¨5fªXˆÅZÊ0±°,qÍ`˪j7„EnvHO ƒúš`u5ÀÝo(õCüª–¡¨�:Ò6‘|Éœ`ƒ8äÔ–·bóOYdÛH§åÏÔR3ÃŒ~Ñ2Ÿùæ§õ5ÐW;áÐVîPyÄcŸÆ¦Öu‰­eh-PoçŸÃÀÜ¢³äÖ-!!d“-€NÑœUfñ°|,r2ÿ{�úRfŠ†Úæ+¸D°¶å?§Ö¦ Š( ª¹¼7ec1,¸‚Xžâ°5-Fò+Û„YÙc…°â«Ýjw7/dhÆBF}é�ØÑ\݆¸ðBRä4¤r¬O?CL‡_¹óÐÈÇü@h°=!eHZÄb�Û±;IÎsŒw¬Lý¨»ÏpÛ”eAÉÜ¥µóimë�Ôæ—#ÏÌhDË4öøù^#ŸA‚1üé·‡™¤‹]Íæ«à°ô#ŸÊ‹ÕQÒ¹›-zh!t¸ŒÌW¡ÎãN¼ÕQ�!…J+� ç–>”XŒzS ñe@Ç Ü3\�йӦ0¬Ì£…cŽj˜LFÞPwyˆ$Vïžâ‹ÜQXoâ@Z³¹þyý+i d—i#‘ž”€uQ@Q@Q@Q@Q@Q@¾%ÿ�h²ˆçèkRГi 8Ï–¹ÇÒ³¤ÒÚX³H.¯ŽûŽËÕcúTÖÖ�Ù«¾æf?~I$þ5FçPžöV¶ÒÆí¼I7ð¯Ò€!×5$xä´„’ÙùÎ8úV&—,6ú’Ir7FþóÛŠè`±ŒÛF¦îí†~çÐUK_Ë Ú\O,kl=»PŒQK©–î1°9HVô-þûûÓö€=Óðª?„zšk\\j¥‘ò Î ÁÏû£úÒ:Á¤ÆÞ–âN³ŸR}(X±ŽÄEó3;®]‰ÎZ¥ð©ÿMºÿ®küÍMw¥K%´÷W²Ÿ4)`«ÈÕSÃ2„ÔÚ3ÿ-##ò ÿ�u´QE (¢€ (¤$’q@ M“˜Ø{¡8 ¤ýiOC@߆úeÀÏü³_æk¥®[Ã¥cÕæŒ†Œ€>�]MQEQEQEQEQEQEQESUÏömÎNÃVê½ø&Âà“å·…~~Ámž¾Rçò«[MbÚu±#ļ~f€ ¥¬ éwîÿZ»TõQ�2ãýÂhÒäoþà§ßŒÚ·±£ÑÛv—nO]¿Ö�¨1ò‚â4OãD–_ñë}*fû§éI„�Tv§v Rw“fV“Ä­èVµk#Mb·eNEkÒ[â>0¨.&1mUµOL‘U—æÀ÷¦e_QQp2O'­$’ÀÏz¦—n²•ldTó(ºƒ1žGJ piûÛ¬ªìTEB·hf1�G8©$ ûÀ=*KXŒ²±‘NÞùæƒOg›¹fîw€+(=sSDâHÕÇF¨îá3@Uq¸r)Öñ˜ Dn Pdùyr­»fõÆ8歼ȌŸ˜ô£ŽÔ$í.î¹â ¹ ÒÍ´• ·Ë9iØ¿Yתß+0[“šœ^â8��ÓŠeò�¨øÉPÓŒ¬ú–ÕU=:³®�ã$Ž=*ô2¬¨O×Ú‚%•ÇÑE…Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@PÕu±ƒæWáGõ«õ�â(ÅøùÃmÏ·&šú,MÛ/+’2çjÕÀGDÿ�Tô?ÌÕú@¢Ž•FãV³·8iC7pœâ€/QPZÞAyx$ ÔTôQE1¥�3ºEë“@¢«Åk4ž\S£? 5b€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPÖ¹MVÔZÝyCîY>™®®¹ÿßE�ùæÂšWKÓm‡ý3n¢¶ ÛDGBƒ•KHŠ( Š( Š( Š( Š(  ×ñ™-›Wš©cËŸ0çgjÓ# ŠÆØâä­Œ�´™ÓIÞ.74žî8ÎÕ»qU$I…öåœùUØm’02Þµ(9ÎF9¦f¦ ýÔ4¦èÊ·95¥³@ìXƒ‘�еE)4š :ÑE…Q@Q@Q@Q@#}ÓKEE `*Z©$¦$G¥XŠE•/CM—(½ÇÑEˆ Å×�óí8óÏâ+j±5ö&æÍþ0Ãë‘M·ER¦Mþ¦O÷M>£ŸýDŸîŸå@¾\iÄçïHOè+V²¼6ÓÙOiòµh2ÌÄòøçøT~‚µ+"ÐãÄ£ý…þ•¢.íÏIã?ð1L ¨¦G"J3«€q•9§Ò*ÿFŽVZâÇSŒÕ4¿ÔìG—q �œþ"·&¹‚Ò¢ÓqÅF×öЛ𿠾»…09»‹ûÛ§efeVÿ–j8§ÙisÝH £,}Ù†?![ßÚ6 ÏÚ"ù£ûRÇfñsǽY†%‚$Š1…A�Oª‰©ÙH@[”ÉìN*Ý (¢€" #dnŒ0k’2Éc-Äy2´l+¯¬}bÞÃÌ]HÑ3q•æšßH¸»€Ë\€ ÆkvÎÂKm­Ç°fëüF›iªiÐ[ã”…Œcæ&¬GªÙK´$êKps@èp\Á§˜n”£;A ðúùªz6™=½éiÓjDSŸ¼}*ߢ�Ú¾šoãBŒÓ =¬û}o26šPª‡?/&º(ŸÓ-õ©!-�êÀpsü©úÆ—<³™íÆüà•sWF•ÔÅîó�I Ž2F+B˜ÖŸ¡É>÷¼ =<çÖ³¦Òï!œÅä;œà2Žã]µAut–‘‡‘]�;@E,søPv�mum‚â?-Xä×5±YÏ­["ä¬ÿ÷èÓF»fç¯ýû4§Ee&·jŠ$üžYéNå³9Î}#4X v¦ÑJÇ9\ý[­g µ½úÊҫć*1É>õj inÍב,r+nÎ>¸­*Ç»Ð!¸¸¤†5'. uúzU†ÑlY|œmîƒùÖ…!$@Éô¤0ZAn…"ŒF©¬Ùü;’nŽW�sÊàʦ]Vl‘&›t§ØL:µÖì.—q�RE0-ÙiÖöJâ9¼Ääš­ƒk æMÎã²1àS±pßìÙ÷¢�¬Ï» ¦ÜuÇ4¤ö°8Ä{¨¨cÓ­£º ׃ð¨mu9.g )“Œ³8À£H WºUµón”0oU8ÍiV²[EC¶!„ ò?»EW´²†Í6¿V<“V*µô·ÂÒ>BÀm-Ž;Õ9oµ% åé¤úåÅjÑYnÕdiÁ}‹S–ëUp²� =Yø«EVµ‚t%îg29ì£ ¿AV0rNxô ¢ŠÉ¸ŸXûd‹´F~VcÉýhZŠÃ-®³p±¨ü)„k‡ƒœw#ni�¿EsªÚØ;U%?ïm­M9µ_$JB§“H ÔUMA¯•ì 6ï›Ì8â«ùº¸ÛÛ“ìæ€â‹XøÎ_¡­8Ô§û¢±õñ/ö|&Lo –+Ó;MkÁþ¢>ÿ(þTÀ’³5ë9nì×Éž6ÜûÜb´è¤3èï6™m8Yâ@ <ƒíU¡Ð''ÈŠ¿ìó]�¦h­e|× `Tß֬ǧ¢ê\FØFáî+B�: P{ë8ï­Ì2’Au�gh–vë d�9ÉêMOEAqgÎ ±†#¡ïUÛF±hL~@Áþ,óùÕú(. ÊÜÁåôx¢‘¢&ÄEUôŠ}QEQEQEQEQE•â$/¦àt ¬Í[[¥¸–ReÁP�{uýk¤šž&ŠA”a‚+) UÒF‘‘ž¼þ4‰£XªhDžïÍ%Í¥•¤ 7Ù�:/Z™.¬P³$°‚ç$‚95ä–�˜'™Y2 ˆþU–—“O‘k¦.;oSJÚ~¡pyŠ(G±Àý(ÔÚå´X†Í|Ö(ì£ñ§Aygù’Îd¸u›ôì=ROÝ Kzã&¦rû×ϲŒPêÚ¤Ø:BÌY±ÔcŒÕMkKhÚi™Ë»\�5Ô§ËþfÛD¶·V]Ï"·Ur1ü¨¶mó÷dúâ£þÝ· ´£þ•div`äBHlmš2†*zŒQ [_€tŠCùSá!ƒ818üE\þʱÿŸd¤:M‰ël”IüGû°¹üEC?ˆc‘J2ê}Xb´Ž�bF<€>„Ò.�d¿òËÿ4ÎM{�¹-RÜ©¥7Äûb–@HÏS]$zU”L`RG¯5obÿt~T\SA†s«$�ËUbÌG�ñ®¶�´€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*+  ¬ÁŽFÏåRÔ7jÒe'ÆÀŸÂ€¦Œi¶ õò—ùUš­§È>Ûœþéyü*ÍèÍ”ã�õm×éSÔÙ7Æ|¶ëô  úF“ož»Oó5qâG`Ì2GJ¥ œéùô?ú­ ;Q@ ›}Dœq»?�kÕ{‹E™Ãî*G§z±A­I©%Ü*˜<ð£q\Φ¢ƒ4ÚwE5ÓÐgçnjÄ1,)µ:u©( §9KvQEQ@Q@Q@@`A‘#HÆB�juýŠ( AEPEPEPEPEPEPEPEPEPEPEPEPYÚênÓÉþë©ýqýkF«j/åØNØ Þ„z9LƒoLæjïJ¡¡€4˜9ëÿ¡¼Ë¹Jž„b€9mcS’åÊDÅa€8ÏÖ©YÙÉ{.Ä8ã$ž€Tš�”ö“”(Æ?áp85½ÕÄA¢…ˆß÷”u5@_Ò·Ûꈑ6ḫÜWWXÚ ‘HÍÌèD¤�¹ã¶iÎëZŒž{AEà㹬˜bŒÈ¯+aIù°9Åhêör%ë¶ÂRC¸U$0º„ŠCЂÙɦÜù)uºÉ‹(Á\õ»$¨'ƒŽkžÒ´‰ Ë-Âm�yõcÚº*LŠ(¤EPEPEPEPEPEPE×À ÈØÏu'è(Z)îPH#=�jZ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦K*Cy*ޤӔîPpF}hh¢Š(¤ÈÎ;ÒÐEPEPEPEPEPEPEPEPEPE‚€Šˆ»4»Sî¯Þ?Ò¥ Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ŠŠæu··y[¢Œýj†‹-ÕÀ¸žå²ŽãË^À´©EPECwp¶°4­È©íN�¤x¥P²”v4%`ø�~x[ý†þ•½Xž"80g¦úS@k[ÖÑÝý*Z«¦’tëbF–¿Ê­R¢Š(¢Š(¢Š(¢Š(¢Š(¬Ëõ1Ìx'�kN¡¹€O?ˆt Ò”¹evI�Xwê†Ú&†-¬rsSPD­}Š( AEPEPEPEPEPEPdPèAî*žŸ�òqýjõW�Ue|Piî´X¢Š(3 Ã×úu§éÿ} ܬ=|‘wgŽ€äÿßKM¹ER¦Mþ¥ÿÝ4úkýÆúÌð÷6,{—ééÀ­JÉðß62zù‡ù Õ=i�•l?⢼ãƒÏéV#Ñ´èÆÒ?Äf«Á�øIn99òGô­zŽ"�JÃƤä…椢Š@WžÆÚæU’xRGQ€Xg›ý›eœý–ÿ¸*ÕTiÖ`çìÑçýÚM²c“kGû5jЬºuš8u¶Œ2òÞ•fŠ(¢Š(¤eV`ô"–Š‹ìðÏÿï‘NF"5ã§ú(¢Š(¢Š(¢¢šâ3H©ž™4±M˺'Wªs@QER`–Š1I€;RÑ@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@>"ÙÆÖgô5©¯ÐVW‰24õÇüôÈÖªr‹�J`:Š(¤EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPPÞqg9ÿ¦mü�MPÞ.ë)×Ö6¥3MçMµÿ®Kü…YªÚiÎ�lé’ÿ*³@Azže”è:´l?Jž«ê}Á?óÍ¿•A¢1m&Üž¸?ÌÕú¡¢)]*Nx'õ5~€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ EÎ>lg=©h Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ªj¿ò ¸ÿpÕº«©È:ãŒþìЀ‹DãJ‡ñþf¯Ö~‡ÿ ¨rs÷¿™­ )»6í«Ÿ\S¨ Š ÇZ‰®!O½*« �¨a†�z�- �·$(­êf«Ï¨Æ’E$K$Œôµv€ ) b÷¦™~ó¨úšq ž•¤ÏqæH@îÚžøïTµKÏ1VÖÔ‡’^»OAWíâ[kd� Í0&¨nîRÖ•Ï õ45ݺ4ñƒþ𬻂º½ú[£f¾faÜÐ�„’Ëj²MÃ>N=j³HÀ3*ýâ}M šìrÝ*7º‚3‡š5>ì*²Ý »ÕŽ(†çoSØPñE5�Qrìz“Š…¯m”á§Œ÷¨Å0J†Vˆº€Hôª—­´Q±IUÜtæ£Ñâ—d·3ç|Ç<ú”ÀÒ¢˜ÓF‡")ô$ �¯m”gŒþÕ êå- idÎ@:“è*µ•´²No/ïO§üó_ñ¦C_Ý‹©Gú<êTŸ¼½þ¥LŠ‚æòÞÓoŸ MÙÆ{â«\kÑ[³Ç vþäÒw¼A{ª|ÎA-þÈÅY¬ý&ÙÒ#=Àt§qÏP*Ü·Àʲʈ[î†8ÍKMwXÑ�ŽFI¨d¾µŒáçŒ~5].VþìG ßoË·b݇õ  ±9xò•Ï8=@§ÒzMR]^ÅÎáOèhõfÞ_;Ü¥�™c™ú…ãM¼Õ¢•´o2Váp:Túmˆ´Œ³á¦~Y¿¥0.Ž”T3ÝAnTO*F[¦ãŒÔgR³òñàiaÝSŽ2@æ�YVòGQ©Í´'»õ£<ñ[GæNê‰Ó$Д×u�Ü…U$öªÿÚVxÏÚcüêœÒZqoÿE^eqü^˜¾ýZàO +k~íOñŸïVµ5c@ˆ¡UF©“ÜÃo·Ï•#ÝÓqÆi-Esp–Ð4²Ÿµ@Ú¥šu�MP–Oí{ô†#›X¾f8êi�{K´ <üI1Ý�AØUÚBBŒžªÃQ³lâæ3Ž¿5 -QUQ´E,nÆ–ÌÉ07�»ÇÈŸÝ_ñ4jІ{¨-ñçJ‘“ÓqÆjíK<ÿ¯_®(åEµ[c…�IJ1ª÷5t�ªK2hhª‹©Ù8ÊÝDàT×Õ¬ÓþZîÿt@žUŒ cË�ª=M>³ì�Ûf7��ƒ+žÃ¹­ (¨&½¶�¶Í2#zÍU¸Õ¡Ù²Õ¼Ùß„P8ϽYy ·Lg9‘‡è*ÅW²·k{p²>ùO.Þ¦¬PE#2 %ˆw5RMVÊ3ƒ:“ì  ßÝ}š ¨Ý+�±¯÷š¥�]!E‘·¸3zš§l‚òïíÌ?v«¶V«7w�YÆáö‚p8É&˜Õ[»‡Œ,0g“…ÏEɨN³g峇c´tÚA4ºt,Û®ç\M1ÈøW°  � ku�qr9f=X÷55éiQTŽ­d ðÞùÎljûPŸâëTo5˜æ¶híCù’ F1š´³Á¤XÁÔ˜lc�’OzЬØõŸUð¨0ª’íî*+Íb'„ÇfY¦“„ùOz±¥iâÆ ¾ ÏËOj¿M.ª÷5RóU¶³˜E)mäg ¹â’Âño¦šDR< Ü9õ?Ò�¨¨.·i¥?(Àú“Ò³æ×a6ù· ÓÂ�x4§çÅçy>bù½vçš’²´« ’V¼¼mÓ¸àtU‹ÍRÞÎO)Ë4¤W=zPWÑ›û¤´çÉL<¤¾‚´#�"@‘¨U^€vªö6æݤ9–V.çßÓðUª(¨nnb´‹Ì�ö®qŸzÏŸT[¡½Œ˜–fÛ¸�º;ŸÒ€%ïïÏÍ‹kfÆñ¿ø Ѩ­­ãµ…b‰pª??sRÐX¾"!D,{ãò­ªÇñƒîå ð¦€Ñ²B–p+�ƒ'ð©ê¶œÌÚ}»?Þ1ŒÕš@QEQEQEQEQEQEQEQEQEQEQEQEQEQE].b« ÿJo­2ãÔ³ER +_$\Zc¦N5­ºÃñ<ëVlm’?M¹ER¦Kþ©ÿÝ4úlŸêßèh/Äý��aÿ ­^õ•áÒMœ™9!ÿ ­^ôÀÉŒcÄÒûÀ?¥kÖJŒx•½LÖµ©QEQEQEQI¹}GçI½1�Ë�ï@¢š’$ƒ(ÊÃØæ�@Q@µ +9^3†ƒéMÓ&y¬b2¶éßz}ñE²œÈ@P‡9®VÞöãcCíÞ{qL íSRŠ0FwÈü§¥Ísm¡¬ƒ>r¨É=†zþTÝ7HXeœ‰$ì;/øÖœÆ5‰ŒÅDxù·tÅq¶÷ÓÅwçù¬ÌN[žWfŽ„f¹)¢‚kÒ¶qF`ª¿½u¨»(ì1@š¦–÷·ÈŽiëÛó¬äÙZ¨Häb„¨o|×M\êª\k§Î$m”àzàq@ÍÂZÛ¼Ò•N;Õ ?[‚ð²¸ò[?(cÖ�”QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEeø�KiÇ£×ØÖŒ?êSýÑYþ bºkŒ“�ÐÕø?ÔGþèþTÀ’Š(¤EPEPEPEPEPEPEPE"²°Ê�G¨4´QEQEQEQEQEQEQEQEQEQETr‰~SÞ¼î¨í/a¼ó|’s”`GqV(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦M̺•>™7ú™;ü§ùPYΙjOüò_åVª¦•Ÿì»\õò—ùUº*¾¡·ìÎË9?…Xªš©+¦ÜÙ G¢t¸sïüÍ_¬ý�ÓS0ýkB€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ ­¨ÇŒÿõÌÕš­¨�º}ÁóÌÿ*è„¶—züÀþf¯Ö~„âSzüßú­ (ª÷·klÒ¤/1_á^µ�ÿ ¾aSh=†ãŸÇŠÖÔlÍõ©„Hc˸{V[xyð¹S�ï'ÿ^†×æB7ÛªƒÐA?¥!ñù`¹ôÝL šv’,å2Èáß+N°�ˆ.L ?àTÏøHäï÷Ýiêzjj1¢¼Œ›NF9ê+8øxí \‚{nZSâØ@=²ÔßøH_8òSÛæ  zn‘ö)Œ²H$|``` ½wl—vï „…aÔv¬SâAA¿Ìh>!—þxGÿ}ü#Ûs²ãóOð­:ÄXÂWpwc’ØÅfoÍÁû:cýãA׿ÿGLREoÕ OMþÐòó)Œ&z æ¨ÿnOÚçÜÑý·rq¶Ø0ühálö�qþÅ_Ó4ña¯˜]œäœb³Ž·r£/jõæ—ûrrØñèhNþÆ;øDR–PAZÎ>b;“�ö”Sµt6êlƒHºÍãgmº;hkmb™YÌŠ§;vã5³X'V¿n£=ʵ ÕïÉ#ÈPGm�Í\¾Ña¼¹7ÊHFª�ósòž¸Jgö½ÿ8ˆzªjck7ý£ îb4ÐEÅFŸu@Ÿ\çö®¤ç �Hÿ¦gŸÎŸa«_ÉurÃæ#œŒ\ô¢Àij:dZ�Fwtd¾õQt¥®¨ ‘´s[4RªWúl7å ¥•“ «´P)ðúã tãê Ö�…šØÁå«$ä±ÍY¢€Ȭ�øGíÁm³J3Ó�qúV½�g¤Ek0”Êò2ôÝ�ŠÑ¢Š£{¥A{*Ë+HFÖíU[@�?-Ęô VÅ¥²Ú[¬HI©=é/l¢¾„E6ìÜ œjÅ•ýƒoÚIÇL�ð­ xÚŠ1ò¨ÇÖ¥¢€ ©}§A}´Ì2}ÖS‚*Ý�tvYåçúUë(ìaòã%²rXõ5fŠk ‘£ ÊMR¾l¸íÈãô­z(%4ÕšY)iÆéZÊ(  wÚlû Ûƒ'FSƒUÆ…ndœŒu©ER´Ó ´“znfÆcÒ®2†R ŒZ(,hjNÓ †î1¼?nHýì ÜsZôPVÐ%´ yÚƒ=jZAK@óèÖsÜ4îŒ$n¥XŠ}®™oi)’0Ìýcœ}*íQEZö ä 8bM¬ES:§4 ½Z´Pvð%´ @„A�šŽòÊ Ô p›‚œ©Î5bŠÌ *s!çºÖ�PEPqÑ,‹³ì`X’pç5%®—mi/™møÆY³Š»EAwg ä>TêYsž0j Ðì‡E“þû5¥E2(ÖÖ8ÆF¨o, ½ ç©;:aˆ«4P+}*ÖÚU’%mËÓ-œUÚ+œ•¯µ_2H$*!•“ËVÛÇcžô«6‘g4Í+Æw·ÞÚH´{8¥I_rŒ¹#5�,õ\&üeÿëÔŸbÕ9pë¥0:*¥s¥ÚÝOçL„É€¹ G²�ެ?‰�ÒZgØõ^˜“ð“ÿ¯@Všu½›³Â§qË15-ͬ7qìž0êGµsâËVþZõÿžßýzy³Õ�¤ü$  Ht‹H%*1e9œœT·š}µë#\!b™ÚA"±~Ūž3/×ÍÿëÓ…ž­Ósã×Í  K}*ÖÞa*!Þ:sнX#OÕOïò{bCQý‹WÎ 7ÔM@×Z]­ä¢Y£&@1¸1û;(l‘ÖØvÜwóXÿ`ÕzyŒí­9t�A†Zé�ÿ×V4³smÜ&—r>•¾�kláá„+‡$ÖOön¦~V˜‘Ó>i¡ôÍIF]ßöÔŠè*¼¶6ÓN³I´‹Œ7~+銀Và±=A•¸¦ #QÏ.¤z™I ’Šç×F½R?~¤�ýöªÖ×;<ù·3ç�!‡šØ¢Š)ÉcI£häPÈÃâŠêXpr¬F1ÛµwTÒŠz¨?…svšÝÌ^M¸‰e9 ’H&¶5{y.t÷Ž% ÙëƒV"´·†BñŠíÕ‚òjj`rm§JÛâúÜZßð‘[¨]ñHêF«$L1,hÿQš¬4‹ûþÌ™½?*†ï[·µº•gÀ™{f²u¸d¼K«f*@ù²1ÍnÜévwO¾XFücp85�ªYÚij†$g‘ÏÛ!G­jjv’jH!` ƒÐÖD:ß;•±nµ§¢ê/x�¡CÆþ!Z´œO¤QHÛ™WŠžŠ)QEU#©À/E©ÈrvƒŽ3Wk–¼%5ÒÄt�1úPSEPEPEÏ\=Êëñ+LÍ”asÀPCEPEPEPEŸ¬\ÜZ[¤¶øÀoŸ#µhQPÚ\%ÕºL�tô55RmÎ)h¢Š(¢Š(¢Š('ÄD­’cûÿû)­8Ô§û¢³žõÇb¹Îyëž´€ïhªºd�.�nï�ÅsV¨ª«\GËnåvçp~‘€e!†AàŠ­at.¡É?:ðßZy»…nñ!íŠÍ�~Áª´yýܽ(Ö¡1Ê—i�WïcÛ‘L š)‘¸’5qÑ€4ú@QEQEWR2-„ƵÂðEZ¨nNm¦Œ„?‡Cçý”õY[õçúÖ­fèJÈ÷%³ŸÀV‰ š£¬¼ÑØ—�Š�FìzQ£ÜµÍ�26çRA?ʬÝ'™k*õÊšËв—1ç+…#õ¦ÕQHŠ( Š@A¥ Š(  ×öÖϲY0ÝqŽ•]µË8ó‰ú!5-æ›mvÛåRœW'qäI#}—qU8÷¦Ký»gÿM=¾Nµ×ã!Lv³¶îŸ.*¥ºKoá·™TyÎK#•RzþUŸo­^ÂB¼ã`þòŠÛmfo›e“ðqódJhÕï,±úãùVCêó³oHÏ÷N'öœîFÛÇ#¾¥k½ö¬ÿê¬öã®Wÿ¯H%Ö\«Çà+:=ÆA¾ »å"™-­Ü¨Æ+±&Ñ“²sœ}(ô�¬àãÍǰ¶ÕfRÏÁõ|Z·áfci:¹$‰3’sÆÑ[”Ìh…´ûé’åÖ4ÚAÜ{äcúÖÃkZrŒý®23Ž9¬?¡[óŒüê/éXŽY g‚½¨Ðâ–9ãDáÐô Óêž—k¥Œi$0ÞI=I«”€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)’ÿª÷M>™/ú§ÿtÐ}(çKµ ç÷küªÝRѳý“kŸùæ*íWSÓ®û­U]L§\p h�9G£7ó­ ÏÐÿä1ýöþu¡@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@W¿]Ö7Ö6þUb¡¼RÖs(%ð¡SBÿ�bcûÍüëF³ô@WMEa†V`G¾kB€ õ@øù—ÜúW)÷zd­´4NFe¦ªøcæºãÙ*†£k”á ”¸Ç9 àÕIoîä‘�ç“-× @üªË7ÍžO4ì4)¤žÄ‰rBªÇ¸®i’;}I× R±ï€k­µTŠÎ/²¯îöŒX‘ÄÄ—#oÏ?Eÿt †Ž†©k9þËŸ'ùŠºªBŽ€bªjÄ 2àž›ií0cN¶ÿ®`þ•j«iÏæX@ØÛò�§f€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ @1ÜŸ­-QEQEQEQEU ºæS�Çñ«Ç¡ª:qÜ{qA¬> 袊 ‚°üK…[gx�ùVåbxŒ [gƒ–çò¡´:RÓP±ê8§PM“ý[ý :›'ú·úÉðÐ?c‘ÈùYþ_ V½døs``3÷¹Ï®k`e ÿŠ’CÿL?µ«%OüT­ÿ^ÿÖµ¨áIeŶ�oök=‚ �ÛqÅf¦³ªN¬ðÙ¦ÁÔŒœ*dWº½Ú—�•Tmüë4o–öXÄ$còÆ $Qí�¢t]ùÇ-À?ZÑ•5<·@3�8dþTË./_j]”ÇÞ�J�l·!;í##Œ—çô©4µ’Îg-w iЀwoúSÕ”ïôº|òoF%}qÅ3Ãm¶öâ0N6ô÷Ö«Aš†°d˜>ñÆxµhh°uK ¹#Ÿø 7h¤¢� Eek“ÜÁMnp2I úv©×Uµßo Wt ÏAžÙ  ÕäæÚÖI–6� ÎÕêj®¥«&žÈ¦3!ažàUËyÄöÑÍ‚ªêد¥ßBÔÌÑŽò¸úUÚhe)¹H+ŒäV4ž"�\�™3ÉÈÍmCœWªÄñ_ÈŽÌÊÊX玵ÕÚMèe�ƒÆìv8®Ä[ð –8=)�‡�ަ‰ž61ü+¬®;@�&¯ã�ÊÊ>§ÿÕZ—äƒRX U(FÛ‡Sœ@´V=ψ-á’HÑFN ª â+¡&Y#eþèýiÓÑQÛΗ¬±œ« ’€ åuÆh5VuÈ?+ï�þµuUÌx™qwþò#ÿס«£j- ù˜ó# ;�_çWÚDV Ρ�@OZã´ÍBK ƪC€>ßþº~¡¨Iyq•Ëb˜�U}BÙ. &ÙPGãY‰âeŽ1l\¹ånsQë–7x²Â¥„˜_”t>ô½©2�Ã)èA¬}\yWðÊ2T“ô5�¥LÖ——!ÆNÇâ´‚¨ø}]F3 jö<�?V¾»óZ)jç…^8 ŽÑL6±Âò‰5 ÍëY¶÷QYÞÜyŸ(ç ëÎEs–÷ÛËæ#a² ÷«Z�ȸ½vƒ$9G©À§>¯w9e´P28ÀÉ­}9nÍíƒJ:�sšÈ¹³þÍÓP¡ýë0ßÒŸg­Å²E8s"äzgŠÞ¢²ä×m·™.ç¢c>õZ×^ó.g‰PŒ†éš@n“ŽM-PEPXšÜ1B‘yq¢bN3[u‘¯ÆfXPg<úS@?Q=ÄxÊ*VÝ=Œ p¦÷ù·È™ÏÓò­íhbÄx + µ–ÐZJ …èê2zô  6—Ü÷vŠ;#AÓñ«mŒÉó_Ç’y*f¹É°�™‡©¨·Ðü–:VFÛý¾¿89ªÿcòƒMmyª‚3œÈŽ‚•œð@ GGáfl]! °üˆþ•¿\ï…wº-œa?­t4†`x•vÍm'³.#\ÔÌ^g-Îâs]g‰5¼ qĘý fÿ`½ì0Ïlê«"üû»j`t6oÓ­ŸÌJqéÅXÏÀ‚8?º S—¥>Š(¤EPEPEPEPEPEPL›ýKÿºiôÉN!sþÉ  ÚN?²í±ÓËr©é8þ̶Æ1厕r€ §ªãû2ç?Ü5rªj‹»M¹ÇîÍC¡È8¾ßδk7Aÿ�pο�iPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPHÃr�{ÒÑ@4𪓅Î<÷ëõ«uOM ¤øí;ÿ:¹@dFÞ_‰%’ 1ïֵ뛾�.¿½z¦Áþ:h�Ñd ’(e#�GZ絆ËRE‰  €:w·s}ok Y¤HÎ1Yz£ØÞ˜ÝgDã¡äzP jI¾Öð;’ŠQ튇K¿kP—"Øuí�ZÕ¸žÂíPM&dŒTæHÊ‚M©�›ÍMâ.R'S•=¥YÑ¡¶—NŽXãU�¡F`9ÏCQÜ\ió¨‰åÌ[v÷È©l®´ë(<˜§;A$î$šç.ì§µ•£xߣc йáû‡Šô¦Þpr:zVÔš�¤£äœ¾ÇšAfHf›§lÇÖax/ðvËÎ�VĶR‚FÖÆ:߸ºÓ.¶ ¤ å¶åàŽi.n4«Ý¾{+‘Ðàƒ@ü—k—2Ê¿Ú8©lµK›}Á_rž�ù­ñ¨i¡AÓ`à.Þ)‰6“y¨±+gï DVww÷k1–5X• jÇÓ,þß>Ó�ncé]'öµ‘8ó{z«ku¥Ú™ ¯˜rÇi e(o¿³®eƒÊR¨HsžÜÔ)­Ý¬¿;« Ù ¯éS^.Ÿstn â¶7(C“Š™ÎŠÐ,E¡Pw~tÀ¥5ýõôŒa2_ድ.Ÿ¬\Û̱ÌÍ" Cõ¥i}¦ÙÇåÂ\É%I&›-æ’÷g‡|£1Ž�C=ék7ûrÏyÿï“H5ÛCÿ=?ïš,ƒà£g¦ bxT“m7Õyü*K�~ÛÊu�d,T�‘�Px[ƒr£;pŸÖ€:(¢�Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@%-QEQEQEQEQEQEQEQEQEQEQEQEV~”A’û#ö–ÈöÀÇéZ�jñ[ÛÞÜ€ÍûÙýN8Çé@4V@×íÙAHÜúŽ8¦ÿo(Æ`8?íS°4V+x�âŸBÔŸð�ŒÿÇ¿þ?E€Û¢±ˆT�õ?ïR7ˆ@¿5jŠÄ!Áƒð:_øH¼þú¢ÀmQX‡Ä ø÷ãýúˆF?ã܃þýnŠÄ ÉÇÙùÿ~�ø‰AÇ�8õz,å†ù4Ç×et*ðDTõ’(ÞÔg&w ²nâˆr<]0õB «Y &Û¥¸�V"0 x~W:¢Ü-¸id_(…n¼ö ¢¨ë9þʹÛ×oõ«ÕOWÿ�eÇû´€–IJ€.1°túTõŸ¢é‘û©­ (¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*µ‰%óßZšŠ›[Q@‚°üJ>KsŽ…³ôÅnV/‰0D_›• „9E> S©¨0Š=…:€ Fû§éKHÇ Iô  ä[K‘�˜ôÅlV7‡`—ýáü«f˜äãÅŽ°â¶ ÆO^•�) âxG÷¡Çó­f@X1ê:P:…·Ú줄}â2¿QÈ®[N¹:mëI2>Ü*:ç?ýjìER¿Ò ½;›)'MË@Ë[]Ê.`•I SÁ«nörEl·w’‰R 3§ëŠü#IžnîÒ?‡ $ãÕh3i£r^íÉ?íóü©�k¡¯Îne?F'úT«á–Ý–»ãÙ*aá˜{ÜÊþC~‰‚ܶ;’EFÓ骗äöÌ•­ÿÝžA/7Óu=|=d>aÿ�PM¦¥!ŠÌ+·É¸ÈIæ¶´{ ¬ÄÍrêòHÙÈì*H4‹($$YeèX“W¨¢Š)OT·{›'HÆ\r£Ö¹¤Òî^Úyš6SÆÂ¼·Ò»(’Ó¬¤ÔœÉ…[=a[šË‹}1¶å@*£ZЃÙbŽhÌr t=AÀÌÑ&7K'ñ!dþ£ô5‹¤Yy×Ã2�ñÅ»ý«ª¶µ†Ò/.Þ0‰œàzÓ–’V‘cPíÃ0šålîæµi!¶gnF2sÒ¢›GÔYˆX˜ó¸‘ŒŸÆ»k!�"‡=XM>‹�Ï_ii¶žÎ4 �7q‚;ÕMGM¸[÷Û8v,¬£ æºÊ(¸ºxzáí�Ý•eþÏ_©§Xx~I7ÍÐàü¡H$×ME ³µK;q eŠ‚N[¯'5=PT5=1u™rŽ™ÁÆx5~Š£‘e(û:3‚Ì2MY[h?-a@ŸÝ 1RÑ@ÃionŠCêš­«Þ›;L ÌŽv¯·½_ª×öI}–ä®TŽÆ€9‘#‰2ì 7±Íulšž››*ÌŠÀŽ â³#ðäÅñ4é³ÕAÉ®‚4ƨ¿u@˜–ZVÒ‰C!S•À©.ôk{©LŒ]œ�§­hÑH –šuµ™Ý>1½¹5$öv÷¢W#¹= Z[¢X# ;möŠ6P¬ŠTtp)ôP`cªej\9·�pï´UŠ(ía¸‹Êš5xÿºEI,h¨ƒ £zS¨ Š( Š( Š( Š(  ¿äiŒÃ³©­ õƒ×`þUG^RÚ\€zйhÛ­!lc1©ÇáLN$h$�$*v“Øö®JÔa½í‘fl‚s÷»õ®Æ“€Å�J¸˜«]HGSZQÙ[¥¹�b_,òWÔÕš)Ü ¡¡[ 7n|g;kA-âEcQŽœT´R«hîà0ÊӃǵ-¼ oÄŸuzT´PN•ium}uçs r‡=y&£ŸEy/Œˆê!s–ÇÒ¶©)��6‰i5´pm*¨s•<Ÿ\ýjù‘.»�EÏ4îÕÉ[L#Õ…ÍæíêÇ'ƒ‚?*·x›5`reSúƒ]sÐ7Úõc"ÿ«œŸJèh`gkñ­öÙƒ“Ô©ùªž“¦ÜÅ4wü¤•''šÝ¢�ÐéQÁö˜‰‚ v晨hÑÞ7˜§dž½A­J)Ü (|7æiY½Œ ¯&‰%¾§nС’"’sÊàçŸÊº6u_¼À}M( ŒŽECwl—ví ™÷A¬#áÉ™Îf@½Ž5ÒQH 'ïœlÇðõ4Ãáù^ù™™ Ù98ÏLWEE;€QE€(¢Š+/^CöPàAÇ`{Ö¥!�d¢€2ì.ÓU·’"#`Žx5ŸqáüM¹.cXÉèýEt1ARTÐV3øj9Ì—26î™â˜ŸÃê2Æî=꼚FÀvÜ[¿ÑñŠÖOÚ oy_ÔnÆjq¢X Ã�}XÐ:t× [Í€ã°�Q-¹-�Ã=«¦ˆ9Øÿ÷Ù§®�d­¹c`Þ4VÇP´³¶XÝ€“ø¶/zœëv`ýç?D5!Ò,‹ÐO\“J4›ÒÝ(”·6úË}“d‰† ®GqÿÖ­kxRÞ†?ºƒ™�½»†%V=HÔô€FŠ0)Ô˜ ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦¸Ê0=1N¦ÉŸ-±×€)è˳J¶ìÿZ½U4¦ß¦[60|±‘Vèªú€ÝapxÛùUНu¸XϹ†v7 vÅVÐÆ4ñþû:ѬÝ·iÀÿ¶ßδ¨¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠB@ž”ZÄçí'~ýº~j«Ù�Vm½¥oçV(¬­rÖ6±–u�÷¨7nQÉ­ZB�h.M:V(.]¤FhסíÖ™'‡â|mžE#¾­p008–€0ÿá\ÇËg×h¦�s“tïŠÞ¢€1‡“5ËçÙEñœbæOûäVÝ‹ÿô`ä\8¶"hq8Ïœàƒè+k¤T œ´ÀÉ89™óô« Ä§>sŸ¨¯E 1ßAG?ëÜ}RÂ=ü÷“ò³Ed ŒJÿˆæÐâ`•øôµh  µÐmGV�þ4‡Ãö§?<£?ít­Z('ûÛ?ë%üÇøQý�mÿ=%Ï®EkQ@ð�Û‘þ¶N¾ÔÛ’{(œ…kÑ@’xnû·¯à hiú|Zz2ÄY‹ãqnø«tPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE™´´RdzÑ‘ê(h¤,R)  êËùШ¤ eH#ڂʽHS@ E3Í�þz/çG�üôOûèPè¦,¨çêßCO šÄ’1×4U ž” ¶ úf€!û©û€ÔÛ—ûßzƒì6¹ÏÙâÏû¢“ì˜ÇÙ¢ÿ¾NdE. {šd—0Ä¡¤•Orh‚ÆÔ-âÿ¾E(²¶D}s÷EF5;"ûEÌyúÐ5K#Ÿô˜øïž(Agl½ ŒÀE/Ù-¿ç„_÷À¨›S² í1�z`æ‘uKQãÜâ€&–ëÒ‡Ñ/ÙáÿžIÿ|Š„êv@ö˜È‡4Ó«Y g„ƒ@ý–Üœùÿß"�²ÛÿÏÿï‘PZÄ)o´.Ö£þÛ±Á"B@ôS@¾ÇmÇî#ã§Ê)E¬?¹�ž¿(ª^µì’‘ŸîÓOˆ çH@?d·ç÷óþȤK+häGo¸èÁ@5š|Aÿ—wÇo˜Sˆ‡ðÚŸ|¸¦åSÕÎ4»žß!¬æñÛů>ïÿÖ¨'×~Ó°IÑ"íÈn”©¡gû*Œ·ãÉæ´*¦”¡tË`:y`Õº@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE‰âQ˜`ÿxÿ*Û¬O!ƒ°ÜÙü¨@m/ÝJZd|¢ŸaO ‘†T�jZCÐÐ7‡[1\G�³XÞû—<çé[4ÀÇ™sâx¤$ÿ:Ø=+"S�Ãÿ\±üëb€RÒ Z@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEfëÒôæ#©`^€bÇû#ùVˆ@:w98qÇçZ¨�ýÑü¨JB@ê@¨®®Ö–CÀíê}+›_µkWŸÄ±ú�ºƒühª¢š‹µsœ f�@Q@Q@Q@fßhðÝÊeÑÈz‘È?…iRx­T°Ó¢²S´—‘† š¹U,/ÒùdÚ¥J};žáÞ;y^5Üꄪúœq@QY:÷³yÍvŽ�T¸Ç=ð=+Z€ (¢€ÐRÑEQE)•ÆUƒPi“§›‰œnR+ÃÌÉs,e¸Ø8í�h ¤Í7Î�xO1wƒ<Óè.á¸gXß,‡ O\ö  –¬“/ Hoñ®�Het#4ÀZ(¢�Q@V»ªOo0·¶!Nܳc‘ô  Ú+›�QÕLH‚'Þ#9#ëY÷s_ÝÎ#-&àØ9§`;J+“}?V†=ÿ¼$vËŸëZÔeœ4 ]‡*Ç®=(rŠ(¤EPEPEƒ8ëÞ€Š( Š( Š( Š( Š( šä„bN8§Sdb±³’ P-?Ù6ùÎpz�sWꆆXé6åº�sùš¿@W¿ X\g§–Ý~•b«j:}ÏýÛ*«áñÿÅ>®Çõ­:ÍÐHþÎvv­iPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPL”×Sé;N:ÐTz„Ênç|2zÓ×]³eÈfúb¤±†9ãÌ�X‰ßï ÷«-k´1Ÿø¦/íËQÚOûæšuÛleUÏåWþÉnzÁýò)�°9GŸ÷Eg�~ÿ,¤ü�/öý¿8�ø÷wì˜ÇÙ¢Çû¢�§Ú¶ˆþÀ  ÄŸ)³õßøH¡ïø­#elÇ&Þ2Ýákn:Aýò(/þ(;Dß÷Фÿ„Žóð!Wå60ˆ»d �#„¨(‘•>€`ÐWü$0çýQÿ¾…ÄQ±cêµü˜ÿçšß"�*?î/ä( ø�GH�÷©§ÄKŽ-Éÿ�VÏ–ŸÜ_Ê—bÿt~T‰ÿ Sön?ÞÿëR�1Î-ÿSþ·µº?*6�A@ŸÛî:Ú‘øŸð¥ä›y¶Á=OøVÖ¥  OíÙ¿çÍ¿ ßáA×'ä‹L|çùVå†5»‚¤›RnÊšu»¬ql ÿu«tœVe®®%½kicÙóSŸç@†·tGüy·ýòßáGöÍæ2-‡\r­[´PÕï³ÿdý©F¯|Güy0÷ÚÕ¹EakjœYœ×6£ûSSíeŸø­Ú(¸ŸÚ:™m™÷ RÔÁØ’;�¦¶è  ?í Tò¶g¶ÃÇëN7º¶x´Áô+ÿ×­ª(ÞjøÏÙqì?Ö�Ýk'¥°ðþ5¹EbµÆ±Ž û(ÿúÆ0mùõƶ¨¢àbùÚÁ8ãþùÿo›­†ÿT÷Ûþ5¹E~µÇÈ?ñÞ)kG‚ {åknŠ..Ýlò±"�·Z¢>üVÅ\ bšÖÍ}ˆÿ Z×¼�ñ#ü+fŠ.9‹Z?òÖ ~¿ýjO#ZÚŸ=ÎúÕ³EÛkâå=¹ÿëRùÉ\yñýAçùVÅ\ o²jà`])ú·ÿZ�i«Ž~Ô™úŸð­š(¸¿Ùú©äÞ€~¦� †¨¡·ßŽFÖÅ\ Q¦êŨÃ4§KÔ9Ô[õÿÙ¢‹��ý•{´~ÙüÆ�i7£�¨°˜'úÖÍ\ a£Ýç�Að}Ö�ì›îŸÚ'o¦Óþ5³Eh×Xæý¿#þ4«¢Ü…Ãj2“Û®?�lÑEÀÅ:-Ãcuó�¦Æ—û`A]BQ�Qÿ×­š(¸ߨN~õô¤ŸQÿ×§&‹,rþU÷ +^Š.\š]̉±õ)™OPTsQÂ>¼ƒw.µlÑJàcÿÂ?]OŸr )ÐS*EÔÀŽã¯EþøÏ[©ÏÔŠrhH�.§M¿áZÔPwöI徺_£ð¦K¢G9k«‰鹇¥jQ@Ãöá²e”þ_áNþ€ó;d…jÑ@ŸØÑ�µnn{€Ýiߨñci»ÿ¿Æ´h  á£AÔÍrO©”Ñý�oŽ%¸þi­(8hðÿÏ{¢= Æ‘´KSÆéÀôšÒ¢€3¿±m0ïF=%aGö%Ÿo8ÛVÿÑ¢€3×E³RHY9ÿ¦­þ4ŸØ–=âcõv?Ö´h  ØÖ9Ȉ�mÇŸØ–B˜8 o<~µ¡Eg�OÜ~,MØšhýôkBŠ¡ý�`@ÝN=Í)Ñì`Û.=2qW¨  K¤X/KXÇáIý�§çþ=c«ÔP1¥Xƒ‘kü)²ì¿çÚ3õnЍtË&XŽ:|´6Ìã6Ñœ³Vè  £N³"Ö Ü¢ÂЋh³ë°Uš(³XZ7Þ¶ˆÿÀ7û.Çþ}bÿ¾jÝOû.È‹hÆ}ª­ö“g”òEn‹"ÆÄ7qZÕ[PãO¹?ôÉ¿•3IÒí똫•SJÿ�e¯Ý/ò«tQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV/‰†m¡=ƒå[U�âL8ÇrÇ‘¡«ú´ÿtSê89†3þÈþU%QHzP?‡F"¹é1±XþÇ—uÇ>qÉ­Š`eHøŠ,çp�ðèúõ­Y2ÿÈÇýréëÖµ¨¢Š)QU®/í­\$Ò…b3ŠÊºñ_²&T ,õË®«¨Ê¡!¶®âŽ^ÒuÁvþUÆÕs÷HèÔìÕQHŠ( Š( Š( Š( Š( Š( ›“ýÜ}iÔPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPv¼?âY# |„75vÜæÞ#ê€þ•Ÿâ&#I�â`çWíù¶‹Ð þTÎê7Ú7ër�%Nn{šÚK›;(1""(À¹;ÛVµ»’ xV8úv­K]&I­Ä²ÏFN98¦´zÍ”’ÖSŸR¤ ¸²+;‡Ì2=ëû>Æ=:k¨d2�„ïϧ^+K™$upNS€h¸¦‡RH FzVv“©-Ü;%`&NOÞ÷¬8®^ÖöYI;Îð>§¥®ÍAuy¢«KŸ˜à`f¹(u[˜nS#9�dž³>¡oªÚIA„Èž`zu¢ÀmFë"+¡Ê°È4µÌ[ë2[YQH z[n¢·¶Å› "ýåþ´X k¨e ô#¹™õÛ�s˜ÈTÂFknÇPŽöSj®Y( Öüi÷.@Ü+·>õ£¥jó__Ïq°;ŽN¥PÒ-­§¼Ÿ•�!8Ï­mè­3i±›’ÆL·/×8«õ�¦êQEe‹¹ÆðÍדб.µgjË'˜[ ^´£EgYë×Rù�Ï@ÝëF�rZ¦fÔåSÁ2Ïä+­®gY‰¡Ô7ºä8>ôÐú�ÐÓìFÕÉ8E…gxzÜHÍw jg¹îjñû.µB_°Î8 â«]¢G=Ž�Ù°bsÏm†¹mvjq(À8<{bº+éÖÞÖI㌭ax~’ù§'"4#ñ4ÒÑE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)®pŒ}©Ô„d@4"N“NOÍÿ¡ЬícJˆ{·þ„kF€ †ïd›=66*š¢¹O2ÚTé¹ý(�‡ÎtÜœd»gZÓ¬¿ÿÈ0uûç­jPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEŒp¤ã8WOÆ.1ÿ=ß5n©i¿vçþ¾®ÐU¯¯b±‡Ì”òxUîÆ¬×/âwcygåTÈRš9µëÙ\ùec_E\ÿ:ÕÑuV¼- øó@È cp®^ o¸zb¯iŽVþQÈoÓ½v5^ú_&ÊgÈCŒTâ¨ëN#ÒçcØç@õ�ª^�Ò2º&áïëZ: ËùÏnÌvÊ�Ʊ­�Ä„FNXcŽõÒhúy¶V–Q‰Œz Ó)i23ŒÒÒ¢«=ý´w J<Ç8sS³ª)g!T ’{P¨¬û}bÖæå`ˆ±-œ0+B€ (¤Ü2FFGZZ(¢€Œ‚+œÖa1OÑŒ3sŸq] Hˆ@gU' '­U¿¶ÛHŸÅ÷—ØÓ@Y‚A4) þ!šxÏ9™ ÍæZ´g9FïïþMjR¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ª÷ÿñáqÿ\›ùTù¨/†ëǬmü¨-#�2ß�p˜â®Õ i6àõÁ?©«ôQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV?ˆÀû3óäkb²P2 g@Eާ±ŽIVút«šµý̲"ÊÉ •$Œ3ÍUfŽûZQ¥úŠ`fyLó@X“ŒzÖ®‹iuüRyR$c;‹ 1Tí›Ä!Fqq·õÅv´ÁHdXÐ9êÁFM9Ñ] ¸X`ƒÞ�E ¶³‚Ò2�FXä�Z­.‹c+î1ì¬@?…hQ@}ŽßÈ0y)嫎*œÚ Œ»qLuÚzýkNŠ@‚–Š(².øÙ3�ÃÍ·†î ®�o©Îk¦¢€+ÙZ­�ª@§p^§Ô÷¨­¬mmîdš"¶xÏ×q†å#¦EdIo2ÎBÆÌ3ÃzÐÙ¥8)îìejÚ}Êê3J±»G#n £=…2ÛI¿fÞ±ÿxâº?.ycÚÀ­$O5³„‘w#t9éL=Ÿg©�iáßÜ¿Ú\,Œr6s�ZI§¤ZkÚ!$2‘“ÜžõvŠFgºeãÜù" žIQøÕ´ðõÓ,›Ê!wœî®¦Š`rö:5Ù¹�¦QFÁ‰'9ÁÏÔQE «}d—°ìc†u‡jµEq¯öÝ*iï�wìÕUÍ̦pB§yo§5Ý:+Œ:†„f’8£‰6DŠ‹è£Àæ^âóX`‚#·‡v"»ò]0m ï]%sRAöu¶¸^wž}±] 9ÐÀZÊñc§ðÐãwµjÔ‘ ìæˆŒ†B?J@`hVp]‰Là±B03Æ*OF‘}™c@«†à¥VÐg0Þ¢·A´�~Õ£â,*Û»}ܰüȦÍ-Cip©)L¯&�ik òÅgòÛ› qÚ¬i$–”< �§5mŠ6c$dŽ™çÍøu7_ïÝ÷c8\WO\´±I¤j Ãî õ•´ú­ºZ,äòÜîO¥`ßX�:ór¸d$ºŽàWR¼€Àe¶çñÅsö°¾§¨4�÷T�çú èÉ 2x€9Kx.µYXAÀË3Ö�–� A�ÖÙ‰?.2¬•¿û-ô“[`©sÇb3]\2¤ð¤±œ£ŒƒC8,mmä2C#‘Œ�V(¢�Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@ ŽAÍ-Pv¸?âZçû¤»úˆÿÝÊ©kÍ·J—ܨýE^‹ýRº)€®êŠYÈ I=«%¼Cl¬BÇ#zð3Mñ5ÉŠÉ"^ ­×Øs\ä;]*K“Ö€;‹{ˆîaYb9V©k/@GK`%}Ç©HŠ( æ‘a‰¤s…Q“QÚ]Çv…£<©Á¨©f�f…ãa•`A®sL�loå6Õ «gÔtþ´ÀÕÕ4µÔ°.UëTô­k[¡=Ĉvçh\óïWSWµ’í GÎà~nƒ>•~€8±–úºçï­ÀÀú·øWkQ5¼/"Èñ!uä1Š–�%-[PžKkV–% TŒƒéžil®–ò"Œ„z’á�H‡º‘X¾�ý¢x‰þqøÓzŠ(¤EPEPEPPÜ”CSS%�¨w§r‚)jfÝÐÔÔVv (¢�Q@Q@Q@Œp¤úS!”J¤ŽÇÚ\’Š( AEPEPEPEPEPEPEPEPHzZ:Ðg‡É:Zg®÷ÿÐ�iÖn�ÿ Õç?;ÿ3ZTS&8…Ïû&ŸL—ýSçû¦€2ü7�°ÈÇï? ­zÉðòl³”ùé�ÐVµQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE„àKM~¾”ZÁ·5×9Äì?AVê–ž~{±ßÎ'óQWi° ÄÔôg¹»Y!*ŸÞz{ÖÝ€ç¤ðÑÚv\ŒöÜœP¾”u¸Lÿºk¡¢�ÀŠÞ/"�9ÚÍKE€FPÃdP–Š�ÔäÕkw1^4Lxuܿ֯‘šÎ¿‰‹$‘ƒ½E0&›t’…+Þ­"í\U{L·ÌOáV¨`&(¥¢� 9=©®§-&)Ü_»N¢Š@QEQEQEQE‡888=�-ÈÃ…ÄŒú�Š}!8ÒÐEPEPEPEPEPEPEPw¥¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š) Å-!dRÓqN Š( Š( Š( Š( Š( Š( Š( Š( Š( ™0Ì2 g*•>£œí‚FôRJ§¡¸}* `éèkB©hë·K·ìóWh¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¬¿ãû<Ð8þµ©Y~ Ó¿àb„ëNma?ìåSTDµœõ1�åSÐEP?‡Çîîp婯YÇÚÆå®k^˜—xþÞ°ë÷ùV¥e^65ÝͫĎ2C”ÏçW¯§ŽßYŒ£ üoߊ¯­#Zê"xø,CƒïÞ´íìmnÙ/ÊŸ2@¬yã"˜U™¯MäØ<1A>•§QÏ sDzd™Ú�ãkYÛ)ä ž=x­¡ÀÅdZ¡¼Õ$¸ëôé[ØQH^+K�í…Cª‰rHŸZÜÔìEý¯•»c¹N;Õ¶!FIÀ¤GY20e=¦ ÂK$I\1gÜ1Ð Tµ]2éï¾ÕnÌàŒ`2ý=«z«j ie,è»™@¤/4Z„¸Ib¹r½i÷wXÂχÜÄœghãÇã[Ú=ûêÏ$ˆ«mÊô<ýjäóGeæ`«ïLjÃZ{s&(ÌaÁäã5Ô2†R§¡5‡ ÚMÞ¦ˆ�?$ƒŒ Žkv€0¤ðÔeÉŠvDþé\ãé[Pİđ Â¨Àªz½ÔÖ–¢H$°žÔí&鮬դ ȼ1õ  ´S$‘"Bò0U$“N9�i´QEQE„€2HÔÒÕaCé“¡8Üýhàu'�=qšuq–¯-¤Âh‰8ÏcíSêwòOtZ �cdh$sÞ�€ë(®vßÄE²Äñ™$A�Äã4�âV{i1ŽR0§v@4XŽŠãmïõ ²H·Mާ$~‚´¬5  �›÷,Cƒþy¢Àth®gNÕZ+[¡#�ÁAŒwÉÈÿ †×[¸ŽäÉ3—]„lížÆ‹ÖQ\r½íõÃ:»—ûĆÀQW´ÝiÒDŠáüÄc�ǪÑ`::+—žîk]q�Ù¶‰>eªâµÓZµaÕ‡áE€Ñ¢³$×mS8·û©šÑ�·Æ­‚»€8=E EPEPEPEPEPn¼3¦0õtøð­]¨«è1T5Ïù“’u'™­rèÄÖþmŠJ:ÄùüáYž··žáÒ`K £<_é]Dñ,ð•s_ŽOí58b$ ©Ç«úΗ-Ìpp£H'P÷Ô-â³[©\*2‚=OµcÍâG�‘mQêüŸÊ©¾‹|è„áznaU>Ëqnå$ŠEnŸpšé4½_í’˜%P$ÆA sº›¨Ýã÷‡ð­mO¸K¥žXÌhªq»©ÏµI¬èÍ<†âÔvûèO_q@¶—ab‰=ÝÄ�Ѐ8ÉëÀ¢šÕƒô›U"°µØn#kE“î,!F:¥QD$({ZîQÖE ŒOB+Q×%ŠèÅf¨Áx%†wAW4›i¢ÒÌr.F,@ôÏJçÅ•í¬Ëû™<Àp.yõ ŠÿUŽÆ5,…äeÎÑYVž#”Ü7ÚLMÐ/Uÿl:5íï™%Ó˜Û¢oç?áUC¿‰ÈùžèÃÕAsô жGC‘È5�£¡†ÿæ dÇ¿_éW4; l¡�Ï€òòƒœb¢½ÓnN¡ö…Bnrqƒþ³ER¢Š(¢Š(¢Š(¤##´P{s‡ebª€VóØÕª žáEP@QEQT®÷É:ƤŽ21RÙNf‡æûëÃPhàÔy‹QQ}¢-åw ÐBMìHFF*µ°òå’>ݪ×Zϼb·!ÁlP]5Íx—ò=ij´¢3¹Ø³}x«4$“Ð(¢©K<“N`€íÇÞj1r.ÑUVÖHÎä�Éôn”ë{‘+20Ã/ZãÕjO¸ŒŒÒÖmã=@o—#§j¼òªÄ\€(¡dŸrJ*žŸ+H¯¼äçŒÑ9�B¡Ã´³|ü¥Ê*­½Ô~Jï�nÇ9¨'½fŽ¥©I»4T)sF°\ö4ô”; ñÞ‚ZÜ}Q@‚Š( Š(  ÝçMSÎK¹9ÿxÖ•ghCp’8ýkF€ dßêdÿtÓé’ÿª÷Mfø{ÎBA|þ‚µkÃcmœž»Çþ‚+b€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ FR=©i¯÷é@lÔ,÷`Ï@Oýò*åV¶¸¸÷e?øè«4ØQHŠ( Š( Š( �€F -ÕP£�IK@RPÑEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE‡=…-PEPEPEPEPEPEPEPEPEPEPEPEPEPEPQ΂@yOò©)“¨“ýÓü¨¦‹Î—Á�l}I«ÕCD9ÒmÏû?Ö¯ÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPY~ û? ôqü�jVn¼q§7û€-ÙqeóÍ•OU´Ó�:ØÿÓ%þUf€ (¢€1ôæðöóHþu®+'DÀ’ìžgøÖ½02oä=§ñü/ü«Z²o°ºÞœO£�Òµ¨)i)iŸ­Z}ªÉŠÞGó/}EfèúºE·˜«÷Xv†º*«.�i3xqê@Á¦m«Z*îÞHöVêîæúŽš›¢rDŒx"®&™h‡"?^jÌq$H5 £° …¨´µX�É“ïVh¢�Q@µufÓäÙÔ`Õ 6óìº3»`”r}sÏõ­‰£óbtþò‘\›Å*\‹<œä ¾þ´À׳×b•å/–Êœç>ßZ—NÕ×Q¸–$  ¸dç#¡ÍgÜè® #�x Ö¦‘§}‚ÞA•ÎX�ÐPvÑý®K1 õŽÐ£¬í~f{ß,Ÿ–5¤Ô×öW#\‚ku;”–…Ç\ýEK®i“^K–à�¯“ŒZÐKx¬­I†%œ�É8¬�3W+<ÿm˜ì Èè{ÿJß* =ÅcŸEædNá=03ùЖ¹·Ôì§XvÑÈ#Vf—¨Åkqå0!d!Aµ¹ieš…1Ÿ¼O$ýj¼=¼ŸiRÄŒáOA@^#ŽCt¬ùòŠa}=ê;½Iç†-Õ×` …<·®šXcž2’¨e=�CoamlÛ¢ˆõêh¸—ö…äH`óePBy�ßÝA.ô™Ç±$�ʺMKEŠþO7ÌhåÆ ƒøR¦‡gå"Ìžcªà¿LþT\ ôÛÁ}h²ã ’¬=Å[¨­íⵋ˅v¦sŠ–�ex…�l¯O0núsýqZµ^úÔ^ZI 8Ü8>‡µeéP%î“4dŒ³œîœ Um'K›û@µÔ%R.yèOjÔÑl%°†T™”—}ÃoL` Ѧ¾F¹.’순íÆHö­H¬m¢ƒÉX—n0r95fŠ@ssx~e‘„ †2xÜy´ôí),‘÷6ù$cÐíZ4P>|8ÂS²uò�LŽjÁðí¶å+$€£=kbН œBÑD�U†©¬«_$2$åÑO ·»EW¹²‚è~ú0O÷‡~5Ut;E<ùŒ= V•vöã÷Q*û÷©è¢€ (¢€ (¢€ (¢€ (¢€ (¢€3µâK�ž€�çW¡ÿRŸîŠ£®ÿÈ5†@Ë(ÉúÖ€è1@÷ÚÄRyEZI;…íPÚëÖÓI¶T0“ОAükwó/ÞG²Äàýkn]âYm‰Œ²çoQL ‘¶@¬0è=iÕÍØÝO§]ˆ.7y]=½Åo]\-´V€Ç€&¢«Ú]¥ÜFD`àƒÔTvZŒW’É‚¬œà÷€¹ED—<Ï È ˆeî*Zd±G2í‘�B*(¬m¡}ñÀŠÞ¸æ¬Q@Q@Q@Ôpà‘Øâ�@)kWš{k…x˜¨eǧk7Ÿk§‚èŠ`MER¢Š(¢Š(¢Š(¬¬éIT5Ù"×xtM{©‹EPfQEToøÿSß ‰-ï Œ �Î=MMpJ]DÁIà⬔êÏi] ¢Š(3 ¯oŠi$±ÏJ±EM¤Ñ™q5ÄSa‰ ò1Ó°ÛÉ%טÙW“ïZTR5öºY"3e •àÔBÍA?3ô«4S3S’êSk9h¤)žÔø¬Õre>aDã¨1ùVÅbøkþ=§ç8“ú Ú Š*9åÆ\ŒûP4®ì‰(¨á™fMÃ�QRP YÙ…Q@‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( šÿq¾”êkýÆúP ‰§cüEOþ:*ÍUµ$Ïq“ýÎ?à5j€ (¢€ (¢€ (¢€ (¢€ J( QHzRŠZJ)h)h¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¬ÝSTDG‡”òAèiQPÙÏö›H¦+´ºƒ�Jš€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ )‚©,@©4ÈçŠV"9ˆêÍIEPEPEPEPEPEPEPHÄ*–c€9$ÐÌK1À$Ö>±¨§” …ƒo1·¥h[_ÛÝ9H_sœcµY¬�ÐÅ\¸ÃKÂ�E­j(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)“s ƒý“ü©ô×û�ô4GAÿ�E¸Æ0ýMhVn€û´ÄÝ$~¹­*(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š+/Ä9þÍ8þúÖ¥PÖB›Þ27 ›Oÿ�}·ýs_åVj®›“§[gþyе@Q@ú<ËÂÿYþ5¯XúúËÕtIýMlS+SêšqÎó�ëZÕ‘ªœjzi$�œÿJ× Š(¤EPEPEPEPM(¥ƒ‡CŽiÔPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPv¼iŽv^¿Z»oÿñóŸ�*¥¯ érœt*Z¹k�²Ãƒ‘±yü(QÓ"´F�Y˜»÷íšy¼¿K;U³¶i'ÌøÎÓš³¯¶Û8ÆzÈ?‘4ëkÛ{m)ei*o''µ02—LÔ/fÝq¹3ÕœŽ>‚º?)L>S|Ë·o=ëŸÿ„ŽV˜ì…v€õvÇ\[™R)bØìp9  úcMN[fé!Çâ?úÔÛþÏ®‡!ó»¡úÒ#²K¹O*s@?ˆ\%²âÝ�Y66WZ„l¶Æ§“Vo.[RÑÖá”+E&ÖÇLãÿ¯V¼5(ky¢Uƒ~þªÒÓíM�œp.W«³\ÝέqìÈ�•W#k”äÔu;¬ý•A#¯ËÀ¢ÀtTTVÞwÙãûNß;oÏ·¦jZ@QEQEQÔÀÄlGLŠº¿t}*¦ 2‰õæ­§ÜJ eð!h¦±#§PdRz Ž Öu%sÁÁ�ÙÚâË™·æÆ IEúS$}€ ÉÇ +�¢�ŒÕ{‰|©ç½Š»±fŽ•XÞ'DVcíNyHj0cÆ(+‘õ yšbùÒ§¨à�ʈ/~õ%•¯ QEQES]¶�šPr2(h¢“ sÒ€ŠjH² ¡È¥'&€°´STrBžGj}Õ‚Š( �𠥤c…$ô€3´tÐÙ³³{šÒ¬¯¶tòi�ÄÖ­‡¡¥¤<@þÿ�y€ã?•lÖ?‡?ãÞl|Ò¶(¨/6ç5=2a˜œuâ‚¢ìÑFÌùS…Ï +F²-{”Çc“Zô‘­uiQLÀ­w3C�½éñÝDä.ì1ìj=AA€Ù¸¨5’ÌH¼2÷è7Œbâ®hÑPYÊe‡-÷�Á©è1jÎÌ(¢ŠQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEÖû�ô§R7Ý?J«gÌÓžrÁ ÿ¾jÝU´åØŒ`ÆŸÈÕª(¢Š(¢Š(¢ŠŠk˜ dY\)vÚ¿Z‘ºqï\μYu>àmVߟð«ޝæÛ¬pd9ïô§`"º¿¹º½ZÈÊ7mî}k¢PB€NHšËÒ´ómšAû×Áû¢µ3•Íšu5Gzu%-”€Z))h¤¥¤ ¢Š(¢ŠJ)hª÷wqYÂd”ýêhÅONÔPYJ#/–Øç¿«”QEQEQEQEQEV%Æ´öú”‘:ƒ giÇ^ƒŸÖ¶ë—ÔV#©Ý¬Ÿ!À*}N4ýÍìVöÞq †.?ˆÖ�jú�ãMpK"œ·¹ì*”o%ÃÅ >[ŒôQÞºëx¢·‰c‹{{Рt´QHŠ( Š( Š( Š( Š( Š( nî­´“°ÈAœõGOÖb¹Ü“Ž™èE;_'û8¨ÎÀ?Jæ¥ÄMû¬ôïL M_SûQ6öÇ1g’?ˆÕíM6hf—>tƒþèô¬;Èl¤O�ƒÛø}ë°RAÍ-QHŠ( Š( Š( Š( Š( ƒÀÍP4šõ»Û‰Y™²6‘�ư`#í ÒP0${WHt+Bå¾|�¡¸¨u=˱ìÕT�‚½3éL t*PlÆÜq�Jueè–W6qKö’2ämPÙÅjR¢ŠLÐÑEQEQEQEQEQEQEQEQEQES_î7Ò�Hßtý(#ÜZ̹Îú جŸ¦,�óËÈxôÇ­@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@g뀶œÀuܿδ+?[Ó˜Ž¡”þ´ &Ó?äm�ùæ¿Ê­U]7�>Ü9j€ (¢€1´ –¼$òeéùÖÅdhƒý"÷Ð8ó5¯L �dµØ0è%ÌV½dëÝX/¬ßÔVµ%-R¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(†´ÅtÙ ‘œŽ½ù©ì?ãÂßþ¹¯òªºÿü‚¤ë�έØÿÇ”õÍ•0(ëð¼ÐBQK|œvâ«Ç¤ãE‘6±šB$#ÐŽŸ¥nÑH2IÃykôÛZÖ,©p“ÎBl`ÀI­Ú)Ü_Ä*ͪF#r¢©÷,jçˆl'¹Xd·C!@ÊÀyÇøVÓFŽAuVÁÈÈÎ)ÔRâݦÓæC?àXÿÍðý¤Â ¤º‰£W!v·ÓšÝ¢�Ú^Œöw¯,¬¬ª0˜ëõ5-Þ‰ouv. ²œ‚Ê1‚EjTsÊ …ånˆ3@ß ’ÆeõCXžȽ�hóùþ56�-Ù¹‚éòï–@F0jf€»o&û©Œþ4ÀÙ¼¶[»i b@qÔv5Ÿ¤hïapóK2»Ú¡F8Î¥kÑH siVSÊd’.NIɧ˧ÚÍ…áMžÃUš(¬:}¼mjŠ|¦ÎA9'5KFÓ'°¸¸2²”`�zàžµ¯EW–ÆÖi<É FïÍLª¨0ªzN¢€ (¢€ CœqÖ–ŠjnÚ7ãw|t§QESÔ>ê�Ö­F1çÒ«^™*ÒýÑô Ò_�0a�sPÞgìÍƒŽ”ÛøöS@¹}ÞbÁR=j�‘òî$Œõ#�®³ªcqÆzV/©VÀ‘ëAtÕÓF•QAˆQEÃ*‰ó¯y�É�­GvJ]Äݸþu5Üm!Œ¢çæƒh¥ŸruUQò¨Ju éKAˆUynJœGR)ò>_Ë’9§*Ó (-YjÆÃ:L>^£¨5-U¶‰„Ï!]¹ãj�M$ô (¢‚Fº†B Vyp:ŒîPqVê¼Ö«+n©=qApkiR´ 2H¤Þ�Û�Çæ#ó©ÑhG£kh�·2çÛ

hßÈ£ ’ßd‡î¿QW؉am‡·j&�fŒ!ãíNŠ1œÔµêfA0I\·ÞÆY´�¼Ï-Îr2 ¢æÄ1i#ÈoOZ„‡ŽxKŒ)7­ :(¢™ÈÉ¿ÔÉ�îš}5Á1°H4“á·S`œž=ªî û k#Dh_ºå[Ø÷¬ˆ×2ù’¡¿t ÒI©t%³”K9Ë/¢žóÖ4ß�óTr[ËŒÖù*ý@íSL6Œ|ÅNs@5ù»™ÞÀ†u™•hÞÌÑ(Ûž{Ö6€Åfã'qçéŠè%�eŒ£t4e&ö;~cúÔ™ „[áq¸Ò¢Gkäã©'©¦K³Ø©bžUÔ�¾÷ ~uzY4%˜+-çf¼ÝäñÍ\ŠÕ؇¹mì:Â¥TŽªRd]ŠL¶xùrzšK;„¤Ùõ­}Ž?7n¸©Zœ‚Ȥ�jçO]7:ý¢Øìç#"’Ò"–û$$œŠœJZf\Îܤ6Ð�Ù Ù5PKm»°¢Š(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQER†–šü#}( ^‡™ü�Yªvg3K�Ç—>¼¹@ KIE-Q@Q@>#µ’GŠXãgJ�£8æ±à´¸žáaTucÔ�FÑë]µî@ùvÓQJ““‘RQH´Q@Q@%-”´Q@Q@cëw¬°Ájì�'oZجMBÖóûDÜ[¦àT(#S@U¶Öæ‚6Ž_Þ7ð–íE½”ú¼¾|ìV<ãv9?Jlú%ØŒÎJ»u(:Ó¬[UfX &4^òGòŠÝ³³†Ê/.À'$“’MX¤\íŽN9Å- (¢€ (¢€ (¢€ (¢€ (¢€ ¡{¥Cy(•™‘ñ‚W¸«ôPþ†È�ì·1þ%'“ôªÖ]ÝÄñ™Ä‘$MÕŽÐWQE;€QE€(¢Š(¢Š(¢Š(¢Š(¢ŠNryâ–Š(9áŽâ#«¹MT‹F³ŒÑ™ îç5~�gqÎ1Ú€)E¤YÅ/˜"Üæãœ~zŠ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦šuÕN¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)JZCÒ€(hjFœ¤ÿ1ýkB³t�-9ÎÆ}~cZTQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV~¶?â\äœËüëB¨kC:lŸUþb„ôŸù[¸*åRÒtË|wúÕÚ(¢ŠÇÐN^ó?óÓ©­zÇÐKy÷ ôߟÔÖÍ02uŸõöõÜVµekC2ØûN+V€ (¢�Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@#ªN Ç¥-QEQEQEQE›¯È8ŽÅÔ}9«Vñãoÿ\×ùUmp¦¾q÷”�®jÆœÛôûvÆ3þTÀ±œRÖV»¼1ÌŒAŒòê K¡ÌÓiÉ¿;�”ç¾:~”€Ð¢Šk°Dg=hÔV.�«Í¨]HŽŠ#Û½Hê¼ô5µ@Ssó@ ,Ñ•Õ铊$Ñ�pÈãQT5»o>ÓzŸš3ŸÂ¢ðôÌöÒFÄŸ-¸Ï¡¦mö�=¥ÉhÕ™(Ëœ�cRèÛP%ƒ}ÆÏæ+¤¤€ .ÑE€¯}3Ag4¨2ȤŠåK«†o.I˜òÇkêïäX¬gf „s\æƒ$q]³JÁC‚OÒšΑ¬Iæ¬7O¹…cÔzè…qÚŒÐËxïl6§Ó>µÖ[35¼Lü1@O×-‹âI$Ž6¹�§Ÿ§k2Á K†i"÷äŠê¨¦£¬ˆ*FAê@QEQEU»Æä,pY*½Éb3š³ArøPÉcÆPœf’„1„5% ô4wk\Áç*àà©ÈªRÄmdûÝëN¨ê9ùðÿZ ©Iß— ±½ÅÆH�=qÖ®­"p‹ô§Pe)_dQE•î id�†0½sV(¢�¶Ú°QE�Êq“'žÕ%P6îQE (¢€ (¢€ (¢€ (¢€+Ü\ˆ˜ cUoc9W,séž•5ê0u•võâ¡]÷“«!EM4’RFˆè)h¢ƒ˜(¢ŠËÐNmgûöüzV¥cøså·¸OîÌ�­Š)²«lzu!èh#ë¶Á!°à?ݱXžÏ‘8í¸*Û ©Þ6É#Ý÷Z¹Q\@³ÄQ¸î Á¥-J·J‰,02NxïWêœVn²£;‚©ÐUÊ ¨Ö‰;…QA�QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQIÎãéK@Q@5þã})Ô�ÊŸ¥S°väª�ù»YšY&yòGú¸°= iS¢Š)´QEQEQEQEQEQER ;ÐÑEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQI‘ëFåõ�-Ïc2HŠ=Î*/·Úgi‹þúfŠ«ý£gœ}¦/ûê¢}gOCƒrŸ†M_¤= Am}mwŸ³Ì®GP:�¬Pn‚骪r7ó­*ÏÐÈ:rãûíüëB€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ ¡­çû6Lz¯þ„*ýQÖqý›.}WùŠ]Ù�cÐÿ3WjŽŒs¥ÁìýM^ Š(  m"æðg#yÿÐ�lVF‰ÍÅéí¿ó5¯M�—­}û.?席ZÉ×?åÏþ»­kPER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦,Šîè½SŸz} t ¢Š(¢Š(¢Š(;^ÿ�cçûËüê}0cM¶ôÍ•A®€t×»/ó©ôÏù[×1ü©€ëäße2Ÿî“YZUÉ·Ó.æw–Å‚úð+nEÞŒ§ø�ș巷šÔŽ°Ù”Ðiš ÔeXöyaO^¹ÏøU{-Vyµ´¹‰e€Ç^;°째°“ÍE`s‘ÁfÁå¼Öc”.>r펀b€:[{X-·"H÷�£©Ö5,ìGRkW¾¸Óõ"’cÀ;{ïRxŠVk;vLùnrG¯P«=PÞjÁY†1Ÿ3= Ð, €HÉíšÉðÓ#ÙI�ó‰oÈb±.¦‘µ6’RC$¸üÿ ìXR§¡¬OÞN˜è?©«f®/®d„ǰ�¹yÎETИ.£qr¤þMÏó  íV %ÜI;GALºÖ­­¦òÈg;C|¾õ…¬¬’jr†ü¼u>�¤Kw'™q¹#¸å¨n×Tµ¹ádßÝ~ \0Ê�G¨®æÚX§d’6IûèëSÃ·Ž—BÛ?º“8_Bx  �fÑ®ìQ¶²üãÐãµrúm»ÝÝ‘€È'&»W]ÈËê1\~˜íkªÄÄ›c׊۳У…ÃÎâ\…Û�V×Pƒí�jNÇ\ž‡éW+™Ölî[VF�¼Â¥O`Gÿª€4|Eÿ ¶õ¸üëÒÐÜÛO$|¼@6ßQ[¾$ÓTwóŠ«áÅH£¹–Bx\“Ç?Ö€Ã÷„JÖîÄ«r ö5ÐW#k“ª@cã2Œ}?ýU×PÀ(¢Š@QEWœfTÇZ±PH3:ÔôÊ–ÈŽv+ °êQhÞ8Äñ1<н:–�ÀêTâ«Ú6ûWVÆAÍ#H;FåˆdÄ®;ŠyŒ VÓÿãÜŽÁŽ*Õs\²iQA!EPEPEPEPEPEPEPEPEPEPEPE `sƒœRÐG‡±äÜ�I\óô­zÆðé>UÐì%â¶h¤= -!é@¾á.é•?ζëÃÀ,·j@Ûýkn€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¤= U€¨]cÛZ·T¬›}̯ýè£?¡«˜".#y1ü(2i�-œ59ÊØ]øÖ”jOŽln�ôØ(°Vwöœ˜8°ºÏ¦ÑGö”¸ÈÓî!E€Ñ¢³N©(é§ÜþB›ý©pO˧NJ,¥•ý©vĪé“gÜàPú…úœf9ÿ�ƒE€Õ¢²†§{œ2^½�oÔOM4þ/E€Õ¢²�ö¢NŸ�«Ó#Ô5Á0ÚFÀæw¢ÀlQY¾v­´ië¥1®5|ñiý÷E€Ô£—çj祴{µn±Ÿõÿ÷ÕjQY�õƒ�Ñ[mÆŒë=vÛ}2hRŠËƲ@ù­Tú`Ó¼½\õÖÇþEiQY¦XÿË͸öi<�Xõ»€}#  :+4Áªö»‡þýÒ}›TÿŸè¿ïÕiÑY‚ÏR#æÔF}£-DôÔ±ÿl…iÑY‚Âøœ¾¦ÿðÀ éׄçûN_ûäP�'zÎ:mÑþ&sîÿtb“û:ì�[S—#ÑEiÑY£K—9:�×àEIcÖþìÿÀÇøP•˜tƒÿ?÷_÷Ý/ö:÷¼º?öÒ€4¨¬Ñ£Dh¹ç¯ï)±m±ó<íîe4¡‘ëFk?û˺9úÈßãN:=™Û&=<Æÿ@^Ü=GçFåõ�P-ˆÿ–l~®ßã@Ñlü±ÿÇÏøÐâè:²þt†XÇYþúSû"ý²Ÿ©4.‘`§‹Týi�kÏ‹þz§ýô)>Ñÿ–ÑÿßB«O?ò쟭/öE‡üúÇùRÀº€ôš?ûèP. 9ÄÑñÏÞÓl‡KX¿ï‘Hº]Š}ÛX¿ïš`?íÖ˜ÏÚbÇûâ“ûFÏþ~¡ÿ¾Å!Ó¬ÏüºÃÿ| p±µÞ/ûàR‡S²j‹?ï T±^·QßU(´¶€ÿpR‹hHcðL?µlOK¨ÏãMþذòô•d[@:Cýò)ÞTc¤iÿ|Š©ý±aÇúJsõ¦sOÄùÇ¢“W¼¨óŸ-3ë´RìQü#ò¤­Øž’·ýð”kVg¡—þý7øUüAK@ÃZµ$€&?Hš…Öm˜#Ÿ�údkFŠÎ]f8XnIöˆÒlÅÚÚìœãýI­*(;ûXc"ÊìÿÛ*Tv‹ ¾=PëZ4Pwöœ‡¥…×ýò(þѹãþ%·ûŠÑ¢˜õ×?ñ.—�öÖ›öëÌgû2\{ȹ­)œoï01¦JsþÚÿ�!½Ô3ƘØ÷•kJŠ`f‹ÍHŸùÿäaN7z†@xú™F+BŠÎ7§k(¿i¾~¬Gp¬µ§E3ÌÕÉÇÙ퇾òiwêý<«_®ãZTQp2ÉÖ· L}M/üN?éÐ{üÕ§E0ÿk fKPO .Í\ÿËkQÿ5nìí�[ÑÆjZÎòµƒÿ/6Ëÿ&�³ê¤Çì ûEZÎqŠ}fý›SÇ7ñôÿž?ýzAiªºŠ¤?ýzÓ¢‹�›ö=Gþ‚_ùP,µ ¤iuïå ŠÒ¢•ÀÌ}÷}RLûF)FŸv?æ'1õÊ Ò¢‹�™ý™r['S¸Ç Rÿd¿ý.óþø­*(¸¿Ù-œý¾ï›éFW#uåÙÿ¶�kNŠ.ch�‘�stýu4Ñ [g&[“ÿmMjÑ@g@´?Ç?ýý4Â?cÇäwó jQ@GÃöYÈ3ø/öŽË!ÿ�šÔ¢€3…b3…~Û5ðå‰ÿžß÷ðÖ½BÏH´²ŸÎ…[~6嘜 ¿E�¢Ç“ `‰_#ӚѬíþ=çÏü÷~}y­(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š*޲ Ó&Çû?ÌUꥬgû.ãvÿZn‹ÿ ¸úš¿T4_ùD= ÔÕú(¢ŠÇÐóæÞzy§™­zÈÑ3ö‹Î¸FZôØZÿú«cßά+'_µ�‡ð̦µ…QE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€8 sϵ-PEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPv»�ìÇÏf_æ*m/þA¶üçä£ÖÆtÉ~«üÅ?H;´Ësê”À¹Uä²·–_2H•ŸÔ÷«›©jéeò*‰$î3ÀúÒA‘6²‚¾„qQAiolXÁ F[©QÖ¡Ó/Æ¡nÒØÊÛXUÚ§¨iÑj ‹)+´õÇ¥:öÆ;Ë_!‰@1´ŽØ«TP-3N]:'Urìç,HÅ:}2Òâ_6XA\ã5h� ’pRiÄ‹¹H#ÔÐ!·†DQªg®Z£k¥µ¾¯=æñåº�¨ œgùV�˜’-3v‰íÍféÚ³]Þ4O“p ÿŸZи�.ax¥W5OOÑ °�ȬÒIÐ3v£ENM2ÖK´º)‰U·dt'¶jåQEKSÓÆ¡ ¦òŒ�¹O^ج_ì;ÐJâ2 ðwu÷®žŠÊÓtqi/Ÿ3‡� (…­Z( Š( Š(  ¯½XªùÍÞ=X ¹t†T�jÊY_cBƒ’y­VR3ŒÖ|ù7ÇyÉ#ƒA¥&’e¸À·…S¾?:�î]XaAÅK4^f8`*‚E4e¶‚Å�z KVXšé˜„ƒïc&¥´¸óãÉaÁªrÄöì³ýimÖ|—…@V=è)Â.:TS#÷„íO æb3RIÀ0¹`ÊX"Ÿ¦io3övÆ}ñMŠxRù±�ÒƒH¯vërIæž§¥4™@ܸ#JòAs†„åõ8§E|ëO%‰QsEIò¦–¥�zžFö0þ°²+FÍgÚÚ;–y×h=¤[I£Ê¤Ÿ! RŒ/dËQM¹ØÙÅ+JŠpÎ÷5XØã$!»šQb„1‹7­òùkpÆr1@ ÷ªbÅÁÇ�òý)>Àùâc�¥Ëæ/QU’Ц?|ù«4Ò[29fXø=MV–í£çå>Õ,öþk ‚)Ÿ`VÌbIô Ò<‰j;퉰2HɵH·”߸I¬p�”gŒsQ g?']´ ÷l±©'Ü`iõÛ*Mæ!ÀÇ"§ ‰[ QEPSö{¶áZ–òä•+í’EZ–”Ý©Þ4RÎF 4)ÇI=Ì�0Tº �‡¯µÛ³·’¹DêqÖ²ô»a%ÝÚ+•TlSÉ­¦…’°z÷ " k•�OfE#϶,ôÅTŠ Äá¶ç$ö«—«?Í’®Q@J0Œ¼Œ]Ýåâ�#?NkX_ÆPǵføs!îèBŸçZËkKæ(çÓµ§ jŠw3HÅ éWmn|á†á¿�NÑ£ 2‚)±ÁD”4)ÂQµ‰) ÀÍ-ŒIçiõQ-gWò‚N*ÝI%³ (¢‚BŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( �ô4´‡¡  :z••�Æ<ˆ¿‘«õŸ§36{AþÍZØ!85�¨ëRYݼ+ °P9n3Ww®©¦¦2*h¿ÛŸjû9vß� í8'ëW낺ŽKyÞ)·ÌW]£]›Í:9åÆQ�©Ë­b k¯!”’ { Ö†AƒÁèkžñ°[´�F<ÅÃ}GÿZµ4‰¼Ý=9dùMdÙ_ÜÚêMÄ�";ì`Ç89ê+¥®[S º“ÈŽ3½O_¥u‚2(`-Í9E‘K E%ÅÄvÑ%`ª)¡Ÿe*d‚W#Ïi×ß`›,”çþ5nOG‚#·b{naƒXÒN®ìÀ`‹LÝX2†S�FAµ—¡NÒiøoùfħZlZÀ[—†éD`g =¨°ÔUK}FÖåöE(-ŒàðqY‘x‡÷³ £>^Þ§žô¬õË>½zÒ“–û»sZzf¶—rfQÄqÏ ô  R@< ®×öŠûZâ Þ›…QñŒ-A*¥þlw¬adÒiÂêßs0�«*ŽƒÖ�€ëÁ S�zK\¶‹©5¬¦)ÝŒqžvŸjÕmzÐ8D;–(_ZVRŠ( Š( Š){PÑEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEc=i1KE&)h¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€3tOø÷¸¨¸|þu¥Yš((·j{\5iÐÀ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢‘˜(˽-V¸¼HS�ºPOzÍòÀ:÷ïLŠÊI[|§õ4�ãM-fL÷AÎÑ’G'mX‚a2ä JqÁÚ QXƒ±›ÔÕù\[Eª(¢‘�QEQEQEQEQEQEU-\¦\gû¿Ö®Õ=WþA·îPZ:b¼ßú­Îа4ÄÇ÷›ÿB5£@Q@:&—ÿžkZ±´rEýòv.[ÿ5±M�›¯¶*OQ*‘ïÍiEeø„gL>Î+N?õkôê(¢�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@uŸùܺ?�.ŽAÒí±Ó`£W8Òî?Ýþ´š/ü‚m¿Ü  §88ë\h*/XßÃyóyÍvuFûK·½°Ù'÷×úúÓM:ÞÚÞ߇1±Ý�ÙÍO,±Ã’W‹Ô“Xgq¦h.”2FpOáYך…Åô{%pUNv�Žh«µ½·¼ äI»oQŒT²Ë™%`¨½I®WAºŽÎêGœ�0> Õ­SP‹RÓ[É H¥”ŽÜÑ`4$¹‡W±¹†ÒLÉ·#ö¤Ðme´´xçጄ„Îv�óÍRð¼k›™yÞ6¡þÖ˜n�޳!f;^_›èh¤¢ ¹›É·y@Ý´gŠã®¯îg”³ÌãœáX€(°«ýÒ=Erú[õˆÉ#’WóZßV¹…J,…ƒqósŠŠ(ååŒ1FX‡µw4W=o¬j7[{xæa×·ë[Ñ3´HÒ¨G PsƒHÑEQEQEQEQEQER' vÜr3Vꥮ ò�*ÝÔÜŽw) °êgK1YYΠǵnR=k-™Ò32¾E´|‹ðÀæÞÍÇsSR/ÝJZ mê!õ¥¢ŠQEÙâÿžkùT´P4ÚØ@Œ£–ŠQEQEQEQEQETN&g_îÔô ¦�˜QE(¢Š(ª·WM ¬q¦÷<Óêhÿ×G�ëA¢§&®RѾMOPB>mÙýMmV‹&ý^ð–Ë6Oặè3 ;QEbhññt:cBkn±4þ•vIé�ø­ºlŠ(¤EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPHzZCÒ€)Xó˜ŒçÈ‹ÿf«ÕBÀ8ž¹·‹Ÿûê¯Ó`dëº{]B²Â»¥�·¨¬[+éì±µÎJ‘Þ» ¯-•´ÍºH�©ÅÜHÓJò9Ë1É5ÐxZU6’ÃüHû¾ ÿúª-wMHc[‹t ‹òº�úÖM…ÛX\‰Ðn\Ëê(Òë°ù–;ºØé\ÄsÊŒR7pôòk¯¹O¶éÎ#ÿ–±åÅsºNœòê+çÃ"¢|Ç ŽGJQ¹†X¤Û:²·\¾o.#ÑÕ„†b™î¯ãZ:æ�5ĉ4 ¼ãk/ò4ø´}ÚR[LÛdÎòG84Ì–(C+{�y«7�sg;ÑçŸQZká© ÃÜ®ßd9©í<>�Îí3‰c*@\P2€€Oz\g­v_Ù6_ghD +wîÖ¨/†ÓqÝrÅ}ŒÐ~™‹Oå=�OéMñ \ñÊ áÁÉ÷©¦i‹§vHÎ$#6±]EåÌ»—9ëŠã!2ÆÞt{†Ü�À~u%½Œ÷QI,1–XÇçôõ®ÂÚÚ+XDP¦Ô8©@¥…�ž&m§�¤T«et"óÖ pÁç>¢»·…ÛsD„ç9Ú*ZÆkk«ý!(ÅÀ9ÃpO_éRèV³ÚÛÊ— 3åW9íÍjQH «� e2Fï'$«¶öpÛ¢ª"’?ˆŽMX¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€2´Ln½ “ûö­ZÍÑ@ wŒÇËÿJÒ¦À(¢Š@QEQEQEQEQE#0U,z“Yr´×ŒDsÞB5$㹦ÛÄTc–5=“²å[QAEPEPEPEPEPEPU5OùÜÿ¸jÝVÔ6œf3Ïá@´4ÕûíüëJ³tù®NNöÏçZTQE�¤dßÝœ÷?ú­šÄÑIû}Þ}Oþ„khÓ3ÄièFñšÑˆî‰ªƒYÞ ]Úczï_çW­=¬L¼‚ƒ•MER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(޲@ÒçÉÇ~¢�þAvüç �Ö“Z8Ó%ú¯þ„)4Bš˜þóèF˜QE 9Í^Âúêý™ VŒƒǽ>Ó@pÈÓ•™AÎkaï­c“ËyãWé‚jpÀŒ‚õ¦4Ú™7E&ÿ v« £ÃŒÐ'ß”d¹õ+JŠ@ghú{ØE*ÈÁ™ßæ!z IÉ9^»N*V‹ƒ“Aj>ëeª(¢‚ Âv[¯)¹¡«5�3yz€,xÈ5zÿx~tÎ6³Cª6™¾~”þzƒQ­´)Ñ+unû£4$Î_ ×5^ÑŠÝIéÍ_ ¹¥kQA�R3c�KY×ìÞz§8#Š „y�‹bæ"q»§µ/Ú"Üñ“T’4BxvaP¬ó1Æ  ÙR‹êlQY‘Ü<¨!Ý·ïf¬YL[÷nÛ˜t4Ê“Š¸�(Ší”wÍ[È'æ©Ý£G ™>¸ZifI<ÄdP_'´³¹­EfE,ɲI � ÖŸZ §P¢Š( a‰L‚B>aÐÔW„YV©dq98ì*´Q´Ì^@pG Ò7øŸC#ÃØþиÏ]‡Mßþªèë–ðü‡ûT©êQÁüÅu4ÝÝŠ( F&‡Ÿ¶ÞgüüƶëC?é÷€ƒœŸýÖå6ER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(7L-ö‰A<bÀôûÕ¥Yúz2ÌŇޅ0~›«B›¢Š)ÉcI£häPÈÃõ’ž¶—gv�9öüëfŠEPªFv¥¢Š(¢Š(¢Š(¢Š)(=(ŠZ(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€34~·£þžŠÓ¬Ý$6ø‘‚gàñŸå@ô!�<¾ßδk3AçNëŸ�¿�iÐEP&Š?Óï8áIøñ­ªÅÑGú}æ>îOç¸ÖÕ6v¹Æž}Ý�XÓxÓàŒ ªúæ?³›ýõÇçSé\é¶äÿpPº(¢�Q@Q@Q@ LóŒPÑEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEŸ¯i3Ÿ÷ô!Lðù'L\ÿ}¿�K¬ãû.|úæ)šüƒýöÿÐ�04k/]¾’ÒÔ$'IÀoîŽæµ+–×îÖ{ÓSˆ~R}Iæ’ìé„s«3Ë&F“ƒÞ¯CéЮ«ƒ»äçoþµ Ö'X’8€Pª@äÖ¶�5Âé�-Áfq¹—w\v¦¡%ÂiëöœåŽä rBž™­*¥¥ß ëvre8`>™¬][P¸šêKTb¨¯´Æh¦0Ê�Gµ-QÒl^ÂØÇ$»ËØì¿J¬5£Ödµ›#‚œsŒR^Š…® FUiPá~n´È¯íf˜ÅÈÒ6æ€,ÑXÞ!GSBì ­�zÊ‹X»@ªeΟOJv®úÑX:¦£i{§IÊË/ÊÁy9£M¼œéwI$# G'Ÿð¢Àn3ªýæêiApA®åîwfäɼóóõ«þ»xï–ØŽ@r ïÚ€:ºit ° z òk]¾žÕÑ"m©"qÎsÿת:E›ÞÞ­Ñ“CŒƒÉý1üª®¹ Á¨´€æ�È}ÀÔ¢$`„P œœ R•¨ëL�w–»¾ö~µƒ¯©†ò+…ûÅ@�ÿë×AQÏoÂlž5‘}f�d·“1†=ì>cŒ VŽ�£Ýý¶)¦_)c`Ù$dûWE1@»a�Q}b¤§p ½·ûU«ÄŽ õ¬ G¹“íhR5éƒ÷�µt´Roå³ ü§§X¥„5;™ŽY±Ö­Ñ@º®’5޲yn¼gV=ׇîa9ƒ¨ô85ÕQ@:\·:L1;ææ%1=OqSè¶RYZ2Í�1Ûqçý+BН{j·–íqžAô5“�&ãæLÿ²+zЧi¦[ZH$�I“ÜNjåPER{Ye‘˜M´ƒž(*)7«±kpõä4. Œ‘ÅG®ÁËî&�Ù)pÅ�áAIE=É-­º†55PCww (¢�Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@:&©vû_úoVŒ j—„õÿ�ܦÀ(¢Š@bhãþ&—¾Å±øµmÖ&�1ªÞ÷¿ô#[tØQHŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  6¹û{çœÀœúüÍWª•³æñ‡ý1Sÿ�5]¦À(¢Š@QEQYÚ†­”Š˜q’é@4T6³ý¦Ú9¶•Þ3ƒÚ¦ Š( Š( Š( Š( Š( Š( Š*½Ýì`›ôdš±EP}^Ô[™VLžËܚˊîþþñ<–p��m¼3NÀttQE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ F`ªYˆu&–³ï—íw1ÙîÂm/ qÛõ  ±È’®èÝ\zƒšq`½HZæâi4«Ò…�–>â™,³jÚ€H‹*äÏݽ;ÔQE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢‘ˆU$ô4´‡¥U±Ô"½ †^ÇÓÖ¤»¹[[v•¹ÇAêhCíNñ¼F)øIëWkžÒ|Û½HÏÈTÉcؓںlŠ(¤EPEPEPEPEPEŸ¨j±ÙH#(Ìä튾ą$ œp+5¹¡¹x/!÷;V�ö„&É®Tä(äwÏ¥béÖ¦þøÍ&J«ncïØS¥¢Š)QEQEQEQEQEÉIXœŽS\•�õÍ£¬¥™û0c�ÕÖ̆H]Áe"¸ùRxÔÙ°bU³´ œô¦€Ó¾ÖüØÂZåA±àý)ú>–Y–òåyꊙ¬›–×jnã,ªyR:{×a‰"�ƒ)î >Š(¤EPEPEP~›‘w¨ëçgðÇ¡YÖ »QÔs÷·¨ü6ñýkF€ (¢€ (¢€ (¢€ (¨å•bRIçÒ�¥}‡<‹åŽ*V�·6BúS#F�üÉ>ïaV€`t ·héÔÇJZ( Ì(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢“œûPÑEQETW_ñë7û‡ùTµ×³öò  ÿ6ëö~!Zµ“áàÒP0G™œþµ¨¢Š(DãP¼ƒ“ÿ¡Û¬M�Õ/=yÿЫn›†µ�ìæÈÏÌ¿Î�£�tèðs‚Ãõ4šÖ³ŸÞ_çFŒOötyþó3G@/ÑE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š¥¬t»€z¨´?³WvÏçSê¿ò ¹Æ>áëUü>s¦�÷ÛùÓNŠ(¤EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE”´QEQEQEQE%-PEPEPEPˆ?âgxzuãþkz°ô’§VºÆrw�l­ÊlŠ(¤&›Æµr=wŸüx�mÖšs®Üç¯Ïÿ¡ ݦÀ(¢Š@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEP³?ée}!ÿj¿YÖ`‹æ¯•ÿ³µhÓ`QE ˆÜ³y&EuÛR×+­©‹R�©?0¯µ4¾¡«Çk˜âd¸üÖ²ôËpfŸæ@Û˜ÿxúVt9–E‹!wn=vV–ékn±GÐwõ>´( ¥¢Š@QEQEQEQEQEQEÍêÒÇ6¢ê爓j�SÖºJÊŸEIîÌÍ!Ç,¸äþ4ÐØVßí]†ŸQZF !Ï©ªšŽ˜²Z¨¶@­@;ŠÊ³Ô¦´�áŒ,~PÝ�u4Tbà[¯ÚÙZSÉÚ0µOHŠ( Š( Š( Š( Š( Š( ¥giL.êïI)T$U÷]ñ²ƒŒ‚3\Ú›ëH¾Â7�¿tªýáŸZhkóG%¬|•b*4Kæ¡ NpyêWÿ×RYhÁ¡f¼{ Ý÷úÔ6ºÄWÑK$©²6È+œšß¢Š)QEQEQEQEQEU^s„›OÎÿ"þ5z©êVföª@u9\ô¡Ï?I¼VÆ鞌)·Wò_̾a+~êö­¡O9Ýs>â5n=É:‰êçúSº~£f²%•º:ç¡#©Ç9­j­m§ÚÚ±h!Ucü]OçViQEQEQEQEQEQEVˆ‘~ÑjXà0*O§Jߪµ�¾· „ åIéô OÌeb ’3ù×E¦_ÙÃåZÆXË'$íàŸ­Aÿô†ß™MéÔ~usJÒ~ÄÍ,¥^cÀ#¢Š`jQE€(¢Š(¢Š(¢Š(¢Š(¢Š)03œ úÒÑ@ú––·£z’�×­QÑ,¯mo¤)H¶óÎCØýkzŠ(¢Š(¢Š(¢Š(¢ŠÎÓ³öýDã�1GéZ5BÀ–¾¿' ‘@üªýQEQER�ÍV’vs¶žÙ ¨Å²Ig ÂòÞ”Èa-óMÉ<⟠!9n[Ö¦ nIh‚Š( €¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¨îmåìåRTsÿ¨“ýÓü¨3Ä›9IÿžŸû(­zÇðÙÿB�zIÿ²ŠØ Š(   í‹ÃÛãÕ»XºIT»Çž?àUµM�GYÿ�l¸9\~b“Dÿ�rÿ¼ßÌÓµ…ݦMì~F£ÐH:jàÿ:Ò¢Š)QEQEQEQEQEQEQER ãžM-QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEOVÒî뙪ÞiÍ“�eb=ªÞ§ÿ ÛŸúäßÊ«xþA£ÝÛùÓNŠ(¤E€òG¥-Q@Q@Q@Q@RZ(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¤Ç9 ¤¥¢€–’–€ (¤ ¤¥¢€ (¢€ (¤Å-Q@Q@Q@&yÅ-QEQEQEƒ¤íÍÇ¿™Œ¾+z¹í0mÖåþ)?ô*èi° (¢�ÖK·]¹Î9ÜxëÚ¶kÏŸOì?˜­º`QE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€3­~¢ç¸‡“µhÖ]�ü„dôÌÿèfµ)° (¢�sœ\j¯Ìì0;Šéé03œ úÐ5s¡M{ã"OP:Ô–Ķè!¸C ^Î®Š¡’Ö ÖD�õÀ¢úí¨_•evþèZЂ_:�£G»øXr)±ZÁú¸Q~‚¦¤EPEPEPEPEPEPEPQ h¾`…<Ïïm©h Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  ë´uÏGC�¨­¡dÔurÛ�“í·§ó«ôQESEŒ|Æ£yòJÆ2ؤ†�òòOj Q¶¬`2\Hs•AV#�cQOéEr¾�EPHQEQEQEQEQEQEQEQEQEQEQEQES&ÿRùþé§Ó%ÿTÿîšËðãn´”€$Çè+^±¼6sk/ûãÿA³@Q@:9Ʊv;�ßúnÖ—ÿ!›’>Oü ·)°*j§läö_ëQhJæö?­M©ãû>|óòÔ:Æœ õÞß΀4h¢Š@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEVÔ€:uÈ= müª¶‚XéÃw÷ÛùÕ�DgO¸ôÌÿ*©áó�8�I~´ÀÔ¢Š)TLJÜ'£)ðÿ&¢¼Ô-ì‡ïŸæÆBŽI§[Ì—¶ÐÜFVù†î´bŠ«ý¡oöÃj_l£ #ƒÆx«TQEQEQEQEQEQEQEQEQEQEQEQEQERRÑ@Q@Q@Q@Q@ʳÛȱ’©ÚAïTt[Ö¸�¡•‹K<õÅiÑEQEQEQEQEQEQEƒcòø†aýâäþb·«Ÿ´'þ91œn|þ_ã]6ERÔÿÅC0é÷¿¥nV·>#›ž�¿�­Ê`QE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€3­3ý Ç#ýQôõhÖu®¡Ÿâ1¾ÿëÖ�6ER¢Š(¢Š(¢Š(¢Š(¢Š(¢“ÒÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPu�ÿ‰®¡ÏtþU£Yvl#ÕõÇì?¥\3™ H�Ï­1¨¶K$ª�O>•ïgÏð->89ÜüµOH«¨ì1#Tœc4ú( ‹Ü(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢�œ Z(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ d£18õSO¦¿(ÃØÐG‡?ãÞ_÷‡ò­šÇðòí‚UㆵlPEPЧûR샕³õ-ÿÖ5»Xš3ÔoX“ù1ÿÛ¦À©ªgû:|uÛPèD�0ýU§@T7S‹ki&#;œzÐÔV5†º.gHfˆFÏÀ!²3[”0RFãÐg­-Q@Q@Q@S]Õ³°UÉÅ(¥¬Ø5Ë9î…º– Nò“õ­*(¢Š+ÕRÛZ”½!!qéŒÖÍ`jWÚkQÊíÀœsê) 7設îa¹�|_j–�ÓP�¯žÐ©VS€O~3W+R�ÈÔâ»þ—ü?‘­ª`QE d¯åÄï‚v‚p;ÓéÈÁé@ô½Au+v•c)†Æz»Qà vñˆá@ˆ:*J(¢šOFñ QUÞúÕ%XžxÄ�Ðf¬P?n˜ñ#ßÄç…tΡ?ð’�ÿMOþ€k¢¦À(¢Š@aÂø�ðz’1ÿ¹XQ`x�†ˆþ{kv›¢Š)QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE•hÄê¤z$Ÿú­Z̶j|v_ý V�6ER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠŠIÒ0yÉô &ö$$“PIt£+Ì£Ä×Ýò¥XŠˆ|£ŸZ ²ŽæE¸óu™ÖC† ? ÙDT(Åf[©ÿ„‚éˆê×òÿ Õ —&Š( �¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¤= -!èhĘfà˜cJÙ¬o.Ï´/ºÿ#[4QEÎirn×$Àê$çñÑ×-¡¶ý_%pv¹Çã]E6]P�¦Ü“ÿ<ÍVÐ1öÀçÌ9ý*Ö¦»´ë‘ÿLÛùU?meÀé'ô­ER¢ŠLsšZ(¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€!¼ÿ�9øÏîÛ�³ü7Δs—lþu¡xJÙÎGQÒ³ü4áô•#ûíŸÎ€5ª¦¥lnmT|ëÊÕº(DÔR(͵˄ ~BÇ…]¾Ö-í!Þ„LÙû¨{zÓoô‹{¹7ò¤=HÇ?…2 ÙL®e ÎÒ0)�.¨|í7ÌŸOòkï%šÑ-8 IÇñz ꥉ&…¢`60Æ*•ž“mk9˜3Hÿû-aé·�¥Ý:̬£§¡õ«×׃UÒn5xü† Ccæ§ycgvCNáüA°h¶·±†¶‡ËÚßywdŸ­q[MIºIÏÎK\sÎWRº5‚ÈI%�þüTöze¥£IåÛø;Žp=(Ÿ‹U¼´µH¢`ÁË‘œ�JÛÕíf¿ÓTD0ù´ñž:~µf X|PªŸ^µczsó:ó@¦ƒ�TBÜ0ý+^ÿS–Ò÷˘ð½bÝÊÑj“}�³ó�¥O­_·Ñ$˜´·“f(ä�©  ˆ¯í¥@ÂdÄàŠ™&ŽO¹"·~kx|mÀ¹?]µkNÒc±™¦óG+·�9  *ç|Ee3Ü$ñ#:2…m£85ÑRf�t–·:l°Êà«TŽÇÒ¶5Wú•*U�¶5nëÈÔldò�_g ŽÌ+?B“/,Èë�§õ¦‡Õ†«ÑŸ•·{ Ž*-B)mof�‰Ã1`¼ Íu¶ö–öÅŒ$eºàu¢æÒ ¥ ×SºmN9&�¶où†~]¿JÒ¶ðú¬¡îd;T`­Kw¡E3™ sØÈ  š®¡ÓF°“˜É9#ƒW½n¬ªÛ¦æ©­¡F- #ƒ>sæ0ý*„þ¸Ž é ‘óÊ�Ú€5µMI¬"ŽDˆH®q»8Ò²àñ,ÙÄÐ!ÉþŒ º–·†¨ ׃Óò¬XôkÉŸhˆ¡Ï%ø€5´�50í+}šERªz`Ž¿�E¡tÚÊF'/ HWÆJž÷Hsam$<°.Âznš6˜ñIç\¡V\…õÍK´³YÝÊ‘þòÝw`÷àþ•Œ5»ï<;KÇuÀÅm[èil·a%,']ªû£Ÿñ¬Û} æY‡žhæ9ëô  EûIнŸtd »�<ç?Ò°ö´JÂ"Û3šè‡SÌ;.PöÀÈ«ñi–ÑÚµ¹]êã [©  }KŠò%žW8VÆÕã‘]-Aiiœ>T„É<œóSÒ5ð“1ÏBOþ9[ÕÏ&‰ ÿ¦¤ã•ÐÓ`QE 0ÁωGBô ܬ.ž%ï�ߦÊݦÀ(¢Š@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEeÛ�5@þsÿ} Ô¬ØÔ.©IYIÿ¾…iS`QE (¢€ (¢€ (¢€ B3Ž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@Q@Q@Q@Q@S$•cûÆ�¥qõ“$|Ï¥Bï4¹ŒZ|VÊ ùš‚¹Røˆ‹ÍpHAµjh­Ö1ÏÌ}êj(>ˆ(¢Š3mþ]rð`|Ñ£gô­*Ì„‘âÆx0/ó­:(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š) ÒÑ@¾'uÐ=˜sùÖÕbx&k²>îGó5·M€QE% 9­cX`y;_˜®–¹�ÿÄÕÀäl|ÄWOM�WSÿ�uÎ?ç™þUKÃÀˆ&ô.1ùUÍT¦Ü€qò¡á¼ùW ÿ|cò  ª(¢�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@ïÈ%º›?‘¬ÿ  ]/‚\“ù Ѿ*,n Œ¨�³ôÅføeóc"�€¯Çä(fŠ(  Ë­+›Æ¹3HŒË‚* ñ{/â+jŠÆþÂoùü“ò¤:˜À¼l{¯ÿ^¶¨¢àsÏá§q†º ÎyOþ½5|0âL›¥ ìœÿ:èè  SáäÇü|¾}vŠOøGÈ$­ÉÉêvÿõënŠ.*èN™Ûxøô ãùÕk�xà’Q:³’‘ŸZèè§p8!ò6ElZiÞÀ“‹°³ÆÒqÏÖ´.ô+yÉ1±„““´dUûKd´¶Hc裯©îh!4+„-ï›Hþ´£Dº"ðÀÿ�nQEÀÃ5Ø\ ±í÷¿Æ¢}ùU�.A|p775ÐÑEÀáI"V‹;yägÕ½?K¹»‘™_Ë >ñ®­í vÜðÆÌ{•ÔŠªŠ@v\ ?ì+Œgíƒw®øÑý‹v:^:}ïñ­Ú(¸GE½ ƒyϨ,?­ÚÇ÷‰¥þÏÕT·Ã§©æ¶è¢àa¥†©Èk®½Ãž)Eެ>Ø>»�øVÝ\ _±jøÿ�µüÿúÔ}�X^—`údÿõ«jŠ.'ØõŽ3vÐãúRMdŒ}¡Güÿ­[”Qp1ÓXïr?ï¿þµ×Yã+ø·ÿZ¶è¢àbý—X9áyï»§éJ¶ÚºE°ÇBßýjÙ¢‹�ˆmµœqp½½ÿÖ£ìºÐÿ—”?�ÿZ¶è¢àcu¡ÖxÏâ?ƒµ‚¢XϹ#?ʶh¢àb,Ø÷èOl°ÿ <�lÿËdÜ�ð­º(¸‚ k'3§·#Ê�A®wš?À�ð­Ê(¸bo€e_®GøS–-ctœ�ÑJóúVÕ\ #o­Äøþðÿ VƒY+þ·v ?·(¢àsÞFµóeßÛçÓ¸¨Û^Cÿ_ë]\ öØ¢ûXÄû~z±E€çüŒd�Òoý–º:æ§`¾"ÈÏúõüt´ØQH •ñ 9êø÷ÅoVƒþ*t²þ8kv˜QHŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( �ž8¥¤  عÕ�“ÈY8üEiÖdd Y@Uÿ˜­:lŠ(¤EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPER¹Õm-dò哿îgšåš †gú Ò¢°_ÄÑò[ÈÇÝ€¦Åâ`Ì|Ë|Û[š,AEb7ˆâ#ä…�ÔŠ�¼Jàü°!ÿ�v¢¢¸¸u‹˜n^esó¶Y Êõ®‹LÖ!¿ÊcË” =~”¥ER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠŽI’1ÉçÐP4›Ø’˜ò¢˜þ_Ζf+á}jD¶Q‚üš åKâe–Sˆ×hîMH¶ëÁs¸Ô 08´—`(¢Š (¢€ (¢€3�â­¸þu§YHâ¤pçÜcó­Z(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š))h  /ÿ®¼ç?0þf·k@n.—ß?©­Êl�Œ‚)h¤3¡©]L02ŸnŸá]5sú_É­J™Îwÿ:è)°*êd.›rÍÐFÇô¬ï °dº#þzåZ:”RO§ÜEÝÖ¥–§o˜’Hòs€G4ÔÑ\ß—­°3+ÓrœÔ ëN u>¥”Pý†�ë>yyÿxR5¾´TâcôÞ?€7h¬²ë-ÖR3ÿM¥8Ùê„ç±>¦LPå„4ýPøù9ö�Ò-†®ü}uë™ þ”½Eb�?R9ÍÎ=÷šFÓu&97kø±  º+ iÙæóð&§d]œyø‚ÙþtµEaÇ£ÞÜ׬ôf?Ö—ûäð×§ê3Ÿç@tV0ÐäS‘x߈?ãJti�ü¾°úþ½käzŠBê:°�cÿ`’rn˜Ÿ÷icÐAÝ;#‚¥kù‰ýõüé<Øÿ¾¿�e6€‡¥Ã�ø¤„g3>Ýá@þb}:iž%iPv˜[2~›¿Â�ë7票ëò1®‚Šç­¨¿Ü…†zbHº¦©ÐÄß÷ä×IEs—WÚ›!C mu 툞´Í>^Ù Û@ª­Éóp3]5OOkò¬5ˆá1žµrŠ)QEQEQEG4žTeºžÂ�¥})›ÊçúTµRÁ©š_¾ÿÊ­ÐTÒNÈ(¢Š (¢€ (¢€ (¢€ (¢€ (¤ ¢Š(¢Š(¢’–€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€9«Á³_rLÑŸä+¥®nõ¿â|< cN•ÒS`QE 0§;|I�£ô5»X7Gþ*8�õL~F·©€QE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÌ@?µP÷Oæ+N²â!uaÎX‰?˜­JlŠ(¤EPEPEPEPEPEPEPEPEPEPE˜ ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(+/]ÔÊÙV#‰d8Ðw5©\v¿qçj2/hþAMž]ä<±>æ´4í&kþYÄqâ<“ô�Œ/Z·imwq½º3*uǯµ ûHìîÚܸP9>µù3‘ƒM ZC¹ŽORÝsVã°¸ž&xWÌ ×š¬˜ëVcšÝÍn’œtb@ý*¼±IÊèQ½`Ó7�¸$g#•Ø€uÀ¦Û¿“pŽÙ°Ý+Z²£ÿ�ÎO«�ÑkV›¢Š)QEQHFih¢�FAÈ¥ Š( Š( Š( Š( Š( Š( Š( Šd²¤1´’*õ¨lïa½V0“òõ`гEPEPEPEPEPEPEPEPEC=Ì6ã3H>´øäY20e= ÑEQEQE•ÁêuýÁÉ?½aÏÔ×y\—ˆáXµʸó1÷<çúS@dF3]‡5b‚KyäT!÷&xÈ?ýzš@¬Nšv7ÚT¿¼\$¸ûàuú×3¶Jù¹éÆ3KkL0Yǹ+@ø¢°¼�i¾]ì3ü[‡õ±Öãü{óý(nŠÆKm[ ¾ã ãsúSž°GÍu�øÿ Ü¢°Å¦®3›žqýÿþµ e«œî»ÛÿÏô  Ê+)l/óó_¶=1M6–x¾8þT¯Ecÿfß–Á¾|w9æœt˽  B\úе“™x_R�ûOm:è“‹ù1èhNŠËþ˹#›ùI¤]&|ü×Ò°  Z+,é/�‹ÉaѦcó^É�bGõ  z+/ûùn§-Ø–â�hÝÚæMÝðMjÒdzÖSèÌHÙtë�¯øÒ ½s'CКÖÈõ£#ÔVRè1Á¸˜Ÿ]Ô¿Ø6øÿY.Þ  MËýáùѹGñβ›CŒà‰Náß3niÉ?JÓó8Þ¿�lß_γ?°¢ÿž‡�öiF…0dlué@^l`gzþty±ÿÏEüÅf�Ø cø UЭ”œ–>�8  ,c¬Š?i¸„™£çý¡TN‰Þÿ\ Hô;u?3³N_70³Gÿ} OµÛã>txÿxU!¡Yç�ÇÓž”ã¢Ú�­ƒÎ3@¾Ùl?å¼÷Р^Û“ÆqþЪŸØ–™ÏÏùÓ×G³SŸ,“îhÐ Åõ©éqýô(7¶£¬ñÿßUéVKÒÝQ¥ÙźPÿhÚÏÄ�Q³n#üé²i–’u‹CŠiÒm9CÏûThÿ´¬óÿ Ju+AÖ`?Q®“h£Y?SGöM¦ðÅã¶ãŠ4A©Z“­4ê–c¬ß¡¤þÉ´ ¸!9ûÆ—û.×9(OüÑ 5k6àM“ì V²òØ~F¤[ UXgÚ•lm“¤+øóF€BÚ½š€L‡ý“BëL8›ô5/Ø-w‡òpéÅ8Ù[A…0NzQ ZÐ ·~SMÕ‘é#¢Ÿì¸Ç�•*Á®Ñ�ô  ƒW´=ÿïƒHu« q½‰ôØjȳ·‘ dûR›Kv0§åF€T:Õ êdÿ¾ *ëÌ¥€“ýж–ðÆ0‘ ü)átUü¨‡öÍ¿,¸?ìÐÚͺõY9ö«­O÷£CõyÏ4ÿ¾h�öÌE1$gsN:Ÿ8+ >„b¯**ýÕè)œåãF>¥A  ö×-ÔãdŸ§øÒr‚Iü+CÈ‹ò“îŠQc¢/å@Ã[�ŽÞR}£Wb¹û Ï·ËZA@èúTS¹ÈD<“ÏÒ�¥vf¶«™s%´ƒ"Ÿý¶œÿ£È1î+E"P¿0ú‘NòÓû‹ùP ™C]€û3óþÐ¥Ñq˜íœã®MjlOî¯åK€: elÈ6�ÉãæÿëR¾­**±´aŸV­LQ€z�@-¬Ê½m×u4kr’3hGü ÿ­[‚ŒJÉ]^áù[&*:œÿõ©_U¸Q‘fXc<þ­Ed.©xÄbÀàûŸð§I©]GŒÙŸ®OøV­‘ý­>qönHã¯øSF¯t_h´ýü+fŠÉþѽ*H´Ç¦A¦�Fü�  Ï~ lQ@R½,@µçýÓNš‰û(×5«Edý«Uo»jŸ�"ɪž°Áÿ}Ò¢€2¥¹ÔãÆmã$�áɦ‹�T¯ú…ýßþ½kÑEÀÊY5�Ø1BGù÷§gW9[�sšÓ¢€3vêü|öÞü]š©ÿ–¶ãð&´h  ÇM[wË,ôÛNòõ\çÛç±ØkFŠ.w“©ñ‹ˆ³îµ�Vû¢h󟽴bµh¢àd˜õ~‚TúàRuaÿ-ƒ}1ÅkÑEÀÈX5Rg õÁ¦ù¶Oï‰üF?•lÑEÀÈKmS�÷§L�ð¦m\cçþ?¶¨¢àc}ŸWqóH«ô~• ²Õ:ý¤ƒþÿÿZ¶¨¢àb¶�¨·ë�v<Ô¿Ù×lªMÙFi8­Z(¸ÿÙwœÿ¦·¶I¥:]Ùß?àMkÑEÀÉ:]ÈRã¶{’j#¤^1ÏÛö Õ·E ´K¦À7yõÎhþŸ�AúÖí\v_ÜvÉÀæ¡_Ý7´#ñ'¥uQp9áá¹vór™ÿpÿ�$ž˜bž2{Sü뢢•Àå£ðå×ñ4*}‰?Ò¦_ Êq¾å?ºŸýzèè  Ö6ien‘©ÜëÉ«4Q@Q@z‰[µÝÓ)üÍnV¢3®Zàdå3ôÉ­Ê`QE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€2#[^ßñùEkÖPñ6Oúé'þ€µ«M€QE€(¢Š†I]ÌcŽj¦µr`´Ú‡!LJzË×÷®¢ï” ã?ZªÓO¨Ma·>6Š`lø|KöiF% |€öõ­jŽÞ! ôQŠ’�Q@Q@Q@Q@Q@Q@V7ö«1‰¦@àã÷©n%ÛÉ)8¤× éþŠ“ïË»°Çõ¦ž·|%>Dg*§’SZ=ˆ´¶ ÃHoAYºÜÝ“ "ç¹®ž€ (¢�Q@Q@Q@Q@Q@Q@ –EŠ'‘øUšçF¯x— $ƒ8ÈM¸{VõäæÒXAÁu æ.’è"Ã"6#á~_ëM¡¨ÜÚ‹åbI&Á$œ‘õ£Ãi&éÜçÊÀëX°á]|ÜìÏÍë]›©Z¼©gm ààcŠÖ¢Š)QERRÒP\׊—÷Öí�áaŸÄWKX>(OÝ[·ûELÿJhiãSÏi=¼»$R3È#¡¦Ánó6Ø×svQÔÕ”º¾³;KH€q‡~´­¼’¶ÈÔ»7 Ûñ?ÙmCõ~¸¬‰o®e}ÆVÈî¼*ÑÓfmL}Ší™ˆ£“¸Å1ˆ!ñé]^™;à‰]y@ÄQ“ŠÅ™lìnJ‚nÙ}xPµr/¾í“žYàíí@~S\Ç%Ä’‚Aç'&«r ’}‹3¬g1çå>Ôù¡…(Û•”ã¾:P ³Œ5Ì]Îáù滪ä´c-ò6î5ÖÐ1ÔQE (¢€ (¢€ )¸8¨f’T+²=Àõ i]رEWI�õ|Ó÷ÉýÊv+%¢¡2IÙ( 1tQ`å&¢ ýþi|¹åé/™.@êi¦TXTBÛŸ™Éãño9 v�r7½…;“ô ¾‘ø†"O¸«b—¢/åOƒ¥ТòeùŽÏÒŸ�½}Æ®Q@�WÓB4†49Tõ©(¢‚op¢Š(QEQEQEQEQEQEQEQE“w ‹]¶$gt{3ZÕ�z›üAj lÏäI­š`QE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€0ôƒÿkÁÐ|ßúnV&�Àê·œrKdÿÀ�mA99Ø ER03œ úÒÑEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE#6Õ$ö¨aعÓg}Î#^½ê®Õ‚öBÑEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEbjM·Z´#9%Gêkn±5ùÙç ùšÚ¦ÑE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¦»¬hÎÇ I§PEPEPEPEPEPEPEPEPEPEPiñ5��þ7ÀEiVS7üN!^sæ>ï�Z´ØQHŠ( sÄQ²Ý,‡î²¸¬Û9^Öe™Ü:f»6Eq‡PÃÜf¡º²‚ê0’'N„pE;�Hk¶þFý­æcîc¿Ö®i÷‚úÔL§$}ES‡A·GÜîÎ3ÐñZhŠŠ*Ž€ uQHŠ( Š( Š( Š( Š( n¡ûE´°çÔŒ×;‹w#d®y$ÿ*ê(¦ms%…ÉxÇ̹VVè}«ª³¸ûU¬sm)¼gµY[I/šð£?÷ˆ©€ ; Z(¢�Q@Q@Q@Q@Q@Q@Q@÷šE½×#1±9%{Ô–Zl\Æ3&0\õ«”PEPEPEPXÕÂ3¨cÐɪº­§Û,]|ãæ_¨®rêG›TbOžún®¾˜4 a¼Œ³”¹aÔU�VyfP�&ð¼ƒ] þ‘ãoÉŽOï/­P>r0gR=Á z.8-ŒÕÛ+èìKHŠ^b0¹è*ëøbP„¥Ê–ô+�U$ЯPó÷4 À¾[99É©- YÙ„“,XÏ4Kk5±Û4L‡ý¡@c“ØP2.×+œã¸©ŠÈbD²ž€zÕë}*âðäGå¯÷˜`VöŸ¤Ãd œÉ'÷�o  dz “ÚZ3J»d�çÀì+R™+ãg±PNz¡§jË{3Dɱ€Êú@tQE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€2î�üOlǪ7õ­J˺ñ>²ÿqÿ•jS¢Š)QEQEQE„f—¥PEPEPEPEPEPEPEPEPEPEPEPEP&•‘¬ÞƒîñêÛ¬M7jëw‹Î~c“õ·M€QE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š)’¿—oÊŸU.Ì™b#½A]�¶LæFcÐÕŠEPªt´�ØQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEbj  fͽ@çÓ ÿ×­ºÀÖ›µ¨è¹ÿ¾¸­ú`QE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€”2•a�zŠZCÒ–€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€2#\‹#�Í�ûàV½d´›µ¨“Œ¬Žò­jlŠ(¤EPEPEPEPEPEPEPEPEPEPHI`d¾Ô´PEPEPEPEPEPEPEPEPEPEPEPHii’6ÈÙ�Ð5§ ›VBØ9oç]1$kœÐãΡ»û¨krúèZZI1ä¨àzžÔÀ°:sÅÉÛë:€fvq"wÊp+gûWv“%ڧΟ)^ۿÚӬÍ[Vs"ˆŒ¬Ãw\`Vn™®LnÂ]¸hä8Î1´ÖíÅ�µÓ«Ï HÊ0 (]«* Ê#8#5FÖêÍ®^áXÙsÎÐÅ]Žh¤,±ÈŒW‚çÈêCʾ¸ð®Æ€:Øî!’CH¬àd€sŠ–°4[[ë‰|¶ árÁõ­å`ÊAä@ \Ê¡k`1ÀÔÿ]?SÔn"Õ¶£•HÈ{z晬Í’ÇqnÊã$„t š–«ÚÝÃrŠc‘Y° Pyb�Q@Q@Q@Q@Q@Q@!¥¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€3.ÇüOlÜåZu™{òë:{öÇéZtÀ(¢Š@QEQEQEQEQEQEQEQEQEQEQEQEQE2I<°‚W¹©ÀädRÑÒ€ (¢€ (¢€0ìH ¸ä‡þk[•‡§�ý»tzŸ˜gñ¹M€QE€(¢ŠÏÖ.ÚÖÓ1œ;0�Ö³týjcp©rC#g"Ÿâ'Ìð ?uI#êúÕ•¨ypÌ ?Ž9¦iUšö$¼[fÈv±ÿ8©-äAÿyA®r)šë]‰˜Ÿõœ vÐQER¢Š(¢Š¡«\Ëm1¹{Š­y¥Ão¦J‘gŒ9,rN+j�€rÎh¸LPÜGÚ⪇‰üô®‡IÖôžD‰¶P»²:7­jP»@ôÅG­¼.^(Qõ*¸45QHŠÌÖ5°X¼¥Vf<†ô«Z}ؽ´IÂíÎA„³E';½±K@Q@Q@Q@ KEQEQEQEQEQER7CKEG žla°T÷±©(¢€ (¢€ (¢€ )3Î)h¢Š(¢Š(/QÇö¶›ž»›•jVf¢ö¦œFp¿•iÓ¢Š)QEQEQEQEQEQEQEQEQHT Å-QEQEQEQEQEQEQEsúsÿÅAp§©21]`XFSÄúeÿR oÓ¢Š)QEÌëÏ�GƒÑcó¬™KK9vîkC_�“Vf?u£R?QY§îç yǵ0:{ ˆµô"~„ ÍÐÆíYO`Œ•.›âÝå#1€Wõ—mw-¬¡ám¯ŒgÞQ\퟈ùÙsãŽSôª²k·¤Ÿ™SŸá_ñ¢Àu”V›­´²ˆn1ÈáÀþ”Ë}l‹¹šáϔؠ~TX‚³µÑÿÇ?Ýe#óÅfXër}¤›—ù\ôÇ *íÝõµý­Å´º_,²‚ÉÐ%¥ÕÑ>D üœ…ZÕ5ä©ûÛé#'‚‰ãóª~Buë÷Dg'ß"º€h;h~Ïm%ÚMŠæêjZLœÒÒ¢�ðsK@Q@Q@Q@Q@Q@Q@Q@Q@Q@ÖÎ88ä:uQEQEQEQEQEQEQEQEQEQEɤòã-ßµ>ªJÆyv(ÊŽ´v>Ö> �ÕºUŠETÐRÐww (¢‚BŠ( Š( Š( Š( Š( Š( Š( Š( Š( ¹*¤ªî=…:Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¤É¥¢€ (¢€ (¢€ (¢€ (¢€ (¢€0uçÛ{nsÂŒŸûè…oW?âC‰¢=ößC”Ú˜ ER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¤Å-€ƒÞ–£hÈ9SŠr‚;Ш¢Š(¢Š(¢ŠÆ›�ÄqÏýòkf±'$xŽ" ÿÇMmÓ`QE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€)jé»N—@Ífxj,Mq!?ª?ZÛ¸�΂Hÿ¼¤W;attÛ—FÇpÁÚ˜ ľLçøA5�£†}L0=-K}« «�¹éÜÕË;W±Óæ¸l Ù sü#Ò€5Édœ ¡®N}Zâkw·”«êqŽ*=>þK·òÊWIëéE€ì¨Í!®jãR¸½µ2b°cý?•YÒ5K‰e’+�®±Ç»pñŽ('Rlê““È.jÕÄ3ÞÚ[Ë lêªT�Î0ÏåY÷r¬·’ºd«9#?Zé°Úv�û¬oDÝÏ©94ÀÆ¥ÊÛ‹|�Û�¸8§ÚÎúh2@~•wqšžÃYV‘þÞTà|­³ô­[Ÿ±_Yn™•¡ë»8ÇøR[Èï­ÄÑäg‚§¨5b©XÅk ¾ûB¦"IÜZK]ZÒêO.9>rx 1šºÄ*’N­5]rŒzƒšÉñì-’ëâ}‡ÿ¬T~pÐÜ Ù;�ÛéÅnÕ ^éí­±‘úJ¿X$r³@½¶±ýEÒ—RycœI¾Øa#öõºk. ž fˆou�#¾kNÕn!¹ q<’Eƒ•àæ€:[«û{=¿h�&îœf§¥ ‘œûW¨]›ÛÇ›iQ€'8hjSÏh, ‡Ë 'vZ,ä«cª�„¬¦3Ÿ”ò*]ÖöJ‘‘'eé\ž�uöK±1€`f®ßLu+!xP¡ŠCÈ ÿ‘@Íõ½¨S;í ŠÉÔõ§Ü±éì§¹_AG‡§ûDYλÕ9¹=ª¿ö5ÌzŠ„MÐù�·ö œâ€4ï5„³+‘–—`gU=3V?µ,ÄK!�B°“È®kTu9¼ÜáŸ'�¿J†U[‰ÂÚFFx ÜÐk‰*�ƒ+ ‚;Ó«˜ðõç“rm]ˆWû öjééQEQEQEQEQEQEQEQEQEQEQE˜¥¢Š(¢Š(¢ŠÊÕ †Ÿ†Çï:zô­ZÉÖ2/4æ¤ÃùŠÖ¦ER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(ž´}þ%�ŒÇé] s¶™�IJ!æwÿÐs]0 (¢�RàMs>"oø˜*ž‚0SVpÃ>2†?Ÿ5‰­ßí\b›6’ƒÿ×­<Ý8åQ°†õ\š`TÐ]g¶¹€dAüÿýU·$VÇÉ‚$IYxÀv5f+Be6ð–}ã“Æ::£sv×¼’ÉXô µ‰¦›Ü_Å(SåÆÛ™»{Vž¯¥I,¨ö¨˜þ%Î9õªÉ©]ÆÅŒÂ#JuEóòÂ:@YÒôW†äOrWå*y>µþ—Ïc‰å�9]®5g9ü?úÕ¯¢µãÁ!½ï“xÁÆ(³xv.6NëëÀ9«¶šUµ¤‚TRd˜æ®â–�ä «ƒ�V)’.ä"ˆÎPSØ¥¢Š@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEG4›Üô¦ZűwóB¢izðµb‚Û²°QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQERn¢�:€ËŸLШ¦™P~´†D%Ô­>Љ®a_½*ø¤v劉“#¶êšŠ‡í0Ïdÿ¾…'Û-¿ç¼÷Р è¨EÔdMýô)>Ûmœyñçý꞊ªú…ªu™sè9¦jÙà~÷¯l»EPmfÍz»ß�kVDýöå hQY­®Ù#2w Iý½cýé?ïƒ@tVbë¶mždõN´nÙ÷2ø iÑYm¯Ù `ÊÙôCNmrÍÌð@þ'áá?ì7ô­øÔ§û£ùW;«ÜZjJ….¼’ ¯Ì„õÿõV�¦­e$±ZG)i6€>Sέ04¨¢Š@QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE„àRÒ0 4Õ}Ý©ôÔ]£§PEPEP%ÉLj!àõ_äkn±.Hÿ„†!þïò5·M€QE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢“pÅ-›—ûÃó¤Þ¿Þ�:Šo˜Ÿß_ΓÌOï¯ç@¢˜f‰FLˆ>¬)¢æ2&�»…KEBníÀÉš?ûèS ý¨ëqýõ@hªßÚœÿ¤GÇûThZc>zcëE€³ET:•˜ÏúBqHÚ­’Œ›…¢À\¢¨6±f?��ÑI¤Õ–qæ‘õSNÀhQYçY³Æß÷ɦÿnZ…ñë¶‹¥Ef6»f¤Œ¹Ç ¦oÛgˆå#×mZŠËþݶãå~~‚šÚì#8ŠFü¨°ÕRëN‚é·¸!Çñ)ªc^ˆŸõ.(:èÀ+lç>ônÓL·´;‘w?÷›“V�C¡VR0G­elM¸(±“$ddõ¥þÓ¼Û¸i’ãë@�Çö í&èAÎÂ9>ßJ»s¥ÚÜ�ÏÖ¯WûN÷ò~™<Óµ®ÉâÏuÈnhFÞÊÞÞ#Q¨S×#9úÓÖ‘J¤j õÚ1YÚw祑ü�'ö–£Œ}‰³þé  ¡k+ò’Æ6Ï=¥I$—š¬áT3· 8P=iº©¹k¡-ÔF7q�=‡£aq|-—ì6‘•=[O¿4FëJ»¶ÉhË ܧ"¤²ß.Ÿwj¹Ü@•G®Ò2*{�GP7&ÝÂr6” ×5JÊ[˜/”D”’ zÓ¡ 3ÉÍ£«yn¤†Çô5@é7ë6ÑnÙÅ‘�ζ„šÇE‚0Os€5Æ´ùÈE_öHÍ!�ŽÔ]Z I¥ 4Q€prA¬Ý!Íž ��–Ãñ¦Z=Ì7²´eUäùw7×¥°^Ep%”_�Ê{Ó­¬�~Æ[µ…à�Ìt$8?þª†ukˆ’D»]¬3ÉÿëTŸcÕÈæñ?þµ /ivïm§Å ¿|‘铜S&Ñì¦}æ-¬zí8ÍUû©ÿ?`ÿÀ¿úÔõÓo\f[÷SØ'J±ý‘c·oÙ×ëßó©íí`¶]°Ä¨=‡5Di7Ô®3ߦ*1£Ý3bMF]Ÿìä¸ÚU›KævrqÐþ;[BÐLk垪e¶“xØïI_W'4.�t:ÞœwêsúÐ�µ¬ˆVäûÔ¥€&±Æ‡#0ó/Œçÿ�)ÐA?ñ÷(†:P›½>ÚñÏ� þ pi,tÛK)<ÄmòtÜÍÒ«ÿÂ=ës)ü9tT’'“'¿aì¬ín˜ •Nr>¸«_iƒþ{Gÿ} ͵-$�ø�ð§&…§’NÆo«š¾níÔàÏ?ï i¾µn#ÿ¾…VþÃÓñ�³�®Ni?±,ßrÆ€,iYÏÔ_÷ФþÓ²ÿŸ˜ÿ:A¥Øà²ÄqÜ®MGý‹aœùú1¤ÿµìs�´)>Ù£û^Çþ~õ£û&È˺Ÿ®i²ìÏXþ4ÀaÖ,ü¼/äi¿Ûš~3ç㦥UˆémåS-¥º!E†0§Œ  ˬذțÿ4ßíËùèß÷Á«Ùöœ£ÇÇO–—ìVßóÂ?ûæ€*nÙqÌœÿ°i?·¬òqæœgm\[+U9[xÁÿtSþ͹��öEg7ˆ-ãkþB�ëð�‡òÿÒ[xT`Dƒþ)|ˆ¿ç’ß"€2Lja9Ä2dvȤ:òó‹fãÕ…jˆ""OûäS¼´þêþTŠhÜÀEnÑXLÚÆÞ�øšhm`çå“ñÅ~Œb°âu÷H8'¨+Å/•«ã«ø  Ú+ !ÕØ�ìãþ)®°�0ãÔÈ(zŠÃúÉÿ– {ïáNû¨hÝëóÿõ¨jŠÄk]X®<ÞG£ÓÇU'ýp#?óÐÐõ‚tÍE±™WƒýóGö]ù<̤{±  ÜŠ3X'H½<ùÊ?àF„ÒoÁ;¦Cžû�odRÖö5áÿ—„‰©F¹ïuÛ§8  ¬ÒdzŠÄmï[•ÛéÍ*h— MÐÁö4³½OñÎ�1?¾¿�c� ûÜ ÿ»Ò˜<>ûònFßM”´eŒ ™­lxÎõÇÖ²@ ×9§ÉN]ÍËcýÑ@fâë*ø¤vç¤ñÿßB³ÿ°£ÇúöëýÑMÿ„~-ÙsÐ…i}®ßþ{Çÿ} Cyn?å´÷Õg�"A3I‘è8èqv™Çà(Ð ËylÇ «V¾Ëoÿ^ìôö¦·ö¿E1ʵh¢àe"jùÉ’,ǵ)�V þö0~€Ö¥\ µ‡V™â'ÓýjE¶Õ\|÷h‡ÙsZ´Qp2Í®¤HÍâŽ{ FµÕ�nÓÃÒµh¢àd®Ÿ¨yš�YÞ*`^³ö…hQEÀËzˆãí þÏJOìûâ9¿mßN+VŠ.P°¿ï~Æ�é·¥³öò?þ5­E1´Û–9ûsƒÜ�ÿצ�*á¾õôŸ—ÿ^µh¢àe�&MÙk¹ôçüiŸØ®O7²ã=?É­z)\ •Ñ�:]ÈO¹?ãGö3•Ã]9üÿƵ¨§p2†Š¡ ùïϵ5tÁÊÛ½@­z(¸CC‹\ãÔ S¡ÀzÉ'éZ”R¸‹¢@?备ñ Ió%Ï®EiÑEÀÍ%°êÒ1É¡tKUËŸÆ´¨  åÑm‡9îZœº=¢ÿ «¿EQm&ÕŸqVÏûÆšÚ5£�Hq�F5¡Eg�Ì ÿßFƒ¢Ùÿqÿï³ZPhÐì�'cœú¹¥%ˆÏîØƒØ¹­(<è¶$“åÚ4ŸØvÁ‰�ü Ö�œº%’ˆÛ�W5+éVnrðƒõ&®Q@%•´`·ŒþÈ©(Ðå#U> bŸEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEG;ºBÍ~c�ÂçªFöû¶œïà­(™žæsªG+[˜cç“ZK{¨�s§cÓ/UîÇüTx+ŸÈÖå03…Ö¢AÿAO¡’ƒ>¦O‘ŽïšÑ¢€3<ýTçýqýêaŸX#‹XGü §¾Õ!³;2IýÕíTÓÄ>'·d_Pr*yºÕú}‘Aõ�ç@›X<ˆPqЀ?­kG"Ê�у+ ‚)Ô\ ƒ.±ÿe“‚QÇâ+Z²uÌfÇ'zÖ¦ER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š( ÀɬÙåk¹„QýÜÔ—S´¤ÃObEX¶·XXõ4ÆÔ×3Ü|0¬)µGÔúÔ”QA‹wÕ…Q@‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ¢�öÆpy5-V8–ç’‚¢µ¹%º�æûÆ¥¢ŠÝÝŠ( AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPE‹œs@ EPEPEPEPEPEPEPEPEPEP vë–ùõL~f·+S\ë6Üã ÿ¾�nS`SÕb3ió*‚Ç€=�gé·ªöÞKü²"�™èÕ¹YWš2Ìþe»ymÔŽÆ„? ¥Ü·$¤ß’IÆ1øÔR$‰pÉ !”àÖжբ`��“±W~t°h³Í7™xøÉåš� áûC¹®]pÊžþ¦·©¨ªˆ@ êC(jZœvC)wnŠjË¿Õ »‡ÛæÇ�+ùV½î�ñS(!—£)æ¢]ÌJ»cÕ©�ÏÙÇq;´6èHqóžÀTÚÍnäK'8Éí"†(lH¨=ªZØS§¶ãÈ#oÖ€£Ïö�>2NY~SøW5ªº„è§!_ÿ¯Z>yÌñ“ò �|Ö…î� ܦ]Í7ÞÀë@ørt{W„.×FÉ÷½K­ÙIylžHÜñ¶vúñSØiÐØò‹37VcW(ÏGݦ´w ²fbAà•ô¨l´Vá^ä¨D9œŠ.kûAyjð“´žAô5›gáõD�]6âÜ.Þ1ïõ­º)‰‡c–’fdìÁ¦Â9ûÌý§)ž›9­ê)Ü­àŽÚŠ%Ú‹RÑE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€1ü@ÅVØôL“ô­ŠÇñ"Ú åñúV¸ä `-QHŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š*¬çx�n”¢Úmª¥ÝÎÏÝF79ãŽÔë›�™Hþi=j-m¼¿�ùsúP\RŠæ�¶–þJe¾ùëíV(¢ƒ97'vQE (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€ (¢€#™¶ÆqÔô¦Û¡UËu51–ä ÎÑV¨-è¬QEQ@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@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@š†?¶b,x?�mÖ¨GöÄc©ÌÎ·é° (¢�Q@Q@Q@sž ‘ÍÊ¡$*¯‡5ÑÔV�Ý YÓpB) 0<>çûGhèclþbºj«i§ÛÙ±hT†#“ž*Õ )qÏ´QE€`RÑEQEQEQEQEQEQEQEQE%-PE5·q·y§PEPEPE”´RRÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPHN;f–Š@sKEQEQIžqK@Q@Q@Q@Q@Q@Q@^ !mbb3¶@@õàÖšd '®+'ă6HFx~ßCZÉ÷è)€ê(¢�Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@fÊ%‚å�TœŸJÒ¢‚á>S65¸wg ´Ÿj»>ѽŽ{Ô´P9O› QE…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@2WÙ=ûSê´Ù’`ƒ§z Š»n§fâ0Ʀ¢ŠÝÝŠ( AEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEP£‘®EÆrcþu¿\ö¨Ûu”úÆ?Zèi° (¢�Q@Q@Q@Q@Q@Q@Q@Q@Q@TsOºo•‚¯Lš’ŠŠ ˆnP´+¨8$T´QEQEQEQEQEQEQEQEQEQE%´”´”´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@>!\Ù!ìúÔŒ““Ô�Yž#ÿ�oü V”G1!õQLÑE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠF`ªXô5Vä’MŒ úÞ‹ùBų8f#ò¨f¶ÑdQ†Q“A¼!½î¦�2IhYº ŽÎq< ÷^ 2øŒq“Aš�½ÊËâD § ŒŠuCj‚;hÐt¦ –’nÁEP ¢Š(¢£œ%öýà21QÙÌeˆî9e<ÐW/»rÅR©‚E¢�zÒÐEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPdpˆXÔvã ¹êi³�õ©À;P^ÑõŠ( €¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(žÕc-­Géû³ÿ�èkX º¬%yÜôoþ½oÓ`QE (¢€ Bp3KEeÙêësvвìeN}:æ©ê:ä‰1Kb¡Æâ3“YºŠ›mFe^ÌHüyþµ¡ Ú,ì×`‡jƒëTí´¦kxä �Ê K@éEHQ@Q@Q@Q@Q@µÔ)7”Îñœçµ™5 Á _2ƒ…õ5gÄfTár:µtTÀ(¢Š@QEQEQEQEQEQHHPI ÜÐ;�AmnR)T„oãôªwÚêEŲ‰v< ©«ßÆÛ®äSÔu?ýj«¦¼)p¦á§|ö÷¦A¤ÞI{ld•6�ؽH»v�¸ÛŽ1KHŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ŠJZ(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÊñ>Ç+¸W#×­jƒŒVgˆ?ãÅ[8e�}ù­5û£éL¢Š)QEQEQEQEQEQE™ª K{Uø°aNãhª¹Çê©ù$TRÄ(¥Ôéqr§¢9Y@4Í@~éO¡ªÏtÆer›xÁ÷«SþþÈ•ëŒÓ+Œ“d–§6éô©«>Öíb€«žTð=jŽțvFÒ("tä›eŠ*»ÎÇýJ‡÷¦ý¡ÓjŽOjv'‘–¨¦!Ç¡¨¥¸1È2¸äÑa(·±b¨)û=Ùa®$©'Ý`j è÷E¼uZEÃGÊú�¼™Ñ‚'Žh[uýë1'® SyyâÇ\�[;ÓI"í’&Ê–úf¦¢Š op¢Š(QEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQER€O¥‚Hî*ÜîX׫u i]…¸ÞZBO­OH£j€;RÐ Ý…Q@‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š(  MYsªZ¶3ÀÿЫn±uoù ZzeGæÕµLŠ(¤EPEPu—Z„¨™YÛñÿ “L¼m:䫃±ŽÙ§½u„¦Q‰ñcš‚çN·¹1ÓŒnîbÕme¹H#bÎüŒ/v©ÙiÐYÑåœñ¹ºÕÊ@QEQEQEQEQEsv:}̺‹Ir�·sfïÏ¡¤$Ã}¶ONƵ(§p9«[ÙôÐÑΤ"än9ö5·§^ ëQ0]¹$ô«H1"+B3Bª¢…E @(ÔQE (¢€ (¢€ (¢€ (¢€ (¢€(ê—ImYˆ—* öâ¹Bå¤Á$.k´žÞ+• 2Prõ¬½OHŒÁæZE‡Oá_âÀÓ´ XÄòöŒb¦®VÆëP�Ö u'çå þJêFp20i´QEQEQE&~lRÔmŸ5Ol’€ (¢€ (¢€ ÊÔì.¯nP$Á-öüÀ“×éZ´P{[(m'=Øõ5Ÿ©éF3Z€ýäì~žõ±EaéwKt¶’Ââ=¤å”�¿�¥nQEQEQEQEQE&éŠZ( Š( Š( Š( Š( Š( Š( Š( Š( Í-PEPEPEPE'9ö¥ Š( Š( Š(  ¯ éÝF7ŒçèkJ/õIþè¬ÏÈ7¦ñŸÖ´áÿRŸî�åLÑE€(¢Š(¢Š(¢Š(¢Š(¢Š(¢ŠÈÔÔÉtì Wà¶ åBžàUkˆ™µÂ’ hÒGEIµ¤W¼ˆ=³€9"«X–{y#¹£LŽ$‹; õ¦B�£Êe˜ã�‹mý†*Õ¥»Ý›†~•s–�Ê«jÅ+eš¡Nýjo(ÈÀ¿Ò§¢™m»�eÜ)¦# 3RQH›´VŽÎ8åÞ ã ô«d`ÒÑ@97¹ ZÅ›ÕyþU5P ·¸QE(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š¨òyw …+Í-±2ÈÒƒ¥C©1GB;ƒQ5ÃÅHAw>”\êPæŠk©¥æ§™åçæ§Õ[;sn“™¯µZ ç’IÙQA!EPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPEPd%QŠŒ�*+iüå9á…OT-Û·AÓŸçA¤Rqeú(¢ƒ0¢Š(¢ŠLPÑEQEQEQE%-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@šÏü„m=™Oþ=[u�«ŒßÚúåqÿ} Ù¦ER¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(@ëKMQ�ŠuQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEeø‡þA§�âÖ´ ÿQº?•PñüƒŒ²�Ö´ccQ覨¢Š@QEQEQEQEQEQEQEQEQEQEQQ\¶ò×iÅJîÄ€ç¥-giŽDŽ„õÅhÐTáÉ+QAEPEPEPEPEPEPEPEPEPEPEPEPEPHH' ¥ªÚƒ³�Œäàqõ ¨®f‘Ô�›÷?uœÞ¯©  ô¬Ï'säs¸¥\°9´NsŽ)TŒmxú(¢Šg8QE!8ÐÑLŠA"Sè¬QEQEQE^ IJ¸â§= PÓ�ï¤úPi§Í (¢ƒ0¢Š(¨`a¹“vqÒ¦¬ø‡—¨°ÏÊÇúPitÍ *­ä­ F^™æ¬#‰2œ‚3A.-$ÇQEQEQEQEEqn—óÁÈ"ˆ`HFó5!8úU{k±;²íÛŽœõ µÌã¦Åš(¢‚Š( Š( Š( Š( Š( Š( Š( Š( Š)‚©cÐPH$àPa�A¬ÍJo28ŠýÓœýjXìØF­ ¤dgÚƒof”SnÅú*�­Û—h§e8ÍY{ˆÔ‘œ‘ØPC„“±-Y¯c\pjh¥ISrŠã$®Ðú)�*#c‚zSè&ÁEÖ‘ï0S@¢‘X0Ê�Gµ-T+s. ÁN¹¦Av³1R6žÞôÉ-ìY¢Šhub@ ‘A#¨¦»ª.Xà ÖEÊE³ÜugÊÞEîãÐóZCS�r£Ž£Š )[šÏ¨÷Ô#jƧ…ä|—@ƒ°ÍCaˆà$äÓ’èµÇ—°ãÖ�Ê+U±fŠkÈ‘Œ»æ„uuÊ�G¨ ÊÏqÔTSO+—l{T1jHH#oÖ‚”$ÕÒ-ÑMGY2ƒN €¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(U\êv waÓØŠØ®z{—¹ñ€BûsëÆMt4ØQHŠ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š):u ¢Š(¢Š(¢Š(¢Š(¢Š(¢Š(¢“#ÔRo_ï΀E4ȃ«¨üi ÑŽ² ú° ÑPÛUëqÿ�Š>Ùm·>|XõÜ(z*¹¾´?i‹ïŠ�µK87Qgýê¹ER:µ€ûT�V±$r„ŸJ»EP}fÁ:Î?#MÝ‹,¤ÿÀ hÑT?µísÇš}Äli­éÉ÷òMBŠÏ:¼#ƒ À>†:Oí\‚VÊå±è£üh°4Uí'?vÆäñŸºõ£ûBr¤®Ÿ9Ç©úÑ`/ÑYÒj3Æ¡žÂaÎ>ðþ”G}y6|½<�êòNÀhÑT>Ó¨gþlu«TÊ..Ì*…êùs¤¾õ~ªj ›|ŽÆ‚©?y º¸‰¢Úy8È›pż­¿/'4¶$Šdq¸ƒ�šbo|À¹ý)Ú6pF¥\Fýf˜×‘,�3õ>”ÎnI>…Š*?>/ùè¿�,r¤Ÿqƒ}(˜ú(¢�Q@ ™¶Bì{YP?“(“�¹æ´îFmä«Ua…fµ`:ƒAÑM¥rãH¨»™€_ZDa•`@¬¶.̰Æ@ÅNÖRÂ7Êh¥».$ñ»ìVÉ©+:h ³¤ˆ S%òù�PK§}c©<’„ã«zUi®¥ˆØ ÷ª×sn•dˆŸzÛÙ�« <~t\Ò4šIÚ嵺I i‚CIg1–3¸å…S±�¦$È1§­K5¼�ɺÝIÆ�8A7“Çw¾á¢+€8Ÿ-ÌqpÇ'ÐU/²Ünó1ózµ¨OšO™ÏéL™F [�†å&áx>†Ÿ$‹–cYW‰Øª”"¬ÚÆ·11|–g4T’\Ý ‘H%@À`vEP—å�ìjU²<™$'4ãåº)¨‚5ÂÓ¨2 (¢€ B†–ŠÃ½R¿(=¥L³Ý, · ôíN2cüê݃´LsŽ*z�²šöiÚä’P¹O˜ŽM ˜*6©â´j)-¢‘·2óíT`ª.¨ÍºŸæR 1Æ3г`Â8Û{Xð*È·‰G?iµˆ¶ph)Ô‹�)VéšF.£åNõ47Ñ”g Þ¬„P¸cÒ¢û$÷l žx5fŠ×—gËÄYž¾Õµ¾d�ïÆkBKxäP ôéŠ�,¢^ ·Ö‚£R 6EK)ü¢Å¸J¾—¿FDZ§ùhFµ'•íÛ>¸ ‰Ê2w±JæÒG˜´uúóÒ�-‘¦#‡}êõµ–†h–ë^ÓŸ\Rý’xðÈÙnø­(µkdfºÝÌ›8Èešß*#'žr+VŠít³Z[‰z.ÁêEI,Löì¬w6*z(3ç×DW²[#f© ZÎvÞ ŒÖ­5‘Xa”¨ ¨ÔI»­—9-ÜžØ[%ÊgËVúÖ E^ŠáN ¿m¥’ÐÈ’ÊydÜåsõ¦ÍfÂIPð5ªð#�HéQKf’/Ò•‘Q®ô»3¬$�Ë^â¶W œšdP$C ?RP•ŒªÍMÝ ¢Š)™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@! ž¥¨/a{‹v‰ib2}³ÍsžxþÝó#;³0Žù⺪ÀRYjñ²[´°€Wœg¹úVÅͪ\ª‡iiÏÈÅi°'¢³›H�¿åæäúéLþÅ]À‹»‘ÿ  J+)ôw|«ÉƒöÜÜTM¥^�p£þÔµI‘ëX¿Ø×\¥þ{¿Æ�¢NOÏr¸öühk#Öšd@p]GãY#BlÝ{aúô`#/Ï6[®vбš1ÖDð!MûD8Ï�?Þ˜š ËI™½p RŸÁž%ÈQ _h‡þz§ýô)êûÓF?àB³†ƒÿ–ÒcÓ�ý…oÿ=$ǧáF€^¶ÄdOïSQ³SƒsçUF‡n:I(ãGøT‘èÖh>hüÃêç4h¿Ú–Cþ^cüé©d|õ?LÐ4»1Œ@¼t¦ȶï(ý7Q þÖ²ÆDÀý¦�fÈyŒ~ˆjOìÛ=¸û:bœº}¢©Q`õâ�ƒûjË�Þ6Om¦‘µ»%ÆçaŸöMYû ®Ð¿gŒ�ê´äµ‚5 � ¶ÑF€TþÛ²Î7°8ÏÜ4Ö×lÔÿËCÿ«�go&7ÃÇO–�´1’R$R}Dë¶c¡vú h×`lypÍ!=•sZ>DA·yi»×h§ªªýÐÐPaÖp?ãÊçþø¡ui$}±XNÇçŠÔ¢€2Æ©rN›0Ͻ*êwLHlÙ~aZtPXÔîØüºl¼zšoö•ñûšcŸ\¶+ZŠÉmJùxþÏlõêhš£Ÿ’Áõg­j($]jåöýŽ/÷·qN3jùÿ�h:öjÔ¢€2DÚÁýÏv¥ó5•´íìÖ­”nµQƒö49ÿjšÚŽ ’l6AÛ°\ÿ:×¢€3>Û¨…ÉÓ¹ÏA § õ6£!ú(¥E3û:ë:ŒçÐ`SÓL`>kÛ–ÿ�â´(¢àP:Z·[›Ÿûúj94¦ã˹Ÿßt¦´è¢àf�!HÁžsõ”ÓWD‹{y“ÌéØoŒ=Óé1@ EPEPEPEPEPEPEPEP€Iè(‘A¥ Š( Š( Š( Š( Š( Š( Š( Š( Š(  ¤ˆ®yରyæm½GO­K~��ã§JšÎ/.Ÿ¼ÜšŽnXs-ʱK$b¸ÅK¦Œ$ž›¸«nŠã �z5 •DâôÜlã1“ÜTVR´Šèç,‡ö« »”©ïQ[[-¸m¤’Ç$š Mr´Èd¶sv$_ºH$Ó.m¤7 $CëíWè Y"�õ³ÎˆS”ôÏZ«nÿfsæ¡ÏjÖ¤   �[G•ìf´rß9%v(èM]†'X r>ãÓ#°©¨ ™Tm[¡Ÿökˆ‰0ÁïO[7s™œŸj»Eud @` `†1&ð£uIEwbP)h¢�Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@Q@¢ùs«âëZV˶Þ1þȬû•kË–T胊|WRE�Ô–j]N¹EÊš�TOuuäJŠ0AëVIù œV}½�xY¦b]Îr{U«hCɸv©™MA+'ª)ýªL žž•r¸ä' {r[FŽÌ$ö4å‚4mÊ€RƒèWÔÈ­Ž‡RIDìªN5©,bXÊ7CUÓOˆ&–>´N¤Tuܱ)@‚§Õ?ìõvGj4 @IÖƒ)(ôc¨¢Š (¢€ £©ÁæAæ(ù“ŸÂ¯Rz „œdš)YÈÏ`@2 }j(îv)̼ìH«–öâÄ6wTÛFs�A«œnô*ZBÆC<ƒŽ\¢Š ¥''p¦º «t#ê($©gnð3î#iéRKkγŸnõ=ç&ùŠO§‚s•ö#4£O‹31>¹«”P?k>åd±…GB~¦§DT@ö§QA.MîŠ*3*‰D}ÍJä”TSÌ!MÇ:zÔŠw(#¸Ígk�™<È�ÆF*8`ädœñVh |ÎÜ£ H_yQ»×ú( ›†3Ö£0DzÆ¿•IEM­ˆÄ�ãéIöxAÏ–¿•KEÌûˆ–Š(QEÖEq†P~´‘Ä‘ "€)ôP;»X(¢ŠQLg ÁOz×EPEP]B?2Õ±Õyªú;’§¡´ezŠËÒ[¿Þ_åÿë¤÷:`ïJK±­ES9‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( e ¤àúZ( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ªÝ܈@PFOZµUÚÑãÎcŸj ‡*w�¶ÐyJIå˜äš›ÐRÑA-¶îŠ( AEPEPEPEPEPEPEPEPEPEPEPEPTPù—ÄŽÇùUêγ¼sž›¿�´ö“%ÔGî”ûÔö¿ñíû¢ ÔÕ/ûÕ5¹ l„ô�¿á¢j)ªÁÆTäPÌeŽ(1°ê)‰"I�Œ=)ù -`¨|Ãö‚™ã5RŒƒ¨?RAApW¹vŠ( €¢Šj¸làô QE4ȃ« u6BDlW®8 2·B )Çz±VÆá¥²²ŸÒ­ÖjâÞø�FúÖ••RNë¨U{Õ&êœÕŠl‹¹OB(".Îã-œÉ ±ëÞ¥ªšyS/÷N*Ýš´š (¢‚²l—e�Ùd[ß4´¶sšFÔ¤’’eê(¢™ˆQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEV}§É{"úçùÖ…g– ¨d÷l~”ÓÕIy_ŒÛþ"«™›ìËuÇ8ô«WÊÍnBŒœƒM²‡le˜rÞ´”.û�YOJÁÛœþ”ÝBG.—Ž­^ІÝåŒÒ\@'�iàŽ†—@U#ÏÌAaE.H‡£»˜™¡û§ñB\¤‡€H$Ö…2HÒUÚã"‚á.WpINPäzÓ騋…A€)Ôí}Š( AL’@˜ÏS�N+>ßtï)ÆÓÀ4Þï±5øýʓԚۛxóéU.äó¤XÐçéW£M‘ªú P\´‚L\KE…Q@Q@Q@Q@ eb~ö•QW�9=éÔP;…Q@‚Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š)‘Æ#.C1Üs‚z}(ôQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQEQE¶±ÈÛˆ ûžŠ›[ÅE÷G>¦¤¢Š¶÷ (¢�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@Q@Q@Q@Q@Q@Q@Ômè­ŒdN Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Cþ¥?Ýú( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( Š( ÿÙendstream endobj 5 0 obj <> stream 0.24000 0 0 0.24000 0 0 cm q 2480 0 0 1748 0 0 cm /Im1 Do Q endstream endobj 6 0 obj 60 endobj 7 0 obj <> >> endobj 8 0 obj <> endobj 3 0 obj <> endobj 1 0 obj <> endobj 2 0 obj <> endobj %RRR010createpdf*001.00.200**********1000 xref 0 9 0000000000 65535 f 0000176802 00000 n 0000176862 00000 n 0000176742 00000 n 0000000015 00000 n 0000176424 00000 n 0000176535 00000 n 0000176553 00000 n 0000176618 00000 n trailer <> startxref 176951 %%EOF Solaar-1.1.20/docs/LICENSE.txt000066400000000000000000000421631522022367600156020ustar00rootroot00000000000000GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The 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. 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. one line to give the program's name and an idea of what it does. Copyright (C) yyyy name of author This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, see . Also add information on how to contact you by electronic and paper mail. If the program 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. signature of Moe Ghoul, 1 April 1989 Moe Ghoul, 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. Solaar-1.1.20/docs/PRO_X2_SUPERSTRIKE_CLI.md000066400000000000000000000224571522022367600177050ustar00rootroot00000000000000# Logitech PRO X 2 Superstrike - Solaar CLI Reference This document describes all available settings for the Logitech PRO X 2 Superstrike mouse via the Solaar CLI. ## Device Identification | Property | Value | |----------|-------| | Name | PRO X 2 Superstrike | | WPID | 40BD | | Protocol | HID++ 4.2 | | Kind | mouse | ## General CLI Syntax ```bash # List all settings for device solaar config # Read a specific setting solaar config # Write a specific setting solaar config ``` The `` can be: - Device number (e.g., `1`) - Device name (e.g., `"PRO X 2 Superstrike"`) - Serial number (e.g., `A1C55DB2`) --- ## Available Settings ### 1. Onboard Profiles Controls whether the device uses its onboard profile or host-controlled settings. | Property | Value | |----------|-------| | Setting Name | `onboard_profiles` | | Type | Choice | | Possible Values | `Disabled`, `Profile 1` | **Commands:** ```bash # Read current value solaar config 1 onboard_profiles # Set to disabled (allows host control of DPI, report rate, etc.) solaar config 1 onboard_profiles Disabled # Set to Profile 1 (use onboard profile) solaar config 1 onboard_profiles "Profile 1" ``` **Note:** Many settings require `onboard_profiles` to be set to `Disabled` to be effective. --- ### 2. Report Rate Controls the frequency of device movement reports. | Property | Value | |----------|-------| | Setting Name | `report_rate_extended` | | Type | Choice | | Possible Values | `8ms`, `4ms`, `2ms`, `1ms`, `500us`, `250us`, `125us` | **Commands:** ```bash # Read current value solaar config 1 report_rate_extended # Set to 1ms (1000Hz) solaar config 1 report_rate_extended 1ms # Set to 500us (2000Hz) solaar config 1 report_rate_extended 500us # Set to 125us (8000Hz) solaar config 1 report_rate_extended 125us ``` **Polling Rate Reference:** | Value | Polling Rate | |-------|--------------| | `8ms` | 125 Hz | | `4ms` | 250 Hz | | `2ms` | 500 Hz | | `1ms` | 1000 Hz | | `500us` | 2000 Hz | | `250us` | 4000 Hz | | `125us` | 8000 Hz | --- ### 3. Sensitivity (DPI) Controls mouse movement sensitivity. | Property | Value | |----------|-------| | Setting Name | `dpi_extended` | | Type | Complex (X, Y, LOD) | | DPI Range | 100 - 32000 | | LOD Values | `LOW`, `HIGH` | **Commands:** ```bash # Read current value solaar config 1 dpi_extended # Set DPI (format: {X:, Y:, LOD:}) solaar config 1 dpi_extended "{X:800, Y:800, LOD:HIGH}" # Set to 1600 DPI solaar config 1 dpi_extended "{X:1600, Y:1600, LOD:HIGH}" # Set different X and Y sensitivity solaar config 1 dpi_extended "{X:800, Y:1600, LOD:LOW}" ``` --- ## HITS Tuning Settings (Hall-Effect Inductive Trigger Switch) These settings control the advanced click behavior of the PRO X 2 Superstrike's hall-effect switches. ### 4. Actuation Point Controls how deep the button must be pressed to register a click. | Property | Value | |----------|-------| | Setting Name (Left) | `superstrike-tuning_actuation-0` | | Setting Name (Right) | `superstrike-tuning_actuation-1` | | Type | Range | | Range | 1 - 10 | | Default | 5 | **Value Interpretation:** - `1` = Shallowest (hair trigger, minimal press) - `10` = Deepest (full press required) **Commands:** ```bash # Read left button actuation solaar config 1 superstrike-tuning_actuation-0 # Read right button actuation solaar config 1 superstrike-tuning_actuation-1 # Set left button to shallow actuation (hair trigger) solaar config 1 superstrike-tuning_actuation-0 1 # Set left button to deep actuation solaar config 1 superstrike-tuning_actuation-0 10 # Set right button to medium actuation solaar config 1 superstrike-tuning_actuation-1 5 ``` --- ### 5. Rapid Trigger Level Controls the rapid trigger sensitivity, which allows the button to re-actuate quickly after partial release. | Property | Value | |----------|-------| | Setting Name (Left) | `superstrike-tuning_rapid-trigger-level-0` | | Setting Name (Right) | `superstrike-tuning_rapid-trigger-level-1` | | Type | Range | | Range | 1 - 5 | | Default | 3 | **Value Interpretation:** - `1` = Fastest (most sensitive, smallest movement to re-trigger) - `5` = Slowest (least sensitive, larger movement needed) **Note:** Rapid trigger cannot be disabled on this device. The minimum level is 1. **Commands:** ```bash # Read left button rapid trigger level solaar config 1 superstrike-tuning_rapid-trigger-level-0 # Read right button rapid trigger level solaar config 1 superstrike-tuning_rapid-trigger-level-1 # Set left button to fastest rapid trigger solaar config 1 superstrike-tuning_rapid-trigger-level-0 1 # Set left button to slowest rapid trigger solaar config 1 superstrike-tuning_rapid-trigger-level-0 5 # Set right button to medium rapid trigger solaar config 1 superstrike-tuning_rapid-trigger-level-1 3 ``` --- ### 6. Click Haptics Controls the intensity of the haptic feedback when clicking. | Property | Value | |----------|-------| | Setting Name (Left) | `superstrike-tuning_haptics-0` | | Setting Name (Right) | `superstrike-tuning_haptics-1` | | Type | Range | | Range | 0 - 5 | | Default | 3 | **Value Interpretation:** - `0` = Off (no haptic feedback) - `1` = Minimal - `2` = Light - `3` = Medium - `4` = Strong - `5` = Strongest (maximum haptic feedback) **Commands:** ```bash # Read left button haptics level solaar config 1 superstrike-tuning_haptics-0 # Read right button haptics level solaar config 1 superstrike-tuning_haptics-1 # Disable haptics on left button solaar config 1 superstrike-tuning_haptics-0 0 # Set left button to maximum haptics solaar config 1 superstrike-tuning_haptics-0 5 # Set right button to medium haptics solaar config 1 superstrike-tuning_haptics-1 3 ``` --- ## Complete Settings Summary | Setting | CLI Name | Type | Range/Values | Button-Specific | |---------|----------|------|--------------|-----------------| | Onboard Profiles | `onboard_profiles` | Choice | `Disabled`, `Profile 1` | No | | Report Rate | `report_rate_extended` | Choice | `8ms` to `125us` | No | | Sensitivity | `dpi_extended` | Complex | 100-32000 DPI | No | | Actuation Point | `superstrike-tuning_actuation-{0,1}` | Range | 1-10 | Yes | | Rapid Trigger | `superstrike-tuning_rapid-trigger-level-{0,1}` | Range | 1-5 | Yes | | Click Haptics | `superstrike-tuning_haptics-{0,1}` | Range | 0-5 | Yes | --- ## Batch Configuration Examples ### Gaming Profile (Fast Response) ```bash #!/bin/bash # Gaming profile: fast actuation, sensitive rapid trigger, medium haptics solaar config 1 onboard_profiles Disabled solaar config 1 report_rate_extended 125us solaar config 1 dpi_extended "{X:800, Y:800, LOD:HIGH}" # Left button - hair trigger solaar config 1 superstrike-tuning_actuation-0 1 solaar config 1 superstrike-tuning_rapid-trigger-level-0 1 solaar config 1 superstrike-tuning_haptics-0 3 # Right button - hair trigger solaar config 1 superstrike-tuning_actuation-1 1 solaar config 1 superstrike-tuning_rapid-trigger-level-1 1 solaar config 1 superstrike-tuning_haptics-1 3 ``` ### Productivity Profile (Comfortable) ```bash #!/bin/bash # Productivity profile: deeper actuation, slower rapid trigger, strong haptics solaar config 1 onboard_profiles Disabled solaar config 1 report_rate_extended 1ms solaar config 1 dpi_extended "{X:1600, Y:1600, LOD:HIGH}" # Left button - comfortable click solaar config 1 superstrike-tuning_actuation-0 7 solaar config 1 superstrike-tuning_rapid-trigger-level-0 4 solaar config 1 superstrike-tuning_haptics-0 5 # Right button - comfortable click solaar config 1 superstrike-tuning_actuation-1 7 solaar config 1 superstrike-tuning_rapid-trigger-level-1 4 solaar config 1 superstrike-tuning_haptics-1 5 ``` ### Silent Profile (No Haptics) ```bash #!/bin/bash # Silent profile: no haptic feedback solaar config 1 superstrike-tuning_haptics-0 0 solaar config 1 superstrike-tuning_haptics-1 0 ``` --- ## Programmatic Usage ### Reading All Settings (JSON-like parsing) ```bash # Get all settings as output solaar config 1 2>/dev/null | grep "^[a-z]" | while read line; do setting=$(echo "$line" | cut -d'=' -f1 | tr -d ' ') value=$(echo "$line" | cut -d'=' -f2 | tr -d ' ') echo "{\"setting\": \"$setting\", \"value\": \"$value\"}" done ``` ### Reading a Single Setting Value ```bash # Extract just the value solaar config 1 superstrike-tuning_actuation-0 2>/dev/null | grep "^superstrike" | cut -d'=' -f2 | tr -d ' ' ``` ### Error Handling ```bash # Check if command succeeded if solaar config 1 superstrike-tuning_actuation-0 5 2>/dev/null; then echo "Setting applied successfully" else echo "Failed to apply setting" fi ``` --- ## Exit Codes | Code | Meaning | |------|---------| | 0 | Success | | 1 | Error (device not found, invalid setting, invalid value) | --- ## Notes 1. **Device Discovery**: Use `solaar show` to list all connected devices and their indices. 2. **Persistence**: Settings are saved to `~/.config/solaar/config.yaml` and automatically reapplied when the device reconnects. 3. **Onboard Profiles**: When `onboard_profiles` is set to `Profile 1`, some settings (DPI, report rate) are controlled by the device's onboard memory and cannot be changed via Solaar. 4. **HITS Settings**: The actuation, rapid trigger, and haptics settings are stored in the device and persist across reconnections, regardless of the onboard profile setting. 5. **Button Index**: `0` = Left button, `1` = Right button. Solaar-1.1.20/docs/README.text000066400000000000000000000004651522022367600156210ustar00rootroot00000000000000# Documentation Readme This project's documentation is hosted using GitHub pages, which serves static pages using Jekyll. [Please refer to the official documentation for instructions for how to build the site locally.](https://help.github.com/articles/setting-up-your-github-pages-site-locally-with-jekyll/) Solaar-1.1.20/docs/capabilities.md000066400000000000000000000465311522022367600167350ustar00rootroot00000000000000--- title: Solaar Capabilities layout: page --- # Solaar Capabilities [**Solaar**][solaar] reports on and controls [Logitech][logitech] devices (keyboards, mice, and trackballs) that connect to your computer via a Logitech USB receiver (a very small piece of hardware that plugs into one of your USB ports). Solaar is designed to detect all connected devices, and at the very least display some basic information about them. At this moment, all [Unifying][unifying] receivers are supported (e.g., devices with USB ID `046d:c52b` or `046d:c532`) as are several Lightspeed Receivers and many Nano receivers. Solaar also reports on and controls some Logitech devices that directly connect to your computer using a USB cable or via Bluetooth. Not all such devices supported in Solaar as information needs to be added to Solaar for each device type that directly connects. ## HID++ and Centurion The devices that Solaar handles use Logitech's HID++ and Centurion protocols. HID++ is a Logitech-proprietary protocol that extends the standard HID protocol for interfacing with receivers, keyboards, mice, and so on. It allows Logitech receivers to communicate with multiple devices and modify some features of the device. As the HID++ protocol is proprietary, many aspects of it are unknown. Some information about HID++ has been obtained from Logitech but even that is subject to change and extension. There are several versions of HID++ and many Logitech receivers and devices that utilize it. Different receivers and devices implement different portions of HID++ so even if two devices appear to be the same in both physical appearance and behavior they may work differently underneath. (For example, there are versions of the M510 mouse that use different versions of the HID++ protocol.) Contrariwise, two different devices may appear different physically but actually look the same to software. (For example, some M185 mice look the same to software as some M310 mice.) Centurion is closely related to HID++ and is used by some Logitech headsets. The software identity of a receiver can be determined by its USB product ID (reported by Solaar and also viewable in Linux using `lsusb`). The software identity of a device that connects to a receiver can be determined by its wireless PID as reported by Solaar. The software identity of devices that connect via a USB cable or via bluetooth can be determined by their USB or Bluetooth product ID. ## Pairing and Unpairing Solaar is able to pair and unpair devices with receivers as supported by the device and receiver. For Unifying and Bolt receivers, pairing adds a new paired device, but only if there is an open slot on the receiver. So these receivers need to be able to unpair devices that they have been paired with or else they will not have any open slots for pairing. Some Nano and Lightspeed receivers, like the Nano receiver with USB ID `046d:c534`, can only pair with one keyboard and one mouse and pairing a new device replaces whatever device of that kind was previously paired to the receiver. These receivers cannot unpair. Further, some receivers can pair an unlimited number of times but others can only pair a limited number of times. Bolt receivers add an authentication phase to pairing, where the user has type a passcode or click some buttons to authenticate the device. Only some connections between receivers and devices are possible. It should be possible to connect any device with a Unifying logo on it to any receiver with a Unifying logo on it and any device with a Bolt logo on it to any receiver with a Bolt logo on it. Many receivers without the Unifying or Bolt logo can connect only to the model of devices they were bought with and many devices without the Unifying or Bolt logo can only connect to a receiver that matches the one they were bought with. ## Device Settings Solaar can display quite a few changeable settings of receivers and devices. For a list of features and their support see [the features page](features.md). Solaar does not do much beyond using the protocols to change the behavior of receivers and devices via changing their settings. In particular, Solaar cannot change how the operating system turns the keycodes that a keyboard produces into characters that are sent to programs. That is the province of HID device drivers and other software (such as X11). Settings can only be changed in the Solaar GUI when they are unlocked. To unlock a setting click on the icon at the right-hand edge of the setting until an unlocked lock appears (with tooltop "Changes allowed"). Solaar keeps track of most of the changeable settings of a device. Devices forget most changed settings when the device is turned off or goes into a power-saving mode. Exceptions include the setting to change the host the device is connected to, the setting to persistently change what a key or button does, and, for some devices, the fn-swap setting. When Solaar starts, it restores on-line devices to their previously-known state except for host connection and persistent key and button changes and while running Solaar restores devices to their previously-known state when the device itself comes on line. Setting information is stored in the file `~/.config/solaar/config.yaml`. Updating of a setting can be turned off in the Solaar GUI by clicking on the icon at the right-hand edge of the setting until a red icon appears (with tooltip "Ignore this setting"). Solaar keeps track of settings independently on each computer. As a result if a device is switched between different computers Solaar may apply different settings for it on the different computers. Querying a device for its current state can require quite a few interactions. These interactions can temporarily slow down the device, so Solaar tries to internally cache information about devices while it is running. If the device state is changed by some other means, even sometimes by another invocation of Solaar, this cached information may become incorrect. Currently there is no way to force an update of the cached information besides restarting Solaar. Logitech receivers and devices have firmware in them. Some firmware can be updated using Logitech software in Windows. For example, there are security issues with some Logitech receivers and devices and Logitech has firmware updates to alleviate these problems. Some Logitech firmware can also be updated in Linux using `fwupdmgr`. WARNING: Updating firmware can cause a piece of hardware to become permanently non-functional if something goes wrong with the update or the update installs the wrong firmware. ## Other Solaar Capabilities Solaar has a few capabilities that go beyond simply changing device settings. ### Rule-based Processing of HID++ Notifications Solaar can process HID++ Notifications from devices to, for example, change the speed of some thumb wheels. These notifications are only sent for actions that are set in Solaar to their HID++ setting (also known as diverted). For more information on this capability of Solaar see [the rules page](https://pwr-solaar.github.io/Solaar/rules). Users can edit rules using a GUI by clicking on the `Rule Editor` button in the Solaar main window. ### Sliding DPI A few mice (such as the MX Vertical) have a button that is supposed to be used to change the sensitivity (DPI) of the mouse by pressing the button and moving the mouse left and right. Other mice (such as the MX Master 3) don't have a button specific for this purpose but have buttons that can be used for it. The `Key/Button Diversion` setting can assign buttons to adjust sensitivity by setting the value for the button to `Sliding DPI`. This capability is only present if the device supports changing the DPI in this way. Pressing a button when it is set to `Sliding DPI` causes the mouse pointer to stop moving. When the button is released a new Sensitivity (DPI) value is applied to the mouse, depending on how far right or left the mouse is moved. If the mouse is moved only a little bit the previous value that was set is applied to the mouse. Notifications from Solaar are displayed showing the setting that will be applied. ### Mouse Gestures Some mice (such as the MX Master 3) have a button that is supposed to be used to create up/down/left/right mouse gestures. Other mice (such as the MX Vertical) don't have a button specific for this purpose but have buttons that can be used for it. The `Key/Button Diversion` setting can assign buttons to initiate mouse gestures by setting the value for the button to `Mouse Gestures`. This capability is only present if the device can support it. Pressing a button when it is set to `Mouse Gestures` causes the mouse pointer to stop moving. When the button is released a `MOUSE_GESTURE` notification with the mouse movements and diverted key presses is sent to the Solaar rule system so that rules can detect these notifications. For more information on Mouse Gestures rule conditions see [the rules page](https://pwr-solaar.github.io/Solaar/rules). ### Keyboard Key Names and Locations Solaar uses the standard Logitech names for keyboard keys. Some Logitech keyboards have different icons on some of their keys and have different functionality than suggested by these names. Solaar uses the standard US keyboard layout. This currently only matters for the `Per-key Lighting` setting. Users who want to have the key names for this setting reflect the keyboard layout that they use can create and edit `~/.config/solaar/keys.yaml` which contains a YAML dictionary of key names and locations. For example, switching the `Y` and `Z` keys can be done as: Z: 25 Y: 26 This is an experimental feature and may be modified or even eliminated. ### HITS Tuning (Hall-Effect Inductive Trigger Switch) Some gaming mice (such as the PRO X 2 Superstrike) feature hall-effect magnetic switches on their primary buttons instead of traditional mechanical switches. These switches expose tunable parameters via the `SUPERSTRIKE_TUNING` HID++ feature (`0x1B0C`). Solaar supports three per-button settings for each primary button (left = 0, right = 1): - **Actuation Point** (`superstrike-tuning_actuation-{0,1}`): How deep the button must be pressed to register a click. Range 1–10, where 1 is the shallowest (hair trigger) and 10 is the deepest (full press). Default is 5. - **Rapid Trigger Level** (`superstrike-tuning_rapid-trigger-level-{0,1}`): Sensitivity of rapid re-actuation after partial release. Range 1–5, where 1 is the most sensitive and 5 is the least. This cannot be fully disabled. - **Click Haptics** (`superstrike-tuning_haptics-{0,1}`): Intensity of haptic feedback on click. Range 0–5, where 0 disables haptics and 5 is maximum intensity. These settings are written directly to the device and persist across reconnections regardless of the onboard profile state. ### Extended DPI Some gaming mice (such as the PRO X 2 Superstrike) support the `EXTENDED_ADJUSTABLE_DPI` feature (`0x2202`) which allows independent X and Y axis DPI configuration as well as lift-off distance (LOD) control. This is exposed via the `dpi_extended` setting: ```bash solaar config dpi_extended "{X:1600, Y:1600, LOD:HIGH}" ``` LOD values are `LOW` and `HIGH`. DPI range depends on the device sensor (up to 32000 DPI on the PRO X 2 Superstrike). ### Haptic Feedback Some devices, such as the MX Master 4 have haptic feeback. The Solaar CLI can be used to 'play' wave forms, for example ``` solaar config 'mx master 4' haptic-play 'HAPPY ALERT' ``` Solaar rules can also do this using their `Set` action. ### Extended Report Rate Some gaming mice (such as the PRO X 2 Superstrike) support the `EXTENDED_ADJUSTABLE_REPORT_RATE` feature (`0x8061`) which enables sub-millisecond polling rates beyond the standard 1 ms (1000 Hz). This is exposed via the `report_rate_extended` setting: | Value | Polling Rate | |---------|-------------| | `8ms` | 125 Hz | | `4ms` | 250 Hz | | `2ms` | 500 Hz | | `1ms` | 1000 Hz | | `500us` | 2000 Hz | | `250us` | 4000 Hz | | `125us` | 8000 Hz | ### Onboard Profiles Some mice store one or more profiles onboard. An onboard profile controls certain aspects of the behavior of the mouse, including the rate at which the mouse reports movement, the resolution of the the movement reports, what the mouse buttons do, LED effects, and maybe more. Solaar has a setting that switches between profiles or disables all profiles. When an onboard profile is active it may not be possible to change the aspects that the profile controls. This is often seen for the Report Rate setting. For some devices it is possible to make changes to the Sensitivity setting and to LED settings. These changes are likely to only be temporary and may be overridden when the device reconnects or when Solaar is restarted. This is in keeping with the intent of Onboard Profiles as controlling the device behavior. To make the changes to these settings permanent it is necessary to disable onboard profiles. Alternatively, multiple profiles can be set up as described below and these settings controlled by switching between the profiles. Solaar can dump the entire set of profiles into a YAML file and can load the entire set of profiles from a file. Users can edit the file to effect changes to the profiles. A profile file has some bookkeeping information, including profile version and the name of the device, and a sequence of profiles. Each profile has the following fields: - enabled: Whether the profile is enabled. - sector: Where the profile is stored in device memory. Sectors greater than 0xFF are in ROM and cannot be written (use the low byte as the sector to write to Flash). - name: A memonic name for the profile. - report_rate: A report rate in milliseconds from 1 to 8. - resolutions: A sequence of five sensor resolutions in DPI. - resolution_default_index: The index of the default sensor resolution (0 to 4). - resolution_shift_index: The index of the sensor resolution used when the DPI Shift button is pressed (0 to 4). - buttons: The action for each button on the mouse in normal mode. - gbuttons: The action for each button on the mouse in G-Shift mode. - angle_snap: Enable angle snapping for devices. - red, blue, green: Color indicator for the profile. - lighting: Lighting information for logo and side LEDs in normal mode, then for power saving mode. - ps_timeout: Delay in ms to go into power saving mode. - po_timeout: Delay in ms to go from power saving mode to fully off. - power_mode: Unknown purpose. - write count: Unknown purpose. Missing or unused parts of a profile are often a sequence of 0xFF bytes. Button actions can either perform a function (behavior: 9) or send a button click or key press (behaviour: 8). Functions are: - 0: No Action - do nothing - 1: Tilt Left - 2: Tilt Right - 3: Next DPI - change device resolution to the next DPI - 4: Previous DPI - change device resolution to the previous DPI - 5: Cycle DPI - change device resolution to the next DPI considered as a cycle - 6: Default_DPI - change device resolution to the default resolution - 7: Shift_DPI - change device resolution to the shift resolution - 8: Next Profile - change to the next enabled profile - 9: Previous Profile - change to the previous enabled profile - 10: Cycle Profile - change to the next enabled profile considered as a cycle - 11: G-Shift - change all buttons to their G-Shift state - 12: Battery Status - show battery status on the device LEDs - 13: Profile Select - select the n'th enabled profile - 14: Mode Switch - 15: Host Button - switch between hosts (unverified) - 16: Scroll Down - 17: Scroll Up Some devices might not be able to perform all functions. Buttons can send (type): - 0: Don't send anything. - 1: A button click (value) as a 16-bit bitmap, i.e., 1 is left click, 2 is right, 4 is middle, etc. - 2: An 8-bit USB HID keycode (value) plus an 8-bit modifier bitmap (modifiers), i.e., 0 for no modifiers, 1 for control, 2 for shift, etc. - 3: A 16-bit HID Consumer keycode (value). See USB_HID_KEYCODES and HID_CONSUMERCODES in lib/logitech_receiver/special_keys.py for values to use for keycodes. Buttons can also execute macros but Solaar does not provide any support for macros. Lighting information is a sequence of lighting effects, with the first usually for the logo LEDs and the second usually for the side LEDs. The fields possible in an effect are: - ID: The kind of effect: - color: A color parameter for the effect as a 24-bit RGB value. - intensity: How intense to make the color (1%-100%), 0 for the default (usually 100%). - speed: How fast to pulse in ms (one byte). - ramp: How to change to the color (0=default, 1=ramp up/down, 2=no ramping). - period: How fast to perform the effect in ms (two bytes). - form: The form of the breathe effect. - bytes: The raw bytes of other effects. The possible effects and the fields the use are: - 0x0: Disable - No fields. - 0x1: Fixed color - color, whether to ramp. - 0x2: Pulse a color - color, speed. - 0x3 Cycle through the spectrum - period, intensity, form. - 0x8; A boot effect - No fields. - 0x9: A demo effect - NO fields. - 0xa: breathe a color (like pulse) - color, period. - 0xb: Ripple - color, period. - null: An unknown effect. Only effects supported by the device can be used. To set up profiles, first run `solaar profiles `, which will output a YAML dump of the profiles on the device. Then store the YAML dump into a file and edit the file to make changes. Finally run `solaar profiles ` to load the profiles back onto the device. Profiles are stored in flash memory and persist when the device is inactive or turned off. When loading profiles Solaar is careful to only write the flash memory sectors that need to be changed. Solaar also checks for correct profile version and device name before loading a profile into a device. Keep a copy of the initial dump of profiles so that it can be loaded back to the device if problems are encountered with the edited profiles. The safest changes are to take an unused or unenabled profile sector and create a new profile in it, likely mostly copying parts of another profile. ## System Tray Solaar's GUI normally uses an icon in the system tray. This allows users to close Solaar and reopen from the tray. This aspect of Solaar depends on having an active system tray which may require some special setup when using Gnome, particularly under Wayland. If you are running Gnome, you most likely need the `gnome-shell-extension-appindicator` package installed. In Fedora, this can be done by running ``` sudo dnf install gnome-shell-extension-appindicator ``` The likely command in Ubuntu and related distributions is ``` sudo apt install gnome-shell-extension-appindicator ``` You may have to log out and log in again before the system tray shows up. ## Battery Icons For many devices, Solaar shows the approximate battery level via icons that show up in both the main window and the system tray. In previous versions several heuristics determined which icon names to use for this purpose, but as more and more battery icon schemes have been developed this has become impossible to do well. Solaar now uses the eleven standard battery icon names `battery-{full,good,low,critical,empty}[-charging]` and `battery-missing`. Solaar will use the symbolic versions of these icons if started with the option `--battery-icons=symbolic`. Because of external bugs, these symbolic icons may be nearly invisible in dark themes. [solaar]: https://github.com/pwr-Solaar/Solaar [logitech]: https://www.logitech.com [unifying]: https://en.wikipedia.org/wiki/Logitech_Unifying_receiver Solaar-1.1.20/docs/debian.md000066400000000000000000000003731522022367600155200ustar00rootroot00000000000000--- title: Debian Repository layout: page --- # Debian repository Solaar is now part of the [official Debian repository](https://packages.debian.org/solaar). To install it on your Debian machine, use the following command: `sudo apt install solaar` Solaar-1.1.20/docs/devices.md000066400000000000000000000212701522022367600157170ustar00rootroot00000000000000--- title: Supported Devices layout: page --- # Supported receivers and devices Solaar only supports Logitech receivers and devices that use the Logitech proprietary HID++ and Centurion protocols. Solaar supports most Logitech Nano, Unifying, and Bolt receivers. Solaar supports some Lightspeed receivers. See the receiver table below for the list of currently supported receivers. Solaar supports all Logitech devices (keyboards, mice, trackballs, touchpads, and headsets) that can connect to supported receivers. Solaar supports all Logitech devices that can connect via a USB cable or via Bluetooth, as long as the device uses the HID++ or Centurion protocol. The best way to determine whether Solaar supports a device is to run Solaar while the device is connected. If the device is supported, it will show up in the Solaar main window. The directory contains edited output of `solaar show` on many devices and can be used to see what Solaar can do with the device. ## Supporting old devices Some old Logitech devices use an old version of HID++. For Solaar to support these devices well, Solaar needs some information about them. If you have an old Logitech device that shows up in Solaar but has no settings and you feel that Solaar should be able to do more with the device you can open an enhancement request for Solaar to better support the device. ## Adding new receivers Adding a new receiver requires knowing whether the receiver is a regular Unifying receiver, a Nano receiver, a Bolt receiver, or a Lightspeed receiver. This can generally be found using `lsusb`. To add a new receiver to the Solaar code add a line to `../lib/logitech_receiver/base_usb.py` defining the receiver as one of these. If the receiver has an unusual number of pairing slots, then this also needs to be specified. Then add the receiver to the tuple of receivers (ALL). ### Supported Receivers | USB ID | Kind | Max Paired Devices | ------------|------------|--------------------| | 046d:c517 | 27MHz | 4 | | 046d:c518 | Nano | 1 | | 046d:c51a | Nano | 1 | | 046d:c51b | Nano | 1 | | 046d:c521 | Nano | 1 | | 046d:c525 | Nano | 1 | | 046d:c526 | Nano | 1 | | 046d:c52b | Unifying | 6 | | 046d:c52e | Nano | 1 | | 046d:c52f | Nano | 1 | | 046d:c531 | Nano | 1 | | 046d:c532 | Unifying | 6 | | 046d:c534 | Nano | 2 | | 046d:c537 | Nano | 2 | | 046d:c539 | Lightspeed | 1 | | 046d:c53a | Lightspeed | 1 | | 046d:c53d | Lightspeed | 1 | | 046d:c53f | Lightspeed | 1 | | 046d:c541 | Lightspeed | 1 | | 046d:c542 | Nano | 1 | | 046d:c545 | Lightspeed | 1 | | 046d:c547 | Lightspeed | 1 | | 046d:c548 | Bolt | 6 | | 17ef:6042 | Nano | 1 | Some Nano receivers are only partly supported as they do not implement the full HID++ 1.0 protocol. Some Nano receivers are not supported as they do not implement the HID++ protocol at all. Receivers with USB ID 046d:c542 fall into this category. The receiver with USB ID 046d:c517 is an old 27 MHz receiver, supporting only a subset of the HID++ 1.0 protocol. Only hardware pairing is supported. ## Supported Devices (Historical Interest Only) The device tables below provide a list of some of the devices that Solaar supports, giving their product name, WPID product number, and HID++ protocol information. The tables concentrate on older devices that have explicit support information in Solaar and are not being updated for new devices that are supported by Solaar. Note that Logitech has the annoying habit of reusing Device names (e.g., M185) so what is important for support is the USB WPID or Bluetooth model ID. ### Keyboards (Unifying) | Device | WPID | HID++ | |------------------|------|-------| | K230 | 400D | 2.0 | | K270 | 4003 | 2.0 | | K340 | 2007 | 1.0 | | K350 | 200A | 1.0 | | K360 | 4004 | 2.0 | | K375s | 4071 | | | K400 Touch | 400E | 2.0 | | K400 Touch | 4024 | 2.0 | | K400 Plus | 404D | 2.0 | | K520 | 2011 | 1.0 | | K600 TV | 4078 | 2.0 | | K750 Solar | 4002 | 2.0 | | K780 | 405B | 2.0 | | K800 Illuminated | 2010 | 1.0 | | K800 (new ver) | 406E | 2.0 | | K830 Illuminated | 4032 | 2.0 | | MX Keys | 408A | 2.0 | | N545 | 2006 | | | TK820 | | 2.0 | | Craft | 4066 | 2.0 | ### Keyboards (Lightspeed) | Device | WPID | HID++ | |------------------|------|-------| | G915 TKL | 408E | 4.2 | ### Mice (Unifying) | Device | WPID | HID++ | |------------------|------|-------| | M150 | 4022 | 2.0 | | M185 | 4055 | 2.0 | | M310 | 4031 | 2.0 | | M310 | 4055 | 2.0 | | M317 | | | | M325 | 400A | 2.0 | | M330 | | 2.0 | | M345 | 4017 | 2.0 | | M350 | 101C | 1.0 | | M350 | 4080 | 2.0 | | M505 | 101D | 1.0 | | M510 | 1025 | 1.0 | | M510 | 4051 | 2.0 | | M515 Couch | 4007 | 2.0 | | M525 | 4013 | 2.0 | | M560 | | 2.0 | | M585 | 406B | 2.0 | | M590 | 406B | 2.0 | | M600 Touch | 401A | 2.0 | | M705 Marathon | 101B | 1.0 | | M705 Marathon | 406D | 2.0 | | M720 Triathlon | 405E | 2.0 | | T400 Zone Touch | | 2.0 | | T620 Touch | | 2.0 | | Performance MX | 101A | 1.0 | | Anywhere MX | 1017 | 1.0 | | Anywhere MX 2 | 404A | 2.0 | | MX Master | 4041 | 2.0 | | MX Master 2S | 4069 | 2.0 | | Cube | | 2.0 | | MX Vertical | 407B | 2.0 | ### Mice (Nano) | Device | WPID | HID++ | |------------------|------|-------| | G7 | 1002 | 1.0 | | G700 | 1023 | 1.0 | | G700s | 102A | 1.0 | | V450 Nano | 1011 | 1.0 | | V550 Nano | 1013 | 1.0 | | VX Nano | 100B | 1.0 | | VX Nano | 100F | 1.0 | | M175 | 4008 | | | M185 (old) | 4038 | 2.0 | | M185 (new) | 4054 | 2.0 | | M187 | 4019 | 2.0 | | M215 | 1020 | 1.0 | | M235 | 4055 | 2.0 | | M305 | 101F | 1.0 | | M310 | 1024 | 1.0 | | M315 | | | | M330 | | ?.? | | MX 1100 | 1014 | 1.0 | * (old): M185 with P/N: 810-003496 * (new): M185 with P/N: 810-005238 or 810-005232 ### Mice (Mini) | Device | WPID | HID++ | |-------------------|------|-------| | MX610 | 1001 | 1.0 | | MX610 left handed | 1004 | 1.0 | | MX620 | 100A | 1.0 | | MX620 | 1016 | 1.0 | | V400 | 1003 | 1.0 | | V450 | 1005 | 1.0 | | VX Revolution | 1006 | 1.0 | | VX Revolution | 100D | 1.0 | | MX Air | 1007 | 1.0 | | MX Air | 100E | 1.0 | | MX Revolution | 1008 | 1.0 | | MX Revolution | 100C | 1.0 | ### Mice (Lightspeed) | Device | WPID | HID++ | |------------------------------|------|-------| | G604 Wireless Gaming Mouse | 4085 | 4.2 | | PRO X Superlight Wireless | 4093 | 4.2 | | PRO X 2 Superstrike | 40BD | 4.2 | ### Trackballs (Unifying) | Device | WPID | HID++ | |-------------------|------|-------| | M570 Trackball | | 1.0 | | MX Ergo Trackball | | 2.0 | ### Touchpads (Unifying) | Device | WPID | HID++ | |------------------|------|-------| | Wireless Touch | 4011 | 2.0 | | T650 Touchpad | 4101 | 2.0 | ### Mice and Keyboards sold as combos | Device | WPID | HID++ | |------------------|------|-------| | MK220 | | 2.0 | | MK270 | 4023 | 2.0 | | MK320 | 200F | | | MK330 | | | | MK345 | 4023 | 2.0 | | MK520 | | M2/K1 | | MK550 | | | | MK700 | 2008 | 1.0 | | MK710 | | 1.0 | | EX100 keyboard | 0065 | 1.0 | | EX100 mouse | 003f | 1.0 | * The EX100 is an old, pre-Unifying receiver and device set, supporting only some HID++ 1.0 features Solaar-1.1.20/docs/devices/000077500000000000000000000000001522022367600153735ustar00rootroot00000000000000Solaar-1.1.20/docs/devices/00README.txt000066400000000000000000000046141522022367600172360ustar00rootroot00000000000000Files in this directory are edited output from `solaar show` providing information about devices and receivers that Solaar supports. This directory does not contain information about all devices and receivers that Solaar supports. Information is generally only added when provided in a Solaar issue. Directions for constructing the files are given below. The files Unifying Receiver C52B.txt Craft Advanced Keyboard 4066.txt Craft Advanced Keyboard B350.txt MX Master 3 Wireless Mouse 4082.txt MX Master 3 Wireless Mouse B023.txt are good examples of following the directions below. File Naming Logitech device names are often reused so the names of files can't just be the device name. File names start with the name of the device or receiver as given in the first line of of output for the device. The file name continues with a space and the WPID, if the device is connected to a receiver, or the second half of the USB ID, if the device is connected via USB or Bluetooth. The WPID or USB ID are in upper case. As devices can behave differently when connected via a receiver or USB or Bluetooth there should be a file for each possible connection method. Files that do not follow this naming convention are retained for historical purposes. File Contents Each file should contain the output of `solaar show NAME` where NAME is enough of the full name of a device or receiver to identify it. The output of `solaar show` will provide information on all connnected devices and receivers including their names. The output of `solaar show NAME` can be edited to remove serial numbers and variable information such as the current values of settings. Passing the style requirements for Solaar documentation may require removing trailing white space on lines. For older devices probes of the device registers should be included but for newer devices this is not necessary. Unifying receivers can pair with any device that has the Unifying logo. Bolt receivers can pair with any device that has the Bolt logo. Nano and Lightspeed receivers can only pair with certain devices, so the end of their files should state the devices that they have been seen to be paired with or are part of. Updating Files Newer versions of Solaar add support for more settings so it is useful to provide updated versions of these files if there is information from the current version of `solaar show NAME` that is not in the existing file. Solaar-1.1.20/docs/devices/Bluetooth Multi-Device Keyboard K380 B342.txt000066400000000000000000000137141522022367600251010ustar00rootroot00000000000000Solaar version 1.1.4 1: Bluetooth Multi-Device Keyboard K380 Device path : /dev/hidraw5 USB id : 046d:B342 Codename : Keyboard K380 Kind : ? Protocol : HID++ 4.5 Serial number: Model ID: B34200000000 Unit ID: 16000000 Firmware: RBK 42.01.B0017 Hardware: 72 Supports 14 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Firmware RBK 42.01.B0017 B342C18DBFDD Firmware: Hardware 72 Unit ID: 16000000 Model ID: B34200000000 Transport IDs: {'btid': 'B342'} 3: DEVICE NAME {0005} Name: Bluetooth Multi-Device Keyboard K380 Kind: keyboard 4: DEVICE FRIENDLY NAME {0007} Friendly Name: Keyboard K380 5: RESET {0020} 6: BATTERY STATUS {1000} Battery: 20%, discharging, next level 5%. 7: CHANGE HOST {1814} Change Host : 1:Luay-A 8: HOSTS INFO {1815} Host 0 (paired): Luay-A Host 1 (paired): BCM20703A2 Generic UART UHE App Host 2 (unpaired): 9: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Search:Regular, Multiplatform App Switch:Regular, Multiplatform Home:Regular, Multiplatform Menu:Diverted, Multiplatform Back:Regular, Multiplatform Insert:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular} Key/Button Diversion : {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Search:Regular, Multiplatform App Switch:Regular, Multiplatform Home:Regular, Multiplatform Menu:Diverted, Multiplatform Back:Regular, Multiplatform Insert:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular} 10: unknown:1E00 {1E00} hidden 11: NEW FN INVERSION {40A2} Fn-swap: disabled Fn-swap default: enabled Swap Fx function (saved): False Swap Fx function : False 12: LOCK KEY STATE {4220} 13: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {Caps Lock:False, Scroll Lock:False, Insert:True, Win:False} Disable keys : {Caps Lock:False, Scroll Lock:False, Insert:True, Win:False} Has 16 reprogrammable keys: 0: Multiplatform Home , default: MultiPlatform Home => MultiPlatform Home is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty reporting: default 1: Multiplatform App Switch , default: MultiPlatform App Switch => MultiPlatform App Switch is FN, FN sensitive, reprogrammable, divertable, pos:5, group:0, group mask:empty reporting: default 2: Multiplatform Menu , default: MultiPlatform Menu => MultiPlatform Menu is FN, FN sensitive, reprogrammable, divertable, pos:6, group:0, group mask:empty reporting: diverted 3: Multiplatform Back , default: MultiPlatform Back => MultiPlatform Back is FN, FN sensitive, reprogrammable, divertable, pos:7, group:0, group mask:empty reporting: default 4: Previous , default: Previous => Previous is FN, FN sensitive, divertable, pos:8, group:0, group mask:empty reporting: default 5: Play/Pause , default: Play/Pause => Play/Pause is FN, FN sensitive, divertable, pos:9, group:0, group mask:empty reporting: default 6: Next , default: Next => Next is FN, FN sensitive, divertable, pos:10, group:0, group mask:empty reporting: default 7: Mute , default: Mute => Mute is FN, FN sensitive, divertable, pos:11, group:0, group mask:empty reporting: default 8: Volume Down , default: Volume Down => Volume Down is FN, FN sensitive, divertable, pos:12, group:0, group mask:empty reporting: default 9: Volume Up , default: Volume Up => Volume Up is FN, FN sensitive, divertable, pos:0, group:0, group mask:empty reporting: default 10: Multiplatform Insert , default: Switch Language => Switch Language FN sensitive, reprogrammable, divertable, pos:0, group:0, group mask:empty reporting: default 11: Fn Up , default: unknown:0070 => unknown:0070 is FN, divertable, pos:0, group:0, group mask:empty reporting: default 12: Fn Down , default: unknown:006F => unknown:006F is FN, divertable, pos:0, group:0, group mask:empty reporting: default 13: Screen Capture/Print Screen, default: Screen Capture => Screen Capture is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty reporting: default 14: Search , default: Search Files => Search Files is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty reporting: default 15: Multiplatform Lock , default: WindowsLock => WindowsLock is FN, reprogrammable, divertable, pos:0, group:0, group mask:empty reporting: default Battery: 20%, discharging, next level 5%. Solaar-1.1.20/docs/devices/Bolt Receiver C548.txt000066400000000000000000000004371522022367600211710ustar00rootroot00000000000000Solaar version 1.1.4 Bolt Receiver Device path : /dev/hidraw8 USB id : 046d:C548 Serial : 38423638313332394241363434313837 Has 2 paired device(s) out of a maximum of 6. Notifications: wireless, software present (0x000900) Device activity counters: 1=252, 2=135 Solaar-1.1.20/docs/devices/Candy companion chip 405F.txt000066400000000000000000000023371522022367600224460ustar00rootroot00000000000000 7: Candy companion chip Device path : /dev/hidraw11 Codename : Candy Kind : touchpad Protocol : HID++ 4.2 Serial number: 5B2B9A98 Model ID: 405F00000000 Unit ID: 32314707 Firmware: CC 07.00.B0010 Bootloader: BOT 32.00.B0010 Supports 11 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Firmware CC 07.00.B0010 405F Firmware: Bootloader BOT 32.00.B0010 405F Unit ID: 32314707 Model ID: 405F00000000 Transport IDs: {'wpid': '405F'} 3: DEVICE NAME {0005} Name: Candy companion chip Kind: touchpad 4: unknown:18A1 {18A1} internal, hidden 5: unknown:1E00 {1E00} hidden 6: unknown:1EB0 {1EB0} internal, hidden 7: DFUCONTROL SIGNED {00C2} 8: unknown:1801 {1801} internal, hidden 9: DEVICE RESET {1802} internal, hidden 10: unknown:1803 {1803} internal, hidden Battery status unavailable. Part of the G PowerPlay Wireless Mouse Pad. Solaar-1.1.20/docs/devices/Couch Mouse M515 4007.txt000066400000000000000000000027461522022367600212420ustar00rootroot000000000000001: Couch Mouse M515 Codename : M515 Kind : mouse Wireless PID : 4007 Protocol : HID++ 2.0 Polling rate : 8 ms Serial number: BED587E9 Firmware: RQM 24.00.B0023 Bootloader: DFU 00.02.B0010 The power switch is located on the base. Supports 16 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: DFUCONTROL {00C0} 5: BATTERY STATUS {1000} 6: unknown:1A30 {1A30} hidden 7: REPROG CONTROLS {1B00} 8: WIRELESS DEVICE STATUS {1D4B} 9: unknown:1DF3 {1DF3} hidden 10: VERTICAL SCROLLING {2100} 11: HI RES SCROLLING {2120} 12: MOUSE POINTER {2200} 13: unknown:1F02 {1F02} hidden 14: unknown:1F03 {1F03} hidden 15: unknown:1E80 {1E80} hidden Has 5 reprogrammable keys: 0: LEFT CLICK => LeftClick mse, reprogrammable 1: RIGHT CLICK => RightClick mse, reprogrammable 2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable 3: BACK AS BUTTON 4 => BackEx mse, reprogrammable 4: FORWARD AS BUTTON 5 => BrowserForwardEx mse, reprogrammable Battery: 65%, discharging, Solaar-1.1.20/docs/devices/Craft Advanced Keyboard 4066.txt000066400000000000000000000301221522022367600227600ustar00rootroot00000000000000Solaar version 1.1.4 2: Craft Advanced Keyboard Device path : /dev/hidraw4 WPID : 4066 Codename : Craft Kind : keyboard Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 112C46EA Model ID: B35040660000 Unit ID: 43DAF041 Bootloader: BOT 41.01.B0015 Firmware: MPK 07.01.B0015 Other: Other: The power switch is located on the edge of top right corner. Supports 38 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 41.01.B0015 0000B6A2C54601 Firmware: Firmware MPK 07.01.B0015 4066B6A2C54601 Firmware: Other Firmware: Other Unit ID: 43DAF041 Model ID: B35040660000 Transport IDs: {'btleid': 'B350', 'wpid': '4066'} 3: DEVICE NAME {0005} Name: Craft Advanced Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: Keyboard Craft 7: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 8: CHANGE HOST {1814} Change Host : 1:idefix 9: HOSTS INFO {1815} Host 0 (paired): idefix Host 1 (paired): idefix Host 2 (paired): Galaxy Tab S6 10: BACKLIGHT2 {1982} Backlight (saved): True Backlight : True 11: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Calculator:Regular, Show Desktop:Diverted, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Diverted, Host Switch Channel 3:Diverted, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular} Key/Button Diversion : {Calculator:Regular, Show Desktop:Diverted, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Diverted, Host Switch Channel 3:Diverted, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular} 12: PERSISTENT REMAPPABLE ACTION {1C00} Persistent Key/Button Mapping : {Calculator:AL Calculator, Show Desktop:Meta+D, Lock PC:Meta+L, Screen Capture/Print Screen:SYSRQ, Brightness Down:Brightness Down, Brightness Up:Brightness Up, Mission Control/Task View:Meta+TAB, Dashboard Launchpad/Action Center:Meta+A, Backlight Down:No Output (only as default), Backlight Up:No Output (only as default), Previous Fn:Scan Previous Track, Play/Pause Fn:Play/Pause, Next Fn:Scan Next Track, Mute Fn:Mute, Volume Down Fn:No Output, Volume Up Fn:Volume Up, App Contextual Menu/Right Click:COMPOSE} 13: K375S FN INVERSION {40A3} Swap Fx function (saved): True Swap Fx function : True 14: ENCRYPTION {4100} 15: LOCK KEY STATE {4220} 16: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 17: MULTIPLATFORM {4531} Set OS (saved): Windows Set OS : Windows 18: CROWN {4600} Crown smooth scroll (saved): False Crown smooth scroll : False Divert crown events (saved): True Divert crown events : True 19: DFUCONTROL SIGNED {00C2} 20: unknown:1803 {1803} internal, hidden 21: CONFIG DEVICE PROPS {1806} internal, hidden 22: unknown:1813 {1813} internal, hidden 23: OOBSTATE {1805} internal, hidden 24: unknown:1830 {1830} internal, hidden 25: unknown:1890 {1890} internal, hidden 26: unknown:1891 {1891} internal, hidden 27: unknown:1801 {1801} internal, hidden 28: unknown:18A1 {18A1} internal, hidden 29: unknown:9280 {9280} internal, hidden 30: unknown:1A20 {1A20} internal, hidden 31: unknown:1DF3 {1DF3} internal, hidden 32: unknown:1E00 {1E00} hidden 33: unknown:1EB0 {1EB0} internal, hidden 34: unknown:1861 {1861} internal, hidden 35: unknown:18B0 {18B0} internal, hidden 36: unknown:92C0 {92C0} internal, hidden 37: unknown:9203 {9203} internal, hidden Has 24 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: diverted 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: diverted 3: Brightness Down , default: Brightness Down => Brightness Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 4: Brightness Up , default: Brightness Up => Brightness Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default 5: Mission Control/Task View , default: Mission Control/Task View => Mission Control/Task View is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty reporting: default 6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty reporting: default 7: Show Desktop , default: Show Desktop => Show Desktop is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty reporting: diverted 8: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty reporting: default 9: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, group mask:empty reporting: default 10: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, group mask:empty reporting: default 11: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, group mask:empty reporting: default 12: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, group mask:empty reporting: default 13: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty reporting: default 14: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty reporting: default 15: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 16: Calculator , default: Calculator => Calculator nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 17: Screen Capture/Print Screen, default: Screen Capture => Screen Capture nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 19: Lock PC , default: WindowsLock => WindowsLock nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 20: Left Arrow , default: Keyboard Left Arrow => Keyboard Left Arrow nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 21: Right Arrow , default: Keyboard Right Arrow => Keyboard Right Arrow nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 22: F Lock , default: Do Nothing One => Do Nothing One is FN, pos:0, group:0, group mask:empty reporting: default 23: FN Key , default: Do Nothing One => Do Nothing One nonstandard, pos:0, group:0, group mask:empty reporting: default Has 17 persistent remappable keys: 0: Brightness Down => Consumer: Brightness Down (remapped) 1: Brightness Up => Consumer: Brightness Up (remapped) 2: Mission Control/Task View => Key: Meta+TAB 3: Dashboard Launchpad/Action Center => Key: Meta+A 4: Show Desktop => Key: Meta+D 5: Backlight Down => None 6: Backlight Up => None 7: Previous Fn => Consumer: Scan Previous Track 8: Play/Pause Fn => Consumer: Play/Pause 9: Next Fn => Consumer: Scan Next Track 10: Mute Fn => Consumer: Mute 11: Volume Down Fn => Key: No Output (remapped) 12: Volume Up Fn => Consumer: Volume Up 13: Calculator => Consumer: AL Calculator 14: Screen Capture/Print Screen => Key: SYSRQ 15: App Contextual Menu/Right Click => Key: COMPOSE 16: Lock PC => Key: Meta+L Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Craft Advanced Keyboard B350.txt000066400000000000000000000272241522022367600230030ustar00rootroot00000000000000Solaar version 1.1.4 1: Craft Advanced Keyboard Device path : /dev/hidraw5 USB id : 046d:B350 Codename : Craft Kind : keyboard Protocol : HID++ 4.5 Serial number: Model ID: B35040660000 Unit ID: 43DAF041 Bootloader: BOT 41.01.B0015 Firmware: MPK 07.01.B0015 Other: Other: Supports 33 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 41.01.B0015 0000B6A2C54601 Firmware: Firmware MPK 07.01.B0015 B350B6A2C54601 Firmware: Other Firmware: Other Unit ID: 43DAF041 Model ID: B35040660000 Transport IDs: {'btleid': 'B350', 'wpid': '4066'} 3: DEVICE NAME {0005} Name: Craft Advanced Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: Keyboard Craft 7: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 8: CHANGE HOST {1814} Change Host : 2:idefix 9: HOSTS INFO {1815} Host 0 (paired): idefix Host 1 (paired): idefix Host 2 (paired): Galaxy Tab S6 10: BACKLIGHT2 {1982} Backlight (saved): True Backlight : True 11: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Calculator:Regular, Show Desktop:Diverted, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Diverted, Host Switch Channel 3:Diverted, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular} Key/Button Diversion : {Calculator:Regular, Show Desktop:Diverted, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Diverted, Host Switch Channel 3:Diverted, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular} 12: PERSISTENT REMAPPABLE ACTION {1C00} Persistent Key/Button Mapping : {Calculator:AL Calculator, Show Desktop:Meta+D, Lock PC:Meta+L, Screen Capture/Print Screen:SYSRQ, Brightness Down:No Output (only as default), Brightness Up:No Output (only as default), Mission Control/Task View:Meta+TAB, Dashboard Launchpad/Action Center:Meta+A, Backlight Down:No Output (only as default), Backlight Up:No Output (only as default), Previous Fn:Scan Previous Track, Play/Pause Fn:Play/Pause, Next Fn:Scan Next Track, Mute Fn:Mute, Volume Down Fn:Volume Down, Volume Up Fn:Volume Up, App Contextual Menu/Right Click:COMPOSE} 13: K375S FN INVERSION {40A3} Swap Fx function (saved): True Swap Fx function : True 14: ENCRYPTION {4100} 15: LOCK KEY STATE {4220} 16: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 17: MULTIPLATFORM {4531} Set OS (saved): Windows Set OS : Windows 18: CROWN {4600} Crown smooth scroll (saved): False Crown smooth scroll : False Divert crown events (saved): True Divert crown events : True 19: DFUCONTROL SIGNED {00C2} 20: unknown:1803 {1803} internal, hidden 21: unknown:1813 {1813} internal, hidden 22: unknown:1830 {1830} internal, hidden 23: unknown:1801 {1801} internal, hidden 24: unknown:18A1 {18A1} internal, hidden 25: unknown:1A20 {1A20} internal, hidden 26: unknown:1DF3 {1DF3} internal, hidden 27: unknown:1E00 {1E00} hidden 28: unknown:1EB0 {1EB0} internal, hidden 29: unknown:1861 {1861} internal, hidden 30: unknown:18B0 {18B0} internal, hidden 31: unknown:92C0 {92C0} internal, hidden 32: unknown:9203 {9203} internal, hidden Has 24 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: diverted 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: diverted 3: Brightness Down , default: Brightness Down => Brightness Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 4: Brightness Up , default: Brightness Up => Brightness Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default 5: Mission Control/Task View , default: Mission Control/Task View => Mission Control/Task View is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty reporting: default 6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty reporting: default 7: Show Desktop , default: Show Desktop => Show Desktop is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty reporting: diverted 8: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty reporting: default 9: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, group mask:empty reporting: default 10: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, group mask:empty reporting: default 11: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, group mask:empty reporting: default 12: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, group mask:empty reporting: default 13: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty reporting: default 14: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty reporting: default 15: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 16: Calculator , default: Calculator => Calculator nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 17: Screen Capture/Print Screen, default: Screen Capture => Screen Capture nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 19: Lock PC , default: WindowsLock => WindowsLock nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 20: Left Arrow , default: Keyboard Left Arrow => Keyboard Left Arrow nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 21: Right Arrow , default: Keyboard Right Arrow => Keyboard Right Arrow nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 22: F Lock , default: Do Nothing One => Do Nothing One is FN, pos:0, group:0, group mask:empty reporting: default 23: FN Key , default: Do Nothing One => Do Nothing One nonstandard, pos:0, group:0, group mask:empty reporting: default Has 17 persistent remappable keys: 0: Brightness Down => None 1: Brightness Up => None 2: Mission Control/Task View => Key: Meta+TAB 3: Dashboard Launchpad/Action Center => Key: Meta+A 4: Show Desktop => Key: Meta+D 5: Backlight Down => None 6: Backlight Up => None 7: Previous Fn => Consumer: Scan Previous Track 8: Play/Pause Fn => Consumer: Play/Pause 9: Next Fn => Consumer: Scan Next Track 10: Mute Fn => Consumer: Mute 11: Volume Down Fn => Consumer: Volume Down 12: Volume Up Fn => Consumer: Volume Up 13: Calculator => Consumer: AL Calculator 14: Screen Capture/Print Screen => Key: SYSRQ 15: App Contextual Menu/Right Click => Key: COMPOSE 16: Lock PC => Key: Meta+L Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/ERGO M575 Trackball 4096.txt000066400000000000000000000106431522022367600215550ustar00rootroot00000000000000Solaar version 1.1.4 1: ERGO M575 Trackball Device path : /dev/hidraw5 WPID : 4096 Codename : ERGO M575 Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 460DFDC2 Model ID: B02740960000 Unit ID: 460DFDC2 Bootloader: BOT 40.00.B0009 Firmware: MPM 26.00.B0009 Other: The power switch is located on the base. Supports 25 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 40.00.B0009 0000ABF1CB8B01 Firmware: Firmware MPM 26.00.B0009 4096ABF1CB8B01 Firmware: Other Unit ID: 460DFDC2 Model ID: B02740960000 Transport IDs: {'btleid': 'B027', 'wpid': '4096'} 3: DEVICE NAME {0005} Name: ERGO M575 Trackball Kind: trackball 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: ERGO M575 7: UNIFIED BATTERY {1004} 8: REPROG CONTROLS V4 {1B04} DPI Sliding Adjustment (saved): Off DPI Sliding Adjustment : Off Mouse Gestures (saved): Off Mouse Gestures : Off Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular} 9: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 500 Sensitivity (DPI) : 500 10: XY STATS {2250} 11: DFUCONTROL SIGNED {00C2} 12: DEVICE RESET {1802} internal, hidden 13: unknown:1803 {1803} internal, hidden 14: CONFIG DEVICE PROPS {1806} internal, hidden 15: unknown:1812 {1812} internal, hidden 16: OOBSTATE {1805} internal, hidden 17: unknown:1830 {1830} internal, hidden 18: unknown:1890 {1890} internal, hidden 19: unknown:1891 {1891} internal, hidden 20: unknown:18A1 {18A1} internal, hidden 21: unknown:1E00 {1E00} hidden 22: unknown:1EB0 {1EB0} internal, hidden 23: unknown:1861 {1861} internal, hidden 24: unknown:1E22 {1E22} internal, hidden Has 6 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 4: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 5: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Battery: 85%, discharging. Solaar-1.1.20/docs/devices/EX100 Receiver 27 Mhz C517.text000066400000000000000000000157641522022367600221300ustar00rootroot00000000000000solaar version 1.1.11-80-gdea496f EX100 Receiver 27 Mhz Device path : /dev/hidraw2 USB id : 046d:C517 Serial : None Has 2 paired device(s) out of a maximum of 4. Notifications: wireless (0x000100) 1: Wireless Mouse EX100 Device path : /dev/hidraw3 WPID : 003F Codename : EX100m Kind : mouse Protocol : HID++ 1.0 Serial number: The power switch is located on the (unknown). Notifications: roller V, mouse extra buttons, battery status, roller H (0x3C0000). Battery: good, discharging. 3: Wireless Keyboard EX100 Device path : /dev/hidraw6 WPID : 0065 Codename : EX100 Kind : keyboard Protocol : HID++ 1.0 Serial number: The power switch is located on the (unknown). Notifications: keyboard multimedia raw, battery status (0x110000). Battery: good, discharging. Register Dump Notifications 0x00: 0x000100 Connection State 0x02: 0x000100 Device Activity 0xb3: None Pairing Register 0xb5 0x00: None Pairing Register 0xb5 0x01: None Pairing Register 0xb5 0x02: None Pairing Register 0xb5 0x03: None Pairing Register 0xb5 0x04: None Pairing Register 0xb5 0x05: None Pairing Register 0xb5 0x06: None Pairing Register 0xb5 0x07: None Pairing Register 0xb5 0x08: None Pairing Register 0xb5 0x09: None Pairing Register 0xb5 0x0a: None Pairing Register 0xb5 0x0b: None Pairing Register 0xb5 0x0c: None Pairing Register 0xb5 0x0d: None Pairing Register 0xb5 0x0e: None Pairing Register 0xb5 0x0f: None Pairing Register 0xb5 0x10: None Pairing Register 0xb5 0x20: None Pairing Register 0xb5 0x30: None Pairing Register 0xb5 0x50: None Pairing Name 0xb5 0x40: None Pairing Name 0xb5 0x60 0x1: 0 None Pairing Name 0xb5 0x60 0x2: 0 None Pairing Name 0xb5 0x60 0x3: 0 None Pairing Register 0xb5 0x11: None Pairing Register 0xb5 0x21: None Pairing Register 0xb5 0x31: None Pairing Register 0xb5 0x51: None Pairing Name 0xb5 0x41: None Pairing Name 0xb5 0x61 0x1: 0 None Pairing Name 0xb5 0x61 0x2: 0 None Pairing Name 0xb5 0x61 0x3: 0 None Pairing Register 0xb5 0x12: None Pairing Register 0xb5 0x22: None Pairing Register 0xb5 0x32: None Pairing Register 0xb5 0x52: None Pairing Name 0xb5 0x42: None Pairing Name 0xb5 0x62 0x1: 0 None Pairing Name 0xb5 0x62 0x2: 0 None Pairing Name 0xb5 0x62 0x3: 0 None Pairing Register 0xb5 0x13: None Pairing Register 0xb5 0x23: None Pairing Register 0xb5 0x33: None Pairing Register 0xb5 0x53: None Pairing Name 0xb5 0x43: None Pairing Name 0xb5 0x63 0x1: 0 None Pairing Name 0xb5 0x63 0x2: 0 None Pairing Name 0xb5 0x63 0x3: 0 None Pairing Register 0xb5 0x14: None Pairing Register 0xb5 0x24: None Pairing Register 0xb5 0x34: None Pairing Register 0xb5 0x54: None Pairing Name 0xb5 0x44: None Pairing Name 0xb5 0x64 0x1: 0 None Pairing Name 0xb5 0x64 0x2: 0 None Pairing Name 0xb5 0x64 0x3: 0 None Pairing Register 0xb5 0x15: None Pairing Register 0xb5 0x25: None Pairing Register 0xb5 0x35: None Pairing Register 0xb5 0x55: None Pairing Name 0xb5 0x45: None Pairing Name 0xb5 0x65 0x1: 0 None Pairing Name 0xb5 0x65 0x2: 0 None Pairing Name 0xb5 0x65 0x3: 0 None Pairing Register 0xb5 0x16: None Pairing Register 0xb5 0x26: None Pairing Register 0xb5 0x36: None Pairing Register 0xb5 0x56: None Pairing Name 0xb5 0x46: None Pairing Name 0xb5 0x66 0x1: 0 None Pairing Name 0xb5 0x66 0x2: 0 None Pairing Name 0xb5 0x66 0x3: 0 None Firmware 0xf1 0x00: None Firmware 0xf1 0x01: None Firmware 0xf1 0x02: None Firmware 0xf1 0x03: None Firmware 0xf1 0x04: None Register Short 0x00 0x00: 0x000100 Register Long 0x00 0x00: invalid SubID/command ... Register Long 0x00 0xfe: invalid SubID/command Register Short 0x01 0x00: 0x000200 Register Long 0x01 0x00: invalid SubID/command Register Long 0x01 0x01: invalid SubID/command Register Long 0x01 0x02: invalid SubID/command ... ./scan-registers.sh ff /dev/hidraw4 # Old notification flags: 000100 >> ( 0.035) [10 FF 8100 000100] '\x10\xff\x81\x00\x00\x01\x00' << ( 0.015) [10 FF 8101 000000] '\x10\xff\x81\x01\x00\x00\x00' >> ( 0.020) [10 FF 8101 000200] '\x10\xff\x81\x01\x00\x02\x00' << ( 0.030) [10 FF 8102 000000] '\x10\xff\x81\x02\x00\x00\x00' >> ( 0.036) [10 FF 8102 000200] '\x10\xff\x81\x02\x00\x02\x00' -- << ( 0.142) [10 FF 8109 000000] '\x10\xff\x81\t\x00\x00\x00' >> ( 0.148) [10 FF 8109 010000] '\x10\xff\x81\t\x01\x00\x00' -- << ( 1.790) [10 FF 8170 000000] '\x10\xff\x81p\x00\x00\x00' >> ( 1.796) [10 FF 8170 012100] '\x10\xff\x81p\x01!\x00' << ( 1.806) [10 FF 8171 000000] '\x10\xff\x81q\x00\x00\x00' >> ( 1.812) [10 FF 8171 011200] '\x10\xff\x81q\x01\x12\x00' -- << ( 1.838) [10 FF 8173 000000] '\x10\xff\x81s\x00\x00\x00' >> ( 1.844) [10 FF 8173 643F00] '\x10\xff\x81sd?\x00' -- << ( 2.046) [10 FF 8180 000000] '\x10\xff\x81\x80\x00\x00\x00' >> ( 2.052) [10 FF 8180 030000] '\x10\xff\x81\x80\x03\x00\x00' -- << ( 3.326) [10 FF 81D0 000000] '\x10\xff\x81\xd0\x00\x00\x00' >> ( 3.332) [10 FF 81D0 000000] '\x10\xff\x81\xd0\x00\x00\x00' devices 01 mouse Red button pressed >> ( 1676.106) [10 01 0810 000000] '\x10\x01\x08\x10\x00\x00\x00' >> ( 1676.114) [10 01 4600 000021] '\x10\x01F\x00\x00\x00!' >> ( 1676.122) [10 FF 4600 211100] '\x10\xffF\x00!\x11\x00' Power lewel? ?? Input: 10 01 81 07 00 00 00 << ( 1739.032) [10 01 8107 000000] '\x10\x01\x81\x07\x00\x00\x00' >> ( 1739.040) [10 01 8107 030000] '\x10\x01\x81\x07\x03\x00\x00' [10 01 8107 070000] '\x10\x01\x81\x07\x07\x00\x00' power change >> ( 2441.563) [10 01 0703 000000] '\x10\x01\x07\x03\x00\x00\x00' >> ( 100.159) [10 01 0707 000000] '\x10\x01\x07\x07\x00\x00\x00' enable power event << ( 59.190) [10 01 8000 100000] '\x10\x01\x80\x00\x10\x00\x00' >> ( 59.193) [10 01 8000 000000] '\x10\x01\x80\x00\x00\x00\x00' 03 keyboard Power level? ?? Input: 10 03 81 07 00 00 00 << ( 1777.961) [10 03 8107 000000] '\x10\x03\x81\x07\x00\x00\x00' >> ( 1777.967) [10 03 8107 070000] '\x10\x03\x81\x07\x07\x00\x00' power on >> ( 1571.805) [10 03 0810 000000] '\x10\x03\x08\x10\x00\x00\x00' >> ( 1574.709) [10 03 0800 000000] '\x10\x03\x08\x00\x00\x00\x00' red button pressed >> ( 1619.043) [10 03 0810 000000] '\x10\x03\x08\x10\x00\x00\x00' >> ( 1619.051) [10 03 4600 000011] '\x10\x03F\x00\x00\x00\x11' >> ( 1619.059) [10 FF 4600 221100] '\x10\xffF\x00"\x11\x00' >> ( 1621.747) [10 03 0800 000000] '\x10\x03\x08\x00\x00\x00\x00' Fn pressed >> ( 1651.715) [10 03 032C 100000] '\x10\x03\x03,\x10\x00\x00' >> ( 1652.170) [10 03 0300 000000] '\x10\x03\x03\x00\x00\x00\x00' Battery status: 1.9V critical 2.3V low 2.5V full Solaar-1.1.20/docs/devices/G Pro Wireless Gaming Mouse 4079.txt000066400000000000000000000051751522022367600234510ustar00rootroot00000000000000Solaar version 1.1.4rc1 1: G Pro Wireless Gaming Mouse Device path : /dev/hidraw10 WPID : 4079 Codename : G Pro Kind : mouse Protocol : HID++ 4.2 Polling rate : 2 ms (500Hz) Serial number: 40B217C0 Model ID: 4079C0880000 Unit ID: 40B217C0 Bootloader: BOT 74.02.B0026 Firmware: MPM 15.02.B0026 Other: The power switch is located on the base. Supports 28 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 74.02.B0026 AADF85EE714A Firmware: Firmware MPM 15.02.B0026 407985EE714A Firmware: Other Unit ID: 40B217C0 Model ID: 4079C0880000 Transport IDs: {'wpid': '4079', 'usbid': 'C088'} 3: DEVICE NAME {0005} Name: G Pro Wireless Gaming Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY VOLTAGE {1001} Battery: 3926mV, discharging, 70. 7: COLOR LED EFFECTS {8070} 8: LED CONTROL {1300} 9: ONBOARD PROFILES {8100} Device Mode: On-Board Onboard Profiles (saved): Enable Onboard Profiles : Enable 10: MOUSE BUTTON SPY {8110} 11: REPORT RATE {8060} Polling Rate (ms): 2 Polling Rate (ms) (saved): 2 Polling Rate (ms) : 2 12: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 1600 Sensitivity (DPI) : 1600 13: DEVICE RESET {1802} internal, hidden 14: unknown:1803 {1803} internal, hidden 15: OOBSTATE {1805} internal, hidden 16: CONFIG DEVICE PROPS {1806} internal, hidden 17: unknown:1811 {1811} internal, hidden 18: unknown:1830 {1830} internal, hidden 19: unknown:1890 {1890} internal, hidden 20: unknown:1891 {1891} internal, hidden 21: unknown:18A1 {18A1} internal, hidden 22: unknown:1801 {1801} internal, hidden 23: unknown:18B1 {18B1} internal, hidden 24: unknown:1DF3 {1DF3} internal, hidden 25: unknown:1E00 {1E00} hidden 26: unknown:1EB0 {1EB0} internal, hidden 27: unknown:1863 {1863} internal, hidden Battery: 3926mV, discharging, 70. Solaar-1.1.20/docs/devices/G213 Prodigy Gaming Keyboard C366.txt000066400000000000000000000030351522022367600234550ustar00rootroot00000000000000Solaar version 1.1.5rc1 USB and Bluetooth Devices 1: G213 Prodigy Gaming Keyboard Device path : /dev/hidraw2 USB id : 046d:C336 Codename : G213 Kind : keyboard Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: Model ID: C33600000000 Unit ID: 31314709 Firmware: U1 09.00.B0006 Bootloader: BOT 31.00.B0002 Supports 15 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Firmware U1 09.00.B0006 C336 Firmware: Bootloader BOT 31.00.B0002 AAC8 Unit ID: 31314709 Model ID: C33600000000 Transport IDs: {'usbid': 'C336'} 3: KEYBOARD DISABLE BY USAGE {4522} V0 4: DEVICE NAME {0005} V0 Name: Gaming Keyboard G213 Kind: keyboard 5: unknown:1E00 {1E00} V0 hidden 6: KEYBOARD LAYOUT 2 {4540} V0 7: unknown:1EB0 {1EB0} V0 internal, hidden 8: REPORT RATE {8060} V0 Polling Rate (ms): 1 Polling Rate (ms) : 1 9: DFUCONTROL SIGNED {00C2} V0 10: unknown:1801 {1801} V0 internal, hidden 11: DEVICE RESET {1802} V0 internal, hidden 12: COLOR LED EFFECTS {8070} V5 13: unknown:1821 {1821} V0 14: REPORT HID USAGE {1BC0} V0 Battery: N/A, None. Solaar-1.1.20/docs/devices/G304 Lightspeed Wireless Gaming Mouse 4074.txt000066400000000000000000000051761522022367600252240ustar00rootroot00000000000000solaar version 1.1.8 1: G304 Lightspeed Wireless Gaming Mouse Device path : /dev/hidraw6 WPID : 4074 Codename : G304 Kind : mouse Protocol : HID++ 4.2 Polling rate : 8 ms (125Hz) Serial number: B2D05D23 Model ID: 407400000000 Unit ID: EB490C63 Bootloader: BOT 69.02.B0021 Firmware: RQM 68.02.B0021 The power switch is located on the base. Supports 27 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BOT 69.02.B0021 4074452F3940 Firmware: Firmware RQM 68.02.B0021 4074452F3940 Unit ID: EB490C63 Model ID: 407400000000 Transport IDs: {'wpid': '4074'} 3: DEVICE NAME {0005} V0 Name: G304 Lightspeed Wireless Gaming Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: BATTERY STATUS {1000} V0 Battery: 90%, discharging, next level 50%. 6: COLOR LED EFFECTS {8070} V6 7: ONBOARD PROFILES {8100} V0 Device Mode: Host Onboard Profiles (saved): Disable Onboard Profiles : Disable 8: MOUSE BUTTON SPY {8110} V0 9: REPORT RATE {8060} V0 Polling Rate (ms): 8 Polling Rate (ms) (saved): 8 Polling Rate (ms) : 8 10: MODE STATUS {8090} V1 11: DFUCONTROL SIGNED {00C2} V0 12: DEVICE RESET {1802} V0 internal, hidden 13: unknown:1803 {1803} V0 internal, hidden 14: CONFIG DEVICE PROPS {1806} V4 internal, hidden 15: unknown:1811 {1811} V0 internal, hidden 16: OOBSTATE {1805} V0 internal, hidden 17: unknown:1830 {1830} V0 internal, hidden 18: unknown:1890 {1890} V0 internal, hidden 19: unknown:1DF3 {1DF3} V0 internal, hidden 20: unknown:1E00 {1E00} V0 hidden 21: unknown:1EB0 {1EB0} V0 internal, hidden 22: unknown:1861 {1861} V0 internal, hidden 23: unknown:18B1 {18B1} V0 internal, hidden 24: unknown:1E22 {1E22} V0 internal, hidden 25: unknown:1801 {1801} V0 internal, hidden 26: ADJUSTABLE DPI {2201} V1 Sensitivity (DPI) (saved): 2200 Sensitivity (DPI) : 2200 Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/G305 Lightspeed Wireless Gaming Mouse 4074.text000066400000000000000000000052011522022367600253570ustar00rootroot00000000000000solaar version 1.1.10 1: G305 Lightspeed Wireless Gaming Mouse Device path : /dev/hidraw7 WPID : 4074 Codename : G305 Kind : mouse Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: ED5E9515 Model ID: 407400000000 Unit ID: F074D567 Bootloader: BOT 69.02.B0021 Firmware: RQM 68.02.B0021 The power switch is located on the base. Supports 27 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BOT 69.02.B0021 4074452F3940 Firmware: Firmware RQM 68.02.B0021 4074452F3940 Unit ID: F074D567 Model ID: 407400000000 Transport IDs: {'wpid': '4074'} 3: DEVICE NAME {0005} V0 Name: G305 Lightspeed Wireless Gaming Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: BATTERY STATUS {1000} V0 Battery: 50%, discharging, next level 30%. 6: COLOR LED EFFECTS {8070} V6 7: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Enable Onboard Profiles : Enable 8: MOUSE BUTTON SPY {8110} V0 9: REPORT RATE {8060} V0 Polling Rate (ms): 1 Polling Rate (ms) (saved): 1 Polling Rate (ms) : 1 10: MODE STATUS {8090} V1 11: DFUCONTROL SIGNED {00C2} V0 12: DEVICE RESET {1802} V0 internal, hidden 13: unknown:1803 {1803} V0 internal, hidden 14: CONFIG DEVICE PROPS {1806} V4 internal, hidden 15: unknown:1811 {1811} V0 internal, hidden 16: OOBSTATE {1805} V0 internal, hidden 17: unknown:1830 {1830} V0 internal, hidden 18: unknown:1890 {1890} V0 internal, hidden 19: unknown:1DF3 {1DF3} V0 internal, hidden 20: unknown:1E00 {1E00} V0 hidden 21: unknown:1EB0 {1EB0} V0 internal, hidden 22: unknown:1861 {1861} V0 internal, hidden 23: unknown:18B1 {18B1} V0 internal, hidden 24: unknown:1E22 {1E22} V0 internal, hidden 25: unknown:1801 {1801} V0 internal, hidden 26: ADJUSTABLE DPI {2201} V1 Sensitivity (DPI) (saved): 1600 Sensitivity (DPI) : 1600 Battery: 50%, discharging, next level 30%. Solaar-1.1.20/docs/devices/G502 Gaming Mouse C07D.text000066400000000000000000000036041522022367600215730ustar00rootroot00000000000000Solaar version 1.1.5 1: G502 Gaming Mouse Device path : /dev/hidraw1 USB id : 046d:C07D Codename : G502 Kind : mouse Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: Model ID: 000000000000 Unit ID: 00000000 Firmware: U 88.02.B0017 Bootloader: BOT 14.00.B0007 Hardware: 72 Other: Supports 19 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: FEATURE INFO {0002} V0 3: DEVICE FW VERSION {0003} V0 Firmware: Firmware U 88.02.B0017 Firmware: Bootloader BOT 14.00.B0007 Firmware: Hardware 72 Firmware: Other Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 4: DEVICE NAME {0005} V0 Name: Tunable FPS Gaming Mouse G502 Kind: mouse 5: LED CONTROL {1300} V0 6: unknown:18A1 {18A1} V0 internal, hidden 7: unknown:1E00 {1E00} V0 hidden 8: unknown:1E20 {1E20} V0 9: unknown:1EB0 {1EB0} V0 internal, hidden 10: ADJUSTABLE DPI {2201} V0 Sensitivity (DPI) : 800 11: ANGLE SNAPPING {2230} V0 12: SURFACE TUNING {2240} V0 13: REPORT RATE {8060} V0 Polling Rate (ms): 1 Polling Rate (ms) : 1 14: ONBOARD PROFILES {8100} V0 Device Mode: Host Onboard Profiles : Disable 15: MOUSE BUTTON SPY {8110} V0 16: unknown:1850 {1850} V0 internal, hidden 17: DFUCONTROL UNSIGNED {00C1} V0 18: unknown:1801 {1801} V0 internal, hidden Battery: N/A, None. Solaar-1.1.20/docs/devices/G502 Lightspeed Wireless Gaming Mouse 407F.txt000066400000000000000000000071621522022367600252430ustar00rootroot00000000000000solaar version 1.1.12rc1 1: G502 Gaming Mouse Device path : /dev/hidraw20 WPID : 407F Codename : G502 Kind : mouse Protocol : HID++ 4.2 Report Rate : 1ms Serial number: DDDAADBC Model ID: 407FC08D0000 Unit ID: DDDAADBC 1: BOT 92.00.B0008 0: MPM 17.00.B0008 3: The power switch is located on the base. Supports 30 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BOT 92.00.B0008 AAEF21F1FA5F Firmware: Firmware MPM 17.00.B0008 407F21F1FA5F Firmware: Other Unit ID: DDDAADBC Model ID: 407FC08D0000 Transport IDs: {'wpid': '407F', 'usbid': 'C08D'} 3: DEVICE NAME {0005} V0 Name: G502 LIGHTSPEED Wireless Gaming Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 11000000000000000000000000000000 6: BATTERY VOLTAGE {1001} V2 Battery: 90% 4166mV , discharging. 7: COLOR LED EFFECTS {8070} V4 LED Control (saved): Device LED Control : Device LEDs Primary (saved): !LEDEffectSetting {ID: 1, color: 16711680, intensity: 0, period: 100, ramp: 0, speed: 0} LEDs Primary : None LEDs Logo : None 8: LED CONTROL {1300} V0 9: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Profile 1 Onboard Profiles : Profile 1 10: MOUSE BUTTON SPY {8110} V0 11: REPORT RATE {8060} V0 Report Rate: 1ms Report Rate (saved): 1ms Report Rate : 1ms 12: ADJUSTABLE DPI {2201} V1 Sensitivity (DPI) (saved): 900 Sensitivity (DPI) : 900 13: DEVICE RESET {1802} V0 internal, hidden 14: unknown:1803 {1803} V0 internal, hidden 15: OOBSTATE {1805} V0 internal, hidden 16: CONFIG DEVICE PROPS {1806} V4 internal, hidden 17: unknown:1811 {1811} V0 internal, hidden 18: unknown:1830 {1830} V0 internal, hidden 19: unknown:1890 {1890} V4 internal, hidden 20: unknown:1891 {1891} V4 internal, hidden 21: unknown:18A1 {18A1} V0 internal, hidden 22: unknown:1801 {1801} V0 internal, hidden 23: unknown:18B1 {18B1} V0 internal, hidden 24: unknown:1DF3 {1DF3} V0 internal, hidden 25: unknown:1E00 {1E00} V0 hidden 26: unknown:1EB0 {1EB0} V0 internal, hidden 27: unknown:1863 {1863} V0 internal, hidden 28: unknown:1E22 {1E22} V0 internal, hidden 29: HIRES WHEEL {2121} V0 Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False Battery: 90% 4166mV , discharging. Solaar-1.1.20/docs/devices/G502 Proteus Spectrum Optical Mouse C332.txt000066400000000000000000000032241522022367600247770ustar00rootroot00000000000000solaar version 1.1.9 2: G502 Proteus Spectrum Optical Mouse Device path : /dev/hidraw4 USB id : 046d:C332 Codename : G502 Proteus Spectrum Kind : mouse Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: Model ID: C33200000000 Unit ID: 31374706 Firmware: U1 03.02.B0012 Bootloader: BOT 14.00.B0007 Supports 20 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: COLOR LED EFFECTS {8070} V3 3: DEVICE FW VERSION {0003} V1 Firmware: Firmware U1 03.02.B0012 C332 Firmware: Bootloader BOT 14.00.B0007 AABF Unit ID: 31374706 Model ID: C33200000000 Transport IDs: {'usbid': 'C332'} 4: DEVICE NAME {0005} V0 Name: Tunable RGB Gaming Mouse G502 Kind: mouse 5: LED CONTROL {1300} V0 6: unknown:18A1 {18A1} V0 internal, hidden 7: unknown:1E00 {1E00} V0 hidden 8: unknown:1E20 {1E20} V0 9: unknown:1EB0 {1EB0} V0 internal, hidden 10: ADJUSTABLE DPI {2201} V1 Sensitivity (DPI) (saved): 7000 Sensitivity (DPI) : 7000 11: ANGLE SNAPPING {2230} V0 12: SURFACE TUNING {2240} V0 13: REPORT RATE {8060} V0 Polling Rate (ms): 1 Polling Rate (ms) (saved): 1 Polling Rate (ms) : 1 14: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Enable Onboard Profiles : Enable 15: MOUSE BUTTON SPY {8110} V0 16: unknown:1850 {1850} V0 internal, hidden 17: DFUCONTROL UNSIGNED {00C1} V0 18: unknown:1801 {1801} V0 internal, hidden 19: DEVICE RESET {1802} V0 internal, hidden Battery status unavailable. Solaar-1.1.20/docs/devices/G502 SE Hero Gaming Mouse C08B.txt000066400000000000000000000035141522022367600225730ustar00rootroot000000000000001: G502 SE Hero Gaming Mouse Device path : /dev/hidraw7 USB id : 046d:C08B Codename : G502 Hero Kind : mouse Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: Model ID: C08B00000000 Unit ID: 30324703 Firmware: U1 27.03.B0010 Bootloader: BOT 81.00.B0002 Supports 19 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: COLOR LED EFFECTS {8070} 3: DEVICE FW VERSION {0003} Firmware: Firmware U1 27.03.B0010 C08B Firmware: Bootloader BOT 81.00.B0002 AAE6 Unit ID: 30324703 Model ID: C08B00000000 Transport IDs: {'usbid': 'C08B'} 4: DEVICE NAME {0005} Name: G502 HERO Gaming Mouse Kind: mouse 5: LED CONTROL {1300} 6: unknown:18A1 {18A1} internal, hidden 7: unknown:1E00 {1E00} hidden 8: unknown:1E22 {1E22} internal, hidden 9: unknown:1EB0 {1EB0} internal, hidden 10: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 2400 Sensitivity (DPI) : 2400 11: REPORT RATE {8060} Polling Rate (ms): 1 Polling Rate (ms) (saved): 1 Polling Rate (ms) : 1 12: ONBOARD PROFILES {8100} Device Mode: Host 13: MOUSE BUTTON SPY {8110} 14: DFUCONTROL SIGNED {00C2} 15: unknown:1801 {1801} internal, hidden 16: DEVICE RESET {1802} internal, hidden 17: CONFIG DEVICE PROPS {1806} internal, hidden 18: unknown:18B1 {18B1} internal, hidden Battery status unavailable. Solaar-1.1.20/docs/devices/G502 X C099.txt000066400000000000000000000054201522022367600173470ustar00rootroot00000000000000Solaar version 1.1.7 1: G502 X Device path : /dev/hidraw2 USB id : 046d:C099 Codename : G502 Kind : mouse Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: Model ID: C09900000000 Unit ID: 42004C00 Bootloader: BL1 59.00.B0002 Firmware: U1 60.00.B0009 Supports 22 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 59.00.B0002 AB17 Firmware: Firmware U1 60.00.B0009 C099 Unit ID: 42004C00 Model ID: C09900000000 Transport IDs: {'usbid': 'C099'} 3: DEVICE NAME {0005} V0 Name: G502 X Kind: mouse 4: RESET {0020} V0 5: DFUCONTROL SIGNED {00C2} V0 6: unknown:1801 {1801} V0 internal, hidden, unknown:000010 7: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 8: OOBSTATE {1805} V0 internal, hidden 9: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 10: unknown:1875 {1875} V0 internal, hidden, unknown:000010 11: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 12: unknown:18B1 {18B1} V0 internal, hidden, unknown:000010 13: unknown:18C0 {18C0} V0 internal, hidden, unknown:000010 14: unknown:1E00 {1E00} V0 hidden 15: unknown:1E22 {1E22} V0 internal, hidden, unknown:000010 16: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 17: HIRES WHEEL {2121} V1 Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 18: ADJUSTABLE DPI {2201} V2 Sensitivity (DPI) (saved): 1600 Sensitivity (DPI) : 1600 19: REPORT RATE {8060} V0 Polling Rate (ms): 1 Polling Rate (ms) (saved): 1 Polling Rate (ms) : 1 20: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Enable Onboard Profiles : Enable 21: MOUSE BUTTON SPY {8110} V0 Battery status unavailable. Solaar-1.1.20/docs/devices/G502 X PLUS 4099.txt000066400000000000000000000110261522022367600200730ustar00rootroot00000000000000solaar version 1.1.19-25-g7520c9cc 1: G502 X PLUS Device path : /dev/hidraw8 WPID : 4099 Codename : G502 X PLUS Kind : mouse Protocol : HID++ 4.2 Report Rate : 1ms Serial number: C6884511 Model ID: 4099C0950000 Unit ID: C6884511 1: BL1 42.00.B0016 0: MPM 27.00.B0016 3: 3: 3: 3: 3: 3: 3: 3: 3: 3: The power switch is located on the unknown. Supports 32 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: 1 BL1 42.00.B0016 AB0BFBB13A33 Firmware: 0 MPM 27.00.B0016 4099FBB13A33 Firmware: 3 Firmware: 3 Firmware: 3 Firmware: 3 Firmware: 3 Firmware: 3 Firmware: 3 Firmware: 3 Firmware: 3 Firmware: 3 Unit ID: C6884511 Model ID: 4099C0950000 Transport IDs: {'wpid': '4099', 'usbid': 'C095'} 3: DEVICE NAME {0005} V0 Name: G502 X PLUS Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 11000000000000000000000000000000 6: UNIFIED BATTERY {1004} V3 Battery: 77%, BatteryStatus.DISCHARGING. 7: ADJUSTABLE DPI {2201} V2 Sensitivity (DPI) (saved): 800 Sensitivity (DPI) : 800 8: HIRES WHEEL {2121} V0 Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode Low resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): False Scroll Wheel Resolution : False Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 9: RGB EFFECTS {8071} V2 LED Control (saved): Solaar LED Control : Solaar LEDs Primary (saved): !LEDEffectSetting {ID: 0, color: 10820909, intensity: 0, period: 100, ramp: 0, speed: 0} LEDs Primary : !LEDEffectSetting {ID: 0, color: 10820909, intensity: 0, period: 100, ramp: 0, speed: 0} 10: PER KEY LIGHTING V2 {8081} V2 Per-key Lighting (saved): {A:No change, B:No change, C:No change, D:No change, E:No change, F:No change, G:No change, H:No change} Per-key Lighting : {A:No change, B:No change, C:No change, D:No change, E:No change, F:No change, G:No change, H:No change} 11: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Profile 1 Onboard Profiles : Profile 1 12: MOUSE BUTTON SPY {8110} V0 13: REPORT RATE {8060} V0 Report Rate: 1ms Report Rate (saved): 1ms Report Rate : 1ms 14: FORCE PAIRING {1500} V0 15: DFU {00D0} V3 16: DEVICE RESET {1802} V0 17: unknown:1803 {0318} V0 internal, hidden, unknown:000010 18: CONFIG DEVICE PROPS {1806} V8 19: unknown:1811 {1118} V0 internal, hidden, unknown:000010 20: OOBSTATE {1805} V0 21: unknown:1830 {3018} V0 internal, hidden, unknown:000010 22: unknown:1875 {7518} V0 internal, hidden, unknown:000010 23: unknown:1861 {6118} V0 internal, hidden, unknown:000010 24: unknown:1890 {9018} V0 internal, hidden, unknown:000008 25: unknown:18A1 {A118} V0 internal, hidden, unknown:000010 26: unknown:1801 {0118} V0 internal, hidden, unknown:000010 27: unknown:1E00 {001E} V0 hidden 28: unknown:1E22 {221E} V0 internal, hidden, unknown:000010 29: unknown:1EB0 {B01E} V0 internal, hidden, unknown:000010 30: unknown:18B1 {B118} V0 internal, hidden, unknown:000010 31: unknown:18C0 {C018} V0 internal, hidden, unknown:000010 Battery: 77%, BatteryStatus.DISCHARGING. Solaar-1.1.20/docs/devices/G515 LS TKL 40B4.text000066400000000000000000000143101522022367600202250ustar00rootroot00000000000000solaar version 1.1.13+dfsg-1 1: G515 LS TKL Device path : None WPID : 40B4 Codename : G515 LS TKL Kind : keyboard Protocol : HID++ 4.2 Report Rate : 8ms Serial number: 54FEF928 Model ID: B38940B4C355 Unit ID: 54FEF928 1: BL2 19.01.B0011 3: 0: MPK 25.01.B0011 3: The power switch is located on the top right corner. Supports 34 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V6 Firmware: Bootloader BL2 19.01.B0011 ABD580558692 Firmware: Other Firmware: Firmware MPK 25.01.B0011 40B480558692 Firmware: Other Unit ID: 54FEF928 Model ID: B38940B4C355 Transport IDs: {'btleid': 'B389', 'wpid': '40B4', 'usbid': 'C355'} 3: DEVICE NAME {0005} V3 Name: G515 LS TKL Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 11000000000000000000000000000000 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: G515 LS TKL 7: unknown:0011 {0011} V0 8: UNIFIED BATTERY {1004} V5 Battery: 82%, discharging. 9: RGB EFFECTS {8071} V4 LED Control (saved): Solaar LED Control : Solaar LEDs Primary (saved): !LEDEffectSetting {ID: 1, color: 16776960, intensity: 26, period: 2167, ramp: 1, speed: 0} LEDs Primary : HID++ error {'number': 1, 'request': 2537, 'error': 7, 'params': b'\x00'} 10: PER KEY LIGHTING V2 {8081} V0 Per-key Lighting (saved): {A:indian red, B:indian red, C:indian red, D:indian red, E:indian red, F:indian red, G:indian red, H:indian red, I:indian red, J:indian red, K:indian red, L:indian red, M:indian red, N:indian red, O:indian red, P:indian red, Q:indian red, R:indian red, S:indian red, T:indian red, U:indian red, V:indian red, W:indian red, X:indian red, Y:indian red, Z:indian red, 1:orange, 2:orange, 3:orange, 4:orange, 5:orange, 6:orange, 7:orange, 8:orange, 9:orange, 0:yellow, ENTER:green, ESC:green, BACKSPACE:red, TAB:yellow, SPACE:yellow, -:indian red, =:indian red, [:indian red, \:indian red, KEY 46:white, ~:indian red, ;:indian red, ':indian red, `:indian red, ,:indian red, .:indian red, /:indian red, CAPS LOCK:red, F1:indian red, F2:indian red, F3:indian red, F4:indian red, F5:indian red, F6:indian red, F7:indian red, F8:indian red, F9:indian red, F10:indian red, F11:indian red, F12:indian red, PRINT:red, SCROLL LOCK:orange, PASTE:indian red, INSERT:green, HOME:indian red, PAGE UP:yellow, DELETE:red, END:indian red, PAGE DOWN:yellow, RIGHT:indian red, LEFT:indian red, DOWN:indian red, UP:indian red, KEY 97:indian red, COMPOSE:white, POWER:white, KEY 100:indian red, KEY 101:red, KEY 102:red, KEY 103:red, LEFT CTRL:indian red, LEFT SHIFT:yellow, LEFT ALT:indian red, LEFT WINDOWS:blue, RIGHT CTRL:indian red, RIGHT SHIFT:yellow, RIGHT ALTGR:blue, RIGHT WINDOWS:indian red, KEY 254:white} Per-key Lighting : {A:No change, B:No change, C:No change, D:No change, E:No change, F:No change, G:No change, H:No change, I:No change, J:No change, K:No change, L:No change, M:No change, N:No change, O:No change, P:No change, Q:No change, R:No change, S:No change, T:No change, U:No change, V:No change, W:No change, X:No change, Y:No change, Z:No change, 1:No change, 2:No change, 3:No change, 4:No change, 5:No change, 6:No change, 7:No change, 8:No change, 9:No change, 0:No change, ENTER:No change, ESC:No change, BACKSPACE:No change, TAB:No change, SPACE:No change, -:No change, =:No change, [:No change, \:No change, KEY 46:No change, ~:No change, ;:No change, ':No change, `:No change, ,:No change, .:No change, /:No change, CAPS LOCK:No change, F1:No change, F2:No change, F3:No change, F4:No change, F5:No change, F6:No change, F7:No change, F8:No change, F9:No change, F10:No change, F11:No change, F12:No change, PRINT:No change, SCROLL LOCK:No change, PASTE:No change, INSERT:No change, HOME:No change, PAGE UP:No change, DELETE:No change, END:No change, PAGE DOWN:No change, RIGHT:No change, LEFT:No change, DOWN:No change, UP:No change, KEY 97:No change, COMPOSE:No change, POWER:No change, KEY 100:No change, KEY 101:No change, KEY 102:No change, KEY 103:No change, LEFT CTRL:No change, LEFT SHIFT:No change, LEFT ALT:No change, LEFT WINDOWS:No change, RIGHT CTRL:No change, RIGHT SHIFT:No change, RIGHT ALTGR:No change, RIGHT WINDOWS:No change, KEY 254:No change} 11: unknown:1B10 {1B10} V0 12: unknown:4523 {4523} V1 13: KEYBOARD LAYOUT 2 {4540} V1 14: BRIGHTNESS CONTROL {8040} V0 Brightness Control (saved): 40 Brightness Control : 40 15: unknown:8101 {8101} V0 16: unknown:1B05 {1B05} V0 17: unknown:8051 {8051} V0 18: DFU {00D0} V3 19: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 20: unknown:1803 {1803} V1 internal, hidden, unknown:000010 21: unknown:1807 {1807} V3 internal, hidden, unknown:000010 22: unknown:1817 {1817} V0 internal, hidden, unknown:000010 23: OOBSTATE {1805} V0 internal, hidden 24: unknown:1830 {1830} V0 internal, hidden, unknown:000010 25: unknown:1890 {1890} V9 internal, hidden, unknown:000008 26: unknown:1891 {1891} V9 internal, hidden, unknown:000008 27: unknown:1E00 {1E00} V0 hidden 28: unknown:1E02 {1E02} V0 internal, hidden 29: unknown:1602 {1602} V0 30: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 31: unknown:1861 {1861} V1 internal, hidden, unknown:000010 32: unknown:18B0 {18B0} V1 internal, hidden, unknown:000010 33: unknown:1801 {1801} V0 internal, hidden, unknown:000010 Battery: 82%, discharging. Solaar-1.1.20/docs/devices/G535 Wireless Gaming Headset 0AC4.txt000066400000000000000000000020011522022367600234570ustar00rootroot00000000000000solaar version 1.1.8 USB and Bluetooth Devices 1: G535 Wireless Gaming Headset Device path : /dev/hidraw2 USB id : 046d:0AC4 Codename : G535 Kind : ? Protocol : HID++ 4.2 Serial number: Model ID: 000000000AC4 Unit ID: FFFFFFFF Firmware: U1 90.00.B0200 Supports 6 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Firmware U1 90.00.B0200 0AC4 Unit ID: FFFFFFFF Model ID: 000000000AC4 Transport IDs: {'btid': '0000', 'btleid': '0000'} 3: DEVICE NAME {0005} V0 Name: G535 Wireless Gaming Headset Kind: None 4: SIDETONE {8300} V0 Sidetone (saved): 0 Sidetone : 0 5: ADC MEASUREMENT {1F20} V0 Battery: 60% 3920mV , discharging. Battery: 60% 3920mV , discharging. Solaar-1.1.20/docs/devices/G600 Gaming Mouse C24A.txt000066400000000000000000000147251522022367600214270ustar00rootroot00000000000000This mouse does not use HID++ [root@gpiro device]# lsusb -vv -d 046d:c24a Bus 003 Device 002: ID 046d:c24a Logitech, Inc. G600 Gaming Mouse Device Descriptor: bLength 18 bDescriptorType 1 bcdUSB 2.00 bDeviceClass 0 bDeviceSubClass 0 bDeviceProtocol 0 bMaxPacketSize0 32 idVendor 0x046d Logitech, Inc. idProduct 0xc24a G600 Gaming Mouse bcdDevice 77.02 iManufacturer 1 Logitech iProduct 2 Gaming Mouse G600 iSerial 3 385226BFEFD20017 bNumConfigurations 1 Configuration Descriptor: bLength 9 bDescriptorType 2 wTotalLength 0x003b bNumInterfaces 2 bConfigurationValue 1 iConfiguration 4 U77.02_B0017 bmAttributes 0xa0 (Bus Powered) Remote Wakeup MaxPower 500mA Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 0 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 1 Boot Interface Subclass bInterfaceProtocol 2 Mouse iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.11 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 67 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x81 EP 1 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0009 1x 9 bytes bInterval 1 Interface Descriptor: bLength 9 bDescriptorType 4 bInterfaceNumber 1 bAlternateSetting 0 bNumEndpoints 1 bInterfaceClass 3 Human Interface Device bInterfaceSubClass 0 bInterfaceProtocol 1 Keyboard iInterface 0 HID Device Descriptor: bLength 9 bDescriptorType 33 bcdHID 1.11 bCountryCode 0 Not supported bNumDescriptors 1 bDescriptorType 34 Report wDescriptorLength 135 Report Descriptors: ** UNAVAILABLE ** Endpoint Descriptor: bLength 7 bDescriptorType 5 bEndpointAddress 0x82 EP 2 IN bmAttributes 3 Transfer Type Interrupt Synch Type None Usage Type Data wMaxPacketSize 0x0020 1x 32 bytes bInterval 1 can't get device qualifier: Resource temporarily unavailable can't get debug descriptor: Resource temporarily unavailable Device Status: 0x0000 (Bus Powered) /sys/devices/pci0000:00/0000:00:08.1/0000:05:00.4/usb3/3-2/3-2:1.1/0003:046D:C24A.0007/report_descriptor Usage Page (Desktop), ; Generic desktop controls (01h) Usage (Keyboard), ; Keyboard (06h, application collection) Collection (Application), Report ID (1), Usage Page (Keyboard), ; Keyboard/keypad (07h) Usage Minimum (KB Leftcontrol), ; Keyboard left control (E0h, dynamic value) Usage Maximum (KB Right GUI), ; Keyboard right GUI (E7h, dynamic value) Logical Minimum (0), Logical Maximum (1), Report Size (1), Report Count (8), Input (Variable), Report Size (8), Report Count (5), Logical Minimum (0), Logical Maximum (164), Usage Minimum (None), ; No event (00h, selector) Usage Maximum (KB ExSel), ; Keyboard ExSel (A4h, selector) Input, End Collection, Usage Page (FF80h), ; FF80h, vendor-defined Usage (80h), Collection (Application), Report ID (128), Usage (80h), Report Size (8), Report Count (5), Input (Variable), Report ID (246), Usage (F6h), Report Size (8), Report Count (7), Input (Variable), Report ID (240), Usage (F0h), Report Count (3), Feature (Variable), Report ID (241), Usage (F1h), Report Count (7), Feature (Variable), Report ID (242), Usage (F2h), Report Count (4), Feature (Variable), Report ID (243), Usage (F3h), Report Count (153), Feature (Variable), Report ID (244), Usage (F4h), Report Count (153), Feature (Variable), Report ID (245), Usage (F5h), Report Count (153), Feature (Variable), Report ID (246), Usage (F6h), Report Count (7), Feature (Variable), Report ID (247), Usage (F7h), Report Size (8), Report Count (31), Input (Variable), End Collection /sys/devices/pci0000:00/0000:00:08.1/0000:05:00.4/usb3/3-2/3-2:1.0/0003:046D:C24A.0006/report_descriptor Usage Page (Desktop), ; Generic desktop controls (01h) Usage (Mouse), ; Mouse (02h, application collection) Collection (Application), Usage (Pointer), ; Pointer (01h, physical collection) Collection (Physical), Usage Page (Button), ; Button (09h) Usage Minimum (01h), Usage Maximum (10h), Logical Minimum (0), Logical Maximum (1), Report Size (1), Report Count (16), Input (Variable), Usage Page (Desktop), ; Generic desktop controls (01h) Usage (X), ; X (30h, dynamic value) Usage (Y), ; Y (31h, dynamic value) Logical Minimum (-32767), Logical Maximum (32767), Report Size (16), Report Count (2), Input (Variable, Relative), Usage (Wheel), ; Wheel (38h, dynamic value) Report Size (8), Report Count (1), Logical Minimum (-127), Logical Maximum (127), Input (Variable, Relative), Usage Page (Consumer), ; Consumer (0Ch) Usage (AC Pan), ; AC pan (0238h, linear control) Report Count (1), Input (Variable, Relative), End Collection, End Collection Solaar-1.1.20/docs/devices/G604 Wireless Gaming Mouse 4085.txt000066400000000000000000000072361522022367600231570ustar00rootroot00000000000000solaar version 03cfa128 1: G604 Wireless Gaming Mouse Device path : /dev/hidraw6 WPID : 4085 Codename : G604 Kind : mouse Protocol : HID++ 4.2 Report Rate : 1ms Serial number: XXXXXXXX Model ID: B02440850000 Unit ID: XXXXXXXX 1: BL1 04.01.B0014 0: MPM 21.01.B0014 3: The power switch is located on the base. Supports 33 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: 1 BL1 04.01.B0014 0000B01B3067 Firmware: 0 MPM 21.01.B0014 4085B01B3067 Firmware: 3 Unit ID: XXXXXXXX Model ID: B02440850000 Transport IDs: {'btleid': 'B024', 'wpid': '4085'} 3: DEVICE NAME {0005} V0 Name: G604 Wireless Gaming Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 00000000000000000000000000000000 6: BATTERY STATUS {1000} V0 Battery: 30%, BatteryStatus.DISCHARGING, next level 15%. 7: COLOR LED EFFECTS {8070} V4 LED Control (saved): Device LED Control : Device LEDs Primary : None 8: LED CONTROL {1300} V0 9: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Profile 1 Onboard Profiles : Profile 1 10: MOUSE BUTTON SPY {8110} V0 11: REPORT RATE {8060} V0 Report Rate: 1ms Report Rate (saved): 1ms Report Rate : 1ms 12: ADJUSTABLE DPI {2201} V1 Sensitivity (DPI) (saved): 800 Sensitivity (DPI) : 800 13: DFUCONTROL SIGNED {00C2} V0 14: DEVICE RESET {1802} V0 15: unknown:1803 {0318} V0 internal, hidden 16: OOBSTATE {1805} V0 17: CONFIG DEVICE PROPS {1806} V4 18: unknown:1813 {1318} V0 internal, hidden 19: unknown:1830 {3018} V0 internal, hidden 20: unknown:1890 {9018} V0 internal, hidden 21: unknown:1891 {9118} V0 internal, hidden 22: unknown:1861 {6118} V0 internal, hidden 23: unknown:1801 {0118} V0 internal, hidden 24: unknown:18B1 {B118} V0 internal, hidden 25: unknown:1DF3 {F31D} V0 internal, hidden 26: unknown:1E00 {001E} V0 hidden 27: unknown:1EB0 {B01E} V0 internal, hidden 28: unknown:1E22 {221E} V0 internal, hidden 29: HIRES WHEEL {2121} V0 Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 30: unknown:18C0 {C018} V0 internal, hidden 31: CHANGE HOST {1814} V1 Change Host : 1:host1 32: HOSTS INFO {1815} V1 Host 0 (unpaired): host1 Host 1 (paired): Battery: 30%, BatteryStatus.DISCHARGING, next level 15%. Solaar-1.1.20/docs/devices/G613 Wireless Mechanical Gaming Keyboard 4065.txt000066400000000000000000000071471522022367600256330ustar00rootroot00000000000000solaar version 1.1.19-25-g7520c9cc 1: G613 Wireless Mechanical Gaming Keyboard Device path : None WPID : 4065 Codename : G613 Kind : keyboard Protocol : HID++ 4.2 Report Rate : 1ms Serial number: 710EC3A3 Model ID: B34F40650000 Unit ID: 2A923B25 1: BOT 46.00.B0006 0: MPK 05.02.B0021 3: The power switch is located on the unknown. Supports 32 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: 1 BOT 46.00.B0006 00006E86A7BD Firmware: 0 MPK 05.02.B0021 40656E86A7BD Firmware: 3 Unit ID: 2A923B25 Model ID: B34F40650000 Transport IDs: {'btleid': 'B34F', 'wpid': '4065'} 3: DEVICE NAME {0005} V0 Name: G613 Wireless Mechanical Gaming Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 11000000000000000000000000000000 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: G613 7: BATTERY STATUS {1000} V0 Battery: 80%, BatteryStatus.DISCHARGING, next level 50%. 8: CHANGE HOST {1814} V1 Change Host : 1:cosmo 9: HOSTS INFO {1815} V1 Host 0 (paired): cosmo Host 1 (paired): Mi 11 10: REPROG CONTROLS V4 {1B04} V3 Key/Button Diversion (saved): {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular} Key/Button Diversion : {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular} 11: REPORT HID USAGE {1BC0} V1 12: ENCRYPTION {4100} V0 13: KEYBOARD DISABLE BY USAGE {4522} V0 14: KEYBOARD LAYOUT 2 {4540} V0 15: GKEY {8010} V0 Divert G and M Keys (saved): False Divert G and M Keys : False 16: REPORT RATE {8060} V0 Report Rate: 1ms Report Rate (saved): 1ms Report Rate : 1ms 17: DFUCONTROL SIGNED {00C2} V0 18: DEVICE RESET {1802} V0 19: unknown:1803 {0318} V0 internal, hidden 20: CONFIG DEVICE PROPS {1806} V3 21: unknown:1813 {1318} V0 internal, hidden 22: OOBSTATE {1805} V0 23: unknown:1830 {3018} V0 internal, hidden 24: unknown:1890 {9018} V0 internal, hidden 25: unknown:1891 {9118} V0 internal, hidden 26: unknown:18A1 {A118} V0 internal, hidden 27: unknown:1DF3 {F31D} V0 internal, hidden 28: unknown:1E00 {001E} V0 hidden 29: unknown:1EB0 {B01E} V0 internal, hidden 30: unknown:1861 {6118} V0 internal, hidden 31: unknown:18B1 {B118} V0 internal, hidden Has 2 reprogrammable keys: 0: Host Switch Channel 1 , default: Hostswitch Channel 1 => Hostswitch Channel 1 persistently_divertable, divertable, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: Hostswitch Channel 2 => Hostswitch Channel 2 persistently_divertable, divertable, pos:2, group:0, group mask:empty reporting: default Battery: 80%, BatteryStatus.DISCHARGING, next level 50%. Solaar-1.1.20/docs/devices/G703 Wired-Wireless Gaming Mouse 4070.txt000066400000000000000000000035741522022367600242220ustar00rootroot00000000000000 1: G703 Wired/Wireless Gaming Mouse Codename : G703 Kind : mouse Wireless PID : 4070 Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: AFE674F7 Firmware: MPM 14.02.B0007 Bootloader: BOT 64.02.B0007 Other: The power switch is located on the base. Supports 29 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: BATTERY VOLTAGE {1001} 5: unknown:1863 {1863} internal, hidden 6: unknown:18A1 {18A1} internal, hidden 7: unknown:1E00 {1E00} hidden 8: unknown:1E20 {1E20} 9: unknown:1EB0 {1EB0} internal, hidden 10: ADJUSTABLE DPI {2201} Sensitivity (DPI): 1600 11: ANGLE SNAPPING {2230} 12: SURFACE TUNING {2240} 13: REPORT RATE {8060} 14: ONBOARD PROFILES {8100} 15: MOUSE BUTTON SPY {8110} 16: unknown:1850 {1850} internal, hidden 17: DFUCONTROL SIGNED {00C2} 18: unknown:1801 {1801} internal, hidden 19: DEVICE RESET {1802} internal, hidden 20: unknown:1803 {1803} internal, hidden 21: unknown:1890 {1890} internal, hidden 22: unknown:1811 {1811} internal, hidden 23: LATENCY MONITORING {8111} 24: COLOR LED EFFECTS {8070} 25: unknown:1809 {1809} 26: unknown:1830 {1830} internal, hidden 27: OOBSTATE {1805} internal, hidden 28: CONFIG DEVICE PROPS {1806} internal, hidden Battery: 3807mV, discharging, average Solaar-1.1.20/docs/devices/G733 Gaming Headset 0AB5.text000066400000000000000000000035741522022367600220660ustar00rootroot00000000000000Solaar version 1.1.19 G733 Gaming Headset Device path : /dev/hidraw0 USB id : 046d:0AB5 Codename : G733 Headset Kind : headset Protocol : HID++ 4.2 Serial number: Model ID: 0AB500000000 Unit ID: FFFFFFFF 0: U1 37.00.B0131 Supports 9 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: 0 U1 37.00.B0131 0AB5 Unit ID: FFFFFFFF Model ID: 0AB500000000 Transport IDs: {'usbid': '0AB5'} 3: DEVICE NAME {0005} V0 Name: G733 Gaming Headset Kind: None 4: COLOR LED EFFECTS {8070} V3 Sterowanie diodami LED (saved): Device Sterowanie diodami LED : Device Diody LED None (saved): !LEDEffectSetting {ID: 0} Diody LED None : !LEDEffectSetting {ID: 0} Diody LED None (saved): !LEDEffectSetting {ID: 1, color: 131072, ramp: 0} Diody LED None : !LEDEffectSetting {ID: 1, color: 66048, ramp: 0} 5: GKEY {8010} V0 Przekieruj klawisze G i M (saved): False Przekieruj klawisze G i M : False 6: EQUALIZER {8310} V1 Korektor (saved): {0: 5, 1: 4, 2: 3, 3: 5, 4: 5, 5: 5, 6: 4, 7: 3, 8: 4, 9: 5} Korektor : {0: 5, 1: 4, 2: 3, 3: 5, 4: 5, 5: 5, 6: 4, 7: 3, 8: 4, 9: 5} 7: SIDETONE {8300} V0 Efekt lokalny (saved): 0 Efekt lokalny : 0 8: ADC MEASUREMENT {1F20} V4 Battery: 89% 4058mV , BatteryStatus.DISCHARGING. ZarzÄ…dzanie energiÄ… (saved): 30 ZarzÄ…dzanie energiÄ… : 30 Battery: 89% 4058mV , BatteryStatus.DISCHARGING. Solaar-1.1.20/docs/devices/G733 Gaming Headset 0AFE.text000066400000000000000000000034421522022367600221040ustar00rootroot00000000000000solaar version 1.1.11 G733 Gaming Headset Device path : /dev/hidraw3 USB id : 046d:0AFE Codename : G733 Headset New Kind : headset Protocol : HID++ 4.2 Serial number: Model ID: 0AFE00000000 Unit ID: FFFFFFFF Firmware: U2 00.06 Supports 9 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Firmware U2 00.06 0AFE Unit ID: FFFFFFFF Model ID: 0AFE00000000 Transport IDs: {'usbid': '0AFE'} 3: DEVICE NAME {0005} V0 Name: G733 Gaming Headset Kind: None 4: COLOR LED EFFECTS {8070} V3 LED Control (saved): Device LED Control : Device LEDs Logo (saved): !LEDEffectSetting {ID: 0x0} LEDs Logo : !LEDEffectSetting {ID: 0} LEDs Primary (saved): !LEDEffectSetting {ID: 0x1, color: 0x0, ramp: 0x0} LEDs Primary : !LEDEffectSetting {ID: 1, color: 0x10000, ramp: 0x0} 5: GKEY {8010} V0 Divert G and M Keys (saved): False Divert G and M Keys : False 6: EQUALIZER {8310} V1 Equalizer (saved): {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0} Equalizer : {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0} 7: SIDETONE {8300} V0 Sidetone (saved): 0 Sidetone : 0 8: ADC MEASUREMENT {1F20} V4 Battery: 60% 3867mV , discharging. Power Management (saved): 0 Power Management : 0 Battery: 60% 3867mV , discharging. Solaar-1.1.20/docs/devices/G815 Mechanical Keyboard C33F.txt000066400000000000000000000037611522022367600227340ustar00rootroot00000000000000solaar version 1.1.9 1: G815 Mechanical Keyboard Device path : /dev/hidraw2 USB id : 046d:C33F Codename : G815 Kind : keyboard Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: Model ID: C33F00000000 Unit ID: 35304716 Bootloader: BOT 84.00.B0003 Firmware: U1 31.02.B0018 Other: Other: Other: Supports 24 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BOT 84.00.B0003 AAEA Firmware: Firmware U1 31.02.B0018 C33F Firmware: Other Firmware: Other Firmware: Other Unit ID: 35304716 Model ID: C33F00000000 Transport IDs: {'usbid': 'C33F'} 3: DEVICE NAME {0005} V0 Name: G815 RGB MECHANICAL GAMING KEYBOARD Kind: keyboard 4: CONFIG CHANGE {0020} V0 5: DFUCONTROL SIGNED {00C2} V0 6: DFU {00D0} V0 7: REPORT HID USAGE {1BC0} V0 8: KEYBOARD DISABLE BY USAGE {4522} V0 9: KEYBOARD LAYOUT 2 {4540} V0 10: GKEY {8010} V0 Divert G Keys (saved): True Divert G Keys : False 11: MKEYS {8020} V0 M-Key LEDs (saved): {M1:False, M2:False, M3:False} M-Key LEDs : {M1:False, M2:False, M3:False} 12: MR {8030} V0 MR-Key LED (saved): False MR-Key LED : False 13: BRIGHTNESS CONTROL {8040} V0 14: REPORT RATE {8060} V0 Polling Rate (ms): 1 Polling Rate (ms) (saved): 1 Polling Rate (ms) : 1 15: RGB EFFECTS {8071} V0 16: PER KEY LIGHTING V2 {8081} V2 17: ONBOARD PROFILES {8100} V0 Device Mode: Host Onboard Profiles (saved): Disable Onboard Profiles : Disable 18: unknown:1801 {1801} V0 internal, hidden 19: DEVICE RESET {1802} V0 internal, hidden 20: CONFIG DEVICE PROPS {1806} V5 internal, hidden 21: unknown:18B0 {18B0} V0 internal, hidden 22: unknown:1E00 {1E00} V0 hidden 23: unknown:1EB0 {1EB0} V0 internal, hidden Battery status unavailable. Solaar-1.1.20/docs/devices/G903 LIGHTSPEED Wireless Gaming Mouse 4087.txt000066400000000000000000000112631522022367600245670ustar00rootroot00000000000000solaar version 1.1.8rc3+git1940-4e7b6b3 1: G903 LIGHTSPEED Wireless Gaming Mouse w/ HERO Device path : /dev/hidraw13 WPID : 4087 Codename : G903 LS Kind : mouse Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: 3EF038B9 Model ID: 4087C0910000 Unit ID: 3EF038B9 Bootloader: BL1 06.01.B0013 Firmware: MPM 23.01.B0013 Other: The power switch is located on the base. Supports 31 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BL1 06.01.B0013 0000047072FE Firmware: Firmware MPM 23.01.B0013 4087047072FE Firmware: Other Unit ID: 3EF038B9 Model ID: 4087C0910000 Transport IDs: {'wpid': '4087', 'usbid': 'C091'} 3: DEVICE NAME {0005} V0 Name: G903 LIGHTSPEED Wireless Gaming Mouse w/ HERO Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: BATTERY VOLTAGE {1001} V2 Battery: 90% 4079mV , discharging. 7: RGB EFFECTS {8071} V0 8: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Enable Onboard Profiles : Enable 9: MOUSE BUTTON SPY {8110} V0 10: REPORT RATE {8060} V0 Polling Rate (ms): 1 Polling Rate (ms) (saved): 1 Polling Rate (ms) : 1 11: ADJUSTABLE DPI {2201} V1 Sensitivity (DPI) (saved): 6400 Sensitivity (DPI) : 6400 12: DFUCONTROL SIGNED {00C2} V0 13: DEVICE RESET {1802} V0 internal, hidden 14: unknown:1803 {1803} V0 internal, hidden 15: OOBSTATE {1805} V0 internal, hidden 16: CONFIG DEVICE PROPS {1806} V4 internal, hidden 17: unknown:1811 {1811} V0 internal, hidden 18: unknown:1830 {1830} V0 internal, hidden 19: unknown:1890 {1890} V4 internal, hidden 20: unknown:1891 {1891} V4 internal, hidden 21: unknown:18A1 {18A1} V0 internal, hidden 22: unknown:1801 {1801} V0 internal, hidden 23: unknown:18B1 {18B1} V0 internal, hidden 24: unknown:1DF3 {1DF3} V0 internal, hidden 25: unknown:1E00 {1E00} V0 hidden 26: unknown:1EB0 {1EB0} V0 internal, hidden 27: unknown:1863 {1863} V0 internal, hidden 28: unknown:1E22 {1E22} V0 internal, hidden 29: HIRES WHEEL {2121} V0 Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode Low resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): False Scroll Wheel Resolution : False Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 30: unknown:18C0 {18C0} V0 internal, hidden Battery: 90% 4079mV , discharging. 7: Candy companion chip Device path : /dev/hidraw14 Codename : Candy Kind : touchpad Protocol : HID++ 4.2 Serial number: 4E4E9946 Model ID: 405F00000000 Unit ID: 34304713 Firmware: CC 07.00.B0010 Bootloader: BOT 32.00.B0010 Supports 12 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Firmware CC 07.00.B0010 405F Firmware: Bootloader BOT 32.00.B0010 405F Unit ID: 34304713 Model ID: 405F00000000 Transport IDs: {'wpid': '405F'} 3: DEVICE NAME {0005} V0 Name: Candy companion chip Kind: touchpad 4: unknown:18A1 {18A1} V0 internal, hidden 5: unknown:1E00 {1E00} V0 hidden 6: unknown:1EB0 {1EB0} V0 internal, hidden 7: DFUCONTROL SIGNED {00C2} V0 8: unknown:1801 {1801} V0 internal, hidden 9: DEVICE RESET {1802} V0 internal, hidden 10: unknown:1803 {1803} V0 internal, hidden 11: COLOR LED EFFECTS {8070} V4 Battery status unavailable. Solaar-1.1.20/docs/devices/G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard 408E.txt000066400000000000000000000101671522022367600302750ustar00rootroot00000000000000Solaar version 1.1.4 1: G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard Device path : None WPID : 408E Codename : G915 TKL Kind : keyboard Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: F085CB9D Model ID: B35F408EC343 Unit ID: F085CB9D Bootloader: BL1 12.00.B0017 Other: Firmware: MPK 14.01.B0021 Other: Other: The power switch is located on the top left corner. Supports 37 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BL1 12.00.B0017 00008B79E978 Firmware: Other Firmware: Firmware MPK 14.01.B0021 408E5E599E54 Firmware: Other Firmware: Other Unit ID: F085CB9D Model ID: B35F408EC343 Transport IDs: {'btleid': 'B35F', 'wpid': '408E', 'usbid': 'C343'} 3: DEVICE NAME {0005} Name: G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: G915 TKL 7: BATTERY VOLTAGE {1001} Battery: 3923mV, discharging, 70. 8: CHANGE HOST {1814} Change Host : 1:archlinux 9: HOSTS INFO {1815} Host 0 (paired): archlinux Host 1 (paired): 10: RGB EFFECTS {8071} 11: PER KEY LIGHTING V2 {8081} 12: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular} Key/Button Diversion : {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular} 13: REPORT HID USAGE {1BC0} 14: ENCRYPTION {4100} 15: KEYBOARD DISABLE BY USAGE {4522} 16: KEYBOARD LAYOUT 2 {4540} 17: GKEY {8010} Divert G Keys (saved): False Divert G Keys : False 18: MKEYS {8020} M-Key LEDs (saved): {M1:False, M2:False, M3:False} M-Key LEDs : {M1:False, M2:False, M3:False} 19: MR {8030} MR-Key LED (saved): False MR-Key LED : False 20: BRIGHTNESS CONTROL {8040} 21: ONBOARD PROFILES {8100} Device Mode: On-Board Onboard Profiles (saved): Enable Onboard Profiles : Enable 22: REPORT RATE {8060} Polling Rate (ms): 1 Polling Rate (ms) (saved): 1 Polling Rate (ms) : 1 23: DFUCONTROL SIGNED {00C2} 24: DFU {00D0} 25: DEVICE RESET {1802} internal, hidden 26: unknown:1803 {1803} internal, hidden 27: CONFIG DEVICE PROPS {1806} internal, hidden 28: unknown:1813 {1813} internal, hidden 29: OOBSTATE {1805} internal, hidden 30: unknown:1830 {1830} internal, hidden 31: unknown:1890 {1890} internal, hidden 32: unknown:1891 {1891} internal, hidden 33: unknown:18A1 {18A1} internal, hidden 34: unknown:1E00 {1E00} hidden 35: unknown:1EB0 {1EB0} internal, hidden 36: unknown:1861 {1861} internal, hidden Has 2 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default Battery: 3923mV, discharging, 70. Solaar-1.1.20/docs/devices/G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD 407C.text000066400000000000000000000176151522022367600246200ustar00rootroot00000000000000solaar version 1.1.12rc1 1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD Device path : None WPID : 407C Codename : G915 KEYBOARD Kind : keyboard Protocol : HID++ 4.2 Report Rate : 1ms Serial number: A502B0E1 Model ID: B354407CC33E Unit ID: A502B0E1 1: BOT 77.02.B0039 3: 0: MPK 09.03.B0041 3: 3: The power switch is located on the top left corner. Supports 38 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BOT 77.02.B0039 0000EC44D534 Firmware: Other Firmware: Firmware MPK 09.03.B0041 407C3791543D Firmware: Other Firmware: Other Unit ID: A502B0E1 Model ID: B354407CC33E Transport IDs: {'btleid': 'B354', 'wpid': '407C', 'usbid': 'C33E'} 3: DEVICE NAME {0005} V0 Name: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 11000000000000000000000000000000 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: G915 KEYBOARD� 7: BATTERY VOLTAGE {1001} V3 Battery: 80% 3998mV , discharging. 8: CHANGE HOST {1814} V1 Change Host : 1:Yon 9: HOSTS INFO {1815} V1 Host 0 (paired): Yon Host 1 (paired): 10: RGB EFFECTS {8071} V0 RGB Control (saved): Device RGB Control : Device LEDs Logo (saved): !LEDEffectSetting {ID: 1, color: 11546720, intensity: 0, period: 100, ramp: 0, speed: 0} LEDs Logo : HID++ error {'number': 1, 'request': 2799, 'error': 7, 'params': b'\x00'} LEDs Primary (saved): !LEDEffectSetting {ID: 1, color: 16776960, intensity: 0, period: 100, ramp: 0, speed: 0} LEDs Primary : HID++ error {'number': 1, 'request': 2796, 'error': 7, 'params': b'\x01'} 11: PER KEY LIGHTING V2 {8081} V2 Per-key Lighting (saved): {A:white, B:red, C:white, D:white, E:white, F:white, G:white, H:white, I:white, J:white, K:white, L:white, M:white, N:white, O:white, P:white, Q:white, R:white, S:white, T:white, U:white, V:white, W:white, X:white, Y:white, Z:white, 1:white, 2:white, 3:white, 4:white, 5:white, 6:white, 7:white, 8:white, 9:white, 0:white, ENTER:white, ESC:white, BACKSPACE:white, TAB:white, SPACE:white, -:white, =:white, [:white, \:white, KEY 46:white, ~:white, ;:white, ':white, `:white, ,:white, .:white, /:white, CAPS LOCK:white, F1:white, F2:white, F3:white, F4:white, F5:white, F6:white, F7:white, F8:white, F9:white, F10:white, F11:white, F12:white, PRINT:white, SCROLL LOCK:white, PASTE:white, INSERT:white, HOME:white, PAGE UP:white, DELETE:white, END:white, PAGE DOWN:white, RIGHT:white, LEFT:white, DOWN:white, UP:white, NUMLOCK:white, KEYPAD /:white, KEYPAD *:white, KEYPAD -:white, KEYPAD +:white, KEYPAD ENTER:white, KEYPAD 1:white, KEYPAD 2:white, KEYPAD 3:white, KEYPAD 4:white, KEYPAD 5:white, KEYPAD 6:white, KEYPAD 7:white, KEYPAD 8:white, KEYPAD 9:white, KEYPAD 0:white, KEYPAD .:white, KEY 97:white, COMPOSE:white, POWER:white, KEY 100:white, KEY 101:white, KEY 102:white, KEY 103:white, LEFT CTRL:white, LEFT SHIFT:white, LEFT ALT:white, LEFT WINDOWS:white, RIGHT CTRL:white, RIGHT SHIFT:white, RIGHT ALTGR:white, RIGHT WINDOWS:white, BRIGHTNESS:white, PAUSE:white, MUTE:white, NEXT:white, PREVIOUS:white, G1:white, G2:white, G3:white, G4:white, G5:white, LOGO:white} Per-key Lighting : {A:white, B:white, C:white, D:white, E:white, F:white, G:white, H:white, I:white, J:white, K:white, L:white, M:white, N:white, O:white, P:white, Q:white, R:white, S:white, T:white, U:white, V:white, W:white, X:white, Y:white, Z:white, 1:white, 2:white, 3:white, 4:white, 5:white, 6:white, 7:white, 8:white, 9:white, 0:white, ENTER:white, ESC:white, BACKSPACE:white, TAB:white, SPACE:white, -:white, =:white, [:white, \:white, KEY 46:white, ~:white, ;:white, ':white, `:white, ,:white, .:white, /:white, CAPS LOCK:white, F1:white, F2:white, F3:white, F4:white, F5:white, F6:white, F7:white, F8:white, F9:white, F10:white, F11:white, F12:white, PRINT:white, SCROLL LOCK:white, PASTE:white, INSERT:white, HOME:white, PAGE UP:white, DELETE:white, END:white, PAGE DOWN:white, RIGHT:white, LEFT:white, DOWN:white, UP:white, NUMLOCK:white, KEYPAD /:white, KEYPAD *:white, KEYPAD -:white, KEYPAD +:white, KEYPAD ENTER:white, KEYPAD 1:white, KEYPAD 2:white, KEYPAD 3:white, KEYPAD 4:white, KEYPAD 5:white, KEYPAD 6:white, KEYPAD 7:white, KEYPAD 8:white, KEYPAD 9:white, KEYPAD 0:white, KEYPAD .:white, KEY 97:white, COMPOSE:white, POWER:white, KEY 100:white, KEY 101:white, KEY 102:white, KEY 103:white, LEFT CTRL:white, LEFT SHIFT:white, LEFT ALT:white, LEFT WINDOWS:white, RIGHT CTRL:white, RIGHT SHIFT:white, RIGHT ALTGR:white, RIGHT WINDOWS:white, BRIGHTNESS:white, PAUSE:white, MUTE:white, NEXT:white, PREVIOUS:white, G1:white, G2:white, G3:white, G4:white, G5:white, LOGO:white} 12: REPROG CONTROLS V4 {1B04} V4 Key/Button Diversion (saved): {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular} Key/Button Diversion : {Host Switch Channel 1:Regular, Host Switch Channel 2:Regular} 13: REPORT HID USAGE {1BC0} V1 14: ENCRYPTION {4100} V0 15: KEYBOARD DISABLE BY USAGE {4522} V0 16: KEYBOARD LAYOUT 2 {4540} V0 17: GKEY {8010} V0 Divert G and M Keys (saved): False Divert G and M Keys : False 18: MKEYS {8020} V0 M-Key LEDs (saved): {M1:False, M2:False, M3:False} M-Key LEDs : {M1:False, M2:False, M3:False} 19: MR {8030} V0 MR-Key LED (saved): False MR-Key LED : False 20: BRIGHTNESS CONTROL {8040} V0 Brightness Control (saved): 12 Brightness Control : 12 21: ONBOARD PROFILES {8100} V0 Device Mode: Host Onboard Profiles (saved): Disabled Onboard Profiles : Disabled 22: REPORT RATE {8060} V0 Report Rate: 1ms Report Rate (saved): 1ms Report Rate : 1ms 23: DFUCONTROL SIGNED {00C2} V0 24: DFU {00D0} V3 25: DEVICE RESET {1802} V0 internal, hidden 26: unknown:1803 {1803} V0 internal, hidden 27: CONFIG DEVICE PROPS {1806} V8 internal, hidden 28: unknown:1813 {1813} V0 internal, hidden 29: OOBSTATE {1805} V0 internal, hidden 30: unknown:1830 {1830} V0 internal, hidden 31: unknown:1890 {1890} V5 internal, hidden 32: unknown:1891 {1891} V5 internal, hidden 33: unknown:18A1 {18A1} V0 internal, hidden 34: unknown:1E00 {1E00} V0 hidden 35: unknown:1EB0 {1EB0} V0 internal, hidden 36: unknown:1861 {1861} V0 internal, hidden 37: unknown:18B0 {18B0} V0 internal, hidden Has 2 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default Battery: 80% 3998mV , discharging. Solaar-1.1.20/docs/devices/G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD C33E.text000066400000000000000000000104141522022367600246260ustar00rootroot00000000000000solaar version 1.1.10 USB and Bluetooth Devices 1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD Device path : /dev/hidraw13 USB id : 046d:C33E Codename : G915 Kind : ? Protocol : HID++ 4.2 Polling rate : 1 ms (1000Hz) Serial number: Model ID: B354407CC33E Unit ID: 8816D0DF Bootloader: BOT 77.03.B0041 Other: Firmware: MPK 09.04.B0042 Other: Other: Supports 37 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BOT 77.03.B0041 00003791543D Firmware: Other Firmware: Firmware MPK 09.04.B0042 C33E8A23A76B Firmware: Other Firmware: Other Unit ID: 8816D0DF Model ID: B354407CC33E Transport IDs: {'btleid': 'B354', 'wpid': '407C', 'usbid': 'C33E'} 3: DEVICE NAME {0005} V0 Name: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: BATTERY VOLTAGE {1001} V3 Battery: 70% 3965mV , recharging. 7: CHANGE HOST {1814} V1 Changer d'hôte : 1:stagcrown 8: HOSTS INFO {1815} V1 Host 0 (paired): stagcrown Host 1 (paired): 9: RGB EFFECTS {8071} V0 10: PER KEY LIGHTING V2 {8081} V2 11: REPROG CONTROLS V4 {1B04} V4 Interception des boutons/touches (saved): {Host Switch Channel 1:Interception, Host Switch Channel 2:Interception} Interception des boutons/touches : {Host Switch Channel 1:Interception, Host Switch Channel 2:Interception} 12: REPORT HID USAGE {1BC0} V1 13: ENCRYPTION {4100} V0 14: KEYBOARD DISABLE BY USAGE {4522} V0 15: KEYBOARD LAYOUT 2 {4540} V0 16: GKEY {8010} V0 Définir les touches G (saved): True Définir les touches G : False 17: MKEYS {8020} V0 LEDs de touche M (saved): {M1:False, M2:False, M3:False} LEDs de touche M : {M1:False, M2:False, M3:False} 18: MR {8030} V0 LED de touche MR (saved): False LED de touche MR : False 19: BRIGHTNESS CONTROL {8040} V0 20: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Profils embarqués (saved): Enable Profils embarqués : Enable 21: REPORT RATE {8060} V0 Polling Rate (ms): 1 Taux de scrutation (ms) (saved): 1 Taux de scrutation (ms) : 1 22: DFUCONTROL SIGNED {00C2} V0 23: DFU {00D0} V3 24: DEVICE RESET {1802} V0 internal, hidden 25: unknown:1803 {1803} V0 internal, hidden 26: CONFIG DEVICE PROPS {1806} V8 internal, hidden 27: unknown:1813 {1813} V0 internal, hidden 28: OOBSTATE {1805} V0 internal, hidden 29: unknown:1830 {1830} V0 internal, hidden 30: unknown:1890 {1890} V9 internal, hidden 31: unknown:1891 {1891} V9 internal, hidden 32: unknown:18A1 {18A1} V0 internal, hidden 33: unknown:1E00 {1E00} V0 hidden 34: unknown:1EB0 {1EB0} V0 internal, hidden 35: unknown:1861 {1861} V0 internal, hidden 36: unknown:18B0 {18B0} V0 internal, hidden Has 2 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: diverted 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: diverted Battery: 70% 3965mV , recharging. Solaar-1.1.20/docs/devices/G915 WIRELESS RGB Mechanical Gaming Keyboard 407E.txt000066400000000000000000000075321522022367600257120ustar00rootroot00000000000000Solaar version 1.1.1 1: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD Device path : None WPID : 407C Codename : G915 KEYBOARD Kind : keyboard Protocol : HID++ 4.2 Polling rate : 8 ms (125Hz) Serial number: 7FDC464D Model ID: B354407CC33E Unit ID: 7FDC464D Bootloader: BOT 77.01.B0035 Other: Firmware: MPK 09.01.B0035 Other: Other: The power switch is located on the top left corner. Supports 39 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 77.01.B0035 0000691BEBFB Firmware: Other Firmware: Firmware MPK 09.01.B0035 407C691BEBFB Firmware: Other Firmware: Other Unit ID: 7FDC464D Model ID: B354407CC33E Transport IDs: {'btleid': 'B354', 'wpid': '407C', 'usbid': 'C33E'} 3: DEVICE NAME {0005} Name: G915 WIRELESS RGB MECHANICAL GAMING KEYBOARD Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: G915 KEYBOARD 7: BATTERY VOLTAGE {1001} Battery: 3914mV, discharging, 60. 8: CHANGE HOST {1814} Change Host : 1:evoxs 9: HOSTS INFO {1815} Host 0 (paired): evoxs Host 1 (unpaired): 10: RGB EFFECTS {8071} 11: PER KEY LIGHTING V2 {8081} 12: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {'209': 0, '210': 0} Key/Button Diversion : {'209': 0, '210': 0} 13: REPORT HID USAGE {1BC0} 14: ENCRYPTION {4100} 15: KEYBOARD DISABLE BY USAGE {4522} 16: KEYBOARD LAYOUT 2 {4540} 17: GKEY {8010} Divert G Keys (saved): False Divert G Keys : False 18: MKEYS {8020} 19: MR {8030} 20: BRIGHTNESS CONTROL {8040} 21: ONBOARD PROFILES {8100} Device Mode: Host 22: REPORT RATE {8060} Polling Rate (ms): 1 Polling Rate (ms) (saved): 1 Polling Rate (ms) : 1 23: DFUCONTROL SIGNED {00C2} 24: DFU {00D0} 25: DEVICE RESET {1802} internal, hidden 26: unknown:1803 {1803} internal, hidden 27: CONFIG DEVICE PROPS {1806} internal, hidden 28: unknown:1813 {1813} internal, hidden 29: OOBSTATE {1805} internal, hidden 30: unknown:1830 {1830} internal, hidden 31: unknown:1890 {1890} internal, hidden 32: unknown:1891 {1891} internal, hidden 33: unknown:18A1 {18A1} internal, hidden 34: unknown:1DF3 {1DF3} internal, hidden 35: unknown:1E00 {1E00} hidden 36: unknown:1EB0 {1EB0} internal, hidden 37: unknown:1861 {1861} internal, hidden 38: unknown:18B0 {18B0} internal, hidden Has 2 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default Battery: 3914mV, discharging, 60. Solaar-1.1.20/docs/devices/G935 Gaming Headset 0A87.txt000066400000000000000000000022531522022367600217060ustar00rootroot00000000000000Solaar version 1.1.7 1: G935 Gaming Headset Device path : /dev/hidraw2 USB id : 046d:0A87 Codename : G935 Headset Kind : headset Protocol : HID++ 4.2 Serial number: Model ID: 000000000A87 Unit ID: FFFFFFFF Firmware: U1 29.00.B0012 Supports 9 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Firmware U1 29.00.B0012 0A87 Unit ID: FFFFFFFF Model ID: 000000000A87 Transport IDs: {'btid': '0000', 'btleid': '0000'} 3: DEVICE NAME {0005} V0 Name: G935 Gaming Headset Kind: None 4: COLOR LED EFFECTS {8070} V0 5: GKEY {8010} V0 Divert G Keys (saved): False Divert G Keys : False 6: EQUALIZER {8310} V0 7: SIDETONE {8300} V0 Sidetone (saved): 0 Sidetone : 0 8: ADC MEASUREMENT {1F20} V0 Battery status unavailable. Battery status unavailable. Solaar-1.1.20/docs/devices/Illuminated Keyboard C318.txt000066400000000000000000000005351522022367600225260ustar00rootroot00000000000000solaar version 1.1.8-29-g0ae14c7 1: Illuminated Keyboard Device path : /dev/hidraw1 USB id : 046d:C318 Codename : Illuminated Kind : keyboard Protocol : HID++ 1.0 Serial number: Firmware: 55.01.B0025 Notifications: (none). Features: (none) Battery status unavailable. Solaar-1.1.20/docs/devices/Illuminated Living-Room Keyboard K830 4032.txt000066400000000000000000000033561522022367600252350ustar00rootroot00000000000000# Provided by Mikkel Munch Mortensen (solaar) 3: Illuminated Living-Room Keyboard K830 Codename : K830 Kind : keyboard Wireless PID : 4032 Protocol : HID++ 4.1 Polling rate : 8 ms (125Hz) Serial number: 9F7C6FD7 Firmware: RQK 56.00.B0020 The power switch is located on the edge of top right corner. Supports 27 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: WIRELESS DEVICE STATUS {1D4B} 5: unknown:0020 {0020} 6: BATTERY STATUS {1000} 7: BACKLIGHT {1981} 8: unknown:1B04 {1B04} 9: unknown:2005 {2005} 10: NEW FN INVERSION {40A2} 11: ENCRYPTION {4100} 12: unknown:4521 {4521} 13: TOUCHPAD RAW XY {6100} hidden 14: unknown:6501 {6501} 15: unknown:00C1 {00C1} 16: unknown:1811 {1811} internal, hidden 17: unknown:1830 {1830} internal, hidden 18: unknown:1890 {1890} internal, hidden 19: unknown:18A0 {18A0} internal, hidden 20: unknown:1DF3 {1DF3} internal, hidden 21: unknown:1E00 {1E00} hidden 22: unknown:1EB0 {1EB0} internal, hidden 23: unknown:1861 {1861} internal, hidden 24: unknown:1A20 {1A20} internal, hidden 25: unknown:18B0 {18B0} internal, hidden 26: unknown:1F07 {1F07} internal, hidden Battery: 50%, discharging. Solaar-1.1.20/docs/devices/K850 Performance Wireless Keyboard 4062.txt000066400000000000000000000203251522022367600246620ustar00rootroot00000000000000Solaar version 1.1.1 2: K850 Performance Wireless Keyboard Device path : /dev/hidraw2 WPID : 4062 Codename : K850 Kind : keyboard Protocol : HID++ 4.5 Polling rate : 20 ms (50Hz) Serial number: E2A15F0B Model ID: B34D40620000 Unit ID: 178D05AD Bootloader: BOT 43.01.B0004 Firmware: MPK 04.03.B0015 Other: The power switch is located on the edge of top right corner. Supports 31 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 43.01.B0004 00002FD362F001 Firmware: Firmware MPK 04.03.B0015 40622FD362F001 Firmware: Other Unit ID: 178D05AD Model ID: B34D40620000 Transport IDs: {'btleid': 'B34D', 'wpid': '4062'} 3: DEVICE NAME {0005} Name: K850 Performance Wireless Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: Keyboard K850 7: BATTERY STATUS {1000} Battery: 90%, discharging, next level 50%. 8: CHANGE HOST {1814} Change Host : 2:desktop 9: HOSTS INFO {1815} Host 0 (paired): rpi Host 1 (paired): desktop Host 2 (paired): laptop 10: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {'1': 0, '10': 0, '189': 0, '191': 0, '192': 0, '193': 0, '194': 0, '2': 0, '209': 0, '210': 0, '211': 0, '212': 0, '213': 0, '214': 0, '221': 0, '3': 0, '4': 0, '5': 0, '6': 0} Key/Button Diversion : {'209': 0, '210': 0, '211': 0, '213': 0, '214': 0, '189': 0, '212': 0, '6': 0, '4': 0, '5': 0, '3': 0, '2': 0, '1': 0, '194': 0, '221': 0, '191': 0, '10': 0, '193': 0, '192': 0} 11: PERSISTENT REMAPPABLE ACTION {1C00} 12: K375S FN INVERSION {40A3} Swap Fx function (saved): False Swap Fx function : False 13: ENCRYPTION {4100} 14: LOCK KEY STATE {4220} 15: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {'1': False, '16': False, '2': False, '4': False, '8': False} Disable keys : {'1': False, '2': False, '4': False, '8': False, '16': False} 16: MULTIPLATFORM {4531} Set OS (saved): 0 Set OS : Windows 17: DFUCONTROL SIGNED {00C2} 18: unknown:1803 {1803} internal, hidden 19: CONFIG DEVICE PROPS {1806} internal, hidden 20: OOBSTATE {1805} internal, hidden 21: unknown:1813 {1813} internal, hidden 22: unknown:1830 {1830} internal, hidden 23: unknown:1861 {1861} internal, hidden 24: unknown:1890 {1890} internal, hidden 25: unknown:1891 {1891} internal, hidden 26: unknown:18A1 {18A1} internal, hidden 27: unknown:1DF3 {1DF3} internal, hidden 28: unknown:1E00 {1E00} hidden 29: unknown:1EB0 {1EB0} internal, hidden 30: unknown:18B0 {18B0} internal, hidden Has 21 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 3: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 4: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default 5: Multiplatform Back , default: MultiPlatform Back => MultiPlatform Back is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty reporting: default 6: MultiPlatform Search , default: Multiplatform Search => Multiplatform Search is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty reporting: default 7: Previous , default: Previous => Previous is FN, FN sensitive, divertable, persistently divertable, pos:5, group:0, group mask:empty reporting: default 8: Play/Pause , default: Play/Pause => Play/Pause is FN, FN sensitive, divertable, persistently divertable, pos:6, group:0, group mask:empty reporting: default 9: Next , default: Next => Next is FN, FN sensitive, divertable, persistently divertable, pos:7, group:0, group mask:empty reporting: default 10: Mute , default: Mute => Mute is FN, FN sensitive, divertable, persistently divertable, pos:8, group:0, group mask:empty reporting: default 11: Volume Down , default: Volume Down => Volume Down is FN, FN sensitive, divertable, persistently divertable, pos:9, group:0, group mask:empty reporting: default 12: Volume Up , default: Volume Up => Volume Up is FN, FN sensitive, divertable, persistently divertable, pos:10, group:0, group mask:empty reporting: default 13: Multiplatform Lock , default: WindowsLock => WindowsLock is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty reporting: default 14: Multi Platform Language Switch, default: Multiplatform Language Switch => Multiplatform Language Switch is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty reporting: default 15: Screen Capture/Print Screen, default: Screen Capture => Screen Capture is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 16: Calculator , default: Calculator => Calculator is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 17: Fn Up , default: unknown:0070 => unknown:0070 is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 18: Fn Down , default: unknown:006F => unknown:006F is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 19: F Lock , default: Do Nothing One => Do Nothing One is FN, pos:0, group:0, group mask:empty reporting: default 20: unknown:0034 , default: Do Nothing One => Do Nothing One nonstandard, pos:0, group:0, group mask:empty reporting: default Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/K850 Performance Wireless Keyboard B34D.txt000066400000000000000000000227141522022367600247270ustar00rootroot00000000000000Solaar version 1.1.4 2: K850 Performance Wireless Keyboard Device path : /dev/hidraw1 USB id : 046d:B34D Codename : Keyboard K850 Kind : ? Protocol : HID++ 4.5 Serial number: Model ID: B34D40620000 Unit ID: 420F6F9D Bootloader: BOT 43.01.B0004 Firmware: MPK 04.03.B0015 Other: Supports 17 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 43.01.B0004 00002FD362F001 Firmware: Firmware MPK 04.03.B0015 B34D2FD362F001 Firmware: Other Unit ID: 420F6F9D Model ID: B34D40620000 Transport IDs: {'btleid': 'B34D', 'wpid': '4062'} 3: DEVICE NAME {0005} Name: K850 Performance Wireless Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: Keyboard K850 7: BATTERY STATUS {1000} Battery: 90%, discharging, next level 50%. 8: CHANGE HOST {1814} Change Host : 3:shoaib-MacBookPro 9: HOSTS INFO {1815} Host 0 (paired): Host 1 (paired): Shoaib’s MacBook Pro Host 2 (paired): shoaib-MacBookPro 10: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Calculator:Regular, Multiplatform Back:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, MultiPlatform Search:Regular, MultiPlatform Home/Mission Control:Regular, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Regular, Multi Platform Language Switch:Regular} Key/Button Diversion : {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Calculator:Regular, Multiplatform Back:Regular, Screen Capture/Print Screen:Regular, Fn Down:Regular, Fn Up:Regular, Multiplatform Lock:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, MultiPlatform Search:Regular, MultiPlatform Home/Mission Control:Regular, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Regular, Multi Platform Language Switch:Regular} 11: PERSISTENT REMAPPABLE ACTION {1C00} Persistent Key/Button Mapping : {Volume Up:Volume Up, Volume Down:Volume Down, Mute:Mute, Play/Pause:Play/Pause, Next:Scan Next Track, Previous:Scan Previous Track, Calculator:AL Calculator, Multiplatform Back:AC Back, Screen Capture/Print Screen:SYSRQ, Multiplatform Lock:Default, MultiPlatform Search:AC Search, MultiPlatform Home/Mission Control:AC Home, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:COMPOSE, Multi Platform Language Switch:Alt+Shift+No Output} 12: K375S FN INVERSION {40A3} Swap Fx function (saved): False Swap Fx function : False 13: ENCRYPTION {4100} 14: LOCK KEY STATE {4220} 15: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 16: MULTIPLATFORM {4531} Set OS (saved): Windows Set OS : Windows Has 21 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 3: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 4: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default 5: Multiplatform Back , default: MultiPlatform Back => MultiPlatform Back is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:3, group:0, group mask:empty reporting: default 6: MultiPlatform Search , default: Multiplatform Search => Multiplatform Search is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty reporting: default 7: Previous , default: Previous => Previous is FN, FN sensitive, divertable, persistently divertable, pos:5, group:0, group mask:empty reporting: default 8: Play/Pause , default: Play/Pause => Play/Pause is FN, FN sensitive, divertable, persistently divertable, pos:6, group:0, group mask:empty reporting: default 9: Next , default: Next => Next is FN, FN sensitive, divertable, persistently divertable, pos:7, group:0, group mask:empty reporting: default 10: Mute , default: Mute => Mute is FN, FN sensitive, divertable, persistently divertable, pos:8, group:0, group mask:empty reporting: default 11: Volume Down , default: Volume Down => Volume Down is FN, FN sensitive, divertable, persistently divertable, pos:9, group:0, group mask:empty reporting: default 12: Volume Up , default: Volume Up => Volume Up is FN, FN sensitive, divertable, persistently divertable, pos:10, group:0, group mask:empty reporting: default 13: Multiplatform Lock , default: WindowsLock => WindowsLock is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty reporting: default 14: Multi Platform Language Switch, default: Multiplatform Language Switch => Multiplatform Language Switch is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty reporting: default 15: Screen Capture/Print Screen, default: Screen Capture => Screen Capture is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 16: Calculator , default: Calculator => Calculator is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 17: Fn Up , default: unknown:0070 => unknown:0070 is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 18: Fn Down , default: unknown:006F => unknown:006F is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 19: F Lock , default: Do Nothing One => Do Nothing One is FN, pos:0, group:0, group mask:empty reporting: default 20: FN Key , default: Do Nothing One => Do Nothing One nonstandard, pos:0, group:0, group mask:empty reporting: default Has 14 persistent remappable keys: 0: MultiPlatform Home/Mission Control => Consumer: AC Home 1: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad => Key: COMPOSE 2: Multiplatform Back => Consumer: AC Back 3: MultiPlatform Search => Consumer: AC Search 4: Previous => Consumer: Scan Previous Track 5: Play/Pause => Consumer: Play/Pause 6: Next => Consumer: Scan Next Track 7: Mute => Consumer: Mute 8: Volume Down => Consumer: Volume Down 9: Volume Up => Consumer: Volume Up 10: Multiplatform Lock => Unknown 11: Multi Platform Language Switch => Key: Alt+Shift+No Output 12: Screen Capture/Print Screen => Key: SYSRQ 13: Calculator => Consumer: AL Calculator Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/Keyboard K600 TV 4078.txt000066400000000000000000000311601522022367600211730ustar00rootroot00000000000000Solaar version 1.1.7 1: Keyboard K600 TV Device path : /dev/hidraw3 WPID : 4078 Codename : K600 TV Kind : keyboard Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: C4E873FC Model ID: B35340780000 Unit ID: CA575869 Bootloader: BOT 73.00.B0015 Firmware: MPK 08.00.B0015 Other: Other: Supports 36 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BOT 73.00.B0015 00001E30DA07 Firmware: Firmware MPK 08.00.B0015 40781E30DA07 Firmware: Other Firmware: Other Unit ID: CA575869 Model ID: B35340780000 Transport IDs: {'btleid': 'B353', 'wpid': '4078'} 3: DEVICE NAME {0005} V0 Name: Keyboard K600 TV Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: Keyboard K600 T 7: BATTERY STATUS {1000} V1 Battery: 90%, discharging, next level 50%. 8: REPROG CONTROLS V4 {1B04} V4 Desvio de Tecla/Botón (saved): {Fn Left Click:Normal, Multiplatform App Switch:Normal, Multiplatform Back:Normal, Multiplatform Insert:Normal, Brightness Down:Normal, Brightness Up:Normal, Host Switch Channel 1:Normal, Host Switch Channel 2:Normal, Host Switch Channel 3:Normal, MultiPlatform Search:Normal, MultiPlatform Home/Mission Control:Normal, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Normal, Previous Fn:Normal, Play/Pause Fn:Normal, Next Fn:Normal, Mute Fn:Normal, Volume Down Fn:Normal, Volume Up Fn:Normal} Desvio de Tecla/Botón : {Fn Left Click:Normal, Multiplatform App Switch:Normal, Multiplatform Back:Normal, Multiplatform Insert:Normal, Brightness Down:Normal, Brightness Up:Normal, Host Switch Channel 1:Normal, Host Switch Channel 2:Normal, Host Switch Channel 3:Normal, MultiPlatform Search:Normal, MultiPlatform Home/Mission Control:Normal, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Normal, Previous Fn:Normal, Play/Pause Fn:Normal, Next Fn:Normal, Mute Fn:Normal, Volume Down Fn:Normal, Volume Up Fn:Normal} 9: PERSISTENT REMAPPABLE ACTION {1C00} V0 Persistent Key/Button Mapping : {Multiplatform App Switch:No Output (only as default), Multiplatform Back:No Output (only as default), Multiplatform Insert:No Output (only as default), Brightness Down:No Output (only as default), Brightness Up:No Output (only as default), MultiPlatform Search:No Output (only as default), MultiPlatform Home/Mission Control:No Output (only as default), MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:No Output (only as default), Previous Fn:No Output (only as default), Play/Pause Fn:No Output (only as default), Next Fn:No Output (only as default), Mute Fn:No Output (only as default), Volume Down Fn:No Output (only as default), Volume Up Fn:No Output (only as default)} 10: SWAP BUTTON CANCEL {2005} V0 11: CHANGE HOST {1814} V1 Cambiar Host : 1:romanescu 12: HOSTS INFO {1815} V1 Host 0 (paired): romanescu Host 1 (unpaired): Host 2 (unpaired): 13: NEW FN INVERSION {40A2} V0 Fn-swap: enabled Fn-swap default: enabled Intercambiar función Fx (saved): True Intercambiar función Fx : True 14: ENCRYPTION {4100} V0 15: LOCK KEY STATE {4220} V0 16: KEYBOARD DISABLE KEYS {4521} V0 Desactivar teclas (saved): {Caps Lock:False, Insert:False, Win:False} Desactivar teclas : {Caps Lock:False, Insert:False, Win:False} 17: MULTIPLATFORM {4531} V1 Especificar SO (saved): Windows Especificar SO : Windows 18: TOUCHPAD RAW XY {6100} V0 19: GESTURE 2 {6501} V0 Gestos (saved): {1: True, 2: True, 4: True, 5: True, 10: True, 30: True, 34: False, 42: True, 43: True, 45: False, 84: True} Gestos : {1: True, 2: True, 4: True, 5: True, 30: True, 10: True, 45: False, 42: True, 43: True, 84: True, 34: False} Gestures Diversion (saved): {1: False, 2: False, 4: False, 5: False, 10: False, 44: False, 84: False, 85: False, 100: False} Gestures Diversion : {1: False, 2: False, 4: False, 5: False, 10: False, 44: False, 84: False, 85: False, 100: False} Parámetros de gestos (saved): {4: {'scale': 256}} Parámetros de gestos : {4: {'scale': 256}} 20: DFUCONTROL SIGNED {00C2} V0 21: DEVICE RESET {1802} V0 internal, hidden 22: unknown:1803 {1803} V0 internal, hidden 23: CONFIG DEVICE PROPS {1806} V5 internal, hidden 24: unknown:1813 {1813} V0 internal, hidden 25: OOBSTATE {1805} V0 internal, hidden 26: unknown:1830 {1830} V0 internal, hidden 27: unknown:1890 {1890} V2 internal, hidden 28: unknown:1891 {1891} V2 internal, hidden 29: unknown:18A1 {18A1} V0 internal, hidden 30: unknown:1DF3 {1DF3} V0 internal, hidden 31: unknown:1E00 {1E00} V0 hidden 32: unknown:1EB0 {1EB0} V0 internal, hidden 33: unknown:1861 {1861} V0 internal, hidden 34: unknown:18B0 {18B0} V0 internal, hidden 35: unknown:1F11 {1F11} V0 internal, hidden Has 19 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 is FN, FN sensitive, divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 is FN, FN sensitive, divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 is FN, FN sensitive, divertable, persistently divertable, pos:3, group:0, group mask:empty reporting: default 3: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty reporting: default 4: Brightness Down , default: Brightness Down => Brightness Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty reporting: default 5: Brightness Up , default: Brightness Up => Brightness Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty reporting: default 6: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:7, group:0, group mask:empty reporting: default 7: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:8, group:0, group mask:empty reporting: default 8: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:9, group:0, group mask:empty reporting: default 9: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:10, group:0, group mask:empty reporting: default 10: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:11, group:0, group mask:empty reporting: default 11: Volume Up Fn , default: Volume Up => Volume Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:12, group:0, group mask:empty reporting: default 12: Multiplatform Insert , default: Switch Language => Switch Language is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 13: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 14: Multiplatform Back , default: MultiPlatform Back => MultiPlatform Back nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 15: Multiplatform App Switch , default: MultiPlatform App Switch => MultiPlatform App Switch nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 16: MultiPlatform Search , default: Multiplatform Search => Multiplatform Search nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 17: Fn Left Click , default: ShowUI => ShowUI divertable, pos:0, group:0, group mask:empty reporting: default 18: FN Key , default: Do Nothing One => Do Nothing One nonstandard, pos:0, group:0, group mask:empty reporting: default Has 14 persistent remappable keys: 0: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad => None 1: Brightness Down => None 2: Brightness Up => None 3: Previous Fn => None 4: Play/Pause Fn => None 5: Next Fn => None 6: Mute Fn => None 7: Volume Down Fn => None 8: Volume Up Fn => None 9: Multiplatform Insert => None 10: MultiPlatform Home/Mission Control => None 11: Multiplatform Back => None 12: Multiplatform App Switch => None 13: MultiPlatform Search => None Has 16 gesture(s), 1 param(s) and 5 spec(s): Track1Finger Enabled(None): None Diverted:(None) None TapGestures Enabled(None): None Diverted:(None) None Tap1Finger Enabled( 0): True Diverted:( 0) False Tap2Finger Enabled( 1): True Diverted:( 1) False Click1Finger Enabled( 2): True Diverted:( 2) False Click2Finger Enabled( 3): True Diverted:( 3) False TapDrag1Finger Enabled( 4): True Diverted:(None) None DoubleTap1Finger Enabled( 5): True Diverted:( 4) False Scroll2FingerStateless Enabled(None): None Diverted:( 5) False NaturalScrolling Enabled( 6): False Diverted:(None) None Scroll2FingerHoriz Enabled( 7): True Diverted:(None) None Scroll2FingerVert Enabled( 8): True Diverted:(None) None Zoom2FingerStateless Enabled( 9): True Diverted:( 6) False FnClickGestureSuppression Enabled( 10): False Diverted:(None) None TwoFingersPresent Enabled(None): None Diverted:( 7) False DeviceSpecificRawData Enabled(None): None Diverted:( 8) False ScaleFactor Value ( 0): 256 [Default: 256] period unit Spec ( 3): 2048 DVI field width Spec ( 1): 8 field widths Spec ( 2): 8 multiplier Spec ( 5): None resolution Spec ( 4): 4 Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/LIFT For Business B033.txt000066400000000000000000000124011522022367600215430ustar00rootroot00000000000000solaar version 1.1.8 2: LIFT For Business Device path : None WPID : B033 Codename : LIFT B Kind : mouse Protocol : HID++ 4.5 Serial number: A67F904D Model ID: B03300000000 Unit ID: A67F904D Bootloader: BL1 56.01.B0010 Firmware: RBM 21.01.B0010 Other: The power switch is located on the (unknown). Supports 32 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 56.01.B0010 B033B0706FCD Firmware: Firmware RBM 21.01.B0010 B033B0706FCD Firmware: Other Unit ID: A67F904D Model ID: B03300000000 Transport IDs: {'btleid': 'B033'} 3: DEVICE NAME {0005} V0 Name: LIFT For Business Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: CRYPTO ID {0021} V1 7: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: LIFT B 8: UNIFIED BATTERY {1004} V3 Battery: 100%, discharging. 9: REPROG CONTROLS V4 {1B04} V5 Key/Button Actions (saved): {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch} Key/Button Actions : {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, DPI Switch:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, DPI Switch:Regular} 10: CHANGE HOST {1814} V1 Change Host : 1:feathora 11: HOSTS INFO {1815} V2 Host 0 (paired): feathora Host 1 (unpaired): Host 2 (unpaired): 12: XY STATS {2250} V1 13: LOWRES WHEEL {2130} V0 Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 14: ADJUSTABLE DPI {2201} V2 Sensitivity (DPI) (saved): 1600 Sensitivity (DPI) : 1600 15: DFUCONTROL {00C3} V0 16: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 17: unknown:1803 {1803} V0 internal, hidden, unknown:000010 18: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 19: unknown:1816 {1816} V0 internal, hidden, unknown:000010 20: OOBSTATE {1805} V0 internal, hidden 21: unknown:1830 {1830} V0 internal, hidden, unknown:000010 22: unknown:1891 {1891} V7 internal, hidden, unknown:000008 23: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 24: unknown:1E00 {1E00} V0 hidden 25: unknown:1E02 {1E02} V0 internal, hidden 26: unknown:1E22 {1E22} V1 internal, hidden, unknown:000010 27: unknown:1602 {1602} V0 28: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 29: unknown:1861 {1861} V1 internal, hidden, unknown:000010 30: unknown:18B1 {18B1} V0 internal, hidden, unknown:000010 31: unknown:920A {920A} V0 internal, hidden, unknown:000010 Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:empty reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:empty reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 5: DPI Switch , default: DPI Switch => DPI Switch mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 6: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Battery: 100%, discharging. Solaar-1.1.20/docs/devices/LIFT VERTICAL ERGONOMIC MOUSE B031.txt000066400000000000000000000124021522022367600226250ustar00rootroot00000000000000Solaar version 1.1.4 2: LIFT VERTICAL ERGONOMIC MOUSE Device path : None WPID : B031 Codename : LIFT Kind : mouse Protocol : HID++ 4.5 Serial number: E86E35D0 Model ID: B03100000000 Unit ID: E86E35D0 Bootloader: BL1 56.00.B0008 Firmware: RBM 21.00.B0008 Other: The power switch is located on the (unknown). Supports 31 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BL1 56.00.B0008 B0317599BD37 Firmware: Firmware RBM 21.00.B0008 B0317599BD37 Firmware: Other Unit ID: E86E35D0 Model ID: B03100000000 Transport IDs: {'btleid': 'B031'} 3: DEVICE NAME {0005} Name: LIFT VERTICAL ERGONOMIC MOUSE Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: DEVICE FRIENDLY NAME {0007} Friendly Name: LIFT 8: UNIFIED BATTERY {1004} 9: REPROG CONTROLS V4 {1B04} DPI Sliding Adjustment (saved): DPI Switch DPI Sliding Adjustment : Off Mouse Gestures (saved): Off Mouse Gestures : Off Key/Button Actions (saved): {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch} Key/Button Actions : {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, DPI Switch:Diverted} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, DPI Switch:Diverted} 10: CHANGE HOST {1814} Change Host : 1:gtronick 11: HOSTS INFO {1815} Host 0 (paired): gtronick Host 1 (paired): LAP0707 Host 2 (unpaired): 12: XY STATS {2250} 13: LOWRES WHEEL {2130} Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 14: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 2400 Sensitivity (DPI) : 2400 15: DFUCONTROL {00C3} 16: DEVICE RESET {1802} internal, hidden, unknown:000010 17: unknown:1803 {1803} internal, hidden, unknown:000010 18: CONFIG DEVICE PROPS {1806} internal, hidden, unknown:000010 19: unknown:1816 {1816} internal, hidden, unknown:000010 20: OOBSTATE {1805} internal, hidden 21: unknown:1830 {1830} internal, hidden, unknown:000010 22: unknown:1891 {1891} internal, hidden, unknown:000008 23: unknown:18A1 {18A1} internal, hidden, unknown:000010 24: unknown:1E00 {1E00} hidden 25: unknown:1E02 {1E02} internal, hidden 26: unknown:1E22 {1E22} internal, hidden, unknown:000010 27: unknown:1602 {1602} 28: unknown:1EB0 {1EB0} internal, hidden, unknown:000010 29: unknown:1861 {1861} internal, hidden, unknown:000010 30: unknown:18B1 {18B1} internal, hidden, unknown:000010 Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:empty reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:empty reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 5: DPI Switch , default: DPI Switch => DPI Switch mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: diverted, raw XY diverted 6: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Battery: 100%, discharging. Solaar-1.1.20/docs/devices/Lightspeed Receiver C539.txt000066400000000000000000000006561522022367600223640ustar00rootroot00000000000000Solaar version 1.1.4 Lightspeed Receiver Device path : /dev/hidraw8 USB id : 046d:C539 Serial : C1469DD4 Firmware : 39.06.B0040 Bootloader : 02.09 Other : AA.BE Has 1 paired device(s) out of a maximum of 1. Notifications: wireless, software present (0x000900) Device activity counters: (empty) Seen paired with G502 Gaming Mouse 407F Seen paired with G Pro Wireless Gaming Mouse 4079 Solaar-1.1.20/docs/devices/Lightspeed Receiver C53A.txt000066400000000000000000000007101522022367600223630ustar00rootroot00000000000000Lightspeed Receiver Device path : /dev/hidraw9 USB id : 046d:C53A Serial : 5B2B9A98 Firmware : 40.03.B0014 Bootloader : 02.09 Other : AA.CA Has 2 paired device(s) out of a maximum of 1. Notifications: wireless, software present (0x000900) Device activity counters: (empty) Seen as part of a G PowerPlay Wireless Mouse Pad with a Candy companion chip paired a number 7 Seen paired with a G502 Gaming Mouse 407F. Solaar-1.1.20/docs/devices/Lightspeed Receiver C53D.txt000066400000000000000000000006231522022367600223710ustar00rootroot00000000000000Solaar version 1.1.3 Lightspeed Receiver Device path : /dev/hidraw2 USB id : 046d:C53D Serial : C271A999 Firmware : 43.01.B0009 Bootloader : 02.10 Other : AA.D2 Has 1 paired device(s) out of a maximum of 1. Notifications: wireless, software present (0x000900) Device activity counters: (empty) Seen paired with G613 Wireless Mechanical Gaming Keyboard 4065 Solaar-1.1.20/docs/devices/Lightspeed Receiver C53F.txt000066400000000000000000000004641522022367600223760ustar00rootroot00000000000000Lightspeed Receiver Device path : /dev/hidraw3 USB id : 046d:C53F Serial : Firmware : 44.01.B0005 Bootloader : 00.02 Other : AA.DE Has 0 paired device(s) out of a maximum of 1. Notifications: wireless, software present (0x000900) Device activity counters: (empty) Solaar-1.1.20/docs/devices/Lightspeed Receiver C541.txt000066400000000000000000000006271522022367600223530ustar00rootroot00000000000000Solaar version 1.1.1 Lightspeed Receiver Device path : /dev/hidraw4 USB id : 046d:C541 Serial : 18E8EC31 Firmware : 01.01.B0027 Bootloader : 01.27 Other : B9.BC Has 1 paired device(s) out of a maximum of 1. Notifications: wireless, software present (0x000900) Device activity counters: (empty) Seen paired with G915 WIRELESS RGB Mechanical Gaming Keyboard 407E Solaar-1.1.20/docs/devices/Lightspeed Receiver C545.txt000066400000000000000000000006431522022367600223550ustar00rootroot00000000000000Solaar version 1.1.4 Lightspeed Receiver Device path : /dev/hidraw5 USB id : 046d:C545 Serial : AD1567FD Firmware : 02.01.B0006 Bootloader : 00.01 Other : 3D.88 Has 1 paired device(s) out of a maximum of 2. Notifications: wireless, software present (0x000900) Device activity counters: 1=22 Seen paired with G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard 408E Solaar-1.1.20/docs/devices/Lightspeed Receiver C547.txt000066400000000000000000000005731522022367600223610ustar00rootroot00000000000000Solaar version 1.1.3 Lightspeed Receiver Device path : /dev/hidraw6 USB id : 046d:C547 Serial : 9B341CD1 Firmware : 04.02.B0009 Bootloader : 00.05 Other : F3.24 Has 1 paired device(s) out of a maximum of 2. Notifications: wireless, software present (0x000900) Device activity counters: 1=171 Seen paired with the PRO X Wireless 4093 Solaar-1.1.20/docs/devices/Logi Pop Keys B365.txt000066400000000000000000000213451522022367600210460ustar00rootroot00000000000000solaar version 1.1.8 Bolt Receiver Device path : /dev/hidraw2 USB id : 046d:C548 Serial : 31454343464242444143334635323035 Has 1 paired device(s) out of a maximum of 6. Notifications: wireless, software present (0x000900) Device activity counters: 1=28 1: Logi POP Keys Device path : None WPID : B365 Codename : Logi POP Keys Kind : keyboard Protocol : HID++ 4.5 Serial number: D1F99582 Model ID: B36500000000 Unit ID: D1F99582 Bootloader: BL1 44.01.B0008 Firmware: RBK 69.01.B0008 Other: The power switch is located on the (unknown). Supports 31 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 44.01.B0008 B3652BE8BAF4 Firmware: Firmware RBK 69.01.B0008 B3652BE8BAF4 Firmware: Other Unit ID: D1F99582 Model ID: B36500000000 Transport IDs: {'btleid': 'B365'} 3: DEVICE NAME {0005} V0 Name: Logi POP Keys Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: Logi POP Keys 7: UNIFIED BATTERY {1004} V3 Battery: 100%, discharging. 8: REPROG CONTROLS V4 {1B04} V5 Key/Button Diversion (saved): {Show Desktop:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Emoji Smiley Heart Eyes:Regular, Emoji Crying Face:Regular, Emoji Smiley:Regular, Emoji Smilie With Tears:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Mute Microphone:Regular} Key/Button Diversion : {Show Desktop:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Emoji Smiley Heart Eyes:Regular, Emoji Crying Face:Regular, Emoji Smiley:Regular, Emoji Smilie With Tears:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Mute Microphone:Regular} 9: CHANGE HOST {1814} V1 Change Host : 1:astra 10: HOSTS INFO {1815} V2 Host 0 (paired): astra Host 1 (unpaired): Host 2 (unpaired): 11: K375S FN INVERSION {40A3} V0 Swap Fx function (saved): False Swap Fx function : False 12: LOCK KEY STATE {4220} V0 13: KEYBOARD DISABLE KEYS {4521} V0 Disable keys (saved): {Caps Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Insert:False, Win:False} 14: MULTIPLATFORM {4531} V1 Set OS (saved): Windows Set OS : Windows 15: KEYBOARD LAYOUT 2 {4540} V0 16: DFUCONTROL {00C3} V0 17: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 18: unknown:1803 {1803} V0 internal, hidden, unknown:000010 19: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 20: unknown:1816 {1816} V0 internal, hidden, unknown:000010 21: OOBSTATE {1805} V0 internal, hidden 22: unknown:1830 {1830} V0 internal, hidden, unknown:000010 23: unknown:1891 {1891} V7 internal, hidden, unknown:000008 24: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 25: unknown:1E00 {1E00} V0 hidden 26: unknown:1E02 {1E02} V0 internal, hidden 27: unknown:1602 {1602} V0 28: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 29: unknown:1861 {1861} V1 internal, hidden, unknown:000010 30: unknown:18B0 {18B0} V0 internal, hidden, unknown:000010 Has 20 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 is FN, FN sensitive, analytics key events, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 is FN, FN sensitive, analytics key events, pos:2, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 is FN, FN sensitive, analytics key events, pos:3, group:0, group mask:empty reporting: default 3: Show Desktop , default: Show Desktop => Show Desktop is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty reporting: default 4: Snipping Tool , default: Snipping Tool => Snipping Tool is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty reporting: default 5: Mute Microphone , default: Mute Microphone => Mute Microphone is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty reporting: default 6: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty reporting: default 7: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty reporting: default 8: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty reporting: default 9: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty reporting: default 10: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty reporting: default 11: Volume Up Fn , default: Volume Up => Volume Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty reporting: default 12: Voice Dictation , default: Voice Dictation => Voice Dictation nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 13: Emoji Smiley Heart Eyes , default: Emoji Smiling Face With Heart Shaped Eyes => Emoji Smiling Face With Heart Shaped Eyes nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 14: Emoji Crying Face , default: Emoji Loudly Crying Face => Emoji Loudly Crying Face nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 15: Emoji Smiley , default: Emoji Smiley => Emoji Smiley nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 16: Emoji Smilie With Tears , default: Emoji Smiley With Tears => Emoji Smiley With Tears nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 17: Open Emoji Panel , default: Open Emoji Panel => Open Emoji Panel nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 18: F Lock , default: Do Nothing One => Do Nothing One is FN, analytics key events, pos:0, group:0, group mask:empty reporting: default 19: FN Key , default: Do Nothing One => Do Nothing One nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default Battery: 100%, discharging. Solaar-1.1.20/docs/devices/Logitech G933 Gaming Wireless Headset 0A5B.txt000066400000000000000000000036551522022367600252200ustar00rootroot00000000000000solaar version 1.1.19-25-g7520c9cc Logitech G933 Gaming Wireless Headset Device path : /dev/hidraw4 USB id : 046d:0A5B Codename : Logitech Kind : ? Protocol : HID++ 4.2 Serial number: Model ID: 000000000A5B Unit ID: FFFFFFFF 0: U 98.03.B0027 Supports 9 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: 0 U 98.03.B0027 0A5B Unit ID: FFFFFFFF Model ID: 000000000A5B Transport IDs: {'btid': '0000', 'btleid': '0000'} 3: DEVICE NAME {0005} V0 Name: Logitech G933 Gaming Wireless Headset Kind: None 4: COLOR LED EFFECTS {8070} V3 LED Control : HID++ error {'number': 255, 'request': 1147, 'error': 7, 'params': b''} LEDs None (saved): !LEDEffectSetting {ID: 0} LEDs None : !LEDEffectSetting {ID: 0} LEDs None (saved): !LEDEffectSetting {ID: 0, color: 9519532, intensity: 0, period: 100, ramp: 0, speed: 0} LEDs None : !LEDEffectSetting {ID: 1, color: 0, ramp: 0} 5: GKEY {8010} V0 Divert G and M Keys (saved): False Divert G and M Keys : False 6: EQUALIZER {8310} V1 Equalizer (saved): {0: 8, 1: 8, 2: 4, 3: 2, 4: 1, 5: 4, 6: 7, 7: 10, 8: 5, 9: 11} Equalizer : {0: 8, 1: 8, 2: 4, 3: 2, 4: 1, 5: 4, 6: 7, 7: 10, 8: 5, 9: 11} 7: SIDETONE {8300} V0 Sidetone (saved): 30 Sidetone : 30 8: ADC MEASUREMENT {1F20} V3 Battery: 100% 4183mV , BatteryStatus.RECHARGING. Power Management (saved): 30 Power Management : 30 Battery: 100% 4183mV , BatteryStatus.RECHARGING. Solaar-1.1.20/docs/devices/Logitech PRO X Wireless Gaming Headset 0ABA.txt000066400000000000000000000034551522022367600254350ustar00rootroot00000000000000 1: Logitech PRO X Wireless Gaming Headset Device path : /dev/hidraw2 USB id : 046d:0ABA Codename : PRO Headset Kind : headset Protocol : HID++ 4.2 Serial number: Model ID: 000000000ABA Unit ID: FFFFFFFF Firmware: U1 12.01.B0203 Supports 6 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Firmware U1 12.01.B0203 0ABA Unit ID: FFFFFFFF Model ID: 000000000ABA Transport IDs: {'btid': '0000', 'btleid': '0000'} 3: DEVICE NAME {0005} Name: PRO X Wireless Gaming Headset Kind: None 4: EQUALIZER {8310} 5: SIDETONE {8300} 6: ADC MEASUREMENT {1F20} Battery status unavailable. 2: Logitech PRO X Wireless Gaming Headset Device path : /dev/hidraw5 USB id : 046d:0ABA Codename : PRO Headset Kind : headset Protocol : HID++ 4.2 Serial number: Model ID: 000000000ABA Unit ID: FFFFFFFF Firmware: U1 12.01.B0203 Supports 6 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Firmware U1 12.01.B0203 0ABA Unit ID: FFFFFFFF Model ID: 000000000ABA Transport IDs: {'btid': '0000', 'btleid': '0000'} 3: DEVICE NAME {0005} Name: PRO X Wireless Gaming Headset Kind: None 4: EQUALIZER {8310} 5: SIDETONE {8300} Sidetone (saved): 0 Sidetone : 0 Battery status unavailable. Solaar-1.1.20/docs/devices/M720 Triathlon Multi-Device Mouse 405E.txt000066400000000000000000000137641522022367600244400ustar00rootroot00000000000000Solaar version 1.1.1 1: M720 Triathlon Multi-Device Mouse Device path : /dev/hidraw1 WPID : 405E Codename : M720 Triathlon Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 205F2717 Model ID: B015405E0000 Unit ID: C738473C Bootloader: BOT 34.01.B0005 Firmware: MPM 04.10.B0013 Other: The power switch is located on the base. Supports 36 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 34.01.B0005 000000A96719 Firmware: Firmware MPM 04.10.B0013 405E00A96719 Firmware: Other Unit ID: C738473C Model ID: B015405E0000 Transport IDs: {'btleid': 'B015', 'wpid': '405E'} 3: DEVICE NAME {0005} Name: M720 Triathlon Multi-Device Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: DEVICE FRIENDLY NAME {0007} Friendly Name: M720 Triathlon 8: BATTERY STATUS {1000} Battery: 90%, discharging, next level 50%. 9: CHANGE HOST {1814} Change Host : 2:desktop 10: HOSTS INFO {1815} Host 0 (paired): rpi Host 1 (paired): desktop Host 2 (paired): laptop 11: REPROG CONTROLS V4 {1B04} Key/Button Actions (saved): {'208': 208, '80': 80, '81': 81, '82': 82, '83': 83, '86': 86, '91': 91, '93': 93} Key/Button Actions : {'80': 80, '81': 81, '82': 82, '83': 83, '86': 86, '91': 91, '93': 93, '208': 208} Key/Button Diversion (saved): {'208': 0, '82': 0, '83': 0, '86': 0, '91': 0, '93': 0} Key/Button Diversion : {'82': 0, '83': 0, '86': 0, '91': 0, '93': 0, '208': 0} 12: PERSISTENT REMAPPABLE ACTION {1C00} 13: POINTER SPEED {2205} Pointer Speed: 1.0 Sensitivity (Pointer Speed) (saved): 256 Sensitivity (Pointer Speed) : 256 14: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 15: DFUCONTROL UNSIGNED {00C1} 16: DFUCONTROL SIGNED {00C2} 17: DEVICE RESET {1802} internal, hidden 18: unknown:1803 {1803} internal, hidden 19: CONFIG DEVICE PROPS {1806} internal, hidden 20: OOBSTATE {1805} internal, hidden 21: unknown:1813 {1813} internal, hidden 22: unknown:1830 {1830} internal, hidden 23: unknown:1861 {1861} internal, hidden 24: unknown:1890 {1890} internal, hidden 25: unknown:1891 {1891} internal, hidden 26: unknown:18A1 {18A1} internal, hidden 27: unknown:1DF3 {1DF3} internal, hidden 28: unknown:1E00 {1E00} hidden 29: unknown:1EB0 {1EB0} internal, hidden 30: unknown:18B1 {18B1} internal, hidden 31: unknown:1850 {1850} internal, hidden 32: unknown:1E22 {1E22} 33: unknown:1F03 {1F03} internal, hidden 34: unknown:18C0 {18C0} internal, hidden 35: HIRES WHEEL {2121} Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Has 9 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 5: Left Tilt , default: Mouse Scroll Left Button => Mouse Scroll Left Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 6: Right Tilt , default: Mouse Scroll Right Button => Mouse Scroll Right Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 7: MultiPlatform Gesture Button, default: Multiplatform Gesture Button => Multiplatform Gesture Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 8: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/M720 Triathlon Multi-Device Mouse B015.txt000066400000000000000000000155321522022367600244250ustar00rootroot00000000000000Solaar version 1.1.4 1: M720 Triathlon Multi-Device Mouse Device path : /dev/hidraw0 USB id : 046d:B015 Codename : M720 Triathlon Kind : mouse Protocol : HID++ 4.5 Serial number: Model ID: B015405E0000 Unit ID: E167BBCD Bootloader: BOT 34.01.B0005 Firmware: MPM 04.10.B0013 Other: Supports 30 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 34.01.B0005 000000A96719 Firmware: Firmware MPM 04.10.B0013 B01500A96719 Firmware: Other Unit ID: E167BBCD Model ID: B015405E0000 Transport IDs: {'btleid': 'B015', 'wpid': '405E'} 3: DEVICE NAME {0005} Name: M720 Triathlon Multi-Device Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: DEVICE FRIENDLY NAME {0007} Friendly Name: M720 Triathlon 8: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 9: CHANGE HOST {1814} Change Host : 3:shoaib-MacBookPro 10: HOSTS INFO {1815} Host 0 (paired): Host 1 (paired): Shoaib’s MacBook Pro Host 2 (paired): shoaib-MacBookPro 11: REPROG CONTROLS V4 {1B04} Mouse Gestures (saved): Off Mouse Gestures : Off Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button, MultiPlatform Gesture Button:Multiplatform Gesture Button} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button, MultiPlatform Gesture Button:Multiplatform Gesture Button} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular, MultiPlatform Gesture Button:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular, MultiPlatform Gesture Button:Regular} 12: PERSISTENT REMAPPABLE ACTION {1C00} Persistent Key/Button Mapping : {Left Button:Mouse Button Left, Right Button:Mouse Button Right, Middle Button:Mouse Button Middle, Back Button:Mouse Button Back, Forward Button:Mouse Button Forward, Left Tilt:Horizontal Scroll Left, Right Tilt:Horizontal Scroll Right, MultiPlatform Gesture Button:Alt+Cntrl+TAB} 13: POINTER SPEED {2205} Pointer Speed: 1.0 Sensitivity (Pointer Speed) (saved): 256 Sensitivity (Pointer Speed) : 256 14: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 15: DFUCONTROL UNSIGNED {00C1} 16: DFUCONTROL SIGNED {00C2} 17: unknown:1803 {1803} internal, hidden 18: unknown:1813 {1813} internal, hidden 19: unknown:1830 {1830} internal, hidden 20: unknown:18A1 {18A1} internal, hidden 21: unknown:1DF3 {1DF3} internal, hidden 22: unknown:1E00 {1E00} hidden 23: unknown:1EB0 {1EB0} internal, hidden 24: unknown:1861 {1861} internal, hidden 25: unknown:18B1 {18B1} internal, hidden 26: unknown:1850 {1850} internal, hidden 27: unknown:1E22 {1E22} 28: unknown:1F03 {1F03} internal, hidden 29: unknown:18C0 {18C0} internal, hidden Has 9 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 5: Left Tilt , default: Mouse Scroll Left Button => Mouse Scroll Left Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 6: Right Tilt , default: Mouse Scroll Right Button => Mouse Scroll Right Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 7: MultiPlatform Gesture Button, default: Multiplatform Gesture Button => Multiplatform Gesture Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 8: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Has 8 persistent remappable keys: 0: Left Button => Mouse Button: Mouse Button Left 1: Right Button => Mouse Button: Mouse Button Right 2: Middle Button => Mouse Button: Mouse Button Middle 3: Back Button => Mouse Button: Mouse Button Back 4: Forward Button => Mouse Button: Mouse Button Forward 5: Left Tilt => Horizontal Scroll: Horizontal Scroll Left 6: Right Tilt => Horizontal Scroll: Horizontal Scroll Right 7: MultiPlatform Gesture Button => Key: Alt+Cntrl+TAB Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/MX Anywhere 3 4090.txt000066400000000000000000000130601522022367600207230ustar00rootroot00000000000000Solaar version 1.1.4 1: MX Anywhere 3 Device path : /dev/hidraw3 WPID : 4090 Codename : MX Anywhere 3 Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 8F4A05EA Model ID: B02540900000 Unit ID: 8F4A05EA Bootloader: BL1 13.01.B0015 Firmware: MPM 24.01.B0015 Other: The power switch is located on the base. Supports 32 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 13.01.B0015 0000AACD8D78 Firmware: Firmware MPM 24.01.B0015 4090AACD8D78 Firmware: Other Unit ID: 8F4A05EA Model ID: B02540900000 Transport IDs: {'btleid': 'B025', 'wpid': '4090'} 3: DEVICE NAME {0005} V0 Name: MX Anywhere 3 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: CRYPTO ID {0021} V1 7: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX Anywhere 3 8: UNIFIED BATTERY {1004} V0 Battery: 65%, discharging. 9: REPROG CONTROLS V4 {1B04} V5 Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Regular} 10: CHANGE HOST {1814} V1 Change Host : 1:apollo 11: XY STATS {2250} V1 12: ADJUSTABLE DPI {2201} V1 Sensibilidade (DPI) (saved): 4000 Sensibilidade (DPI) : 4000 13: SMART SHIFT ENHANCED {2111} V0 Scroll Wheel Rachet (saved): 12 Scroll Wheel Rachet : 12 14: HIRES WHEEL {2121} V1 Multiplier: 15 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode Low resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): False Scroll Wheel Resolution : False Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 15: WHEEL STATS {2251} V0 16: DFUCONTROL SIGNED {00C2} V0 17: DEVICE RESET {1802} V0 internal, hidden 18: unknown:1803 {1803} V0 internal, hidden 19: CONFIG DEVICE PROPS {1806} V7 internal, hidden 20: unknown:1812 {1812} V0 internal, hidden 21: OOBSTATE {1805} V0 internal, hidden 22: unknown:1830 {1830} V0 internal, hidden 23: unknown:1890 {1890} V5 internal, hidden 24: unknown:1891 {1891} V5 internal, hidden 25: unknown:18A1 {18A1} V0 internal, hidden 26: unknown:1E00 {1E00} V0 hidden 27: unknown:1EB0 {1EB0} V0 internal, hidden 28: unknown:1861 {1861} V0 internal, hidden 29: unknown:9001 {9001} V0 internal, hidden 30: unknown:1E22 {1E22} V0 internal, hidden 31: unknown:9205 {9205} V0 internal, hidden Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 5: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 6: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Battery: 65%, discharging. Solaar-1.1.20/docs/devices/MX Anywhere 3 B025.txt000066400000000000000000000125261522022367600207450ustar00rootroot00000000000000Solaar version 1.1.4 1: MX Anywhere 3 Device path : /dev/hidraw1 USB id : 046d:B025 Codename : MX Anywhere 3 Kind : mouse Protocol : HID++ 4.5 Serial number: Model ID: B02540900000 Unit ID: 179ADDDA Bootloader: BL1 13.00.B0014 Firmware: MPM 24.00.B0014 Other: Supports 29 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BL1 13.00.B0014 000095D7D19A Firmware: Firmware MPM 24.00.B0014 B02595D7D19A Firmware: Other Unit ID: 179ADDDA Model ID: B02540900000 Transport IDs: {'btleid': 'B025', 'wpid': '4090'} 3: DEVICE NAME {0005} Name: MX Anywhere 3 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: DEVICE FRIENDLY NAME {0007} Friendly Name: MX Anywhere 3 8: UNIFIED BATTERY {1004} Battery: N/A, None. 9: REPROG CONTROLS V4 {1B04} DPI Sliding Adjustment (saved): Off DPI Sliding Adjustment : Off Mouse Gestures (saved): Off Mouse Gestures : Off Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Regular} 10: CHANGE HOST {1814} Change Host : 1:zerocool 11: XY STATS {2250} 12: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 1000 Sensitivity (DPI) : 1000 13: SMART SHIFT ENHANCED {2111} Scroll Wheel Rachet (saved): 12 Scroll Wheel Rachet : 12 14: HIRES WHEEL {2121} Multiplier: 15 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode Low resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): False Scroll Wheel Resolution : False Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 15: WHEEL STATS {2251} 16: DFUCONTROL SIGNED {00C2} 17: DEVICE RESET {1802} internal, hidden 18: unknown:1803 {1803} internal, hidden 19: CONFIG DEVICE PROPS {1806} internal, hidden 20: unknown:1812 {1812} internal, hidden 21: OOBSTATE {1805} internal, hidden 22: unknown:1830 {1830} internal, hidden 23: unknown:18A1 {18A1} internal, hidden 24: unknown:1E00 {1E00} hidden 25: unknown:1EB0 {1EB0} internal, hidden 26: unknown:1861 {1861} internal, hidden 27: unknown:9300 {9300} internal, hidden 28: unknown:9001 {9001} internal, hidden Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 5: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 6: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Battery: N/A, None. Solaar-1.1.20/docs/devices/MX Anywhere 3 for Business B02D.txt000066400000000000000000000130041522022367600232770ustar00rootroot00000000000000solaar version 1.1.14 1: MX Anywhere 3 for Business Device path : None WPID : B02D Codename : MX Anywhere 3 Kind : mouse Protocol : HID++ 4.5 Serial number: 00000000 Model ID: B02D00000000 Unit ID: 00000000 1: BL1 36.01.B0011 0: RBM 15.01.B0011 3: The power switch is located on the (unknown). Supports 35 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: 1 BL1 36.01.B0011 B02D1EEFD8F8 Firmware: 0 RBM 15.01.B0011 B02D1EEFD8F8 Firmware: 3 Unit ID: 00000000 Model ID: B02D00000000 Transport IDs: {'btleid': 'B02D'} 3: DEVICE NAME {0005} V0 Name: MX Anywhere 3 for Business Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 11000000000000000000000000000000 6: CRYPTO ID {0021} V1 7: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX Anywhere 3B 8: UNIFIED BATTERY {1004} V3 Battery: 75%, 0. 9: REPROG CONTROLS V4 {1B04} V5 Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Smart Shift:Smart Shift} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Smart Shift:Diverted} 10: CHANGE HOST {1814} V1 Change Host : 2:archlinux 11: HOSTS INFO {1815} V2 Host 0 (paired): archlinux Host 1 (paired): archlinux Host 2 (unpaired): 12: XY STATS {2250} V1 13: ADJUSTABLE DPI {2201} V2 Sensitivity (DPI) : 1000 14: SMART SHIFT ENHANCED {2111} V0 Scroll Wheel Ratcheted : Ratcheted Scroll Wheel Ratchet Speed : 15 15: HIRES WHEEL {2121} V1 Multiplier: 15 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode Low resolution mode HID notification Scroll Wheel Direction : False Scroll Wheel Resolution : False Scroll Wheel Diversion : False 16: WHEEL STATS {2251} V0 17: DFUCONTROL {00C3} V0 18: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 19: unknown:1803 {1803} V0 internal, hidden, unknown:000010 20: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 21: unknown:1816 {1816} V0 internal, hidden, unknown:000010 22: OOBSTATE {1805} V0 internal, hidden 23: unknown:1830 {1830} V0 internal, hidden, unknown:000010 24: unknown:1891 {1891} V7 internal, hidden, unknown:000008 25: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 26: unknown:1E00 {1E00} V0 hidden 27: unknown:1E02 {1E02} V0 internal, hidden 28: unknown:1602 {1602} V0 29: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 30: unknown:1861 {1861} V1 internal, hidden, unknown:000010 31: unknown:9300 {9300} V1 internal, hidden, unknown:000010 32: unknown:9001 {9001} V0 internal, hidden, unknown:000010 33: unknown:1E22 {1E22} V0 internal, hidden, unknown:000010 34: unknown:9205 {9205} V0 internal, hidden, unknown:000010 Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 5: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: diverted, raw XY diverted 6: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Battery: 75%, 0. Solaar-1.1.20/docs/devices/MX Ergo Multi-Device Trackball 406F.txt000066400000000000000000000161041522022367600240670ustar00rootroot00000000000000Solaar version 1.1.4 1: MX Ergo Multi-Device Trackball Device path : /dev/hidraw4 WPID : 406F Codename : MX Ergo Kind : trackball Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 0E0F20E7 Model ID: B01D406F0000 Unit ID: 13AF9325 Bootloader: BOT 49.00.B0001 Firmware: MPM 06.03.B0022 Other: The power switch is located on the base. Supports 35 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 49.00.B0001 0000CDE885F3 Firmware: Firmware MPM 06.03.B0022 406FCDE885F3 Firmware: Other Unit ID: 13AF9325 Model ID: B01D406F0000 Transport IDs: {'btleid': 'B01D', 'wpid': '406F'} 3: DEVICE NAME {0005} Name: MX Ergo Multi-Device Trackball Kind: trackball 4: WIRELESS DEVICE STATUS {1D4B} 5: DEVICE FRIENDLY NAME {0007} Friendly Name: MX Ergo 6: RESET {0020} 7: CRYPTO ID {0021} 8: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 9: LED CONTROL {1300} 10: REPROG CONTROLS V4 {1B04} Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button, DPI Change:DPI Change} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button, DPI Change:DPI Change} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular, DPI Change:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular, DPI Change:Regular} 11: PERSISTENT REMAPPABLE ACTION {1C00} Persistent Key/Button Mapping : {Left Button:Mouse Button Left, Right Button:Mouse Button Right, Middle Button:Mouse Button Middle, Back Button:Mouse Button Back, Forward Button:Mouse Button Forward, Left Tilt:Horizontal Scroll Left, Right Tilt:Horizontal Scroll Right, DPI Change:Mouse Button DPI} 12: POINTER AXIS ORIENTATION {2006} 13: POINTER SPEED {2205} Pointer Speed: 1.046875 Sensitivity (Pointer Speed) (saved): 268 Sensitivity (Pointer Speed) : 268 Sensitivity Switching (saved): Off Sensitivity Switching : Off 14: VERTICAL SCROLLING {2100} Roller type: standard Ratchet per turn: 18 Scroll lines: 0 15: DFUCONTROL SIGNED {00C2} 16: DEVICE RESET {1802} internal, hidden 17: unknown:1803 {1803} internal, hidden 18: CONFIG DEVICE PROPS {1806} internal, hidden 19: OOBSTATE {1805} internal, hidden 20: unknown:1813 {1813} internal, hidden 21: CHANGE HOST {1814} Change Host : 1:razorback 22: HOSTS INFO {1815} Host 0 (paired): razorback Host 1 (unpaired): Host 2 (unpaired): 23: unknown:1830 {1830} internal, hidden 24: unknown:1861 {1861} internal, hidden 25: unknown:1890 {1890} internal, hidden 26: unknown:1891 {1891} internal, hidden 27: unknown:18A1 {18A1} internal, hidden 28: unknown:1DF3 {1DF3} internal, hidden 29: unknown:1E00 {1E00} hidden 30: unknown:1EB0 {1EB0} internal, hidden 31: unknown:18B1 {18B1} internal, hidden 32: unknown:1850 {1850} internal, hidden 33: unknown:1F03 {1F03} internal, hidden 34: unknown:18C0 {18C0} internal, hidden Has 9 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 5: DPI Change , default: DPI Change => DPI Change mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 6: Left Tilt , default: Mouse Scroll Left Button => Mouse Scroll Left Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 7: Right Tilt , default: Mouse Scroll Right Button => Mouse Scroll Right Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 8: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Has 8 persistent remappable keys: 0: Left Button => Mouse Button: Mouse Button Left 1: Right Button => Mouse Button: Mouse Button Right 2: Middle Button => Mouse Button: Mouse Button Middle 3: Back Button => Mouse Button: Mouse Button Back 4: Forward Button => Mouse Button: Mouse Button Forward 5: DPI Change => Mouse Button: Mouse Button DPI 6: Left Tilt => Horizontal Scroll: Horizontal Scroll Left 7: Right Tilt => Horizontal Scroll: Horizontal Scroll Right Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/MX Keys Keyboard 408A.txt000066400000000000000000000247471522022367600215100ustar00rootroot00000000000000Solaar version 1.1.4 1: MX Keys Keyboard Device path : /dev/hidraw1 WPID : 408A Codename : MX Keys Kind : keyboard Protocol : HID++ 4.5 Polling rate : 20 ms (50Hz) Serial number: F359F7AC Model ID: B35B408A0000 Unit ID: F359F7AC Bootloader: BL1 08.00.B0011 Firmware: MPK 12.00.B0011 Other: The power switch is located on the edge of top right corner. Supports 32 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BL1 08.00.B0011 00008169E8BB Firmware: Firmware MPK 12.00.B0011 408A8169E8BB Firmware: Other Unit ID: F359F7AC Model ID: B35B408A0000 Transport IDs: {'btleid': 'B35B', 'wpid': '408A'} 3: DEVICE NAME {0005} V0 Name: MX Keys Wireless Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX Keys 7: BATTERY STATUS {1000} V1 Battery: 50%, discharging, next level 20%. 8: REPROG CONTROLS V4 {1B04} V4 Key/Button Diversion (saved): {Calculator:Regular, Show Desktop:Regular, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular} Key/Button Diversion : {Calculator:Regular, Show Desktop:Regular, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular} 9: CHANGE HOST {1814} V1 10: HOSTS INFO {1815} V1 Host 0 (paired): brandy Host 1 (paired): Pixel 2 Host 2 (paired): devlaptop002 11: BACKLIGHT2 {1982} V1 Backlight (saved): True Backlight : True 12: K375S FN INVERSION {40A3} V0 Swap Fx function (saved): False Swap Fx function : False 13: ENCRYPTION {4100} V0 14: LOCK KEY STATE {4220} V0 15: KEYBOARD DISABLE KEYS {4521} V0 Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 16: MULTIPLATFORM {4531} V1 Set OS (saved): Windows Set OS : Windows 17: DFUCONTROL SIGNED {00C2} V0 18: DEVICE RESET {1802} V0 internal, hidden 19: unknown:1803 {1803} V0 internal, hidden 20: CONFIG DEVICE PROPS {1806} V5 internal, hidden 21: unknown:1813 {1813} V0 internal, hidden 22: OOBSTATE {1805} V0 internal, hidden 23: unknown:1830 {1830} V0 internal, hidden 24: unknown:1890 {1890} V5 internal, hidden 25: unknown:1891 {1891} V5 internal, hidden 26: unknown:18A1 {18A1} V0 internal, hidden 27: unknown:1DF3 {1DF3} V0 internal, hidden 28: unknown:1E00 {1E00} V0 hidden 29: unknown:1EB0 {1EB0} V0 internal, hidden 30: unknown:1861 {1861} V0 internal, hidden 31: unknown:1A20 {1A20} V0 internal, hidden Has 24 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 3: Brightness Down , default: Brightness Down => Brightness Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:1, group:0, group mask:empty reporting: default 4: Brightness Up , default: Brightness Up => Brightness Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:2, group:0, group mask:empty reporting: default 5: Mission Control/Task View , default: Mission Control/Task View => Mission Control/Task View is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:3, group:0, group mask:empty reporting: default 6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:4, group:0, group mask:empty reporting: default 7: Show Desktop , default: Show Desktop => Show Desktop is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:5, group:0, group mask:empty reporting: default 8: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:6, group:0, group mask:empty reporting: default 9: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:7, group:0, group mask:empty reporting: default 10: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:8, group:0, group mask:empty reporting: default 11: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:9, group:0, group mask:empty reporting: default 12: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:10, group:0, group mask:empty reporting: default 13: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:11, group:0, group mask:empty reporting: default 14: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:12, group:0, group mask:empty reporting: default 15: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 16: Calculator , default: Calculator => Calculator nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 17: Screen Capture/Print Screen, default: Screen Capture => Screen Capture nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 19: Lock PC , default: WindowsLock => WindowsLock nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 20: Left Arrow , default: Keyboard Left Arrow => Keyboard Left Arrow nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 21: Right Arrow , default: Keyboard Right Arrow => Keyboard Right Arrow nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 22: F Lock , default: Do Nothing One => Do Nothing One is FN, analytics key events, pos:0, group:0, group mask:empty reporting: default 23: FN Key , default: Do Nothing One => Do Nothing One nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/MX Keys Keyboard B35B.txt000066400000000000000000000241531522022367600215160ustar00rootroot00000000000000Solaar version 1.1.4rc1 1: MX Keys Keyboard Device path : /dev/hidraw8 USB id : 046d:B35B Codename : MX Keys Kind : keyboard Protocol : HID++ 4.5 Serial number: Model ID: B35B408A0000 Unit ID: EC96CD5C Bootloader: BL1 08.00.B0011 Firmware: MPK 12.01.B0013 Other: Supports 29 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BL1 08.00.B0011 00008169E8BB Firmware: Firmware MPK 12.01.B0013 B35BFE037737 Firmware: Other Unit ID: EC96CD5C Model ID: B35B408A0000 Transport IDs: {'btleid': 'B35B', 'wpid': '408A'} 3: DEVICE NAME {0005} Name: MX Keys Wireless Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: MX Keys 7: BATTERY STATUS {1000} Battery: 100%, discharging, next level 50%. 8: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Calculator:Regular, Show Desktop:Regular, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular} Key/Button Diversion : {Calculator:Regular, Show Desktop:Regular, Lock PC:Regular, Screen Capture/Print Screen:Regular, Brightness Down:Regular, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Mission Control/Task View:Regular, Dashboard Launchpad/Action Center:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular} 9: CHANGE HOST {1814} Change Host : 1:ak 10: HOSTS INFO {1815} Host 0 (paired): ak Host 1 (unpaired): Host 2 (unpaired): 11: BACKLIGHT2 {1982} Backlight (saved): True Backlight : True 12: K375S FN INVERSION {40A3} Swap Fx function (saved): True Swap Fx function : True 13: ENCRYPTION {4100} 14: LOCK KEY STATE {4220} 15: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 16: MULTIPLATFORM {4531} Set OS (saved): MacOS Set OS : MacOS 17: DFUCONTROL SIGNED {00C2} 18: DEVICE RESET {1802} internal, hidden 19: unknown:1803 {1803} internal, hidden 20: CONFIG DEVICE PROPS {1806} internal, hidden 21: unknown:1813 {1813} internal, hidden 22: OOBSTATE {1805} internal, hidden 23: unknown:1830 {1830} internal, hidden 24: unknown:18A1 {18A1} internal, hidden 25: unknown:1E00 {1E00} hidden 26: unknown:1EB0 {1EB0} internal, hidden 27: unknown:1861 {1861} internal, hidden 28: unknown:1A20 {1A20} internal, hidden Has 24 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 3: Brightness Down , default: Brightness Down => Brightness Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:1, group:0, group mask:empty reporting: default 4: Brightness Up , default: Brightness Up => Brightness Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:2, group:0, group mask:empty reporting: default 5: Mission Control/Task View , default: Mission Control/Task View => Mission Control/Task View is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:3, group:0, group mask:empty reporting: default 6: Dashboard Launchpad/Action Center, default: Dashboard Launchpad/Action Center => Dashboard Launchpad/Action Center is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:4, group:0, group mask:empty reporting: default 7: Show Desktop , default: Show Desktop => Show Desktop is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:5, group:0, group mask:empty reporting: default 8: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:6, group:0, group mask:empty reporting: default 9: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:7, group:0, group mask:empty reporting: default 10: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:8, group:0, group mask:empty reporting: default 11: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:9, group:0, group mask:empty reporting: default 12: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:10, group:0, group mask:empty reporting: default 13: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:11, group:0, group mask:empty reporting: default 14: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, persistently divertable, analytics key events, pos:12, group:0, group mask:empty reporting: default 15: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 16: Calculator , default: Calculator => Calculator nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 17: Screen Capture/Print Screen, default: Screen Capture => Screen Capture nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 19: Lock PC , default: WindowsLock => WindowsLock nonstandard, reprogrammable, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 20: Left Arrow , default: Keyboard Left Arrow => Keyboard Left Arrow nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 21: Right Arrow , default: Keyboard Right Arrow => Keyboard Right Arrow nonstandard, divertable, persistently divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 22: F Lock , default: Do Nothing One => Do Nothing One is FN, analytics key events, pos:0, group:0, group mask:empty reporting: default 23: FN Key , default: Do Nothing One => Do Nothing One nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default Battery: 100%, discharging, next level 50%. Solaar-1.1.20/docs/devices/MX Keys Mini B369.txt000066400000000000000000000162601522022367600206420ustar00rootroot00000000000000Solaar version 1.1.4 255: MX Keys Mini Device path : /dev/hidraw6 USB id : 046d:B369 Codename : MX Keys Mini Kind : ? Protocol : HID++ 4.5 Serial number: Model ID: B36900000000 Unit ID: 42BABA25 Bootloader: BL1 53.01.B0006 Firmware: RBK 73.01.B0006 Other: Supports 31 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BL1 53.01.B0006 B369FD70F4 Firmware: Firmware RBK 73.01.B0006 B369FD70F4 Firmware: Other Unit ID: 42BABA25 Model ID: B36900000000 Transport IDs: {'btleid': 'B369'} 3: DEVICE NAME {0005} Name: MX Keys Mini Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: MX Keys Mini 7: UNIFIED BATTERY {1004} 8: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Backlight Down:Regular, Backlight Up:Regular, Play/Pause Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Delete:Regular, Mute Microphone:Regular} Key/Button Diversion : {Backlight Down:Regular, Backlight Up:Regular, Play/Pause Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Delete:Regular, Mute Microphone:Regular} 9: CHANGE HOST {1814} Change Host : 3:fedora 10: HOSTS INFO {1815} Host 0 (paired): U308198 Host 1 (paired): DESKTOP-9C4GF7M Host 2 (paired): fedora 11: BACKLIGHT2 {1982} Backlight (saved): True Backlight : True 12: K375S FN INVERSION {40A3} Swap Fx function (saved): False Swap Fx function : False 13: LOCK KEY STATE {4220} 14: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {Caps Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Insert:False, Win:False} 15: MULTIPLATFORM {4531} Set OS (saved): Windows Set OS : Windows 16: DFUCONTROL {00C3} 17: DEVICE RESET {1802} internal, hidden, unknown:000010 18: unknown:1803 {1803} internal, hidden, unknown:000010 19: CONFIG DEVICE PROPS {1806} internal, hidden, unknown:000010 20: unknown:1816 {1816} internal, hidden, unknown:000010 21: OOBSTATE {1805} internal, hidden 22: unknown:1830 {1830} internal, hidden, unknown:000010 23: unknown:1891 {1891} internal, hidden, unknown:000008 24: unknown:18A1 {18A1} internal, hidden, unknown:000010 25: unknown:1E00 {1E00} hidden 26: unknown:1E02 {1E02} internal, hidden 27: unknown:1602 {1602} 28: unknown:1EB0 {1EB0} internal, hidden, unknown:000010 29: unknown:1861 {1861} internal, hidden, unknown:000010 30: unknown:1A20 {1A20} internal, hidden, unknown:000010 Has 16 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 is FN, FN sensitive, analytics key events, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 is FN, FN sensitive, analytics key events, pos:2, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 is FN, FN sensitive, analytics key events, pos:3, group:0, group mask:empty reporting: default 3: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty reporting: default 4: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty reporting: default 5: Voice Dictation , default: Voice Dictation => Voice Dictation is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty reporting: default 6: Open Emoji Panel , default: Open Emoji Panel => Open Emoji Panel is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty reporting: default 7: Snipping Tool , default: Snipping Tool => Snipping Tool is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty reporting: default 8: Mute Microphone , default: Mute Microphone => Mute Microphone is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty reporting: default 9: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty reporting: default 10: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty reporting: default 11: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty reporting: default 12: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, analytics key events, pos:13, group:0, group mask:empty reporting: default 13: Delete , default: Delete => Delete nonstandard, reprogrammable, divertable, analytics key events, pos:14, group:0, group mask:empty reporting: default 14: F Lock , default: Do Nothing One => Do Nothing One is FN, analytics key events, pos:0, group:0, group mask:empty reporting: default 15: FN Key , default: Do Nothing One => Do Nothing One nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default Battery: 40%, discharging. Solaar-1.1.20/docs/devices/MX Keys S B378.text000066400000000000000000000220471522022367600203150ustar00rootroot00000000000000solaar version 1.1.10 1: MX Keys S Device path : None WPID : B378 Codename : MX KEYS S Kind : keyboard Protocol : HID++ 4.5 Serial number: 48548420 Model ID: B37800000000 Unit ID: 48548420 Bootloader: BL1 88.00.B0013 Firmware: RBK 81.00.B0013 Other: The power switch is located on the (unknown). Supports 34 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 88.00.B0013 B37851DB9520 Firmware: Firmware RBK 81.00.B0013 B37851DB9520 Firmware: Other Unit ID: 48548420 Model ID: B37800000000 Transport IDs: {'btleid': 'B378'} 3: DEVICE NAME {0005} V0 Name: MX Keys S Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX KEYS S 7: unknown:0011 {0011} V0 8: UNIFIED BATTERY {1004} V3 Battery: 75%, discharging. 9: REPROG CONTROLS V4 {1B04} V5 Key/Button Diversion (saved): {Calculator:Regular, Lock PC:Regular, Brightness Down:Regular, Brightness Up:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Diverted, Mute Microphone:Regular} Key/Button Diversion : {Calculator:Regular, Lock PC:Regular, Brightness Down:Regular, Brightness Up:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Diverted, Mute Microphone:Regular} 10: CHANGE HOST {1814} V1 Change Host : 1:vs 11: HOSTS INFO {1815} V2 Host 0 (paired): vs Host 1 (paired): DEV Host 2 (unpaired): 12: BACKLIGHT2 {1982} V3 Backlight (saved): False Backlight : True 13: K375S FN INVERSION {40A3} V0 Swap Fx function (saved): False Swap Fx function : False 14: LOCK KEY STATE {4220} V0 15: KEYBOARD DISABLE KEYS {4521} V0 Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 16: MULTIPLATFORM {4531} V1 Set OS (saved): Linux Set OS : Linux 17: KEYBOARD LAYOUT 2 {4540} V0 18: DFUCONTROL {00C3} V0 19: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 20: unknown:1803 {1803} V0 internal, hidden, unknown:000010 21: unknown:1807 {1807} V0 internal, hidden, unknown:000010 22: unknown:1816 {1816} V0 internal, hidden, unknown:000010 23: OOBSTATE {1805} V0 internal, hidden 24: unknown:1830 {1830} V0 internal, hidden, unknown:000010 25: unknown:1891 {1891} V7 internal, hidden, unknown:000008 26: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 27: unknown:1E00 {1E00} V0 hidden 28: unknown:1E02 {1E02} V0 internal, hidden 29: unknown:1602 {1602} V0 30: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 31: unknown:1861 {1861} V1 internal, hidden, unknown:000010 32: unknown:1A20 {1A20} V1 internal, hidden, unknown:000010 33: unknown:18B0 {18B0} V1 internal, hidden, unknown:000010 Has 21 reprogrammable keys: 0: Brightness Down , default: Brightness Down => Brightness Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:1, group:0, group mask:empty reporting: default 1: Brightness Up , default: Brightness Up => Brightness Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:2, group:0, group mask:empty reporting: default 2: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:3, group:0, group mask:empty reporting: default 3: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty reporting: default 4: Voice Dictation , default: Voice Dictation => Voice Dictation is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty reporting: default 5: Open Emoji Panel , default: Open Emoji Panel => Open Emoji Panel is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty reporting: default 6: Mute Microphone , default: Mute Microphone => Mute Microphone is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty reporting: default 7: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty reporting: default 8: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty reporting: default 9: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty reporting: default 10: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty reporting: default 11: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty reporting: default 12: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 13: Calculator , default: Calculator => Calculator nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 14: Snipping Tool , default: Snipping Tool => Snipping Tool nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: diverted 15: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 16: Lock PC , default: WindowsLock => WindowsLock nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 17: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default 18: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default 19: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default 20: F Lock , default: Do Nothing One => Do Nothing One analytics key events, pos:0, group:0, group mask:empty reporting: default Battery: 75%, discharging. Solaar-1.1.20/docs/devices/MX Keys for Business B363.text000066400000000000000000000237031522022367600224470ustar00rootroot00000000000000Solaar version 1.1.5 1: MX Keys for Business Device path : None WPID : B363 Codename : MX Keys B Kind : keyboard Protocol : HID++ 4.5 Serial number: C8457F05 Model ID: B36300000000 Unit ID: C8457F05 Bootloader: BL1 31.00.B0009 Firmware: RBK 68.00.B0009 Other: The power switch is located on the (unknown). Supports 32 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 31.00.B0009 B3636927CBB5 Firmware: Firmware RBK 68.00.B0009 B3636927CBB5 Firmware: Other Unit ID: C8457F05 Model ID: B36300000000 Transport IDs: {'btleid': 'B363'} 3: DEVICE NAME {0005} V0 Name: MX Keys for Business Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX Keys B 7: UNIFIED BATTERY {1004} V2 Battery: 60%, discharging. 8: REPROG CONTROLS V4 {1B04} V5 Key/Button Diversion (saved): {Calculator:Regular, Lock PC:Regular, Brightness Down:Diverted, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Mute Microphone:Regular} Key/Button Diversion : {Calculator:Regular, Lock PC:Regular, Brightness Down:Diverted, Brightness Up:Regular, Host Switch Channel 1:Regular, Host Switch Channel 2:Regular, Host Switch Channel 3:Regular, Backlight Down:Regular, Backlight Up:Regular, Previous Fn:Regular, Play/Pause Fn:Regular, Next Fn:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, App Contextual Menu/Right Click:Regular, Right Arrow:Regular, Left Arrow:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Mute Microphone:Regular} 9: CHANGE HOST {1814} V1 Change Host : 1:Ryzen 10: HOSTS INFO {1815} V1 Host 0 (paired): Ryzen Host 1 (paired): Ryzen Host 2 (paired): Mi 10 Lite 5G 11: BACKLIGHT2 {1982} V1 Backlight (saved): True Backlight : True 12: K375S FN INVERSION {40A3} V0 Swap Fx function (saved): False Swap Fx function : False 13: LOCK KEY STATE {4220} V0 14: KEYBOARD DISABLE KEYS {4521} V0 Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 15: MULTIPLATFORM {4531} V1 Set OS (saved): Windows Set OS : Windows 16: DFUCONTROL {00C3} V0 17: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 18: unknown:1803 {1803} V0 internal, hidden, unknown:000010 19: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 20: unknown:1816 {1816} V0 internal, hidden, unknown:000010 21: OOBSTATE {1805} V0 internal, hidden 22: unknown:1830 {1830} V0 internal, hidden, unknown:000010 23: unknown:1891 {1891} V6 internal, hidden, unknown:000008 24: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 25: unknown:1E00 {1E00} V0 hidden 26: unknown:1E02 {1E02} V0 internal, hidden 27: unknown:1602 {1602} V0 28: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 29: unknown:1861 {1861} V0 internal, hidden, unknown:000010 30: unknown:1A20 {1A20} V0 internal, hidden, unknown:000010 31: unknown:18B0 {18B0} V0 internal, hidden, unknown:000010 Has 24 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 3: Brightness Down , default: Brightness Down => Brightness Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:1, group:0, group mask:empty reporting: diverted 4: Brightness Up , default: Brightness Up => Brightness Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:2, group:0, group mask:empty reporting: default 5: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:3, group:0, group mask:empty reporting: default 6: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty reporting: default 7: Voice Dictation , default: Voice Dictation => Voice Dictation is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty reporting: default 8: Open Emoji Panel , default: Open Emoji Panel => Open Emoji Panel is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty reporting: default 9: Mute Microphone , default: Mute Microphone => Mute Microphone is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty reporting: default 10: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty reporting: default 11: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty reporting: default 12: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty reporting: default 13: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty reporting: default 14: Volume Down Fn , default: Volume Down => Volume Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty reporting: default 15: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 16: Calculator , default: Calculator => Calculator nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 17: Snipping Tool , default: Snipping Tool => Snipping Tool nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 18: App Contextual Menu/Right Click, default: Right Click/App Contextual Menu => Right Click/App Contextual Menu nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 19: Lock PC , default: WindowsLock => WindowsLock nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 20: Left Arrow , default: Keyboard Left Arrow => Keyboard Left Arrow nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 21: Right Arrow , default: Keyboard Right Arrow => Keyboard Right Arrow nonstandard, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 22: F Lock , default: Do Nothing One => Do Nothing One is FN, analytics key events, pos:0, group:0, group mask:empty reporting: default 23: FN Key , default: Do Nothing One => Do Nothing One nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default Battery: 60%, discharging. Solaar-1.1.20/docs/devices/MX Master 3 Wireless Mouse 4082.txt000066400000000000000000000142451522022367600232320ustar00rootroot00000000000000Solaar version 1.1.4 1: MX Master 3 Wireless Mouse Device path : /dev/hidraw2 WPID : 4082 Codename : MX Master 3 Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 198E3EB8 Model ID: B02340820000 Unit ID: 198E3EB8 Bootloader: BOT 95.01.B0015 Firmware: MPM 19.01.B0015 Other: The power switch is located on the base. Supports 34 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 95.01.B0015 00006A9CA89D Firmware: Firmware MPM 19.01.B0015 40826A9CA89D Firmware: Other Unit ID: 198E3EB8 Model ID: B02340820000 Transport IDs: {'btleid': 'B023', 'wpid': '4082'} 3: DEVICE NAME {0005} Name: Wireless Mouse MX Master 3 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: DEVICE FRIENDLY NAME {0007} Friendly Name: MX Master 3 8: BATTERY STATUS {1000} Battery: 100%, discharging, next level 50%. 9: REPROG CONTROLS V4 {1B04} Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Mouse Gestures, Smart Shift:Sliding DPI} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular} 10: CHANGE HOST {1814} Change Host : 1:idefix 11: XY STATS {2250} 12: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 1600 Sensitivity (DPI) : 1600 13: SMART SHIFT {2110} Scroll Wheel Rachet (saved): 32 Scroll Wheel Rachet : 32 14: HIRES WHEEL {2121} Multiplier: 15 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 15: THUMB WHEEL {2150} Thumb Wheel Direction (saved): False Thumb Wheel Direction : False Thumb Wheel Diversion (saved): False Thumb Wheel Diversion : False 16: WHEEL STATS {2251} 17: DFUCONTROL SIGNED {00C2} 18: DEVICE RESET {1802} internal, hidden 19: unknown:1803 {1803} internal, hidden 20: CONFIG DEVICE PROPS {1806} internal, hidden 21: unknown:1813 {1813} internal, hidden 22: OOBSTATE {1805} internal, hidden 23: unknown:1830 {1830} internal, hidden 24: unknown:1890 {1890} internal, hidden 25: unknown:1891 {1891} internal, hidden 26: unknown:18A1 {18A1} internal, hidden 27: unknown:1DF3 {1DF3} internal, hidden 28: unknown:1E00 {1E00} hidden 29: unknown:1EB0 {1EB0} internal, hidden 30: unknown:1861 {1861} internal, hidden 31: unknown:9001 {9001} internal, hidden 32: unknown:9203 {9203} internal, hidden 33: unknown:9205 {9205} internal, hidden Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Battery: 100%, discharging, next level 50%. Solaar-1.1.20/docs/devices/MX Master 3 Wireless Mouse B023.txt000066400000000000000000000135361522022367600232450ustar00rootroot00000000000000Solaar version 1.1.4 1: MX Master 3 Wireless Mouse Device path : /dev/hidraw5 USB id : 046d:B023 Codename : MX Master 3 Kind : mouse Protocol : HID++ 4.5 Serial number: Model ID: B02340820000 Unit ID: 198E3EB8 Bootloader: BOT 95.01.B0015 Firmware: MPM 19.01.B0015 Other: Supports 30 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 95.01.B0015 00006A9CA89D Firmware: Firmware MPM 19.01.B0015 B0236A9CA89D Firmware: Other Unit ID: 198E3EB8 Model ID: B02340820000 Transport IDs: {'btleid': 'B023', 'wpid': '4082'} 3: DEVICE NAME {0005} Name: Wireless Mouse MX Master 3 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: DEVICE FRIENDLY NAME {0007} Friendly Name: MX Master 3 8: BATTERY STATUS {1000} Battery: 100%, discharging, next level 50%. 9: REPROG CONTROLS V4 {1B04} Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Mouse Gestures, Smart Shift:Sliding DPI} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular} 10: CHANGE HOST {1814} Change Host : 2:idefix 11: XY STATS {2250} 12: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 1600 Sensitivity (DPI) : 1600 13: SMART SHIFT {2110} Scroll Wheel Rachet (saved): 32 Scroll Wheel Rachet : 32 14: HIRES WHEEL {2121} Multiplier: 15 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 15: THUMB WHEEL {2150} Thumb Wheel Direction (saved): False Thumb Wheel Direction : False Thumb Wheel Diversion (saved): False Thumb Wheel Diversion : False 16: WHEEL STATS {2251} 17: DFUCONTROL SIGNED {00C2} 18: DEVICE RESET {1802} internal, hidden 19: unknown:1803 {1803} internal, hidden 20: CONFIG DEVICE PROPS {1806} internal, hidden 21: unknown:1813 {1813} internal, hidden 22: OOBSTATE {1805} internal, hidden 23: unknown:1830 {1830} internal, hidden 24: unknown:18A1 {18A1} internal, hidden 25: unknown:1E00 {1E00} hidden 26: unknown:1EB0 {1EB0} internal, hidden 27: unknown:1861 {1861} internal, hidden 28: unknown:9300 {9300} internal, hidden 29: unknown:9001 {9001} internal, hidden Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Battery: 100%, discharging, next level 50%. Solaar-1.1.20/docs/devices/MX Master 3 for Business B028.text000066400000000000000000000150511522022367600231050ustar00rootroot00000000000000solaar version 1.1.8 1: MX Master 3 for Business Device path : None WPID : B028 Codename : MX Master 3 B Kind : mouse Protocol : HID++ 4.5 Serial number: 18F3413B Model ID: B02800000000 Unit ID: 18F3413B Bootloader: BL1 41.00.B0009 Firmware: RBM 14.00.B0009 Other: The power switch is located on the (unknown). Supports 35 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 41.00.B0009 B0281D13EFC0 Firmware: Firmware RBM 14.00.B0009 B0281D13EFC0 Firmware: Other Unit ID: 18F3413B Model ID: B02800000000 Transport IDs: {'btleid': 'B028'} 3: DEVICE NAME {0005} V0 Name: MX Master 3 for Business Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: CRYPTO ID {0021} V1 7: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX Master 3 B 8: UNIFIED BATTERY {1004} V2 Battery: 95%, discharging. 9: REPROG CONTROLS V4 {1B04} V5 Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular} 10: CHANGE HOST {1814} V1 Change Host : 1:bork 11: XY STATS {2250} V1 12: ADJUSTABLE DPI {2201} V2 Sensitivity (DPI) (saved): 1000 Sensitivity (DPI) : 1000 13: SMART SHIFT {2110} V0 Scroll Wheel Ratcheted (saved): Freespinning Scroll Wheel Ratcheted : Freespinning Scroll Wheel Ratchet Speed (saved): 1 Scroll Wheel Ratchet Speed : 1 14: HIRES WHEEL {2121} V1 Multiplier: 15 Has invert: Normal wheel motion Has ratchet switch: Free wheel mode Low resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): False Scroll Wheel Resolution : False Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 15: THUMB WHEEL {2150} V0 Thumb Wheel Direction (saved): False Thumb Wheel Direction : False Thumb Wheel Diversion (saved): False Thumb Wheel Diversion : False 16: WHEEL STATS {2251} V0 17: DFUCONTROL {00C3} V0 18: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 19: unknown:1803 {1803} V0 internal, hidden, unknown:000010 20: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 21: unknown:1816 {1816} V0 internal, hidden, unknown:000010 22: OOBSTATE {1805} V0 internal, hidden 23: unknown:1830 {1830} V0 internal, hidden, unknown:000010 24: unknown:1891 {1891} V6 internal, hidden, unknown:000008 25: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 26: unknown:1E00 {1E00} V0 hidden 27: unknown:1E02 {1E02} V0 internal, hidden 28: unknown:1602 {1602} V0 29: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 30: unknown:1861 {1861} V0 internal, hidden, unknown:000010 31: unknown:9300 {9300} V0 internal, hidden, unknown:000010 32: unknown:9001 {9001} V0 internal, hidden, unknown:000010 33: unknown:1E22 {1E22} V0 internal, hidden, unknown:000010 34: unknown:9205 {9205} V0 internal, hidden, unknown:000010 Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Battery: 95%, discharging. Solaar-1.1.20/docs/devices/MX Master 3S B034.txt000066400000000000000000000154071522022367600205420ustar00rootroot00000000000000Solaar version 1.1.7 2: MX Master 3S Device path : None WPID : B034 Codename : MX Master 3S Kind : mouse Protocol : HID++ 4.5 Serial number: CD2A6BB7 Model ID: B03400000000 Unit ID: CD2A6BB7 Bootloader: BL1 69.00.B0003 Firmware: RBM 22.00.B0003 Other: The power switch is located on the (unknown). Supports 36 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 69.00.B0003 B03438FCA4E6 Firmware: Firmware RBM 22.00.B0003 B03438FCA4E6 Firmware: Other Unit ID: CD2A6BB7 Model ID: B03400000000 Transport IDs: {'btleid': 'B034'} 3: DEVICE NAME {0005} V0 Name: MX Master 3S Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: CRYPTO ID {0021} V1 7: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX Master 3S 8: UNIFIED BATTERY {1004} V3 Battery: 25%, discharging. 9: REPROG CONTROLS V4 {1B04} V5 Acciones de Tecla/Botón (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Acciones de Tecla/Botón : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Desvio de Tecla/Botón (saved): {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Mouse Gesture Button:Normal, Smart Shift:Normal} Desvio de Tecla/Botón : {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Mouse Gesture Button:Normal, Smart Shift:Normal} 10: CHANGE HOST {1814} V1 Cambiar Host : 1:romanescu 11: HOSTS INFO {1815} V2 Host 0 (paired): romanescu Host 1 (unpaired): Host 2 (unpaired): 12: XY STATS {2250} V1 13: ADJUSTABLE DPI {2201} V2 Sensibilidad (PPP) (saved): 1000 Sensibilidad (PPP) : 1000 14: SMART SHIFT {2110} V0 Scroll Wheel Ratcheted (saved): Freespinning Scroll Wheel Ratcheted : Freespinning Scroll Wheel Ratchet Speed (saved): 0 Scroll Wheel Ratchet Speed : 1 15: HIRES WHEEL {2121} V1 Multiplier: 15 Has invert: Normal wheel motion Has ratchet switch: Free wheel mode Low resolution mode HID notification Dirección Rueda Desplazamiento (saved): False Dirección Rueda Desplazamiento : False Resolución Rueda Desplazamiento (saved): False Resolución Rueda Desplazamiento : False Desvio Rueda Desplazamiento (saved): False Desvio Rueda Desplazamiento : False 16: THUMB WHEEL {2150} V0 Dirección de la Rueda del Pulgar (saved): False Dirección de la Rueda del Pulgar : False Desvío de la Rueda del Pulgar (saved): False Desvío de la Rueda del Pulgar : False 17: WHEEL STATS {2251} V0 18: DFUCONTROL {00C3} V0 19: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 20: unknown:1803 {1803} V0 internal, hidden, unknown:000010 21: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 22: unknown:1816 {1816} V0 internal, hidden, unknown:000010 23: OOBSTATE {1805} V0 internal, hidden 24: unknown:1830 {1830} V0 internal, hidden, unknown:000010 25: unknown:1891 {1891} V7 internal, hidden, unknown:000008 26: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 27: unknown:1E00 {1E00} V0 hidden 28: unknown:1E02 {1E02} V0 internal, hidden 29: unknown:1602 {1602} V0 30: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 31: unknown:1861 {1861} V1 internal, hidden, unknown:000010 32: unknown:9300 {9300} V0 internal, hidden, unknown:000010 33: unknown:9001 {9001} V0 internal, hidden, unknown:000010 34: unknown:1E22 {1E22} V0 internal, hidden, unknown:000010 35: unknown:9205 {9205} V0 internal, hidden, unknown:000010 Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Battery: 25%, discharging. Solaar-1.1.20/docs/devices/MX Master 4.text000066400000000000000000000174411522022367600201740ustar00rootroot00000000000000solaar version 1.1.16-7-g2cb5fa4b MX Master 4 Device path : /dev/hidraw7 USB id : 046d:B042 Codename : MX Master 4 Kind : mouse Protocol : HID++ 4.5 Serial number: Model ID: B04200000000 Unit ID: F03B4069 1: LD 04.00 0: RBM 27.00.B0015 0: RBM 27.00.B0015 2: 72 Supports 46 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V8 Firmware: 1 LD 04.00 0000642BA1A1 Firmware: 0 RBM 27.00.B0015 B042F21A379A Firmware: 0 RBM 27.00.B0015 B042F21A379A Firmware: 2 72 Unit ID: F03B4069 Model ID: B04200000000 Transport IDs: {'btleid': 'B042'} 3: DEVICE NAME {0005} V5 Name: MX Master 4 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V1 Configuration: 11000000000000000000000000000000 6: CRYPTO ID {0021} V1 7: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX Master 4 8: unknown:0011 {1100} V0 9: UNIFIED BATTERY {1004} V5 Battery: 45%, BatteryStatus.DISCHARGING. 10: unknown:1701 {0117} V0 11: unknown:19B0 {B019} V0 12: unknown:19C0 {C019} V0 13: REPROG CONTROLS V4 {1B04} V6 Key/Button Actions (saved): {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift, Haptic:unknown:0109} Key/Button Actions : {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift, Haptic:unknown:0109} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular, Haptic:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular, Haptic:Regular} 14: CHANGE HOST {1814} V2 Change Host : 1:idefix 15: HOSTS INFO {1815} V2 Host 0 (paired): idefix Host 1 (paired): idefix Host 2 (unpaired): 16: XY STATS {2250} V1 17: SMART SHIFT ENHANCED {2111} V0 Scroll Wheel Ratcheted (saved): Ratcheted Scroll Wheel Ratcheted : Ratcheted Scroll Wheel Ratchet Speed (saved): 10 Scroll Wheel Ratchet Speed : 10 18: HIRES WHEEL {2121} V1 Multiplier: 15 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode Low resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): False Scroll Wheel Resolution : False Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 19: THUMB WHEEL {2150} V0 Thumb Wheel Direction (saved): True Thumb Wheel Direction : True Thumb Wheel Diversion (saved): False Thumb Wheel Diversion : False 20: ADJUSTABLE DPI {2201} V2 Sensitivity (DPI) (saved): 1000 Sensitivity (DPI) : 1000 21: WHEEL STATS {2251} V0 22: unknown:00D1 {D100} V0 23: DEVICE RESET {1802} V0 24: unknown:1803 {0318} V0 internal, hidden, unknown:000010 25: unknown:1807 {0718} V0 internal, hidden, unknown:000010 26: unknown:1816 {1618} V0 internal, hidden, unknown:000010 27: OOBSTATE {1805} V0 28: unknown:1830 {3018} V0 internal, hidden, unknown:000010 29: unknown:1891 {9118} V0 internal, hidden, unknown:000008 30: unknown:18A1 {A118} V0 internal, hidden, unknown:000010 31: unknown:1E00 {001E} V0 hidden 32: unknown:1E02 {021E} V0 internal, hidden 33: unknown:1E22 {221E} V0 internal, hidden, unknown:000010 34: unknown:1E30 {301E} V0 internal, hidden, unknown:000010 35: unknown:1602 {0216} V0 36: unknown:1EB0 {B01E} V0 internal, hidden, unknown:000010 37: unknown:1861 {6118} V0 internal, hidden, unknown:000010 38: unknown:9205 {0592} V0 internal, hidden, unknown:000010 39: unknown:9201 {0192} V0 internal, hidden, unknown:000010 40: unknown:9300 {0093} V0 internal, hidden, unknown:000010 41: unknown:9401 {0194} V0 internal, hidden, unknown:000010 42: unknown:9402 {0294} V0 internal, hidden, unknown:000010 43: unknown:9001 {0190} V0 internal, hidden, unknown:000010 44: unknown:18B1 {B118} V0 internal, hidden, unknown:000010 45: unknown:18C0 {C018} V0 internal, hidden, unknown:000010 Has 9 reprogrammable keys: 0: Left Button , default: Left Click => Left Click analytics_key_events, mse, pos:0, group:1, group mask:empty reporting: default 1: Right Button , default: Right Click => Right Click analytics_key_events, mse, pos:0, group:1, group mask:empty reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button analytics_key_events, raw_xy, divertable, reprogrammable, mse, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button analytics_key_events, raw_xy, divertable, reprogrammable, mse, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button analytics_key_events, raw_xy, divertable, reprogrammable, mse, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button => Gesture Button analytics_key_events, raw_xy, divertable, reprogrammable, mse, pos:0, group:2, group mask:g1,g2 reporting: default 6: Smart Shift , default: Smart Shift => Smart Shift analytics_key_events, raw_xy, divertable, reprogrammable, mse, pos:0, group:2, group mask:g1,g2 reporting: default 7: Haptic , default: unknown:0109 => Unknown_1a0 analytics_key_events, raw_xy, divertable, reprogrammable, mse, pos:0, group:2, group mask:g1,g2 reporting: default 8: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button force_raw_xy, raw_xy, virtual, divertable, pos:0, group:3, group mask:empty reporting: default Battery: 45%, BatteryStatus.DISCHARGING. Solaar-1.1.20/docs/devices/MX Mechanical B366.txt000066400000000000000000000340261522022367600210730ustar00rootroot00000000000000Solaar version 1.1.7 1: MX Mechanical Device path : None WPID : B366 Codename : MX MCHNCL Kind : keyboard Protocol : HID++ 4.5 Serial number: 2DF63C09 Model ID: B36600000000 Unit ID: 2DF63C09 Bootloader: BL1 45.00.B0016 Firmware: RBK 71.00.B0016 Other: The power switch is located on the (unknown). Supports 33 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 45.00.B0016 B3662CB9B8E2 Firmware: Firmware RBK 71.00.B0016 B3662CB9B8E2 Firmware: Other Unit ID: 2DF63C09 Model ID: B36600000000 Transport IDs: {'btleid': 'B366'} 3: DEVICE NAME {0005} V0 Name: MX Mechanical Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX MCHNCL 7: UNIFIED BATTERY {1004} V3 Battery: 50%, discharging. 8: REPROG CONTROLS V4 {1B04} V5 Desvio de Tecla/Botón (saved): {Calculator:Normal, Show Desktop:Normal, Lock PC:Normal, Brightness Down:Normal, Brightness Up:Normal, MultiPlatform Search:Normal, Backlight Down:Normal, Backlight Up:Normal, Previous Fn:Normal, Play/Pause Fn:Normal, Next Fn:Normal, Mute Fn:Normal, Volume Down Fn:Normal, Volume Up Fn:Normal, Voice Dictation:Normal, Open Emoji Panel:Normal, Snipping Tool:Normal, Grave Accent:Normal, Tab Key:Normal, Caps Lock:Normal, Left Shift:Normal, Left Control:Normal, Left Option/Start:Normal, Left Command/Alt:Normal, Right Command/Alt:Normal, Right Option/Start:Normal, Right Control:Normal, Right Shift:Normal, Insert:Normal, Delete:Normal, Home:Normal, End:Normal, Page Up:Normal, Page Down:Normal, Mute Microphone:Normal, Backslash:Normal} Desvio de Tecla/Botón : {Calculator:Normal, Show Desktop:Normal, Lock PC:Normal, Brightness Down:Normal, Brightness Up:Normal, MultiPlatform Search:Normal, Backlight Down:Normal, Backlight Up:Normal, Previous Fn:Normal, Play/Pause Fn:Normal, Next Fn:Normal, Mute Fn:Normal, Volume Down Fn:Normal, Volume Up Fn:Normal, Voice Dictation:Normal, Open Emoji Panel:Normal, Snipping Tool:Normal, Grave Accent:Normal, Tab Key:Normal, Caps Lock:Normal, Left Shift:Normal, Left Control:Normal, Left Option/Start:Normal, Left Command/Alt:Normal, Right Command/Alt:Normal, Right Option/Start:Normal, Right Control:Normal, Right Shift:Normal, Insert:Normal, Delete:Normal, Home:Normal, End:Normal, Page Up:Normal, Page Down:Normal, Mute Microphone:Normal, Backslash:Normal} 9: CHANGE HOST {1814} V1 Cambiar Host : 1:romanescu 10: HOSTS INFO {1815} V2 Host 0 (paired): romanescu Host 1 (unpaired): Host 2 (unpaired): 11: BACKLIGHT2 {1982} V2 Retroiluminación (saved): True Retroiluminación : True 12: K375S FN INVERSION {40A3} V0 Intercambiar función Fx (saved): True Intercambiar función Fx : True 13: LOCK KEY STATE {4220} V0 14: KEYBOARD DISABLE KEYS {4521} V0 Desactivar teclas (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Desactivar teclas : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 15: MULTIPLATFORM {4531} V1 Especificar SO (saved): Windows Especificar SO : Windows 16: KEYBOARD LAYOUT 2 {4540} V0 17: DFUCONTROL {00C3} V0 18: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 19: unknown:1803 {1803} V0 internal, hidden, unknown:000010 20: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 21: unknown:1816 {1816} V0 internal, hidden, unknown:000010 22: OOBSTATE {1805} V0 internal, hidden 23: unknown:1830 {1830} V0 internal, hidden, unknown:000010 24: unknown:1891 {1891} V7 internal, hidden, unknown:000008 25: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 26: unknown:1E00 {1E00} V0 hidden 27: unknown:1E02 {1E02} V0 internal, hidden 28: unknown:1602 {1602} V0 29: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 30: unknown:1861 {1861} V1 internal, hidden, unknown:000010 31: unknown:1A20 {1A20} V0 internal, hidden, unknown:000010 32: unknown:18B0 {18B0} V0 internal, hidden, unknown:000010 Has 41 reprogrammable keys: 0: Brightness Down , default: Brightness Down => Brightness Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:1, group:0, group mask:empty reporting: default 1: Brightness Up , default: Brightness Up => Brightness Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:2, group:0, group mask:empty reporting: default 2: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:3, group:0, group mask:empty reporting: default 3: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty reporting: default 4: Voice Dictation , default: Voice Dictation => Voice Dictation is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty reporting: default 5: Open Emoji Panel , default: Open Emoji Panel => Open Emoji Panel is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty reporting: default 6: Snipping Tool , default: Snipping Tool => Snipping Tool is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty reporting: default 7: Mute Microphone , default: Mute Microphone => Mute Microphone is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty reporting: default 8: Previous Fn , default: Previous => Previous is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty reporting: default 9: Play/Pause Fn , default: Play/Pause => Play/Pause is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty reporting: default 10: Next Fn , default: Next => Next is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty reporting: default 11: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty reporting: default 12: Volume Down Fn , default: Volume Down => Volume Down nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 13: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 14: Grave Accent , default: Grave Accent => Grave Accent reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 15: Tab Key , default: Standard Tab Key => Standard Tab Key reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 16: Caps Lock , default: Caps Lock => Caps Lock reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 17: Left Shift , default: Left Shift => Left Shift reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 18: Left Control , default: Left Control => Left Control reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 19: Left Option/Start , default: Left Option/Start => Left Option/Start reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 20: Left Command/Alt , default: Left Command/Alt => Left Command/Alt reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 21: Right Command/Alt , default: Right Command/Alt => Right Command/Alt reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 22: Right Option/Start , default: Right Option/Start => Right Option/Start reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 23: Right Control , default: Right Control => Right Control reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 24: Right Shift , default: Right Shift => Right Shift reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 25: Backslash , default: Backslash => Backslash reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 26: Insert , default: Insert => Insert reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 27: Delete , default: Delete => Delete reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 28: Home , default: Home => Home reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 29: End , default: End => End reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 30: Page Up , default: Page Up => Page Up reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 31: Page Down , default: Page Down => Page Down reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 32: Calculator , default: Calculator => Calculator nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 33: Show Desktop , default: Show Desktop => Show Desktop nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 34: MultiPlatform Search , default: Multiplatform Search => Multiplatform Search nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 35: Lock PC , default: WindowsLock => WindowsLock nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 36: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default 37: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default 38: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default 39: F Lock , default: Do Nothing One => Do Nothing One is FN, analytics key events, pos:0, group:0, group mask:empty reporting: default 40: FN Key , default: Do Nothing One => Do Nothing One nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default Battery: 50%, discharging. Solaar-1.1.20/docs/devices/MX Mechanical Mini B367.txt000066400000000000000000000271031522022367600217470ustar00rootroot00000000000000Solaar version 1.1.4 1: MX Mechanical Mini Device path : None WPID : B367 Codename : MX MCHNCL M Kind : keyboard Protocol : HID++ 4.5 Serial number: D4E94F5C Model ID: B36700000000 Unit ID: D4E94F5C Bootloader: BL1 50.00.B0010 Firmware: RBK 72.00.B0010 Other: The power switch is located on the (unknown). Supports 32 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 50.00.B0010 B367A91B7FC8 Firmware: Firmware RBK 72.00.B0010 B367A91B7FC8 Firmware: Other Unit ID: D4E94F5C Model ID: B36700000000 Transport IDs: {'btleid': 'B367'} 3: DEVICE NAME {0005} V0 Name: MX Mechanical Mini Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: MX MCHNCL M 7: UNIFIED BATTERY {1004} V3 Battery: 90%, discharging. 8: REPROG CONTROLS V4 {1B04} V5 Key/Button Diversion (saved): {MultiPlatform Search:Regular, Backlight Down:Regular, Backlight Up:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Grave Accent:Regular, Tab Key:Regular, Caps Lock:Regular, Left Shift:Regular, Left Control:Regular, Left Option/Start:Regular, Left Command/Alt:Regular, Right Command/Alt:Regular, Right Shift:Regular, Delete:Regular, Home:Regular, End:Regular, Page Up:Regular, Page Down:Regular, Mute Microphone:Regular, Backslash:Regular, unknown:013C:Regular, unknown:0141:Regular} Key/Button Diversion : {MultiPlatform Search:Regular, Backlight Down:Regular, Backlight Up:Regular, Mute Fn:Regular, Volume Down Fn:Regular, Volume Up Fn:Regular, Voice Dictation:Regular, Open Emoji Panel:Regular, Snipping Tool:Regular, Grave Accent:Regular, Tab Key:Regular, Caps Lock:Regular, Left Shift:Regular, Left Control:Regular, Left Option/Start:Regular, Left Command/Alt:Regular, Right Command/Alt:Regular, Right Shift:Regular, Delete:Regular, Home:Regular, End:Regular, Page Up:Regular, Page Down:Regular, Mute Microphone:Regular, Backslash:Regular, unknown:013C:Regular, unknown:0141:Regular} 9: CHANGE HOST {1814} V1 Change Host : 1:chimera 10: HOSTS INFO {1815} V2 Host 0 (paired): chimera Host 1 (paired): Logitech Bolt receiver Host 2 (unpaired): 11: BACKLIGHT2 {1982} V2 Backlight (saved): True Backlight : True 12: K375S FN INVERSION {40A3} V0 Swap Fx function (saved): True Swap Fx function : True 13: LOCK KEY STATE {4220} V0 14: KEYBOARD DISABLE KEYS {4521} V0 Disable keys (saved): {Caps Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Scroll Lock:False, Insert:False, Win:False} 15: MULTIPLATFORM {4531} V1 Set OS (saved): Windows Set OS : Windows 16: KEYBOARD LAYOUT 2 {4540} V0 17: DFUCONTROL {00C3} V0 18: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 19: unknown:1803 {1803} V0 internal, hidden, unknown:000010 20: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 21: unknown:1816 {1816} V0 internal, hidden, unknown:000010 22: OOBSTATE {1805} V0 internal, hidden 23: unknown:1830 {1830} V0 internal, hidden, unknown:000010 24: unknown:1891 {1891} V7 internal, hidden, unknown:000008 25: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 26: unknown:1E00 {1E00} V0 hidden 27: unknown:1E02 {1E02} V0 internal, hidden 28: unknown:1602 {1602} V0 29: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 30: unknown:1861 {1861} V1 internal, hidden, unknown:000010 31: unknown:1A20 {1A20} V0 internal, hidden, unknown:000010 Has 32 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 is FN, FN sensitive, analytics key events, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 is FN, FN sensitive, analytics key events, pos:2, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 is FN, FN sensitive, analytics key events, pos:3, group:0, group mask:empty reporting: default 3: Backlight Down , default: Backlight Down => Backlight Down is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:4, group:0, group mask:empty reporting: default 4: Backlight Up , default: Backlight Up => Backlight Up is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:5, group:0, group mask:empty reporting: default 5: Voice Dictation , default: Voice Dictation => Voice Dictation is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:6, group:0, group mask:empty reporting: default 6: Open Emoji Panel , default: Open Emoji Panel => Open Emoji Panel is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:7, group:0, group mask:empty reporting: default 7: Snipping Tool , default: Snipping Tool => Snipping Tool is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:8, group:0, group mask:empty reporting: default 8: Mute Microphone , default: Mute Microphone => Mute Microphone is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:9, group:0, group mask:empty reporting: default 9: MultiPlatform Search , default: Multiplatform Search => Multiplatform Search is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:10, group:0, group mask:empty reporting: default 10: unknown:0141 , default: unknown:00FD => unknown:00FD is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:11, group:0, group mask:empty reporting: default 11: Mute Fn , default: Mute => Mute is FN, FN sensitive, reprogrammable, divertable, analytics key events, pos:12, group:0, group mask:empty reporting: default 12: Volume Down Fn , default: Volume Down => Volume Down nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 13: Volume Up Fn , default: Volume Up => Volume Up nonstandard, reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 14: Grave Accent , default: Grave Accent => Grave Accent reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 15: Tab Key , default: Standard Tab Key => Standard Tab Key reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 16: Caps Lock , default: Caps Lock => Caps Lock reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 17: Left Shift , default: Left Shift => Left Shift reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 18: Left Control , default: Left Control => Left Control reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 19: Left Option/Start , default: Left Option/Start => Left Option/Start reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 20: Left Command/Alt , default: Left Command/Alt => Left Command/Alt reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 21: Right Command/Alt , default: Right Command/Alt => Right Command/Alt reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 22: unknown:013C , default: Right Option/Start/2 => Right Option/Start/2 reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 23: Right Shift , default: Right Shift => Right Shift reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 24: Backslash , default: Backslash => Backslash reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 25: Delete , default: Delete => Delete reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 26: Home , default: Home => Home reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 27: End , default: End => End reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 28: Page Up , default: Page Up => Page Up reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 29: Page Down , default: Page Down => Page Down reprogrammable, divertable, analytics key events, pos:0, group:0, group mask:empty reporting: default 30: F Lock , default: Do Nothing One => Do Nothing One is FN, analytics key events, pos:0, group:0, group mask:empty reporting: default 31: FN Key , default: Do Nothing One => Do Nothing One nonstandard, analytics key events, pos:0, group:0, group mask:empty reporting: default Battery: 90%, discharging. Solaar-1.1.20/docs/devices/MX Vertical Wireless Mouse 407B.txt000066400000000000000000000140731522022367600234430ustar00rootroot00000000000000Solaar version 1.1.3 2: MX Vertical Wireless Mouse Device path : /dev/hidraw5 WPID : 407B Codename : MX Vertical Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 87A544C3 Model ID: B020407BC08A Unit ID: 7818C6EE Bootloader: BOT 78.00.B0009 Firmware: MPM 16.00.B0009 Other: Supports 34 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 78.00.B0009 AAE28E5B17FF Firmware: Firmware MPM 16.00.B0009 407B8E5B17FF Firmware: Other Unit ID: 7818C6EE Model ID: B020407BC08A Transport IDs: {'btleid': 'B020', 'wpid': '407B', 'usbid': 'C08A'} 3: DEVICE NAME {0005} Name: MX Vertical Advanced Ergonomic Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: DEVICE FRIENDLY NAME {0007} Friendly Name: MX Vertical 8: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 9: unknown:1002 {1002} 10: REPROG CONTROLS V4 {1B04} DPI Sliding Adjustment (saved): Off DPI Sliding Adjustment : Off Mouse Gestures (saved): Off Mouse Gestures : Off Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, DPI Switch:DPI Switch} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Diverted, Forward Button:Diverted, ?, DPI Switch:Diverted} Key/Button Diversion : {Middle Button:Regular, Back Button:Diverted, Forward Button:Diverted, DPI Switch:Diverted} 11: PERSISTENT REMAPPABLE ACTION {1C00} 12: CHANGE HOST {1814} Change Host : 1:pudim 13: HOSTS INFO {1815} Host 0 (unpaired): pudim Host 1 (unpaired): Host 2 (unpaired): 14: XY STATS {2250} 15: unknown:18B1 {18B1} internal, hidden 16: VERTICAL SCROLLING {2100} Roller type: standard Ratchet per turn: 24 Scroll lines: 0 17: LOWRES WHEEL {2130} Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 18: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 2800 Sensitivity (DPI) : 2800 19: DEVICE RESET {1802} internal, hidden 20: unknown:1803 {1803} internal, hidden 21: CONFIG DEVICE PROPS {1806} internal, hidden 22: unknown:1813 {1813} internal, hidden 23: OOBSTATE {1805} internal, hidden 24: unknown:1830 {1830} internal, hidden 25: unknown:1890 {1890} internal, hidden 26: unknown:1891 {1891} internal, hidden 27: unknown:18A1 {18A1} internal, hidden 28: unknown:1DF3 {1DF3} internal, hidden 29: unknown:1E00 {1E00} hidden 30: unknown:1EB0 {1EB0} internal, hidden 31: unknown:1E22 {1E22} internal, hidden 32: unknown:1861 {1861} internal, hidden 33: unknown:18C0 {18C0} internal, hidden Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: diverted 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: diverted 5: DPI Switch , default: DPI Switch => DPI Switch mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: diverted 6: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Has 6 persistent remappable keys: 0: Left Button => Mouse Button: Mouse Button Left 1: Right Button => Mouse Button: Mouse Button Right 2: Middle Button => Mouse Button: Mouse Button Middle 3: Back Button => Mouse Button: Mouse Button Back 4: Forward Button => Mouse Button: Mouse Button Forward 5: unknown:0000 => None Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/MX Vertical Wireless Mouse B020.txt000066400000000000000000000114761522022367600234360ustar00rootroot00000000000000Solaar version 1.1.3 1: MX Vertical Wireless Mouse Device path : /dev/hidraw0 USB id : 046d:B020 Codename : MX Vertical Kind : mouse Protocol : HID++ 4.5 Serial number: Model ID: B020407BC08A Unit ID: 70926049 Bootloader: BOT 78.00.B0009 Firmware: MPM 16.00.B0009 Other: Supports 30 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 78.00.B0009 AAE28E5B17FF Firmware: Firmware MPM 16.00.B0009 B0208E5B17FF Firmware: Other Unit ID: 70926049 Model ID: B020407BC08A Transport IDs: {'btleid': 'B020', 'wpid': '407B', 'usbid': 'C08A'} 3: DEVICE NAME {0005} Name: MX Vertical Advanced Ergonomic Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: DEVICE FRIENDLY NAME {0007} Friendly Name: MX Vertical 8: BATTERY STATUS {1000} Battery: 90%, discharging, next level 50%. 9: unknown:1002 {1002} 10: REPROG CONTROLS V4 {1B04} 11: PERSISTENT REMAPPABLE ACTION {1C00} 12: CHANGE HOST {1814} 13: HOSTS INFO {1815} Host 0 (unpaired): minerva Host 1 (unpaired): theseus Host 2 (unpaired): athena 14: XY STATS {2250} 15: unknown:18B1 {18B1} internal, hidden 16: VERTICAL SCROLLING {2100} Roller type: standard Ratchet per turn: 24 Scroll lines: 0 17: LOWRES WHEEL {2130} Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 18: ADJUSTABLE DPI {2201} 19: unknown:1803 {1803} internal, hidden 20: CONFIG DEVICE PROPS {1806} internal, hidden 21: unknown:1813 {1813} internal, hidden 22: OOBSTATE {1805} internal, hidden 23: unknown:1830 {1830} internal, hidden 24: unknown:18A1 {18A1} internal, hidden 25: unknown:1E00 {1E00} hidden 26: unknown:1EB0 {1EB0} internal, hidden 27: unknown:1E22 {1E22} internal, hidden 28: unknown:1861 {1861} internal, hidden 29: unknown:18C0 {18C0} internal, hidden Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 5: DPI Switch , default: DPI Switch => DPI Switch mse, reprogrammable, divertable, persistently divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 6: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Has 6 persistent remappable keys: 0: Left Button => Mouse Button: Mouse Button Left 1: Right Button => Mouse Button: Mouse Button Right 2: Middle Button => Mouse Button: Mouse Button Middle 3: Back Button => Mouse Button: Mouse Button Back 4: Forward Button => Mouse Button: Mouse Button Forward 5: unknown:0000 => None Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/Marathon Mouse M705 101B.txt000066400000000000000000000042611522022367600217560ustar00rootroot00000000000000Solaar version 1.1.5 1: Marathon Mouse M705 (M-R0009) Device path : /dev/hidraw1 WPID : 101B Codename : M705 (M-R0009) Kind : mouse Protocol : HID++ 1.0 Polling rate : 8 ms (125Hz) Serial number: 23691D3D Firmware: 17.01.B0017 Bootloader: 02.06 Other: 00.04 The power switch is located on the base. Notifications: battery status (0x100000). Features: special buttons, scroll accel (0x420000) Battery: 65%, discharging. registers: # writing 0x10 in this register will generate an event # 10 02 0Dxx yyzz00 # where 0D happens to be the battery register number # xx is the battery charge # yy, zz ? << ( 0.001) [10 02 8100 000000] '\x10\x02\x81\x00\x00\x00\x00' >> ( 1.132) [10 02 8100 100000] '\x10\x02\x81\x00\x10\x00\x00' # smooth scroll - possible values # - 00 (off) # - 02 ?, apparently off as well, default value at power-on # - 0x40 (on) << ( 2.005) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00' >> ( 2.052) [10 02 8101 020000] '\x10\x02\x81\x01\x02\x00\x00' # battery status: percentage full, ?, ? << ( 14.835) [10 02 810D 000000] '\x10\x02\x81\r\x00\x00\x00' >> ( 14.847) [10 02 810D 644734] '\x10\x02\x81\rdG4' # accepts mask 0xF1 # setting 0x10 turns off the movement events (but buttons still work) << ( 221.495) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00' >> ( 221.509) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00' # appears to be read-only? << ( 223.527) [10 02 81D2 000000] '\x10\x02\x81\xd2\x00\x00\x00' >> ( 223.540) [10 02 81D2 000003] '\x10\x02\x81\xd2\x00\x00\x03' # appears to be read-only? << ( 225.557) [10 02 81D4 000000] '\x10\x02\x81\xd4\x00\x00\x00' >> ( 225.571) [10 02 81D4 000004] '\x10\x02\x81\xd4\x00\x00\x04' # read-only, 01-04 firmware info << ( 259.270) [10 02 81F1 000000] '\x10\x02\x81\xf1\x00\x00\x00' >> ( 259.283) [10 02 8F81 F10300] '\x10\x02\x8f\x81\xf1\x03\x00' # writing 01 here will trigger an avalanche of events, most likely # raw input from the mouse; disable by writing 00 << ( 261.300) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00' >> ( 261.315) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00' Solaar-1.1.20/docs/devices/Marathon Mouse M705 406D.txt000066400000000000000000000222401522022367600217650ustar00rootroot00000000000000 3: Marathon Mouse M705 (M-R0073) Device path : /dev/hidraw3 WPID : 406D Codename : M705 (M-R0073) Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: B14D65DA Model ID: 406D00000000 Unit ID: 5E1A15B8 Bootloader: BOT 59.00.B0002 Firmware: RQM 67.01.B0005 The power switch is located on the base. Supports 26 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 59.00.B0002 406D5F5048B901 Firmware: Firmware RQM 67.01.B0005 406D5F5048B901 Unit ID: 5E1A15B8 Model ID: 406D00000000 Transport IDs: {'wpid': '406D'} 3: DEVICE NAME {0005} Name: Marathon Mouse/Performance Plus M705 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 7: REPROG CONTROLS V4 {1B04} Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular} 8: POINTER SPEED {2205} Pointer Speed: 1.0 Sensitivity (Pointer Speed) (saved): 256 Sensitivity (Pointer Speed) : 256 9: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 10: DFUCONTROL SIGNED {00C2} 11: DEVICE RESET {1802} internal, hidden 12: unknown:1803 {1803} internal, hidden 13: CONFIG DEVICE PROPS {1806} internal, hidden 14: unknown:1810 {1810} internal, hidden 15: unknown:1830 {1830} internal, hidden 16: unknown:1890 {1890} internal, hidden 17: unknown:18A1 {18A1} internal, hidden 18: unknown:1DF3 {1DF3} internal, hidden 19: unknown:1E00 {1E00} hidden 20: unknown:1EB0 {1EB0} internal, hidden 21: unknown:1861 {1861} internal, hidden 22: unknown:18B1 {18B1} internal, hidden 23: unknown:1850 {1850} internal, hidden 24: unknown:1F03 {1F03} internal, hidden 25: unknown:18C0 {18C0} internal, hidden Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 5: Left Tilt , default: Mouse Scroll Left Button => Mouse Scroll Left Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 6: Right Tilt , default: Mouse Scroll Right Button => Mouse Scroll Right Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default Battery: 50%, discharging, next level 20%. 3: Marathon Mouse M705 (M-R0073) Device path : /dev/hidraw3 WPID : 406D Codename : M705 (M-R0073) Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: B14D65DA Model ID: 406D00000000 Unit ID: 5E1A15B8 Bootloader: BOT 59.00.B0002 Firmware: RQM 67.01.B0005 The power switch is located on the base. Supports 27 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 59.00.B0002 406D5F5048B901 Firmware: Firmware RQM 67.01.B0005 406D5F5048B901 Unit ID: 5E1A15B8 Model ID: 406D00000000 Transport IDs: {'wpid': '406D'} 3: DEVICE NAME {0005} Name: Marathon Mouse/Performance Plus M705 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 7: REPROG CONTROLS V4 {1B04} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular} 8: POINTER SPEED {2205} Pointer Speed: 1.0 Sensitivity (Pointer Speed) : 256 9: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 10: DFUCONTROL SIGNED {00C2} 11: DEVICE RESET {1802} internal, hidden 12: unknown:1803 {1803} internal, hidden 13: CONFIG DEVICE PROPS {1806} internal, hidden 14: unknown:1810 {1810} internal, hidden 15: unknown:1830 {1830} internal, hidden 16: unknown:1890 {1890} internal, hidden 17: unknown:18A1 {18A1} internal, hidden 18: unknown:1DF3 {1DF3} internal, hidden 19: unknown:1E00 {1E00} hidden 20: unknown:1EB0 {1EB0} internal, hidden 21: unknown:1861 {1861} internal, hidden 22: unknown:18B1 {18B1} internal, hidden 23: unknown:1850 {1850} internal, hidden 24: unknown:1F03 {1F03} internal, hidden 25: unknown:18C0 {18C0} internal, hidden 26: HIRES WHEEL {2121} Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode Low resolution mode HID notification Scroll Wheel Direction : False Scroll Wheel Resolution : False Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 5: Left Tilt , default: Mouse Scroll Left Button => Mouse Scroll Left Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 6: Right Tilt , default: Mouse Scroll Right Button => Mouse Scroll Right Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Multi Device Silent Mouse M585-M590 406B.txt000066400000000000000000000154271522022367600243520ustar00rootroot00000000000000Solaar version 1.1.7 2: Multi Device Silent Mouse M585/M590 Device path : /dev/hidraw2 WPID : 406B Codename : M585/M590 Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 37216581 Model ID: B01B406B0000 Unit ID: F2D653C0 Bootloader: BOT 48.00.B0001 Firmware: MPM 05.02.B0007 Other: The power switch is located on the base. Supports 34 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BOT 48.00.B0001 00005BEB5EE001 Firmware: Firmware MPM 05.02.B0007 406B5BEB5EE001 Firmware: Other Unit ID: F2D653C0 Model ID: B01B406B0000 Transport IDs: {'btleid': 'B01B', 'wpid': '406B'} 3: DEVICE NAME {0005} V0 Name: M585/M590 Multi-Device Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: CRYPTO ID {0021} V0 7: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: M585/M590 8: BATTERY STATUS {1000} V0 Battery: 50%, discharging, next level 20%. 9: CHANGE HOST {1814} V1 Cambiar Host : 1:romanescu 10: HOSTS INFO {1815} V1 Host 0 (paired): romanescu Host 1 (paired): espinaca 11: REPROG CONTROLS V4 {1B04} V3 Acciones de Tecla/Botón (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button} Acciones de Tecla/Botón : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button} Desvio de Tecla/Botón (saved): {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Left Tilt:Normal, Right Tilt:Normal} Desvio de Tecla/Botón : {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Left Tilt:Normal, Right Tilt:Normal} 12: PERSISTENT REMAPPABLE ACTION {1C00} V0 Persistent Key/Button Mapping : {Left Button:Mouse Button Left, Right Button:Mouse Button Right, Middle Button:Mouse Button Middle, Back Button:Mouse Button Back, Forward Button:Mouse Button Forward, Left Tilt:Horizontal Scroll Left, Right Tilt:Horizontal Scroll Right} 13: POINTER SPEED {2205} V0 Pointer Speed: 1.0 Sensibilidad (Velocidad del puntero) (saved): 256 Sensibilidad (Velocidad del puntero) : 256 14: VERTICAL SCROLLING {2100} V0 Roller type: standard Ratchet per turn: 18 Scroll lines: 0 15: DFUCONTROL SIGNED {00C2} V0 16: DEVICE RESET {1802} V0 internal, hidden 17: unknown:1803 {1803} V0 internal, hidden 18: CONFIG DEVICE PROPS {1806} V0 internal, hidden 19: OOBSTATE {1805} V0 internal, hidden 20: unknown:1813 {1813} V0 internal, hidden 21: unknown:1830 {1830} V0 internal, hidden 22: unknown:1861 {1861} V0 internal, hidden 23: unknown:1890 {1890} V0 internal, hidden 24: unknown:1891 {1891} V0 internal, hidden 25: unknown:18A1 {18A1} V0 internal, hidden 26: unknown:1DF3 {1DF3} V0 internal, hidden 27: unknown:1E00 {1E00} V0 hidden 28: unknown:1EB0 {1EB0} V0 internal, hidden 29: unknown:18B1 {18B1} V0 internal, hidden 30: unknown:1850 {1850} V0 internal, hidden 31: unknown:1F03 {1F03} V0 internal, hidden 32: unknown:18C0 {18C0} V0 internal, hidden 33: LOWRES WHEEL {2130} V0 Wheel Reports: HID Desvio Rueda Desplazamiento (saved): False Desvio Rueda Desplazamiento : False Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 5: Left Tilt , default: Mouse Scroll Left Button => Mouse Scroll Left Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 6: Right Tilt , default: Mouse Scroll Right Button => Mouse Scroll Right Button mse, reprogrammable, divertable, persistently divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Has 7 persistent remappable keys: 0: Left Button => Mouse Button: Mouse Button Left 1: Right Button => Mouse Button: Mouse Button Right 2: Middle Button => Mouse Button: Mouse Button Middle 3: Back Button => Mouse Button: Mouse Button Back 4: Forward Button => Mouse Button: Mouse Button Forward 5: Left Tilt => Horizontal Scroll: Horizontal Scroll Left 6: Right Tilt => Horizontal Scroll: Horizontal Scroll Right Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Nano Receiver C52F.txt000066400000000000000000000003451522022367600211760ustar00rootroot00000000000000Nano Receiver Device path : /dev/hidraw3 USB id : 046d:c52f Serial : 6D0342C5 Firmware : 30.00.B0009 Has 1 paired device(s) out of a maximum of 1. Notifications: (none) Seen with Marathon Mouse M705 Solaar-1.1.20/docs/devices/Nano Receiver C534.txt000066400000000000000000000005571522022367600211620ustar00rootroot00000000000000Solaar version 1.1.4rc2 Nano Receiver Device path : /dev/hidraw1 USB id : 046d:C534 Serial : None Firmware : 29.01.B0016 Has 2 paired device(s) out of a maximum of 2. Has 18 successful pairing(s) remaining. Notifications: wireless, software present (0x000900) Seen paired with Wireless Keyboard 4075 and Wireless Mouse M185 new 4054 Solaar-1.1.20/docs/devices/Nano Receiver C535.txt000066400000000000000000000004451522022367600211570ustar00rootroot00000000000000Solaar version 1.1.5 Nano Receiver Device path : /dev/hidraw5 USB id : 046d:C535 Serial : 1F3F94FC Firmware : 31.00.B0001 Has 1 paired device(s) out of a maximum of 1. Has 39 successful pairing(s) remaining. Notifications: wireless, software present (0x000900) Solaar-1.1.20/docs/devices/Number Pad N545 2006.txt000066400000000000000000000007351522022367600210420ustar00rootroot00000000000000solaar version 1.1.8 3: Number Pad N545 Device path : /dev/hidraw3 WPID : 2006 Codename : N545 Kind : numpad Protocol : HID++ 1.0 Polling rate : 20 ms (50Hz) Serial number: 900A4D98 Firmware: 13.00.B0037 Bootloader: 02.03 Other: 00.01 The power switch is located on the base. Notifications: battery status (0x100000). Features: (none) Battery: full, discharging. Solaar-1.1.20/docs/devices/PRO X 2 40A9.text000066400000000000000000000061441522022367600176560ustar00rootroot00000000000000solaar version 1.1.10 Receiver Device path : /dev/hidraw3 USB id : 046d:C54D Serial : 8FF3BF7B Firmware : 07.00.B0008 Bootloader : 00.08 Other : C1.53 Has 1 paired device(s) out of a maximum of 2. Notifications: (none) Device activity counters: 1=51 1: PRO X 2 Device path : None WPID : 40A9 Codename : PRO X 2 Kind : mouse Protocol : HID++ 4.2 Polling rate : 8 ms (125Hz) Serial number: Model ID: 40A9C09B0000 Unit ID: Bootloader: BL1 71.00.B0012 Firmware: MPM 32.00.B0012 Supports 32 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: Bootloader BL1 71.00.B0012 AB1CDBC0A7D9 Firmware: Firmware MPM 32.00.B0012 40A9DBC0A7D9 Unit ID: Model ID: 40A9C09B0000 Transport IDs: {'wpid': '40A9', 'usbid': 'C09B'} 3: DEVICE NAME {0005} V2 Name: PRO X 2 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: UNIFIED BATTERY {1004} V3 Battery: 96%, discharging. 7: XY STATS {2250} V1 8: WHEEL STATS {2251} V0 9: unknown:2202 {2202} V0 EXTENDED_ADJUSTABLE_DPI 10: MODE STATUS {8090} V2 11: unknown:8061 {8061} V0 EXTENDED_ADJUSTABLE_REPORT_RATE 12: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Enable Onboard Profiles : Enable 13: MOUSE BUTTON SPY {8110} V0 14: unknown:1500 {1500} V0 FORCE_PAIRING 15: unknown:1801 {1801} V0 internal, hidden, unknown:000010 16: DEVICE RESET {1802} V0 internal, hidden, unknown:000010 17: unknown:1803 {1803} V0 internal, hidden, unknown:000010 18: CONFIG DEVICE PROPS {1806} V8 internal, hidden, unknown:000010 19: unknown:1817 {1817} V0 internal, hidden, unknown:000010 20: OOBSTATE {1805} V0 internal, hidden 21: unknown:1830 {1830} V0 internal, hidden, unknown:000010 22: unknown:1875 {1875} V0 internal, hidden, unknown:000010 23: unknown:1861 {1861} V1 internal, hidden, unknown:000010 24: unknown:1890 {1890} V9 internal, hidden, unknown:000008 25: unknown:18A1 {18A1} V0 internal, hidden, unknown:000010 26: unknown:1E00 {1E00} V0 hidden 27: unknown:1E02 {1E02} V0 internal, hidden 28: unknown:1E22 {1E22} V1 internal, hidden, unknown:000010 29: unknown:1602 {1602} V0 30: unknown:1EB0 {1EB0} V0 internal, hidden, unknown:000010 31: unknown:18B1 {18B1} V0 internal, hidden, unknown:000010 Battery: 96%, discharging. Solaar-1.1.20/docs/devices/PRO X 2 LIGHTSPEED 0AF7.text000066400000000000000000000032221522022367600213010ustar00rootroot00000000000000solaar version 1.1.19-24-g693159ee Centurion Receiver Device path : /dev/hidraw4 USB id : 046d:0AF7 Protocol : Centurion 1 : 0.02 Has 1 device(s) out of a maximum of 1. Supports 5 dongle features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: CENTURION DEVICE INFO {0100} Firmware: 1 0.02 Hardware: model 26 rev 255 product 0508 3: CENTPP BRIDGE {0003} 4: CENTURION GENERIC DFU {010A} 1: PRO X 2 LIGHTSPEED Device path : /dev/hidraw4 USB id : 046d:0AF7 Codename : PRO X 2 LIGHTSPEED Kind : headset Protocol : Centurion 2.6 Serial number: Model ID: 0508 Unit ID: 1: 0.02 Supports 10 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: CENTURION DEVICE NAME {0101} V0 3: CENTURION DEVICE INFO {0100} V0 Firmware: 1 0.02 Serial: Hardware: model 26 rev 255 product 0508 4: CENTURION BATTERY SOC {0104} V0 Battery: 97%, BatteryStatus.DISCHARGING. 5: CENTURION GENERIC DFU {010A} V0 6: CENTURION AUTO SLEEP {0108} V0 Auto Sleep Timeout: 10 7: HEADSET AUDIO SIDETONE {0604} V0 Headset Sidetone: 55 8: HEADSET MIC SNR {0602} V0 Mic SNR: True 9: HEADSET ONBOARD EQ {0636} V0 EQ: 80Hz:+0dB, 240Hz:+0dB, 750Hz:+0dB, 2200Hz:+0dB, 6600Hz:+0dB Battery: 97%, BatteryStatus.DISCHARGING. Solaar-1.1.20/docs/devices/PRO X 2 Superstrike 40BD.txt000066400000000000000000000104411522022367600220210ustar00rootroot00000000000000Solaar version 1.1.19 1: PRO X 2 Superstrike Device path : None WPID : 40BD Codename : PRO X 2 Superstrike Kind : mouse Protocol : HID++ 4.2 Report Rate : 1ms Serial number: Model ID: 40BDC0A80000 Unit ID: Bootloader: BL2 73.00.B0011 Firmware: MPM 42.00.B0011 The power switch is located on the base. Supports 36 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V7 Firmware: Bootloader BL2 73.00.B0011 Firmware: Firmware MPM 42.00.B0011 Unit ID: Model ID: 40BDC0A80000 Transport IDs: {'wpid': '40BD', 'usbid': 'C0A8'} 3: DEVICE NAME {0005} V5 Name: PRO X2 SUPERSTRIKE Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: UNIFIED BATTERY {1004} V5 7: XY STATS {2250} V1 8: WHEEL STATS {2251} V0 9: EXTENDED ADJUSTABLE DPI {2202} V0 Sensitivity (DPI): {X:800, Y:800, LOD:HIGH} 10: MODE STATUS {8090} V3 11: unknown:80E0 {80E0} V0 12: SUPERSTRIKE TUNING {1B0C} V0 Left Button Actuation Point: 5 Left Button Rapid Trigger Level: 3 Left Button Click Haptics: 3 Right Button Actuation Point: 5 Right Button Rapid Trigger Level: 3 Right Button Click Haptics: 3 13: EXTENDED ADJUSTABLE REPORT RATE {8061} V0 Report Rate: 1ms 14: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles: Profile 1 15: MOUSE BUTTON SPY {8110} V0 16: FORCE PAIRING {1500} V0 17: unknown:1801 {1801} V0 internal, hidden 18: DEVICE RESET {1802} V0 19: unknown:1803 {1803} V0 internal, hidden 20: CONFIG DEVICE PROPS {1806} V8 21: unknown:1817 {1817} V0 internal, hidden 22: OOBSTATE {1805} V0 23: unknown:1830 {1830} V0 internal, hidden 24: unknown:1877 {1877} V0 internal, hidden 25: unknown:9403 {9403} V0 internal, hidden 26: unknown:1861 {1861} V0 internal, hidden 27: unknown:1890 {1890} V0 internal, hidden 28: unknown:18A1 {18A1} V0 internal, hidden 29: unknown:1E00 {1E00} V0 hidden 30: unknown:1E02 {1E02} V0 internal, hidden 31: unknown:1E22 {1E22} V0 internal, hidden 32: unknown:1E30 {1E30} V0 internal, hidden 33: unknown:1602 {1602} V0 34: unknown:1EB0 {1EB0} V0 internal, hidden 35: unknown:18B1 {18B1} V0 internal, hidden Battery: discharging. SUPERSTRIKE TUNING Feature (0x1B0C) ----------------------------------- This feature controls the HITS (Hall-Effect Inductive Trigger Switch) settings for the left and right mouse buttons. Capabilities (function 0x00): Byte 0: Flags Byte 1: Button count (3, but only 0 and 1 are accessible) Byte 2: Max actuation value (40) Byte 3: Max rapid trigger value (20) Byte 4: Max haptics value (20) Read button settings (function 0x20, param: button_index): Response: [button_index, actuation, rapid_trigger, haptics, ...] - actuation: 4-40 (quantized to multiples of 4) - rapid_trigger: 1-20 (cannot be set to 0) - haptics: 0-20 (quantized to multiples of 4: 0, 4, 8, 12, 16, 20) Write button settings (function 0x10): Params: [button_index, actuation, rapid_trigger, haptics] Solaar Settings: - superstrike-tuning_actuation-{0,1}: Range 1-10 (maps to device 4-40) - superstrike-tuning_rapid-trigger-level-{0,1}: Range 1-5 (maps to device 1-20) - superstrike-tuning_haptics-{0,1}: Range 0-5 (maps to device 0-20) Note: Feature 0x80E0 (unknown:80E0) appears to be a non-functional stub for haptics. Haptics are actually controlled via byte 3 of the SUPERSTRIKE TUNING feature. Note: Feature 0x9403 (unknown:9403) appears to be a hidden BHOP (bunny hop) feature that is not accessible via HID++. Solaar-1.1.20/docs/devices/PRO X Wireless 4093.txt000066400000000000000000000053741522022367600211330ustar00rootroot00000000000000Solaar version 1.1.14 2: PRO X Wireless Device path : None WPID : 4093 Codename : PRO X Kind : mouse Protocol : HID++ 4.2 Report Rate : 1ms Serial number: 8B24D1D1 Model ID: 4093C0940000 Unit ID: 8B24D1D1 1: BL1 25.01.B0018 3: 0: MPM 25.01.B0018 Supports 28 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V3 Firmware: 1 BL1 25.01.B0018 AB00FE92436C Firmware: 3 Firmware: 0 MPM 25.01.B0018 4093FE92436C Unit ID: 8B24D1D1 Model ID: 4093C0940000 Transport IDs: {'wpid': '4093', 'usbid': 'C094'} 3: DEVICE NAME {0005} V0 Name: PRO X Wireless Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 11000000000000000000000000000000 6: UNIFIED BATTERY {1004} V1 Battery: 71%, 0. 7: COLOR LED EFFECTS {8070} V4 internal, hidden LED Control : HID++ error {'number': 2, 'request': 1908, 'error': 5, 'params': b''} 8: ONBOARD PROFILES {8100} V0 Device Mode: On-Board Onboard Profiles (saved): Profile 1 Onboard Profiles : Profile 1 9: MOUSE BUTTON SPY {8110} V0 10: REPORT RATE {8060} V0 Report Rate: 1ms Report Rate (saved): 1ms Report Rate : 1ms 11: ADJUSTABLE DPI {2201} V2 Sensitivity (DPI) (saved): 800 Sensitivity (DPI) : 800 12: FORCE PAIRING {1500} V0 13: DEVICE RESET {1802} V0 internal, hidden 14: unknown:1803 {1803} V0 internal, hidden 15: CONFIG DEVICE PROPS {1806} V4 internal, hidden 16: unknown:1811 {1811} V0 internal, hidden 17: OOBSTATE {1805} V0 internal, hidden 18: unknown:1830 {1830} V0 internal, hidden 19: unknown:1890 {1890} V5 internal, hidden 20: unknown:1891 {1891} V5 internal, hidden 21: unknown:18A1 {18A1} V0 internal, hidden 22: unknown:1801 {1801} V0 internal, hidden 23: unknown:18B1 {18B1} V0 internal, hidden 24: unknown:1E00 {1E00} V0 hidden 25: unknown:1EB0 {1EB0} V0 internal, hidden 26: unknown:1863 {1863} V0 internal, hidden 27: unknown:1E22 {1E22} V0 internal, hidden Battery: 71%, 0. Solaar-1.1.20/docs/devices/Rechargeable Trackpad T651 B00C.txt000066400000000000000000000021721522022367600232410ustar00rootroot00000000000000Solaar version 1.1.7 1: Rechargeable Trackpad T651 Device path : /dev/hidraw9 USB id : 046d:B00C Codename : Rechargeable Kind : touchpad Protocol : HID++ 2.0 Serial number: Model ID: 000000000000 Unit ID: 00000000 Firmware: RBM 05.00.B0026 Other: Supports 9 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: FEATURE INFO {0002} V0 3: DEVICE FW VERSION {0003} V0 Firmware: Firmware RBM 05.00.B0026 B00C Firmware: Other Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 4: DEVICE NAME {0005} V0 Name: Rechargeable Trackpad T651 Kind: touchpad 5: unknown:1E00 {1E00} V0 hidden 6: GENERIC TEST {1800} V0 internal, hidden 7: BATTERY STATUS {1000} V0 Battery: 90%, discharging, next level 70%. 8: TOUCHPAD RAW XY {6100} V0 Battery: 90%, discharging, next level 70%. Solaar-1.1.20/docs/devices/Signature M550.text000066400000000000000000000077701522022367600206640ustar00rootroot00000000000000solaar version 1.1.19 1: Signature M550 Device path : None WPID : B02B Codename : Logi M550 Kind : mouse Protocol : HID++ 4.5 Serial number: D074434E Model ID: B02B00000000 Unit ID: D074434E 1: BL1 39.01.B0013 0: RBM 17.01.B0013 3: The power switch is located on the (unknown). Supports 30 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V4 Firmware: 1 BL1 39.01.B0013 B02BB0706FCD Firmware: 0 RBM 17.01.B0013 B02BB0706FCD Firmware: 3 Unit ID: D074434E Model ID: B02B00000000 Transport IDs: {'btleid': 'B02B'} 3: DEVICE NAME {0005} V0 Name: Signature M550 Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 Configuration: 11000000000000000000000000000000 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: Logi M550 7: UNIFIED BATTERY {1004} V3 Battery: 35%, BatteryStatus.DISCHARGING. 8: REPROG CONTROLS V4 {1B04} V5 Key/Button Actions (saved): {Middle Button:Mouse Middle Button} Key/Button Actions : {Middle Button:Mouse Middle Button} Key/Button Diversion (saved): {Middle Button:Regular} Key/Button Diversion : {Middle Button:Regular} 9: HOSTS INFO {1815} V2 Host 0 (paired): mst 10: XY STATS {2250} V1 11: LOWRES WHEEL {2130} V0 Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 12: ADJUSTABLE DPI {2201} V2 Sensitivity (DPI) (saved): 1000 Sensitivity (DPI) : 1000 13: DFUCONTROL {00C3} V0 14: DEVICE RESET {1802} V0 15: unknown:1803 {0318} V0 internal, hidden, unknown:000010 16: CONFIG DEVICE PROPS {1806} V8 17: unknown:1816 {1618} V0 internal, hidden, unknown:000010 18: OOBSTATE {1805} V0 19: unknown:1830 {3018} V0 internal, hidden, unknown:000010 20: unknown:1891 {9118} V0 internal, hidden, unknown:000008 21: unknown:18A1 {A118} V0 internal, hidden, unknown:000010 22: unknown:1E00 {001E} V0 hidden 23: unknown:1E02 {021E} V0 internal, hidden 24: unknown:1E22 {221E} V0 internal, hidden, unknown:000010 25: unknown:1602 {0216} V0 26: unknown:1EB0 {B01E} V0 internal, hidden, unknown:000010 27: unknown:1861 {6118} V0 internal, hidden, unknown:000010 28: unknown:18B1 {B118} V0 internal, hidden, unknown:000010 29: unknown:920A {0A92} V0 internal, hidden, unknown:000010 Has 4 reprogrammable keys: 0: Left Button , default: Left Click => Left Click analytics_key_events, mse, pos:0, group:1, group mask:empty reporting: default 1: Right Button , default: Right Click => Right Click analytics_key_events, mse, pos:0, group:1, group mask:empty reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button analytics_key_events, raw_xy, divertable, reprogrammable, mse, pos:0, group:2, group mask:g1,g2 reporting: default 3: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button force_raw_xy, raw_xy, virtual, divertable, pos:0, group:3, group mask:empty reporting: default Battery: 35%, BatteryStatus.DISCHARGING. Solaar-1.1.20/docs/devices/Signature M650 L Mouse B02A.txt000066400000000000000000000113321522022367600223370ustar00rootroot00000000000000Solaar version 1.1.3 2: Signature M650 L Mouse Device path : None WPID : B02A Codename : Logi M650 L Kind : mouse Protocol : HID++ 4.5 Serial number: 46756ABD Model ID: B02A00000000 Unit ID: 46756ABD Bootloader: BL1 38.01.B0011 Firmware: RBM 16.02.B0013 Other: The power switch is located on the (unknown). Supports 29 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BL1 38.01.B0011 B02ADFC9033D Firmware: Firmware RBM 16.02.B0013 B02AB0706FCD Firmware: Other Unit ID: 46756ABD Model ID: B02A00000000 Transport IDs: {'btleid': 'B02A'} 3: DEVICE NAME {0005} Name: Signature M650 L Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: DEVICE FRIENDLY NAME {0007} Friendly Name: Logi M650 L 7: UNIFIED BATTERY {1004} 8: REPROG CONTROLS V4 {1B04} DPI Sliding Adjustment (saved): Off DPI Sliding Adjustment : Off Mouse Gestures (saved): Off Mouse Gestures : Off Key/Button Actions (saved): {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button} Key/Button Actions : {Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular} 9: HOSTS INFO {1815} Host 0 (paired): legion15 10: XY STATS 11: LOWRES WHEEL {2130} Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 12: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 1200 Sensitivity (DPI) : 1200 13: DFUCONTROL {00C3} 14: DEVICE RESET {1802} internal, hidden, unknown:000010 15: unknown:1803 {1803} internal, hidden, unknown:000010 16: CONFIG DEVICE PROPS {1806} internal, hidden, unknown:000010 17: unknown:1816 {1816} internal, hidden, unknown:000010 18: OOBSTATE {1805} internal, hidden 19: unknown:1830 {1830} internal, hidden, unknown:000010 20: unknown:1891 {1891} internal, hidden, unknown:000008 21: unknown:18A1 {18A1} internal, hidden, unknown:000010 22: unknown:1E00 {1E00} hidden 23: unknown:1E02 {1E02} internal, hidden 24: unknown:1E22 {1E22} internal, hidden, unknown:000010 25: unknown:1602 {1602} 26: unknown:1EB0 {1EB0} internal, hidden, unknown:000010 27: unknown:1861 {1861} internal, hidden, unknown:000010 28: unknown:18B1 {18B1} internal, hidden, unknown:000010 Has 6 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, analytics key events, pos:0, group:1, group mask:empty reporting: default 1: Right Button , default: Right Click => Right Click mse, analytics key events, pos:0, group:1, group mask:empty reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:3, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, analytics key events, unknown:000800, pos:0, group:2, group mask:g1,g2 reporting: default 5: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Battery: 95%, discharging. Solaar-1.1.20/docs/devices/Unifying Receiver C52B.txt000066400000000000000000000005261522022367600220700ustar00rootroot00000000000000Solaar version 1.1.4 Unifying Receiver Device path : /dev/hidraw0 USB id : 046d:C52B Serial : E0662192 Firmware : 24.11.B0036 Bootloader : 02.09 Other : AA.AC Has 2 paired device(s) out of a maximum of 6. Notifications: wireless, software present (0x000900) Device activity counters: 1=225, 2=132 Solaar-1.1.20/docs/devices/Wireless All-in-One Keyboard TK820 4102.txt000066400000000000000000000075321522022367600243750ustar00rootroot00000000000000Solaar version 1.1.1 1: Wireless All-in-One Keyboard TK820 Device path : /dev/hidraw5 WPID : 4102 Codename : TK820 Kind : keyboard Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: 7D7699C9 Model ID: 000000000000 Unit ID: 00000000 Firmware: RQK 52.00.B0025 Bootloader: BL 02.00.B0001 Hardware: 72 Other: The power switch is located on the top right corner. Supports 28 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: FEATURE INFO {0002} 3: DEVICE FW VERSION {0003} Firmware: Firmware RQK 52.00.B0025 4102 Firmware: Bootloader BL 02.00.B0001 4102 Firmware: Hardware 72 Firmware: Other Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 4: DEVICE NAME {0005} Name: Wireless All-in-One Keyboard TK820 Kind: keyboard 5: BATTERY STATUS {1000} Battery: 20%, discharging, next level 5%. 6: WIRELESS DEVICE STATUS {1D4B} 7: unknown:1DF3 {1DF3} internal, hidden 8: REPROG CONTROLS {1B00} 9: unknown:1F03 {1F03} internal, hidden 10: FN INVERSION {40A0} Swap Fx function (saved): True Swap Fx function : True 11: NEW FN INVERSION {40A2} Fn-swap: enabled Fn-swap default: enabled 12: MOUSE POINTER {2200} DPI: 1000 Acceleration: low Override OS ballistics No vertical tuning, standard mice 13: DFUCONTROL LEGACY {00C0} 14: unknown:1E80 {1E80} internal, hidden 15: TOUCHPAD RAW XY {6100} 16: unknown:1860 {1860} internal, hidden 17: unknown:1E00 {1E00} hidden 18: REPROG CONTROLS V3 {1B03} 19: unknown:1890 {1890} internal, hidden 20: unknown:18E6 {18E6} internal, hidden 21: unknown:18A0 {18A0} internal, hidden 22: unknown:1830 {1830} internal, hidden 23: unknown:1F04 {1F04} internal, hidden 24: unknown:1EA1 {1EA1} internal, hidden 25: unknown:18B0 {18B0} internal, hidden 26: ENCRYPTION {4100} 27: KEYBOARD LAYOUT {4520} Has 15 reprogrammable keys: 0: Fn Left Click => ShowUI divertable 1: Metro Appswitch => MetroAppSwitch is FN, reprogrammable 2: Metro Search => MetroSearch is FN, reprogrammable 3: unknown:00B2 => MetroShare2 is FN, reprogrammable 4: unknown:00B3 => MetroDevices2 is FN, reprogrammable 5: unknown:00B4 => MetroSettings2 is FN, reprogrammable 6: Previous => Previous is FN 7: Play/Pause => Play/Pause is FN 8: Next => Next is FN 9: Mute => Mute is FN 10: Volume Down => Volume Down is FN 11: Volume Up => Volume Up is FN 12: Sleep => Sleep is FN, reprogrammable 13: Left Button => Left Click mse 14: Right Button => Right Click mse Battery: 20%, discharging, next level 5 Solaar-1.1.20/docs/devices/Wireless Illuminated Keyboard K800 2010.txt000066400000000000000000000056311522022367600246550ustar00rootroot00000000000000 2: Wireless Illuminated Keyboard K800 Codename : K800 Kind : keyboard Wireless PID : 2010 Protocol : HID++ 1.0 Polling rate : 20 ms (50Hz) Serial number: FFC65665 Firmware: 22.01.B0019 Bootloader: 02.01 Other: 00.07 The power switch is located on the top right corner. Notifications: battery status (0x100000). Battery: full, discharging. # 0x00 - Enabled Notifications. rw (see HID++ 1.0 spec) << ( 0.055) [10 02 8100 000000] '\x10\x02\x81\x00\x00\x00\x00' >> ( 0.084) [10 02 8100 000000] '\x10\x02\x81\x00\x00\x00\x00' # 0x01 - Keyboard hand detection. rw, last param is 00 when hand detection is # enabled, 30 when disabled. (when enabled, keyboard will light up if not # already when hovering over the front) << ( 1.085) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00' >> ( 1.114) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00' # 0x07 - Battery status (3 = one bar; 1 = red/critical; 5=two bars; 7=three # bars/full. Second returned param is 25 when keyboard is charging ) << ( 7.327) [10 02 8107 000000] '\x10\x02\x81\x07\x00\x00\x00' >> ( 7.368) [10 02 8107 030000] '\x10\x02\x81\x07\x03\x00\x00' # 0x09 - F key function. rw (read: status, set/get: 00 01 00 means swap # functions, 00 00 00 means do not swap functions) << ( 9.411) [10 02 8109 000000] '\x10\x02\x81\t\x00\x00\x00' >> ( 9.440) [10 02 8109 000000] '\x10\x02\x81\t\x00\x00\x00' # 0x17 - Illumination info r/w. Last param: 02 to disable backlight, 01 to # enable backlight << ( 24.965) [10 02 8117 000000] '\x10\x02\x81\x17\x00\x00\x00' >> ( 24.988) [10 02 8117 3C0001] '\x10\x02\x81\x17<\x00\x01' # 0x51 - ? << ( 99.294) [10 02 8151 000000] '\x10\x02\x81Q\x00\x00\x00' >> ( 99.543) [10 02 8151 000000] '\x10\x02\x81Q\x00\x00\x00' # 0x54 - ? << ( 103.046) [10 02 8154 000000] '\x10\x02\x81T\x00\x00\x00' >> ( 103.295) [10 02 8154 FF0000] '\x10\x02\x81T\xff\x00\x00' # 0xD0 - ? << ( 253.860) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00' >> ( 253.883) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00' # 0xF1 - Version info (params 0n 00 00 where n is 1..4) << ( 289.991) [10 02 81F1 000000] '\x10\x02\x81\xf1\x00\x00\x00' >> ( 290.032) [10 02 8F81 F10300] '\x10\x02\x8f\x81\xf1\x03\x00' # 0xF3 - ? << ( 292.075) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00' >> ( 292.116) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00' # 0x0F - This changes, the last commented line was observed in an earlier run << ( 17.728) [10 02 830F 000000] '\x10\x02\x83\x0f\x00\x00\x00' >> ( 17.976) [11 02 830F FFFB00000240025C000000000FF90080] '\x11\x02\x83\x0f\xff\xfb\x00\x00\x02@\x02\\\x00\x00\x00\x00\x0f\xf9\x00\x80' #>> ( 17.999) [11 02 830F FFFC007F0243025D000000000FF60080] '\x11\x02\x83\x0f\xff\xfc\x00\x7f\x02C\x02]\x00\x00\x00\x00\x0f\xf6\x00\x80' # See also https://git.lekensteyn.nl/ltunify/tree/registers.txt for a verbose # meaning of registers and params. Solaar-1.1.20/docs/devices/Wireless Illuminated Keyboard K800 new 406E.txt000066400000000000000000000100471522022367600254600ustar00rootroot00000000000000 2: Wireless Illuminated Keyboard K800 new Codename : new Kind : keyboard Wireless PID : 406E Protocol : HID++ 4.5 Polling rate : 20 ms (50Hz) Serial number: 636E1413 Bootloader: BOT 60.00.B0002 Firmware: RQK 68.01.B0009 The power switch is located on the top right corner. Supports 25 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY STATUS {1000} 7: unknown:1983 {1983} 8: REPROG CONTROLS V4 {1B04} 9: FN INVERSION {40A0} 10: ENCRYPTION {4100} 11: KEYBOARD DISABLE {4521} 12: unknown:00C2 {00C2} 13: unknown:1803 {1803} internal, hidden 14: unknown:1806 {1806} internal, hidden 15: unknown:1811 {1811} internal, hidden 17: unknown:1890 {1890} internal, hidden 18: unknown:18A1 {18A1} internal, hidden 19: unknown:1DF3 {1DF3} internal, hidden 20: unknown:1E00 {1E00} hidden 21: unknown:1EB0 {1EB0} internal, hidden 22: unknown:1861 {1861} internal, hidden 23: unknown:1A20 {1A20} internal, hidden 24: unknown:18B0 {18B0} internal, hidden Has 15 reprogrammable keys: 0: MY HOME , default: HomePage => MY HOME is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, gmask:0 1: Mail , default: Email => Mail is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, gmask:0 2: SEARCH , default: SearchForFiles => SEARCH is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, gmask:0 3: Application Switcher , default: Application Switcher => Application Switcher is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, gmask:0 4: unknown:00E2 , default: unknown:00C1 => unknown:00E2 is FN, FN sensitive, divertable, pos:5, group:0, gmask:0 5: unknown:00E3 , default: unknown:00C2 => unknown:00E3 is FN, FN sensitive, divertable, pos:6, group:0, gmask:0 6: SLEEP , default: Sleep => SLEEP is FN, FN sensitive, reprogrammable, divertable, pos:8, group:0, gmask:0 7: MEDIA PLAYER , default: Music => MEDIA PLAYER is FN, FN sensitive, reprogrammable, divertable, pos:9, group:0, gmask:0 8: Previous , default: Previous => Previous is FN, FN sensitive, divertable, pos:10, group:0, gmask:0 9: Play/Pause , default: Play/Pause => Play/Pause is FN, FN sensitive, divertable, pos:11, group:0, gmask:0 10: Next , default: Next => Next is FN, FN sensitive, divertable, pos:12, group:0, gmask:0 11: Volume Up , default: Volume Up => Volume Up nonstandard, divertable, pos:0, group:0, gmask:0 12: Volume Down , default: Volume Down => Volume Down nonstandard, divertable, pos:0, group:0, gmask:0 13: Mute , default: Mute => Mute nonstandard, divertable, pos:0, group:0, gmask:0 14: Calculator , default: Calculator => Calculator nonstandard, reprogrammable, divertable, pos:0, group:0, gmask:0 Battery: 50%, discharging. Solaar-1.1.20/docs/devices/Wireless Keyboard 4075.txt000066400000000000000000000060221522022367600220320ustar00rootroot00000000000000Solaar version 1.1.4rc2 1: Wireless Keyboard Device path : /dev/hidraw2 WPID : 4075 Codename : Kind : keyboard Protocol : HID++ 4.5 Polling rate : 20 ms (50Hz) Serial number: 00000000 Model ID: 000000000000 Unit ID: 00000000 Firmware: RQK 71.00.B0002 Supports 19 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Firmware RQK 71.00.B0002 4075 Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} Name: Wireless Keyboard Kind: keyboard 4: RESET {0020} 5: BATTERY STATUS {1000} Battery: 30%, discharging, next level 5%. 6: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Calculator:Regular, Mail:Regular, My Home:Regular, Search:Regular} Key/Button Diversion : {Calculator:Regular, Mail:Regular, My Home:Regular, Search:Regular} 7: WIRELESS DEVICE STATUS {1D4B} 8: NEW FN INVERSION {40A2} Fn-swap: disabled Fn-swap default: disabled Swap Fx function (saved): False Swap Fx function : False 9: ENCRYPTION {4100} 10: LOCK KEY STATE {4220} 11: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 12: unknown:1810 {1810} internal, hidden 13: unknown:1830 {1830} internal, hidden 14: unknown:1890 {1890} internal, hidden 15: unknown:18A0 {18A0} internal, hidden 16: unknown:18B0 {18B0} internal, hidden 17: unknown:1DF3 {1DF3} internal, hidden 18: unknown:1E00 {1E00} hidden Has 4 reprogrammable keys: 0: My Home , default: HomePage => HomePage is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, group mask:empty reporting: default 1: Mail , default: Email => Email is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, group mask:empty reporting: default 2: Search , default: Search Files => Search Files is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, group mask:empty reporting: default 3: Calculator , default: Calculator => Calculator is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty reporting: default Battery: 30%, discharging, next level 5%. Solaar-1.1.20/docs/devices/Wireless Keyboard Dell KB714 4015.txt000066400000000000000000000033561522022367600234050ustar00rootroot00000000000000Solaar version 1.1.6rc4 4: Wireless Keyboard Dell KB714 Device path : /dev/hidraw6 WPID : 4015 Codename : Dell KB714 Kind : keyboard Protocol : HID++ 3.0 Polling rate : 20 ms (50Hz) Serial number: C0A37A58 Model ID: 000000000000 Unit ID: 00000000 Firmware: RQK 51.00.B0005 Supports 19 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V0 Firmware: Firmware RQK 51.00.B0005 4015 Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} V0 Name: Wireless Keyboard Dell KB714 Kind: keyboard 4: BATTERY STATUS {1000} V0 Battery: 90%, discharging, next level 5%. 5: WIRELESS DEVICE STATUS {1D4B} V0 6: ENCRYPTION {4100} V0 7: KEYBOARD LAYOUT {4520} V0 8: unknown:1810 {1810} V0 internal, hidden 9: unknown:1830 {1830} V0 internal, hidden 10: unknown:1860 {1860} V0 internal, hidden 11: unknown:1890 {1890} V0 internal, hidden 12: unknown:18A0 {18A0} V0 internal, hidden 13: unknown:18B0 {18B0} V0 internal, hidden 14: REMAINING PAIRING {1DF0} V0 hidden Remaining Pairings: 54 15: unknown:1DF3 {1DF3} V0 internal, hidden 16: unknown:1E00 {1E00} V0 hidden 17: unknown:1E90 {1E90} V0 internal, hidden 18: DEVICE GROUPS {0006} V0 Battery: 90%, discharging, next level 5%. Solaar-1.1.20/docs/devices/Wireless Keyboard K220 4005.txt000066400000000000000000000037601522022367600224300ustar00rootroot00000000000000 2: Wireless Keyboard K220 Codename : K220 Kind : keyboard Wireless PID : 4005 Protocol : HID++ 2.0 Polling rate : 20 ms (50Hz) Serial number: 5BB1D72E Firmware: RQK 37.00.B0011 Supports 14 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: FEATURE INFO {0002} 3: DEVICE FW VERSION {0003} 4: DEVICE NAME {0005} 5: BATTERY STATUS {1000} 6: unknown:1820 {1820} hidden 7: REPROG CONTROLS {1B00} 8: REPROG CONTROLS V2 {1B01} 9: WIRELESS DEVICE STATUS {1D4B} 10: unknown:1DF0 {1DF0} hidden 11: unknown:1DF3 {1DF3} hidden 12: ENCRYPTION {4100} 13: KEYBOARD LAYOUT {4520} Has 12 reprogrammable keys: 0: FN F1 => Do Nothing One is FN, reprogrammable 1: FN F2 => Do Nothing One is FN, reprogrammable 2: FN F3 => Do Nothing One is FN, reprogrammable 3: FN F4 => Do Nothing One is FN, reprogrammable 4: FN F5 => Do Nothing One is FN, reprogrammable 5: FN F6 => Do Nothing One is FN, reprogrammable 6: FN F7 => Do Nothing One is FN, reprogrammable 7: FN F8 => Do Nothing One is FN, reprogrammable 8: FN F9 => Do Nothing One is FN, reprogrammable 9: Mute => Mute is FN 10: Volume Down => Volume Down is FN 11: Volume Up => Volume Up is FN Battery: 90%, discharging. Solaar-1.1.20/docs/devices/Wireless Keyboard K230 400D.txt000066400000000000000000000046661522022367600224560ustar00rootroot00000000000000 1: Wireless Keyboard K230 Device path : /dev/hidraw5 WPID : 400D Codename : K230 Kind : keyboard Protocol : HID++ 2.0 Polling rate : 20 ms (50Hz) Serial number: 9BB42D7D Model ID: 000000000000 Unit ID: 00000000 Firmware: RQK 40.00.B0011 The power switch is located on the bottom left corner. Supports 14 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: FEATURE INFO {0002} 3: DEVICE FW VERSION {0003} Firmware: Firmware RQK 40.00.B0011 400D Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 4: DEVICE NAME {0005} Name: Wireless Keyboard K230 Kind: keyboard 5: BATTERY STATUS {1000} Battery: 70%, discharging, next level 20%. 6: unknown:1820 {1820} hidden 7: REPROG CONTROLS {1B00} 8: REPROG CONTROLS V2 {1B01} 9: WIRELESS DEVICE STATUS {1D4B} 10: REMAINING PAIRING {1DF0} hidden Remaining Pairings: 54 11: unknown:1DF3 {1DF3} hidden 12: ENCRYPTION {4100} 13: KEYBOARD LAYOUT {4520} Has 12 reprogrammable keys: 0: Fn F1 => Do Nothing One is FN, reprogrammable 1: Fn F2 => Do Nothing One is FN, reprogrammable 2: Fn F3 => Do Nothing One is FN, reprogrammable 3: Fn F4 => Do Nothing One is FN, reprogrammable 4: Fn F5 => Do Nothing One is FN, reprogrammable 5: Fn F6 => Do Nothing One is FN, reprogrammable 6: Fn F7 => Do Nothing One is FN, reprogrammable 7: Fn F8 => Do Nothing One is FN, reprogrammable 8: Fn F9 => Do Nothing One is FN, reprogrammable 9: Mute => Mute is FN 10: Volume Down => Volume Down is FN 11: Volume Up => Volume Up is FN Battery: 70%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Wireless Keyboard K270(unifying) 4003.txt000066400000000000000000000032111522022367600243140ustar00rootroot00000000000000 2: Wireless Keyboard K270(unifying) Codename : K270(unifying) Kind : keyboard Wireless PID : 4003 Protocol : HID++ 2.0 Polling rate : 20 ms (50Hz) Serial number: FE8C8542 Firmware: RQK 35.00.B0017 The power switch is located on the top case. Supports 12 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: BATTERY STATUS {1000} 5: unknown:1820 {1820} hidden 6: REPROG CONTROLS {1B00} 7: WIRELESS DEVICE STATUS {1D4B} 8: unknown:1DF0 {1DF0} hidden 9: unknown:1DF3 {1DF3} hidden 10: ENCRYPTION {4100} 11: KEYBOARD LAYOUT {4520} Has 8 reprogrammable keys: 0: Play/Pause => Play/Pause nonstandard 1: Mute => Mute nonstandard 2: Volume Down => Volume Down nonstandard 3: Volume Up => Volume Up nonstandard 4: MY HOME => HomePage nonstandard, reprogrammable 5: Mail => Email nonstandard, reprogrammable 6: SLEEP => Sleep nonstandard, reprogrammable 7: Calculator => Calculator nonstandard, reprogrammable Battery: 90%, discharging. Solaar-1.1.20/docs/devices/Wireless Keyboard K360 4004.txt000066400000000000000000000025551522022367600224350ustar00rootroot00000000000000Solaar version 1.1.4 2: Wireless Keyboard K360 Device path : /dev/hidraw2 WPID : 4004 Codename : K360 Kind : keyboard Protocol : HID++ 2.0 Polling rate : 20 ms (50Hz) Serial number: 334AC01A Model ID: 000000000000 Unit ID: 00000000 Firmware: RQK 36.00.B0007 The power switch is located on the top case. Supports 12 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Firmware RQK 36.00.B0007 4004 Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} Name: Wireless Keyboard K360 Kind: keyboard 4: BATTERY STATUS {1000} Battery: 70%, discharging, next level 20%. 5: unknown:1820 {1820} hidden 6: REPROG CONTROLS {1B00} 7: WIRELESS DEVICE STATUS {1D4B} 8: REMAINING PAIRING {1DF0} hidden Remaining Pairings: 55 9: unknown:1DF3 {1DF3} hidden 10: FN INVERSION {40A0} Swap Fx function (saved): False Swap Fx function : False 11: ENCRYPTION {4100} Battery: 70%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Wireless Keyboard K470 4075.txt000066400000000000000000000062211522022367600224410ustar00rootroot00000000000000Solaar version 1.1.7 1: Wireless Keyboard Device path : /dev/hidraw6 WPID : 4075 Codename : Kind : keyboard Protocol : HID++ 4.5 Polling rate : 20 ms (50Hz) Serial number: 00000000 Model ID: 000000000000 Unit ID: 00000000 Firmware: RQK 71.00.B0002 Supports 20 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V0 Firmware: Firmware RQK 71.00.B0002 4075 Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} V0 Name: Wireless Keyboard Kind: keyboard 4: RESET {0020} V0 5: BATTERY STATUS {1000} V0 Battery: 30%, discharging, next level 5%. 6: REPROG CONTROLS V4 {1B04} V2 Key/Button Diversion (saved): {Calculator:Regular, Mail:Regular, My Home:Regular, Search:Regular} Key/Button Diversion : {Calculator:Regular, Mail:Regular, My Home:Regular, Search:Regular} 7: WIRELESS DEVICE STATUS {1D4B} V0 8: NEW FN INVERSION {40A2} V0 Fn-swap: disabled Fn-swap default: disabled Swap Fx function (saved): False Swap Fx function : False 9: ENCRYPTION {4100} V0 10: LOCK KEY STATE {4220} V0 11: KEYBOARD DISABLE KEYS {4521} V0 Disable keys (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 12: unknown:1810 {1810} V0 internal, hidden 13: unknown:1830 {1830} V0 internal, hidden 14: unknown:1890 {1890} V0 internal, hidden 15: unknown:18A0 {18A0} V0 internal, hidden 16: unknown:18B0 {18B0} V0 internal, hidden 17: unknown:1DF3 {1DF3} V0 internal, hidden 18: unknown:1E00 {1E00} V0 hidden 19: unknown:1868 {1868} V0 internal, hidden Has 4 reprogrammable keys: 0: My Home , default: HomePage => HomePage is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, group mask:empty reporting: default 1: Mail , default: Email => Email is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, group mask:empty reporting: default 2: Search , default: Search Files => Search Files is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, group mask:empty reporting: default 3: Calculator , default: Calculator => Calculator is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty reporting: default Battery: 30%, discharging, next level 5%. Solaar-1.1.20/docs/devices/Wireless Keyboard K520 2011.txt000066400000000000000000000006721522022367600224250ustar00rootroot00000000000000 2: Wireless Keyboard K520 Device path : /dev/hidraw5 WPID : 2011 Codename : K520 Kind : keyboard Protocol : HID++ 1.0 Polling rate : 20 ms (50Hz) Serial number: C17F6771 Firmware: 26.00.B0012 Other: 00.07 The power switch is located on the top case. Notifications: battery status (0x100000). Battery: full, discharging. Has Swap Fn register Solaar-1.1.20/docs/devices/Wireless Keyboard MK270 4023.txt000066400000000000000000000033001522022367600225400ustar00rootroot00000000000000Solaar version 1.1.7 1: Wireless Keyboard MK270 Device path : /dev/hidraw6 WPID : 4023 Codename : MK270 Kind : keyboard Protocol : HID++ 2.0 Polling rate : 20 ms (50Hz) Serial number: 90A794A3 Model ID: 000000000000 Unit ID: 00000000 Firmware: RQK 49.00.B0029 Supports 18 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V0 Firmware: Firmware RQK 49.00.B0029 4023 Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} V0 Name: Wireless Keyboard Kind: keyboard 4: BATTERY STATUS {1000} V0 Battery: 30%, discharging, next level 5%. 5: REPROG CONTROLS {1B00} V0 6: WIRELESS DEVICE STATUS {1D4B} V0 7: FN INVERSION {40A0} V0 Swap Fx function (saved): False Swap Fx function : False 8: ENCRYPTION {4100} V0 9: KEYBOARD LAYOUT {4520} V0 10: unknown:1810 {1810} V0 internal, hidden 11: unknown:1830 {1830} V0 internal, hidden 12: unknown:1890 {1890} V0 internal, hidden 13: unknown:18A0 {18A0} V0 internal, hidden 14: unknown:18B0 {18B0} V0 internal, hidden 15: unknown:1DF3 {1DF3} V0 internal, hidden 16: unknown:1E00 {1E00} V0 hidden 17: unknown:1868 {1868} V0 internal, hidden Battery: 30%, discharging, next level 5%. Solaar-1.1.20/docs/devices/Wireless Mobile Mouse MX Anywhere 2 4072.txt000066400000000000000000000071551522022367600247510ustar00rootroot00000000000000 2: Wireless Mobile Mouse MX Anywhere 2 Codename : MX Anywhere 2 Kind : mouse Wireless PID : 4072 Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: DDAE1933 Bootloader: BOT 57.10.B0003 Firmware: MPM 13.10.B0003 Firmware: MPM 13.10.B0003 Other: The power switch is located on the base. Supports 28 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: BATTERY STATUS {1000} 8: CONFIG DEVICE PROPS {1806} internal, hidden 9: CHANGE HOST {1814} 10: REPROG CONTROLS V4 {1B04} 11: ADJUSTABLE DPI {2201} 12: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 13: HIRES WHEEL {2121} Multiplier: 8 Has invert Normal wheel motion Has ratchet switch Normal wheel mode Low resolution mode HID notification High Resolution Wheel Invert: False Wheel Resolution: False 14: DFUCONTROL SIGNED {00C2} 15: unknown:1813 {1813} internal, hidden 16: unknown:1830 {1830} internal, hidden 17: unknown:1890 {1890} internal, hidden 18: unknown:1891 {1891} internal, hidden 19: unknown:18A1 {18A1} internal, hidden 20: unknown:18C0 {18C0} internal, hidden 21: unknown:1DF3 {1DF3} internal, hidden 22: unknown:1E00 {1E00} hidden 23: unknown:1EB0 {1EB0} internal, hidden 24: unknown:1803 {1803} internal, hidden 25: unknown:1861 {1861} internal, hidden 26: unknown:9001 {9001} internal, hidden 27: OOBSTATE {1805} internal, hidden Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Button mse, pos:0, group:1, gmask:1 1: Right Button , default: Right Click => Right Button mse, pos:0, group:1, gmask:1 2: Middle Button , default: Gesture Button Navigation => Middle Button mse, reprogrammable, divertable, pos:0, group:2, gmask:11 3: Back Button , default: Mouse Back Button => Back Button mse, reprogrammable, divertable, pos:0, group:3, gmask:15 4: Forward Button , default: Mouse Forward Button => Forward Button mse, reprogrammable, divertable, pos:0, group:3, gmask:15 5: Left Tilt , default: Mouse Scroll Left Button => Left Tilt mse, reprogrammable, divertable, pos:0, group:3, gmask:15 6: Right Tilt , default: Mouse Scroll Right Button => Right Tilt mse, reprogrammable, divertable, pos:0, group:3, gmask:15 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, pos:0, group:4, gmask:0 Battery: 90%, discharging, next level 50%. 15:29:59,190 INFO [MainThread] logitech_receiver.receiver: : found new device 3 (4024) Solaar-1.1.20/docs/devices/Wireless Mobile Mouse MX Anywhere 2S 406A.txt000066400000000000000000000114061522022367600251040ustar00rootroot00000000000000Solaar version 1.1.3 2: Wireless Mobile Mouse MX Anywhere 2S Device path : None WPID : 406A Codename : MX Anywhere 2S Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: C53F2F0B Model ID: B01A406A0000 Unit ID: 3F714CA3 Bootloader: BOT 57.00.B0003 Firmware: MPM 13.00.B0003 Firmware: MPM 13.00.B0003 Other: The power switch is located on the base. Supports 28 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 57.00.B0003 406AD22DCF4D01 Firmware: Firmware MPM 13.00.B0003 B01AD22DCF4D01 Firmware: Firmware MPM 13.00.B0003 406AD22DCF4D01 Firmware: Other Unit ID: 3F714CA3 Model ID: B01A406A0000 Transport IDs: {'btleid': 'B01A', 'wpid': '406A'} 3: DEVICE NAME {0005} Name: Wireless Mobile Mouse MX Anywhere 2S Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY STATUS {1000} Battery: 90%, discharging, next level 50%. 7: CONFIG DEVICE PROPS {1806} internal, hidden 8: CHANGE HOST {1814} 9: REPROG CONTROLS V4 {1B04} 10: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 4000 Sensitivity (DPI) : 4000 11: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 12: HIRES WHEEL {2121} Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Free wheel mode Low resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): False Scroll Wheel Resolution : False Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 13: DFUCONTROL UNSIGNED {00C1} 14: DFUCONTROL SIGNED {00C2} 15: unknown:1813 {1813} internal, hidden 16: unknown:1830 {1830} internal, hidden 17: unknown:1890 {1890} internal, hidden 18: unknown:1891 {1891} internal, hidden 19: unknown:18A1 {18A1} internal, hidden 20: unknown:18C0 {18C0} internal, hidden 21: unknown:1DF3 {1DF3} internal, hidden 22: unknown:1E00 {1E00} hidden 23: unknown:1EB0 {1EB0} internal, hidden 24: unknown:1803 {1803} internal, hidden 25: unknown:1861 {1861} internal, hidden 26: unknown:9001 {9001} internal, hidden 27: OOBSTATE {1805} internal, hidden Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2,g4 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4 reporting: default 5: Left Tilt , default: Mouse Scroll Left Button => Mouse Scroll Left Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4 reporting: default 6: Right Tilt , default: Mouse Scroll Right Button => Mouse Scroll Right Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/Wireless Mobile Mouse MX Anywhere 2S B01A.txt000066400000000000000000000127221522022367600251170ustar00rootroot00000000000000solaar version 1.1.9 1: Wireless Mobile Mouse MX Anywhere 2S Device path : /dev/hidraw1 USB id : 046d:B01A Codename : Wireless Kind : mouse Protocol : HID++ 4.5 Serial number: Model ID: B01A406A0000 Unit ID: 3F714CA3 Bootloader: BOT 57.00.B0003 Firmware: MPM 13.00.B0003 Firmware: MPM 13.00.B0003 Other: Supports 24 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BOT 57.00.B0003 406AD22DCF4D01 Firmware: Firmware MPM 13.00.B0003 B01AD22DCF4D01 Firmware: Firmware MPM 13.00.B0003 406AD22DCF4D01 Firmware: Other Unit ID: 3F714CA3 Model ID: B01A406A0000 Transport IDs: {'btleid': 'B01A', 'wpid': '406A'} 3: DEVICE NAME {0005} V0 Name: Wireless Mobile Mouse MX Anywhere 2S Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: CONFIG CHANGE {0020} V0 6: BATTERY STATUS {1000} V0 Battery: 90%, discharging, next level 50%. 7: CONFIG DEVICE PROPS {1806} V0 internal, hidden 8: CHANGE HOST {1814} V1 Change Host : 2:mburcheri2 9: REPROG CONTROLS V4 {1B04} V3 Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Gesture Button Navigation, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Gesture Button Navigation, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Left Tilt:Mouse Scroll Left Button , Right Tilt:Mouse Scroll Right Button} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Sliding DPI, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Diverted, Forward Button:Regular, Left Tilt:Regular, Right Tilt:Regular} 10: ADJUSTABLE DPI {2201} V1 Sensitivity (DPI) (saved): 3400 Sensitivity (DPI) : 3400 11: VERTICAL SCROLLING {2100} V0 Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 12: HIRES WHEEL {2121} V0 Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Free wheel mode Low resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): False Scroll Wheel Resolution : False Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 13: unknown:1813 {1813} V0 internal, hidden 14: unknown:1830 {1830} V0 internal, hidden 15: unknown:18A1 {18A1} V0 internal, hidden 16: unknown:18C0 {18C0} V0 internal, hidden 17: unknown:1DF3 {1DF3} V0 internal, hidden 18: unknown:1E00 {1E00} V0 hidden 19: unknown:1EB0 {1EB0} V0 internal, hidden 20: unknown:1803 {1803} V0 internal, hidden 21: unknown:1861 {1861} V0 internal, hidden 22: unknown:9001 {9001} V0 internal, hidden 23: OOBSTATE {1805} V0 internal, hidden Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2,g4 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4 reporting: diverted, raw XY diverted 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4 reporting: default 5: Left Tilt , default: Mouse Scroll Left Button => Mouse Scroll Left Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4 reporting: default 6: Right Tilt , default: Mouse Scroll Right Button => Mouse Scroll Right Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3,g4 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/Wireless Mouse 4022.txt000066400000000000000000000027511522022367600213570ustar00rootroot00000000000000 2: Wireless Mouse Codename : Kind : mouse Wireless PID : 4022 Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: 00000000 Firmware: RQM 38.00.B0044 Supports 18 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: BATTERY STATUS {1000} 5: REPROG CONTROLS {1B00} 6: WIRELESS DEVICE STATUS {1D4B} 7: VERTICAL SCROLLING {2100} 8: MOUSE POINTER {2200} 9: unknown:1810 {1810} internal, hidden 10: unknown:1830 {1830} internal, hidden 11: unknown:1850 {1850} internal, hidden 12: unknown:1890 {1890} internal, hidden 13: unknown:18B0 {18B0} internal, hidden 14: unknown:1DF3 {1DF3} internal, hidden 15: unknown:1868 {1868} internal, hidden 16: unknown:1869 {1869} internal, hidden 17: unknown:1E00 {1E00} hidden Has 3 reprogrammable keys: 0: LEFT CLICK => LeftClick mse, reprogrammable 1: RIGHT CLICK => RightClick mse, reprogrammable 2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable Battery: 30%, discharging. Solaar-1.1.20/docs/devices/Wireless Mouse Dell WM514 4029.txt000066400000000000000000000043211522022367600227600ustar00rootroot00000000000000Solaar version 1.1.6rc4 3: Wireless Mouse Dell WM514 Device path : /dev/hidraw5 WPID : 4029 Codename : Dell WM514 Kind : mouse Protocol : HID++ 3.0 Polling rate : 8 ms (125Hz) Serial number: 17F2CD56 Model ID: 000000000000 Unit ID: 00000000 Firmware: RQM 44.00.B0013 The power switch is located on the base. Supports 23 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V0 Firmware: Firmware RQM 44.00.B0013 4029 Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} V0 Name: Wireless Mouse Dell WM514 Kind: mouse 4: BATTERY STATUS {1000} V0 Battery: 70%, discharging, next level 5%. 5: unknown:1830 {1830} V0 internal, hidden 6: unknown:1860 {1860} V0 internal, hidden 7: unknown:1890 {1890} V0 internal, hidden 8: unknown:18A0 {18A0} V0 internal, hidden 9: unknown:18B0 {18B0} V0 internal, hidden 10: unknown:18C0 {18C0} V0 internal, hidden 11: WIRELESS DEVICE STATUS {1D4B} V0 12: unknown:1DF3 {1DF3} V0 internal, hidden 13: REPROG CONTROLS {1B00} V0 14: REMAINING PAIRING {1DF0} V0 hidden Remaining Pairings: 124 15: unknown:1E00 {1E00} V0 hidden 16: unknown:1850 {1850} V0 internal, hidden 17: unknown:1E90 {1E90} V0 internal, hidden 18: unknown:1F03 {1F03} V0 internal, hidden 19: VERTICAL SCROLLING {2100} V0 Roller type: standard Ratchet per turn: 24 Scroll lines: 0 20: MOUSE POINTER {2200} V0 DPI: 1000 Acceleration: low Override OS ballistics No vertical tuning, standard mice 21: DEVICE GROUPS {0006} V0 22: unknown:1BB0 {1BB0} V0 Battery: 70%, discharging, next level 5%. Solaar-1.1.20/docs/devices/Wireless Mouse M185 new 4054.txt000066400000000000000000000056531522022367600225550ustar00rootroot00000000000000Solaar version 1.1.4rc2 2: Wireless Mouse M185 new Device path : /dev/hidraw3 WPID : 4054 Codename : M185n Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 00000000 Model ID: 000000000000 Unit ID: 00000000 Firmware: RQM 64.00.B0008 The power switch is located on the base. Supports 19 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Firmware RQM 64.00.B0008 4054 Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} Name: Wireless Mouse Kind: mouse 4: RESET {0020} 5: REPROG CONTROLS V4 {1B04} Mouse Gestures (saved): Off Mouse Gestures : Off Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button} Key/Button Diversion (saved): {Middle Button:Regular} Key/Button Diversion : {Middle Button:Regular} 6: WIRELESS DEVICE STATUS {1D4B} 7: LOWRES WHEEL {2130} Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 8: POINTER SPEED {2205} Pointer Speed: 1.0 Sensitivity (Pointer Speed) (saved): 256 Sensitivity (Pointer Speed) : 256 9: DEVICE RESET {1802} internal, hidden 10: unknown:1810 {1810} internal, hidden 11: unknown:1830 {1830} internal, hidden 12: unknown:1850 {1850} internal, hidden 13: unknown:1869 {1869} internal, hidden 14: unknown:1890 {1890} internal, hidden 15: unknown:18B1 {18B1} internal, hidden 16: unknown:1DF3 {1DF3} internal, hidden 17: unknown:1E00 {1E00} hidden 18: unknown:1F03 {1F03} internal, hidden Has 3 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default Battery status unavailable. Solaar-1.1.20/docs/devices/Wireless Mouse M185,M235,M310 4055.txt000066400000000000000000000060611522022367600230360ustar00rootroot00000000000000Solaar version 1.1.4 1: Wireless Mouse M185/M235/M310 Device path : /dev/hidraw2 WPID : 4055 Codename : M185/M235/M310 Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 82C9A01F Model ID: 405500000000 Unit ID: 82C9A01F Firmware: RQM 65.00.B0003 The power switch is located on the base. Supports 21 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Firmware RQM 65.00.B0003 4055 Unit ID: 82C9A01F Model ID: 405500000000 Transport IDs: {'wpid': '4055'} 3: DEVICE NAME {0005} Name: Wireless Mouse Kind: mouse 4: RESET {0020} 5: BATTERY STATUS {1000} Battery: 70%, discharging, next level 5%. 6: unknown:1810 {1810} internal, hidden 7: unknown:1830 {1830} internal, hidden 8: DEVICE RESET {1802} internal, hidden 9: unknown:1862 {1862} internal, hidden 10: unknown:1890 {1890} internal, hidden 11: unknown:18A0 {18A0} internal, hidden 12: unknown:18B1 {18B1} internal, hidden 13: REPROG CONTROLS V4 {1B04} Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button} Key/Button Diversion (saved): {Left Button:Regular, Right Button:Regular, Middle Button:Regular} Key/Button Diversion : {Left Button:Regular, Right Button:Regular, Middle Button:Regular} 14: WIRELESS DEVICE STATUS {1D4B} 15: REMAINING PAIRING {1DF0} hidden Remaining Pairings: 116 16: unknown:1DF3 {1DF3} internal, hidden 17: unknown:1E00 {1E00} hidden 18: unknown:1EB0 {1EB0} internal, hidden 19: unknown:1F03 {1F03} internal, hidden 20: LOWRES WHEEL {2130} Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False Has 3 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, divertable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, divertable, pos:0, group:1, group mask:g1 reporting: analytics key events reporting 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: unknown:000200 Battery: 70%, discharging, next level 5%. Solaar-1.1.20/docs/devices/Wireless Mouse M185.text000066400000000000000000000050101522022367600215560ustar00rootroot00000000000000solaar show rules cannot access modifier keys in Wayland, accessing process only works on GNOME with Solaar Gnome extension installed solaar version 1.1.14-2 Unifying Receiver Device path : /dev/hidraw1 USB id : 046d:C52B Serial : EC219AC2 C Pending : ff 0 : 12.11.B0032 1 : 04.16 3 : AA.AA Has 2 paired device(s) out of a maximum of 6. Notifications: wireless (0x000100) Device activity counters: 1=195, 2=74 1: Wireless Mouse M175 Device path : /dev/hidraw2 WPID : 4008 Codename : M175 Kind : mouse Protocol : HID++ 2.0 Report Rate : 8ms Serial number: 16E46E8C Model ID: 000000000000 Unit ID: 00000000 0: RQM 40.00.B0016 The power switch is located on the base. Supports 21 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V0 Firmware: 0 RQM 40.00.B0016 4008 Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} V0 Name: Wireless Mouse M185 Kind: mouse 4: BATTERY STATUS {1000} V0 Battery: 70%, 0, next level 5%. 5: unknown:1830 {1830} V0 internal, hidden 6: unknown:1850 {1850} V0 internal, hidden 7: unknown:1860 {1860} V0 internal, hidden 8: unknown:1890 {1890} V0 internal, hidden 9: unknown:18A0 {18A0} V0 internal, hidden 10: unknown:18C0 {18C0} V0 internal, hidden 11: WIRELESS DEVICE STATUS {1D4B} V0 12: unknown:1DF3 {1DF3} V0 internal, hidden 13: REPROG CONTROLS {1B00} V0 14: REMAINING PAIRING {1DF0} V0 hidden Remaining Pairings: 117 15: unknown:1E00 {1E00} V0 hidden 16: unknown:1E80 {1E80} V0 internal, hidden 17: unknown:1E90 {1E90} V0 internal, hidden 18: unknown:1F03 {1F03} V0 internal, hidden 19: VERTICAL SCROLLING {2100} V0 Roller type: standard Ratchet per turn: 24 Scroll lines: 0 20: MOUSE POINTER {2200} V0 DPI: 1000 Acceleration: low Override OS ballistics No vertical tuning, standard mice Battery: 70%, 0, next level 5%. Solaar-1.1.20/docs/devices/Wireless Mouse M215 2nd Gen 401B.txt000066400000000000000000000034101522022367600231320ustar00rootroot00000000000000Solaar version 1.1.5 1: Wireless Mouse M215 2nd Gen Device path : None WPID : 401B Codename : Wireless Kind : mouse Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: D225825E Model ID: 000000000000 Unit ID: 00000000 Firmware: RQM 27.12.B0029 The power switch is located on the base. Supports 13 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V0 Firmware: Firmware RQM 27.12.B0029 401B Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} V0 Name: Wireless Mouse M215 2nd Gen Kind: mouse 4: BATTERY STATUS {1000} V0 Battery: 90%, discharging, next level 5%. 5: WIRELESS DEVICE STATUS {1D4B} V0 6: unknown:1DF3 {1DF3} V0 hidden 7: REPROG CONTROLS {1B00} V0 8: REMAINING PAIRING {1DF0} V0 hidden Remaining Pairings: 126 9: unknown:1F03 {1F03} V0 hidden 10: VERTICAL SCROLLING {2100} V0 Roller type: standard Ratchet per turn: 24 Scroll lines: 0 11: HI RES SCROLLING {2120} V0 Hi-res scrolling disabled Hi-res scrolling multiplier: 8 Scroll Wheel High Resolution (saved): False Scroll Wheel High Resolution : False 12: MOUSE POINTER {2200} V0 DPI: 800 Acceleration: low Override OS ballistics No vertical tuning, standard mice Battery: 90%, discharging, next level 5%. Solaar-1.1.20/docs/devices/Wireless Mouse M310 M310t 4031.txt000066400000000000000000000033321522022367600225410ustar00rootroot00000000000000 1: Wireless Mouse M310/M310t Codename : M310/M310t Kind : mouse Wireless PID : 4031 Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: 03E8C0B4 Firmware: RQM 40.01.B0017 The power switch is located on the base. Supports 21 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: BATTERY STATUS {1000} 5: unknown:1830 {1830} internal, hidden 6: unknown:1850 {1850} internal, hidden 7: unknown:1860 {1860} internal, hidden 8: unknown:1890 {1890} internal, hidden 9: unknown:18A0 {18A0} internal, hidden 10: unknown:18C0 {18C0} internal, hidden 11: WIRELESS DEVICE STATUS {1D4B} 12: unknown:1DF3 {1DF3} internal, hidden 13: REPROG CONTROLS {1B00} 14: unknown:1DF0 {1DF0} hidden 15: unknown:1E00 {1E00} hidden 16: unknown:1E80 {1E80} internal, hidden 17: unknown:1E90 {1E90} internal, hidden 18: unknown:1F03 {1F03} internal, hidden 19: VERTICAL SCROLLING {2100} 20: MOUSE POINTER {2200} Has 3 reprogrammable keys: 0: LEFT CLICK => LeftClick mse, reprogrammable 1: RIGHT CLICK => RightClick mse, reprogrammable 2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable Battery: 70%, discharging. Solaar-1.1.20/docs/devices/Wireless Mouse M325 400A.txt000066400000000000000000000065331522022367600220050ustar00rootroot00000000000000 1: Wireless Mouse M325 Device path : /dev/hidraw4 WPID : 400A Codename : M325 Kind : mouse Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: D72D97E9 Model ID: 000000000000 Unit ID: 00000000 Firmware: RQM 40.01.B0018 The power switch is located on the base. Supports 22 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V0 Firmware: Firmware RQM 40.01.B0018 400A Unit ID: 00000000 Model ID: 000000000000 Transport IDs: {} 3: DEVICE NAME {0005} V0 Name: Wireless Mouse M325 Kind: mouse 4: BATTERY STATUS {1000} V0 Battery: 70%, discharging, next level 5%. 5: unknown:1830 {1830} V0 internal, hidden 6: unknown:1850 {1850} V0 internal, hidden 7: unknown:1860 {1860} V0 internal, hidden 8: unknown:1890 {1890} V0 internal, hidden 9: unknown:18A0 {18A0} V0 internal, hidden 10: unknown:18C0 {18C0} V0 internal, hidden 11: WIRELESS DEVICE STATUS {1D4B} V0 12: unknown:1DF3 {1DF3} V0 internal, hidden 13: REPROG CONTROLS {1B00} V0 14: REMAINING PAIRING {1DF0} V0 hidden Remaining Pairings: 117 15: unknown:1E00 {1E00} V0 hidden 16: unknown:1E80 {1E80} V0 internal, hidden 17: unknown:1E90 {1E90} V0 internal, hidden 18: unknown:1F03 {1F03} V0 internal, hidden 19: VERTICAL SCROLLING {2100} V0 Roller type: micro Ratchet per turn: 36 Scroll lines: 0 20: MOUSE POINTER {2200} V0 DPI: 800 Acceleration: low Override OS ballistics No vertical tuning, standard mice 21: unknown:18B0 {18B0} V0 internal, hidden Battery: 70%, discharging, next level 5%. Wireless Mouse M325 Codename : M325 Kind : mouse Wireless PID : 400A Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: ABB05E01 Firmware: RQM 27.02.B0028 The power switch is located on the base. Supports 13 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: BATTERY STATUS {1000} 5: WIRELESS DEVICE STATUS {1D4B} 6: unknown:1DF3 {1DF3} hidden 7: REPROG CONTROLS {1B00} 8: unknown:1DF0 {1DF0} hidden 9: unknown:1F03 {1F03} hidden 10: VERTICAL SCROLLING {2100} 11: HI RES SCROLLING {2120} 12: MOUSE POINTER {2200} Has 5 reprogrammable keys: 0: LEFT CLICK => LeftClick mse, reprogrammable 1: RIGHT CLICK => RightClick mse, reprogrammable 2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable 3: BACK AS BUTTON 4 => Back mse, reprogrammable 4: FORWARD AS BUTTON 5 => BrowserForward mse, reprogrammable Solaar-1.1.20/docs/devices/Wireless Mouse M345 4017.txt000066400000000000000000000015351522022367600217730ustar00rootroot000000000000001: Wireless Mouse M345 Codename : M345 Kind : mouse Wireless PID : 4017 Protocol : HID++ 2.0 Polling rate : 8 ms Serial number: 920DC223 Firmware: RQM 27.02.B0028 The power switch is located on the base. Supports 13 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: BATTERY STATUS {1000} 5: WIRELESS DEVICE STATUS {1D4B} 6: unknown:1DF3 {1DF3} hidden 7: REPROG CONTROLS {1B00} 8: unknown:1DF0 {1DF0} hidden 9: unknown:1F03 {1F03} hidden 10: VERTICAL SCROLLING {2100} 11: HI RES SCROLLING {2120} 12: MOUSE POINTER {2200} Battery: 90%, discharging, Solaar-1.1.20/docs/devices/Wireless Mouse M510 1025.txt000066400000000000000000000007711522022367600217620ustar00rootroot00000000000000Solaar version 1.1.4 1: Wireless Mouse M510 Device path : /dev/hidraw2 WPID : 1025 Codename : M510 Kind : mouse Protocol : HID++ 1.0 Polling rate : 8 ms (125Hz) Serial number: 93E8527F Firmware: 23.01.B0016 The power switch is located on the base. Notifications: battery status (0x100000). Features: special buttons, buttons control resolution (0x820000) Battery: good, discharging. Has Side Scrolling register Solaar-1.1.20/docs/devices/Wireless Mouse M510 4051.txt000066400000000000000000000051271522022367600217640ustar00rootroot00000000000000 1: Wireless Mouse M510 Codename : M510v2 Kind : mouse Wireless PID : 4051 Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 8989B04C Firmware: RQM 62.00.B0013 The power switch is located on the base. Supports 22 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: RESET {0020} 5: BATTERY STATUS {1000} 6: unknown:1802 {1802} internal, hidden 7: unknown:1810 {1810} internal, hidden 8: unknown:1830 {1830} internal, hidden 9: unknown:1862 {1862} internal, hidden 10: unknown:1890 {1890} internal, hidden 11: unknown:18A0 {18A0} internal, hidden 12: unknown:18B1 {18B1} internal, hidden 13: REPROG CONTROLS V4 {1B04} 14: WIRELESS DEVICE STATUS {1D4B} 15: unknown:1DF0 {1DF0} hidden 16: unknown:1DF3 {1DF3} internal, hidden 17: unknown:1E00 {1E00} hidden 18: unknown:1EB0 {1EB0} internal, hidden 19: unknown:1F03 {1F03} internal, hidden 20: LOWRES WHEEL {2130} 21: POINTER SPEED {2205} Has 7 reprogrammable keys: 0: LEFT CLICK , default: LeftClick => LEFT CLICK divertable, mse, pos:0, group:1, gmask:1 1: RIGHT CLICK , default: RightClick => RIGHT CLICK divertable, mse, pos:0, group:1, gmask:1 2: MIDDLE BUTTON , default: MiddleMouseButton => MIDDLE BUTTON divertable, mse, reprogrammable, pos:0, group:2, gmask:3 3: LEFT SCROLL AS AC PAN , default: HorzScrollLeftSet => LEFT SCROLL AS AC PAN divertable, mse, reprogrammable, pos:0, group:2, gmask:3 4: RIGHT SCROLL AS AC PAN , default: HorzScrollRightSet => RIGHT SCROLL AS AC PAN divertable, mse, reprogrammable, pos:0, group:2, gmask:3 5: BACK AS BUTTON 4 , default: BackEx => BACK AS BUTTON 4 divertable, mse, reprogrammable, pos:0, group:2, gmask:3 6: FORWARD AS BUTTON 5 , default: BrowserForwardEx => FORWARD AS BUTTON 5 divertable, mse, reprogrammable, pos:0, group:2, gmask:3 Battery: 70%, discharging. Solaar-1.1.20/docs/devices/Wireless Mouse M525 4013.txt000066400000000000000000000026011522022367600217620ustar00rootroot00000000000000 1: Wireless Mouse M525 Codename : M525 Kind : mouse Wireless PID : 4013 Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: DAFA335E Firmware: RQM 27.02.B0028 The power switch is located on the base. Supports 13 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: BATTERY STATUS {1000} 5: WIRELESS DEVICE STATUS {1D4B} 6: unknown:1DF3 {1DF3} hidden 7: REPROG CONTROLS {1B00} 8: unknown:1DF0 {1DF0} hidden 9: unknown:1F03 {1F03} hidden 10: VERTICAL SCROLLING {2100} 11: HI RES SCROLLING {2120} 12: MOUSE POINTER {2200} Has 5 reprogrammable keys: 0: LEFT CLICK => LeftClick mse, reprogrammable 1: RIGHT CLICK => RightClick mse, reprogrammable 2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable 3: BACK AS BUTTON 4 => Back mse, reprogrammable 4: FORWARD AS BUTTON 5 => BrowserForward mse, reprogrammable Battery: 90%, discharging. Solaar-1.1.20/docs/devices/Wireless Mouse M560 402D.txt000066400000000000000000000041521522022367600220060ustar00rootroot00000000000000 1: Wireless Mouse M560 Codename : M560 Kind : mouse Wireless PID : 402D Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: 16E6E42A Firmware: RQM 48.00.B0015 The power switch is located on the base. Supports 22 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: BATTERY STATUS {1000} 5: unknown:1830 {1830} internal, hidden 6: unknown:1850 {1850} internal, hidden 7: unknown:1860 {1860} internal, hidden 8: unknown:1890 {1890} internal, hidden 9: unknown:18A0 {18A0} internal, hidden 10: REPROG CONTROLS V3 {1B03} 11: WIRELESS DEVICE STATUS {1D4B} 12: unknown:1DF3 {1DF3} internal, hidden 13: REPROG CONTROLS {1B00} 14: unknown:1DF0 {1DF0} hidden 15: unknown:1E00 {1E00} hidden 16: unknown:18B0 {18B0} internal, hidden 17: unknown:1E90 {1E90} internal, hidden 18: unknown:1F03 {1F03} internal, hidden 19: VERTICAL SCROLLING {2100} 20: HI RES SCROLLING {2120} 21: MOUSE POINTER {2200} Has 7 reprogrammable keys: 0: LEFT CLICK => LeftClick mse, reprogrammable 1: RIGHT CLICK => RightClick mse, reprogrammable 2: BACK AS BUTTON 4 => Win8BackHorzLeft mse, reprogrammable 3: FORWARD AS BUTTON 5 => Win8ForwardHorzRight mse, reprogrammable 4: unknown:00B0 => Win8MetroWin7Forward mse, reprogrammable 5: SHOW DESKTOP HPP => Win8ShowDesktopWin7Back mse, reprogrammable 6: unknown:00AF => Win8Charm Appswitch GifAnimation mse, reprogrammable, unknown:000020 Battery: 70%, discharging. Solaar-1.1.20/docs/devices/Wireless Mouse MX Anywhere 2 404A.txt000066400000000000000000000033651522022367600235740ustar00rootroot00000000000000 1: Wireless Mouse MX Anywhere 2 Codename : MX Anywhere 2 Kind : mouse Wireless PID : 404A Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: F3B81C5B Bootloader: BOT 23.00.B0007 Firmware: MPM 02.00.B0007 Firmware: MPM 02.00.B0007 Other: The power switch is located on the base. Supports 26 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY STATUS {1000} 7: CHANGE HOST {1814} 8: REPROG CONTROLS V4 {1B04} 9: ADJUSTABLE DPI {2201} 10: VERTICAL SCROLLING {2100} 11: HIRES WHEEL {2121} 12: DFUCONTROL 2 {00C1} 13: unknown:1813 {1813} internal, hidden 14: unknown:1830 {1830} internal, hidden 15: unknown:1890 {1890} internal, hidden 16: unknown:1891 {1891} internal, hidden 17: unknown:18A1 {18A1} internal, hidden 18: unknown:18C0 {18C0} internal, hidden 19: unknown:1DF3 {1DF3} internal, hidden 20: unknown:1E00 {1E00} hidden 21: unknown:1EB0 {1EB0} internal, hidden 22: unknown:1803 {1803} internal, hidden 23: unknown:1861 {1861} internal, hidden 24: unknown:9000 {9000} internal, hidden 25: unknown:1805 {1805} internal, hidden Battery: 0%, recharging. Solaar-1.1.20/docs/devices/Wireless Mouse MX Master 2S 4069.txt000066400000000000000000000152611522022367600233600ustar00rootroot00000000000000Solaar version 1.1.4 1: Wireless Mouse MX Master 2S Device path : /dev/hidraw1 WPID : 4069 Codename : MX Master 2S Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 9429B808 Model ID: B01940690000 Unit ID: 65D747F7 Bootloader: BOT 56.01.B0006 Firmware: MPM 12.01.B0006 Firmware: MPM 12.01.B0006 Other: The power switch is located on the base. Supports 31 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 56.01.B0006 406916A9FC5401 Firmware: Firmware MPM 12.01.B0006 B01916A9FC5401 Firmware: Firmware MPM 12.01.B0006 406916A9FC5401 Firmware: Other Unit ID: 65D747F7 Model ID: B01940690000 Transport IDs: {'btleid': 'B019', 'wpid': '4069'} 3: DEVICE NAME {0005} Name: Wireless Mouse MX Master 2S Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 8: CONFIG DEVICE PROPS {1806} internal, hidden 9: CHANGE HOST {1814} Cambiar Host : 2:lapega 10: REPROG CONTROLS V4 {1B04} Ajustar DPI deslizando (saved): Off Ajustar DPI deslizando : Off Gestos de Ratón (saved): Off Gestos de Ratón : Off Acciones de Tecla/Botón (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Acciones de Tecla/Botón : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Desvio de Tecla/Botón (saved): {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Mouse Gesture Button:Normal, Smart Shift:Normal} Desvio de Tecla/Botón : {Middle Button:Normal, Back Button:Normal, Forward Button:Normal, Mouse Gesture Button:Normal, Smart Shift:Normal} 11: ADJUSTABLE DPI {2201} Sensibilidad (PPP) (saved): 4000 Sensibilidad (PPP) : 4000 12: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 13: SMART SHIFT {2110} Trinquete Rueda Desplazamiento (saved): 50 Trinquete Rueda Desplazamiento : 50 14: HIRES WHEEL {2121} Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Dirección Rueda Desplazamiento (saved): False Dirección Rueda Desplazamiento : False Resolución Rueda Desplazamiento (saved): True Resolución Rueda Desplazamiento : True Desvio Rueda Desplazamiento (saved): False Desvio Rueda Desplazamiento : False 15: GESTURE 2 {6501} Gestos (saved): {45: True, 46: True} Gestos : {46: True, 45: True} Gestures Diversion (saved): {46: False} Gestures Diversion : {46: False} 16: DFUCONTROL SIGNED {00C2} 17: unknown:1813 {1813} internal, hidden 18: unknown:1830 {1830} internal, hidden 19: unknown:1890 {1890} internal, hidden 20: unknown:1891 {1891} internal, hidden 21: unknown:18A1 {18A1} internal, hidden 22: unknown:18C0 {18C0} internal, hidden 23: unknown:1DF3 {1DF3} internal, hidden 24: unknown:1E00 {1E00} hidden 25: unknown:1EB0 {1EB0} internal, hidden 26: unknown:1803 {1803} internal, hidden 27: unknown:1861 {1861} internal, hidden 28: unknown:9001 {9001} internal, hidden 29: unknown:9200 {9200} internal, hidden 30: unknown:9202 {9202} internal, hidden Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: default 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Has 2 gesture(s), 0 param(s) and 4 spec(s): Thumbwheel Enabled( 0): True Diverted:( 0) False NaturalScrolling Enabled( 1): True Diverted:(None) None period unit Spec ( 3): 800 DVI field width Spec ( 1): 8 field widths Spec ( 2): 8 resolution Spec ( 4): 2048 Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Wireless Mouse MX Master 2S B019.txt000066400000000000000000000145561522022367600233770ustar00rootroot00000000000000Solaar version 1.1.3 1: Wireless Mouse MX Master 2S Device path : /dev/hidraw3 USB id : 046d:B019 Codename : MX Master 2S Kind : mouse Protocol : HID++ 4.5 Serial number: Model ID: B01940690000 Unit ID: D34FD133 Bootloader: BOT 56.01.B0006 Firmware: MPM 12.01.B0006 Firmware: MPM 12.01.B0006 Other: Supports 29 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 56.01.B0006 406916A9FC5401 Firmware: Firmware MPM 12.01.B0006 B01916A9FC5401 Firmware: Firmware MPM 12.01.B0006 406916A9FC5401 Firmware: Other Unit ID: D34FD133 Model ID: B01940690000 Transport IDs: {'btleid': 'B019', 'wpid': '4069'} 3: DEVICE NAME {0005} Name: Wireless Mouse MX Master 2S Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 8: CONFIG DEVICE PROPS {1806} internal, hidden 9: CHANGE HOST {1814} 改å�˜ä¸»æœº : 1:yan-desktop 10: REPROG CONTROLS V4 {1B04} DPI 滑动调节 (saved): å…³ DPI 滑动调节 : å…³ 鼠标手势 (saved): Mouse Gesture Button 鼠标手势 : å…³ 按键/按钮æ“�作 (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} 按键/按钮æ“�作 : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} 按键/按钮改é�“ (saved): {Middle Button:常规, Back Button:改é�“, Forward Button:改é�“, Mouse Gesture Button:改é�“, Smart Shift:常规} 按键/按钮改é�“ : {Middle Button:常规, Back Button:改é�“, Forward Button:改é�“, Mouse Gesture Button:改é�“, Smart Shift:常规} 11: ADJUSTABLE DPI {2201} ç�µæ•�度 (DPI) (saved): 1000 ç�µæ•�度 (DPI) : 1000 12: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 13: SMART SHIFT {2110} 滚轮分段模å¼� (saved): 16 滚轮分段模å¼� : 16 14: HIRES WHEEL {2121} Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode Low resolution mode HID notification 滚轮方å�‘ (saved): False 滚轮方å�‘ : False 滚轮分辨率 (saved): False 滚轮分辨率 : False 滚轮改é�“ (saved): False 滚轮改é�“ : False 15: GESTURE 2 {6501} 手势 (saved): {45: True, 46: True} 手势 : {46: True, 45: True} 手势改é�“ (saved): {46: False} 手势改é�“ : {46: False} 16: unknown:1813 {1813} internal, hidden 17: unknown:1830 {1830} internal, hidden 18: unknown:18A1 {18A1} internal, hidden 19: unknown:18C0 {18C0} internal, hidden 20: unknown:1DF3 {1DF3} internal, hidden 21: unknown:1E00 {1E00} hidden 22: unknown:1EB0 {1EB0} internal, hidden 23: unknown:1803 {1803} internal, hidden 24: unknown:1861 {1861} internal, hidden 25: unknown:9001 {9001} internal, hidden 26: unknown:9200 {9200} internal, hidden 27: unknown:9202 {9202} internal, hidden 28: OOBSTATE {1805} internal, hidden Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: diverted 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: diverted 5: Mouse Gesture Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: diverted, raw XY diverted 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Has 2 gesture(s), 0 param(s) and 4 spec(s): Thumbwheel Enabled( 0): True Diverted:( 0) False NaturalScrolling Enabled( 1): True Diverted:(None) None period unit Spec ( 3): 800 DVI field width Spec ( 1): 8 field widths Spec ( 2): 8 resolution Spec ( 4): 2048 Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Wireless Mouse MX Master 4041.txt000066400000000000000000000144401522022367600230770ustar00rootroot00000000000000 4: Wireless Mouse MX Master Device path : /dev/hidraw4 WPID : 4041 Codename : MX Master Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: ---------- Model ID: B01240410000 Unit ID: ---------- Bootloader: BOT 18.01.B0014 Firmware: MPM 11.02.B0014 Firmware: MPM 11.02.B0014 Other: The power switch is located on the base. Supports 28 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 18.01.B0014 40410862AB80 Firmware: Firmware MPM 11.02.B0014 B0120862AB80 Firmware: Firmware MPM 11.02.B0014 40410862AB80 Firmware: Other Unit ID: ------------ Model ID: B01240410000 Transport IDs: {'btleid': 'B012', 'wpid': '4041'} 3: DEVICE NAME {0005} Name: Wireless Mouse MX Master Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 7: CHANGE HOST {1814} Change Host : 1:jaaxx-elite 8: REPROG CONTROLS V4 {1B04} Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular} 9: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 1200 Sensitivity (DPI) : 1200 10: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 11: SMART SHIFT {2110} Scroll Wheel Rachet (saved): 8 Scroll Wheel Rachet : 8 12: HIRES WHEEL {2121} Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 13: GESTURE 2 {6501} Gestures (saved): {45: True, 46: True} Gestures : {46: True, 45: True} Gestures Diversion (saved): {46: False, 98: False, 211: False, 212: False} Gestures Diversion : {46: False, 98: False, 211: False, 212: False} 14: DFUCONTROL UNSIGNED {00C1} 15: unknown:1813 {1813} internal, hidden 16: unknown:1830 {1830} internal, hidden 17: unknown:1890 {1890} internal, hidden 18: unknown:18A1 {18A1} internal, hidden 19: unknown:18C0 {18C0} internal, hidden 20: unknown:1DF3 {1DF3} internal, hidden 21: unknown:1E00 {1E00} hidden 22: unknown:1EB0 {1EB0} internal, hidden 23: unknown:1803 {1803} internal, hidden 24: unknown:1861 {1861} internal, hidden 25: unknown:9000 {9000} internal, hidden 26: unknown:9200 {9200} internal, hidden 27: unknown:9240 {9240} internal, hidden Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button => Gesture Button mse, reprogrammable, divertable, pos:0, group:3, group mask:g1,g2,g3 reporting: default 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, pos:0, group:3, group mask:g1,g2,g3 reporting: default Has 5 gesture(s), 0 param(s) and 4 spec(s): Thumbwheel Enabled( 0): True Diverted:( 0) False NaturalScrolling Enabled( 1): True Diverted:(None) None Finger9 Enabled(None): None Diverted:( 1) False unknown:00D3 Enabled(None): None Diverted:( 2) False unknown:00D4 Enabled(None): None Diverted:( 3) False period unit Spec ( 3): 800 DVI field width Spec ( 1): 8 field widths Spec ( 2): 8 resolution Spec ( 4): 2048 Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Wireless Mouse MX Master 4071.txt000066400000000000000000000151261522022367600231040ustar00rootroot00000000000000Solaar version 1.1.4 3: Wireless Mouse MX Master Device path : /dev/hidraw3 WPID : 4071 Codename : MX Master Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: D3596818 Model ID: B01E40710000 Unit ID: 9803B76B Bootloader: BOT 56.10.B0005 Firmware: MPM 12.10.B0005 Firmware: MPM 12.10.B0005 Other: The power switch is located on the base. Supports 31 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 56.10.B0005 40717622661101 Firmware: Firmware MPM 12.10.B0005 B01E7622661101 Firmware: Firmware MPM 12.10.B0005 40717622661101 Firmware: Other Unit ID: 9803B76B Model ID: B01E40710000 Transport IDs: {'btleid': 'B01E', 'wpid': '4071'} 3: DEVICE NAME {0005} Name: Wireless Mouse MX Master Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: CRYPTO ID {0021} 7: BATTERY STATUS {1000} Battery: N/A, recharging, next level 0%. 8: CONFIG DEVICE PROPS {1806} internal, hidden 9: CHANGE HOST {1814} Change Host : 2:rachel 10: REPROG CONTROLS V4 {1B04} DPI Sliding Adjustment (saved): Off DPI Sliding Adjustment : Off Mouse Gestures (saved): Off Mouse Gestures : Off Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button Navigation, Smart Shift:Smart Shift} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Regular, Smart Shift:Regular} 11: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 1000 Sensitivity (DPI) : 1000 12: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 13: SMART SHIFT {2110} Scroll Wheel Rachet (saved): 10 Scroll Wheel Rachet : 10 14: HIRES WHEEL {2121} Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 15: GESTURE 2 {6501} Gestures (saved): {45: True, 46: True} Gestures : {46: True, 45: True} Gestures Diversion (saved): {46: False} Gestures Diversion : {46: False} 16: DFUCONTROL SIGNED {00C2} 17: unknown:1813 {1813} internal, hidden 18: unknown:1830 {1830} internal, hidden 19: unknown:1890 {1890} internal, hidden 20: unknown:1891 {1891} internal, hidden 21: unknown:18A1 {18A1} internal, hidden 22: unknown:18C0 {18C0} internal, hidden 23: unknown:1DF3 {1DF3} internal, hidden 24: unknown:1E00 {1E00} hidden 25: unknown:1EB0 {1EB0} internal, hidden 26: unknown:1803 {1803} internal, hidden 27: unknown:1861 {1861} internal, hidden 28: unknown:9001 {9001} internal, hidden 29: unknown:9200 {9200} internal, hidden 30: unknown:9202 {9202} internal, hidden Has 8 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, raw XY, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button Navigation => Gesture Button Navigation mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: default 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, raw XY, pos:0, group:3, group mask:g1,g2,g3 reporting: default 7: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:4, group mask:empty reporting: default Has 2 gesture(s), 0 param(s) and 4 spec(s): Thumbwheel Enabled( 0): True Diverted:( 0) False NaturalScrolling Enabled( 1): True Diverted:(None) None period unit Spec ( 3): 800 DVI field width Spec ( 1): 8 field widths Spec ( 2): 8 resolution Spec ( 4): 2048 Battery: N/A, recharging, next level 0%. Solaar-1.1.20/docs/devices/Wireless Mouse MX Master B012.txt000066400000000000000000000143631522022367600231170ustar00rootroot00000000000000Solaar version 1.1.3 1: Wireless Mouse MX Master Device path : /dev/hidraw4 USB id : 046d:B012 Codename : MX Master Kind : mouse Protocol : HID++ 4.5 Serial number: Model ID: B01240410000 Unit ID: 3E9C68EF Bootloader: BOT 18.01.B0014 Firmware: MPM 11.02.B0014 Firmware: MPM 11.02.B0014 Other: Supports 28 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 18.01.B0014 40410862AB80 Firmware: Firmware MPM 11.02.B0014 B0120862AB80 Firmware: Firmware MPM 11.02.B0014 40410862AB80 Firmware: Other Unit ID: 3E9C68EF Model ID: B01240410000 Transport IDs: {'btleid': 'B012', 'wpid': '4041'} 3: DEVICE NAME {0005} Name: Wireless Mouse MX Master Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY STATUS {1000} Battery: 50%, discharging, next level 20%. 7: CHANGE HOST {1814} Change Host : 1:heimdall 8: REPROG CONTROLS V4 {1B04} Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button, Back Button:Mouse Back Button, Forward Button:Mouse Forward Button, Mouse Gesture Button:Gesture Button, Smart Shift:Smart Shift} Key/Button Diversion (saved): {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Diverted, Smart Shift:Diverted} Key/Button Diversion : {Middle Button:Regular, Back Button:Regular, Forward Button:Regular, Mouse Gesture Button:Diverted, Smart Shift:Diverted} 9: ADJUSTABLE DPI {2201} Sensitivity (DPI) (saved): 1000 Sensitivity (DPI) : 1000 10: VERTICAL SCROLLING {2100} Roller type: 3G Ratchet per turn: 24 Scroll lines: 0 11: SMART SHIFT {2110} Scroll Wheel Rachet (saved): 35 Scroll Wheel Rachet : 35 12: HIRES WHEEL {2121} Multiplier: 8 Has invert: Normal wheel motion Has ratchet switch: Normal wheel mode High resolution mode HID notification Scroll Wheel Direction (saved): False Scroll Wheel Direction : False Scroll Wheel Resolution (saved): True Scroll Wheel Resolution : True Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 13: GESTURE 2 {6501} Gestures (saved): {45: True, 46: True} Gestures : {46: True, 45: True} Gestures Diversion (saved): {46: False, 98: False, 211: False, 212: False} Gestures Diversion : {46: False, 98: False, 211: False, 212: False} 14: unknown:1813 {1813} internal, hidden 15: unknown:1830 {1830} internal, hidden 16: unknown:1890 {1890} internal, hidden 17: unknown:18A1 {18A1} internal, hidden 18: unknown:18C0 {18C0} internal, hidden 19: unknown:1DF3 {1DF3} internal, hidden 20: unknown:1E00 {1E00} hidden 21: unknown:1EB0 {1EB0} internal, hidden 22: unknown:1803 {1803} internal, hidden 23: unknown:1861 {1861} internal, hidden 24: unknown:9000 {9000} internal, hidden 25: unknown:9200 {9200} internal, hidden 26: unknown:9240 {9240} internal, hidden 27: OOBSTATE {1805} internal, hidden Has 7 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2,g3 reporting: default 3: Back Button , default: Mouse Back Button => Mouse Back Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 4: Forward Button , default: Mouse Forward Button => Mouse Forward Button mse, reprogrammable, divertable, pos:0, group:2, group mask:g1,g2 reporting: default 5: Mouse Gesture Button , default: Gesture Button => Gesture Button mse, reprogrammable, divertable, pos:0, group:3, group mask:g1,g2,g3 reporting: diverted 6: Smart Shift , default: Smart Shift => Smart Shift mse, reprogrammable, divertable, pos:0, group:3, group mask:g1,g2,g3 reporting: diverted Has 5 gesture(s), 0 param(s) and 4 spec(s): Thumbwheel Enabled( 0): True Diverted:( 0) False NaturalScrolling Enabled( 1): True Diverted:(None) None Finger9 Enabled(None): None Diverted:( 1) False unknown:00D3 Enabled(None): None Diverted:( 2) False unknown:00D4 Enabled(None): None Diverted:( 3) False period unit Spec ( 3): 800 DVI field width Spec ( 1): 8 field widths Spec ( 2): 8 resolution Spec ( 4): 2048 Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Wireless Mouse Pebble M350 4080.txt000066400000000000000000000074271522022367600231470ustar00rootroot00000000000000Solaar version 1.1.4 2: Wireless Mouse Pebble M350 Device path : /dev/hidraw2 WPID : 4080 Codename : Pebble Kind : mouse Protocol : HID++ 4.5 Polling rate : 8 ms (125Hz) Serial number: 2B442F40 Model ID: B02140800000 Unit ID: DE12CCD9 Firmware: MPM 18.00.B0007 Other: The power switch is located on the base. Supports 26 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Firmware MPM 18.00.B0007 4080BEA0D686 Firmware: Other Unit ID: DE12CCD9 Model ID: B02140800000 Transport IDs: {'btleid': 'B021', 'wpid': '4080'} 3: DEVICE NAME {0005} V0 Name: M350 Wireless Mouse Kind: mouse 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: Logitech Pebble 7: BATTERY STATUS {1000} V1 Battery: 50%, discharging, next level 20%. 8: REPROG CONTROLS V4 {1B04} V4 Key/Button Actions (saved): {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button} Key/Button Actions : {Left Button:Left Click, Right Button:Right Click, Middle Button:Mouse Middle Button} Key/Button Diversion (saved): {Middle Button:Regular, ?} Key/Button Diversion : {Middle Button:Regular} 9: CHANGE HOST {1814} V1 Change Host : 1:brandy 10: ADJUSTABLE DPI {2201} V1 Sensitivity (DPI) (saved): 1000 Sensitivity (DPI) : 1000 11: LOWRES WHEEL {2130} V0 Wheel Reports: HID Scroll Wheel Diversion (saved): False Scroll Wheel Diversion : False 12: DEVICE RESET {1802} V0 internal, hidden 13: unknown:1803 {1803} V0 internal, hidden 14: CONFIG DEVICE PROPS {1806} V5 internal, hidden 15: unknown:1812 {1812} V0 internal, hidden 16: OOBSTATE {1805} V0 internal, hidden 17: unknown:1830 {1830} V0 internal, hidden 18: unknown:1890 {1890} V4 internal, hidden 19: unknown:1891 {1891} V4 internal, hidden 20: unknown:18A1 {18A1} V0 internal, hidden 21: unknown:1DF3 {1DF3} V0 internal, hidden 22: unknown:1E00 {1E00} V0 hidden 23: unknown:1EB0 {1EB0} V0 internal, hidden 24: unknown:1861 {1861} V0 internal, hidden 25: unknown:18B1 {18B1} V0 internal, hidden Has 4 reprogrammable keys: 0: Left Button , default: Left Click => Left Click mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1 reporting: default 1: Right Button , default: Right Click => Right Click mse, reprogrammable, analytics key events, pos:0, group:1, group mask:g1 reporting: default 2: Middle Button , default: Mouse Middle Button => Mouse Middle Button mse, reprogrammable, divertable, raw XY, analytics key events, pos:0, group:2, group mask:g1,g2 reporting: default 3: Virtual Gesture Button , default: Virtual Gesture Button => Virtual Gesture Button divertable, virtual, raw XY, force raw XY, pos:0, group:3, group mask:empty reporting: default Battery: 50%, discharging, next level 20%. Solaar-1.1.20/docs/devices/Wireless Multi-Device Keyboard K780 405B.txt000066400000000000000000000232221522022367600247300ustar00rootroot00000000000000Solaar version 1.1.7 1: Wireless Multi-Device Keyboard K780 Device path : /dev/hidraw4 WPID : 405B Codename : K780 Kind : keyboard Protocol : HID++ 4.5 Polling rate : 20 ms (50Hz) Serial number: 3C60AFA4 Model ID: B33B405B0000 Unit ID: 6CAF50FF Bootloader: BOT 25.01.B0006 Firmware: MPK 01.04.B0028 Other: The power switch is located on the edge of top right corner. Supports 31 HID++ 2.0 features: 0: ROOT {0000} V0 1: FEATURE SET {0001} V0 2: DEVICE FW VERSION {0003} V2 Firmware: Bootloader BOT 25.01.B0006 0000C9839F9301 Firmware: Firmware MPK 01.04.B0028 405BC9839F9301 Firmware: Other Unit ID: 6CAF50FF Model ID: B33B405B0000 Transport IDs: {'btleid': 'B33B', 'wpid': '405B'} 3: DEVICE NAME {0005} V0 Name: K780 Multi-Device Wireless Keyboard Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} V0 5: RESET {0020} V0 6: DEVICE FRIENDLY NAME {0007} V0 Friendly Name: Keyboard K780 7: BATTERY STATUS {1000} V0 Battery: 90%, discharging, next level 50%. 8: CHANGE HOST {1814} V1 Cambiar Host : 1:romanescu 9: HOSTS INFO {1815} V1 Host 0 (paired): romanescu Host 1 (paired): espinaca Host 2 (unpaired): 10: REPROG CONTROLS V4 {1B04} V3 Desvio de Tecla/Botón (saved): {Volume Up:Normal, Volume Down:Normal, Mute:Normal, Play/Pause:Normal, Next:Normal, Previous:Normal, Multiplatform Back:Normal, Multiplatform Insert:Normal, Screen Capture/Print Screen:Normal, Fn Down:Normal, Fn Up:Normal, Multiplatform Lock:Normal, Host Switch Channel 1:Normal, Host Switch Channel 2:Normal, Host Switch Channel 3:Normal, MultiPlatform Search:Normal, MultiPlatform Home/Mission Control:Normal, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Normal} Desvio de Tecla/Botón : {Volume Up:Normal, Volume Down:Normal, Mute:Normal, Play/Pause:Normal, Next:Normal, Previous:Normal, Multiplatform Back:Normal, Multiplatform Insert:Normal, Screen Capture/Print Screen:Normal, Fn Down:Normal, Fn Up:Normal, Multiplatform Lock:Normal, Host Switch Channel 1:Normal, Host Switch Channel 2:Normal, Host Switch Channel 3:Normal, MultiPlatform Search:Normal, MultiPlatform Home/Mission Control:Normal, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:Normal} 11: PERSISTENT REMAPPABLE ACTION {1C00} V0 Persistent Key/Button Mapping : {Volume Up:Volume Up, Volume Down:Volume Down, Mute:Mute, Play/Pause:Play/Pause, Next:Scan Next Track, Previous:Scan Previous Track, Multiplatform Back:AC Back, MultiPlatform Search:AC Search, MultiPlatform Home/Mission Control:AC Home, MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad:COMPOSE} 12: NEW FN INVERSION {40A2} V0 Fn-swap: enabled Fn-swap default: enabled Intercambiar función Fx (saved): True Intercambiar función Fx : True 13: ENCRYPTION {4100} V0 14: KEYBOARD DISABLE KEYS {4521} V0 Desactivar teclas (saved): {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} Desactivar teclas : {Caps Lock:False, Num Lock:False, Scroll Lock:False, Insert:False, Win:False} 15: MULTIPLATFORM {4531} V0 Especificar SO (saved): Windows Especificar SO : Windows 16: LOCK KEY STATE {4220} V0 17: DFUCONTROL SIGNED {00C2} V0 18: unknown:1803 {1803} V0 internal, hidden 19: CONFIG DEVICE PROPS {1806} V0 internal, hidden 20: OOBSTATE {1805} V0 internal, hidden 21: unknown:1813 {1813} V0 internal, hidden 22: unknown:1830 {1830} V0 internal, hidden 23: unknown:1861 {1861} V0 internal, hidden 24: unknown:1890 {1890} V0 internal, hidden 25: unknown:1891 {1891} V0 internal, hidden 26: unknown:18A1 {18A1} V0 internal, hidden 27: unknown:1DF3 {1DF3} V0 internal, hidden 28: unknown:1E00 {1E00} V0 hidden 29: unknown:1EB0 {1EB0} V0 internal, hidden 30: unknown:18B0 {18B0} V0 internal, hidden Has 19 reprogrammable keys: 0: Host Switch Channel 1 , default: HostSwitch Channel 1 => HostSwitch Channel 1 is FN, FN sensitive, divertable, persistently divertable, pos:1, group:0, group mask:empty reporting: default 1: Host Switch Channel 2 , default: HostSwitch Channel 2 => HostSwitch Channel 2 is FN, FN sensitive, divertable, persistently divertable, pos:2, group:0, group mask:empty reporting: default 2: Host Switch Channel 3 , default: HostSwitch Channel 3 => HostSwitch Channel 3 is FN, FN sensitive, divertable, persistently divertable, pos:3, group:0, group mask:empty reporting: default 3: MultiPlatform Home/Mission Control, default: Multiplatform Home/Mission Control => Multiplatform Home/Mission Control is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:4, group:0, group mask:empty reporting: default 4: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad, default: Multiplatform Menu/Launchpad => Multiplatform Menu/Launchpad is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:5, group:0, group mask:empty reporting: default 5: Multiplatform Back , default: MultiPlatform Back => MultiPlatform Back is FN, FN sensitive, reprogrammable, divertable, persistently divertable, pos:6, group:0, group mask:empty reporting: default 6: Previous , default: Previous => Previous is FN, FN sensitive, divertable, persistently divertable, pos:7, group:0, group mask:empty reporting: default 7: Play/Pause , default: Play/Pause => Play/Pause is FN, FN sensitive, divertable, persistently divertable, pos:8, group:0, group mask:empty reporting: default 8: Next , default: Next => Next is FN, FN sensitive, divertable, persistently divertable, pos:9, group:0, group mask:empty reporting: default 9: Mute , default: Mute => Mute is FN, FN sensitive, divertable, persistently divertable, pos:10, group:0, group mask:empty reporting: default 10: Volume Down , default: Volume Down => Volume Down is FN, FN sensitive, divertable, persistently divertable, pos:11, group:0, group mask:empty reporting: default 11: Volume Up , default: Volume Up => Volume Up is FN, FN sensitive, divertable, persistently divertable, pos:12, group:0, group mask:empty reporting: default 12: MultiPlatform Search , default: Multiplatform Search => Multiplatform Search nonstandard, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 13: Multiplatform Insert , default: Switch Language => Switch Language is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 14: Screen Capture/Print Screen, default: Screen Capture => Screen Capture is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 15: Multiplatform Lock , default: WindowsLock => WindowsLock is FN, reprogrammable, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 16: Fn Up , default: unknown:0070 => unknown:0070 is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 17: Fn Down , default: unknown:006F => unknown:006F is FN, divertable, persistently divertable, pos:0, group:0, group mask:empty reporting: default 18: FN Key , default: Do Nothing One => Do Nothing One nonstandard, pos:0, group:0, group mask:empty reporting: default Has 10 persistent remappable keys: 0: MultiPlatform Home/Mission Control => Consumer: AC Home 1: MultiPlatform Menu/Show/Hide Virtual Keyboard/Launchpad => Key: COMPOSE 2: Multiplatform Back => Consumer: AC Back 3: Previous => Consumer: Scan Previous Track 4: Play/Pause => Consumer: Play/Pause 5: Next => Consumer: Scan Next Track 6: Mute => Consumer: Mute 7: Volume Down => Consumer: Volume Down 8: Volume Up => Consumer: Volume Up 9: MultiPlatform Search => Consumer: AC Search Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/Wireless Rechargeable Touchpad T650 4101.txt000066400000000000000000000033631522022367600250000ustar00rootroot00000000000000 1: Wireless Rechargeable Touchpad T650 Codename : T650 Kind : touchpad Wireless PID : 4101 Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: 22205A4D Firmware: RQM 41.01.B0037 Bootloader: BL 03.00 Hardware: 72 Other: The power switch is located on the base. Supports 23 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: FEATURE INFO {0002} 3: DEVICE FW VERSION {0003} 4: DEVICE NAME {0005} 5: BATTERY STATUS {1000} 6: WIRELESS DEVICE STATUS {1D4B} 7: unknown:1DF3 {1DF3} internal, hidden 8: REPROG CONTROLS {1B00} 9: unknown:1F03 {1F03} internal, hidden 10: VERTICAL SCROLLING {2100} 11: HI RES SCROLLING {2120} 12: MOUSE POINTER {2200} 13: DFUCONTROL {00C0} 14: unknown:1E80 {1E80} internal, hidden 15: TOUCHPAD RAW XY {6100} 16: unknown:1860 {1860} internal, hidden 17: unknown:1E00 {1E00} hidden 18: REPROG CONTROLS V2 {1B01} 19: unknown:1890 {1890} internal, hidden 20: unknown:18E5 {18E5} internal, hidden 21: unknown:18A0 {18A0} internal, hidden 22: unknown:1830 {1830} internal, hidden Has 2 reprogrammable keys: 0: LEFT CLICK => LeftClick mse, reprogrammable 1: RIGHT CLICK => RightClick mse, reprogrammable Battery: 50%, discharging. Solaar-1.1.20/docs/devices/Wireless Solar Keyboard K750 4002.txt000066400000000000000000000041051522022367600234700ustar00rootroot00000000000000 2: Wireless Solar Keyboard K750 Codename : K750 Kind : keyboard Wireless PID : 4002 Protocol : HID++ 2.0 Polling rate : 20 ms (50Hz) Serial number: 5692B2EC Firmware: RQK 33.00.B0015 Bootloader: DFU 00.02.B0003 The power switch is located on the edge of top right corner. Supports 11 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} 3: DEVICE NAME {0005} 4: REPROG CONTROLS {1B00} 5: WIRELESS DEVICE STATUS {1D4B} 6: unknown:1DF3 {1DF3} hidden 7: FN INVERSION {40A0} 8: ENCRYPTION {4100} 9: SOLAR DASHBOARD {4301} 10: KEYBOARD LAYOUT {4520} Has 12 reprogrammable keys: 0: MY HOME => HomePage FN sensitive, is FN, reprogrammable 1: Mail => Email FN sensitive, is FN, reprogrammable 2: SEARCH => Search FN sensitive, is FN, reprogrammable 3: Calculator => Calculator FN sensitive, is FN, reprogrammable 4: MEDIA PLAYER => Music FN sensitive, is FN, reprogrammable 5: Previous => Previous FN sensitive, is FN 6: Play/Pause => Play/Pause FN sensitive, is FN 7: Next => Next FN sensitive, is FN 8: Mute => Mute FN sensitive, is FN 9: Volume Down => Volume Down FN sensitive, is FN 10: Volume Up => Volume Up FN sensitive, is FN 11: SLEEP => Sleep FN sensitive, is FN, reprogrammable Battery status unavailable. Solaar-1.1.20/docs/devices/Wireless Touch Keyboard K400 4024.txt000066400000000000000000000055631522022367600234770ustar00rootroot00000000000000 1: Wireless Touch Keyboard K400 Codename : K400 Kind : keyboard Wireless PID : 4024 Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: AC5F5069 Firmware: RQK 50.01.B0013 The power switch is located on the edge of top right corner. Supports 22 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: FEATURE INFO {0002} 3: DEVICE FW VERSION {0003} 4: DEVICE NAME {0005} 5: BATTERY STATUS {1000} 6: REPROG CONTROLS {1B00} 7: REPROG CONTROLS V3 {1B03} 8: WIRELESS DEVICE STATUS {1D4B} 9: unknown:1DF0 {1DF0} hidden 10: unknown:1DF3 {1DF3} internal, hidden 11: unknown:1E00 {1E00} hidden 12: VERTICAL SCROLLING {2100} 13: HI RES SCROLLING {2120} 14: MOUSE POINTER {2200} 15: FN INVERSION {40A0} 16: NEW FN INVERSION {40A2} 17: ENCRYPTION {4100} 18: KEYBOARD LAYOUT {4520} 19: TOUCHPAD FW ITEMS {6010} 20: TOUCHPAD SW ITEMS {6011} 21: TOUCHPAD WIN8 FW ITEMS {6012} Has 18 reprogrammable keys: 0: SHOW DESKTOP => ShowDesktop is FN, reprogrammable 1: METRO APPSWITCH => MetroAppSwitch is FN, reprogrammable 2: METRO SEARCH => MetroSearch is FN, reprogrammable 3: METRO SHARE => MetroShare is FN, reprogrammable 4: METRO DEVICES => MetroDevices is FN, reprogrammable 5: METRO SETTINGS => MetroSettings is FN, reprogrammable 6: Previous => Previous is FN 7: Play/Pause => Play/Pause is FN 8: Next => Next is FN 9: Mute => Mute is FN 10: Volume Down => Volume Down is FN 11: Volume Up => Volume Up is FN 12: MEDIA PLAYER => Music nonstandard, reprogrammable 13: Lock PC => WindowsLock nonstandard, reprogrammable 14: SLEEP => Sleep nonstandard, reprogrammable 15: LEFT CLICK => LeftClick mse 16: LEFT CLICK => LeftClick mse 17: RIGHT CLICK => RightClick mse Battery: 90%, discharging. Solaar-1.1.20/docs/devices/Wireless Touch Keyboard K400 Plus 404D.txt000066400000000000000000000230441522022367600244170ustar00rootroot00000000000000Solaar version 1.1.4 1: Wireless Touch Keyboard K400 Plus Device path : /dev/hidraw2 WPID : 404D Codename : K400 Plus Kind : keyboard Protocol : HID++ 4.1 Polling rate : 8 ms (125Hz) Serial number: 6DC5C81C Model ID: 404D00000000 Unit ID: 641487CF Bootloader: BOT 22.02.B0002 Firmware: RQK 63.02.B0016 Other: The power switch is located on the top edge. Supports 23 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: DEVICE FW VERSION {0003} Firmware: Bootloader BOT 22.02.B0002 404D6217AD40 Firmware: Firmware RQK 63.02.B0016 404D6217AD40 Firmware: Other Unit ID: 641487CF Model ID: 404D00000000 Transport IDs: {'wpid': '404D'} 3: DEVICE NAME {0005} Name: Wireless Touch Keyboard K400 Plus Kind: keyboard 4: WIRELESS DEVICE STATUS {1D4B} 5: RESET {0020} 6: BATTERY STATUS {1000} Battery: 90%, discharging, next level 50%. 7: REPROG CONTROLS V4 {1B04} Key/Button Diversion (saved): {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Application Switcher:Regular, My Home:Regular, Media Player:Regular, Search:Regular, Sleep:Regular, Contextual Menu:Regular, Back:Regular, Show Desktop:Regular, Maximize Window:Regular, Switch Screen:Regular, Fn Left Click:Regular, Second Left Click:Regular} Key/Button Diversion : {Volume Up:Regular, Volume Down:Regular, Mute:Regular, Play/Pause:Regular, Next:Regular, Previous:Regular, Application Switcher:Regular, My Home:Regular, Media Player:Regular, Search:Regular, Sleep:Regular, Contextual Menu:Regular, Back:Regular, Show Desktop:Regular, Maximize Window:Regular, Switch Screen:Regular, Fn Left Click:Regular, Second Left Click:Regular} 8: SWAP BUTTON CANCEL {2005} 9: NEW FN INVERSION {40A2} Fn-swap: enabled Fn-swap default: enabled Swap Fx function (saved): True Swap Fx function : True 10: ENCRYPTION {4100} 11: KEYBOARD DISABLE KEYS {4521} Disable keys (saved): {Caps Lock:False, Scroll Lock:False, Insert:False, Win:False} Disable keys : {Caps Lock:False, Scroll Lock:False, Insert:False, Win:False} 12: TOUCHPAD RAW XY {6100} 13: GESTURE 2 {6501} Gestures (saved): {1: True, 2: True, 10: True, 30: True, 34: False, 42: True, 43: True, 45: False, 64: False, 65: False, 67: False, 84: True} Gestures : {1: True, 2: True, 30: True, 10: True, 45: False, 42: True, 43: True, 64: False, 65: False, 67: False, 84: True, 34: False} Gestures Diversion (saved): {1: False, 2: False, 10: False, 44: False, 64: False, 65: False, 67: False, 84: False, 85: False, 100: False} Gestures Diversion : {1: False, 2: False, 10: False, 44: False, 64: False, 65: False, 67: False, 84: False, 85: False, 100: False} Gesture params (saved): {4: {'scale': 256}} Gesture params : {4: {'scale': 256}} 14: DFUCONTROL UNSIGNED {00C1} 15: unknown:1811 {1811} internal, hidden 16: unknown:1830 {1830} internal, hidden 17: unknown:1890 {1890} internal, hidden 18: unknown:1DF3 {1DF3} internal, hidden 19: unknown:1E00 {1E00} hidden 20: unknown:1EB0 {1EB0} internal, hidden 21: unknown:1861 {1861} internal, hidden 22: unknown:18B0 {18B0} internal, hidden Has 20 reprogrammable keys: 0: Second Left Click , default: Left Click => Left Click mse, divertable, pos:0, group:0, group mask:empty reporting: default 1: Back , default: Mouse Back Button => Mouse Back Button is FN, FN sensitive, reprogrammable, divertable, pos:1, group:0, group mask:empty reporting: default 2: My Home , default: HomePage => HomePage is FN, FN sensitive, reprogrammable, divertable, pos:2, group:0, group mask:empty reporting: default 3: Application Switcher , default: Application Switcher => Application Switcher is FN, FN sensitive, reprogrammable, divertable, pos:3, group:0, group mask:empty reporting: default 4: Contextual Menu , default: Right Click => Right Click is FN, FN sensitive, reprogrammable, divertable, pos:4, group:0, group mask:empty reporting: default 5: Search , default: Search Files => Search Files is FN, FN sensitive, reprogrammable, divertable, pos:5, group:0, group mask:empty reporting: default 6: Show Desktop , default: Show Desktop => Show Desktop is FN, FN sensitive, reprogrammable, divertable, pos:6, group:0, group mask:empty reporting: default 7: Maximize Window , default: Maximize Window => Maximize Window is FN, FN sensitive, reprogrammable, divertable, pos:7, group:0, group mask:empty reporting: default 8: Switch Screen , default: Switch Presentation/Switch Screen => Switch Presentation/Switch Screen is FN, FN sensitive, reprogrammable, divertable, pos:8, group:0, group mask:empty reporting: default 9: Media Player , default: Music => Music is FN, FN sensitive, reprogrammable, divertable, pos:9, group:0, group mask:empty reporting: default 10: Previous , default: Previous => Previous is FN, FN sensitive, divertable, pos:10, group:0, group mask:empty reporting: default 11: Play/Pause , default: Play/Pause => Play/Pause is FN, FN sensitive, divertable, pos:11, group:0, group mask:empty reporting: default 12: Next , default: Next => Next is FN, FN sensitive, divertable, pos:12, group:0, group mask:empty reporting: default 13: Fn Left Click , default: ShowUI => ShowUI divertable, pos:0, group:0, group mask:empty reporting: default 14: Left Button , default: Left Click => Left Click mse, pos:0, group:0, group mask:empty reporting: default 15: Right Button , default: Right Click => Right Click mse, pos:0, group:0, group mask:empty reporting: default 16: Mute , default: Mute => Mute nonstandard, divertable, pos:0, group:0, group mask:empty reporting: default 17: Volume Up , default: Volume Up => Volume Up nonstandard, divertable, pos:0, group:0, group mask:empty reporting: default 18: Volume Down , default: Volume Down => Volume Down nonstandard, divertable, pos:0, group:0, group mask:empty reporting: default 19: Sleep , default: Sleep => Sleep reprogrammable, divertable, pos:0, group:0, group mask:empty reporting: default Has 17 gesture(s), 1 param(s) and 5 spec(s): Track1Finger Enabled(None): None Diverted:(None) None TapGestures Enabled(None): None Diverted:(None) None Tap1Finger Enabled( 0): True Diverted:( 0) False Tap2Finger Enabled( 1): True Diverted:( 1) False TapDrag1Finger Enabled( 2): True Diverted:(None) None DoubleTap1Finger Enabled( 3): True Diverted:( 2) False Scroll2FingerStateless Enabled(None): None Diverted:( 3) False NaturalScrolling Enabled( 4): False Diverted:(None) None Scroll2FingerHoriz Enabled( 5): True Diverted:(None) None Scroll2FingerVert Enabled( 6): True Diverted:(None) None LeftEdgeSwipe1Finger2 Enabled( 7): False Diverted:( 4) False RightEdgeSwipe1Finger2 Enabled( 8): False Diverted:( 5) False TopEdgeSwipe1Finger2 Enabled( 9): False Diverted:( 6) False Zoom2FingerStateless Enabled( 10): True Diverted:( 7) False FnClickGestureSuppression Enabled( 11): False Diverted:(None) None TwoFingersPresent Enabled(None): None Diverted:( 8) False DeviceSpecificRawData Enabled(None): None Diverted:( 9) False ScaleFactor Value ( 0): 256 [Default: 256] period unit Spec ( 3): 2048 DVI field width Spec ( 1): 8 field widths Spec ( 2): 8 multiplier Spec ( 5): None resolution Spec ( 4): 4 Battery: 90%, discharging, next level 50%. Solaar-1.1.20/docs/devices/Wireless Trackball M570 1028.txt000066400000000000000000000006271522022367600226020ustar00rootroot00000000000000 1: Wireless Trackball M570 Codename : M570 Kind : mouse Wireless PID : 1028 Protocol : HID++ 1.0 Polling rate : 8 ms (125Hz) Serial number: 891DC05A Firmware: 26.00.B0003 Bootloader: 02.06 Other: 00.01 The power switch is located on the base. Notifications: battery status (0x100000). Battery: 100%, discharging. Solaar-1.1.20/docs/devices/Zone Touch Mouse T400 4026.txt000066400000000000000000000047101522022367600221510ustar00rootroot00000000000000 1: Zone Touch Mouse T400 Codename : T400 Kind : mouse Wireless PID : 4026 Protocol : HID++ 2.0 Polling rate : 8 ms (125Hz) Serial number: 131A3093 Firmware: RQM 39.00.B0029 Bootloader: BL 03.00 Hardware: 72 Other: The power switch is located on the base. Supports 28 HID++ 2.0 features: 0: ROOT {0000} 1: FEATURE SET {0001} 2: FEATURE INFO {0002} 3: DEVICE FW VERSION {0003} 4: DEVICE NAME {0005} 5: DFUCONTROL {00C0} 6: BATTERY STATUS {1000} 7: unknown:1802 {1802} internal, hidden 8: unknown:1810 {1810} internal, hidden 9: unknown:1830 {1830} internal, hidden 10: unknown:1850 {1850} internal, hidden 11: unknown:1860 {1860} internal, hidden 12: unknown:1890 {1890} internal, hidden 13: unknown:18A0 {18A0} internal, hidden 14: unknown:18E3 {18E3} internal, hidden 15: REPROG CONTROLS {1B00} 16: WIRELESS DEVICE STATUS {1D4B} 17: unknown:1DF3 {1DF3} internal, hidden 18: unknown:1E00 {1E00} hidden 19: unknown:1E80 {1E80} internal, hidden 20: unknown:1F03 {1F03} internal, hidden 21: unknown:1F04 {1F04} internal, hidden 22: VERTICAL SCROLLING {2100} 23: unknown:2101 {2101} hidden 24: HI RES SCROLLING {2120} 25: MOUSE POINTER {2200} 26: TOUCHMOUSE RAW POINTS {6110} hidden 27: REPROG CONTROLS V3 {1B03} Has 7 reprogrammable keys: 0: LEFT CLICK => LeftClick mse, reprogrammable 1: RIGHT CLICK => RightClick mse, reprogrammable 2: MIDDLE BUTTON => MiddleMouseButton mse, reprogrammable 3: METRO START SCREEN => MetroStartScreen mse, reprogrammable 4: ZOOMIN => Do Nothing mse, reprogrammable 5: ZOOMOUT => Do Nothing mse, reprogrammable 6: BACK HSCROLL => TouchBackForwardHorzScroll Battery: 100%, discharging. Solaar-1.1.20/docs/devices/anywhere-mx.txt000066400000000000000000000054141522022367600204040ustar00rootroot00000000000000Receiver LZ301AR-DJ M/N:C-U0007 (ltunify) Serial number: D1759614 Firmware version: 012.001.00019 Bootloader version: BL.002.014 Supported notification flags: 00 09 00 - 01: Wireless Notifications - 08: Software Present Mouse (ltunify) HID++ version: 1.0 Device index 1 Mouse Name: Anywhere MX Wireless Product ID: 1017 Serial number: 13865F99 Firmware version: 016.001.00040 Bootloader version: BL.002.010 (solaar) Unifying Receiver Device path : /dev/hidraw2 USB id : 046d:c52b Serial : D1759614 Firmware : 12.01.B0019 Bootloader : 02.14 Has 1 paired device(s) out of a maximum of 6. Notifications: (none) Device activity counters: 1=19 1: Anywhere Mouse MX Codename : Anywhere MX Kind : mouse Wireless PID : 1017 Protocol : HID++ 1.0 Polling rate : 8 ms (125Hz) Serial number: 13865F99 Firmware: 16.01.B0040 Bootloader: 02.10 Other: 00.06 The power switch is located on the base. Notifications: (none). Battery: 100%, discharging. (scan-registers) # Old notification flags: 000000 # 00 - Enabled Notifications, supported flags: Battery Status (10) >> ( 0.792) [10 01 8100 100000] b'\x10\x01\x81\x00\x10\x00\x00' # 01 - scrolling settings? # Flags: # 0x40 - Enable Smooth Scrolling # 0x02 - "confuse KDE", see https://github.com/pwr/Solaar/issues/115 << ( 0.011) [10 01 8101 000000] b'\x10\x01\x81\x01\x00\x00\x00' >> ( 1.710) [10 01 8101 020000] b'\x10\x01\x81\x01\x02\x00\x00' # 0D - battery level. first byte is remaining charge in percent; second is # (guessed) maximum?; third is charge status (30=discharging) # "10 ix 0D 64 64 30 00" is a battery notification (when enabled) << ( 9.789) [10 01 810D 000000] b'\x10\x01\x81\r\x00\x00\x00' >> ( 9.816) [10 01 810D 646430] b'\x10\x01\x81\rdd0' # 63 - DPI (range 0x80-0x8e (inclusive)) << ( 75.521) [10 01 8163 000000] b'\x10\x01\x81c\x00\x00\x00' >> ( 75.550) [10 01 8163 890000] b'\x10\x01\x81c\x89\x00\x00' # D0 - ? << ( 163.118) [10 01 81D0 000000] b'\x10\x01\x81\xd0\x00\x00\x00' >> ( 163.148) [10 01 81D0 000000] b'\x10\x01\x81\xd0\x00\x00\x00' # D4 - ? << ( 166.034) [10 01 81D4 000000] b'\x10\x01\x81\xd4\x00\x00\x00' >> ( 166.063) [10 01 81D4 000008] b'\x10\x01\x81\xd4\x00\x00\x08' # F1 - firmware/bootloader version << ( 187.172) [10 01 81F1 000000] b'\x10\x01\x81\xf1\x00\x00\x00' >> ( 187.199) [10 01 8F81 F10300] b'\x10\x01\x8f\x81\xf1\x03\x00' # F3 - ? << ( 188.629) [10 01 81F3 000000] b'\x10\x01\x81\xf3\x00\x00\x00' >> ( 188.661) [10 01 81F3 000000] b'\x10\x01\x81\xf3\x00\x00\x00' # FD - ? << ( 195.715) [10 01 83FD 000000] b'\x10\x01\x83\xfd\x00\x00\x00' >> ( 195.746) [11 01 83FD 00000000000000000000000000000000] b'\x11\x01\x83\xfd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' Solaar-1.1.20/docs/devices/mk700.txt000066400000000000000000000017471522022367600170030ustar00rootroot00000000000000# Enabled Notifications # 10 - battery status # 02 + 01 - remap FN keys (multimedia + power buttons) >> ( 1.412) [10 02 8100 130000] '\x10\x02\x81\x00\x13\x00\x00' << ( 0.011) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00' >> ( 0.276) [10 02 8101 000000] '\x10\x02\x81\x01\x00\x00\x00' # Battery status << ( 6.033) [10 02 8107 000000] '\x10\x02\x81\x07\x00\x00\x00' >> ( 6.344) [10 02 8107 070000] '\x10\x02\x81\x07\x07\x00\x00' # FN status << ( 8.055) [10 02 8109 000000] '\x10\x02\x81\t\x00\x00\x00' >> ( 8.144) [10 02 8109 000000] '\x10\x02\x81\t\x00\x00\x00' # ? << ( 208.316) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00' >> ( 208.353) [10 02 81D0 000000] '\x10\x02\x81\xd0\x00\x00\x00' # version info << ( 237.436) [10 02 81F1 000000] '\x10\x02\x81\xf1\x00\x00\x00' >> ( 237.744) [10 02 8F81 F10300] '\x10\x02\x8f\x81\xf1\x03\x00' # ? << ( 239.459) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00' >> ( 239.766) [10 02 81F3 000000] '\x10\x02\x81\xf3\x00\x00\x00' Solaar-1.1.20/docs/devices/performance-mx.txt000066400000000000000000000027451522022367600210670ustar00rootroot00000000000000# Notifications (r1_bit0 = battery status?) << ( 0.113) [10 01 8100 000000] '\x10\x01\x81\x00\x00\x00\x00' >> ( 0.157) [10 01 8100 100000] '\x10\x01\x81\x00\x10\x00\x00' # ? << ( 1.050) [10 01 8101 000000] '\x10\x01\x81\x01\x00\x00\x00' >> ( 1.097) [10 01 8101 020000] '\x10\x01\x81\x01\x02\x00\x00' # battery (07 means full) << ( 7.335) [10 01 8107 000000] '\x10\x01\x81\x07\x00\x00\x00' >> ( 7.382) [10 01 8107 070000] '\x10\x01\x81\x07\x07\x00\x00' # Set LEDS - ab cd 00, where a/b/c/d values are 1=off, 2=on, 3=flash # a = lower led # b = red led # c = upper led # d = middle led # below: all leds are off << ( 86.592) [10 01 8151 000000] '\x10\x01\x81Q\x00\x00\x00' >> ( 86.639) [10 01 8151 111100] '\x10\x01\x81Q\x11\x11\x00' # DPI (values in range 0x81..0x8F; logical value: 100..1500) << ( 108.430) [10 01 8163 000000] '\x10\x01\x81c\x00\x00\x00' >> ( 108.477) [10 01 8163 890000] '\x10\x01\x81c\x89\x00\x00' # ? << ( 240.505) [10 01 81D0 000000] '\x10\x01\x81\xd0\x00\x00\x00' >> ( 240.550) [10 01 81D0 000000] '\x10\x01\x81\xd0\x00\x00\x00' # ? << ( 245.690) [10 01 81D4 000000] '\x10\x01\x81\xd4\x00\x00\x00' >> ( 245.737) [10 01 81D4 000012] '\x10\x01\x81\xd4\x00\x00\x12' # Firmware/bootloader version << ( 281.016) [10 01 81F1 000000] '\x10\x01\x81\xf1\x00\x00\x00' >> ( 282.177) [10 01 8F81 F10300] '\x10\x01\x8f\x81\xf1\x03\x00' # ? << ( 284.106) [10 01 81F3 000000] '\x10\x01\x81\xf3\x00\x00\x00' >> ( 284.153) [10 01 81F3 000000] '\x10\x01\x81\xf3\x00\x00\x00' Solaar-1.1.20/docs/features.md000066400000000000000000000333241522022367600161160ustar00rootroot00000000000000--- title: List of HID++ 2.0 features layout: page --- # List of HID++ 2.0 features ## Feature status See functions in `hidpp20.py` and `settings_templates.py` Feature | ID | Status | Notes ---------------------------------------|----------|:------------------:|------ `ROOT` | `0x0000` | Supported | System `FEATURE_SET` | `0x0001` | Supported | System `FEATURE_INFO` | `0x0002` | Supported | System `DEVICE_FW_VERSION` | `0x0003` | Supported | `get_firmware`, `get_ids`, read only `DEVICE_UNIT_ID` | `0x0004` | Unsupported | `DEVICE_NAME` | `0x0005` | Supported | `get_kind`, `get_name`, read only `DEVICE_GROUPS` | `0x0006` | Unsupported | `DEVICE_FRIENDLY_NAME` | `0x0007` | Supported | `get_friendly_name`, read only `KEEP_ALIVE` | `0x0008` | Unsupported | `RESET` | `0x0020` | Unsupported | aka “Config Changeâ€� `CRYPTO_ID` | `0x0021` | Unsupported | `TARGET_SOFTWARE` | `0x0030` | Unsupported | `WIRELESS_SIGNAL_STRENGTH` | `0x0080` | Unsupported | `DFUCONTROL_LEGACY` | `0x00C0` | Unsupported | `DFUCONTROL_UNSIGNED` | `0x00C1` | Unsupported | `DFUCONTROL_SIGNED` | `0x00C2` | Unsupported | `DFU` | `0x00D0` | Unsupported | `BATTERY_STATUS` | `0x1000` | Supported | `get_battery`, read only `BATTERY_VOLTAGE` | `0x1001` | Supported | `get_voltage`, read only `UNIFIED_BATTERY` | `0x1004` | Supported | `get_battery`, read only `CHARGING_CONTROL` | `0x1010` | Unsupported | `LED_CONTROL` | `0x1300` | Unsupported | `FORCE_PAIRING` | `0x1500` | Unsupported | `GENERIC_TEST` | `0x1800` | Unsupported | `DEVICE_RESET` | `0x1802` | Unsupported | `OOBSTATE` | `0x1805` | Unsupported | `CONFIG_DEVICE_PROPS` | `0x1806` | Unsupported | `CHANGE_HOST` | `0x1814` | Supported | `ChangeHost` `HOSTS_INFO` | `0x1815` | Partial Support | `get_host_names`, partial listing only `BACKLIGHT` | `0x1981` | Supported | `Backlight` `BACKLIGHT2` | `0x1982` | Supported | `Backlight2`, ... `BACKLIGHT3` | `0x1983` | Unsupported | `PRESENTER_CONTROL` | `0x1A00` | Unsupported | `SENSOR_3D` | `0x1A01` | Unsupported | `REPROG_CONTROLS` | `0x1B00` | Unsupported | `REPROG_CONTROLS_V2` | `0x1B01` | Listing Only | `get_keys` `REPROG_CONTROLS_V2_2` | `0x1B02` | Unsupported | `REPROG_CONTROLS_V3` | `0x1B03` | Unsupported | `REPROG_CONTROLS_V4` | `0x1B04` | Partial Support | `ReprogrammableKeys`, `DivertKeys`, `MouseGesture`, `get_keys` `SUPERSTRIKE_TUNING` | `0x1B0C` | Supported | `SuperstrikeTuning` (actuation point, rapid trigger, click haptics) `REPORT_HID_USAGE` | `0x1BC0` | Unsupported | `PERSISTENT_REMAPPABLE_ACTION` | `0x1C00` | Supported | `PersistentRemappableAction` `WIRELESS_DEVICE_STATUS` | `0x1D4B` | Read only | status reporting from device `REMAINING_PAIRING` | `0x1DF0` | Unsupported | `FIRMWARE_PROPERTIES` | `0x1F1F` | Unsupported | `ADC_MEASUREMENT` | `0x1F20` | Supported | `ADCPower` `LEFT_RIGHT_SWAP` | `0x2001` | Unsupported | `SWAP_BUTTON_CANCEL` | `0x2005` | Unsupported | `POINTER_AXIS_ORIENTATION` | `0x2006` | Unsupported | `VERTICAL_SCROLLING` | `0x2100` | Supported | `get_vertical_scrolling_info`, read only `SMART_SHIFT` | `0x2110` | Supported | `SmartShift` `SMART_SHIFT_ENHANCED` | `0x2111` | Supported | `SmartShiftEnhanced` `HI_RES_SCROLLING` | `0x2120` | Supported | `HiResScroll`, `get_hi_res_scrolling_info` `HIRES_WHEEL` | `0x2121` | Supported | `HiresSmoothInvert`, `HiresSmoothResolution`, `get_hires_wheel` `LOWRES_WHEEL` | `0x2130` | Supported | `LowresSmoothScroll`, `get_lowres_wheel_status` `THUMB_WHEEL` | `0x2150` | Supported | `ThumbMode`, `ThumbInvert` `MOUSE_POINTER` | `0x2200` | Supported | `get_mouse_pointer_info`, read only `ADJUSTABLE_DPI` | `0x2201` | Supported | `AdjustableDpi`, `DpiSliding` `EXTENDED_ADJUSTABLE_DPI` | `0x2202` | Supported | `ExtendedAdjustableDpi` (X/Y DPI + lift-off distance) `POINTER_SPEED` | `0x2205` | Supported | `PointerSpeed`, `SpeedChange`, `get_pointer_speed_info` `ANGLE_SNAPPING` | `0x2230` | Unsupported | `SURFACE_TUNING` | `0x2240` | Unsupported | `XY_STATS` | `0x2250` | Unsupported | `WHEEL_STATS` | `0x2251` | Unsupported | `HYBRID_TRACKING` | `0x2400` | Unsupported | `FN_INVERSION` | `0x40A0` | Supported | `FnSwap` `NEW_FN_INVERSION` | `0x40A2` | Supported | `NewFnSwap`, `get_new_fn_inversion `K375S_FN_INVERSION` | `0x40A3` | Supported | `K375sFnSwap` `ENCRYPTION` | `0x4100` | Unsupported | `LOCK_KEY_STATE` | `0x4220` | Unsupported | `SOLAR_DASHBOARD` | `0x4301` | Unsupported | `KEYBOARD_LAYOUT` | `0x4520` | Unsupported | read only `KEYBOARD_DISABLE_KEYS` | `0x4521` | Supported | `DisableKeyboardKeys` `KEYBOARD_DISABLE_BY_USAGE` | `0x4522` | Unsupported | `DUALPLATFORM` | `0x4530` | Supported | `Dualplatform`, untested `MULTIPLATFORM` | `0x4531` | Supported | `Multiplatform` `KEYBOARD_LAYOUT_2` | `0x4540` | Unsupported | read only `CROWN` | `0x4600` | Supported | `DivertCrown`, `CrownSmooth` `TOUCHPAD_FW_ITEMS` | `0x6010` | Unsupported | `TOUCHPAD_SW_ITEMS` | `0x6011` | Unsupported | `TOUCHPAD_WIN8_FW_ITEMS` | `0x6012` | Unsupported | `TAP_ENABLE` | `0x6020` | Unsupported | `TAP_ENABLE_EXTENDED` | `0x6021` | Unsupported | `CURSOR_BALLISTIC` | `0x6030` | Unsupported | `TOUCHPAD_RESOLUTION` | `0x6040` | Unsupported | `TOUCHPAD_RAW_XY` | `0x6100` | Unsupported | `TOUCHMOUSE_RAW_POINTS` | `0x6110` | Unsupported | `TOUCHMOUSE_6120` | `0x6120` | Unsupported | `GESTURE` | `0x6500` | Unsupported | `GESTURE_2` | `0x6501` | Partial Support | `Gesture2Gestures`, `Gesture2Params` `GKEY` | `0x8010` | Partial Support | `DivertGkeys` `MKEYS` | `0x8020` | Supported | `MkeyLEDs` `MR` | `0x8030` | Supported | `MRKeyLED` `BRIGHTNESS_CONTROL` | `0x8040` | Supported | `BrightnessControl` `REPORT_RATE` | `0x8060` | Supported | `ReportRate` `EXTENDED_ADJUSTABLE_REPORT_RATE` | `0x8061` | Supported | `report_rate_extended` (sub-millisecond polling up to 8000 Hz) `COLOR_LED_EFFECTS` | `0x8070` | Supported | `LEDControl`, `LEDZoneSetting` `RGB_EFFECTS` | `0X8071` | Supported | `RGBControl`, `RGBEffectSetting` `PER_KEY_LIGHTING` | `0x8080` | Unsupported | `PER_KEY_LIGHTING_V2` | `0x8081` | Supported | `PerKeyLighting` `MODE_STATUS` | `0x8090` | Unsupported | `ONBOARD_PROFILES` | `0x8100` | Supported | `MOUSE_BUTTON_SPY` | `0x8110` | Unsupported | `LATENCY_MONITORING` | `0x8111` | Unsupported | `GAMING_ATTACHMENTS` | `0x8120` | Unsupported | `FORCE_FEEDBACK` | `0x8123` | Unsupported | `SIDETONE` | `0x8300` | Supported | `Sidetone` `EQUALIZER` | `0x8310` | Supported | `Equalizer` `HEADSET_OUT` | `0x8320` | Unsupported | A “read onlyâ€� note means the feature is a read-only feature. ## Implementing a feature Features are implemented as settable features in `lib/logitech_receiver/settings_templates.py`. Some features also have direct implementation in `lib/logitech_receiver/hidpp20.py`. In most cases it should suffice to only implement the settable feature interface for each setting in the feature. That will add one or more widgets in the Solaar main window to show and change the setting, will permit storing and restoring changed settings, and will output the feature settings in `solaar show`. A setting implementation is a subclass of one of the built-in setting classes illustrated by the pointer speed setting implementation. ```python class PointerSpeed(_Setting): name = 'pointer_speed' label = _('Sensitivity (Pointer Speed)') description = _('Speed multiplier for mouse (256 is normal multiplier).') feature = _F.POINTER_SPEED validator_class = _RangeV min_value = 0x002e max_value = 0x01ff validator_options = {'byte_count': 2} ``` A setting implementation needs a name, a label, and a description. The name is used in the persistent settings structure to store and restore changed settings and should be a valid Python identifier. (Some older settings have dashes.) The label is displayed in the Solaar main window and the description is used as a tooltip there. The label and description should be specified as translatable strings. A setting implementation for a feature (for modern devices that use the HID++ 2.0 protocol) needs a feature identifier. A setting implementation needs a reader/writer and a validator. The reader/writer is responsible for actually writing settings to the device and reading them from the device, writing and reading the byte strings that represent the setting values on the device. For most feature settings the setting implementation can just inherit the standard feature reader/writer, `FeatureRW`. Options for `FeatureRW` are supplied by the `rw_options` class variable, which is used to provide command numbers for reading and writing as well as other information needed to identify the parts of the command and response that hold the setting value and modify the reading and writing procedure. `PointerSpeed` uses the defaults; here is an example of specifying non-default commands for reading and writing: ``` rw_options = {'read_fnid': 0x10, 'write_fnid': 0x20} ``` Some old devices use registers instead and the setting needs to use the register reader/writer. Only implement a register interface for the setting if you are very brave and you have access to a device that has a register interface for the setting. Register interfaces cannot be auto-discovered and need to be stated in descriptors.py for each device with the register interface. The validator instance is responsible for turning raw values read from the device into Python data and Python data into raw values to be written to the device and validating that the Python data is acceptable for the setting. There are several possible kinds of Python data for setting interfaces, ranging from simple toggles, to ranges, to fixed lists, to dynamic choices, to maps of dynamic choices. Pointer speed is a setting whose values are integers in a range so _RangeV validator is used. Arguments to validators are specified as class variables. The _RangeV validator requires the minimum and maximum for the value as separate class variables and the byte size of the value on the device as part of `validator_options`. Splitting the minimum and maximum makes it easier for code that works with settings to determine this information. Settings that are toggles or choices work similarly, but their validators have different arguments. Map settings have more complicated validators and more arguments. Settings where the acceptable values are determined from the device subclass the validator and provide a build class method that queries the device and creates an instance of the validator. This method can also return `None`, indicating that even though the device implements the feature it does not usefully support the setting. Settings need to be added to the `SETTINGS` list so that setting discovery can be done. For more information on implementing feature settings see the comments in `lib/logitech_receiver/settings_templates.py`. Solaar-1.1.20/docs/hidpp-documentation.txt000066400000000000000000000002061522022367600204630ustar00rootroot00000000000000Documentation on HID++ can be found in the Google drive directory https://drive.google.com/drive/folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28 Solaar-1.1.20/docs/i18n.md000066400000000000000000000070761522022367600150640ustar00rootroot00000000000000--- title: Translating Solaar layout: page --- # Translating Solaar First, make sure you have installed the `gettext` package. Also, you would need to install language pack for Gnome for your language, e.g. `language-pack-gnome-XX-base` for Debian/Ubuntu. Here are the steps to add/update a translation (you should run all scripts from the source root): 1. Get an up-to-date copy of the source files. Preferably, make a fork on GitHub and clone it locally on your machine; this way you can later make a pull request to the main project. 2. Run `./tools/po-update.sh `; it will create/update the file `./po/.po`. 3. Edit `./po/.po` with your favorite editor (just make sure it saves the file with the UTF-8 encoding). For each string in English (msgid), edit the translation (msgstr); if you leave msgstr empty, the string will remain untranslated. Alternatively, you can use the excellent [Poedit](https://poedit.net/) or [Lokalize](https://apps.kde.org/lokalize/). 4. Run `./tools/po-compile.sh`. It will bring up-to-date all the compiled language files, necessary at runtime. 5. Start Solaar (`./bin/solaar`). By default, it will pick up the system language from your environment; to start it in another language, run `LANGUAGE= ./bin/solaar`. To edit the translation iteratively, just repeat from step 3. If the upstream changes, do a `git pull` and then repeat from step 2. Before opening a pull request, please run `./tools/po-update.sh ` again. This will format and sort the translation file, and ensure a minimal diff when updating a translation. ## Supported languages Some of the languages Solaar has been translated to are listed below. A full list of available translations can be obtained by checking the `/po` folder for translation files. - Chinese (Simplified): [Rongrong][Rongronggg9] - Chinese (Taiwan): Peter Dave Hello - Czech: Marián Kyral - Croatian: gogo - Danish: John Erling Blad - Dutch: Heimen Stoffels - Français: [Papoteur][papoteur], [David Geiger][david-geiger], [Damien Lallement][damsweb] - Finnish: Tomi Leppänen, [Niko Savola][nikosavola] - German: Daniel Frost - Greek: Vangelis Skarmoutsos - Indonesia: [Ferdina Kusumah][feku] - Italiano: [Michele Olivo][micheleolivo], Lorenzo - Japanese: Ryunosuke Toda - Norsk (BokmÃ¥l): [John Erling Blad][jeblad] - Norsk (Nynorsk): [John Erling Blad][jeblad] - Polski: [Adrian Piotrowicz][nexces], Matthaiks - Portuguese: Américo Monteiro - Portuguese-BR: [Drovetto][drovetto], [Josenivaldo Benito Jr.][jrbenito], Vinícius - Română: Daniel Pavel - Russian: [Dimitriy Ryazantcev][DJm00n], Anton Soroko - Serbian: [Renato Kaurić][renatoka] - Slovak: [Jose Riha][jose1711] - Spanish, Castilian: Jose Luis Tirado - Swedish: John Erling Blad, [Daniel Zippert][zipperten], Emelie Snecker, Jonatan Nyberg - Turkish: Osman Karagöz - Ukrainian: ОлекÑ�андр Ð�фанаÑ�ьєв - Bulgarian Ð�иколай Йорданов - Irish: Aindriú Mac Giolla Eoin [Rongronggg9]: https://github.com/Rongronggg9 [papoteur]: https://github.com/papoteur [david-geiger]: https://github.com/david-geiger [damsweb]: https://github.com/damsweb [DJm00n]: https://github.com/DJm00n [jose1711]: https://github.com/jose1711 [nexces]: https://github.com/nexces [zipperten]: https://github.com/zipperten [micheleolivo]: https://github.com/micheleolivo [drovetto]: https://github.com/drovetto [jrbenito]: https://github.com/jrbenito [jeblad]: https://github.com/jeblad [feku]: https://github.com/FerdinaKusumah [renatoka]: https://github.com/renatoka [nikosavola]: https://github.com/nikosavola Solaar-1.1.20/docs/img/000077500000000000000000000000001522022367600145255ustar00rootroot00000000000000Solaar-1.1.20/docs/img/favicon.ico000066400000000000000000000033541522022367600166530ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs A Anäk±tEXtSoftwarewww.inkscape.org›î<iIDATX…½W[p[W]ç>$Y’õp-[¾òCN�'~G±›¸¡5‰ChÊL€a(ÓÒòÁ4|” e 䋘0�†v€á#a&‰Ó¦¡©'Nbc'–‹D±,[J$+¶dYï+ÝÇ-UrõCÞ¹3÷ì½Î>kß9w�}6Í`0¨S»º^K×7Ø$_O9ž „‚l‚èæ èæ;Í‹ HcfGÈޤE‰Ä“ÎëŸ�Ùo½"ÓèºövˆÛw¼ØMY–‚ä¦(˜ì*Øð1yH.NAÝ ½‰Ë>ys‰”†êÝQ'?ûï—ƒ““Ólmmmu²×v&ºÿÀ0L¶€äUþ‘ecãì;)ô‘"sY†¦v˜õÜZäIíÿ_Y¾wðõÈÐÐÁ0… >.›�h6Õp¾#Ö×õS–EY“$(&nºu|ç"‰H¥`Ìú:Õýîí*®My!•„(ÏÑ´ÐÐÃQ…ÜXȻܡª›7Ï+]w~ès:WÔ õ—"ÃÏôÃ*?¼1ºúÁ—ŒËÞ'â.÷q[çÓ©ífuIJEBd%+ ¯C=rñ×áwÏ}ÓçtH²ÅÅ_po|+–óÜ�ËæO�|Ng`mäü·Tgß;Ŭ­“�gÞ49S®zIS q{ëQ\Ö·:>vAymârî/ÌV}òòêøø…<+¶}ê�¤­.n-²\¢ýûz4ƒC' &-Þÿ�ÜîðgÇŠ[·*|®Wó1úýƒ'bƒ¶Ý•òs•TYq‡å«¦eëo¼Ç „æ¦Ü:¡îm.¸2Pð,ÿkæ^vŽÉj}"Øþé/K*e¥ô• @¼»Ëq{Þ€ÃñBÖº4òãRøHcó/c¶nr2ù?à ±§ýóú¥¥ÝA‡Ý†�]¢Vó,* ¯ž]ž�½ú¶¶öXOÇPNÔ>Xïƒ%Ypy^edWçéP_×�hn’ƒEFæ^zYÓÔrI33ý¢¸ºêJz}ìlµþ׸û¾÷0ûH½è†~Ó äó ðûýQÍÐÑ¿¬;úʳH @ÊÒ¬· Gœ _8÷õšy×[ô†ò%, Î ¡ŽÍ‚¬(¹cnŒ{ÿêñ­, ah0´2ììè õt SNÊq41Ðù”þÎÒîÕ«£§´³‹+VqfØvZ4 ¶¢Àimm1Xês‰Zݳ¢©Q S,ž²4ËU‚öæa/•GÍì+ÐèGÛ)�Ñ ¿€D­¶Y¿DCC¡…^;Ë{–¾'š›«Š%“9“x°rŠå€ŒD Š. �´¶õgjkg‹mBýÍÙŸn|ø[�`:Ÿn4=Ge…û€ˆi¢›º¼77£ïòÛ‰îöWJmÂ’Ò‚Q�Œªb‰DŸ¯wßù?wëy4ÞÛyHÜÖ¤dNwB1>õžfvæ%¹Á ŽZ,߈ïíÖëˆrÝS1å,ÓÐДÒ×Yü»Ïq½Ó½‡6Ô�ûËg‚ó{B”i4š5ï£�$(ìödU‚®™i¸0½œ››Ñ6¶\LZ-Ï�­¼Ç‰@ÕäÔ‚zÑõ£µ<Ÿî™Ã?êr‡QèÒÈkÙ˜ziá„x}Òè*å®H‘Äâ�9œoeOBÐY;Íñ]Öãѧö÷DèN´[¿fè´mÏÆ½ÇŠ|fîÏL4V±¸ŠTWÇ&ÖFß?™ï˘M¿J¶·ÕgljŽ�µISÝOò1ÁÑÑ“Ê+×í¨`e 0áuðÎ{礳¾š¾þḭ÷`Ag fëþLM_ßp>O~îÞŲ-”¦J%M5"‡}WóÙÏ�6¶¶0©ææWÒ�¦� QºQ¨J™-ßÀ[[ ÚÃG~=6ôbÙ–Œ"É‘DÒÀR #nkщۚ¾’šœî×Õ5:Â{{Kacövë¼¾¿‡ö´µ&lX¦àŸßj$–Xæx¿oŒd2”+s7`$z;[½�Í9q*bRu5 ½püà*¾¸˜&œ×7Ájbá1pò#bK‹ñÿy3R�\q*¯Ýx‰�Åb)•\q��D÷¥M¦úÜí1 é4Q�\¹Ëß¾û�‡wïzraƒÁ NY»_M õû$9o¤¼ì“½ž‹¢D©eÎãWܾýs¿ß€ÿ3GÁÍÈÅ©†IEND®B`‚Solaar-1.1.20/docs/img/favicon.png000066400000000000000000000033541522022367600166650ustar00rootroot00000000000000‰PNG  IHDR szzôsBIT|dˆ pHYs A Anäk±tEXtSoftwarewww.inkscape.org›î<iIDATX…½W[p[W]ç>$Y’õp-[¾òCN�'~G±›¸¡5‰ChÊL€a(ÓÒòÁ4|” e 䋘0�†v€á#a&‰Ó¦¡©'Nbc'–‹D±,[J$+¶dYï+ÝÇ-UrõCÞ¹3÷ì½Î>kß9w�}6Í`0¨S»º^K×7Ø$_O9ž „‚l‚èæ èæ;Í‹ HcfGÈޤE‰Ä“ÎëŸ�Ùo½"ÓèºövˆÛw¼ØMY–‚ä¦(˜ì*Øð1yH.NAÝ ½‰Ë>ys‰”†êÝQ'?ûï—ƒ““Ólmmmu²×v&ºÿÀ0L¶€äUþ‘ecãì;)ô‘"sY†¦v˜õÜZäIíÿ_Y¾wðõÈÐÐÁ0… >.›�h6Õp¾#Ö×õS–EY“$(&nºu|ç"‰H¥`Ìú:Õýîí*®My!•„(ÏÑ´ÐÐÃQ…ÜXȻܡª›7Ï+]w~ès:WÔ õ—"ÃÏôÃ*?¼1ºúÁ—ŒËÞ'â.÷q[çÓ©ífuIJEBd%+ ¯C=rñ×áwÏ}ÓçtH²ÅÅ_po|+–óÜ�ËæO�|Ng`mäü·Tgß;Ŭ­“�gÞ49S®zIS q{ëQ\Ö·:>vAymârî/ÌV}òòêøø…<+¶}ê�¤­.n-²\¢ýûz4ƒC' &-Þÿ�ÜîðgÇŠ[·*|®Wó1úýƒ'bƒ¶Ý•òs•TYq‡å«¦eëo¼Ç „æ¦Ü:¡îm.¸2Pð,ÿkæ^vŽÉj}"Øþé/K*e¥ô• @¼»Ëq{Þ€ÃñBÖº4òãRøHcó/c¶nr2ù?à ±§ýóú¥¥ÝA‡Ý†�]¢Vó,* ¯ž]ž�½ú¶¶öXOÇPNÔ>Xïƒ%Ypy^edWçéP_×�hn’ƒEFæ^zYÓÔrI33ý¢¸ºêJz}ìlµþ׸û¾÷0ûH½è†~Ó äó ðûýQÍÐÑ¿¬;úʳH @ÊÒ¬· Gœ _8÷õšy×[ô†ò%, Î ¡ŽÍ‚¬(¹cnŒ{ÿêñ­, ah0´2ììè õt SNÊq41Ðù”þÎÒîÕ«£§´³‹+VqfØvZ4 ¶¢Àimm1Xês‰Zݳ¢©Q S,ž²4ËU‚öæa/•GÍì+ÐèGÛ)�Ñ ¿€D­¶Y¿DCC¡…^;Ë{–¾'š›«Š%“9“x°rŠå€ŒD Š. �´¶õgjkg‹mBýÍÙŸn|ø[�`:Ÿn4=Ge…û€ˆi¢›º¼77£ïòÛ‰îöWJmÂ’Ò‚Q�Œªb‰DŸ¯wßù?wëy4ÞÛyHÜÖ¤dNwB1>õžfvæ%¹Á ŽZ,߈ïíÖëˆrÝS1å,ÓÐДÒ×Yü»Ïq½Ó½‡6Ô�ûËg‚ó{B”i4š5ï£�$(ìödU‚®™i¸0½œ››Ñ6¶\LZ-Ï�­¼Ç‰@ÕäÔ‚zÑõ£µ<Ÿî™Ã?êr‡QèÒÈkÙ˜ziá„x}Òè*å®H‘Äâ�9œoeOBÐY;Íñ]Öãѧö÷DèN´[¿fè´mÏÆ½ÇŠ|fîÏL4V±¸ŠTWÇ&ÖFß?™ï˘M¿J¶·ÕgljŽ�µISÝOò1ÁÑÑ“Ê+×í¨`e 0áuðÎ{礳¾š¾þḭ÷`Ag fëþLM_ßp>O~îÞŲ-”¦J%M5"‡}WóÙÏ�6¶¶0©ææWÒ�¦� QºQ¨J™-ßÀ[[ ÚÃG~=6ôbÙ–Œ"É‘DÒÀR #nkщۚ¾’šœî×Õ5:Â{{Kacövë¼¾¿‡ö´µ&lX¦àŸßj$–Xæx¿oŒd2”+s7`$z;[½�Í9q*bRu5 ½püà*¾¸˜&œ×7Ájbá1pò#bK‹ñÿy3R�\q*¯Ýx‰�Åb)•\q��D÷¥M¦úÜí1 é4Q�\¹Ëß¾û�‡wïzraƒÁ NY»_M õû$9o¤¼ì“½ž‹¢D©eÎãWܾýs¿ß€ÿ3GÁÍÈÅ©†IEND®B`‚Solaar-1.1.20/docs/img/solaar.svg000066400000000000000000000072651522022367600165410ustar00rootroot00000000000000 image/svg+xml Solaar-1.1.20/docs/implementation.md000066400000000000000000000403221522022367600173210ustar00rootroot00000000000000--- title: Solaar Implementation layout: page --- # Solaar Implementation Solaar has three main components: code mostly about receivers and devices, code for the command line interface, and code for the graphical user interface. The following graph shows the main components of Solaar and how they interact. ```mermaid graph TD subgraph User interface U[UI] C[CLI] end subgraph Core U --> S{Solaar} C --> S S --> L[Logitech receiver] L --> R[Receiver] L --> D[Device] S --> B[dbus] end subgraph Hardware interface R --> A D --> A A[hidapi]--> P[hid parser] end subgraph Peripherals P <-.-> M[Logitech mouse] P <-.-> K[Logitech keyboard] end ``` ## Receivers and Devices The code in `logitech_receiver` is responsible for creating and maintaining receiver (`receiver/Receiver`) and device (`device/Device`) objects for each device on the computer that uses the Logitech HID++ protocol. These objects are discovered in Linux by interacting with the Linux `udev` system using code in `hidapi`. The code in `logitech_receiver/receiver' is responsible for receiver objects. ... The code in `logitech_receiver/device' is responsible for device objects. ... the complex device setup process A device object stores the currrent value of many aspects of the device. It provides methods for retrieving and setting these aspects. The setters generally store the new value and call an hidpp10 or hidpp20 function to modify the device accordingly. The retrievers generally check whether the value is cached on the device if so just returning the cached value and if not calling an hidpp10 or hidpp20 function to retrieve the value and returning the value after caching it. ... Not all communication with a device is done through the `Device` class. Some is done directly from settings. .... ### HID++ #### HID++ 2.0 The code in `logitech_receiver/hidpp20' interacts with devices using the HID++ 2.0 (and greater) protocol. Many of the functions in this module send messages to devices to modify their internal state, for example setting a host name stored in the device. Many other functions send messages to devices that query their internal state and interpret the response, for example returning how often a mouse sends movement reports. The result of these latter functions are generally cached in device objects. A few of these functions create and return a large structure or a class object. The HID++ 2.0 protocol is built around a number of features, each with its own functionality. One of the features, that is required to be implemented by all devices supporting the protocol, provide information on which features the device provides. The `hidpp20` module provides a class (`FeaturesArray`) to store information on what features are provided by a device and how to access them. Each device that implements the HID++ 2.0 protocol has an instance of this class. The heavily used function `feature_request` creates an HID++ 2.0 message using this information to help determine what data to put into the message. Many devices allow reprogramming some keys or buttons. One the main reasons for reprogramming a key or device is to cause it to produce an HID++ message instead of its normal HID message, this is referred to as diverting the key (to HID++). The `ReprogrammableKey` class stores information about the reprogramming of one key for one version of this capability, with methods to access and update this information. The `PersistentRemappableAction` class does the same for another version. The `KeysArray` class stores information about the reprogramming of a collection of keys, with methods to access this information. Functions in the Device class request `KeysArray` information for a device when appropriate and store it on the device. Many pointing devices provide a facility for recognizing gestures and sending an HID message for the gesture. The `Gesture` class stores inforation for one gesture and the `Gestures` class stores information for all the gestures on a device. Functions in the Device class request `KeysArray` information and store it on devices. Functions in the Device class request `Gestures` information for a device when appropriate and store it on the device. Many gaming devices provide an interface to controlling their LEDs by zone. The `LEDEffectSetting` class stores the current state of one zone of LEDs. This information can come directly from an LED feature but is also part of Onboard Profiles so this class provides a byte string interface. Solaar stores this information in YAML so this class provides a YAML interface. The `LEDEffectsInfo` class stores information about what LED zones are on a device and what effects they can perform and provides a method that builds an object by querying a device. Many gaming devices can be controlled by selecting one of their Onboard Profiles. An Onboard Profile sets up the rate at which the device reports movement, a set of sensitivites of its movement detector, a set of actions to be performed by mouse buttons or G and M keys, and effects for up to two LED zones. The `Button` class stores information about a button or key action. The `OnboardProfile` class stores a single profile, using the `LEDEffectSetting` and `Button` classes. Because retrieving and changing a profile is complex, this class provides a byte string interface. Because Solaar dumps profiles from devices as YAML documents and loads them into devices from YAML documents, this class provides a YAML interface. The `OnboardProfiles` class class stores the entire profiles information for a device. It provides an interface to construct an `OnboardProfiles` object by querying a device. Because Solaar dumps profiles from devices as YAML documents and loads them into devices from YAML documents, these classes also provide a YAML interface. #### HID++ 1.0 The code in `logitech_receiver/hidpp10' interacts with devices using the HID++ 1.0 protocol. ... ### Low Level Information and Access The module `descriptors` sets up information on device models for which Solaar needs information to support. Solaar can determine all this information for most modern devices so it is only needed for older devices or devices that are unusual in some way. The information may include the name of the device model, short name of the device model, the HID++ protocol used by the device model, HID++ registers supported by the device model, various identifiers for the device model, and the USB interface that the device model uses for HID++ messages. It used to include the HID++-based settings for the device model but this information is now added in `setting_templates`. The information about a device model can be retrieved in several ways. The module `base_usb` sets up information for most of the receiver models that Solaar supports, including USB id, USB interface used for HID++ messages, what kind of receiver model it is, and some capabilities of the receiver model. Solaar can now support other receivers as long as they are not too unusual. The module lso sets up lists of device models by USB ID and Bluetooth ID and provides a function to determine whether a USB ID or Bluetooth ID is an HID++ device model The module `base` provides functions that call discovery to enumerate all current receivers and devices and to set up a callback for when new receivers or devices are discovered. It provides functions to open and close I/O channels to receivers and devices, write HID++ messages to receivers and devices, and read HID++ messages from receivers and devices. It provides a function to turn an HID++ message into a notification. The module provides a function to send an HID++ message to a receiver or device, constructing the message from parameters to the function, and optionally waiting for and returning a response. The function checks messages from the receiver or device, only terminating at timeout or when a message that appears to be the response is seen. Other messages are turned into notifications if appropriate and ignoreed otherwise. A separate function sends a ping message and waits for a reply to the ping. ### Notifications and Status HID++ devices not only respond to commands but can spontaneously emit HID++ messages, such as when their movement sensitivity changes or when a diverted key is pressed. These spontaneous messages are called notifications and if software is well behaved can be distinguished from messages that are responses to commands. (The Linux HIDPP driver was not well behaved at some time and still may not be well behaved, resulting in it causing devices to send responses that cannot be distinguished from notifications.) The `listener` module provides a class to set up a thread that listens to all the HID++ messages that come from a given device or receiver, convert the message that are notifications to a Solaar notification structure, and invoke a callback on the notification. The 'notifications` module provides a function to take a notification from a receiver or device and initiate processing required for that notification. For receivers notifications are used to signal the progress of pairing attempts. For devices some notifications are for pairing, some signal device connection and diconnection from a receiver, some are other parts of the HID++ 1.0 protocol, and some are for the HID++ 2.0 protocol. Devices can provide a callback for special handling of notifications. This facility is used for two special kinds of Solaar settings. The module contains code that determines the meaning of a notification based on fields in the notification and the status and HID++ 2.0 features of the device if appropriate and updates the device and its status accordingly. Updates to device status can trigger updates to the Solaar user interface. The processing of some notifications also directly runs a function to update the Solaar user interface. After this processing HID++ 2.0 notifications are sent to the `diversion` module where they initiate Solaar rule processing. The `status` module provides the `DeviceStatus` class to record the battery status of a device. It also provides an interface to signal changes to the connection status of the device that can invoke a callback. This callback is used to update the Solaar user interface when the status changes. ### Settings The Solaar GUI is based around settings. A setting contains all the information needed to store the value of some aspect of a device, read it from the device, write it to the device, and record its state in a dictionary. A setting also contains information to display and manipulate a setting, namely what kind of user interface element to use, what values are permissable, a label to use for the setting, and a tooltip to provide additional information for the setting. Settings can be either based on HID++ 1.0, using an HID++ 1.0 register that the device provides, or based on HID++ 2.0, using an HID++ 2.0 feature that the device provides. The module `settings` provides classes and methods to create and support a setting. The module `setting_templates` contains all the settings that Solaar supports as well as functions to determine what feature-based settings a device can support. A simple boolean setting can be set up as follows: ``` class HiresSmoothInvert(_Setting): name = 'hires-smooth-invert' label = _('Scroll Wheel Direction') description = _('Invert direction for vertical scroll with wheel.') feature = _F.HIRES_WHEEL rw_options = {'read_fnid': 0x10, 'write_fnid': 0x20} validator_options = {'true_value': 0x04, 'mask': 0x04} ``` The setting is a boolean setting, the default for settings. `name` is the dictionary key for recording the state of the setting. `label` is the label to be shown for the setting in a user interface and `description` is the tooltip. `feature` is the HID++ 2.0 feature that is used to read the current state of the setting from a device and write it back to a device. `rw_options` contains options used when reading or writing the state of the setting, here to use feature command 0x10 to read the value and feature command 0x20 to write the value. `validator_options` contains options to turn setting values into bytes and bytes into setting values. The options here to take a single byte (the default) and mask it with 0x04 to get a value with a result of 0x04 being true and anything else being false. They also say to use 0x04 when writing a true value and 0x00 (the default) when writing a false value. Because this is a boolean setting and the mask masks off part of a byte the value to be written is or'ed with the byte read for the setting before writing to the device. A simple choice setting can be set up as follows: ``` class Backlight(_Setting): name = 'backlight-qualitative' label = _('Backlight') description = _('Set illumination time for keyboard.') feature = _F.BACKLIGHT choices_universe = _NamedInts(Off=0, Varying=2, VeryShort=5, Short=10, Medium=20, Long=60, VeryLong=180) validator_class = _ChoicesV validator_options = {'choices': choices_universe} ``` This is a choice setting because of the value for `validator_class`. `choices_universe` is all the possible stored values for the setting along with how they are to be displayed in a user interface. `validator_options` provides the current permissable choices, here always are the same as all the choices. The Solaar GUI takes these settings and constructs an interface for displaying and changing the setting. This setup allows for very quick implementation of simple settings but it bypasses the data stored in a device object. ### Solaar Rules The `diversion` module (so-named because it initially mostly handled diverted key notifications) implements Solaar rules. ... ### Utility Functions, Structures, and Classes The module `common.py` provides utility functions, structures, and classes. `crc16` is a function to compute checksums used in profiles. `NamedInt`, `NamedInts`, and `UnsortedNamedInts` provide integers and sets of integers with attached names. `FirmwareInfo` provides information about device firmware. `BATTERY_APPROX` provides named integers used for approximate battery levels of devices. `i18n.py` provides a few strings that need translations and might not otherwise be visible to translation software. `special_keys.py` provides named integers for various collections of key codes and colors. ## Discovery of HID++ Receivers and Devices and I/O The code in `hidapi` is responsible for discovery of receivers and devices that use the HID++ protocol. The module used in Linux is `hidapi/udev` which is a modification of some old Python code that provides an interface to the Linux `udev` system. The code originally was only for receivers that used USB and devices paired with them. It identifies HID++ receivers by their USB ids, based on a list of Logitech HID++ receivers with their USB ids. It then added all devices that were paired with them and that were in a list of HID++ devices with their WPID. A WPID is used to identify the device type for devices paired with HID++ receivers. This code now also adds all devices paired with HID++ receivers whether they are in this list or not. The code now also identifies HID ++ devices that are directly connected via either USB or Bluetooth. These devices are recognized by several means: the internal list of HID++ devices for elements of the list that have either a USB IS or a Bluetooth ID, any device with a USB ID or Bluetooth ID that falls in one of several ranges of IDs that are known to support HID++, or any device that has an HID protocol descriptor that claims support for HID++. This last method requires an external Pyshon module to decipher HID protocol descriptors that is not always present. Device and receiver discovery is performed when Solaar starts. While the Solaar GUI is running the `udev` code also listens for connections of new hardware using facilities from `GLib`. This code is also responsible for actual writing data to devices and receivers and reading data from them. ## Solaar ### Startup and Commonalities __init__.py configuration.py gtk.py* i18n.py listener.py tasks.py upower.py The files `version` and `commit` contain data about the current version and git commit of Solaar. ### Solaar Command Line Interface solaar/cli ### Solaar (Graphical) User Interface solaar/ui Solaar-1.1.20/docs/index.md000066400000000000000000000205301522022367600154020ustar00rootroot00000000000000--- title: Solaar layout: default --- **Solaar** is a Linux manager for many Logitech keyboards, mice, and trackpads that connect wirelessly to a USB [Unifying][unifying], Bolt, Lightspeed, or Nano receiver; connect directly via a USB cable; or connect via Bluetooth. Solaar does not work with peripherals from other companies. Documentation here is for the current version of Solaar. Some Linux distributions distribute old versions of Solaar. If you are using an old version and something described here does not work you should upgrade using one of the methods described below. Solaar runs as a regular user process, albeit with direct access to the Linux interface that lets it directly communicate with the Logitech devices it manages using special Logitech-proprietary (HID++ and Centurion) commands. Each Logitech device implements a different subset of these commands. Solaar is thus only able to make the changes that a particular device supports. Note: Support for Centurion devices is new and should be considered experimental. Solaar is not a device driver and does not process normal input from devices. It is thus unable to fix problems that arise from incorrect handling of mouse movements or keycodes by Linux drivers or other software. Solaar can be used as a GUI application, the usual case, or via its command-line interface. The Solaar GUI is meant to run continuously in the background, monitoring devices, making changes to them, and responding to some messages they emit. To this end, it is useful to have Solaar start at user login so that changes made to devices by Solaar are applied at login and throughout the user's session. Both Solaar interfaces are able to list the connected devices and show information about each device, often including battery status. Solaar is able to pair and unpair devices with receivers as supported by the device and receiver. Solaar can also control some changeable settings of devices, such as scroll wheel direction and function key behavior. Solaar keeps track of most of these settings on a per-computer basis, because devices forget most settings when powered down, and the GUI application restores them whenever a device connects. For more information on how to use Solaar see [the usage page](https://pwr-solaar.github.io/Solaar/usage), and for more information on its capabilities see [the capabilities page](https://pwr-solaar.github.io/Solaar/capabilities). Solaar's GUI normally uses an icon in the system tray and starts with its main window visible. This aspect of Solaar depends on having an active system tray, which is not the default situation for recent versions of Gnome. For information on how to set up a system tray under Gnome see [the capabilities page](https://pwr-solaar.github.io/Solaar/capabilities). Solaar's GUI can be started in several ways - `--window=show` (the default) starts with its main window visible, - `--window=hide` starts with its main window hidden, - `--window=only` does not use the system tray, and starts with main window visible. For more information on Solaar's command-line interface use the help option, as in `solaar --help`. Solaar has progressed past version 1.1. Problems with earlier versions should not be reported as bugs. Instead, upgrade to a recent version or manually install the current version from [GitHub](https://github.com/pwr-Solaar/Solaar). Some capabilities of Solaar have been developed by observing the behavior of Logitech receivers and devices and generalizing from these observations. If your Logitech receiver or device behaves strangely this may be caused by an incorrect behavior generalization. Please report such experiences by creating an issue in [the Solaar repository](https://github.com/pwr-Solaar/Solaar/issues). [unifying]: https://en.wikipedia.org/wiki/Logitech_Unifying_receiver ## Supported Devices Solaar will detect all devices paired with supported Unifying, Bolt, Lightspeed, or Nano receivers, and at the very least display some basic information about them. Solaar will detect many Logitech devices that connect via a USB cable or Bluetooth. Solaar can pair and unpair a Logitech device showing the Unifying logo (Solaar's version of the [logo][logo]) with any Unifying receiver, and pair and unpair a Logitech device showing the Bolt logo with any Bolt receiver, and can pair and unpair Lightspeed devices with Lightspeed receivers for the same model. Solaar can pair some Logitech devices with Logitech Nano receivers, but not all Logitech devices can be paired with Nano receivers. Logitech devices without a Unifying or Bolt logo generally cannot be paired with Unifying or Bolt receivers. Solaar does not handle connecting or disconnecting via Bluetooth, which is done using the usual Bluetooth mechanisms. For a partial list of supported devices and their features, see [the devices page](https://pwr-solaar.github.io/Solaar/devices). [logo]: https://pwr-solaar.github.io/Solaar/img/solaar.svg ## Prebuilt packages Up-to-date prebuilt packages are available for some Linux distros (e.g., Fedora 33+) in their standard repositories. If a recent version of Solaar is not available from the standard repositories for your distribution, you can try one of these packages. - Arch solaar package in the [extra repository][arch] - Ubuntu/Kubuntu package in [Solaar stable ppa][ppa2] - NixOS Flake package in [Svenum/Solaar-Flake][nix flake] Solaar is available from some other repositories but they may be several versions behind the current version. - for Ubuntu/Kubuntu 16.04+: the solaar package from [universe repository][universe repository] - a [Gentoo package][gentoo], courtesy of Carlos Silva and Tim Harder - a [Mageia package][mageia], courtesy of David Geiger Solaar uses a standard system tray implementation; solaar-gnome3 is no longer required for Gnome or Unity integration. [ppa4]: https://launchpad.net/~trebelnik-stefina [ppa2]: https://launchpad.net/~solaar-unifying/+archive/ubuntu/stable [arch]: https://www.archlinux.org/packages/extra/any/solaar/ [gentoo]: https://packages.gentoo.org/packages/app-misc/solaar [mageia]: http://mageia.madb.org/package/show/release/cauldron/application/0/name/solaar [universe repository]: http://packages.ubuntu.com/search?keywords=solaar&searchon=names&suite=all§ion=all [nix flake]: https://github.com/Svenum/Solaar-Flake ## Manual installation See [the installation page](https://pwr-solaar.github.io/Solaar/installation) for the step-by-step procedure for manual installation. ## License This software is distributed under the terms of the [GNU Public License, v2](LICENSE.txt), or later. ## Contributing to Solaar Contributions to Solaar are very welcome. Solaar has complete or partial translations of its GUI strings in several languages. If you want to update a translation or add a new one see [the translation page](https://pwr-solaar.github.io/Solaar/i18n) for more information. If you find a bug, please check first if it has already been reported. If yes, please add additional information you may have to the existing issue. If not, please open a new bug report issue. If you can provide a fix for it, please also open a GitHub pull request. Label your commits using the naming conventions in recent commits to Solaar. If you want to add a new feature to Solaar, feel free to open a feature request issue to discuss your proposal. There are also usually several open issues for enhancements that have already been requested. ## Contributors This project began as a third-hand clone of [Noah K. Tilton](https://github.com/noah)'s logitech-solar-k750 project on GitHub (no longer available). It was developed further thanks to the contributions of many other people, including: - [Daniel Pavel](https://github.com/pwr) - [Filipe Lains](https://github.com/FFY00) - [Peter Wu](https://github.com/Lekensteyn), who also did some [reverse engineering on pairing](https://lekensteyn.nl/logitech-unifying.html) - Julien Danjou - [Lars-Dominik Braun](http://6xq.net/git/lars/lshidpp.git) - [Alexander Hofbauer](http://derhofbauer.at/blog/blog/2012/08/28/logitech-performance-mx) - [Clach04](https://github.com/clach04) - [Peter F. Patel-Schneider](https://github.com/pfps) Thanks go to Nestor Lopez Casado, who provided [public Logitech specifications for the HID++ protocol](http://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28). Also, thanks to Douglas Wagner, Julien Gascard, and others for helping with application testing and supporting new devices. Solaar-1.1.20/docs/installation.md000066400000000000000000000153641522022367600170050ustar00rootroot00000000000000--- title: Manual Installation layout: page --- # Installing from PyPI An easy way to install the most recent release version of Solaar is from the PyPI repository. First install pip, and then run `pip install --user solaar` or `pipx install --system-site-packages solaar`. This will not install the Solaar udev rule, which you will need to install manually by copying `~/.local/lib/udev/rules.d/42-logitech-unify-permissions.rules` to `/etc/udev/rules.d` as root. ## Installing in macOS Solaar has limited support for macOS. You can use it to pair devices and configure settings but the rule system and diversion will not work. After installing Solaar via pip use homebrew to install the needed libraries: ``` brew update brew install hidapi gtk+3 pygobject3 ``` ### Optional: Set up macOS launcher * Option A (recommended): Configure a LaunchAgent to automatically start Solaar and keep it running in the background. It will also automatically restart Solaar if it crashed or closed. ``` bash <(curl -fsSL https://raw.githubusercontent.com/pwr-Solaar/Solaar/refs/heads/master/tools/create-macos-launchagent.sh) ``` * Option B: Create Solaar.app launcher in /Applications. It can be added to Login Items to start on login, but it will not automatically recover on crashes. ``` bash <(curl -fsSL https://raw.githubusercontent.com/pwr-Solaar/Solaar/refs/heads/master/tools/create-macos-app.sh) ``` # Installating from GitHub ## Downloading Clone Solaar from GitHub by `git clone https://github.com/pwr-Solaar/Solaar.git`. ## Installing using the Makefile Solaar has a makefile that can be used to easily install Solaar after cloning the repository. First, install the needed system packages by `make install_apt` or `make install_dnf` or `make install_brew`. These might not install all needed packages in older versions of your distribution. Next, install the Solaar rule via `make install_udev`. Finally, install Solaar via `make install_pip` or `make install_pipx`. Parts of the installation process require sudo privileges so you may be asked for your password. ## Running from the download directory To run Solaar from the download directory, just cd to there and run `bin/solaar` for the GUI or `bin/solaar ` for the CLI. ## Requirements for Solaar This is only relevant if you have problems with the easier methods above. Solaar needs a reasonably new kernel with kernel modules `hid-logitech-dj` and `hid-logitech-hidpp` loaded. The kernel option CONFIG_HIDRAW also needs to be enabled. Most of Solaar should work fine with any kernel more recent than 5.2, but newer kernels might be needed for some devices to be correctly recognized and handled. The `udev` package must be installed and its daemon running. Solaar requires Python 3.7+ and requires several packages to be installed. If you are running the system version of Python you should have the `python3-pyudev`, `python3-psutil`, `python3-xlib`, `python3-evdev`, `python3-typing-extensions`, `dbus-python` or `python3-dbus`, and `python3-yaml` or `python3-pyyaml` packages installed. To run the GUI Solaar also requires Gtk3 and its GObject introspection bindings. If you are running the system version of Python in Debian/Ubuntu you should have the `python3-gi` and `gir1.2-gtk-3.0` packages installed. In Fedora you need `gtk3` and `python3-gobject`. You may have to install `gcc` and the Python development package (`python3-dev` or `python3-devel`, depending on your distribution). Other system packages may be required depending on your distribution, such as `python-gobject-common-devel` and `python-typing-extensions'. Although the Solaar CLI does not require Gtk3, `solaar config` does use Gtk3 capabilities to determine whether the Solaar GUI is running and thus should tell the Solaar GUI to update its information about settings so it is a good idea to have Gtk3 available even for the Solaar CLI. Solaar needs a library to interact with the system tray. The library that provides this interaction depends on the distribution and window system. If ayatana appindicator is available then it is best to have this library installed, e.g., by installing `libayatana-appindicator` or `gir1.2-ayatanaappindicator3-0.1` or similar, depending on distribution. Otherwise appindicator can sometimes be used, e.g., by installing `libappindicator-gtk3` or `gir1.2-appindicator3-0.1` or similar, depending on distribution. If desktop notifications bindings are also installed (`gir1.2-notify-0.7` for Debian/Ubuntu), you will also see desktop notifications when devices come online and go offline. Solaar includes its own version of `hid_parser` because the version that is in PyPi (at https://pypi.org/project/hid-parser/) does not have some changes that are in https://github.com/usb-tools/python-hid-parser and are needed for some devices. Do not use pip to install hid_parser! Some distributions (e.g., Fedora) may separately package this code. If the `gitinfo` Python package is available, Solaar shows better information about which version of Solaar is running. This package may not be available in some distributions but can be installed using pip via `pip install --user python-git-info`. If you are running a version of Python different from the system version, you may need to use pip to install projects that provide the above Python packages. Solaar runs best under X11 with the Xtest extension enabled so that Solaar rules can fake keyboard input using Xtest. Solaar also uses the X11 library to access the XKB extension, which requires installation of the X11 development package. (In Fedora this is `libX11-devel`. In other distributions it may be `libX11-dev`.) Solaar will run under Wayland but some parts of Solaar rules will not work. For more information see [the rules page](https://pwr-solaar.github.io/Solaar/rules). ## Installing Solaar's udev rule manually You can install Solaar's udev rule manually by copying the file `rules.d/42-logitech-unify-permissions.rules` as root from the Solaar repository to `/etc/udev/rules.d`. Let udev reload its rules by running `sudo udevadm control --reload-rules`. # Solaar in other languages If you want to have Solaar's user messages in some other language you need to run `tools/po-compile.sh` to create the translation files before running or installing Solaar and set the LANGUAGE environment variable appropriately when running Solaar. # Running Solaar at Startup Distributions can cause Solaar can be run automatically at user login by installing a desktop file at `/etc/xdg/autostart/solaar.desktop`. An example of this file content can be seen in the repository at [`share/autostart/solaar.desktop`](https://github.com/pwr-Solaar/Solaar/blob/master/share/autostart/solaar.desktop). If you install Solaar yourself you may need to create or modify this file or install a startup file under your home directory. Solaar-1.1.20/docs/issues.md000066400000000000000000000072351522022367600156150ustar00rootroot00000000000000--- title: Known Issues layout: page --- # Known Issues - Some internal structures in Solaar have been updated to use more standard Python language features. This has caused some problems and introduced bugs are still being found. - Some devices, such as the G515 Lightspeed TLK, have multiple ways of controlling their LEDs, for example one way controls each LED individually and another controls multiple LEDs at once. For these devices the settings for one way should be set to ignore. Having multiple ways that are not set to ignore may result in unusual behavior. - Onboard Profiles, when active, can prevent changes to other settings, such as Polling Rate, DPI, and various LED settings. Which settings are affected depends on the device. To make changes to affected settings, disable Onboard Profiles. If Onboard Profiles are later enabled the affected settings may change to the value in the profile. - Solaar expects that it has exclusive control over settings that are not ignored. Running other programs that modify these settings, such as logiops, will likely result in unexpected device behavior. - The Linux HID++ driver modifies the Scroll Wheel Resolution setting to implement smooth scrolling. If Solaar changes this setting, scrolling can be either very fast or very slow. To fix this problem click on the icon at the right edge of the setting to set it to "Ignore this setting", which is the default for new devices. The mouse has to be reset (e.g., by turning it off and on again) before this fix will take effect. - The Linux HID++ driver sets the scrolling direction to its normal setting when implementing smooth scrolling. This can interfere with the Scroll Wheel Direction setting, requiring flipping this setting back and forth to restore reversed scrolling. - The Linux HID++ driver sends messages to devices that do not conform with the Logitech HID++ specification resulting in responses being sent back that look like other messages. For some devices this causes Solaar to report incorrect battery levels. - Solaar normally uses icon names for its icons, which in some system tray implementations results in missing or wrong-sized icons. The `--tray-icon-size` option forces Solaar to use icon files of appropriate size for tray icons instead, which produces better results in some system tray implementations. To use icon files close to 32 pixels in size use `--tray-icon-size=32`. - The icon in the system tray can show up as 'black on black' in dark themes or as non-symbolic when the theme uses symbolic icons. This is due to problems in some system tray implementations. Changing to a different theme may help. The `--battery-icons=symbolic` option can be used to force symbolic icons. - Solaar uses uinput to simulate input but this needs write permission on /dev/uinput. For more information see [the rules page](https://pwr-solaar.github.io/Solaar/rules). - Diverted keys remain diverted and so do not have their normal behavior when Solaar terminates or a device disconnects from a host that is running Solaar. If necessary, their normal behavior can be reestablished by turning the device off and on again. This is most important to restore the host switching behavior of a host switch key that was diverted, for example to switch away from a host that crashed or was turned off. - When a receiver-connected device changes hosts Solaar remembers which diverted keys were down on it. When the device changes back the first time any of these diverted keys is depressed Solaar will not realize that the key was newly depressed. For this reason Solaar rules that can change hosts should trigger on key releasing. Solaar-1.1.20/docs/rules.md000066400000000000000000000443371522022367600154400ustar00rootroot00000000000000--- title: Rule Processing of HID++ Notifications layout: page --- # Rule Processing of HID++ Notifications Creating and editing most rules can be done in the Solaar GUI, by pressing the 'Rule Editor' button in the Solaar main window. Note that rule processing only fully works under X11. When running under Wayland with X11 libraries loaded some features will not be available. When running under Wayland without X11 libraries loaded even more features will not be available. Rule features known not to work under Wayland include process and mouse process conditions, although on GNOME desktop under Wayland, you can use those with the Solaar Gnome extension installed, You can install it from `https://extensions.gnome.org/extension/6162/solaar-extension`. Under Wayland using keyboard groups may result in incorrect symbols being input for simulated input. Under Wayland simulating inputs when modifier keys are pressed may result in incorrect symbols being sent. Simulated input uses uinput to simulate input so the user has to have write access to /dev/uinput. The easiest way to maintain write access to /dev/uinput is to use Solaar's udev rule by downloading `https://raw.githubusercontent.com/pwr-Solaar/Solaar/master/rules.d/42-logitech-unify-permissions.rules` and copying it as root into the `/etc/udev/rules.d` directory. You may have to reboot your system for the write permission to be set up. Another way to get write access to /dev/uinput is to run `sudo setfacl -m u:${USER}:rw /dev/uinput` but this needs to be done every time the system is rebooted. ## HID++ notifications and diversion Logitech devices that use HID++ version 2.0 or greater, produce feature-based notifications that Solaar can process using a simple rule language. For example, using rules Solaar can emulate an `XF86_MonBrightnessDown` key tap in response to the pressing of the `Brightness Down` key on Craft keyboards, which normally does not produce any input at all when the keyboard is in Windows mode. Solaar's rules only trigger on HID++ notifications so device actions that normally produce HID output have to be first be set (diverted) to produce HID++ notifications instead of their normal behavior. Currently, Solaar can divert some mouse scroll wheels, some mouse thumb wheels, the crown of Craft keyboards, and some keys and buttons. If the scroll wheel, thumb wheel, crown, key, or button is not diverted by setting the appropriate setting then no HID++ notification is generated and rules will not be triggered by manipulating the wheel, crown, key, or button. Look for `HID++` or `Diversion` settings to see what diversion can be done with your devices. ### Show notifications Running Solaar with the `-ddd` option will show information about notifications, including their feature name, report number, and data. In response to a feature-based HID++ notification Solaar runs a sequence of rules. A `Rule` is a sequence of components, which are either sub-rules, conditions, or actions. Conditions and actions are dictionaries with one entry whose key is the name of the condition or action and whose value is the argument of the action. If the last thing that a rule does is execute an action, no more rules are processed for the notification. Rules are evaluated by evaluating each of their components in order. The evaluation of a rule is terminated early if a condition component evaluates to false or the last evaluated subcomponent of a component is an action. A rule is false if its last evaluated component evaluates to false. ## Conditions ### Not `Not` conditions take a single component and are true if their component evaluates to a false value. ### Or `Or` conditions take a sequence of components and are evaluated by evaluating each of their components in order. An Or condition is terminated early if a component evaluates to true or the last evaluated subcomponent of a component is an action. A Or condition is true if its last evaluated component evaluates to a true value. `And` conditions take a sequence of components which are evaluated the same as rules. ### Feature `Feature` conditions are true if the name of the feature of the current notification is their string argument. `Report` conditions are true if the report number in the current notification is their integer argument. ### Key `Key` conditions are true if the Logitech name of the current **diverted** key or button being pressed is their string argument. Alternatively, if the argument is a list `[name, action]` where `action` is either `'pressed'` or `'released'`, the key down or key up events of `name` argument are matched, respectively. Logitech key and button names are shown in the `Key/Button Diversion` setting. These names are also shown in the output of `solaar show` in the 'Reprogrammable keys' section. Only keys or buttons that have 'Divertable' in their report can be diverted. Some keyboards have 'Gn', 'Mn', or 'MR' keys, which are diverted using the 'Divert G Keys' setting. ### Key is down `KeyIsDown` conditions are true if the **diverted** key or button that is their string argument is currently down. Note that this only works for **diverted** keys or buttons, including diverted Gn, Mn, and MR keys. ### Key and button diversion Solaar can also create special notifications in response to mouse movements on some mice. Setting `Key/Button Diversion` for a key or button to Mouse Gestures causes the key or button to create a `Mouse Gesture` notification for the period that the key or button is depressed. Moving the mouse creates a mouse movement event. Stopping the mouse for a little while and moving it again creates another mouse movement event. Pressing a diverted key creates a key event. When the key is released the sequence of events is sent as a synthetic notification that can be matched with `Mouse Gesture` conditions. ### Mouse gestures `Mouse Gesture` conditions are true if the actions (mouse movements and diverted key presses) taken while a mouse gestures button is held down match the arguments of the condition. Mouse gestures buttons can be set using the 'Key/Button Diversion' setting, by changing the value to `Mouse Gestures`. The arguments of a Mouse Gesture condition can be a direction, i.e., `Mouse Up`, `Mouse Down`, `Mouse Left`, `Mouse Right`, `Mouse Up-Left`, `Mouse Up-Right`, `Mouse Down-Left`, or `Mouse Down-Right`, or the Logitech name of a key. If the first argument is the Logitech name of a key then that argument is matched against the button that was held down to initiate mouse gesture processing. For example, a Mouse Gesture condition of `Mouse Up` -> `Mouse Up` would match pressing any Mouse Gestures button, moving the mouse upwards, pausing momentarily, moving the mouse upwards again, and releasing the button. The condition `Smart Shift` -> `Mouse Down` -> `Back Button` would match pressing the Smart Shift button (provided that it is a Mouse Gestures button!), moving the mouse downwards, clicking the Back button (provided that it is diverted!), and then releasing the Smart Shift button. Directions and buttons can be mixed and chained together however you like. It's possible to create a `No-op` gesture by clicking 'Delete' on the initial Action when you first create the rule. This gesture will trigger when you simply click a Mouse Gestures button. ### Key modifiers `Modifiers` conditions take either a string or a sequence of strings, which can only be `Shift`, `Control`, `Alt`, and `Super`. Modifiers conditions are true if their argument is the current keyboard modifiers. ### Process focused `Process` conditions are true if the process for the focused input window or the window's Window manager class or instance name starts with their string argument. ### Window under cursor `MouseProcess` conditions are true if the process for the window under the mouse or the window's Window manager class or instance name starts with their string argument. ### Device notification and device active `Device` conditions are true if a particular device originated the notification. `Active` conditions are true if a particular device is active. `Device` and `Active` conditions take one argument, which is the serial number or unit ID of a device, as shown in Solaar's detail pane, or either of its names, as shown by Solaar. Some older devices do not have a useful serial number or unit ID and so cannot distinguished from other devices with the same names. ### Host `Host` conditions are true if the computers hostname starts with the condition's argument. ### Solaar device setting `Setting` conditions check the value of a Solaar setting on a device. `Setting` conditions take three or four arguments, depending on the setting: the Serial number or Unit ID of a device, as shown in Solaar's detail pane, or null for the device that initiated rule processing; the internal name of a setting (which can be found from solaar config \); one or two arguments for the setting. For settings that use keys or buttons as an argument the Logtech name can be used as shown in the Solaar main window for these settings, or the numeric value for the key or button. For settings that use gestures as an argument the internal name of the gesture is used, which can be found in the GESTURE2_GESTURES_LABELS structure in lib/logitech_receiver/settings_templates. For settings that need one of a set of names as an argument the name can be used or its internal integer value, as used in the Solaar config file. `Setting` conditions check device settings of devices, provided the device is on-line. The first arguments to the condition are the Serial number or Unit ID of a device, as shown in Solaar's detail pane, or null for the device that initiated rule processing; and the internal name of a setting (which can be found from solaar config \). Most simple settings take one extra argument, the value to check the setting value against. Range setting can also take two arguments, which form an inclusive range to check against. Other settings take two arguments, a key indicating which sub-setting to check and the value to check it against. For settings that use gestures as an argument the internal name of the gesture is used, which can be found in the GESTURE2_GESTURES_LABELS structure in lib/logitech_receiver/settings_templates. For boolean settings '~' can be used to toggle the setting. ### Test and TestBytes `Test` and `TestBytes` conditions are true if their test evaluates to true on the feature, report and data of the current notification. `TestBytes` conditions can return a number instead of a boolean. `TestBytes` conditions consist of a sequence of three or four integers and use the first two to select bytes of the notification data. Writing this kind of test condition is not trivial. Three-element `TestBytes` conditions are true if the selected bytes bit-wise AND with its third element is non-zero. The value of these test conditions is the result of the AND. Four-element `TestBytes` conditions are true if the selected bytes form a signed integer between the third and fourth elements. The value of these conditions is the signed value of the selected bytes if that is non-zero otherwise True. `Test` conditions are mnemonic shorthands for meaningful feature, report, and data combinations in notifications. A `crown_right` test is the rotation amount of a `CROWN` right rotation notification. A `crown_left` test is the rotation amount of a `CROWN` left rotation notification. A `crown_right_ratchet` test is the ratchet amount of a `CROWN` right ratchet rotation notification. A `crown_left_ratchet` test is the ratchet amount of a `CROWN` left ratchet rotation notification. A `crown_tap` test is true for a `CROWN` tap notification. A `crown_start_press` test is true for the start of a `CROWN` press notification. A `crown_stop_press` test is true for the end of a `CROWN` press notification. A `crown_pressed` test is true for a `CROWN` notification with the Crown pressed. A `thumb_wheel_up` test is the rotation amount of a `THUMB WHEEL` upward rotation notification. A `thumb_wheel_down` test is the rotation amount of a `THUMB WHEEL` downward rotation notification. `lowres_wheel_up`, `lowres_wheel_down`, `hires_wheel_up`, `hires_wheel_down` are the same but for `LOWRES WHEEL` and `HIRES WHEEL`. `True` and `False` tests return True and False, respectively. Solaar keeps track of the total signed displacement of the current thumb wheel movement. This displacement is reset when the thumb wheel is inactive. `thumb_wheel_up` and `thumb_wheel_down` tests take an optional integer parameter. With a parameter the test is only true if the current thumb wheel displacement is greater than the parameter. The displacement is then lessened by the amount of the parameter. ## Actions ### Key press A `KeyPress` action takes either the name of an X11 key symbol, such as "a", a list of X11 key symbols, such as "a" or "CTRL + A", or a two-element list with the first element as above and the second element one of `'click'`, `'depress'`, or `'release'` and executes key actions on a simulated keyboard to produce these symbols. Use separate `KeyPress` actions for multiple characters, i.e., don't use a single `KeyPress` like 'a+b'. The `KeyPress` action normally both depresses and releases (clicks) the keys, but can also just depress the keys or just release the keys. Use the depress or release options with extreme care, ensuring that the depressed keys are later released, otherwise it may become difficult to use your system. The keys are depressed in forward order and released in reverse order. If a key symbol can only be produced by a shfited or level 3 keypress, e.g., "A", then Solaar will add keypresses to produce that key symbol, e.g., simulating a left shift keypress to get "A" instead of "a". If a key symbol is not available in the current keymap or needs other shift-like keys, then Solaar cannot simulate it. Under X11 Solaar can determine the current key modifiers (shift, control, etc.). Any key symbols that correspond to these modifier keys are not depressed and released when clicking. So if the shift key is currently down on a keyboard Solaar will not bother to simulate a shift key. Under Wayland this check cannot be done so the net result of a `KeyPress` action that is not a `depress` or a `release` and that contains modifier keys might be to release the modifier keys. Simulating input in Linux is complex. Solaar has to try to determine which keyboard key corresponds to which input character as it cannot directly simulate inputting a key symbol. Unfortunately, this determination can go wrong in several ways and is more likely to go wrong under Wayland than under X11. ### Mouse scroll A `MouseScroll` action takes a sequence of two numbers and simulates a horizontal and vertical mouse scroll of these amounts. If the previous condition in the parent rule returns a number the scroll amounts are multiplied by this number. ### Mouse click A `MouseClick` action takes a mouse button name (`left`, `middle` or `right`) and a positive number or 'click', 'depress', or 'release'. The action simulates that number of clicks of the specified button or just one click, depress, or release of the button. ### Execute An `Execute` action takes a program and arguments and executes it asynchronously. ### Set setting A `Set` action changes a Solaar setting for a device, provided that the device is on-line. `Set` actions take three or four arguments, depending on the setting. The first two are the Serial number or Unit ID of a device, as shown in Solaar's detail pane, or null for the device that initiated rule processing; and the internal name of a setting (which can be found from `solaar config `). Simple settings take one extra argument, the value to set the setting to. For boolean settings `~` can be used to toggle the setting. Other simple settings take two extra arguments, a key indicating which sub-setting to set and the value to set it to. For settings that use gestures as an argument the internal name of the gesture is used, which can be found in the GESTURE2_GESTURES_LABELS structure in `lib/logitech_receiver/settings_templates`. All settings are supported. ### Later A `Later` action executes rule components later. `Later` actions take an integer delay in seconds between 1 and 100 followed by zero or more rule components that will be executed later. Processing of the rest of the rule continues immediately. ## Built-in Rules Solaar has a built-in rule, which is run after user-created rules and so can be overridden by user-created rules. This rule turns `Brightness Down` key press notifications into `XF86_MonBrightnessDown` key taps and `Brightness Up` key press notifications into `XF86_MonBrightnessUp` key taps. ## Example Solaar Rule File Solaar reads rules from a YAML configuration file (normally `~/.config/solaar/rules.yaml`). This file contains zero or more documents, each a rule. Here is a file with six rules: ``` %YAML 1.3 --- - Key: [M2, pressed] - Set: [198E3EB8, dpi, 3000] - Execute: [notify-send, Increased mouse speed] ... --- - Key: [Host Switch Channel 2, pressed] - Set: [43DAF041, change-host, 1] - Set: [198E3EB8, change-host, 1] - Execute: [notify-send, Switched to host 2] ... --- - MouseGesture: [Mouse Up, Mouse Down] - Execute: [notify-send, Locking] - Execute: xflock4 ... - Feature: CROWN - Process: quodlibet - Rule: [ Test: crown_start_press, KeyPress: XF86_AudioMute ] - Rule: [ Test: crown_pressed, Test: crown_right_ratchet, KeyPress: XF86_AudioNext ] - Rule: [ Test: crown_pressed, Test: crown_left_ratchet, KeyPress: XF86_AudioPrev ] - Rule: [ Test: crown_right_ratchet, KeyPress: XF86_AudioRaiseVolume ] - Rule: [ Test: crown_left_ratchet, KeyPress: XF86_AudioLowerVolume ] ... --- - Feature: THUMB WHEEL - Rule: [ Modifiers: Control, Test: thumb_wheel_up, MouseScroll: [-2, 0] ] - Rule: - Modifiers: Control - Test: thumb_wheel_down - MouseScroll: [-2, 0] - Rule: [ Or: [ Test: thumb_wheel_up, Test: thumb_wheel_down ], MouseScroll: [-1, 0] ] ... --- - Feature: LOWRES WHEEL - Rule: [ Or: [ Test: lowres_wheel_up, Test: lowres_wheel_down ], MouseScroll: [0, 2] ] ... ``` ## Button diversion example Here is an example showing how to divert the Back Button on an MX Master 3 so that pressing the button will initiate rule processing and a rule that triggers on this notification and switches the mouse to host 3 after popping up a simple notification. ![Solaar-divert-back](screenshots/Solaar-main-window-back-divert.png) ![Solaar-rule-back-host](screenshots/Solaar-rule-editor.png) Solaar-1.1.20/docs/screenshots/000077500000000000000000000000001522022367600163115ustar00rootroot00000000000000Solaar-1.1.20/docs/screenshots/Solaar-main-window-back-divert.png000066400000000000000000004567301522022367600246770ustar00rootroot00000000000000‰PNG  IHDR8(*aPšsBIT|dˆ IDATxœì½w˜dGu÷ÿ©º¡Ã¤Ý™ÍA«MÒ&­r¡€d!,0ÙddlcccÀ`øóúuÛ¯c“,ùŘ ð+ƒl�„QBI«ÝUÚ]mÞ�Ý�Øá†ªß·oÏížî «‘Vá|žgž{oݪSU·g¦»¾}Î)E æ¼÷³¶U¹ ‚ ‚ ‚ ±¦ÿª�©æ27{‘ ýg½û¹“ ‚ ‚ ‚ ´˜‰~‘:ê'sÞûY{茷‹q ‚ ‚ ‚ ‚ L›¾{¿Y9$âÆáSßrlGõ è}à;õóò<AAAA˜½|‡þ«>¦ê!*ÊDÇr<ψlH�S9†#AAAáX æ¼÷³v`Ãk�õ8žq¾³~îTDàAAA„—³ùÏ$ɨ2á±Ë3¢ïÞoÖÏ×ýò1‰ ‚ ‚ ‚ Ç‚Dàˆ_¸á)Тâî=†#AAAáX�äàxç߀¦ü!/𹂠‚ ‚ ‚0}j!*/lQ ¢2¼ò¼c8AAAAŽ/º•ü�Ç�áHAAAA8LèÁQ^°nâÖ6‚±�f3×¶M5Á½v¨V7ÜÏ&I}¡{£‚ ‚ ‚ ¼˜8ᜠëçqlp]?-µÏÞ‹c0a_­l•�p`Ï.Ê#C8qø¬Ï£ÙN;»ÍskÕ&[^fÿÎíÏÚ<¦Ò¾Ý˜§Ów«×£5Žv&#”›ˆéyãÍñíëu�‰íf­ÄÖñ&¨aBTJ‹O™²mAAAáÙe¢…xJöºÕ8K³xÑ|¯yÑÜÊF³­¬½æÅvº^žl­æT*8ž?é<ÚͲ¹µ{F)6­1�y´ê¿­žßTÇœ­Ó®m«òöúÅd98l<ÞXuÿ±ÛÐ#O‚*�²cN�Žcå =1TÒn¬£Zq¦�Jq䎣rÂ+±ù.Tb¯~̆¨t켿ídAAA„ç–r ªÍ ×ìu* ´£�0Ò|/=Ÿh¡>i�°\_/O6�Vç~>O›–ö'k{4õ›çG�ã(æ1“Õm%þ´çdmL6¼­˜0‡2��y»ÆÙyÕ5K1Ý+º&J¤â„"#NÔ tÓ}mÁfÚÖœŒø¡Æîë¡!ò¿øqßÅ„K6ÖU‡aä…ŸODAAáÅF9†‚qàx~ýÜš7W ƒa#Ò/ë³õ³çÙ/óÓòìýæ{í®³åA¥BEÉ‚:ŠÔÍ£•ÍfgƒÉÆ1ÑØÛ�¹]Çó1Qˆ‰BTe¸a­<Ñ<¦2ÞéΣûø¦õØ'›G&B�¯,U&^óOâÁQ8”ÆÛý0ªÿ(Ÿ¾l“çF«Tã ÖŽ±ÃfnM`ÃtwQ~Åzr¿¸ogL¸ôÔú½lˆJuΪ© DAAAx)Ç�Êã…€ å±ù~öÜš¥�†rkb¢j¹¡|2{“•7¯—ÛÍ£�ÍfûÙq7Ï¥•�vÏd²:q ]'¦5�Vv'Ëd×S7ší§ÏÄñ|lÆÁaRÚTP&Âj]:Œ³ã¿)Ÿ¹´&Q#jÊÄtr†ÖEŒ6m³"GV@IÑÕSVS¸ýfâÞã°ù. q•®'n�Æ€AAA„g“ŠMÜõ;Âa¬n“ˆ2 ÑmîcÐZ×�)ÖŒO«0QùT1QˆŽaêëå©Ìcª´ßÑŒYi‡8 q\¯Þ>}F‰`R SyæÑj<Ùq8®WLþ:7“ VA¥Œ¶¶­~SØ&V™ï‰;©®Y*3�lJ Ï =4Œéì¨ "ìžb,ztÓÓ�N!7Ú¡Õ�Ëð¹“`í¥õ1Ö‡%!*‚ ‚ ‚ ÏKŒiŸsa¢{Ùû“Õ›*YÁ$kSk�Íä£lµÆ<Ú1´ës:m›$ÂAóø4`k÷µ5ÏÊÓ{Si§—8 Z>ŸVã€1!ÁÓ–hó°q„‹!vü¶¯IÜäl2Ù¸&*Ÿì5O^�¿i­˜Üƒ#ްj”I“dDÞνävT×½•°kþ/¾‡Åtu´¶=ZÆ9ÜMõÔ7¢GS¼õ¿—iÂå‹ÁmÞv¶FMX1nV°Žß¢2ë‘ëÛ�QAžWhzfw1ÏlÌáÃ#GDAáEHÕ(²«ÂtAÛ|Œªœ¦µ`»ºÍÇVõã("ÍÆ‘=o¦�-h\/gç‘.Âã(ÂmZ¤·;o×ïdíšç2Õñ{q•jM8�Ví#44?Çvkôý6—§íÓc˹µ¸Ÿ}q¨Å<š™0ɨJ“ŒN”h£v«xÿ&̬s)Ÿu::ª LD¼ü\r[ÿ“òé«v:IÂP ¿õi¢e—£°�ï$8í¸»»ûvJçž2¾£ŒÆ¢Xí‚5�!*Äã‚ €›+°¤·ƒ9­ˆÂ€�‘»Ž”~.ßFTo~ÇëùÛ5˜Ã|öo¾Ïßìž·[AAx¾PµŠœ²T"ƒ;…”Ù­M[Q±žjX§4_7Û›Ìö˜�§2ˆ ƶ%7�Œ­¨Zicgf?XL×^Õ:øÚ¥öó˜Çuæ’sÇRWÄŽß0÷¬H‘] ®«¡v¬¶™Cj¿ÕëY�áAgæÑЉ·‰�C¬ã5•¶;Âù³qªU°Ž—´-ôÇá žÓÛP_@‹1ÝsúQÆÎë¥)ãèø±Y‹ŽªÌ~øºz¹ñZ{‹‚ /mr³òÆ Öñ–“—ræÂ"ùN‰6ª²}Ç.þûžG¹òÎ�lŸZÂï£GEßH‹2j{Ï ‚  ‰(Šq§´ûæxL¢k‰*ó*&Ž’ÅoPÁñòõzéö®iÝv6&"±QU>šò¸õr«y´²�]¨O¥ïŠuðã Úõ¦<Öé0•yØ8D5ii’O€|.GQ|'mXe¦]P.¡µ"ª]ÇQDwm«ßQ±WS�LÛþ²eé34Q„•[Ì#K{“úC‹q7j‰2j‡pé¼»î"^¸mʉw¯<—ÜCÿFéüYcIJ�%ÿÐÓDë߃jÚîE¾“pãÉ@-O‡jõ�xsØÚÖ:Ù•Þ¾7Ù”A„—kÏ=Ÿ+ß|"'æ'®©ÜËW®ä+Wòž ¶ò±¯ÜÌ·ö=³,ì‚ ‚ðR§lèdKÒ8¬ T»@‹Ö¤ }Ó”H3+8^ž¨ZF;ã—¶iýT0hec¢þr6 Êx ”�"6!~;­úku¿.Ìõc¬r©Ä†ÆÛЮG&_ò;^®­½ÆùFØ ÒàõÐøzhݸæNËÒÄžZ«ºàPÔ†E‡«ð´e '9drTªÕº åxé.øôúÐQSRF#Ø?R¥ŠWßúQ#Ž"Ü\¡~�µU?Ÿ$bcr�£��æm\µ¦²~…Go ØpY}‹Y;ïü§"X¹oûÓØÙ§×Å‹´®¿ù§”NY:“¹49šS€(ÐQ«´„¥‚ mP,>ë"®}ÇJhÀÆì{ê ®¹{;·?}˜�ƒUFcE¾P`Éü¹¼|ã ¼ûìÅ,ñ cá‰|îwcŽ|æf~³|X”‡bÎA+Å¡ŠAÅŠx4` öSqÃqÝÁe,G8å-t'8¦+˜Y=˜Üfœ�=˜îyõöñ¼Uø�lÆÛû`Qq�`ú†>ôà~âÂÌìu4‡¤dÝwë¹8Òj­¡/³‹Š„¨‚ urKøÈëWÔÄ� ·ý¿ò®0Üì˜84ÊÎýýÜõÐf¾rËF¾ö{çrI�›³†?¿l+·\»—ñ‘µ‚ ‚ L—T«e¼Ú·õ©`‘õÂH·ÕŽ[¿ošB²bF«~²Çdÿ�öǺÍÚuàæ°åÑ–öë¢C�ijz¹Ä¿=ŸÛs5s•fùÙë¸ð‡{ù‘(‚ ‚pT˜(Â˜Ä #ŽÃºxfr;À˜¨Ñ|�-w\¯~íŒËy6ÔIï7Ÿ7×i>ÖiòàÈÎ#Šu™ÚN Ž1 s×÷ëBEó‚Ý÷\våYPtÈ×Vç}y‡RlØ;ÔÆÜ˜t’ÝQ*‘S/K…–æzš¸¥'JêÅã?à$Ï(lxÖ£®GÞXTEšÀó,‡TbÈ;‰�T ³üdL=¾NÄ�œËH%$r §àa¢ˆJSŽÁ + Eš¼Š'|}ܸÚÖ£&ËÄGú¢Ù[Ħ!*i4IZœÏö…8ýÛ‰ç®HD@…ôÐPÓÑ‹õ É=ÇÇ9øQ_ [\Üf MMN%DEAhEW_7½µ·¯Ñ]yjŠù;ûº—�|wù‡yt÷!žh+nhæ¿‚·�µœóWÌaÅì<].å »ôsï–m|÷gOñÀÐ3Lª l<ùÞtÊÎ\2‹%]9 Ž¥R.³kßAîzä ¾ñ³Œsm©<\r6o˜¯±Ñ®úö&ö{yÓ«Ï⊓ç³,ñ‹þ›·ÿä0’½DAx¦´=ZÝk.Ÿ¨ns�ìÑq=ܸBèhjÇ'Ú©%šË+V;9r®¦«¦«T"KÞU[¯“WcŸ#ê^™ c[í¬’- #3åyDÁØ€æçW b‡>ƒ±ƒZ*µ7z¯–bbᬎ†<$y'&ª�£å�ÁØ¡U©V±"¯âq}e¯ÓcÅhTO:�É=8ê1CM"‡jR62çV)ˆ’£ËC8OÝBœ;L4w6(p÷ G{ˆŽ¿[솰 žf<©Í6©vk1F¢"‚ ´"ŠMýí«Ð]¤KAuޤá®ÿŸ#×Éõñη]Â_œÝKWóÛTG�sfsúºÕüæ«síµ7òÑÛÑÚÉubü¹«øë÷_À»—äÐ-úY8§—37œÈo]ºƒ¿úê�üÓ¶ íæî3cËaź5¼s�až;®ÛÁºw¿–<¥Xóvµ¬œå£AA!!@�y h×ÅDÑ”Ž@CY»ö)SµÛîGa}A=Ž \ïc¢y´º—–T£EŒT”£%ñ)*©PS;âÇlƒ�‰l7÷à«æ@œ±ydŸ×dóªV* jÃÁ¼"‡OžÏó“O =Tñ ÉØC×�.OËH³w¸Âàh•ræÑNåõ÷ˆ™Üc*IFÛ)$ÍIFÓúÕ*þMxâ ôÈaœ§®§tÚJl×ÒDÑ®:U*Q¼çzâů"ž·oË‚ã+ØŽbb§Ý*õ¤£GXÇ•A¡%£û³ÃÏ üOæ�Önç�–yƱ:=¼ûŠËù» Eñh?×ݶ™?y„½Uèœ5›³6®å=§Íav¾—7¿ýrºÍ÷y÷�CÓZô«übþ×ïþïY QÀÈþ|ûîÜ·¿Ä�qè›3—‹ÏYËkåÈÍ^Ƨç•ìýËøÞ`‹íÕgÌVD%ý”¤\æœt¿½±ˆ2UžÞ=ÀžP1:·YA„—(Ac8Jº�žê±Ýy«zGc?{Ô®K.¥xÙP”Úyv÷’©Œ7+äUL§ :Ÿx`ôù0«˜Çw,£‘Âs<ò6 ;—cNq,\ÆÄ1#µõq)´ ¶ÓD¢ÙÀ†zŸå!˜`A¥„ëùSz~e4¡bç`•(6?+aˆ‰ Úõi&ª D!–RdØ5bØ;2*LÖs}XÉy»×£Z ÆÏ£'mµ¿lQ¼ç!”.4 ÉWd*Љ¿”ÆÙv¥S–×E‹:;(Ÿ½’Â]·cOx5fþiï¸<‡q‰=PXÊ”/8|·á¾Š# QAZíÜÊ¿ïØÈŸ.wQn/ïû�7±ü~ÎßÝü$÷‰Žr®Xúòóø³š¸ÜÊoýÃO¹îpV6ÙÅ�¾‰«Ï¾„¼g%‹t‘W½áå¼þ‘qíÐÔûYöò3yÏüD�¨>}oø?ws_CèÈã\sóf~ûwßÀŸ¯É¡»—ó‘ çpÝu›¾©™A[ÖŽ%ÿRE^sÁßa~‡G‡ŸÌaV1OŸŸŒ-4!�öéòú”áäÙŠÑî±…ÑÀ°4ä`9¦R5²dËÒ]bÊŒŸGöõp‡( p=¿¾S‰ÒceÙ#À(°'4T"ƒ Ê,íë¦ÓÕà@%v.á»F9tÖÂl*!û*ŠmU—ÊF…Žã4ìŽÒn§”t¹6Í£ÓN2ªŒA» ˆV_œ BkT‹_]-cülÇqãm$-±�E̬ª2‚íšK¼æ� õ¬Öè(À¸>î“7£¢ë� 9Ý^VBTA„–˜#|åê»xŇ^ÁEÝ åuqñ¥sÑ«Îgß®½Üºew=¹—»Ÿ<ÀãÃSô:ÐsxÏEKèV€-ñß»�ÿ<ÜêC“aûÏïà³g.å6øèŽe¼ïìþãÆÁ©yq(Ÿõ‹Š –#ÜÜzóCÜß*/Fx„¯ßð$¿â:æ+ÍŠ5K8îMùFfÒ–úÛ¾ÓÇ9K÷ñgy;?8øŒýbA„9Ù`|,cÜxÔµåj­ëµ(Kë6[‘îÐ’Ý©%í³`*6Æš¨¾•lExQj·ÚpLæ×^èï*ºôù°¤ËeN^‘w�#Gð‚�Jd€2!ß×tóäƒZ ×âédl¥ Ê`¥±¯ñ!,c÷¼¦yd‰k^Qö95…ædïEaÀpí¼×÷.ÌîL6¨Äô‡…J™Ž¼�—/BX¥Á`)7Ë:Ýê6Žq§>†ìy½?7�VðmÌ#eB�£žÀæùjÇZî‹ÄsÂÍœgÚ è�5‘ùdRsfáÚOœ[ÑP®L„2`\–[´´(cP&�A¡-Õ=ó®¿áco{¿½¶‹¼¥<.=Ž·.=Ž·^’|ãqøÀ~öØn~úðSüðÑ~Ú9#¸‹–séüÚ~÷ƒÛøÖ¦j{aÄŽpý=»ùËõËéP'oXʼ›Ù;%ÅV¹þšorý5I¢®œ ÛöSÝÓÏc1ÌwAÏêb‘‚§ž-[MŒlz„kö‹¸!‚ LB�³Ñ´ÂDMáÆ"'?ãÃqã ùz?Ù>¢0TTo|DBl ž¶„&ùúÞÓƒÓPîhM\ûV `wt°¤3 ;1&&0$ÛЉH2Œ-îó&¢%×y×!ï:,*Bh<ö �­�51§¶ÃHÒ¿£õXˆŠIÞóæG˜(D¦6F­5Ƙº‘ Í÷ë6šü)”‰éP@®V [dåÊÚ Ã°eyý<(Am<*¬LúeÔÔ=8ê9Fkn9éî(íÂCLNmÙ†QØdŸWËX> £âšò•ª16å$"‹rP&3$»¨‚ Ó zpþ…§ùêò¼íœÕ\¾q1'Íòpj‘–J9ôÍ_Èkæ/ä5ç�Á_ ä‡7ßËßÜ´�'›2Zu7—•µvÁö½<0ñvì îØÏãf9§8à-šÃZöNómËD!­¤þúýjÈhí½Q9¯Mnî™¶†GÛK‹”‚ ‚0FM4(‡9MCØC^"'?®¬b4®ç3;xfj;€4téø8™| Ù0 ×ó© &é „|oœëæÆROf„‡„xu1##TíƒE*zDaåxØ8$]z£µC�*=Qˆï' ‰µKP­à[TÒ¦ÅÔ"Zð´­Û#B9ŽNÆÅÔ®5v‚]GLPÁ!ÄÄÇ„œº¸àÕ„ SÛ±%½ßãkzóÝ®¡¨cÂZRTÏ÷ÉW’O¾[ Å@LQÇt»†^ÏT e£Û&®÷íÖú1M"ƘäY¶�É -âz’rÓþ^Z¥³wï áò´€LRÒ± çÀaLç)­ûlè#;IÛPGBTA„ɉٿíq>·íq>÷ïsÌãìU 9gÕBÎYµ€“úrõżß5—7\þË\vÆf>øO·ðÿúÓ÷ Í’¾®š0bÙ×?4¡Xf·�SÐ…N îÛ9U”Ë¢¥‹yÅÊ9œ8·‹ù�>žÆu4®Ö¸^§ú•ÅLÚ²!;ûKÏR¡ZiŒ3õ=— L„�”Tè€Äó¡�Ìë1V‘ŒtLÄ©F!Úõêe£VÑãv{,êôèpáÈÈ(Z;ôóôtÑDQÈHTóêðu&6sʰc8¤Ú ûÎâ9jJ;¨ÀTvQiJ4jµ†pÎÖÖ<0ô˜'†ŘÅg'G¹ˆ*•°�ŒÛfP£eÜ#>ñ,5|½û.L&1‹²«T²£Š=/3 6FÅ‘„¨‚ Ó$¦ß^®ß·—ëoPgÏáÜõËyã+ÖñºeE|Å…kùâÃ<ùw÷òpíí°«è×sI�”ÃÉ÷qÈHÉ—>ÝyÃSuypX¶ñtþê ¹d¾_÷89:fÒVJÈð”öÝA„„ì$Úõ’0‰ÚÑs½úûjZî)K^´ãPÐÏÑÓê/ŒãÄ{ÑjJAŒv½Ä³£©ïìxbÇÇ!tPÁÔC;±4õq¦¹;ÆÎ�\�¸Ú¸�ì¨vÙ;œ,ÓKAÌ?ñV˜íkzŠI¢R¢Ü1/’ƒÃeFk"E)ˆÙ?²w¸ÊáØ%´1N ]—J¹QÀÈ&;µ5¡¦éî$Ù×"° 7ž @GÎgAgŽy�N]Üpý<:Jú¯VJD®G’b£t»y‡ßaA1&6¥*‘Q„±­=£š¼áø¸ñøñ„±­ÏÃ) b:zÛÎgŠ»¨d¶„u=FÎ?»VlA«Úý¤‚ª–é¸ûAìÊ‹0K΢xÿO)�y¶#ÑŸR3ªT¢ð³-˜€½ïŒž·:ÙqEÙ›cÇÚXšÆ'!*‚ Â3ÃR:r�o?È�w<È?�×¼uK4–mä÷7>ÌûïOrm(­êïeã¾ýh‰!¶5‘_©ämsJh–¿üUüð�ËY k:¸‡›6íçÑþ—"*±!Š ¡³€ß÷FNm›sk&meÈî¨"‚ mÐ&J6�ˆÒ „„ta;ѱ`::;˜WtYPP ¹iõ] bö�„(…TŒnÛWó9Mb†6Q½žCû-l›Å�dIþÊÁj™�ÜÚ7 »rl˜cè,dD?ÇÁá2�ôWØ9Ð(^,%cLŸc«Ä¦­Ê„@…UL⚣½†çáÖí4ŠQ�Ž¥C…,îÌÑáÂpC0J—ï€v®Ä”*É3+º$åÀp­¬ËwXÜ ‡G\ª#‡ª�Ï;7F�¦#3ž¨&85¿­˜ÔƒCGA¢¢5;`ØÖߨØ|žp¡CîÀc˜¾å˜ã.¦ëîÛ f…˜9³@kô¡#x>fÑØB7úÐv‚…Û‘I3Îᣖ»£éƒ¡Ž QAfðð­?å+ðõ³‹h•ã¼µóðîßI”«cÛËrÞäñ Ê£�úÁÚˆÒÈUÏjþâMÇ׉2·þç�øÍ勵• Ppx«Úˆ3iKAŽÛfýGŽë¢k íær•+0¯è± Óca§KÑmïÁƯÉE±ä�]�†U†kvãÔÛ¢vž=fswL4�´~ó邺FãÂ@êùªåqåõºqÔ h´7R<¥Z׉ªãlgÇS*�Ôº«¥BˆS[Zk!¬�«%E �jòRßí¤Å¼ŽA™R3RËVê;Š‘ ¦Ƙ \O–j¢°nË5cãj¶ßLÎTÆÍ#|…Q£ÛÚhç`•J…#£UúGªô—BF2âÆîÁ ýÃeänÿp™§�”Ø32P ©Tè/…ô�T92ZÅ•Äk§ÅkÑòõ‰ª­çÑÄäyÒ­/6(Õ6D%÷è“Ø9ÇÚX‹óÔm'Lâ�C—xå+’¥)s6�ßô å³7$‚Ñ4r–IˆŠ ‚ÐL9Èqꆅ¬Ñ`»NæNxœOl ¦öö¢»¸ôä9É÷Ö°ùéä‚íOsÛèzÞÚ¥p,ç—ÜǦ=í¼C<^vòRf×Ä…m[v³}ŠŽ$Y=&ŒMûq{sùÍ_:Ž®ºò?.šsFm ‚ ÂÑ’3IúƒúB=WhX\§žYJ•*»kù*zò]=. e"JÕ�½#!»Ë”¢Ö97ÆD 'Sfh—í£j^`âí¸-èéR¼á~S}€rdØ?\¡è9Ìëô¨82²¸B¹æ}ZO‚ê¸ÉóÊ%ù-£j7WÀ5U*aR7}¦n­NX›‡Ž«-£7?¨%øŒ#´ë¡]�¨Z&ïiTrP›ÙîÁ±vO*S�-¥¸&NÄ¥\�ƒ#U†Êý�ä�Œ93ì®r¸T!0z\ßí^‡dË^‚¦aš˜BˆŠK6B&L¤õG#=8HîHs|Oƒ }h•åy‚ÕkA�÷Ôv ûžÄÌYŽÕnÒOÇl¼mT� bzÓöi?*¦R‹µ¨šš%!*‚ B3Ñ®GùçM'ñù“rh=‹÷¾ï2üËM|þ±:Q8\ôºKøäê$¿†­ìâ›÷ �}(¨îäß~>Ä›.îÁqú¸âu'ðí¯lag‹O þ |ô¬ÎäM9<À7î:8a8Ë–=‡ÓPÅ +æ1K r¸ùíWwòê·þ¿77àPX`Ž*ŸgVCÜÌLÚA„£ žRµ '³Kgº¸6µ2GõsHôåÑaúk«Ö0ŠèÎOþ½òrØš×ÈP%bßp•C¥€òè0¸Å†>Z¡¿–£•0�S–(3fí¸“ÚLi®_ {‡um~‰¤²k¨ÊÞá*å Ä´Èæ�%¢j¹ám:½—Û:šF9“ QÉ µ±eË¥Ìa£©Æ–\Md:\ªÔÅâ¯ÞöPòžæp©Bo1É·Y�-GÊɼ´£[>·ìóÑŽ[{6†\TE‡% G¹‹ ´Ù¡¤•‡1z³ä‚†vÊĘ‘ÇÎ:­^5<þ8üm÷£ÍÒ†~Ì’“)Ü÷F/>£&fLM™“ÐAav„oÿûm\¼ø"^׫qº—ðÉ?|;o}ôq®}p?ß5ÀΡ*¥Èâú9æöÎ⤕Kù•³WóÊy>Z�5%nüþí|ëHö=/æîßÅ÷N»”7ÏVÌÝx>×¾7ÇÇÿߣÜÚ_Û6Öɳ~ãF>ý–Ó8;؈M?¹“«öOÕ=ѲoóŽqº«è9ùeüãE#|ø–½ì�í³|õ*~ëò³øõ•·û¸çÜKùØR�rðªuyþã�Jík‚™´%‚ G�“o¯žÁÄUås¤rhp˜þž.¢Øà¶Ù.6{/ª‰�Õ ”ª |˜‚aâˆ0ŽÉ™gBjÂÊXÂÎÌb~ªâFÖ~J%4.UO“tÙjH%6cÂÁ3D•ñó˜ˆÌÜš©„ 2ê籩7…ªåiÑ&�á��$DÈÍajõÛ=·ly*)%ó°?“‰�nQ¥…‡¿{®³ãúcíL„Úý¥�Ë@g~µ¢rÊ :î{{ücõ•E»Ëñ¶ï"\¾¤Ö-tŽLÿ&’A¡%ñáÇøÀ?Äìÿ�óyßò®òYµ~=¼~ý¤mM©Ÿo|çF>ñ³¦{vè)þèËw1÷çpa�˪3ÎåÚÓ_ÆÈð(ýUEwO½~m;Y²õΟòîì£Ô¢Ÿ¶cßÿ(yÛ¾uál|ÝÉeo~=—¼®ÊÁј|g�O¡lÄæ[ÌnÙɲ¾a>²´GyÓïàœ£t€]•ö9(¬ Ù·ëi®¾îF.ùôµ|ègGh—ºkdǃüÚ_]ÇÇoÝŶ²¥éêîbùÜNú|6bï¶ÇùÌW¯å’kž`Ç”’‹fSå–ïþ€wý×vž¬X,àø9Ì.2Ë…Ñþ]üË5ÿÁk¾µƒÖpï�næï·ŒPµ œKt3Çl ‚ Âч„&n¸¨šÌº²¶à�ã¸~?=w§Ą›A×§E¦lÇKì´SŒnXT7׳MbCvFiŒo·¡<ë‚EZž0LÖV aC[S7šíf•´mZ?k»±R�&JÆš®ÿë‚I4ÖGzÞ$NÔÛ*Õx?m“,Òú™>êmšûl‹T�=šPsÞûYÛÎë!ìèEC¼ïFÏ9}Ì“¢þ;hA×.âˆÜö�äŸ< OźPOÿœ‘—‡é94 =Ñ5\¢ûöm˜¥g¡*#°÷AÊ't®Zž;&¢ÔûU‰°�¥xó}8ÝI8Ìð ÔÇ<û×M8aAá%Žr™3gË{‹ô\3ãn°3É<ƽ-ÆÜöõÉœ¥ÐÚŘ­ÝÖ¯$ Óˆ�Œ¢3‘#éu¶Ü=DþÀè°TŸG3:�,ɨ©UœB. ×£ºjá²€üCáï…ÊÓÙÙº¾µØŽå%.…mwôY*—®Çær5£^‘º8’ WÑeÝ L(!*‚ ÂÔ±ýûé?8ƒ6ã*;vîeÇδ™Á†eß¶‹Ç'¯Ied„íÏ‘-AA˜MâAÃuó¹y�ÝÂF"j$eN“M-sfí6„¬´B¦0—¬ˆ@Ž &F×þ�$êbDf|© ¡­_ž/â1AF×®us>Š8¬÷=•pÇÚF!"ãA¡Óg‘ õqEca M¯£Î”¥^Y Ý”ê˜mmC»æ6 õýü¤sšXàˆ“ïs´)¢‡‡1Ý]™›Í‰F“sãy”Ï<…êÀ ¦«cÜý†s¥Ö�@tܦgV“°‘©×´ƒ‹Æ ŠØZ8Œì¢"‚ ‚ ‚ðüƱv¼ �’õ®¨…Ž´ I½/j!-õÀ”VâHF̨ÛÍ &iY&”Å�ÚŽ¢McÌz\dŽ)Y¡" ²žÍ^ÍÂF:^Ý¢nö9Þ¯{˜´Ê©™vZIYÃ(Õàq¡Û¼~õz©à“zr´¢. ÙFû­ÆQƒC’OÄ F0íwQ™<`篢ðÈÈ>¼I²—šYÝ�‰EÈx„h…éžÕª×6†-ùÃÎY…ª¹Ó(ÕAAA„çí»M´5¦l³EY6¯F+ûõ²šwGË<MöÄ‹iŒuJõ§Xw¢ûé=e¢ñBÍ4ÈŠ¦Íz[[;V¯Éƒ£Ù{­Ä £ZG�Xíûm"DjLâÁ‘tl½¾ZD¼i3•ukÁÑ� U/h!PÔë5†›ÔoZƼ8Zížbcò¿x /XÅ4ÑH !*‚ ‚ ‚ ÏWâ0Ù"vŠ"LO蘬î´D˜ÐË$§,�¿_KÎT¨êÉC(Ž™�UÒyDÓx= µq4u'³Ó|?½V&B‡% í=8¦$å¨8Âö.¡pÈàÜ}?å «1ÝÝSi:žT¸h7ÆUj¼ÖCä| ¿<ÛטTDBTAAAž¿„&Æi>Ò„J¿ø�ª=©×ƒñÇRµjÜ÷ðU�þ‹ªAeJ¯Çó£ycµ;îõhfR�CeÝ^z—à‡sðïyŠØ%ΫZ�KšTev<©yq(Õ¨W¨L�¬ÇFݤ¡2X‹S²¸a3wr c²JKhŠ ‚ ‚ ÂógŠßþOEܘH™®@2Yý��°Œcm[�©Š­úlU6Á¤¹NöZk¯U¸MXžÖØ&bªõ'}ν¦ŽÉ˜8DÅT-9‰ÕNrîxØEëpMŒSssQ&»Ÿ©Ûª¬ù|¢{õó|r®M »V;(k$DEAAáùJº nò˜l¡ß|?½ž®‡G»ÅsÎT¨¶³UsÖcÀ±vÜî&­Æè¹zBa¢ÕXZ•ME0i®Óp‡„qŒßÔÆÓ&h9šŸm»g?Ù¸Û‰2“ :éy»ö¡rðµ‹bb‘cÂ$£Y¢Õ¹2qÃy«û“Ùšj½‰úï?ëÝõAAAáùƒ§½tPhXL§´Zô¶ºÎ™J½]«öílf˳ él9€_Û0C×v­×kJìÙÜŸñ‹mí¶:Ï™J£ý¦q¤÷�Ò-ÛeÛ7·°iÒO'76æx¼HÐjSy†:(MúL[�«Õë”mß܇g5„v}:Õç¢"‚ ‚ ‚ðü$·wó³c÷Y±šÁ+e<8 Vº)åýÂ$÷ëxÅO”gkÏ:MóhÅ‹Bà�AAAAxió¢8dAAAAxió¢8$DEAAA^Ú¼( QAAA„—6/ �CBTAAAá¥Í‹Bà�AAAAxió¢8$DEAAA^Ú¼( QAAA„—6/ �CBTAAAá¥�  £ Oá·Žé`f†÷ë‚ ‚ ‚ ‚ðpÜÿ”ÊAëÁ‚ ‚ ‚ ‚ Ži ¿ý“3>A„_¾ø©c=AAAxN°ÖÇ1›·láî»ΪU«Xºt)§œr AÀðð0ƒƒƒ<þøÜyç]œÞy¬\¹­g6¨dÚ‡ ‚ ‚ ‚ ‚µ–0 ùÑ�o```€·¼å-äóyúûûùö·¿Í½÷Þˆ xó›ßÌqÇlj'žH?7ÝtÛ·o碋^‰ã836ÉÁ!‚ ‚ ‚ ´HÅ�»î¾›‘‘ÞùÎwâº.CCCüéŸþ)?øÁéí›ÃM7ÝÄg>󆇇9pàÅb‘7½éMìܵ‹‡~cÌŒ�IAAAA¦EÇ òàòêW¿š0 ‚€ ¸é¦›ÐZÑÓ;¥7Üx#q£”bxx˜r¹Ì¯þê¯òÓŸÞL¥ZÅZ;#c�CA„g‡`„Cý9pð ú�^"} ‚ ‹œÔ{ãŽ;îdÅŠôöö†!®ëR­V‰jbÆŽ�;QJ!a¢µFkÍèè(Åb‘ °uËVâ8ž‘qIA„ç)vd�ífÌiO‘ï;ŽåsòíZ0¼ç vÆ4ðó–GŸ¶|�mO¦Z³åÍZÊÊùZ毶öo{šÃabIù½,;~.…I’]Ïô˜…vXÊŸà¡MO²÷P‰Ð-2{Áq¬Y"K:§ÇjKì{jG¢äÉëÎE¬^Ü5þ›�J?Ûv¢R»lû»°cÛ~J@‘ë]Ê’]Wò뾎ƒp–ó¾¯}•ß\9sq¶n:v}?Èßš ‚p,1ÆP©Tصg—]z)Qá8J)<ÏCk�±– \Ábë†RªþS.—Y¹r%›·lfíÚ5õöÏ8Až§„÷ý ïÿôÍTë«Eþ¬�ð½Ï¾š¾VÿûãǸæã¿ÇןÎ(àîjÞÿ/_â½Ë5ÊâÖÏ}˜¯ÈŽè;ñ,6Ì{þ¼]Æý÷qõ¾È5·=͈itçT¹yœzùoòGW\ÌòÂ$†ìÿó÷ä ›BÜU¿Î׿önV6=öÑ»þ‰+þìFk]©Â+øôwÿŒËº_Ðhó7øÐ|�½P9Îþè7øÛÅÏ`¢Â„¼hþÖA„$©ÀQ.•˜7oÆ”Ruûöígdt”ÑÑÑz»TÀH�ÆJ¥Qãûö òŽ&‚ð‚ÁR}äîh£o»‹ÛwOàÞç¯äí}ëk_½›þŸðù+ïc¤Ù\ù!¾ö…ÿf¯±€Â_þ&þèm'�;c>FØÃ?åsŸøÿ“ÿÍ¿Þ_af¢BŸ9öð|æþ?¾rËŽq‭àþkÿšßùôÙ9Y¾.=ŸSOY@êÓïÜÌ£CÍ6#{d åL±­næÁǦz†ý›·ÒŸöé¬àô“gá.½˜ßýÃññˆ�ÿá»yÅ\ùØñìñÂü[A^xXk±Öqc­ÅCÇõk ½½½‹fÏž�µ¦Þ.ý¨T* ÆÌÌ{Ôóô“†bá|�µ }Ö.té›âgÊwXµÐgíBŸ5}/coî\�µ =ÖÌÖ“OZi-Hê¯êV­Ý·Ÿõ1 )^Ñå´‹¼þŒNÞrZ‘KVú,:º•– ¼`I\ùÀ–äÖ{†Z,¸ ;1Psûk…¿òÍüñ»Ö&á6fÏõ_äʇ*™¹ú |W„”»”7~è�lhçõþŒù¹ÇrèÎ[x°ò|‘5R*üüª䇻‚äµÑ=l¸ü·ù_ñüõÇÞÃ+—ækïW†�{¾ÎÕ÷”'±ç°â”“™U{S´áVn.Ì^Þtˆ­Ä °éá]4~ ©²eóS¤i.ô‚“8m¡FÏÙÀe¯}-¯Ýkyýå°¶ûùò¿¸xáþ­ ‚ /TšE�ô< C¢(ÂìY=ÄQ„Vª^ÇÓ p”Ëe|Ï�±$£3ês;G`­ÿ8sT?žªR±y™>žŠW²/^0õoÀœW¼£�Ë –;~¸Ÿÿ"ž´ýñgöñoz¸@¸k�·üÛ»k�ŠËzøâ«rt†ÿüõ~¾~ ½µ%§Îæÿ^–§+ øòÕý<1tlÆü\£sK:áÈ‘˜á™Û©çèñ=^ýÊYüÞ©>sšÂ¦MqÇÏùÌ<Æ*¼è97' ÌãìÓ«¹£òòç¼½x)‹öídgTá¾Ûîcø’‹hX+šÝÜ~Ç6"@÷-fqi;K­þ™x¬zˇùõ;>È—7•±ÑN¾÷ùorÉ—Þ˺�‡¿¿v;¡”Ã’ËŸ+6…º1£cN±TúŸäáMO²ûÐ(�ÎÑ3ÿxÖo\Ë’Ž‰¤ë˜á][xxËvö% GלE¬^¿�æ2¢·ah÷“ì⎮¹þ[Fö=Á–­…–¹'lõO<²‰­;û)ÙÝs—±þ”µ,m‘à ïáñ=IÎåÎbéŠùtT÷ñÀí?gë€Ë ç_Æió&˜Gå~~tsMlÐÌÍ'ùüGϤ€—sþ�+Þ{%›# f€‡ÙE|öj&Ê:‘[w 'å®çæ²3Ì£›vŸµ²ÞÆŽlæ¡m‰”¡»ºébØž~øQ슱Pˆè)6=žzºhz6žÊjly?O>=@"›ä™{ü2æäŽþyLçyO•£³9Õß©™j713ÿ·Ø*‡¶=ÊÃ�ïâàP¹Næ,^Áúu+™W?ÒàÈÓl;PN^OÝÍ’U éÌŽ¡!¯O»|!Gÿ|ž�ß A¡=J)ÇÁÔD c Q”|ÕEqÑÓÓÃàà …B‘¸&zdééî™1ñ}ÆŽÕz gtlåÂó^FoïÙxžG©Tbßþýüü�Ø:ÜËæìiÛµ(Î8©À‚‡FØ;Ñ{±ö¹lƒ‡-DËŽûŽð÷Ëæò§k|®¸¼‹{ÿmˆMͶ€Ó×É'_™§ý·áê}ÓWffÌÏ=+Ïîãß^nù—òïÇx0Úå o˜ÃÇVj"n¿¿ÄûbÊ®fõò"¯=Ñã¼ó{Y’;ÄoÜT¥tŒ‡ûR@å=^ó²Në°üìŽAn8Ò¶& —wðÖSòlìÓ¬eïþ*?¾w„÷ÆëQÓ¨¯4kNêäM'xÌÓ†mO•¸úþê˜[|šsÎíæ—¼*WÞRžøoq†ž¼�ҾͬzmWüÆGø—ý ßûÉW).XK÷ÊóŽÎèQ Šë8yåvn�(Ý;÷Œ^ÄÅ�c÷ÍÞ»¸ýÉÐtŸ¼�ewìfg;cÞ ÞþÑwpû®äá²%xêZþî»ò•_søîç¿Å–j²Ñó™¿ïT:Žòýf&ÇlŽü‚o|îsüß[Ÿf´!4C¡ ‹8ï]å�ßv2³›V@•?áŸÿÏW¸îý™\µ–ºÈ²sßÎG?ükœÑ«�€»¾ôA>}[�©ò‹ý0¿ñ¯ —¼•¯~ý·Øàfˆ‡¾ÿEþöÿþ”'†Ål•_ÄËßþ‡|ò]§Ó—OôàUüΧþ‡’Uü%>ó�7ðÄÇ>Ê×-añyeïEœvÑb’:ž×}ìœ>0ÄÐp‰y/?µ&n$8‹V³ºK±ùH23•läÅ œ~¢Ë-†X ;Ý ]Ioí5·>ÂæÀšÞsÎgí×s[Én}˜MÕ_áüÚpÍ¡ÇØ²¿ö‡¨|N:m>mùØ&Ñç´žÇQ<ïI9J›Óû�zæí¦ÂŒþ âÀ½ßáó_ü7o!nkò÷v΋¿ç,©''5¸áo¹âŸ7ªxsÝŸpA6yi¼•kþø#|w¿–½ãùæû×ÔÅ´£~>ÏÆï† ‚0!i® Ïó°@©T¢P(4Q1{Ö,ž|â :çÍKD�&o€ƒr «QzfþQψ�€5ÜÏ[Þø:–,YÂUW]Å™gžÉ÷¿ÿ}–w¿úš‹Y¨÷0×îžžañÔ!‹¿´Èe}Wõ—¸´E ¶ZÈØ˜ÿþï®A'Ÿº G±¹Žãñk¯éæô<yb�?¿'bÚ»ÊÍ䘟S4ë»Ï›˜¥ž5ÝüÎ �ª|éê|ø†a¾÷P‰ÿº„Ïï ¸% ŒâøÓº¸¬ëX�öÅÏÜã»ø»÷ÍåS/ïàW6æY×vÅ«Xî®~[¿¶ÊE—böŠõºøßï™Ë'Otš~ǦS_±êœ>¾üËfªrë.8õÂ>¾x¡O«\г×ôð'ççÉí¯r:e�Ò¾Ílù�OqÁ…çóø¶Í\páùlúÞŸPÚ·ùè�6ìeãéKA´t·Ü—•õ -‘•ãä“O@µÈÏ�Å[ñfþø]ëj¡*6_ó9¾ð¥ÏqÕ#µoáõ\€Ÿ�æ IDAT.ûàû8§ëèÕôsùQþåcŸàŸoÞÁ¨±(·“ūײzA'޲˜ònnùÚ'ùãïnoøŸmßÌ_~ø¯ùîƒýT­BçzX´l9+–Î¥ÃUXSbûmWò‘�^ÅC“Es4Ll”¾öGüÁoâñá« Ì[}2g�¼œ>_a+{¸ã_?Åïé~†3SRù"ùÚã´ÑO\÷U®Þ\šºÀ�[Ä)ç_̯¼öõ¼ýïà—–7~Gaöoc[šPEX½zé„Þè>N9eiíïÌ>¶‰-uñ?æéM›H\,XµñbÖ.M,šÑMüâɱ§]}ìQ«]*÷Î8©cÒðÎ)?�£|Þr”6�öwêYû]LíÏØÿ‡˜Ý7ü%ïÿø•üd["n(å�ïì¤à*ÉßÛ�ßø_¼ÿSÿÉö_ Gý|ž�ß AaʸnòYdhh¨îÁ‘þXk¥R)3:2R÷ÚHŽJ¥‚Öšýû÷ÓÕÙ‰ž¡ÊYÏ.Š6³ö„•tvvâº.ßþÎwxÝ^ÕW^EE¸ŽÃÊã0+jÿ}AKlÌ=O…DÚã—Oò'p7Qœ~R�î{:Äió\l©Â?ü`„í±bù™³øà �ù¦X}ö,Þ¿Ta‡Ë|ö¿JG÷�ï �9¥ØísöÚ"o8³“·ž^äÒU>‹'ÉC¡\‡UÇå¹tco8­È«×æÙ0[�ûÀÛÙã±fq�—-H~©æÏóY»Ðce‹ü#ÚwX·²Àå§uòÖ3:¸t•ÏÂ6ÛË©¼Ëš…>kz“>s=>ŸÚÁ×ùÌžx䜲:G·‚C›‡ùÖ¸Õ©å±ûF¹'åz¬Ÿ'±ÄÏÊáÜ‹çrÍÛºY?4Êî´.ÆÜù�|â<Ÿü¡Q>úå}üú7ñ¡«ðú«ùyàò+—us^þ(ë»>o>Ócø¡þä§#\{çþ÷ÝÇ�ÖÙ`@óüþ%ô–A>·Ù<3)kÿöî;<Šj}àøwf[vÓ+ ! ¡÷P¤÷¦4±^Ák/("–«^»×öÓk±‹bCš‚€ôÞ{ „’Þ7eûÌüþH! $›p=ŸçñÙ)gΞ™�yçœ÷°çD±M›Ò²EkB¢BX¹;hœ`­yTb{t£‘ ¨ÅlY·“ò|Ôj7Æ­�dlOï~wo ùM�qWû’¼ š}?ßÿ°§t¦ ™ÐÁy°o`-s]Ì2kd¯ú’ïʆ?È�ýÊ—ü0çC¾œ÷¯ �(ù!ÓììûîG¶;Ëw@Êï?²:GECÂÜé.>[ð?}ñ ß|õ¿}û*×Åé‘Ðpžø™OWå¢abГ_±ð«Gè]~]3Ò}ò\þð¿L¿•6zpüš·æ'–$Þ”Cøäl~˜3…÷ßÿ„fN¤‡¿ šƒ?MçëŠ9-tº³×_Ï1ü´¹én�8™Ç&ÞÂÀØ:vªÔä§§“š|‚=kçóÊ Ÿ±¿´û¿o»ñÜÞ×÷‚›M»t"¬ôn@-<ÂþS¥ß„fåÀþ3%½¨ä&thßšŽmKê[ÍbßþÌÒV '-OD*Çt¦Km’‰Ö²>¼®ïóðn›Þ´©ú¬W t}PS󯔵¤{Jzíø¶½ž×¿ø…UK²rѼ9®~2 ©än™É›¿¤TÓ+¯®¼¯Ÿ‹Ñ6A„Ú)›êU–e¬Vkyî�²ž999ȲLaa!@ùg�›ÍV¾\Ù , ¡A†¨è܆WÊ„ZXXˆÓYr§©( ƒÉe¥nY4%Òíj¤m{ ë\쨮K…�£ZéÀnã�3}ºÔ¼Å¢S¼´ÁÈÌF®Èæ¹y¬)S”Ï÷3â£zX°$ŸUEu)çÅ+³d1rëÈ`în­?§›¸êô°rM¯os�½‘@¦í�Í�ûïåÃ.4ÍÁÞK9|ÝÚÕ+Í…·õs1Ú† ‚PWEEEh¥ʲŒÇã)~?~œìì,|}ý�KÚ*öîp:�è òó­çßI4H€Cu£“#p:�¨ªJ�µ€_~ZŠ��©<*š§î™$«�•éþ´klfL¼•ÇÎ}¯ÜÒB? äî±³Õm¹@·�Cò˜ΣM-íéÖÆÀïÛ\hš‡ÃŽâÛýÉ,R c›ö´1Høµí@3Ýx4‡öqØ=”+Ô£ìO, „ YHèÚºî3‚ÕT Uß ²MoÛÔEj‹UÕ÷\SϰmGFy� }›� j\¥"åÆôëÏÌGðJÚv¥©´kRŸ‚{Y?£m‚ µV6JAAAùŸx<Ìf3ݺucûö팿AæÛíôî݃ÁP>D¥¨¨—Ë…GQHMOûsÍ¢¢¹‹±;8�ÎÒ+xTó[évW0Ûñ^�J|# gZ/¯vVé QG Xf]”…qq2²êæËŸrù¸ÂP�]'œÒ5bZWCº™ùàH1Y¥]Ë{´÷!DÒ8¼!‡§7z*tu°j¿“̻¸9ÀDÿFp82NÛX”/1b�…8Tö,æ— IFõQ~<ÞÀIñðí÷ÙL=ULqs8ÙÁ¦Œ`>»ÑBǾŒÜŸÃ/e³Îh ‡˜žWÄó ØÓM¾afºÚ�æ²Fò®"–^ꄨešBbf-—5êij®‡ÓÕôVr=œV!&Ä@cÙα:.Ÿ¤� ÈNI’�Ñ(N.ù˜˜t•sb>ïPP%‰ð`f�JJ�Z‹a5+t”žÅÿë¡)•øÐ¹_ý�<5ŸMàìÑ’Íë÷`×@2´d`ŸH$jàpáówç“èª|LjÑ.>ž¾œ>¯� ²Þ Qf ÛéMüôÓ2ÖïMäLv6‡·Çƒ¢ª•¾’³—i2üZú}„Õ¹*šZÄñu?ðáº@’0ÆÐ¡[/ Åè^±œw–Š”,Ò˧nÒ°­}‹kÏÓ]FIO!ÕÍ«¾6–BhÙ2´~ãDåp: N'iÇ9˜˜IÒ–Å|²e)ß-¸‰×ßš@�ÀZ:¤ ºÄ£Ûv*E‡’¤ô$äÐARTñÚâ/�ÙžŽá2ÒTÔüÃìOUéâ<Ì¡âÒÇLC®èèÍœÂ5ÔGCÕwƒlÓÛ6u‘Úâ9êy®yÒ8“Vv•”07޿ܑF2‘�¡“ŽàÑ5“ÔLšÔ§ ‡—õs1Ú† ‚Pkš¦áp8°Ùí¸=ìv;>>>å‰Fï¾ûnòóóùöÇDZ¶lÉí·ß^Þ{CÓ4 ±Ùl¸=ÒRÓPKÿ½¾/$Ž­ºläçåáp8°Ûíøù•¤îö÷÷Çétât:±Z­(.oBY‡mlv‚_s Cª$””ƒÌŒŒ•Psl,M®ýƒ‡jµñß_m¤i2­¢ôè�Nf.*âP�³Š^¼2«YÅ<17‹û¿ÉãûŒsóPìIráô!bËÚ�$X:,ÅSÝÓœÇÅÇsR0%‹Ù©µ9‰,4“Á~¢�ÏN�Û»%ïX! Ò5$£‰­*$…ÔJf‡‘�°}c{½ nÈnÊ”ña̹/’¥÷…pM€‡?Öæ2i¹ƒÚÌâ+\|²Y&XÕ®�_]³ö¨ä»@²È„Hu_^-TÈÒ$BýÏæÎ1øëF!£°d¼øƒkròá2ŽØ>z(ŠÅ1ÿ¡HÞÀçd®½BÇŸ#’fîÜ—^þ%C0rvlãhÑ^6ïv !¡oÕ�þQµ½¬»8ü;Nt¡’¹-׌íP:Nźy6¬Êi€ñõõ-³JÎÆiÜ3á¦ÿ¼ŽÝÇÓÈ)°£È>èSc#9|8/NyŠtŽ R‡MÕš�+çóÞ³¸ù™9RÛÄŽš·RûßÍ]LQuCÿ% ~õí½¡oËøç^àµWþ�fÍÏÓï¦[i=žÏk³¶Õ2`/Ó$!¡<˜¥¦â`ž“#Ž—L,‡Ð¡}Tɵ]ßœNmÍ%ç rš#‰6r–B@׬3 A^WMõÑPõÝ@Ûô¶M]”¶X�z�kš §»¬^$Œ>Õ'ú’ ó‹¹p¹ª]¬N¼ªŸ‹Ñ6A„Z) Rdfe¡×ëÉÌÌDQœNgyŽ6mÚðñÇ3oÞE¶fƒoœ?Ov‘Ùú[>‹í&ž¸ÝŸ™Vný¸ˆd_^¹5�ÿ t2îW'Þ¶®´±£Xô´èÛ‡èZÆ7œG¿åÍyÇJ¦c”Œ´ÿ(�Ý¢§ññ™yÀ�¦æñÇÌY¬»âizóÀÚPevíã³i‹Ir”ä 2·ºŽ—_¼‡~MÌÈ€çÀÇÜ<ù;ÎÔp�17ÎãÓ†21å Û¶ïdçÞC8|˜c)¸4 47™[>æ¥/ÛñÅ}m/<´B6c1Éà* <âE¾y¨KÍëI:|j¬5lS’ hÿî²€]¿ä ¢’µy‡Ü=¸¢ãEô-èìÿÉVÍsœƒ‡Oq¬dFÉÔš„–e1ѾC ô«öàÖÜœ<~œ}™ÇJÏa™¨„šxùê¤ÚúhÀún¨mzÛ¦¼-V§>çšlÆ×\V/ö¢âjœn› OùùfÁ×RͧVÓcNsàpœ»h™:×ÏÅh‚ B­©ªJò™d z=‡�¡il,‡�NWi¸IHHHy¯Ž2‡£ÑHÒɓȒDAa!êŸ*Àá,"??»ÝŽ¢(Œ5Š‘#G¢iN§³¤g‡Ã�ÇámæN�Í{ídvð¥}' Ͷ�¨²‘‘ è<.~Ýï®Ó›FÉâãWûÑ\V9‘©adÂv|YÀÁ‰ð7P™ zzwöåêÖ&Ú‡ë 3Kª&­²ßƒò˜Ý8”ûâŒ\?2Œë®RIMs±ý¤ƒMÇlLQ8Ï=Fe’ŽˆÒi"㻇òMÇêŸ" –’·ê>þ:%¨˜Cs+dÕã�Š‹Ï¿Íd‘AÂbÑÓ2Ö‡±�ýx¼½/7íËãáÅvRE ãÒSÁ SýÔ”èu¥ ¯–wóÃj#nbÖ->ì÷èë²K6òð_‚OZyt�‚.ÖŸ�þ «—sÌ 8m|{ÈŸémÌt\îd«cUʆ¨œ™ÿ Wôï†ßª?(Pޱàë rT@ߌ�ý¢‘áÂ%t%òõ{ßr¸$º�¡é <>¾%&Œä&VNþ’£. 5{%Óæ ¥ëã=¨Çl±õ*³’´�íY¥'¸d Ë wп‰¹¼�3#í‚9}@Æ7ºƒ¢;0è[ê¾}÷ ælÏCÕ<œÙ¶�ä{Û¡‡s]1�e8RòhË/FöõÃï÷rîù’çæn�Ü‚`nxï}în^ñì)™�¾Œf+:Ä¿c{º¶7±d£M-æðö?È*í–¡oÑ‘våyndÂ:´'Z·‡“ŠJê±ÕlI+�ÚU s× scQæbÔwƒlÓÛ6Õ€m±Zõ¸>èbh«ƒ}%õâ\Ó7ˆ7îŒdÑ=Áü£±\»,íJ[‰$KõÕÿ'¹Rò<¤ØÎ�šiŠFýbFé™n¦¸Ø~ÌÆ¼•¹ÜñY>›m±ƒy¦³®a²P/šS¥HÙ(Wƒ)˧J¡V÷åòŽås×Ü<æ�ò�‘VÌ›_dñÜ>•Žýƒ¸ÑÏÅŒeŤhà¢'PS8�Wv‘ÔHÍõ šõÄzy‚ÿY†¨X®èOw‹š‡¬Ì\T@ß—�1µ9\$Ο‡K¦]•tÑ\÷è­”¥M0µÇ×Ç•R5•´¥Ó™½»>Êú•Y³c«ð['˦¯vŸä矷VøÜCù W*Û~ý‘¹3§òò«_°¥Ò“¾Œ¥qwn½á Ê^>kn¥úžDhØm¶³…rcºuiTzÍÑpí_ǺJ•ôuŸóÞGs™ûíO,ÜtÚ«CÕ1økdì?ıÓéääaÑüÍäVx^ÔŠö²rKVyÐ[kDDmS#H~$ti^zýV8¹bûK§ �l×–ˆ _“®i:”ÌŠûà*V¦”D %S;º¶oࣾ½Ý¦·mªÁÚbíx}}�#éݧEùKOÒJï¯\›ZÑ­I/OìéÓ¡=%@Æ?$èì Ï1ÖnÌ<ûF³²ù»%­n°·õs ÏEA„¿»’!*�••…¢¨äç瓜’R2+Šþ¯:f³™IIxT§ÃñçêÁá²#Ig’“‰oÚôœÏ­EEèŒfÜÎzü´¨.–îwsó@Ã;ù8ÙE·Ž>4’TVﳓ]‡MÅt â‰6:(´óÎo6Ò0kI1=nõ£y�`&ŸÈâí¤úͤRÿ2K$ô b|¤„šoã¥oòY–W¹D†fA\ßÁHµéÜT•à yý@!’^Gó=›ûpeÚDZx|¼Œ{n .ô̦iØÜûÖfñÐNå’¿¿p娸ò�?=»éèÒÚ‡À�Åä]êBýÍivÉ6è¨'J†“UzIÈ�zëÀ“ç!E­ûòe 2íÌÏ<{-ñ‰à©+tìY™ËÏ¥�Àd��ÐpT¸™vz@“$Ì^õû.¢bü Q$ßn ìfaÕšâÒóQO|ÿ~ÄÕ"¾á>ñ#o~u˜’2Q£&3!¡Â44˜étÇC\»þI~HVД~žöÃgNÀ›Ü‘õ-³Ü¨1‘:ÈPÍÍöog³¸Ñš+'Y3ï¾>` Àß…µP-ŸCRp%ÄaÔ;Ù÷Ó,fu£Izöz,®p> IÓ(ö2!^‘à þ^îBò£gÿ.XÖ®/‚ ‹a@¿Ø ÷dòœä»÷¾déT»rØP¹·û¹ÃO,�¹ïá¬z iª†ûä�¼3o ³îjEõi/^™åF¹ºÇWìÛP€Š†ãø"þïáE¥Ûô¡ÅM/q�ýž[˜�ª¹Ø?û†|Õ�'¿y�qýƒ5OÍãˆÍCÊê�xdõGÕ }£OÓ�-l…=§<(@ãf>5ÎÞØ‡Î!rõ¹êL¢]Bwôôã®NFªïð¬£u¤p*"¸ñ§ ²i¿�„UlHF#7_aÄèv±ôPY ¢®ËW%ѶOÿ r1ç×bNUX¨0ÇCzš†–O/DÓp=r‘›¤êÆuÕB‘S!;Ñ…^ òn J" {?º˜KŽOÓ�M/töyHúq Ÿîw”>T3hâ}ô¯6�¨„�{xtXxÉ5Bsqô»ø.©>ƒÍ¼)3 ‡3ú©W™Ø¿ ¾òÙïSç×”!÷ý—÷'ö`à?ïgdœ¹d aMCÓ„þ°é IDATù࣓ðít¾ÿonîO°Qªrm“ÐûÇÒóºGøèãçQq>\9œQ=ÀП ÓKüü±ÈbǼȜ·îeD»PLŒ%ŸðöŒšøŸ¼<ŠØMHú&WñêÌwyìêÎ4±Tj(aŒ§ßøg˜5õºÔµ7…±dŠ×ŠkÉ�ÛÓ!¸ê…_&¦c;‚*þ³B—ÎMè7 ª‹QßÞlÓÛ6U�¶è/ϵ²²¶ÿ'ïÍ|ƒÉ#;eÖU*«¤ó%¦ëX›2ƒ·®‹¯ð”‚øèë<=¢%�ú³çªìÇ�‰oðöÍ�¯0 –Ãæ,½«Oý\ºsQáïL’$t:q±±X­VüýýI:yƒÁpNBѪÜn7F£‘¼‚"""ÈÏÏ'ªqã pHaw¿¥!•üð�~ÿþó.|hïN&®lVígjÊ& {Þçª+‡Ò¿_?¢££±Z­8x�ÙŸ~…«Õmèâ‡×®T:^x$”«M.ÞŸ™ÅWÆ´ á§ëÌèÝ>z…¯¿È䃔³O·Æ6!¬¼ÁŒœlå¦/Š8û‘LŸ‘á¼ÓU�–]ÄCŸYÙYÍ´¥ÆFþ̼#€z•õK2yb�R»ä¥ ]fIÏmwDðP´DêŽlþù›ól¾ YGÿá¡<ÝL¬'PqðÊ´–8@òcÆý�tV]Ìù:›9©UR"ê L¸=œ{£`Dz &o/9>ÉÏ—&ÑCöðÕ發_¡|r /Ó&ÑÓ¨²ku6ÿÚè®”ûÃæË·Ñ×âaÞ—™L)�ÎÀÄ›} ¶óÈùl©CbǦ½Ãùrˆ£ÛÍüŸr˜–X±çˆDÓ„`¦�2%©ü±0ƒ§÷7À�"á>ѾLîd(ïêo¡G?jcoi'%ÏÎìÍNò$=×ÜÎ3-$RŽ3ÿ�‹|½žÞ]ý)qpM6“Ö»Î&¹­ëò#ý™u»?®µ™LÚì©Ü³Hgä¡ a\[XÈ# ŠH òãµñþ„ìÌæ¶?\Ô¥Gú†YLºãƒ‚(R|(°¹I9�ÄŠ¿Ù÷¾j×™9ôm;u­Ã^„ Ópæ%“”jÅm &6.šÀŠÑOÍEaN.…š™�Ð@|ª<#j®B2ÒÒÉ)tâ‘ ø5¢IT¦óÎPë ;ù Yv ŸÀGT³¼Š3/�Ói¹+:üBXyªË‹E)&ýôi2òm85þaQÄ5 - ÂüU]Œúön›^µ©z¬wIxŠHOI#§À‰j  QL4– KÜ…©œ<“‡]HL|4ÁÆÚAÞ×Ï%<Aþ†Ün7ÙÙÙ<ôð#8=N'MšDxX‹·Û]í�›ÍFNNÉ99¤§§³oÛ6®¹f,ão‡¯¯Å« GìCQÓh°x¶ÝOh_âÕÓqçžDçŠÒCŸ7Ðù7n�ý·±ºØÌX? %ÃÆ¯iµ{¬ oÄs]ôè_\PmpÀ•QÄÿ­õaîP#}†scr6ós.A™5«ö¹¸;ÚDTצŠY‘®bò7Э�™.:/ÏwpåíÁ 0š?Ôù„‹M‡mÌÚáË´žFî½­=ŽØÙš¡Pà‹ŸžN­Ìô“pçñùþ³ÁÍîád1ôÐsÝè,I°;ùx½ƒ<«�·Vø0s”]‡óuSËOxÈV$Â#L mg"ƨqf—•Ïkš«±ŽNnËgF³0njছ10ÕÉî,›$e¢k„ŒÈ:b僃"¸q±B}¸¶«Ï9½hZ´ö¥EéßÝɾÙâ$_4 ÎFÄý�üx¬eI� w±›å+ò™²µJ°¢®Ë—Ѹe„?M3 ¹g›çÜaSŠ‹OX‰º&€9� ©*ÇZyn}Ý‚–ȶ|ôù�Pñ-IX"ÛÖqKBýH˜‚chSÃÇFüÃ"kE$ý‰Œó'².»”}‹mIØùÂܘ–Á óW':_"ãÛÖí˜.{£¾½Û¦Wmªë]z?"ãZÖ¹¬ÿÆ´lçÝwä}ý\ÂsQáoH§ÓáëçÇøñã˜1c&!ŽÙlF’$TU­4ù”F|||(..æôÉ“ i :£ÑËDyU4h‡=É'cëk¡õµ©›*àr²ä Â˜2÷Û9Q‹îº`_ža&\Ò8°!�9)ç{Ö8±5�™-Ây4ÎĤ1þìüª�D/¦•¬O™Rvæñ|`0Ït7Ñ¡“?:•d¬M?Y̳K Xc…´M:ö7Ѻs ÏÄñÀ+;Vfópaô0Ó±½ íÏnSu)ìÞmeæê"vW|rTœ|³ÊF¯ÑbÃ}¸>œ'=ÌÝhgvçro¡“ù10Þ—»âÏ®j/p±xMnw’[�jªÄãæ›ï²8Ý+€{ºúÐ6Ú‡ÑöiuñÛ¶fns’Õ0 w…jîÍ¡ßÞº­£¹Ü,þ-‹¥+e"uø(*éV[ ßS]—@qóég©|zžEléÅ<û± __£[!ÏËÜÍûм¿w+ ‚ ‚ Â_�$Iø˜LôéÝ›í;v°uë6rrséœ�€¯¯/z½EQp»Ý8+Lëv» çÔ²e¤&%ñÔ“Oúç¢"\<²QGÓ0þ’F^¾‡3Å•‡�èŒ2Áz�|›VåM¶„_€Žh³‡Br®BÑyu&1�2¸Ò­jÉL U˜ýôÄ–l³°ÈÙ|µÎoÅëF" POc? ÖB…äõâ';/‰!*‚ ‚ Â_�ªª8222ùpÆGìܹ‹'M¢gÏž¸\®òÙQ\.WynŽââbNž<ÉìÙ³¹fìXî¾û.üüüêà¸(CT„‹Gu)œH­¹ ‰âRÉ®6 QTàáHAí÷¥8Nfž¿»Š½ÈÑ¢ó.ÒÀ4 ¬n jœJCAAAø_’e“ÉDDD8OžÌâ%K˜1c_ó £G�"::šˆˆ©©©ddd°qÓ&¬ùù<ýÔSôîÝ«ÞÁ�ªD€CAAA„:ÓétøøøÁ¸›nbذa,_¶œ Ö“‘‘INNF£‘¨¨(š4i€þý=jAAÁøø˜Ðét ÜàAAAÁK:�Y–Ñëõøúúrûí·1~ü8Ün7Š¢ Iƒ£ÑXþgY`£!ƒ ‚ ‚ ‚ ‚ Ôƒ$Ièõzt:F£MÓÊÿ+û\–åò€FC6ʈ‡ ‚ ‚ ‚ õv1zeÔ…|Éö,‚ ‚ ‚ ‚Ð@D€CAAA„Ëžp‚ ‚ ‚ ‚pÙ«sŽ­ÏE_Œr‚ üeìÜ|¢ÞÛHKKk€’‚ ‚ Âå-**ªÖËŠ$£‚ Bu¹� ‚ ‚ ‚ †¨‚ ‚ ‚ ‚ð ‚ ‚ ‚ ‚ \öD€CAAA„Ëžp‚ ‚ ‚ ‚pÙAAAA.{"À!‚ ‚ ‚ ÂeOL+‚ Â%µyË&¶nß @�+zЫgïK\"AA.G"À!‚ %®B² h: ÁÁ¾êz§Óɺõë9r샇 `íš5Ùè߯&“é—PA„ËÉŸù¾GáïM³‘v"™|�Vå YÖa4J€QŒ6¬³òº•ð‹jNLÀ_§][ÞgÜ +±G�cÖç÷ÓáOüK?ÿûï¹êªèM�;v ''‹6-Û3ÿûï¹íÖ[/Â^U S�“R¨a �#>ìÂAÍžÅá}û8–œ�]ò!´I+º$´ ÔØÐë)%áÀ©\ÜæF´lÛ‚Fféüû°e�xÆŠИ–Q~œiAAøkûßö‚ üÍyö1÷ÑçXT Ö¸ˆ¤³Ù¦'#®¿•[‡ÆãÛ€O7ª-‹ä•à¨FøëkÿÙe¡¼nõô}æÞ! /…ÜÜ\"""°ÑŒ£'дu3"‘››Ûð;t¥²öÓ·ysþ^r<2-ïú˜Ïîl†®ÆìœøõC^ùhG Ά% ¡ùÇcO3©_d57S^¬çIå··Ÿãíe§°I2’¦!uâ®—_垄ڧ–˪w&óÂj×¾5“GÕ½JAá¯är¼-Aø›‘ mÓ‹N�Î>†iª»5�Ä£§H?ðŸÜÄÆoòÑ„Ž äP8þíÓÜù�/}9•ñQr-?„º±Z­ËßE«˜¶Ø•B�N$@ØÀ{Ñ(Nü•iÿ�ÁâãvjÍRI_ö½µž\|i1øjFuoJ0yݸ”_6îeÞKOáúïtïî_a“Þ¬§’òË;¼µ<“¸ñoñæÝ]ñÏXÅ›O¾ÉÜ×çÐñ³Géi>÷˜òÖ}ÌÔ?ò‰ó:t«O�ÎEq^1N½™ ‘�þoÀUœO‘KÆ' K;ˈ‚­ ‡jÂ?È‚áRG„KF8Aþôô´¹îi^¯¦—�ZtœEï¼À[«Ó9úýl�™ÊøÆ ðx¢pèP *­êö™ Ô‘Ûíâ�#‹q™ Ø•¹ŽÓ‰it Ò€{PI^þ�¾³š-’~ž¤Ã®×˜±M9ïZZÑff}¼�|¹bâ4ÞOÙ`–£Æ0hö¿xè›DLŸÏè9÷ÐÖP�õÔTVþ¾‡ß î¼ã "Œ@Ì&\û +g®æ×íéÙß§rù¬™þÁJr"FòÎ}WàïutÃɱoŸfÒì ú>?�ÿ ö¹ð*ÂeÎÅÆwoá™ÕÜ1c[Ÿ?¡æeÓÞtœUGK–’,1tëO@•6豞`ëúíJ-Dµ„Ó®'ýã{ÎO”†-u›v&‘G0­º÷ S£Ú¡šÇáÍûÉ iGß6¡‚q9kßåþ÷Ñö±i¼9¦‰xÈ„¿)qî ‚ \Æd¿æ\ýÀ?X¶þvº9�è†ÆÕåP±ecßÁ$Rsm¸u>5jJû„6D[*Þmj§çLÎ6ñ i2NáP�SH"”T’«ý,†øps¥ŒjÏàÈÞƒ$¦çcW�E6£cçÖD™Ï Àh…©M-K$-bñ¤ïgýöD¬>MéoAñHX"š\Ã{9ÍAFÒirݾ�≠ºø?oµ:>ÍNæÉ3ä¸$Ìq4 ®!ù‚VLÚñò•ês‚Ô¥./7šª!IzÙˆTÚ‚4­æaYu§�º/y‘Cxâ¹G¸¾•Ââ=,Ö KY“«¢k2†®?¤@²Ðé–Û¼ä%~;½Œ…{o£m7£÷ë9Op䤂®E+Z”¯ ѪAæè±3(ý[žJ£°qæt~ÍgôkèíutC£xçl^˜s�°ëÞâ߃Âÿ\½7Ôk9•{[‹$Å‚ðw$‚ —99 ˆ@Ydtò¹:šu_½ó.Ÿ­?C±ZñUB¶Ä0äÞgxæúÖ¥C[Üìùôqÿ­°4o@"óž}�yÈÄŒ{‡‡­/òdµŸMcÞ¤ö%?*j>»¾›Â[_là¤M­”@¶Ä0øÎ'xò¦V(ª{÷\xaøò¾B^}âsØ4äFc¸»Ý:æþQˆïàçøñÅÁç¼%PSñÂ}3Ù«Æq÷ÌÙÜTßZ=�:ŸÂ¾ÏÿÍ ã7ôE~þO|«Ûä‰xò¾Ï9&µà¾93¹;À›}]žTUEÓ4̓Vz„šVÓ”WtD |Œ9{o‘@³Öb'{·íŦÉ4êÙ‹ÖÕÅÕ|»Ð7ÁȲ5yìØv¥[[t^®'çcõhÈþVˆ0Èþ�Hùy¨PàÐ(Ø:‡wË"üÊ—™Ü;Àû¡)öÌyïN‡ŽfÊÝ šÃ§A8vóÝs)¸0ÃZ™ÿ\Á—‹éOuÜö¢b<š�Îw¾Îäç\$ŸPâ+tQÓóÚë I4_Áý¯>Ƹ®�09RÙðÅyåÛOyvZ_?ۯ亥cþÌß(è÷<óžïO –ÍÂgîäÝYK;ý&b*¼š¹œwgí$亷¹«C5�)ˆþïcÐ–×øò½ïôá­´O:‚ð·#N{A„ËœãÈ~Žº5$S[ZUÍšÊO/?njŢ{qÇÍ#èŒÑ•C⦟ùlÁ>VL}øl^„„žæ£&óLüV¾žµ’SD3ìžqôÔáÛ<–®š>‹.¹ ׊Ùùñ¿yì»ã¸,͸rÂÍŒêK –ljíKùò»u¬œñ4Yž©|pK‹ò·Û’шA—ý?ÍZΉ€Ž O ¥ý»Ë,Z³�Ì-ËY�;ˆ±¡ç Ô!eÝyÀÐöJ®jq”×õø$?z ïMàšåX·®fsQ†úUݨBâ굜P$Œ†1õn©¤þ:—)F®xäfº[j^R±e“œ^€j¥qd ¦óìÓcË!-³�!€ˆÈP|ëq:zŽà°S£±7+«62Ïdà ˆ&¦JÏ)oÊè*L'%ÓŽ؈&a–ó$¦wa&i9Å(z?Â…ãw¡„UÊZ›ã®Ó1¸‹HOË¢_¢Gà[§»�âÂb4IO£éÐþSááÀÏóÙîðgÐãÏpG· ’6mnLÿ Ïpï�{˜ºú;–Üч6‘QÓ÷°3UGÇÛ»•´e)„ž=[¢ÎØÅîÂSÖÀÕ,–½?‹-W3õ®ŽÔÔ\¥àÜ{Ã|ÖÎýžOV�áõaA"�´ ü͈‡ ÂåJ)âÔö%|4u1©š…¶7ß͈ˆÊïú”#K˜¿»U׌[^~‰ûZž½ÓîÒ½±î»ù×ÂLþøy-öK¸,Ó(a8c¢ŠùmÎJNL‡!£[žHô|Ÿ�çè|ÞýáN}ã^›Ê#]Îv1nÓ¡;}Z¾Í�Ïÿƾ/ç°ìÊ×^º®¬G¨É°"ú:¦Í½—Ne¯“=±ŒˆYÂç§wñë錹1ªòM5…?Vщ+®Ré�_Cóæø|» c`È älcÕ¶"† ®ÒíZ9ÆŠÕ§Q$݆"Zö~_—#UUÐ4 USÊ“6l/(¹df« ûf©áI",<™D”œ,²TR½\Ï×?�„Z\D‘JyŽ­¨�"MÂ?Я<€¸mÎ4¦3üʼn vrfã/|»l;Çsܘ"ZÒï꛸¶Kø…“,*ÇY¼pNß\;,¢Â9åfû”[xxqg=Oܯoðæ‚äº5�d,Ñ}˜ðüÓŒo[ùø\Éë˜óÁ~Ü–L±¢zÿXú\?‘ÇnïI¤@£x÷GÜûÄÏdvœÌgï^[á|UI^ðwNÛMИ¹5ïÿxc� €´©ãè3Õ@ÇIŸòñ¸Æ5ôhp³å�›ùׯ‘<ðѽ½û<_u<öM<Ö C­ËàbãÿÁã+"™0ý Â~zƒ÷Wœ¤HÕ@2Üö*yf2#b+>ìk_ÆG|Á¯{2°©%Û—-�è|Õã¸ãœñÓA½ÇqmËÌ<º›eë³s]郕Tòl«Ú¡Û-7Ó±â�´¾%£F¶â›�³oÙJN]+ñ»-ŸY˪c°ôdôEÍ!àåñùtâÊA,ü!ƒ-k¶Q4hp¥„�žÃ«ù#YA2÷dÄÀ²ò×£./3šZÒ{AÑùHG$â¾.¢òÐ }+ºuò­r+3|$]??Ì–ã+øõèx&µ)ûùR9¹z ‰™ÀÁWÑ?è"vFöúøŒt:ˆ&?Ë™m«Ù\4ˆáå7V¯'E• èuåÙò7D]^&4MCÓT<ª§¼çÆ%ïÁ¡zPU �ÑŸçNIÒë‘%@QP곞®)ƒÆóùgëù~ùxº�iŒ®ø óÀЇaÝ}‘ì{™3e!gúñ⃠õìæ­Ï¶b�ºši=Bw hÖž¼xç+ü6÷Æõ¹“–5[ÐÈ?°ŸÓªžöÚ�ÓÝ_’$PÒØm½—ÏÞ¿™øÒcéÐ>‚ì]÷òQâ.¶¥©´�‘'»¿™ÃÊ?ú?ó&Ï]Y6³E-Ú5GŸ=�©‹çòó ]¸-FÌt¼ãßܶýQæÎù�%½^áê°<~ÿh6›M¹õ©{éæ«‡öýè{|!2gnÑ“Áµ^êt:PSØ�tÓ>œH§òˆ¯“�u*#H²j.G·2gê]´)í¬Ñ¹s;|²ïäõÍ¿ñã¶ÛéÔß8Øòõ—l-ò¥ïS¯óôˆ³ÛoÞ¶úŒ»xkóW|»o(ÿJ0^ ¬Mj8î:Ö³–Ïšï#E çšÇŸç®¥‘˜¸tˆöpפ¯©ÝY¦– QAlj¥op÷së9œãDÕ$ôþMè6ò6¹kÍJ‘š›M¶GC %¤šë–B°¬r";'` &H*$Ïê¦ä±D£0ÏŠ*,�–ÇÍ`�ÏHÞ¹'�â-syqæRv¤cŒhÇ•wÿ‹‡†6ÁXy'tì�¼ë»9¸)ò<ã¯AøËA„?==ÿõ-ïT�&VsS”‘ÈÖ•ó™õåÞb»›Êëc¢+_Üí©l^²€Eëwq0)…ì'nµò­mƒ¼ßRsJºç'xž[~«~«k>Îì, ªô‘L¡„û�{W,‡dlï9l[•Ìòe¸§MBÉür’Uk’ðÈa Ù½Úž ¦ǧo=„aqß37i'+·1l˜Éwé:ÈŠµé¨r®ìq¶gGÔååBUU4*'-ËÅqÉÈz z < .wÍ‹)NªŒ%�Eo×CGóæÖ�Oóù»¸v~cÌù§I.bÀèdÏGSùጞ�Ìð0åÐv¶çBÄuCèRúü&vgHW3¿¯ÞÆæÔÛiYãx-…3§RðH~ÄÆ…TþK®º’¦/&r$ñ1&¤£VòòUˆ‘ÁsŒµ3Ào(c„VÞ–ŰaíùpÏ6mÍâ–˜F%Ÿ›ZqûS·±uò'̘¾’6C¶1}­�Öwü—{:x?MmÉ‹�¸!£¨”ƒÒ›2 £Õ°a´ªøô,‡Ð¯o; ›vppßI<ýÛ¡wfÃÖ<4Ÿ~\uÎö#0 =S¶ïfÛŽÓ( -Ð�¯¬5©ë1¸�°ë  É·3ý*ש±ÅÅÎãø©ZìEÅ.4%��«Lô¿ê6F7F.8ÅÖeKYóý<�XÀÌ·®'ÞšÓŽCÉTøyn}{3ëgÎbe¿—¸ª´'€fÝF­ƒm IDATÁû�¿À·Ç` £uç>ôhJ€�½^�”¾™o—ÁÑåÑÜ¥ušâÆí®¡7…%Œh èõTˆ é�è«[Mò§ï¨�„­^DæêelŸ�@_ ('ֲ꤂.zc:]äþ õ9>]3†mÁs޲mõ †#Pçþ?X›©"GôgD· ! P—— USÏæà dÊXM½Ä=8äý$°ST\S°E¥¨¨•’ÙNüeo×É·÷¿?›®¿¯`óñ\Üæá$ º’Á­‚p˜Ã[?ŸÆ·Ï¿ù×Ð0dÀ––B¦ª£]ãŠäF"#Ã�Õ4Τ)Ôœ�F%?׊&ERÓ2FÂ#üÏe4�P(˫ْ9�£‚%�u_Ìå`•Í)iVt(œ9�ŠÂÙ²›ÿƒgïÙÆ=Naâ6Z»{˜òÏVõï…$鉉mTé�ÖÛ2"ù×´Q•‡c ¿¨Hü%�ì¬@W”Lr�ŠÜ8ŽØs@" : y'ÿÏÞ}‡WQ¥ÿÎÜšÞ!�z'!$€ˆ( øS»Ø»«®½·]Wëê"¢ˆ�µwd¥JM„:�Ò{½mæ÷G( $�ÜHäýìÃó¸¹3gΜ{æÎœwNÉÊÁE×#”6�ׯ4÷”òÂDtÜpú‡é#8eò>úûݼ³~.³~?�Gû¡¨*Ð\4x¸jÿ®ÔÚó6÷ãÒ+òë[/q¿k4}øá+£›H—Š•¼øæÔ1ÏpûOüwÌ#·Œ¦�¯×\Ź??Á¯¿mçºn½ë5j,��ø*E…E¸$À!ÄEBÑî©„Aß™«XY±žµéNÆ5v6Ì›Éü6ÔˆÑ<ùÊŒ�¬?¾cm!ßü¯•Š/O ÈD¿ëßàõIA­:{½uÐ8Æuü™�öÿÉ/«+6ʃKg¯f$vÌz�pVÅjÑù©tu.½çngcÊ2V–�Ç8?ëýI¾f ã¨óP÷«9ÉeÙ–Ô.[»ŠJÛéÁJd¸òläæ” ÑÐü&9òp¡`�è@íü¾îîw�%‚„‰W“Pws[:½ò%{<yäî1„ÕÎ6нªMW°zZëÔ ‹§EÏ¥²úxA"5vºbÁÜàkv@1 N\ëôƒoâõÊ=üñkNƒ«‹xáe8:g¤Óy㈛³�åUÆœK—-ÐÑŠëQC¸�GÅ/�c¿AÅdÆ‚N…ÃŽ0L_±6ÜkA1[0£Sa³á„#Ã)Èkcš{ºÍV›'³¹�<™0›•&þ¦XˆNCtCYc¹ä²á|¼i1©É[qŽNÄàé�—zUÕ:Ç,=¬WWR©)¨^Þx(*Q“žå?AßñÝ»È3öcú?'1)Þ̪—ßd£ùÇ­Iø)N6ïÞ‡r!1‡5G©ðkÆ>*õÞõ‡ò™-XÐ)©±7q(Žâ¯BBñ—â ºæ`ãЕÁª5¹hð×3&òèÖƒNYN6U­õôg§c¨e¿“칸jÝ›Œ±ãÇuã³÷¶±jÉZÊÏ gñïûÑL½?¦ÓÉC×ÂóS#F2¶ï6®KaÉšrÆŽHç·Åh†Îœ?¦{ý´NvY¶!º®ƒ®zspœîG=º¢¦å³3}6B�™À­€-[óÑ0Ð¥W·ÚÏÝݯQ6Ò?y�O÷XIºÿ.&„ªå F³ p9ë7Ê]':ÌÇ ø©˜L œÎãʼn(XP;\Ìks®§{S—…Õ‹Yöï9ü鈠Kd)¾ÅÏIÏ0±5&„<ªQívq`wû©;ìØP0Xj‡)ÖÚôõêšç2Òm6jP0Z=޽ޛ¹lî9èf3t»ûÑyÒ«©ªÒ[¥áo Â�¼ÊªÚ`O@"=T6äe“ã‚à£NØ‘“Mž¦QgÞ +�ÏšÊ=gÎ åkf2c¡Æ˜§næ,?pQUm«ë¡2S,xXôêÚ`J½‡Ã�“Éô—  !&=¶„¢ÝÓ)Y»Š-N@� SÔÁ'J½ŠŠªÚeý�ýÁwîå§Ÿ7Ö>üçI÷xÁõ>S0°4¬YÍîNé«Y¿¿Â�!*Ñç�#Î •ÉKY¶v K²4<�eLÄ)¸�µôüÔÎ=jHùsEþ`E‰Ž©çÆÆÕZ9éeÙvh. ]—î:܃Ãuº{p`¤÷°D‚U�Š5‹YQ~ìU í_ÂÂt'Š)–C-]ìî~ ³mŸÏ¿>ß…eð Ü?>¼Þ¶–à`¼UùEu†8)Ì/BWƒ >^ XÅ×ÏE+£¸´ee­xt¤s¨Š–—ÁÞ&wÓ(Xü&/ÿVBìå�1ë™+èY½’7^ù‘ý'¡2»—G@«$+«ä¨¡:•9¹”ë*aa¡µóiøt$:@EËÛ˾cÒ×(Ê̤B3áv ²¹ç ø†jQÐó³É9ú÷õŸ=û›Ù²ç³uÍr®Î ª��kr²)Òüƒkç“1u§O3zîf6æ]·lOÛL¥âCß~Ñ öBÐ+Rxçµ_qŒ¼“»Î:´Ô¬ŠÕb[�€�n§Æ¡£Xê=�by)庂ŸŸ�4v„8ÃÈ5/„í˜V�Ïæ…oóàëRª)xõ›À]>6ª!„‡Ö.ë·=-½þé3�?Þz‘/Ê‚ñUA·•R\s¤1¦ µsa¸Š((ªÿ�Úøg*�ÇN$ÞSÁ•ñ53çï8æ�ض÷^|ä1n½úVÞL³7û|Õàs¸0É¥j-³__DÞ ½`Dƒ³õ·¾–žŸBàY£Ið„ªõðñâÕëfŒ9‡ÈcîÆ'¿,Û —æBÓ\8]öƒÁÍuº`8‰‹»™ÑË–ñÖk‹ÉªSÄzÕ6æ½òév¿a—01Zmñ~ǰïâÓW?g›i·Þ;á˜:bìÚ‡¾V�ý6’¨¸»HI+ƒ€~ ìt¼‡�ÈÈ z ™Y-{“oìÆˆ¤p”ê~Xxà¨`€‹ÌÿÅßžû€e9G>Ñò~ãå7—Qs)_Õ ï®—ñÐݰ%¿Ç‹_ïãPÓûÐÊ¡Çqfl=Iy¬ådóÒåd×ý³^ª•[p*þôØ©¶‘nìÁY‰A(¶u,XVP?}×/ÙŠÓɰĨ&=x7xÞÍ=Swú÷² W®gùúú¿•þÇÒì&^c®]|õ�gxêé×øvïQ߃m_~µ–*%�Ä¡=jƒ7JÃGÇáíJ绯7RYgs­`Ÿ/Ì�БŒØHß%½’ä÷_çÛYÜ{ÇYu~Û�Dv¿�LÛÁ?9³Ø›¥Ü9šúsSkäîÏÆ†‘ˆ¨piìq†ù«öxBˆ¿)ÿ¾‘)ÔoÅkö*ÊJ+¨qé ¨xu»ˆ'›|d^A5‚Qçàƒ-)dÿùFÓ)@eMnßþëi*‡�ßn½:ÿã}~ܹ†Ûf¬`Ý{÷ruʹœ?$† £�üÝ©,^’Jfµ‰¨ ·sM?7Ü+¾ ?’ ß$'§5è&$=bóÊví×0áÝã¤`êdzžbB€‚ÚÂóSü7ԇ勖ñå"'º5‘±ç44O->V[WRRBYiºÖžT¸°•™ ñê�ŽNYi%%%øûû·è8zá¯ëýƒkÒdh\ ~®Ò׬!½À�!ü\¸sAu«�»ûÕã`ׯñÑ6ñwÝˤc#`(¾gqÉØþøn/Ìñãº!Þì_8›/÷›é}Óâ�;[§JhÏ„([رe;ö CZ0¹§™Ónà¼ß_ä·wâѲëù¿Ähü\El_õ|¾š‚¨iL÷;xZ6?¾òË+;sõ WÒÇR›F�i÷rÕ÷ðÁœ—ù45ãé€Eq²cÑü‡—_wF hÚ¤œ-Êãábò%¼økzÑÅM ¢£µœm¿ÍåÍ?+1u»„KšØJ•×3lù V¼ùÿ¬¾Ž „c.ßǪo?àƒ�NÂÇÞÀÔîMyìV=ïf�ƒȨ)çð~ò¯üôòÓÞt)Ã"Í”ì\ÎgŸlÀ?Ö›œÝMmy$pÕÕƒøýÍTÞ¾÷~ö^2Ž!Ѿè%»YñÃ7,Øn#øì{™>øPY(�{×ÿ”Æ[_=Éå—ñIÑXJ·ñ¿/¿æ�²ÎâJâ‰oTnø€?VsöC·3ª^äZ¥Óˆ‘ô˜;�ÿÎßÄà+:“÷í,)‹dòy=ê7hô*Ò7ïÁeˆ¢oÏ–Ü„í‘8„¢ÍÓ©)Í#§´ÎŸÕhÅ+ #±]û�4jà{chð7|“¼ŠÍö!ĵ F¦�âñ׌D¼5›¯ç¾ÀÒ9µ¥¨˜ýévÖ ù~ã^àl·ÍÉc] ¹õ!"~}…gïy—JMÅLP¿)<óèt«ó{«†�ã¹™þýú~zóq¾×j‡}¢Iºêî»vM¼N­�œ·©Yç à;ôN^ºËƳï/cî‹É|ˆ‚Ñ·+ãïz’ów>ÁÝ»œ8œ' rè4åYÞñzŸ×ç.à‡÷fð�^›¾É/†×ü�»¯F½©SL1L{á%Lo¼ÎœÅsxaAmÞ3l —?q/·Ž nø;¬ÚÈìW¤<éî=7è˜mÔè‹yü¾}<ñÖ߸àC Õ»çÝõ8×õ{3ò(×Ìøwˆ&*ÀRï­–«º„›??�zË´º*óØ—S žD„ùcU›öÙÁ£R]”Efv)ÕºŸ H:†û4¸Ê@³T%óÏkæÛÂNÜ0k7umòŒ�­ì$�ßi?Ö©QRRBqq1+W­"??ŸÊŠJ4MÃÇׇ��†&%Ðâ­C§¦8‹}J¨Q½�Š"Ü»)ïˆÜݯy´šR ËœxøâÝäJádëì[¸á“Îv.OŽðn•7Ý®ªä–R£xNÀ±? Í£Û(Í+ÆáH �¹U†œ8�Ö¼z÷þ`äÒ׿ñ·FìeÈÊ·¡ú…ìqÜ|ØËsÉίD3û„—;?Q'8ïf•³½œìì<*ð&"2 ÷« “Ê‚\rKm(D„4ð»T>« 9�[†ËHD˜–V©d5—Tcö Àë˜sÑ(øé1¦ÎXGì­ïóîÔH¢"Ä ú®s(¦!=8„â  z„Ó+¤ÑÏ þ5ð’ÜàJLl#û糃GÅ#0Šî�QÍÊëñid-ø”…ù:žñ“¸°Ëé nÀÉ9¿¶p¬SÃßß:tè€ÍnÇn«Xo¶X°˜ÍX,îšh} Ö€ŽtèxŠökÕêGˆõÄÛÕg¤ÇÅWrÎ�/²øÓï¹fèÄ´ÂS¡Á3˜¨˜à–'tˆbÁ/,¼õÒ£yy<Ô¿ÁìÛ�ߦ¥oö £“�{y;ìçݬr6ûÑâ ñ ޤK3¾^ƒGQ�ƒZáØuµÔH…·¥óÙçÉT‡^Àô $¸!ÄH®{!„í„NeúÇ<;;�jµ]3†ÖXQRœ^‹_‚ƒƒ Æ×ǧ�7þº”Às¸ó¦!X·~Îk?h׫ñvvÌÿ7_ídÌmבèÝŽ»¸ !Ü&=8„B´iZÞj>ûv=Ù¹›ùcÙfrfº^ö7öw^!€JÄ÷óȆ»ybÖ?ù¸Ï¿¸¶[³»‚ÑèTnø€g?ÞEÄ”¸od L.*ÄJB!Ú4½x?~>Ÿ=.Õ#‚áWþ�G®€¼œ¢¨AœóÀ Þ>g7Î œXåáÝ.¼Ÿâ:v>�ÃàDÓ9(3ô㦧Ϧç�^øÉýAˆ3–ÜÄB´i†nWòÖ¼1”¹Ì†…âg‘q)B´*sý‡Eœî\´!*Ý’ÕítçC4�™ˆ¾Ã�Z,„�‡Bˆ¶MµM+OS'„B!þbä5˜B!„B!Ú= p!„B!„¢Ý“‡B!„B!Ú= p!„B!„¢Ý“‡B!„B!Ú= p!„B!„¢Ý“‡B!ÚM— ŽÓ�!„B´3ÆÓ�!„§‰½œ‚²tƒ'^'ÿ†pª�×–µvY´£²]¹z%™û3q9]x2æƒy(ºŽ(ŠŠ‚ÝdäƒË/ÃåÒp¹\¸\.¢;vdÚ´+NóˆÖg§¬ ŒT¼üñ2�îü!„h¯Úò3�Bœ¡jÈÏØG� ÌÑt µÖ6ü W`GV9šÁ�¨Øp¼ݰŠìÝû)q‚5¤31�fì+gòO-Å9•Yso¡ïI¾#ØW¿ÁÔ'Q}ŠŽwJ.WïˆX¢|›Ö1²µË¾=•maa!IñCé …8ʪP||jÿùú¢˜ÍèN'ªÊm£Ç¢iº®S^ZÎ;ï¿�ËåÂ`0œîӭɾšW?Íš¦½ù!÷´å ,„¢M“;ˆB´5º“Ô÷ïãéeÕ˜ãîáËW."¤Áv³Æî¯žfúœ�8�½¸ãÃ7¹:ªá¶vàGžºå]Ò\¾Œ{îsž> PTŒªŠ¦ª(�FÄñ972çÞÇø¡ÌÈðG¾dÆ8ïFƒQõœ¡e_^^NP`+ÖþIlçpT»‹Ê/¾@7éhs¶c¸¶h€§'•ñCq9ò±;}0 (Š‚®ë§÷$ÎZU>û 5"Âð‘'E!„íˆÌÁ!„m�âEBR_,ŠŽ}ëZR*iÐi¹¬MÞ‹ Àµ‹Õ)Eh n¨S¼.…mNP¬>À€ùìÇY´ø7–Ï»‰>òBü”:SË~é²¥xzxqÎðs±>ˆÍùQííã­`Ñp}²Ý×�ÙvèÅõÒ�ÇÉæb×ç3íúø)¿á_!„¢­’‡B´9 þñ‰ô6)è5YµÁÖàVzi*«¶9Q|üðUlY»ŽŠÛ~U¬KÞ‚]W°ôOb°÷Ôe@´)‡ƒÁƒÉc4×¢Ú4Ãu=À¥ÔöàPA©VA/FSºœÖ<Ÿqô2ÒÓ³ – !„m›t<Bˆ6H M )Ö@jz©k·`?+óQÛT­Of£]!xô†¬üœŸÓ’Y_=†³=�Úж‰Õë«Ñ}’âñ;ßÐ+°=«ÝH§Î!xú{ù¶(ÏpºFùáÌÙÄÉ;)õèÁ¨s{P'>¢Uç²-m ;sJ¨ÖÌø‡w¡ßÀDx¸?w'=Ý^Äî-[Ù•SD•]ÅâLt·ÞôŒô¦±ÎîìÓš-ûƒ?Tö½†œ-©¤îÌ¡B³àß¡;qƒº|te8Wi;s*Ðð 4&š fîßZtt@L^R‘;ý³*0‰Ì¹>Þzø¿5ÃõöWå`îiNýj�ïÂQ²—´ [É,¬Âiñ'ªçÅs-7zÍY;Ó7Æ—SÁ3´3�™}S¯!wÏ>Š ^a1DûÑʰ#»<È�òÇè,eÏÆ lÞWŒÝèMxL_ö Ãóð©ëTæì"³p3+·9Ñõrwo#½Ì€%0Š˜�zïܺöµ 27®cCFUºa1ýܯ^�ï!„B4‹8„¢-R#:$Šÿ¤ï¡0%™®¸£†2ØH[“F5fÏÀâ¯ùiÕzVmµsv\ýæ“s[2É¥º24!øp×=GÊlnn`¢KÇú9ÜöÄbîbÞÍå<÷À\6Wé¨aSè<²F@+aÝü™üë£?ɨÒê49TÏ(F]÷^Ö÷p0å„ÜIO¯$ýÛ×yñý%ì,wÕoö*ÂMáþ‡¦3"ÜØ²}N‚FË>í#î|t!5ýïà³§ºðËs/0w}ÎÃU0‡å®ŸàÒXK“Ž¥®à¥{žå‡ý 1“Ÿæ­»£OÊ95…®ëj%+ªþ>;)wnÃ[,Ô|õŠÓÙò»Q¿Zô]8sY>û%^þjyö:µL1Ô >z##ëԱƯ¹‰L|9KÊñõ_=5 ß®)íÀ§–b4aT@¯ØÅüç?a±}87?œD�3ÕÙøî£/X•³’·f|CÂÛ—Óù_§^±‰÷}�öëtû(3ïN$ð4NÕu¥n?€ƒ3¬j×ä¢,óCɰ¢GØÑG–¢~ (ª‚Rw&Öæ6„ݬ¯nz μŸGÊF èÃäËÆ34&Jv±üëùüœö�?`cÆ;w“èS{^�_s½‘ òÃïß“·z!K‹Îᢠ£#YË'Ý ¦^ç3¶kíÕ¯š�¨ 8KÖñöSÙ8–»¯M ‹¿JÉîU|ýéO¤mþŠ'žòçý7¯ Öh$vü�<³†Of-b/‘Œ¾a*Cü xÅFÖFݽöí[™óÄK|·Ë�µÓ9\{Ý… éè�-o;˾ú„žÙM¤ŒœBÑ $À!„m”±[‰Á_’™¿—µÉù\×9ìpï WF2kò5 �âˆ59h‘†t²RRÙ§õ"æÐ†Z.k“÷ãÂ@ô�„6ˆP�mÿ~‹œÂësn¤�õg�ÛþË+_îÆfìÄÔ^ãžAGVéÙ7�aÝ^æºÇ°qÞl~=ÿE.jx ˜#émw'½JVÿ¶’"ÍHÏ«žåWF×™T*‘Qc†rÛ½|ž¿†?v]EÏž7÷9ÅTpí^È‚¸Û™õÚÅÄî�“@bDÓøžœ+X™{�#ŽS¶¶=ü÷é'™»ÍNèÈûyõ�³ ;Í3o)G¯1£ÌЈ2´qÅ(_£O)§_G¢  ª-Ë´{õ ·¿ û–ù¼ñK6NK/n™1ƒëbí”ÈÙ#zb½ùA¾Üÿ ³~¼˜„iQµuðxל3šqQ?1wß:~Y’ÃÄK"êO ¦e±dévœX<ö\Ž,¤¤Öæ?+™ naöŒËˆ9´œÄÙ}¼¸ñîÏÙµõ+>[;…LJz6` #*Y0{{  ï¹ã¹¨Ns¯,uÊ–ÎwÛÁ3ž»^zœ‹¥Ù½'ƒ†ô'èþ;x»J—™á„B´˜ÜJ„¢­2÷dXœ/ªî }í:J¿¹Ö8�’B¦K%$.ŽÎ0tD\€ŠkO2ÉuV>ÐKRY½Ó j0‰I]›6¿„R;Š@«†ø+§ÑÏ«n£ÔÁ¦…ÿc�<¦ríÀ£—EUð:•ÉÝŒè5ëùõ�‚LVèfzZeåNtŒÆbõ–žÜ<ûg–~÷67 T¸³Ïi¢+áL¸vb�u-�ÞécQÀ•Ï�Ü㔬+‡__z”7’Ëðr3GÔiè‘r´cæÏPP”¯BÀ¨£OͳŽòMðÁϨ pÔíÀѬ-¯¯Íû.lúm)™.ðL˜ÄÅ]êï¤x äÒë.aò¤‹H ¶ã8’�Ư9c7Æ_Ð6þºˆ½GePË\ÆâNðŒgÂ9!Ç>Ø©œ;í¢#Á�Cùï5‘‰½Œ •²fõ6N<Èݲ´±nE*•º‚ç�ñŒ=:(gîÌ”‹ñ’B!Z�8„¢Í²2 ižŠŽmÓR«þY/!uíNœªññÝ1˜{“8ÐÛYµ®ìp3²jC ›ì:ª<Ã{5³…kìN|¯ú�-�MéhèÜ¿‘96ÔHX­s$ IDATú÷ DÕlÛ¼óH#®!Ò§w8ÅÁæyÏó¯ïRÙWÛÑoþÝÙç4Q,Ýè×½�Ù+�>øx(@ 6{#-}½„Õo?Æ‹‹óñ0�Wž™L—¦M×qÒéº^o¸‰¢ªµ½8VùAÕÁ²w(¨«ÐUõà?…ÚÉE•ƒA�&k…úÚ¬ïBËc˶B4 Dõèα ©ts+ÿívn{ì𭆮9T¢Æ\@œœ»~ã—íuCKg§SÅoØXFø{‚Š©'ƒú6PÔzt @E£dï>JN8r·,µví­AÇ@T·X<ØÍ£G/ºHŸb!„­@n'BцyÆ%2Èc)Ë«6°z“�ó†X j«7ÛÁš@B¿C +÷Á²h ik6R5n^ØH[›Fµ®â—H¿f6rK!G·Ð´Bò jßËf|ù8W.h8 à,-AGÇV�O™�ŽRq;=#½®z�¶<Áì [ùöÕøî o:ôèO|Ü`†ÆÐÞ¡Xëeß�}NÅê�wƒwhõ𨎆ۣÕl™÷$³¾ÙƒÝÜŸÛºœ^ µ(Û§mªêžF÷틆Ze@ñtázp/†0œhÎm@Œ{i…úÚ¬ïB+$¯PŒøú5+�\s€4’‹†Îfíâý,üu37ôPqe°ø÷=8Õ`F]�Ðàj$ŠOa Vj•€@?TòÐ*J)×!øxv·,µRŠK–I€oƒe¢Ø®;!„í_ÛxU%„¢AŠOÃz™P´R’×ìÀ Ø6§°¾Ì=¸_·‚ßÀxºu*×'³É8w°f])šbaÐÐ�½zì �m4c<ºÑ¡;°;tt—‡ÃÞà?Ý3˜ÈÈDúq5�vk¤§xõaú«s˜óøt& ‰%ÐPÅ�Í+ø~Þ§‡{­==ûg^ÿh3èöM|òþ2 Ž?FèÔ;xjE’Ÿs!57e∩D+°`üG”èXƒvÛ”Š‹18>¯×ëCoΕV©¯Íø.tv{í�Ææ8ºæ†�I°ª‘·ôW’«jÿìÚ½ŒÅ. ‘ç2±#L‹s#1šŒ³íÂq¢bu·,u;6Ç¡ã™.ƒƒ*!„-'=8„¢-S’Øcê&òÒÒÈÔzR™¼žÍ@�Á ª¦VC‘e moë3\$˜RIÎÓPÌ}wôxy7)V¼<�"ý®ƒ×'µ,Ý–¦gð§çè«xdôUè¶"vmLaÍšüoá ¶îXÈ«/ÅôÞ Lª;îß�}Ú ]Óðé%O^çÍÇOÌ"uñk<ׯ+¯LîØ&nøÊÁÿ¡€‡)ª¹ƒòþk1T±|‡Zé�2;ç½kÐ{¡/Âåõ<”Ö¶èë­¦Ò¤¶r}mÂñ<¬:5Õ5hx·Ú›$ë qŒëø3íÿ“_VW0l”;–þÎ^ÍHì˜14:ÍfÃÖHðÂ~0ò X-XNT0î–¥fÆrp„�ÃfGçè!8 ×TQ­�þ°¢Bˆö¯ý=½ !ÄE%"1�.peldSI6å¡:�YÿGÜЉ„¸T×Ö§å‘¿a{] ¦ž‰ i`l¾[ át 5¢à$û@îñ{gœâôK ]�áŠÛŸbÎGÿà’NFôò¾Y´¿Ñ‰NÝÙ§-SC'ò쿦3,îž¼k�”±æÝ0w›ítg­–R7H¡c·g`؂˩¢P<=!PÔmÀ¹t'Š¢ùלãµv}=5”ÈPà";+§Á:¤;mØœn4æ�=?®&½‚UKÖRîØÎâß÷£™z1~L§Fèô²<òj:ž‹‚üB4 A!Ÿè‰ÐݲTöWùù O:¬eï'û¤9B!ÎàBˆ6N�BR¤ݱ�õ)HÛãB Ä�.G¯ôa¤gü|U'Û7­'yãº�®I „¶Ö¯½À€��0 q`Íjv7¸ô‚FAújÖï¯8q#ÈÝôl…ìZ¿œŸW졦¡d}û3jp Ņŵ�*wöioLxTÂÇÞÇ#c#Pk¶òáó³X[~úß�+Š‚¦×–¬Ó~ƒ© ~ߎÄû—$jd�ÕŠ>(ã�ñ˜¾ ¦áh¶ŒÃÃR4M£YCFZ»¾žˆHÿþ‘ÐÈIIaÏ1 ºØ>÷6Î=†sú™¢f}%*Ñç�#Î •ÉKY¶v K²4<�eÌqzéέ¤ll ÆkûÙœ^ކJt·. NþY/{î–¥F·/T4²6¥StÌ…¥±/9…L p!„hàBˆ¶ÎÐ…¡ !¨Z9ë¾ü‘´ï�ñôn`aK¿xX¡zã|™V…nˆbè�­øc¯ÒyìDâ=\_3sþªŽÚ¶÷^|ä1n½úVÞL³Ÿ”ô´¢ß™ñ÷§yî¹Wùxkõ±sfØö�º©]1�êæ>íšâÏYw?Äå1&œ™ßñük§>Žÿ6l^�ÃåÀhéHpä pi˜3Âñý- EU1ü2uk$ºÍ†ÓršÚƒÑ@Ú¦ øûùc67g5 Ö®¯'b ëùÐתàÚó-o¿�º}gœÙ‹øðç}¸0Ówh<ÍíX¥ŸÃ…IÞ(Uk™ýú"²ðfè#Ž;A§¢—²xÞI¯wâ:%+¿àûÝNc'FŽ8ÒD1jçqQP/ánYZpÖ|Uû†oø$­þ7öý¿ðΗ»Ðd!„­ - ÉBq\&z% &àë9°u(ŒHèßàWÅkCz˜X¶n+é€Ú1�¤ÎG÷ôh5ü¸s ·ÍXÁº÷îåê”s9H AFù»SY¼$•ÌjQnçš~ DaZ!=5|,7Nþ�û¾ØÌûwOg͈á é�¯I£ª(“´?–°jŸSÔd®RÛxsgŸ&s°ö�k˜ðîqi¦~Ü1ë)&œº†œâÙŸ›»š´;ç°qñLžïß•W&EÒº5¢i4M#!>��›7òý/ß’?”ð Ô¨(ôÒR¨®F·ÙP,ðñA Äd6‘µ/‹¥ËãííÍäÉSp¹\ †&ÏÇÑÚõõ„Ç‹šÄ7¬æÎwRYýÆ\»b$Ã{c(ÞÉŸKV±»ü]ÏÝãÚDS|>~$A¿ÿHNN jÐLHô9nŸ5r(g)_pçÍÛ~±�*Å»VðÓÏÉäèF:Œ»�KëôS|£é ²&7‡oÿõ4•ƒÃÀo·^�ˆ¿›eé5ì ®í¿‚7×ïeþC·²ë¼‘ Š´R“�Îò%ÉT%Nâ¼�ßð¿½]v�BÑVH€C!ÚKŸD¼fA™†bêÎ�A�Lª7¸3†uÛq¢’�D�Vÿ¥75áIfÎ[³¿aYêO|�rð#EÅ#¤§ßÀmhâÒ�n¤§xÛ+Ì ~�w¿ú�M‹¾&í·Cé)¨a œp=·Ü8™>Šûû4™Ž½²„¢Êãlb®À~ºá[º^Γ·oâÆ™«Yýî‹Ìíõ*Ó»7sÍàÒu§Ó‰Ãá ( ˆÊò*ýþ?ÌŠÂÄòr 11(áá¨è55h íÚÅGŸÍÅVSChh(]c»‚®ãp8PUµ޶v}=3Ý.{Žwƒ?â�9?±fíÏ|²jëX8ƒ/¹Ž¿Ý0š.nÆR<�clä/|œ©>j,ƒO´<’ÅeÏ^B××gòÑoQyp2OÅÌ ÿ»�GnŠ_Ýó6õcÚÍç±úåߨ—±‚o3,q�˜~ ¸Y–†N\þì?ÐfÎäÃe¬ýé3ÖŠÉŸžcïã…ÛcXxÛ·€�š.ç"„B4N žþ/¥6r¿ï�[Ž»qzZ*qI#NE¾„¢ÝJ]µœ^ýãNw6N�ê¢,2³K©Ö�øEÒ1ܧÑe)ONz*ó³ÉÊ/£Ê¥âáLÇÈP¼ŽØqgÑN§“Ꚋ‹Š((( °°�ÂÂ:¦®#°¸¿âbüJ˨¶˜) ÇÇ›�ññ„‡Bhh(ÁÁAxyyÕ.ÁÚÜU€Ö¯¯'â¤Ì·…�¸aÖ,nêÚpûò¸à‰ETGNå½�n¡�ì¥Ø»¿ˆ£7aÑÑ„z4Þ‡ÄU™Ç¾œJð "Ìë1›ºW–޲ìÍ*¦ OB££ ÷:ý‰„Bü•DßõoÅ4äQN!D ¨xFÑ=0ê4¦gÂ+$šî!Í9Ž;ûˆ–0 xzx` Å? €èèhjjj¨œ€­¦†›�,—†Á b6›‰´Z‰µX°Z­X,Ìf3&“©YÃSŽÕÚõõDŒø„w¦gxk¥§‘µàSæëxÆOâÂc&nØÁ9Z1ûu ›_‡&ícð %&öx[¸W–&ßtõmZ„Bˆæ’‡B!N:EQ0  ¬V+øøœî,µ3:•éóìì4ªÕL½f áí~&\!„¢uI€C!„¢�ÒòVóÙ·ëÉÎÝÌË6“ã0Óõ²¸±CÓ !„g6 p!„B´Qzñ&~ü|>{\ ªGïü�\=oYUU!„8†8„B!Ú(C·+ykÞÊ\fÃBñ³4m\Š)îFf½?Í@”<í !„8CÈ-O!„¢­R­EFÔÌݯ0bcÃNJ–„Bˆ¶J¦§B!„B!D»'!„B!„B´{àB!„B!D»'sp!D”��}º³ „B!ÄiÑäm%À!„mPs~È…B!„2DE!„B!„àB!„B!D»'!„B!„B´{àB!„B!D»'!„B!„B´{àB!„B!D»'!„B!„B´{ÆÓ�!„B!„âLår¹(*È£¼¤»Ãš†~�§ªLf3F£/o¼}ý°X=NâO p!„B!„§˜®idgeRQVŠ·Ÿá‘±X=0šÌ8vl5Õ”SQVŠ` a1[ÖŒ×4»‡ÃAEY)û÷î ,"o_¿Ÿ×é$!„B!„â*+)"÷@þ�ôèÓ¿Á …Áà�Åê�¯ .§“Üì,vlÙH‡N1øúù»}lU5`±Ö¦ííãKxdåeädeR˜ŸK‡¨N˜Ì––œÞi#sp!„B!„§HQ~¹ÙYtŽíFDT§&õÈ0�tˆêDtl7²öí¡¸° UóäíãKמ}ð "cçvª«*Z5ýSEzp!„85ìå”Õ < ð:rjìï§“½‚²j4Å¿ o̧;?�9�e׿·æhïùBÑ.äQT˜Ol÷^˜-ÖfïïéåMl÷^ìÞ± EQð jÕü…„a±z�™±“Ž�ºàáéÝâ45McÃÆ ìÝ›AIi .§‹€ @:„w n`±ˆêȩ̚{ }�Çÿ{ÃjÈÏØG� ÌÑt µ¢4²¥^q€Yåh?¢bÃñjtÃ*²wï§Ä Ö�ÎÄšq¤Íâš¿ÿH±ßDf~q‰­wßmUÍ+»ƒŸoýéËT f+>þ!„X1œèØ+gòO-ÅÑœc·!í=ÿB!ÚŸÊÊ òórÜnb¶X‰éÚ�ÝÛÓñðôÂbu?­†xûøÓ•ÌÝ»èܵ&³û¯z øyÁOX=<ˆŒê@—®�QU•òŠ r²³™÷éG\pþtèСUò.·s!„hÓt*wÿÆìÏåû”l*µcçÔVT+¡ýÆrÓ=73!Ö£Ñÿ_‚î$õýûxzY5æ¸{øò•‹i0²£±û«§™>g'Nc/îøðM®Žj8¤ø‘§ny—4—/ãžûœ§Ï:©gpú972çÞÇø¡LkøsEÅìAϸ¡Œ?‰ C"ñl¨R)*FUESU”6\é´ª|öjD„áS÷©§�ä_!Ä_G^V&¢ZeŋՃ°QdîÝM×½[!wõy{ûÑ�ìÌ ¢c»»•†¦iü²p;EJvÖöeìCsi‡Ûµ ¡a¡ü¼à'®¹êºVéÉ!!„hêÓçqïý±±RÇ£Ã@. }N¨å• žIô;ÒWÃe«¤87“Ýû�¶ôKÒ~ÿŽyqÓxìÑ«I ®ß§Ã|öã,Züø©Ît3¹ØõùÃ\÷©wÍ{�Ë#ŽÔ€ö‘!„Ey¨Á!­–f`pHíò²¥Åøø´Zº‡‡„QRXP»Ê‹««lÜ´³ÉDdd$«W®"$8”„ø!Mf22ö°vÍZ†�5”Àà@Ö­O%qHb‹ó,!„h«´~üÏçlªßøÛxçÅKˆ=ºâØI\3m/ßû ßen`ö¿åÜ—&ÖÖÇ«¸MÁ?>‘Þ¦µ¤ÖldÕãÎ:¶[¦^šÊªmN?|*ËØ²v“Æà{L,¤ŠuÉ[°ë –þI ö>“^åé9åa^ç}L¯gÉ.þøácþóÉ2ö¤Ìãï÷ñÂ÷2"°�U,½Œôô,4Ü{ó$„B´–’¢B""£Z=ÝÐðäf8)€°ÈŽdgîs+À‘™µ�ȨdìÉ $8Œqç�;üY§¨h •;vÙ�œY­’_ p!D[U“NêVºêËÙ—^xlpã CðPî¼u<Û?ÞOx„N±Âèˆà(ÙKÚ†­dVá´øÕsƒb�™@S/?ÀöåàN×(?œ9›ø#y'¥=un/ê´†�¥ûHKÛÆ¾¼2j ~¡Ñôê׋Î~'¯‰š@R¬�Ôô R×nÁ~VÜ1çPµ>™�v…àѲòs~NKf}õÎö-XÚµ1¾þØ¿[MM«ÏÅàããÇ]ÇVSÝì¡5…EEDuŽ"';›Aýã�ù¼KLW–,[DL§N””–·J~%À!„m–§Kõx= ¼Ïº‡9�ÍáÌeùì—xù« äÙëÌᡘê?…½‘‘áGnŽõs¸í‰Å8Üż›Ëyî�¹l®ÒQæÐyd/Œ€ý‹g¿ÌkߤÕOPÌÁ š|'�Üt6Q'£1§F0tHÿIßCaJ2;\qô©7zÂFÚš4ª13xÐxÍO«Ö³j«�³ãêgȹ-™äR ]šÐÀ£Cézf¿ð<®+âȼœ –ˆ³¸çÅG¹¸ËQÑ$­„uógò¯�þ$£JãHé(¨žQŒºî¼¬ï±Áw÷;i¼z\ÊSwnæÊüAÉŸŸòåŽQÜÚ£¶®8Rfss“t6©þ¸{®M®Ë6|p?÷/(?˜öN>{ô>C%jêë|v{´Fò¸U¿iqç£ ©éŸ=Õ…_ž{�¹ëë×søPîzñ .�=“†B !„(.,8)Á�C||ý(//=)?¿ÊËJ›ਮªÆj1SV^I`Pð1ŸøûQQ^‰Ùj¡º¦²Uò*!„h«,1tïh`ùî2–~ú_&÷¹’>ÍB¡—ðçÌûyô§l´€>L¾l�ë„&œ;X�ZŠfìÍ ¾¡ô/ˆÁ°b;)kwáŠëUgu{’SÉÓÀ3„¡Ží5 ˜ ùåùgXiÎÍ¥Gˆ‰ª¬u|;ïkÖdÿÁë3¾%î­©>¼^IêþÎ}ówa÷ìÂù7Mcü hüôbv'ÿ̼ùËYôÎÃä;_ãÍ+»r¸™ëî~'�Jð9—0vÎ þ›½Ÿß—íæ¦Ý�»Âʉë�»eÔœºl$vü�<³†Of-b/‘Œ¾a*Cü xÅF¢�L±êvýVŒ&Œ 軘ÿü',¶ç懓èb¦:{ß}ô«rVòÖŒoHxûr:·³Ñ>B!ÜW]]EPHèIKßÛÇ�â¢B‚CÂNJú^~¾äçd7yû¿>ϪůcêôèPS]É{ÏõBsUžØ[×tt<»?€¦¹xõ¡†ž÷7†žÿ¨Ûy•‡B´U†.L¹úl¾{n)ë?àÖ«W0rÌyŒLŠ#®w'‚¬'n!Ù·Ìç�_²qZzqËŒ\{è•s"g�è‰õæùrÿ/Ìúñb¦EÕö`P�mÿ~‹œÂësn¤�5Vmë?åÍÿå¢:3í…W¹k€çá‘=úÄ‘ÔÍÌô¿Ïþ_gñÙä!ÜÖ£õo5ÆnI$Ifþ^Ö&çs]ç°Ã½/\ɬÉ×0tŠ#>ÔHä ADÒÉJIeŸÖ‹˜Cj¹¬MÞ� ÑClpjþdyøíü絋‰9TtñCHêXÕ÷Ç�í²2÷R:œ¼Ò¹ý¿¼òånlÆNL}á5îtd~‹ž}Öíe®{|çÍæ×ó_ä¢�–íwJ˜»3¸¯'_dW’µ}ez÷zÃLŽq‚úãÜæÞ¹6·.‡ ÃĈJÌ^Ä^è{îx.Š8q¹Ù6¸Y¿Upí^È‚¸Û™U·Î�@bDÓøžœ+X™{Ùá:#„â¯Os¹Z´,ì‰X,VÛIKßl²à°Û›¼ýŠ…¯ððKïñæœ\\ºŽª¸ìÖxz˜ñò²  TUÙ¨ªªáëŸó@×1(îyòÌ|òï- pÈÝU!Ú,•àsàõÇÓÓWÅY´•ßæ¿Í»�‰'ó·>Âsïü—_×gRîjh›~[J¦ <&qq—úÃ3¯�\zÝ%Lžt‰Áv‡?¨�zB«†ø+§ÑÏ«nkÖÎúE¿“­)˜LfZ?Ï£&¨Tð‰»˜‰ÝŒè®,–þ¾“³ÖRæž ‹óEÕ¤¯]GéáaRRÈt©„ÄÅÑÙ†.ƒˆ PqíI&9ÿÈ{{½$•Õ;� “˜ÔµÁ^ º΄ë/¬ÓP­åÑ{½¬ ¸ò9�{(M›þ�=NðH˜Êµ�ž¼SÁèT&w3¢×¬ç×? ö"pw¿SÅDXx0*:ZQ!EÇ®T\ßqëO ÊÈ�ºÜl-¯ßº΄k'6PgÒÇrt�BqFÐu ¦“7?™ÁlÂÕŒDsM&\Φß]N&�žDFx²tÑ"üüŒ„‡GŽ�o0ÞÞ�†Eh°¿ýo!Axù ÇÑŒã4˜×í-„â$ó ö‚û™3òr’—üÆ¢?Ö°fÃvr*+ÈJ_MVúj~úü?XBû3áš›¹eB/ü÷PÈc˶B4 Dõèα£[T:�¹•‡Ç4rhcwâû{Õoài9¤o+EC¥cßÞ4¸¨†Aï^~¨Û ÉÞ±‹2½çñßø»ÅÊ€¤Axþº„ÊMkH­Çyž€^BêÚ�8Uâã»c0÷&q 'ß.ÚΪue\2ΨÚ�Â&»ŽÏð^ ?t(ÖôïÖÀg/|¬ ÔÔ`;4Gƒ–Ǧô4 tîßÈ\j$ýû¢nËgÛæ�8¦„bqw?·ÊÍ cmøG×4´8i°þ¸_F-ªËMÕ õ[±t£_÷&Ÿ1úàã¡€­N�BqFУáä5½�#N×Iy¥€Á`ÀÕÌôu|™zÉ%ÔØ4¬V#šæ„:³n©¦Ú9¸®¹ª7•5x{Y±Û2ZœW p!D; zF2dµ ™p-h5äîÞÌÆ´M¤¦®á�µ[ÉËÛÀׯÜǺ=Ïñî]ƒkŽZ!y…`Ä?Ð@OD±rtKÒUHþÁ4ƒC˜”ÁA�¨¢R¬sà—È �¥,¯ÚÀêM6Îb�ª ¬Þlk ý…¬ ÜË¢5¤­ÙHÕ¸xa#mmÕºŠw\"ý‰(/<œpBE=´šÈ¡?i…äÔ¾™Ïøòq®\Ðpé8KKÐѱäS¦Aˆ»û�²>˜e¥µ“u¼¼ðlâwÙ`ýiIµ .7Y+ÔoÅê�wƒOW Ô!„gpºœ˜Œ'§‡ÓåÄh8Þ Y-ãr¹043}GuºmÏ>ØËJ©®Ø�­º”šš jj*©©©ÄV]I�­‚šê*<­:uÝâ¼Ê!„hoT+a]ã}ñµ<øüÛ|3ÿ-î?§&ld|û6Ÿm?a×ê­h4›à0š1³“‡³ �"ý IDATö¿L¦ÆÓ4˜j[xºÓ‰ã$µæŸ8†õ2¡h¥$¯Ù�°mNa} ˜{&þðп�ñt7êT®Oþöî<¾Šê|üøgæ®Ù÷�[BX@\ZEPAkåË×µî»m±V­¶öëÒ_+­[[7j]j]‹¸¡RQd IHB „%@ö}Oî>óû#B�\ú¼_¯hÈ�9sfîIæžgÎyNÀ½‹Ì-ÍhŠ…©3§ÐsõX¯è.œ.ÝãÂåröú¥û†K\�±szƒ·û�,Z={ŠÑPñ‰vp™ØãéµýœÈ5:�¶ÜwѾOÚ27B!NŠ‚ÇubS/ŽÅãta0Þ:än— c¿§Ø( k {@×Pt7ºîìüÒœèšMs yh;šÇ> u•Bqš3'óÓ_ßÍ®‚ù¨®œ¬-UhãâP+>V»Íކÿ‰Gµ+V sØèôÌ¡Ðy<‡ÍŽ(V+–Áêï©¡dL‹1§€šü|Jµ$Ú³riÒ Œ›6…°n'«FN%=Þ@þþ|r÷yH7å�U£¡˜'0+µ·sð‚bÅÏh01ñgÏòÌ‚°¾•«y¹ßI¢Õ¬çëB7(&MMæ„>>�À5ð¶|”ú ™ö-„â{C5p:ìX}ä‘Ê;&ÓàM^uºMýü ŸšñŠ2‚C!†$' Å[øê“wYžSü¤’Öh†…«€NGGGçx5’¸Hࡲ¼ª×2t·‡»7 5Џ(ল¢ê(# ÜTUÖ¢¡`ŠŠÄ©*1ÓÓI4€gßV šªÈ+¨A3Ä’žwø Î�@zjª§‚ÜüjóòØïQ0%M'c Ö±5D3,Òˆ‚›ÊŠê¾�²ðv¿“Aoeãëï‘ëÐQƒfqѬœâí¹F[îõ8C©} !„ø¾ðñõ¥µµeÐÊokm& 0pÐÊoonÁ×Ï¿Ÿ{¹¥.Ç#·e!„’Üä½ù=ù"Oýu;޳ò—Þ¼ƒ‚2(fâ†u-™ª†2iR4ª²³Ù{DoÍÃÎ×ncöys˜ýë•Ç_@ gòÄØƒeîï­èÜAf~ºb"iR2>}9]/©ñ̈3 »ŠÈÍÎ#¯5t*‰=ç‰IJ›L êfgA.Y[wáÒ Œž‘Nä@Ý •&OIÀ€FEæ&Š{½¯kÔn"·¬íPçÙÛý›n£è½Çyì³*4ŇÉW^ÍY' òö\ -÷)ô1ÄÚ·Bˆï‡�ÐpZ››­üÖ–fƒ­üææFƒûµ�~ŠÙH€C!†$_ÎøéÍà*~‡~÷o2«{_þËQµ‰e¿�um:jØÙ\23 ë)»�Ñç_È«‚gï þöQ Ýã$îÊÕ¼º²f&ÌL£o Œ�;Ÿ Vwñ‡¼ðEE�ø¼ƒÝË_eeµ†0�³£÷FcHdfzªÖÊ–÷?!ß®à?%�ñ½Œ¢´LLc²l[?æýütC<33b°~*#.¸ˆ4_Ͼå<õÎ.:zláØÿ1O<ðn½úVžËwžà~ƒÄÝFiîç<ÿàMÜò÷Lt1çþ’ß]>¼×¥tûÇÛsõ®-+CgOu }Yšuˆµo!„ß þ�Á¨ª�ÖæÆ/»¥©£ÉŒÙbð²Z[›Q³õøåkš†ÝÞ•KC?|Õ”þ°ÛíhšwKªK!„¢,IWñø/ÊXòÔ7”mXÆ=›ß&vL2IãôQñØš©)ÝEAQ%mPƒ&rýooçÌnOÙÕøÜ{Ã&î|>‡MÏÞÁµëÏaVr8†ÆÝ|÷õFŠ[!hêϸ{^ß;jjü%ÜwÃn~ ë–ÞÉMÙrîÄüÝ ìÉþŠ•Kè0D1ûžÛ8?t°˜Hž1��åŸP±£ÎJŸÔëSuÅo2ãL|»e…€:,�#6ã¸}!÷Þ™ÉmK׳ååŸsuölÎÏI˜ÑAmq_}�C©ÍDüüÛ¹f¢ù„÷;1.²ÿ~#—þ³Û{äqÒÚÜL‡³sé6ÅNú¢%<ô³éD POÞëkäE[V‡“¢’Y]ÅŠ?=Bû´(ÊàÖ«§5±ìÐjßB!¾/‚C讪$ (d@Ë­©ª *&n@Ë쮪¼”ÈèØ>mët:)/¯èü‡îݸAw wÂõ¡{jiiññðö!¨Ò“8„bÈ2“0ïa^M>‡wßú�/6l£¤p3å…Ý6QT|#ÆrÎ�çñ¿‹.drXÏ?ëfÆ\ñ(/„¿Î³¯|Jææ•¼™   úD3íòëøÅ ç‘Ø¯>³™QW<Æ‹]enZý…_¨�™°¤9\wÓM,N;Ú2›Ë’2�tÿ•|Þ¢¡˜Æ’1õ(ICÕ0R§�À°e'nT"Òg0nÀï‚Fâçÿ–eáoó×eðmΧü3»ë%EÅ'"…‹®¿�Û.›Ìá}co÷;:ö檚ýDQ�˜}Bˆ5šIi³8þ¹¤Çú pÒSoÏÕ‹¶lšÈâ›ÏeÓ“_R²o=+ö)XR¸þ*ޱrÎÐjßB!¾BÃ#in¨§¡®–Ððˆ)³¡¶…€ þM髺Ú* ŠŠ¦¿èºŽÓ墦¦ƒÁ@Gë6‚Ïc*m˜¦VTkFk fG;V§§Ó†ËéÀbvÓÞR‰j0PSSCTT$‹Eéß§%üú?é(�O°Jž½å˜æç�:ã¬~@!~hr6®%yRêÀ¬»h«­¤²¡•‡†bñ'$2†ØPk§¸i­*£¼¾·%„aÃc6Ÿh×ÕM[U)¥µm8U+¡±ñÄ…X¥ã€†­¡œÒÊflº‘€°8†EpüKîí~§#oϵmÙÓ^CIU;ø†ŒµÏ TÚ·Bˆ�ÓÑÞFÙþbF�MÆb=±,N»�â�…$Ž�Å‹‘ÇÓÖÚBéÞ=Œ3SWP±Ûí”—W°ñ¿ÿGùÎP#(]ËÅrhŠ~p…ýÐÿ@׉O^Ä´ßׯÃïú;bàBˆ6h!„BqZk¨«¦¡®ŽÄ1ã¼Î›átØ)ÞUDtlÁ¡á\Ãμeûö0,a>¾~}ÞOÓ4œN'6› »½—³yÃLf3V«/>>>˜ÍfTµo�º8dŠŠB!„Bq„†G°gg! ‰cú½üjG{;û‹w?(Á�ºš*j«+ûÜPU«ÕŠÅb‚»�Ôè›ÓQú;-¥; p!„B!„'IhxF£‰ý{vJTL㱻淛êŠrš›ˆKÙïe[�§µ¥™êŠ2TEeĨq˜ÌÞ'5ˆ@…·$À!„B!„BœD�Á¡SUQFÑö<ü‚  ÁbõÁØ•óÂírb·uÐÜÔD[k3Á!aŒMžxÜ`Èñx<Ü.'N—“öæš›Q…ÈèØ>%Ê$À!„B!„BœdŠª3l8‘ž8ëj¨*/ÃåtÒ¹X»~(+g—úÚjêk«Oø¸ªjÀd6c4šðõ÷'>!ó $*=$À!„B!„Bœ"ƒ�ð¨£bNuUN{²Ò™B!„B!N{àB!„B!ÄiOB!„B!„8íI€C!„B!„§= p!„B!„â´'!„B!„Bœö$À!„B!„BˆÓžñTW@!„B!„ø!sØm´57ÓÞÞŠÛíÆåt¢ižA;ž ª˜Mf‚C �Ä`0 ÚñN p!„B!„§@[K3Օ凇ÉdÂd6£ª'pð¸ÝTU–ÑÜЀPÁÁ!X¬>MfÜ.'»�¦ÆFöìØF@`Ñqñ(êé;ÑCB!„B!ÄIär:¨(Ý�®ëÄ%ŒÀß?p@Ëomn¤|ÿ>‚BB—2 ƒñÈ®¿ÁàƒÅêC`p(·›êÊrvïØFTl�Á¡ZŸ“EB!„B!ÄIbko£lÿ^"cc �ðòëꨪ,eĨ1øøù÷iƒÑHl|Á¡aì/Þ…Ûí"tê6Ø$À!„âäp¶R×bG7øâwèt´ŸŸJÎ6ê[lhŠAaþ˜Ou}Žf(^»¡äd^y/„Bô�­½�²’bâGø¨ €¦†zª«Ê56³ÅÚïý}ýü56™â]E'äðxð¬[‡'/׿LÜ…;Ð5 eìLé¦NÁrÎ90@ù?äþ+„§GÃ>¶ïØGYMíN ƒÙ—ÀðFŽMbt¤uÈ/‹åÜô,‹^�-n/½v ŒÇþyïìÔî+¡Îæ�á$FZ;“dõBo«`Wy+š!ˆøQÑøuÃ*‹Ëhrƒ5b#C͸ò_âš_}BcÐE<õÞ/™nòþ¼Sÿ®]—ƒç«eƒÉŠ_P8Ña¾œÎ鯼º>ÞkÃSüäwkp�„c !„8=9�ÊJö?rp‚»�Êòý$Žñ.¸q€Ùbeäè±ìÙYˆÕê�¯¿ŸWåh{÷âXr/t´ãö±¢bøÑ,4E�ºk×àùp-f Á/<�iôh¯ë|€Ü~…bHÓi/þ’e��²+i׎ì”*ª•ȉpÓ=73”ÏQ;üß º›œü’G¾µaN½‡÷ÿ| ½Fv4Šÿó׿²·1™;^}Ž«ã{iŸð»[^ ßÈÜGßæ‘3õ N=÷V^ùùoø¸E;övŠŠ%$‘Œ9—rýU�8ÔCh'‡ÖQKY½FHLÝ?E)*FUESU”ïõ/¡BoU–î'2:vP‚¥ûЉމÇbõ9á²,V¢cã©®,e䘤þí¬i8^yÏ?_E�ŽD‹‰ÄSß{KðänÔÐ`ÔÀ IcðÔÖQ¿ðR|o¹™À;î€Hr*!„Âl…oðó%¯³µ]Ç'v Ÿ;ƒ‰#¢ ²‚»½�’�Ù|µj»ó>ä‰{öÓúÜY“™5Ù2è§0t¨„%Í`RÔ‘c4<ŽVjKv³«r7kßYÊÆo6óàS¿áÂØÓy<Ç@ð°çíû¹îß~ÜõÆÓüOÌ¡e>û!VõÐ)¬›Bˆ¡¬­¥]× ‹œ¼-M�(ŠBHxÄ€•AC] u5„†Göy?û?þ�ë_o¢ �ÃÓÒŠ^´ºÒøÔ¦WV£WT¡ï܃::ëä Ø^} M× ¾ûn¯ë,!„ª´*>yñm Ú!0í6žârFõmxÁ®Y¼ž'þ{>,ÍcÙß¿`ö/"ê{û°]!8m:ãM›É±oecžƒ¹g9SoÎac‘% ˆ€ö¶oÞBÛ‚9 é`KÖvœº‚eÒ ¦ùÿ�½Iºô~ž˜ë”Q?Nª6¿Åc�¿AVÕ7,}:�Ôÿ7ÿ{ܶú@o¡°°�±§º&B!N35UåÄÆ�Äò+ˆŠ‰ðr#£c©ª(ës€Ã½gö—^F��CÛ_ Í-�˜zŒÊÐuE×Ñu}çnÂ2jmÏýß¹s1�õî^+!„ªì…äìp «�œýÓ‹� nt1„ÏäÎ[ç±ó_eDÇè4º ª—�®¦ýäçí ´¾·%˜ø¤ÉLzDM½µ‚�­àÍèø ÜU¬ËÚM³Ï8~<;™�n½aws ùùE”Ô´`W,E'yb2#‚o‰™ÎŒQr ÛÈÙ¼癩GœCGn[� áçÍ'cÃÛ¬ÌÏ"×6‡³}{lè(`S® ]1‘2#� ž=ýƒ�ìTmÏ&gw5mš…�¸q¤NMØ1²�j¶jŠò·³»ª ›f&8:‘‰SÆãsì�·û <3Ñé×ðû›vpÅ“›èØò5ëæqiø‘áoê¬;(Þ¾ƒ=U t8U,�á 3ž¤8ÿcæýˆ6§µT°«²ÝÎÈ„0ŽøuÑZ)Û]A«n%bDá�öª=”ÖocC‘]·S]\Da‹Kh<##| ­‚�å­èæPFDàÓKÔ¨?u×»Ê;ð{hÐíTmÏ!gwmš…àØ±¤NCø�Í€+„â‡Ý€ÀàLMqØm¸Ý.‚‚¼ìÀà*ÊöÓÚÒL@`б7öxh»ãN”@hnAinAQUP”Î�TŠzçH½+¸�®ƒ¦¡75£øc‰‹¡æg×÷í7(^$•‡B YnÜPPÔc�,Pð?ó^9Zîw5k—ý‘'ÿ“G�³[ÅDؤK¹ïÁ9'úÐíÀ•û ·=ü®ÉwñÆÍ­;‹]žTR»ÿ9ÈÏÌdž™iSç1¥q9ŸnÌeã'g§^!wQYÍF33½—),F#†æ\–=þ¯niàP^NKÌ™Üóă\–Ø£{¬5±å�§øÓëß±¯CãÐÕQP}ãùñu÷rߎ ¦x»ß RIÏ0Ã&Š<µTÖjÞíb{Sg½�ÂÏðÄ?¾fw«‡ÃZ�b!zê¥,ùõõœÝã#Ê€µ9�öõã¦?l@}¯½| £z¾ñ¶�oíªïnÞzðÞB%~Ñ3¼u{ Zö2n>Z’Q/êîÊ�;\…}Ò¼õ»D>{ôq^Ë=¼ š£gr×óÓQ?¤©UBqúikn&0(dÐÊomm”àÆ�A45Ô7ÀáX³O}¦Èô’2TUEQ”ƒ_’Té]A�ƒð”U`“Hûî½tü÷¿øÍ�ÛïºJ€C!†*ËHÆ3°¶¸…5ÿ~—…)W’Òß)zß=µ„?­D Iaáó˜92šö°vù;¬Ì�‡îu°ôù»™Þ•ËB1›1)à´ígùK«(œÈyçŽ$È7‰ÐX³t ¯ªA÷ÃÅ×/â¼IqÓJIþjþõæ*rÞ{Œ{Úá•ûÎ xÀ;äFNO'ö�½”Vf³©T#eD·ª{›ršÑŒã™:!’Iu#1¬ßIöæ=xR“»�ð°7+‡ Œ#3˜{ähÅTÏg�ýž ÎYÜ|ÿLÆE˜è(ߊ7–“Y¹Žg–® õ¯‹8xx½�œÅ/ßÙƒÓ7‘óoZ̼©Ã Ò)ÎZÉï¬eõó÷Së~šç®}h䀷û�Z[;í úàëÛíÍôªÎ:Mß<ŽÏ~Eƒu8g_y)çMF°ÅM[eë>^Ág[Þᡇ,¼øüµ$ØpÊÛœ‘Qóîä�‘™¼ùÒjöÇy7,"#Ȁߨ8Tà¨)[½¬»b4aT@oÛÃ;�½ÉWÎYÜ|ÿ ÆE˜±Uæñáëï±±j]úéûFü�§ !Ä×ÞÞFdLìà•ßÒBHXø •ïDyé¾ãnçÌÙ‚®(ÐÒŠ¢ë��Ž®`‡Þ5‚ã°`‡¢š®ÒØŒÙbƶ9KBñ½bHäÒ«ÏæÃG×P—ûOn½z=çÌ9—sf¤’:>�0ëñ{4Îíïðìg•¸-Éܲt)×�:ðˆx:gŸ•„õæûx¿ì3^úä2ÒÇwÍ‘4b´²¯ù2îRžyåF&u[cÕ‘ûožûo5ša‹ÿ wMö=8“c\J*3Ƙ¹þWQöÅK¼µ0ƒÛÆ ü­Æ8fÓÃß§´v?›³j¹nDÔÁÑž}YdÖjRI‹47u*q†Bʳs(Ñ’y`C­šÍYex00<#½×¢Vñk£oçŧ/cä�K—–ÁŒav®\ò!;¿cCõOÑ•lÒ½ó]þü~1c‹š{¦Êo‘4!�3Æ<Éu}ÎÖ7–ñÅùOpIĉí7èôV6¶– ÔÈ&uKªé]�ÛÙôå4#IWý¸rx·Q3Óùñœ "nû9o×f²nÏU$%u†£y§ºÍ©DMžÃE1í|¾l5û aÂìy\sü÷Á뺫 *à)^Åç©·óR÷6H:ÓcÚX|ïGTíZφê+¶A!„C�ËåÄl¼9…N§ó„–…=‹ÅЦyŽ»�}Ãz FšÝŽªëDîÚ}�fâvSž˜ˆn³aô±ÒñÝ:¯ê*wC!„²TÂgßË3÷Í#)PÅݰƒ/ßùÿâ.ºh!?¹õ}þ]¾È-¥µ×{Ž‹‚/×Pêßô\–xø�Uñ›ÂO¯»œ… .az¸×Á:SOh6H»r1ýº?w’»ú*5óä…,žèÛ#A¥B@êe\4ƈî)gÍ7»9þíÐ æ$ÎH DÕ]nÞBóÁaûÙÙ”zT"RSaCâTRCT<{³Èª=ôœ]oÊaÓn7¨áLŸ1º×¼ºÍüŸ]Ü­cÙÉgüT’­ xj©¨>P¦‹‚Uÿe¯|Òq픞É;‚g.bá#º=—/ÖÕu=õ÷v¿A¤Ù¨/Îä½'ïåá••hª?é‹”ƒ×ÁË:k´´ºÑQ0{ BX’¸yÙJÖ|ø7nL:ðŽ ‘6畯»®D3ÿÚ‹ziƒSH±ôlƒB!†"�Û…Á8xùÉ<.'Óà•o0›®‚r,΂m(f3Ø�S:û“CÃh]G·ÙQ­Vìyù^ÕUFp!Ä�æÃ¨ —ðÊ9ÿCÖ×_²z]&™y;©jo£¼på…›øôí±DNbþ57sËüd‚ŽP¨a{Q=âÇ�åÈÙ-* snåþ9G9´q,i“üï�iU5£¡2lÂxB{ “«1ŒOB-ª§r×Zô¤Ã“ +“gLÅ÷‹¯i/È$Ç6—s}½‰œÍ»q«¤¥�Å`Ïô)¾¬X½“�[Z¸|n0 Б—M�SG IcVrï ë8&�éå5ƒVìvr*h5Ö¡a`Ĥ£äÊP㘔ŠZTKѶݸ.�Äâí~^]·î\¬ÿãBfý±——t­k©b 'ãêßð b=ñ¶Îj()ã£1䕲í�Çø“õFþwöd†ú¤öȲ>tÚœ îŠe ÇöòÔÏ@€�ŽnmP!Ä�äñx0x‘0³¯ÜFÃàuí�#}¹ÓhOgÒP]C×4p»;}ávw%Õ%õ¦®^í%„â¤R}ãȘ-ó¯ÍNuñ6¶æ�““ɺÍ;¨©ÉcùŸÉ–½�òÂ]Ó:;œZ=5õ`$84è(K��b #¢gTÄSOmW™á‘½$åÀ@xX(*õh õ4ê JgÓ7u:S}Ö°¶#�MÎͰ@G›¶9ÁšNúÄ!+“§¥`Y�I~æV:æž…ò7çcÓUüS§3ñ(ÑÅâ‡o¯ŸGÔƒ«�nØþ0Ëòv°â/÷òá³þÄŽ›DZê4fÎ<ƒ™ã#±v?Øjsý6uW¬þø÷úi­—6(„bH2 ƒä0 ¸=nLƒ4JÄíq÷és¤!i®ª*Lf3z‡�ŠQ£®žrpè©z·/Ìf\--X&¤xUW p!ÄéFµ5:�¨ÑiœwÙµ,i*dùS�óì7ì[ñ7Þº`·Ž3€îÂéìÜÅh4ö?Àa4cŸ@�¿®ÿË+œñõ'|ðÅ7¬ËÛKŶõ”o[ÏGÿúA£Ïå¦%wò“äõ:m®ÿ¢îC!R#„âDŒ¦Îi*ƒà0˜Ìx\®A pxœ.8æŠ~�¬3ÏÀöï71øùu®’Òµ:ŠÒõÿît8,¸qà{ÅlÆÝÚŠïÅgyUW p!ÄiΜÌO}7» 䣺r²¶T¡�‹CU¬øXtì6;þ'žxI±bíÊaå°9Ðé™{¡óx›½ó†fµb¬þ™JÆô±s ¨ÉϧTK¢=+—&ÍÀ¸iSëv²jäTÒã äïÏ'wŸ‡tSY5Šy³R{;/(Vü|�ö,Ï,ë[¹š—û ëx®½ûbÖ,ù€ÒÏžãïç¤ðëŒ×ÈÛs=ÀLÒyWñÀyW¡;س5›ÌÌõüwÕzvìZÅ_~ÕŒéåÇY£žš6§i“çd(ý¾!„8eL&ó &5™Í8v¬>òÈæ‡U=~pÆœ:•æ×^Åj±àÑuÔÓ]•^î~]¯ nº¢ úù⬫%$}šWu•$£B1$9i(ÞÂWŸ¼Ëòœúãw¶¬Ñ W�ŽŽŽÎ¨¸I\¤ðPY^ÕkºÛ�ÃÝ�ÇÝjqQÀMeEÕQF¸©ª¬ECÁ3 S)ŽRb¦§“hϾ­4U‘WPƒfˆ%=-îðœ!�ôÔTO¹ù5Ôæå±ß£`JšNÆ@­)jˆfX¤7•Õ}eáí~ƒÈoÊuüüÂHO%?½ŒÌ¶mdë¬XB=mÿ{ûïxåõ®©¡K IDAT?py‚½5›V—u¶Ùos]Ëպǃ§—æ¯57Ñ<Ž!õû"„âTñó÷§­¥yÐÊ÷ ¤µµeÐÊokmÆÇ×ï¸Ûù]pJH(ö–”à 4�MÓýÿÀ—ǃÞõ½ÞíçjX(ŽÆ&ÔÐpü½X"$À!„C”›¼7á¡'_ä©¿®`‡ãØ[ëÍ;((ó€b&nX×’©j(“&Åa@£*;›½Gô®<ì|í6fŸ7‡Ù¿^IC_âj8“'Æ,so=6ç2ó;ÐI“’ñéËézI�Ï`FœÝUDnvù{=¨¡SÉHìù”ÁHRÚdU7; rÉÚº —n`ôŒt"êN¨„0yJ4*27Qìîm#�ºÂMä–µêìz»ß`Rü™yãíÌ WðT|ÊÒe9´woÞÖÙQϞܵ¬\¿{o‡ œÄ�§…¡ ÑXߨàø6gò±`P@oj¤ñˆò4ê·d³ç8ºOaÁ!öû"„âÔð ¢¥¹qÐÊ¢µ¹iÐÊomi&4,â¸Û)1o¼N[mšÉ>Ö¿ºÿ¬ë{ÅÏ�ÅL{u ±ÿzÅËé<àBˆ!É—3~º€D3¸Šßá�ßý›Ìjg¯[:ª6±ì÷/°®MG ;›Kft ƒ70úü ™`Uðì]Áß>*¡{œÄ]¹šWW–àÁÌ„™iôm ƒ�±sç3Áªà.þ�¾¨àð¾­ƒÝË_eeµ†0�³£÷FcHdfzªÖÊ–÷?!ß®à?%�ñ½,:a™˜Æd+ض~Ìûùè†xffÄ`ýTF\pi¾ ž}Ëyê�]tôØÂ±ÿcžxà7Üzõ­<—ï<Áý—2‹;n>ƒ`ÅCÙÇÏð–Žn�zïê¬5|ÃÒ_=£�þ…í°$pì%§ ]1?<¦ë½ø6g–@œ´æ,¾Îk?¬îÊÕ<ýæ64Ñ¿ŠÁЙ—ÆÓ@]C_†x ±ß!„§„Åê(´ Ò( ‹Õ£ÑDë QZšQ üû´½iÌ‚~mUhAA(ahpøŽî_€‰JkY9�wß�qôèƒSXúKrp!ÄeIºŠÇQÆ’§¾¡lÃ2îÙü6±c’IE �ŠÇÖLMé. Š*ió€4‘ë{;g꘩ñ ¸÷†MÜù|›ž½ƒkןìäp �»ùîë�·BÐÔŸq÷¼¾w¬ÔøK¸ï† ÜþüÖ-½“›²/ä܉1ø»Ø“ý+7–Ðaˆbö=·q~è`'0‘œ•>©×§àŠßd2Æ™øvË uX:3F l²/5úBî½3“Û–®gËË?çêìÙœŸ1’0£ƒÚâ¾ú:‡R›‰øù·sÍDó ï7¸T"çÜÆ­_æò§Ìr>øË+üø¥;Iõõ¾Îjôܸðc~ùÞ6þq÷õdž5‹ŒÑ1š4:JÉ_÷5KܘârõyÛä@·9uÄ�¸`ÜÛìÞVÅG�ÜMãg1>Ü„­º�oWç`Yp¬z‰�êuônq %p8 !*™ÕU¬øÓ#´O‹‚  n½zúQÕ­ß!„§Jdt,U奌Nònu�¾”_]UI@PÈ€–[SUApHxŸ¶Õu·Û�ùÆ¡µ•Æ——á…9!­µ t›”μSŠÕ‚ˆ£±‰öý%pí5hW_�ÝnÇ××·×ÜÇ#!„²Ì$Ì{˜W“ÏáÝ·>ä‹ Û()ÜLya·M߈±œóãyüï¢ ™ÖóϺ™1W<Ê á¯óì+Ÿ’¹y%of(¨>ÑL»ü:~qÃy$ö«ÏlfÔ�ñbW™›V¿Eá—êc&,i×Ýt‹Ó޶,æÀ²¤L'Ý%Ÿ·h(¦±dL=JÒP5ŒÔi#0lÙ‰•ˆôŒð» ‘øù¿eYøÛüuÙ|›ó)ÿÌîzIQñ‰Há¢ëoà¶Ë&sx_ÖÛý™ÃÅw]Ã7?Ï–²�yòŸg³ìŽIøy[gÅ�´ÛþÌSá/ó¾¡`õrò´TŸ(¦Ìÿ·Ü¸�ÉÝOt€Ûœ:œE¿ù55ø++ öòÍöò ªO 3?ÁË­¼õ�º‡³Û$ÓDß|.›žü’’}ëY±OÁ’šÀõWqŒ•x†Öï‹BˆSÃ?0ˆ†Újêj« �ˆðòƒC¨©ª ¡®–ÐðãO'鋆Út]ïWyš¦áÑu”o•žAó¯�©¤³Å‚ÑßcD8(àikÇÕÖŽ£¾§ÙŒý™gð™0·®áÑ4¯Gp(á×ÿIGé|‚Uòì-Çܸ0?‡ÔÞ-×"„?9×’<)uà Ö]´ÕVRÙÐJ‡CC±øCl¨•¾�CpÓZUFy};nKÆÇl>ÑÞ²›¶ªRJkÛpªVBc㉠±JG [C9¥•ÍØt#aq ‹àø—ÜÛýN%oê좽¶’òÚ:<*>�á ‹‹Äï¸A§�lsíµ¥”T·â2—0Œ0ëñKò´×PRÕ¾!ÄDÓ‡]¡îB!N7.§ƒ}»wŸ8 ÿ¾Mùè‡ÝFñÎBÇ&wM‹9±²öì,dXÂ(|ýŽŸ`:Gphš†Ýî ¥µ…öövZ››q¯ù½ c~æ½û°'$àHIAOIA=óL| $((??L&SŸGp ¿ëïˆiH€C!Ø 8„B!ÄiÍÖÑFÙþbâGŒÆ¿�y-ú£©¡žªŠ2ÇŒózYZ§ÃNñ®"BÃ#û=äÀÈ —Ë…ÃéÄa·Ón³a·Ùq8œ8ÝNÐuTÕ€ÅlÂêãƒo×—ÅbÁd2¡ªj¿¦§tpÈ!„B!„â$ðñõgXB"¥{÷;àÓU‚CÃÐu�=; IHƒ¯Ÿ¿öïhogñNÂ"úÜ&Ìf3f³™ú–Ác`H€C!„B!„8I||ý1z,¥ûiª¯#*nAV~HX8£‘’=» %*&ƒñØ]�ÛMuE9ÍÍ DÅ#p€“•ž,àB!„B!N"“ÙB¨±´µ4SYZB…®‚_` f““ÙŒªz¿Ú[`P0~ã'R]QNÑö|ü‚ é\RÖÔ™]Þírb·uÐÜÔD[k�!Œ—‚¢ž¾Ù¡$À!„B!„Bœþ�Aøá´Ûiii¢¶²·Û…ËéDÓ<vœæÆzšë;ÿ¡tþGEÁd6Bô¸ ¨ï*C…8„B!„BˆSÈlµn�†ÈS]“ÓÛé;öD!„B!„¢‹8„B!„BqÚ“‡B!„B!N{àB!„B!ÄiOB!„B!„8íI€C!„B!„§= p!„B!„â´'!„B!„Bœö$À!„B!„BˆÓž8„B!„BqÚ“‡B!„B!N{àB!„B!ÄiÏxª+ „B!„8ýéÎVª+«hhuà€5 ˜¨¨(‚­Ç~¦ªu4RQ]KS›�jÄ7 „¨èHÍÊIª¹âûBB!„Bïií”ä|Ë7[öÓèêñšÑ�áÏböôöŒs8رi-ßm¯¤ÝsøKŠ1ˆSÏdvZ<~2æ\ÑGàB!„BxG·³oÝǬÜÚ„[õ!jlcケê+v²mg%9«XášÇ¢³†a90(Ckbëª�XSbS0#Ç�#!Ò“ÛF}iÛ‹Ø›ù98çsŬX̧ô$…§ p!„B!¼¢Õäòí¶&ÜŠcç\Êù£ý%ù?�äˆOy÷»rš ³Ù15ŽÉ  c/Þ̆;º)†3ÎcZ„éP¡))ŒËþ˜÷7VÓP�CÑ”&úÉt!ÄñÉ€/!„B!„4j÷î£ECôdfŽòïѹP ?� ண²öÀ<•ûʰ~£S™Ò=¸€‘ð )ÄO-ÕõúàŸŠâ{AFp!„B!¼ ‘º�ë’Ú±©þö6ÈÂ`Åר5Üž� ÃÏYÌõÓhFÿ^;$ŠÉŠÕ¸A×%À!„è p!„B!¼¢š­ø›­øåuÝÞHC bèú©‚ÁdÅßd=j¹ž†jj€1”ˆPt.„è p!„B!žî¤<'Ÿrc’HêS BÇѸ›ïVçQ§©§L%É_òo!úFB!„Bˆ¦Ñ¼s «¶6á1E2ý¬‚�ßÐêÉÿ*“}v7ÎöFjë;ðXC5}ç¤Ç*ñ !DI€C!„B1ptu«ùè»}´©A¤œ{>éÇêv8h(ßϾö®ýˆO|df n!úAB!„Bˆ�¡µQ¼îsþ[P‡ÓÉÔóç2k¸ï±—nT"˜vÑOHv{pÙ[©-/f{akж‘7îÌC ¤áBô�8„B!„'L·W‘óå*6ìï@ É�æÎfB¸‰ãÂPLø‡Et%*�fXÂ&%ðÉëØ_ô-_Åİ Åÿøå!~ð$*„B!„8!º­”u}Êwû;°Ä¦rñOæ0±/Á�£0„$“6ÚEqQ±·›¬+„èÁ!„âäp¶R×bG7øâwèt´ŸŸJÎ6ê[lhŠAaþ˜Ou}Žf(^»Ápº¼Bü@éÎj2?]Å–Z7þ£ÎbÁy)„ë’ÖÌÞü]T¶» IÎ ¹×ÕU,V+ èv'.d‡§'MÓÈÛšÇþýûhjnÂãöJlt,©SÒ0›Mv¬ïíg!!„ø~Ñq4ìcûŽ}”Õ4ÑîÔ0˜} �aäØ$FGZ‡ü�<ç¦gYôðjlq‹xéµ[˜`<öÏ{g§v_ u0‡ '1ÒzÔÏ»z[»Ê[Ñ AÄ�ŠÆï¨vPY\F“¬#jÆ•ÿ×üêƒ.â©÷~Éô�»ï¨þ]».Ï÷h�C &+~AáD‡ùbÈ {éty?„øAÒmì[÷_2«]ø ŸÅ‚9)„÷‡›š¢l²ê!XÉØ3¢Žü[£;¨­iALþ~X‡úMNÑ«úú:V~þ)VââcI=UUimk£ª²’7þý:ž!±±±r< p!Ä�¦Ó^ü%ËþþeWÒ®Ù)UT+‘/à¦{nfþ(Ÿï÷.ÝMÎ?~É#ßÚ0§ÞÃû¾„ˆ^?ôjÿç®e7nc2w¼úWÇ÷þéX«ø„ßÝòùž@æ>ú6�œ9¨gpê¹·òÊÏÃÇ-Ú±·ST,!‰d̹”믺€äX†?­£–²z��˜(äÓ’Gå,ÏbÍŽ6ðÉÙçNèCpPC36’ìõÕ4¬e]Ü…œ™à×-Èá¢aÇ:6•º+ÇÉÈ-!NCš¦ñ٪ϖOTT$•å”ì+Aóh„G†3jt"‘Q‘¬üüS®¹êºÉ!·l!„Âl…oðó%¯³µ]Ç'v Ÿ;ƒ‰#¢ ²‚»½�’�Ù|µj»ó>ä‰{öÓúÜY<ò{üx[ñ#}Æ,k3qìØLvûÅÌ è%¤£U³9k?Ï6e7pe|x/£\t·dSäÅg2³&[ý†•°¤LŠ:²7âq´R[²›]•»YûÎR6~³™Ÿú Æ…ñ'ƒ‡=oßÏuÿöã®7žæb~XÁ!úL·S¼µˆVg%ßýçMÖcsóȳøÌ8TTB'�ÅŒ’Oø®¼Ž¼OßbOdqaþ˜pÐRSNy�  þ£fpæè£�ÖB ][ ¶b6™ˆ‹‹cÓ†�D„G’ž–�Ñdfß¾½lÎÜÌgÎ$4<”-¹9LϘ~ÂÇ”‡B UZŸ¼ø6í˜vÏ?q9£¬=¶¹`×,^Ï“?ÿ=–æ±ìï_0û�õ½í�)§Mg¼i39ö­lÌs0÷Ìžôæ6¹Q‚hoaûæ-´-˜CàŸ�;Ø’µ§®`™4ƒiþ?¤�ÐF’.½Ÿ'æme'U›ßâ±Çß «ê–>�Fêÿ›ÿ=n[Ýè-–£1öT×Dˆ!΃ËÙ5Ìc§­õØ[›í.ŽC4„“:ÿ2Bò2Éܶ�šêýÕt½¦ƒ)0†qÓ™9)¿Âß!¾‡JËKˆ‹�eßÞ}D„G1÷ü¹_KˆŽÁ ²k×ââb©ª(�cJ€C!†*{!9;èj gÿôâ#ƒ] á3¹óÖyìüWÑ1:�.ˆêe ‚«i?ùy;(­ïÀm &>i2SG…1ìWo­`gE+øF3:>wUë²vÓì3ŽÏN&¤[oØÝ\B~~%5-Ø A‘ÃIž˜Ìˆ ÁE¢F¦3c”�œÂ6r6oÇyfêçБ›ÅV§BøyóÉØð6+ó³ÈµÍálß: Ø”kCWL¤ÌH#¨gOÿÀ¿u;UÛ³ÉÙ]M›f!$n©SFvŒ1Óš­š¢üíì®j¦™ ŽNdâ”qÄøû“º·û <3Ñé×ðû›vpÅ“›èØò5ëæqixÏ‹¤ÑQ½‹­Û÷RÑÐ�Ë`%8j)““ˆó=v�ûÚ&ô÷C§½j¥õÛØPäF×íTQØbÀÏȈïù0!úKñcâ‚›™èíþÆ@F¦�ÇÈT {[-íN<Š‹_ Aþæ!‘Há½ú†âGÄSUYÉÔIiG¼ž8r4_»š‘ 45'BÚGàBˆ!Ë�ÛÓ™6^Q�Õ­Rð?ó^9Zîw5k—ý‘'ÿ“G�³[ÅDؤK¹ïÁ9'úÐíÀ•û ·=ü®ÉwñÆÍ­àÕ[ùò¯aŒx™ß�|häƒmò€Á?ŒŒšw'ŒÌäÍ—V³Ÿ8λaAüFÅ ù•Š„Bˆ¡`ý�±ñ«g0%<:Ømí¼üh2šÇ†Òuk×5]ß±¿@Ó<üå×Ì<÷Ì<ÿA¯�-!„ª ‰\zõÙ|øèêrÿÉ­W¯çœ9çrÎŒTRÇ'Ö‡5óœÛßáÙÏ*q[’¹eéR®u`ÃtÎ>+ ëÍ÷ñ~Ùg¼ôÉe¤/ŽïìÀ©F €Vö5_Æ]Ê3¯ÜȤn�à¹ÿæ¹ÿV£F°øñ¿p×d߃�×q)©Ìcæú_}DÙ/ñÖ n7ð·ã˜LŸÒÚýlΪåºQ;Ÿž}YdÖjRI‹47u*q†Bʳs(Ñ’y`C­šÍYex00<#�½\N­â;ÖFß΋O_ÆÈ—.-ƒÃì\¹äC*v~džêŸ2¢+ ¥{ç»üùýbÆ=þ4÷L=”ß"iB:gŒy’ëúœ­o,ã‹óŸà’ˆÛoÐé­lþl-¨‘)Lê–lÓSô)ïæ¶¡¹ò÷�pó˜CÓ’¦¦g0Üu=¿ø¨†¯?ø–;Î<´Ú�Wm²ËÉx?¢&Ïᢘv>_¶šý„0aö<.‘$£B!DŸ­_õgîÿãË<÷J5]GU \qëR|}ÌøùYP ::ttØY¾²tƒbàžßþ�§~û« pÈ[!†,•ðÙ÷òÌ}óH Tq7ìàËwþÆÃ¿¸�‹.ZÈOn}€GŸ—/rKiõô¶¿‹‚/×Pêßô\–xøô Åo ?½îr.¸„éáN\_èLu Ù íÊÅLct¯s½u%šù?»øPgº‹Ïø©$[ðÔRQ} L«þË^7ø¤/âÚ)=“w*Ï\ÄÂ1Ft{._¬«C;¡ý‘f£¾8“÷ž¼—‡WV¢©þ¤/þ Sº]uÄOøÓËãù??Èå£zæ\ñarúx|Wé^JVØË6Ùåä¼B!„8.· “Oq1¾¬Y½š  #ÑÑ1„GDŽ¿(¡¡‘ÄÄÄîÇ—ÿ]MD˜~A³p¹{ÞýûGFp!Ä�æÃ¨ —ðÊ9ÿCÖ×_²z]&™y;©jo£¼på…›øôí±DNbþ57sËüd‚ŽP¨a{Q=âÇ�åÈÙ-* snåþ9G9´q,i“üïjU5£¡2lÂxB{ “«1ŒOB-ª§r×Zô¤Ã“ +“gLÅ÷‹¯i/È$Ç6—s}½‰œÍ»q«¤¥�Å`Ïô)¾¬X½“�[Z¸|nçt‰Ž¼l œ:jH³’{OŠªXÇ1iL/¯ü°*`·ã8�CB«¡ ° #&%W†Ǥ”PÔ¢ZжíÆui$o÷óêºuçbý2ë�½¼¤ëhzçy)¦p2®þ ÿ· ö°§"ŠO( £BI8l? �Û�ÛãÁ¡Z0+`s8p@�`›<)ïGï‡B!D?è²èò˱;4¬V#šæ†n™°TSg^¬k®O[»?+NǾ>®8„â4 úÆ‘1ÿZ2æ_ š�êâmlÍ/ ''“u›wPS“Çò?ÿ’-{å…»¦uvæ´zjê5ÀHphP¿WP,aDôì�zê©í*3<²—¤œ E¥­¡žF�Ap€oêt¦ú¬amG› œ›a�Ž<6ms‚5�ô‰ºªV&OKÁ²:“üÌ­tÌ= ?äoÎǦ«ø§NgâQzµŠÅß^Óø«¨]'hðH=5u�cö½ÿW~ÞûÕq77¡£ã¨«¥Eƒo÷€1˜Ö (Â|{¼9ŽªêÛÐÔ02ÝÀÕÿˆiqÖÞÛ�­‚�Ÿ®àãu[ؾ·œº.í𤳇Uó„ÛäIx?dl«BqÂ\¶|tÇj,¾)8[š±µã°5c··a··c··ã°µcw´a·uàku‘�xÞ WBqºQ­D�N#jtç]v-Kš YþÔã<ûMûVü�·.XÆ­ã  »p:;w1�ýïLÍ�ØÉ…ËÝù�Étô2 ¦ÎÛ‹îvãÒ�²Ñ RR9#Ùĺìf²2wáΘ€g[6¹v0O™FÚÁ©5 ASÒkÜDAnγ˜®î"sK3šbaêÌ)ô\=Ö+º § @G÷¸p¹Žru|Éóc�±súŽ·û�0©·¾ÈÒ¹=¦nØ·ó÷Û~Á{)k a\lïÁ ½9›g—<ÌÛ»ì` gÜ”3ÈF ÕÜÙÞª6òöª"ì‡ítbm²_NÙuB!( k {@×øÿìÝw|UúøñÏÌ­é½'$!!…NBXׯª`]•e]ËÚ]uÝïÚ»~m?•]lkå««¬]±#¬HO€€„ÒëMn’[g~„ Ò ÁçýzùRsçœ{fîÌ�{ž9ç9ŠîA×]�ÿh.t͉¦9ѼN4¯ÍÛ¿©)»H€C!†9Cp&çßö7¶l¸“Oê+X½¦-=U±âcÐqt8Ððïâ%ÅŠÕÚùŸÎ':ûæ5è|?g‡P¬V,ƒÕ‹UCÉ�’†1µ”k´­^K³f }òDºì¬9‰œ¥¬-ñ’cÊgu­†bËÑYÝíC(Vü|�Fãþò4O�vpõj},7X¬£¹äogðýMRþÅ3ŸƒÙÝ>Rr™g@wofmÞ: ¶{QC'‘;rßD F2²'¨z(Ú°–Õë·àÖ ¤NÍ!r î„J&&b@£rå Š»½¯kÔ®`íûžw_Ë &ÅŸiWü•S¼•Ÿ3g^>m]Ͻ{»(„„ïÿcÂSÊç ×ãÒéšOlpÎÉ÷a`Žëáyþ$Ä‘C×uZš›©(ßNñæ_ؼa›7¬£xó/T–•ÐÒÜŒ~˜žô !�~˜-H€C!†$_Ž:ÿ,FšÁ]üwÜ÷&+k\Ýné¬^Á¼^`‰]G ;Ž3§ìŠo uúiŒµ*x·Ä¿?)£kœÄSµ˜ÿ,,Ë™±Ó²9¸� ÒN�ÁX«‚§øc^ø²rŸø¼“­ þà5` g�5¸7ÃH¦åD j­¬yÿ3  þ³½ï€À2.› VèXÿ)ï´£˜–;€íSIúýL²}¼% ˜ûÎÚ÷ÙÂYú)�Üq×\t ϸúYnp)!GsÝUG¬xÙñéS¼°¦}Og_� :R<îÝ^O-Kž}„÷Z TAwÚhrì*9çdOú~\ƒ¡3ÿŒ·‘úFY£rÓfP|86g|·£F¿ 䦛øqÍ& 5>‡©IÝ.ÉÑgjôiÜ|ýJ®�³”5/ÿ�‹òNdzn2aF'uÅù|û]>å&fü•‹Ç™û]np©Džr-×|³–ÇWVðá¿^á„—®'ËPc8aú^ݘGÕ'qƒãLNNóÇY_Lþ�?°Æ5•{ÿ__]ÿ?u¬á�ç?@ËÉä¨ãÇ6çd�{ÐÇ㪎 1DeeM5=~?m“£ (—k.šÒÏ ‹¿uÕ•´Øš‰‘Œ_@À~¯[¬>X¬>„†G`··RQº�Ž 6"¢cCk…ÁårQQQÙù?ºt'à݉~À ×{n°åå;HHˆÇº+ñ[/H€C!†,3‰§ßÃ2�çÝ·>æËe¿PV¸ŠŠÂ.›(*¾iÂéüiÖiLÛ÷kÝ̨ ä…ð×yú•ÏY¹j!o¬PP}¢™|Þ¥üÏå'3²W}f3)<Ä‹;ë\±ø- ¿ÙÕ3a§pé•W2;»§ed–eÌrü²¨EC1¥‘;©‡¤¡jY““0¬)ƒJDÎTÒü.h$aÆ½Ì ›gç}È�ùŸójÞΗŸˆ1̼ìr®=w{Ç~úZn�©1œqÃÅ|yÕó¬Ùñ)O¼zó®�*qgÞÆƒ5�òÿÞ_Ë/‹^ç—E ¨>DO:‹‡oý ÇE{ˆž½ˆ ¯­§èóçylíù®Þ¶ZʪÛÀ7„˜¨`¬rb q@öV5•¤fŒÆ`è]Ùãñ°móF¢bãñ¤ !‹Ãá ¢¢’å_ÿ/E¢*FPv.Ëž +{òîè{þ¥ºNBæ,&Ÿpk¯FpŒ¸á9vÅ4$À!„lÐB!Ħë:ÅE‰O‰ŸÿþÓR†ÝÞBEi #Ó2{ýäVqxiš†Ë墣£‡£·«wyÃLf3V«/>>>˜ÍfTõàž,t pÈ!„B!D¿µÚl˜Í–>7üý1›ÌØ[l`넃MUU¬V+‹îõ I»‚šý nJ€C!„BÑo­­M…„õ»ž Ð0ZmÍàb˜ˆ@E_I€C!„âj³·PY^ŠÇí>ÜMbÀEÇ$ô»?*ʶckn€ !öe4™ˆKH·£­†* p!„BB•åe$&�Â×ßÿp7Eˆµq]F“©ßõMf £'d@«„ûj³Û)ß¾•Ô̱‡»)Nò� !„Bb½›•,„Bˆƒ!#8„B!¡¸„DÊ·oÅíî]vy!†�Û…ÁàÓï:¼^/ëóWP«„]™Lfbw3…8„B!!_ÿ€#rX°•e%´ÙíX¬ý p´µ¶J숤�i˜â7C¦¨!„B!ú- ([SC¿ë±55Ê *Bˆ>‘‡B!„¢ßüƒp¹\Øí­}®ÃÞÚ‚ËíÂ?0h[&„ø­�‡B!„¢ßE!*6ŽŠÒíx<ž^—÷¸=T”•�¢(ƒÐB!Ä‘NB!„BˆáDPPeÅ[zäðx<”m/"(8ÿ€ÀAl¡âH&!„B!Ä€ �ŽÁ×ןm›9¨é*v{ Û6oÄ×7€ð¨˜CÐB!Ä‘JVQB!„B ¨ðè¬~~T”nÇl2†Ÿ¿?F“è\ ¶­µ[S.·›¨Øx¹!„è7 p!„B!œ@ ~i™Ø[l´Ú𩝩Âív£ c4™±úø�`�äÜB  p!„B!…¢(˲¯BˆCBrp!„B!„bØ“‡B!„B!†= p!„B!„bØ“‡B!„B!†= p!„B!„bØ“‡B!„B!†= p!„B!„bØ“‡B!„B!†= p!„B!„bØ“‡B!„B!†= p!„B!„bØ3î!„B!„¿U^¯—ÆúZZ››p¹] ièƒø~ªjÀd6c4ñóÀ?0‹ÕgßñБ‡B!„BqˆéšFUE9öþAADÇÅc±ú`4™ð¸]8475ao±JTL<cÿºñšæÅíráv»±·ØØQº€¨˜8üƒú½_‡“8„B!„BˆC¨¥¹‘šÊ ‚CBI3¾Û …ÁàƒÅêC`p(^�‡šª ¶l\Olb2�AÁ}~oU5`±vÖíHt\öÖª+Êi¨«!6!“ÙÒŸÝ;l$‡B!„Bqˆ4ÖÕRSUARÊ(bjD†Áh$6!‘)£¨(ÛNSCý€¶É? �ÔŒ1‡†Q²µˆŽvû€Ö¨È!„8¹ì4´t )>…ùc>Üíé W+õ-tƒ/!!~Ãã†5\Žûp<¶bhééêíß…â7¦©¾–Ɔ:RÒ21[¬½.ïëçOJZ&Å[6£( Á¡aÚ¾°ˆ(,VÊK¶Ÿ8_ÿ~שiëÖ¯£´´„f[3^�—�°Pb£cÉš˜�Ùl€–w’û‹B Aî¦rŠkÛÑzYNõ‹eT|Þ‚—¸ø–Ïh šÉÜ÷þÁ”�»o2®O3ëžÅtÄÍâ¥×®fl¿îXêJʨw‚9d##­(=l©Û+ÙRÑŠf"!%¿7l§ªxͰF$‘jÆ=LŽ{ŸŽíîýUð�I!!ð×�êö*¶T´àUˆO�%`÷æ-Û¨°ëãH�ñÛóYì~�½S«)¨ÌV‚#ˆ±bèåþ=:ÎÆ6n*aGm3m. ƒÙ—Àð’Ó2H�´ù!¶=�C=þ}Ù\þpß÷¸äzBˆá©­ÍN]muŸƒ»˜-V’SÓ(.*ÄÇ׋µïuuÇ? �„äTÊ‹·‘”šŽÉÜ÷G6 õ,\ô9Vâb™š„ªª´ÚíTWU1ÿÍ×9múiÄÆÆHÛåö"„CŽFýâ9\ñÌzܽ,i9êv>t:ÃsÖä Ò=äÿß?¸ÿÇÌY7òþ?Ï$¢Û¤Fñ÷sÙ+[ñ3¹î?ÏpQB÷]M­ò3î»ú ¼�œúàÛÜÌ îÁáçYÏ+¿‹O[Œ}ÇûÌ9Õ¿Ç €{Í+\{ÏbÚLÇòà'pÊîäì.–=÷ýäÆï”ùâî£öŒtÙý=„ös@ YÓ8åô³˜‘‡ï¯5bÈÑi+þ†yϽÆ'yU´iûçÈWT+‘ã~Ï•7^ÅŒŸ_=ÆÃŠ¢bTU4UE9bvJ!z§¶¢œ˜Ø„Y±Äbõ!*6�òÒbRÓG@ëöæïHDL,Uå%ŒHIëSš¦ñÅW‹ˆOL **’ªŠJÊJÊмá‘ᤤŽ$2*’…‹>çâ?_: #9$À!„CŽ‚5f Ó¦ùáÙëï:meë(¨p Œ`âØXö�×›2"Ž€§Ûƒ@ñ#gêX,?­Ä¹iymgpj@7½,­†U«Kñx·±"¯‘ »yš®Ó´&�ÍP|&pô ) ,•°Œ©Œ�Ús6{�m4Õ”S\VIÁ÷ïSðÃÇÌÏšÍ]w^Ä”ðáqÖwÎçï7½Îú6ŸØ‰œqÒTÆ%EdO[#eEy|ûÕ2¶®û˜Gn,¥õ™Ç˜�¬®²~ÃzÌ&qqq¬X¶œˆðHr²s1šÌ””lgÕÊUuÌ4BÃCY³6Ÿ)¹SúÝf p!Ä�£rôU<~ô¾÷RøÒe\ñF9J©ÜþÈÑÃ8öÞŽü8ò)gOa´iùŽõ,_çäÔcöΩÛòY¾ÙƒD@[ W­Á~Ö)î igÍê�¸tËø©Lö—GÒËHÆ9·óH7£D<ÍÛXòéyñ�Ùž7Ÿ[þÞÈÃOÿ�cCmR‡Fõš/YRj&ãw'26¸7ŸWÊv­¦šÏ^|› m˜}-Ï?r)ûž‚¿?‹‹g/剿?ÀÇåë˜÷Ü—œøØL¢†ú|!„ÔÜØ@L\€×KMUå 8¢ââ©*/ëS€£¼¢Œ¸„XJ¶—Å©ÓOÝýZb •-[¶KueÅ€´WBq$ÛÕÓToÌ#k vÍBH\:YS ÛgJ¥ÖRÉ–ªVtk8ɉaûOuÑZÙ±µ’VÝJDR"á;7Ðí•U´‚o4© A\�åç±qG+ßpFŽÏfb¼ßî‘ÎúM¬Ê+¢Ò~‘#ÉÊCÌ�æxll/XÆÒF"“Ç2yL,~ÙùS#s˜šb ¿ÐNþª�¸ŽÉÚ/ hûÚÕ¬w)„Ÿ<ƒÜeo³°`5k;Ná8ß}6tn`ÅÚtÅĘ©ÙíÛô^÷®´Ž6ldku3š™à葌›˜NŒÏ¯ïh_Ë 7Æà~wѽää¾Ëí·¼Ìªò…<úS¶ G!ù›œèj Ç�ÆþÁ�� áÓ¸þšÓ)úï¢ctšÜÕÍ!ws)ë6QÞÐŽÇLBÆ&¥„îwNë­•Uî¹6=ÕX²z+6ŸtN81“�.ç®ÇVFAÁfÊj[p(‚"G�9.“¤ þ�"Ùõ¡›CILŠÀGÙû;tÕóÉßZ�]³›FÖ¤Q„÷tÍhÔlYφíuØu?¢Ó&0)%3.JK¨uNyàï!„Dö–f4ÍK@?–víI`p•;Jq:ž‹ ˆJ]ÇéèèõÔš†ÆF’¨®ªbÒøìý^™œÊw?.&91‘f[뀴WBq$31ØÖ2ïá‡øÏšFöänT°ÄÃ��Üɹ#wõžtÚ–þ›+]†–z)¯½|1)ûv;–óÔu�ò“7™Ë_~‰+S:;{î‚×¹þίpŒ¿Ž7o‹à¿w=Æ'Û;ØõvŠ!”œ«á± ([ð(·¿ð3U®Ý¯bŠ˜Â��ßÏy#÷ïÅ(Š‚«ôsî½ï9¾.ßS'ŠJ`ÚÜñ¿×sBôAt:Õ¦å&ðbávòV³Å›Å˜½Š9)XY@f&O:�‰M ø|ùZ–orq\ÖÞíòl^Íj›†T¦åt3…¥WÇ}'­™5ïÌåñצ¤]Û³Ÿ(¨¾ œpéÍÜzÁØýƒ)}-7¬)ø¥ŸÏ}×ÿÂ…�.¡ùç7yË \“>”Öxðxu@AQíÃPð?æF^é)§‹§†Ÿæ=Ƭ£ÖÕ%‡‡b"lü9Üzç½ç8¸×¾Âµ÷|‹{ ̿ª•o~�_ÚuÔ¨sH:>“#àªäÛyOðä‡{× (æp&�}=w\y ýXÈ�7�«ºI2Úõ»ã­ûFòŃóÚÚ½¯sô4nxäÎOÙûšñTþÈ“ÿ;—›lìNg¢Xˆ™z1Ü6�Ÿîº‘ù!üáŸopKÖ‘1ÕG1<55ÔJpc—€À Z[mƒà ¡µÅÖëGG{V‹™–Ö6BÃÂ÷{=$8{kf«…GÛ€´u(ÿBÑOŠ©�/z€e®£¹êöi¤G˜h¯XÃGó°²j OÍùˆ¬gg‘ÔχüŠÑ„QÝ^ÄüGßf}ÒÜyÅh"i`ý¢ÿ2I%«þïYæâYôz Y—ÞÎ iÁxk øøõwYV½‚çžûŠãŸIä¾mñnæµû>bKÐI\ûç\ÒBMØJ–³àÍÏ)Øü ÜÁˆgÿDÊïh’§ä;;åUy¬(×ÓuÇ=[X‘oC3ŽfÒØHÆ×'cXZDÞªmx³2»ä6ñ²}u>µ“s™»ÿÁëõq×ÛÈñþñÎ6\¾#™~ålNŸ4‚ ½‰âÕ ™ÿÎO,~þvê~ý=–W/ãÙ9’óï?î¹f\…Ì»û>ØæÆ3…YžAN¼•Öâå|ðækÜúÈñŒnÓfãÝB Cí„EDZýþA4565(õûRW]uÐÛ/ýò!–û¦Ä;@GG/?˜‰æíØ�hZ×tt|Ó@Ó¼ü붦�ô?L›~gŸÛ*!„8‚i•?óSô_yñÉsIÞõô5;—©ñ.¼éc*‹~fYÍù$Åô3¡*¨€·x1+N¾�Wï:–Ð�7°)“#iºäV>¨ù…WŸkâsžç¦¬]¹r˜RÏw}Iã†U¬uÌdú>ÓA¼•kÙ0ñæ=qþž}È�Êqcü¸âoo³mó¼½úîšzà§ ÆQS™þ>åu¥¬Z]Ç¥IQ»G_xKV³²NÃ�˜Ev¤‘¸I“ˆ3R‘—O™–Iò® µV­Þ�#rsº õö¸{ŠÞåŸïã4&2ëá'¹qÒžÜcs8jÔ\z÷"ÖÏŸÇ—Óá̈þ•;b˜Ó˜<Ö—÷ªÚ¨(ÚB‹ž¶×”‹!Å0’s.:Ž�üžúµ¯rÍEK9þ”“8~jY£ ³ø³qm|‡§¿¨ÂcÉäê9s¸4e×É5…ãŽÍÀzÕ­¼¿ã ^úì\rf'tžÛª íøŽoâÎá©W®`|—µ��kß䙯kÐ IÌ~ø_Ü0Áw÷9”>&‹©£Ì\vË'ìøò%Þ:;—kz”ÌîX”õW^êzÍ�Ô;³oþ„ê-KYVsÁÎkFÇöã[¼W쟉\7ç!.ˆßÚš8™ã�JãÎkçÇ&…!¿æ®∧y½ýZö@,+n·sÐê7›,¸]®ƒÞ~éWÿäöÇ^æ™Wjðê:ªbà‚kæàëcÆÏÏ‚j0ÐÞÝÁ‚…µ ë7Þû(sï½EB!º§+ÑÌøË]: �|FO"Óú •Ž:*k4èo€c×û©‰Ì˜uÔîàÖ Æ¥YPíÂ�1“Y÷Né›9†Tã—¬p×SÝ �ï>mQC8ñOÝìCæLff¾ÏSëm¬\Q„gê„ßÔ̕ȂE6 W­Áö‡Swvˆ5*óò(÷ªDde‘dÃÈId…¼MÙöÕ¬®›MòÎL�zs>+¶z@�dÊÔÔnG ôÙðÕ×l÷€ÏQ³¸d⾉5‚§ÍâìQßðBÑZ¾\RÏÌs"Qû\®¿Ü¬|òBNý÷" níý~¯1ŽŠ­±�FB7Må%T·w]jÖC™Íº›†²" ÷: *±)Ät~}/{ *á'ÞÌSN_|n›7ñÍ;›øæPLþĦŽaâ„IäN›ÆQãØïÄr³á›ï)÷‚ïQgqî>Ó¹¿‰œéyx6h„†»pC爥3%ŒÖÙÎfœ_×ÏÍÅÚÅ?P¥)˜'�Íìq¾û�CYç2sÔBžß\Á÷?låªôŒA%£+Ñ̸df7×ÌDÆX>¥ÚÙõšq°fÙÚu¿ig3#~ï¢OæÚó>féË…’pY14è:ÓàM•3˜Mx{€è-£É„×sðߨn�“Oq1­|¿x1¡!>DGÇ`6›0 (Š‚Õê%(H'2¼�o¾^Lt„~ASq÷â}ºmk¿J !„Òk:ãGusC5ø`UÀáÀ¹Ïœû~½Ÿe$é‰ûvŒø™�É)DïÓT|ýñÐ�¸ºi‹bLgÒèn&W¨¤� A]_KSi)6}a|zoeÂÔIø~ùmV’ßq*'ùz3ù«¶âQÈÎNÃ`Í”‰¾|´¸ˆåkZ8ïÔ` }]\:jH6Ggvÿc¥WÇ]«eCa=’Æ÷�+C�cü˜PÔÍulþe+îs"±ôµÜ�Ñé¸;Z±uô»¢ `0vžoº¦uæaÐêXôØõ<µ¾»Hv>}è:>ÝëofŽ»çC?Ù§eŠ)§ÝÄ+Çÿ‘Õß}Ãâ%+Y¹®ˆê6;…+¨(\Áço¿ˆ%r<3.¾Š«gd´{äP-77 a !=�ýg·¨$žr ·ŸÒÃ[ÓÈï·wC«¦p³ •ø±£év!5†Ñ™A¨›¨Ú²�=cPFÉ(–QŒKë&ɇ1€œ]¯™jŠKœèHÎHeÿ£¯2bÚ’^)d‹¶ß‹BqÈé€Ñ0x]o£ÁˆÇë´ú Þ^Ö¯ȬóÎÃáÔ°Z�hšºd SM�yÃ.þóhìmüý¬¸œ%ýn«8„â¦Xüðíöq«Šº³33pá P|ýèn±eç„K_?Ÿý–ýDQwþMï¶-J`$‘Ön{ï„„¡R‹Öj£Eç à›5…I>ßóSû:VlprR®Ú×±âXsÈ·+`eÂä1X¯¤`åzÚO=?œ¬* CWñϚ¸¢½:îZµõ�½°’÷ïæÂEÝ�ðØšÑÑqÖ×Ñ¢AD_Ëõ{‡™i·¼Áÿ›ð«[y~~Œ3øŽ�IÖ�[+:`ðÛyî)þ¤wç¥vý!¦S�ÿ%?—›É8þDÆì•çÍHjÂΫ?e{Aõ�#wÆ%äθ45Å¿°¾`ùù+Y²jµµëXðϰfûƒ¼pÃäÎà•Ö@mƒ  Úÿ::ÅFľQou;ë �ì&Y.ÂÃBQi@kl IgpVü»ýUÚÝ5ÓBSKg»C‚»m·�@œA‘‡bHP�׃É88£8<^FÃàe¡òz½zY¿»£Ý¹‹ï\-6:ìÅ8;l8vŽ6Ž6œm8œvíøZÝ$Ž<¹ßm•‡BˆõëëCô�Å‚¹‡‚FsçmLw{qd¤F Èâ¨LKòl¬^¹OîX¼¿ä±Ö打ÉÞ=„_!hb6iÆlX»š ®c™¢naåšbaÒ´‰ì»zlŸèn\nÝëÆíîag}Éóc�oÊ ÕhÁl6ÿúgm<‰´¶7¡¡â¿s™Ø@²/¸ž­\… IDAT½£s³â‰Yº#ˆ)³¯çšô~¤)ý(ÛWª•¨Ôl¢R³9ùÜK¸©¹�sæé*)ùèß¼õûy�ï©»Ù5úØh4ö>Àa4³®M7nOç™L=×i0í¼Î<žƒ¾Îz¯{¤»pîdÓãQ£™ƒHk"„‡†¢àu»-Àáu¹1˜û±ÔÕxÜnŒ½žb£€®�î]CÑ=身óÍ…®9Ñ4'š×‰æu yfR¡8„B©¯`õšj´ô8TÅŠ�@ÇÑá@ÿÿùT+»Vtv8ÑéîœÖqv8ÐÅj=øël0)f,;?l§ËÝ}ò®6Z½ƒ�Bˆ^Q \NVŸy4²§Ó�É4xk¥¹ÜNŒ¦^ÞeõÃó,±m!„;)(Š‚è^/Ýõ 4[3¶CáÐ[j©qtw“ôR_Û€†‚!,bçÓûƒ¡3%‡‘ð–¬gCs5ë6Ô¢bÉÉŽÛûÆhH$'+Õ[ÉÚ‚ZêÖ­£Ô«`ʘBî@­—iˆ&>Òˆ‚‡ªÊšƒeÑ×rG ½•寿ÇZ§Žt43�îý´�CÇEcñ¾ýì]ä78Hh�&>¼sµ�öööΩj$q‘ÀKUEu·uè'NO/~PªQÄEU•Õ=œCª«êÐP0EÅ À§ †¬ µÝOÏö­”xuÄ¢{>¾¾´¶¶ ZýöV��ƒV›­_?ÿ^–:<_ÂCá6%„bˆ0ùX0( 77Ñ´_oG£aMÛqOZ÷’¿Þ±ÿ Ú6¶¢¡2bÔÈn öLMÈejœݽ™µyë(ØîE �DîÈý¤fdO PõP´a-«×oÁ­H�šCä@ÝA•&LLÄ€FåÊwû{@£¾pkwØ÷tBûZîH w°ù½‡yè‹j4Ň ^ıC7¼Ö½q?w?ñ"sŸýˆMXÉO·mbÃ/(fââw.e¬†2~|4ªóòؾßê¥èµk9ñäS8ñ¶…4LœC g¸ØÝu–vw’¸6±² ]1‘1>³W×Ù Q£HMöCÅKɆ�4ï·¯ò¿YB•äßB !¡á´Úš­þÖ�AƒV¿ÍÖD``ð�7ìB?L¿<$À!„b7S|"qÐl«ùn]Û^I?=U‹yò�_Ð ‡¶#©è6¾�ÿ.…{­9ªÓ´ô]>ÝîA1&rü±‰½»¡F2-'UkeÍûŸQàPðŸ˜ÍènF_ZÆe3Á ë?åý‚vtCÓrcðª’ôû™dû*xK0÷�-û-¯ê,ý”Gk.º†g \ý,7Œy씯]Äów^ÉÕÏ­¤Q7sÒ?¸ï¼XºTÁ/*…ô´$"|z�½¢ewñå¨óÏb¤ÜÅïpÇ}o²²¦ûÏÃY½‚y¼À»ŽvgN Ø92Å@êôÓkUðnÿˆRF×8‰§j1ÿYX†3c§espŒ ¤�:ƒ±VOñǼðeå>ÏÛœl]ðÖh¨S8ëĨ!òÃÑÂÄcr TuœyïñÚšÖ.ßUj~z޹ßÚñÝ?éˆBþ�Á¨ª�V[Ó€×ÝÒÜ„ÑdÆl±xÝ­­6EÁl=pýš¦ápì|(¥ï½jJo84­oQjÉÁ!„b75éwü>ým¶þRÍ'÷ÿ�¦ßËèp5…ü¸8ËY—òû¯^â“}°ŸŽê�ù>Ô„c9Áð×_µ™Ó§ç�ªÒ¼m)Ÿ-\Mµn$öÔË9¿‘b"sêdB|Få¦Í øplÎønŸN+~ÈM7ñãšMj|S“6Ѥ}7_¿’kç,eÍË碼™ž›L˜ÑI]q>ß~—Oy‡‰„åâqæ~—úÜä=wç¼Ú¥ƒêuÑj³Ñîê\VN1…“3ë&îþË¢Øë62öâ'xõâ¾´¥?e÷°dü™‡ÿg7Íý�Ëæq㪷‰•Iƈ(}T¼6jË·°asv/¨Aã¸ìÞ¿rL—‘)jÂYÜ|ù ®>ŸO_Ç%K�çèÌp M[ùù»å·BФ¿ð·Ó>¡&œÉ­—/ã¯Ï¯aÉœë¹2ï4Nƒ¿§‘myß²pyí†(N¼ñZ¦‡�€�ßQrùÄåÌÍ/áÝÛ.£`êTÆG±çñÓÚ²þv1©/=Ï×Cb9c!„€àÐ0jª« Ðzk«+‰Š‰Ð:»ª®('2:ö ¶u¹\TTTvþ�îÝ x@w¢p‚æž{Lyùâ±DPe_àB±‡:‚YwÝFí£ÏòцíüðÁv~@Aõ‰aêìG¸g¶•·~P:W1è)óçq»Üh:¨AcøËƒ yî?ùÏ«ÏÒ¦u¾¯bgҮ厫§u.£ÙK–1SÈñ_È¢ Å”F†ªadMN°¦*9SIð»§‘„÷2/ümž�÷!?æΫy;_RT|"Æ0ó²Ë¹öÜ ìÝÇìk¹¡NÇa«¥Ú¶ç/ŠjÄìBBJ*ã³�fúŒ“ȉífÙá!ËLâé÷ðŸÌãy÷­�ùrÙ/”®¢¢°Ë&ŠŠoDÇŸp:šuÂö=ÑÌŒºàA^�§_ùœ•«òÆJÕ'šÉç]Êÿ\~2#{Ë2“rÁC¼¸³Î‹ß¢ð›]í1–q —^y%³³{ZFö01Œà¼ç`ý¿—˜ÿõ:6ýø9›T ¡£¦0ûÁ«¸(§„G_êÜT>'‰â‰­±�Æú:BÃ#¤ÎƺZP‚z7}ä`Õ×UcPTübú‹®ë¸Ünjkk1 ´·þB@ðÉ` CÅŽ™$0µ¢Zí­-˜�mX]\®Ü.'³‡¶–*Tƒ�ÚÚZ¢¢"±X,(½üWÂ/{\Gé|UöôÕ¿ºqaA>YS�íÕ!ÄoMþòŸÈŸu¸›ÑOmuå”Õ´â6—OØXsÑÕRIiy#F¢GŒ Òçð·iàit4VP^e£C7G|t@�Kåö¿œ8,t7öº*ª[iwj(B"cˆ µ`ºÍ.Z«wPÑІÇBüˆ‚ûýa{°W—S^gÇ¥Z �M .Ä:´Ýѽ8ÚÚñ˜üð·ìlmû×ÜrÖ£üäMæò—_âÊ”^ÞW!ú ½ÍÎŽÒbRÒ2±Xû—ÕÈéè ¸¨�‘i£±ôa¤Ã�Ø[[(ß¾�¤Qé˜r‡ÃAEE%Ë¿þ_*Š>DUŒ�Qæ�Ã~w=Ów¯°¢ïù—è: ™³˜|­½Á1â†çØÓ�B!º¡â‘HæÀ<`0æÀXF�9¸a’׊Ohi¡ ‡¨œ8,þ‘#Ù× ŒD'‘=��2â�Læ€Ö98tGe¥eTØ|�3Š`ÿ€½^wmb‹k<‰QÜB ¾~þ„GF±}k#G¥÷9o†Ëé`ûÖ"bâG Jp£µÕÆŽ’mÄ'¥tpÀl6Ë鳿âp<ŒÛÕ»ü_&³«ÕÌæ¾M­•‡B!„V¼ÛßçÖëÞ¢LIàÜÿ÷47çtY&¸cï¾ú5µšŠö±äøΖ !ÄÞBãØVTHâÈQ½^~µ½­�Òâ"¢c ðöÕ×VSWSE|b >¾½ûUU«ÕŠÅb‚»ŒÔ88»¦£ôvZJWàB!„Ê1ã<®›þw.*gÁ�W°éècÈN Æ`¯¤`éò+(Á9\{õï‘iZBˆ!&4< £ÑDé¶-…„‡Áøë]s¯ÇCMe6[#q‰É½^¶õ@Z[lÔTî@UT’RÒ1õq L ¢¯$À!„B!†%„ãny’%¾ÌË,á—ï?æ@A1‡�vüù\vÕlŽ�—ŸºBˆ¡)08”€À`ª+w°yã:ü‚  ÁbõÁ¸sZˆÇíÂÑÑŽ­¹{«�à�0Ò2Ç0r ^¯�Û…Ëí¢ÍÖ‚ÍÖ„¢(DFÇTBÑ¡L¾õ…B!Äðc'wöäÎöÐV_Km«Lþ„G† Ùu…À¢ªÄÄ� ÒGS}-Õ;p»\t.ˆ®ïÉʹSC] u5ý~_U5`2›1Møúû“�8ó äò8$À!„B!†1#~á±$üTt!„8$ áQ1„GÅî¦ {C~å/!„B!„Bˆ‘‡B!„B!†= p!„B!„bØ“‡B!„B!†= p!„B!„bØ“‡B!„B!†= p!„B!„bØ3î!„B!„¿U^¯—ÆúZZ››p¹] ièƒø~ªjÀd6c4ñóÀ?0‹ÕgßñБ‡B!„BqˆéšFUE9öþAADÇÅc±ú`4™ð¸]8475ao±JTL<cÿºñšæÅíráv»±·ØØQº€¨˜8üƒú½_‡“8„B!„BˆC¨¥¹‘šÊ ‚CBI3¾Û …ÁàƒÅêC`p(^�‡šª ¶l\Olb2�AÁ}~oU5`±vÖíHt\öÖª+Êi¨«!6!“ÙÒŸÝ;l$‡B!„Bqˆ4ÖÕRSUARÊ(bjD†Áh$6!‘)£¨(ÛNSCý€¶É? �ÔŒ1‡†Q²µˆŽvû€Ö¨È!„8¹ì4´t )>…ùc>Üíé W+õ-tƒ/!!~Ãã†5\Žûá<¶Ãñsíj¸·_!ÄaÕT_KcC)i™˜-Ö^—÷õó'%-“â-›Q…àаm_XD«å%[‰O‰�¯¿ëÔ4�uë×QZZB³­¯ÇKHX(±Ñ±dMÌÆl6 @Ë;É}Y!† wS9ŵíh½,§úÅ2*>oÁK\|Ëg4Ídî{ÿ`ÊÀÝ7׊§™uÏb:âfñÒkW3¶_w,u%eÔ;Á2‚‘‘V”¶Ôí•l©hE3‘��_�¶SU¼ƒfX#’H5ã&ǽOÇv÷þî�öLAÅ`¶ADˆÃ�Þ{Ù\þpß÷¸äs=ô†{û…B>mmvêj«ûÜØÅl±’œšFqQ!>¾~X¬}¯«;þ�$$§R^¼�¤ÔtLæ¾?²ih¨gá¢Ï±úø—ËÈÔ$TU¥Õn§ºªŠùo¾ÎiÓO#66v@Ú.·e!„r4êÏáŠgÖãîeIËQ·óù£Óž³&‘î!ÿÿþÁý?v`κ‘÷ÿy&ÝNÒÔ(þà~.{e+c&×ýç.Jè~6§Vù÷]ýÞ@N}ðmî?fP÷àðó¬ç•¿ßŧ-=„Ýs@ YÓ8åô³˜‘‡owÁ!EŨªhªŠÒSðhÐÚëØÑ E@×_KäýB!†žÚŠrbbdŋՇ¨ØÊK‹IM=­Û›¿ 1±T•—0"%­OuhšÆ_-">1�¨¨Hª**)+)Cój„G†“’:’ȨH.úœ‹ÿ|逌ä�‡B 9 Ö˜1L›æ‡g¯¿ë´•­£ Â�0‚‰ccÙ7^oʈ8àôß$Å�œ©c±ü´ç¦Uäµ�Á©ÝôNµV­.Å àÝÆŠ¼F.Lï&a•NÓš<6{@ñ™ÀÑ~K!%•°Œ©Œ�Ús¦y�m4Õ”S\VIÁ÷ïSðÃÇÌÏšÍ]w^Ä”ð½ÏHóqw³øÛ»u£{É˶·oçÒ7ý¸aþ“ü1fÏ0<Ú/„b¨i¬¯E5 �°:CÃ#:——µ52`õîEsC}ç*/}X]eý†õ˜M&âââX±l9á‘ädçb4™))ÙΪ•«8ê˜i„†‡²fm>Sr§ô»ÍàBˆ!G!äè«xüè}ÿî¥ð¥Ë¸â�r”„S¹ý‘?2¢‡TѽùqäSΞÂhÓ*òëY¾ÎÉ©Çì?œS·å³|³% ˆ€¶6®Zƒý¬SÜ/ÒΚÕqé –ñS™ìÿ[z”o$ãœÛyäTÿý¦ùxš·±äÓÿòâ?²=o>·ü½‘‡Ÿþ;dž³œæz ……hô퉕B±¯æÆbâ¼ÞÈèXjª*%ÀOUyYŸåeÄ%ÄR²½„ˆð(N�~êî×F`0¨lÙ²�¸¸Xª++¤½àBˆ#Ù®¨î zcù[k°kBâÒÉš˜JØ>S*µ–J¶Tµ¢[ÃIN Ûª‹ÖÊŽ­•´êV"’ ß¹�n¯¤¨¢|£IMÂàj¤(?��;Zñø†3r|6ãýv�„pÖobU^•vð‹IVöbº�ÏÐ…ÇÆö‚5l(mÄað'2y,“ÇÄâw�}g52‡©)ò íä¯Úˆë˜¬ý’€¶¯]Íz—BøÉ3È]ö6 V³¶ãŽóÝgCçV¬í@WLŒ™šMоMïåqïJë¨asÁF¶V7Ó¡™ Žɸ‰éÄøüúŽöµÜ@2§ð»‹î%'÷]n¿åeV•/äá¹ãøï§¾³»ÎÝJbR>;�•ÞZIQåžsÈS½�%«·bóIç„3 érŒûº¯îæR Öm¢¼¡�%˜„Œ LJ írè´Uo£¼á–mö ëjŠ7SØbÀš@r„ôÐþ®<¶2 6SVÛ‚C±9‚Ìq™$í?ôv¿kGwP½1Ÿü­ÕØ5 Á±idMEø�ÍX+„â@ì-Íhš—€~,íÚ“Àà*w”ât8<@@@•ºŽÓÑÑë©5 ��$$%P]UŤñÙû½>29•ï~\Lrb"ͶÖi¯8„âHf4b°­eÞÃñŸ5�ìÉ©`‰9†¹“sGî cè´-ý7W>º -õR^{ùbRöí/v,ç©ëå'o2—¿üW¦tN?p¼Îõw~…cüu¼y[ÿ½ë1>ÙÞÁ®·S ¡ä\ý�]�@Ù‚G¹ý…Ÿ©rí~SÄn|ü~ι/NQ\¥Ÿsï}Ïñuùž:QTÓÎàŽÿ½ž¢bbŽôÜ^,ÜNCÞj¶x³³W1'+ èÀÌäI§3±iŸ/_ËòM.ŽËÚ»]žÍ«YmÓÀ�Ê´œn¦°ôê¸ï¤5³æ�¹<þúÏ”´k{öÕ7�.½™[/»0¥¯å�‚_úùÜwý/\øèš~“÷·œÀ5é�?9Üy󸪛$�pí=ßâžpó¯jåÁ›_ã—v5ê’ŽÏ$ÄØ�}õÔðÓ¼ÇxâƒuÔºº$IUL„�?‡["ã£�€›u¯ÞÄM‹ZwÖ½•·î¼Ž·PI˜õoýu ZíÀUÉ·óžàÉ ö~@1‡3éìë¹ãÊãHèr:u½vÞºo$_<ø0¯­Ýûœ1GOã†Gîáü”ßÒT(!„8r45ÔJpc—€À Z[mƒà ¡µÅÖëGG{V‹™–Ö6BÃÂ÷{=$8{kf«…GÛ€´UBqSL |ñÐ,sÍU·O#=ÂD{Å>š¿€•UKxjÎGd=;‹¤~>äWŒ&Œ èö"æ?ú6ë“.àÎ+FIëý—ùK*YõÏ2ßÏ¢×kȺôvNH Æ[[Àǯ¿Ë²ê<÷ÜW÷øL"÷m‹w3¯Ý÷[‚NâÚ?ç’jÂV²œo~NÁæOxàþF<û'RxG3�<%‡ØùÛ)¯ÊcE¹Æ˜®;îÙŠ|šq4“ÆF2¾>ÃÒ"òVmÛ•Ù%·‰—í«ó©ÕÀ˜œË´Øý^¯�»ÞFþ‹·ð�w¶áòÉô+gsú¤éM¯^Èüw~bñó·Sçy’g.LÝ3²¦¯å�JøïÎã÷¯,åݪüðc1W¦§ýj~ÅlƤ€«£”/}Eqà8N>)™ ß BTúqŒšùyîMÜùyZÈξàt¦%‡@ó6~Zð Þãî›�ÌyþoL 0’rúõÜ‘¼’7^ZL)qœ|ù,rƒ ø¥Ä¡BÏ+é�|?ç&îùªÝg\6‹“ÇÇL+e‹ùï_‘ÿÞCÜh¿ŸWn=Šà�A˜=×Î6Þyè ¾uÍU·O%=ÂLGÕ:>~ý=–W/ãÙ9’óï?öûZBqèut´9hõûÑÔØ@xDÔ ÔïH]uÕAo¿ôˇXþíS˜ïm¼ü`&š·cw‚n]ÓÑuðM{Móò¯Û"˜vÒÿ0mú�}n«8„â¦UþÌOÑåÅ'Ï%y×Sãì\¦Æ;¸ð¦�©,ú™e5ç“ÓÏ^“ª ÞâŬ8ù>^½ëXBwÞÀ¦Lޤé’[ù æ^}®‰?Ìyž›²våoÈarH=Üõ%�V±Ö1“éûLñV®eÃÄk˜÷Äù{ö!w*Ç�ñ㊿½Í¶Íðöês¸kê�Ÿ*GMeJøû”ו²ju—&Eí}á-YÍÊ: CbÙ‘Fâ&M"ÎPHE^>eZ&É»6ÔjXµz^ ŒÈÍé¶ÃÙÛãî)z—¾_ŒÓ˜È¬‡ŸäÆI{ò[dŒÍá¨QOpéÝ‹X?_N„3#úWî�0§1y¬/ïUµQQ´…=m¯i&ûQ�mÇw|wO½r㻬ÑëÙÜ·}um|‡§¿¨ÂcÉäê9s¸4e×2…ãŽÍÀzÕ­¼¿ã ^úì\rf'5áfÆ´±hÞbJ a쉧sæA\ÎuoòÌ×5h†$f?ü/n˜à»»}éc²˜:ÊÌe·|ÂŽ/_â­³s¹v爖=×ÎW,Êú+/u=gÈaJŒ�Ù7Bõ–¥,«¹ ÿתBˆCNózûµ,ì�X,VÜnç Õo6Yp»\½ýÒ¯þÉí�½Ì3¯ÔàÕuTÅÀ×ÌÁ×ÇŒŸŸÕ` ½ÝI{»ƒ kA×1(n¼÷QæÞ{K¿r—Bˆ#˜®D3ã/gté0uò=‰L«Þ:*kz|&Ýû÷S™1ë¨ÝÁ ¬ŒK5¢è:†Œ™Ìš¸wrJßÌ1¤Aw×SÝÐM[ÔNüS7û�9“™™FÐl¬\Q´ÏŠ3=0gpTV ªî¦pÕl»§hTæåQîU‰ÈÊ"Ɇ‘“È Qñn_Íêº=íÒ›óY±Õj8S¦¦v;*¡wÇÝ͆¯¾f»|rfqÉÄ}“w*O›ÅÙ£Œè޵|¹¤~ç(‚¾–;TLDE‡£¢£56Ш`s¥3u‰ÖÙÎfœ_×½éÇ1úæ{ʽà›sçî3Jñ›Èù—žÇÙg�É”pW?’óºX»øª4ó„³™=Îw¿öd�ËÌQFtoßÿ°µs¥ž.t%š—Ììæœ™ÈËÀ_«B!!]Ç`êÿ¨=1˜Mx{€è-£É„×sðwI·Ç�É'ƒ¸_¾_¼˜  #ÑÑ1„GDŽ¿(¡¡‘ÄÄ$îÇ7_/&"Ì¿ £q÷â}ºmk¿J !„Òk:ÿŸ½ûŽ�ªJ8þ»wJfÒ{%„N¨�„*"Ò°­®¬koXVWw-k]v×ö®«k×UY]Á^Qé U:H ”�^H›dê½ï¡†„d҃ϗ�ufιgn.9÷<÷œç ìYK‡jð#À¢€ÝŽÃYßÈÓ‹ãùt£wBÍ!¿‘?3à&°kw¢k„Ö_ütÎZÚ¢{3¸o-‹+Ôz÷ AÝ™ÏÑC‡(Õ“«7Ï„…¤ƒñ]´Û®�l©šÂx_@/a˦}¸ÕRRza0÷eø _æ-McýÖ2®œŒTnßÌ.§Ž’¨>µß¬xuÞµ|v¥¢a ËÀ:re¨q 슺·€½»÷áº<ŸÆ–«ï5ƒ±úZÐ5 ­¡—™±)ýN4áý²· ñ½{qæf7* ïàá‰^¹Ói¹¤î-EC¥Sÿ¾ÔºiŒCß>A¨{‹ÈIßO™žxÚŒŧ'zÕ’IÔ@€UGóþ]BÑztÀhh¹¡·Ñ`Äí©:o>ƒ�—õë2ãÊ+±;4,#šæ†S²g©¦ê\Z×_Û— ›? NÇÁ&·UBqS|üð­5ñ�Šz|W‹æ<ž¯µm†¢[péëg=ckQõØkz­mQ#‰´Ô:¢%$$•|´òRÊtàßäá ¶®`uåv6ìr0~˜TngÃn'X†2tÀñ€…¤!ýðYº‘wR9e4~8رiUºŠòpÔ-ðê¼kEäV?™?øÅã\³°öÉ•îÒtt…”iÑØr­6wS£¬´:Y§Á¯öë¢6ŠO5#M9GE`$84èÌk¯¹xŠ(8vœðÈZ’Î` <,•"´â"Žêœà°øã_ë]YËü]BÑzÀíqc2¶Ì,·Ç�ÑЀ„ë�äñx0xY¿«jºc)>¾ýp–•RU‘�£ª»½»Ý†ÝnÃQeÃî¨À^U‰¯ÅEB· Mn«8„B4«³ "5ÀôñÁ\GA£¹ºÓ]\ ý)Éœ×ÇĚͥü¼1÷°þxvof›̃†�rbi„BРz7°kÛÏìrŽf¸šÎÆ­¥hŠƒG¢æî±�¢»pºtt� —«Ž/ëNœ/ƒŒÕË[®µhEìÏ8ІŠ\§ÛÄÖG1š1Ö¿¬÷ IDATü*M9GÇfì�Æ– pàÂul�”ÉT÷q ¦c׫Û]ËõÚjÛÜ!„hmŠ‚Çåj±‡ÇéÂ`n¹ýÄÝ.F¯—Ø( k {@×Pt7ºî¬þGs¢k4Í�æq yìhž¦-M9NB!NÓZ9�àpP×Ì|§£º3T,>ø4t|¨†2lx/Œ[v‘¿c™Z"¶Ÿ·Q¢è=da§ ÄÕÈÁ �7°ãжô0Ô´…Ÿó5sF%×ÌÑHŠ?_ ØÄ€›^áåKÃV¯ÖÈr­DË_ËòT7(> ܇&Ýv5áY-:ö*;þ-“|L±p|g>G•�Ú® G•P,–†_¯B!:<Õ`Àé°c±6Ë£‘38vL¦–[„êt90š¼ìÉõ¶™w(IF…B£ (  {7¹9h(˜¢bZq©�Bˆ¶fõõ¥¼¼¬Åê¯(/% 0°Åê·•–áëçïe©¥ovÒ½ !„8ÁdõÁ €^r”£gŒÒ4жnf+�¤uw*[vÚÏ|C;®Ôr4T:÷ìFý›Äž¤ÆcDœݵ—m›·³ã€5t0ú�™ 51%‰@ÕMÚ®mü¼3—n Çˆ¡D6Wª„�4(Ù7�Qëý€Faê¶©89xnl¹–¦W±÷ó§yê‡\4ÅJÒ5×1: ‰Á Æ~W5”�ã0 ‘»y3Î8 ÒÞ¿“q&2î/ jÝé¥A¡5œ¤±'Žs¨¶“íÜÃÆ•芉Ä�}¼º^…Btl!¡á”—–´Xýåe¥µXý¥¥G öªŒÞF�^$À!„âS§â  •þÌòí¶Ów¼ôán4CëέWôR–ÍýŒÔÊS_Õ9ºö3¾;àF1&0ft‚wš¡#‡F jålýb>;ì þƒRè[ËìKŸ)$Y jçw|±£ÝÏÈa±ÍØ�ªt™<�_ÏÁ¯xñÓt*k|Âqè;žyä1î¸î^Ýálb¹â® sÛBÞ|ô6nc#ź‰˜ñfÖ•�kÝJ×;�ý®zLºˆþÏ�y¼þía§69g)ÿ[pfú�Láø¤Å`¨Îâ)¦°¸!S– ôš2�þwÆ7ügQv�çVö}õ?äi¨ùt\”Ü€ !įˆ`0ªj ¼ôh³×]Vr£ÉŒÙÇÒìu”——¢( fKýõkš†Ý~ì¡”~ú®)Þ°ÛíhZ㦠K!„'¨].drïOØ·;—oÿöGŽNMßpUy©¬ZºŸKodòâ·ù¶HGoé¥*zu¾5~4c _r÷̽L�4”î¡*%û×2ÁÏäêFb§ÜÂoϘyQ}F !ä«ùdïÙ Š•ÑCÖúT]ñKbXo«¶î!P; eD—æÍT®F_ÄwoäÎçײõ�û¸nó8& ëJ˜ÑAAÆ–-ßBf•‰øiwqýs“Ë5�‹ÍoÜÊåï�èò8)/-¥ÒY½å›b gèŒûyü¦áD5ÓH¾Ñç(þR¸ew¿¹… ¯ü�ÖŽaTŸp G÷ñÓòõd”CÐà›øãÔ“A%°3 !*ór™÷Üß° ‰‚ aÜqÝð:˪ñ—ðÐ-ë¸ëÍ­¬yþnnÛ|ãÄàï.fÿæe,X˜JCãI¡’€C!~m‚CÃÈËÍ! (¤YëÍÏÍ&*&®Yëý†3Ô Ë4S/† ®#i¨Fò�.¶¦áF%bèz7{ïi$~Ú_™þ ¯ÍþšU[¾ç½ÍÇÞRT¬ý˜~ó-Üù›$N7¶\SèØKóÉ-=ùŠ¢1[CˆïÞƒ�)£˜4m‡WÞýž�›ðáFÕÍ�+oäO·L Û©ñÓ®ž9ž ÿZÂáƒk™wPÁ'9�›¯å,;ç˜é~ÕS¼uì8–~Lê’ãí3–8‘o»�«SêÚFV!Ĺ,4<’Òâ"Š  �h–:‹ òAQònùHCäbPTü°üE×uœ.ùùù *Ëw<Œa¨T`¦ ˜ÊQ--e˜6,N;Ng.§³ªÁ@~~>QQ‘øøø (ÞÝM(á7?§£T?‰:üÊígýpêŽ-$�íÕ„â×fËúÕô˜ÜÖÍh" [A&‡óÊq™‰KèD˜¥í‡eβleSeô'ºsg"­mߦæ§QUœEfN)Uº‘€°8:EÔ¹UnÓËuD�ý®nÊs��UdÃíB§Î1Ÿ¥�Ç–Ïá\ø†LÃÿ ¸©ÈÍ$³ §j!46ž¸‹6„âW®ÒVÁ‘CtïÕKÓ²19ìUd¤¥Ò­W_|1Ó¡>åedØO—ž½15p»ÝNVV6ëüYi_£*FPŽmËÉ+ú‰Vô“ÿR]'¾Ï †Œ}È«�ïyƒã1 p!D3;7B!„¢¹æQ\XH·ž½�7Ãé°“‘¾—èØ8‚CÛ¹…Õy7ŽÜO§„îX}ý\NÓ4œN'UUUØí•¸œÞåÿ2™ÍX,¾X­VÌf3ªÚ°G§8d‰ŠB!„BÑ Bã؟–JB·ž^o¿Zi³q(#�èØø næçR�—ãup@UU, >>>@ð)35æøro—¥œJB!„B!D+ �Âh4qh:A!¡DÅÄa0ž}hîq»ÉË΢´´˜¸„®^oÛZŸò²Rò²� **]º÷Ædn|ròæT4–8„B!„BˆVJ@`0¹ÙGØûËvü‚  ÁÇbÅx,ç…ÛåÄ^UIiI 奇„ѫπzƒ!õñx<¸]Nœ.'¶Ò2JK�¢( ‘ѱ J(ÚžI€C!„B!„heŠªÓ©3‘ž8Žæ“›u—ÓIõ¦ëúɬœÇäQT�×ä㪪“ÙŒÑhÂ×ߟø„n˜[ Qi[�‡B!„BÑF áQ1„GÅ´uS:<Ù±L!„B!„ž8„B!„BÑáI€C!„B!„ž8„B!„BÑáI€C!„B!„ž8„B!„BÑáI€C!„B!„ž±­ „B!„B4TEY ÅùTUU¡iž¶nÎ9IU X­¾„FDâÔÖÍi0 p!„B!„è ór()."6¾3~A †¶nÒ9Éãñ`+/%'ëöª*£¢ÛºI "!„B!„í^EY)G‹‹èÙ§?F£ e[’Á` 08_ÿ@ÒSwa±Z;ÄLÉÁ!„B!„¢Ý+.È#.¾³7Z‘Ñh$¶SgŠ òÛº) "!„B!„í^UUþíÁ¹Æ?0{•­­›Ñ àB!„BÑîišUrn´:ƒÁ€GÓÚº "!„B!„BtxàB!„B!D‡'!„B!„BtxàB!„B!D‡'!„B!„Btx²�°Bˆ¶å,§°ÌŽnð%$įaScÊ´F]ÍÆIYavŒø‡ãÛîGx°=ŠÍ£` #ÀÜÖíB!D{¡iÛwnçСƒ””–àq{ %6:–äA)˜Í¦f;Vû¸�BQGñA~Ùs�#ù%Øœ³/�á1tí•H�HK‡�’ç\÷"WÌZ�+no¿;ýÐ35¦LkÔÕ<¤ò0w½µß±�ñöãcñÕ+ÉÉ8B‰[?í“ *³…€à"B,Ô»q^õœ¨Íèƒo@(‘ø(uU¢Q–µŸ¬ c`=büPP(Ûô*·=ûΤ™¼ñÏ«èáãý7B!ZžŽ£¼˜2»ŽÑ/˜ßtü.y¹–Ùq+&|ȉ÷¾Ž·µËµCEE…,Xø=«•¸øXºõ肪ª”WT�›“ÃÜ�æpѤ‹ˆ��m–ãµùmœBˆ³Ñ±e,aöïóíælÚ™SEµ9`2·Ý;“iÝ­Ô9.m¯£ª¢©*J�Æk•)Ò‰‰"Àذ2­rü£S¾éM}göø+yîÁ±D©€k'ïÞ÷ߕձ½¢bˆ!1y$§^Ê´aqøÖv^ÜõÔ (˜üãI{ ×ßp )á5¿¸“uoÞìÕ.ü&>É�Ÿ‡•˜‰2+õúz6�¾Ñ�ÿÞ7„€w1 !„8§yÊ9¸y5«wå`ÓTÂ’/åŠäг<$rQœ¶žå÷Q`?½ï4X£éþ†'ø×R¾µËµOš¦ñÃâ…tJˆ'**’œ¬l<ŒæÑ� §{�nDFE²`á÷\í�Í2“CBÑŽU¥Îå¾ûç°Ó¦c�ÄÅãG0 K4ApÛŠ9œ¶™e‹×±oû7GèÌ1ÁÖšŸP KÁÀ¨“�p<Gó2É8œÍŽ_°cå7ÌM¾šÇ½Žááu=ê9³ÍUIqÖ~Òf÷¯³iõzî}áIftoÀt ÅŸ¡3ïç7›àóo_àÕoóÈÈ€ŽpBqNr¥±vÕö¹hXç¤S‘¾ŠïWĆaÝzÓ+._*)<œFêá\¶/]ˆgòÅœçÓ†åÚ¯�»vb6™ˆ‹‹cúõD„G24eF“™ƒ°iã&Î;$¡á¡lݶ…áÆ7ù˜àBˆöJËeþ[Ÿ°Ë�)wòæ3WÒÝRã3“/åú«×ò¯ûþÎ7™Û™ýÆ"ÆýszõSÿŽN/#55 �^¿’ã;ØùÁ[ü�¡næúþgD7#‰—?Ì3Süϸ7s—ìgÍwðÖ‡«8°y.ÞWÌÓ¯ÜÇèÐÚ.†ºë¥{æóÜßß`YöfÞxîK†½ñ{º6dZ¬u 7ÝrKþ±‚o~Ì%É3éß1îÁ„Bœ³tÊÒW0ÿ§ Êô†Ž&*{³j[®y G&7†qçqQÿ�ƒçž½{ÓuÓæo/â—õ»èuy ‘j•kÇ2³ËÁ‰�bʤ)'ÞKˆïŒÁ ’ž¾Ÿ¸¸Xr³³šå˜à´!į”=•-{èjüöâ3ƒÇÂGr÷SéÓ'™á1:G]µN«Ê#uÃr¾ûæk>ûú{¯K%§ªö¥ zE6{÷îeof)ÝNîîµ,øæ«ê²Ò)tÖÝtÝYÌþmkY¼p>ó¾]À+6²;«¢º®:޵ç@U:€Ž-w{~Yź½ntÝN^Æ^R÷¦‘QP…^[½Šüi¤îMçàѳ5ÌFξêÏe[¦áÕñó�’›Q]þP]'úØùÊ;ö¹Ã%îº?wj‘âÌ™Ÿ‰ÇЕ˯>� /§>ƒ»sáueöË3¤àÌ\ÀÓ/.¥ð,«Qjg (ñRýãÂUGúR~̨í'W…�Ñ3¸´³Šûð|欞Õ�ž|š÷·s27¥‚9z$÷<ó¿=uù‚n#uÞË<óßåì+÷œ>¸U|ˆ|9÷ÿåfFGŸì~\›g3ó´$Ÿ.¶¿w?÷/,?V~?ú>F%~ÆË||W?´še v¾ÿ O,·á?~_ÿu4~µ�ŠŒ/xhæû¤+=˜9û?Üèåñ¯ú?f=ͬ¥åø�}Œ/g�%°–�–ýOÌü;´nþÏ;Ì ®ëgw¢G~œÏ˜“¦2½AÓ%j£à×û·Ìº{7×<»†’Ÿ>â‹ô±ÜÑÛûîÞ/i}Œ )påp(Ë =Ø&c¦OëÇoìfý·KÉžp%qò8E!D›Qè:ŠË‡u&Äàh@7yYy8QðïODmý˜9†„h#éìd)F‹�@mõrí[Ue3eå6BÃÂÏx?$8ˆŠrf‹Uv[³SBÑ^ùt¥W'«3ÊXñÑg\Öïúù{ùX_·±å­ùó§ûqúvcÒmW3upg‚ô£dü¼€¹Ÿ®fé›Sà~‰W¯éÁñP…b4aT@¯ØÏ§O}È2ç(f><‚Þfªr¶óÍœÏYŸ»Ž×žÿš¡¯ÿŽ.*€NÉÊyà•e[:sÁ5—3¡'‚}ÜTäìeÍwóøaë§<þ¸o½y‰u¦ 1Ò}êÝ<Òu#¾½”CÄ1á– 2à×=8cR‚âψ‰# Z¹˜Ò�+X_1šñþ5?äaߊUdxÌý'01¡®Û‚³¿#+DZü[ò7,fEñ…\Vóg¢‘µz%©n0õ™Ää  h¹¬Y�†#G�hâ´S•ð ¯dò»kù,ç+Wep[ï^õï°RÓ‰Œ«Š—‰\UbÎ;ŸÞoïb×ÞÕ¬ÎûM«ä/B!j§ÛÙ»"z9EG]€JhhH�¡¡�¨Ѝ(>Šƒ¬­]®Æ'²rrÈÉÎiÐWŒ��%6&ºAŸõÖÚEO±~Ù˘ìU6Þy²š§êÄ=…®éè:øöú;šæá߉`äø?1rÒ£�>¶8„¢½2tãòë.à›'WP¸í=î¸n-c&Žg̈d’û&f©ÐèNûŒ¾ÈÀaL`ÆÓ/qïà“9û弞ÿâÆÇ²sîlMz†KŽ?2PTÀ“±˜…ÉwñöK¿¡«ùx­CSÁÕ|KnúZÖå]E—°±aÉ:Š5#‰×þƒg¯é|J=œ±‡qç}|R°‘5û¯%1±î˜QI™ccáì¥"„þã¦rI=ƒd¿” Œ ]¼¢M,ÛTÁ¸±5òKxÒY²â0Ň”‰žeVA=Çw_Ä”øïyÿðV~XžËô+cN¿ѲX¾" 7> ™<ŽøŒíuÛn¶îs£«�HÙô'2æ^ éïËç96²ÒÒ)Ó{âelÌžº›4·j,]:y—¸V�@R”Êάt¶î®äw1gD›„BˆöK¯ÄV©ƒbÆ×¯®>PÁê[½{�^i£R+­\®–†ìÜ\²sÎ䈋‰i¶mYk³vñ <üÏwxõÝ<<ºŽª¸êŽçñµšñóóA5¨¬tPYiç«ù ë÷þõY^üëƒM pÈ#!„h·TÂÇ=ÀËM%1PÅ]¼‡%Ÿ¾Îº…éÓ/ãŠ;áÉ7?cѶLÊk]Šéb×â9àëÐÜ0¨fBI…à‘3¸¬§ݾ�Ek Ϙ¡+ÑL»aú)Á�jÖ¾ƒè磀§€ì¼c¥´JÊÊÝè(�µÄÏ}™9{+¾y�[ë n4�e “.ŒDÕmlX¹‰ŠÉÜ{V°üˆŚ̔1M˜ÖiìÉÔ‹zaÂÅÎEK9Tã¤i™«X–îߦ]ذãxí'ᣘ»Ò»ssœQÑá¨èhÅE{™Õ¿Ž×_[Dž¦à“8� ]½<[†.ôîfFÑ�d¤¦aYH„BˆvBwâpé€ÓY¦˜L¦cwàl‹r5ÄÅÄ�’<˜Ø˜˜:ëˆ�Ž&%9¹Åfo¸Ü.LÖDâb|Y±t)AAF¢£c�ˆ& 0ÿPBC#‰‰‰'2Ü�%?.%"ÌŠ_Ð(\î³ä8k™Á!„íš•îÝÏ»c~ÇÏË—°tÍF6nO#×VAVê²R7ðý'oá9�i×Ïäöi}:>ÕòÙ•Zˆ†�.ûמ´R�c`¿PÔ½ìݽ×呜ºé…âÓ“½Ìg–3`UÀaÇá<6zVCé×7ÃöLvÏ}Šç,·òûqIt89`WÕ–Œ«›8þB:}ý ™›V°¾âB&ÿÒ.v¯XC–¦8b£ƒ›²y©JüÄ‹H~ö/ᇴßqWâñîTãàŠ•ìs«��Üàã8ós(ÔA ‹&ª–Óí=ƒ±ú¼ëš†vF€ÃÃÁeïòjÆéÓ=vJ²ÓÙ²e/ùv%$™»¸üØ$o˜ˆŠ E!‡Â¼|\ô•!„‡®ë;U géU­^:«kÕ‰Z»\-âbb ØÂ39b££’’Ò¢Á�ãt™q啨‹MsÃ)ÙÙTSu^¸ë¯íK…ÍŽ¿Ÿ§ã`“�+÷BѨ¾q ›væݚ�¼ŒÝìܱ‹-[6²fÓòó·óÕ fë�'ùÏ=CªƒZùǶÐ8øÅã\³°öÓ]Z‚ŽŽ£°€2�Ó[)ükí)TŽÇ*NvUFú\û·üò³·ïaÞ¿à›Wü‰í=�”ä!Œy#ûFbiJl¡ÆÞã˜�ð9ïØÂÒ L˜P=kÅù KV墩Á\0iMlƒ6†KFÎfÓ²#,^´›[“ªCžƒ,[y·ÎØ‹†ÖšèôL:•e64Tÿ@ü›%¤QVZ�$ÕàçWK¶xYæñцÚK+¦`z޽Œ;ó¢½[žRM% ÐOy9•:X[ðç.„B4+åX Aóà9ˆ%šÇShP Õ¹®Z»\Ž9Ô­ G²³�Ö n¸ªv ;–âãÛgY)U8ªJ±Û+°ÛmØí6U6ìŽ ìU•øZ\$t›ÐäãJ€C!:ÕBT�¢z¤0á77pI*_½ø4¯¬Ìæà¼×ùxòlîèmÝ…Ó £{\¸\uŒ0}Éóc�±–m\½•*~ý¸ùßïrÞòù|½h%k¶ {÷Z²v¯åÛ^'¨Çxn»ÿn®èSs¹L31tcâøÌ™�Ʀ(?� »–³*_C�Í””:öÛõ†À¨©c_ñù+ñómIŒòOÆ*–ô`ˆÇô�>õ×€ŽÓéD³ -uVZû3Ž¢¡â׉ð3‚&Fú\õ·>õ\((Fÿ0â»t&·i‘³É\½NØíÂY½�BÑ1(,f\îcKGj£ãt8Ž}Ü‚�ÐÚåêƒA5 éÕõ iáe)gR@×@÷€®¡èntÝYý�æD×hšÍã@óØÑ ܇3¿²Jh÷¡œw^ š§Û…¨Ff n!„èH?°¹¨¨°£ãWK©SQnCŒþø)­]î좣"II ÐÊÁ @÷2X3‘$£BÑ.9)ÎØÊ²ùŸñÕ–¢:×Yž`‰¦S¸ èTVVV/1DÓ)Òˆ‚›œì¼Zfg´<Å'”C&òû»fñîœg¹2Áˆ^¾™¯—©ÿ;5’3†ÉýÍPµ™åËÑíÛY²ö(š!�I{5_dߨ›©SzbÒ+X¿|å®4–­<‚fêÃÔ‰ ^t° VTôŠrlM½ÐËY?çs¶9tÔ QLÔ“'4leh(¨þþ²bc^틹˜ý÷ÿ°¦BG »€KFžì,»LžNН‚çàW¼øi:•5ËúŽgyŒ;®»ƒWw4mq„V¼’çüO>ùo>ØSufPÀq€-»ŠÑ#ñ�cê퀃£xŠ),ö&¢zþ†úBå¶5|°lGu3I/$êÁ� IDAT΋^¯!ÇWÃ/äâþ(•›˜ýòR²ðgäE£ õò®ÃÐ¥]Í ºãé‡qCà® sÛBÞ|ô6nc#ź‰˜ñfÖ•�Ïš„¬Åx2IÏp¡+fºvo£6!„M`ŒîC¿pºý ëÖî§ìÔîÙYÀÖŸv�ïQ°&ô#ñ”]ÓZ»\{¢ivû±Ç\ú黦xÃn·£i�›ë+98„¢�òI¼–§ÿt„û_\É‘u³¹wÓ'ÄöìCbç(­*žªRò3ÓÙµ7‡ ¨A¸ù¯wqþ)OìÕè‹xàî�ÜùüZ¶¾s×mǤa] 3:(ÈØÂ²å[Ȭ2?í.®дçìjôdn½ì;þüùnþûÇ›Ù8zÃzÄhÒ¨,ÎdÇšå¬?ìÆ×Mˆ¨?ÀØ™„•�y¹Ì{îo؆DAÐ0î¸n8¾õ• Δ‘¬^ºŠ/–ºÑ-Ù|a¤WQý³ÿÄ}…Ȩ©c[9ŸÜ\;jØELîýSÅ¿/I] ü´'›í»ŠÐzÕÕV›ß¸•Ëß;å'奥T:«·[SLá �q?�ß4œ¨6zŒ¡îfGކbìÆà~µ­#B!ZIÕ>~ün3y'ÆË:{uô d÷">J;ÙY:�àÊóª—¨¡ •Læ?“³%_ì%>6‹n£ óù•Tÿîœ?¢Ûé÷%­]®q:�deUïÚR�\Ô¸Aw ×;w÷äÝBfæâã;a±xŸ^BÑn™I˜úÿë3†Ï>þ†Eëvs8uY©§|DQñ�èرSùýŒ‹H «ùkÝHü´¿2;ü^›ý5«¶|Ï{›O–µFôcúÍ·pço’¼župÅ�”;_àÅðwøÏ—+Ùµô+v,9ñ&ª5ŠAÓnâö[/#©!Ë&L¸zæx6ük ‡®eÞAŸän¾–tìþ ŸpÁËRìR 8"c¼}Úq–ãŸ:b·žÂ䏸 S'zìd†4æ®C�côèî¼½'�ÝkÖStÙ%§m×{’޽4ŸÜÒ“¯(ª³5„øî=˜2ŠIÓÆ34ÖÚ†A�Âu?±Û†ÄQœ+“E…B´]sRUQAE-ãk�£’ŠS–ƒªN_Ïk ÈEÓ¬l\·™=¹9ìß“Sý†êCh×$FŒH¢s-Ù>[»\{ ë:N—‹üü| •å» žÆ0T*0ÓL娖 Œ–2̧§³ —Ó��Ù�­,Õ` ??Ÿ¨¨H|||P/wô ¿ù9¥zòèáWn?ë‡Swl!yÄèÆ~g!„øUز~5}&7ź‹Š‚rŠË©th(>þ„DÆjià�ªâ,2sJ©Ò�„ÅÑ): …v¸pa+È!« ŒJ�Š50œNq‘ø5"¬î±ås8×¾!ÄDciåñr½Ç¯ü™ÿ»áaæ%pËÛos[�Æ-ÈÐò¿ãO7¼ÄFWoîüïk\ŸÐAÚ!þwÇLÞJ32ü�ÿñïéõÏÖB!"uÇ$k“c»«J))³ãVMøãïÓ°Þ­µËµ”�[6Ö{k·ÛÉÊÊfý�ÿ +íkTÅʱíb9¹`E?±ÃŠ~ò_  ëÄ÷™Á�±y5ƒ£ó=op<¦!38„¢£PLøGv¦gdc+P±†ÆÓ+4¾9[U~�éÑôš ~‘tíÞôzZæøY ?bq�ŽoÊ¥\Ü­ñÙ&ÔÈ \7ùS6}�ÆWŸm⊆7h ¸öE§býg|•îF��Îõã$¸!„âÜ`´n j÷åÚ’Ùl&..–©3^Än—Ó»ün&³‹Å«ÕŠÙܸ¥ÓàB!EÇ–úÿ˜½ƒ*5–×O$ºI£y+)7Üʸ•O±tñùð’ÁÌìÝÁöqìaîì%ÊÄ™×1¸½.B!D³SU‹Å‚��|ÊL�†9¾ÅÛe)§’‡Bá-ÏÛFNÞnÖ¬ÚM®ËL�«àÖ�Ö&×­„ŒáÏ^Ç®¿.áÃ}Èù¯ÝD_ïókµ‘*v¾ÿo>Éð5ù^þ4&X’‹ !„¿Bͨh,™9*„BxA?º‹ùŸ|ÊKv“oˆaÔ�OñÒíIø7K®zþ½üãÚÞö̬WÖRܸÖZ™FÑêWøÛ§0&^Ë“÷�"D¢B!„he2ƒC!„ð‚¡ç5¼6w"e3¡Q‘5wÒ/Å—�7ý‹�'`Ó}0zè½µc÷üë¿WãO¤U¢B!„h}íþ–I!„hWT aq� kÑcø•à×’Ghf&‚b»Ð±R¡ !„â\#KT„B!„BÑáI€C!„B!D»§ª<O[7ãWÇãñ`P;Fè c´R!„B!įšÕê‹­¼´­›ñ«c+/ÅbíKg%À!„B!„¢Ý �ˆ$'ë·»­›ò«áq»ÉÉ:Bhdd[7¥A$À!„B!„¢Ýó "(8”´Ô�”-–å*-ÈãqSVR̾½¿Š@ÇH%.»¨!„B!„裢±X­åç‘u(�¦µu“ÎIUÅâëGTl\‡ n€8„B!„Bt þ�AøvœA·h=²DE!„B!„ž8„B!„BÑáI€C!„B!„ž8„B!„BÑáI€C!„B!„žì¢"„B!D¡ëz[7Añ+¡(J[7ÁkàB!„¢;Ô85¸!�!DK9ØÐuýÄw”`‡8„B!„h§t]G×u*ÊK9ZX€½ª Mó´u³„ç8U5`±ú�@ Ð1‚àB!„¢:Ü(ÌÏ¡¢¬”˜N� Ã`”[x!DËò¸Ý”–‘�y{•�ðÈ ý9ä·£B!„í̉™e%T”•Ò«oº®ãt9Áéhëæ !ÎuŠ‚@0½û…�öË6,_üƒŽ½Õ~ƒàB!„¢Òu�£EEDÇ%àv»$õè:nMCQ¢ã(ÈÍÁ/ °]7@¶‰B!„¢ÝÑuMÓ°WUâëë+Á !D›Ðu«¯Ž*š¦µûßEàB!„¢9u×Mó ·ó'¦Bˆs›¢(xN n´ç ‡,QB!„¢=Óµ¶n�âW¬=4j’‡B!„íX[!D›’%*B!„B´3鉩â×£½ÿn’‡B!„B!:ø„€O�÷¥eYûɪÐ1ÆÑ#ÆïoauÅùeÏAŽä—`sj̾†ÇеW"="-µ®›tnx…O,¥*no¿;ý�õ\Îu/rŬ¸j¼^/çž¿îo,¶Çpõ«ÿãÞc]_[Ò+ÈÞ—M©¦£úFÑ=>¸iû¹tn„8‡4K|ÃY¡´4öÉçh¥ ŒV‚"béÞ«7]Ã|Îþ;Ýq€ï^zžw–§SìÔÁoÿ÷å_8_¯ãuss4Xq®Ú·Y9G¸øâËÐÑ+#‡�$))‰\̪ŸVrÁ¨1^×-·(BÑ^¹wòî}�ñ]YÛ**怓G2qê¥L‡omw¨õÕ (˜üãI{ ×ßp )á5»'ëÞ¼‡Y«]øM|’?�†ß¿êØ2–0û�÷ùvs6íÌ[uEµ9`2·Ý;“iÝ­ ž(*FUESU”æx`ØÜõµ箹ÜûÇÏÉÔ@ Ë“=Îø€h|;97ZeGŠ4Bb¢8ï`Îõï'š¢ñ!ÏÑ_˜ÿÁ>Z´�¬J팚ÕBÔ€±üöÚk¹"%Ó5høâ_¼°8·BÏóRèÔ›PÕÃ�Ok{½�L7B´[éûÓèÓ·/Š{ÓöðóÆŸ1 4˜Aƒ3aüæÌ�ð”aX,V¯ê–îS!Ú=•°Ä Œ:9WÃã°q4/“ŒÃÙìXñ;V~ÃÜä«yìÑë^לŽ3ëÐ\•gí'íða6|û:›V¯çÞždFwŸfi}Uê\î»;m:ÖØA\<~ºDd·­˜Ãi›Y¶xû¶Ã3÷¢üÕru×3o±k2_ð8K—=Þ,ml‰úZ^%ç/%K7áçg ²|=ß./dì%ÍžA¼}œû?y˜?òãž¹/ñ»˜s-Oú¹þýDëÓ)ÿåSþ:ë}6yÐ ‘½3|PObC¬¨ö2rìbãÏ»ÉÞþ¯í\Í’+æÿf#üÔËO/eçÎC¸t•Øßüƒ÷îK¬{p;ò™WÛëNg § !………ôí×—Òòöü²‡)“."0 €~ü«ÕJÒ€AtíÚ…={÷2(i�WuK€C!Ú=#‰—?Ì3SüϘÙà.ÙÏšï>à­Wq`ó\¼¯˜§_¹�Ñ¡µ Žê®<”î™ÏsƒeÙ›yã¹/öÆïéZïú—zh¹ÌëvÙ 0åNÞ|æJº[j|fò¥\õZþußßù&s;³ßXĸN'JÆwg¥¯fÞª£è–¡Ü|³…ÿ½¶š- ~äðôßÓå\8BtŒÎQDÕ3�D¯È&-«ÝJB—¬5£6Z™;·²ý`!•º•¨®2 ?/ë;þ:¾Ñôˆ ÛÉýe [öåR¡ùÛ‹äÁ= ¯kÍŽVE^úNv( B÷#ºWƒ»‡`ÆIÑ¡ƒäÛ Çw#¦ÖõEuÑ8òã÷lªß‘2eŠ?és×°0m ö\Å]}ëéÞ›éÜhe٤産[ÂéšÆ?2­œ#û²)×-DtI ¼Ætg1¿ìan1•NŸÀp:÷ìKbœÿ)¹etl¹ûÉ,Úͺ½ntÝN^Æ^RË ø„ÆÓ5 5FÎbÒ¶læ—#å¸}Ãé60…A�üNÌlqîaÓæ4²+À/²É)ýÎzþµª<öîø…}¹%Tif‚£»1`Pob¬gþ%óþz©ÿûu�S¢yßÐòùîõwÙXª£ÆLâÉ×aL� w•wÍÏšã™úÐËD[îá¾/°çÓ×ùô‚—¸¾«Š-7ƒ#%¹äWê€FeÞ~ö¤ùc/.Ar×x=E $®{4þrÑ !@Ó4< ƒ¡º×� � ªª�ǃÙd¦²ªÊë:%À!„ž‚_ïß2ëîÝ\óìJ~úˆ/ÒÇrGoïÅû% ¢�q!®e¹¡©ܸ=Õ� õlw¼ þçßË»ç7¼f׿Ù̬#ñ¥;k9ÏÏz‘o÷Up"凢Ðs:�þ5¥–ÑB]õ¹vÌáîGcø>žÕ�ž|š÷·s2g«‚9z$÷<ó¿­±¬Ç�½Š—þñ"_í)=¥>ÄŒ¸ž¿ÿ%‰Õ�ÝËܬ®xáCL®YÎÉŠ÷±`A*Å�ó'Ž"ÔßÈ”óCXxìŸ|{ êD½Š!”¡·?Ã?¯ŠçðWÏòð~"Çyâ]Lù÷¹¿qe·Q*­„­Ÿ¾Èss~âài¹ TßxÆÞø]ÕŸ S.mﯗú¿ŸÜ¬ oCžŒøb³ ] fÂ�w1:À�ÛSWÕÜN3ƒo½‡‹×<À—9éÌûf3îë϶÷îçá%•'޾ëÃG¸õCP Fð¸Ï|Ý:–g¾z˜Ñ’dTÑ º®ãñTÿ‚2›}p:]xúŒËú]C¿–~´çÜûOü“oö»°$\È 7^̰NVùi¬úòCžþ{q^4A1š0* WìçÓ§>d™s3Aï3U9ÛùfÎç¬Ï]ÇkÏÍÐ×wryˆ3•Ù�?×û]˜c†3ãÚi íd¡=3†¾60a6zwNìÛ°à°5ø|¦�@’'�%vÁd¯XÀO3‡0!°–:›ùÜ4ŽNÉÊyà•e[:sÁ5—3¡'‚}ÜTäìeÍwóøaë§<þ¸o½y‰&#ݧÞÍ#]7òáÛK9Dn™Á° ~ÝãPýÄÏ(�¹Ï~ÂÎ.Wñè­}‰¤ˆ� ?`îšl6ý÷5æ:±pNÉ7>ÌØ^ÁxòwðÍœÏX—»�7ÞXÌÏM'òøÏO·±å­ùó§ûqúvcÒmW3upg‚ô£dü¼€¹Ÿ®fé›Sà~‰W¯éqböŠ÷×KýßOïhÞ°‘L¨pÉ+š^_€DÇcêÇÅã™7ç…Öó‹k½.ý3O -`íœwX’¥Ðí¢;ùý ?*²rÐc­ìž{êëþ¨†het!D›Ù²};Û¶íhÐgJbpÒÀæ=þšÿ°jþ,\®³,XÓÁ·Çã'þÇå¬â•YýrÞo˜pù󨪊ËåÂ`0PYUéuäW�Bœ+̽Òß—Ïsld¥¥S¦÷"ÄËÁª=u7inÔXºtòbFA] ݸüº øæÉn{�;®[˘‰ã3"™ä¾ „Yš{ø¦S¶ú>Ëp‚o ÷üóq~sž‡f(CB ¹ê±EïÚÄ6ût&;Ÿî´Ïxá‹ Æf<ý÷>™»&±ÿPÎëù/n||!;çÎfѤg¸$âX{q½Ô÷ý„ðn‡ƒûŽàAÁÜ«?½½aåuè2 ?�ê!Ž=Àþ"Hî?Ž©ý�pôÛÿ²$K%¢ßX¦M AUTðæƒïN]Ñ5î^~h*‰�*îâ=,ùôužøÓ-LŸ~WÜñO¾ù‹¶eR^×ôi¯8غv 6]ÁwØT&×$š»pùo†ã׈Y ºÍ´¦Ÿ2X­fí;ˆ~> x ÈÎ;¾w€�­ë¶R©+ø�¼Œi�NŸKcˆžÀ�WöÆØˆ; -9óÖU :3er¿“y/ ݘ2%3¶~¿„CglcÐrçÆ»/PIY¹£±–ç,>‰Ìœ½€߼έ‰ÞÍAÒÕ¦Í8ïDpK"zQtCâtf :=É®oŸ~ô0‚î*$·èøIs±kñ�pƒuè nT31¯BðÈ\ÖÓˆn߯¢5…gìáÝõ"ÄÙéÞüÑJ(‘™výLnŸÖ‡ Æ[Ëeÿ!;:â{v¯5…µwºW°ÃË€ŠâÓ“½jYXn Àª€ÃŽãx^-—Œƒt tMìQK;T:�N—wSI÷jŒ«qhÑ÷lu€©Ï$&÷85 7~2ƒßû… û2?õ·ÜÓï”Y8-xn¼¢†Ò¯o4†í™ìžûÏYnå÷ã’èpò»¨jã.ŧ½jEŒø™7�]»]£jÅ׿:¹ªîÀyâç—Ï®ÔB4 txzŽ�“�Œc`¿PÔ½ìݽ×å‘§%Yõêz¢Yix<ÕזѤ6pXrŒÉHõo .‰¿ Ñáx<öëËm7ßÀæ-[O{¿:¸qûõ9‘÷¢¹iº/]º�¡Kw ¡ën@?¨ÐuúõïN¿þTÏÎ4w.n‡ ƒÁ€¢(x<û÷g�˜ØÇë{ p!Ä9C£¬´:Q¡ÁÏ�37…ð�µam¨½´b ¦çØËþŸ½ûޝª¾?þ:çŽÜ›½'I3¬°Ap ‚ q mµT¬ˆbÕªõ[÷ªV«þÚâÖÚ:먣΂²‘)„°wÂ!{¯;Ï9¿?Â$�$rïg÷8÷ŒÏùÜ›s>Ÿ÷ù î¸c #cÛ {Ê Tÿ†Mº™a“nÝIÁÞmlÙ¼•ŒŒµ¬\·“ÂÂM|óâÙ°ïYþyÏ�Æ+•§¢WPVQ7mahXp£³O¨a‘Ç?áo&ÅH`£wM•#÷Þ£ ½’²Êºt„E„6Ú\R�M$Á¤´,ÀáÞάyYxñcØ„ËHÈ”/®ã­ö` Sºl+oƸ#‘¢3š7-£ôaúKï3rÉ÷|;+7í#wÛ*m[ŬOÞ$¤ÛfÜ7¿èub×�f컕ïÇðàöš�§‰-ý#Iðsˆ™†EE™'S´5�øØTÊ©>xˆR}1ͼָrs(ÔA±ÄÐ)Zz² ÑQkÉqËÑ–Gƒg¨åÆq íèK1¼†»î¥»1tú‘—æD׎�tØ�¡lÛ¼MÓ2xh‹-!„8Gè…«X²Ã Ši{Ѱq¼JxסŒÙòJã™f íů¾—=[cVñ!Ò7ä£÷lÅ Š¿Ã'îq¹1hp®†³GÃþ;m«^:\n74òi஡JkÉ£ÕR–|¿’2]A5ƒ£´€¦&O3© ÞêuÌZRÈØÉ1uùØy£ë Ʀ8–ÈPRÇNåѱS1\¥dmYÏÚµ«X¸`;÷,à¥+°¼ó×´Ç`›Š� ÔB¿[^ãÕk"|îoFœoZòwi¢{ß^Xç¬Æµ;�ôŠILjÖˆÓn¶glÅa€©k}ŽWšpÑiš—Þ=»3ã–›Hë�ЦyÏ‘OïZзO?úöé×êí%À!„磊Ÿ?ú’�.5ôB®¼0Ä*dnJ÷ncãö=”Ç�aò ˆ“,l±tŠT¡Ø ¶¶¶u·G5ŒÈP 4ŠŠŠÑ k0U®ž—CÞ™~xq4:%…%è68wï¾Lö· œ¡ZĬt†Ç /½Ï}ý š ±ûýÛ¹åÃýlüa!®žJŠÊÈEQPCÓh,V£W”SÑŒ.8Š_8݆\N·!—3ej/Ýý_XÏ·‹s¸jjÒÙÝK§h3JŽ—¼Ü4"¤À$ÚUË®‡ ÁÃG1ÔÿgVÔfðõ¬,ÆÜÜSêj; IDATí¸1b£—,ã«e¥èŠ•~c."^iü¸M¥EÂBøMÓè×§7Þ³Ñr£îHgé8�“¶gBÑÑv}ù™›�®ØéãM\Ôþá ð²é?OóÄßÿÅËo|ÇN×É×6*v²5GÅJB§˜ÖÝ Ôº§ ¢shëJT®u²Ó×sðŒ8bè–€ŠÆþ­Û)oPòw’±h%yÍÃËî¹sÙæ60uˤ¾M7Lt7žÞVðfÎgöv÷Ñ4µuÞXì~˜0ÊË(k°�NɆõd�¸ÜUBÖÆÌYµg#ûT‚Ó=$�²’²F[€œñŠ”FÿɘÐÉ]»†½�–ÕtŠw¬acNu#ÝSN�TEF _Asó5I˜ñ�ùåKü+½¢nàé¦^®C|ÿʬ®ÒQcÇsËøè†ë4•–Ö¦Q^ò’×Yyi^­nÌ�ÓÝWsí;B±8„¢£òVspã<Þzl¿ûÇZJ qcþÈS¿Ljðd¾}ø3òW×ÐÅ ž½_ðèSŸ²¶ÀÝèš®ü5¼ûç²²Ú@�¸„«Gµ²Šý/F°jàÞô-ÿÙ\}Ü=Ù�3—·¾ÊB?ããLø1àp:\ë¿äà UõÒá¥`Å?xùÇjüÍÍL‡sßÍ?ˆ¦Xé3a]Oñ«ñc¸r€ŠžÇüï3¨9œ¦¶ÎK§dL W¤³dSÍqûóæ-æ•ÿlC7¿?½t3|šgŸ}‰Ov:–™\ûÈØZŠ¡˜ILŠ;ZPQL&Ì ‡§¯<Ó…'•Îã¯d°¿‚¶ÿ^þbµ'&óÀlžôqî¸é^ßÜø÷º%Îîù‰sža"õ·ssO;¸öñõÓðôéä:Oü‹Ó¨Ø»”·�—×”aXS¸þá ±µ¤6#„8߆�ËåÂ0 tZ9Æét¢ë§w”—Báó<¬ÿÇm\ûA½Š¢æ¦ª¢‚Z·Ž(–H†Þp?OÜ2¼ÙƒÉ� ~©Syîÿr¸ÿåeä¬~—?¬ûœøî½HMŠ!Ø®¢9*(<¸‡­»ò¨Ö@ éÇô?ÝÅE§Ñ%`äo¸9m¯o<ÀßAÖ˜Q L°áÌÛÁŠ%éÔ¿†1[¾ea±qF2Œ¼‘[üÌËûùïÃÓÙ|Á¤Å˜©Ø»ž º÷·t{û-65�ÆQ«¾çÇÅ>�+ÇÄ�úé„Îè‰Ãy3}¥+æ²âŽáLUÚ‡¥ïý‰åŸ„‘Ò£+ñav,Z …2Ù}¨·¡` Oãæ'ÿÌïÒ,x¼M¯©G¹-}Ä+„8—¸Ýnòòòꦂ5<`¸1ð‚á:ð85]×ÉÉÉ¡‹-»½±Éì›GBáó œ…äW[¢¨f¬ö0»v#mð…Œ›4†¡ñ�L�Ùî¬$_ñ$ÿî5Šÿ~ö?æ¯ÞFöŽuÚQoEÅ?ª£F_Áon˜HÿˆÓ¼5™’ùõ3/ ¿ü2ÿ^¾Ÿu?|Æ:ê¦ÁMÿGž»+…w~¸qzÎ`�Ü”Ä/Ÿ�‰í½·ùxá&v.ÿ��ªá݇3åÙÛ¹iè~^x»nUådœ^È¢Ùk¨ÒU‚/˜Àèˆæ|Ê Á#&riø f•¬eö�…Œ».µ­óFMâ†Ç¦ð…7ønë>–}½�e(¨ö8.˜òÜvFºÕx*s9p¨ŒZü‰NJ"6 �:ïΚZ¼–ý·I¨]ȃ׼À -…[ßy›§êwÒÆZ’7îeÏpùSKñ$ÜÀÛþ޾ bP:5EÉ.¨Âc &!¹Íš×CMQ‡Š*©ÕTìÁ‘tJˆ&à$1.­¦�ìüð#.&´ÅSí¶ŽŽ£ôó*pf‚"è„õ Úçü„¯1 ]×Ñ4�¬�[éÒ£÷iìMAµX±Z¬¨Zy‡ (©rƒ5€°è8¬è7·§ÑÁ‚Aň՚³ Ç‘`e“Ë…碽»·Ó5µ/&“ UU� @¸\.òòòøyÉKdoýõèxG®†qô_Ç~)`:1)—3b $%&¶¸GÒ=ÿàHLCZp!„8{ �ÑIt�>;‡³ÇÓ-8þì솳ŒìÙªð§÷Ðî„÷¾{÷NöxA±u"9æì^Z’7Æáþ°Š¢4ÑÚD% *™^Q-NQIôhÁv¦€hRº¶ô8§KÅžH�ðÄ3~¤ö9?áûN'x` {œ8=N@%,:�ð00tµÕ§CFÃ]SAõšZ.„8ßX­Vâââ˜pí38'>‚ÇíÂhÁeËl±`·`³Ùðó;ÕœO§Ø×im-„BˆFiû¾â¡ßF¶’Èuÿï5Zoê^Gÿý`!…ºJàà‹zfúX´�ü¼"4ÿ@ü¥»„˜�®Ÿ­©"…ç EQðóóÃjµR¯¥Fó·¯ÿûtH€C!„8Ì©¿ä÷ã–ñؼƒ|óØmì¼ð"'‡bªÎeóª•dä:QB‡rçï.%Ì'ƒû}À·÷³îÇ]xQ‰éÕ‹xé2!ÄY'�?„A[*ZKB!Ä™ „qɃ¯ðRò;¼óõJ¶-ýÛ ÅF�Q¿búíSÕÉWoÅ:…æðÕ÷åèŠJpÏkxà¦þœ^ÃQ!D«H„C!šÅWKUB!DÇgŠdØ”G6ÅKMq!…U.°IЙ¡²MYxÇ[|öËZt[8ñ±!øùz’…8gI„C!šCB!Äg& 2ž”ÈöNGËXƒbH:õzB!„¾@zÒ !„BácÚ³»B4ÅׯMÒ‚C!„B¥ª&4MCU幤¢}èºÞa®A#•B!„Bœ‡lvœµ5í� !ÄyÌé¨Áf÷é9í�’‡B!„>¤þT‹Áaᔕ£ëz;§Jq>Òu�Òâb‚ÃÂ}bØS‘‡B!„>FQTUÅ? {`»·o¡¢¬Mó¶wÒ„çMóRQVÊîí[ð Â? UU}:¸2‡B!„>éH�#"2«ÅJqa.d¡kZ{'MqŽSM&ƒ‚蔜BPHX‡n€8„B!„ð9G*&“ €àÐpƒC1 àèo!„hkõ»¢¨ªŠªª˜L&Eñù ‡8„B!„ðAõƒªª¢ëº6„g͑ǑÀ†¯7@B!„Bø¬úORëW.$Ð!„8Sê_k:ÂÀ¢õI€C!„BV¿‚q$°ÑQ*BˆŽ«#^g$À!„B!DÑ+Bq¶È4±B!„B!„èð¤‡B!„„Œ½!„8[:b‹1 p!„BáÛVBˆ3åH`Ã0 dT!„BÑ6 ÃÀ0 ª«*(+.Âép ëZ{'KqŽSU6»?a‘Q#È!!„B!|БàFqaÕ•ÄuJ"$4“YŠðBˆ3Kóz©(/!÷`6NG ‘Ñq€ï9äê(„B!„�9Úr£²œêÊ zôî�a¸=np»Ú;yBˆs�¢JÏ>aìÞ¾›ÍŸÀà�Ãoùn�CB!„Bø Ã0(+)!6!¯×#ãn!ÎÃÀ«ë(ŠBlB2EùyûtpdšX!„B!|Ža躎ÓQ‹¿¿¿7„íÂ0 ìþ¸5èºîó×" p!„BáCêÏš¢ë†�?1BœÛEA«Üðå ‡tQB!„—z{§@qó倯‰$À!„B!„ë@u !„hWÒEE!„BÓ‘ž˜ !ξ~m’‡B!„B!:<é¢"„B!„Oóí'¦BÑRº®³'s7»÷ì9< 6DEEÒ·Oa¡¡­Þ¯8„B!„ðe>ß0¼Nªk½˜íØ-Ê)— !DS–¯XFEu%û$$4 عk'³~ø)ÉÉ\rÑ¥­Ú¯8„ÂWµäíÍ¡Ükv¢S’ˆ°6c3GYÙåxÕ?†.‰¡XÎtZ;"O%Ù»w²ç`¥Õn ³þ!Q$¦t'59?)£ !|D›Ä7Üåؽ›ÌœBÊj=`¶O×=I‰ð㤗<×>f¿2“w–ì¡Ôm@ÀXþß×s‘ÑÄòfÜ«„ç¯Ì¬LååpÕU“10??;#†� ÿþ,\¸€å?-ã’ GµxßàB_åÝÂû÷=ÎìJ;#þ˜'†Ÿ¼ŠÎþ¯žbÚ{»ñ`éw'Ÿ¿ö+dÄ¥£ôò|ÿÉG|:7�ÕZʃ¢b�éÇøëoaÆä4"Lí‘ÊcôÚ"rJtÂâb’»¶ç©Ö‡8´²íu×¼ù9T«7Ø“¢Úˆé7š_M�Ê/G5×Ù÷ÕßyqÁ¼jÝG¦kHOÂU�}_4¶ÜGš›!|Öž¬ÝôêÝE�]»w’¾6“ÉÄ€0` cÇŒå£�?bØàaØlöí[ŠJBáë'ëç-#üµÄ�,XáÝÃü…Yh((Š2�gP³óKžxü]~.ö‚j'º÷@†õíJ|˜ ÕSCqNÓ7�™¿‰ï^¿ŸŸÒïæ•§¯¡«_{¥Y#ëóG˜öi÷|ü ¿>é‡/„õTmÿ‚?=õ!ëJ4 ÅFtÏ� Ð�ø0;ª³’ü}[Y›¾�ÜMsycË ýòþßíȬ©1*زåC%þºgøà¾þX ¯«�ï[îö ·Û9 !:‚ââbz÷éMEU9;·ïd¸‰1wá\ìv;ýû %¥3;wíb@ÿ-Ú·8„Âש�HIÈcßÖùÌ?x Ó’›®äº·-dÁAƒ�N�0¤ö,&Ó×éyóxê‘·Y]fà×éRî~ì^®ëJƒîBÖ|6“g>\OÑêðØÛɼ÷ڣˊQÉŽ‡ÐéÑBøŒVÄ«µœïyêñ³¶ÂÀÚi4w?q×§…aÒt P@QLP�Éì7ÿÂÌï³Øñå_xÄö7Þ¸9Û‘éjkuÀL§Ä §÷É– !Ä)¸œN,+g Ng-‘‘qÉE£X¾biý�œœÂöm[%À!„ç5œ¡Ã8øõæÏßÍÔÛS›¸x;ÈX°Œ|‚= …µ9Oº[oE6›7ï"»°§âGHt½úõ¢sH# ”+sÙ“W…a‹$%9‚ ô*r2s©2lDuN&ò„ w){·ï$+¿”Z·Š_p$IÝ{“šØ0ÀP·ŽvmÞNf~9ÝJhlú èIœ½…-ŒRüãmV•騑—ðèKO0!¦‰}X£~ó3¼ÈýÜñï}ÔîXǶÚþ k$ÂÑšô5// jò³8X²�Õ»¼†“‚½»ØQiÂ/<‘”(;F+?£*—ݹUàK·Ä¼ù[Y™žI…½'£/ëEX½Ók+ Ô¸q<û棌 ñàu8ñž¸®5‘+z•XÛ=Ü÷Õ>v~ñ&_\ò ¿MQ©ÉßKNy>…µ S[�ÅÎÝ�8KË1B¼',BQƒIèK Œa$„h]×Ñ4“©®„…ÃQ‹¦iX-VjŽïSBáótb/¸ˆîÿÛÅÎÅóÙ4-•Á� àV�Μe<†Ñý4~þ¾‰Ý¹sùñÝ¿óÊ·›)t_lV¬‘ œ|7�θ„Ä£Ç0¨Yõ&3^X�Þm¾ó[ºžX¿uüÌ«¿�Z ·¾ó63º®Ê5ìøîUžo ™U'Œw¡ø;ðZîx:Çžp;ÒËÙðÅËüí£ŸØ\ŸqÕ?‘ÑÓà¡ëûÒÌB´ž3Ÿ/WW¢+þ\pËï×Tpã(©¿yŽ/®²nk8îIkÒ×¢¼ð°éƒû¹^Õáõ2ùì±ßó*‰7¼ÊgwõÆÑÊÏijñ}î|òG<ýïáãÛ«xö�ÙVk Æ\KçQ½3Ÿ�óB´LËBÚÞ¹|µ¾C eì�wqq� ¯ÖÔ®5¼n+o»‡«V>À×y{øî¹á¾¾lüà~YT{ôè[ÿó(·ý“4oÃåöÑ<ÿÍ#\,ƒŒ !šEÁ0 4­îeµúáv{Ð4/Šªà”‡Bœ‹tŒØ‹Óã#vìXΜôÛ<òÄ— ÊW-à§J›xCm h´,k”²tæý<¹ #°;WM¿�±i „REöæÅ|òŸd|ùþPý4ï?4’ÐÓz gP¾ìexíGJmI\r㵌íÛ‰P?/Õy»X9û;ænø‚'žðã_oÝLꑆ#F ÿz�?~‘…Û¿ ãfLáŠ�I„eìMŸÃÇ_¬`ñ[�Pä}…×oìÖ°åB#ùW¸f »½Šÿ®¼4Šfµÿ°„ÞØiµ&}-Í 3]¯¸›GSÖòŸ·s€ÆÞzÃBLtMh^ú› X­Xp;ðÍÛ ØÜ�±cRñO%L=[çw' „8�ì5k9¨�u W_`G7N 1Ð,}¸êòD¾ûèÅk~f»g=®ù#O-bÕGï°è�B—‰wò›TÊÈ·³íãúËQM±¤JíBˆv“±i7nnÖºôg`ÿ´¶=þʲüû§ðxNÒaÍÿnOý�Çí൧ú2däuŒ½v&ªªâñx0™LÔ:ZÞÙZ.ABáë C‰çòñýxg{Ëæ®âÞcŽz®³tþzj•h®?[ÅüFŸ÷¹6}Êë ÐM�™òÜKÜÓßÿh넞}qAw+ÓœEÎü·ùlò0îìy:·‰Ö,ZM©n&uê3¼pcR½ŠùpF_>Œ¨;ïã󢵬̚Jjj] ïîÿòâW{q™“¹á¹WøÃÀÀ£iLí;”‘Ýÿδ'æ±åãw™?îy®Ž:Uu_c_æ~4ÌÝúÑÇÿ4N©Õéky^Äô¿œ+ãj˜÷îbFßË®àꣃŒžÆ²ª ç,aQµ¼úþm¤Õë~ãÝuvÎOÑ-ú“w±/3 k�¾ôTŒæmo@ç~} VPV¶�¬Ô÷2®è›CÙ¬÷XtH%ªÏh&MCUTвùdöñËCGójœ2ž"„8#TEeã–-dlØtÒõÀàAÛhêc~šÿþ况&@ýö¯†(•óÉ×ÈËËÃåv š¬Ü|÷£|ôÚ“ ¼øÌfn�0ðx<†�¢4ÿ‰› Ç.„‚JÔ¥ãî5ëæ³¤äø1êõÜ¥ÌÙìBM¼Œ+úZ›˜JÖÍÆÅËÈÓ¬ý'3¥Ÿÿ ë) ºŽ+»›1´C,]–Ùx+�æÒk©¬òb `67(ñKåöwç°ôorÛÑ ¯‡­ ²Ï ö¡7pó€Ài q“»›1œ™¿²øÔ£õŠK�è(˜#¢ ?­;_+Óת¼8C”º"‡î€Á7N¡ßqc‹œç'Ä9ÈhÉ�^NqYÝßchLV¥ùÛ*áÑD©€VJq©†®¹ñx¼G¯³†áÁãqãv;q7²Üãõ¢·,µò#?òÓ†?ƒôçö[§×/š0xÐ@fLŸÎÀþi-Úwsx\Nü‚ú±?»†%Ë÷PRª�ª?¨�(j11 \>*™ƒ6S’¿Ÿ+Æö 1y$aá¡Ø� §Ó‰¢Ôuai iÁ!„„2’I†°báfæ,ÎçêâG©uö/^Èv�‰ncÇÒÓLÃAäô|vìª@G¥SßÞ�WôÕ8z÷ AÝUBÞž,*�Ôã�l5œ>½c1m:ȶ�ÿÂßl·ñ›Ëú“t¬‚«ª'$B/dëŽbtLtNkbŒ 5�´>á¨»ŠØµ-ϵѧè¦âåp×NLSÁ[¾~‹ÙY�åœJð _qרDÔÖ¦¯5yq¦™{08-àøü8—ÎOˆó–ަÕU̵™Õ’Ã,fêz�yðÈ\¯Bt8š¦‘Ö§73¦O`}ƆãÞ¯ nÜBZŸ^GǽhkºáOç.£èÜÕè†0Ž* ƒ>}»Ò§/u­3Ý›�×UƒÉdBQ4M'+k/©©½Z\~�‡Btþ Ÿx Ñ‹f±mþBöþòfº™ï.æ-Ú‡féÍıIM7ÍÓJ(*©›Ò/2:²‰õLDF„£R‚^ZB™Aë˜é5õ!nÝþ$ïnÚÉw/=Àÿ^ $¾gƒ aĈ‘Œè�í¸®6%וª÷õ7Îk<•ÞŠr \ÅETêpÒ^*Š»‚xjkñ Ç¿óp0}³V5ÖgT%Æo wŒMDmuúZ‘g˜âAÔ‰SœCç'Ä9¥%Q £îšP[ãhQw£ÖA­(þøÛ”ºãÖß¾þÿ›Z.„hWšW#­wofÜ2 “ÉÄÚué@½àFï^hMŽ:|ú\UP�ÕøÙ{áÕ8ª3q9Êq:ªqºjp:jp9kp:«q:kñ³ºéÜåR £®ü¡ª ÅeÅ„„‘žžã&¶èøàBˆÄ/m<—'üÀÇû2gÇo¸·¯×Ö…,Ìѱ ¹œ±q'«é{ðn `±˜›hÉ&KÝ­Áðzñœf�U èÃô—Þgä’ïùvþ2VnÚGî¶UÚ¶ŠYŸ¼IH·1̸ÿn~ÑëpWÃÛ``h<ž&RéI‚?˜CÌÍèFc!6>…\¼ÙÙähгA/ ý(ÏŽ­ÿÈRãÀüðþšÊc‹N#}-΋3L1[1Ÿx sèü„8o©�ÄÇ RNõÁC”êƒ8åÄQ‡¹rs(ÔA±ÄÐ)ZZ] ÑQkÉqËÑ–Gƒg¨åÆq íèK1¼†»î¥»1tú‘—æD׎¸4lÈP¶mÞ‚¦é <´Å‡–‡Bt$æžL×…ÏÞÏbÑüÍÜÞ§ó—S`0jü%Dœ¬æ¨Ø°Ùêþér¸0h¬¢iàr81Åfï¹5Q]oz, S(©c§òèØ©®R²¶¬gíÚU,\°Š�{ðÒƒXÞyŽkâTPlø¥úÝò¯^Ñ•a3]ûõ"ðË\*­ãçœiôL>±àn&®ÿ(âŽ[æeÓŽ÷�pœnúZ’§ëdŸIS:Òù q^iI´ÙD÷¾½°ÎY�kw:铘Ԭ¦xn¶glÅa€©k}ŽWšpÑiš—Þ=»3ã–›Hë�Ц5Ú‰¹��Þµ oŸ~ôíÓ¯ÕÛK C!:•Η�§¯Å xõ 6Wf°hU9„ŽäŠ ƒO^UcHˆ1^òró›hùà%?¯KLÜá® ŠR×ÅÃÐ4´Fî[zE9ͨM+~átr9¿¹ë)Þÿè~™lƨZÏ·‹sê*ã¦X:E›Qð’—[pzƒœÖ0x4—„ªàÝ÷ÿ]Gukï½m˜¾SæÅÉ·n³Ïä8>s~BˆúŒ½‚‡�b¨¿‚áÌàëYY8›±�V²Œ¯–•¢+VúŒ¹ˆøFz¨œ˜–Ö§Q^ò’×ÙxišF¿>½é×§7^M;­}5ßÙ¢4MBÑÁ¨±£˜4È£$�%_-gM%D�Ç0û©6Œ¤¿xLèä¯_Ï�Æj¯î�¬Ý\‹¡XHMëÅ‘]Zì~˜0ÊË(k°�NɆõd�¸ÜUBÖÆÌYµg#‡R‚Ó=$�²’²ºJ¯FÿɘÐÉ]»†½��–JñŽ5lÌ©n~Ü87Þл¢S0÷^˜ˆ“ÌÐ^Ç]ÈÞƒ5'$º•ékM^œàÄÂE«>“SiÇóBœDKk"Asó5I˜ñ�ùåKü+½ýdë»ñý+°ºJG�Ï-㣛®Ý4w¹¼ä%/Ÿxi^­nÌ�ÓÝWsí{——‡Bt4J8£&\@ùÌÿr9eJ<—�ëwŠ™DLô˜0‰¾6ïÞÿñÏù¹'ÄØ]d~óoæè¨Aù沘£7 K§dL W¤³dSÍq÷9oÞb^ùÏ6tÓñíGôÒeÌ|ðiž}ö%>Ùéhxotí#ck)†b&1)îð±T:�¿’Áþ Úþoxù‹=Ôž¸Ù�Ù<ÿèãÜqÓ¼¾ù”aŠ£çžò‹¸gX(ŠVÀ�û÷ýc!;ËÖà g ;–|ÂSwÜÁß×Ta˜£Hë{Zék]^€b2Õ�“¡•R\z|�¡5ŸÉ©�ÝóBœ!†‰Ôß>ÌÍ=íàÚÇ×G!C IDATO?ÀÓ_¤“ë<ñ¯S£bïRÞzüA^^S†aMáú‡g0ÄÖ’ÚŒâ|g.— Ã00ÐiYDä§Ó‰®Ÿ^€DÆàBˆG!xøxF…-gv‰S×1LHµ4kK5ñjºu5w½µ�•3ïfÆú‰ŒéG ·”¬õ?2ççljM1\ö‡;~¬r¬v¾”ñ=?'s[>³ž¾—²ñÓ;Ò‚£`ËgàwÍ4Æ/x›Y%ÆÑÀ½;žÛ&Ïæ�_nã½{§³öâ Ö-Ž`‹NméA6¯\ÂÏÙ^,‰“¹ilÔÑJ¯;‘î^Ë�3W±á�û¸iýeŒ–B„ÙEÑÞ ~\’ÁA‡…ÄIwñÛ~ çCi’%‰ëþü"æ™æ•ÅÙd|ñ·|ý: Ý{’„MwPQ’KffnÿNqóý`ê ˆÓJ_kóB N"9LemA>ßýíij†Ä@È0î¸i8¡­øLšõ9‹ç'„h®–V tSWn�ùWÌO?Ã{ësXúÞŸXþI)=ºfÇ¢ÕPx “݇*p ¦ð4n~òÏü.Í‚ÇÛÔñšz”ÛÒG¼Bˆs‰Ûí&//¯n*XÆ/®Ã�SÓu�œœºØ‚±ÛOÕ,¹iàBˆŽÈ WŒŽá‡¯Kè=~,]Ì Ò+]¯ÿ ÿŠüˆ×Þÿ�5‹?cÇ¢Ão)V"R/gÚŒL|Â4²j7<þ0…/¼Áw[÷±ìë},CAµÇqÁ”çyrŠ�Ï–)`¸q¹r•ßù"/G¾Ã?¿^ÆÖÅß°ùȱPPí1 ˜t ¿»m2ýƒê·40“8éO¼ù9o¼û-Ë3~àƒõG6S±GõáÊé·rçuý oi{ W?ù/†^1‡O¿šÇ’Œ,íXOÎŽzé²…Óuè0F�ŸÄäK{Ñ vÔŠôµ6/,ý˜rûÖü}ÙûWñÝ~¿AÉLŸÚÊϤYÎâù !š¥U¡CÃã—Ê´—>äÒ¥ßðÉ·óX¾%—¬-ëÈ:²Žb" ¶£Ç]ÃÔë/£»Ý…«ÉàÆÉÓ"á !Î_n�‡¢¢"T“™êòM„ÇŽA±„£ªN,F"˜kPýª0»ª°Ø«°y\¸ÝÜn'³·« ·ÇEaQ ‰.l6ŠÒºò‚9ýoJ]É8ûµß�tå›3tÁÅ­:�Bœ/2~^A¯´Aí�ŒfðR��ƒEÕ¸Uáñ‰$„ÙNñt]§¦è ÙUx,Á$$w"ÂÖœçñjŠò8TTI­¦bޤSB4§ ³ë8Jq0¯‡a&("�N±AXÛªŽì­¥(/—¢ 'Ì„FÑŒt�NúZžZM!Ùù5àF\L(Çgyk?“æ8;ç'„8ža躎¦idíÜJ—½Oco ªÅŠÕbEÕ*È;T@I•¬„EÇ‘fE÷¸ñ¸=�X *Ö€@¬&МU8ŽL›Z.„8íݽ�®©}1™L¨ªz\Âår‘——ÇÏK^"{ëǨ( ¨GÇã8ru0Œ£ÿ:öKÃЉI¹œ^ )1±Å-8’îùGbàBˆ6ÖqB!|QÃG¯6Ú³R¯bb`è:º!� !Ä©íݽ£É‡a¸ÝnNg-·‹–\ZÌ v{6› ???Tµejê8äyŠB!„ç]o« ¸…¢Ž¢(øùùaµZ ©×R£ùÛ×ÿ}:$À!„B!„“6BˆŽ -­%!„B!|™D8„¢Y$À!„B!„O“‡B4‡LE/„B!„BˆOB!„Bø˜öìÃ.„Mñõk“tQB!„ÂG©ª MÓZ¤þT‹Áaᔕ£ëz;§Jq>Òu�Òâb‚ÃÂ}bØS‘‡B!„>FQTUÅ? {`»·o¡¢¬Mó¶wÒ„çMóRQVÊîí[ð Â? UU}:¸2‡B!„>éH�#"2«ÅJqa.d¡kZ{'MqŽSM&ƒ‚蔜BPHX‡n€8„B!„ð9G*&“ €àÐpƒC1 àèo!„hkõ»¢¨ªŠªª˜L&Eñù ‡8„B!„ðAõƒªª¢ëº6„g͑ǑÀ†¯7@B!„Bø¬úORëW.$Ð!„8Sê_k:ÂÀ¢õI€C!„BV¿‚q$°ÑQ*BˆŽ«#^g$À!„B!DÑ+Bq¶È4±B!„B!„èð$À!„B!„BˆOB!„B!„èðd !„B º²œÒ¢Bº®µwr„ç8U5a·ûM`pH³¶‘ë”8[ZóýôàB!Äy¯¸ �òÒâ“ Ád2µw’„ç8MÓ¨©ª ïPN‡ƒÈ˜Ø“®/×)q6µôûé+$À!„BˆóZuee¥%tïÕ³YŠFBˆ³Ãd2Ž`0{vlÅf·7ù¤\®SâlkÉ÷Ó—ÈB!„8¯•��˜$•!D»0›ÍÄwJ¢´¨°Éuä:%ÚKs¾Ÿ¾DB!„8¯9ƒ|ÿ©”âÜ‚ÓQÓäûr�íéTßO_"!„Bœ×t]C•¾ìBˆvd2™Ðt½É÷å:%ÚÓ©¾Ÿ¾DB!„B!„èð$À!„B!„BˆOB!„B!„èð$À!„B!„BˆOB!„B!„èðd"e!„g€›ÊâJ\Š��ˆ@¬í�ѶÜUW:1Lþ„…HaâlÓ=¸Ü:ªÕ‹<ªBø"_»Ni.j]^ Å‚Ýn=ö”¿©åmy �®ëlÚ²‰öS^QŽæÕ‹'>6žAcµZÚìXR&B_eÔ’·7‡r¯B`\Wƒ›¾UzËsÈ*¨AÇDHBâÛ÷¶ªø/÷LŸ½=ïà³7®§“rä\ŒÖTPUV{0Ñ[¥8Ð,F5¹™¹Tèª ]CÏê ݽúe~ñÔR< 7ðö‡¿£ïyYšpSUR‰S¿ ‚mÊ™?¤·”«V².«ˆZ °veâ�—’Üê™#�œÃ —Š‚¢(˜,6ìþØLgáÜ„gÀ¹p�j„椬¨ˆ’ŠjÅdÅLDd$¡öÆ¤å¬æó…Yx‚Ó˜üË¡Ä.nhÙ«øtñ^´–·*YMã|WRRÌœy?`³ÛIHŒ§K·Î¨ªJUu5ùyy|üéGL7‘øøø69ÞyY$BˆÁ»…÷ï{œÙ•f.|ô+fN¤±¢‰7o1Ïþß_Y�¯1â^^ÿs·³žÔãé­_Ï>ÍD§A‰SÏ‘sizuÅäOlêp&\7•©cRhÃr˜^[DN‰NX\ Aææ¿ç«Ü[?æ÷~ÉAÔàÑ<ûéŒ jû‚k“y£¨˜U]UQÎ׺¯^@úÜ…ìrª$�šÂÄî~gø€e[W°rw1šj#21�P[$Gê+†»†JØ‚ðkn¡úè9œx¬GµÕ‰½ûÓ¿kx›¶Æ:Yš[u>Bˆã� שú{w±sÃz6îÉ¥ÂÝÈuKµ߃�ƒÐ3ʯÑ2SŠ‚ª*r�9#t]gî‚ytJN$&&š¼C¹dïÏF×t"£#éÚ­ Ñ1ÑÌ™÷¿�:­MZrt�¢œBˆÆè…+øëƒgA¾Nøð»yõé«Iiïþ F5é»ð( ҙ㟥¨D¤^@Ẕ¥†îÅQ‘Oæîäo[ÂÛW³jï_ùÇŒ~mäÐÈúü¦}À=¿Â¯ãÔf¾ç«jYûýbLÔVý̬%ÅŒ¾:ª�›Ã6�7ÖKž`ñ�O´éÑÄ©8ÉË+CC!(õ2&�Œ«WˆÓ)ݲ€¯7Y¸àW“Hkq°K! *‘èÀz­º†×UEiq9U{Y_p�¥ã¹zhL9N–æÓ=!Dû8s×)wñV/\Ç�0K§Ø‚ìÍIeqsK¨ÈÙÊÒ¼d�ǘž¡œªáˆ©ó¥LŸ~iKOT4Ó–­[°Z,$$$°fõÏDEF3tð0Ì+û÷ïcÝÚuŒ¼há‘álؘÁðaÃOû˜àBˆJ/ý™zžïs¼„¹“WžžL×3ýp¦9œ[Y»Å�ØŸa=OŒÄ›I½öžo¤5Š^�Åì™Oò·¥ùìþòf_ù ¿Žoƒ*»QÉŽ‡ÐéѲ÷|”Qº‚ï–—a؆2}º�¿±‚Œ9 ɾò7tnËGÌ›sšáÁí1•�Ð� p. ‹*ЉlåÎU"{_ÂøFžî®vþ´ˆ{«)ÞºŽ�©mp8YšO÷|„íâ ]§Œš,–,XË�ZÕ¿ƒG]È€„ÀÁ oõA6,[AF^{WýHPðUŒˆk»±DË<”MBb<û÷í'*2† ã&}/91 “IeÏž,âÉÏ=Ô&Ç”‡Bt@FÅzÞxø¾Ùç!xÐ ^~æt·Ÿ|ÝQÀ®ÍÛÉÌ/Ç¡[ �íB¿=‰³×«N öeSêQð�îLrXƒzëĤ�zìvâٕΆj¿ ÓßÖüsR»rÕ�¿bþÊ×Éðd²-ÓñÇ*\ze.{òª0l‘¤$GР*¦W‘“™K•a#ªs2‘~5ùY,ÙÆê]^ ÃIÁÞ]ì¨4áÞ‰h-—œFßK$%Ê~\Æ[‘ÍæÍ»È.¬Ä©ø�D¯~½èÒ0Œê\vªÿXº%†`2œäoÏ #3ŸjÝ�Ðø Ø�ÈV=×ÉYøëà?âR&LdÏÇ+™·{>sv^Ï]½O}[÷”`ó¦�,©ÅëJbj×õàdùV—7>GÃNrç(ì�ÔwÏfžîRönßIV~)µn¿àH’º÷&µ‘°/1<ÕPVåÂ� {`81±‘YŽÏPwU Î*j<žšR ‹jPTv?7ŽÚB²‹uÀKMY1EN“á§_°Wü"HÞ�=ûW“«•RX¢Q¿¿’ᬤ¤Ê…a $,ÔÞ°`i¸¨,©Ä……€ÐPüÍà®.¡¢‰4•M¾wâùèÎrò Š)¯qâÅ‚- „è˜hBm�Dú\UW9ÁLxˆ*ª òÈ-­Â…{Pñq‘øûòFˆvÐþ×)'{×üÌþZÅÖ‰‘WŒ¥ohã¨æÀD†Ž»~˜Ãúâ2vlÞGZl�“·=|m0Lþ„†ÐXj4G9ùùÅT8Üè&!‘qÄGØ[|Ñ�•”V»0°z^\oJJKIìœH~^Ó7x¿KJ7–,_LJr2åUmrL p!DcTmáíGŸæóÝn‚Lçåç®'Õÿ$èåløâeþöÑOì¯Õ9ÖkUAõOdô´xèú¾„(^¶}ò0O,®"`ôã|ýÔh‚)è¹³yòö²YOfú?ßáöÐ#ïhìMßH‘a&mpZú W %DU“ZcƒšUo2ã…Õèݦñá;¿¥ë‰uÇϼúûX¡¥pë;o3£«Æ¦îçþyU‡Ï9“Ïû=Ÿ¡’xÃLî­xЇ}ïU>»«OÝ Ò�Ë�ïþ�W¾ÝLá ý}k$'ßÍ£3.!±^ÅÛ³ù#î~lδßóÙS]˜ûìs|¸±”cã«*XcGpÏóOò«–6¹ñf2gÎ\J]~!á�f&\Æ‚ï1wÎné=”&ã\ÞV¼ûWþþõ¦ãÏE±‘v-=v£bÍ€ç$ùV—7úúw¹½©AFÏfž5ìøîUžo ™UÇMñ#vàµÜÿðt.Žõ±âŽá$wË*VlÜOYƒ< %eàE\Ò/†ºø FÞú9ÌÍt]§`Ó|¾ÙXº0¨ó!2ö¸¿S¦³Ø„Bp¿+ùõðè6鶤XmuýåõºÁGës\÷˲1"ñËÉ ?ñoÞ“ÃO³—rÀgÈ5×0$ /c.sw7–æ+éZļFß«w>Z%{×­ä§yÔh'ÏäO|¯ ¸th Áõ*ZA³dâ�Î c"Øýã2òÔȘĈËGÓ7ÂǾ/B´¹N•™l=àÄÀLÜ€ôi"¸q”%Š�"ÄBR\§WUËM绦Õ«9�¾œåÛN¼Ö¨ÄõáâQCèÜÌAÝ G6+¾ÿ‘ á½ÆpåÈÐSotpÔ:°ùY©¬ª!<¢aë�°Ðª«j°Úüp8kÚä˜rBˆĨÝÁ‡�?Á‡Û¤ý–™ÏO¡·ÿIîÞF ÿz�?~‘…Û¿ ãfLáŠ�I„eìMŸÃÇ_¬`ñ[�Pä}…×o솟ÈÈI£ˆZ2‹Â5 XZz)WG4èL¡ËØáK¯qŒïV¿ß~é‡ÐLI Ôò1!œ»¶²Ûc øõ¢�Ó½E™ézÅÝ<š²–ÿ¼½˜$0öÖb" kÝÜM½—P—n£”¥3ïçÉ…�ݹjú ŒMK ”*²7/æ“ÿ, ãË¿ð‡ê§yÿ¡‘„Î&ÅlÁ¬€Q�Åù?º/äöG. g”GÞ&þ÷Ñ—üœ¿š7f~ËÐ7Ý¢n%ÎMs˜“­¡†^Ĥ ‚P€AãG?ç+r—Îá§Û‡0¶±ˆ”QÎO/ßÏc?䡇õaòõW0"% ʳXñÍÌÙü%O<àbæ[÷2<èdùV—7M{VóÌ |ÙË<ðÚ�”Ú’¸äÆkÛ·¡~^ªóv±röwÌÝðO<áǿ޺™TŸi¥ì&wÝ<æl.A³†ÓmH©ñ!øNÊífÖ}ì]³€Zý ®ê� •ˆž#¸4¶šìMì­Rë>„´+Š)ˆðÀ$‚²)=‹r‚é:8�N~ Öˆàæ °× ÞâJ4ÀI\äé†LT"»�`Thci!ÒÛÔ{GÎÇÁ¾•sY´§Ã/’žƒûÒ=6nÊó3Ù¸)“Ü­K™í1qÝÅIÇ~ª UÃSÊæ%›Ø«'3tT"‘&¼•ùìØ°…ìêlVÿ´�NW¥ýn q¢Cyyäåæ5kÝøøxâãbÏpŠÎ_¹NÔæ¤P,ñ¤vmÞuÍѹ :W:9°j. vVbØcèݯ'‰avg û¶oawÞÎõ2ñê‘t:Õ³ Wé –²£Â ¸û(&�ìÄÉŠn§ÃW¾Ÿ«æÿ…Ÿ|Kò£`€ÓQÃ;ÏöB×G'7tÃÿ@×5^z8Šcþ�ãkõ±%À!„…#“ÏŸ|œ·7Õàßg*3Ÿ¿‰~§…Ó»û¿¼øÕ^\ædnxîþ0ðØØ©}‡2²ûß™öÄ<¶|ü.óÇ=ÏÕQ*¶þ™�øfo`î’|®üeÜñ� ýK–îÆ‹CÆ_Fbý.å¬Íô¢F `HR *BZ5Òà¯|O®áO¯)Ó™}ú©˜þ—se\ óÞ]ÌÂè{Ù\}t°Ì“½®MŸòúÂtSg¦<÷÷ô÷?šw=û â‚îV¦?8‹œùoóÙäaÜÙóð-UUPmïæ º‹·_¹®ÞÀ¯CWÍ”f‘¿g« ®§ss65ªøiöŠt•ØË&0øp«kŸqŒïü-ïí[ì%E\vMçaîí_ðÚÜ<¼~½øÝÌ™Lëz$AùäâTl·?ÄW9syûûë:%ñùÖ´³›g5¬Y´šRÝLêÔgxáÆ¤zç=œÑ—#êÎûø¼h-+³¦’šêm�õâ­¬ÜZ‚W %íò+w¬dÓ‰ÄÈå|½pùÓÙÝm½㺑[�s÷öV)Dw£Wê±¶:QÁ.ö¤gQŽ�˜.=èÕVƒrê.Êsw±æ§�TV¢Ó†Ðý´GþUˆëJj“i>Ù{àÍÛÄêÌjt5Œþ—OdD챦@‘Ññ$F˜ùzÞ*÷¬cKj'†E©G‹è%™ì‰Îä+úvä+߉NÁn¾˜»ƒêâl²«û*›Š“ÈÍÏ'7ïä•È„¸¸6›öòló�ë”Aii: †ÅÛ‚n¯§K+ØÂêÝ•hæ(†MœÈ ð#ŒNtNŽÂòÝ<¶VìfÝ®>$¤…4xñ–²åÇEdi¤\Ä•·í,q�ñ…ïçª/òÈ_ßáõ÷ Ð U1qý3ñ·[ ðC5™¨­uQ[ëä›9…`˜øÓ ¼ü§%À!„ç:õŸožù3¯¯/GWCríUô;eáÀÃÖ ÙçûȸyÀ‰{*„ޏ�ÉÝñÏÝ™¿²˜+¯�F5w犉=øô_;Ù21®›JJ½º­~p9?îñ‚ÿp&]z|+�ÚMëÙêV0„ÔFï0Ò߸…«ß©—ÃKmU%µ•à”áÜøø4nÛµé®g…›�‹—‘§+XNfJ?ÿy4è:®ì>‡·vbé²Lnï™z\\C‰eÒÍW6˜ÕÆÞ{}üf“ï*"·@‡f8ôÂ%|·ºݔ̄ñ}Ž�Abê„ ©|üÖv6ü°ˆWýæ¸Ï ± Ì åd%YÇJÔh$™äÉ�¤¡§;7jé‚B ÖÀ`3PePi÷ü:á#<, ’€4šmDö edRR/½Ñ“ò)+Æ * ñðU¼¹êŠ+0™ôz-Šbƒz«eÉ:Ǻp×_‹¡Ú„§‡‹ùØ_Wtp‚ ôx •*î|ЧnêGê3÷ðü¦tÞ{ü?D¼ö(Óš›Ê¡”PTì¨ûf!×üêü}¶ŠrTTÌÅ'©T H9`"�ŸíkrXµ2�ùC¼ýkÖÅ&2yöh<œè0Ûv•£ê“Øøé}cïý‚Å�·‰U­ ��²ú+Þýøg^½ ;ÿ±„çæ…wOAe/ád‰h l¦R¥!0À™”ÒÊT6Öõžx: ¼L]»»­ÝXö³ì×Ll¸2fVÃiArÀ…Ìû.Û“óX¹"�ùqc9µî¬RBQí½øú·0ŒöLuyœi‰¹öAæï_Äû»òÃK÷ó㫞ôÏȤQŒãcƒ[]`®K©5TW;î lßï|uØyàìF*`«®Æ¤rÖ‡3ƒ†Èó¯dv“mb̆r3÷’²+ƒÍ¿d“wÞ\f õF}ª‘êǔ̈́AÂÃÍ ‰Tc F•!’Ƨ-1©'¥¡Ç«kDÊ;%ròò€s szX>¥AW»[‹b±b£™‘�M­9•׸¹é;PnZ(Úù;;”aÓ†2öÂx‚»ø‰MOHŸVãTój\Ýã°TV`4da6V`20™ª1™ª1«1™ ˜Œ5¸ë­DõŸvÆ×‚ =ž–ØùKxýÚh\�°Gqôž‡ù%PPí *Hª Uµ8^ŠU1£(f»ÅnB±ŸÙÔ”:¢ƒC¡Ç“ñ <5åCòLàŽ§ïäø]KØ”ñ)�>Æ;OÍ"¼ñc I�‡;PªcøM¯òÊ%íªÛëGÌbVÄ >ÊÙÄ/Û œ7Ù�ÃÉë8®h0}:1 žF(¥¥qÌ.6bíY_´ñ½Ÿ?�a/oe‹aÛؘ9¾��=¥ùÝ=ÚKÒ£¯—k6šQqÖ@V1×>Á’ôz\ÏVÅE-eíO)S$d-K 16óV�,a3lgÙÚ"¦]âxÂ-éqÓ;Âk2šPð<;Oß»+Î4¾ �v-�L»Õ\JæÞTRR6óÛªÍ<¼Š—¨@÷Þ³\ÒÖÅ\Ï*-.:À¨!$é"æÅtïJ3m'áMÈælN˜óÈ.VØxQsÔÎlúhÑÕæsöf瑨ØêŽiµhE‡†p–…†32iÀ9й=+Ÿ’ñÂUªÄdÈáDÙ(BÚ’÷X1™eô®ï¡ÅÑïÈO÷“¶JQq KdÒv¯ÞN^ÖfÖ†0;Ö§ËG¿ukúìÔü¿ízBi/‚ ´“6b.O>~9t*Å_åáwvQոф¬EÂF~^!ížV®œYƒÐ©¶®ÝN•õkÖå èb˜3=ªa¢HK=„Uòcä¨�4„ÔŠÑT×e!!I ÚO?Å­O©(§¢³z8äÂC4€�ü¼‚fâÎFAþI$t!a�¥UÉý�e;Œ¨rW¾´Œõ¿ýÚÌëg–^�F5³ëçß8^r0áÁÀN~n�ÓN ÕfÆl;ÊHˆ3ÉÕŸ�£¦ó×;ž`éGÏsE”µ*•ïWçt^ç×™�½ðötl´[Ueèaj7;V›“�+ukv4¤šk0uVWòÄÛS*›�?ƒ¡Ú±èŸgW.J(ü‘…‡…9¦œ zX>¥ëÓ�HW ”rì9Þl}–ü|ÿÅWü¸ùå¹É/O P©ª¬r>BE±á,+t||SgŽ$ªÏ0¦Œë‹;f²·¯#­ØÖ�Àœ¹îKŸÝs¿¢ƒC¡W’ðJZÀów�ÁO2qøë§yüÇ4Ü'ù‘�……¼”md9-gŠlcWŽÁIƒT¦ïŒY$é¡zG2ë·¯em®‚Ûˆ™Loü4Ü´—”½fpÎè¸æ–m •òí[Ùoä0¢"O4Ô¹¹¢‘@-/£¬I`Jv¦’ÙJ/NKí¬Çä@†÷AƒBAj*Ç��×r�”=5¨’Ž¡ñ1giׇ~ù…t‹Š&zs‡µ·ΘI¬ ØŽ¬dùþÚy)²?ññá§îåh“{±sèÃÛ™2m:SZA©³Fj[‚ÚÕqf.!s×Vl>ŠÉÉaÉ;žÉ£�P(+)ëöJºƒžÐ0_dTªr²)u(•š“9äWš{H˜Œ¹9)€ì…_½m´:2 šë]4¤R“—×Ì}v€äNh¨72*†¼\ç ûIrò-€† Ð�nÞõEz£–O¹D’ˆ•š¬-$ï/m±Ù¬Te²~ÝA*¬F*Í\;ÒÚ•Ü õ©Íkò(kr“ Å;—±téRþ»ò5�k\Ð9†Pâ9è&òB¶ždgòvrÌO/¥¶ÿÑZ§‚ ½–޾=ÊS—G㪖³õ�ÇY’R^}j¢gÎc¤»„ýØw¼üåá&…°ùørž{ä1n»î6^Ûcir9p�óDªÙÎû¯¬&OÆÏž€£§¢Öƒ;ØiPq‰M"±ƒ­VÅx’ôUoðà+›¨P$<†ÏevÿÓcAtQ„k@©ØÁÚÝÕ ݶüÕ,ù4Åɼ|I£q S·—Rܨ¦Öü1 ƒgÍe˜^–õ#o¯ÌkT¡2sä»ÿ±¢PAöË%SBÎN�jÚÍ+³±K.ÄÍšÁ€V†ÆÈ}¦2/ÑIÉgåOiT×ÞËÀ³¦—°ý�7–� ~ýÊ–¿šÿ­8�†�IÝ’'-Å›s]gJé:?ð$Ï<óŸ46í„1%m_)ª¤%²oX©ðHø J¸ (eélÞ[LãǶòƒ¬[¹Š¿^ÆÖ‚¶U%YF–ÕHMMç V­ÕÞʯ[ŽaRÁ%dƒë­±#{ûà#ƒjÊåhAÃ’˜þ=eíAèMzZ>%0ü|F‡¹"©FŽoYÁòM‡(46*—T3¥Gw°bùzŽ4>C¸p\¿v¤Ë ìÈkÊÒÙ–QÞ ©®Te‘šQŽ‚–�È>­\COÔ¸ ‰÷×`/?ÀÚÍGéälºGQ“©ö±ƒÚp×”ö0™L(JǺÏÄ‚ ½™äŘ۞äo'þÎâ”|ÿô3D¼òš˜ :¼�Fµa5·¥0·tÌ'† £N°l[>Ç7-ãû¼Á ñÆE­¡,7‹Œìr,²Æ�í¦…P¡'êåù”6€Äi3!y5Û³«)<°�ï3¶áåï�¯»+²ÝHeI e&; ¡ŠcÒÔ1D�A ùÄpÁ¨l~ږljÍËùúx4ÑAH¦ŽgeSj}Xㇴ¡#Õ%”ÑÉÿ)•¬M$‡0+¦›v£:Ë, ¹¹Ž][‹‹š¨fÔVÇûœŽÉìì"##Ðë�nTÜ"ÑÁ!‚ÐÛéúrÙ¢G9z×B¾9¾‹7-¡Ïk÷31@´DÎ}œ÷¿àõ÷¿g}ÚÏ|�Zû9IÆ-(Žy7ÏçöËšŒÊ¨ã6b3Ãá“l•ÐÉ3Õ¸u«°cg.vM8£F´öT^ÅTQDAE½?I²V�‡_Æ1nò.›:ŒÀÆcËå¾\õØC=ÿ:?ì;ʺo�² Ù-ŒqW?Ç¢«õ|¾NÕ‚ÙR¯)¥ÎÕ·NeÛ¿çıÍüpLÂ5)Š›¯må˜ä€+ÿÉ;�ñêÒŸÙ¶úsü^f†NçÆ ¸zds[¢ž!¥ˆß—o£J‘ñ7‹Émé�ð?›IþXV’Âò5E̸<]ù o×ÞKÊö|šâx¿ìʨ+näÞùÓè_¿�«…¸i®ƒº0Î$FÞþ^|�·¿]ǾÕß±ç÷S‘ÝBHœ{ÿwË¥$x�Ýçøv‹©éåú4æzëÆÈø ™Âå»Ù²c?Çò2HÍ«;&¡óaÈÈQŒ� m!ž‘CHÓŸì ™T”�`hûø22‘6¯Œg3Uchô7IÖá¢÷! ˜È~Cˆ‚{ã/NòeøÄ ©^¿•ý¥Ý_ÊQ@ÒyÑ7~:“âµì9*ÕîÆÐÆ0·x?ü‡MçR÷]lIÍ ;s'3ëNªÁ#hI£Çß§¹­ªá�©×çS®A$μœ¾GÓÙ½ÿÇ +©*. êT°´xF1`Èp‡8É«ÚMCÀ°i\\›×ääbWNí¥t^DÄ�ä¼QðocÿŽ& ž©c ù~s'R’Ù4‡‘�çVS\UU,V+EEEh4jªÒñò�Úd ¸ º*d½­¾s5z‹ ‹ÅˆÕbÆÕÅFue>²FCQQ!!Á¸ºº"µso)ðæU$Ç7sâÕÿkñÍö¤‘4nBGïYá!mëb⓺;N(KsÉίÀ¨jñ '"Ô —ÖÊ�šü놇ù¡$Šùï¾Ë‚��Jsµ’cûŽRªøÐx4¾gý‘„BõÉlNVaÕyA€¾õ‹Ú«‹8QP î~„…øRÿ#-s°a(È&û¤‹¬Ç¿O$á~ú^úôÅFUA¹%ÕØ\ýˆè†o ‰ õ¸iþ:]gVªOæ“{²’»Œ›w áÁx´±îx`OÓƜ•�µLÅj¬¤¢Ê„U•qu÷ÆÇ˵Ëô*–j* fйãå©ïâDT,ÕTÌØ5®xûúàÞ†´æÖïGÁl¨ Â`Á.kq÷òÁÛíln…,g×Þ´”fë"Ÿj*›‰ªÊ*Œ´.xxùàÙ¡7Ú‘×TV[Q´z¼}½qëœÕÔ{•–Òg“ÉDnn[{šÜCß#KZ�j·‹åô„õÔ+êéÿH€ªs£&?Ø®}ï~“º>�s«ÛHAh�Œ›$ƒý#Ûñ…Ü_?cÕI÷‘—pQ'%ºäMôð¢;+˜­’ñŠ"&¨}ŸÒxÓo@û�9hñ íG̹° Z¼B£ÚÆ{i=nš¿N×Å™� ¾ ngšè~:7Ý|:ål²‹~þ�r®ö“pñð%¨�—o)Ì­ß�Œ«§Áží»¦ íÑ3ó)I«ÇÛ_�w'„©u޼&Hä5­rqq!<¼s®z“éY¬–¦ë»µDçâ‚^›..[´^tp‚ ÍP©>ð O¿¿£Ü‡«®ŸNhï² ‚ ‚ œe²,£×ëquu|ë�Ôh›ºé(í�–RŸèàAPжñù»È/Lgãút ¬. ¼ò~n‰+ö ‚ ‚ -ëŒŽŠŽ‚ BjÙ>~úâKŽÚ xžͽ%-STAAAAèõD‡ ‚ ‚ ‚ ½žèàAAA¡×‚ ‚ ‚ ‚ ôz¢ƒCAAA„^Oì¢"‚ ‚Ð�TUíî ‚ð!IR‡>'ò©?¦Ž¦—î$:8AAºX]c¡~£A4 A8[ꪪªžúwk�W‘Oýqu$½ô¢ƒCA¡ ©ªŠªªª*(+>‰ÉhDQìÝ,AÎq²¬AïæŽ_`ž^Þ@ó�V‘O íI/=‰èàAAè"u�†â¢| •„EôÅÇ7�VTÉA8»ì6å%äeŸÀd¬&08 hÚhù”mO/=�H¥‚ ‚ ]àÔÑÊr • ŽM@UU,V XÌݵ‡NOIù”´)½ôD¢ƒCA¡‹¨ªJYI ¡áQØlV1Ÿ]„®£ªØI’ �âdA>^ÞNGpˆ|JhkzéiÄ6±‚ ‚ ]@UUEÁd¬ÁÝÝ]4A說âæî�ÙX�¢(Mù”P_Ké¥'‚ ‚ gYýÝÅŽÚ߀ ‚pn“$ {½ÆjÝÔ”º‹|J¨ÏYzé©ÄAA„®¦*ÝAþÀÚÔ@ù”P«'wh4&:8AAºX/ª+ ‚ð%ò)¡7STAAº@oz&ÂGã58¡%==�ˆAAAAz=1EEA¡Ëõì'`‚ "ŸÎ&EQ8|䇮ݎ‚‚�Ÿ¯o‡Ï+:8A„³ÀBeq%fI�O€'.ÝÁÁREq¥ U㎟ŸÇ¹S è�÷u®·,UWšQ5n½ç;¡¡îʧDþÑ GÝÊ„Œ‡�?ºîÏ™Y¿a†JF$ŒÀÇ×T8˜q�e?ÿH¿¨(.¼`R‡Î+Ò‹ BO¥Ö�Ÿ•C¹MÂ3l‘ÞÍÏ*´•ç�YX�‚ŸðþôñìÞˆÊñ¯¸ûæ¥d ¹�Ï_¿’©î^×–$dYƒ‹›7Áx»ˆ™“N©ÎãOBFã¢ÇË7ˆ ?=šVNcÙò2z"køU¼ûáÿ1ì©ôÆûjw»A­¡ +—2»“ß�¤ÁÅÝ›€ ÿ󲤼Î_žXƒ©Ï•¼ýÁâÎô;ée÷/ç‚Îʧ$d4:×¶—U[_åÏO%cí¬üã\aIá?7<Íoæ0þòʹ»GÌ‘Ì#äæçpÑE—¢¢*®®nŒ;ž„„~ûmë7­ãÂó'¶ûܽ7VAÎu¶½,ýûc,¯Ôrþ#ß°x–'Îv¤·å¯æ™{_`U�BÀø{xí©�]Ô†N¦¦rÔ®!"ia2`­»—æ·œ“4î„ˬ˯åÚ©ýðpv³ QÍIrJüÂBðÒ¶ýX�ak%þ$¯0†&�gúœK˜;&wgñ'ÉheE–‘:1~»]¯¼¯v6lûøà¾EüÔÊo(dÈf^þW®�í< tYväW’ŒÔ��»ùþ•šbrK|Â�ä!̈́ޭ“ó©Ú²jȈ±L›}sG‡ãæìwªÑ:òt­Yê¹Ãݺþ·/#;2VdÙÑ)Ð[Χ{l”Ê<çW¡êé@“¾¥Šœ#yT©z‚¢£tU©.È$»$�-6TÕDaV*5¸úGlÏ#Çé±Hú¹5h<Ù*N°gO'Š*1I®ø÷%fx Ñ>MãG5äq(· ÜCéƒF5Q°?�´#W|û &iÄ ;y¤�Öw“®{œÑc¾âáÞc{ö ž}y8Ÿ<5�@¹aØT¢¢ƒpÃHѱlJ,nÁQDû5(µšüÌ\ÊíÎ׃iSÚª;UU‡òNÇ�­`w¡Âm“§ÄàWñª¥”¬ýÉ,(¥Æ"ãêHßA± ÷l2»É}9yjßӾÎÔKë>£Ú-˜Í¦¦SÖ´á̹ã*~Y¿„Tk&û3m¨aΩ`,:¾ÇÈ-­Á¦ÑãElüú¸·Ü!`-?ÎÞ½‡È.©ÆæâKß¡ñ$ô÷o²�pkõp{EníºAz‚¢ûІ¸<ÓûW*ó8R`@u º™<$73Ÿ*Õ•À¨Ú<¤0‹œ’ýl=dCU�dâ@…—Ú<$×é±Húê›ä!{÷âÄÉ*Ì’+>A‘ 6”(§é/ŸÃyUà€Gú+<°‹�™ù=¾aƒHLØéyˆ 4vVò)×pοæ F�‹á�{ß"%ûWžuÿ{|Z½²ÊñPuþDE¢ÇDѱlJ­nA}‰j¡¬*ÈÊs”U¡ý‰hRVqhï~2 Ë1*®ø†ôcXÂ`B›)«çNým…élJ=B…Û`ÆÄ¸`(mÛo¿=×<ý!9ûv±çx15ª;ÁÑÃ9¬ÍÄuo¦( v»‚Fã(Ùƒƒ0k°Ûí¸è\¨1Û}NÑÁ!‚Ð˨U{y÷‘'ùâ�ïÄ›yùÙ+êÞ”rv~ù2/~´‰c5J½QBv�dò�÷óà•Ãð‘l¤ò WWá1ù1¾}b2ÞN‹JÞrÝú6{”(n~û=n=µ›—�¬»8©j‰™€W;‡‡ËÞ¾øÈ £‘ëX¥zó,x~ ÊÀùð½ëиn`ÜÊ+w>Ï{?æ¿÷. ØÙýÁ}Ü÷kUí=áóGïäsd"¯ZÌ=Oð Óc¯ðùqŽÒ’Çš÷ÿÍ’ï÷Pdi´hšK #.½‹G\Hd½º–uÏGÜõè*Lñwòùýùå™gùpW)§×•p ÏÝÏ-âÏ�>äFÂcÈŸyâ®t®y~#å›>ã›Ã“¹mˆ£¸·¦¾Ï­õãÔØÙûá,Z[�çÔ'øþñ M*PJÖ7>{i nΡF©LBv�`òÍòÐ¥ƒ›Ní°±ñƒÅ¼ô]£x”t ¿„û¾‰ Cš«V6 ƒR²•Å÷=ËO9ý.yœWîŒlÓ]7<_{ï_¥zëÛÜöÂV”�×óß·®q’‡lãµ{^d£½7½ýóûÛÙûáƒ<°².Ÿ8Ìç ïásd"®|‘»+žâa§Ç^â“ÿ‹9•‡¬]ú2¯ý¸×Iú ñâÛyhþ"ê§¿}Ÿð·…¿a~;Ÿ,Œæ×ç^àãÝ�Ò_ÈXîüçcü©¿èåΦ³“OÙ­v´Ñ—óÔ={¹úŸë)ßü%ߙȭƒk˪�K¹ý©uXûü™·–ÞBœÆFú'óDr5žSãëÇ.p^VýŽGnÿ˜ÃÒ¼ó:7x×^_)g×W¯±øÓÍoRVE0éº{¹ïÏq ˪=rçk±ÅßÁÿn1ðìC³¿FE¹ˆÛ’ykU+¿ý\À–—ÌËO½ÆòL§²hIÆkàzld½Î“^>„ã UU±Ûí¸¸¸b±X±ÛmH²„Itp‚ œÛÔš|øØB>L7â=‹Ÿ»šØ–&™«Õ¤½óÿø2‹{f,¸š9#ú⣖‘µc¹�Õo=ÌIÛ^»f ®’'çÍ�HÐÚem[Eré$.h2™„Ü ë8`]Ì f¬÷<])dGZ.vM_F%ÑÞÁᦌ}²ªH®1$ >Ó"JË€9wñH¿>}w5Ç gÚü«ã£Ác@_Zš;^;Ü´”äÅ÷±hUªç .ºù*¦Å‡ãK'ö¬æ“OW‘öõ?ù›áI–>x«î)) IDAT¾µÑ$iuh%P ™|ùÏOYc9Ÿ[Ç� Œù»ùñ£¯ÙZ°…×Ïè7þBt§Ï � œt3—næ«üÖ­ÏbÁ�ÁÎW­—<7}<>ëVQ‘’ÌVæz6~“�#ÉëɲK¸ ›Æô¨ºGlíL[u—tqA'�ÅxœïÞ]E–÷p¦Mí‡�ûPüd•òu/sÿ«k(Õ÷åÂk.cÚ°|]mò3ظü~Ùù% ºòÎ[70´µ-òzíwØqæƒûȰªH®±$ nô­+y|ÿ켓Z�.âKfÍ» 9i_Ì’«œ.«\õ¸J`5çðÃû¿qÔ;�3úãë>„¸ñ‰,ÜÒo¿c×Ä’ÁÿžüË2­èûMåæù—0.ÒsáAÖ~õ!ÿzö­Äkw§—´�o³þ§'°Z-Í¿I÷� Oý�ÕbäÕ'†1ê¼Ë™vÙbdYÆjµ¢Ñh¨1Ö´; ¢ƒC¡·0á‹E�ñîîjÜã®eñs×1¼•U8m‡¾â?ßdaÖFqÕ³KøÛˆÓk7 6šóý›þÊÞ�ßgåŒç¸8HFŸ0›Y‘?óá‰�ü²¶€yW„5l (¹¬M>„ WFÍœBdý.åi¤±!%2ªo;jÝvÇwüÌ›K~"Ou'æê›™|¦µv™�„éÌ «æ×÷Ws?†M™Ãŧæä·t Ì»?ãµß Q4Ñ\ýìKÜ�à~*î†Ä%1n� 7?°Œœ•ïòù¥c¸½v”²„ سVñkÒ¼»äòz ¿Žfl˜�«ï_FÁáÍl)¼’è³±F‚Ë`F sçëüjr¦R|jêGc#§1Ñÿw~(ÙΚí¦Ln´¾‡ý0¿'ŸÀ.¹2rú$ÂkƒÛ‘´€¬E(9kù=ü2^Yz ñ§Ò±�•¿o¡TÑ2ôÚ§yþš¾õÒÞX&OCÐíç‹“)l̼–¡C[Þl°G‡žÛN3s> œHý…·_û‰<ÕƒØkoaf€Üà}öŒ_ùv—E3€ëÿù4·ôEQQ̰¤ÑDYnäî Iþq#·�ŸGÝWfÙÿ ¯¯ÌÇæË/¿Ä Q2vEi$\0·ùÿàËÜ•¼ÿó%Œ¼*²içA]x-Çøæ™§ùø�…�Éóê}ãñµ¶±s£î¿Õs49.;‰ÙÁ•¬xgÇðgØÄéÌ “Qí6©ùcvEżçKÞü½EÓ�k_x…»bu(Š‚ŠD¿A‰ŒìÊ�÷~OöªÿòåE£ø¿ºN] GúË\Ū‘w³ôµËˆ”ì(ª ñIŒ 5pսߓ$…m…W%7<§É’Ì®½{IÛ¹»Å÷�LJddÒˆÎ}¨ßÙùTã·K9܃/ó äΤRÔ´¬RUEŸ8�I«ø®x;É©&]ظ¬:ÂÚõ޲jÔŒ ©½¶íз,ùö(fm4ý×kÜïŠbWP‰dÀ�‘ŒìÆõ¯`ß§°jÚÓ\T7OF:]V­ÿo~´€an*ªjÇn5´ùß~Ç®©R¹ñ¾É²€Çhþ¾x!—ر+@TâG'ø÷[yµFåT&ë$~»5½›Vþ“{ŸøzÏp¨ÿ © ¢"Qt²œO¾=N~~>f‹Yã w=ÂG¯.bÄ„ûÑj5X¬@Åjµ¢ª*R;¶H‚ ½€j>ÆwO?Åk©å(²/£.»ˆá­Îÿ°²oÕoµ�ÛyWqCbã…)%|Ç_Å¥ƒ~çíC»X¹±˜y—#k1gö`>{ç {W®æøå×Ò¯^ýYÉ^ÏšÃ6pËÜI GiÔìNeŸEÂ'qC�–0Vv¼~¿W¿Ð³QSUI�UÆ»ßX®yìFnš6€öm ÖÙ,ìZ½Ž|EÂeÄ¥\=ܽIÜy%]μA+x+#—äuG¸uÈУ$T)”¹7Ìk²«�[l"q®Ë)0Ÿ$¯P�³²¤Ž�Ð@d (¥%”ª4ÛÁ�>ž“‚YöM!ÛÖmÇ0irƒ©E¶ƒÉ¬Í±#¹�eÖĺﻃiËq PŒ0òš«vÒ)5TVÙP‘Ðj�$ סÜúþ n“Ûg=û;T;\«´²ý�[¸¼þo;ÕU•­2ÞýÇsýãó¹iJ8kÃ)>Rÿ+yéÓ(«ÐÑ'ŠÅZï v‰˜Ñq¸ýX€1ûÙŠZ;Þʾµëɱƒû—qI¸ s½Ï¡�áOó¯Â¶WÁ7ĆWê×™­Õ^Èoÿ^Äë©•ø�û;¯>6… ÅÚ�Ý:zÿj£·ö Ô¾ÇnE±×½WE±[°Zë¾o¥…cv¯]ïH#/çªÁký·á2ìR.¼œ7æ²~c&ó;FZ�šT#…2ï¦Ù„ÙMXê}NOœë䛋È/²£†ž3[åN$%& ÕéxoéÿHMÛéô=#“F°à曈�‹95Ô¿3t<ŸªûtkŸ— D¦ ¥¬ŒRUÅWr’ª6–铃ùá«BRÖï jÂĆeUÆ’³íHîã™=Á§ösVöý¾ÚQV]p5×Åj°ÔËøìvn£®ä²Á«x3c7¿m.fÎÅŽrN•TGYU#1úº«¤1b2Ÿ¾^ó¿ýŽ^ÓÌ®miT«îcç0Õ׌¥n¡Uì„pñç±tÏjªh>ëÎô`5›põαãÙ=–Oü°þx×öuHH@HˆÓ'BzÆ4’Ž9ÓÕ?_<=Ü V«“É„$Iíîà]¾‚ =ž�ôñÒ–2<ü|qUËYÿòS|”ÑʼD¥ˆ}ŠQÐ?¬ÉÈüý‹x÷A~xé~~|Õ“>Câ™4ŠñãÏc|l0ú¶<Èééßa‡‡~ëÿ7¼<׫ÑoȆ¡ð0ÛV}Æ›ÿû…×ÞÊ®{þÍÓsêÿ†T”êl¶ý²œŸ7ïæÀ±þø×�®…)@Ý–^j™«v"«[pu‹Áf7b4Ál,Çd4`2Wc2Vc6Uc20™jpu±Ýªêˆ7Y–(.+ÆÇÇ‹;vÀŒÙíº¾Á!‚Ðãi‰�¿„×ï8Ÿ>n}˜÷è"þ2À¥`-Ï-ú�=5Í”pjÝtÇ0k«Õâô¥ºÞ‡p-§Š;É‹óçL$PV(J^ÉŽÚ5žìYëYsÌŽ&| óâ>«U²ÓØQ  é—ħ�Ë[ éð �aÊ5‹xåž±xª%l|û]V—wWÍÝŠµvàŠN§m¦³4:GÓIµÙhú µ‡�+%df•¡ ãqjë½fiú3}ê@´Ô°=yÛ©'Éæ}kY_¤ O`ÖÈz{þžIÚª%i]Ð:‰"É#Ž›_ZÊÒ…7sɘøkjÈKß̲�_å‘;¯á’ÿ⛆6Ô»{ùwØÕVC�ÁÐðUmBãÍ„¿<Îÿ�—Zʦ÷?`m½ß�Z±“×cÞüžä•øÅ\ÀEºŠ¯¿ž[n¾™s†6í SmÔͬÐh4íŽ5¯}ºƒªe½½†¢3¬Wwôþ»– kí}ê´ÍÇ[ýôgsTÑy!Ô:ýdþ&F&�hØXí…#7PJɪ-«ÜÃ#œ�´k ’©Ó¡¥šíëwœ.«Ò7°¡HA™ÈìDÝéŸ�j«-TTÅŠÕfsúÂ=ˆˆðp"|\šüä$­®}Z:zMÕzjJŠFÛL™%5Þa®yÝž^Tû©—¤ÚPU‹ã¥XP3JÝËnB±›|t̨ѤïÙËÑ£G5rt»/-Fp‚ ôx2¾��§¦|Hž Üñô�¿k ›2>åÑçÂxç©Y„7^oQÒãá”ê~Ó«¼rI@»'ú³˜±‚�r6ñË6çMvãpò:Ž+ZLŸNLƒ,ŠÒÒ8f— 1‚ö¬/Úø^ƒÏŸÀ°—·²Å°‹ílÌßÚVuAP:<ä½ I�¾¶=o6šQi¼Æ€ŠÙhB$½cµõžB)ÚÌÚ6�\‰Óìt¡Ód¢&O!öÃCìM]Ï–Ê©Ìò1³kõ&N*"&Ï ¡þIÎ0mµJãËÐi×òÈ´kQÍ¥dîM%%e3¿­ÚÌÁëxé� tï=Ë%-­}Ñã¿ÃÎ_½OUlØ,6¼ÇL`¸v3› »IͰ2}¬°°ç³Wùúˆ9l&O¿ö 3C5ŽÅBq<î´ì8É·¿ÄTÿz’+zWÇÿM&ÜÛõtLU¼®ç©ù^|øè›¤&¿ÎóÃúóÂEí�u¦÷߆GË ò�ú×héÚÍ=jvÅ­¶Ød2£âlT›‚©^úÓ;æÑZ:iÃJŽÂ9Ãn·;d nº€øØ¡Øí¶V>u&:?ŸªO9¹•ä6�ô$ŒŒÎéûþ-bâTâ>È`ÏÎ�¤TNdº�…Ýë6sRÑ9uqr½š€¤ÇÝ @Güü·xý²VÊ*»“Éê,wi%\õû¼¦¢Ãµ¶ºc1[Pqkò9ÕXƒQ©Ÿ/µ¿]Ÿ^êœYž4,n8Ãâ†wøób‡ B/¤�˜Ë“�_Î�JñÆWyø�]T5.O4¡Dk‘°‘ŸWØä zëœYƒÐ©¶®ÝN•õkÖå èb˜3=ªa¢HK=„Uòcä¨η$m7+FS]EEB’‹S©v;vgm“Šr*:«‡C!ç3ï|Ÿ6u>Èa™9ÌŒ©¬M©B5íæ÷Íe(š(fLܰ1z¦i«$WŽšÎ_ïx‚¥=ÏQZÔªT¾_�Ór‡VÿÕ¼ÚúyÅV·¸¦“µv�>û RÒŠPÐ2üÊ™èg¡ÆhÄl6a6›1[LçæQ­6:¿Lx¨°“ŸãˆÇ¦×³`¶©NÃ+‡\̳‹o`dÜ%<ù·  ’íï-æãC–®½$¨—‡ØÔ¦Ÿ³W–S®8¿FK×uzL¡OèéôgsúY{½ôJ Ü¶ëµ'.ÄëÜ{Ùív†ÇÅ2<.›Ý~FçjÍ™ž³Å÷ªUlýì[GYå{sÇ{6øL³ç º€™ñ.P³“u;ªPÌ{Y³¥ EÍÌ©ý¾_LD¨£¬ÊË>FUµ�š–^&ÇÚ@�ÃÐÚ½ª�qMÙ—@?°S\\ì4¯µæ�go=\Ý•^NëŠN”æõ”ê˜ ‚Ð.^I xþî1øI&ý4�ÿx¢áâX’ ‰QhPÈKÙF–ÓòF¡øÀ6våœ4eúΘE’ªw$³~ûZÖæ*¸�˜ÉôÆOÎM{IÙk÷ጎk}¼@óTÊ·oe¿ �ÈŠ<ݬֹ¹¢‘@-/£¬I`Jv¦’ÙJK»¥ºÁ19�„á}РP�šÊqgçµ$eO ª¤ch|L7ïúRK5’ñõ³üó—É�„k®cB«»íÔ’ƒ˜4-7L¤nÚIéî�l.WÑ �ÎÌ~�º¬Î8m5Ã\Bæ® ¬Ø|““Ã’w<“G ¡PVRÖJGÿϤvÙr«�òÔm¤Û¹ÑáÇß5Õ* áçãŽÒ¸öl=ÁÊ_ö:­ÿ’|áˆÇ´]kÒR·sø“{˜9g3[IiãÖ�Ö­ÕŒÝfÃwÊ}<6; Ù”ÁÇ/ü—ÔJµëî_­—‡”•QÑä>Jw¥�ÎCš¹¶ÚB¸“ü‰�¯M»8ᬇÒÁŽ=Õ¨’Ž˜ø\[mÙ9‰‹VãC¼ÎÅ—Ýfw¬¡p¦çjÍ™œ³¥÷(F}÷"/üZˆ"¹“xݵœ§oëyü¸pZnIÛº‡Ò=[ØZ®¢‹™ÁôðÆçð!>!º¶¬ÚÎQ«³ó)”ÜΞƒãታ¸iå^Õ覀~žÈ(äì;ä¨ç4úLvZÙÍåQ=!½œŠ�NOÛ!¢ƒC¡×ÒÑ÷¢Gyêòh\Õr¶¾ñ8KRÊë•A2Ñ3ç1Ò]Â~ì;^þò05�Î`>¾œçyŒÛ®»�×öXhLœÄEã<‘j¶óþ+«ÉÅ“ñ³'œ^䪖õàvT\b“Hì`+Q1ž$}Õ<øÊ&* �ás™ÝÿtÃZE¸”ЬÝ]Ý ¬µå¯fɧé(š¦�yI£q¬õ`/¥¸Tiã1 ƒgÍe˜^–õ#o¯Ìkô<ÂÌ‘ïþÇŠBÙk,—L éÞÕf {ׯ¼õèþïÍJUaSÿÁWômÇh ÿ ¦1Újvmä“5Û(S]H˜>‰ð&7wæiË¥t‹x’gžy‰O›Ö§ÌGIÛWŠ*i‰ìÖJœ÷²ï°(¦böÿþ�½^ûJ˜Ç¬èÚ "62vï§ÁL¶“l~ûß|[„� ª©œrS]ìKô›6—áz ûÑe¼ós6æú-Hæ“•ÙØq%þ‚1η#®=•jseì]�ò×þ:lÙ?ñ¯76RÒ‰õàïÐö‰"¢6IÞÛ()XËkŸ7—‡h[ÈCš;&1`ÆE ×Kز–óþïù�ÒŸ…Ì>á×BÙ{—Nêäi^‚ÐÙ äìù�wŸ¸‹;ßÙA©ª£ÏôxêÒжïR‚Š÷¸iŒõ€êÝ[øb] eª ‰3&Ò佑Ó/f”‡„ýؼöM&�÷Ÿ³œø™’»æÿ�7÷µ}稜~û»¦–ø Æâ#«XvÿÈ{®5eÉ]Å{ße¢´q Ž®¦ª*f³UUQO�ƒi?“É„¢œYÁ ÖàAèÍ$/ÆÜö$;ñw§œàû§Ÿ!â•ç¹z€c…:›ûïJáöÅ›ÙùÞß¹.u 3Æô#@kædVkÖ¦‘mÔ9÷®îdä…äÍùs&°î' Lȳ™;¶ÑîØÉܱ‹bECì¨$ç œS¬¤¾y —}ÐðMŠ¥†Ê &» ’ŒÇ ‹yü±K‰¬×┣'1sÈI/`Ù“÷P6s±�:Œ…X¿: ×KndæªwYV¢6xx y÷%ÊO&¥°€^|’êQ!à3†Û®‹oKÇ"/æÁù[¸ã­�l\| Rg3uxž¶R2S×°bë j4!LùÛíÌhÜãsÖ8‰?»…ªŠ j,Šã!�.�ÑWÝÇ›ÆÒÞµ^}Æ2k¼V¯ç›Õ6TýXfN vÚð?ã´åôœ3¹åÒåüãëtþ{ÏͤL8Ÿ1ÃðÖ)Ô”f³gãZ¶ž°¡‹¼”릵Ú!!÷Èï°N{+uï·²ãíÛ¹ò�CF*+ ˜kCžƒ/ãÉ…óÃæé"3qæ–¦o'ù ÜkœÃ”�˜KޱsãFv[ÿŸ½û޳£®÷?þš9}ÏöÞÓ{OH%Ô‚€¢ÈŠ¢þT°×+"* "W¸z¥J'@BHƒôÞ7e{¯§ÏüþØMØlIv“M¶äý|<|ÏÌœùœ³gæûý~æ[ðã_Îá•ÛîaI`=O>ú4±Yã™»piÙ—sççVòÅß¾Çêß}•›W.dþø4µ{X±ô]ö5Bò¬Ïòå¤béWÓñlë¿1ç8nþþ§Ùð…GØøÖƒÜ3y$÷\‘ÛƒDÜI~~À,<—KÇ?Á®Íe<ÿÓ;¨¹hÒ\*¶³ì­ ø®þ,—½òÏTÙØÖû�,�„|†§š¬.+åÙ_ßEÓŒ,HœÅÍÿ5›äcm˾Œo~n9·ýv ïÜÿ5¾°îb.˜”ƒ?ZþuKxiõAŽl.úê¸0¡»åœ»z±«ÇÛ"§BÞ§bašÚ•UÌù¯oðÃOO'1ÒÕ¼LjÁ?“ÌOdÉëoóÔQlß|.]˜Òõ¾éqç—WñùŸ/cýŸîà3ëÎ碳†‘ê Sµo=o-YÏ¡ ‹Â+¿Ìg¦:éúBìüÚ1ï 'xNïœëùÌ´w¸Ý~žüÞ—ÙsÁB¦çz –mç�¥ëÌ»†‹7ý‹W*­£îQA8¦´´Û¶ÁŽ€Æ& v¨-áq|–eqèÐ!FzñùN¼O¥""ƒ�«�«¿ÿöÝþ=þµ=ÿóýûÉý휗fN .ÿ�¦ÿ�}š¥k_àOkÚŽ3L|“¸â¦ÏrÛ5Ó:õÊ8Ì7ãR>�÷9h“}Á8+®ÃVï­+&æÈã¬Ç{ n¬¯ ¬¾ÝK†�éôâOÉgÔèIÌ»àƒ\½h2éç5 ¹î»ß¤âgòÌæ},ù÷>–``úr˜wýÝ|ÿz/O,1À ·+ô]S¸þÖE¬úåë(ZÎ3Ež™Ã¸éÆãl3ÜŒúØ]ü!ý1øã ¬ZüÛ^?³›´ñóé[náúYÝ-Az*tþþ Ó‰Û—BÁ¨ÑL�u6—\¾ˆÙ¹�''ë™xæ^´€ä7^¦&b’°ðbÎKîî�Nþ·Õ‰ágÖm¿â¾ôGøý¿—°yñSl|ýÈFL_Ó/ÿ Ÿ»ù*¦õhèÍ@ü¶:ñj©M°¾’`×P|jcÆLfþ¢+ùÈ¢q$D‚G­Ì‘õÁoqwÅÝÜý�µl}õol} ÓGöÌk¸ç;Ÿf^b�¬¦±éOØùңܻá#üfÁR-›Â«ïâ‘ôǸÿáçY¹æþþ´þM²™ý±›ùúÍç‘K¸ÛôÆ‘ÿoG!ÿZ~tû&nºw«ù%÷s>9¦§CÛNüóC×~ÿ»Tüô7<µ©ˆ·Ÿ)âí¶{Èü~Á¯sð—·Zï!‡çîÀ9‰�þbVÞó*ŠVñ\Û}âS6ØÇÚfAþÕ?åÑôǸÿ‘çYñæ“lãpÌnÒ'\ÊÍŸÿ×Mñ�=½éÑŸ¸«oáØÛEúB_Þ§ Ó‰;.•‚Ñc˜6û\.ûÐ"f¥C(éÔü=n ÏörÖEg“²øEª#&‰ç\ÄÙñv×ñZ™—ü€?eü“þð/ÞZÿ2�­;¾Œ)\ù¹[øâ‡Ç‰¶KÇvpìû‰žÓÎæ#wýë×÷òÇ·ö±æå'Y®d&\ö ~~[/Ýöo Ã=jG"TVVb:œ4Õm 5{†+Ó â² ÀÙŒéiÄjÄåkÄ ‡ƒ¸œQ¡Z‘•Õä„ðz½ƉÕdŒô›~acÕõÒ IDAT´æÍ<ð¹cî¼mãZfÎ;ç„N$"r¦X»òm&L�ÙßatÁ"PSÌÁÒz¶“„´<ò³p¯ühy�{>õ-ž©Æg~˜[FwxÖj7P´y5V#§ 'ù”·-š+r ¼‘ˆ+‘¼aù¤y�ÒXsÊš!.…œ¬dÚr¬m­¢4•ä`eaÓKjny)ÞA?¤¡ïœàoë˜"4W–R\Ù@KÌÄ—˜N~^&þ~4Ó¿CÛ¶±,‹X,Æží›9vb/ßÁ‰7ÁßåÒºmgÀ¶,l+F4&‰uQù5qz|¸¢5ìß_N£å!%·�üDƒp0HÔ2pxâpÅ© yHNti¶Í¡b`ºÒr ÈMr …G;4ïœ>üqn ;L 1ÐÅ6N<ñ~\¦E´¥‘`ÿÎç'ƒØÞ�[5~2‡Ól½žºû” ¶�eŰ¢Q"‘HÛ*N]pÅïsu{ÿ0œ>ââÜ­GZh «˜Nn�“H] JëØ.Òó(ȌÌ„…£GÜëðx×þ œÀpàöú ¥œýÅÕ´à'³°€,w”`(†ÓïÇmÚDZ �æk¿ãï¥}" QZZÊÊ7Í�Í�cb€a™�ãý$N‡’ `ÛY#.fþ¥?£°  ×=8 ¿ô;ç4”àéc7Áq",ŠŸºƒO<°f}…¿ýòCd«U/Òk�ú/Ãl­œ¶%¬Žƒß¯6ÒÍ xÃt´­jdaŬõ±§ Ó�i€…eY=ÿo˜Gޱ­OO�µ­Ó9»ùÞEN³½;·'ÁÑ�÷©SÄ0LŒÃ÷?ÛÂê.ÉÒã7ìÁµ"ç<ê>ëfÛéÕñ÷Ò>ÁaÛ6áp˜@ @0ØB$êż*àt¹ðùüx½^<Ï‘ßcOµOphˆŠˆˆtæyÛ_øïG70s¹î“+¹!2Ø­‰‰î·»ë³muÓ;b±­Xï—7¶»›'ã8ÛNæœ"Ò§lÛÂ>Öý¯×o؃kÿDÎy¼ûôc�·ÛMRRR· òcßþß“¡‡ˆˆŪXÅϬ§´| Ë–n¡,âfôÇîàæ©b!T‘!a°'DdèÓ}Jz«/'J 9Š]»™ÿüý싵N¾wö _åÛŸ˜FüÀ\™LdpRËAD:ݧdR‚CDDŽâs>~1 17©Y™$y4.E¤ï©å "�îS2ø(Á!""G3½¤å’Ößqˆˆˆˆˆô‚ˉˆˆˆœý9&YD¤;íïMºOÉñ ô߈zpˆˆˆˆœF¦é ‹õz<‘¾bYÖ1ïAºOI{Çû½ $ƒ#J‘!Âë‹#ØÒÜßaˆÈ,hÆëów»]÷)iïx¿—�D ‘S¬ýÒy‰)©ÔÖTaYV?G%"g"˲¨©ª"1%õ¨{“îSÒ•î~/•""""§�a˜¦Iœ?_|;·n¢¾¶†X,Úß¡‰È ‹R_[Ãέ›ˆKH Î�iš�æàÐ}J g¿—�Hspˆˆˆˆœ&‡iéY¸]nª*J8¸V,Öß¡‰Èg:Ä'$�?l I)Ý6VuŸèùïe Q‚CDDDä48\1t8$&§Ÿ˜ŒmÛGþék퇘¦‰iš8Ž£†¦´ßO÷©3[O/‘""""§IûƃišX–¥ƒˆœ6‡¬‡ªÝõàݧ¤g¿—�F ‘Ó¨«Iý@OFEäÔ骗Ʊ«ºO�Ùzû{H”à9ÍÚW7KåQD¯ÞÜgtŸ’Áø÷V‚CDDD¤ Æ ¤ˆœYtŸ’ÁBËÄŠˆˆˆˆˆˆÈ §‡ˆˆˆˆˆˆˆ zJpˆˆˆˆˆˆˆÈ §98DDDDDD¤O45ÔQSYA À²býŽœ ÓtàóÅ‘š‘I|bR‡ÓcJpˆˆˆˆˆˆÈI«*/¥®¦šÜ‚Bü I8ŽþINP,£¹±žÒâCÒ³²û;¤Q‚CDDDDDDNJSC=µ5ÕŒ™0§SÍÌÁÎáp�˜œJ\|"»¶mÆëó ŠžšƒCDDDDDDNJMe9y…Jn 1N§“ÜüBj*+ú;”Q‚CDDDDDDNJ  >aà?á—Þ‹OL"hîï0zD 9)–ÃÔœC’Ãá fYýF�(Á!"""""""ƒž"""""""2è)Á!"""""""ƒž"""""""2è)Á!"""""""ƒž)êÂMT7° Iiñ¸û;‘S%¢%Å6\ø|î^<Ñ�l ÃÀåõáîË®V„PØÂt{p™'ãàdY6m`ÿþ"êêëˆEc¤¤¥’›�ËÌé³p»]}v.%8DD“pû¶og÷¡ j›£˜ž8’3ó=~,Ó»N]D6>Ì'ïüµIWpß“_cnß•!C—ÝBéÞCÔE âsFQ�x쪇ÝTÊ®âbFù£sIê5‘>f‡©(¯ ¶1H'Þød2³2Hòô®P�XÎßï%–8•«®�MVO�dÙ“‹ÙMdÚa~�<†h Û–/ãÝ=•´Ä÷(.»á|òO4ÆA¨ººŠ_~¯ÏG^A.#GÇ4M›š(+-åñ¿=Æe—\FnnnŸœO ‘AÀªßÆó�ý‰¿¼¸–C-v‡í†ÃOÁ¬KùÄÍŸäòq CþIÀ)ÝÄÿßwy¾ÁÉÙßþ÷^�qŒÝ#ëþÈmß_L³ë~òÜ�¹ØwÚ"=ŠÕRÉ¡j‹”œ,T‹ˆÈ``µphÃrÞÞx€úH‡ŽÓOþÄùœwÖ°ž?<0 LÓÀî÷Ê�Míæ·Y¶³Š˜é%½ �do:^c ÅxjY–ÅK¯¾Lþ°²²2)-.á@Ѭ˜Ezf:£F�$3+“_~�OÞøé>éÉ¡ê�ˆÈ€fÓ¼ó)~ð�‡Y^Á6<¤�žÎ¼é£ÈI‰ÃªåÐÎ ¬X»‡«ÿÍÝë—³ò«?ã,ÄÓß¡ËicÏ߿ŧÿæçK�ßÏÇs†x­IDD†€V¾Ä+[눙^2G�gtN^;H]é¶í­âÐÆ7øOô®Y�×£º�cøùÜtÓù§8îžRZZK ƒ„ñrÕ‚œ÷ß&ÆSkÓæM¸].òòòXµb%é™Ìž5§ËMQÑ>Þ]ý. Î'5=•uë×2wÎÜ“>§""˜Uþ:w}û!–WÙ˜é³ùì·¾Æ ³³:𡲕üùž_òëKy㾑•÷?|yZ?u#�þa7°m[1cû;‘‰Uldùö:b†ŸÑç_É…#ýï÷B?‘±™¯ðÔÊêw¬gçÔ\¦Ä«?åcGGlÀ$)9éŒlx,>@^A.EûŠÈHÏâÒK.=²mXA!‡É®]{ÈËË¥¬¤¸OÎy&~Ï""ƒƒ]Ç›¿ˆ%UFÒl¾úëŸpí°®çÙðdÏãÖŸÝ_þÚ¹Ÿgÿö&×Où íâ®ØAʶ®aíîrš,)yã˜9}4iÝÎ>jÑR¾‹M[÷QRÓBÄá%9k8“¦�'/®s/»©„�Å�—Íè‚$v�²­kY»»Œ&ËCrîXfÎCzwç³”ïÚÄæ}•4Ù~²ÇNcƨÜ„©Þ_DEÐArÁHrâ:Wr¬@9;6newYËMröH¦LGޝÿ{3Dë°qãT44<$e2aʆ'ußÓ×°wëvö”ÕÐ6ñ$¦S8f"ãóâq¼¿Íe{8X½…;¢Øv�ò½;ØÖàÀ“ZÀˆ ß1‡×ˆˆˆô‹êýh°À‘=™9#ü†Øš$��HáÚv‡ª)¯Š1%ÞyäØ`C �!0¼ ¤'´{ôj¤ª1ˆíˆ#9ÅO§RÖQ_VJY] aÛE|jyY‰=š„ÝŽ4QY^Nmcˆ0|ñ©de§“à:º¤ 7VSl¤9`i®¡¢²Ãô’˜–€§‹cÁzjÃØ¦—ÄÔ<]Þ‘æêZbàìæ³ 0Õ55 / ¬´”SguÚ>rÄhÞ\º˜ÆQWߨ'çT‚CDd€²J^çŸËê± /Óoü ×t“Ü8Â7�¿ñ ê X0c8IÛôN'Žúõ<úÓ»ø¿u5D� s5ðä,ä+w‡kFÝ7Ä®ßÄ_îýÿ·ì ÍVûq±f\Þüm¾}Í8üí áÈÆÇ¸ý;¯œúEžøáH^úÉOùóú£ÏçΞϗîþ>uôù¢%K¹ÿ¿ïã©íõ9�á!gÞ'ùñ7§ñöw¿ÂãÅ)|äWåΙíŠu«Žuÿ¸�_<öEGÍQÒ矾ƒo|l2IýÑÒ—ðÆ£¿äþ§7R>zl±áNgÆU·óí[Î¥ ýŸ×nfÛ3¿áîÿ}“Ý�±£ç\1žó/Èé>T;Hɦ弽¾ˆÚNey2#f,äÜ)Yx[# tÍ‹¼´;|dŸò ¯ðÔÀ5ŠÜx>…]ÄhZU¬}u {ƒn†-¼ŠKÇu˜ÿ+t�wž�íMNræ\Á)þc|·C %€×㦡±™Ô´ôNÛS’“hjlÆíõ6÷É9Uç�,ªß]ɶˆ�á›Á•—äôhâи1çpY7Û W5/ÝõcV„ÏæÖoÍg\†‹–âu<óøS¬.]Æoî}†™^ÇðÃ'²JxêÇßå¡5͸òæñ©ë/efa îp5»W<Íÿ=³‰×üÎŒGøá¹ÉG aÃéÂi€Ý´‡ÜõWޟͭߚǸ 7�Ò <ûØ“¬,[Áƒ÷>Íìÿùøûç oãÑïÝÍ¿÷DpçÌåº/gv¾—ƽ+ù÷ßþÌ7î>�‰Í6àÂílWäÛͬýÃ�|í{Ç�ä’[®çƒ3 I²kÙûÞ‹<þ�·Yüз¨ŒÞÏoo}zç&±kxëÞ¯óýW+°ãÇpåM×qÑÔ<’iäÀÆÅü寯²öÉ»øJÓ�øã7�lØÔ-¹�;xƒo!çÞp5MÎ'Ù¥©tËž†—Öýƒï}ÏÃúã]NF}ðv¾=b5}x1ûÉã¢Ï^Çœ$þQyšpVDD,Óå%>ÉK|w;„ê¨ Ø`&’–äèn¯ž‰U²fñR¶VÇp%�dÆÌñä':‰6WQ´eo½QCB—†)y÷e^ÜXMÌ�Ê賦2>7 �¤¶x'ë6ícïªWi±>È•ÓÒp`’6n>çg7q`ÃZö6¤Œ9‹©Yn GâѽkÛ1âF±ðìC”/ÞÍ�wW±»àBÆé­æÐ{+Ùٞܳ8or*]}Å¥¥”–”öèëÈÍÍ%7'»GûöÖòWîbå¿Á5ìÛ`C0ÐÌ#?™€ `´}$Û²±mˆûc,+Ư¿™ÁüE_eþ%ß9ás+Á!"2 ÅØ»kQç0¥Ëǽc•¼ÃÛÙ_à÷_ÈýfÍa^~�¾þ,%;ßaEùGÞ69elÇ üs}–c$7üøGÜ:æý3fÏ¡0r_}®‚7Ÿ^Ê~èýÛ40�ØÞWyyæx¸ýù˜ÍÜœ&®¿ã9Êv-gEùÇÚÎgS¿ô žÜßt¾xï]|,¿­èž~ç-ËwnûKkm0 Ú·Ú£;ÿɯþµ—�s×ýô~¾2ãý'ã'ÏfÁ˜_òéï½Ì¦Çå•KîæCÝÕ,N�І¿ñÛ×ʱùþ§¿æKÓâŽÄ6nÒLæ�qsÓ�Ïq蕇yâª9Ü6Î 4³êõÔXNÆßøßüì†Âvw.\<‡ŒÛþ¯\Ͳ=72~¼ƒ¬isEN3/?º˜ý¤0ùÂò!M2*""ƒZ˜’ ›)Ž‚3k cÒÚ—k.òg\È¥lŒ¸Ì%óƒE›Ø\wó>p>“ÚJäô ró³‰{éyVF ã¸N«j3Ë6W5“™zñY�óþ£’Œ¬| Ò—òï×vQ¶þ=v޾„ ~ƒøœÑŒÏ®'¸s{ ü™£™0þý¹ÑbÝÄ7|çŽ+ç•íûY±ªˆ¼ FDÊÖñÎŽloóΙ@ò1>pIY%¥ÇNräåäôÙ²¬]Yþê¯øÖÏá·,'fÛ˜†ƒ�}þ^â|nü~¦ÃAKKˆ–– O½X¶�Ãpð•üŒû~p§""COˆššf, \YÝfû{Ã6²¹ü3W¶K6´òMœÁïs”+))· ­alÿ¿xd!5 †�ê8ÊÓÇ´Ùñ=_Nàà>XtŠÑ6²¹üSWtq¾éLò5½ãr®Éó¯ãª1¯óû�ëyeYW\ݳŠÐá÷_}ÿ \ú?ÇI0E‚´tz1ÌúÅK(µ Ü3®âú)q�bK˜y WŒy‘‡vóÖ’ÝÜ:n<«…†Æ(6NgÅ´g<·>ú"Ÿ7•À‘¡Ê¢a×2o­Ãre0kþ„¶^އ™Ägvßó£“(eKî¼±ŒIèP®;R˜8©€ue{ uˆ£|×.j-pNeFNç~ ¾‚©LLÛÃêªRvhaüÿIÌ}åaØì…L,}…Í{W±jT.çç6°vùVjm#æ�ÍøŽ±·“—“3�µt›äÈÍÎfÖÌ™§¬÷@$ÁåO^N#o-^LjŠ�ììÜnN§Ã0ðzc$%Ùd¦7óúk‹ÉÎðãOšG$9þ ŽA ‘�ÈŽmKï;\®.»!ö–áÇÔ1]LGåð“à5 $Ôn\©áKeبT†—E,%‹2=¸ „B„ìNïŠáÔ±]ÌâL Ág@¨Ýù¬2ö…°q0büh:¯ÿbR8.Ãÿ¸�]V»—­ 6o«ÂÂÁð©Ý̱aæ1uR*æŽJvlÙMäêÌ^ S±‰©ôø€v±•±mG=&ù“'’ÚU>ÂÌaâ„$ÌÕ”îÚCƒ=ž3•I³ql8È–ÇïâÞ›ù¯ §Q˜ðþ¯ÀTrCDD†¬UÛ–ðòŠý4IŒ?w3ÓO²Ùj7R]L’ÒR»œœÓ•žAй—²öu»‰òÊlLR²3ÛæØèÀH$;Ó‡QÕLUy5ÖÿÉÕÛ<¹Ì9gÅ/mb犕$Ö²±ÆÆ?j>çŒ>~òäXIŽÜìlΚ5ë”&7³Iäºk¯%²ðz�XVÚÍ|bºZçLûä�ijï÷�ôy•àˆ q>›hs3!Ü'9JÅðø‰ë²Ä59Ü^î”§”°ò…gx~Ù:¶î+¦ª!DIJ;ÝÍù¼ñÄwYÊtq>«�Ú p’’–Üå{šÙä9Œ Žj*ªZ_(ú×÷¸á宣‰Ö×acªª¤¡‹Þ&Ýs3ÿοrÏ%]�Ê=òþïüœýøMŽš+VMeuëgJÏLïæ{r�ž–ŠI5VM5µ6¤N&Üø >»õû<ºa;Ïüúž} žÜqS™5ó,æÏ_Àü‰™xµ4Šˆˆ 5VE+óƶ*"® ¦]xóò;ö€<vˆ@°uÉVŸÏÛåû^>ƒ£+Cv ÍÍ­/Ôn~�îê:’X ˆ D›› Ú5ùú‰pgÏäü)%<·~7«·€™0–sç·Wé‰ÃIs�Á¡’àô&7"��Ø¡Åxâ&n¨'д—P ž`°‰`°™`°™P ™`¨‰` …8o„a#/:éó*Á!"2 9ÉÊNà˜èÁ}ì�ÁäÓ|Ƕë×ðÀ׿ÏßwÁ“Î¸é ˜“ŸF¢×�ÓéÄ([Éß_ÝA°ÛwèEén‡ µõHt:ºù N7ÞŽY;B¸m 6;!éæœqéäÅ�3ÉÙí¸×î˜Nn·û˜ŸÆpv•¾ˆ‰¶þ—Ëåìöx‡«õóÚÑ(‘¶J•áŸÄM¿þ# ÞüO¿²„eöQ²e9Å[–óÜ_þ‡¤Ñ‹¸åë·ó‘ ‡äˆˆˆ R¡ Ö½¹˜wµ`$ gáEç2)­¯B�k«Ýõ‚4MÌN…ªḚÁŽ‹uSêºý$ºÁôš��')yYø7TÓ`¸S²Iïå,éy998L–ÝÑY§xXJgØØ1°- ;Šm‡[ÿg…±­–Š…°bA¬ØÉ M9L ‘ÉÉÈÉã‰7‹i(}—åûnaò˜tx´Ô79HJèÉjîÇfÃã÷ñ�]!Ìœ‹øÁ¯îàyG¿gäÝjž~íX Ž^0ÜxÚÞ>CW«Ñ‡›iŒu¨6^üq@�‹)Ÿy€ß|8mà4ø /Þ¶¾¬¡@›®’6¡¶§>†×{ôš÷ŽdÆ_t#ß¾èFìP {6­aõêå¼öêr¶ïz•_ßY�둟òaM&*""ƒœ8ÄŠWÞ`cU_ö -šA¾¯/Kt'ζjT,ÖÍ£ŽH´Ý’öïçvY3¯äŠ �ÑžáRÞ}g; øðÇ…i>¸Š¥;³¹t\B¯ê9ÙY™Ìš9à4'7»oR=½¥Z‘ˆÈ7ó<$™ÛϳO,£ö¸å„MóúG¹å£7òùû^§èdá±"V®.ÇÂÉä�|†‹ó:&lÊJi髲ËL!=Ù,ª+ª±ºØ%ºo7EÑ/:²ÉÏtb¥´¤¼×½3N)3‹¼,¥´¤¬›Ø¢”•V¶N&›•ÓýÒqžTFŸu1ÿõ…òÇÇ~ƵÜØ�kxzñ¡.¿+‘A#\Áš×ÞdcU ÿ°\yéÌ>Nn†_\ëø“–æ–.ËN«±ž†Žõ3�ÄøÖúIccÓi*sC|w[êlÆ�Ã5O%Ý q`õ2¶4ô>‚¼œœÖ!+§]ÇJÛ顇ˆÈ@åŸË�׌ÁcXT¿ù[~òô¾cö–ˆ–¾Á=÷<ÇÁ@ ›Ü$ŸL=»…¦0HIíbNŒè~^xqa›.&î8f£Gø1‰Q´y+u�Þ3ÈÚ×—QÚ±\7R˜6},JV¯bo—e©EÕ¶U¬?Ôtz f:Ó¦äâÀ¢lÍöwuòðvVolÁ6\ŒŸ:¡urÕP5{ֿ͋˻þ{‰S¹à¬4 ,j«k»¬lõÏ3‘Þ ²囬©ˆàË›ÃåŽ'õTŒ10âIKqa`Q_^I SAiS_RB}§BÕKvN2&6�‡RÓe~Á¦¥ò¥ ¡>I€¬féöìø1,<«ÆTÎ�’†*aõÛ[¨$O6ì~z줇ˆÈ€åbôuwpËÔxL«†¿ý·ßÿ"›k:tͰšØûæ£|õöŸóz™…«àr¾û¥s:,§ÖKfÙ™&eçÆmG/�­`ÙƒwódC:‰&Ø¡zjƒ'Û¤ö0}áM›Ðš'ùóºÆv�ô(åoÿŽûÞh"ÎÙñC™ ÿÀÌŠ3ˆ=Å}ÿØÕi¹ÖÐþç¹ûÛßåóŸø<¿Ý>É8{ÃÁØK/g²× º÷Y~ÿJI‡g!v?õ¼Xna&ÌåÃfaVÍî½óGüä'¿æ/Û�“¡}¬Ý\ƒm8)(Ì9R�NˆÕPÕu LDDd@‰”¬eÙ®&ðcÁyIíñò#Q*w®aÕê÷xwO×Éþ£9É–�×€XÙ6”½l¬a'«6Wcwª;¤ŒOž¬Ú-,ßTEDzѺí,yåUž}ò9V–�d£>°�åïì¢?cÌa˜·5öÌég3-ÕA¸tom¬X=VÛ±,‹`°íñŒ}ôª)½ ±¬«Ëh‘�Ì3Šî¾îú ¯,góÓ÷rËs‘3j4éñ¸"uïÞEQmÛ0I5ßýñm,8©ì`æpÁ%ÓøÓÖ5”>w_ ~ˆ‹ÆÆªÚËÚ¥KXžÇî™Í«·ÿ’·ëøÇCÿÆš=�çM"ñOé_pŸ�¾’ûÖñÏoÞÄÆyó˜šå¤~ïÞ^`æ—?Éè‡âµK¶šÙ—qÇí«¹íÞå¬{äÿñ‰5rÉœ¤9CTî]Ëo®å`ÀEÁå_à“SNvn’Þ1 >Ä7>»‚/<´Že÷ÞÎ-k.cÑ”â£5ìYó/®<@‹#‹ ¿r—¤mŸçÜ|Õó|íÉ-üï—obõ9g3gt‰.‹–šƒl\ö&+Dq\Å'.Êx?Á‘XȰ“Õåe<ó‹Ñ|V$ÍáóŸ˜{rÉ.‘S"ľ-»i´�h)«žû'«Ž±·{ø9|d^nÛ¬1ª÷nbÝ¡®QéÌ•rܳ¹ ¦3#û +JëØøÊ³ÔŒAN¢“hc%EûŠ çOdTÙv·ØGMaÄ�eáÜC<»l?%ï¾È“Å#“Ÿ‚Ï£¥¦„Ý{‹iˆ8H?—éÙ'±@¬ÝÂîå+ØÝ þ1ó˜WØnVQg3ΞDÑ )_ÿ6kó®`vÆÀkʇÃaŠ‹[Wmi�\4DÁa7 õ~eåàÁCäãõv¹0ï1 ¼oEDDŽbÄOäÆŸ=Ê‚%Oñ×§_eéæJvn dgÛvÓCêØT�g6 IDAT³¹äÊë¸á²É¤÷É„ã&yú&?)ÿ÷ük=[^~Œ-/ƒaúÈžña~ú�Ïpnv”ìë_fóŸ7±ó…‡øùú�ò»sN<Á�£�kr/Þÿ}˜Ç_ÛÀö¥/°Ýô�:f.×ÿäV>1»ˆŸ=Üö™�j°;)¸ü<šþw|ôi–®}�?­iÛd˜ø2&qÅMŸå¶k¦‘zÚúnF}ì.þ�þüñV-~‚m¯ŽÍMÚø‹ùô-·pý¬vËÈ~fÝö+îK„ßÿ{ ›?ÅÆ×�lÄôe1ýòÏ𹛯bZB»äšÂõ·.bÕ/_ç@Ñrž)2ðÌÆM7Ò«mDDDN ;F$ÜÖ!¢©)tÌÝÝÁ“œÓÁLfê¢K°Þy‡uûk9´c#‡L/™crñœdv?·ˆ=ª-n’4îB®ño`Å{[)*ÙÁš’ÃÛ \þ,ÆÍ:‹¹³{¼Œkg6M»–óNQâF³pîp:NgêÊšÎ9“òŸMÕ¬_º–üÍ!§¯™é¶mŽD¨¨¨ÀápÐÒ¸…„ä‹À™†In†ƒ«ÓÛ„ÓÛ€;ÔŒ7$ ‡ð¸£47”b:TTT�••‰ÇãÁ0zW‰1Òoú…�Ñši:ðÀ玹ó¶�k™9ïœýÌ""g„µ+ßfÂÔ™§ìý­`%%åÔ6E0<ñ¤çæ‘�pêJ8+PÉþ¢ -7ɹ…¤xŽj/ÇuÔ…<$%ùè4‚äDÙ1‚Í-D]~â=mMÿ–׸óÃ?ãíØ>ûÈÃÜ2ª«§$�šb–Ö°�$¤å‘Ÿ�€{@4ð£4•ä`eaÓKjny)ÞãŒ�Ð\YJqe-1_b:ùy™ø�ñx"Ö\Á�²fˆK!'+¹óÒº"""§À¶�k™2sN‡Ñ#±`#u�"8‰OJ&ÞÝÓÂÒ&h ¾1HÄ6ñÄ%’”àá$úm ›Ö®>ný6 R\\ÂÊ×þ›â�OcÎÖ§RvkÆèpÇûHûý À¶)˜pg]ð�^õà(üÒï8œÓP‘AÆô&“?2™üÓu>_#&dt»ÝáK&­VM³ƒµØ€âú8&ÎCr|ÂQÛÃ;·³+ †7ŸaYÝU%L|©ŒM-8ù€úœ“øìLèÕ*m.ü…ŒíþëïÄáÏdÄ¨ÞÆ&""ræpxHó&ÇN \¾$Ò}I}ÓPàv»ÉËËåƒ×ÝG0øS"áÞÍ}ær»ñzãðù|¸Ý'6¬X bûþÅ7¾øŒ®¹çî˜�ô~O‘Àþù§×¨°Lâg�ÃlF*""""™¦‰×ëÅãñÉízjôÌáá(½–Òž""2 8Ç_Ë/YÂw^>ÈSß¹™íg/dÖ°dM%l\¾Œµ%AŒäÙÜö¹óICNDDDD¤£¾HTœ(%8DDd`0R8÷Îûùõ°GxäßËØòÖ³l± w cÏû(7Ýz=çå«è‘ÎTK‘�ÑΜë¿Íœë£4WUPÑW<é™é$ Œ™BEDDDd€R‚CDD 'þô\F¤÷w""""2Xhñ8ô”à‘“bšb±X‡!§@,ÃaŽÔÁàˆRDDDDDD,Ÿ/ŽæÆúþCN�æÆz¼>‡Ñ#JpˆˆˆˆˆˆÈIIÍȤ´ø±h´¿C‘>‹F)->Djff‡Ò#JpˆˆˆˆˆˆÈI‰OL")9•�Û6Q_[£á*ƒ\,¥¡®†Ý;¶’œ’J|BR‡Ô#ZEEDDDDDDNZzV6^Ÿ�êŠrŠ÷ï%fYý’œ ‡iâ�ó“•›7h’ ‡ˆˆˆˆˆˆô‘øÄ$âOƒX† Q‘AO ô”à‘AO ô”à‘AO ô”à‘AÏÙ߈ˆHg¥¥¥ý‚ˆˆˆˆH¿ËÉÉéñ¾Jpˆˆ @½¹‘‹ˆˆˆˆˆ†¨ˆˆˆˆˆˆˆÈ ‡ˆˆˆˆˆˆˆ zJpˆˆˆˆˆˆˆÈ §98DDDDDDdÐkj¨£¦²‚@ €eÅú;9¦éÀç‹#5#“øÄ¤^¯‡ˆˆˆˆˆˆ jUå¥ÔÕT“[Pˆ?! ‡ÃÑß!É ˆÅb47ÖSZ|ˆ` @zVv¯ŽW‚CDDDDDD­¦†zjkª3a2N§š¸ƒ™Ãá 19•¸øDvmÛŒ×çëUOÍÁ!""""""ƒVMe9y…Jn !N§“ÜüBj*+zuœ""""""2hâz?_ƒ lñ‰Iͽ:F ´,+†©97†‡ÃA̲zuŒ"""""""2è)Á!"""""""ƒž"""""""2èišYé¹Xˆ–PÛpáó¹LÏ %8DDDDDDDN†¤¾¦‘0&¾¤4â]ÇÙ?ÚBm]3Q\øS’‰ds¤Æ,ço‹÷KœÊU×Î&k€d8”àÂ,Ë¢¬¼”òÊr‘0Ñh—Ó…Ûã!3-“ì¬Ls€”H""""ƒU°ˆ·Ÿ‡C–�‰—~œsóŽ]¿²ê¶ñêsë©%ƒy×^ÉôDã4ÚG Ó4°X5R ‘!*‹±nÓâý Œ5�ÛƒÃá ÑÜÜDyy)¥%LŸ<‡–V‘r ?Ÿ›n:¿¿Ãèd€å[DD¤¯ì;°�´”t&ŽŸŒeÙ„Ã!¢‘0.‡ƒ¤„DF�ƒÏǾ{û;T‘“¦""CTMm5S'Ž!ZÿOü®Qøçâp˜X–�X¬&?s;‹šû;T5RÕW"©IL"4•—RRÓH'¾„4rsÒ;ÍÙa¨n �;�Ô$/¦¢¶¼„Šº QÓM|J6¹~\ÝŽ„±‰4WQVQGc L ¾„2³ÒItwqP[œ¶#Žä?G¦ 5PÕwküVS9Upe0rT¾¾û¦º¤‡ˆÈ‰DˆsWàI½b%ØÑÍØV"&ÞDpÞJ¢õ8¡pv‡*"""Òï¬úz¬�»°Š‹‰UV`Û6fZ:f^Îqc1SRNy ±òµ<ÿên¢Ùs¹nQ;ßx“µ¥¬vû8â ™ñLN{¿9+~—§ß,ÂΜ͵çınñrvÕEÚeâËœÈù‹æ0Ìß!a,gý²e¬Ý_GØ>z“áNfäYçrÞÄ Üíã,y�gº˜d4Vº–g_߃•3Ÿ�ÎñæËk)ƒáŸHʈ |§x ‰""C”Ï㡲&Bfìq\þó0<Ó1bU`æ6ÑúßSš…ÏîïPEDDDúUlÓ&bヒïƸѶ�ÝØDdßn‚kÞÅ3w>ž³f�Ú@L¦v¤†�on`¯5ŒÙç�îwm(cÛºMh:ÀŠw¶’åT’Ûr†Ã� Ä‚¥¬z£œJßhæOÏ'Õgª=È– ;(­ØÌk‹½\sÅ4R'ì¶¼ñ«JB˜‰…Ìœ:†Üdf¬…êý[Y·½Œ=+^ÇŒ»šEýÇ�ßiâ0 ­cË»»©qg3jd ^W&¾Ó0�ª""CTFzåÕM¸½²oÝï8kz2¦k$¶UCñ¡Ýd~‘šº&ÒÓ’ú;T‘~~þyìÚììL…°kj¡¸0|^L¿sX!¡ukïÞMÂǯ;uÁ`VõnvåÎåªN"åðp”Ü|òÃüã¥m4Uà@Ó’Œ£�k8Diή¾l )‡“y Ëtñô6RS¹… Ź  uP‰UµƒMe!l3•é‹1;íý.¹yù$ÛOñâ¶&önÝǼaèØù£sü&&`×ïeOâ.¿f6ÙîãÓ‡”ࢲ³²©Þ±…@ JÈñÖîò2eB›¶ͧ‘M¦¥¥‚1£Çöw¨""""ý"²aѪJÌÔTìò ÌÄ$\ bff`U”Y·«¼WF:¡²r‚ヌwöY§60#žq3Ç¿ŸÜhãÊÈ&Ó¹�¦h�M6$tÈ8>FLÿ~rãÈq㟹™åeA¨Â*ÈÁÌäÉ\úáá´„$§v?â"'/ ×¶&"õµÔÙ?ÁÑÆŽ@î´©§5¹Jpˆˆ Y.—›œÌljêª6l8«W¯¢®±Ž†ºF.Zt1•U•¤§¥áv�æ’GDDDd°êê½óÎŒt¨ªÆ9i"ιó0LãpLjøxÌ#‰¬^EtÃ\))´¼½×èQ8NåœÎt²Ò�_wxð: ˆF‰Äº8ΑA^¦«ó놟ôTFY3Áúz‚äàò‘œæ#ù¨�m,˶,¢Fë�“H,J´7ñ›éäf{zsDŸP‚CDdKKM§¶¾–––f’S“Xtþ%,~ëU‡Ãäåæõwˆ""""ý"²}¦Ç ¡0Fr2ιóX¹j%–e1wî š±ÃB6Ä~ŸHvncGQ)u ´#Ä:N6ÚÛàôáï‡ghJpˆˆ aN§ lƒ½E{HOËà…—ŸÇ²blØ¼Ž¼Ü\ê½!"""g¨èÁƒv0ˆsÁ|0 % ®®–·–¼‰mÛ444�™™ 8gÎ$ôê«N‘¢ýÐ>¿q$`cwq®Nl«m?£ëäÁ‰NÈétvÛÈ7Ͷ7�Ù­ ³â¥Ål¨Ž€3ŽŒìBò}x\N¦ MÙ¸«²w½7£m²ÔÓM ‘!n˶-äåå2mÊ víÙAYy)MMÍlÞ²‰ñcÆ÷wx""""ý"Z^†+)AŒŒLlÌ_ÀÒ·—P__@bb"³Ïšƒmƒ‘™ á0fbÁ²²£ßÌáÄ`G …bÀ±×CµCAB6`ºñ¸ú0í~(I,ֶجӉӈQºþ6VG0Fsáe �xt·‘Xq3[w÷>ÁÑ_Nñ*´""ÒßâX½ê]š››±-›p8ÌÎ;IŒOìïÐDDDDú�eYض�eÛØØØv[ŸŠvc@ÿ—}xÀ¶¬ÎoæL"Åo1ª*kéb�ög¦¦´‚� †?…”>œªÂ5Óér -Í-Ø€×:<Ūåà¡flL²&ÍdTbç11ÁÆ&Â=ê’20(Á!"2Äíß¿Ÿ©Ó¦à÷û1L·ÛͰa…í/êïÐDDDDú�3#+‡‰U^ŽmÛ¬~w���$$$O}C+W­lM„”—c;L¬`WÛ*+G˜© +ŒÇÀ¦q÷öº?¯Ý¼—µ;ë±0I>‚ô¾l•[•—w‘á°ë)¯ ac’”–Jë4‘ֱ*^Ÿ·ó¨«–�;ˈ=wÓÿ4DEDdˆ;{þÙ,y{)7l:òšÓéäüsÏï¿ DDDDú™£ €ðºµ˜þ8"ëÖã>Ó4IIIaîœÖIFß[ó.n—Û¶ˆ¬]‡árknÁ=¾ã0_ÙSf2l÷RŠûXúªΛÉÈdw»Ä�E r'+–®f_ÀÆð�dΔ ºœKôDÙAö®ßÄ䜙d´›l4ppÛj,0S1,¹5&ÃO¼ß€f‹ªòJ"£r9rˆÕÌþKØôã3DC#Àé_¥W”àâ&N˜Äða£¸õöÛÙ½g/£G�äá$.ÎÛß¡‰ˆˆˆôÏÄ 4¯XŽ#Þ�QYAdÕjæÎ™ GV*Y0ÿlÀ&òÞ{Xe¥Ø¾8¢¡‰S¦vz?Ã?šó5ðÊâõ”Vnáµï$>-�´N;Ls]•uAb€—ÏÜ‹Îf¤¯o?“™XÈ0¶ðü3UŒ�OŠÏ Ps€;Ñd›$Œ›Åä´¶.#F#Gg³¶¢„ÆmoòŸÈFf¸‰5ÕPRTDi¬� .Éc×–²?Rʦ՛!/“ü™ ÔZ¤""g€¸8/ùã£ý†ˆˆˆÈ€áHMÅι´¬\Ž'%…èúõXÅÅ8gÎÀÈj‚bWTY·«¬ 3!žpm-þ…çàLKíò=½93¹âê¶nØÈÖ½%ÔV•ÒTux«�Ó—Îðј9u ™¾S°Ìˆ‘Ä”‹&‘º|9ë×®xþ G¹“ærÞœÂvÉ ƒÄ 籨é-–n)¥|×:Êw†‹„œ \|î,†ÇÇH˜º“ŠueTíXÅ’Ò)|høÀMpé7ýÂÆhísà�Ïsçm×2sÞ9§#.‘AkíÊ·™0uf‡!"""rFضq-SfÎ9áãkÿ ±ê*Ü)É�B(„n›ÇÂíÂðx°"uõ8’SHùÔ'ÁèArÂŽh¬§±%JÌpàõ'�ïéÛ!)mbûßâϯí!’8•«®�M– ±`µ b†›øädüÇX­ÅŽ4SW×LÈvàKL"É{t_+$uàó¹NëDž›Ö®>n½ºðK¿ãpNC=8DDDDDD䌕ò‰iYµš¦%oáòû1Ü.Ì„¬`�X @´%€á9øçÏëYrÀpâKLÃ×O ×9¼‰¤{{vrÃå'%ÃßívÓåÅïêv󀡇ˆˆˆˆˆˆœÑâæÎÁ3v � í'\Z€+3 ÷˜±$N™Úí°8”à‘3ž#%…øóÏïï0ä$œÎá3""""""""§„zpˆˆˆˆˆˆˆ bŽœ³¸êê)ØIgp7%8DDDDDDdÐ2M±X ‡ãT¬O2H¸ãIM‹ïï(úT,Ãaö.[sçvDDDDDDd°óùâhn¬ïï0¤�57Öãõu¿²KW”à‘A+5#“ÒâCÄ¢ÑþEúH,¥´ø©™™½:N ´â“HJNeç¶MÔ×Ö‹Åú;$9A±X”†ºvïØJrJ*ñ I½:¾×sp¬]ùvo9eÒ³²ñú|TW”S¼/1Ëêï�ä8LoœŸ¬Ü¼^'7 — Ž Sgöú"""""""§Z|bñ‰½oËС!*"""""""2è)Á!"""""""ƒž"""""""2è)Á!"""""""ƒž"""""""2èõz™ØölÛî«8DÃ0Nëùt=ÉPvº¯'‘¡LõFÊN¦ÞØëÇá‹©ýE¥ L†’ÔmÛGþûT5Ît=ÉPw:¯'‘¡LõFêú¢ÞØ«‡mÛØ¶MSc=µU•,+Ö«Š ¦éÀë‹#%=ƒø„D ïeºžäLq:®'‘¡LõF9Sœl½±Ç ŽÃUUE)M õää’”œ†ÃyR£\D¤X4J}]5% 4“ž™ô]£LדœINõõ$""2”©Þ(g’“­7öèª8’1l¨£©¡ž±§aÛ6áH¡�^d 2 â’7)…�[×ãõÆŸ˜Ô¶éäeºžäŒs ¯'‘¡LõF9ãœd½±W=8j««ÉÎF4Ñx/Úl›¨eaÙyè,+ÅŸ�ا=8t=Éã_O"""C™ê�rF9Ézc�–‰µm˲Zˆ‹‹ÓE%g Û¶ñÅù š±,«O~ûºžäLu*®'‘¡LõF9S�h½ñ¸ Žö³õZV [OÜä c±vÕÉ,ºžäLחדˆˆÈP¦z£œéN¤ÞØû™i,«×‡ˆ f§´¦ëIÎ0Jhˆˆˆœ Õå s"õÆ^'8T5é;ºžDDDD¤'To9¾ÏÁ!"}s-èzi¥kADDäØTVŠ´êéµp‹'ë"ë±p#U !l‡�”ÿ‰|ÙÇPú,ʸžôÛ8uôÝŠˆˆÈC Þx²†\Ý(LCUALüI©ø]‡_jŸóôéýw5˜¯«pûwîd÷¡ j["àô‘”‘˨±ã‘桯§í ¯x€�þø-"¹ã÷º…É}úË´ Õ±mÇ~UÔѱp¸âHLÏaø˜qŒÎôö¬{N…W=ÈÇøÁSòYÎ`ñz²›(Ù]J½mcÆe2*?ù˜7Š3ë·¡ëNDDDúÉ@¨7Ú-üÿöî<:Š*_àø·ª÷ì+a „€ìdÜaØQÇQÇ‘Q�AÇå¹Í0 ã0*£ˆ¢¨OEQGŸ›€ ²²ï[KXB !$díîꮪ÷G'dO:�f¹ŸsrNÒÝ·êVõýu~÷vÝ[çOžã²ZYe$ F �¡Q4� ÀàçÝ_ÕܨÚc­€@‹øX¼­—²�YþƒÕÎÜÿö'<ÞÍS°nû‘�[“XƒCÍ:Ìò/çóÕ{9W •;I¶Óý7Ü3v,w÷‰ÆTáVjN71Ê2šÑˆ,•>wZAç.i„µhFp�Þ�‚“kùäƒ/Xºû<ZùwD’-4K΄Ç'0²½Í/7ºlðlG’‘h˜í >ª�çQ9ôž|r!)È!ƒ˜þÅ‹ü&¸òVÔ�Ú†ˆ;AAªz‘¸ñé3SYžSÍ‚§’Œ%<ž~ƒÇ0î�at ñÏW@W57òöXK2õäé/frw3o�WÆss I.>žºéG6 �|ŠŠNîáoxéåù츤¢KVšuêEÿk;Ð2܆ìÈáBòA¶ï„ö{œ�^¿‡x“MÓ �GBz'ãØÂë�Oå»Óû™÷áÍELmÛ~ÙÏ’ÔêµzvõÌÍ,ý9 ÝÚŸ �Ú˜7{=»W®åìÈûˆ«¬ 5”¶!âNA„†¬>äWê`¤ËÝ/òêˆàòW­J’ä&mÇ—L›þ);Ò62ëíÞôš1²aåF%޵ë}/óæÈ ޵\ UQðzVKeÇãï~dÒx/jÑÒYþÞ<¶gëÈ-†ñÊ{/20Ô…Ûî@-ûZskn{îmš[çÉ…É$~óßÞ2›ã=£ŒZN*Ç.ä¡["‰�‹ÄRn_¹œ;qžÝBt\Q…/ÐóΓ”š‹nŠ mÛ(¬’N~ÚIÎ^:ÌÖ$7ºnçÂÉ$Žd°D´&>ÊZuÐ8Ù›èD—C¹õÞQ´Öí(JÙ¹ ¨ž<šÄùgiÑJæ² bÊUÜÙg8p ‰3sqHB£[Ó%¡3q¡¾|ó¬aO?Î�#§HÍ,Àe°Ö,Žn=:Ñ2 ªO²š•ÓsSI:Ÿ1\Š;í›w'ÛÖ‰�;îï…Tš�s?­dGÜ8ˆaCƒHúl+’V³òèÝLêâåÇ…;›ä{9|&»!˜fm»Ñ·k ªj5i‹5�Gwµ-'âNA„²tUAq:*Í£Â{Žå•I‡¹ûÕ-ìÝÀ–ÌŒ‰ò¼Ú×þ•74{:GædÚe 4 a1ñtïÙ‘æ6ßGWtUAqT~¬ÕW*�”ƒ{Ù:ƒ|=€˜¶ ôIhI`eû«e?²&ùfcËó|Xƒ£î†‰–,]ÂÒåË*|N–eL&V« £ÑSmMUQ\ Caôí£K½^=¹’»òÑå0†<6™›ƒ�¸Ê�lÒU\Š™^gô¦ÿaÑùcüwÉ^î}²7tò¶~À¤×·¢]ó Ÿ¼ÿíËÆ†}ï<1“Mj<ðãÛyF”=óxlú\-ïáýyèfTØ?ÿ9žý!·ð,ãë©Oð52±÷Îâˉ]ª~CtUõ\z¢knÔÊV ÑU,ýŸ`þÍ2ºêÆ¥¸(5sLIeݼ·˜³äéJé÷S2Grí�ñüø›‰5—ØdÉÍ—izöA¾š5›ù¿¤”Y›@BˆeÐ#Ïñü˜Ž” _Ê)ûçóç—×áî1™Ï&ä1ãù/8\ #ÇŒ¡íÍ�¼_Чžðg<¹ì)]{3�ÿŒÉ[ó ¸�³båœR· @ˆÕÈð›#Xµô«Víá¡.}+¼ª©è$YB9³‚—§ÀÚGñ‘I2!nã¹i�10¦Ì¥‰5n‹¾Ä£*â®–å[Ü ‚ BCT—ý°šÐKüVU�tU!°SWZ¶�¨f�vIE�2à[>g(³ï ö®]fï·sxã?¿pºÔº‹žgàŸâ™{ºZƒ»·ÇZwêzÞš>‡e'òЊg‚¯ÅóëSb`¢x>÷#}È7[žW¯ª»tù2î}§N�"??Ÿ‚‚Š¢ Ë2³f½�Á`D–= ë:yyyüuê‹e84ÎlÛÎYäè[¸c€ ­Úûæê¨¦nŒښşŸ&cÛV»zÓËRáþ� ¯C É…�K…ó´ •(çyØÈ5w<ÉÔÛøâýÕœ"–az€þaãc«¿û‚5žŽ­ l<‘͆¯2ºóïéTq„ꪇ½¢'²ØðÖóL[s=¸#w>ú†÷jM9œÞ³šù_¬bÏ8hþ»·IDAT¢×x*ßÄGÏ ¬º-•ÿÎx™wåcн�GÆŽ¢oÛÌÎ ’6/bÞ¢}¬�; cô\¦ÞVÀ>–“,V,¸œ),þx É!=6¬a�‰hâSÐR÷?GX‹þ¤î–¸þ_׸¼sÿ*V�Q‘Ãoæ¶~6ÐáÚƒiµüÎmXÍæñ}REƒpeþôÿr<|(S¾žN‘&²“aÁKÙ—´œþ#šÖoßGû¢OÛbÍãQÄ�ˆ;AA~ jn.y Û,ñí‰Ïý«ÊèùìùøEžýö$J`{FLËè¾m Õ39±m9Ÿ}µžŸþw*Õ7˜}ûòWŒÔå(ŸM{“¥'\XãóÈø;Ð:gZ"ë¾�Ïk3NQá×’¾ô#}Í­YžWïÖàÀjµ¢ª*šæùþÓ`0`4‘eF£ ƒ¡pꈦ„ÍP¦^N’�§ "aî˜@'I÷®Þ:´íž@ˆ|š¬¬dN\Òè#•*,¿-oæ‚é€.Ýu #›å°âÃÕœ"‚„[‡r[ Ï7¾jwf(EjË]ã±äåµ\Ü7Ÿ??¼…[âæëzÑ«k"-Õ·@çþo˜ûc:š!ž±¯¿Í”®&4MCG"¾ÃµôïhaÜSÿåìêOøft_&v¬ ‰”8Fõè*íÍC3´çÁþƒ ñxÖ& # ½û§ŒãñÅi¬_²‰I×ßN´\»rHF €–²Žµ­îfîç�’`ÓÑu·â¦ºSXïø©¾Y;qœ¢ÓðX5”‚Ì�„÷­A=rÙüý.j2-�àZ³'f ‡2"~!�ÜÆò  º=ºÒ5u‡zMaþ¬»i-©h:H½úqK·@žüŽ'ý—;ïä…þžë@|n‹5ŽGw"îA¡¨ÿok²†žËΕ?“ª�“@�æ%oRÍv¼î_y~u'-bö¢dœÆ¶üáµ9<Ѧjè´¦}§>\ßÑÆƒ/¬àà>eõ�0Ú›;JÔz½�œM YxR�À~<ùÆTÆDª¨׎ýzõäŸx§@çJ‚]‹~¤Ïùf#ËóêÕ€   ‚‚‚�$ Y–Q“ÉDƆõúëT�$®ÿì3Bº!Iƒ\º^Úe2²ÜèH„ÅDb–¼¯µÑŒh²ÔL22UôC¹K“ªÞVñ+J–+:sºêBS‹_¡© .—÷Cc¡7ÿïþÕÆ´9+HÌ<ÊÚGY»$S-Úw¡g�ké׿?b .·P±Â¾u9¯I˜ûü–û:J(.WñÓªsÂFw\Æ{‰çظéã;vÄPɱHíîeÖgCÈÊ6Ñ2Ö…RrsªD—~ݰ-¹€ýìÎjú•»ÓøZN—t$@+�è÷Çûè`°ãpz}úêÅSúñÙ´êþS8±Ý'‘~ümÚôûÜëòÚÅ ,Ýš‡fhËÈá1èE5‹eØÈ®Ìï {WþÄéQ÷Ò¶Ls½rrƒÇޤ…êàʪ Ú�bt×oxk6;v&áêߣÏmQ÷)EÜÕ®\c‹;AAhˆêË•b•dbšƒK§²þ»Ïøø‡óhr0¸‹îÆâ\ÌŸý+pqðǵ$»ÁvÓýü±«¥D’£ªnl}ï宎«™{tk~É`Ô•iWž›ýŸ¿ÀÄ%Õ]Jb¢ûØW˜ÒßVø·“½Ûv“¯KôÅà0'JÑ¡¨ÄpÇïn`Þþµä–95ïGÖ"ßldy^½š¢žµ6Ìf36›íÊcƒKn.;ÇŽeàâp¸Øòà¾{w%[Ñ ç̃Ñ$×ì£Àd,œaïB©lÍŽ_‘î–ˆò óŽe×O?°fãV¶î=Êù¼h}>9È–ã«Y™x�u­x ÉØ™ÞdÊÝ)\£C‡äýid�M![ïN¤îÿ¶X—DÜq'‚ .6ϼ‡�3+xJׯ, ™¢é?î%^¹½º»\–èZ:GŽf a ¾{g*¸ä@ך‘Ð-91�cGNâº#ºÓT4rR“8œZÝëÌDäxò+ @K#ù´m®‰Ã\®Z¦ö�ig\˾Úö;ý‘o6’<¯ÞMQ‘eY–1  L&šªÒ|Ù2z\ŽÁ©¡ä¹1…„_)#Qv‰�›çÝ*È·×èMÒ ìè€d%À*•?Þê.¡*ùwe—5UW¾ê¢¹8¥pzû#½G�à )¤Ÿ8Èþ}ûÙµs+·!íâ~Ï~Ž}É/3groÏb:î,2.i€‘¨¨p¤ ÷+�LZV—5/;¼YêèhùgÙ¶rßÿ²�#§R¹”ãÄUæƒEö[¹ÂZZ#ˆ´–¼Á©Eý�yId‡œsKˆëýt÷d= IRhÛë)ޝ½žÐØ1D¶KPÇÊ7¤aÅ긱Ðä­´([§�¸ýú ¶ý”Êêö2®K?llF mF”©âc E& -7‡\ "Õºh‹%«èowµ(WXËÆw‚ ‚ÐÕ‡ÿ¿%ê` ‹!ªì�I”Îgä¢ÉQôÿÃD3�ÞÑ (jåÕ¯I>WQ9õ23<ƒ'É þÎC+*þ–È•“…ŽŽãR9*ÅSq«ªf®{rÓUvÏ“"F‹µ8×Ss¸œíÉÃÂ*<)4‚ˆ¢êVÖ_ô¦é‡|³±äyõî Ï”ÕAY– ݵ‹x%�˜îí¸ôÕy\È"Ï}ŒoLžå_"Âɾó.B{öôlD¢eó@d.“wö™Zo¯ï¹ìLM!]ÉÔœVÕ¶ú_‘®¡ºœ¨.‰�VݸµMO�dz¹GYøÆË¼µ.•SË>äÛ¡sy´£p_¹“ŒÉh ²/ˆ &O³ÐÝnÜÕ4p={ï½0�o�;ÀEçÞ7qCl!63F£éÂ/üge"?•+"Mõ¯ñ^%ª’Å…Ã/‘wñ"Zõ¢ó c²6ÃeߊÙÚ]9Dd›QG÷äbò·œÚrAQÃiÞí æðrÛ+صŠÕç5@ãè—ÏòÀ7eßt 5OAG#sãj6?Ü—!-?m6WvŒæÂ6åR Û”ÿÛâU!â®ÉÆ� ‚ %™è;ùf� .�Û8óÞ£Søìd&g/Ò6LÃYáe¡~¤»q¹ttÍ…Ë]I. šØ0†šk܇7[ ðâ6±zñ—ëºëÊ”ƒÑXqYIÆàÕ*ªÕ©}¾ÙXò¼z·_Å!Ë2¦ìl¢×¬¡û#ñdý˜†c`Ð#ÝJ½>ëH6ûŸ~†›Ö®)|ÄÀ5 ]0­Ø‚’´“Ù·q›W×¶+Ú}»†øº—ŸYVá1M+qY~Es§Š/û›w³Îª§£kšæ`Žã®çŸ&éÀs,¾xŽÝû. vl‰,Y°^‹åp8Ѩ(H5ìvÏ->%«Káú%‹Âþ¯ÞaÁq'r‹áLŸóÛ -ÔA×΋,Zåé0éµ.Wv0³þÍD¬)_Ž é§Ø‚¢‰»ö$ÙŒ#g-®f[nÙ3èçrîBÓtÂco" <–ó‰+Hú©?ínY�9 Ä=‹õ+!K“��P�™FA%û5Èî¼,ߘΠÑÍʯ…ätâÔ+:"‡Ó3P²Zå.  _*�×HñŒ}r kŸ\ÈÙ•s˜{ã;<Ó7¨Lîãçþ•d%À`¢Çø÷y÷®Èª"T'v‡Ë‹³Yòš®y1ÀQ‚dÂRøíŸâTа•+¯Û °kÅ—ÏýH?å›�!Ï«—ƒ4%¯Þ� œdlNÇu$S3 Ù¯^ºòZI–P;BdÛ[�í+×låç‚Ý|·ôCº¦ÚyVÚ¥ ,Ú�‰&™é:øZKžmI’'puUE­à×r.s¹Ž¦”SÈL>Âþ#ǹÜbwôЍ|a]Å%…Ó*J†‹:v§§!#Çв¹.¸9Ÿz•ð €JÚù‹hHXcšW}é–z†í»ÓÑ0rí½ã®`/u‹L�KçRÉ/{Î|-'ÐuÈ’·ý‰sG~ ,¦-!Ío@BÁ弈¦:<+!›b‘ ²/l ãÔV ¦hºù?tsºVÜXµÔu,ßU€.·àþ9_ò̵æJöªrô£‡ùã¼dö­ZÇ™Ûî+¿ØhNiLe?NU2Ó3Ð�0EF)øÚ¯v<ЏAAðš®bîú Oßö3O/½À÷sæsë{“éT2?ôs>ghFls#RŠ›Ô³§ÈÍ·Ô�N®FT¸ i*h„Rv-z--…T¬ûèï|³«ùaéuøS¨ä"#É9Š]‡²!ÀJ³ûâHnna³ËÅf—‹MN…Ÿ.Yé1íåÒÛ ¾™ïl�ÇÌâÃ�Ùž[ÜTöã<ÇòÙŸ²%WCŽÊ„‘1Wž3Ù,$г²Èv—-«‘¹w7'Šf%ÇTÙãº×çÇÍÁÿ›Á´·>aÎË8ê¬úõúåD¤¨ ™iƒ¬R=z´Â€Æ…]{9SîXå(;÷ç£K&ºôè‚¥ªcÑäë€DxhšZf[®3ü°ò€g±BÝåÊ~øÕe[¬j¿þäK]Lqt²‘V ¯r9ý"'·Hþå�ƒQì§@ &ûâ~’6M#ãìaZõ˜Iç!›À‡®j¥ÚÔ±Õ«9¬èâ‡1²½“üÜÜJ~ ˆ<‚nfp_Ê#J¹ó£»�°ç�£|}Õs:’‹†L\‡x¬µl‹þˆGw¿rÜ ‚ ‚PsW3÷õæÿxeù�j¢ïø) �–Pϯä­O÷’¯•~�_ûW„Ò£g[ h¤nßA²«¢zi\JÜÁþ”<Ï€ŠŸŽµÊ)†öñAÈh¤L"«lî¥kœÝ½›³þèGÖ&ß,é×n[U½^òaܦîk_t{آ톸Ծ=#¢PÏ…sã Ø:väa{÷g^"å¾{ïÕ«ô¶t™®>σ�làLfÑ´ÿaÚ7;Hu”‰.ÜdŸ\Ïû{–·¶e¡[â¹÷ʼnôµ¿ÎØ2ŽXhÙ;Y ½Dy÷…uÌùúš¡ìê0•·É`À(…·¢õîÜpãý¿¥½\É yé•oØ™®TøZ%m;Ÿþë#6åêÈQ¹£Ra}Ú»�îV ÷Ée|üãyÜ¥Ê:9±øKV¥iÈ!30¢°\%Q&GÑ"FÜÝw{É׺Óù僳(7šPtÇe.�{_ËýªXWj^MS±ä=‚„á;hwý¤ù·’‡Ë™‰Ë‘Nê¡…Äøœ„á;Œ�½ ­l�Ö¹Ÿåk΢JfF &®º}GäöÞV$íŠA×¢\:ÅžM›Øçº�éÿ¾ŽU�½ÆFû^|¼wŸÎ ¸©‹Ïå‚Ë�•†­6õw¹]¸Ü.Ì!°…t&ûü/ØÂ"¹tîG¬!]1‡ ??¯Ò=goý�u—4$[FßEõ3eäÞÛ¾ŽÌM«ÙôH_††I躎Èm2ظ˜'§eÄoú!“sr+Víæ‚n¤å¨G¹»5Å /ùØ}�Gw"îA¡!«�ÿ+­“®:ð1[³‡×¶žcÉ»_pËœ‰\àyÚïý«¨!<ûÄ6&½¾‰½Ÿ>ËÃ{2¸o‘F…‹É{Ù°a/)­G?ÁÃ=Lè5šÎìbû»¸ëCoVà� ö"ÿ;¡Ft,×Ýϸž›y{ÏiLý 'Ýĵ-­Ø/$²yã~ËÐ ùᢆ^Û~¤òÍŠþnhêÝmbÁs‡ÑhÄjµb49qâ±­cé÷Ù<~œñ*¦ �\÷÷¿‘—Ÿ�ÃaGQ”Šë¥«¸-]yäÍùüfý"¾\²†MR8q`'Šö%› ‹ëÃð!·óû»ÒÞìÀYî-øÝßÿFúŒ·ùîÀ)~^|ŠŸ‘�m-¸þ�™¼|¯�/×K +žU‚+¬ Å�ºñû‰CÙúújÎœÚÆÒS–Þq<¤Qõ55n�˜ÁSù¢Ë@¾ý꿬Ø|€3Gw‘z´äÉ“ hÖ‰A¿¹ƒ±÷§k€‚Rrb› ­ÇÌàã¨Ï™ýÑ2¶¬[@âOEeÍDuÁ„I¹/Á†ÛU"ò+‰²˜Q/ð¯ôñ¯ovsxõW^ ’l£yïßòÚ‹ãê æ�žütI+?æÍ}wóöõ]èác¹N•F{å‡ú«n7-º<ÏÙ=&$ºy—²‰ëõª»ì _ ÚEÖ­ÜN®&zýpn®¤Ý–Ðo$ƒ"7°8c'+6\dðÍp;4äÐ.Œ›ñ;Ú½9“O¾ø�üÂOMÉMï{¦0õÑÞhîâÝøÚ}�Gw"îA¡!«ÿkÐÖÝጜ2ŽUûßewÊ ÞúüFÞŸ˜€gŒÃÇ|®²œDÕh6ô%>�þ–w>\Èú½«øbOás’Œ-º;£'>ÊŸïèD€ËíݩԋQò³Éô¦ 2’S½ò…ž®7çw¯ÌDë æ­Ofתì$S]F>ÇÌÇZ³ò±E€‚£¶ýHü›o6TRÔ#3u$Ïr'gÞ™X£iªªr"ñ í:v©³ÊLüócLž4…ÌÌLÌfG�&a °p]ÿ~y£‘ŠGÎTUEq)Ì~k6oýûÍ*¶,!›,˜M&$-—ô”ͼû—×X•!ÿà|=±’KAQ\WF²Ê‘MXl”Kg9�–ƒËJ«¸V„ËNNsP&YÕŸ‹³h•)€ › 4'ö<j©Í`rg‘’–�á´ˆ´¢:¯Ú“$›0YÌ :ùS9Ÿ™K�SE²Ѭ-ÃÍèn—S©pÑž¢óa±È¤�åìÅ\ÙFdË6´ 5 :(î2ÚƂ*:£Å†É�ÅéÓÈÕ,„·Œ#6‡·&a°bRs¸ì´bÀ•ï@õµœÑF`€IW°çÚñÇš<Þ8™t„ö�®¬S²ÖD]Å“Ñh"yÓp4÷dckâoZ�Ûíª¢„Œ) ‹tWvoV’$#–À@L2¨Ž\슆d $ÐfÕAA�ŠÑjƒ‚óœ:{ »1˜æ­Ûerât¸(?XîC[ßâwõ%îüO‚ ‚И]Í~˜÷ŒXƒ1J Ús°»ªÉ¢d ¶@+ 4%»£Äà‚/ù\¥¹Qá&�Ì®Ëç8sþ2vÝDpT+Z7 Dv9p*^n”9֚Е|ò%¾h”Œ˜­6(¸Àés—( �fmÚcvápªƒ0Ë:®‚œEÅ|îGú’oþ:ý+oy“7¶y|.Ecõj€cÒ”Éüåñ§8tè Š[!¡{7L&#PæöC%êæVݼ?÷æ¾ó®—{‘�d�Ä�ÿĤoÎAÄ�üuÎ �òn9I6 K ¡iZñåö¾�ä+ÛÒ5ßnÉ#¾É…ë{n[YƒJOÍË–Ù�§ÁU¶�¢•’Ë=îc¹«¬¾p œäðš›é:ôg0·óßv}Qâ}Õ4Õ«8ñ¥-ú�"î~õ¸‚ ‚P½ú9Àá~í_mS’=ù:º®¡Uú-öUT*ÿR+ÿbÝÛmU“Ïú-ßü•Õt€£^­ÁÑ>¾=ÿùêK.ef°iÓÏÕ–Ñ4�»Æü¶õÒÑ5èt÷ƒÜ¸êu~ÎܬisqMú7vƒ¼äЂ*93º¦Vð-´�t­’ozk²‰ÚÕÆoÇ£k¨j[Ò+éHúZ®‘ðç±É¶tþÍ÷H¶hê¯<öZÝûZa‘š·EŸÚ¯ˆ»&w‚ ‚Ð5ÖÿÍ~í_mS× †¹h�ó!?®r[Õ4ˆº8¯ �kpÔ]hý}êß1šL5.§88Ž•ÑÃnå…¿%r~ÚbŽ[ÉëϬôU¯½!‚ ‚ 4L ôxA¸šj>ÀQ‡ìùWogš› ÞSøôó[XùýzvŸÌ +a-{Ñ=D\.-4LbpCAA„¦Ê«ŽÆ:?ZwÛÑBºpÛC=¹³ðþúæªb‘@¡©óG,4Öx„š± ‚ Uÿ+ÁÃÛX¨Ñ²l@UUd¹ñLßÐUŠÝ…òkWD¨·4M«“6ßãIªSWñ$‚ �™È…¦Èë¼±p�Qt•EˆÕ€ãjN#„zÀaÏÇj ôûvE< MQ]Å“ ‚ 4f"oš"_òÆj8Š.‘$‰�ð²23ÐjyAh(4M#3#ƒ�ðˆR±à+OBSæïxA„ÆLä�BSækÞèÕ’$!Ë2�AØ‚‚I:|€ì¬LTU,h(4Nªê&;+“¤Ã& 0¨Òû.×”ˆ'¡©©ËxA„ÆLä�BSSÛ¼Ñë58Š‚+2*³ÉLFz*gOŸ@SUŸ+/õ•l0Ll\<Á¡á~xš’ºŽ'AAhÌDÞ(4%µÍktƒÁ³xGHXA!aè…÷bÖÅ=™…F¤ä%P²,#Ë2ƒI’üzOBSP×ñ$‚ �™È…¦Äyc�®àOpɲŒ¦i" „F­(°ŠÊßWp€ˆ'¡é¨ËxA„ÆLä�BSS›¼±F·‰-9¢Rr'"À„Ƥdۮ˅E< MÁÕŠ'AAhÌDÞ(4þÈk4ÀQvGE%’U¡1ºíZÄ“ÐTˆv-‚ µ#òF¡©¨M»®ñ‡¿v,Bi"žAAoˆ¼Q*æÕmbAAAAê31À!‚ ‚ ‚ Bƒ'8AAAAhðJ­ÁÑæ‰k¾]õW]AAAAhª$C­Š‹+8AAAAhð‰÷IEND®B`‚Solaar-1.1.20/docs/screenshots/Solaar-main-window-button-actions.png000066400000000000000000002732751522022367600254560ustar00rootroot00000000000000‰PNG  IHDRµIg§psBIT|dˆ IDATxœì½wœWyðÿ=gæ¶íZ­z¯¶%Y–m°�ml°cš$Ä@BMˆBB'ðË ! $†¼! �7Ô„`º)¦$ÆvÀE¶q/²¬^WÒª¬V[o›™s~ÌÌݹwïÝ]I+Û’ŸïÇû™¹gÎyN™+Ï}žyžç(êÐõ¶ÏØzå‚ ‚ ‚ ‚ <÷èýú‡Um™›üz/zËÓ5&AAAAžåtAh/H*']oûŒ=ú¼7<ãAAAá4`úCß®„Æ„¾ó_÷ÌŽê$è|ôû•óÓy‚ ‚ ‚ ‚ðl§óÑïÓûõ«Jȃ2þ39ž“"¢á”†ŸÁ‘‚ ‚ ‚ ÂsÕõ¶ÏØþ5¯z¦ÇqRٖʹSƒ‚ ‚ ‚ ‚ œJ:žüi˜”Qï™ËI1ý¡oWÎV½ü‰ ‚ ‚ ‚ <7 ÁéîÕ!é�žgp$‚ ‚ ‚ ‚ðÜ Ì¡pçO€šü§ù\AAAát y8½•ðdÈÃв>ƒ#AAA„çg\ÈCöð¶gp$‚ ‚ ‚ ‚ðÜ`\…ÂìUã·¶>Œî<™øl4Pã\k„ª×qÕõdRÉÓÝÛBAAádXyÉ‹*çA`p]9ž(ãµO^ 0n_õdåŽqøÀ> Ã8�wÊçQ+§‘ÜÚ¹Õk“,/ q¨{÷)›ÇdÚ7óñô]ï~Ô#òPhTaå_¹¡!>¯¾8¶}¥®3¾Ü¤” ŒuRãÔ°U!ùyë&-[AAáLc<Å7&ù¹žÂ™¤ÖXP{­VI­'£VVR^­rë§Í£ÞÊÅ"N*=á<Í¢¹5Z£›ðþ?žyÔë¿õÖo²cNÖiÔ¶^yc{ÁD9l0VXi˜ôÖ»ÑÃ;@åAÙQ'‚jÇ�ÑrÕž*l7ÚQTœh bƒ„‚ 2 )®|16ÛŠ <¬“ª“!ÍÝ�4œ¬ ‚ ‚ ™N!€ÕŠa­¢˜ü+á�hdˆ¨½Ÿ�§OXÇ+TôÓ‰æQï<�ͦ®ü‰ÚžHýÚù~ p󘈉êÖ3¶ÔçDmŒïUÝ�zŒ›CA™êÎRû7àtßJé옶¥€bc€"a ˆ tÍumÁ&ÚV & cƒ½®É>þÿ¦_�7mÅJ¢/aˆ8ýóA‚ ‚ ‚ œ,…r^'•®œ[àfr^¹Ê�xeâ—ÑÉúÉóäËê¸Ñ</4Œ¤•¥Äø:ö ‘AAiRû7 zEá³Á© Yˆ &&adˆ6qi¦­•Âå«É<¾žTw€·àüʵdÈC©kùd"‚ ‚ ‚pFS 6ŒU¼Ëu�µ×“çÖ(íT•[à— UåÉ›¨¼V?m4�F2kå'Ç];—z2­ÉDu¯ŒvS8Aù¸æQOîDc™èódŒ µòã5qRilâþ„ 4¨ Œ�Õ.:߇³ç(<5hMUlÃñäX¬ lý¶I£‚µc Ú¡´n¹õwt.Äf[�ê]Z·ßuAAA8³(ÚÐý»ÙÂê‰û|Ýà€1­uåcÍØ°øñÊ'‹ñ=RÞ>¦¢ŸNf“¥ÞøNdÌJ;¾‡ã¦*íã5 ¥Ñ°‡S0�zãIŽÃqS•ñÁÄ÷¹–Ø@P.ÐÖ6´À$¶�TÆ'µý^Jg/Õ` u< ôথ92@Œ³»ƒ±è‘!L{[<…ИЭ(­]DúÉ{)ŸóÒÊ+C‘�AAA T2OäZòúDõ&KÒ@‘”©µÆ&ò÷ÕÓéNt �ú<ž¶5BE½v|°ÑumÍ)™G�Uãq%ÇwbóÕÉ'òP?k£ |¬ã¢‡wcÚ–Õ—�È�€ï‘ݰ]˜N0í¥UgUW°„9lh8ÈlÞ†s¸ Ó²‡âùgC:5ÖþPa:ZÑ¥-a÷ÆÐ™yðZg5œ¬ ‚ ‚ ™NÉ3dt¨PÅ»(ÇÅ~Ãc’‰ê*Ç�”ìä5€ ²Auc ÖX<*}±~:Ñ<ê•�×g|m2í”ãxåºëSo0ª¸§´Å?ŽyØÀÇÅ8é†÷$¨q¦˜h\ã•OtÏÃû�®™G=&öP|¬aÂ$¾Oª»‡Ì¾2¥U¯Çkí"ýøÑ##˜Öæú²G 8}m”Îÿ=ôHMwý7Þ"�·d¸µÛPFD¡Æ- ½"ÖIW…­•™iÀôõ sTäA„g%£Hja±Y{ôKEœÝ«QÝÚc½ú�ïgSHž×ÒHTë§ÉyÄJoàû¸5Jq£óFýNÔ®v.“*(Q*ûãΣ^{ µëØH'®ÓomyÜ>>Ö�[�ëñ1m}ŽÖ™G-ã&eTqRÆñ%D—šو鸌ÂE¢ý"ÊøK.#³å§.\QµCÖÙ-{ñ½……l å Þˆ»ï R÷¯'Ùº±%lJ�Õ.XSò0N|‡ ‚pzãfrÌïl¦«9EN+|¯Lÿpž}Çò =�ÿûWͼö�¿ËgÏÒ`úøÌ?üˆØ?5î ‚ ‚p²”¬"£,EßàN"$<¹Õa=ŠÖ¡9¥ª”ИÚϵò&’=*ÃÃ)`Ê£ÛŽ™GB–_*6�3µ?ŽW^É:¤µ¡\Î7žÇ8®[5—Œ;šz pÒUsO⣋Áu5DÇRƒ9ÄòëÝÏR*ú:1�zŒ¿mdàa�TMiÍN Þ¬i8%‹ö‹X'¶Íµ qúú º:«êëcý¨òºJŒŠl.ÇüY3¸tíJÞrñ<æ§ yÎYüó»ŽÝp¿~¦ç!‚ Ï �ïøéILàWŒÆ÷ª?ÇÉü´ ZUve°‰Ýâ6±ÃÚ î1&þ\QÔýQ¹v.•ÿÖ ¢Õ£ý%ëÄ΄֎õTJÓ–q˜™…%­áX,‡ –B<îÃ/PÑ–‹õúˆå^ ¥4ÖšÑu jŒ1ÑýÈÔ*k—\GcÑxLOì\šemÓ3 ”b¸èq �&›èñaÈ08´8‹ÛÓt¤anš2Z)Ž *P#eú£EŒ� ŽëV8Fó)x“ÞRs\ƒÂñ*ꦣ“Ù„ÓÓ6³Ò>˜¹œô“›Hõl,*ÈQ^³ªª=pˆ w3mµ!I·ÒJ.…¨Š²†é‰]$äAá 3ŸüîÒȘPäîŸüœ7ßz˜¡Z‡¹Áºõrß›øÒ�kùÊŸ]Æ5íŠT×Ùüí˶pçM=Œ�°A„ç±Òí• ¤¢·Ñ±� éeo3¨·rÝÔ¸º'�õúIÃý+2£Ï�W7ƒ-ŒÔ•_QòËa\c*“Ei�SÁOå*õ¼(¿@*“�ÆŒj?'Ë7UùìŒÉYàUÕ‰¯×ž×Ö©=V¨ñPHÎê$™h§ǘ*EØM§+†�Z9�r™Óšev“C6Ò†§gò�¡g¸�¹:I!„»7}§R6jëi‚ºž±×‡Œýa®‘WµÖ#nЬ±(¿ŒïkÊ©�bY'4”‹†Žt8¦ö´� —ᢇï@{.…ñ}Š^@!Ç+2èk²*÷þ¸A©¡ÇH’ñ ñM³ãlG'DØloº‡Ó»›`ÆÒPé”WD¥1Í�Øt.¼æ¤qŽìÄŸžÇ6Ík0��…š•ò ‚pfÑ:½�Îè±3²ï;'™ï°÷‰‡øÀ�=ÜÇSû�²½¡1A3cñRþà¢%\±´‹¥Ó²´ºP.Ù¸—‡6ïâ¿ÙÉ£ƒ'™hQçX{ÞJ®[7ŸçÏï`~k†œc) ì;x„ûžÜη~³gœqN¡,•åÊk.æ5³4Ö?Ì׿·‘ éN®{ÅE\Þ,e}¿õxÃÿö!Ù'Až»422Ô»V[>^ÝÚ:É£ã¦pƒ"e@û“ˬ<ÞN±²_[^´šÀÉ�q5­‘£è[²®¢É±•:Y5úü¯¼ÅOl Yoç‡d™ç›IÏÃ/�>¸kׯXèóÒ ®g)FèT”"`NGsU‰¬àGã(@Ác p(ø%JÅÐ8�UÁ˜¾’ŸãcÑhTL8�‰=*1(ã*×£3¥ÀFqvÞI�éß1 ¸=ýè‘vüÅWb›ÚÀ+@J�#³A¿QÌŠ„<‚ œYø�©©TŠ!/|Ê·S"• Çî™ bphM)Uà¤7ftÚyËõ¯ä×4á(Fz¹ùîMürÇ1zJÐÒ1�‹ÖžÃ[/èbZ¶“׾ᕴ™ñ–{�KÉVÙyüõ»‹·ÎÖ(`øÐ¾wÿ>”gÐ8LïšÁÕ—œÃµs3d¦-âï|1=Ÿº•ÔÙ&yÊdùã_7Ê¥ëÜçñ§k›P¦ÄÞýýð##Áxû: ‚ §åêð†Xq�ì±Ñy½z'"?yÔ®KÆ¡¤’¡ Ñyrw…ÉŒ7©¤gU@‹ :zLOCGS–´cñ)'EÖ–iËdèj ¿0AÀp¤�æ=[%;N¼˜t”¯ôY„qæQ.æqSéI­_M¿§è(á†ÅYð<ŒoÐnšZüÈ ãaÉû†}Æža�~Oa|¯’«Áš€ ž7º¥Ryì<ê0~RÆzûMz>M>�Ò¹…?|•¤ü€`Þå 4ή»É¯[R1TÑÒLáâeäî[�]ù ̬ hºç.H9ŒIÌ€ÂR påy�v«®«À—�A„3 ¿{ ßÙ³–�/qQn'üÎëXò«øÇ;vðà1ÿ•^Å‚K_È'#c‚wd ïøÜ¯¹¹/i¦ØÇ/ØÈ7/¾†Ÿ½usu/yÍ¥üî“·pÓàäûYtéóyë¬ÐPÚû0¯ù§ûy¸*a7Þ±‰?}÷køÛ³3è¶%|àE]Ü|ó‘š7S(ËÚѤKª‰k¯œÉ´OòG_º—Ÿ‘ç¨ ™„JnX'©`íçä1ðÊ8©tUÛx§ƒÚ¶qÝÚcmÝqǪ5A¹LQ¥ñƒ€¤šœŽbÝãù^ '•©œ'½ÆÈUáNÓÓ³šS4§Ã9t4e™žÇæ�²NÓšr˜® çMSŒ´e,Œ” ‡F<Žò#B’dY¼‹E�±óHÞÇqð½2n*]ÙIAéѲä`8àоÁ– ,˜ÞF‹«Á�bàÒ?”'í:åÐ…mô=»úKôåËŒÆ÷Ê8ŽSµ{C£�bõÚ«™G=Ž;)£2íÎÆ_qu8­Qu¾,ºTÀ¤û±Í ÇÊ[b[š0yTqÛ:ƒàìß«ªgµFûeŒ›ÆÝqʰéÑ!ÇÛMJȃ †9Æ—¾y—¿÷r®jS¨T+W¿ôj®zÉÜ×Ã]›pߎîßq˜mC“|«®»xëUóiS€Íóã®ç§}õ~ìv?pŸyþ>·&�n^Ä_ÜÎ�o˜œ—‚J³zn7wÝñ�ÔËkàã·îàÏÏZÅ,¥Yzö|þ¬&_ÄTÊÂRy\;Ó¹dÁA>ù©õüìÈIû}‚ ÏR’!Àؘ¶ ú¨#õ0ðÊõëÕ)‹ëÖëï ‘ÜI"î3gËm€5~ekIÏ÷Iù±ÜRÕ1œ_cƒxk“Ëô4ÌouéÊ*²nhPÈPR”ËEß<4é´¦µ)K¶åp-)Ž-_.1P¬îklHÄèµTÍ<’‘�Ÿ\§šP�ä5ß+3�w¦Ó ÊLk 77è/ôz¹b�ælšT¶ ¼ò¡1a PFÇ[_ŽãTÆ�<¯ôçfq½"iëÃ8óˆ× PIÀ`ãŸjÑ1Ê]z¸‰óDۡÔ;;ÆNª«ƒÔÑC™¥UåÊø(ÆM£½B�–e Ê”%äAá ¤t`oþì0þƒËùÓsZÉ*P*Åœ yý‚…¼þšðÍ@ßáÃüfë~~½a'?ª—F/ÛݹKxé¬hßê�]|wc©±!Âó‹÷ó©ÕKhVç­YÀÌÛ虌å–øÅ�ßæ7† ’2ÖkØOé@/[˜å‚îhe®‚�§JV ßäÆCbLA8cñËd¬\á‚&ðqƒ"¾“�òá¸AŸl¥ŸdŸ¾*òÊ/Aj¬‡{` )mñLøz:¥-§ªÜÑš ²žçl™yÍÍÌo ÃŒ (Âí¤Ë¡Qb¤<ªLg�OÑ?g]‡¬ë0· <“âàà¨>ª 08ÑaÿŽÖ£!&|VWÍ#ð!(c| ˜hŒZkŒ1…?6$Ô^¯È¨ñP& YqøƒW«“ ))Ïó¼ºå•ór¢ñ(¯8áK›É{(Tr2Fn'ñî � ŒŽ «W�†û>ZFó!˜D–¦ØúaPNhÔPÊ£‚d—A„ç¥#»øÛÝË——,å.YÁ+×ÎãÜŽNq§”ÃôYs¸vÖ®}áóøôÐ~~ÇCüÃí»ØQ“I¨má –EíÊ»{xtüm•Øsˆmf ëHÍíâzŽóqc|�z&ñÊõ’ÇHôLSŽ&5Nîã©”†'·öP'eƒ ‚p&)éÏ'£©r£ÏjƒïdÇ”�ÆM¥ RæøòèN'oŸtÛwSiŠFƒ û(”=réÔ9ÖÍŒ¦äOlàᑪÊž�Š~ÄFß+¡œ6ðˆU]c´v(Ç–ß#�=@h—r©HÚ: Â6E? Š� ¥mEö(>ÊIáèp\~@ôYcÇÉAhÊEèÐ3±`TàKȃ Âs†€Þƒ=üâ`¿X hšÖÅe«—ð{—¯âÕ‹šH+hšsÿvý;þñ!6D�±Ö¦t%‡ÏpÁ›X™<†=_¤iË*šì+}‡Ek/äÓ¯YË5³Ò�Šc*eÅx MjNAát'¹C‚vS¡Û}tL¹©Êó0.O)KV´ã�Ó–”£�«?/B¯:«É—´› =júNŽ'pÒ8„Џ.1•Po4 ¿2Î8÷Â蹓É”ª·—Ñ.=C¡Zœ/K‡oã§¥5íMabG|ÜQ/‰#CF"£@¾phÄ£g¨D_àâÙ'(£]—b¡Ú`�Li#ÃH#âÝ’÷¢lnP®Z€æLšÙ-f¶8c‚›Î¢ý°ÿR1�麗C¬oíМv˜Ý˜ýù¾Qx��Ö(2'8iÜ`ìx¼ÀVæáä0Í� ç3É]ì¨-ÀM1|ÅÅQ±%Ü{t‹GU*Ð|ÿcØeWaæ_DÓ#¿&ÿü•ØæÐÞ‹Qù<¹ßlÆÌ¾,èƒ�3òÂáŽÊVÉ=Fc©Ÿ„<‚ ‚ gÚøar{?vj‰ÉñŽ9[¦¹¥™™M.³sЦ\æ¸úΗ{Î{�nØWí95ÆmüJ=‡Æ[ZÖÂq„ùþJºû‹¸‘E~Nk†5]†–\¨�Îpd¨À“½Eºû«�Gòáãu¬—²^Y•aP^ ã{¸ÆÃèTÕz¸9ÕÆŸÇÒ¬<æµdhva¨@y„Ö´Úa¨�/†kÖä–CQYkÚa^ ô »”†}Ž–ª×;6&ŒMsb<~d੽õ˜ÐCAûåÐj5ÖÁ .6›Å›ã�9¼3} fáÕ´Þ¿žr‡‡éê­ÑG�‘êOcæ^‰Íµ¡�î¦<Çb›É?Æôå^¨ƒöËò ‚ €-³á®_óÑ¥³ùÆÅMh•á…çÌ$õH7e PÝn2—IMüHS)r±¦õÉO2œTµ¯àï®[ ÜõÓ[ø“_öÐ[O�Ï9¼Þ ŒS)KAxnam}O´À÷q\)¶µå*“cfSŠÙ-)æ´¸4¹�=¼À’ªq�˧G?�x%†"¹AìM�'�ÉÜ ãÍ#®_;Ϩªò¸Ÿ|Ù'ð}†€’Ud¢0�E­)ZÒ£F€B©ÌP) »¿XIÀXIôX³5åxó¨ÐÀ0P6 Œ�ëºø~xÔ&Ræu ?’ï™lŠÖ´¦ÉUäÒiS$ï[cÈ—v÷å9V×{ZÚ²¸³©bTH¶iMk25·1îÛ÷}š£±Çenz:ØIßS® IDAT¼¸ßCÁøaˆT+ò6á=P7ï£Åº¡ÅG¥²˜¥Wâé£G°Zcsç`:[QA€òËèp´£ò¬­Ó_¢»è\ûe¬Öò ‚pF¢H»Š²¯Òm‰·Å»¸‰ ж¶i ŒåPÿí8hfMkÆ¡Qä`ˆnmyÀúyŽL.D kÍ ^” TùÍðg·ôÐÛ ©nÊÐ>Žec*e ‚ Ï1¢8þ ê­~èÒø>¡b[[žË(f·¤XÖQ½£@ì.?¦›ÀâY[1<4¹š9-.> C5cˆÏÇ(ã~iŒ«#þ’ç“1~¨ä×È "å0¨ñ¨ýœQ6|ûØHi¯ž_¬Èdž‡8Ñc­œzóH}£ÈÖÌCE Ý \ùí÷£x¢]³ò‰â.Èê²Y(éÏ—90챫¿ÌÀHhéoÎáhͬ&‡Ž¦4-Ù,Y0µ/™ê~ÇŽ¡ºl²ï'Æ ˆQ��×-tì—J•Šdö—±m³+2@¡œ4fÚâŸ-åÝ{¹{d5¯oU¸³—ðòÙ³ñ@#£yŠœ·€i‘2¿kó~vOÒQ"ù„ôÓxÜ©üÉo-¤µb!Y8•²A„熯WãL®J™�=’ä‹%ö DùÚ³4¹zLXÃxäK=Ãû äýú9F�N¢ÌÐ([CÉ*RAøhÇ­«ǪoÕõšúßph¨HSÊafKŠ’�c#‡†Š"¯ÈJÒHÇ ×+æôKÜL×”(zaÝxMݨŽÍC¥º  k×¢„ˆ��vSh7…_*�Mi3ÍlÿÀh»íG ”K>ˆŒ�O>“ãÈp‰ÁB™¡Î²ÇF_Ö*Ñ—/R6zLß�î�C¸…'åš+j˜DȃK†@"ìÀÖ5*è�2Çr˜ÅíU2ôÑ=—d)¯8¤vî&wp¦k V»a?ÍÓHíj¦tlÓ·�:©DØC4kQ‘õHBAÎü}OñÅ�çò/çfкƒ·ýñË8üÕÛù—­yÆupš¹êÕ×ð±a~[ÜÇ·}˜—ºù¯¹îêvg:׿z%ßûÒfºë<íÓsÖðÁ‹Z‡©w˜oÝwdÜðˆQ,úâÐ ÅÊ¥3éPôÕZt ¯xýoñg3Êõrt¥@e³tTÅaL¥,Aá9EîP² '±k_¬Ìš¨Ì~åBº02Do¤%z¾O[vâwÐ*•ÁF^ƒEŸƒC%ŽæËF†Àmªê£ÚqIGù ê)âeñcÖŽ;¡Ì˜Úú…²¡gHGó MûKô •(”=L�¬ÅI#€_*T=^ãkñ±¡¤_&c!IÃB4¶dYh°(Ðg4¥À’‰Œ:}ùbŘAà�“ª´=Z‚lJÓ—/ÒÙæ',–c…p^ÚÑu×-¹>Úq£µ1düÚËc8Á] Á õ<Œ!÷Ä6Ìü+«Ú)`†·R¾è‚JUoñBÒ»A›Uý˜ùç‘{ø¹úy‘ñ`r–0 uA8ƒ°Ã|ï;wsõ¼«xu§Æi›ÏÇÞ÷^ÿÔ6nzlìë§{°DÞ·¸é 3:;8wÙ~ûâ¼xf­Àš<·ýh=ß=–Ô¾îÿå}üð‚—òÚiŠk¯à¦·eøÈOžâ®ÞhI'ËêµkùÄë.àâ `}6þï½|ýÐdÝæ,7íaƒ?— ]Eûy/àóW óþ;{8ä:Í’ËyÇ+/â—9¬ÿÞ¯xð²—òáåÎæ%«²üøÑbdNŸJY‚ Âs‘TPžx›ä&ð)©4Ç G†èmoÀ nƒí#“×üH/[M¾* “PüMàã㣂Dˆ†WMp˜Pž'kLHÊ�)z†¾|)ô¤ˆ·•,y3ª¨Ÿ$º\;�ñHÌ­–¢g°åFÒYlì- ¢üuÚÄs8Ú߆œ¸LT¿Ñº%ËcŒ2~8;þšŒoP0>è:Uêx(¤÷ÀuæcÜôh;ã£ö?I~í"Љ/ V×-¥ùáǰ‹Ÿ7Z_Y´»„Ôî}xKæG}QÇ®�øyd| yA8Ãú¶ò®Ïú£+øã%9\•fùêÕüåêÕ¶5ù^¾õýÛøèoúñj®ÙÁ�|èßïcÆ».áEí.ËŸw7]ø†‡Fè-)ÚÚ›éLGÛKZ�-÷þš·üì ù:ý4û¡§øÔÝgóÝM#­[xÙk—k^]âÈH@¶%G{J¡¬Ï¦»~É»îìfÑô!>° G5qÝõoä’Ã#l¿ïv~ÿÖ^ü©”usAÎê(â[¦¤Òa9ÔUJ ž!0ùccŸ€NÂD4xï`B¹É¾ãóÚã$Íí�0*˜­�úóhÔWt,K�þ(¡¡QÕóÐÚ å[S%·Òg¢�ª2"/×…:Wø¥Býy×®Q %•†b œè¾ÅÝÕ[ßè¼ä¤!•¨ßhÝëôiÊ…(ä¡þ<ªÖjüËTeš�Ô¾C‘Á«´Óù~¼¦‚Ókj+‚®ixÓò¨á£•úÊŠÔžCaYÅnPçýв•±õ^ô–ÊŸ ‚pfP:²ƒ�}öÛ¼èK÷ñµ'³¯Ø8‡€5÷íå›7߯5Ÿ¸‰÷þæ�R& ïyŒßÿôÍ|ä®}ì*PšÖ¶V–ÌhazZ�õéÙµ�¾|×ܸ�=“JƘL‰;ð3Þüß»ÙQ´XÀIg˜=­‰Fz÷ñÕ̵ßÝÃakxè–;ø¿›‡)YPN†ù³ÛèJŸY‚ Âs‹ÀÃ3AÕg€’I¼­�Ì *×ãsÇqªŒ1èÊ€ãÔÉì¤B9uÆ «”ØÚz¶F¹OÎÃ(�1cåV•^Å@—' &)«Ž!A[S1&ÔÊM0â¶qý¤ìFJ% "~8ÖXß®(üÑ>âóc@¥­RÕ×ã6IA\?ÑG¥MmŸ5ÆåûcïG ªëmŸ±�Þê{Í�(cÞÉÈ%Žz (Bk@G…�Ofw7ÙÇ`ÎùØ\+jï ¿`!¦­…J¦Å8”A[ÔPž¶õ»0 .B‡¡ç1 +Ûð–/‚”;êQéW…†,Mw<ŒÓ†W ­¼²2æi�ß<î„A„ÓåÒÕÕÁ’Î&:s.)eñ=�cƒÃì9<ÈÁâ ¸):ÍídiG–&ÇRÈçÙÓÓÇÎ!JBT*ÇòùÓYÜšÂ1eéã©CÆæLVd[š™�6ô ôëì¢4…²A„3›á¥/•Ãâ Ž_óŠ9ùF;þ\û¦»¶^¢Nc¼'á)�ì'6R GÛÔö•9#GÉôíÆ) âw̯š‡S¨(ë:rÁ7J�zÔóD ¡ô×ñd¨çá�4$=â¾*}&Æ]%g‚yŒ¹uÆÜðþ$Î�RhíbŒ�Önýû¡ÁÐÖÖÌ=j׋>'Ë�‘£doG{ùÊñé(ÎOaZZê×·Ûœ£0ß%·ë^ÊÓ-Å—®Æf2‘Ñ R‘Š1"þ  Ú@OBAž XŸÞ#½ô™B™A‰=Ý=ìéžB™ ¬W`Û®}l›¸&Åáav?M²A„3œe½ês­¢Z«ÐÖ‘Â2§F¦ƒ�:‰ “r«B ê&1—¤ÒNà�L€®(Ú�0T”ÿÄøb€¶flyÒXŒ@tôY׿¼Jß“ ßp¬­Vü:^‹Ø`P—?VPsu¢,öBHúT IYÖVµ«mSU?��pNã‚ð½‡6Mè¡!L[ë8µÃÁšTŠÂó×QêÀ´6�¹^u®åU+ñbÚ;j ‰z5;Lèþ!œr6 ¯�]AAAªq¬«ÀÇ$½¢P„z!@µwA"Q t¨gŒH*r“Џ,á@´Ã`Í“‰cLÒ0+üIÏ…Z¯‚ZCB<^]§nr�€q¯W<(êå LRên’£T•G�npÿ*õbKì©P�ŠÆV˯7Žh a>§<Œin¼ËÃÄ9;k9¹'7‡!£¥ã¶1mÕ‰«Hxi¯‹ôƒ; œ-YMÄIUbG†ÈKA©jû€JÔIz$T\ª*ƒµ8y‹ë5af¬�\¦jLVi uAAAHàLòíödŒ ãŽ× 1Qýª7â^ÇÚ†þ“5&Ôë³^Ùd µu’ŸµvHÕ ßðmf=õë7ÙzãÞÓ„‡ÂDŒò` *J.aµž;)ìÜU¸&À‰Ü8” F¯'êÖ+«=ïZå<žk@B®ÕÊ yAAAˆ‰Øš·á)Öµ×ãÏÇëÁÐHY͘"¥F²¢1'߈;ÖŽÙ}¡ÞS®×Po,õÊ&c ¨­Sõ9ðð‚€tM›”v0åj£BíÚ6Zû‰ÆÝÈ2‘%>oÔÞSií¢ߨ0nRƤÒ_ï\™ ê¼Þõ‰dM¶Þxý÷^ô–ÊŸ ‚ ‚ Âs™”®~K®Ëy€*å5¦ž’YïsÆ+íêµo$3YžT\“åé(¡¿Žv¬Ô«I„XÛŸI75”[ï|˜¦¦&®»î:º÷í㉠0ÆL٘Ġ ‚ ‚ ‚ Ïr‚ ```€Ç}ŒW¼âxžG¹\¦\.sûí·£µ¢½sJ)n½í6‚ @)ÅÐÐ…B�ßù�ßá׿¾ƒb©„µvJÆ$!‚ Â3Ky˜£ƒ ¨Í4?]O§g²oA8�ñGèëÏã[P™6ºÚ2L}ª¯ÓYAN±wÂ=÷ÜËÒ¥Kéììdpp×u)•Jø‘ñ`Ow7JiÊeÏóH§ÓŒŒŒ0cÆ fϞ͖Í[8÷Ü5¸îÉÿ葟M‚ Bclžƒ;÷q̭غe.+济uo+ö²kÏQŠÑG•îdÑâäjI{ýìÙuˆ¼Pd:0ß×øÃ÷ßÌ8Køã¯|™?Y6u±}ãám|æú~:°ÃغˆQÇFEvúB–teµ`èÀvöFß[䘹d!ÓÓ§x°§O˺–ûؽ»—‚µ€Ë´…K™=æTÃÈÁm<¹i7=ÇF(ë4­Óç±üœsXÞ•«Ô–�±{×a Î6M×¢%̨™ZáÞÏñÚ�ÿŠ«™ñ;ŸåGï;÷”®‹¥tt'6î`_ï0ž“¥}ÆBV®>‹Åí©qÆo)ÙÎwÐs4�ç61möBÎ^}ó[êü[? ×叿7f¾Çû=“?ȦÇ7²ãà²LŸ¿’óÏ[.ÿ�„SŒ1†b±È¾xÙK_Šïû8ŽƒRŠT*…Öc-åB‹Ek�Ö¥Tå¯P(°lÙ26mÞÄ9çœ]i2ˆAAAhŒíçWÿ÷=üëFwùò�¯¼…e5…‘û¾ÀõŸ¼“‘èׯÊ]Î'~ðI^ÖZý�ò7}‹÷þÅé1€Êpñ¿Ågç= óxŽâ=üUÞþ‰;(U´Eö¢ðÃϼ‚éõ~?[¹ñ#Æ7ö£eî ÞþÕÿÇÛ–H”dÌ©]Wñ ?áŸÿñkܶ»*¡º“ßùìwøËçÕWœËÖóÕÏý;7=ÔCÞT»°*ÝÌ¢Ë^Ëûþâ�\òþ÷ò‘÷½…ËgÈ£éÔa)=y÷õ×v»îcýþ‰4)a,S³®¶°›_~þ/xÃ_|�_ÆJÞ˜£wñé÷~’o>p 2&(´“&¥ °f„Ýwƒ¾ï <0<:>;<Äð‰þ„±¶oï ǧºX¾¤µ�[ÿ¬Ki ÿù‘ñ¹[·�1&Ør~úO¼ë¯~Ì.?QÞw7üÅÿÇ—îÜ3FÙ°¥Ã^ß“|÷“á_æ$~ ‚Ðk-ÖZÊå2A`­ÅC•?k ���45å˜6mÖšJ»ø X,b,35Ïûg§‡‚w„­ö0hSÌX¹–E­XMòûÙ¸©‡‚jaÁê³™•9¹îK¿x'Ë_û}ÊË?Äú�Ÿá’¤©5ÿ_}÷ó¾û0‡ŠÚßÄO}“W�@ŸãöólÁ²û‰môz JᤛiïšËÂ9mÏÒ/Ôä8-î‡ <í8,]wß鿍ëmaÃV�W^”ðm5=lØx´úG©égã†}.eôý]‰Í›vÿæ×³Ïå‚9í®áe¯ZótLæ9MøÂb �q׃ƒ\û’öeǰçÞûØ*RF§(aÓ™ÌT­«éþo>öáÏsç�Eº¹�ßv7$`ë�¾Îm‡, ô,®úÀßðá—­ Íå±ïÿùµ‡0oßóõ[^Ë󮛃ÌÈH£h-oüÀ«9«ž-O7±x~Í…`7[w–Ã>ÓKY±hìÓjÖŰÿgÿÎ7žÊGJz†—¿ž7_³’¯‡ûü-~üd?ÃÐc7ò�û^Ê_¿°(òÀ×?ÏÏ÷EcÔí¬¾ö¸îâùd·qëw¾ÇÝE,†þ¿Á7¼š�]¾Æ?=Öå$æwBß3°ýwñ¥¯?Â@èÊÀô ^ÏŸ¾îyÌòwsû7¾Ê϶°Þ~~òÅ›xåWþ�³Nç„‚ð,¥Öˆ�<÷}c í ô£•®Ô1ÆT …é”ûìLÊxÃg?=©z?üßÿîM ¯Û#?ä]—¾“ÿõfóö[öð¥kÆÊò7}‘×]òižR—ðÙ§ÖóÁå'ÿª\Ç!p4Õ ÿùm¼ûã938ïW³júùœðË´†ý<‹ðÖó7W¿’ÿ8:�ýZir³ÖrÍÞÃ_}ìyþôÓð ãép?á ³jçf~Á fˆ§6v\´¬b(°Ã›xbWhåÖ­m4� 2d {7 §Ïc^þÝù‰´ŒGw=ņmû82X†L ]ó–²zÕ2fæÆŽ´|l/»‡oD•ncþò9´$Ç`‹Úµ—>/|Ó^?ÎüÄ×çT|7¦j]ýî'x¸§©é\ðšwñþË÷ð‰÷þ;Æ{�dޱqcqç¬WñöW¬ ]Lçü׿‰—üôQ~pÈ€õغq;ÞusÈ^~˜ØÉRµ.åÒ¿˜ &ù«Ðöïd{ô»@Ï[Æò:.õS².æ wþú©HÙU¤V¾�þúÍ,�Æù [9ü†¸;oÁ òØc;ð_¸·ø·ÜÑ95³®ýÿòÁçÓ À¥\±&Åõoû›| ¦Ÿ Oî#¸xÎé².'1¿úžaé[ ÷ F=¶^Æ{>~=/›¦€ó¹`î ›Þþ ¶ù÷/ùù“oä¬uòVF¦¥Žã`‚Ïó0Æàûákß÷ |ŸöövÈåš"#Cò```€ö¶ö“uˆ™2ƒÂ Ÿý4o¿þ ¯ù«_âí׿ƒ‡}`ªº½î‡ <�4­á³\î|ÌÃbè~j3v�ÑsÈÛò$›ÊÐt^rçÜó îÎ[¼-ØXúm®ˆôAst+›EÆI•æÜ V‘üÍßå} #ú�}�wþŸ_‘· š~‹¾ÿ¶øƒ|å©<–4/ ®Š;ä‰ýŸýÏ_³}(¨r»UÙ¹\ú†÷ñ±7_ÈqÙ;OPfqÏÿòÅú7?Þ›ˆ›ŽÚé&]ö>øþßçy�zJÚMÕ´Šó– {‹Oþ‘õ<8rW·$¦Úsëw€¦í¼5,ºg?Ý ¥ù~èûüË¿}—;v‡»dŒö„ÎÍå’ß{ïëå̯¼0¾õ³\ÿÅ�x€jºŠ¸ù¯¸2ùÎ ØÂ�ù�PÆaÑ?Ï·ß~vÅxuÂës*¾qû)[WMǪWñçﻞkW´`wüç$z7$½Ýu[É߇N­¢wÆÆ®ê†‘¡‘ŠW‘jnc"gÐ$Þ®íìð¹%˘_Ç35ë¢Xråø£µy†óšÖ]ÍâÄO Õ¶�%]š»÷€ed8ödXÌ«?üQ.ìdp(ÏÌKÏ�”íhYæ®`E«bÓ±h5‚X›>MÖå„ç'ö=+ñÄÃOEÿæés/å‰/š»ø\6ïF¶í ÀôòÈ#{ Ö-ãÌIo+2«PU IDATÏÓ::ر};-3g†F†o€#Gްrå ”žšÀS®ñí?ÔMÏ�žª²G~”·_ÿ>Ìœ¹sàáG§ºÛ§3ÈÀ \–­:‹F¹yÏL\.|÷òƒ·NkXdï­ÿÀ½ùoùÕîðž?»†ýüzœ†Ž ‚ Ô §³nÝôc; °x[7²Ù»–KÓ{7n¢?t!`ùÚ«9gï-ܽÅÇŒläñ>W¬5¥­O±5ŠwPîJžwnó„Û©©lYy ÖfûÍ_æ››òcctí�~åC¼ÿ;ÛÂ\*ÇÌå+YÜ4ÈŽM»9Z<À=ÿñøóá¿ãßßuÁ䔄”iûîàSïÿ{nï5X:ÓÆìÙ�dÍ0‡zzñóì¾ûk|à@žÏázÖæN®Ýd±^'k_0ŸÿÙ²› ÿ0w>œçê+›¢«†Ã÷ÝËfß‚ÊrÞy+1wßÒ@RÀþ[?Å»o¸‹ƒQL»R™æª8BÑ·˜Â~îýÖ_³yûŸóÅ¿{‹§àeå ¯Ï©øn$Ç5EëšZ÷.þã’Z¢çæ¤"[õtÖ¬ž�óX7àïÙÆöò˹0òð±ù=ì<IR)Vž³‚Ø~32‹8¨=Ãþ�{(²¬ÊÈ!ÂÔoó888È´iÓª ÖZFFF( Œ W¼✠Åb­5‡â ÎGG;?œô˜NZB =z¸æª—W>ßðÙOsí+_Á¾ý=ôôìçCû8oxÝ«§ºÛºØþ�<º£Z³ve®fÏo~Å��ï¦?hbÆÒ ¸òÅ07[¿�ÍÌæìÕóiV–�]�³ýÈNö [À0ܽ�‡:€Ö9²n‘BYѺp gÍlža‡é~r ‡JжEç²rFªN?'7î f„îÿŸ½³�âjûð=³»qq#@ð\‚S¬X¡´P ´¼´¥”ê[w7ª´¥¥H©ÓbÅŠw÷ !q×Õ™ï� ’Mô{Ï}]\\›�™sæ™Ù™s~ç‘Ã;ØG–âBHûÞôŽðÁ=‰§£ˆË×Ò ¬ ]êүߎà�oñÛ‡ûiöÈZ²7ÿÉêć˜ê_¾ KÎ%ïÜÃÉK)äXìñjN·^�hè\µú`L9Å®í8Ÿ��ÉÞ›°Ž½éáKUé+jÒV¹ëAqQgHÔK8µ¢yeÉ9Ô,b�E“j–p � ‰gYM¾F}ȸÀ‘ àRxíM—vò÷†£¤:wfôØÎx‹P Á-ACÃvmhðK I (9g9yÉBd˜Ô,¢N^)ÊHëVÍ�vE>›†¢¤pâd2J+d,Äž:W’¸QjK»êÄ‹i4×V¹ÌçYþWrÃ^LÔoòp .+NýÎ'‹¢ �/{Òû…¯xoˆ?6@Á…żôôlöçè‰ùk&¿÷ŸÍÔf7žáZwL…«ÿ,ekZá¤×¾Í˜=}=C+^Wõd&e’oÎ'%æ Ë~ü‰“Ea5Ž-ïã�îÅSß©]ª}~VÞg–tRÒKdœÝ®/¬ÃÍÕ #**æôÒp‹JA�R\úQ–e²²²0™L%‚B±÷AZZ²,“““Pâ¥P\Ù¡x»â uA½ú¤‹ «W­¡[—H^xõM¶nXÜy³ë³ÙŒ;ß¡ÿˆ_Èëñ%§¶á—ñãùhk"×ò J؆ ç³òDĵ¥ã¦WèQ&9Ÿ‘moöfäoÙ%ªõ¾�Óù#�œFóü�m|¾(×{½pl‰pi”˜9Œëø<»”–¼¾ï(ïyUÔNíú `ŠYÂÇ=Æ÷R¯¹ Jö4ò¿ÍïÍÊ‘=ù$Ú‡iÿÄðm¿º.,áÝ5’0íZ[âˆ�³€©[LIaûg�1õƒeœÉ.[nHviÎè7ç2ëÙîåK(™.±òõÿðøW[‰+íã*Ùà×óI¾ûù#F^¿üeE[宇ÖÈî÷2nQ&n÷-"æ�ѸVpÖ–3ÙémŽImy÷ðAÞð¬E¶¾AïÑ`ìõ5Ç>Î`Ò ·Ù—­¢ ~’–£;ã-B·]³vD8®`CŽ ÊU¢Ng¢†y"Ïrüœ�][dK³ðæØ®ÜE�j&úÄiòÇúã¤dpúLRI̯g›¶4¬Ž?l™ØâtÒ�îæëo§Ñ¾Ìò˜žÃ¯çRÑj¹&t� ö/Y´o<ŠG‡­âÐqXÌ—Y³æ$“›µ«põ°öÇTHNH.zþJØú†àp­¯:¯n<úê´K±¥�—~ÅYà­Ý¯ú¨ªŠ¶yW:{,cyªBÎÁÝ-èAw{P3ö³í”©0I[‹®tq“*™È˜‰Z±„CE1Ý’MKz}}‹“Ó9ÐkêËL:ù0ßFQU=Ç—¯ą́GhY+ÿgkíS÷FYêÆ®Ö#{ôä•ïà?ëg–í‰æÊöy»¤ ÙÁ�v½FòÈ”»KýnTòóòKŽa¹|€måNÌHêñe¼ùt †ïÞb¨oñ’vç.­VkÒ4´â¡d½ÚÅ’Ìö¯^áÃâ<’ÿ!�2.¬’a­i?ŸN|›MÆRv±÷¡ÝÀñ<ùÈPš–\ð©]ª}~V¢�_’µQÂÖæúJØØ^[tQsó¸Qú�@`=¹¹…ÕTrss‘e³Ù\"6\¸p�ÔÔ��‹BJ{/ ´:™™YuÖŸzÓ‹s*¬^µ€'Ÿ{‰Ï¦¿]_ÍUˆ¤³A'�š}ŒïcŽ~ïý¸œõÿ¬c霗¹3X‡ñÒ*^xôÎTéó¥£íCß0wÎÜÓHhi9ñ3æÌ�ËÜ™�3ùá{ Ð(d®ý™e‰=A-\øk1L`Óá&DT­ãXÝoý>Þ5‘ïö§¡k8„—æ,cã–õ,þz ¡ÇÞfԃߕ­€dƒ­Mý,u+Y™…€%'\Jû�ªYl}yw¾¼”³RkÆ}ð;öâவüüöhš)gXüÂFL?оôÕþ~¼?÷~º•D÷H¦Lÿ‘¿V¯aÙO1©ƒI;¾`ì ÿòO†Zû¶®GrçÎñÃh +d®_̆̊62s|ñ¢Ì¶�&0®xÄle$;;l%PóN3ëåO9éÑ“±S¦ñè˜Îx ¥_p+±kE‡æºÂIšjæLÔ9Œ€%6ŠS¹ aÓ¼ÍuN-ZÓH ¢?}‚3&ÀtŽ“Ñ…Â’í›Õ¼V¹¤%|Ä=´½®Ö<–K�Ê.+$l|pÊL'-½ø_6Á ±•ÒOœ(WF­VS¦�wƒ’Uà¬�Ó™òúwüºvÇ.e`P%Üš÷d`ÏδoŠŸs±¬Ý¯†èZÑ»‹[a–ÿ¬ýl;®T²ìæ„AIG‹]ñ©lò¯\áÀ¡¤’\móÞôñ¿îá$ûÓ£ûµ•bKÂ1Ž$T¯0]åXiŸú¸7*¢¶v­f2ã/Ÿ–�¡ÜXFE5f“’p‘3—2K¹·[ÈÍ-¸&tK:¼"†ðð“ÿååÇÇ3¨© rá�%mßÎÛENÑÆj~,ç‹®§Ü Mܪx9Õƒ]Ô‚ó,yû^[y±(Y£ŒkÄd>˜Ö¹Úá*’Ɖ�6�h×"„¶¥wú÷Ú¥zçg%Šs©D)’\þ˜eþ¦XªJ!jDq¥†ììì’ÿ‹3ÚÛÛÓ¡C._¾Ìˆ; ¤¤¤Ð¥Kt:]IˆÜÜ\ŒF#f‹…øÄ„Û£ÊÃÕ«q¬Y·šD“™^C˜¹p#®æ«´h΂E+8tè0�;uæ×?—òû¯³ËåV¨wd0ÿ…ßïø‚][ž¦E‰€:ˆA¡Y´<‹KGV²öòó4­ìá/ÜçêyŽ´ÞfIŒŒ÷ñ<ü°oáàÚäÌ„¦sùèÌ~YËž-«ÔX¢ùkÉ!LØÓïÁq„ÝèaU¿UR—~ÌÌzpîËô +xªIÑåí3�‘ÃÛ3¦ëd–'© ËHõ19UÓÙøÓ_ÄZ@I÷F×NÔtø3žšqœ]Kž^¶�/úº•¬®uˆÄ�í&ÓéîŸØóá+ü6a5­vö~Êó?^Àdß…÷×oäÕ6Åqwr×ÈN8vÄ·ççñÆÜ'é÷b³Â ÍV¶UÎýÇ3Òï7æÄo`ɆLîãVvUÐ|„EKÎ`–ìé3a �äÚ�/-ZÀr~! ?Îú£ÑÝUÄ9n$7"Ú…¢9p3 ¹§OqÑÒ�Ó§¸Z3ÚºÎȾ­÷’‰JPP2Ïp2^¡�á §óЦuºæt ·" �äAX˜gy%Ü’Bbrñ,P%û'Œ¬bYÏ’x•x34®jÕÎêcÊI�ÅgÙš® *¹\ر„ow,IÂÆ5ˆÖºÒ§ÿ†v .ålí~5ÅŽ¶=:ãºvJ&{vEaèÆÞ�Ç(PAÒ…Ñ;Ò‰ãïnNàJBñTAÂÞ? ‚JG2¾þ>h¤³˜U@I&>ÙB…êª�•ö©�{£BjiW«QIßù%ÓÞ^GœIEÒxÒiÜÃLèÕWs Q›þ`ÎÊ(⎭ã›�ûîL^‰tCB"¸×Dil$4îá Q’”r䈞>õóÏQQÈØ³•ƒ=éë–‹ç¹`,t§×…6!´ÊËZ·v±$ïfÆk±ô\QX‚¤Å§ÛT¦¿1ŠæU命ïÓ ².p*:™‹ûþæ‡}kX¸| ~ò�]%ø—Ú¥úçg%²�¦°Ü%P’)þ*&£ùÚG�®æ‚±@ ¸!Åyò 0™Í`ggWö0yòd233ùsi4aaa<ðÀ%Þ ªª’““C~~>&³™„ø”¢¿×6ôÁê!IVVK—/¦{dw|uäÞn�ø4êHŸÞýX´tŽœ½p…_ÿ\ÊgÓß&!>¡0!ã-@•òà›SKMÊ qìÖ‡ÎvX®pñr-´T];œÔ ìùe§¯;”åìR1�Ë&ÝXm£×¬ßùl_½…UÂuÈ4&5)«iCÆóáÓЕOeV{,y$œXÇ7� àþ.b‘Ýé÷âSô(é·‘½¿þÆ)8|�Wú\7)GÂkè Li«CÍÝ‚W‹V“Œì]°�h38 |œ©×M@$×><ùÖ3LylüõE%ç¬m«zsÿè`4j&–¬'ó:ó™,béy3’s&Ž.¾¶µèCQÍi%ú¾ò2‘BLÜ6ÈFDPìÝ«$œæT†�³Q ñdZ·*ŠÏÖ6¦M ûÂûÞr™³Ñù¤Ÿ*@Ó¨-nVÜÛ’N×{'¨fL–ê?ÛTS¹¦mdý1e¯¼õåKÜÛÖ›2‹ƒªŠ1ó2‡7-â‹WaÜ+K9[píkk÷«)öm»ÓÕYÒà\îqöÕ£"¡mÚƒž~U¼¥T#†’ø; »ŠsËÈ:›R+FŒÆ 7«VÙ§>î�J¨•]­Å|Šßg­'®ðGHƒAÏññÔAtiFó6‘Œ~æ]ž‰tBTS<«ç,'Ú`KØ÷3ù�‰L~`�([áÂ.ŒQCZ•\CUÇÅ$PÉŒ¹PX‘ÿÆ�¨è'Yšº²‹ñÊ:Þ|ê–‰ ’ìJÄýï3ïý»iîpƒNh[pßkoðÁ»ïóÍÜßY6s2Šú”{fÌ9@ÿN»Ôìü¬DvÆ¥¤¾«JA�ẠT ú’¦ì\³ê�àÆ‹É))hµZ’““±X, †’ Í›7göìÙüñÇÌš5‹°°°’ïôz=&“‰¸«WÑh4¤§¥¡–­Ãj…mÛ·Ùµ�5aݹ‹ì‹NÇd2Ó(´1]:v#Ð?˜ýÔI'k‹d×�ní+ôèÜqw–  Ÿü‚ÚL´5„�ŸLßw÷³þøoüvøE>êT¬ÍZ8½t1ÇM2 †Ob„WõŸ°5ê·å"Q§óQÑÒ¢cÛ îh:”–oîç¨U÷Ž‘Õy¡{¨ü7ª¢ ¨Åñ´ôí7<ÖäZb$Ë%ö--{F–Ï‘  #²›/šCqÙ{ããAØY.±ÿ`´4íØžòsk Í&|Æì ¥þdm[•ž·-‘÷�¡ñwŸpþŸÅ¬ÏÃ}%I2Œì[ü1�;'2¼øÚÖEtèÛõÆ1ÒA}¢ ‹ ­óâ²TóN�‰Áû|aÅɶaÅÏ=[Zµn‚vó1Lª‰Ø 8‘|¾(ŒŒ_DU8UI…"ºl�ƒ­ F�qü žlWù ™¤ÁΡ²/ëæ˜ö ðÜWw0õê)<Ìá㧉:s†óW³1ª*¨&’÷Íæí_[òË”%ǵv¿áÐŽ>�œX¿1%ñû7ås(¯°‚Q“î‘Tumd{í‹í¢R�›W¡(kÊÏÇ\òZuÀ±¢ Ÿ¢”w‹Võ諈E«±}êãÞ¨ŒÚØÕJ”øcN, @¡yû6e3ëK®„· A»³°T§%î'2TÂܰ¾ În®h$ ·ª£QÌ\8[xÝ$5 ºqiÀ:°‹%qï=ÿ› æ$ûP†¿ðÏÝá_eb抑qiu/“ú-çÈŠ4Röîá´©3oøƒº½ìR÷çWÙ!½ñ÷ÖP¨˜(d¦g¢rm�LÍ!%ÍTRÂÎ×w¦)Ô9Š¢w%�VË™³giŒ^¯G£Ñ” _ððð(ñZ(F¯×cccÃÅØXdI";'§o#ë°ZPˆ¹Mÿ;b2iêÊÚÃÉôkåJVv&­[·aïþ=uÒÁº@rtŵ‡¨Mѯ¶ëö²ÿ=Lö*ÿ,<Ï¿ìâ­N} 'ˆæ(–,9‰IÀèáR_ýVRINSÞ~ÞzAhB›ÒH+qÔÊ•"‡Áø:]wd}—ã3Q4~ôî^žr/ý;•�+ ÄÅ>O}}¿Tüš5¤¤  ’5Ž4”â _®^¾•dK¾kÛª*Ô±Ã8ƶø‚÷Nndñú ÆŽ+ʬnØÃ¢¿.a‘½1q0îÅ']}�üðwr‚à6æí[Ù²zwª’Ç™ƒ[H)r;Ð6 §e‰Ë±LƒÖ­Ð#Ö¢~+ûŠJ=Ê.´mߤn3küò—áláï.?3ÙÑ §Úü„êä˜2Ž­éК>w(äÇâÏÏ?fÞÁ ÕÌ•‰{¸e#î¬Ý¯º8бgœ6o!Ûržå¿'‘¦ÚFôîQX�¡Òw¢&ˆFÁ8QhCl qJ—釙‹Ñ±/ôKº`i­æÚóPµ¤“š¡€Ïµ�•øhÎçÝh€SûÔǽQ)µ°«•¨z=úR­hp¨(¥“ÑTÔÜKìß{†øÌL2² õŸÀ€�Òï*…¤„¤k¢�쎧›J2çbr E$M0MU'6¤–v)8Íü7¿`c‘˜ ;µâÁ>`J[—JEwñ_ymþ^’Ò3HÏvgô_3¹qéó+¬å^ŒšŸKž jnì¿Â.ÖžŸÕÈ^4 sCŽ*·¤_¸@ªrÍc ÓEÎÆ×ÖÖ¼‰yê‹ÅBbR"ªWããÉÌÌÄÞÞL¦ªÝëôz=¶¶¶\8v �FƒÞ`()'Y[¬Ó FlmmÉÉ5н©;¹ 'éÜ(€‚ü|lll0›Í•Vs˜0þÁª.'öV¨Ö9ZŠ’¿HrÅ1 EnäõŠäÁ°É÷à¿d6W–üÌÆ�ú0Ì Ì'–°ô”mãqLêUâá5é·j@_TAW.ûn:{ìµ€U‚‚ }§båƒîeû”¿—WºöfúÉd.døÒ®‘Sù>«F FPQÍôúJFÀÎ4r�§ æâý Eñˆ:]õlam[U¡ gÜ}mùøõCl\¼–ôûÆã)�~çB–ÇYÐ�fâ¥|Bê ’�-õ”7S °ɉˆv�Ñî>‰ ±7’PT:зe‹2‰C5 [ÓÚI&6KÁtj3›ò ×¢%Û–´oUÇfd:´óA>{ãÉìHİ÷ …Ä¿²à„77„td@·`ª|"[{Lc<6íáÄ¥+\Iñ`ð³éRâû,ãà߉ £;²àÐ?䪠š,…+�Öîg%{ÒÉa+›rͤ$§  íNï (²/Ý"›ðÝÉÓ˜T0_ÜÄß'ïåé6׬©æbÕ¶Ä’Dˆv­#éRŸîìᆮxu×|ží»“¹g”o¡`¬f±wájÎUôP¶Ö>šz¸7êîV"{ûã§•¸h)\%?w,мA]®y)¨ÙD�¼\â "Ùúà!ƒé즟[Éok3z¯Ç–,åŒEGø„‰t¬ë*�¥‘ì°·+*’U ‡Šœø ²ÈªÍ´"ºòêWSùkà7œÿñ ^½û ³_':HŽ8;I€ŽnoïbÃT¿ê‰R±›¬B^n n7~AYÛV•hh6v�ß=ÄîMKX›v?°má ®Z´4;‘¥Í]/}nd|#"Ôœä¢EÅœ“](†I´ oTö…bÓœ6Í´¬ÞoDÉÍ!·èÏÚ¦íËWi¨5ZZEÄÊo9’¯¢æîã›w~Àá©»è॒tl%3>û“ÃY Hv´{¼3Ãêë˜Z'þšÃÜs&TIËq³/NêM l%=é—�³rÑ�¢’j2nÍ›æ*”¬ÜÏJ$ÇôîàÀæmyE« ZB{ö ä†Y™�aã¼üMV%)`‰cñ{ïâüÔƒ hê†9á«æÏfU‘¾¤ bäƒK&döÍÃiªÛÁQ£ j‡f¿ÆÛ9÷Ð+ÀÂ¥ÝËY°[&ÐKæra0:ªRôβ֮õroÔ‡]UòN®âçíñ%³šEZñ+[-à䪹|½¿è@’+G�%Ò«3:;±wG ©ë¿ä5�ÉŒ‹l„œÙº€Y»‹¼ƒ�ñèÑ�v ÙG2²ov®NAA!}ǧL~lwt Á©à ¶îädª¥hïDç{‡¦KÜ¢‹\"4 ›Ð¨š£Hkí¢flaþ²ØñL¢€ã?¿È?WÒŽg?^ýxÍögdÄ">;”�ŠBÂú÷xàr$}ÛáhJâÄÎí.N.*i îÙƒ&�\þv‘­â{**&“³Å‚^¯çJ\!ÁÁÕò2(((ÀÍÍ�´¬,É2‹åÖ{(M‡†•Äm�F²s²Ðj‘- À!Œ¦�2D8zà8¦1ݪp�2qbÇ2е¦¥5‰¾ê ]&=ØŽ/_=Èú…ëȸ«‹—žÃbÛ�Æ·¼q<]m�½ñó–á²…„+ñXp+מ)ê(§¬L6UÎ}ÞæËI+1ï"?<ñwü–�¥¯ƒ¶!�C´HÑf.Å\ÂŒ_õ\á4Á…®µ1b£c±PNPPMè±Ã^'Õ®­ ‡ÞËýÝ_g÷–M,]—Îø»÷³hU"ж5ãÆw(ÛF=õA ¸Є¶%Âí.¦]Sµ%]m®Ï+¹Ðºu0šýÑ¥î�Ê�c­]UòÎoå�…G©ð5­½u ÑÅŸ5�húŒ!ÒÛƒAO<ÉîóŸ²1Ñ„jNfﯳ÷×rÃ6h/MéZîáH·G_`Ì™7YxA�ªšI;³•Eg®ßÍŽFÃ^äÕ!>Ȩä\Œ&¾hâèѸ1 ªk,+í¢æ¤“n¼6ØU•\â/äVº½œÛ¦PTÒøs׳OrèÙÏÙ’dFU�¤žÚÊâSå:†cÓ1¼8¾¸Œí¿2dßY IDATÃ.ÈÖžŸµ÷  cÂs÷³÷ù_8•¯bH8Ä_?*Ó–Ö֓[9þ?#Kî\¾rb.^¤oïÞX,7..`0ÈÉË£�·7ȲŒV«­u…¨E•�ΆÔÔd²³3INI"9%‰¤”Dôú²²2Ñéj±¯kÇ]ÃBÐ`!æ·ü•X¹r¢\ù“çŸÅŒ–&£FÓá–ÎÜ44�0™Þ�µq1+×ÿÉÒh Ž}d¬u�®5hº!á­\‘1sz÷^RË™,—m¿/ãR}–ܹóƒÏë/aŽ™Ë¯o"«tû’7=z·D‹…‹ëVs²Â·˜Büþµì8Ÿqmò!ûÙ# -.oú‡SåÜ`Íy·.¶Zœ‡þ@’Z‹¶n„ÈÝ÷÷Á‘\¶®ÚLâ¶¿X›¬bÓqã[]§ËÕW‚ۛ’�¥_?²+Z—ËÀ%Þ’2¥ØeÚµmXO⪎àao1ÜÒÛÒ/HIÆÎ«C¦~Ìï !¸ÚRº5Ç”plóß~ýã"Cq·¹>tMBëL—QOóÝì×\âmí~Ö"áÒ©íì [Ñõ WÃê^ ÇV÷óÅ÷óÄ�áøÙkÊôUÒ8Ô~Ï~9‹OF…–Mš'¹Ñû™yyp®Z©äx²cý¦~̧ãÚàå,—OŸo(Iôf½}êãÞ¨Ü6ÖÛÕ:dßþ¼3w/ßÓ…P—ëÃ%t. ‰¼÷y¾Ÿõ ½J•,�\;òô7ßðæØn4r-»Ÿ$ÙàÞ¤'¼þ-sŸíQTÔB̹‹VFÔÚ$¤¿å›omà ÞûþsžÞ–@¹¼]\Céqß+Ì™ñíJyMý[ìbíùÕ‡VðõŒg¸+¼A™J+’Ö…Æ}&ñù7/ЯÚjŠ@ ¨ ’$¡Ñh &++ ggg.ÆÆ¢ÓéÊ%`¼“É„�� ÙÙx{{“™™‰Ÿ¿� RƒÉŸ¨H…¯Ë_?Z寧�¦}מ¬ß°ŽÄÄx:vì„‹‹Ká _UÉÌÊäðáCøù0hà`«;¦\ù™»;NfE2¸u~’Ù?½Ë=-\J) &’÷Ïç…ÉÏñkT>rà8þ<ð÷ø^3ŠñŸG <‡d¯GX{y¯×8Œ›™:€Y‰L^}•n`X:÷{alò;£>¡kIÁ†s|Ò½5/í“éÿ},õ­ _@ Ç6åþ%zCœ¹zÙÄÝœgá�rÛVÖŽµýÎZ>‘°Ñ¿‘ªmÅSk·óe¿â6M\Yþ8ƒ^BBv&™J#žÝ~šÏ#«¡¾×0Ù8?¦éöSBù %(Äý2šöÿYNª¦)O¬;ÀWý®Å8*—fsg›ÇØ�ëB¯6³úåöe*QœúŽ{ú>Éš´PžÙz’/‹b,ç¾ O»çÙ©÷dð×ÛYöx‹’`ÓÅ_×c2KìéÿíIÖ?V˜qØÚ¶*½îE¨© Ýd+lÇñÌ�Ûøê—tzs†/¿š`mnxí‚rxïZ´i«»q“Q0d$r9!�<‹'O‚ü\Ë–¼IÇT�9$%$’–cÀ,épró!ÐÏ Û¹z[¹ß-ÁœKâÕÒ² (6.øàípãI‘)'žØ+h\ À½‰c¬·O}Ü·ª‘Ì„«$fä¡W48yøèç†Ý�ì¢èI�¿JRf&�îÞºÛ^÷¾7½q![¯(…aNƒGYkaë&aÉ#ñòe’2ó1¨¶87ð#$Їÿ/v±öü¬F¡ -ŽK ÙµŽxáëT§©vA˜L&RSSyò©§1˜Íè žœ6 ¯ pppÀd2UÂ�ŸŸOZZqii$&&râÀîºk÷�‹££ƒU¢Bð“ßQ¬!XýëïÇ6oÙÄæ-ÉÏ¿âàà`Oóf­è×÷k €ôóÇ0rôìÜÿ÷…Ï'(¢�¼°·dsõÌA�IA¯Jèññ²ïí{Œ$O†M�ßÒ¹\ŽÍGö›Ì¤!åÅ„úÀuØk¼Ùw OoŠâë!­Ù=t(‘Á6¤�ÜÈŠ­9ôýê "^}Ž?+÷¬2�ã¿à½Û˜¶þ<ßO{“»÷Ï OQY 9d23¿XKŸGW²ýÕ^DlǸ�áøÙpõø&/ÜHtž aÉËݯ¹ÇjšNcæûkèÿü&Ö?Õ�vßðNh’�²fñjN¦«xö}‡Ï'_+_dm[7Bj0„ñC‚ê cëîO˜»ÿ-?¦dãŒoˆ3¾5lÍÚýn Z'|CÂjÜW�³?a-­»FÖÛ§>î�ÛÉ7ÿPÜjzz²��ñ¬j#šôŸH“Ztï–¡qÄ7´EÍï—‹]¬=?«‘±÷ ¦¹çMkP �G''î»o,³f}�‡·7¹¹¹x{yaoo�$I(Š‚Åb)“pÑd2aggG^^—ccAUpÇØØÔ�k¿Õ‚‚F£a@ÿ� è?°N:R �^ï°ñHf8�Y‹¶pæðf..þZÆÞ·=#Ç?Î+/>Hg¯úu�« Žý&s“ùôœJȘ)] ^Ñ6çñ%qxã%¦ÿ¾•ƒÍã l�o»¡<»ôc^Å#Ey2ëÀ»¥<šPšñ :?Çös³˜ööÝìû¢Îè{h»ý?á¥×¿aù¦y|°±h?IÆ10’Iï}ÀGOôƧLßìˆøï ¶û¿ÃsoÎåŸõ?ðÙ:(t‘mH¿§ßeÆûãi]ƧÖÚ¶n„ƒÆ�Àká�$eÜïšÈ]Þ• ¾ú �@ þ×�$ ;[["»uãà¡Cì߀´ôtÚFDàèèˆV«Åb±`2™0”* i2™ðòòâÒúõÄ_¼ÈK/¾ˆ‡§ç­y¸é(ù$Çœ'6)£ì€»(M‚=nO7ÅÜ Lm9„Ù -yóÀaÞi{ ÜÀT3ùYÙm]q³/[²ã.Ÿ‰¬4‡óæÁüq«ÜÓòÏs.6…<Å7¿Æ„5¬Îµ4‘qé1ñY˜ì½iܼ1^v7ÚÉÚ¶ê’Û¡‚ÿUþ7C�@ þÿ¡( z½ž¤¤d¾�õ‡áñiÓèÒ¥ F£±¤zƒÑh,É­�——Gll,sçÎå®#˜<ù?899ÕJP¨“�‡›Žì€w“¼o{_; 1?}Ìïq Ný§ñP››gb5?‰s§Ns!Õ•NƒÚáåæQ& ¸áð~Ž™@²£yÈ­¼ô2޾ÍhçÛ¬†ûépiE‡�›ÑV]r;ôA �@ ü›‘e[[[¼½½xê‰'ø{õjfÍšÅï 0tÈðööF¯×ORR»÷ì!+3“—_z‰nݺÖZL¸ž� ð¯@%kÿ‡<øú6ò4Mxúõ‰ßļ<æ“_rW÷霓šñØß;™9°ÁµÜ yÇøú�_¹b‘qp7w¸Þ¼~ �@ � öh4ìììðööfì˜1ôïߟ ë7°k×N’’’IKKÃÆÆ???éÕ³C‡ ÁÍÍ;;[4M�‰ …:A¹²†/fm%6v«–íâ²ÁŽ6ÏÍå­žŽ7µºNÿeúÄÅÜûÓYf�ˆàЈQômÙMf »WýÅÖ˜|$¯A|ðÑ* ý�@ Ám‹F£A–e´Z-ŽŽŽ<ðÀDî»o,&“ ‹Å‚$Ièt:lllJþ/êRL!(Ô Jò.~üôSN™%dçÆ {ù;f¿Ö·›=i—|¸kÎvÖ4…7¿ù‹}K¾eŸ !ÙùÐnô³¼þÑ+Œ «›Œž�@ �@ ¸ùH’„V«E£Ñ`ccƒªª%ÿŠ¿—e¹D@¨k!¡!(ÔÚ¶¯°éÌÒLöø„ÓÀþÖeÖÐÿÅ_èÿâdÇ_æjz>Š­;þÁ¸‹,€�@ �@ðÿ†úð:¨ BP¨ 4Nø6¾™õ«ƒÿƸü?-µ-�@ ‚[Ë-\J�@ �@ðoE �@ �@ jÌ¿"äaßþtéÜéVwC þ'IHH¸Õ]�@ Ü$üüüª½í¿BP8rì˜�àQ“—Š@ �àò �@ � ÆAA �@ A�‚‚@ �@ ‚#�@ �@ 5F �@ �@ jŒ�@ �@ Ô˜EÙÈÚc$;5 ½¶. pµ“*ÝR)È$-×ˆŠŒ�‹'.¶ÅÛšÈIˤÀ¢VÝ”ÖÇ «³IJH"=§ZìœÜññóÁÍöºŽ)—ä„R² 0K:\½ðo€ƒ¦êÝ�@ ÔŒ½ûö°ÿà~:wìL×.Ýnq��@ ¸}©wAAQdù:C( ì_¹†Óz™†wLbx3ÛŠ7Ë>Ï?+7q.[űa/FjpíKËUö._ÃCÕMÉîí¹wlW¼KŸ®’Ç•ÃÛÙz$–LÓu‚„Ö‰ ðžôëŠK9™H;³“�»Ï’¬WÊ|£qð§Mï;ˆ un&A½`&79žÄ,=ª­'AÁžØÕh•ü¤ Ħ[p jJ€“TÉßjÎùóçHNIÂÛˇ°°¦VC ”Å`0°cçNΞ?Mß~ýؾm¹¹ùôìÑ[ÛŠÇ�@ ü/sSEQ°±±©ï¦j…šÖ¿7s.[Å!¤w l…Gi‹£�ð ñÃ¥ïÙÑÛ2s=—v®dõÉ ,²=>M[Ò4À ;UOÆÕsDE§påÈzV˜†2¦W׆+*9g7±bK yØÒ IKšyâ@>)±§‰Š�çÈúUX†Ž¦w�äu‹�+»–ñ÷±t ö-ñ@‚k¤Þ©dFïaó1#͆4!ÀISÉߪOLL IIIhu2]»DrøÈAöìÙƒ���5ªÑ±jŒšOBL™æë½´$dYƒ�½ žÞž¸Ø‰SðïdÑâÅ 4­­DÛðö¤¥¥Ð<¬‹/fâ„ µlÁBV\ ñyÊ�7EBë@?G®—Õ‚Μ8Áù¸L $;<›Ò.¢ ž•³,äÆ�%êR:&{ÂZ4ÁǾj1SÍO"úJª‹?a~Nåú A1õ*(˜L&ŒFvvöõÙL­Qó/±íï�œÊT°ŠdÄÀp<¯³Œj4`PÙ‡výѬšúˆ%é;Ne`‘œhÚÿn4qºæQÐ2œæ>³hW™§q¦] ÎE¯mÃ%öî¹H¶FŽbx„GÉÅjÖ¢%�÷.gùáTNî:Jó1]ðcx� î0^æÄ©tÌ6tÚ�®:n™t3HJJ¢K—.¤¦'“–‘BHÃxx³oß¾úÌ'˜ÿÌk¬Ê®|2$iðmÞ…ÁwO`¡8Öá,DÉO!.MÁÝÏgmõ¿ªKzz:ÞÞÞÈÚ6œ‹9@›ð¶¸¹x�žž^ûÔ\¶ý$ì3Vcc Çï±öõH® 7 ˆYû-ï~·ž³ÙÔRÛê<ù÷Ù—™Ö÷ìÀÎϺO_ãÓõ—È—d$UErkÃÞy�‡"* Ôt6öolµeä'ßó‚Ÿ•ç+‚ÿ êmèe0èA’pppD’ncm[Ç®Õ8‘nÁ>°+#G५`;£#€Ö›j/**¤^Œ%K�_];]ž ãÞ"œ†â8gH!1ÅBDÑh¸ ö1ù*²[Kº…{\w¡lðk߉Ƨ×q6ã §â;â(*u…Z�O¾4> iêë\§ãÚb4qusC+k)0å¡×ëord<›w¥�ϵgŽª˜)ÈJ$úÜ%£¶ðã©=쎙Îw�„בí,\øóe&-päÉ_gpŸŸ\Í‘••…-�Cš¢ÕêÈÉÉ&33£n.Ùàߦ;}íÌUn–y~?GãM8:9”3($®ÿ˜'?ÙI:Ž4é;œ!�âNçv¯aÅîãüñöK?šÉs�œ‹„…«+>ã“ É„Ü÷ Ó'·Ç9i3Ó_œÎüçþÓ3t)·Þ£’±c63¶dâ7ìCëPï#yy´ö¸9Û‰ðÌa!?;½b‹³› K�àv¡Þ³Å‚Éh$Ûœ…ÑhÄl1#K®®î¸8»ÔW³5Ã�ÀÞÕë8šbÆÎ¿ ÷û’§¶j4bTAÒÙ`Sí·«ŒW‡‘<Ð<½ä„kEûiìp°•À `.Iøh&áJF$œƒCÊæc(Æ&€†þZÎ^( îJ*J �xY µF¥ #‰ôÔ, €jÎ%51�<�Þ®�•Dz¾„ƒ‡7®×E™rSIÍ1cçîƒ{‰_k‹Á`@BáŠá"ÇböÓ;èžzk«b´4õ2.?ÑPr/°ê³7ødk"çÏeÕ°Üç_O&5›Ó§¯¢PA¾ˆª¾jˆÉd$-5;;;ììÒÓÓ‘åºìíé0á :T±…’´Ž—¦ìBréÂ#ãÚ” ÒÔ̙ܽ½‹4é8õ+>Z"9xÈ0úÌý/O.ˆfùÌE �÷-t€ϦN¢wêä;âmõã‘‘+ØôýVÖœJ—že3èY»™ùÍ&Ò¼ïä³)q¶úQfàüŸ/3mnÝ_ÿŠ7ûÖ,Íí„’qŽ=Ç ½T+@r¢C§P\Jl¥’‚=‡/’�;M;u¦�O%ç¯dpfïIRÄ�&õ;ôËÑgp>ëP½¶a ²Sc†?v/ëw~ÃaS4QÑ&ð¯(Ç‹B~ÒyNœºH|z>&�n> iÑœ‡ÒvUÉK¼À•´(öœ5£ªz’bÎr:[ƒ­G Þ–xâ*ü.ˆP/û2‚‡R�ÄÙ㧈N̤@±ÁÍ·ám›ág_þ «æÄs.>|iäŠ9ñ$;F“e×�Ö¡XÌÞ q¯L�Ö“tñ2é& GŸP‚ÝÄTàß‚ªÎ%¹hô"I¨jurÔJ*¾™Ã®,{:>ó8CKbU²v­a[º‚&p�ÝJ™_•ä@›ñé»úmÖ]^ÏÊãiÑÁ 1œ�µ iÒ”&%;Èx7m‚g8wþ –ža”È%j6»¿ŸÉÚT/†~ðݬVTòÏå�y§h0ê^èãu{-x(]ûÉaÃØôÆ#'óÉE¼ñÖfò+äÀ±ÌùùQZkTÒwÏ`Ú;17ï@#%šogþÎ=δ¶×‹° ‰k?åéIŒør&=Ë|§%hèó¼|â1^ùæ~ ›ÁÕ$‚[M½Žr´šÂÃgçd‘žž†V«ÅÅŵ>›¬¦TŽ®_ÍÞx#6¾6¤#¾7P T£“ ’N"÷âaNœŽ!.5‹³„ÎÁ¯€F´ŽhM¨[MÓŒ\=rŒ83h}›Ó¬AÑ+WÍ#7_ÉGÇÊ:&áà耨y¹ä)PÁ¸X Ô[÷½¿ô(Ö®:Lºwgîîß GY‡ƒ Wnu÷Š0ZnPnæ"»¸á*K€ŒF.?!Q³NðÛgŸóÓÎ+ä)¥Gè²Cý~…WînV*aâØ�Ïñܺœ¢xñhþxõqþ@&hìg<•õ/VøÝWü1­Uá NÉäÈÂ/ùä—]Äæ+eâÎe‡ úNzžÇ´.ãAf::ŸÇÞØŒ)âI~�’Ã{ÏÿLT¾Šì3ŒÉ-w0KŽ}_cé[}K­J^C‰_ÅS¾ç¸Âäïç2Å­¶VÜ,Š+S•ºQPÕ”‹®T2wÎaæ®,lZ>̇ù—š„8~à8ùªŒO—®4«h˜áØŽî6¬ß–Á¡°th�œ—I–YEvvÁµÔø@vvÅERÉÌÈF�"AA%{ÿ<>_—‚×Àwx¢›‹õ¡QÌûb—=‡òåäˆÛ*d ýQ~3ŸìGûÒ¿©ý Ä•‚Ü<ÌªŽ¶“>ä‰ÎåÉΓÐbUÆržE߯#»ÇëüñzO\ÕTV¾2‰Ïç¬aÄÌ1”Ö¡•ä |>ç0£>å?­+6$7zN�BŸ}ðë‹éóíêY««¸)�¦ììl||ü°¿’3šÓ9ñÏzv^)@•ì lÝ ¿jˆ¾F£°$bõzUc‹³³Žr>Ù™IÄf&{î,­ú ¥Oãê”rTÈ:»… '2Pt>tîÙ÷â—®jÄ`T-º*ô ]Ñ—ÅÞ� öèì�qq²+dkìprv¦°º£åÖv¬FóÍΛP}ôgOrΤ"Ù¶ ¢éõÙãùë�טu(]@W7˜öÁîØÓˆÞ³ŒŸ–Ÿ`ãÌ×ÑzÍå­^nHhi<ä ^ ÝÏïs6q‰ú?4–ήÓÄXÙw…Ï`5�ó_àÙ…0:4bà#ãÒ.W5ƒ˜ƒkøuá6Íz™ó ¾ߤdÕW²±A'�±àÍÙ@ŒK8ýïÅÕ¡%=;ɬڶ’ä}ØšÞ‡žå?¸ºc§Í k1�AMD~›Šª2sýU"›Ùuì2F‹…�'µ­ÿ†ó�ñÃì-¤ÉÁŒŸ6ŠÐÒ?%�èX=*ZB‡PñeO£Æ�h¶] ñÂErÔ¸¨j¡."IeÅ�¢Ïj)AOÍ=Ĭ¯Ö’èyN�¬8D³Z(į�Ïò«6t|z�*ßÒ’ŸJ\b6н'þ¾®×UÈ*‹9?�„älÌ:¼}=q¬ÅÏÊ|>Š3ÿjm­’—“‡*iñiNëVU¯>)‰Ç8¯!ü�…6”<èÒ% eÖŽæÜKP±a•Ö=‡}.ÙñŸp*3“äÞ‹‡G/bûüÅü°uöw7Ám‡Õ‚Â¥K±\��#--[[[ CÑÿzlmmÑë ØÚÙâèàH^~†¢ÏÎNNøÒ°Fí}?wžµ]-B‡F£�¸-— Ø8ØcÎ/ fû¹£c…™‹Q1 …/f� �;õ$²u ®ºÂºòÆÌXmÝÊ¡øt¢6oÂÃó.ÚºUõÈ7‘rr#«w^$Wr£e¿Atô*u)T•Â÷¼Œ¦ eB’ed@Qn’C¦@ ¸ 0 ·UÂ[K.—®æ»¯:ÐbÜd_—Ærv5‹Žæ¢h1þ�·™ví¹Û®Sg‚M“ùïÊd¶,ÛÎã=Fà%ËøD `˜_ëæmâî´î7„%‰«úÌçñù’ ÚÆ~0ƒ§Û]s9nÞº‘aŸ2éõuœøuë~ȯ¢}e-@‰ÛÂÆ€Q|5ÿaÚ/³šƒ´šŸ/aí–D†ÝãWV@V®²eë9ÌØÒqP¿2+’‚ÛE±�žžGÇ»BðõmÀW¿n¹  ..›ËÊ«*ý'3±Õuñö–t’S��ðjàPÉ„R¢�—'2ÑXÒRHQÀÍÑ'�„’—K®ŽÅN�¹9äªήN%ÂÛ�y_±2Á�oM¥·»�+»Wðçúƒ\H3aëF�ácÙÎëÆÉ-ø{å Ž½Ùß»ÔoÃÄÁ/ÇóÔß ˜:çuBÖ~ÌôåQ¤›T�d"yäõ—¹¯EÙó3Æí`Þ7óXz Ž<‹ Hh�ƒ‰¼{*Ï>Ðߢ0ƒ¼£ßñðóËH‚Ÿ>Yêw§·ü%&}u·ao1!ã}>ÞQ¸“0c,‘3t„Oû‘Ùcý+YRÉËÍC‘p¬†«…’žBªêD˜G±¥dÜ<ÜÑ(q¤¤«ª ©›¿eæ>'F~òÚU¹Ö¦!äΡ´ÿíKv¯ÜD|¿ÑˆgŠ@ ¸Í°ZP¸G``Š¢�ŸŸ�»»ùùù¸¹¹}.ü¿iÓ0Ž9Zò900ˆK—.ÕXP˜úÈÃÖv”Klüi §M*½߈Á êìAÜ?ËØ›À¾u[qÕŸ0§Ê^n#™ÒZY‹N#•ùÎÆ-”nwj(X´š¨œŽE%ÞݯâU%‡˜]ëøçd &�7íÞI÷àëêLKEB‚bÁRÅ¢¨b± ²¦’ �@ðÿSQÈÃÍqÅ.×:gþ‡sK=µT3ù9Ùä›d\B»0þµIü§ãry]䆣ùdnÒ³m i|ýÔÄžˆN-±_•DÁ•‹\VÀ«Vg'7üÃE3ØGŽåÁrñËnÝÆ22l#ߟ;Êú�© U4’@”è0~á¥'Ú0†ÜÙ”³Ïpbý&.Ý=�ÐÒnÌW¶³ù¼º0ôv‹ÜUQQU¸�˜ËÉØÂê¥~½“Ô¬ü°è,F›Üÿ`÷òÞj>9*`‡}¥Ëøvö6Ea�9ä©€ma2;®\$ÖLQž(…ô˜ÒU""yGäóU ¸õy�§z¹rõï×™òù~Ì!]éáMÊáµ|ùü.ξý-¯õt¯r…Ü»›í—ì{õ ³SÙ±’V«5›CóÞe�Ú‰ÇÞ„PG—wýÎ7 w1ó£´�ÿ0-ŠF¦JêÞ{æC6å†pçcï1²Cöù—Ù·ìGæýú&OeÈü§;à$I8BÓ—ò IDAT¶�Ì«cŽòÄóùìï.|9¢PèS’6ðåG0Žä•©] Œ}�WÝ~æ“U—ö4urÅ­‰{¿S•ܼ|TÉ'0“—‘N®Å7çòå„U©¬Ø+.>•DÓ¤mcÆw{pú!�¶­L º†ìÑ•Þ-uì?¹ƒ]É£ã+ž*�àöÂê§’ÑhÂÙÙ‹Å‚‡‡‹ww�2Ÿ=<SÛh¹ò÷|–ÅooOøƒ/01ÌÌ�yß²:Y%�¾›Ë}Cƽô0µø´êA÷¦îÈȸ7éBß>=éX•‹€Rò€…˜53yôpŒº�»F�äŽòô·‰É¿¶µì掛”CFVñÓD%'# Ev£�»j[¾›Å6»;yþ¡òöÍçùI÷ÐwÀ� ÿŸoŠ+Â*»€l:ÏÑÓ·o¸Ûÿ±wßáUTéÇ¿3·ç¦÷^i@BG¤ ¸ö¾ö¾E·èÚ~îê{ÙÕUÔµ÷ " tH�PB é�ôäæ¶™ß �ÀMHBhz>ϳÏîæÞi‡;gÎyçœ÷‚ðË5à ‡7“///ZZZÑh´X­V´ÚŽÿööîø»N§ëöÿM&Ç1ͶSDÂèn>ò6ßƤ¹S¨ÿr…Õ™|·Ú“_�—Ø-yQöífvC¦ñð“][¡j[1¿]Áަ�±Ì™“F„[�MÉ/ Zì47[Pqµ´JKS  õð¤ÇÁ‚ œ‡“¹�6‡…Ó7,IÇøß}ÄÓG/©Úi©ÚOúªOxíÝoyñþMlÿýó<9?¬ûƒÆRÎæo¿bÉÆíì9PFm“»Ò½Ã6(ïß”ƒÃÄ�ÂÏâêå®÷êhl@EÅZ[CÓQ£"$ƒ.*WÙoM\LÆêRV®ØÍM‰)ùœ…¬^w‡ìÏôóÓ0Æu§Ô¡ûØ©¨tf 8¹÷¶5‹Ï–äa—‚˜sÑx×Ë4ÊZtZ Nl½4ŸœVGÇtI�¾sj‚†ØKî嚟þÌÛÏÜÂÂOB15SÚêÍ9÷ßÂt/+YÿyžÏJÜ9çÁ»™í/ãÌÙÊÖ:\4ƒÑ�É+�©&¾_›Áæòëˆëq�“’¢2’;‘Q=¬P%éH™sÑ]+9˜˜Ò¾Fêˆ�Á‘ÇúŸªÀ}&óÏñë¾/9„Y³†óï¬,6¥×puDç²Ù†x®ûÓµ¤ßý¯¼¼ŠÄ¼¼ÞBÂõç¦]¶ÒAK« ÕYÁO« L�s-ób}�›ŠH_±ŒuŸþƒ;ö7ñê¿.&Frðp’ýlؾ—ösGcT›Ù±#5âbFxAÃÆWy~�Ž ž¸™±ÍKùÍcŸppæ}¼üÑÔ­x‘Çþñ8^‘ÿáæ¸®¤!4*%”W¡#F> ‚pFp@ÁéTÐh4ŒJI=îw§L>²ŽÓéÀé�¹#zHø'{âå.�¥•–Öžj…––f:Vqðèl§HæÜöâë¤~ÿ›óë°›f“rîyL�÷ƺ{1ÿú²ó¤?ð»™þÈ@[EÕŠ†a¡A]:­z‚ƒý‘• J*œôœD¡¡®U !À·§ïè ô8fú‘Þ CÂÉ¡æ¡ÚVJñAÜ*ØðΛì9jwΊF48)).ÇÉ‘sÕÇ^ʃ7epÓ¿Ÿãö ê°›xîªx—mº¾Ñ0lá}<4UGdêdFim-Z8›wþp/¯ìx›×ÖÍäÉY^Húd.½j+^þ'÷9g1ܞŒ�F¦ÿe>CZ6ñäKk�gÿwŽs£ü“Ud1–n›ÅpO ®»†ËfÅû¸!nX·ºÁ×OI¡î`NPá 3à€BTT+V~ç"8pd˜ «¿É²LÜи�ö¤0„Mä‚) |¶¾ˆÚ¬•¬ð\ȼ>G^*5d|ñ 5'^Á¯Fy;b@©¥ ¨  ¯À .#,Øø=UvL“¹è¼áø÷Í¢LPt$æ�»i-ΣÈÓe éjÃ~öU+ }Ë; ‚Ðg&“ ‰êëšP£�Ì%VsÙUlãT p:UÚêœhå�¾u;™d'OeÄs›ÙÔ²ƒŒs&êYï>ÇÇyVä�Y<òÌýÌ ëÞ�²gäËï)  1»u:’ý"/,ðÔzÒ8z.s×ñNé�|·¥…IÓMä­]G‘¢%völ’D”÷¬¤( ªªâPÔÃSNÞ [×n¡I‘ ›8‘¸žª9�°` T[©ªl@!ÐE‡R¡²¼'Æ�PºåC5„�6ÿZÒº~ÝšÃ;Ï|ÆÓx¸w6AÙ±µµ£¨F7c—ûEÂàfDR«hµô\qÒns¢JôúžF`j�{š:Ú…ÚÞN» jë6®¨tY³ºûùaÖÔ5s.©of±¡Í@Úì 9βà½3™6›HWc¹ä²É¼·k5Û¶îÅ1k<:d"<Îý¾æë�ùTk“¹ñ X0FÏæ§^b9³øûíð’ì.(F ¸�˜C9ZôÄ„I¬(,¦UÖ}š–Þ€•†v§#sŽ BoPHLH"1!i0Ïå4’ñ>‹9õ_²$»Ž¢—³Ás!çFvΫ“}‰s#½ºžÊ̵d†ÌelP—¾ÒÂ�ײ£Nm#†‰–ÛK3XŸÛ ¦!L�‘܇`Bmè’ö²©º€×ç0#¯CÛÚªÉ\¿�*§„)6…a>"œ 'ŸŒoD8Ûê¨Þ±– ÆÑ ñÖao,a×öBôaþÈêqQTŠ¢pnìBt:Š¢P__R�wbìXÚ;;cÎB6§W¡ %åW¿fvØÑ­|•¦Ê Ú«ø4Á„j‘JT”WáÄop×IÖ&pÁÜ8>|=—Ík2hžÌêu¥(ºa\0;J¼A%$Q¨]ýOýÐ@ì5ÏñÊ´Lî½ë¼øÌRFýã"Â2€ÌVÃÞ{)V#˜2>ú˜öV{euª„·¿o�SOÕ–L^y~öiqÏï΀€ŒÑ kgÎ-ÕF»]Eêdèäln¤Y•ôòÁJAÎ8" Ð•ìCò¬YÔ}¹Œìú2~Z¾¯EÓâ&�>”I ᓱ™m{K©+É£®¤s;I‡GH£Æ�cd˜ùHe¯:±Û:£üŽvš›{È«·tékFsáB›6¦³§¼Œ¼Æ²Îó4à;†É“S‰ÙaÐI^£¸ôöQ.>1:f×§XhljÅ.ñðrï\:l>wv´%:ùZîž|¼¿õÝ�!C2dÈÀ6>K 9>æù—~¤Q‘0�šÇùC:[ñrÁ�2Ô8Ø—�CÛÌÔ#�sG5_~’O›üñ”Ëi²6Rß®‚®£~“4šŽ\Ž:jëèÒaïù3™è9óóÑól)ü‚ç>žÂ3WÇuëX‹–ðä/ñSc0W¼ð&¿Ù¿±Ñ²ÿ¹\8á 2Öf°øÕ¸3ýü©øŠjù¬åTœ8«Ý�ÃáUE9IyŸÚP¦€ìN„gï?è\·œÿî[ÏËϯ&ñO394ÈGmËåÝg>$Ç&á5íæGöÒå´åóÁ³‘«Íý¿�GØQ_ÕÎã6gí¤F‰%Xìùdf7�ÏdFEõÖ+ׂFÝGIY ê(ï�¿Mׯ1uB0}žÉ’•åÌ\Ú¥#í¤dé3<»=€E·\Ï9�£”êxê¥õ4Å\É?¯IÂÝËŸ®ú‘[ÿ÷:O~1Š/�DKç*Ž€ÝÞ‡áÎ|>ÿûÿ±´}÷¼úWEu Xóùìó Ú$_fNLpÝ V[ÙúÆ ,±Ná±»¦t©´„E‡#m,¦Ä n€£Œ¢2ÿ™‘G%ÚV¨*­ÀŠ–�ˆ`PáŒóË(ÈQ̺ñfõ廯¦]yÓ\}¦÷'iò|’&Ùiml¤Ùb­³§Ç,F Hf’ÜNò œºÞ/‘i ™ÜÖ@}“‡¬ÇÝËÇõñA85´&¼|{Tüóe'ó?7³è­£Þ�ÚÚhjl¡Ý©‚$cŽ»ˆGþ²ðHþ69„éç¥ðÖžL*¾ù÷´_Ĭxw¬µl[¿Ží¶ <ò�4VÞý,Ûùø•ÏQÒ’˜4m8~ž‘DùȤWUòÕ¿£ulx�ãökÇãÝÛgÁçsÿÝéÜñôOlý·\›9ƒóÆÅà§µRS°�Õk¶QbÑ1ïN®KÀDkÉ“ÉLÃoÝR*+Û‘ýÎgÞø£Î gƒ††š›PUò3S\XJIU#Áž¨¨456ÑÐЀ··÷ Q¡¶º» ²¯?=æ0+Õ3ì–EŒé5»¡L`bÒòöìÃ6oÜ $CÔ“råMÌ\÷$?¼ò'lú5¿‰—³Ž}›¿æ­�¶Pq%7Z–K©`é3¯°¡5škŸ¸šá†Ž}$\ù[®ÙøÞzó)>H}†ëbõ¸yû`�ä­ú”¥Á©˜½â™ž亣nJãškG³î¥müû·÷QtÉ\ÆEz¢6ðÓ’/Y¾ÏŠÿ9¿åƱ®óÙ´f½ÅÓK-œó§;™Þ-Ò(5u o¿Ë'ïbìUÑTõ)kšÂX8ó¨à„ÚFÎî85ŒHõ‹ gž_F@a°I:ÌÞþ˜«]ÑZ7oÜNáA\Rio¬¦²±ËŸ$ YkÄìNìÐáL˜~‹fŽÀ¿Û`™°‹þÄ_«þÎ?>ÛÁîåï°{9H²‰àÑ xâ�¿æœ`ÁW.g×Û;Ù÷í+üsÇ¥ügêpütÉ\yëL¶<õÅ…?ñU¡„!5НzûLÒ1ïûÄË‹¿dý¶oy+óÐ9˘†3ÿÆ›¸ãâ”�*0�žËœ°ïx¯D%xúÆŠ9hg‹ÅB[[žró¹øùù¡Ñj¨­©åÀ�xxzÐÖÖ†Á`ÀdŒ`¢J[s * ›ÜŽ“ó ƒ!þ žyÁ‡W^|›¥ÙÙü°$ IãAÌ´«¸÷ØsdÂQøÿ|/yä�Ü¿ ¬‡)>&Ònÿ+¶>Å+ÿ�»ÞÙ-˜´+æ/WķѨMœÄDÿ/ùrëfvÛÆ‘z eÿé<ô¼–�—óÅÛO°öÍŽ¹’Þ›¸)7ñÀÝ—“lpRòõ³¼”n!æÊßqÃð.�{}×ýþ2Ößû>oþóCÒ^ºž¤± ¹rÄïúš'Y‚×Ü'8§§€¢=Î+æ7xáíå,yýi¾V$t^1L½îÜ{Í$\¦hhÛÉâg—Ò<á~~;Ãï˜ýË‘óÐï‹yøåßqþÿd÷(fÞó7$5y²�wØ�Ã&0¹·Ñ'‚ §‰äã¿T¤ŽÇJñ‹·õúåœìm¤N˜ÚëwN†W__Ìí·Ü|Ê�+‚p¶Û¶yI#�¿¼ï©¤Xj(*¬¦YÑãI„�¡Û[7§¥�«//S·e�­ÕW¶‚›!AÞå¾}ÖyT,ue”T4bQµxø…ìAOÉèû¬m+ÿ¸þÏ|u0Š›^{�[†žš•>„ÁÕÐÐ@}}=›6o¦¦¦†Ö–VEÁÃÓƒ€€&N˜€��Ï ŽP8*íõe—7Ð.› Œˆ Ø}ðß)í�lr`òöŽÏ7Šƒ½‹oã¦÷8ïñ·ydªû ¼Qw¶ÕR^ÕH»dÂ?8ŸcoðþQ­4V×cwóÅ×CßÇiZk«¨j´"™| öqQÏ €³�ú z/Ì®ò¼|û.z;±·¿Á«—‡‰)‚ œ"ïù‡bb„‚ ‚pJɦb’zü\còÆÏÅ+[�9�˜Ø¶éå³Î£bò� Þ7¢_çÚ;…²å°²FÅmÌ."‚ g+ooo¼½½ Åj³a³ZÐ ôz †�Þ|FŸpâ}ÂOêQd£ý^™VKÂÅWsîÒ'YýÁ7\7ñ*b¡¥©qó'"ÆÿÄwtˆdÀ+(¸Ÿi1û‡1dO�¿ ښÇmÅx>7Î ÁAÎH¢nA„~SiÍy�Çgc‘C¹èºÙ®‡= gƒÁ€§‡þþþøûûãéáq†Î|’ï¹Ü}Ë8Œ{?âù¥å8�¿‰à’�¼�ÿÃ祾̾ãÆ‹$Ü‚ œ¡ÄAAè#¥z ~µƒŠªÝl\¿›J»ž¡—ÝÏÍ#©I:áh2!çßÇY÷òðkÿà½áÿâú¸~uø…SiÍz‹ÇßË'dÑü~š¯HÆ(ÂKA¡�Ôú],ýèc8%dS“¯þ\›‚xy(]È~œ{ÿÓüûÜZ-80Šg¿ØiÒ$sËcç�8. /Q¿‚põ» ‚ ô‘&îj^~w6MN=¾A�x‰%|Á5}#'…œî³8Ké 1 Qz‚ œ D@AAúJ6â‰ßé>AA„3ÀYñjetJÊé>AAAAº8+ Û³²N÷)‚ ‚ ‚ ‚ÐÅYPAAAáÌ" ‚ ‚ ‚ ‚ ô›(‚ ‚ ‚ ‚Ðo"  ‚ ‚ ‚ B¿‰e#AAøÅÛøö�Ôm§µ©{{+ŠâDÖhÑé xÆráŸ8ݧ(‚ gPAN?[3µMí¨7||Ì'ÿátª�w&ì²8Kʶå` EÙË)Êü”šâ]´·µ°ðâ˱©zü¼=Ñhu4·Y1ê5|øö¿yûÞp<|ƒð Œ#4i&æßrº/AøE³ÑTÛD;2f/_̺Ó}>‚ üR�©ÏùAf£©¶‘vEI‡»¯nš>lfo¡¶¡ EIï�¯·‰#›Ùi>؀ũö¾­_ßÞT*Ö¦ƒ4¶«hÍ>øšûðObo¡º¢‚šF I‡›Wa¡þ}»¦~RmMTUTQ×lÁŽ£»A!AxÄlAøeh§¦°˜Z+è}"hDêá›jK9yeÍ(/"bƒ1÷øÅ6* Jip€1 š_=¶MÏñ«G×b»œ×Þ¾�'ùédÛò"—?¼ Ë):Þ)q¸\%ÜCb‰ðì[==Øe¦—möŠçÉÝðN«…ˆèh’ãÂqOMâ“ÞÂ7 „Âí˰Ô;ÐkT,-v¼F]†¢¨\rÅõ´µ6Qð «ß¿� Ü�—_8Wüc÷é¾$á—ȶ…§¯}Œ•í!\ùÒÿøÍ™v£ ‚ð‹1¨µOSS477ãp8Ðêtx¸»„··÷`ª” Ò¿YFN» 舞q5&ºg#•ºìïøxK   ™ÌÕ Sð:Ô@v–±ù«eìµö¾Ù'•K/Ÿ@ «v�³‰‚ô5¬Í*£U‘ñO»”ËÓüzIlaçàÞ�üðS.ÕíJ·O4n¡Œœ6“I1ƒ“Ci¥dÛzÖn/¤Á~TÐDëNDòTfŒ�¡�íUAÎVªƒmoüžÇÖ[Чþ†Ïž¹ˆ—÷½BÁç�qã›ûqh“¸ë/qm„ë B)_Ê£·½J¶Ó“¹ýˆÇ¦’ŒV–Qd©§@„Ð;ÇNÞüí_XÒ¤eòŸñô\÷ƒ?ÝüÂÊ~ë×Orá¢+ñö0ÑTW†ÖZŠÉcÒáÏÛ[hQe|=ôÈ’³ã¥ ×ʨ�™ÂÏE£Ñ2wѯY³ìãÓw!}¤´ÕPzPÁ'$Ñç[2ë¸:ÂßE€S¥~{&¹�L)LNé¨Aôç<ĪÕ�Ük\ú¥•½›‡/ƒkÑ÷Ø[[AÛýWjw*4¶:; Šr¤% Úš�$‰”á‰dnÞþ§úôûÉIþGæ†ÌÜóîó\"Þœ¢œAøå”€‚Ãá °°�ääd4 ééélÛ¶�ñãÇ“œœŒ‡‡ûó󩯯ÇÇÇg090²7~^M¬ØË¾†Œõé¹'ï¬ÜǾ“·746`;êsÕfŪr£gÍ!AßדPiÌýž¯×í§Qõ$f ‚˾gSÉq¦NX‹Ø¼é­Ÿ´ˆ S|ÿã%$ #vóW|µ­–]?î ñ²ñ�À³ÌYµ� {êqJîÄϺ˜ÙCÝ�t †%“´”O~,¥!'“½£ÃIqÕ¹ágBÂ{Ìx†é2ØÖ¾“ÍYVæN1ó-µq›sH^x´6±'c;- f»ܶ±}ëlª„aäƺ‹úC8µÌÞÁX,­˜µF$©õ˜ÏíN«Õ�Í® ‘%TÕIסŽÚ=¤Œ?—šªJÌÞ¡§òÔûOm"'§ …øÓ}&?o¢œAø”€BEE>>>èõzTUe×îÝ$$ű}ûv†Ž,˸›ÍÔÕÕ�Þ€n„Gèi¨¯%7·†Ô �=L°Sº/Ÿf õ£¸¡áدجA­}¿r¨4UV`ñˆãÜ™ç�¨²§üø[Y ÷PЦ"{cb²ïQÿpzBRÓˆÍYNný^ö”�%(\¡¥®�6èÜ}ñé1Á¡ü`ðôÇ˨R{ �F4!)Lˆu?ªŒd|’’‰Î(eŸµ†Ê')blŸ ü¬É�iLˆÕ°-§…m{°MIåèjÛŽ­ì´IøÏšÇ¸M±,{+;,³9çèÙeÖ]lÙaA•t Ÿ0æð42µ¥œ}eͨz_¢¢0ú{s9ûîxbÓ IDATÊ›Á-˜¡^8*w±që~M LŸ‘D׸°b©"7{û+°(z¼ƒ‡�<*�ÓÀ"¬ÙŸj«£`Ï^ò+ëh³É<ý‰ŒFb˜;=ÕÂÙf0õXö�?Töµ�Ê=ÛØ¶¿’Å€wh<©£ãðïs@½ƒ³±Œý•-(˜Œ‰Ä¯ŸÛŸ(³o–¶Vܵ&¤£†¶ZìØìNTE¡©Í�§›Eéø ûÛêrÐÉíXÚŒë³7‘�µ—’ƒm8 ÞD$¦0:Ö÷˜:§ÇºÁ͈7œ ·Àh¢|zÈV¨¶Su ˜:»„9(†Ho-JS9yÍàDl„7ZG#vf±»¸›Ö�à˜ŒJ Âíð¥÷¯œTG)-”ìÜNVa-mª‰ ˜‘ŒMÅÜó‚ §Ô ô- £UíxÜ:lV‡ ãï’D{{û`î¨xD ÁW5Õy{)O $ÜUkÍZÌÞ‚60Æ¢R´ÇÅžl6l*H:=ú~½`“ðˆ�Æ¥“¢ñÕô¥LT”T`CÂ#2Êu>}Ñ¡Zró-”–Ô¢„{S±õVì·aˆ;�ëgÇó0PfñígÔâÏ„Ë.%Í(0f!×%¶Ñ.¹Éѕƈ›A«‚ãxI)A8ûÉ!LÁsp0s+yÎT†w«;­d§gcAÏØÑ0ªþ ¾Ý¼ƒÍ{mœ“Ú½æqänek£š¡LL;2%ž¹˜[]$´ïx“;^�=åÞ½µ™¿Þÿ6»ÛTä EDOKÂG ( lÿø9þõÎ�¶)©•$d·¦ßp?¼l„ëúÌ•�ìOm%ç«xò�5ìovÒ­f” �^Ä}º‘©ÁÚÛæ$è±ì³ßáîWÒ>ò.>|tßýõ ÞÞQ‡ãð‰Jèƒ'rÏ“silß&¿)⟿yœ%¥1 ãå{û×! îþChkÎBôB#—wëð5µZ ‰GUš›àë©Cq:»MM”T� >4WÄ-tL¿Ž}Bej+gõâ§xþËlªmÝŸ½’ÞŸÑ ïæ�[Î!B`'ë­û¸oysçïj?>x"qù |xçðã7pœÐõ9ªØ°øŸ<õyV÷ë“tø�\ļ™i]î…žë†ùÜ8lo®iÆ<ý/|þèt—S\•ò%<|ë«d+QÜøêëÜê ¶Œÿrëãp¿•·ÿèû¿ÀŠâö#×.i𶈿>’Š$š`‚ œ¥•b³ÙÐét8�NTUÅÚneoNZ­æÈÜCUÅn·ÆáN€ 1 Ì ªª€½% �>6rm)ÜGa;¸%Å¡Íu™GAí¡ é .;ê=“ð�îçi7q°ÎÈøúùö0ªB‡ŸŸr~-Íë°DT|4Æü\Ú‹ó)¶Æ2ô˜öžBm~>u h‚ã‰ï|Õ'ëLxx›ðèé|Úë©kSAöÂÏûT¼?áôÒ3>�ÐwPR‘É–…áÑ]j"G[¶5¢h‡1zD #kcÐü´�ÌŒ|œ©I]Þ²;9°uÕ hcÆ11ôø#$½�6K_¼¶’ÏdfÍŒÁË-P[Ùöß?ðû�ó±¹ á¼[®ä‚Ñ‘x©õl]Æ»o`Õ+¦Æñ *TÖåtË¡t$j6q 8›©³fôëØ.SµŽµOßÇÃ+«QÝã¸ðÆË™52 oš)Î^Å{ï¯dÛ§ã7-�ñæ'á-i‰½ànˆIçý×VQD³nºœq^̱aÇOÞ<Àûjà××À�ÏÝǃßV ø gáe01ÆòÙðÅÇ,Ëþ”‡î·òô+÷2¾sšeÏuÃ0¦¦É,Y÷ Õ[V²¶î\.ò;:¢ P¶a9Ð%�Çœ¡µ”¬×"KàhØÎ¿ÝÉ>ß9Ü{}C¼e 6óÅß’½ûs~Ô›7^ºŠXmÊy u”m/o>üO¾Î·cŒ:—ëo¸�qá&¬ÕûXÿùû<ñ„‰c‚ œ-  7p8¨ªŠª*(Š8P°ÛíX­ÇYá¤SQ%/âBØRYJÁÞBÚ£ãè6Xm!_ 6É�¤„pt–\×{²Ù°« é$ZlcgN¥µ�X:7/†0"e1ރРT[iiSA2`6÷¾�p3»!jk ­ ø‡Çë¶�]­%ì/±2ô舂RK^~ Z"â‡öž¤ò0eÛ³(u€68‘‘xH~ ´qïÿ%5Edl­á†è Ã�gáVÒk4Q©Œ Ô6z4ašÊ2·Q¬$sè‹J[Kq¢!r\Úq; ÈZ4€Rº†Âñ›73²Ëz”ŽÜOx泬Ú(.ây~3úÈʉ#Ò˜÷7<´œ�ï.fÅyOr‘ë%*Žìoß@ö×Ê–6Q§hI¼æqþ~ud—Ûx¦ÏGÀ¿å£št6æ_Cb¢f€Ûœb²„ 8 V²<õN^{þbb?‚ÒÒ•÷CeÞOlªºŒèÞÑYðÉc�ðv®�Ài÷ñìýçœP®Ÿ•r>›>¸�q“ÎÅ;ûÁ½‡?3éeZj¢ª &§Š¬*ݧFèÌ´¶ƒÅÒFà�´þ|€ejÍú€—¾¯BÑDsåÏrOŠÛá3JžÊ„8=7þáJW¼Æ‡ ÇqG‚– ”ÙÌieùâUáÈpQ“ì>øõÙö|Ì‹ßUà0$qÛÓOsCì¡�ÆsÎÔDŒ·þ‘ÏJ¿ãµ¥“veDǽÒ[ÝàˆdnÄ·¼]¼�ïÖT2ÿ’�îA¥Œ5k÷áÀÀØ938² �Üqþe[ÉJ¹�ÅO_FÌ¡fÜØ œ3ÜÌÍ÷~DþÞÏù0cM4·œV–*M>⓸�áž>ÄŇöŸÈèq#ñ»ï.þݦ28K{ ‚ Ü TC6›�öövv»½¾ãA`è 28,ííg@@@Â=6‘(=XKö²¿µûx1µ)Ÿ½ådï8‚{nÀÙl6TÀY�É·+6³»¬Eï†Y¯ÒÞPEáîM,ýôsVç7÷¼RD_©6¬6Тë%>¡ëüP=œß!”øXw$¬ç—pté+ÕûÉoP@Nbl_–ShÌ]ÃÊ�õ(º ÆNA/y-Aø9Ñ'2)ÕYµ““±�ÆÃU§Byf&%N™€ÔT¢5 2šTç�­l­é’!¿a[ö;@ögü„¡}Ë uŒ6W,0æê+I6w­tììZù=`J»œëG]�IxO¼œ…qZÔö¬ØX{œúx€ûSÚhjv "¡ÕºˆÓ¹uñ2Ö~ýon>È6§‰*3ïúù]:†LÃF1Ü �³†òª^JÖYÉŠ>È‹[›ðwÏ=8—ˆÓ0ââ½É“€èJä±uÓè‚FþÌ “i«;@[]žnZìYRQ» R×z ¡¤¤�Øñ— øúW¦6v¬ZG…"¡OYÈ•ÉnÇü.=R/f~œÕYÆÚuû;V[°¿¯úw}vvý°–'¸¥-àâ!Ý7’Ì£¸ô†KX¸à"ÆûÛ8<Öµ·ºAÇçÇ£ÃÎΫ(:ê•’õ¬Îs€Ûæ�plcXöaÆ• &:ÿ¤ùÌOÒ‚ÒHú–\=–á!-K+ÛÚF«*á6îæÒG³èâñ˜EL„3À ŒPhooG’eŠ¢0jÔ(víÚÅÈ‘#q:;kV«õ„ ¯¾¾øÏR‡F¶tüOc4‰1& rËÙ›×ÄðQ^�¼J]^.UN¿¸xezh|ªØ¬ÖŽæ…Ɠش©LŽ—Nêø¬¡�̵kÉ,¯c÷êUøú-`”÷ ÔúªÚ9wNFÓKH’;"늪tž·†�¸¡xíÚNCi>E֡Ĥ P™_@£*aŒL Æt¼“°S³ë¾Ýx€É›a3æ06@$c„_#)Fã¶b ­»ÒÙf™ËL7@m`[Æ~²cÆÄ£Ðcü(7¾Zµ�ÍÛ›¸d®7Ж•É.›Šì3†ÉIýìQjã3Òܽ1®T³+§ Ñ#{È‘ ‡1r¸/rn ¹»÷c_Øó´‡�îOöeø°`4Y%ì~÷oüËx3WÍH!ÒãH @–�ª¼²Íi"âHŽw1:Në�‡Ik{gÐÛµ�-ÿù O®®Áœr#ÏüßB†œk �tëß¾ ‡ÝƘ)GÎ]'«h52H*n Íêá ’ÎŒÖ3Šœ�_1óŽ�/µÙ¯2U*ÉÉmDA&|Ä0×ÓDä†%y!ç¤"/Ÿ&5qàÿA¸¯úw}ÕìÉ=ˆ‚†ˆ„xŽ]øE&jöíüyvçëªn@&böù¤¾½—-ù?ðݾ+¸3ñP›E¡pí:ö;d¼¦Ïaª‹ö™¤Kdô?T9€„8ä�Õ4Ó ŽÂ¿×%ÈX–J%ùEí¨hˆˆ‹ÅUÍ”�ÄíZ²O,z$‚pÂ¥GhµZ»ââ∋‹CUÕÃ#Ç n¿åæ�Ÿ RÄÿ[FŽíÐ z"bqß·‹ªÜ}™†¿ (5äæÕ¡h‚HŒ÷éå�½„wÊBn¡‚¬E§‘º}¦÷Žaâù,Ÿ|Ëîæ ²vW’<9dàÙº¥Î@‚âÄÙ˃Cq:; ²æð±ä€8â|²È8XÂþb+ñq�Hg%û šQ%1 ‘½Ï+Vš)øq9ßïªÁ® dôyç39ò臷 ?wn©ãmZˆ¶,¶ì²2sœڲزÛÆ4Ò’Õ$FRÆǰ*�ìô�´Í�Š+ÙÙXT÷Ôñ$÷³S)ü8º§¡¤º¶#|ZøÙC\½ÜuÜÑØ€ŠŠµ¶†&zœõ0àýiIºæ�Ü´çagíå«gïçëÝ MɘԱLœ8‰‰Ã1v;ý�lszHFwÜ]¶dÅ<\‡,ìy÷^ûò6ýHîüÓ$7x}jD�žGxú§ÈZ‰ª(tæ”F#ƒN+aÐj‘e©#ñ°z$”Öo8ùÙ˜¼Âˆé_BÆ®úU¦ÎƒÔT-þ�þ= -Õàïç‹ÌA”ºƒÔ«œ@@áÄï«~]Ÿr�êÎëóöõêwÛÂeÝÈ~Ó¸hâb2V—²rÅnnJLéhë8 Y½îÙŸéç§¹\-Aò ÈåÍ'ããë…L5JK#Í*Ç ( °,•Fê;ËÄÇÓe™È>þøžõƒ  ¼þ°Z­Øìvl6Š¢þÏ¡U;’5žS:hCˆó’Qêö±·º£²wVä’×   K îx d-:�î¨`B†p†Åz"¡ÒRUEˉd╌ ¨öžßq¤|%£ áӒýˆê�Œ�’ü¢ÃkJ8+ö“ߢ"¹!1¼—7…ÖJ2—}Áw;kpz aÚÂLÁAøE’—ø`ßWÇ#û2rdØáë;pÌ�ì{ûf͌̚?-£®_?™Èóæ’j„Ö­kYŸ±†5e ¦Ñs˜Ý˨Õ±—Ì�.îL¥”Ý9Í(ÈDÆ 9~9´,å âbÌÈ(”íÊ¡î˜ @¡xk&%"  Â`Pšu~~~Lš4‰�ÙÙìÞ½›öövÌf3�†ÊÊJvíÜɘ1c ŒÃ "7†$Da¤™Ü¬,’ñ ¡ÇŠ)û憪:©Ì\KfÕQ=|¥…?®eG�Ú@F :á‚Ö†Ž 9@ƒÚ^À�ëóhìú±U“¹~UN SL Ã\dbr‹I R¶²¶çѦj Iˆs™qØ^šÁúÜf0Å0uF2~§wÅ2AÎ$š!LL @VšÙþÙR²Û%ÜG�a˜‹„î†ä1¤Á²s Ÿe·¡j"˜8.t—M—‰ž3Ÿ1nÎÂ/xîã<ÚŽú†µh O>ðn¿öv^ʶ�”ý)uëxú�ñ׿>Ë{{-Çvܬض«UÒÒ±϶9«IÞL¹÷O\£ÃQò5{þÌɧàÇø_=ÞùÿTÌS7UUEUAãhB’aÚ¯_Ã;xèi8C ñsç1Â(á(øšWW”5RÑÊþ/þDz*Ùc< fisHMG~gµÇöJ{0Ø÷Õñ¯oèyç3Â(á<ðÿþ¦¸Û2׎ŠUüoY1NôŒ˜8†þp’ýÏå îHm,~ae¸3ñü©½&4”ÔFV¿û 9Ý.\¥aÓ§|Sà@ÒF1mjTÊy ei eÊ8Já-•%”Ô´`“�ø†Fæcìõͽ³µšâÊVpó!$Èc¿š ƒ}_�ƒæÊRʶâ0ø‚÷‰¬m+ÿ¸þÏ|u0Š›^{�[†ºþ·³mx‚ó^…%ìr^ç6†kÀÖXNQiíZw‚"# 4õ\xÇ/ç�•¥½©œ¢²zÚp#02’`óé×#Â/]ä=ÿáP A4Wƒ¤Ãìí�ùØ3O­›7n§ð€‚ g<“oñ¾§q:ÌøV»z IDAT‘Ä÷kQ£�l# £ÑˆÁ`ÀËË ›Í†ÍfÃÊÐáQUÐëu  :�½^ ‡hqŽ!)¸ï[hÌ�ÄÄôxƒ}_��àhûq}½S([þ+kTÜÆ,àÂcȺvhµP½W(q^¡}Úæøå<°²Ôy†2Ô³oç ‚pª‰€‚ ‚ ¿X’$¡ÓéÐét˜Íf|||N÷) ƒF¥5ç=_œ�Eåòëf,t ‚ *PAA~6”ê-|øÕ*ªv³qýn*íz†^v?7�t•>VA8"  ‚ ‚ ül¨õ»XúÑÇpJȦ&_ý;¸6…óV ‚ & ‚ ‚ Âφ&îj^~w6MN=¾A�xõ1qµ.õf^{ãr­¢…,‚Ð'¢ºAA~>d#~a‘øõs3ÉDllÐI9%A„Ÿ+‘šFAAA„~AAAAú­ßSÆ=Qv2Σ÷cÆ,<-ÇA8Û½:ótŸÁÿ³wßñUÕ÷ãÇ_çܽ²w$„ö’%\¸­£Ôº+ÕÖÕjm]µý9Z«ßjÕâ¨ÕºjÝâ@EQ6²‡` �$dïÜ›;Ïùý‘B$¹ŒÀûéÃÇCsÏüÜsï=Ÿ÷yÞ!„Bq¼ê £Ò,Gû„B!„BÑB¯(!„B!„âØ"³<!„B!„G�®ëü¿¢(GéHzF B!„B!ÄaÔ2€Ð:˜Ðü·–A…Þ`�€‚B!„Bq4t]'ðSRT@uy�€ŸP(€¢¨¨ªŠÑhÄ`4¢(ê¾€BO Š¢b00Tlv'ÑÑ8œ=?©$  „B!„B„™®ëèºN($÷NªÊˈ‰O ÿàaØN,V>owe%ET–•‡ÝéÚXènPA×u´PMÓðù½îÎâ’‰‰‹Ë9J@á„¢áR±è:5õþ£}8Ç i!„B!Dø4*ËKÈÏÛIBR*“¦ÏÀh4µYÖètápºˆOL! °k{E{HLîƒÁØØeïNPAQ F#Àd6ãpBÀï§¢¬˜ÊŠRÒúe`±Ú{tž'H@A!9ÑH”ª¥eA*‚‡°–Ù@f¬ ûƒì¬Ðt²¼+ÊDª |õAvÕµÓšÉndDš™~.“®Q]dK¾ŸB_ûç�”`$ÚÐù…¤Cä•…ð¶óšçä¹›"È,ªáÊ×ê)Ðo»¨CÓÌô�4`C§¦6À�ö4tÞ6´‹¦QUdK�Ÿ½ÇI»tíüÚêêu¦˜ dõ53(Ú€ �ŠÊëö霄B!„]ÓL(Þ›OiQ#ÆLÄuHë�&AbJ¶¬_M|b2F³O]“ÙLTL^�›¼ÛINëKDdt··Ö€BœRÊóvâ”rLНn¥B‹%7”Iq(‰ƒw}ƒ…_\Ë6�eŸ•ðÛ�¡ƒOúøX^?Õ„ÔpÅëõ¶·’ÑÈôiQü~¢…8¶/.åš%BmØlâÜÓ¢¸mŒ™8Ã�/i� ߯ªáñ%^ŠZnÀ`áæ«c™iíü˜CåuÜð¯Z²µ¶¯Å§[è¯B~ž�"�Ã×.ª�‰'Gñ»ÉVÒÌÐò²×ƒ!Ö¬®æÑE^ö¶n ³‰™§Eqk{íâ²ìû_楴å¹õ¦véÎùµÔÕë …ÌQQ– ®ÿƇ§·µKwϯI—¯3 yD4Ïžg#�Ùn>Ï R…Ê �.hág—Æa~·Œ'sµ£ì;\#çœáb¢­óÅBåþ±¢ÅuˆBr†ƒ+G[«bÓuŠJ||µ¦ž¯‹5ˆõ(*Y#œ\6ÈD‚ª±+×Ãë|”·R™4%‚&ÿ^ÔÐùµÔ‰Ú�Kðg3àÂX~qý]¼üê‹|°à%ìICˆÈœÚ½�*ÝCQnÕAgr&ijç‹×±½°–�â¢Ï€\ûר-ÜIa½Ž1"•ÉŽýÁ®}ûh5�*³WT<ñÑVZÅãz!_e?æäQPZ�Û¯a0Û‰ˆK&cP¬tÞºGŸå3\ùàR¯ä¥×~ÉpãAþ¾â)~òÐB­þ.„BOšƒ µ5UìfÌ„îšÙìFŒ�ÈÆÕËIL뇡é!\A“ÙŒ+*Š¢ü=˜-6¬Öƒ<¥mGX~ÒMøÉbWüäg˜Ífž{î9^~ùeî¸ãfÍšEJJ ¯¿û9¡BÊ”Ôpì²{´ ¹Uú§Ù9'¶žWË;^ÔÜÇÆÙ±P]D‰1ÒÞeÐgD ÏÌ´‘Jˆ%ßU²¹_4¿êßù›kNw2;SE øyáíJÞ¬Øã¼µÐÇŠ2xë§RF¸¸d¥wß1ª§„üüwn%_bzü>&3Òt¯�U{[õfÂØ.¦T¿cĬ‡øjnú1´¿“¾Áͼ½±¼2ÃBŸQ.f®ðñNMãK‘YÜÒ_Eñù™óf9¯·8Æun¾œÇK§šIë✕>>¬ë]íÒÝóƒî]gŠÕÊ/O·‡Æšåüfe€æ¦ùbƒ›…§ÅóÜÉ&.™áäó×òcÇi½“¢’5ÈÆ™�±5‚y~^ÜPP6%ŽL7ã „È) Pb00l¸‹)ÃlŒÿ¸œÇ¶†š‚ &ÅòÂ4•5«Ü,ö™¸ðÔX&F”sý·~Zí+:+’¦YXÿq-Å=ˆÞxгÉùèArwmfû®l¦Ÿ:�k®ưŸ(‚ úüRSÌD+*m`QeÛ›ÉúÝ^V78¸Ðnbh¢åMËXT è w7rÔM)VÆZÁ·ÃÇÆÖûÃØ.Yé£B  ž²C­žøëä­¯gÙT g[Í ORx§FF´¡@EvÿkÓãÒÙ¶ÖÍê)f¦M KPø°®7µKί›×YÔ@§:!TáaΚýÁ„æým\^Ë·£c97ÎÎ…}ëøq×q–£ ùyzÎ^žîàå´“âøÏY&ÖnòRÑô7c¢“{§š±V¸¹û¿Õ,m êØœ<~U$çŸÁ’ÝU,òF3—�7Q·©‚¾óá6L¼>ÑÉÔå•ÌoQ¬C±[¹ýLjNOg÷0D×Ù˜[EVÚ0lÅÕl(†væ2îÝTb³&12q.BÈ禪$ŸÜ={Ù´ð}6-šËcgqÿ}W3±õ¢cTCöÜy×ëüàÖ±¥Œæ‚3&1"=‰H+Ý•ìÙ¶–oç¯`ÇÆ¹×®Ìî¡°dA _×µÙl·í*mü.µdv“ã‘1*“S¯þ#/ÿc6ã#üùóxô©Ô®hb÷7ÿâïϼÉÒ’N óº-x³Y—ãCW]L»ü‚¶Á„&†¸ÉÜzóL† ËÄd�ª¦ Tïfí¢¯øøÃ�xÿóïX¹³²Ý)oõº½lݺ•­ù5„_ñf|ö1.ȦªÕ¥¬Ùú%_óñð¿?ã‹¥›È«éln£C§×7Gή2ZNôÓü÷æãC÷R¼e9óæ~È»}Îü•Û)ïìûOk dë*|ù9s¿XÈÊ�UMíà§b÷6²·îìð{W!„—æì„ªŠ2B¡ ±ñI�¤aü7.!‰P0@ÀïÛ·¿p2›-èºN}}×V…%CA¸iðzñù|„B!4-D0,�7#Þ!oD†c�ݤ€¢…˜¿ÉÏìT ÓFÚˆÜî¡æ€e œ6‚]ñù& v{Xǰ êyi›�?¶qÇ….ª¿¨gu�Ž8b¬\{¾‹¡ªÎž5µ|Zµ=ƒYÁ®€æ‡„Á..eel¢‘xÜA¶æ5ðñ*7K*ô6yÅaaB¢‚VëcM{uŽX»(Œ�ìdœ¼¾(9´µq6n»ÀI¦ªS°¾žyÕû_;Ú¥³óëU%Ñ¥€®Q^ßö¼›•׆Ð0ap‰S¡ª}¥Þ•Á-v­¨áý–éf#é‘ UÙÓNÿ)Td�i1&RÔvé j‹7[QTtš‡Å+V ¿:ÛŽmG5ßBS⣠؂…µZ�2Bj+ËîXH½ÕãFô`K½•‚cð冎!„8véºÞô„?1ì�ý¦—€·ÁƒÙl ë�‡ff‹•Úª*œÎCÜ–»/Íª ¯×K0ÄétRYY‰ËåÚ7졦¦†�¿ËÏ��²ߟnaz¦�Ó]>jñäP�²qn_­Âü…{÷!æÍ-'0-’›F¹xöV·†GQ‰¶+ëü|½°Žg¨<«ŠS\#¢ùÓIF ~?ÿžï¦�ÁM;3ñ“ó#8Å®àŠ020΀Ùà»Åµ<µÌ{ÀЄ^Ù.]8¿nQT\æÆc÷tòd¯¡©ã X”v‹ŽwT?�n#ÞÝÀ“ßûxš«ÚT¢ÐBT·w]5ªý ØUbØY¢LWˆu©(4N)jrˆ&DI�¨œ4=Š ->ÿʃ·os.r2Ω +:»ëyèÃZÖt3i«ª¦�G~s!|ú“îmภwêeœýÊrÞ-*`Ñâ\n<èØ�Â’Á >–äÖ²ð¿ïrñ°«æìâ�€^Ͳ§îâ¾Ï‹Ð¢‡qñ3™œ Õ;Yòá;ÌÛôÜíãÉçog¢«qÛŠÙŒIÃn>|i>¹#˜qF‘ö,¢U@¯dá“wñàüRtç@.¸áJfŒL%Š:ölZÀ›oÍgÝ{�pGýŸxåž“éîˆ�Ž(FFôú�¼óÈ[|ëŸÂì?Lbp¼™†¢�Ì}ý=¾/^ÁsO~Äøþ”ôæ06/?ðì `NžÈ•??�ñ}¬Ôå~Ïÿ}�{›ÎP·˜0O¼L!„Gž®ë4xêIí—qØê[EÇÄ‘·s+z7§x<“ÅŒ·¡k}ö°‚ 5TV9÷®»î:Þ~ûm®¾úê ÞîåüæW¹iZÏ’²‹×Ô±ºOã­¦îiàóm‘La漡Fæ® îKwÏfg˜Agû–r´0ΫقÙn$=Ò€Ó¨ ùC”Õ†p«:F³‘H‹�Ôx™N¥µû/D‡UiL¥ùnq5Ï­õQØô$Õcåºó¢¹¦¯‰‹.ˆfWY9oï{úª0¼¿;:‹vùÛM‰mvøÚEaÐI1‘!i·\6—åÿÊ>þ¿Û„BStMÃd2q˜â ˜LfB¡nLmwˆTƒŠêÚÍiX !o-õn'n·£±í&wïÙºF°› ‡ƒo�‡¯+\oã¼”:þQ cN³sf xs=|ÓÓqìíR=9’³"¡~[ ,òÒrè¾æòí7U$%'pGš�›Ç׳lQcçG×t:yŒ®{}|’äÂIFRÍ$)~òuPc-œ ¡k!žÎvQlf®¾8†[úU7ðäûU|Pr(ñ:�âÒÅøY³ÝÃ~+ÿø¡½®d=Ÿ>òk>=àof¦=ø›aëÙº‡ÄFæ¹wñÊôŸ²æ»oX°t«6n£Ø]OaöJ ³Wòùÿ^Ä’0’ó®™Í/ÏBds¬B+åÇ­hH<ˆ¶£%Tú�y38³ƒ]1n¤ãÀKF+&{k *}†¥Ý‰2Ôd†‰DÝZAÑö�ÔêY‡% D± dÄ vŠ4]¸l ø¼øšë;hÅäæùÐ1�‘5€¶­¯ÒwòDÒ_Éfû PF!ÄÑÕ\/A×û9£ñ°e(ŒF4-tÀ>Ù¥ ( Z‡k„% àop£( ùd¤§·y½¦¾ƒÙFÀwLÜ�6ÒüÌÛ`ÖtgŽ0ób�Ÿq#¬$* h ½}=¦×Ï€ŠNN®¯ý)äô kwÑÒLôëc&F PvHï©NE]c¡7Õ¬bWÒ-d¨P´ÛGþ¡l'Lí¢:¬ÜþÓf%)Ôä×qÿµ¬îA …‡7²]Lg`Ì`+‘ëÜT|5޵véH÷ϯz�Â"’"UTÚ N($E0Þê ¥Çy@¡ÿ`ýU�eÛ|´?Ò‚x`|¤‘dòZfÕH#)V)lјµ¥ ¼[ºÿ{ÍšÁïO2°qA%5½�SãŒÞÁd_tEÁÖÍ$ƒêzÖCíÆ�™É¿{‹¿žåêt©à²Ç¹ðÏßu}ö•.Ѩ­©küñv8?ߊ“AÓ.à²-ßD�âu_±,ßLÖôÓÕrF¤5=áîɺ] ÚS™pÞµL8ïZм”äná‡M›Y·nKWçPZº‘ÿï·¬ßõ0/Üv‘  UPZ¡F¢b"»KR,±Ä·ŽB„*(kÚf\B\# ÄÅÆ R�VYA•Îá (X�8Û½#Q÷M¥»ïkJ«¥ª¶ñ¸£c£Ú=n5)�Tƒ"!„G\0Àl¶|Ánn[UßX>]×Q» K@Á1˜Ê^¯·Ý×£ccùqWGf8v6»6{Ø<%’‘lŒ´+œ9Ðnó¶,¾»M`«}·¯ù%ŤÐò³jP0ë:Þn�bœ**MÓ×é*cÓ͘ôkvu4}`[=mÅbæ—7J·Vsç\7;;Ë;U�Loc¤Keׯ敵·�N]ƒ†ŽÕ¢àTØ7åÙ1ß.=<¿.Ó5rŠ5´4RLXµ§¯¨ Ki nåî Ðþ'÷8¡›nÄ °.¿ƒ÷*`C¡Î¥ƒÌŒIPXѪÆGl_ ýU��»}ÎòÑ’ÑÌõç:I*¬åÞuûëlxýº¢bmñmk5)(ºŽ»‹ÓÎ6«©ób�ïÞºá -˜ÍæN;µŠñ \×*Ø™[…†Š3µq*@㮸•q,`å‹Y^ÉÄY·róà‚JÖí.ÕJâ€q$ÇŒî‰< IDATK¯å®êl>|êQžY´—¼�ÿÉÛg¿Ü¸O=€¿éz1�](Í´­M Ðè2™:Þ¦ÁÔxñêÁ`û5F¢ g¤ûñ5ý¦ ÜÆÍBY !„"¬TUÅï÷a2÷`j¤Nøý^ ýö…�ÒP ]»× ËÏm ï¹lËÉE!..‡£±f¼ªª8�Nüþ9×èw^8v6ZuŸåé(. §�·1Ñe9Vvó&ÿ ôÅu�Ó†¥'š:­Ò?Έ økCTè€jâÆë“YüûdžolÿM3˜™6 ±øVÉ^cVƒÉÌÄ4|~Vú]`ÏÚEeêY1Ü�ªP³«†;?>H0…¡£"¸v¢“ëGšiÿãg`pRS»Ô…;Û½¦]ºy~ݦóãv/å:8ûÛ9¹�'ÙjŒ�³RôP€Å;‚‡¥^È1Ã`bx¢‚î °£Ãá-+67P¥9’•¸–}³™Y'™1üÌË†œÅÏ¢ü¼ü…›Ý-ª«R�‘ôXeß²éñFÔú»ºYdÀí×X¹l-Vëá‰~÷Zér¾Ë‚bfä˜!|¶zCÔ.ÿý휫¢‡ Y³¾¸ñšS¬Ø¬:Þox>³ŠkSÔÚ×àë 0ªãkð¢ŠÕŠåX(z©˜±4½Ù>_À~7u�î…Bˆpir ( ªjÄëñ4¦Õ†½n£ñ€}†SH bh§„Ag¿�ÌÀ=øüç?oðî{ïQ]]MBB&“‰ 7òúkoáðSˆÉ ËîÂ'ÄÂM^ê0rÎÑz�ù?øñ®Ýé!–åøñ‰Ã]\™Øöp¦:¹j€‚¢k¬Èiª¯Y¹[à( Ÿŵ©ê�Ïr ¦ÎˆbV<è?mðL)VÆZÁ¿×dž.�T÷ÛÅžÁ]# ànàïŸÖ³óPj†h¾jÚ~ßqQÜ6ÀÐ*uF!}T$7öol—•[}�iÔ½¥]º{~=àÛíæƒbÅnãö³í¤¶4*3לëd¨ª·»ùô°Œï9v¨.#©FÐêB”uÒ «ÝVÇó;5b†Fóâå‘\9ÂÆÙc\üéêX~[–×2·ƒq(æ$'¿Ÿd${i5ïV؉ îmà›*…Ó&:îPˆIuru–ž- léj¯PQ¨óøøÉùÓøùÏÂŒsÎÆë 4V²?Ñèu|ÿú{lð騑S8Jׇ9~*s×óígïòẊƒ¬Iô‰kœÍÀãñ4vôÕR @ˆ¢Ââv·¡}ø‚]èD«‰¤&€ E{‹;ÈÖ R\T††‚)1™øcá©¿M\” hT”¶ßžÁ];È;|5«„Bˆv™-Vª«ÊÑÓ?UUå˜Ì�Ië¡€Ï�ÕÖµ åÖ/¡¦N&›ÅÇ;ñéÂçTæapÄ¢Ç Åtò_1¸Rµ«°ªÝéa¡ÛÆ…N…P‰‡/:›Î°Åiç‘«#Þ¢£fkªž�>!–Gíÿ{ ·š«çyiò×ÕðÂÀ8nO·pë5 LÊn`ui*‰IfdYH6AiN Ïf7§gëlYVÍ›±\“dáæk9;ψr� ÅÀà~VFD)(Zˆ%ßTñNS13ÃBœ¢óã._—Çãw¯]TN=ÉN’˜-üêÚ$nédiÏÖ*®ùÚGÈ[]Íóýã¸=ÝÄW$2}¯� e!<ŠJj²…± *& lk ÏþØÛÚ¥»ç×ýë -ÀçÕ1ùªF‹æ­;Ëò‚Ô¨†ô·0Ô¥ªñðäמökyG«ŠKͯáîìíÒƒ|òQ9¡Ó£øåH'¿ؘ„p˜ÿM5O­ò·?4Ä`âªs\¤—Ôqãê mú0!?ÿþ¸†ä‹"xùÎMcç�5Ü¿´óéJÛcOœ×>8pncEÁž4¤‹[êåô¶¾÷(�|QŒ¦ØsÕÕLu»á²ñ­?ñÀ7õ2ëÈzþF†v’\¢×ä°¹ Š•Ô>‰MÓ?Æ0rd*† y¯]Ë®Ðp�‘bÛk·pÃ{°Lü-ïÿu&1k5ŽQ#R0lÜMñÚµì #³u–£?‡U›<芉¬‘CÚ)€x¨‰ Èp n­%oó�TëýZ�«—uß,¥HC¦ŒBqD(Š‚¢(DÅÆQ^Rxà½ZUW”㈌†¦ý…›ßç%>)¹Kë„u†b�Æ<øb|qï™×ÞïãóCœ?AåÇÍ äâCEUˆ‰4�ÜΉš¬’[ŽüöO΃þû¿Rò&Eð‹q6Æ�r1¾Åºž?Ÿ®®å…Õ¾Š1ê>sÞ,#oj׎´�ÑßNÿþM¯é:ÅùÞYTË;»C�O™#ãÓ ´kòº‘ÒÞ�vQìæ¦‘°&•¤ÈÎwÛ•Ûå�2öLŠàƱV†¤Z9'uÿ² 5~¾ln—ÇÒ+Ú¥ç×íë ð×qç!~}Vôµpæ˜ÆŒ®iäæÔñÌ×õ¬¨=ä3ïµBEµ\ñ—C;QÝà³/˘·@%)Ò€5¤Q\ÂÓÙû ðêöòj'‹xŠÝÜ÷¢‡CÅQÕÍaU™S‰ÈœÚ½•�Ázò7/å³wÞä�{ñb"ùŒßòÐe}ò›£àHÌdð 'ñ¶.WèÁºÍìœ|ùEô_ü;rßáÞ‡lÜÿ›Ë˜�Øv�†¯x%¯ÿõ–Öë¨qÓ¸p²«ésm`ÀYç2üÝظëcþùÉi<~I_šãÁ¢ügÞB˜>yQ‡t¨�sÃßž�¹syá«üefJ‹;>üóJ4T×D.:=ñéŸ[}Ê"æMÍÚ÷xmý)Ü9¶¹�‚”,™ÃSßÖc7*Ô×㹄BKE!:6žª²*ÊK‰‰Këö+ËJ1˜L˜-ÖÃ’•é÷ûP‡³óÂÛ­¾ŠÇ’�—‡ÿ^ÈÃí¾¨³þëb&}ÝþªþœJ¦>ÚöïZ­›[þÚÍÄôPˆå˪X¾¬W¤‘T§‚�šºµZÛ'œÍGê ðù7|¾@!>ÆH¢M� Fyuˆbo«(˜®±ä› ¶(»J::Ž0·‹âý·öò~Gç}0Á K—V²t©BD¤‘”ã¥]zp~=ºÎO©‡'Þôð¬ÃH¿(«®SZ¤¨u»ˆh�½åáî‰è¸Ý¡Ã<ëÁñ"ÀÚ9¿à’W[ü\†üÔÕÔàñ7fð(¦8Æ_y\?‘ăör� ¿æ ^½¦;ÇÒ“u÷³dýœGSÀ]O-¢`ÅËܱú¤ BVßD"l*¡†Jó·³ykõ!P#GpÃÅ)-2/Ô´‹¸ûÆ•Üúü:V>ók®]>�)Câ0Tí`Ùwß“[‘c®çö™‡ÞñWÓ.äžWð«ç׳ôÉ[¹ií¹œ1"g°’�k¿eÞ÷{ð9ýŽ[8ë )GŽã䫸qô÷<µ.�w›&Mbd¢‘šÜµ,ÙÐÀØÛ¯aÀKÏóõ14¹”Bˆã›¢(˜Ífœ‘ÑîÎ%&6¼´ wçâpE`6™Kv‚»¾–ø„®e'À‰P8féÔÕÈé°l|G«é”Uhw²€}4ò |äuûØŽ&�ÚšµÇm»tóüzÀë²Uz²¢×ÐñÖ”RÜâ3¢¨F̶hÒ20rÜÎ:ï Æ§ØŽáº ­™é7óAþ3d:ï¾=—¯VlaOöj ³[,¢¨Øã1ý´™üìÊsÛú'ÚÌÀ+æ…¸×yæ•ÏYµzo­PPmIœtÙuüæÆôïRuJ3™W<‹MÛ\¹àm²¿i>3±YgrÝM71k\GÓJ%†¾\öð“Xÿýo|½‘œÅŸ“£Zˆ8‘YÏæêñyü奯EOÄ#B!ެ–Ecⓨ¯©¤¤¨�„¤Ôƒ¬yhJŠ ÐÐQþáá *4xÜTÑq]‚(q7üMGiLÝóÌ/;]8{Ó:n^п[)„âÈ{áŒ\†Œ{´C´¦¨/+¢¨²�OC±8‰NH&%ÆzˆCƒÔPXá&h‰¦Oßd¢Ì=½±R_œO~Y=~ÕJLJ©ÑÖc+�Ð=„×í!hrà´4­çk~wÑ_XÊàÆ½ÄMmŠC!„á¥ë:º® …(Þ[@YQCG�ÃfïZ‘ÃÖ<7Ù×⌌Á�ªªa (ü~êjªI0‹õÐ >ö½mÍ1ÉPB!Ž4Å„3¡/»=¼Òˆ+)�¬¤p”gRCºÍÃC÷V±g÷ kì ?�¨Vã=ýÛrØÅÚ‡~‰LBqø�¥—@Ðï'gó²†�Ájë^Yã�‡­[6àŠŠÁlµ…=;Áï÷Q_SMrZÆ!Z;æ<!„B´Úõ>÷Üòîº÷þµ¦†ªÂ4ìäÝW¿¦TSqŽ›Êøž=B!ºDUU, Ññ‰DDÅ’½i-õu]ë\_[CÎæu8#¢PTf³5ÌÃêkkHNË "ò Õô;! B!„èUŒY—ñë³qß—ù|xß/È™r ãúEa¨ß˦åKY·×‹5ž[~y*ÑRCA!ÄÒœ9 ª*‡]OÀ`4°íLj‰‹'-=ƒ¡ó.x($?o'Uåe8"c@iÜ–¦ì¿Ï‡Ç]‡ªè—9k73šI@A!„½‹Í´ß=Íßûý‹}°”- ç²EPPÌÑ š~97ÌžÅô>r›#„âÈjîð œN'ƒÕhÆ[_Ëú•ˈŠ�%&6›Ý�ÉÒØ™ø¼xÜnª*J©®¬ "*£Í‰ÉdÂjµv»n‚®ëh¡!-DÀçÇïó‚¢—�DL7 0¶G~i…BÑûâ˜0ë^&Ì â./¥´Î&'q q¸z\ R!„è¾–A»ÝŽÙl¦ÎjÃhµãs×±;w;Á@]Ñ8vcÀ Ôðz}øAìv;îPO]÷3EÅ`0`0°ÚÄ'%ãhUw¨§$  „Bˆ^̈#.…Œ¸£}B!Ä~-‡?˜L&¢¢¢p¹\444àõz hšvÀ2V«›ÍÖ˜ÕÐ"+!œSD†[— «îÏ\šB!¿ußçíCB!„8!5t]GQTUÅh4ât:�Æ! Í˵\¾7šu;C¡ÁãîñÎ[ÎÉŽí !Ž]òy?¸p·QOç=B!„=×2`û -×ú¿�eÝ(„ûFUn|…8qÈçýà¤�„B!Ž­ƒ­ƒ ½%€ÐšÔPB!„B!Ž Þ@hM=Ú „B!„BˆÞG B!„B!„è2 (!„B!„¢Ë$  „B!„Bˆ.“€‚B!„B!ºL B!„B!„è2 (!„B!„¢Ë$  „B!„Bˆ.3íB!„Bˆ#M÷×QRTLe��¬®(‰²¶óÌUP_Y�;¤wºMÅè &ÆÑA'K'X_J~q%õ Åê$.9…D— %'$ÄQ !„B!ĉCs³gÝb­ßMU ÕkF}GLåô‰éD´Œ+h{Yþñäø:ß´=†Ë¯œHb«˜„î/gË’ïX¾µï¯X‰z2çœ2ˆh陉^H.[!„B!ĉA÷’·ôSæýPMPµ‘8(‹A©QXuU{·±e[9{ÖÍçãÀL®œÚKsê@È�/`#>=éÀ`C ª3kë?†*ÙôÕg,Î÷bp¦0rx&I.#¾Š=lÙ¼“²- ùD±ñÓiiû÷'D/!!„B!Ä A+ÝÀâ-Ճμ„³8÷•:œ!ñŸóî²Bª³×’3&•Q®Æ¾î÷ÐCcgœÍ`ó!±l�5zç^| ö¦¨ÁÀAd¥9xïÓMTæ¬a˨TÆFI‰;Ñ»H@A!„BqÐ(Û•G­†¤QLÎt¶ªP¯=t8ýÖ²Í[NQYˆQ®Æî’î÷â0Z0º°ËP1›6•Tì �2q0KÊÎ>7¯#†øŽÒ„8†I@A!„BqP‰{1×e¹iP�D´7¼À`Ån¼Áu¿¿ŠÉŒ© ÃB%¹äÖƒâÌ +­�´ÅF|¿ô®žˆÇ (!„B!NªÙŠÓlÅÙÁ뺷ŠJ F½?AñûñŠÅŒå�÷¦Q_Z†0&$“М€ ñú`´`1©2ÃèÕ$  „B!„ºŸÂu›( €19‹¬˜ýC´€�€ŠQ¥~×:6e¼OLŽHRú3|ôPң̪«jÑPˆˆt¡Wí`ùÊ ü¸»OÐ�Øãú0tÜDNÍ!—eâ"!„B!Ä N£fÛBæÿPMÈ”ÀÄ©ÃØ_QÇç €¡’µ|ö¥Žn´ârÙ±« ÔW•²«º”]Û¶1쌙œ¶¯6C¯×�Ž‚Á½�yn¡È”@Zæ쪟ºÒ ÊóX3¿ˆÂê™\tR¢D¯#!„B!ĉKP¾yŸ,Ë£^�dØg1>¾e7I'à÷¡"Èœ8•)ÃR‰4)€Ž¿z7k.díÞJ¶|»€˜Ø ¥‚$ШؖCÔà\uê"›GRè^Š×~Å'«Š(Z³ˆuý.cR¼f½‹„B!„'&­žÜ¥_òõærüæÆœuSúÚÛÌþ9ê"fÓÁ`Àdhùª‚9*�ÉçžAûŸ³¥®ˆ�›KuJ2*Êþí8rÊÔÁÅJÒØS—÷ËJ+ÉÞZÌøøº2‰„G›„À„B!„'Ý[ÌÚy2ï‡rBœzñœÒ&˜ÐHQ�˜Ì¦VÁ„¯[R6 p—”R§Š ³¥±¢‚!.™S;+ª.úö�D<•xõv–â& B!„BˆŠÞ�ÏÒOç³¾,€-e,çœsi¶žëË‚83§rÑŒaÄŠ RLÛýÔñx<è€b±Ò˜˜ ‹Y¯Æ_]E•Im‚:>¯P-fLL½Œü !„è"_e?æäQPZ�Û¯a0Û‰ˆK&cP¬½v<�ÅSüä¡…R¯ä¥×~ÉðCø•ìÎ:Gb[áácûÿþÀ¯^üûi÷óÒ§a×=åPl//WA5Z°»bHˆw5ÝP‡Ï±×>‡Óñû9;$þ•~xóE¾(�˜7pÍp[;ËɺäúãÔv;GZîûÜ3û5¶+˜ýò ÜÑÅý_ñWfW<ÊC êpœv?ƒ3ûuÔêlÿ˜ì™NüwŸPºr> +OåÂØ6== —,";¦!gqö€ChÅ,]²� FFN™Dë>g—쫜¨XDQ¯dá“wñàüRtç@.¸áJfŒL%Š:ölZÀ›oÍgÝ{�pGýŸxåž“‰:È¥Öõkäàïk·¯Wsã´oþ†Ý|øÒ|r#F0㌠"íYD¬-Ãð9SÍFT‚ÕëùçC?°-æln¿v<ý£Tªs¿çÃÿ~Φ-ðàCQüûÙŸ‘Ù|'ØÍóíözþ^yðqæî `íw*×^wúØð•ncñoñèŸsIíðÔU’O>…Á/mfóÖ%,)¹ô˜¨!„'" (!„88C.¹zs^Hù†W¹ùêåL?ó ¦OËØ¡ýˆµüf>¸í]þïý\|Æ~\ùèÓÜ1fÿØû¬áã9yà\÷À—üðÆË|uÖc\ß´MUAB¹óùrì¯xééKÉØ÷Ôz<“ë™u÷'o_Ί’+HOV7+¿YA¥füÿìÝw|UÚÀñßÌ-¹é•Bè%t)‚ ˆô"*–EQ”U�µ®}­»êkY× ¿ÇF" IDATVÄÞ‚"½Kï½…žÞ ý¶™÷�RîMnnø|?æcÈÌ™™sfæÌ™gΜ!~Âxé–æåÞiíË a}h2õ¾MßÀê„ ÄÇ»»ÑV‰ê>Œ11ùÌŸ¹„c„Òeðh®®áæÅ¿×P†-fvæF–nÌcð Jã 8²xùqœŠ½†]QÍÓÕÖïÅȸßùìøVþX–˜b*¾»«%²lùøÐ{Ä`â<¸çÒów³õ�]mF÷n‘uq¼hïn8tP›Ò²Ù™¨�uû×¼³(ÍÐ’ñ/¾Î½ÝýÊʧCçž\ÒÎÌ�Ìáä‚ùfl¦v¨¡¹âÅ1RÓ~õþx5b´“ËX{-oͺ“nþêá<µ¸,7±½ûÝÌ|mec6ö¾„Ë;ûsç}ß’°ï'¾Ùx-Oõó­S~½K§“³ê[¾?l¿^ÜûÊS\WZöíãéѧáýƒ:î@5¦+Ý£Tv&dëînŠ©µBqH8W!„T"?Ì[�Ž&>HÅ‘µ�ÅßÍàé'1fÌX®ŸòÏ¿÷= ¶� ×é*½�] qľßÈÄ‹*ä§ÒïFƶ3¢mcÁêŒ*Oþu%š+'Ž)w£XÌ·ÓEtöQÀ™NRjI*­€œ\: F£‹›QŸx&ÏœÇò_gp§Û`BXº1üŠHT=Ÿõ+6’W©ë¶cßr–�t¢øödäÀ&Þ_Œ�í=ª=&ìì\°„c• M;±’¥à׋+¯ðl=Îc ¶ê(æVthî}ÙØÓÖ2cúR5Ÿø¡ mUºvÛ–¬ YS0wËø®~UŽ…Àž×1¦�Ý™Èò‡pyH¹P«c¤ú­÷þxU@´BèuËxºzLê~ž•_T(ƒÇ_Må@øvØŽFÐN³aý~uʯ·é¬l]³…|]Á¯ÏhFTЙ[ríu}©¶è -éÐÚŒ¢Û8|àxI>„BœmÒCA!„‡|i3ê!f ¼‰M˳dõ6l?@J~‰{ד¸w=¿û>‘ݸò¶ÉÜ}eG‚Kï´4víÍ@Ã@Ën.ÞÁPcéÖ9 u:ûwÂ~m$åÇsT|Úѵ½‹��ú*`-ÂZú.¾FçNѶŸ`÷/ðªåNnÜ�æ�gn�Uµ!cêfº ¹‚f¿|ˉ�ËY—wÃK3mg÷òÕ$j*A— g@Mýù«¥7l=?ÛÇú„Åüqà&¦Å—^Ú5Ž._Á!‡Jð ¯Ç––L†Jx4QnÆ“,æäèÒY¼s¸âLº³ˆSIÙ²e?iE:JhO¦=|mÉ«(€–ÂÞý§ÑPiÖ¥a®vƒC§ŽÁ¨û3I>˜@Ž_ý`†%juŒT§ŽWŒíéÕÍß‹Áëpž•£˜âéáêój:´ EݙƩcÇ9¥_D„îe~½-'-…„cEèˆk×WßñíÐ‘ÖÆåìp81†B2©iØé$�Z!„8¤îBQ+ª_,}®œHŸ+'‚VDêáÝìܱ‹-[6°zã>ÒÒ¶óóÿþÉÖ#Ïóþ½½‹o2´LÒ2ŠŸMýñ)n™ïúfÞqú::ÖŒtr4hRn6Å@€Ë«–JilàÌ­¢‘ŽeÒž§™¹}³_˜_ß i‡nôêÙ›~ýúÓ¯S$–ÞØa0C[üÀ¬#[X²>�¡C‹o.m{X¼2M áòá}¬ã6¨á¹ºßL6.=É»™ß½øÆÖy”¥+ŽàP#4êbÓ)ÈÉGÓA " Ú˜‹“Äõ³ùz½ë©Š)„vƒÆ2eÊxúG—{LîÌ$=SŒDDF¸é5a "< •L´¬L²u< (Ôê©F}¯>á4©í8#å·Ø›ó¬%° Q.p•а`TÒÐòN“«C„·ùõ:Ýi²O!¡A.ƒ.jhaÕŸJ`P*:ÎÜ\ tʾú!„âì‘€‚Bï©¢Úö"ªm/†^7‘‡Níåç7^äíI�=ƒoFÌdJèvlvÝiÇnwÓò÷‹ ÖŒÁFÝÜkw· øwæŽ×gÑÙoü²`«·!i÷w¯aΗ3n;„»º‡ë;Vî¦]O ­6¤-ŸÏ<ÀÆåëÉ2”`¬»–±2MC�ÀÈ^n¾ XJ —ŽHÄò¹¤-_À¦»ºs©8¯déQ'†ØÁŒéæâIµK:6› PÌ>TŸÊHÇqOpg�òyPPŒ&,áĵlN—ß&´c/éŸn2Ý–½ÁTÜDÑìEŠ×_/êáxUŒfŒõu`yzž•çãƒÙÍú�¥ekw—­·ùõ:� «½t[L®÷šÁ€¡Ú/]€ÙdFt‡[ñÇ1„BœePBQo !ùÛc÷qp׿˜“‘Ȧ­)hbQ þ~@–‰®·¿Í[ׄŸ�¶¿!„ø¡xbètk ;7³aÃ-\þƒ yý‘Ó˜>z‘kd„x•ƒÓé³ìܼ’µ9CleÛ’?I× 44œîÕ¾Rà9K�‘Œl6�ÏOþÉëóè?È—ƒËWpL3ÒfØ0:ºýŠEe fsñ̺݆­ÚyUÂÚ\Lÿþµ È(,%1k¡Wéu¬…ÅŸ:T,|Îö�â¹:^=äö<+?“ÕŠÕM ÆVr7¯X|ŠËÖÛüjÞ¦3ãSrìÛ­6tª¾¢P¨UI²9ìè€j4¹ žÑPt½Òçn9Å_“ Ê(„¢6²oeéoßóó–̪ŸI¬ÌM³ˆâ‘Ü Š»˜¢iiDÁArRªÇƒìÕ'Å'Œ¶½‡qó´g™õùKÜЈž»™_–œ¬9O^Rc2¢‹ 7³lC.zÑv¯ÉF3´`ø°öõÕ7v`ôÈv˜ô<Ö-ÛH®ýKWœD3udô°µ¸Ø+ø * çå’ïqÏ€ZP£ˆ�2’“RÜ R’ÓÑP0EÅTx•à¬8'Çk=œgåè9i¤¹Ú�N2Ò3ÑP0„7!BÅûüz›N %"Dœ¤§W€@K>Irµ ÔÈÏÉCCA �×ÄY¡ë:º®£iZÙï®þ&Ä_‰„BÔÀÁö¯žã©ÿ~ÀÓg³ÏZýÜúé}ì:éÅLl³¨â �J÷‹Z`@#iÃz»’]#cïz¶�Ì«û œ5“„m«˜·æE.&+AÝÔ;�ìÌìZjÕTT›pÅЋð¥ˆÍn%kûjÖœÒ1ÅcD+ï¾ àzý*͇�¤§ò7-gåÆe,KÔðí1‚aµì}áI¸Zf*)v¯6±zjÝ»6Å€FÊæÍsµ³mûذ£]1ß­£ËAûê[…r=ÛÇ+P/çYùéŽ}lÞéâè×N²{o.*ÍÛµ..[oóëm:5Šv­üQÑHܵ—¬*' ÆñM›9QmÁÚIMÍDG!<:’zêì#„K¥§ÓIzjûwoeóÚ¬]¾�µË²yí öïÞFzjN§³,¸ Ä_�„BÔÀ�þ»†Öf°þŽ'žýš ©®;Ã[SÖ3óßï³:OG ¿œ«û• DˆJËcèå§à<ú3o|w�‚Êi�Íåÿžx’)·Ná�Õw¶¯‰–µ‚×yŽçŸ�/÷V½ ·aË®,tÅH\ó˜/†ŠÁPü>¼3‹Œªw?Õ¥$첡\ìÛVóåÒõdëfº»‚ØZ\�=Y¿qW]€R°‘™o-!‘ú�PÃÀvUZ¶¥•YA·áàñ†x6o ýÈ+ébQpþ•÷$Uú䟕C?ʼT 5°/× ®z³\_Ü—ëÙ=^‹ÕÇyV.oúi–~ñ={+l¸Î©µ?0ç°ÅØ‚�J{¯x›_oÓùÐý²>©:¶í¿ðÕŽ¼ ç¨íä¼÷cZuc(8Opð°]1ÓªMsàã¯Bgz%dg¦±mÃjÒS“‰ŒnF¯~4ê�º†^ý.'2:–ô”$¶mXMvVºôV2†‚BˆùÄOàÅOòÐ+8¹v&÷oü–¦í:ß<Š _gáiÒNd×þdòœ wåŽg¦qY¹O¨Ñ£xøž L}m [?z€[7fxŸV„­¤ÞÂÒe[8Qh"îÊiÜÖµnÏÕèÜ9v.ÿüa7ßw\JŸ¶1™4 ²N°cõ2Öw`ŠË­C›ÔPjN‹P• ©)Ì~õ9ò{GAp¦ÜÚ¿šÒ÷ed¿@V-YÉ�Kè–¾Œ¸"²V7ÉÕ­¿ìk�J—ŽHøŠßHI)B Å•}«ÞhÖ¸®€NtoeàÏ}Ilß•‰Ö¾vÛê 5îj�´–iïmeõk÷p׿Q éC€#‹„ÍK™·î8†(ß?•áµ�ˆÔBµåz�×Rõqž•Rcûq™ò÷LÞÏèáÓ&L%;a ¿ÏÛDŠn¤éÈIü­u¹Ï¨z™_oÓù÷¿™‰ÝÖðζc|÷؆ ¤G¬…¢ä½¬Z¶‰‚¾×0dç/,ÊÐÑ]ÄдŒÝìHÖPŒ­éÑÙ›Ïs Q3]×q:�$;Lzj2]zô!4¼I•ùü‚ð¢Y‹Öde¤±{ÛFò¢NÛ¢5ƒAÆW4 (!„ð€™£ŸæÓŽùþ›_Y°v7Ç÷n$qo¹Y¿&í8h47ß8Šîá•/1Fâ®|†™ß2}æ/¬Üò;Ÿl>“Ö·IgÆÜ1‰©×u¯õSõ*zMýoD|Äû?­`×’ŸÙ±¸l"ªo]y;wß9–îž|·ÑÔ•ñ“‡°þ¿‹9~t ³�*øôlÁ¨1 ôÚŸ�¥óɲ«^6Œ�!µÌ`5ë/'åÛc$#bÿàË:уFлæ�«J�eÀ€6|¸ï»W¯#sìÕ 0†�™6ã^àƒˆÏy{Öï¬_ò {K÷�b&<~¿ë.Æ÷r÷YÉzRm¹žÅãµL}œg¥óÅ1î?7Ðö­7øü“éä— p¨˜#èqýTž¸»_¥OMz›_/ÓZpÓ^B{ã >]y”�¿ÃFŠ?7?⟼8­ §ÎlUù̇FÆÚ?ÙmCü¥\ÖT:ÜŠúWúšCâ±ÃäœÎæ’�C1™j†EDrÉåÃØºa5;L³–mPUU‚ â‚¥DÜñªŽR¡>þöÝÕμwÇz^2àll—Bˆz°eÝ*:vëYÿ Öíä¥'“œ•K�UCñ 42†¦a»kf%r"ù4…º‘ÀðXšE6ÐHívòÓ“ILÏ¡À©âA³ØHü½©;óÓ8ž’~¡ÄD…`9Ë÷15®¿`/O|œÙ™-˜ôá‡ÜÕÖ»ŽàZÚ\œø&ì˜úñtnkÑ�u�—r‚éyØT aM㈠µœÕw2kÞ¯góx-Ç‹ó̶êEF=½„ÂØùèó»élÛé$Ž�Ì¢È@TóæDúÖTºÞæ×»töœ$Ž%fS€‘Í›í_Ãq«ãÓ)“ùà€‘¾Êëcjîe$Dm”½æ�•Α{é7p8F“ÇŸËÀn³±nå"Z·ïDHXŠ¢HPA\0šßû.¥1é¡ „¢ö‘ÍiéíT|ÃâhWŸ[å† ÿ&Íi_µ—j­ü#iÕ¦îËi˜õk$Îÿš…é:~½®áªÖÞ¿U®FåÖß±ñ—üüýF®¸/þ Ö6ÝŠŽÑ µüšÕ¼_ÏæñZNϳÒ×·ÍÁMiÜ´)½Í¯wéLAMiäéöéä­ûžŸ:P›Žá¶ÁLõO×uœGì¥K�>ŒÆZ�‡`4™è|ÑÅìÞ¶‘î½ûc0%  .HR !„ç=�ü½_òŸ™;(T›rõmÈ®ÓÞ—^ïdp¤.ü˜¯ÔÇ ƒBÔë>¾˜¹˜tÂ2ùVzxóZ�Õ(í��™™†¯Ÿ?!¡áÅÑ9/~BÛ`ñõ'+3Mi,é¡ „Bœ§´´õ|3{É©»Y½r7)v3mÇ=Ì�Ýêþ¡E%t ÿüçZv=³˜¯þû—M¿�N–zØh!¼VÈÎÏ^çÛÃN¢FÜσCd0FÑ t]';=•¨¦qèµûXpåGzJáMÎa7,!�„Bˆó”ž½‹ß¾ýŽ#NÕ7†Koy�'níN@½Üe)„]v?ÿ™p‚¾ü†gßîÀ�ô¯Ç…¨ �ÌUoóÜwG0ÆOàù.%´�ŽÅ7~;Ê{‹qØí ³Ѹé:èN^aãÚNÝ©k§‚�ÐpöïÚÆÞ[PUU•ââìQ ¢›6#84¼ÁÖ!!„âõÜPUüèvûùfh:ùºF'ÒrhäL=ïäÃ�oD3†wAí+'Æ67òß�ÇG¤oÃE¶Þ_”HXtK|,þ ¶ш麦귓٧ί)˜|,èºFDTŒÄYg·ÛHM:)!„B¸ Z�mNÃ5ÕŸ¨rcu¾Pü£hÓ&ê\oF0Ü´%Ágimмëþ×T¶ßõ3ÿ®ë±P’^/÷œQ\H$  „B!D‰{FÄ2}Á1ìòÊÃ_�^üŸî$»�ŽÕZ€ÁX§%Z‹ P…ŒÔd ƒ|>RœUƒ�¨˜f º (!„BQâÞÑ-¹wtËs½âÑ4 §ÓÉ�=ÛÉÎÌÄ×/ NËËÊÌ 4¢ í:vÇ`0È+â‚#G´B!„B”JZòI¯?Yú“–|’À Ðs�!Œ„B!„Ê^I §¨°€ìÌtt]÷ê'+# kQ�Ááòªƒ¸`I@A!„B!J(Š‚Ÿ¿1q-Ù¿{;v›­ÖÁ›ÕÊ�=;i×??yÕA\°äÈB!„BÎôPPU•ÀàpBÂ#Ùµm#v»<ú±ÛíìÞ¾‘а‚ÃÊ‚ ÒCA\ˆ$  „B!„%J ~~¾„DDáÈÖõ+9••Q㘠§²ÒÙº~%~A„DÆàç狪ªL,ùʃB!„B”(½ùWU•�à`EÁbñãàîíøXüˆŒŽ!04‹/Ö¢Br²3IOIÂZTHt³–øTL�€‚¸PI@A!„B!Ê)í¥„Éhƒ [aéi©œ8z›µ0ûX°øúãJXT3ƒ‚Ëz&Hïq¡“€‚B!„BTRTP?,ŠŠ‚) .Äf³át:0 ˜Íf,_|}- L: (!„B!„ å_PUƒÁ€Ÿ_ñ«º®W˜§|¯ &ˆ¿ (!„B!„¥Á]×1 e�Wó•ÿ¿PB!„Bˆ”T*HAüUI@A!„B!jABSÏõ!„B!„âü#!„B!„BÔš„B!„BQkPB!„B!D­I@A!„B!„µ&_yB!!wß9B4>ˆÿRçñ×U—:L B!D#QÚ /ß°—F¾�Wi#\×õ²ßϧà‚Ô9BüµÕG&!„¢Ðu]×ÉË=MvF:E……hšó\o–¢ªjÀâëGhDƒ€ó#¨ uŽê^‡I@A!„8ÇJöiÉäåœ&¦Ys‚CÂ1å2-Dcçt88}*“¤Ç)*Ì'"2hÜA©s„¥êZ‡I­!„BœCeO sN‘—sšö�º£ë:6» lÖs½yBˆš( �!tèÊ�=Û°Xü .™Ôø‚ Rç!*¨c&!„âÓu�ìÌL¢c[àpØåf!Î'ºŽCÓP…èØ¤§$ãÔ(ƒ ¥¤ÎB”©c&Ÿ�B!Î!]×Ñ4�¢Âüüü¤a/ÄyJ×u|ýü±æ£iZ£=—¥ÎB¸âm&!„â)?º¦9ÑñM!DÍEÁY®!ÞØnÖ¥ÎBTÇ›:L^yB! ];×[ „¨ƒÆ@¨‘Ô9Bˆr¼©Ã$  „B4çÛ½ˆâü&uŽ¢®ä•!„â:ïžh !<ÒXÏíÆº]BˆÆEÆPB!„B!Dƒ‘W„BˆFCž !Î&©s„u#!„ç'[.9Eè?BCý/Œ š´í…gSc¨sl¹däXÑ ¾µ¬ËmädäP„Špþ¦:¦óz;„øk“sE!„wô<’%qZÓQý¢hrV/*¶µopý³Ë±ÇÞȇŸÝM— àŠVë¶½^@ÊáD²�:`!²esÂÍ$+L#áÄ)ì€êIë¸δÅ5r’“˜§c jJÛhÊ>,Wa}g(¨L>†4¡I¨C­¶»>–£ÝšfA¾ÉéfýÕRüˆiÕŒOŽ3·ËWPf¿ ›„d®f{§8q$�<ÝHh\+¢}kø¼Ÿ5ƒ#Dz(R,DµhN˜ìÙ'8œ^HmÇñWýchéwŠ£^¦mèú�ZÛ)Ž8À¡“idØÁèKp“¦´iß�Vá>¸Ía¹òT|ÂiÕ"Ÿê6¢´ì Y›¦Ê ¾n5†:Ƕîmþöï娛ŽãýO§u¹mÿ›øYc¸é­�¹×Ó„nÒÙ6Lç¦g—RTÛíp§Aêç X}ԛ✸š_B!ÎÛ®/¸ÿ¾8¡�4ˆç¿~Š!�õÿMs­ �“™¡1Q–¿j)*FUESU.œO©×²yïØÅ'=Ío9(¾ôä^æþÆ �c??ǤYqè`êr7_¿y=MËÚhVÖ¿?Ï­¶ã7ìßüþÄ%”µ�˯ÏEÅC‡}:ê*®¼8—÷Áõ¾#—>ö-¯Œ¨!ï®ßSwþùÅ+\éAcÖƒå+?¢:ôaÄu73aPKü*m¸~j5¯Ýû›aŒ}å éUý-…óØžúÇ7U:rÏ'o0>2—½ÁÝÓwb÷ {åùô{„�zÍ÷2í£Ìyq(å·-{¿}ù9_/ØFb�Vå(WT Q]ñ· ¸¾W“ª7OåÊS1µâæ×ßfZg÷!…²²cÿ™ý4C,µÌÄ_J#¨s ÆâºÜhDUj³=*ª  ªz-òâ&�ªçCQQê£ëFƒÔϰz¨7ëB+È 1S#$&²b[£†iB B!¼RÀ†ß–�¨›ð÷7P�»Ž9Ë2tu“zí×I·�ó÷¯ý¹÷‹7¹)æÌÒÍ—?Å’¥OÕëÚÎ?JqÃXQP(bó¢U¤¿†èêv‚ã —Ɖ‚¢è VžYA)ù“¢T�VÜW‰èØŸîÑgšNkY)ÇI8–ÄÎ?³så\¾êy#Oºf§àT2‡ö%uÏr>Û»Žu‡ÿ�铺Tl+jɹ¤TÝE.Wi(¹Q9s³d‰íÊ¥—â¨0£NÞ±ml?YˆÔ’]›â[iQ¦ŽQÔ!m¹Ü’»ç;žyö36f:Ñ ‘zÐ÷¢v4 õE-Ê!åÈ.6lÚMÒö?˜¾s‹oxœ—'÷!¢BžÏìgÝ~”ßùžÁoßJ¼»§½ee§z`µPÿuŽùògXõç¿A³c-²ÕºWLãÕõó…¬êM¯9IøþI&}ãÏ=Ÿ½Æ¸ ;©ºi$  „ zÖ*f¯ÌF·\ÌwXøtú*¶Ì[Äñ17Ó²>¯µz{÷&¢Ñ¾ÚˆÕö¡Xéüj­ã’8¼s �_Åm-ÜïÛî%,:®Ò<ýÄqòK—ãnݺ«ß�t¼þ ^xæ†MQPít+gÆ»_,ãðæ¯xì¡,žý>. Sp9nþíN¹õwºñYþ7*°æO]Ãi³áÑ[Õå�â@�žŸÀ¯¯<ÎKK“9ðã,~ýãbÜäÍ“‡¯UÊB!´ßdþ{yåcÁÉÞ&rûçÇQâFñäË㉫2‹»ÖÛë´6»³ø×“¿ñ쓟²á´Ž¹Ù îyêÆu ÅàÔÐu@E1@Þ!æÎx�×~K`ï/ð¸åU¦OŒ§¬cAÙqIÓ&™$ü‘7À;7µtݼ¶e÷WÖêG…·ÉkÞ–ÊËó6]}7g£~¾�ÔG½éõºsØ¿/�øâ`¤îá4H@A!D­iœ\ô; Á¯ßŒÀÁ/V3ÿÀæíÇ´N5_Zì§Ž±cû>Ndàð !.¾;=Ú„�éZ�N~J'2w³v¿]/"õð~öæð ‹£U_ÈKâ@b.º9Œ-›¸ìï8}œ;ös<-‡"ŇàÈætìÚ‘–ÁUoCô’åáMÛ¸` z){¶°åP yš!MÛÓ³G;"Ü<ÕmYÞ³�„”, l*>A4o׉øØ€šÇ(Ëuíéj8}úøsüØ.>ÈøIÜ\à‹Ø²d%)1ä¢Ö¬?~¼ÆuWnË–µ½�6¬Ö¢ª7â>±\z˳\|IGyð=6œ˜ÏKowáÓg†Vxê\ßË©.îòU¶þ"믣ógŒeô´ùcå›l¶'°'Á�c®�^wñ{Më«�ÞiÃê¬<§{Ù#` [QV—íqgÒZsgÌbÃi5f8ÏÏx‚�Áv…ET¹w4Ç1úÑ·ˆ¶ÜË?aßw3øîò7¹­Õ™3G0¶bÜä¾|ÿâ\v}=ƒÙ—½Ì ͪž]µ-»¿²ÆPçèyÉLÊE7…Ñ¢eU:iyœÜµ�Ç2(ÐýˆlÙ…^]šâ_SÚEÚª IDAT^j™Î“x‚V˜Æ��{HH=E¡æCHT+ºtoO´¯ë¡!ëgÇéãìÜy€ãé¹X‚›Äß%ž.®oZN‡RòÐ}Âiéj -—Ä„dru"Z´ ¢Ò º-‹Ã{p$%‹|»Š%(œ¸¶éдúë›Wå…÷õfíó©“Ÿz˜“™{XwÀ�®’rø{O0‡5#Ò™D¢Ëiq´Š°TؾÚì�Òc¿(Ú4+no¤îÝÆÖ„dò4 !1í¸è¢¶nÛ��„BÔŽãóæíŪøsÙ°K 02ò²Pþ–Èó¶r{§‹«tƒ>“6•U3_á¿?m'ÍV®‰¤˜ïv-�þëNF;Û?yˆ‡æç–40ñÍ¿þÁ7¨ÄÝøßL댶y&“Ý ÊhKbéÌÿòæ/;*®PÌô{OÜu9qå.ÖöŸsÏ¿RÔí|ólkþxþE>Û–…£,¹‚9º÷þßÓü­M¹fŠžÏÞÙoñ/ãP®³bÃOñ!ºÇµ<ôØ ˆöh4?æqÅITßËiÿË>ö.]ÌŽ[ÛÓÓUC$o VeCð0uq°fŽ«õzúØßM“[wâ´;1¶¼Žß·“ñ/¬äÔšïøùÐ@&·wU ¼œ5ô-§ûüi¾�«  b4€ûýPÛ�‚§]N\ýÛÓuTŸÖyø~Üœ�®†0tê4ZqT P”.ƉÃf¦Ç�÷rÕê‡ù)ù ³ÝÆ�ô¬xC [1t½ƒ_Ç£ów2ëÝù\öÂh]È%œà¹s_çØ·Îbê¿W`oú7Þ›ug…ÁIËyãßï07!­4‰¢Øv4�=Ù«Ü ]Å}ím:*ü½íÛ¾‡×¾Zñ ã€(¨~͸âÖyèo� v™¬Ïú°%±lÖ¼óëN×·p.ºz*�M@3ó™ôùëÞgÊ+ëÐÚÞÆÇïÝB›ÊçLázÞ¹ïUV;[qûû3˜Ôº$L ç³oÎt^ùd…‹ë›™¨‹Æòà#¹,ªò u)¯Ò<×¶Þô&ŸNv~ö(�,(mkä›§îãTš�{•{Oÿ›Ç]N{�/ïîX|#]ëýö]_rÿS‹(ê:•/ŸjÉüÿ{…/¶WjoDõå/<Éõ­TA B!j¥hû<æw¢†\Æ•—wIì9bMçýHÒòyü9¹7Cƒ\´ôSüùÆCüë÷d´ÐÎŒ7š~­BáT«~þŽy;~ੇ­¼öÞ}ô 4Òfô=<Ñj_}¸„cÄ2tÒ�ô 6àß&Ü¿g«g±üµ‡xzaz@;®ºãF†v‹%„\ŽïX—_-dË/pÞsÌz´?!¥ïàMÐóøî…¯Xj»”É�_B‡&f “·óëç?°.e-Ó_û…‹gÜTòj‡Î©oððÛKɲ4çò[®eh—f„ø8ÈKÞÏê¹³ùcëw<õ”¼7‘øªÛ‰ÙŸ¡>aÏž•Ìß|;=ûUëèœZ·˜?s ìÊÁôôY€»û»ú k‚ÜÀÈèÕ|›t’U«�0©};�{kÔ÷r#ë¾]ì·ë(>�èÞþBÈQ)�ãë7p j“˹ú_4½æ€ˆÓÔ™«†Å1ûócd¬_Ç{OzT8gØm¾ô›2•A^`ÉÆÏx{i_^^Ïc·ˆšÕc�S:N@Ù8 %lûùô¹ÿ1'ÁŽ¥Õî˜t —ÄùaMÝDzï?ãå�ÒÌÕò¼M玞ÏÖ™OðÈ÷‡±ù·aä” \Õ»%Áz ëãÓ¯—³ôçHw¾Æ›ãÛ¸øI=–•žÍŠ7ã¹Eéè�í¹æ®›Ñ#Žr8¶u!Ÿ}1Ÿ­?½Ìƒù&>zè’3×·reìò\)?fË™ÏúpjÕ;<6}Y–\1ñ†w�#ÔÇAnÒ>VÎþ‰ß·ýÀ³Ïšy÷�[éPz®Ö¹¼ªW]½Yû|i{õ<Õn=_¼·�£4cøä[èbÀ¿UsÚÙÝMkVòúƒ—ûÃäƒI�‚#üðò7,s `êS—Ò1ÒLAÒV~ùä[Ö¤¬çÝ×gÓûíqTó–L£ !„žÓsùsî2Ò5•èÁ#éåWügsçáŒhù YÏœeé ¾&²ÊÅܶç;Þþ#‡OGî~í5þÞ¦4êÞ—ËÄc™ü(?žüƒ»Ž‹ÇÇÕ}cbò™?s Ç¥ËàÑ\íÁ»’Öí_ó΢T4CKÆ¿ø:÷v÷+k¤vèÜ“KÚ™¹ã‘9œ\ð!ߌíÃÔ%—BUAœ‡2¿ç4>|ó:Z•=¸˜¾1yŒx)×°6u-cT Ÿõ‹×’¥‰Ÿð^º¥y¹|÷eа>4™úߦo`uÂâãk¸iôö}ft"6²;ìÞĪë8ÝwPŧ?Z&+m¡@‰d̈n˜³çŸY�§´kùÐ\WÚЫ«?ß%å‘x0�­¡Ê¹[Ž·ù¨µš–ïÌãøæ?xÿ�ßHÒýé4áNF„«uë Pyýµ) oóï6­•#‡NâDÁܾ ݳuèвk‚Ôcdg!!S£GT¹rÑut]GÀw÷eÓ+kYýÑLVô|”A¡J…åx’¿»v³iË–j7©ÇEÝéÑ­›žjluNÙßurVÿÈ�‡mà1¼öcÃ�85 Ekº]Ü�ˆ&óv�NY¥[§tî¶~âÍŸŽ`5¶äæ—ßá¾n>hN �8ÚtèE¿ö¾ÜöøsI±¦“”ªAŒ Z9¹tŒF—TŸx&ÏœÇGêÖëxgrùú½¿‰å›³<ër®?³^-yówXQ›eT¼‚¾¶âzõ ˪8ÅõV¹Ÿr†BDT*¹hÙÙdézÙšs³œÊìøüqîþµ¦Lt�ð<÷ôuû2�v6θ“ë>*¿|'ù¹9ÚU‚Z÷ã¶g&qûàX v§Ûv±'y+¿ÿªÛkTÙ×µ)5Ój§ÈÈ.>/B¢Â1+ž¯C ‹¤‰ ÙÎ,2²œèQåË®d�º“Ðá÷0yá^Û¼œŸ\AÏûPÚ1ªjÙ¹Y—Aaçž=lÜäºAÞ³Gwzõ¼¨çeã×ê×Ç”•më·�¯+øõÍ�+¶ÒÁ74pÅÕ7ôgÖŽ%äR¾¦ò6�»í°³kñŽ8À÷²ñÜÚÉ€ÍvæcªN§ßÞ㸶ýBÞÝ¿�Ek2]åkGõUV6¶/[Y|}ëu7¶W°ÙË}ØÕéÀÜe,WµŸËŒ}‰¬\�À¤öí1T:o=©MttÐ ÉÍ+¹¾)Šl¶3ùr‚ƒ–Üùɦuì…Ø5½žÊËÛzÓ»|êN;šóÌQ 9mØí¥[¤U3ÍÛýQ.Ö¤D3æöQÄ8‹°•K§´ïFgŸÙ$[ÓHNs¢G»¾F5–:¬‘w BÑxh[ð;[­`ê0œmË߆«ÄA ØÍç·½•¾^¯¥±g&â:´' ÊµQ¥Å°)<þà4&«}È3ëIaïþÓh¨4ëÒ‰0WW95†NƒQq’|0�œJ×Yŧ]Û»xgÑH ¯a-}OR £s§h Š�Ý_¼À«¿náxnÅŽªêÙüì—_FA)ÚÁ‚¥)å^ Ñ8ºl){ìÚ B›³ø-=ÕP|œèZÉÈþçx9iä$`ÏÞý5ü 1GóªIæ´[)´–ÿ±¡i€î$÷äNVýþ=?mHÅ^ã’Î'Î’ÏaMjíÊÍd,ùrƒ½Ü�UéÎ&\ýÀ­tõÕI]ð>³¶ÔzÿtëÒ…É“&ÑçâÞU¦õêكɓ&Ñ£{÷Z.õ/¦¡ê-•#ÇŠÐ1мm ÌUv®†©M<­+Çq½Mçv;ÒØ»? ­ºÆã§U=Êt-’.�ÃQu;÷v.×µ¬´Tö(¾¾ÅuiO ‹ŠP×#ˆïR|};t¤Êõ­VÔPºtŽÁ ØÙõÅKüoîVNT¸¾9qXó)È/8s®ÖSy�õf=ìŧ]Z»z…ÓŸ@?°bµ»ß‰�¥“ B!§†_Θ¾²qy æmaRç¾ø•NÔ2IËÔ#!aÁ ÷mxg&é%뉈Œp57†J&ZV&Ù:”ï-­XpyuTË^õ=sy7Òq£LÚó43·ïcöëóëÛ4íÐ�^={Ó¯_úuЬ:j¹;Þv?.ý]3Ó{ÄD-ø…Ý‹—qäÚ[hcY´ôNSFŽ©ØT§â¿]-×ÝöÕ¸½¹§sЃ¿ñèê5uCmÐåTžÏLŸfñïA•Ç}¯LÁècA©õòMô{øGÞ¸²Òg)uy©Y¿ðkÞýô¦?¾Žm÷ý—ÿŒŽuß0«iÝ5uõ­.]ÝR»ø»/~%Ÿ])È/¬UH/(¤@?ü,ŠëcSРéX¿”»>9Èœé_3dú�tµ¸Z¨ëui'�:´ç®;n`ÃÆM@qCü®;n§[§Ž8ÝŽ$y�h uŽ«ýëÌáÔéâº<4$Àåv*Áa„)õ”ÎU>uÀyŠôŒâÛ½#?<ÍÄy®+s{N6::E™ä8¡‰ÚeåÈ&£ôúê¦>R C%-;›S„V¾zRwêÚßò8“÷<É[÷3ç­'˜;#€˜v]èÕ£'}/éÇ%ñMð©Ð‘ >Ê«žêM�óYÃ|î¦ÕÃþP|ý‹ÛIUÖqf, ÝÕô�¥“€‚B�äoü�É ±ÿëGÿCÕyyvt4²VÌcõä> /}IT·c+éÏg4. €{I÷V“Éýz ¦âËŸîpP5ø_»­Sü;sÇë³è¿ì7~Y°‚ÕÛ��´{ ‰»×0çË·Â]ÝÃõ0ߥtŒ�†3¼Ù>;²”ûÇ1­“ ëî¥,9©aé3œÁMðþ²¶´,ÎFC%0¶™ë#gs9.˜-~øW~5ÆÝ«žº£€‚<¥Êò A-pÓ3t³2þ¥5ü9ó–õ’aåÞå(þÍÚVü”KQQÎb—ÔšFû£rм‰di=‰òpŸY“N’¦�bŠ¢Yd ‰4h3î~n\ú_›Ã›ß_λ·µ§6c¢kÎ3 r§³¸á]Öw^àÁ„zÑ@uŽn/{UÁàîš¡¨ÔJS¼Mçv;%×]³cw¸9&ýšÐÌŒÁæj²Zײr`/9$MFƒG×7GëzÝÔŽ‰o|ÎeËçòÓKY¹õ0É{×1wï:æ~óÁmqÇýS¸6¾äúVOåU—zóì©§ýQÇ}Ôê0 (!„¨™žÅ²ßV“­)¨F(ÌJ¥ÐͬUÁ‘·‘9ËÒ:6ª¸—€bÁ× STX„F@üs§X°”<¡´ZÑqu¯c-,B‹¥âÓoBˆ:�'†N@·f‘°s36¬aÑÂ5ì;¸�×9�飹¦ÆA%ëú¸P¥#F´á«™‡X²x'“:vdË’U¤ê ÑŸà*w§5uOðtZUZú:–ïu€b¡{�ö˜ª}$ÙðË©8oÙÒÑõjúÖ{¥æíÒ5›ƒ >èj\ßyÛÙ¼ßΰ¾Åþ‹ è…ää9¨©ÉæÌ=UÜ�Vñ'Àå#/WÛVÝ|uIk ]—Ž˜ç­Åz`›N_É•¡žœh6ölÙE¡†6Ýèì²+JÅkƶL|ð*–ÿóþð? x…›C”rõKÍùÓœ:uhÇ]·O [§xœNG ©.�¡Îq±|Å„OÉWlV:¾Uêr½°€B­|] {ŸÎívXðó0ÑmÒ{L¿6¼úà£ÓJQ‘½$u=—•âƒoÉû€EEVt\B5ŠÊ]ß,Š'�é9�¬¼NÝ�Ýf¢åå7ñØ� üËqŠ„íY·îO,XÅÞC‹yë_§1½ûWE«õ_^•·¼Úz³ùôæºçõþ¨’+«<½†kä9®Ãd !„5Ò3gS!ºø×ç°rÑ|7?¿3ëÖ–t+Û~_ıÒ+·Il¤p’œ˜ââ}AÐV¬u}œ¢Fe$'¥¸ù,¢ƒ”ät4LQ1Å]-ë‘âFÛÞøyÚ³Ìúü%nhaDÏÝÌ/KNºÿÔe Ý‹Ÿªéuš IW“NƺµìÈÙβµ§ ôRFõõ­!­ûÛ7OÒTøÑsY÷õOl³êÅŸíP!ÍY_Ž·ùðòÇÓåkŽÒAÅìÙõ3Ó|bi©€nãàþ£Ø«]Žƒ„{ÈÑ@�lI ¥ÁòîYZ… ¾¹ØOA/ÚÂOs(ò`ÙÎÌü¸" M1ÓyÈe4uñÆC•õêæ.ypdJÑ>¾˜ñ;ÇU&wó»[·ÓI×Î�èÚ¹§³Þö}cW?ÇvÝëœ*WCˆU'8]l‡3õ$IÎzJçn; ‘4‹6¢à éÄQróó(¨î§ÈŽÖPe¥FÑ4úÌõÍárÿ8Ë]ߢ‰P‹ÏG”â§ýºÓ‰CwQ&9§8¥UZ_¹mv:¬X ó)°›‰í:�qSŸáÓ¯^c\K#zîVæ,O,.ëz//×?®ëͺ峺õºœæõþ¨y}µ)‹ÆP‡I@A!D øãvÛt -‡re—ê:h;|�Ìà8´€¹{JÞsPÃèÖ-)›7s¤Ê�¾“ŸMeðÐa ~lY.®h]äÔºwmZ¶žc®" ¶}lØQ€®˜ˆïÖ‘ÚŽÛ_�5“„m«˜·æE.&+AÝÔ;�ìÌì uºò—ÿ[øeŒémAÏÜÌÊ_þdCD^1Œ^&½æ´5µd<ÙV­�?¿Ê+óSÑ?.ºuý-çp9·ëñÇ£åëœÚ¼žÝ@mJËXÙij+ô�FE#qÑlVfén—£¥­äË?NàÄ@Üå—ÓAõpûê’·šæ ÀÄkšcÄΡ^çƒM§Ñª›ßšÈoo~ÂÚ\ 5z·�ˆô¸¼œ÷ž|„7Ög£›[1î±»èm©ÍŽÖÑü.áž)—B›>ÿž-õý‹¨^½×9Fº]Ö—`UǶýW¾Ý™W¡~µ%.䣟ЪŒ…àm:wâ†]MoçÑÙ¼ócB•×ýlÇçÕgžãžI÷óî.¾;àuY)´~]- ŽÃs™¹8¹ÒõÍFÂì/™Ÿª¡]ÂØ+μn`lÚ‚fÐNobùÎü eâHYÆ;ßìF3T,-koþëþ亮ùú€«ëÛ!6îÌDWŒ4oÙ´¤Þi€ò*¿M5Ô›Þä@1ݶ5ÜOó~\hd !„ÕÐ9½æ7–fj(¾=3ă›b5ŒA£ú2cÓ ²VýÁª)}¢ Æ]ÃÓÖsÏ{[Xÿö?˜¸f —vŒÀ�}ˆ?—­ãp.÷¸�ûFŸ¹ÉW‚šÓ"TeCj ³_}ŽüÞQ܇)·–û‚DåÕÇ]Í£“Ö2í½­¬~íîÚ<Š!]cpd‘°y)óÖ§ÀÅàû§2<¬n—w5zwŽ�Ë?ØÍÇ÷ÝÁ†—Ò§m A&�‚¬ìX½ŒuǘâÆrëÐÊßÚv¥¶­o—�Ôðï5‚�aË™“Qˆ¡íP†·©nù•—SÓ4;›ÞŸÊ¸OË•ŸÓF^N¶âÏ+*¦&ô¹ùQžýûEÙí•–ZÿËÙ0}×~PÍþ4uaÊŒ'¢Ô.]•ÐáOðÑ��=hóE5bö #®m;º_|9£®B¯°ZíÕ¼êQ˱åŸ&ËítÀ\ˆ]«œÒ•QQ¬Î²÷}=S5( ªÑB@XíÚu¡ß�«¸~HíEUG×øt˜ÀôÏzðëg_ñÃ’-=¸�Ôƒ¥ËRñ oÏ á7pû-Ãhg)ÂV}4ÁÅzÜÕ˜Vwb÷‰çï¯ÆËæË_æ³rg ;7’P:�bÀ?º+ƒ†_Äqƒiç[óX*no»œaŒºw"ìœÁÖݳmü‹k uŽÛ¿ëÑ\ÿ«h¯¿Æ¬åGØ<ÿ6Š)„ޣ啩qü1õ'ÀVö}�Ò¹Ù4�ÈáÏðI“ïyûƒY¾m>Ÿo-™¦¨ø6éÊUwßÅ?®é€ŸÝáYØÖÛúYƒf×¾È̈Ïy󣹬]öû––n‹™ˆŽ#¹sÊÝÜØÕ‡½|�à O?IÚ‹oñóΣ¬š}”U(¨¾1ô»åUž½ÑÀ—Ë‹Çl)+ÝL—»ßä�È™ñý2v.ÿ•�ËJ—§ úEÑ㪻˜6y |lg™u.¯ºÔ›^äÀØ™›¦ cÝË 9~t=sJÚuЫ›æåþð$4[]˜¿±Q"îxUG)î*rüí»«�yïŽ-ô¼dÀÙØ.!„õ`˺UtìÖó\o† rSN’˜™�Ã'”fÍc1»¿ávæ§q<%üB‰‰ Áâq$ÀA^Ê N¤çaS-„5�#6ÔÒ@]Âíä§'“˜žC�SÅ7(‚f±‘øWº×uMÓp:�$ìÛEëö�j¹N#–@ŒŠ[^>¶JwÜK ¾f­(�‚ÊM~øšÀYDA¾µÜͺ‚Ñ/‹Q{>y…å;q–®Ïen@×Ñ4'šÃ�ÝnÇéúqÌYZNåÅ:°æå—|&´éÊ/–O~‘'#g×´|]ÓÐ5'» »ÝY}ƒQ5b2û`2Ø9•œHrV>vÕBPx Í"ýQ�6ìV[ =Î0øàëcp±ï*­‚j2c6™Q�§INL%3×fB#cˆ 5£ÙmØmv7y¨þ8¯@õÁ×ß‚At;Eyuþt^m>°‡6ñ]0 ¨ªŠrοãyF£¬sJÿ®Y)Ì+ª8˜®bÀlñ…‚TŽ%fR€?‘Íãˆ2;(²:1úûcVuì¹XuLgô%ÀÏìz;ÕèƒÙLjýTÇ“OQ¨›Œˆ%.ÒÕnÅj«|sÜõ3ŸO>ø{¯Ú IDATø¨¤žàDz.6Õ—ð¦q4 6à´Z±9\œ$ª _3¶Ì“KÍÁn &¶E,¡ª•"«Ž9À“ªcÏÏÅê<³.ƒÙ‚Ù …É$¦Ÿ¦Ài(¹¾5ÁW·bsS÷x_^U—UÌÃzÓ«|‚jòÅäÈædj>ø‡nÁYdC¯ašWûÃè‹¿ŸE·Q˜[èbi#>þ˜T GA.]vê‘'uXó{ߥ4† !„¸€5Þ€‚W�ûŽçz“D£¦ ¨*ªRüÚ†®khnƒ-�•R®�Z|ƒ ](c”8|`ïyP8OêE-.KttÍé¦ëx=¦«n‘ŠŠRºÌs|*ªáL}àá¹t&�†¦i�K£¨jqÞÑÑõ’›{OÒ�£òò*ŸŠZ–F×ôŠù«nZ•užßu›'uXù€‚¼ò „Bq^(¾)rý9ÔóEqï!jE×М^Œ´émºê©kèõ¼LoySx[‡jŸïsU^^åSw7ÎA Óê²Î €„BˆFâü|–!„8_I�#„¨+ (!„�…´î…g“Ô9Bˆ:’€‚BÑhHë^q6I�#„¨›†èZ!„B!„4 (!„çPc^Që¹ÝX·KѸxZWÈ+ÿßÞ}ÇÇQ�ûÿÌlÑزeÙ¸›b1½„!@psá&„BK#” 7$!$@h�p ä!ÔØŽ Ýî]ظK.²dÕ­3ç÷‡$[–%«Ûß7/½l´sfÏÌžg=ç™sΈˆˆ ¶íÁql[¹~‘½•ëº{M ë;GDZêÊw˜¾ADDD€@0D¤¾®¿«!"Ý ×&÷w5:Dß9"ÒRW¾Ã”Pé'Mà -Ë"-3‹ÊŠr\w`<ß\D:Çu]*ÊËIËÌÚ%¶}çˆH[ºú¦„‚ˆˆH?², Û¶ %§LI¥déBª*+pœDWMD:ÀqTUVP²t!¡ÔTBÉ)ض=à’ Mô�#"Íu÷;Lk(ˆˆˆô³¦ üìœ<ü>?å›KY¿v®ãôwÕD¤¶ÇCJJ*…E#HMÏÐÉ„&úΑ&ÝýSBADD¤5ý£íñxHËÈ"%-cžßô§ˆ <͇Û¶�mÛx<,˰I}çˆH“žøSBADD¤Ÿ5¿À·m×uuQ/²iºoº¨É„&úΑæºó¦„‚ˆˆÈÐü.AóÈu‘/2p5�Õ�ºc[ô�#"=ñ¦„‚ˆˆÈÑüó¦‹ú½¥s"²?Û[ãTß9"Ý‹{%DDD ]Ô‹H_ÒwŽˆt…)"""""""�¦„‚ˆˆˆˆˆˆˆtš """""""ÒiZCADDö¨¬¬¬¿« """"}¤   ÃÛ*¡ ""{Ô™TDDDDdÿ¡)"""""""Òi¡ """"""]fŒéï*H7tç±±J(ˆˆˆˆˆˆH§4%š'”XØ»4%Œ1;þÞÙä‚ """"""ÒaÆŒ1ÔÖTQY¾•H8Œë:ý]-éÛö†ÈÌDJj餂 """"""Ò!MÉ„ò-eÔVWQP8ŒôŒl<^u-÷FN"AÕöm”®_G$\GNnÃbÜM*èS‘ví™P½�Úê*F�?c ±x bÑþ®žt…e‘’šÁ˜ ™”,�O "%-½ñ¥ö“ J(ˆˆˆˆˆˆH‡c¨Ü¶�ü!E$q­›°·3†„ëbYùCŠØº©ŒäÔ´�PÐc#EDDDDD¤]Æ\×%®' )™°1Æ % ×áºn‡?[%DDDDDDd�š?ÕÁuL75(“eY8Í’ I*hʃˆˆˆˆˆˆtŽëöw ¤‡ueĉ """"""Ò)šì  )""""""ÒZ3aÿÑÑÏZ#DDDDDD¤“”\èS±Ê«£O�ÌÌäÓ‘(õ‘½EçÛY¿z µÆKæÐbòƒí,-gõÚ "V€¼¢adùû¦š=%öñ\pç»Ä_È£O]ÉÄÒ“ Õ‘}�ëºlÚ\Ææ­›‰Åc$q|^þ¤$r³sÉÏ+À¶5ODDdoÐßù³}÷\ÿ'>OdqîÝÏr㡾=nï¬}�[¯}Ž5Ö8®{ê~¾5dïºæ0/^ÛÆõz±­þ?ÿM”P‘^ç8óÍ!%9•FŽ&ÉŸ„Çã!‹RWWËæÍe”m)å�‰“ñx<ý]]iW?wi-»qA@ Û6í×DziÃ`c[Ø~€ñ÷K>øðNpãD#1Ê36”P‘^·zÝj²3s9b•Û·‹Eñy½ø<ÒSÓH ¥°zÝ—¬^÷%�êïꊈˆH{ú»?nZü½½ú´|½¿ëßY‰áDWbwJ(ˆˆH¯«¨ÜÆAãG‘¨z�dßH‚iSðxl\×à†çŸR˜{0%kêú»ª"""²1µe””Ö@(� Óñ˜›–ÍgÞª2jÝ£˜tÈä´XsÁ­.å‹MµÊedaÞDk/déúJ¢žò‹'rȘ\‚mάp oYÉ¢ek(­¨'î �‘[Ä„ƒÆ08´{¡¦z_Ççh\2ÂÔ”RRV»£þ‰ÍKøpÎJª‚c8ᄱd¶³´Dw)¡ ""½.�òo!)ëbpJ1‰Å7 ›0ž@x¿Gšû ÑX~WUDDD:ÀôÀ-~³q#îô8Ÿ}N|É\×Å=ûðÃðŸu&žáÃ÷øþf—¿ï¹>¦Å�†¦ÿ�-~–Þö&‘¯æÙÛ†3ã7wóÌ‚ ;6·ðçMáÚ_ßÊù#vfbsžàê_Ϲ!ƒ¿Ýùo®‹ì|ËCƸs¸å—WrÌ ]¦j1ÏÝ{?S?Ú@½Û¼^v¨�/»‰›ÏM¨Y2 6ïI®¾ó=âƒ/àÏO^Á„Æž|láT®½ý]ÃÓWÔr×Íϰ´Þ`ç�ËðcÇ�ÑË=~%DD¤×“’ØZ'×y_òñXI‡`9å` ‰ªG©ŠJ0ë慠ˆˆHp_xóÿþNAfP6ÞsÎcpKËH¼û6õO“_>…2m*W}ċϼƂ¥/sÇ�ÑDõõõäçiʃˆˆÈÞÀtñ¿ØsÏá®ügX!΂EX CòÍ·�1m™Ó¦‘rËϰŒ�³`�qcpÖ­¡úñÇ[ÙSgkÓÖ¶�¿µòùÚwÏ À‰KÄI8 ñÖ胘�d�³…²-Îîû³³8éâ3)HDˆ'â$œ8ñxFžÉÙã½àVñÙç+ˆ7–²F\ȽO?ÎúçƉÅÞËqâÄ£ãŸ@Ð2Äׯc½Ûzýw9Ë`n½Åáÿs£]ºõ3f,[Ë·’“��ßçog"""²Wrׯ'|ßýØy¹XËK~ã|Rÿö7’N9oAÞ‚’N9…ôgŸ%øßc–.'8¢˜êßßCbÍš^­›•4†‰#håqŒÉ¤†, J4¾{‡Ûò�eò{÷r&ƒQ£²°qÙ¾~#Û‹Zþò‡ gü„Á¤íØÖʼnLjFÃÔ?I‹ëLÿÞ;†Éã}˜>~z…¦<ˆˆHŸÈÎÊ¡²ª’úú:2²Ò9é„SyëÝ™TWW‹Å2xHWQDDD:ª ×èëoàIMÁª®Å^LÒ~È}ÜG"áðƒëˆëºÜó‡»ÉÌÊâºk¯#>ûS¬MeøeSóÜÿ‘ù³[º^Ÿv¦HXÁdB­íÇXØÖÎb»•KËe�¯õ÷OÏLÇf3nm5µ.äØ ;pëÖ3{úëüë£,[Sʶê(ñsì–õl¯þ�,²­×£7)¡ ""}Âëõ�±ørÍ*r²ñ¯¯ãº ÏcÈà¡ø4:ADDdŸÿd6¿gûv’n¸l‹m¬Y³š;õK\cذa'N W\NõOŠ'$òÑG»í¯¡Ÿïv쮼ë6Œ"°ì¶×xìJgÜïo³Síõ5¼bâÎŽ§F˜ªy<|Ë�¼°2I9Œ�| Gæ�ôãõz±6}Äߦ/'ÒÉjX^_¿tî•P‘>³dÙ† ÌÁNâ‹U+Ø´¹ŒÚÚ:/YÄØQcû»z"""ÒA]™o]¸€ä¢aP±{ÂŒ1üô'7òë»~źõë2d×|ÿ:Œ1Ø'Bmž!D.Üõ=X`ÂT×&0ítm5Û©6€•LJhgý[˜äžŽºE¹h”¨i­œ!�`’H² † Ÿ{€WF± NãÎoâ´|O㢌 Ä?ßÊK3 »>³e=vÿ}×VAè­¡ ""}&5%•OgF]]Æ5Äb1JV”�–’Ö~aÙ«9Ž‹ë¸8®‹1.®ëÛ³³[j[`p›¶1“Hì¾³¤! ˵ÀÄøbÅZÙ¢™_.\Jµ vîpŠ’{î1”¦z3["­uã*¶–ãbáÉÎ!Ûœu|:w .^¼ðRNÈŒ‡‰F#Ä¢Qb±åK©ëë¬@7(¡ ""}fíÚµtð�$''cÙ~¿Ÿ¢¢a¬Y»¦¿«&"""�a:ÿãŸ0�DUø}Ä.Âu]zøAJKK)(( ?/�õ6pÿ÷ãº.ñ… 1~ñªj'îº?»˜c�ÊÇÆe㛯ð~…ió}Ý-ïóìôõ8xzÜqŒ±›½Þ‘cjkÀ$–3wId÷2ÎF–.«ÁŦhT1¸êë `‘™ÂuZ”‰¯ãßÓ5,Ƹ§zt¤n]ýé$%DD¤Ï}äÑ,[º‚?=xÓ¦McîœylÜXÊ1GÓßU‘Né|oÕÄÄjj1¡ á§žÆux¼^Š‹‹¹ùÆ[¸éÆ[5jÉ¡ ®ëþË“XÉ!â5µ„Ž=¦ÅþlÆ_p)ÇeÙ¸ð‡Ûã�uu¸»öЩ\1�ßþüA>¨4ع_åš FbwºGÞÖë`™*ÞyîŸ,7ÿ½ËöÙ/óú— ,ïpŽ?¦ vy6�`Å‚¥„›ï+±…�½‡—j‘nƒ‰lg{Äí@=»÷™t7£ 5DD¤ÏŒ7�áE#ùÞu×±rÕ—0rÿ…ý]5é„.ÜÌ&tÞ¹l½ï>ü¹ƒ°–,¦þÁ‡øáu×ï²Pâ�7Üêÿü(ñyó0ÙÙDª«ÉÿÖ·vï>gœÀ­¿.£êçS™¿üUîøÞLrGŽfd~In=[×—ðÅú*¢ÆÂ;h ?øÝ�9:ÅÅi¶£Öºä{:VÓâO{ÈÑgÿ“]·‚Ó¿z(ÅY6U_ÎfúŒ¹l2^Ÿy%ç¥aáH;�ãO›Ä“K>£ìõ»ùqøLN< ™Ø¶5Ì›5‹ñ£¸óž¯0ãêßñ~x>/>ñ ‰CÇrÄ1ãHiQ‡–õØSý{“ ""Ò§B¡Ï>ùDWCDDDº£+Ã㇠#ïÖ[)¿ï^ÒFyúiâŸ~JàŠËñx ÎâÅ„Ÿ|šÄ‚ùx ò©Y½†Ü›oÆ.*j\s¡y$�¾„‡¦NâÕ©ãÅ·æ²æ‹lþ¢ñuË&){4'žúM¾ûß§0*!æ´¨xk:òzÓŸV!Üu!£îûO=óu��´üƒ˜|ÁuÜvådBnbÇæygÞÂo¶ü†ßâØ¾¨—ˆˆô€¹Ÿ|À¸ƒ&÷w5DDDd/gLÃB‰Žã°jùbFŒ×¥ýø}~6œs.ñ+ †�bªª1uõÀJa§¥âúýÔ¯Û€¯¸˜¡ÓþE,o{§¶Ÿ? Ÿ'Áö² ”UÔ·¤eP˜›ŒíĈGc´Ì%à ’òc™áš0Îî�”’ŒÏ6$꫉4®þûä^νã-ÂC.äÑÇ/çÀä Ô•±fÃ6"ÞTò†#Ç%‰³kÄÆ›Ä—¨díÚMÔ¸Id.¢0 b‘ ד”ŒÏ©f{4‰Œ4ñºŽ/DJÐn”pmdg=Û­ç|Y²Œ‘c'âñx°m«•gl»þšr¡ """"""}"�Qô¯7¨xø6ýêW„ra§$ãR€$¶W«ÜNd[¹7ßLö�D8\¿ç�º â‘q,’2ò‘Ùð¤c\buµ{.›SWÞÓDk«ˆîa ã&ˆ…kÀ“Faq×­%iµ²$¢u$¬ùE#(À`Ü(õõ;‡8ÑZËCЛ RטH‰×SÛZN¥Ýú÷.%DDDDDD¤Sº3²¾>\OÚ÷¯"ý쳩˜:•Ú÷ß§nîHÊg1ô’K hõí%ZÔʸN‹½£Õ™ÆÅq:øîímkLŸ¯‡ÐJ(ˆˆˆˆˆˆHç˜îuwcÑvnY·þŒA¿ü¶§a½ë¸8Nœx,†mõÿÀcL߯†8@(¡ """"""}Îu]¢‘½$i ­RBADDDDDDÚÕÚ}û+ߤ+øË_/ÁØÉ Ú{Õý¬÷ÁC‘ÞbÛÇÁ¶íþ®Jÿñ§Q�—Þ°£ãî3\×íôgº·é¬@0D¤¾®¿«Ñ¿Œ‹ë88ûH2 ®#LîT%DDDDDDd�š†À[–EZf•å¸n_7%DDDDDD¤Ë”HØ鱑"""""""ÒiÝ¡ 92²/ëëL«âIöeºs!"""²ïétB¡µG‚¨#$û’¦Ž�1¦Ë‹“t”âIöu}O""""Ò·:•P0Æ`Œ¡¶¦ŠÊò­DÂa\×é­º‰ôÛö†ÈÌDJjÐó� Å“ì/ú"žDDDD¤ïu8¡ÐÔù)ßRFmu…ÃHÏÈÆãÕºŽ²ïq ª¶o£tý:"á:rr €žë)ždÒÛñ$""""ý£C½—wR«·S[]ÅèñcŒ!�A,ÚÛué{–EJjc&dR²t>�@ˆ”´ôÆ—º× R<É~§ãIDDDDúO§F(TnÛFþ�"‰¸æy˾Í®‹eYä)bë¦2’SÓzt„‚âIö½O""""Ò?:ôØHc ®ë × …Ôù‘ý†1†`(™h¸×u{¤í+ždÕñ$""""ý§Ý„BóUè]×Á莒ìg,ËÂiÖùéN'Hñ$û»žŒ'é_�_Îu{¡"W¯vxO²ŸQADDDdßÑé„‚.EzŽâIDDDDDöV^CADz&O"  """"{·.<ô^€«¡¼:ŠñÉÌLîÊÉ8ö¥cPö�xRÛè=:·""""2€uþútoîÿͳ¶¤„•¶PYo�ôAƒ9z ÅÙIôôòx±�à‚;ß%>øB}êJ&öhoÀ­XòkÙ°e;uq�/DZNÃG�á€Ü@džŸtPlöCü×íoé•cÙ� Äx2µ”®,£ÊìP.# 3öøE±µ Å�ˆˆˆˆH“ýb §r)o<;•çþ=Ÿ�õînÇ`Ùòü*\r ç:_½¯ñxñÚ6®×‹mízîÜúr6nsÉ(È%µSŸ‚¡þË·øË£ÏðÚÜ2êÝÝ?ËN"wâi\qýœ12Ø#‰c{öcÙXì�í` ˆç1¶äoüèGÿ`ƒ vÚ‰ÜùÌÏøjjÛ­hojŠ;‘ž³�Oy0Ô,}ž_Þ>•϶9+@î˜IL9dƒ3ƒØ‘j6­^̧Ÿ/¡tÁ4Zô>ÿùæ-üî{_!§n3ú�û%|x'¸q¢‘;×ówXõÂϹüïÉ\7õ\˜ßñ7‹,–ŸÜø,‹ê Á!“9çÔ£8¸¸€ô€E¢¶œµ+>ã?3>ä‹…¯ñÛŸ¬¥úþßð_Å=‘"1mü]ºg �Ëz>›ö6¥ÆGJЇºšOxã½rNøZÎî¼ï-mCq'""""Ò“öé)Ά7¸ýÖ§ù´Êà/<‘ënû”‰Çq1°À²­2اò¿ÿŒÒã$œ–Ûú‡rÖM"?p=?úÇj–?ÿ0/w?ß.ö4쪺”/6Õb’²).Ê&i·÷ªaãª2ªMƒŠŠÈiÜÀÔ–QRZƒñe1|xËP·ùKÖo[Ê'% Œ ³éË–UyHÊJqN`Ïä£Ë™¿<бÓ9þÂ3jÂÄb-7ŠCÊ¡\{ÍÙ,Ÿºž‚!6Ûã�·[¥!QµŽE‹JX·µ†ˆ•Dú ¡Œ›8–¢ô®ÜYu oYÉ¢ek(­¨'î �‘[Ä„ƒÆ08´§^UçÊ™šRJÊj!”Ç…é$6/áÃ9+© Žá„Æ’ÙÓ aìW\6¾=�Ïê!tô‰œzJ %O¿Ç´’™L_q>ß×Á¯‹D«Ígéº ÂžTr‡Oà°ñì©t¦-v>wÝ-§¸‘Öta …Þ»Eöêk¯òÚ¯·úšmÛø|>� ^oCµ]Ç!�qÊI'sö×ÎÞe{çËé¼8§cgpòÕ×plj”øn™„FÆ!ó3éŠë9{ÖOy©ì ^~u>þh2Ij?y”ïßý îßæ/¾˜‘-¯·Ã³yà¿g–SÌw}˜ËG4$"bóžäê;ß#>øþüäLðÆX8õ&nüwMãYü‚¿ßöþŽMá…÷òìUãöü�ÇiZaÜN[«=‡¤)?`ê±6ÆI�Å›M·b¥¼óä}<øê"¶Ävý<-6‡|ýjn¾üX ýÍvÙ|÷-Z�©ZÌs÷ÞÏÔ�6´˜[na‡ 9ñ²›¸ùÜÑ„Zt:ºR.¶p*×Þþ‰ƒ®áé+j¹ëægXZo°óÎeø±cÈØËRd=OñðV¼u,cNú_°°ó;H¬dÚôeD­Ž;õÒ^N;6‹¯mdÆŒy|gÜa­ŽÚi:˶ˆ­›Æíw>Ê[";�̲Iu7Ýq5'äyv-Üé¶Ø•xtwÝ,·¯Å�ˆˆˆˆôŒuøÚ¯sÎÙç±fÍêêꨯ¯'‰‹Å°m›{ïý�ÛnèAc¨­­åç·ý¬EBÁeÝìOYï€=è8¾~D·Ýç�ßÎ>e(¯üu-å³?ai|2“|`5¾–§õyä–Ýø{ »ùÅ{³r ¿örÀ×Äm£fóÌŸg²†BNýÞÅLÉð�\\Øþêð�bFõðþª*Þ{îœ=ö¿ŸÒú­AãD‰„[{¡’÷î»™;ÞÜŠIÍ9Wþ7§MJÕ¬�7“©ÏÌ`ÞK¿ãÇu>¿á2Ú»óè–òò]·óØœ:|…GqÙ%grØð,üÑrJ>|‰'_ZÀ[�Ü�wÐ#ÜvLÆÎ;Á],g%H² ÝÀ+O¼Éê´ƒ9õÔd„Æ’Õ“Ëëï…JÞDFÁJÞHÑ”¿wº|tá f¬s°3�å¬Ãƒ`à�ÓObÈϳñ½™|xù¡œ”¶‡‘XÁÔ;_feæ)\÷Ý#“í£jõG¼øÌk,(yƒ_ÿjCÿt#›¾uºØ;�Š;Å�ˆ°7oðIDATˆˆˆô†·†B("à8®ÛpÏãñàõz±m^¯�§q*‚ë’’’B0jQ¯(«WnÀÁÂ?z"c,Ó±z~àDÒìµTV®fÕ6—IyVËÛ„»ï«#óœ `l�?�3r«™öØLÖ�ÅÄãOᬂ†;šN++ÇïÂÎy—žÈ«·¿ÅÖS¹ö»sÜI'rìW&1iü0²“Ú¿²�.|žGþ³×SÌ%wÿ‰ëÆûp]ƒEñ¨C˜2:‰Kü2ëgþ…çÏ>Œ«F·ÒDš£³b/ͯÅõŒäÛ¿þWÓ0·œÑLœ|8E±K¹þ•ͼûê,¾ä×dw¯–ànx‡·†œÏ#½’‰Aƒ1‰X‚öNá€ÓCõ­¯üœxýÆœ6�E3N¡¾âsB™‡u¢5|ø¯÷ØêÚœt:‡øbÆ3úN/þ�9›7Þ+çį j³î”Îcɤë˜zïù µ\Ö¤Ã9nB2ß½æo¬,y™??‡[¦4Œsèr[ìt<*îw""""ÒÔ”€””RRR°, Û¶‰Åbø|>Êß{—%?¿ ,‹#Ÿ~š´‰°, �ÇÞµ^îvÊ+,2ò²ñ[¯µ••Ë *� Ê+Lž§YY³Û°ãÝíÜ¢y¹¦3gœ8®³s ׉�wü_ú±?塟¹ãÁi,¯XÁ[/®à­Áò¥P0rt‡O™Â Iõ´,cÁ;ïSæZøý�¶ˆÅã;_vø'žËÙ£_çáåyÖ*.=OÇ`�¸�{Ÿ>™Ê*ƒ ãÄšïαwø‚¯n"¼~ë]³ãé]-g,ƒ¸õ‡ÿÏEŒò„‰D;|úœžŠ§-+ïgÈ�—áñeRxà÷Ù²òO ;ü¯.ïn}�×>©Åõ çŒÓFã1M5+äÔ3Æ3õáÅÌŸþ6kϼ�á-šëŽ#°³8é’3(p"ìXbÀ‰ÃÈ39{üóÜ·°ŠÏ>/!>å@¼]n‹¦Kñ¨¸ë^¹}-îDDDD¤g ¸Áª¶mã÷û ƒ„B!‚Á Á`�äp˜Ï/¹„)Ç�ããoÿÏöâ6Îy¯Ïî\—Íçmœ!'ÖÖš ýÈ$, O¾�©/=Ç#?¿Œo3žÁ)ˆ×Rºü3¦¿ð8¿ºáJλä&þø¯T5ŸÄínfEI.6C'Ž&µ•i Æä0v|6e+WSÝÞÍ[ ùC†3~Â`ÒvìÄʼnLjFÃÔ?I‹Ñ|ÚxWËíàÃäñ>Ú�ɲˆ‡7P_þ!™g®ü'YCÎ¥vË»ÄÃ:¸—µoÎ`~|cOçÔ¢]_Í?ñt @|åL¦/�·¾ ÀòŽeò({×uL£FeaãR¹~U†^i‹½Iq×Hq'""""Í ¸)¶mcÛ6��ǃÏçÃuò_�ƒŽÌÄu‰Õ&ð¥eî(cÑrZB�P°aöo}]¸S¿¦>L½¬¡€µûñ¶7ĺùÿ·54»½ò{®!néǬ|ëHÒ Ï%{äõ$¥Œn{G±eL›¹ŠIL9ãx ZÖ)í(¾vd ³ß.eæ¿çsé¸Ã ¶²+=—_ëÇ”ž‘ŽÍfÜšjj\Èvz£-6û]kÿ¯¸ëF¹ÆZî+q'""""=b@-Ê4NaðìH*ضMúœ9Ƕ�wà¶=WÆ¢M•Ô&¾ày_Ãrè³2©:ç<Ò>¸a'v ƒó“±ÙNíú�T¸“;ü<øh鶸`ùò2hÀ àØÉ¸8ñ(NÀ"mÈŽv0'ž{)7Ö¬à¸�ûÞ)eÍë�ñÂ)�påh�Øñ¤ Ÿ×Óæ£ò<¾†fa ítLÕ<¾åN^X�¤ÆN>†£ sH úñz½X›>âoÓ—é¡rM,¯oà5Þ>âÄ*Ù´ô—Ôný7YC&1öÄ{ðr‰‡?ÁŒ‰-!{Ø™¤:˜­«_`ÍÇg‘’sùþ�?s·ýÕÏ™ÁÌ2pYñì�\ü|ËÝ©�ap©x&~÷0NNo¥õøým=ÿ¯¿±MÅ�Æ6Õóm±O(îöÛ¸‘Ý ¸5`ç(Û¶ñUU1èÍ79ð²b*ÿ³;ÏÉ—MØeûÊeU,üÉ óÖ›�¿ñpÀÄqø¦}L¬äs>«:‹³:ô ôKæ.&lÀS<‘ñ©­<ª­µ3àºÍ†y·¶†BÓï[þ­c³ÀÛg0®‹ë& ø‹8ïæŸP²è&^Ùº‘¹ 6ጌm%Lj(‰Dq µÒ¹q ‡ùg$5®?Ñú±ÄXøÜ¼¸2Š]pw>x§å{ykXÔ/þùV^šÑÐA1Ý.×rÐG_´ÆÞÕ•#(yû‚)ƒ(:ä,ÛO¤ú-âõ>üÁ"vC’-�ƒë2 �!”YHÙòi”¼=…ÇÍÄj6§ÁTòîô�¨t-l/ÔWl¦¾�÷õ؉ÚÏxãý-œxvîŽùR;Ž %jZ;"C$Ú0U $5´©.·ÅîÄ£âNq'""""=i@Þlj>:ÁöxˆZPþáâËjðå&QõÛm;¶µl gt2do¶‹ô)Çó•Ð'|P?—¾¶Š“¿sIí¼¯»í=^z¯×ò3þ¤ãj5ì˲,,À8N+WÒnõv¶ï6q¼§Å¨X½Œ…ËV²½àD¾>)«í0ŒCÜÊdHŽ [ áhCG;�ÁùØ” ¬t™­4‡Íe[q±äå³ÇAÎ:>�»/‡\x)'dÆïòÈ<ö�¥Ôµå�ìlªÎ8“9Kª  ÷¢"Vç'ña<·ñ8³¢1ÞÞà ;nßu_©Çòís†â%ÎÊïå±Ï«mÖÖOt#oÜÿ׸Øy§pÅy;^ó“ðX`*+©J´,ëR1.«šplã˜Úú½éðùI°øÿîâŽûþƒ�¾ÎŠèž·7Û—³hƒ–Ÿ!…yذ²8è !xpÙ4g>ëv; ¶‚ÏÖa,ãGÒžŽÅ�P_g‹Ìô®Ób_ñuü{ú¢†ÅÝL”kÙÑéͶ¸§÷íI]©‹¯ˆ±'¿Ï�‰¿eû–­|ùécÔmßv*±ð°R©Úº�’YwP¾~)Cú=cOž¾"ŒãîÒ¦¾˜9“¥1ƒ§øTÎ¥®¦¦�Ÿz O:� ~H¬|“iËb»�“XƼ%‘Ýëëldɲ\lŠFèf[ì‰xTÜõs܉ˆˆˆÈ>¡ ‹ô~¯­éq‘M?îQG±mäH¶fåàlÌäè‹'=šï†ëùVÅ66\t™“&íº/c3þÛ7óí1Aˆ®æ¥;~ÊÏFiÄmñž ª¾|—?ßz#÷Í®Ä$sáÏ®â°ÀÎí¼ƒ‹(ô€[õ9ï.ªÅ4+ŸØôþ} ®§é®lûWá–ǃ×MÙ±sâèo}ƒ‘~ˆ¯þ¿üßçù|K¬Õmc›?å©ß<άƒ�s_ŸÂj¬ÏÈS¿Æ�‹Ä—¯óÄÊHìR6ʪWžeÆf;íÎ=!«±\=;‡‚<H°bÁRÂÍ·Mlá£GïᥚA¤Û`"ÛÙÞtî»Z®Wz6ýÝê|]\×!\_Kò Ó™xÚgŒ8òJ—ý‹D¬–x´‚xd ¥KþAñeâiŸ‘<ètÂõµ¸-{�Ñ…¼ñæzËÏÄ3O¢¨½÷t_›ÀrËxsÆ|ê[œËTñÎsÿdy¸ùï]*?ù'o¬N`y‡sü1…Ýn‹]�GÅÝ@Š;Ùta …¾Ñô”¿ß�Çã!qñÅÌÿýïæŒw{+Ó�E‰Æ"8®CÂIìVÓ„ç.¿ç·xîü5OÎÙÀ»¹�÷ŸÍ¤xôHgñ9ul^»’/6V3ž¬ƒøÎmwò½‰>âÍÆR[ÃŽãô±ç‹Å›xý®©8ù(Æeû¨ß²œß]@à¼Ë9ãßæ•rƒëî£ìõ»ùqøLN< ™Ø¶5Ì›5‹ñ£¸óž¯0ãêßñ~x>/>ñ ‰CÇrÄ1ãº\.u·³²wëNýã‰8ñDÚÓÆRUöÁŒl¶mü�´ñøÓŽ ®®¶Íw®úäß¼³ÍÅ ÊÙÇçÐþÌøŽ;ãþô*fÍdÖe‡qJ†…1°‡�ÀIÞWøÑu+8ý«‡RœeSýål¦Í˜Ë&ãeð™WrþPv>u¥‹m±«ñ¨¸S܉ˆˆˆHÏp��„† ^¯—@ €×ëeÕªU-äð§Ÿä?wýߦd¾ò‹[©­«# ‹ÅZ¯—qH$�ç²?Nå«ï¾Ä³¯¾É¬EXµè3V5½—í'£èPN;ùkü×ù'0Ò!ºÛë|ó·²å®?ñÏEkøà•5|€…,àÈ‹Ïízxö] LŒhÌ´QvþÞ3�ÿºê>¹{&ëÖÌæµ5I“‹øŽËžÇŒ$\òNº�gÆ�À Ͻ̴±nÅJW4?y6¡Ü1œøÕ¯sÉ·Nc|(F¬ùDs†ž{Oäü•û��ßy‘åo7•õ“3ît®øþU\41H"Þl"zÙ‘¼3oá7[~ÃožŸËҙϱt&Xv�üÉßàw?»”#Ò#ä]|0‹ŸZ@Éô'øã‚óùÓ‘ã8¨‹åÆ´™¥ÙKõ@ý�D‚‚q7³~Þµ¤ Bí¶*Š&ý'Ñ2ÉÖŒ»•w¦J�k“~äi›ÚF»m!tøœ˜ý¯”δ÷¶rÒ×sIDc¸ìôq\z×7ñÇßó—g£®±Wlù1ù‚ë¸íÊÉ„ÜÄηéj[ìj<*îw""""Ò£¬œË~o°<¬{àªÝ60Æàº.Žã°jùbFŒ×k•¹êÚ«¹æû×QQQ�ßïcÅŠ‚¡$¾2åp’“Sc³vÞJt‡X<Æý÷ÝÏ}÷üq{¶°}Iø}>,·†->ä¡þŽåÅß~”¿_5 +#‹ã¶u¡lûH &Û¶žµ›«‰ûÒR4„L;J$jð§¤à³]âu5D›æoûB¤}àF ×FpvÙ]_¢’ ›k!9“‚ìN$Ö¡ëtËöáKòãõê¶–RVQC}ÔÁJJ%+·€Á™~L"F<kuѺ¦ó‘”dS¿y=ë·Ö³ƒdÆàtN4B,ÑbU;oˆ”PkÇbãM âKT²ví&jÜ$2Q˜±H„„káIJÆçT³=šDFš‡x]§«å¼A’C~,#\Þåœö¦/K–1rìÄë{4o‡�Ñ[ñäõúX=ë4ÜÄ:lïPŠ�™I"ßC _(•$/˜x=õáxÇúˆ–—¤äd|68‘Â1Ë—LrÐ N„úzo õe¬Y¿�°7•ü¡ÃÈñE‰Fâì¾VbÚ"t-QÜ ”¸ë©x‘¾7ìúGhÊ! ¨§W}AAAŽÚ!Ô›1aZÚiÇ—Ì¡ÓÞt4ú%‚ ‚ ‚ '´=ò“’(UŠÑ®SÞpt{õ h}üç¥ýcy‚ ‚ ‚ Ç­�ÿœÎï}T•Bv•ö�fžñc»Ð{"‚ ‚ ‚ ŒÕþŽ/™îå¯<ÚýxFé†Ò¾�A*‚ ‚ ‚ð|§eíoäFJ{G»/ψ¶G~RÚïYú7G±'‚ ‚ ‚ Âh ipì†ëByÈn²§ã(öDAAA-áÒcxþ(TÌ=ÆÇ"‚ ‚ ‚p¼…ìÛ".²Û7ÿ¼£ØAAAa´¼àBvÓ¶Åž‚ ‚ ‚ £eXinÊÒákWމ›Ô0×j¡ª5\v=ž”éX÷ö ‚ ‚ ÂÑfÑY/.í�ƶ­ÒöH®~üZh€aÛªf+Ûs˜{w“ëïżg}•vjÙ­[µ:ñó¹þ>öïÚñ¬�c4õkõy,mW{Õˆ<¤µ Œ •ŠÐâ~ùÅ¡õKeíáíÆ­.ÆN S”…ìf§ŸÒ8/ÖIe(0¼FÁC Re‘سÕy'¹SO»"ä6rdŽLL¤7&viº©‘ܹËH=¹ŠÄ®oæ)¥kñ�ÝBû‚ÑtDAA„ÈP”›C…›[u[y=¾ot€²ì²óFø…\Ùù‘ì�t¾RßÔG-›•öãý®K5µîÉHeÏÅrØ�;¦qT³;R_F:�­´_¼'v"‰‰9Gô�ÖZ»Sic9XÙ.ì�ÿKîôe`Y”ÅæŽ%GQItšêuã¢Ô˜¡Õ²)œ¼�̪»ZgaÒ�@y–ÝÆ§îC‡AAA¨$oÂðÅz¯cÕH|ã{X5®h­±,«´-bôÐi�Ã�-Ú÷Hxøè’¾Í8FKµþIŸ•eø¶“(Õ/Þ£PàÃvŸ…qTëO¼¶“(õF~Ε_0¸ù–15õ&ŒbÙ¥}OÝOá„Ù jt¤ŠgÓêíC7ÔGv˜ìºÚ` ô¡››ŠCÅh-,EaÅl’kïÇ]rI©�¥®HÈ® ‚ ‚ ŒZמ38ܵøõ‘Ê�–¸À�Û´, ËSMijµ9–ºB¡WÙ? 0ÑuËègeU –ûïß‘�{PÓ�"d·zÖ#øÛÁêß�nš_ÝB,÷¾GzÍf¬\Á„½–../`ç|šPx¦6nÁ>P‡nØIþ” ™ª_+ÂyuK#VaSؼִÆBv½ÆÉ5+‚ ‚ ÂÈÁÜsHmú-¹S–e Ãr!½éiüÙ—£0�nÀ]ùfœÝ«I<¸Šì9•뉚2M¬Ë£ËCv‡‰OAx¡ã¤2Ìh­§½>AÆRøžKw–݇³ô=—�ªž×¿ùoùòb t_úâ¯øâžñ ×Až} F‘R†¼¯qF1%.¾TI5òƦ>¡ÊDL‘ÊãJ{#Ù´áaç{Ðîà2#CƳåò5ìŒïæXíŒMÒÒ¸n¶ö8FÀvœ²±¤œØÚ£v²lìqQYÜ:hÇ‚h[¨1†¢ýjϳ„BÑŠ�£Ã/û­óYNE¦Üoòì‚Áòóƒk„fš�YØ]Ýí­eå­ÃÝ(w:ºibY;Jk¼I­Td8Ú7c°üÖÜZ:¯Õ½±‚ /TR-SyíKyÃI39}jé*Á,Æ/°cçnþ÷áõü×ý»Ø1ºÄyGŽòcߥ}ÔÖHAžø~€3ªÕ4†¢}+JŒ“V�Š7×��H—Ê—k)–­ec8B>•Ä"7DßTG5Ûqa5š¶óÆ&䱜Ĩû:F3x¨ ÍVL*�N¥¨³4I»X±ÀþX=7—Ų~tø>MQ*ߤ­pŽEÁ×5Û‹Ÿ+ÞCíû$ü,^•qÄ©íÃ-Ý/ô`Ö,ðfÎ ñÀS—bé\轂ùç�ZýC²ç· &EÒ†ôê§ñ—½µl=Q¥}T×ýx+N SáY- 9ü/J½Ùm}ü—# IáB‚%çœÏ½~1‹Ó×TNйóçsõüù¼õ‚M|ôÆ»¸yß3Ëf(‚ ¼pÉiV¸ÄHàåQªVàiuŠÂLW$î ¼ô·ó"1šçÞßüž·Ü~€¾Ê€–Þvíïä�Õ¸ñî|çÎáâfE¢ý>wé&î¾¥ƒ¡3hAa�¢hó 9‘7¬(0ã^Îâ2!–í”®ëŠP͸ø¬ÖN|æg­½-ÙŒŽÏ'…É Tµ_‰n8o%‘J£, ÛÀOdJå¼h~e"•Žú<(J•eQïÀdÇej&ŤTxÞ6š 0 ¸a}Ûq0èªõ�Öti¿D1˜´Ê|Míûƒ×µÁ²n> Ëu’iŒPVL¨ë€4�"ciÚRR®6�N0 °È{P”„’”ÄhC:A½IK¡�"�°±£,¿Õæ÷ÆgåTΙ­Ö•Œè!‘Š¿©ü ³©|î’W„!º––…»ü20ì( 9p;Ü�³ë>²§Ï¡¡H‘«èXû`´„ì ‚pÜ‘œ3——µ„Ÿ‰ÞîÕ|ìŽ*b´‚þ]«ùÀÏ&³ê] ™¨,æž¹”ÿ¾ƒ?ˆ"A*о�Ö¡—3¼’ØôbsaèZšÕÖ°´�DéØ2gÓ++S¼^¹_Y¦r[¢ÂC‡”'PÐQ¦X[ë2!å$“%aY)°’ ‡©�i¦ÔÙ¤#5Õ–¶ÉšŽ~7êsy’³çæ}»t®(Œ+ËYU=½E¯³ ýâï‘Wv¯œimP¾‹ï[¸‰=9�|i;žn^Ó’ ûÔœ´B1šrèÏ{ø64ghß'ïä°½<½¾EZÃ>'(ÔôXÇ^�šfÉ—Š5CM:�׿awî ˜8/�€òòX½@YèúVL2^³“Ø·á·e1uÓkt¤ÂcZñ£KBvA8Þhlk¢5úXØ}�m£ÌÔ¹ú>ô‹½¤t±~Ï!žª)F-&ΙÇϘËùóÚ™7!M£n.Ïž�<²q;¿øë6ï}†‰Š¬ +NZÄëNžÁé3Z˜Ñ˜"cò¹»÷ä�µOñã¿î¦ŸãhK¥¹àâ3yÍd ãà{?[Çšd+¯{ù\uÒdf§}ž¼ýyÓŸ»�Ù·‚ µ©%R«]«‰D‚>/ül¦@"öÝÓAI°6&ž6ô»}yz äb·v4Ï?AÀÈþÑÑ$5¥2/•/H°ðÏÃêïÂÞvÙ•ó1�3ÃäDx æ ²Yê¾�`úË&Í'±q#îœ<¦¾.´S+Ãn)É‘A>Æv$dW„ãŽ�}]ì4sX¤ ¹ø$>²d[Ÿã/¬b7såU—ó•åuØ ‚�Nn½wÜz˜Ž4´LàŒKxëÊv&¤[yý›.§IÿŠ+ïï“HSéé|úý/å­S,п'?{p'�îÏÒ«mÚÚ'rÑYK¸lZŠÔ„Ù|ê}/¡ã ·óËž*Ë€�›-Ÿ|ñÛ_9´Ÿxï]Q‡ÒžÞÓÍ^O10 —w^á……[ž[>£ÝÖÚ¯VîHìÇ·–ã�òȉxhn´Ïn;šþÆE^Z48`¥Cg[ZêÒ$mÀ¯HØ ÒÆ¥)•¢½n0|Xý‘žÉz¦Ìv1qQ<гÔf®†‡›Ïâ$’£º9,º=Å®ž~ ™Ó’ÏCûËIR‰ zCÖ×ìî×tô{t{ í{¥¹ªFn¸_ëy îÐqTaø¤FÕÖ‹ñ|ê^�²2‚1|U¯ü€`ú¹ ,ìí÷’=ynId–ÑPOîÌùdX…Yôrôä•ÔÝw$l†®;ª0äÈ]p$�²ë*ð%dW„ã×&~ºsŸœë œVÞù¾×1÷·øÊ][yø°„¢I1óìóøL$F½ƒ›xÏ×þ­]q™»›?>´Ž�y1¿{ë|¦Yu¼ì5gó·kÿÀ-½£ogöÙ§óÖÉ¡€,<ý(¯ù·y´,”v 7ݵ�÷¾ÿ5|î„VÓ\>ôâvn½õ`Åãq´eÌ`RUÇeLbÂÞµ¼ýÆûùÝAùžáøBÅ—÷¨’”§ò8¾ <;‘,«[Ì4[Y·X¶r[YvؾZ�ë’WIü .³’Ñ\¿âx¯€�H•öã^É!vU˜I·-i3¹>A}2CK]š¶dØ7O{¸V’Æ„M›Òœ4A1Д"00àjöxÌd=J"4Nü\1‹pŽ¡ãˆ?Û¶ñ='‘,e²UÖà¹ø`Øëiò¾Æ¸9f¶5ÑàX`C>pèîË’tl´²iˆÂŽ»óûòŠíݺ².9má{.¶m—eÏ­•I·(ϼŠqTcÌI�”ÖXÎü……�°,T•?«�C'»1õ³†ÚkbêÐ-YT¾Ó8‘à„×–•3–…å»h'‰³õ.”`’ƒ]..#!»‚ wèÃÜø£8÷ŸÏåÂ&…J4rÑ%qáËÎgßîîÙ¸—¶vðàÖlé¥WÏjç­ΠI&˯¹ŠßvUû1 ÙñÐ}|éô™|my«~6ï<³™_ßÑ3:/©J²lZ=9'÷ܵšÇªÍëôóƒÛ·ò�‹—2YYÌ;a³~W1_v�$‘®¯@·žl(F{r.Vqéš À¶íRâû¥öœ4Ž—'i|fE†¤¥ ¨¦øS&ÚFs7CϤÛ�Õí;€ÛÚ2œùpPí-$í'HÍ+;¯´�Ò �$–—«RÓ ´FiWBvA8.)ì]Ã[¾ÜÏGßx.ï]ÒHZ�R ¦ÎœÅ3gqÅÅá›×®øëæ=üeÍ6~¿¾“ZÎ>gÚ\.™­ËÖ³�›×j YÓÏmïá ËæR¯lNZ>“Iê¡c4Ê×¸í¦ŸpÛMa…”ñj¶SØÛÉæ&;`µ42MÁ¶gËVýëÖrÓ~£‚ Çø.)ã�i:ˆ|œ �o§Ç½;N�Ç']j'Þ&€ï…BPùH �Ð ´&a<ºÇ–Ac—�·-‹ z;™1.Óëë™Ñ†ájàjÂåÒÜPÔ¸ƒb,­}ò~xœvlÒŽÍ´:ðt‚}½ƒzÆ"\÷3Ì@¶o[Ö`È®¿ËÊÆø¸hßÃtÔG˲ÐZ—cQˆV^/Ù¨ðW*P¯€bø®WÀ«’-!nÏó¼ªçKûn¢þ(/?âKñÑ{HK9�"·w1{n­pYíƒ]¾fhÉ�QÑùh>¨PAô¦¢¨žMÊE±²Q:4$YvA(ÜÎç¾ñ4ßž;�7žµ�ËWLçÄ–v4£B)›¶ÉS¹lòT.;ï4®í;Èïïz„/þi;[+2 4ÍšÈü¨ž»£ƒÇ‡_6Œž�ûÙ¢çr² ‰ií,±¡cŒÇÚ÷¨öʱt½à1P\wÚ¶H “[oˆD^ÎóIY”…�¦-�o§‡œËk '‘¤/°Iè±å¡ì$vl¾a<ìÔI$Ék tØ&@ÎõÈ$Cì'5˜5&\Màá‘(‰O×óQÑfQ¤ú^e'¢µ3£¤A:À²lÜ¢2÷=’ÉÐC �åàò$� *¬“÷¢_Ñú�¾ÿâõQvÛ ûåDÇf˜>ÚÍcã¡¶ƒ­=4vI &"!©£Œ¾ÅëÍI‹Ö´M“£©³¼( S"™$­gšt2äü¨³šMkÂà49m…¶uPj;A€µ£+"fµÖὬ9’A†¤UâœÃóºöµb‘†VœŽ¼¹ÅÄ’åØºÐ 'Wo³¬�ø MY Ùáø&`ÿö-|}û¾þS›ö)“8sÁTÎZ0•³LáĶTI|%'òšËÿ†KOÛÀn¸›ßt?[-f´5FBÖ°¯³wXqîc�†“m°2 LÏ@)&h´(‡i3§sîüvOldrC’ú„…c[8–…“¨gÅh_�ާ-㱫3ûÌ“D ‚ «^ÉSX…ÅmQB( íÀ#­=–)—!žQ$”)Û$¢ù�¥ã˜õŒ‚XØiÎõJßeÅ~$Tyhªvó(†zH­ñ y”ïcE§æ ð,ObTI2áàz¡-R¦zˈ=�Ás>aOEwÁ÷°œDéÜ€Q4'5S36S›LkHPïÀáþ,˦¹.MsC ß÷è÷#¯iÒfZCh3¥4;û¡ iKcÙ6Ë�°«-ïX/¨c‘u,'zN+ÚŽ÷'°“Ø„BÎróèR¨«7dÌ’øŒíÛ© A¡|y˜Ë¡£/”UY7àp2ôNHZ4×…‰‘ð=p½´ûr D¢2ëìðèè+Ð8x&À\,Ç!Ÿ+œñäJ&Öµ(f¯�? ×(œÀ-»7õ©$SRLj°KbÔI¦±¢%: ù,¾“ ¢küâ²h6õI›)u�NÐ�-àk…˜èErÔNâCûã¦4;Ûƒ®o­9žQfÙ5ƒZÒIÐþ™ÑiÑ¢ªÅŒ»ª�£þÁ'0ó/DÏ8ƒºÇþBöôE˜úð}AÑŒÊfÉüu#zÊ`ÀÚ÷$ç- 3ò*Sfspõ¥¢²+‚P CöðAîXu�;î{‚ο�›®˜Ç 2³Wð�+Öðîǹ¢ÊR¥Ïè!oa«¢ Lô²Q©¡ëÖÄbîÙ/ã÷?—)` ½÷ò§uûYßÙOWÖ'hü@ãÙSøÇ+WpJÍ\ãi+F<ã® Âqˆ¥ý0¹¨_ Ê ) ‘á¶ãRßPϤ:‡)E]&5¦¶³nÀ¾~�ÙpmÑZmUîP!>-í—ÊÙÔ^’¦RŒ†ýóåôrìêÎãDo<§6¦XÞ®iÈÄDi2ÅÁ¾k;óìê.›³a‹÷±Z"¥jçÊ„5 ¼Ú÷p´‡¶e÷Ã)Ù)yÐ`ê•Çô†õô¹¸4&m°lúòÙ|xÏêÂó@_t®1i3½ºú ý>‡ å÷»(F´E}¬?~ô‚ òyTcD©å»á[�¡Ϊ˜toªMêÀftÛ\ô¬‹h|pn‹‡noËÂ:t˜Dw=íL¦ ëÐÜ©S›ü<¤½hîiE,ß•�]A„Ñ`\ÖÜó>6o ?8³K¥8oÉ$�íÂr…Áåb2©ÄÈù*A¦?e|²£œ.¤šòù×͉dŽ{~ûÞõÇ:« ÀŒÍ¨!"ÇÓ– ‚PŽ1Õ#EßÇv¬HUžW© “êLiH0µÁ¡Î©í!õC¢"´%›<ð ôEvƒ¢73Ú�oíaÖºŒ�£X¾ržVeç‹íd]ŸÀ÷é F‘ŠÂŒg7&hHŠÈ\Á¥¯°«;_J`TJ”T±´Ìpã(QCX¸Z�öqß·–ŽÄ •À�ì;@*� 1iQç(2É$�Γõ �ÖdÝ€]Y»áýž�4Ìi­+‰Òx�ƤEªâ1Ûö}Ÿú¨ïÅsNzZÍ(‡Ã{Hµ†èB¹41ïeÕ¼Iã„o T"�žwvà‘)í‡"±ÂV‰‹ ÂKYyœR&ôþ&}åã+ Á¢p-&Jª´Smñ­¯éŠq¨(!’¸¥ïæb{á6ú‚‹Õ«W>ѼÒVé4äótg]öö{lïvétw}Û²˜\gÓR—¤!�&môGõ º¼Ý¡}(?7Ú÷¿Ãt«À¯ºÆè Cÿ¨T!Oj�‹išR² e'Ѧcš§B²[¯F7O%¹W£ú³Ã™.k·ú«u´DŒ/¡»‚ 4Î?‰o^ý·ÜwýUlyÿ¦ŽId)2I§ôê¼()�áÀž®’g±~F; F˜ò“œÖÆÂèÛÆß×ɦQ-Bj1{Js”˜B³iÓ^ö óyߺ`:ˆ ×?[‚ Bœ¢*xþ�°ØÒüÁBnÈùRÙÀ/ µÄh‘„RÕËø…!¶ãýÉfû£æ¢©|~y*c xyRQ&O«š!À¥l¸UÆU¶usd½€þ(;RÒVô»Y/@»¹Rr&í{%[ŽìW¥ýJR:?daçó h«¦�Ê~öx�Ïç9OgÖ£³¿Àá�ÆÍ‡^ñ*Ï¢êóñ ÕÇQÁÈù�*Uí_?©õ[1í+냽í^´í…óŒ<‡`þ¹aB¤"íËI¯{‚Ü™ËC�?†\²+ÂñDÎMqÊò©œ`�i<‰Z´…�mrG÷±i5rÉIíáûR£ÙðtůuwÇÓÜ;°Œ+Δ¹üÍ”GY··ÖKÉ/:i&"1¸}ãvŒÒQÿñ]»ß‰‰¼ë¥³h,½�:sd0•Ha"¯loÞg__�CY—Ü@8uemTò’ÑüÎjB.¥ ~¬Ï–íŒh³Heùœ«éè³¢ñ…xwo�޾9×CWÉŠ‘~!WöõS¼VÜÖ Pò]R:²¦QßâçBÁ›£K[C*z)Е͗Ä0�v¢T÷PÒ ‹®lžÖº0¿O!0Î…ã²l«ê}‹ßËv¢{£Iù,/‹æ³ìB� ¶Õ<¤Z“Y½=ゲzJèþ͸g¬,õæÌ"¹ý1,=³¬=ã$2�þ™�‹N‹ÄçèÞ¤H¨® ǦŸŸýô^.š~!¯jµ°›fpÍ¿¼‰+Öoá–'vóÐînvõÈú'™bbk 'ΟÉ+Î\ÈK&%±�åŽ_­âæÃqõðàà—+/áõWœÏ-ïHñ¯¿YÏ=�Ñ20vše+Vð©7¬äÌ`|Öýù~¾·´a-†}v²ÆŸÆ©Ž¢ù¤ñÍ ûùàÝì÷+ÉÜ… xÏågð¶ù6«~v'Ÿs �i¡œ)¼liš_?ž�^Wާ-A¡‰ÀÓšÌ:ð)¨$‡s‡zúèlnÀ4N�å_â×üH̹Ƣ;[•„QGøxA@Jû¨ bìåÅÄ×hÅhÜ~‘¼§éÊBOnqY˜‚G>ЃBïb¹ù¡ãŽØØ*É{ãö0�LcŠÞJÍ­R§8†CÝÝaÈ´“BGåkÝ·øù¢€WÚÇa†¿'à RíƒU¥HirÏ^{ÚIÖÓ>jÏZ²+fƒû´ù“çQÿè˜9§ –WË™KbÇn¼¹3¢¶¨¢Kc?´/!»‚ w]›¹úkûß~>ÁQI,[ÆÿY¶lĺ:ÛÉ�~ûk7^Å5Ó»��üçL¼ú,^Üì°à´s¸åÔÑß7@gAÑÔ\Ok2ZÆxlºÿ/\ù»}d«´S³ïû×ó…{OàæO i5péëÿ–‹_Uàà@@º!CsB¡ŒÏ†{þÈÕwïbv[šÙŒ­êxÝUoæ¬<õÀŸø»Û;ñÇÓÖÆ ‚p\PEȤŒKA%ÃóPUÔäÀ­>Àî|í9”F{ìÛý4?ºõ.þÔ-üó_S+¥BÿÎ'ø»koå_ïÙÍöœeÑØÔÈ܉ ´%ŸŽí[¸þÛ·pñMO±sTÉŒâ�)p÷/~Ç[þg[óØÉS&ÔÑâÀ@çn¾{Ó¯¹ìæ�0šGþp_ÝØOÁ€²S̘ÒD{òY°%‚ ”xx:(;(蘷((A”®÷mÛ.Ÿ%3X¥¶]%ãœ�íTéS€U&‚*Ë™ q‡VZµ[v>ðJ³x>.8uÜV!j]£•vã¸X·X>n»�R1Aí‡}-êµ’ÀõÛ(îWˆÉR]¥Ê¯ëÄf±|¬�R�Ê6+Ľòý¡Ï£ÕþŽ/™Z^E¯¾¥5Á¾»8ëÔAO¥"ô�Mi%ôÀ'µcé­‡aê)˜L#êé‡èÑ,tS¥LEÅP\Ë ú²4­ÚŽžy*ßO�[Ô„·`6$œA/l©] Q uw=ŠÝ†÷-º Ôç OÞ:ì€A^°(‡ööæ¶ÖÑšqH(ƒïyîígç�^öå� ŒÈN1{Z+óZÒÔÙ†\6ËÎŽ.¶õùãêªÌhcNc[»ì?ØÅúý9†æäS¤ê™’Ôtõæèõ«dyG[‚ Ç;ýó^Š‹|/vÅš˜eµâq¥§­²\¬LC¼¤¶óTÆÛ)Š\¬Á:•íDçì�C¤ºv`çzñ[f”�ÃÎõ”Äž…�je z0«yB‰‰Æ*žÔjÖ¸ Œ{B‹m•ÚŒõ»ÌÎãò<ªô¹æó‰ík¥°,­},Ë©þü ¬€U\Ë5&Z­X$mñ8~Þ8DúÀSX^¶4ŽJ,o`¤¤F:*8йœN‚‚yx³]Ò«W“ì€üŒº¡¡zyc0õr32ÛïÇm3ä/Y†I¥"ÑY*HIÌÆ× Í)h¥= ÙA0>�;é<8Ž6ƒ;wu°s×8ÚŒa¼[¶ïfËÈ%É÷÷³ã9²%‚pÜS!öÊŽ+…N¥ ªb#¡á9»Â¦�†*‰€âvËBx« ×QŒ%.ú¼Aaª¬’P³°b²$cý+ HËè¡çãb3ÐVtlUΧ ¼RÛ£ ?¶�)Ž1¥U¼EÁYê—?[ñ­Ø¹¢4îÏ, Ѹ-cÊêUÖ)+ŸL�8¦ái¾W¶tV_º©q˜Òagu"Aîô“)t÷ ë‡\/ÛW wé"üY½èæ– !+W‘á×êîÃvë0Qx°dÙAA„ñÇ6f¨,÷^F¡´ÕBt�rïfâ[ Ô­&fcâ³d7.p‹çb¡½6D+„Tô1îÑŒm‹Ä…eQ0Æ=§•^ÍJ!Zì¯U¥lü>Ã^/yp«åð‰ ñ*Â?.8µReM«Æó+•+ ô¢§´%oÊíWëGÔ›p>¬íö£ëkgÙy)`&/ ³vãຢáÙaëè–¦òDFeÄ<®–B7µTkµ†aCúñ͘ö¨È]­´_ú'‚ ‚ Â8PKœTPK„ŽÚf•sñy¡Õì—ÎEÞÓªóP+ì—‰Í1ôuTåGYv¸ëÅkƒKoq±¨kè#˘ÁrÒjįU£ºÚ*,„/‚d�ˆÙˆ<¤aÃ&‘!©¦¬Û@~é¨LÙó`ªÒ‰*‚²T®šØ,†äVñЖФŸÜLÂ�uʼn²®„ì ‚ ‚ Âxxá’/£¥06a:RÙ1‰\Ö‹›RWÍç›Òy ÖÈ!¥G�XæÝâ8ü1<¨.�¤ìHv*¯�•öŸù:¤ SÓ:ƒÌ!�ýàcä–/D77�¦êPFZƥƱÕÝKú‰Í$s“0må“b%dWAAÆOØÕÂi+°Ü,:Y÷õª6E¯¢N”÷¥`ÔPù¬ôó_”Æ(¸ùQ=�çZ)Ò&ÀXÎ�çQɈ‚´l!ÓÖ$½v’o#°7¤Uô[L:¤bq#/©RåúRÅÊÄ=¢%kYa0;kp¼:ôÄå�I•õÉ(KBuAAaœ±Gé]�N´ŽUÐŽT¾Ì#çå°�©éo­­Öfµs£¸•eâÇ–e“¨~ìÕZ¬müïßhË ûLcÒ‘>d×hT4¹ÖXv¸o'0Ó–âè;r#+ ^�•­v®r¸k¥ýt¸oébv�e£Œ–�]AAAOЍÂ7’0«¼^<«µ–ØIé<…Z¶¢>Ç=r¶1C²ßVëc±†’ÕúRíÜhne™²ãÀà *—ÈNX6Ú-¥•÷¶Ö½©ßµDôH¼¸_«¾§l’–ƒbxQ:lR£¸h¬¶¯tP¶_íúH¶F[n¸ö;ϸ²ôOAA„gFÂ*÷ÒYn Lü©&Rª§t¾T¯ZýZ6ãçãÂ'~ %Tµ‚ò¨+ U¶§“u5íVÛOé|¹ýŠ~¯—Ö0­¨¯_YÀ“ Ù©Á>CE]µqŒæZnvÄ{Z­_ÕžS¼~e S®ùjqä雞GHÈ® ‚ ‚ Œ©Ž ÏŽÝgÅjŒD~ÌCš90òêÔGBæ¯gF¸^"QWæé}¶Æñ¬S1Žj¼ ©„ì ‚ ‚ ‚ {¼ ©dÙAAA8öxAR ÙAAA8öxAR ÙAAA8öxAR ÙAAA8öxAR ÙAAA8öxAR ÙAAA8öxAR ÙAAA8öxAR ÙAAA8öp,?ÀÓßxÏQíÌøðÖ£ÝAAA¡³>ð-P6(ëhwFAAA8>A*‚ ‚ ‚ D� ‚ ‚ ‚ G¤‚ ‚ ‚ ÂQA© ‚ ‚ ‚pTA*‚ ‚ ‚ D� ‚ ‚ ‚ Gg,…7¬~ìÙê‡ ‚ <¯Y²båÑî‚ ‚ ¼à“ XyÖyÏF?AáyËc½÷hwAA^�HÈ® ‚ ‚ ‚pTA*‚ ‚ ‚ D� ‚ ‚ ‚ G…1Ï!AáyˆÛÏ¡Þ�T‚ú–꟫où£Ù¶P›ãö¹xôwõ� ŽSßBkÝq1pA8&‘ÿ;AáÙÆdÙ·m7‡}€Õ0�…Ó‡†)å;Ù¾óùèP%[™=g"UQÎëfçöýd €"Õ:“»ÿ‹·}ðVjÀžË;¿ómÞ5ß~6G5Ø�uG¯íçÓ¿—Í{úÐ8L˜9�)u•%"èa×Öýô›ðY£2Lž3‹ÖäsÔÙ/ôçR=7¾÷Cüb¿lf¿ù›üäÝ'0ÒÈÇí9»‡Ù±ý¹;š¤}ö\&¦‡ô„¡m¬Y·•Ý�ýxv𿉳X´l1sšÃZÔÙ}lxr[÷õ�#MÛŒEœrÒÚŽÂߟ Œ¤‚ ‚ðlcº¹ó«àë<œoãß¹’ùŠtà�¸ê3w3Pú�{.ŸúÅg¸´±üG±¿áÇüó?ý’ ¨g~øÇ|yús0ŽãïÑïòîOÝEÁV3—_ÿsþïU„�¿—?^÷Q>ÿç½x°Xñ–/ðÕ…Ïu�…#a¼žs°ë·|ü}?à©`„í¼å†ïóþ%ƒRÙômà–o|�ïÞ¹•žèV•leù¥ïà£ïýÖWe3À†ß|�Ï~ç.v hk*­ËxÝ?ÆÕçMex9+G¤ÕÈw±÷Pã42irsÕÿy�7@w¯K¢±…†d�·gãÐŽð"ÏC„g k2§œ<{Ý. ص�õ½†ù-ñïŸÍk7’‹ý5… <±ÙãÒSãî Íþ ›èÔÑ¡=�SOjÁÉ\ÄûÿenXßj愉’&â9Åïàö/Vˆ”+¯å«o[NãþLž‡Œâ9›þ>úͰVªSØÄÿëGøÎº,ºÊeãv±æ·ÿÆÕ»ó|û˯anéW|ÀÓ·~†þÆ#ô ©hðºÖrógþïºoñ¡Ó�?GáH‚­‰ñw·??©w�ÍkvÒkL\´‚Ù#}’g÷°nC9ÕÀÌe'09õÌš/Üö>¼þç¸ >ªu_⬸2É®æ»ï'Ÿ¸ùQöç 4ÿ=¿Ùÿ#^ymÛÎóÓËŽÕ[èôj|²*…�¬§¹}³¦6=Oÿ FÇ1ñ<A8F±™wòI´üt‡4ok6{\~Fì‹]w°fÝ¡ò¢º›ukvœ:/nX`ã†møÑ‘5åDVNµ°œå\úÊåÏÅ`„J‚}ÜqýGøüŸŠ"¥‘“ßv-_¹r òëÿ…Ã(Ÿ³ˆE9¬àÍz‹«½²ê˜3£xA³çwÿÉÖGbT¥˜yî¼åâE´x<øëóëµÝh4}OÜĸ„OŸW€é¾‡¿÷X$F-ÚV^Á{ßp“ýüéßåw[ro¿ùÖ-\þ�·±øXþ±&5,Ë¢¯¿�†z Çß?¢qµvý—¯U¹G}ŒŸß|KÍëæà/¹úì÷ñgo ïþÃNn¼xx%îoøo8ëZÖ«³øòúU|xÁ3œ¡lÛ&°-TÙIÀº¯¿ƒ÷ÿàQ<{"'½ü"–¶�¿„®ÙÎóoŸ½èr¾¨Ú»ºÊ"3y¿é|üš·qzÛ1øfþXx‚ ³¤–žÌ‰©Û¸+g@÷±~Ý.‚3æ—„¦éßÀêíaŒŸÕØDý@/}Zóôšõt›y´?—üm¬Û’�Bò,šWœÂBLn?[Ÿî& N3qÎlÚ£—¥ºo/[ö†sã”ÓÂÌy“©/ìãñU±©ÛaÑù—²rRùç¶)â©µëØ´«“¬IÑ4q6ËN^Â̆#ÿŽ=2›}»7²fãöÀ%Ecû4.[΢I™a– 8Òzc$ØÏŸ¯ÿŸ»c/n$RNyûu|å-K©ŒªŒ3º{áÓ½k;Ùð;X¥Ú˜3§�!S)йs'óÑ_EýÌh®(£"Ϙf c�®ÞÊþEÃäùœ²r S†LT.ë,‡¶¯gÍ–Ýìu!Õ@ûôy,[:ŸI™áî¤!ß¹•5ë¶²çЮ•¢yò–­XÂŒú¡õÆþwêrxë“<²q/Ýn‚Ö9Ë9cÅ,‡éÑ3†çìeûÃ2€jœÇÙ/y +GúÅ­÷q÷_Ö“�æ…'½‰ë?ýæEõÎ;µ‘oºž{³t/O<±ÿ¼8ºVý�ûzÿ«ñ>ðÉ«¸t‚Naå´^6¼ûlñ þŽ?òûµofñÉòÆ];Zk …õuõãn{Üéõ_¾–w_õžš×¿ýÝy÷Uïá‘ǯ&Ÿ5R¯ù ½ÞO†^0�Üw÷Z\c3ç½?ãþo¾„̳ÑÎó›©§_ÆÙ³*?Ä ~î0{6>Á“ÛŸà·ÿvøÕùîŸÌ[æ[¯àŽ­ç!Â1GÝrN]ìp÷Í®õé1ói�~Ìz›Ö²!ü¥KëYç³ä¾Û¸7kð6­a]ᜩ}h3÷G/ U’W.% øoæ_j$°ñŸøïûÄ�d ¨º—rýÏ_ÃSý0ßYŸÅ�ä%­²òÂb½¬þÕðåÿþ OõÄãcTzg¿é_¸æ-§2¦÷ŽGh3¿óÏ|ëßnäÖ';Ãy}ñzV³ÏyþàßqZ«5.õÆL°Ÿ?é#|æö=‘Hibå;¯ãËo^R[ŒŽé^(öß~Wýp Ò§ó±Ÿ|‘W¶•7=÷pý{¾È½9Ø,xÛ�üàí‚TYXz?wó \ûë�ôÅ–NÛ ®üø§x×Ê–ŠpNŸ�üœÿ�›¹kG?AÙ½TX™iœõÚ÷ðÁ·žËŒ ß�>ü$?þú×ùï{žf@›!õÎ{ˇù?o<‰ ±G0–¿SÓ·Ž_{-ßy cð+‹ú¹/ãCŸ¸k<ß‹�é9kúJ‘ª¾i”!ÛŠ¹¼‰·¯ÈÒŸÍQwòẺýŒRM³˜ÛnqïÓ`è/†õXýèúè(’'žÍ‹bSœ9/âœé7±egº“Ç{šàäù#&xÏ÷ÈçóøžKÁuñ|�¦Æf‰ñ¡1îŠaÏþ]tìí(;÷Ø£�óî«ÞÃþ˜:m*<úøx7ûÜ {ééÕ€Ãü¥‹«¼¡|!ãpêûÿ›_¼uB�¹yž¾ý‹¼ý-Ÿãοàÿp1/þýUÌ<¥‚ Ï V'Ÿ<ë‰m¼ÍëØè]ÆÙI€€§×m ;t ±`ÅE,yúÜ»ÉG¬ãÉ­>ç/ ¿² ›×³9Š×UÎ"N;±~Ä9a*]GZAÖ€ñûyêÖoó£ Y†LÆ0<þ��ðÁŸn 碪 “,bN]/[7ìàP~/÷}ÿücÿçùÏ«WŽî‡öÚ4]wñ…^ÇŸ:5…•jbÊ”VÒºŸý� øYvÜû_|ho–oÞp+2Ϭޘ ösç—?Âgÿ¸;)ÍœzÕµ|éMÈÑ1ß ›…—\ʲ›odµk0…5üù�..E[ì™úYÅc‘wT%séKç`CÅÿJæ§æÖóÝ�~Œïo=ùÊi`ÚÜ™ÔõíbÛþ~‚ÜîþÎ5t;7pÃsJ?FGýwª;øÝç?ηþÚ�Qa%ëi©7ôoÿ#_üäNðÆüD«sÏy  Ôg«¡�:“eïºÕ¬ÛÕ�—lbêüe,Ÿ]‘«ÂšÊ‹ÞðV^T£ºk ›Ÿ¨ÅÄIm¡¨Ô{Ùº³1¡˜8sfy¿ìÌ™i£v4{¶í$Ï|ÆßÇ%¼�(¸öØGC}ÉD’L¦ŽT:]гoÆ]�vìíàâ ÿ¦t|ý—¯å²Ë_Îî=ttìá#×|’7½áUãÝlUL÷6ßÚ�sX±¨Çô³ó¯wr÷“;èê˜8o%¼d%ÓÒÕë™ÔNX6ƒzeèÙþ$OÜÆî~húw­á‘GöbYÒNžœ«hœµœÅ“j„›~v­ÝÄþ‚¢iö‰,š˜¨ÒÎ3ëw =À®Çîå�u»éÑMÌ^yœ4™yömXÇî¬CûÂÌiÏ?ª4³^ö)nºö!¿ëé½ófnÛ÷NÞ;mhAßN[õkw¤/È0qΉ¼èüÓ™Ó8¼zu®ç¾{fKG/^f O»€ NšÂpÓwÇÒÖ�çÁ»×md_^Ñ0s'ÔšœlzØñäStúŠ–¹'± ­ü½ã˜úpx+�o= Má³÷v®â÷·?Agã¼öŠ3˜$¡Ä‚p c3ç”´ÿpû5è¾M¬ÝpöBLëÖî \[3X¾l1'>ÕŒµéZdÍÚèeÓ°ر~s)ñ‘5ódNͼÛôˆø[øÍ¯z°æœÏß_²‚I Ð4+»ëÌ—~þT”©� >òï|îåÓH¹­¿à_ÿéFê˳íWÿÁ�_z#ï]<ò›ò#³©ÙsÇ/¹ëP(*3+ÞÎ�׿™EÑÞÁûù·}šßìô)lû5ß¿ó5üÛe­¨#®7FüƒÜõÕ�ñ™?ìŽ2²¶pÚ»¯ãú¿[~øóšý IDATÍ;¸`Vd÷°ê¿¯ã³¿XO¿Öt=øŸ\ë©ÜðºéX:ïü?+†•[“¹ì³ÿÉÿ=§¥»¸ëº«¹æöh“cÍÏ~É#¯þg¿^Gùwš{ä§|ç¡HŒ*‹Içþ#_ýØ+XX}[~Çç¯ù&÷tŽ0Õh4ÑsÖôÇ<¤ºça¾ñîrï¶~JŽb•¤ýÄWðÏ}7/�9Š1úºáG<ý�¯œY¼ø¼¹á½ º8ØU’¿4¶T.'• ¥9ƒÂ _>t¤KC•ˆiA(hM¡PÀu],Kš@ûá6ðÑZ£µÁ”^ )ê˜Ø>‰ -­cnïY�©,ŠÑÛ~÷?¼è̳ùÈ5Ÿä®Ûÿ‡o÷Æg³ÙîªÏðÒWþ��s¿ÆúŸ­à‡o~3×ݵ�Áü<ŠÔìËùÊ­7ó' ¾"uÿü1Î-Knãr÷'/àÕ7õ–Þx=xÝ¥œq¨†×òá—ßÍWÞEóëÂS?»¢~Goû6o<íÃܧ—òñŸàs«µóÌú àm»…yãûøÏ‡;CkT†9/ÿ7}ï~ûêóøÒS“¹úŽmÜpáxgÉRL:ël:ÿËcÁnvì`ZìOL䞯¼�÷~á×lì-OIn5�Àk?ùþßÏ¡­òþy;ùíÇßÎûÿý.vÇc¯T’©ç}€oýà:^=§âGÑ´5äy8.÷îe¼ñçÝ´üÝÏÙöÓ×R9# Xóu^}ú§yR�Ìg{„O´=ƒ>Üõ .xíOqÏÿO~ñ0o»äÓ<Øk°g}€¥¯=ƒI2íCŽi‹Oá¤ú[¹½Ï€Þú ݘ…m(w«7û„˜¥œ83ÅâO õÛûÈŸ§Öl {Å4ôa6lÜý°h[q2sF{ÿ\Õ]t5¼†oÜp5+Ë~Uçyì÷dgä ³ç¾‚w]Š%€Ìü¿å=¯ø�þt7�ÿ4ÿó?kyÇâSþ›äHmjtˆ¾Ç©)s™[21ñE¼çšOpÊÁí'2uzci~ä‘Õ¦Àßþ(·ïØ[ UÎ/�A­%+ŸÑ½P­¼ä²³¹á¡?Ó­ …Õ÷p_×ËÃv³Opï#‘Q¥9í’ó™\Mlh~ñÕüß×.¡Y´±òï?ÈÛzßXãbÐz`k¼Ó8=á³îÖ[x4  äRÞùÿÙ»ïð(ªõ�ãß™mé=!…$¤Ñ„.Ué]Q¹b½v¯],¨?;ö–«b¡ŠrQ@z‘^¥B¤÷ž-3óûcÓIiô|ž‡'dwgÎÉìî̼§¼çÙ{\–€Ç)ˆ«ïyЇîàãÃ4­„ƒË~ãØ„;é¨Ó0{veÒ-¡—P¬FpÃUîöã,{Ñox/<Ö¬ K5÷8‡Uú„—î÷¢>§ö¯ßBYj ɱwk•ÿ¦$ìbãy/±�qðgž(ó'/0Ö¿ŽèPIcÓûOóꆌÒ\Gà˜»™Uz¥STR1üÚd¬þ�”0š*Ôµ‚ÂÒÆ A¨�“ƒ#‘áQX­V,3H I2’$!K²ý»ªihHöŸšJ^~Çc�Ñ%º+NŽNõ*¯ÙÚGÊæ”®Xþ<ú$sÞ˜Ý\ÅÕH21H åà½[ÿÅÜ’q¼üõ2Vý±’%sŸbtˆË™å<~÷‡«s­(]oÿ�ys_áÆp §ã­s˜;oó>º�™wÜD�N%ç÷oø9¥¦o¹Â©¥‹Øec�iL�©» Áõ.ÙÁì ·òÉÎL mÆðäÜŸY³~‹>¸‹°³™0ýç© 15t©š PssìYÞ$Ü*�åÒrÙðÔpF?µ„ãR'&¿ò=«·ía÷ÖßùföDÚ©ÇXôøÆ¿±¿|Axûvéüï¾aÜôÖR<ûq×_³tÅoüüßטÑÃ…ÔÍï0iä#ü‘­5¾¬ê$OFO‡�¬’³j«sjz‘�ƒ‹sØ&aê5•Éu�ªƒäà€I­ð(Ÿ>õ‡¼2é®{¹ûæÞø‰ÖLA¸ò9DÓ£½Á~ß­Ù8vø@‰?Ì‘�0¶�¦½AÂ¥C'Âu%Gÿ☰žàP¬­4øp"¦{»ú/Q%éé<þFºVïâQΰÿp^y{·)¨.9Ydf•ýËÃ+¤ & @%믿8{¡þïSÆÇϧô&E%wÍÜõì'|÷ûVœÉƬIx´Ȉ�½éÞ>Œ×²£ÐÐíêA+áìé¤*sS5K™¨ µf7¨ÞK^磿JÀu0o¬þ…#KßÞA#¸þÚîÜÜg&ËR5�e¤æn´,Öüw)ñ èZ÷£xÅjÝ;‡ß;H±¡#ý¼‘wW\0{ôÉèn3éuÃÙöêÓÌŸº‚;J[aÍÛßⱯOau¼Šÿ[µ†gº”�SÍu×÷¹çH>>ùÏÍ{€!O´C׈²jâ:l ×ÌgnÒj¯ÎáÆ›«]èmûX¸ø6É‘ASo¦¬‘·ÁuÐéÑÊÉ,ˆ¸�Uû_£¿{ó4‚Ð$bº…¡Ûu*G�pZ¹ ¯£GHTt„uꀫ²4�}e'«¨9Ç8”¤ÒÍ|Œ£…¥!�¡==;7 ›�äET”÷ù-ÒJ:)ie7ÚE›ÞäúMµïFII$Éuu‘6xŸ2­‡_Ï€EÇÙ�¥¢©œÚ¼˜�7/IÂèL§}4l cû„T~ØÐíêI’ñè|÷ÎâË�Ö�¬h¨›xë¥hóöTÚ×ô¶4æøšº0~x˾‹GÑÌظ�¬±ãð–,غË>÷Ï#è[ÛÄ^Ù�Ðꙇ�iå“öe„Ô²r4ðIælrYØ"áTÊ2þ�­ÐIDZi€šFRš­í÷$E ÛXºt[Ær6#�¢+V› EUÑ*yµõÖÕú9Í&=«�"{2ü‰P^o Û¿›Ï+8�{œ§Uo½•ðû8wuýžY{×óÃ/‰Ì¼/ ÛX@¬ \ÆÝÇ=Õn¼$÷A<ðÂÃX·©ø–`t .«N×pËľüà «¯"ç¦ITnˆµîZÈ’“6$×1Ü:±ì½mD$ûtq5?ýýD0*32­cbð—�sN5ù(G²Íø>Uº®¡�¢ìç}]:8² ¹MIàxlYùe�+è»ãÑ€s„ä„KMà4Våâoà5k!V¨sÌn#ö)ûç…wÁ÷Ý/ùõ@ZEO•¦aÉI`ïÚö®û™ùWÝÅ[³'Ò®ô&½¡Û]4ÉHøøçxç�þøJÍ:ÃóOP¢iþ–ç>Œ`îc}«\+{,@GÔ¨QD/°'72ÜÈæÌ1\ïq‚m»²Jçû2xdwj('9`2�ÿ¾ë •î4+f«šÅþÓ¾!F‡šs(È#zÀ €‹@%óϸÿÅåœ.J*É\ps7 ©…ää–pÁCQÛç Öò ½Ápþ5\2`jliCßgLD ½…¨ÚöëÅ„1Ñ|{|V@+9ÇéT•Á•îA-gWòâãï².ÙjO %»ÓeòÓüßí½ñ­Þ©!»âæ"aŸ˜¬Q\l®ö sqIy�­ìz±Y…¿ ‹ÅÂWÿý’s‰‰¨äååãææZ¯ŸÎN•”ÿîíåÁÏ?/+/ÃÁÁ�ÖA­¹mÚmåj}48 ݸi=ýú <<’•'N³#6 «ÕFxXWõìKëÀ†ÞÐÝ7)É¡}»×p25xâé*AqEÅ�iEÓ5e&ƒ_Úɪƒó™¿÷ ^ëUÖþ¤ptÉ"Ze|®�Áxß‹? Ô«ÞÊi-BCO‡ž]q©©ŽcÇÒñù�ìoМ +n÷ÅpûùÏhªŠª•Í3 bجùüðïÈŠÄʶïHDAOÇ�ýΟ#  ‹¢__t{αoû>,÷ã œaçîdô´íÙ�óc3í¦Îáó©•jhYµþÝ&úÝr3Ÿ¼ÉÉ?±*ûfþU>IØÂŽEK‰Sd¼FßʵeïmSÔÁЃÁÜ›)—™ -ICW×ÅœËUÑl§8r,¿“ö9€’©1Qe×Ñ�"ѯ;€U³ê¥�,Í' C<êTãZ˲#N&,öa—ž£^à‡ºÕÞ›"ép¸Ð4¡FîÓ±Íp}(÷$a×î½ì=x”ÃÇŽq21‹¦�f%mÇçÌþ®#ßÞÕ¡|¿ Ýî¢HŽDè�¿À�Î3žã¡ðÖŽTÍÆÙßÞ`vÄ̹!¤ZÕÆ 9h(ãÊ’™³~{6cÛïfWi¯«.h0£;×Ñ: QtÞäA�⢒JÃKpr�@vÄÙ±¬®Å…Ôtë`-*ÂV¾±ÎNXþâ¿ïÿ¯4•pl;�_¸�­ík¿ÚÎäûpö"n»jüœJTL‰Ô°”˜Q êqT‹È/llïhßç ïWwtöï²fÆb©¨«’²–—{‡u)ö¡ù’c×>þ2� ¬9‰£ìG ŸûzO*9Y9¨„VéZ>é™Öò,¼þþU–ÚþþŽ=Œ_+?LŽŽœ<KDDééõúéåéEnn)©iDD„áæêN^~.ééøúú€NÎN=v”NÑ�ê]Ǥq§c6tV‹….aîü¾7�!ÑîäæåЩS¶ïÜÖÐ]79ÉÙ÷Ï:t¥_ÊÆÎï–odæ¸gøcÁI~üv+/ôd0l‡Y¼øV]§�Ä­¹ê­f�–©üüjìñÓ…µ%\/±¿�]¤N>!ø»T_$.“„¤T]Ã}…§îº‰!.U)5™sIö‹Ú‘®#æÛš[NÌéé¨h%ž#S… 5™sÉöev|ý}/®g¹¡eÕ±sC�ÉLêð/ZâUÙLš\š‘Ѽ�…KÏ È~Œ¿uTE+iÔAr ðüfWAþŒÑt�6±âÏb4µ�c»×“^Úí©�ìLÇò;ŸNÑ鯨$�ÜÀŽäÒä5²]»G6mfB]Á�2·Ÿ¿Šr ‘�]piÌ©¨Iö)ãÔ‰AA�t€JQÒ~zûu¾Ø�mvíæÜª tjèvõ¤âú§ãè}³YžhCSóØùé‹|þ>t­t=lì±�¼RšÜ(W5shûNî!AÐ>líëú@¨©Ä%¡µ«œÈIáì™s” è”t­ô“ALxˆþ²×ÕÇ9uUŽ“�Ó±ñ”­®"BÖ¡œÞÍî²åI$Ý&Ng`kÇò2Í©Éd5æ¦KöÁßO. À4¬‰gHV«rSÓNרŒF5¸È÷Y+ˆgçöc$åä��k&xØT†‡V¾PIMN­äeO¼ËF:å«çßaMi0*»D3ý•W¸««[í Ô²/m£<�Ûï)²N�"C�¡R Ùý‡Ùµg}úöå·¿Ñ®]$))©õþéèhÜÑÉ:�ÀÏχ´´äòçýý[Ѿ]vîÚÞ €´Á§`³Ù‚ÉdBQú·õd`@½Ã]P£ÑˆÍfcîŸ×øoê”éuï\*K´¦Ö>· 2¥t‚viö§ó÷×\«æT.Ëq3o$P§pvñ7¬)°?lûk1KŽØÐGLfÆÕõTŸzkfJJÇ%Î˰VÊàˆcƒï^Œ ~c'cc‰­üïÄï<ÚɈ¤¦q*ÛŸná.ç×Y³`¶Ø‡’h63%%%5þÓ\ƒ�ˆ ÜÛh¿8jÌf{ «Á`¸¸cÑвê¢ïÌäuÅ@ký^~!-Ù²€eçtÁ¹uh¥>é&¨ƒd4ÑLy§Ahi’ 1Ý"JƒI…ø5k8Tº´†ÇU˜éÚt¢“‹}NžõÈ:Ö&ÚçõI¦Žt�nâLér =ºµ*½1аÚÌæ*‘ƒJÊæox瓯øê§¥üº-�âæÚ§%‰]¿/á«ÏÞãÅ—¿eG•Þ.§À^L�س<Û©fUì½M Ý®‘$Ï~<òÜ:”îX³ÄóÓËsX•R)(jôñµ'7ækÿ<ï_ÃW[c±’±}ùÚ£µÒÌìY¹ž*ùxJޱnkEò"9¸Ý%�ýéÛ/’²Q¯¶Ókùß¡ªµÑ ö°|cJy’&‡Ný¸Ê]B+®šÅU–+ÝËXãùùç�•ž·a»àE¸Ù�Ží*æ–*§·°>¾òN,Ä®ZËÑúî÷"\Ôû¬ždÉÛoñƇs™ûíw¼ûź*Ç\ÍÞÁüå'Ê é‚:ÓÅGÌþnßž(Mˆ$û2≗êF0Ý·gi¯§†íØ:VŸ-Û»Fî¶ÕlÉ)›wÅ€Þ> ¿ù®8ÙÙÙ AVF&mÚ„�“�C›PûO“©ÎŸe¯³ÿÌÅÏÏEUðõ󦸸ˆÐÐÐ*¯ËÎÊÄjµ‘•�Uïz6ªqUQvïÝ€³AãÀÁ=hš†‡»O>þLƒö+99ã$I ��s¡ * dÚ×TBç†G“®­Y?Nƒg2%êKÞ8ñ+óÏaìM.X¼„cŠ�ÎSo¥gS¯²R™ä€£ƒýo/).�š¡ç’ÛWÞÊœúðÌû÷°tćœüú~ž¹a7ŸŽò¬zò”œqu‘}goeõ=\J¥ÃP),(DÅãÂ'ц–U'í&M¦÷K{øsíb~ϼ…©>Ål\𠉊žÈI·2 òán–:‚ð÷!ãCkÝ!N+¶ü<{£”äDÇÎáU/ÌÆöti§gÅN jA>¥m�èÛv??ûh£ééxíb~ý˜}EZÁ>|ñKœ¼Ž¾©~å½9?±7WÉ�n÷õf\síSo毥s™wŠ&é9hsâ‰×С•&©„¬„ƒüºpWi`#ãѾ=­u€ÔÀ횀c‡©¼|ÿIîœó'Yª†š±™·^úžÐwn¥ƒC_Sg®̲ïΠäïfË S§a «ž@Ó*†ÚJÅ{¿àé÷�<<±~¶³løæ=—6r ™è8rHir>™ÐqSµìy–§ª œcÑË/áúàt†·õÀ–|€å_}ÎòÒ@LÒsýô´’Amˆ¿{¦YÙýÓ<þ×jJ<ü’ïpsµ�›¯‚–ÃÑÉXbBëÑk ÓÐkZ¶�³*hÖX¾{ù¼ú}üÎlžÏœãPe‰²‰ªšÚt÷>zŸ%·~\?؇-+ÒQQÉÚü3ÿ½�¡½Bq)>Ë® [8”¡”�.ô¾i,Q:в×óÕÏñå $Åüæ ¦}Ss=$ï!<óúdÚëÀ±Çõ\¶†¯OYÑÌGùòɧHÑ Ÿ’XÖÿ¶©t‰Ï�72¦®!aÂßÎöÛéÝ»éi©ìر H8“P©ÓKªÔXú;öáò‰ç’ûÏN�;“™‘ÉÙ„Î$ŒÉh"áÌYÎ$ :t¤_¿þlýs+׎½¶^õlT@j±š‰‹B§Ó¡i‹…¼ü\JÌl3­›Sm[Ëkfÿ®ƒXoî[Çð+mÞF¶ ºàNtlH‚‡¦bèÁŒéÝx÷™Ý¬Z°’ìëÂY´äŠ©/Ó¦t¬»å²±d?üdHPH>›„‚ÇyåYï爵ƭÅuÐlÞ�ñ ã¿8Í—÷Ïâ†Ý3¢òû oCD¨)ÖÆ™¸3ظ¸á"ºû�¡8…øØx‚Î H5k1%8àXÖŒÛв.@»‰[ú?ËŸëײdeSnØÉÂå)¨úNLžÒ£jÍTAþ>ta]‰ñø‘Ó™]'’!Š.Õ³ØIntê‚ngl¥‘:‚»vn–¥ äÖ×òô}û¸ï�?IWTrüÀ3·ÿP­N:|ûßÏÓ..I_ƒö)·aÒ7±ñÉ9^d#qÃ'<´á“ö.¡ou5ÌèmOæÓÐíš„Ž 1�óÜñxâ×sX5�Â#ßñÜûÌ}¢^RS_=mG�¦ã‚Ïù«lÞ¡ä@¯‘W×üy°UZâCÁè±&6üú&w/«þB Ǩ›yp|E’?É­/¿0“äY_±'[Å–¶ƒ¹Ïî`nõ-u>ô»ÿ·ÌÊ­®áÚÞóùkk*%§–ó./¯käͳ¹½x³~Í@Õ,šw;Cæ÷â‰^eôEg0FOâþáyfu*ЦQ·’×ZYú¬Œ÷À›“°˜åg@æ(�žšUáBï³3}ï~œ›�=Ï‚S%hš�ÌcXx¬Ún$ÂÇ=Á3cì½æj~Y•æ’jjI§ ¨�\Ð¥¢§ÙÅÔGoaûcßr¤Hܼ‡¥ßì©\ú€¡a®¡Û5É�¾÷>ÇÌhÇòµfÏ­|“—&”εlüñ•ƒ†2®«©üï’]ú0º–µGÕâBÊÝ"{ÑuæË¼{Ï`Â]äò×K:®¹�·ß˜Nç*3‹$œ£oá�Ï^çþÑ� pÔU)CÒ9Ü}<ÿy÷SÞœV‘pGöeì“/sÏÀÖ8—¯)¡siÃ�»^ãƒ{zsÍ-w3:ÔѾ§¦¡ép¨ÏZòäšGßàùë¢ñ®Ôµ*½érÝã|øÌuDUúÒ”››0 å‚ï³äÞ“‡>ü�ç'õ%ܽê”#I2â9�iÏ~̼ÿ ¨a9�†qŠžÆï=Ìu�}¨œLYÒ»1hoø8C|Dïè?‰ÅbÁ¦(øxûУûUtïÚ“˜ÎÝéÝ•Ží;Ó®]GÚF¶'"¼-mB# nCpëPZ…„«@|}[áç× ÿ@‚Cn݆6m"ˆŒˆ"*²=íÛu"ºcºtêJ·˜x{ù a_¦>$Ÿ™ojHö³@Âw×ùâ£÷Ò½Ï@V­^IJJ={öÂÍÍÍþE×4rrsØ»wþAŒ1ª‡ÏN=û 7ôœÉ/iàÑû>ÿïKÜØÁ­Rm%mçW<>óQ¾;\„Üz2?íšÏ�þßBËw:j.i¾wò{Â\FT�‘-ë¸7l8Ÿ¦x1sE"_޲¿À¼dž7-Äù8[¿IŸò„¹'x³'žÜ!3ì³xVßí_Ã|ÉLLjË-‹KhêJb‚•~<É‚›½Î{mmå4´Þ¹Ën%jâ|2ôÑ<øû&ÞRV¦•³Ëîcä‹IÎË!G ç?›Žòv¿‹ˆÞ-¿13ðZ¾Î40î¿Éü:ݳƋ¨œûv"Ýo[F†®-÷¯ÜÅûC*æ=¨g>gt—³ºÀ�«_YÇŠ§ºWÉ\|änü¿e†ñð†C¼[:V9ñƒº=Ƙ ò IDAT–oF}°‰ŸïëP>Ùzú[&˜É’dG†}|ˆUÿ¶g•khYµ¾ï¥´Œ˜9•_L“yxôFÞÿ6‹k><Æ÷…œ×²ÓÐ:\ð½¡Eìݾ™]º·t5.1sv ÉY*:\¼ p§†•Cš}Ÿš%ŸÔä2óÍØ$.­hà�é÷× ÝîÒhàñUN2÷ö{ùê´Èx�y…EO^U¿ž^K.gãÏ‘msÀ+(˜Öîq±±�’˜LfžÕèF«à üœêŠ"5ÌÙç8�”‹ÕèIHhUŠÑ,ägf‘¯9âåíŽCߥ •ø³JÎø‡†àçxY¼¹Ô²’IÍ)ÆjpÂÓ/ˆÖž¦Z¤@Š3Ïq&9‹Þ¿ÖÁø»4iú3á ‘ššÊKÿ÷EÅE—´\Gž›õ<u/÷òÀ'”Å  þ„:œuëײnýŠŠ*†è:99Ò¾]4Cmè®�ƒ§ñÕ¢8®Ÿø [v¾Ï¿:EpL/bÂ}qTòH<¶›=ÇÒ)Ñ$ A#yýçϘèŒC�¼7s"Kæ‘_„0“cÎF›ƒû¸YzçwÝý+›ž¹š˜µ“™<¢3¦b®eÑ‚5ĉºã]žê_1!S×ö^>ú¿ßöØZV=Ø—nÿ»‘q½‚Ð¥íç·E+8”¥á=øEÞžY‘⼡e]ˆä3†)c¼øå§Å|ô£Õe So¬y Óæªƒ Â¥#cò $Ê3°Å÷)]ñuÅ¿ž¥5t»K£!ÇB%cÝ|––w’t¡Œ¿¾Gý‡Ý nëNp}¶Ñ»àU�c)aò ¦½g-¥HF\}üq­Oj siED‡V�ÜK3’ðj�WëKV ŽÞ!´÷¾Tå —+I’˜6uŠÒħ/@–kI2[‡¤:�ŽáÃF0|؈†îâ$¼®~‘5ûñù«oðéÂõÛ»Ž„½eOË8úwçú)÷ñôÓé}ÞJÁ-ÇyÈLn‰üš·Nh„Þ<�¡ç/ Ú<ôí¹oñœž{’7¾ßÀî¥_°[vÄ¿ÛXþ³äužy˜;KóLÕósrqtaÜþÞsüÐûQ6�ø”{gßÀŽw®.½Øˆº}!¾É“Ï~Ȳµ_ðÊšÒí$çÖý˜ñò+¼vÿ5´ªR7bù…M�/òèóóøcÕ—ÌY !;·aÈC/ñÞÿM¡S•iW -ëB<9e<¾ ¾&Õ"ãyÝ­\çWÛš«‚ Â?‹•sû·r"G%7n m!§,IÍ5·rs[Ñû%Âù|}}ñön™–‰úÌ…F Ù½äÔ"ÒâNŸš‡EvÂ30ŒÈ¯Fj&«¹§ã>OîÈó»öòb׸Xh6Šró°˜Üñp, Öóæs]«[ùÕÖ™çwïåŘ–ºˆ©¦œäD|:…ª �€¢Ú\Ì{i%ûÌ â’r±:úÑ>_‡ mÔвšÒåPAãŸ9dW¸<ðÛÓ7òÒŸ•—Ðùbö§³ÞT“A.¡&²{ÉÉNøEÆàÙÒ¹…¸ÿ¾Î÷çT\†ÝËí].Ý!ÖŠR9qä(§2Üé5²¾^U†ñ˜÷îä€$Ç(Ú‡¶ä[/ãìߎnþíê¹�ÏÐhz„^вšÒåPAáï@’h3†{ÿs§FAø[¸rÒ+‚FîÎW™þìF u‘<ôì­„\Âk…íл\×ÿ NHíø÷ÿ¶ðÑŸŠ¹«…øàÅï8«Èx ¿�¡î—®^‚ ‚ 4” #žÿ�nùÛ$½ýñw3Šõ­AøÛiPÏþÆ;Ÿn >~ËÞJ‚Ù�.�Îã…�Η´†^�ðÆ­‹¸é¿Çùt| {ÆO`pGt9qü¹|)âŠ�|GòÊk7SëÔGAA.+zG/‚½Zº‚ ÍB¤M@MÛÊ×o½Å›„ìÁ¸§>áóY×\úŇ¥V\7w¿µšç?\ʎųC��ZÑmâxöµ§™Õ¢‹µ ‚ ‚ ‚ " mú®O³öØT2­Ž´ Á§%×ÀÒ1ì‰oöÄ—ä%%�˜U„jò$0$O‘EGAA„ˈH›‚Îÿˆ—Ù:gÜ#pkÊåãAAAš�HÏ&‚ ‚ ‚ ´� ‚ ‚ ‚ -¢ÞCv{¿’Øõ¨»Ì0;O›/y¹‚ ‚ðÙÐÆï#99¹ñ;A„+@@@ÀE¿öŠ˜C,RAáÊVŸ‹³ ‚ üSˆ!»‚ ‚ ‚ B‹© ‚ ‚ ‚Ð"D@*‚ ‚ ‚ ´� ‚ ‚ ‚ -B¤‚ ‚ ‚ B‹© ‚ ‚ ‚Ð"®ˆe_O" • r¬œ-®ý•z'=‘î2¹ÙV’J*öáï§ÇS'ÕY’fSˆOW(©á9Ù¤£c°‘pwŽhäæY9rÎJB±Vwí :Ú‡ië©Ã•Ì,+{¬dÚêÜLA¡Elß±��»wлgoú\Õ·…k$ÂåªÙRƒ¬b�5Šlºæ.ªv:wLñæZG�-ËSxô JM! Þɦx0ÂC"ãd÷/µVÙÇ=·z3ơŒ|fÎËã¨ZéAYÇUý4f2c¥™üJ[töäñŽx£{´�q6²‘iåÌ„(·Üàƒqa:sâj°AZ–L¯a>¼}•@-,ä¡sØQËù³f!Ýy¦·ÄÊ…ÅìÍÓjyìâå�ÚLQÊQ"Ç{sÇm�òÅן³dí\œü;à1°^ûª7­ˆä¸säØª×YB–uÝðöóÆÍ(fÔW¦…‹1rä(ô&‰®�»�™™Nû¨h.ZÄ­S§6MA%qüúî[|¾îY œ‡óæ²§hlØî,;>`Òsk)šÄÜo¾îÇAh:Íöµ’Ððr°äRD\®KsÓ$dû—'×zIäÄåòÐÒBb«u;Ê&  P,üðK+Í·oC�+ÿé¦Ç¨)¬ú%�ÙGÊïÅöò[’7_ 3Ñ:Æ•1ÛÌ,(í:�¸{ˆ#>¨ì^›Á#;¬”ùûþB6 öå£~& saÅ—y©× ž Â%`2qc7&³™OÊfyŽFÁep®*J9ʱŸŸ#îô!Nž>Ê5ƒ®fÚôh¢'þ_󤶿øêáY,ÏSk}‰¤s¿ýUŒºa*S‡†á܈NŸêÔ¢tÎeªx´ÂUñÏ ÂÅÊÊÊÂÏÏ�"Â9w€6íÂñóiEVVV•¢rzñ›¼µê6ÙƒÈ>Ýw‹ÄC´ã©Ù.9�Î%h’Æ‘,wlj^M›˜ädâ�I^Lô•È�Ïå¡%œ°ÖðB“Œ³šU¥°cd£Ú:ÐZë¹>;Z)@#~_[šé`¤“¿Ä‚\{«¹G”3ƒ\@É,â“ÝÁhÙvþÌc]WoFû81>$Ÿ#§E© —ÙI‡·lÉ%¬JTȸ\NSšÆ�¸l¢ÃÚ`Ò›È,LgíþÐ.ee¼Û÷¡K«ŠÑCšj£87…ØgH9¼ž¯�lãϸ7øäÎÎM”*œúé)füàÌ߽ǿä‹|Nê'77—“9ûhÜ�b%Ÿ£ ±¸éÝ›®-—ûã±j2×=Ïu¥i ‚p)5[@êf´àçd¡—_6­œJð0Z°iýØ“æÕ\ÅÖ‹ä`äž›½˜ì/‘—�Ç#‹ 8f©ùµ²QÆEÍ¢RX�{–ã[Ó™p@‡»¦�TÓvŠJV àåï†D—p#Ž@j\ ÇjêQ0[Øš 1ª½Žžat§-\‚ xúiã§ÇEI§#ªµ_E%.É^FÂ� 3ùjàÝ ´u—ÈÍ´_Ô|õÛ›E�¿žƒ¹ëøzõG´²Îm¾Âj¤§ý„§xu” ÕcMµàËç<Ç›R8±hËǽǿ› @Ôò8z4•¶õ{NêÉjµ°þøÿ°˜òØ—¶™„Ødzxiº´" ŠT@OëÐ`8JW„ËD³¤Ç²Ý9WhEUÂËÑB€S1£B“Ù›æÕâs%“‘7y3=H¦ðlÿY˜Ïá:†áJ2΀fÖ(¬G9ŠE%%K%¥¶ý:wT§2K�Ф'ÂGBB#.ÕZK ©—fCioÀßO�²ëQ/A„æ#Ówˆ³£JC­ÞšæR:‡4}oÞ鬱ìÇT^«6º#´›'Ÿ гñçdž:Ò¼WФœÓ,?=Iº¼FñÈ.\ûï›XµåCöZc9k…ÀšúTŠROòבÓ$eaÕ9àѪ Ñ1í rªÀj¦œâlæa¶·¡i%¤Æçhž“Wkü”$ÎÕø\0a¾ŽUfµ8•ã�›’C±jÄÃ?œÎ]Ûàx~À¬å'q")œü‰ vÇ–rˆ-»cÉuhC§0'›„“_B= 5­„ÔÓ dY%œ[…â!Æ_)4UC’$ô²©ô¤iµS¯Çž)L>ÅÙœdÒŠ4@¥(-ŽcÇ3�d7ZGà”ŸÄÉä|4ÂB½Ïï9Uó9›D¾æ€o›P|Dת ´¸f;»k@¾Å~‘¹Ê?“aÁ)ä[ ìLõnñ`ƒ�ɽ¹;D¦01ŸGæó׿„êŒN¨ðkçÊ�1to¥ÇËE…6ŽÇ³lg!›3µzü}ÝûºÐC%çŠø=µôaY¦•«šJFAíûËÈSP1 sÕã#CvSœëAMeýŠTø8óú-®„'åq÷/Edª™ ôjéê•Ê/)�´I‡ê^ÙÍwYdtòù³–ûóç¼Í·œ¥P­\ Ù)˜!w<ÍÓ7´+êkåÀ×�òèÊüÒëI,?>s?"÷>?Þm¿QPsØ·à]Þüv+ñE•éÙË<ã1ž¸¹jÝÿÿ~nÖ˜øî®|^~ìiÈ­Æ1³ãf¾ZŸ�óàY,ya0n5´ ¨IËyî®Ï8¨†2ó³yÜåÑØ£*\*ªª¢iŠf£ì.Fk’½_>Ì•ÿ$·}’Ó^ÿeÝÿü˜;_Û†9ƒoæM#¢z[IñvÞ¿ï56+aÜ>o.wF\ÞI7áŸà’47öòËâûãmˆÏs¾ÅÕIÒë™8Á‹ÃddMe÷îBÖ´hh5Î2 tå­@²©¤äªd¨2^Fxéßɉ_–gòƱêsEk¬ ­;{2»§�Å—« 9Svv•d\�Eµ !(¶Ø7�L-dA**$U¬6•Ô\…t 8o€jËÉ/Éié*Ôªäø!NX5$SbÚVÏ>”ÄÒgñéžB A}˜>yÝC<1Z2‰Ýö3ÿ]ök>z½ï<^¸Ú =cîçé°�|?w-gbØí“èí®Ã9"„HKmÏ!h…ìýüqþ³à§pFÜ9™1ÝBpײ‰Ûýß-ØÌÚOŸ"ÝöN‰,ï‘’ŒF XŠÏ°tîjâÜ:3lhîNØKfùÆ_IÛ±š Yƒï}ÞÀe7oä¨ F02R WUÓÐP±©VTÕÞZ®*MÑj®'j܃<Ý5�íßͺ$‰°wò¯g$}íD'º \‘üÕíbØK¤t˜S±'qsw#/7¯ôg.nîn俨÷óõeÿ¦tÜrsàŸ?±Z4­ÝëUÞ�W»5´ª¤ìÎgW°‘NW{ÓÇY¦°@Åä"sÍ(/¦gfðurÝ-wÎ’ýÂl³±~Sí1“XšüÈÉË�c=™bàºk=9�žÁ�™uíM¢mO/æ wÀOµ±|yVÕò%°7ˆkØê8k*(€^’—jA„úÉ7ÛÒËjÈ®RÀ™Ý+øä½ÿ‘¤9ÑaòLFùUíâQޝ`áþT]8S^œÍ]QC^»õêMˆu&�üšÆúŸ7q߀ñøÊ2­b†3. �•_¬å žt2†ñ剋êzl'òöâ8ÌúP&½òu«˜÷Ú¾S/úE½ÅŒgWò×w_°jÄ«Œ÷-ÝVÖ£ÔsëY4�÷¿ºƒ.eÙ™l!Œ ^Á7 ûø}} ãn  Ê_©&²~à l˜è9rÁ"ÇÒEU4MCÕ”ò6¨¦é!•ñï:‚ñ]Α»âÖ%ÉøvÆøq^eƒ«,Ÿ'•¡Ái¤t˜ýû¢©6222###ƒ°°ðÒßÃÉÈHgìØ±|ýõׄ‡‡“žžÁ€þ}±¬ßÄAê�ÎÛÔÀ•Ït<÷�7½ísíÈä¹�6z^ïÃ3m�Ü5Ñ“sßfñGEœÝ‘ÁÐ=€¢Q\­û³(«„Oeãq‡7×»›˜ÔÝÈâ?,Ô”¬�Žk†yóBN ?þœÅ§ªÄ�*XU@'a¬#ÒÔé±¢ªVsY‚ B­Ê†ìÖg¢EÓ±²û£Û?¯R0¬Ù(ÊÏ£È*ãvSfÍà¶a8VÛRn3‘7ç +ÏDhDõù—ŽÄôêˆãòTŠÏž&AßFsV­þƒÓ6pì7‰é]«'a’ðè;‰ë£ÖðÙ‰ý¬Ú’Á¸ ~öàR²Ç"j1ô˜2™Î•Së£3º-?|~Œ¿V­åÌ S «TOõì&Ö�´�ÓUŒ䋈G¯,šjÿV)š J¿_Š*R/ ‚P³ŸãKŠ Âb±‰Åb!""‹ÅLddDéÏH4U#22³ÙBTT$Á­C(.*hÊ¿¡4oÌàßkJH²ÚX¾<›Ó4dwGfMt£KÛ5U£Ør~0Zþ|‰™_�ÚP¿ #þ54¸KŽF¦ÝìËë= s‹™ó]ïWFí…‘[H.µ×É¥t±Z¬RÏuáAþñZzÈ®b-¦¨¸Ò¿3Š h ù‰‡Ùºò~Ý—~^ƒ£äèEhDºu Ç«ì*®©(V æ’b̲ £˜Í˜{mPÓ8t4mºT�#ZN¢K´²fåøáØóHõméÑŹZ +<|4ÝÀvj ¿Ÿ¨¼žšJü†�ÄÚdÜû�d ÇeÔƒ-\MÓÐ4›j+ïmšRAþŽÜCZ\\Œ�—/¡¡!¤¤¤b2™ÈËËÅÁÁ�¼¼<Ú´ %%%'''òòò ³ÿîååMII185åŸqñrò•ò‹¥Vbæã%¹„Nó`@ +¯]k㮥E$6hšƒFf¾Š‚}‰' *7ºËÎ<ø/û3¹gó™µ$�]µ¥ëÕl$æjà&áï.#SCЊ„¿§P’c#MœçAø�kHàÓ\òÍ9`l©!»®zä'æT_öE³R�Ëε ™ûÝ >xlûþó¯Ž ªzÁ.NbûŠe,ß²�#§ÉÈ3cU«^š¤WQÍ$-Ã~Š_ü,SVÖ¼W[næŒtòªõÊJ&o|]Î?Ʋ÷5Œïû»Ö�cõªÃÜÞ>Æ>ÿT‰gÝÆÓØd�î%r$\�TUE£jR£²¹¤‚ Õ5< -±b4™1íŽ ¾ö©'f•ÿßl.¡Ä|ù 0µeòÂ2=ŸOr!²�oQ¸g�¹Æ9²N¨i”ÔrNõr‘‘µ¤j�¥d2rÇMö`4íxÿRÈ©º�¦r,EE ÖhÀ„Bqõ×H2Ñ�:d4â’¬\D^&A„Ë‚¢‚&I˜Î»IxÊ—lxfAI.¸^¢Â.–dÀÅ¿C¦›ËÚ³YÚS¨åîáƒGŸã§“%`ò¡]×~ôní�›ƒ½^�”²�ŸVošë‚fÅbÐÐ+Vk-Á»“AN wן—ÔOÒÑ×´™äJÿ1×à³a9iV±ûÎú;�·‰uñ º !Œ«kè’pÙR5µb)ö%`4U´œ ‚P³¤‰=xð‘‡P•²a6Ziæ|­<ƒ~ÅðŒŠÇ�täx_ÓÐb›E~|Oý¡gÞ(¢z{ñrv:�ï±U ;’ Ü>݇Û$Ž­Mã®¶ó{,uF®Ž´'pHN²”f“�8‹™A¹§syxY!§lÕ7®NãÈÉ2z:ãîD?ÇÖV‹He/'FJhŠ…M±5ÔGᲤ‘S¨ ¡§�¯ùdÅùKçéÄ„péÍé,0+äÆZ0êø£€m�X G¡9©ÙÌ|­¦¬ê*û·f2a‡L�§GM%%K!_ÈdÀþÊ¯ÕØÿG }þ¸ÐcÏ-b n¶ñ% §stóÞûp+¹ª„s×±Œ/½«–}ñ÷“!ÝÆ‰ƒG)Ú½"G -�-½Ê¢<Üä$ò̹d—h`°_Y$�Î>—Ó–EF– •¾ÚŸ“i3r=~z�ñKywÁÞžU%/¡ùÌr^}úCþÌõç_ïÅÃ]ª÷ÚÖMöĵ}¾d׆]|ñ¾#i¸0xô@¼.×ká‚UAUlŠ¥48ÕP•K�¶%H'sw³þ@!½{Udx¶%¯å½ï£ê¤æjï¡þ©RÂËï$òòE¼T+63çó$æÔôœÙÊŠ5™¬X+á륧•£6•Œ…”’ÎlšÂâï“X܈ª¥ñÖü">tÖê!ã i¤eÙH®©�«›+EEE˜L&›§"r“f=IÚk±ìÐi6.9ÍF$dÇúL~•ç&;ðãF 4 f‹hÜ„Ë�ä3óM É>(჻ë|ñу{¹gmø¥¨Ww^íÆ¼Mblª ‚Ð2>G‡.Ý[ºU¨Å霉O#_5âB°§©J¯¢RœCŽÙ„»»c•eW”Â4R ÁÉ“€V8È÷\i©g%r69—bM�«w­ý]16¶;³h7¯OŠe™¡Ü>w.wFÖo&ªpyÈÉÉ!;;›mÛ·“žžNaA!ªªâêæŠ¯¯/}ûôÁÓÓ³Y{H+¨¦Ÿ%!5«Á� ÐÖxŸÿ�¡…„<ð e1¨è!A„+�ìèKXßZŸ×9zà]C'”ÎÙ�°ˆZ¶©ã¹ÒRqô ¦­Wp½êZ7•Ä•?°:]éÇu\.‚Ñ+•‡‡b¶X°˜ÍM&LF#&Ó¥\WVÆÙ7”:¾"‚ \&D@*‚ B Ñ(<:Ÿ—¾8H±ȤiÃñ�XW<“Éd>]][º*‚ \D@*‚ Â%¥¦íàÇeûIN=Ì–M‡I±‰¼ù1îèÒLó A„Ë–HAA¸¤´ìCüï§œVìÉfúOy„§o�ÁE¤ÖAøÇ© ‚ —”.j }7œ<ňW+?ÜMbœ® Â?•HAA¸´d¼ƒBðnéz‚ -®ÞéÎYAÍQ�:íØ¹‹�³z]òrA`ïö¸–®‚ ‚ ü-]cdö8ÐÒUAAAšØ� ‚ ‚ ‚ ?" AAAZ„HAAA„ñÿìÝwxUÞÀñïÌmé½’B %´¡Š‚t ˆ€}uí®º® {y]]PÔµ! ¨ˆDA‘ŽR j„@zï¹}æý#¡nB¸\@Öóñáy�{çÌ̹gÊïT� ‚ ‚ ‚ …HAA„óGQÀn«õb‰ BbRAAø_a©¥¬Æ„ªñÀßßóü?ä/ôþþÌ\�—PÞnÚ²‰Ü¼\ì6;åŒøt’ª"€$�$aÑiùôÆIØí v»»ÝNtd$S¦Üt‘Ï@p= 5e5˜�ñô ÀSw±�Gø3û3ßß\G­!'ãeV$O"»u!Ì­ ›ÕeWV dïhºwAâCŽîʢ̶š†äN—nx´ø ;•ÙdW(¸·ëJ×vîg>®ú<Ò6l`ÇÁê%/Â:öfÈå=ÛtNgK©9ÌÖß7³;§”z<ŒJ eP?:ˆ;‹ BÛ™(Í9J™ôþÑÄ…¸5¾¨; Öp ¿EãKT|ž-~±�Âì<ªlàCl€˦Y\÷ÜZ¬“ùhÞÝt?ÏOyË–ÙLž± ãÚßq<_%¼Âã‰òi[g2Wçý¥”·åååôï=€¸Øx(/ÃZÓ€äíÝøÇÇI¯GµÙp—eî>EQPU•ÚêZÞÿä=ìv;�æbŸ†àJ–-¼9ýyV˜Â™òÎg<ôg.ÀÂEçÒÒ‘——Gzz:˜L&Ü=Žrڔ͒çïàž™ë(´jHz>�mÏ%¶ò£Ô³ûÓ‡¸õŸóH/·qbÏúðÁ<ðþ<^›ƒKBE[>¿½v÷¿±”µ 'Ÿ¥äͰfóñKˆÕ·˜‚ Ÿڲå?±kw=º'2fô¸ó»3ÕFú'�ðüz#ú䇸ö?Wì0ÎQÈþîynŸ{›¶ ÷}öÓ£DJÁOÝYKÛžt GæO窿-¦Hõ#qÒ]Ü|UwB(fÇÒOøhézfN…iéFÞ¹* mI¶D-ç—‡†3ñýý˜5!¤L»“)Wt&@-gÿêÏùøëí¬zãFÖýDê»Wá÷zð Â_Š=“/�ßÊ•V¿¦íz3oüsØI÷:9¿}Ì;s—²q_!u?bz^É”ûâÆ^þÍ'/P*H[0“ÿ.I'ßêO—‘wñøß‡îè餖ðë«OóuÃ(f¼x1N6¨¬\¹’ŒŒ Z~ðQæ|ú!3gÎ$11‘áÇ;—è™Hž¤ôïŽaC*æý[I«Ï(o7O¥˜­ÛŽ`°bKZS£‚Lø R¹=�LHîI Jj|é/†U«Ÿ9?ç ´ê¯š÷kׯ%:²=W †¹üqd[Lãåóý �ý‹ýh¦$ úXÑ›ïÀ(ý ð>ž†HÏ7;‡¾z‚[¿ôä�oqc¸˜BFøsqI@j2™X»v-S¦LA¯×óî»ï2gÎzè!¦L™B»víXþË/:tˆøøxWìÒ9šNtë�Íž?æñåþ{yªkËo3æMŸ³0K!¨S'Ô™Ôœò¹R]IµèúóÈß2Õ§­açЂ©Œ¼ûk²ÕÆ¿:—þknâ©öV·R«~âÙ'–P¨ú2ì�õüôHwŽuî�vûߘøÔŒx}=ònI…”sh¹´¤þ›‡?ÊÄ$G3åó ÌŸ}¢ Üy7÷CÿGVqpî«Ìÿçpl5²á’¥”�öã"¾Êméþ¤`³XÑëÇ‹ÿ†?u¤¾:†Ñ3~§Ê#šÞºe9Bê/òó— Yõå>žØ®)À²’ñÆ8†¾PÊЇàjït>yf4¿å®`Ëë—áÙl_*%?<Ê�/¬fð—/Óþz÷eddðÐC±ïÀ.ÞÇ�+.'¡CwfÏž}þR$üz÷£«n+é¦]lÞifÔe§�³P«ÓÙœiCòöÅ»¾†½[·S7a>§Å® lß¶‹*aHìO/Q3(\V«•>I}ÐjuXj†cªû°ñEBskgìÇZHe�Œ2¨•(r`»˜‡ý×¢Ö°o_> �.ö‘‚C. HÓÒÒˆ‹‹ÃËË EQXôõ×L¸v,Ÿ|2—n¸�FChHÈÅHå0®¼Ê‡¬w¶óù‚tþùZJ Ý[ëY³àލ\?¤¿eežö µ¦Š$7|ZhuÌÎá�(‰™Â»óßåžÞv>]¦mTÊ~œÃE ÚNwñêý'‚Q$=ñ,×}rŸï›ÇÜõ3H¹ÒNÞžý™$¼¢º‘ÚÂAªÕäì”ÁÐ[ÆÖYwü‡»_ø�ú„»Y²âÆE4ÞAê2fqÝ•�ñÙ}O0þŠy\ã/�i-ïÍÞ†ß-ËXøêp<°q™e}f½ÍÒ'qãIÝKÔ²¥<þð"ì×.`æu¡çÔ DUUêêêèÒ±²,£( 罕FI¡¼†ô}u¤oÝ‹å²dN­;lر�]‰ ácé»é+–elc‡q—Ÿ:�y7[vQ%Ýú÷Æ·)CÔº²òkQõ´� ÆýØ¿×�UP atˆòÅV´›ß·¤Ú½3C‡uiÖ“G1“™±—ƒEU=~aqôèÙ™pwç*�IOµT�½w?‡Š*h°È|‚ˆîØ•„/Zª‹pfWj1ï›þýXÞkTE{ÓI?XD�bÀ¯]'’{u$è,+’íÕù,ªCÁ��Øh/Ò�@�çxêŠoG]ØšדýóýÇÿ®hîk¶½$IMi8çlÊ—+~ kÕ2vî'·¼›Á�¨„$zÅœv-·x͹ÅÐ=Ö»MÂ#$†öþ- ´RM>J…UÂ34–h?-JM kÁ#”ø(?´¶jïÚÉž£•X´^„Åv§gB(ÇO]¥¾è¹å{Ø”iCUMgg²¯Fƒ! ŠØ`÷f÷R§®}¥ŽÜ]ÛÙ™SFƒêNhl"}z´;¥BQZç’€´²²_ßãs“ÉDmm-f³»ÝެÑPUUåŠÝ�…è±éùÁ6ÒÎã÷çRêh" ª_˜¿¸oâÚAv–ì ¥š*ª�}ühã|M4´¿îC6¿1–®^¨emØÆÈÆß~§NÕ5r,ÉŽn”¾C{¹_|WÌêßvb»²_ºŠ)_Wáwã×d/¼_›Ùw½Å5)ϳSêÉ‹éÛ˜¨¥×Óë8t[åš(b�›>ˆ?ª¬�¢†SþŠì‡>æ¾gÖ _õ>3§F6µxšX÷áÇdØB˜öÚëǃQ¯Ä™õðôœñ-ïóL¸«Jv*i¥z ìÓ4ñ›–„}ñy%©{lÜxYÓ‹šZÎÏÿz�/­ølæ ǃßsQSSƒ»»; Øl6ÊËËÏ=Ñ3‘ÃÐ7Š÷¦½ÆÐ³ò{~Þ¼ƒÍû-\~Ê�ß–¹�mÕ h:0 åD—^kÚîr0±ŽuÇ\î™±kÒ,¸«–—›Çž9t"1Cºà¯”*¶/šÅ¿çÿANƒÒlžÙ#Š¡·>Æã“º~ÏÈ™ôÔzö-~›W?YÃÁZ{ó0E2Ök"�þëv‡iÏm›ó Å¼Ï˜ÏýO­À”x Ÿ‹cùK¯0oG¶ã*¡À¯Îà†ø¶Õp+åyý¡Yš'{Íó¼û`ôy9§¶PUõøÐ#IvÇÏû 5£†9þ²Á€é»'‘l.xwp¢|�Óoa+fÜ×yã»�Í'´”t&Näñ§îdÈIe¬åkn·wÝÀÜ5µx}šïžê (K™q×d(í¹ýƒ�¹Ë,[?ä®7`ïvó÷gÁŒ·ùõ¨éĹKüºNäéçÿÎà°²óÓGyô—Ú¦ïdáS÷±™¨Éo³ðÞn��€“×¾- o>7‹Ö¡ÛH’ñî8ާžMÆÑˆ7ApÄ%w纺:<<<0›Í(ŠBMu K¾_†››»½±«—ªªÔ××»bwçÀ†Ú~"7ô~�­[¾eÞo¯1t¼÷)ßQ)]º€ŸË!ô¶) ÷œ�£ÎjjuS ©�¯ÃIË4t~–“gسٵ§-Ý’º¶ð£yÑ-±Úïvr$c7•ôcôÔq};Ÿ²_¿aEÕuÜàwê662¾ù–=6 ÃÀiLiê¬õ !ºS-=ÞÔ²½ì-R@O÷Ñ:*9J>_<ú,«mù÷ÌÛNŒÇ·e°rM1ªçDÆ^qê8 �F�¤ÃóélZ±�Ú»&ã^^J¹êA�€÷Ù?Ê)9>nU¥ò—'yp�‘ñsßâÆv®"`±X\–VÛhˆí—B»‡É-LcK®B·“‡<ذ%½EÛ•^ÝCH,‹E³1‹´­‡°'w9©•ÏÎámé”( �íË€6䉤ף“Àb<Â÷­ Û§ïŒÅ×#PëIÿðŸ<²è�8®úÛÆôŠÆW­${Û2,ÚÀª÷Ÿ ÔöïLíÀÃ&§ÒS©Z7‹Çf¯¦Â-šË§Ndx÷Hü 6ê 3ù}éb–o_Ä3Ïøðý[HÐ9»Í…%iuh%Pë±èå/XmÄ]Oô§s°cáN–Ìÿ†ÍE›x÷ÍHyïÆÖç·ÔºÝ|üÔ+,ÍS‰ù³ìGÀE9£ª*ÒÉílM3:)7#­÷EÊqC · ©F^H²„tòÌOg¸8Y^�þ-Ô*þ˜õ(Oý\ˆâß�k&�a@¬?TbÃ÷‹X–ñ Ïæ­›"�íµdçSçN\¤ï9=ÄÖlÏãå9kñôÐó߇žCJm§íØŸ~Aß’[z„­ÛJ¹5&ôxë¦=g©¥ šöÉôÑÑ«š}ä§¥sTér¢ÇŠRÌÖmyØÑÝ7åŒ ²  ä­aeÄDÞž{'‰'­'cËüšÿ|›�Y۞ɯ¼ÅC½N<»º§0°ãÜúÌ/ìZ0‡_¯z•«O|"½,gÒ«gËÊMT(Z¦½ÈkS£OšÌ©CGô%øž‡ùª4•ßM#!Aãä6˜,!öìü’|/½uíI3Ô§Ð/¼Ž)�ýHÑ��l*žDLkΘóõóÏ2/ÓBÈ�G™ùØå„^äi¤SßJä¦\ƒ2ªé» Ô‰e`“àû$$dùÜÚ¹ò…Ó¿…eï"f//ÄfèÂÝo¾É­ñÇ6êÇåƒp»ëq¾Í[ÎG?]KÊ”¨Æ2ØÚ5g‹fTÔÏÌ;º�åkŠw}ø)“½å³fm6 ô9ŒmË�ÇŸ¿��Iw3çÍIÄ«déÓŸË»yrçƒ_qhÿw,Ü:‘g¸š4‚qáõü2gGð§û°1\}Rs./Uj6|Å×Ùðèͯ?õÇÒì”@¯¾‰>zï5¨8˜‘MNã’bRWWGee%&“ £Ñˆ——ÞÞÞ˜ÍfÌf3•UUÔÖÖºbwçH&âú[éÕ¿Î㻂æ³G*Ù_³`½M§)LØÒ:q*5U5(*X·¾ÂÄIOóÉšl¬¾á„û©”Hå§ÿÅ5}p÷wGÎ}ؾRCUmãª^-.H'áéå�ĉñ­x á¦ë¢Ñ¨U¬øöWN]¡Æºõk¾;`CòÎôë"ÛP,Zp7¿›‰Í³/O̾—ÎbÙ0Aøk±îdöŒ/(™ÄK�¥pò¨¥¼˜R»ŠJ�£Š{ÁÞJi1% h"¢ˆ��T¯ø³äS*µ#ª�ÔjVϸŸOªGò³§â±îy®lLdB7ºD‡Ð~賬.s¾OXyUÏ?x5õ °¥TŸÀÀddÕʾ­Û©>~ø iiäÚe‚““‰Ñ€&®Éþ2öÃÛØVzâY¥V¥³å  ä úõïжñ‘Rc¯JާN¡G³g‰•Ý+~ã° ÜS&sKÏS+R%üL暎ZTÓ~ý½ŒÖç]v2=¥�šZ*Z­ƒªCwÍYÆÚ%ïqç±ÀÒ™m.U cì-ãN[.ͽkOº$°—RPÜJÎÚ‹øõõ§˜½­¿¾÷1ë©QDý –?mü§$5®jð]0hUÔÉ¥ W‘~júŒÆ€ôäÒ³ºŒÏ½¼žÝoae÷ʵäÚÁ#eׯ5ßHòìÉ ·^Ï5®¦_�ë‰ÃhùšÓvdÌèNè°²ë×U9å•Üõ¬>`�ÞŒ½"øô÷3ÙŸaS®>Œ;þ.ã×E J5©[2Ûðþél^šÙ¾1�zU£ïFžZ‰¢�aâµýZ^CYNá’æ­ªª*d­“É„ÍfãÖ[oeáÂ…LŸ>ýø8Òêêêsj!ýàã9çtŒ}_û�Ê;�‚ÆsËÕÁ,ù|ó¾ÊæÎG;4]ìvö.\@ªEKâMSIÖµ4œBMUuãEiˆcâóïðú½Ã‰ó”…Ú¬¥¼v×ßx}ÝnæÜv3]»¯æás‰ÜvE´èZyøÈ: ¬6[ÓqxÓ$âÿûoüö ¿VNâÆ€cw [¾ùžl»LÀèéŒ>Ã]C­eÇofÂ?–�§íÄmŸ}ÃS½Ew]AøkQ)[ü¼·S¥×KO0. ù}C56`TA208º¥HÜ  Ö6~OŽʰ•·ZNáßn£�TÉÊ%ëh¿–+»j¨Y÷÷}TÁð÷Þá–Àuñü<­eÍ™m.ÉБ�L¡õÆÛ]³ ³¥…ÈL­bËŸæÕÕ¥x&ÝÎ^¸†¸³šPñüQUµY÷[I–7ûÂ�Åà¡€UBÞâ�*ËljÆÉŒ¤¦ µÍ\P^Ïê·PJØ›YŽ‚†¨Î�8}Bk™ö#þÎ#Z8^G×2Q#F“ÿr76æßÔ8^Çq@ª¡ã?ÖRy¯:7< '›2Þ�&ðÊzÊ’ÇóqÎÌþ`÷κì´ØÚL£G¯•Àj¡)¾wÈf2cW½áø�W×{ “»Ìä¥Ý+ùæ×J&OiZ£Ô¼‰¯¿?‚]áê飬•zË?z-·þ7�Zïþ±p1ÿÝî‚ÌZ(Ÿˆýóß^B™ç^¿ÝÁxv�¾ñ>w¼Rìª «µql•^´‰Ü÷Ê­|yý ¾òú¹ífÙ*?ç1.·ýÎã÷~@é°·Yv[ öõo°$?ˆ‰þ�$ øÜÆC׿ÂUßǦ·G0܉lu�Z˜ký|òHîG/÷µlhØÉ–Ýf®ìk€†�lÙc·Rz»ƒ»‘Ô§†U©d¤î¢aÔ`<1“±5£*ã•Ü�g”H†@‚O}£VÊ))kl÷Èùö¦þâ8€³UW¡¢b.+¥F�{í:�ž–.Ó玽3˜³s?‹g>Æ’Ù^´ëœHïä> 0�]CpkvøÎlsqHn^x9|ë’�÷ruŽÙ»àY>úá0}"÷þëFºüIëƒmæLdÙ<´X9 ¹AƒäaÇþø4o&¡ÑØPl™@¬s;qAy=«ßB96¦]‹_€ïYÃrxÍrà®0‡­«óXñëîHHj|w³ç°zÝalrCG§8¬l“¼ƒ uX¨eü|‘)A©«¦Vå ©“y©TSYÝ”'þއ’ÉþAü ®;áÒà’jÚêjêê멯¯Çf³a³ÙšÆ’6ò#G�¢*ÊÅCz÷ËoáÆZl{¾`~jcw-Ó XtÀŽÇÓ™äpzÙ$�;ž^ž§£'}î?œÛ¯�Eƒ�¼-›9Úzÿ¦ÖÉúË�]w«[JH¡ª² �‚'©Ðö`Ê�=ÑQÃÊo–SÑt‡5ý¾ˆÅyv4Q×1ýJ¯w­Vläõ«rÃ{Û1µ¿–wÖ®âMŒ Â_’}ï—,H5ã7úf&†:xÁòõÃW>1 ùilUTÖ©H¾þ4VúK�{ŸÍ©óyøŠ8¢Snç¿Òøjz›_¼‡÷Іðò»w§Q©ô>ÞÏM·go:iUêwlc·° u{5Šd ×€ž8ªÛú¾µz´§þtª‹@Eµ[±Z-ÿ¨ADD´#ÂWëp²?W¤'yvãö™s™ûÌíLèO€¦�‚=ùqÁlž¼o*þö|»¯®YàæÌ6‡soçjá2Þž¿‡:TËn¾ød=eçòNq>4�Z]Åg”�Çô·\¬±õ(e´¯%"¹C¤ åžHu×¢±~Õ¬Uõ¬–\rIy=‹ßBµrlþ3­V{ö©£k@òfИ!É %ke[Cã?۳׳:ÇŽ&bã[¨q2+õÐê´M‡mÇz¦lu6/U fë±ýéç‰FƒF©Ð6.›Ô((4”ܼa IDATÞ|-áç| i‹CÃA”šjjœÿ5ÑÄ·×@nG�” å );G³s±#áOäñˆQCçÉSèûbW}Ëòò›˜ddÝ¢%äÛµt˜<k³ ÿÊccnà­íõ^ö4_}óŸñé«ßâ¥øÏ5‘®y‰;GRÓHà×îU*L÷Q›¸�Q‹áÓdäz/¤9ÉØNEí\�¬½»çËPÝøNØl¶Ý6íÐÅåµ ûswP1M(x¹lž·^£¹Œùy°|K‡ºs`í:Ž(ZâGŒ Åùf3æn{–¦HQrkaèÄÉœÍKE�¡©nÐj¶ rj—dPM •‹_ $\\rM%&&b6™0™L?÷ Äd2Ñ­[7WìÎE4t�z ý …?ÿÀÆòÕ,ZZÁWsó¸¶]�йžk‹ŸRRTÚØbéx¢ÅÒr$ÉÉáh°±+5‡uúJ>©©G±£¥{ß^ÍjÍ娏i�Ô®â»_*PÖñõÒ"mW¦Líí°ÃšZ³‰&Lâ­íF"'¼Çš_^Á¨ ü•)ù¬]½›®'Cù9¾Gêz1¸¿jÅFÖï:õæ¨P´~ {lZz Äi«cLåÕ{Þâhÿçyïï›zcHxxy"© 4�½à¨4Ô7 Êžx{9wƒ­®süÌ:ÿdÂû¥§{Î.vW±sw Ц)½#š?˜5íIIF¶°#£„Ò�;9b—Ð%ô£¯ƒ±eNÑ„¢EÂFaAqë­Ÿ8=É@‡>#¸éÞç˜;ÿ5®o¯E­Mã‡Uy-N¬äÌ6frÈ8^ü÷í L¾žgH5¤~ðó2[Ãs!I'•*KšƒÁØm2j ÉÃÂIBÎl¶ƒ Ú�$éÄŸ³ÙŸ«Ëë™È!D„h;…ùEË�j3c¶9|i;3fTGtj›×l¥ÖšÅêuy(º.ŒѾŗtµ¦„“£ýÙ)+-GABìxr¹“9›—²?A~2`§´Ôñ$gJa…bü¨ÐF. Ho¸á2÷íI"((OÏÆ*gY–ñòòÂfµ²}Û6&OžìŠÝ¹Œ3‰[‡y¢þÊwoÇŠr‰ˆënfÄ©K“žÊ–ÎKýððdÄìŽ/`Ë–ü|¢úö%âœrZGÊøÑ„kª~YȲŠÓoBö¬E,Lµ"铸z\\ó.µr$×ÞtžÔ±véjŠÖ}Ïò}ŸiLíæ ~U-eéCSx%µŽÀáo²láßé~¶ýÂAøßbÞΖV¤ nôhiÝKÉŸ‘ÓÆ¢dòÙ›ßSxò[JíFÞzg&��LŸÔ¹…nÿ&¶½~3³ûñÜû÷ÒùøíI¿sáj6û²ŽÍˆkfÿî(aÝèÚê ©–Yí*[þHÃËóÂÏ#Gõ¥„՚Ɏ´�d¶#ô¢oÜ©9£%¡w>²�¬Ý;ضëVUC‡þ)„¸ª™Fò'©g{4(¤n!Ûá`…²}[Ø‘Wwæ—VgÓ3—shÇ–m<Œ£ªÉ'‘¡}‘P¨,¯l| vf›K�Î-€LØÈGxrd8²i?Ÿ½ü[k/~ ”$I(jcÎÚ,htqø.‚×òþ˜’òÁÍ µWÚŸz£ûn衘sŽwÓmÞu×°«Ëë™È$&F A¡(-�ç%h'kÞ= >‚aÿZ†ƒW´Ö'úªQ$»Aý¶µ¬ßº†5ù î½F2¢•Ö|Õ¶Ÿ´]J¼’Çž}µ(ÈDwŒs8ÙP³Ãs6/åP:Æz"£�¿{§]X G·¥‘+R¡�\ò8ëÔ©ÿüç?ùòóÏùæ›o¨ªª"$$�NÇÎ�;ùúË/¹ûî»ILLtÅî\G ãš[Æà¯æðùÛßS"7®Qzƹ´Ý¸jhvÕÌæWïæõÍ•Í/pK.K½“·öØ� 7gÛqAº‚ñý½�¶2çíUäãŀу[�HR«Y½àkö5;q•ªMßðc¶ IÛž!ƒO´°JMã8V{eÍ¢GgóÒ@Òe}ñ‘U,;à‹Œæc´-yËyÿÛC(b ©ÐF.~0lØ0’’’X¾|9~ø! 8$„ä^½øtî\¢££]µ+’s ׄ~ËÜÂ:´I71­O[¦j4Ð÷É÷yì·ñ¼ž¾†g.ïÄ—C¯â².Áèj󨾿W6åÔ¡j#?s.u=ñö¦ÎcÊ�çØ|üþ¨P_Òø?ûÞM‡OOÜ” #ß&ýà �3¬i{ð�Ÿç—áO±aátznù˜1Wv'ЖǶ_~ak�mû)¼3ëFÂ�í ÃÔ1,ùê[Þ]hEñôëŒEUËùáݱuëyj`O·’Þ?&mÖpçgá’ TUP¥€ìã‹OkoõšxîXøÚÝϳóÞäáŸT$ô!½˜òŸÙÌz(ÅñD<æ�üçž×Ù×s›ìzz%ž¡?3¾˜Iδ§¹,üI�?Ý'¿ÃÂ}[^~¤‰‰‰,^¼¸ÙD*’$]àJS]ú÷ÁÿûŸ(ØŸ ’;ƒSVˆJžIôí¬cýöýìäÈúǸv…6šÇîOåž77²ý㇙ž6Œ«úƨ5Sš�Îê5éäuD�½—›{œùŽïLzrØHî¼f)�|³‡O¼�ÔÁƒèÛ!�BCE.¿¯aóQº¨k˜>¼imFg¶i3+[gßÌØZy©Öõà¾�žcl«SÕ»–ä‘È]OO'ãþ¹ìZ=‹—;ðŸ e²AEQHé�®=»øqùbú÷@X`0rTju5�¨f3’ÁÞÞHèô:ò�æ³výj¼¼¼¸æš‰Øív4M›+…\]^ϸ¿¨ Ü©m]ÉЭ)^Ëø¥FAÒu¢o¯&)’Iîƒf{6d‚SúŸÔ�ÙU´D�}–9A_ñîœXŸþ3Ÿ¦5}$ɸwcÜíwpϵIm\ÊÁ‰ô$Ozßóf}Ìß­c÷ªïÉXy,= Ù=”žcoãî;¯!É[r~›6S±ÔWQQßÊWôuX.B·DC‡yöÞÝÜ9k [>x•y]fr{§ Ûõ\UUl6V«•@ÿ@êkXµî7ô’ĸÚZ4±±HaaÈþþ¨&JAÊ¡CÌ_8³ÉDHHâ;€ªbµZ‘eù,z)¸º¼ž‰žŽ“^⃠ùÌžû3©[—ñE*4–±0ú\+ÿ¸c8qNƾî½F12b9Ÿçª„ IŸ3 “’¢˜ôâõtx{ó?}—ú¦Éƒ$}½®»‡'ïÐ|â9]¦Üu%[ÞXÉÑœ�,Α0$·çöi€äd^jÚs㋯¡ÌšÅgësØúóB¶’Î�„‘�ðʽ±¬¸g1`ÁtÆé~…¿:)èö«H�µ(GgßÝê—÷e¤“Üð…8®f>øxι­Cz¾Ùë(8x€Ü²TwÚÅu$Úï|®m§ÒP|€Ìì4¾DvJ ýyÝŸ Â_[úæ tIL¾Ø‡q�(+òÉ-¬Æ¨jñŒ 2Ì»Åe&ÎOzVêK É/­¡Á.ãîDdDž­âÎl#œ ›Í†Ñd¢²¢‚²²2ÊËË)//#2};••øVVâ[]ƒÑ §Ìߟ"o/öîMHPÁÁÁ„„„ˆ§§gã’*Nu›wuy=µEyä—×c3øŽß¹î¬aÿwË,.oÏ}Äß:8nï¶lx…Ñ3VaŒ˜ÌÇó鍊,ÕÉ«À¤õ"4:š÷–Ûhíõ%-ªÂCýp;í«Î奵¦€#ù•4àAHt4ažbLáÌ¢ø/ÇbPq›v�í:÷¢]ç µC �ÐNô ít¡v(‚ üeȸDÑ) ê"¦§Ã38šNÁg³g¶Î…F£ÁÃÝ]H~þþDGGc2™0öIÁl2Qd6“oWÐhdôz=nnÄ ¸¹¹a0Ðëõètº³ê®{:W—×3ÑâCB˜«ÒSÈÿåKV”ªxôžÀøÓ&6sìØˆ½o;:ú¶kÓ6Ïbã[û†sy©óiGŸ¶ƒ 8"RAAá¬I’„F£A£ÑàææÞgZ¦@hN¥~ßç¼8'£ÜŽÉ7� ì’ŸyKΞHAAáQJ¶°pñ ‹÷ðûú=Yõt˜ôw&žq�AøŸ$RAAA¸@ÔÊÝüôÕ"Û%d÷pMýONOÂK¬’"üE‰€TAA.MÇ©¼»`5v=¡!øÚÖOW—|'}2EëO”xƒþ‡ˆâ,‚ ‚ ŠìF`D4�g¹™äJ||èy9$A¸˜ÄÐiAAAᢩ ‚ ‚ ‚pQ\i¯¤¤‹}‚ ‚ ‚ ‚‹]éö�;/ö!‚ ‚ ‚ .vI¤‚ ‚ ‚ Âÿ� ‚ ‚ ‚ …HAAA„‹B¤‚ ‚ ‚ ÂE!RAAAá¢é_ŠS}=u fìûPþTD¾‚ ‚ ÂÅ ½ØpaX¨)«Æ¤¨ éð ðÇCӆͬu”U5 ¨ é½ ðs§åÍTÌ5åT›T´žþxž9kíÆJŠŠJ¨¬7cG‡»w¡á!øê%GCmyF»Úz¢ZO<þ°jå/ÚBEÈ@¦N쉯t~óEµÔP\XLE­+Zܼü ÅÏÐz=Èñ|©3c—õxxŒÏÿH¾œÝù�v´g]ΰÖQRXHiµ›¤ÃÃ7˜ˆvAm;'AAA8�\�ÖÔÔPXXHmm-6› ­N‡·—¡¡¡øùù¹rWgG)$õÇeì3©€Ž˜aSŸàq†�T*2–³hK)   ÄÔk’ðu3ØkÈN]ÃÚ�ùÔ+2A)709%°åægk™›ÖñǾBêOi’“t>D'fhJ{¼ONÀžÏæÅËØoný¨eÿdn˜ÜŸ�Óv®RŸ—G…"ã�·ÄùË¥žÜôõ¬ÝžC•õ”@QëET�Á ë‹Ï©Çh­`ÿ¦ult˜/¾Äô̽£ñºTóÅ™ó;ÙÙ–3¬”ïÿ�•3)1)Í>Ñx´#qÈ• ŒõÝ$„¿¬²()-&$8”Ž;]ìÃA„¿$—¤IXX²,cµZ©««ãðáÃx{{Ó¡CWíîXÉËþ-¿ÍØ‹²ÈªRq÷óƒê*,§}C¥:ó7–¬;HµêClÿa„åÿƦÜÖ_ÜìùÛI=jDÕ†Óü’ýN¼u‡FÒ>þ¼—êýÛØ“Ôþø1ª3f�Cé5|$�O�XÎÄZDn‘ ÉKÔ©Í„.Ì{ñv6ì­Ä.yÑiøµŒèàu"ÈëÚƒ„Пøú�<ªö¥±¿W$IÞ�û2e§²)׈ªgà5ãè¤;‘h·tNû‘ï¶Q±'�¬žát÷¼´òÅÙós¶œa>ÂæM‡©Ç@äÀ‰ŒO 8~±wîÒ•øÍ‹Yœ^Æî?v�0©¡¢™TpD5R’s�¬º–Ê›ŠbW�#Cé< µRœö?¦bÖz€—½–⬭äd wĆÅy6¥ e;~懭F"{§/eÏ–Ÿ8Z7žIÂÑ�²7cö¬ÚšO»}�FŠ‹‹éׯe%”W–Ò>¦=A!lÙ²E¤‚ ‚p�¹$ -,,Äßß½^�ªªìÞ³‡Î]:²}ûvºuë†,ËxyzRQQqqR<ˆŒÒSUYFff)ÉýCZè®h%/ëµèÐ.�£UU¾£RSTˆÑ»#W\y9=BTöœiÿ*ÕÅ%4¨ Æç{úÞõqDºíc¯±‚â2+ø7EXsc�£Õ£wb쟽$—|³Š¶}á§¾å¹,_ÊçP­€&<‰þñ^§¤#ãߥ1[óÈ2—RTj'É[ Ø(ÈÉŤJxvèMRЩ¨%¸{7"ÓŠ8l/¥¨\=°]ùrççT9cÎ^²Td¿® èpÊ…®'<9…ø}¿�Y¹Ÿ½}�JäpO½‹Á?T¨Úý_o('²s Ç:µ+e;X³µ«_7Æ]=˜˜¦¦NkùN–-ÙȾõ›‰�¸’8`ÏgWF úÎãÕ?- áöríÌàpr8�Nn¼7åðÇïQã†38þL]èÏÌb± €ªª˜L¦sNSA„³ç’v£ÑˆÁÍ Um¬E·ÙlXÌl¶Æ�rªª‚$ý ø*Þíã’*ì§ ¥)UÍGÙŸÝnÑćË8n�ðŽ ×� GHÛ»<Êrc !i4Ž'H’4hš~I:Ñ Z,XT�tzÚ4÷M3 yùÔ«2!‘íp;ísWå‹Lpïk¸ù¦ÉÜ0,Áñx[� P°ŸˆHKÌ�iÜ>ý&®ïḖD玻VUåÄž/�|qþüœ+g6 s ± áÝÞÁ¸Y@AL;-¨FòrËÎØ5]N¥Vïeí–|¤¨~\ÖÉ«©ÅÓNþž½”©t0àx0   LdpRRÃ!vªoL£¦„£DpXpÓu!ã‚ÁVJqÅÉ¥ÒDΦ d*±\6(žsGÁl6£( V«³ÙLCCƒ RAál¹$ µX,H€ÝnÇf³a6™Ù¿ïV«EQPT«ÕêŠÝ�¼cé¢A­Ëf®ãã1æd‘c�˜ŽDiÕ^Ö%ü"c8­U­5ÞaaxI ”Rè`"µ¦„R£ š`ƒO„.jSK ¤7œ6¾ðŒÔZró«Pä"#¼ At]¾È:w¼ý öm!x2URÑ ‚ìK Ÿæ¤í xzûâãæ¸¥N©(¢Ä¢‚&�à€ÅöÒÉçÎÏ©r¦ÖP^adZ¸Èuú"£P[^Áæ„„æÔz27¦’§„ÑgP‰î³J9¹ù�CbÚ�zEJøEGã'Û(Ê-Ĩ&#&´¸¹�¸×In˜0ž4nÕ|t3ë2mļŒŽžçÐW÷v»XèIA.6—tÙµX,è l6ªª¢ª Šb4�Á(¯…¾¸TTÉ—N�ÃÙR”GöþL1›·Œ©uÊÊÅ"yÑ¥s$:c¦K�@Ö“~±Y™�Íï+Óq’H”·P±T!mÍvŠÿ}èêÛ¼…Ôª‚¤“¨;œÎ®}Ùä•Uc´Iè<| Žˆ£{RwbýD.Æ|rË$¯"Žƒ¼Pùb!ûNòl  K sP[êCT,•ùcõNÊ¿îÉtöù_Ê—ÖÏÏ)j=u *H<=[ Ó%<<=�µ¾ŽzÜÅ8R¡�ÌGSÙ”c! × ýO*8Ö**êd_ü<]d_|%¨ªª F�¤Æ2xr§UEAâxs.›6ìÇÚ~(—wôDR­Ô×ÔaÕxâã¥?§ZÕœ¢Ö§ç ÓjÛ?êRAÁY. HM&6› EQÐëõ�Ýx›‚T£Éô'H$¼âh¿)�C¹û9Xßá¤ñz Öb� Ù¯#�Ã4pØÕ»÷"aø4©IÝ—Êâ©è=<ЫfŒVdÏP:öKaP¯“f ¥1�UÀ^’ÆÏ¿*¨ÞÞxÊ ÔT“SULNV&݆�åŠøæKyX r)²I¸µ‹tÜ}ó‚ä‹BuæVìªDÑ…ÒwpwZœ#H)gך-äm˜ë*)«¬Ç® ¾ï@.OŽn^’ùrççÕ‚Ù¢Zt­´¬êš><ÖÊ,m¢”±sKõîÒ+¤ÙÐÕÔ€QÉÍwG×·Ö w½„j4b$//<±Q_o†¦Ž¸öúzŒxâí)rS׳×̓;¢-ØÊ+ÓÉkP�T �ˆd®Ù—H'/š“•!};³.Õµ�‚ ‚ ´�KR“É„$ËÇÒž={²{÷n�w‰2›ÍN¤Q‘‘|ðñœse0»Gâ«“?«Ê!míZÒ *سz�èéwìmÐNQ^!V´DE…µþƒŸ·|±Rº{%?ÿ~˜:É�®ÃFÒ'¸µ#1Qžw„œú¦f­áÑí‰ ñÅÐ,p¼Tó¥­çç$Um†*�ìˆ$ËÈ€¢*b ©ÐfÆÃéd”«÷M&æÔžùvv�ŒÆa…“­T‹ › ’g‘þ*;�¥¾kž’™ÜÃØ<∠�±ä§²n�™¨ËÓÅPÀºÕi”`Ê”D|ë÷²bÉVn gê�¨Ófäm “ÙFam­[ ‚ ‚à*. HÍfs³€´cÇŽtìØUU±ÙlÇÿ8�Ž=êÜP9ÂÊÏ–±Ïrl†_=Ñ�ãñÊÚMqfå‰)É4®%y EJB'ÿ¶-÷x–ÔúC¬Zü™uz"z�åúäh|š~ÕZIvê*Vflá§âÆ\7”Xw ¿¤k¸«» ²]³7= ½_,Fk0~ý3{j Ù¹§ˆƒÂ[.”RŽæQ5D�6¦ëTç!_”Z²ÿø…ßv—bÕ…ÐëªÑ Šöl= 9„Þã®§‹Í†ÕXKYa6{÷î`Ý�]ìì<” C;â#_ÂùÒæós’Ôˆ*vZ"§Øí��¨ÜÂ[‚p*µšý‡1j£ÔÅÁødYÓøoJKcï$�Œ,r‰ýÈúußýx”PM99y;´'F7I IDATJ!¬ßƒ1ò2ÆwñF)ØÎáz7â†t'H/�¾ Iqi,ÉΦhpQN\3fkãÐAA.—Œ3›ÍX¬V,–“)Šr|ÖÝêêjTUý“tÙm¤mי޾2JEûK_�ì…™¨RÐEt¦ã¹ŽãsÈNAúF²j í1²ï‰`@Òù?pýÂ4(5™lÚuÒì§²�NwJÐuC$]ã}�P©+.æØ²�jUyµ*r`$g>'—拹ˆ´eß³|W)vï8†\3�ËÎŒ Ã;0˜ÐÐp"c:ÑsÀ(&_;˜önvª2×±f_݉™l/Å|9›ós†ä†›AÕÚÔuב×£äæŽá|wáÎÿ³wßñUÕ‡Ç?çÜ‘›½2Ø+,A@µn­{”Ž_­«¶¢ÕjUkm­µÕÖ½­{Û:pÖ­8Y {C �„ìÜyÎï�  {Àóö•1÷Œï9çžä<÷»ìŠ5¬Ú",s9- uk¸G»¶ý>Z|ëY~¼Üa;»$„gM眳ÈØ~1D§Œà¨3Îá„aJçA~}?¦LI¬¾ª*ˆ!nçtY±q1ÞJ*ÚwÇøü�•ÙºáDDD¤#:u”Ýêêê_÷úý8]®^0Ên3f Ç&`ÚÕ¬YUL�…«×Qc‡1pX‘]±Ok;E›ë°q�2°Ëû0¢ÉÈhý´²¤”úV?(5Rc4M…6µÅETX1ĵ&ttÒy±ë ˜=ëm¾)¨',ý~tæñŒÙcþÍÖsÄ�`ÂàH üo( õõ®ó²7í?¾QÄF@€šš†½„[›ÚêZ,ÀC”©ì—Mņõ”[.2²ví㾓'–8��]SEu U¤vMÕ!0cãø~fObc'MáðÉãš�µeŸå×Ñoò4FÇ66Á‚€—óûõN$lßy}í\QDDD:M§ÒÔÔÔ�Ír[A($99¹3v×I †'ÍaS·i%ÞbÖll€ð,FduxX™½à4Æs�ûvÌ?j4?£v(@p¯�ýlêÇÖTã壸p+!#œþý“Zy±;á¼øK™÷þ‡,Þ"*{güh2öU iU±añw|óõ·¬¬ØÛ„yÜ�#rú|øš¥¬^^:x|mfD‘œ‰�Mù–­´xWÚulÙRƒ�IbJr»úßÉAÆ®£¨¨ËL"#}/ÍÜÍdú¥º°}¥l.ßý½nS·¹˜ Ë$±_úÞï –1ÿ‹ŽHªÙ^Ú¹ìöŠ*ìˆâÛùbȲ).܌ۭ~¤"""=¥Sibb"‡~8KòóY¶l^¯—ÈÈH¥¥¥,]²„‰'’ššÚ»ëDä ËÄC «òÖÓ`Ä2tX¿Îé©%FY9i8±©]=Ÿ¼m{6aö—.fÑ&?ê�ÀL`@F¶¢tÁç,ز[°jÙðõç,®°À™Âè‘©˜@¨¬�bŸ�3µ?û·gí?/�¢ïørU „g3õè1$¶æ9ÏLdè°dœXl_ú_oªÝm@”+f3¯0F³ûØyiïñu€³ßhÆ$;°½ëùúË5T5OÁþ2|¹�-!ƒð챌Üëü;"߳모 ‚½Ï&ÞžìILè¡~í§¼þþ·ä­ZËêåóùèÍ÷XTá müጊÝKݶˆÏU’rÈô]ç7Ì”! Žõ±./ŸÒúõ¥ù,\ï%nÈPÒÚñ—̲,N›:˜óOÇŒcGí^DDDºW§e¯ììlÒÒÒX³f óçϧ¢¢‚ˆˆÒÓÓ9ý´Óˆ��í¬]u*Oæ0rÂ×±¼>€™4„aÉ­|²©_ÅoÌ£tg²° 64>ÐlχgW~¿Ç€#ùñ²qa;z*‡mšÅWEÅ|ýÆ+ DÿÄ(Üø©ÙVÈšu›© šD :‚#íøØßAÚÄéŒ/z—[‹ùö�X•1€~ñá˜�:¶PZÀ6#É>âhÆÆ7Ö–So›¤ôÏ ¼[΋—uKVQm�Í|ûúó|»�¥Ý9GqÞýq`��;�)³øºxyï½Äú” ú%Fâ²}T—S\Þ@“¨ì#8bðŽ£é+祽ÇG;ßg€™È¸é“Ù4k›×|ÌËeËÉÌHÀc×RVPÀ–ºfô¦1˜ƦÙƒíóâçû�‹öʈeÔq§b~û%sV.æË��Õ¤Žðd†q$SsSZþÃÚÆ¢/Q‘tçäÆïùi©#•ÉÇIÍÇsøÏÓs°Í0OãøCRÚB8 ‹Œ%.ʽÿvÔv€ºª*jàôKtØîkyÙ^RA=ÒïS¹ÃÂ[SIõ{^Úy|¬¯d{uAÓMTl| çEDöeáœÙŒÈ�ÐÓÅ9 ¼ü!vdÐ.ë.)­a�@JtW3\DÆ%·¯…<ħ÷#¾¥ë9&žè<ìyiçñu€3"Žäˆ}ž‘n§jé ¤""""""Ò#HEDDDDD¤G(�ŠˆˆˆˆˆH�P ‘¡@*""""""=B�TDDDDDDz„©ˆˆˆˆˆˆôg{Wl¨¯ëðÎÃ#";u{""í¡ßE–ξžÍ·'"""�«Ý�´³ÿ@뾈ôú]t`ÑõéÝÔdWDDDDDDz„©ˆˆˆˆˆˆôRé ¤""""""Ò#HEDDDDD¤G(�ŠˆˆˆˆˆH�P ‘¡@*""""""=B�TDDDDDDz„©ˆˆˆˆˆˆôRé ¤""""""Ò#HEDDDDD¤G(�ŠˆˆˆˆˆH�P ‘¡@*""""""=B�TDDDDDDz„©ˆˆˆˆˆˆôRé ¤""""""Ò#HEDDDDD¤G(�ŠˆˆˆˆˆH�P ‘¡@*""""""=B�TDDDDDDz„©ˆˆˆˆˆˆôRé ¤""""""Ò#HEDDDDD¤G(�ŠˆˆˆˆˆH�pötDDDDDD¤w±m{—ÿ7 £Kö£@*"""""r�k@w£;~Ö<”vV@U é#Þ]XÎ+³‹X¾q+u >¼^/–êÀífÿØ€†±ó{0â£<wÈ®9cñQa;×îh0U éÅ,þõöFžxo)A "bS�Ï!>% §Ûƒa:Ú·aÛl"œ!’B,^UÈ1úsÊ”L†dÄÑ/)€ÍÛêX]TÉ;s6òƒkÿÇÔÜ~Üöó±ÄEº€Ž…RR‘^jÁú.¸g ¾q# �Nèœ 7…ѬÈJ–.]ÆGdóï+Ï!6ҽǢÃÄ1l@?:,‹ª:?e!ÇÝø!¿;+—O´?”*�ŠˆˆˆˆˆôB/Î.åæ§ç›–MzÖ@è¬q…šÂè Èr–¯XÅ 7ÃøÁI­Z56ÒÍíLáìiƒ8ÿŸRTÞÀ5§ÚJ5틈ˆˆH ì`5ÕµÔöÜ£Oò×°mÛV¶n¯#ØÓe‘ýz~v)7=5‡ÄÌ1D'uE­`Íšµ¼ùç[F››08™7o=‘·¿ÙÀ¿ÞZƒmÛ-†´?ª!é6¾Š�,_¹‘¢²Jêüw1IédÎàÏÁó©±]OÉú"*ƒ­}�q?0‡´ð®™‚ïzfÝ}'�~ºš ¿ ‘Çò�7o`êž­Øúÿ·wsÖ-ŸÈ8�Çžù£õ(ÒkÍ_WÍŸž™KRVnç5Ñ…�a4ÙãeÑ’åÌúó‰d§Å´{s9é1¼pÃ1œ~ËûäfÇqLn2жšRý*éV6uë?扇žaÖ‚ê¬=C˜azHs<ÿöNÞiŠ÷ZÁ%£ÍØ¶Åæ‚õÜø“ñ�¾í+ÏÌåo/-äº3‡àp´¾–T�TDD¤»xW°p¥ÛŒaÚ9?Ú3Œ6q$ÆÌKObõóE¤¥Ûl@ª»–â5›©¶ÃHÉÊ$q÷j;_96nË‹ø�Ù{ö¯ UQ¸®”Z"IÏéOÜÎ'‹ú-kX²|›+ê 8<Ä¥f1jìp2"öLÁVõfÖ”Ô@D*ƒÄá V±aIË ¶ãwF‘–=šqÃSiaÕNØ^Èú²zl3šŒAýˆÞcŸ6õe)Øîw™YÉì½Û©M]É: +K(«·‹ú²õ¬\µ ÃŒ¡ÿàt"j�Ýö$‘�™¸gÍ©UCÑÚÍÔØ’³2IjZÀ®ÝÌêâˆHcð€X¶—Òå Y¸¶”Z+Œ¸~C™0~IûH¿�ÊMäç­¤°¼ž`X†�eü „f�Ù¦®t…åËøvUÛö²eý*VT;K@vr84•ÃÞǹV�Ÿ¿Š‚²j¼F±)1fY±{ÖÒwÆq‰È®Þ_TN žÎnªÛT;ðÕòú9n…Ÿuž& 䦧æòÌg…üò‡™@ëjIHEDDºM�`È s_¤ ¢Žü-OÙìG¡2Þ¿ã2žXÎñy•[§îšfëæ<ÄÅ·|F-azÍ ÜsJÂ.®W¾Äïf¾JqÊ<ðüåLìª%<×?yú«ÂÝú²˜8ú¢¸áÌaD6Û�ÿ»G¹äϳ �º„g®�ç¹›ïå^v®m8ˆy7þéR¦¦tm*u„Öðì ·óÉö(¿æQî:9u—� ìšyÜsù�ÌÚÆØ_=ÀÙÉûØZ€…ÿ¾’k?ªßy,Ë^¸Ž_¾FÄÑÜñÖ�LøæA.þÛ·XƒÏç™Çÿ�A»^Ãî½ìoÌesáã�qñ Æ‚@þ³ÌüÇxs/ã¥[rxÿ/å™Å|?†“�;í0.¿ýfδ[Ì naöçÎÿæQæov� ‰¹gpí.bzš�÷ÔÕ\ýAMSù×òÒ.ã%Lœw//ýfÖ‚'¸doƒù7óéwrÏù»î0ÜIŒ?}&7\<�ÍÂe‡ŽKDZôÊì""âRºdÛ¶mÓP]Ωã2›Î?Üæ¨q¼øùÎ?z šìŠˆˆô:aÙ íï`öúj>ñUNõSFEµ²M–c “'¦òäºRòóÖœ:ºÙñ+.¥Þpæ °|Ñ2N™JÄÎ×-ŠçSb™ÄŽŸÌH`mæõ[oäáu¸2¦ð‹'0a`Ýl�}ÜÅüxl$†3ƒa8ÃéÂi€]»ŽWn{�OýGpÉõS–즡$�·ž}�9¥ßòÀ]o0éÁ“µ#èÚ•|}÷ÕüáݬøQœ~îI–•ë˜ýú+¼—ÿ7]ã㮇¯àÐh'ƒNšÉ Ùóxá±OØDÇ\x“cDÊÀö:d”]Áçw]ÍÍ–aG áGœÇ1¹ÄQCAþ'<ÿ‡,|í6~[û'ž¼öp⌗ˆìÕòMÛ�Ëê¢­Ûøj·3}ì˜N¯ÝaZn?^ùrc›ú¦*�ŠˆˆtGgü|oýås¶-~ŠKþ Ó�ý!Ó§L`ÂÈL=ûzbw2lÒxâÿó.[óó(´F“½cñÐF,®ÀøCŽ�üŒ÷–,fe`*v$0»’Å‹72™pèh<@hÕ»¼º¸Ë‘ÃOoý— ù>®�Ÿ4™�� ¸jVŸ½ñ%—y*É;‹fb¡âùä�ýOÜu.;Ç\:d ÓFErÑ/³nåyé»3¸é°ðN<�»3H8ò2®;i)¿÷kxx6“ošN‚õùÏr÷Û%Ø1“¹âÚÓÈÜow&“´qÇqjnUï>ç›M’Çé;kšmjÚ[LÓhpøˆS8e„¬*æÍ]E°}'ªõŒûõï8³¿Iù§óà7UXÞå<}Ï›l´â™vùï8¥—!ÛHãä_œÒ,´5 9ŽQa„¶²yËŽ“`éÇŸS‚ˆI§qfή+‘ã8çü³9ý´S94ÉO Ý¥ò³ø“/(± ÜcOgƘˆÝÆQ1ˆžp&§ qb‡Šùü‹µìþÖlÛq‰È¾ø|~®®ëx úIŠvCc—ÒNÿJ‰ Û{kŒ½P ©ˆˆH· gЉWóäô3ÿ³�ùä«yÌË[Mi]-Å+æR¼b.ï¾ü(a)¹œü—ð«“G»#O…çrè¨0>™·’E˼œ65°©É[Äê ›ÉãF3*lÿùŠEùåX9ɘ@`Õ"òêÀ•;™I±�qÃO sP™Í‹f[„‚A‚¡>3 · >¾>H7\Ã?º…~�f2ÆÄc.)£rS•ö8’Z=Rd€ïîû?N~dß+áS¹éÙ+9¬) Q¹ô÷g2ÿš×xÿþ‡pÄ^Ù"ù‡Wðûc’{ͧïFØÆ máAÓMt¸>/¾ý7­2–¯*ÇÂÁ€aCÙ³e·Iæ±—rý±,”UÊŠUUX˜ô=’„–N–™Îȱ˜«Ê)Y³Žj{8ñÍÊÓ¦ã‘}²BALG'G´�Ígm¬`€˜(w—Õ�ÆD¹¡©v´q×û¯%U éfD“Oþ“OþX^¶¬_Æ’ü¥,\8�¯¾[IYY¯ÿów,Úð¹üb Àˆá�ÉCpÎ[F~Þº¦~¤^ò,ÃïÌøÑ‘D¸réúŒe‹–ÒpúQDbã¢|¶Y†NžÈ.ã 5lfλoòöW‹X¾¡˜mÕ>Ö®){ sFt2©ž–2Lâb1)ꭢƦ �ÔÆ_WIEݾ—2|µìžo"ÇžÏMç-â7ÏÈ#ÿ1p¤ŸÈuWL%±Çæ�Ù“á‰"ªÅ'/sG××?²Ê)+oœ~&.!¶ë¦Á •³µi?I)I{¹Þ’0)Ǫ(g»Í®�´-Ç%"ûd:œ]Jwlß颪ÆGr\×t§¨ªñµyºR‘žfzH<‘ÔÁ9æÌ_puå ^¿û¯Ü÷Åf6¾ù /ÿ—s&©'’åX†üüÆ~¤ÖZæç×bôËe\ЉaŒaì@ó—æ±Ì“�ÛX¼¸Ë‘Á¡‡dì vÕî»úf^^ã…°$†�;œÉý‰ñ¸q:�¥sxùÃUx÷Væ°ÆÔ–8]��v D MIÄÍa¿�;Ž‹ÞçR&Î=*äæX޾î=*Z¸N­ŠªfcÇôÛ¹ŸM-•ß¿’yùõ؆‹á¹#ºášŠ¼Î=²? •e]°e ðDÆòi^ ¶e7Öšvâ—mÙ|žWÂ�§lü¯µ£ @*""ÒM"8üœÓÈqC`ý+ÜpË‹ÌÛâoqI_é\ž¸õ¾ªµ1§qêaÑ»4£ŒÈ�D®Ç¢té,>^âÃ0–qͪ"̈́ьíoâ]ú9¯ç•`yÆ0e\³a&“–bAV篠¾ù΃e|õÀí¼V�DŒ ¶¯Ší-Ô„vŸ>÷*+vYÙ¦òÛטµ>ˆáÌdúÔÌ.а·ÅÝÿú%$sâ—pxŒ„1ògWñãõùÏpÛËkØOþoWÿL2`UÍç³¼º]_°äîya–£³Ú³:|܉Œö„6¼Éƒ³ v9†`É'<ý^!ÜŒ>l"qM»5œª`[Ekªk =ádF{ ‚ëßâ‘ÿmÞmªk_š÷¶XÛÊÙÿ IDAT˜Ñ‡rÚÑ©zxéB'OHÄåoMylÝÀå‰$ÒãâÃ…E�>ëËó‹ˆ wñ³i­£ >¤"""Ý&løÏøëUE\}÷}û¿ýîeú Áð�©Ä„›„ª(+\ÃÒU%Ô†ÀŒÃü Gî68�3Ž)Ã\|“?‡¹6$ý`,YŽf 82.7ÞšÇìJWî$&Å4Û†™ÎQÇ�å©å (™u—{O嘡Qø¶­gá—_°È?…?Þ1‰gÞÉì†E¼òð±&�àð飨ÑËÌ8Œ#�טyÉ*N:nƒL¶¯û†wß›O©í¤ß rNNóBukÝ{n…”ã.ãòÛ�FëÉù¿;“ÙW¾Âòçîâ™Cîå’ÄÃÌúÇ{™µËJ™õ§+Ø~üTF&¹hز‚/?YHØiçsü‡�1«ÜÆî„¦»æ€Ó¸æÂ¹Ì|x!sﻌ_|3�#F$áØ¾–¯?›ÃúˆÿK®8éû�hÄ $3ÞdÞ–RÞüÇŸ¨;$b'séÏeo=Ò̧rí…ßò›‡ñÕ]3¹xÁ‰üpL:QÁ Ö-ø”÷æPïHåèßþšãÔ�T¤«]xÒ(}o%ý†&vê˜a†a€ÃMzzîsÇMÈè¼�÷¿¹”#G¥6Ž @*""Ò¹É<éfž1�W_z‹ÿ}»Œ‚ßQ¼¢Ù"†IDòP¦u?9ïDÆ&¶ð§ÚLæ�C²p,^MЈ$wü0\»,àb䨑„¿õ%u–“Á‡NܭߟIÆ©×ñ—-ãŽÿ,fÙϲì0ÌpÒÆŸÆ_¯ý%ÓÒ‚¤Íø€¥Ï,aõ»ó÷ÅçðÐÔQ ßYΜûç³|ïÝ<ûÔÔ5Mc¸“Ö¯¹áW‡Û¥ÙÅ¢ôÃ{¹û‹rH:†«~säÎZÂÂGÿ×�9‡™¯®åù;žfò#—2®#íMÍ�œwãu”ýíÞ\º�/þ»�/00ÃÓ™2ãvnžáá¥/ °ý�4鍊!çþ…G’žå¾'ßeÞwïñÂ<3<�CÎ>Ÿ«.<†œæ]€]c˜qÉ™{çÇlü†77„MÈ䂟±×@ n�{�6ígî'/±â㦗 7‰Ã�åü‹/fÆÄ½M #"�éw?Êâ…OWS½­€˜ä��³QÃh¬Æ4`C]4a~‹?_ÏŒé9�²ùç?[‡7hqå)9;›ë¶6”IüÃÆhü³à¾_ísáù ™0ej‡ ,""Ò—,œ3›¹:Ãv€Ú­%”TÔPï³0¢ˆOI§_‚‡.®[ÜÉjØÊ¦�eÔXnâú d@|Ø.ȇ*©ô…ŽÓÿì¿râÍŸÐ�q�?û+F9À_µ™MEx�Q¤HJø�[,ê¶R°¥†€+†ŒÌþ$zºú˜ƒÔ”Q\^G0,žþÓ‰ÛÛ¼;@¨®Œ‚Ò:ˆˆ'=5ŽÖ/Hmi!…[kñ›ú #Þ£ *ÒÍm¨åìÛ>!1s áÑ �³Q»±q­mY$˜ålZ¿’×þp4C2b:´ÙÕÅÕœ{û§Ü2c'OÎÆápì7�¼ü!vdPÕ�ŠˆˆôÃETÊ@†¤ô\Ìðd²G$ïõuGx‰{©U´›*ݱýÛ¯ J×[™D&g²�ÓÖœD§e1<­uK;"SÈÔ¾ýD¥e3¢•û‘®1>;ŠÛ.˜Â�ÿþ–ä¬1x¢;¾Ñfµ¤å�hr‡æpþ?góÜï§‘�Õ®M®/©å—ÿœÍ9Gdr츌6׎‚5éuf‘Ê_/<Œò‚¥To- •cgï—a˜N7kkc”ÕŸóþö‹×·}¥EkË™qÇgœ01�ßœ˜EXX¦Ùöx©@*"""""Ò Í8"•×nü!Ví6¯œ‹·ºƒ£ï�ó*›8Ü‘¬­‰að l.¼ûny~!ÕõûŸ'«º>ÀÍÏ.äâû¾æâr˜yR6‘‘‘˜¦ÙæÚQP“]‘^k|vy÷ËÝïlä±w–Q^d—JDT·§Ûƒa¶aä�¦¦»†iâpGQXç$6-‡µ¥µñ»wøAn'2€!1¤%6‡VZ^Ϫ¢*>XPÄù¥9*•ç¯K¿”xÂÃÃ[ÕotoHEDD¤Õ\.ⱟ‡åŒg€ž"DDºÍU§dqÕ)Y|�WÁK_²lÃFªë½x½^,+ÔŽ-ÚM­€m°B¬ 6`[Þúª†Yßn£©1­aà0 b#Ã8:7™—®Kjb ÑQQ8�Îv׌î ?%"""ÒjFd*ƒ¥öt1DDZ'ŒMà„±�3ò®mÛ;¿,Ë" ÑÐЀ×ë%`Y�“*›¦‰ËåÂãñì¬mDÛFA�TDDDDDä ´#LÚ¶�a˜¦‰Óé$*ªqÔ]»i8õ�³yíhÝA�TDDDDDä ÖιõsýÎå‘§.ft/I‚½¤"""Ò–eQº¥„-[·àø ¸œ.Üaa¤$¦�–šŽiªGŽˆô~=�Gíʯ¸óò{™Làô¿?Ïï'ºö¹|hÓÛÜxÙ‹l4F0ó©{˜‘Ñ·~×Ú'NÓÄr:1�ž?ÿ;(�Šˆˆô¡PˆEKÍàAC s‡áp8ðù}ÔÕÕ²eK %e›7z‡£§‹+"²=‰ ³i@Ó´÷_ä±ÕÄ4Z±|/ãžöGf}+X|^?½eŒcR‘>bCÁã“”3„í••øý>\N'.‡ƒØè¢"¢ØP°ž ëœ=¤§‹+"²o=�çìݾß_yv½§ËßVA/ Áž.ÄžHEDDúˆŠíåäŽB°êU"]ƒ�9‡ÃIJl¬†ÅÀ<ú§Œeõƺž.ªˆÈAî-aõæˆHepÿX¶—Ò‹Y´®„ZËC\úÆ�LÒn}N­êͬ)­…ˆõ�ìbãÒ|–nÇçˆ"-{4ㆥ¾×–Á ekY²b#›+ê 8<Ä¥d2*wý"ö\iG9mWYYIxšºÌÚ5›Y]R»³üÁ-ËøzÁZªÂ‡ñƒ '~?]k;J�TDD¤�D¸ËKø)„6c—b[1˜4àðÄ€ób¬çðùÓzº¨""ûewB£]\Œõþ„¾›O`Ù2,ËÂ:sÒ!¸O> GVÖ>÷oïòý¾ËcïV¥ºãÿýKŸç·7}„w̯yþ¦,>¸ýï<—WApçâîÔC¹ì¶9+çûTê_ð¿¾í+B#/âßWÇñ­ðQ�÷û½âFœÆõ¼˜#“w ˜vÕR^ü×=<óMõVór˜ý9ê‚k¹îô¡D4 “þEOòë[¿ Ðï~ò"F5%Aþ3\vËgsÃÓÕò×ëžcy½�™z:YS‡×ʼnQ�TDD¤� ckE€”Ðs¸"§c„�Ãm³`¬z„*ßDÂ=þž.ªˆH—³^} û±Ç¥§b''â<íD°m¬Í%?ÿ”ú''ü²™D\x]WÍg¸ÂpÐP¿�×îx‰Ï‚SùõMG0"ÅMýæE¼ñÔË|S:—‡þõ&‡Üw.™MÙÒð¸1 Våñè_–°:ñ$®ºðPÇ›l_÷ ¯=7‹¼åoð§[ãxôžó´#¹Y›y㯷ðè‚:\ý炟�Ä!Y ¸}ÛXýõyò¿y|òПp&?ÄMGƱóÈw xg8h~6Œ0a|E¼ùÄGlˆËqÇå1œ„n·I�TDD¤�HNJeKy-nÏÑlXô‡Œ‹Ãtå`[­%eàeTTÖ’”ÛÓEÙ¿T�zgÎıiÖ¸1PU�µvö¼…Ø€‡35çô©4<û, ~DâË/íJÛÚ‡t÷uw,o€ „Ö}ȇ/çÉûÏ`€²mÈ�Àä´Zλê JÖÎcî–³ÉLkJyvã J¡âùä�»Œgî>›þ„°m0ÆNbÚ¨H~ù›X»ê ^ýî4n˜â ´êþ»¸Ë1ˆÿ»íÏ\” –ec3”Ñ&‘é?ŸËßÜÂço}Å¥‡�BrK¡r—ò;qVÑg|’q={1£Ãml;DÐÄêâ¾²}k¬b‘ƒXZjþ€�†† >Çñ,\3Ÿ=…+ÇPRs¾`õõõ¤¥ªÉ®ˆô~v;ÿó¿ø"ÖÚ5„ö'”·#hyÝõĽ÷ñï½GÔõ7`Ø&¡¼%xF #T°‘êÇoaKm-ÍÞ–mú©‘Æ)¿<‘ô�0@0$ðb ÍeT˜¡2JÊB{nÏLà‡?=‰ô —@0@0 ð “øÑH'XU|7�¦µŒœsù×Ó�óĽ7sFÿþ@ã¾B¡ŸÁˆI£7l…Z-——c0l Àª7˜ôóóâhÀëóâóíq¬­?K­¥@*""ÒG¸\nÒSÒ¨¨,'33‹�›61{Þ2 ‹6l8[·m%)1·«�ÍÖ."ÒJVa! w߃™š‚±r5ágžEô /vì±8ÓÓq¦§vì±Ä>ÿ<á?ù)öò•„çdSý�; nÜØ¥e3†1:‡¦S‰$:Â|ø{6Ã5œ ÃÌ=׳ã2$‹ÊÂb*›V5ÜQ¤ed1rT?bv.k øñù¨·Ý„€ß�¿-ùÐ9Œ #]ØÝáHïŸDL¸§Ó‰Qú /¼¿o‹a8]=HEDDú˜e+–‘‘Ñ�±cƳfÝ*J·”P[[ÇÒeK>dxOOD¤UÚÓßЗŸGdæ@¨¨Ä5 Û¶¹æw¿ç¶¿þ™‚ÂB222øÍ¥3±msôh¨­Ã‘‘Ž7?×}z^[ëÃL?ž[ï¿–ãÓMƒÙ`C`þVþûAc Ýuj›Ý˱çÏÛ× ´cÔ‡TDD¤�‰ŽŠfÞÜ飼«Ã¶lü~?«W­&&*fÿ+‹ˆôa¡�…²Y¶maY`c:¾�5¦a6ÖŽel;Üsca L1Àö³fÕFZX¢™ ëó—Sm�™’EfdçM#cWo¡ÌÛR Q±uŽÄ$M TÀ¼…eX8sîùü ÞOCC>Ÿ¿Ï‡ßïe[ñfêº;Uv€©ˆˆH³iÓ&rÇŽ!22Ã4p»Ýdfdã¦�=]4‘Ö³Ûþå5Š`U¸]ò—`Y¶ÛE ªÏèÑ»nÏÌfêái˜Xô&_VØ{ݯUö%Ï¿_H¦Mc˜ÙìõÖÓÞ–ìàJ.óî¹N¨˜å+j°0É’�Ç,/õu6`�Úm�@ÿ{Iã`Fû*GkÊÖÞ¯6R écŽ8ìV,_Ž÷ßÍ{ï½Ç‹(.ÞÌ‘‡ÙÓEiƒ¶§÷”)økj±#Âixêi¬P‡ÓIvv6×ýþz®ýýõ 2„Ȉp,+DÿŸÄˆŒ PSKÄÔ#wÛžÉÈsÎgZ‚‰U1›»ny”Ï ê°vMxl_õûÃýÌÞnc¦ÍoÎ„ÙæD··×Á°«øìÅ×YÙÐüç•sßàíõA gÓ�ì�� fé©&dUÞršo+XÆ7�ÜÉk’‰5ÁöVRéµZQÎŽ]“Ž&Rõ!écFŽEVæ .™9“µëÖ3xP�=ðžž.šˆH«µ£2�ˆ3NgëÝwãNIÆX¶”úûà·3/ße ¡ß_}-`Sÿð#-ÂNLÄ[]MÚŒ{Ư¸pãm%Týá¯|‹?]ò!)ƒ†2(-Ž0«ž­…«YSX…Ï6p&Êw\ÅQ¡fj)ÒíëXíÝþ53Ž`šù:WÎ\Å GO$;Á¤jý\Þÿ`!¥¶“~']ÌYhxÉLeúñãyrÙw”¼ýw®j8‰£Gâ/ßÈ¢¯¾"/p8·Þ9™~}_6,æµ'Þ$8q8SŽAÔneؽû*WR éƒ""<<ÿä=] ‘ökOóÎ�I½ñF¶Ýý/br²ñ>ý4�yóð\t!Ž1c-]JÓOÌ[Œ3=�š I¹î:ÌÌ̦>§ÍË$lèÏxà™ñ¼õÌ ¼öÉB6®ÉcËš¦× “°Ä¡uÜÙüò'Ç2ÄãÅÚ­à-U€¶æõÿý9ç¯ç2äî»xê¹G©kš¾Åp'3᜙Ütñ"¬àÎÅSOºžÛËnçöW²üÃYþ!f8iÎäŽÎgJ¬—ÔŸŽeéSy¬~ÿ þ™w÷6‚¡»—©¥DÚÎf·a$]ðÃ@Á}¿ÚçÂ+ò2aÊÔî(—ˆˆH¯±pÎlFäNèébˆˆôi¶Ý8ÐP(bÝÊ¥ä Ñ®í¸]nŠN;�ÀªUDd Äðù°«ª±ëê±#23&Ëí¦¾ Wv6Þ{0°÷�šN\î0\Ž •%E”TÔ0=Ä$¦Ó?%3ä'àó³{ÀNd„ÃöÓPÓ@hÏ‹ŠÄeÚë«ñ6�žäŸó/NÿÓ'4dœË#�_ȘÈp¨+acQ9^g4©’äòáóØ5F›8ÃÂq·³iS)5Vñý2é~¯— eà‹Äª¦ÒF\Œƒ@�—�+‚¨pX>j½ß—s¿åo›õ«W0høh¦ib´0GÎÀËbGU ©ˆˆˆˆˆôþ€ŸÌwß¡âÁ‡(ýóŸ‰HIÆŒŠÄ™‘Ž+«ðo¯Ä[^AÊuבxÕ•44Ôï{£V�€7Hƒ°¸4râGêµm ]í¾× 6PWݰ¯ðÕVáÛǶÄßPŽúgÇa`cYµ4´8™¨EÐWGÐð�–™C:6¶å£¾þû*Ï�¯–�á ÜÄ[×ÄõÔ¶”É÷[þ®¥@*"""""Ý®#-CëꉹôWÄþèGT<ó µ_~IÝÂ<>²='»÷8�Ž¥W9î'½7ºŽÎ­ˆˆˆàÚþ|Ó—ŸŸý•lZ½šµEel¯€3œØä~ :ŒìÄ0:{xÿ·÷qέŸèw.�À�oùo—ËA¬7ÞOv-›×–PeÛ˜) ê·Ï_×{C÷�ˆˆˆHg:(ú�†¶/ç�çŸáÅÿ-¦¸ÞÚã ÓC꘣9çg?㬉ɸ:i¿¶Ã‰Ó4±œNLc×sgÕo£¸Ü".=…è6]›úõŸðïGžcÖÂê­=¯ˆa†‘2úx.ºü"NÞ)AÛ6�Û1L úæû 7ê�çѿ쮼ò?Y`ÆÅ­ÏÝÀÑÑ{õ¥÷†î;‘Þåo²kS³üþxË3|WÂ6<¤ Ï¡ã†Ð/>Ó[M醥̛¿ŒÍyïñÀ’/ùøìë¹ã’É$uB5‡{Ú™ýõ­`ðyý|?žjˆu¯þ� _Šdæ3wqnZëwæ]ù<¿ûýó,©³ ϘÀiÇÎØìtb=ÁÚmlZõð5kògñ·ßm¢úžÛùqvgDl{/ßKÇô¶sYÏwï}ÊfÛET”ƒºš9¼óÅ6~pJÒ>jþúÊ{C÷�ˆˆˆHos@7Ù ½Ã-7>ͼ*wÿ£˜yÓ•œ›�#daÛ€†á€Úµ¼ýàmÜõÎ:V¼v×{þÁ¿ާ£zi¶ðs»šU+‹±Þø�ßÚsjmá�Ç_eiÄNºœÇÿ~Ù® –e7��qìiœÿÓoùûå7ñú¦|ž|ô#ŽúëI¤v4`ïþ\܇Þ½Z/;�vÅ×Ìš½Ûs(]Γ÷|ÎÂ÷?¡ðÄóÈÜÛ{¨¯¼7t߉ˆˆˆô:n�$«Œw|’yU6fúqü{÷]U•/pü{ι÷æÞôJB@„" ‚0t댎OÇîØgtqŠóÄ™alÏþlË2¢Ž>TA¤I ½H%$¹åÔ÷GH%$$à÷Y+kéÍÙûìs²¬½ïnÿxùÏ �10A¬š×z:pñ„hë½�û?ÙÁ¦)/óÑ�ç¹!]+Ïêp[”â„%�ž–@X­{•°oÛ~;a$¥¥‘Xq�SºŸìœw<�:%âUÊngOÁ–f›8N€Û³ÙX¬ß�ôDï±§ù…6±zSG�᢫ÇÑÁ  ë5/2 ²÷Ü=žM“÷�Ò^å�ɵ fñnÖ­Ëfw^ A%Œ˜¤ôÈêNZLSFvl¹[Y·q'9…~ ÍKl›4zöêF»ðcµÊ—Î)É!{)„'sVj æÁlœÜIDATõ,Y¹•b_7†íN\s/>£Øìûz6Ëý~Á0F�Œ$û�EÌÊžËìÍWqg�ãüçÂ,fǺÕlØ]H@‹¢M§žœ›™Â±ªAcêbããQâîDÓIÜ !„¢¥4a iË}E?ýóé|>sF�¿SU·Û�×ëÃå*/¶mYè†ÎÈá#Éøj×[ÛgóñÊ25–wÝÍà¨F­žhÇÂÐ=ô¹í>Æ/þ#S÷oá³é«¹úþ¾„áPºô5î|r)öY7ðÖ«×Ñ¥f{-°Œ÷‹­tn~íení\Þ‘ÕW½Í]�-Âh÷+^}û6zºtÖNžÀC_–T¼Å-|øÈïø•Ô«Ÿåý;zûâXXVùЮc›Xõ­vu,ÂüŽÉƒUËÄÐ�*Ó…=‡o?ÇKÓב«Wÿ{*žιô.¾u0©ž*YV;F-pŠâƒgŸgòw{k¬­SPÃSv˾<ƒð�Ö¦¤Ó×NæžG`öº›wn+eÒÃï±Áï &_N§Á݈=žbiÎx2{Ù<0݆‹Û—Úø Ì­Ìš½‘�É�Q‰öº=8ž9ŸïcΜUÜØãÜ:g T>�¢*è»gñèc¯1oðè“)*Ñ]/fÂÄ»š¬UOÜèºØ”x´$îN0ÝéwB!„h=ZU3âó™3¸lüìܹ“²²2ü~?Á`]×QU•gŸý4Í…ª–·@Ç¡´´”¿<òçR›ÝË~`�jÒ.èÃnð¼;ËÝ“ñ#;0íÝ]ä/[Ê£/}Ü TÜE«{�¢V|® VmüUIWþ±‹³.½ŸGº.ã½W粓TFýö:ÄjD¤§6¼;§7�Œßl+fÑŸ0¾û¯ÉŒ¬{h±Buý¢ˆEÏ=ÌÄyy8Q\vû1ºOb9Ì®Us™üÞVM}‚Êܼñà@bù°sølÒ£¼¾² wêùÜrý8Îí�'”Oö’©¼=u ó_™ˆ+é¹0öèHTÓ)a^Â0B{™öæDÚ€�>´vsv[¨qƒ¹¸¿8gÌpÚϜ¾EsYrk?†G£B˜›™üØgl�ɽ7¢[‚›âßññ{Ÿ³&{&ÿü{^¸†.•ÿê4±.6>%î$î„BÑZµº5¤áááx½^,˶ËÇ4MÃår¡ª.—M«˜JkÛDFFâó…×(Wˆ[÷b¡àÉÈ¢›â_¹ètvÑê.ŠŠv°­À¦O²Rs˜¢v^dzÎË•¤Ì¡Œms˜Y¯Ïe'ñd]4’‹SÊGT¬:vî¬FéÄ7 cú£óÉ[3™{nþž!Ç1ø¼>ôÉìHBXÃ-ÃÐÚ)¼òU.¶–ÎõO¾À½™nlÛÆA!½ë9 Èã¦>cÏÜ·˜2þ\îȨ£ŠTyFkó¦®.ÅÖºpÃ?ÿÎm锯­#ƒ¬¾ýIÓoâ¾iY8}1wº„$õÄÒ¡¸Ð{ïæ·¿ŠWÞ½�,ŸƒãX˜ºIC¯°Õi¦òú‹V`øwÒmô,Ö͉¿páqç6¢%,ùby¶JÊð1œã)�-c$cÒ?á�í˘¹(Ÿa—$ÕÛ�³rV±¾Ï½L~ö*:(¶JŸþ éÁÍwÿ‡­ÙŸññŠËøÓ€òqÖ&×ÅFÇ£Ä�Ä�B!Z«V5e 22’ÈÈHEAUUt]Çív“¿h!ëÿò( ƒÞy‡è¬ž(Š‚¦©ÕËe"¿ÈÄA!69�rü¥VâÛ�¤B‘UH~¡…“¬UIëÔš6WÛÑ+ª¦«|sŽe`[G¯°-Ã8þ!†˜ÁäÿâcâK³ØT¸™ùofþÇ ¸#Ié҃޽Ρÿ€ ÌJ%J«™ZgÍ‚oØo+xú]É5 ºaýµeâɺœñ3xyÓ>¾Y¼�[32Ðêy¥óÕ<ûΊŠÝ´K5Ыfg)ôèßßôöìf�íÙ½¸©éÅAl¿Bÿß\CW-@0tܯ¯Õi®xÊÝú<íϾÍGêÙw’»õ:ö÷¸ÓÛy‹ø|i)¶Ö‰±£3Мʒ¥2jl&“_þ‰Õ³¿f׸«éT£ºy5žá×�%Å rd‰¥e@—qŒÏœÂsk‹Y¾"cÀÙ¸š\�&Å£Ä݉¥;ÝâN!„­G«›l¥ª*�ŸÏGxx8>ŸŸÏGD ÀŠë¯gÀ…ýúè|ÃoŽ‘‹]±æ \nµqM~·«b…˜�^ßšÓŸ‘c*¤Žx�ÉS?à•¿Ü•fÒ.R£”œMË™ýÑüýÁÛ¹âú <óÅfŠ«.b³²9»•YDÕ1�Ùqéž‹ŠÅþ­;8ÜÐà‘'’¶í;‘Ù³ÑG2±± �P(€ßñ¦ºNÕesMMw„«}3Ý48û `öâÏ_B\ÊxEŸßþrJsbög6»æÍauÜÝÇ0*­úoÛC?/[ç2{“Qw€âêNß®jõu“N,]»Æ£bS´g/Å-R[’Ä]‰;!„B4³V7eWUUTUEÓ44MÃívc[mgÌ × 8´��^j⎎;’F¡æ´Zá¾òÕOþ²@£OŽ?€ß/á^¥öó64E°êÿ×7µ°¡ôÇ.!¶$¤ÄÑ{Ôoè;î&4E'wÛO¬]³–•+–òͲ�Ì[Ë´ç'°fÇ£¼tw_bÀ,"¿À\$&Æ¡Ôy_…ø¸xTò±‹Š8dC\ͯ-ª½»lËfÏà‹ïÖ°qg‡C5æð©Í–®¢”Þx¼µ??åœ@ùC¥Ùäo}‘Ãû¦“Ö÷÷8æT§EÑéÔç¶ÎDLêå$t¹�°ÈŒú3Ò72kî6LÂ0ö"Rj–)ú|.ɲ¯s˜ûåjnêÑ_Ù(1mHt×ýL1±1¨Ä.9L‰ VKÔÅ*ŸÕõÿw'�®¢”§KÜ !„¢ÕhU›Spµ#�RUU‰Y¹’t=—ä³;SðÁ~Ö(¢ÔÜÂwùv”Yñq_v1½{—g¢FÒ®m*‡(ݳ�B»ïqŸÊÙK® Š»-í“ZÝòQŽ�e„° …èö=¹¨co†]~•læ“ÿy”çä°sÆë|4ònÏÐóÈNÃn—VïQš»¼Z8¦‰Ù@ÃÓ)^ÅËzŒ�¶!,‘î}/äüÔD¢}\.Ê�ïøÏìM›)]%Åån}•÷$±ô"løoJó¾$¾}º{·· F`)o;}= Ǖԛ¼±óû‹‰LMÛžÿ@óÄÕÊÏ¿rs÷Û€Íæ÷âº)5ÿè V©ŽƒMá7sYr󹌈©£öx<õí?‹ËSQ§ «¢N5]<)$îÎØ¸B!DËhukHáè(©ªª¸‹‹Iš7�³oI§è«ƒ¨ÉÃnéYíú¢�ŬýÃ\8^Å'geõÀ=ë{ôì,/¾˜‹�ë <�õ?þDÀ-=‹Ì¨:ŽZ¨ë Øv•iŠu­!­ü¼æß*¸†98¶�m›`ž4®xød¯›À´¼}ü¸æVF;T% _ŹˆÁ`›ð:Ç6�@ù‘Š×KXÅúÛºŸEgí/òñÖjÊh{i£Ûj›¤”oŠc¬Ècêœò®sÂéj:ŸŒÚزšòÙ_Ä™DÚ9¿BQ=ÏÇð»ñøÒ0Õò/iŒÐJlÛ!.õBÂãRÙ¿iÙ_ ó�¹x«ÌÉuŠX8û;ŠlÕþƒøë¹¯¦*˜¥Ë™ùM.ÃÆ·92ßÿÈ„B„œºžÈ!*Ÿê«xÃÊëT“ëâ‰Ä£Ä�Ä�B!Z›VùewÕÑQUÓ)�¿$cc î6a?^päZEU°2" ¡S•b\ÄyáKùÖÿ#Ÿ~¾�7žEgÔWc,bê¢BlÅCæð!tPÊóRp, «Ž–˜}ø‡j-œkn:…;6²vãV¥ ãÒ>ñõ/v, %Žö‰*ä9BgBªÉ´k«Á“ý9°ˆ«£XÜŸ‡�‚7¹-Ç$¶vóÃ�¹Ø¸8çê›§¨vä…CÁ¾Êj¾³¦¦dŽ˜ÇŽe¿e߯/‰MîDtÛóQÐ1ByØV°|GTw*ªFñ�Eäï\ŠæN"sÄÿáxÒp죕ÕÎYÀÌ•~5…k_zŸÏñÔsW‹ÍoÜÌoÞÞÁš9 Ø}ñ5µ77:|�ƒAÜ5»[…¹ùØ(¸IPšZOvÜVwme˾btGA‹ïÅ��<Æo³ÜUæ*‡0¦û‡lùé3&=Dáˆóé‘àÆŸ»‰% ×à½âVÆ~ù*Óòlûè;ª£)Y.ª�âU~8°ŸéÏN¢´O2D÷ãÖÿêOl½K]ÔÎ×òøC{¹ÿé¯Ù»ì\ù )]ºÑ­cQ^;XBîž-lØr�R ÔØÞÜöØ] ôqtjcÛqL¸ã{î~i%Kžÿw¯ÉО)D˜…ìXµˆ9?ì! µeÄw3,Ê9rà}�Ï¢&sÑè>¼½~9ûg<É�q ;+½`'«/f�q>�=}sîz‚o«ùøÍi˜ýº3ðÂMNUë­œÚN¤ü†i`˜žè�ø¢»S¼ÿ;|± ìû ot&žè�”••Ö{çâ¥_² ÀFñõcüE‰4¼20’!còò (\<—Å·œËÈXÇq°µãP†»¦qÿ½›ó‹~¤Ç«Þ¾ŒYs~ä€ã¢Ý¸Û¹ªGw½nb]lj�Åëö²mÝr¶UÞKõ›Ö�Ñ#.á×W ¥‹'H¨Ö—)üòo%wÒ |ºn'ßNÛÉ·(¨¾]÷�^­ñþB��îÔSŽ~®õä×wŒdé“sÙ½sŸïTë›Æ�6dz6m’‡?Â{=†òÑŸ1kÉ:vo^IÎæª/O%¼M7†ýâR®¿v4™á:zÕ…vt¸|o&¾ËóoÌàû³éëÊ´{Œá¶;ïàš,¦Qe!^=½ëäqâ_¹ÿâ_S~dÃÜØ0ÕGÛ¾WòÄŸob`L�äëzóÓ¿×�=ûMžYs/ êA¯&¦ëVo/ÿÕ å·L“”³gÕ=D'µ§´ ˜´>O`™5¿¤©ÂÎcÁì(±Ub�fpT=õ¶†ðþc–°ˆiù+˜µ(�á—¶Á 騍1=¸iÒ/éüÌS¼õÞë”UôªO}u/�ÜÞ—pÛº©s¸Ý.tÃÀ8TTëzÇq0-“P(Ô@Îå‡Ú�  Ý殞ÂÜ)ûØ5ófŽþ#XNk„Ê ”ðDÒ;'6¶YF ¢á*-¦V) ?¥õô lÃOHñ‘Ü6°�»Q àØzÀ@ÔˆxR#¨ØwÇ6”ê å€m  Fµ!=:¹"­N ¾-6M?¥‡ë|ÌP¦â¥mZgRppì~ÿщËV¨KÑð¹L‚eƉ¥3” ª3Mƒ}_düÁdŽœÖ@gÀÆðÓÐUµ8f­ºîeÕê¹(5šÔôXl»”@}[6¥.BÓâ‰;‰;!„B´6­j i—ô.üçƒ÷)(Ì`ñâoLcÛ6W\~e#ÊåàØÐíª¸`Γ|[ø=ÏN|ãÎ_rA×X(õ£ÆÄYÏ›ql«ŽQž&rìzFR“ʼn•¦ÙžÇ±±¬cäTçù”'�î4ќϦúºÒý_ øºb['kì¸ ý]ëLÒøºØ¤ú+qwÆÇ�B!Z�&¬!m¹fÊßù.·»ÑéôP�P°Þ!˜:9±ñ§¿nbÿÄilÝ2›'œ]þ ÷ÙüþíI\q̃…h&ÍO¶iâŠìwìµ£B!„B´"­jÊnÀ_vònf›Dö½—¿;„Ù_,äÇíùøñÛ®gGËz&qj’ΨB!„8•W‡ôtÝpÂ1ØÑ=¸øÆÞ\¦–?£cÇØ”Dœéš#N×x¢±$„BѨRUÓ°, U=}¦³:ÖÑ�J„¨‹mÛ-RçOÇx¢!-OB!„8…Tì°‹cóô½Z¼Þp‚'sZ­­@0P†×ÑìùJ<‰3QKÅ“B!NM vH+§T)ŠBt\“Wþ«öZ§eT˜lç:ŽH)1 £¸ Qr ›î`éCEº §YÔpCÇP‰ëßpú, Ïu0­D±|xŽ|_èw19ãˆëO´¦•(öª_çr‡(;ŸÃPjÐõbª† Ò%±ñ! 󦂨Б µÑ݃¬« Dú QK¤ÂèëA66„Cðw% AaÑT’+Â>á¢b‹]Ñî%�F£Ñh†�”•}x;=^-ßP‰Šøh�†a "sîâtÏpûP©ÍC)[ÖÀ³åý37”<"㈩°äcدhÿ†7î~Ý:÷’ø™–ÂsQ¦…Ñ»Ù03¾†È|G\‡ôŠõ¹¼Q»)ÌŸ[šAáû`+_\§ÖnÀÜ_ƒ¬ÛFþ¤y�L Ôèe®'²©£°Îo^Jš#î%NýØŠƒÕh4�F£‰Rp$)Ãa4 aZ(Ï­¸�R-¯0­!Õ=àºÚóJËH)QRáH_…®Ú8âÒk3<6”r´ð;öüÄõúÅmÂP¸‡0å¹XH<3YñšxeFùjý,½Ú5÷¯‡G²lqT·t{.JôQÕéÚuIìØCj§Maþe8õ­$Ÿ¹£¯Y__w_³½�ÂI—bôµSsÿßp¦8Ó'‚U‚0 p;‘VÃÉ£Ìd‰{IÓÊ;*÷Q£Ñ<‡1hUϘ$ <ÚÛ{9¨_|i4š!P�‚¨R EVùÖ-ä1ËôI¥¼åÛ¸üžëzwG÷Ë©T”j¸è8Baè¹.V™p¬´_©ÝjåÊÇ2Ôþ'¼Ûtqå] (?�•tcL»åéaùp;¶˜ãá6©\ÆŒ£œA'RŠp"å`ŽÛÁ¡š'W!›Î&wú)n!]¼ég“Z÷gr§Ì.‰0â»�@zÝvÜ©¯@  ]‡}òåX;—“xdÙ³Ëãm«Ý/(Ã%KÝKôâ8ÍQÅJe˜Ô\Kkm‚Œ!p›ÎÞ,;;²ôÍ?GQËë/ ßœk€lç_û_Û52¯y5Ís—‚¤„"ïJ¬!¸¨FÃÜÅ‘W&µ Q"ÔBÊ?—×W­îþ:Ì|ÒîQ7`‘ºÜB¾B=#{“>Ôú Ê$iHl;[yU0-«d,)+›ÛL–Œ=*œÃ­…IJ ¶… cë�»žÏÃFdq 20ˆƒ]JY’gì(Ì‚Âpóý1´3�ÀÌöN¼Öæ’üFG'žˆl]ÒŽ�gL3e³*öM) ·À¨·Óe"Þª®ÑhFŽTÓx.]:Ÿ7,žÌiãkHǼSn�­Ûvò÷ÇVó³‡v°uh“Ç�p#w%…�.ââ¹j4šç7®ëa )Û@¤ë`“ñÒÂÃs}Afçz1éb¾0Ô_˜·Rƒá×áRI r4\Ü8âꎊǡ´�W&I/�a%†Ü×Ca(ãPžƒ(Ó¥áDF€t*E�!IšaÁû"åì\øÁgÏuiB¤$M�í)° ®¬Ø^4-<‡ÒuI¸Yœ˜qD©l‹/žÇ·DWÌ(p&O"ñðÃxãçcÈœo…¼™g“Zþk²ç5õOÄ”Šôòí¸ ÞZo[HÑþ΢Å~ÅJ•YÈ‹Cöÿ!m¢î%ÍOÝRmH�fØ$8áìóøÙëç27=xNa¥˜>s&WÏœÉ[—®ãã×ÝË�{oƾF£ÑŒ49鯒<'�8„U³�¢ø”e“='�™Hãræ@¹æEl\ƒµ—R6n4F·xÒ!Y¡ž¸öâŽÇQkÁ複yOÒËÀ: +�çøÆP3‘ªX_éx]”�/�5^r=l £T†iáäEÃE\cHÆeµ– a(:m0=‡ƒ2E¾P(Ö!Ì2Iš“P¨û>öõ(�(†_h{®‹•Ê?Gë*îWñ¶¨.º‡ê®aäL%³únì…à ¨1g’ܼ{æ [·£F�RÔaÞäš“]25Xp'°t‡Â»Ü¥\€áPÂÐ.%ÍQA0ñôó¹ùò™Œ3å±wóFnxd+˶·³£«@Ÿ'Hg2L;š³ÍáŠ3&2)µãçòÝk<:¾~/wõëqh4M)žëà¹É! né¹E!-]§ôs8Ͼˆ7D1ÚˆŠD¹Ë„B_)/v~.ŠY·_D–�¥»BID`ðìo/">#Q锸fPƒ†”ɘ4L¯÷û²7§Ø—Sôá‹Ô° ?þx°”zLaýžS@¥dÿy)[¥'¼©2q]vìkãáåk¸î¾E\ÿ¾³¹°Q�h�Ç—.^Ç}7ïa w¡F£Ñ{Baêr$«f(¢£Öê0ÄœaZÅã²Ì­ *°ãÚ‰ný¸•·Å:ƒÏžcƒ•Båúbë/ aÛ÷ëK¤ÒÃÀ´ûp™b>'ðwN¤ÒAŸû…·0 j-kٌϤ“òÓM%ñêµXîÃ^þðPNUKwUʾSùyS©}jö /÷ÝI {áËü.ÍÀyƳÓß*‰µãA²§M«ÒPðÔ.°#]PR»—h4G�ä´é¼¤Éÿtv.çS÷Äî2zw,çý˲wÍf´0˜~Æ|^ø×=Ü©U·F£9N�®‹”¾µÚ󜢠v"¾Â00Öt\Œçp±•p?.Ü‚,Ñýò<åÛ"e–îè8\¯t� "p¸˜˜R–ˆE+™,Šçr™LXŒ¯O3®Æ$(Æ–´IÖ“ìé Vg,›X~T’¼kÓBñ_žÏÀ‹µØ‡o\oà�…Žœ’sÝg%HK…pm\×ÀN$èÊ9ä=H›¾¸¶ó’¦¤ß§Æ¤á î”EoÞÁ5¡1“@º.yÇ#ç�éäév ÒÂôúX^¡â›‡(ƒ‹îð¢©A–ÅÔVé4N‹ƒÙ¶oôŒâÊ<ÂÉctïa k›QÉŒÌLb،ےEÕL¬Ð‘2ËwÙ½v/ÑhŽ<õ- 4·�¾�Ø<Ä9ŠmËç#7í&½¿�Õ»²±¢à6=mo<}:çÍheƨ4õع<»ö·ñøÚ-ÜôŸÍ<Õ}˜“#� ‹ÏáuK&qÚ¤&&էȘŠ|.ÇνxxåF~ûŸmƒôsëi–^x¯k Üýüü«X‘læu—œÎ•‹Ç25íòÌÝçMÿlG{Ãk4Ç•„xܱòôÁò–ç‰nM+�åå±ÃâòåƒDH qyz^xfŠ”ePhý¼«H[‚Só¤Eÿ=¹h ŽŒ‹hMs\9äq¸vÿÍ´üüåm�v'I—gb9Š|pÓL.Ëã›jKüÚÓ¦‡ô#ï9‡.Ï$ç(ä}�Þ€¶¢ŸÃm^Ï«:Žê–O•8Ýa¬„×?1F®só}x©vÜÑ£@€µ§£¯wÚRTM89HÄ­v)¥ÿ°¡µ{‰Fsäq=Y¼ dj¨P¨béö vpÇ¿:Ï“jáÍo¼�ÿ{F3õåîµƵŽâ”ù³y×%íÜ|ó=|tÙAâ_ªNrô,¾zÕR®˜”ˆig|k3§-œË»/ÚÆW~r?ÚbWœF>2u™Ì˜?�7Ï3ÁIóàíÛ˜Å+ùÁ’šàíªbfS´èÖhŽží¯ÿXW ËBºî�¶@IZ¥ò!C­·ÒÖs�¢È€�+¶1Ø8⎅i×CàaÚá¦È»¾o‰ðò Üsž‡D•Ô1XÝåí$E¹Mÿ8¢ç«Ú¸ ù<]†ä@Z�"I—D"A�ãßy)�Èø}w¤Wåõ �#½¶Çžž<]}r‘S;”ëŸÀ£º�{()‡øôQÌ_(�ÜoàÌ��ÑÛŽ¹ù²'ÏDÕOö'DàÌš†Èf©y켉/Á3“ÄÚµØÓò¨Ú¿žJ‘KŠ+UqÅLí^¢Ñyúö¶³MMcŽ€äÜÅ|ì„­|juŽÃÊg6rÅ•¯à[ k0x}mÜþÀîÚÔÁžÔ5�âôE'ðÖ“[•næõoz òO\ñP÷! Q‘žÈ®y1og €Þ}ÛøÃ#Ûxb_–niÒÒ:š Î<�—MH‘5•Ï¿÷EìùòÝÜÒ²tÄêrɇ¿6¢õÄSyÏ¢„,°}W'»A_Ÿ7Xü(�F3Ø¥®$¡¸ê¶Ò~\¾áÔÝ–EÊé#$¢n$Á~4jÈPú²iáQg�‘ö-Õ-IhªI“4}® a&H+›†TŠÖš~Wéyôš-먒ºÃÉ’Q§„b›¹ndv>‹•Héüå0èt;º ¸ždZSéJ +I9nðÐâ Èº’�½’=½�Ž@ºNÑw\IÏö÷+]�BÁ8ŽŸHkÐq©yl9ÂÈ \ð�p=¼‰ç€00·<@vÉô¢�.¡®–Ü3É<¼ 5ç䨓©yð~H˜ ŒË-PäÈ-] I«ä¸ð\í^¢ÑÜëøý¶E|nº…°šyç{_Çô=Ê·îÝÄcî0…¡`òYçòÅ@p;Öñîïü›ÛÛ£R~'w=ºŠßœq!yëL&5¼äµgñš•wrs÷ÐÛ™zÖi¼u¬/’ ÛŸàµß~„'JÜ>6pýkxÏ5¯åKóR ÓùÈ [¹ýöeV˜¬K©þI9¢†—-èÝ+yûuñ—ú¾¦Ñ D44\ÌDÀòÏÑ­çØ˜‰dIÙ0‚GyÙ0où¶<ï }5 <Û&/’¸žGTJ&ßÛp<žSÀL¤ŠûQëò€z…¡¤%i2¶6AmÒCSMš–¤ß7G:ØF’ú„I‹�,%èkHá)è³%ûúä<²E¡%šFgÉ1pÑëaš&®cc%’Å!ÂèO‹nú€ÝŽ$ïJ”�crKu–&ä=‹Îž,IËD “ºÀE¦3ï°7/ØÒY =k““®ccšfIT’JJB ê”�#ŽCžH)¤Ä°ÆáξÀï„a b¾,F!‡Lv¢j§ ¬Ã/‰ª«A6eù^Týh¼y—–äS†�áÚH+‰µé^„ë¡’ý]C j÷�æ( ;¸î7sÎÏáü�HÔsÁEpþKÎcïÎ=Ü¿v7oÚÃ#›ö³¡gˆÖY£•·ž?‰¨,·Þ²Œ?·ÇýøH¶>ú ß8m2ßY˜Ä¨�Ê;ÏhäÖ{º†fíIL¨¡+çbeàþ{—ódœŸµÓÁ¯îÞÄÏ�ÏXa0cÞ$¦ü¥Ì}$ëBQ¼}š-œ9y/_üò2þr@/ê£Ñm¢î%À@Ÿ.¯tkÊsìø|1iaÞòmad”h„”°ÍŒ²É+%ÝbXAÇuI¸a½…’­?¾Êòõ5-I˜ToÑš¤ƒUS€¶í�w%�ÃÁ ™4¨¯I“¶ŸfK‘ÂDgí]ùÒ¶ºŸôK”�#ŠX£Ýèy*s«‰s›ž`¿9™¤'g3ªÎÚÑ™÷hsL2ùµé$‰t 8r.te}ÁÝ•³1°‡ž‡išÅ>D÷‹íYi,'OR¹0È8BÝE‡pþ|ÛÀ—Ú·0[‘ýHÙžýØÍMƒU蝹‰ÄÁ}x©%éBº ÒJb8¹˜’ !%BÚÚ½D£9Jv¯à-ßìåão<‡÷œPOZ€ ÆOžÂe“§pÙ…¾5£}ÿ~þ³~ÿ^±™¿®n£’ÑÖš0�‹Æ1d»¶pãªBe±®z¹ã±]|yÁtj…Éâ…“ó�.ö EÝ«wÜð;î¸ÁŸ@“RNÅv »ÛXïÁX Œ¦z&Ø|¤ê*£wÕJnا·FsÔqmRÊ=$w9é¹X^׬²RØ0°¼<.éb;Ñ6\'XXÐ-@b 7�'% CáHßÌ™0³$Ý4 ¼à©?£l&ÖÖ2©.XèGzØ?¼«í ÷>»_p¦¥KÞõ?§-“´e2¡™`ow¿f3ðãbû‘=üöMÃèw/‘þý³dž ží¯z È �†a ¥,ŠâPl—/ÖQfwÒ£V¡«‰SÀ‰™1­ÏqœØôâ¾�… ?ÂÉW56 ÝÒ]œG¼¾£’Trí�.˜¥1µ‹©`±›Ð?[z/x Ÿ”Âô…¿0Òë¯HG/ÑhŽ…[øÒ÷·ó“é3x㙳yÅ¢‰œØ” \uW“–±ãyÙØñ¼ìÜSùJÏþzïã|í[ØT6Ó¤aÊhfåì­{xªÊbl]Ûö±ANg‰ ‰ ­œ`žCüó—®CÜc|ñxÁ¡/\À4H 2|$ëÉÊõ{ˆq!×h4G’@Èæ—”A‰ËBÚ�¸fz@Z^X‰$=žIBÚÜ7ÏLbFü£.V"I^ ý6r¶C&9pÙue¥úCMDĹòE�m;."¸I‡BÜu 3\y1˜¨(= ÃÄŸ>\‡dÒ·tƒ�gXØ…‡==Ú= Gy˜ž�aYäs¥¢::¡S•£‚D¯…­–g—œ€ÚT’qu)ÆÔ™EÁm%ÓAëB>‹k%ÝI”†q5©MšŒ«ñðd‚ÎlW Oç(�ÜfËØÇSÅq˜Ù.dmsÅñ 1z‰ê×ËV‚ÞóÎ’AÇÃH&¢�£ö‘§Q3ÏGN:�š'ÿMö´9¨Zÿ™(¬Fd³dþ³9n)(0ö>Cß¹³ýH'B•ÔÙ¿ úRÖ?í^¢ÑO(²¸gÙîyði~tÞùÜpÙ &�™ºˆÿ^´‚«žô}·…!Š÷„–�X$^¸X—ãcWÄ`úY/á¯ož,c¯è>°›¬ÚÇê¶^Ú³.yOâzÇÇ_±ˆ“*Î…ɺ"D#™h4š£†!]?hƒëýS ÅÖ`ÛŒ²©­«eL�ŸŒ &“:¤¶³¶ÇÞ^‡ýY?öv¥¶Ê÷(؆t‹ùL*‡3,Ü~?ü9z]…;:óX�%a|}Š…­’ºLDx'Sèɱ²-ÏŽÎRA} ¬ØÓn\_Š}�><Â) ]K:H#Qr>¬b=¥Hu¦¢V8L¬KQkA�í�ÝG}Òä'ï‘Íûç¬ÆÂOz‚´ú¤ÉÄ:hïµ(ôº,”žïPp÷IƒÚHÜà!¨üzÄQÕÒm¸¶ÿdWmmœ•NãŒ7Ií_�l™Žœrõ�,Ãnr�­M`;Ht&‘–¢2 ·b�W¨ÚÈd„í¾àe}0\[»—h4Ç+ÊfÅýÿæS3Æñ«3j0DŠsOCâÉØ@®Ðj0“JT¿Åˆ™ð½«rÉÑ•R4Îæÿ¾nZ ’sÜÿç;y×]{h‹¹“Ë$PA(�d]�æø@©ø·LžëbZF þÊÓE*Øšãꌯ³¨±*[ºO‘({-–Möîs ôõ†+6†ûÑ­9H,èè8Âüåãp¤(IÛÉÚþRñ=@A R�KÌÔúuÉ~¡œ+ØôOŸ4*ÖQÞÏ.òù<}Úz ´ez#‚{WWž¶ž]ŽŸ·­'ÇöŽ,»{:³6½ùü9“0ö·BOXÚ½D£9²¸;WsíªùÞ‰) £‰w¼óböÿô|o}vð!ÍZÎÕ…|z¶ï¯­ò;ùÝÝý7×Â~ýh7¯» ÓláÊWÍá×­eGÌÝ79~!=½Î¿¹9ûùíÃå˳WB±»=tcÌ™1†&ÑE{¹Z6ê¸ä²ó¾Ñ6� ­ é4M%>/#Y—F£9.\K J`F"¶…‚/\�FznÉB5†i‘ëë¡-PRŽëÒ�®nˉ*°®wç]öö8˜µÉõõ€USº*f †i—|�«)¡p#}Ž®hY�òü9[²§ÇÆçËü�ÝöôÈÙ2föwT(»…\É-/<n+¾ÜtmR2â^ßáA‘4_Ôçh—O‘ |Ú³ù¢àÇsÀLË,@:aОÍÓ\ãÏ),xŠŽœ?.Ã4bÏ[É ¡¦œIÊ-`8Y$ÃŒ^"ƒÄYº¥$³|rÒÒ’rBzÈÞõاŸ\ÌêL›BrË“rrI;rÒb2Oü“¾ N öОµ[‰Fs„Q½üá÷pÁÄóyU³�Ù0‰OèM\¶z7?½“Gwv²£»@ÖUXÉ£››8qæd^~Æl^4&‰!@É,÷üi7vDªÇ#w=Ì-'_ÄëG F/:�›ß‘â·­æþ¶ „ ™fÁ¢E|þ 'sF P.«þù?ß7Ô×aнk¶±Â�À)– qñ øÁù½|ø¾=ìs#ÉôÙ³x÷+Nçm3M–ýá_ä) "IGÎá`Wm�õ¸žÄª:0zÌ «­ :³É’nk×ñöÿfôÕgòÂF‹Y§žÍͧ¼€Þž>Ú ‚†ÆZš“AhAå°î¡sÅ_ö’�i§bß÷­æËÌãÆŽ"iÔqñë_Ã…¯*p Ï#]—¡1!ÊeÍýwqõ};˜ÚÒÃG&7bŠ^wå圹¿��ÿƒÿº» w$ë:„1h4š#HŒXH)›‚Húé+ÜrŽÄ“&ÙŽ�w%3"ã½ v]é×m;Ü/ß�~_óˆðVšŒG¥¶‚m>_ t“¥(‡a˜~ýJ–Ô[l3ÒFI�G…eAL@·�‹wù9*£ ’�/€\·°¹¸óìÌ$$"ù+�÷˜6¥� ÜKâÇQr®?LÉìÐÁHìÜm§XÎÈvâÔtá�n)Ë-ðZGáŒÊ"zó )ÛöùiEmcªØ·¶Ó¯(þ×h4GŽÂ�M|ú›¿ã…×=ÌÏ–ïgg¾²O³’{wnç7·ßÃ…Ÿ¿™þ§£âŠ“½Ûžæ¿¾r;Ÿ¸'[r„A}C=ÓG×Ñ’ \ölÙÀ×r3Þ°‘mCš@íL�ûnú oùÛV6å 0“)Æ�ª¡É‚¾¶�üô†[yÙ�ÛØ¯$�ßy/ÿ»¶—‚a¦˜4®�Öä¨K£ÑxŽôJ>dÄêˆ0ÏóŠÇÃ}Ó4Kv±ŒâÓŒ™Ym&üzbúäa”½ò|ªLGÇ!…�”ë-I÷œ¢ˆÓ£¢ZFëŠÛ†’EÁ]^oTä‡eÃüѺ+á yhpý¾†š´(âÝþ6Âý2Á\,+Déñ°LTD‡ù#mË”·Yö#\wàõ(C´¾ãª’uØ©mFH‰·÷>úÎ<%²² ¾¥[IŠ«Sx.©­;Hoê€ñ'¡2õˆí�Òû‚)Ȇ:г#C·C!z²4,Û‚œ|:"ß {ž&7§gÖTHXe‹âm çÔÜûfƒïÊÒ3gi±Ï£ž¹}Ðk4šDX´¶61½¹†æŒEB(\Ç¡£»—mû»Ù›ÆëG3ÅÔ ÍÌhJSc*rÙ,Ûö´³¹Ç· ‘È0kR Óê˜Òfß�vVïËÅ,ã+H×Õ2.)iïÎÑíÆDkÁº4ͱ¡wÆ |•ïÆ,_à$j ?—[LËóEòxž7ÀÚmš‹s´�PÈcô—)o'H3û’jߊ™ëÆmšT23×U´Fàî …Ño‰Ž³hÆ1ñ8KyT4G-Úa[Å6#ý.©§Ê8\�˜>W¼>‘})†a!¥‹aXñ×|Qa¬óˆ07"^áçhºÙw�ôþ�N¶8Žr §¯ÚDJd‚oµ• 0kÎT›ôòå$÷@~RYWŸ_)Tm†Ü$‹Ì–‡°[ù‹ R©@X3RìÑÝ9 ¤£ÝK4šc…ri;ÐFÛ�¬Ó+°mǶíÁ:#('dž-;ÙP='ùÞ^¶¥º4Í1¢LЖ|.så¢/¦_hûifY�&’Ø¥g#õ–¸›Ä‰ó!Œ%*lñœ~ñ-=Œ¢50""¹(�#ý E²¡äÀô¨ öúŒà³Qîßì9Ŷ‡â*c*U*Ž#–f#<¡¨.öËíwá(»ŽF$-´fGíÒFÙIRºJ•”+/S’?™®p¤Ÿ*ËÀûöCÖ`ôô êɬQŸH�;m …Î.d}í€ã%ûB`ÏŸƒ;¥ÙØT&¶#ùÊ"§�=˜v *peÑÑK4�F£Ñ¦REnHÔ ¸}Ĺ“¥VêÀ¥èT'Ø#»XoTći7‚ère}ŒZ¦#Û�¨xEqÔ^n�.Ûa�˜¼Ñó z¼h‰�›7}؈y¸‰Šj)D‰eÚ¨pýŠù‡�ÐâGñAE•Ö×� &¾ºi÷"k+G/©îÓ ¨±³È¬\Y5ªÒ–M ¥“'KˆXÎ �lhŠkµBÅŠôSëQ­³Ák½8ŽF£Ñh4šaSI€•QIh¹Î˜´¨Ÿv\ýÅ´À ë^V‰ >„¾)ÿóv<<ÖšzxD±¬  ¥úó•Yºãˆ‹ܲÂZ5ʰð’¼;ªXºý†U"CRLÀ[µ†üü <NÄ-Š 1¢¹˜/~éxÿxŒu»˜Å#ýÌzö8¨ ×mí^¢Ñh4�fxxN°˜ÌЄ7šø®–÷�„< j�O …-ÆIIÉ<£ºûÃ1#Ñ$‡{×âòpòV«§üxøYH÷ðãtƒ/¾Uó$2%æ#O’[8ÙØX½`ÕBVøltv“~z=ÉÜTK©“ºv/Ñh4�F3\éaƹ~”aØYd²æ(õª2¡uX&JûRP"v…“‚‘>þ…w„‚�Òõ8�B�Vʰ\�rª/Ž}=Ð<‰¤ÓJò±Íxæ:¼´TÂ‰Ž‘uŽƒ(#~”“h…‘«°œäè…�I•ôI C»•h4�F£6æ­¤C܃ óCíÕò—XV�¦RíæCÜqmÆ¥ EÄ—ç‰~6 “Dœ«ŒS)¸ìÈŸ¿¡æôšF,ÝÕܽDIDàì® Óß7¨ 󱤇¼Òë?É—V¾?رâ~Úß7¤‘z•a"”Ôî%�F£Ñh†G(òʬªÕÄgùñðó¡ZÂ+ º”ÌS¨TWÐç¨eÕTj@T‘¸>&,cP±×—¸´¡ˆøò<%Ÿ=Çó(_¶ a˜H»Tx—ŸÛJç¾Z¿+=(T{È÷+•w„IÒ°U–<t"eTÇí é•ìǯV×Pó Ö¾^G£Ñh4ÍpH¥ÖVÃöW–Œ ¼�8!÷9%óÅrqå+ÕM�Š»h:@2Tax¥«”O^,oO&k*Ö·Ÿ’¥K²—÷#<^Œñ]V.Z¾¼,€ '6š©þ>Ç,¿7Ž¡œCÃÎV=§qýŠ»NÑòåm$ÔÐVlþ”Ñãí^¢Ñh4�f8¤ö¬92õ‘Z#$jp#–îÌþê+ ‡Ì0�gª/’¨)±Ø©qqÊÆÇsBtk÷�F£Ñh4ÍñÌsBtëè%�F£Ñh4šã™ç„èÖî%�F£Ñh4šã™ç„èÖî%�F£Ñh4šã™ç„èÖî%�F£Ñh4šã™ç„èÖî%�F£Ñh4šã™ç„èÖî%�F£Ñh4šã™ç„èÖî%�F£Ñh4šã™ç„èÖî%�F£Ñh4šã Àpýe:·ÿÝÇ´3#Ã[�u4�F£Ñh4¦¼ÿZ&ãXwF£Ñh4�F£y®£E·F£Ñh4�Fs„Ñ¢[£Ñh4�F£9ÂhÑ­Ñh4�F£Ña´èÖh4�F£ÑhŽ0Ztk4�F£Ñh4G-º5�F£Ñh4š#Ì!-޳fù“Gª�Fóœâ„E'ë.h4�æ8â�W¤<ùÌs�D?4�æ9ÓÿyàXwA£Ñh4ÇÚ½D£Ñh4�Fó¼ÂqžñÂ£Úæ![º5�F£Ñh4šg#¶í°vÃ&î}àa,XÈ{?ò–œ8ŸÓNZÄü¹sH§“G¬m-º5�F£Ñh4ÏYöíoã™UkxfåÖn؈m;¡èèì`ÙcÙò,¦M™DKs—¼øE̘6eDû¡E·F£Ñ<±{9Ø�ÃS€HPÛÔDíÑúE8–mk4šçÚò¡ÿó¥øƒÊ÷²ö<lmÖmØ @oo–O~ð½#Ú}›Óh4šã •eïæ�t¸ £n³'Öœ„“oc˶ƒäƒ�"ÙÌÔi£Éˆ²|N'Û¶ì#«©æÉLÚù3ÞöáÛ9 s:ï¼þ'¼k¦y$GÕß�UÇ®í£�êÝÍú]=ÈbŠ Ý2…é­éJ%èÙ½‘]=ULË0fúZŽÜ›îgGä¼ÚlݲŸ\ÕÖ“´N�ÎèJMÙílÝÚFN)ÀbÔ”Œð‡XŠÌîeÍ3«Ø´·‹iZ&Íá¤Å³ô5aV­Ûˆ”2öXWw'��MË­]�í¸$#'•µèÖh4šã ÕÉ¿þ÷ý|•ÿ Ôšõ6~uýÌ,SÝ}ÿˆ+¿x}�¢™søüM_äâúÒ{wÍoùàna�DŠ3>ú[¾9ñ(ŒãyŠóÄO¹êó÷R(*=Aúô�pË7.¡%N‡yë¹áïãWÛ½þ4k6WýôǼcºŽwr$Ϋ·ãÏ|潿b£S>Š9‰·üè\sBùá¤cÅm|÷[?ãž­9ÿ�ÀhæÕßü=Ÿ<5_—êcÍmßᮿ—­}ÑA¢y¯ûð§¸úÜñT(­9DÖmØ„”ñ¸³³ €úúúÇ �¯=°†Ï�âˆõE‹î8òíì>˜EYõŒÛûÅWN�Ý6‰ú&ê’ƒ?ÍN;š£ˆ¾šãc,'-‡¹jàíXÃênÅÌ¦è½Æeýʵäú±Q…5<½ÞáâS¢¦2ɾ5ëh =æ NYÜ„•¹€k>4Ý/o42o´wGEaåƒ<ÜùR^>jàï…·åa–íª¦ú49üóªz{èUƒf©\6·•»ú¿|÷ÖÕtxC­Äcûí_äƒßœ®ÆW…Ó¾’¿ø œ¯^ËGN«c˜êBaûÎ]E÷‘rºK·çMˆ=¾móx΋nçëWl£[%=gSë«|í²»Xµf9QÇäó›:¼æ w¼—Y¯ÿ#ö¬�±lÕ783ª¾²Ëùé5ïä³7>Á¾¼‚Æ7sÛ¾ßðÊa´9h;Ç ª›­Ë7ÐæT¸¡�™¬¥±uSÆ7§_¨¡ñ¬¸šç &3–,¦é÷;8(A9ëX±Þá§GÄ´ÜÊU)ù)‘�¬Z±ï”ôÛã ¬]³7ødŒ;‘“ÇÖB.~å£1˜ç5B@¡rOsÿcݼì%�eBJ²í¡‡ÙæB ¥†©ŸGŒÔy•}}‘7E‹¸ü#¯bnÜó§QôIý䎿ñé�ÿ€ûvP’µuÙ^òU.�꼟ë~þd ¸ ZN¾Œ÷¼áTƺ[ùǯ~Ê_6äPÎ.n»öf^qýÛ˜ûlþQ=Nؽg_E÷’)Sü‰’•ŽwìoѾ——S¸…«Ïz/ÿtÆqÕ�Û¸îÂÁœÜ5×ò†3¿Âjq&ß\½Œ�Î:Lß@ab™&ži JþŠ=V}÷\ó«'pÌÑ,¾ä淜İ DÛ9Žp–ñ?¼‚_ŒÿB™±‹¸ðMïç3Ÿ~§µ< ­fφë¡yÞ�š¿„SwpoN�ìaõªx§Ï,ŠiÕ»†å[|+žQß@m_7=R²}Åj:ÕŒþ×íîfVmȯ° �Äl Tn›¶wâ;°¤=m*­�ñ@öìfÃnßwVXMLž1–ÚÂ^žZö(ë:-æœw1'�)ýW…ƒl\¹Šu;ÚȪ £§²`É L®þýxxuzôì\ËŠµ[ÙÝчMŠúÖ Ì^°�9c2ƒ,N1ÜrƒcLœÌ„½;Øáæyâ�'è¹ð|¢÷¹‹enÁŒ–‰LÌîfG¶šr+ppËjVlØÉ�nRu´NœÁ‚ù3“ØS»c;[öû®Âh`Ò¬ñÔEû òìÛ²�vGQÙOzøççH|7Fê¼:Ù^ìPt×Ïଽˆ“‡ ŒÜËybO-œüÚ«ùð9ÛøüͦA ëŠöewò`·ÿ{jÔŸÍû?w%�ÀIœ<¡›5WýŠ ®ÂÝz]y9s—hëÏáÒÓÛë^âÔŽbï«þãïþ‰¾ŽyŒ®ƒ#Ú—a‹îYsÏܾqÝŠÃ*$I½öwt;¿x@µñà}+±•É´÷ü�‡~ð"2G¢�ã“ñ§½Œ³¦”ßn®ƒ]kŸæ™-Oóço_É�º‹Ÿþó·¼eÆqùLW‘g×õÐ<ç©YÈ)s-î{ÚA!Ù±z-]j&Í�°pÖ­d�­ƒæ3Ïã„ïà�¬ÂY·‚U…—s^ ™äÁõ¬Ý<4‹$'ž<Ÿ$஽‘U˜Ìè>ýsÞûÙ‘U j^Ì×ÿøZ6~ü£\¿:‹"É‹šÏçäóúYþ§òÍ_þ›�=QY#Ò8ëMâÓo9…Czf�ùmÿäÚo_ÇíÏ´Eü~ƒrF SÏ~ýðqj³1"冂¨™Ïâ™»Ù±Î%ûä2ë;Ÿ ê"CÝó0Ë6y€AÃâ…L}p;*Öæ²ÿñ?ò½ÞȽ[{)õh™ œyé»ùð[ÏaRÑV%Ù÷7¹òÚU8€¨9Ÿ¯Ýþ–FmYÞ:nøäG¸iŸL¦^þ~wÕ¼âÞ°ÏÏ‘øn„åGä¼JúzúŠo‹DmÕ^¬÷cÐ4ÿ•ü÷‡®äe³ëP›~9„2–?±:8‡‚ä‰gñ‚ˆË˜5íœ=ñ6ló@¶ñä“Ûñ–Ìä¹3Åøè£”"Ÿ/Ä“y‡QwþÜß·�X”Vïˆöç°Ì‘W¾û½œ|Ê©CΟ˜¸„Ú3ß~8M[d7]ݰ˜9.•&1?7±8åš_rÓÍ7ssÉÿ[¸íŽñئÝl¼óóœ?F`o½‰÷¿ï—ì¨b×h4ƒ`´°dÉäà&­pÖ¯b­ôؾj �¾)šY‹.à„ÉþO³ì[Å3›Üb5…õ«Y|ÖN=±¶ªŸ¨H×�2)·—�·ÿ„߬É2ÀN¨úxêú�ñ�þƒ =Jd3{1§/žNKR ò»yðŸå¿ü$=Cõ˜f�ªý^¾üá¯rÓÓm”ÀH52aêtfLM­%P2ËÖ~ÆG>ús–ç¿ÜPQN3‹N™„ ¨ìÜ÷D6rT²ÿá‡Xë*)/žƒ�•N”Ç®»¿ÌUŸøÿÜâ n!LÒuud,�@!s»xè·_àªÏþ™­N…jµÿÃ=?Gâ»­~„Îk_o_ñ{mÔÕQ£²ì^õî¹óNþö¯‡xj[q§2±äj~ñÃòŠÙuCRr7›¶…o�£'O¦6úÇhNbÚd3øû”ìÚ¼­™HsxH)üWB!“ “øû1y¤7²s-†mŠ|ó[.'Ÿífþü¹ÌŸ?÷JÚ0ûòá6{H¨ÎÍ<µ©ê§±hN+–êeÛþÅ}Ïl¥Ó«aôŒ“Yú¢“™�Ž/§R㘷`µBѵå6ØÌÎ^Hzw¬àñÇwcÒVžœ-¨Ÿ²�¹c*¸Â¨^v¬\Ǿ‚ aê‰Ì�ˆiçðú]Dö±ãÉxxÕNºdSO^ÊÒÅcI‘gïšUìÌZ´Î^Ä´†‘ô¡H3å%Ÿç†¯<ÊÜwý�îÝÈ{ßÉ{&ÄLnéÙÆ“Ëfå¶ôxFO;‘œwÓê¿uÙVóàý�±aO7Nf ³O]ÊÒÅãÌ�þPÚp=èc窵ìÍ ê&/`^¥Éª‹­Ïl¤Í4M_̬–R»Ä!õ¡cOmê€ÿÚ;Û–ñ×»Ÿ¦­þt.½ìtÆh·—ç&ÓNZDë¯7³O‚ìYÇÊmgÍ6Au±jåŽ RÂ$.˜Ë‰1ÖDʬX¹¹`[W¯/N¶4&/ᤡøÃ™f¿uÍÝÀmê˜vo¾hcè£aŠÿÓQXý[¾ñÇ�ÁdÌ–~ì{|é’ $�ܦ›øÄ®ãÑž<›ÿôC~ûâëxÏÜê¯Ê‡W§d×=·pïA‰B�Yôv®ûúåÌ©ñÿ`œñí�|�Û¶¹6ßÊ/þõZ¾ý²fİË®dÊé§0öÆ­ì–}<òÀ“ô-=‡Zy�‡\‹£@¤ð‚Å)î¯P�ÜõW¾ö�ûÙëúo7jOx5Ÿùô;X:¥²»Xö˯ò?7­¦WJÚù|ýöSøÑë&žeí0ÎÏ‘øn”0"çUÒ±tË®ÇøþU¿æ�ͽ5ºHÒzâËùàǯâÅ“ûßEMuê«‚×Î�ö¢Ä§¾©< h‚¦Æ …Âm?@»„Úg¡·æñ‚‚Úš4]Ý=Žy˜~ãŸù"ÆeÛîØž$iŽÌE¶è~ӛ߄ixêÐÌ™¦0ð*8¬�4ö²/òâWþš¾s¾Ãê?,â×—_ÎWïÝKÿœ@Ajê+øÖí7ò¾ÅýŽ"ö??Å9%êlîûÜR^}Cwñ‰ø‘¯^Ìé_Qw)½ä>þ÷�í4¾þwlüÃeÅ׿QäæŸðÆS?ʃr>Ÿyäi¾4:®�Ãë7€³ùf>ôÆ÷òÿkëõ(2L»äóÜðó¥üùÕçò��c¹úžÍüèü‘*sæY̶þΓÞN¶îô`Bä+&pÿ·ÞË{¾|+k»KÃ$ ó¸ôs×óãŸ=0ô“³�?æí\ó½{Ù}·)’Œ?÷ý\û«¯òêie7ìa´5àzX6}é%¼ñ��4ý×ÙüûKiŒµ·â»¼ú´/ðŒXÂÿ<ù8Ÿm9Œ>ÜûY–^ú{ìó¾Ï3_ëàm}�Gºæ”÷3ÿÒÓ£ÝûžW$æžÄâÚÛ¹»G�ÜŪ5�¨Ù-{Ë×»ø�GæsâäsOœGêÏ’S.W¬!öÅ IDAT{ÙêdkÖî D…AË¢%LÊ»êߨvÚë^Ë÷t5'—˜åò<ù×»ØÄ7§¿œw]ì‹*€ÌÌ×ðî—ÿ…'~¿ÏÝÎßþ¶’wÌ=‰Áï:íS²Ïþàž'H�›ÎÄšþ¾&F¿€wú³œt EëèÑŒŸX_´&¯ÜÐQJaÍ;“Ó›oå¶6IÏãñtîÎ΀êx”ûV;þD¼ÎäŒ&QAº¬ºýfž|’Er>ïüÌÕ¼(œØW3‘óÞóIÞ¶òJ~´ÊF©<Ëoûk_ó.æ–oÂpÏÏ‘øn”22çU‘íë·�{Ûã¾YlÚ–ßÊç>p€ÂµŸçeãC|©ÙâLKA*Y>bA2ÕoÜQ½}Tsï×T'“JÓ!»¤Ù6Æ-û”¿oZÄ)ÓΞ^î||+¯È�~úà°\aŠH7âˆ/Œ�¿Ã%iÒC’<<:ººØ×vÏ“þ«à…ãv��kFnâ°-ÝRIjH¡�yä1&OšDkk …vQ± X®zUEz/Ò{ 5H#½îfÛÌó"…”MH¥žïç“Ù™9çìÙ)¿ùŸÏ!¼µìiSúóÉÄk»qóÕÓ™FYFj§f³âÛßHt‚¦e_úE�ý¢ö�ïòÈŒ½Xtxô÷µ¼?ħÜbÔ½ï(®é:�ž×˦7žå‡© ¹»Ô‚cÝüO~s»±7ÿYº‚ç:—ùÔ\ĉ=qï1ŠOŽÎæÅ/fèSW¡iD_®ð>…‰!?ðEÊ2æ-Ë寛}*[º»˜;ïÉÈà©7%7îû¢Ñ¢œGç0'úA–îþ?úy Ÿ’+ɇ¸®‘h¶Æ�BaüAN8{ã�d@Cd§öxJ w$6Pæ@ª‚’{ˆý) ]­‡ˆ/*•>ºvôˆm@$ŠäGLŒu �3ƒ´ô²{¹ŠyÝÛL¬É7p¦%“â€èÚÌ™ nS¦åˆ‰ôÿå0k²T¥�ãëçñÉúy Iè½ÃéÔýjÃØ«#*,×7ô¸úâF—þ½ð^¼„%—MÀÚ+†Íö`QAÒÅ0¨o0{]îHåtj™ü’0††¹Èš%Ú�t‡ (餤;¡ecLÝ œŸæ87\ÒÈyE"bà4î‰vßXÆ��+ìœ8~-y„¯ÛPQÈÙ´†í– 1Õwœ¥ÈZtš’T‡à*M�ŠÝv6�NÔ‹h$‹–¯‰‹ã”e*«i»âTH=~˜Ð$ãið-DQJœÎUU=瀪*äååãp8PΓ¥» UnÍí/ÝWA¸–àÞg0½Ü$pžæÄ©F¼OêºrûÝÑceÓw?_¥)çá_ùe—¼FpÇ�-ë<éõ·™u WS Jx�y€;ÚT~ŸÒ¶šÂ�vGW=ªñ8‹HÝ·„�ïÁ­_�À)û2ô©Gè_>n›¿ÿ�ƒvpù/ž\E¸"8ö_ÜÛE‡Z¸šÿH.µ�ØØüãŽ9ÀcäƒÜWE0HÞƒyøåǸ÷þZ\ìÒоjÀ4ˆ[oˆ@£æ²lÞRr«LŸ}Û\~=ê@òδÊ~ÛFŒ¡4Ÿ¬RCž}†¾Bp_áÈ´Œ‹£lE[I�ç`Ž•ÃŽ—¸›É~têRrÞi£éÜÞXr®9Oqø˜™ìƒeâ4Q]ˆóiÀù$™ð¨jåPØë\¤¤ XṂûѦ8‚—?xš›º•ZPËvR±åžbçʹ¼ÿÜ=L~öWWøkèqõÅØ¥W{Ê€BÖŽm)ÜËæÝŨHhÛög@H-OÕ†Õ~Ö-Aïæ:¾DÖé+XÒlØl oy› ™Ÿæ87j QóŠ�˜a·2ý¶iL¿m*·_W9“Š[ ×�éX>§jq'Î4Âh({âUž«QÅb©šUCÅj).JËžõɦ"pÅŸKV É2VKEù9®ƒ%Ïñ—r&½ÉÆÓpKw©à® ªª¢Õj‘$0›Í8›8ô\HnÝéÓÍÅMJ狯§3fKcĨ†˜)Óòï­,Ýû?ì|ŠÿëYö~ê$þ×_Øk— ¸öÆÖý ª×¸�'8oFEKû]\xhˆ;–/mewƒî6Þˆî®ê[TEAQË| Ãþüüx›³�XΓlÞ’Œ-ôu]®WCß>Áhv$±kó.l†ãæ<ÉÖí©8ÑÒ¶G7ªëO WM}—YS+|ÔоjüÞúÞz3ÑŸ¾ÍÑå¿°4çfn)wÚ·±å—ßHpÊø]3�kË~Û¦ƒ®;CúW-ö ¸ÑÆÄÑÅsIy ªã8%t´$“ˆd¸Š¸˜²{��Ž�Ú ]µ»j'ñøqö¥-�‘ ‰‹£–E�Zq™·^6b2È`SßÑ/óãÃ]k¶ÌIÜÎe!ld›ÆÖ#xâÃaÜ—|�mÛw²so<âhr>6UÕNú–Y¼ò}¾»·}y» =®^˜º2¸§KW䣤ícëJ3;ŠJ²aµé×—°Ú~Ùˆ»±l^T,…E.�v³Gù£Ì„»Éŧ(Õ]ÔbŠkñµ«÷ü4ǹQ�™×s"áéã�F¢ä:R­Øl�Ð r¡AJòt*äfç¢Ðê¬!N- #Ë^žÝÄ-8_áVØ(’Ó2ð0è°;œX‹ ѹy”VªNE!;·º?xCi„èVQÕºUκ*®+²,#Ë2 a³5Q.£:"¹{ãíòj×P�ÚXû¯z#ÓÇ=Çò9Gù黿y¹çàå8À¼yû±k¸áöQx5׸•LÒ³@GPH�Kkº&²-QZ‰Ý ´~˜"ö¨š7‹S)¹(š†?ñ:ÏÜ{C£«”®URIJ)yXühqß¹^î´fd  bNN"K�0%•¤Ô’›g`p`ÝVÚW-�ëºOfRû÷ymÿ ~YšÃ¤É¥Ù ¬›˜ûÛIœrã§�¦¼ qŒA2…ꢬ±à Dß‘n ,ÜhAUŠ8´}5¥ækm›X:”ÇRËtêH˜f‰N…”£kØ’ZšæOö¢K·6M[ MBx¨ ‡KÎusn²»Gå¢+¤M÷°N ëÄà æ”üüÞ›ÌÞžƒ¢:8½m;Iw·§²GaC�«+&z èŽÇªÕä;�2ÿgÈRmƒú—d©ñ9¤ '*BûJæÅš˜@’ÒŸèJãppâXbyz;IAT¸PÑjÎÞƒTg6™9 ´¨P]1åG‹Îe�©Çü4ǹQ# ŸWµ0‘­›‘’›KNž•ðáSѪâýZáL꙳/2²/þ Y-*C¤mŒò�’{öñãd*gW²°ŸàpbY~O1íÚ÷’F¢ªj‰�BÖ ª N‡ YS÷;¡ª¨¨M˜ü£áî%ªRg÷UU‘eI’J„÷9“Ä–í¢P'cº³4Ø@’]¿Á”.Ù7+’ã¦ßH¨ÆÉéyÿeEi>uǾyüzÐ�6z2w ¬g)�úŒ[µR\šÙCW-"º�cƒŸºz†¼µƒ£ÇŽq¬âß‘Å<ÑI�¤¤s<'˜®QÕǬڰÚT@EuX)..vù§z†M”¿¾¤dµjÃj-©�¦Óéê6 í«6´±L¾¥ :òYñËbÊ2>o˜Ãü$'šð˜V±*CŒAÒh¦XWÁ¥†äA\×èRÁì$qÅ ö—¦� îоR€­¦u':y”È ûÁU¬L.±iJ†tëØÄÙŠäPºwmQžGܶ=ë³+Þ°ÒÖÿ—÷?ýš¯þ�?7�âœÞ mӖ¶ſòõç3xõµïØRTñShO¦ÞЃ2ïjw–X.z\1õ@O“ªƒŒôl@Ù�AáçxËÁôéÛ]é8'Vò×þʳ©î`ÁÚ´òàE·N}éí-2ž~>åÇâ8ʺ�ég-åj›ç,,Ïå^‰†ÎOsœµÐàyUŽòë{ïðÖÇ_ðÅwßóÁìUTôQr¶ðÂ#å+š°X:4Æô¬£cŸ¥ÖkÇ¡U,;]ÖºJÞ¦elÈ-‹Áˆ¡¯€†‹4&£’z�U§ÓY?÷U%0À·ÉÆÓh÷’ºXºràjYF£Ñ IÒ9Mû’É“$�ZHN®ΑHÈ™U’Ë�>Mš{º~˜†LgJÌW¼uäO~XœËØ›<Ø3ïW9uÄN�F�¦ÎÐWÉ ci5‹bK1¸r˜°ä‘ט'†+LWó܇÷ñÛÈ�9úÍCí[Y KîxzH€Ž>¯üͲûBê& ¥²åQ…¢Â"|Î}jh_µ¢áªI“éõïl\9�ÅY·25ÀÂÚ9�ìÔÒfÒ4úWœîfƒàÊE&8.Ž–šýœpª8 òK^Ò$b£*ßÄõíè|•–…[m(…”ÕRÓ¶íV=ûH£ÑÒáÚëˆûóv™UÔÂ-|üêW˜™@÷@•3{þdÆ»?³3OÉ�®öb\sµ©µ²ï·/øòˆUÒ²×aâ©;Ѿ…©˜ìS{ùsî¶Òôk2>íÚ•ÄJ <®�HîÝÔÝεeY´DèO«sÞØdZ�›Âèù/±àŒÎ$~yíßx>r;#ÚúàHݯg± ­T°iÙxûÈrc¶±],muëÙmSAµ°cÖó¼Rp#ÜœÜ8Ÿ7Ê´ ”9•Qr|y†±†Îk³œM?¯’W_& `à²×¿Ãôû71¬g+<,§Ù¶fû3K+iÊôºili"•¢ý øïº”rƒ‰š{€¬²Ç«jaÿ‚/ùhké$ozÜ0‰¾A2Æî™¹‚oŽÛQ­ñ|õô3¤�ìJ@ñ1V/ZWb¥GÆwÀ�ŒiœoŒèØ6šøÃGJS1–xhT`­U‘ˆ‹íØdãi°èV•"Kq�?áê6äš‘›S9wÊ@S m[ÊpÌÊîm{±ßܧ–%;ûÖo"GMx':4fé§±èºsÇí]ùà¹í,�³„œ Qüò뜆>Ü6¥Có–r•ƒ ’ᔓÔÓ)8ñ©ÖŸýÀn6ƒg�çàWøàŽ??û_=ô<×oÿ„‘mk¢[i‘Ž98™p!u[2ÓD”,©&8I<–ˆ“ê…T»…bÜ0–™qÚ×9�#oâÖ~/°qõJ~]’Í”ë·2wAж“§t¯ÜG3�Ap墉ìBœÏOœÈ:{¿•t1t®e-yÑ©Sš­Ç*¬žhïÛ,)'å–×ò샻xðý�d8òöüÈswýXeLû=ij×Õ-ˆ¼AmÊ­™ôðM¬}ú'›$¯ù”G×|ê¢u m‹�<|G/L�9®¡HôÐÓº ©€&œ�ý#ê4/’W{y:©ÏÍŽGú¾xa _TÝO@߇^澸³–9d“‡ÌeïÒ @µœ`ÙWï° @2Ñùž²ý%>Ì(qq*eB³áóÓçFÍ“ÓÐyu§Ï?þÅ͇^bÎñbTÕAÖ¡5Ì=Tµ}7¢Æ=ÅscÎZ®á§9»]V«DµplÍ<Ž•ý¯i‰fðÍô t1L}âV6?ùÍ*ÖÔüöß;C2Œ'À…”3— “®Çkoˆ¤×£5˜P¡^q…Фaô��M6žF¹—šÍdääÖé/§ �ì‚B Íæs§ Ôue¸Vhp’ðà ~s™ûºt§æ�¯ã@K›ën ûU7ÚN�Î ä­ø…?—þ̯ǜ¸¹�I s¬G×­‰íè�Œƒø�›É¬6e…¬ýßïœlŽVÉ—k^�I¡Ž„/yè…•äUì_ ¢ÿ hqrbÉBö»¼K)¤l]Ìú£9gÅ‚Lßþ1hqrjårV[þt°ëß=ñ2hñûgÔFôu.ä–\ë`Ü)dÍ‚U¤­ý�Åé*úS™Ò±Ê»ks�Apå¢/I÷Wñ,‡v¤Sµ(+™ðØøTüXö£k—ÖÍôÒ¯#bÜËÌ~ûnFwðÇPqS’q ìȘûÞä«WÇQgOCÚ”pï|Ÿ|ô/&÷�ÄW_Õ5OBëAïëåÓYÏ3ºÜ‰¶¡Ç5 ¯žýéj,éEÞŸ�uªVT:ÖŽ·òþçoòÐ5±„5•Æ*iÜ ï6žÇ?øŒ·¯‹¬\©WòaÐcoðÌè¼µRy{²{+†Þ÷&ïLîL §\Þ^±ÙZÌ×ðùiŽs£æ¹iè¼JÞ=xôã�yiR¢¼+»1J’ß6¸í…Oøòñþ.Ò46 SÇÛøhÆcLˆ ¨”FÒz=øÞûø_ m”‹ Œ>=»áíå…No@Òê+¹Žh5´ ®jCpP K÷ww:Õ«êzíHÓßV‘JNÎSý£Ö�ã÷î¤ÛÕhsUl£:>v¸ödãÊéÿr}�éü‘>½fÖ·ÿæÆö^Þì¤oýšM‚[Næçm?pcðÙ3ضü´ýé�÷°øÔŒ¬êÞa[Å‘#ø,Í�é “ùjtÉÖ_'áë¢R$Î#¼Ý¯Oo‘þy"ËþìÂ9‹9“Úrë¼bZ¶ò$ù”�ë:Êœ›«—®©Ÿ†Ž;oþ4bnø�LmGY¼Ž†–õiçôüu÷ü.›AbùƒÕ-* Ã9{Á%ÁÎÍëiß¹Û…ÆyFÁ𓯩ÔlŠœ<üC ñ®œfî<µ©Ú 8“šFV�‡¤Ãç-C|0œCÇ4ô¸ ‚£�´äT²ò­(z/Z„‡d:·Ð´¤�x:‹Æ›ðÈ0|ë<ÒðùiŽs£PŠÉNIæL®»Î„oP-} Íè¨`ÉJâdj>6­;A-à öhÒpgp÷#O“™•͉ •> &%%�ˆ°P¢¢Z±fý¦jÇŽ>”wþý|£ú�xøSÊtvƒÝs‰æÆ"‡ßÆ×¿$0ñ†×Ù°õCn‰ýšð¸žÄEbtæ“|h;;eP¬JèÂFñæïŸsCðEpKþŒ›~!¿~É©D3rÈtîS]p7Þãžç¥!‹xtå>Ó‰�cÇÒ7BOÖþü±¦€!¾HÜsOðsá¹Ûª?2-§¼Ïk?®å�¥Gùü�—¸~ë —¦k‘[Mgæû‹ü�?Y÷Ü@âVNfòÈXB ’÷®ä—9+8V¤'æîx¦ßÙeQMÛ˜ùŸE r%KéC׿nd\Ï04é»YôËBög«øy•÷¦ŸM»Ôо΅0†)cüøãçyÌüÉŽâ1†©7†»\.j®1/2ßPb|C/x›’Þ“àVž׳·†wAÐzÜ*¦ÞcÕy†Ó¡a¿QÃç§9Î�f@vïe4~-Ï[‡ý#hç¾ú»22°ÿ›ó[5·’¬¬lœN'…f3kÖoÄé¬ì…a2yô¾éM:–‹ø•JÂo૬Ø5˜Yo¼ÅgsWshç*Ní,Û,c îÆÄ)òìS·Ó+°Y=¦ë…ûÐéÜÚæÞ9¢ÒêæÛV=ivó mǃóV`zñiÞúß¶ÿ6›í²‘à®cyü×7yfÔîy®d×z¤©¬;šHîšñ"?öz‚uG>ã�W®gËûñ@GÌ]sÙú6O¿ð1óWÎæõ¥ÇI2î-ûrÇk¯ó ¢E¥±¹÷Ï?Xú*O¼ô%Ë—~Å»K di´5Cý73þ3…N•ÖRÚ×¹ðaÔ”ñÎù†36ß Ó˜TSÍ5�@ ueÊ�Ù¹{/‰‰‰•>/,,bäÐA,[µÖåqO?ú -CCšt, v/9ï(fÒŽ’x&›lÂ74’6~ßò@á2îë0†Y©xiÛN^írÞmTæ¼|lo|Œ¥/$ù?0¡Å4þtÄòÒö�¼w¡Þ¹ŠÒŽr$1ƒ"Å€OH41­ëò[ÚÉ9y„„”<ìÆ ¢ÛEèv®ƒÚWSr1ŒAp>¹2ÝK�àâÄátòÓÜßùxÖWäÔºoçNø|ÆÛøùú4IßMâ^rÞ‘Mµ‰#¨Í…ȹp’ðí›ü/IÁcøÜÕùüM±j>уñÏô¦ç¨®úøUŠ´·îÜÊ;HÆÚµº�?½Œ{ðUt ®op‚ßVéÞê|ôÕ”\ c�àÊD«Ñ0mò�Œ=œ÷gÎâ×ù pTq7ÑjµLŸz �Ü7ƒ‹jàM1ŽfiõŠE%oëÜþÂZŠ4mxô…iDœÇÇþ˜Ðï-ŽHWqÿ_˜92à¬/yÑ>zõ{N;e|F\Ï0ïó7.�@ ‚ �Ÿ¯ÿyñiþ1}?Îù•åkÖ¡( Ãä¶É7Ñ2¬yã„èn”Ó‹xÿ³5$&nbÁïsÊêFç'¾äåîçuºžÿä­i¿pÓ·‡ùl|;Æ_Ç�hrظà7Ö$˜‘GñúÿÝL�®È�@ —1áa¡<ýøÃ<ýøÃçµ_!º›%ýo¾yç:$dÏhÆ=ó)³žtþÛK-˜ðÅ:µ{–—>þ�-ó>a‹ !¹µ ë �óÂÿ=Ëu1¢T‹@ ÁùDˆî&@ÛåYVšJ–ÝH‹V/`RWmßúŽáO}E~Ê)’³Í(_B#Âð‘{�@ !º›�ÁÑí/²Ü®:¼B£ñºÈÓ¢ �@ \ \Œu¶�@ ‚Ë !º�@ ‚f¦Þî%½^OnŽqÔÞg¤�­'¬ç½_�@ hŸk|©©©�oD ÍJHHÝ«V^>ÝqáBt ‚+‹úÜÈ�@pñ#ÜK�@ ‚fFˆn�@ � ™¢[ �@ hf„è�@ š!º�@ ‚fFˆn�@ � ™¹$R6‰�Z|d PHÏp�å¨ÃQz Ñþt€jsp9â¤I´·¬¡w_þÕÇ�p}å¾T‡“íÛry}m1)5V �@PÊ•!º+ "Ñ#ÖHðÞBRkSݲžÑ�thÀµ8×ʸkUáÐ1k�âSÉwàÊxíÑÂÄc×z3®…\CÕ ‰õåã±FüQ8_ÄÂ9È´�q纷^€~nï&(um²dúŒ à�îZtŠÂÁýE,;é ™Ö­MLì £g?>ÖgqÇ+�êKpÙ i=Ì“ÞÆÚwsfšùpSÅóF"$Ò�I]Üèì/cTURÏXYº½�åi •ÞW%™v±ÜØVG�¬p"ÁÌ÷;­dºz©Eæê~^ ×Yùj­¥öëýbE5“š�D®£êà%dYƒÞè…�?^zá)(¸ÆI^R)E.oU�Ðz…Ñ&Ä�ªkت%ƒCûöq4)‹ù¸Þd IDATä†˶t�kƒ¿¾æ~ “sàd6vc bÚ·¡…ñ+ãæ3;�‡êJLˆGµ1.}šTt+E˜·†=eªÝŒ¤3¡ û]h¼Â›²«ÐABކ¨p£ý ù&³æ]õ-�Œò‡Ü,’Ÿ÷*Ûeƒ„‡8müøG6KêQ0³e¬�1†“õ«³ÙßÊ—¢j¿¼$77þ1ÔH ÛWfòÏ-vʺ\¼»ˆ5C™ÙWÇuÃ=XøU>a�Ö…yòxW-zÕÉÒ?2xå ó¬õ}w‹Rüùz¸�–qžŒÙdeN^Ãû\FH2íÚáUó.Z�„#ÑÆ¬rÑ-ѱ_Òãawr(ÙÎ�†Ž�<é×ÑHÏù™¼qØY*¼%Ú\íÏçe¶o-b�UÇøÁþôöÊäÎU6,UúòmçÍ  욟OZwöw#ðÅKð»myƒ�­Ç>¾~ìyä×,$�‰àv½}ýT¦‹Ä½ ŸÔŠ9ƒ¤,ß�xjë¾M ¸hP Y÷Ñü¾ÅV‡�%ÜG¼ÆâúrVK[HXü ÿþt)‡ó+®�Kèüc¹éñgx pe1åHaÉ;ÏóÎÒ“˜%IU‘|:s端qW\ bZÍfÕ»ñâßþœ‰‚´—%Mv«TŠ2È_ø †Ž7àÞëA$£?ª%‹âã+(Xò^c?Avlªî†êd[‚BDO=×Äêù~µ­W ‰î±F‚QXuÊNoÓd�q—@µ+ÕËŸC"´¥¿\3ïü™Ç¯©pmĹ�ò‰qg°8³Ì|ºý¬à.ýbì٘Ϫ.þ\`b|DO@P -Xò$Õ¤:dBZhð‘¡0×Îi Ä´u£¥ ö¤B>�wVqwQIÜUÈß ŒrÓÓ)XbNÞ¥hB49Š�Ÿ¦0£†Íá=øv¤Ž{‹É*ýLÛƒgèqË*âÉsÙPjþ6yðÖoÆ�öbýÉÖZ=7õÔQ°7‹V[)vkt|×Ûƒ³YV!pB2¹ñÈ#ò¡fÄ×oå§!â¹1b½nÈø·»šÎ-4埨ŠK^ÇŽœ$íÀj¾9¸‰� oñé=±M$¼�ÿùîøÑ�‡¿ŸÁ-!r· ’žÐÎýâVûƒ:÷èVv§Øq÷0UÈ0¡�¶ôM~{Ù¸ÓfȵŒéÙ_r8²qlÜËO¯<�íÿfòDOÏR1­�üÇ»¼½,�V·¼Í[Ó»áyfo=õ_¿1›Øos±¨’³~3Vç2î îï.¬Ü—+M&ºÍÛ?ÃÐáŒ'%!¿Û–cì4©tûçx z±©ºk iÇŠ9ÒMOûŽ&âÖÛØáê:tscL[ X̬>-Ñ·kõ]d½Œ‡ªM¡F=ë•ÔC¹Ü¹²˜6¨[‰ÎQzŒÀ™„b¹²b[mü}Jet; ="uhN8è< €ÿ´—)<˜ÍÄß-º8LrçÝé^Ä`gÖìt¾²Àá¿3¸n�oÕIŠ«ïæTÈ.ÜÀMX¸u@öuç©AÔ„\>ØÖrÝ­›;md…%«óÊ7€9½�÷·šøß`#7¶ÏgÝ.'’�žöîp8É^˜|2ÙF�Î��ËN—�¬2ý†ú0J.æÕ–r�_jѾ·ÌGÒW]ûjn´´»îÞ]ýa¬gÁ»/òöš4Žüò% ÆÍà–Ð&Áj>ññÉ(´­ß6�À±]{6Y[ûvm«ÇÞFºO}‘îµì¡œYÂÓ÷þ�äÕ›{&w.Fjáf¾˜õ7Y¸Óã¾yoR$†Òm£ÇŒcð—ÿäá�1æ\ÆÎ¾‹ö:@Iaåòý{ æŽÛ{¤‡rÏÄ?Xùùo¿�Þ*ƒ©y™ùñJ²‚®áÝ{{à)÷eK“I&{ÊÜ{=èr›[ôpr÷ýÔT]5 )ÏÂÊ4O:„™ÇŽ£ÕU¥oŒ‰þ&ÈÞca«ÝäRKn2î€jU)ªçNŸ¨-—‰«Î´DHH¨$œ©)ÐR!!Ý�³�Žà -^ØØ¸¿˜¼v&¼£Œôv³°ÒE·1í�DÉ`K2³¬ÔÝÆiSHËVH«i8&Q€âàx–°r Î�¤aôp/zÊ6>Z^tÖ·ZÖÑ«•ÉnaÃÉêçÑ©„b’z¥Ç´Ë‚Õ(ã�ʱ ™s”b…|dü*XŽ<£½x2Vbý‚<–7CÀ�R˜†Æ/ºén ²G4×ÞK7|ÌNû1³C¨ÁÅž æ3GÙwð)Ùfì7|Z´¦c\;ÂLïr*EiÇ9�u€M‡¨j1gŸ¯Áà×’ g I.·…h¬ôR XÎpxïAŽ¥åbQôøGÛå*BŒÕïªjA GR ÀL›poiûÙ°ýyn­éiÂé�0µ¦•¯ÎõD¨Åœ9qŠl»„{‹H"|„Eàb£~bÙ5M)ÞP2Yöñü�g¤Çc2¶EÙ¹©’÷÷"Öf+hZŽãþëÏ n$�§LcÈÂWXrj)î�Fûîz°&p8щ¦M[Ú” Ô¶ >âÈÑÓ8ÄP¾f¥æ³ñó™,Î dìë÷ÐG(îËš&»+©v3’Ñßå6Éè�j¯¯4m$�'ËöÚ¸7ÌÀÀÎF¼�š©ä’,ikÀ¤:Y¸×ŠÅdr¹Ì£ÑK˜$Plt•'7ƹѭ…?˜‹N´0kë³ÔF5²L O T…ÌšÛËÌw¢ Cã©-ɆrÂÌšB×y)³ªê2»¬gx{Tvì·œÍÌR+ÝúxÐ] ÅIfŸiì—\îxF{qŒÄ‰MyÌ«hvÖkií J¶ƒSöêÇ9³œR ÜOG¨lá„ W¸ %IBFE)=w%7Œ2a<–Ëûœ(’D ¯£C!9_©%3PÝq¹Ý9snÀwÒ¯MÐCý‘½|ð–%@F#W¿c©yûøáÝ÷øvÃiŠ”Šº„l gèÝÏòìõW•º¥ØÙóÍ<±¤ ô~qŒŸž{�Ÿ� Ÿô.�ä½ÌS.·}ÈOt,y¨(¹ìšóo÷7‰f¥’¬l gÈOòÔÍ�ð®0TûÿÅUØãæû{ xíÉÿrÀ¬"·ÇôëùzuîCžç×—‡àå⦬¤,àÅ{?g¯ÒŠéŸɽ>��UAsPѼdá„…†ž‡Ñ¨änø‚™ç¡ïp7ÿZÁÈfeï¶½˜U™½¯æ*Wïzî]é§géÚvl;޳{{ä¢\ò*²§ÞÞ-eOo¼$•Üœ|(Ý*ù[góÞ’ G¾ÊC}¼„[ÉeN³™š%¨¨IPÉ8dfóPƒ¢M õ4ó{k˜ìcäš %ËÌ¢$•šVOÝÝd$@êÉ;׃äPHËSÈTdBüôô÷ÓÓ¯“‰?dñÖ¡ª~ÑõD’ñÔ—ŒÝ\K,ˆÅVòh“ RIà§ÝÆÒCN&ôÔл½�xK¥L#Ú#Cý@µZYtÈɹc»%ZÆúòJ-›�¯–áÂ@)œEÖqË #�EÞÝl£âé+e|%P,Nr]�G…\H&? Ž8ÉP%ü=e$Jštž|qr¦@dz òa¼ÁÊ[KÍGxñéº{H¨’JÖÉB^þ-ŸíæÆ}%¥Ðõ›¦jÍo\Ã� øð~ŽØU$C{âÚV�xLá·WŸç³Eè®æöÉ£éá‹Þ–űM¿óíü}¬˜ùÚÀ/yy Z¢Ç<ij‘[ùß+9IÃïšD/o îÑ´±Õ´-¬D°¨Eìœõ/Ÿs›)Š‘÷LfL×¼Õ¶/âû9ëYùÙ3d8fðñ”6åÖCI¯G'�Ír’ß¾XF‚W,ÇEâmêÀ€ž2 ÖþIú–e¬ÉÌxÿjN6$¯_K¼tíG2ª�Á¥Ë¶í;D·y_ÍZM–Á”®#²â¥£¤r,±-‘Ñ­p}F‰Šn‰fíqÒŽŸ @m�—Zj“¤ÊºôµÂK¯Z¸ƒÏ>\Lšÿ0Þ¸¯o¥—PÁåÉ%³þvÏÀZR"Ô�´ílkYúni¶°ðˆ7cõŒí å�-ŽrÁÙÑDG�ÊÑ)5O�»›Tò€q8X½.—™;¬$—ZëL~nÜ1Ö—Û"tL¸Ö—™üÔÇÒ2¤2랊£e¬*à´’Tþ½÷€…¤î„Géc´°¬<ŃD§ön„I�ÜÌús.DH´íáÇ»#ÜR,X�Í7—d6ÁùÄç*Onl‡×²¡jz­„AÕ vW§’ªbu”¼D¥Àʶ,¸¥��€]f2T™^mõ¸³5Ü[yòTW™­KrùËbàÉÛ°ôXY‹P’V³"ì:>üún:—E„:"¾�ÿžÚÅâÕiŒ»1¤²ÛŸ’Ìê5Gp` Ç¨¡„‹¸ÎKš;v1qüµ5nï?x8Ö¬hd/NNüþ%&«ø ŸÎ´ŽUŠn8³IÏT@ö 0ÀõŠ7Hú#s gV ø¸{â¡‘PŠ )TÀ½ô\T (T%<½=Ê_N·Íþ�?S}ñò} òµrzãü¼t;dzì‚bèíÍLìH U‚K�KFt¹®V$�/>êOOƒ�M¨lÞk!½“;;›ˆÚ–Ï1�õ\ÓI‡Æacñ~{­–ßÓ[2¶pªXª˜±ÍÙÅ|öK>wû3ÑÛÀ¤nzæ-·áb½n(`W�„¾ŽF[ºd¥¨å}9RÍ,Ïôà® âd–(]êÕèÞN‹¬:Y·¯¸ö\Û ƒ†ûórw&›�Ÿ~Ïæ£ãu±Œ ®h$-cz¹ác·2s�‹X…’óTƵI­¦T”(væ­13ú¾˜âÆ~‡Ž~‘°þ¯vÉzíŽob�íq¢‰ðd�§“5‹Š8j¬f~Ž÷df;#±Ë¬lmÄÒSM¢[24Î0P;v¶Ï¼“ñ_Vxô«Ìù˜í2^‘½™òüÜ9<šª‰äÖ7ðö—ýÉÎ7Ð*ºêãÛH\ÏœÁrú§l”`µ³ÙrN8ÀØw·w©ø)áÓgcVðù‘Ý,Ý�ɸë‚JDˆTR„K±@÷)“‰­˜‚EØkÚòã¬Cì[º’“×O%²Â8•ÓëXuÔ¦ÞŒX§ðtÁÅ˶í;jÝž—×ø<µjÞz¾š{›¾=·ÞÞ¯º•Y5S`Q7Œ†šLÐnF}‰»¨ $©‚¡1a2ëOŸ Ñ-ô Ù d«zúFµDŠvÃ{ Rñü<� ô&ù¯¸÷½­8Z]Í�¸ 2v.æƒ'ÿæð+Ÿðü_ávr™Ðd÷&IgBµ¸6窖¬ í_;ÖSf–gƒ&ÐÈØÐ’ÓYnb„Ÿ4³"·öãUEÅb«.¸Ë·[ù3¾Ä‚¦'¸1WŒª�W HµTÀô(uyQ, ùe–CÅÎÒƒ6ÈôjïF™,ЇäJ~1‹k¶XKF=·ÝÈ›=tèó,¼û}& Á-¨r ‘1¡…Çͬq‘:Gµ*ªg3Uo@ÆKX•òS9Gs¹óë~:éàLjo}—Áóûbøp£‡�Ï–‘¬‚§ŸoÕÉ©œ²s[%%Û�bÔajÜ÷r¹1nnn§Ý‚ÙRá¯ØŠST'Éø{Éü¹+£Ú˽dô£Ut{ºv�¯zr»ŸÁãÂ*ßÜ-)l^8ŸvqðD2™ùVìJåR“X`”¬’%y qÞ LYâºUG^.**ÖÌ ò«X×%ƒ?�.ÞÂdÿAŒï3›m«’X¶ôwµ‹+ñw&²jí rC®éY­�™àÒ¤6¿nooïÆ5nÝüG±K-5¾·ë}²�V‡[-ËÔN«£$�[§/uÑ}ã#LÝø ÿ}ï&ΠŘ{Ф">yC¼­ìùtóN{0𹇠ãŒßÎölºn(]K�’wO†v3²|Í66§ÜFŒð™º,h2Ñmì~KžJRV,Žc�ÿ¯±3›ª«&ãÄ~3ûûyÓ¹�‘Î&‰1(2³èhÝŠiÈ ½ªR\ƒÙ×ÏCF¦4­Yc,HªÂ¡4%\C›PœÕ}R%™Ž¡dTRÎæ1Pr-,=íEçÖ†FÉ,9¬gxŒY±³t¿ëA’AÏÝ7•îôù<öGÇì#¸â�4tk­Eã´³ót דÓÎîd•ëÛêé$±©JŒ€„�(YåøI+5.&kõÜy�ÁÉù<»óllF±MA•äJyäÝt’ªRT‡Âto x$Áí:åE:ú¾ÀÔw6³áó/XÙÿF•Z|Õ¼|ôÄ‹ü|´ \Õ¥/½Zúãå¦G«Õ"¥mæçe‡©g"SרöR�¢¢:íØí5X�M„™@ë­­æv$iõh]&yÒoÌ Ö, }ÍR¶ßG?8Ö±*щ&l(ã:»J•(¸©Í¯»±þÜE[—°2]AÓr£;ÕPÇ]öÂÛCK…5–�W(,,(ɪäé�g©.–Ü;ñ��¾¤Ûòl>ž�Ý8‚¸Á#ÒÖë�Ù¼ýû)Üûþ‹ @̩ɤ+:„¶¨ðò«'88YIåtª¨pyÐd¢[ãŽ×ØO0oÿœÜ}?¡Ú‹�tîèÂzà5v&²éW£t�’ká¯D/⢠í)ÑÛ;Íœ³Z¬¬ã®Û¸3DâÐÊtî­ˆYŽFÏÀ6%�A©)62µl«rðh1™=Ü ˆ2Ñ×XÌÊ*ª[ö312TBuÚXw¬ÊxT'«Xy¨µÝÚð·èëö3K2\~AŒôcz˜DÞ‰<›_ÄñzUÝ\ñhttj!¡šíseæ@aÓ~ 9W™wµsç[È,»Nôz&÷У·ÛXïâú@¢}_nõ±ñÙ7Eœ¬°SA–ƒ,L´ö— G$Zj‘ Íœ8Gö’æ¯.ÙÈõ@§6³©p7ÛâŒê£lìùþæµ"‡ ç¥÷ždTXe‘aß–ÅïË›HtKn¸›€l±w~ćü›ÔÕ­ëhF·\ÄwI³xK!}‡9ºf-'-Ñ#F”'\œË¯»áXؾf ùŠLXŸ>ÄÔ'%¬�t+gÒrQr±¤�–’Ž ·�P*Å0Bè9n•$Zãùî½yœ0öæÙGFP’\Åf.FQ%ÜLn® ƒÉ I=C‘E$-¸\hÒ@JÙ=ð"¨:Yœ¬Ù[Ì#ÑFF÷Òà¦:øß>[•ë.Pl9©pw¨–Ný|¸=)›o“+Xó4 ÷ar ¨v¿ï®©Ü|ݱž,â×4÷…yd”‰C Ì$—šˆ$ƒžÛ®ñ ƒr±À…oLö [‡»10Â�©v~’ÊÎrs›"½x"VEÞ_P(· ÞÈžZ´ d9ɨ% ÿHŸwãÙ¾ÌÒé™o#W«¥O7FÂ�µùü‘ãúX}°O_­%~]:s«ir¤XX‘ãÎÄÞÌO-$Åǃií$Ní´p –ñ\2îZ±c)[~s&²yë´ÄÝp'#ªZõTòÓR17Õ3]LË -R’ƒÔ”38ñoÚ‡Œö*ÆŒŽá§/³yõ6 ú³jmŠ®cF´”—MQ §QزiW!ŠìE×15ŸŸr WµõCÞ›Á±ø£X ª¤Œ’ÉÁC(hˆjS}{%¬Äÿo?žpãê'®P„GB«×!NGåu§Ý�нx™¼l¸d²—4ùÇͬ)22ÞCÂyÆÌâ:¥ÁS9ðw.?Dús[°�ûnkÁ¨Äbvg*8 ®jåF¬�„¤8Y¿"‡9D°äaâ?Ó¼èTáíÚX¥ßº—?¿Å�ýÜž�Ë´EÅ%®$Š�ÐgŠ]:úò¿P':È“5´�2ÐÁS™gæÝåf—e¯Us1KŽ) ìh䦎’­˜Åñ®|Ãe÷0•~ê ÕE©ã$ íæ‚TËïTëOXñÉ—¸.­Ðìþ›µ5  æÚ«¿bÛšmÌþÐH: ¹f~âFtQsÁ-Ü¥ŸH YÙ¯%á®J›VÀÐe×Ç,aÖ‘uÌœ±ŠvO£l±H5æû÷~"Þ&á=èFÆEÔ"¹mÇùñýŸ9¬ëÊ“��%¬Ê®Ú6éä¶€Í{ö‘¡D,öãìØ›¾ýèÒJˆîË…+Ct;‹yíýd^s¹Qe×ò4®®aUÙv(›¯»Þ¦Zí,\‘Å•�~ZZ%p(dæ:I+vmRò‹¸ÿ͆§1§›yç3»kiå#㦪¤g;H­¡¿JÇËaô5¬Õ—¡:™÷¿æ5x„AÃPì )™M�ŒR¥¨ÈÉ¥ŸtÇÎŽOïæºoªXÚlfòó )vª ɸnjç¥ç'ž�¹’C22Žoî õÏÿðpñx†·õÀš™ÀÎukÙe»š—Þìɲ‡Þa½es>û¥g{úꈿW­|e¶žIcþÛ¯PÔ£x÷â¾i½ñ©m[ð5<ùÐVîw#»¾|Œi;†2²W$þZ+ ;Yµz'§-:ÂÇ>Àm±õÜH^ô3ÿµ‘–VŒì c{{Š—APÈLÏÄ®‚ìp6…fMh"™üäíl~ü+v¯ü?n‹ÿ‹>Ý"ñvf¿u+ñ™v4ÁCyò¡!T+’ZŽ�ã¿Ìà»Ãº?üª*n@òêÏ�£BØðÇ÷¼þµ7wôò iÙlæ%éépÏutñÁ— W†ènnT•Œ,;.c›‰â"‡/}%!ê„Jq^:iÓ¸H²Ö wß–D·éÈÕCÆpݰNTZ1— ÿ4¯�ù?Þœ·›K¾ãÀ�d#Á]'ðúSw20ØAðä%ìÿï>Ž,üŒ·vßħ:⯋eò½ÃØòÎ N%nd~¢„¡[+¦OjÛ&i û³~fæìßY·s!ß”ÅÄI2ÆÀŽŒ›~÷_×`ë´±ëhF…-æ‡Ó*ÁCFÑ£‘¹×W *æ‚BT@6šÎáƒ]‚¡í-¼÷¡/Ÿ}ô_þÚ»— ö i<‰t+�ø»0ýi܃ˆŒ®á˜Z¶•öŠÑ/œ¶~áõkí($/ù‘e*¦î¸6JnÁù@ÂÍ·%m}[6k/²›7�µTž\Úˆpo�@ \"¨ÅÿÀ¿gïÅ"‡2þ¶%Ag�@p ,Ý�@ ¸¨QÒ·ðÓüݤž9À†uH³ëisó“Üݹ.^¹�@pq D·@ .jÔœýüõóN8%dcý¦ü“g§Åá!\^Á%„Ý�@ ¸¨ÑÄLaæ÷#Èwêñk„·Aø”‚K!º�@pq#»á�ÿ…‡@ 4‚z‹î­Ï‡5Ç8jeËÖml}þ—�‚º°ssÂ…‚@ .2.‰5º]{ö\è!�@  æ’Ý�@ Á¥ŒÝ�@ A3#D·@ �@ÐÌÑ-�@ 43Bt �@ ÍŒÈÓ}Eᤸ¨‡¤Åh2 ¹Ðùhó"¸B±�™_Œª1áëëÞü„óÝßÅLSÏ…˜[�à<`#?3Ÿbdܽýp×Õïè+亴‘Ÿ™G±¢‚¤ÃÃÏS]”•½�Ì\3Š ’Þ?c-‚LÅšŸE^±ŠÖÝ?÷sO­Ó’CZZ:9EVœè0zúÑ"$o½«ÚÆv ²r±8ÕÚÕºãççú†«æìfþœ-dõeÊu]ð–šw^T[>gRÏ�]`ÁŽ7_Z„´ÀçÕäÊç¥ÐŠSÖcòô£Ep ^—ɼÔïûUm½Ï3ì…¤§¦’‘gÁ!é0yP·ï$¸@“‘xŠL+è}#ˆ r£¦³C-LáhrŠÆ›ðè`ÜkÜÑLjB¹p lM¤ŸÛ¦¸áå5ØÃ&ñÅÿA§f~"ض|ĤWb9Oý�ÊçUÂ#$šp¯º- 7õÜ_–s+\lضðî´WXVÂä�¿åÑz^hWÆe©¤²õÏEÄ«€ŽÖC§pm;Ó9RÉÞ»˜9[2PMH?¦LŒÃÛÕÍ™OÂÖÕ¬Ù“L‘"Ðó&&õô¯ÙwÇžÍáMkù;>•"gåM’΋ˆÎÒ³žp&³yþ"YkµìÛ�›&]MPµÎUŠ’’ÈVd¼ÃÂð”h¾yQŠ8½skv%’k¯"†µ„Ç`hïHª=›ìÙÚ´–�.çÅ›Ö]0¸{—ê¼4äûU¤¾çv²m`ÅÆÃ¤+•¶hL¡t4Œ¾‘žÂÇìbDu°ó«Çye�…ÿgï¾ã«¨òÆ�fnMrÓ;é„4JB¡ (Š ¨ «¸<®å±`×}Ö²«««»–ý¹ëÚví,»Š®½+6:H $@(I€Ò{¯·ÍüþH!¹i7‰÷¼yñzÁ½3gæœ;å;gNѧÜÃG»‡?”BÞÇ�qÃêcØ´ Üñï¿sM˜ã_T)ùŠGoy•L»‹�ÇÎ$­,£È2Ò@žù„žlXýëßóeƒ–Ù~Ä3‹L½> �F”ýiìv;ÿÇ+Üuçmh4gw­€ÒRIQµ‚wp îÿ‘Öq¶•óY°‹ÃÍJQN. q“ðèëB§T’s¤¥�E,UYlÝð#YUVt¥U8ôýçlÌoEv'eÊD¢üMè”6êJ�±7#‹üôoø´uWž‰Kçzv  ¹âŒG/×#Ù̓Ãý0STX�]r%4ÔQ 6\åÒFþ¶/øú`-vÙ…ÀØñĆxaTÛ¨->¡c•îýŽÏ­KX>7 ÃÉtë8øÝçl*h�7‘âˆô7¡³5SUt„ÃyÕßý õ–K¸röôg[¹8›¿ƒ>ÎPiÌYÏçóhƀ߸ñćùâJ •'²8t¢„½ß}‰}É/˜fè?9á§%¹‘:c"†­i˜³w“Þ| ‹ÜüðJ9»÷äc°ç²+½†«ÃüÇ*µ{Óɱ�ä’Äì¤öß\?÷aÖoxxdó"8$Êþ”C‡óô_ŸÅÕµ½rãoº…ßÞÿ&Œ†÷ÌYvrßû×ÿÇ�»Ö<Ï/ƒEÕÆÈ8ûÊyXƒî¦¦&¶lÝF~AV«�NGxX³fÍÄÛËk87åÙ _ϪK³9R7‘©Þ½G/ö²#©Sqñò‚ú:,=–P©Ïù�Ï7£^õ jÆ|‚Š`GaßÍìÅ{I+hEÕ3ã’Ťx�:HüC‰ð�w¿>L}ö%EœÜGÕbƬr É,$®{TÖk…e6$CaÝ«{‡±\ìå{Ùz¸»d"ö‚ËY0Ît*?‰øÀ¯øàÇ"ê²ÒÉN%©#�hËKcGa+ª>˜YË.fŠ_—†R&—þï*£æP:G&3Ñíì*góçìq†9Ÿ�;ŽÓŒ�ÐY—qI’ÏÉ“=.a<Ñ;?㳌*þ¸�øåÓ ýתÿ2^S¦3^·›Œ¶ìÜofÑ9ÆK©õì̱!¹{âÞÜÀáÝ{iZºÀÁb {÷Æ¢Jg0Õ$ªV…3«¨¨ˆ;ÓøjíZjkê¸ùæ¸xñE|ùõZ~÷Ð#øøxsñâÅÌœ1�ÐÐÐ3¼Çƒ 6�•UŒBì™Þ“Ÿ·³°œ‡-ènjjâý>dòä$æÍ�ƒ››ÍÍÍdçäðÉ'ŸrÕò+1™Lõ9'¹¦§®¶ŠœœJRfôòjÝJÑ‘\10nŒ/uu–Qi(+¥Õ=†sϟˤ•Ã%ým_¥¾¼‚dßHÆzöܺ>d,¡Æ,·ÖP^eïŽ(Òbnä´zôN¼u³WRlVÑF„Ü£áÿp•‹BÕñÔ+  NbF´©[:2Þ “ˆÜ]Äs%e•v’ܵ€�’…´©nã¦�ä×}µøOœ@hzÇí•”U«§‚Ò³¢\†�?§Ž3h=q˜¼Ùk<3'ùt;Ñõ§¤�õ-9µÙ.™J`èÙý*÷çHHeF´†Œ¬&2vÆrNJ�7 -ûöpÀ"áwÁ¦íx�µ™{Ø×º€¹Ý[C™²k_+ª¤cÂŒ)'›=©M%)nDÕûé�Kçç�%)i× Æ…yb+;ȶ=Ǩw‰ã¼ù t}þTZËÉÉ<̱²:Z=^Ac™49Ž`çžäœIOµÔ�w8›Ü²Z,2?ÂcÆb굎3ë §^˾ãóβרm”Î ãXMН1±¤$Çà7È {}1ÇÊšPp! *ßÁVP “›o¹�ܼã�œ<™»ï¸ƒää$dùÔï{éÅK¸xñEddìcÃæÍ|üéçTTT=6Š7^{yÐÛŽ2µÕ�™™CAEm’Ï€p&%éÙõz®Ò\–Kaõ!väØPÕ6ÊórÈjÐ`ð #Êße`/*Üy0ù³Ö哹?›Âêl/Ââ“HŽöéqÍéõÚ`Œdb”+v›„k@$Þ½ô0TÛ(?^@�UÂ-0Šp/-JC GKÁ5�è0/´¶zŽØÏ¡‚Z,ZAQ™ˆëɬ®œ�ºF)MØËþU´¨.F%2uÒÜz_c@†-èÞ²u“''1%%€ÿñwßyÇÉÿoÙº�Å-®Í9IÅ=b,~+¨8šMIjc sÙy-`Œ!:X%ÿ°£´$Ü£çqå¬H|tmÚYn?$�Æñ…]Ò é8¤. ýT‹‹ ’NÏ€úÛ�F¡¦¨˜fU&8t ꈩ\dü§,ãÚøÚ$“ãöï#® Ì ¶“�µDÎû7Loî39>(u.¸h%°© œªå=;ÊÅùü9wœÙ(-,Å‚„{x„ƒvì€>„È1Zrr[)*¬B m»G9˜™ÓÂx-ë8Õé{8jOaÂiÇŸ™Ì´LZÑ35y1“k?áë�ûØ™manÊé·J[ÎöÔ+ ÇÌÔSÍO¬é«Xé 3Ÿußjn{dÖ¤»X³²‘Çï{“C-*ràeDÎKÀ[ (uì}ÿ9þòÖ�œhQ8uÔJÈ®aœwý}<°|¢ãë€#Τ§6“õÙ <õÏ�k´sÚûÉ@PòeÜûÛ˜¤Ú:# ×²Ï|‹;úž¶Ä;x÷ѱ|óø“¼¹¯ÛÉ•ÐÍä®§áÊè�5 Sª·óô=âË"‰¨e�ñ�»ÃG$O‘›wœgŸyšÉI‰}.'Ë2S§¦0uj{ ±o&¿¹ï·NmsHej)aê¿òü§™TXNÃ(éýH^v'Þ<—0=€•ýÿº—{¿mì8®ŽñîCwð.2aW½À»·Oè?èrâ<Rþlål]õ4ýxÿéù“tø&^ÆÝļ.çBï׆‹¹aüVVolÄí¼ßóñ£ç9l’©”|É#+_%S‰à†Wß`¥Xv¿ÆÊ?mÅ>a%o>àÍšG^ໂ¶Sy—4x�¿Œß?v+sä�—³“×([ñFžyô9¾8Ötêv,ɸÇ\ÌCHAêçEs_†íª’_PÀ¼¹s~Çî=éõ©!PÁ=Šq»)/Ï#»p&¡‘=ŸÆZOáD¸&ĦÍé¥�®„Whä ·/á„Iª ±º”Rs"îÝ"=µ¡‚ÊV4þûŸúyÔŽ]IoèñäÙ/µ‘Ââ:Ù‡ÐG�|†¯\d� î^.¸÷¶/mµÔ´¨ {âë¥é²ž7]ï7¥¦¬ý‚ ñÅßçTxxö”‹sùsê8S¨®±2>¾>½Ó:|}=‘s«h¬®ÁLà©þÂ(¡!jz*cÖ§°4�]… "»üš¶£ìʨGÑŽ'yb‰UQh¶!}w.ö”„.õvŽïÉ BmÔ4fŽéÿñJÒëÑI`iÍç“׿'Ïcœ…§k<Þ2 6“ñÚýüæý\,®c¹ðæ,NÇS­%oÏZÖ¼¿•õ¯üŽJÛóüýêqô:•žJÝæç¸ïÅ ÔÙ{õe\01/ƒ�¦Ò¶}ùßì}Ÿ‡6ðÚ+ׯsv�Ÿ–¤Õ¡•@mÊåý'Þaƒe6+7ƒ8=­¥ûùü­ÙY¶ƒ<ó)©/ý’È~~Nµé o<ô$_©„.|ˆçÏ|ÂŽˆ §¤¤´ß »»â’"#"œÚ¦ÓeªÖ°é™{yäû TS —Üp$†àE#™ëyû�ïÉøð îizŒÕÌÂKÒ½øNŒJã�×דOÜxÓ<5¸E‡ô_±áäyå|þêøñ¹{yèëRï ,[¾˜™QÞP—ËÖOÞgmæ‡<|Ÿ™g^¹›éMA{¿6ŒgNªÌ—›¿ b×÷lª9—K}»ßUŠ·n&˺„ Y8®ý*%ëµÈØêöòÒ£8â³�»¯Ke¬—L]ÞN>ùÏ×dú˜GõâŸÿ¢µ(gg¯Q–lV?ò4ŸçZ1FœËu×_´PÌGØòñ;<ùÇA[dÌé5œj¹G ±H&âBѵæ ëh‚&3=êëòòض.—y‰„¹kK}>é÷R®ÈxOšÊxÏÓkº­*H:‰¦ãÈÊ£¨ªžV›„ÎÕÿ�±LLšH”—ƒ»Dk1…U ’)„P‡í’ªr±P¼w?E6ÐÅç7�+¿Š¥ö?nØO•"ã51…8�ŸS¹ô�?§¨Í4µ¨ psëíQDÂÕÍ P››hVÀÉÖÂÒÆÌ`ºßGVæ³{O%×Gžz#a?±‡´JMD S´„$'¢É¢8=ƒ%�¨Î•rvï)ÂŽ†ði©ýiÈZ4€R´‘u!—ñÂê›Hì2¡-çþöQfmW=ù<÷$Ÿzh�Ÿ˜Ê¬˜¿rýÃßr`Í*¾»ð).u<ôÊ©ôŽ8“^3»Öí FÑÿ«?ñç«Ã»5Ó9oÁ4üoû5ïU¦±-÷WÄÇkœ\ç'&KÈ€=ï{¾M¹�ן¿œ¨“§q*Óƒ›Xqß”ÝÎŽòåDöÕyÌ|œûoæX˜w/ÏÞ7÷Œ÷ߟ�@Vv6‹/Z8¨õ²²rHïÜF�,Sóþÿð÷ÊQ4‘¬xòYîJr=y\ÆMHaFŒžîÿ‚¢ï^çÝeÓ¸-NK`Ò.næÛUëÉÇ›‰ósé;ø9w8Ÿ?Ëá÷yñ›Rl†nyæ®�î\i:sçÄc\ù}Ãë_]Nꊰös¥¯kƒ-œEa_ófÁ^¾ÙXÆÅWŸþ ¡³qÓl˜ºp>§Z’Û÷¿xû“naÕ3ˉê¼eO�ÁÜ nÜt÷{äfÌ»»/ãá™.ý–³se©Ò°õ=>ȳ€ëîzúa.ïL36žäi‰øÞ{/µ¨NO-9b§ßÝwÞ1RI‘„):ž=˜ ³9Ö|ú{µ!—ì²W qA#pÁ•LÄ_°”…“Ã1”§ñÙšU¼öï·ø×¿VñÆ;kÙ×àIÌôÅ,›vZí�ÅbAìé|ýÝN×£è]qÓ«´Õ•sâоúðc6ä6ö¨iµ”Rf“0Ž uÜÔ }ÇF¸\ês6òý�Z] SçL¤×~‰J5Ö¯å˯¾à£÷Þbõ{?p¸Ñ�èi‹¹ìœðÓ‚Þ³²\‘?§¨ÌТ룦N×ñeçÛaÒÇ3+ÅYµ’µ{/õ'?…’ôt í2þ))Dj@36™oûñ=ì©HŽÒ S®^Á¤Óÿ¶rðû8n—Ô«¸nr÷·D^3¯bYŒµmßm«êg('ÓSZhh´¡"¡Õ:¨?2ijrÕZ6}þ7uÏάs†¨RK®»¸KðÔÎeüd&$°WRRÞGÉÚËøîé‡xqO^Óî็vjî»;gö,vìJôz;ÓÒ8gö¬!m{pejaßúÍ”*ú¤e¬˜äÚã¸tO¹œ‹c´¨öb6m>F·‘`ièçÕàògåàºMÚÁ5u)—�=}%Ém2W^Ë–^Êt? ÖS»ÑûµAÃâ‹bÑaåÀwëÉﶃJá6µ�ë–œëß3•½™¿âÒSwçþ'\ÌÅ ZPêIÛ•ƒ­×2ìälYšÙ»=ƒfUÂuÚbvXÒGrÙåÓ{Ÿ aΊ!ÃBCyõ�UCLE‡Fnmÿ§1’ø(òrJÈ>ÚÀ„Éž?ˆJÍÑÊí2¾1±Èô;d 3ì­õÔ6¶`¶«È:WLn®èT vkm–fj*©n ÅtrÀf‹ÙÜÞIãAtêfM ÅS'µWw‚ôM›H/©áІõøø.e²WçQa§¬¨+Z‚úþÁG¬\¬T\Ç×ÛŽÓ$y1~þB¦ú÷µ'mTås¢3ÀÕš� 4À“ÓçÕ9[Ëe ùs’ªv´C“OöpD’ÛkU‘ã\F’f$ãúÝFš¦‘Ѻˆó]µŽŒÝǰÉîL™‹@?žé“]ùlývîmàŠE^H@ËþtZTdï)ÌNìôi±LIt;ý†¥Tp0«  ‘‰½´Ù–CHœàƒœSIΡcX/ 轉‰³éÉ>L„f!‡Ö<Á_Œ7ñ?ó“wïÒlMîv8³Î"b˜ëàM•Öw Ìmרuìzù÷<µ¡·¤øÛ—1v”Œ :5%™òò rŽ%.6¦Ç÷¿{KÖ±Ÿ?�ý'ßÁôiNo{Peª”‘•S�‚LèÄñŽ›äÈÁŒOðDΩ¦ôh. j|ï•Iý†ójpù«àpN5 Ââbé9 ‘LÄ‚[ùÝ‚^ö×ѵ™°‘òf6»r×ñÍ‘_r{|çÝUáĦͳÉxž·�9^=3(éâIžèà@•ý‰‹ñF>PA]~uêdüúÂ×ɲTÊÈÍoCECXL´Ã&—.q ŒÕn"ÓÉ'¬³"è^2Ô˜J>ëþ½–,‹wÇzÂã¢19HyΪSñ“ikùh Š&�øXï÷2 µ9—õŸý@N“ž�)K¸"%�Ž_AµÖ’—¶žu™»øª¼�Å¿8�( ¯¤e¬œ¨‚¬E§éºgz¯(f^¤¡õƒ¯9ÔXÊþCeLšÜ^£¥TRPÜŠª !lL­žG \”Fò~ü–VbÕ�|áEÌï~¢v#0åâ+H°Ù°¶6RUšÇáÃûØ|ôûãÎcéy1뜥å2àü9Iê¶;ö>. ŠÝÞl˽têF×”é$»lbkË~v4sþ4´ìg×! SI�Ôy“2’4u†õid¦ eÑÜ0“¹;“VUÆ”2�Iƒ ¼$ƒ/þÝïÆJ5Uí�i'>z˜«¿u|°ÚêëPQ1WUÒ ÐËä>CIOK¯àÆÃ�°j6Ÿ={Ÿ¿hbL\"SR¦2sæ,fŽÀxÚî;³Î™!M˜Þ¡e:Ÿ ‡Ü­^ó^ÿô8}"·ÿö—$Œ¢:�Ž˯ä­5ïðäã�õøÞ’u ßk—#éõT­z Çÿ�5¨2µWSY­Zü�} ÁÏ×™j”šjjU†tý¼Tþ”j*:òçåã9èxÇáµ�}çqéÌUìÞPÄ÷ßâÆø¤öû 6l>ŽMö㼋RŽ"¹ûèðä“ñöñD¦¥©žF•~‚n'ËR©§¶¾£L¼=–‰ìí‡Ï®ÃöH¯Óéhnnvø]ss3zýŸ¨Ú1qÄxÊ(5GÈ®hÿqì¥9­SÐ…Ä3ÔvµÙ)ÉØÎ‘FCÄlN;pH:o¢g-`z�¥!‡º¼>’µètºn�e†PÆG{ ¡ÒT^NSÇ™¥ÖQÔ¨"û†âÚž†µ\Ìe¤¯ý„oTbw˼eK9§¿€î¾þË䙋¸êò9DíÔålfcVÓ© ÇÙX.ƒÉŸ3$#Fƒªµ÷š0TÌfsÇâ.½L$Œ’{ ³tHJ={ÒŽḃÒÙ×úø©L9ù®SÂsòbµ*ÍûöpÐØŽ’¶·E2�'öòôo0ô: ™¶³œ­öþËÙÙ²T-˜­�ÛÓ9.��ìü sØjºÃÃÂÈÎÉ99D`WYÙÙD„Ÿ¹!Š’ˆ�õa_Z5GsŠ™Ô>Ö²j`lÜØ!�Åè�RKQI3*ÂCoCr'$Ĺ´†ºÒ2ZT?¯}®ˆ«›+2õ'‡ÑCRi*.¢F‘ð ÁÁÛœž†©\Ô–¶}ýû*m¸OeáÂTÂÜöFã�@ʸ 6Q|¼€¶ ã8ÚÆè*—Þ8Ÿ?$žî4YillEÅñÈ,M M(€ÖÝc€Ç˜pFÈ>L›‹6ã ™™*ñ4ïÙG�¢!nêd|»T�Èɤ†iÈÌÏdß ;©º öT(Hú‰ÌNàôäý‘Œ¸¹5:&ý°Ôwhé5=�ñüŠ/øª¹†Ü餥mç‡ï·“}ô{ž½¿ÝO²´kûLgÖ9K¨Š‚{âÕüázo?ò:žçñIãøÛ²ÐQójÛÇÇ›ûîý5<ø{>|÷?¸ºž~µ«~볿›~uòÿ5k>øiwR2bìè`cn5÷z5·¶m'�C«¼îójÛs1¨´µ¶¡Ð}^ 瓱(t-oýÈ7»š˜už G7m&_ѽ`½¶r3wLv瀥#–Œ†þËÙÙ²Tô:ꇭf *=+ Õ¶Z矮†íŠ2kÖLöíÛOzFÆÉïææfÒ32Ø¿?“9çÌ®M  ŸØx‚4*ÍùÇ)m+æè‰Vp‰$!rÈ]ÙzaÅÒñˆ&÷ÑØ¶s|nÕf=­Ã€j·bëµÆB¥µ¥µýä7t”fŠ +±K.„†ööz¬ÇÖ‡^.–2Ò¾ùž}•vLQs¹ì’i}ÜJ=Ç÷ífû�;È®é-ƒ£¾}´�n'æ¨/—!æoÐ$þþnH¨T—W:ît¢6S^ÞˆŠŒo€?£ •Ð+™à驌ՀýÄÖ•±ÿ`Šf ©Sº C¦‰ 5ÅÙ^Â¾Ì *÷ï'ß.¡‹ŸÎ´=]€&ˆÐ-6JKʇØylxÓ“ >Œ›º€ÿ¹ýQV¿õg®ˆÐ¢6¦óéú¢^û-8³Îh&\ÌŸþr³R®àw͇Ò^ý3oæ˜Ïô®�fÙ¥—ËÃ�>†ÝA;8Ù wøïŸŒHH °QZRÖËqi£¬´ ]`pïM¨b¸Ï«þÈ„h;¥Åe�uÕfÆlsâf¤�cñ¢tj;7î¦Ñz„ ›‹Pt ,^Ñë=Wm¨ ¢ÍÑöìTUV£ ¡ñõ§ß�Ïœ-KÙ?/°SY鸸RZDé~œa º½½¼¸jù•”—W°æ�ÿðâ?^bÍ;ÿ¡¢¢r”ÌFÙ“ä1Ž„PjsÇ2s)h·è¸‘ëá-5rmÎ IDAT™ðp“…šªš^+55í#mhMî¸J€RÉî�þÉ+¯¯æ³Ìzǯ=•*òòP�0¶×\ZK)(³�~ a�oµ;´riåø¶Ø]nÅ%l—^8ß~«W¬”g§“¾?{r*{)—6*+ÛËEc2�eåâdþœ&Ž›¤b.8J¾ƒ{­ZwŒ# È~DE:n»&ŒrØ4f„hP­9ìKßOæq;²O2ÓÆv?~µÄOIÂC¶qäà>ö8ŠUÕ0nFj#ô ’äMÒä4(”¤í"ÏáS�BUÖ.ö5õÃs6=s5¹û¶²vûq‡SFI‰œ7Õ …ÚêÚö¨3ëœmt.¸jd‚þ†#·eóï'^gwã™o4ÓÕS�ÿ‘¦Æ&î¹÷›N~ÞÙ¤¤ú­¨Zõ6ÞW-;Yëý“‘ýHš4 eééä;:�-Ù¤e¶ J:â¾�p‰÷yÕÙ‡ÄÄ�“ù;Þ#A;GÞ¼�ù,`þo×R3¨CG&üÂE¤¡yÏ&¶ìÞÈÆb—ä…,èãí‘jË&ý€ƒ3S)âPV# 2á1cû/ggËR$&Ê …âƒYô¬#S(Ø“NáhºL&‹/ZÄ­+oæî;ïàÖ•7sÑ¢…£2ànçÊØ¸Œ4’³?�Vɓظ1#÷ N296-*MGö°¿ÊÚcKÙ>öæ[@2Ú>á‹ìCXˆ+ªj§,}éåÝ¢(¥‰ã?nb_�Ú&ŽoË÷äç�¡ôÛWð4Η‹µh7[rÁ%Š9ó'á;�˜Vö%6Î- µ7óc~S·›�•𬭤ZA2u–•‹³ù혉Lò× ¶åñã–£Ôw½HX*Hß’A¹]Â%*‰ñN÷ü~2š±ÌLõGVÙûÑWd¶I˜&Oa¼ƒÅ0i IFh=ð%e¶ j˜9mÌ0^ìe"^ÌW û‰Oxîý£´t[œÿ%O=ø{n½æVþžÙ_[\çÒSj6óÌý�ñøãÏòvvkÏàÆ|œŒƒ5¨’–°ðöñ‚�Yç¬&yqÎÝ¿å—Q:l…ŸóÄó£«}·Ñhäå¼@Ș .¹ì|øÑ''¿«YÓÞ¤¤öýϨYóÁ0µé ±‹–0Ñ(aËûœW¿+éöÖÐ̱OþÍÚrÙ}:KçŸC_ÒhÚÛ;Ûk¨êõífwÃ}^õŸ¿q^ÄD£„ýøg¼ôE]ï ¶Òõü{mvôLœ9e`Í0»æÆï\.™aBjÙͪÖSŒ‰™Íé³¢¤Ö³aÍd�–q•ºòEž IÁ¼9(ggËÒ@Ò9Óð�U,û?å�ÌÓûvXоá•�rQFC›î³•1"ޱ.¹n±"ûÅ7Ð÷C-9|ûie'g[k{dS›ùoeŸJGv¿<7 žç03ÿ ¶óã§ïSM¨¯ =« 9š[B£MÆ=›ÙÑ�Í4M™GrÑפW³ãÓwÈ cŒ· ²µ™Êâʬ¨²Q³ç“äÝ^›^]TL‹*2èöÁΕK¹rhPk ;>y›},­{WÍEƒ„OâèFJü8w²2› ˆ�=­SR_TÅBKc#� Ýnn¦±Ë#£¦µË󱯗ÉK®À{ß.ÒæQ”½—“_Jè܃IHœÆÌI!§À®쥗á½{'ÙEÔ¥¦sEI‡{p“§M#1Ä­c ÔFŠŠêQdOÂBú>Ðr¦\T;VKG•ª­�ÆFG/p»dé´rñ#¹³\§¢ü9å�_¶—Kì¤iÌH ÁÔu_ΆrBþœ>έ2—,saǶ4—s´¾¸ý Ù€oôfÏN!Bô eKÆ×ü+½ã+IÆÅßp#·]ž4ÀᵜHOrcÊmã9¿7xõãÍ\ÿ ™ë:Ó“�]™¼ä¹å¦e$uLaíÔ:¦bi®£Æñ ^íôMXF¼±nO†q¿ä·ä¦çv±ëÕ§x3áYnˆ%wwHžœÄ¿ÞxíLïF7z¢—?Ák~oñâê¯Ùµþ]²:�I�oü®¿ùfVLéÖ7H7‰+Ïg×_×Qpb;Ÿ��0¤Dpïèg€‘á>¯úÏ_ÌòÇyµ#i»×òN´Ÿ AL½âzþïÆ ëd|ï’¼ˆ…!ßðv¡JÐy ™Ú_ �Æò?]Á¸žã­ýƒæŽ‹’Þ�ä_ÜÆƒ·Ì<}Ìí>ËÙɲÔDðË?ýå¹çø÷–ìþú]v’΋ø…¿áÉÛ£øþ¶Ï mN W#ùÝð©ýÉ¡àÅ[ú\8+3ƒ”s½¡7 æÆ:ê[ÌØÑbpóÄˤïÿ‰RµÒ\_Oc«´FÜ<6œYGøïe£©¬�ÂÊ&,²Ÿ1a„xû¼nÛ›+((kWo‚½0ê²;ÜçUl4–Q\ÝŒÍàMhx0^CÝXËþßu¿ã³ên|ýunçøýŠeë“\ôÈzZC®â�·na‚,õ%äÕЦ5N€Kï…×9;W–Ö†ò‹kiÁ•€ðp‚Üœ{?~×ËtÆÙâòrFÉÜ}päj’7/?ܼúZȈwð¼ûZdÔ’1ºû`üÙ–‹“ù­«þ®}Œ 8IÆÅ'ŒXŸ°3˜ž7ÿpbý³gÖþ{i1E‘4ð54nDE;»½á>¯ú£Å=(’øAä¯o Åßþ‡ï+U\§,å’�¾S;*�õžcˆñ3 uú/gçÊRç1†qÛ‡�Õ]‚ ‚ Â0QiÎz›?­Ê¤UÃ¥×. HD›€¨éAA†H©ØÅ»Ÿí£´üÛ¶¢ÌªgÜòû¸)Ñé©Þ~vDÐ-‚ ‚ ‰Z{�¯Þ{Ÿãv Ù%˜ÙWÿ^“$f<îBÝ‚ ‚ Â�hb®ækÐ`×ã€ç;ìëRnâõ^…¢õ&ìg•þ̳'‚ ‚ Œ8ÙˆoH8¾ƒ\Mr $::pDvi´MÛAAa„‰ [AAF˜ºAAa„9ݦ»µ¥¯¹nÆÅÕmXÓadüœÏÕáÎ[×ôA¡“ÓA÷pßXÄ�JÎ?çsõçœ7AáÌ£—‚ ‚ £–Ú9?|I:;ÿA· ‚ ‚0jt ²»Ü�Ÿu ¼Ï– \Ý‚ ‚ Â×`«ªŠÕj¡¼´ˆºªJ¬V v»I’‘e­V‹F«E’ä“A÷P‚oI’Ñh4h42.®&<¼½q3y =S]ˆ [AA8£TUEUUì6…ù¹ÔVUâãÀظ ¸º™0]0·µÒÒÜHey)5•xûúájr?|;x«ªŠb·£( fKÅù'@¿€`|üü‡%�"èAAΘ΀»¦ªœÂ¹…0cÞhµºËjMÜñƒÍfåøÑlJ‹  E£mk� ¼%IB£Õ¢tz=n&°Z,TW–QS]AXD£ë�ò)ÆéAAΈ΀»¬¤�¢ü<&%Og\üD‡wwZ­Ž˜„ILLN¥¢´›Å|2½á Óëñòñà7pâØQêk‡”žºAál`i¤ªª’ÊÚflCù\F‰Î¹¼´ˆÊ²&§ÎÆÝÓkÐéxxz3yÚlª*˱Y,Ãx]Ýp÷ô¢´0H�·h^"‚0Z©-”æQg“0GæÑw=‰ÚTÊÑâì’;¡ãÆà~rq…†â\Š›T´!Œ vãäËדÛè6$2½w/ü½�h†;o?9sÍ gŸ ¨¢Žf‹‚F_0Q±ñŒ 0ŽúZ(Ë®¹ê‘õ´†\ÅëoÞÂDm?ŸïxŽ_<º k·Ïa4è Œêk)-Ê'yÚì!Í•àâêÆ¤”éìß½�À°4gôp�l¢Óëq÷ò¢´°½Á£Ñ8è4Ä)(‚0ZÙ°ú׿çË-³üˆg™èëöaÝ»šÛYO³n�ñG¸t~caÇ+wñèV+n 盇g¡ï± Åq¢’ŒÞ=˜ø”™,X¼”%ÓBp=;Fçê Òœ·ŽU/¿Éé¥4+=k¿$ÙHÀ¤…Ü|ÏJ–D»ôYÆgIF+Ë(²ÌY2¢šð_FQ Oä26f<®nîCNÏÍäNdL<%…ÇññF3̾NgÀÅÍDq~.Ñq½¾ºA@Æ7~‰�§ê´íæfjË É+(!sÓGdnþœ5)+øýC×0Ýïì¨ûnÍZïï}‹Í*.c&sÉù3˜„§lÍ5IgÃ÷;8¶ÿsžº'ŸÆ¿?ÍŠ¨þÛ’ž ôsfý†‡ÏônB�µÜ•¥Åh5Z‚B†­9HpH8¥…ùØí6d©ý\Îq¼]\]1·µPSU��_À ÖA· ‚h‰¿ìw<å 6ÝV—˶/ßæµw¶p<} ÷ÿº†'_ü5s|új�¡P¶÷;¶åë‰?w>½sÓʺ]“)ã«×Þã`3xL¹�Wžº‚èîo„.åÚÛùë¯ÿÈç…ûYõòwÌúbG{[A8Ë)ŠBuU9Q1ñÞvøØNËÁ7pøk»\MîTW”‹ [A^Z¯hνæ¤Nû€ßÝÿ» ×òäs“xû� ðë58µ“¿î žýÆ“kÎe¢×`jƇ²nmYdd›Qeæ^yIÏ€»ƒÆo&wÞº˜#o¬Rk…@CÏå¬uùdîϦ°º›Á‹°ø$’£}N5Õé 6–p¤¤\ƒ扭ì Ûö£Þ%Žóæ'àÝ%°Õ�™™CAEm’Ï€p&%é9ôÚvµ©„#Å�¨z""ýq‘Nÿ¼sÿ4je‡3È8VF“bÀkL,)É1øuÏX'¥•ò£8x¼’&Õ� Ø$’£½Ñc¡:ÿm¼ÂÆ|vµC~"�µÜµÕ•Øí6|ýƒ`;=ø‘›}«ÅŒlh?ñ‡³¶[¯7Ь6ÐÔÔ€i舠[A ·¸+yôÎC\ýçmÔýø>:z·Æ�æÛˆ ›]$$¹¯®„éœ{X}NoÉ”³uÕÓüõãýTXº’ßÄËxà¡›˜tª¬ûVsÛ#°&ÝÅš•�<~ß›jQ‘/#r^ÞZÀR†UåùO3OO�ô~$/»“ožKXo�ïXÓW±ÒAGJkæ[ÜùÐ÷´%ÞÁ»�Žå›ÇŸäÍ}5œêK+¡šÉ]O=•ѧ?}ØJ¶ðüŸžã“ìzN6�— ϸ–?þ6‰­¿¿‡5ÅÞüâoïpÊÏ£™Ž0üTUí¨)ÖQFºlo¿ÚZ[Ðë #2M¼Þ`¤¡¶VÝ‚ ÂH�ñ;÷ ®ÞÎ¥ElÞ’ÇÍq±£wdC±¡¶æ5°é?°lÂÕL0 òæ«Öñãs÷òÐ×¥(ÞX¶|13£¼¡.—­Ÿ¼ÏÚÌyø>3ϼr7ÓÝ;¦¢ÖëÑI`iÍç“׿'Ïcœ…§k<Þ2 Ö°é™{yäû TS —Üp$†àE#™ëyû�ïÉøð îizŒÕÌÂÙÖ5½‘´:´¨M¹¼ÿÄ;l°Ìfåïf篧µt?Ÿ¿õ!;Ëvð�g>%õ¥_Ùù6ÒŪ‡Ÿâã\+úàé\õ«%¤†iÌÛÉÇÿy“žšÇøfС׊Zn¡wªªÒÚÒDHDÔ°×rwòöñãDnª§÷ˆ¤¯3èikmÔ:"èANËÔ‰®|XÚLñ‘£4¨±§5—U4c¹ìš¹|þø&ªöý‹[¯Ùμç3oF )ã#ð5ößpÛrø}^ü¦›!�[žy†ë£;«ž§3wN<Æ•ðQÑ7¼þÕ央k¤LnŸÕN)ÚȺ�ËxaõM$º�*$ó¾ÿð÷ÊQ4‘¬xòYîJr=ÙŽ>nB 3bôÜpÿ}÷:ï.›ÆmÃý6A–�{Þ÷|›r;¯?9Q'kÔS™ÜÄŠû¾ ìèvv”/'2XT근ˇyp™ÌÏ<ÁòÐŽÇ­ÉS™7+–‡nû [jU�$1 ˆÐ«“Ó½Ûm]\Q™ ÛèêŠÍjƒŽí wm·FÖb³ n|t ‚ ŒzVÒž¿šE/õsÓ°¶Ñ2âû¢#0È™&”šjjTð–¬Ôž ¬¥ë°ƒ6 êm Z©.8BÖiQ˜Œû˜hBÝe`(ëöGÆoþ}¼`våñ—¿%§&›uïg³î}�t&ÆŒ›Àä¤d¦ÍœÉ¬Ia¸÷¨²·rpÝ& íà:k)—�=½­‡ä6™+¯¿ÛA? VÀ �(­0åêLrëú»YØ·~3¥Š„>y+&¹vë¸*ážr9Ǭ啜b6m>ÆÊ¸øy› JA,¹îâ.w;—ñ“™`ø’2s%%å Ë@{wì¥E•p›¹Œ%¡§ï‘&èn»âs¶¿‘…uöUøùQ�NÇÅÜètzìö‘›JÖȨvû ÖA· ¨§bmm¤¾õLFÛp©ŠÒÞ®W©äÛ§ï䅎­&¾|â¾<í3=sù”¿\à2´uÄ…è‹îeõ¼_²gã:ÖoK#mÿÊš›(ÎÚEqÖ.¾~ï5 ‰,¹v%·,IÀ³3žW*8œS�‚†°¸Xz¶L‘‰Xp+¿[Ð˦µ±LIt;=¨VÊÈÊ©GA&tâx#3>Á9§šÒ£¹4¨ñ#ò6A2Ä0)ÖA£q­;î.˜Û0w¶7WÊÈ;aFECTü8z–¾LøÌéD®Îâh/C¾ BgûmUm¯ßÖhµ#VÓ­ÑjQûiÛÎÚnI’PÙ4FÝ‚ £žž™÷¿Ãÿ»°ïÉ#l?>Í¥ÜÈàZ–BC}cû ÓÍ­}¢ÉDìÜK¸b\×Z•²Œïø±POü¼ùL8mfg-ãÂ:jJ‡²î È®!L[rÓ–\Jåy‡8�y�ŒŒ4¶íΦ¢b?Ÿüí7ì=þ8¯Þ5O Pª©¨V-^>žƒž4G2øâß=R·WSÙ‘¦_€_/­04øùú S�RSM­ÊÈÝF&‡Q€ŒÜ±c'C ¥�Ú†öýööõr¸ßrP!IÝ€٬VôzC SÚ²yîI^Ü\‰Ï^âÝ…«Ú·©Z±XÚWÑjµƒºµzzö'´bíxã­Óõž¦F×~{Vm6¬#ôú�ÁäHµ`îx¡Õô:hõ  ™¼ Ë2‹�~CôôÁbiCÓÛ±: »‚¬ܵIœ‚ €)ÛÙ˜eIObrB�1ªÏF¯®üíÝ\ä+£Ú‹Ù³· @2âbPikmcX*p%#ÆŽñÂÍ­æ^^¬«˜[ÛPÉhÄ0:ªJz ?¶¹óI¤;K3�ö{B~:›wH’„,kikii�2Ûš[Ðhµ§ms8Ùíà‚zt ‚ £6²ó­ÙgV‘=gsñìÁ7¹øéX¨ÉÛˆ¯>à“Œêþfc¡~í£t´´´´Ãr!ÀNiq™Ã4T›³m�¦HH °QZR†ãnX6ÊJ+Q�Ðã?îÔ²7~^2 P]ḃZGÝ‚ BïlMîû–Wº™[^N£FÕ|þoxôŠð~†±“p Œ&.6—A·†º�\™uåRÆêÁš÷>>úÒÊ7‹0—íbÕ_e[“Šì;—KgºwÔàkwáEL4JØ�ÆK_Ð5v·•®çßk °£gâÌ)œÄFCì¢%L4JØò>çÕïJ8½rØÌ±OþÍÚrÙ}:K玒µ�ÉçLÃCV1§È›{»4�±Q¾õežÛЄ«˜GI’ðöõG#k©®ªöÖ%Õ•ht:ô㈼�³XÌH’„›©ïÎíÝ‰Ž”‚ `%ý囸ì_]nQv �õõ´X”ööÅ:?R¯º—‡ÿw:�ýF‚Z&^ûWþu­3û2”uO1ÄÿŠ'ÿ¯ˆ{ŸÛLÑŽUܳû=ÆÄ$ˆ‡‹Œ½µžŠÂ£Ì)¥É²ç$nøÃíœÓ¥_[Ê}7îâÎW2Øõâ\·}³üÐÔãÇ�;ÉkÏäÿåîÅŽå°KyàÆÜþÊ^¶=s'7§_Äù“‚1ÙjÈMßÀÚ�´h™Ïm\è3z‚X·YWsãä�<—q‚~{™3f�¨¥>/�­ûZI¹ûZƽþ ?ŒŠ¡-…ÑL’$ôz=&OoŠóóðñõÖô‹óóps÷@¯Ó�H-wsSþÁƒ^OÝ‚  ÒV_AYý©O$Y‹ÞÅ›°èq$N™Í…KÎ'uŒË(nÇÝ�žˆÅ�ðï„y|ðîç|·ãY»)Î겈$ãê˼óó?W]D’o÷Û¢ž˜å�óªß[¼¸úkÒv¯å�4 Ù%ˆ©W\ÏÿÝxcÕ£TOôò'x­#Í]ëß%k]çþèñ�_Àõ7ßÌŠ)½ )x†h¹âñg0þóuÖü°Ÿì-_“-ð‰™ÎŠÇWrMê þüzû¢#ç?];6úøÑT_Cyi1A!Ã’~yi *’¤9Ù´d8ïÖ–f4²o¿Á?(H~7üEEjIXðâ-}.œ•™AÊŒ9Ní¤ Â‹Œ�[IHL9Ó»!t§Ziª,¥´¦‘³‚d0áÌãg|´ÑXVDqu36ƒ7¡áÁxé‡z3·ÑTVHaeوϘ0B¼�£+ØvDµÓÖÜ‚Mç†Éб·-?pÿÒ?³ÕÅ�o¼ÎÍÑ#1�¦ðspj*x;e%ET–1>i .®ƒë˜Ø]KK3YûÓ1yúàîá�,ËÃt[-ë눇Á8°Nšáw½Lgœ-jºA„ÿ’S@81Î& Å=(’ø áÜ)-¦ (†5Í‘¡¶ÕR�_@q½+ãScðêÖžÕr$›£6�Œ¡DŠ€[èÝiµÝ~Ø,²î#~b2F纷¶´�shî^>è�.Ã^Ëm±˜iª¯#8,jÀww£þaZA„3Ï~ü#¸íÿ¸÷Á'xcOýécŒ·æòÁ¿~ B‘1M™CêÐ*,…ÿ²,c0ðöÄÃË—¬Ìtšëû_±›¦†z²f`òðB’5èõúAÏÙ—Ö–fšê ‹ÂÃÓÓétDM· ‚ ýÒÆ_Ánæ¡o ù䡛Ȟ}S"¼Ð4•�¹}%mH^©Üv˹#2m½ðóÒY-Ë2nnn¨j­†#‡àãçOXdt¿3JÚí6 OäR[U‰›§HíiÉÃTËm1›iinD–5DDÇat²†»“ºAAèŸäÍÜûŸçÙˆ7xããmÚô9‡T IïMì¼+¹aå æ…ŠÐB˜Î X£Ñ`2™Ðh4ÈZ=mM ìÝõ#^¾¾øøàâê†ÎÐðZÍm´47S[]A]M5^>h]Lèt:ŒF£Óí¸UUE±Û±+v¬f sH~Aø8ÑiÒqf‚ ‚00?¦­x�i+l4WUPÑh� ¿?Ü ž7ô IDAT‡Ü©TøoÔ5ðvuuE¯×ÓhtAktÅÜÜH~ÞQlV+ªjo„[jªm6…¶63« WWWšíVZ�¯á–$�FƒF£Áèê†Pð Çáî�ºAA$-n~cˆò;Óû!ütmj¢ÓéðòòÂÝÝ�ÖÖVÚÚÚ°Z­(ŠrÚ2F£—öÚñ.µÛ#1.÷pA· ‚ ‚pFu̪ª"I²,£Õj1™L@{ó�Îåº.6Û�DÐ-‚ ‚ Œ ]ƒj8l÷¶\÷�f"èAAF�îu÷Àûl ²»A· ‚ ‚0j�­AvwbrAAAa"èAA„&‚nAAAa"èAA„&‚nAAAa"èAA„&‚nAAAa"èAA„&&ÇAAF˜‚¹¡†ú6­É×Á† *æÆjê[$½;>^.hº¤ÝV_C½Y@:O|ÝõüÔS[AA9öާmbÃþš ÿÔ+¸*ÕwPÍ-Ôæ£¬ûh¹­  ™Ãõ—NÀ­3jVÍämý”uö¥¥�]ÄÍDv Ú"èAAF€Š¹*‡­ë·“UeÁéªeµ‰ì-;Èkíå{I‹û˜H¢µ}Õt«´UQÜ`CoÐ;¹#C#‚nAAa˜)Ôçlà³ÍǨWÝ;ó<‹×±£p M@ºRiÌÞʶãm¸y˜h©or°ŒŽ°”„õ•JS6_pÉÁŒäàŸ¼–DGJAAa4”•Ðê>Žó.»‚%ÉA§šƒ ‚Ò˜ÅÆíù´¹ŽeÖäçWµ™œm»8Þª'lúlâM?ukîv"èAA†�Gô<–ÿâ|&œkY¢4ppÓ.òÍ®Œ;g6ã\œIE¥åøN~ÌkE”œñg,øA· ‚ ‚0Ìd܆eè¿øèé¡Xô’ã¤Sw³¼‚jôÆâBD¸�ç®6¾ãSŸÎÝ~V-ö5¼z˳,´FsÃÛŸñ@g•œuos×þÆÞmï½<Ž6ÞõµqKÂnoUñcâ�‡–óÕÒÃèÑríÈöø)Œ>åψv2…”ÀJTxã9cçt×Bˆ¦O'ÿÀŸLo&?oH&_+t)ª™ˆ.£¸ë�I\ÚÚÓ;ý�¢bTU4UE)Sy­ �cÁÑ‘ø«Wæ¬l¿Þèä®{Ÿ§>ÞŠ5öZþ÷èP"UÀ±�þ‹_r*HPL~±ôz9·Þv9½Âê¨Âuy¬‹�ýãZ•ó ŸyD%zÄ£LÝu�‡æLç©÷ZñɃà_O;¯˜|ð5Uü¾Ë\ÜX ÞøùúV8w·#3ƒl K ��áÊb�¢© !„p¯p×<øðçlË×ñiÖ�ˆõ¥KË(ÍàÌÏäHâ/\ž-?ñÒ‡É}ûenˆ¯äªÕy zšE‹ŸvóŽ‹ýß>Áí_ûrÿop}´Z�2ggûõEÏ]Í[¯Îã-¸ñÑÛéáSv •Є¾t�<ó sÍQ@æñý$9šŸßeÝ_«yàÿžg|ëÚKÖå±.rö�kU·~æ1Å�Þ“æêu�0ûçÿãí¾ñd?ÿ*?tè{ø}Î:’O}NÔqºÈÜú+3wŸ>ïÆØ\?¤%usD5 óòÐP-¾øÖÉ:ë†ÝBÑXi)Ìûð[¶çC@¯É¼ÿÒµ´6—YfÔÜzÃJ^yp?ÝÂô÷~çâ—Ç�Ž6uz»vG£Ýy²}Û¾ü�ù©2üNní\.âŒ$\õ/]âç&èq‘½{ÿ›ö‹“6ðÞÿ~àÂ÷n$¾±$´–hèóZÖùÞϪç+wLÄŸÏ-å·÷¿áòž“è\Õç9ÍIAn¹n¾œq٠ȵ�þÝhuà.qÊS6«PL^xüúz A·B4VÖ]lÜmCWtÝeå�b†°~ÜwÏ¿q´ ®¨bù$ï?ÎI—‚_tkbÔšm?8K^:YKDKâ‚+›Ó­¤ï(.C+®º¡?�5 &\ÁSÿHdëSóIß»ˆ?ŒgRÛòQ·3û[·îáHZVÅ›ÀˆtèÒ�–�å÷§üñ9óõê·‘ªÏké]®Q{ÍM"1ét]œ)ÛY±~Ù>ízq‚+;–uÐÏ´œ$ö&ç‚%’Ö±A�Ùܶ…G²°ýˆŠïL÷„ÈJoˆ­ÉþÖºœ–ÇÑm›Ør躑ñ]¹ K³JF…‚ŽçŠËùôð<>_v/� ®t´[ñëÄÕ÷tª´î5eh=‚)÷ލb)•È~7p_¿:Ýt�� [!-'N—((j¥—7ü<ÀŒ¼­�dÓ¬×ùßçs¨@+5¢¤ Zbzû#<6®óAžcëçÜ÷ÔB¬]ï囩­˜ÿü‹ÌÜœÉéûø¼¢úqÿKÏp]é=Ÿ]sßä¥O–°/×uæè•âMT�«xøñ;uúòãØ0�Igܨç`˧óð‚Üâòûøæ©{ù•ØñoòÍ”NheË\l›ù(Ï,ÉÇoØTæü{ ÛB;ð=�MšÉ^¥ “¦À�5Üþ¸ÿ2)ãE¦.ÊÅwè¿øaêPÜœ-éž™ô[µ8îüàc&UtîN•àØóX“^ÝÆ0¶ÃӾݺÓÁ¸€tG2‡�;¡tÐmObñôWxcÎVÒìgŽ-*^aô¸ò>ž¼k±¥>³”?>ů׸�T}^�àY{Ý<ƒÉÏ,ÆÑí~¾˜”Ëó�ÌdG�Žy-w ¸Òh§öý̾îC&=÷®N“˜ùX0_<ó&¿±ž®»b ¨ãUüëÙ{Q&ö`kSÎy| ¯N}�Ÿ÷åq*u]Qño;–§þÝ¥¢!gcÆ^Ú�¯ÞÛÁꟑ4üZšŸ/#ýuD‚n!„h¬¼ãicà¯9,ýú;®ìt�ÊÍG[=Ÿ�>Ê?gíÇniÅÈ»n`L�êYXÿ_Ìú‹Eï?Aºó Þ¾© %á³b4aT@ÏÛϬ¾b±ý"&=Ñ—öá^&oá§Ïg³:eï¼:‡Þï^OK@çä²×yä­Ådš[0覫Þ9† o'yÉ{XñË\æošÅÓO{óáû·‘Pa§‘ÖcîãÉøµ|õÑ"ÓœáÆsa ßÖÍQ�rßX+~ôÑ�Àe É^»”ÕyæWv!û–.ç€KÁ«ópFÄU1T¶ý6ô+Lø’ŸI[³�¥™C¸<´\4Äñ¿–±Ë ¦#Õ¦´–Š¿qb¤ëE})—ÕÈ©»•3o|Ô3YúêÃ<³0 ݯ-—Ý9žá]›D.G¶.â˯²qö <�÷,3ëOPM­æm¤êóêq{õò¤€½ð0?~´�]>,ž@KÁUË:ègª—UçÉM¼;u‰!£øÇm½i¤ròÀj~üúW¶îø�g¦ñÉÛ7Òº$úòp=.gßÍŒg^æ§ýÌqC¸íö˸0Æ[Z"ËøŠ§ y…»®Ýí?ÚÎö=ñWêÕ�"¿)‘ [!+C+®ºe?=¿”›?åž[V2xÄ0÷íIÏŽq„š«¾à9¿ãÿ¾?€ÍÇøßà�§s�:÷¦ÛW¸ýélûb:¿�|‰ËK¦×RTÀu`! zNá£7®&þÔègoúDçqÃ#?“²w%«RÇÑ2ZòYóç*25# 7?ÇnjQjzµ> q!á“äÛôµ¬Ø3 £*‘ÝF06:ŸÓq˜`:_<†Ë«¸ÀûöÎà�?™›±ŽÅëò¸xh™¼g×^þ\z—âM¯C*¥«bûÎÑ\û+3�lbþ’Æ^}æ4rÚq–,Mĉ7Œº˜ØjÄ%zþ6ís¢«1tëQ«i鬻v�èÔAmF˘ӟll[¾æí?RÑ -¹áÅ׸¿›åÔñiß©'}Ûzqç£?sì÷�øæÊ ™Ü¾ŠÁƒ6RÕyõ¼½1Ú±%üÙü*Þœ1‘®MmQVô3P‹ŽÅñõlév7Ó_Ç©û,/èË N¾LüÇ·ìßý߬»Š§ûùÔj=+§“ó×·|wÀ–^ÜÿòÓ\]rìÛ%Ð㮄>|/ïè>¯\�îB·H•mÇ÷²iG×G—ûd+*!Q„¢ÑR »øÞ|l *ÎÌÝü9ë]žyhcÇ^É5÷<ÉóïÇï›�’ërWÞÁö…pÐ >½Çs[÷²7ß)õÏ•m�èÖÍü¾âD¹d]‰âÒÛÆ– ¦ŠøtìN'o\é$¥—Ò ÈÉu¢£`4º ؼ˜4ý7–þô.+ ¸kÁÜ•‘C"Põ|Ö,[G^™¯É�»—²ä˜ ŧ'— ÷ühl˘Ñí0á`Ûï‹8\æ iG—³x¯,½¸tHõ¶ã:¼Ÿ6Å+žö-WEPúLÅ»-]Ú¹¹)Ñè�¿�6+¶’Ü`5„N£0l9ÊŽ/^àæ‰Üxq7ZøŸ"Uµ>Çz¼è:l1s¾å躥¬ÎˆS ;رtÇ5•€¾#XUîD¥TbGŒ¦çÌݬÙÿ'ó¯gJBÉåTãÐÒeìsªUííØÓ’9¡ƒEd¥Oýsqhñ Þ>pæBºËÊɤ½lܸ‡4«ŽÜ“)�\Uœöh)ìÚ“�†JL玄¸; j4;¢îÉ yï~rô„Êo@,V£6R™:h¯ÛÑ««¯sh×¢Ÿ•¢˜èánZ5œömƒQ·¥qòðNêÝ Ó=Ü_O�“–ÂþÃVt Ķm�»¹q|Úw •q)[+üpa"2:…dN¤¦á £’5 ÇJ!šÕÒœ /½� /½ 4+©v°mëv6n\ËŠu»IKÛÂ�ÿ÷O6|žî¿ èB¬e�v¢hŒëÐ÷OsÓ÷¯3û$::¶éähPúnŠÙ?·W •’øùt8e¤ÃÍ�1aç3Lß²›¹¯=ÂOoùѬ}Wzõ¼€~ýúÓ¯cæzœÂËØþb†ÇÍfÆÁ�,Z“ÇðáÅó Ûwòçò45ˆA#/¬õÃ=ÔÐÁ\Þo:ëcáï;˜�Э(øsbñ²ƒ8Õ0†Žî]Í9‚u ròÑtPýð«ôs‰‹ãkæòõ÷ï*¦ Ú½’{î¹�þQ¥†[]¤gh€‘°ˆ° Fß „…† ’�–™A–Nõ‚JÔE{õ%¼¦÷=”®±'ý¬Å?œH· \%8$•4´¼lruót=.—MVvQ pûÁD #¤Òçâà‡ŠŽ+7—�S³ÙˆªIÐ-„M�j&²M/"ÛôbøÕ·ñðÉ]üøú‹¼µ,‰Csßå›QÓ¹§½tv€ŽîràpTpu´„ÑÜÆ@£›”‚š]QßNÜùÚ ú/™Çœß—±bËA’v¬äøŽ•üüå»¶Æ]ßÇ5ÜÍ3] ­1¬ ŸOOdÝÒ5ä N ¶íKXž¦¡F ä’^Ì WŠ?�LØÒ_H[ú;ëïêÆEpXÎâC. Í/fl×ê>˜FÇn/žWØË›ÊKé0îI&ö(½ ŠÑ„Ù/”Ø–-w;/�Gq.€Éd¬ðØLEa�îtâ¨öÄÉut&ë ½*F/ŒuÕ°ªÛÏJóö®p^hcɱu¸ŠŽ­§ûëq9;6GI]LîÏšÁ€¡Ò\ÀËä…èNö¢I_D5IÐ-„Mœ!¨×=þönŠŸOgý¦´öÍQ3¾ ÓD—;ÞâÍ+BÏÎõÑDÂð›yrøÍè¶LöoÛÀÚµ+ùcáJvï]Èk�fcúøE®¨—™Tâ†^LÇ™‰lÛ°œU9ø$ÐÆæE“®ˆ:’n•¦oTŸ¹Ç%\óŸû›ùkòè?Ô‡½K—qX3ÒzÄ:Tûñz ^^E ë;öJ—U iÝ›þýkø¡E1c.ŽÓm…6tܕױMs§˜Íœõ§g7T{­¦ ûYé…l6l|X±G¼ŠÙ»èØzº¿š§å¼ð.nû›�òi8ºµ€B­òO[vgуlT£©Þ<£ëe¦µTS‹¨9¹‘R!%;™6±xÞwü¸1£üye™£ˆ +š¡    èë|C1Fœ$'¥VûƸº¤x‡Ðæ‚Ü8e*3>ÿׯÑs70gѱª÷ÉCjô`Fuö‚ ,Y›‹nÝŸ+³Ð qŒÑ®îF›ŒísI[Lz«—¬#בÈâeÇÐL3"®X??Tô¼\òëòÑ|%ÔHšG'ÉI)´')Ééh(˜"£ÏHÛ8+¤½ÖA?+EÏI#Íêîº8‘ž�†‚!4œ0Ï÷×Órj0aA*à"=½üMÓZò1’+]¡F~N ªŸ_½¤–躎®ëhšvêÿî^kŠ$èBˆFÉÉ–¯žåéW>äõwæ²ÛVùÒzön¶s�âEó˜È¢?îJ0ݺÇa@#ií¸�j@ãÄ®5l>–Wû Ç–ÁþÍñÛʃXݼ­teè¡(hdedÕ(è®Ñ%V gÈðîø`eÃß›Èܲ‚•'uL #åáCgÜo_¥ÅÈKèi†üõKY¾n KŽkøôňŽâ{GDª€–‘JŠÃ£*VN £[—fÐHÙ°�ÃîN¶}7k· +&ºvp{£]];óáIg¹½uÒÏJ¿ïÜ͆mnZ¿vŒ»rÑPiѶUѱõt=-§FÒ6Þ�ãÛw‘Y®jY¿�£•X©©è(„FEPG_œ ª].é©IìÙ±‰ «–±jéBV-]ȆUËØ³c3é©I¸\®SxS"A·B4Jú_w­¼Àq`ONýšµ©îl)k˜>íVä騡ƒ¸¼_ñ̓¨´5–^סy}Ö^ Ê–=ü /=ù/î¹åÞÞZybCU´Ìe¼úè³<ÿük|¹»°| j;ÈÆí™èŠ‘ØÑU^€ƒ¡(?וɉòBe% 0œÞ(ؼ‚/¯!K÷¢[¥ss{¶}5l—õõC)XÇô7q?ú�XÅÍhåZ¶!ÞKA·dï‘úã5Ðî’KélVpø‰~O*3Ý›�}?~Æo©ª®¸¸|@YW*>®g·½©‹~Vjßôlñ»Î¨¸ÎÉU³ùù€ÅÇà�%ß‚xº¿ž–ó¦Û€ Puì[æðÕÖ¼3ú¨ýØ|Þÿ~?Ze9Ý®£ì=à@W¼ˆoÝ‚ºšø³dô:+#�ÍkW�žšLDT ½ú fèè+:ú zõDDTsÒS’ؼvY™éMnÔ[rº…¢‘òN¸™:ÆÃ¯/ãØªé<°î[šµí@B‹H|T\…Ù¤ÝËö=Éä¹@ ìÂ�ÿžÂ€RSs¨Q£yä¾µL~u%›>~�[6\ÌÈ ã 5ÚH?°‘ÅK6r´ÐDì¥S¸µKíÆ­Ô¨QL¼òþ9{ŸüãNÖ¼ˆ ÛD`Ò(È<ÊÖKX}ĉ)öJn^õüÕJ@ â‚UÖ¦¦0÷Ï’A$^È=·ôÁRUÙÀ>\ÒÏŸ¿-çûENtsF ©ÙCg*Ûþ©™•.3˜ÐeóHI±¢†ŽæÒ>僱*·åבnñþÞ�Ä–íhíj÷€wÔØËylÂ*¦¼¿‰¯ÞÇ]F3¬K4~ÎLöoXÌo«�P`ˆäâ&3²¦Ÿj ÒãzÛk‰ºèg%Ôæý Ìæ¾I{3²7­CT²ö¯ä×ßÖ“¢ivÉ®kUj M÷×Ór¾ýoä¶®+y{óaf=~û‡ ¦Gs3Öä]üµd=}®`ض9üqBGwó9S;±ƒ­Éб=:y25cyº®ãr¹8~øé©Étîq!Á¡áå–óõ À×/€˜¸VdžHcÇæuäEfÓ<®ƒ¡Iä{KÐ-„�–qcžá³ƒùø}ÕŽìZÇñ]¥QT,áížE"Z´ Ê·Šv«æ³{&ña¢‘>�|ÆkckñTWJ¥”d¦s0qý�Ähªö”?Eû`·³zù´jב �0Eit�w‹ûߣ$Ζ‘n!„h*~-háé T|Bbi[—µª€ ßð´+ÿ-q�|#ˆo]ûõÔÏö5Ž/øš…é:–^WpY+ϳ\ÕˆáÜ2jëæ$òãwë¸æ‘*É]+Fü¢âéU_ë¯ZÕçõl¶×RjÙÏJRŒ½›Ñ6°Y Jzº¿ž•34£M@uë§“·ú;~ÜëDm6–[/®]À Åi%N'wѹDžŒÆçgM&:uïÍŽÍëèvA Fc£ ºK“)…B�èäïú’ç¦o¥PmÆå·Ž ªVWUzÝ6‘‹C uá'|•X7 Ql»ùbúŸ¤°I·ÐÓªRJF¹32Òð±øZôiŃŸàÐpÌ>¾df¤5ú+e¤[!„¨-m ßÌÝLrêV,ßAŠÃ‹6ãab×ÚO²§æŸÿ\ÅöÿÉW¯|Å€wî c<@Sϲmæk|{ÀEä¨xhpP�Ý@™•žJd³XôšM ZvED5�%=%‰Ððüê¦$èB!j@ÏÚμogqÐ¥ úDsÑMñä-Ýð«“oµB<Às7åÁ/¿aê[íùðÑ(c` IDATþuxÓ 5¡‘ñ×[<;ë Æ„›yþÁ‹®ƒ¶X2"�Ÿ›CێݨíàtPp({¶of×Ö�¨ªŠªÖü+'Õ` ªY �Á¡µ«L%$èB!jÀÐö&Þùb9./B"#ô®ãLMÅB×;^á›áéäëÞ]ÈÕº‘3õœÈGŸŒG3{N�+ÆÖãyå“ð‹ˆ%¢ŽAi·Y1yy×:%ÄämF×5Â"£=º;©IÇ$èB! ÕLhóÔߥP}‰Œó­Ï-ˆ:¤øFÒºudCW£˜lÖ’À:\cI€­ëÅI%%ùÙµ[i¹u7Æ*%èB!„g�—·›­ƒÑ¿Vë±Y P…©É§”SÓ Û`0S«zTE‚n!„BqV(Šrj$ÚâçOVF>¿Z­33ãÁaá´íÐ ƒÁàQzÉÙÐ8k%„B!Îi�Á¤%óxºÀ’Ÿ´äcø7ôîTI‚n!„BqÖ”¤ø†b-, +#ýÔŒ&5ýÉ<‘†ÍjÅ?0´Q>‘²4 º…B!ÄY¥( _ ѱ-Ù³c »½Æ·Ýf#qç6šÅ¶Äâki´i%%wí„B!Ä9¥dDZUUüC �`ûæu8t¨Ö�Ãá`Ç–u‡„ár*à–‘n!„B!Š•Ý‹Aa‘XüüÙ´f9'3OT™Ã}23�Mk–cñ ("‹ÅUUuÀ 2{‰B!„8ËJdUU DQÌf {wlÁÛl!"*ÿàP¼Í>ج…äde�ž’„ÍZHTLK|ü 8pKÐ-„B!D%£Ý�˜Œ&0˜°摞–ÊÑC°Û¬ ÍémöñÅLHd þ�§F¸›Â(7HÐ-„B!HIà­( ¾¾Ìfo¬Ö@¬�…Øív\.Pôð///Ìf||ÌgÛM!à º…B!D*�j¢ª*ƒ‹¥(­¤äÑî%Ë”oJ7HÐ-„B!XI­ë:ƒáT°ín¹Òÿ6%t !„BˆF¡tP]6ðnŠ�vit !„BˆF§©ÙeÉ<ÝB!„BÔ3 º…B!„¨gt !„BQÏ$èB!„¢žIÐ-„B!D=“ [!„Bˆz&A·B!„õLæéBˆF(99¹¡« „¢ ÑÑÑÕ^V‚n!„h„jò‡\!Dã'é%B!„BÔ3éB!„8Kt]oè*ˆZ¨Í£é%èB!„¨G%�vé€[‚殮$ØÖuýÔÿk€KÐ-„BQOt]G×uòr³É:‘޵°Ms5tµ„TÕ€ÙÇBpX8~þ@Ío º…B!êAIÀ}"-™¼œl¢cZŠÁ(áWSär:É>™AÒÑ#X ó ‹(ºá½º�·œu!„Bˆ:vj„;ç$y9Ù´ëØ ]×±;ì`·5tõ„'?ÿ Úw &qçfÌf ~�ÅoUxKÐ-„BQt]'+#ƒ¨æq8�Éãnêt§¦¡( QÍãHOIÆ×? Ú#Ý2e B!DÓuMÓ°`±X$à>‡èºŽ�Å[a>š¦UûÜJÐ-„BQ‡JÏV¢i.ôZL3''EQp• ¸«xKz‰B!D}Ò´†®�¨cž|s!A·B!D=’Ä’^"„BQç$‡ûüQÝs-#ÝB!„õJð³ÊžË‰ºÁ‡à`ßFì6–z!„Bœ›:ævžäèÁ4òt#Á±ñDùTqc§ígbUÌDƵ ÄëìT³®ØW½ÅuÓ–âh6Ž>½‹Î�$Ú•ô!„Bˆz¤7ð�vr¯Ü/¦<Éç;�U.ï<ü ÿº÷^&Üû* Òµ¯� FŒªŠÁhDUêo;5ÕHb!„BˆsUu+jñ(«‚ªV#dTTŠÆÂUTÅÓ³áx ú7ý= 46«�Æ2wŒÝBqêÒ£w�–ß¶i]=ÕDÑà1«^æÿUÕ§ìû ]ÿšrZ)t6t%Ê“ [!ÎQÕ ¤k  !ÎOz^2‰I¹`‰¤ML ÝJÊ®ÍlÚŸLžf&(º-=º·!¬L¸–“ÄÞ”<°DÐ:&£3›CÛ·²óh6ƒQñ�éÞ>Ÿ “ž5 Óö±m×!’2 pÌEÄÑ©k{šYÊ*©§n ¡eË0ÌÅ)ìzn‰Éy§êïLÝÁßö‘íÓž!C®çgIÐ-„牒àZFµ…8»ô*ÖKÕ@?ã·Š—wWÚ¾ýKxú¬]&óåÓ-YðÒË|±%ç©Å¼"ûpï ÿâšV§#oû†éL~a®Žùäá ¾šö±žÞŠb ¨Ã<ñï»~f­goçë×Þ`æÊch¥ë¥ Zbzçc<~e;,¥fû¦Lž¶ G³ëxÆD:G»ö­3¹wêœ]§ðÙÄ<^|ü v訑WÒr`{‚ê9*– [!Îl !jC1ycR °à ³ÿû Kœ™üôEtˆð¢ is>ý–•)kxïµ¹\ðÖ8âŠãgÅì…ª€3{ >¿�ÄÐ1<4¡m‚U²ö¯dö?³eçž�ćoŒ§uItª%1çÅ©|¸!SLî¼y ´ ÁËv‚Ä¿`Æ[XôÞ³ÃßãéAœŠ»Õ’ (=x­x›ñVÀa;ÆÜép0 #G¶"È’@ÈY˜ZD‚n!„8OÈH· ¤ŽºS®�èöõ¨ï§Wû5½/²ôòJÑ´w®ý YØë~f¼}±Š MסkO.ŒÊcüCsHÞ·–5©×UÉêE7rºŽ¯gK÷{™ùúµÄàB×AéÖ›A�|¹cÊWìÛ3‡ïÖ]Á“}͸ö,à‡Íyh†ÖÜúÂsLŒMÓÑiGçž½‰³ßÎýsSYúÓ îé7–pw�óõ7b´cKXÔüÞûü.:ûèèº §Ý‰VÏ_HHÐ-„BQ�ê2½¤Õ‚oÏøýÀ%×W#]¤lmª»¼~F:Ê©%бwŒ&ÚeÅ^²¨Ë‰Ò®+�¼ç’lK#9Í…¥œ¹>5„a7�!ÚiÅqªœZ�᲎³x}k6ëÖïÁÑ·+F@i5Ž×>NV¶‰f1ì§ �˥Сw'|~J¡ðèŽj:a%1þ{R*µFÑQ­@¡÷-ãik(Äj«ôPÔ) º…B!š€V ¾%?/·Ê×ê›âݞέp3Ÿ/þl6lŽò�½bJ g{µ|9=ˆ¶mCP·¦ròèqNê] S@ñò#ªyÑ1:š«h¾pt —Ó‰SÓ°ê^x+Ph·c¯Éçc{zv4Qͧ·× º…B!êS-‚»ÔëîªÑò‘³?®z¡šLè&EññÅân=º‚ªœ.V®\@á&÷Û D%-/‡<�âQk-ÿ(kæÿ¯+·°ëP96eò@Ô²õ¬ªþæBÍîëQŸ$èBˆó„är Ñô´š_”Nr`ôõ§þ_Vé÷*õ.Š…µê�îjZÑh´¢¢T4�ž'«—W…�§ÑTôŽîp�š EÏÞÄ»OLã»}Vð#¡çúÇ„àã…ÑhDIYÉWówc­a5£©A` º…â%óo Ñ8Ô&§;//Çíÿ+[®³3 è…ää9Ñ«ÿœ¹'ÉÑÅ? årº‹þ_�‰Ë”³Ù°éîÊéXmE ÛŠÙoEGÇÎÖ¯ßbö>jô(¦½ý£¢ Å7Rê ƒc}:?,( ºÏœ±l=Ê¿^uýëžÝBqzð�ûxãÍwáâ¼çÝœ ³³wÏ!œ* �غ“ Ôˆ–ÄùÖÝcôœTÒ¬:˜Ê®ÓEfú 4L¡a„ª€ëk7¦¡a¤û¸Ûl§°ðŒµ‘q<‰ü&ô´Ì³0+¡Bˆ³mÂí·ñà÷5t5„p:¯¸6?•­§ªm¨ñ ì…ŠÆñ?æ²g¯úè€_™:”­Gu�Y]“ [!„¢>5Š¨Û‰w»›ygf~šù³mäÐÞ-¤î-~_QñmÇБ×rÇ�#hk¶bw•Y©»�ìê¼_ò¯Ãu/Ž£íë¯òé’_<õŸâNÏëîãé»zbÑœ§�ó/¥½ÄK³6²sá×ì\ŠêCTÏ«ùï“·Ó7ÐJäMÝØþéçOçÿ¶\Ûý:Юl�ÜEݦˆÔ†vçÿtGÞº»Ò…wmÝHϾÏF½„¢ÉÚ¸ú/:tíÙÐÕB4]×Ñ4 —ËÅþÝÛiÕ®C­×™>þžJߟõAõV¤1yyc289™|ŒäÌ|ª™€Ðhb"|Q]v6;eãmŒ>øZ¼Pt;…¹…¸Ê/€·Ÿ/&UÇY�ƒÕYôª}õk\ùì" ›�ãƒ�'ÐÅ×ò“9t,«ÑŸÈØ„™lجŽ2ÎQ1zû`rfqøp ¹š7ÁÍ∠»ÕŠSS0xûbråpÒæMP€G¾—É‚Ÿ� 4…yÖÓõ¬²þ5s q­:c0PUÅÍüŠ-î�’8[Fº…B!¹øùßTú~^NvõV¤9qX�8PðŠ¢U°è躆=?¯ò²ÎBòs +[[^6•=Y]×œØ sÁ@L| :š–G¡Ûɶ5œ¶|œŠ™¨¸VD££k6 N]»ly¸>F'ÖüâçÄ; Ès¸Y]•õ¯_t !„BÔ£ºÈbÈ­nP]m:ºæró(÷ºç6«C×p¹ª¹õª–u;÷wã#A·B!D}ªÖc Ϻ~öï`l$dÊ@!„B!Ꙍt !„BÔ1w7Õ�¯L=&òÉç7£«¾„Ÿƒ‘guÏõ9¸ëB!„�ƒªp¹\¨êyœ\à@td`ÑM“.íœÈ.Ñ4­Æçôfß•‘ [!„¢•¤(ŠB@pY™'д³1Oˆ84M#óÄ ‚CÎ8×U‘ [!„¢Ž)Š‚ªªX|ýðñó'qçV²³2q¹œ ]5á!—ËIvV&‰;·bñ÷ÇâëWáCqÜ©qN÷ÆÕÕ¸’B!„ç›’À;4,/“'R“8zx?š«¶ÏB A5ðóó'&®þ�Á5 ¸¡†A·<ÖX!„¢j%Á˜ÁPôð€ ü‚ЋçìÖeîî&¥t‰ªª¨ªŠÁ`@Q™½D!„¢!•¼UUEÓ4 ¶›¸’ »$Ø®·‘n!„BQ}¥GHKh|7-¥Ï]Mnž,M‚n!„BˆzT:H+ ¶åá9MSmΛÝB!„g‰Ûç/™2P!„BˆzV«‘nÉGç²³=!ýIœËdtOq¾«qÐínª Ť$8ÐuÝã›%ªKú“8×�Íþ$„�Y�‚n]×Ñu�¼Ül²N¤c-,DÓd‚wqîQUf Áaáøùu(H狳џ„¢±«vÐ] œHK&/'›è˜…b0ʽ˜âÜãr:É>™AÒÑ#X ó ‹ˆê.P�þ$Î'õÝŸ„¢)¨ÖþÔˆ\ÎIòr²i×±º®cwØÁn«ï: qö) ~þA´ïLâÎ͘Íü‹ßª]  ýIœwê±? !DSQ£‘ ¢šÇát:$ïTœÛt§¦¡( QÍãHOIÆ×? NGº¥?‰óF=÷'!„h ª5e ®ëhš†µ°‹Å"‚8o躎�Å[a~�=¾Wú“8_ÕGBˆ¦¢Ê »ôì šæB—‘ qžQW©¡6�‚ô'q¾«Ëþ$„MIÍïÚÒ´z¨†�W½ÒŸÄyF‚l!Äùªæót×G-„8OIB!ÎÕÎéBÔM_�þ$Dé Bˆó‰“ËÉj³çr"džnð!8Ø×“ƒÝxœKûÒ¨œýIÚFý‘c+„猚ÿ oÊ1‚ý$‡Ùw,�¬} oFëví‰õ¦®oi³¯z‹ë¦-ÅÑl|z�ëôŠ©cË<Ä®=‡9–v’|‡†Ád! ,š–mÛÓ&Â\½¯1ªÉ¾æ®Ÿºk½ìËy¬1ö'=�¤}Édë:ª%‚Ö1A•þ¡8¿Ú†ô;!„ž9/rº]Y;™÷åL¾þ}3Ç ´rû ¨f"»\Ìu7ßÌ5½Â1ÕÑvuƒ£ª¢�¨Ê™ÇN+8Áñ � èüktt ,⓾àç�Éhåψ¢zÑyïŸÈèÖ>uòaBW EëQTšf;hŒãq´ïøŠüžc¨C™öÅ“\ì_q+jJmCú�Bˆ†rާ—èäîœÅ¿§Îd]† ]1Ѿ}º·¥Y°ª5‡”ƒÛY»~I[~ã�mËùóÚ'øï¤ «ƒá*¯Aÿ毿§�æÀfµszž û¿{Š ßørßÌWUý�YwÉ?ý’mù:>Í{rÅÈþt‹�&ЬàÌ;Áá=ëøsÁßìÝú3ÿùçarÞx‰ëãëâc„^ÁÿEí4¶cYÀºß“¤›ðó3�Ÿ»šyËN0dlX%#¸M¥mH¿BÑpÎéô×±yLý×g¬ÍÖñŠÊ}O?ȸ®Á\º( (ÈÛÇ/ï¾À«óö³kö þŽíùØû~>~ù:âMN4M/ÞeÄÜ~Ó*^¾ÿi~<¼•þÁÐÇYÛe¯ýM¨4j�ì8ê™óó_Yèæ>L¼Ë‡o,eãüE=ž¸ŠÚPSiÒï„B4 s7CPKcÞ»3X›­£F�äùwŸdH g¡WÙe½b¹ô±7‰2ßσßd÷¬wùnÐÜo(ZUN{SòнC‰� Żܶr9¾?™Ý›ð¸8ŠÐó’ILÊE7…вefE'?õG3v²:щ®’r ‘]Ù¼Cb‰3Wþ•´m7›wÛÐÕ@�C¬^ˆÝ^v!øõâÞ)—±{æQ¢›«œt@d¹Jƒ3ûÛ¶%r$=«âM`x,:'èÉ�FaÚ>¶í:DRfƒ™ ˆ8:umO3Ke‘GÍÊé¹I$&ç�%’61�8Swð÷†}dû´gÈ�‚åY3µ q|ñ|ր墡ŒáGâgËø-q!ó÷\Ã=ªùç™ÍÁm›Ùy$“Bƒ?-;qAÇh*k5i‹5ï�Òïj[Nú�BÔž9ÝMc¨Åu`>³7䣫A Ÿ<…�þ6å¢íbº ‡Ý‹ïç²�ðCò^æü´™qöÄ�¼ÕpÏË«ÑÚÜÊ'ïßDë²×¤Â5¼õ�ÿ±Âϼ˄VEÁº}Ó &O[†£Ùu¼?c"�Œv¶Î|ŒGÏ->Š{ùæéð *1ã^ãË»;T~Bt.Wѽ®9qU”}®»ðîófTÑ]Nvg<‚ŞĒ¯óöOÛH³Ÿy>¯Pº_>™Ç' $Æ«Ô*K¯¾L+г·óõko0så±2¹® ª%†¡w>ÆãW¶ÃRæÂìI9ûÖ™Ü;u ήSølb/>þ; tÔÈ+i9°=AMìcd£êOÎ}ü66Å�A#û`62j` ~>΂›¸­Ãn¿ý)ÙEU°ù�©Ó>`Ñ1ëé=STÚ^ÊcÏNfH¤áÌÂ5n‹žôG—ô»Z–;×ú�B4„sôO¥Æ‘5k9ê5|—÷õA«r>X—©—�ˆeîç‡9±f5;=éaE-¾ª+÷y­ŠZüº‚ZúWª\ÑËFÚ\þ O·]Ãï/ä1Œœt}‚ øÆÇT=ë�9žv±–ïÏfÙ×ßsYÂõtôs?Ĥ»lX ݽ‘Ų×çÙ?ÒÑýÛqÅ]72ªG,AäpxÓBf~±€M?ü—‡òM|üp_‚ªÁÒ’˜óâT>Ü��)¦?wÞ<† Z†àe;Aâß?0ã‡-,zïYŒáïñô€ Ó#Š–S¼Íx+à°cîô?8Ð�‘#[dI ¤.§�8Ù¶.`Ájð@.íí:t¿dÍçÍâø²…ü=¡Ã*iÎ=Ìœ6‡}Á#¸ïŽ~´5‘}p%³¿ø™-‰óxá¹pbßOë’¿:¶Åš÷GéwÒï„¢á5Êœî”k'Öhù¨ï§—yÅÆÁ}Çp¡àÕ®3í½zõÖ¡e—Ψ‡ÉÊ:Èþ �‘JÙá¦òëªNÞ¥è*á‡0:"‡ß>\È!B蔟¦."}ËLî½cƒ† eà…=èѱ¡ÞU_ýl[gñÞŸih†xn~ùMîëhBÓ4tâÛv§O;onhG~¬Ë.àîvnšH©}tíYÀ›óÐ ­¹õ…ç˜OQ®+íèܳ7qöÛ¹n*KZÁ=ýÆ®Ö®Š [¢æ×ðÞçwÑÙGG×]8íNª:„�Nc©¯žËß¿.#]S‰v ݽŠúŒ¡Ý.‰ÿž�¬aÞ² ^a�êJÚÄŽ÷1óµkˆU\h:(=z3¨“/wLùŠ}‰s˜½þ žèS4^îq[¬q”~'ýN!Þ9‘^R®NÚINd9ÑQŠ ÅK©~­•�ÂUÈrer"Ó…i(UV/÷¯ûÚèÅÿ;ýZI-u—Íuz ÍeÇá¨þPQàÀGxç)ž}û7vgîaÑì=,š ŠÉ�èÖèÖµ;½ûô¡oçü eKÛÙ²d9Éš‚W¯«ßNÁîpœ~ÛåÄ«ó•\ÖîÞÝ}œå+ö3¡]; ì €Òj¯}6œ¬lÍbØK¯Î¥Ð¡w'|~J¡ðèŽjú©Ya<-§+:  (ô¾e|�N]ô§¤¤$fÌü’¯$33‹��`èÏ·ÞL³fͪµ-}?¯ÎC3´dô¨vô’šÅ0rtGf¾»�ÍósxÌ8Z–i®§ö@ aØÍ£‰vY9•òìr@ë1\Öq¯oÍfÝúD}º`ô¸-êõGéwµ+w®õ;!„hçèƒZq&MjÍ“±8cÓ�½¢ð¤;b†?Ì̾潧îäêiægGI»×1ÿ»�yîỸêæÇø¿_÷�]:©TKeOb6*±�Ûáï&åF×ÃH脊‹ä}É©jÐË�¨æ-騩§V¢árر٠)нðV»�Òi¬ž–;ÅØžžMœïO‘^µz ·M¸›fÍ¢ùúóÏØ¼~ _ÍüŒ¨¨(n½s«W¯­ÆZ4ÿ±€Í60%\Âȸ3ß�z ½ÌàØ·�ù»îW(Æz¶UÏÌcЃhÛ6�¬£ÇÈÖ©—¶XŸ¤ß“~'„k”é%­æ[­åŒ¾ÞÍ×Ë>X|в ò kt�Ð )ÐŌŬ¸Y7•�]ú÷о¯ª|å5DsX±)Áty =ÇÜŽA±“¶;[·leÃúÕ,_³‹Ôô­Ì}ã1¶œÊÛSz¨Î,Ndh€‘°°`·ÛU AåZV'5.ûÑìŒc £åeÍü_øuåvJ"#dž£Ì÷Íj�•+®¥9„Psù×›œZÔ?))‰gž}žÞy›Úãt:éܽ›Ö­âž»&2è¢LùÇ|>ãc¢£¢*^‘}¿-Ü�oúŒLtÙ:ôgl??Ö,Nbá½Co|ܬF Œ Ìä~ŸƒQIEËÍ!WƒPW}´ÅR¯¹û]ú]-Ê×ò\éwBÑí�”ùy¹žVýhå‹ÊIòŽ'SëYíùrmIÇHÓ@1EÑ<¼ k¸6\…€æ�Ü¢C¯¼�Gs÷ðý«Sy}I‡~ù�ïF¼Ç]í €óÔ .&£¡ÂiÒ ¦¢f¡;�8«¸¸êÙ›x÷‰i|·Ï Þa$ô@ÿ˜0|¼0�()+ùjþn¬uT®„b45ÞÆ{–|úùWÜ|ã ´k×Gñv{vl%?/‡ÝNûöm¹aü8>›ù%O>þH…ë)ذ€…É ±çËG¹iVÙ“®àʳ££‘¹|!ßqÃÝ´/¯ Ÿæjô*nSWq›ªû¶xVH¿;ïû�BxªÑæt×d;å—5ЦsL¿­Âž¸žuÙ—riµ&’µ³cãv u0Äw¦£¿›iºÜÕLÓJ}¥î.§ûÌZÖ4+µj:º¦¡iNp^q\õø?IÜösÓ�³qK ®vÍPo|Šç ¶ZmhXÜ……EÓ½)f3ÞÅùðî÷ŸLÕÑ ÉIDATÎÖ¯ßbö>jô(¦½ý£¢ Å7f݈çXŸÎ Š.âz­Ë•ýò 1ÞaP3µÙƒ+WòéÇár�~SûN]Ù°f.—“Ñ£F1ñžÉoGÏbéü•di ª 2S)¨`{UÁ™·ŽyËÓzYĩܴSk¶Ù°écµ¥¥(fï¢6åq[¬M”~'ýN!N“´H»nÒ¿GÌþ¨Š �}s¡e5läÇŸ÷3ü¶6å¢Q†–±Œ–e¢)^t6ˆX¥h]Š¢ ºË…ËÍÕFË9ÉÉr‰¬uÍNæÁ]lݵ�“ÑC¹¼GHÅ ùº ‡Ló0Òu mÅs&«‘4‹2@Š“ä¤\»i.R“ÓÑP0GFQé`¿ëk7¦¡a¤û¸Ûl§ðŒéÒt2Ž'‘_ö˜yZNœ!33‹°°àJ— &##³Â÷µ¤%ÌÛP€®FsÃÛ_òpw¯ –t±çã;¸eÆA¶,X‘KÇ—¿¡2'•T«¦²!¥‹Ì´h(˜BÃUέí}Àv�ž}„gg­#ɪ•YÖIö�¥¼ÿ¯Gy}Mºw<ãž¼› ̧—36‹#ÆZöz–nËC/UÞ™²„·¿Ù�fPÜÔÅýqS Œ P<-aõމ…‹n¸šÖ^à8ø=ÿ~~ëÓìn—µ§®åÓ—>fE®Ž6„ËûXPŠëÓzäXº˜œ~aúŸÉ8Ï(kcÿÜ/Y�ª¡ôåÊ!!Åå*¸ú«aDGª€“=[vRXzYg+?x…rà TA·žädɱ÷´\½\ý:Jð¼N `þÂ…nêyú÷ßþÁ �ݯö•yÅ¥xÑyÌ0âªÚføÆö4£hÉü±`3e¶«èÙ,ùúGv–~]#kõ�Ì;èD1¶dð€˜Z·EOû£ô»ÆÔï„âüãAN÷ÙQz;¹¹ÙÕ^¶ô«NC&¼ò Ó^`Ɔc,ýd*Ë¿ &¾]kšû`rå“zx{�gc× !]¹íéiLêlÂQê{k¥Å .Iø†½ÛSøåÅGÉÞŸ¡& Òvó÷Ò-˜¯šÀèßßgî M;3ô)]ÇS¿ûÇÒ2DemJ2?½ö"y="! nì]É“ètÔV7ðŸG�ñà+‹9¶æ3Þð=Ñ­ÛÓ¾E8þfÍšKÚѽìÜ›Jž Ô nLœ6™¾>œþ>j �ݽŠ)ooàï7þÉ”M#Ò)_g&7-cÁÚ£¢þІúë§záv_ÔH�êÁŒëHþåe*ÃÐ6¾Ø3±iÅ ¶8ú3í• Y0ù¿,/ÜÌìésqöJ ï€—ó¯Ö¹o:jSÿ;o¿…o¹�>½/ K—ÎåÖ¹uÛ6fÿ8‡o¾üÜÍvt²WÿÎ’ ŧ— £êL]?�îË»k—�¹b!ÿßÞÝÆ6uÝqÿÞk_;vœçJZ@¥êXºvÕè& Ñ­†Ò‡©ë [;uj+4^°uR_Œµ�Ö7P@bZ·©**kµ¶êÄÖ ¶i1i¥Ôu[ÑÚTŒ‡‚xI!$¶¯}ÏÝ‹$`H±c'Žýû¼Lî½¹NÎÏþçøøüw,þ< j-|ßÇö´¹ÌnâËör÷¼Û¹¡ÞæÜÁwÙ¼eûAšî]©\ÜM(DZ˜k•;åNDd<í–�YýœáŽõ=Òá›Y¼ö×ÌÛö{^ÿã_ÙÑ~Œíÿâ@ÿ!–¢vúí´|å«<¼p.7†$m0…E?~šS+žçí‡Ø¾éÛ±°#S˜ýÈ~òͯo³ÀwIºþÐ÷“Yu>Ãí øÇê­9ô.:dž5�Ç W~ï!m˜<ÿ^kžËoßØÈæ�íÙûÇ÷fcÙD'Íä®y÷óíoµpsÔÅÍ\øêÁÔV°¾ñU~öÒŸyç­ß±çoç†hl¾›ï,må¡["¤S c‡ùbò½ËYyj%+7ìb÷Ö7ؽ,;µ³dÕ�ç‹5 &?r¾ò>ûÚÖ³öý…Íüû'‘Nºìšf_±ˆk×ð«×ÖÑÓ_9Z¡k˜õ�e<³dQ“¾øcr‹¹æQ¹SîDDƑոx��Õ×BíÈÏ[àû>Æ<ÏãÀž™ñ©æ‚ßÔ釖fuü5^¼Ê¶&ä8X¦›SÇvòË'V±¥Ãâ†G_ä7­7a¥\\75|;cÛ! ãž9Êá“çH95\7ý:êì$‰¤O(ñ ©žn’ëI�(±ˆ&Iü|ï’ËEqÒ];y*ë˜ÒP�—pGôZfÙN8D0àÓsú8':»éMzXá*ê'M¡©.„ŸvI%Ý!?h6ðû‡mzOåèén\;BCÓ4šjxÉnú²"-%ê±ØÃœt‡L· S×4�ë«ÁM$H‹@¸Ç;Ç'É0µÕR= ¼\Ï F¨Œ†°|—xwœ±ê_tpß¹ñÓ·°mËÉn8ƒå;O�`�ÎOβnÝKü}ÇNΜ餡¡ž;︃ÖÖ%ÔÕVã¥ÓCœiãD«ÁOõÒO�¬Ž²‚„++qlðÝÄ]ƒåTR ‚— ·×#X�Þ:z†x°Šk§N£ÑI’L¤7ÎÉe,BnyD¹+–Üå+O""ÅnÚ÷^` Î.Ê¢;V]“ÕñçÏ]yùÉ¥,,ÛgÏúï²tÃÿ ~Oýb9 G¶¼Ý²Ø–Œ1£ëÌfÙ®å›Ü¶á²ú_°ú÷sèÛÂ,‹›ºøx²?÷² õ½xw��'}=ÇóÆX±ݶm㄃–máŸt:…ë&Ïp�•Œ¿«1Þˆr’ËXÌ)�ÊݸçNE·ˆ”‹Ì¢»(×twgUDgËÇ70sá£ÌÙ²ší�ïðÓg_ µtsnª…ó½Ø5õĆùÍøÆb¶.×[1Ã̈es‰ÑÝMÞ�oð¼+\iÈý›Gq^‰ÈÇcóŒÁKÄ�øU�3Wû»yJöc1§ñ«Ü•}îDDÆCkºKã©Ø¯½“åOïáij›øh«Ÿlëû†s+O¼¼‚¯s7J)%’'¹² ѧ LšØ¬e¼òê—iûË6vì — j›>Ç­Õz«SDDDDògDEw©®·óÓqLu3÷=v_³û£oRWø ””»|d¡Tó$’-eADÊIV3ݶÀóaªX�R’9¶ ùa/åIÊÁXåID¤ØeÝ‘2óIs 8Ш”¢±×Ê“” �k)w£j¯'Q‘üQžDDDJ—Ú‚‰ˆˆˆˆ˜Šn‘SÑ-""""R`—¬éžöýuÙ_ÁW3)qV`T§k¦[DDDD¤ÀúfºG3[=ʪ_DDDD¤è�ruÇÿã &|ÊIEND®B`‚Solaar-1.1.20/docs/screenshots/Solaar-main-window-multiple.png000066400000000000000000004164521522022367600243340ustar00rootroot00000000000000‰PNG  IHDRÖÏ®|MÖsBIT|dˆ IDATxœìÝy¼\u}ÿñ×÷{Ιåî¹ÙÉž „M eQ*µ.ÕºU¬»µÖöWŪµÖQ[mµVÜhÝ\¨Ú ˆ¬‚ û’�=¹¹¹ëÌœíûýýqæÌ=3wæÞ›ä&|ž�G3s–ïù~ÏÜäNÞó]MÌz˧l³íB!„B!„B<õ}ýªq››}‘j}ë.8TuB!„B!„â÷Þ,Hr³LÀV{2ë-Ÿ²{ž÷ú§£^B!„B!„B<#̼ã;µpMAªõÿ§Oo­@ïÝ?¨=&·C!„B!„Büþë½ûô}ýª6T™èé¬ÏÉ]uü‘§±&B!„B!„â¹BÍz˧ìÀÑüt×ã€Ä…ŽÚs§"ÁšB!„B!„8¸zøŸdñe§».dæß©=\ý‡OcM„B!„B!ÄsE¬ÅÏÜa P?47¸ýi¬‰B!„B!„x®HæX{ϯ óÃ=ÃÛ"„B!„B!žªCAŸÙaTv(èðŠ>�5B!„B!„ÏϺ¡ …]ëŸÆš!„B!„BˆçŠ {¬•ç­žøl�r›¼¶-NPìkE5»pÝþìâ ÏôÞwB!„B!„80GœrfíyG×÷×Dçg÷ű˜ðZÍÊ* îe×¶-”G†pâð ·£±œVå6¶­Ù9Ùíå‘avnÞxÐÚ1•ó[Õy_®Ýìýh¦Úc­Õ“„`ÊM´ôyýÎñç׎u&.7[J`o‚#lÝPÐÒ‚ã¦\¶B!„B!ž}& €RÙ×Í‚—¬ÆÐ¬q_cXÓ¬ŒÆ²²å5† Ñ-öcÐZ×SÖŒŸ6k¢íSe¢/%ÂÔrš©´cªšÕoꬴC…8®W;?½GIPç� =íhVŸl=׫Õ&Ÿ¥A)@P)£­m™›Á$CA! ×¼ÇoÁ?j ¨LE²Ã=›ô4ÓCØŽöj7Áj Æ¢G‡1Ý]i’P­­ð×.!÷À-«^\«c­Z2T!„B!„UÆ´žSk¢}Ùý“7UÙ .[¦Ö›™ç¾Y¶±¿uhuÍ}9·¡"@X5ÖO¶º_[sPÚѤÀº—i½²õÛ¿v�eSS Ú|uGXÇE�lÄt­¨ß™ö(ˬ1@R¸ÿ1ty&ñŒmø«�¬?À’„r6 Ðò�¬ÇÙÕ†éØDåø£ ç�ÏᆉšžN´ÿhRGcèÍ  ;ç¶l¬B!„B!žýüÐ�×I°�®R©G-³&;V9î”ÊÎÙYןcŒÁKh’ð#Íi&kG³í]3Ý7•ó”ã‡AÓûÓ¬0`yÚíC;lábˆ�\Ë÷$nè\7Y½&Ú>Ù{ž¼1¹†v43y�µ8ªQ&�-Šð6o'¿%À_ýÂÎYäîýztÓÙÞ¼ìÑ2Nþñ‚í§íÆÿ%\¢ —-×mzNè·Œ+X'W7´ç�_´®£B!ž%4Ý3:™“lLÿ{¤ÓºB!2|£È¦i�Òøùœ† ¢Õ±��ÍŽ�£ˆt¶µìóF­Ê‚úœ&ÛŽ4ü‰£·!jõ¼Õu';¯±-S­¿ûøA4a;š�¡¡ñ>¶Ê†š\·q{z~úØ´mMö§�9±§I;M¸x�J/˜h"µê®¶»ÄôœJy݉訂2ñ²SÉ?ú?”O\Y·rg2Ü �>E´ä¥(,:Nxî–ûðn»™Ò©Ç�¿P&ÛS ¬vÁšú¡ Œ{B!Ä�qóEö¶3«Ý£¨Q00RbËÞÇòW°jçÕoxŸ>RƒéçSŸü1ŸÜ:=C4„BñÌç[E^Y*‘Á�”Qµ9ÁZ¨X‡vOÕ…1©Æ×�åMVöX!Ne”kÙÆ¸vdÊŠüJ‹r¦÷CÙ¾–ç[‡œ6A©u;&á¸n][òîØÔd±“«k{6K] ®«¡úè·hCZ~³÷Ó�“ÀKgÚÑÌ„=ÖTb¯akó�-œ;Ƿ訂u¼äÜb7°§€xVoÝñzï*X€éš]we áœ^V2_7kÑ‘ÀŒû¯¬m7^óÞqB!„Ø?ùžùüÉ«ùÓcqÒü6 M:°ÛÈgã¦-üßïâk·lfãÔaÚ*Êô£·(¡b Ö„BQ/ŠbÜ ßMÄD!º:~AÅÄQºå¯P;.Ž¢ºc[•1‘¤Œ_åДÇå4ÍÚѬìl@4•kW¬C.® ]oÊuÝSi‡�CTCö”.PÈçiÓ†œ“žè³3s^P.¡µ"ª¾Ž£ˆ®êÒ£9GÄ\�™–×ËnK"¼¨DؤY­ûÔÕnB˜ô(·£:Zõ!\´ïÖ[‰ç¯F›rÒ› ˆWœJþ¾oP:½glñc)Ü÷Ñš7¡–/Uý·®=¨Îæšý Hz¯ÙêR±Ù¡ ½wÿh²& !„bJt5ÁÑç¡LT ×ìœSÈ=yÁŠåxŸÂÎ8±š¥Ç澎ÒqK@gVDHõÆ)ÞèÈÇ*-Ã?…Bˆi§X°î,®xà æiÀÆìxòq¾uÛFn~ªŸÍƒ>£±¢P,²pîl^°ö.8y =hŸ$Ÿû˘½—^ÏU#Ow;„Bñ\G!q’›b¨f⨖™(¬�Nz¯UÔiU[ÅÓfV�LÏIÃJi¬5c÷%n%«ïG¾!@«Ý»ì}4MÈÌÌ-æXÑå03¯@)F*!Ûr9 ¥˜í G1‡'diwŽžV€¶¼ƒVŠ=ƒŠñhÀ@õ&¦¡šãºuAߨ|k!ÖLíKâ ƒµ} ¬LO7&ÿ0ÎÀ6LלÚùñœÃÉ=ð0ÞöÇ‹Š‹G¯®»†ÜI\܆™±šÆ¡ŸÙ¡µ¹Öª‡(k˜™YT†‚ !„Ó ¿�÷½by5T«pÓOίÞÅpc'ö¡Q6ïìãÖûæ²Öò•÷œÊ¹Ý oÖQ|ô¼G¹áŠíŒŸýC!„âÐIçÐ/ãU{'¥AY¶×YœöþrÜÚ~Ó00¢5»Nö1YO²õc­Ìêë8 ÀÍcË£M˯…]A2熗/ ´Æ F‰¼bí¸°:ÿ˜—/Të<®)­iwa®0¿˜gN>ÙîXC[Fƒä|Çu±˜¦ç[c°˜Úóšt�b“ùÌL�í7­A%îéæ X£t&p41b OQfæ]fä5�±Pð8ŒÐTBH£­9j¡ZGÁ£Ý…œV«(xNuUÒfóßegiœS®1 l4i�µ–Ò¡  ?S•£–Ð~÷Í«þ(ú©]КàèóÁpª]ãp’Gkp7ÿ†ÒIK'¸àX—5«ª¯MÖÈPP!„bšå–.ãE=ÉïÝpË}\tM“P­ÁÈæûø«ïÏåæ·¯d¶Ò,;y5gþ|;¿”dM!„‡˜‰"ŒIz�ÅqX ÍÂÌÜ]0¦5¾Înw\¯öÚ7§YXwLº¿ñyã1��5 =Ö²íˆâúIlMueËǘº@ÈÍåjYcP”ó\æw˜×æP¨¦B3 ¥Ø°}$¨Ö¹~2HVû¬DNm[ð5§‰›ö¼K{Fñø‡É= ëîõ¨ëQ0D‘&ð<Ë!• N CO.©SwN'¡ZÞe¤9Ð]ô0QD%Œ)Çà„†"MAž?nì·ìA˜5q°–¾i¶q&cCAÓQ›éæB�pfˆÓ·‘xöò$üTXAí¥1í½Ø\1Ùçäpv?I4³„m[Т" =Ø>ØËPP!„bzuÎ좷ú«tËnžœâº}÷ÝÁû~¸�®~Úº‡Ç[†jšÙK—óºuË8}ù,–Ï(ÐéBP®°uWw<²�þöIî:À t‘µÇÁ«Ž[ÈI {XØ™§èX*å2[vìæÖçÛ¿Ý4A=§±,UàŒsOæ•s56ÚÅ׿ÿ ÷çzyÕKÖñ¶c粤qïÕÿÇë¯íGf§B!ž>­Â¶fû·Otlã1ÙGÇõpã  £©­5ÑÊ£ièÕ¸½b5±“'ïj:«y^%²\E›ckÇÔØg°Z¯.œqÛZÕ'ŒÌ”Ûcžï_%ˆés Ænh©T?$yÕ)Äæ÷´×Í3Wpb¢j=*1PŒÊ‘�_IB²‚ŠÇ]+û:}¬�ŠãIÛ1y�µÚØÜ†pM5$j™çV)ˆ’£ËC8OÞ@œï'š=¸ÛУÝDKÏÀ¶uAXO3^Zf‹%<ªcye(¨B1½¢ØÔ~õ»ÚèTàOÒc-9q/¿øõÞ‰�ÉÏäÏ^w.;¹—ÎÆ_ñíEæÍšÁ‰«Wòö—ôsÅ×ðþ›÷Ð|@ÄÄr³ç’wœÁ óè&×™?«—“Ž>’w¾xŸøò5üdž ÅÚçÓU–ÃòÕGñgG9øÍ•›X}ÁóùãÚª##,+zrh�`M!„8Pqj¬—€v]LMé¨ÛÖêüÔTËmõGa-È'(×®1Q;šíK·øQŒ"Æ *ÊS‰’q *©PMÙâÇl]•Ýx€œjð:ÖŽìýš¬]~¥Â 6ì.(òä(áyÃaòI«¯˜Ô=4q-xëô¡±Œ1Û‡+ Žú”3·v*ï¿GÌäýÕ¦²xA«d®qñ‚ôxß'·K¹=Ò�óä/(�°Û¹( ã4„‡/E•J´ýîÄ ^DtôÌ`ÝÚU¼é„YÌ(ôòê׿”.óc.¸ehŸÂ&UXÀ?ýå9¼ižF#;7ñýÛ6qçÎCÆaæ¬Ùœ}Ê*Î?,O~Æ>üÀö�_Í�ÇÇaÓWVD%ý„©\fó<Þµ¶ e|žÚ:À¶P1:· ÷„B±�‚úaŸi€3ÕÇVÏ›·?ågµë’G©^vÈgõyv5ΩÔ7VTL‡ º�ô8›™ƒž¶9Ç2)<Ç£`ºòyfµ� K5qÌH5—)…¶®ìt�‚ìÂÚ5ËC0A;‚J ×ËMéþ•Ñ „ŠÍƒ>QlXÚS€0ÄDíæhUƒÉK)2l1l & ks¹YÉóVï‡ïãÛÑÄÄ‹4LÒ—Ô.¢íw÷¡t±!øJ¾ÖVQL¼à4PgÃM”Ž[V Ëêt´S>yÅ[oÆñÌÜhûÍ�à9Œ›¸ …¥LùŒc!çÖíWq$CA…Bˆim~”ïnZË?.sQn/oý‹W±ì×·ó™ëŸàw{£ý ‹^ðB>R ÕÂÝ�òÎÏ^Ç•ýÙ¸n WÝþ ß<ù\~ö¦¦ÛxÑ+_À+ø%W Mý:K^poš›aþSwòʽ�;ë†h®ç[×?Ì»þò•|ô¨<ºkï;sW^¹»áÛÕi,ËÚ±‰qUçŸ1‡ÛàÍ—ÝÂÏvËg!„b:©Ì„óÍ&ßo|�}ŒÃÇËÕ�›®ŒÙxnzlãcã±ÖUkâ  ¢rDqL6.ÊUçÂJÛ‡>Ž—¯=ÏöW®JVþœ™s˜ÛîÑžKÚÐÓV`f.©[hB�£Ós˜© ÇÎPŒvå‰-Œ†�£!»Ë1¥�Z˜–•Ý–®zZf|;²ï‡ã8Da€ëåj+o*=¶-û0 l •È`ƒ2‹fvÑájp » —ȹF9tT‡³TBvT|úKe£‰ÂÇqêVûlµòg3… íhfŸ/PÆ ÝyD+ÏN*¡5ªÉ‹ö˘ܶ}ñø2’3±m˜žª2‚íœM|ÔŸÔgµFGÆÍá>q=*б¹±*+aµ+CA…BˆéförÙ7oå´¿9�³ºÊëäìŸÍY/:�[¶sã#Û¸õ‰íÜöÄ.ÖO±—•žÅ›ÎZH—l‰Ÿüèfþ§¿ÙNÃÆÛçNZÄg�ΡۗðÖ“»ùÉ5ƒS뵦r¬9¬�Ár„[„¯¿�»šÍ{î忯~‚÷¹š¹J³ü¨…,þYÃ|rÓY–ÚG&g&§,ÚÁG>~3?Û}Àý…BÑBv((0~¾…¸þQWc’8 š×d[zlãc3銣ٕGÓkm@ÅÆX¡TÒ»,Œ"¼(-ׯ{LÚ×ú˹Î6—™9XØé2« (¸I°–Ç<‚ ¤ Lˆ&—Ót¶(Õ9Æ\‹§“º•ŸÁJýµÆÛç5´#+®ö*‹²÷©alv_ WŸ÷ær —ft$‹aTbúB‡b¥L{!‡WhƒÐ§Á`) Õ˺ŒÆqŒã8µ:dŸ×®çpà 9ÁíHM¬Õ&h³éÇåêcun³¤§˜›yž9wxAoÏDÅ'�šÕƒ·g'q~yÝve"”ãæÐa¹É™e Ê2T!„8üm÷óÆO�ð�×�Æ»VuRP ”ÇüE‹y͢żæÜä[Êþ]»øíc[¹îþ'ùùC}´ê|å¶ŒÏM>Ô˜Á |ïA¿u gGøÅï¶òñ5ËhWǽˆ9¿dûT<ëó‹o}‡_|+™Ä6oÖ×ñ·õñX s]Ð=�¦àɃUVƒ‘à[;%TB!š( o£}šÊÂÄn\!r Ó^7®Q¨]'{M€(L-ùà�ùƒ§-¡Iº+yÚbpê¶;ZW¿É+Ú€íí,ìH†w¨I87Œ…JQ‰’×סà:Ö¡ñØ14–Ëhb NuÅÌäúŽÖcCAMòy©®qq€‰B4`ªuÔZcŒ©_i Ö¸¿VFCÿ1ebÚ� }Â&3ÖfË Ã°éöÚó Õú¨°2éÈSï±V[» Ú 1]í³Õ0L�c“ÃëjaÁªêöê|i&FÅÕÄ5Mm ÊIÂ=å L¡åÜ"å(bÚtL—kèõ,�o(�”mâÚµ=bÂêuLÃHLcLr/[¶dÌÄÁZ“ñ³ÉvÓz_zHG/îöAÂeé2‹Œ½pvõc:Žk~ͺkdi뎑¡ B!ÄÁ³sÃz>·a=Ÿû®Ã¬ys8ùðùœrø|N9|ÇÌÌ×B¤\çl^ùÒ?ä¼ç=Ì_ýÇ ü´/ýý­Y8³³ÈYvô MRÄ{‡Ùjà8t±ƒE¨�˜*årØ¢œ¶bGÎîdnGŽvOã:Wk\¯�µSýšq:˲!›ûJ¾„B!š‹ÃZÏ­4ÜJÓ€ ’pˉC*®—9¦>N ­ÂS¶îÀ«ÎV{� ÕB« 3œ±„µÏKi=Q5èl|?š™´ÇšŽ‚$½mìpf›Ëj Âùù]�af.Ã,>›ÎÛn&è 1³z@kôž½x9Ìag`‹]è= æ[l{frÀqܪs³5|¨ÖQ CA…Bˆß6àþ¯ã¢åóøï“ÛÐ*Ï WÍÁ»k3Pö£Ú×cż7ùœÊ£˜Ž™°¥)Nu¢ºWò±W-­aenüŸ_òö«¶Ó×,È*:¼Æ-°é,K!„‡–m‘[ÄQ„ãºèjÀÓ¸]å‹Ìió˜×á1¿Ã¥ÍmÝc-Œ-^CwöRnìõhè3\-7N{—UŸg³s³MÔŽôøÆv„FÕmO¯S "â(bð­"_¾º¤Ó£#7†•ý€a?fó@¥¶PuÐ׿ IDATAmA·>:š¨5-B€À(0®ëEÉ£6ÕPK{DÕò] _ðèÌiÚ\E1—#6J‘%6†R³±¿ÄÞ ¹ß3r–¥½mµp-{NgN“oxÓkGQD{µîé67Nz¾Ù)t䚸ǚ‰’¡Ÿ0A¨ÖìÕbÝ$ùT^³ü œ8$·g7Vklq¦·Ǩ(@'µ+ÏÚñ×Sc»Óç: °ZËPP!„â Pä\EíC×*ëó»Ç÷žÜFEWW‘`Ù90JL7š¹3Úqh5«EBw¶'�`£;F§6trÖÑ+9³˜|X(=r;ïùåvúZœªÛòtO�ðMgYB!„8Īó|Åu½¼’¡~q“<�Û‹yż�=õ+P¦ÃÇ]&¶„ÖÖ¸6W3¿Ã…8bÇ�a¸¡éóq¡Tä� rtuh£FäM”„] eÅÕ�$nè5Öø:¯lÒ+¶Õðª¾}i •pé‚�å4kGö12ŠBC;Tuá7jŸÿÒë%�ÕQ™óÚUDuN :†B*JÛFB6  Ž&Aà@{Gkæ¶9ô´åè((蘑êù¾©¿îø:Ôo›êw¥Vq„j5TCU‡€6nö+ä·Ø®yµ2@¡œfÆl÷|ȵ¡â±îL÷|rÛ j¤4VЄŸ�íØ�RcP&ªýB!Ä�é\q,Ÿ÷+øÍ¥ocý_®bþ>…EŠbέýžü°:1¬e×ÖþZO¯ö…³8|’éJr‡ÍdeõM´£�G'^7©J³d^wur`ã�ncÇŸ)z_Àš †�N_YB!„8”Ò Ç£qÃ-kókùåqÛkÇÆQ]�Ö*TKyJ5?&òÇ•�­O©4R½\uª«¨~Ê|k-„òÕÅB£Z-­­ÞÙ¤]u�A™R3R]!ç(F‚˜Rc‚rm…µ²\3V¯ÆòåMe\;’ÊW5ºe�õ ¡R©°wÔ§oħ¯2’ Õ¶Vè.3&Çö —yjo‰m#!¥€‘J…¾RH߈ÏÞQT’^ŠMÞ‹¦ïOä7oGƒÉ×®²f|È¥TË¡ ù‡žÀÎZ;v.€µ8OÞ„qÂdŽ”Ð%^qZ²ðAjÖѼ‡òÉG'Aå>Ìç+CA…BˆéSòô|ŽÒ`;�å¯�XÏE�SûÕ¬;yñ±³’ï­áá§úI?:Ÿâ¦Ñ5¼¦SáÎ[Æλ“·µê çñüc1£jmxd+§Øq.›†±i]oo6o?g1�µoëÆÍ81­e !„âÐË›dz«Z@”/Ö…:iOµ¬RÅgË`u>²îm®7Üs"%?dûHÈ–Á2¥¨ùœjca˜“Ùfh5››o^`âí¸Mƒ¡4ªÛßp<@92ì®Ðæ9Ìéðð ì Ù9\¡\©P[\Áq“û•OæÍ�ü2n¾ˆk|*arlzOÝê1aµ:ö›.VÕxÿ¡ºp@¡]ízD~™‚§ÙUÉCµe[ÇÎ{|O?¶”âj(G”òEv�ø •†{;(ìë¼µcا¿T!0zܵ[½?$£1ƒ†NLa(¨K2<“ÌpÌæ+õà ù½EÌÒîº2ôžMT–V®Þ“)îx3kV»ÉuÚgàmhÇß;ˆéMÏO¯£2ÃA«u±UMQe(¨B1}¢-ñÅ�áߎɣuoyëyìúê¯ø·ÇJLØiÌi笗�ËÅ+“ùÓle ß¹shì•¿™oÜ>Ä«ÎîÆqfò¶—Á÷/{„ÍM>qåæÍû×u$hÂ]|ûÖÝcÙÖŸ9U±|=j�þÆ�.ºƒ—¼æÞ3;`OXd–ªP §n|êt–%„BˆCª: Ô· 'Î óK'ù¯n3qT{I�T¦¯š–„QDWaò>IÊËc«½ä†*;†}ö”Ê£Ãà¶Õ]£í¸äªóŸ5 ¤òÊeê¬wÒ2S�Ç—Ãöa]m_åmòÙ>ìSBL“–²aXä—ë>â¤ûÒÇ–ƒ¢€¼É ÍlÕºe·%Á]™~£ñcK¾nö—*µP�8Ç«�»Ç‡‚§é/UèmKæñ÷cËÞrÒ.íè¦÷-{´ãVï�!ùè°„a?W…+n6ë±f ÅûÖcžQwž21fä1‚u'Ô —.&·á.´YTw³ðXŠw^ËèÙÏ«†hSK„e¨B1�ìßÿîMœ½à,^Ö«qºrñÿ{=¯yh=Wܳ…Û· °yȧYÜ\žÙ½=³btòJþ`N­Àš×üøf¾·7ûy!æ¶«nåG'¼˜WÏPÌ^{:W¼%Ïßýô!nì “�N�5k×òá?=�“ó€�xðÚ[øúΩve·ìxx÷G‡q¢«è>öù|þ¬þö†íìŒ�cÙÊÃyçK×ñç+nþþ¯ùÝ©/æ‹4Ê�Ç‹VøÉÝ•êW{ÓY–B!ž^4í5ÕŠ‰#|•co9dÏà0}Ý�D±ÁušGFÙ}Q5” ¬f äƒÊÁ0G„qLÞD¨83t5¬Œ-� ‘¦ªeËOUBCÉOzÖ 'a`É©Äf,°:@:¨ŒoÇD2mkT 6d4WÀ¦½ÇTu~¸&ç¤mØ30� Åuó˜êñ­î[v{D*%í°ß“‰ƒ5�nrH“k¹­Ûp�…77vž‰P[ ´v èÌ VTŽ[Nû�÷`—>oìxeÑî2¼�[—-¬^‹&ùZæú&’¡ B!Ä4‹ûãÝŸ�ÙùæÓyë²"®Êqøš5üýš5“žkJ}|û×pÑoöÙ¡'¹ðK·2ûݧpf·ËáÏ;•+N|>#ãôùŠ®îvzsªÚI=äÑ[®ã‚Ÿí Ôä:-ë¾ó!>~ÓQ|ïÌätç½úœû2ŸÝ£1…Ž"ÝžBÙˆ‡o¼Šwß°™%3‡yߢnÕÆ«ÞöNÙ5Êã·þŠ×^ÝG4�eíC„B1 šRyà«\²š†3åЇÒÞñŸBœLT·èŸå`’r³×NŸ7>NÁØÜo™pÍÄhí4oG«kU+Ÿ 0P�øß¨úvhí$å[SWníš™kÔm£:úÑu¡ÉB§‘_nÞîÆ{ÔÀW9¨øàTß·ôrÍîoõ¹ïäÀËßê¾7¹¦ ÊÕ¡ ÍÛQw¯&ÞMÝŠ uT}ÚåmÙY ÓÂÚyº4@Ø6H<{fãÉijfÎ(¡FöÔŽWÆ Px›v&ÛjùY“ïz•­Õ­oݵ?B!„˜þî'¸øÓßáÌËnåk÷íbK¥õcÖ„ìØòß¼òÎýðüÍo÷ÒjZÛ‘M÷ðÚO\Éßݸ… eJÓÙÕɲÙÌÌ)°Û7¬çÒ/_Á¹ßzœMSZ´ [Ÿ~ø3Þø¿y¢b±€“Ë3oF=.Œömá«ßú ço»¬áŽ_^Ï¿<2‚oA9yÎëbVî ”%„BˆC+ M\÷À7™<£´Äq\ÛŸ>w§.D«ƒ®ýpœ&«9^RN“:Åèº0§ñ8ÛreÛa”ƘñåÖm�ÃZP–nÏg&[V“@M[S ÕËÍyé¹éñÙ²[‰•ʃQR×4wªuÑØ5Òç ¡Xí\¥ê÷§çdƒ²ôøÌ5jç4^³!¤TQ4þýh f½åS¶U/¯°½e ñŽ=åıžcµŸA ºú"ŽÈoÜLች0ÿxl±õÔíŒ<1¦«ƒÚŠéOmQÃ%ºnÞ€Y´U�í÷P>¢‹ðð%à¹cá]íº* Ô°´]'NW2ìtøˆ3južqï•6X!„ûI¹ÌšÕòÞ6z‹.ž²DaÈÞ¡6íbGe?†8y–ÖËòžmŽ¥\*±i{?OGÓ2„RyE_8“¥�Ž Ø¹»Ÿ‡v–¿¾“¢ÐÑμœ¡¨ÌPÔdåói,K!„×Èòç'!Ie'jèr”íᔾnìùÔx\æ˜8ŽÇõZsœLϱìuÒ°=vNãuªÛœÑ=äû7┇ˆzÖµÃ)ÖB+]šh”ëQÖ¬g™ð«I϶f=Þ²ÁX¶gZz­Ú53õ®+g’vŒ{?šÔ¹åû“yn”Bkc"´v›¿�o€NG^fÂ7�¡™¾ÎnwF÷PØõ8:,ÕÚÑH‡£“-^`ªNa®3×Ã?|9á’€Â}÷‘Û•…¦££ùñÖbÛ‹”º7ÜB0ÓRyñl>_ ÏjR å2ÃBuYA(ÊPP!„âP°}»ûèÛ=�eÆ>›6ogÓæi,3ÆeÖoØÂúÉ�¤22ÂÆCT–B!²†Ðªîuc`Óì4)# Ó’mNC™šLøŸ-·nhh³n mɆWÄáXÀfbt-pÒèLV Á2õKƒ0mÍøíÙÐ, uõµnœo,kמʰVÇÚú,ÓcL§÷" ÎjõŠÆ†[6¼�:³-í•–í_¦¦23&B[[w^ã9uÇç “¶iâ`-N¾ƒÕ¦ =<ŒéêÌìl\À yn<�òIÇá b:ÛÇí¯{®Áê#ˆaº{µÌq +’ê�aœ  [v*«‚ !„B!„¢‘cíø +•íMV¢Ùlè'PßÛ¬:t´6´Y(— Ñjåfƒºt[fȨØÆyîçTË<¦²Y|e{²5ö2k ÔÒúê&Çfï0áþZ�ºfsõgÅ&f683JÕõ0Ó-Þ¿ÚqiИö\k¦FÚúò›Õ£Z‡d¾8'Á´·^tò9Ö;÷pŠ<Ù›7ɪ¦§«~Á‚:™pZaºzš]µEÁ–ÂÝ�agŽªvT&ªýB!„B!„h²4h¦M¹Ì&Û²ó¦5+¿¶­Ú›­é¼Ð<ÛŸc'+§qúZ™–0´î±6¥QŶw!Å=ç¶»(½ÓÕ5•SÇK³ÆPmÜAõ¯õÀ…{#Wžƒ�Y?iœ B!„B!DVhbœfÃ4蠄ɵ¢Zµ–öò2^}]|«Æõ;ðuá÷?\ËðƒÊ”Þ�ßF) 6ÆjwÜûÑhÒ`Me»ùõ.$Î"÷»'‰�Q₪&MP™<«½Ö”ªÏÉTæ˜lµZ—·ºƒÁZœ’Å Û0³�†b¾®NVi*„B!„Bˆ:Î{;M%T›(|Û×`n²ãëzH…ek[ö›j¨ÖìšÍ¶M%¨k<&ûZk¯Ù°Ö°¼Ou›ÈT�Ÿô>Oôžfz¬Mfâ¡ Ö ª“ÏYí$Ï{Øj\ãT»õ)�íÏÛl[ãó‰öÕž’çÚÄ�)×je� B!„B!Ę4Èiè5YÀÔ¸?}½¯=ÚZ…6ySÁoUVµÎÙR޵ãVëlVGÏÕbÍêÒlÛT‚ºÆcê^Ç!a“k8ÇÓ&¨×ïm«{?Y½[…�“‰éóVç‡Ê!§]‡k.^� ¿š=W&®{ÞlÿdeMõ¸‰®ß·î‚Ú!„B!„B<·yº¾×”Ju!NªYØÒìuÞTjç5;¿U™ÙíÙ'» W]RÇ~}Ý h¼žÉµµ,·Ùó¼©Ô—ßP�t¿QºéyÙóϰébN~¬ÎñøpªY;¦ruPšôž6«W³÷){~ã5<[Ÿ]µ²ÿË4ü‘¡ B!„B!„Hå·?|pÊ=(¥fxmD™kÅ]ëÊeŠû¹¿8Éþ¯­®çÝÁjÇA×ÐŽfžÁš B!„B!„‡Ú³"X“UA…B!„B!Ä¡ö¬Öd(¨B!„B!„8ÔžÁš B!„B!„‡Ú³"X“¡ B!„B!„âP{Vk2T!„B!„BjÏŠ`M†‚ !„B!„BˆCíY¬ÉPP!„B!„Bq¨=+‚5 *„B!„B!5@Gžú÷w>­•™ozº+ „B!„B!ž¥ÿÕA9 ôÓ]!„B!„B!ž‰$XB!„B!„b?H°&„B!„B!Ä~�`M!„B!„Bˆý ÁšB!„B!„ûA‚5!„B!„B!öƒkB!„B!„Bìw_~ø¾»V=„âYeÕÚžî*!„B!„8Èö)Xx×µËF=„âYãKg?ùtWA!„B!Ä! CA…B!„B!„ج !„B!„B±$XB!„B!„b?ìókB!Dk† 4̈¯È·wО{&|2Ò?H)¶€Âmï¡·M~=¸çØ} FØ3T&i®G{OíÏâæŽy޽ÏB!„ ä“�B<ƒ„C[yô‘'xjç^Fü§ÐNÏœ…¬8b%K{rOcÍ|6þê+üëåWqçÖQb J8ã~À'Ï阾Ëýlذ›JmC�ÙK—0+eFqÙ»ÞÇwÀaÉ>ÏwÞqÎWö9n?ï«ÙÆc[‡1¸ÌX´œymªùÁñ ›ŸØÉˆµÉkUdîÒÅô> ¿Ɵÿí•ì6€³Œ·~å˼}Åsà§Hþþ!„â9N‚5!„ø½gxè¹üòò‹;·0ÛqG(§ƒE'¾˜7¾í�œd×!çï?p9ÉOØ�ÕÍC�”-±ñž{Ø43�\ÇÑsöç×�eàúåmŸ¸…Ñô2ªÈ)ïÿŸý£™´ˆ^Ä3LxçWyLJ¯Ç·€î楗þ€Xç�?0ÚÆU—|€�]»�кƒµoü8ÿ²òP×X!„B<—I°v€”Vtäq`(ÅOwm„Ï:¶ÌÃ?øg>ðåÛÙ�Ôj‡Å#ö«4Tëä¸?ÿŸ¹` ª !„Bˆ&´Ö � ÓÑ®qÝé�Âz°æiƒ§-¥hÿfÛÐm9þø´.Þ¸6ÏÂ<ãz8Xcؼ¡Ä7næçÛMuN–ƒoùº|`­‡k ë÷ÙPÙ[ý?£Î;,쀽{c†U…„Õ©…[˜gÖ³C¯ä7•’kÚ‘ßòåÿ¼¹ª©Ü^ü¾�ówç-¦.2{í›xçÝßâƒÿøMî2Øp ?¹ì'¼ü‹¯g™3¼�õÛ’9«”Ûâåsi÷wp÷Í·óè€Ë§ŸÇ s²¡”¥Ò÷÷?ø[÷Œè<Ýs—²fí*¶×7ºs›ÊlÌ|«°éÑG)iv˜ß\s2´ËÈŽÇyäÑ"*×Ë’¥³)N) 1l½þWÜ&¤ç�{=oïø&ÿòëaLø(W_÷¯{ãÒI†Àì}â^îxd�GïÒ£Y·v1�M�­°{ÃSôɽ×msY±¨§É/MŸ=›6±«Ò긩ÞËj+›½W ü]sÛ]�²uÚç,ãø“ŽaQ“ókÂA6íeô`­Ý�)¸ñ~kmó:øØ«»8µK¡°ôíô¹í©�m£–ÈÕ,ž—çùË<¯èà–yþÿõñá{#‚ƒÐŽzšc»xÀö»úyëU>~fgò�XþýK»ùîÀA¯Œ¿_”æ¨Õí¼bUž#z4ndxjK™ŸÞ^âwCÍz,)æ/kç5ÇX;SS´–í;}®ºc„kv4„åJsÔ1¼ê�9Ú°áÉ߼˧¯i€­9åÔ.Îñ|¾vC™íûÙYj艛(íx˜Ãÿx&o{óûøêå—ñ£k¿LÛ¼Ut­xáþ:%–þƯ÷T§y>6 ÝóuþâC¿¦dAµ�Ã¥?x%�àý|å¡–Ð{'œ•Äfï½|ûsŸã¿n|ŠQ“½i ]<Œ¾ñýüýëŽe†ˆyô{óžïª{Ÿ¢'®àïºÈqÄ–Ç 3{Cî½üoyóå ¾†/ÿ÷;9z*¿‰Ì&®ùÕcI%•çØÓÏ䜶ûùâu71j#¿ö:ý›9¢Å¯;ü ßþÄ'øÊ­Û« 4íË^Äû>t6z\îóÀ·>À?üjèYÄg¿ó·œÜpóíÐ�|ê]Ÿä†’–¼þßùö;{öã^VïÝ=—óî]Ëhú^]ù^zôq>øõÛÙÔ*ŽÓ½š×ð#üźÞú0Ñ–yüªËøÔ—Éý{ꮪÛYúÂ×ñ¾¿~-Ï›ÙÐ`3Ä}?þŸþ¯ëx|8®?¯p/xýÿãâ7žHãiû~_@¼“k?u!¹zk5Tëâ„·^§߰ªu¨¶OíRì¼úÞö��Ä€*œÄEßù$<³¾p;x#—¾ó“ÜTNÞóÃÿü2þûÍ ÁšÒh³“>ÿq>ñ“GŒÇÞ;wæZ.øà‡yû = !gÄ®;~À¿}á{\¿q„ú©“Ÿ™Sþä�üí›NcaÆýûY›ú¿ ‡ô}B!„˜aR©TˆÂ?£�®În<¯Éܽè }RXfw�2î{~§»ÚøÇ?íæÔ.…®pÙwwòò¯îá#Wñ•ß sù ƒ|äû»xÙîáë› Öq8ë{ù‹Å‡`ˆÒtä,[úƒ<Íêî!Ÿ8\ˆß Ú奯˜Ã×^ÞÅK;„Ã1ÊåÔu=|þm3yãüÆ¿ŸŠ5§Îâ›¯ëæµ‡»èRÌÎ@±æèNþùM³¹øH'ówIqø)3ùÒéÙãsã8þÌ™|áÌÍ<Î8ª›ž^ ¿ÓgÇŒ@,íx˜G~ò!Î8ótÖox˜3Î<�ôAJ;ÞÿB§¤Â=·ßO¹6t-òò#›„j)EïYò½Ÿþ„Ÿ~éc\ôæ?`yµ«�*´Q¨Þz�ðø•_æ›—w[ÊñÕ\įßĨ±(·ƒ+W±r^޲˜òVnøÊÅüý7M{{'?~×<™\UŽáì̤kݬ«®?uW?Ò¢Vf;?ûØùâ-i( Ð¹z{Š„®â“ÿø Ojç䳟OOõÐôßÎ�6~mc¾ýfîHß$g çžsDò�Õ~ÞKU,fÞ«a6üïgø»/ß– Õ’ëÆƒòí�ÿWïÉFš>ë¿1ï¾ô¸oO€E¡Ü"�íy´kFÙpÃ×xßßü;·fʳ£Üý• ùë/üŠõÃ1V™³òXÖ»Œ™9…­lã7—ˆ÷þç] g«±_÷u?Å;ùõ§/䟯ÚR Õº9ñm“„jûÜ.‡•/>�5¹¤@ëßϵ·ö7ü=±ŒÜq3wU{«)ïHÎ;gi“0-O~ÿ#|øG�0ì(zº¢Y¢=÷ò_ÿøq~²5ûÞÅl½úã¼ãï¾Æµ’PM)‡BGE7ùrÑ”·rË·ÿ‰w|èؘ½¯ûû³6Õåû,„B1 üÀgûŽm„a€çåèéîaá‚Etw5Ž2˜­ÇÚaí¬²<ÔßMdö5ìÒœuv7gv‚-Uø×ïôóþæÿ3ö+|éû{à‚Y¼yžÇËŸ_ä;›Kì¶  .GÎÐàG¬ï7¸Ý9N[îÑã‡üú¡€½™rÚºr³ÀeA‡Æ3†�Áˆ6lõë¯×Ñã±°ÍeNN–b—ǪùÆÆ ”5=9ž?O¡”bîœ«Š–`4âÉ!;þêÏ2 Nèá}«*›†xï‡yÐPÌ;²›Ï¿¢�w�ßÉí—ñhuÔ ;·ƒ‹^˜£°g”÷g€›‡“íms:¸ô ÝüÑy]Ü´i/7T7Ç«Oò¾o¼Î§Üãx|ãä^xK?WWÆê¡Ú ¼÷Ü"ú‘½|îas`÷¬åÞ'÷²fÙRònž=£»¹öž`òßèx OlôÇæ-[¼–c» 5Òít7—å8cÿñ�ÖóÓ¢—žÎŸ½x-s‚ lN IDAT¥k± Xú~ýM¾¿>™Ã =—óÿùKüéÝ(ÓÏõ—¼›‹¯Þ…±eîÿþ�¸ãåï㔼Ë1oý"W¾¾Âoÿýí|âÆ2p�¼€/~ô|æiP¬ —¼å߸5ÈqÒ{¾Ä‡ÎlG¹m̘Òo¡�õk6ÅŠÂÚ38µW¡XÇ9ëÚ¹þºl¼�k¯}�w¬9vÜ¢ å;¾ËWnLzÕ)ÍœÓÞË¿\ôG¬l‡áõ?ãcž›t{l;álNfŸö0}Üú›G O8†Úw\v”Ûnº«º˜‚Â;òlÎ]æìç½LßÃL˜=È·¿1óÜ÷ò�¯YÇaÑ®þÊçøÚ{0Ìàm\yÝ.^ôªyh Þð#.ùú} @9Ì;ã½|úÂóYÙ³ûÎÿæâ}�ûG þS?çÓ—ŸÁ·ÿæxŠ€ÿзùÔOB\=“3.ü7>ú’ÃÈå'~ÈßýõeÜ>\áÉ�oŸsï:Ò; ûºÏ¢Ý\ÿ/ñ‘_n©®ÚÃóÞq —¾öÈ ‡îO»ô‚³yé ÿÍý¿-c­Ï½7ü–þóÏg¬ÓZ‰ßýæîÚ{ž;æ\ÎYÐäïe¼�__7‹ÓÞó.~ù*zÌîúÞ%\tù] 0Ãwsùwïâ%ïÀlý9Ÿüì�ìˆ, i_õr>xñ[8cq”¶ró]Â?ÿð!FŒ¡ÿ¶/qé•'ò¯Z€>�Ÿµ)ý»pßg!„BˆiƒïûA€ÖŠ86Ä&Jÿ?{÷Eµ`ü�Ù’ì¦'¤�$”é"½H+b»ˆbTD°\ pQ¤Š‚`WD¤Kï¤BÒ{¶ÏÌý�$!½ç÷˜ge§ì9gfggþ§).TUEU5´Â~7žžÖ ÂÏ׿ʟwÅkÞFAfí‚2 6Ûð5:pi‚Ø�rñ„Ê~fîn,#£±oK6?VT+ætðÕ²LâÌ.6ŸqRToˆðæó;Mâ²¹o­Ä›Ã¼iîjN±9ÈTA2¹ÿ?n¬¿à]µ»X³!“÷v:È@¢u×@>j^4vŠDóNÌïšÃÊücn �)ª•6pï]�Ü œÛ–ÊÐ5Ž«ÞÂC®*IO�æF̪“Ù«Š‚jIDz™zÈ�I-ÌÜV7—÷c ÆÉjÝÚƒ(Yeźìâ €%%�);Ì|ÝÍÄ�Ñ9ü¹WAò5íÇâ�ÅÐÎ&8È5¸Ó4Pâ�sE× ™Î=|é+Û˜°ÚJz dmÏÉ ÂBôÈ^ËL'Ø9«öú7ÔlÒ³J®}ºÀ`‚ªÛ¶ôµMÍ Ãóv¦}:’Öe.z*v¿zo« «Éí| 6•ýéÔ»¾«—‘¡‚š}ŒÃ *76�1xúèéÀ×­d_’у€ÀÀ’ôZ½Ë´´3zÕ"0° ³‚:³jCRჽ­ºwÄ_ðäÆîíðÚ°ŽU%yÃö>Þ’eÅr°oÝ&Š{ÔšÚñèóƒhX˜w¯†ƒóÄö¼»ñÂ11Ý[Ðçæ@~ý)•¤m›9öTLq×U-ëw¶ð‘ ÄôêN¸  U«,/ ŸîXC–ªa?ð'›3ú—tµìccñ1w§mß› ®è{©�O·‘¼~G4>@­ï�á;fÚA*é[7qÐÙ–v‡—üÀnKÑXŠMyä�‘t/šŒÃÆÍOŽaø¡Gùô°M³qà—ßùë¶Çhª«©s­²ëÂU:΂ ‚ 5Èìn"ªACœN'‡$�$I’�%¹à>HÓÐ� ^5•œÜŽ�ü‹ÍnÀl2Wéó®X`í¯Lâó�H€¢Jø›Ô6[éqž=)þmAÐÀ�¦:Ðv–t]Ò„–$+¿—{Osi850ôÜÑÃL¤ÍΪ#.²íN24@ÒsÇ�ž®/ãÊ´1«…Ýi ƒŽ†QŒhãFïÞþ(¹)ŒÿKECãø¾,Þ�Óѱ“7=}!ö`6‹ã4TÕEl¶�Ä7îïn&«6ä±Ã¢‘Ÿriy„4YO} Õêà@Zù…»O:°¶4Ѷ¾]¬E6Ð>B‡ä´²éì…W„¸Ó6âoö"¦�ó^+v“Œ'­%ëª6•düKõõŠô楉�K³Y•{Án«-1+–¥±³�¤«4í æBq•ŒË„ÑH�Œ é‰|'7\ÐÔG&¬ÓP¯d^Ùà @µ�oU¹‚£ ”aÝ·†u)…µIî­éycÉØTíºÓÉk+²UÔŒM¬Üó:•:!ÔDþ:™W| Ö7lG;¿Òy—ðíЉ†Ml¶—?�ÄôìJØ/ßqNõü66žzŒæ� ÚùXvmdGQ0Äýúu .,‘*KÉ�vƒúP§T?CÉ·%mèÙrØ h8ór±Få»÷¦çÓФí|KçÓ@³Ÿòë½2&³ “QWP†ÊYöÎ)®«s Æ3+£L@Ú¿n=ܤx,šJÆÁƒœS[Éå”kh6ÎÅ&–}Ëq†Å'Ñð³qô«0ªuù’%<;ô§gÐ:~LR‹»ƒ€Øla{aIöì@ÿÎåÇI+ʾ‰6]ÚÕ É!th�îà \€š}š“©*íBαswrIY6éJ·Ðrù’C¹©s}>?|  œßÏÞó*MëÔÔ¹VÉuá²¾?‚ ‚ ׎$I�FŒÆòýY )5‰Ä„s8\NE)^_¯7TkÆÐ+XÓ€\GÁc`‡�tz…'‘ë0°#9àoºeI46 ”T;­—“ �ýMôÎÌãÙÙ9ì/ÕµSjfh„Œ¬:YðS3K Ä´÷´�³º`¦¶ÖÑ£�‰OŽå“ªAÒY ¿ÆéñiéEO_H�·²d_ɀȇ3%úu3�Ê¡#ù,“ÿGdp�RÁ2§E!Gƒà=&äõÔó5ÃE\ãó(.âT÷7*[‰Õ(D¾Ô3�$IÈh�Õ-¹»1²¯ÓÉ,¦VP%‰@?&—JBŽZaº.U®-»à®tÐ"² ww‰‚ÁŸ44K> Ü.7®'ùÓ°a@%!1 KÜV~úi%›œä\Z›§Ë…¢ªe²~µŠ,ìøc3ÍÕp‹nI#g)©EËëÒ*ÆÌÊMyhj›Ví ·cW¼ŠÊIÉ$5£(, a ¿\æ%SmÂü$*ŒÏÝ�á?òåY”6m>Ãã�#ÑaaçÆÝä¦Ëܶ]Ë r_e)QÇT6p#yáí]êE-8ÿ•$’Šò)c ƻܹ"›¼ (? ¡’JRJÑv–??dÈŸ•¤P’HtA¤tyåZ%’ŒoÌ]ŒêžÁÜé«9¯h¨iòÑÄEÔ›|?M.œ¶³úù2n-Ü».¿,8ƒ¢ÙÙ¿a+ 9Ø¿y'Y*€ŒßM}èèUÉR"¢ü ȇ¢£ °†šEF–µÎsî|ÑÕIÂFà_P™�Ð`tÒ1\ ¦�˜¢@™9×*».\æ÷GAázcµÙ8w†f�›áînB§+¨ÅÖ4 ¹š32]ñYAÚeðõ±zœÉ¹”iM%<%dÀ™«�z9÷iZA€O6®-y(7^šššÏKólø»kœM.ÿAûcØZ›p÷7PWâòÒ"ÿvšBb6Hz®첋=}ôøH ›d¼$°˜dü$P­ Y}·\*Y�Ì2þœÊUHÕ$¼d$ ‚Ù/~($çŒKÔ¶«/ƒÝì|°Ò‚­®7ŸÝêIO MÒH?›ÇøŸrØe©^örmW9J.R;H©µ®sgˆS¸Ä1É.B2ãYáÀT*é[¦1jÂRbmE‘J£»'Þ>$5Ÿ¬l[¹™ ¯<-w;l+ß ÛžyNÀx™åz©$# �cÊ3� 1؈È8Ë3 �cÓ4òŸO"™õRGüÊLµó £a¿~4ûv&öؘޟ!¾ÇÙº3£ð˜Ò½ok*í$ ¹ãVA\o(õÖœØ�hނׂ 1ºWMÃîÉM PsíìL‡{¢Ü¨µ×Bª&Ó¾‘÷<;ÒÀ#‹WZÉìX‘ÅoV7^zЋ¨”lG¼—ï÷áÍ®v†.·S�†°¹ö‚ÀÚUë *Ñ4ÚùpA15e'›OºhÙä"—më~æ~°õƾôïC˜©â— ³à8Èü©¿>œK˜ÝÆ„ñ�pS2à:<“a£¾åÜU ¬idm^ö¼*H¬{X±)ƒ¾…]÷ %ûsØì(P¶[­j!7¿²ÏÐÙ£�ÆrÔ¥á:½�͉÷·™mE]};Ó¯½gÉ&×¢,%7ÌnSfjXó­—6�lÂì&ƒ£ ‹ _¿ñ,z¦UåÝŽ%îf@¹Ür½D’‰f7µ'ÄàNÌðqŒ>þ mÏBÕ\œûýÞŠœÆ¤Ûë–ýìêæ«hó°ž ,šÄÀ~˜uÛ2Ðd; [ÁéºsKÌ…Ý Ši,– +ì¬[ɽˆäŽÙ]Ù„‡©(­Ö¼ü ��Ób¡¸w8f<ÌR�žk^.ûû#‚ ‚pyŽ=LPpn&'Nœ$2²>©©iUzõ÷ó';;‹¤ä"#ëãíåCNn6©©iÖ ÌfŽþu”æÍšW9�Õ 'J:ÌM�;Ò A}дâ×úõ ©Ð AÐ4 P¸¼šªqSçŽÔuî»Èž5,Ž‚–fz7™Šëm«Fs*¤Vö$mÐÓ±�ïÝÄ’çCÙüZ[Ç„²é•PVÝe¾°\„Jhüµ-›ŸÓ5B[ú³àA?FßìÅS}ýùâ1Ú§Ù9¦‚¦h6´À C…uèu…�7ÕÉë-d5ðeÖ}þ¼}O ã›ÁÆõ¹ì•�<ÖÏ¿39LÚ¯  5ÑÕKaýŽ|NØÁšfᛣ*��LÄT½(é zõæ÷ÕÓ´KgBŠ®ÒJ<¿Ì[AB¥Ñ};“¯Ö¯`î^à®;F³àô¥WM(±»Ø•Z4B¹�VwîãIÏ0™ìó6–íÊcÁ–\¾Ø”Ë܃ªÙkLþ/iV“¦3m¿[€‰a�½¸µžÌÑ-éŒÜXПHÉWÈÖ@³«äi e<+ `Ë2ÞFÀ® 3džÈbļLŸu‘|>Ÿ¾Jåõƒ*1]|¹ÓÓÁŒ•ù$hàå¯ÇGSˆË,z¢ÔHÌp¡šôÔ­Ú/Å®zWPÀ­ÅíÜwƒ¹pŒ-•œŸò»K9šSî!Ö•ÁÞÅyeÁ±â™Ý£ºrs½K�"jÖ|J7°‘e©dl/ç~þyG©å.\ÕžæXÃj)p¨˜šò'췗̺yç˼ñÊK¼vÁßËŒ¿¯5¦‚ȎëY›XXFrM—Œ¥Änbݙ҉wpråŽ^,?r=z4Å(š“Ã[¿aåÎÌÂ.�µéÙ»Y™J «W–¥ÓJû6µ‹ƒÔÊÉ�¬?W:°jçàos™÷å|fÎüœ©ó·’*K ‡Ò¦UѤ ŽCÙX&£’´ñK¦|6�yßüį[ã Z|ÖD¹V“ä׉çÇÝGtá´ šã ß¼=‰•I¥¾ÕÍWɧàÙ¡?½ Æ0³î[ͼÍ'q’± ýzÕ«¸B ˆfg÷Šueƒ›¶¿X»¹d’9<š¦>È!tìEQoJWì~;T65ZÞn–ÍŒ‹„{óNtð‘®ü¹v �³ ‚ Bff&h�‘–N½zuÉÊÌ¢^DÁ«»›ÛE_‹Ö+xÍ&((EU ÀjµQf½ÌŒtœN™UNgµ»‚Z­VjùQ—¤¤dÜÜÜÈÉÉÆÝÝ�œœêÕ‹ ))³ÙLNNõëüÛß?›ÍJå“hœŽw�§éñöq£sJº”Iø˜ Ûz©U³-;ûrOˆ„šeá­EY¬Ì,»­¡�/·77RѸȂ TLͳóõov¾.÷¾¹‰a2ħ¹°šÕE¼Úùè©-Ùr�«d=¡:peºÊ´ÒÊI±ò]JÉC§{˜7¯¶Õ±M?g¼çf��а•zس»@“$LÕœZ3מÆ«Ø@eÈ‹O±eÔÙœ©‚fçìê�ydóB6�¦~ 'zk*'àxš½8X%û´æ©o­RÅ„JˆŽ‚@€æd×7³ù-x ‘Ê6,žËׇ x{9ÈÎUAËâèá-# ‚MGç†ÉPÔMÑÅáe‹YÝxõeþ�#¨0�*ñëÖp°°Ÿ°dˆ¦çÍÁ•ÔIøuìFk÷íl²jhÎcü±î÷<�Œ�æ¥föÔœ'YðöüGßÃ�! g7.dÒâÓ¨²DÑ@TšZþwD&¨kOn˜u€í6 ËŽå¬R »Fô¤_“²'Õ-ËJéi2øÚ.™Êö| Íñó'|Œïè»h`'vãBþ»ä|A`F29xíÜ ¶k:è6Zþú){-ZÞv>™0ó³·Ò&P#yÿ¯|<éöd« ¹Óêéö ¨‘r­>Sôý¼=ê�MÚB†ª¡¦m䣉_1å¢/+_¥¸Å0¨O8¿,8‹’»‹Mû$Üš÷¢WùY;4­¤ §$aÝ3‡±S�ú·ëŽyåõâÿ·ÛmØìµ+a9ce³ÅÌ-†t4ñÝÏV2ÿæ3<"¼™;ÔDÆ�Þ[e¹à!ý²žŽ ôÈhìÛ™ÃªÌ o}|ôT8–¯ •’õE+n9Uø.í¹á¡)ìŽuŒ�¨8Ù— q{##­‚$¶ž/û ¨ëFYãÔY;åæA(¡72âOBr»ÇUüPks¨h’Œ{©+œ»ABÒ4òîéoåÙ²Á«zÛ^]�¼3Yã½ñŸ±úœ ՚ʱ�©»`m cHGFNË�U‹ ÊÁ]Ô~!7ç ¢a;µ”wž]Z¸[w¢î~‹G¬“xý×4TÍÁ¡Ù�Ðca;^Yôƒýþfçú†´ˆvgÅ.+ö“Kxsä0váí_'лüL•êYV­>Q8þž„1¦;]/œ*±$ç>èÕÖÄæ�4Íʼn5ë8uïpêÀØl(£zoàµ?’Q4 ëé¼?zEQÎ èrýã~`éYÐp)Ê-êä€Îôn=ƒ[¬hŠRpKzõîAd¹¦K—S–·üMQ^Œ\{ c_8ÈÓï¯%Á©a9µŒ÷ž]V® dÚ=Îøû�“%×ÄØ§÷òô”-¤**ÙûñÚ#‹Êm§#°ó(ÆÞV§8¸YåZ}:Âú¿Ì¸cÏðʯñ85�ü# 75’Y¯tÂ_ª~¾JèiÔïš~;“ƒŽâ©‡i×÷f‚*:]Jɸ°ºHnàÆú_?ä‰_ʯ(ajx7Ï/þLÉ»#Ï�˜ó¯Ïcw¦Š+e;³ÞØÎ¬ò[êjÑiÔxžlYPåw5εk{œAAø¥ª*GŽ¡c§N )Œ1�N‡N–‘u:t²Y'£“uèt:dYWÐz_*xO’%trÁ�º¢((ª‹>}ú ¸\Š‚ª*ôéÓ EQQTEQ¯Á«V¡ªj•f­v`-Á½ Ï>?U)j¢Nã®Oç®Ïë^ò’ެ€®ß¹Ý΂]zv5íÛç\ŒÝåÄVY&|ÍŒäI¸ÌîÙ—4¬�Œgá¸Ã™yê…Ë´4b€jß Š˜œðÿ&úæ >ï¬cÏò^ܧ¯Laž<-ãJÎaI|Ñ7Jeë!+™�Í ¼Ñ�ï~±’V´ÈhdX[#F§ƒß�º*„]"º“/÷ú:˜ñE>gK­”›î"3õ$È,Ô»^ 9ÏBl5ûwçÙ²O:0êþ.ŠTóL‘y{Nk.ý�ïVnd÷© l¥[…Hz<ÚӭßmÜwÇMÔ7Wãê#2àÕ·Éøè#¾Üœ@¾ZPn:ϺÞ7š—îi‰oòܲ Ë㬨š†¦sÇýRz›Ê�ôæ)v¿ñkãm¨…Á2ƒ§æJ~¯”kX[øû"¹ÓªGg.WÉ›NÝÛà±i#y(qkùãØý4lªÉ�®/~À›¦�˜öûÒ ƒ$’1€˜[eÌ“-Ù5æ'8[ðãa³Ú/¼îK¾téÙóÖ��Ó.¢éÛ£‚€Ì•,Ë‹’ é5–9ÁÍø|Îw¬:�Œ¥è<‘dõ³YÑ4ñ+>dBÔ4&ÝQCuóUŠÖ“�7ÌçÐŽ‚IdϹ¥³o…¿ïª5Ÿ¢‰9‘ý¹áá1Ü6�÷¿Ú@l^ÁJ’Γz7ÝÃËÏÝCL™€²„G³{™òy#¾Ÿ¿€Ö!ÉZ ’tÔiÙ“»‡?Àí-Jº¡^�síZgAAþ/9\ŠB­€ZÔªXÒB­HqKµRíÕ¤rë¾§]ps¢•{¯°å½V°µÕfÃÃ|écIµþPC*¸ÃŠ›öÄEW>z`O®ipÉ;¿,z «ÅÓue$Måðîl¦l¶r¨ôìp’LdO^èíI[/ gF>¯~™ÅæÂgC}_~æ�Ÿ%ŸÑŸd±½tÀMÒóÀCA<&‘¸;�{WØKÆS“utéÀ˜?=>Š�‰SÓYf+¿-ìXžÌ3{JÝüzzðÉ(_ÚË.~™Â´q{)üÿ�<ùl„­dvä±&IÅ­–;wv0ÓXv0çë4f'– Ýzw c£$NäóÝQYz=[{Ò/DâȆ4FnrTT7†x1ëA/¦0r›‹2CüèŒ<óX-†äæ2ú—<}=y÷/ü÷¤ñÀ:Ui´–´y#º__òwr,NâbY½z!�¯p›Ï{ž&ºEå3_.—%�„ÄT²- ’›~A¡„ú¹UÐÌ24ì™ñÄ&fã4úQ7" ŸÒ“jrÓ3ÈÕLøøà^•Um¤ÅŸ#Õ*áîDh�7n5“èK¦ä%sæ\ù’!u ªdæÔšqËò8s“ˆ‹O#_uÃ+ „°/.2�e!{fqç3ÈWtx„^Û·¿‰Õ^Ýr­Žêå å³ɼX� èÿ.߿ڡòÑ,*âÈæÜ™x2]îø‡…SÇçï�®<’ΓžcG5zF�ùbѰ«s®]ÿÇYA„‹ääd&¾3‹õêŽ|orwgÜëoR»ví‹®W÷™Ï(Š¥U»ÅÚçr²ðût¸ÕŸ'¢t4oëÇÜÖ>œOq—«áÔÉÔ 6PÏ£ omNboÿ”]Tû[š‹µ<æFíÖþL7ä³:IÅÍË@›&&ZélLøÎFŸý¸ÙèÆ===‘O;Øú—ƒ´‹íÖêâL>´÷ÖsÛ̱.°Ú™¹Éö·ÝYáŸNMÏãµ$lèÐð IDATÆöõ¤Kg_º ‘–`aÒªl~L,hÖ\üúsJ_žháÉ jœùNþX�ÅwTTCgà¾~^ÔKÎå‘�å‚jŠƒ¹¿dSûVoæ<ç�¤ªœ:’Í뛪T0‡DóÙ—?–­æ�$Ì!ÑUÜSÍÑ›kUë í]ÂÍ/œ&~á•,6âU+¤z½bewjÕmÈ•Jù¥Ðy|•>í –å%0x…RÅ­dÜüBièZ¥­®n¹VGuò¥’¶v!?¶Ä’t Ò¦jA5£á�|¨ä,¨˜Þ“�ˆ†\úÑ»:çÚõœAAø·�$‰ïE¹º³�˲\åqµ¯ßÀ Ù,ø6…-ÑÜ߯ÌÍázBCÜ-¼ÓÔ4�ô$ìÍåëýR/© h‰„=™¼áãÇØvn4oáEóûL:“ÏkËrØ� ç·š‰éâFã|‘ÇSÇ%ÝÕ*¢ØY´ÖÂ�ÌÔ tçö@°Ÿq1o3ÕïS*ÿ gryyfžÞ:BÜÁš¯p>_«¤;'h'¿­Hå÷52!>:Ü•¤lËÅ®ŸŠ“/æ'òÅEV±$åóÚL 2F§Bf5ÇVóŽì‚wd—êm,Â?Œ“ø}›9ž¥’}úO¾û~YÓ¿â×õînt]ß6 ‚ ‚ ükpM>»*ã«ÁõÜ´²A&ÔO�Ÿh.�ôLçm—­’�:êÕÒá%idf¹8—¯•‰�éŒ2~z�,‹va˘JèÜt„ûÈàPHÊV©�d ‚ðq¥»‚ ‚p¥äñûØ;™¸¥t$^BØ�·f¼Nï‹ô'‚ ‚ ü¿øgt­€êT‰Oq_Óûu(œN¬¼¹›âPI«bkÅ®p&¥ŠMèAA¸nH²;Á-û3ò…ÇDPMAA¨Ð?*°&‚ ‚påxÒçÍE´JËÅê’0„âm³| ‚ ‚ •�5AA„Bz“?µÃý¯u2AA„ѯAAAAAªAÖAAAA¡D`MAAAAªAÖAAAA¡D`MAAAAª¡Ê³‚îx=ìJ¤Cá_c϶ӗ½�óçÏ×@JAAA„ªª]»ö%¯[åÀš ‚påUåB.‚ ‚ ‚ \¢+¨ ‚ ‚ ‚ ‚ Tƒ¬ ‚ ‚ ‚ ‚ B5ˆÀš ‚ ‚ ‚ ‚ Tƒ¬ ‚ ‚ ‚ ‚ B5ˆÀš ‚ ‚ ‚ ‚ Tƒ¬ ‚ ‚ ‚ ‚ B5è¯u*¤åpæÀ ÒœHÔiMˆû%l–ÇÁã)84�½êÒ¼qF,$>Êy+Ⱦõh€îb;R³ˆÝŠtŒA�ˆ©ë…tÕÓ,q¤aëæÝ‹ÏÄ®÷"(¢í;·¥¾·ˆ ‚ ülÛ¾•»vоm{nìÐñ§HAA.M�ÖâããÙ³g‰‰‰Øl6Lf3¡µkC½zõ.}GÎMLì9ˆ/ÒU�¼0÷8KG„üMpKáè´Ûi;n7N Œ�'sôÏh È[7†>£W“eîÄ{›×2¦…[¥û95ëÚ?½’Ló�¼ýç:ZÔ½i¾úÔœxNžW lP?õICy‡Y0æI^�³™óv­Ô Ù3’/Mç³×ûRçú  ÿ2¿/ÿ�ƒ‡Ó¼ýox­“#•sä’–cCÓ™ñóó¸NkÐ Øív6nÚıGéÞ£nØ@^ž….7Ý„›[e¿Õ‚ ‚ ‚p}¨±ûí]»v±sçNn¼ñFZ¶l‰Á`Àb±�œœÌÚµk £oß¾UÛ©$!‘ÇÚ¯¾çìCÏPïb'ç^¾þz?.$$I+·Ð@ã‘s™º®ÃÚÊÄïÒcãDÚ›/Ü�ëØ§<>vøÒã�/x¥Õ%4;»"i¾Ú\œÜŸ¶ïûðÑ_x®þ5n æ:Îçwuçé©àÕ„�OmœY5›Oæ-eËÑóäé|©wCO†�Í=­ü*è^…õÕ v/˜ÂgKö�àô#ºïã¼òdWjWt%ÓRXùÞë|géǸ‰wPï¢ÍT+·zõj8€›YÏsϾȜ/f2eÊZ´hA¯^½ª·ÓK¥Y8:ž,Wù냄,ë0š¼  ÀÛ(ZoVYqÙJxÖŽ$ü_ÔÖ±}CÇ­Á6”Y_>Aóë8²öÝ÷ßÓ·o?ôn7Ä´ ==•& ›ñÝ÷ßóÀý÷×èç¹rã9|à/Φä`“=®CÛ˜P<þæðkÖTþ:x�ñYX%wê4¢UË(*mb®�ŒÃg3pš‚iE°éâUmš%™“ç²Ñ¼CiXÛóï[Ê ‚ ‚ ×…¹Ý¶Ùl¬_¿žaÆa4™>}:sæÌaôèÑ 6ŒÐÐP–¯XÁ©S§ˆŒŒ¼ôëÑ,ê4‡7É¢¿FòZÓÊŸŒí[²ø¸J­F�ÐN#§ü r]îÿ|&ëöÜÁü½òð›½Ø:éæ²Ça¦>öë² pÐdæŽjB•nÕdš¯&-��ÛO ÐöZ¦¢�Fú�ãxã�T4ï.¼·~9cZy”,~âiî{·]Æmåèçï²è….<öïy(¾þ¸H\ûO>:‘ßbmhºHü}·’ÀZ;ÞëÏ-ã6‘e®K›ŽÍ wœeÇ×Y¶h1k­cöm¡¥‚eUYßÉ��Ò}B*ÝŸ{†Á^{˜ûÆ-¬:÷Û?¸ �2éÐHùùE�°–.‹Þ!¢šA5€0zôhŽž8ȉأtív3M¢š3mÚ´+XsdÞs¯³4G­tIg&¤IúÝ~?÷÷¬�G >�«–TâÓUüj㥿ôeÿÅe«§óؘÔO2®…ŒŒ ‚‚‚°Ð€ã§�P¯q‚j“‘‘QsäJfÓ¼ÉLþq7çm¥Õ’ŒGÝ®<ùÚóÜÙ¤¢sÀÊéåŸ2ñ³•ËQ(ÙRÂÃ]/ŒaäM!eo¦\‰¬øèu>Zy‹$#i’o FLx›GZVrži¬�4ŠqëÝòáç¼\»¦2.‚ ‚ \i5�ؽ{7 4ÀÓÓ½^Ï·ß}Ç­·`îÜy¸\.t:ÁAAœ:uªŠ© ¡gŸ0¸ö³pÁœ•®˜ÏºßsVó§{×”JI�ƒøï£ˆ6882í^]™Yê&ÙÎþÉ�2~S.rØP>�9¼z-\j8ÍTòâvñÇ÷óùü“©Lûl.‹—mãôE¶4[7üÊâù³™9s. ~XÁöSY¸Ê®Eö™}ìÞþ#+v;д<ÎÜÅ®]»9ŸOùd)¹gÙ¹ü¾øü¦}:‡Å˶s&·âth™§Ø³k{ާá¬g7ñýìéÌøf)ͯ•MKW‘¡Ê„Üý:£[y”[n憑OÑÓ$¡Ùö°ý€«Â½5@Mà÷—»Ñªï›ì¨û�Üä~Ñàƒsßdž˜°‰ü&O°ä¯“ìøã7~_�S;&ÓÛó$óŸï™ZõÖ·­çÓi»ð}h‹ß{–‘cçðÅó�8>s*K3ËžPZÚR^yî[”Û§0åŽàË ˜hšF^^õêÑ0ª1µBýÉÌÌDÓ®f+S™€&�èÞµKñ_·.éТ>þI‡×ñÅ;O3röAòk,Y §¾ðï²,µüwübË¡j²³³9‘µ}�‚3 ‹Ci[ÉÊʬ¹PÓY÷þs¼ºhIjm?Ì«¯¿Æ¸ÑÒ¯‘'Ö¸uü÷¥ üWþ·D%iåû<óárŽå™ˆê>ŒÑ¯Œå­WžäÞ›Â1f`ñ[¯òñÎÜR¿•* K&ñá)Ô½çC–¬üƒ5 ÆÒÛtˆyïÍa‡µ¢jdnœÉÇ벨=`4Oµ¹œ ¯ƒüÌL2rmˆoæÿG~™9X”k�’š¢`ÉÉ$#Ër‘{hAA¸¾ÔH;ƒÌÌL¼}|Š4m6¹¹¹ØívEAÖéÈÊʪâžUê¸�>ßÅîÅ_²i|;ºWÔ33k_ý’÷r{g…å³+ÛŸ„O·÷øòµÍt›°‹Y�?OŸ�_0$Hºû}}g;]$�Íþ„;kW7æX³iÖÒ6òÑ�óî/ÇÈQË�3æÝ„»ÞùŠY£Úâ]ú.\Ëf×gOóè¸o9�é*“LÔíñ ŸÌ}‡ÁÀÁ¦ =4?£p½}L¹µSÐõÒFŽ|Ô± ÕžšÊŸ“žâÉw毵L­½ìÝ„;ޜ͌:P*ŽõãèzÇb7Ocÿû™ ïûÛs4tuŸ¡éí ª´9 ‰þ3O’ðnv�pL¬!yh–Àª¢^<*)\×~~ø:�¶o­dΫ�ØúÀæVº²� 3gsÀÄýÿù€�a%—ÏÏòßç¾æ†q?0ãû÷¹õñP¤*®¯žÞÁîT­:µ¥ ·ž&Ûã÷ÎjvvqÏM…'”–βWŸe‘óVæO¹‹�h†”““ƒäåàPÎ:¾Z=�7;}sù;­=MnÃ{´ªRóN±tÒ8>\ŸÄñïg³tàÇÜZu&ZG�& Ò¨jË¡ŠœNëŽý†Ã-‡½)‰;yž6~=jlÿÖ= ˜º&UeЄiŒéä_\«8``OZŒͤm{™9c =Þë[ü;¦åmcÖÌͤãAÛ'§2yh}ŠF|ë× Ýf?Ï3‹NòËôï0ç¢ €šÈšU‡°yvcøCm 2á=xlÈÖ|¾žå»ž¤C—²7Zö¦²†ô [˜ôx[¼ª}Ͳsâ›1Œœ�Lç7¦òf…7¿‹ƒ-“ïcìú š1‡'_¼FXÍ<ÎÖIØ+«€6‡Ó¦]ý²÷”€+û4;6íâhb.ªÙŸð¦èÒ²¢.Ô–ălÝK&~4jמÁ•œ‡j&m;DªS:7 (UÓ¯‘þçdž˜r”è¦òÁÀ:×õ8‘‚ ‚5XËËËÃl6c·ÛQU•œì–üô;îîn(JAš¦iäççWqÏ.´ˆÛ¸«Ívnÿ�/Wý‡îƒÊ�¦¥‘ºtËÒ!xÄ0zy|ÅÅ+íL´}íKÞý³/¬]ÀÈQ}i;·3}ŸÝV#M_˜ÇGý.£¶¸Ó¬œbư[»: c䯾2‚îÑA¸Yϳÿ·é¼7c#ß>w+ú°},¸=°0Í©?>Å g“lnÂ�±Ïpw§†º»È:³‹¥³>aáÚ�¸ç6·½E£�#¦2«ér&½¶ˆc4dèÛ/Ó«–§jÙ¬Ó›“öcónÁ°w_ex�&ø«)^5—÷'ýÈ÷/÷'Á¹�5cn èJrwÇM{þQfŒYÀ!ÿ. ½§9Þí ºès¿„ÁßÚþ•®á<²•�Y*’[ ­š]3-üKé[ðüÊÝ4‹ñGÆ~ñu]X½.Íã6tó.·PG£~}‰zk[ÿØHîãCñ®âú¦ôTÒ531þ%¡VÙÏ?ÒII/j›¡‘¹b,Ï.°2h^ ˜ %fÅò{Ü,$éúê0({F2è©»X¹éö8Orø¤B+ð]Å’|‚ƒGbḬàÔ¹ã\�f-›f.]NùI§8—~˜­Ç\hš�äÓÇ8š£ÃÍ¿AJ"ñ. §~ ©ÌµSµ&sìÀN&eaU�ø†4 æ†ÆÔ6]x\´ÜDŽ'æ‚9„¨p\I‡Ø´ë$Ùîõh^ߌâ’0Õ#¢²™U4ɱqd8%<‚ëS×÷Ê?Š]Rþ4+)gΑî�0EPϯ’A¹´|ΟJ K©xÌ·ª”å?�¦jH’„^6"ý’i5ÕÞÊÁþµIQ%L7ÞÇýË6Õ7†3dÔ],Û=‡#»–±ê|ïÂë†FöæßÙ�¡¢«3�§n/ ª ™iqßt_ö+âVòë�ˆncûiŽ�QÐE5"ªx™ FQøòÇOœCéÒ°dfr-‡-ŸOgyZ Þ}ŒŽÕŽªiäï™Í¸9G¨uÛ‡¼Ü-°fº$Ô5“}ËW‘Òp}UT]ö/u�åÛuè;Æ�_‹¥’Àš\§ü¸Œ*É?áåÿ,åD¾†d4 s9qj3¨Õú!Þ›x/-<‹ÎY�Œ-3rÂj\MÚÐ@=ɧӿæÎ÷'3ò†ò•B*IË?bôÇÉ þïtº”Y¦'|ÀKŒ9øc?y—ù ?æÑÆbAáúVc�5/ooìv;Š¢ ª .—pÃé,hÈm±XÈÉ©â(bš†¦‹äž»0~Û–Ì_JúÀ{Ë´ŠBMà§«È•ëòЃ=ðHûò‚î‹0D3jÞǬïð0¿ü8ŠA±þÙoÇÔf<óß¾ù‚šºk•f×îÙL[Ÿ‰ªoÁËßÿÈÄV%d7÷éGcG ýgÆñãg?ðÁ�§(f,›U‹~%Y5ÐæµŸø~ltÉ <·pÇ}ý»ñf>Ž_Áoûß M;=á7ßÏÃõ³øú�E#˜‡>£¥&/pî™Ä³ÀjhÊèŸ70¥»oñ R›N}¹¥Õô»}>[ßËÂû—ñh�Âmuzô€râ[¾�|š•ûþCgŸË J¨äù–W†Oæ b$ê±±*š†z8qü±.hYÅõ›Ê:dT”RÏÛš¢  CWx’kY«xý™ùäõŸÍÇ÷†!+¹$žN ÏT›u|.ë‚—gÏ.øŒ«ÚôÒÈÞ¾øÈ £“/üŽiÙY8i2ó7�#¿|ËWs8=ËØÛŽÏædÿ/ò⊢îm'YüÚÓ,F&|è$žÍÏ+.›Êâ‘Í ÊXÍbï·ÿåï6sÆR®…«9œîÃ_â•»›SúràÜ7�§Æ­ÅÙò<žËÛ/}Éa‹†<�‡›ndÞº\<º¿Î�ã»Wx�V—2îñÏ9 Fððç³yÜ÷rKõ"ª”?…ƒ_¾Ì¸uùxöÏÏov¡|çvõô¼òø—œ�¢x|Îç<ì]�ÏúgRUMÓP4Zakì{¦¦—‡ŠŽˆÍ𫠜䰎t®ÿ‡Oœ`Ç�\††ú açÀÎX4™à7Ò¸¢x®G+:·4²rC&»wžBi�œŸE¶KCöòƧÔO“ì僷¤‘•™ƒ …¿Ë9;æ0yE*�}&0ª£wõ+õ¬‡™3e qøïÃ-kt¬ÅaÛÇ·ŸÌ#ç‰îôjdº¾‚~WÒu•o k^>.ÍÀ ÃßcTû }’{õK5zSÏÿÆ»ïýÊIS[žxû†¶ÆÍ–Èæ¯þÃÄo¾àµ©|ýÚM×åß}¾‚œ›Þ`ñ]ðÑÒøuìp&Ïú�ÁÓï&¼TæÕ”?˜·¿µ„5Sûá½=@üŸRÓ“IU4ä€`jUte1Õ"ÐKBMM&E­úúº°pÂd+I‰%c#:H•B Õ�–ÍÚq£˜›Ý—÷§Ý‡yÃ[ôŒ¤N“fD× "¢û›¬M«þÃz®­ª]Ù¯Û±CwjHnÑ´lT~–�D~šð:3þ<‡«ö�<ôÒ¦N›ÆŒIãyñŽüìçX=ý >Ú˜UX®z"û�bìS= &}Ð…Ñëñxíåy²{]¢*]Vðƒ¢å³gæË•¼Kð«\Z/%ßUʃ3�¤¸XNÆ¥�_åáe5òsóÑ$=ÁQ14oÖô‚¿f‘Á˜‹ÏC‡þŽ]6/º�ËCm‚1I ›BéòØX�1�¾þ[–%~g“ö³'QGLÇ6ç²ìO‡ QOìe_n©2PSY9mÛ½ñòˆ*;]%¿›yôކ¨Ç¿gîú¬¿¯4A„k¨Fê²²²�õzl6.—‹ádzxñbxà�âqÖ²³³«Þb­�Tk dÉ |ùÍi}1ª0"¨pdñv8ô´¸÷>ZàÒï3$Ì�xë(ØHSq©5÷³]i–ý„‡6ðìÍïr æ#öy†¨„9Ü×ýFŒë‘½+l1ôwŠZ¬]W]A•<ÎîZÆgÿF¢f&zØÃô+×ÏZ9¶Œïöå¡êpß„·x¼aIÓ›VíÚS×ù0ÏÿšÂºŸÿäé›(Ë·ìÍÀÚù¬˜³†³øÑ¼G�;y±eà:þ“8�]ÁÐw?ft«’.@Mš·£SÃ�þÆ .˜ÃÊ>ï18°p[Y�Pã×±:ì6¦Î{”EÍn\u龌/ãö²|]ï¬]¶VHM`Ýúã¸p£mßeZFÔ´êäÏ£M/ºú¯æ—ô�¬Ý™G�îåºE)'X½>Er£MïnMr\í²ü‡QUMÓP5…¢ ÖX‹5É _OPÈLÍ@#ðÂu4''€FzZ  W2HISAö$°–¹’ß/‰Z�ÈœDIO%U_/žÅè�s¦òëy?z�’®~vÎmYÂ7+wq*݉[PCnt7CZþýìäÊ)~ûõ v�›Ò+¨ÔwÃÉ®ÿÞdz¿ÕâÉYo±ü}>øå0N $sX'{c ÷D—ÍŸ#~#s>™Ã�;ãÉW ‚’z¯ºtºýI^x°!ú‚²Êß÷�¾ô3)1£˜?yH©ï�Jü/¯2|ê>|ŽçþÌwxcA éüÇCéô±�˜‘_0shh%µ»N¶OÆóËCxê³GÉ›ü ŽÛðü¿¼ÐÃ%§ÀÁ–ÿÜÅ‹«CxlúKÔúé}¦­>Cžª�dÀ/º/£ÇŽ¢_ÝÒ•—ù§VòÙ'_±|2µ`ÿ²9˜ú>Ä �÷%Êüwi}›§3&0ñ"ù¾ô<Ø8½|>[ÍñzŸ(nùmþîü(�¯¼|TɌǥ4iTbÙº#ͽ =;—«T•CèÞ½ ÓeË®tš‘JšæICÿ¢3VÆ×ß�Oj†FA´M%mí§LßîÉ�GÐꢕÙ:"n@ë…ÿe˯kHìqbxAázU#?QÙ99deeaµZ±Ùlôïߟ¯¾úŠ^½za·ÛÉÎÎÆj³U;°ÞôyèêÈvv|µ�CE‘(çn.:„ËíF¸7º’åŠii¿óâˆ�9äô¥Y‹ôy›™0â?ì´T3‰W*Íù'Y1í†ö¸�úA^¸éõÜÜ1yxRkÈ|R.¨Ô7Ðnì<Æw BÊÚȨ́zÑ$8�ÈŽ·òØÓùqÛ¹JÇÖ¨�zžøDP82íVZ6oNó þZñØw©¨hXâI/—&É\›ÐŠúß\*C;Æ,ßÁŽm›X³t!SFµ#gùdžÐ’6-&VL z}01¸\‹5NgAË$£T�õõ-xúÝá®z†.=‡roÿ›xh1 zû%nvmbÂÈÏIíñ.ŸŒ¨‡²ã'–$Ôâ¶çž¤¥·�茾3„Ä%?²õÂF—äÚvu²kúßq7ƒŠþn¿�žý†pÏ«sÙçÞžû^ŸÊ'E_0Ù‡\ï>œý)3&¿Æ�‘åÑM´lד¤á<KÜe7rrè�UĺÀÔn(]0®Ž„oÇ¡ i¨G³íc妴R-\ b*ªÚÜ7Œ˜Ò~ú†ô¿¥œ\¹†³åÒ©žû“µ'\`nÀ+:¶T5óçÞ‚>Ý‚�µ|¶oØI^¹SÈõ×zÖÅ+H¦ÖôëZ”þË(ËM-hå¥h.(l—¢¨54Å¡äK“èt¨œÛ¶•S´:Ò2¶óç' ¡Z­3jr­àŽ©Âȉäè3 IDAT?€„»© e¸–Ÿ[0#¯[ Ãd”s±œ)¾°©dœ>M†f¤~ƒ:È@þ¾/˜¼ô<¾ÝžâÙ›}Høm"�¿>›?κQ72 ùÄrþûÒh>ؘù·-u”3[ø3NÅÔö&Ú{–N«„^¯-‡Ýs&2#¾%O½ó1s¦È›÷Äà–¸™éÿYÄ_¥.ÀjÚ:Þ~n" ÷èöÔÛÌþâ ~úOu�عàMž�¾»ðü•þÇÞy‡GQ¼qü³{—»ôž�Òé%¡…Þ!tP, ‚€ˆRT¤(Š ¢ ¢¥«( ½†zï$$�éÉåîv$@B iüœÏóäyàvwæ�ÙÙÙÙï¼ó6Õû2¦«?¦#ó™¶6ê~ûSnndú�áÊ<ÇëQ¿ûXÆt @‹†€Ž#˜ôñ86tÊç9½gw g—Ïa-uy¥Oo^­ã‘!¾ØÆŒ´4HÊv͜ȢÄF ŸüßOÿ˜‘�Êb>³ŽIãæs,-K}F¬aìðiü~ÎŽVƒ2Òÿeö§¼ÓÜŽ³«§2xâßD)�²µ 5ò)wáÊɇçòÞÔ \´®Ã€‰3ùeá¾Þ�øÅ“Xp¶ O¾JRr ªd�­µ ˜H¾{‹›±‰rKÂp�‹Q ï@r„8“qÄE2qùâµ Ï?UEEÊ>ù$I€J¦#*êíí̘½ëÃx³z^‚u–\œëÑ´²é§w²;ç€W ‚§†ùþHˆ�')9™äädL&&“)3ÖZÆKðêµk¨ŠR a ¬šô敲ZL'aáþŒ/ã´Ý‹XvÞŒu³^tõ/DQ”H–zƒùÜ;Ïà¯í \Ñ‚ÔÃSèûÑNв`õqجÆþÃÈÆ5h?l:+Âbq©Ý‰ÞƒÞá½Ñc;þ#Æ¿VÛ\F%’CÆýs‚}¿|Êmƒ)¥MàrØŸÌ›4„—àS«7ßîô`=Èt é* ¢š ¤¥¥åú§ÚyH€‹.‡H"éôÂHQ‘ìð ªEH݆´è؃á_¬âÀÞohãbàÜâ� üñÚ3ûAùÿ„ìàˆƒ JBñ¹ÝSw“T$'¥ÂŸn¿#lÿB†7 À'¤/³wbi/WÂ>y‹o£›òé¬þhTî^¸@¬ìOùÀ{^ZÊû#ß>Ϲ˜¢µ–'½ÔlL%%5Ë_š!#Þœj&1ò$»×¯æÏðÖ $+g|+Q£FÎ÷ºUÁlLÇ�–ŠAÎ|> †G. {$Ê-NœŽEAƒ_Pq¿d/‚ª8#«FΞ¼�Ã^´å©dóЗŒwh;jZ‚éâ&þ>—µ—Q¸²m;L2 ÚÐØñ1z¹|:‚Z6£ŒF%ùÀ6²)kFNnÛE¤"c_¯õûK¢.ŸTUEULŠé¾p]r¶† mÚPI¦KËùì‡CÜ΢Ù) 'Y4y.û š �ì^”7Å„¢¨€Œ6ÏhI«E–³9C\ÐøÑ¬©?š»»X±ñF†C|ò)–¯9‰É¾­Bl�R�1oúŸ\·oÄÐAMq1áן÷ïىɳ?eÌ;ïòÕ¬÷he‹õóWs!_�Q%îä ®)ZÊW­œcY�$I`ŽâH|S>û´�êU£jµÚ´ðÝËk0G†sà¾JdàȯóØ|Û–Æ#>gìË ¨àKÙª�é1öSi¹¾v>¿GÜ;ߊj½ß¥W9æ}˺Œ5þü3ûö¦ùÑýýþÔ²ÑRªJ#–wBFÆ©l]š7kL­2ùÇÝÐh4 D²ûr0Ÿ}=ž¡}zÑ£‘r¡mI–@¹Ã¹´æLüäu:Ö¦zÍÆ¼üÎ' ©g�éúzVÝŸUMcß/‹ØŸdCá“ýRFú�Uêóò¨O\SG|Øb–O„­ÞxæYîB–A�cûŠõDªnt9Ž×›T!з,5[¼Æ§ã› G§p™¤’±3—þšBß;Úåž{ñyZvîͰo7q)Ëä²r'–X“Šìè’kÈ ÙÉ'Y!)ö6@vtÂQJänü½žH%ñn<Šìˆ«“ê]¶ÎþŽí–íÕ/˜ä}óÕç%š‡¶£M�‘|¹9‚ó^²Õªy!ÏsätÚÃG�@ xj(±Í \K•âzDþ~~9ŽÇ'%aemMJJ1ÜÁ,jÓ«g5¦xŒe ·óIýúl[´’kŠ]^{ÏK™8?§CVÞ¯WøfvO|e>ùa8›ZNåÄ×ýÝz³B�б3hIØl`פ�|žŒÆ¿ þ™Ç«�Ù·,Oßxƒ9‹’k­jݨÕ},s»�EM�æø®Mü³þO–þ²šCá Ú.ÝÁµ¼ñ(AR²ÁÎV,¨?a7z¿^JËŠýy·ëþ™ÉŽß7; ?îOƒaÿa$ç²”u‘Ù|õWLPñ!wLóÕ \Nm`´…??ç ôÂýóRÂ>à­™‘4šú;5€Bjr *V<©$aie‰¤&�\(—Í$â@ÿ¤–‚ZP÷�¥Lkû�×’j$éæöo^ÎÜEëøfÔ^ÂGÌ`rG¯ì�{ê ÂÖýÁš]᜺Il‚ãCKßKd–E¹�±|¸²r=Ö瞪)>Cl d]Á(é]pËeÆ@viJçúó8°%‚�NÒ¯bpÆ.�æ+lÙ~“ìJóv!EZæ[`ŠQ>m…´ò]Áüˇټ/‰V­ì2îeú)6íˆF‘iÒº÷7…,�º|VP•ì›Ü›˜+ dßx¿ß!ÎéåïÓuwUjW*….ù'�œæ¦M^iÉÒõW�õVž´² ­&sæ2ÑÜ1L(*`¡Ë\²©!ð¥¡ôÜ3š_¾ÁóËKcw�ˆdGšŒzƒæŽÎžÁÊë¶43˜PWó郼î]ZP#S“BhQÓŠ¶ ìÆk”Ës}³™ëW#1I¶øø:çþK·i�_ÖNAöÀß[�t.ž»q xË`:ÏŽ=7Á¶%›¸dOKö¤U«*|{ô({÷ÇÐûTÆq}y^{¿ûÿÈw³6S±ÅfíH¥BïÏèW5û˜¥0d8:©ø¶hO¶ØöE± å[µ¢|ÖŸ²3�VÆbï!N¿‚©qe´Æ3ìÞÕ²mr¤ïN“&U˜~ð]Ã\M~¶æEaË`ÁÁg6ýËem¨Jû–Á‚ë\¿vÿÿÎÆ�@ x¦(a-((ˆ˜Û·IKË}6ÉÉÅ…»wîP¥J•b䢡r�ÞÔ›ô{ÖýΞ۩,[s ÜzòZG—‹=iG§Òçý�Ü‘|é3û^ÎŒ dÛð#~õÍ&aÎ#h½>Ï[©)†Í¦¬ßx 34:‘W ªÜ¾r…„h’•A¡= íɈ1›Ö¸³NobÎ’³ôóˆå¨Z?}µHL\½tž�Ž÷R\LçYóõ¯ì¹‘B¥×'ñZÕÜš©'gG$"0ÇÝ%^÷ǯ\P,jиž-ßÿ¹‡Ç�´­�µ¥(DïØÊI“–jMfÄê+ìù¹‘ºŸÉoÍàZ½)¬X.³-KXÛÚ ©ñ¤Ü>¨’’œ‚*Û`g[´aù½¥ O’¶•hÑc ô®T¨Þ€:e\°·Ô¡Õj‘¢ÃXºñ,%â �%V•j6b4æqã¬]ñ²­ƒ6GðpI«C›kÌ=;¶oŠë¶5ÜÚ¶�ƒoÓÐÌ—v°åŠ�W :åX¯T²§|šB[–eá¼sض�„–­p�Àpb+;n)Èî�i[+K?_uù¬ ¨Êƒk¨H’”-ÈñÑS®Û§Ì-µ˜Ù ÿbï¥cl���­<©Þ|ï÷éŒvIo– áèâ˜Ñ�Èö8ØJ�šLRr^"ŸBRR" »~Úev-’MUÞüæjþ³‰°‹w0Z…ܬ5ÍË;b89�/~¿†Mƒwy§¥+2�É-ECåÒY… ®ÈJ×£Ìä8P!îN<ªä‰›s^çèps·Ë±”X§·@Â|§e5%‚k·°ŽbçÂùœz(9sT<Ì\¿v3lվ̘~è÷ítHG­Ü�鯖§ØO£¤ÅÛ§T6!¥¨6"YâëWê!QFÂÖÓ;I%6æ6f@“AD‚‚\ÚŸ�°÷òÄN>ÌÍÈhÌ”}0~ÊÅÖ¼(l¤Ä[ÜLQ�ÊxPêáá�Æ“2ž(�°¦¡òó#רŸš rðÎíò|( ßÊwG0w{K&·r@’e4 ˜s_`Îø]ÒÈåÖUãåW«³aÖçŒ4·¢Šñ(kvYÒ|lG’ö2yæVäÐ�y»Ž57–oæ(µùàÍVT±—൞´øk<6�£O¹ÊÙ>NôÎÎØK wnßÁ,„5�@ <¥”ˆ°öòË/3lØ0*Uª„««+©©©$''#Ë2ÖÖÖ˜ŒFÂdÊ”)ÅÊGöëJŸãصa«¾Nfãm ¯7_#Ô®€ $îfÂkŸ°7IKàÀ¹|ÙÉ-Ë@Óšºc`ô†&||p!oiCí%¯;Pj‘mVˆOP-îî9ÆS,˜¿ƒ RÖ%3©QßFxBY^ê”s·%É¥ /¶òdöéHnEÝBáaaM;¤@r§QÓÊh7‡syý:NLªG�ÊšÂ�ý¸èT�úåœJ Q%sàçO™r*hºÐí‹z9èj,á‡/cF¦Œ·Õž$'Úôì„ûKøyÚo ùµ÷cÚ'îaÆÌí¤Y7 W× m®°çç �ƒŸ¿ÅW—ê2ißÛT¸ßð$œ*TÄS]ÂéséP6céÍ™çQ<ºQÙµh‚yºI!öB:VNEºþñ"ãÞ°1U§‡±7éN›hSßHçè¢é,;o@ölŇ_Ž¢�Wö†�nóû?%$¬I–ØXw,¨öú7|ý\Á'= ‚e�¶´-ó #vó÷¾$4·âü¶í\U´††Réq«þÅ*ŸŒoóT^pŽã‡v°7¡%m Ù¼›EC™æ­É¶ùóc®Ë§ EQ2—‚‹ÇZ–ø6ëÏçÍúaL‰'Á ÃÞÑ PoóÛÕxI‹�¯W¦°æŽ—‡n¸‡B.ïa¢oÜÂŒ„¥gi²í¢÷$¤c/B²žn8ÍÂ/WrÙª. ¥TÆ.¤§¤¡¨–ÖYw —Ð[["©7INÍOd4“–nF•ôèòй i�5�n=j¦ç‘š|™]¢síwm]\°Ñ<,ájñmÙ–šó�²3EOHh Þȼ(Hz,õÙk½È6JVØX弃’…=*IÆtL€Efú’eî^Z’N�•$ƒp¿˜¹Øš…-ƒj0dØt/Þh6,Ðé¤ö z|BBñÉí�e /umÈâ[8|ð ¦VuÑXÛb#�š’±�ÐÃû¨©É$+²�-V€Œ÷sŸ0Çe5«w]ä–¶}§<Çsµt„M�ÉzZñÙÀz8H&N^º†êÖ ÿ{‰ê¼ñ÷’ØpåÉjåìKßuzô¨Ä¥tÉ«@ ÿ>%"¬•/_žwß}—�?þ˜è7hÔ¨^^^ÄÇÇsôèQ–ÿú+C‡ !((¨xI<ß»=ï®_Éâ¯o‘"2òµÆ9‚uçŠz›¿ßíÃWÇ XTμ)¡äˆ§oU‹Ñ󯱾áXÂVe`›züÑׯP›"”˜Ír|Ëh ÂHøÎ0’^i‰í½cÆë¬y§'³î”ÁE¾Àí”Xb’UÐI(Ñ+Üv8;µõ¸¼e†<4K�z‚­{¢Q$ ÊU ¸_6Ik‘á%bºÉ�h3Ü_"ª¡òkoÒ|Ú[l<9“á_vaÝèšlRO}Ï�†ð×m†o;ÁôFE_þ€¶Ý{ÕfÚè0ÎÍ~›÷šþÉ´e²xÊ%sú§¡|²1Uv¢u—Ø/GA¤„}Ëû?ÏŒÝdæòÁtPcØ4u3¾ Ѿ̄Q-q•$œ;̧íþáÍå¯Ó4ù0ƒ»ÖÄ-õÏ™Î/§ôÔùx*ýﵭžŸCøTÞžzžZ‡1¸bvEÅ¢Î+t-û?|õ5oÔ„ÿ¥YLýí.åßìAÝBŠ/’$a4™ú3666˜L&.]ºôtíš #©i™¢„ù aûo¢ %øÅ× õzøkW%!:ªpšä‡Æƒ2îZ¤Q7nbÆ¥d^2÷ÐV }Ûr,ùá,a[�ØÈƒ-Û#P,*Ó>Ô÷ñ{2³|²gSÚT�ÏñðClÝŸH›Æ§Ù´ç.ŠÆ�Ö¡å³§õ¸ëò)BUU�Àœ-ÆÚ㊜)aaíˆK–Y'5éûÎA@pÕÌ0²Ê;#‹áÂéópÏùÞVb9u& •Ê=â½nàô/3øõ²%õF¡C©ý Vg�˜MÙÅ ³Ñ„Š]¾}–Œ……„„S17ò‘¬¬°”@.ý3æ¿Nù‚~Ô»ì˜=ŸÝFO¼îpèçYüUïc:z”ÀùP7[d1’nÌÙÑ©Æt HhôKy%ËŒôÕÔ´\cNªiHh-­r>�|%¶ ªN‡^5=�ô‡mRSIIQKDpÒ»¸à€Ê­ä” ‘Ñ©4^V2GoEmׇ lŒŽâ–"ãáåù@`Ä¿FÝÖè¾�$îŸÎ´� ¡  ‘ƒ˜II5€¥%–÷êLÒc¥—îïžMX31"aaañ;¹ ‚gŸ§·hÑ‚àà`þþûoæÌ™Ãùóçqsw§f�ü4>>>¹Î‘ çö½y¾ÔJæG%¡ ~•žµ 2-ª¹loÌ»€I_�Ñ?N¤©}î¯g}ðHæMø›úïí䯑ý™Ýp=C*§šŠh³&�{5åÓ}›¸2çUZ%¿I×ZN¤Eg몕ì0t`Áš6,iÔ—?“·ñõ»3PZף틽™ðÖÚÏØËÇM«òÏó]hUÝgK…¤¨3ì^½œõgŒè* fô«eîˆJ.©XJæk—˜ûÆK$¶ò×vLÛ7ß¾Ìúêoš½ù';Æ4!xswº·®†§>•Èc›Y±l’u”ë?�Ñ ‹)ªežJC¿çÓ ­xwK83;Wä��æ4®V[å.—neÛñ[¤£Åë¹i|ÑÍ] ¶ *†³ëùaÎZ Ù~7rì�8–ù?]ÃòŒÙW ÐÒoÉ?hß̇ ¦1|­‚Š„Î½Ý¿ü†éÃB²{Qöü{Žòå[Ÿsºúxö­œsy²¾ãùŠ+=ÇÒÈó�U»ÍdÉø:…^žÄü‘-˜º$IÅŸ((QTâ„qÊÈžøzgöYj I)* áäì˜Sx2]eÝ_ÇIWAÊçË,¿�¶ì®NW÷Esø<7öïãÒ•)Ÿ£ûTˆ=}€»*T+c[ȉ ŸÖm©¹è,ûncÇ�Rl�T° iC¨ç¿°@¨¸å“ÝhÖª:߆ïçÐîpîØdOœŠE¥PÚø?T�½.Ÿ³‚ª‚Y5ß÷X3— ÇšáÚVo=Æu‹Þè^‹ì¯…ë­&,,Ê7¥…ß½v¤¥rƒº¸þö'±û·°'±-í²¿i”ˆ­lu3ë§õ¦�Û–~ÍÇï¿Ã°a#;e"œhÜo›¶M'4«Ëž®#>ëNyk•„“2çëY,Üv%sÆÖ‚rý–³gÍ't«aCäæyLzoƒ‡�æ³ù›‰rj@Ÿ¯6°cv'J•”ÂëµûX=±;!ž û×ò˼ï™3�Çbáӈקn`ßò× üuãxâH8õ^CšªfîÚ—ûŸaײŸ· ¢Ïì\‰‰æâ©ãœ8Ilä!¿Ó0×Àê…=}0cÂ’HÜý>UóЩmkbÙ©îDÝ úî-Ž-@P®*]þ´jÕŠ#F0räÈû#FŒ U«V…Oì1 ¤Æprã·¼÷õnâ ›jh�ù™#»áá.&Î;�}£Ó-v͚̊WìeP ñÜMË"j4^¬æ;ÄÞÉ.rä}LƯMGjYK˜¯üÆôeçsl®b¸º†ÉŒe`¯�Ì<–c¸G"»6£S=[¤”Ìûz3‘ØR¿]ã\w­+yŠ[> çF­±†”#»X¼ewUÁ¡Ír ;ðøëòiÁ¬˜Q3&sz¦È¦¢˜KNXÓ/°fá VΟÉ÷â²Ä‹Rˆ?ú3>‰Ar¦E�Žøe¹úêÏñB9jÂfÍØBd–*VSβèË%œN—phð}òN¥_äׯ–rÖ¢‡wÈq¯µe«PÕR!âèqîoZl¼È¡c àT�ê¾ù©S¼¼<Ѩq\�L*žç’¶�ëy ¥bÍÆÅÕ2s}í¼3ñ'vDg©Á[›˜:s þ/3ºg%lËvåýWËa8ø“»v—ð{¾Fc1÷®-‚�˜8¹m'QYVãÛ{ “äHµê¾â�¶�êº ÂY¿#6{úælÙz“Æ‹u½ 4€ÎµÜ…-ƒEy‚*éQ“�°óHö^ ùè?l‹*à³b¾ÈªÏ>æ£ 3øãêC÷Áp‘•«�"9S·~… ÑPr¢a«šØšO³ú·ã$g9]‰ÝÁÒ�ÑàÞ”6ÕóðÕT“9øã׬14bø FYúh-^~e�b®qýÞøÚÉÕHW?Ÿ‡v»W¸…-žÞBXÁSËÓ)IèÚ3?ÖÌü\êi2㦹_ªq)ʲl¿iËäïØ�ÏߢöÄ1¬àW”¸Íh¼h?e3WÆFpæô5â+Ü*RÎÝ*sÖOGýqÛ‰v‹˜4+\]í2âÅàAÓ?³kÄ\â#.q)ò6I& 6Î^–õÆ!×e%ü_]ÄÉ“95ìJáëëŽõýQŒßvãXÚn ÉÑç9w%†dE�£g åüœÑçòQ« �C”yNþõ–Vt÷+Ǧsçêy.GÇ‘&YáìHY‡Ç¿‰‚ XÈÖnøWr{lç ìKyþ,6rhvºüô�ÇLz ñI¤™U�dlÊuæÃ±Ï?ˆs.{Ò¼u0?�:DÔŸŸ2$­3­ÊÛbˆ½ÄáÛ O¯Ç‡SBØ8x*;SÃYöÝ*”�J4hZ{|�döߌæ�/&�\»8Ôa`¯º8æwÌ££ïç­i{ÿa8½µ u\´b.fËÖÃ\OµÀ»ÃÛ¼V­�˜${¶oŠËöµDG§!»´£C݇³®n|ó¾Ï'‹j šûœ$äb–Or¨KÛúvìܼƒ•›M¨–uiÓ,·ø];¯§�¸¸8âPUp²¬HJ¬C‚7› TT∋‹ÃÑѱXùhžç­vyoí5~ÿ /'ë7¤FiÉ×�³ëÀEîštø?7ŠáM³·#�?ÝGõ&lÄ�Ùü¯�^Kýšþ8˜c9½?§c�hul‰Ø8�•:*¿Ñ…ZùºÙʸW¬€›tŠó§Î‘Þ¡ð^¹Ðܽ-·OfÓwï3&áu^¬ëƒƒùçÂVóÓÒ}Äzw§¯Cf”(Ö~ù;“ýè5©UôiTè>œž»†ñÓü©üZóK^ Ôaíè„^2q~ó ÖzÔÄÆ¡<̓ ì¿X6Þ¯&{<îþÆû“ͼѹe,9»i3w'cQî%^®qÏÛÞ’�¯Ó`ç4öÌË”Ô>t ö@—x�°?~â§ã&<Úô£[N÷Ñ\�ò,w¡Ê 9Ó¼K3~<¸�uS'àüÆË4ðÒwa'K~9Šc -Ñ— ©Z…гW ¶Ï<Ì·ÃGrõ¥¶Ôñ±G�»Äž5¿³þœ×&Ãé[û^]H¸´èÇëëŽ1kÕ‡ JìÊ‹õ|Ðǟ埕¿±+Á�Öã{P+]-ùèOL[›J“÷ߦy¶™߯M©°`Ë—� ö«~Üúc[¼x¾e…ì&j §O^Ƭñ¦jÅâôó�@ <^žNaM� �]ªÔ)“çq­�;Ýo IDATž¹n† Ã¡LEjä}iδ¼©ä�Ï26¨áQ¡à‰I‡³_œýþ½,‚§ •´ø[DgݘT’�µ–Ø8•!°lê5oO—–Uqͦ8Ëxu~Ÿ‰7?cÊÊ#œ\¿�“ëA’­ð¨ñ“Þ{�&&<º¯çÄ‚ãœ[÷Ÿy™Ù�«àbQ�îZ²oê&®]ÙÃW$ô5}éÛÈŻÇÌs]ʬy¿³ãð:~:tÏf+·*tìÛ�·^.²—™U�¶´ñú›Å×U<š·¡v< ’žÇ�ä|NÑ%‘~?üUqËgKÝV pܲž;F»F¡4uÌ«"]>)RSSIIIÁÎÞŽ+W®ÐÁ½3...h´bcb¹|ù2vöv¤¤¤ ×ë±²*P4ÕÜ‘ìi0l*Ÿ9ÌdÖï8·sg3 w©H§o3¸K•ìq�2Ñ—…/¿vâ»o°öØ16­9šq¥Æÿ¦¯2tð«ÔsÏ[2]ù�ÏŸFz›QÏyå±dΊ��m˜ÊwË>eÐ"�­=é>ž±¯ø?r ¦­Ø€ú®¿óûÁ0N¦×¡f14VÙµ9ãfhñœ5�ßLbÛü ÁFÒ9R®Q?>Ü�jVf®¯þŠ™ûSñïþ}ªd ¡«Àk#º²cè/Ìÿ| !3{S©öót¯º�y'V3ùÃ58´�D“" k…±1+VÔø>ž¾ä“aß“¬¨ ép©Ö…�ǼJ¹,ý¦ìÑ–‰Ó5Ìþz>ëfŽãO%c9½Ö·z=?fDï9côæ�eå¶(T$ìëæó!>ùq &äg$´öei?äCZ_ÏЋ&Œ¦G‰k|»|Âw6?òõ‚õ¬ùa«ÕŒô-üiüÚ» íÙ€l¡ñ,üé>és,¾ùšù[æ3i}Æ$Žu©ê¼2~8›»æ~SŽ3﫵$ÖÅð.9Α}^`܈kŒŸõí~V�m}i9d}Š—Jj8»�¤#{Õ£a~^¡�@ i3²¡¤ÆpõÊ-Ž¥}ðvÒg›ý7§ÆgÐãà`•±ÌóÞïÉ·¸� ÖNx–rÄR.رÌ\I½Éõ¨xRU-v.^”ñ°Ëu·½B‘r�)½GóÇm_úÍ�ËeŸTt±ÇT¾'ž×¿C\\wïÞeoX111$'%£( vöv¸¹¹Q¿^=œœœŠí±– cQ×#ˆI2cáà�¯·KÏìüPI»ɵq¤É6¸{{ãa[òs“JZ<·LX9:c[à›kâ̼7é÷K­?YÀ‡�mKijǜË�›ñ¤IV¸zxà”ó/ª�ø[w1Z;ãl§+‘e}�¶ÑÈþ¯^eø-/ÏXÄ;ÁZÒnc@vðÀÛÕ*_;Òo“Œ¢sÀÝÓ›¢t5�(w¡ê9=‘¨¨[$a‹§W)ŠÞM$ÇÞäf¼ÉÊ O§\úï‡ìL½Í�› ˜-�ñ,å�ëJ…BcNãn\*:'lr‹!¹n,ݦ…8ðG¾ïæ%–‚ �à©ÂgÈlîiiÂcM þÈVù/µÕX9â’‹S�ÆÆÿÀ<®ÉçXf®X9{SÞ9?/ØÂ¢¹þW6ƨX×zŽNO2dÿã(ßÓ�׿ƒ££#ŽŽŽ”.]Cz:醌€K:½½N‡^_ôE�yba‹g@E< }¡„¥SÊ;¼Ȗ¸z -^èA³µ“Ùò럼VÿUüK`t§±vÅÛßµø ÝCÒãPÊ£äÒ£p6ÞóçÒÙ—Æ¿€ñtv¥ðÍuE@!xD¹ UÏ:;<‹m€W/ q{5V.xû¹”@ÞYµÄÉ%�o8Í’¥IuoGߥ…¨&‚§ñžÁ3‚JòéÅ|2ï©ri:¿š}Ù’à™D¯×cog‡««+®®®ØÛÙ=Qíÿɹƒß¨ƒå™¥ÌX{ó£/žbÒ9¿l6«"œ }«umŸa×\�@ ü'k�@ xªQnícÉGˆºy’];NmÔQ¶ë(ú#î–@ð…Œg»‘|pt(ãçNaq•/è]®Ð®oÁS€JòÑŸødñE<»LbDSg±i�@ žz„°&‚§õî Ö.]Æe³„låIÃïðA¯`„ƒ@�Ù…f£¦ñm³K$™’0a)yh(×i$“jI”ñ{’ËÆÇH‚¦oLhBÅ:•rÝTD ‚§ 1æÁS�¦\f- %Á¬Ã¹”;z±þS È�'A Aîÿ§rõh^îIÛ!(8:<«6(BD�@ žBXÁÓ�l‰‹—%6[ �@ Š�˜ö�@ �@ Š€Ö�@ �@ ‚" „5�@ �@ � aM �@ �@ (BX�@ �@ Š€Ö�@ �@ ‚" „5�@ OŠf3�OÚ�@ �à‘hŸ´O%iw¸q;Uk‡{),r9E5&—�Ž…�#¶:é±å#ø÷Cð_#=‘Ø„4T�5NN6�ÿ…ðoç÷4SÒuñ ÕíÞ}{¹q³ÉŒõ�Û„þ´IU‘ @’@’H·ÐòÓ+]1›Ìf3f³Ÿ2eèÞýÕ'\AÉ“NBliÈØ88c#^À�@ ž!žÎ±·1†sǯ’ ZàV>_»GW)‘œ<Eªd‹w•Š”Ò/{ú·(ûòrÒ˾ˮ“_P/ë/åóõcüÒCÜLSÁ¡'Ü\Dç"ä™o>O jWŽ�'Ö¨æ~\’Ðèlpp-��§ýSÚ  Æ3q?ÿÒˆ¹r�Xèœ|p·$¯^PMºÁùÈD�Þ�Øäyb Q—"ˆ3�¥›þÎ:Ò÷NçÅ�¶aôêÆÜoRõ1?Àéû¾¡ÛøÍ¤þKùý+ܯW [Ï@¼í æ^Òuÿ,ÕííÛ·©W«>þ�p;cB ’�]ÆŸ½=’N‡j2a%˼ժ Š¢ ª*‰ñ‰|÷ã·˜Íf4Í“.† $IßÇ´^ؘæI÷™?3ìinÀ�@ Q¢#—ϧN.Ðy‡fùÒ•yWcVñvƒ·Ølô`Àú«Ì Õ回éôlºÖ›Ì)©SOíbTÙb¸% Z�³FFÊö‘jæäŒ¾ Zp£Æ�àö-©ìR·¢.¨Í3Ÿ§ã.>iÙ‰Ÿn+ùŸ'ÉX• "ôÕ!ŒÓ‡—gp•ñ³p?ÿ T‡Á„©èjcå—�óèg.­š@ßù0i+1èç™ôòÎýÙSn¬å£7¿ç˜Ùž¶—2¡ ÉheEm¾È˜Ž3øXÖ$hiøÁJ¦µµÍSÍÆ´îqqvaÏ�Ýúy §›I^±ÕBE™Mï  ÖÖ$ת�ÙCºÉ�Vƒ$I¨j=‚CI‰!â¶‚“g)ì„Æ%�@�/%6\ú|êdô3ÏãsçÍa@ÿ79¾¿¤²|lè_ø•ã¯9¨±ìÞ~‚tUƒßÀeì™Ù«Ç‘ÏS‰Ï�4ðyØ�KÅ”z—È3G8zù~ÕŸõ¿m`Þæ_èðl�ÆŸ­û!ø¿F²!¤^Uô;÷c8s€CÉ�h››ç®r“¯b0_dß¡;ôðvÍ%x¦ÊÝðCœ5�dLÃà []“qlÞ2îñ–E�+ÿպ߶c>e|iÖ°†Ûï!›ü2hT”Åg@ó/gÐt¯ˆjoDgèGªô>`w? !¬=nÌ\\:š>¿Ú0dÑ ^ñ|'Ê�@ þEJ\ùˆ¼y�¨QÙ~;|(œýßäæ­[x–ö„Cá%�í¿ƒ’@|‚h ¬\Ë'mÏ¿Š–Zƒ~fEo§<¼1Ò¸¶q ¯÷šÈ–++28”fkû“‡óŒ@ È ÇZu©lq€ÃiÇ ;j m£œ=Ž˜°³&$;ì’8u œ¤çB±Ïñ�¦~ð骄>¨µmÿC.R‚§ £ÑHíàÚhµ¤'´"-iNÆEBÓ§æ{k2H©2¨wQäÀô$Íþo¡&pút$ 埴%�@ Ï%.¬E݈"´E»ûÿÿ|êd:tjODdQQ‘¼;æC^íú\Ig›+jÜ%Â/Þ;?‚Ê»¢U“¸¶…íG¯g¶Æ- &M›×¤´eîשz*V)ƒ�¤ù(b.‘¤ I×�sðà dÙ Km©év>U©àžÇ²U5‰ë'ÎrÓ aï[�òn¹äS<»ï£$sýðNöžŒ ^±Ç·fSš—BOѧO‘¢Åµ\~9¿¾‹�%>­?bñäýTxão¶,e]t?–Ι‡9ñ*‡wíåÄÕÍV¸ùU£~“üìòWáÒcN±{ÇÎG%`´r§\í¦4 ö ¿ðv…É+Çý ™ˆ“gˆN“°õ®Bż‚÷©ñ\9z�X“„£0e]²/E.” w/~ñ.ØgÜ{ãÕ]¬Ýx„X»:¼Ø­îBùÏ »‡P/PÃáÓI>pŠôF5y¸wI9r�ãé®­:PgïRþ:v�#©¡4±~èDà öIE•,¨R¯÷úš¤œ‹LDÕ9ãëç†Õ½ßopîF"X{PÖÛSô v¼@¼U𷍄S–v¨¤Þäì±S\ˆŽ#UÑáè@µêð´*šª^”ôÔô;\:u†‹ÑwHI—ÑÛ»âS®2½lÉ+0@Q®)Iò¬ûÌßïÕ½FM#úÔa_ˆ&IÑãXº<5k”Ã5ÿ 90ÇGr!: +Üý}p)äõ%…Š H ‚…M'’nöE]’š^hæÅgîÿ[Ñ Êv½$I™i�´¯’¸Ƹ«;z†ë·S0éñ®L�@çÏržÏœ¥Uý­1›$¬ÝýðuÊ#ø§šÆÍË׸c”°)å��£%áç£Áº�ÞŽhMñ\>~”“×î’®µÅÿ*Õ+–Âú~ÑU’£/rýöIöž5¡ªiܼt–Ó ôÎÞø»Ye›X+Ò³¯$qýx8G¯Ä’¢ZQÊ?ˆÚÕJc“÷�@ O=�u­Þ=QmÝš¿¨_·ïŽù�mÿbî¼9�3Ûû¤ïú˜V�’Üh:§–±°G>Û̓8üzßNL[½”ÁÁu¦oþ€Fقا³ýæ<¿8áþp~ßgm©óH¶/2ªýv¾\~‡—å²n8ç¶bëÒ\º×Ån¥2ãöa¢[nùÏn㥕¼Óý-¾?‹ùÞù’~í?bñü¦üù|c¾¸PŠ·ÿ¹Ä·-JúËJ½^Êiÿæ°9‚+f(�¥‰)1ì˜ö'ýΙ%˧‘„l_‘?ü�ïF4Äåáú3^åÏq¯3èëmD²|PI:<aö‚ÏxÞï¡��"ä•ã~hÓÙ3±5Ý—ÇáøÊr.-y‡\Jm>>ƒçC&pTªÎ'‡2Þ¥6lOÓ—�ÞäŽN¹KŸ6Ø— ¢ñBåëà.6Tøï {R¿Ž7sN_æö¡ƒœ7פJ6ÅÇÀ±ýÇHEGíí©~÷7Ö…!ìL:Mjf¶Mgr0^MYê‡ìÖDHø??�YC}K™ ‚ªªÜSg$Ù G» $´m‘ûÉz=i«>@2•€·ZÚW±î…é&;ç}ÎÔUG¹•žõ½e�KPÞÓŸ¦YÚXÞÏ\GúVÞÉü­‰Ø4˪�šçâ‘ Ê�5Œð=Ç_ú~ÿ!ýÀ|²s•,xωEã¿fõ´e—48VîÂØ iì.FŽþ4’‘ë3ϹÀ’1ƒX‚Œw·¯Yòv•ŒAcŸ}SäV¦}4�?/$¡ÜŸÈØ•ëȘk"‰¾�@ žQۗý˜k÷D´!#ßgÚçWv¹"Yè°�@M8ÊŒ^“Y™öêH /K’.ocÞ§_±þêÞ}s&­v¿GÅ<Ý,¨Þo&?4‰`ý”YyI¢r¯) oâ€lHÃÒî,]õ/à÷è®ôó|xÔkæâo+8`]�×蜵Ùî´}LèÒ‹ÙÇ èýÛ3êƒ7-gÍÝ1ûó téý2u�tèu�ÇõI‰�#^d[ì³Æ„RãÙ6:”ÓŽ’fD÷IïÓ§EEœ•[œüçG¦L[ÅŠwÛiÜÎæÑÕ,³UcX;¨/Ï»ˆRªÞéOÛª¥�b޲zÖTîüŠnmÒX6“Ð{n4EÍëa$'ÚõèˆëÊ…ÄnXÁƸyÙñá“L[±’“& }ƒžt¯¬)– ’¥%z ɧùnô"N87¦Û+Uq±¯ƒ»XVûCƒÝJ/ºÌõ¨Cì»®PÅ/K#0�gßáxmejTu'(ÖÍžs:psÍJY¼®Ì\>x˜[ hýëP¿ô£’¤ËèƒÒS¯òÛÜ�\²¯F«–þ8XWÄIÔdÏy—Ë.’n@ë7ºÓ¾†ê].ü‹EËv²ù»ÑĘf0³GÙ|½J¡¨é©ÄmŸÎ¨o¶pÇÒ‡&=ºÐªjõ&’¢Î²kÍü¾ŒqãôÌù®7-ŠzÍ¿‹¤µ@+�št‘eŸþ–ô† ]� n:R£Ž²zá ¢÷2kÚï„|û ~�¸�jÒ ~3‰5*eÚŒaúк8?Á¾DUU¤¬~O™;7(¯ÝDÚá€tÅÕ3µi<ò^ �$KHYwx(¬SÄöZä{¡Æ±{úHƬ‹BqªÂó]ÛSßß â.²ó·eüulãF˜öÝPêf¾'ó~æ*Ó8DfÍö?¹µo#Ûî4£sŽÙ'…È�Û9m‹J­i“¹�“¬Ó"K`Š çÛ�Žsι C{‡à(w)Œß~]DZ“«ÿ‘#?Î|•@­–ÀöƒùÀ?¿ÌÝÌU¼hÕ¯u4ØzeòE}öÓÏ0ü笾hÄÒ·½ût¢N+ ·Î±cÕ/Lúø^Â#[ Á3J±„µÈÈþZ¿Žh£#qn홵l¦H*•¯Æ¯ËWsèÐaê„ÔaÑÒUü²hNŽØk�YFLÇòK˯ؽu•î�òÚÐÆ?ž*m¿ãjøŸü}mýóúÚ�ñiöýŸãö�XyI¦tÃôïï‘ñy`´£gùøìÌV.¿ÂëÃü³7_à·•‡0bE‹ÞÝ)÷¨uFE²[%vÕfO»æ|¾q5CËfÞÞf­y¾SMºÖëË7U�e¤Çña¥ÞaÓÏ¿qÅ š2 hð  ÆÃÓ:ã©•öûv¾jîxÿÓªVƒ6´«Ñ—�~fïäXÜsýËdh›Ê¨Ÿ.b´ªË§61&èžÕŽçžÁ¦v¾=?�ñ? ¡Å{Ð#¯Ü°kÕƒç=3÷ÆFVnŒã¥®ŽÙcÌ™ÂY¾ò &ÉŠf=» ¯¼h´hóùe, Ć#ŸÑ°À.?‚ÿ7´åêQ×u%×c®rà` }üJÝï[ÌW²?FAã[“ZîZ¼jÔÀKsšÈC‡¹¦Tâ~w¦ÜäÀÁÌhð©òH!Y‹P"¶²É« _ÏïO�̓vh:»œ/W^ õ¥Û¤ «ñ`'ÌŠUChPn*}Æ­çø¢ylh=™Î�Ø:Ùt®(é%³oÓ^î(Z*öü„ÏzødéwëÒ<´no giÌ~v]ìIÅŠš"^ó/#KÈ€ùÒFÖ×|›¹3^Àÿ¾bu=“è>êO¢ÏïaïÍ®øåXÞp™å>dÁÙtÜ›Žä«QM(õ„zéá(�r¦A�PÚÞEZåŠÚ%Lüæ…„„,Ï袵/Š|/ÒO-㛿£0é+ñæ´iô ¼wQ]š4®ˆå€÷Xñ7s×¾@HwïŒ6˜ß3gò¡­÷:\ çï­Ñt|É3ûC‰dë¶s˜ÐS»M‹,±M3ÆæÈƒ ~“yÓºâO,®]�&Ulè?t)ϬbÉ�.Œ«oE©àP:z&³~Þf®âDÕí霥�­.Uv.eù¥t°®Å�ÏÇñ½4ËW¤F� \FâÛ•\v^�@ xê)ò&>>žU¬ aƒ†” ¨ÍËõËP* 6Íš¶`ùª_±±¶æìÅë,ZºŠiŸO êFTÆÆOUö£÷‡³ˆSØÔoFK Ì×¹|Í\ô ,jлO-tØ»ðWN?””ùì*V„Á>”>/•)p¥Îîv¬ÛJ¢*áÐþmú”Í®™j}{0yX-,Š›&OÌÉD_ÏÌ7ByõǢe'Z¼7”F¦ª [´˜SF°iý.4{HœB­û ¨n�š´•_WG¢Ü»î×e\0�mëA ¬–Ý·LrhÆ��†3à­· -�†±Xyå�uS^}Ñ�ÇÆ•ˆ{¨úŒ–³ê¼ É®½^¼wo‹aƒ”ñÙ©$BóFÓ@ˆjÿmtiPÓY5rú@8ñ÷ÛŸÂ�C‡¸n–q«Y? hjPÓIÆ|ù c´j5î0û.˜@v¥n½²‹&e¬ÖSR¡V�îT³ÉÚ�œØø—M`Ò�ÞÕms´oÇúÝx¾œ5ívÅæÿŒ5=%…„D*Zm.sDúŠ ˜÷ÛVKÿ{YQ®yB¨’zwÌ"äd`U¹:Uô˜c¸q3Ÿš5G³áó1|s0Ç:ƒ˜>¦-ÞOÁRòñÑ$)£ß[åZµ[ èT¤ß]3�‘!¬euX+Ôk¬øíµp÷ÂȉMÛ¸në�çx! ûE’Mu^îóÏ?×™º®é™ï-òæ´åhß®<9¾a3W2P¹¾ƒ-çM`]‹ÍÜrŽ1d'Ztïü@T»g¥Žt¬¤%žýûÎ`{ˆ¢Ö¥�ð=‡IV%¬ë´§ÍÃb°Î�./ÔÅF¼î�@ <£YXÛ¾c+ ê5"  ,I©éì»p‡„þ�Ô­]ŸáƒßdÛÆ¿Ø¶ñ/jרCíuð*å]’¶ɲõkæ²É '; ÔRR‹#8i(×£/Í­Áxl1‹³3szÕ Že\;õ¡³[ÁGŽ…²Û|™“§SPÑR©vuls³±C*ÙG1�uýܰÐjÑ>ô§±°£tP;†þx˜x­­>ú�_ßÊòo¾JؾHÌh©Ü¸AÎjšr4¨ï�FM'<,œôÌëöŒÂŒ–òµkæ«IC…žÓ˜óíWL윱œ²¨y剞¯v%P«ÿÏ 6ÜÍÚNÒÙ·â7.™eœÛõ¢Ó½{[6XÔ¢y#‡Ã^–ÿv³ìNç^mì”X6HÖž”v²š¬kÖ¥†Õ6v¦eß -ëè!å(ûN¦ƒe!Õî}0[\» úÍû9¶ÿ8)mcƒ�cŽ‘ªÊØÖ¬KµBŠ+’Þ·‡•å6·b3üP®¬G�õ¹?<¦ø8TT ±1$(�çjÐ"§§¥RÏ÷èwj<óŽžá�¯F±úW¢VÍÚԯ߀ú•ݱÌf~Q®y2H–¶Øæú†–ﯞÌý½•Ê©E2÷÷ˤë‚xûýW¨”›’ñ`2œE–ÁZ‹qÄeÐ+È)$k3æ÷®¢™ŒFcB1�ü‹–I ´×BÝ åvæ»X‹£sá'Gr}æÙ¥)�ëÏãÀ–6n8I¿ŠÁ¢œù [¶_Æ$»Ò¼]H®»kJvn”ʵQË89; s %)žD\ó3¸¨u©Äs7>³Nœìs­ÙÉ5×�Ÿ�@ žŠ,¬ éèõz“ 4,ïDRÔ êx‘š’‚N§Ãd2å¹ûgϽóOüþ„´R°%f3fIÎàø~z9¢º”<’3û¾Dé•s¸þ?öî|s_ IDAT;¾ªò~àøçœ»³÷ 6 6([PQPqU­ŠÖº~¶ŽÖ:[GµZµ¶ZµîQ7¢*doÂH$@Ydß}Îï� �Inõûö•Hîyžï=÷œ{îùÞçy¾Ÿ¿Ëü§Ç0%<[?ç‹íŒÝ®æ†sÛxwÓ–¸u'ަЙ&s+Õ>M6lF8Á­V˜ûÌzf_zdL «x`ØhžÉ*e÷Át=zj »š¾Í×Ñ=NŽVî°ãè¦psã”Ý…Ó© &“éäöE{û:c?®¾ª?{x=ó?›KåU×®€cù'Ì*ðbH¸ŒëÆ7#胳…Nª/!Î2Jà@Fô2±|}5ëÖäâÒï¶õlr€¹ÿ 2ÏŸRîŸIwãj²6­#ËuCÕ\Öl¬FS, Þ¿¶öm4c<ú8ÔݸÜ:º×�ÛÝÊ�êAœƒ�w¢}ÚSüû0ã…·±è[¾ú~ Ë7çQ´m…ÛV0ûƒœ:žßÜ{'—õúù}©=Ûœíë]/žÃKïy«B»²øð?KÿÐ"ÎŒ�x�šžZ]å;8k ÿf?Þ”z å̯ôF»c'z¼í¶\”ºK12P”O#ÕÛ2Ô'Çk^ Ý�«ék4ÛžXkéœPyÁh"CéâïY÷› Fú�wÏRæ{1Ä�cJz+™sKëףɨ¶·YåñV´w_ê.œîCýµr-70¨rÑB!ÄÙ©Cï½^/ë6¬Àߤ³yËzt]'$¸±tâýx°]í*~þø) èu¬r­$ŠÅQQF¥‚i©ý)â7vפý‡grfóÁÜ*.¼<€ÍŸÁN¯‰~×^Ç ã?�ŽQ¬Øš¾‘vØÐR­K{5Õ'üäÜF~Ãxð¥[ùò¼�ûö�û"¯e¿¾¦÷É-Þ^j±Q*à¥xQ‹#DÜÛ6±ýø;³]Çü…™7$¢zòøÏ�ñãÑ µ“é–dDÁÃÞ={Ob�ä&†Dº&/ù»ò[|NºÛ޽y²°½}�€šr9¿i…Ú|1¯½a Ÿ~S‚fìÍÕ×drÄýL'Å ~©Tb‡¦«¼ù[ɪ*asV)š¡ ƒ3ãŽ|7$1x`$ª·ˆM[J)Û¼™½^SÏ¡ ñÕ{£!†ø¨Æã»¸èÀñG£�âöK©ƒ&ò«ÛÿÌ[ï=Íô$#zíz¾ZPÐj…öls&S£¦ðø³31p:�þߨaÍkOón¶ót‡ÖHižÓq¹ò1ìŠÄëQÑà (~~( jvðì݃¢(?ÿ´¥?_¯'¢FÕxÝ*.,iñÒ=Nœžv$‘Œ=¸`r&½ŽU‹ÖRëÎaá’4S/.˜˜Ôê:½¦”RGKýy)/«@CÁyâQ�íÝ—j(!�ŸOÊÊZ.f¢PÜé/ŽB!DçhwbÍd2S^^JMM¥e(-;À�²;ÕÕU˜LžeÀÔ)Ið²çƒù²¤õ ÚþÿòÔ[Ùx0’zÉedžÖªgº_;ƒÑ~P=ÿ3fÿ_¾ØåÅìõ\™ÒÉ# Éô댊‡+VQ~Ì.«cɇ_±·3>¸*¡œÿ×ç¹²‹‚gÏÜùð‚fÕ %ŠQ£{cÄKÞ¼ïÈj1¹§Q´f.ËrþœˆRc1* #^ö-ø‘íÇd¨�ÎÆ9Ó&®êØç¿ÀÓ‹*›} v³Ö=Üõi5�¦Î D‰º„gž¾˜HÅî×ïà‘E5Íú7Ðû׿el�‚gÛ?øýó¨;j{ûö×øÍES8·×`þ°üÐ €‘ôëf0ÌOÁ“õOþôïGÜ »ó>â©·vâÁ�aS&ÐX”³½}�ð=õZ&AÍâY<÷É\Ju+£®½’nÇ Eì¬Ä/–¡+ÃG¢jµlüü[¶8úgÒ»…7^OÄ@êyçÓתàÍ›Å?gï£ùXAOñÞ™³/fúϤ­IÕˆ1\4,¥a-o¾´€B~þ9Ç]ø_Ñ«Yøþ§ì8â‰ëT­üŒÙ{<(Æ$FŸóóˆ7Å`h\çÍ[IùY°öîK £†¤ê¸6Ň[êŽ8÷\syõóÝh²ÆšB!ÎRí^reÂø‰,\´€…‹æÓÐðóÔO??={ôaÜØñ LMø5o}¶‡i—ý•åk^âª~o‘�1˜Œ®‘ؼ5î\Çú�e8tSÜ$þöÕk\ÖùÙ«S™2ã2b¿xƒ}ù ¨±3¸á‚°S²ÆVð”‡xtì~·`/_З^ȈD3Yóùzq-c_z„Œïå¿Ggy|B%þšxâ£%Üþ}.¯Ýþ(—®y‘1MePÕ¤¼òÂ\Æüv6K<—ŒWsõyýˆµØ)ܲ€Ï>™Ï®z3i7ÏäO#^°ÌÐýv^yrî[À÷w gÀ·Ó™28Cé&æ|öY•:ácãù?ß´·¯Q".àš Âøú¿ŸóÊÇn´€ ¸vzB‹7ß�ƒø¥2ÑkØ B¿ü–¢�Ù Ø8gpz‹#Lÿ †ô0±tãNvjü`†%ûv"ºs>÷ݹ†Ûž[ÁÆ7~ÏuëÇqÞ�Â�NÊöl`ᢠ췛H¸ðv~ÝïÄ_w´§=5f7Oû†{>ÛÆîšÁšsF2$5– “FCå~¶,_Ī}L Ó¸nBSUáölsÒܬ}ù×\øÚqÞíMý¸ãõ?sá)¬ø«ø¥sËC×±åηغp&O¦§òüÔ¸Î]š š¦18s0[·meöÜY ËNLx$jBzu5ØíèN'ŠÅ��(aa˜Ì& ÷²xéB˜6í¼^/ƒá¤×[óõñzÂþ¦rßM«¹óÕ ¬~ù®_1š‘½"0ÜÅO‹V±§‚ÜÈ]D·=y«1ò‚Ñ„/ù–’jøù\84ð¸Ÿ1Ô¸áŒR>ãÎ[²¹à¼Át S9¸{ßÍYG‰n¤Ë䛸¼ÙèW%(‘¤P•5J˜õì_¨ ÁC¸õº¡„´s_ú�ø×§¯à›öòÉý·²{ühÄYqï`Ù¢u4 �Êø­_ñc¹Ž~VB!Ä/Y»kƒ�‰Îcâ„ó|O3 aç>Æü�cø÷SÏð꧋عa!û6úµŠ-f Ó®¹ƒþx=C"OÇmBËüÇÍàW©oó÷�¤+®§yÁÈNeìÉŸÏÇï‘ûyæÃŬûòMÖ©6b\È=_ü�?MÚÆošêI´uýç“bHá¦á£!÷²4çUnÿË¥¬~á\0‘vÓ§¬èò,÷?üf-x“¿ÎoÚNQñ�Á Oü•§ïMô±Yɸûk–vyŒ{}ƒ¿ÿÏÍPPý“÷»ÇyñÉkè{D1´ööu"!Lºæb"?y›.•Щ×15ªµ:+ñKeé3”Ás˜W£¡˜º3d@+ÅÔpJư1*‘ƒ‡ÑÃç«ÖI¸ðQÞŒø/¯¼ùK7|ÇÛë›~¥¨Ø"û0eÆMÜviÆqGÒt¨=ÅŸÌÛžgfļöŲ|É–Cç ª-šþÞÈoožFF ÒþmNšŽ«¾ŠÊúã<Ä\‡ë4Lw³¤^Å£·gqóÌÕ¬~í)Þíõ3º·RA²“躎ÇãÁívN}m –üˆYQ˜R[‹!%%&54Ýá@+*BÛ½›÷>~§ÃATT©ÝRA×q»Ý¨j+UÀ[äëãõD̤]ñ¯E¼ÇËo}Çšµsøp 4c1 š~wß4�®íÌáÙLfRÜ\>د3vƒNTîWIàŠÇ§“úÒLÞ{ûꛊ(æ\vüv8ÁÍŸ·©Wß2žÕŸÏ¾üÌÊW° LbƵ€ÒÎ}iHâªÇŸF›9“w–æ³ö»�Y (¦zNº‡¿ÞžÂ·Í\8|]dI!„¢“)3žÕQ“Rû^þíq¼cË;çTÄu,­�Ò=¹ä¨Á¥úÚ%…ÔİW±:ê~àÖÞðïâÞ<ºv�õ? µØt Õ5¸,Á„Øš’Ž505ú:f{úñèº <–qºjÄiÔ—ä’“_F½f!$¶iÉ'óZº9¸7‡=EÕ¸mQtëÙ�Hë‰6jo_¾t&Ä N¥ «–Ñ+}àéãѰW²¿¸»n$0<Žø˜@Ìí>¾ÛÓž›ú²b ËjhðªØ‚"ˆ�‹Âÿ¸oqíÙFt„ÇãÁîpp°²’òòr***¨¨('~ÃFÂ$øàA‚«k°[Ì”‡†RÀ®ÌL¢"¢ˆŒŒ$**Šˆˆpüýý1�m¯ øþx=µ%VÔ㱄ŸKHG;kXÇß®ÿ³*’¸éõ×ùMjË_,º–ý•óY€=îJÞxï·ô1€«ºˆ½•8ŒD'&ek}Ìœ·¾”}%õàJltÖcÚ¾}é®)boáAð#*1‘ÿ3ç‹Q!„Bˆ“•øÿâP.íì¹…PýˆJÍ *õtr"^ö¼ó7>,Иp;7¥Ÿº]¬7 gûv—3xÒ"CÂhþE¶sÃ6»A±¥Ñ3ét¾ô*þ1=Ó£�Û™MêCfÒ©è˗΄„è,*¶°º‡%œÆöLøG&Ò=²-ý´gу?› ST!¡¡$&&âp8°ŒÓá Äé¤Ð«a0¨˜Ífâ¬VºY,X­V, f³“ÉÔ¦i Çòõñz"Fc’éã«ö4 ç}Äe:~™S¹è˜&-kªý€9¸ iÁ]Njƒ)ÝŽ÷ˆöíKSPRƒN.!„Bˆ³ÁÙ“X;+èT¯yŠë^B½!•ß=|‰§põkOÖL¦Ž|†¥·}»œW΋øyªXýf^~ì}ö{UB&^ÊøàS—B¡( ƒƒÁ€Õj…ÀÀÓÒYF§~Ç<þæìj®üõDbÎú B!„g?I¬ù€¶/¼º˜üü•|óÕOìsZI¿÷ þ|Žÿ)�Ã4ønž¹î3.'›W/Î`ýÅ—0¶w†ª=¬øæKïi@‰œÄ_Ÿ¾‚V—B!ÄC+]Ídz6Q|`Ë—n£Äm&õŠû¸9½¥ò%B!„âT“Äšh¥?ñößÿÎv�‚Ø�)úÿ~h4!§:y¥D3õõ¥Ìéù�þãKVþOVë Š5š—ÝÃÃO?À%i¦S˜B!ÚC?˜Å·ÿý„<¯‚j‹eä5wóÀuÈdB!„g„³§xÁ™Ì[GIþ~*Ü6¢“‰8ÎbÀ§Ž›š¢}V6 YBé’G¨¬–/Ä)ñË*^ „èTšƒŠâRj¼f¢£¶œÜg ½þ{JjÑŒ¡$$…cíä0…B!~IÎÎâg2C1Ýzá³µ‰}ÂDP—nÈúÀB!ÄYLµ—Hx7Sü£éÖ-ºSBB!„?;†V !„B!„BqÖ‘ÄšB!„B!„ípV$ÖV¯Y{ºCB!„B!„âgÅk7ofè�Á§; !„8eŠ‹‹OwB!„Bñ‹{Ò�=+kBñKÓ–7r!„B!„§ÇY1T!„B!„Bˆ3�$Ö„B!„B!„hI¬ !„B!„BÑ’XB!„B!„¢$±&„B!„B!D;üBª‚º¨)¯Æ¡é ˜ ÅÏp›¹ë(¯j@ÓA1b£q3u•ið€b $"ØŠr¼vt'5584PýBˆ0�†˜Å!^ûAJJJ9XçÄ«šñ #:&’ óq_E!„B!„B´‘®ëGü¿¢üoÝ{û4±VSSCqq1µµµx<Œ&�DGGâË®ÚF+fÍì9ìp耉äq×pQO¿l¤S¹e.Ÿ¬.C ±#¹fZÁ €Š»p%³–à4Æ0âÒ©d†·–¾Ò©Þþ#Ÿ.݇ÃͰK¦p:b>õtWÕ ` Àr&Œ�tW²såVì(¦Þ{ä¯S0ÉýÏaLf"gB¬B!„B!ÄY¨y"íè¤Ú¡kž\;Ûm>K¬QTTD||<111¨ªŠÛí¦®®Ž¼¼<IMMõUwঠ{75=út¼×N+#;§­Å_ª„öǹ…Ÿ3O k®'þ’!D·°7µª­,\µ⇎#3¢=ãÇ|ó©¦Q±é;>Ù`f䯦Ñÿ¸�ŸŠpªÈúþkﳃ)”ä>=HŽ Àä©§¼ ‡í{*È[;—j×E\>² æÓ­B!„BÑ©¾ÛPÁ'Ë Øž_F½Ý‰Ãá@Ó¼'Þ°Uz³?t@E9üwP B¬œ7(�û.I#4Àrxë³5Áæ“ÄšÇã!??Ÿ~ýúa0X³f 6l`èСôë×�ÀÀ@víÞÍÁƒ õE—í£†\CEñNrªú2(´õÍ[’CN•Ž-$ª«pý%€ž£ÇPP6�e™¿&žËG•�Ñ*Ù¼h5N°%�`|¿Ð¶/jç˘O)J«Ðˆ:­QâØ³†•ûíèæXFL›BfD³é¸}úÑcýl¾X]Bå¶õäô�¥¯ÿÙyB !„B!„­Ñtxá›|Þœ“…G¿à(l¡] �²`4[QÔv.&¥ë€ŽŸÑK„w›²÷3a`I¬Ùív,Vëá¹³�—Ó…ÇÓ8„P×uP‡/ºë�À¤®Dd•R𻓢ÁQÄ·”Œuîcçž°¦Ñ-VgïöÖ[4Ç ebf1_®-%kñr/OWxÊ6°`ÝÜj0}ÇžCª_{ Çì(fÃâŬÍ;ˆë¨©ÎŠ9”Ô¡ã×/ꨩ�.J³–²`õ.Ê�GO45ß�Ñc‡’¨^ŠÖ~Í7;�M¿/gãœÏÙˆBpÿK¸vDLcN·S¸i)‹×ï¡ò¨@s(Ý�alÿX¬ÍþÝ[¸†/æå¢u9‡«‡;™ÿÍJ\ ô#¬[q­4’<úZf uà5´|ЛlØŒ xôƾB!„Bñ?â£e%<òÎj‚cRˆMNäøÛ )©ÖÍ¿‚í;²ùð� H�8©MƒýÍ<5cÓÏíÆ Ï.¤ ÂÎ}Óº�“\Ó4�Ü]9ääæâñ¸ÑuˆŒŒ oŸtB;PÀ'‰5—Ë…ÉdÂëõ¢ë:N‡“�;r1 hZS"F×q»Ý¾è®tL!5j-ìaçþáÄ'[¡ÓžŸC¾üz¥‘`Ì>ÁšeF¢2Ç3¼èK–æ°xi"Qã‚Øºh¥aýÇ22ÑzÜNYÌz5[˜ÃŠ'jp2ƒô$>Ô†êi <+ë¶‘»|.ªÿœ×õçñ_öÝKøfY. ÆPº ìGjL06£Ž«¦”¼í[ÙY°‘ys�\6}0QªJDÏsº—�«s9H0iC�`U0G7�». W}Ãì�åxÍát:�Þñ!Xt;•ûw°~Ónv­øŽzm— Œø¹ª©Ñ€A¯ç [WfSaéBZjVs4¶œsªÉ‚¿ÉÒêïµÊJ]:‰ “êB´‹«–òºÁ�ÐPÿ“»À´¶M{Ú:n?uTÔØÑÁ᲎¢B!„øÅø`Y �¾½Šˆätß�RƒfIµJrsw1ëñóI‰ js3S#™õØù\ñĨŠÂ=SÓß'×–.[Bu] 2:ìÌÞÉìï¾&%)‰sG�iW»>É ¸\.Üž¦]×/x§iš¦áv»q:�'h©³éèJ0Ý{ÄbÔس3ŸcÆÐéuìÎÙ�K µG<Ǧ°Z †’>n)~P¿g)ß~=Ÿ�å^ŒQ™8¤£ áû.f­l;›‹œèj8'Mfxï®$ÄÆ—Ð�Œs.db¯@½ž]Y»©;Z�Íü-eèºÞbEÑöÚµ{…ÅŒ3ŽàÐPt,V+ÇçÊ+®¢º¦–¥?-iWÛ>±æp8ðx…ÿ™å£ª¢©*§{‰­¡Œ‚ �ÐØh}VK[!„BˆÎ¥épÓK« ŒêêÛ¤Úá4ª ¶óÈ5™t�oÿTÊCz$„ðÀÕyþ³ÍŒí3£±�…Z�»;‡^½{£(��³“ukÖa0èßýû`Âø ¼÷þ{ É‚ÕÚú î-ñÉ † IDAT-‚Ãá@QÕɵþýû“••Ezz:^ocRÆétv(±öÚov0JÕÞøWk2=SlìÉ.bgn }úš¢¨S™›Í¯JxZw¢TN0 ôHF«�Ãkÿû8»ê“˜M~„FøqdùMÓÐ5 �Ò8ÕÒíñpx€ˆâGtTjaÖÿÈbÓ0¤v!Äòs’­MÃ3õZJÔ££ÓrK &6Æ¥¬Ž²’r´¾q:©QÄŶ>­óÄTì%¿¾éõ1›˜D|T0™*ÎH*á=‡‘ýó™ kìÕ%ìÊÙKɶE¼½}%+ö<ÿ~Óï"¹f>÷a,|øt‡xÙýß?qÃGþüßû/rU¬¼I!„Bˆ³Ãó³ó±;½Ä&'ø¶á¦Ñj)�5T7øÕ¸4Ÿå?®›Ð�æçðìW¹<0½à›)¡åååôîÓ›êÚ*vnßÉäóÎ'(0�¹?ÎÅf³‘ѯ?))ÉìÌΦFÿ6µí“ÄšÓé<"±–––FZZãŽõ4›"Ú‘ÄÚ­¿¹¹ýj{™ÿÎv¸¥”Ì$öèF@N²s¨HL„ hedçV¢¢éÙ=´mkù9ö²|á*4 aáfª*ŠY½pq— &Ú'{ÙG1»«Ù»#‹y…¨¬¦ÞáÆ{tƒ#þO%:sCJ粺°”¬%³ÉZf!82–øø’’SHŠn¥ @KôzêšZ•[æòQvË{ívtÀS_‡ýÐè¹CŒ~t$¯¦F‘9e:½<ÜöZÊ‹÷°}û&–änes�±L›F�Ü;‹3Š‘ž—ü‰§&sŽku»ùæ¹Gxvq 9Ÿ½Á7S^äª.rûŒ^ÃŽ…ht?Ý‘!„BqÒ4Þš»�и^¾+TÐŒ®kíÛÃC¿àó¶i:O¼�û/MÃ`ðͨ5§Ã�ÉdÆî¨Çáh "<‚ÀÀ@Î5š¥Ë–�Þ¯?II)lß–uúkªÑˆËåjqº`uuucQƒ3b*h#c—¤ogCe;K3£â-Î&·JÔЃ´¶¬³¥×“³t1Û«uüRFqñ¸@6}9›MeX°&žé#b}²Pv‡cvìgùìyl,wƒÑŸ¨.É$ûa11¨*ÔîeSv)Ç,gdŽaðEW‘´{;YÙ»É+ª ú@>ÕòÙ¶þ'¬i 3Šô¨“Évix5t/^o+1›6ƒjU9:ï­ ¨zc0I ±Ä'w§_Ï,¾ûj{³—°(&–‹û›ÀâL¤tã¢Û.çûåÿ`ƒ{Ûv¹¡KKç¢FÃ�\¶nÏ£¨²·ÁJHt2}2zçwüDœ»j/[6ïdEK =3Ð-¬ÍïkÞêBv•Ô¡a#*%‘ðã4 ×‘SX‹n#)9òØ%š�¹[ÉÊ+£N÷'¦{º…bÆEÅÞ|JBº{tEæÃ£Š”l_φ]¨Ó,„Æõ``ÿÔf1éÔ—ìfÅ6Vf{Ðuöd³£Æ€%,�”H›¼G!„Bˆ3ÖÜ�¸½`õõЦÑjng^‡‹ó2šþÍw&Näá·Wóî¢ýÜ8> ð]!MÓðzµÃ »¨ˆHìö¼^/f“™»½Ímúl�5?jjji¡D©ÃåÂh2�UA›Q£èÙ=ŒMk*ÈÍ.dXL 9»©Õ-tíÑÿ“nH£jÛ"–ì®ÿ4ÎÝ�@‹Â°1쟽‘Š- Y‘0�1 b勘½­_¦r7jPw&^4–îÁGf~½ûëÉÊi!± ÚˆJËd\Z&x(/.`ÿ¾~mØ�ÇÚ‹�©Ø—UGaÞ>}zÓ¶YÕBœ>jPÁª¨ZÈ:ëÕ[ùà¹çygù~êµæ=Õ/�q7?À—ö8v ©çËÞ|†¿±¹±jîáÍL„§_¼™Ñ1'wÑ*VðÌïç›…”iá•»�ûx÷ú7¹åÏ‹qÇ]Éëïþ–¾Íºñ-åÅÇgòåÎj?ÅBì°_óØý,{èw¼_ÊeÏÈUÎÅhÄP½‰7ÿú$ïl¬Äsøi)XbGñ»§äÒ®ÀÍæ·ïåÞyµMÉý]|üà|ŒJ•/ññí}|sB!„¢|²¬¿�¨Ni[×uì5\Ü?Ð� ãƒÛ?Ž�çqøDWUÐuýð²ef³—Ë�×ëAQ§+±M}CÃáBG³ùùᨨ 22ÒÝùˆBX÷žÄ¬_NñÞ<Š^róí`ëN¯ä“_¾Þ[¾‰ù+÷á �^£G‘Ö4:Â;˜qý÷óåúr²ÿDâôqtíp¦¦1k•ìÝW‡ŽJl¿!¤;œÒQ[‹ëdΣ ݉Hè΀Ì–~õ-›�•[EïÌLGUƒT¡Z£¶¦ ?ß”¦=­š¼-9×{ë5”ža-õ¨`±šQÝéÄ©sì!ÎPŽì,rÜ:Š¥Ý�z[׊øò±‡xu}=¦¸a\õd&†bvU°kåW¼3k+ó_ycäüùÜ�ŸÏ_½ŠŸfÞ˃ߣ…öaÚ0<%ªv³ìËO˜³å3¾ÏÉs¯ÞÅÐÀãŸ,z]o<øW¾)ЉŸô 3ïJ‹§áÉpíà͇Ÿâ‹ÝṉC¹òÚ o¥vÏ*¾øè]þøÔhz×ë€ ³ñظSsŸ|Œ•®‘Üò§áôˆ4ÑP¸‘YïÉšâå¼ôÜ,¾r%ɪ‘nÜÉ)køðõì%Ž 7]É�`þÝâ:ÿ}K!„Bˆؾ·[Hr'µ®ã¬;ÈèŒ~>­vȹé]ødiþ ×nÛ°ü5–~ûgÜnWëÒÁ/õáÃÿãvÙyùÏ}4âR&\òªªâv»1 4ØÚ«Ok½{÷fÞ¼yDFFâçç‡ÇãÁår¡( &“ Í른¨ˆ &ø¢;ŸQ‚R鿚¢}ûصÅÍ>ø÷éA‚éÄÛà.fõ‚µ»U‚ûŽáœäæ™3#1™c´ÿ+V—f³xYQÓŽ\+ì”ÆìÂåÖ›_ S˜´Jvî( (Í�[O¥%”¹‚IM?ö€±v¡[¼[ÖÓÐ`GçDë¼ÙˆíŠZPN;½T �&ò˜;T�úÒýT[¢‰ ¶øàÖÍ��ëY_ ¡jWÒ†GÓBZ‘²²Z4ÀÀѳDŽ8#yëØ»î;þõâ·é~ôºz“£ŽŸ-ŽlJ5v�»°€Þ°‹%ß,§P�¡fêE ‰:*ƒç©¤ ¤•�РÃÏMQÕÆuдêt8yÂÒG3lßl~*,góœ�ÙG—pLº“šÒB +ìxQ HÉÈTY]Mœy¼n; Zó7÷¦B º—ÚÂmü4ïkÂïcúQ‰jÅFR·0’š7¦kx=<^/NÕ‚Y{ÓèÆ¦KÙž]�†�„Ý[i«’4ñVþ4ñ8ëU¬þ×C<µ° ÿŒ<ÿØ4ºvt©I­„=ùNt ¤ôLmaD•ÄáCI~k¹­\…kÒÓZÈîü ´*àpà<©9ñB!„Bœ¹4¯ÕàãU�OËÔÑ–a{?gYa«m&îâDt$_ÔŽ˜A!¸Ïx&ÕÎgÑ–BJ²×Q’ (&‚âú2yìPºz °“’uE”íø‰…Eý¹´k ñ#¦25`%+7ï¡$w ŹÍZ5Ò¥÷† éwd!B5–ÃÓØ·(‡ªÊ|²*ÁÊ`PTBzMârÿ ü´z+{ ¶³¶àç8M±ô2”ýºà³Ò†\8�ÐM«Y³-�ÒùdhÖg`,Ýû aXz2PEœqL ½û¿<7ù¨jµº›º»X³àS^ÿ;^¾o%ïy‘§¦Äùæn/bÕw³øfùF¶çR^ãÄ­y<â°×*(­Ð#!aÁíekgûû�òúWy¸ÌéÜ~ÿUôòE¾Z«á`Mc\¡á!-N?Ucˆ3(­'Ö,þøµøþ«rèú)i5!„Bq¶S ÆÎI®jßh¢ºÖIdHç L©®ur²7"ÎÚ�¨úJ,¶^x¼vìu»pÚ«pØëp8ëqØëq:êq8êp8°˜]$wƒ®7Þ4¨ªBùÁr‚ƒY·nœw~›býe5S“˜0ã6Z^áÍ@ܨk¹sTË›º�Çm·ŸwdsÁ}¸xFŸ6ôBÆÔ›É8ù-|3Š?Éçrà:¬Ã©±…b;t¨Ä šÆŒ ;v�›ÍÔtãêG\Æx¦gŒÅUWMu½·¦b²ú€¹ÅD”BPÚ®IFU­L~Úøy-q•ÀÄALNÌÄÝPMU­·nÀâLH�¥…5ÐÀ�0†›nÓê.;!cɃ&’¨dœB!„8[\1*{Ui'´¬€Vÿ`n.F×ôÆQl>üÑ5�Å›‹¹jt"Š¢œ¸B§ÞI7'IkBqÓìelûáŸüñ¥Ÿ¨Öüû]Èù]›V)T#‰‰R9[vÐÐ|CO)Ë_yŠÏj"RAwVsÐq(ud õ¼óékUðæÍ⟳÷Ñ|¬™§xïÌÙ‡3}‡gr¼ëœ¨»î窞ý_óä‹K)o÷uÏBÿQCRuœë?ãÝ�µÍ’],û3Öágl{¹…Ö(CãÚ�ÞJÊ+Oï[!„Bˆ“uáÀpLpÔVtBë &«?þV?l(àÐ÷ô¾ú™·®›‰kÏ�k5©¦ë:N§]×ÑÑhï×à‡MëØç|YcM!ÎxnÖÿëf.yûÈ‹Šæj ¦º‡WEÅ?íb}h ‡¾2Qc{^oo_Oñì'ù?ÇÅL耳|–.a£k�þm0?Üùw–Ù7òÉ«_  îňÑ}O˜Ê}7­æÎW7°úå;¸~ÅhFöŠÀpp?-ZÅžZp#w]}Âoh¿tnyè:¶Üù[ÎäÉôTžŸ×b‘’ñq 7õ_ÅÌ ù|zÿ ¶ Fz´‘ê=ëY¶ÉÎÀ»~Mêë¯ò£½�·{P"I¡*k”0ëÙ¿P?(‚‡pëuC�ŸPB!„â4»é‚>ü{ÎNºt?é ›'CQ0˜‰��ç³¶qÞÀ8ß5ücV£úDc6›[M¬¹\.Š‹‹Ñut7è.t< ;›m'¦itµa³µ¿º©$Ö„⌧ã¨.¥¤ºÙ?) ªÑŠh<ÝRû0lì\2¾/GQ‰»ø~ž8ð4û|Ûæ½Ç¶y ¨6bL导‘sc<Ä\=�¬w·’óÝ«<³érþuNÂU3iW<Ákïñò[ß±fí>\  Úb4ýî¾i][¨ÐKêUO¿~xuœ©Wß2žÕŸÏ¾üÌÊW° LbƵøôÉB!„¾vÏEÉ|¸0‡šò}E&ú¦QEi¦@^} —ÆG‹÷põè®>iþƒE»qx4~?¥ëái -%×\n7eee¨#uU› ‹�b CU˜ô0Ö£Zj1:k1Ùj±º�¸\v\.&£—ó .·“Ò² âœX­ÖO9m…1ãY¥qÜÀ¾—{ÜïØ²��ÃÎiWGñÚorëon>åý !D{lXµŒ^éOwGÐìeìÍ/¥V3Ò%‘„PËy!¯½Š*§…à`ÇΤôP[R@aE=K(ñ‰±„˜Ï€¬’îÅQ߀ÇäO€¥iÜ\Ã�üaêÓ,ó¦pÓ¯ó›níw,o})ûJêÁ/”Øè¬²�‚B!„8 lÌ«cú“ Oê‡-0Ì7�ê�“6uM#L­`ïž�|öà8Òâ‚:ÔlNa W<µ�?_Ý‹ ‡¤`0ZM¬9�NŠ‹‹Yµèöe½�ŠŠzx½µCCuýðß~þC]׈N™ÈðÉO“˜�Ðæk‰ÿ÷/åÒdÄšBü¨¶HRzE¶ú{ƒ-„ðV¯%Fc’éÓ)¡µ‰î8Ⱦ½û(¬ö£÷à4BެäÊÙI®k¿ŒËG&1±ÜqG«˜Ífbcc™|Éã8Îÿn—½ ˬM&l6¬V+K;fÒ4o«C[Ÿ"22NwB!ÎÞ¼Ïùã³OIàÒ¿½Ì}ƒƒygßͧoÿH©¦�yƒýOg¤B!„Bœ® ç‘·W•BPd¾X×DQT0šÙUDjr½ˆ×7‚þ]Û–¼Û¸«‚[ÿ±‚‹†ÆsûùÉX,TõøSDEÁb±`6› n62ídcWŽø³#ΊÄÚÆÍ›:dðéC!Äifì9�;Î[ƒóöóåƒ7³sä(2“B0Ô±eÅr69PBsÛoÇzÌVB!„âLpõÈhzvÏ 3WRTQDX—4¬A½Ö4jMQT fvÕê¤vKᦙ+˜24Ž{/íG�Ÿé¸MÔ4¸ùûç[™»®€[ÏïÆôáqøûû£ªêqG«†ïdíuV$Ö„B”PÎý˼�ôo|±œm‹¿f›  ˜Cé>úrfÜr5£ãåò&„B!DsRØüòDf~›Ïëßn£¢@Ç�_@³£ÙŠ¢¶a9•CÉ5UÅ``½‘à˜®ì*©cä=ß2&=†ó%�DL¸% dT3o}K¶”0ªO4Ü•A—¨Pl6Ûq×U;SÉ�‡Bˆ³‹!‚!W?À�«=Ô——RZëSQž E„B!„8ƒÝ=%™»§$3os%/Ý϶¼|j84ÍÛŽõ¦Ú:h^r=vtÍÍ×Ëk™½rocQEÁ *û[—ÉÇwgD`@F£±M#ÕÎ$’XBq–2âÑ…”ˆÓ‡B!„gŸÉaLÎðM¥P]×ÿhš†×ëÅn·ãp8p»ÝhZcµNUU1™LX­ÖÃ#Ôš'Ôζ¤HbM!„B!„BtÀ¡¤˜®ë(Š‚ªª�F«„*.Ð|M´£ÎV’XB!„B!„vt1�Öªu6O¤�ÍI5�ÄÚ™Gsãti¨f ¦ãW—B!„B!„8£�4;:¹v¶'ÒŽöËM¬yíT––R^U‹Ý¥¡ÍØ‚‰ˆŠ"ÔÖ†*¾â©`ÛÒE¬Ê-¥Á ˜»3åÆ ¤œ†P„B!„B!|á-‘v´NO¬5_ îL ;JÙ¾n5vPåjaH¢j&$¾™CÑ+Ê©yùu*7/dÉÎ2¼ª�ȤxB­‘Øš:×]uT7€-(Ë™±…B!„B!~ñNIbMÓ4ÌfsgwuB®²Í|?w%ùu‡ªÉ%v‰ ÈfFñÚ©.+doA9Uû6³ 0�½ç^øÿìÝw|ÕÚÀñßÌöôÞCJh)t+ b¯ÈÕ«¾öÞ»(zíŠb»V®Š½¬ 4A:jH!¤’„ôl�yÿ�’�H�çûùhØÝ™3çÌÎΙyæÆ&Òõ�Æ)*ªÄƒ‚_ÿ±\8*ºÅ£Q±êg¾XiæØ�Kªß?;Ò+„B!„Bq¤èÒÀšËåÂét`µÚºr3m¢×eóÇ/ ÙR¯£z÷`ØÉ'�ë»OÐÌ]›ÏòÙsX^XCΟ3ðõ¿€ã¢L]œ9N§¨øìõ¥Ø)-«B#¬kó „B!„B!Ú¥Ëk‡//ïnП¶‘œ…‘W¯£X{0êìÓØz;4£o#Æ�ßÿÀ²í•¬ÍÈ!52pT³½Úf?‚¬hµÅl)(§ÑNR¯0v‡u\uÛ).­¤¦Á‰G1aó "<2 óžûÂYSN•½†:Wóz”–Õ£¨Vl'� %ä—i€‹ºÊí”Ù ^ûtq°O!„B!„ÿX{#uÕÕÔ××âv»q9�hš§Ë¶§¨*f“߀@‚BÂ0Žü�å»,°æöxp9�Ô¸«q:�¸=nTEÁß??_¿®Úl«ôêl277¢c$jð(î'¨¶‹)œÁ'�& 1€øè ¬;cažÂ¥|óÛ&´¨QLéà�—RâÅg A‰aD«€½˜•sç²lóöÂM1’4üNFSÇXÇD&# IDAT…K¿ç§lç®eJVþÄ—+SCz°|£cç'ådüò5(ø§žÇeÇD í !„B!„¢=êjª)-.À? �°ÈhL&&³U=´@—Çí¦¤xÕ••øøûˆÅjÃhjŠ‚¸]NöFªvì wÃZ|ýü‰ˆŽEé&ãòwD—Ö¼½¼q[šÿWp¹]8*+ËÿæÀšN}A>¥ÀC¿Þþmš�ÀÒ“¾{¿i4`PÀãÞAÖ¢�TX¢è•„ÕÞ4Ñ€^MÖÌ_X¸Í�êÏ�´¾ÄÚPÝ ”oÉbùÚ"6-øÕûbÆö´*!É£8%ªŽü•KÉ©Qê3‚ÔH3ŠÁ� Ÿxü‚òÉX²‰øÓkX±VsHÛÊ „B!„Bàr:(*ÈG×u¢ãâññéÜØLmõ ó·àDŸþƒ0÷ 9 6,V~AxÜnJ‹ ÉÙ°–ð¨hü‚:5?—.cÍhhJ¾¦¶šÊÊ ŒF#~~þ]¹ÉVèT–W¢jP$‘ÖCHJQQ½j›üpÎø‘D¶˜“A+[Çê"ºLú©§1"dwÄ5:¶�ÚçL_[KΚ\ŽI€�¢à݇~QUØ×/#§FÁ;¢7ýûyíZ/ÜßÁÆ%›Ø�IÉô—É „B!„BÑ�õulËßLXTÁ!á�žþŽòrJŠ ˆOì…ÍÛ§MëŒF¢bã &?on·‹ .È[WëòYAjjj�ÄvX&1pÑÐà@ >¾xwB\JwALzúA550…3.ìIƒÃH`ðÞÍMDÅF`Z[‹«ª’*�¦qÛ„Bü#èîFê<lÞx™þ'xg-å5vtƒ��ÞσB!„èt�õulÛšGlϤNo¥PUYAiI!‰½“1[ÚßšÉËÛ‡ÄÞÉämÚÐ)Á5MÓX�µšüü-TUWáq{ "*"ŠôÔÁ˜Í�7n}‡¯“óó·PX´�ŠŠJ, ‡cç_;‹»Ý�ÅjÁÛË›ú†z;_ûúøC\\|›·Ã[ïNíhV&“j6£’té줆iÙ÷}“�!^îñ¦Ž¦i蚆[iêJêr»qz.„GGåÖmØÂ¶²*ê�³~!‘$ôîKR˜õèwQo 8oUnýàË`$°GO"l]ì²ç1}Ê ¼=;›J§Þcxþûe>øªÝ™sÑ.˜4WôxÞ™v=$²&„BqÄq:lÛº™Ø„® ª9ì�æÓ³WÇ‚jÍÌ+ I½ÉÍ^�Õꃗ�w‡Óª¨(ç—ß~Æj³EϤxTU¥¶®Ž’âb>úôCN{:QQQÞFK¾L.,ÚFLL,š¦ÑÐÐ@`` î|Ýô·wï^dd¬Úõ:&&–üüüvÖÎ8ý´Žfp³iÆ{ü–ëÆàÕ7pÈsN½ði%®€«šüõkX¿¹�ÒÊjêí.<{Obp¨ÛBEtêóþ`êÓ˜¾¢˜zmß`’¢Z x*×Þ~g$ÚþùçwïÝñ0?Öhm[^ âÜ>ã�!]1›²Ææ¯Ÿç…Ù¸Õ’F¤ÑÓ/‰€#(Ê©5lg[…F`d8¾-¯ £ª¢©*‡}ro!„BÑ!Åù„EDuIP  `K‘±X:¡‡¢Åj#"*–Òâzí3ê}›hšÆ¯3#&.–ðð0Š ‹Øºe+šG#$,„Ĥž„…‡ñËo?sùeWvJ˵ÖœN¾¾¾x<‚‚‚¨¯¯'0°éoóë   t�=^ûûùãt:¾�N£âëç�B5ZU;4ˆ8ÄÅ`@mí&Ã^À‚é¿‘Qî£7aQñÄú{a11¨*Ôæ³jc™´VB´Yãú�¸ãîɪױE¥rÖ)#�¿Üõ•lÍ^Á왋ÈYýOßžOíkÏ1!¡+HÝ‘JPR:}CR•)¾$uU¤K¯fõª-¸t•Èseêí©ìï¹K÷ä!÷ó¸òSonýèe.‰Ü½ŸÌÇOdÖ쉇1oB!„âPÔÕT£ë:Á¡]3nYMÕE!0$´ÓÒ ¥²¼ŒÊò2‚BÂÚ½~Öš,Ì&ÑÑÑ,Y´˜Ð�0††ÑdfË–Í,[ºŒcŽIPH«V2|ØðCÎs‡kn· /›7þþþÔÕÕc0q8�MšÞ7™L{¼¶Ùl¸Ý®CÎxÛ©‡‡aQª±×neKå"BÚrƒåÂîP±ZÚÚ¾ÍCÑŠy¬*w¡úõfÌY'ÑÛÏu=õ¬É–Àš¢�´~zûsÖÔƒßàyóé IÜ»uõ©çpù„…¼pÇãüP°š©oÌàäçÎ$üj1ÕqF’/z”ɧù¾Vzzu `$&.–#®÷§^Ãúõ…hô>Ü9B!„�¬¬¤�¨Øø.L¿ˆðÈèNO7,"Š’¢m ¬n%:6Š-›·Îicw÷€Œ‹í�Á ²iS.ÑÑQ”vJ~;Xóx4 ©)é]ö¸cGµXÏ�ÇÓÆî;�Ä“Dœ5‡��;X›±™”1‰¬‘¢³p1_ý’‡WŸ‘œ|\ov“ªU’¿µ•È�Ãèå¿o@Î^[‹³­C !„}=+78ÐU?Ž¿è¬}ƒj;BFrË ãÈþx‘:;\n®£pS5º…°ø8‚÷nFå¨`ó–rì˜ì‘°ïøcžj rK¨Ã›Èž1ìª-4J7‘µn3E• ¸ VÂãéŸÒ—h¯}O”ZM›ŠkÁ+œÄØŒîj6g­fíÖ8�>D$ µo8­¬Úé\; È+k@W}‰NŒÂwŸmê4”maë'˜ƒˆ‹eÿòéÔçRPULYƒh4”å±ac9ŠêGLR$^µMe×­!$ÄïÛ’M«e[Nµº•Ðø8Bv. ×‘]X ^$ÅúcÐ픬[ÉÊœê4 Q½IOëEÈ¢x®ª|2Wo  ¢·%€Ø¾)¤%µüéÔ—äRP±–EÝèº�Ò¼�¬¯1` Š%!Ô;ó¡`_¸«·’™¹‘­e5Ø þa=H˜L¼ÿ¾­&;£\B!„¢möF||»¦ ¨ÃÞˆÛíÂ×? ÓÓö ¤h[>µ5Õøúù·kÝŠÊJbãc)).&mÐà}>ï™�Äœ?g‘GUum§ä·Ã�µ¸¸8fÌüµ• ™Ž¾Oðh÷{ªªÒ+©WG7Û1æ8Ò†’³´Œ†œùüÀéƒ÷[x­fsf¯¥Ê¥ãr°¶é†Ï‰Ó¥*6¯VÆ8Ò*Ù°¾ HpMÑ&nÜPPZíÞLÁç¸Ûyï¸oyÊøõÙ›™šgãÔ'¾äñQ{Fåê¿Áµ“æP‡…á÷|ÂËgíqÞroøŒ»nù’°óxýã[Iôê,>žü",(Øk¬7Õ+–“¯y�Ïï³ÇìËÎeosÝæãéÓî ä£G^aÆV;»ÖV ô;�‡»�Qa]]3x6ñáƒO3k‡ÇÜó6“Ïßc½v)/ßú0ÓK-¤\ÿ:¯'¨I»‹•ÿ»ƒû~oØU–µŸÜÏÿ}Š×É<ûÃä/ü/×>³-éJ¦½{9‰{¯q1¯Üü ó= \ýî;\›Øô@Æ•ù!·<4û ›ùlRO~}â)¦­ªd÷\ 我Üúô#\”¸W¸Î]Êü©ÏñÂ7«)kù$G1<è<î{èNˆ0.V¿7wÿV»3ÿ9|öÐÍ|†JìøWøì¦þh+¦rÝþ&/p1{ê ¼ü]æžÛsiçÞƒ×Ol‹ Ù!•K!„B´K]u5~þ�_°ƒjk«»$¨ÖÌ×ÏŸªÊòvÖ±ZÌÔÔÖ²Ïç�þÔÕÖc¶Zh´×wJ^;XëÛ'™¾}’;%]O%$õDFlû�…E lYðßíɨ!}ˆhÙLBwP‘—Áü«(¨×0ôçäãÞº Å_oê4¶—âêîçõZ›üA¦Ý›RM£ÛN£ Ú2�¢ªMã¹i Ô7èà'#H qÔ°$Ð;ÆÀü¼æ~ú%çö¿”þ>m<z0lp8ïå–�¹:÷¨-Nø.Ö¯\CƒbÆbt±.c-�gŽÂk×ç…«2)ÖTüÓ†ÑÏhE|ûøÃ¼¹¢Sô®˜pé=1;+ÈYô|ŸÅ¯OÄú.“ŽØ¤SÍFTÜUüwRÙA§rÛCé R•·˜o?ý™ÌµßðȤþ÷Ú¿Hì™'Õ�“¸ûÎ%¬yôw¿û3‡Oâ´æ¡ôz–ýï5~.Ÿ´kxèâýÓÑËÌU÷NgÛŒwøìÜaÜØeì`¹„B!Dû¹\NÌæ®cÃétb¶ìg¬šN`±XÑ4O›—_8óExî]^{¯�®£*.¾a2^63ÞÞTƒ�† v¾ý¥ tƒbàöGŸaÊ£÷R`íèºjµ„“~Æ%Œ?uÉÑþXpR³½ˆ­[6³¹ „J»‚wh©'œË¿Î?ŽžûÀs þýOáÔ´h|ÔFJ6.gÁü¿X´*—jßœvÞ)ôIdHZ6ÕÅöõ1{I5ëªF’6²FgåÖdf±¡¨�t'â( rò=¼rß8úú©¸+7ðÇÿå‘;¯æÌ3Ïå‚ä‰7¿dƪj[©s,†’æ¥àÙœIfÕV¶š…:þN`l¿¨È"£ Eû$ûZV¬w‚e#R›Ú±©ñðü»ÿåÍâÂĽÛrÙHÚ›¢ã*ØÌÖÖš:©�œ<álöž°Ô–|&g&A«fé’�]?¹‹âÇÈïâü•ŠÙoòß…Õhöu|ðò÷lÑ9þÖ»8³›tt%‚3®8³E𩉭_*ý- x¶STÚ¼³]¬ùc.ðzç÷Üs%Å;•‹®¼�sÏ9›á!N:>…�“U³æQ¬)˜SÎeÂ@¯½†>PðM?Ÿ3{Ñ=…Ì�—ÃÞ‡fûÊ%„B!:Âãva0¸Æ!¥ïrb0u]ú³ ´¶>\n&[_¢#½˜;kþþF""" �À×/Ÿ ‚‚ˆŒŒ%,Ä›?~ŸEh° oÿcqâ›GO‹µ]Ì'atâtw#5Õµ4:=`´à퀯eÿ7T†Ø¹úÆ÷Ÿ´âMüÈs¸rH;vÔáÐ�Øü°5ïf•ˆ!çrUJ#�n#6›igd3€ô n õi üz�æÒ¸TÕ:Àä…Ÿ¯ £ôâ(a#ñô»yï„KX>çf-XÊÒÕÙ”Ô×Q¸~ …ë—ðóçoc Ä—_Çõg$ãß|³ bx ³–n c­�sFÙ�ÚÕd»Í K@K2^_/ #³­g(*àÚ˜Áêz0 ÆPÿ¦“�b ".1ˆ¸–YÓ5¿¹XöêåœñÖ�WPl£˜øáŒÜYï+>ƒ¹áÞóY~ÏWüúڛĻ™/6{=å6îÚmž8)–^ ìÝÊSF£/¾6vÍã›ie¬ÛX�†�Ø>½Ù·Ç°Jܘx`Ì!fJ+aýÆj4Tbô#¨µ�¥FÒ/ÙucÅ›r©ÑûØ"?í*—B!„è�ǃÁpÐnæöx0º.¤d4iã/¼»CÃj5¢inh‘ŠjÒÐ�Ë/ëG]½o+NÇ–CÏë!§pSŒ6üƒm´o(¼6¤kò!(Ìg¿Ÿ«&Þí ìªf‚‚÷Ÿ¦âŸMõŠfØW0ìŒ+@³Sš·–¬Ì5¬\¹”Ë6PV¶šo_¼‹ŒÍOðÖ­CðWÅ�!Ãza\º–ÌÕ¹;ÇY³“¹b-Nci¼ñ2 ¢Ÿik3ÖÐxîIxãaKF&åš�ÞóÇ|�E,þù{~\�ÁºÍ…”×8píõiA)Å7”pkk0•À TÊÐꪩÕiG`MÇY_EåAÆUuûÌÈì�r%ÇgpÓÇ3yëkCäéÜÛ(‚»ÑC ÅêƒO«µ´ŠÚ<4\ó[Ze`$ Èß t:‹§‚í;·²ŸïÛ@Hp*h•ìÐÙ3°Öžr !„Bˆ1 ]\3 ¸=nL]Ô*Îíq·ûšÖÕ˜‰î˜…Å«?Κjëòp4Vc·×a·×c·×ãh¬Çî¨ÃÞØ€—ÕE\Ïчœ×£:°&„G$ÕJxÒ`“3úü+¸»j=ßNyŠWç±åûÿòÙ©S¹¡�P <˜xC›33›ÆYÓrXžY‡5ˆÔ0EHJË׬f­ó$†ËYµªÍÍð!Ñ»'zõ ^½û>ßdK}R�aXL0~V3F£¥d1ŸÏ܈}y¶4µhk�ÑÔTé.®vETÌŒ¼÷žë{À¥TŒû4�²?daŸl¢@WðN@/ßnUhÏ¥„îÂélú§ÑhìºÀ.\;ûëšLûߎ¡ù;u»[ùN»Û~B!„øç1MMÝA»(°f0™ñ¸\]Xó8]4ÍäØ èèÐ5Ý�®;›þÓœèšMs yh;šçк€6“ÀšBá É\tÿmlZóÓË YžQ‚Ö§)(¦ÆaXćälÉ$«zq;2XY§¥ÒÓCÚÀ ˜žIÆC#×°b£%t0Ã{6WÂNV4…/69P#Góè‹÷pjôž‘*ײ ¾ûý�µýtp:š*4ÅjÁÒκS5Z0›ÍíÕèõ«xçÅÙF á!õ”-~›gMaò‘_WPMÛÿÌ›í¥X±Ytì�v4|º¦ŠëÎ1j�t|ZÙ÷:ŽF;: X­íþN…B!Ä¡3™Ì]:Á€ÉlÆé°cµyuIú‡UmgPP?<ýºËP2B!öà¤2/ƒÙ?}É·++€±F¢: »»Ò“–ˆâZÏʵv¶¯Î ßca`Z_šF<3Ñ'¥6­�ŒÌíØ×¯"Ë¡0x(ýš>y¶°xi)F\ðŒ‰Þ»ù—NMI1 ¨Çôš2Êì­-à¡|{ †àPBþŽZI¯céÛ“ùº@#bÜ}L}òzkXüæK|»­í3˜‚¢((€îñ´:áŒV]EugEÖÔ0¢Ã €‡âÂ’V�ÝíÀá>Ä‹ 5œèpস¨dŸ‰ š¸))ÞŽ†‚)<²Å ±B!„âïâíãC]Mu—¥ïãçGmmM—¥_W[�ÍË»�kuùTh­’Ë]!„è–ܬþä1&¾ð6S^ÿž Ž/­Wo`Í6(f¢cÂ[œÜÍ š‚·ÞÀº¬,–¯ÈÆeìÍà�»Ÿ,Ù¤�lr“½:“ÌŒ,ªt/Ò‡ d×Tzu : °oÅáÎçç_²šÆ1ÛOÜFwo`EV+íÙ´m¬]_‹†J�^=±¸˜�@§zÑ›<ûc1zø©Üsý0B“'ðÀøž˜êVòæóß°¹sZ„c²Y0( Wí`Ç>(�ŠŒävVO bРh h”¬XÁæ}Òõ�=íFN=†“ïÿ…ÊV¾§6…ÜÔRFíÚN~kùwn`ifºb¢ï ä¿á;B!„{óñó§¦zG—¥ïëëOmuU—¥_[SMPph»ÖÑ÷óØ·«I`M!º%/޹èzšÁ•÷Nú”¥¥ÎV—t”,aêão± NG >ž³GúîÑ=ÏkÐPY5JÖLç�,jl ©-š†©AH‰Q±¯™Ë·«‹Ñ¬‘Ú"¢†¦n²3×ÓÐrãî2¼þ4_Õ„à§‚î¨fG+-Ó½šÙ}Éú=VÖ©ZôÓóÜ(Æ8N×å•’¾cS^šA1¡œ~Ûuã§ú]v'—ô4Ñ�9�'?ßÄAâ˜mbЉ#ÚZõr欮ß#på.žÅËŸ¬E3tV?IIcOg€UÁ³ù{þ;}ëepÏâƒ_¶âÁÌ€‘ƒ عYÅ`hšeÚSIye[šÏè}Ú °*¸ó~à­E{=t�óíüRª¡ú眓ÃåBC!„â0°Xm€B]µ*³Xm�&j» xWSµÕ`ÀÛ×ï Ëjš†Ý¾ó¾¾ç, ía·ÛÑ´Žu'‘1Ö„¢›²ô½Œ§îÜÆÝSæ±mÑTn_ö9Q½’éÛ#?›Š§±š²‚M¬ÙXL�Tÿ�\õèM·× üŠ_*#ú˜X˜¹˜%:„œ˜B|Ëá =H?,e~•ŽiÐP†úµHC�䤱)¼¿nÅÓŸäVûÙŒî탣<�•Î#Ã9‚GŸÊÌ[^`~c_¼ù ÚÐdŽ9¡?ÍÓ ¨Ñ#9NùŠ[®Ûȸ±CI RÙ‘»�ŸYN‰n$ê´«¹¨g×M€VÎﯼÊÌí6öfn=¦Åì™Ö~\y×ùÌ¿ã Ö}4™iC^áºäC�B�?‘Sû|NÎÚ¦?v;NE¿�¥ëùsÖJ,ç\É©3ßaz…ŽÞ ]BÕØs¸çê%ÜòæJ–¼z3W,<�c“C0ìÈá¯9‹É«ÿ´ÿã¶q»ƒ]Š_âU–––ðýó�Q?$ü‡qÿ‡³¿Ñ2ÔØ³¹ïêEÜôf &ßµ+Nç”�‘ø¸+É]1›_o¥ÁÎÉ·ßÈØ `M!„âp ‹ˆ¢¤°€¤¾ý»,ýÒ’b|ý;5ݲ’"CÚ´¬Ó餰°¨é…îݸAw t@�ÝתÛˆ��Ájmÿ=€Ö„¢Û27î>H>�/?û�‹Ö²uý2 ×·XDQñ íÍ '�ã_ãO'%¸•ÓºÊ�!ñVeãV¼”Ö‡=çî1Ñ/¥¶þ¤^3’4|ð^ãb©DŸ}?O”>ó_¯bío²ö7PTiçðÔ}ÿÇñn"&üÆšiYdÿü&Ï­ºˆ7Fõ§ï®|Ærñ.$é•)|øþëÔkMO’siÜȃ×�Ä¿Kc0%3_aʼ Í�7·«ÕV3ۀ˹ÿüÅÜòe?ûÃÞº�ÔCéǨö`üÃ÷SöÌë|¿f3ó¾ÙÌ<T[$#&<Í#¬|6O݉ÃÙ­šéuñ¼ò!¯¾÷3K—ýÂ'KT[C.¼’;¯MÏ–Cä™2áºSXòÂlݲ�ï·(XÒã¸ê2öX3‰?ÉÛ;·³dÖg¬ÿcçGŠ™à¾c¸òÚk™08DZ« !„BF>~þTn/¥|{)!¡á�ž¾_@ e%ET–o'(¤}Ý6÷§r{º®·)=]×qº\”••a0h¨]‹oÀh0£R‡™x0Õ¢Zë0Zk0;ê±:í8��¸œ,f7õ5Ũeee„‡‡a±XP”öݘ(!W=¯£4µØúêõ\x}æJÒGŒjׄâh³rñ|’¥w~º‹ºíÅWÖÒàÐP,>†Ed¥‹Ûzí¢5n'Kµš™€¨ÄZöèvêi¬¢ÊaÁß߆Qçü§8ý‘Y4F�çݯ§¿œÕEäo«Änô!¼GÂlÿôð‹Fýö¶–Öâ2ùC°µ«Ë즶d…õ¸-�Äôˆ$À¼ÿ O}[KêÁ+�ÈðÚž=7u%l¯Ã©Z ŠŠ%:Ð*5!„BˆnÂåt°%'›Øž‰øø¼ke{9ì�äe¯§gïä�ÝO-­ÜìõÄÄ%âåݶ‰ ìv;……E,þý?f‡ªAQhîÒüøZß5c¨¾û�è:±ÉãrÒ}íýVnÔ IDATj±ÖãÖ7hŽ¥u¸ÅZcC}GWÝ¥å �‘ž¢cŽæßbg—½ý3×´ƒbÂ'¬½Âºn£ÚBIHÞÿÓ#ƒ-€àýÔ§Íu™Ù?Š^þQ]�»îJÅ;4Žì¶.`Ä7"ž¾m[ÚàFBbǶã‘@r·#„B!þ^&³…˜ø 6矄OÆ-k‹ÕFdL›s²éÙ«fKdžSq:ìlÎÉ&$,²ÍA5³ÙLttãÆOÁn —³õq©÷Çd6cµza³Ù0›Í_¡¬uöÍc—ÞŒ !Úìhþ-ÍeB!„Bü3Ù¼|ˆ‰ëIÁæ\B#£:½[h@P0º®“›½ž¸ž½ðòöi×ú õõäçeÖî.¥ªªbµZ±X,@@‹–imÓÜí³½Ý?[’1Ö„B!„B!þÁl^>Ä'õ¦¨ ŸªŠr£cðõõï´ôƒC0�lÍÝ„_`á‘ÑŒ9yÜnJ‹ ©®®$<*¿C˜¡3d%�5!„B!„Bˆ8“ÙB\boêjª).ØJ‘®ãˆ·Ÿf““ÙŒªv|ôf?ÿ¼û ¤´¨��ë2ññõ' 0‹Õ†ÑÔÔÍÒírbol ºªŠºÚ*|ýIêÓE=rGé•ÀšBˆ.cJ¿†wþ7ÍH¬Ô8B!„Bv>~þøøùã´Û©©©b{q1n· —Ó‰¦y:m;Õ;*¨ÞQÑôBiúŸŠ‚ÉlÆ? �ˆ>P ×4l]Gns„BtÅ;œÄÄΟÚ[!„BqhÌV+!Ö8Œ“£ý¹mí„B!„B!„8Œ$°&„B!„B!DH`M!„B!„Bˆ�ÀšB!„B!„ �5!„B!„B!:@fB!„ø›èº~¸³ „Bü­EéÐzRg�:z¼NXB!„èBÍ7-oäfA!Ä?]s€D×õ]ÿ>XÐDêÌ£WGŽ—îBkB!„]D×ut]§®¶šåÛ±76¢ižÃ�-!„âo¡ª¬6/CBññõö,‘:S´çxéN$°&„BÑšoÊËŠ©«©&2¦þÁŒrù%„âèàq»©®ª ¨`+öÆzBÂ"�}ƒ%Rg hûñÒÝÈQ*„BÑÉv=u¯©¢®¦šÞýRÐu§Ë NÇáΞBñ÷P||èÓ?�ìu«°Z½ðñóßùÑî®Rg  MÇKw$�5!„Bˆ. ë:;**ˆˆŽÃívÉ1B!Ž>ºŽ[ÓP…ˆè8¶—ãíë×j‹5©3E[�—îF=ÜB!„ø§ÑuMÓ°76àåå%7B!Žjº®cóòÆÑX�¦iûLN u¦hé@ÇKw$�5!„BˆNÔrF3Mó wó§¬B!ÄßAQ<-‚$Í]@›ÿ-u¦h©µã¥»’® B!„]I×w„BˆÃ®M�©3ÅNÝ9�¶7 ¬ !„Bt¡#èºP!„8¬¤ÎG"é *„BÑÉŽ¤§¬B!Äßmï1Ö„8�î~ŒH`M!„B!„Bˆ�® B!„]ª{?eB!º©3E×Ñ4�M9ÙdoÚ„ÛíB×!44„ýÐát%°&„¢ 8©)¯Á¡XñöÁ|¸³#š8k)¯±£¼ ôþç\t÷rÉ=‘ÁYKy�Ý`ëÚãÈYGE�­;ž»sÞ§¿ëØBH�y0r>:$ΟGu] i)iø€6n`úÏ?�ÇñÇ�Ø¡tå{BˆîJo 8oUnŸÈDbýöß{ß]µ�ÜÒz4 øG÷$Êçðöô×ò¿äÖ«Þ#¯Ï |öúÅÄ(ÍeÙûjIAU ˜m~‡ãg– Z¥·¾ÿT f+¾¡„Z1$ç¢)\0i.®èñ¼3ízüC®º{¹Ú}� 7P’WÈ�‚oDObðÛÐëJØTTƒGñ!&1 ß#ög¤ã¨ÜÂú�ù–UQçÒ0˜¼ð ‰$¾W’¬]:†‰sñ«\ôø\\QóÖû×Ò¿‹Ž#WÖT®¼ÿgvøŸÁ‹ŸßÁ0S×lg[6n$g[;ܨf/¢IêÓ›¸€ÖCf[ÞŽ0Î¥¯sÉ¤ÙØéØÐ¨-Σ°VÇÔƒøKggSˆ„Ž×™û[SÁ`´àãBx°×A¯•º»Î9�rrs(,ÞÆYg�‹ŽèX,6FIJJ ¿ÿ>“?ÿšÇñÇžÐî´åkBˆîÊ�Å{w<Ì�5FŽ}ðk&ŸæƒÒÚbųxâÎç˜Y¢<ò6^{<éoÏêž4¶¯XÁf��˜ô4"UÀÕ\–ýO¡®¼ˆè;œÓοŒËNIÀ»µÂv4G ÛÙV¡ޝ±íŸuîƒì?EÅìIßô‘Œwg ‹Æ«µý§¨UMUQ:qÿvݾ\í¼Mp¯áý»á§#ÇÞÿ9Ï�Úúo¿™kõûÜüèlL£øÏ÷�pŠõ�2ÛaZC9…‘aíü-é4äÍâo}Ìô•Å4hûî/Eµ6àT®¹õjNO´pt˜ÁØt�¨ÊžyèxÙZ¡ªMùWTÔ.hš¡Uoà§�¦ñÉo6hûlA1x“>–_}§÷öÝ3XÙÅy;bµØ/JGö‹³˜ùÓ^ä…¯²¨p«ôºò þwyƒ/D×èh�¹ÿkLK`CO9—+/CòAZu[‡z>:ŠmÊÍ&¹_?6fo`ùÒå RSÓHMMcô)£ùð£6xV«­]iw×[!„m •Íç¹{_`f‰FÐð[xå±³I8Ü}wô:V.߈K fð�ø½nT‚ûŽ`PøîwuÍMcu 9Ùù”¬�Ãûë±0ï9Þ¸v`'×<ä~þW~êÍ­½Ì%‘j?ëŽöÝG=;J ÈÛZDæÜ¯Éœ÷¥Oàá‡þÍð�=÷¾ùø‰Ìš=ñïÎt—ûç•KAÝyì+j~Ê΋lÔ® 8µ‰‡Ü/æêϼ¹eÚd.Žhûoɾáîº÷c²êulÑéœ3öR"ñ·*¸ëÊÉ߸Œ?~û‹M™Óyæ®|j^~šK:¿)•ùøG™ÿ×ã ¹pØ�ì¾EëxÙþ^: ›¾gÒÄ©,ÚîBW,„ôJgdz/¢½08wP°a% —çP°ì;žY½ˆÅ·?ÉÄÓ{ m§ºŠN}Î ^}þm~Ém„öü®…mÔ\gª„$CJľ!�£†²üMdå²à«—XòçrxéN‹”ðöѤ¼¼œ~ýûQ][ņu8mìéøùúòëï¿b³ÙH˜JBB<6n$5%µ]iK`M!ŽPZåb^¼ïi~Úæ&`È�¼üع$v‡»#û–f9Q|RÖgï›_#}Ï{€§[i}§ÕåòãäGx~n Ù_½Ë�g¾Ì%Q�p«×°~}!½Û÷Y·´ÿýç®ÊeÁ�óö'²yÅGÜ{G%O½z£‚ºkà(ÒÞÊ{/°õõ½þ}8`ë5lÜPˆFߦPm̓VÊOï~Éšzðz+ï>w &7š¦£ë€¢ Œ9‡+/]Äs·NäÛüLÞ{ûwNzjá�}h»í4º[y¿£eÛŸ.ú¾´²Y<õðÛ,*×QC‡sÝÄûø÷ÐPL ]×Ñ•¦®÷®²Å¼ÿä3üoe s^y’ð¨W¸e�­KóvÄëÐ~Ñ(üýYîœ2�"=‚ãoxˆ�+çõ%Ù·BH‡ëL#É<È3§ùîû�IQP7¥Ë>æ±ÇßgY韼ôJ:iO�ÞùuIW“ót‡9ìvL&3�özìöB‚CðõõåøãNàÏùó40•¸¸Ö­]#�5!„8èÕ+xýþÿðíf~é×2å?Ðë -–µÆR6f®#§¤ŠFÍL@DO¦ö!ÒÖâŠB·Sºy+•.¯°xâ÷Ó*¤ÅrÞá ôØ]�¸6.'£NÇ2b0)íè’¦ú$rÖ�1cÁk¬tå°6ÇQ»#…ZM›ŠkÑ­!$ÄïÛÂB«e[Nµº•Ðø8B,:õ%¹T¬eÑF7ºn§4o#ëk X‚bó±­ÕÏbIݳ«™»z+™™ÙZVƒ]±àÖƒä�ÉÄûï»ôº"² kÁ+‚¤X º�’u+Y™SB�f! ª7éi½éä–…Æ€DNü÷£ ö%Üû.Ë ~á©)ùøñ1„¨{æM7Š�FʶPáT°…ŸŸLéõçRåi}¼¿6[ÍIÕ‘]´{ÿ¸KÖ°`yÕ¶>œtr2�;w¼î¬$oÝrK*ipªXüBèÑ«}£}öé>µO¹Zi r8¿ÃŽ\óî}ÝÜže[[Þ]½•¬¬l¶n¯Å¡Xð�¥ï€¾ÄµRþ]i9+É[ŸÍæ’Jê]*V¿`b“’éÕò;Щ/Íc[Å:g»ÑõFJò²Y_mÀKBˆõÀ­èXµÁ�®úsüÅãˆÑq8÷^È>ƒ¹é¦³Ø0­€Èh•.3×Q”SL�n&4.Žà½O ŽJ¶ä—cÇD`l<á{žj¶å•R‡ 1øÛ‹ÙTT‹n ".>«Ò¾²¹ªòÉÊʦ ¢·9€}‘Ò3hŸ v}?ÍǺn§t}¹%ÔiV¢z“–’Hp{ÎzsÞy‡?Ë5”€áÜóêSœ©ãj´ãØ{Yÿt®yîY¸ùV¦nÌgúó¸xÀi„ª�‘7�ƲÖ¬ßBaenƒ•€°8ú êC”W+烺¦}ŽW8‰1M¿µÒõ«ÈÈ-nÚ^d/RS“öù­ut½=rÚXFvÖ:rK«hÔ,„'0 ¥7­�·öúwÛ~ÓŠÖgQ9†û'ÝÉù=íLÏèH:B]¥ÎÔ=Nû~ë�€”Ëxâ†u\ðÌ"VÍcQåiœ²ïÒí9?ì^ÉNiNk7—S§{Ù{)=1ã¤"?Ÿí1 Dì«C«)"§¤ÝLü~®k s‹©Õ-„ÄÅÑ<,ãÁÏGí<×±©¸n×ùÔ]º–¿V4]—�xbß]×eÿ$š¦áñh MW3a!¡466àñx0›Ì446¶;M ¬ !ÄF¯Íâ�ãól'~©W1å©‹éëu€´*2¾˜ÂóþÅ–=ÆÛQP½b9éÊ{¸ïâø+nÖ~|?gÕâ}ÒÃ|3é$üZ©Pµ¢y亷ÈÔâ¸ê­w¹n×ìÔò–¯b»ndÐà|ÛY«~ø«  bØ£«ŒNýÂÿrí3‹Ð’®dÚ»—“¸÷µAãb^¹ùæ{¸úÝw¸6ÑÃê÷ïæîßjw–9‡Ïº™ÏP‰?™Ûª'q_«Ÿ½Âg7õoª �EÌžú/—I™s¯‰Ì!¤�{ ^{<±-nÞ\™rËC3±º™Ï&õä×'žbÚªJÜ-îXÍ#¹õéG¸¨Ó›*x÷¹ˆI·¬åÒgPõ×§|½é$nèÓTÝ»VL庖ƒüÌ-¶×ÑõšvV«¾|�ÉŸ,$ŸóV 'þûNÿç­½vàþ>Ø‹JÔ‰÷1íÖáÄœ8]î½Ö”°š­ëº:S÷8ñîÓ�XÃ"6xÊ)­ð@Ëa3:x~pÏçµ'_ã»�Õì:ý)f"†_Ƥ{RXðè]|RÈùÏÀ]i&@§~ñ[ÜðÜb´¤Ëùß›—¶r]»„×n{žžþï­ÿruÏÖº­îuVéÈy8s7Ošƒ{ÐM|pMOÝÿëtÔðsIÕ‡ÀdÄHA×u<ž¦ŠÒl¶àtºðxÜ(ª‚]kBñϦ7¬gÚÙ¶¶ïA—3ùé ôku”úæêYùö½ÜõE.N¯žŒ½vãÒzà¯ï où/|ôÅ|f½ùÛÝ/óÚ¥IXŽ9ãBçL§lÉLæVžÈÙÁûtÚ¤pþ<Ö»Á”<–S“Z^�”²|e!C†¤‡¶{?ûÆ5d»tK2)½µŠ2’8îLXÊ'ïÌ"ŸhF_=žaþ¼{�äÜßgÑ;»{U2wòÝ<2³ ݧg]5žÑƒ¢  –­™³øø“™¬üêIn¯{Œ÷î;†€æ±sŒ&Œ èu¹|ñä'ÌvËuŒ O¨™ÆâÕüðáW,.YÄë“¿cè/!¾Ó» ¨„œx!§¾·�/‹·1ïÏ<®íÓ»õA²FŒ‰ÿ¼™T/�ËâºQœâ³÷BræþIžGÁ<`4câš›¿µóØjÞ¤ÙŒIgc>ß¾3“<¿�Œ>%¯¾ª:Uó¦pÏ«³©´öàøKÏcô€,nêŠ7²àÇïù5ã &N´ðö›WÐ÷`Ãl±ßa'Ñw0oÊý<öûvtßÞœsí¿85-–jÈϘɴ�~#ã›g¹³ÞÄ»w�ØY~�ªù¯qÿës¨´Æqâ2v`,�7µEøóûoøyÕWLšdæ�×þM“‘¤³ï`b¯%|ôæL¶ÃØë.ex€ƒŸ¬ ôŽ5ðgn5ó>ýš³ú^B?ŸÖÏiºÇ�½åµ®¡#‡†óAn YYy¸�ë×âÂÖņUkiPÌXŒ.Ö¯^‡}ܱìnØ«Q”¹†M%`ðHú™ugnÃÎ\ʦW±ð•ûyä×b´ �\pÉY“;r˜÷Õ§ü”õ “îsðüë73t¯' б‚_ž}ŠÅ®QÜ8ñ8’ÃLÔo[Á7|Å’’…¼>åÒ_¹ˆ¸ƒîD�ŠåKYïÒQlƒ9ç”`´V&€Ø“SÜÆ(ž]AµCÈ›VÄwOMâíõ˜bŽáªËÆ1$>³£œì¿¾á½oV3ë�Ç0†¾ÁÄãv8““� ›ùêÙϘãÅ��%9ÌLCQß½ÿ9 K–ðÆKß3äÕ‹wm¯£ë¡×“1õAîý2§w"§Ýpg ‰Ç_¯$wÉO|ðé\f¿3‘ížÉ¼È˜êBt7+W¯fÕªÌ6-›–šBZÊ .ÎQçñÔÖR§ª ï–×Ð=?87ðÞ¤çù6×…9j$ÿºâl†ÇZ©É]È—~̃Ïm¥£˜°ZvoOiQç´zšWÔ�ïïwõ€:z¶X±(àrlãû©¿³Ù/…±c{àÕ—¶Ž&r¸�—• ÞâÏŸ&áríÓä}7¼’&îzár6òê¤ 9æ|FŸ7UUq¹\ Ú� ¬ !Ä‘¢1‡Ïy˜wV×ãÕÿ2&?ýodtwö—¼øucãŸz™ÛÓv�ÍÕwÀPŽéõWNü�¬�¦2cìÓœªbM9�ÓbfÚÖ ~�S™FîYák…Ì™›� CN=™Ø–=I«V²4Ç�šÊ�íˆ6xêÈ_þ3o¼üEºÉ®â´°C�V¨„§ŒáÌÈz~›:‹|pò8ÎÞ5AÁ�>ÇêOyí÷R4C<žz‰[S¼ví»>ýÓÑËÌU÷NgÛŒwøìÜaܸ³Uª‚ xòfò[úM¼óòù-&”ÊðÈ:&Ü3�’M YTz1ñ]1a‚¹7CxñUq=…Ù›¨Ñ{ï·)¿÷àÑœôßW,cö²:N>i¯ñÛ<›øcîV<Š…ÁcN$zgv;rl 1Ú¶9ü}¯¼w ƒvÇuÌøc•𑾗ý‡g.íÑâØÎIc†zã|¾}) r/£oß:Üm¾ÃCc­½ýÅZ,ïÈü‚7þ(C3$pÙs¯pK?𦡣�Ð+•á½-\yçwÌü_œ5„ë{�z–Í^L¥f$ùЧxvBšG4˜Æ '캛ù¤| sÿEŸ>Bû�Èéa5üòöL¶Ä€ÆpFdSË2ÏÁ±ŠM×aÐ`†GÛ™pÇ·nZÂ’Ò ˆ;èd ¶änÆ­ƒ!a ýlzÛŽ�›}†”ë`Þ<ã›Uuh†D.ò?\“@Ó8yôf@úPâœWrë÷¥Ìýa7Œ<“æÓ M¿µÜ™Ì|+ï½v±ŠgçöÒQÇø;¿£8g)KJ/ܽ/:¸ž;û^þf3c<ÿzö5ndAóhèÄ’Øg0#{Û¸ü�_XóÉûÌýÎ ieß·ã7©»[´RkïØ‰BFª¢²*+‹•«¸ÜàôT§§uîñÜ•u¦^Ëò_çS¤�>€A»ûÀwìü Sýç—|“ç¯tn{ùi. ךnôOãøcûðà5O3w‡ŠÚÔÍ~W¿Õƒä»-åjñ~ÇÏû¯ËfE_À^Ë›Ž®{p;Ýô9 ‡ùxþšñ$wNz«O4´¼ŠÕ›v¸ŽBÙö*>þ&ŸââbÎFTƒ™+ny�_}„´Q÷`4pºœ€ŽËåB×u”vL5/�5!„8èŽ-|ûŸÇymEšÀ�óÎbàAûYºX3ów6»ÁvÌx®HÝ{À{…€‘ã9·×¼•½Š Ê9ó¼0Tc/Æ�Þ›OßÞ@ÖŒYäŸ -î-´‚?™½É ^Ã9ãÄ=[¥5¬^Á§‚êú¶ZøXþúÿqö»-+=7 µ54¸Tü†séÃWò£iß$×�ÍɪYó(ÖÌiç2a ×>ûÎ7ý|Îìõ on,dî¼®ëÓw�VaºÁWœ¹Ï,­¶~©ô·üH‰c;E¥tÉL¤&Â#BP©C«¬ RgÿcdX1öÄ0¦]Ê’y˨;ñ¤=ºðº7ÌeÎ6Šm8§ý?{÷^E•>pü;s{z…„z %�ÐA”jwuíìZ@ÑõgY{î»v±+k_×ÞP•*"�@Uj �„ô[gæ÷GH¹é@¾Ÿûø„;åÌ™¹ç̼sʨÊóÝÌk«ü+@wÂÀ+.«ÖË(*öa `6û¹€l½¸næl¦©�ɳ¶s�fßAzYþÒß9ûµ~ë^GÞ­VîÍú‹Ë�à_¸¤‡‚Çë=²ŽæÃÚ÷|Îé1‹W7g±xÉv®íÑ“¤â(>\ϑ߸>:1åÝyÜh6ð:Ëðê†æE×*÷k k¼ÞÆ_ס§ÞÁ+÷9xøåÙlÎß¼Ϸ0ïsP,AÄvM"%¹?ƒ‡eXßx‚kÄRÍIƒH üžŸw¦“^ðW:FTŒ]s �5{ Â&�Æx{ß•κ½ý+ 3Wk7{À–ʰ~VŒjgÉ8œ�õ›— ³Wƒ€S.à¼8î*YŒ9‰ ¯½_ºNX{ lTy¦Rb9ûÚ3‰ÕœG‚zš¥{ Iö¯Érå’�«aÄ4TÖ»8t¨Kt4‘J󝏿¦Mér1Ï¿7–C…:Ä{ñT½Ô4…¤Á}p|›ƒ3s™ºqdÜÇÃû‹áì«'«¹ªï¯G2}lß�í®¾¿æ­çeÃ/óÊË­S.crož* Õ4ŽAsA�ŸxmË:~^z�3Ï-/óü]ÍÏ]*¶Ñüó$ı–Ú?³ÅÂÛï¼Çê5ký.30uS¯¹šä>I‡»Ô -ûeÔñËÒ]äíÞÀ¯ÞcæÜlt5˜aW\@?såÒÍ-\¤­XG™¡4â|&F¹�”šBGqÃÅ_±äÍ�x©ú˯^ç4\Y¢®ò¨Ùå°b”ß—•) ž| ÝMN\µç¬_k^/^· [p?víÎdç®l’ûv!22¤"Ʀ íÛ2ndlY�I±pæØ$tì@xDA�À„×ëÆår¡(ŠÖ„âäã#ãÝY^PL`xžC,~á>Hü7Wõ¬'ü¤ç²aÓAtLtJîë¼5Žä>¨[°%㼴ÆJ¸I¤¾¿™åÛaÎÖK¹ñp”Lg×ÂEüáS 3�SênÔÆUé8±1xPŸZvWÒ¼NÊôªëéh:`hgeðÛ�ß9™‹R£ëméØÓsØ´¥•ø¾½ý7…Wcé�Šº%�ìmÛ)2ªðªØºÓ¯‡Ÿ\0ìPÀíÂí9V�U &syÂÐõÞ6ZI>c4ñ_BæÊ…,+͸Ñ5/ —�¥«„ ä|7ûÚªÂ܃�É�Õƒ]j}zÇ`Z—E2(` IDATIƇ�ó´} —ŸžBb•hŠÚ¨ 'Á90ð:‹)lúP ïgËÖòãOèÛƒ`£v: #Š^½ÃP7$û��å-Õpúö‰Å”¶‡ >Ås–«¸tt2 ‡Ï�†Ï]Н‰7Ýõ1| ñcoçýÑW²zþ\~^¼Œei[È.)aßæ•ìÛ¼’9ŸÍÄÝ�IW^Ë”I= ­<Ÿ¶> íkãçe›IÛäæì‘vÀ xý:¶úl KéE/[?_LÚ†|&wŽB¼ÛÖ³®,)ƒI­Õý¹‘ô\¶lÍCÇDb�.Økµ60ˆsw�4/žý{/úu2¨ÝKÐQ~}¹Ü¸½�¸¾ �Êg“õèÜÚ75mŠ5ˆ˜¸bã�Šéòùðé:.ÊM§Çƒ¿ŸŒbëIß.øÙ_ Á ¸ýçE“ÖÓsÙ´¥¼Üêܯ~ FCoGß>‘¨›sÙ¶iÞs£[ØTˆ“¦i$÷éÍÔk®¨,9–A’æóòÛÓeôÓ~¾2Œò­€b‰fèUÓyììv•årsË}?»ö¸00ѹg',5 #C#vè0:ÏÜÈÖcÜ%¼¥å0枤ö¶àçv¡AmázÑ�:uE§®@Ç0|€�Qy@†AŸ¾]éÓ—ò  ûrð¹K1™L(Š‚¦élß¾ƒ^½’¿YAkBÑæéô½ø¹º3«»™§~ËàíéÏÿò}Œ­«Ë¤žGîÁòZ|×pÅ�þ—ó``à>x€"¢UP#Gqî𙬜¿—Ÿæfpm¯”ò‡ móíħF1fÒàêÝû¶±<­ÃÒŸ!ýk¶ªdaèmŸðìÄ-œ /%ûÿ`żÏxëØqÇï¬ýç‹g?,]Ǧ]ûÈ+rã­ñpz¸+l�í*Ž@š´¿f¬§p ¢ÜÚùùƒü}¶ÿLòÂÀÀ•w�"­z¹uxƒÍ)¼¥+¨8Áh>�äÞ½™zõU˜L&V¬\T ’ôNBóƒ I º‚ÚÃÚUsæNOÙ‹ÑÕ(†^~=WŸ?šÔhðxªLÎÓÜòA/¦ °¢ˆñ_×FÇgRÊk�èÒéï¸üþ]k½–Ãö"íuì§Zíz©à.^‹jüŽÍ‘„Osâ,ù·³—³—»—³·«—«—« ›ÕC§.£1Œòó®ª $44˜U«VÁøIMÚ¿Ö„¢Í3ÓûÚyåÊNØ€ØûdçÍ÷ð¿í xòÁ8Ú½pÉþ"'Fe3ðò®Z^oOZQÄ€9ÔÌáêN f䙣ˆZ8‹Ü…sY55…‘ íXÌü]¦¸Ó9;¹ú{|=s «rtL]SÐØÑNïÏBPL§_ñ }ÂàÊg–±ä�·˜wÊÃLkáb³xñV >d±˜ëœ¶Ýd)¯F Ÿ�Ú�)Zq~r=�í;¡£�¿a‚ª1uaÜÝø`æVV.\NÑc UÀ½a‹suÔv§2q`•[rmUPÌVÌ~VSûpÍóï0bÁ÷|=wKÖíd_ÆR²2–òÝG¯Úí ¦Þ~&Õì~ZÓ ~+S`øðzÜõ¦Äç÷&ØwxVH‹ÙÔ¨ã¯ÜŽaéÎß_ø€SÎâË9óY¼vÙ›–1kÓ2fýïMB»Žáš[¦qA¯†ÎA:š×�æP‰ëèÄÆœwoá‹gâ…ûØ5ëM>÷S{˜…¨þélZÇŽô öê½é¤ogÍú”¸dR" 7ý;šX™±�MžQ 2ç±~]&º)žaÛ7ÿ •½kM¦ºó¸ž 4«e@m&ÚÇD¡°ßž]djлÅwøMK›Q¸–Wïy„Ïþp�-Š^©§0">Ї³ÙŒ’³”ÿÎÙŒ«þ]67©�\ÎWQ&º¯¯Ž‚1 šø0‡Z%ö%þôŽ´DºúpK£ÃA’6ÓR­’…A7þ‡çÏ ®^»6òêÔ›xoG>™�t Ók·6onù`xñTÜk˜Õ: ^ÕŠÝÔñ’åhii9¬˜--µúõbh‡?ŠáÃ0<å݃¡»Ñ+?š ]«>ÑÁ�AƒÉXŸŽ¦é 8¸É»–ÀšB´y*aQQ‡»V*A)Üøè?Ø}Ó‹ü¶å¿Ü÷d,o>2‘¸šã¸+v€| ý®žÁKçE6éÁÏ>`"ãgóÁÞߘ³¼„cl[¸ˆÝº™®ãÆ‘T­Ÿ¦Nîš5ìÒTb  )óÔ<Öv#O¥ï Ëø½$�•›|LÞÈ¡ºî§;P3)vìq$·Ó��¿‚�Û黽v žV¤ç.eÁ&(6’$ÕÙ-÷•ŽcN§÷û[I_½˜ß‹Î`b¨›´y¿q@7?f<)U7ÒÂk«A¦0z�½’{Ç^‰áÎg{újV¬XÊÏ?-eó¶ŸxþÎB,o?Áyõ�mÖ¦Îa ^¿7¢yŒáï/ņ£"öír¹1ð׊TÇUåøí•¯Ú ^�…N§]ÊÝg\É}¾¶¯[ɲe¿1wî¯lúã^º¯ËksÎá�õ›–憺ŽO÷•?ŒX;ò—»ÿɶô»øú@kÖå ÷è€ (RóÛv¥“Qx!‰ëX{ÂÏL¦£b1¤ô‹„oÓY·ÛÇÀ˜�¬ÝêC‰Ä�ÄÚ9èÿxü›bÃn+ÿ7§Ë…N@“gBn8Ÿ“—*�û&¬î¥0{%¿ïú½»Õ?±Gù¦]–˜ ®«ŒmlÚ<¬ÿxŸÿáF��À£/ßÅ„SÅÄàYu€/¬| «k»ÍÍ‹F®§Ø pXH¾öu^¹ �rKsãrÕž1õèD�ÆoDˆãCÓ|ôîÙ�©Wÿ€ä޽дZSŸEͯ3 _ÎR¥úo[éÌä[Ïgþ­_°gÎ˼>r·ªqOÐÜòA·`«(BÝn'àglw1Ň߀øÿýûkò\õ¾¶¡òïx•à ;þ×K¥–¥½oŸ~ôíÓ¯Ùë·Õ â…BÔÃOÿ ]-—Ìàž7Ó(®YŸ˜bˆogFÁGö¾ýµZ 5¼“žœ9±;£„e VRìÝÊüE{Ñ-Iœ9®cõ Ä(aÍê­x•pêJ#éÁ‹ÓUyK¡ (å7J†¦¡ù»ÿ(, ðhEÖÔöĵ7>²÷åÔ‘w>r²”Þ>¶vw¡Öb³ìƒÏIs¨¡#9{dh£‚^jì(&ôµ‚s5 Vc¸ÖñËÒC覎Œ×£ú›¸–^[M Ø"è6h—ßøï|ðu4c¯æëy{뤶¡sh4ãÓÔõk-¯¶§CÌ‘ã÷ù]O«rü1D©U¿3Ð|nÜÎRʼVâú�ââ¦óÞŸåâNfŒâµ|·0 ÍOœòv®cÁì/ùzm~µmÕú%œ³°9Ý.÷ªQ;1hPŠwk7»8°a»5;ýúwÇ ˜èžÒ‡=‹´Œƒ¸¶¬'Ý¥>x=L�Ëw¿Ç¦¶#.ÆhdïÍñ›~ÝçÁí3jý{CyÕÔóoKÅÈ0´ÝÌúl)ùFCë”®{�.¿š̘Ï.o Ò¦íaÅš\tÌô»ø*F…{(s:q»]¸ÝnܳöQjøßnsó¢Éë™ÚS^níËÜEqi eõ}\^êê¹Õœßtó'ò‘Oë4M£_ŸÞôëÓŸ¦µh[ ié6k}ohXzÿ�ÛÎj�¢åðýËï³²¤F¹ÜÜòA #*\tòò[xwog§¯fú¨r_ë3üäyQzÍõê8Þc\·åëåˆã¼«[[y BÑ$ Á©Syêÿ†®¸Øöù£LÿvOõVæJ8)ý;bBgߊåìð[ßèÜ´œ´½%~*‰ã'’j‡ÒU Y¼r ²t&0®fK!W:+ÒÝÐ�Á}nU7ƒ‚•ËØèÔX:& çX6L ‡8T+±:ykW³½�O}tµïÔ(RúuÀ„NÎêÕìö·]ÏfV¬/ÃP,ôJNjåYL+N¶|þ�ÏÉAW¤\1™Sœ=¶‚Íè±ýqàbõokÉ_·„¥–^ã˜Ð¹F¨´Å×VÜylOû•ÙKwúíª „$3fP$ :‡ò5XkCç°%w’Í]^‰ 99®âøÓØã/²æÙªõ¥Š…¤ä$làÎgǺ¥Ìý}î#O%è>/^——¹£E•ŸƒüBt?i0}œ>6|ò¿ð^~c[Üõ/ol&}¯Š•¸øö¨Gžˆè=¨?AF›26²fÍ6¼æž ìm;¼®µW2I[×g�¾~F ©ƒ“076ßý›F¿äøò<^“Æ®Zy¬±í£›™pæÙL¸.ùz�}Ôw~³LÕ¼±¥rù…=°):y‹Þà_ßV=µ?¾ì…<óì÷ìu"Ëé ÜÔ‚´é.ÊJ @!<4½æ“¥ws礗–Ýœãô·LsÖ#”ä”NåÖJvzý­§“·y%ë÷–”¿ÀiÉoò(œWùȧ-}4ŸV>FVK·Õ�–l³Žï Í kobB´‚–=‡ÞM£´Zä¼™åƒÒž.�ƒPÑØ™±¹<Vmió#[¯�¾Ã÷µ‡QX«þÐÉO[sä¾¶¡ã=Öåp[¾^§ýÏÑ ¬ !Ä ËBâ9÷ñÈ_:a3 Xöêt^\QP¥Ré4ál(h»¾â…O·QVc îݳxòÞû™6y/¯÷P“5šs†¡”­dæKóÈ"ˆá“N%¢F¬Æ»ykK ¬½SéßÌè„î<@ÆO¯r×K¿Q¨+ö;‹I]Žt,ñ‰3�^¸ŠëJ«Õµ¾ìy¼øß tSí ’b2•�å¥ås0_oäw&zL<‹¾vߎoycî¾ïÁÜüñÕ{ÌÞ¯£å¼ÓÛ·n…ê+!3íG^¿o*׿¶‚|ÃBìÿä¡‹›ÐzP!â”± €²´%|49‡ +)ãFWëàZ~mù£ç/âÙ;æ±Çžç£ÍÎÚ÷Sî�¬Ù��¡˜IHŒm ÏO°sxÔ)týì ¾³˜ùKv�ã÷°ý›�øq¿Ž2ŒóG—w{ÑóåÅûçɧfðñVçàV¦ça(f;u8œgŠÉ\çï¬n�Œ¼ì/tµ‚wçLìSVåú„Ƴ%ï>ù6KŠ Ô¨Ñœ;´úŒ²¶ÞƒH±ëädüÀ‚ .ÔÄd’«ÌD¡„ö&%AÅ•±˜o×g£Û“Þ·q/ê>6…ÎcÏ¢Ÿ]AÛùoþ�IÕÉR}9 ùhn&6’ORmbŒ£ÎPètÑ]LK FÕóYöú=ÜúÊ\2ÕÈO½„�‹ßãÎÛžgþ~KÂ9³—í¡ÌÔžÓo¹�ñ5#�ÇŒŸüÓ<Ræ)ŸZ]±D1ø’Ûyàê¡´oê¡C™8<˜_ç-æ‹y> ûP&Œnç7àÔâkËï6'0åüYüóó þsó5¬8u$CºÅbÑ)ËÏdý’,ÛãÃ’p>“ÇF7SÛÌ9lê�ž¿×ÑMY¾BÌ$î¾~)7¼¼šß^ü'7®ǘ>±úòÙ¹vsVdâ4Å0ö¶9=XG7@��Ä´¿üÈ-Ÿnâ½Û§±jÄpumO°EÇyh/–þÊòL–Ä ùû˜ÔŠý)ÁñtŠPY‘“Í·Ï?NÉ€ö2�)—¦îùG L].ã©;÷rÛ3óÉ\þ·¯þ‚Ø®=é™Mˆ]Ess sÛöS¢�–”Gn`¸Ã¨Þ%<°C{YX²n9Ë ˆ>½ U§gS;�’_¯dI��¥ÿ Ö—¯U·ê;¶˜³¸óúeüãåU¬xí6¦,;…á½"1ÚÎï‹W²³Â^ËÍ"Pü¶±ô—†¦žÿrºÇ%O= �?ÄëKsÈøîEnüámbºt!!2³·ˆ};¶±û�CQ Mºˆ¿žÁv�ßîõ�N›ÚŽQðNÆJ²gý›Ûœgrz·@Üy»X»d ë¼#xä™!̽á_,r¦ñù̯Ñöbè)I„Ô¹í¦äEÖ‹Ë�7/gÚ¿—�öî\½v4cu$ÂìáàÎ4.Jc¯ËBâ97su²ϦWÇo¬Fþ/òf8�ÿÜ: {íÍñ'tŒêLÃGØè¸ñçµ<µ,‹o_ù€Q/_Oÿ€Šï›Y>8†\ÎÔÔßyvÕ.¾xpéC†Ð·�™¢�kY²ÞÅ Û®¢ç¯0·¬zúÔÄÓ˜ØëlÛ�ì'î ì’"-8s7³dá:\ˤ¹¯óÍAC¯z\~Ê£cZ·]�‡ììl Ãà †îŠ@[Ãt]gïÞ½t±‡àp4¿ï‚Ö„âDgIä‚ïcçMðÅî4^}ðE:¼|£"UÀLÂYÓ™õ ¯ÌüšÅk~àÝÕë)*Žè>œ}͵Üð—”Z­Ð*9LdBÜ>Ê4ˆ3�A5ÐsXµ6 ÍÇ  µú1pæ’SXåŸÕl'0<ž®Ýú0lÌ™\pF_¢jާ­&rÉýw“ûÔ+|³a'‹¾ÜÉ"TG,Ã.{’/³ó¿E žê³=YúqÙug°ü™_سk)ßìR°¥väš+øN±ÒõâÇy3êf¼óËçý�M¿T¦ÙJd¯q\5u*— Œ:Ž-�j矢š±:ÂIèÚ�ä�#Ö îàhædA ;‚°ù?’ïU >e£êŒŠ´üÚªE dà ÏñBÔÛ¼ñå"6ÌûŠõ¿þÕÑžþg]ÍõSÎ'¥Q]\ÛÆ9lémjSÃj‡ÿÖ!þ‚'˜õ/¾=‹ß|Îæùß)V¢’&2eÚõ\ÒÏ�Ï[qjXé{ý‹¼Üî-^ýlé ¿%}AåÔ€ö 8g*7^w6=mU2æ>\:mËþõ{v-绊ßÒß 0ê;UšNû±ðAïÑ|ö߯™ý[:{¶¬fß–*Ë(*íz2æôs¹ò² ôôà© RÂIÔÓÚ-ø” ’ûwC­–7*=’ûâøz!¥º™îCú®Ô.©–�õ›n�xÁã¼õ/¾5‹e«çòÉªŠ¼rÄ0øâ)Ü>eð ûÙ�¿¿ý¥¥q4¼æN\úÔ»Œüõ+>ür‹Ög‘½-�ìmÙ¤Úˆìy*οœÉ{¬¹ðÕç9ikæ=<™û$O~º†�?}ÌÆŸ@QĤþ…ÝwÃB\´¿"…ôw×±uÎLž]w!/�H"¸™ûkvê:íÆOçÝèϘñæ,Lû‘ÖV|§¨8¢ûqÎõSùÇy= ðúê|ŒmÌ9Ñu¹¹ì÷ÓðÍ[’Ïþ’#ÛŠ½Mîõ$ÄÉêXÖ™†ÎÄ›®bÎúWX³w6Ï8’ׯïK4¿|0ÚsÞc/âøÏë¼ûÓZ¶,ù‘-ª�ˆùò©iLNÙÆoTl¦Z½ËEÞOî/ñUú.~ýf¿VÜ׿âiºÄÄG Ëïk]^£ÁòèX–Ãm•ÇëåÀ�¨&3%눈9Å�ªº° `.Eµcvcqc÷ºñxœx<.,f÷!<^7¹òˆKpc·ÛQ”æÝA+Q×g1®ù¦XtXÝUB™§Æq[rX@wã,qU°þc;’Ç¥û÷’•W‚ÏA|b !Š·Û{¤á€ÙA`€Åðà,vúƒÐŒ-(‹ªã++ÆÕäñ˜T‹«ÅŠâ+$;k?ù%[0Q∠TðyÝxDEE=<ÞÚ‘àg�°¤(`:í;�cøÄ§HLHhr‹µÄÿ{�ÊXšÖ„â(k»�µæÐÉúê&ÏXoáãgÎ%F¢IBÔ«v`-©µ“€¢šP00tÝhø1^QUEEÁ(ÃD×ëøWÔŠ}èºÑ¬@�Rqã\1_Z£ÓzÌ5âØÕT‘v]k ¯ŽEAU*D ]«ä;êûSË|ê:o•³àµ…ó å×vez ý˜fŽ`ÇÖM ÖÚH�ÙÈòÁp�¹'“}…ôØ•pUãHáYÿ6“ïþ†ýöQ<üñ]Œö»9R?ëèºN‹ŠÈ¬nHÍë¥j`Í0 <N§—« ¯Çݤ¼3[,8�Øívl6Ûáë±±ªÖ¤+¨Bˆ:”núˆGg®Ç©và’¿�“ š'0Cךü&º<�Ö„} ½Å�›ƒw­¥Çfè~Z�µ&Ã@7Žcû£< X_zÚRþ†ŽQ_z…Z�-´Ýßpÿ­Ÿ“©Äsþ£ÏpËÀ�#Ãq¸vòåG¿�««:…�u4ˆjNý\wÂO¬r¸%EÁf³aµZ mr°°2H×ÜîŸUI`M!D5zîrþ÷MÙû3X²8ƒ¯•nßÁ”äæè)ÄŸÙÉr+„Bk'Z�iêu 7Oü�{fï囇ÿÁæa#�‚©$‡ Ë—’–íF Ê�×�$˜“'¨Õ–ÍYsI`M!D5Æ¡ |ÿɧìÔÊPyÅmÜ;9… Ö««„8±É]´BÑ8'Z�©0ìöW˜ÑéMÞøl1~ýžM€‚b� ç˜Ë˜2íR†‡ûðJÙ“–Ö„BTcê~¯|8Ž"ÍJDûv„Ú¤ÿ§-s¢=%!„­åD«3 |;ý.º›™—߃+/—Üb7†5˜¨èH‚Tn—¯ŒáxR“ÀšBˆêT;‘q‰D¶v:„B!„hót4wenPlÁ´s„”�eæ*¢´µ“&Ž ¬ !„Be­9·BÑÖU­'O¦:³|ÒƒÖNÅɧ­_#XB!„8FTÕ„¦iMžÂ]!„8Ùèº^o}(u¦¨ª¡ë¥-91R)„Bq²;p•IG!„Âå,Åî¬ó{©3EU ]/m‰Ö„B!Ž¢ªÓ¾‡„Gp(ÿ º.S� !„øóÒu�üƒ �¨VOJ�)ü©ëzi«$°&„Bq”)Š‚ªªÊmއ IDATá fëÆt å£i¾ÖNšBqÜhš�ÂCùlݘN@p0�A¨ªZkŒ5©34îzi‹dŒ5!„Bˆc òA!2ª=V‹•ƒ¹ûÈܽ]“Q�…Bü9¨&AÁÁÄwìLphx�A©34þzik$°&„Bq”UÞšL&BÂ" Ã0 €ÃÿB!NVU»ð©ªŠªª˜L¦j]@«.'uæŸ[c¯—¶HkB!„Ç@ÕUUÑu]„BüéTJ*$uµX©3Eã®—¶FkB!„Lj¿šAÞ¾ !„8ùùk•V_�DêÌ?·¦^/m‰Ö„B!Ž¡ª7‡•'Ê�¢BÑRM©ó¤Î'âù–ÀšB!Äqr"Þ, !„­AêLq¢P[;B!„B!„Bœˆ¤ÅšB!„B!Ä1"ãÄ5Þ‰ØRQkB!„B!„GQe0­jPMlu« ¨†!“!„B!„BüY†�a”rèà\N'º®µv²Úyô^.Sí:÷ePŸ6#¨;÷³eýFþÈ)À©[ ‹éB¿þ=‰uÝà¢V˜Å9%è8h×9±Öx�J‡ábÿÎ=ä{Úu¢cxw?U– lߙİ#ÕuóΗB!„8±þþ#‹óuL‰çò�ób1Ü|ßj¨ôºô*Îøîfïù™Ò¯ )µñ®y·¬am‰�mÄ@’�++¡ÌÅ€Cwáq7ë Ž¹¼ü|:%�“�Í€ä�µ¾ïÒ¹ Ï£sÇŽ•}J`M!Nx �=ÿÊC7epÅSK(øíc¾Ø6†i=Ë‹xïê™\çoò£”M߼ēÿYÀÅZõ—TŠ�˜pûÝ×pjLõªÂ(Lç£gŸã½%™”êU×RP8}ʽÜû—žúi‹®( žÝ?0ý¡×ø9ÓydŸŠJH�s¸÷Ñ›ÓÈð�^ÀÚO_àé~cW™^m¼ 5 �1WÝÁ]÷%ô(Œ+§ç-åß·<ʬ½ �ϘWnNlf:|d|t7Ì+&pÌý|ùÐBü¤Oß7‹¯{ƒõzG®yãm® £ÙçK!„BF‹›¬¹I_�N™¡3t]¨qÿ‡�fëˈþ6æ,8Äê5Ûñ¥öjä‹V�kÓ8`˜IÔ�¥áÔjÎJtPƒq4bùÖâ,sb·Y)*.%"2ªÖ÷áa¡”—bµÛpºJ�Ê>åî[!N *Q£/bÂ;Kù,{/‹ï`jÏõT¬‹^àŽóÉ·'rÚ0¶oüôWæ½~|/òòݰµ g�’ ¼}ßÌÚk?á>^¸y(‡{Ú65J#ÎEô‚ïÈ]þ óGsndÍ\ÒÉúu›|`IÏ„n¦æŸ/!„BqbÒsرۉ�™.]âý�ŸfXéÔ%Ó‚?ÈÙ±‡b£a�y©¬ïgÍš,4SG÷�hÔØlFI)¥€è÷zk[:÷q–Í KÇ{Á—³”·KBל‡'p3tÀ€� ëÏßÍð3ncøøûš½o ¬ !ÄÉÂÚƒA}ø<»”¬­Û(2z^g¥WÊò_~'_7ÓëÊGyêŠDŽtXʘqCˆ¾áV>9°‚%Û¯¤W¯ò�¶å>K+A7uáŠGæºîG"8!Ñ{ ·}—Ë‚¯ó�SÎ%ºFoLm_úOcæ3¥seKõ!Ã8­O Snþ„í[¾ä“Upÿ0G½‡êÛúÏ}±·¹#—<ñ"· 82þ\¯¾ƒÑý®zàGÒ?œÉÜñOrnÍ„4–{'Ÿ=<�÷·xh7êvž¿ã4ÚWÙTsÒaO™ÄÄ„xÏZæ,Èáì‹b©–:=‹ ·âÃÆ  §“ BsÏ—B!„h%-mÒå;Ä�:¨ÁDEØ©k>€È¨HT¶¡åä a�¸ 4­gÕ>Ôè ìи´êeÅ” (ä.ù”/\ÂÚ?ö‘ïR ˆè@�þ#9÷Âs™`oÚ$ GÉÒŸžãž¿ÍËïìG3 TÅÄÅÓž%Àa%0Іj2QV榬ÌÅW³sÁ00)&n™þ/L¿³E�5ÝZ!NÚÇD¡b çç‘__©—QTìÃ@ÁlöóŽÅÖ‹ëfÎfá·¯2¥J�Fít!O¿ý*¯?wu­Ù,ÊAÊàÞ8oæNöè~ö«†súåç ªU®™t6g'™A/dÅò­‡ÇŽðψŸ~f§ƒ/áïýkNê 6üÎïnÆp¥1wÉAü%¥AZsÿ}3V6ä¼pßDªr3ÓaîΙ“z`ÁKúÜy쮑8=s1ó·ù ` g�Ž.¯¨›y¾„B!Dë0ZúŸQF‘Ól8lu-V‡0JJ(3·íÒ kØàQKHwµ1kè—”aàÛø÷<ö.ß§åà Š":в¶°ôûÿpï�·ðô¯ûñµüè›Ü•Öëóbqô".6€…óæj&&&–¨è‚C¢ Š "¢±± ´‹ ä—Ÿçé 0t$^Ÿ·EçZZ¬ !ÄICÁd.ªºŽ^_]¤FЧw ¦u™d|ø8OÛ§pùé)$W ¢©µß½(Ž:v� cÕ4t4ŸŸ¦áVmXpºÝ¸ýì_1÷d@o?3ÕhzvGMÏåÐîÝ)Ôê!YIÏeæƒè˜è”\ÇjjÉ}"P·`KÆx/h×´î FË_»Ÿ'ç 0åž{ä|ºÔÜ@³Ó¡’0n©ïofùö_˜³õRnìUYëìZ¸ˆ?|*¡c&pje[þfž/!„Bq‚2|º˜0Õ¹1™Q@Óù2ÙËÆ5é”agÈÀÆŽÉfà,-+ß¾µ§Où'7ÿe ì `P¶w)ï=õoÞ[»‹ïŸ~†N�þÍÅ ÇÿÞÔ „K.º—[Çn7£ë>ª6ÇS-åã!ÿíÊÞ””º ´ãqïjñ~%°&„' �¢Âb ÀH@½m°Í$]y×n|�™ë6óÍówðíŒ :ôLf`ê †ÁðÞí°ûÛ†sË~ø†YKÖ²qg‹ÜxkDñêªF•�v´ó»Q•ððPTrÑ‹ )2¨'°–GîÁòÛ†]_<À?úß›¯°÷ÁéÔê–Z7'?œÎ[_ïÄcMæÆ»/%É_ÏÔ¤C�ŹÃg²rþ^~š›Áµ½RÊÚ.æ/Ú‰O�b̤ÁÞJ ΗB!„8þZÚT±`1+àóáõÔ½=Ýí-¡n±b1±_߬L+À°¤2¸Ÿ­Î.¦Õ©$üõ%ýU³ ^<Þ2œcÿ«‘ƒ¸î‰û(¸æn¾ÊÉàËï7qÁ´>ïa½ÎõîyØúà)*ÄY²·³—«—«—«·³—»—³Œ»—Ž]ƶx¿XBˆ“…žÇö‡ÐQ Š‹'ª�@’؇kž‡ ¾ç빋X²n'û2–’•±”ï>z•Ðng0õö›¸0éHG£p53n�O¶¹ÀEÏþ#IˆÝŠÙlFÉYÆ'?mÁU×Nmå-Úü1[Ë«$ë᭯‚7¼x¼†æÅë­cƒQÄ€9ÔŒVVTß|öl^ú@C3ÏþûŸÅœqÿèÚùÙ’t(ÁŒÄ÷Fk ::ŠáÃ0<å݃¡»Ñu7ºæF×\èZ˺€V’ÀšBœ$ôÜ¥,ØäÅFò€$¬ ¯¦0z�½’{Ç^‰áÎg{újV¬XÊÏ?-eó¶ŸxþÎB,o?Áy±*àa݇/ðé67jìX¦?wâªïÅ»2�¯®'°ævã©#hæq—WlŠÝ†­¾:^±ä[èwõ ^:/ò¨’ ]'8ù ¦_ÄG¾Åšù/òX¿nøœ4·�:’³G†69ؤØ"è6h—ßøï|ðu4c¯æëy{ËÇSÐv±lÅ~tÌô½ðjÆÅÕ ÝådSV_}[”Ë~—¿4ææ¡£`ŠŒ®¿µ�)†øvf|dïÛߤÖh�¡¶;›GŸ¾†©1ýÿFA+ÞxŠ÷·Ôx7×Òt˜{ræÄîXŒ–-XI±w+óíE·$q渎 VÐ ž/!„BqâR#éÞ#�í›wàñ·ŒžÇæÍ¹è˜èšÔµá1…�ÒÖnÅ«D08µc“Ÿt� w�³Œäån=Ò*](êŸíX‘ÀšBœè '[>‚Ççä +R®˜Ì©Á Ôdî<¶§ýÊì¥;ý¶.SB’3(�Cy‡Ê5F%e V»ñíæ‡Ùéå-ÒꮾM¬I÷³G}/6££’ؽ þ†4;’¸pRúwĄξËÙá·þÔ9¸i9i{Kšð²80¨ÄLø'÷NˆEumæ½Çßbeq•kq:TÇO$Õ¥«²xådé8L`\ÍgÍ9_B!„¢õ-ý¨ô>ŒhU§xÅB~/2j-£ï]Ì/›|(–nœ6´]ùxiõ}\Y•î†Àdõ25>-¾í¼Ó_Î%üóë}åcºÕüxv°ä÷,4TÚ'õ,/¹¥yÐä,?Ú¯ÜGkBq¢ò•�™ö#¯ß7•ë_[A¾a!öŒòÐE‰ Îî£ç/âÙ;æ±Çžç£ÍÎÚõ–{'k6äc(fcË+ 5š˜v*àcëúM”UKK.K^y’Ï‹¢QÁprÈOË4Å(dþ‡Ÿ±©Úʇ–~Ƭ�>sGF�ÚPk-•NÎf`€‚¶ë+^øt[õ´îݳxòÞû™6y/¯÷û~¯q”0N¹ùn.ílÁ—ù-�¿¸˜ƒ‡£V-O‡5šs†¡”­dæKóÈ"ˆá“N%¢F\´YçK!„B´¢GÖ0÷=— {X1Š~å�W²Ïsä;£l+ÏøŒM…°Sþʤ oÏ»e-i%Ö>©ô³6!-¦ŽŒ‰fxÈøß þ»©¸¢«kÅÇ›ËÒ·^ä³]Š=‰ ÎìŽé(c躎ËUñêÙ¨> hS¸\.t½y¯§eŒ5!„hó¼¬~m ¼[%Ú¢y(.,¤ÌS>e´b‰bð%·óÀÕCi߈¨Š3�)çÏ⟟g🛯aÅ©#Ò-–‹NY~&ë—,`Ù–„ó™<¶b<5–1ãSxwãj²¿{œÿs�ËØA¸î`ÍâE¬õ cú¿óÓMÏð«s-Ÿ¾þ%úà$FŒêC°¡—7 O8•1¦/¹éº-œ9~0]#T ¶/åûÙ«È1Ìt˜x-íÒð¤ßjÌ$î¸i7<»”µoßÊäÕ§3~Hg"ÍnìXÃükÈtZH8ëFþÖ¯Q£ÍÕI Hæºû'³þ¦wHŸÿ�'wã¹óâ0�t(!Œœ}͵Üð—”Z­¿šÃÖíR¦ß¸�)/,gùOò~Òó\ÓÃvTÒá0‘ qsø(Ó fÌøY¨YçK!„B´š£YÓP:^Äó¯Dòú‹ÿá»´ ÌŸ�€b ¡Ë˜‹¹õæKH òâk(†¤ïgíº,4S<ƒ’#Ë»�6�nîÅõ/½J§÷ÞâýÙ+Ùµz!»*î{ÕALÊY\6e*ícÇã9>Q5Ã0ðx½äææb2™(+Î 8l,˜#Q)ÁJ'°£ÚK0Û‹°ºK±{\xG‘f%¢};BmÒÿS!„âdЭ¥þ Úz¾J`M!„8žT;‘q‰D¶v:„B!Ä1¡ª&4MCUåjséº~Âä߉‘J!„B!„Bˆ€Ý€«¬•¦Éx~Ph{êÐõ¡0oæð£ë: uu…†ÕI úK‚5!„B!„BˆÃ¤( ªªâç€# � kKhÚÓ€¦ùŽvÕ†MóÑ´§� kKð ÄÏ?UU‡t¨2ÆšB!„B!Ä è ×Â#¢°Z¬ÔíÞÉö­èšv´«6ä©&��ŒŽK 08tX„j ÁšB!„B!Äaë �L&A!a…`@×Wq î�|ªªŠªª˜L&EòáškB!„B!„ƒ {¸¦ª*º®K 6�ÁZg 6ÔC5�`M!„B!„bÐtï}Õ=’€­oÝ?§á0aAw¬ !„B!„B ¢îáPg 6\‚¢£i8~F¬ !„B!„B!Ã1,ý§í !„B!„B1I�5!„B!„BqDô[îXëÁ'ÁšB!„B!„݃´Þ&l0 £×É †+ Ö„B!„B!þË|˜_ÏâåU¬ÝRK«Ó�ËåB×µÃ(ÑèöÅP”®ï@5™ °3or,·�=�Ð[×ÚÃ5`“`M!„B!„â¿€nÀ_ÞßÂ3•âÓÁ/xŽÐ±„ްa¶ÚQTÓ¡l€�ŸY#BÛFáúíÌÉÍ‚iqLˆ aT„?;ëZÙPÕÈ+·pÒŸrbú(î¿$ƒ 0<Ã5 Ö„B!„B!Žqy•Í\ñØJœn��˜d�aƒSpG¨ïßHiiÇŸÀÿÝô‚ý­,:)6„I±!œ1=ž¦VZœÏ¼ß~Æ-ç¦óÓc�á®I°&„B!„Bq {uy w?¿ŠàèFÆ��ÁÊ®:Bµqþõ¬]·žWîšCÖøˆ~­ìoåÁ+¦qÞŒq\öÐWTÕ;¹máDàÈ„kº®³qÓ6l܈ÏçÅ0 22‚Ô”tBCB¹\ Ö„âXçi¦n¯ ÃäGh¨¿üâB!„â¿ÈËËkøÝs+‰ˆO¼^jÐ-Tk`ãÆM¼ó¿§‘4àb²ÇGòÎ}§qþï?CUn9k0øáÚ²å_ÓÔ²—¬Œ,‚CBÀ€òõå¼÷á»$ÄÅ1ã„“©\ùûJ!†*£�êÊ*}=¦§FÅdµId¨�ƒ�‚àùîQνg)Þ˜ øç ¿ U~ó !„Bñ_aMÅ^î}aÕ Õ"í. JÖòÞ!†j�ÆŽ â•»æ°h®u< IDATðž�IOaNz$0xáÚ¦ŠM쨮âŒ3bÐ^w›ÍÁô©ÓÉÈÈàóÏ?cÙ·_3ãø™.[þ¼Bˆ¡ÊW³7ý–÷÷꽿¯¨XG’˜=�¹óÏâôÜüz;ï(*fUEWU†òpz[-Uõ:¡#£”³“9v„B!¤påã«1vpCµ® è4U­åî‹r˜8úÐ¥ì4)6„».Ìæ‘7Š89efó!N¤Ð‹�HJNFQ`ý†rÖ¬^ƒÉd"33‹ÌÌ,æÌžÃ‹/½HnN.v»c@e«ƒVK!„GˆJxâqœ<óĮ׌i٤ŇciÝIñÒ7yäÎ+øé­Ï³ªîÀé±­3ñåW_°ü¥«H¼sÓ Ó¨ø÷¯¹ðòø°¶� Qˆ^ɱ#„BÑ›GÞÛ‚Ó­;¸wôVKÜK€ÝÄÏfMÀ0ŒAy]2g"v«™‡ÞÞØõ³ÁPWWGxx8MÍ�”¯-çÔy§qîÂsÙ°q=ë×—ãï@BB<åë׸l¹¯+„Cž™Ä³̓§0ƨ¯±‚oÞ™¼²ŒÍy/qûM <ðÄMœ6Ìî›{Y·n:�vMÄp#ÇŽB!Ätžý¸ŒÐ˜¤Á›¨ ÃÐÙ¹­’ßþ,kÐ˾éœtþðZ>wž3“ipz¸].,+NW+.Wá2ã„™,[þ5éi™ÄÅ%°¶¬”̌̕-ÁšB cæ�qœtÉû:¿¾ý_|¿ý#x4�—ï›KDG¶f´ìdÃŽf kqñ‘8p²{Ëvê= Žqć8 vûŠ­TWì QS9ŽØ ýÃ:ݹ‹õÅkÙTÓˆS·=–´ÌIŒtêÍ;Ù°³ü¢Œ¯¦”oÖl¢É1‘©ÉVšÊøn½Ãp±«r=ëöš°…Å’éè÷u€·q+ÅEål¯oÃg !61ƒ¬qaôl]ßu™Äɳ’í¶A_Ó6Ћ׳m÷^\Š�àcHJK">ØÒ­ÀvlÜÉ^ÃÆˆø8Âm=6è®gó–:\X“@´£G‹´&¶WÔЂ?#ÇŽ&ØÕ¾¿:ëg2\Ô¬Í'S -º��QÉΚ@D»í`úµßŒ£pŒ´ ´Ý­5l¯?ø±cx¨\[NEMm[Pc&$“pÐ1 …B!†£� êñj`ìG@;z«yÝmh.órb;~6xN�2†EÏ­â…%Û¹|v0xc­éºŽ¦é]�݈ˆHœÎ64MÃj±Òæt¸L Ö„bØSðŸôî¹¾Œ‹þð �߾ʛOæšIí¿â½yÏpu÷É L%/ÜÎÝKZ ˜}oÿîDü{)U¯|“;®~��Êx®~æï\Ñ9©ÞHÁâGyèÅoÙÒ¦ct«‡êËÉ—ÝÆç§ÜíÜç-|–kïþ oÆ ¼tu3¿¿íÊÚ Ô¨3¹&s OÚÜQÎ&^ûÍ/y •Ø çµëR~¢òíbù3âÏÿ)b·§ÛI]±ž~6wüæçÌŒÞWJßu9›ø™I„šÏN¾zæÏ<övñþeŠ5‚¬…×s×U3ˆµún>þã/y¦ÒÁ)¿�ûN´ï·|ëʧ¸êž%´`cêm¯ðØ‚°ýÂB_ùkÜrýëìq6}ùR‹_äúß|†+ý—¼vÏX>þý¼PØÀ¾9,¬ÑÓ¹áÁ»ùɸž)ÞÐ~; ÇÈ€Ûí¥è¹[¹õ“8vŒVÖ½ó8þß65kì·'ÑYgsë�Wpb´\ !„âØ²xy~!#ŽHÙ†aàÜ[Ï™™1Ð1À o�“3cxuéf.›5f�gU0 MkBÇjµáñxÑ4Šªà’`M!þ[©Dœt§<»‚׫«øzY%WMšØ{o%€is§üõg4­^ÊÊ–™Ðs!�MK—Q©)XSç07®³û[+ùÿ¸�[Wàñ˼«.d~Ö‚�=T®ùˆ—/ç˧M­ï1ž¼h<�±�bµbQÀãÜÊ[ÿüŒÊ 4æÌN Ø/‰äãR¸kìj^ùç—l%†9W^@n° ÿq1ÔhäÛGoå7V£‡¦°ðüùLO…Æ –¿µ˜�Šß`Ñmn~úWL TR—DBUÀh`é÷r÷g»1&pÆ0'=†šÙVü%/¿òùoÜÏ�-÷òìÇbCnNÏVÔP\´ ߉©ÝN®^Öå—Ò¦X±™½¬-(ùàDüºÞ×ÙQXLµ®œ•K²³³FK‹ï…¯<Çsõ¯§1)ÒŠ³ºˆw_|ƒ•5ßñׇßfÊß~J|žúè~;ÇÈ€ÛmfÜüë¹+¡¯cÇ ñëG¹í‰¯h°�aÆEg3'u4!6-Õëùæýwø¸`1‹ÙøÇÓ—’héÙ>!„BˆákíÖ:!ñG¨twËff¤ zoµN3ÒG±xÙ–ƒŽ±–ÿÍßYöÁ=x½ž¾2Àoü¢®ÿx=Nž¸'•ÉÇ�ܳFUU¼^/&“‰6gÛ€ë*ÁšB+¬™œêÇÕ­ìØ°‘½ÆÄýkìÎ?g3þà�úïùêûf�Ücü6m#_,݆¦ØÈ™{1™‰oÃë<òf%ns<ð7fí[/1u ÇMø3—-ú„’—žáÓyrfdÇŠª W-ዘ³yüÙŸ“î¿o‹ú¨V>yæK¶Jê¬ùœ9²cÄyÖ.æ‰�«ñÙ’øÅÃsÙ¸Îç§2ãÄDìWßÁ›UóÏÎaÊ…±íAÝAêâ.|•'?ß…nŠçÂþ ~]mœ”’Í´ V®¸ý=ª>ý'¯-ÌåÚIf&MÉ"ôÍ©-.b»žJBgõµ-ä6 Œ™Í\ÿ%|TRH¹÷D²;C£‘ÂÂÍhŠƒì©©Ø¯ª Zåg|’}ÿ|캜ÂÔ‘-\xÛ{Ôl\Áw»Î'¾ŸÕ¡ì·ÿx»£2æ²`d_ÇN «¾øŽÝLâÅÿË.Ó-¨�ÊÉss‰¼ö&þ]»šo*.&1Q B!ı£¥ÍIXäÀf·ì ðy]ÄG‘þj Ñ�ø¼Þ® úêµöí§÷só=�`ˆa¿Áä …öÞt »kyù?[©®®Æíq¢š¬\zý]¼øÄÝd�xf³ �×x;¶9�^rÃltk!„}³�Š�ÞPOÃ�ãìéÌ;iªÑʪ¯¿§¥Ç²¾ò¥,©ÒPÙœ:3²ãdá¥ô³ÏÙìÇ” ¸4³çd !Ó/`á3†«�O¿©Cß÷  ;!ç¢ IóŒîÜ^J¿XÊv ü¦œÅ9c÷LñÏä'—�dzÎdj„o¿êâ¡ð˯©Ö¬ ¹0Íï€6fŸÃ‚ f mK¿Þ„ØR§�å§ m.¦¸q߇©ï."o‡ApêLæ%G@} Û»Í\é*#o�l©LËôÛoK†Íé—.è.µs$g’bS@«eç®þÌ‚yˆûíÇ>F»Ýz{›}(˜Í½ÜG´%rõ3±ôÝ¿ñs Õ„BqŒq»=˜,‡8(o?h>�VhrmÐ_#‚l\'öÆëva Lc˶V–,ÛH}ƒŠ?¨~  ¨þDEÅ0wfÛ·S_³…ùs&w¡a!ø;^¯—Ë…¢(ž‰T‚5!„8f(˜Ìí�¡ëè?x>°’>û$F› Z¿_ÊÊýR/eK¿a‡®4m'†tD#únJ×Õ¡c">}ÿñ±º¨1¤§„¡^Ö—mÚfu2O$'Ýp&&Òw³v}=:&b'M$à€BUâæ^ïo¾Ž«çŽã€ÑÈz«‹^úõM訌NM¦×ÉUÕ‘$'£¢Q½±‚½àHgjŠ ¼å”¹:4h.*`ƒÏJjf*)éIøiÛ((®ïºHð®/ ¨,‰¹Léñ�*¶ ¤MìåbÈH C\¸=ý8éò~;:ÇÈ µ[ #%9“â¥ì¥ûyèÝ|¶5kû/¢Êe�B!ŽMºæC5 òCŠ]�“�îó`Å8Bÿ‚¬ÐÑ[­}Ó}_ÿé†ñcgròìK�šŽaš„ašˆ®Žo)ãHI�Áùç.䜳瓘”‹ÉdÆçnÅd2¡( š¦SQQIbbÒ€¯åQP!„8fèìmjÈÝäï�ßAÒ+ó¤Ỷ{ƒg7çóåªæÌ l™¼€JTNñ&�ÝÅÅl×ß&Ö· ŒJ's„Š–FÆÎÒ"Ê<€^GaávtS S'÷6Qà }P‡³ßŽÂ12híÿ®øË³<»è ÎÊG˜©��e+xï¥'¸ë—qÖUäÍu-Ghd!„Bˆ£Çf³¢ýЀþ‡Éd²P»×uÄz¬íjr¢äºÐк^ŠáÃ0<í/݃¡»Ñ;_š ]sí·jîä)”—°yóf&çLðg!=Ö„â¡ï^Á’u>Pl¤g%qðTâNžEò (É[Æw{gsj°›Â/¿¥V71úäydt/D±ãï4XH»ü ?+|#�C ØqØ \N:‡·H±cïȉÜN7=ÇkßžÛé»[Çjìdr£_dÓ–bJš.$nOùurj&cM£ÉJ ƒ÷Š)Ø¢1ed)yë}(‘9L{Çø:¬ý6Ì�S‰s.æ®9c¸¨(Écõê|þÙ Ê7~Æ_noÂò¯8«Ÿf!„B ~4¯‹Ýïà ÷—¢t<ª`²ÚÙ\½—¤Ø�Á+¿›ÍÕÍí7Ï;&øáÉï6ijJ©)i‡¼¾\E !ıÀhfå‹oPè6Pƒ�gÁñý{4R9“SR­àÌcÉêf W_¬ØƒnŠcÞ܉ûß}1E3z„Õ;wõÒÓèG¦Ž f„ ШÞQÓëআÏ�Û7€­EL” ðQ½³¦�6ú¨©®EGÁ5rßcŒæñäf‡¢xב_梶¨€­š�´¬ÄŽñÝ,LÊHơ¸׺BJÜ !9SH¶ôº¡Áq˜ûmX#=(¶0ÆOžËÏ®»‡g_üçÅ™1šóxû˪~ Ž+„B1\¤ÄGÐÖÜpÄÊ·û³¬¤úˆõX[V²“Ñ‘�ý¬�³?$XBˆáÎp²þ�¸ÿãtÅAÆE—pb`?û ©‘œ4'.ò¾- ¡èV4XçrJB�^TJ(™q˜ÐÙ¹z•½ž¿têÖ­¢°ªå�C•~Ç`jéé1˜Ð©ÉËcóÔØðµ̚3—Yw~ôó¤v•AFÚ¨®2·öÖO9«‹Û0 ‰éIìUÂJê” ü�6Ö–”°&o^óDrÒöÝ%t¤f�dñ±¡¨˜â‚ ?²sÓœXa0î~‚ÇH_öÛÅîz* —óъ͸zYV JçäÉá(èì©ß#ÁšB!Ž)çŸ0gãî#P² Øýƒùª¨C7Ú{± âËÐ –UóÓ™cPå ½Õãè^ÉI°&„Õ¯…í…Ÿðôo®âO­¦Á°0rö-ÜsÞúÿ`¡BØ s˜âm…ßðòW«ØcXɘ{1œ!TâOY@ŽŸ‚¶å-]¼‘¶K¸·¾Ïƒwý–k.¹†'‹û?¦ƒb2µ�w¦5P×Ðߣ‰ñóN#Õ® m~‡¿½· w·w}Õ_òüGÛа’:=‡�~e�&&žz:©v_å»üýÓ�=î¹ÙôÖó|´KG œÊY³¢ö;‘ú¥O!Ý®SSú_”¸Qc3Èì6Ø�–JÆhWéRÞ*ªF·§1-óÈ øºÏáî·¡qŒô¥¯cGoøš‡o¿—ßÿþ/¼\î<0°uo&¿´C1;f¤\ !„â˜rzv8¸šë�@é »?þv ŸåWaÀ ¾>YS…¿ÃÂÅ3bú Õ ÃÀívc:‡ú8¨ËåB×/˜“1Ö„bÈó’÷ÔÏ9û¹n'ÍCsSm½}¬/KS.¸•E—O%j€ �<•S§²üËe¼ù¥Ã>•SNÑkРFŸÆmׯæÚ‡WP𯛸$oór7»©­Ìç«%ùlwZˆ=ý:þ'íࣼuÕ!h q¡*«wÕðÎC÷Ò:9 ‚s¹æ’©?ˆ©±gqÛ•«¸þé|V=ñK.]1“ã“"0íÙÄ·KVRÙ ÁY—ó«ùQýNÔØ3¹ãÊï¸îé¾yøz®Ê;�Ùi# ð5P‘÷­ÜF›)ŠY7^˼°ý+§e2m’…Å+Ye@ÄIÄwO9McÈL…wW³¼ÑÀ’>…)AG~²ÃÝoCáéKŸÇÎŧðó…ïsËeü߯®`õ‰Ç“;~$A�¶†í³„•Û|XbrÉœH Ö„Bq̹r~ ÿø¨œQÃs~¨ö°ËdeäÈÑ<ùNó²c¯pàÉwJ9!% «ÕÚg°æñx¨®®Æ0 0¼`x0ð�áîÚN×uªªªkÂá8ô›Ý¬ !Ä�gàjÚMMÓ¾Ÿ(ª«#”ØqãIÏ9žy§ÏfÊ(Ç!ž/˜:ç8B¾ú„¯Jà s™Ùgše&öôßñLÄ¿ùë3o³,ÿCžË몎È\q%מ“AØ@*cIã«g³êÏ_°mË ÞÙ¢`ˎ㊋9ÈE€• çÿž¿G¼ÈÏ~Èêï?â•Õ ª#šÉç]ÆÍWÎaì€ò+ãοŸt”¹êË×X÷Eg­„'Î岫®âœˆÃ5’É“ã1nÀ§ø“ž5‰ý‡O³�œ‘ŒãÝe´êfÆOÍÙ7FÛu¸ûm#}éóØ™Jε�ðhÄ¿øû¾¦ôË·(îÜ�(¨Ž(2O¿œ_ü|!ý}tZ!„b¹åŒx^ùj{ë¶9fp U”öÎa ln ÄæÑyui%Î;(Å¿¼¤—Oç¦c»í-\óx½ÔÖÖ¢šÌ´4=ņªº°±`nEµ5cv7cq4c÷ºñxœx<.,f÷<^7»k뉉uc·ÛþÈi”ˆ+2PÚo§o{â?¸ðºâ|²§�xHBˆÿù+—“”ž}´«ñ#Ðq6ì`{uNÃL`x ££±FF¡µîf[M+ø…22*û€B'Í5Uì¨oÅg eô˜‘„Ne:Êl©ÙÎöÚ<ª�°Q±Ä„Ú‡yï¦ÁßoCa[?|ìxi­­fGí^Ú4GP£cFà/·…BqŒ+ØÜÂy÷Ix\ŽÀ°Á)ÔhhÓÐuÂÔz¶V–óÆof1!&谊ݰc/ç?ø÷\˜Äé¹ ˜L¦>ƒ5·ÛMuu5+—ü…m¥/¡¢€¢v�·Öù`¨at}·ï‹†¡•0—é§þ�1±±î±6憧èÌÒ$XBˆAö߬ !„B!†º×¾ÝÅoÿï;"ãÓ°†N¡†�ah>cõTlÝÎK·Ï !:à�Š«¬ná^ÆüÉ£¸ñÌ Øl¶®`­÷Íx<œN'.W^�cì™-ìv;6› UØ­óîÁšÜ«B!„B!„8F]x|0�»Ÿ[Iàˆ‚"cŒA×E³•M-AŒ�ÍXÂ?o<ŽÌ± ï 6ÕsÍ“+8cêh®;-¾_A—¢(Øl6¬V+ÁÁÁÝz¦õ·îÊ~_‡kB!„B!„ǰ ��"qÔl.{ô;vÖï$lÔìA‡Ñ{­c¬5EQ1YýÙÔl0~\W>º‚Sc¸õœ4‚ü,?XÄÞ6/~³„�×TqÍiã8oz þþþ¨ªÚç# Vcð²C%ÁšB!„B!Ä1.+!€¢'æòè[øçeÔW8B¢ð Ãdµc¶ÚQTÓÁ êÔ®©*&kÛ[ÍG�eSM Çßò'¥GsÚäX&Äî@M}뫚ø$¯Š¯‹k8!%Š—•Á¨¡8ŽWm¨’`M!„B!„â¿ÄÍ â¹yA<Ÿ5ðÚ²í”mÞÂÞ6.— ]סD£cnt��>'†îåÝošyï»­í“ ( &U!ØßƬôH^»9ƒ¨ð 0›Íê©6”H°&„B!„Bñ_æÔŒ0NÍœ™B Ãèz麎¦i ¸ðz½èzûl�ªªb±X°Ûí]=ÔºjÃ-T Ö„B!„B!Äaè Å Ã@QTUÅl6Ð>KhçäÝÇDëù®$XB!„B!„‡­çd}ÍÖÙ=HΡH°&„B!„B!IÏЬg¸6܃´ž$XB!„B!„Gı¤õ¤í !„B!„B1I�5!„B!„BühúwKˆáØ»M‚5!„B!„BQ�aZ÷PM6Ñ©ûd='@ê$XB!„B!Äc†aÐÒÜÄžºZ\N'º®íj‰!FUMØ~„FD �pM‚5!„B!„B�¡ZÝîjZö61rô‚CÂ1™%ŽûÓ|>šëÙ¹}.g+#FC?\“#Y!„B!„ƒ®«§ÚÞFZö6119Ã0ðx=àqíꉡFQ aRJ(Öb·ûÜñÖÐ ×$XB!„B!Äa{ê뉎‰Ãçóʸj¢o†�O×Q…è˜8jkªñ Ò¡€z´+ „B!„Bˆc�a躎ËÙ†ŸŸŸ„j¢_ ÃÀáç�ÛÙŠ®ëCþ¸‘`M!„B!„ƒªû, º®a ñ^GbhQ­[¨6”Ã5yT!„B!„G–¡íˆad(i=I°&„B!„Bˆ#jå$B ˆ< *„B!„BˆA7œz‰¡k¨G¬ !„B!„BqäQP!„B!„BaC»×‘8öéºÎÆMذq#>ŸÀÈÈRSÒ 9är%XB!„B!Ä‘5Ôr5O3u{Ý&¡¡þ?B8âaoÝ^\¨ø‡áo9â=,[þ5M-{ÉÊÈ"8$ (__Î{¾KB\3N8é�Ê•`M!†wÃÖ–o¡jw#­“Õ� ˆ‘$LLdüûÐ}¶ßÓÈ–õëÙTµ‹=­>°8ŽŒaü¤I$„ÛèßÄëøýB!„b¹š›Ú-Û¨ó€5$–±#ì}^/-ÕlÜÙŒ®;. ÿ>l£¦r{4pDÄfųò ~rßR¼£ÎçïÏ]EÊ‘NG<«yäÒÿås÷H~úøÿqÃß ènSÅ&vTWqÆ 10›ÍÁô©ÓÉÈÈàóÏ?cÙ·_3ãø™.[ö¤B i­•_ðÌS/ð^^5­ú�—$ŠjgDÚ)\uãÕœ>ÎÑÏ êàô¶ZªêuBGFxg mOï¿ô<¯|\@U›~ÀÅ”¢:ˆNŸÅùÿs ç匠÷›vG¯ýB!„b0õ3Z3<>w÷-wb;�Å- ²×;¨:•oÿ/W=· Ÿ9‘ëž}Œ‹F÷~«U¯þ�{¯û'%Z§üïËüî8Lf̪Šn6£*?Fw:UPPÕö`Güx6Vl )9E�õÊY³z &“‰ÌÌ,23³˜3{/¾ô"¹9¹ØíŽ•-ÁšB aÎu/qÓ­/RÒjà•ɳ§‘M°|­ lÛ�ÇWŸ}Ǧ¢wyðÆ­4?ù'.LŒ~åÿþ5—½êÏ /=ÆOG¤?˜AsÙk,ºû9V×kŠ�ȉä¦�cd¨Õ¹—š­kY“·ŽêÂy¢øk>ÿÉoyèš©DôØÌÑk¿B!„8*”r�OÇöÍJÜåy´žÎ¼À^n�ê»ÉËÛŠ U²:Žïå)ƒ=…lð�â—ÍŒL;Ö¿cù·÷�îÅíò ÙV‰£¬®®Žä”dšš)_[ΩóN#(0��?ÿ‡ÃAFZ& ñ”¯_OfFæ€Ê–`M!†*½†þñoJ[!(çZž~ð<ÆÙ{,sÊYüÏ…+øóM÷ñîö"žyêSfýiQ‡û\¤±—uëv 3qÀ«jÛßgÑ]ϲªÉÀ3ƒkï¼�ó2Â葦ïÝÈOÿ‰Ç>®díë÷q»ãžº<‰®ûCG³ýB!„bp  ƒVPÖTR,«Ès•°ªØÍ¼ãz^‚ÑXÀêõ>” ‚ZšX»¦�–³ : ƒk£(oCÁ–1�lGG]|.œ¾ÃhÏ@=¾—k?*·Ë…ÅbÅéjÅåj#"<‚ÀÀ@fœ0“eË¿&ã³F IDAT=-“¸¸Ö–•J°&„Ç ×:òËÝj3~rÆ�¡RSÄt®¿f>^®"z¤Á/DÙ\Nwîb}ñZ6Õ4âÔ­„D�%-s#ÝS(ƒÖš ¶×—ñÝz†ábWåzÖí5a ‹%!ò �Zê»xÿ‰±ºÉ@�žÍ=�ÿšÙ½÷ÝG šÀ™wü…(û�ÜþöVÊ_{’Å'=Ée ¦#Ò~!„Bqô (G Ïaúxyk[È_SŽû¸L¬=i-. Ä£9ï rW¼Â‡Åù¹fsBϧøÜkYU؆¡XH�žI@G]:Çg3,aÄÅG`ï¸Èíü9~QŒŒÉp±k]!Õ´èvBFN 3s<=+ÔIo¡ª´�â­u´~ŒˆO%'uþýø<|MÛ()ÙÀ¶ÚfÜŠ�àÈXS‰ îv‹Úhaç¦jöV"ãâïyÝën`ËÖ:\X��'ÊÑãê]k¢ªr-ø�0š�ŽTÈð4P¹n›khõªØƒÂ‰ŸÄ¤Q˜úhêp¤ë:š¦c2µ·jDD$Ngš¦aµXis:\¦kB1dùði  ¨?g)œp#ÏžÐÇÛz#‹å¡¿eË~c�)¨~±œ|ÙmÜq~*Á €—¢çnåÖOš;–ÛÄk¿ù%¯¡{Áã¼v]Êž8´Š�Xœ×Š¡3ëêë˜ÕG¨¶¯ AL½ú—Ì_ñkÞ©ÙÀ[oòÓ[s°fû…B!Ä0€hMÁ´icxzm%õùylÒ2HÞ/ÝñP²¦ˆ6lLÉ:•¬=oðÁŠBV—»9!kÿÄË·!Ÿ¼&L8.'¥£Þ‚g¹ö¾¯ñŽú O?ûó®É ¼¥/sã¢Ïq¥]ËË‹âùäÁ?ñRQ¾®ê+X£¦òËû˹c{lkçR½ïIÞ¯h¡kh`E%pü|îümN·Ô=º¬yv²äÙGyòÝv{öÿœk8™g^Ë�WžÈh+ ×òÉŸų•æÝû ¿;aÿ»Ïm«ÿÎ5÷-¥Soy�‡ç‡îwcÜ·~1·Ýø&;G,ä‰ç¯%Óh¥ü½¿ò§ç¾fS³¶ÿ^R¬De.äæÛ/儨c%>R0 MÓ°Zmx<^4͇¢*¸$XBˆcˆ-�‰£M,¯ÜËÒW_gaÊE¤ ph~£•üÜÎ-‹+ðø�eÞU2?k ÁÆ*×|ÄK‹—óåÓ¿¦Ö÷O^4fÆÍ¿ž»VóÊ?¿d+1̹òrƒMø�‹9ÈÌ›:Û¾[Év Ôˆ9ó„�þM$àÈâ¬Ù£yÿ•mÔ­ü–µÞ²-ƒÔ~!„B1 )Œ™’KÌó•l«Îçûí—‘ßíJÔ·‘5ùMèæT²’ÃH­‹é›õäåW¢e%vëa¥±¹ ŸÝ:˜ÇNcjT·kIµ£<Å´ß5«b±aQÀÙ¶™7þøK|'rí¢ãIa¥mgo?÷oVԬ⩿¼Ãä'Î'®³Zžõ<ï#¼WáÅž0›+®<‹i±~¸w•³äõøã[Ý[S�=|ýè�Üûy-FàDκêgœ’K{ÙZð/¼ô ÿù#7·Zø×­Ó1�aú”(ž¯¨¡¤¤ß ÉÝ‚/å…e´)Vlf/ëŠÖâšü¾¡VÐÙY\J�®’3�d‹Aã²'¹ó¯Kh°ÇqÒ¥ç1/-–P›�æ�å,{ç?|Xø÷Ücå©'/aR/CçQXXܯ½š•™AVFz¿–í¯üoþβîÁëõô½�~ãuýÇëqòÄ=©L>îæœý0ªªâõz1™L´9Û\ Ö„b¨2�åìKfðîï—RWø×\²‚™sg3sZ6ÙÉq„Û>�˜oÃë<òf%ns<ð7ft]8$¦NḠæ²EŸPòÒ3|:ïAÎŒT‰Ê˜Ë‚‘­|òÌ—l%”ÔYó9³_“¸Ù´± ëÄ4’ûê`C—‘BàkÛhÜSÁÆz�ìhuPÚ/„B!†ˆŽ)¦Ž�Ê´È×Ù¶{+k ê¸$nD×M^mKß×ê˜â³É S‰ÎÈf´i-UyEl¿,‘® NßEþš*4LÄMÍaL_uèÞ�LÐ*>㳜xöɳ‰U4tÀôlr£[¸àæ·©Þ´šU»Î#.Z ö~ó&oVzÀ 7=¼ˆ…ášÄ�%}J7]Ím]�èØž»x1O}±Ý”ÀÅzœë“-躎�B„L¦N´qÙÍo³ý³ÿcñ“ùÅD3ã'çöúûÔ–”P¥%ïk¯¶•ü¢”¸yœâÿ””Pî9ž¬Î@Ìh¢¨h3šâGÎÔ$¬F+_µ’ÝLÒ¥ðÇ G¡kzû‡�žÃ̹Sqõ/y¥.�?cÒ¤ U•Â’ò Š~pædg’“�5ècË}ûéýÜ|Ï#ØbÚëÝÉP…ݵ�¼üŸ­TWWãö8QMV.½þ.^|ân²N¼ ³Ù„Çë ¼^/†a (ý¿¡/•!Ä�¥1ë6¿c>‰A*¾†r¾Xü7î¾ùJ,Xȹ×ÜÅïŸ~�O ·Ó¬õ¶¾—ÒÏ>g³S.àÒÌ€=ÈB¦_À f W!Ÿ~Swx³!é{¨ÛãÃ@!8*’žÃ9üsdTû4êZµõ�µ8Üö !„Bˆ¡Âè?Ó¦å£^Ö­)¢Ñè|GcgA>Û4•9™ÄªJ\&9a*Úæ<òê´®2ôÆ"Voò�É´©ñ=j±¯f½ýÜP¢YpùiŒÔ\x|^|šŸ×…21�›ÚnªwwnËMáª|Z ¿©ó™âÆãó¡é>4Ÿ·Å™çGçÃû¶å¦hÉ2ªukÖ9\0QÁãõâÓ4´ŽíYSrÆD3†¶ƒeßTàÃÀœ4™lms %�zWiZm ùU!i3˜—õ%Uíû< Wå°¥1-ÍŠ¡;ini¿~7+>\O{;5/>¯·ÏÏŸû’o?úW%©½î§ìÌ ®¾òŠöЬ9ÙY\uÅde¤èè¯Û…-0�-ÛZY²l#õ (þ ú�€¢úÃÜ™qlßZL}ÍæÏ™HlÜq„†…àïLx½n\.ŠÒþ¨è@H°&„Cšƒq§Ýʳ‹Ÿçñ;.å¬ã’éoo ;Ö­âÃÿ�{n¼Œ?½™‡Þ_GS÷dLßMéº:tLħwŽ¡ÖƒCzJªáe}Ù&¼‡UW_Çàë;D[,³†úðì7;Óa´_!„B cÒ¦e㯸ËÖPØ9ô•ÑDaÞ&|j9ÙãÛû4O$7Ó¼X]¸·+’i+- Ìc †NfúÄ�ÅŠm©cé寳?�~ àÆííØ’¾‹Í[]˜3>빌Že\"c{^"ë»X¿¡ •ØÔ‰öèF‰É!¨hToÚÌ^°¥05ÕÞr ×¹;—¤¹¸ˆ >i‰$¦§à¯m£°´¡« Þ�ŵ€%i Ù€JjÊHLŠ—Ò—þÀ#ï°}¿;Ö>w+m­mxû¸ÎÖ4�ô”d®ºâ²^õöPírÒS’ºÆ5lºáGüØ™œ<û£¦c˜&a˜&¢«ãÛ_Ê8RRgpþ¹ 9çìù$&åb2™ñ¹[1™L(Š‚¦éTTT’˜˜„ªìX‘GA…bPýbÈ=ýRrO¿t»*Ë().%?5ß|_ÎîÝE¼õÈ-lþ=¿ar{ˆ¦×³»®ý ¸åÍE\ôIï'_Scûý²ºZöêp°ùúfǯ£›ZkKÛ€zyN'NPø÷ÒÕí�Ú/„B!†Ž?h`OŸJ¶ã+¾n-âû2'O¶Bk1߯õ€=—)ÉæŽr­¤NNÅöÅJJÖ”áœ{<~x(]SL›¡˜3•TS�:ôü¾Gý‡?~½ÕÛPP•}«aÚ^›tÀLhH@¯mU‚Ãë¼FíÜžouõíëED„¢ôú)„…†¡R‡¾g�:„ªþdåN¼²¤}œµã’1㦴° �y™Évlæt’-_RZX†sÁLüÑØZTB�nbRn6ᆉ‰ýš«×þ–¬ç½Çïâý¿0rB*9YÙL�6�i‰‘Ørm­ù4Ò““¹êòË0™L¬þ~ Ð-TKNBó¹GLÜͨÆwØIø4'ΖM¸��¸œ-¸Ü­¸œ­¸]­¸\-¸\mجâÇž„a´ÿ­¤ª u{êdÍš50ï´m_z¬ !Äp£Ú‰ŸÃœs.åŽûÿÆÛ‹ÿÊ­'�‚›-ïü�×6tœ´ //€�¡yñz=½¾ ¿bbFlæ°Nwj£¢ýPÑi­ª¢~½Ç\;¶³[ÅELôANMým¿B!„Þü2˜žbAÑ›È[³à^WH¡¬É“Éê6!f`z“Ì-E¬õÐ>ÁAaºb'{Z*¶CÙ~Ã@ÃÛõÔ…Élî}/EÅtÀL÷>¼—®³©Ï‰¿L–ö>Q†Ï×1;©BDf &�Ý%eT逯‚ü┘t2ÂN&3΄³¬”u@¯§¸h;ºi4Ór¢º¶eX&pé£/òÒ½Wsδñ„›Ú¨^·’÷_}ŠE7^ƹ×=Ì[å-ý(öõ\»œœì¬ýCµ#ÔSm?†ÖõR †áié Ý�ÞùÒ\èšk¿Us'O¡¬¸„Í›739gÊ€7-=Ö„b˜3…$ñ“;ÅÆÒßð^ÝÖÔ OŠAUìøû Ò.‚ÇÏ ïß,�‡Ì¤ÔD¬¯Â½á{V7žÍ™aýÙ¢›Ò¼2œ˜Æ¦‘:À™?ûlÿ¡5B!„B‡0j½È䩉˜×³»´Œ*}"­Å4ê&sÒ éÖÅK OgÊE[J(Úê#ÛRDÞnÅšÆqöƒlÿ‡f5ø!]Ï ¶Ž ýn î®r tŸ¯Ë‰Ë<‘“&G  ³§¡ ½ŸûLóiícªNª6�?BŒ£;ƒ™üí!„C’Çýä,ÆZÁ[¹˜»îy•Õ»<½.é®YÅ3÷ý�oZ Ôðœ9=°£ ¹Jü) ÈñSж¼Å£‹7ÒÖsÝ­ïóà]¿åšK®áÉâ}å+&fШkȉÊNÚå·sÉD¸+ycÑ�,zu5;œ=ÏŒM_ñ×ÛoâÏßíÁ°ÆsÞíW3=°³óû`´_!„B {ʦM‰DÕ›)|ç#Š] �YY$š\ÔœœM¦œ¥òvI†i Ó'�ø® ͤŸ0•`ÕÀSô.ÿ.ÙL2ÏŽÏø×[茱¦0nÞ¤Ù|•ïóÌÕ=ú^y¨xçe>Ù¥£McáIûíbKžL†]§¦ìC–”ºPǤ“ºo %8™ŒXWÙ2Þ-®F·§3=ÕÚõ¾Þ°œÇ~s?þá ^Ýà<0Ëroâû’z Å̘øQC*@2 ·Û�aè ´�['—Ë…®^0'c¬ !ÄeK¼˜n®âÖG¿¦ê»g¸ñû3jB‰c¢r¨hÎ&voßHéújZ4PƒÓ¸âw×qBྒྷ©}·]¿šk^AÁ¿nâ’¼YÌËM Ü즶2Ÿ¯–ä³Ýi!öôëøŸ´}'Y%h q¡*«wÕðÎC÷Ò:9 ‚s¹æ’©„äÊDq¤pÕC`ºïž/ØÎWÿ¸‹¥/„1vÒxbÂü°øZصe뫚ð ¦ÐT.ùÍ=\3yÿ@l0Ú/„B!†ŠC >@aâÔ\Âþó;Ë7€â`fN2Ö^ÊSì©LI²°4o=ëut.SG÷gÛ}½ßÛÏ{ëêöÜ ¹<ã[+ØÊ‹~EÅÉ'�9ÊŽ«¦œo—àœvsKÞäÓZCïÖ%+ú4îüÅ ®}2�o»…ë ærrÊHü} l.øš�WoÇiŠfÎÍ×1+PGï¾yÿ4¦&Zø¦h« ˆœ•Fl÷©EÕQdd„ÂÛßóM£�%s2YþûÞWGžÆ5ç|Â�‹×ñü­×°æ¸éLE Eǹ§ŠÒËYµÝ‡e̹\zrê!ïÃÁçñx¨®®Æ0 0¼`x0ð�áîÚN×uªªªkÂápr]$XBˆ!ËJÜü»y>i&¯¿ö.Ÿ~Wƶuß³c]·E¿È‰Ì?»à42Â{þZ7{úïx&âßüõ™·Y–ÿ!Ïåí[י‚+®äÚs2ØožK^=›Uþ‚m[VðÎ[vW\ ý¹å§†dòóGžeæ’·xõ½ÏY^Zͦ¢Ulꪷ ÿèfÎ>ƒŸýd6I!½Ür”ö !„Bˆ¡àp"SR.S?àã&Å’È” {ïå)Ádæ$`Ê[�•¹¹ŒS�õþ¤çÁÖ0Œhνÿ!ô¿<̳K7“÷ÉäŠ%„¤ÓîàOׯòñµÿ<¸¼Æ¾2t}ö<ñ"�ýë}¾[òå_u¶ÇJDÒ©üüš_pAšŸ·G`¤„’=9SÁz|Jé™ãQ÷«ŸÊÄôTo/¥U73!7“P¥Ûû†•Ô_<Æ“#þÉß^_BÉÒw)YÒU8ª_Yg\ÅuW/`’̓6tr5<^/µµµ¨&3-�E„EÏF±„¡ª.,F,˜[Qm͘ÝÍXÍØ½n<'� ‹Ù‡Ç½�×ÍîÚzbbÝØívåÐnÐ+WT‰áÃÝÚJÏŒ©“j ÀÏf O­®>¶·øà°€îÆÙâÚ7Þ°Ù�¿ŸÅðàlvö2±[€?UÇ×ÖÌ~Å+&¬v´íbëŽzÚðgĘX¢¬>\n ³¿?VÕÀÛÖŒ{¿j)¨6›JÛ®íl¯mÆ£:˨`šÛ�Ç×{ƒ»·×çlÆåÝ?ýR,~ø;,€�îj¡ÍÓ³“ÕŽÕ ÎºjvÔ6Ѧ™pE0:&‡áÆã>:¡Z况ŒKLÅd2¡ªê~Á—Ûí¦ººš•Kþ¶җPQ@Q»Æ[ÛxöˆL @ÃЉJ˜ËôSÿÀ˜ØØ÷XsÃStfi¬ !Ä ;bÁšB!„ÃÄ�ÁZÒÑ®Ò�GQÛƒ ]Ûÿñ̓®jBUÀÀÐutãÇK´UEQ:êm´oÿhvR«Ü°®Ï`Í0 <N§—« ¯ÇÍ@>*³Å‚Ãá�ÝnÇf³¡ªëAÐ=X“gf„B!„B!‹¡£k‡6 ¾¡k½ô’ûq´iGw†ÍþR›Í†Õj%88¸[Ï´þ¯ßýëá�`M!„B!„GÔžKC3 ;T¬ !„B!„âÈ’dM£$XB!„BñÿìÝw|UõýÇñ÷9w$7{BØ{qjk­ÕÖªÕjk­­£jí°Zµ­[«­ZµŽZ÷ª£Š eï½É$;¹óœïï��\F¼ž�Ç}rÏ÷œÏ½$Üï}ßïö2’5˜âÜß 8¸¬€=®#×½Â�£³ÿ1ì5¶í‘ã8²mÆö`׸®»ßü¼ìU€ýRb I¡¦ÆŽ.û‘P°Q‰�äŽ.c—¬€=jÓô=˲”–™¥êªJ¹®ÛÁUaຮª*+•–™µÕÏQgE°ö8˲dÛ¶’’SHIÕ’sU[]%ljutiè„'¦Úê*-Y0WI©©JJN‘mÛ�:T“Xc ì%›Âµìœ|ù}~U–oÐÚÕËå:NG—†NÆöx”’šª®Ý{*5=s¿Õ$‚5°l E<�$)-#K)i2ÆHÒæ?�ÖS>mÛ–mÛòx<²,«Ó‡kk`¯h®Ù¶-×u Ô°C›‚µM�ZgÕ$‚5°µ�Ô:(!`Ã&­.ö‡ Z#X{Uë°dS ¶¿'ØwöÇŸ ‚5°Ïì�á °#vGì�±À.b]0`ïÙG3¬°›Â´Ö¡°çl ÔŒ1l^À�Â#cŒêkU]Y¡P0(×u:º,à€cÛ%’”™“«”Ô4IûG¸F°@6…j•å%j¨«Ua×nJÏÈ–ÇË[i`Osb1ÕÖlÔ†µk 6*'¯PRç׸߀ml©VW£†ºZõ4\ÆE¢)îèò€�e)%5CýgjÉ‚YJLLRJZzË]�7\#X  ÆUoܨ‚¢îŠÅ¢¬«ìMÆ(溲,KEÝUQZ¢äÔ´NªI’ÝÑÐÙc亮BÁ&%%%ªûˆ1F�¤d…ƒ�r]·Óÿî¬ÐJë]@]בéä#f€�eYrZ…j�9\c*(;cÜŽ®8¨tæ m[kìÄ~ôÀ>ÆTP¶±?�˜d�ýw‘` ˆSAØ©Î=bÀ7s]WK—-Ñ’¥K‹EeŒ”››£!ƒ‡)3##îó¬À�.Ò �uA¹V@éÙ)òwt=û›Î�«EêUY–ñ”™™ÜŽ7óÕUÖ)$[ÉéYJöí¹’L,¤†¦˜¼�d|ÖnÔì}?ÿLµ u9|¤Ò32$#-Z¼Ho½ó¦zvﮣŽ8&®óòsû“H�V.Z¤eëÊUÝ“��¤Œ¼®ê3 Ÿzd´™Eç<¦^ÿ_U§Ÿ®û^þ•ÆíÁÎÔË4©dÅ:ÕÄ,¥öVqÚÎWN0 %Zº¾NŽ•ª®}º(•…8 ìN®æ6•jÑÜ…ZQZ£ ”–×Mƒ† PqjûÞŽG¦<¨soýTÑ.ßÕߟºLƒwµydšî¹è�ú0\¨ï=ðOý|—îDx¥Þ¾ÿn=þÉRUEŒ”|‚îzõ×o�À^¶lù2­/Y§3Î8KFF’QBB@ãÇ�×ðáÃõá‡hâŸé¨Ã�n÷¹ù1€ý€[»Po?ó”ž{w†Ö5¹Ûuî,O²ŠGŸ¬üø‡:­* hî®Ø\=yÍoôv�W‡ßôŠî>9EÖN�Î|RWþö#5úŽÔmoݪû¬Ò­¸MZ·ÑUfa¾ÚÙW;G´ælÔ´çÔ½/NÕºàÖý7+!O£Ïþ™n¼x¼ wõCO�W^Û–ëõʶÚS�-Û’$K¶Ý(ìW+_ù«îù`©bv¦ú6Z½Óû+Ë6»Q#°w-]¾D ’eI‹—,Ò×Ó¾–Çãш#5bÄH�pü zæÙg4vôX%&¶¯3O·:5£Æ%¯éw7?¦ÉQ+AÙ}FèнU˜™$O¸Zë–ÌÖ—3–kÍ´WuǬɚòË;õ»S»)¡£KÇ>æhùnÔ�þ�¬Ÿ?{¿¾WH¼ @‡1ušòð¯uó[k±35èä3uò¨nJ7µZ5ý}½6a©¾~ñ6]¼Mÿ¼z´Rvö ^ ÿQ¿Óç_Ü*¹Q…C¹{ÿQ´ÍÔjîÜÕŠ[]Îù£žºf¸üÆQ,•ÛYj¶QYY©Aƒ©¶¾F‹,ÒÉ'�¢´ÔT½÷á{ >t„zöì¡E‹kÄðí:7ÁtbnÙÝ~Ó£š\idçŒÑ¥7þJŒÉß.4 —NÑ¿îú«žžU¢�ïûƒò‹þ¦«‡wа)t S§… ×ËU¿Ž®€O;_E��°ä IDAT¾¬ÿ»Va«@'ßú7ÝzL¶ä¸2²dŸv–N|ƒ.zàk­ï?zÿ¼‘úNþ.|  )ÛÍÚ÷È€µ šš\I^u-Η …ÙÝ�½, Éçó+jT(Ô¤œì¥¦¦ê¨#ŽÖÄÏ?Ó°¡#Ô½{O-˜?�` ¦FŸüýQ}VéÊJ£_Þ{›¾Ó½íuÔ ÕåwÞ.]ý+=µdµÞü÷':è©ÊmÝGÛôI¨ ©tÁtÍXV¦7A™Eý5jDeïpWWMeK5wÁJm¨jRÔ“¨Œü<|€Š’¶ïš† Z²¾^J*PŸâtyLH¥ fhƲR5¸ ÊèÒO£FöUÎŽ®çU¶t®æ­¬PƒIVA¿áÙ;S~E´qõ*•‡<Ê(î¥Â¤í?ÚuƒeZùã­6ˆmøT÷Ýú�Þ^ÞЪe+µÏ©úõoF·ú�m›!kn�f½ô�î~~²Voׇêªc~ðK]{îà–>TD³žºV7NhÚ|ܼçoÒ�Ÿ—¬À±ºãµ5®�=îr=wË]ú¸:Eãù7ýùÔ¼­Ö6õ_é�_üNÿ-OаËÐ=³Ûñ\íeÉ#Çq$I~‚"‘¨'&˶"X€…«�_MѨ‘©3N*Ü¥ ’ú©SvpŸåÛ¨÷n¿U_F×å7ŽWÿ\ŸšÖÏÔϾ¦i%“ôÀÝohÔÃç©Ç¦ ¹ôÚ­¿Ñ£Óå+:T�²FuË”?²Q˾|]O¿1W¾EÞÜÇõû£26wØ,¯O^K2 ËõâíÏëãÈáºüÆCÕ?ׯ`Él½ùÌËšRú¥¾ûu�ùÛ÷¶\/²POÜr‡^]•¿pœÎ»ð4�隨úSôê¿ÿ¥î8Zƒ�$ŸüÞV ™iÔŒ\¯_½¸\‘¤^:é²óuêÈnJ7ÕZñõ»zöÅÏõÑ£7ª"v¿º Ï¾]{ÎTéÓ»¯Õo?(—Ié«3.9O' +R†êµfÎGzîù4ãåÛõ‹†?èÉS†%IF5ŸÝ§ëüXU‰ÝtÔgë„!]•‘SCÉbMzû ½7óEÝrK‚þñèEàóª÷©W馞ÓôüciµŠtÂ¥çilºGɽ‹ØÈ€`y”‘[¨LcäšíC9S»J+ªŒd©w÷Ö½KÖ¦nŽ½Í«ø¦¿[ž­G£Gëé?Ü£·–G•Øóx]ré·thq’Âe‹ôÉKÿÒ]Z¥®mi5ó‰›týK+Iî­“¯¸PgÒCé¦J˧þWOÿûS}üØ-ªpîÖýç÷V‚¼ê÷­_é·c*4ù™Ç5a½¥^§\©ï�H‘í)ÐoÛ5Ú9Çé××ÏЂ›ß×Ô'ÿ¡ c£“rìÍ5|ýô#z¯\J}…~ÿ½žòµD¢óš1{¶fÍš³KÇŽ1\#‡۳ןôwMüïï�Fv|�‘’úܲù/ÑHPþ~ˆ9ì�pöݲm[ÑhT�GMÁ¦v×@°�’£KW*f$O�¡š¶ûC­Ü _èó‚Ÿê÷Ÿ£ž›>ú=V‡v é‚kßÔ†%_è˲sÕ£eÑ{gñ;ziVƒ\O/]pëtyß-#ÄFŽ«nÑKôË·ÊõÉëõ³#ÎÜ2íÔ¶dKrV| ÷GýT�µ¾žÆh\aƒÎ¿î-•.�¬/˾Ûr=£Ú‰/èå)0B?»ûv}·kËdLJèèÃúéæ+ÿ¢‰ÕF²,µN‹bK^Ò=¯¬PØÛ]çýé~ýbä–)†ŒÑa}ÿªÝò¾æ>û„þwÒ:3wßEMáÙÿÖC–ÉõôÐùºW?ž´¹¶þƒGéо~]rý[Z÷¿ÇôÂYcue¯¤FM�ð¥ª\¯\øGÝyA·VwœŽ=q¬r¯¼Fÿ©˜¦IË/Ô€å?Q§6êý'>ÒjejÈq§êL6/`Ïi÷ºdFÆ1m73Mšõ⫚‘‡œªÿëi·:’Æ\|›î9ÛÈ›ÝKÞ]wóÀ3£ºI¯è•)yŒ®¹û�•íÈq%uï¥ac†+çšËõ`“ÙÒj9glÉ«ºÿÕ• {{èûw=¤«‡%Èu\«wÿÑß/ Þø®æ=ÿ”>8á�:#ÇVÞ�ãtê�uª~럚°ÞVîàcuÚÉ™²Œ+'æ(ÜV�ÆQʸŸé¦ÓgëWoOÖ#ÿ˜¤Cn:JY–œû¼øo‰Lú¡ºæÆÓTè8lx°Ÿ±-[³æÎÕŒ™³wzÜèQ#4zÔÈÝ_ão_üïvýò÷÷(1¥Hj9K’‘‘¥òŠ=÷êj•””( ÊöøuÑU7陫‘G^'¯×£H4"É(�Ê#ËÚõ÷_kÐ)…UUÕ(W–|¹ùÚY�± tÚÅg´ ¹š�ÔÀÄ·´!T¡ e®ÔÈØ=¾­¿<~„ªêÔ½÷¶ë€4|Ì Þ.SpíJ­qµ]�Æ*Ði�ÞÆõFhpÂÛ* ·¾^H3¿œ©&c)yüY:­«g«6ž‚tåwÞÔäÇ*ºÕ=QÍûàC­ŒI�ÃÎÓE#R¶YOÌRÆøótVß úû’YúߤJ�~v^;FqE5íþ tòß¾á…5ÒöŸmE4ë£ÏTâZò�R}K«æ–QÍ›ðQsêˆóõƒAE"[zYŽSà�ïêì~è‘ųõáäJ�zf®l'"×�m®×˜¨¢ÑÈ–uàÚ¬Q2Ž_‡\yƒÎ�y½^üôq=zì0Ý8ªDO?ô–V»Y:ö×êä̘œ=º`ï5b¸¼>ŸòiMŸ1³ÍcF�©Ë.¹XÃÜ<sO‰†CJHªU«×jåª ÒKÙÙi-›%KR~~²N©[®…‹›ûP=‡P’ÛÆtU7OCgË^T®¥ W(zfîn,©aäú‡èò›ÎÕ´kþ£ÿ=ò¸Š]¥WV:Ê;é—ºþ˜T¹¤jû%Çq4lð ]vÉ�$i»pmo†j›¸&I=z­½}’\“dd6MÃ6Fƒ‡ôÖà!jÍ$¹±RÅÂ�òx<²,KŽãjùò0``»ûÚkÐY J زdklTØHþÝœ j%$+©Í„ÎÞ¼ÆvÝ™àMyç ½=i¦¬\¯Êº°¢Ût¼vô²c%¦(¥ÍW™6®çÖ©º®yÛöÌìŒ6Ïi«Ècm¬mTyeó7V½r‹.x¿íjbµ522 WV¨®�Ñu;æ×øëŸ×]'¥îô¨ØÖ™·~¢ÆÖßt6ªbcócÊÉËÙÁóäQNv–lm”[µQÕFÊ´¼xá ºtÁoõÄìEzãÞëôæƒ)êÒ˜F�:DãǦñƒòØ- €}iw3Ÿh¹&þã�ºãíe & Ô¼SW� (kljÍ6_IN�jj[úP)mÖi¥g)ËÚ¶]�*ZúP+_þ­.z·íŽE´®ZFF¡�•ªsZúPmÕ±³7ÿÝ‘Àõ»ïO×Oþ5A�½nÉSxšnúù8¥ÆœÝ~ŠÑqœ˜£aƒ鲋$�Ç£i_}-©U¨6h œØÞ Õ$)\?S¶ùR ��Š9A–)¬Q(Ø P¸Q¡`£Â¡F…B …š”à�¨G¯cdLóï€m[ª¬®Tzzª¾þúk餭ZÝ6‚5蔼Ê/È–¥õŠ­]©ÕŽ4dÿ�mj§ëÁk«ÿ, I 9ê?â0�íš­´D¿¼^¯¬Ò)úÏ‹ÚáÚ‘ü˜ˆÂ-³¼žwº¦M›¬?˜¬EK?н××Ê÷øŸô-6)`ˆ/úq«§ë‘ßüI/- +}øEºóöjd ¢hlw—èßôiœO -+}D¶ëo˜`“‚›g´ #³•�$Ÿ†]ú¨>ûúPNX¡P´åª;–ÖF�­¿Ó8[�Ýó¦Ö)K¹ *›üwýùýºë”v2?8NLƒú÷Õe_$I6h€'ö ­ö„Ý‹f‡ ª!ƒ‡ÆÝžŸ]褒F­ÃÒmÉY­7_˜¤êo|½0jœõ„.;÷B]qß­Š~Óñ;á¬Ò”ieråÕ�o_¬‹¶ ºŒêJKÔ´§>^´3•“aKrµ±|c›»AÅV.Óªm_—=êšç•¥˜J6”µ{4Ú^eç«(ß#)¦’ ¥;¨-¦Ò’ŠæM*ò w8EÕJÈRŸCNÔ÷ú{=ùÌ�úNw¯Lýt½þÑ:vÎ`0qÜܦ…zê÷wè¥eåu­»û‡–V¤eC‚xnÛÕdg('Ӗ䨲²RNmœ²uÚàlÓΓ§®Í}¨ kW©¾±AM;»…¢rwVÇ®Üg4íŸèµµ® N¿IOÝy�úyë4õñ‡ôúz'îç„[çº9Ž£¡ƒièàAŠ9»÷ïºëöEx·ckÐY%�Ó…çôU‚åjã'é¶×WîttX¬äcÝu×[Z¬ÒÚ¿2vgL²iRC“‘d)3«�5Ïb«õλsiÿ«^Ûì|õé™,[ŽVÍ[ šíÎÒŒ “T²mŠdejøˆîòÈÕ†iSµ¢Í×TW• §jÖº†}¼Ù9>´‹ÔWZmëz®6.úJsÖ54ïÖùMµìôûFµS×Ýï”Èœ¢.®”žßÕMßï-_ÃL=vÏZÙÍç†[§¹91§yMµÝ=×®2ûQ3ÁtZ>õ9ï:]6,E¶[¥/ú•®ºÿ]Í«Úf(šÛ Ÿ<¡_^õgM(uå+>M¿ùù‘ÊØ�9‘v® òlI1-™³PM­ï‹•kÒÃwè庥ْ ת:ÔžW¾¶$hÄc•f…§¿¬ͬoõZSÙç�è¾�”äÝöAÙêñ§kt’%gÕkºïÅ¥[×*)¼úmÝqÓotÅ®ÐCs"Úw<êwòi’h)¶âMýý¶ù,-¬e¯=­wË\Ù©ãô­ãòeKr«>ÓÝ×ÿA·Ýv¯ž[ܾO^©óªd,¯Š»n~!·<y-IN•*«Ç@G Îz^N(—2�Òµ7Ÿ¦"'¢66ÞlCX‹þ÷/ýãŸO럟¬Þ…½vÄ8¥ÛF‘Ùoê?s¶ê;DÖ Ç_[.wÛ5Öd©øÄ3uH²%gÕzè•åÚvôÈšwô—ßýAW]ú =2ow¦BH¦f²zh‚J•§Ó®¹\cGêsþuú~oŸ‚óžÓ]//Sx·®‚ƒ‰1FápXÆ™Íã)Û/ Éuw¯ïÌkЙ%ôÖwÜ%Ý~››R¦y¯ß­ËÞzT…½û¨8'E¾h�Ö/[ªUÕËVÚ€³õ›[¯Ôa»•ªI² uìIÃõÔ‚é*yëvýÎÔ‹�¾*wÌ@vô`¥ÅyÉäÃ.Ð¥#¦è¾«ôÒ¯/ÑœCÕ°|¯jWL×糂uõÕç±Gõá6½>»à]wÕ4]y÷dÍ|üý`úq:ilOe{êX1C2Ckƒ>ŸöSýpèî®=×>vñ™ºáÒ/õÓGgjÒÝWé²é§èø¡…J‰Uiùô�õî”5jòäë¸_\©“Z¶ë² þO?>ëmýêåùúçÕ—hÚ‘‡klŸB¥ù\5U­ÕœIŸhÊš˜|Ågé'än ÖÒº©{¦­ie¥zã/Pã!ùRúX]ñƒq»²µëM»©Óço}¤RWRÓLýí'èál)éð«õÄ#å“$ÒÊI¯éù©QŽë«ÛMm¯²»¥žÄ±çëâá_èþ™«õò-Wkù±GhD—D…J鋉3<ô�8÷ý¯Â•q[ Ê9A×_=UWüy’f=u�.žyŒN8¤»²¼U®œ¥O?›¥u!Ÿº�qµ.æUÛÉàΆµ|ßݨ�þö¨&THù§\­«ñËmY7×µ{ê‡×�«‰?ÿ·¾ð€žýW]Ú?a'O.Ð,‰¨¤¤DÆÉD%‘QL2ᖠ훹®«uëÖ©Wbš�@ܵ¬@'g¥ Ò…w>¡Ã>{MÏ¿þ�&ÎÛ  KfkÃ’–ûíeõ;\'�qž.8eˆr|{⪶ŠÎüµn+»Sw½2KóßFóß—,; ‚‘ßÒŸn¸XGÄTpþûš÷¯¹ZòΣúó¬sõÈ‘ñkòtÓwn»[‰ÿ|LÏ~8[‹&¾£Ev‚²úŽÓù·]®ŒY¥;kyÌ[E^Ÿö;=‘ó=üÄëš8ã=5½å.ËV w°N¿äR]yÎð-[Íï3~õþîíúGÎ3zðÉw4õ£´p¦ÚüÊp¢~tÙe:tΖ!äV²F_y�îËy\õ3Íûè5Í™°ùNÙ�|�8íbýäÇgixj«äªó/?^Sÿ:AkVMÖ«,%Œê®K.T»6hÛk×XS(knªUéNwz²”\ïl5Þfs?Çòl[µ®a«ï›}ûö¿È½÷n=ùéJMÿeM—dù24ð”ôç+‹õÞ•¯JŠ(5[ÎãºÊ;éwz*÷%=ø�Wôé¬÷õÌÌM׶Ȫ3~r™~ö­þJŠÆ¾)>ÛA�®Ê&<¢‡>ß(垤k¯£€Óê\Æ‘§ïºñÜÉúé ËõÂ=Ïé�.Õ°ø3$"Ѩ***d{¼j¨™­¬‚ãeù²dÛ!ùL±äm”�P/o¸^¾@½£aE"AE"!ù¼1EÂÕŠDÃ*¯Ø¨¢â°eYñuš­œKþbd5gàküÉN^8g†Fzd\€ƒÅŒ)Ÿkà°Q{íün¨F6”©º!*+!E9]ŠT�ºGÒ´¶¯¬ÐêUåªwýÊèÒMÅ™ [å4N°F5ᥧ´ÝLÍxG¡Æ&Å|ÉJIh‰œš>ÔõߺSŸ;=uéã�é²Þm}~ë*Xµ^kKj4^¥f©kAªü�"XŠ©¡t­ÖV4(b'*«K±Š2¿aM†¨+J´¾¢NMŽ­@ZŽºå)y'‹9�åZSÚ(%eª0?C‰,ú@»c亮ÇÑòEóÔ«ß v´¶åKJQ®vŒ¢�jnZ0Â’/)µ¹m´I ÁVS0}IJ ø$7¬`Chëi¢–GþÄ€ÔT¦Õë7ªIÉÊëV¬|L¡°#or²ü¶Q´©^ámÖ¤µ½ ò'x­Ù 5%5 ŸRsŠTœ—$;V8²m¨fËŸœ"¿GrBõ FZÝÛF�–/IIŸ,7¢PcP±í:KžÄdüžæv�!m»<N+–,PïCäñxdÛöVÁW8VII‰¦|r¯ÖÌ{V¶,ɲ7¯·¶%xÞ&š6’,ÉWù=OÔø“ïT·ââv�XëöóG´)KcÄìgìÄ uí•¡®ûêz�\õ˜»Ãû=� eï�OM¨ZkV¯ÑúÚ$ ÓW)©[ÝY²HKc’•ØUÝóÛž!Ù d«_Vñî´Çy•RÐS ÚÓÆ§äÜnê·ã§;žä<õìÝÞÚÀε'éqmªU|«’™·�6ªaG'51E‚õ’�¢¢îi²ddÜF5µŒ–‹4ÔjG+ͺ±�B1Éòg¨¸gVs[ã*ÒØ°ƒŽ"�;8_5šh£wúd9¡z5ìtd°5¿ß¯ÂÂB�|ö:åFE#a™vüšz}>ÉJLLTBÂîM?&Xt ÎÊWtÃÏ^ЫXçÜõ ®“¾ed\p¹^zêC•»¶RF©1ÉY)@'e\¹N| ±ãÊÄÙØ×,ËRBB‚ü~¿ÒÓÓ[�LÛõö­ÿÜk€NÁ;à;úÙIŸéæ÷×êµ›¬E‡¡ÑÝ3äiØ 9“'iƆ�¬Œ1ºò'Ç(³SLí f&�Óž ÈâE°è¬Luýýº·ûãzüÕIšÿ雚o$É’åÏT¿£ÏÕ%—Ÿ¯£»òÒö1’5;À»@çáÉÑØóoÒØócj¬,Wy}Xò¥('/G©�cpP"YÐ6‚5@'äUrNõÌéè:`ÇìŽ.€Î¦#×l°Egÿ]dÄ;`Û9Ž#Ûf\ °¯¸®»ßüÎíUÐI 55vtÀA%lTb ¹£ËØ%k´²iê™eYJËÌRuU¥\×í઀ƒƒëºªª¬TZfÖV¿‹�ÁÛ°,K¶m+)9E�”T-Y0WµÕUrœXG—�'¦Úê*-Y0WI©©JJN‘mÛ�:T“Xc €6m ײsòå÷ùUY¾AkW/—ë8]pÀ±=¥¤¦ªk÷žJMÏÜ/B5‰` €ílzCïñx$IiYJIË�1F’6ÿ `÷µžòiÛ¶lÛ–Çã‘eY�>\#X  ­Ã5Û¶åº.�°m Ö6j�=T“ÖØ¡Ö#iZ¿É'`öœÖ¿[ûÆ­¬°­ßèo Ôö—7ýÀþdü½"X`í�oüì=vGì�Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q XâÝ 9 IDAT@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8¬q Xâ@°Ä�` ˆÁ‚5 k@Ö€8x;ºÀöJJJ:º8(îò±kÐ µç?r@Ç`*(‚5 k@Xc  u5ªª(W0”ë:]â`ÛIÊÊÍSJZz»Û¬´SeY‰jª6ªKq7%§¦ËãñttIˆƒã8j¬¯UÉúu ƒÊÉ/hW{‚5€vh¨«UuÕFõ8D^/ÑÊþÌãñ(-#KI)iZºpž�v�\c�5€v¨ª(SQq7Bµˆ×ëU—®ÝTUQÞ®vkí •’Úþõ¸Ð¹¥¤¥+llW‚5€vp]G6kªp<�×mW‚5 k@Ö€8°}:7'¬¦pLÆò)ðwš‘bkû7¤ÚªzEd+�ž­ß7kRuM£bò)93CIûÙÞ ÎšÉú÷G+ä¤ ÓYߣüN’¬¬ÀÌu]•–•¨¬¢L‘hD±XT>¯Oþ„åeç© ¿P¶ÝI^‘ìºÐ*}þöZç4èäï騢�÷ëÝš…úà­YªV®ýΑfí£B÷Ë’m[2�ìí Á ÇÑ̹ӕ’œª>½û)ÁŸ �Ç£p$¬ÆÆ•••¨¤|ƒF %[…èÄ<=ŽÑ%—ÓÑel§“å|€=eåš•ÊÎÌÑ CäºF‘HX±hD>�Gé©iêݳ¯‰IZ¹fEG— û%F¬Àªªz£† ê«XíKJöõV mœ<[®kägIš¦®yõdUcG—  £„ëUY’|iÊJO�­¨ÊJ´¡ª^ayHÍV—œíÖd3¡:m¬KþTe¥'Êvê.Û òš�b¶_)™ê’›,ßgœE+UZ^£ú`DŽ| ¤f*/?Giþ6µÔi«p¤ £KJnm­Ü%Kå®_/§¢\ÆÙÙ9²‹ŠäíßOvfæ^¯Á)›¡·?X¦XÁ8�w|¶–|ü‰f”å¶:Æ“ÒMãOŸ(_ŸÞòìÍ5×¼9ÊÏölÿ}O‚½–‹)ê´ÑΓ«¢<ßöß·’•“�UÚ¨Pm­B*T’$ùÊÈ(c«ƒ�\וq]Ŭæ©�Q'¦X{ê·sÔ¥ ¡=-ö‚58€eg娺¶ZMM�ÊÈJ×ñÇœ¤�>ý@uuuŠD"*êRÔÑ%�è¢Å²üR8"+#CÞq‡jÊÔ)r]WãÆ*cŒ¾˜i[“sÖ7jÁ²ökeçÏ:`¿—š’ªiS¿Rcc£Œk‰D´dñ¥¥¤utiÀAÅu]cä###cZÆ�µšk¹é+³éIÆu·?™7]™É–$G•ÕjãˆÖWVUI¹ÂF²’3•¹—"3áF5FÛ¼GM�M2’줤æi nµÖ®k”‘­üÁ£Ô;mû¹§¡úEvi^ç@°¸Õ«WkØð¡JNN–e[òûýêÞ½›V­^ÕÑ¥onžÜPXòØrËÊdŒÑ´¯¦ª¾¾^©©©JIIQm]�¦L�ÒÀ••Éxl¹¡°|-»†nfg©{·Y2ª_6_+ƒ;¾®i\¡KjåÊVz�žÊÙ“i�[¡õem$k¦VeaÙJÏÎRó2lQE¢ÍsB‰ÛÏ>u«µdI©I»6¿µã1p‡�?\Ÿ}>QsfÏÝü=¯×«cŽ:¦ãŠBžâbEfÎ��œ¤èÌYò÷è!Û¶•™™©qc›7/øzúWòû¼2ÆUtÆLY>ŸœÆ&ùl»Œ‹GCG©û²‰Z\©‰¤£G©W†¿U`å*X±D_Nœ¦•A#+¹—ÆÍU›{ÄË„´bÖ\ )¥ÜV›×ÎÕÂ*W²³Ô³{FsMV²R’-©ÑUeY…¢½»hs·Q«¿üLóBÉ Xu ÆÂ E%íû�>Û…` pƒV�î½uùUWiÙòêÓ»—{øa%%%vtiÀA%aÐ@5~9Yž”dYåŠN�¦qcÇI²6ï¼yØøÃ%E¿þZni‰L I±pXiC‡mw>+¹�Ž9¾Nÿûh–J*æëÃW—(%;GÙ©yMD�5•ª¨ É‘d'uÕ¸W¯Àž}LvZ7u×|½ýF¥ú÷éªÌ€¥`Õ-^²N ÆVjÿÑ’Ý2DÎJU¯>šQ¾Aõ ?Ñ£Õ+×/§¡JV­R‰ÓMÇžT¤¥ÿ�¨ÕÑÍ�6O*ÊSמyê¬ï^Öà �””¨çž|¢£Ëjž¬,%y”š¦LVBf¦b³fÉ]¿^ÞQ#eå7Oõ4ååŠÎœ%·´TvjŠ"ÕÕJ>âHy³³Úñ~>œsnY?ºŒ(ŠbN„ª²Ê*#X† _Jé©I‰�úYÃÚ4“I3ÖNÌEßAž V ”âÒ*,ÃKjf&)‡xú¨®`ïÞ ‚Ž z¾Ç~ÙáU~¿çˆ> `Ù¯›Ïu»ý9jki±&"""""""reýð**ç}Eù¬™xRR0¼Ì´4ì@«ªŠHe)§�NÊÉ£¢+ªnüéíð§7cãÁåK'ÇÝÁ O Y¹)�¾oz|¤x}»ÅPaMDDDDDDDäKyI½{Qµd ¡�›m߀§}Þ^½I4¸ÑéŸÒr¨°&"""""""r¸²²H=úh7CšàHNSi54bMDDDDDDDDbâê8œ‹.„ãò“ц‡m©°&"""""""ÓtaY.Ws€ˆˆˆˆˆˆˆHk”šžAjzìÅi=4TDDDDDDDD$*¬‰ˆˆˆˆˆˆˆˆÄA…5‘8¨°&""""""""ÖDDDDDDDDDâÓSAës'Qíiq Ã8¢ÇST5ëè…Ê(, â¸üde¥Äs±[ŽÖt.-J+ˆ'õ�æ£k+""""GU+ÈWšªÕÝ“‡(-,%€IJF6)žÚ—[Ûy9±_«c9®B{Ù´f k·î¢¸2 n?¹�èÙ»ùí’Hô²Œ¡/ŸâÒfîtÏ¿r#Ú3‚EY¹z[wí¥"lãò$“žÓ‘½úp|{_tãš÷ ß¿ïÍr.mXKŒ'§œ‚µÛ)qÌäöôì’yÈ_m«o(îDDDD¤ i ùŠSÉöõÛØk5Ö—;‰”Œ:´KÆ•àÃÑ{òÞkŒd:æw!3Úv…¾â±«ÿ—éÁŽ\ñäKÜ> zÃæ­_´nmb�5«x“_ŸÄ-f[¥}Ð9¦�¼AßáÒ«®â’sñ4¸—Ø9.7nÓÄv»1�¯�]Yȶ=6™Û“Ó·àP¹þc^zþ5>X¸�JûàoÄ0“h?p<7Ü~zúR0tLWõ~ ƒc³´D-ñ:†¾ùwÜñ[m0ÓÇðÀk¿â;i�÷¢c©o(îDDDDD¢×"î?#ßðÊ�÷2¹ô0R0L’²ò1ö"®¹òlú¥'柼�è=y´çZ—g¿xíQ.iíùšT?ìÕÀ0÷ŸOóÔ/Ú†V>Ô¡lÅ›üî¾IÌßcá>Ú÷ÊÈzÑ)Ë�(edžå|õõ7,™Â3Ë>ã¿ß»‡‡|9 ˆAï¿ãó9€&±?4,Ö½õk®ÿg ·Mú3—uˆþ`�U¯ó‹»^gY…ƒ¿ó0.<û†äw$Ãg)/dÓêùüwÚ¾]úýb¥Oü‘ïç'¢Tè4ògiš–v-+™?å ©©.*Êæ2yV!£ÏË9ÄH¬c¥o(îDDDDDbÓ2îAMÀ$§ß) éppà –²kÓ·¬)XÇì·cÞg_sÏc÷pNÇDŒ_;²÷äµçÚ®×púµ�¢dã>ŽÎ>ˆ¯mξ횣~ÑV´ê© ÖÖÉÜ÷›WùªÄÁÛe ·Ý{— ÎÂeÙ8`€a¸ |->ûþØÆ´i‹øQ¿á Žâ¬=Ã4mžÂ}<ÏÇ[ûÏÌ0Iïu.wß £óê ÅŽ¹/Æ�–⮉۵¶¸‘è4gþ §ÎŸÕ&Ç ‘Ò§?]]_²Ê*dç 'ÇE|y„«Þ±8º½—Åo=ÍŸÿñ›XϽúÞzôÎ�— #†BQ´çz(‘‚™<þÀÓ|¸®{ÂFÚñùåoN¬SÛŒ¸ëqä9­-¿hQÍý`ò‡\xþÅlܸ‘ŠŠ *++ „B!LÓä±ÇþŒËåÆ4«#ÀqÊËËùõ½¿ªWX³Ù<ï+¶X`æžÁ£üØÎá:¤ƒåÀùãºòÞß7Q8o.+ÂÃê£æx®†×™2Ìš×�šùÐ5êlWý²›ã/¸ƒ{{Í㵿Ng#]8ûÇW22ÓEJ~—Ã?MЗOï®.>[W¬7Þáü¾ß§jÃêXAU ½Q̬ÇÉý3vã¤õæÂÀø¡]ɤ”M‹¦3éµi,z÷a~^ááowŽ"óp¿ìþýà}¼° O—S¸îª‰ ï‘�7XÈš9ïòò»Køø¹ûqç>ǽ§eîà8·3’|$nå½g°!}gŸ}™É}ÉnãS½ –ÞMfÇ‘,½‹î#ÿóöÁ¥Ó˜¶ÙÂÌ:�sGøÁ�ÎKçÉo²mÖtæ\"cÓÑ!"«™ôÀ¿Y›5ŽÛ®=™>í<”lø‚·_û€%k&ó‡ÿͥ듗ӳö·Nœ}1öxTÜ)îDDDD¤­°ÊÊ(·ÓOJ�-Ž;¯oŒSÁ¢Å]o­'”Ò“sn¾Šó‡÷ Ñá!IDATÃ)bݼɼúÆL>ù÷²Ûú3O\ÑóàrÍ%´šWïÿ ¬ ãËËu×_Ȩ®Éw®âÓ·&ñðƒipF<õ‹xsºV–_´¸5Ö’““ñù|X–…mW�÷p¹\¸ÝnLÓ…ÛíÁ媙¢iÛ¤¦¦â÷'×kW� k·baàí=�>†]»è1h éæ&Š‹7°n�ÍÐ<£~‰úà}E3çÚ“Üþ£™Ð¾”)/Lg#Ù )#¸ãÏ÷rQ; ˺ÇàCȹãÇßà ­û÷ƆqnûC·; hd1äì2lâ5¸Œ»Ö-gé’¥,øz.ŸÍ[ÉÎÝKyY²á>ž¾uXõb‰‘b ÷Ø€›œœ,Œ�k��•�I!vq1{mȪ_V?à8Ø[˜7õCþóÅVn,`Oi�p½_,f¶«i¥/›v¾ƒ_?æ4¡ýÁò5®}ŠÒmïÓ}ØÏp";0�b #D�¡?gíÇ'“Ñå"Úõ¼�¤ÔÞ�ï(´’)Ó×!‰‘Τcý6¥ŸÂy'§2´˜kú�ÀßÀnŒŒöäx>§ŒÌ Lvb—•RfC;«9úb�×ú»â® ÛÕ´²µÄ�ˆˆˆˆD§%Ü÷Õiƒ/3�œúOÚ •²½° ÛÌaänâÚ‹F3,B!«ñæÇ’G4´�µ—Ý…ÕE» oÿ–Miø_ÅÃ¥Å88öRj±©•Cµ /'Ýñ2Œiìžµ ÜI¾ý9†UÊÞ’êÜ#+3µÁs02²É®mncuŠhê ÈsZK~ÑâF¬UOítí+®™¦IÆ‚ä‡v‘7è8ö¼±�e;Š)�|Ë›žêÇJ Ì΢ä‹É2¤z'f*�:¤`²—ò-Û(²‡‘å˜Ë`ÁVvÙ`x:Ðù°½þ(rl¬p+ `�Þygv˜‹®á®²Õ¼óçûxüÓ6~øo�{Ž{»€È¾'£zÜ.ãòTw '!r˜î”,âÙ{à­µHÊ¡ï°Ó8¥Ké~/n·cÇücê* Ú®–áö´¼Î{„X¡bv¬øå»?"»óPúŽù_{ÂUsñú:ᄾ¡]·‰¤åa÷†·Øøå¹¤æŒ§Ã€ßãòf´¿ÊÓ˜¾ÝlV¿~W¾YÿK7°ÊC8Ø}6�9×笆kãõ6ö¼LÜÞš>¶júTâû⡸k³q'""""G›‡á·¾ÄcÓ¼§¬àÙoãÕõElÙ›B�L›`ƒÓ/ȉŽ88v˜p¤‘ÚAr.]’Á�á�¹väõ%“š’ÜhþP§1û9á}S?]nwÃÛ&®¨žÎp8MÏsZK~ÑâÖXƒý£ÖLÓÄSRBîŒ º.ŸâÿîÄÌs1æº|¾xe Kq'§}<£æÇì‡gÊ—„Ö|Íü’s97ª9d!¾Y¸œ*\ùéŸvð îçbÛv�éo ÍQ®}½þŸ¢›Ý}xŽmcÛÞî\üË_°fÙݼ·{ —ìÀêÝ ÓHÂ_3ö4bÓP�ÚTUª‡’ú|$Õ¬O×ð¹„XúÆS¼½6ˆÙq<<}7ã;¸jCwÀ�ð×»ywZu¢î4y»úEô–7ã?VñœÁšOFáOÍ¥û —b˜^¥®ôàõw'bV›ÃÁضCV—ÓHÎêÂöUSXóÉHŽ;c:Þä:s=�bfNý‚bÛÀtCeÑN*9®Ë4ˆ”Ïgòg»s~ûƒ×º  : �‘C X=×Þð%U÷©¸ûbSâQq§¸‘X´Œ;¿:÷ñ‘J*+Œï§�|®ºã">¾ã¶L}šçN}Š;‡§Ö»çNp^oøHöx|ý_yæâv‡.€YAªá(®fÝOØØŽEa­ÃCRÍh‡P0„�ÿ í�ªJªìýwúq×/”ç´†ü¢EëŽV3].‚ÎÙExežöI”<´gßg ÓÀê�ízÔÙƒAÆÈ39)y.ŸW.ä_¬ã¬ØùÌöžY¼;«ÛðÒìt5ª÷eÕ�ëXV߸]º—½Í4u{¿EV²tåZövÃC³_øÐ±YtÎ1a·CU°º#cæÑ©ƒ vDØ^°‹¬:€ÅÎí»±1ðåu8ôPUk3_-Ü…�›.»†ÑY!ªªh{¶PQÿšÅ»�Ðÿ¬l˜÷c¶­üˆÌ¼¤w8ƒáànl+Pý„OLW%;fQ¸q..O.ýÏú?ow{gµ >eò‚J³#W<ý:wžàm䨫ÿv-?|yK¦}Êæs/?ø!¥;ÙpÀSÿשEÑ®Bl <írhgÄÛ�t<*îDDDDDZ4ÇÂÛÿj~qîçüâƒüçéIœùì­ŒH­›—$8�pµ§K7ÆÖ[6RV‘Ô2Š+f&9Y&ì´(,,Ä&ƒúÏV³wn¥ ëÉ':Ï9†Å~ZN3þÔ¨;”ví(™0‘ß”@²�ö—wgC‡$æ„ÃÌ ‡™ ñɃï¿ïÀ}¥�ÎÕvÅM˜µo?Æ _—T?²µ±Ÿà6&?ñ _–Ù˜yã¸aBÞ¾÷<þ$\8ÅÅ”DêokS´x!ëj;f#çÔØëNÔ×'Âòÿ{�û‰§Ÿÿ�ÕÁCÞÙ»Še[-0¼tî’‡éF6ƒwÆ…ÍŽ‹Ù|й¡Õ|½´ÇðÐop?’u.v€Ê 0ÈÊHƶêí+¼™�¦.«^ÝIÀvõù5g_<Ôq)ž¶xºÓ÷¬Ïè<ð!öîÚÍú¯^ bïV0ÓUm#�’ÝKY3û~ ·¬ óàGé{ÖlðtDZìúÔ·Ó§³"äàÊ?› =ƒT”•5òSI—±ç0À ‘µ3˜²2tÐõq"+YôMààöZÛøfe6&Ý{åãkb_LD<*îŽr܉ˆˆˆÈ±áHæ\ÑÜ?6vny~ýmŒÏ5°¶OåñWSaø™„æõd0xH\Ø|5Ÿ á†Úe³gÕ|–n-¯.ä%è\ùcäÑ3?›­Ë×P\ÿžß±Ù²p![Q¿hJžS×Ñî[‡ú¢G½°ù[oÆÓAíSNaOÏžìÎÎÁÚ–Å©WÄß»7×VUrEѶ^~)YC‡¸/ǤÿÕ¿äê>~nàÝûÿ‡ûßœOA ^t¡dýLþú›»x|^1NR>—ýê&†ûöÎÝ©;]\`—|ÍÌeå8u¶�ìø”§ÿù ¶«þê�÷ÃåÂmV…EõôF~’9õŠïÒÓ á ïð»ß¿É×»B ~6´ó+^ùãߘ]æ`æŒæ‚‘É5íéyöy òDÖÈ‹ÿÝNä€mƒ¬{ïu¦í´1ÓGqÑèìší‰23‡Žy&aõ’TÕýld_<ÿ'Þ-Ë%Ã'°—½µ×>ÞíŽj6—ØÛbÛU•å¤äžÃÀñó9îä×(Xù"¡rÂÁ"Â�]|óù£þÎÀñóIÉ=‡ªÊrìú•”àR&ÏØ‚ex8q,ÝwìÜÑœ7̇aogÆ´ÅTÖ»>†S§oü‹UUu_·)žû/&oˆ`¸{pæi]šÜã�GÅ]KŠ;96Éœ+šûÇÆÞ·±“Gpëͧ‘eXl›ò/.®8 Wˆ?¯oèøÐuÜ O1°6¾ÇÓï¬=ðþ‡Ðæÿðèïîç¶ëÆsËÎ!â;×Cý¸|ÚH2L‡Ð’÷ù¿eeœghÛGüí_ë°ÍDÔ/š’ç4|¬–ó›8ÖX;2jŸ êõzq¹\D®¼’Å�>J7kî½UYáP�`(€e[D¬ÈA-�¸Žçú?=„ë�?ðò‚­Ì|é>>{=‹üÞ=é”åÇcU°sÓZ¾ÝVBÈ1peæG÷>À�z×jt;ƒsúþ“o—ïàÃï¢è¬Sè×ÎCå®UÌ™¹ßÅ×3᣿ò^¡ƒmï¿F ‡�Ö•Ù&_íØÎû�=HùÐÂÏ«&2æøB{6²höl–„Oá�?�Ä´[泪żýâ{DNì˨ÓúŽ]ÚAWåØÖ”ö‡#a‘0ÞôQøÓûR²ý ü™íØ³í¿øÒûãMEEEy£G.™ûŸî±1ü'rþ™9~f{*gLų_}JÑìé̾n8ã2 ÇÁÌn£ë~�;n[Í9ß9‘ül“Òõó˜2m!;7�&ÞÈ%]Ù¿°fœ}1ÞxTÜ)îDDDD$6-ñ¾¯Ñ69£oá–‹xxî6Þæ5Îxú&NH®~;áy}ÎYÜõÓyÜüÈl¿r×.ÍØáÝiç±{ÃbfÍZÌÖ€‡®çÿ”k{pbZ®&ÌWÏÜÀÅ/D³ÂšIÖÙ¿âÿÝ07I']Á5Cæðä¢M¼}ïÏX7æ4Nèä£jÇ*æ|¶ˆÀ¨ï2nÙ;|´ÛÆijý"yNC?ÖÄ> øœ±a¸Ýn|>n·›uëÖÑ¥kF¼ú2ÿ}ð!<;R8é·¿¡¼¢‚@ ŠP(Ôp»‹HR®ûË$¾3ó]^³—meݲù¬«=–é%³û‰Œ?ë<¾Éhzzz$_G¾÷Ûß°ëÁ'ùײ�|þÞF>ÇÀôwää+å¾Ë\¼>Ó'Týô‘ÛÂþ×]øþMã˜ûÈt6oœÇ ’†uçG6‡C±É{/¯õÍ[oü›)s–±yõ V×½x&Éíû0æ;pÕãéŸ"Tw¹]/z�sþÎû�/?}›UŸÔnë%§ß9ÜpóM\>ÐO$\'ò‰²¼‰÷ðÇ]ä�o.dÅô7X1 ÓO‡aßåá_]èŒyWaù+KX3õEþ²äž<¹ƒãÜ®O£Ñ~ŒJ@û­H„Žý~É–E?!=·3å{Jè>ôa¬Hýbsön>�úe¶IÆÉã9=­‘~[Oòˆ Œi7‹÷ ¿fʬ݌½ =‘`Û3£×<ø=ŽûË£¼ôÚ TÔüÖ4¼¹ »ô6î½qÉvdÿaâí‹ñÆ£âNq'""""±i ÷}1TaœHn»†iKŸaáÖ)<þ÷SùëM©®­Å™G4v/lÙ´÷;^É}‹§^x‡™‹§ñÚ¢š÷ î οéF~rA’Ñè.¥³ÿ¡ŠŠ¢Ù#híÀà8øÞïÅyüϼà8¶mcYëV-ç¸Þýš­17ýän½ù6ŠŠŠðz=¬^½r'�AJJjõbƒÆþŠ­eY„Â!žxü ÿÓ_±gÓ“„×ãÁ°ËصuÏüìa¦ä_ý<ÿ¼©F8D(ÞWA=ˆé!ÉŸDhÏ6í,%ìÉ s÷Îd™AAoj*Ó&\QF°v¾²'™T¿ì Uå¬v—Œ'RÌÖ�å�’EÇv>¬@(ªþd˜ïq‰Ûo<ê|¯¶mE'ñôŸâQqwÔãN…5‘–©eÖ/¡y}í> ³:OÀÁqlìFGíAÜ÷[�$Šv_‡É£–çe±ÖZÔk=ó{ò�7^gOQ!³g~ØmlÛæâ‹¾C»ú\r5§N{„Ï‹¾ä±ûŸ#|ó÷8µW&”Wbfd“ÚÈ•ql«�Q7qrìFF¶Ä²‹¦µ&açãØXÖ!öä4RÀˆw»V"‘çfú{Ñ÷;ÿÁð÷¶ŽrÍÿpßkƒ›ÄÞã꿊»6w""""�ÖzO˜Ð¼¾vŸŽ 1æ@Í.޼ì�û:L‡hŽëz,ˆc�µæ ­ßÞû[ÜOÌÛ…‚‚�@LÛ8™grÏoV±ýþ÷XûíT¹sjõžAüìå¹87ަŠÄ*�ñdG"¸SO<ôÚj""""""Ñ:FG‰I±ÖšQUeÅ‘;˜!uØm¼ò÷3˜úŸ™,\_H%>2; ePº¦%ɱIE5‘#'ªÂZk]ÿƉTa§÷ãÜ áB³ú;|ˆÅÇ¥­KD,´Öx‰•bADDD¤åÑ=šHµhc!¦k¦é²,L³õL“t¬0¡ª0¡£Ýi±lÛn–>ßãIäpš+žDDDD$±”¯H[u¾Róà‹˜"ÄçO&p$§kŠ´�ª |þ”„ïWñ$mQsÅ“ˆˆˆˆ$–òi‹âÉW[X«úféYÙb7ñ‰x"Ç Û¶)*,$=+û€Xˆ—âIÚ²DÇ“ˆˆˆˆ$–òiËâÍW¢±f¦i’œ’Š?5�5+–QR\„ei¡ti�,+BIqkV,#9-�ä”TLÓLØkŠ'iKš3žDDDD$±”¯H[ÓÔ|%ê5Öjƒ«]N^�—Â]lÙ´Û²ân¼HKeº\¤¦¥Ñ¥{>iY /(ž¤-iîx‘ÄR¾"mIS󕘞 êrU/Ζž™Mjz&ŽSýèÌÚÿŠ´u‡|š¦‰iš¸\. ÃHèSAOÒ4w<‰ˆˆˆHb)_‘¶$ùJL#Ö :¸LÓĶm”´jµ�UP‰±Š'i;š3žDDDD$±”¯H[Ó”|%êÂZí�jÿ[÷ 0iMêöíæ\`]ñ$mÁ‘Š'I,å+Ò$"_‰©°Vÿ@µ¥$IZ£#ѯOÒV¨_‹ˆˆˆ{”¯H[Ñ”~sa-Q‘)žDDDDD¤¥R¾"Ò0óh7@DDDDDDDDäX¤ÂšˆˆˆˆˆˆˆˆHTX‰Ãk¬uûé ±ïÁ±Õ‘#Çp5is�X‰Cõˆµ¦Œ:kbeODDDDDDDDä¨hâLÌÿŽtµó¼ ëIEND®B`‚Solaar-1.1.20/docs/screenshots/Solaar-main-window-offline.png000066400000000000000000002123371522022367600241170ustar00rootroot00000000000000‰PNG  IHDRQ‚°IsBIT|dˆ IDATxœì½w¸×y§ùž nN.r$H$À F*˜Š–õX–¬q’fdÙ²-{vv=ö¬ýìŽwÆc­-ÍÎxÆ;³+¯Ç»3–5’-ÙV %R‰QÌ $H0 ‡ Ü»»Ò9ûGUõ­î[}p�ô÷>ÀSÕU'Wßîóëï;ßQä0ðÉÏ™¼ë‚ ‚ ‚ ÿ�ýóßVÍלì‹T<�ÞüñKÕ&AAA„×,k¤Œ˜ªŸ |òsfìM?{9Ú%‚ ‚ ‚ðš¦ÿ‰/Õ…”‚X@�_ÿÓ—·U@ßÓU?=÷CAA„×.}Oÿ£þÛªîΧtx9ÛsAdÝmoö2¶DAA„7:jà“Ÿ3“×üÄånÇ•:êçvMD” ‚ ‚ ‡žç¿–P:¸Üm¹ úŸøRý|jÏû.cKAAAx£‹¨èõëÊ�î|…©¡ËØAAAÞèÄk¢^Çë¡ i=×ë¼/‚ ‚ ‚ ¼¶IÜù^ßÂ#ëÎ7³ó­—±%‚ ‚ ‚ ¼Ñyùó•†_¹Œ-AAá�΢–¨êàžÅs›棤g^›Ô"÷Z¡r®™†ûÙÀ¯w«š ‚ ‚p~ì¾õíõó(ÒØ¶U?ž/‹åÏÞ‹" °h]yeU¦&>sŠêì4v\ô~4—ÓªÜæ¾ååÉ^¯ÎÎpî䱋Ö�åäoÕæ•Ô�÷<òH,Q­,!x” §ô¼ñæÂüõ´öâåfK‰|Œí.’Â4¸óU6^·ì²AA„7‹MöS²¯ó&ÙYšR󽿉y^ÍeeËkžÐ§sò¥ú‘׿VÃv Kö£Uÿ—ê[«1J1϶•ô#¯þ<òÆo¹mΦi•7ïzk�´Ôš(-,Ì›¥ðòX³‡AU@™ycQ£�hþº‚F‹’ŠóÍW”\ÎdP©SµCq µÝïÀ”:QQ€±Ýú1ëÎ×~ò©–�AAÞ¸T#(Ó8nžg_§Â£­ÄWó½ô|11°dš ZŸ“/Õ�¼óB©DéÜò—Ê{>é›û…uýXŠ¥Òæ ̼v.•@‡AÃóÈcÑ5QJ7Væž~ûä=xWmFwí4X‰ðI�"#€’ VÓ}Ë€Éä­‹ÄŒÀRó÷­éiJÏþ_Dýï"Ø´¯® UdÄ×ë}— ‚ ‚pþT#(Û>¶[¨ŸáËD�ß ž¢À'5:dÓgϳF‰ôzö~ó½V¯³×ýZ�( ãI{6LÚëG^™ÍF“¥Ú±XÛ[µ¹UÛ- Ã¨ÚLÃ||±~,§½+íG5*PÐùm_ªQ‹Á‚2x,®+–°D%"JY¸§ŸC�þ€ê�W�Ý䎗Œ–&#¬ÒƒÉÜZ¤ ÝÕIõ-{)>û îɈ`óõõ{Yw>o`×r"‚ ‚ ¼A©F�J¤…bÃÏ=6ßÏž¡,»áºÑ¡Wm¸¾TyK]ož“·êG«2›Ë϶»¹/ye´“¥ÒD��叨‘¿¢~ä•»T[–z½Õ\~:&¶[Àd 5KZ¢Zí­¤tˆ±¬Ê8öñoS½i/X ~{+‰QJ&?oVH³PTY6ÞuWP~ð^¢¾-˜R'Ð�¯óÕûWÐ AAá�BÍÄ®MíÁ Æj| °ZÜÐZcYVý˜bôÂe.‹]_.: pƒ9Bt}N¾œ~,—¼ö�O›•e…¶ãÖó§c‹2oÞ¥ï"ô#¯=ÙvØŽ[o,ýœ›IE1€_«b³èþ³K†8W:Ä}õGxWmÕ¢!9$kzÝÑžˆ®E¢òiƒ57ƒîîJ» ¨VX oßV Ïÿÿê÷ÔÛXoŠ¸ó ‚ ‚ üƒGëÖk`»—½¿Tºå’eÙ2-ËÂdbäÍcÏ· ­ê\IÞ¦†±8inŸ˜ä¾eôEéGN� /ÓveÛw~ýž×!ËpçË�<¡¢c;X³ÇÐ];óKÈÄ (=÷2VµŸ¨÷ Þž+â5L&KÅC¯`·¡;ŽS»þ*(¸ 5W“«ŸîéÄò^Š«×š¾Œ;_й®egAA„7.^ )Zñ$2�§l…-�Y–J«lgYegïD‰NŠ¢Æ>˘àAêxZ‘�y¦“ææcèÕ°›æ›­Ò6óÒGaHº:*{ÞL«² qNžíG:Ñ�§I´:oUïRùšû²Üö»‘‡ç‡‹ö#/ˆÍãØJäÔÛ|=ÍŸsû–s?=LÈXN?šY4°„JK,¶ð)¹ÕöÔAtÏ›©Þ|#VXCé�hû›)¾ô ª7^ÑA/vÙƒÒK'·~…�Rþ ?‡sêî£Rysó~O¦AÇ)ÆrÀèFw>ÙlW„‹€S,³©¯��v—²¥ŸÉÙ §&*Ì\Ê�ÕÎGî'ùü•èq>÷‡Ãž^wA„×;žQ•¡jœe,ñȆåΣflÚ]Õ0ñNi~Ý\ÞReÏ—`צÐþ|HíýÈ”zµå¬î—ÑJËóŒMÁÒø~¥u?–Àvœ†¾�ÌÞPv¡¡ïY!”4ŽcArôZô!-?ïyzQ,n¬L?òX<Äy²S#Mö‚u½ØžÁ kó{8•»�-Øã“D} é­‰I”¿ݵ¦¡¥5ÁÚ>š¢L,l›1X¡@ïs_¯_×n¾ÕKa¥{ÖóSwìá§÷oæ¦õm”rŒñ&ô8vüß~üþË�NrlyA�Îf>} J‡¨ì³!‚ð�0Œp–9z!: °’à%…ñÛ¯Îb»¥zº44yš¶U‹—â©Õsò¼~ä•�Ë©»fl Q Ëq—ÝÖ•°œ~˜(@5éŒ4°@©X¤ÍÒì4£Ç¹L>¿ZÁ²aò: Cº’€[áG /Ô-ëË^KÇP‡!nX!ÈéG–Ö¶²ú ±¥¨eÀ@°yîí߃¥«±•ˆv¾™â�ÿFåm=ó�)´¡tàáÞO4ì÷¤tˆÿÁ¾ýqÁÆ4Y°ê]Žÿ%!³î|}Om©. ‚ ,�ËÕo~ÿå£Wreiñ”Ê)²}çN~mçN>qÇKüöîåËg/,R“ ‚p~Tu¼÷hˆ‚JµrJË'º)xBÔ°Ý¡WŲNŸÓô©(É+c±úŠÆ'Ì(´('¯¾¼ûy´;°¦a”C-Ò̲° Ëq‰‚ØXa»Å–å5ö7ÄøµÆ½®ž‡�e5ÎëÓki0ËRuQÓfiËŠvGáZ†Iì(`L©y^½ e»” è*è+@{¢ÖæB87ëááÖÖC,œ¢0Ä)–믳eÕÏ—ðn[ZD-×=β¨íÝJù…{ð¯yo=<:€Y{+…#ðwîÀ=vÓ{c] ¥i /þ�Êu[“ |KT*¤š—d)°B£,qáaQl¼ù�|õçv2h&âì‘Wùâ£ÇxðÄ8'§<æ"E©\fÓº5ܾo7¿e#›\h_%ü™ˆ‰?º—»g/w?Aþa…QPX¦€ÒQXF: _§ ,‹2KÕ£é™L·4O*ÜŒ‰r�)éëº8 çEAs_ê±ÙŒF%‰ùú2b"EÛ˜… JYtmÖ–`{gÜ–³UùªaŽXt¤uÄû_ÅååÕ‘–JY£çÇ¥i×ßôy›ÄR}ì²ã¨ ýXW.°³Ë¦¿¨@)fkg J•ˆ¡fÂ�M‡°­»@O6” ­hc)ÅXM£"E4ç3™ b* lÇiuó룂e‡_TD­TœèžntñEìÉ3讵õüÑÚ]žwèeÀ ¢2þ5{갦ΕϠ{÷Ðì¾—u]©¯�J’(£6Ûw>A.ˆâ&~ó'w$ªÆ÷-~ážafš òÓsœ<7ÊÃ^ä ÷íãÿùõ7sg·Â¸ŠßïKÜ÷Õ!z­ ‚ —ŠTh^7±:¤¢(kMJCb[¶S¿¯›Ü¸²‚)¯žì1ŽëÖúX/3y>8ELu.·üº°ñcq·XBY¶?Gè–ëé‚d½�[,%mžRʲhw`�ã³¾\dm1¾nMæü8¿í8tn~£5]?¯“:šå¬?Òa8_,Ká×b—=§PZ°‰±Ñ%" HÙÒôz‹¾6PrÙ@XÔHeLo�º€ê(¹´;P°Ú(J®��DÌ[¯–õ†o^Ö,›YÒµ$Mï©ÚU[iúAü«Fƒ�8+F>`ÇG£qN>Då¦mKT”¨ÈtÃ^‚ÑâÎ'ªQض�w÷ÄŸ5Á©üÎwsT³'ð_Yǃ¿tk”Åö[öðöo ñQQ‚ —†h[“¢(¨ ¤ ³Öîu”·ÇPºykzž—>oƒ×ìysšæc�&KT¶aÔ¸ØV'æBll­&ÿN¡PCÍ¢ à:¬ï,1ØfSJ@ɦi†fý¤Í�� ŽºW íúµTÌ5§³ˆr-j©u/Œ~)Æc4ŒõœãRÒú„¡…ïºLUj”ìX,ù5MO!nSwÁŠTÑa¶ÚÐ]vÑaH-ˆ¨F`5¦C‹’Š}>Näµ´ fY\D¥Í,Þ¼iO'S*ôأLjÖì¨ïô«‚Öô0( ÝÞ‡)”ã{v{äaÓ¶±ECš,SMqçaµèìï¢/ù¸›;5‘eÆl=ð¿ù×g( �óÂé1^m) ,ÖlÛÁÏܼ�·í`Go‰Nüj�ÓãrQqœpM/(p†&±æº ·Ý�ië‚  ®µH™-êMü1Å�O„Õ"Œtýã®ÜÕF§o KTœq‚»~0±xšb??ÿ3wòon飳ùc­½Ìà@/7_zÿ8_ýêwù玑ïܱ8…5»øßù>¾©ˆ•SÏú�>nºæJ>ýžã|öO¿Ë:ê· ´:eÙìØs?• A‰‡¾~œ=ÿ þ亶ÄËð³§€"¢A¸0"?ÞO4±~XŽƒÃe�†k­ò§,·ÜVÇ( ê“öøÕz‹õ#ï^z À #¶¯Qa‘Zûò©( F¢¨¢EhLC‹•Ý\@A5;-Î÷#;^Kõ˫՘²4#%E‘%B\×e&ˆ¿aºñpËqÛÕEV§«´aÖ�š©15çQÍ írž¿KÄÒv¨å–X¦š¬§÷< ÃÁ•;°fDZ�ÜEå†�˜ÎÍq€ ‚]ÛP• m�ßE´ñÝDkwâ:„¿­†io‹Ëi™¯hÂÄÛŽ¸ó ‚°jÌ�ç¸ÙÆn…+÷ó[Wãw^¨rÁAÄín>þ©òo¯iÃVÍ�òõ^äîà yÐÑÓËÍû®æ7 Ð[êã£?ûAºôßðñM¯HX¨ÒFþ·ÏüŸ´PÀì¹ã|åÑã~£ë^:Y_î±Õy^ºó)?{´‡b0G p³n{Éy6*ÞrÚ›&%Ñá€UŠ-Iýèi+Q° s¡Âµ]JƧ«Xd mÞµPG³É¼˜†²ÓàY'°z�ÕiX¤~­‚ã–5~U,&ÅÉ)�0Òlë)A C�åh&LDh€¡jNÍj†f&…ƒúÚ+£#"?>oõ<<Ï_Ø�,‘=i{üÊ*/Ü@… #¢�oea}€ÊuÛë¨�Žvª·ì¤üðƒ˜ÝïG¯»�¶‡î×fá¾P C•êû¡à4ÜWQ(î|‚ ¬áÉ—øïÇ÷ñ/·;(§�_üÕ�°ý�ñoï=ÌãáyNô›o+ÿ*PÁÈK|úßÿ�¯�g¥Ù)î~ì qË�|ó;Ù`µñîßÎO>ÿ¾:½üz¶Þ~ŸX‹ïÄ“|øß=Ê“ nv¯ðÅ{_äW>óa~ÿª"V×v~óí|ýë#M¿®bYÆÌ/ÞUm|àŽµôžyžò…ñÍùüaõPÙPÖ9�š_g�Qàc»…†¼i„ºæ¼iÚæcsÚEÛjYD¾OM£ˆ¬4($kWÒþD�‡íëçYëÏ‚rU�¯¿`³®Ý¥½÷¡§­D!n[ |«@§kÓ¯4û{s]E"s¾æÜ\ÀH5¢PNY²×ÒèƒUö#ûUm>¶m7DÝk�/•AS?òXq` ¥5–3HxÅ»âFX*çÍbyUtaÓ¾eaqNLGº§‚ªÍb:×]õS éŒea…>Ú)à¾F˜Â|“ÓÐèâÎ'ª¡'øÂ_<Ì[þÙ[xg—B¹�¼ë=ïâ�ï~gO qÿ¡3<|xˆGóÊÌ2­'ÖŸxç&º`*üí×äãy_²šc�=ÄçnÚÌ¿¿¦€Õ¾•_¼¥›¿ýîÔò¬QªÀÞ mLUCœ2ÜïžÊ[§Lð_ï9Ì?½rë”ÅŽ«6±å›Më¿V³, õ¯ »Ÿ[7Ÿå_ýÁƒ|sD6 áâ�uçú G�G+™G�ŸŸ.çZš¶ù˜Gù/0­³l|j&Âè°=CÜ0-×k8ÆýkýTg›C6u: ”%'QE<ÀÅ÷j¡ªX �m%J~²&È1¸É6EßcªÖX×Bw¿ù{nS?²D‰µ(ÌŽS“cö^øÌ$ç}…3UŸÞŽ8(Ýd-b4°)ת´— ¸¥6<ª!LUb5Uõ±Ò0íQ„mÛõ6dÏëõ9%œ FÁ„°H?RQõU&�&$Çd-Rlr2發3Ãø}=‹wj wìQqGÃu¥C”í°‚jNNƒÒ¥}qçaUñÎ<Ç/|~–ßþ™·ð+WwRR ”ËúÍ[øØæ-|ìÎøW¸ñáayù4?|îßza”VFgÃvÞ³.ÙÛcê(_>èµ_f–»?ÍìÝN»²ÙÍfÖ~oŠ¡å¨5ãq׿Ä]_ŒÚMвïÌ(/G°Î«§“ Ž\¬²š˜=ø<_<'J„‹DèS4áŠÜ°uâD5B{‰ÖÏ'ªRª×“­ bñ¢BÜ…Þ[‘Ö¸–!бµ »áºmYDɯUeã³±½�MÉÆÁ:Â×ÄÛnø±›óçDI‡ÔÂøuɱ)96Ú Ð.g§ççàñ¾Lq亸~Û²æÝùtü=ÑÐ�(„ÈG‡ “6Z–…Öº.rRñÔ|¿^F“]Héˆv¤®}�G�³²6[^¹×ëç~’ö¨ ¶ä�¤Ë·DÕãJ$æÅ4ê^+W:‚ݸ§S½ “lž›®oÒ*JÔuªøLÊŽ…œ²Q:š/H¢ó ‚p‘ñFŽòûÿñº}?së|pßF®íq±/f¥lú×­çëÖó�·¾‰ÏÎŒð­{Ÿà¿w”ÃM+R»¶¬ag’Ï?6ÄÓKlb?uü¯èí\gƒ»a€«mZáÇœò~~ªß÷æÒýöl w‘¸A«Yhžyˆœ%X‚ N"LªAHÑ¢ÁE¬diB»´àZM[8n�™ÈÆÕ+‹ÙìÌú™¬Kšã¨i t\'@Õ(Üå§8J-#¶LàÖ“„¨äË(Vaà¡l7ÙÛ( Ü #,ËÆOÕdP(Ä–(°ˆ,ß«Q06¨8O-ŒH¼ÿp“ý• û¥¢lÛŠÛF$¯-Ì"q´_Ã&@Gl[h캀qñ£“H€éýî‚E_ɦËÑ´YAÃ-(%ûMœ2Õ0"Ú¬ˆ.GÓç|OSÕV\¶Žêu»DI=ºÉ›Nk�e˞̳¸ˆÊñ�Œ¯ëÖ÷Ò$}8CSÛÓ d‚ìÍ¿°‡ÇÑ×å×ÙPG¶“¦!�¸ó ‚pqˆ8wôþøè+üñ·\Ë-»Ösë®õܺk�kû‹uÁPè\Ç?ø>Þû¦ù�ÿt7š~fYlêïLÄ—áìèô¢‚ š˜á´†ël°Êl,Cݧa¹(‡ ›7ò–�\¹¦“uÚ] Ƕp, ÇmgßrF[ͲLÀÉÑÊ…êAÈ# ê™TȤÇTÌ@,dì( –ì §iœ:Fá*Ópp“õJõ×—´ªÔ¿'Òv¸ªÑmMû5 -Q‘Ö^ †X@j<šK��$Òk^­ÆÉ p(ÑÛV¤»`áiE1QGe§¾†Ð§»3Þ¬w~ËÞØnÂל˜¨áÕý¸ ®ƒÄâ)%S[pÈ<�ùk!qKç…¢XŽ[¿6gÝÍú²Íú.— ñ&º³sX–Mw[‰îŽ2a0&Ö©‚Í†Ž¸Ì¢ÒŸ ¨fѺ³¸¶ZVd>XNt¾æ›- ‚³Ø/}+±$Yó%*ŒÐo‰ETµ U©`:ÚÉ ‘®æª8¢žjfëôÃèÌB9e F©8RŸ5ÖÚLC ˜…âÎ'Â% bôìw�â®m½¼yïv~ê-{øÐÖ6 ÚÖ_Íÿù©ÿÛ'x.ùøìl+ÔׂÎVƒ¥D0@üƒ[�®’bÉëØlÝw#Ÿýð>î\W¨[ÎÎ�Õ,+%`fY1ãA.Œld;Ëqc—²äè:ný³8½î*CÉÒX¶MÙ2¸vÞö;­ ¢(¶Ü‹Ša9nl¡jª;ÛžÈ.`“ì§ê×Ðu7¸`Á>EuÁ”9·‹e"¯1úœå04K�Š1‘lJÛ[°èn‹ƒS�Ùìwd¦Ê\"„*~Ĺ¹€¡�ñÈ!0väc9µj£Hʸ0‰lEõ.û,|£p"¿alÚ‹;Ьí°ëÊ)”°’-”¼Z…ÐqIÝ÷L˜n¯aÓ^°l‹ˆ´ËdÅ#ÔŠ 2É%Ê.àD ÛD¦Þ»2…nïkÙŸeFç3óúÇq™}Û-ÉeɦWi¤>åUiôÌÎw¢7ÝLÛS?¤rÓnL{¬qÓbT¥Bù‘CèÁ;À€uöYæÞzEÉO™†2ç�I[šÚ'î|‚ \z •‰¾ûàß}èþÓÛÞÉ?¶ƒM”·îãŸî{Ž_~*^û¤,Uÿì[ð‹\.š(Ýä\©…û3µÄbûíïæ[?¿�A 0†é‘3|ïà9^�e¼R‹4a¤ ìAþéÇ÷q}Ë5³«YV†l¤>A„UÆÒa”, È~$¥“çÅŽeãÓÞÑÎÚ6‡Á²¢­\\QÝ?âìlÀp%Þû©U]Íç4 &K‡õt6­Ã¯7 ¨¸qÌ‚)¯ÊÉÉNò ØúÎ"× h:Ê!U(22SåùÑ''ÒH%nc:ŽyÁ,ò®5ˆA@: pt€¶Ü†ñpêå4 ÞÛЮ6viw`Æ�ÀŸ£³`ƒe3S‹¨Ôâ1ksˆ¯3ÉµÎ‚ÍÆŸuðfCƼÆñNÔœ¶hÏ´'LDmóóÈcIK”ú±R_j¯ÝS*¬·)¿ŒîߎÞò.:}¿'@ô€ea�MàNÐîÀ”»°ÆŽá¯7˜öÌb¾õ%k©šÚ`…¾¸ó ‚py1>ÏÝÿC~gÇ ÿõ–6,Uä­W¯Å}ê$>PõæC£—‹îҥʥœú˜�Ê2]ôU÷ü›�lKDO•û¿ñ~éî!FóDKÙæch!|V³,A„K‰1ùÖî( ±+™Ì7_WÅ2kÛ\;\Öw8´9­-QAdp›Ìó•Âüë¹Àc&)7J­FÉyöh/²Q¶iúæ~Z5\Oë©ø!Q2xFQL\·vºtæ…OÕó™ñ"NNÖêA$êÁ*šÂ¨/Ö�:-Ä €¯èÇqÃøhéDÀX.aR¾K.�‹6GQ.ˆt�Jhˆ´¦âG¯0áÇãÝ[0lëk« ©lžÎ‚E±é1¦u‡aH{ÒöôšÅ-³ Íâ–(Æî{Ð(^6ÂÍ{£Œ“ì†ì–Ð;îÀŽ c#Ë”¯F÷u¢¢úXqkçË3&§¾LuɹúËw>AVEÁQøá L&ÆãñWÇni£ˆ¢««Lð1œ›œ#¢‹u½íØ´òÆŽ±:Ûcñ˜°Âٹ广 w; IDAT\so/'$zŒ_ÿΣ-²ZmEºQs«Y– Â%%Y—5Xobw­( ‰Põ �²×ËEÅ`‡ËΞÆHp©+Ø‚j"C`L]lµ9ë;ˆBÎNkfšÚ�ž/ ¡·`Òn%îi^RÔa,lšÊŠ’ qÔd j~]T&¶²D&*�ýKÅK*¶Ò`Íåäõ#{ µ¢ÔÔ•¥p"¿þ½—Ö“/�L¾v’ø³P²"(• Vc²âsf6àè¤ÏÔ\,ú&ÛËØ–ź6›ž¶¥%+b6ÉïéÆz¶¡ñÚr\ÔÙ3ÞÈv±IDÎ÷^�âiÓ5X/Ê. {7bº×C¡ •‰Í®»×S8£Q³•ÅŠn¨·î¨u]6ÝáÂèܹŸ?ùµŸä¡?ú¯|æjÖ¯H(ʧþÙä{A²xÕ0|z¼nÁiß4À®%Üì ú¹"ùÏŽòÒ²6‰²Ø:Ø�,`Ö¼ôÒÎ.ò9Ú·k#{qå[½²A.é¤Ý Â.sõõ0^uÁõzÚ(lM­TŠ«T~šÐ[Pv¶=•ÊlR]²4%l g`Œ� F1 „hÕÒ=°E/§_ G¿J%ˆ˜M"TlŬQ "´_­ÈÐaP/ËÑóíj.¿™¢®-èGÜøsÚjYFs;§¨ÕjLÌyŒÎzŒVf3êôT�Ñ™*SAœvt¦Ê‰‰ gf&+>³µ£•€ÑY�‰9ã×bëcγÈ}>¡—ß�&–ާdôBA£ZÏ,Š/Æ ì›Ï ` ö‘Ðvû÷ÑηÄA)R®¡tðª·\‹Ò¬;w>AVƒª_äúkÖs•¦s?ÿÃîWø�—üå}Y�¼gÿ@üۙѼxbœôëÒ?v‚æöò±N…3¸�÷ >ÉÁ3­~ r¹mÿfzsôÐiŽ-Ó –ýd"ݺÝî~éǶÐYÿ5j¡·öj–%‚p©)êx9J] Ë øÔ•¥Ró85•¬ê.ÑæX \ö£â ÍœšªR ó×@Í ;sMÓjõ•gnäÏoÔ›#Òé~Ãý¦ôÕPsn¦F›k³¶ÃÅÓ01pn¦F5ñ¼¨¾°�x¼ŠqLƒÐ«âË8Ú£ÄiÓ1u’4AÒ+òr(5�?$A¢Ëq±—ЫRr-†kEHzvzj>ß«cU¼ÈP‰æ7T®ËŒÌzLW}fú:(MÌeÎÎxŒWjøÚZPw«çc‡›ÇÏÛa~že¸ó9Ä.vd\êL®�²¦¦(N”ÑÛºʰƎSÛ^¿âjPà9FùìaôÀvŒåÄõ´÷âmÇ›˜B÷¥ùÓ¯m•qéK÷ž2¨D1‹;Ÿ «AxêþóÁkù×±¬>ù‹ïeøÏ¾Çx¹’»i}»�w~èN~÷Šx½“©�âKONωx'ùo�Mó‘wucÛý|êC»ùÊq2ç[¦°þþùÍñ‡x0Ì_><²¨ëß<†3ã©Û b÷޵ô¨)Æ›Õ�ÕÁû?öcüúŸ± Ì€ ªT¢§ÁÇp5ËA¸„$®|žQØ™Óé>ÝàVGaÃÆ·–íP�›a4™aHWii[ƒr‹˜Äú5] 9;ã1Vñ©ÎÍ€ÓÖPG–íPHÖ+å‰�¢2„™6[¶³d™)Í髾fhÆJú˶SÓC3U?@çDýÉ ŸÐ«6|´§÷ÒcK'‹Ð§¨3î|Y1•n8œ¹‹´*ãÚ‹ ÅDÈŽWjuG€íÖóŽyPr-Æ+5úÚâ ^d˜¨Æý²l+wܲãcÙN26šbèa4ç�ZD¾Ë³DiMùÀ+èMw4äS:BϾŒó õ¤Á¶-Ž>…¥77Ô£7í§üä÷™{×›Á´<õ/n|‚ ¬ f–¯ü÷xׯwò¡> »k¿û?þ,{á¾úÌ);5ÉÉi�Jhp EÖôõpíÎÍüø-Wð޵,FWøîß<È—'²Š#âÑ»æk7¼‡�ö*Öì{_ýd‘ñw/pÿhòÜ.±wß>~ï§oà–"`B~ÿGüù¹åšå g_<ÎsántÝûoãOÞ9ËÿtßçBÀ*°ýŠ]|úƒ7ó�wÚ<ø•ðø›ßÃoo¶PÎ ïÞSâoŸNwh_ͲA.=nä¯h?:…xªÀD5`lj†ÑîNÂHã´už½&Ä7“T¡aÃÜÅê ¢ˆ¢QQÆý0¨ÍiÈ†å ¨lù)µ@3^ñb‹YÝ ¨Ez^œ\ –_[Ø�ÅÈô­™Z 1þs…&µ ©d=WNž´c““±;¥SD'é[�[öz*:•ã~˜ÅÇdq¥C°r’äX¢ §ÏàØ›ÐNa>ŸQ§Ÿ§²o+X™7 ¥¨]·ƒö'ŸÁl{Ó|ze°œí¸ÇNlß”ÔEŽ–Ê|5ëPÜùAX5¢ñ—ùµq�_Ü^ÆQvíÝËÿ¼wï’yue”¿ü«ïò;�L4Ý3ÓGø­ÿûaÖüÚ­¼½Ûa×›ÞÌWo¼�Ù™9F=EWw;}…$º xéG?äãßò©ŸãÖá9^}ø{ü£{F W³¬ôAá‚ÉEãã©B|r'âÕ@i›ÊÄÂO_;#Ë¢v—›­;=o>.ƒùµZ!¥#,ËÎïG«º’c­æQ&“  Z5öòì¸|£Ê­×™©£á‰›ã@NÀÁЫæ÷»yŒšðTjØÉsK«Ëßäܳ àfÒ·÷œ:µ_MÜùòûÑ0V‹ß¦!ZÆb¸§Î%Â)¨ç³*“mSDkú›R+¢�^‚Þ jv¬ž^i�Bá?_«k¥œß3•©·môæ�×ÿ ‚ \(ÞÈa~÷ó_âí_x˜ÿr`˜SµÖk‚Œ8{êñõïrçï}•öÈ­–ÞΆôÙ¯ó/î?ÅѪeÑÙÕÉö5ô˜�¡£¯ðGúUîüâ«_V@‰lc<îûëoò ŒÃ5ƒìB‘ÁÞ6z˜=ÅŸ}ñoùÀ—�3l4O|ç^þ�C³x”]dÓ`…‹P– Â¥$ tÔðÀÓ™_å“IuEõûé¹mÛ ‚©^ Vý?€mçDԱݸœœ6EX ÷æt¦IÐdû¡•…Ö Ëm¸uQ”^ÏŠ$�-+G�&ÔÀ'?gZYo‚ö>”ÖDgïcîÖ3;å[¢Œ¦¾ dR<ÍÙÚy¸AØE¶nècGO‰6ÛP­T8>4Α™pUÜà”[fצ~¶uºØÚçÜÈ8/œ«²0Þ�¢ÔÑÎ`A3>]e:̉ººŠe ‚ \LfwÜOˆkÓØÍ¦f-éëf‹FsºLš(ŠX£l;cÊÖ“ 3¬ù<Íõ$×ì¹1Šãǰ«Ó„=›úaW§êÅJÜË´²æ-Ey'2B'Çb•gÉÊŠ ¬Å)­«^g¦Ý å,Ñ�Ï#§Í-ŸOæ\+…e9hbYNþóƒXdVº×VFhY/»ôuöº=7FiøU¬ RïG3V0·T` �$\ÆÚ$ÇÅÛµƒ`«OéÀ CPÛä¢;:òÓƒi/SÝäP>ú#ü~Cí={1Åb"”ê © °ìQU] t î|‚ \\LÈèÈ(£#«XfäqüäÇO®b™LPå•£§xeé”Ôfg9v‰ÊA¸¨4 ”†×Í“óæI|N±pНÙMeÚhÈ Æ�-·Á½/Ol-£/Y¡BÌ‹)aÕÅ……•=uÁ“i_*z,£^Ï ¤h^ôYÉk«y}PÔë^Žk¢mL£ØÉX‚¬t,R‘ToW8ï2×ô­ÌµÔÚ”µYM.kbÓ�¯9OCúBiÉ>-.¢¢øwFK·aÍÌ »:I7V».Õ›®Ã›œBw¶/¸ßp®þžÝ„[¦ÑÝ=Mâ)“®)2 59ƒí·a×A‰Î'‚ ‚ ¤ØÆ,-)Y+Qâf—ç¾4Z‘÷¿º_žË¦z¹YQ–^˸ýÙ�DÃnjcÖr”9¦dÅP*r²ªfëQ³xJÛkå¤Íްèýº¥,/ŽBV<æˆÕ¬HÒJ5Xެϯž.•©E*�ºð4�åçµ#iƒM¼¾ËögÑí­£ó-½& 0ëvQ~þÐü¾OñÕEóèž®Æ` d,[–BwõäÕÚ¢`Céé—1»P‰YP6ÛAA€Öê&Z §e—™s-»Î)¯üúµÄJ•»®ª©ü�´‚¶.+ý2Ó.v?½7¿5Òù‘8ºÅœÞ2f>]“%*�ì½<¥[ì}k,‡¨Ð›.a KT\±qËÔ¢ƒ/RÛs54‡zÌXŠTýBŽª§ËH©»^Žõ©ž$¢ôì˸þ ´¥ ¿|qçAA ’Íi—'¤`ebj©´+f°¨µ¬¨ ¾^°¨kxÖÒîf—�Lľ´á žä žóI»T9Í÷Ó×J‡¾OÄbÊôm¢<¦±}Šê5W »»—ΘÇR!Ë[¼¶&§)=ó2…êZLã"/qçAAaç¹Ú5aùt¡íµª5©õF»�mñŒÊÝ1Õ³J¯}!•ÁókËz¯´R”L„±œÏ£™¥7ÛÍšïú6Q(<~„È~‰¨¤‡À4ðƒÊDÒK¬QJ5j"•I“µ<ÕMY ‰ÁìŠÁ ÚÐk®�r±¡MFYâÆ'‚ ‚ Éz¨e°µ˜ÐZ©[*}ƒå#¨bÓÒ®µ\•Wg޵刲æ4Ù×–eãæ¹&­6ýXýñ[nºEŸiƵ‹»ó�J‹ËŽÏm³aŽŽ°s�ÒÑüýLÚ¼kÍç‹Ý«Ÿ—âsKG�)×X6ÊhqçAAæ'íMV�¥ÄDóýôõJ-U­&èE]ÃkUVÒæ¬åÃ6fAÔ¼¼6ºŽµ¨øÉkK޵刲æ4 ¯£€ ŠhÞеl´ß(¤šÇ¶ÕØ/ÕîVÂo)јž·Ê(›‚å –Ø*~ÑÀY¡“w®tÔpžw©²–›n±úe³]AAÁµ­!–_h˜°§äM¬ó^u­ž//«2³×³“õìu€BˆÍŠwßkæÐ\Ÿ.´µ,7Hk�å7µ#½_ßcª)_6s^“z°‹ómŽ ‘¼~,g -¿²ä˜æµ+ï9eó7×ášåítþ!4^Cˆ;Ÿ ‚ ‚Pzñâ”{QJÍà¶f,Qåá¥wæ;Êçy¿¼Äý:n[ƒEíbõã¢ÓÔ�<Þ"JÜùAAA¸T¼!D”DçAAáRñ†QâÎ'‚ ‚ Â¥â !¢Ä�OAA„KÅBD‰;Ÿ ‚ ‚ —Š7„ˆw>AAA.o%î|‚ ‚ ‚ \*Þ"JÜùAAA¸T¼!D”¸ó ‚ ‚ ‚p©p¬°À‰ÿøéËÚ˜Õá—»‚ ‚ ‚ ¼ÁØòÿ” ÊÆºÜ�AAAx=!"JAAaˆˆAAAX"¢AAAV€ˆ(AAA„ "JAAaˆˆAAAX+Úl÷ÅO]¬v‚ Ëàê}7\î&‚ ÂeŃçûÌLO3=3CµRÅó=lÛ¦X(R*•èìì ¯¯˺86£‰(€n}ëÅh‡ ‚°O=òÀån‚ ‚ \V´ÖŒŽŽrêôiúúúèîîfpp�B¡@Exž‡çyŒŽ�qâäI¶nÝJ_o/J©UmÇŠE” ‚ ‚ Â¥&Š"^}õ0ÕZ•½{÷â8•J…ƒræÌÖ®]Ëž={èî¿ŸJ¥Â‘#G˜šœdûöí«*¤dM” ‚ ‚ ¯i¢(âÔ©Óx¾Çþýû±, ÏóøáÈK/½L¹ÜÆ‘#Gx衇ð<�¹¹9\×eÏž=LMOsîÜ9Œ1«ÖQ‚ ‚ ‚ ¼fÑZSó<†Î±{÷n¢(ªÿ?räJA±\àðáÃcPJáû>arÕUWqôØ1Â0\µ6‰;Ÿ ‚°zD>/À@Ù¸¥…KõsÝå¬[^Ïè€jÍGÀ)Ò^”é! ãòBkÍÉ'èíí¥\.ãy–e†!Zk”RLMO£”"Š4QaÛ6¾ïÓÞÞNGGccc¬]»vU‚MÈ»Aá ³ãÓÔtìΠ ]ôuXà!V˜œª¦^N™îžvÜætºÆäÄl’Na—»èšyНßýs°z¹áÇœú.�’‰F._Ý—†±�yo…ÓÖMO[ë¯rfŒi/ã¾¢\Úzºi³/jK__\Šq�ªLNV�eQêî£cјÁŸcxtŠÙªO¤l å.úÖ ÐŸ×®¨ÊääÜüßl+”C¹»‡ö¦"‚“óW?Æ7î;ŽŸ^p·ðö�¾ƒ]…Ætzä9îþΠ̇�·˜ww]ä>ü&:óß¼÷Yggãí|ìÎ+(çeУøÞ·yfJÏ_³ú¸ñ'~œë{V7JÕ뙋;®†Ú¹C<üðS™Œ'x¨2WÝùÞ²!Íœà©Gžà…33Í“åÒ³y/·Ýr-Ûçóë©—ùÁ]Ï0®Y«‹}ïÿ7dëÖL�OÅ èíëÆæ"Ž‹?ÂÁGá©£ãxÍíµË¬Ýu=o~Óô7ýj£+CxìQŸÂo§�õ»oäöë·Ó›É÷z—óéß<+ŸAÀ衇¹÷ÉcL6½ÑìòZ®¾õ-Ü´µ“ׂ–2ÆFA[”RW½y¡¤˜��Ã|¿þÍUWÙr‚0@k]/ãBxýD·ŠÔÆ9sú§ÏM´Hb‚9&Æ&˜]ðN_Ýz„Kˆ<á�Žjgp]Gýƒ_O�0ì5'ÒŒ�Œ5þ „£œ‹šÒfGG©¤�VKX];¸éÖ[yËm·ò–[÷³¥]¾f.&áðINÖòïéÉSŸYjö(ä±*ãNrø±oóÕ»ãp:±]S=Îß¹�gOÏ (eÙØé\ÏLžx†{î~œÓ~&cà-œx/›�ññY4€j£¯·Ø:å…ŽK8ÊÓßû.�ÎPQ•á—æ®ï¿ÈDö~õ}çûÅ\-ŠÒwõ²f —vwaK£ê“sÉ„Ø*ÒÕ×I¡©¼¹‰)ª‘¡õº‘ Ÿ‹ðÞX­qÕSç83‚ÕÆú«oâ¶-“üðîg­+͘#Ã3¤I¬þ+¹áŠ>Š  �õ×ìcÇKgyaÎc#ãDtâQÌÿ Qèeó¶í¬_î0Ô&˜HLÊVg}93ÃU3Ëñc#õ ¾Ý ?ööýô&íܺ¾ÈÜ×äD�³çÆÑ[×a…C¼z,ýaGÑqÅ[yïí“÷Úf¶¬µøæ×ŸbDÇùÎ ÏÔ?Ó^ãrý;¯÷P9q˜“^º6v ·Üq#»Êƒ¬ïôýÖ3ŒiГ‡yyx· ^þ9�eYñº§(Âq´Ž;©µÆhM±T¢æy8®Û`±ÊЍZ­F±T\µ½¢VMDýÑç?Ë/êÓ-ïÿéŸ}�_þÔ§yâéÇV«Ê‹FñÃ_b:øÒÂf”‡î{ߨlû•¯ð£?yG¾ÿë…ÖóšÄfýMàö-ÍæCX�àô¡gxöè3|ãß}ŠïüÍÝüÙ÷ÿ’_Øñú²K½¾ž‡ œ'îZ6 X;«ÍÔÈ(}õϲhl˜‘@QÞ´•�“/s"=zŽ‘p7[SATgt6� ج[¿6žÌ�>ÇÝ-‚;è¡§ùÖ�Æ®‚îîüèÕŒ÷ž ›måí¬ßžVàqîÅÇxè™cŒûM3§“Í×ÞÆ[÷­§m%ß…çYf8u”Ç~‚Cg+4;5¢\z¶\Ëí·^ƲZ•|ËÂ]úÞ¦Æ4ÁÐ NûÛÙ‘Q0fæ$'Æ5 (®¥ûÄ4S- ÓÌ�9È#�=ÏñIŸæù—r:Ù´çMܶ ]õß( sG~Ä7ŽûænçÇþÑÛØ–ý S�qà{ws0~3Ðsíûøð�uÁ~Þãs1Þ)«6®Šòš+¹å¶ØÝWÀŒ?³ŒÊMƒX‹”TÃJEEüÇE&°�!È®q‹,þÓs#Ñäx}Í�ÓÓK³AXµqéÝz-ׯ ðÃwp=Ùº Ýô¶Yœ˜Ò€Á÷R‹UW¾ù­¬¯yx¾Oûæõ ý³:ûè+(FjÉ€èô=ñz—óíœßû,dxhx^Ì®ÛÌæÌdÖêÙÄæÎŒMi0Î M¢û.ëú¥ʲÀ@¸‰Pên}åR‰‰ñq íí�®~‰µ  R©0ÐßÿÚQ)§Ï�dèÌPõ§ž|š_þÔ§97<Ìú ëáɧW»ÚKƒžfjZ;÷\Iér·ç’âpãgþ?þú½-~¬qâž?äŸüÂïóƒcÍoüú�¼ý[ŸbóåÿñB„,ªÌà`7ÖÙ 4 ÇF�v³ÙÐL �&.}ë¶³fêUNŒiL0¹ ÍÖÄôŽ 36ÿ“9Ö.ÃÿÕuqñZí3~èIŒä­@ zòîy~ÇðL méè[ËÚîbN�ÃìøDýo¾§¿7?�ÀjŒ‹êdÓÞëØÔ¢û¦:Æh¥þ¡B{G[<ßp:ÜÚÉ`«|³“LÔ}öúú»ëþן\@ÿÎë}ffŸªÛçhëêjŒ¼juÑÓ­ˆÕžffrŠ�¾•ÿ-­2–R(žçQ.—-QÆ$ûA¾¿@<…aˆRŠÙÙYÖ®_½ï|Yu5tfˆ;ßù¾úë?úügùÀßÏ©ÓC �æ·~÷_ò³?ý¡Õ®63y„§�Cç6öíÀ1³äÜ÷ì1&£6Öìü÷¥ž IDAT¸�;ÞqJùùLq�«ön¢]¦Ž>Ë«#G85kÍìÉçxâ‰3XV™’S£ê+:·\Õk[¼ÍÌ,'Ÿ‰sž¢këµì^ãæÔsaí®£ç8ùÔ<|ðSº‹­7ÜÁû×Q¤ÆÙrªâ0pÅ>¶u­¦ÏZ‰-ïþ=¾øÙǸò—¾Íô¾Ì]g‘_Ù�ã2sœ§|˜ç��0•Y³íZn{ÛMlë\ü›Ùy�‡îœW†¦ Êk¹âMwpÇþA[޶’º<æ8uðgkŠŽÍ{¹ªÕb;3űg_e4TôlßÏ®þÆ�Úµaâ0Ož€®øÙÇä[÷<ÃhçÍüÔÇnf­¸ ŒE÷à:Êj‚9ÆexJ³¹ÏÅdÍA4|€½�L’U™m·¿�w\G‰ &^à{ß~‚Ó~ÈÄ‹�q`ûyÓÀÒ³úó+Ó0}äŽ%}wÝõüø�í«G ‹æNòð=÷rhJŽâécWóÞ+Ê�oC÷¦ ´œdÆœ>1„¿mK<Ñ1Nž�­;ÎZ6­³9Þª˜éWxè‘T@) Wñ¶·^ÏÖn‚N<ó÷½0‚o ÕSOðС ¼?Y‡sþœÿø\Œ÷FcÓVg\q ç1é´Øs;�ÞÏ+³3û >Pâ†Ýëh3³ ½ø ÇÊÝ}%7îNŸƒ!ðüúÚÔÎðè7ŸåÄ„Ÿ™TÛ´­ÛÍ­·ßÈŽîìwTÈÄød<¡Ho_[þ³]­qi…™ãÈ8“þ¦bu³mKO ëGHm¶F æ&Îpè™gHŽRX{ û7Ï‹˜×ç¸,·œßûÌT™«Ö¥%År±©o6¥¢ƒ"º2GÕPj—ƒºèQ Ïóˆ’ @ýX­VQÉýôz*¦‚ ¨»ô™åIÍeqQý­Ru×7ÿžÛn¹�ßúÝɽ÷üýÿÏÞyGÇQ] ü7³»j«Þ»dÉ’{/¸wÜM3ÍØ¦8$%!$�! âÐ ½™â.¸ÆMîU–Õ¬^wWZiÛÌ|¨[+YZ­\òÍï�Þ™÷î{óÞÌ»÷Ýw/o¿ûVwVÛˆí§¿3íª�1�ûÇ—äã… yn[Q³�¡ž óxqÍünPÓ̶ùQƵ0`cû¹f™©±ëw?7“‘Ï�à;Ÿ?ÎÞοWTpÃgd,¿‰`'MÎ|›ÃÿÈÏr_Û}�§ÃœÕÓ5¹왫øý‚»ùïÞ2¤Æ9âMâ쿱ìý‰|sÍxþ•Á=?dòúwÛÂG�!E»ŽýRÙyR3 —²ãÅ»ùí3_qÒ$7Æ¢oæ?ñoþa,!çöŸ=‡o»ƒ{_ÞF^‹< D�¿�7>zŽkÏ�…ÚùºZ=­��OOgÁ �7¯ óóù8iµtä%®ñ$‡„Á<µ�7œZuE†m�3qþçØ&¼Â¡VrûŒ'ÙmRÐÄßGßù#鈱_Eå|hB£ˆÔ�äŒ �«()µB°78Ê(®ß^<ÃЊöT.vd*Jʰ÷óÃC±PVf®wûðŽˆìüî„RK­G_fÍAT‹qí ðôê�e!¥2´gS˜]]Po†¥ž¢ð¨ Y6r:£„!¡‘ç Ãëj™ 檚Ævj|ñk&«FÇðñˆ2kñÑëñõo0´¸z_ÇQCcˆñ>ÁÉkÁYŠíñÄéK>Ùu>™hBc‰ñÚX¼É”ž:Ö´pÕ„1dˆ&›Î�„áã\ò {J%ÀAñÉtÊzsý,p�ô.öOwŒ�s$sK¿ºŽà�À¸“ðK;ȉ³˜r²­Y%‚Î�¨„Þ ֻż±Û›vtec¾¹$jŠO°u} Ž9Iõ­Ærå  mc"wk¿ÈfrvoâǬ†sA"þ)ÃÐÖÙj)ŸŸ¿ÚFV3PAçKdÒ®–Js;æeÙ/�hŸK(ÍgiÅÖj´Z >t«Í^—gë0âÚmu °ÍfC„ù¢***¨©©ÁÃãq—©A‘²ÛíõA%D,µµn“§Ûœ­ÎH}·ö{î{èϼøü“ÝU�S�:Ó!^Z|3o[æòô_³á‡õ¬~ûfÅë°å¬åá»^åd+‡ìæèü«Wyçíg¸>Ih黸EÞ~çÞyí^–Üy1ú�øªÈ™†+qæË•쵃ǰ[Y4¨}ÝÕe¹-»yòÚż±§]âlþüöWlÚº�•¯ü†‡žäÚÛÞà˜IÁÏn2)ÈFC]ÁÿæQ#Û¹’Y�¬æ”ПÏ|ÊÆ_ÒØ÷ó:>zr>½ä“¬|x6W=�QB•R¾½w7¼°�¢ 1üæùøò»ïùêÃç¸}˜/Å?.妿ç‡J¥ëu�‹Ĭ…s e V²Ñàì"‡W®â˜CÀsÄ"ôÕtIÁË Oó Þ|äŽ�ç¦ßÜÃ]7Ž$\u�TqÚ0¢C>œ2å%e8ÙPJi½µFN˜Džk� •X�?_<,µÔÖ6üYñ¬¯O¡¶¤¸uÈßsq¹L_ïFk¿%ógÖnÝËáŒ\ŠŒµ8¯Ð’bˆ į1 �«÷u¶ ÃIŒñª‹ÎfÍ'»¤noÐR�GÝj‹‹Å·­âù…æ¦~ M ñÜh¸‚ññMQåêb «»jÉu±ºcl8£«ýÚ%d,ÕFªjlM†Ðf(’su%eFK³³k2V[óÐÖ"úˆ†ŽŸIiÚiPjsÙ»?·)œ£’òzAAL�W;kƒîèGÇ·¯gË)Cýζ€gä¦ �éø‹èA@x4Qa�x·x]ÆýÒ¡ö¹ˆ"#µ¦ü©W�K‡‹u9ÃoÚB®‰ZÆÛYµÑÀõ7¶|ß8°bÕI‚7“ÝH’صö¢ÑÖÎ?½œåÉ÷²áàsŒ ¸Ì?*ÿcx„XP†Œ‚­¬ ƒ‹wY)¦:_>ÃCñßpÂõ%U Š¥Œ’*…HGYSÚM(Ñ.|Jo‚�¹È(5T™›>ÙöœŸù¢ó­\e¢J† öÞ«.—)àߣñÇ~"»VÅFeÎqöä@ã@xt,‰=RH�  )€�«÷u-ñ1xfd`Q,äå–"Å“—STçî&“ç‹@q[ ÅÔ,�ÖÏßI0__="eu )ÅLU�]rw±ºcl8¥‹ýÚjswñݶÓuóPô&¦ÿ0&á)›)Í:ʾS%˜Š2ؽ±ÃäÙŒ�«û&ÆdXP]Á;‚^)4ÄãèÝ+ž€uëØ_. µy9ØHÔ�\YAeCïÀàFƒÉ…èÙ|–Ý[~äx¹½qJ7œ+'ô!´=¯ Á‡ˆÄDIÂZUAi…C~:ûóOsôd?¦^9Œ˜ú5ÓåØ/�iŸK¢¹8 ÷-KÍ,ôÍ%‘TV’$ìv;’,ãp8ZDè2d‹…£Ç+ aРA�»PPwŽÊn¯K²[UUÕ¨”]´d»F£‘Õ_¯d옱D$ ç†Ñ±D$ gÒÄ)¬XýzN�9Ë'_¬æÅ矤° °.¨ÄE@¹í‰ß6SDêÐ�žÄH/¤³då¶»Õ>º!Üvû0<°òËÇŸq✢¤S«YyÀþWrûõ±îôÎÉ]ÃŽï¶R¥̾‡Û{¶\ÔhòìÃйÑ´ÉLá‘õ¼úë+¹å½,$1ˆ)ºŸq�rÛØõÉ2ŽÛA?ýa�tŽ"‚@Øœ‡ùÍ`JõV>[“_oõ°±ë³åd8Àwú½üv@ËC`BÀ$îûÛƒüæî{¸2ÚRÈØÕºÚÀg"·Ì�G£ظj†sºÏ¾w«O;ü¦±x~Ã³í‚ ‚€ÈU0ùÑG£*P*Ý‚€D�ž+Õ¥”Zõ!“Á›ð°úób0¡õïÙHY¹�ÚÒe Ä H"\‰²#èðpfjVäºðèE¶;OÚé¦2}gŒ£_¤¾•ÕQ²)Ì<Æ/›¿aÕæã”7‹‘áê}�EGœ‡(ÔæSn+&¯¨>gLH<ñíåYT$M/ŸzžÖ-QÒy“М—ú§;ÆFt©_]E.áȾŒú¹% OÃÔáÉÄ„GŸQ“W?iä*N§�¬î¢%8iC bÈ � NmRІÐ;%¬i·Øa¤²>Ÿ¥²¢>a¶ˆ_P çówW¿HÆ ¶­ßƱJð$rÀ®š| @ £ÿø‰L™4…YóæsÓì!D×Ëd+;ÆŽ´üú¥Ë¯_:×><[x#Ù­©Kö¦<ÁÓ³>ÌþÅCQÌf3‚(b6›‘e¹ñ\”,Ë„††2oÞ<®¿þzæÌ™Cpppão‡Y–1UU!ˆ"µ5µ?OÔö[3jII=YŸžÅîŒ ìvI=’¹bøhb£ã¹rÚ•n²«^Ã=Ô‰Ú® "ÈO€Újj»Ò¡R.aòS{ØpxËöÿ‰çF4L9‰«WrØ.:ïv® ëøHì”ÜRÇNÔ  ¥ÏðÁø:“qÎú>±‡ƒ.}Tl|÷«0t¿jý‹"ËÈJC¾�¦ýuŸÝݳéÅ$å°kw>ZúŽÓúÌ€&…1£#Ѥåq`×l÷Æá%å°g_!ZR‡¥µ>¡¡×¢ykQ³rµ®6Ûíɘ[n$ù�qú‡•l¨¼‘›½ÙؽòK2%‘àY‹™×ðlÝ!ƒn“Ç\ .È*ÿ£ˆÁDzÇdU@® ´Ì@MCÞ'M(‘�ç4„‡£É*FBÆXYI‰¹¼Þˆ)àá⦄à||‹Ztês yõœÈõ#£Ú6> Úó.ººV¦.0‰Ñ3{0ÜTJ~a!…Å¥”–•Qn²Ö÷ƒŒ9/�m‡Ã¹fX“k£«÷u ] ÑddYQªKÈË´Sh¯ )ßþ³uxhú¥e8èæÈÍrí€gý­8;®íÀÑŽÂÕéþ鎱Ѧp]èWQªš»JŠ„DEœãÒæEDD šÜº°ò²©˜ „ø´*ªž^^Íæ›„$Õɪ¨¨$ƒHPpÀù�¼nè¹:‹?üBfC¤A] ½FOaL’Ÿ s@À3¬ƒzœ¢ðT 5yg)“cˆî€ÅúRê—îhŸó"õøéBå+XjkQh¾Þ°b®mZ(jô¾¸’…Á�(Š‚ÑhD#Š”•—Ðq¯9Í£ö5àp8Ðh4 Àj³^|%*3+ƒiS§c·ÙØ#€uûK˜Ò/£É@ÿþÙµç·è}N_¤šº-M:²ÄèëY2÷/ü°ü4Ÿü31©nQì8ƪUG±kb˜Û ü»Kn¹Œ’rÐîtÂkz¤’¤8è¢ Ã'4žÈs�z-åä�5QL{èùÍ LIöm¹8’ É+¨Ëûpü•«ô±óפµ´…šü<Êeˆ‘ É+¬ )Ö±UCC Üq_GÑ“�GvV¹œSGªë,èb ñ牢'ø(@qÝ—D2TbRâiùê‘›¢”hò¯s!›/`äZj, 4K–¬T•S~Þ¿�éŸnmÒ…~uÅá ¹Îél¡§(̓ÉulFòóʨ²X¨µ:ðOHr@óY©P]]ÝÌë o/”j**’_Ü!¿Ç.ö‹½”ƒÛ~áLÃy#�pO™Â°È¶ýÓE‡Ør0sm-µVoú̘É�þuMÓÿ+v[] .›á²è—Ûç*‚ž�`o„3 –ÊJj”ÈFÏ$e Ñ[ÐzqsDAÓN‚@UU‹�N‡··7’Ô¾'YƒUQQ�(ŠØëw¦Ü�ËJ”ÕjÃÓÓ“ªj+cSƒ¨.<ÊȤjë#c8Ž6£ð-Zx[û… çÜd:¤,JR½ ŠèÜ¿QhÃâéN„`æ.¹žèUoqvÕGlzns}Áqd«�;Ð&/àö � aÛ¹+–úÈu:§>2€Îo-¸¶ìÁäçÓøæÜ$Š «µÎâ¨Ó�'s}WëjíÜ<˜>–Ʀ•머y!!X~ZÎ×yš¸ù,žÚlïÏ 2ž5œ¨Êÿ<ˆˆ Bs¶ Cf&U nD¡¡Í׈�á„ë V©4‹,{CÊ0¢ÂÝäUð#:R�PV…H%¹äÖö$µñõ©P�sˆ#% ^Þ^øF“о»�«eJUäg�¥Ä`ÂTãMÏуˆi¬H@çÃÀ>Ñ)8S÷Z•”ºMÙÅû\œóºèx¢uYdÙdÌæºÈSb`ÜùÓX¾ÄÆ£)® Ã,2I/éËÍ“VÙ 9•Sݸp×…ÅëU×o/�VÈäœ5Ó·wÃ7ÀJÞÑÓM¹Äšãj¿ŠÝ06ÚÁå~uQu1[d*ŠJ±%7°`¥¤!€V�Ÿ·rÇù™œº¸ïxüˆœ”Ü”6Å’ÇáôŠÆûDÿ"½p(¯_, º@B|;Ö.×ûÅAÉá_8TVïŸ)èI3©] @ã æ’Òú±d&ýX½ÇÆ7íŽØŠÉ̯i£¢�o]Û•Ë£_\nŸËˆ„ÅFãuê4µ HeYœ1õbP½‚i9{†³ ‰}5ÁÄÇ´ÞýÑp~Él®A–e, ¦ª*üýE±CJ”N§£Ò` ((Éá¸ø;QPwÈkßþÝèu ‡§¡( ��üùῸT®à£ÇG¨³Tìp;“T^Z—UZãO`7½Ü:‚Ïä%,Ly�çÓ¿aÙ:snðåЪ՜”t X´˜áÝ™©L¨· –Z 8sP«5bì’ù >£øËË¿åËé¯rúƒßñ—ëöñæÌs-A�Ÿ¯èýäÏlümTÇ&¤àƒÞGdÌÕfdÚÊᆺÚEC¯›0ò©4vn^źò[XZËöåkÈ—´ô¼i1ãšww·È ¢ân|##ñK¨”A¶Yë:Â"‚ZÎ5m(¡"éùŠÍÖh‡ÑGµŽ®×eDÂRûyj…vÀ–ÇžíûÑ�ìE´ª‹N±kçQ ­  %jD ©meïìj™¢Dɉ4ÒÊe@¤XÖ1fpazO4‚D­±ˆôcùõç1Wñˆ&1ZGVvc’‚â�¸@Ÿ‹@`Ê@’Ol%ݬ€lâØŽxŒDr¨rU1§ì#½ÁÅL  × ¦E¨.4œME€�‚}›ÙfíK‚Ÿ‚!ï$GÎ øëŒõçL×-®ök·Œ�îèW°—œâ`NU“Âc)¥ñÔ€â $=�Ýùõ ^D÷éGœ>†¤hòrm((˜ÏüÂï! ˆ ‹Zʳ�²÷lƒ,>q=ˆÖÄÑ;QOîéº�…Úœ�|ý]IÑ�x8ŒägçRÒ�ÄVð ºo Á"Ȇ ¢x‹Aç žà†~©ÍæÀÉÊf®¡vŠmâËÃÎ/¼{0~jB“èqŒŸ í€BUƾ2Æ‘€‡RMIn�RDâãëÚâyyô‹àjûpuœ è¢{Ñ;è *dp”²Ófª“"ñqT�u:§þ<˜€wB?R.⺺9rýчÃ�Éd"0  CÊ�ÝnÇËË‹Z‹… ú°è²›KtI‰²Ù­$÷HA£Ñ4f 6U±X»ƒÝ'…ÔX2¬Ü{û�£Û±$Ù9òã/TÊ ‰ëO_×ü!܃n·ß6„ÿüe–¯§òê$V®NGòÍ­ ûºæïÞQÄp¢ÂEÈ•(<[€D`«úìÇr¼ ˜ÛÂoÒ“üçö5\õnïýî¯\·ïu¦7ÚD’´r2spÕ1Ë &ž¤x dJdgd#ÓJ‰RìµXð»!|“«u�±Ç Ü2ö1vnÝÌêõ,¼n+Ö!kû³`á°–ut“ **îF Œ ÂS ²ù™PM0‘¡ç~< @̯hæú"âÑE‹¨sÿ^ŒQÄ÷»r1Ë –¢#lþæÈ¹Ò£�ɸ>þ2R¸T¦H¿‘ýÈÞt„r»Œ){/ë³÷:-_Ô'pÅà˜º¹îê}.ãAl|Ùõ!šÅâ:x¦Ò3ŽÑ“†P½ùÙœGÚÖ<ÒZ êCÜȉ �l‚_�S|¦>LºÃÀ™;9€Žˆaè‘¿•]õg/¥aÁêzÿtÇØhWûUÁV‘ÍÑcE8·‘Û©È>NE£¸þ‰}‰Ó{ÓsääUü\çî&›É;üyN” � c‡ÇÖ›˜uÄ C¿ò­­p2µeÙ+;÷.-A©cŸR·[h¯¬hÜ}ö r™±-\ëÅV‹EjñTUV´y½ ¯OªìG¯ÑWP°a'Yf�¨)Íæx©ÉBú1f`ÃùÂË£_\oŸ«ãL1„�£’·ñ ¥v�ª 8q¨ ÅÝ¢_Æ �oçÌø…C¼½½0šŒh4*++ILHè�%IV› ½‡ÝŽ ŠhÄ6<×:‰Ë¶/�΃²²L&%¥Å””S\Z„ÅR‹Ñh@§ë¶‹nWÏM@ƒDæ²—øÒiî¥:ä³_ðìû§p ¥çµóvQW«R-a¢7­ä› _°:CB?ù6nj3|º»ªNd@¿DœØ¹«Îe¼Õlÿô+rº„°M„ f=óonŠpd¾ÃïÛŒ±yýB8ã&öE‹DÖúï8êT‘“)سŽOW6¹¶‰‘Œ—‚‰ÜÍ?p¼•ß�ƒO�ÀßS‹ßœ÷êÜú]­ë|ˆ±\wË$ôT³míжɺ�á‹XØïœgwÉ ¢ân4a­Â“‹~ᄷʉ"àF‹¼‰ŒêÀî°Kˆ¤NäªiÃèæs޵O@«'eø4®š”B@‡p­L�ˆ¡Ì™5–þqAx9±„‰ÄôÅœ¹ãéÙÌíÇÕû\Å3:¾qWPô�'¡Ù�ua˜1w#{†ã§=ç>QG@T/ÆLŸË•½ƒÎé7/FMa\ϼšŸéÔÐcø4®ì�O³ìÍ"~¹Þ?Ý16Ú¦+ýê ‚o“æÍb|ßX=[×¥ñ $®ßæÍEBóÓþžÑŒš5‹‰ýâjuŸ¯àMœÍ¼Ññõ†™Š Cýâ[$(¸ssùB÷‹èŸÌä¹3�‰¿“œÏ@âû�gÞÌ¡-“w_&ýârûº€.l³fŒ¢W„OK£»èIPâ`¦ÏK�Žk�ÝFC2Ý€€,V+T �y ÚC–e4 «½^�ÅbÁÏ×QtÏxB—üKA¨ë¾ÜWîj÷â‡÷3tÔx6l\OQQÇ�Àßß¿îŨ(ŒöïO#*2†Ógº,˜|ö#®¾„5%8ò>Þúð)®ïãßl0Û)Ùó>/yˆOŽÕ Æ.à‹½Ë¸>²é�Û~¸‹„™oSökÖå¾Íôsõ:Ûîéq%o³ä»|Þ›Yw�uõMݰ[χùéØ¿Õh/��íÏŸw‹Lûo6ïŠtrþ§œå7¥rË* ± ~äçÚ¹îóÓ,¿1¸ÕµmÕãªÜƯ“2eÚ~Ü¿nÿ™ÒP§�³_ßËŒ;WQh2`�“øÃŽü{Lf¢í{–DÏãƒrs?,l}&ª™¼�ç3ôޝ)Ó¤ò»õ{yyJ“PÎy‹Yïfcµ?žÙÂw� mA°öø\?ù>¾/ïÁƒÛŽòŸzÿ8)})“†ü‘Ÿ,!Ì|e_ÝÛ§Ñ*bÏú˜ã–°ºÐ›i¯eÃÝ ˆ]¨«Íç^�Röó{.b�眵�—?®`â«'ùáÞøV/YWe8ï³WùÍþ]?ÒgàЋ-ÆFÁa©ÆTU‹Mñðñ#Àϳ‹;û.–)Ù¨®®¢Æ*!#âé募ŸÚó­3\½ïb Û¨®ª¦Æâ­'z?ôºó/8$[F£»èI@ ¿SŨ�›]ìŸî—–*Õ;YÄÃÛÿŽô‹oÊüó IDATâ ¶ÊDµÅ�,êðöõÃß«U y*2�’mÐÖ³qnPæ/²�j“‘j‹ žÞ~ø{Ÿ?ßÚåÒ/®¶Ïeìµ&ŒUV$ѽ¿?¾®&ï&dYÆ\Súï×áPê–_1b>>>ètº9¡šc·Û©­­ÅTSCuu5ÅùùôîÕ›þýûáÑVü€óß4èM.»óM›z%[¶nfËÖMÔÔ4¹ïùøxÓ»W?¦Lžêjшq·òþÊL®™ÿ ?íy™›¼OÜ  J Ã[2‘ri'K±(º˜üó«ÿ2?òx!Ì]2Ÿ¨Õï�›]ƒµ„Ûg·V ºƒ€¹å‰ÉßóÀæc¼2»?;çÌaL¼åG7±f[“_~œAyˆ/ª»£v‘Ø…Kyú³íܳá4ÿ½ç ®Ûó“êÊ Kxmé:&Ýõ ;þ2�A›°`ú¢Ï›+¶rrÿr÷7ü,â9”kÞË£º�‘a—ŽíI?e ·ôü€Òn¼�©j&h{sïªMø<þgžÿtû¾|—}¢7‘Cæð‡Õÿä‘Çøu}¬7¸‚¶FÓƒ_½ô8Ÿ�|ˆéorϓױ{éêÞÿ:R~µ‚�ÑÿâÏ�½Ê×›ßå™Mõ÷ "úØ1Üþô3<÷»‰D´�Í‹A¿_ÃŽè¿óÐïðÆ÷xq=€€¨OdÊOñÒ?Ò¿EpWë:�ÌXxaË? Ø&tõb®o«€î’AEEEEEEEåÿ‚  Õj‰�‹#?¿€¼‚|jjk‰ŒŒD§Ó!Šb‹äº ý$IÂÇÇcFUcÇŽÅÛÛûâ»ó]päJ2O“]lÂ&ú݃žñÁ=‹²Sª7òÛ¾³y«°/OìÝÏß»9pGPÔMØ<ô®W0M˸:b1ß8ðľýü}ÐE� sÑiÒ³K1ËžF%“’Ø‘gi§2'�Ì#vïp’{'Öê솻êr'—‚ *ÿ üÿtçSQQQQùÿŽR™Ïl6³gï> 9b±±±H’Ô¸ Õðß6› ƒÁ@ZZ½{÷fÈàÁxzzvI‰r‹;ßGô!¼ç Â{^lA·Dæ‡ÿäÓ<ßi÷ð«�®‹•šbÒ�ŸàLY#f !,0˜æ‰Ì­û÷pÈ‚w ½.æ£ÑGöbHd¯NÞ§#(¡Ã.D]îäR�AEEEEEEEåò¤a7J¯×sÅȤ§Ÿfß¾}>r„Ô”üýýÑëõ8ªªª¨®®æìÙ³X­VÆ�OlLL—¨s¹|”¨Ëãžg¹í±í˜5=yà±ÅÄ_À³yŽ£ÿáê±Ï“.ôâîoâµé¡Mg±Ì‡xåïŸpV ¼ò:¦vÒß]EEEEEEEEEåbÑ\‘êׯ/ÉÉIdœ9ÃÙ³g1W›©©­AEüýüñó÷#!>�ÔÔ¼¼¼ÐjµnU @U¢Ü‚|ö{–¾¹�ìì_XûÕÏäZ½øÐ;üm¼þ‚Ê¡ñ{ž_¼’><Å›W "íªk™Ü7�!“�k¿d[f BØ žyîFÚ<Ê£¢¢¢¢¢¢¢¢¢r Ò H‰¢ˆ‡‡ƒ¤¿~HÍ‚JhD�FÓø×&ÝݨJ”�K~æƒ^à¸C@ôKfî#oðÖ_'rÁóþ \ýö¾ïý(O¼ú%»W½Îîú¬Ó‚WCæÿ�Çž{”kSÔÔ¯*********—'¢("Ö+K@«çÝ¥85GU¢Ü€vð£l>¹ˆr»7 ñ„z_ÄøúÚ¦ýéc¦ýé=L¹äWÔ {C�É@EEEEEEEEå„E©»&g¨J”;Ðø™Ü‡È‹-G tøG'ã}±åPQQQQQQQQQùßâÒJI¬¢¢¢¢¢¢¢¢¢¢¢r‰£*Q************�à²pçÛ½g/WŒq±ÅPQQQ¹ì),,¼Ø"¨¨¨¨¨¨\’DEEuøÚËB‰:pè�ªD©¨¨¨¸�Î| TTTTTTTœ£ºó©¨¨¨¨¨¨¨¨¨¨¨tU‰RQQQQQQQQQQQ骥¢¢¢¢¢¢¢¢¢¢¢Ò T%JEEEEEEEEEEE¥¨J”ŠŠŠŠŠŠŠŠŠŠŠJ'P•(•NpY„8ï2Љìç)³+ è‰íׇH¯ÜV•Ë‘ôl ˆ~ñôïŽGÓ�äI§Ä¦´[†àEŸ~1ø´y…Deæa2+d¼£ûÒ7Úûür™óHûñGf”`|‰LÆÄ ƒ;Ô¦Î"›²ØûÓ.Žf—bƇ�¸ÞŒ{©Á:÷W¦¢¢¢¢¢âL&#UUÕøùùâïp‘%RQQù_íJT^^û÷ï§  ‹Å‚·�ÑQQ 0€ÄÄDwVÕ9ì?ñÔÔy|P.ƒàÇœ÷ÒY{G$B»7Iœxå:†?ž†]�±ÿæÄŽ?�Ô°wgÛÆã¯æcCûJ”¶Ï£ürøY†;ëiK&kžüw/ÝN¡]à'ÓØ÷·�í<3G?x€ÛþˆýåšjðˆÏ}o~ÄsW'âõÆ‘ÏÏÝËï^XËé*™æ­¼ã™rß+¼óôÕôðh³•ðýºo9rô0údö¬¹[•ËEQ0�˜kj À`0"Ë Bû_~•Žâ6%jß¾}ìÝ»—Q£F1hÐ t:555³eËbbb˜1c†»ªs A@ š-¯$ç¶ûHlÏ™Ñ~€O?=„Ap¢(YM- h":k=<�£‰íOP«w¶‚ñàû|O-Þÿï~ðK—.eàÀ�L›6͵B;Œ�ª Vùœw› ­'Þz<5êäV¹¼())!88ðÕû`·Ûññö¡¤¤„ˆˆˆ‹,aÇ‘ìl�§'êá •K·(Q‹…mÛ¶±`Á<<;yéÛöêÇúË2>O— MME9} Ó9¿ËÆJŒ2 Å>]ÅBÿŽ !q擅̸k™J"óž}ŸQ[oá/¥vïR ßòÄ#k(T˜ò¾ýCÿ-ù5×þeW>�·ÿðonÛÿ #º°CdÛó/|û1žË~äã›â›Ê�÷rë³õ‡Íd¼ÿ,?<�ûÛÕFUTºˆ\BÚ7Ëùâl[sDÆa³£�rO=<… ªÙóìlf=þŸx†�îOœ-‡=Ÿ>ÅwŸ}ÎæÏ¶òεÑõŠ”�Ã/ÌeòßK™üà}\å·Ÿ÷›Åg7²ûùqè[Ô¥PòÕCÜù÷-Œÿì$¸¨@>|˜x€§�p:ë'M wÏþ¼òÊ+ݯDÉÅذ…tk;;颿ÐzöÈ€¤ Ü¹é¬ØÍ˜jÁÛWßjqØÞo**çÃáp ÓéÐûøPSkÀW¯G£Ñâp8.²t�A¦hß7¬O×ÐwƵŒŽT'ƒŠÊ¥†[feZZIIIøúú¢ÕjY¾bW_7‡÷Þ{‡Ã�F£!"<œ3gθ£:×#™:}0:Ç!–}²{›šÙúÉJr”`&O€äd�¡˜ ˜¼üñocÊ9Y;¤$q¯ý˜Æ×ž@Äyb eß¼ËWE2Ú”ßðìïš(Æ>òóCì'>âýPÌäMcß¾ýœ,¶¶S´‘ìƒu×e”K€ƒC_Ç‚ǨùÇ ñçhÚô¾ówÌ P¬ûÙu �²UTÜ�n)¨¬¬DQÚwv/>¡q$&&4ýÅLj�è ª$›;¾ç»´ln«S¦òèfV½ƒtó¹mmï7•Ž!I">Þ>è}ôˆ¢‡Ô¾¡REEE¥³¸E‰ª¬¬Ä?  ñão±X¨ªªÂj­[`K’„¨Ñ`0ÜQ]�‰Ÿs-ƒuéŸÄO–6.3¬ç㯋 d&×�ÕáÌv%› eýñïT/jH˜ÿ»ö,ãžáA\„ղ󇟨V4DϘÃPg&á€ÉÌ™àƒ ³å‡C8°±óéé\1bcüc%KG^âšÃ1æW|^ eÈ_·sæÔ!v}t;=œµÍ#”ð@°S[{9YöTþ×�μý�mEœþ–.Œ­¡YØþÖ;v„sÓsÏ37¦É à;ð~þóà4E«xse! eî!­TÃ�1ÃëÀhé=z$Aæ4ök6¾•r¾ûóý|f¿š—ÞШ°u“É„$ITWWc2™(//ïz¡�B$¤Ï8¦MšÔô7e 3g]Í‚ç2¾‡/"Ê�§‘^å.¥ÆJi™ çΙíý¦¢Ò1dEÁa·ãp8�e»Ý†,©£JEEޏE‰ª®®F¬V+‹“ÑÄš/¿§¦ÆŒ$IH’„¢(˜ÍfwT×( ×rÃ0䳫øè‡*'×(”®ý„ïÊ!bÞ¦éeœÙ¯cýN”þ�ZLiH™6—¾¾�¸IÊäȱj´ôÔ· L_ú 쉉œÃG©$ˆY ç*Ê6¬d£SýÕÁá•«8æð±ˆõî�ZßpâS2$Ù¹’§”çx‘ šdú÷>4A•nAÎçÓ‡ž`‹c ]zGÓGÇa6m-FÑO`Τsýl5¤ÎœAO�…_6þH ——R®øÜ4–Å `‚(§¤ñ–BåúG¹ÿ“Zæ½ð7G»ÏµÆfsß�;<‚IÞ��*(­hË’¯`7—‘—�ÁÉ'8vò4gòJ1Ù[+]öê ÊJs9[&̆rÊÊÊ©4ÛÛý­U�ŽjJó³H?u’c'Ó9“WJ•£ %ÏVEyYåF+2à¨.!+ý$'2‹¨¨¬«Ã`io�íÀ\�±ÝëT.EAQ¡iž^Š%d{ †ÊJ*«¬N×¢\ÉfÆh¨Ä`2c»Ã»»Ú¬¢r1pË™¨êêjüüý±Z­H’„,K8vÀ»½îXSSƒÉtîÉ¢ Œ¢ h’¹ùÖñüm×fÖ|¸–ò¹·ÒüÝ*çóå'?P%ÆsÛ­SЗ}„³O³Ãd ZÑWCÞ×ÏñÆû_²íÀJjD|#{2tòuüú÷÷0¯—oׂ<H…œ-�@ $:Ú¿�òD¢b£9ˆTp– M[È5QËx»`#«6¸þÆÀ–÷:°bÕI‚7“ÝØy°=Ûÿõ¶ZÀgô,ôÿ#J¾Ê¥†Båº'xì[}þô"÷ôn6«Ó9‘+¡éÙ›T'¹´=û�¢…ÓéÇÉr@_QƒˆLsCµ"IHhÐÔ»Ú*†øë}R=û^º%Qª¢ 3Ÿjï(’bºô"Ýz �¼» ½�o<0¦ %¹Áà O�ç‹Pk ‡wîä`®‘s³=ºz Ǹ>¡õç©$Šn`CFƒÒXÁ‘Íßqÿ~ӹº•œþ6“ëG„×Yü …Çv±óP.•ç(i‚.€ÄÁc×/œæÖRá¾Ýš…y׳²cãAJì èSžË�,ºÄ Ü4)gžÙŠ)�-k÷RL CæÌcX7¤’Pq/u ”(4Dnr¿›¬DîŽålÌöaðœ«ÒüêàÌ–/ØšĈ«g3(@d v­f]ºÃçM ã'~>QB­  ó�cè„q =_|]Cú6¾ÿ%b¯`Ö¤j÷v¾\[E{÷"£¸š†©$è|‰LÌèaÉ비]_­ç˜Ò›Ù×�$Jl’¡`×—¬;YƒGÒ$nžßX©dÿÚo9P›ÌŒù£÷¹£Í**—&nÛ‰ª¬¬Äb±P[[‹¯¯/~~~X­V¬V+•UUÎv~.4"1×ßÎ 0nøˆÕ-M/ræ >ÙQ‹&u‹Çxµ¡°(˜ &dì{ŸáÚÿÊ{[3±D¨P~zß¾õg®>š»Vç8uì² CU]Ž+_}[*™€Þ×�¦óZøLä–ùñhWmàÜhìö½+X}Ú�à7�Åóc;0lœùäWÜúÚ)ú‘<òÊ=ôêÂÁz—±â•Ç?¥ üFžþ㚯kåòbJ%1$‚PgƒÚ;”0?¹´˜41qĈµT6Llù” ÑÄEk@1²åñßñžqÿ|e!>ÛŸdjB±½ûÑ'>œ„ÉO°¥ÌõZ¹¡†'ï¿ sÍ¥·#å(/¦B´¡D†œ¢ŠÛ6³7LjäÇà1“™5ks¦ObtŸ¼$#™{¶²3§ÁoZ$¸çŒÞƒ@ýH6šñcF3¼G!mþÖ`8²S˜ööå` �䡘5g.×ÌžÆÄÁ b$kï&6©hiáÖjPN¤¥Ò3‚¤Ô^ôNŒ$>%AÁ–ŸAv­³P0åfS&ƒ&$™ä`õpÿ倀иÕ€¢\ü]DQ+û·³ÏɈ)³¸jÖ•Lì�¦*—½?¡´]1jrvñî<䈡̘Ћ MçË•M§Ø²a''Ë=H1…«®¾†ù³§0*у²S?óýŽÓT)€Ll¤Ô”PdjöŽ“ Õ¢Ói°—Óÿüs/^Üx.Êh4vi'ê¿ï¼Û%G>÷• „Îã¶«ÂX³l;}‘É�õ¬W $Žþ {lZÞ²�¡:ÚP€dLc�ß¾g×>ù*Ïß3�$½ÈT¥¯å¹ßüšç·åÝ;n¥oÿ-<ØmCv É  E׎ÁFÔéÐ`w8êåödÌ-7’üÆ¿8ýÃJ6TÞÈÍÁ J˜�Ý+¿$S žµ˜yaçÙ/Sª8øÆ­\ýû5äiS¹ãÕüe˜êʧr1P(ûúŸ¼~HaÈÓ�07¸åØUjk¨U@ðôÄÓÙ°<ñò¥ªî:1v2Sz+¼üí: }ÑB%›Öl§&ê:¦öÕ`Úþ7î}»‚i¯¿Êm!Û¹Â3ðŽßGÏüwY8ù>îx|<Çß¼òœH~ÃXmaZ¾K=ÑmÈ6 …éìÛ•ŽIÑÖÉçpäòtŽÛPÄ NšÄ°f FTt ò6œª&ëd#â{¡ô‘I¤úÙÈØŸ…oÂSèå×Pn{¿�\~Œ�Ç+pˆôŸ:“Q‘M‡CCÃcˆ ù™¯·dP|h?ISéÕ ¯ "Š1‹LÿÞ̼z ïQÙŸÿÓ4‘‘UEj_¿–†3¥Šììr$´Ä$÷ àÒóSqÂ… ÎÒ @®¢Ø:Œ«gö'¨~Ê„‡ë©)ú†½…T)„µ1ÐlEûÙøS5!™9¥?!:WÊu�äù6qã¦2.Ù§~ÌŒÆü5?åáhq£#µ„ÇD ;}–¢ Ö}ós…UZbRã(N/¦°J!²^f{q!e’Žˆ˜ˆºè.¶YEåRÆ-J”ÑdBÔj©­­E’$fϞͬY³P¥ñœT­ÅÒ%%ê·¿¾Óumß³$z_›F2ö9¦ß6ŸØÏÞdÏÇË8úÀ“ Ôö4–}v‡çhßÒ m)QR~¿�Ê{dÐy¡÷l® ‰ø¥^Í3_yP6tïdÿÌ+ÿý…{þ3ÎõÁ<´ØmXÛ †ç°Xë" zx6º¥è†-à¦>Kyúè&Vn¨ä¦õ9¤¬¿°âË$1œ«Ït’˪¶¾~è:nc?U~#øýç_ó¯YѨ›P*é ¿¼†2ý•<¿ÄÉA�GÝ\k4&œƒâÀnÁÃÐäÞgnç³ëïcüÔõ\áu”ï7üwÿÈÇOüéžÿR:åe¾¿#iÇ ¬ÉåÚ·~Ë  øßÁ×?Ãô/WóËËW2Í…In¬¶‚{Rd»€Dáî5|žÖ쟻͊Mð Šeà„A I n%¡Зis㩵i :w‡FKdtºSÕØM•hs½CÈ”œ9ƒA]\G¶îh¯ØþôÎd_ygÎÖ�Ú[ßB!R=`@“ †Ð3%„#ûJ)>“…±ÏÀyïS6Y2èbIIÔwÝ5[å‚pÉ*QhˆHN¦Å”| ò×@¹‹EÁ™¶î¨8Îæ­Ç0úõaêÔÁD´š,W.#7ß‚¢�§g¼OË1-è‰OCSPLA¡92�Èhµ9”•`OM@XKŠ('„‘©‘8NgSTd�o@ª»NB\”'4îí»Öf•K·ø&˜ŒFªÍfÌf3‡‡ÃQ6ªn�6'7E–/þ™¨fxO¸�›{jqû”�÷Ô¹ÑX~þ„å§%|&-æF§aéštÞè}õç(PÍ~šÆ’ë{ A"o÷.r»²]-$Ö¹õÛ*HÆPi@ÄàЦ—•v nŒ›V®£¢!ªóOËù:OB7ŸÅS}Û¬Z©ØÉóW�á†×`I¸ŽW·mæEU�R¹ˆHÇ?ã“=VgÝʵ­?¼b@ bSÍV8 TV+Aõ f�°¹o²kÏÇ<8)‰øKxãÇ4¾XÊ®§îæõ¢‰üãµ;IÒ(TfdP&ö 5¹a£%)µbùiÒ]ôI1V;õ#»`Ȳ›½ÙŸÃA]^kU ¹§8Udn}\çM`pQ‘Ax7>Y–�v$¡Î�‡Ôõ䊙’ÒD#Â�ž]Bð#"܉²’ŠÖþÄP¢Z­<’z©¹2“Ó-:+²s¨�¼â’‰WÏB]68;¾wé(VôúÖãP£Õ  pnþkٜɎÍiˆñŒ�:œX§c±ƒåZMTYD} N>äž~~x2fSu� äElˆÐÌmÏAIA r@‘D)”Õ§@�+)*¶"ÅíÓü!t¾Í**—n ,ÁÙ¼ù¥3‚BB°X,ôë×ÏÕ¹ }ÞÆ(O™Âï¾bgù–¯-�°«¸unH‡>ü²ÕLM›{eJŠJëv†‚BhåíÒÄX†�Bƒƒ#{öãÔn-ç³gO.Zú�Bó db�¸e¬Tmfõú ”ší¬X[„¬íË‚…Ü:)¦_øûÕ7òÒ�Zb¯~�­ëŸV(•‹�œÏ¶-'pè3ql óyªÂøQ¾(;ÙqäÜ *S´c+ÇZLÛ22gsj÷ðìÝ/‘;êI^ÿmJýΫ€�¯A©¡¦¶a‘¦Pc®Aõøùº6É�Õm%¬»˜ˆxø†ÑcÀDf�ŒÅC©!w_YÍEµ°{Ý7¬ßsœÌ2 ž!qôìÝ—�2dÐ`†$‡ºÑI±!z¢ŠŒ,KNÿððÁßß?/¡UTUA£qºC�&ÌÙg(¨2²!‡,£Œè߃Ôèzø% IDAT5 éåFóEû…_À»swEFðKaêÌÑ$xÕ�¹k''ÛôH9?‚N[§<Ù[<É�Ðhµõ D�€è(|1P\lA6RT£%"2‘àÈp} ¥¶¶³ÙŒ(Šøøøà°Û9°oÿüç?ÝQ�Ûoäö)�ñÓ† ¬~ÙÌÆr�˜»nåJ¿óÜèØÏÓc§ñ̾†ýë;JiíÞf;ÈšïÎà@CòÈ‘Äté�¢cļYD½þ_ ÖÎ÷WqÃ9‡é¥ôå|¾ÇŽà1Œ«æ&µ”GŒåº[&ñç­ëÙ¶v E!YW¢à1r û9J)kXÀ3{ª ™¶”ï?ÿ-ýUW•Këv´#„öc@[¹š„ f,šGø×Ÿóá‹_rßg75…æ­ÚÉK¯nÇâ3†Å7öjÃ-Õ¾çïfiæ<³ûz5N� ^½‰R>çDº zzVN=�y}C][¨Ù%…Ý?§á«wê¤v‘ÐÇǾ+�<[!ùe2ɱ" QtxG+ˆ~IL¼r Éþ-{S*¨áDfY×£“ ÁCÔj<‹Y½ÜÔFÙ“žþ§9dÊåtþâµTdgc”E‚’’ SW„—Í#ó ‚@aq!EEE€B^ÁÙ× ‚@tt,±Ñ1�®GPd¤sýU•ª]Ü™n]‰)#GÒ#R$jLk¶žfÏOG›1ˆPWVpz ä›�$htSÁb4aWDšv�Åàh¢½Ž“YTŠQ* „Ò7¼®rmX¡b6…ÅÕ„”• y%ç4,ªŠÊÿné©©©<üðÃ|¶l+W®Ä`0ŽN§ãСC¬øì3îºë.èŽê܇É5·Í&HÉfÙË_R"Öå�:ïçYÛ�é“#‘+»žý?öî;:®ì>ðü÷…Ê…B…B$Ì™lvdGu·Ú’Z²få �¼¶gÇëÙÑzçìžñZ^¯×gf}Ž-�íÑÌñ:ìq¦:ø4�e!y7ñìË§ŽŸ§ýänLW�l/£n×3<¶§ž¹PÕ5„ä>bºƒÆêò)d‚áJlW;ÉÉê#"„Rè—~ßB*Ülz¿ù+ n|íâYö=úÔ½8¯Yþô/þßÕ­µÖŒ7Ûé‹Oa¹Ê©ij¡!°–ë¾XL µs£s˜)¥ŒºÖ-4®éñAXÎÿ�­»ö­¾ ³Ÿ£ß>B[ÎBuxpÚf­¨„ehäry £÷$lÁVž~þn§»³H\‡×ŽÇÈKNªš6³1dÇH�ëífШçðó5t¼ñ½šJEË^¶×„¨ÛP…Ûâãï¾ÅÕ4Øu4ÕxÀQÇ�ݵ8ÍÞÃd²ý^ÿ¸—)ˆ?²‘æÚ.Ù`jóxýíaÙÆÀ1þá�6²ÎV^úï£n�.*-zŒïü¸�´’«…úqêÅOëC×u¢Ñ(••UX–…¢((ŠÌ‡}ȦM›Èå²\¾|åöö­­-8Nz{{yî™çV|\KË�He0>Ÿ ÛÔyiäÓ$ÓyP¸½nìb:“ ,¨ák­¸I¤*ÅKÍæ½Ôl¾W”p‡[Ùn½WáJÏ¥IÍYÄ[’mØœ~ª‚UÔmhaKSîY�+ ÿæ'y6õ!?¹6Èpdž;Ɇ¯z Ï=±—F¯‰oÇM†/ 1Ú~ŠŸ mç§«pËUì<°‘èG�LNôq}ÔH€½»€…Þ“dÊZžæsîKœ<{�žXçbwÎÇæ©¢uÏ>n />¯u¶È&šý7¹8iáÝØL� ¦ibš&Š¢�Éd°ÙmÈŠŒa˜·×­œ@´µµ³cÇvŒ»2C,�dsQV^Úd'÷Šb÷°ß·5á�&‚(A„‡�\ÇáŸû*‡WS†ä¦þÀKüìž4“Sä,§ÏO™óÖmE¦j÷Ëüüö,Y]Å鼓2Ù·ñ)¾X·�ÉTT>¯UZì½B™ÞÚÝ*6—Ÿ —™g»‹ÄÍKt¤-l5›i]Õâ~Âý ª*ªªâp8n÷L\¹v…|^cçÎXlß¾˲Ð4 ³t‹: ‚ðA” ‚ðÐÓâ9zvMö±cWÞh^‹0›$IÓó¡ }‰ÍÍÍܸqcVr‰™Ûnn½gcñAøA” ‚ðP²Òý\º>D*=LoÏ0)C%¸ý öU‹ÉPŸ$›[6³¹EJ‚ ”–¢A„‡’•¡ýÊeÆM�Tõ{å©]b�Aaq"ˆAJrp'¯|¾©�ÃãÁ©Š1|‚ ÂÒˆ JAx8I*.ÙŠS¢ ‚ ¯eQ�üßѵ8�…�¹ñó÷市 ëÉŸ>¿Ï@A€"‡ëîzÇý>AAAà ¢AAAÖ D ‚ ‚ ‚ ,ƒ¢AAA–AQ‚ ‚ ‚ Ë ‚(AAA„eëD=T$ ŲÈå-Œû}:놨A()#ÏTNÃ’ì¸\¶µZw¯�·ž•º.DÝ ‚ õÐQ^¯ŒS’‹tÚ$c.¾�¤H”»åÂMÃ0ŸZ¸�mw*ømzÞb"g-Z¾b“©*SØ%d,²Y“‘IƒÄ<ñzdœ²´p¡¦ÅDÚD/v=n;¯ìwPžÊò�óyÖÚÖ‹¤JTúÊ�2*�ËŒ$L&µ…ëfV½XÙœÉp Yì¢xðêe¹×7×r?g’,S�©pÊØ°ÈdL&�%]“ðI£“ž˜$£ƒâ*£Ü³À- Ÿd4™Ã’œ”½ØæÝP#9– g‚â PîR0úŽñ�ïwcøwðÙÏï§j�[ÞFô8ß9Ò…v�ŽwoÜ©W»/ˆß±ÈoÜ´R×ý'³nM4Í@Rl¨rñ× -K^—PìÓÛ{M„‡WIƒ(7i*•Q\Ò *ÓÅ„$iyKy¨å‘Uöír³yújûÚR¼5h²Xó³¬ÖÃ6ÅF"Ëw.Øw—/³¡ÑÉu*n ÆzÒüS�1ùŠBËF'�DÜsî‹–iÒߟå£^�äÌF®¤r`·›–EþbÖTŽ×Îäˆ9¸' P.Ab\'i±võ"ÉÔÕ;y¼^ůÀÌK´L‹X4ÃÑž9× ׋aÒ;]/éYÇz€êe%×7Ór?g@°ÚÅÓM6*ÔÙ#¯sµ=ÃÉQ K=LLϽÅ{=JäQ¾ôâfv¯�G[�´z¥…7¼MfóV7O%ÌœÎÅÞ<=) ]’(ó©ìh´S×àâ{†nÓÉÞÚM‘°É…+ˆ�N7ö‹]_Î$_ô=‰H¹ŠŒÉÀ„uש–®^$êšÝ¼X##[#Ãy:'L²Hv¶TÉÔÔ»xE™âµ›¹Û»ÉlÝêæ‰ †Iï FoÊD—%*Êm´V(46º(S2¼Ö©£=hõ²Òë›¶üÏøÂ.>ÝjÃeYŒÇó´�þv¶Uvlõ _Islüîë>©ìÔÔU¡öDÑãÄ´Íl*Ö6·RD& ¶9N,ÃÎ27ÅÚåÙÁ£&`«¦¾ºpKQóÕ¯^»Ëæ%ê~Z?çNÜdÔ(cÓ�­ÔøC¸õ~>žûšé"»»B 4é Kìá“­$A”ŒA%1¶o݉¢(œ³A¡,â`STçZîÁª—•^¬ìs&©*û7Úp[]S¼ÙoÜZØ>˜§{£‡Wê¶6Ùi?—cDtG=4œ‘:*•(1}ˆþA�M EnÙý£&’Ý�]Ë120H~KŽ»6Ôˆ £j¸–Ú%v–Âý`MM2©Y(Õ[ytG+NÀšŒÞõEûçe‚­�ñlë==eAÖ±’ôGûÌ8¡Šrìv;²,sùÊ6omáܹs˜¦‰,Ëý^Æd)·r–ÉÀ˜‰)Él + ^|$¬âµ,b“ŧÛHøü ®¬ÆÇR¼Ó§“YÂã|ŸOÅ)�•Ö螺{‡ü„NT+Ìc©ôÌxC•±K…ápÚ 2(~•ˆ ú¤ÎàÜûC ë%X¡R&�‘Èq&>·‡Ãb"–§ÏIV©òÝ) R¡b— Ïq95·TÈ3`ܪ—~@êeÅ×·ÂÏ™³ÂÎ;X�SÆ]s³{stj »mlžg˜–ðÉ$yj¨+—ÁÊ):oO`H—p7¶Òè”Ї¢ ÎíЇ‰é€BU]Í� +Ÿdt4N|"=»W5Ÿd4gt2‡ è©aºÚ®s­3~§×}𥧉vÑvã:W®·ÑÑ?BR_yŸéŠÊ32ŒöÑq³�ë7ÚiïŽ2œÈ/<v%û”ÒBu?z§îA'5ÜGû�k…úˆŽ2µ‚ßP37}¼ÑI2÷1+�‘O391ÎD"M~¾Ê¶ÌµÛíwž {mLmЉñqÆ“¹E“™Ú‰‰qÆ™ùÏY„u«4=QF‡ÓƒenHº®“ÏåÑõÂOˆeYH²„dfA)ÅWJ"5¦3Q¨¬´î1ˆûáRm´TÈ kt'$ê#ÅʲHƳ¼Ö©3aÊ^Š[udYƬϽ‡K`š…Ìš%KØ%À°È/éH³•N&6À¨™“,@gh`…ÚH ÕÙk´õÑ?jÐX=ûÜ` k�¤®æÎp?cà,?(’ÜÀˆ�ã‡ïuaVâ ûs}û<ÃHž-6„ˆÈ€•%vå8_èe|NÉVƆ=�óäöª"½bóXQyñëÇ9z¶›±»Z·*ÞÈb/ ^y•û”Þ¼u?t�×ßíÀä‹Ï¹ùÁQÎffÝgo=‡ž;̶àÒšV¦��Þø€ ‰ò-ÏðÊ¡²Ò_Ð"òc79uò7‡RÜúóJ6/ÕÍ{xl3A@žöwÿ‘ú¦}»?à¯ÿú$»„ukœ÷ôkrÅ^¾ð™EŽdýøÿ›3'Êdàøwy£ÍÍ�ϦìæOøèÚðtÒ ›¿ž}‡ŸdghöØ#ÑÃÙ“g¹:�@›þÈö2ê·à±Ýu¬ñGD„)Ie™Za2½a`Y¹lŽë×ÚQU³ a�¹Ü±Vk §Ñ•¶Séµ±¹ydÊëjð^'‘ŒMXTf|jÍ1úcY,¹’êJá©rä¾Qbýã˜Õ¡=²&ã1ÒÈåµÔû–à« ²†>Áµ3Œ;Â4m à°Uâ”4bgÞá­Ëc¶rš÷í¤5âÇaehç╺Ný˜)óe^Ù\Â3¹••—í>Æ['ºÈ¨elع•�U>œª…–ŒÓÛv�öØeŽQùÌgv’W¾Ï=%ê^ׯ¹|ô]fûŸª¥Â­ '‡¸~á ý©>N»NÍ+;,öçÌsöÝ£ÜHXø›ŸâåCµ¸îq§¶™¸Á‘·N5Ëi=ø›#~lZ‚�öóœ¾ñ?J›¼ú\ >I%²ó)ž«îáÔé.¦*·qx[%Z6‹l sîökU(Îr<,0z{Y–�g? Ýªåàsû Øt&û.qâJ/§>¼Dõ«û¨œþ›[SÝ}ëC:se´ìŽ-5~Tm‚þkç9wñ=ÞÈ=Ï«�Ö FÆ ÂúWš ÊÐÐt]×±, Ë21M¸D隆©çYúãÃ5 �dZt ìoQiÛpŒj³{ $™ U**mCºmþ j%ŒdŽ3q•§C6m6ÉÞÌ1�-tHÙ\*{6;¨”,&²´Íß"É`— q¨'ä`[X¥Ú+ã–!¯™ŒNh\�æé�*Ò¹eS©õHX9ƒ�bw†{X/‘z;ô„ÆÍù"­9ln•C­Ê%‹d,Oû'¬^º¾‘Ác— ½~ùùóPLå �£ì�qI,i˜ ðÉ ë¨s_åjz‚��4{ÞÛŸ[sb€è”…\!â‘ñUWã—GHĘ´BÜžŽg¥ˆMb"SVSË’F…J…ì•Öd�þ-¼üê~Â3Ò›£Wøøêº\ÆŽç_æÑê;MÉPU-õñÚ‘› ]8ËͦçÙ\<µà*ËËíê'cÉ„v=Ëó;Ëî|§#µlhªÅýú›\žŠÒ;¶“PH^á>÷˜TèÇ6Ç:¸9Èg_ÚJù­¨1RK­/Ïwß¾Aj´�þÔv Åú8WÞ�óqφÇxù‰Æy²<®%�è¥ Dó6êŸ|ž'›oõ„–Q^DI¿ÆOú/qy¨‰Çª¼U�xì\8SîJ7l@¬‰Wn¿Ö8Ý(ZÆØ: 0“ åöóêË;(ŸþÓVUy˜ü>§Æb $-*Ë$@gðÒY:§l4<ùOÍ8ç`e%ó޵�çú¶»üb˜µ ¬w¥ÉÎgäÉf³èºŽišØív2™ ‡]/—BƒK¡¾ÊÆ�SüdÎ\$›_¡J†Ü„Îȼ åµ® ØÉÓ52’ap¾CcbÞM¶¶:h´�Ý)tɨºAwOŽã½úƒ_/˸¾•‘q(€Ú�XÚ­ù ª$žz>l”õ×nf$·mÓô„z‹T,F”pG"d�Ë#T;/311ÀÀÔNÊoµ–³1úÇÌÂðÀºà²&ØZ:ÔìÜ9+€“áŽ&L°Õï`OõÝŸJgݶ;9=:HGß­[< <´Xay–F.WöUèe˜C ±ÿs_æ€4ãÈ+Ùç~‘¼´îi½@M³…ª©To�ÒÓ$ÓÌD™):>>‰�ÎÚGxùÉMøïGÏš§7šÅRØÔ0's¤ä¡¡±e`¨èW/ïó¹| áææÛTá¼”ûÍ‘ÍZP&�9FO ìMlnœ{Î>šš*998H_tŠ�þ…>Û‚ ¬% ¢ -G&“¹DíÙ³‡Ë—/³k×. £pcÉårúJf­@߸ÎÿpØ_‚3-ü$YšF{ÜIcX¦%$s=zg  ò*U’Åè°NÜ*Qæ�9U&à�±Ë…t×éœE^2‘‡*áw+”Û Ò3RµßZçÇ0éêÉpjÀ 1ý°ÌæRÙÓêbw™ÂæÍ.&¦¦¸t»gE¢*¨`ºÇ�Ÿ¯­e½TÔ¸x±YÅc™´ÝÈp~¾\ä’DE@¥~º×Ò2M†Ç bI“¹kË>�õ²Œë[ mµÅ×€2)œ³¸Y?lTªëª±Ýì&?%¦mb£ K,:†!Ù©‰T†·)•ÔUÛ¸Þ9Fÿ`ŽíÍ…pK`XÉ¡~¹=+rˆHxNPc¥™ÂB&žgΓä#\åBMÃÜâ™HßJË“\T†¼Èƒ F.å#u;7†)›±ºª47ZÉ>÷‹¤*X¤Ö;U]GŸ7#B–è©wù°3�­z//>»…ò’®6¹ ¹Éœ…ì PVär>v)F:‘Â"¸Æ'£àñÌ Ò%UA¼õ»®%˜œ²À–¤çÂ9Fæ|$Ìd‹Äd“>Û‚ ¬ %Î7»'ª¥¥…––,ËBŸæ§ë:–±² êÍKK�<Yåð£n6+wZ¨}Cé°�ªjå9Æ, ký„$ÓàæðÚL´—6ïvÑì°ì›âŸ{uRÓ-]I‘Ù°ÁÅá/ùe~|.CÏôDŸDÿ;`� sæF£et³ßÔ¾ IDATN_ÉàÜïf‹Ce{DájÇtF6I¦. ƒ©M,¾PÉëE–hlòðLDÆf\¾–áÄØ" ך:ç/§¸¡HØl2e*­Õv«²±}(ÃmwÖƒz ëe×·"&€„²@»M–§ƒ>kYƒW„O[¤Žj[7½ÚýÃ:kUІèÑA­¡&|ëö R]S…ÚÙÏPtˆ|s#öÛÉ'$ìÕµT-÷N¢¸¸«ÍiM‘žÎX:qõß½YüÃkf³X€15EÖbþad+.O¦r÷“ì�áì`œëÇÞæú ;þŠ0‘H õõõÔUzæÜ^�¥ëè *Eç$EEòFá!Ùš$’´¤ ùÖ9[ùqz;REºÙÝnl’øE„AI~M=O^³“Ïç‹e˜œœËÂÔÖÃp¾cR£sÊÎ.��V_žã ¥ÌF³ ô1�ÎÕÎK)J¢ºÎI³ò£YŽtë³&¯Z†IWg¯×á2jóôvç–µp oK7¸1b²¹NÆãWðJ“H.•ˆ¬”Al Õ_Êz‘l »¶¸8X.cf5>¾šáZjikÅ¦Òætr ƒ�Q�«1ƒ÷8© »y*‘ä�˜õÀÖËr®oe,r…¬ÓØø†ÛÔ[=³VizÀ„‹=BCH¡7–e`` ³¶ sx€A”p ‘Cíár?ñ#F#µÒÑÁ, ‘úȲ‡ƒJŠR¤Ánb˜V!íô|íH»¿d§´ÈwdåÙ*Ùûâ«Ôw·q­£‡Þ¡q#}$Fú¸qñŽàFö?þÛB3®|%ûÜK_¯{+ÕΉ ÓéÀõa.žëaãSpß§6ɦ‚'M/<4šs–QX´\QÕ5Ê·t’͆*�ìÛÆËŸÛCÅz91AV¤4Ãùô<�H$w½ŸÍçA±aë ;ß-–Aû°ÁŽ Ma™Ó ƒš*ÝÃÚ’3ó,‹$ HHXŒŽÏ“ Í2‰MšP¦PæWpIE–“*¶#S¹Âð-Y–n/öê)W(— 5©³¤UºJT/’MåÐN7;¼�Käx÷JŽ�e§Ï»ÃÈh\±S[#S²áˆåïZWfž ZWõ2Ÿ•__ÑÒHf-p€×Yø¼Ýý’𺠓üõ¬Izç.< $5u(±aÒCCLZ!´�A²–L¨¶zVãXòTS[&349Èà„I�c m�¦>Rª @Án2 U{>ͧ7»îoy²“PÓ.žjÚz†±áÑh/�}ÄÇ:8övå³Ï³yæÜ¡•ìó 0-ìÕ»xz·�‹ï�!Öuœª‚¼´Å‚{§D4=É„Áœ€Ä";™@³de¾uD¡úx$úÒEÎY„MI¾Âº£‚©œ~;‰Ä\.·›TFC³•—âp%3>¬1l‚;h#lSiª�!¯Ó>ºš^€…٧ǘæüG¸õ–$ƒ:c3Iu�{¯Û.!¦nM7À%"Ù2‰Ž/2„n†ÕÖ‹¤*ìÛ^ Òñ,¯_Z$€’dk<Òä¤Å=ßFùéD’¬'ßë¾^Vy}ËfÁH ,$‚>¹ø“ ª|…kÃç?ÿÛËd¬|Œk]‰ù¿û+Ùg“<­<ûÂ^ê#ÛxúP=.rDÏ|ÈùÑûôë!WÐPçF2bÜ왚]§f’Îî8†ì£¾Î¿~æ|Ê4Ôy‘´Ú:’s>&“mñæÑóô¤ÄOˆ <|JD™e-ŒÅã I¸ÝnìöBP’$ìv;†aÀ ´–âp%ceuÚ&‡ÊÆZµ*¤ãýk¶êºI*_wPæUæ©|‰rw!Ò2rV¡·J’Ù»×Ç/>é㕹ø AVh¨(¼—NN÷^É µe€a]Æ$›ÕÕ‹DC³›½~È�gyëzž±E÷“¨Œ8Ø]ggOµ2ÏØu™ ït½ä§ƒ¡¦^Vx}+f12Vè³—Û¨³Ý½…ä´Óì“°L“žÅæ¨ ŸX’¿–zŸ Æ(C±A†ÆM$W5µås�dB‘0Édtx�èð2ÁºÚ¦¶v®.CÆ"�2^4걘ŠGLä—­°<=Ãø`í}ãÅ.8Âl¨q!a‘ÉæS­hŸ�b£� UÂÛüO5û�µ8Žž!º²éΫ¤R³sõ�þGøÉµ>†ÇÆìáü‡G83dâÛ¸�못G¡zÇ>š<ÑÓïðî….¢ñ1F‡£´�{Ÿ·Nt08aár¬›°O„”æ×Å _±—sç/råʲÙ,�EQäüùKèÁà •äp¥cÒ=¨‘·d6ÕÚpaÒ1<�x`-X}#…§þÞ*;;¼wob÷ÙÙɲè�ë…²e�°�%‰ª'{üÒœ§Ä2�MNvºÁ2 ® NO¤õ©DT0“ƒËzX¸òz±•;x<,A^ãX[ž±¥<þµ nÊ/«qr((ßõÁ T;Ø[~§^4xpêe¥×· ƄƵ¤6�n²1sÉIUØÝb§R‚ìXžk2vUx ÈAêjÝHVžØÕv†t {¸†Ê"‘¾®!¬‚6ÜÆµ! ä2êk¼%|Ê/hn¥ÆæÄUŽ_½ë{ O¶ñá�ßå‡ßû!'‡ûæ­¬<+ÓÍÇï¼ÏG�s1^äBŸ 6œÁB¦¬¬pý+ÙçÁæ¤áÐì(W0&opôXχ�—–äÝij/?ÁÖŠ�'�ðýïŸï½ù>g£P³ë^y¢�Ru”–ŠäÞÀá—žfwµÄÀ…£¼ñÃð½ý˜£—G°5ìãÅOí¡ªÈƒ/AÖŸ’åÖ‘üõXîJ®�ws£ç$ffÉæwrà Èv_©UR¹q�nÍÆf;X)�›Kì™�ì6žÝí¤êöÝÐÂfŸ^6¯ÖÅÏ„ïÜ&Íñ ßk/4Œ'c9NW( ¨Üí¥nD#š6Ñ�ñz6†T|Ja܉‘[ÃÄ,Fz³\,w³Ë«²·—æ �Á) S‘¨Ø;ˤ·3ÕéFqyyaÎÎȸ¾ìž�•ՋĆ;EåànØZÍðZ‡ŽLD³œ*ws( °m»—ƤÎà”‰†„ß§Rí‘P€©x–“\½¬ôúVþ9Ã2¸Øž§n—ƒêJ?íµÑ;a’“dBå • +«q¬C+>7OxHÈTÖÕàºÖF2l4Ô†)Ú†³…©«PèŒ3HþšB†Ë’¼-<öȯÜKìÌ[|o`#͵\²ÁÔxŒÎîšBYëAv‡Ï·¶’ò$ß&ön¹Áð•aξùцjƒ^2h™I†z»èŸ4Qʶ°»iz-Ÿ•ì³dÇ¿Ç;½PªÍ*~æZW;�l9laö?µ‹Á�c¸ûG«ƒ¼¸ùÞÏ?²šyüåfåÓ$ÓyP¸½nìEND ìæ _ݽèk SûØ—øåÇæ¼öøÏðË�Ï~­úàùåƒÅάØöŠ¿�ƒ/4°_›"™Îb`Ãíõâ\h\º ëNi”ªN”ÐmY?9c´�X´ÖÂÈ°ÆøRŸ¦IàrHøä/LSTߌš5l3~MƒK—RLÔ;ÙQ‰T;¨™Q¬–5¸Ñ“ãLTŸ5Ùß2tN]H3Þè`OX!Pn£|zŠ™¤Wºr\ž¼54K¦6 !Y+®µ’z‘$lŠ…„Š„w‘6Ž6³¥f\ºœf²ÎÉÞˆB¥_eÓŒ¥Á´¬ÁÍhŽÓú¬'žD½¬âúVü9ŒTŽ7/˜lv²¹L¥9Rxݲ,Æã9Ntäé_? 3…ûD©¬¥ÆÞÎÍœJuE¥@rS]@ÅDÂ]S·ãeÊZžæsîKœ<{�žXçb·O›§ŠÖ=û8¸5ÌÒâ…•”g£æÀK¼ì>Ãé«= w^c¨óN‰’ꥺu/û÷náNU­dŸ¥3´,™…º§•< L³]3JpÏæûÇ£ôŸþ� ¡Ù[qòž+v»ç¾{¥d››²À¼eAXç¤Ð/ý¾…Thíö~óWÜøÚųü�ï6Ý‹ózHHØ�2~;¨Xds‰Üâ ¤xÜ 0-¦²)}îT"àWpa1‘4È�¦i¤“ô÷tŽÔâõ—­úº@Q‚ ‚ ‚ ”XbbŒ¡�(�ò ›·ï*)Š ‡Ó…?ÄÐu†bQÚ¯^¢¦q#þ²ÀŠ�-Ë g¡l¯ÏOum=©d‚Áh£#CÔÔ7b³;VsybN” ‚ ‚ ¥362ÌP,ʆæ"õ�KêYRT•šúFš[ˆöv1>/é9y}~6mÙN XA÷Í62S©U•'‚(AAx˜y¦¦Ò¤3æj^AÆãÃŒ�ŽÐܺ—Ç»ìýÝ/Í­[ŠE™-ùùUT†©ßØLOçª)1œOá¡£‘K�3Áî âwH ožO2šÌaáÀôa¿½¹E.1F2’ÃO…ÏVäs¦K2²¢bwºq;ÕOÄ“<=3ÁH|œD:‡f˜HŠ §ÛG "DУ²HíÞwFô8ß9Ò…æßÁg?¿Ÿ*y‘×ûŽñ�ïwcÌy]!�N12Äöç8úöy†5�<[l‘#I×Ù�9~}n™€â&²åžÚ׈¾@f Œ�³ü Hb c诿Û�>ÈŸ r󃣜ÌÌÊà§xë9ôÜa¶g7?ÌdÇ?8ƵxŽ;ÓËT|u»yæÉ0=GÞäbÂÉÖ—¾ÈÕëù³!§ñÑøšP·øüe$““kD”••“LLŠ JAx�H¸7l£ù|W’IzzÆÙWQ±~3÷)B~™Þñ]—®°¹rUËN씥ïøÛ¼Û–ÄrU±e{ uRnŒžk—i¼Â‘wt^ü©G©½U¶ª K`è\;ÓÁ¸#LÓÆ[%N C÷Çoó^G Ë^AëÞí4‡ý8É31ÔÉŋĮå�ü3¼úD=%oŠÈ…óÓµq.½D—ÙÀþ§j©p+èÉ!®_¸Bª�Ç®SóÊ·âOc„³G>äê¸�â«cÇÎjü*ùñ~®]>Ï;n 2o Š)ëR&3EEeÕš•ïõ•1>6J¨2¼&å{ÊüŒ Æ–µ�¢A„ûO© ¦ÒÆ•džÄè(y*JßÈ/¹œ-»¸~´›©Ás¼þ½>›6ÒX_CM¨ —ºxK߾‰›I µ’/¾Èžò[]Cµ46„PðW'or¦m5;ü…4é’Œ X“]tú·ðò«û ÏÚ¦^âdg S°óù—84ãÍŠÊõA…×Þ¹A¢ã —7×r Tâ0U 0Ç:¸9Èg_ÚÊíËŠÔRëËóÝ·o�í£?µ�€¯POÙžË\7@­æ‘O=ËvÿôyU×ÐX_Á‘×?¢;cÊA” ¬K¦a¬*¥ùb'š–[³òí6Z>¿¬}D%‚ðÐ28ö]þîä"-SCgy·–•�ñzÝÈä±228%“lbœÔ¬üá&“Y,“Ìä(ñYy¶%ìþ ~»¬fßÅH¸7>Χ ;œºI<§óJœÎ+€lǬ¢ººšÚºzê«üØïŠUL†»º˜4Á^·…­åsÆÖÙªÙ¶gæ°…Ë­c¬ùQ–5;wÎ  À`¨«›¤jõvTÝ=qÈÙJkE;§ãIº{ÆØ ­MoŸä¥uO+w]V¨šJõ)=M2m�O4ûcä{ýZü³ÏHö6q`ÛuúÎÄ™;:Q„uIJPlk7aQ±Û0–ä,‡j³aèÚòöY£sA†žÇÐï÷YHHòtÚ²(¬Ñ›¦ý£qbÈ,²}žGÄ�Y¯)4þY>Õ¤‚µŠ}—ÄFù¦ÇxµqÝ�töö308FRË“ˆ÷“ˆ÷Óvù4ª'LËîh q{Mc+ÍH<ƒ…Œ?TÁÝ#%Mx²ižCË!"á9{Y)Fâ9,d|U•Mp(ù¨ 9‘âS$ÇÆÈZ›Þ>5HU°È¤+ÅŽC•@×ÑoEDVšñ � „‚EÖ “(««#p.Îè|KŽ ‚pßY€ª¬]X¡**º±v�REÁXfù"ˆAxh)Ô=þE>µÈb»fßG|ëý®5î�²Èå Id»›Hv*6³­|v ”ŠuЛ� iÊ3ßQú§£‡Õì» ’ÍGmËnj[vƒ¥“ahh˜Ø`”Þèéô×>~‹Øø³|öP kŠtÆdœ.Ë>ªâÂ3÷Ofen—éñ¸çéa’ð¸œHLÍèí[îÁ')EWÈwdz²dr…óv¹œEëBòúñÉ0*º¢aÝ’Ýб©kÓ¥:ª²ŠŒ8‹0 e™å‹ Já!&)Êâ7Ž{‘áÁÊ06žÁBBõú¦×SrP³ýjfmhý¸‡¾¤ƒº�,�Åo5û®�¤â Fh FhÚº›Ç²#\?þ!'º“LÜ8É¥MŸ›>¦É­ž²¼üs�¥ÈÜ c:c ÈÊüeJ·þÖ¦Yèí[‹9F,½ÓÈX¼.dE4Va½“$ M[³ ÊÈk(öegðY2]ÓP—9qÝ&?AVº�îxaöO¸¦òî5’@²³’mOb“[3É@,=\¨ØT ]Ó—p,DE�Ž4 m¾ñ™Ö�÷Tu�dºSQ§ÿØóÕ14rb(Ÿ ¬k²¢�Ïe׬ü\.‹ÍæX|ÃÊk9TÛò‚4D ‚ ÷Yžþ WÔArÖÓZ¿nóò™ñAºÚ®p-–Y<R½ø§WÖ4­°½äÆç‘‹T2U¼ SG/6�k>’¿§�P#™LS|W“Tªðžâõ.° ñ=$9q¹ u‘I¯Os|ŒÉåÔ… ÷œËí&™L¬Yù©ä$>¿ÍÊOO&p{¼ËÚGQ‚ Â}¤3zå(Go¦°P©Þ¹›†µ±Q&C—ÞãÈǧ9~ê:ñÅ’rdã ' =l>¿§pÓ•\„Ã~d,R1&î LF/¼Îßþíßò7?n'³”Ӓ܄þB™±�âA‡':¤ ¡ªÊ"IîÉCE™ “‰áaî~Ž­ëê%)z¢a]+†HNN¬YùÉÄ$>Ùš•?99Žß¿¼Å‚E%‚ Ü{fžÉÁ›œ~÷ûüàT”Œ%ãkzœ§·•-zc²y‚„‚ MOE9ûÁizó ¹ØRk(ŠL°©…*̉kœl›œ•¾ÛLvq®}…ªºÈ3èÉT4·Ê¿Á©ŽäœÞ(�±kçiKYHŽ:6oô®Ét¨åS©n¬Å!�>p•óƒ3Ó—˜¤{Oq¼+�M´Va]óúȲBrr¼äe'&ÆQmö5[‡*™œD’$ìÎå•/æj ‚ kÈ vòûüùMvË —Í¢ÓÝ ²›Ú�qxOÝtB‰…ÈTíþ¯î^ɹ¬fß;”Ð.ž{4ÁÛÇ»IôŸå�ï^Ƭ¤¢ÌƒÃ&aiYÒ‰1†G“äM�Uì=üȬ6©l3�ïíçG§côŸx�ïõm !äFÊŽÑÛÕÏxÕ{9Ô²ô`G*ÛÌ{ûøáéAz�ýˆïl¢)ìÃnf�uÑÞ?‰&{h:t€f×êê ”lu»ØWÝϱØWÞy�áºzª¼¹±½CÕ�ì&xæë"¿ ó +Œá++/i¹Ãƒ„#µ%-s¦ÁhUÕ5‹o8‡¢A„5¥çÒ¤f.4/ɨª“²ò ášš[6Rë[ƒË–H!Ðò4Ÿ¯ÜÀ•K×éèf"%Ÿ¹�„ÍbÆMìØÑBµknWŠBpû³ü”û"'η1mçbtzO›�Úm{xtoÓ] Ö.v^åÛŸã³î‹œ8×F´ë2ñ®;ï¹CMìÙ¿Ÿ÷:é…š&—±íÙ—PÎ�ábÇ #=mŒH*î`-;žÝÏîš >• 1¥aªNüe>œ«NOX(s2�Ç�U\^?~—º¾‚§¢Lô¼Ž)Û°ßr©uòö?|H¯UξÏ|†}A1¶OÖ«©tŠþžNš[·âp®®Ë;—ÍÐÙv�¦Öm8–9Ôn)RÉ}]lhÙŒm‰™ù¾ö'ÜŠ›DO” ‚ ¬ŠŒÝSF…gû{„–—jIeV–´Ì5¢g˜˜˜$™³SYÄ9g-ct„1P}”yE%ë™Ûã%T¦ëfM-›W<�)ŸËÒu³�H]ÚPÉä$ýÝÔmh^r5—ø5Aá¾1'®òã½Å[ï~À™�Üì7µ1®œï$mIØk©]×™A†ÂC!:Ú®1•N-{ÿ©tšŽ¶k„#µ‚¡’Ÿ_|x�þîNê›q¹WüôKôD ‚ ‚pÿÈ¡mlêáÝ› ®½û}Fëë‰\Èù$C}½ $5$g-÷oXb¦BAî·`(ŒªÚèéh/Ì�Ô¢¨ ‡†®34errŒÚÆ�ËN9¾˜db’¡�~dIfCóflöÕ=•A” ‚ ÷‘‹ÆÇ_æ¥ÀYÎ\ëe¤û÷ÞR\TlØÆÞ};ØàƒgáAâñù ôsãê¼¾�òrNêô:]Ë“ÍL191A*9I ¼‚Ö­; ¸cº–'¯åIO&˜œG’$ªªkV”D¢D ‚ ‚pÉnjw›(bý�ìݱƒ}m½}þ922·³1M• a˜ôÔž mÅ[yÿõËð�ŒT:ö=Í#{Úißû"ûKßÍÙ²¸ÄLH%„B!Äb1ƒœ~ù)ž=ÒMÌžÃÆ›ßÆÕ%îq«öùÖßÁG×(°X°YFªaO+ãÊ[o$üëÇ9:ÐÎÁ#�¬¿&íì~<˹fÛ¨ @s’·éz67ü7¯tõr¼¦ƒË² Hfñ¿¥JBM!„B!�Št°ï‰ßñÄánŒÔr®¿s;׌  †hº›Ý6&€õ¹£�5Ë|h@¨³‹h6ìÃoϵdåS`› ¡žBI‰ìé%¢&ØFŒ#=QB!„Bœg*ÜÌË�>Ã�3q\›xÛÛ¶PìšKÿ††ÛíFÇ�ŠG‰)@Óð¦xÑégò%ø4çÐÇñÄÐ }e¹¾iI%„âÒdÄŒÆQš—Ë6³¡³Is>ö5o ¢ƒQèØ]ΤÞ53ÿY¹¯�X#åNÃîtaÓMb‘qlwr/޽D¨X'{†gx+·qÇ[×�9ƒV¹2âš ë„F188ˆ4‡“¡(�ôìL쪟X} òÆÕ{E4Aº#¹wP-eD !Ä—÷s¦»�@(JÜ0Ñ,6œîÒ2³ÈðX/Ú’Fó«üzGFj5ÛïÜ|öý(óœæ|ìk~$è9ò�ïëÄV¾�Û·•c#Î@o€¨9ÁøMCÓ¬X.¼û¼Ï‘¸ð®ÏºTëÙŒ-ìúýê)¬½õN¶æhD[÷ðèËM¹›yû[×�±”Z¤*LÃËϲ§3Ž«äjî¸i ™ÓU0³›Ý¿{”}] r®º‹?ÙàÿàÁ즾)€ ørrð *[a…Î:êúë©ißL^á˜1}f€Æf?&¾ì,\—taœ?K©È !„%ÖWÇþ×RÛ>04ìc,ÍŠ'·’Í[·P•~~]hº®¡&h¨xˆ@\^v}fiÎËñP¬m/ÏïïÀH]ÍMW•5°ÌN<ý<µÑ©'AXì>òÊW°~ý Üó”áù¼ÖÃãºNç’¯g³¢‘Ry×u÷ñôñý<·7�;®(X2KkÇZ÷²ãDÜå\{cõô€žNi¡‹×;ûißÿ"ûònaKžãlðm©ùEt+°æR½:çÍš³œ�+}Ô¿áçèÎ]mßF¥w¸‚¨8]wr Ëk«WdI¯ð -•Ú*„b”x÷Ažzú ]q…-%�åÅä¤ypZÁŒGèïi£¾®…ÞŽ^zÒOì¶›¨N»¸¾Z-¥×òç~ퟘôyއÛ¸ü�o£:E›Ašósükf÷®ZüøXwÕòÇ}ûk¸³ŠÈñž{�•#è£Çï§µfmM-\qó ¬™‡Æþ|^ë!‹p]§±êÙìÙ)Ü|%«ÚžåhÍ«ì.Úζ¢%F©§×0kç•ßþ’]Sln/¿�?½¦ ¹›¯eSó“ìínãÕ‡EMaé.,ñ ]­Ítø(‹‡Šk®gCúèrd%ÿ²ëÙÜö¯Ÿ9ÎÿÝAIY!G#M�ƒ$4Å—_Çúô¥RþæN‚(!„XjT�“{�ÐGþe¼ãÆÕŒkW®`}u3»žÚÁ‰@û_?Eù[«Þrq‹r¦;€Iæ9~‚ÎCû8wÅFÖçN¸<™«®á­•5bM"Ý'yåÅ=Ô´±ç•ãÞ¶– ¯­¿Ø÷uŒ%_ÏfÀšÇÆ %œÞÙÀÉ׳"o39—|ËÔ 3‡Œ˜zk{$ÎH¦f/àÊ;ï$ýõר[ÓJoó)z›G¶´’R°’ —]Îú¢ñ«ûiö|®¸ývR^ÝÅžšvkúhPŽôb6l½šË+Ó$0H‚\+!„XjÝ´õ$@sPº¦j|Ãn˜î.æò-Ëé94€×«à™`[•ÒÝy†¾`”¸ÒqzÓÉÉË"Å:AK06@Ï@¬)¤ûè$vµÓÞ$¦,8S2ÉÏËÄ=Ùð#Lß™nzƒaↆÅáÆ—‘MVª}ü”ác)‹ _šö⟡¹Û„ú{èŽjX\©¤{l¤‰êN€Õ“Fšk²Œ�Ì-{J©-Éã»±Ç `õ¦“æœ,BIêó6ÀæMÇ7év£„9XëÇÔ3XY]Œcúcè8³V°mk]Ï�$Ô{šºþ5lÎl3ê§³³(J+��ìÜlÒäs‚ë3ú÷É”‘iïë(I—×@lCy1ƒ]4·õ±fQ^‘…sªË6õLE舂ÍKºÏ‰nFéëêàŒ?‚¡Ûñ¦å�—å™r!€¤Îw®éT g�þAâÊŠ'=—œ& ÛG8K«Yékâ@-WsS¥kÊ|]ô4kïø(kg›ÜžÉª«ßΪ+c„" °:ð¦øðNTÏF§udS}ý¬¹&Œ¿ßÏ`‚ÓJZŠCÞ 5 D !Ä’cbšš6uCÊ^rw”Lò¡ŠÐ~ô5vl¢/~îdÍæ£lÃU\³&çœF»Ñy�ÇŸ«ÃȽŒw]ŸÁ©wòFGsÔ6o1[ßr-«Ï™i§ûÄkìÜß@olôÖV¼ù+¹êê�”ŒŽf´íçÑs.0èxãiž>Þ¢—ÃÏ=Îa4R×¼�w_–ƒ—FÑyð^¨�c¯¸Ž÷][:aƒPõåÙÇÒK›oÉÿF¶„_â…Ó1le×òÞëË& vT –ç}�NÒØøöílž² œ®¡5–¼åTÍa¨Ž=7�,ý$!#ˆ?`Âè Ê ~ÿ.^;ÑAÈ“Ðâ&åålÛTJê¨–Úøë3üû¤ËÈô÷U‡Ù•×ö<öB=fÞVÞ¹9ÊÎgÞ +šg%ieYäOy9ç^όֽ<²³ •½™w^íâà ¯qÊŸµ…Ž3{%×^¿…’±ÝW³8ß¹¤3 ìÚñ*5½1ΦҰgVqíuù0Ù´;=ƒå˳8ôz-µõ*V“ºTzâæB·ãIËÂ3‹¤šÕEZ–‹´yÏÔÒ"A”B,5–4²Rušú¢Ô>ÊŠìuä$=!Nû¾gyúH/†-�ÊMk©ÊOÅ¡"ôµ�äÐÑFê_ÿ#ƒæÛ¸mmÆÙ§œº]ƒD¼�#;So–°y[!™n ‰�NN›Ó‘ J!–=�•ëJ8±³�ÁŽ<þûfJ+Ê)-.  ˇkša>fÏQvë%¡û¨¾ñm\‘w¶u˜•SHqæ+<üü):îçTÅ�¬i½kCMp³·ŽSù—±ý–U¤�´Äò )L‰ñÛgjö4Ó\CZŠÄh­o!¬t²ÖÝÀ�k}g›ñù…”Uâ~ü)Ž ¶ÒÔ»–¬I£( O^U)1Ní¯§9eËY1MƒÍž_A™ë4'Û¨o�Q>6Š2{9ÝÀÄJaEÙ”�Å)�o.cyêIÞðwpª~€ªÕ)ç†+j€†† ¬V–3i¬6Zü í½&è©äæzæ´ŒvâL=& §�æ;ÛìNtfÏé ¦žÆÚoaë¨9W™ÙùgXxøÙuû8²¢�-“G¹CfQF¦»¯³/¯:: üõœN]ÉÛîØÌ„SÊ&2õìÍkh¥3o Ûo^s6P*(¢$ÇÆ#O¡¯û8‡ÛVrm‘mNç;ÛtÑÆ#í5ÀVÀåo½–U#×>3‹üÂ\ÜÏ<Áž8“¾ÀUóæ�çÕè ôÒѧ:e ,0!.zÜ´P!„ MÃ]~·^]E–CÇwsúèë¼ðÔøåCÿů{Ž�{�R×`ÜÈ9Lºêêè7ÁVX͆¼ñ gQ5+3tHtP×<8¾‡GóRµ¡êlãx˜-+�l+ B „†S©8ÑèÐ1]ŸàkËšÅæÛßÏßw›¦k Ï†5—Ê21ZÛˆ�ùØìn !`‚-ŸeesTôL–-ÏÄ‚Ag]=þ1M¨ï5ÁVÀòÇìï¥/XÒÉôÍþÚ¡fö¼^GP�5«œŠ‘.B :ëP`Í]IuÎøÞ¿ŠªLÌ{™°HM$™22¥¹—W•€‚µkg@ �ÀëÙè]¹(«^ÁØÑ˜¶¬*Vdë "´¶ô _ÛÙžïlÓ%èhi'Ø —³lìSK«VN½|¹žNfº0èíöϼŒ±ˆ¤'J!–$éË®äŽÒjÚNsº©…¶Ž^â1Ý-º[¨=²«'—åë·°eyŽ‘¶‘ Ñuf…NZîs*´rs\h=!º»z1WzÎ�¸lÍ 'c‚©Ì;«‰‰‘¹5š‹ì,/zG€3wòŠukËsñ�zÐtsNæÆBny©'Žàok 9VÆÙEìLº›( GQ%¥ÓŽU›Š†¯byÏÐÚwš“=Õ\öfP¨èoh¤×Ôp–UR2Ãã¡ ƒ 4—ï”3ÇþÓØÝ{îFJ%ˆôÐÖÞC(¡Ðœ\våª7‡Y¢‚œéŽ¢ÐIÉÉžø%�Z ÙYN´îAz{‰1Í‚ #’)#SžÚ<”W=‹üÜÙôŽÌ¡ž�sÎYäO´l�æ!3Ã…Ö"â÷!÷lÏwÖé‚ôö'�ÔŒô –ÖÌlÒõ:'�yu¼^„C! ²å)¿¸àI%„K˜fK¡pùz —¯• Ôw†ÎÎ.Ú;Zij=C(ÔÉñ]OÓÞwÛ· 5¬Ô ¡Á¡ÖPÿ±çùí©‰3AÆà Å9óq4‹Ç„�z�ññ�NöúkØØý<û;º9ñê3œØm'53—üüŠ‹‹)Êö,èšžYN…ïúÚ¨o‰QY1Ü 6ÎPßDiNJ+§yÚ>š»ŒEûi«PW×Ŧ¬¼¡Æ¼ÙO}C?¦æ¦lùÌ_J�Mò×ììSÆ™&�Ön�äcÝIfùJ¶l^KñèwI©0¡°t<žñË*Ÿ—�AT8LX1ý|"’-#S˜‡òŠÅ…g7wVõltz»{•1AÃår¢BÅ"ĸg{¾³N%*N—cÂRÍé °' ¢4ìûÐÐÅh”L¹¢Ÿ ¢„B Ѭx2ò©ÈȧbÕz®ŒœáÄk/±»a€þš=^v;[2uÀÄ0¨‘È&`w“jÝ©M0œoŠöÔDlÙl¼ùŠj9^×HSg�3ÍÎ4Ssèuål¾êrVg-Ð\ =�Šò öuÓÖØB´¢`tÕÓRhž–�ƒí,Ø)Y^†»¡†PCm›ò(¶�ÙßH½ßDO-§*w¦ÇQÆPW�f±L³„±NöškØ”7zßè¬v©i><®£m¼yÿuËä}šeøè¦‰©˜tn̹‰’,#“š{yÕ,–䷩̸ž�bµNÚ`ÓF†¸ CÁìÏw¶é 3t}’R¦ëèÓ\?‹Å2T,L“ÄLˈ‹H‚(!„Ò�Ù¬¾z+=]ÏQ38@[{•™‚†» [ÈÙp+·Ž_Fn¡2DVÅ:¶U¬ƒD˜Þ®vZ[›¨;ÝLwo¯>Á²ýÆiŠ˜�´²r²vÓÙÖHs´‚eŽõÍ *�Ô²JòæéE+Ö¼e,K=ÉÁ@'[/£¸ÌJoC~S'½¢’ì�sÒ° 6Ê0™z䛆3£�ââdƒP+Öá–„OÀ„}djø3ÀjÅrÞÇ‹T^ghòz6J"Ab’ôæH3rmÕ,ÏwÖé¬X‡Ë¾aLÒ‡”ˆŸ&"6Ls¨×TסŒ‘<r*„KŠA¸¯ƒúÚ£oOÿ¤ßê%Õ=¼Ht<>´½žBªg¨G*8\œIàV¬½ìzî¼ó­¬ñé¨X;ÇëóÔ{1ž–Rʲl+ÄÛ¨o�B¢“ÓÍa”2sþ¾PõL–/ËÀ¢b´4´5{©oÀ´d±¼Â—Ôz«}xxU<:m#vV4© 0MRL‚Á¡Ï,^/îóÝ@^”ò:õl$4a¥ í_w»‡† Îö|g›Nsâ«7 O˜Îœò"(âÑèPåpÈP>qQ� J!–“ÎÃ/ðü®½¼öú º'{¼="ÒMWÀ,¤¤z†¿4œäæùÐQ ´¶Ò7akK1ØÝJG 6÷Fk"L_G#'›û&~ïÈ¥¬À…†"Ž,X…桬2 Ú›;ìl¢9¢°dVP™6Ÿ_§Ã LØ ÖÚ@ck=õ&¶¼eT$ÙËfõxpi` .Dô ¹ÉÍMAGloÃ?Ñ1ŒnZ;々¬œìEh Ÿçò ÌO=½»nÚ;'؉ Ð5¼°ÇÙEf{¾³L§yÈL³¡aè:Cx\TøÛÛ'.o2Ã(4ÜÏ4CO—6¥�þ~Z›ë9]s”š#©9r�Ó5Gikj Ðß�R öWPŒ"A”B,)6ŠW¯$ÝFïþ¸ã0­¡‰z%‚­ìq/M1ÐÜ%¬,™î®‘VYE� Ìþc¼v´‡øØ´þZ^úãs<öûÇØÓ9“%Ô&§Â ìzv/î|�CµFý´w…Qèø|Þi{j4]šŸ¡Â ŽoñMÉURI¡ âí�>ÝBXYÉ­,'5‰Øf&Ç×êÙ=µ˜ŽñÄ£=,¯,$Ý¥îkæäÉV‚J'eùFÖdŒZò–ç;Ûtö¢ulÈmfw‡Ÿ#|Œ¾òRòR­$ºijh#V´’ŠÎãÔ ÂD�$*|†Î  z&yÙ2˜o"g:Úøû)*)Ç“’2îs‡Ó…Ãé"#+›`p€ÖÆz¾Ùy‹�Û¥A‚(!„Xr,¤-¿Ž;³Ë8zøu-]ôw·è½�†Í“EYÙ2ª«—“çûlXÇ·ü:nwfÏþ4¶×r }tÚª6lâ²U¹Ì½Ýl£`Ë-¼Í½�½Çé:}œÎÓ£rjõ’Wµ‘ÍW2ÁûAÇÓsX»¥œÖWNãïoæD?XóÓØ¸n&Ë*Û)¬(ÆYа©a/©¤4Ùœâø£#[þ2*SOqȯð–WR0›¶¥–BIiûº»9ÓÔÂàÊç.Ý=/,¤¯y Û݇Ø} –Öú#tןýÌ�UÁ†Í›©Îw/ì‚kS^×óY^GÌG=Ù,•57¬"}÷k|c÷Ùùm7ù«/ãšÍÅc–EŸíùÎ2�î£ú†·b¾ú*o4õÓzò­º“ìeWò–ËÒ¨{ì� 1®CT1ØÜÄô¬Jda˜‹Û™Ž6ÂáËV¬Æb�¾éîõ¦P¹b5M§OÒÝÑNV^þyÈåÒ£e}èŸÚÐÓ„¦ïüå”?´ŸMWl;ùB1Æþ×^bÕºM °g“Xh€�p”¸šÅ†Ë“‚×e�á°E<<@ !®t®TRSì 4¯Á$ 0%njØœnRS<Øf1þÇŒ‡ðc`u‘âub=Ïm·i�oãå‡ÿȉp›Þñ6eÌn�“ ÕðÔïÑjdqÙ·±Þ·�'j ð‡bº—7•T—õ¼®V=ý}=Ÿåõœœ%]ÏŒ¦�üòùzâ©Õl¿s39:Ñúa ÍŽ'͇gÚ‚;Ûó�]:#:€ B+Ÿït•SùyãñGØÛ­StÕ�ÜR5ÿ½¥³à€ŸÎ¶V–­\�Å’\ßG"‘ ®æ¹ExSR(‡KKɽ?`$n’ž(!„Xòt왞٦װ¹RÉt��/iÛœò:jO6ééó°£9¾"pê0u!…­`U鳟%¢y*Y_y”¶=?ÚÆê«f0lqÖtìÞ4²½ v€és0í}=Ÿåu´¹Ö³!G ™Ùã‡sMn¶ç;»tG Ž™ç/Ör”ã=&zjëË%€M)Eg[ E¥IPV«•ÂÒ2ZðT­B›·—� �…%„Bˆ N¼û;÷w×SX±®ïœÚ>V Öo¢ÜÁºýêž�…„˜‰3Ú_Gå›Ö“/Ó¡Î1à÷c·;ðx“ šÏåõ¦b·Ù d¡‰ù&=QB!Ä@…Z8|¢“`¨‹¦Æ.‚†•Œ5W³)oZ–®2®¼¢…®uÞu˜’Û6�--±¨ât|�Ã} oå\Yæœ>É30Ї/=sÎûñed2àï'Å—6¹#äO¨BqP‘3œ4k Å®`Ûº\f±&ß„\¥[¹a�Ÿ§æ…Ý™l¿ºxQ"ŠÁÆÝì8Ú7´Šá•%,T hkn$»`ûÅ!/¿xÎûðx½´6Õãïï�‡]¬6…Åe¸çЋ7í1lÏBŠT 1 IDAT!„˜1=c-·ÝYATYpz<8ç}¥ ¹næÝ!bÊ‚n"ƒú/p–üMl¿½eq’zIÝ+…%£š›n_‹Ýãó€­Ñ¶æ&JË—ãö.âD½Y:vpVÛÜ{¢­6;‹…Õë7ÏC®.¡`�æúS,[U½`Ç� J!„¸hV\©¾…íÒlx|i,Þr")6/é‹�‰… ãHIc‚× /ˆä^©-ÄÌH%„B!.I…Å¥4ן"�-vVf%�a±ÌíÑJ"Ã0 ïß3O¹ºðÙlv ŠKôD !„BˆK’Û›² CºR[S¡`‡snATh`_Z%eó“1Èhh!„B!.8)¾4ü}=sÞ�¿¯WVæ[D !„Bq�ñ¦úˆÅbƒ³ÞGp @,Ûê›Çœ � J!„Bˆ ަiäÒÚXO"‘H:}"ž µ©�Ü‚"4m¾WûD !„Bqò¦øðùÒi:}2©@*‘HÐT_‹/-oJêæpé’ J!„Bˆ TV^>n·—ºš£3Ú ¨«9†Û�BVnþyÈáÒ$«ó !„BqËÊËÇéñÐÚX�ÝfÇ—‘‰ÇëÅj³C˘‡ð÷õ‹ÇÉ-(’¨&A”B!„8oJ*žªU~üýtw¶�ÇÑPXmvœ.7i™ÙxS}2ê<� J!„Bˆ‹€¦i¤øÒdÉò €Ì‰B!„Bˆ$H%„B!„I� J!„B!’ A”B!„B$A‚(!„B!„H‚QB!„B‘ ¢„B!„" D !„B!D$ˆB!„Bˆ$H%„B!„I� J!„B!’`]ì !„8ÚÛÛ; B!Ä)??ÆÛJ%„KH2_B!„˜˜ çB!„Bˆ$HO”B!„³ ”Zì,ˆ9Ð4mÖi%ˆB!„b†F§Ñ”S—‘àI)õæÏÉTD !„B1J)”RüôuŸ!cšÆbgKÌ‚®[pºÜ¤geãMI’ ¤$ˆB!„b#TwW;Á€Ÿü¢|i™X¬Òœ¾‰þþÚš›ˆ„Cdå -¼4Ó@JîºB!„Sx³*ÐO0à§jõz”RÄâ1ˆE;{b64 oJ+Ö¤S{ì œN7ÞTßðGÓRD !„B1 ¥}==ä–’HÄeÔÅN)¦‰¦iä–r¦£OJêŒ{¢d‰s!„B!¦ ”Â4M"áAÜn·P—¥.·‡h8„iš3¾·D !„B1‰Ñ«ñ™¦�šÃ²Øâ¤iƨj&�” çB!„b¦Ls±s æÙlz%ˆB!„b†d ŸÎ'„B!Ä”dÔÒ1Ó{-=QB!„B̘TçUl€î@eq‘žî¹`‚— %B!„B\ø;†JôÓ\ßEPYI/.'Ï5ÍBÑnê{‰hNrKKȰŸŸlΗثßá=÷ï ^p?üéG¨¾@¢— $B!.&¦iÒÑÙNç™Nbñ‰D›Õ†Ýá '3‡¼Ü|t]FŒ !.=‹C©þ—ù—{ÿ•½‰ îüú/øÌfÛ”Û��ò…O¼ž–UVá°;°X,DcQB¡ ��í´wµ±¡z‹e±³+„ól‘›ñš>¼¨�†®«éó£é õUéèÚ ¶¿Àدý^zå~0ãD#1.”µ%ˆB‘”ú¦z2Ó³¨¬XN_?±X›ÕŠÍbÁ—’Š×í¥¾é4õM§YV¾|±³+„ók±c5æçéò3öóÅβ‰ÅÎÄxD !„HJo_ëV/'áÿ5[%®Ô­X,:¦©0Ão{(ÊYOmCh±³*„b*ØNmÛ¸sYVäâ"tƒuíM'iùËÙ¸aYcæP™�6NvÁ�CeQÖ„Ÿ†#‡8ÖÜGÔâ%¯¼š +rpM:jÐ$ÜuŠÃÇhë$nq’–SÊšu+(p�O4’OeË ¬, çð05ÐFm{ðÍü':�òʾSø]+¸þú•¤/ð;‘%ˆB‘”x<ŽÛÞ…#ãý`´¡GPf*:a,ÎT°~”TóçDcy‹�U!„˜wjºrTk+æ“Oa¼¾—øÑ£˜¦‰^U…~Ùìo¿ KYÙ”ÇWçüÂ5ÙçEÊ„‡¾ùmÜÕ 9:_º»ˆ>ôY ÷¨(và>vÿ‹Ä Þÿ=p7k†£—Ø¡ùÄ—^ ±îãüìî _½ïçTè¹wR¶mi åH%„").‡ƒ3½qrŒŸcó\‡æØ€ftƒ^(þâ�nÆåŒ-vV…â‚cþú7¨ÿwŒü\Tv&Ö;n¥0ÛÚIìxžÁŸü×'îÁýá�¶pÝ)šÍ�Mƒð`=¿ùÚ¯x!±��}ñjVåØl;Àïú_ìêØÍ¾ù0[¾s¥Ãñ�æ´£k�ðäGÿç0µ™·ñéoeYºN_Ý.~óóG8xì÷|ùþ4~ôí÷R9m˜müþ«_âGûBØŠ®âC¸�-eØ£ÝÔ¾ò[øíAžûÁ—±fÿ€/^“Æ›g>²H‘faôÕÐNÄ£-<ü“g©O]ÏÍ7W�æ^IÆyX;C‚(!„IÉÎÊ¥³'ˆÝùêü€-ÒÐm(³—Ö–Sä”|‚Þþ Y™¾ÅΪBÌ¿9tDEî¹Kc#憵à`žªGíÙ�´ô4¬¹9X¯ÛFø?ÿ“ð3Ï’ù_¿H%;'jlÚ‘í5УîžÙ|/|÷�k¦R°n—çyï§Oû©=ìî|7¥yщZØÂhÝËÁ ŸàÁo½›" ”mýe\»ÆÃ_|ü—œªù=¿~ý>…£æ)~ûFÓRÉŸå¹»LS¡¨¢zÓe”Æ>Ƚw²ã/óWW¾ƒì‰¡sòoŘ-/ð\á»øÁ~„j—B)ƒD,�¹Às¿.®5…B,º¼Üð.¢‰4ÉË•á|BˆK�šå?±‡Â�¦tŒƒ‡q®Z�ÑÔ@àÇ?ž`OÉæf²m‡«åñŽ¿¸•|#B,'a$HÄ#hUëXãÐÀ袽Ë¿?=ƒßù‰ñDœ„'�@åml_mÓÏë{kˆ§Ò*îâ›?û1?ù×ÿÍ;‹âÄâCÇ2Œ8ñ¨ÆªËÖàÒñæ&šÍ‰óÎ9h 05.ûÿÞËrK˜H4B4Çw®3¿J3%A”Bˆ¤Ølvòsòèíï¡´´Œ†ÆF^Ús”¦æVV¬XÉ™î3defb·]dotBˆb67þÖ·ÑssÐNÔâú“w‘òË_â¸é&¬ùùXóóqÜt¾_üן½u쮊rÿü/$4ošcÕL°t¸‡·D‰ÆÇšm%›VèãÓ©4–/Ï@Ǥ¿¹•þᤚÝK^a«×�úæ¶&Fú–/Z ˆ^VŽã“Í·¾ó- ƒOÞûט¦É¿|ãë¤gdpÏ'î!¾{ZG;öìLú/Ò?ÿ¹ÙçgšášËƒ{¢ý( ];›l\ºÔ²mß—îC§3 hB–>´3ÔÌî'åñ]9ÞÐFO J|̸;}l>§Ë¿3ƒLçÄùXHD !„HšÕj¥qº¡Ž¬ÌlêQLÓàà‘c“^(!„xSüµÝXì6Œþ~û· kôôöÒÐPÏýÿø˜JÑÒÒBuu5hà¼ûÃþîï°8]Dví·¿¡ØÆœYï‹iõiúäëTÌ&±Û' $¬¶¡OTÜxsµ?å?À÷?w?¿>G+7]ÃUEY¤ºìX­V´Ž]üòÉD’̆fµ-J@#A”BˆY9zü(……¬_»‘“u5tt¶ †8rô0+—¯\ìì !Ä‚˜Íü™è¡ƒxJK ·}Í”RüÝß|†¯|õijn °°��ÿÕ=(¥Ð««!ÂR˜OäСs�étâD&L ¦iÎ'ú (@óàuŸÍÿÄ ŸOuÖcÒE£DÕDé‘hÍéÀ¡)1=ô~s*Šž ÷÷³Ü’g^XB�‚øÞ3üö©¡ êÜeÜÇæcüïg7«indN”BˆYIñ¦°g÷ë„B!”©ˆÅbÔÖÔ’êM�>±B,!†ab&†i¢”‰iš€B·œmŠëš(Ì‘m”B%ãwæ(¤$GãdMl1J‚Ó‡Ž0AÏ)£Ô3K¦«@']‘‰BƒÞ3ݘhX2³ÈÔ£‰=û»0±²ö®r}zŒp8L4!�‹Eènm#t¾#¡9� J!Ĭ466²nýZ<š®a·Û)--¡¡±a±³&„ G%ÿ¯}Í~?ØmÄÆ4M¾÷ýïÒÖÖF~~>y¹¹4·´ðíï|Ó4‰:„²Ûˆû8««ÏÝŸ^ζ«òÐ1i}öavöªI�kvíäO6c`¡øÚkY¡�ú|&ç4Ù6€Jœ`ÿÑÈø4F+ÇŽ`¢Sº¼§Ìƒ!h¤ûܘƘ4ñ&ž~òðЂSåc&y›í¿I’ J!Ĭ\}åÕ?Vÿ~÷[<ñÄìßw€ÖÖ6®¹êšÅΚB, ä[èö+® 6D¹]„ú3L#�Åj¥¼¼œû>ó9>û™Ï±|ùrdH»ž/|¥ÿß?È'þÀ—?ú 9•UTæ¥á09Ó\ËÉf?Q¥aÍÞÊ'¿öi®öš£v4Q2Õ¹ª1ÿÕ ¯æZýw|êžÞö–Í”gèøOïæÉ§öÓ¡¬ÜöÞUÌÐâz.×ݲ‘޾Nû£_çÓáÛ¸a™‡XO^~™ƒñ«¸ÿ_.ç©�}��á7øÍO&±y%W\³ ï˜<ŒÍÇTù_HD !„˜5·ÛÉ/øÉbgC!Ο٠ý*)!÷ _ û[ß$µ¢œÈÏ~F|ÏœwËÚµGŽ~àg$¾�5?��úr´txÕè<$pT}€ï=¸‘?<øK~óÜ~N¤óäð皎#³Šn~7ñg7±Ü!fŒÉøDM3ù|ä¿Zïùê],ÿÖ7øéÏDhx©rͦ͞÷ÜÃ?² ·™xsóÜÛ>Ç?uýÿôßû9öÌC{4ÝEÞ¦?ákŸÿ Wø"ä¾=G~z�Ú'Âÿð]üë•«¨›§‰¢¨YÉ› -ëCÿ¬Ð,4}ç/§Üøø¡ýlºbÛùÈ—Bˆ1ö¿ö«ÖmZìl!Ä’¢ÔÐb†aPwâU«fµ»ÍNËw¯©Á]V‚�¢üThh7zj ¦ÝÎ`S ¶òrŠŸxœX">ùNu+6»›%A{ í½!⺓ÔÌ|Šr<èFŒx4ÆØø « �ÛŽ¦b„Âã7Àáõ`Ó‰Á‘á,b¯}“;¿üá»øá�?ÌZ� Bí4´ô±¦�[\B–-J4ó"^«Ã…-ÑGcc¦ƒô‚RŠR!‰�05,6#@ÔAZª…x(‚asãuÙÀŒFÎæsÚü'çtíq*WVc±XÐum‚õàKîý#q“ôD !„B±Àbñ¥�?Fï÷@Ç?þ#îœlt¯ka>�è÷ëë'ÒÓKÎ}÷‘ùéON½S3A<’ ކ#-�Šô¡þ”2‰…‚S§M„ ÂSm@4è':ÅÊL €%•¢ò44¦$<áËžLÑ ÍI^iù(”epðl×’ bh\Ö‘Ðpð$8Q9mþ–QB!„BÌÐ\F� †Iý«¿Ä·};½>HpçNBûà\»ï­o§ø€Ò§  ÆäJ™Æ˜žŸ…1á(:eb3<útÛNøî© �QB!„BÌ”š[?� çd‘ñ…Ï“ýÿÝ24<Ì4L #N<ÃŒNØ•sáQêü¯èp�� J!„BˆóÈ4M¢‘‹$P’ J!„Bˆ)L´ÈÀReÛx7ÿñŸ@é²/ÁHb¦÷ú‰¥â|Ô'!„â|šq5Òàëîj'ð“_T‚/-‹UÖ¦—#‘ÀßßC[s‘pˆ¬œ|`þ~RŸÄR²ÐõI!„8ßfÔb{ó‰y Ÿ`ÀOÕêõ(¥ˆÅc‹.t…8ÿ4 oJ+Ö¤S{ì œN7ÞTßðGskøI}KÎÖ'!„b1$ÕÕ×ÓC^a)‰D\æmˆK›R$LMÓÈ+,åLG;ž”Ôy퉒ú$–Œ®OB!Äù6£%ΕR˜¦I$<ˆÛí–ŸX2”R¸Ü¢á¦iÎKÙ—ú$–ª…¨OB!Äb˜6ˆ½z˜i(yr(–MÓ0F5øæÒð“ú$–ºù¬OB!ÄbI~»i.@6„¸p-h#Oê“Xb$hBq)Hþ=Q ‘ !–(©OB!„ŸωBÌO]�ú$Ä© B!.V³x)�|éÍXl€î@eq‘žî™Ížp\JçrA¹ê“”�…#×V!„¸ %ÿ�|1·ùbý4ÖÖrª¥‹¾Á8X]ø² ¨¬ZAy¦ƒùžâ{õ;¼çþÄ îâ‡?ýÕóÚRD{8^ÓHKW?¡¸‰Åæ&5+Ÿ²å+X–ãœY7ã Åv�÷}éy" r.KØ…XŸT�¶Síø•BwçPY”6劥U6¤Þ !„b‰Ì‰2úŽñØ/ä¡§ß uÐwšî$wí[xÏ>À»6gc›§ã*‹«®cZ­èÚ¹×Î즵Ç$-?‡”¤î‚bðôsüÇÎ#ûÛ4ÇßMw�S} wß{7·Vºæ%8Tºeh?šŽÆÅY.DâuŒý%ŸúÔÿÐb‚žz÷ÿüó¼%eòRt1• ©wB!„˜—øp>ÅÀ±ÿæ¾ô ¯÷(ÍIΊ�lݰœ‚tz$@Gýöì=JÛÁ'øÞá�üñÝŸãk½œ¬yxœl¿öxé•ûÁŒ�Ä8»›AݯÿžÿÊÃ=~ƒ»òf~°È‰_ð7Ÿù‡C Wá&î¸ù*Ö—çãsj$‚Ý4ּΟz…“‡áÿþM#�oÿï+Ÿ�°PMò³˜› íZòúÏÓ¦lx½B¯ñØ‹Ý\ÿެ)zX.–²!õN!„óã’Îg´<Æ—¾ð3öøö¢¸ç‹Ÿâ®uéX ¥ 4ÍÁS<úý¯ð�Çê8þ›¯ð9ç?ó½ÿµç\3�ˆNLð{ æD+&+‡¦3½¦f'�ýø× �ï²{ùñ×ßC¹-�iªáóÑÐnºƒ¾ÿU¾~ïù]ã!øÑ³ÜðÕÛÈ�kP8¶-w•ƒ ÚvUï+<òRʹ•»?ââ�oï`ÿ“ÏÑ|ë{)�¬ ],eCê�B!æÉ¥;ÂÞìâ±ï?À¿BÏ¿™ÿóýÏs½/N"Á»­½˜·ö_ÉsÞ˧þ§žÿý}~}í·ùórËЮmœì¢™”—fâw¬ZëÚ (Ù¥¥d o ‚íÔ¶  l”•eáÔ¡ÎÓ4÷ãµÚJ…é8]Ëq¿GF1åYΩ‡EOðƉ(J÷qÝ]·Q¬ÂÄbc7Šƒw3ŸøøvN<ØL~¡NrÇeþ&®¥éÌÍ�/»˜UÕ+)õÍæ ºI¸ë‡�7ÐÖ;HÜâ$-§”5ëVPàžª%™\:5ÐFm{ܹ,+ò‘è<Ê+ûNáw­àúëW’.ï®�“ÖçŸäõAp_}7ßä¥ög/òDí3µ Šàk?䯾þæ²?ç?þíýTŽmc„wó�Oþ3/åüſχ+†‚¯Ø�øØý//xÿöÀݬ±Æ8ôàgùÌÓÃWñ$¿úâ'ù:Ew}“_ü媩oˆ20Œ¡.4e&0&›½¥ [?ɃÛt”‘ ‹sÎ+]cm¼ðÀ·øîÓ;÷~jöL6Üþ1îûð6Šì£v9z÷cJ�òá¡o~›wµŒ™+¢¡»‹¸áCŸå¾;«p�ihÍ&]ìЃ|âK/�X÷q~vw�¯Þ÷sŽ *ôÜ;)Û¶‚´‹ì±À|Ö§x¸…šç¶±âÆ—°¹Š’ßAâO^üÖ}|ùÙ3¨”*îøÈŸqËÆbÒÐxàüùSøí×øtÈöÿÚ»óð,ª{�ãß™yß7yßì!� E…²¨­K«õj-j­ÖÚÛÛzµÞÖ^±·Ôª×­Þz룵j­½¨( *  " ,² ²ÈJHò.³œ¹$��…ì1Àïó=éB.ãΙ>™Þ çrpE>«nÍäøSt{;/>ð&;“¦rçMã”â¥|÷G¼ö·²aÇB~÷Û4úæ¢É“¸ð¼‘ŒÌíKJTó£™Èƹ<ýn!ÊÈæ†‡žäÎ\/J)\4²žÃØœ(fýüMöçÿ…¹—ŸËm9�t‘:Çèl_¼õ•(c7þî·ü0›ê\rÈ5†,s?�„åo­äöñ—‘¦·¯šP–ñ^ï«yú¥[É󻸮ƒmÚ4w »�jo°l-Vpƒ¦-bÓ’©K×H:·í¨`ÕÛ+(R:“§sޝ:fŒœ©LÏ~�g¿ZÍÂØ]26IDATÅLº,­É‹§às6�¼“»š>šƒrA9†‹†ÆpÓgçŽ7ymí·¹wlõó¬6÷ÅVÇ£Ä�Ä�BѱºÕt>€ØØXbccÐ4 ]×1M¯×KñŠålþÕ} iŒáâó†¢i†¡ŸÜ.u”â2�Äô|ZË[­%÷ M‡2§”âR7ݨSÖm0¥¦¡[Ô-W{æ\ÇB9'¶PމeµüVnÂ…ÿÎÿüÊÏì§±­t;ï½¶�÷^ÍKÆ€!Œ~cÆŽe\^&qFýÒ&–}À!¥á}׿h˜–uâ׎�/ï .ÏYÀŸ¶䃕»¸%'£‰cÐú_Ãc/L¡¬ÜK¯L ³nuŽÆ�1Cñ¿u˜Ðþ}ìWîñUÛZÎÕ\4@5Æ|ÿZ!‘Ÿ¾n§£â©pçôv3†7‰Ìa·S¸óIúŽy©ÅåUÑ þùI%ÊèÇŒi9nmË2¹dF./þé Ö/~Ÿ½3¯¡_½îzüôd&ß0ƒ 'Ìñ”!Ç‚3¹ü~?�@¿ß�ßï'&bí 70v‚Ëè‘&ßøýSÔ¢jrÀãÕ[7Lõzj2,̦r¨¾F®­‘9å.^œ÷ Oÿêf®š�K¯X¬J ¶­añ«ÏòÛ»nåÊîáÑ··S^7)CaûŽr:}òrˆkdŠ£ë¦287‡C;ws¬¹›ô¾XzöîGîÐ^įDáX&‘Hˆ ë#JL“ºi m-wœg£r½4;Kó,`…,^ERÆå„ÊÞ ¹÷T.Ç ha нK—°>ÞÁÓ¹$ëäßöœ4�ÑÑ`íÌgñ6«ñ*Í3˜Qõ“ó€ÜDLFGQ¶ÿå.�Ò;“Ä] ‰;!„è†Óùt]G×u ÃÀ0 ¼^/Êqè¹`ÃÇ'aDf¥�7>éx�úSîüüÕ³ùƒU¡V}á»ÁAТ Dk �·¹éCuÿÞÔ´£æÊŸº…(+LDKbÄ%ßgÔÌYšIá®/ظa#ëÖ~«·r¤h#󟸇 »ïç©;F‘ vÅ% ð�šš„Öè~5’“’Ñ)F••qTARýKí“Î�‹ªÚÏêÅ xû£ lÝS@ɱV½ù=z‡•«iet2)Ñ ??í´£ý‘Êïü#ǾEÖ¨ŸáÚ‡ÑÝ24ͤßÈŸ³ó½ñ$d^AÊ€Ÿ›ÓtEæVåïÂ&б3.&£~›âÏç²ñ±¬~¿€üwÖ3kÈü�T£%ô ÕÛø1%$& sUqŒ )NgôÅ:Ÿ5öw‰»v”«iå™wB!D;u«…%€šéyÆñ )]×IX·Žl³�ôaý)yå›—QiÉ\oõ2VyÉI”ûJFŒ¨®D�¥WÏtŽR¹ÿ ¥jT‹ß×)8@¡ÍÛ“ÞiÝîAÝ ®Â±"8€F|ï¡\Üw“®˜ÅÝÛyý¿ïçñeìYð ¯N}š[s À>¾B¡×c4¹¬³á­î®mc73XrË?çO÷>À«;ÕÊàQ8?3•x¿�ǃvø#þ¾xá*WKóx»_çí"ŽYÆá-ÿIeÑ;$÷ÉàI�à�î�ú_t/\s3)}g—6‚¢Ý¯²çãK‰M�FÏ¡ÿ…áKjP_pÝò)@±ý廹~nýt §ÒÄEQúA>«n:—) �ôŸ¯©uëðøjú”åÔô©Žï‹]Bâî¬�;!„¢®n—'žF麎·¼œ´¥Kvs6eïAO7˜tóГ¶/ÛZÎÆ_ÜÅ„÷–Ö|bð�¼!x}Œ¹c-kÊ/åÒ½ÈÄdóg_rÁÈÎ#7®‘e…;JÕ™ÂÔXNTíçõÿÔ²¬Žæ¹¸J¡” àËâÊ_þ‚›îa~ÑA>Ûp'§º…¿æ½5ápE ‘�"ª^žZ‹Ž&ª&Ÿ¬ñc1ÙøÊymg=c…Ò ƒˆÅ« ±¶VàíEùƒ%Ç·Õt ''RúÕ©A#aìÅœø„ƒŸñÆ?w1åßhøRÎzTÉ æ­(Ei>r'_D­º.MÓÐ×qp=¨cG9Ú ¤£™”îÞÊÆ­;9š1‰o�Ln:¡Íu°´$z§êPäŠÔ¼³GO§WOÛ*8ŒCR#ÀáÈ¡"Ñé=9åÃ8gŸ~VˆÂÃ9×Ìbb’Iè¤å�]JPUÿœµµœ wÊRv¯þ·¾Cbz?â{ž�†‰)B9áê•Ô¼™èFå‡WP¼ç o¹Sþ×—…«NtVU°Œ…낸z×=õ2w�ãkb¯ÛŸ½‰ï?¿› K–±ïÒk.0qìGÂ.xë_"8”£Ð𦤒¢´µ/vuc&ë6—C š×f±»g«,‹U–ÅʈÉû%Ñ Ÿ}ÿÉuÅ]È�ß�¯=Æ3kË«—ámê'r�…Oü•�+zúT~8#ýøï¼þ( ܲ2Êíúe¥ë?cWí"MSSŸ»->?6_üßf?þžúó¶GN½½{t›8 ùè�™ŽîZ2Ç÷Æ@qxÝzö58ÀÜÎÚ�U¸š—!ÇuªcQa‚U. ‘”@9õê²öñÎâMÕ ên”«?¸ë̾xªýv¤¶´Å›Åà)Ð;ïAŽñÕ§ÏPuôèq˜¡= ÅQ^´‘+gS¼ ½‡?Ìà)+Á›…먓úÔ—ùùl1]ŒìK˜1 BUEE?A2'Og¨ì�KY´Õlp~\{+Ÿo7l¯s�Í[+Pèd Ì&º�}±#âQâîkŽ;!„â4׆¤ŸÎ©Ö.m^û£Î?Ÿ’(JNÅ9˜Ä×çáÏÉá¦P�ëJK8píwI9òäº\�ÜÉ�ƒüÙͼÙÿÎì¹k(«zû´)ÿj9ÿûë»y|unT6×üÇmœ}b;O¯,2 PåkY¾©·Nyûð2žúÇf”Q{÷½ù‘‡fx4 fõ–�›\w|`í~�ÿü¯¹¬-4ÝÖ<ò)ýý³¬¬pÑS'ò­±´šö ¸ä2†EkØ_-à¹waŸT6®ù/³äˆB�Ç“kÊ51šÓSÉH×›í¶ª»­]ÈG~„yi$èà†�r´öÜ·µ\§Œæ¾îQ_ëÛ¢”C(XILÚtò¦­¡ÿø¿Q°õml³+RŠ.¤`óëd�{‰¼ikˆI›N(X‰ª?jŽldáÒý8š�¼™“Éjnßi¹lT4š:ÄÒ%ë Ö;?š[βWÞ`[¨î犲OÞ`ánÍÓ�‹'d¶»/¶5%îºSÜ !„§·6äDu�ÚÕù|>†a`_=ë~˜¾Î=|ˆ·›CåÈtˆÍ-ÿ2†Ä&S·\ôþ×ñàÝø·GÞçÀê¸kÝëd Ä ¾iÄEë¨p…û¿dË—G¨t@OÁø1ãüœ˜öÔs&÷Üö1w<µŽUOü‚;>ŸÊġĨ¥ìþ|K>ÝOÈèÉ”ŸßÁ¤8÷øK4==�‹§�äùÍk8´à!~šÉ¤oÄ`–ìáó•+Ù`�Ï�œÇ’ÿ�Bëyí¹ùØ£3nÂ�6—‹kpVNoíi¿e[X¶…/~þøÁ”úb %ß%:>_ü8ªª*›Üsù'ï°¬D¡ùGsùÅ©4ŸéËE3Æñ§O—Qº2Ÿ•7ŸËÔD ×uQ€Þw"“=óù·;·3ý›£ÉNÖ9öÕj-ùŒÃ®‡^3oåê>œX-³�}±­ñ(q'q'„Bt”n·Ä9T?‰òxù>þ6d"¯¾ò&‹Vmbßöul¯{òt=1é›ßâ†ë¦‘01ë&Ž8ÐçŠ9<—úO<»€�—½Æ¶÷kËúH2�Þ~׿ù±­:‰%M\¦Ï¼—ßþžßÏýŒ-ù¯°%4ÝOÏQWñ‡ÿ˜Å¸„0é×�à‹¿n`ÇâçxtÃÕ<9~ÃÛXnP“W¦§©h¿cÛd ù%û?ÿ ñi½©,)'käpìú7êPE,[ü)J'aü4.Œk¢ßÖ3ƒI)+˜_¼–E+Š˜ü­Ø傞0„Ys¾CÿGæ/{†ªš+͗ƨïÞÉ}·Ž" ì»ik_lk4×$T¢«Þ‡üÕŽ­ œw<_¯n?l�Ί'�ÇËî•ÓPö>tO²'äcÛM¿t¼�8¢<àZA‚!«eãbÍCTL ^œp!S¡ycˆñ{À  :x¢ý<Äžý%„MÓðù|””cÚ&玅×ëÁ´,¬£e ¶w]Û±‰D"ÍÔ\ý¢Ì°4â{\ÀU“3ÈŸ{�½ _`á´{™šÚLz˜²ˆTYh�T²û§ eWª,E*ËiÐ +HeãXe‰h~Ò{Õâ�€«,Ì�… è1ÉdƦP³^®²UšÍÕ€²Â„,Ðãz�Ÿ^SÖ$ÔÔÒ\v�Êc� v¤ [‹¦gV2pqU„`ðĤF'R‰£ø=6á*«}åìUÇBˆ“Ù¶EŸQdËÒ É�:¿™ (…,§¹­pí}ݵªNêçf¨ôx2³ÑpQª’PS/jK_„¶Å#wwB!DÇèV9Q²ð÷W^¦¤´€•+?l¶ŒRŠ+¯¸ªírq ºúF.Xò–~Ìc³ŸÆºý;\00*ƒè ÉÄ6qf\å4r7½�\ÕÄëÖTѾÖtØñ¸ Ç9EM�¾?¨åÎylº ƒ¿ù6š ÊéªgtMhîßµÑ"­ï‹mê¿wg}Ü !„íÕ†œ¨ÎûjýÍ}¿Áãõ¶ºœ  7y«»QnâÅÜûëmš=Ÿ�_.æ¡»WÿÂ;ŒŸ=?‡+Où¢!:HÆ“²m<±£O� %„B!Ú­[Mç «ºngÊ&vÔ�üõ¥‹Xüör>ûª˜ Ñ$öɰx™Ÿ/NOr%„BÑùZtu¦&ýºv?„K0‚oëÕÇè*ë‰áâl×±p¦Æ“­%± „âtÕª'Qºnà8º~æLus�ÉâB4F)Õ)}þLŒ'!šÓYñ$„Btºš•ùp�S¾¥�h€pWN¹¢‡ªˆöÇtx½OâlÔYñ$„Bt¥f/¢j§[hšF|R2e¥Å¨v®L%ÄéB)Eiq1ñIÉ'ÅB[I<‰³YGÇ“BñuiÑ“(MÓÐu�@L,þØ8vlÙHyY)Ž#IìâÌä86åe¥ìز‘@\�˜Ø{)¨Ä“8Ûtf< !„_‡çDÕüRRÓñy})`ÿÞ]_ÿûh„èºaGfVâ’:|À'ñ$Î&�OB!DWkÕê|†Q�LŸ˜Ll|"nÍ;nÜN|w”]­î4#]×ÑuÃ0Ð4­CWç“xgƒÎŽ'!„âëЪ'QP=ðÓu¥” öÄ­vÐW;Øëè'Q ñ$Î�OB!DWkÕçuï(Öý”ÁŸ8“ÔíÛ�™ü.ñ$Î]OB!DWjÕEœü%X;Ø“/Dq&êŠ~-ñ$ÎÒ¯…BœIZ}U—|) Ñq$ž„B!NòÚx!„B!„h¹ˆB!„BˆV�‹(!„B!„h…“r¢úþë3­¯Á•—ƒ !„B!N#šÑ®âò$J!„B!Z¡úIT{ž&µó*N!„B!ºT;gÓý?A¹¢gÃÉIEND®B`‚Solaar-1.1.20/docs/screenshots/Solaar-main-window-receiver-old.png000066400000000000000000001713431522022367600250560ustar00rootroot00000000000000‰PNG  IHDR¤‚÷ÕßsBIT|dˆ IDATxœì½wœG™ÿÿ®êî ›µZE+Ë9ÈÙrÂ6Øg0Ɇ“Á8àðÝq�ŒÍïฃÃÄã &ƒÁpdç‘£œ”µ «ÕÆ ª~LÏlÏlÏî*!KzÞ/üêžêª§ªºÅÌ~úyê)E =o¿Æ¦• ‚ ‚ ‚ ÂÎÐ÷��¨Æ27ù¡*DûN¹üO5&AAAá *z3!Lk'=o¿Æn;é²½1.AAAáaúƒß­‰R1Úüë÷î¨v�îG~X;ß—ç!‚ ‚ ‚p ÐýÈéûÆGT-dW™poŽg—H†;命8AAAaª¨ž·_cŽ~åÞÇ.åÚjçNI© ‚ ‚ ‹�®ÇVIj¤L°·Ç²KLð»µóÁ#ÿl/ŽDAAA˜*Aí»áºP²›ìÝ‹#AAA¦Je é>¼~Ö¿îãsAAA8PˆCv÷m— Ù^ú’½8AAAaªìw!»¹-ÏîÅ‘‚ ‚ ‚ SeBiqö‘·¶!Œí“øl›4P\k†Jë¸îz2)Ó¾îíAA„½Í¡§žS;�"ƒãèÚqg™¨}òZ€ ûJ³UÜΖ�ë)Ž áDÁŸG£�fvç–Ö&Y^fóºÕ{lSißlÌ;ÒwÚóH#ö�6«0‰xTnE„VÏë/Žo_«ëLl7i%ò±Ž7A [²[8è¸)ÛAAa< §*ÉÏi‚%I£Øl¼Ö(rÒl4ÚJÚkGU}3Ù<Òæà—J8^fÒy4›ÿdskv�ªØDôêŽÌ#­ÿ4ÒîßTÇœ¬Ó¬mZys½9ÙR�7V!óÌè‘çA@Ù1'f½ãr¬\A½§SUÚ�u'¨ª UµBv¥C_ŠÍµ£¢ëxµc2d·uÝÃM'+‚ ‚ Âä#ÈS/,…FòsUÄ5£™�m¼V=ŸHXMZ'(ÖôÍdóH;ÏärD‘Iµ?YÛ�©ß8Ÿ(LÒ�˜ÇdLV7M¬§�s²¶& êžG®!U¦¾3oÃc8ë~Cùðù˜Ž%€‹Èª˜T$Äd\ ®h 6Ѷ&¸bU�]×CCäþø?DÓÏ#˜·¬¦²U$„쾿VAA^ #È;>Ž—©�[áfóD�_'D£À§ê KÖOž'�eÕòäõÆkÍ>'ËýR‰( +( ëÐDóH³ÙèÌ›l�½Ù˜›Õq¼ & 0a€* ×i›‰æ1•ñîè<ŠQ†ŒIûd󈂊°Î(K™‰5Ú$ÒX�*�·á1Tß(žx88 !·±#sr"µz°‰KØ0íÏ<ŠìïÄ[Ì?¾v-²[î9x*AAaŠTåæxáæ§¯'Ï­‰PÚ©+·&",ëÊ'³7Yy£¾i6�f6í'ÇÝ8—4ÍîÉdu¢ÀG»NäïÐ<ÒìN6–É>OEŒ6Ú¯ÞÇË`ÄI=¤ÍöîT&Äj]èÇYóO> ´¦.6wGrÕD§Mo›¥ÖŽ¨Ú¡|Ü!ä5¨{6×ÔgÙmîö� ‚ ‚ �”l%|±5Æê&‰oÂÝä€1­uíXÅšñË'*Ÿ*& ð‚QBLMßLeS%m|;3f¥¢0Àq½Zûê=ªÜòXØî˜GÚx’ãp\¯6>˜ü97R}Áà—Šhk›êM˜Â¶/Ê„xÏÝMùð… š $ų©‡†1m­±€� »®±èÑaLgGu 1Ú ­(/[Hæñ»ñ�¸°6ÆÚP$dWAAvÆ4_38ѵäõÉêM•¤ÀMÚÔZcùoÒ4ÁÎŽ¡YŸ;Ò¶a @Eè5ŽO6¾®­Ù#óH1X÷±:®äøvnÞcšn !»éY�Tb=²Ó±4ÝB"÷a@î±gÐÅéDÓ6R>ò°ú –ÊšO[žÙ§ŸÅÙÒ‚i[CéøÃ!ã�ׯ ἦ«]^YéÞº!»Aû¬¦“AAarÊ�!«+�W³¾*ÇÅFaÓc’Éê*Ç�’íä5€(ÖœQT߯ƒ5–ÀTDCUßL6�´ò‰ú¬^›J;å¸D�ŸzÒÆcÂÏÓ–pæa£Cädš>“¨Á™;Ù¸&*Ÿì™WžGD¦aiLî!�B¬eÒEžaˆ·®—ìzŸò‘o hï!óÇ£GG1í­é¶G‹8ý”�-z´Ÿ–ÛI°P,>ÜÆmdbâP^ãÑA ëdêBv»ÿEó1 ‚ "4�ÓÚ™™lDÿÛ$€EaŸ¢lɿ⫤ñ–K8 »7«ÛxL«…!ÕÕ¤ÉóFšÙ‚z}“œGU4EaˆÛ ªš�7ëw²v�s™êø½¨LÙ'œGZû �÷±™¦Jé·±¼Ú¾zL�[Êõê1cC¶¥Ì£‘ “©jR£‰ŠÆ—Z~ÓuÅSND‡%” ‰ŸAvåÏ(žxH]&ÜJX.äV®%\ø rmø'¼wý ¼ûî¤pFã~¢¶N+V»`M}ÈîñÉ‚ û;n6ϼîVzZ=òZ>#Öo/0ü§üzT­¼îͯæÚÃ4˜~®¹úF®Þ°{µA„=OÙ*²ÊR î–Ä%·*I£dZ=U'bª4~n´7™í1Niã�m32n [a¹ÔÄÎîýÁÜQ{eë�Ñß/4ŸÇ$8®[7—¬›Ø{ÔÉÔÍ=)*«Gƒëjˆ�å&s¨ÚO{žå¨"ubiL¼íK¼Ïg= ™rc‚YÓpÊ–ÆöÍw púˆzºëêëí(ÿ LÇŒº~”13»iÈp4~lÖ¢Ã2Ó»©Vn¼to¬ ÂþJ¶k¯=ûH^ì|NžÓB.%˜Å†eV¯YÏÿ=ð$_¿{«§–8oçQaâW¢LˆÚ�=ÒA„aáNi7�ñ˜0@ljqr*" +bÅ/Žàx¹Z½êv-ÕºÍlLDÅFHYeÐÇé›´y¤ÙN «©ô]²™¨„v½)�uG˜ÊÜÚM*̦ Áüyx÷ÜC4çH´)V¼—@´ô ²+þ…³ºÆ’"KnÅZ£ÞZ·Ÿ¨2!ªÿn‚eÇV [ÛàY­M¹ò¿8õr2d·û‘O6%A„ý�#Î8‹¯¿î0ËM\S¹Y/]Êû–.å­g¯ä#×ÝÊ÷7íZ6CAaÿ¥hèÊ#QPB©f�§éT…™iHÜ%/GX.¢�ñR¤Z¿*ðÒlLÔ_Öú„É=H�"2™&vÒúK»žF« 32V¹”"Ããmh×# *N4ÇË6µW?ßë—ê÷R­{>Z×k¤jY5‘�Öª&[´av^Ñê*ϼY38}Ù¡\¾ü æyÐ:ç0>ÿþˆíŸ¹•_�ìíy‚ /V¢0 2S£& k"Ó„Aýçj2­*W«ZV\›ÈÆZmSÁÖF©Ç*ÕÏ5¡Ž ¬Æ¹Ôr¬ZƒŠecý%„YbgkÇG÷(¥éÈ:ÌÌÁâöÊX6-›‹–Q*®ÚGeÕŠ½´>ªö£ ŒRkÍØ}‰Ä|ü<² ³vï’÷ÑX4Ó30+Ÿai‡Ãô¬¥)lÌdÈ"zC# mNÀ¢Î ]˜›ƒ–¬ƒVŠm%ƒŠѨÏ@|«bÔqÝ:�<¶ž4˜ò–8 Òz¦«“} g`#¦cf­}4ó`2�?…×û `QQÿè#ëúЃ›‰ò1ÓŽ¤1D7öU[KWQÖ0=‘eWBvA8 ÈÎãC¯^‹ÑwüôfÞò›- 7´ �²ns÷¬xŠën[ÆW?pt*¼žÃùÄE+¹í†^Ư A„1ª¢-(ñboXU`&½œÕmB´ãÖ®›†PͤøLë'y¬ägm~¬ÙŒ?G�n[Mµ_‰~eÝŠ—Í¡´ÆñG ½|­^¯¯ô²¹xÌc¢TiM« ³\Ÿ9ù,3³•rÇ¢È2êWÚ;®‹Å¤¶·Æ`1µóÕ`Ò”õš& Ç®‹Ö ¿T Ëu39¬‰P:!ÔMDŽȒ׆éY—iY�o,ä<æšRUI8-CMŒ¶åa¨ñ=�Áb@)‚œSž~ÉЕ©Œ©3£+b4ë2R èÌ{˜0¤D#p‚C¡&§¢ Ÿ€•›z¬“L,H«ÍN°åKÞ¡6—#˜àô­&š±¤"”ÐC[@iLk76“¯\s28[_ œ^À¶Ôd Ó†?º$dW„�öétÇ_Ë£ë·òÂóõ­x�ýh#¹-ý<¹aÏ5£š‹–ð¦SsÖ’–LËÑî‚_,±aK>½ŠÝû� íb¢"�gÙ±‡réqó8y^óÚ³äK©Xdý¦­Üóøs\ïš Æ¹m©g_°œ×ÌÒØp ßøÁ<–éæÒ‹OáŠcg±0òÇßü—ý¾Y}+‚Мf"5íZcùDuë$�ŽëáF%|@‡SËÜ7Q&ߪXl,/YMädɺšöX—BKÎU´8¶V'§Æ~k^ÄÄ0i™w“eAh¦<�Ðûak¼%?¢?È09¸�¥ÿ€yñÉ9]­uëhsND�£Å€ÁÈ¡–)—*â2§¢q}%?W�%£QQ4é<&÷�Öb¨'Ù‡4!­RVnŒ.á¼pQ¶ŸpÆ4Pàö G; ��m造žžÀf“~ã˜k Ùá@#ŒLík9ßÑB»‚ò$ÒJÃíüâÛ'®“�Î_¼éþ}y7í�_¿­yf÷LãÄ#á�÷sà ¿åïîÜFzpÔÄdf̧ßu6—ÏË¢Sú™ÓÓÍÉGÆ»/\ç¾ò[¾¸Êošbo÷ØrXräáüÅá9îºi G^þJþ븖8Jʲ´+ƒ¤‚ ìÿD>¨1¯€v]LNéÔ•5k_eªv›£0¨  qøÅZÍ#íZµ  F("ß Â,¥°¯«¢€±:�BTa°u6&²ÝØ@F5&�Í#y¿&›W¹TbP¶æY2äñ<�á ò+ØI/_{`¢š`m÷�±Œø½Ã%GË·v*Ïß#brÿèT’MQ™×ê—Ëd¶h‚Ö Gúq^ø…–bÛçW’i^„*hyàD½ŒhæR¼§ŸÆ_T¶¶Tì4˰[KrdQQˆu\ Ùá€ctS?kì"U�9ìX>|Äj>öd‘]ÞXÅéäò+^Ág�nÁQ�öqÓOñëç·Ó[†¶®iœ²ìÞzBÓrݼî²WÐanäò»‡vH¤©ÜAüËûÏç­³5 Ù¼†Ü·†‡62Ó{fpÞ©GpÉÜ,Ùi ùç÷¾”ÞOþ†¦l¶Ûl…”ª¿þʥ瘓xϲ”)³vÃÅèh4QÞyA„ý ¿><·*|¦zlvžVogì'�ÚuÉ£”/šŸ'³ÛNe¼I‘—Sm.è\ÅÃ9=]-92Že4TxŽGÎútd³ô´Œ…›(b$Ö3…ÀÖÙ®&.JzÖú,ÁóðK\/3¥ûWD3(Ö – #â®&4h7C#a,è,…а~ÄÐ;0(LÔÖªZù•ófÏ£\öÇÏ#…‰“¥í„´<°¥ó ‚±òª^…ÑAg‚Ò8«î pÜâšÈ¬£­•âò¥äï¹{èŘY'Ðr×íà9ŒßwTa)R<ûXȸu×UJÈ® ẕ|oÍ2>¾ØE¹Ý¼ã½—²ø÷óÙ[Ÿç�íáNŠ&ÅüÓ_¿Æb4غ’wînêOÊÜõüúþ'øöò øù[—2W·ð²×œÎ«ÿ7 M½Ÿ…§ŸÌ[gUdyíC¼æ?î㡺PÚgùέOñž÷¿†OžEw,æCçôpÓM[ÞïF[ÖŽ%eP-\röL¦m|œ¿¼în~¾U~gA8°PÉí=R’ò4~N£ÀÇñ2um«™fÛVë6ëN8V­‰|Ÿ’ÊFI™•‰×úUçe/[;Oz%ÇÙU•LºÓ3³Z=Z3•9tµä˜ž©Œ-0¾ÎÐî9LW†c§)F;²DF}ÃæÑ€­ÅˆB@M„&I–U³?�äóp‡0ðq½L-“­ÒceÉ#À(°10”Bƒõ‹ÌŸÞA›«Á�Rä20\ ã:åЇ”6•«Êô|ŠF>ŽãÔeÏm–I·*Ï‚†y¤±ÃI�”1hw6á!çU¡5*å‹.1™lë‚ñ6*-±m-˜®ª4‚mŸAtøkëêY­Ñ¡�q3¸Ïߊ #lflÈÕíb$dW„³�ë¾}gþõ™œÛ¡P^;ç]xç¾ì,6­ïåö§7rÏó½Ü÷üžž¢WO÷ðÖsçÑ¡[à'?¾“Ÿõ§ý1`X}ÿ]\sò|>wtݺ�w,ïä'¿œš—Te8jn ƒÅ7·ßº‚‡ÓÖuÛùÖožçÊÃŽd–Ò,9| ~Þ°^vwÚÂRû9s¦sêüMüë'ïäç[wÙï,‚°Ï’ ÙƯYˆê�:–Qà§×K)«Öm<¦QÍà›Ìä[í3o}J6š°¶5L†xaÕn¹îX™_óŽí-.Ó30¯Ý¥'§È¹Aš¥ xø~@)4@‘M&£ioÉ‘óã5”®Å‹·Á,øeKõ}�黿5Ì#I{1Ãä}jUN^ Ÿáø¼;“a¸è3­­’\v Ñ8äKEZs¼\ eŠ! *bt°è£«[×DŽãÔÆ�<¯õçæpƒÂó¨2¡ ­-@µÕ?eâc¼v³â™t牶Ã[ð»»&2_™TOÞ¶ÍDÙ%uåÊ„(ÆÍ ƒbJK‹2e| Ùဤ¼ñ1ÞríyÓ™¼çˆvr ”ò˜3o˜¿€7\PyóÚ¿e ÷>³�[{�›Ÿì£™³Ï�»˜ gÅû² ®âûO”› Y;Â/ØÀ'�ZL«r8öèùÌüÝ ½SQ¾¶Ì/¾ó]~ñ�J…¬ šöSÞØÇ3ÌrAwµ3WÁ {ÊV#O<Îw6‹á&ôÉÚp‡–ƒ˜(Ä�J„Nn·Ç�J„äjý$ûƒŠTa¼ñš‘1xÚ˜Š{ÌÓƒSWîhM¿�Ì[ŸƒZ[™×V Ã5&Â7T¶Kó+¢vÔc9R +Ÿs®CÎu˜Û�ñØ44¦g4•}?+h+ý;Z�…ìšÊoYÝ<¢"hÀÄcÔZcŒ© ƪm¼^³Ñà¯T&¢UÕðÝ L�’-!i/‚ÔòÚ¹_€x<*(MúR|êÒZN£Øí]ÍžÛ,\Ö„àÔïZ3dU\¯5*ŠßTTÕ³�@9Q¬”‰Æ I–]AÊ[Wñ‰/¬å+‹—ð¦SáËâ˜.'^Q¡”ÃôYs¸dÖ.yÉI|jx+7ßú WÿnÏ7dèX0ƒ¥q;u/�L¼mƒk6ó¬YÌqxs{8Â�Þü:6a@Ú+ÇÚõrÀhußiGãM�[owÚÃãÏô’²dUáÀ yÅ $«© ÍiCè䯕•ŒÆõ2 GžÙ±<4‘“ÁI¬7L†�º^†’Ñ`*}ý€|ÆgǺٱ”¨ áj£€¯&>ý DÅ?˜U‘e”ãÅ{gÆIƒL„Ö~U™‡™LÅC šH»øå뀪´)…q„/^¼g$xC”ãáèʸˆø³ÆN�ÃÇø%LdÁqqL€Á©‰A/’&Îè[½Þ™Ñtç:\C‹Žâ$L^&C.ÞÏ4ãæ)†Ñ¢#:\C·gñˆ¢ÑÛ&ªõíÄý˜†ˆYcLå^6�É Ò”8çJ¹i~­Z¥­·w�`qµ€D²Ü±Ζ~LÛqé}Öõ‘œ¤­«#!»‚ ØDl^õ,Ÿ_õ,ŸÿžCÏì™,?x§<‡SžÍ1Ó³5ñ•iŸÁk^ñg\tÒS|ð‹·ñÓ¾êw«fÞôöXÈZ6õ M(î¢íÃl0pœ:߯Ay¨ÅMå2wþAœ¹´‡Ãf´3«-C«§q�«5®×ʲ©¾:Ý�¶lÀº¾Â®'‰AØW‰‚š§°* «Çª0„Š(t¢€R¼÷d¥N½ ¬ÂS¶îàÅë;kŸb4° a§E?¨ý–UÇá©úÐTã—PŒ÷�FÆ”K¨0DU§æ˜ð¬ObT-+—J¬Û.9¦µdéÌhÊF‘�•fÞÍ‚o ôélÏWÊó,”ÙîÖn/Q.Õ¯'Éx.~P¢UªÂ*žÅ:Ïc¬,¤2Ò1Ñ]´ëÕÊF­¢3c˜“w˜Óá1·Í£Õ…í#£híÐÙ’£³-O€& FÂØkšq˜ÛV±™U†5ÃÅÀNØwÏQSʰ SɲÛ�ØÈj Á&œ•7ÇN=æéT ÂsÐòŠ -¶  l[+iÛÆ¨Ñ"îö QW5¼½áLba±²«T%ã®=31 6BE¡„ì ‚ ÔˆèÛÔË/6õò‹;-Óz8ã¨Å¼öÌ#yÕÂ2 ZæÁ_1ÌóŸ}�Çâ¯ùö–Lm�ÿH1˜\ŒE#T^²fèÈ)žªKÑaá²ùÔk–qÁ¬LÍ£»sìN[U†§´�Ž ÂþO2C­v½JØh|ô\¯ö{Q-÷”%§ ÚqÈk‹ç¤mïØœ Š*Q/VSð#´ëU<§ }'Ç9*BNû%L-Ô5·fM|&Î�lž¨\¿=̨vé®Èª‚±=SñNËh:[*‰‘pǼ´[‡‹ŒÆ¢²àGl è.Ó¹6‰|´ëR*Ö Îdr% ëfT³×&Ÿ…onä×Ý€Öl†ÙmYf¶951êfrèx‹Îr©@èzTCtmXÝÍ¡5ã0»%"2…2¡Q‘�ïQ,G� n4~!J3Y¶y¼¯Äº�z±¹µPcõ>¦%RJ+«Ö€ ʘ0À5F{u÷í٩yÐæXZUÀAmYZ]ö#ðGiÏ8 †K…Råžµ¸TÊ�Ḭ=ãpPô�¸”GB¶•ëïwUŒŽMkbÃåˆu¥Z£Z¢¤†­e&šG�&ÂÀ7 Lˆëº„aå¨M,µGÛw�lΣ=£iqùL†È”(„–È ~ÄêþÛýÊýž–±,ên©‰Òd›öŒ&Ûð«}‡aHk<öj™U<­v ŽÃ‰=¤&¬„èB½´ ïejÞ$‹u+o ”—Ã,9' ÈlÛŠÕ›?ÓÝŽŠ"Tè£+£³gmJ‰îâsúX­%dW„EÆUøá¸òl™žÛF°¼…,ŠŽŽ<ÀDzy`”ˆN4³q IDAT¦µâÐleHÝÞZ‚€ l�ZˆkÏчpN>Þ(üéûùÀ¯zékÒT·déœ@ïN[‚ Bñ:ƨΫX ÉŒÂ�UÛp2YžÏ*f·y,íªÏèZ ÷×Md ¬­ ×W3§Í…(dÓ�a¸a Õóqb.,�@:A-!YVDbƒ­(Qƒ—²ñsVÙŠ÷/²±è«Ÿ_UV…k5QR£�´y$�¡Qäæ¡â„Hnä×~›«ýUŽñ\¢]« ‰×Õ�ÓärP*1PðÙ8°jÀgp´" Zó8Z3«Å¡«%C[.GNGŒÄí˦¾ßñc¨/›êûß ºU¦î1:ÆøTª\"»ÁÇv̮مr2˜ia;ç@¦•دÆtÎ!³Ñ F ™®ë·úkL¼EL(¡»‚ ´/=–ÿzß«¹ë3Wðìû�`Ή,E>ãÖ¾Cýr'%°lÙÐ_ó,¶ÎëáàI–üdæNç�ø×&ÜÔÇÊ)mBªY8»3NLaX¹r#›&ø¾ï>ø Žš \w÷ÙA’TP9Ç…ÅÖÖ–‹ãÊku£°N€6£U<¥Òë„åq¶“ã)Fâîâ¥|a}*k-%²q¦À¨¦!Àµl¸)óª;úE AÄHœ)ã(FüˆBaüb-9“ ƒš-׌�«Ñ~#YS7�ÊàKŒÝÔFã8(•Jl-Ó7R¦¯0’£Kô  *uû†‹¬Ý^`ãHÀ@Ág¤T¢¯Ð7Rfûhë—*^ñ”g‘ú|Ârú<˜<ß 5ãÅ¡jþ×OöÉç±=ËÆÚX‹óÂ'¨¬3 \¢¥gV"Ué9šÜ�R\~tEàï@. Ùá@¢èg9þè9®Á¶Ë_ú,[éOíkS·sá±=•÷¥ÖðÔÚ~ª?ëþêµÜ1zohW¸³óg³â‰�Í^Jzœvì|¦ÅbpÕÓX=EGmò$ˆLóq{3xçù h¯½�¿rdwÚAÆ“5•å{5a•Í׉¡ªg4I¡Tfý`¼Þ²3G‹«Ç…åND¡Ð;°~°H!L_3:&"�D™¡ÙjÕ²Ux‘�‰B´ã¦ ªªtª»ÞP 6—hñf¶y” l Ø<\¢G-Õ’.9nå~e+ùtÂr7›Ç5eJA¥nõžºq� ž‡ŽÊ© ï?Ä …¢ízh×#,Éyš-¥,Ä3Û08Öî¹mEÊ‘¥Åb2 )dól)3Tôîn#·}ÌY¸i¸L¡„oô¸¾›=‡Ê<ø ƒ˜BÈ®K%Œ–DجM¥zp�ìöˆé®¶¯þi¡a»Õ½M-*~û !»‚ H„ëŸäKOÓEë.ÞþŽ‹ØòµßñŸÏ˜ÐIé´rî«.àªC*ëCmi=ß}hhìÇ®¼Žÿwÿ—ž×‰ãLçŠWÊ®{šu)¿†™9Gów§´U~l‚-\ÏÖ Ã{ǰl쯆+]2“.5H£’Ôm\ü†óùÀ ŸmAžT.GW]ñî´%‚ ԇ떭ÂIìºQC&.3QX;‡Š+ŽÓ«Œ éÈMîS^{e‡J!›†Ël+øG‡Ám©ë# í¸dâõ�iB.«,abÌÚq'µY¥±~Ñ7ôëx~ ¼~¨Lïp™¢`R²â%EdX.ÖýüT¯U�M”BŸ¬I„ì&…i<¶dYEðé7šrdÉÆ/ú ¥š& Àñjm·•!çiú %º[*ù}Ê‘e{±2/íèÔû–¼?Úqã{cȆetPÀ°“Yv¡IÛ4©1äW<‹™wv];e"ÌÈ3ø§œP«,Z@fÕÃh3¿®3ïXòýžÑóNŠÅçÔÞ¤H¨® v„|ïÎ;è\^Õ­q:æqÕß\Æž|–]ÏýëX7T¦ZÜL–Ý]³t>/_~/�™A+°¦Àoo¼“ïoOª·ˆû~}?>áB^7M1cÙYÜðö,ýé“ÜÞoãä8jÙ2þùõ'°< Ø�'~7ߨ<Õ°˦§ÖðX8—]Eç±§ñ_çŽð··õ²9t†Å‡Ì»_q o[êpçþÀg\ÈGæk”;›—™ã'�”âו»Ó– ‚�†ù;´'³‰BÊ*ÃöbÀ¶Áaú:Û#ƒÛdû—äµ0s¾Õ Ê 20áh¢� ŠÈš%BŒƒÒX‚ „øšªMÚ¯R ý…rÅ“[ݦPŠÌ˜ÐÛE´_?�‰HÌ­‘R`°þ £™¶ê­Tñú×”6Õ9l¨„L»YL\¿Ù}K–W¼2aevâ{2± 5!è”*)Ò̆�¸Î<Œ›kgBÔ†Ç),[:ñP+JÇ-¡õ¡G±‹N«¯,Ú]Œ·z=Áâyq_¤èÒÄŸ&”�]A8¢þgxßç"6ÿåY¼cqWe8ø¨£øû£Žš´­)ôqýËÇî h¸f‡^àÃ_¾‡ï;•s:]>é n8ñ4F†Gé++::[éÎÄÛÃØ€•wßÂå?ßD!¥Ÿ¦cßü$Ÿ¼ãp¾Î42º�‹^÷j.xU™­£¹¶<�žBÙ�§nÿ5ï»m §ó¡ù�8ª…K¯x3§nå¹{~ÇÓG¸;míÀAR„@Öú”U¦R©¢¦"ãPØ>þÂIHܨ‰?ÐÁTì&û®ž7§ÀØÚÖ„(5Z;éóhÖW|,•Ê”€�8!�QõóÐÚ©Ø·¦În­ÏDueÄQª® )‰ƒÃr1}Þ�÷¨�²Ê@© NüܪݥÝßø¼ìdÀKÔovßSú4~1ÙMŸGݽšø2u™š&Â[¿9¡A­�. ´ ͘ÞP[õL#˜V@�l«ÕWÆ Pxk6WÊjº3åýµ²µ±õ�ryí?A„…òÖç¹êÚïrÎu÷ðõ[X_j¾†Òš€Më×òí›~Ëÿ|}ïvš¥TYó(oüÔM|ôöõ¬*PšöŽvÏhczF� é]õ,ŸùÊ \ð�çX3¥dFÉÁ”¹íG?ç-¿\Íó%‹œL–ÙÓZèra´o=_ûÎO¸äûkØb þêVþ¿§G([PN–y³;èÉì[‚ B=Q@`¢ºÏe“ðÅ%Š¢Úõê¹ã8uâ³f]ûÀqR2Î9^ÅNʘ"t�j¬gÄarFiŒo·®< j³Zžœ&i+Eˆjkjb´ÑnRWÛVë'm7#R*!¨ÃÊX«z­&pñ>ªç b²ÖV©úëÕ6I�Y­Ÿè£Ö¦±Ïq¯Âpüóh@õ¼ýÛÌ«´v£Œ!Út£§ž8æ©TT<¤ÖPÛ = É®^Gîùí0çxl¾µö~FN[€éh£–©¨Š«-j¸@Ç�«0óOA•F ÷QЇv¼'Ÿ"×ÖÊ쌡¨ÈP˜’å}7ÚA8ÐYrZE\”†pöĬó¨U?7zÚë%êDQ4ÎKê8 Oe²ŸªÈE�µiì'.sF·‘í_�S"ìšW7§8X{:!5J�y0Ó<¡$DcŠ'5ÍÚ”IOhµ¯ZŸ‰q×Ù™dãžGʘ›>ŸÄ¹Q ­]Œ ÑÚM~P¬€®îåš­:I[ýœ,wF·‘Ûò:(ÔæÑˆF'KjdâŠSXËéz”^B°Ð'·b™^(Íó0mméõ­Å¶æ)Îsɯºº¥táQØl6�µŠÔÄlrÒ¢‚P&��]AÒ·µ�¾­»ÑfTfͺ^Ö¬Û�6ؠȳ«Öóìä5)�Œ°úOdKဧAìÕ}n:�‚(ÅFE„VÊœ›R%íÖ…ð¦ ×)Ì%)úˆ‚1aj"tM¨itB@ÖÄcb|U©­_ž›Ñ˜€Öñgݸž2 j}O%üر¶^8&<”ºz/ª‚³6®p,,¶á9êDYÕ šôgÖ„hÒ–µuíÛÔÕÏä&�ÓÄ‚4ª¼WÖ¦=<ŒéhŸ ve°Æó(ž|å�AL{ë¸ëuçJáy(á‚!LgWƒMÔkÈð«†qül,YvAAa÷ãX;^VIz/ãPÚ´] Þ»‡øÖuÓÄlB|Öì&nµ,Úë@¼CHÓÍıJRXVcÒsÚèÕl¢ÕñꔺÉûLx½æÁMËá“â)Â?)8�RuMÝäùÕêUzÕSšFMÄÛzûiãˆÇàPYëø#˜ÖæYv'_C ØY“üé±}E+¥¶1]õ‰ŒêHx\µÂtt¥õÚİ%÷È3ØžƒQ±»Z™°öŸ ‚ ‚ »�fâ¤�f"tÊ6SÊ’ëBÓì×Êbïiê:ÔûubsÆ:¥úS¬;Ñõêµ±­7wޤX4Mô‘¶v¬^ƒ‡4�äµ41jÒva¡ò‚ Ê4‰˜�™ÄCZéØzy2j.ÑOQ:òhLÙœð`ªZAŠ ¬ÕK›Õ�ܯh­JDî�Ïàù³¡¥ºPÖ—�]AAAØ�DAeË—)ŠRØ1a:Yݹ0¡7«,¾ŸÏ7kJ”õä!¥{�DæÝê<Âx�.w¦îdv¯W?+îú>¤P¦¶{ùm羇)}¦³s*MÇ3Ù6.M>ë�!r�>C¦8;½~Q¬„ì ‚ ‚ Âî%0NZ8mÚ/`2-¢Q5§êU4^ýXÊV�—@Yç^ü¢4AÙ/Méy¼0J‘³V»ãžG#“ Òº�L»ç‘ zÈ<𑳒(§â ßjÒ!•Ȉ{I•ª×—*Q'é­¹Xë*ƒµ8‹´`f ùlݘ¬Òª+‚ ‚ »gŠÞµ©ˆÑ‰DëŽ ÚÉê×yä‚"޵Mý­S£i}¦•MEà6ÖI~ÖÚÁK ?šmÖ¶ûïßTëMøLÒɘ8d×T¼¸Öj§rîxعGâš'v#+�]OÔM+k<ŸèZíGAѸE¶§Œ_/Jïm³{?Ù¸›‰èÉxõ¼Yû@9d´‹bbQ:aR£¤hL;W&ª;O»>™­©Ö›¨ÿ¾S.¯ý'‚ ‚ ®áéz/�ö uâ§JšHIûœ5¥Z»´öÍl&Ë“Â'Y�‰ªê¨~êÆDB�ý™LKS»içYSª·ß0ŽêõÚ¦ í’íÛØj’!';6æh¼¨K›ÇTî¡ö “ÞÓ´q¥=§dûÆ><[¯ùš±óé›^DHÈ® ‚ ‚ ì>²½Oí»{Äj¯…0á!Ío™|wê�!¿“×ó“\¯áµÔyz÷Ô<ö8 óHc¿¤²+‚ ‚ ‚°ï±_Rɲ+‚ ‚ ‚°ï±_R ÙAAAØ÷Ø/©„ì ‚ ‚ ‚ ì{ì‚TBvAAAö=ö A*!»‚ ‚ ‚ ûû… •�]AAA„}�ýB�JÈ® ‚ ‚ ¾Ç~!H%dWAAaßÃÐa €µ_x÷^Ìîá­{{‚ ‚ ‚ B|ðK PzoFAAA80A*‚ ‚ ‚ ìD� ‚ ‚ ‚ {¤‚ ‚ ‚ Â^A© ‚ ‚ ‚°WA*‚ ‚ ‚ ìD� ‚ ‚ ‚ {wG*?µâá=5Aa/pIJööAAØ(•Jüì¿äÔS–³`þASn·C‚à=¿_²£MA„!_>ï…½=AAöî¸û¾øåëX¼x?ºñ'üèúoO¹­„ì ‚ ‚ ‚ ;ÅS+ŸáK×}•ÿ¸æjÞþÖ·ÑÞѾCíwØC*‚ ‚ ‚ Ûúûù×O~šþ‡«Ø¸q=÷>ð~ÉËwȆxHAAA`üÀÇ¢(šzßçcÿô/¼÷]WP*ް}`˜?®XÁE/;‡ú© ‚°ïã�°m¨HdåÑÚÕEkê/œÁ/ 3RVd[ÛhÍìÂ{Ù)÷)ìäù‚ LÏõbtt”­}[˜9s&³gÍF)•ÚæšÏ}žÓO;•™3ºákßü_úüÿG&“Ù¡¾å«YAØ%Ê}kXµ­„P-Ì^<Ÿi^“Êák_ØÌh¥2¹é XÜ“Ûå1O|�·ýíMl5€³˜w|õ+¼s©“%«÷Uþã›¿æ¡ £D”Îqö?ü�«ÏoÛC}¾¸°#yfÃ0¦i …v<²­Ó˜5³‹ü‹w*Sb_{>‚ {¥���´··“oiaÕêç¹ýÎÛdþ¼y,˜7Ÿ ÑÞ^Yúý~L©T朗œNß¶~¾ð¥/ó/ÿø1¦OŸ¾Ã}‹ Av�ˆu7ÿ;ïøæóDÞÑüõ·?Ïç¤{íÀí\ûþÏó€à°ðÍÿÅwßu8{Z&”ÿ&ÿ韰:´cc1†  ¤¿ûÝ¿úïúç[)ÛÉj*t~:‡œôR^ó¦7ñŠ£ºd}� ‚֚i]]L;îDN8îDJ¥k×­eÝúuÜûÀ}œp܉léëç׿ýÿöOW±eëV¾uý÷xë[.ãˆÃÛ©>E�¦ájfäËöQC˜REiE[Vù†ÂÔC­w¸áOˆ<AØgqæŸÇûÿf1E èNŸ‘”P!ÏÜ~'kc1ª2Kùó€W-tñzò;-F'îs_ÆbŠ}¬¼ãG\}Ï­Üqå5|êU Ù±¬½Ïþû|Aö ÆÊå¥r™Âh�R¹ÄÈȃCŒŒŽE†~„'W>ËÕŸüÅÂ(wÜu/G~žwÞN÷ûâ¤Z³`¦K«² l èõ'©ï9,éqÈZÃæ­!ý;+c2wqãkóxý#\qÝ �'ã›<�W]ÔÅ{ŽÌÐíåþÜvn߉>'ìçEƒbÎ,—.ÝìO6‹‰,#…ˆM#–]¼õ{•}ãy‚�†î9š‹^yt“«†ÁíCTƒÎ’—òÆó�eá.꓉û|‘£²,Z~ÇÍL~·[Lq�õÏü‘k‡-Øp+w}ñ¾Üqù®Þ°?1ûôóAø±yó&ò ¶lÝÂÀÀv2™ ¹lŽ\>G6›£µ¥•ÎÎNæ4�Å‹–rõg?Çë_óJn¸áÌ›¿�uë×qí§>¹KcØ­‚ôµ™oM©ÞC=Ìêcþ³éuÕšç£oëâdñ“ïmæÓ«&Ž/rzZùôÛÚYŒÏ¾¼•ïlß¡a§Ðv|¿KN™ÆG–y¸ÆðìseV¶Oþ´ãý¼hp²\ñæé¼"?yÕòHÀ}OŒð�» Kgí §Wå8æµäïOIYìkGyâ[Ï•ÿû£lù~õûxóÛZmËÛxîñ'X¹®�‚ÍÒ1c!GwóÛ& ÂYõÄc<½v+C¾CK÷l>j‡ÏÊM8�é/ýßD‰­«ÖÒçÇϲeKçw¥ü1TfÛš5l)5¯·#cIý÷PÞÄ#wÞÏÊ—CϺˆfî[‚_„ýƒ[n¿•��íœtâÉ,;úX2™ô$…B‰w¾ÿý\ö†K¹õÖß³xñ®ÿÞùìÕŸBë]ûþÚm‚ôµ™oñ®+ÞÝôúW¾vïºâÝ<øÈý¬žÌë¹ñŸîçœO§]Ñ»ÀÅzîç¿.SÞ#ý¼8éÛXbÅÐx±æ¸š™=‡tyœµ|§žã“ßéç—{a�»À¾ö<a#|ô›¼ïŸ~ϨÕr>Ÿ¹éJºüIþñ÷³É¯~÷(œÎ#¹ìÿ•÷žÒ][Û>ý}þf\ËÊï_ÅnÜR—È'|þ>òž€ Çž1›ÇïZK¨ÜÉ|ì»WóÊéõ’ÈÞÎgÞ}5w-àpðÛ®ã[ÙÙ¤Og—ç`¶?Ì×ÿíjþß#}µ¯]E~þ9üÍ¿½ó¥rõ> ™}ép×í¾tÕÊQ¯ §üàIn)XÀ°qm/! Aj†XqãsíÿÞÂsÃÉ_•›Ëé—ý W½åD¦7þ�b‹<÷ëë¸æ+¿â±m~};ÝÊ¢—¼‰ýÕ9©±áNô—þ|"ÿÎGø‡ß aÝór>÷Ý¿ey¶a˜C·sÍ{®æ¶Bå™/¼ì \ÿî®�Ë£ßà½ÿô Õ?| Ï}äïøê“,^Ú}.'œ»ëɽAv”W½ü•<µòiž^ù4�=¾‚3O ‡|ȸzŸþ최ý’3¹ïÞ»èééá¡Gã�¯»”óæíòv{Èî†ÍëèÝØ[WöðC�ð®+ÞÍæ-[˜3w<ôÈîîöOƒÒ´e,ëûB^Äšz`yú¡í|l…!ݨ˜½¤��¿²�“:óüÝE­<ôƒQ6‹³Q„)¢òyrŠŠW.fÕ/?Ëg¾rÛêÂç-Ñà\ÿÉÿdé7þ™‹Æ)ž£í˜ó8ê�ÿe…o±åÇøý=ý¼âåÓ^:Ëȃwòpì)SÞa\tþ"˜ [í.Î%ZËÿåã|ãÑBíûV¹9:Z`tý­\ûñ2§8c†”E-C<ÿÔj¶•6r×7ÿ‰+Gþ�/¿ïÚk Ë<ûƒ«xÿudÈ(”›£-k-”1f”U·}�­ÚÂÕÿýWœÖ©v±¿4ZY~Þitýá×ô0ý÷sû>ËOH®�µ ß'ã»ï,ä‚ó­üÁ´“cQ¹r l8Âs7}…o?Uhò{*‚ð§#Ÿo¡­µ�|� yðÁ‡ÑZ×mõR,äó-t´çÐZ³¾w �_âÖ[Ï“O>Æ_}àÊZöÝ�a·ÿŠõnìå‚sÿ¬öù3×~ŠK^q1ë7ôÒÛ»�_õq.{ý«vw·©¨œËaÓ4”Cží7D(æ”åøY.íÚ2°Ýçá5[Ã&íˆ5[#Š@[—Ǽ—™XòGÌq0ÖàEÖ�ÂPÈšÑf?/ŠY3]º Y[°©ýìʸǺRÌš�å˜mÊл©Ì#› >Šé=.3=èèÝ÷î8,›^âã·zÜpIŽÖEyÎhåÆáñ5uÆáðù–v:´hËÀ@Àеþ¤k…½—e 2,hÓ¸aÄÚ^ŸG6G¾Ø‘¾Æ?ÅÌ.Ó](…¬núl5sf9tiX×®¼ScˆŸ½Û™áÌ%]å€?<é³¢ÑáÅ‹vƼ„á\ÿµ�é\ÉÇßp sÃUü櫟çënÃX0ƒ÷qÓ-[xÙ¥³'ÈërÌ;¾ÄM—•¸÷ ïäS·±€{Øå|é—0[+²mpû£ßç±{‹X[æ�·ÝKÿ%—0æ$-ðÀ]�Pˆ·©Ésç4¼ s½ûzþwE,V”¦ç´÷rÍÇþœ#;`ð©Ÿòoÿø?ÜÝW¤ í¨Ýœ%ذí®[x(á(�ƒ[Tûƒ¡üäõ\óÃçâdAÓ9ûÃÿÉ'.žK(>ÿ#>úW×qÿp‰nüo®?ÿ:ÞsXEÚF«~̧¿±¢"F•Ã쳯äÚ_Â!m[úWýÓ÷ylÔP^{3×~ól®ÿëãÉïBÍh9á<Îêþ-?í3`ú¸ç®•'3&Àí(÷Ýñpí™{‡�Ç‹�]š;Ž3æ]Ÿå§7¢�Å_\¸Œ™ŒÒ±àÅ™ÒC„ýk-ßüßoð÷½Š… VK©®`ÛÖßÏ[þò\xþ±¬zan¾…é==|õþ­47þôÇüð†ñ¶Ëߊãì\Îü=ú X£¿øù/9mùé|øª�sëo~ÉW¾vݞ춆7¿�/¾¾…ܺAÞpcÀÅ>�·-tê&í–øÂ�úùa•ç-êà«uÉm'œ=ƒk�®þè+Ž>}:ÿ{:X¿ÄwžÏðæ#4£Oõóê‹ ¥ŒEOkåßßÞɱ*àßÜ— iýìڸܮ<óê.^;W'þH³ô>7ÌÇo.sÖëfð–i7|w3׬Þýïfû7ø¬59WsÛ�¤ UšãOíâcgäY˜­ßfÁ”Cn¹c;Wßç3ØhT;œuÎ4>rJ–™uÿÎ-}kGùÌφ¸m°a.;ÑWÚs_ö’þýÍÈ“ýüùOŠŒ¤ÌYÏlå³oïà®ûÚ¾^{³°cXØÁ—/Íã­äÍP|üM�34ª§}¶K¢%a¦îÿ$£„KßÏ5ýsæ;syûUCÎÛ;ž +n¾™§ã=gTëi¼ç¯_Î!m ÐÌ8ñ­\ùòÛxÏ6aÙtÇ-¬xßñ,Ïìl�[ÆËΚÁÏnÜŒÁ°éÞ»XùÞc8:þ‘µ£rkí™{sþK™¯weî4ü{è§¿í5|á‹ïã„ÖaÃ!A^Ì<õôÓtww3Þ|®ÿÞ·)—Ku×W­Yϱˎ"2m�<õôs\|á¹|åk_æÜsÎåâ‹.áÊ¿þ###tttÔyV§Ê¤Ÿ¹öS¼ëŠw×Äç?ôQ>û™ÙSÝ¥b#KhAe<ÞøªvÎs‹|ùç%VCKW†W�ÙÆi�9®ü³VîÿÖÍõ™å™GøäZ‡ÓNïà¼.XõØ ß[k1&dÅHž—ÞÊÌ¥-œÓVäg)ªå Ãòé@°¡ÀÿmÞCãv3¼óuÓ¸t¦"(ñý»G¹¯ßÒ1#Ç¥§µsÍ+\žŒ9ý=”Wg5m °–Ñ: æÄs{øÜ©™rÀonáæÕƒÊaÉâÞvjžóÎïa†³•÷Ý$¼žš3/êáÓǻ蟟Ü?Ê=[ ¶Åãì“Ú¸xAŸºLñ·ßà¾Ò®öÕˆáîÇK ÞBç’<ËsE~__ë�#ò,Ñà¯/ð›¾]ƒ -�…ŒçòÚs[XZ*óÛ'CËýÛ%H¨,'¿âeÌKè%Õu,'-q¹û‰°#Ôa·#Q´-¿˜ófÞÂ�7™qa»¥ws_¬ütÛr.>£kǽ‘;2—h#ϼ0Êér Ë»“ X1í´39Ö»‹;'ßP´9¶ÀƒßþNRM·Êÿñƒœ7-žu´†GŸŠÃ•ÙƒfÑ6Ð϶D›î‹Èªõ¬¡ÿ±ÇXgŽg©]ÇC�l­…9{‡ÿÿìÝw|UÚÀñßÌ-é•ô@(�H¡A„PAÁ²ØÅ²ëZ×¶êkWìŠQ¥)Mé5ôÞI€ô~ssÛ̼$„Ò Üóý|v]÷ΜsfrË<§<§=¼+ÞIQw}¢Ûe\\]p1–Mnh}5v‰Gè‚y¤ª ¦maý‰ݾôdÞ¾žDsYàìÜ™aq�¥ÁxcµEÒsã­tÁ¨ MLUU6mÚÀ€ñœJ>I`@ ă¦¡iðôs/p]¯ž,[¹‚¢"_}ú).®Î³bårÚµmOtT ‰‰‰ 8½¾þáå%¤Í¤L®sÞ ®ÍÈtÁÇsÿÄËq†1Ìž·�;vÒ³GOfý4Ÿg}qÑÚÒËN+]㣠teøÉî™eâTy faK¾ÌOÜr¡�—‰S5$áIO6³(E�W'yCÖéî.Kf k,ÍqcŠŸ7tÔ±$Q¹pm‘¤g`z4¶ï+!µ¶gˆ¶Û;Òƒqج|4;‡¹çæw&[YsÌÎS|ˆs4�˳pE¦g¬ !¨…VöT˜_ªvçÉžœ?ýœÍÉçÖ¢Ú9|ÚÂæ ¾»Õ•˜¾ž ߟòafc¨Ó:éÑÛm|>'›o3Ï5ܺ#6Jîñc¬¯+÷u1±m³õꪊù¤™5&WÆx81¨µÌªC•ÖÐÊF:С±c g´K»^´Ò­sd_ç™xô«Bö4êÔjA¸FÈþ´l^)s¬ä�§g…ÿGQQ5¸äùªN±Ü88Œ³N¡hVö¬ÝLî #i&ÙØ³qù*€ŒÏõC¸®æŠU«Ïµ¨ùääŸOzdôÄ·R@#¹„ÐÜG‚ôË×K%éé6z,wŒ½�^Á2þ(Y¤gžû…Ó0¯{‹›ÖU_Ž’~†³'�3éçΓq ijҭ”]×õJ§ùºººb0ÈÊÎ"~`Ýf£ºe§—D’ð pfÜ ~¼ÚY‡¬©lÛ\ÌîòvKDG»ÒF†’¤"¾K¾81RÞ±"¤kHF'†Eœ[{%íB J’Š™ŸyáYšÕʼu&~ÛQLb‘TÖ»Òкªa·±ü°‚ŠL¯N¸WzYìB¼oi[þ8¬”÷œ7¸ e}²¶o2±W£ÂUOB’*¬aÔT”f`hŽ Yªî¨ÇPy) $Qí–È—DG»aÈ*Ë`Ý»–õ9*8޲y[néçZögàЮ¸6¨üú\‹‡½ü ôýÅñ¶¤£ЕÊp¡Ãð»ypê½åÿ¹7¡5çf6kª·È~ô®œ~Ö�]©{ ¬Ù‹1Ù͆å|º` Ý�ê h`}µÑµ%a`˲u� É›7“¢%»X»ÍTö7÷ ïàޜ˭Ôhm‘\q££‚ 41UUÙ¶m�;uÆ`0�–žFHHHy0Ц!ÉŸNÿ€Þ~‹Î±±Øíç¿Ô4M#22’}ûvM^^¨jý×—5ø'­»ó.õïG›6mYvô$[�çb·;hÓ:œ^ݯ£yHƒ7´øF¥9ì쫪'YU)´z ç:þ6V'u¿™ýŒôpex°‰OΞ¯¯u¤ meÈ?VÌ:óej·¤§�Ÿ„„Æ©4;UmšrÜÂÉ8# ú”è;2˜Í#«|©< Ò…Ä�y¼°Ãq>ð–tÄ„ÊÈhœL­b�hé‰ì=£¢ëˆ5 ß®`“tD—ž—’f«rýfòþÞØ_±- ¬«ÚëÖØ{ „ÓÝÜiÑÚ…ë\JXQ~s%¢;8*Aá 3닱 ª�©Õe4„«‹³K…½#Õ\2sTh^u ©f¦‘Q°Ê¸{º7rBž†‘C1²ëÌÒäFÖ¬Þ’Ç ‘ÛÙV6"¦ Èð˜K›\'’ ..PšŒ@Ãb*Æd¼E)¤ Š„qõ«ÇHÛøñÜYqRK'lÇŸ`Ö);ššÏúÏ>ã¯n/0¸â68² ®N2ØT@ÆgØ‹Ì~¤ Õþ„J:œ]»®NØ4@£¤¸¤n�³ ­¯V:Âãã‰øá$‡ޤ-l<{;A)Ùrnжw_†õ¬Ð ÙˆmiȲ_A„ư;¹ˆ¿ö—.6(IÎâÎQIN9E‹æ-.=÷ψ¶áXmVÌf36» ½^�ÑhD¯×Ñ2¬Û¶%¢(®ï×�Í[·|Q–ÞÚ48 õ—R‰êp#v›�ØÖ^,Ý™I|”…ùDGDz%qsC‹ntšMÅTÍ/ŸÚHOüjQ ‹ŽyÒ³£ž!1F¾:k- 0dñ è5…Õ{­×VPõj·$ããRÚ»ŸkªzVÍwpF…ˆ†%ÀÂbVȱUªX/ä!#k ‰[ ™¹«„íyÚ…�”¤# lš[ë͘SõM7¸ÊH€³‡/ ²$¥ RÉ+®cpÖкj(Ü‘ffe¶;÷81¨�ÌÊemÑIˆÔ#k ëöYÎçoj„6hv…¬ªzáª#ãÖ7yéÔV5‹­›�aëÔ¡Šµ�%ì]³™ó37= oëwuL]”|‰/KnT ZÙ¿eÇŠw�¢èh“�@ä•H„*Ò„Uøã+§VóíªTtÎθºÓuÈõ´sn`}u ·ÀàÈ™ÞoGSŽ“¸#�ð£ÛÊJÉÄ ¦[Å)Ä ½vA„«@Jj I'“X—H—¶�ì,Ž%õt*ùùytëÚ½4 -›®§Uø§Á`ÀÓӛ͆ÕjÅjµb³IŒBCšsüÄ1ˆç¿ÿ}…†�Àh4^™€ÅŽ““E&+}#|0¥í§g›PJÌfŒF#‡£Úlº«ì#j.»|‰£T·^Äs#t5,�¼ü#M*ö”�ÝÁ�ÀHWz®¶²Áºâý@É+aIJý[Qç3¤Ò­gÕM—S4¬*Р€TcǪLž¬¼©ÁÈCSü¸3@Gsg•#•ƒQ e’,a¬î]gS8c‡¹ì�)�¡Â5Õ- m`]5Qí,?hcr€‘žœñ<`¦0¶p!ÎÔB T̈ÕmÐ�ºÌ:„«�SLz{­`Yž ($ÿöžƣ}*Œ•pjù¼±(­¼ÃLèÇàè+0êX'¥É�üW3?C¥d÷Ÿ|Sx #Ë÷½ìd?b¢ƒÑíIAÔ³ñ˦ñDõ/K¦¤å²vöœ¼,‰é$ܺMáá�yîÏTT²V}ʧƒ:ñlÏÒúåºu D>r Ûþõ¬ÏÊÈòQT•ôõ³˜½OÁÛ׿–Ý|].r=»óÕ‘T@9¾ž5©c¹³å¹»jeß’¯ùæç³¨€ì3Œw†õ£]Cë«ËåÊAÄÇwä‹{°jvlþ‰åIyeÓuƒ48Š &,_ζ‚ \FÛvnãĉDGÇçãÍúã¹èt:ú´uà’•�Éï,ÂŵªiÚùÿÖJ§êªªZ¼ª*´lÕŠÿ||}9|ø]ºtÅh¬ûïû%õ÷*ŠÂö�[p3hìÙ»MÓðöò`¾mrƒÊÕì �$<œj=�‹®49‚¦RÔ„kî,§Ì,ËuãN_g†‡Ël<¤Ò.Ò…V²Æñ}f^¦Ì¶hÖ²ò�ô¥£Š1ȸ7öP„ÝÆ·+Šx»;-:yñàož¨´jf;€Æ¾uY<²S©[p©iXʽº%djÞˆþ’êªEÊÁô3ÛÊ…>®f–š%ºvtÆ_‚ÓÍ쩸8÷2µA®Zn½™<¡#ë?ÛO±šå??;…u‘]è£�3‡÷°;9Ÿòe„r3N½�.uøŽ¿bœb5¤ f%£mgà §èB®Ô8®ŽöC‡Óñ—/ÙgÕ@Ífùë�R´w=ƒTNo]Æâ]%¸ºÊ˜Ì—a”Tò&î¾{è“ø UP3ù}ú Åxç'v¨ 9Ó塞”®ôÐyã-t_ø![‹54Ûa¾{ù¼§�¥{3+'×ÿÀû Ë:+$#á7ÞDg.¡¾º� ˆDç/÷²Õ¢aN\ÊʲµOº–ƒYy2îål‹ Âå±wïRRN1ꆑe‰VªJs/ёѤ¥ŸAÓ< kÙš+—Ѿ}$í#Ú”œ”ïGª�ÿ¥£§h(ŠŠ¢*H€©¸ˆþýú‘¸}+£¢¯\@j³[ oÝ�N‡¦iØl6 ‹ °X/q®¡ÝAJà#b@¨¦d<áaF<%P œ¬b[Ž+Fµ±d¯� �ôîè„ÇQ¥tJ§ÃÆûíuNfÔ šBv±žàç)#£^TŸÞÏ@ëËÐÅoN.âý½.¼ÛYÏ衞¬þ¦â,€ªpº@Có‘öÑ¡C©[r%MáL�Þ¥çÉ\<Y’%Œ”�ü^J]µPóKXžêIl+'âÛÈ,;b$¡�Yµ³|¥÷çejƒ \½ô´û/ž}–—ž X4 ‡6³ìÐÅGK†@úÞÿ2ÏÆ_%ÓuËé‰6œŽs¿`ß¹å ’3=†ö/Û³ôÊ�[ŽæŸwmá‘/÷P¨‚Vrš�?Ï`#€ìFÌwÓþ¯Où¥9 êUÀ¦M^ή�÷P¬i¨éKy÷›|÷hWÜ$�›�♇vñÐ{›ÈRT öÌæÙ{f_Xˆ¤Ã¿ïÃ<3¦yùßXÉ3Oìã¡ÿ[Å»†ùÄï¼þèï•ΓiÖc*/NŒ(]oh}uºÖf}Üõ37• ) €¤'bp<áUü^^ζ‚ 46»ÝÎŽÝÛ{ëÕAAa&³ ‡ÝÁ¾»q8¸8;ãââJ||<Ë–-åº^¥™rëCÓ4$I¢M›6Ìûyv[õÙYªÒà€T• dggRX˜�Ýá@Ó4¬6+PP��*]B– Õκcnï©'4Ú��[sYYUF@ötá®Nzt@ò‘_Ö¨¯v)ûÍì¼ÞHÏÖ.ôo£0з4Cìʶ”išÂñ, 5X¦Us#Þ8È½à‰®Ñ.W3xziT6­)`e¸/C}Üx*®„ÉË­’)ìIv ´2ÒÆ™ðÕ¶Ò%8•ø‡8j±±/W-}(Ðö¦:PZjíLkÙÆ±JçµïçÏ·×°Ïãæ¹frZWm4…Õ¬<ÜÊ™®N4+q¢�ØÏšY–UùàËÔA¸šÉþôü#fö^À÷ó–²fßi í¿l$ôîÁÄ\7˜›'ÜBBøÕ‘̨29t#;ÇþDKiÆk÷Þ oÈÞ£—Ä™ö^ç«�y|=5;“²0ãN`x'âošÈí×›øæ¯ó÷VjôÖÉ´ý0W>ÌW‡­hšÂéEÓ™1às¦ur „�|‘A?óÙ׿²úP.Ös=ç’Œ³_âo�Âý·v#@a¹A Ï0#0ŠÏgÌcåÞ ÌêùóÜ‚£xã�üãÖn^ðÑÐúê@ò¦ß î¸n^_Ú‘H† �¯.˜¼ŒmAhd‡�&ªc NNFTU�§‡F£’$¡ª*ªª`³Û±XJpQTü|ýxò©'ÈËÍ«½ðJ$IBSUúöé‹,ׯ;®Á_—§ÕpVþµ†>½{âëëWž�)¿ ŸÕë6pZ ohÑ€ÆÞ­E¬�ò!ÎÝ…§Çz¡-.dU¶Va„LÂ'Ä•i#½ˆsµÐÌç[mM¾îN-,aÑqOztpfêP�TVï±\°qö塱û¨…‚W¼[»3¥•…÷O�›:+ØÞ‹v”(V¡!ÛèÕZ{q ­¶Ðs”3Í»zsÿ‘LÞ=u~=éÉ}ÅìèíM/7žè]Âã›ìTìÜwòsãÙqÞôuu0gV&ï—mÖzlŸ™}½¼èìïÆÃ]Íük»£<­ÞÛ•)�J÷ÝÜJþ%ÖU›Ü£%$&8Ó?Ì™Iv'|%��ö­èrµA®nÎ4¿î6ž½î6ž¶æ“v&�œ"ªÎ Ÿ@Bƒ½q®á7ÊÐe‹WO«¡|wF¼±Œª²Ô|®‘~Ï/aóóu¸5—Œ,{Ùw—ŒO¿ê÷­©ÎK¹–R.´Œ›Ì+qU,}±%Rx>‹.n.u I�qÿaíšÿÔáHÀÎÝ_,åîjÐØ}/uÏ3y餤åR¬èpoB‹`¯òíc.&ãsÏ|xÿ,J'åt6ŪÍ‚ ò¨"VÃë«ýo á•ð2%ÔrØi‹ BãJ:u‚qQ ²,—î-ª–%ͳ۱ÛíØì6l6ªªÑ>›ÃÎ�AC\§N¯Ç©ÓuáÒ�ö(YÛÉZº�z~á¦";‘âhÃG÷† ”˜¯þªÇë:…¸óÚT722lËS±ÊþÍŒtð“1Ž" ÿ’ϪjFQ¯¬ÒäF9‘nyI¨&3K*¯©¼LLÇŠø:Ù™'Z[±Ç,ì-/'âZJl_QÄÑ�^ ¹L9D2÷çóEtOµÑsó0OV[À޲·†Z`æ­?�ù|„3]úóc+3+’d+þN êèD £Fê®fVÎÔÜbÞ^ëÌ'ƒœè=ÄŸÚZØ�¦ ºèÓÁ™p(H.äƒÝç§ó6´®Úhf ËŽ«ô�ral”„d³°´š}e/WáZ!;yÚÆ›Ð¦nH½¨d¯ú�_“Kç,Hº–ÜxS·î=ÚpŽìClÚ}‚´ôLÒ³�é5y½}ÎG9ö{Øw.Ë®ìF›ÖM85TÆÉ'„v>!õ>ÓàDx‡ +V_㻚Ú"‚p±œœÜÝ=).6¡×ëÁVš4TEÅáp ( ªª`·Ûqww§ °�zeÉ=§!çÀ%¤ 2;=ÙéèÙÐ"jU˜RÈC_[ÓÇ�[;:Ñ2ȉ  ¿]V“�µûM|·ÙÌ�Ë´–¦!JN™Y–çÆ¾�~Ð̶úM£n8ÕÁÏó³±Äyqg´‘‘ntÐ4rÒ-ü8¿�™'ô<7°ôPírÄ@šÂÂE ½Û‹.ÍÜøw? Sþ´–� j¤îÎåÞ"wàN\k7îj}þÔ’BKÖòÉvk¥©ÆǶæ0µÈ“Çâ\éîʤ²ÁwÕ®°=±�÷Öš9¡\xNÃêª�Ê–ýò;ºâ«ƒ¢£fÖV»�Ïåjƒ �ËÎéÝ9š¯R�´Žy?o(ݾŸ¸;qåç]Jù[ùò�Ywh éX�ëÆk�� ÊGÆ”¼�/Þ_@YÌŒÇ�ÎÎW¼�‚ ÂÕÏnw “uØívTUA‘HeÓi5UEQЇÃ�ÅR‚N§Ãa/ýw'§+—uPò»û- ©tájÊôûj<øÐÞ�ÜÿW›+Ñ®‹I>ÞzBÜ$ šF¡Iát�Ê•ŠõêÅèÄÓ÷ùq³»�ßdòeFÓ4ÃÙYÆàP):—QÇÉ•wó¡¿Ü´ípq׿%ã"A‘ÉAj~]þ–^zBÝ%ô•39òê�-¨au5®«¡ ‚PÙ烒èÛµ©›ÑÄLüñÌ­¼²©â'RBç?€—>{ŽÁþM0ö¨±õ£Gyê×d¬ç–'J: °Û•òEÉ©%·¼ú>OöºÒk\A„kÁœys¸aøH$ Ì%fdY.Å<·}‹Ýn£ÄbA’$ ‹ Ù¿oão½í²¤a�|ʹôÚYr¯iäåÙÉ«ÿÛ+.4Öƒaž`>YÌ¢Ì+W¯d� ó3ÐÜUåà ;y•ŠÉn�AÚé@³;H.¸ríªJ‰ÉÁ‘zO±Ö(*°s¸žmoX]�ëjhƒ µ“dg;�àÁ'þÑ4Á(€äA¯‡?à“°oøô§?Ù�^‚ª)œKZ(éÜhÞy0“¦ÞŨHŒ ‚ UŠŒˆdÙŠ¥Œ»õ6Ô²\?ªZ:ÅFUšFƒI–س{7íÚDÔkË–Æpí¤×÷^à„‹êà§ fÒ¯àò@�¿;ïLö óçfñvR…µ«ãû¹(�餅ĦÜGáªáÎ�ÿ̦Kv% —fAy›>È“½ˆ¾éq>½é! Ϧp*=Ÿb»†Á½Í[†ä.~¾A„šuŠíDzF:3g}K\Ü‚‚Ðô¥Suv;EÅ&ÒÓϲ{÷nü›н{÷¯m(ñ‹ÖdOgnïæD°—‘~í�é5ŽoÉgFÊ•MVã8kâã}.¼ÑIÏ-ãˆz9ÚQ£­‰ÛèճǯWáïlç–¤K.#--­Z"‚ ÂßIppp��½&Ö�îÚ³G¤‚ W¡úüà‚ ‚ T&¦ì ‚ ‚ ‚ MB¤‚ ‚ ‚ B“© ‚ ‚ ‚Ð$D@*‚ ‚ ‚ 4 � ‚ ‚ ‚ MB¤‚ ‚ ‚ B“¸&¶}¹dZ!§ö#Û®�äFó¨9×á´¢öÍĦ�ìFtûŒç_$eßQ2mZ�eH.Átˆ ŵÚ#ò’ö’”«âÒ‘Ž!.µ·«ø4;Ö¯g÷ñLŠ%w‚Úu#®ç:]S}©…'Ù¶a ûOeQŒ+ÍZDÒ£o/"| �_™ ‚ ‚ ÿS5 =}ú4;wîäìÙ³X,\\] &&&†V­Z5fUõcßÀ+ƒFñmŽ ’7|}”Åw!Õx’¡é7Óý…Ø50ö}—C랠͹1eÛ^ˆÍ÷ù5¤úϰyïët¯êN[’XøÒ=<ðÞZÒì::½´ƒí/ÆÖðG)fÿ·Ó˜ò¯™ìÌqp¾f cp?ùl&oŒnE£„ŠŽ3¬|ã!~{1ÇŠT*^¥äFü#ÓùêÕÑ´6V[‚ Mà�¥KØ·/1ѱŒ>²©›#‚ ‚P£F H·oßζmÛèÝ»7�:uÂ`0`6›ÉÈÈ`ÕªU„††2tèÐÆª®a$ «¾ÿ™äÉ�Ъ¦ Ëö]üøãHHRA§µ�‹º@º¿žÖNU£k�ÏE‘¯FÁîo7g- IDATxò®'ùvOµDÆeT’¿¿ƒ!ÿX@ºæM츩Ü9$š2ؽøk¾\¼Ž÷Æ Ã²x ñ­[‘ÕÑrX6-�1Ÿƪ  Ç¤{™0 =¾Z‡WýÀWóvñ×ÛcjZBâÇCð¾¤Êá SŽðãSo²2G­ñ0}Ç;yû_ñ>¿N­üŠ�¾Y̦Ci˜tÞ´ê<ˆ Oã¶.>®PsÙ1ë=>]¸“3v: �ÊS÷Ç\Õ7®–Éòןcžy/¼r ­t »¬?ÿü“½{÷âäªç±GŸdÆ·_ðÞ{ïKBBBà AA¸Ì% µX,¬Y³† &`4ùøã�™1cÓ¦Mc„ „„„°tÙ2Nœ8AxxxcTÙ0º¢Ú&q`ãLf~�g;VÿägÝüsŽªøED ;Ba¥×Õ‚< TÀЛ'~ü…‰žum„‰Yzß<’´VŒzýz¯¾�gW(5ž¥å/á?O/$Mó"þíu,y"šs“{'ÝýÆ<;€ÁoîæË'ÞeòÎ×èq #—¶Ä·xìË#Xä0&ü°žïLJ�£ÜûwöAï'þâø7¯óý¿x´ÆÈ^®2j&;Íå§Ôê>s*›}|/^ùW<>˜H|}Ã_Ø@¾kÝ®‹¦…-™Ä_á÷Ùsøköj¾R”ÚÙûöH¾œÅÀÇáF��|ýüpV¦®`ë›×ãvA]™¿=ɽ/¯¢ßìÿÒ²�Á(ÀÞ½{™6m‡ŽíãØÉCÄ èOdÛh¦OŸ.RAA®Z�IìØ±ƒ6mÚàîîŽ^¯gî¼yŒ¾ù¾þú:�ŽÀ€Nœ8ÑÕ5œÄ !�18öðì�Ø«=°˜Õ³~&Yóe`\ J¤Za>…HΞxV3:Z5…“›Ö“Ùj¯ßÁ‚÷'°Ö‡P�ìE3ø-]Eßn*¯?|>@ò¤ïÓÿá? û¡™|³ÎZ1§÷ï`ûö�ΰÖPt§v—wu|-aÓÊ ˜4!Co kU£Ÿ^¹¡¿+’šÁª•{p`cÓ«CèÕ£}[BA5%+û>à¦ÝéÑçæ¤èéòÜZNÙÖ™Sh]Õµýð–;%%UÝA¸6)'¾â¡çW#ù/ïMl^öiaí_±×Àø7Þddèù.÷ØGyÿ±.èÒ᳟ÓÐ%)‘Y:ºôé^–ÌLOäu=ñ)ÞAâ� Ÿ-‡ßÿý(³í£yç½±åÁï¥(,,DQL&………äää\z¡‚ ‚ —Q£¤&“ Y’°Z­X, Yøë˜ÍÅ(Š‚¢(hšFqqqcTw h-Ç0¶›5õf®,ªâ�¬Å³ø=GM ÁM¥ª‰}ZAÙ©§žõz�ÔÑ.a$Ýëq’’ľ&4ôDuêXÍ<÷Þ]çט;öòçê 4·þÜ0 òÜ|ÆÒVgaóŠõjN9š+¾¾ç?²�/>ä�Y¾nU#oÙ3<:«„QoÀm!�7íÝf³5ZY‚ ‚ —[£¤%Ky@ªª Gé„X»ÝŽÝnÇl6SXXy%æ¦ihºpn»³.Z& ¿[LNåÙlê~�µ’"9Œ[ïŒÇ �ª&¼9 ó1i »ë8½à þ1¢í‚}ñòò#´}oFÝÿ‹Ž˜ª<·Þ”4RÏ* {âYͨªLpó`d4”³©œUÀ#a"7˨ù+øeEþÅmqìbÞ/‡qH.ô›4î|ášh…¬}ë}V[Àµç]Lêô¿±s�ðw§‘·ô?<¿¤��¼Ãƒ‘Þצ£JQеŠ$¢Šý›ôm;ÐN%GrÒÈ:dT” 9“4EAA‡®lz¾–¿’çùÓˆ·øàöPd¥ˆ³ÇsôtA•32êcõ®Ó$<ü#·<ûÛ%–$‚ ‚pù5Z@š——‡Åb¡¤¤www<<<°Z­X­Vòòó)*ªjDòJ“ ½u C=¡`ùL柽0Ó¦š4�YëJÐELàŽ>ÎÕ…ù…¨Ø·½Æ˜qÏñõê$ì^Á{käKdÉÿæ¦î×qßüäK~ÀD-$¿¨tUw·êFV%ÜÜ]‘8¿¾×8n¿% �–ÏŠ_–Sy‡û¶yÌ?æ@òHàŽ[š×áÍ`ãĬ{¸óã#8Üzòôôi IXáªaßÃô~älÀ8^ýg*n髿d�¥hÈÍñ«êCâ⇿‡„š•A¦ ºÐ„Ê%¤ŸÍ+ï²�=C–B‹h¬záa¾.ÊÿMŸˆëÚ—ÔÒŸæ‘Qt  åÀÿ°*»á]Y9ùf^zôFŠÍb¤TA„«_£ oåçç#ëõX,S¦LaΜ9ÜqÇåëH .i„ôó¯f\R{¾ñy+ö ù�bò�þ,üa-3JâÞ'Û–c çÌ"Ѧ'öö‰t5PM0©R˜_€ àÔ†1/}Ä›&ÐÆMTŠŽ.æ�©ÿà͵û™q×�tŒ^Åc—¹©UôjØdT6ÐI`w8ÊÚíDŸÛÇþé[[ù3ËóÆq›ï¹€ÖÆÖŸ%I‘ñ~£ük™B¬±ûÓ;ýøBNë#¸ë»Ÿy¶›˜®+ühd/ø?>Ù£ÑåÕ§é{ágA+1S¢�ää„SUÉ g'ЊJ�“›$>RãÃ%KIûÇ]„Hyü¹p-æà›ÔQGáÚyèË\>ùˆÉÍÖòhÿרó6»>BÛ33˜8ðîz¡?\)#oݘ,ìÜq¦AwBAáJk”€´ °Y¯§¤¤EQ1bÇGÓ´òi¼%Ë%¤÷ÿãÞ†7Ðöw‡ŒbAaOú¾àÉ�É·Ð|ög$~ÿû§½D¬°ïà‡Ùûq8]Ç·w@Gu©Žv�¯!ïA θ9U 6e<"FóÚoF²»Žâ«S™þùf|ÿz¼‹ÎˆQ/�݆µ†¤¶‹µ4#°Ñ‰s‰ Ý&0¾Ã{¼ºÿO~^žÇø e{”Z73ï×d9€ïVÅ^©Ø’YðäÍLùt'E=x|ÎÞ‚þ”|ÿáB²ÝóæÝU¬Ñ6K?»å=•hìv�ŒFŒ �å¡×¦0ûÖGè7h½œ÷óÇ_0jÆ?éïØÀS~NVü‡üqW+”uo³ðŒc¾¸ŸNž:ð¼‹i·¾Æ�_ç³ùÃÁ$4àK£Àdjè¹AA¸Š4ʔ݂LÅÅãp8p8(Š‚ª–N‡MNIASÕ¦_CZ�KÿÉÜÖV�ãÀ�|ŸX:µÍ²qs�)¸¸ƒqU¦—=O2¸àæîV)­ðºOwßÚ §·n!E­ò°º‘}iæ#—NÝ-¨® •ü¼|T@öõÃç\óõ1L¸­3 ùóç¥äžÛ™bÃ\œVе¸…;¹W[µ–»‰7oìÃØOvaiy3­ù‹wD0*ü�(g3+ÑŠ÷ð;xqÏŒìå�—|>³öEùä™4$/¼% ÿ‘Ÿ±%ñ{І°wóéúüt‡[^y€OÒãøïÇ÷ÒF§‘wü8Ùrk"ÂÏEžzÚD´FÎ9ÆÑ¬†}i˜Jtž ‚ BSh´5¤’$‘zút•¯˜L¸¸ºb6›£ºÆaèΓb0¨'™ûýZÌš‰U³~!EõbØ�7|É[0è Bh…]J@ª #¼¥43)É™T]”BJR* N­Âi^1êh?~=�Pô×/,ÍÑ3kç.䌢'|ü\ï\e�¨Ëyrð0žY‘Ž÷õÏñûæy<ØÙã’öJ„«‹ÂÁß~å€Ã�¸ðªâÍ-ù¶¥m3%ù8§ª"U’�sÒúðö´)^•ñ�½™G^|ƒÿ{åInï„}ëyà£3\ÿÊÇL ×%Åf4\p-Ÿý.áì⌤™)67lié© ‚ µ¡QÒØØX¬eËWŧY3, QQQ�Q]#ÑÑqâdz;©¤ýþ›rV1wq&øßÈ�#›Õ)èR­Å˜íÕ¾JfzV鈥O³ó#– !7§k×`t8Ø—¸“*Ç?Ô3$&¦  'ºg*&•[�åö¾ÎPôó—墙×2oq:ª¾#&v«rrŸV¸™—G�ãƒ]%4ý «—½Ê @1.*üͨgX³êCgâúzWý¹7t¡_ow´ÜM¬ÛWù¯’¾n5zbâúÒ¬º/Ž’D^àRz¿Ä'÷·+›a áê™1—œ >5ÌÅf4Ù ÷†}i˜ªÛ`YAáêÓ(騱c9rèH~~~¸¹•¦â�ewwwv;»¶ogüøñ�Q]£‘[�cJ¼jÚræ8Ÿ9¡·ÜÉ`�ZNtìäÕ^¾¸º6cðôcUîSŠm7 ?�-zö$ô’î´�£†¬SÉ_6‡?r/9QŽÎeN¢É؉G¶¹pJ­Üœ›o€&Ö,^EúÚ_Yš©aì>‰‰QU,#Ö²XÚ)~øðW2å²=Jk;OÅ��A(š•-¯ßÇ›[ò.ÜãÓ–Êâ'ïåƒ$×L½§×%§qð tqFË™ÏS�Ì!©Â¬<­p;o=ð&Û¬~£ç®ÈÊ�Å�£'1Ø ×,à�¹KÉÔœ¹~Òx«x‚6ýõ"Óf%£ùßÄß=Bt5SzáZ§ž9FR‰†.´%¡ÕN�ð½ñeþ;Ü�Œyw7úßLŸ5—9_¾Ê�n佃Nôü÷ÛÜ^õשu×Û<øö1º½ð)G^øM`èyãÚæóÛ{²%£ˆŒÍðö¯yDL˜H¯z~iH’„Ýnç›g‡±îË»Xôö8ìv;’$&Ù ‚ ‚põj”,»ñññtêÔ‰¥K—òÅ_pìØ1üèÚ¥ ß~ó aaa�UU#’ð1™›á›4úN·3©{]ÒZ:Ñó™ÏøçÊQ¼¹s5Ï÷�`öÀ!\ßÁCÑiv­^ÎæS&4}(£Þû†iÏ?éji3™÷"[Ê·T)Î,ý—C §í·çŸB�†~ÈÎ/F—ný �áñ/^bY³¬Ÿs�·~ňAÑ4sœfû²el;kEßr½AU­ƒóÁľ,üé>žcGuÁ¤[[\Ü#¡åðÛdzHVÓ:žíÓ†çj¸c¾bÇû Ï ,MHÍÏ%_ÙÓ ÏšºçtáÜ3g%ú?Ìf¾ÃcKT4$Œ]˜ðîtÞŸÖƒ*'X÷ðîor¨ó l~´ãÅSN½yáÇ÷85é9®~UçCôø�˜óBOê;¾Ë‚ дóÝc’$]}�‚ ‚ 4Z@ ЬY3&MšÄ¤I“³ØËË}“ǵdæô³ô˜t;UÍ`­ŠäÇë«Öùò³¼9óO®˜Í�e¯éÜ »þn¦½ü*� ¹à&kŽ"2’“I®bÏz[þY’óÏÿ»sfñ#¯.]Ÿâ÷5�<3íE¾]·–¹_®)­OïKÔ-ÏòöûO3¬EuOÕÞ �x#þs¿%Ã&ã3úFT¹jŠŠl¥õš³IIήé.à™m¦a©W¡é黿ÎAûëu:Vòˆeʧë¸ó�,’“30šÖ*�š¾3œ:ñìÏÖpˆ{ׇ˜{p*…ÙXÜü poØ×rBB :WA¡©H~w¿¥!•Žà¥L¿¯ÆƒíÝI×Þý®D».ðùW3.mÒËM1qöø1R³Íh.>„´iG˜÷åÜPÜqŒ#I™˜u^4�ˆ¤åe­O„¿£�[ÖÓ!¶kS7CA„ÿ1a�|ʹ´QGHÿgéÜ iß…�öWªB ×ÀºF\© AAA]£$5AAA„ú© ‚ ‚ ‚Ð$D@*‚ ‚ ‚ 4 � ‚ ‚ ‚ MB¤‚ ‚ ‚ B“© ‚ ‚ ‚Ð$D@*‚ ‚ ‚ 4‰k" íÒ©SS7AAAAhd×D@ºkÏž¦n‚ ‚ 4œ­ˆìì,²òŠq4u[°Q˜�Mfv.Åö«¹Ìú6áj»Ï‚ Bm®‰€TATs¶¬bÑ‚_™·àw–mÚOJÑÕzØ6¿Ï-·ŽgôÃ?pøjh®m+ïÜ1žÇ>ÊŒ#�Ô ËQf}›pµÝgA¡Vú¦n€ ‚ ÔJÉfëòîœÍ¤–¨h^’œé~óÃWdÏOfïžÃ¤æ˜q8yÓ"²]Â}©¦–º·»ról¹$<̉ô\Ì6'O?ÂÚu$2Ô½Ò{Xá›Hÿ§(XŠ-8$=.®Nⱜ¸/‚põÒ1éæÏ¥P ¤ªçƒ7>VµN¥Ú¶}ÁÔWÖ£DMeæS>ÌzáC–§XίM•txwÃs/ÝO¿€ +Õ öñÃ;ïò݆TŠÕ V³"»¶ þÞgxææö¸U†ì;f0õÅ5ØCÇóåÌûˆ.ûõµïþ†^X…½Ó#ÌšZÄ«ÿœÉ³†8†VqðÑj>»æ¾Ï[ßo䔹âúÙÒúNù'O�‹Æ«Rðå8³šw^|ŸEÇM”7S’ñh7’gÿÓI£Þ\f½®AaßÌñÂêbܽÈoÿéWe°«&ýÂSSgrLjËÔŸs·gõ÷¹´ñ¬Ÿñ&oÏßC¦­BC%ÍbÇðÔ³÷T鱨!÷^+æÐ‚yýëÕ/R.XïŒäDP—1<ùï»éW¹.A„ÿQÿ#߆6 ³ °¨HÜ}}p­KÔa7‘�oFÕ@2zàëíRC°¢a-Ì¡À¢¡wóÁ×­ö[«”䑞žI^±.¾àe¬j”�¢œ|J”Zž ônøúºUù‡Õòv³`îVrú0qLg¼¤Ë{_4[!iä•`G�³»�Á�x;Õ<�®ü¾˜¬(²W_ƒüñü›Ü—ú]ßE­­÷û »‰Ì´4² JpH\½ü ñ«Û5 ÂU@çêM�«7AÕ¼®œâd®ráa5�s�'õÈ8òwñÉ‹û8ê;”G'÷ �·L~Ò~�ý;{Ìç…½ùú£Û ?÷QSÏòëËÏñÙŽb ¡½™Õ’шA[I2¿~¹‚$ϵÆË5ЊÙùÅ¿xbî l®mò� Œè†—–GÒö?˜5w=}ö4YŽøhb[Êdžm‡ùæ…7YxÂŽsËLž2ŠžÍ]°feÝüyíå$Bë»Ö¶¡eÖ÷$wz¾¯µ+(H\ÃS?¹W.Táøšu$)Æè·¬eš¶–ÏÆ÷ŸäÙßÓP}¢¸iÜ®kíù'Xÿë\þØû3ÏÿÓÊ;Ÿ=J/�sÃ× ¹÷ùkßçŸÓW‘ëFÿ‰cHˆnŽ·“SÚ6,^ÀÒ]syþy'¾øl2‘Wk.A„+¨QÒÂÂBÒÒÒ(**Âáp 7ðpw'00ooïÆ¬ª~Ô4ýÁ!‹h?‘Q‘®µœ¤‘»w)s·f¡ºà¾L¼©ÓE=Ð(…$%®fÍž3«2~=Æ2¾G³ê÷Ô±çrdóZ6J£X¹ð%ÉàIXl?öh‰GÅ”3lYð‡­5·ZöéÊØñ½ ¸¨r�âÓ§ÉUe¼BCñ�¸|÷E-&uç:Öì:E¾½R ¨w§EL?â{µÆ³rí¹Þ¼–MUÞ/ZuîÇ€na¸_«÷¥!×WQ}ßgØÉ9¼�?7!ÓrᨑÎ5„ظAôií!ö~ú›9vì(™YøÒ®]DS7çòÓÌìšó ;là5Œ¡mëÚÓ"#Ê™íìét3ÞGësÁA÷Þô�rãÞGâÄáùÌÙ6†ç¯s@9ò;óv›Pum˜øòKLmw>¢èÒ£'aö»y|Q&«[ÇC×߈m0Y�PO¯æÏÐ1|øÍ½ÄVZu™Ç»¿$aÕ·dük0­‹{y�݃>íÞfÊóËØ7kˇ¼Î�þ2 Q¸þ'æ%ÙÀµ�¼ù<7—5$"’.=ciöäC|bÖê±ù[ÃËt­ÿ5¸uK Î÷OälcÕ6ñÝ/ î•cü¹&Er¢Ûà„Ör¶ƒs™¾4 ‡Sî{禄Ÿë¸èEÿ~‘8O}Š_N/åË%7ÓcB ä¶ŠÙúçfrU=‘“^á�‰anG/î‰ÿ�ñSV"NL"2Rô ‚ 4Z@zöìYΞ=KóæÍ B–eìv;&“‰“'OâááAÛ¶m«ºK`çô‘¶�Á³¦Þa5‹#Gs¨mò—-ûëWmäP¶�Z»Â´B¬XÈêäd�0ºv‹¦µ¿;ÕB~ÚqvíC£èÈ_,\�D1NøµíHd‹f¸b&ëÔ!œ:Ë®å‹Qn¸…¸µ¯·û[Ñò9²i'©–šGÕ%ßH®ïzþ=ŠBaêAö>EZ^1vÉ ¿æ´�‰¥�ŸÓ…ÍJæÑÝì;™…Iu·E]£Bp«ò¡¹„”[9æhA�žá5¿Ïj�””DFFzƒLï^}عk;›7o&00�6mÚ4¬Ð«ž�Ó+Þâå_SQ\"¹ûÑÑÔ6PvÙ‡ø 7žF˸tÉÈ¿ðá¾·Áq]gô€ÜêÞúêzr �h^yxË…N=:â²8ƒ’Ô“¤¨Ô�J¥iµºMœ@ŒÛ½Xì_±’“pé3žÉ�+eHx_7ž›ÚýÉçGw³|C6#Ç ceצ�k®=G04¸R#Œ­ss/¾Û·S�oTCËlà58Ç2d@‹~É`ëÚm˜ ģ‰ŽÃkX}ZAréŰ8ÿZâj;ûÿ\Cª®}Fss› ¿a%·ÎŒ�r+Žý*¾~6ì€SCÛ­š),r !¡×WñˆåÉÔp¿,ºAÎi”€ÔáppêÔ)bbbÐét$&&²sçNzõêELL ?q‚¼¼<|||£Ê†‘½iæUHNÚaŽæGÓݧú'?%ý(Gó5\¼½¡ ÛEGhYɵÇ)ÐÚ̖Í')Ɖæ}Æ0ª“où‡½}‡Ž„oYÀ‚�Ùì߸›Èq½ü_z6ÒJÈý"SÚ׿sE2DÒ%ºŠódÚ·óAÞ—I~r ùZgü$�\|iîKË Ú¢¢88«ì„Q‚kÙwS]é#èëvaУf²ÿP6*:ZÅ^¼F´´�¡ÄFù"ÉâÈ�ãØÇदs"Ù‚†ŽíÂÏwlVàÒ¾môkØ«TñbUZfC¯#±ƒÐü·ŸHݶ†-¦ .�HíX³�3ªŒgï!ôó®åƒ£frðH*:Z´�¨b[ ™–ƒïçéÁ�ÐnÙ—¨ŽAèö¤r`ÖyËù^n�ïD˜ÇùÞRY£‚ h”€4-- ŒF#š¦±ÿÀÚwhÇÿ³wßÑqTgÇ¿³M½wK²%÷ncc\¨¦¡„H-”�JH¼$„@’P�ĘN=ôn\qÁ½÷¦Þ¬®­3ï’mY–díJf]~Ÿs8‡cÍÎ<÷ν»ó̽sgéÒ¥ 6 ›ÍFlL UUUáMH‰&'×Eõ® Ö¯/gÌqéÜUõQ°a3uDпW ;ª«ÛÙÆ¢¶¤˜¦¸œtê ŒH·XSt ã[Ô”–Ñh�-%�¾ ûݕݗœÈµ¬iª¢´Â»Wôz𓇠W3|e;)ôX8úä’µß3+=U/&[·Qc‚=kÇõ‹m³ICF�·¨€ žrJÊŒŠs~жíÄmÄô˨Զ:H>ŒœÅ%l ”SRiíMØ‹zéFùBjgдm [-l‰C9~Dr›Žî"kÌ8ú­ý˜õ»Ö±¦èX2rŽ¢ic¶,¦\öS¦´ûG“êUïóÚìJrå±{¢¶Y±Œ‹Šñ%ãœïN!¯e¨ÓW¹œÿ7�µ³æ“Ÿ}*}#€@!+W”átg—ƒ“¬@%ÿ]¾‚­c²Ø:÷qocîœMX}§2¥ß�¦…˜×ë%-%˲p»ÝÝÞç!ÉWÊÌ'ïáïl¤)j0?øÝ}ü|BgÓ×;fÄ¥‘Ùn¶ARr6Ê0ëk¨³ u÷fMEÌÿàÞ›³”5[ ©¨õà3­6Ÿ2ŽˆÒÚfJf%eÍó.¶½q7—}Üþ^ý5ÕXXx*Ê©5!ͬaW� 8HLŠowR…-)•ä`n€„ºÏPË`Ç S˜Úçu¦o] ê™:5®ù¸Þ5|>«Ó–È §�ßgä´ýØ+)«l‰=9¡k“LBŽÛÁ�Ëïàê5ÿÇ´åëxç¡Ûùßc±ô4’±cŽåøã'rüÐtÚmr""G©IH›ššˆˆŒÄ²š�ý~?^�¿¿ù6©eY`‡ÀÅ‘E\Ÿ¾¤®*£lã:ŠÆ¥Óîu¸gë¶4BäúeYl_ÓÞ¾ âú�ÈÅóHvt­l6[ó¯�a··¿@’aÇÞò»g{±,¯¯†ÓE—Ö¾Ù‡IUA! –�¬œ^Dî÷÷žªicÏçǃq±íßQ¶Ga€ÇÄ¿g!"y'^ÎUÜœ±í7JgQü´ºð;<ê%ôò…ÖÎüï,Æ‹A\ï>í<7 ¸²Éëå`ýæ& vV`ædèYRÀªYÃW 1rOdòÀÝSô®^C…Í ã�ß“Œ8SF2eÔþ³`3+7Gß¡1Xµe”5¤e¦µœkI™éD,. ´Êdàž©Žn¶}=›õf>§MêG÷ÓQðx<8�N��@€ÆÆÆØë¡Åª[Í‹ø=O/ªÂž9…Ûþø.èÕµ$£=~w8œÍgÐòØý8¼U³˜Çnû?^Ý膈T�žÈøœâ#]8Œ’ù¼úéú.þ"ìe8\8ÚÆaùðú,¬€Ÿ¯ƒ@£SÉŽG‚ƒ€åÅãÛ]gûuc·c·Qk¡î3Ô2ØûrÚ©ýyaÚ}µ€ÚS§’`€gÕ f•™ØÒ§pæØý¿¹÷�݇·eÚŠÃáèâS¡ÇmÄ ãª‡¦3qÆû¼ýÉLæ,ßJÑêy®žÇ»/=ABÿS¹ö¶›¸pHÛiÀ""G§IH½^ïž‹ ˲ð¸=¬[»‡ÃŽi¶‹+"rê‘oB¯×‹ÏïÇßòŸe™˜fóE‘iš˜¦‰ÏçÃã9ÀR¨�…e$0pP«‘-ë¶íÑ`Õ³yÃN¼F,ýåì÷¼WwÙ3G3!?<[˜óùvÖù÷Äæ­ÙÆüK)5m$ =–¡ ûŽ�ú,0œõ[—ðåûoðÂsÏðô´éLåMÞ›¹”­Õ$üM…ì¬01b³Éi÷9Èo«^¼.]N�郔ڕægáݵ‘™_.§Â´‘8d ƒâ�¤zé¼|!±¨o´ÀpÓÑÕšAtL4`5ÔÓеW7Ñ<;òõ6/É#&1²u’㫦ªÞÄŸDb;·ðl I$௮¢Ö0šëµõu¹eab°gÒƒg'_Ï^‡¯ÏDNƒaùh¨ÙEu½÷€ ©ȶ’Z^øp¯}±®›{:´X�«yæ·÷òêF/é“Á?¼²ûÉ(Í7ËÚ]à*@Ey%&ö”4Rm@`ó–bâ`ø…WrZvÛþÕ<ž1„÷{¶ËžINº?ÅE¥tùVƒ-‰ÔD ¼¼¢Ý6eP̽‹P÷jv6ëDÎÅÌXX‡å^ÎçóvaÚûpúi»vWÝ–NvºP\XÒnì–߃ÇßêÄu3îÖŒˆdú{?¼ñwLáO\ÔÇ�U·˜·¿(èv9ôØ©ÛíÆï÷cš&.—«yoD~sÂÕäv )€Al¿Áôùº€Í;×±©¡«çõÀªÝ̺"?¶Ä Ê´ÃÖž>|,ƒ§ž‡}á<®]È;/.Ä�ËòÐØäÓÁ€ ã˜tL«hi®c ”-æƒOL,{qqÑÄØ©­.e[u)Û6¬gØ)ßá¤~û¾ÊÃ[´“¿Ad¯œö§o~+õbR³~Ÿ®Ü…éÌ`ü”át¸F�YÉÊ ØÖäÇS¿‹Š] \Éô?‘ÆôÞgjíaY/A”/$–�×8;É��-Ü=Ê|T3+X¾` Qý9ñ˜ô}¦Ó7�ú€MT{mÖI”ËÀjj¢ 0bc‰ÁOCƒZ&âh"†¸ð²sá,ÖxzsÒ”8ŠñöçK(h41,ƒèì1œ~ÆxrBl�n'ŽÄÌ…ëCÛÁ¡ÈªfΣäÙµnâÇÞÈÃ÷|—¾AO‰è`×þu,^éæì‰m昬^[‡‰�Þú6Ï °›oö`�”œ¸ÿ]ÿv>øpeóc=‘”IŒÝû’�-\À–k‡2p¿_m“е‹(ˆƈœØæ¶kË`@~ ¶õµ®ZK•9 Íj¿&;¾YÌÎ]¿-ê>C-Þã¦qÒÔÑ<±t!‹ç.¥*þæU[8‡œÆù]|öÝ–ÌÈ‘ÙØ—m£dñb¶†3`Ÿ�Øðü \õâ"&ÜÊ>›äPãöT²yíÖ7æpÊÄüý¾Ï�ø‘œ|l on/gWå.Lzëq 9êõHBêv»1l¶= éèÑ£Yµj#GŽÜ3}Ìãñ„œ�ææäðÔ¿§u3J'v[SóÿFæ18?Š-ë‹X·±–a£w/r`Qµq=¥)’nã Ü½ 4Õ°«®OÀÂæŒ&6&§e'à«Åím ¶ªœÊÆb÷¼�ÒÂëñ`Øãé7n ‡ç�à4šÿV½�Å_}Åâ¢*VùÉ)ç1zϪƒJ Šñá 77³ó~ÐêÅGùªÏù`ÎVê�D†žrǦu‰›Ê‚ílkh¹¢sÄ’Õ»9é DìóË}¸ÖKWË"Ëjy Õ¶çyäö¶æ÷0š–yÔߥoÚº„•iãÇ�×vfuÀß<:b·aoÿÁ9v°¼~ü1Ùä$Y,ß¾ƒ†¡ƒ‰1<ìÜZ„?º/9É6¼… ™¹ÚCî SQÄÌ/S™r<—^:’„†5|ú¿Ù|¾ ‹ËNÌ i&‚Û㧸®.„Oº—<ÇCŸ–Bân¹óüKF «†/_|�‹F_Á�=òZTý:ïnñc8úrâ”>ÍIƒ-�Ìt”ûÙ°b-�§ŽÙû쯿Œ9ÿx€×kS‰·Që©a—Ûgwf<ØÈ;ãƾú ¶½ÅÃÿ�Ìß/°ÏóÆžíïñÀ��3¯&“<:�_ŽtŒš<žøO?£fùÛ¼¼ânnõÚoÁGüó�͘ÁC-ÃnÉ“§2Ì^6‡—"–³Ër1¦ ïÝËNÿÓÏbøkO±|ë;<ñîÉüå{½÷ÜôõÁsî €‹áÇ�¥ùg"´¸Íª™üíWO°Ì1”¢‡äêÁmžoöleɪ*,ÃAnï¬VÉh‹_úol1âî¾xHϾ(^DäÖ#ßw�gŸ„tÀ€ 0˲öLãõûý!'¤ß9ëÌîhnçóç>d­w÷ ¿.zêGì†U”®ß@åÈqÍÓ±ÌrÖo¬Â´g0x`ÒAYlÀjØÌï|ÆúzÙc¿ÃEczßr,ß.¶,ü‚ÏW,àýÒZξðdò£ G�ÏO‡[`sàÜçªØÀ•˜ÏñgÙizíV׳|u #&e5ß­5ËÙQØ„eÏ&w¿çßÚ:õbÖ±eîÇ|¶ªŸ3�cN?‹I½÷öh¶tÆžsCü~|MuToaÍšeÌܸ’åƒN漓o;Œë¥Ëå ‘Ñ’ˆš:{œÐ šQ[ l-¬Ö­ØJ“#—ICÚyæÖfoþ7Óê q71M0ì6l`Keä„Álød6o¾»ƒ {%Û ÿäÑd›ÅÌ�µš¦œÉœ;$³h)["é{âpR]¸†0ªïbþ·e %SrÉ ¡x|8’ΨUËÌ·>¥ÄšVðÔÏ.ã©76ˆžrÏß4¶Ëɼ-ûx&¯sÓO×söéãè—lc׿y|ðá7”Xz�y5÷m©O['Ÿ>Šg×,¦øÝ?òs÷w™:0OÅ–ÌšÉRïqÜóçq|zÓ_™Ý´”ÿþóMÌqC˜xâ°ŽŸ«?P|™gqûM ¹áoóXúï_ò£Å§púø|RÊ·,áËKØÙä$÷;7òã{¿Ëb&þ�+FÎãñeÛùﯯgó©'rLv$îâµÌžñ �ÎãÔ•oóY……ÕÅ;R¡î3Ô2ìf$LàÌãã˜ýÅ,ÞøÂ�9�3NêhÕóê1÷¢§òÛ Ê&"r¸ë±„ÔæpàõzÛ}¿VMMMóbG‡Ä”ÝfŽ^ƒ�°†%UXW6–É™6ÅëÙXmâÌÄ€î>Ç×®EK污Î$"ogŒïML«¿Î$úM<�º²W™]¼ž¯WŽ ÏøÔ–;óœ�ýúFä0´__ËÔÝöìí�FdTË‚-G'«j#ëKDôDßv–º5\Í+8[^^ ö[ÈôâöY±gÄ%*ïD.¾¨7ë·”Ñ`¥sò¸�ôÏpRòõ¬hìÅ”³‡’`@cM MÄ“¸çP ‰ñîjª›,rCXìÈãõ�Óµï3¬‡3ËKcc y&„»†’’šN66ˆ©n™5ÑUF.ßÿÃEôôa^xö4´,Êc¸R9æÂ¸óºã[­n#û»¿æ¾Ò?ñç7–±úãXý1¶(2�9�û︒2ýd^ú1«ž_ɆþÉ_–]Ì“S†18”²à ÷;÷0-õUþ1ímf-ù€gïŽÝFTÚ0ιêjn¸`Ô¾¯\±÷áøæÃóܬm,úà?, g"ƒÏ¸•ûoÌçÓÞZÚoW„¼Ï˰G,¦N$ñË�©òÙˆ›|'èÝ£ûq1àû÷ñTê <6ý.ú�—Ø¢29ö¢ŸpËÕSÛŒ¾‡·ÃØþÎéÿæ©7g²ê‹·XñùîýØ¢2ý�+¹îšó÷¼‡[Däh×cÏ�FÇÄP[[Kbbâ~w{½8œÎC`•ÝVlé ˜Ì²…•l\_Èq™™Íï’´"è;¨ï>‰b�1wQPÔ€…�ôÞ9íÈ#;;[qÕÅ%4Z©í¼Ä»Ý��š=¯BÁ°¨/, Ê4ˆÏΦK¿ß=T/Vãæ|ð ËÊýDeËgŒ#· ‰_GìICÓ ;VÕS¸uîaC»¸*ì¡U/ ½|í0bIˆ3 ÞG]]í¯ \_[� 8ââ»ØÆŽDU[·Pi:ÉËÛ÷¹í="HŒ4(¨«¡Ö„¤6ƒ�V] µ°%$²÷Õ‘)}•ÒwÏvþÒùÌXÑ@¯‰g1<¡yZ¹ßçì8{?gwØ/>?!q{ü�>;|ر¥ráßpáAÚ½eYØ’FqÅ}ÏqiMÛ ªp;bÉèÝ›ô¨vîvÙR™xÝßyçÇålßVF�é"±Wor“"Zú™“?~„÷/®¦ÚABBTóë\N¼‡™_ݳßîœÇÞÊ3n=@”N2'üˆ?N¸Œ¦ªBv×Ðd9ˆKÉ&'3®Ã×Ö ùì÷ÏðýÚ"¶hÒ{÷&3¦¹_ÿÂg\D]uoŸ¡•a·èãïàÃw0>WõÜ,ŠüS®ãáS®¦®¤€ÂÊüIäôÎ"±ÃBˆÛ–̘K~Í¿.¹•†òb Ëki ؈ŠO%';�˜ö®¼ŒÎ}ðcÎ=` EDŽ<=’�fddÐÐØ¸g£¶¢¢£qWV’––Ö‡ë!É“¹xÅÛ·Rì°q[D dH^·—•逯¯yA ['÷í~ÿ¨å÷ѺF­€�€áÄÑîG-š›°h~ÅDóˆ—‡Â�åŒ(rrR»8½©êÅ[ÂÂ�>eYy€ØüøîiÃH鬥™5l]±�â?ÉC&08¹½H ""]Í«—¶¼¦a÷3‡|½t³|A3bIK‹Á(®§²´ÿˆØý§/Z ”–Öaa#%=­ÇW“>lX TaÚ2ÈÎê`ê¶-�^NVn+¡¨Ò¤Ï>+`Y4ReÚHé•Õñ‚Tþ2¾™¹œºÌã9kØîg��–…¥<­’Ï–$Õpâ ñÙC�/pôžÏíMv%ôb@B¯.}Æ•Fþ�ŽÓìQ‰¤ôø»”lD%ç2097¨O9ã{Ñ?¾kå:øû ­ =ËA\fƒ3ƒùL(q;‰IëÍÀCéÒGDäÔ#‹» :”ÊŠ 0 ¢££q¹š/ì ÃÀåra1|øðž8\�1âû3$ljհƒM+6³Ã 1ý‘{°®æŒXâc À¤ª¢ªƒeä}TUÕ5�\ÅÆmf9‹Þx†þk:ﬨi:šYÁ–íµ˜Ħg4�xùŠÙQâW/r3ºþLY÷ꥉ­s>cQ©�¨Ü‰|÷ô$£-e.]·˜ÅË—óÍúòêÅMyys½Øcc³z ±|!³‘‘×›óc#ÛÛ™)oUobC™ ¶Tòóâ�Þ—³Ê)­01¢’Iépzl½æmU³vÙZ74_ ËWâwf2¸_bõ léL–Öf0á„á´~SIDR"1Ô²«:°gÛ]U5XÑÉ$…x_,`Zî,Âå:‚ž#‘#V�$¤)))Lœ8‘•+V°zõjÜn7111ØívJJJXµr%cÇŽ%##£'׃¢é;¨‘Ô±~ùšŒêuðV¶3bÉ뛉‹ú ß°¼bÿ)ÌÞ’e,Ýî#’ÞýrpØ’É͎Ʋ”,þŠÅ¥m2 ³ž­s¿bY• Žt†m^”!P¶“B�…##‡®Û³�ÐëÅW°ˆYëë *Ÿ)§Œ ¥+×ĶJÃ�É®U3™»½¾Íâ1>ªÖÎfáNôÎ?Ìê%Ôòuƒ£×pF¤Ù±Ü[˜;k#5­³`o‹g-¡4`•?Š¡¾çÈg5ÔPã#&®ÓiË‘ùã8®w$�›¾ä­�¾fùúMlXó Ÿ½ó!K«ìd3‘a ¤£Kùji5éÇž¸ïûM[úú'xؼ|%�>KV°d‹›ÄÉ áÛÙ4MΛҟŸœ3šKO¶g•s‘CU�å^ùùùdff²qãF¾ù檪ªˆŽŽ&++‹óÏ;�„„„ž:T�Šì3ˆ¾Q›YÓèÖ:€Ai]¼ l\ÏÇo/l^ù SóÅß®ïóº½û±çNæ'åãÄ aøŽßþ.s ™ûöÙѯ9)±¸ðRW±“�›‹¨óÛˆí7‰Iýv‘ØÉ{"Ç|ÀâòB¾~ûeÖgçÒ+) ›¯�ò”Ôú°l1äO:…QIÍ£°•…4Z6Òs²ƒ~1´zq³yåzj-ÀWÄ×o½Ä×�líê{2—LÊÁŽAòÈ9nÇ»Ì-¬`ù‡ÿaKz6½RbpZjË )¬l"€�ØüILê¿»4‡K½„Z>Blg€-…Ñ'Žgû»ó)Úø9¯–­¡Ov2‘V=e;vPÚÀ7€'õ§�u|Ž–Ç�—½ uÈH`ØéßÅöõ,æ¯[ƬmÍäö¨4NšÌ”‘éí™*X:s)U©ÇrñȤýïÚ3?u2uŸÏç�çæcÙ"Hég›ô:¹¬[·®Ý9Tõè``TT#GŽdäÈ‘=¹ÛƒË™Ãàþq¬]Ñ@úÀ�¤t1µL/�uuÔµ³\~ÀÓ@]«Á:{S«'Aí)ŒþÎE$-[ÀÂU[(X·”�{þhàŒËbÈÈñ?"{ßÕ<]½˜xÞ÷HZ4Ÿ%ë ¨Ú¹‘ªÝ4œÄe aôøñŒÌŽi¾èµê((¨Á´%�›ü”ÌPêÅ àó¶ŒÈøÝÔÕ¹;ÝܵO½¤rÌîzY½•²Òm¬/ÝýÇæz8b<Ç�Ì&¶u,‡C½t£|!·3À‘v çžÅ×s²¦¨��5…ͰE�Òo,“&�¡ÏÑ»š¶ôã¸ìú㺶±3…!'|�Á›¨«kÂo‹$6.WgmÀžÊ±^˱�í6m8g^:o£›€3’¨N—�îXß¾}éÛ·ï�7œc®á_Ï\‚éH"W/| #õª-Œæ{ñ;»®Ó�×®X˜ã¦|q%Ljj¨kò�#’˜øâ"Ú~ÊÍ®â*‰$939ôrÂÂÄ]WMí[/!–¯ü�ÕìªmÂos›�ÔN½ÈÑhÉüÙ 9&ÜaˆˆˆÈQ¦÷ÏŸdwªûÂae#".™ô`ߘn8‰IL%fÿ7ì´IRV/’º]øØˆŒK&òˆ­—Ë× ŽèDÒ¢;­‘o�†IDDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""ŽP?ØÔØÐíƒGEÇôèþDäЦ>ºž®»Öû —�Òž¾˜ÑÅ‘ÈÑE}>tª;9RhÊ®ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDŽÞ†jªvÕÒ8øÇò5VSµ«†ÿÁ?Ö‘îH­Ëp–ëÛì ¡ò7ÕPµ«š_×¶?RÛÉ�­å>Ò(!‘Cš¯d3¿šÍü-uXneѰ}1_}5›%îo1ºf¹)]=“·^yž§§½À>^ÈÖ:³vìeÞß(:àv IDAT/ã;ÞÌ ›öU¸�%O\Å9üŒiët•Ø=>–>u-ç\p=O¯>’ê2œmäÛì ¡ò³ú™8ç‚+ydiW2Ò£µÏ­å>ò8€ˆˆHÇ,¿Äÿ=ø —<ÊnÖÁ—IñŒ§¸ëÙŒøùó‹$�äê?þ‘+‡Ç`œ#÷0Ƀ'sªÛÅ Ý÷–öFmä`÷ýÙÿaTŸ=êh-÷‘G ©ˆˆÈ�¸—ñßǧS{ÝÉLÕóÓ‹¬zæ?q›UËÐïßË]WL"/ª‰­3ÿÍ=y�gþô,Ç{ÔÑZî#�R9jxëJ(,k–�ANj4ö.~οq5ë<½:ÙÆWWFqeG,iiÄ:»—¹ã]žþ¸„èãnçþë§�nˆ!ÿäùm���ªò°»-ˆì⩯ž’ârê‰!«W:1]øµ÷7VR\V‹ßOzf 1]­œ YxjJ)®l‚¸trÓb:<AÅpSU^I�Ï &)�”Xg�#Ê]�ˤiW %UMX dd¥v©®�”ÔbF¥Ð+3�ˆ‡»½u¥–5bOÈ ûm¸'Ïi×ûNhõ³ÿn)ÛYŠ'>›Ü$×> ª\!ô…}Žu�ûþ�ö¿»™Ë)(®ÃŒ¡ýt»oÐsçã`õÿn úX�Ô‡O ©ˆˆ¡¼ÌûÓÅÜöy&×þãvRßú3�}¾�zÓÃIÒ�3¸ùΛ8³wgn>¹û|~7Û @ñ#—0ñ'#n|–§/é… ‹†ÍŸðäã/ðÑòRM 0°Eg0úŒ+¸õ§gÐ?ú@qšlŸ5“�þÎ:ÿ¤–dt7CÎÿ9Cº\f7[>zŒ{Ÿüœ µ~,  ý9ëÆÛÛÁ'¼³™öø4Þ\T@C 9~G\o&^p=·þx™À,çíÛ¯àÁeéüèÉiÜ8¸ÍåƒYÂùYÝ›k§=ΰ7.å–£¹äñç¸yøÞm›¶}Æ?Ãû+Êq›vâó'sùÍ7sùèÄ=£C]Š©…Õ¸‘÷þùÓ?_Ei£‰FɃ&óÃÆ¥£8êÔµ¸”-|‰¿?ù6s·Õâ· ù\gsÜE?ã7?™@úž‹Xß<|¿x?•ëÿu7}>ú3yg5U> ÑÙ¹öîßðƒ!Ñ]L lØ<›xû¾yâËí{Ûðà3øÅooâ¬6m8˜úk_(}'¸úYð×KÚ´ þv)·|”É O^CýßïæÅ n’¾ûÞ¹u,ΠË|_Ø×Áîû�í?½ev«”™O<ȃo¯¦²Uû¹æ®_séÐÝÓøÛ«Ïîö�ž>£ÿ·)÷Ð]A|O=ÅUù¶àŽu€ú�Ð)!‘#”�ÝéÄ0«˜óø}ÔÅŸÌ/ø9µlœñ*ÿ~ÿî¿;š^ÿºž‘N…u2úÒ»ømâó<øÞvzŸs3W�K ±6 Pðwýò1úqÎÏnâÜ1ÙD7±äƒçxêå¦R“gï?‹¬Î2"«�5k¶pÃÈ!`¹©Ü¹ƒÂj?Ñyô͈îò4¾†%ÿ⎿~BIÚñüôW—rBŸj6ÏãÕé÷ó¼µÿâHfÅ îûå|Q߇³n¸�óÇfÕ¸ƒo?Ë´ïáµ0ýæ±ÄÚR9ñ´Ñ<¾d3gn䧃‡ìsaÏâ‹5>œCNã´>6ŠÚ‰Í,ý”ßÿòAf›C8ïg7pRßXÜ… ùïô7ùç�åXÿx˜+ú9»“XõÌyô·üùÓ£.¼™Û&÷%Ùé§ró|Þ|ñMž¸³šègþÂ÷:9]�Ë¿éeî¸û6Ä�áòß\Ì伨ÝʬWþÍ+/ÞËo£žäé浌ö8v°jY<í|h�ã†?^K~Œ‡s_æñÿÎåz…ÑÓ¯aH—®Ä¼,Ÿ~?sNâæ~IŸèz6ÏøOýï¸;†ì_ÇȈ Ïi§™pð}'¸úiÿ˜ÍuÖÈúמf)øÁOòH韉=„rÛöw°û~çûßmë«÷±Ø1Žëï»–¼Ø&¶ÏþO¼>—'þüŽé¬ýt»oôìù8(ý¿­ ¿§‚;Vçõ!Ý£„TDDŽX†Í³Š îË™öÈ• nÐ=z(‘?á�ùóæ¢3rJGCv2†MfÒæw±±“¤þ8ù¤´– F7 ^~‘…õ1LúõüæÌ”–ïC¿!}q”^Ƀó_âÕ•§r˨NFaÍ ‹qiDo~�ß<ô³v6Ð<àâ"}Ô÷¸ýΫ9á@ÃZV53_ÿ˜B+�ón»›+Ç·d }ú3<ÛÏ•7¾Üf•bË^™Æ•±L¹ó/ÜuúÞøû퇣âZy:o_x ?ʵ‘4éTÆÇ,`öìÙl¸zC÷„cR0k&kýsÚIdÛh'!õ°ø•g™]“Äx€;¦Ä5�ìŒÃØÄj.¹ç ^}í¾çÖþµÌ^° £ÏåÜrù Ü}e8lãû¥ð÷ÿbíò@VG‹Åt5® ”¬Øˆ'9““ò[n83©edj#úzÙpé£,þ|&[/É£K †a@ ˜e5×ðÜc—’ßR_Ç¥S±ôžÜ´”EÅ&Cr»p»Á¬bSàÇL¿ï ´4¥‘#á*½’?Îÿ˜·þ˜‘S¢‚>§� ®ï˜ì ²~Úc·ÛÁ,dîÖïñè×3rÏió°$˜rÝÚ�æ ÷ýÎöß²b¬YÅZÏ÷xîÁ’ß27bX5«~ÂãëÐ~ºÝ7zð|¬þ¿#ˆï©àûJÇõ!Ý¥%©DDäggàÔ© l}]hKfò¤¡8­zÖ¬ÜFH/ ð­cîÂ]X‘ÇpÆ )ûþ ÚÒ9á„a8Í2-ÞA§/—°©k²À½�Çïûkê-<þô3¼øäýÜþÝ~¸W¼ÆÝ¿~†å�Šg=K×x1bF3yÔ¾C¾®þ'pRï6?ùþ�ÌšW ±ã9g¿ø³˜:uNÿ&¾^XŽ ñÇqÆqqXEsørC«3 ørÆFüQc8ó„Ôö/,ü™;¿+f '�‹k5MÕ ö¸xjús<{Ãh"‚Œ ÃE„ ̲•,ÜæÞ'Ɉvwýöf.ÚÉUcWãÂFþ÷ñŸW_æþ=ÉVË–‰yä%X•T¶x3œŒ:ãtòZßK°e’Ÿ�aÖ°«º«¯ô±3hêiôk݆�d&N‚Óªcõª­Ím8ØúëÂq»ÖwB¬Ÿ6 °,úœr6Ã[Ÿ¶`Ël_VOõý1œŒ>ëLòZϵ¥Ò;» í§»}ƒ<«ÿ·sW¿§B8V‡õ!ݦR9²‘ôÉËh“(ÄfegXT”W øD«¾€‚Z[¯>ôŽØï Äggg[Bia úw<­Ë21`6Ö’}õ4þta¯–Xó0téîkøÍ§ïò¬KøÛ™‰>shÕ•QÚhbäd’Ѷ0ö,r²ì°½Õö�ì¨4!º˜Ù/LgM›kô@q vìÜQD€ lÄ0aêD¿üŒY37pýС8sÛW|±Ù$þ„Ó™’Ø~tVc;ªLl9Ydµ}ØÊ™Hn~bóvµAÆäÆE—�㋇òÄO/åƒÑã™8n ãÆËèþ)\ª«qífÖí`áìy,Ù¸“²êÜ>?~_ [j,pÚI>\¤¥Çµ9g®']ÍG�Húôn›ìÄf¶´á²æ6lúœvá¸Aô�àë§½c:Èí½ï1ƒm«F�}!X=Ö÷Ĉ -­�öãêBûéfߨ{¸8«ÿ·p×¾§¬º�ÕN}H÷)!‘CÚîë¦M±³L³eû6WZF1Qû_>NXÔû¼ø�ý®+t<··Fd®v.î W.,ê=ü@‡“vm‘ÄDàèÏ”ImÞŸjÄsÜÔñ$|ö1kWnÂæ±.žay<Íñ¸\íÄãÄåÚ·fvÇo5leÎ'%í^4Ǧ¤cß›FD�9•R>åÝ9³X{íPF8lþj&[ÌDÎ>}&}¾ûžïý!/¿ñ 3Á+ß|ÆË†�˜ìq\pÝϹæ„^žÛ®Æ «_âW¿}ž¥µ.2�dHv2ñ‰.v;eö>lرuô·`ÑD·×†]û¶agç´óãvµï„X?í3‚Ȉ}�l»¶/«ÇúþÙ0BÎ|º×7öè‰óqÐúûºò=e†z¬vêCºO ©ˆˆ \QØ ¨«­ïdš¡É®]µX†AL\L›»×>¼¾ýÓYËçŃ�=ÂÒ ‰Fd‘XMn<íd˖ǃGdTç?¶¶ zeØ¡ÄÖî]w{l|óh”»©Ó¤Üp¹ˆ0Àòzñ¶ÝÐj¢±ÑÚçóFTsü¶^ðÈô+÷>cÖ™ˆœqbï¾5‡ë¯aÄàÍ|þÕ¬ôs8slÇ/IÝ[WͦnJL8I}¿}¿ôV³uÍRÌû‚ÿ½7Ÿ—~Mû7·�i~]Wã"°•Wz‰¥õYœû‡¿sÇ”ô½çÔ¿‚‡æÏeÓ�¦Tw‹Ï~'uÿ6Zýu¦‹}§§ëg¿{JÁ•Ë ²/«ÇúþAzߨGwÏÇAíÿíèÂ÷T·ŽÕ÷˜d_JñEDä�‘ß�\»Iýªelðu°‘w –VcÚ{3t`›ŠÌ «Û$³ %¥ÔY622ÒCšRgÄåÐ;ɆY¶�î¶5©Ú¹“zÓNvï¬Î/J�†í…=°ƒu[¼ûýÙSQF•i�”’Üé�¶ŸFz„�U^LIÛ‡bl-Ø÷�¨òÒm˜eÛØ¾_üq1âÔÉ1J˜=kî 3ùªrN>�ÎÖm2¢sè�bÃ,ßÁöÆ6W¤þ"þ3—ÒJL­ÃK$ôÉüàÆûø÷ÿ�NªU—_¬¦£fÓÕ¸ª×°b‡{¿3¸tRú¾+wîÚÊ–ªî¤7]`6PÐ…6Ú9íü¸]é;VÍÁ­Ÿ`Ël_:žžêûߦ ûFg‚>ßVÿßãÀßS=ÞW¤[”�ŠˆÈ!ÍÖg*ç�Ä,x�Ç^YKCÛk[³šo¦=Î[&±c¾ËÙ}Úþ´ùYýÕlŠ[_U[ÕÌÿz ~#‘£û0!5Zîˆû|­.߃˜}o!�F2c�íÛùÅ­s #‡D`5,cö²}‡£–ÆWÅmÆ—˜r\&FÓbÞû´¨MÒ`çûrË}Ï2«dß¿8�ÂÔ>E‹¾æ“s) §Ÿ6°óØý™8>£i Î(ÛçX Ë^ã¾ûïã�ïlÄt“wÝ›Üõ‹ŸñÇÏ+ÛŒxD&%m€ÍÑÉÙíj\v–Ïßò~Ífs¦½Îr?Xþ�ƒ–—úY3c…û´ášýÛpˆç´³ãv©ïØrý[®`ûB'nßï`ÿ= Û}£3Áž�ƒÔÿ; ñ@ßS=ÙW|•lYµŠë‹÷ÿ}’.±GsÚïwOP¿å¬c;ݸ¢´˜¬œ>ßF\""r�ì -#+Üa˜ÇÀá lš5—Eó>ãã¥;Ùµ«Š¢íY>ÿ3^~òþ5«²NáÎ{¯bÔžM ¿~“�7:ÉvmæË5R#Ôlgþk�òØÇ˜¾Ï�W�%¥Óë2£ì^›±™ŠÚ) > ª#ÉËL$»oë>ŸÉ×_/¥,*•D—Ÿê+øà_1ma i§ßÂ]çåu€)^Fbú4|͇_ÎàË•58#Ljv,å½=Ì´»ˆ�pÿ÷ãaÄw¶#Š^±E|òåJ–/Ý€/!—»‚õóÞà¡.Å™ rW£Î9�cSm€�Œ~Ilÿò+æÌ�Ïf3‘„È ¥›øú½§øó3³Ølç ƒ±Ï*Ÿ‰$×}ÍÛ3–±º°oþÅÜqÙöÄfR8ï >ÙèdøÙçs\º p�•ÍšOg³`Á7ì0bˆòW²qÞ[<üÄûl6ûqÙí?åø´ˆ b²ET3ÿ•7øpæRŠŒh"ñÑX]Æ–U3yá_¯ñMuç\w%“2;š”ݵ¸&fÇR±ànÚÂN3“ìX%ëçóÖåeó\.HZÁ²¢"óG“ŸI\”�Ò…oóÁZ?O»˜²[7°Ýõã`è™p|fg)‹IÁÜ7ødS}b¶òÅJ)Ijv°ð�Gyì£û´áÏi;Ç ¦ï®È ëÇÖN1;©³ Ët_èÈÁîûí?š² ÚÏþ}®û}£ÏÇAêÿí×´8à÷T°eè¸>ÌÊO¹ûÚß3m¡�IßG††ûºäá�±;=dfˆˆˆtÄ™{<�ÃëÏ>Ï›_~É‹Ë?k¹ëoàŒËeì÷~Â5WœÃˆÄö®¢ý¯Éúäïüáæ§h0-0\¤Œø÷þö‡ 褑ǞϥÃ0mÕÿxàž÷H8ó~N•�3óLî{ØÎ“�NçƒÇïæÝæ—‡âˆëÍq—ßË­WL$©+ÏÑsÝ_ø[ìc<üÚ»<ôû·°0°E¦2ò¼ÛùÕug’sà%Q‰?þ&þòsxfÏ?ð ÏaàˆïÏÙ?¿‡Ó7ý¿ØìÇ×jË–z2w?â ëÓxëùûùjzK­º0ùjî¼éFì÷ˆ™�>'ŸÂОfEµ‹±WœÔ…ØÀ–y÷=lðø#ÏñÑ´?ñ™i�a#¶÷$®½ûüdHDÐ1q¹õÁ_ùèó|øïøÐl)›á ®÷8.ÿýϸftçÏÈu-®\.þÕMlüÝS|öâ½,z G<¦^Ë_o>‹¤EÛù|Í'¼{ïu,ºè!^¿iÈ�+¤K,>–-“Sn»…ø7ÿÌn~ºÓ6Ú9íHûŽ-ØútMW®àûBGvßoÿ)A×O[=Ñ7:l;;ýÿð{ªgûŠt‡‘zÕƒFs–¿ã±ë:ÝxíŠ%Œ9nÊ·—ˆˆdKæÏfÈÈ1á#x�&*‹K©j àˆM!+#‘Èv" ú!¿|ÏÁÅ�¼È-£xk‹(,÷`KÈ$75*¸çV,5e»ðE'“çÚï³ÞºRŠË0] ¤g¥ê‚¾zÊJÊ©3#IÍÌ$!"„4¼u—QO,YÙÄváös ±‚¢ÒÜF©™™$µ_©=ÀÂS]BQeĦ“›ÛáÝñ`b 4URTZ�;`'*)“^É‘A>—Ô…¸,/ÕE…”»íÄgö"#f獵žZŸ‹øØýÛFϱðÔ–PTîîRýœ†Øw¾¥ú ª\!ô…ýì¾€ýwW÷ûÆöT;;8ý¿»¾ÍcI³Þ?’Ý9¨FHEDäðb�"%'�`Æv�ƒ¸â{‘âq�22;ü³+.ƒ>q!î»5g,é¹±¤wg®8²‚ Æ�Jn~jwŽÚE‰Y´yÅg»‚‰É•Bn^wF–º—á"1;Ÿö6±EÄ’컃‚fŸÕå6Üç4¨¾ó-ÕOPå ¡/ìç`÷ýì¿»ºß7°ÿ ÚÙÁéÿÝõmKö§ô_DDDDDDÂB ©ˆˆˆˆˆˆ„…¦ìŠˆÈÊ΀soãþ±9y¡>Ð)r4Rß‘o�R9BÙHp'w"‡õùöhÊ®ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""a¡„TDDDDDDÂB ©ˆˆˆˆˆˆ„…R %¤""""""JHEDDDDD$,”�ŠˆˆˆˆˆHX(!‘°PB*""""""aáw""rø*..w"""rˆÉÊÊêò¶JHED$dÁüàˆˆˆˆ´¥)»""""""!‘#šeYáAäˆfFÈŸUB*""""GœÝIhëdT‰©HÏÚ�ˆZ–µçÿƒMN•�ŠˆˆˆÈŲ,,Ë¢¾®†]å¸ÝM˜�@¸Ã9"Ùìv"#£IJM#6..)UB*""""GŒÝÉhEY1õµ5dåô&!1»C—½"CÀ罹º’â�;p75�šÞ¼àaW“RõL9"ì­­¦¾¶†�CGaY^Ÿ¼žp‡'rd2 bã8,‰ k–Ml|BËŸœ”*!‘#†eY쪬$3»~¿OÏ�Šl–…ß41 ƒÌì>”—ßåR½öEDDDDŽ–eaš&nw#ÑÑÑJFE¾E–eƒ§©Ó4»Üÿ”�ŠˆˆˆÈa¯õªºf €Õ�×PˆHh à Ð*íJRª)»""""rä1ÍpG rÔ eV‚R9âh²®ÈáASvEDDD䈠gFE]í�!‘#ÐQœœz먨õ`Ù£HJŠÑȼÔVÔâÆFLB21Îp„päŸË#±L""""r´ w>j5R¼¥�ê@{�Øì.bâ’IK‹#¢‡×_ò~ýßû¾^ßç©g¯e¸®øCã]ÈC?þŸz²¸ôÑgøù°o¿"�†syIDD7¦iRRZLiy)^Ÿ¿ß‡ÓáÄAzJ:™YØlzÊDDº.Üù(þÕ<{Ûݼ_ÛÉâJ†�36—cN:‡ýè\ƤöÌ¥¹ewà°Ù0lÆ!P‡-Í‹5¶ðÔãÑp.•�ŠˆHX–®\LlLýû $Â�ÝnÇãõÐÐPOii1ÅeEŒ>»ÝîpEä°þKw›`#uÈDFeî{Ùmú¨,ÜÄúm;XøÞ?ùfÎ~þà½|¿Ÿ«ÛÇu�p³çÞ ¦�Û‹Öî áhSGùTB*""aµuÇVR’Ré×w»ª«ñz=8œv; qñÄFDzuǶîØBÿüáWDáÎG÷ßÁ� ïäOgƱÏÌ\ j×ÿ�?ÝýŸ.á©¿¿Å¸Ç~@~wï½ùÝ4ù»¹Ù· …'=*Î¥R «ª]•Œ:ÍkÄ8û?»Ý†iZ˜MË€…ä¤�bö†p‡*"+àÅëqÓÞ£¢‘yçp×/×±ü×P¶q_l½˜kú·ÍHMšÊ6±rí6ŠªñÙ#ILïð‘ƒè½ÿã V}1Šê°œÉäå¥Ùr`«®ˆ Åõ�Aÿœü¥«™»x5Qƒ8é¤Á$uò,ëî}îþ¬ÝrS²vK7SoF’˜5€cF÷'µ“^³©Œõ+×°¥´šF3‚ÄŒ|FŒHf”­õ�(ÚTL�å"½OR"ÚìÄSŶí4á$)7�̨6Aj(ØRJÑdåç�Ø•lǬ§`Õ2Vl¯ ÁŠ&#o8c‡÷"¦+íR™Ü”mÛI¥Ï :­7}’:¨$«�’-Eì Äeö%'ÞÖá¹lÍW½�•+7°³²¿+‘ÜÁ#Ý7™ÎÆÚ»÷·D ©ˆˆ„•Ïç#ÚUFDòe(Âò¯Â2ã±Ñ„=2?%Þ|�73Ü¡ŠÈaÄ ûië5«Ãx,Ó‹sØh†:>¤ÌWÌŽb?Vÿ½I�U³ŠWz„ççÐh¶Þ‡�-:‡“¯ºƒ_Ÿ?�èV‰Šwétn¸w&¾^óÏé×°{-ïŠçùÙïfày#Ï]SÏý¿~‘5�¶ŒóÉ›2¨ÓäÍ»ê%n¾û3Ü#nॻóøø�¿ðâò*ü{B2peLàg¼‹ û¶I…Ìj–½ö8{yÛÍV5Ñ\†“~t ·]<Œ0Ëù诿`ú–(NÿýËÜ39rŸ]5.|ŠëîýŠz"˜pëóüíì¤}}ÿúÿrÛÍoP”~>�=w£;.RóöE_ñð½�óÞæzöT¯a#®ÿÙüú®±­öÝæS&ü¬zé7üî«bO¹‹×ïšÜn²kn}‹ßÜð"�~\ûô?¸"Þêð\6_ÆœgÿÆCo­ ÌÛ*6ÃIʈó¸í7WrBF›“TÜß%¤""VQ”WùH¼ˆ3æDŒˆÑ� °õ,ü5OQãKT¤7Ü¡Šˆ–µ;10Øgý6³ˆ·ïÿO/nÀ™3‘«.?›có’¶C IDATqy*Ø0÷M¦¿¹œ/žü=Ž´'¹{râÞäi÷N û>ÉšI„>OïLûŒ­ñ£8ýô¾$F&ùc†3§M�[yýÏÿa† 7Ü=‰!é.‹–òö³¯2¯dO>ôÇ>ö}úìÞŸÕÀÒiwò«×¶à�éÇ™×_Î¹Çæ‘`U±yÁû<÷ÊW|ù¯»)ü�G.íG„½7Ç�Ëà¹Í%¬\¹ÿä¡­ë–­¦Ñpáð±vùÜgO"jo…Q´b%¦�ıÇ3ô@¯iñ®ç¹ßÿ�w7ûˆÌ?•«®>�ãr£ñ”®cÆkÏóçû·‘Óî ²LF,ÏœDâ¬�©þf ë'srlÛ�Ø4k[®grFž­Ós‰UͼGÍÿ}TŒ™<‚ p.û%Á®MÌ|ýÞ_ù&¿»ÃÃÿøãâv‘÷ª¯§(!‘°JKÍ ´²Wä)l]úÿíÝw|WÕýøñ×½÷³³ $²Â^Š ²wmµýi­³îÖ¶_­mmÕ~k[m묶~µîÚº‚È” a6„�=>ãÎßI dBï§ù|î9÷œ›óæqNÎ=ç¼Àˆ!ñ¨î8v!{ó¶Ò©ÛÝ—“œwª‹*„èHZq‚ô­9[yóË-üpb/®ŸpVÓî‚õ‡‘�Øl: ¦“•î:r­µy&¬.ÇÖzrÃ~Ï­Y`Û½0l$™ú�ÜûñAæ}²�;Æ\JJ}ƒÊš÷V\h€�7—9éWó·1Àïà8¦nbï™) Ö¶YÌ~/¯ªžã¶‡Ò…ïóþv¢Frß_âÊ$ Ë2{0hä`’ïû1Ï�ÊŠW?ËfÖÉ7d"ã’fñaþ2æ­(gÜùѵ˜ÖVæ.Ø�¥x1ù|Rë+{�Ÿ¥¾á}þþÅ~Lo6w=õ$?ÊT±l”áŒÛÿ-?ç�½_ðòçW0üÚ®¨Í,÷É {è !„8¥ÒRÓÐ�¡�ID›ÂÊ-qF³bÓ@ö—]MÄŒ' ’–*¯ì !ÏiÅÿÞ˜½…û®=›{¿;‚7foidªÆ•F?¼˜þñmo¿É\˜©ùNéq O¾ö/?ó[®Ê0Ð Ó2±,#¢ÐodüŠƒ±g7{ìúîíÔ¾·â vPa䯥—" Ñ ¬FÖÇQÒ¸ô¦‹él…ÑÍÊò˜F¥÷ ú{°±ÿPun:뾜Ãü£~À³5tÝÀ´,,ËÄÐÃøG\ÃU½]8áf“�…ƒ«ß†E)X;Ö²¶Ø>RëðZVæ9Ä<ŸÉÙÉP°–œ¼%¯gÕ&¼=Ðs‚úDX½d%ŽB`ÔT&ÄGÐMË6±L�ˆ•Êåß=‡h¥îO°yu²]ÙLß Õ©`é‚å”9µKclþšy{,”À.>/®ÆëûY꬛»€< £®âŠt“ˆ¡cZ¦Awõãê[®åê«®btª‰Þ‚r7翦’R!„§”Ûí¡s§4 ‹ ÈÌìÎÒ¥K(.+¦´¸Œ‰&q8ÿ0ÉIIxÜ-? A!šÃ´l Óbãî"L«©oXì˜û:/l«ýþ¨c…)Þ·•U«¶p8â $ŽàÞ.§+9ÚCñD“–Kç §j& pl,ÓÄ´mÂŽ¯!]GoÊ8ÀÕ‡aÙnœfÌ"+Þ> èA=Ç�DP !bTelbãæ|l4²ö%PϬcwb@ÿ$ÔM‡Ø²q;Æå)x½ý5ÀËìÅ›X½1Â¥çú‡²59äš^FîK_o¢Þ[Àêu…ü0+0¶¬!§܃G2ì˜Wbë°²cW�ngeÖ3›jãîÙ—®9äX5?nf�Pé?áBº~ð6»W,diùùL¨~•ƒ _/b¯­7f2çœ°ì‡Øœ[€�F·Þ=ðÕ-‚ã�>þÇ<0° tÓnA¹Ûž H…BœrI‰É• VŸÇ„q“™3o¥¥¥èºNz—ôS]D!DGÓŠ¯ì:ŽCiE„ü¢ LÃh\ÞG®±Ø»äSþ»¤þËw½'\ÍÝwÿ€³ã ŒZ#=»bKf|Æçßä°qç> J#ujõýŽLcÖ)G�ò*¾D’|Ç~ÞŠ?Š@Ý{8JÕ¹«U_9€UÌáüÊ íxï·ühzý;å¥E88„ ò)µ E�bèÙ}p-^[¹Žôœl\DX·z=º«C²}x]ƒÈvÏaÝêõ„.½€(,vå¬%ßÖèsö0’ê+cMV)Å%6à"!>ºÞk•¸D«‹\ý›]'PzŒgR÷wxyû*æ-+çÂñUGé™ûõl5�ó' #àÔ(N}?K«˜ÃUeO¨¿ì¶A7jÖ·ùånk2 Bqʹ\np¶ïÜFrR ŸÏü Û¶ÈY·Šô.]qËì¨â$zcöÞœ�‹aZ8ŽC|Œ�â²0ùÅA¼šÂ¹w¿‹ã8hªÂ�.ÊæÖK'7Ùßÿ-·÷×øLAq¹ñÇ$Ó5«É]×ë FÁ)YÅó>Ê»[ÃàM¦ï°±œ“‘L¬ßƒËåB9ð ÿž±‰p맸Ü-4v ë˜feÇ60ÌF7�2àŠóP½¹Sò�ádi9l_»ž<;›îö6V®)GIÄà$ÈfH¦Æ²õëØ¨_ÀWkrö`kŒžZï;µËf W�啕\õ_¯¨hj�oš]'€®L˜Ø‹×þo3Ë,§tÜx∬ÿš¯Ù¨©pñ÷‰_{uLŒªÁ¦¦i'®k‹Ëݶd@*„¢]X¿q=éé]~7ƒnù¿*éøƒ'+B(lTæÝeg§½Æ–�kYWr5]‹sX• SÑMqpHcðÀ$ød-«w™ KÛÀª\%e#»5â篸ñV½E­GtlüÇ”Í  ÙGŸ^‹ë¤_0�þ¯nfͪ…,)½€Iq:«çÃa[#cÂD²U›º“¢5ÿæ(^|ÞÊ¿‡Âa,'Þ¨…ånK2 BÑ.ÄDǰtÉ2õŠc;èºNîæ\úö‘Á¨âä2 ƒ¢²+6ï¢ò(UUQU…ÕÛò�ü¿ãؘF#ޤrL,ÓlÜLV5k7KWÂÆÅ�knd\‚N(T+S öî£âÔ·Ú0­i.”<“}{vRVámüàCíÎȉ¼ýéFVo 32?‡]–�s‡ô¢r©Ñkp}MÎú|"%kXVH˜0‚>Zcò�'9A…ƒùùùØÄQ7™}0�}V�[R'€”±Lô2kV¬bÁò2&ŽÍeî·EØZMÈj\Q;‘ž¦Á>‹ýy°It€ÝÛ¶±3w yÛ¶sÇwÏn8¯–”Ŭp…„¸¶Uç{c7_ÌX[¹™QcïÝ’çÓ˜´u¯!ŽAƒ»£a³oé2võ¥³)Ø´Œ5yåXµ>×È1„h'ÈÆõX¹r †«ó½G®ñôD?·Iîšõ¬]³Žb'Ša#ûájL}”TzfE£b“·.—¢ºÏ×±Ù³r%{¬õiq�'�ó'ÃOˆ•‹×P¸æ[;¸ûMfRz#–J<e as`åjvšuÓXlyë'L™z)S~ó…vk”»™m¥d@*„¢]8w̹lܰ™gž{ŠéÓ§³rÅ*öîÝÇØsÆžê¢ !:¤æ÷¨o»l«Þú1ëÿ{Þ¹‡ÒÒr㣈� PVVÁ–�~Ζ�ÁÆÆW =N^-(‹šLçT0Ùœ³�PÍïÌC|óÏ¿ðAY q*8ábŠÃv=÷­{ï–<ŸÆ¤­û=t�t9#¢¬�óÜû[k×}÷ç<ñ»G¸ç–ŸòÂ:½ÖwÞì öÙX?�¹ë¨Ý1(áhþJ\?wU ¯_À'köcû1f€»‘õq1hì(âT=çþ»¶ §f¹ö~ÁKnÃVëîjÔ²:�Mìè ŒŠ‚Šœoùïü¥9†L>�ÔF?wÈš8•�>kǧ¼øùn"5Ò˜æòÖ{°ð2hìÙ$(­Qî¶‘¶—™Z!„g¸ì~ýéžÙ“ßs[·m笞=ø¿¿ÿ�@Àwª‹&„耚1QsD$!‰Í˶‰ x‰‹ PVVÒöåQS¹`ÊP^Y¿ŒýŸ=ÎÏBSVzÁNV-\HŽq�þålfÞùg„VóÞËcïËè±ý¨yjHÍ!B}Û斿¾´u‡¤$OäþŸ,áŽÇ²úÕû¹iÕ8&ŒÈ$É¥sxÇjæÏ_M^ØM×Ë~ÂMƒÜ857vŠȨ¾næ,e‰)$C©‘·šÎàÁ ðÑ2;¸‡Œ`hTcëåà=ûÜ8xϬÚÅ{ý”mãÇ2¤‹�Ð�M,Z°Šðèï0iíû|qØÆ±[©NQÙ2&–ù_~͇_™8þ1\46�úÖ½Ö?ÌÒ.ån_Â=Ï-gé ?ç–Åc9§oZÑ6¾]°Œe?ü~2%¨Z—ÚÒr·� !„h7o½òò©.†âtÐ’in—†eƒKSq»´ÆåÝ’Ñ_•Ô©òÇCä�ï¬dì·Ù0 ÕOÚ°ïðç_ÝÈè¸0©× fÝ«9äÎx™¿å\Í3cúÑ»î}ë‘6u2ëDiúÞ²é4éw¼šò.Ͼø>óVÏäÍUUß)*þ”�\vûmÜ}y†Y'Û†�ÈB[µS‰fÐà³Ðj] Ò{àüÍ£ÂvÑëì!™@mL•œ4¾û¿Oà<õW^™·ƒ3ßc ¸ãéwñïd”K!D[¹økú vª‹!„­Âqœªq-¶mZG�ÞýZ-ï×fnâ…w¾à®kÇpãE�ÙlÍ…/& —V¨”�ќËëÇm±k×Êl/ ]2Ɉ=Æ´4on«”∗øX £"Œåíwƒ!TæÈ¾<.?QŠ£* Qw¿žãWçDi]x££p«f°”°Y§&./¯£x/»÷rÜÄ$§ÓµSª&¢×?R½Ñ¼•c3TJ¸ÎsTÜ¢ü•ÛÙá2‚z§õŸ‚ص·€ QtêÖ�T�A8bኊƣ:ÁR"­T§ÊÛÜ(€c †ØÑ¶¡Ÿee.¨n/^¯JÅÁ<ö”czÉè–F¬¢‰ÔŒ¶R¹c{îFzö€¦i¨ªŠ¢»US·{_ z *3¤B!„BÇ�¯Â=׌@�DÐ#�9ùÓ$ÜŒW{k³1#˜Š�´ÌtÆÁ±#ƒG§<­H9–¢áw™„+ª§4‚”õ)DEi¨ž/á„iM"å%DøÖ6#„ÍŠ'�®YI(88Ž�^Q~ÜÛÚ‘rÊÊ”ÊÁ\½um,ÇD•�Czf\e¹jÅ£——ÐÐ>ÊÍ­SåmƒT”6¢|Ç­Ÿƒm„  Å¤�Û ;RÎñ~R-)w[�©B!„8í´æë†‘H˜H£¡mı±¬ãÌü9-9uõärŽW—SåDÏøxIÛA�»IóÝ•iÚA¹A¤B!„âtät”!šg69öE!„B!Ä)!R!„BqZ¨oó!Ä©ÑØx”Wv…B!ÄiEÕ4,ËBUeîEˆ“ɶí&Ç�D©B!„8­ø|ÂÁŠS] !Î8áP>T“ÒÈ€T!„BtxÕ¯*ŠBlB"E…ùØö©ßATˆ3…mÛåç›�X+OD¤B!„â´ ( ªªˆŠÆCî†5”bYæ©.š§-Ë2))*$wÃü11¢¢QUµíÖ�®\üu“ )„B!ÄÉP=(MJNÅãö�p{vmöš~N£âÄTM#::†ŒÌÄÄ%4i0 M�ö4¬ÉB!„âd¨îkš@l|"ѱñ8Ug’:r6©­ªæ«¹ªª¢ª*š¦¡(Šì²+„B!Î<5¥ªªbÛ¶ D…hcÕÒê�h›Í� !„BÑÞÕœµ©Ù1–�©­«f|5e#£šd@*„B!N;5;ÇÕѦv”…�Ó’Ø’©B!„8­É@TˆöKŽ}B!„BqJ´h†TÞ糓ýÛT‰'q:“Ù !„BÔ§ÉÒú¶Í–Ž´8�TwœÇiöâìÆ’x§»“OB!„èxš4 uÇq(/+¡(ÿ0ápH§%UÓðù$$§ ´~'ZâIœ)NF< !„¢cjô€´ºóœh?å¥%tÎèF\|šKöE§Ë4)).`ÿžÝ„C$wê ´^'ZâIœIÚ:ž„BÑq5ª÷{d&§´˜òÒzgÆqtC=ÒÖeâäS¢câéÝ?�Ü «ñùDÇÆU}Õ²N´Ä“8ã´a< !„¢ckÒ iQAi陘¦!ëÜÄéÍq0mEQHKÏäð�ýDÅÄ¶ê ©Ä“8c´q< !„¢ãjÔ±/Žã`Û6áp�@ �gqÆp ŠH¨Û¶[¥íK<‰3U[Ä“B!:¶Hkîj[ŽüF[œaEÁªÑynI'ZâIœéZ3ž„BÑñ5}ÛnƒbÑ~µi‡YâIœad*„Bˆšš~i[”Bˆ3”Ä“B!„8“5z ©¢ubAâIˆJ B!„hÆ¡‡Ò�h4½ŒüÒŽæ'!!ª9»ý8�êÒ®œñ$m£íȳB!Äi®éý›ŽÜÖ‹Ù•›ËÖ¼C pù‰KéBÏÞ}ÈJòÒÚÛËèß>Ë÷�‡Ñåþùêm hÕÞ¤C¤p'7ï"ïP1†�æ›Ü™î½úpV'_㦿I_òw¾ÿðW„Û¤.g°öON9û¶î§ÄqP�è™Ü(ά¶!q'„BњΈ5¤VѦ½õ:o±š½Aû˜:(ª�Ô�ò½ë¯çêá)¸[龎æÂ¥ªØ.ªRûÙÙÁ|öØÄwîDL“~ Áísø×?ßäÓ•û ÚÇþDÕK§S¸õÞ[¹¸§¿UÚŽªU棨(tÌvеÇ稯ÿ7÷Ý÷>y6¨±ãyôÍ_qaLí¨#µ ‰;!„Bˆöå4eסlÃ;üîá×YV`á(>:õʨ!½è’àG —r`Ç:–._Ͼœéü}í¾üîƒüùÇg“Ü ÓžóÇ׋Û Ö9ºŸªÅ¶wÍ-ÿ‰âž×ÿÊ5i�¿YxÓ[üüþ·X[áàOÆ“ÏapVgâ| fy>»6/ãË™‹Ø²æSþôó]”>ýG¾ŸÕCl§�ÿ-ÓÞže�eÓ¿bŸã&:Z£¢l1Óæç3îÒäãÌüu”¶!q'„BÑޜ֯ìZyÓxø7¯±´ÄÁ“1ž{º�k% Y6Ž( (”oå³çÿÀ_§mcã{àAßüýG}ñµ´f˜�YÏçN)›7íŦoe'¿±ÏÔ>È´—Þe]Ä�¼——ÿYnÛvªê£ Lº‚¯û–Çï}ˆw­á•g3þ±©¤¶t€]·_Ü�ÚA»ÖΞ£S¸ˆO¿.Âñ�âÖÛü¼òôÿ+ÆÅ˜¡0VÝk=]¹ä�gHóÝË}ïï`Ó;ÏóîùOsC–V™Ué>¶(Çñ&‘•™„÷˜{•±wÛ~J/)™™$W]à”ï'w_Ž;‘îÝ“ñ)·³§`‹sM'Ä�í¹l,Ñð&v%+Ùwü×ü"›X½)‚£ÆqÁ5Séê„Ðõº=œ»ïºŒM¯ï¡sºJ±©Ç̒ݬ]›ËîÃe„/q)]é7 /™q͙ٱ ÚÊÚ�;ÙWÄÐ|Äwʤÿ >t ¯WÞ´tNÙ>r÷—C •³2â0®gÑŠ­”øû0n\_Z{!ðÅfïW3X„À¹ã™<)šÜ׿3=w36_ÍýùÏ…YÂŽµ«Ù°»��C§îý‘Ý™ã5ƒ¦´Å¦Ç£Ä]KÓIÜ !„¢­4c iÛýŠþ“O?áÓiŸÕû�ªª¸Ýn|>?.We±mËB7t&M˜Èe—^Vëzkû Þ[Q�£Æ3ñλ8/&‚qÌH´Šcaè†Þz/—-ü>Ø¿…�>YÍ5÷ ËCùârÇ㋱Ϻ�ýã:zÖí¯…–ðìOž`¡•ÅMÿ|ž[zTdõU¯pç£ó1º|�¼r+ý]:k^€û¿(«zŠ[øÏC?á?¨d\ó$oÝÞïø?Dz*§vÛÄjhµ«cáõ^?OűL ݨñº0 ïcî+OñÜ'k9¤×þy*ž$†\~'¿¼å<2<5²¬™}�Và”¬ãí'ŸæõoòꬭSPŒ¿ù~yeou:­ÍI§¯y�»ž‹9è.^»µœÇ~ù&‚jê•t?¯ñìW,­OF(�ÍsΣτ¯qû3šž�¹•é36Q¢9òhb}.¦œ—ÈÌO÷2sæ*~ÔoD½o T×@QôÝÓyøÑ2'/|´fŠJl¯Kxà‘;—ªÕNÜä¶Øœx´$îZ˜ît‹;!„B´íªñé´Ï¸â²«Ø¹s'ƒAÂá0º®£ª*O>ùW4Í…ªVö@Ç¡¼¼œ_?ô«:R›ÝK–²Ç5å|.íÇ>áyw–»?—MêÊÇoì"Éb6Ãê¥ê~(Zýëèµêsµfç¯FºÊ�]œuù}<Ôk oþc;É`ò�¯cT¼FTVƉwçôeÑ»«Æ‚m%Ìû}.ëû}²£ëŸšp¬áP}_1ÿ©_òÈìÃ81½¹â¶ÿÇ”¡]‰§”]«fñú›3YõÁŸùY…›—~1šøÍ|Øûøè±‡yqEîŒs¸ùú©Œèžˆ'’Oî¢xåƒæ¼ð®”xhlüÑ™¨f¦S¼>¼ ‘<>~y6;b3yrâ}IlÍíM; }k ¾ó(ö­¹ŸÌQÿirúÈš™ÌÜm¡&œÇ%#ýàÀ�‹&�>íöΟŢ[†3!ö8 ÂÜÌë�~ÄÖ„IÜsÓú$¹)Ùñ ï½ù)9¹ÓøÃïSèú̵ô¬þW§™m±éñ(q'q'„BˆöªÝ­! ø|>,˶+ç4MÃår¡ª.—M«z•Ö¶‰ŽŽÆïÔ)W„[ó°Pðô@Åi\¹è>p±ê.ŠŠv°­ÀfhªRwšâؼ³ÎË•”ìq\Ü©”é/Îb'‰ ¸`—t®œQ±êÙ¹³¥;WÝ8žOžÃáœ×¹û¦o9ÂxÎ;{(C³»‘ä=qÏ0²æ^øò¶–Åõ�?Ã=ÙnlÛÆA!«×FõörãÏ>bϬñÎe#¸½w=M¤F­Í3ù`u9¶Ö“þð{nÍ¢rm½0l$™ú�ÜûñAæ}²�;Æ\JŠÚ²t(.4ÀΛ˜ô«yá�Ûàwp S79Ñ#lwZ©¼Á¢åÁ�ô™2�µ3',\N aDÊQÆ¢ÏçsØVé<á"†x*cFë=‰‹²Þç¥íK˜6?Ÿñ—¦48€³ö­býÐ{xýÉ«éªXØ(CGr~ÿ(nºëßlÍýˆ÷–_Áƒ£*çY›Ý›�wwB!„h¯ÚÕ+»ÑÑÑDGG ( ªª¢ë:n·›üùóXÿë‡@QóÚkÄè�¢(hšZ»\v1ùE& ñ©Ix”Æ—ZIìDŠ EV!ù…NªV#­sÌksÇ:zEÍtÕOα lëè¶¥c�Ÿbˆ;ïøû¯ý<òÜt6nfÎ{›™ó(îh:÷ìÇàAC9j£d£ÕM­“3wûmÏðïpmoÝ0Ž~m™x\Ée½?ãùM{Y°p·ôî�Ö@]”×ðäk)*qÓ%Ã@¯™�¥ÐodüŸ ´g7{lçÈîÅÍMç( `FþðZzi!‘F?¾v§µâéÐÖ§Ix3š;�Œ�wphë3tùF£ÓÛ‡çóéârl­;Oé�æT—,ƒÉgóúóëX=ã+vM½†îušë‘¨‰L¸þb:[aŽ,±´ è9•˲ßá©5%,[ž‹1j ®f·E§Yñ(qײt§[Ü !„¢ýhw/[©ªŠÇãÁï÷ðûýøý~¢B!–_=£Æ: ªóí ?0¶ÎbÆ&£þ,ÅÕ—a½ÔÚë&œxzõJDŦhO%mÒÛ’Ä]‰;!„B´²v÷Ê®ªª¨ªŠ¦ihš†ÛíÆ¶,Ò>ûŒAcÐ"6z¹‰;6áH…º¯Õú ø+W?+BMê<9ÁAP||ʱõ=Ñ+‚5ÿÞЫ…'Jüba"Jƒ'ÿ�aSoDStm[Çšœ5¬X¾˜K6rðð>~úrv<Ìsw #NÌ"ò lÀErrJ½÷UHLHD%»¨ˆbêþÚ¢Ö3p°+ö°dÆg|þMw4‚Qç>µÕÒU•Ò—H’ïØÏ;œ”?RžKþÖg)Ýû ™Ã~Šc@uŠP�îCÆÖ9cˆË¸’¤ž÷â�îÝpFúF¦ÏÚ†‰—Q_@çºeŠ=‡KÇD³ä«}Ìúb57ö‰¿žl”¸N$»ë¯S\|*±ËJ)³!Éj‹¶Xã³úþ.qׂtU¥<]âN!„íF»ÚÔ¨zW;2(UU•¸+ÈÒ‘:°oïgí�"ÊÍ-¼ã®ÜŽr@b%W\EÜàÁ•™¨ÑtI‹B¥˜ò={)´‡5ú<ÀȾ<Ù ¸ÓHOiwÈG96–Á2bÓûsA·ÁŒ¿òFî/ÛÌû}˜§æîcçg/ò­·˜Gvv»´�ºÐÜ•ÍÂ1MÌt<�’U<ÿࣼ»5 ÞdúË9ÉÄú=¸\.”ßðï›·RºjŠËÝþïIbéEØð;ÊAbúPúŽÿ n_'ŒÐb<¾.8úz’ºM%&e0‡w¼ËÎo/!:y iýÿÍ“pL~Á3™µßl6¿u?×½S÷‡®`•ë8Ø.˜Å¢›F01®žÖãñ4´ÿ,.OU›2¬ª6Õúmñ¤�¸;cãN!„m£Ý­!…£³¤ªªâ.)!eölÞœEÑ—QS5ÆßÜ¿ÖõEKXóó_0vÎìªO4ÎÐ÷ôoÑs—³¬ä.iÔAy:ëW®#䀖5€ì˜zŽZ¨ï Øv�×ë[CZýyÝÿkÜ*¸splÛ6Á<™\õËŸ“»ö>>¼—•9°zwAU¼ø«ÎE ‡#ØêéÛ„B•Gv(>Þªõ·õ×EgÍÛÏòÞÖjç)<úÜLIÓª6I©ÜÇX~˜fVvp�§«;é|2ZcÛjN r¿�?:…Ì!ßCQ=„Kç`Ýxü™˜jå/iŒÈ lÛ!!c,�„ öošNîW£èqþ,<�ïä:EÌ›ñ E¶‚ê‚`áA‚ ÜWSÌòeL[pˆñ—u:ò¾ÿ‘D"DœújäŽT¾ê«ø¼•mªÙm±%ñ(q'q'„Bˆö¦]þ²»æì¨ªiDÈ_tccîN^JþTpäZEU°zGAR÷9(Ä�º€³‹ù:¸’?ÝÆÄ�E=gÔ×bÌçƒù…ØŠ‡ì çÓU©ÌKQÀ±,¬zzbvi1ÅÇ,œkm:…;6²fãVŠ;�çò¡‰ /v, %�ôd;„"UgBª©tIÓà€Éþ}°H¨§XÜ_jÇ�$¶v³tå!l\ ¹æFÆ%è„jyáP°wuŸYsÓ ²'ÎfÇ’³wãħv'6ítŒÈal+\¹#ª;UóRr`>ù;£¹SÈžø_O&Ž}´±Úûæ2mEGíÌž{‹_ ñ4pW‹Í/ÝÄ_ÙAÎ̹ì¾äÚc77*=ÈÁ°îºÃ-‹ÂCùØ(¸“’IRšÛOv~ˆìàƒGþ‡GÞYƾ°]çž&%Ûçñ�ßÜÏSKŠp¼Y\ó«Ûá;z�«K&Ø%Ë™·¶§FzóÀ\žûÏzl­zVèĽ8EÓp)@ÕÑ2�{6ÎýÁwèécÇûüîßaù!½ÞkõƒKyõ�/±°ÌAMÇå£(Uåé9ùRúÌíŸñò—û1k¥�°íã·˜yÐF�Í•ã«Ò5Ð3V“霪&›s6ªy­yˆoþù>(K!N'\Lqõ³onº6éŸêtÓËbÛ¡`9Q)1`Ê2zŒy“}?ÇÔË1"…áCì[ÿ>Y£ß`À”eD¥\D(XŽ]wYôÙ{°¦N óD÷NÇ¥Ã|(ö~fÏ\M°ÎóQœæ¾ý!›B5?·)Zü!Óv˜(®î\06£Åm±¹ñ(qמâN!„¢R3Ö�žÕ»ìz<4Müî:V?ñݬÁ¸ŠC( †!¢‡±l Ó2�)©©�Å-ùÚ£à•yÌû×Ã,x+�¬Þ=é’àÇmUpp×V¶ì-Aw´ÄAüè¡Gùñ7F�w•nçsQßÿ°eÝ>{ì~ 'žC¿$7ÁC›X4/ßU·pñÿàã|Û>úŒêéJVŠéJ÷D•¥öóÉ“�Q>4b‡sËÿI|ƒK]Ô?àO÷çqß_¾"oÉkübÅûtîÙ‡>ÝRˆñ©Øá2íÙ†-)·@�Ì­�ÞÉh?G_mL›Ê·Ë]Ï­`ÑÓ?ç®U“׿3Qf!;VÍgæÒ=„´4&þì.ÆÇ8G¼¯·.j*LÊ+ë—±ÿ³ÇùYh*ãÏŠB/ØÉª… É1ÎáÑ¿œÍÌ;ÿÌ‚ÐjÞ{ùcÌá}=¶_³ÓÅóT:¶–”ß0 ÓÀ;l_Jöƒ?>‰‚½_â‹ÍÆ;šŠŠòï\²ø æØ(þá\vA2'^Íù�æù¥s)\8‹…7�`R¼‚ã8Ø€Úm\sß=›¹èÂád%ª”n_Âô™+9à¸è2õ6®îÊÑ]¯›Ù›�wwB!„hÚݱ/P9Cêr¹ðù|¸\.¶mÛFF× F¾ö _>ö'Ü¢8û·¿¡¼¢‚p8„®ëõ—˱0½ÙÜü·×¹pÞ¼õÉl®ÍcÛÚel«¾—ê!>s8S&^Ê÷¯GOO˜È1[\v滿ý ‡{†×îäë�wò5 ª¿3c®{‚‡¯ÑxkžŽNDw( G?×úóýÛ'±øñYìÞ¹„Ow*x‡eò#›ãÏY›6©âÍ~ãx÷í�˜¾h-»7¯`ßæšO%Щã/¼œë0…쀎^s¡�]¯|Œ—“ßàé—>ãÛ¹ï±é«ê´’û]Ä­wÜεü˜F�…x Œ®S§>Èý‘?¾³’ ³ÞfÃ,PT?iþßu#£ã¤^7˜u¯æ�;ãeþ–s5ÏŒéÇ f¦ëÓà(¿ƒj…ò[¦Iç~¿dϪ»‰MI§¼ „Ì¡Æ2ëþ’¦û0sg,¥ÌV‰3…óbh·uF^Ìø¤ù|œ¿œéó3áòN˜Û5®7>ö]züí þõæ‹TT�ªO þwÝ6Œ€m½MsÛbsãQâNâN!„펒|óŠÀîgo?æÇq°m˲ضi=z÷k³ÂÜ~÷�ÜuÇ=âñ¸Ù¼9ÀËÙ£F]¹™‰rt*ò,tCçé§žæ©¿üí89+¨n/·Å.ãPÞ"þþÓ?33_!ë†òŸÛ{¡:ºn`7ÔÑRÝxý^ô‚=ì:XŠáŽ#=3�5B8âà‰ŽÆ­ÚeDª×¯¹DûÝ`G•‡±jeÀm‘w°¢èœäà ë�êç)ª·×ƒKs¨8¼�ý…e#Š7†ÄN�é’àÁ1uŒˆ^ï¦/ÕÏÃëU ÜÞÃe誟¤.Ýè§aEÂèf�]a\¢õÕEÅåõã6‹Øµëe¶—„.™dÄ‚cÚ š7 ·UJqÄK|¬†QÆjn:—Ÿ¨€ÅÑ •…j=Ó¶´=w#=û8²¾¹f;lжŠ'—ËÍŽ…S°Íݨ®®d��…iÇI¡âÄàu�c †ŒÆ�1Þ¨(Ü*Xá2Bº�âŽ"Êï+L0háòù!¸Ÿ�{ ¹bHëÚ�dw„HØàؽ†šÑ¡yñˆÄ]{‰»ÖŠ'!„BtLÝî}�ê1h»ÚeWQ<ùè¦ÎˆQÃp»]è†�Q\tÌõŽã`Z&‘Hä9Wj6€Bl§sù΄ÎÌzg/»¦½Æ´)2)ùËimƒH…�H&«G `c›„ª:ž‘òŽ)…¤¼�1�m‰(~RÓ€ÝèN1€cè!P£ɈN¢jßQÛ T®Ÿ(l#LÈ5¦Y±©UiuB m±i)/­·&˜‘ LÅGZf:ãàØ‚Á£/.[‘r,EÃï2 W-Kg†¨( !j3Mƒ®ÃžeÃìóÈžôñ £6F°„]u Ç<¦­;FE­v®‡Ê@�%#+Û.'ÔÐÁ–Íi‹Ð¼xDâNâN!„íM»ZCÚ3«'ÿ~û- óX¸ð릱m›«®üNÊåàØÐçê8wæã|]ø-O>òÆßåÜ^ñPD�K$º�'ãØV=³<ÍäØ Ì¤4%‹–•¦ÕêãØXÖqrª÷|ʤ;M´fÝT/ú^ø9Š¿¶u²æŽp¢Ÿk½IšÞ›Õ~%îÎø¸B!DûÑŒ5¤m×MùíC¿Ååv79�  78S/'þüÍ&ö?ò1[·Ìàñ_̨üÂ=�Ÿ¾òW÷ @!ZI+Æ“mš¸¢‡í¨B!„íH»ze7¬8y7³M¢‡ÝëoœÏŒÏç±r{>A|ÄwÊÀXYÏ$:&Œ !„BˆŽ¤QÒÓuÃ Ç aÇöã’ æ µ²ŽŽmgSq¦k�X8]ãIˆ¦’XB!D“fHUMò,Tõôy�Õ±ŽnT"D}lÛn“6:Æ“'ÒVñ$„Bˆ¤j‡]븧ïÃç >™¯Õ Ñ„CøüQ­ž¯Ä“8µU< !„¢c:ဴú•*EQˆMH¤¨0»…;L ÑQضMQ~>± ‰µb¡¹$žÄ™¬µãI!„_£fHEAUUQÑø£cÈݰ†’¢B,K6P§'Ë2))*$wÃü11¢¢QUµÕÖ�J<‰3I[Æ“B!:¶F¯!­îD'%§âq{È?¸�=»¶�úó…hª¦CFfbâZ½ó,ñ$Î$mOB!„踚´Ë®¦U.>��O$:6§ê E§ Ï&âd«ù*¡ªª¨ªŠ¦i(ŠÒª»ìJ<‰3A[Ç“B!:¶&Í�Be'ZUUlÛ–Ž³8­Uw «;έ=C OâÌÑ–ñ$„BˆŽ«IǾÔüMwÍ΄t¤Åé¤fÛnË�W$žÄ™àdÅ“B!:¦& H¡v‡¢ºã,� q::íZâIœ)¤] !„¢>M�Ö$ !Z�Ä“B!„8Ó4êØ!„B!„¢µÉ€T!„B!Ä)!R!„B!„§D­5¤Ý~òbÓsp¬Ö*‹B!„BˆŽDÑZ”\fH…B!„Bœ•3¤-™åláˆX!„B!DÕÂ7fÿ?Z»xxdEÌIEND®B`‚Solaar-1.1.20/docs/screenshots/Solaar-main-window-receiver.png000066400000000000000000002222011522022367600242700ustar00rootroot00000000000000‰PNG  IHDRQf½� sBIT|dˆtEXtSoftwaregnome-screenshotï¿> IDATxœì�y¸U™ÿ?§ªz½knnö�°DaQ‘UpepTÆÇÑqAG�qÆeÆAðç8ê8ƒ::.(*.¨(*ÈŽ€a HYÈvonîÚݵ�óû£ªúV÷í¾Kñý ‚ ‚ ‚ ¥ƒÙŸ½"í~h»Ã°'‚ ‚ ‚ ì¨îK¯4ýG½ê@÷c¯ó­Õs»""JAA„ýCçê_D�%”öt_öŠé+¿_=8òå°'‚ ‚ ‚ ìD"*|þºòA­;_v`Ûì‰ ‚ ‚ ;Ñš¨çñz(¨[Ïõ<‹ ‚ ‚ Ïmbw¾ç·ðH»ó -=íöDAA„ƒ�ƒÎ�/¿óÉØAAAvƵD•g9~iÀh”ôÔµiR@�s¯ªAš©¹ŸŒñ|·ª ‚ ‚ {Æá/|iõ< 5¶mU�{ÊxåÓ÷ÂPŒÛV£ºJ»Ù¹u åáAìÐßï㨯§Y½õckT&�^bÇæ§÷Û8&S¾YŸ§Òv£÷шØÕ,CÁ£C¬r?„èP l0!(+.—L*BFÇ× :ßD+©0Àd èB'XNÃLiw¾Ò¼c›ŒEAA8˜o²Ÿ�¾n4ÉNS/�êïÕOÌÕQ_Wº¾ú }2'Ÿh�ÆàU*Ø™ì„ãh6þ‰ÆÖì%˜”gÛTÆÑ¨ýF4z~“ís:O³²�Ò›k¤‰ÖD™°öZØÛP•¬¡§!ŒÅOÜ9K�-£TœžUÉ!NS*NKD›]k�Á§ˆÉ-DfvÌCƒ±3¨ÐÇØ™w¾–Í4¬ ‚ ‚pðR¡@íd¸~rœ¾N„G3š‰¯ú{Éùxb`Â<~¹:'Ÿh�γùB²uãhÄÄ–(¿Œ 1…ÙMó€A�T°*dŸ&œsÞ¼YØÛîÅîÙM8««�µ ì݃ æàu–;Bþ¾Ûe f´aZò�­^Æ`Šy;°Ü!ÂbW�;_çêÆé§ Âó‹ŽimÌÌ&¤¯o˜]btAhˆ«-©ëdÒ\ Ü ¶S»}N³¼õÇFùà Y•>¯§Y]P;'O�#™è‡A€S'š�7kw¢rõc™lÿ3¡‹ë㎣Qù ꟣Óh[£Æã¨OOÊ'džckp?9fMÀ®ã¨gÜÀÊh”ÑŒ]ÿ4v=Töé­Xf!þ‘/GaÀÎ`Ú–àô­DOó1¹Lmݾ‡Ý[�Â2ȵ`œ,þò‹p6Ü…Ý·�Êñ‡�m3e‘RJ£• F׺óÉf»‚ l¨^÷W¯åª#,Ð}\yÅO¹â™}ãb"‚p0áEN*�Æ™Ä�tXîFTŒMKFÕL¼ê¯ë뛨îÑ:|ìÊÚ ©=f©º·Ò¤ž};žj}®±ÉZÏ+5ÇØŽS3–œ“ÚÊÎÖŒ=-„’£ƒÆq,ˆ�n“1$õ7zŸné+5ŽFŒâ¼+qâÐ{ºP@©iX¡‡Î£²Åé0<»¯‡`vÊeÀîÆò: »çV÷{ÂhLKÆÎSe¢Aƒ+t!p™öÈõ£É™–±yAžÏ¨ õ)lP:@Mao A„?7‚ ÄÙÃÈÑ:ð±âàyÑÛ+cgòÕ|Ihò$o³:Æ#ª#ÀUY,Êcæä�ÆÑ¨î´˜LÛc“ +XNfÒ}� “‡ }”]ÛnØ ŸËQ´4Y;)è²#UÎ+—°,E_‡A@{0k+¼Ð€cáºi{é´äê ”ðŒ#Ms[YòtŠ?ÁÜé8�¯�ŽXJa,ãd¡mÎî¶2¦­å.Wpz5¦íP‘ÂT¡�òËØC�Q>zv”nLc—> `0–…±ìw¾®2Ñ�AA„ƒ�²V`Eá´C¿‚R͜ғˆ ]‚%gVãSì@õua÷÷r`[Øe,·�`Vwµ c9d6߇· SL,QÄNÑ(bŸú‘‚>AA�(:[ød') tT…‘üÚë$ �¥"Qf©j4=“Šâ–”I„›1aÃcBr]'Á¨(¨K2ÿ5F£bãÃh{)1¡RáØÍXo¥,Ús63ó°¤-êËö²aGÙ0B$:’6¢ý¯¢úµ‘Ôú.JY£GŸKÝ®¿ÉûÈÕ‰¥ê³K?Gm°ð™ž…Y…,KÛm¦ç(ÅpÅgk6K¾²-€¡ DcÓjû,îÈÒ™…¹y(æl,¥ØUѨPŽxôÇ1P¶ãÔˆºÑõQþ¤Ã¿�+¢FÅÉäö„ »:aóX#»0-]Qye¡gInÃ-ä6®ÃX eЇœ ʪ¶a•úÑÞÓø³–�íGõ,²@¥»£Œ®ÙlWÜùAA„Dhøn™LluHDQÚš”„Ķl§z_×¹q¥S£vÒÇ(®[ócµÎø:ô=pr˜òHÃú«ÂÆ‹6‡Íäò(ËÂöF2…j>?^/”Éåã>� )eY´80Ëñ˜SÈ13¥ÛF††/*o;ݰ¼Ñƒ®žW‰µ›n°þHÁè}m°,…W‰\öœl~Ì&ÆF‡ä �K3=ç0-gáiù sñ‹Š‰Œ™–¥* ZóZÈZ mùŒ�Gl´^-í_¿¬^ Ö3¡%jJØ6•£—R\y3þ²×D¡Ê-“-àò2” ÁÎb¢xèq�=0gÝï)Ÿ¼xlxó*£¦(£"ñdt¡'î|‚ ‚ :Ð:²&…¡_H~j­ ŒÝë¨ÑCÉæ­Éy£ü�6xMŸ×ç©?V©³D¥Ç„^í½8Â\€�­uÍäßÉf«b¨^d3sÚòÌ.Úäc0=oS 5Û†½¸Ïµ� ŠºW ìjZ"æêóY„ -j‰u/ÇĈž‘_ó¬Gœ ymP�GXx™ eŸJy;K^EÓ™�úÔ‘µ"•s®ø6t2è  â‡”C°ý ƒ�E^…ã¾'޹0㋨ÐíObMÔ(&“ÁŸ™ÁÞ¹–pö2ÐÊ¿JG›ã!d[09 ì,ö޵³³èB¾Y­5Wª®;âÎ'ÂþÁaÁáK¹ø¸…œ² “…í9Џ• ;võóȺMüâ¾õÜ»{"Ó¿ÅŒÅ‡ðÆ“—pú!Ý2-O›^¹Â3;{Yùø~|ÏS<8¸—Á"¬+Ž9œ‹��ÏIó;™ß–£`*å2[¶÷ðÇÕë¸æž�¬û=¶ïëRyÎ8ç.šea‚�|ó‡kx$ÛÅÅœÌ_3‹Eù€‡÷.¹¹�É9N‚ ì_š «F÷êÓÇË[Ÿ'}´� NXÁ¬ Vœ4ïgó€‰À©O¯‹ÐΑs,ÚbíV yGQ´M5O^�~U­5©`ç�"ö¥Óü@Oz�7úRÿü*^HŸŸe ´q|C%þ¢ÈX 0Ìél©Y–·C‚¸•(û „6åÀÅ­D‚(¯Â1m¥¯“cE[¨0œp“°DYgÒBÇä²P­Q#½XCO¢Ã^”D–&m£ÔtLË!è–™à¢;Tƒ €I�Í6ù�î‹;Ÿ ûUœÅ{ß~.?ª�ܘ� v�;“}8ïzÅÉÜøóßñÞ?ìd ÑïM¹é¼é�çðo§tÑV_OK�ÙÝÓ8áÈÃxç}\wÝïùû;wÑØ¡c|²3åsso™ŸkÐo)0§»‹“Ž:‚w�·‘Ï~í÷üׯ©£ö¾©Ëæ�#—ñ¦e6øyîº~#G¾åU|ùØbü­bXÚ™ÅQ‚ ì;BÔ¨õÀrtLêÔ¤5+Ÿ0Ùz›ÃÀ¯NÚÇà•«mŒ7ŽF÷’47Q„ØžF9*Aä˧BŸ ±¢ T¢15uŒWw};YUï´8:Žôóšh\n¥Â€¥éÉ+rdÉ�Édò£o›\2…¨ï¾«"«-£ðµaØ Ù6Ta`Ä¥œz´“yÿB&¶CM&°DØÀå{(m"“P=/9„™�„‡¾kpj÷#xss„3€c�ÇnßÕ�³ùl}$á¬åd×݈ž1„Îå@�R&òÛÃDÛ‚|~4bŸ1U ”¸ó ‚°OQ-¼îÍð©£ X@¹÷~¶rì¦ß‡|K;Ë[ÂEÇÎdV¦�—_|ÿ9ôc.½o„[’ÝÁ[þú•|þ¨"¶‚p¤—ëïxŒß®ßÍ6Z;§qòŠðÖã»™–ïâu—¼’výSÞr÷à”„…ÊÏãSï=›·Î¶PÀðŽ�üðÞ�Ü¿£Ä ¶™Þ=ƒ³^ø.œ›#7mŸúÛ3ÙvùïøIÕ·ïê ¨$ߤʡûèy÷Š"J»lz¦Ÿ­¾bd$œäŠ[A„)àÕºî%“õÉ›�7Ê·'õ§�–ã�óG¨™´Û^|žŽŠ7™þ¦…I^…´:`å#KÒô,tódmÃH ÈØòÆ£=—£»8êZ¨Ã�áx~_òMMÝIðˆ´XµÍò Œ3¯RÂÉd'õüÊXôûŠÍ.A¨YÜ™ßGËÉRO‹PC)ÐlÖlöé÷:ð«k¯Œ ½è¼Ùûp]oì80~`‰F±Ñµ¦ðètaØv¼o„QV`f¡‹\�7;K8cZ¼Ö)þºTáÌ.°Èlڀʴ g® »á)Œ·Y÷ë§ÞFåE/ˆEØè×® qçaŸbÏZÆ»WDÊÛò }þ�ÜWï¶vÛý\uÈIüàý'rJ¡ÈË/8šc«êG±àE§ñ/±€ò{Öò®ÿ¸…ëûÒ2k ¿½o ß=å~ùÖ¥ÌµŠœ{Ñ‹xíê¹np²½U,zÑI¼mV$zÜM÷sÑîåþšþ>É÷n}Œw¿÷">³,‡Õ¾„¿´›ë¯ï©ûÅpÖeÌè‚]UäÂ3f2mëjÞ~õÝü²G>³AØ?¨t(ë�ê¯ÓÇÐ÷°3Ùš²I„ºú²IÞúc}ÞqûjY„žGEe Â�´4ÈÆkW’ñ„¾‹�ÉUÏÓÖŸ1õª(ßô¬Í¬– -Ùh �Å<Ó³Qß|íãYYÚ26Ó•æ˜iŠ‘ö¡�O³cħ§Rò© §4é´$ú`™±ãH¿Û¶ |'“­FÀSÖhZú0lõ5•@c¼2 ¦·ÓêX`C%tè*‘ul´²i�]û+>Û+Š ý.}%�²¶|Û¶k¢î5‹À—H ¿n�˜d`‰Ôo…Zc—L_ÊÆX*ùCP “kÃ*÷aÂ]„Ý‹ê‘AÅ aWÎ3›±½!të,”[¨Yïd,…øh'ƒ½­'ŠE‘¸eƒŠ€¸ó ‚°/ÉÍëæp @óäCOò@“u?OÝÏ?ýªƒ÷Ï÷ØÜÛG˜aÔ7Íêæ­/›O»L‰ŸýäN~Ñ×è‹Uóô}wqåI ø�£²X-‹xÇ)üì÷“³F©,Ëç(8¸ýÖU�ûëïæÛ¿[ÏeGÉ,eqȲù,úeëõ~ª CuaOç… ¶ó/—ßÉ/{d“`Aö?iw>`¬ßpX{´â)qè{�ó5HKòÖ‘DþKGLÚ,�Š 1:¨†A÷ƒ€L�ÔëÖ£ñ5ÿ1ª­è0= óÛºóм‰¨.�Áó|*�ÊøXd³mÅ7|/Z\›3~ÓvÜ­½<Â,¬Î6æ(X¿¿êªcxÍj¾·C” Ï�GÎLåG‡NX!°›9Ûsœ°B@¾ÚNºM€À�Ä‹ \ÈÇ”µ&c|!2–AcפۖEÿrU0óZZ˜ßo¬C< /b#Þ¨€Èë€J]盼c3·¾Î°}pÔ5Ò"Ú—)Š\µo[Ö¨;ŸŽ¾3jÆF‘´uàc:î£eYh­«"'Oõ÷«uÔÙ…”iQ@âÚç»ø VÙ¦ëó}¿azõÜ+Uu‹ò+º›O6jDÊ›M¼ù˜nìNgé0Z.UI/Þê)úgâ%UºÑ¿¤¾ØLh(;²:%b®At¾fýA˜*î–�¬ ³N9�¯�¿€E¹©ÕѾpKc+¼÷ô6œ`ãú��;x2þ¾ÈÌíæ“Û#²ø5 hÇÜw}F¯jÛ"ÓlG‰}\hV?±­qà A„}I,LÊ~"P¼êщCl×§%×CaäZ6Õ®¦æ:©;9¯Ä.e e¯ñ‚qR_4)±eB_+2ñ~GžTS"¬‚ØJ•ÞÛHÇ[^¢&Ÿ¬BËÁs]tÊÂU Âj¹¤½Àw |Ï|·Ú¦ }ß­öÅŒÍN{líWÇek?î£Fk�­ýjZú~GÖ¢+oÓîhŠVˆ�…�E&›%�G�¬cSB‚À§h…´;š®Œ¡`EýÊÖ´�I -]çz©µÆó'Vb"w>VÅLx¨J?X ¾å ˜\+h �ŠËÛÔ*ŸxÏ'm¢b9lФ@É ÙoJ;-kÑQŒ­]�©Í~{†ÊŒÄSþ’²cÄgÛ�K_èà›;ô°‡J¹V$¥\˜X 6#‰z—~žQ8¡WólZrYf·æ˜ÙjW”“ÍcQûn¥DàŒ.D6A²Õ†MKÖfv1$ÔúK.�Vø¡‰ŸQ,¡ì,N8¶?~hªã°Kè–®¦ã™\t¾tˆsË¢|Ô¡‘ˆQ¦jTŠ D"ªåáU„‹ÎDæ‘yæ ÈXÓÚG×G�½k�ìÓƒ(g)Æ)`o»ŸòqÓÑùܘ@  Ó v­EK…á˜õX‚ û]â¶nàÔ;gòò“ç5Ç-æŒÅí´[€R§Íäü3frÞédzæ�wñ®kçñÔ÷�²Tõ£l̯p�$4ñç�Rc÷gjŠÅ’�˯޴„Ù` ƒ=[¹iÍí¦¯P 5A¨ñíÙ\ö–×ÔUp_Ö•"©Oa?bé+ˆÖà¤?ž’ÉóxÇ‚ñhimafÑavAQ,LÍ�»ä…löÙYŠö~jÖVý9u‚ÉÒA5ŸMóðëõ*êG8 ¸e6÷Wpâ_Ãæ´å8ª[ÓZH ©lŽž¡2«{+lî¯H=¥¨�ÉslÌ¢QZ�”ï¢Gûh+Só<œj=µ‚·Õ6´(Ÿy­9ZòBðFhËÚ`Ù UBJ•虢t`(NkËÚÌk…¾aw8`—[û¼5¢-ZRý bQ[ÿ>1¡%Ê }t½‹]6‡IÄy²ð)Ž'oTŽ�ßþ(fæaXö‘ä7®'غ œc+,_aéVÈ,Åg`õ<�7/OØ ­”(«žÔ ¶¤�'î|‚ ì7Ü��üü÷;ùùïï$Sìà¸Ãçqú²œ³b!ÇOË`©G�z&?´<ÎþöSôÄ—e7¨~rr™q�@e($>& 4¹ ßQ‡ño/ŽEO™Ûq#ïüí6z‰–‚ÍëÓQN÷c]‚  S¿¿iLØŽƒOæëÓU®ÀÌb†Ù­æ´:�æ–(?4dêLõ¥ìèõˆï2×&V£ø<}´ÇÙ‹(=Ž$ý8|­jÒ“vJ^@ ®QäbÄEmZ³£Â§ìz ¹!›û+Õ Õ`uaÔÇG•&bÀÓ t€ã8At´’µQV† ®ßrù mY‹¢£(d³„ºB)0„ZSòBžî+±Û‹ž÷´¬aqW±*¤ÒeÚ²¹º×˜´-qß“4'Œ,Zfšñ-Q:À¨‰L™ 6k |ÈLeA¾eÅ1.„>¥BL¡ œ|B9ÑNÍ&®Ï¨Ú�‰[_Ò\ìâg…>Ú²Ä�O„g¿4À} pßC�òùå9öŧñµ¿<Œ¥ż“Näm¿ßÀUÏDk6wô�Ò��Ŭi-Ø4óÀްÚZ"ñ˜ Äö‘ɹ¿uu/-Ä›">~ï»q½MŠZÅ㨹}Y— Â#^—ÖXo"w­0QÕ �Òé…œbvk†¥�µ‘àW°1Í„ߘªØ*:sZ¶j†êú�œ� �;fÒnÅîi®�ÓA$lêê “-ƒê¬Aõ×9e"+Khb¡R;¾D¼$b+ Q_O£q¤��VäëÆ¡â NèU¿“ö¢cüE’*×¢bßvòVùCÏ�Ø IDAT­%:Ÿ Ï>ºÂCw܇î$”=�“—ä«ë v>ÓWµà´ÌïæÐ ~�ÊÎ�Îañ'w°½—µ“Ú$ÊbÑìŽxѲfíÚ­lç³³ëÐy,Ç•oßÕ%‚p`H&í®Œq™«®‡qËcÒ«yàF45P ¥ç Ü1u§ûS* ÇÍÅÑ®ƒÚpÆð+äâ@¾VMÝ«QôŒ«æè•)ù!Ãq„Ь­öBJ~ˆöÊÕ:ð«u9z´_õõדӕ1ãˆ:_aD[Më¨ï瀕J…Ý#.½Ã.½%Ÿá”€zf BïP™?ÊÛ;TfÓî[‡}úKÕ ½%ŸÞa—Ý#.Æ«DÖÇï¢áû ÜÆã¨câÀF×®‰š oñ¡Ç`Ʊ‘Ë$ñÝCÔ3+A ¥ èù§Äkœˆ\gOþþ•”_|tƒ ã#î|‚ ì3¬‡.�ËI »9¤´�«þØKsg‹�§v ÒŽ�"—±IvvðžÞÄ#Ëy}›Â™½„—ϾŸ5[›- Êpê1 ˜ ˜ �?ÃÓ“\C”þ¸ôÃ1Îש&fðγÒ–^úëA8�ä´‡ftÒîä 5øÄ•¦TqÙ2¯êÈSt¬1.{ãQr}¶ ûl(S ¯�>v*MÓlõ•k™Ðݨ·�H¦û5÷ëò”ÍŽ¡ ÅŒÍÌÖ ®†Ý#>;†*”]S¯e;ÑóÊEqû·Œ“+àh—ŠåMž©çñãqX¡Û0˜Rýó‡8¨C`9,'Cà–Ég,vVr�ì™�Ñrëv•qCC)ÝP¹”+Ð3ì2Xöêj%¿»TÍ¿}È¥¯TÁÓÖ˜¶›½›8ܼ×h·ùQ&t狘œˆrzû°ýèhMÕá£zÖR>¤•`þ"°lœ­½ž^ƒ™ñŒ�‰Üóí8»»pvôÌî†êT„è¼êÒ¯�2¥}e³]Aö!ªƒKÞt˜e¡Gf²åÉßð톋‚•ã¤Ãº¢RSá©åÑ/w3ß¹o�‹ÏêÀ¶§óׯ>œ^ý8›T•�srkôÁíïäš?öŒëú7Šak_â6¨8ü�™tªúê?²­V.xýÙ¼o†Ç.¿@wT>Og��ᾬKá»ò¹Fa§öZJ&ðÉ·: j6¾µl‡òȽñÌØÚóÛT&‡‰­_ƒ•€íC.»Jå‘!pŠ5m4²²ñz¥Fâ#§ AªÏ–íLXgB}þ²§Ù6dÅã‹dÛ–A—mC.eÏG7ˆ”>�[‰6¹—›:\9�rçK‹©dÃáTZ$ÒÊôi 74äb!ÛWªT¡v¦Zv— ùŒE_©BW1òvsCÃîr4.˶>·ôó±l'~6š\àbù%4{�¢˜ë“A¹.Ù§{ íhPÖ¨« æ]t×ôªå)œV$ع§ÜÅiq;¦ûprëVv¶a¦EÜøAØg„=|ç[¹ô óikYÄçþîBÿò~¾·jO�DAQ]3çðò3NáS'°çüàÉôçeȽ¿ý#?9þ<^7M1cÅé\wiŽ�ýüQnï�CžÛy–¯XÁ§þòxNÉ&`ÍÍwóÍ“ nØþØF ær‚£è8æT¾ü²aþî¶mì+Ë’Ãå]¯<™·-µ¹ó‡àO/>��.°PÎlÎ=2ÏÏLveß—u ‚ X2¡7¥½étàª,»Ë>»†èíh 5N“Pçé{A,@ÄðôàCK^ÍWNé ßµ€ËÞº€ËŒ¡Rq ›ÏÑ–I…0ÜÂåßü÷ÖE¬5ƒOñ‘ÿù#3ÞóB^Úápè‰/æºNexh„^WÑÞÑBW6®Çø¬½ûÞòË픘<áŽG¹üŽe\ûÒid­VÎÝk9çÕ.=#!ùÖ…2�Ýþ[ÞsÛfMâà :°U‘‹ÿú¯xáÎÖýñ&Þð»^‚}Y×¾y‚ S§�øÈWe£th8/ûšPÛ”v�ý$¶S²,lbw±ÑQ½é¶“óúã$]«•R:IJìÆãhÖV|¬T\*@”A×�³,;ªßèšz«m¦Ú¨I#6ˆ8�|à·ÜxÜõϨWe¡â‚¿·¤¹FÏ7>wí,dRù›=÷mj¯»ó5Gͳÿ6`&ãÎç Ž`•˘x:€ÒnÂÌÁŒÎjt”"˜Þ†ßbFvVó«0„òÖ`O£Úlƒö•©nÜ{ò[ªÿAö=ÌϾ}/ÿ΃ܰ©DÅJ‘/äénËÓ (od77ßz;¯¹üW|y£ß°ªá�ñ†Ï^ÏÇn߆²eÑÖÞÆ’­LÏ*0Û6<É¿í:ÎùÞ:6NÎø?Šq¹íÇ¿äÍ¿~šõƒìlŽÙÓŠt:0Ò»…o|ïg\xíFvÍÊoåÿ=>Œk@Ù9æÏn§;»êA8P„>~Ú“*®NÍEãIu†ÕûɹmÛ5‚©Z Võ€m7ˆ®cg¢zô)Ī™¸×ç;5­,tï°šôÐ¯Š¢$=-’tº®âÉ2º* êëM‹¶¤l’?]w3B¥R"0ˆúškª¢,m#9¯@Õ²JÕÞOʤEQ’?ÕFµL}›u‚TG(WÝ—^išYoü–.Ti7�·�ÒŠC£5IÉR% F÷‡2X#%œÞ!r›ú°ZaŠ�è‘§©,ÌΙ·ÿñªh}“ݳ›Âú*¿(2÷í^‹·´ö4t{K�ðŠË«(|páOÈxó0….†?£šmÚÃ×�;`A„©’kiçðÙíÌjÉ’· ¾ë²£¯Ÿ'v”(MÅÍαhn‡tæ)Ú†r©ÄÆm}<5ì78•)pèüé,nË`k�=}<º£ÌØCŠ|k ³³š¾Á2ƒAƒ­*öa]‚ ÏÇœMˆ+ƒØõ¦¦-Éu½E£>_*O†c¬Q¶�²¥ÛI„Öh™úvâ4{d¹¾§±Ëƒ�ókÆa—ªÅŠÝË´²F-E�,N¤„N‹U#KVZ¥-NI[Õ6Sý®©g‚qŒy úÜôý¤ÎµRX–ƒÖ–å4~‰,ÀJ¼éRB˲Fñ’ëtº=²‹üÎuX~©:Žz,d¢À”�ÂAUÜqÖ))tk+^!OÐÝF~Ý38›ÖÎ*Î8¼6FDCØÕA°¥‡Ì3÷ÎhÁ}áBÂÖ"dœT¨§êÆPÕSUñP¡…QJûâÎ'Â~Åä‘õƒ<²·….7ocãæ}Ñ«±¿Ì“¶ðäÄ9© óô³T— ³F�@©¹®Ÿœ×OâÔ §(Í®«ÓFCƒ` ézkÜû‰­IŒ%-TýQ1¥C¬ª¸°¢ýSc±S<©þ%¢Ç2zlzZ …£¢ÏН­úõA¡_m{2®‰¶1µb'e ²’g‘ˆ¤j¿‚Q—¹º÷h¥ÒkSÚndÕ-EÒ:À2¦¦\}™šüÙ|“;£Œ/¢BlÇÉìØ�·xÍÙ°mtk‘òŠ¥(߈êb¼T¤½Û¢²|1ˀc×ÕoFI²68Ûû°½<*u�OAAH°�+ZÒV¢ØÍ®‘ûPkEŠÝÿªN|�XJ0UëM‹²$-åögƪ›’ׯ�JÒb(9i U½õ¨^<%ýµäM?'`ÜûUKYý’ƒUñÈ®ÛN¦?‹*vDíž¸ó ‚ ‚ úñæ´“R0515QÞ) 3×Z–SO��˜Ó\kbw³F*b_2Ž` ï ž=É;Q=õ÷“k¥ƒ½ß' ˆâ¤·Ì$7¸ õÔ6üŽ<ÁŒ®)íå4JU™Ž)á¹8;ûÈô”Éô9Ð: ¬Ñ âÎ'‚ ‚ ø:ÄnäjW‡å•ÐÙâ³Ô«æ$Ö�©í‹kTC§.×Ê?÷…T ׫Lê}<ÐJ‘7!ÆrƼ�z&Þl71ßY´Í!W »£Lл•ÐÀ²âœŠ¼W½6£ýLÊuO©hªª ªS e4*T8~Lªµ3Ê÷ˤ7öAAþ¬±'iŘŒ€OhMU„M”¿Æòá—±�ijך¬€jÔf£´Éˆ²ú<ék˲É4 ùî—§Ô·ñ˜lþ Ÿóxï4e‰šˆñÝùŒFŋŌe£0�o:ȺØ@ƒR(F÷Óy›¤ÕŸ�w/:ShCh ©ú�w>AAatÒ^gõ˜HLÔßO®§j©j6AÏé n³ºâ>§-¶1c¢æ5êcƱÆ?�úÒ(m2¢¬>OÍuèã‡!õ[f,íÕ ©úgÛìÙOÔïfÂo"јœ7+ï+›¬å &Ø6~‚çaãs äZj L�Î'º?ѽšóÔ¯ I_’£¸ó ‚ ‚ ËF‡£“ßñ&ì�&Ö�®sº‚ht¶Ø°|³:ÓééÉzý¤>kÅ{:…n�å©>˜C}{:[¬Ù»¯™(LÎëEC}?’ûÕ0éuåj,O „ŽI=Ø£Ë}Òïb¼qLæZ^©æ~£±4êW3±Öh,–W"c&·ëýž‡Ðx!î|‚ ‚ BnÛcû§ÞýRkŠL‘ e‰*ìœx—¾=¡°‡÷ ܯ’)ÖXÔö×8ö;uãhÄA!¢Ä�OAA„g‹ƒBD‰;Ÿ ‚ ‚ Ï…ˆw>AAAž- %î|‚ ‚ ‚ <["JÜùAAAx¶8(D”¸ó ‚ ‚ ‚ðlqPˆ(qçAAáÙâ QâÎ'‚ ‚ ³ÅA!¢Ä�OAA„g À *lúÒ»hgö o=ÐAAá cáû¿ Êecè΂ ‚ ‚ <Ÿ%‚ ‚ ‚0DD ‚ ‚ ‚ LQ‚ ‚ ‚ S@D” ‚ ‚ Â%‚ ‚ ‚0DD ‚ ‚ ‚ L�)m¶ûتöW?A*^°âøÝAA& R©ð‹~Í O>…… æMºÜ”DÀñ/õOgëÖ-Üó§yÍ…¯˜Rb‰AAáy‡ç{x¾O†“/ãyüã'>ÍßþÍ_S)³»ˆ‡W­âüsÏžRÛb‰Ašã ³k°Lh•¡¥³“–†ß¯4ݫȵ´Ò’Ý‹ßè&ݦp@�÷#Âs„Œ“app�‘‘zz{˜9s&³gÍF)Õ°Ì•ÿñE^tê ™9£‹��a¾ñ­oóÕ/þ?²Ùì”Ú–�=A„ç(nïF6ìª`T‘ÙK0-Ó$sÐϦ§v0e&?}!Kºó{ÝÍÿò¶¿»ž ØKxÇ׿Æ;—Úé^òôM_ç ßú-÷?3Bh@YyÎø§qÅÙ­û©Íçfx+O<3„nšCaÙr-Ó˜5³“Âsw(“âùö~A8xQJÑÑÑA[[…b‘ O¯çö;og``€óç³pþ.\L[[´ÞéÚë~B¥âòÒÓ^Dï®>¾ôÕÿáÓÿü�LŸ>}Êm‹ˆAxN²ùWÿÆ;¾µž süîyÜÆÓ;W½÷‹üɰYôW_æû³Œý=µuW‹øÜÏx:0£}Ñ?4þðà¿ÿüͧnÅ5åTXù.;ñe\tÉyåòNñ©AØX–Å´ÎN¦{Ç{•J…M›7±yËfîùÓ½ì ììíã·¿¿‰ýÄÇÙÙÓ÷¯ùo}ó%¼àˆ#ö¨MQ{‰ñGèôÈ´uÒšýs˜.‚ð焽à,Þû¡%” `u°lFzÚðÄíw²)P*»”×|ä}¼z‘C¦»°Çjü6ŸÏtekïü1WÜs+w\v%Ÿ}õ"¦æ@rà9xß� ÏG´Ö¸n…ŠëR)Qq+ 30ØÏðÈ0a¨YùÀƒ<ºöI®¸ü3”K#Üq×=¹ìÎ;ë¬=n÷ù#¢*;ytå}¬zb3;=ìBÝ 㘓NdٌܳߟÒ*¾ñÞwð‰kïgGÅ@Ç›øùŽïòªÐA„ý…Õ}ç¿ê¨&w5»I 0ö!gò†³�aÑ^ΩÇoó9ŽÊ±ø”s8vfZBty€-O<̪MƒLÐÃ]ÿu%×ûeÞ²·ìYæyý~A8(رc;«]ÃΞ�ô÷ï&›Í’ÏåÉòäryZŠ-ttt0Þ|–,^ÊŸÿþò¢WqÝu?dþ‚ElÞ²™«>{ù^õa¿‹¨0 ÑZ“É4s䟠|Ͻüïg>ÁUßþëCê½%”ÓÁag¿��}æ¼íÄ®gÉ5"dÍ/å½ß¾ßžÁ1œÅ‘Ó�#ù1NnaÝ6ÍŒC6_¿ BÊ<³ò6î~bfÚ Î:ÿh¦OÉœ¡ÙqÏ�ùÕ�CÏý+ÎX`5IŸ_ÿæW<²zGµ‚ ^Þ8äéàÎ;yä7§ñâ·NèÃuÀÑC[yrk´fG9�,8d- Ü��qïkyfZf.ḓŽfAKíó1å¬ßÔ�@ž‹Ñ�3ŒìØÀæþ2›R‘ü~6®]KÉ2hca©ØB•›ÎâÅÝŒ]¡åÒ»q#=•(ŸÕ2›Cçw`5lsïÇ2:(—ž'äþµ[Ùí:L[´œSŽ[Ê´Œaxë:¶ i ŠLç–Κ¢EMå9ú/ÞÏ?œÜàÃߌ°æÛÿÀeÿ·†Æ}‚o~Š¿ºôÐ1n—ÆÝźÕkX»¹—’ÉÑ>cË�} Z'pÐôذæßÔàgSìšÍ¡ËW°lV~ÜqL¥½Æz6l¢×‹ßeqKt6˜d¸ìÚ¸‘�•æù¦Ò—†îv¼ó>Öö;~úù?óù%RA˜˜[n¿•þþÝœxÂI¬8ê²ÙÆîR©Â;ßû^.yýÅÜzëÍ,Yr×üàG|þŠÏbY{÷Ù°ßE”ïû�¿"Ê0ôÀrÉ«?Æ [<Œ*0çØ—rîéDzdV;NyO>p+7Þü0OÜøEþú–ë¹ñ«¿æ;—.kðE½�1½ÜuÛj�W}q5%Ö¬wò›M_ãÜ)ù:…<ùÃà]ÿ9À_ýâ/9cA®IZcnºé&V­ZE®èðÁË>Ì7¾u5_øÂX±bgŸ=ú4PÏ‚‡¾Å{>q3#TñlþýúËèúÉåüó7ïc»—ˆ@…Ýq$—üó¿ð·'�þ <~-DÀ°öÚ�ó¾Ÿî¬ ¦¬¿Ž�¾û: Ë1/žÍê»6*ÿøý+xU�"6·óïﺂ;ʰ9ômWóí·w4iÓÞë±èÝð¿ÿzßy°¿ª…/åCÿúNôWßÏò‹Ù�ëÞ¿bß}Qª–ÿåEœüÃG¹¥dÍÖMÛH‰(=ȪŸ~…«þïÖ Õþp¨òsyÑ%âão>�éõ_-¦Ìºß^Í¿_ýV÷ùµå¬ŸöF>ü�7pb}Á=h¯ñû Yý½�òO7 ¢«ûüÇ÷ÿŽSêþ»™ÁÛ¹òÝWp[)zç‹.ù×¼«sÏûòÐ7ùÛOü�Rò÷ð£‹X÷Ñ¿çë�–0d9³ëeÿ²ý>+áYæÕ¯x�­}œÇ×>Î#«Wñ’�Æa‡6&ßç>gœöî½ç.º»»¹ÿ¡GxÃë.fáüù{݇ý&¢Œ1”+e††˜Ö9õˆzÓ5¼ý•Ï [5öÜóøä·®æ#ç.#�ÊOßÀg/}Ÿ»u×½çbúG>úÔvžzçÔ€ÃÒ#�¨í“ÙÅŸî}’�÷oá`cð7|õëk(·½”Ëý-Þ~HÏòb‘U«Vñ�|€Çž|„'7<Æ/=�e‡Å—¾ô¥ªˆJÔÑ/¿ãy#¤T¡@^Y?‚!6üúóüû×îeWM89C8°†k.ÿO–~óSœ?f–>5Z�>‹åú?Vyã>ÂÍì㕯˜ž²††WÞɱEBeŽàü³cÃ8Qîör,á&~ôéOò͇JÕ ºrò´adË­\õI—“íÑŠ2ö~øŠ´Ò?)ÚŽ=úLÌ~ý#üÝžŒÖ©3=œÅÅAÖ?ö4»*[¹ë[Ÿà²áãÞsÀ©j/ÛkD §œu*�ø-}tß}ܾÆã”ãÓÿ‰ C÷ÝÉÊrüôíEœsöáÑDdû¢òEò JL0Ìºë¿Æw+�ñZáà¢P(ÒÚÒÆÊ•+ñý€•+À²¬š°æe×§P(ÒޖDz,¶lÛ‰ïU¸õÖ›yôÑGøÀû.«FíÛö›ˆ3ºgMÝ\fz¸î£æg[CT÷y|ñ¦ëyï ÿz\X|!Ÿùåõpú™\þÀ£|ýßć^òæY`v¯çÁõ»¡}1+ïÆßx'¿úÝCô¶�Ì_¼þdF]Ö5Ûàî{WóÔö<»•‹–sÊi'sH{ºï†� ³®ç)¶ G¿"o~„•+·bÙ]Ìè¤gÇÝÜx¿‡1Ãl~d%+wÙäg/cùü–?‹(U‚°§èÞml÷ ™“^ÅO]L“ tûc ÃÃÃ,Z¼˜¬“cw©‡Ý»wcL4%KÔQçþ˜¶®èW¬»¾=ú?û9ëÚgÙ£Ö˜` ×|#`ú9—ñÉןÌÜ`¿ûúùß•»ÐôÀ½\ËNνxö8îÑG¿ã«\I…{¾ôN>{{8G¼…¯~æBf[Š\+Üþеã2®úÈ…ÖÒsÿ·ùø'®å‘�»éW\õ­3¸æƒÇQØ‹öšQ<þ,Nïú=?ïÕ {ùã]kñ�?zT4šî½ã�ê;Ïqç,±÷jìØö¨/x’Ÿÿtkñé¼é¼Ìd„ö…ÏŸ¥ß‚ Lc ßú¿oòû8‹.JR‰¿®ÙÕ×Ç›ßþÎ;û6<µ§Pdzw7_ÿïÿÆR?ýùOøÑu?æmoy+¶½gql÷Û§KÅ­P*�ðÌÖ- Q®”±-‹Å‹—2oÎø&4ýÔ÷øòÏ{ЪÈiÿ ïn" ª´œÂǾñ=ï9‚ Î\^5õ{·~‚3þâx§‰‡¯ØÍÛÎû4÷ì…ïçÈ¿8™™0½wpÕ»þ†Ë¾–A]ã<€Õ¾Œ×ýÛwøÚûN¤]xÜöÉ3xÍ÷FRßû¹ó9ùs Z_ÏÇ_û{>ûݾøÞC|áÕ§ðlýû;xôªS‘åQ‚Ј�žÇî屇×3 ÁT¶ðð]w²57›å'-Ŭ»�Gw*f/?‰¥�µ‹õG6=ÄC›ÊL_öB–uïÕ588ˆjóX=x ß¹é+|òE×°ë™[xü¦—qÔ™Ÿ¦½=÷^tñܵ–Õ·|š£_~Ç>i¿�~lz„`é{¹òc¯a� 0—K?>ÈšK>ÏÝeÆç‰µO0{ܨq™Ö.f´ztæF+W٦ϘA´Åpæ…/â¿î»™~mpWÝÎ]}Œºô•⎕‰ Ésây§3k2¯p�ÇRæþÛîa ÖHªp"ïüðk92þ¡¬ãñOïz˜×îN†ª:j$”ñÙ¶êNþPªýRÖþ[VßÎ/~ó@Õjfu¾˜×�='…øÕoÙG:´—¼‚wž?·ú K_Ë»^ñKîÿÁÂ`¿þõj.=â8²ø¬úÕ¯x<ޝ®ZNåÝ|‡µ*ÀbÆ oå²WÜÆ»ø !†íwܪ÷Ç)Ù=moò+8÷ôüâ§;Ðh¶ßsÛíS IDATkÿöhŽŠgfd%·Vßy†£Ï>“h‰â^ô¥æï¡�¾Ö‹øÒ½‡ã[ägKA8˜yìñÇéêêbÁü\óƒï⺕šû6ná˜Ë uHkG;�=¾Ž Î{_ûÆÿð²—¾Œ ο�Ë>ø>†‡‡ioooº1ïxì75sÆ,*n(eQ®”äÉu�O ¢4Û~wò ªåe¼ãMK'µÏIëqñæº4•Ï“SàŽ<ÆÿÃwYÝu¯ÃQLo?9ú’×óßo|5ÿxS?Ù¥ò�};g¾`&¹ò6þÕWøìßÁ?øjœyñÝ‹f Èpì;¾Ì×OßÂ�W|’ëžRùæ+øàéX™CX¾è,>ú7|þãßg-‡ñúÏ|„³»mÚWLn ‚ðçÉ¿ùØY¼õ—ñàý_൧!^õeüÏ^À+¿“å�7näêsÒS¸�µ_3/ý·õ¼úÚ]\÷úâ>ëÑÖþ üzÓתª•¡õ<~Óß°ú–Opê+?À`ßVÖÜõcŽ~ù´Ï|É>k¿¢rœôÊs™ŸúPR�Çpâ!w¯ñƒ?<„ {z[ÑzÊœ5ó~²]�q髬º›{cµbµžÂ/Õg*c ·òÄS£n^Îa'sJWZµ)¦�úŽÉÜÅ�oøÔSbåw?ÃÊ ²Y-‡ó†~?gM‹Gnä¡5ƒ±+£"7o­ý}ìJ•éZ¸˜œÚBÉhúy„Íú8–šÍÜÿ`OÕ2³ì$Nªù±!Ãò·ÿ¿¸Ä¢P,PÈÆîƒ{ÚÞ¸B7ËÑg�Á¼ŸÿˆÍô¶{¸cý;9êˆè•VÞÁ}¥Xìå�åü3fEr_õE9ýª‹9V” ÔhýÿÙ»ïð(ª¯�ãß™-ɦ'¤BH ¡„’ Ò;„ÞÄ®X±ì½7ð'R, R-(]éRCï�ÐB¤'[gÞ?’@ �è{>σ˜ì�¹g »söÞ{®Æ?ÿ¬¤cÇx9DHp;ƃ®£ë::ðâ˯ҪEsæ/ZHffÆŒÁâáNvv6 - v­º4l˺uëèÔ©FcéS¢JçvwË[-tìx"ûîÅÍìNxµˆËådǦí8t06hG«€r¼Œ×¾iL‹~Œ›ß§�ïùó9×M`ôÒT4cÏ͘Å[�Ï_2´ïÖƒºöXz�KdÖ˜™|xó#TSU":à¡v{9óíÌ<¨RµÍ½ zîÿyt?½2…=„Ðò®‡,…%„¸ _nûf7mwŽãönï³£ÙÛ,ÿñ>B�Þ„˜á¯kQ–-àÜ4>wïhêöIaõšuT¯FöæÈHI`Çš•ÿ® @ "2¼HÅ9ÅŸB¿qih±S®[7u�à×ɇqé6¶,[ÍÙÞ}¨¢ØÙ²j=i€ŠÛn´ºô‚›â•æ¾hiœI;_xÂB@‘·gÅR•p’*oZ¦b ¡I¿;¸ÿŽÞ´+4Ë•BRrA*¤“³ü#n^^òy\IÇ9á„h’8žTpœŠ%$Ÿ"¥jñ¡Š¥è ÊØße2kS½NÄWŸÅ¤#.pgåªÃ ©��Ö¯H ;Í–GÓ.t(•¬¨X”j×®" ñ—��ÍŽ]»2äþú{ Äæ}^ç'PšËź ;~œ!=@ëV-�¼ÏtL&)§SˆïÏ´é?Ó¦M C©G£®ÊdácÇ�Ò(öFüý® u§’ÒÑPp �¤Zy†p”¼ùìZ&tù"­}/|p žä· ·pꬅº�о{Ó¶[+<Æ!gÏöºàJ¦ë !JKÁ38’ÈŒÜÜ�¬‘ÿïÍvM"Ê´¦]ð³ËåbúÌÙ|?éz`±fرf%A�g0kÞAîíß³¹¢«`((J¡59º†ËUrkÝéÄYèÚ_UJzÃ2rQ±TEA­”/ï ÔîуÓÆ±Õ®cÛºŒgzq³ß^V¯?›7ò Ñ©û�”m±4÷ʼnÓq®F“ñâQ1P†/#‹œÃB½ýéT¨”¾ýà_Lþë6t͆gL;š…-[çÄáºòäMwd“åŒv¬çË ^y%ܲöw¹—¹¡]:Eòãă¸pqdõjESÓ¶‰eë³òŸsoÚtmɹ�䊊EñÀKF¡„øOÓ4�õë×sC£0™LœL:I×®ÝÏ%Pè:Šª0fô`6›p8ÎW ×u�˜˜¶mÛL|§®¤¦¦rêÔ)"""J½6ªÌËW,eíº5ìÝ»_2Ò3òÿNÇÇׇô´¼Ÿƒƒ‚HNIÉÿ½/a¡¡´hÞ’öí:b݉£`^´›[Ådy¦&tjë{ѦâJÝF¡Ô½  §Ã�Óé$×àŽE�ìÜr+ï‹I!Äu¦`$JQ\.?üømÛ¶âö[zÛ .ìƒÈ6ðË‚ýlÜ´™Y¿þÆìiS+<‘r·ÚÛG;Kò ‹OŽ´ä“œ:—d©xùx]ÅlÔj�és㤼¶,Y“Jï˜ ¬Ïy0TëDÏØ«P†Q±`±:Ö¬lìpáZUWé™åíÇL­ø»PxŸ(k#ìûŸfòaº–ÆŠ¯¿æ¯&¯ÒµpÉwÕ‚‡› v Pñïñ:So\òZZÅ€»àpÃÃM»èäfç^²ºa¹û»,ÑññÔùñ»œ:΃kXuâBW±¦`ú¦_z4÷ª”XʲŒMqýÛ|$“¿¶çMòÍ=’€¾�8’x˜êáÕ/…*ø»N­hlv999ØvŒF#f³£Ñ@dD Ö¯_‡Ëå¤m»v¬^»†°°°‹ªû]N™ÇVÖ®[C«V­ˆŠª º~îïš5£Ð5ˆŠŠ]§wïÞù·G¡k:­ZµbÅÊK,ÀV<ðò4  ãHOϯâS>ŠGUýKxP²÷3ôÓÜ5ƒ½q31¹¹cñô"ðæ‰$_ѧ‘⿤ðt¾µë×ãííIdd8éédeeQµù,>»�„„�DD„àÄᆵà(T#Â9·_¬–ÂÚÕû°Û6—­KWs~V—ѵ¯�iMJñ½[㣺�íkØ—�@¢ À@T—.Ä\�9já¡ß2ê8íã�óÂ&®£»Ø™U oúîõøxOªò>‡´³Ë=f%©…?ß aT¯ZðŒéä¤e£zzáåUÂO F0V£zÕó÷Ëv<‘SEî‚ëð¾ù2�i¿®`_Ž^öþ®€Z½#]còGú\ûY—�ÄæUëó‹z¨wèJ“ÂÓ +1!Ä¿[âÑD–._ÊïëŽQ§ªuªúà Œãè±£$$l v­:ùë  ©ó›L&|||°X,hš†Íf#''MרV5œýöÑ©c<›7oÂf³�›Â¥ÊüÑ•��MÕªÕ°ÛíÔªU‹ääd¢£k‘œ|ŠZµ¢INN¦V­ZèšN­Zµ8u*™ÚµkQ=<‚¬¬¬KœÙDDÍj¨ìùg;{œÐ²œeí³æbÞpõÓ‹x¶Û­|¾) ,Õ¸±c_ºÖ ÃßÓ“É„zäO>Ÿ¼�œòu/„ø—É´¦Aþl« ð÷EUU|}}ɵæòÇßG !$$€:u¢ù~Ò<6lh…ÆáÛ†V¾ ™—ª.Žüò_ƽˈÖÁ…¾¥Ïåð‚/xÿ÷“çF Ôàvtmx•7Ù*Q^�‰.AK˜uJ#wób¾ËØ�PÌ1çö†ªtj ± Ã0lÉÛX;ñ3ÿ¹‹íó ZègY6e.‡.1e²ì<› bx§U¼¼ø )�aLçF¼ÔÚ'¯µ*M‡ î9ކŽ}û VœíNŸs£UI+&3e› ¿?#›ÒµUµ*Í›„1aÏQ\€kÿ –½ƒ‘�ª�m|Ëw3Näm‚ë߃Oz´£vYû»’»«†_Ÿq;¶`ÓìXý3 ¦æOå £s×\0™±2cBük­ß¸žаa,üýX±ÿ,ƒ�Öµ<1¹2H9�ÌŸsÇâQÜд~þ¿zÞ—¢š¦å'J:š‘5jŒ@»wï¢qãK5£¤ÌITnn.�ADFF�”t 77722Òqww'##ƒ5"IJ:…‡‡Ô¬™÷s@@¬ÖÜKœÙDÃVÍðU÷qöð|ænŸ–�¯ L=›3©ª\éÎä6V¾;ŒQ›²1Ô¼—I‹¾ážè �µ/<Á¸%‰âzår:/ߨ ²lyI”¢(8].l6³çÌÚkÇÝ2�Ȫ!9q*ÿg3]:´ÁQ±x¶`@ÿú,ÿz{Þæ²ÖÌxiËcÓ8:wgÇwoaó‘4Î-‹Q«ÐiÈ=4¾ÌÎW•[,}»Uç×ÉGpen`å·†]èRõj�—¨Û½'õgŽg›Mí4 ÞAæÖ4Õ8¶v>s6åâá¡’•S £QІ>DëuŸ°2C-™?GCçØ§hé­Fê÷½…F¿Ŧ=k-_¾ù-#úÑ$HçÔ–ßùⓟ٘®�âNãÇšÓ#17ÝFÓßF±6[G·ïfâ›_à÷Ä4­bãЊùü·ü[1}ÓÍ4s§ý] •à�¹aüVÖZurÖÍc‘–?}3²3=bŠ~3Z™±!þ�¶nÝBbâaúö¾ UU¨¡i„ûfÑ0¦!'“Ž£ë>DDÖdá¢ùÔ­CÝ:y‹s F“ •ôóÿ“7J…ŽË¥áÒ\(@Vv&íÛµc݆µÔoÐðê$Qv»³ÙÌ ƒ/ÛöÅç_>÷ÿ6›‡Ãq‰Öà½æÇä�Løè†O¹£ÐƸÅÑÉX:’Ö}g2àCÆq/1—{ œÛ™¿0&ÚŽx›»£‹&_:g&CÖB q )�ÝŠõ¢²Ó¹>˜De Lç+�““ƒÕ®³eýZ5k€5×~îç³gÏVBFjÞñ*¯Ÿx‰7;@¶èVNíZÍü]·VL!´ö&/Å_'SùÎ1R§GOêOÇ6{ÁF³î4ëÞ>O©«C�ìdz¬áññ[ÈÐ@Ï=ƪß° @õ$öþ©û×fVÒ7gjp7ž¸€MÿÛB¶®£%ÍãÓï:2qÄ�x* †÷eäc›xì³Hqi¤o™ÂKM¹ð$Š� 6ÃyKø¹çX ëÃȧ·ñØsÜ¡“sàOÞñg‘ãTª4Âë÷Ö97ŠYÖþ®è¾ViC׿fÝ?¹è.WÞ¿SÅH�®ñD3ôX™±!þ] ›7pÇíýqiNÒ32ÉÊÉÂép²mÇfœN'ww,âãã™?­Z´)ua]×Q…¨¨(¦Ï˜ŽÃ^ü„ù’”9‰êØ¡#O=óGÁ·¯»ëg…~g0èÝë2ß!ùöâ¹ÇodækHš>‚ÚÄ0cxl‰Õ›‡¦2ô�¯Ù—­‘™æF•+™þ§g�ž¡F‚Cƒ/~CvìdÒw+°é ”rŽd~Hþ%Dy©…£ê{Ùµý®>1ç¦~9üÀøèTü�‹Ý©qz¿‹ÉUU±Úl ˜Ù¾{3À¹…§?gdd”yÇóËRƒhÿÔ—Ljù+?LŸÇÒmÇÈp~wQ0z…Ûª+·ö¿�.Ñ×GA‰¢Ôj�ésÃD¶¯³¢ªWKz–eo¨rq§nÿ÷˜Pu:ßÎZÂÆƒ)äàEHt#âo¾—{Ûfñí_ç[¥Â£S©Þo8÷.΄Ý6tÝűßGóMDZ<ÑÈ0Ñçu¾ �Á×ßÎfÉ®³Ø >÷ÀzÄß>ˆa·7!ØxáyC»Œä›�Œýf:‹¶ž"G;œgX:Ý4€‡ooBÈŸ�eíï (~´ëÜ�Õ+ò’@1Õ£{|I P%Æ"„øWÙ½g7 êÇâæfFÓŒøxûb6»¡( š¦¡i.ìVk.—F`@ Ï<ÿ4©gSKÝ—¢(èšF›ÖmPÕÒ}=Sæ·¢~7ÝB¿›n)ëá—a&î™oxkQG^\žÄ¼'âé¼û>å~Z†br¥²}öG<ùä§ü}Â…¹Î&Œº� +ùÜSÉ 7À1›V¬!ëîΜ«ä8Êœ§îãgé¢îçLÎiR²uŠ]XU„b4å-xužâD’ dŸ(!ÊÁHýn]ˆø` Ÿ æé€çéW׋¬ý‹ÿѼ;5ÂôëîR/-‰¢(8Þè:OOOœN'3à�?ÿ¤JPð¹v»÷'^pÜ®}‰ ¸÷ž ‰¡xî„·º›—ZÝÍ‹¶4NOâL¦Íà†·ÕÂüp¿Ä[�©ñÌYòÄ%ÎïE¯÷çÓ«ÔÇši÷ʬ~å î‚v–S)Žü/—TüÛ•¼7Ô¥ú,Ï}Éc!²Ã@Þê0ðâ›ìëÈ8W�OÁâi¹¢4ÊÜá5–-}í Z¦h7�Kl`$¤iÞhz7#ÓN’xâ,Ù.^UªR=Ì·Rñ�½™‘£næÙÌ$��&[sûJ(ÕB½/Q™¼ôý]þ9Pðíò&u¹L³«‹âßäàátìÐ —Ó…ªªy{?i ãp8p8Øvìv;šæ¢NÝ:Ø�ºuîVæ> F#n¥¬°{ý~Ÿciij¿ÍƒûîâÕ¹‰¬ùj0­Ç=C�¸¨Sͳ-…›7²+ÙŠ®¨4{œog|Jï+Ê C4·Ýß�wÖ.æð¸{è’=”;›øc=¾�%³f²ÜÖ›Isº3µíƒüž½”QÏ}�Ö­%=noEØ%N«T‰!&ÄÀâăŒøv2»DB`OÞ~¹ç•%wBˆ ¸·{�‰oîcà{óùrh?F£`ªr#ŒšÁ+Ö§™ûë.ì6;àYî¾âââøõ×_/HÊEaâ7øhÔ(î½(!¡Á,œ3‡n}û^ðóÕ¢ºùQ-Ê�jW­ÇŠ qúï™}$oò¥bˆä¦››”qo¨²sžÞÅ?›p2)™¤Óî´ØŸ–…*·:la[Au>Õ“¨šÅÌR¸jÜüªRÛ¯j©�4y‡]/ôªõWñ®§X„WÛ™3gðòò!;; £Ñö¼ýAGsi8�N\.šæÂápàååEzF:ÞÞÞ¥Þ0(Ó1p='Q€â×’çæl¥ç¬/ù䫸}Õ~m\Æ¡�ù·«BoìÇÝCžåÙÚRµT ¤JÔЉLMÀÐQKX;émÖNEõ$2þ1¦Ox›~5lD¾ð=kÞZÁ¦oŸaèÒ§YrK+Â.õ©jnËÓï÷gáÃ?±wÇïŒÛ¡`é\�W^‚ërŽ�× C­gYmöâ”Ú½ü'žNæà�“dü‰¬�Ÿ `.Ö‡ 76ÑöóC8?¿ÜïŠ×¥Kºt)þ«ó¢¿¿š‰Ó¿“ƒc›W±7M#ýàr¦ÏXIZ~‰kÿ÷sg�«ÿñ£¤­eüû“ÙïÔA1°ä¬'ï>Õ‹þ*YGV2îó_ÉÏóPƒ;Ðí†+-T$„¢¢8N ª‡Ã�¦¹p©N”ü©vº¦ár¹pºœ8�N¬Ö\ NGÞÏnnW¯ª’øàG:JÞ\þÄÑ—.Ï»këFnlÙîjÄU,-'™CIN·¡Xü‹ªM¤ùËøº2�±{W"iš… ¨j_8…Ù™LŠÕB` 7¦+L„œéGÙw$ ¼CˆŒ ÆCfõ ñÿÆÆ5+¨wãµãËbîÈÛyëŸÂ u Ayãë—ét ÞõLÖ~9‚çg¡ N‰¢0™Àáp�[»«¸ErÛÛŸóL‹«½fK!ÄÔéSéݳŠ9¹9l‚[PªÜá°“kµ¢( ™lß¶�»n¿»Ò“¨ˆÇÇP�7]×#QE©ÁDÇ]Áç5x‡Ó yx‰·½ƒ ó.Ý9�¾Õ©W½œ‘ !ă¢ºÒ¨�>ýðµI oZ ÿ‚¯"¾cÌϋٜ”‹¦»((Ȥ< ¿¡+÷ y€¾1Þ’@ !Ä5S'†ù çqçíw£é:iéihZÞ4Msát:Ñu0›L(ªÂ–Í›©U§TåÉ+¿*‰BñoáE·×¦Ðøt&¹NK•PB}Ì×>1Q}ixóSŒ¹ù12N$r8)�l‡ŽÉ« á‘„zÉÇ¢B\K�â‘t*‰I“¿§C‡Ž„‡b4ó¦ñ9�82³³HJ:ÁæÍ› ªLÓ¦M˼¶©¬äÓB!D¥0Z«p­Ã(�Ÿªµˆ“ÚBq]QU•î]»³{ÏnþYµ’ôŒ \.g^9òüy׃///7jBlÃÒm’[Q$‰B!„B\7TU¥~½úÔ®U›ììl233ÉÎÉÛ Ýâ‡¾¾¾×$y* I”B!„âºc2™ðóóÃÏÏïZ‡r©'„B!„¥ I”B!„B”‚$QB!„BQ ²&J!®C'Ož¼Ö!!„ÿ¯„……]q[I¢„â:Tš7r!„B\]2�O!„B!JA’(!„B!„(I¢„B!„¢$‰B!„BˆR�$J!„B!JA’(!„B!„(…ë³Ä¹žÁá­û8íÐAñ$¼A=Bݯà°ÌD¶íMÆ®ƒêAúÁ˜ÈáøŽ]œÌÕ¯�jUÁp©iiÚr€3.0×!6ÂåªÇ, ØSv²zU{Ž¥b3zÙ€æmšRÓG¾B!„W_…&QÇŽcãÆ�œ8q«ÕŠÅêaaÄÆÆR£F�+?‘c%ouîË÷g4P¼éýí^æ<z™DÆÅ®Ñ·ÒôÕ:˜Û|Ê®åO¥˜ÈZò"ÝžXLšGkÞ[õ7/ƹ•xžãï¦ùc HõhÉÛË—q-b¾ú´Œcì?©�¿éÚÄp�¬L~q/|³Š“6½Ð ªW4½Ÿýc^îNøõùU€ø�™;ï¶mßJlÃ8zõìs­ÃB!Ä5Ta—ë6l`Μ9T¯^�ž={rç�wÒ9>ž€€þþûo,XPú“* Yüýà Žh—iëØÄO?mÁ‰‚rQæb¢î£ß2êæP”¬Õ¼õÀ»¬Ë)þ4Î=_1dä"ÎâG§w¾çùÆW0œT)1_mN¶}Ú‹q÷2éØå¿áìeì�ôÕJN™ëÒgÄûŒ™8™Ic?â™Ûâ“s€9oö£û Ëȼֱþ?¡§mbâȇyàÁçùy¿ë-­^ô%ÏôïF«b‰mÒŽ¾½Á”M©ÿÊ*E{í, “^á¡[{Ñ£ï½<õ¿eœt–p2 Þ}˜‡^žÅáK…{‹/æ³Ï>ãБƒ<9â9ÈgŸ}ÆâÅ‹Ë~R!„Bü«UHeµZYºt)7Ýtááá|÷Ýw4k֌ٳgA§N�8pð (݉ uhP׈uÕ$¦ì¾ôU�mõ�LÝ«X§UŠKHÔî;Ž�5 X7}ă¯-¿øâÛ¾ƒQ¿Â’4êý)ß�¡Ô2óÕ¤ŸaýÚ}”ãZ³霙õ*¯,LA÷iÇ»Ë60gÔ‹<2ð> }ŽOf®áï·Zâ‰�]cßeÊñë éûOsrâï÷éwcküà&þ0›õÉ%=æY¬{¯Mz<ÁìÅIuï4Öýô÷µnÉÿœ(’•¦½ƒ­÷¡Ó#Ó8Óƒ›Z›XþJOº¾¼’ì‹âÐIþå¿9—ÜÆm‰¼äüÝKÛºu+O<ñ:¶gß¡]tèØž#F°uëÖ²ŸT!„ÿj’D%$$…——F£‘iÓ§ÓïÖÞ|ûíw8�N !ÁÁ¥O¢ÔP:w»“s ?NÞˆ£Ä†Ù,™<ƒ#z�:ÄâÒ‹o¥õåóï‡SÏdgçè‡xaA*ç›ÚØòé`^_™‰Zí.¾7ˆe¹ðªà˜óhd%n`ጉŒýr£Ç|ËÔ?×p0ãÒɃnMb۲ߙ:qãÆ}Ëä™óY{ � ¿¸×I?¼™„µ³˜Ÿ`G׳8ºm6$°ýX6EÃreaý¼Ÿù~ì—Œþê¦þ¹–ÙÅÇ¡§`ㆠlÜ{'�{d%3&ü�¯^Gò%ïo.+ç,⬦zçË<ÑØ³ÈíÜðè#t¶(èÖ�¬ÝZÒP„(7í8sŸëHã.b(µu¿äUÇæOúæJ²c†òÛîý¬[øs—nãÀºOé굟‰�½Èï©zÙÚ[—òÕè ø üš©ï�àÑ‘ßðýSuØ;nsR/|Aé§çðü“ÓpÝúŸÝrù5�— ë:YYYDÖ¨AíZu ¬@jj*º~ɱB!þÃ*$‰JMMÅÇ×÷ÜE…Õj%33›Í€ËåB5HKK+å™5"zß &{§Nb¥µ„fióùá×$¨Òƒ[Û˜(ù’ZÁ·ã{Lz©)ÎŒò¿å_Íç&|ÀàwÖ’cˆæ¡ _r{XYšŠ�Y?½‚�nk@µšÍé~ç<2âIžxl0÷ôiMíê ¹ûË d½–ÓÓÙðÕ}4®Z�FûqÏC6l0îèIËÚU‰îò¿)Hïì¬|³3ÍZ=ƬÓ86óY¿4kÖ‚[Fm=—–Âò�n'6<нúóà##xbøÃÜÓ§Ñá ¹óÓUœ)‡}é«thÞŒVC¦²Í[tŠkÏ�Cçñ~d×%ó ½Æíçøá=üó~G,Å´P<ƒòP@×Ð.��ŠòpnaæOÇiúÆ6-þ€žá—úfÁʲqØê æ®÷?¤Oµó‹Õ¼âFðù“�1$Íäë'ó“óÒµw\GBŠ�Æ­›â€‘˜VÍñÏN`ÝŽB/(ý ¾0‚)Ž~|òÙ„VÀ(oFFéÖ3,9ñOϼ‰3gΔÿ¤B!„ø€Áp× IDATת�$*++ UQ°ÙlX­V2Ò3ømö\rr²q¹\¸\.t]';ûâI7—æD�¼…;š˜ÑŽÎdÒ¢âV¿è¤Ì™ÌŸg ¤oºxj—™’f¡éK“x·“/zâdþ3Ç2×òÎàHÈ5Sÿ‰ïø¸G•r|s]�1»ðuÿ~Œœ½{ÍÞŒ7‹…ËW°lÁtF?ÞŽàœÝL{²�þ’RhÄH'eÖ#ôñ[µ¸yäWL�³�Å‹æ2sÂ[ lêÅñ¿?æî[Þ%Á`"î�QŒÿèêcmîz<&ŒçÝ;¢óªêé,}±+=_œÅ¥!ýßý‰…«ذj“Þ¸�ºÚnf<׋›>ÜLáœQqwÇM={_¿ø1ÛÚq×�Gzgs‚/ùÊS0yY‹�Åqì\Íú4 Å-–Æ ®‡*ÿQÆ8žZ�Àœ—ã 3^æ_…s+‹—œB÷lOïŽ>En4P§Gwj¬¬^¸"o*m)ÛkgR8£{p>­Výðç Ég FCuRç�dÄä\ú~üwW­¸*-'Ò1÷ðx”k¿€Q!„×X…Ô5ËÊÊÂÛǛ͆ËåBÓ\8�À ‡#oÄ#''‡ŒŒŒÒ�X×Ñ ÑÜ= ¯¯ù‹ß&ÎáLŸ{.\?¤göäEdª �çéIMA»ˆ©ÿû‚¥-ä×YÃé{(€�[lXš¼ÎÄ·ÛãS¾¹?³3a£—¦¢ãxnÆ,Þj|¾øyûn=¨k�¥×¸Df�™É‡7?B5 �ES~ç”f¢ÉK³™1²^¡rî=¹íÞTkÙž/ŽÍç�-¯Ð¤™‘êíïãÁšiüôÊöBË»bpÍóŸŽ�Ÿ0â‹­äšêóÄ/Ëø¬“ß¹$³Iëîôlü Ín�Èê÷F2ù¾?y8<ÿXƒ#àÚ7�iÑ�±`óû´ñ-ï¨FÆÎiX¨Z—‹�S'³În$îž{¹±T³º<ªáS0L£k8µŠû†¹"bVà�WSÉïÊŒDÉt>!„BTH•ž‘AZZ¹¹¹X­VzõêÅ?ü@—.]Î%P¹Vk™“(ð¡ÛÀÛWm¬ûáG¶äŽ~œ²§[Kî¿§ð´µËÓOÏ噾`»Ã�q‘³Vñæï³¾„ý£®YÌÙû™?úi�šÁÞ¸�˜ÜܱxzxóD.®4m¢ÙÈïx½C0JÚzÆ=Ò…˜� ¢[õãáWþǬ5GÉ)M®¨�äØ p±st?5lHËþ4æáé)hèä?Æ™"1)aTõ/Ç…§©/Î[Ǻ5+ùkÎ�|6¼ó>eDïF48•CRœïú`2cp:‹/”¢;q8@1›1+ehoŒã±w´èqÚu¾‹{zµeàTèûö³´w®äÍGÇ’ÿ._>P׺Ùüv<�[žF#žõà‰ÛC9ñÛ,V_”å_™Î'„Bˆ’De¤§“•�Mvv6N§§Ó™¿6*ïjúHb"º¦•#‰Kû�Ü]ˈsÇOü°.ï*Ⱥj2Óö¹ðèx?wÖ,Å]ÑŽóócóÝ�à›¾`î²I �1‘»ñ|}E…mÞZÞ˜õÓ‹x¦]cz=ñ93Öœ¦JÓ¾ |ì)žñ%^~õu^ЯbrÅ·5¯,ÚÎÚŸÞáá�1fphÍï|óîãÜÞ:Šˆ&ùj]êå׎èvlvÐÑ�¶s£�EÿèÞÕˆŠŽ&ªŠù¢ bÅì–w\VŠ7qMhÖ¢ ñ}îåÉ�f±~õhºW±±÷Ça û6±„M\ÅÕ¤úúá«‚–‘FzqOˆ3�Ô,Å×?¥ôíA!¨Ï׬Y÷OvŒ"¢ÙƒŒY‘ÀÏ÷²æ­Gø*©ïüo0Q�Ôýû9­Ö¤NtÁ4X#Quj¢žÙÇÞ”²½Zd:ŸB! TXa‰À�Ž;FÍ5.º==+ ‹‡99åæ15åþûbùüµ­LûaoµjÅÒÉ3IÔ|¹eÀ­„]ñEº“}ãâñ™' ÚÝŒs~*oMx’Å�?fû¨‡x±ÛZþ×Õ¿\{Ë”?f+ßƨMÙjÞˤEßpO´û-ì O0îÇ û¨ƒhÒÿeÆ÷=7‰m+³hþïüüÓo$lú�=S0oøƒ‡/—|*žx{)€‰Vo¬bá°°ò?.À=f0ÏÝù‹Ægù/ 9=d0Á×C`ÿ�)µ¨UEå¯#û9섘"ì®#û9dct]¢Œ¥oŸG% îV�»õ\»œ5#yäËã´ýø†D�Üìt,xœ[ã¨ànqGÑ3È.ÕPìyY¶4p“é|B!„¨ ‘¨¸¸8lù#Åñ¯R«ÕJƒ ÊÑ‹�ú÷¤¥›ÆÉ?áŸ33mN2ÝÄ€>W^’ܺåc½°�³J$ÆŒæŽüý ¼Ú¼Î„goÀ͹Ÿq?Íï—Þ ¶òcvngþÂD\˜h9âmî.’@�ΙÇ/Þ#ªŠ%”¸®÷ņ̃ÓY·c.Ãë™ÐÏ.fÜÔ=—)kiDÁÉ‘ƒG.±WrîcΧo2ò™øa{I=ððCAÇ•–ZüH†¸ºL�i×Ò ýì?,ßVt›i�¤åKØá4Û¡MÞÚºÒ¶/Nî:Þ{ä [¾ÁWÃjçO�UððòDÑsÈ9·XP'';]õÄÛ«lo{Óù„B!*$‰ºãŽ;سk( ���xzzæ�\UñòòÂép°iÃîºë®ò[ãNÅ{¢�\À¬Q³XxF¡Úmèê}…'È\ÅÞbu–‘è!ãù´oP¡Dƃ/OàÅ&´#?ðèãÓ8^æeŽYÏ =CT‚Cƒ/~¢;™ôÝ l:Px�FîI¶-û…æl+v„J©ÒžÛº„¡¢‘|2¹˜ipú…Óü”`Úv¨�‡æÿÉö¢×ºhœX7�ûR+(ÉÊfýÄwøà³Ïxï‡ ØŠk¢ŸfÓÆC¸Pp ¯NpiĉʡøÓý¾¾k{˜øÉì¼â2ÿá‹/—aõhÍýwÖÍKvJÛþ"V6|øŸlÁë_?š·ÏY^ ø×�!L?È®½  lìÞ¾-´õË6’dwjœÞoÇÝèW¦ã…BñßQ!IT�:uxî¹ç˜òã�̘1ƒ´´4‚ƒƒ1™LlÙ²…éS¦0tèPâââÊבÊÍ{á¯æÇQ³IVóöcº¢ªäúæ=7ˆÏ¶Ù0ÕÎ7tå¢Z–&¼øÍ+´ðÔ91sÃ&¾üHMeŬ†nlZ±†¬Â·9Ž2ç©ûøßÙpª¨ çœ&%;/õÑ’f0¼Çm ºg(¯Ï¼xÝSîv–ü“„¦˜¨uîâT1š0*€ë'’ ßkõ ¥“�‚sÇ—<ùéÆ crwŽåá¾}h_¯Ï­,~4²TŒ±ô¿¿)ÅÉÞ1�òüŸÇ¸0wËf×÷#xkaºêO·[â)ºU«¨9k¾âñaÃ6lÆ gÜ;è),þø±üß cøÇ‘W9\!à¦7y§g §¦?@‡~/0zò4¦Ž›oâ³�n4ácG¼í”¶ý…l›>æÑ�÷ÑäÕ1 �¹°Ì¥©ùÝÜY+�_>ÅšS™œZýÏN¥Nÿ{iQʽ™EÁápðF׉|ïZFßú‡C¦õ !„ÿ�UX�èøøx5jļyó7nûöí#(8˜7æûï¾#""¢zQè5�›CfòÝÉ,Œ�îᾦE÷O*ŽÆñi�ñð7ûqºÝÀ‹ß¾M‡vÔukô ß¼1�Vϯ`î3ƒÓf>�×-ÏÃTƘ ÑÜvÞY»˜Ããî¡KöPîlâ�õø6–ÌšÉr[o&ÍéÎÔ¶ò{öRF=÷Z·–ô¸m o<2Ž^_¬æÍ Ytó-t¹¡îY'w³ê·éÌßíÀ\w8/Þ~.‹VªÄb`qâAÆ?|;™]"!°'o¿Ü“ Èùßgóè8ôw–¿ÔžFõ§·XÂÜr9¾õ/fL[Ìþl3µ΋mŠN;, õFŒå�]xîïM|yS ¿6ëD»Øp¼´TmXÂÒmÉØ1R­ß'|tWðu±Në¿GǶg>ÆýQd4ÐÁÖ_'°5ÿ's›:<ýLgÀÍCSa|a8¯Mú„'ÿÐÐQ07¦ÿ§£ùü‰f\°¯niÛ°máÓG>d× ¯²zD}.Ê‹ÜZòêOŸqø¾—i6ÍàOû¾dê«Íq+å£ǯ¿þzAU>EQÊÿ¥�B!þµ”À?ÒQòÆ#G½dã][7rcËv••}.VíË÷ÍùxçJž­Ux2��åOÖ#~ô š´�ÏÖ¾`ª�mÖ]øß1WëOÙµüi¢TpîKß–�1ÿ¬…æo.gÙ«7rÉK}ÇFuoÁÓK2ðló>+ÿz�¸Ë]yUp̸Ž3÷å µ„cÖ¼ 8Eõ$2þ1¾˜ð6ýjØXýNn~kÉ0E?Í’]ŸÐFMbÙ¨yyÔ,ÖÍÂuîÚOÁàIÛ»žâ�w£mHá(\š2ˆÿÄÞP°tþн !\°sdÞG¼ðÊ—üº)9oa^@x†·âާßåýá-”oÚ %²Çx’ƒf^âxº]I¾[XîAþøôÞû+Nä¢î3¢5w>þ&o�ˆ§Z)GÄÕ¡å¤päÈ)rLUˆ¨†÷e¾‹(mû+ã ãÔi¬žA{]½MÅ6®YA½¸¯ZB!„¨|��¡ oº>“(qWæ1vïJ$M³Cí`Ë#/ÎÌdR¬½1]0$c'ýØA?C–Ó€g@5¢kUÇ÷I‡3ý(ûޤ�w‘‘Áx\4“J#;i{§�­¹áMíÅo–ZQt;g�ìãPRVÅB@X4µ"|/}â:!I”BñßS8‰ºz_ÍŠ23x‡Ó yx‰·½ƒ +¶P…ßð—|èÅçò­N½¸ê—h¡âZ—Æ¡u¯ü¤å¥˜ ¨Ñ€€W¯K!„B!JR!…%„B!„âÿ I¢„B!„¢$‰B!„BˆR�$J!„B!JA’(!„B!„(I¢„B!„¢$‰B!„BˆR(õ>QÍß=^q!ÄÆØÎ×:!„BT&‰B!„BˆR�$J!„B!JA’(!„B!„(I¢„B!„¢$‰B!„BˆR�$J!„B!J¡Ô%Îÿ_0ªYÐtR³5œÅ4QT/7—]#ÇUyýˆ«Hž!„Bq®Ï$JU‰6â©è¤�qpÒ~™ö&Q�Üt�S)NΖ5©Ég®åÇìÛ,˜Îf1x\:ÛµÂ}™è×Ã�aõÍ[Ï}žÊò2ôyÉ~® a!FüT¥„Ûu4—NVŽ‹¤,�r>ô×Ô¿ãùB!„×Z…&Q·™']Q»„„�ŽUâ튧…ùÑLuñËÔS¼H¿äù �ž¼?È›šØ=6…SKv±\¨úÅýF5÷çù8FMcß~‡r¤^:¼2õsÝ0¸1øÞ*ôµ\¾©-ËÁÚY|·*‡�¹•Ze¸îŸ!„BqÍUXu›yC-ñöñߌcÈà¡lØ´€Ã—]º†ì»ÏÒñýânQiaÄœÜx–‡ذUJ?×§Ó'¬l͸8Á0U‚MÔö3Ѿ…?­bÜy÷dzÌM»A–ÿíùB!„×F…Oç;~ê('Oœ¼àw61dðPN%'V5 6Ut·W‡¢âå sì´“ë8¬:»R¹U£øq…Ð(o^»É›¦¾žíáI´lNÉ ŽB!„ø�©ð$ê䉓t�ïyîç?~�Þ}{qìøINž<Îs/½Æ=wö«èn‹¥¸©ë¯‚Íɾ³.ª¹Ñ8Ĉ·ª“–jgã)ÎŽsº8’â"ðò3îa$ج:õ hº†]Sp3@N†“#Ù%e !ÁF ��î$1G/¶ŸòÄ}¾+…�P7bƒ x)'“ll:¥aG¡J ‘`¤�up²<ÃhÑI:˜ÁkKMÌìíŽg m¼²™�yqKÕl ¦º™h_ªNZšƒ­‰öË®}3y‰‹0á¥btºH4t-#‹C»í¤J± !„Bˆk®Ò’¨?~�!ƒ‡žK˜æ>ùð�Êê®XºKÇ©ƒb6qw?o:s;ÇÊžLðð3Ó¯­­|ÝÑÓ“u“²(9§ÐÙ»9�w ´jíCg?8´-�©‰:šædk–…n1žG{ÐÑ+—ß‹¹Ò®V×B}8Žç0ïT%Åm4óðþܬàH³òó?Ù¬=«ãäÎí­¼ù¨¯‘�漦öJ*£§º©x)€®“}ÁH‹J“ø@>oiÂls°piv�®ˆªéÁ –:w $È�£ÿ8 �.©´íÈû��¨Yv~Y—Íê ÝÃD‡¦^ôŠðâ½{žþ>�µÖòöU”Æ?Û­¤Çxàe¡…{.Y/nU»ž…(ìÇrXxº|1èN‡f“‘Ûâ=ˆ¶ÚX´ÓIºÍÁY™)„Bq](WUEI¦•ûjð¨B²{/þ7m1¾ÎãÔ«˔鿑�°‘æÍš3ùçYü4yÜEk¥*�`ñ ç¡tšœÅásɃ•5i*?÷÷$,ÔBkß,_¢BÒ‘~O4âÛÈ›Î~�r,—ß6»òÖ©:óÎx2(Ð�Þõ ü±ÎÅŠ‘NõLÑÙ°-—£—».cÜ~1Þܬ€ÝÆ—SÎ0­`î×K÷9x�?¼]§„…Må¤Ò<ÎBU´ [ Í=3†yñLsn.'?Ï8ÍG ÖV9Ø}ÌÊêSþL¼ÝƒØ6>ôÚ~†_ó‡óÌÕ¼y¢‘£ÃÎØ©§ù>¹ p+Ë÷ØÉ}(�;<Ú8‹õ«�håè«89‡rXšåÁ-Þnt®©ò÷®"kÂT3]ê™0 “°=—ãzùî/z^™x5ÀB×Ô,FLÈ`K…N»B!„å¥^¾Iñ<È¢ƒe ·÷lOhTSîhNHTS:vˆgú¬)xzx°çÀQ&ÿ<‹O>|ƒ“'N數ÝÉ+² %"yr�ÙØéTU}JÚé hvþÜjÇ�Bl¬5ŠœJ­b¡K¨6ì*’`UXÜ �k™ñ²ögóG‘Å3®ôƬ·WβŠB`°;wöäí ¨ºÆúÕÙl>·BÆD©�{0“‰G..N‘º/“_“t³Ýëò_˜ Z¨®BîÁlf%_x”n³1}y¿$d³.SÉÿF ¬}•ÀagÁn*-ê¹áUäfc˜…ø€¼Xæî.xnËC~~«šaÃ?Yl•J!„âºS摨¦î›èܾQQµ˜¿÷k÷ŸÅápU3šM[^5‚®]ºVd¬e¦;lK*fèEÓȰFwSùú8º=‡„vfZ{Ð3,‹¯Nœï¯fŒ…Z*¤íËfyN%Å­‰ TPÐ9|ÒAqÛ4%î·r¨ƒ™:eÊÚô cuŸbo:—è.ëV¥òj‚ó|²¨ˆ­¦¢¢sèh1kžòdëq -Ì@�j&Œ\Ø ÂòŽK4¯o¤[¬™ 'lyŪ‰øz&Œº‹%[md_îD…”*nEÅß’W9ðlVñ£]Zš“ãÔ1sã°æ¸8c/Ò±Q%Ô[EÕ]¬[“Á¤M¹lHÕ/¼øW {çen5›UaJlñºÉCEܽ ø*�¢Î[`Ejö&eíë'wžÌaÑi/ v£s”Ê¢ù±Ìt‰1¢ê.–o³ž¯¡Q1è)ÿÒ ‹…B!þëʾ&ÊåÀÍÍ�Ì,mêø“ur;Í£ª‘›“ƒÙlÆét–X…ïoG¯KŸûÜ’åJFM FB.±Ô§ò¿Ñ×X¹%—Óõ< ‰ñ ù+í`¶®Ô\þH,}W|„’WfÀYRÑ—ŽMÊ”Dé$ü�Ì3E÷‰2™ylP ‚ „»kì)š@(`ʪRTsI¯:»‹ãvpæä¿00ºOW–D•±¯KÑ,Øig`°™æõÜñÙ‘C:`®n¡ƒhVæ®JR1è.ÇåâB!„×D¹ K¸\.6l\ €§IgËÖt]ÇÏ×€Yö�e:¯îбꀢàívùö‹Ð52¯áëáæŸõd@€;=£UVíÒ¨c¡†ª³[;+©"ºŽ-ÿünƼћ‹˜T¼Ê¼ ®;ß/̦Ó=^ToäË£{ì|x H¢¥ëä8t¶-Oáñ�®+Kˆtkþ".‹YA…˯'+k_—‘¸3—íÌÄÕ°ÐÚ#‡y9 7Öw'H�c;sØRx±Y%Å „B!®庤¶;lD׬M�Z1Ô©CdõšøWÁj+ç<$‡“ÄL…:UM—Éô¢#Ìø( e89TL ê«F³óÇV;E¥e}7¼ ¦{9ÌÝî¸â‚e¢»8�¿l �Zìk 4Q³ŒSù.%çH&Ÿou¡«Fúu÷¡¹{‘š‹cé:: aþ†+Ó]O×!ÿ¸âî“¢*¸¾¡¬}]†––Ë‚£:¸¹¥¢˜ÜèRÛ€ª9X°½HÁŽJŠA!„B\ÊœDiЉӧ“ÉÈH#9åÉ)§8•’„ÕšKzzšRŽJ šƒåûò TkèE§¢%Ñ Q},<ÐȈ8º'—Ý×x3ÒÄí9lt€WM í£,t €Ü#Ù,ºDùô ¡»ØŸ¢£¡P#ÜŒßE nlh!¬EK¦ñÏÒte‚Áß“ç;­bçbË'. j”;Ñ%¼ê‚ªºsC€z>éÐ]l=šw\hMwjs\ÝvA,Y�¥wyPž¾.Gw±d‡�\n¬ãF•wZ{‚ãdóSŠ6®¤„B!Äu¡ÌIÔ1-šE-Åh4JHHá‘x{û²dùJŽiÑåKgëÚLVdƒêeáÅ;|é¨ VÁ¿ª'¯ÝíGOÐ2r»Ö~Íבh¹ü¾_CwsgHwª¡±z‹•3•Þ³Îæ½VÒup«éÅ yE ò(„ÔõåÙú Ù•”dêÙ¹|¹ÄJªá7ú1¬†Bá|íжll`òäé–&<ŠïèÉKwVaü° FT?ä¾m9lsä7üF#æBÇý<Ô(o�¦íûmä©eíërÎîË!×Ç IDATÍe� <#ܹ¯¾;ŠÎ–B{CVY1!„Bˆk¯Ìk¢6:šáJÙ@ʼ…´ó ‘\ª‰Î(¶8›–+0-#‡·gñ½Í›FU½xwˆ'§NÙÙ—ªaS‚ª˜©¨bœ™Vþ73�¿‹«�}Õå˜8ãI¨¯‚–•ÃE×U’¬}™|{Ä�§k˜¸ëî`âöYÙš¾AntˆTذ0“½�|éf¾ü¹Ê"y{ãó|”‘[{ø°äûtò_Zz-vgl/ww â§9,<èä´K!(Ø�ÎõݨnÖ9º)�I…v#ÖÎfóñ2w¾êìFËnAüXËÊÊ“.4­ë¹m�ô#|±ùÿØ»ïøºîúþã¯sîÒÒÕÕÞÃÚòž‰ã™AÎ4P „$P ´Pú£eµ”2HI ¤$¥Ì–�í`ÇIï½ä!YËšÖÞûîs~ÈK¶dKò•í�ÏóñÐÑî=çû9Gyèž÷ù~Ï÷{~FÂɶu%ú�‡M§4n™aå¡ ŠÏÃ[c¬û5U5!„BˆëoÒ!*ˆÊ‘À"Ž…²žúêûø«ÿörß2N·�ž`!!áüëÞ?Û‹øÕÞ!J&°þÒTs×±©ÛÎÇ£ åäÇ^„(´´/½Ò�g…“¿œi¦ ßN�®ÓÙâá÷¯ôñë*#ÿ¸jø­úT\·ëAÞx§ŸÛs27ÚÎß/÷ðÉÍ^†5:§�vñx¿ƒÏ¯t°"ÓΧ2Ïoêîóñ§í}üô�—®‘;¥r'OôGð¥6gÙøØ™NNÍäÐ�>~¼}ˆªàÈm&×Ö•hì+öÐ3ÝF”ú+†Ø>æœõSUƒB!„¸Þ”˜Ç~¨£ ?•Qÿì“—}séñ#<õÞ´kQ×¥W¤‘$»‚I×éÒЫ]f‘ÔëÈláÿ=Ãý?/ü²�_´^Ÿ2ÂÂTL�þ³³Xl<ý%·¨×·.«ÃHšSŪ@ÿ@€Ó=ãù]*„;�$;Œ�ÆÎÝ�+n4ɶBëF¨A\;Ï­©¦ pÞõ.C!„!”ö…Ÿq67]Õç×”®ÓÝí§»ûzreÉ…áÜC5ƒ¬o»ví*&•´)6�“U~º=NVhN0‘cÝ vª'º¸÷@€ò ¿ÔéïõSÖ{-Ú ­¡!„B¡^5èÏ‘ηVZ°jÞØ5DË5|ÜÅëàéOÆð㇣øÌ4uÄĘL<²ÜF¼Õ^Çõ´„B!„x?{ÿôDÝÀÔˆ0þb¾…D§™åyfŒ:§öõðBýµ�0 Ð4Àž°ò½ÙFx8Žü ‡;44‹�Â\+ó"ô!?Ûææ}С'„B!Ä IBT(v3÷,q�©‚æ °kGßÛí¥ÿšW¢±}c_êŒàÉVfØ™yæ=¤¼tˆ_nëg[—Ì'„B!ÄdIˆ �`K?Ÿ{n§ªÓÕ¤g“L-È�½ÝØÛƒ=Ü@l˜‚Ôhï Ò¼òæB!„BˆË“ ºNgwà,¨;:ƒý¯}w˜B!„Ödb !„B!„˜ QB!„B1Îwà“§¢ŽËÚà ‹-¼æí !ÄdÙW}½KB!Äz_ôD;v½KB!„Bà}¢„B!„âF!!J!„B!&@B”B!„BL€„(!„B!„˜ QB!„B1¢„B!„b&¼NÔû“�¾Ž^<šŠ G” ›a›ùèèBÓA1‡iex³]Ý @±„ã C¹Ü~t/}�}x4Pm‘Ä8LסfqVÐÝMKKÝ^‚ª[xñ ±D˜/û[B!„qˆêë룹¹™þþ~�F“‰p‡ƒøøx"##CÙÔÄhÍX¿‘R�˜ÈXý(÷äÛ®°‘N×ñ·xq;`H¼‰Gï��SPñ7îåõ] x� ,»ó£ÇŠ*:½'ßå�;êñãYrß½Ä8®GÍמî w¬,7BŸ§¿‹²½ÛÙSÚÌ`päKŠÉIƜ嬜Ÿ†ãF¨U!„BܰBv¹ØÔÔDEEN§“œœf̘Á´ÌL¬V+555œ:u*TM]%? åUôéWx›ÖNyE'Ú¨/ª¸f®æ–LŠ¿…[Óc7='زï4,¤,^Íü˜Éô …¢ækM£óè~ÿ‡w)¸Rá×¢œŠß~ƒÍÅÍ ©.2 —°rÍZn]±”¹Yј½Ô|‹7ö6á»Þµ !„BˆZHBT  ¶¶–¼¼<"""(**âù矧´´”ÈÈH222èîé¡»»;ÍMžI´K%Ð\FEÏå/ìƒ-TôèX##±ŽÖ“£8È_±’üp•@{›Œrñ­uqlë~¼`M_ÆšY®‰ŸðPÖ|Myhmë¹Axª°÷´ÝœÈÒûäž›ç1+/—üs¹ùö¸oQ&‚t•¦bð}B!„→ÕÜÜŒËåÂl6£ª*Å%%ääPTT„¦i¨ªŠÃn§««+Í])©1´NÊËÛ/s�ï§¡¢Š~,¤$E£�uMmÍà–Õ³ˆRƒtßÊžzï/é8º•ýÍ~{6+Wæ1©`âšÐñ´Q_UFñ‰ã+.¥¢®•^ßÂCpˆÎ¦Z*ÊNR\RJYU=-½ÞKjòõwÐÖZM]›øèj§­­�Îÿ¥•øûi­¯¤´äÇŠORQ×JŸŒ:¼½´·µÑÞãAýÍœ:y‚•m¸/[x€¦ÚÓxt{ö|fÇ\üL𑨙3H1ÁvZ:%D !„Bˆ±…ä™(·Û�%, ]¾ø ø¼>�áOt]EÁãñ„¢¹« ž>�˜â6Ú*ËhZGÊh£ë¼õ”UAXY‰:u'ÇÞ£9y1·ÎoæÕƒmoÛEÚCk˜f…@ûÞ;ÔŠ_u2sÕr²m“í qÍžfŽlÛÆÁšn.ÎLŠÙEöâ5¬ž‡yÄ+>ÚŠwðÞþStx/ŽLFÂSf±bÕb2ÃU HÓÁ7x³ìl ì hãË¡àœs[–0œÜu7�Gw°íp5]¢˜]d-Xɪ9‰„]ðó`ã^ÙT‰–´œ�.õ²ùÍ´ø@qÌ"*+Žä1o ÉXñ1[ì!hrŒþ?½ÉŠÕ¨@@ç T!„B|À…$Dù|>L&Á`]×ñz¼”•Vb4д3ݺŽßiOĵ¥Cx&Ùqim­¦ìôRR2.�)Ï][A­l9¤˯0$ÍHÜü5,mz•��lÛ‘FÜêNl=B[À@ÔœUÜ”vÙ=\³šõ^N¼³‘= ^Tg ææ“â²¢†è¨=Á¡’&*w½…j˜Û¦YÏï»j;oî¬dÈè"kÞ,²œX�:¾¾6jNž ¬¡ˆMoyàÁ…Ä©*1ùËYíª£h%Ý8ÉY4—Ô0sŒóÌ,†>÷½Éú¢‚æhrÏczJ$ÝM×éR­âÔž j÷rß¼˜ó³  º9±·œNK9ÙQ„™ã¯8|Q5Y°›,c¾®uµÐæÓÁMl”Ì,!„B!Ʋe¶X躎®khZ8¢ü~?^¯÷ò;šr:ºâ$7/‘ý- T—ÕâÉÈÑÛ�>@UÅi|Šƒ‚¼Lîò+ïVuQ¸úf^ÙBuõþÔFWGcÜBn]”tQ¯Îõ«Yk?ɱ&/ºͼÛï`IÌù°�œš†KûëKú9U\Ų̙8/§+kÒUâæßÁ‡æ¹.˜Î=�¬Ü4쯼ÆÑÁzj;æ§âHÊez„—òý•tc#!»€ŒeÔÚ�²ýXÕÅœÝËòäóá&.!�ôØ-¼øV͇÷Q–{3g¶UTT@賓Ò9“u�,%ñêN. ãë>Åî-ÇèÐT"gÎ#orã.…B!ÄDÈB”Çã! if³yxˆß™`àöxn€ àÈÊ'}oU§Ë85˜ÍLûù‹f½¯Š²¦jdy ¨ç^ÃóXµ¢�ö·Ëioó‚9‰›WÏ'.$g845«®ÙÜõà4†¼F\Ñ÷¶˜HJMÀTÒ�¿§‹�á¥ûñx‡‡eªê(=4Æ8–<üK•ñ�–òrº40eÌeAò¥½CÖô¹ÌŒ©`o{#µƒLŸé±—yó& ´NNlÝO­;€w ›ŽîA‚æ(²-ã–yi\M¿¡B!„øó’K|�ǃ¢ªçBÔœ9s(..¦°°�`pøÜëõ^Uˆzîù®²JõÌôaägZ©.o¢¬²�sÎ3Óéª,§5¨�“KœÊ„f—3†Y9·^«®Ÿ{F,$BQ³É†+ƆkÄu4MC×4Êðp9 À¹Ûñq¨�=´~—m¦%ÌÍN"ò‚…Ÿ”q(@ï§¥u•¨Ä„Ñ‹â$1Á†Ò>@{KÚLÇȃÕ8’Çšwe:ê¨=; ŸÑAbZ:)qÎc=+!„BqC Iˆòz½#BTNN999èºN 8÷u5!ê©Ï<>ùµ:6ÿj#¥¾³ñÁLZ^ŽŠbZË+è,\HŒÊð:K•]h†xòs]LhP—§Ž][ŽÓ©YˆŠ6ÓÓÙÌþ-GH¾o!ñ!9Ë!ªÙßK]i1¥5�´võ2èñ¼x‚‰ß©ÄÏ_Í¢¶·ØßØFñöõï´àŒM$%%•ôŒLÒãǘ¬a4ú gÂK×ñ·øßòÑ+ºÝè@`p÷Ù^±³Œ6W“¡Ô8æßý �~w?ÍÕœHÅŽmœìÕ±eÞ̇W‡sôÕõm?Â{RxpYâU>¢š=§Ùµ~E~0Ú‰KÊ ÕiÃb2bPUè¯ãhy—¬lN`á=!½ê$ÅåUÔ4uÒÛZKok-%‡w“Ãâ•7S7žd£ÔtЃƒcÔlvà4ƒ¦rqžb0 ^ÕcK&£c  ‘”Œ\få³áµ�Ô•ogkB"žá˜XˆB!„!{&Êf·Ó××Gddä%¯{|>Œ&Ó 0;ßÔ8òs£8z “ÊòF–$$ ¯³¤[˜–7 û¸w¤ÑS²•íUƒ`Ïá–¹„[–¬œÍéõEtßžÔY™z5]'¡¨9HÓáííð£Färë=«ÈuŽœ+=xz�âŠQB€j%.g>«sæC`ˆŽæN××PQYC[G9;Þtcxè®HŒÎˆÙ` aáýÜ;Ã6�0u ®æe¡¾x€Æšz<3¦c½òfB!„â($ƒ–âããÏ Ù�Õf#ŠæBD!*7ŸƒÎ`] ÍžF*kÝ`Í  cüS ;޲yo=ÂÉ_q39gÖƒ2%.dõœ Z/ÅÛvS}ùÕ`§¾f­‹ºútTf-"ÇyébSžþþKÖŽ•ÑFLj.soº�G>r7³]*º·�âÊžKz�.¡Fà W�þ¾þ =s6iZ/5G²g÷^ʺÆjQÁfFt¯¯,%„B!Æ’5}út:;:@Q°Ùl˜ÍÃ×EÁl6£ƒ4751sæÌP42JD6)&ôÁzN¯¢Þö¬¿(XmÖK‡ªi]”•6F$¡À�MÕ”ÕvŽÞC–DVŠ �¡!÷•CV“\¨èôÕ×Ñ9ú‚V ¶ÕÓÔë QÈòÓZv˜ÃÇŽq¨¼}ø/᡽}8Ô&½6²B!„ø³’ͲeË8qü8%%%x<ìv;ƒ�––ŠOœ`þüùÄÇLJ¢¹²1-/�0ú)?V�[q’›—4Î1Žêöl¡¨3ˆÁ5‹5KR¹dÀž1–ù+�`Ò¬ÚÅÖ²þq„Œ)ªYqnW�öæVF ¬Ô¨Ùµ™ãVô€÷™7èC§Øþæ&Þ}w;GÚFŽ袡e•HWĹp¦¨êðsKúƒCµBTÞ RÌ ugçÑv.Þk »„-6ðÊÿ¾ÌîæÑ#Ï„¨ÑäæÅbD£»x;»ë. g~ºJwrà´ i™)!y†M!„Büy É3Q™™™$$$PYYÉ¡C‡èêêÂf³‘˜˜È½ëÖát:CÕTH…¥ç1ÍZÅÉ!?jLy±ãÉ•:•;Ør²ÍÂՋHãªÛ3‡5 ëxiO3u{¶r<ñnfG^]v�TÍJYyIlm ¯ä]^÷Ï ;ÎBp “†ê*š‚¬½3•Š×¶PãoäØžc�OZV>‹f–°þX û_ÿ?ê3§‘N˜üCÝ4ל¢®[ÃàšÅ‚œ &csá²*œè£xÛ&|)á–Î’iXà XqS=¯n«¡qßëü_C¹©QØ A;¨j皊Ùá"vìM/ÝÂì *úr(˜l‘ÄÚ.�ꨄ…G~ ›B!„6äæ»B!„BL€„(!„B!„˜ QB!„B1¢„B!„b$D !„B!ÄHˆB!„Bˆ �%„B!„ð¾QsgϾÞ%!„B!ð> QEÇŽ]ï„B!„xŸ„(!„B!„¸QHˆB!„Bˆ �%„B!„ !J!„B!&@B”B!„BL€„¨�æÇëñâ×®w!B!„BˆÑ¯w×MÐMW[+=¸}ŠÑŒÕá$&.—Õpíë tR²c+û*Û æ\îþÔZ2¯C)B!„Bˆ±MyˆÒ´á.U½1:½tw+%‡p¤¼�^Ÿ~éT3‘)Ì_´€‚8 ʵ©Š®c[Ø^ÖNPµ›ž‚+,ë™Æuß½C`�p`¹1N£B!„X×$Diš†Ùlžê¦®È×~Œ·ßÚK퀱Ç$‘–C„ÕŒtÓÛÞH]C=õÇx¯±†º[îâ¶Sß䦩©‹ 3nãÁåÉüb4:�nàÅ#fnú‹{™qmb�B!„btS¢ü~?>Ÿ—°0ëT63.ú@›7î¡vPGµ§±hõ 楆_�ýuÚ²•C�}œÚñ6áθ9É4ÅÅùñùt@Å銼è—⡵­�¸©­A!„B1.S¢¼^( 6›E¹Þ½'nNíÙMõ Ž–ÆòˆB×èýKÆðt–Üù!xý ¶wQRtŠ9‰8ÀÛK{¯ÌDG†¡õ7S{º·)žìœ8ÎGEÿ@;Í­]ô ù*&¬áQÄ'Æá4�<¾¾z<} øÏn×IkÛ Š†ÕâÃ=ÔB]›øèj§Í£`°Eí˜â`'„B!„Õ”…¨@0ˆßç£/ЋÏç#  * N§‹ˆðˆ©jvTzoÇkÜèIš¿œYc¨sLñÌ_µ–Hw$ÉQ„�É=ÁƼ²©-i9]êeó›hñ�â˜ETVÉ*àiæÈ¶m¬éæâG®³‹ìÅkX=+ŽáÁ�A¼ÎŸ*|çÞÓräOüñ`ÊfÁ´Ó*÷žy¥ƒ¢�/S„‚sÎ}|lY‚L­(„B!Äu0e!Ên³°œ�˜AÁðãózéêê¸Æ!Jgðt­AÀ”Âô\ç¸&‹0ÅL#ÿâ º9±·œNK9ÙQ„™ã‡'�Ð{9ñÎFö4xQ�,˜›OŠËŠ¢£ö‡Jš¨Üõªýan›fTb –³&i€º#8Õ§•·„9‰fCQŽ "¢ê(Ú_I7NrÍ%5LÁ3¾cB!„B„Þ”>e4 ᆵ¿—®®NŒF#Ωlr:]]h€•HbØUìJQQ½§’JçLÖ=²”Ä æËÐÚNr¬É‹®F3ïö;Xs¾¯(95 —öÖ—ôsª¸Še™3q( áÉyLOêÁSz�S} ö„\fL·�Û.Þé¥|%ÝØHÈ.`†L,!„B!ÄuuMÖ‰êëë#>>ëu™`ÂÏÐ�08±‡ ƒè~H™7oD€P]³¹ëÁi y�¸¢/lg")5SI?þž.zt†Ÿ³B!„B¼¯L:DÕÕÕÒØÔ@gg‹¯×{æ_‹�Ç‹%Ì‚Ýfgphï™ïÃ’“RHOϘP{Ï=ÿÂdK ˜Lè«A%û*ös†Gr¢åÒŸ›l¸bl¸FüPGÓ4tM#  ô®¾ !„B!Äu0éÕØÔ@JJ*š¦144„ËÉÐБ‘®3ßÿ›››CQÑÑsß§¤¤RWW7áõÔgŸd¥*ßþ%›ªliàê×}2ÚpŒ’¡ð÷RWZLiM#­]½ zü/ž`âjÛB!„B\7“Q>ŸŸððp‚Á QQQ âr ÿ{öû¨¨(t�ß;#œø|¾+72*ávzÑz:éÖ á*§µS ÔÑ’�ç4»Öo¢¨ÃF;qI¤:mXLF ª ýu-o“^(!„B!ÞÇ&¢?6«§ÓÉÀÀ ƒ¯×‹Ñ8üodäðÏM&Óˆï­V+�€?”Çp*ÑñqX”^<ýõÔv-!!f<)Ê�Ç«fo¿U�¦ÃÛ9ÚáG�ÈåÖ{V‘ë¹mðô Å¢„B!„x?›tˆ 5 sfÏ»â{o¾iùÛµÉ6;)¦”lÒÃNQî¨†Ù·fq¥).|�ûxic5¶¼¥¬¾9וr—ÖE]ý:*‰³‘ã¼4|yúû/Y;J!„Bñþ2镞žÎÛï¼5J ÒÑ/ 禪*9Ù9“mvrÌé̛˩m �ÚÉæ„H>4+z̃×ú*Ùº¥„¿Žßk l\Ãÿ|øü: bµY/}îI뢬´‰  H�B!„â}kÒ!*?¯€ü¼‚PÖ2…Tbæ¬dIÃìi¢v×¼Ö½”å òH°]��t/�ÕEìÜu”Óƒ†È¬¾ùʽV(Âí h´7·âÏIÁtö5m€š]›9îq`Uzq<¸ýÀX“S\¸[U~þJbpHY'J!„BˆëꚬuC0Æ0ïCwÃæ·ÙW7@KñV^:¹›ˆè"í A7½ít¹ƒ€BX\!kn_FÆx—¶R"ÈÊKâ`k}%ïòºÙq‚�4TWÑÌ`í�©T¼¶…#ÇöƒÔxÒ²°_n¿a.\V…Ó}oÛ„/%ÂÒY² m|áN!„BRœ`‰gÞ]!½ê8EÅåT7÷Ò×ÞD_û™×#öØLr¦Ïa^A"ö Íâ§àœ±†Ûû7³õx#-å‡h)É3¹cÕb¦…‰˜[FË¡&ÚKw³¥i÷OK¸üÀj"s—æP¿µ‚ž®ZŠ»À˜âb¡ŽÌ•.„B!ÄuðÁ Q˜‰ÎZÀÚ¬è7}½ý¸}A0Z°GDn;9RWòéÏ®{׊�Œ¥ëøä‚º»ðêF¬‘DZÏžf•„÷òØl7ÕÄpk‘Ì{à)FŸ¢C!"g-�¦/¡§ß &áVŒ „B!„¸.>€!ê<ÅhÅmÅêýšDÅ9Æ|]5Y±›Æ|yômÌ¢¢ÇÞ§B!„âÚ¸Êeg…B!„âƒEB”B!„BL€„(!„B!„˜ QB!„B1¢„B!„b$D !„B!ÄHˆB!„Bˆ x_„¨¹³g_ï„B!„xŸ„¨¢cÇ®w B!„B¼OB”B!„BÜ($D !„B!ÄHˆB!„Bˆ �%„B!„ !J!„B!&@B”B!„BL€ñzpmøèëèţ領pD¹°Ʊ™€Žž!4s8Q‘VÎoæ§¿³wP¿ü>Œv¢¢ì—9ÑFLl IDAT:Þ¾Nz=:F»‹(û8~%þÚš›iïuPLØœ±$'ŌB!„W%¤!ª¯¯�ææfúûû M&Ââã㉌Œ eS£5s`ýFJ=:`"cõ£Ü“o»ÂF:]ÇßâÅýíh€!ñ&½w6NåÌËÁFö½¾‘2ïå÷¢ºæñÐ#Kˆ­Ï/ØGõ�­l;ÖÈ ¦³ð!Y}™îA?�e»Ø¼§œ6�6âƒ-‰ÂkX–.Ý‹Bˆ_?}tƒ —ër7¬®YAôuôáAÅîŒÂnºQ÷9Ñn´ó,„×WÈþ655ÑÔÔDJJ ¨ªŠßïg``€ššÂÃÃÉÎÎUsWÁOCy}y³ˆP.ó6­�òŠN´±^úðÅFlz"cô©öh,£´ãë(eç–Ý”vøáruœ£Ó_þol­f 1ÙÓÉO�ÆÆíµ¥”Ô6Qôö›ïz€©–ñìP!Æ 3ØRÍéÞŠ-ž¬ÔÈö¢Ù·÷øÖ6üÉ�ð‹_?ÉÌë]¨o?OüÛ¼ãIä£ÿñ+þ:MÅ>'ZÂ�vž…â: ÉŸÁ@ @mm-³fÍÂ`0pàÀŽ9ÂâÅ‹™5kááᜪª¢»»—ËŠ&'G�$ÚÙGgs=3Yà;½[*¨èѱFFBo¾‹^×}^¼: Æ3wííä™Ç[„Noù»¼±ý½z™KV“Ðø.{O_aX ·Ž}{kÄBʲû¸gvÔ¹_^^Át²ö½ÎëG:(Þ}”ü‡/ÝQBˆIÒÚ7ó�§~À¶n Ó¼¿æÕ­#öFý›¢¨UMUQÆuCJLŠœg!„!$‹ÍÍ͸\.Ìf3ªªR\RB^AEEEhš†ªª8ìvºººBÑÜU°‘’ƒA뤼¼}ì^&ü4TTÑ�…”¤h´Ñò�Ï;¬ŒfÌzI§¯¥wx+ï{ˆ»ç%aÇ’»ö$ÕC:ªs:KgE]”~Í$Î[H–UAë.ãdSp" !ÄyZ+oýûÏÙÑ=ö_ȉù–¯óÞ–Íìüíg˜!Ï…N9ÏB1RHB”ÛíÆ†®§�@ €Ïë#¾˜×u�NJ殂Nxú4bT�îÊ2ÆÌÞzʪ‡ ,�¬D•Ñ2”îóáÓA1™1O讜BxÖ zðVfÅ�wØ]€æÓÍøP°§¥�þ|•9™Œ$#ènNw\& !ÄX4Z6=˳{ú‰KŠÇ =B!ĨB2œÏçóa2™ƒèºŽ×㥬´£Ñ€¦�¹œ×uü~(š» :„g’w�ÖÖjÊN/%%ãÒ'tݵÔzÀV�Cª±|Ô@¢Ÿé‰RÌÆ=’…È”Œ –ÝGg—P‰ŠŽ#ùšˆŽv¢VuÐßÙ…—x¬kEñ§5oä?ßOä ¾ôH�ïÿ{ë„oÈh}MT6÷ÃÙg©½Ôœ8FI}7>£ƒ„Ì™ÌÉ�Ç6æ-<�¡ÖJNœ¬¡©k¿!ŒÈø fÌÎ'y”�ô�&*ûÑÍQ¤gÄb=üôþ&*šúÁ–@vª“@K1»�¢×šÇªÕ\8š[s·R~ü$§Zzpkf"¦1kN‰ÖËÜgÔ8}¢ˆcµ éVâ3 Y0+ ûÏW¨ö9®cÐÝ´Õž¦Ó§`�K'Ã5Ƨ—>HsU#=AGb©ê˜çùBþž:Ž+ãtçK$©ù³™›uÙÏÈÉœ{Ý×EõÉ2ªZºò©X"bHË™N~²é$B\+! Qf‹…@ €®ë躆¦�ó!Êï÷ãõ^a*»)§£+NróÙßÒ@uY-žŒÂF¼e€ªŠÓøy)˜Üå£ïÉçïƒbR¨9‰Òj:zqL6'±ÉÓ˜9{&™‘!˜FId`HÅ‚Ý>ÖÇ‘‚ÍnCôÁ5¸Üç¿BŒ 5ñú�~Áþ«¾þ9VÊ÷'±ßÁÿâ‰ÞIpÆüú«.~û�Ÿðv½ç|�¾b rú}üã·ŸbùEÝêzï ~÷ô�øÕ®Ó ŽG­ ÚRYýø×øÚýyØ/¸€÷~�'F™ðÀô—|ö[ðÏþ¿}¢Ÿï|å×” é¨ñ÷‘±¢—Ðz(zñ~ø›ÝÔiŒ:noÕ'¿ÂWžy~VÖ3�[yú[ϰþÔÀùáÞŠJxÎÝüÃ7ç¡\á×ÑLzŸ:† '~ýw|cë Ž5ßâµo.5 iÕ/óÕ'~M¥’Í/<ÇccŸçáâ[ÙùÂø·WŽÑæ» PÅDtá}|õgEÂE—“9÷ú ¥¯ÿ„ýï­œêŽ%¢XH˜{_þûÇX~q[B1B¢<�@MÓ0›ÍÃCüÎ+·Çs„(GV>é{¨:]Æ©Álf^ð‰¬÷UQÖ@�Ì!/Á5£ïÅçó¡Á¶Ãlx[C7X·aW‡èëi¥¶§•ÚŠrf¬¾‹•YW9í¸îÃëÓ#¦Ëd2Ó™Ïö’ !Äø9ýÆ3üìðÑ«¿Ìß®ŽFÝ1¹=©f#ª�ž"~ú­TDÝÎ?±�i‘*=Õûxõ7p¼ä¾ñ­Hþû?þ‚¬³ŸBZ¯þÓ?òóØ’—ð‰�ÞÁ¼4f_'§ö¾Æ¯^?Áæÿü:ÆØçùÖ-‘WœÔT1›1)às×ñê/Þ¡:bk×dâ´åãR}�#ÿõwüí‹UølÓ¸í3åιi8õnªmä·/î佟ÿ?ÚÿÎ<šÍ¹Á×¾2~ù�ðF•Ÿ°ô•|â“÷°(ÅŠ·­‚¯üžïþS5É9Ù}NôKn]Šsû;ôØÆ¾�å¬q\¼Ó §¶í :¨`ž¹–[Ó¯ðé¥÷°û™/óšÑ\3¸÷á;Yšé‚ž*v¾ú"�¿Ä׿âå韑Åág» 'sîuz¶?ÃWžÝBWX·F~¾ ìBL­�„(¯×;"Dåää�““ƒ®ë�s_W¢žúÌã“/P«có¯6Rê;;½º™´¼,Å´–WÐY¸�•ᵡ*»Ð ñäçº.s§S!rö½<1SÕˆiÄÓ× æÈL–~È€û�(éoæXI ³nJœüXmåLxÒ‚/3ñž ‡'Õ ãÂ…ã¨ç�Oÿ’#î8îü‡Ï²â2K?LˆêbõG?|>@�a-¸›» ^æ''z9°¿œÀÒ95ã~øüÍtõYHϺ¸ÁÊì…Ó±¾ÙŠût õWQÊð|šæ?úQf]8?Åï¼KM¬Ëás. (D.}„{s6ó\ÅQÞÙÕÁ=÷Å¡â¥hÏuÛ¢;¹=ñ¢"ÌÜwÿb~ubã>Q“Ýç$�!¬�ÛVƱþåVöo?ÈÀÊU„_°a l[‚(ÖÅܱ"ö YÐOñæmœ‚mÙ:îŸ6r¸¹bŸÃCŸ|�@±FTŒ?`™lÝÚ}ýtŒÆQ.],ù<ñÂFžRe»âÚÉ_¯×‹ÏïÇçó¡iÚ¹¯³³õõööO8qC çfLÊ#Ç©¢uUPÖ6Üol.§²GÔœGÎeWâe8<™L¨ XR˜ž�‚Î@k+“#ŽF˜EÝfXßhΟ_%Ì:ê¿B1’Ÿš—Ÿæùcîø"_¼éÊÃäÆK1å3wæ(3�ª±äå¸PÑè©«§çÌŸ4ÅEzVsçN#êì'“®ôûðzÜxUËðL¨Þ3kô�—1—ù…ö‘Ç¥µQ\Ú�†�ŒÂKŸy®3™ÂQ¨ºŸò’Sø´ªê<èHÍÉuòk^Ó&r{r²ûœì1`¦pÍJR :ƒ·±oć“Ÿ’m»hÔT"–ÜÆò+� ÐÚ8YÞ‰†�Ô¼\—¼]%ýÖ§øó9ž¸5kxXÞdëV£˜1=ƒâ§ä·ÿÂß8B}ÿÈ»Šª(!Ä5²g¢lv;}}}DFF^òºÇçÃh2ݳó]@�#?7Š£:©,odIBÂðÚPº…iyÓ®n†%àìD*½ç¦CŸôÕ‰âÀ®À€Ÿþ~7:ß¹Ðè@Œá£|˜ !ÄHþê—øÞ¯Kð&ÞÅW?·dô ÚIRÂc‰õ W”•6´�^úuˆ9û6wû6¼Î›»Š8YÓHGŸÿE õMô2Y±D{ñD­“¶Žá›gµ/�G7�¾×@o::ÞŽvú4ˆÕzéîÕ#‘®ˆQÿ¤«®¢&r'»ÏɃ ƼլM‰_Öá½ý¬]>Ü®ï$›w´ ©‘ÜrÛ¢=T£×ÞI[ç™Ú£œãûˆ›tÝF >öU>}ò¼p¬Œ×üÞxÖAR^!óç-`éÒe,�ǨÿË !ÄIˆŠ��gphèÜ$³Úlx:;‰�� Es!¢•›OÂá]4×ÕÐì RYëk.aWÞЃ~‚Š ã¨Ÿ:î!7: X,W×3¤8ˆ�µ£4ÐÙÚN`–ƒKž™ÕimíGG%:.öÒ×…âB¾Süîß~Ï _2~å –\ñŠy‚,–1×Ð3š†?ztÿ™Œ¤÷æÙ/ƒ?TzÀCÞœe,J‰&"ÌŒÑhDiÙÇÞ)g¢« *F3Æ‹ëÐýøü:zÐ�ß?F¡¶’m`t Âð$?þ³Ç`=4 Ô œËÉîs²Ç`˜Æ­k²ùÍ ܶŸ¾5kq*à-ÞÊŽ6 5n9wÌÇç îÇwæá9£Ñ8¾uu+ö<öã_²lëŸxíííì:VCSÉKö°þw?Å™½†Ï|ùóõ VŒºÚ÷(.3ìÎw&5(ago0ù8öÛgx±Ò‹š¸–oþè+Üž<òùÿÁN^{wâ!jTJvÐebÖ§žå'ë¢ÇÙ‹bÆr¦,¿×‡Žý’ítÏnmã •Iîs²Ç€JúªÕLÿu'ï`oßîpz9úÞnÚ5)«ncöx@T°†èxÜ4Wî)¼ªºC$ùk?Æ×Ö~ ÝÛEÕ‰Ã8°‡wßÙCYå;üøïz1=ÿ]Ö]ül™B„XHþÊDGG³lÙ2N?NII �»ÝŽÁ` ¥¥…â'˜?>ñññ¡h.„lLËK'Œ~Ê�UãVœäæ%]9YªQ¤&ÛÐõ -‡·q¸õ¢g½´jvoãh—Æ8fN�¿êmLšÉ¬Xº§šÝ;*é½p(¸¯�Ã;ŽÐT°fÎfz¨ Bü™Òñ á×u´Î“¼·ém6\ôõÖÑ‚:ç_{ýãz_mžÑÞ¤£½ Ctìð¤>ÁZöhEÃÈÌ>Å­É_Áëôµ43t5Ï–^È�@Jœ…ÍM­\f¾ž‘T1‘*¤½½cÔYPµæšÇ½Ã«Øçd�ál³‰+¸}¦܇Ùz ÝsŒÍ{ºÑ éÜvkîøî°ªq$Ç€ Í�-£/Lðâ \ð‹»Êº/¤X¢È^p+ñ¹oñËß|�Ó�èý‡yí½™¡V1åB¶"]ff& TVVrèÐ!ººº°Ùl$&&rïºu8�ÎP5RaéyL³VqrÈ�“CÞ§|0�0s6p¸½‘½¯ýžòäT’\VTÿ í�õ´ôùÑU;™7­fö…¡f¨œM¯ åÜ_x�€{øc¤ûøŸøMÙùö ©7ó‘•™ÃCóÔhæ¬XDÝú}4Unæm'IOŽ"L ­¾žÖÁ jx+nÊÆ¢s#„øs¥sÇ·xõfcåß¾Ÿðè�ö Íü4¿øæmD«&ì‘ãŸ÷S”qø„‡;—]4U‚Ö@Ii?*i9Ó†'RЇ†GÁyéM§@6žÀ§3©…l/¡¸˜='ÑJšì§ú3ÓɽäÓP££ô á3˜•âžñT�''ÓŽZÞGcq)]ZÎE³jÔ:Ìé ã¿E9Ù}NöεËʵsøiÑï.¢+â{ztL·r{æ8Ïj……ÉŽÖÒrø05Á™äŒØ4Hů?Ëc¿­Ç²øoyùûw5Ùº½�T•ž¤|(…ÕË2¹x°¡QȪѼR×Nwg7i¡¹K,„céß«ÕJaa!=ôO>ù$ÿøÇY»ví  0¥�ŸŽ‚�¸Ü\¢Ç{FÌI,[wkg§eòÑuº’âãÇ9^ZEs?8 X~σÜ9Ã5âƒK×| õ÷Óîk÷™GÉ‚ÞÁ ~ÞO¿{ä3fÆØ¹Üsï* “íh}�Tž<Á‰ÒZÝF¢³q÷}kÈ‘%„ã Z�ÄÆÆ7ÖWÄ™Þ “ƒ˜˜Xâb"±Oà¶›¢÷²å·¤tèŸêôì}‰õÕc:+–§©±$Ä©@€Šã¥ŒØ$ÐÆ®ÿüW^ê‹!BÝÛK÷¨=\:z2n¿›ù6…`í«<óbåÈ6oÝ›üë×þ‘§>þÿqüìªYfß¼ˆUÇwì5~|`Dõ5¼ÅÏ_®B›È3Q“Þçd�á,…¨›×²ÐCGwñ»-ûéÖÍÌÇÚPçȾíCÌ SÖ¼ÎO××sḌ@ó{üjc=AÌÌ\:ŸáÉþ&W·Öµ�§ÿîÛ|ç;?æweîKÿ·†#Å]èŠ‘Ô´Ä .nÜþÝwøÚ7¿Í·_*eô'·…bâBÖuCSÓYûØgý‰,É7ŒÏß<ú¦†¬ÛøìçnýEs 7ÝMÁ2?ƒ½½ô»ý` Ãá$Ü2ú§�â˜ÅýOÍšÌQ 7�ÏŠuùÜ4ÔCwŸ›€jÆát�ÙžB\jòRnV^âóO”sçm ÉŠRé®ÚÆ�‡hÑ�$Ýñišv據ȪÛfó?'Ó¼þ_ø‚çìÍuàí¨æÈŽíù–ðÍï/ä�Ïÿ;ÝE¼øóWаlÅ Â'[_‡øÊçðÙ§÷Pôü—øøáÕܶ(“h£—öê#lÙz„Ón©w}Ž¿œu~x¡}Ù_ð‰Â=üÇÑ:^üû§¨Z³‚¹ÉaxšKÙ¹õC‹×±æÄk¼Û¡£�sLÙd÷9Ùc8Kq.接áì|o/¿@[Ìí+ã&twUM]ÇW>½ŸÏÿüûŸý+>±g7Ä`è>Åî­û¨îçÜOñÅ;ÏkŸLÝjÂí<~ï›üíK%ü÷ãÀò›X”�H„Ic¨ë4Çwme_}Sê½||íë[é>šŽïfë~?VãþaÇ&„—óÁQSM1a�ŒÁ~éìîSÆh‹$Öv Bˆ‰PRyøŸ$û'Ïð›ÿùOÏLŒ ˜c˜ûÀçøÚ“K/˜R]%ùÃÏwZ¿Ç÷_>JɦßP² ÕJÂÜu|÷«Ÿâ–„ ÝDñ¯OP±áçüàèCülù ò'] ‘Ô»¾É 1à?_x�G6ð?‡ÏÖ®b��ÁÝ�}šÏÞ?{äôâ†t>òÏßC{æ~µ£–ƒþ�ƒ€bŠ$ÿö¿å»ŸËä�ϾøðøÇÙc6é}NòÎq°xí2"·l¢Ë¯~󭬸ÒÚP—0“óðwx.æ7<ûË 8¸‘ßPP­ ,xð“üͧ×2rÞIÔ­Ø™ÿÙñLÌó<÷ÊvŠß{•ã›ÏîOAµÆ3ç®Oñäã÷2;Ô3M !Ä(”˜Ç~¨£ ß ¬öÉ˾¹ôøæ-Y~-êá¹ç_à©Ï<~ÍÛBˆÉ8²o'…ó®w×…oçwùÐ7ÞÃ�üÏÿæIfÀ×ÛD]C£ƒø´4â¬c÷uhîvêjÛè×ÌD&¥‘게˜½-èî¡ÇkÁé´^:uù¤i¸»9ÝÜ‹[7�LJBø˜S´Ÿåïk¢®±›!lÄ¥¥‘`ÿ3c¡ßçäŽ!´ô·4ÐØ9HÀâ"%-‘È+0™ºý ¶7ÓØÞÇPPÅCJrÜ„†› !Äd¤}ágœÍMò'G!Ä”ÐÏtš˜�Iä8“Ƶ�j�%³`ì5 ÖH¢­c¾[úͬ»mQöô}ø€b#6=‘ˆ1z�T{4–]êv­gCq7AÕJ|îtr“# Ó=t7VPrª�ÓEoó†ÿ.¾%•óñN§¿ü=ÞØZÍ b²§“Ÿ��!ÚkK)©m¢èí7 Þõ+RG…B!„BˆÐ›Òå÷ûñù¼„…Y§²™«¦Õ±ýO›9Ù£aM]Ƈo›EôEgF÷yñê€Ïܵ·“7ÎLl-bçÉn‚ŠƒÜµ÷sk¶ã|ÏÑôYäÇÿ‰?în §ô0esS˜~&�yëØ··†A,¤,»�{fG�ûeåL'kßë¼~¤ƒâÝGÉx1ñÒ%„B!Ä51e—Þ^¯M×°Ùì 7ðÃ;žvox‡]A¬)Køð³‰5�ò>Ÿ€ÑŒy܇£ÑQSK¯†„Ù,Ér\tÂU\³È0ÁvZÚƒç^qמ¤zHGuNg鬨‹Ò®™Äy ɲ*hÝeœl "„B!„¸6¦¬'* â÷ùè ôâóù¨Š‚Óé""Ñ�ƒø¡—òÓA8\¸�F�×Ââ{pÆùNªÞú��e¹¬Ý˜Çàqi48‰ŸYÆÎ%³ùxÃa�9í¼ ×-’:[6j“"ÔÄÄ{f(TžΆ·%"""""í®ÕOÑøýbbb…B$&& …HHH¬óubb"–E�¯ãbãðû�×ÍgRG_ÊåãzëŽ#ëÜó–äÂ,ÛÆ§³W�ÛTYn·»^€ªÅ“AV¯X ,Êóó)·XÆ—ÇÊ�ÞeÖú„bzræ%—0¾~€0 ÷`jnëkˆ…Ïç«Y<¢Þ/ø‘ŽÒê ˆŒˆ"..¯×‡ÓéÂçóárUÿ?>>ŸÏ‡Ûí®óuDDÁ` =÷Áƒð訯¯ÚxÒ;u<Ý# +™õÙWjõ}qÕ=8j¦C¯ÍªÜË¢÷gòùÞJ+Ó¦22¥Vª1ËÙµd>kŠMp¥0(+åÈ}’�ì,ÜR=™pÎà¨j®.ƒÜé+¾(ØÉ’…ÛètNâ¿×_ÀÊ…«ÈDôJV‚"”ˆˆˆˆÈ±rL~OÔ7ƒ‡®c§0¡ä¿,Ø{� Ï%îÒ 9-É 8Iq&§eÈÊûùâ½×Ù’Þ•. 8Ø¿—¼Ò–#ŠãÎaè‘PãeÇú-”Z@ ‡/Þ}�/š¨ ¬çÙ\9.£ú ˜#‰agŽfÏûKÉÙö ol"3=‘p«œ‚½{ɯáˆéÙãzÙÑM#"""""G(DÕæH`ð¤I¿÷ëîçóÙ ˆ»ìlzFÖ…±—\FŠ¥¬ú*›â}Û(ÞWó>ÃMLÚ†�Í�ô¨¯gë°Bü5s”½”•y›Ü|XU°Î×®N§qÑ¥|±x9›rö³íÐþš:=$õÁ¸qÃÉÔŒ"""""Ç”‘ü“G-ŒêûÄö>uC“ o^·Šác&4¹Ì)Á PqèeUp…GŒ§Õ¶H°²„ƒ¥UaDÇ%tøöD¤õV-]Ä€!ÍOº#"""ßÝn›Æáܤ+Q­a¸‰ŠO&*þØmÒO§Èc¸Ai�.gˆˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q"""mà¯(¡ø`)•¡ŽßV ²„⃇¨6¿¬4ídmËã¹_Dz/´V°êÅK¨´lù“õ{Ù9ë)˜ö [KƒX¸âzsþÍ¿`D#ïðg/búÓÓ™±"›ŠPuý®˜nŒ½üF~ö£ÓIuæÞûÅ�ytMg~8m:7÷¯÷cÙÌã?w^Í»qýô§øÎUÜõQ$W>ýw úzÙªÝóÌãÿâƒuðšNb{ŒçwÜÁ†Åù¾E5Õ°*·1óÏðÂ'ȯ4±Ãð�Øo<ß¿ù®ßì§û-«+DÁò×øÛ´÷X²»” ÕÇ:�1ß¾…{®>�ÎG^¾|üÿ¸ýƒdn|þ~2g=Ÿÿ»‘ ƒÈô±\ÿ=|o@d ³¾í¼÷à£<óÙž¯ÏáþS¸ý×·r~½sØNû5¬5}Ç^û,ûË•õΑËþzwÍJå¦i×Qþ·ûyu«—„‹ÿÌ6·íý²ßêêè¾ßÔú;×,ãÂiå³à™Gyô½�Õ:®»ïW\•uø߆ڳ­}£½�GGôÿzû�uÐÆ÷©gùI‡½m5Ó'ªV‡¨ö(œ‘ß©ÜOå}·ÇÀévc˜Å,~úAÊbÏæÎ‡o'ÃSʶyoòÏ>ä¡û#éòü� iô697îº�_ǿ̣3÷ÐíÂ;¸vTñ½p¡ì™ÜwçS,õâÂ[nå¢áéDVå°ê×xöáÖ|“:Ÿ´¦FñV›6í!ä:�!<`y)Ú·—ý%A"SºÓ3%²Å·øT¬zž»ÿ2‡¼NgðÓ_^ÅÄL‡v|Λ/<ÄËÖÑT˜…óxð·ù´<“óoz�KG¤Q¹—eï½ÈôWËí¥óÂ#ˆv$sæyÃxzÕ ,ØÆOû¨óƒÙÌ]ȧ›¸œÇy™r¨ÍÌŸËïï|”Eæ.¹å&Îê�wÿrþó þq﬿?Î�{¹[^“Xå,~ò×<27ÄÐ+îàçã{’èR´c)3^�Á3÷–ù¯?sY ¥u·¿ÎÝ÷¿ÂÖ˜áüàžï0¾{”îbáÿä�Wà×ÓxîûÝk>U7p¹œ`•²rúøÈÅM¼žQ>ö.y�§ÿ³„¿ÿé †½pZ4Âñ³ö…‡Xww<|'™‘åì˜÷ožý߇<|éÿ¼�!›Ç´Éôf¿ïØkŸ†·YÝf•lyë9Vs:ß»º;I½Sq¶b¿ìö…£utßozý‡ízóAVºFqãƒ×Ó=ºŠ=‹þÍ3o/á™GþÍiM�?mîí{<:¤ÿ×góû”½m5Ý'2ÝÎ'""¶Ìb¶zÀô'®¡ÍçÆe^x5/�ÍŒ?bÈ„Æ>2v’2p<ãv¼�ƒ}$ô>�³ÏêT3Èñ²ìõWY^Ÿ_=Ì=S“jþ=“^zâÊ¿†G—¾Æ›ëÏ审M\í2óØŸˆéD䎷¸ç±×X¸¯‚ê¶Ãè<ô2~qïµLlîò�U‚·g³ßêÄ%?¿ŸkF׌n3{3(=È57¿^ovCkޘΧEÑL¸÷ÏÜ7ùëú{gõÂUx=O|ðï]q?ìê aܹŒŽZÆ¢E‹Øzí²Ž”c’½p›ƒN;ï,Ò4¢|¬|ãEJ`Êæî 1ÕŸ Έø®üí§¼ùÖ—|÷Þál¶QÁÍ,Zv#óÜuÓEô=<š8”ѽ’øÛÿöcôAZcì·´®ÓÉ[· _b*g_ýknššPs ƒ{úÙzÕ“¬üd»®ìNïš ÀP.k]ÇKO]E�šö4°3…«¯cÚöÕ¬È5еÙ,f{èG¼ðà�éSs* Ò�°ükøãÒÙ¼»üG ™aû˜6Å^ß1Ùg³}ât:ÁÜÏ’]—ñä372äÈaó±ÊÎ~Ùî VÓÁ}¿©õ×Ì4g³Ùw/=ú}zÔ\ê<0ƒC®æé-Íœ?mîíx<:ªÿŰñ}Ê~_i¼=NlšrCDDZÉIßI“è[{,ãHdü¸,ÜV9›Öï¦U“ã¾bÉòƒXá§1ebRÝTŽÎLœ8·YÀŠ•{ir"e«’²* ¼ËyúÁ±&ÝÅÓÏý‹W§=Ä/.î…wÝ[Üÿ«±¶²¹z¶°z“#jã‡Ö½´Ö{"gu«÷£4¸�…ŸçCôh.<ªþ4&Mˆ;¸�/–ÀŒØ1Lƒ•³˜Ï¶Öj13›Ïæm#1œ©“þ�ÜÆ’¥°¢†sö¨˜Z·°D�¹‰g_x‰o†ÇfMaxÂÀ,XÏòÝÞ:ãð�ßæ¾_ßÁåYMŒtZZz\þ ÿ~óu:j–ŒïN÷«¨�¢ú8 7C§L¦{íüëH¥GW†yˆƒ%-�¾ÞI¿IçÑ«ö9l$2vÜÜV7ìª>‡í¶_ ¶Û²¾ÓÊö©Ç0Ë"óœ Tû°ÙÝ/»}Á®öêûÍ1Ü ;*Ýkß+æH¦[z Ο¶ö ÚñxtTÿo¨æ–~ŸjŶm�œ®D‰ˆHëádvO©7¸7ˆNK%ư(Cc•�_ibd¤’Rgœid¤9aO­å+³Ù[dBd.‹^y�MõÆ•¡ÜC8 ±oo!RpÅ铯ÿÙÇ,\°•³²pæîù|ºÃ$vâd&Ä7\�U™ÍÞbGFiõpÇÓµG|õr¥6kr äÛ?ŧ�/癟^ŇÃF3vÔpF�ɰÞIÍÎÃÑÒº3Ëö°|Ñç¬Ú–MAIÞ@�`à;Yj`ÀF§Î1õŽ™A˜Ç�AˆPK3”Nf·úÕ :µæ.¨>‡�¶�i ¶k£ïØoŸ†¶é¢k·ºÛ´{®6û‚]íÖ÷›cxèÔ©�ó'¬çOûÆ×›k‡ãÑQý¿Á‚[ö}Ê*kå¶h��B”ˆÈ)êðÏúæn¿±L³fùz£#‚¨ˆ£äî0ŠËo¸�ë&viôض´.°¨Øø¿üõˬ. #¥ß¤'†Ëé¤ÀÙÈ› 'ŽÆ^³Ãˆ$²¡s8¬î9ìnÅ1mz»-í;­lŸ·é!ÜSw›vÏ »}Á®vëûÍr`´z´Þ¶¾qD{�ëÿ kÉ÷)³µÛj =Nt Q""§$ƒ°ÊJË›¸ÉäàÁR,à *&ªÞ§„ü�£#˜ðãÃÀé kÕÌJFxáXU^| $<ËçË�+<¢ébŽº¤8!ÏÑà§›ÎèØêOý½UMI#, �–ß�¿þ‚V••V�÷Õõ;º\Î/\óõ3Mñ fÊ™)¼ÿîbæm¹ŽÁýwðÉü½X�/dêˆÆ‰Õ×mU=˜jt¹ÖÔ„›NÃ.áÎa—p§¿„]›V³ìóOùßÌ¥¼öû»©úë?ùÅð†ï½ii]„vñæc¯±º<�‹þð7îžÐùëc\ÇcK—°½¹Û-ÛÄ�糖zô9ܺökJ ûN{·ÏQŸƒØÛ/Ëf_°«Ýú~‡k}ߨ£­Ç£CûZð}ªMÛúfüÖó#¾Y‘ODDÚ�§G/º:MÊ7¬ak ‘…ü[Y¶ºÓÙ�¬¾õ&‰0+Ø¿¿¤^³¨È˧Ìr�’Ò¹U·Û1tKp`ìa¯·þ«&ÅûöQn:Iï–Öô@ʈ#+« ÎÐ^¾Úé?êe_aŦABRb“? �ØNtöXrÉ«ÿ�W(›]ÙuÿшȠ{gfÁnöUcÂ|î™dy,Z¸ïÖÌφŒ³'ÓÔÜFdÝ’˜ö²§²Þ(*˜ÃÊOæ³`Í~ªÂ[SSíòâé1ìl¾wóƒüó7“I¶òøìÓ�4vÚ´´®Š’M¬ÛÀÙk W�ë\wƯƒ»ØYÜ–!y ˜d·ànÝ1mz»-é;Ö¡Žm»ûe·/Ø®§½úþ±d³o4Åöñ8Výÿˆæ¿Oµ{_9�)D‰ˆœ¢™“¸hP8föLžzc3õÇcf _Nšw³M¢‡_Ì™õdÙ8¹µG‚V K¿ØDЈgð°ÌfC”QóÉc PkÈáêÇøÓ“0|«™½°°î@3”Ãgó¾"èLgìé]›ù!æ¤÷9çÒÇUÊ‚7ßgWíeæ2wær*�DFŒìÙô€ÌÝ—!L“ŠQµ’™ssê ”CìûàQîzðEæÕ}ÅÕï&e䬸‚9ó–�M&“ÏëÛtm®ÞŒ�ŒQµŠ�æÔÙVÅš·xð¡ùã·aºíÕäÿj÷Ý~ ü¤¨Þ•ƒð„" p¸š8º-­ËéÀÀÀ k~ÿQ ³˜ÅÓßfm¬`ˆP‡e© ›æ-d�søÐÑçp+�iSÛmQßqtpûØÝ/»}¡ Û÷Y;hsßhŠÝãÑAý¿É›û>Õž}%PÄÎ X·%÷èŸO'gäiçýþð�¡w�?²É… ósIËÈ<u‰ˆ|cåfï¥SJÚñ.£yF }ű}áV|þ1³WïãàÁbrölcíÒ�y}Ú<¿0ÒÎáÞ~ÂÐ#æ˜ìÿb³·¹IÛÁg›B$Å{ÚÃÒ·žä©ÙÙ˜}¾Ë½×Ž ©É±„�Qð%oÍÛAaiˆ¤¸Ù%átO�'½g _}²€/¾XMAD2ñaAJö®ãÃçcúòCtš|÷]Ò�ˆfnÿ0â{“Yñ}6�ÏÖÂí19´w53ŸœéË}ú üæG‰mj=F]¢s˜óÙzÖ®ÞJ .ž0o![>‡Çþ±wZˆ¢ƒ ½ðF&;')½ØóÙ|/YÊ3ž¸ðùÛùbæ³<ò¯…ì0qÅå#H©3;X<‰e_ðÞ¼5lÜ_ˆ¿Çw¸ûÿw¤6“ýŸ¿Ãœmn]p)c:;i="Ù4wË–}É^#Šˆ`Û>—ÇŸù€f/þï?åŒN[59<%,}ã>Z°š#’pT–°sÃ^yþ-¾,éÄ…7\Ã¸ÔÆnØlY]cÓ£)\ö!Ë·ïdŸ™Jz´�¼-Ky÷™¿ðºy—'¬cMNá=†Ñ#>œ˜'ùËßãÃÍAúž÷&¦×>Á·�‹¬©—sFjSÃl“ì%ï0g»‡Ì¨]|º>@R‚‡Ð¡½,çIžš•M¨Î9ÜÊcÚÀvíô#,Üfû88GÌ&ÚÌæ~Ùî �éè¾ßØú#)°uþÝçÚÞ7ÚñxtPÿoø{M�f¿OÙ݇ÆÛÃ,šËý×ÿžéËŒ»l)'À¥ŸÇg­àpn:a®†ŠˆÈ±çîz!?—ÁÛ/¾ÌŒÏ>ãÕµ×|ºjàŽéʈˮæº_Èàø†~zE0úÆ_‘6çoüáŽg©0-0ÂH|üúûôiÁQá#/åªA˘¾á<üÛ™ÄM}ˆ‰CSp§NåÁÇ�L{ò>|ú~Þ7¿þ�÷c~ð?ûñXZrÿ¼Éi7ü™¿F?Åão½Ïc¿ Gx2C.ù¿¼a*ÍO¥Fì·òçÛ|üá_ yùá/y Wlo.¸í·LÞþnß$PëR�#ùlîÂEÚß§óîË1ÿ…šV ‹§Ïøk¹÷Ö+|Ô#2Ï>‡¬Wžc]I#~|V jGêù<ø¸ÁÓO¼Ä¬éâcÓÃAt·q\ÿí\=Àc»&#f,?{ôW„?ù2ýóa>2köÍpÓm?øý-\7¬ég>ZVWW¾óË[Ùö»gùøÕXñ ®XúLºž¿Üq> +öðɦ9¼ÿÀ ¬øöc¼}ë€æ¤E,B�–#•s~~±3áw<×ä9ܺcÚ˜ö‡Ýöéo»%ìí—ý¾Ð˜Žîû ¯?ÉvûÔ×}£)vϳŽèÿÍTØì÷©öí+'.#ù'�ZÕ©oïS74¹ðæu«>f±¨KDäkÕÒE 2üx—a_¨Š¢Ü|Š«B¸¢“HK‰'¼ÁA|€å�}Ÿ;gºøÎ¯r×PþÒöðáˆK¥kr„½{Å-‡ ˆL$1&ì¨÷úËòÉ=P�Gç´$¢ZûPt œ‚¼”™á$§¦çiÅSÌþ2rs ('š´ô¢[ðQd¨²�œüCx�’SSIh¸QÛ�…¯$�œ¢*ˆîL×”èF?)µSS¨ªˆœü¼!' ©tI ·ù,@ ê²ü”äìç€×IljR¢¾^Âô•S#6úès£ýXøJóÈ9àmÑ9ÜúcÚʾsŒÚÇÖ~µ¢/¥£û~3ëo«¶÷�fÖoë<ë˜þßVÇr[ÇB·Û¦q87éJ”ˆˆTsF�”Ñ;ŸÕþ¼9,¶ =b[¹]ÃC\Jj£/‡Å¤�ÓÊu׿ަs×h:·ea1¤Ù,Æ™L×ÉmÙj xâÓ¨÷+˜d§&gD]»·åüÔe„ŸÞƒ†qx¢‰·;O¾mžØ´ŸÃíqLmõ�cÔ>¶ö«}á(Ý÷›Y[µ½o4³~[çYÇôÿ¶:–Û:Ö¾ÙqPDDDDDäSˆ±A·ó‰ˆˆMNú\ôsa�ѽͿuT䢾#r²Pˆ›$ôÃÙ}Žw"ß4ê;"' ÝÎ'"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆ}RóŸ IDATˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒB”ˆˆˆˆˆˆ Q""""""6(D‰ˆˆˆˆˆØ %"""""bƒëx ""GËÍÍ=Þ%ˆˆˆœRÒÒÒZ¼¬B”ˆÈ ÈÎ7r9¶t;Ÿˆˆˆˆˆˆ º%"""r‚°,ëx— rÊ0 £ÕïUˆ9ާÚJaJ¤ãO–eù»Ý@¥%"""rœX–…eY”—â`á¼Þ*ÌPèx—%rÒs8�„‡G’�܉è˜XÀ^�Rˆ9¨Â‚<ÊKKHËèF\|N—†g"- r¨¤ˆÜì½x«*Iîœ ´‘oÝÎ'"""rŒé(‘SKû¦®D‰ˆˆˆW TuøË(,õa9#HHˆÒ`µÕü”–âÅAT\"QîãQÂÉ{,O¦}ùæ93”UIîÎý”„*ÎÀá #*&‘N�bð´ó¼þ/žâ;Ì'Ðå»<ûâõ ÒhµuüËyìG`®/�ï=ù/nxìòd>–'Ñ®ˆˆH}¦i’—ŸKþ�|ü?Á`·ËM˜ÇCç¤Î¤¦¤ápèÎn‘ãéDÌP7òâÏïçƒÒ&&½0 ÜÑ]9í¬ ùá/bxrû +-§ —Ã�érá0NÐöùFpP=ñ£�Ãq|Úñd>– Q""'©P(Äêõ+‰ŽŠ¡w¯¾xÂ<8�N|~åäçç’[�ðAÃq:�Ç»\‘S؉9´t’ŒehjÝ!£¨ hÿv¶ìÞËò™ÿàËÅ˸íÑøn¯°6o7lâoX´ä0ø¼~4wa{°8çÙÉ|,¢DDNR»öî")!™^=ûp°¤¿ß‡ÛåÂítKtd4»öîd×Þ�ôîÑçx—+rêj‡±í«ŸlçÕO¶ðÃI}ùá¤ÞíT“‹WÜËŸ¦ÆPç®= âtëLþtß“|²Ïþí]F=õ=z´õ3™ �ª ¯�+‘:çÕñÉP'õ±Tˆ9I,bHV‚‡Þ"ÊÝ‹ˆØÓq:˜¦…YµXNFç¡lÝ]q¼K‘6zåã­Üõ½Ñ„B&O½ýeÛCT-VÈ�ß祡GŸÂ3¿Å}wnfí¯>¤`Û<>Ýõ®ë]?E™TlgýæÝäWp†ß9“�CúÑ%òèÛ‰­ò\¶æ”a¹éÞ=™ðš [e9lÍ-‡ÈzgÄÌßÈ’•Û9Ñ�³ÎêOBÏf^çá÷:-/y›×°zG.åf8ñi}8mXo’›¸�fV°eý&væ—PizˆOéÁà¡}I�pÔÞ9Ûs9d…Ñ93“$O½•øŠÙ½§�*Ü$tíNjD½¢C‡ÈÞ™O‘¤õÈ ¾%#u³œì kX·§� +’”îƒ1¨ Q-yk‹öÉKÁî} ";u#3¡‘F²*ÈÛ™ÃÁ�ALjO2b�ËÚ%{X¿~+ûŠ*†ÅÓµÿ†õL¤©kš-ª»ƒ)D‰ˆœ¤�‘axÿB9XÁ Xf,ªp†Ç‚ë§Äš¯âó§ïRENiV;\"†LÁ›÷$2Ûe�V­¿5¶>Ëôã8Œ,×GrÙ›Äêýõ@Ö:´�7{‚—?ϦҬ½Gdgÿän~ui_"k ®ý«_à¦èòþñÂužÁ¿îenùÝ<‚Cnæ¥ëÊyèW¯²©Ò‘r)Ý'ôk2pø7¼Æ÷ŒwðM¼vwf?üg^][LðHIa)§sËï㊞õ†ïf kÞzš¿¾þ9{*ÍZ-Q½gýð.~þ��Ä€y€Y¹�vF0ù÷¯óÛñáuVU¹üYnx`>åx8ýg/ó× ê„Óà–ÿðó;Þ!§ó¥<õÒM k|—ª—Ï™Ïã<ÍÌåi^ÃALï øÕ}#j­»Þ1´³OÙðÚ=ün~ÑçÜÇÛ÷�o0 ™»Þåž›^e›Ñ‹ëŸû;?޵=–ÕŰøÅ¿òØ»ë(ðתÍp“4ø~~Ï5LL©wPmÕݱ¢DDNRŠt½Š;êL Ï0ŒP!8ºÁCÏrÈ7‚ˆpÿñ.UDÚȲ,J+|¬ ãmÌVO`p„™Ã{ýŽçVVàÎËO~p#»'æ+dë’¼0c-ŸNû=®NÓ¸|ü×þÃ+1œu†á Çc@À—̮ͧءLžÜ“øÈþ$6sÂp{pPU¹‹·ù7ó‚¸éþq èFeÎjÞ{ñM>Ï[Æ´ÇþËȧ¾KæáõY¬ž~/¿|k'þ¨^L½ñ\4²;qV1;–}ÀKoÌç³çïç@è¯X?ƒßÝíãѿߨ˜Ã—"mÖÝLóµ•B”ˆÈIªSr ùEå„…ŸÃ®ÕÓ9,‡»'–YÌþìítîv Å%å$'ÅïRENm­¸hôÊÇ[yeîVÁ–eNI™—Â’J?‹ë.ÜúššyžÆ·y[‚8Òé‘î:²lhËlf¬)ÇtöâGü×õÓ´°èË á£Èô_ÍmÿÍgþÿsãÒ©¡ T{Û† '`fÏãÓô+˜öÊõ а°¬A³©v4À„vÌeîˆÛxáéËèj„0- †œÆèÔr®¼ë=r·/gYþ·ÉL­.&¸uOÌØ…ÏÕ�ï?ò4·ö`š&]éÕogô�àG÷|Ć×_dΤ?pq²ƒÞ#G�øÖL¬_Ov(‹Ãy‚ÐV­-ÆÈœÌ”¨Oø`ýz¾ò�ã´ÃaÉ:ÄÚµ»‘Œ8}aMž¥‹ßá��~ˆÅ�½ŸK“B„L ³'CF%ù®ŸòT¥U½ã‡Û²•û>lg%ÍåÝÂÌ_YÎY£ë†¢Ðvæ-ÜKÈð0ròDRª½Ö±ôoz‡¿ÏÉ%èÉâæÇãÇ™B¦ÆÆ�ïOĵ?ã?ûç0ýÃKqeW­¬»#i^[‘“TjJ*þ€�ªª >çVm;Ÿ5†•_ &·ì |Áx*++IMÑí|"ǓՊÿ^œµ‰sGuçâ‰ý¸hB_Æîʦ]E(©dôànL?€)ã0fh¦ÿoM+¶Ð² ý–2ísÈ7 <&sN¦qä5£çwyì¥2ýÉßpYF @0$ ð 5�Ã"°o/û̆¶mÕݶaaf¥Á¨^Ig^ŸŸ?@¨…ûc©\xÍù¤…¼øƒÕõ>Œ¾Cè1 T@nÁáµùÙðɧì BÄéWñÃ,gÍ>„…‚ü^"F~—Ëúº°¼kùäóBBX¸Œdx”Ah×zÖ—˜G*XϪl‹øÁ™œ• EëY›]«rïFVåÏ`Æ kf|¬Y¶Š Ë òô 87Þ‡?$d ýøÌ.þöDõ�`ëöÉteqÞÙ�qX,_ø%eVÝj[1_#r$çOˆ«µÅ†Ž¥Ÿ ó’‚ÈÓ/ã’ô ¾€Ÿ`(@0èÃïÀ×^É—]Ƙ” þ6ÔÝÚ3¾%t%JDä$åv‡‘Ö9•â’"23»³|ù2JÊJ(-)cÒ¹çq ðÉII„¹Û>%±ˆ[Á@€ƒe>VnÙCõmt‡‡Ã`ÍŽÂ#·,“` -·ì†Ø5ïe¦í¨{o™òR’³�Õ«·qÀga$Žä¶»/¦+™ÆÚ‹&5=–´ 3TsËŸe  š&^+ �U~?~;cXW?†g¹±ZqÏðôcPO˜j;Š˜H|>|�š›lÞRˆ‰“ƒûÙÀ¥.ËìÌ �I8¾*`Ûæ�.î„Ç3�ÓyøxéW¬ÙìãÂqá€EÙºµl z3´?ý=‰z{!k6óÃÉ8€À¶u¬-÷ÐQ ?êv¹zÌ|víñbá¤[ïÌ®Z™¸{  §ë3Ö†jÿs+÷ Ï=‡®3Þ`ïÊÅ,/ŸÈ¹‡o³#À¦EKØo:ˆ;c2c›­½€-[‹0qÒ­oOÂë—`Y¤ŸýSîžV(@ h¶¡îŽ£%"rKJLæà¡ƒTVVŸǹgMæÓùs)--Åï÷“Þ%ýx—("­×~k0Ï¿·²æv>“ˆð0¦œ9Œ »‹Ù·såUPs;ß-WžaG–±Ùû¼¹¬áÅ w}Ͻ‚[nù£ã‚ê¤ ³bËfÍäÃÏײywE¥>õÀŽÃÛ;r¹¨^õj7ÂI ?úß[ˆˆ"²þ6,£æ÷bÕ¼d¡VïЮ·Ã�?jx¶‚@éA,,¼E…”† “#ŠÓF÷õt}õsQc³pácÚ�ø]}–ŽÇ5„,÷§lX³‘ª Ï$Š{Ö®§ÐtÒoôp’ª±¶P)%‡LÀEB|tƒËq‰$.ùp;¶zŸÀèy6çuÿÓw®fþŠrÎ9»fÚ{ÿfæ-ÊÃt$0ñ¼áDZµÊièX†J8PTS{Bõ›þÚ�öµ¡îŽ¢%"rs¹Ü`ìܽƒä¤N|8{&¦bí†Õ¤wéŠ[W¡D¾‘®»h7_1òÈ×}.{ŒÄø(bc½”•U°ý¿8òšßï'àoíïêq‘õ½ßpȈZÿf`¸ÜDÄ$ÓµG7’ÂÕÛ¨wyÇ:´šgîy€·¶{Á“Lÿáã9##™¸ˆ0\.FÞç¼>ë+¼6+2\î¶ `[¾¬ �`õ,3@ ØÈˆ<²‘àŒ ãðÉÃFÐù–�ë7’mfÑÝÜÁªuåéCšdY Ët²bã6ûÏd¤«ˆuk÷a:33"¥ÁéäëÖÀ¬þ«ÓåjxyÃÀé¨÷J«÷  +çNêÃKÏoaÅÂ/)=ëlâ ðm\Ä¢GÊ™œ?ÌÝü­qV�ÃsŸ8�Îæ÷µÍuw …(‘“ÜÆÍIOïÂÐÁ§±mÇòòs)/¯`ÃÆõôïÓÿx—'rÊkÍó~¿¿ÿëøa™&Q‘âb"(//msUÕ$öʈ‘QõfW01Í *LA~Ö½ñoo÷áH›ÂOßÍ”TgõÄ5÷á¾<ÀŒÙÕ!ªÎsKõêhø•½V³÷Þš%Œp"#Ü ¹öüý²¤¦ü!UÞ@õº» gtêKlÛ½ž ‡® kÉZVBÂCèfXX¤2tp"üo=köžº‰Õ[ƒ�F2ª[ Î Ã�§æK¿Ï�IÄQµYUUT™_·^›÷ H?ó\¾¸…u«³¬ôL΋ó³fÁç0�dœ;‰,‡Iý‹Oµ¿² ážê¯«¼^BD6?ICëîšXBDä$Ãòe+¨¨¨À2-ü~?[·l%6:öx—&"íÄír2ÁåtàvÕÿe·md ëý  …ÌÆŸK íeùªL\ þîÕœ•৪ª ŸÏ‹ßïÃï÷R¸?‡ŠŽ¾\ÐÎÎd¤º0’³o7eåT6õ§ö ÝÑ�Q#1›Yó•— kÙ gð°>Tg'}†"ÒÜÏÚ�…ø¶¬c½× aÔHúµäð9âINp! xÆ ÌülrBõþ±-ûÐiYÄ»Ÿ±"Î`êøzŽ«áh ¤~‹_ܰŒ[Ÿþ’åÓ~ƵKÇ3¶΃;øbá v•Aüˆk¹}J"PóœU[ëng Q""§€ÈÈp^{aúñ.CDÒ)ª½µ%±ÔH¹à.x˜‡ÿ³ŠMsß`Ó\0¤¿œG1q^Rþo(^\ËÖYÓùÛÚ+xòŒô­¿Ý†R”Ý‹ͽ·±×C&�Ïû/vúO=7ƒùkfóêêš× �sÑ ×sËÅýˆ ë­6�á#{à\½… Í�¡½qÖYÀAßÁƒˆxo>¦‹>£‡qäBUKvÉJåÛ>Šõø_yaþ.VÎ~›•€áŽgÀùwóèM]™uÓ À�×oµÓ>V8#'�#áÓ�( 8ˆ�0‰qQVóu×iWȼô�ü3ùžx~&KWÎáÍ/ ©ŒúîuüüÚ‰t!€Ù^u·3#ù'�ZÕO°í}ê†&Þ¼nÃÇLèà’DD¾ÙV-]Ä€!Ã�w"r‚², Ó4 …Bìøj=û8Þ%5ÀExL.BU¥TZ3$uàòDàdÏž<ÊL ]2Ɉ¿×KÐ4pz¢pK)ñ{ˆ�u¨ðrGáÓGU¹—#s#¸"ˆŠ ðüT•UQ΄¦w§¹÷ºðDGávX+Kñëí‰ËC˜ÇM d?{sK¨²ÜÄ$§ÓµsŽ€Ÿ¿áA»ÃM¤Ç X«ÊðÖkGÃITDõT¦·ŒJ¿ÍË'†‹°ð¨ÌcÏþ"*‰¢s×n¤xx}!\QÑ„9,•¥øÚiŸª7Add`*©¬jd"‡ÆŽeõZp¸=x<*ò³Ù_TNГHF·Tb >_­ÕNu7eçÖÍôê?§Ó‰ÃáÀ0Žž&£ÛmÓ8œ›t%JDDDDê â-;ÔÆu˜}�pR3{�X¦�ÿoï¾ã¤ªîÆ�î½3³3³½±”…‘Þ¤Ä QTT£Q�êãÏh|Œš˜GI4Q“ØPŸ{y b    ½J/»”íeÊ�¹÷þþØÂ²;[¦lÿ¾_¯y½`vνçΜï=çÜ{ιÏñ[K†¿CÑpÙ‚ø*ªðP±¹ —ŠRodYi2my ˆ4ƒ~|A?Š#•ÞýÒQ°°,½¢¼ÑÝšþrÊei5t¬Íeѽe &Ò+'©²SSkÙy½¼½¡¼ExL•»mæoÑèñY˜Þh‰™ä$e¢`aúËilËÑä;–¤%„BцÚãh¾˜²LŒÆnY‘<)«mX– F O¶‰DSßqcIÛÁ1Yfø™oë|K'J!„¢-5ø°%!D{%Kœ !„B!D¤%„BÑÊBMZB´½æÆ¦ çB!„h#ª¦aª*×µ…h+¦i†ƒ±B!„mÄétãóT´u6„èÒ|Þ œ®ø°ÒH'J!„¢UR…¤Ô4Š 0Ív¸â›]€išä“”švBl6E:QB!„­LQTUÅŸ€+!�[6PRTˆa›N,„ˆša))*dÇ– ¸’pÇ'4ø�ÝPžõýНÃΤB!„8QuG*=# ‡ÝAþ‘\ìÛ…é„ͦj ‰dçœDbrjX(³5d䘰3(„B!NTÝXÓ4 €¤”4’R°ªžeɳ£„h1µ‡í©ªŠªªhš†¢(²:ŸB!D{V»#¥ª*¦iJçIˆVT݉ªî<µØ�(!„B;µ¯ˆ×nÀIgJˆ–S;ÖÂYL¢6éD !„B´¡Ú�¸êΓ<ŒWˆ–MœI'J!„¢��Γƒ,q.„B!„aˆêN”Œ×�Uk_ ”X�•\U¢ã“:JtV­:œ/ÔÒ›\¢³¨&˲"žhØ\K¢3kÍXBÄžÔQ¢3‹EV'ʲ,,Ë¢¼¬„¢ücø|^y œètTMÃét“š‘IBbûÆŸÄ’è Z#–„±'u”è ¢­£šÝ‰ª¨ü£‡)/-¦Gv’SÒÑl²6…è\Œ`�’âòîÇçõ�Ñ­;»ÆŸÄ’è*Z:–„±'u”è*¢­£š5W$J‹)/-fàÐQX–…ÐA÷Gž{!Ú#E!!1…�CSÙ±e=N§‹„¤äª?E×ø“X]J Æ’"ö¤Ž]J”uTXw¢Š èÞ+‡`0 ãbEçeYMEQèÞ«Ç矘Ó;QK¢KháXBÄžÔQ¢Ëˆ²ŽjÖç–eaš&>Ÿ·Û-%º˲p¹ãñ{+0M3&å^bItE-KBˆØ“:JtE‘ÖQMv¢j¯Îb–\A]ˆ¢(µ*š EbIte±Œ%!DìI%º²Hê¨ðg šfØI„è¨Z´¡'±$ºé4 ÑÁH%º�Hê¨ðŸö.„¡H, !„h¯¤Ž¢qÍž%DW«9QBtuB´O›B4?"Xô_,æô2òKýXš‹ÔÔøH~”¶Ó‘óÞæ:i,I™ˆù.…m¦“ÖQáètç`�ÒüR|¨Ä'§o¯~»³gëÿ{ê 1¥³oÇvD±ÑPf4[ñÉtOw£Åx÷­znòXCPÜôè—MJsó¥ÇÓ×ÿ�Eþ\óÜ¿¸{XeÂŽÜmK­>'ê£91gîœ�SU»ÝŽÓéÂVõdlÓ0Ð:“ϛ̥—\åÞgmfÞ[oòî¢uò˜õŽUQ�d�ø1?½î:®›‰=äVÂgi6lªŠi³¡*'~Ǧ'ŸC&)=º‘Ø µ¥j•�JEE¡}œs;ŠX|Wº÷ Û??ƒAç-ÇáÊŽÁCìcó;ÜsÏ4AMšÄŒ·âlj _JèHeBâK!Bkç›àf^»ïaæ•6±È…¢—Ú�SÏ�Æ�מÏ�¤fÍViR«žƒ›{¬µÙGñë·žâŠnÍ=^•ÊETõøñtävh[jõá|sæÎᲩ—³wï^***ðx<ø|>t]GUUž~ú¯hš U­,–eQ^^Îo~ˆK/™Õ¾fQ¶å}þç‘7XU``)Nº ÍøSN¦gªÕWÂá=›ùnõfr×Ïç…�_ñù•òÄm?"#qê8û÷|½|˜ü>�ãác°ëß¿åæ÷â¹ë�¿rU÷ØœbËjàߢiÑ_yëÿ›”ãÉ[9§ý_ òT—‡Uó¿$ײ“� QQ¶‚yKó™xIF#*;J™�øBˆ†µ�sŽª¨d 9�QÝë7[ )G÷ýÀŽÜ],›õ4+¿Z̓O?È…=bq_ªuÏÁÕÇš>`Cº5£‰n;‰^Nˆ,oVMºŽÝm;m2œÏívãt:1 ³j MMÓ°Ùl¨ª†ÍfGÓ* ¿iš$$$àr¹[¬üçñÈï^ç» Gö$îzø®™ŠfT­¯((Šå;™ûâcüuÞ.¶ÎzŒ�Oñ ƒqF›� oÐ_ÿ}«”íÛa2¸²ÁÚ>Îg'ª{~i�yl¯¢ü® ŠÂ„×_'iø0EAÓZ¨÷keÞ‹¯ò]‰…Úã|þøâCLLôú0ê~ÖÑ›‹óÝ�wqÏ{Ùöþ‹üûìg¹¾_U‡¯4——cÅ¥Ó/'�¸zû*ãЮ^ÇU÷Œ!‹òÿàö'W`ž|=ÿúûµô¯?Þ•<÷S,3úñ˼ÈÍ'U6µôµ¯rÇŒ¥zþ”¿¿z Ãl:Þø ÷ZVuÄ?ðÞÃwó*ÙW=ÍÛÓ‡4þÃYl›óO¾¶”�eƉߚâ ë”iÜ{ÿ œ™Ug+z.‹_}†™oä¨~âw­8Ò9åÒ;xàæ³ÈvÔÚUíÝÖù…¬’M¼ûô³¼ñÍAá2ÕèÒ¡ØÐóàb¾èu/½y+Ã]–eÔƒ4ú•µ•0òdèEämþ=åÇ‘ÖëOü vg7Þ8œ=±ôͤ÷¹ˆÄÌQÛóoö|s1 çÓcøchŽÔ¦wP/oe,ÿd)ÇL•ç^È)ŽÊØÐNæÂ~ðÏÝ+™·4ŸI—d6Øé0rײyô]¼ñôôV L ”ѧrö°x~yç;ìÜñf­¾ŒÇWÞÏŠ¸ †w_]"¾„ÑiqΜ$«ŒÕ ¾&×5k8#»×^~®‰í4»}VùÏàŽÙ<;{~[_~þÄLîWuNïMÿAc™0ÐÅõÎgÓ;¯ñéyàÒæ¬Bõü+‹ÒeðÁnâOåž¿>Ì´tÃrNbä¸QdÜ{Ï{,j*î(Ú¡×k�¨>i“á|pün”ªªØKJÈüì3FÜÔ�¢Ï� fiLºiØ Ÿ/ÚZÂúû~ÍY_|“ý`“_ÄB!%+‡Òü£SÒº‘©B‘QH~¡�•¥Õ» Ûø¶Ž¢vºêoØ2˜ÆñO˜†N ÐŒ 4½”•W“M âÓõã�\‚ôå–×¾àN›EÀë!`Z€ÎúÅ_‘g*8Æþ„«*è�ÀñmAç1uà\^Üvˆ¯–íâæAÑÈ;€rÒU<ýúy•Øé™@¯½9CaÈ©Ãp}|ï�ý0­šU#Mg) `zNýÅÕ Ð¼øBÌ‘lO‰¥í_ŒÇ•�IÎ)W¢¨|¥_ðØq¸rª•þ5˜¦Ejö™¸S³ÉÛ6Ÿí_üˆþç|†Ã�VÞÌcK™³¢SëË” ¢YÕ¹Íæü)CyãÅM¬[ð%û.ºŠ¾uŠeÍQ©iœ{Ýz>ôê÷Œô¿ˆ©Cßç™ %¬Z½ƒÀøØ".ƒVDq'ñÕùãK�ö2œï¸Îð¦�‚}›Xòáë¼òi¦šÈi×^ÎÛñs|,Ûg`Óç_°'®3Æ/†j'œÓ #ˆkÜU\>p/m_Ïçßäsñ¥ _p¬/Ȇ7dúÇMݳ3âº?r×øê©1~Ö­üž KÁ=þ"ÎMñ£«þd‚A—^9�W7|IY�o"üvhõZ'ªOÚläaí»Pª¦áW ùQ[˰w‹£äÏ5ŸUTc`,4úœœƒ£^¶Lìý‡p’íKÖGÛn�E½Ö ê“6Μ0œ�ôtJ¦\Äš9s™à¦ÛÕ}X6k¹Êk>ï-H窙�Æöö²åÂíªüE=Þ°~HËãÅcŠ·S©Ÿ¯¦n×þC·p›J’ÆÀkä¶-¿ãåµÛ™óÜCÌ}1�†3vôÆŸ6�Ógw²*E䘀�ŒŒT”�ûQHKMC%³¨ˆbRë^V9á˜-ÌŠ¬\0—O¾YÏÖ½¹”ú«®Ì§Æ,]U.�i¤;ë¿ß.…‘GÅÞ—!“¿¢èàÇÚüùû_¦ûÀɸ“3ѽ{qÄ�¦äØoÿ-.‹^#Ÿ"5û2ü>_ÍcšMßÊüE»Çø)çгn>“Nç’ ¬ü2—EŸ®ãÆ!§â ±%¹öÐÇ™œ’ŒÊ̲RÊLH7Z¢ Öz/Ôÿ%¾:w| !¢Óâ¼Vœ)YdÔ]ñN/%/¿ SÍ`üϧóËi“ ºn4œýpê‰PéŒbŽåWÖ«{fýž懾â(-ÂÂÂW�O©ÁñáÑ�å ?ºçUfLjh-½j ¶8çñ:Å(¥¸¤²®IMIy JriÕÙm¨½Ùœvh êµÎPŸ´Ù�¨ê¥Í«_ÁÓO§`ófŽt?”Ê×&2ïÃB®Y¿Ÿ×Ëþ8ƒ´1£1ŒÞöQèÑ=•bÊ¢ÀCsŸ#æÏ=ÈQ{wz5­Ë²à†gÞäÌ%s™½àK¾Z»›¼­+˜»usß{™äþ“¸éW·sùà„ª „Áš í6­Á%<4{eq±‚A‚Mz«d-/>8ƒïôA\ƒÇœÉ„ì ’]l6ÊáoxgÁ6|1JWM±ÙÛ®P· Ó4ñz<$t›Âðìi”]ÌÎeWÓwÌ•ý…(ÚQr7@ÿ3g‘ÔmÝ�×ã‰h_ž5 Y”g&Ûß¾Ÿk߯ûc+å:&…_-bù/Çq^¨å‡Z´Ûæ¨Zù(`T•¥Ø—Á–"ñ%„­Íθ;ÿÅÓÕyv’o /Üzoì.ä@q<}SLü!o£Ç�$°°Ì�`m@w&ÙnÐ’a÷N7 ñîf,©f¿`j†ïi6[è´Š‚Ö¬•3š}½Öê“6›Ô¬Îçp8Ð4�àµ×²î©§ècŒÂVìEIµè~üºÃ4Á¦7^0|öùߢïXÅê⋹8­9…Kgó÷›ðZ õÎÐÄú#uC޹5ÍZC›B�E­~¿î¿š7Š÷ø‡ƒèº�œ³¯á�s¯ã¡`1»Ö¯båŠå|úé×lÝù9Ïý¶ÛK�2µ» J®ªûÌ>Ÿ“P�kâõV.S­8�ÄUÍ �w� ï>Ϭ�~Ô0cæo¸ »V9�½*Ú«�1{aecÍŠ:]Ý‹(ío$w(‘ä2 ˆKž€+i0%yßàJI§àÐç8“†—<�§¼é 5˜©"–,ø†"SAµ�§ð uÅ4U!X¾Šy_eÒÔnõç©úýø­PGiáóWƲ⌫,K—ÁhâNâ«3Ç—":í#Òk�§ƒ<uÖjVúñ‹{¦ñå=p`ÁL^:ãyî—Pçãö™âÄí°3òæ¿óÂåé�wv ?^_ ßfíO˜˜–ÞºÔŠ�¸ª+—º_ÇÄU/½åõâ5�ŸÙ#n‡Æ¨^ëèõI›ÝBQ›Í†ÓéÄívsôèQܽzrÆë¯òùν|±©œÑ¿ÿåx<t]oz£áç‚äñçð#·‚å[ˇswÑœ¹mfÁRf/-ÄT >÷lz+•ÛR”Êà¶ #äÓ£ÍÒbŠ[hˆn}fÐ�ß[�7à {Ä9\uÇÿðú;᪾6¬²µÌ]r¨ò¤¡fÑ«»ÉË=\ÿ!ÃÉ;†‰‚=«{ã·¥�ý|÷ýQLlŒ¸êF&¦êx½^ü~ºîG×}äÊ¥¢îwiº.È0‚ôú åÅØíNÊ Jè1ôAŒ(/4˜¹‹™·Æƒ¥öàš™ ùvé— ¼>ãÍû¡Y~Ö/\ÌþåÚ*=Â_¨Ë ðh>& Zzé*Q”Á¶Š;‰/!„hs–�cèõüúâ,ã0ŸÌ|ƒÕåõGOÄ´žÐº‘Ý݆B�Ü{)«(ÇÓØ«Y¨PSÈHUƒüüüúó‘óÈArc1 +ÖõZþ!YѽE©Êçv»ÈËË£¼¢”©—]Ä™g�NÚ¨œ7ë=Îyí\ƒPRZLYE~¿?ê}‡|%žÅõ—õÆF€�³žæåÕ%•Ë+6ôòbÞ³¯ñm™‰š5™[¦dÕüÍîŠCSÀ**¢$X7­IáºïÙU]Òên·¡ï·úíæ�¿�Ýë¿áÓo÷â¯yß ø¼ølƒ˜8.“¢ÂªcUÒ1²&‡×¬c½¼úvVo¨ÀRì 9„¸ÆònúðTX€Bj²Ó¨³­À~>]°±r⺃tuÏN±.#-%Ê|¹ÒŒÝÙ‡#;7çÌÁ•þã(·ä‡E‹Ø¢[hýÎgJ?ee ¼#™‘£ú¢a’ûÝ*öBåˤ`Û*6,¯ì´ÅèX})Yôï—€ŠÉÁM;(ª{Ž·L|ÿ=bÑ�¦^«­­ËVCßA3EÐ/Œ.‡Š¢àp8((Ègß�}Œ?†SÆŒB(..¢¨¨�‚šWqq¥¥%•�¨–øÆ,•¡×?Àõƒ\àßÃìGÿ›Gß_E®¯N¤d÷þþ»ûyfeV\?®zh:ãœÇ?gë™C¶fÉj–l,Ǫ•>xx13ßÛŒ©Õ�Ñ×p‰R4 ›T-£Þœã1 ¿æÙß>ÆŸþü<ïîðœ�°À¿“U ±}úö¤zMÂþç_§Bp÷\^ù<�à éüìúèm1Q“NcÚÄ4”Æ"OÍ G– Ù¾~ ÞÚŸ å›ü…Ùe™$«`ùŠ)®þ®#M×âQÙR¢Ë— Ð{ÌL*J è=æŒ`È3yó_þ Ìûì†â`øEç’ÓÔç3'rÉ'Š™Çg ×á©ó�)V ‹ßý�mÞÚï›­ø�y{‚(¶¾œsFvUYм Fw_m_BˆŽ#Öui´ç�†þnbºOåÎÛÏ U184ÿ%^YWqÂù9òöY¨ýCïÉ—2.^ÁØû3?Øyâù }ÿ'<õ?�r×Í¿â¥Mz �µ±—�‘gŽ'YµÐ×Ìÿm,;á8õCŸòÏwaª±h‡FS¯…ÞWûx…'‚9QÑéßïdÞy÷m óX¶ìë&Ó˜¦ÉåÓ~õ¾C³j'só_þŒ6ã1^]s�%ÿz„¯ÞN¥ßÀþôLua7*8²o'?*A·´´‘Üðð nn'Pë¾°Òçl.ü?l:ÌÜÇï§ð¼Ó’nÇstË—¬ÇyùÍLùôï|”oašÇ¿ËÐ! $ö¦ošÊw‡óøøéÇ)�Ic¹ùç§Ö<ù¹.¥Ç¦ÿd!÷¼¿•×ﻃU§O`\ÿ,’ì&Þ¢ƒlüæk¾;ÄÞç ®ŸTY¨-€îñ›éßrçÌ5,ö×ܹv2‡õ >XÈžµKYøÝ¼Zwλ÷N&%Z5C ™w5‹s.Í«›W‘7÷Iîõ^Ĥ“ãÑ ö²vÙ2ÖNgÆ_~ÄÂ;žà+ï:f½òÁ±ƒ9íÌ!§K¬÷«¶±È£êÀà‚ê€iFs�Þ¢dŧ,.0Q\c™zNM�TNàì)§ñâw‹)\¶ˆe7�crŠ‚eY˜€Úçε}Ä=wmçÂ�¥_šJéî•Ì_ø=‡-=/º•+úp|Rl„e0Ò¸“øêÜñ%„ˆN{Œóód$O¼“;>[Ç+ññ oqöÌéœâ®üsÌÛgçqÿÝ+¸ýÉå¬{í~~¹v"çŽË!ݦslÏ:–.]ÇAŸ�ÞSïæ—#í„õ”|÷Â-\þrsfD©¤žÿÿ{Ë0lXÄýègÜ8j9Ï­ÝǬ‡Å®IgrJO'ÞÃÛXþÕZ|§ý„É?àÓc&V´íÐÔk¡þß‘´úç¿ø÷Øì ­ÙÕ0ÝïG÷7´fT”,ƒ`ÜPnúÛüxÉlÞþø3–m<È®�«ØUõEu�’3– λ„k®˜H‡½%´zpåïÇÑÇŸãÃ�{ùú£½|�‚êêÁ„kŸâ‘«4Þ^¢€¥W®껬]zµa\3}2+ž\Äþ½+™³W!nL7˜4|Ñr0bú³Ììö¿¼øþb6.ù˜M‹«ÿ¨ º³=õî¼m*ƒúñ±Áôžö8¯d¼É³ÿœË·‹g±íËêd2†\È-Ó§sõÁ@­³A‘—uуüéèŸøÓûß³eÑ»lYŠê¢û˜ŸðÄC7rZ²�¬kG±éµõìXð [ÏMÂÈÓ jð ÐŽÅ �¦a`O85ê¹P˜ÇX¼à;ÊL•ä pVbå³÷©S˜”¾”�òW3é1ν´A¿Ži�š<”ÿ)'ýí)þõÖËTT�AGc~z7ß:·<¾›HË`¤q'ñÕ¹ãK�öça´¸­`*S…^àûƒóyæÍ3øûôáTö£"¬':÷&Ý&?Âk™ïóü˳Y²n!o­­ú›¢âÊÁÔé·ò_—Â6ï«´ŽÿC¯(¡°9iPQüFÍÅHËêΕ| 뙿òê’=¬Y8‹5€bOaÈ”ßðÔ½YpÇl@Çm;”ØÖk‘’qÓSJårÃûŸŸ^ï–eaš&†a°kÛ&N8¤µóØŠT{»Å(ãè¡å¼ð«'X˜¯ÐïúðÞô(]âÙj•T;q®8ô‚ì;RJÀžL¯œ^¤ª~|~ {BÕ$PQ†¿úÆ�ÝM‚˦o¹ï„ zªÝ�=XÄÁ#åŸJ�t'†Oo¢Ì)hxós9t¬�¡áJÊ$»W.KG÷ûCL®¬<þ¸8Ï‘8V†®ºHïÙ‡žÉ†ß‡^÷áu67 îPyW±Å¹°‹Ø·ï0ef©=sÈNÝç#h*hqñ؃¥ëq¤$i*|‘¦³¹ˆw;P,o™·�IŽ‘Ù½c+ý¯y¶™¢D¶üz3;PuŽ5–^A…¯Ö…TņÃéÏaö*ÀC<Ýz÷!+.€Ïo`‹OÀ¡Z<¥ø«“EÜ�¤^k¹öZ´šSGõù/QÝo’NTƒÕbÛ+·qûû‡ í ~;óA&g4o™¢h¨ª˜˜¦Ý™U©Ü–e†·¤¢¨(ªZ9¬È²°L³YéU«Úge3ÒPTTµjUYø˜F§IDATœPÛ©^1§Þû¦k]£Õ”ÊçÁ)X˜¦Ñ¬xˆ¤ Fw_­_Ò‰¢ýê*uTLÛg5Û¬]˜˜ ^ioE'œç�†/þ7w[MÔ“1«×ÚP¸�¨VŸÕqXX& ºâzÎXø$_~ËÓ�¾Dàö+9c@ ”{P“ÓHhà´,ƒ¨¦¨œ°13ä’œÍJj™`„¿¾³e!—ÇŒ`C4ú|ä�ÏŠ"]ÒÑóËijFR#Š;‰¯æ§Bt�õÓöYÍ6#« ZTSçùp·ÕD�ˆY½Ö�D0'ª³†UhVÊ9<øÛmäÍøˆ�?,àÉûTþÁ>‚_½ú8—wÆ…ïEëèb±$„¢‘:JˆF…߉êjÌ cïâµ7ÏfÁ'Kø~w>œ¤ô͈$Š"„B!DWÓ¬NTW·n½˜IC¸øúQ\ªU�/ ðëO,â «Ç’ q D{%±)Dóã ¬;Qª¦aªÚõ†°YFÝ´u6D+3M³EÊ{WŽ%Ñ5µT, !bOê(ÑÕ4»ŽªZTËhði(!9�n|žŠHò&D‡äóVàtÅÇ|»K¢«i©XBÄžÔQ¢«‰¤Žj²U}KKQ’RÓ(*,À4»Úú¢+2M“¢‚|’RÓNˆƒHI,‰®*Ö±$„ˆ=©£DWiÕ¬;QŠ¢ ª*îø\ ìØ²�’¢B #Øtb!:ÃRRTÈŽ-p%$áŽOˆÙ3m$–DWÒ’±$„ˆ=©£DWmÕì9QÕ�•ž‘…Ãî ÿH.öíÂŒÙ"ôB´ª¦‘��HvÎI$&§Æ¼Ñ'±$ºŠ–Ž%!DìI%ºŠh먰VçÓ´ÊÉTI)i$$¥Ô<Í>ÖOµ¢­Ô¾�«ª*ªª¢iŠ¢Ätu>‰%ÑÙµt, !bOê(ÑUÄ¢Ž ëNT–ªª˜¦)Á$:­ê ª¦X߉‰%Ñ5´d, !bOê(Ñ•DSG…µÄyí^[í�Hp‰Î¢v¹nÉ ðK¢³k­XBÄžÔQ¢³‹EV'ªîŽªƒI*FÑÙ´F™–X]�”i!:&©£DWM™»« !Ž“XBÑ^I%D}ò(j!„B!„ƒt¢„B!„" Ò‰B!„Bˆ0œ0'ªÏÝ/‡¿K¾&„B!„è@-ªär'J!„B!ÂPy'*š»IQöâ„B!„¢UE9šîÿ↑çj•IEND®B`‚Solaar-1.1.20/docs/screenshots/Solaar-menu.png000066400000000000000000001613471522022367600212160ustar00rootroot00000000000000‰PNG  IHDR̳È= zTXtRaw profile type exifxÚ­šéuä8–…ÿÊ1ûÌÁzN{0æÏw!¥¤ªìêê)S E� 𖻀tçÿuÝÿðUzŒ.kµ×êùÊ=÷8xÑüë«??ƒÏÏÏ×ÇÇ÷»ßÞwk½Oм•ø�^ÚxŸ8x¿ü:áãa~ßµ÷'±½ Ÿ?_IWÖëýu’¼_ï‡ü¨Ÿ×‹Ú›}�ê|´Þ>SyÿÏŸÓzýÒßîÛF”váB)Æ“BòÏÏöšAzýü/ü ©sœO�×%y÷|`ïÁÈ·å}üöþk€¾ùã•ûýêÿ<øq¼�H?bù>ÁñâO?åÇûéóúñë…ÓçŒâ÷Î åËyÿ¿w·{Ïku#W"Zßõ;| Ã�“�§ç´Ê·ñ¿ðÚžïÎwóÃ/R¾ýò“ïzˆdåº�Ã#Üpžß+,¦˜ã‰ÆïWLÏ{-Yìq‘˜�²¾Ã�FÆvjärÅãRâíø9—ð\·?×[¡qå84 œòÛo÷ï>ü;ßî^5[ f}ÅŠyEÕ5ÓPæô“£HH¸ï¼•'Àßïôû/…¥Rͦ078ü| 1KøU[éÉsâ¸ÂïW gû=!âÚ…É„D| ©„¼Åh!ÇF‚3�)ÇIB)q3ɘSªÑYlQ׿ ϱ±Äõ6ØD"JªÉÈ =E²r.Ô�åF �’J.¥Ôb¥¹Ò˨©æZj­VrÃ’e+VͬY·ÑRË­´Ú¬µÖÛè±'0°ôÚ­·ÞûÑ .4kpüà�gšy–Y§Í6û‹òYy•U—­¶ú;î´�‰]·í¶û'¸Rœ|Ê©ÇN;ýŒK­Ýtó-·^»íö;>³öÎê¾ÿFÖÂ;kñÉ”Ž³Ï¬ñ®3û"NŠrFÆbdÜ” :*g¾…œ£2§œùiŠ™dQnÜÊ)Ì'ÄrÃgî~eî?Ê›+í?Ê[ü«Ì9¥îÿ#sŽÔý1o’µ-ž[OÆ^]¨˜úD÷]+c1£c)ænaž3X8_c´R¡‡U-ˆsì:n¢,ZYt±Ñ[Ûkt²`ùŽRvlÎÒš¬•wO)–fÛ)2«33ËÝÒr‰�¹uMÔ(¥¬Þy#4Þn©ýÜ‘\«÷¤¸ºÏ;žÕvè$ºîœ&0£«`fßo ˆ/±(w–ÜV-€B¤Ð—·ãŽ"ëׂêüXÄ™)‚s(• ¹éêÞ¥Hxe‡–íusÔE:1lt:õëu…èÑßNa¥EjN›Ö"-3’‘Î.õ'¾�¼Z kÐS„x®kƒ‚¤™£J±‰Á9Âæ sœžÒܹÙ"Ð÷€-ÓS¿Lvrp+"©5nfc\‚bw>3"ÇQ¯@ÕLJ§f�MMD£\²liÔ|Ò cùâÚ!LÇõ±ïÙ„œ�ø^* pdðshù°ê¦goê̼GÛ¥SÉW}u�2 ¨RQÙ1˜#Ü—Ãr‡!b°¾ü­ë’žZ@Ř©ùa¹Î°ixã²”?Šóò�W§ùY‹^9"Kk´zžôµiCDA éÉa`ÉÍ·²)M¢“(÷l!ÓÛ¥ÏÉÂh‰ÕHes@(xc›‚ ²T˜Æ˜Õ«ºRÔl ±k{ZxžðÌiø¸»Ý}GȯÜóÉ—÷UÈž@6‰™‘‹‚²•èf*�F¯Ä…ˆªZ˜a8õ¶ìŒ·¹ÚoV®…£i>>úø@oÓ¶á˹üõ\÷ONþz®û''=×ý““¿žëþúdëé.‰3Š{¾cæ0@¯Xæzµ ݣب˜ÀC5'ï”Á�%Æ3䦋ùüÅ:® tJT‚#D¤1·0Po.ÔK†ÙÇ�`)ðˆ O4z µ™ÐÔMò¢AàP#�Û·¥#KŸ‘7Eî`–Úß8†¤Ä—ó:1°Ö™¶ÔÚiæÀŠZ¥›™ž†‹JØx4¤èm]]45Â*@aÁµý„vå ²�d\"3³ÆjMÁû@!¼Kh 4h'ýÐæ>g�HÙ‡Ç(Z Dö¨ä&yÁK†Vi�H€Ãd¸Ë Êó:#«�kº¨åÚ®ÍÒ äqmCx éÜZ�UÑrHL"*DÁÇ%€þ6ejÀÆÊ´\—Ó€àà”Ø{-„t�j“ˆœ´ ~L :Q¹oˆ¬ 2#Ä‚“8[éa¨D„Ò™û�—Å¢@;<°qAÅÃé§e­×©·¦NÄ€¼à:`È ¤¡%ëê°>ˆØUE,Ÿ@]”IÒs…Î6waÀ(|�T[Ooî3>IØEü��…©" aCNF|&p÷¸•K¤âDLI¼à¥«jÈeªó*Á¾C®žÉáan�zP_HÄXÁYŽÍqƒÿ„REøMÐо0BC� 5—6n>×6î³�ÅÖb�½èâFæó˜ØŽ|×DçAí´M…î:/º"`é%™bƒ5 �< ïAD‹Šʦ±D€¾áÔðRsJY»ß„çˆÉRŒ<¢¸•’Žp?é át§D rf4W¿dtÀ­´++ ôºÎ€Ž·¥*KÀTl-|þáóNGËØú’ŒÆ5©~z›TÑÜ% :�CÁÂDøˆngâXƒ9hÑA#Vg•j$jz÷ptY£< .¬ëÃï~ÿÀS÷ PËY ¸-”}‚ì3©Èè#Av©:Ѹ€HºµI)¢é(¾ƒUXš%˜ŠøµJÏã}?~.€.ä2ª¼†_C<Š€Ò­9BHዲñë6"ƒµ·ôF*zl´º¯*-Úí‹a0‡Lô4&R½>�1¤¢Ê…ß™™µG.ù"?ÈEÐ`Ú ¤Æ¡ÖÁÊ#˜M¹zd�0È÷„µ³Ôh¡í‹Q¹ô6ì2‘‚b;‘ÁSÛ…Åw‡ýYU˱8£�îð1àWÜ-d—Š�Q®¨Ò�È6œþNÂòÆR¡ew.Éaq²`1ˆ]Xr½cFq|¾&úSÅD$É¡¶¢" !ÈÐ[x J €Áì+e‹mœÕ�½]Ùí%é¾PØ`ð¥wB¤‡›P{_ÒÿîN 夳R‡û�G3GøF+!Ým¸V½­³rÏl!ÔÒïjҀؓ~dSAü&‡°Ã ?× *™À5p—öѺn¦ô¡ñ1à x¾YÍÇOu¬c„EÀ㹓Ɍ9@Vf]:ÆC^AwYRN@Ä[ÄcVs(CTnà�.ÂßRµÚ¯°Jág”àèZ8ê`‘†V+øDÆZÃî%D7¸VÉ2W_2ð#ÈàfŠÖÚß.Üq”Õ†¢\n?óŽLFÍ Ü7‹ ”™JÝp;>ŒèÏ€eqB#œrw7ÿ6Š`ÚƒiÐ#ðk ¦ˆc•P ,�¡‰£1Õ»÷Óqç‚rÂà€ ÒÖÞã@Í@£)±hV— b–pù8O"—µ‡*ë�¿$€ˆ ‡È3J&&5mE« fFí¸~§Y)òBGg+Ð9GQÊ‘t ñcԖȨ]_ÚKT°ø#¨ñ©�@[^扆0¼…¶¬­ÐIŸ¸`ˆ»‰/H{a)*M¹·øÒ䛘€íùfI8Û°'”mP¤ ”ÌDÇ>ëÔîræQ@Ù‚xHuÕà•émKä83 Dszm‚QÉ�ããâ;necò6}ë·K4<êÁ°6ð³ü>5-‘…7æ8 ° ¯#Ä| �x�\�““Ãà”ÃÒè?:•"ľWÖFW—0±™À͆6k°¡0;-b|�^ÖŠ„¡o)_pÅJr \‚s# ¹& Å·`\m SX.ý9°W¬³9ø‘+u.OÙ"¾‡ì3’9àÖ¶¶?+|F‘1ê¿ØšU“]¸ †6ÌÙ¡8wqgû„ÍܘdÈc ¬àÙyÍt+çÑJÄ—è^¿Ç•¾ , É›W�ð.F$î€ZÇÚÉÔ„ãÌ�ŠZ41óRhÑVb{Y �)n¯ø#Õekr£HŒfæÔß™î—B[IÞÖ'=wë~Ÿvùs“`\ .vÝ<DƉ²XÃJ­&(H½Yû‘P„ÇĪÕäÆuk&U¤ÐVa3:EÁ^·Ô· pÕ`�´ÐXPÂU?»5pàBÞ“T0P|êFsƒ¸qUƒµ©AvÑyòÂÞèpŒ¤úýBŸ×al ^R„º€‘ Wùn4=ðë�ƒâóÉ4y¨´ÅÒ ¸†Y³2ÊœkQ©P£–F®Ç`#Î�ësYÝ<$é^Qi²á4 ŒP Ä2 mqÿˆq~'íð€‚=‘žBQž`%"¶‚�(:R·c6ÅRÇý±¶¼Ò oPåMh!‹j ]Ò|ÕÍ7Ï@QÀä¹…@ÍÃzEmDê¹Tº'œ>±¢À_C‹ î´Ø^ëóD‚ó³ÊYÛSGÜ%EÜu›Ýë­ºfL ~¦»ÚZ#!Q:|uw 97(~±w€!õûÚê©kË\Ú„ú"  ÖA•¹Œü2²ÆÀ#Ô_í~òƒÓ²"5Bá\ìYh+2×´1X^~±„ÁÒ…Âk‰>Á"aûƒ’F÷“‚ÃRÁ=.Ý� ÌÞ¥û¬àÊE§QÚUÓ6úVÖNet¥ +óU2úýv`mtªKÇ'ìÿÜûÙ®§z ÐnŽqÏA5ýñ mLem¬6ôç )Äa[}IÅ*�ÐkÕÓšˆ4\6Æ#‚“yÅŒ\D(RÞÈ-ƒ­(-ѫ׉".g’ùžñ3øcpž/3Û®QT·'w¶µá¦ÛtªÄ<@— $M$-vÇJ(›g…&‡(t§$í@:Ý�,�•¡G#â<êS<˜X\û�€nÃ[úÚ€3Œuá¿0"#Žýú{1(:ˆ·`Gg2æ4µ/ÖM9…³ÆU¥?÷ß:‰÷oÄ>3°gëbÈ6W½pÙ§·�®%¢“òÔvQÑ-§l¨´«ç�p²È1*â ¥î#ºdš¶É»ƒƒ@}$V`!4þº�SWáï¶Õ´)7êf jh롚 Ýèå}µ»Œrº�_*hyH’PêIˆ¡›HA»´Ê!Ìà§nKí.�V‹8( ^»`"=›‘§úN‘‡¦8ZêçÔU1Ýä\¯fïû1�QO]¡ã˜­Ce’¨{gEÈVϽPÈ"ƨmTÙZ’Hh¼š·îR„ûìŽ" †¸Õ‘ °Ì´3:ÕˆKºù È«=Ê�È˳çƒ,‘R€‹è?@q�uÐO:K+²Q»N5tŽFÓBbX[„6ÝÑ+Ô¦½L–jE’ì '&½b_A›!=�ìÉí�_‚ˆ|T탤¦])lñ„F¢ ëR…’$Á-òt}ØÌ5;ŒEÔÖ%¢3⻓¼hhêá442 Ö*Í[+@L­“¹è´ 囃vʳӈAø{¿Ý¯7 ñtˈ˜WÝR§VäÐ ”äï?õ4˜‡;')i£cX!Êð*…ˆÊ–vÐâë64Í-õ0UZ  Kɉ€½DË ¡-Ÿ§dø«¶‘4,.l'�CîÈ+‘$QÄa`êŠöo|¨C<,¸¨ËဈÉÕýsbäºÌÌ´u´q5ਰÕnð15 �àð¹ ¿nuzvÅÃ1t«¶2ÁÜ–n !³˜c¾ÂãÕ@ÖE4Ý"�º9.ˆ»êÇRaJƒïöz˜àL²$C;_Eî sᵋûC².æ /¨ˆ.£+XíU&ˆïÖ@ù”õÀl»ÆÑþâÿv:èÅähû�0%F«"f3‡AÖ]® `ÐáÐXÚ�2$GÔs¸A÷Ød—�@Ï Ö-Bg°Šn¤eœ-rÈ­Täˆ |š•ÚÐÝå¨;@z¨‹Ï†¶hú]ŒÔ¤h°?�€§ŒÑ¼;Dç%ÁäFèsÝb¢«–nwǺÁp¼:©€Øçu›$èA® »W85|ÒFÒÔE�€€\ºË�¿ÑSÏÓG¼–!¹ i'butkïyrB�Øo‘Œ;z :DJ éÈ[ÉŒ?ã’>¯6íºtÉè­D=¸OÑVÎOMÜèt 0›4€7 ‰D\‘pzª ¦%!ýÌKlsƒé²nôŸ«i{íî_%í™ô§£Å¿>ûõAx)�£Íðç|JáÇQî9ìËÙ?þ1Âo�sÿí ~NÀý·3Ï“-~*eàÍqâ„~åóIºž]†lÁO¥Œ#çL4çk˜®“ï—XVÓýtÔO¼ZÚ}•‡‡E:Bh„ïs»Ð?ƒz*jëVõBmòCµíÈ(5Ý9ås”ù”\Rp{h_J›7²ÀEZ u»ôHÔD°Á=6™Œ.ÝÖÃa/ÀY‰tcÎzîíΖUs,b=«ïUcÑ„BN=Ò„¼ˆ³¸”RÚa-ÚîÆ?ÒàEzô{ñ±cI )ßž|¬çÉ“y°õ-Ÿ™°¢Ö‘ëÏC%Ú®Àvè¡öob4µ½ÅÉL@k±ßt·kËCj êùØEû‘]ú¼‰i.­êþVœOµr¨™„iCCPICC profilexœ}‘=HÃ@Å_SKEZÚAÄ!C ¢"ŽZ…"TµB«&—~A“†$ÅÅQp-8ø±XupqÖÕÁU?@œ�]¤Äÿ%…±÷ãݽÇÝ;@hT˜fõŒšn›édBÌæVÅà+ˆ ŒQ2³Œ9IJ¡ëøº‡�¯wqžÕýÜŸ#¬æ-øDâYf˜6ññô¦mpÞ'޲’¬Ÿ�™tAâG®+¿q.º,ð̨™IÏG‰Åb+ÌJ¦FWf³Y‡]tùƒˆÇã)((X½zõÞ½{ Æø|A‹Çã9p §èd‘ÃîÈ?rhΜë†ÉE±¨¨p÷ž]§N§õL�ŒŠì›ž>xð`–íO¢”J’T^^ž�Ð-,<¼ƒwÒ´Ç€ Ø£hJ„äãT-¿�EzGðénåWJU¢I•€@ ¼ceÉ”³¥Dþ� N+§Á ‡Rß="ÿËø�ƒüÆ7›Í:´è¢ËŸA¾øâ‹•+W�Æ Y|Ž£—””|öùçaaaC³†Žw�‡÷¤÷í#Ñl1¥¥õŽŒŠt8œC†IJNª¨¬\¹re]]]¡¥¹¹9$4´ã¸Ò΀­ìÎÛÀ!ÐàŠì´ög;/·uo^J”â 8�—Ý ÈxºêlÛÄBÚ®S‹2Hþ•¢Ž^uÑE—ÿ1™3gΨQ£DQ ºá>WÖ²råÊYW]íp8**Ê»%vs8�„F£9!¾FøléY§Ýn0šÊËË»%675Ÿ={öꫯêe)--í�Ö§#v°Ž°–`ø!ÛyhkûzÜ>DU« ®|;D�?’oÆï/´ù›æ´okŽöÎÄËm-~mª~Úr`?<’•9„ü¡Èw{ÞP «Õª³]tù“H~~þ#�ú =!ªx´í¨~¨W1  B²·E¾ öivÙÄE©Ïa”úN×øfÏò:‡P„ÐyL])R hä’áÉ~#™K!„åã½*PƒD�ãÒE—?“¤¥¥B‚¾Õb§N›Mæn‰Ý¬ÖŒ±$I»ƒ‰aY†aŒœÁjµðOEe…Á`ì ®PJ%QìÂ%@þ:Ÿj<(4r¨ªZøÁ´D]h e Jü4Ò ç»yHï1Š2§>Ö‚0M6jƒ[�‚ÚMB@[Ü&B U„d²INµÆÉ¡ *tQJ‰†'¥ÔëÄCnL]tù_³ÙL•�nqéh!„”——cÇÇ#«Å"Ie†eJH}}}UuUuU•ÃéŒ��ïà˜T»1?7QµP†¡qÚû‘Ú™ñÛ™H0ÃT�[Ò@M k–2 jÉ‹‚ͶÅMy‹õ…5ø,È/ôK±ÚÑ€›¦Þ6ŬGUž¥‹.ºèÒ%Ðâ5§ „BQ‘¼€`EKayóÛùa»j’´m `4ˆZn�¡6b¼dE3)Ùø„¨/¼ ¢h Âin€ú›ö~Ô¡R¿·¨bú£ÚaTò_ÕRØÂ˜¦‹.ºüy¤5EÝ•)“€™oÐÚÚÚääd[T'Ðâ÷̾nÍ7Þ™‰·u’Wô?jEÑ¥!šL’ �ȇP¿aæAÐ×ëæÑ^[ÃïäÀ0Ÿs�[\¶†_ëßU]tÑY‹ ¨bâ”666PJ«ª«ããâþS€�Z²•ŒÔb_Þ¾>Ö0ˆV8D@Fd ¾6 d»ò‡¢ y�jè�[�|TxlDh§ÖL¦bȆÔìN„T¿‘&¦à\½-A#Át¼ÑE—ÿ:Áç>„Ö/›G""" >.N£‘Ð0û¡ H£TãL'JNø¨%j �òWªºø×b5–+àD%%…Ò–š™*ÌFëqQµ4RGh¥ §7Ÿ„_ð_íjZ¯? D£vãÔ…P«¼õÕx�Ýi(èp Q]tÑE‡–Îà ¥ò�@ˆ‹'¡n"2 rº‰G‘Êyw狸ȰÑFÊäÁƒy‹__œ{è@k ~¿S~6´¶x�|2¥­Z„d&$Øk›Ý”±DFZY*çˆxÑ…ˆn‡SÄ&³™CAØ…ì#§H TÀÛj›ÝÀX""­¬¿E,Ù¢m ´z–šÞ¢,H–!”"µŒ’ ãüñ„·ùV^ÿÆë¢Ë´P‰P^B%õ¢»Ã¬èlUóŽC¥ÇÎÔ…P«1ÔH­I#8�$r>”Ïâ7_›{Ó-m@ËŠ�>\üúâêšš„„„<8|±±¤¸ÊAÙð”žÝ,Þ<’@,tמ:SëA–¸Ô”(ƒ??Q¥ª#Å_Kó{_ûÌ6!ñšwWÜ•©®º»ø‡Å¯,ÛZXÏSj™ü¯ogm†¼_j¤ø=‹g?³UHœ½äû2¹@¥©n©‰ýêäÒ«ù1HÉ�¡”" ”:+‹KÅ–´aƒ).¡{|´…ùC!‹ºVÚ•×E]þÈЂ%úýþºÝ­£ËYÂBSº'Rk¤Û-x<¼­ÙVg³ï?^“‰�î¤Á¿RQ]VZZÚZòš{Ó-•U¥¥eGŽæ=𷇃cdãŽWï[¼_Œºâ¥ÏŽƒêaéÌ÷OÎÿô4êïŠ7¯KÂ~û{� ‹Ú£d�YŒ ƒ5¸COóÊë D‘6rhÏð´Œ4Æ'Û¨páUã,ÂkG ,7æÔ©ê+óì3ˆ�×™ æøà‚Ÿšƒ§àZ¬!ÆÈ^#'Ϻî/e„á?Äg<ÈÊ뢋.`h‘�%ªù[¯IKŒ1BQ�ØPƒ�uºE�H“Ëe� 79|œHÞ$»óa«¬¬¼øÂ)Ð"šššÚŠŠòg^øç5³f´¾GG:AËâúHu¶ËžPLã¡ÑV.F€ŒãŸ\¿ñIPm[šå�(Óíʧ–Þ7Ĩºöâƒ"ÜÒe·`ýÆ~V®¶ °‰µbC>tTIU q¾0:„1Ñé£&°>ü�<6gmyaeÑŽU¯n[ÿë㋞˜Þí?O` ãÕµÒE]þKX "(…=‡Ë§�L5q&³‘‰�4„X˜ºfWM½Ýæv¸löÆ&!”ÐN”î*CYyEUmmõSϽ¸æÛ¯V|ôaë IÕ · u ¨Ä¿| U€Çuh`óùJìv»D)Nê‘â3ƒùW†DÁŠ«n Œ!”Ê•`4*Õrú4 ÄK{(ä‹äSf@‘7� $Bäzg!8cÖãÿ˜"Žß‘ÙÌTfþâ??ÙU¹mÑƾ8#ëß2]tÑ¡å·� ”6:øS•Í.Aª· ù§ë�WW×4655;šmQQ!‘a&ô{–/\üækÓ¦O]ñч#‡�ú¿…ÏýãÙÇ;€’>nÄ!/CŽîå è²W”5£�niÉᘸ*�æ,ª°QSD·>C‡ö‰5‚:±U”6ScTjj¬ QGåÉ’ÆŠjPgUññµ€ŒF†÷ˆÈ›Ú=’¥îê®:u¶QÀ–øÔ”–Ú* Ê›©!*µGŒI.Xi¯((kkBZr8¦îªc¹‹*lÄÞ­ÏС}b -qW:rªÖ–„>ƒ‡ôŠ0"¡þì™7‘Ü+Þ¢ ‡ÓVz¦r´!T&WJxœ/@Î�0⦧o?~Õ ;¹[v×_reŒ¿çßUUpèèɪF'1F$ô88=Á|„Æ3ù‡Ž—Ô9¹ˆn1ÝÓ‡ôŽ ÚN®Ýå•¡†¨ÔÔX¸«OŸ­ç‘9®G�ÈãQGåɲF …të�¬±æµ [yA¹M^|±òðÎEMæŒ gDê&8]th9³Ųö¤@ˆ7S#ÀB{·¹¿çæUÆ•u¿¬€G<ýíª/Ž;بøåÆ£v�•ÍGBþÊûlð ºçÓ§zýü‹¬•peCüèù/<õ—ÞF©„œew?³ULºvÉŠ;ûc>÷ƒŸØä’ÃŽ~öøíŸ˜/¼~TÞç[mÖ O¬Zxqò»¢TñãÓó–æ“sßyïŽr—Ýý´ìš¾3àóWÞ¿`ƒ{à=Ÿ.ìµÖÿN8åN|Z»bû›Ï-þöD“VÁuuóÓ� Þ¹à�OË£f½üñCCYÐ £>ƒ:�À‚"ûg&3;NH5•µb›i<¸jñ+ï<ãT£9¶¤\rדŸ= \»äbÕ¯Ë_~훼jÞ{ Ë-F¼òïÿwû… šOl+N¸éaí€òÊ{ÝøŒxø£GŸÞꙸðë§Æ[PªxõãóV¢´;Þ{wnXg.‘÷á½ 7 ƒî]y§ý…GVqR?+õÂŒH=j@Z~»EL1¡u滛MdXÁÉþæß'kR‹+_}û󲥋ãbc�û-l P0Dñ¡B¬�CಟüòÅ϶x.¸ãÑ1鱜«2ïÇ�¿ÞSµç�×¾ñï9=0ø\û^K›6ãÞdžÔïþäƒ-¨ÇÔÛ¯‚™ÄA1·ÿP½wýöú —Ek�5¤|û¶ãpý¦LKcü؇š}Ép ê8¹Js'ÎwÀ_þÔ‹ßœ #gßxÙð$có©=ß~¾âñMèï ç}x„´hÍŒÔu@µÉLvÀ&‹©„ ÷½Gÿ¾ê$oé5åö9— íFNï_ûñ—;Ö,~à¬}Ñ×§y¡�6îzí¾'~® ‘™—ÝtÉèÔH³§bÃç+Öæ½ðþåwîŠÚpóÒÿ«‘4ú}XCFO¾}CSö¶½öñC´ïIEÛ¶KÈ�9i²¼R¾â8ï>ûí{ë‹CNšØ3ÜÚ7R·ê¢CKÅdc QàÅäÍá@ˆ¶VÙ¿kqeîM·È>Wú¥ü­˜ÙÖ+” 0€T¼a]ÖÝK]•ê5±Œ•à¸áÑ+‹vﮞÝ#«%&•ó8~ðÔK•5þ´bKŠ0ùòK£ˆæ©)k>>›»vkÕŒ«°÷’”’²­Û Ed6ub2Rân# jî„1*Þ~Ãc¾; MÛ?[],€yÈݯþãš$À�á�éóäüWm €0`„ÌP"Éy+�¶�·Å¥ºQlpiÛ¿vG9;``7¯~ V-Z]ìa{Ì~~Ñ}CCä22GŒîóÊmO­;üɲõS^¼<ìË·~© w¾üÊM½ `6›‡ïnºë±Õe?/[3køœÜ™Ä’5ù¨Mß×eoÙo¿xBˆïÖ¥ÂÍÛÎJÈ�5eB"îÜ=fRºeSÒ•‹–ß>ЪÂtù³Kí¬P „€D(¡¾â¸Èçõ躔IBȶí[—,}ç¥å«|–ﱦ~úŧåe„�¯¾ýù�‡`0+ãJFŸ]µRZG¼R{EùÅ_zÓe©Ó½)sp€T]QEÆh«VÛgÆô>ˆ‡×o:C|FJvl)Á2lÆE²&k=Å_âw'Ô”9¸¿�T]Q)�è9¸ç ƒ@Èè+.Mb¼½�Âñ“ïùK_©!ò>   r0 ¢v6Ä]W¼ïëWyfm%Á!ï»j°÷N„#6œÁ<|ö_‡„h©`Äèk¯èÃR÷Áõ;k‰|䯭¥XF\qe/ß4�uÈ_n¾úŠ™WŒˆæ…Î ØBLƒ¦\‹©#{[¶]31ñÄÖ­¥2gM¿P^äÎ\ .Ⱥþº:®è¢KWùZÔ:2iáÝÁíÝ´ti&þOk~%ñº97|{ ~bJØ‘’�+³&þ²qíÊ�>€ÂSe…§Êþñìã••••••ò) š±]‡AËê“Ô¿d1R‹€Ò3Óý}ÂLh¨ïñx´%/ÂbŒˆa%o'Ož‘µòÄÞ“×\;/ƒ@¤ÓÛ¶�”˜ˆ±—Œ�Tꌵ–yoH�nð«VƆ…ZxÜ`0ZΦOœÔãë§r6ï³OšŠ€?ºi{Áã§z]9¿áÈ¢#‹.ºt´Èº‰xY E ƒy·ôrž!èGËž=;Ç�Ÿàr9ÌôK Ý|¸î¾a„’Ɔ†áÃGnÞ¼±#нan4X­`µà/ _^7ò•²X ÿŒI¨x=R> Rlk2Ú zÁ%Ælû©zÛºw ¾À Rñö­§%&qâŒ�Õ§Õj”–†*fHm?xa„Œ£ÜœXvˆQJ�3[X ‚€Û×P+ÍeÙ¬;—¾4=Ägs{÷ž¾©j(³E¦w3!Þ£Y�€R‰øÊÞ›d&Œ“|G˰m)éŽT˜^S&öþdyáþ­{›'NGà9¼uG Á±ã§e™~ó%k`udÑE—.4ˆ!E+S@x"‰,g@/G‰aŒp×4‹‚†ÆÆn Ýl¶f‹5d€wÍñQi)·Ûíq¦$wojnj5/àÚÙ×·¾ß7™uÙô©©±™ Kˆ¥ew¯MÜ2Í1X±~¥®#ÒTX1 ¹dZÒÚ�Kwý²Ç>æbsá¶ígÛ{Ê” NƒR¿¥^Ž ò£(�Û£<}…Rzì6IÛyG¡j>/Sð¶/Þ»1õ»é¾™ûþRúË[K.ÌüÛ`NSÇÀl5;`fF·IGLf#€Ëí&Òª'°ãÜýâ‰ý>*<œ³}Oó¤iឃ›wÖ&é⩃ ]u ]tÑ¡å­arxs')¥ï1š-¤Á浆aM¬ê9‹$Ighr4U×U@¯”ØŠª0MFƒ‘:ûšàøÒê¸Æä”XeBÑñbqBÿ`ë":j#€cSSCP0 Ô¼M5'äà=ÀûÛç’i½?_V°wË>۸ĭÛK ×ú”ŒŠÍ¨mËÔá5.)‘1‘˜V‘ÚêB-%¨pºè” çIRM·2Ù6¨ä· àÀ)_Ä2äæû§xtMåOo,óæ]#ÕUbâ“âT&U–WKÝÖgÇ%Æ3P!U–UˆÑB =<Œ2/èø€­]'ᢩ>8œ›³uŸmêøc›w7&uÊä>¾¡Îùºèòg–.jF¼1‰È°�Ä{°&»taΤ$I©É=û¥ÔþôHêÉó<$vëô§-\¶÷ø1ñHÙ†ÕÛꃰ+R½eåÚR ˜äqõeƒ*sŸ¡Š�ªBšÿ2+*(N™2#ˈì¶ýºËÖ2b:mr7¦EŒopvêX)°€”€6JQ\Zª•éôác�šÂ6”ºnÜQI”R/J¨€÷Ñ!„µÏ¯µˆ12ú¶{&Ç ©bÍëËs¾:�‘ƒ§2@ʳ÷‹�ëZ{|o^™ÝkYÂQ&1@*sœò³gIÝ3eêÔ)�¯­§�°Õ~ìE“†˜Á�»+·>ï×Ý�”ë;yZO­Çìœ/¡‹.:´œ+º(½­äFˆ³3,è)]çǾ´¬¤¬¼´¢²¬¼¢´¤ôLAáñC‡sìÛ9ŒjpÍ_ÇFbR¿ý•ïl>ãÔ¸†Ä†ã?½øØâ ÇN¸sv×.aPÌOªª§„JDR‹=*¾è^B|­Q˜¸ —� AÎ}ËߨT!£§�‹J) ÔæÄ0¦Ø²�‚bHµ¸@ÆÁãF„3Ô“ûõ'íc†Á Cª~}gñVg‡5¸Gi@õ1ä«þâ×OSSøE޽ûö1H*ýéÍ÷r�Ê;8uêeY$�þö�U…ÚÅž3?¾ôÄ“÷Üt÷Ûù<˜Í!¯˜5<Âb¨\¿rc 6›åîÅbå¦�Öž•À�9&+ubÀ6ÈvÔØÉÃ-àÈÛùÙ–} ”¤¤³@'ïY]t9/1P‰äÈcB©ÛÑ, nDv±È¹ø¨‹Êé#„ÜwcSƒ�3bŒ ¥¢À»Ü.‡Ó#ž‹Ù ÇM}♊Ç~zèø7 o]—–ѧ[„ArÔ”œmôPÄÆ ¿ûù'D¡vïPm4Œü<þÈçq‘Éœä#½Ì…Ž�>>fÛšÊ*GOŸ1*ùL[¨¼øÏû¼Zjª£R\€uÌõ· ÙûVŸ¸ýð¨Qã¹Æâ;rY»¡÷ûK7º|5.Õ —²ÉÌ›¢š{ñYÈ(P„pÜ”{îÜœ÷ÂŽ²ï8aÉü¡Ù5ýáù{ç¿¶ûà²nΙ8yxÏhޝ)ÎÙº%§Ä̸ͦçÆp¹\=õîë·Ý¿$gëË·ÍÙ|áØŒ˜wÙ¦µ[‹m>tî½—xË]vpÀ¶Sø¨i£Cݼ}õf‘šFN»(ÍÎõºè¢CË9ézÕ,/£‹Álepƒ$xbeG Æã®aHá§ÎœbY¦¡±(%‚(@DDdiyIxDĹL%lÐÜ7Þòý§_|»åà™‚ÜªùelŒêsáä+oš3µ_DGgáç—ËÂ`ÕÝ"+~¬­š¢ÑÔ”R0½djâ/Ÿ–A„iÃÌ> i‡ýQ?Z¡r"?bº_ýì+æÞÿxcÞÑíkŽbCTŸÑ×>wû�Ãϼü>¨F0•`!ŒV+r"ÿþ-Ô÷!PÿÀ —Íÿë�ûß8Xúã«+ÆßÃŒ˜ IDAT¿Ï ›ÔÐÕzDmégGSsíù–'¾¯ëqË’¥·§1$Å[‚ƒ„üÑ÷÷q)L)*ºN‘ 1bŠœÿ流¶K©s—,½£7C)ÈAÉX©ÒÓF€ŸÒ†,f/ z<žVW¶¾ìle“›²!ÑIÉm-¬h«,-«w£b#"Z=®ãžÃ§á¼_B]þ+eòäÉV«µeV|WF¾”¥Ôd 5ÝÄÖˆ"ä«Ü%Ab½zõž°gß®ƒsEÑë`eY6**jʤ)Ý“ºf2Ø™Ô;2©kŸ‚7ÆA� }XåOÊ×}±±†Z†]qY/¦úhjzÑ5›©¦�bÓ4«ên(+-+i0e O‹ SOå Nˆ É=âªZðŸU[ÀØý(5¶­Cî4lŠJI�Jé¥MHÍH³Ùìr¹ºbÀsø4œ÷K袋n ºi•»[QJ)¸�6Áã¤�§@ÆwÕV¯W¯ÞA©‰(Š-ÿÞ4ÐûOÀŸj*mœ)ì8þéó˹˜ÄÙ�’ħºr€"ÜD†üšfR !càÏ|ýØß¾:C“®|aÑC#¼f ê>ùÕŠõU"²Ž;ܪ4¥AÞØ5�5ÎÏ ”ðs·è¢‹.ºt´`Åü.Ç3,ËŒœ�yêõäýã·&WmHç4@+Á¹¾•òd^¿ºJ_Hõž/¿?XQut׎#•‚!mö÷4µÑsØÛ­Áy„±6óQ‹7¸ÏÕwLØòÔú3ß>ylj Æg¥†c[Eþ®¹•<Š1ﮋ#½8R‘…RŠöœË¥ T,Õ[Ï뢋.]-ª•�(¶–5pœ�a XàåbHŽ[úc¯…×}}Þ[,·º½§ GÖ|ùÕi asâ×ßÿè�ƒ¬�”ùS‘6 ‡hë4¥TE„ÃÆ\üø¿_M]úáw;�ìøáÈV ØÝ÷¢Ùsï¸n\" ^ÐCÈ¿€‚l£êxò‹T©%£‹.ºèÒµ¬EõJ)E·“wÙ�!NM«€ÿ†Míï¦"‘6WÞ›ÖlŸÞüxj³ÈEÅÅ…Q°%£�1b(hõ•–ta…ÇPJG�˜óøÈë$gmuµÍC�!111!¿œ~÷©é£šÈ‚Õ×E]té*hQ7¶j “ÙŠ™fŽ3H`¥‡qWÿàBϯÆÔ&³(!¼ˆ6EwK‰V1µW-Ì/g%°!¤W@1Ž!T‰x欱‰©1Þ3ÔZ:o�Mý·t|ÑE]Îk‘Óè¼{bžw±¬Àåu´(½&ñ‹9ý¾cû»ÜQKn­é|€ þ!‘ÑÓv¸§Ô·GUüÒVMöeÈ(Ë®PK˜u„ᙕXd]tÑE‡–Î⊷#‹RK ,Öp£ Ì<lr70À!oÁú?�tœôhˆ‚OY+Ž–y$j ¯ÿ…|gk �*Å ”b„{ëPªˆ¢^)X£ö?S¬`~÷ÊÂ/¬ÙïZ�ÒfÐpGEÇ']tù3B‹ªå~-DöìzÍ=Ú.“« jwZ�€¾`­�¸„(P­S?;`Œ†E‘EÚvdš¬µ|>U«Xú³Q5yE¹¤Þ±&8­Ýâ7!�ûWêß:]tÑ¡¥#¬a„)!¢D‘¨¶o—Io1¯ÇE_ñ–XÒÚª¶ 3²:G ÏðµW¡r³OeB¥Ô—5‰1BH’$ÙûEJ¤ áCQM‚gÚø,h Þ$mõá"†3p¬·#" ¼ éø¢‹.:´´!‚À{x7%’H¨Û#²,ƒY–pÙlÀ f0fbb†e0Õ7­¿� FË\DÛPYa1�˘a€RB(`0#³"I¾rC7ªIÌ‘IFp’ê»õ"­Xk0° xܢܠ“3 êöˆúç@]th ¶ï¦´¹¹ÉÞlsÛ›#C¹ºÊ Þj1YÌrB¢SÂ`<îZGcF¯8“‘#¢ÔØØñ;3Ô1®ð¢5­‡Éö._Tž&X›�¢¸÷‘lñRíPTæ1ZB„šBýMtÊøÕ” ìt†s š5‰1"H^ˆ¢D"„e0Л�袋-AÄívK’””œxª¸pTï>Ö༭©ªÁæä]1Ä,ÄGCM¦p+—c 5'ŽKIIöx<<Ï�F}õÛÅ—@TQŠÝkU¼¯’²‚%ZÓõ²µÌ>Jüj™)gRB´ý+)¥¾¦˜>³›/H HÀZJJ)•#ÕT·‡é¢‹-­ˆÉd2›ÍãÇŽËÉÉÉËÉ�ŒŒŒˆNŒŠ´&‡YB¢- H"oknnl¬+),¨­­îŸ‘1pà‹ÅòûãÊQ—u>{Fv«Ë¸€@K=|ƒ!ä”"„0f!@©–ô(}e¨`��� ¯ÅÍ‹2DñÛ«�cP»s ¢ bÎ`‘̰˜Š¼Dôož.ºèÐÒšš‹ˆˆ°Z­Ⴧ >{ölYYyÁ‰£/ˆ’(Š’ÁÀ8g`ããâzöì~Ñø±‘‘aaa,«7WXHë�£:Q|ìBFÉ!Þ£FÞÖõ@’ƈaX �D(‘‰‘¹ˆJ�¨fL”dM con‹|¨âöW¿\S�IkeF”B†aÀˆ¤‰é¢‹-íÇqÑÑÑÑÑÑ}ÒÒAA’$Q%Ib†eY†a8Ž3ô~|�ƒŸ¯ÃçA²º÷FSŒ0õEgy½ð#J©( *>I’¤´Ãê°ÈWw!Œ|.{ämFeW €ìqQè’—¨& ¹Uê‚9£�‘x�7( 1£Á· ]tÑ¡¥C$Æ`0èrNBÕ€b?tQÿDùU‹TÞPÈR¸‡üÈÉ’˜Á20È|­Ç^­+`1ôö@Ö¤çSmFŽZòÅ‹]H+è‚QIR�+T%jd,�`Ø¢gGꢋ-ºœñØjlnÊX"#­lPB£éFìå0J = €Œ©75‘z›?zškmÊXÂÃ͘ø<+¾^, M·G>N�XC© KT­Šé#T.Ýfd`Ðì}otÑE‡–?¡¸kNŸ­óÙ½Wœ)H±b{EaY3aÂSz'Xƒ¼í¬,.mÁ›šià÷,žýÌ>qöÒ•ó2Ù–À¢q³SJi¨UƒÁ@K,<»ß¸vá&wÒµï~xg6,¨†–øÆ÷…*£@TðFŽyéQ"ZA"I”e8VâEBfYŒ¨äçÇ÷®0ÇöìÝ:葉ª“gEd‰ï•ÁýדÔs›8uU—4¶– dŒNM�1yƒØ*N–5SSt�Ô˜V£i¨»æÄ¡ü²F2G'õ28-Z·Gèòg†–õ~9zìHÿ~™S§Lÿ½„˜ûÁÃÏíp²þöå+3cë;“âož¹ãÃ"‘͸ç÷nHnñvÅOÏܽ4_ ›öÜçO�E€1Ë0„e‚mîýQAá”Pm§1I’0Â^*ãuÔS¯5ŒzKðÈð@[r9¤Ló·ÚANÁ÷Ž€�¶R²ÂŸ‚¶»$ÏÇMœ÷¢DäyG‹˜ÿáCOþÔL™/xô£—§GµÂkÈ™ÕOßöA¡H�0ï³7®IÄÿåÖsœ¸ppÙO­µ‡¦Çuï-¿=ƒñ•¯Ø±â•W¾:T'â>s—,¿¹l«TüË¿_xwý‰fÕŒ‰¸è�yð±ycô­¨.:hÙºuk^^ž„„»ïº÷£O?|ûí·333'L˜pÞ/Œ¬ÃGgÍöËÎq\>-TÓ �êýûÏH �Ü{ þºä}Hrs D@æÁ 2R †ñ Öo\̦hwðùQ|ˆB0 #W “IR’T0ò ÖšÒ¼Q`Étƒ¢ ÒŒêMÕWጠ¢"U\2H-[D1J‚GZDK·4”!pX·­jꬄ ˜!®ÛX,©!Óÿ3ò›'.:ì<ÙwÔ€n-Žíê‡TÔQôË[/½»æ¤«ÍpqR¹îŸ¼²³¬i.›>"5 w­ýa÷¡/ž}œá­G„êÅštùý ¥®®n×®]9¹¹%gKÜ †Ôž©C¾à‚ ¢££‡™9rdÞ¼yyGrŠÏŒ7¶O¯~K—.ý= PDÖ¨~Üþ\Ï὇<ÓÆš´_]Ú”³¯@D¡á¡ŽæcÙ¹ö™SÂü¾šÎƒû�òŽÒÆwÖ¿@²’ýˆÔ2” #ljÈå�½½»|Í|Ú4Õn¦�ôR [# ¾rÉrÀ˜ÚY>cçH;i:íVøÁÉ=“*N^·¾äŠ›zQ±üÑ�Khxr2-+qþ/}ëĉÝn§l¿kŸ|fš¥ík�²õ/>ôúÖ2?îöG2¾°$;x€µï]öþ®:°»kñ+³{Êö²i—\vѲ‡îÿ¼èûwVÍxï¶ NW›ºœgh¡”nظñóÏ>÷ðžôô¾qqq={ö2™L”R—Ëe³ÙöîËþìóÏMFÓ 7Þ0iâÄóZÜ…Rêp8Ò{÷—Ó/~·ze8nÄè^Lîq{nöQ~l–Ö(íÌÛ˜G1“fŒØóåÚüyî)ãµ>iÏá}y.ŠØþ£³Âå]½½¢ ¬™¢RSce¿ µU”7ƒ5!-9\¬<¼ó@Q“9cÂÅQJŽ»ä¬*8|¼¸¦Ù!ÂâR êÓÍÊ P ‚) 'È8L}åŠWUAÞÑ“U�NbŒèÖkààô3%ŠÌWdŒ¯/>vâdE½KÀưèîé™}C°2’¯¿§þdA^qE½SÀ` éÞ§ßĦ£‹5|„¥ä›¢uë ®¿#£ÅçÒ�³~[%„NÜ3»´$¸y©él~þ‰³ÕÍnd �Ké7 _�p?-HšË +lÔÓ³G´Ÿ“�ØÊŠÊmÔ“ÚCë}�g-OÇÝÆtˆ«ªà�²Œ ¾e<¿wÚ��ÑÒþ—X*?r¨!aâCÿ÷·YéÒχZý5í\³½ž0ɗΛÕÓ·È2ðú¿Nøù™ug×ÿxè¯Ãt¯‹.çZää,^¼8..nê´i&“©¾¾¾©©©¹¹ÙãñB8ŽcY611133Óívÿý+V¬|衳†=“±Ùl!¡¡.—KÅúúúV8ÆyHÍÇÝF�Lyïø©ºû‹¤¬þ>õãÉßwÈ †¬!3†4|óóÞƒ{�ñã5Ð#8ÐD€é;f„×P&ä,»û™­Bâì%+î’ÝøBÞ÷.Ü, ºwå�öYyÄIqü¬žfDa ¤1oÕâ×>Ý}ÆId»•D6§\|óßÿ>{@˜bÝRe´’�4\µø•�wÊçP„­)nzøï³„+¾|®ãß½ñÏå[Šì’b‚C†Îzð‘[Ç%°Êb: ~xó¥¶– œü‚ÇãÍaJQ}BZ]|?j|Ÿ ŽoZèæŒ¬õeÏþå×›4a€´wMË�}ù–対ùÝ¡j^ãþ1Ä ¹bþã·_˜lP,B»Þž÷Ò’6÷ƒ¥í­Õü®=oÝ÷¯RÏ[–.½½7#{üû7ÿõÁ–"›¤Ñ7kß]·XF@Ø¢,c‡¶R¿qâÄiw@ÖKû(Æt»ð¡÷æ�J5# M­æÉ?�ï¤8~äèôjbrÁ Ãúí öKÃ2]qêr> …RºbÅÊ­Û¶N›6Ýh4–””Øívµïºì.E‘ÒØØxæÌ³Ùœ••åv»_ýõÉ“&ß|óMç�¾‚Ð V—£ ÓsÔðÄON•Tæì+!ýS•ïºX¸/§‰°ý‡ ŒXדÙ]x`±”¥~3¥Sûsª °=G�êÖªz@Ç!Üg¿{oý©Ð�“'ö ·ö�ÀÄž»ô‘G¾*¦áéSï¸vÚàäPR_œ½æã/wlZúÕÒ¢7®O3ª61P%+j6wé#ÿª˜·ôšrûœK†v£ §³þøË›—þ_�´è�ë{@ÓöÅ�¾µ©Î�2þúY“2“" ¢½ª`çßý’³jáBãÛoß”Á!Ò´}ñcÿÞÒ`ì1ùúk' HŽ0ˆugòwþøÝ/¹«>m~ï½;š�7>Zx^ fŽ‘ aìÄ>+�ß¾öÀYc´äŽ6îZ¿«"§_<ܼ!°®%­ßöúÃO¯¯¡!i—Ýrí¤AIá`+9´é³Ï6ä~ýƒvîýGÆDtîãF·/~ô­ÍõÆî㯿RžŽ½²À;�…ÆwÞ¾Ùk¢ŽÜ÷ýûª“~˸­fÓ:PÑè7NœÚívd±ZÛŸN6ºWqò´›Ó³w�àaîÙ;™Ù~²ªø”�fDèþ]ºZ$Izö¹çm¶æ«®ºº¤¤¤±±‘j¤¹¹™eYƒÁ E»Ý~øðለˆ)S¦îÙ³§°¨è¹gŸa˜ó²õÙq¨ì••¿Z,†×æ�l]uœ‡uL=2fuIÍéì57¥ÆË@!�ÞŸ]K˜C³bÙÄ!C™ãå99%$à =¤êÀþR ˜”#RÛØxb– e[6%]¹hùíƒB0J…ã_.Z]ìa{Ìyæµ{‡X(!”öJï?ltŸWn{jýáO–m˜òâåq V4R*Xµè›S¶ÇìçÝ74DaÎè?|TŸWîX¸þȧË7Lyá²X `ß»aga2n|öż~ £&L3ÿ�UÕ{wÝЯKÁ¹wã®:‰éwÃ3/Üš.æ0dÂä1óXÝp0û”�ÑK ÌrÎÀ‘ Éø”Rœ8iÚ eÇrv¬ÝÕ4z’oËOj·m8àD±—LjjZ0Ï¡ÏßÞPM˜Ô9ÿx}þ ‹|RßþY£ÒŒw<öCéú÷¾¸bļ¾�úœ;ömÜUOØŒŸ}áúîÊ“%OgU;]'oÌÈ`@,X%?ï2@FæˆÑ}^¹í©u‡?Y¶~Ê‹—ǶÇ)~ëÄ%§ÝE›qͯŸ³vûÁÂòz76G%ö:~æ5WŽM1uZÿKõÕµpXL´¥Å¹(&6 C‘TW]C B§-º´»�éì ¯¿¾H„ ..**jhh „È4EþåÖ[o q»Ýê‹*ÆÔÕÕ=ztذa‡cÑ¢Åçi>õM®ÇçÍp:ùÎàÊ9ïÁ(€!cÌÐ0LÅãÙ¹MTÙ8P"áØ¡Y© 0½†fEbéÔþý5J�ùÆÜ}'EÀÑ£F÷nùUE¾î]€€JNšuÝu™9’ÊÎÝÓ[Gιa�…Ê©íPÄè9Wöa©ûàº�µ’ÒÕiJÁG7m:-‚u䜹ÃÂÕ0g„™È1s®èÃR÷Áõ;k P Î&»H)bY”†¡ÆŒ;Þ_»é»wnÉ`!L]6»D(0ØÆŒ;Þ_·õ‡w榙§P"Š"A «=Îìk÷éW\m–ïØë4ª¯’Š­kñ8eâ%™†�ŠÏÛ´­‚ Ãà+¯ Uˆ(4kÖ¥}X*•mÛ^Ô¹þÄÙl—( –a§óÞÏ›¾}ûV/íŽlØpJóðÙ¢�Á@£¯Õ,c‡¾†±Mi{öú­uDÃ"Ú˜8uØ�”‚xüÓÇŸ]þSn…`�Ž¥Íe'vþøþãwÝûòöªN·- N›“ÍAP ™ÌF@ív§^N—.‡–o¿ý®¨¨hÔ¨QÇŽs8DI’ä_,Ë3Ï<íñx$IR‰‹Œ1N§óÈ‘#ýû÷?zìè÷ßÿp>æÓlwoÿâ›5=÷×ÁÈuêÇýëë’NÖi#"¡€ Z?±,FDÒíèÒűêêêÏ>ÿlΜ늊Š<�Ö³J£\0™LO<ñÄóÏ?_SSòlwñx<Ç�X¹r娱ÄÄÄtí|š<À&:Ò2täÓÖμ}‡=GÁ™·ïˆÆÃÈövÓ áý�›³e绦�·€'?û�“â�¬ÑƒZ·Ç+¹&ˆ±Äv‹ä8S „HD¬­¬%"�\õÄMk±R�E> �Ô][ÝL@¶Ç¨OG6³TÔˆpzõ“7ý‚•ê.ÞRÈbS#p×U7dÂ\Æ �Üzláò¼ß½þÈ÷oXÓfe =æ‚ÑýâLXU¨¬|ز¼ß/z䇷BÓff=æ‚Ñ’Í�qǽbWqä´ ã6þptÆâ¿ÜœÆˆë7�’¸~Ó&w²’êjêÓâ]&:: C©¯k Ù jʪ³V§ã›µÏZUW]Gàôê§nZxq±©‘ú?‚v?>­L¼ð‰NþËëë® ÀLõ}lI¾à®ç™¦;žü¡êð×?½jþ€N|0Ç1D‘†‡Ä# ÀôØc]º˜µ,YºtԨѵµµ6›MR$€µ¨&Ž… ÆÇÇËÑbb³Ùª««Óûö}wÉ’®g-×j)QhÖèþ,"M² EÏ‘yn0ôžåu³¢ð!Ãú°Ô‘·ÿ0 fç6d2j°98¨øJz!˜50’›"‰n—[¤„ÉÃ{x�ç^x^àyÞã¡æØ¤ÄÄÄ0NRIÕ�3*ò @Qôž%ð¼(ˆ¢ÀSs\²÷\ Èš9÷Õåï-¸uæÈ^Q¬«âØž?ykÁ½7^=ï¥oN8QÊTZ3羺üý'n�9²wã,?ºÛ{Ø]ÿZ}ÜN)b[jÞ8hÚä$F:µñ—ãxoØXJLC¦L žO("€�e[Êr PQ:ÉK½ÓY8�«´Ó¡/¥¯®¡úø: �œ8 Öh2›4¸¢~‡]6!©>z´ªS¼‡†‡"• ‹Ín'8,<ëjS—®c-%%¥'ŽŸ˜uÕUùùùª¥ ¼éx~ôE“ÉôÔSO½øâ‹§OŸfF{ ¥´¼¼<33ó×_w”––%''u©AŒ·XþS05rd_6çpu~~)Épää5¦ï°!ÑX5¨žÂäŸÉ?xZÎå¨!È0à‚¬ ©’Þ .MícJ‰$I¢R6Ÿ"“Å ìÀ¹o-¾"ZÉ…l%‘ÇWLÝlUÎ]43Ú›4‰#ìuä¨E*åᘈŒI×gLº<õ'ÈÞ»kã†Ý' 7¾ñh3·ô3UÅÇDdLº!ëò;¨§þdþ��¿nݸa×ñ ‹m†7ΈÇÚ¹µ¥êÙôiSz}ñáÉMëÝÞ?3wýö*j5u|tP!Ö›Š�·¬¿¿Ölnlj}wï7�,µå|¿©”//ceyu¹:3qùÎy·[ òÈê› ë,ᘾ鑤“Ç‹Ã`HíÑc5˜^}LºÖÔ¥+¡e󦔔”ÚÚZN´ˆ¢ÚǼpIÚ±c †'Ÿ|2--MF­Ô××ÇÄÄlÞ¼¹kç#HtÿžƒVk‡$Sÿ„�s\Í”#“*_Êñ½yevI™FHÓ›˜Š48•Z¶oW¯ÐÙî†hí‰}yå Æñ 'ó~]»û”K)†é…º°A†E�úºB)òÔçýºn÷iûM… š04‚RÚÔàSÝ3ˆ¥ Z¼¸èÒ¡FZ—½uõ¶}Í{áÔæVµá �‰ �Ê9g<<;ÏIÛwP?Yrƒ€664úIêrsNj_ñÔ�Ìûõ—ݧ6)ò¬�†º ,#)ÏÞS,¶ÐÄšGÐÚÐá‰K…+î¾bÒ%W>°º,p-…¢í{Ê%Àñý2b:Ç0Ø~cFÅ`bß·y—Íï+AJ·n<."®×¸1ÝtÒ¢K—AKcc£ !‡Ã¡Â‰(ŠMMM2À@ !dùòå›6mŽãž|òÉ‚ …§Ó‰r:�MMM]2„� o?<ùç7nøâùY¢(¶›˜é­¬…º üX!½Æ �ÁÄvpõ�ù2dXÿäjã€aƒŒà:üÃê|'eRF�ðUïE¾a„1âX–eYˆHDE‰HZó#¥¨ûäK‰túÛÅ_:5õì=g~|é‰'ï¹éî·óy/I¥t±—±©S/ϲ éôwo~UäRÜø!þìO¯,xêÞ¹÷¼{D ”’†­¯?öì?žý³ã.ª‰=¦î“ûóë(b’R€RÒ°M>ì“£þÏ©œ#µAÝ{u7b€Ãq,"¢ØŽ E�Ÿ>:ªÖ½£%Nž:°õ�“>}F¦‰Åß¿¿¾B£á=E߬ü¥šàÐQ3/ö㸤I �¦ý[óê}Š•›Þüô0a|ŸÒ°íõGŸQf0�Š˜äî²zÅ©S/˲ éô·o¬*ÔºøAg>Äž8ÓcäÐ(‰ G>}ý“£o–P½óÝ×V�–�±ïÌý:›¶frŬ>mÞþΛ›Ë•{§ÎŸ.úü�ÂÇüeFwYtéØ>¥#�>s&&&VÆUÁÀUW]õÕW_™L&o‡(�™C’¤+VÀ¤I“X–}ôÑG_z饃jõ£Ãá ;}úÌàÁƒÎ}&™™™kÖ¬q*½¤B™™™í}“»|=¹ŒQÃ#¿]S~¢�iü°�Öd<"ƒÝ‘{âN>:•ÑÁ�¯M (N ÙAE¨¦1¤ÌPpüô‡çï�ÿúî¼eÞœsñäá=£9¾¦8gë–œ7›2ãž(N¼¤–ÐÇ Óž¿÷Þ×vç-{`nÎÄIÃ{Fs|mqΖ-9%n¶û¥wß�i 8aúíW¬yøëc>x{ö¸qÃ{LJq’«¾ôðέ{ÎJ\Ê•�‡ nêm3üû×G?xàÖÃS¦ŒHKãHcEQþέ{ΊlÊå³'ÄrFÆ@‰Èób»$…�šzaäöŸêÜLïISûrÀ‹­nŽ’gþý¶=÷-Éýõµ{çåLŸ8 Ñ*ÖؼvïY'wñ}wOQjÕãÔ‹¦¦^t´êÇçîo˜:®ŒÁYuô×͹ƙ7OÝðþ�uTnáŒã§ÝvÅOòtö�'OÇU_"O‡K¹òÆIÞ˜/yç¿¶ûà²nÎ™ØÆ#è8¶N¼U1ô»á�ë,ø¤àà{÷ß´~èðAÝÃ9g͉Üì#UnÊÄŒ›ÿè5J±KZ·îéûWñ.!u5ŠpúëÇg¯õ~ü¸÷­xø0=¯}hîž¿/ÏÛô¯¹G׌Îê.ÕÏÞw¬Vdâ'>4ÿâh=_—.„–ÚšZ‹Åâr¹d>ˆ¢øÐC 4(++ëÕW_­¯¯—㌵ÐB)]¶l™(ŠÓ¦Mã8îñÇùå—³³³Utq»ÝÇÖÕÕuÉL&L˜0nÜ8—»¾–óñ51=ýôÓ³gÏž9s&B袋.JOO×¢!$++ëÑG5™Lpâĉçž{Îf³µ0Ît­rF�Éß]É*Z÷Ü1‡R’‹~Éù?ÈgÑB¿ß¼Ý ‘ÖÊ®Í(FŠÁMNB¢TŽHóv'FHòÞ’lÚÿúø¾°åÖ@³½¢úºè¢ËŸZÔcäÊùŸ|òInnîý÷ßÙ­[7-Mš4éÞ{ï•+ïÝ»÷ÕW_ ØÉž�V]^ƒÏy©nÜ6ÔœóM Bˆ·æõ±ÐsÄ0r‹bŸa͇> ⃠B)PÕãO(U8e0F©A¾Ì¤ÞZ°û“Ë3íÕ×E]þw¤£~9Ù Tòòò|ðÁÜÜ\ß ß|óÍ÷ß¿Œ+?ÿüó?ÿùÿì]w|Uö?÷Îké½BM $TA‘* èÚ•]*.6쿵,V]t-+ (®©J‘’@HBHHïíåõ¹÷÷ÇôW’ÊŠìœOÖ%/wfî�ys¾÷´ïyýÜ<$¿£Ðn¬¡�o�¥åÞÜY@€Â3 ƒ0æÂ-¼µàé.“ØË+#À»¤b }\ijJ áò𠔢R_{ ”RB ¥cŒ±˜¸Œù¾–.ÂhtZLìV³Ùb¶XíkuZ5¬Š**´V‹¼4ÒIZZZ/^üÙgŸqf Ã07Þx#§Œ>ÿüó�>úÈm�œS¾ò…G… bc �× ç\m‰ÝèùæÂ„ÎhÄs‰=ôââT¨ÁáPÎ!ÃOCfé‰4û²I"¡¥˜¸z‘Ú‡rPçö^!†aqØ»!ÕWEUþ§­§êH‘L°nݺÂÂBùQùùùëÖ­ëAã]L»C<ý9\u\”O¦]×g pÊšBO¶OŸïå(¥Š{áÉ0d4/2 >RA¸V "]¿{lA¸GR}UTQåZœ°ÄUBBB¢¢¢äŸ¤¥¥½ùæ›Ýœö".Î+õ{>§–Ç�Ì$ð õ$ Âæ^™XT¼<ê‚D„ëò‚<�Šh|p$Z!Â焊ܣâùÎÇC u‡^nú'ÕWEUþÇ ¥ûññño½õ‡"„�ÿüç?‹’““ß}÷Ý &ü÷×vau÷̧OÉÇQ¯R¸¨ò´œýÁ×F"¹ʳ%Â!¡vx6Û( @b¬E$¬–�‰ùÆ2cHöoŒ1ÆXâ±ä»FaÌAw¬W~ÈžHõUQE•ÿ-hé]’““ßxã�ÈÈHîW»ÝþÝwß-Z´èÌ™3àïïÿì³Ï.Z´ˆËBöòœç�(æäÈýí`]˜ž»Á"äô‹€”� äÆ>r/^ZI(€ƒeY–PM™<qINˆ"Ï™TÞ·Åç†aÉ\¡€òî^P5YUThéÆ�ÿ�ü#00Ðéóêêê§žzjóæÍܯ“'O~ë­·½·„ÎÕÎ�Â_sDµÞ“a„ÜfBËŽä:wcÎñv*Ù€íͬ‘ÜÄÛC)!”%„òIbTôÑÉ=¥Næ%”J‘ô™»ÇI]Ü_..2ŸžD}KUQå'^Õµ`ÏQ×Ù³gÏŸ?ŸS{÷î�ŽŽ–NÚíö+VDDDŒ= pöìY¹æá”/$²ün› ¢¸m™‚¯Ï)!â_E+Õ²\+J ¿#χ(røYLû”ät¹²ä4_y!¾ü¬.÷žB5c,<ŒDY¹½×#‰‹Š.ª¨ryZ-ƒ�ÍfÓjµN~§{ï½÷þûïçtåºuë–.]j·;·Õ¾çž{8\!„,_¾\Þ …a–uøø\¤®�èbùôQfRâœÈe�.^ôZJ>ë‰Y ?r T¹¹•Bå _ÎBÁCÒë` Öhµ½"ÕWEUþ¬–ðˆp«Õ*~¢Õj{ì±I“&q˜±jÕ*Ññ2ÄùóçÏž=›óÎ;ïìÞ½ÛÉr8Øððð‹m]¸ñÔPa‹á”=o¢È]GTìs^/©‰£ˆA,ÚÔsóFÙ0åMA‚i¢ÈæHøhŒ‹)÷QF¤"÷yÄn³�N«7h¼&ÕWEUþ %©OŸöö¶~ýú‰Ÿ§¥¥€Íf[ºtéÁƒ]UØ‚ ®¹æp8o½õ–ë½^ße4öé“xñ–çV× d0BÈÁ³-�ÀÉ•äùB ¦êÊšÐóF!—\Ldl+ÔSÆ[¥ëâù«EÛˆv 0Tº(¢Š¨�Xˆn}’KL*ÄŸÜΕµ[Y{/IõUQE•?²xå öõõ???�F£ÑhZ[[—,YÒØØ¸xñ⬬,� ¢æzä‘GD\áÚ´h”âããC º�Ò³…!hàq¹êU× IÚ\G|@\TÏT‘ÐûY»=�ÀK ¼; áA€*JX¨,[ Éñb �èó«ñA  ¡2@¥z’îP^ÅUTQ­'™rõ”¼üü°°°††î“ŠŠŠÇ{Ìápˆˆ"ºDôzýÔ©S9›æí·ß>vì˜| 'F£qê´©eYuË‹z´�…¯È×¢ 09"§Ïå'á.F�¢^%tõr½H‰'ÔÙ…Å �&ÊÅ>¨Ì1¨(ŠD®°Gåæ‘dÏHðt+TUQE•ËÐj€)S¦TUUFEEiµZ¹�âd‹È±Z­K—.-((иˆV« lnjšrõ”‹a¯ oÂÙä¼6ÑHЧbb•hÐ w…ù¨;—ÑùÁŠÌ’ªôÝXi ä;¸Èσ9rLÔíÅ(õÄn¦‹*ª¨Ò;«%!!~ذa���ÑÑÑ���=‹eÙ²eEEE®ö g²´¶¶¦§§ÇÅÅ^xEK{ò,QûÃÝä¢4)¸·eœLמ1î- ·bëlê°PÆ7$Ä«�Hi~¹_”ÍØÔi!ŒoH°ŸFš®|ŽÒr)xlf)+”:çÁqèªz¼þÅÖÑÔaE† 0�º"Uz -°àÁxàÁ‰“&Y,K·}‚ÍfóòåËËÊÊœò•9Ñjµ~~~¥%%¯¾òòEò‰©BãƒÌåÓMˆ‡s‚Lu*ø¾,�åg›­  Iìi@r6~î cmIuÑÇ÷‹òs½5Õ�®js€!"))Tg;ôÎ-‹wÛcoù資x‹-¢KN¼¶Ìp³yï¶—všcoYñÙîœ|*›r7HìÔåœêEÝÞ g<§ç˜RÌߪÕÇÇ„y~›©¹¾ìl›ùFõKÖþÑ_>aá>}Ïoᤳ¶¬ºƒÂú$…ë=�ÇÞVQPpêlS§ùG%¥ë‡�®Twº²ÍS Ÿ>,))ÜàtáŠïŸ¿úô ¿|ï–8taVDLuEy'O×·™Á™˜:4%!@ÓÝŠ;íŒoHTRê°A1¾—âŠzžgïŸ&µ4çå—T·™‘OXÜÀÄ]JHØ h‰ˆˆ¸çž{Ö­_—ž>êìÙ³\3cgÿÆ]]]ï½÷^EE…[{cZXxò¾ûî »àë)++mljŠï߀W8<¡ÞwÖ¤(©áŸX…1âz0SGîê'_ÙgÖ¥?úÍ[s‘¢éR¶nñýŸ–:4)}úÞ�ñÎß'RûÓâ‡Vä³�3^ùú¥ k0& ö&l�dÏR›/§… ®:¤„" Èm…ŸHN}Ü#ÌõZùŸ>ñÂOÄÇ7tü3Ÿÿsf¨‡ó�Šþ~ßêíÐ_½{sì�>YX8 ŸóZ¸­vßgo½õ]^³¼û£Oîêç¦Ù\¾måò¶œh¶I»"lˆsÓÃOýel´¨íÇ>~üÅŸ�î5Óçö•ŸÌOQœ�4ædŸa™øô‘ÑÀ~Þ+b›Ž|ùî²oU™%ºl¤�uÃ#ÏÝ;>F«XÑÖ•Ë?tZ‘OÌø[}r^f$sɬÈËyöêi‚åôÖ÷—ü{{q+¾òÚ°a7-zvÁ„hÍZ`ΜÙŧN•––0 ¶¶Öµ@Òn·ðÁ•••nqE£Ñ•••�™ÎÕ»\@)//¯©©±³¶ÌŒÌãy¹G‰ŒŠLJJrõþôÂø‘ ÉiÏ.æ;!@~c‡è˲fåtÍž€ƒ‰% G�V°”-;œÝr{|¸Óžª57ç”�ÏðñizÐM|~ûÎç{µõÓ™{PûNAäb„]tãó@Ï|þ|„X²·í©™2'Ôa“ÿ…¯Æw”lÛyš…‹˜ ñûˆ°ðúé7D»ËîN»J·¾÷æ¿7—™»vR»é•'ÿy¨]•1oÞÜñ#|ØöÊüÝß|µõЗ´õåUOŽ âwtmpHò˜¡1.ÆŽèàœšhÌ=ZlG¡é£’˜ó_í8ôÞÓÛxÖ†ƒO›5uDBí(Ïݹñ×ң߾¼È¼äãÇ2ü¹ °U?.~ré‘6ðIœpãôqÂ}ì-¥Gwüô[ùok^¬2½¹ê¡á|%öï»"ïçéýÓR·íõÇßÚß~®ºnffR´–øyãÁ¼o^~ζä½E™è-ðĢǿüʉ'† ÖÒÒb2™äýòË/M&“[\Ñëõ~~~ÅÅÅ111‹삯¤¡¡!##£ª¶²¥­)!1!,$âèÑ£"´¸1IzÒ†Ô³~å°JHýBÁécR´Gs-‡Ž[g\a�#mÏÉ:倀 À®ŽÂ¬\ãœi�ŠËšŽ=i£H?lì(ä5ŽHâêEkÃcÖ[OöBžVÀr·53çkÁñ}ÚÎlÛU3÷Îx�ÍfsÞÌ�ܹ³’ÅÇÓêJÓå-8¾o\홂mÛ+çþ¥�½åyá¤zû?žX¶»šF]1ÿé!Ç–|”åÞ%iÍýö“#mT?ô�·^»=�7¥¦�í‹îú¿Í5Û×l¸y4wib4)€fð­/,žá K†õDV� ù�ÈLÑžÿŠìEß¼ûS¥EN{þ�'GñšýÚ¹× þÛæTýüÕÏ·¥ß�hûÞOWm£¾Ã¼óƼ�‚CköÜé_<ý×Õ'+6|¹ãæasÃ÷õbžÞ?Mj<üñªÍà7êÁwÞº¥/ç/›qÍuW~üÄc_—nøpí¬•÷¥\Îâ^û†yååÅãÆ�=xð€Á`ˆ‹‹óõõS¿l6›k>˜��ODD„F£ÉÍÍ™4i⫯¼|ÁyÃøl³…‡F†‡F†…Dt×/™zפ‘zRÑΚEfŽíË5;zÒI#šŽÍ·¡ð‰³&#K~öq§•µàÈq3EšÔ±éAB`æTqqñ™F‹Öé¬)...®jg¬õ¿lþqý/E­bA=¥ÄT_tø×Í×ÿã–‡Šêͽy3ìÚõ[¶,ªsw, ¶–²ãwlݼaÓÏ[÷9YÓźE çaF¶ßÄÐŒÌþöô¶í§(ÃèõN.fKÎö=u�>¼/ñðÔígsÛ±aÝ߮߼u^E»³IM:jŠ‹‹‹*š­.žíêSÅEÅMÊ?x¿ñ6~÷ã–‡ÜßFoîpçúð¼p¶æD^kôÕOükÅë·§…bÏ6KQQ+¦ÿø‰qò=ò1aT ¦ŽòÂá{i2š( �Ÿ¿w{N{ÑÑcFª’ž¦?ÿ±e¿¬f©6õÆ®Œ’)mŸk¯ýÔ‰Rî™Zóí 8tò�7”J çÎÉÐ!j/9YÆ^+êÍ<½}š´}ÿæ½-„‰»vÁ }¥9"ßawüùª ä8»}Sží�ç­Ã»ïºkøðáË–- 8p ���Éd²Ùl\J.¦Â0ŒN§Óét&“©¨¨Èd2=û̳#F ¿x‹±Ùl˜a¸˜Næ”{ï í1t Ø¤Ëm1—¢8f̘„UÅå-ÙÙ¥lzªôZXó�ä™@—>bÖˆÖu[;\h›˜.ÅÚ§²³Û 0Éã2ù­‹=çã‡ø0þ©ìÇ?}ø¥_ìi¯yÀ¸äéÏO˜(Žº>iRJ@[s¿}çí/öŸ5 lÏaß„+ÿòäS· êÞ "mÇÖ¾óÖöW˜Ä×aß„«œŽ¥]EþõÆê_K;YY’˜.zä ‹ž¾÷ ѯK»Š~ü׫­auÜ0«ÕêfX·ŠsÕÀ�§ŠvmÏ»+%]‡õz½ÍfãM&cÖÖßZ!pÊUCÙÛ]|ͯŸ¼ý¯ólò9†�˜»ð¹ù“âuÂ|°àÍCdÀÝ«Wü¹¿üÕ5zï‘7ö±}ïY±b~¦«öþ6ö°ð‰²…+ÿØÝ™˜IO¬\0&Émïn;ˆ@­óc@:­føÛALÆ.ÈÏß׫='{:ûX#Õ 5\é‚9·1ç-_{MKŽŒqºº&(Ä�Ñaµp˜­÷äîë´û8Ǹ‘!(Ø€ÀFÄÆ¦¿ëŠz1O¯Ÿ¦5?;ßDqÔ豃œL¿ãÓtÛ÷¶f=ÍŽJaþˆÐÂÉÈ#>_³fç®]_üç ›ÝŸâçç§Óé(¥V«Õd2ÕÔÔTWWô†yž7åê«ÿ Í9`óm NùÁîãÖÎÈBÝ%H‰éXQ Lß1±_”WÖe©¼/5 ‹Ø#9íD“:bXä°æ¾ÌÁ’죧Ùtñ©³gŽæ4Ðô3&{2��V«E`³œ]¿rû逡S®îä—‚(Юc+Ÿ}rm©Í§ß´ûn¿&=1�´–ýù?ßîûeÅÿ5²Ëß½c€ç䒮ܕÏ<µ¶ÌæÛoÚüÛ®™HÝKÛö¾óÌ{¿´è'Þqý”¡ñÁ:‡±îÔþM?nÍ]ûÒKú?¸+E+ {ÿ—}âŒ;nç†5Wä» ëáÑAô„«®),Úûsöýéã|0Æz½ÞjµжÛt@ÈÌÉ>;œ0mÙ³ìÉ¿oo¤þ®»çÖ)iqAÐY™·ë«¯vä~¿d‘Q»êéqÁ½ûÞy¹jïocﮘI7 ?j¬7fQô�ÔH\Tw&¿ ó†hÜ‘úâSmi$À¯Ñh@¾~~ÞÜ1RŸ“SÍ2‰##ð…Xãíf£^q¦•Žë—ÈÍi aÑn,׊“…F‚´ýöÕ\+êÅ<½}𤶬ÜB�éÛ¿� xøôíÏì-«?}¦“¦£?,´p zÚÔ©Ó¦Nmnn>pà@Nnn~~g.øúú&&&\uå¤ &Èy-/¶œmèž?Ì�Ïvc‹¿{gÝ›¶ïͯ-ddw‚”!™c¾uï‹Û ¾øxû´ÌŽÀ «X1ÔqjíòN[5}nyuù##ù wì}Šc»Žì<ÐB4)ó^^rG"?G:æª)™á _Ûpdé�)ƒ5@»Žì<ÐÂ2Éw.^2?…f:⪩™á _Ûxä@Ù¼”wQ”R;eFÚÇ…9û~>Ð>vJ„�N§Ò´gG¶ E\3c¤¡}»Ó³æ}ýÁŽÂ$ÝöÚ²…i¾ÜZ’SÓÇ ÐßÿìÆªí΄Îí IDAT+¿™›¹ ¹Wßsw«†1®Ëñú6özá‚énáÞ‹vèM÷�ß½dÿoï½þMÐã7dDSõáÏßú¶�Õ&ÌþËuB>k2š)`ÜøÛ×ë~Þ{¬¤¦Å‚}Bc“GNœsóõ Šj¦¶Ü¬21*_ÄQÓ±o¾Ï±�!uÆŒÝ|‹ˆ©b÷ûo|WF´ñ×Ý>3ê’]‘ûyz½wnih"€ÃÃ|]»†G„b(e› 3dh%,,löìÙ<éëÄl±O5pvI·n. TÁò˃…S†-©÷DpI©Ø�‹R º”q#×ok/ÊÊmÿÓ̤6;»’Å#Ó“`ú�Lù¶òÌÑ£�·qÐCÛr�”9GŒÛŸqŠm(J3¤ßqû0èì;vœvPŸ±7ÿyD€lš(hì­sîZqêØöýM×^‰ÝDðí'vì8ãŸq·üy„åþU[ºøPÒÕÞé €´®ÃVJüÙ_G\9}ôÊœ}YÛw7OžŽ)¥6›M×¼ûç<N¸úš!:tÀÙv|מZ‚t#¯¿u¨üeCé7\;pËGÅÕ{ö–ÞŸÜÿ@7«V,ÇëÛØû… ;ÔnÞ«ˆjÔÌç—j?û÷ê-Ÿ-ºc�op°/ílm·jÂ’§Üw÷_o3Hh—ÑD)8о|îeBµþQQaaÚ–ºêâýUEvîœýÜ’§&IQS^ö  1Êp_¨Ù«·¿õêúJÖ�|Ï#s±Öú·Vhµv6V”V´Øü’®¼û�Gïx©­¨‡yzoQ›:M@ïcpÓ|Öà£GÔh4]I”ôÒ—€š�=]gôÆÞròÎñˆ\Ã#„1ƒ±¢ÄĉEè'†´±#ýµžÈÊ5ó[ œìRH5H ºÔÑÃ}Á^|$·ƒJßcŠƒG�ó&ŸC3(=ÍOîË8QØÄR¦Oš‹CÇ K ÁÔQr²Ìî„©ÜHÒp¢°™“Ôã±8tÈàhÙO|ñÚÛr*;Yñúö¾&þÚçþþ—dwÎEÒ^–}øÀ‘œü3ÍmxêèÌ‘Éq� \r+êažÞï{„RÆ]. �#²—€*Ö\fÐb³³çn ò¡Y'�„½|[x.K‹"„|GŽaؽÏtüH�õêÑz0?rÂúÌŒ¡Ü+aHËHÕÿ’•—•ož9ѬùYy&ŠýÓǦyá�GúЩ2inh¦´üûÿ²ÍY};ÚÛ(PKSC�ìÚù±¹¡™@ù=«I¹óé{ _úäxñ†wžÞø¾ì aéécÇ�;8Ò Ý4ÍàyÏÜWôÒÇÇŠ7,zã{þ±ƒ† 2ŒÖ»}™ïè“"wn,ض­ðÚÛ0ŽSÛw�aµƒgLu³g¶¹±™0a‘á.eÂÂB14“–æV !½˜†lÕÂr¤U£s¸�½XøÉ;Nßt—lá©îÞ+uÔ´ç�Ç—loôqçk+ï­ æ³{W¿ùúºÕÏž¬^òáSW#Ó²ms)0:ƒN¼&ö�ÿà«Lûý/l¬/ø~ãÉ?-ªGiÖ±6ª‘9Â]ŒÙë÷þûïK6”˜|’o}ñÕ…c°‡g5ï�®³ÙºÚêJ�ÿöÓæïßùåÇï§=½ü™«c¸„VÔÃ<½ß÷hµ ‡ÃænÏB¬vB4ºK�¨âr³Z¬6;xQ_Á÷F”oè‘�¡TøJ¡òLeê½á€ˆK H›ªA¤=;«Ä`=‘}ܺÁé¼±�‚FŒ¨¡]Ç�Ø%Y¹íéGŒî#3�DÞ{—ýˆN#RCRj·Ù¹Ôc›ÝæüC}"âbccµ¬«¥ܱ@)Ûó±ØoÈÝo²êù{çŒîʘjNÜôÅ{Ï?<ïO¼ñC‘‘ š‘§a¾ñC‘±û§á#ïvJ›15Ž¡¿ì©Ðøøøà²ßvVÈiSÜתÙí�Fãª4Z¨Ãnï¥À«åôæ6z#ÜÂÙ3;·ÙÀZ°£Û…÷b»uüë;ê‰ÿØ_¾‡ÇÀ>‰W=ôü=C4l펕ëùX¤Ñ| 2-,ºG]wU4Òpòd= •9Ùõ„é›>Òsžì9¯ˆvžøâ…G^ø±Ô9qÑ;Kö„+€|¢ûJ‡7®Q}$ïn‚£Ggöc€-Ï;ÑV——ß@˜ØŒô8é3}2G†c¶æx~ccÞñ i“Gg#çrfäW€ àÑDÅE1ØúÚÖGf1ÂDÅE1غéX¡,Æ ²È�r2¦ÝöÐK«ÖüãÆ$ íÌÙ°³JžB‡œ†}ö�ûhhgΆ]U^nÍ‡ÍæHš6}ˆ–6ú-¿#w×Á6wÍxñNîM¶®¶ÎÅ>pÔ×5@Ú¨h.QŽ»³”u°Êe’޶vÒ�+ÒýrÜÝÆó|{±pï…šM]T´áœ/‰1P‹E¬%6‹ÅMY mmi'8 0Pã±ìb; IÕ�¹ +¢¦“«ŸåÛ[ä„Gßó÷¸ÂVïÿöó�þ½rë×Ïú# lggý½WÔËyz÷ O‚�-+*µ¹ø=O6`ú¥ 4¨± .,¡µÕµ:Ù[„zdM”Y œg‹o˜HEò}¾ß—Ë©œK/qBæè8†ÚOËÎË;ÃâБ™Š/ª&yÔð@ì()8–“_b§Ì€±™ÒþI“S¿J×0BÌ0 ƒPhÚð$H͑çJ�ÆÂCǪ;=ø„ðÇf’Žå�"¶±ðÐñj¡ìÜÚRvü·­Ï8q À´«F…" ­-­ØZNçíßv¨ÜâÔ‘SÖÜJ¼ÃŽ•G]yíH=mÎÚýÞ#1iz¦�Ç7-mX,¤.;§ÂiÁ¶¢¬ã&Š4Éiƒ¹7Mëk`жÖ6VzÊÍ)“bmîaÕÜrÜÞFñ-/:,ÝÆ^lI½^xo”QT$À–—V¸Ti›ËËë }dT(`K>{hî”k®ü‡jççe/Ý{¨†58%X ŽØÀwXÆÝ…\mÛÿ¯W×YG-xûÅÙý<*HóÉm_ügí÷k¶�r^m/9UKé""C~ÿy=ÏÞØ¶ƒÇ� ÇÄxä—� P"U»w9�¶ßãb° -V!׎ïwÇŒa7NNáj'Q÷Ô� óqu,BÇx.ˆ"ÆT„(r ¶(ö"ýÆe„cÒyì‡MùVä?bTªò‹ª:*Mæ‚�?ä›(N“)#±å®ÂARL‰&…œ4ýº‘>ÈQ¾îݵ%fÙ"¬›ÞüÛ ýËCäÛ<_—î‹ØòõòcB¶ŠŸþù·ÅcIëžeÏ,~íÕe_™•grN´RÄÄ'Æ`Ò²gÙÓ‹_{¥‡a=ŠÄvŠB'ÎõÛ¿ß׊b§Næ9Ñ�4sÖ=rœÞ°j{­LÃ[K×­ÙÚ@pÀ˜9“ùÚm\Ÿ8HûÑÝÇ¥�¢£n׿¾, Œ,ùλU{º�Þ<O_Hïîý+9~â`" ;>ÿ¡T—´ëä·ß2S8fÒH`úŒÊRû‰/—}qR!³7ìÿ÷Òµå,Ò'Ï™5X`/¹ðÈÂ¥�­zü®œ«§ŽJ ÓÚÏäîþ5§Ò¢I˜õ×yC=¾�8zæ“ /\zðØÇ�ß•sõÔŒ¾a[SydË�ÅQ3î›ûÓSߟ\ýø½G®¸"s@t –˜[*ó÷ï>tÖ¡M¸~Þ” Ñâ°{ ¦O熵Ֆ:ë�Š 3}RÈÞŸš-Lÿ)Ó“µ`sx\Küœ§î;ôÈG¹¿-}xAÎÌ«‡Æú9ZNgÿòóá³&&rò#M" 8éÊ郾.=Y¿é•ÇZ§_‘®3ÕŸüí—\ýœ»¦ïXµ©™o8ãíªÝÞF­­ñtŽ7�ÀÛ…wóÝmÞö÷Ç>;áÜ^m(ÿþ¹[~æ¿TÚÌG>{r¼püœGî?øô¹Ç>|tþá+¯Ìèá¦ÆÒ£;wçÕÙp伒KŸÖ ¾óñ;²ŸÿâÔ±•�ýeûÈŒ´Ä ­©±87ëD½…2áW,|ææ>€-Ë>ÖD˜Ôô‘^ ¼^íØ³~{0å­|øÎ•îNå;ñÉÕ Gi'ýiÑYO�SòýówïK1¼_„�kOåæžn³1aÁÂÉÁ¿ÿŠz1OïŸ&Ó÷Ö'î>ôÔ'Çw½q÷ÉÍcÓû±�EYG ›LÔÕO,œvit{½| %)))>>ÞìÒ£Œºú¯¼` wó‰wè¢:6Ãÿçmi“3Fº°ã°ôQILn‰pDæØA¥mÂWÉt×@˜#˜A4ñ×¾´"ìÛ?]¿/gËš£” ÌøD¤^{ï}Þ0<´»©jâg½´"ìÛW¯ß—³eM6‡g|"†\{ϽұÈ/}ÁÛKÃW­X·÷Ä/ëòwñsÀ>‘ÃgÝýÀ}×§qDKÒ°=â0«Õæ<¬Wâ3òš«"·¬kN�6¥Öî†êúßüÚ¿Ã×¼ÿé–û¾)ÜÉÍQ–<í®ùóo%KJƉ7?ÿlÃël8qfïº3{aCôØÛ—üí6÷{P›�Ë$órÕno#70bȵ÷ÞÛÓ#ðjáÝA knih¨S&¡Ú�ÍbY—¾M°ºtýn{ýƒ¤ï>ýôǽ9Û¾9ʧ°`ßÈ!×ýéžûo!Þ#ä7üÁeïôYóÉ[sʳv�É⢆ͼùî{oÆ©ËÉ­f™¸ô‘Þ•’{¹"j3™Y Ööºz÷_~¿v�$N×ÿ¶|�¸võ§+*:´­P|DCgÜp÷üGF0—ÀŠz3Ï^.RÑ]YœØiW7 éü�‡�«øøøˆùcÝ?c]eU“ц ¡1 ±!/15Vžmè´kcûćºy»]µ»ÛÈ=î6^’bשׂ®n1Ú‘> 46>ª»5UW6´[©. ,6.ZÎL;*Nœi!A}‡&ÿîzŒÚ;ê«k.ýy?ÏÞœÔÒZ}¶¶ÍŠý"â¢ý;aêÔ©~~~®Eè—3´È4¾+ÖPŒ0¡ò„_ 2�êŠ.|~‘SûʧlIµü½Ó)îZ8:c Uþ?rÁ$)K 9÷ÑôúKJegGÞuŽqgáù å)Ý55¸XТŠ*ª\*Т¹ü–Š„4/Á4q[ë„~ç�GX‰¤NÀ’A#9À}U¾’‘ õìk“O�ºÓ× BL�ÙLºFX⤒’ù¾dñ´›Ý`ƒ[ÛˆRÄÃ’÷wYv*)7©oš*ª¨ò߆–ÚÚÚŠŠ³Fc§ëŸŒÆ®.SW¿¾ýÒÒ†‰…Ùçj&‚Xßè..ΕÏ#„�Ð,�J;uW¥,Y6TÖÁåA ’ #,g ÌËBBg³’»’ï§Ìáa�©ÖÈó§"Šz�.r0ïqµ;E}'UQE…–ÞIEÅÙ_~ý¥ªªÚ-ê466Μ1£oߤóÔ/TÖ¹ËE›¥HR¤^„æ©ü`÷ \®õ-=0œMqz^CS Tn�ˆ•”k#óŠñ-g8sÇ:zêdFýÞ„©n_*Þ¨¢Š -Ý‰ÑØYUU]YYáïï¯Ó*’ö*+Ï–””IMumŠ~NðâÞCÞBzãÀâÆ"'Ðð|‚n>­—Úw)à�Dë!$È�åA¡ûò{nR �œ‘@fž�K¼HUTQå÷„Nüýýû÷í"1œPÍÍM§OŸ¾ ×¡Ò ž%ć2øÊHçL_…b£ ÝØ5bÑn¡ì¦,Ýw›…<ÒHgG‡s2[C~ „±ÀC)Í�ìÈ < %®ˆæŽ|V þ1§Å!9¥ÌyáU­UTQå÷„@€£Õéý‚ü|ý9}ëç€Ð…ƒƒ*PåS™Il.éıè 0ÞìÌ©»!Tçæ�Jæ£ïn!ˆÓù3@ Àˆ!BÈ�‹?µ2f£œ*uÆ!Å'èºÝª¨¢Š*Zìv»Édr*k`Y–eÙæ–‡ÝŽ0F´„„„s||ýºp›^ç3qìÆ@]Œ9²——÷œ„,j|A¹E%ó… IÒ„c‘ÕâP„±ÐÆ «?€"9¹[Æ4z^�@•ëD*®¨¢Š*ÿEhijjÊÏÏ?s¦\þ¡±ËØe쪫¯ojn ôGc„1ÇåëYêêêzui±dRÔz²xxOJ‘Ê}Dè|;HÞñœmE¥‹tßÝRˆÛˬ ŽbŸÊS�=ë~Á³ÅC ívQwù`½ ›HLjɤ*ª¨r± åСÃ�ØØÔÔÔÔäïï€â‘Keä®§ŠŽŽ>h‘ ùÆõ”P)A=l¶¹0»�–Õ½fíž FL"æ l\«a¨«�'Ç¥„Q±æÆ©€’*`Lö [˜A·u&â…é…r†Éfãë«B‹*ª¨rÑb-½OHôàÀðîד¹ËÔeí¬³ëÂcŒäV ºpA`¡zEä ˆ¢žB½P¹ RòÁêVjéjp�d$fT‘k&iþŸÜ"ŒâºÂbÅ%À8¹Ò(UYª¨¢ÊZt~á C¢Œå'”PRWv¸ºx‹9hÁHæÃ¹€È‚øòz„!”ÿ„"ðXl. };ëe�›u>›Y„™í u„Æ”Tf»HIbŠÃäÅ‘‚ka$$(+L.%¤!å9(HÉ’Û­¡$ðÂlswïÎÃ(QßCUTQ¡Å[ÁŒŽÑºLc—‰ûÄhq8éBñf‹¬Éâ…žñ ødc�+…ïååî* £\¡Ò–_JqV–Êx.¹`¥Tª™—IR!GMÁ•"N† >:>‚�dÜ5rø“ …ÿæYÑxDAnŠgèEÆ‹^H�Î.{TQE……BÛ::+køö öæ6»ÝHƒƒ1#wˆ]Àô0±ÂB‘ÅÂ碄<Ù+ŠØ‰kÔDB$ M@bn$N¶o!IËKdÃâ¢à£qâñÞj’<â<¥Ozȹ€†‚›#µ„EUT¹àÐbµZkkkkk\v‡Ýf³U”—×74ˆjÔî`ÍVž»…Ú„®Í»7bç .惄.’¢¦”ºÙ™#™zwk )Ù~]LùYDúa©#2Æ"#ŸÁå 0ò"ã¤tMêªè©›e(±ÆƒéåÝ=ts9$3£Àó-SEUThé½#??ßo¿É?ìê2µ··�]»]ã,ÓTX¦ê8dAB´‰ž¥ 0¢–gH ®±pê&e ¸~J� *�¯%g¨”@‚ºÀ–`–¶’éq9E½¢ìÑ…øË  äB»½A=˜}îáG€=ä¦{§ 0ª¨¢ÊyB‹Íf«©©Í;žg7ø…Æ`ê²¶µY6»AC}dzÇ)–Ç!CLk8O¡Ð£+HÜo÷@N‰Dž—¹QŹ�Ó0eH�‡ "ßùSgmÍÁ‰[[ÁéòÈ¥%˜sÿ2E„¿× Ÿ§1êÉäA€¨¼ ŽÛ®eª¨¢Š -ç#Á‘ý"úŒÀ=8v›ÍÖÙRÕQ[D&Ï*›ãs?v=fpš�W�Jl@N^1�èÅ�]àDD&ssñ§°u6uX@ãâ‡�ðÉÇqÆ„Æ\<€lz!.#Zš†ÄWÉ_ B8�šgZ– —àm,¹QFEÌs©¤é®y³°ê–VÀ ¸l�MÊø†ûjÔ÷IUT¹ Ðâž81z‡ƒå4‘Á7ØÖYoj3I:ŒRlá-<ŒO…ä_ÎÙ„ä�MÝ-sU Ú“Ê ,ÂiOcmiMð�ì¬UOrŠÛvä½;^ÚeнeÅg¦2\¾—�—åR\‚då÷œ¥&¯µ¡²BM1Ñ€åÓ�)Or&QíƒØúR:\™F¥ÿJ�A­-å…ÅåÕ m�6Âèü㓦 ˆtÓ Þcá UPqÚ¿wÇßw™cnùh̓CTlQEU.´pbì27¶´Ûí°´µ˜ÌV…“D,Ôà©!9s…ó‰]È‹ÕTut}fÚ¬ß ¾ñn4£»(¸ŒðDZ·�øbÑ£k+)Â�“_þâù«„™"ÁRàA“ò("ìåiü…xŒ!2‚0F,K”†‚LuóÍ•å%/Ôµ:“t5T7Óà˜¨­' .,b:½sõGŸoÊ®í" _ÂúÈ¡3ç?zÿ5ý}äÜjn2åºO8S�aª¨¢Š—Ðb·Ûív;K§ßĸ{WW—Ýn‡™,Ö†æV‹Å´«�Xm¹’ "ƈbŠ¢Àó•Šì§‚¢FUd?•<é9IWŠ"yÃxc‰#¦ˆw|¥DЧ¦¬ŸvUƒÎßwuÜ´»éªÙ˜ŠIÅR!®>)ÉöÅ ½'.½[Y/~8_û‚øh�ØñÞÉìNÆ–­ýÛ}_û-ü|ù­ÑØi€”#@�"j)ú≧>Ï1#®›2fXRt€9ŒÍ•%Ù¿î8Tš·áõEï¾q[_­“¼wA:=_UTQE…–î¤ìôé¢Â¢¦¦Æ.“ #ìïï§Õé ËØUZVªÐ)”zÎYuÞI#„,èB•ç›�Z:Ïô�ðŸ“;¯ïlÊòËPÆØAž8¦ÌØBNz’¶ìÛ´¯•ê3î¾ÇçóËݲ³òÚÛû`s‡+bTvF²¬-11±…=È‹jFÔÍ­ã\a.,ý@;ŠŠª$£­¶î§_tA਼vSƒìO3æÎ»íàÒ'^ÞXy|õGÛ'¿~möx:Š<äŽÑ f·¨Õ‘ª¨ò?-E…Eë\_XXÔÔÔÄ0LTT”¿ŸŸÕCxë„…î‘)F*Å„1!ŒþVKuᲘÔyŒ686õÞš“Ë^ñ…¼…$èæKé‘sÆ–B)’ê�[²Ìà;öª3J¿Ü¿µdÛÏÅ7?4X#mÌ)PÄG)¡”Rêh?“—{òl‹…ñ�è;,#5ÆSžñø@±g ò‹Ï6v˜A™0xÈà>AZYeÛkJë:ˆ>¼oŸ0½¼©01V—VwRCxRŸp=5Ö•U¶œ8TÌRji8}ª¨ëBûFܤ#kan¡�âÀI7ÍVà 0ácÿú଒/ª¢¢h« ¢ Š¿:ÚÏæçŸmè°€!(2aðÐÁ}‚´Èm ¶ó‡Ä\_’_x¦¦Ådg|‚£’†¤%Çúº®FúøøÐΚS5�à= >ÈQW°?»´Ý'åªÉ)!jå¦*ªü¡…“ðè~Izn˜rø IDATß ÀÀ½N›¹£ùlgÓY)jM%¬°—Pp1f–ó#pWÀØ;±šª:ë÷'Žx±³eSHìµ9oXMUzß±õ/߬D2É?&`8+ÃQºùçB ò›2mBˆŸfÚøà훫·nɽ{p¦(åàPŠÏ`°–o^üò‡»ª,B@�ƒf?·xáUÑŒ´t{õ¯Ÿ,}ïǼF;BP]øˆ¹ Ÿ›?)AGÂÔtðƒodܽzżþXvSÌß{ä�}lß{V¬˜ßŸä}öô3Û: P ¥ß<¿ðkÀ ·¾ûÅ‚T�ÓÁò”/È�a�ü'<ºj‚‹1b«ùõ“·ÿõc^ƒM–4'L8^ç–µ" íù_þãõ5û+»ˆ,¦ã›0ù¾çž»!ÙWXjÏÿjé²GÚ�úðK¿ØÓ^ó€qÉÓkN˜(Žº!iRJˆš8 Š*\h ‹NŠ0Á/4Žaμ°[àԾΦ³2!@¡‚þæ»::•iÈ=b<�#œ»_ÌÒQ\SønËÙ i ¨£‘6[°…[Ɔ%^�ò¨!0ÄŠw)×a,´E¡H8–ã[¶V8pðøkÆ €ôé“c¶|W³{Ëþù£¦ºTŽ€ãÔç/ÿX4eÁ¼1B4‡×½9¿xã«/G&¼{†ËYkÙ½ô‰¿oo¢þfÝsëÔ´øÚ^™·ë«¯vä~¿ä £vÕ3ãƒ(áoB²˜ 0¬˜~³>“”õÕª�gQÜ”{oÍbüúÇzÌãÖ÷Ïì;ݱçëïæ¹cˆ?rï¹B 5¬¤-{–=ù÷í�ÔÀu÷Ü:%-.:Å /2j?~z\�h"9�ŽÔ¬õ…�´hcÇüùö™é‰!:ksé¡?ß�¿ëƒ5+_œŒä#³»z‰´Z-›åìú•ÛO ›ruß ¿ä¬¾¿ª¨òG†­Þ×/8\çÚiì²Ùl`7‹�ÊJ„V°ZX1ñŠJ ÂJN3.t F¿1!Þ[Ÿ˜ÃÚzöØ mµÛBb† šøŠVa7g1ú0j/ M˜>¤±|ýÉ_fGÏH¹„Ñ#©0€è““V’Žƒ?ín¤LôäkÒ}èR§MOZÿé™Ã›ö4Mž‰)gÿH&[{ìDÚ+ÿys’Œ;qˆï�}[vêûµY×ÿßX°æ}ýï�MT“të’e Ó|1 Jiòàô±}xvcåö•ßÌÍ|0YÃâKÔ™Œ•6õÚhã¶Õ;+!dÈÕ×ÌŽö e9dú]?oÒ¦×v7ÿô¯wí¿rÚ”‰£ÓG¦ö sI9wÖ¼¯?ØÑ@˜¤Û^[¶0�7’SÓÇ ÐßÿìÆêí+¿™›¹ YãÖÜdOmþ0}o_¼øþ�|^ÀˆÌщö{ŸÜÔ¸ûǽM˜�å#ûõ8°† U¿îŠ»~ù'ó‡ù©Ž0UT¹¤¥?«ÕÚÐØt¶ªælUMMm}§±K0M(P”~¯¡å­êà€pqÄ·ÃBS•sÑÇ7�6·f' ›™léØcjÝÀ:ÚX[‹ÃZmißb·ä„Ä�M~›©íèñÍ™VÓYÑdá½`2\\¤á× �”é3cÆ=7–é7szŠÛó~þ¥’ˆ)ÄHV\|õsúê%2Ÿ”Ù³R4ˆ´g)vP°ßµ§– mÚÜ[‡øJãH¿aÖ@ a«wï)a9˜vSäL]¬03Ü4¹�óÙ…O~jÙÓפbGKñ®o?\üäü¹sn¸å¡ÿ[òÑÚíÇ*;Y~� X!Vnºá×ß:Tî¾Bé7\;PCÙê={KYÅüd_©¤ß\ñÁoýß�ýå9Ñ>i™C|µW–W’^�ä–JÌ�~ÇíCU\QE•Ë Z,k2™:;;;;;�Fg¾V kámJx5I¸(7Ëýð3!IKÄ•sC—Ô)›ö¯=µ««ù¤Æ'kãíÖ&«ù¬ÕRƒp$Ò$t6©-ÜÄ0C¦nöñOâŠh”¤)о)¤bÇ–c6К:c# Ž�2c¤ì¥[*²Ët¶à±Ò JbPè~&"y`0F´µ²²�¢uE%,EqCRB1È�„E§$b`ëÊNwp\ü‚‹PîF¤îÓz-™‘39 6ôŸù䪯?]þô_f�K‰ñcÀn¬.:²åÛ//ºgîO¼ýSQ;“«ë‹NµÀñC‡:}ApLjJ¶®ôt;u7dMìŸ2bd?þXJX»Íj±X±N‡¬+íõHÁÆ”®,ª¨rÙ8Äx"x(8ïe…ž"<„ÂîO„p›oî B bò¼,±.D¢¿ï¥ø¥¤NßÙR¹±úÄ›ÍUŸF ˜¬õ ²™OéüÒ:šóëJ¶kt‘qÃ^ Kœ+B (bÕòòx„Àzbó¶ÓÐe̼:Žk†PŠÃ®˜™¹âðžªí›³ïMëã¤Ãƒ¢Ãõ ¨¡Œh#ÛÑÖ(œ´6µ@8<*ƒ‚Ê@3mmi%€|òæ©P�m,¥¶d {Â7.sÖ]™³îb©?}¢ ¿ 7çÈþ¬â††ãë—-:~æÕ÷ÎBlsc3`Â"Ã]¶LhX(†fÒÒÜJ!¹‹µ€¥æÐºµ›÷çž©nê°Ú¥½Ë^ÆRshó¯F }h„¿Š,ª¨r¹@ ƒ„~$‚@p(Q „BË;u°àÖ¡@©ø9wUòsIÁç‘zš0'4aN{Ýž’ýŽr­ÃÖ‚˜ÆÚ ýÇ}%7gyW©a#Ÿ3…DÎÓÑÍ;ê)ÂPòõ³w~OÃ0,ËR ¬ÑF�´ìÛºÿÁ±Ó‚ø6’€PŠt:-Pކ[¡D«e8CÏ!»ÕFÂz­VêøE)ÆhuÜH‡�‚iL˜m÷�†–‹ó!ž›`CÔ€QQFMýÓ݋ڊÖ/õý½µg6|øÍôU&38^Ði4®ÏE£e(uØíT¶G�V´=ûý§_ú¼ ôáÉ#ÆgÆ…´ŒFƒê­Ý~Ê"ÿ^µg¿ÿôKß–XzÉ/M£Ó¨È¢Š*—´G>"Y-„€@ÖËÛ3,K9!,»:R�[-ˆúGžÐñ<{KE_é˜ÜQô>­u{ ƒƒc®”ÈúyÆ.)Š/�ë t_Z÷ü´¿ÙA‘†5·Ôš�H´Ò0Øn<²ñ×ú)×G#¡Ü#„v›¼•¥`µ9èôz „ê} :Àb±‰p&ð€³ÉJ°ÞÇ+;Û‹–w !Ä<�’šL2Wdä•Ý[„”R&(ù¦g-=ñü¦¦êÜÜ:šÈ`ÐX,V Nfµ˜­é} |¶†ÒÙò¾X¾¶ÄŠ£§¾°ôÉé±R’²=«yÃ9`x?RUT¹|bD0N8hÁ@E]H(¡,ËY'ˆeEEG€RÂO ƒXÂÈ4âZíÂ…é×;䩲à ƒBºZ:ûŽZ"ª= €\z‹Õ›ˆE!@¤jç¦ 01·,]ýhšNîC„ØSŸ>8ÿóòã[v–Ͼ³/Ÿ×(í¨o´Èê°-�-�6<" #€¨¸(µ5µ¢ú~Bìõu��>2*¢#„ë`) ÛÑÖN@1+áßnúÌ Y­%ØZNŸ8^XÒ3enzvË´¯�ŽÃÐDMf@8*6Š�z¶®¶Ž…0�Âßæà&lˆŠŽ`dÝ4Åp[~(«�€fÈ�÷L�Õɪ멩£�|xѰ•Ç :õ>ióþ:»�Ìýå2RUTù£‰Wa|*tKäB'¼[ŒÊ JXÂþ‡ˆa ”°„u8¸JX‰Fìübø®;CgHh1575›Ìf³ÁGo5›»©¾¥ª¨ryB‹já@EøË )¡”ˆÐBÅx ¥KXËý–u µ`A.ºôÉXÞÕÞÒgÔ;J/E½¡ØQX^ØI͹·U:�fðŒiý7Æà˜©³Fè©ÝþSŽI¾]'í¿|þ]¡YJkh=¸ö§3v¤é3ñŠD H3pæ¬!zä8½aÕŽZ‡¤Ž­¥ë?ßÚHpÀ˜9WEq™š¸>± %íG÷ï}^Žº]ÿú²€0Ê[Äh”min!ÎüøŽ»iN?ØO¯}~ñ×Yõ6Å( ֺß¼ºbEa“®€1ƒfÎbÀìé�«¶×8¤óYK×­ÙÚ@pÀ˜ÙWE!'�âÀGDG`¶$滑 ކ¾¹Îĵ¶·Y(€Ç‘û?xýûŽˆ@,©Š*ª\–±Æš’ÖöN@:«ÝN­–®.“Íj ÐZý4Ð^WLX{W— w6iívÀÄŒI—ÃFš«Ž›;›Œm­Zs“Ùd6™LzÆ ··µ1Çrs«ªªôz½ÁÀSV�8qBN¥|nâ24uò:Ÿ�!‚òD2„q—éJûþŸ~m&HŸqÝähDù¨ù"9‹‡Nž9ößY»›÷mÙ÷À˜Á„%8aâUÌ�>PtÍ´Ì~¡¸½ìà–Ÿ�ÖQmì5÷ÝÔ�áT.?çéù‡ùwîþ¥?”3sòÐXGKéÑ][�TšpääGLãN¸Ï•Ó~]VXÿÓ«�·N›�®3ÕŸÜ÷K®~ö_¦ïüxS3¥¬Àƒß'gÕ×mxkqרhÊ|`Þ˜Œ\[œéSæ½öxõSïì©:ôñ¢yßÄœÜ'2ЀYKGcÅ©%u�,à ´»_üëøÞ±…æ<=ÿð#åþ¶ô‘93¯ëçh9�½ëç#•&&rò#ñv³W‰¹júðÏ ³k7-yÌ2ûêAþ¶æŠüC Øq/¼ž±óÑ·öó¿ûè’™:vRŠóȦÓ9{÷³�}á;y{ŸåØÚ�~ ™©“gŒR½bª¨rBKK}y[[f˜°°0Œ±©¹Ùd2jB‚ýBCŒÍ§M­•,%À²ZAg#Dˆ:ê ;êOJt„5¶µt¶4S?_ßÐ�Ž’_�Ïqƈô”%%¥ç-y])Ä3sõŠNÉ(ë¡lã/[Ž)<þš«" GÊŒ€��PนW†íû©9ë§_¦Ýe·Ú¡LÐ�»_þSßw–ýg͇FB�R¤�~Ãÿ÷ภÁÜCHßÿæ×þ¾æýÕ›ïú¦pB˜°ä©wÍ¿ÿ¶ŒF¤àÒô¹å…ç^CÁé½ëNï„ Qco_ò·Û ßîC@¬6;Aˆ„@—vÛü«¿½«²üà†r¤OO¼ûNÉÒ¢„J�%Ð%\óÂ')“¾ÿvãöC'ÏeUñ˜KùF œtÕµ·ß23-L#v íwÓ«†‰æn€6,yÚ]óçß:*œ r¶ž«pììg^®ãÕ¯ŸØöŸÛ�Ö'8!ýÚ™7>Êü§Ô¼o Ë·¯øç±ß¿"uØìg^®ãŸ?;±í?'¶†è‘s_}꞉юèÛ·|žjËGÿ»Ma[ $ýEj,,e“qMëÞ0‰$R2A( ·)€¸¤hÙ–):§É³‰Rœ–Šj]èqÙ�§ +pg�mÊ<Öy$-ãï+÷=ðôPÂÄh5| Öh5@-©WE•Ë\.·VJ#�yi(¥@øôhI1bÎ% Aóþ0*à§·9kqéÊ¢‰‚$öcŽ¢†O$¨.ƒÚRe‘—ï+=P”)/_¤�˜GQ|ȃOŒµYY®””PŠ4z-õÈ‹&«ÞWEUTh¹dÄnw’÷ø¢€XÉÑϵ�A€y]ÍD¡ ½Q|4”" \]4G¨ ä9”Pî#I.'>°‚a Ïa�dá{ñ$²ã)•%B®Wwˆ¡ä”ÒüQ„§ýäÑ’:,+?+)7IA ·¬0 ÔQ6Eîo#ÊÞHD Æ@lž‚inÃõ*Þ¨¢ÊÏ�tÙ9İ“ ²)y$Z ï#,¸¤£‚Ê6þRü�«’‘87©y³èò¢òŠ,©ÙÙ¦ôÜ9™/Âq=?‡Í†tZ�AÃÙt›ÍNÔ÷NUThùC K@XÐà£&ò05bò2—Rň! yÿ0y ’Qø÷H*FAr~HÅxJ‘„W ÕrŠ)"q¿¬÷Œb•¼Ÿ8å Ë.ã6O!ɧ- ‘Û¨¯T~‡=€ k·²v©1Ž*ª¨¢BKOb·Û‹Š‹óóò‹ŠŠjjk»ºº¥T«ÕúûûÇDG§¤¤¤ OK4H«ý¯A‰…,CK‘,± (6þR*ËCà” bäCŠˆð1 Äõ>J e†…K­ r7s!“‹‡:EýˆlâuŒŠ†™Â³ !D–¬àV�“…B)‘Û1ÔÉæ=²‹ª¨¢Š**´x#eee›6ýt$++<,,0((44´o¿~~~~„Øíö®®®ÖÖÖ¢¢ƒ¶´¶ŽÎÌœ=ûº~ýú]Ôõ Œ€!DÌîåœT,!J7_XN•9»Š`…ºäÁCÙ~(ƘB� mÍ€ˆ€De¨%Ë_–™J2ìÀHbÌ®ˆ1?I�§’ õó”Œ1—ÍÅ`¨²Ú”�Ï#,_Œ`œ¹ÓõTN|ãࡤ_UTQåü¡åÌ™3«>þ¸®®>66öÊ+¯dÆl6[­ÖÆÆÆ††¹^ÆGDDôéÓ‡RQQñêkKbccîŸ??))éâ-\÷ßTÊ"Hé.Cs1Œ±’OÑÎ…@,Ì$\à]tª!¤8ƒDœŒ…_�¨”‘¬²#ÄR"“ðeù„Ê.Ï›bü¥TªÎ‘"8J/•PSÖµK†" òîB¥sÉÖn0¨7iÊ'€ŒÜFUTQ¡…›Íöégköïߟ˜˜˜‘‘a2™!\µæ[kñª“ãk±X,íííãÐÐи¸¸ªªª_úû„ î½çn·<•]d!¢t‰vFÀ«HQw®`…ÓƒT(6T¸¯Äz¹I°BD‹ƒÓúÔmƒ.*S÷ŠD0ž…†ÊŠV0 *ÓäœZFR´žÃ>±xEêÊ,›4¢®�(EãIjZÃñ‰Q¤$$ß%PY÷J3§[`AX£Õi„(k·Ùj _U.oéEòqMMíã‹ 6ÌÏϯ®®®££Ãáp€¢Ž�orüÿí}yœ]U™í÷í½Ïtï­[Sª’ªLU�„I2´"(Šb;´¶¶�tOŸ(‚Lýdpj6Ýb·mkƒ=j+ ¶8" cÂ2TR©$•JMw>ÓÞûýq¦}nUB"ñµçƒ_~7§n�éæîu¾a­àJð§”Ò÷ýr¹¼gÏžb±¸|ùò^xá“W\±k×îC_K·—›Ú,ñT’hò8ÝËQ!Hs¤Œ+ÕÈ´ $$r)�HÊÄØ‘ú?Îe"ýe8…",¦ï…*&*w'Þ¡ó~:ùH¦,B‰¨ú*4^)²oiYÌ@hÙ¹k×�7ÞÔÞÞaYV­V‹q")ÿ( J*¨Pà=F­G¯öèձתl%#/ò¡§×­[çû~{{Ç�7Ý|+c¡$/ÀD5‘$ÈH 8½‡D·EB�áb‹˜Ö{Ie-ªvd¸È#!HT)-TÒ µ"'Ó\øøÝ�:sÒ>AP¤^R³Ëª²bzº §ˆ1‡b6qÄ7 „FÁ ZXS-Êu„Pe â{+…�BìSž2-œÝ…l¬,‹,fx¼BßuÝ[n¹%_(X–8ö_xÄ£P®¨�Ìñ‹S:†ÏìÜ%í1¨ïÁ‚Ý`×.xüôÁÁÁ X–uËçoùÊm·’®~¸ ¡NEôîóxS¤ßE@}¸�eÀâ„&MìÀ˜9"%AAQKÄ'1Å=LpūޕmIsmíy-\»°°—ŽªŒza¡ sxAŠŒM¸àG' ,«]Š�W˜Ôˆ XåNn߸ióΑ‰šZ®µ«÷ð%GôÏ2”go/õ%�CNSI !î“·¿çoôzßó�w^²ŒAJ¯K˜(㔈í–È�€ˆIÊi&:yÙ´ìc¬>Ï”IIÔ“LÎA*“Su_@¢uʛ䟛�~Ê'”Ñ'³Èâu -ƒƒƒ?üHGGç<]ÑK!Dн6«§•hzÌÏ ,lX]Yo.�OúΖéLú/Þ3úÌÓ7oZç:ÃÃÃ]]]¿ùÍCg½ùÍÅwùá½?øÑ�ïU·ø¾ï¸®Æ4Ã4c 8w=÷ì·œsþyï•0¢h‰¥. QL¼tÿ¿ßù�žÝQOq05ç,û“w}èƒïZխɹRi%ýeáN{SB8%ª‰—hìÝ9&ZçÌ.j�Ö€‘‰§c“ÆŽÂ�R´OÇ¡2.dƒ IDAT�Œ•^RœɸàÌŽ ¥+’ø2G3iaå@ÓÊ$7•¤nô4%²,²Èâõ-ÿôõ¯Gö'"e},%E™#¤Â@×:åÓÍå)5¯Rüé‡�뮚«Þ ÔYÛí>þ÷CkÖܼõ¸]N>>Šã8õz]Ó´o~ë[7Ýxã�Ÿú�~|ïÛÎyûàà`½^¯×ëÁ~u?ÿù›)e±iq­Z½ñ–Ï?ÿʹL|t•á. ¢ºîžnø×5c\¢1kÉ1',?|v›Åìòðö—~÷ìúáçÿû«ŸyøWï¾æ‹—¬žEâÆj'MOèêQ´Ó®ýù/¯…”þßrÏ5ýNþÒ»nûÓ9S•'’î•;4„HŠî—­Ô~ýö‰ –wLšIS´[° OTÛ2H¬˜X‰’©ý¸„’B ª¿B1©Æe‘E¯3hÙ²eËààŽB¡À9�«‚õ†¢\`ÕÎï,0®Sá>r«6»—| zæbÍçœí›�Í�ä�'é\—՗ýÝŽ×ßúòÊ’¯k(<™LLNNvuumݺmÛ¶mýýý~ö¹\Î4MÎyL ašF¥”=!ÁE¾P°¬œÂ„í§î�ÝÃ5ßz²$�¹§_rÕå.ïÐU.Qøé׿üwl]÷ÝÏ]eÞvÇG–šxKʦ® ¦ûÿÁ2Ì:§¥'%Êò† C–@Òí‰]'ãJªÍ9¥+iÉKHWÚ¢‚ DÄæ²˜ú6!ø€©…Æé½¾`?èÂ}. ¦iÂõ eCáe”É,²˜á±Ï ±ûî»bû“p} …Fx§V[]îÐݶ9í¹îN)8€ùÜg„'|ÑrôÑú’³„œØPûÕ­õÍ/všü ‹¿aÑÓõ£²Løh̘=ðÈG‘Ëå˜ÉYÖÄc�>ô¦7ýêŒ3*ë×SLä¢L¼âU ÊHJÄžûÿáO•$éþ“ë¾rÝ{—whé%šŸûé[o¹`¡öúïÜ~ÏVÌûŠò®�›6nØ>æ"$–•Deh㆗6liˆ°‹^Þ¸iÓúm{m!%Èúð– ë~bƒ/„=²uÓ†�ÛFmõâ "‰©,ñy$ÉjŸhDÝ”ˆŽƒŠ�=(° �EÖÇIOHá`‚”¡ÆLüSDD$*ÔÃΠøuNŸ·x®Ë�¦e™¦NÁw]ÿàÊaÙüqYÌhñ<ï©5k(¥RJ } =‹¸9â©sl~ïælZj�åçÎ3N½Üxã§�Ó®ÀÃÿ¸~œ1.Yviþ¼/æVœ‹ù9Àm)Üüií|וfÿ’Ý�ÜWw,' Û˜[ .‰ÖÌz½Î{ü‰'zÿ�ž=!º®›¦àŠeYV£ñÌÅÿ±r…·æ¯>6¾ AÕÚ+™` PèoþÉ÷ž®IR<ó’KÏì"MÒÃQs¤xâÅýÖn"��þðÙ†”RˆÚcw\rÉ¥—Üü“\Š€U¼·ñÄ?ü¯Ë>zÙM÷ñÉœ§ÿù¯.ù닯ÿÁîsw~ú£—Ýþ`‰ƒ¿ùîk/û‹K.ýì÷· €P�ÒÍ‘K±ˆ’GŒ:õ¡$eÂý”á¤1 ¤M†§°vbŒX1é·©)‹”S¤É¢„,>È>²î9vÈQ±/óË"‹×kAlÃÆ�Œ1Ƙ”òòKó�:©¼ùÑ¡—'r”wn¡=ot-Ð?C–¶9ë~–ûãÀ]ð°¶žÜê��ð)).’N¹¾æ»åõë šöÙ¾g€Kõ¬;v,óL Ð0c›6 ,]zÄ�C !„RJ)Õ4ÍuÝY¶Þ[u¬&›¸‹ š®D%¸ôš,$[ô¶Ë®î[óŸßüõ Ì}ÓGÞs|+-Ö3�;}Ru’2öt‰¸8�–5A½Ø˜Ü/›&ãZ¦ªwÊUœLLË’š]¤º�âÉCAWY&‹,^;188¨iÚÔÂÅôÐòüsÏ{ž§ëº”òÈE²è„‚ó’1¼�–báÄ °ãHäžýÜÝÕÁ![2 ÄÝ*ê“áïsÞº�šå—IÛ`:¸U÷…»ý‰ÁbÿüøÜóØÐØ’ÜäÓ•Ù®À UBÄçž{îÀ¡%˜kŠ£uíÚ…îÞî£úÆ¿7¼~o©êoþ¯ÎYpd{ÛÄEÚ¾òؤ¶é6Fc³öæ�P[¼üH@ñ¥WûL€@[qtñîÁ‰‰­câØ9dZÁÆèô’’URš ©0dΊ³Îí©ÿì_=íG¿émçÏ&±ýƲÇ*F©µs"¡ ÓŸFª[�ɰW3qF*m© Z¢ª)Ó—c¤TgÍU­²,²Èâ��³Bº•ÚںÛr�­Æ1ï¾ûüÝÄ,°Eo*ôÌ>¼º§•:U_  …Rºk÷Á‰¾± .æ"Œ=9ÊjZ—>xÛX8F�–ƒÎ…ªŽF|Çheç¾/¤®3uÔc+Éd1G¡Q*%€çxª,¤šN$®_ñžÒ©FŽ/ñY4u2‚2]â9ò\”j b³¢æa˜Æ  Ý4‰+ôý°­Â#ª?(h%0D” Q¢âé,S‚2û`MˆS£‰«^M”©,²Èb&CK­VS¨~„ €fï�À yž”¢ÁÙ½KK"_®Ö‘R†ˆ'êƒö¶ö/j;ú$Lì~ŒÛe‰f}¬lHç¿„çŒOx¥ÁŽy'Xó››wö›å�N!Xn!Õjå`+'ºxå7Ÿõì~°,ou^0÷‰{wìÞY 4ì ëÝ_¹N]ð9çRq"iäò@Öªu (Å1ˆŠ?�FÐÌ™Q  Š>cJ+_­OÅÂ,‚ ĆèÍbq5J8É1ˆdª›pL°T3”ÈF©–%Š˜�Âe€áìY$–’øTó•Ô¤Yú,¦£”î?4M‹gdzÈ"‹-žç™¦¬"nÝ6«CdÁ¹…> Aõ_¸RH!¤#u¤V¯SJƒeeïZy|ËÊ·#R@ÄÖE¶�oÚ\èl)?ü/ÁÎ�‰²7Y’�½´£WÓèB³òÛR²hyžP¬qA�E¬^=¹ví˜ïwïj]ýž–î›x×#¿µíú—¾ü¥Ù«WÇ:]¥]YÏi±wvŽb¹644ÊOè!H ¦“ƒvIäÝ‚€è안lvïìHB-HLH0ª-‘`œª S …Àã´ƒqÄáÛ-ioȨŽ)ÃåPySʘœyØQ‰ÊkÓ³ßåô⛉ʿÒW‘ í}L—Ìd8‡*ríó(S#°fȾ‡Yd1ÃbÊÇ Ý.'7€pÝï©üöκïIî€�BDpc”RÆØ<ÍÍíá ·æ=µíî¿_óðúIiŽ�7†6îþÛ[ó¹ôÆw!5µ¼ÕFmB^•7T0!¦ëºiYxÑE/îÝ[³*¥"¶µyžã¸Ž¼Ùå1¬ø… /9z‰’<ý»IPfºÏ®è‘ÜyñwëêBÒ¾eËZù±©ìÁ ŠŒ#^ˆLúûQkž`¢•ßœ^¤–iH¹“f›¹D.. º$eÂxÊhql]–˜Ô„§I� IÄqpº.’ܧWX†Yd‘e-I™"¶%~`káØ%£ jåmÛ[ué Á¥yêW¼z^ŽÔ ´å€YÙ±çñ_¾8ð°8v,²ê6ÈPiŸ‚˜�ãïiù�_-=„éZ�ú*´hÚÁy*#"c,˜�;w¶÷ö,ýÚWºõ6¶'¿êÊO×êuÇix¾§.q*y=êhcÇÉg®úÚÓ�ÙÏ~ÿG›ÏúÈb]*â\ÊŠÎ÷þú¿¨yæé IÐÊAÀ¹ÏE¨X8ÊòdI¤…¸šÊdq® e“‚J €¨RH"cŒ¡ È~PÙÑìËœÆN3�ZØÌßG@ ¡çæ4UAPÀGÈD3MNüûá*í¿\–EYÌ(hÉçó¶mвeÒé�ð‘‚BJ Â8�ÖØÎ-Øó°LUZ€$ß=«ºí…�>þB}ö#ø—²ù�vÚm.Cl^‰tðUß�&rÇu¼š(­š`ätnoï�C‹¦iããc®ï»ê¦1×óSµ‚Ĺç8ŽúHž*Ô`l`¬øÐ§Þ¿öêÛ¸õû×ÿïÑ?¿ôÒwžÐkD4@å-ýÇÿx÷s“Òè{÷•uR!ìÁksÎ¥rsééß>>.q¦�¤ÐδɄ‹¢B4;†ñ\@üÅÞXÊÀS*n•;#„@ 3E‹QDY¤B*E«(ÉI² )B:=¨Q :�Æž”ƒ@rŸ÷MÇßRrP’qYd‘Åk%°^«NÝêyÞ‡?ò­­­A»%Á¢óÔ[F¶I^Ö‘Nlï]¹¤mÅiþØË/ÿâ75—ðtÉG“^®Eï;s5)ö�¯ý�ÕÖb-<®¶e�[·ÛŽZÕØµmÓÃkl¿ÎíADÓ4«ÕÊ]wÞIq]w``à„WÔÅ$ТˆáÙB ißÔnij6Ä‹i0ÖÅ�Òèî'þéÊÿûóQè{ßíw}ìH ”D@Ù½”PÔ÷î©x¬Ø»pÞ,‹&’-BŠi�ƒ„‚×FwW!ßÞÓÝf„f,#@b1–öæJìU¦Ñð�i÷±O¥œ6SPXô‘ª&*>4J×GQJNx•ÉQ¢Ý[–¼ˆ‹�º®û¾ðW‚ ˜çyA 4Þ®L@ÝϾ™Ydñšˆ‹.ºè „^4M[}â‰Ï=ÿ|±X ¾öˆH´^$GlÅ~F�J)>$žÛb´µYó�žwò±å;±É¥ŠÑŽ¥K±ÐíŽíY·­sñ|k�Ÿ_tl¤änipg]è£Ð†ˆù|¾Ñhœ´ú¤@äU^­:ç&M¸2í¯AÌ, zqöÂ3Þyæ¿ÿò{»vϯÞyÃ9]D5&NÚ'ˆ4×µpi—rñ áD2Ƭ¢Z°ˆ“\WÿáÝñ›ÇÈ"…ɸ&cIÉà<RÔ%»A SyâŸÆÜQ$¬�%ŒN˜Æ$,ª£©ø%§Y¦«nˆóW‚¿ªlü©ÓÉ�.Cö¥Í"‹™V€sÏ}ÛSkÖ• Ù}`5bPB÷Öš'æí{tíágÌyË͹ËB=ødÙ‘Òo”7­ÝùôzéËúXeï3�ë•]®ï,m‹jÒdŒY–U.—Ï;ïí‡æ²dʼJUäM­šê|”"¦L×êG_øþ7üì¶Ç&½íºÛýËßûÆÅíP­akG�A2P•‘D•C/§xûbs³DF 2Í"�}2%¦’8$C2M)KÀ  O5¯e6:ÈŒ€(µ¶ä®¥,ËUÅìrJö ‰ÏØtв¯Ç…}mÏ&’³Èâ5k×®=åc8ì°ÃúúŽ��·¶¶:Ž£  H@‰(�VhûZë$£öúàms¦Ý�]iìš§sZp²6bÈ °.­­°äy¸‡zk±µV«¶hQ__ß!ªó5!�ÜwšÒdkœß:çìÏ\µéS·Ü¿eà'Ÿÿø}_ý˜ÿýo·¾»›L…¨ðXa=¦t!âj—lÆ8TžÔ TÆcøHÄŽPé²`\ŒTMR• ‰‘ѽÄgRðthõ2)QÁ¶ÔuT;„¼ÈWÉŸÍ"‹,þÆ‚ òù|³òÓ~ >vñÅ×\{ݬY³¦­Z "P}œõ®Ã“dåññõ{qº¥›#Ûa.ßh,w%á\ú]BŸ W #ˆaj¦iŽŒŒ\}Õgí5Gxl²±J]BšH>Íe™uò'¾þ/§þì�‡×n«K³½÷ØeE¢ÔŠE–´b‹ª&›’&U±¾©c�M§‹ç“ZDÜE g·@ÂÄß8$ZÊÔDWT‚ ¡ �RH ÿ*¸þC‘‰FsÌ›‰e]Ô¢ŸÒàÉ"‹,²`û‡£7¾ñ´gžyvþüù“““SDG$‰¹][6ÔrL l�‡#àÞ(¿àÀ…\r.¹ ‚KN(twwïܹóŒ3N?d) ¤ªGûQÁ€Ç5ÌS-}…Y‰­žU|dÕ;›ëh ÅÕºP�_„ÿÉæ[§ø­`Ü)1¥�,üAM N]bP‰'»b8AÄ@ú%ÜB‘!È’€I i#NM„ÛÂ\LM€TÅç,²È"‹€øðŸÿù /¼P*•:;;'&&©ùÈÍ%–†Œ}SB1]!¤”ÁÓºUñ_ !ÝÝÝ“““º®}èƒ<ô‡j=jš¥/MÞGÑ ›ú4Qß¾Ù!%$VÒŒõ�•&Nâ�$Jc1âÔ§¬� ‘IòeID�xïZ!ÄIO³[¥hvÃbdtWºR.RQ,“�YË´Â^O|Ágä¥Å“N3éßs¼&ò»ôûC‹®ëŸ½ú³W_}µeY1ºòb L±ª˜³¯›d›NçÌ™cÛöÞ½{¿ü¥/éºþ½·ÍZjÙê>•&ž ÈihçØ¬Q—½0ö°W TÛú�kŸ²«¥ÑŸàŸ¢Õßl“º¿ñ›ŠLŠè�Œa: I�©ôM¦±4Q£‰Ä7¹Ëdä¸2S[b±vbö‘½Ê»ôÊëíí¹þúë¶mÛê8NOODS=1M/ö*Qk_2êS@�Í,\¸�s¾mÛÖ¿¹áú9sfO…ÙWw/•US=�Mw°)‘™*y’ÈJÆÔ�°¯Ö‡š¸âÎF6k€A_¢Á:EÔ^Š}=;IU¥ÕS�R&"÷J/'ÕȉgbEçfèUæÒ0ÑBE T�²iîR33f0®À+éeÙ�ߥ:ÞâÅ‹¯¿îº�M›&&&úûûMÓŒÁ#xƒJ@ ^Ä?j‚™|>ÄGLNN üÍ 7vØaû:ûC�Þ©^N*é·J©¨ÌÇÖõ ®°i“IlFE,?TyÁÄ98.Ê\€:x SdhÒŒ‰÷-§[Üe ‰£Hœ� Ùù21©ŒZ, ¤BŸÄè™”Då%Všƒ¬�ŸE¯§h4ûJÈ+fRÁLWÿ�7~nÏžá 6ÌŸ?¿§§'.T\ "Þ¿GJI)íëëëïïß°qãØØèÍ7ÝØ×׌Ÿ5=�#¢¦ë®ëþÞ°ßo’åY¡»L‘Ç’±B1JAég„_N8È+"ÙÈDW?ÑN–dTTUâ�‘¥bàé‚cü §¸"ðŽê]©93 \,eœ{Äh&ã9├°aˆ]J£´ ]‚ðdB+˜ìË–E¯ŸØ×·ž^{í5Ó"J�FÙ¶ÓhÔ+•êd©Ì}ÅÊãvíÞùÄO´··/]ºÔ0 ×uhJMTDBX–5oÞ¼E‹ ?ùä“ý‹úß÷¾0Jê Ûu]Î}!d\¼ ›NœWkÕ¶¶¶ƒÊûµ&N�©`%%ó1Ì`šàC3à(‘Ižù± ýTšbðîØîÒ>Áqâ£vnPA'D$$�”À¿+ѤT`d Ö<î… 8}Ép'˜$U;KˆŸÊ…kL ^eœÇ™rÊÄãÌ»ÀVñûC|dÁ]ºãŽ;†‡‡cS÷?�†X€ žç¹žg7¶ãz®ÛplÛvlÇvmwçî��?úhµZ[¾|ùá‡N™œœ¬T*�F£Ñh‹;¥Ô²,˲ŠÅbkk+ç|``ॗ^ji)œtÊ)sçôê¦n¦i–ajºnºiYº¦iš€„ëºÛûöµwtàÕªÊÇÓ%'(Õ�ßWÑH¸2‰œX,Ÿ�B(´Ge²YíRÂå<&©¦Ju˜ ”©"1 ò©bM NIÍ0ebŸj¾cʱXÅ›©î/ X ’ôH�9+¼S52Èb&ç|fÓZ»™4!ö‡h� !î¾ûî»îºË4Íi[úÓCK°L;®ë:Ží8Žë:Žã8®íØ®íh3¼{ø¥õ/íÚÙÕ5kÁ‚ÝÝÝù|>ÀÏóªÕêÄÄÄðððŽ;FGGçΛwÔQGÏž3[×tË4tÓ0 Ó0tÃ0 ]_éz`)¥ô}¿Ñh uvvöôÎ5 ãUA‹œ¦SýûŽ5¥òL/ÁÑÐTªk“XCbR8‹LìA-dÉ©…=ÜÏ‘ÓÇ‘ º( fñv²o‚¤©ËQÆCeRù¡?Ò`£B´ÈM‘§Ì"ƒ– Zf´ÔëõuëÖ}õ«_ݽ{wŒ+-É I)„ð\×ó}Ƕ×ó|Ïs]7üÃçÜwlwh×Ðöíƒ#ÃÃ¥RÉqœÀ7PÓ4Ã0ÚZ[»fÏYØ·`^ï<ÃÔ)ešÆt]×5MÓu�i†®¦©1¦éz@Љá-¨n9®;91Q.—mÛV©ÓÆš'~û¹ø&¢àÜ×5&¥Ð# Ûñ}?ŸÏSB}×ó}MÝp¹ˆ@ áBº®Ã�Œ ¡DÁ¹ „‚DJ¨�ÂóM§Œ¢m×)¥†i2Ê8÷(!-…–j­^©T 0J¨¡ë®í AÍ4¨¦UªÕ¼eY†áºn½Q—RZòžàŽç¢D“é:e�zÝáœj¥ $hõ=—2J)!ŒPBÇÑ ½á8ˆ�pßר¦ë†Î¨ïyžç!¤„t7ŸÏ†éºžë¸¦e6œ†Ï}dˆ¡çV.WÈ·H)+ÕŠç{”B¨c;BÝ0¤DÏs‘ € ŒQð}N�q)Ü÷ו(Ê" )¯¾ìÁgñí{îÉVá7nìììœÁ866vÄGLLLÄ[*•Êkî*ZZ»Þ‘‘‘Cø‘@266¶råÊ}á ìŸ×B ¥Ô4M€B>®øRrß÷…ZöÜ÷—,Y¶T¢vTÉ :»„Ô¥Œ1Æ(cŒÊ™Â£l:{BHPÂëêêjïèÓuû›b×àj舥Œøœk¦¡Q&�8åŠÇÊ9(¤ PJ€ PŠ”¢”Ò÷|Æ É%"¡uƒyžÝÖÞÁyÞvJ©iZ®Ó¨TÊ®ïI‰HçÒ'šE%ó9g¦^lo¯»®#¸Ia€Ä%ùBÎv=B7L¾Èå H]×Êç™nx®ohŒP´�R�RøŽkås¹|Ž6lŸ|â8È–IDATs)$är-yS3¤žïø¾$B M× £¾íè†Ñ;w®#¼Òä¸c;:cÀ¥]­VjU+WÐu íèl©T*œó\!çû~¹Rá\´´„a–¡1ÄJ¥j™&ešÆ Bˆë9µjCcÌç\„óçÍ >‹\.—­Â32(¥RBxM_`.—k4ñ{Ÿeö?Þ0Mó÷‘ÅÆ}á ¼"erêÒO¥†R:‹ÊKû©5éHOIåù3ÆTŠÌ¾Â0 B¥(� Hî: [HÃb†®éšÇ}$”hš¥kÐs��iORF %(¹”\€@ „€Æ¨�¾n˜žë;žG)RFë�ªiê–e€D!xµZÕ �s�@ZÛ‹¹\nÏÈ®‰Òx.Ÿ§+UË£¥‰\K‹FhµQm+ÛZç9�zógu¶Ž—'�€F©/Ýr¥ª1äœSÊZŠEßç£{G¤ä¦ixÂçžgR–ÏåêuÛv�à6PMëééqt·ØZ°Œ|£^¯VË„�¶ööFÝ™,�kLëœÕQ­Õê^C3LÓ²ìzÝ÷<Ó4«õúøä„©„ÓXk[ëèèh­^5 ³³³rùBybÂе®ŽÎ\Þ*—+ží–*µr©Ä9'”äsÝÔÇÇÆ%H"Ñn4âÁ™*þ Ž/!ø 5­�¯­h:çCþ‘¡ÂœP7ë­= ôvu´°WsÒtǛۿçÙHéScLC‰©\7sÜsm»Á(3M].<Ï£„”Q¢B4]ã(=î )4�¹®@îIIA3R ˆHe‚ _li)Öj5Ï©Z ¹œåû—‚FÎ÷¥ã8 I1×îjaXl-ú’�Ž�¢ô5¦Õ]îqV‹ÕÖ^|üÑG;»º¨F…�€Xli¥@l»Þ’/Ï+�î¥Lk-¶ìÂ\�#`¾hù\4굜i!A.¥¦ë„€•ÏyncttD×ÍbKqΜ¹õF•0Ɖ#õ‡G÷J) ù‚‰†<Èçrš¦ î{®Ã h–E8áœçÍ<ÓX®�Ó Í¶ë€,Xdïø¤ok-6¸‹ ¨† ":N½­­PfP¯Û\p×sƒNdÎÄ37öó :“.P]‹_‹×ÛtþˆKHï͹«Ï{×¹§9Ë@< ¬å�~0Ññ<[Íã~0,'‰ã:TÓ4�ÙŽëy.©J)RJ\Ïq\…àIÃ0 )|ŸQÆ=ˆ$„0¦sÎ]×5s–S‡zͦDËås†n" ¥š¦1Çv«Õjg{›•7jµ*÷=ÓÐÚ …ÉR¹æúLÓ…£££Ðßßï¸.Õ˜ú€R¯Õ SiŠ2ßõ9o0M7 ƒ Ž CÔ4ÝçÜ÷|×qœF]74J©²Ñ°�€` MÓ�@ì†Ã…tOg¾C]F‰išŒ¦1¦³¶ö¶–B‹ë¸žë5¥Ì0,ÏóK•RKK\Çõ…$”Fªõ¡$È"-ƒYfŽûn¥V#”vuuùœï=¸ÇŽ,²x-<òOùqaáªcš¥�§žß=õ޶.:á”ã—ô´�ÆøÐKO=öüκø}ÞÏêY¾ú¸Em0±yÍ“/ŽL©Î‘ö%«—wM¬{bÃØÿÔÈ¿Ñ÷Ö�â¼E8£›{ê…-»ÇSÐR*•~òÀÏ–uÔŠåËÔí÷þø>Ó²Î9ëÍêÆ'ŸþÝÖ­Û.8ïí9+)êmß±ã‘G{ã)§,˜?/ÞXoØ?ºïþE‹úW¿JÝÿøe£Ñxçù穟aÝ‹/­;÷œ³[[[ã�{FF~ñëW¿jñá‡Ç}ßÿá�ïïîšuúi§&‚žc%¾çiºÎ ø†ap)Ñ4 ) !@x¾@J‚¬ÊçœÍ÷9E"öŸ$ºf6¼º´ô9ç€^Þ4(Ó]Û©Vë\FuMÓlÛÕ44 ËÕ’eê(|§Zñ”,Z–ízBøH€ n×ë­í–e4×qÏu¹ãÃÔE”Œ.„ç8º¦·µ=Ÿ†É(õGY° Œ’|.Ç…˜,•5BŠ…<—Üó8¡”ê8¶>!H˜¦1Êu�Û¾¡Àñ<Ï>ÕH÷ìîBKAÓt €„´´äÇÇs¹A"$\¸Ž'(J)E¦iŒR‰"—·¸!솃@™f4l{bbLÓ4Ý0}_p‘-JYÌð ³V½ïŠOýÙê9ºÿÌW>på}£MÕÚuÊe·\}þayž'©ÆPŒ>sç�ŸûÏ«ò`Þ“,ií'ò+×½‰m|æerØÅ—~àG×\ñ�çÔ÷‘Ùç\ùå�ÏþïO]þèÿwž|á9ýÔÖÿ¶üÕN ‰�ôÞ‘à¦ÀSëw â4˜?m¥/f˜§6’Dˆ+õ‰!9°’"RJuƹ|Æ¡T¡iz`vÂ5L�2 „’Â(c„†¡k:"ñ}îy>Hbê&%LpÉý�êx^­Zó}Ÿ2æsQš,kšÖZlC ŽÝ ÛÚZ ‚ë8Àbš�ˆ>ÏFoÏlM£¾ï!Æh¹4!¸ï: §Q羇 )ABÑ÷\!8A”Bø®[Èç ¹œA œsŸê+vöm[cTcTÓ‚Á�"“uM—B:¶S)—õ%Șfš–®BÈz½Q©×%€Ç}M×9çåJ¥ÞhPJ$çÜq¤¥PB"¡ºaê†Å4�P†ˆB¡”P&\Ï)W+>çŽëNN–Jå2¶d µtÏï[0·#7³z2Ö‚3/¿ý_ü`ÿøÖÑéÓÒsîg>{A¿ý»o]ùþóÏ9çœó>týÝŒc?rÃå'ñ Þ£,|‹/¼øœ–ǾtÙ×_÷É�ßñ|ï…Ÿ;Wéc’®³.¿xÕĽ·ÿÛºÆÿØ�Ñû/ÔPÖžÿõ#;£4îÿŠÒ¦Ý»—C‰IEND®B`‚Solaar-1.1.20/docs/screenshots/Solaar-rule-editor.png000066400000000000000000004312601522022367600224770ustar00rootroot00000000000000‰PNG  IHDRobßjä¡sBIT|dˆ IDATxœì½wœW}÷ÿ>3sëVí®z/–lY–ÜmlccÀ!`šC3 ’@H�<¿ðäI¨!¤� á ¡Ø`Š0†¸àÆUr‘%K–¬²*«ÕÖ[¦œóûcfîν{ïÝ]yWõû~½ö5sÏœ>wöÎ|æûýEzÞñS/]AAAA˜9úþëCª6ÍI~ˆE›¾ oAAAA„$‘ÛÔ‰-x$ݦ†W¾øöDAAAaz9éܦ²¶Þ‚ ‚ ‚ ‚ L/M-oŠóÖ6/m|[m<ñÙ4( šk„ª×pÕñdÀåÝŠHAAA81X}ñ••ý ÐØ¶UÙ)ÍÊ'��hÚV½º ƒ‡9°w7Å‘!ìÀ›ñqÔÖÓ¨ÞÚ±Õ+“L/Ž ³׎ÇdÊ7êóTÚ®w>êYÞ4Ê0�ТœP°‰÷«Ž/_Ék7¯7YKàbìT“¦Êmª°ðìI×-‚ ‚ ‚ GJ3‘!&ù¹ÞÃ}’Za¦öX­ P¯ŽÚº’õÕ ±0Ñ8ê�Á-•°Sé ÇÑhü�­ÑŘ„ÑTÆQ¯ýzÔ›¿Éö9™§QÙzé�µ™‰bÞ˜`|eåÒ[~�5² T”3Ž©6ˆKWPmA£Ârc Eɉ*-�YBiõK0Ù6TàaìTe›t›jÙõHÃÁ ‚ ‚ ‚ ÂtQ GõCxíCyòs,x4¢‘èS{,Þo&BL˜Ç+V´€‰ÆQo?�ͺný•=’üµã ü„xs㘈‰òÖ¶êõs¢²Ú÷ªÎG=šÆ¼Qºº±ÔžMØ»~JùôÅèö€+\báE‘^¢«æ8€eÀ$ÊVÄ©„°£ÆŽ[CCdÿ7‚î«ñ­¯(R*ð¢Ï‰¿GAAA8q(�³!ð\ìTº²ot€“Éxn•hx.±‘E2r?i„§'�×kô9™î–J¾Š¾_%4G½:k�D&êG³¾7ês£Ñ8/¡ÒÊP¦¹ž1�åM$Þ(‹ÔžM¨¾ÿ¡xÞé`Û`j,nê…¦_a´M9&q¨Iº½�âeg’yü^R»¼ÅçTŽ%ݦÊ=«&ÓAAAA˜ŠÄÒÌx‘í»­=žÜ7:@YvUºÑ~¹X•>Q}¥×j�ÆÑ¨ÎÚú“ý®K½:ÍÉDyÏÅrRØ�;¥qÔ«w¢¾Lôy2ÂMmýñœØ©4&a˜2¡å 2(íc,«Ð�½óÇ/8,‹Pi‰T—©Ä®4 Ê&œ¤8cÙ”Ï>�ܽwt-ÁdÛ€êÕ¦Úž½g AAA„#£dB’oc5jë{X Žh­±,«²�1z|“fé“Eû)o]Ñ&3ŽÉR¯GÒgeÙ¾‡í¤*åã9 Å ò˜ëÔ Œ£^’ý°�T¥0ñy®%ãÜR˘†Ú Lb©p¥}RÏÞOùô¥ IºFÕ±˜±††Ñ­-‘ØÓd•)m°F‡ÑíñBᦖ¢¼~)é'îÇ=ãÚJ+Ý·)AAAá(£uã'ÍŽ%�O”o²$Å d�–ea±më=?iµ9•²5BQ¤¶`¢ã–Ñ32Ž:V}Œû•ìß‘�{Lÿ˜„ÛTýˆÆ*ð1¶ƒ5²ݾ²ú`l“ˆ+ €ï‘Ý´«ØM0k/åµkª3BáÇ„"MfóVìytëNJçœéÔx­§Æ¥Jw¶a•Ÿ û¨5] ·)¯mnÃÁ ‚ ‚ ‚ ÂtQö4+|x�W?R¶ƒ ü†Û$åU¶3©º“Ç‚HŸ ‚ê2ZkŒ6x:|À޵€‰ÆQ/½Y›ñ±É”S¶Cà¹uç§^?`L$IY ã0��ƒ&°Ó ÏIPc$4Q¿š¥OtÎÃó�®G=&¶¼ |Œe 4¾OjW/™Ý.åµ7àµõ�~ü¬ÑQt[KýºG‹Øýí”ÏyÖh?ù{þÞR oùBpj—�ˆD#í±¼ÆNW¹Mu>q[ã> ‚ Ç9³Ú˜“L@ÿ‡Ä ò8FÎW--íí,È…/©††Ø_å_=_‡�ÐÿÂ,ßA„〲V$Ÿxã‡õÚ­_.a×<ç6Ê[»­—?ð}âè7ÉýZÕÕZ@r±Àø>N�Ñh¿Q»•«ËdûŸ Ê”]¿é8ê•÷± véuÚ­M�ËÇÛºc«s<Þ¦�Ï¡:㨥iÀb,nØ&:”äItç¥/<Ë/¡´O°üR2Ïü€ây§U­ºFAö™çñ—¾ …�l+î¹oÁÙ½‘Ô¯î¥péÙãJèGJ�±0ºÚmª‰�˜ ‚P'“cQW =-)r–Â÷\F ì>\`øhþ[U-¼á-×ó·k,Ðý|æSßåS{¦Ç|X˜ä|Õ`sÅ«“›.L£L™oþûM¼ç‰„:£ZyÓ�×óÉU}|âSßã³{§¾O{´¤UÚV¸�Ç¢ìë†í%Óâ9Ô¾OÊ/àÕG’ƶA•IðB˘q¢À4ÑÆ[¼ˆÔÌ_‹¥‹¡U ¬¼”ÌÆ¯R¸¼s,à±6d7>�æÛQ5Ëb©þûñÖo¢¸8ªÞÞ™h ²¤ÛT×£·L4$A„Sœg\z9_zÃÖd›çTN†å+Wòž•+yûÏð¡/ÜÅ7÷‰ŸÇL£ì�­Yº¦p8¯«ƒµËóêŸÇÇönåo¾ö þkGyJ‹Bžèɼ�#È�{!å›â³mó³|oÐ=ÄæbíqÅ¢³Îæ�«³ì}â1þã™â)uþANDŠZ�.Kx%”jäüSŸXÄÐ5Ay¯„�Êâ—‹XöøÇö8,†Ô«£Y{ãâ'¬<ŠZh�tƒzêµWïx=Z˜�0Ê¡hF_‡å¤¼Ð8ÃNeÖW=^ã–ª¬UªÏ‡‹eUÿ¨Çiq�`ËR1%oiæå-Ž"e\°�C:C©\®Ô¡ì9<ÚsiºÒЩD£>ì)S&UYþBÁ&ð}œL®ò9YWe/¢‰Å›FÔ.åmY”Î\Jâ®{ye™q3çbÒÛ7â®\@jÇó˜YçU„™8oúé;)œ½¬DäXÀ© ¹£ÀòËe‰«” ¤Q,¼ð*n~ËJæY€ Ø·ýYnúÕî}¾Ÿ]ƒeFE6—cÑÜÙ\²~57^´�E)h™¿†xoÀáOßÅí#Çz§zd?ß}p?‡W–C[k «–ÌãìÙRJѾp5Ÿþ“Næ~þ|r›{J ºÐÇO;HÿT¯yª4C3fJüü¶ŸñóFÇU†_~x–Å£#Oó¥gŠˆT*‚püø�¤p£¿"Èhß«þºµT(Yª²:”I¬J—‰#c‚ºÛ˜øsEñÇĈڱTÖ2`Œµ—1«Q3ÞòV)‹öŒÍœ,,o û²¯hØ_4ŒŠq~¹ˆŠ–Ù®×F\à•QÊÂ=6/A�ð��L�HS™»ä~?Nü"î¤Cìà37MfÞŽ#ìÎ_b×·xAŽ{b�Ã+IEV±“´ž‰—–¶l§r\׸Ë$…šzí$·á:E�·•:£Ï�ç‚“ÁGëÖ_TÜÐ_>•É¢, ÛÅOå*ù¼(L*“�ú<ö£«,‹æ:.ósædÂtÛh‚À0ê†åmÇÁ ë–7ZcЕý ±CO�ø2Ú÷ÇŽkƒe)ÜRhêꤳ ¬„¨¥²@†œ¥éÎ8ÌÊX¸Ú@6Å<À¢äA,ŸÌJSnZ³)ZH[ mÙ”�­vU/QÒ»¼6ÆO­UË„–7 ‰Ý¦j¾S¥Ó—Òò轸güFè&e9`Y¸ë®£ÁŽœÂ°Ã­Ñ8»î£pÁ²& Ž™Þ}Ö>-nS‚ “$½l9/ë ÿ—z»7ò‘;ê75ŒìÚÈû¾5—{ßu³•Åò‹Örå�zù‰¨7ǽ[çÝÿ¬éúè‹yqRs×ðöÓ̓›NAõæÄž=—sZcëcAáD@û>Z‡Ö3AàU„¯\íÔºEEŸ“é¶“ª|¶ÇŘñªòÄÇk÷kóÔn+ÔXÞ$ÇáÕAu´b’��­u•èà¤Ó¦VŒH§æ·e™—·ÉFÊCwÖ¦hzGܨÏÕ|!\EªäÛ•´XDªÍgÔµ Š­™ü`üÍj8G^Õ\�:)²Ú |ß·pS)‹¥²v(Ò¸%Mg:ìSGÚ …›ŒÃHÉ÷¡#—Bû>%/ €í•ò-²*hz~œ ÜÐ*Isñ&>i¦Î2á±ÛTÍ=†Éfñº=ì¾³W„  ¼ÖÐPº¥ “Î…Çì4öÁíøÝL~aƒŽÔXâÔÜÓˆÛ” Âähën¯ÄÝ}�í“´JèÛøøÎ^²úyjÏ!žm(ÜXÌ^¶‚7]¸œËWô°bV–6Üb‰=úxhós|ç—ÛytèšCX9ÖoXÍëÏ^Ä‹:YÔ–!gJÅ"»÷ä�'žåë¿ÜÙ¤ŸÓX—ÊrÅ5ñÚ¹Æ?À}ëI6¥»xý+/ä�æ²4ëóøOÌ›ÞT\`üÏðå'/â²óÒ(•áœ�8›޽{S-\ûÊ xe—=Àw¿ÿ(w7tƒs¸à%—òÖE˜"wÞþ+n=x$‚¢mîÞxÉ*^ºj6«»s´§ \(°³÷÷oÚÊ7ÜÍsß·SÒó¹á%grýÚ¹¬ž•!m<öâá§¶ñå»·òè𨠗_s1¯›k�æÿýèan„ëÏçƒZIu-à @±äœ‹øû9¡Ë›·g3ûŸ^ªß�¾Àkí8ûÞ ‚ œŠ4tê«Mo–·6Ork;)œ „ XþäV¢h¶¢U,¬Ô¦—ŒE`gÈ8m‘fTò YG‘·M%OV�ýNU¬S‹†×[�*™æùzÒãðݱ›¹Úù+¹ý^šÁÀÆñ ¥èÇ/…t™ßÙR÷'køQ?JPô lŠ~™r)¼¡Éª`\[ÉÏñ¶¤-TL8މ-o*~l5Žª}34¶o”?œ«8„½ýn‚L?þìY ÀéÀíÀ_v&ß^Rõ–†ˆël90ò{·)A„Éáºòï<מ§MAy2ÏâþanûŸÃÍódºyë›®áo.ꢭößvKŽy=³8oíi¼ë•ýÜ|ó|ðÞCÔ7ÖmNzö*>ùî+¸qQ«N;ó{º¸`Ý~ïÚ�|â‹wð/Ï5Žù2=uÙ¬X{:o=Ý/Ë}ßßÉÚ“ÏŸ��¬v +;ÓXp”‚}ž?X �ƒbVk–ª_X•eýÙ§óÖÅø½<}ûcÜ=Òh†lVœq:o]oƒdè�§.ÞX­¼ìÕ/å_º€9µ¡ZrÌŸÝÍÅëÏ཯xž¿ýòÏøÇ­%ŽGO§î5qÓ»Ïå‚•¸+ÉÒÝÞÆé+–qÃåkøä¿ÝÁæ¦V3)N?ë ÞzZ¸Tøów>Ì탊YK–ó–K{7eŠže+y˲ðSù‰}|òÎ^F㪧åZ;Þ¾·‚ '(� jÌÚÀr´ïOj T¥5*3Ùzmß«ˆãp‹•6š�£Þ±8  ì(lW£ü %?ô™R�G‰HÉ Â5¦ªŽfu×¶�VµÎacãHÎ×Dã*—J ZšƒYE†4Y|R©Ã^øãÛA™T.ì»§ƒŠ¸Ó–RxÚ0âô—-SLLídÎЀɼ¿š8`q#õ§6`qœ¿\&}ÀÂ[³k¤{ûmÎ]‰i[ >x«–¡ ò¿¾�`áËæ¬$µy3%ÖÓh¥©Jcƒ |ŒíˆÛ” Â$Ý×ÏN³ŒÕ Òk6ðggìà#O_øÃ²ÝÁ�ï|Ÿ]—ÇVŒöñý_<ÍíÛÓ[†ÖÎY\¸þ Þ~n³²]¼áͯ¢]—ïšÒƒ¡Ê.ä¿÷¥¼}ž…Föïä[¿ÚÉÃû i›îžÙ\}ñ\· CfÖR>ö/¡÷ã?å–ÁñÔÓW—O)¾kP=g�Ïï¯Ï£t™ç÷ °×SŒŽGÕ¦³%]l eïØ9á¨×¾é7ùòe�d˜ò?½÷InÝÒOoIÑÑÝÃåç¯åMg´“ïZÂ_¼÷:ìø>ŸÝq|YÔZ]gðùw�Ë…-áýÇÀîgù�{¶óÐÁ2&Û«Wqã¥Kùè»_Ì×w�_c¡9†ƒÛ6óùÛ[è^¾š·¬nÁưoËÓ|û¹pµ°`ÿ! ñIœ¶kíøûÞ ‚ œ°¸Õ.R±H0Ùm£ýzùޤþäÖr2Þ(% •t�Šö“«Áï|á~~xðü>¥æð’Õ‘µ�ñÙ¼{`ü©£D÷†Kù\$ÜÏñgÿx_éMöæy~ôÀ&nºæÜrý"º²syÿ›Ïæ'Ÿ~ˆ'Žs�—¿â^Å¢éß|¿ñ¯y&aýóÇžáK÷màkr o]7áÀpàé�üÍÓŠU×.äM‘x³÷ÉÇø›Ûj—i¼ÖŽ·ï­  ŠJ. ]'àníçä6ð\ìTºªl¼âRmÙ8oí¶6oÓ¾Z�ëRRiü )I¤£Ø$ñx¯Œ�ÊTö“Ö.ãêUáŠRÝi›¹-)ZÒá:óYºÓaß<íáZiÚR6ÝJ³a–b´=C``ÔÕìõ8X (xT›$É´x5­"ãÇ‘<¶mã{.N*]YÑIYciÉ-À(°×Ó”|�q‹,în§Õ±À†Rà00\ íØheÓ¹~ ”<ö•Ï ”é/¸µ…ï¹Ø¶]µŠT£¥b)ëG=¦°Xi�åÌÃ?íê°–…ªóe±ÊEtzÓ²d|aILkÝY@•F0m³ N]U>cYX¾‹vÒ8ÛîBù&�0*Ž–·)A„I¢ó…¯=ÀerWµ+Tª�«¯½š«^v9ûv÷rÏæ½<°­—_m;ÀÖáI¾u·zxûU‹hW€)ð½[îåýõn"4;¼�Ï\°˜¿_—ÆjYÊï^ÔÁ÷õ�Jsæ‚<ƒE'÷ܵ‘GêÅ¡ñó•Ÿnã�Ö¬e®²Xqú"–ü°&¾ÏtÖ…¡ò3hwsñâ}üÕÇïå‡��ó�Êpñ+/ã·çDËzvñ½'KÇÆzšÅ[_¾’¹ 0£ÜòÍ;ùjoQÀxl¼ã.>}æ |jMŠÌâ3yçé�ó'O¾Ð Ëé”Mf*§Áü@$',³ˆÎm ½ïõ!þó–'ª„›˜âž�üÙ�—sÏPç•Õô0­×Úqô½A8 HºMã}Nƒê­=Šž[?_�´8oí¶ñJVÉ­â6sÆ¥dŒö+ˉ{¾OÊ�ë-WmÃñ5öÛòÝiXÔæÐ“Ud�ð>$CHáº%_E<,Òi‹¶|–¬Å|q )+ì[Á-3Xªnk¼[ÕØ±TÍ8’‘uŒŸœ§w±ä1ßs‰Ã×u¥Ó ]fµ†‹, ”ú<›\©HK6M*›¯LчÁB(Ü ]¬x¹ó À¶íJ’û•öœ,ŽW"m|h2Ž˜¦âM%`މïb¢mk&´xqû‰²Ãp»:›Uª§“Ô¡ý™UéJû( ÚIcyÅ:% Jk”vÅmJa ”÷nâm;‡Þt¿FYJ¥˜¿x 7,^ ׄo7úà—[öpç¦íüè©>½Œw,çÚ¹‘X0øß|²ÜX,0#Üöë=|üÌå´(› ë3çgƒôNF]0en»éÜvS(.c»•÷ö±%€¹X�m,P°}¦êªaäÉ'¸iÿQ|VŠl¾•ÕËóÚ+Ïá]gv�U€qùåOäûÑ�!ìÙËø�Å6 ú¶òåMMD$3Ä-÷ïæ/W/§E广ì¹džÜ=)ÿïF8 Îå§ÿxîÔ }|âãßáïöŽõ4µd!/Ê…¯�ü};øñÞFçÖ°ã¡-<ðš\=Ñ«³#d&¯µ£þ½A8™ð]2ÆŸ’º|œ „og§½;NPÂ'[i'Ù&€ï…¢‰òË�ÿÊ!К”eðtøû—² »*ݶ,‚è-@θ,liaQkè ¥u€«¡à†¿æ£î˜p‘Õ>%?üœul²ŽÍ‚ØÑRâU½0áZ߆±ø5:@Ñ-Z¬4™” HÊFé`¬"YmJáQ>øýOÏóÅå+xÓŧñªõ 9«3…ù{(eÓ=w>×Í�Ïu/>ŸO äGw=ħ~öÛjž¨Û—ÌfeTÎÝÑË£L îÜÏV½œ³mH-èá êd4CûõdýÊñ²W îªl‹T?–é¬ 4Olé¥Nˆ�#Æž?ÿçógP KU»ê]桟ÞÎïü¬ŸcµHxë²yÑÊI0ú\/'0¯ÜÞËSz9ØŠî%sXjífËq %tÏï"2d¢´§¯iŸÌÈ9¨¹za½E^83w­Mÿ÷Vá”!DŠžOÆ¢Ê'ki|;;.­¤-œTšáÀ&¥'·RRU“v;%éúã¤Ò”´:l èzäÒ©qõ'3vÿ�yLàᑪ5®ç£¢›ÄXÐñ½2ÊNa�XVÐ:À²lÜø·Ò÷H§C˰,·\"mlPa™’yY‘²L¥î1|”�¶Â~ùÑg Ódu&í–°ñÐ�ÛÁÖ»"œ¤"ÑEG+[ÅÇ;Ò]Y›vG“·¼(Àr*�&[ ïÓNŽ¢y+ ÝÑt¥ nYSÔVX·*m§ð¢vt�×’Ö:œË†#£¹xSÇ×,L×��ÅYZ»pzñ–Ç $î,Ç>ØúÑ­g×o³ª�ä MUq›A8ö?·•xn+ÿðß6=óæpѪù\¼j>¯šÇYÝ™ŠP‘n›Ík_õ ^~}-«1 IDATþÓ¼ï_îæÖ¾ø²Å¢î¶Hô1ìëj*„‡‡Ù£ál¬\+ sÀT­C”йlekf·1·5MKʱ-ËÂIµ°~²¯'¦³.㱫¯0­«%)¥*¢Ú„ÍûE6o~–/ÿô¾ºeô˜ 7 XØÓ†}/üÎ…üîÕíÍÝãìnrñnW‹-^�x£‡öðŸwîbÿT ]àþ¡d‹9³ZâÛ-öm?È ³³ßÀÂ#èð„Ìàµ6ß[A„S†À«X ÄJ¼�E;ð(9©DžêxÏ(RÊTmRQ<šÊç„pã ן¢ëUîßâ~¤Tµ{�vK(Æ[ÞZã•K(ßÇbc™1‘¦:@qœV.•Øu²ÌÊgèH[”µ"©29'®ߥ£-üµÏ1Æ`¡ÌaWóüáåRµ{:åàz¡h‹8Z¬T‘8ci~tO4ö+^ö=,'UI5ŠŽ´f~Îf~{Š­)Z8<2ŠeÙtä³t´æð°ð}�?²ÆIÛ,h ëÌ(ÍÎa�¢gš¶�$e«I[O¼ÚTMÐbcYàíÃ~æG‘åŒ5fA£@ùzáE¡xSÌ£ Lk õÖ^P£EœÃi‚Î4jø ÖžЉ@HÊŒRáÊSÖ(Xs1`Tà‹Û”  & o_/·íëå¶{ùY=\zær^wÙZ^½4OZA~þüó;‡ÙöÙ‡Øý<´åÓ•Xf#EoâÀÀcăðEFšö¬‚áÉ>aÛ,]Ÿxíz®™›ž´¨1óuÅx OjíõÉ£‡öðå»÷Ô!Tž+®<“KÛè¾õÅoñ‡›¸Ò5íùxÅ+E×êõüŸÕ“/me3tÚ4ºÏ™z¤—oÜþ›^ "Ñ–KUî^&\¹ËøŒ”ÍW›šB_fìZ›þï­ ©Hr¥&ËI…®;Ñ6å¤*ÿ·ãô”2d-�eÛä,CÊžšå¦¡±±(¸–“ -rjÚNö'°ÓØ„¢‡å–Ðw#o,lJ¥Ÿq¬œ±};“#(W/)>j9ô‡DÁ 8œ_{ÌJ[täÃ Çø8cÖ?‡‹ŒFLÁ Ø?êÑ;\¦?pðL€¸XŽC©X-Î$'›H„jD¼ŠSò\¸FánÕÜ´dÒÌkÍ0§Õ®7N:‹å‡í—K|'Eì&e|7º'°iIÛÌË:Å@¡Œ¯^@/n÷Ó8Áøþx�©ŒÃ. ¢[ºŽg’«M%–wRŒ\~Q”lÀRÑñ0ƒ*iùÕc˜•W¡]Hþ‘;)\°Ójkq5ªP ÷ËÍèyW€kß㌾ø´pe*eªêÛF}©éŸ¸M ‚ L7†ÂáƒÜqïAî¸ï1þåò«¸é†,² ·t=´~ï~$ ”¥*ÿÛǽ騋&0Ñãmäò39,–_ò2~ôÖå̳c:¸—Ÿ=¹Ÿ§úFè/ø”�h<{tãzÎióm:ëJ�\ÁgšÐ#½|íÇ5!ß:ÜÊ�o[F—ÕÊë_ßÞzwOd’qP‰)Kƒ<;<…ßj”Ñ™P?ŽK�}¿µž„À1ƒýž±km¾·‚ § –öÃEvüØ1&$~ho¶Í—–Öæäæåù\fJmÜ€}# %m5l«v€¡ÆÒ~%ŸMãeÌk…›°a,ÜÁr‘]%œè�Øü¶ ëz4­¹„€“Îpp¸È}%v T 3 aãy¬$¹^Z•(¯Œö=í¡­TÕ|8•zª…¶VÛТ<¶fhq`Ø À¥-mƒe3\ (”Â9Ë;„éÀp”Ö–¶YØ ý#åŸCåêùŽ…›QmÑ’è�‰iµç£ZÞX¾*„µ¯‘Lý“ÍâÍ·ÉØ‚î^Ž^r5m¿º·ÓC÷t‚ea:Lj �^p&׎uhî|ƒiIk÷Ú*Š•Ssãaù®¸M ‚ Ì$ÆeÓ=wò‘óøÊEy,•áÅgÌ!õÈ.\ X[b<—IMüìªRäb{^ãS˜¤«·ê8�¿yý²Hl)rÏ~»n說ÞCgÎæ 4\¦³®c‹a÷/ïãÓ-àSkÒ8³×ò·¿¹�«¿½gòÆLÍPcïO¦ÊhÅJE³óþ;¸zÜrí'®?¶êZ&e7ÿ~+‡–´š1ýæh]k‚ ÂÔ0 ž�ßÇv¬HD¨MW™sò)浦˜ßê�w[Þx�!Uc&\H�}õÊ Gõ±•L´ŸÜ&cå4Gœ¿vžVUéq;×'ð}†�²Qd"W¯¥m)ZÓcwŲËp9`×@©œ¸¹f9òfã¨Ð@„pµíã8¾n- 'V ?ªß2Ùmi‹¼£È¥ÓºDÁ7ZSpvô8ì†ó=+mXÖ•¯8É2mi‹LÍiŒÛö}Ÿ–¨ïqš„Æd­²Y(•(¸ìñxnÀep4›ZrØ–ÅܼMg>Mk6KÖ ‰Ê—uu»ãûP�6Ù÷ƒÍïAÕÈ,WEîRµÉå™=.¦}^¥P(;�žµÓ1ÒyTb�sÝ1Ÿô^�)ŒUÔÜ©|ÌýJëhYq_ܧAšÐ¶rŸÏõÜ÷éw²õ½g0JϘŠ\Ú©üïuË^|Íp`OÅb¥eQ«&p×N/èæ´èWÊß×Ç3¬Bb±t^G€OóÌ3{Ù×äw¢kÕBÎlâ25}ux{7òçw¤l@Ù�üΛ/à’†+�j¼xΕM¦Ùk»“5s�LŒ8¼·�pUmEÇâ9,Ÿ™˜fÃÞƒC¸@Ñ1§ƒž&Ó¡rÝl˜3S=Zך ‚0b± ìùã\“*ñNÊÅq镼�_%Ö4nbRJÕÏã—ÇÕ�ìO¡05…ñ«ÃäcÀ+‘‰,{Z5tê¬ Ug\U[·HÁ ‰"§mňPð´[¬^Ö¾W©ËÑcýª­¿–Œ.�GØù£ÚjXGm?=(•J-Ó7R¦¯à1’nö –è.2è…yû†‹<¸ÀÞ��‚ËH©D_Á£o¤ÌáÑ2Æ-…ÖVuÎEÝóã—ë�£†‰ï0Œ/¤(ÕÐm*óÔ6LϺDY :À~ö.Ôsw vü {ë]¡ÒÇ@Ï:²On§*¾Î$é~è•?A¡>E7Ã9ëæszGŠ–5øãÕéÉÿ»µÚ¸vCOøNÂhž~~l jwÇóü"z£ïÌ[Î+æ5ûiIñ¢ ‹™ 'ÏmÞÃŽI%û꺱ƟšÍ»^º„¶ŠÊ?þge:ë:>xüŽ{ùbo8–ôܳøìuó©ëHl\†Jш­V–Ìj<¢Üi+¸¦íÈFì=¿‹»£•›R‹VòÚEÍo9TË|Þtå*.™›aüb¦ÇŽâ®<}GSKsi¾qÞîu+xQºññÊѺÖA„©‹~¹ˆ_.†Ai¿®�S(•Ù=Xäù�"…È":e«IýAH¿w°ÄîÁ"¿~Œ›X,HYveßkb}]6ªJL©'>”Ýp\–íTê¬ÍPô5û‡CQÄhŸ²çqx´ÌþáŨ•€Ê¶Î�•©Ì£“ÉáèreNãô˜xVP_øHæ­M‚xŬTØŽ.s dØ7\晃£<¾g€Ç÷ °óp�§÷ qp¤L!™ )óô¾!žé/Wòï,²o¸L¡DÉ­¶Âª�›Ú´Øs©Í-o*–,¦ZÀi ÜXƒƒdç ¥£ª»o;¥åYF®^ÏÈÕgQ\�Ã>¸­R¿Ò>¦e©þ¬ÃƒÉ†¨4lÌØg~V�‹ \ú.¼±ò'‚ ÔÇßýÿúd袬NÞñ»/çOWç'6Õ´[¸ê5×ðÑÓ¦´›o<<4¶ÒMy_}p(Œ½owóÎW¯fqƒ_—ôüu|ðÂVlÀxøú“�ƒbØÛ?Å÷W¬^1‡ºÞ)V+¯¼á¥üál—CÑï£ÊfÕ‹f¤®ãˆr/ŸûÎSẲXý’+ø³•udSdëþRxþTŽËÏšWµ\gŒÊÎãƒ×ŸÎÂ#5$ñöðÕûûñ `uóî7làÌFªŒÊó²ë¯âïox?üßoãÿ^œ?nD²ààNnߊb*³„?xÉlê5©üBÞÿŠe/ÈÅ.б�¨˜Õš“vT®5AaJD.Se£*¢Œ qš|ür1t¢´âè0}#¡øòü¡ö&üë-•ýçŠì: óoÜÝWÉÿä�ûFÜJŸ›ÍSò»âùå—±¼„'R&^*¼ž+R=Ë­ÉmÜŠ^tEU9¥ôÈÜ Ïëܲ%¤Ÿ{K/®jG/Ú@îáŸ3zõùÑ«ÍÉ݉»” Â$0#|ë¿ÁÕ ¯âÕ]vû">ú§o憧¶róc»yp÷»†Ê|ƒ“Î0»«“³V.æ7.:�—ÌIc)0ºÀß½—oNþüêö¸åÜkyÃ,Åìõ—só;2|øÖ§¸§/ZÎØÎræúõ|ì�çrQ0>Oþü~þ«îú×u;Ͼ§w²É_ÀyŽ¢cËøüU#¼ÿî^öû€•fùi«ø½W]Èo¯´¹÷[ÿï/½–-¶PÎ<^¶6Ë÷-EÆÓY×ñÅÐæù_¿\ÆW/iÅvºx÷›Ïç¶Ï<À¯«îÍ4�<±‹¾ËOgŽR,»ü%|þà]üõ{ÙY2`g8mÍjÞ÷š ù­î}|çñN^·¡5ÅàÅš�?»Ÿ¯žwï˜kѶêbnùã<ÿç{�sëö Ps/åm×]ÌŸ®]ÙÊ{žä-¼àùµÚòî×¼ˆƒGP‘îßɿݳ—CЇ¹éç;ù½·/§KÙ¬Å+øšº�¿ºkO;êէñ¾ë/âÍ=ƒÜÿl†‹W…¢èÔæËph €o ­KÎ;›·`ÿï\Îï.Ïá¨4«Î<“??óÌ ËêB_ÿö|ä—Ôþš¡íüÙ¿?Àì÷\Ì•«Î¿”›Ï{#ãô•í-tÅ«ð�gî¿“¸�æïjú¾ÿ)>þ‹Óù敳H[­¼ü ×sÍ«Ë ȶæèH)”ñyúžÛyÏÝ»XÚ=Ìw`«<¯ç[¸øÀ(Ï>ð3~ë§}øÓYׯ0㘷ßz??Xw ×·+2 Öów¯ØÎµ·î'ù~jô©Gøû-Ëùøš –ÓÁõ7¼š×¼QS.¨tŠŒÆä[_º“//{¯Ý`‘š¢Ž)ìâÿû·»èzï¼f¶ÍìUøü7ð9·D1ÀÉåèÊX•ŸùòÁ­¼ÿ‹òàÄnßbµÍçÍ/›De½çJü÷/"ñþïå#ëzøçóÚHÙ­\uݵ\õJƒëùh'œ/e\üá�|:ý¾»*X4¸÷nÈð–ü¢´‚ks`w­äï>¼’¿ð¶ó®þ„ï–�ε&‚ L‘:¢@Ƹ”U:L‡º@ÑÓÚ¦pxüj;! œfltXo²íx¿v; Æbñ$`Yvýq4j+Ú–JeJÀ@ìW«êqX–ÖotU½•6mT¥yð8ÔY£Á/ë�»vŽj(«4”Ê`Gç-n®ÞüFûe; ©DþFó^§MíC+Ù㨚«æ‡©ŠÂ\EÍë¤Ôîý‘`ãUÊY…¼ü ÁìîÚÂ=³ðfP#‡*ù•Ö(©�ûôŠFSçm‘2•¾‰Û” Âä)ÜÆGÿö\ù…øÒÆì.5Žùb´Ç¾ÝÏóµïßÁ5»™?ùåa©Žì|ŒßúÄ÷ùð=»y®¨AY´µ·±|v+ÝiƧ÷¹­|ú‹7sÍMϲsªÁSM™»¿óCÞöÿv°­d0€�Î0oVžNFûvóŸ7}�ë¾¹“FóÐOîâï6�DA|3,š×NOzê:Î0CÛøØ­;é7€²Y{õ¼YÍ‹˜`€ÿøâ�øèè‹~敲ÈfSd”¦Ï6þæ_nå�a¨-ù­òG0æò¾Í¼ë“·ð?ÙÆÆ¡£ •É2·³…2†âàA~ðã;¸æ“wðÍýÇaT]=ÌÍ_þoþá6ž�®¥H§Sd•¡Ô¿—/}íVnøñ~öŽºÑq‹\zjê�ÜÂGnzŠMSuMžO9‘0ãך ‚05OUŸÊ:ñÌ=ÌAP9ïÛ¶]%ÔTªÁªüØvßm;ÖS§OV•`P›ÏÔ)Éqhe¡õøz«Ò¯"ÆÄéIqF'ëª#ÚXFW„›Úz“bQ\6Ο¬»�R ñÉûk1Èk#Þ¯^*e•ª>—IŠ1qþD•2µmÖaÊ÷ÇŸ�TÏ;>cY«x-](­ öÝÍèÅç�YÀT¾ƒ¬èCà“Ù±‹ì¶Ã0ÿL® õüƒŒ¼h º½5*dÆÜ¡,ƒ.Ð~ïsèÅ¢J#ÐûÅÕíx«–Bʈ*íªP´Á�¿ëaìöÐEkxõ•>ÏzüûM,‚ Ô zz:YÞ•§+ç�Rßó8<4ÂÎCì+�Y«�aé‚.VtfÉÛ†b¡ÀÎÞ~¶ûÓân¤R9V-êfY[ [»ì?ØÏSû‹Œ7ØPd[[˜—Öôò묒8�u�ˆ8¹6Ö.šÅ‚–péÐÞý}ˆ—†°ýÓ‰¤¥Fü¹Ö‚£6_"Oã¬ol;a“l'„°ÆÊÔ¶¥Ù£‡ÈôïÀ.áw.ª‡]¬#V䯣•5fSφ„ÀRÇB§žåNR|IZØÄmUÚLô»ªž Æ1î|ÔésÃó“Ø×JaYZûX–SÿüA(îV쥔x¬„7Sü9™n�"{àY,¯PG-–7Ú\¼ñs�˜]÷0üâs›‹7qg=—ìÆ§H÷AiQŠòYk#ûžñF…«X¥ŸÜBnG ·ÛP:-&“‰š¸N“X–\EuZüjîå(í‘906â6%‚ ‚ ‚ F–ž°�/¬@]Q UâË$òO©�HPh(z¸l7rߪ:ˆDœH¦k¹CûW�P\wº½}2EÇ‹2µÂ͸LÕŸ­�!²�m!]œƒé®â#nS‚ ‚ ‚ ±ÀÓö$bÓXn�Î¥^5&¶Vѩ꾔�g?P¶²Ç¿€“ ì–&u>Ž´RdM€±œq磖 Å•4WêZDÚë!ýëíö(AVU#6*Ô8²¾QªZ‹Q‰ÖÝ„£‹R´¶u²æÌYlyê1²Ù<­íÑ¡ö�'ך CfðÚAÆ#â�  `Œáð¡CÌ[¸ß÷$ö†pêb ¾Ö(¥˜·p)÷õÒÒÖ>­–7r­ Â1`†¯mA¡Y*\aš1Æ µ¦T,�ÏçåaR¯‹\¾…rq­õ´\r­ ±g&®mAa<"Þ‚ L#Éo´0òR*(¥w/ä!O®5A8~˜Îk[A¨�¸M ‚ Ì$ZëÂqÃŒ>Ðɵ&Ç kAfoAf¹�„£ƒ\k‚ ‚ œÌˆÛ” Â4#o ab¦+æ� Çr] ‚ Ì by#‚0£ÈMì �;¡¡Zeéèn%}¬û#'èµæÓ7TÆØ9fÍj9…nÌ\†ú†(aÑÒÑEKj¦š‘k[A898uîAŽÇôyÒPîßÁÓÏìd÷�F=��ÊÓÞ3Ÿe§­aÕœ¬˜_Fxÿ“ßþðmÏ}óO¸p¦$…™ãh_k¦@ïö= Õ +êM;x IDAT,ìT†¶ÎÙÌž•Åž ÷�â uÞ‚7òï_~ëN•;3÷A>wãÿá§åù¼é¿ÄûΜ™�˵-‚ œ,œ*·‚ Ç„c£Ý ÛΗþýküà‘^ z|/”•aκkyçûÞÉ+Væ8Õ×é1–Î� ·'¨ Ç)ÍQ?gþ“|ùÿ‹ 5”¬,ÒmóYsÎżô¯âº ’«s¡ÛÁ±,´ã`©Sé»g.¦PÖÌ�[®mAádAÄA„åè?*”6ßÄûÿì&6�r ÏåÕ/»„ ËçÓ‘Uø#}ì|æ×üì'÷±uãøäûw2ôŸà·–Ëëè1äñîÄäèŸ7KXôœq æ�ÝRåú÷=϶�{Ùt÷-lºç|ýÜøÈ‡ßÂ…=Õ¶8éËÿ’_Ü÷W =Ê%—SsÍ,ÃÑ9rm ‚ '."Þ‚ Ì$GûYAïçGÿñmž…Ž ÞÇ|ú ,Oùhm0P uÍ«ùí·<À§ß÷¿øîÎ�ü×îà%%sOe*S³/Ïx'GÝm*Þq8ãuá“/o³`S ¥zp÷Üúþõkw²ýá¯óáôóןû#.ëJ\l~‰¢t»~\p´®9¹¶A„“oAN&Ê›ylscupÅ_ÉbSÄuk3yÐzï}Ï«Øü•]Ì_h1àÁÜLm>MñÀ³lzz{û xv–Î9K9sý䟦Ä�»8ä)ò³—°tVƒ� f”}Û÷r8P´Í[Á¢öjµHð̦§Ø¾€‚ÎÐ9w9gmXͼܑ«JÞÀN6mÚ®C£øéNŸ¾ž³Wt5Z?}›ûž~”G·ícDg™µ`5çlXIw“œ«¸ú‘^¶ì†ü\V-êÀ6%ö=ý�nëeDgéœçœ½ŠžFíéûŸÝÄ“Ïõ1bòÌ[½ž³WÌ"�Ë¡�;9P¶™µh9óòãýtŽdž�ÛÏö§·°}_?Ï"ÓÞÍ’Ug°fAë„1]NLàâ–KãÝ3 ¹ì-ã‹Ïàƒúo<¸ë'|òŸÖñ•¿|)=ÑtÇß“êbÙ²²5•éÜOù»?Õïðð^¶ôŽT¾Ãþþ'¹ïágÌ­áÊ+OgV<=Âî'cãÎ>FMž¹ËÖqÞº´L4© ×¶\Û‚ §"Þ‚ Ì æ¼æ}æà¯ø¿ˆlª�Îú NŸó¢I4PíÐÀÊd.ú#¾òb øx®Wå®aŸàŸû¾rÿ9 +¿ˆ—¼ãC|ø5« Ÿ|ž¸éÏùØ]£´^õ|ç/.«û`¦Ÿû.þ_c«ZÉ»¾ðϼ½=ªWðØ·?Ïg¿~?; :1ca[W¾íOùÀΤc*�yüÜûåÏò¹ïn䀛è¿JÑ}Ö«ùÀŸÿ—Ïû ¬œ'ÇÁ|Œ/}êS|õ±~üJQEfÞ%ÿ?{÷^U‘ÿqü}Î-é �„Þ‘*EA,¬Öꊂ»®}ýYvW×®+®‚bwmˆuÅ‚‚i¤÷éåÖ3¿?B I€äB àçõ<÷rΙ™3w&ÜùÞ™9Üò�û¹¸ù¾£®ÊÕU±Àâ÷¹ý¡ðuÉû5eâOñ^Ú¾ùyëœÆÍÿüƒKåÚú £þ9ŠÏ—ç°';ËKÝӮ䑻;1íá»øï–d=ý6w�\âý�¤žMË&¼ÌSoMaU^xßÖly©sÒEÜyÏÕô¬sô?NT¤¯efe²jõ ŠŠŠ¯0»f¤ap¹l’kÔ¢aƒ†ÔJ®UÁàëEãyä^?O¿|3]ö­˽“ÿ=ù83ƒ½ùPOÚÖöP°i.ãßǬm¿òò _Òùß—Ðd÷Ù•­«Ýùx¢ðXPT¸–qO~ÈäP/F>t:mk{)Ü2ŸÏßúˆ_·Íâ•ç¿à”—.Ý›_`o>ò4Ÿ­â­ß�¡W_Ài�¢É]ý+Ÿ¼û><µ�‹ à!:ªÄ½ETφì_Fqß˓ɌnBŸ«ÿÌY‘"oË2¦~1žoŒã‘G¼¼2ê*ZÛ&-]±”SOéFr�šeŽ…BAvìÜÁ‚…ó¨W§-šµ8lù'Db¯?sNÝi|´e¿L[ËðV-‹g6Ø»Þ\˵O0#¢º�¤íGÚ†£¢‰² èßÄc`mb'Î:«95bÛPÓËyûÑ瘰:Ht³~\;üBº5ŠÅŸ¾ŒÉŸ¼Ã“�¯£a¥+R}[}[Dä�KÁ‘ªtû+¤ç¯§yJ'V¹j1í÷¹KËjÊÅÃúòå#“ÈH{‡›¯™Aï~}éuêɜܮ1µ¢¾)¼|"ãäã¸Zð—þ�Í(Þ3‡V´ïÜ•&�aÜúE:?9�»ŸGªmˆ>©?}j}Ïg;~ãç¹ùôé¿ï’ð*&OÝ@؊┳zSg×½„VŒçÅñkñ»›2ôÉQÜÖ1 'ì`hD‹Ö]èÞ*†¿Üÿ?ÿ÷-¾ïÿwÎO9xùK>ååï¶ŠjÇM/<ÏÕMlÂŽ« ={¶!fø]|¼ù;Æ~s!].kTü¸ôÝ“€¶Lcz½[yãùA4²B8Æ@Ç.œÖÀÇ�;>cóÊYÌJL“ºv„uµû}¯þžï»ÜÊ›£.¦‘Þ•_gN­›Ïew~ÎÖU³™•þç]ùr¦~Âø5ˆíÌm/>ÁŸë88Ž�O¦÷é­y`ÄüœeÀ²)ùh�Èê¹€ß~šI¦ã¦íÕ�óä�ú8a§¸ð»pÆ€Ó¨}ýÍüwÇ\~]=”Ö­�ò"‹ ô�ÜÜ’kÔ$¿ Ÿp8H(" …0ÆP�WÈÙý2uÚdV­^É Í[V,¿ ì¥b¬téÇÇ[òÙ¼r5¹N˽K‹Ê¤YÝGÒö#oÃn\€³i2“ æ•w¯£}ŒÁ˜0¡@�ìiŸòéšÄuåŽgâ¢ZaÂФ9»v"åŽëy©Ðw„ ¾êÛо-""€‚7""UêP–MEšVR¯»yùÁõ?–e.gÒ¸åL–'žz-ÚÒ©ãIt=í4ºµoHB9ŸÉ­æ—òüÛýÉÊñP¿a�@pï±pØ¢m׉ùrE7°Ñ1¤Ø`Üíз6_|’Îì©sÈëu%¿ø-ÿ…Ÿ7†±b»sn¯¤]wdñ�“X‚˜žC¸ª�‹@‰ÌÂá1§\ÊÅ­¾ç•åiüðë^�Ê�Ã7AOžÊ¦0Äö¼˜ „ð—(?î¶ ~¡E5ê„`ˆbï¸ÑXõ8oø@ꅋسUP8„Õ²m£?g³o;[·‡1u­ˆëŠ}ò«ËyלK½°oßüZuäĨ/Øê/™Ÿ�³Ó(4ñ=.âœÿÞüÂ!H:ƒ‘—~Æ´1K²{!Š)®“HêÙ)"/?„ÁÂm…ð{ë> !š2â­IÜä6‹ –óHú#©"ý#,Þxoà&\ürÂáÛw¤Óºu[z÷ìÃ>#)©)µR*˜ûÁò·H©“‚MNV™ÆPcŸGƒ›½wQÝGÖö#nÖÁœB‹®W]FKW>ÿî+ý,˜5�c{Ú@úÕðؽ)³aêpÁŸ{ðæÂIäQ²­ˆúöµo‹ˆH±?ò³EDDŽK&dѰÿ_ygü¼òൠêÙŽúñ.æ³eÙo|ûÉëüý¯×qñ•÷òÜ7ËÉ)õlbËOÝMiwb}÷$êðû‹(4^¢, `ï–6'ö;“F.CþÜiÌÎ/ùa?È’_¦³Ù±Iê~=v/©r¶³tù\4ëІØrÆ©Mûka› +—®!XæŒRœí,_±�[5'ºt’ÆÐ ïõÜ{ç�\ß¿y™eXVt:45å<®9†„ ðã–ØQ"¢º*‘_TkÚ7§œüâHˆ-•Ÿ“κ > .šµnЧôE&L½ÓºÑ¬t@.Òz¶“ib=\V�Åïý‹ç¾šÏƼp‰«Â„üð ×µÚ5+ g>ÿ¹ÿ1>Y僨ÚtîI�†)$Æxq»ÝXÛ~å¿ß.ÃW&ÃFôëß’·_[ÎoSç�Û§/Iøÿ…_¶;ØuÎàÜ“<{—G˜Å«X Æ  í'*›JÃXp'y>>6!vM®ÀårQù±‡9ðŒˆÒgG\WûdYÁÌ‚{–ž¸íýü÷m{‰vÁ>S”¡ž�§%W¿ð.=þŠñßþÄÔùkغt&_-�ÉWŽ!©E_®½ýF.nA]yÁ`°xÜkv=i °°°- ³ëƒeYœÐ¬ßNü†„dp¹ýlZô7š�ö^ä™;™¬Y“…ƒMBƒ†Å›ú@¥ë>¶¨mØr{Ê~˜,ÑV]nwùe±l\v%Z�ú¶ú¶ˆÈœ‚7""U¨²{Þ¼1÷nÎ:ýbâ£jòÃü½?oßìTúvÄúì…|¾ôYîOý´ò%q'TüáßÛ„‹ï»‹‹î勌ÍÌKÛF¸U}l,üà%Æ­òc×;›ÇFÝËÙu]»6ê,ž2œ“Áø‰Åƒ–Ò;U48£'¾µœ…ó§1+÷ $X0åW2 ûõ§�]â1¶V4±1:•—/®uàABØO‘/xൢˆŽ*¾ß"Ÿ�0±Z¼ï䇃½k»Ïˆ¼®"ÊÏòµë©/~†²>üyä…L©ë¡žMˆ@ÀC“Þ—s_¿+y ”Íê´ß˜5s:ß}÷ KWýÈ¿ÌÁýÊ£œ_÷è®Ä®Ìž7»Y€ƒCÆÒR¸}‰M‡“Ôø ,ËÚu~�U¿ï¤MGÓfдÌ4™’¹8'c&“—†ÀЦÓÉ­pïºbß«J¤RÙº�¨íWQ.ÑVþ1eÚœ)*¤È1ûK¡,õí?lß‘búm,"R�Ò}«ØìÌaP÷‘ì ´h_Ÿõ¡é¬Ê›AØ íçê™kÓøùãùb~f9{-”Ì(LÐJ¦AJñ“NŠü¾âœÂ˜=o;n:\:Œ>ÉŠŠŠðû}ü~;6o¡`#’ÔžœÝÑ …ó™:'ã_ÄäY8®¦œÓ¯Ù¾ WmÖucbËÆuääSx ×Á7vmÔua¶nÚVn˜P€@èàýƒ:Ôºª,»)É6à°3#«Ü{ ­_ÍÚÒÍã�ëÙà„üø‹ ( ziØá .ù0oÿ÷Y.mêÆäÍ竟7¸½UÁÐîi Åsn †- Àko¢å)×°sÕëxÜOšß`×èÉŸºWt6C%ê>’¶_UmxO[ ³cÇŽrËâ¤obK¸œûMS}[}[Dä�MÁ‘ªd*÷ÖõI¦ÎœÌ¼åÓ™ž=†ùùãØá_MÚ²Ùlú=—뺽°ŸëC,þèq}á F�þŠåþçe²—±hS,/ ÖÁ6€ã£° x`›œ‹.u]pß}»¨xƒÎr_Éôîß™Š˜7s!™ g03Ûài{”:—$:vjŠ ‡-³cm°¼ôv.û�…›ò W¤­tèØÛæ-`]¨ô9aV¾g<�³ÿö™»÷�¨È{VúœC©«Hò³êмY<6aÖþ¾Œl§ô5>ü4�­N©t#­g&kÒ~å»ëðï9Ïà„‚}EøÜ­èsJ Y™98mçU¥yïÞ°ll6Î}�w&í{=Íöõ¿R�³…yãš1÷“¦ü0¶.íêÏ¥Uç^d¤Ç“�rúþïå@ù:E¬øìižš˜ŽcÅrÒUWÒ#ú éDR÷‘´ýªjÃVZ4‹ÇÆaÓâd•N×8lœ7��áý\¯¾­¾-""e(x#"R¥*ú©×0Ñ<¾z[?i˲IÌ›¹ŒUéiäd�6sË&òûuùóù71{þ¬rÒˆåô!ƒhá…àÚOyø3g{ Ü¼é³yë‰×™–g°SúpÁi±X°S¨WÇB,O[BQÉëBÛùuô3ŒÏK%ÉãË&ÛWz”á�Ø­§ÅAAÚ >š2›,ã夳zQ§œOú�\À)qáu_0êÓUûæ‡!°áž~øQn~;¯,.ÿ^J§Ù¬ÿ@:D[„×N`Ì7ð—8Ú6™÷¿ÛH˜(:ö<•d+’×®R]E�n:ö<�$ÛàŸûÿ]�ËÞ…7A¶O�—~. Î]vØHêÙÉü…ü'Oüë%>XQX"¯]/ÿ*~[´c¹iÜ´>v…ÛzU9xÞÁ` °m›k¿`ÇúoèØs$Æ?�6§œÅÙW>µçuæe§Q›³Ù¶¹ˆÕË·ÒªûS¸—rò å±iá÷¼öÈÍÜ‚¶_emxo[ ¤}ÉG‹òö¹‡Àæïxý³Õ8v鶪¾­¾-""û£=oDDªPe>ΦÔJåÿ|€»}·cŒÁëñâr¹ †[ ž p[€@0ÈÂ…óËIÛ`7¿îÙÄÏüĦYoó×¹ŸR¯EkZ7N%!ÚÆñå±}ãJ–¬L'? v�NŒxl$Ýb(þVÖ®ÃgŸÌ›¿ÿÆÖ¯žâ΢�ô=!ŽÀÎuÌŸ6�´`{æT&Ž|’©E 7ö B]ÚЭgÛ½°Æuáìî‰Lùñ>û)„‰éÎ9=“)w÷‡”þÜsÛ,n|j Þº‡kæ÷¡ß)M¨å�±vS¦,`“ÏC£óo㚎LEæï×=�»o˜Å-£æ0û•»>³'=ÚÔ•µšScmÔè2œÛή 8ûr•­ÝR?„ºJˆ$? ѧeDç<7gŸþßH�z*ík»ÉY;Ÿé }œrç0Z�~™ï K¥A=[õÎå†A¹ã㥼ýבüÖ£;§´¨C¢Ç¡(k‹~ý…ÙCxæ/}kîZ„tôT$ïâ=o,Ünõ[]FÖ–™Ì™ü ]z�ËÂß±rÑO{ε,›‚p=ºö¾žž¾—·ŽS^ 2gôM\úv‰…Páù¹¹ŠÛ—åIåÔ¡÷òȰ“H ÷Y†RÞP>⺯lÛ¯²6lˆ:uÃ:Mçßó×3î¡ÛYÝ·''Õ�¦hÛ2¦O��¯Û ,ú”ï2ŒSÁß•êÛȾ-""ż©J•øÄ›¶0�† ›PP�G8¦qã¦x=Qäçå³nýRSkãr¹Ù¶-½ü´Cuú=Ä{mûðÉŸó¿é‹Ø°|.[–—8Dz‰­Ýš¾g^À•CΦ]l€@xobuÞÏÛŸà‰�ç±äûXò=Xv u;âɆÑ-ÉG�+:±ø­4V|;–çÒóïîmK<ö7šSúŸNò¤ÿ±3h“Ø«?§Ç™òËv¨=àaÞJý„—Æ|ÊÏ &òÞî�š-›˜ÔœÃuÜ|Akbƒ¡ŠUgØÐä¢òzÊ»¼øÚWÌœûͰ°cêÒõÒüuøÔ'@‰ýR÷:؈¯ÄñHëªu„ùS‡‹þñ"±o¼Ê[ßÏgù´‰,·£¨Ù²;WþëF®ê´’ÇG諭’éDRÏÆK‡^dTí×øÏÇ“Yôó—,ž¼»PvlN>ÿ:nºþm°Š»á¥ŽrqDDŽmÆÇ!³zÙbš·j[ák_;šë†ß@QQ!™™™¤§§³tÙ|>�—>gœAjjmbbbyý�1Œqã~Ó²lž(/n—¡ c [3ó(ô‡±¢¨Y»õ“½˜P€ ¿¼æ6î¨<¡,Ö¯ßFžErý&4L„€ÏGȱpEÅá ç’í�¢F¢‹`��’{�ZîXbc=X€ RXtà͆mwÞ(ÁìÍlØšM‘ñ��Ò€Fµã°ƒ>ü� nö–ÛET”MAú&6ïÌ'U“†�ë’hðûK îÜ1ÄÅz±L€¢¼"Êî£ê&*>�mæâÛ³qh„uq~€åÂ�Çm(( è�'Þ&è÷È�Ìÿ]ö4SÃÍþê‹ü¥‰ëëÙÂå�Áë…¢[Øœ‘CaØELb* ¤cüþJ îÖ¬XJ‹6íq¹\ض½çÉN•I_{ü©'xúÉç((ÌDz¬]yþòwÖ.þ�»ÿ•Ö]nQQÑÜù×ÛøÛ}âv—÷]—›è„8Üû+¾18N¸x‘`�°³ŸJòÄãÇOQ~É~iÝW²íWY,7Þè(ÜÆúÍ;)$ŽÚ�SÇÄç㎋Çk‚…¹ø÷·{ÙDÕ·�ó¾-""{5¾õvÇk4óFD¤šHß¶¯7 ¯7Ф¤dš5kA·n=ö{î�'H (H°ãjÒ0¾Vq(ã)Êàj‡�¿€�MÝ&Í©‡Á8~ ÷~•öç¶\ĸCø ‚eR0¡B r+tÛÅ9†üøB~,o2�šÕ*ž¦oùOdßà}Á•�J“ÄÚX88þ|ŠÊ;=TDAn¹GvŸ€??Ù’GVWægüÙlܰ‘-9±´éÒ‚dÛÂöçQ°ëÄÀª¬�݈Ƶ]eR­|=Â�BŠ`ÅÖ¤QÓ”]×LQ^ùuY�%%&‘••IÍšµöùy·³ž¦ÛYOïó³ÜÜbcãp¹ÊÖc±¾¼œý«„`!ùe»‘×}%Û~•µaÀ„å��@ƒ&IÅåw (ôäçp ßD‡åþÔ·÷SŽã«o‹ˆü(x#"R…*3[$==�n¼î°§mÊݧ£B.½TdŸã‡c8Pž‘¤éTæyÄgrDê*´þ þvÇ86Z ¹ðïÏp{—Ľ�œö­eüû?²Ý±I8¥']bößF"©çâvT}\‘ú=ïOçóÒË/’™™‰1ïäaL™¿ƒ!9¹&ƒ. –uÔ÷ûˆ´î+Õö«² ,툓Uß.[œã¯o‹ˆH1oDDª’©øÇú÷Þy¿RIçådW¶4rŒs·¾ŒÛΙÎýÿÛÄ—�ÞÌònÝ9¹q®ü­,ž5ƒ[ýXɧqÓõ§“`œ£t8¢*Ð×Z4kÎßîË:øÃ6�1ø|…{öÉ©JêÛ""r0 ÞˆˆT ÆÈA91tûë˼Ôt £?™Êâ_¾a©°°¼É´î;„7^N÷ä A}‘^F($?OÁ©†Ô·EDä ¼9Ì´I£TC(M‡?ßÇØ¡÷ãÛ¹�íy~Œ7�”ÔZÄÛü>ÿ11¸;ýD}MŽêÛ""r` ÞˆˆTÛv‡±íƒ/Ñ©¸0!_!XQñ¤F'ï»Q”C¤Û;)ŽãTIP_“ãƒú¶ˆˆìŸ~ËŠˆT‘è˜X|…G»r3Žƒã8ÇÆ¾¢¢câ{ºêkr¼QߑҼ9ŒvO·,‹ÄäšdeîÀ‰ôiO"ÇÇqÈܱƒÄäšûô“H©¯‰T‡»o‹ˆHù¼9Ì,˶mbã≉O`Å’…äde‡ŽvÑîw¨ IDATDޏp8DNV&+–,$6!�ظxlÛ>l{Þ¨¯‰UÙ·ED¤,íy#"Rv*k¥ÔÁëñ²#} ×¯Æ ‡�vÑDŽ(Ûå">>�†Mš“�”|Øwêk"GGU÷mÙ—‚7""‡Ùî¯.— €Ä5‰O¬�1Å;ìþSäxWr …mÛØ¶�Ë岬Ãú´)õ5‘#«ªû¶ˆˆ”¥à�ˆH(9¨´m»xÓI $åj÷o÷Àîpϼõ5‘£¡*û¶ˆˆìKÁ‘*Rò›É’h5°”?Š’í¾*72U_9²ŽTß‘½¼©B%?ÔîHê®üщ6¯¾&rä©�‰ˆ9 Þˆˆ!ú�+rd¨¯‰ˆˆÈñF� ©Æö™yw´Ê!""""""""åÐÌ‘jLÁ‘jLÁ‘£,??Ÿ%K—’ŸŸ_昂7""""""""GÙºõ…¬[¿¡Ì1oDDDDDDDDŽ2Çqöù³$oDDDDDDDDª1÷ÁO‘êËGæ–� ©uIò¾”M°€ìÜž„Ä{-ðe²eg!Æ�@í:Ix_V‡YÕÕIå‹r¬Ô™ˆˆˆˆˆˆTgÇÎÌ›`+æÍaÎÜ4Ö癃Ÿ_¸™ßçÎaμe¤û«¾xG…ÿ[ni݈FMzò÷9ÁÓfáBÆ^Ó•ú‰ ÔJ©Ibí¿0ÁþoFrB£F4éõ8sSVU¢*ê$Ò¢L¼•6ÇB�‰ˆˆˆˆˆHµvÄgÞlظž3¦³3s'ÆRSkÓ£Ûé4lØè€×™ŒñÜÔc$“‚u¹~âzÆ 8ð”ŠÐÒW¸´Û,±ºñÌ’iÜ}‚ëpÞÆq*Ìï/^ËÍïÌ%èJ¥ÓÀ~´«u2©6`¹p»\„]6–u´Ë)""""""òÇqDƒ7¿L›BFÆvÎûÓÄÄÄPP˜Ï·¿¡QÃ&tïÖãHGJ3;˜>e1ã¢é�ó먾Äì>6èrƒÍÒ‰ˆˆˆˆˆˆü!±eS6®gë¶­\xÁ bbö„ˆ‹�ãâ ³víj6oÙ|¤Š#åqrÉÉu7-Úµ&úh—GDDDDDDDŽÜÌ›3¦Ó·Ï™äæfƒ×�……ùtïÖ�™3§3xÐ¥G¤<Æ·�ųf³xm:¹~›ØZ hur7º´¨qÀJ ç­gÞ´,^ŸA^8†Ô¦èÞ»+MÊÆÁLÖjæ¯Î‚Ħtl•Bpý4¾þ~;Neðe§R»¢Ë�ÂÙ¬œþÓ—l&×$Ш}OÎ<ý’*ri…ÊkÈY›ÆªŒ5lÊ7€CþÆEÌ™³ÛU‹'5#)g óWgb¢ê񾀠Äí*»É.þ9 Å÷è6ù¬ŸùSÒÖ‘Ž%µygÎèÛ™úˆU¦NG�”v°÷©Væ*ÒÖfcbЮ]½½³‘vs2Y½` Y&–úíÚQ¿Ì ‡÷Þ#m»""""""rŒJ¹öi“2ü9“2ü9S•^|éy³cÇv³|ùb³mÛf“››mrs³ÍÖ­›ÌÒ¥‹ÌÆ�ëÌ“O=±ßë�ͯš~QìºæúïýÍ/8çAÓÎ�ÁÓÍ<³2T"¡lóÛËW˜NÉnc�¡äËŠ1�ûÝk¾\(›`x»™òÔ`Ó6Ñ.u�eìĶæ’g§™ξ—ø>bâ-Œ÷Œ—ÌÒ�™Ó-Wã[ÍÏådQžÀª�Ìõ'×0¶U²œ.“Üy¤ùtÙ834Á2¸Z˜»¦—J°Råõ™/¯L,[`¬ø!æ3Ÿ1¾O/51ÆÕò3£DV¾¯þb’-Œ·× fÕ–Iæá¾u�ÇÚ7¿¨&˜Q K�R�ìÇ�ß'Çd¾}ž‰ã9é1³0TNÙï™ ¢1¸;˜‡÷¦ûùP“PN�E|ï‘¶]©öÒ.Úó2Ƙ’ñš#öE}~~>EE…bÛ6~¿¿ß�ß_„Ëå"/?·ŠKaÈ?’óoû�ôØ6\ôÀ­\Ú£%©Ñ!²×Íá«×FñþOÏpùÅ1ü2óQºìÞÙäðóýøÓ³iø;2äñûvfj:Ûùý‡7xòÙñŒ»g ›ƒS˜tÿI{–YÑÑDYà/XÊ«÷¿Çâš½¸ìòöÔJ<•ÚY°æÿ�¿Æëi~bÛ^ʃ�Ü@ÿ– ø6Îá‹QO0bÈ"š—÷à­J—×ÃIÃGñzïML|òa>]cÑîª'¹£w¶§�ðŒkËãÅc�ÉMãÅ«žàSß…üã­ó8¹A4ùkfì?Ÿgâú¯¸ç†QôŸ~/m\‘–ñëäù}ª¬ˆî=¶+""""""Ǽo>üðC>üðà %4tèP.¿üòý¯‘Tƒmé[qÙyy¹x<Å�`0ˆ1†M›6R;µN%Љ~ø`鎇.~ƸÚ²÷Tç2øŠshЭ7/nšÈ×iÑ¥kqõç=Ëm/.¤ÈÓŽÛ?ŸÂó}k°{ÅS—gsîÉ×ÒuÐÛÌxâÞ¿òF4Ü5âw¹qá•óq‹›ùnÁ¿8=©¢k¥ ™Ÿ?ÍË }�8€g¾ù€‘Ív•¶sWzŸÓ›zýOã¾|¥¤Iy÷ù Ã{­`ç�òé›ú§_Áˆu÷\·ß§­Û66Zø.ÿí÷<Ó'ßNÛ¨ÝÏæìf9œxΫ¬Ÿ?�o7ÜM›fö!Ôiäur@|Ÿ Y•Hª""»÷ÈÚ®ˆˆˆˆˆˆû8¯`È�! 2ä ‰,ppæ™ýùâË DGo²{€ËåæË¯¾æœ³V´Ü‘qòÈÌ b°ðx½” £Ätåïóò)Ø>“Gö ~Ì|ï}–!î¬{x O�R×Y¤þé®?ɃɟÌ_nÆÙsÈÂ*Ζ¾ÜO� nŠ˜úõ$rŒEÂYÃÚ¬T4"êD®¿íO”MòÊ{ŒÝ”«¾±Dà¦X\÷>œmAx#k7„±Œ‘ÖÉAÒûTYÞ{DmWDDDDDDŽ]r°Î�!C¸HMM%&&†WǼÆÖ­éx<^</[¶nåµ7Þ n�:¤¤Ôª\é+ˮ˩§5Ãm˜õøn=‰Y¡}Nq¹JÂë™9k3aÜ´ëÕƒZå�ë]-éѽ..`þÌùJ÷t¡oϤ²î ¯eñ’| nZžÜ‘ørNIèr'–^Òt8Ê+º Ý;G•=àI&9ÁSHa‘9´2FZ'ÉûTY‘Þ{$mWDDDDDDŽ úŠ~wð¦ôªŠÎÌYüû"æ/˜Ë ×ÝÀÖmé|õÕ—|9á+° YÓfÜ|ã­Ô«W�ï˜H§N'ѦuÛn¥"|~û[&Å{µØ¥Ž†òFd×Ò£ ‰´Œ&Â:© rß§ÃíÞŸJ·]9.TjsŒÁƒ/²©HààÛ‰ßðçÁ—°uë&233ðx¼¸Ýî=K<Âá0¡Pˆ@ÀOJJ]4ˆ/'|Áˆá×G¬e�É'+;øq:á�d:€+‘‰¥†²îTº ù¯ ù¦h‹¦ýÈ'ðÑ¿dîüw¹íÜ ¼s¾æºf6Xq$Ä[€‡î�Nçûëž�±» Ã^ù˜ù¥"QV<­Z»ÁŠ&&Ú ¾"†²ËyLAùáÒ×WQy§HËi�T5'ŒSÑ,õý©LÛ‘ãB¥w6­hÐÀÃÒeK)**`õêe¸Ýž]�÷žÙ0Æ8{8ÙÙ™4kÖ’´…ie‹mI«†6¬ò³à·…/íÎþ·6 ²è—d9àjÔžv5ö?<¶bêÒqÀ•tp%w=8‰Û{�ËËKḋ˹öÁ¶¸ÜMiÑÄ�µ*Äú5ë QïùV‚U‹Žç ¦ãþއëP¯¶ ÂlÝ´…0uʼYáµ+)=q‡ª*ïáiíëä�XX»f™P�P9AšðŽíì¨è®Ï‡ñý9hÛ�0]©^ªôëy˲ÈËË#33ƒÂÂ|rs³ÉÉÉ&;;³Ä+‹œœ,rs³)((`çÎ Ë&æ9™ Ïk‚‹0kÞ‘϶íªƒ³ñ#žxs9!Üœpñ`ºìmeÑ”Ïy÷«E”“V­Þ î_‡í[·?åǪMÏ3Úá&Ìډ߰8XnŽl™ý-¿¬Ì: ›0«fÌ"½Lp ÌÊ~`U™5ZG©¼•i#­“C‡Û'#�Œ2�!‡m“dQEóŒôÞ#i»""""""r\¨òµ 4dáÂ…Ô¨Q“¤¤š$&&‘��¸Ï+1±II5IN®IZZM›4-'¥(zÜõ0çÕ¶q¶}Ê�ÞÉ'KsK RƒlŸ=†kÎÉéWÃKùç]§íY`ålÇ-ç fØÐxæ·<Ê„Š3ù×m8–‡–mšïš¹à¢Ý_n o¢Eè÷QÜñÜ<òK_¶d4×�½Ûvåži¾C¯4bèuá9Ô² þ)£xvjö>åõ¯|‹^JÃq•žUt´Ê[‘–1Ò:94ž–m9Á ÎŽølJÎ>y×~À]ONÇqW4ÏÈî=²¶+""""""ǃJ/›ª¬o¸‰›o½ �§b‹CB¡£_Sî1»Ñ_xsÜ.ü8Ófÿ›Ë;¼I£N]éÔ<•˜p.›—Íaî² |ÆÂÓàlžü|4ƒëîTÛM¯æÑ‘cøâ ;£=?\t1ýOjJÍh‡ü­Ë˜þå'L\ÄÛúîÚpOdËnr-/?ÿ-}n˜ÀÔ{ÓiÒ†œÕ�zQEl^8‰qÿȪ/-G¼Àý§Gj•í‘xÞ<Ðë+îž²„ÿ© ‹†\BŸñ¬›É„O¾'¹dú(>Úâà”ˆb­òVF¤eŒ´N…«Ý% =å)Òf¬ãõËz±ýª‹èÚ šüõ3™ðÑd¢G>ÆïÝÇØ­Ë3’{�´íŠˆˆˆˆˆÈq åÚ§MÊðçLÊðç̱¿ñ'óÒȳMÛZ^c?�ºøeÙ&¦^gsÑÝo˜YÛCå_Új~~îjszãxã²J\‹e\ MÍ#þm~ÙVÞµ~³îÿ0—u®m¢¬}óŒktºöÂÏfk°Ôß_oêÚ»Îuæ;d÷êdübž¹¤½Iv[{ò´¼µM×ošEÙ¿™Û¹ v=sÃ¥3¨|yMh¹yê4��(ÓôVã”8äûôRca\-ï13•¸Gÿ$3²¾m°S̵߆2R�”¯"ï“Õ'æ¶Óë—(§eì¸æfàß2é¾ÙæþÖnƒësw‰Êñ}>Ô$”Sgß{ÄmWDDDDDDª»´…‹ö¼Œ1¦d¼ÆJ¹öiƒU¼È"cì]G2ntèœB¶¯Yɺô\v,Éõ›qBãšDUhK€œMkX³y'ù!q5Ðâ„F$t‚�CÁ¶•¬X—A�E�z-hÙ´¢yF.°s ËVo#�¶nK“¤ŠNš::å­œÈÊy�D*LÞ¦å,ß�I *…æm[Q7öPç¸Drï‘¶]©®.Z¼çï;´'uø3ìŽ×ÛÁ‘ãÀ�‚7ÚCDDDDDDD¤SðFDDDDDDD¤SðFDDDDDDD¤SðFDDDDDDD¤SðFDDDDDDD¤SðFDDDDDDD¤SðFDDDDDDD¤«tðfÖìߪ¢""""""""RŽJoæ§¥UE9DDDDDDDD¤Z6%"""""""R�)x#"""""""R�)x#"""""""R�)x#"""""""R�)x#"""""""R�¹�v¤‚|™lÙYˆq'P»Nž£]9"¼©(“˺…+Ù4å·,\Þ8’RêÓ¸^âa¯XÿÄ[i3è O¸‡i¿?M7EoDDDDDDDþ¼©¨à4þÞï|ÞÚéø<Ë&¦NG ½•‡F×ZZ™&"""""""‘Sð¦Ò\Ôëú'z4.=õÅ*Êb󲤭]À„çG0ñ³ï;é¿\Õ\Õ,"""""""‘9f¢ ï½ÿó̯Ô5íÛwàÚaÃsIÜt¹ùmÆ]�ŒUîq¾’k®ú?­Ç­·  Ï×#h¤ 8"""""""�c&xóî»ïqïw…ðùýø}>|>?>ŸŸÏ‡ßçÇçßû³¢¢">üàÃ*ÞL4�Ïz„÷Ÿ˜Mëë¾%÷§�øfÛpn¬_ê ï\EÚÚlLlÚµ«GLéË�LV/XC–‰¥~»vÔ/sÂþ…óÖ3oÚ ¯Ï /CjÓtïÝ•¦ Љˆˆˆˆˆˆ«Ž™àM‹'pÕ�«+uÍyç�WE¥9‹ÚÝzÐÒý-ó›X·) õÝ€!÷ë;é1ìkœ“céà*uiÞÿ¸ëô«˜êÀÃsæñX§ ¼ENSŸÉ��β\‡½[*[؉müðë¼z×éÔ*ª�ˆˆˆˆˆˆˆTcÇLðfô«£ýêè£]Œ sr²Éq;žÄ„*Œš˜~¾z6 _bG†<~ÃÎlCMg;¿ÿðO>;žq÷ dsp “î?‰èª+‰ˆˆˆˆˆˆˆT�#¼ùðÃùðÃ+tîСC¹üòËËüüÝ÷ßaAe÷¼9±×^s¤—M&“ßþŒuap5ìÁéÍKO¯9|‚óžå¶RäiÇíŸOáù¾5öìÅÓ¥ÇÙœ{òµtô63žx€÷¯ü† µ„JDDDDDDäXrDFòC† aÈ�!=o�€÷Þ}�>}{Ó»O/ºu?�“;ŸD»ÛÒâ„æ4lÔ€”Ôãñx=8N˜‚‚‚ Œ›p[MdÔuúÆZÂv2gÞ{=£ª*Ã3ß{Ÿ%Aˆ;ëèS£Ô&Ê©º‡ëOò`ò'óÁ—›9ȃÎEDDDDDD¤š‰hæÍè×Ç–ûó“OêÄi]»–{lwðf•!C†ì7pТy ®>²R嬚=o|3<O9zŒãà˜âg,oúÿí}>yU6ï&¼ž™³6ÆM»^=ÊßÓÆÕ’Ýëâš»‰ù3縹‘–N‰ˆˆˆˆˆˆC" ÞÜx݈ˆ2Û_§"3sF�ÃèÑc"Ê÷p‹MiLÝøR“–|;Ù°%ÇU�þ}œû¯¿„3[Äïçq⇉³•M[À°ä¥ éônùa"F†ÂÍ›Øé@­œ9fñ ‹‡ ‚×ëå�wÞÙóïŠ,©z÷½·Y�¶ Ryµ?±=×^Y iÿ¼ô}j.®NÞ70S8“º�ÁS‹·³:«.'7¯âÀ € àÀ`B~|¾ýDeÐ<<µ¼„ªºL"""""""rX•§M <˜@ P¡À À{ï½ÏÕ×\…Á †{_þ~¿ŸW‘ÏLJ~TÁ›ýˆíƃÿ¾‘ÏÎÅÊ·náÁAsxõœäÊpœ0Ž9øiXq$Ä[€‡î�NçûëU}ÀHDDDDDDDލ£ö¨ðŠmvkÞ¬9wßyo¥®©š=oö/¡Ï£¼0ìK.»–7nùƒæü‡³j” §XX–…˜P�P9AšðŽíì¨è®ÂhâÆZbýšõ„¨‡ç0܇ˆˆˆˆˆˆˆTÇÌî'cƼƶmé•z�ûÆ‘-¤•̹�?Çeõ-Bk^ç–‡&‘S*@‡Û'#�Œpé¶Mþ‘E]ÛdÕ¦çípfíÄoX,ï$‡-³¿å—•YZ2%""""""r :f‚7Ç «öÅ<õ¯ HµB¬zífþor.%ã7ž–m9Á ÎŽølJÎ>Ç‚k?à®'§ã¸+ºøÉE»¿Ü@ßD‹Ðã¹yä—:£hÉh®;ÿ˜ÂMß­dôM3hö‹ôI,>êjw COyŠ´ëxý²^l¿ê"º6ˆ&ýL&|4™è‘�qÅ{÷1v«ƒS�åSv“kyùùoésæ>Ø›N“†0ä¬Ô‹*bóÂIŒûøGVxi9âî?] 9Ö(xS\ÍþâÿñÁ©eêŠW¹éÑAÌz¾7 ®¶ÜþÞÛlºúÆüºˆÏG-âs,ì¸fœsßÞº7žÆ[`üøüÙ¹ØCËáŸðký§¹ï¡Q|1i,�ÿ¸ë�e×°Ãþñ8ÿºå êh7c‘cŽ•ríÓË@ÆØ»zÁè×ÇrãuGè Nǵ0y›–³|C&�¨š·mEÝØC]ÅæP°m%+ÖePàDQ£^ Z6­I”‚6"""""""ÕÚÂE‹÷ü½c‡ö¤†Ýñͼ9j\$4lÇ) gš6qu[srÝÖ‡3Q9Š´a±ˆˆˆˆˆˆˆH5¦à�ˆˆˆˆˆˆˆH5¦à�ˆˆˆˆˆˆˆH5¦à�ˆˆˆˆˆˆˆH5¦à�ˆˆˆˆˆˆˆH5¦à�ˆˆˆˆˆˆˆH5¦à�ˆˆˆˆˆˆˆH5æ.ù�Sß|Ð NmvQ…Î;x:QÌ^ë?ätDDDDDDDDŽeíxY¸(cÏ¿;vÈØçx¥gÞtjuè¥:ŒéˆˆˆˆˆˆˆˆÏ´lJDDDDDDD¤SðFDDDDDDD¤SðFDDDDDDD¤SðFDDDDDDD¤SðFDDDDDDD¤sü9&¸mRc,p Y¡£])Å"1Á&C~¾C¡9Úå©:±q.âm(* “§†("""rȼ9â,êÕqSÆüì ‹ö¦;ÖÍ I6†œ¬ [|G®”"{û«Uêçc pØ‘&·š N½-’÷çX¢3ó1&‡ÅΡ¦xlÝõfѪ[-^=3ŠÂ¥™Œø¢ˆÂ’G=.Ú4öÒ*ÙE ;3ƒÌÛdçAê¶r×YÔ­í&ÙUúýÜ— …Y—¦¼ÿr<±n:4òÒ$ÁÆã8d儸}S€-þ}ÏKjžÄØócˆÚ�Ã�å³JmDDDDä�(xX¹ë°ò¶`êc›Vmf®(F\Q‹óc Ó¾ÚÆ_:”÷å«»F,�\Qƒ³jXìX™Í-Ÿ«¶\"RÖžþºÿSŒcضÕÇÄßòx÷÷ G®tUï(ß¿å¢axce­`X¯T†�{¯½„ÿþº“ÜꨖÉNŒáþ!Å�›ÌUÙÜþYkõ­¥ÈQµc‹�…¹{C­–eë¢E]uÄpMƒhº×ÞÁÈÉ�ã+€³ËѸÿ§Õâ݆—FgðavÅ�U7VL4·Œ£!!þûM.ó{�Õë�̨?ÅP ‡UK øfMˆ,lZµŒãâ–Q ”‚÷“ ž]³o ?¢ëÜ6qnÀ8,[ågK¸üò:¹!òJff»4(…{[Ø1m^!Ó·…)rÛ´lË­=ôê]“†Q;¹æGÿ®E¿MÎf|ó.íœÌí«¶óøªò¿¬‘ƒûCo¬¬ ï[‡+û·böŠŒ8ïD‚áE|2ëèpìøhî¾<™ókZd¯ÉáöÏ 4Ý\ä¨3,››ÅåÌ”³£=\0°÷µuÑúÔ$.˜_ýƒ •w4îߦ]76åÍ:<Ð±êÆ¢C�$&ÁÎŹ¼³©D,:šÎŒ!‡9“vpç¬ »W}» €Ÿû¦òr÷�ç›7rY>´ëì(‹x øàËL&–Zê´?ImÙÜÆòxåý¼³­D+˜WÀÄÓSx­�—¦�8g–ŸÏvO± øyóç"\ÃÀ~ |±.‡ÅúÿLDDD$"Øà�•µ‚gÖáÊ~­™ò{:¹…A~JÛÊÈ Ú /äó9G>€cÅFqëe5œj‘³.‡ÛÇç³â cÛë¢M#/-’\ÄÚ†ìì 7Ø(y–E�Únjº 07Äú‚ý}÷¹÷¼‚œŽçÝ4EÇdÂ�ùœÓ*‰În'Öµ »ü¾›è¥C7 â‹÷ ÉÎ ±xc€ÍD{bÝtlì¥q¼�;fÃÖóÓÃ|Y®X7-“l,¶g„ºŸJEìþí7­jØ ³vG˜2·jÙ4¬ã&ÁrØ‘"#ñIÆ{é^ײ,êÔöÒ6Æ(±ÝrÓ`?ÇÖäš}‚KîX7yišhe 9¹!–l °®œßmV´›ÖÉ6øC¬ÌtcQ¯A'×q“`²³Ì[$£’ufÅÇpõIn\Çw6 IDATN�Ïg‘SâX�–qô‰‡ðÎB^™,U7†´_sùé¤Zœ›Ë�óX²ÖÒuDÙÄY`‚¾‹“ZF‘hÁÎ¥y|´­tÝVÌ-à·Ó½ôv{8±¶Åg%¦íd-ÏãË1\“ËÕmó¸w‘f߈ˆˆˆì�mÛ8Žƒm—}0ø2xce­àš3êpE¿ÖL^œN‘?ŒÛ¶È)0qîfn½¨#¡ð¾šä8V´—/­É�º¹r¹óÓ|–hdfٜܭœC“¨}÷;pü!&ÿ’Å“³» íOOáñv6K3¹ø³"rËIÒNŽãŸ×&ÑÉ òæ[Û]XÎI"R†SÞ¯pÊÙÅŠõrå¹É\ÛÚM\©½bˆIS²xâ·r–Ù.z÷IæÞS£¨½Ï>#† xjB.Sr*6¶ã£¹ÿÊš\P ÖÌÉäæï߈Ý\Ë$Æž��žË_ÞÈcUéâz£¹ãêdzÛAƾ¹�×Ò-:õNáùŽö®ßk†^’ÊP`ãÌü;¶&Ï”{,ƒË&Š÷xq»é×§wv‰¢v©ÿåL(Ìü¹9<>¹ˆ�%– y%ðŸKc‰Þ˜ÃeŸxQ2Ú¸öùO2�ãã¥q™|’^ñðCÃãè Á …|½½ä‹ŽÍ½Äék|,+o “?Àô †sÚ¸8¥™×ÚሯÛko� 8ì7†_†aúÿÒùÓÏ6ž`9Á7ŠƒAÙAÀe>g8A&¤¸¢¿—î�c©¿8ŸÍŠÞˆˆˆˆ”‘ïwH­Û�é›I©Ó€|ÿ¾¬ÿpÁ+ké�ÊUZ1qÞf üa®êÓ €å›røyÑ6>ÿu=·_܉Px>ߦ­ÀÔ¬ÚŽåeØ%µ¸º�MÁÆ\îú$�ßøM¼M—3Sx¡›¯?È÷?çóõº 9–‹æÍbÖ-†~ýSHuepÓ¯A8L_PDFÛ8j·ˆ¥O|ò˦ڠu í\Ü\È·éUu·"ÇŸèú^Z»À,(=3Ár3ø¢ZÜÜÌ&”åãí…ÌÝ&àqÑò„8®éÅ€5 çmç‘e%g%Øô<'…�ìÆÎðùìfd8˜XgœÏÀÆñ<1Ôâ®·²™u�'ÑYÑ^n¸¤8p³iaw|ï#ó0 xÿ•fX•–ÃQ\Ù7–&ü?{÷^E•>pü;sK’›F$„z‘Þ¢Ht­kÁ²Ø@ìbïmWWê¢ËÚØQ,€ ¥#‚ ½wi¡·„ôv˼¿? å’›PÞÏóð(Ü{fÎÌ=çÌœwÎ9ãeúìå ¹Á+`8üãÒpØóyob³ÁUÇÉ¥g‡qfd0÷^Ê¢OsH©Ìavz·v`GXùGÉEŠ‹>kk` lÝïÁÿò3[xñµv_×NnÒMÁ&¡€J•Ö%òz,R3+^Úë¤m0ˆ×ÃÆƒåOÌÞ?òÙØßÉ !ô‰Ìù N+TJ)¥”ª¾=é>êG…݆<·ÅžôÒwz§UðÆÈJẳbrn+&ü¾ƒÜB/»ÉÇ3¶�Ìù]™¾|7ûòÜŒýu3 ê„XË™¼nD&ÕN¦ŠáöF&¹»³yè›lVg …=!Œ‡z8òyùj\*¯m?Üáó°aWó÷GñÉ•.Ú÷Šà‚5iü�Ûó˜œÊÐØ .jkã§E>JÝŠvú·)êd,Y�ÏN}2ªÔñ™&�“\ ??”ú†°n~“Ë k³%¸¸¦±‰iyóí!Þ/ÜX¾µ€í¶z¼ÞÅÆ9]Cxsc.‡û¾ÎÄpîëhÇîqóÞ—©||àpºælt“s,WE»¸½s‹ç{©°kmwpÍå1 ©op`}:÷O*D¨åãÄþyLÌ08¿Ÿ‹ÆX¬Y—ËG:üÇú ‚…qï6LËÃØqycçÑ©Tv2ŸðÉàP´�dðÒBÞÙ[ü©€Øê¹¸`[&7�É!åÈõ²€&_ %!>„³"sH©DÂrÒ¹ž�ayY¹³L›kšÔ 7@,Rs¤Â©D©Y>,ØÂíÄš�n˜Î›ÓÀe€å†º­Â¹²c0]êÙ‰v@^®—�)ù|¿(—ßÒ*ÞnY¡±!ÜsIÍLa×ò&ù9/V¦›™Ð>ÚAçD“/3þ¯SJ)¥”:ÁÜ>!%µâÑñ§Uð†ì=ÜtÁeLY¶›}éy86|> Ó08¿K"?/ÞI�ÛGn¡—í²3óîÔ‰) @j!xcØí º<š{“LL±X²$—UÇy‚gœá¢© ù›²ùd{ùõÒ7eóý¾îLâü–6&.ñaYn~^åæºsœ´oï¢Éâl¶–HhÆ„00Þ€Â~Z﫸#¨ÔiÉ ûÀºüÔ¯ä?¸BL\6!ó@!Ÿÿ�ÅÇk<ä—IiÌåá� ˆ¶—‹š+·¹)èBp´ƒFÅÁƒ3Ρ¡ ù›r™p t:),ä›99Ø@z¶�ü¯cÚøÛ%1Ü×Ô$cK÷ÿ˜WjªÐ‰8þË S» p§ä2vWù DvJ÷¹¸+ÁNÿÖÞßë.5zÅ/?ý–["pS$W!뼡$ØmÔ�¨x]£’l±šÙ‹G¤¤–ͪI¸@È;ÆÙ|wÑ~Œ ƒÐê¤Bƒ‹¦›Ùë‡óÊ`x-öeZ¤Z& ÑNÎŽvÒë ?LLcÄŸÿQ=¦ƒAGp¶Ë <ÂN‹Xγædñ꼿Sr±WJ)¥”RÇrRƒ7·ö‰¨ö6Vî,dѶJ¾2#,�ÿ�[Áýƒ:2fÖ²ó=ØMÀ—ǯ&3ÏÍ¡¬B²r IŒqqÝ9-xuÜ $¼~µóYžÁ}bH5Éͱ 3é{~4CÒRùxï1:†�ö‰&&¶�îR‹_!>Ví¶°l´Lt`_R´°éÎ5y,íí$¹®‹ rx{ÏÑý$µ¡¹ ›r™£kÝ(UŽÍnb–š÷‚Í(úoD´“^BIËÉf\НÔ;�Äãcû~ÛËnÏf`3!È ‚Á‡×Ã1l´K(ªç;öºñ3Ë‘ík2yiÍ12l˜$ˆáé¶6rwdñà·¹l©F�9Ðã?¡ mLL`ç.·ÿ©aâc힢ö1!ÞqdJÑ‘�½Vû›úeYdvƒ`Gå²ãŒ°k€äøØWöÜ`‚÷Ñr±ÀØ [uÒ¡Á&€×ˬ9¼µ´�ÝÅ?–+:˜¡Eqc#—^Ŷƒ©|™ægÆIó&Áô /Þ�×Çê­…,Ûã%ûùÙ—éC°iüQJ)¥”ª¢“¼=§Æ×W�D&1iÕ+¸P'FOýƒôìBr <¼~{27¼ò+–%$Ƹxâ�xuü ¦¬É…èVµ’Ÿ¬Y˜Æ?g{évY,O¶trÛ (v}vˆé�ÃFÝð¢^R÷ƶ÷èq¸Šž°‡Ûˆ,~šoeçóã¦z´µs^{'£÷=­7œÓÆ�]|ÌZUX¥µ”:= ¦ìã¡r¯Ê6�tУ]·ŸÊ}ƒƒé<9•'VxKwNvÎìÊ%­‚hg'6ÄÀQváâR›µQ7Ì„ôÜÞÎc´ëÃmÝ8½…¼=1›uU}5U)Õ<þÅ´W|ÞÒ²+A(¤åXXØ0CM¢ H/qPâ¶È© aUñ‡ ) $Yù9eÓZà±›�Óæ'q1›�¢à‹%EA±@Ó;¦2`)àòË «É;TÀ»ãÒ©sK —EqM'ã§»Ëâ|n>ýê.—��‚ù{§0jÊÕ«Ó¹÷§|ö”;BV¾MK 6qÁI¡¥”RJ)õçSþýSqÕ’É«rymü n=¯%ˆ�–UÀu/ÏÂç³Jn¦®®½À kg§rçŒöx¼Lœ˜Î—32„§EÐ!¨‚d8Š5Ã4pÚýÿ1Ü>v§{Ù�W2Bg1we>©õZ»èá,úW[ÝΉ_z>?íÐÅn”ª$Ô):§ž,/~Þl]cr ,,Š^ÑVî7¶Ø°Ï y}~[&íêÛ0¶îñPP�tÅL›Að1®üÑaÅS½ ŠGì˜vz÷ gøÀH.Œ«(•��_4¥Î 2Ê+a‡§�ZåGš)¥”RJ©ã:mƒ7Ý’)«syuÜ nØ’WÇ-gê꼓¸9,;%‹Ç§�.-zDó|W;¥×Æô±r»P¿i0Í*øãêÓ)ÚôÛyÙ±&�eK ¡OÓúGCþö\¦WâÕ·J)ÿê$ÓÎ,/)GVÊ5 +r‘žc•Žš.êè¤Üú·âcÕ΢zŸL’ŸzÞªw¿>‘ȯ׸ˆ.û¡WÈ+E·wU:/®òa9œÜtiÝ�1Õ¦:ü?z/`T¤‰i\q;vرb;¥>+v½%)¾IMüm×î¤G#aÃNw­®½âÎò‘&`†Ùˆ/× ë6�*ÖÔÅY!åÓ›Ñ.Ϋo >s6~|€éL7ß”ÀœÇx«»ÝÿÅßæ¤Os;6`ÿ÷‘7ŸµíÁ�žaÜÔÁY~QQBZÅmÓ�íÃOŒ’z‘6 -ÓçÿÍhJ)¥”Rê˜Nëà €D·bÊz<úSÖ{kq�›JçˆËÒùçbnÃäÌscx ™Yªƒ²mu.K ÁʃÉÊ./Ê“WÇ0êŽ8îmX¾Ûceåóãf æ¶¿¹HÄbþÊü½XD)ul¦ÃÆí#ùïßBˆ4 og“(>öe�iÕÈYº®š6zŸÅÕ!>2 ‡I�QœM«óXí)ªçww±—ê4Ûë¸ÚÑ� aÍæBŽwµømzÑšZö˜0þu~Í®sÌ㼇<ì²ÀtÓ¿qé¶Ì^ÇÅg91ý ù;ü¶$L“Ø2C“ŽõÙ«rYí{Ý0îho/37Ø y·p.Œ+¿€ï×U´¨qÍð¥zØêÃn§eLùÏ ·ç2aŸ`¸B¸÷o.KxŒ '7^F[[Ñ['¦V3�åeáv ›apF¯: I,ý[`³Ñ{`Ç�xÜ|·¢øuÞ–‡©«Ý�ºÖážæ¶rç´IÇHnnj`ˆÅÂ�~½7í´Œ30¶î÷ú¹RJ)¥”:¦ÓrÍ›r"“�Ȥ“�‹,ýrˆWcâx¤™�+.�f×çiŒ-^¸ÀÊÌãåÁ¼wa0�ûÇñE“<¦mõ’ê3ˆ«Ä€¶A4t ;—gòéNsŠ.NkJ|¤�•“ÇO[x£�R§ ƒnêò}ŸÒÿj³D¸Ì#ÓPröåòÜ�9©vâå—Õn†%‘Ð%š·¹ÌØgî kë:Û ø÷7œwc}œAüc@æV7ó7¸I=”Ë+³ƒy{@ÉçÅñyóæîõa¹œÕ&˜f!�¹=‹×V?!……¼÷c6oŒ }Û:<½ÃÃ˪҉ðøë`>S÷†Ó"ÑÆe—ǽº€uÙBH¤“>í‚p/ÍbJûH. +½ö�ä{IÉ…v.¿(×6/äòþÜÒ�õÙ¡\^žÌ»‚è}a&å2c§�\Ó¤i’‹‹šÛqY>fNËdª¿w°× )p³â pv};Ø0÷•ù­,c'esæutjÅõ]ÌKñ’iÚhÓ4ˆ¶á¾Ì<þ;=¯tp= tÂÚy|žÃ�ñAÜqc=þ–RÀŠT o��V�ƒi_ÇÀ°|ü6#�¯K‹RgðnÓXîmâàê«ëÑwO!+úÈ3L‚èR×ÄܘɛëÊ_K̰ :F�ø<,ß­×¥”RJ©@hðæTåóòí‡Hº1†«bƒ¸ûÊ:ìþ,�Ù9·¸%;Œ»û…Ñ7)”›JÄžò³Üü4;‹·—r¨‚Íç§ä1%=”¢aߺ<ë8v¥Ž)Øe#¡Ì¿Y>!7×Ëæýn¬Ï廵n–‰ˆì^–ÎÓ‘Q<Ñ=ˆ3:„sFö¥äòäÏYÌ΄½ó]´ïD«N‘<Ñ8‡;7ºIaÓÂ4nËŽàþ¾.z6sq}³âýz|,Y”Åÿfç±¥’÷þlž�éäÃóƒIÅ�=©|´¯òÝè@�ñòÕéÔý{$—7pЯ»ƒ~€åñ2ÿ÷4ž›/\Û0 œ¶+äú ûKɹhÌqP˜âå£yÇùL„Í Ó¸5;‚ûú¸HnN›vG2Cêž<>ú5‹/·ÕÃÇ>g£‡;ê;9£e01KsË­±S¸/›ûÇø~^—4 âÜÎE«Øˆe±uC6oLÏa~VùM’N yçóƒ¤ôŽ`H‡ ’šºhÚ´ø3öíÌãëÙY|½ÝW:°çõ0öëƒìHŽàæ.Á´I æüÄ£çgº™²8‹÷rÐÏI�mL;øöð[Ù•Œ•RJ)¥T¥±Ã^Œ¢1×II×7Á­}"=ÇÏ�dÕÔv„„Ùiib@vŽ—�Öñ×pñøí±\æáƒ�0jÿ‰È©R§/Ói£I¬�pCHÏð²3WJ�@°9M¢ìBFžøy#”Ax¤�Ä0»×bwš—ôÚzmT-rEØiaâðYìNõ’æ9~[��†‘&¸}ìË´J½êXŸ):o à œ"¤exÙ�+'tav3"”×o¯C››w>8ȧ©78ÔNã:&Á"8äeo%_…P:à .ÚN½¼©>öUj‘vê‡!dfûØ•eUü3ÃÎM7ÕåŽX0i?,?A3¥”RJ©¿ˆm[Çr8^£#oþòs¼l¬âðÿÄáœyÛrùñÀñ¿¯”ªËíc랊‡ÉøÜ©F]…ìL2k%k'L^–—õUŒÙû }¤ðÞŽõY‘¢ó¶î$ž7++�OW…ѽ›“A=ƒ™ðs5×¹^6–[0æøJ'ÂÁ4«¼7!+ÓCV%ÏixópÅXé9|¶V7J)¥”R�:í,>…Õç™~A„X^~˜›GfN(¥”ªaéÜ,fæ@½ö\B^×~а;¹¡_qø˜1+›e:=W)¥”R*`:òæ4aFsm× "�ônå$Þ.l^�Á;4r£”RµIró9%�öƒ\\wa8¿}–ÅÚJLûs3hß»×Ö5Ø¿*ƒÿ­×…Š•RJ)¥ªCGÞœ&ŒP'—$‡qU;'u-/sç¤q߬B²OvÆ”Rê4phcOÏsã«Æsç}²3TËb[Õá¹dÞ=Ù<5µ]§X)¥”RªztäÍi·/›»ÞË#ÒeúÈø.vª”R^ª9i\³ÖF˜aá5᯻Œ�g�Mv–—:]J)¥”RªÚ4xsº!-ÝKÚÉ·RJ�®ÄbªÅ_ÿå~Bf†‡?ùúÚJ)¥”R§�6¥”RJ)¥”RJ)u Óà�RJ)¥”RJ)¥Ô)¬Ô´©EO%7ÁÂE‹YôT÷j︦¶£”RJ)¥”RJ)õWwóÑÿ¯òÈ›å+WÖH&jj;J)¥”RJ)¥”Re:mJ)¥”RJ)¥”Rê¦Á¥”RJ)¥”RJ©S˜o”RJ)¥”RJ)¥Na¼QJ)¥”RJ)¥”:…iðF)¥”RJ)¥”Rêf?þW”RJ�t‡Ø“–‡ØÃ©[/‡Ÿ¯ˆ'—Œ,7Žð:„9�žÅ?�íI#Ol„ÇÅé t3ÇÿMNºšÎãŸá˜•RJ)¥þ‚tä͉&Y¤¬\Ê’%K*ÿgÙôœìŒ+¥N¦ÂŸï¤yÆ4îýK˶y«øà¦îÔ�'&6šˆº7òcáIÉæŸCádînÕ�†�Ïæ¹%•i\½¤nZÆ’%KY·'ÿèf¦ÜCëŠ~“SDMçñÏpÌ'žÿò¡”RJ)U“tä °{÷.fü2‡ÝÁ™Ég‘”Ô´övæ™Ës.áã4«òiœýxsóLînø×�µYY»Ø¼×"®i#¢ô‘®: UX v› ŸÍÄ(5¨ÆÇÚ׆1üÓ¥xlqt¼pmc:÷×o.N \&?Ô‹'úèúÂJ>ÙÛÉÎÒiäX×…Sãš¡åC)¥”RµOƒ7À¯sfѵsWê×Oä«o¾d@ÿ�´jÕº–÷j£^§tK¬Äݦ£=MBN‡)^V�¼�nÿ‰ä• ³¹?I{ŸêtSqºb,Yž±å“H*óf¯Á-6šÜñ5¿¿ÙŸ�˜ãÓC0aav ,ÂÂC9ZãSDZ® §Ê5CˇRJ)¥jŸo€¼Ü\œANÂÂÂrÃP>ó @-pìt¿ÿ+~¥7z‡I‹nÂG·“�¥NŽ@ꀕEf–ØiÖ¶Áµ–¹Ó™QÜ)÷¦�óêXu┹fhùPJ)¥TíÓà pÎ9™w v¦‘o¸ˆiØšî½’i[r•Üã׊ó"A‡ëµ�¹m%›neWŽ9;W³dÉL3„`{ùnƒðFgЪn+òJ;×ld¡ADãö´Œ«ü¼)ØÇš…‹X³m?Y…&®˜DZvN¦k³:Ǽ°T¥þVûüû2Ø4ïæ­ÛM–„ÓðŒ³9§Ws"+}”‡E�r#›ÐpWÅ�sO*kçü ûȵ×)Ú_rS"*œCc‘³c¿/\ÃÖ}™¸maÄ5nGÏÞ=hQ3íññxS7±j{&¡4h׆øªFÿ*yÌ5{]hEïf¶TòšQ¹:X$°2WÉò¡”RJ)U±Ã^–Ø›GJìÍ#¥2Þ5ºRß;QÛ©)6¬—7ß~]¶¥l‘ÂÂBÉÉÉ–·ß}S6lX_³;*üYnŠ1‚äâO‰UÅä¾]cåªS0cä¢RÄWæs+íg¹¹±M0Âå쫤°Tâ2{Ä iaŠ‘?†˜mäªÿΕTr§È�ö—AF‰4†Sú<$ßms—Ì�úäb qtú·¬òúÙ^Æù{0‚½½ük…GD ä§¡Ñeò„€Mš?ü»Ùz ùW*@o”(qö~U6ï™)ÿê/£tÙ jüwysE^ùÄù›d܃ý¤Ap™zb'J߯ɦ‚#{:n(µ„ˆ­Å#2ß]”æ‡ë#ü¤AŒ°AòÈÕ±bbJÔU_IZõ·y¤ôr‚½�<½ÔS¹“beÈâ·®“ŽQöòû6B¤Ñ€Gå‡wùtÔßêœ÷æ¯ä¶ÎuÄ,ù}Ã&Q]î”ñÆÉµá†`k&Îó“×r<²â™b7ceؤ£­jÁw×J¸�Ø[=*¿®-ƒ[†–>6Ã&ÑÝ†ËømåÏ­upŽŒ¸¢µD˜eËGÑù¸æ�Å’Yíöøh�–›?Éžä–VAb!rÆðI²¯ìÅ�À޹¦¯ ³åûÊ\3ªT‹�/ 2ç¿|(¥”RJUWÉx�oJ8!œjoD,Ù÷í ÒІ˜u¯�1»JÜm[2}xs±¦Ôð†l(uïœ!³é(.1#;ȵ/|!Óæ/•%ó)ª1 IDAT&˧Ï^)m Áˆ�³^Z.ù¥vw@&ÞÚ\œ†!öø^rÛˆ�åÛŸ'ÉwŸ¼$C»E‹iâl9\¦²Žä¯ê7é>Ù1{ŒŒ~ùZieG°·�k^%£G(_/Ü_  4ÿJUCá”[¤®‰8:•»ÄIü™·È>ù^¦NŸ"F=.4rŠ�!Á=GÈú’eÝÚ+nl,vÃ3º«Ü4âK™6‰,�?]¾1TºD™‚á�¤a?ÊK¤2u |ðÆ'Ûg}*ŒzA®lj°KÛþ+£F�–>ùEÖO»SÚ#ìù`�¿–Æ+¼œ,NÃgϲÁ_]-Ç’ãK¼‰a­åò'Þ–/'N“Ó'ÉøÑÏÉ�îqb3 éüŒ,)Ù‡ °þ|þ ÉÓƒÅÀ�Ð6WË _Í”…KÉìïß‘4�:�Ï–.aU Þˆì]'K–¬”íYGÏå‘@FÓsäÜ–.©wÖ-òÒÇßÊä)?Éÿ»SήgC\=^”U%wãÝ,oŒC‚›],O¼?A¦ÍùMfOýFÞ¸§�ÄÛ Á¬/×M8PúQåö¸âà�•þ›<Õ=\ Ã)͇Œ“•úý=æš¾.ì•”ã^3ªZ‹Zæü•¥”RJ©ê:­ƒ7¿ÏŸ'¯½1R~Ÿ?Ïïß×­_+¯½1R¶mÛ|$€óÆ[¯Êºukk&ÕÞˆˆ•*?Ý’$vÔúƒ¿‘}ÅÉžó ´qbÆ^(£·–¾;v/yZÚ; 1œmåþ_ÒËì×’? •Æ6Ä?_Fï<*øýie7Äp%Ë +K‡E¬Œ2¼¹M0‚¤çˆ â-ÞVÕoÒ‹øv¼)ýœγåÕ­¥š¥ª£pÚmE� Ô¨�¯Éº2Oés¦ß)�mÎ^ò¿e6ï×{¥© 1íä¡9™åÊë¡iwJsbØÛÈ‹�ö¨�UÊoŠy7ʈž� øÞÞ£ûr/–'ÚØ#Xú¼¶µÜ(=ñn�ÿôpˆa¸dÀ;;ÊîWº|qy¨8¤Û‹ë¤\õÎ[$OvW\OyvÑѺhý ìü[’öå•RÇ@Œˆså�2m¡¬‘—Ï.-R…à�?‡`Hxß‘²¶lþæ?&í†`Ö“›~Î9òïž…�:È?—•©‘%Soo,6 ðŽ”ŒÏW½=® x“·J^;/NLÃ. ¯üX6Ua°H`Ç\;×…c}h ´Î+¥”RJÕ†’ñšÓn‘�E‹pß=²hñ¿oÓº-­Z¶fÊÔÉ8N’{&3áÛq5œóž?�3““I>æŸ><4)»tR#† _Å-lìýæ!›˜Š•·€†¿Å_=.{õ}†%•\pÀÍ‚1Ÿ³Î¡ç=Âýê”™“owÑ#ÜÖÉ�äÌbì»±§û5›½vÞpîh_z1#²÷Jó –DªÉc>±ª_«Væ”RJ)¥jßI]°ø½ÑT{�;u¤g÷î•þ~�îɼþæÿèÑ=Ùïß׬]ͪÕ+¹ëŽ{صk3™É¥—^^í¼–f‘¾e ·ï{AÄô"PêæÓ¨3�?¸�YçŽäóû¢åßWóÚ‰ƒßäíëÊtÄ|ÛY°p7>ì´í}1þ:-¶œuf<¶¥»X¾`9îá ömgÑ’½ø°Ó²[?�­®ÿ/ï__僯š@ó_ËÙR§#¸+gvñ³¬#ЍpòóÈË—¢ómeñ’T,l4?+™zþ¢"¶¦ô臹d)ËWrHºS·ÆW9µÑâºaônSW}ÎçËå¥î‡$ö±~Â8VyLb/Êßã*¹s3ž=“°ÏÞÈÂsWèK,j¢=–ƒL}ènùz'}þ�‰_ß;W¾ªÇ|BÕ@¬R™SJ)¥”:NjðæŽ[o9áû<3ù,ÎL>ËïßW¯^Å�?ýÀ}÷Ü�Óédç®íŒýr,—ýýrÚŸÑ¡†sÄ€W—òÉ•Ç{ï‰AHtÙ'ÕEÂ{ÿ›žI¿?ã©× ìIÃx÷õAÄ—ý²µ—]{,@X÷Æ¥tüÌÿ«O ÄBÈÛ½‹4 ­½ìÚ[ô â¸ø¸Ê=™¯ �æÿ´W¦j‹I¤ß1Ù°—³#Ý8ß^vïóÔÇiµ_¿6ö`íßË êVøF¢À™õ¯dØÅO2ýëM|ùÙ<žéÞ¯((â]ËøñkðØ4äoDÉû&¾|ü%¦,3öŬËùO¾Ä?š;èþÄG<³ðrž�½˜÷ïȨ{ë�Ôµç 8—ó/¾” z6ÄU² ª�ú[¥óo¥²?µ¸Ýªë·Ý2ëÕ/êÐ×Tð&¦ ʾ֯hOÄÕ‹Ãd'Ö¡TY�pøðs73åÃwøøû_X´f {Òrq[R&u Õm�%›E/\Á3o¯¡ ¸/}ôÝ뺑£:æ¥ê`•ÊœRJ)¥Ô  ¯ /¶rÕ ¾ÿþ;zðaœÎ vîLá³1c¸âŠA´o_Ó�›"!QõIlU�׊ºh;ðlüg9›}ízÑ)ÚÏÖÄM¡»èEâ-¤  ‚ÛþðDš†ƒ#ÆY4„\Ü�ùq8'ïõ§�æ_©šbU(ÿn ÝAA~¦s8‹æªˆ§wmõ�h.v%õÇ¿ÏÎñŸ2ã¥~\ÞÕ㙰΋½Ù`†ö)1zÂ:Àâ Ÿñé¶2Q [3bny�4·aDžÅÓÓ×pÁ¸Q¼ÿÙ8&Î^Ͷ?òÁ‚ùàňét-ÿ~ï5îêQܶÕDý­Êù— ·[þ¦vØìØÍškÑŒà‚+Øœ3¨( n÷‘ßYR§óðyWðêòI¤K¿K8·yQ¡Á8Ìí?óê˜%ä•:®êµÇVʇ<ô¼¯óøïÓã¹êó«©`�»ªÇ|bÕ@¬R�WJ)¥”ª}¼Ö¯_Ǹñßðø£Oàt±cÇ6>úäc®ºò:vèt²³W!ÉœÅ?ï|�-Ô£ab»&=Ê÷㇛“J?i4B 3g>;�iw$Tî¦Ôpê2‹Üœ\,êÔÌèˇU•ú@ó¯ÔÉp¤Þy¹yþFÎ ù¹yEÓ!]a¥GªÔ0Wÿa\×âCFüñ#ŸOÎࢫÂX9~|Ú_ÝJ®wboÍÐw¾æ¬œ2Ô£e«— {]?ŨÁO!ùûX=wÓ§üÈW_üÀÒåŸqïq.ù‰[“Ì_�`B‚‹ÎA~Bd¹ýIn69¾š‹*HA>l® ¿°([®Ðâß¹�¹/ÜÁëËs±%]ǧÓ?àÚf¥'yº§íáýÏËoªÙ‹Ï"ª÷“|ü¯:ü÷ÊÇøõë»Ö»ïl‰ß&ÇÛ^•޹ªz]8–S¬*¥”RJÕ�Xü<ùgþqõ?p8lß¾�Q£GsåWѹSç“�µŠI:Ó¿�·7Z4¾é#æû(�œiL~ä6ÞÛTæ¹µ½ ÍÛ1ð²}ëöÊ�J±5¢i#à#esŠßâÉ'ßSòŽÛÀ(~b)^OÑSÞ2|©H­ÊŠÂ�æ_©“ÁÖ¸¸ÞxIÙ’RAyõ°}Û.|85¡~mN+qteè�Î8%�©_O!ݽŒqþÀ”Ì�×µ-è�¡Ãùƒ¸òÊ+Kÿt>ü.VFH<νž‡F~ⵓ¸»�94ƒ÷¿ÜXÔfœèúkÖ#¡nÑœ¨½»öøm·|Û6QvpQuHÚv– x퉽»öâÃÀžÐ€xà]Ôi;ðá ùÞçùG³²«s i))d•Ý\@íq‰ä oeìäÿã¢ðÉk§iL{ä^Zš_åã…*sm\ŽåT«ƒJ)¥”R5@ƒ7@^^‡ÒÓÙ°aï¼÷.W_} ]ºt=ÙÙ:!õ§‡¹cô¤ÑÞüÏ$öx‚÷ê€3c&OÞò:kÝ%¾nÔåì¾m±ãcÛ”ŸYã÷õ{Mæ·MéGotÍxÎ:»v|ì˜9�uå,®;AvÂ/ú�ýÅ7äÁa¡Ø °îç`¹†Å¾Y3X}Ìœ”^K Ðü+u2˜‰œÝ»yq½™Á²`!3~ËB ']{'ûYTWjp= -¯F_dÎÇ�S¿bÂf¡ý‡pMR/ù{Y=û;>›¸ºô¨�bFL LÀÄâÀÞEo�:Ñõ×Ö˜gDbâcóü…ì/ð±iút6×`C!îEÌš—SþßF,:„…�–�ÛýÎ’Ef–˜Ô�¯[þ"ìYǧýF¡R¢ØN˜ÀFãßgÔ�$ly‹yáúǘ™^õÒV¥c¦® Çú¬Fê RJ)¥Ô©Eƒ7Àà æ·ßfóÅ—crãºu­üÛ«NÙÿ-÷ßõ))4àú7FpQŒ„ÐãÉ÷x ½“ìßžáæW–Sp$…�¶7ÞNÿïÚ7¹ä2ÊÞrç¯{�[/¹˜>mºóÈÜÃ)ít¸aÉ.ïš·yüýõ%¶ žmcyñ£ xq‘|ñ@¿°ÆÑ¢ Íí`¥NçÛÙ™¥nª=ÛÆòàæaÙË?Å7ììàÛÏž}%ïîÍ¿R'ƒ�NCn!ÙeàYõO¶µÌë’óYõæ³|¶Ý‡}!·^ÓøHC\q¨3ñ*n¾0 #k ÏÜ;–mÅC//¿¸ùqXûÆq÷ùƒzíí¼²8»|g: ³~߇e8hѺiñ¨ž]Cè}éùĘBáì7ùRù,Üô1O¼±ËVƒkÞÈAÆ¿ð?–”:0áÀO#ùh�ÃÑ–Ë.+åd6 qàaùo JŸ ÏN&>p=oj@Œ ’—ÊÁÜù¬=öŸáº\òÚ'ÜFž�ïpÓÝãÙSÅQ/U:fjãºp¬Ï¯ƒJ)¥”R§*]óhѼ%O=ù¯¼W7ÓïkMÂc•é@˜Ôò5KFôÆaíæ«{îáË]Ðà†×yå’Ø£sù]É<õî}Lìÿ ‹^¸™Î�Ëó=\E[h<Œ·þ7™~·ÿÈœ'ûÐqæ`Ÿ×ž„ |v¯šÉ¸¯g°9×I‹[^åñ^G‡ñÛZÞÅ[ÿ7‰�Ïdê½gÒù§+¹¸{"¶+˜4îgÖbúÿ›‘ÃŽÞüÚÚ^ŵÝF°r~ £¯éÍ�.£{b09ÛðãW³¾óß\7æ1>Øka•è01­i]ÏÆŒ[uë•dl ±ðüS`þ•:l-ïä�ÿû‰þÿÂÄÛ“9kæ0®>»ž}¬�ñ%Ÿþ¼žl{#®zý .A9Vˆ8ÆþŽËˆáâaƒH˜0š)y˜ Ãzat•מ1› áÙ;ßçÂ׿óï¾g0ý²ËØ© ÑÁ9{70ï‡o˜²Áƒ³ÕÝ<~mƒ#mB íO ".~‚'zOäáÙëxý¢®¬|ýš…‘›²€¿™FöùùjÞ›|µ§tTe–…ØZ b�ý5t[Ì�ëÿÆõLRWMä£�¦±Ýr�tÓ ÜÓ¡ørkkÆ úò g�òþµ ̽�«»FQ°{5³&ŒgNáE|:ño|yö0~Ìý•×y ë¼dοòLh�+bDôáùÏþɼ>O3ÿ«;¹¹w'&ÞÑâø7�3µt]8ÖgÖA¥”RJ©SVì°—%öæ‘{óH©ŒwG�®Ô÷NÔvþt –›bÌ¢W¯Tú�) wL—BñÉö�/•º&bK¼NÆï·üì [~{¸�8 C‚Ú=,s²Jí\R&=/×t©+AF‰í¦„6ì%C_ýUözüe:GÖ}õˆ\Ð²ŽØ�¤3Ä M’÷�‘ÕÙåóQ¸ù¹·Wýû1Ä m*>÷‹ì/X$�·² ¶æòð|w‰T^ÙúÅõÒÒeI2àÙé«nþ• Lá´Û$ÞDÌz·ÊÔB_˜)wÖ73V†M.û…YÿÕ#ra«’õÁ–„×ˈé»Ä]nƒ×�‚ñWKˆ�ØZ<"¥«ÍFÑÓ!$ßÛ+þZ…¢¼Î—GZÚl’tßl)씈x÷ʯ#‡H¯Fab+y\b o"}oy]~Ûçõ—�*×ßêœëàoòÊUgH”Ý8²/ÃYWºßò‘¬ÎX,O¶µ f‚Ü>Ý߆+'ë‹Ë$ÄÙk¤lÚ7GF j#‘¶û N”>÷~%óËžÃ]òócçHƒàß5C¥ÉÀGåûm…"’%¿?ßGê: CÍ’¹G~óªµÇß]+áþÊ�ˆˆxdÓ{H¬‰a=åù¥yµwÌR×…ã]3ª^«Wç•RJ)¥jVÉx�;ìeÁ(Ø|ðƒ�ìyoôÜqë-‹jz;*¹û6ñGÊAr­ ê$4£E“h‚ŽûðÑCúö?غ'OH]šµnF\EïŠÀGö®�lÜqwP,MÛ´$ÞuüÁéÞÌ�lÚžáõhܸ.哚¥NÛ7²iW:…¶0ê%µ¢Y=×1GF¿ gw´½�÷÷¶å_‹—ñïNÕxé&s×V¶îN#Çk#4:‘fÍyÜW�ØúëNÛʆ-ûÈ&œ­ÚÐ8²vœ¦maý{ÉsDѨUk„W¼®/{Öï à !®ikZÔ )5Ê›}€ƒ!ÄÆ†ã(w~ªÚמªsm\Ž__ª^•RJ)¥Nq7¿Âáx�o”Rê/ÏÇַΥ㽿ÂÀwX;åiÏU)¥”RJ©SZÉà�Þ¾+¥Ô_š�¹èE†<=›\[snyú Ü(¥”RJ)õ'£ +¥Ô_�µsÿ{÷WRRæ3ñ»yì( ¦ÃC£y¦wèÉΚRJ)¥”RªŠ4x£”RAÖ�y|üÊ+¬ó˜á͸øñwxÿ©¾Ôѵ¡”RJ)¥”úÓÑà�RJýÙ;=ÁÌ ×“æ ¡^ãFĆè\)¥”RJ)¥þ¬4x£”RE¶0⛵!þdçC)¥”RJ)Umú(V)¥”RJ)¥”Rê¦Á¥”RJ)¥”RJ©SX•ƒ7�;v¬‘×Ôv”RJ)¥”RJ)¥þʪ¼Y¾re�츦¶£”RJ)¥”RJ)õW¦Ó¦”RJ)¥”RJ)¥Na¼QJ)¥”RJ)¥”:…iðF)¥”RJ)¥”Rê¦Á¥”RJ)¥”RJ©S˜o”RJ)¥”RJ)¥Naö“�¥”R@Á!ö¤å!öpêÖ‹Äq²ósO.Ynáusú(u,…ìMÍÁ2ÈM¨CÐÉÎÏŸ…ž7¥”R5Dƒ7'šd‘²j©©|3‚Æí[§= ¥þ² §ÜCë+Æ’×üæ®}™d­ïµ'o ¿™~µ”ý‘×óýþ1üíç;i~Õ7¸ký7ð’ºi)™‚«~[ÚÖ)úç’×#”íÚ|ü­IöVÿq·€Þˆ3ZÕÅYt ì^»ž½ù`ÖiBÇæ1ØŽµ!+ƒm+·�ægÝ–´oŽqÜ�×tžÕaîƒë˜?o)w¥Sh§nãvôèÕ�¤ˆ²ƒ¦+(O5�Ÿ9�ÑåüQˆ»•É;Fqžþ`•rºœ·Ê—W¥”R�Òà °{÷.fü2‡ÝÁ™Ég‘”Ô´övæ™Ës.áã4«òiœýxsóLînø×¿ZY»Ø¼×"®i#¢´óª”ªq>Ö¾6ŒáŸ.Åc‹£ã…hÓ™80lØm6|6ã¸Q‹êÈeòC½¸q¢�®/¬dá“mŠ‚*%¯F8}øoŠ?NÅÇú7® Û?—âpöÉú9ÒÔp�3ëqλo®³xqÞ/<Þ¡¢çþ>¶Œú=†O%Ý•ÌósfÑ¡Q%¥Æó|â�r×�œµŒyüû`{ K>è10ÚqÑÃoñÎS£Á‘;¸ Ê“RUp=¨ryUJ)(mJ�_çÌ¢kç®Ô¯ŸÈWß|É€þiÕªu-ïÕF½Nè–X‰+¤£=MBjµ'qŠð²zä…tûO$¯l˜ÍýIý`•Rê“TæÍ^ƒ[l4¹ãk~³?GÆ)\1–,ÏØ�‰`ÂÂìX„…‡–t9üòÙ8¶¹‡&Çj =Ëùâ‹•x10Œ²#:´ºëC^ŸÕ“¡ßÎç¹›^àœßž£‡«üf¼ßæ¶'¦sˆ:œóóhçJ Ÿ©•<Ÿh§ØuÇûï]ÕŸáSBxk.¾}vi@hÁ^VMÇ߭aâ¿/eKÖTŒìK8pÜò¤ÔqX*¯J)¥¥Á /7g�“°°p†Ü0”OÇ|PË;ÝïÿЇDé�Öa’Æâ…›ðÑídçD)õWee‘™evšµmEC5Ä(îd{ óÓÙ¶µ¤]ó­¬�÷)c7ÜÅ“m+GQ8ÿs¾üÃ"¶eKdÓF²Ê~ÁlÄõï½Ï¬eƒødùË û×@æÿ·OéN”{-¯ßú4³2 î’‘|xw몯÷S“y>‘N©ëŽ�6áŸ<=í Ñ›�Ìã�C�~|ûp®{a ½ÿ9Ÿõï½ÀØ{s{¢ÉqË“RÇP=´¼*¥” ”o€sÎÈä)“¸ø¢‹©ŸÐàpªÎ}`#kvd#¶hšvlJT¹ë �³s ÷Bp<­Û5 ´Ì�œ/{;ËæÎgÍöƒdûBˆkÒž3ût§Iø±/ªîƒë˜7g1›öfá ©K‹n}éÛ1¾Üâ{¾´Í¬Ü–�¸iÛ6�r³ï­ClY±•tqQ¿m[ꇙ)+Ù¼ïw¦,u#’ÃÎÕKX’f#8¾5픾 4ÿJJ ö±fá"ÖlÛOV¡‰+&‘–�“éÚ¬Î1QOêz~Ÿ»„ ;ÓÈ7\Ä4lM÷^É´Ž dÑ‹œËø}á¶îËÄm #®q;zöîAÓc®)Pµt’¾…å[Ò!¢ ZÆâÙ>—Ÿ¦­ 5¼ƒ®éAÝJö +Û^”T•ó%[Y¾å„åÓ.9l_ð ³W¦�ás×´ }ûw¡þ‘èŒ�¹m%›neWŽ�—�«Y²d¦-†f�’ˆÌ,Ú¦ùo;±rÙ¹ì7æ¯ÝE¦Aã.}éÛ±A°oýZvåÙ‰mÑ�&Ç;IFQ'ÛÈ&4ÜU¾³mÆ3à¼þxs9Ÿ�YÆ#/u¯ ˜’ˬ1ãØ.Ñ\Ù·=ÓÿØèoq—ðêÇw³ðo¯³î�›yìÜE¼ý·Ã Y9òž™›�™8˜·ßJ“@æÜÔpž‹Væ+W_kïºxÊgîÄé²Lâ¯~ŠûJv„pÑé®;ðâ~,XÆÂU^nOtrÜòtU®«†Q´Éaû‚™Ì^¹� Ÿ‹ºÍ»Ñ·_'*LXŶ¨Êu¼ìµrŸðy ìZRõ ´@Ë«RJ©€Å{Ybo)±7�”ÊxwÔèJ}ïDm§¦lذ^Þ|ûuÙ–²E %''[Þ~÷MÙ°a}Íî¨ðg¹)Æ’‹?9$V“ûv�•«LÁŒ‘‹>H_™Ï­´ŸåæÆ6Á—³G¬’ÂR‰È샤M„)GþbF´‘«þ;WRýeÈ�"?<Ú_%Ò NIèó�|·Í]2rè“‹%ÄÑéß²Êëg{cäïÁööò¯)�Ÿ†F—É6iþðïrdë�æ_©@Y²ø­ë¤c”½|ù4B¤Ñ€Gå‡wùtù›d܃ý¤Ap™:b'J߯ɦ‚ÒI ¾»V ÄÖâ™_f“ÖÁ92âŠÖa–Ý^QÙ¿æ�Å’é§ì’®àÛÁf ξoÈúùÿ–žEim�î‘_ýj9Uj/ªq¾&Þ(QâìýªlÞ3SþÕ?^Féc jüwysEÞáòÃõ~ÚÄ,߈Œ¿ZB*ø Ü[ÆÉð±b3J—�&ýGæîŸ/�¶´ f¢Ü5³PŽÏ#+žé v3V†M*ñýÃ×go9õEéá4ÄÖx¸ü’_ÁfÒÇËàXS̸ëå«OK¸�8{�”-e/ ""’'‹Ÿí.¡†!¶FCä»ýE?|Þ’g¥›ËÃÞLn›”ZåkRmå9 2_¥úZ{×�Àë�%îœ4Ù“²I¶,ðÿ•ÂÉrs¬)Q2dâáïTPžŽ§ŠuµpÚmo"¶†wËÌ]¿È3甯sÁI—Ë;«òÊí* ¶¨Êu¼Ä¡Z_ká>£:ç-�¶±Vê�_�–W¥”RUQ2^£Á›NH§šÁKö}{ƒ4´!fÝ+dÌ®w¼V†LÞ\ì†)u¼!–ož$ß}ò’ í-¦aˆ³åp™vÈ:’¿ªo|²cöýòµÒÊŽ`o!×¼4JF�þP¾^¸¿(@hþ• ˜%Æ –x1ÂZËåO¼-_Nœ&3¦O’ñ£Ÿ“!ÝãÄfÒùYRòþßÚ�ߨ IDAT+nl,vÃ3º«Ü4âK™6‰,�?]¾1TºD™‚á�¤a?Ê� @…Áïfy{`”˜Üìbyâý 2mÎo2{ê7òÆ=}$Þnf}¹nÂ�ÒíI€é 'Ý$1&âèv§ÜÛ7LB›ô‘kn»KîzxŒ¬óWŸK�²ª¶�Ÿ¯Â)·H]qt*wˆ“ø3o‘ÿ|ò½L�>E&Œz\.häC‚{Ž�õ^ŸlŸõ©|0ê¹²©MÀ.moø¯Œ=Z>øäIñ#x“¿@žì\´½¤ å±QßÉŒYSeÜ›÷IÿÁwþ rQ¼)Ø’ä�ß*á)Ø»N–,Y)Û³JÔá@È™òß ëå•3ƒÄ0ëÉ�³ü�l9ðÙ¥a˜’0ìgI�¸Ž¼÷:yíœ:bbJÂUcegÖy²S°F�´{h¶ßàqÕFž*»U­¯µwÝ©V:÷òI;b÷‘×¶=i~ËÓ±PW!ìÍ®�!ýc¥^òÍòÒ'ßËÔé“eü{�Èy ‹ë\òËÅu®X mQ•ëx±@ëk-Ýg|Þjk¡TCEåU)¥Tå�ÖÁ›ßçÏ“×Þ)¿ÏŸç÷ïëÖ¯•×Þ)Û¶m>Àyã­Weݺµ5“�joDÄJ•ŸnI»aJýÁßȾâ�dÏyPÚ8 1c/”Ñ[Kß!º—<-í†ζrÿ/éeökÉ�†Jcb„Ÿ/£w–¸!üýie7Äp%Ë +Kß®X3dxs›`IÏÄ[¼­ªoŠøv¼)ýœγåÕ2ù@ó¯TàÒå‹ËCÅÀ!Ý^\'åŠrÞ"y²C°¸âzʳ‹Ž–ã¼_6Äp´“‡æd–+«‡¦Ý)Ímˆao#O,>Úq¨(xãYøXñMuùç²²OÕ³dêí�ņ!ÁÞ‘’±Ü@ÓN½UꙈ-õº<&s3*ßJU½½ü|î†)Q_“ueêæL¿SÛœ½ä%ÛïFÑÓ!$ßÛ[jþƒ7–üü2‰0#¼¿¼¾©dT\Ä“ò©\oÃ0[3yp^å‚7~¾>8’å•MnÙùî@q†Ô¹â‹òOû};å½s]bØšÈ=¿æK~qÞ�¼oÊ'rY=S0£¥S·¢Î»«Û³²ØÏCÿ“•çÀÊn`õµ6®;Õ©CóIæÚ±r{ÇP1 §´¸s²¤Uc³�ÔÕ’u.Ú_�›9\’lEç²d� ¸- ¨Ž^_kë>#ÐóXÛXóõ 05[^•RêtV2^sÚ-²hñî»çA-^à÷ïmZ·¥UËÖL™:‡ÃIrÏd&|;®†sâaÞóçqfr2ÉÇüÓ‡‡&e—NjÄpá+£¸£…�½ß<ÄcS±òðÂð·Øà«Çe¯¾Ï°¤’‹¸Y0æsÖy ô¼Gx¢_�2s˜ â.z„Û:9�œYŒýa7Öátc¿f³ÂÎÎíKO,7"ûqÏ3÷sÛ�wqný<5|†ªŸ¥ªÁÊæPºÁÀátþ?{÷EÕöü?ÛÒi$¡‡’ „¡KyP¤(„"HQ° ¢ øø(ê‹ Š("`¡«4A‘‚ÔB ÔС&ô�ìnv÷~?$@Ê&d7›‚üוÙ�3söìÜgfî=s&÷}ÿ.øèŸܹ²DÜ�AÀ€­ áŒY�s«Wñf3Ï\ûª÷ãÃ1°¾bŠÇÒ%ûaz@5ÔµßÀò=;±yí\¼žs¾4ïÐ®Š ýØ!7¾ÜÝy,·�6cF#Ê« 3hØÓ_¾½DUýߊÐóE¸5m�ÆÎ `>‡ÓgͰ_*¶¬Ü„Û¢ÀëÉ—1 $û,GšJ}ðÉë ¡…£Ÿš¤BP�ø�'psÍl,¹�½W³œús·¤A]#ý¢œ <ωºÒó˜>½*©®cÿžH÷h��ƒF¹&'+¹:ÛµïÚ¯ù)ÄqÇîÊÁtßöïŒNO´C³:X§¾?WÝÆ.dž)QÖ wlUU ;,wÌE¶F„‹˜Ïf‹9»û¢{Û³%Æí�×¢?ϰ­Ýìì6(²ý•ˆˆî*± ‹+cúÌY…^OýzáhQàåGDbÊÔÉhiõÿ¸Cqà`,^ú 1ñ,6lÜ€.]ºº®ÙYpýäì:ù åœà›d‚ÙÂJ™vødÖëØÔ~æ½ñjt>ˆ/ãÌŠžŠoú#[VΜ€�»Îà ÂZD¡œµ¨º:¢š@½7ûvîƒñ• p6' fÏE˜¡A�F �ûüS�š}?Çw}mþð¶±·þE\-ú—S q“*Ðl>†]ã¢ñ²ÛxŒèÙ 5¼ïw›juŽ™]ͧ°{O2,P#$*þÖÒãêªhá Õž 8³/×$"ßI€·Ô @ͬ/Цôt˜L&¤©�á¢wÒR‘&…/w�¶!Ú4÷*øä§öôh/Ź!š6°2Ó§ÖÞ �–ŠT«° Ÿë4I…@ƒÐFõàž»‚¨þÔS{?ûœ5V|žFÿξX>o3fÿ| ƒß ÉìÛÍ8¼p.bŒÔíÝ ´x`0ËZáZΞjd LÇ%žQg»ö]{â5?Ž8îØC9Y’qpýJ¬ÌL‚).Ðô?O uD5xæì­�ÇvÅ¥!¢ê[™xVã…2î �š=æ ÛÙãöÆk1œgØÔnöö�ŽŽ[ÕþJDD÷”XwúÔKd»M#£Ð42ÊêÿÀŠ?–ãõ×Þ€N§Ã¹Ä,X¸ÏtîŠ:�ÕupMœÐö‹½ø©‡×–SàR6ç/@�ÒA¿m.~‰7õ}?wÔ¨YˆSìÂö�ŽŠƒBrÈþJDD÷0`媕èõ\/hµZ$$œÆŒ™3Ñ£Û³¨_¯~IW-orkG¿ˆoŽYPé…°cé(ÔÓ]Ū‘/bz|Žßÿ4•Q­’ LH8•PðQ)ꊨZQ ÀŒ3'ÎÀÚ”Ÿ’ž†´l'A ”Ì_ÉÄ”“•ësò$Û27„½õ'r0Å%uÛ÷Å[“~EÌ¡?ñj¨rm=¾[x,#>Ô•2cÆ„3'Ï䱯¦#át"ÌP «X�ùÝ2eŠÃêµga†‘Ã?F¯j9/DWÏœÁ­œqfo¹Â°§¿pt{•Êû©˜qñÜ«Ÿ+ýÐ~.²ÛÕëÓ‘N\\¹ Û¯nÄ/¿_|;ãùNå œPÐÇ~†ï¬Å5¥žŸöž-Ÿqøwoöf¾]N¦ønȬ¸âˆ�¢uvà¾ûÀxÍOIwLñø}Ò‡óÖ;˜—×Õð.[ æ×qÓžy–ì:¶Û©¸û"{ãÕÞï[)‡º»£G�ÙÿºwD]«ç�ûÆBÅA~Šk%"¢{˜¼�ššŠkׯãèÑØ6ý[<÷\O4hफ•AòocèÌ“�Šý1õÓ'Ôx ¦¿Uºðîà)8”u8°â‡æ­Â �§W¯DœÕ‹ .ĬÂßñ×ïŸ$¨Õ¼:40ãì†u8œëØl¾�"àé¤�ÇSßãræÉ—³»4 `IºŒ¤\g\Ú´ó=3’ì÷ËÛ[¢ÂH»ˆƒ›—aÎï­þ"¬”k‰îíÊC ®\¼’ñäUš·ÉŒ™õ8jmgÔïÂú¿oA¶ˆ´2¡fr 7oY¨à`eþ†ôØýÃß0‘—+ {ú G·WQPWF�Ú^PÁ„#Ûw"9Ws¥`óüeH(ÔUPþT•ŸÃ€ÇÝ`¹¸K¦,ÁÚ« ‚º?�ö½Çéö6Œ}þ#ìHÑ Ú‹30éiß, W4ùïLŒnèK¼üÚ/8ï€ ,»ëlï¾kO¼fßp)8îÜÁîŸþŸNžŒOæì�ÁÚ"’Œ}ÿœ† œ‚+m�\sèº4ÄèY›àÂâáú“õÑÅRg;÷]ûâµ”w4uݯ\ŽO{£V&戇;8òãp|´6¢òF‡®�ÃÓ¾ Ùul·K±÷EöÆki;ϰ¯ot|äWÅâÚ_‰ˆèŸ�ÅgÐ$ñ4I âÛ3 ´åÁ°R^(§@'/?ñ÷÷/À_y©;j‹ED̉²àÙò¢‚Z‚û-•+–ì«OÙ6JÓ)¢¸Ô—÷vÝÉòŽQŽÏê"�jE ¸IÕvƒå¿§È×S>•1ƒÚKˆ»"Pœ¤ú�r)Û:Ódÿä¶â£‚(*/©Õq�¼ý¿÷å�—:K�²jQ ’rm&I¬>KÓa™ØÔU@TeêH××þ'Ÿ|:NÞö´<æí.�Þý\WP 4µå½Ò³´Í_òjEµ*ñ¬ÝY^zý5yéã?3?£½õ'²“å†l|3LœˆâRQšE¿.LøB¦L™$ãF‘'C½D¥(âTë5Y{-ëN—&&?.åTEã+�z¿#§Í�éS>’מODÑV”çæ�S–Rúe½ÅC�¨«�”Æ»¯šåä7íÄS�(j?iÒÿ2é«É2î�¤]ˆ‡è*ô’…û”ÎîŠ@q—úƒ&Ë¿l— f{ˉÖ¾(*ˆÊˆ¬1ØÚhvôv¶×ëiØ ÃU•� \•eÓ1™ÐD+€“´›~Q²~súÅωK®ï@DÒ�ÈÔ¶eEˆâT^"º –×ßxYú¶«!šòÒù›ÉÒËK¨«ÉˆmY ÚèîñA)ŸÅ›²¿w{¥ ,¯¢ +±éÙß¾[w]³IrÒ|÷U³$.ì)Ajˆâ\OÆìHÉoã÷Y ñP ª2må«£éù,[´u¶kß5Ù¯EpÜ)T ¥í—I�ûdìk*7©Ø¤“ô»­ý…=íU¬É±\ÿG¾µ½ÔðÖŠˆ¢r‘ò {ÈËOHš~¹ôͼ|k{%oD/›_¯"jÅIš~v\r½k%’ÿ­t,§(nÒø£½’ö í�Ê—m¼DE<š}š#ÉVø¦ÓÍsˆO¸xø£R%?ä.boý‰ìeÄÍÄS8uþ*RLj¸• Bµ� ðÒ>¨\:n$C|âuÔîð¯RÕü]íºõÇ|;G�œÅ ‹ |«ÖBu?—l¿šn_A’Þ>>ÈzG€½å ÏÖþ"£Œ£Ú«Èˆ ©7oÁèä…2.™7Üš‡.þý°ÂTïïù†óAŽŽ`ÿ¾k{¼–ÊãŽq-!§/Ý€^qAÙòÕRÑ ìvlfO¬Ú®Dú"»ãµ´�gØÓ7E䣨öW"¢G‹ï Ïp7_Ãä Q>$õ2Ž>‚“É^ˆøOý\s€þŽší¦â¬K7Ì?·ÑeJ¦žDÄx%"¢—¬É›Rõƒ&QicŠû]š¶A§ÎÑ».9û$ wbñÕ‡sqάB™öÝÐÖ«¤jID㕈ˆþ½8¶›ˆˆ(Úˆ71¡ß"<ûÓ1|Û9{;wE›0¨oœÂöß—â¯S©P|ÿƒq㟃oß$*QŒW""ú·bò†ˆˆ(?Š?ºÌØ‚?k�ÁûS—b×âo°K@�âì�úÝGà½ñcе:gw *qŒW""ú—bò†ˆˆèA4Ah7jÚ�ú·.œÅùk©°8y#°b¼9[:QéÂx%"¢!&oˆˆˆ L ÏÀjð ,ézу1^‰ˆè߃•bLÞ•b6'oꇇE=ˆˆˆˆˆˆˆˆÈ ›“7ûbc‹¢DDDDDDDDdo›""""""""*Ř¼!"""""""*Ř¼!"""""""*Ř¼!"""""""*Ř¼!"""""""*Å4%]* ý5\¸š ÑxÀÏß Ú’® &o JnáÌ�x$§‹õ÷j�¼|Q±¼§ÃÖ°ú5Ôê¶©!#±õÐDD2{CDDDDDDôH`ò¦ Ò·â£¶OãÇ«–ü—STpñ¯‹ö½_Ã{ï@D9Þ™FDDDDDDDöcòÆfj”�x Qs}˜Ò®ãüÑýˆ=½+&Æê¥k0kÃ|ô«Êf&"""""""û<4Y…¹ófcßþ}6•yì±:8`�ƒk¢AÃW~¢þÞP¬¾¯ÇÙµŸâ…~cã™ExíÕöhýÇ`Tà"""""""²ÃC“¼™3g.F�yf“ zƒ½z½z½z½½zÃý×ÒÒÒ°pÁÂ"HÞ<ˆ3*vøó>‰AÍ!«pkãÏXyi†f¤zÌWO öô ˆkÂÂÊÃ%gqË5œÜ ×Å�aa̵@ÞÌ·ðÏÖˆKHÂm³ |+×AÓ–¨ìÁÌÑÃê¡IÞT«‚~Ñým*Ó©S§"ªÍƒ(ð‹ŒBuÍ*ücNÄ™D3¨ ¸õÇ›ˆð,õ>ÄÞ=:GÑÛbD³~Xaªƒ÷÷üƒà ðY’°åóa:nŽÞ²àþ”Ê TžµÐýý™øvD3”³>TˆˆˆˆˆˆˆˆJ±‡&y3ýÛé˜þíô’®F�YnÞÀM •;<=Š0k"7ñ×èöxêóXè=ë"zÜ;ðx-”µ\Á¡ußãÓÏ—`ÑÈ'q>}36Œ®碫 �bIÞ,\¸ .,в½{÷F¯^½r½>gÞlì·uΛÚu0ð…â¾m €\ÃúŸ–âŒPG¡YÕœÃk'ýŸÏ1üËHÓ†áõe›1¹M™{sñ4Œúž¨?Ý~ÂŽOÆ`^ß•Ì[¨ˆˆˆˆˆˆˆ&År%�èèè.—WâæÎ™‹ÖmZ¢eëˆlÚõÔCXíPT ©Šà Aðñõ�‡§;´:-,3îܹSà„‘Ã˜ïàâÁÕ˜:¤=zf•75Í�ŠjƒFìœ;‡Ó·#1¦u™“(+ð}j$^¬§…¤l‚åçñ€�Q)c×È›é3gY}½~½p4‰ˆ°úÞÝäM^ •èèè<7P­j5¼8h˜Mõ,š9oŒX9ÈZ+zÄb�E2fœQtAh÷ßyX0,E6îÆœ€�»Îà ÂZDYŸÓF]QM Þ›ˆ};÷ÁøJÞ:EDDDDDDô±+y3tÈ`»6–W§ #s¦OÿÓ§g×vÍÕ§"Üs ZÒ_ÅÙ 7`Q—G»·Æaô‹Ïâñjîyt·RÓ±1ö"=Yßý~°ˆFàØÏ|;ÿlÝ�¸„$Ü6»À·r4m�Êy��ý%ÄíŠAÜé˸ePÁµ\jÔ�DÃje²|ñ‚›gbqâÒv¬Þk„H Î܃=WÕp¨…ÚÁnPŠã•Brãö�¼xTFÝ>Ð.a߆õˆ9q&÷ ÔnÑ-«{Ý›ù=íün¬ß°§o ¼‚ë¢Uû(TvÏ;‚Ò“�`ûÖ=8zî*ÒW”«P Í"QËG—kYóÕˆ=}â„°°òpɹ€åNî?…ëâŠÀ°0æX `ýAnöô=yÉÕž’‚„�±9ö n˜]á[µZµi€@ç¼×aK›Ù[în[óêÔð…6=‡·þ…˜c—‘¦õFÅÇš£UDE¸s€"Ÿ�ÅgÐ$ñ4I âÛ3 ´\q­ÇŸÌÛ%ßÿyXîèM²rÏyY¼í¬,Ù– ó6�”%ÛÎHJZºLüy�|2oW×$]bF× Ú&ä˜ÉÊ"æ+²yBw õT‰îý)¢ò •g?ß*É–e,7d÷×}$Ü[“£ Š‹Tl;J–Ÿ1f.¬—?”ͽÔòöv1æ¬Ñ#Dÿûóâ­@t-¾�ã'É�ÇܲŊ¢ �vŸí‘Ë-ÙûÕ3RÙIÉ£ºà§äëi¹Wœ/‹F´–`g%GÜAç iõæ"‰×g-`‘k?u'@´õ>”ÖúŠs¥³3š:òþþô,Emé²°§ï±¡=O\Ø ï· ­’}ÝN•:ËÔý©h3ûËÝYØMœÑFN�q?IßZîÙÛ@шo䛲ü¬µ/‚ˆˆˆˆÈ1²æk¹ß ÇÏ���·z¶©ŽÕÿœÇÕÛt�ª€nQÑ(¤’nê±l{†>]PŒŸSr••›økt{<1z Ž)�!zÜ|¬Ý±{¶­Âì±ÝQÓr‹F>‰ÎöC¿’– ÃÓÃçã@zžó þ¾ë×ý‰Å3?BÿFî8¿ñ3ôê:{� Eݦ`ÆÄÞ¨© ©Žžãg`æÌ÷l5>åŠiŠV­Èͽ˜Ð8¶…ŽÄ÷¿­Æšß~ÄÏ„ÀÉ| ÞŸN}=>:‹VcgcÅšÕX6ë]þñ7¬Y·KfŒÆµ0&üŽ‘/MÅQ³ÚÌÎrj'Ô I1¦ç«ØèߟÏ[�5kÿÀüÉÃÐÜHÞù%¢Ÿ�ˆƒéö}3DDDDD6y”FÞLû-V¾]~@n§eö†“2íÏc2sm¼ü°î„¬Ú›(""SW’Ï�é+Ë�ƒŒ›»K¾Y¶¿ˆj”ÿÈãž÷¤ŽVE&ol¼.Ùä¶È•夒¢xt”™çÌ™¯_—ù]ÝD�V}rXrý.œ#ïÖuWß&26æþ¯óæ³S¥µ]sùâ”9g)¢G’aí‹ ‚(ŠZ*ô]"—²á�õòr%µ@QDÑT—WÖg�Ñ[+úg”uë* nÞ=õ¯áRU Q´µå­-7sÅõµµÃ$D Q4¡2f·ñþëv�¼±¯?°¯ïy°ûí©ïv_Êá#^RÖ “JjtÍdr–~Ⱦ6³¿œ~YoñP2Fy´ü\rÔsÇ;RG«Tþ2à�”~"""""[<²#o–n‰GŸöµ°úŸó¸t=†t3ôÒ &tl„•»ÏAo4ãŽÁ„¸„똻á8†v Dz-ñ%P[#vÎ�‡Ãé€[‡‘ÓºL޹gø>5/ÖÓBR6aÁòó°€å6®]O‡@�V§Ë=_�K>ú'w®ìÄ�ì”GD6u(Œè ÿ¬å�¨zZ("Ð4‚×sĨ{ã(ÔÑb<�³ï#1`ëÂE8cVàÜêU¼ÙÌ3W\{?>ëk!¦x,]²?ÇêldW`gßcQUFÿ÷‡"Ô)ûënM[£±³˜ÏáôÙ¶™ÚZå�£^BhŽiqÜ¿„kK2Ö¯ŠßQQ+Ñ«÷é3gzõë…£IDD�–íÖ"ß,‹Å°.u1wÓIÜNK‡F¥‚¢ÄÍT#®Ý2àÖ‚ʹ¢ÏãÕ1mY,º¶¬^èzÚÌœ€�»Îà ÂZD¡œµ9OÕÕÕ4꽉طsŒ¯T€³*�›T�fó1ì�—ÝÆcDÏV¨á}ÿ«V«y3‘-׺hš³»t‚——3#ÊÖ G¥a¥x–�—@ôHÓgÞ“c>…Ý{’a�!Q‘ð·–>WWEã_¨ö\À™}±¸&ð³wÖp{ú{ûª¥87DÓN¹ßÐzÃÛCÒR‘šVÈ6³¾­§´ŽrË]NŒúõý¡ÞvIG�!IÚ �3»Q*ÑäÍÐ!ƒ‹u{Þ Çøù1˜¶<ú„cæšã¸~Û€;útLy)ý>û ‹ ¨œ+Æôª‡i¿ÅBQ/?^¬õX."ñ‚€àðW]>ÇzÂÅ�” ©çqÕ©´ˆó>ØÕc7ïÆwÃÚaÆð2¨Ò°%oÛ;uÁM*À•D¦¸{ÂÚÕ• €wO�Ü£ZTªÌ×÷¦S1_ÄùKfZ”ÌcN)5ý¡ÆX._Ä àgw¾ÕŽþÀÞ¾Gâ±pôx¬IÊ1G凎ïŽG¯�ûëQܼॵþÙÕ™í\è6s@[+e+ ‚›µÎRß_¨p–ëɸn™'"""¢"ôHÝ6 ãñß"øö·X éPÁÕ[zô™¸ f³%[âFÁ»}›”LEŃ1ãÁ&b2@¯×[ý� T­V UËéî ùW¼¢ðÞº8ìšÿÒ1þš[8½sf�{ =¢ª¢bÃþø&æ: =*Ñ#CÉ�œÉún�“¡FŒësr²rS&­.ã>I7ÀXÈ@µ¹?°·ï±\Áî%s0{öììs–b÷• %ÿöÌÎÞ6+|[+Î.pΣ N—‘}£±Ðßу<’“žŒéÓøÞœQ=ÂñÉ/ûqöÊmTðuË–¸SR‰PÜàá®Ð¢éØmX;´¼ ;4¾hý_̈þ/$ín]�u«Wàçù˱wß " º=`H•G.GTrW¸¹*©wR!È9Ÿ Òî¤B(®î%g1Ã’WÁ–þÀÞ¾G©…Ó~ATJÎ ˆ;jÔ,Ä¡ÆÞ6s@[‹> iy´©>Í�Y=7Žd$"""¢"÷È^¹�éÓŠ¦ý¶cz†#²–ÞíUßü¶¿ä7 ©Œj•4P`B©„BMZª¸ nû¾xkÒ¯ˆ9ô'^ ÕB®­Çw �ÁüàâDä(êJ¨ZQ À„3'Ïä×éH8�3è*VμG�’9ZELé0YI(˜“¯ ¹3?°?°·ïQÊ¡nÇîèÑ£Gö¿îQ×êÄ9do›ÙÝÖ÷ÉÕ³H¼c-{cÆ¥óa†Mù`ð–)""""*b�lòÆôm ‚iËbñ|»˜¶l?T@É'n@ñCóVaÐÀŒÓ«W"ÎêãL,¸³ Ç_¿a’v7/Üß"ÕÚj˵D÷vå¡‚W.^±ò”áíTDEE„æ-B �g7¬ÇQký.¬ÿûDÑ¡a‹H¸g¾ììî�X’.#)WÖÕ‚K›Öã`ÎõÙÓØÛ÷{Û¬m}—wcãÖ”ÜåÌDZ3æ,P£Fý:¹Ê9Ú#�¼25ÞNèùÁïðöp.¹9nrQ#ìù—ÐÆS�éÐT¼1é伄H;<Cžî„–¡¹U°\Z„W;vÇ€Þ/á³Ý·s'bÒâ°iû%X-ª×ªzoOE£…F`¾Œ —8‡¨hhP¯ÿ`Dº*H?0 ïÍ9•ã1Ói80u,æ$˜¡*û$†ô¬t¯“ÖVEˆ°$¯ÃÒÍ7³Åvúéñé6X4ÙG¸Ø×Ø×÷{ÛÌþ¶¾K‘$,7{²5€ iå$|0Š6 Ï<–ÇdÈDDDDDŽóHÎy“ÓËÏ„—Ì¥@Ui ¾ž¼ ­_Z�-ï¶Dø†hDw¨ƒòNi8`ý²'îèP}ðÝ,ãA½ªÊý1vØwxòËø°ÕcX÷LW´«We�-H¹xÛ–ÿŠÕGÓ¡«ù*F÷¾w±¢”«…Zþj¬?{ 3†ôÀív•Ÿ'ðñŸ€/çs ru�a˜ö ÍÛñûK‘ˆÚ0Ï5¯ÏôK8´~!f¯<‚ÛšŠxvÊdDÜ>uسèÝhbwœÁÌž-p¥ß3ˆrFJÂN¬øyœ‡}ˆ>sßÁ¬‹X2‡ÔÙÛØÓ÷”Ê6³³Ü½òÕžÆÓÊd´m´ýûþ�ù«�tàwüøÃZ$X´¨òÂ8¼V—‡Q""""*>'ŠÏ Iâ3h’Ä·3fh¹âZÏÃ-]bF× Ú&ä˜ÉÚ29óçÇÒ³�Ÿ8)Èx PTâV¡™ øâ/¹˜ž£ˆé¢ü5©¿4«è.ê¬e ˆÚ£²´FF×ÔÔ!òöŽ,¥íêDìê{ ÚžþCdM®öè¨|dજ Ø×fö”Ó/ë- DSc”lOÜ$Ÿt /µr¯¬â$-‡ÿ,ÇÒlûüDDDDD¶Èš¯Q|N(ƒ¾“f�x`²gúÌY:dp¡“FŽZϣÂ;—âqüLîXœP¦|5T¯\NùŽŠ1âfâ)œ:)&5ÜÊ¡ZHxió.aºyñ 7Tªä×GþÆ:¢¢”Ž ÇŸxµ;ü«ÔD5×ÜÏjÆíÄc8vöŒN>¨Z TÛûƒ öô=EÉž6³­œá·>ðí¶©!#±íðD4цä“8râÒ4eP¡f-{ðf)""""*Z¾ƒ>ÃÝ| Ç{?4Tp ¨‰ú5m(£ƒWp-Ô.x �W„Ö­`síˆÈZ”©ô"*ÙRF �à04²!®3ØÞd°§ï)Jö´™ýå$s¢ 'Ÿj¨çSÍÖ�9ÇU•bLÞ•bLÞ•bœó†ˆˆ( ]›O°mßHXt~¨þÀ �‰ˆˆˆˆŠ“7DDDY(^•P'Üæ‘‰ˆˆˆˆŠ o›""""""""*Ř¼!"""""""*ÅlNÞÔwȆµ"""""""¢3›“7ûbc²aG­‡ˆˆˆˆˆˆˆèߌ·M•bLÞ•bLÞ•bLÞ•bLÞ•b𒮀þ.\M…h<àçï­•E$ýnÜ2BëQî:¥Ø«øðÐãÚ…«H5<|à¥+éúå�É›â&·pæ@<’Ó¥àeTž¨T§|­]­Ñ#Á°rBžýÆ�‘Øzh""³ö©0ë•AøßÏ{qY/€W_üvy.:;•XuK7Ã*¼Z³;¦Uň-G0)êA�« Éñpæ¦À50 a�./gíÏ7×E€óƒ7/·Ïâàñ+0  ò¨ˆÇjúá‘ϱ-ÿ…òˆ"""² “7ΟOÄú�ë ÕhÑ42 UªT-º�¥oÅGmŸÆ�W-/£k�©'6àÕ ÿþ»Ü,·q⢾U+›É*z劵fµ J¶A5fúr ^™½éj_„?ÙaåêÃ÷ßß]£;XõV3<ÿ» ÇÅb×»¡PÙûsÅO}¿¿€üÇ<™qä«nhô¿½H@×lŽl�ª�ú÷Ŷ|¨Yï·òˆ"""² “7þÚ² ë7D``~þu!Ú¶i‡š5kñVÕð¯×�‚ �¡ÐÖAe—GáNz�>õÂgG7ã�*<§GMÞ1àÔmn¥/È]D’±msŒ¢Få¡¿`ûÔ6àïÛŽæ ww Xàîá–;¡ (P�‚�s!¡ÿk¨œ_ו¾óçÇŠbÃÌGÛò!”W¿õ€¸!"""›0y õÎèœtpw÷@ÿ~0{îOPÄ  "Þø+ú{ó„æ.¹ŠÝ»âaF£’® Qɰ',·pó–€ÕÂj¢wš�͔̋Ït¸¹[¹U×@í�S8´m6}ï†å=¾À°c·À§F Hü1Ü*Òz?„Ø–Ÿ<û­Ä Ù„É�?Þ«Vÿ‰NOuB`ùàbLàØÎxåâÎÞ†¨Ë¢jxUxçúUR�r.Ç.çÔª ·gLæÛ øgëÄ%$á¶Ù¾•ë iËTöȤ‹1é0¶mÙ�ø‹·�îâ‡ê�Z¡UxrN«a¾z±§o@\ƒV>÷(Ë5œÜ ×Å�aatÜ<‹—¶cõ^#DRpîà칪†s@-ÔÎ~Ògoý‰l%7NaßÉk€GeÔ­á�¤ açFlŽ=ƒfWøVm€Vm 0ŸŒIzòlߺGÏ]EšâŠrj!¢Y$jùd�™ãÁ1€ÌºˆÓݸÜ<‹I§�˜",H9w{ö\€Jåg�iFCM¿•ÛpópÍ}ª @Ûž8>uæÍý#ÇGX�P¸ƒMs!AÊ¢G«:XwüX¾[-ؾ“ùQmîw³¿]ßg�”d[Ê$:ŠKzîj£–“FÉMœ‰=�d“‚2UÂR.{‚©Pû¸áömX�˜WarBííѲº×½Gƒ¦�ß�õöâôM�Wp]´j…Êîy§EŠ6ÞÔoéò�kM[l}náÊÝ�7xVB�¾Ð¦'ãðÖ¿sì2Ò´Þ¨øXs´Š¨wž–‘#ù œ(>ƒ&‰Ï IRßΘY åŠk=Žrôè™úÍ9}æ¤ II¹-ß|;UŽ=âØ VÊ åT8I§Ÿ®‰ÅÆâæÄòly•@UNžšuFÌ9Þ·\])ƒ*©Ї4Ÿp@ Ù _‘ͺK¨§J@pïO•g¨<ûùVI¶V!ãY>ª�;)YÊ@ è¤|Ë·dÙicÖȵŸ:‰ ÚzÊ“•õݘ+��!ÐÔ‘÷÷§‹ˆ^þP6G� €ZBÞÞ.÷Önoý‰ì¤ÿýyñV º_ȉ äý6¢U²ï{N•:ËÔý©¹ §ÅË¢­%Ø9GÜ¢8I«7I¼þÞ–úÅω‹QW);Œe–÷õ´R¢¸w—‘Ïùˆ *ñ~ög¹šG\˜OL’f:E ©-ïíM/X£XnÈî¯ûH¸·&÷¶©Øv”,?cÌ]ÎŽø-LûOü,/Ö/#ª¬Ë+jñn0L]$½=�ºšŒØf¥®¹¤ËþêŠFå#ÿÌÒ«ÞíÏu-dÒšO¤±Nu¥WdcZ«¹¾X¢}T¢òí+?ÏŽ¢k6INæìÈmÚwDìëwï-¾ï3_¥¡--×ä—çÊŠ *)Ûk±ÜÈcӦر®�@[O>:˜¥± ¹�?±H†<æ–­¬¢ �vŸí‘Ë-ÙûÕ3R9ÛqX]ðSòõ+�T,ñö ~+�¸ÉGñõ¹…+wga7qD9AÄý$}k¹goE#¾‘oÊò³Ö‚‘ˆˆ¨à²æk˜¼É¢X8…LÞˆXäÒÒ~RA Qùu“¹‰YÎT-7dÝ+!¢QTR¦íWr4뵘å†l.® DåUWz�›/kwì•=ÛVÉì±=$Ô](ž5~Ÿd; ´\‘߇„ˆNQDÐL^œð£,]ù§,ûi¼ hTVTŠ"º¯ÈÚk–{õ³ý"Â,g7Ï•™{KM šêÒsü ™9ó{ùe×匕½õ'*ÃêÁâ§‚hÃÈ«m}% é`ùô§ßdͺղdÆhy¢¢N(âÜd‚ɺ¯[.Ê’ç+‰FQDU¶¡¼0a¡¬Ý±GöîX' ' �Þ*�¢•*WÈ‹HAb wòÆ, ›fˬã¤GUµ ë÷¹Ì˜9Sfý´Qެ&ÔÅý ™uÁZOc’ã#E§(¢k2AŽèÃ"WEK€ ¢¸×’®c¾‘…¿¯•õëþ”Å3?’þ¾¢Vq©ÿ�ìÉz­fgüÚÝþúy/ÜY(âúœŒûyƒìÚ#››&o¶ –2õ›Kw[’7"ú‹‡eÏžXI¸•¥-ï%šÊçG�ÈgM�DQùKÿ·¬·Ýœ.⩨¤üÀ•’¼¸§¸ZK8ؼïd¬Û¾äMñ~Ÿù*%mykùóâ§‚¨¼{ʯ׭U4]þyï1Ñ@§¨Ï%þîö »�×í+ƒš•—°gÇÊ¿­–5¿ý(<"Î Dqi&ïMyAªø4�þãçÈŠ5«eÙ¬wåÉJû¿{‡ïä\¶Ï]\ñV€~ËZÜä·[Ÿ[¸rú¥½ÄM�hªýGžªí.�­^‘IóVÈšµÈüÉ乿F(âÚä9P°.†ˆˆÈªG:y³}Ç6ùò«I²}Ç6«ÿ>rH¾üj’œ>}â^端¿�Ç9¦…NÞˆˆ%Yþ\E4ŠJ£•K™+¹½e„„jQù<)3Oe?{7îyOêhQtaòÆÆë9¶k‘+ËH%5Dñè(3³œê·�”šE×H›ý4Ürc½¼¢(NÒdÂQ1e®ËÞ_€Íg§JkºæòÅ©ì?ŸÚ[¢Â0¬}1ãÂVQ‰w»/åpŽ__SÖ “JjtÍdr–}6õ¯áRU Q´µå­-7sí¯×Ö“5DфʘÝ÷Ïìó‹�ÜÉ›L¦c2¡‰V'i7ýâýmw˘P�@q––_žÊ5JOLGåÓÆZQWi;ílî÷­º.󻺉­4úä°ä ïÔy·®³¸ú6‘±1÷cÛÞøµ¯ý-rua)£@Ïö2-G_(ú8™Øж¼³F^ R oyî—œŸMDÒcdt-�@q•vYâ¦ðû¸Z*ô]rïxžQ—õòr%µ@QDÑT—WÖg_ï­ý3ʺu•7ï¿^¼ñ–¿e«âîsí-§_Ö[<”Œ‘@-?—Ã9¥ìxGêh�Ê_ü‘R¨6!"¢G[Ö|Í#w7nÌî�xýµˆÙ½Óêÿ¡µÂP³F-¬^³  ÕêÙ$K–.rpMÒ±íãh‰È|ÿZâ­?og/ª”ÓŸÍÀÐêj\üõ-¼ó{2,©;1qÔì�g¾ø«d½߈�sçáp:àÖa$Æ´.“ãÞs¾O�Ä‹õ´�”MX°ü<,wË-ø'L€{‡W0´Nö›Ì¯Öxíƒ7ðâ°—Ñ>P�t·PáëO䢪ŒþïEhŽ)0Üš¶Fcg0ŸÃ鳿ÌW غpΘ8·z119 IDATo6ó̵¿z?>ëk!¦x,]²¦¢¨´¶>úh Ø1gŽ˜³¿m>¶‹ö¥ží1 G0 t0°ÜƵëé(Ðêt¹ç°p‰ÀGÿ¤àΕ�ø âîL)…�_ÛÚ? [þØ€›¢À£Ã ô®’cÂ[§ÚxqøSðrøì©*õ€ÿx7×ÌÆ’ Ù?…åÔ¯˜»% êÑèåœÇüżï”Ð÷ù`%Ø–®­Ð»{E¨åÖ.^ƒ9b•¾ûW,‰7Añh‡~ÝïÆ�öqu(Œè ÿ¬]#UO EšFCðzŽõº7ŽB- Æó8{ñîþ_ÜñV4ЧÏu@¼©üÑcÔKÍ1-Ž[ã—ðBc-`IÆúU1Ex~DDD�’�°xúÌY…^GýzáhQàåGDbÊÔÉhiõÿ¸Cqà`,^ú 1ñ,6lÜ€.]ºº®ÙYpýäì:ù åœà›d‚ÙN*”2íðɬױ©ý$Ì{ã-Ôè|_Æ™=ßôÉq!fNÀÎ]ça†a-¢PÎÚ™®º:¢š@½7ûvîƒñ• p6' fÏE˜¡A�F ¬\ì¨Q³ïçø®¯ÍÞ6öÖ¿ˆ«E�Ź!š6°2y©ÖÞ �–ŠÔ´Ì«<ó)ìÞ“ Ô‰Š„¿µ¬ˆº*GøBµçÎì‹Å5‰€ŸÃ“ jTï3m>ŠÁšó0ïŸQqwêW3Ž,Y„é*ø<=�} ¸qU7©ÍæcØ5./»�Ljž­PÃûþ¡D­Î‘,q@üÚÖþ§w8 ª×¯ w+›óhصµ¿b›ƒ¯?Ÿ§Ñ¿³/–ÏÛŒÙ?ŸÂà·B2ûb3/œ‹£u{÷A-¬']Š{ß)¡ï³ J®-�Õû9T›6ñëaÍõçЫìÝiÄ®EKqʬBÙ'úáé»qãˆ}ܵ.„æ<%s‚——3#ÊÖ G¥_…âY&ã¸,z¤éïîÿÅoE¤Xú\KáãMqŠ@ë(·ÜåTÁ¨_ßêmç�tô’¤ ù¸-""*¤MÞ 2¸Ø·Ù42 M#£¬þðà¬øc9^í èt:œKLÀ‚… ðL箨óX]×Ä m¿Ø‹Ÿz<è¹' \Êæüå,ƒG‹ñýÛÐú“9øïš*ñí”îȹ°å"/XÕás¬?zÕ�” ©çqÕY."ñbÆ#ˆ}| öË|Q°·þ�ܸ2**Š›¼¬>òF uæ~vïRÆ|ç/™hQ>8Ö÷V5ý¡ÆX._Ä à—÷‘í¦ ì���Þź_â±pÎ6|Ñ:ã"Ít‹Ç!]„îýÿÏ{u�ÇÂÑã±&)Çoñ*?t|wÈñkSû[’q99³ßò÷±Úo©ü3.Ô>xÀúwGð‚o3gâ^‹ºé{1oALNMѯw(ÔÈ+áPÜûNÉ|ŸSrm©m�ž¡“ñqÜz,Zs=£Ëfƒ ;ðëÒ˜U~èܯ#¼ï¶‹#öqwOX{@—¢RPàîéaå)gªÌ×$Ëþ_ÌñVDŠ¥Ïu@¼)e+ BÎGzT™çMç`¹žŒë °úx""z´ðò6Sì�ýXºlIfâÆ çÎ�Áœ9sÐùé.¨SÇщ› .Þ� Fp¾A(çš×Ï5®k×Á*PàY»ꕵ²¬a0f<ALèõz«â„ªÕª¡j9]ÆÉ°a0dŒùÑjµzÌg‘°·þDŽ¢(6ìÿFŒ ÀÉÉÊ­(™´ºŒqö’n€±¨®„”²è4°Õfœ[<ëS2^6\Œ%‡MÐT‹Æ€–Yžm¹‚ÝKæ`öìÙÙÿæ,Åî+ Å+ וֹîùÿ‡!Ã᯹…Ó;W`Ö¸×Ð#ª**6ì�ob®ß¿°rDüÚÒþ¢‡þn¿eíV Pk QM�æÒ²?z…h`:4sbŒý¶¹ø%Þ ×Öýð\•ü»Å¿ï”È÷Y@%Ö–š:ˆîUZÜÂúE«p-óuýÖ_ð[¢ê Ýѯm–1]i“ü÷q¥ »kqÇ[Q)–>·ðñ¦8»À9�‚:]FöIŒÆ¢ë㉈è‘R¢#oJ‹#GcÑâ_1zÔètN8{ö4~øéG<Û£'ÂëÖ+éêåInnÂÿ†MÇIø£BÐ $þ9 Cl�僪dÿIqÃÿ³wŸáU]Çÿ{Kz¨B ½i@šQDE:‚]ÅòÚAA•ªHGiÒ{—Þ{‡„–ÐKz¹÷¼(&á†ô‚žßóäCîîìÌ–™{÷ì̬§‡X©õÙ&Vô-˜¼E†în`',4 ;¹Ò'Úg·aOəԖ_©¬p¿ÞáaáŽzÎ aáw†Cºy�h|6¸5ìA§2¿2ôø¦.½É³í<Ø7{GmV*uîB�¸s5XÊÓí—?¨šðѲåâ|]XòQÝÿ#Æù„DsàïU¬\¶€™Óæ³kÏdÞl~§�‹è]”ùõ×pÁÕåÎñ�ŒˆDÈù@~B¨-ƒî¦¬5èҹ߲Ÿ?&¯ç‹ZµX7e6gí9yáå6|èz^;kw³ëù̲ci¦\{žøb›WÏf鵎töŠ`ýó¹`³Pº}žŠ7Î(}Ge§²d–Ôžët¨oAb#È"#¢îÏ=CÛx¥”RÿÚóX¼t1^ê€Õj%0ð ãÆ�çÅ6í¨VµZV-qrƒƒúðó1;>ÝcËÜ÷¨êt�¥û0æD‚çh–â”ò±`KàéÀä?5£d13`#àd€ÃADLÜ_.ÆÝ'fC¬ƒ5¶«—¹š’,S[~¥²‚Ùçn½‰%àT@"×k �gÎcÃÀ©XñŒíNo­N·®Õp’,ÿc7¢w3kÎqlÎ~¼ÜÉ7A 7/•›µåÅ_Œÿ×¶•Nž†«7•›t¦ÿð?Ù~h ¯W°"×W1vƱ;mFf×_S æ¿3&*èüE‡í–íÌ ÎdØ|«f|;uÅÏÙNÐâyl¾¶†?^†|Ïór˼¿‘Nõµ“~ínö:ŸYq,ï0•hGÇ:.²š9Ë®#áëùsa0v‹/þ�ªoDOvúŽÊNeÉ,©=×éÐV˵³œs½±|!–‚EðÖ!SJ)¥Ò�o€ððp®ß¸ÁÑ£‡ùeÌh^z©=�?^=«‹õÂÕEè;þR¬+£¾iNá'>`LÿÊ8Ý\͇½Fr(:ÎêF~žªï‹g–-æ Ã×ع¸})OÜøçŒÉ›ÚO•Á‚�³«Wrø�_6±ìù¢&9œ-x>û+—îþ~qñpÇb€ýÊ%®cr  Sžônïs¿!N¼¤�©p;z¶È�q{Ÿ¾9�3’›æÝ^xpró$؃gñz³¶tëø Ãv„ü$“s�få[å)ø~rn Lèú;‡ÖÅj¿ÀÌ7Þ`Æy(Òe$Þóú§ë¸›�~‹… ‡±}pO7ù›/Ÿp»³Ÿü4b) ^YÀ†ëQeµ?þM+QÐ9‚ ûW3ë�Uœ s¢L¯ïTçŸÁü沯òÓWKh<`5Ë߬EµE/Ò²faÌ—÷²dÖb^ò6üœá=þùQcömGÇCÙ·%€ñíër¹Kkjv!4p+ f®Å¥ßçtšò>‚ìØã<7ò–§|3«Îžf\ï iì^Íùò£æäKeù•Ê æ²ýøå«E4°†…¯øQ{u^zª9b‚9´j“!ÄRŒv#Gà'‚ò°:�ã!ù%ÉÈKËm)8gë7–?láóú�±²õ 4®Zœ<.vBƒŽ²iþŸ,;ƒS¹×Ô±Èý6!µíOjåhùÔ]È€õ‡ùluø·£A)¶²àÏ„4{�v›F1óbü6(ýäiÑ•Öfó[P(–*éor¡Ä¥öÚIM»ûhœÏÌ?–÷söjA§y˜?s6?͈ÁîÑ‚Î/uü³lô•Ùeyèww&Íõ’êz“ÆkÄ\ê9ž3FШÆºv~†Ç ˜¸²![A ÝJ‰îƒy£²þÔVJ)•N¼z|+^=‡‹WÏá’£Ç�OÖz™µ�GNÔbéž×tçUÉþ3IÁ¾+%Jl8±•ä7!æÂ�dö%»ƒ Bd《âdâ\q€l¸/s Xò¥´<¿8q¶o˜Ä½héöý: ŠqTèP9âmBLzËò(G+¬–~…L‚ÉKz,M¸B¨™9PZ”‹[o )øDgºò¼D?°ÁÄë@äì—ÄÕ@ÌeJüjsL†>ip–Æc‚ÄQ«p§¬[d`Y‹€YJ¼µ^"SwHDbƒdÝð®R§˜‡˜ã=‹Ký^#ecp¬£¤¸þ¦åøÛ¯l”aí“Üã~^†S~©Ùë79ps‡|èkLå••Ž6œL÷Ús«Ÿ ;‘pŸ#eý[%Äl8K­aÇå�¥wϧS�árÊ–`aª®�T¶»™x>¥cyOÈ¢îRÀtç{8w»™r-Ñ &’¦k¼P?YýÀ¥)‹ºå³”°ùÁrFÎ’v.–JòÉÞ„;3ë[RßÝÉ—ùmnêÒEÎë(žb)ûžl>¿V†´© 9ÍqÚ—ÂRïÍ™r,"åÇ@)¥”Š+n¼Æðêñ­`ÜéÐye»I{ÆŒŸ@ßÞ½R$ʨí¨Ô°|‚ãW³;“«`)Êσs’OÈb¸xœÓo㚟RåK‘/±wd`#äü1Ž�½N´³%+”ÅÛ-é‘z±·Îq"ð&xÀÇ'?&Imù•Ê 1Ü <Ɖó7ˆ2{P D9Jp{è˜Õ¤ë@*„® ¯o ÆùòÉŽÝ|^5­Oƒ£¹uþ4§/\#4ÖŒ{žÂ”*]”œÖ¤Òený�¾v𣧂 Á“"å*à“óQz žòk'µíî£r>S/5Ç2µ²Ó1ɼ²dH»•*©=×ÉOõW'òµ™Nxé�l:ü-OZ êê)Žœ &Â’‹¢åÊSÄSK)¥”J»|=‡q/^£Á¥”ú׳qú§&Tys4þ…CËúRLg¹²Ý\$J)¥”RJ©¤hðF)¥þ…,U?`õÑÎ\‹q¥€O1¼\u¬”RJ¥§†CØ´g v§ü”Ñùn”RJe Þ(¥Ô¿‘ÙïRðÎêr(¥Ô¿Œ‘Ó‡JU|²ºJ)¥þcôQ¬RJ)¥”RJ)¥T6¦Á¥”RJ)¥”RJ©l,ÅÁ›jUª¤KÆéµ¥”RJ)¥”RJ©³oöìÛ—.§×v”RJ)¥”RJ)¥þÍtØ”RJ)¥”RJ)¥T6¦Á¥”RJ)¥”RJ©lLƒ7J)¥”RJ)¥”RÙ˜o”RJ)¥”RJ)¥²1 Þ(¥”RJ)¥”RJec–¬.€R™*ò:¯…#Oòȉ5©ÏÓ3õèÑs™…"¹~ñáâD.ï|x˜3#ÏXB._âVŒ�{ÞBävÉŒ<•RJ)¥”Jšö¼Élr›€}»Ø¹s';w!82™ÉBβ×NvîÜÉîc—‰ÎØRþkE-{ƒòE‹âSw0»bâ|¾¸¥|žžy¨G�žË¤E_9Ìú¿¦0îç5ú7f.ÙÆé[¶4n5‚½ÃšSº¨µ¬æFº”ÀÆ�Ó{صs‡/F8Xnpmù[<éS”Ò-†³ßÑ*J)¥”RJeíy\¸pžUkVbµX©åW›%Jf\f1óE£ç˜x͆'Ïþzœ…ݽ1šÈÆ‘ÛP㻈pª3œ#Þ¥¤†ÞÒ�aÆb6c3›0~2”ÊPöÛç9d'_Ébä¶&Y¦ =ÄÔA}yoÂ&‚¢$Γ{ žyûGFò,>N)ݰpcE^úh=aåßá¯q(š½n"O3ÿ³žô±ž 3U>ÛÅÎO+'ø4S¼ó&o?@óŸ? Ý€Jlý©)¹µMPJ)¥”RYLoÿ�uÖR½Zuš=Óœ¥Ë—pìØÑŒÏÔ00eÍäYÚ“X7fÓ¦í#C ĹÍtnÇÄuäžÔ�¦Ê2±Þ‚Š•;1é|†áaË2™í4:N¡xר�ÓÛwpÙ–ÊÏÓªtÂ–Ë gƒÖ<�g¿]=ÄŽ=aP!G²¯ÿÉ7ã�k©Ì+ž»¬Ž¾|ŒƒgCsJV)Iîš !ôÜAŽ]Š—¸uØÆ™Í¹\ÜŸŸ&ÿD¿ê6&nHNI ò¿0�^æ0øð8¾™ý.óºHbx«RJ)¥”RȫǷâÕs¸xõ.É1zÜød­—YÛI/G�‘Q?�”3§$**JBCCäçÑ£äèÑ#é›QÔbéž×$8Õ•áˇÈN†˜}^“5‰¬c¶ø{™Ä”¯³Ìœä/žâTg¸œ²%X/â„Ìz·�q1ˆ÷g¸–úïÌ’‘qØåúï-ÅÄZõsÙë ï›SäyK%ùdoLœ¤7eÇO�¤Jn‹ òÂp•b�Þ“ùÑnÏvYÖm+r˜¤3Ä”£‚´ûîo¹jOÑщ�ùï5”"Î öÛp’‚õú˼3ñË9¯£xˆ¹Ì@ÙgQäì—ÄÕÁç陇ˆˆíâ|éUÎY ÃU{m‰'<�*[¹w.-åÞ“u{Ç‹Y÷ø×®a–<5^“ÙgâÔ�TÕ­HYÔ-σõ ³”°^þJtÙf¹‰¥¸ ‰\ø²ä6§ºßËÉ‹«å“†Þb5â×MgŸçeÔÞð8©båØ7OˆÄ©ÞH pt G­–~…M‚á&mg†$óhÛäÄwµÅÉ0Ä¥þ�ñ¶k;?]Ú4 ¦¼òì„I˜¥ýÚbééc Oyjè~‰ŠSÖã+Ê¡�» ‹ýŠüÚÜYÀ"U>Û'1ò0695¢Ž8†8×ñ`›«”RJ)¥T‹¯ÑaSw•+Wž&�š²hñ".�ÇjuÊà!T±ˆÏ ´«î„ýÜl&­ q°Žpeá_ƒÏùÓØÝžÈpŠ`æ¾Òÿï×sÑíqº�ÁŠ-;Ùµe%3†v£škëèHÓWr%Í“7Wæôã¹7§±?¦4­?ø™ W°jåf�ÿ‚®5<¸°f^Ì®¸¯Ä’[¬Ô„æƒæpÌx ÿÁÓX±e;7-eÒgm)g?ʬ�-x~è^’ù.�+,z­1톭#8wmú �ÈÜÅK˜÷û×t«îÁ¥�#hÿÌ;¬¼‘†�NÇ<äæß|Òª3¿J½<™%#›S@kà£!f'ƒ_z‹5^þ ™8—¥Ë1mD?žÊopcç/¼Ü~Òô6*+•»�dÜ·)g,ehÿõ8Æ�Çàve©šè²R˜!Õm€auÂj€ÜÞÇ]:0.²%_Nü‹å+—1gÜ š³¸��¯ŒâŸÑOfŠ×®E3ÄÜÈ–ë^û¶€�ì¾lÇpªFíênÉ;öÎÛI Vj´jIÑ8uÃT¸£~îDQãK?|—éâÌù#·XýÉ[L:+äzz0Þ­Ä?}ŒÌ”iÜ_�Ôô™1Qü¹Ö­yoæ›h¶N™Êápo:�äz ŒùžHŸªV$t-Óç_ égÜÑl�þ'cÁ£ékô­â#gÞøômúô{•&…"I]§ˆtÊ#6€é=žcÀÊëäkö=K&w£tŠ_Ÿ¬²”©íÞï‹o‚ ŽÜŸx…îOXÁ~•UKw¤ò:K«´·b*N×OúR!áþÕjÀ.ØÎqælœ~¦b¼^íûçÏŸeõšÕ´jõBšËêˆáõ]ŸÏÇü©ë™4ó4½ú—¾û 0‡gLa{´…Ê;ñ¸ÇAÛiv켊3¥kû9†cƒG/` IDAT.É5óaÚy‘€=û¸.5ÉŸÚ™7MÞ<ñd ,ë�±m°?¯ºÍ»íëS6÷?—’ÙœpöÖ@¶n»€ ¾uk;~c–¹ µkycÞuž=[÷ýZQ:�¯-�í;ƒ°a¡l�ÇÉùÀ6Í”ëüc;§n7Ó-¹ÂòþÏÑë�sä¨÷ ÿx�ǘ½Vew†S êû98q¦"T«Vó¦s\>z”«Ò€‚™=«m:´†Kuj=î`êmknr{NxDüáQQ—Or4à7#m˜= R¸H!¸‹ƒA )R,y‘ʨsÙÁT°8Å™ÜÈÕ˜!Þbm“áL}»?eŸ?ÀmöÅÏ�ŠdÀë](V¢ &Np–hü™X^)¥”RJ©Œ•eÁ›g›7Ë’|kùÕ¦–_m‡ÿ8°Ÿ‹æóÖoãääĹó�LŸ1�ÖÏ¿@¥Ç*gP‰rдk[ŠLÍöÉS9øÖgT¶1»˜:ý ±ÎµèÒ±f Þq!ØX)X¤ŽŸ;›ñ.T3±_ â²ò§úµ•šüƧÛ^à³õ;Û¯1ãÞÌE‰êõxºQšµlEó'‹â÷ÖÄù‹v@8üc+ªLvœyÔ•+ØÂ/œçš ?ìNÌÄù ;`!Ÿw¾Œyç}Zó�¶nç?$Ò¥_ÿö>5=3 œ*Ãy‹QÄÑ+È0‘¯@>LœÃ~ý*×íP0�;$)ÚÃ='9F%̘ï^øqC7ö‹³èÙ #ÓÏå¢Þ‡‹ØüasŠß�mÙCŽ2ï“®ôüñcžßvŠÙ['ð|¾¤"ZÂíë7± ˜rç%×C*›gÝÏùuÀj ™ÌG# ,%z0zd[¼3$hf"wž\˜boÞ Dpø&:¥”RJ)¥2ÚnØTböíßËÜysînœ9w.€É“'óüs­¨T)£7w¸ÖëJ‡ÒbMcòö;³üFnšÂ'l¸5èÂK%vš¢‰Š0pvv0Œé.«Ó�§ßEt'-6rÖæã•Ù6í+z7«BËmÎl]À„Áoðbí’«Þ•Ÿ·ßøçfO¢‰Š¾óò‰�"22ÒáŸx¦d©R”Ìë”ôÐ.‰&*J«Õš1¯ðMcö€_éÿå&nÚA"7ñÝdz¹¨sž>’ W\¹œœïD=$::Íu+uÒ¡ 0Œ\ß‘lüæ=fÚÈÙò;f|ñOàÀäYž¶Ã§óim'bOOæãQû’1TSˆŠŒBÃÙ%Ñc}‡¾�Ÿ¢ˆ À GÅ:TÍ“Qg—;CV%*’È,9¿J)¥”RJið€#G3köŸôwNNΜ={†_'þFëÖm¨R¹jÆÀZƒ.�+aµŸá�Éë —PÖL™ÍY{Nš½ÜæáÃ0 7ÜÝ @ Çñ½…qw™áæ¿WÌÃØmØ»Y±ä£ºÿGŒ[º—‹×.°wž{·5ò›¸¾g2o6ïÄ„3w#†;žàD­Ï6qâäIN>äïȬ^ø$ueÞßo;a¡aɘ#'Ò˜‡Øìä®û!‹V £ANáü¯Òcìq�7ã$‘‰Þ¸GFD`¸¹§OÝJ©Œl‰=ÆÚõç±áDõfM÷x1ùРAiÌÄrlÓf.%Yy œ]î—¢£ˆzȱ‘[kù_¿1œ¢E [¹±ä=úN<ãøM|i&DEýTrÖ^7J)¥”R*‹hðX¼t1^ê€Õj%0ð ãÆ�çÅ6í¨VµZ&•ÀŒo§®ø9Û Z<�Í×ÖðÇÂË�ïy^n™÷áOÄÍ>”,vgPUÀ©€DžpÇxæ<6 œŠ§�ÀÀ¸û´]bcˆup³d»z™«ÉˆX®ÞTnÒ™þÃÿdû¡%¼^ÁŠ\_ÅØÇîÜPYŠSÊÇ‚A,�§Ó6aò=æbw÷ÛFÀɇ7nADLî�Ó˜‡¹ho¦/ýŠg½Ãï?–‚EðN纕,©nRIB¹rg§¬N‰Ïsoî+ #<Éjhà™+'fäæun%¶¾Ü`Å >ü|ÌŽO÷ߨ2÷=ª:]céÀ>Œ9‘.-Kvnݸ…sÎ\xjðF)¥”RJe Þááá\¿qƒ£Gó˘ѼôR{¼z¦–ÁTü%º=íŽ=h9sFÎaÅ5ƒÂm_¦IRs¤˜ óTÝÒX°qvõ*Ž:º‰Üƪ�·Éêuýð¸û±‹‡;ìW.qå�È„�൫8�p{AX?�É î +#o=Ú6.ˆ ;—ƒ.ßé­bäç©ú¾X°qfÙb:ìzbçâö¥lû+—RÃIkΞxXÌø¼<–q]K`ßÁàÎï³ú†Ž¿x”HôvÖn }p�í[·_ÇŽ™²Õ*¥­nÅÏ1‘4–¥¡ Hsa|ŠÜ Ù{ˆ(‡+…røP6 \ŠúÜ j=œKQ¼M`»ÈÙhGkW  ïøSH±®Œú¦9…Ÿø€1ý+ãts5öÉ!‡éÒ"šsAØ1áíS”DæQVJ)¥”R*ÃiððïàÏÆ�ë™6c:]_îJ�êÉ{Uº1¼iݵ¹%€©#çrÙTŠ/×%éY¨Úµ~n1ûáãɧ ˉ`ÿ¨Ï˜hÔ§½ÛûÜ?éÖ2(mûÕ•Ì]+Þ aÌ™é¼ûÍ&ì–ø�šíÁ³x½Y[ºu|…a;B¼ÁŒ8ÈÚÍÁØ +eÊ—¼;yªß—_¡aƒØC£x{ønÞGCïçZR¯BMþ™ä^ƒ…Ê]zàçf{ðg�=BÜT1g¦3ä·£Äâ†_ËÆ$9_jFçaäç¹~çíÇœ‰9ö Ý_×ùo%†\aöàìŒwá — ç·ƒ1V_Z·ö½?Ypjê€a±b1Û%.Û’¹,õm@ª˜Šñl?Ü ç¦~Á¨½a VnmÆð%!ˆ)/ÍÚ>�¬`‘¥BU*:HäAö:ˆ@É¥¹¼ýê$(Bç‡òl^på‰ÇðN%'B6~JÏa{HNë‘l±GÙ{(1œ©X¥|ÖÍð¯”RJ)¥þóô·(P¦tY>úð“,.…Až]i]`6¿…b©Ò‘Î5’÷Š]sÙ~üòÕ"XÃÂWü¨½º/=UŠ1ÁZ5ƒI‹�b)F»‘#ð�3A…Ù·k eß–Æ·¯Ëå.­©YØ…ÐÀ­,˜¹—~ŸÓiÊûL²c¿h0ïÊgýÆÒâ‡-|^ÿ1V¶~�ÆU‹“ÇÅNhÐQ6Íÿ“eGcp*÷:ƒ:þóê^“O~±”¯,`Çõ¨²Úÿ¦•(èÁ…ý«™õÇ*N†9Q¦×÷ ªóЗ„ÇÙïWùé«%4°šåoÖ¢Ú¢iY³0æË{Y2k1¯ y~Îð©¿YMÏ<ŒõøròÿØTïc¶ÌìGϺUYØ·ŒVÂìÌnǘ˵¥­åÕØA×ÎÏðXW÷/ä·ßVh·R¢û`Þ¨üÏ™LMÝ0ò–§|3«Îžf\ï iì^Íùò£æä{زT¶©c¢tßQ|µ¨1Ö¬åýº•YÞ®�*Á“ۜ۳‚?fo 0ÂL‘6Ãú¢W²&C6rùñÔcí8ɦÍAØ/úO�²_`æo0ã<é2’aÏÅÙ¦›�~‹… ‡±}pO7ù›/Ÿp@‚&á_ÿS¶Þï‘c'ìò�ŽüМÒÿöåüÌHv�m…{œ2Ù/nfÓ)†µ2õjå̘‰Ñ•RJ)¥”J¯ߊWÏáâÕs¸$Çèq㓵žJDÔbéž×$Xýd؉Ø #eý[%Äl8K­aÇå�¥³_Wqª3\NÙn8TŽÌ(-Êå‹Á�W;�`¸HÁ':ËЕç%ÚQqNþ)oÖ)$Î÷Óbr/)-¾X#—"·Ë rÁ\Zl‰“:6HÖ ï*uŠyˆ9n^bö,.õ{�”�Á K/"%K¾”ö�ç�“‚a÷¢u¤Û÷ë$(&¥4TÏ(ÍËÆÝoCLî%¤Ñ[Sä@ˆ=þ1œ×Q< Ä\f ÄÝ¥{Ç6áçé™Ç1rbLsñ2!†Ç“òå®ð”î°ÊD·§µîÔ¹ÁdhÛ ’ÓlÜ¿v —ÂRïÍ™r,âÁ´©ª[+§§u–²nÆý4®�~‘s¶¤–‰¤¦ ˆZÑG¼Mˆ©@oYåàD­–~…L‚ÉKz,M°BäY2¸“øvS¼üÌâáó”t¾F.¤¨>ÇÊá!5ÄjâÚx´œ¿¿_6 œØJò›sáN2û’ÝAÚÙ8 ¢8†8W nßMyv”4pŠÛF%þçÒzš„ÄÛ¦MÎýÒH\ C¬O|#G5iJ)¥”RJe ¸ñëǷ‚q§³ÿ• ï&ì3~}{÷J—À‘Ê1Ü <Ɖó7ˆ2{P D9JpK¢Wˆ��óÇ8vö:ÑÎ^”¬Po·äôU‰æÖùÓœ¾p�ÐX3îy SªtQr&>‡é]v‚Op<à avgr,E™âyÒø&—nçôÅ[ĸæ§TùRä{øû†³i*»‹ºvŠ#ǃ·æ¦X¹òñ|Ø„.©«[±·Îq"ð&xÀÇ'?q“`jçÅô*¢C¨”RJ)¥”RJ©GI¦ÜÉûûûãïïŸäz‰n¦LžBƒ†õ¨× .~µž¤ÚãUñ­X�R¥KR¤ha¼òyá™Ã«“»ÝFXXX²FéÆFÐ�eŒêÝ„Ž¿žÁfÊÍÓï½ÉSΕa4[§Låp ¸7È r%˜DÙ ß³éSÕŠ„®eúü $ñ¢s¥”RJ)¥”RJe3©êy3fü‡ŸW«Z…'kÖt¸ì^ð&±€Š¿¿¢�€R%Kѧg¿•3c漉fqÏ|Xt軻ܙqÆp*Lã�¦2½_i2¬ß�-�­Û.`ÂoÝÚŽç´1—¡v-o̻γgë¢_+ªC§”RJ)¥”RJ©GHª‚7}{÷JUf‰p’Ó3g̘±Œ36Uù¦77¯bx{$è´y�³ob7¤qÿÁ êÓŽ§Ky$ò:ñtbâüE; þ±U&;E]¹‚!üÂy®Ù¡°ŽœRJ)¥”RJ)¥™>a±¿¿?NNNLš4éþÿÉR5yÊïìÝ·7Ey=Vñ1ztO] )qN4º‹]sÇÌ„oå¿ú =x™S7¼©V2ƒ7MT´‚ÄF™HTƳ0%=Áš×‰ØŒ.“RJ)¥”RJ)¥ÒU–¼mªmÛ¶DGG$+p0eÊTºvï‚ ÄÆÄýÏ_T4QQQñþ""#™1cfoáæÇ‡#û2·é(NL|�Ûìdt³Ü)àØmØ%éÕ0Üñô0+µ>ÛÄŠ¾3>`¤”RJ)¥”RJ©L•e¯ OnÐæž’%J2à�÷R”&cæ¼IœgƒÏø¾Û|žŸp†__ÿˆ6;¦i®¸áÃ00‰�!ÖA�Ævõ2W“;«°¥8¥|,'c <H,±¦Ã~(¥”RJ)¥”R*ûxdf?;vÁÁ—Rô7a¯™[H#7ͧ}!ƒØÓãyýãÕÜJ qñpÇb€ýÊ%®ØnÀNðÚUHîØ&#?OÕ÷Å‚�3Ës0ÆÑJv.n_ÊÆ7tÈ”RJ)¥”RJ)õzd‚7� #ÿ ýúyò±œ÷ÿ[{›¸ñk™ ”¶€ýêJ殿oYÌ™é¼ûÍ&ì–ä~2ãûò+4Ìa{hoßMh‚5"�¡÷s-©W¡&ÿŽLÛÎ)¥”RJ)¥”R*ÓeÙ°©/E:�àËéëyuù Ƽú m¶ÿ@ƒw–š}ÛѱÆPöm `|ûº\îÒšš…] ÜÊ‚™kqé÷9�¦¼Ï„ ;öd Ÿ2ùôà§KiðÊ6|X�*«ýñoZ‰‚Î\Ø¿šY¬âd˜ez}Ï :ú’p¥”RJ)¥”RêQ£Á›Œ`.AÏþÇô'ú³áøh^ý¬ ÛFÔÃÀ\�·¦üÎù®o3vóæ�:À< Lî%höþ&¾çÁ÷s �("£’3s±•2=ÿds¡oyÿãQüµzƒWÝ]d˜p/R›n_æë×ëS@g3VJ)¥”RJ)¥9†W�oà À• ï&™`Ìø ôí�IopúW³rþÇÎ^'ÚÙ‹’Êâí–ÖQlv‚Op<à avgr,E™âypÖ �RJ)¥”RJ)õHÉ×s÷â5Úó&˘ñ,âK�"é¹MîÞ卿].=7ª”RJ)¥”RJ©,¤+¥”RJ)¥”RJec¼QJ)¥”RJ)¥”ÊÆ4x£”RJ)¥”RJ)•�iðF)¥”RJ)¥”R*Óà�RJ)¥”RJ)¥T6¦Á¥”RJ)¥”RJ©lLƒ7J)¥”RJ)¥”RÙXŠƒ7ÕªTI—Œ·mß‘.ÛQJ)¥”RJ)¥”ú7KqðfϾ}é’qzmG)¥”RJ)¥”RêßL‡M)¥”RJ)¥”RJec¼QJ)¥”RJ)¥”ÊÆ4x£”RJ)¥”RJ)•�iðF)¥”RJ)¥”R*Óà�RJ)¥”RJ)¥T6fÉê(¥”RñD^çâµpÄâIþ9±fT>Q7 ºŠÝä�WÁ\8gT>©‘�Ë–•2ëÚH±H®_¼F¸8‘Ë;æ¬.Of‰%äò%nŸç-Dn—¬.�RJ)õï¥Á›Ì&· Ø‚«1¹JT¡tÞÄáÅ\9Î�³·±c!o©Ê”È¥¥”ÊT)¨¯ró {O]Ãfä¦TÕRä~d«¬|ˆ;ròÜnGÚ0»ä o¡Tx¼&UŠzdh·Í¨Åý(ÝîO¢KäïCßâ—AwèÑÞçñf㸜¯7KÏŽ£©SÆäCäeŽìÜÁ¾ãg¹|;³kN¼Š–¡JÍ”Ïç8,“ie{ÄD-{ƒòm¦ž¦kÃÆ�Óû9}ÝŽk!_| ¹¦±TìÖ‚§mÄ㥩lšÚ�8K%ì<»6ndïÉË„x—©NýzUñN"Б¢t÷Û*‰÷±a˜±8»‘+a ç÷HÅ�¾¤Ž•ÁµåoQ§û<"ë}ËÚÅý©œÖé”RJ)‡4xŒž¿ŸyNðB½2ôkU9c3‹ù›/=ÇÄkVZþÄ‚®¹1­vf:ÝucF€�‚-båŸU3¶\J©%³¾Þ½îcê·™Nˆsf\�C÷L+i<öÛç9d'_ÉbäNÑÍ­pûÀT>ðV�"Ä.¬a˜Ü(òT7¾õ ]+{>ôx¤šaÆb6c3›0d�ú}Ë|¶«ÛùíËÿ1ì÷Õœ¼m#áÑ4,9)Ó¸;ïù?ºÕÈ£ã˜3CäiæÖ“~#Öc¦Êg»Øùiå4ün¬èÏK­'¬ü;ü5®EïÇxÃ88ñ-º œÄîk±qο�SÁº¼1z_·*î ÷P*ÒÝo«ìŽ‹i˜pÎSŠ [Ò¾G?º7+ƒGR•7YÇÊLñΘ¼ýÍþ€v*±õ§¦äÎ�†A)¥”úoûÏo¾ž¶�ü¹Ü™ÿu+&-;Â×Ó¶óA§'²´L¶sséÛ¬3ìhþËþ苯vEVJ%K,†· Æ79vt=o—H~H lûW4kú[n î%ÒÃÿYjWô!¯›‰˜[Aßµ’YÓ±Ã/ôlx„ë—ñÎcéß%ĹÍtnÇLw°$õû–¹„�Ý#éØê}Ÿ�F W Vm@ÓzU)Q –ˆKœØ½Že«÷q|ÙôZ;Ÿe¿,ar�òhSŸQ„[{£÷þLÜBzEåúbôÇI*ÐÜÔó¼·ÄNàä.4íýÁ’‹Ê/õáå¦�‘ŸKì]ø+ãn`ÄK͈\¸™QMóÄ)NjÓÝc¦`Íg©]ì^hGˆ�¸Åå³Ç8xô$›fϦ9?óm£÷ùuÒ'4-äèg` �•‘‹FCÆÒoEF�íÃÀ»ÿ¬£²)¥”R*M¼z|+^=‡‹WÏá’£Ç�OÖz™µ�´2u›L\vXÂ"cdÝ� ‹Š•çî•!S·e\¦Q‹¥{^“€³´üýºØ,¶-’WsÃ0Kþ¦ß˞Ќ+ŠR* IÔׄ"çuOÁ¥�ÌȪºk–ñϸˆáô”|Ú–üt¶32ª¡›˜$Oã²?Ìñj1HŸrNb`HŽfãäl ²H³Ôî["¢Vôob*Ð[–G¥Cùî²N‘¶…Ìb`ˆ¥Ð3òÅò‰p°^ø™EòqÃb6ù¢ô_;ÃËö¨»WÇÌeÊ–è䦊•““ÛK)WC —òü×sdHSg‹TùlŸÄ¤º4á²i`±&)Øy®\�Ó@ØoÌ—— šS.yzø �›Ì~KþTM\ C¬?”íQiO—œ¶*úò^™óU;ñõ4 q.×[æ%¬G©=Vv¹ôG{)`2Äêûžl OtE¥”RJ¥@ÜxͶçÍ×Ó¶S(Ÿ'/Õ/ËúC—¸Ú}AôlQ‘± dI¹ºŠ÷žíÀèƒQämô Kæ¼MÕ$†]ØBÙý÷^!ÄæJ¾â•¨U¯&Å=ã<‘–PÎ<Æ¥(Ïb�Q."OÊ㬗çeóeó1 J=‚b®aóß;9zî†y‹–§f?Ê{%ÞƒE"ƒ9¸m;Ï\âv” ·¼…)[Í�ê¥rÅé>)Ü ØÇÉàÍ,Û�H(çìdç53.Þå©XÄýáOÂ÷±n{bÊËóo÷¥’›ãÕ,…Z2th/ö9A±âv.GAQ—œÞsšëâJa__ &œó"â"‡_$'ò—­D1Ï%‰½Ê‰ýÜ">•Êâvš=§®#ÎÞ”¯Xw#eû}å0›6ìàDÐmb\óS¦F}êWñN|Ò_ø“^B ܺšõû¹is#éÔoP•‚)™-X®0û½þÌ»hÃðz†VÍçµ Ž7àZüY¾\8ê5dðîÃŒú'ï<Õ“Âq;¥ºlvBÏîf󶃜¾E´Ùƒ|>y²î”Ìñ`�%¹yç˜ãYœÊe½°H(�[×°~_7mnä+ù8õ>N!—ôIW²¾ÇÒÄÆ™Í¹\ÜŸŸ&ÿD¿ê6&nHûV%øO¾”XKe^ðyï_„ÂÕ˜lÇR¶C^ŒxUÂÈA�AŸÐöø¾$Ö IDAT×¶L=2‰ß6ü�š�]Ò�.y¬ùªÐæ£?hÒì;^h6ˆÕÇ~¥×kõØ;«3…îêÔ+ƒü/ ¤W…9 ><Žof¿Ë¼.´÷�RJ)•žþ‹=o†LÝ&¿.9,a‘±²x白é¬ÌÙ(Sמ’9›$4"F¾�¹3czà$òtÌ~}ƒ|ä—SL˜$oý!²íVÏøm—eýжR!‡I îÿbÊQAÚ}÷÷?Oí×eV/1a’ÜífʵD6m;9\ê8‚¥¢|¼+õÏ"•ú×HÏž7'dÖ» ¤ˆ‹§¾Þù3\ KýwfɉÈiì7eÇO�¤JnK‚zŽ`¸J±FïÉü€{Ý"eQ·<®‡YJØ,IvR¸5EžwA0å—Kõyˆ˜}òie‹`ä–ŽsCX|{vÉeÜ)ó3ã‚8ŽÑ[Hi3böyCÖE‰DÎ~I\ãõ®Hæ¾EÈü÷JçÇØp’‚õú˼3ñ�½Þ-梯ËêókäÓ§½ÅjÄoO]J¼ ¿ìO~7ÛÉò”³!nRwÄ ‰MFš�Ýsdòòƒr5NñÒR6û• 2´MyÉaJx­Ýù~hÿãIø¹ðeÉm Nu¿—“WË' ÌÏÙçyµ7<]ÒÝ9X)ø»—_*{Þ_¹P…Øï ùµyZ{ÞØäÄwµÅÉ0Ä¥þ�¯K˜üÕ9·˜¥Ø›ë©{7eF[1°HÙ÷¶Þ-CjÓI Û*›\˜ÜZ¼L_ùpgÜœÒr¬lrjDq6 q®3BNef¯<¥”Rê_*n¼&»N�a¾ž¶¯Üî´oX†e»/p-$жµ‹Ò¦v1j”ÎË•[‘ÌÛHßç*ƒaðõÔí^&¹½�¯[·æë­!ä|êSÎÄ9ò¼Jn±nPššÃ1ã1üOcÅ–]ìÜ´”IŸµ¥œý(³¶àù¡{‰0rÓ¢g; ›íÜ\:‰yÁNB 6NÍ�ÅŽpªþ2�«üg;e)•þ$˜¹¯4Æÿûõ\t{œîCg°bËNvmYÉŒ¡Ý¨æÄú:ÒôÕ…\¹_=…+súñܛӨSšÖüÌŒ…+Xµr ³ÇA×\X3Œ/ fW4€•ÊÝG2îÛŽ”³–2´ÿzãÇ�cp»R$ùæb·Ç¨ZÆö«Ì:œm7µ‰°T I£b˜å6›7ì%&ÞÂhv¬ù›“ ®NQl_·™°xËmœ^·ž@›‰¼O7£¦ÃHÉØ7¹Â¢×ÓnØ:‚sצÏЉÌ]¼„y¿M·ê\Ú8‚öϼÃÊ&avºÈä./1&üY¾˜øËW.eö˜�4-j%êÌ_¼Ûç'ŽÚ’s ì­XÌŽhÁpšž�“qÜ�jmèÒ´"ytvLqÙl§íߊæ#ºÄ³|0v+6ldýò?ùñ�ºä?Êo·âÕyWâM lX�° ·÷ñC—Œ‹lÉ—ÿbùÊeÌ7ˆæÅ¬D.dà+£âå—Út)þK3e·Ä7ÉzSÀÀÂy;‰ÁJ�V-)÷×”í4…"X¨XÅ7‘É=¨X¹4lî?È ICº3Qè¥wèèc†Øãü5w?±÷—¥åX™(þ\k· Ñ;ç± 0‘É“•RJ)•:ÿ¥ž7¿üµOFÏß/!áÑ2iõ)ùeÉ1¿â„ü¶ò¤,Ýu^DDF-8$Ãfï—1‹ËÍÐ(1a’\µþ'¯'õl_$zçÇRÉjˆáä+o¯¹‘à ›].Ïï&>fÄðl&ãÏÝ}ô½C>¨` ©÷Ãiyà�XìQùæ «†›4úåìƒË•ú/J§ž7áëÞ”’fİV”þn=Pg¯¯è'¥Íˆa© ì¸÷ü†L{Á] ¬RcÈá{p„o—+»ˆ[¾'å³íÿ<·�% œR9TŽ%§ÛMb[JeÙb¶½/å,–Êò¿Ý '˹-Ë_ñ3†¸4úEÎÇÙ¥¸ùåv”ßÊ~âcFpª/¿Ô¦KÕ÷˜¤¶çMéÐóÆ~}Š´r7K9´=Á¢VHŸ&Á”Oz.MlÂ"»\ùµ¹8ƒX**{cÒ�N$ÅmÕ?½| q~f¼\J,AJ�UÌVXÆ,ò´I–B)¥”R÷Ÿíy3wà :5)ϲݾNTŒ�ȨX"¢biöxaï8Gd´�°¨XÞ`ÊêãômU…yNdHy$â£;´ø?{÷_ÓùpüsîÈ!CŒX{[lµZ­Q³«¥¥­¶t¨ÒR]vjW­Ú±÷н©•XA"ëæŽç÷*‰„L¡¾ï×+$÷<Ïù>'÷Þsï÷|Ïó0p]86�; ßéC­'®¯Ï®™³8nç¦Rß-É=åž-òVE#*j#s–\Æ`¬D·À*ØabçŒ9œHrÙzj!ó˜!GÛ�%k…H$ž5ý‹áéá�Çc~ò¿¹�¨GÚšØ6w>!V ‡zýP;Ç#¯Ù\ ߣG%#ÊršE Þ» n»Ë­3 £�Ý£sG8úóÕþ(¢¯ïb˜fTÊéÈ×áw‚¦ô¤Š»óÕ=Ìûa�•#_.|«·$pÐæl:E„åÑÖŽ5_¢^ ˱-l{X>„íâf6�¶á^³=]j䇰­l>•à (jƒãÀ±6ÍëçHgìñìš3�3piú.}Ê%žDËYŸþÃ>à­¾ïÐ$_\’Ê Pº¢ïKÒ©iœkÔÇßQëÎ_HMéM ×®ÞÁ††¡@!ò§¦ìæ Ò›¾Ì,Ù»‹Íkfòn…¤eL®ÔiZ'Ma>uŒ’’Ò¦Û}Ý_ÍúTsÐÀz1Ùc‘¶vé<�=C,'r4N¡Ù—£R©$¯?[$·ï*МqqN霮áìℨÈÛDª ´K;| åC�Âví ×2ëJS¹œ=šŠåÈ�“�¼Ö„B‘~ÙzoÌÄ)S3ÜG¥Š¨îmÛÔ-Æo‹Ñ·uyfn<ËÝX3�MƒÑ Žp'&ž[‘&"£Mäww¢KC?Æ/>Äk~ŽóQfv {�ÕáäÈãEìµëüݯß• bh•ÇÌRl e×îËX1Pºn­$& ÷£VMoôû.q`×âßõÁ=~]zÐà«`VžÅ¬ýƒéÿ Fßʉ…ó9lÖáñr ¯xʃB$¦ˆ¿{‹›éij=Çž½7°¡§X­äI.3ª/J5Ot{¯rà·”?^:oªU/‚aó)v�èÄ;Î#ù°C=Šçzø¶­×gBv gÊuŸBpÛAl˜?›¿–¬bí–ý„Þ‰à\ðJίdú÷qô ð³Ñ|Ý«îÆã@ÓšŽü´‡Í»bèýª3 ¸µeÌN4©W‹êN5pýi›·†a+w/I¿o#Û"Á®N3y¤ó½ÇJðÞ0¬(^µ29éFO‰®?0©kòÍ5Ç*Ôª”ÌýZ†œ¸¹hCLl*¾%+ f˽íôöö™r‚Mklš³7%*xS"Q\6,f3‹…X½ŽDÇÆ�Ü�4‡*Ô¬œÌ,ÈÆ\ärÕ 6ùc‘¦vé>�=;LC³�.oa &¶Í‚Õ¦ÆÇÌû¯3Ñk`¶Xî'lÓÙ.]4 Æ{ÏPeµ`Mw() É‹Žs„…\ žÈÒB!DæÈÖäMŸÞ½žêþú¾Z�‘³ƒ¿ä}[W`Êꈸk":ÎÌOo×à�ï7a³)ò»;1¤cEÆÿ}MS¼ój…,ˆÆÆ­›Š2û«2lì\—ÞK·3¬mo|·Î¤ƒO _Êla\ºbÇnM…Éog dž"æò%nÚ ¿tùÚÑ£ÕPÖÎ;ÍÜÛæ_ÿÞ‡aË1,8ŠYŸŸ¶Ý^"½×¾…øï²§ù”ó,êšë±[™–uǧßÜMøGk—¯Z#y äKa=Þùò ç ¶ka\·�—Þˆÿ�ÿ1l÷k ß¼‡I}3ù=7ŠT  a£&4kÕšæÕ}pÊ‚\«.‡�{§qÏá`�ââ‘]ìØ¶�Í‚X¶:˜K73¡O}¶ý›Í?5½÷å[ó áKU0í`Çæ˜_­ƒ‘v¬ßIœ±õj»áb@U»? Þ¸�»ït 'NlÚB˜Õ@Å—š$^e)-la\ ³<½=Ó\9¨9åÀ5Ù³¡ýýÎRõÝVsÂÅY�†Â|ç1 ì3øÿIWlÑgú}<ÓþÞ@ðѳ\¹M¼-ñV)#Í9'9“ý¶ýøc‘¦v8�=‘·ncU ËåŽ[Ò¸ôvØ40Çc2¥Ü‹%Ît/ibgo%´ô¶K7n¡}7’Y€,�täÊ톅åvw¤XD$„Bˆ4yf> =-CºT¥˜ð÷!z7-Jq32Ž.£7bµÚ%nt(†v­žE‘©öÕf6ŒiMçbtŸ>—å°†þI¯¶ÃÙ‘R-´ŠÇoAe1—ì�rÍOQ__ŠºÛ=¼2§å¦U�väÓ[¹¸`:ëîßßa9²€…Ç-|;�t�_!€Þ耽ƒ�û1&÷–�)@ÃÞ>™ÛŸî3ÚÝ«®Pfñ÷_þZÎZ|¶ö(»gCïfÈcˆäü®¥LÑŸvµŠR°J7~ ŽH]b!½ô.øTlL‡~ÿhçCvòK»¢ØËñ »ÿÁ;ŒŸFM(m°riÛVÎXó~6l½�Î7€º>:´<µ©[Ê@ÔŽMì1¶+lÙt«Á�¦M‹¥jrßd©xL&h�Æ´/Oœi_.�,’`9u”Sé/‹x(�±©kù¨n%Z¼ÿ#ówÝÀ½êËt{wƒåÓχñù›Uyì\´–&Osœih—‘óØ3AaŠ3¡ÍÞ‡¤×åÆ=—îÞmPwRºÉÆíˆÛØ]nré2Ð.=la>r +:\ŠO°TxFiØ;8Ü»­ËG\–¾9 !„/–rI¡!]ªý[�3¨]¾�w� ×ïâãéœ(q3$Ë7:<óçû÷ª™æVŸ‘ ~âTÝ>,ß;’ö�¾lý+�¢IÿCš3®.`¤æðí¬é“7M´�ô ‹ßïŒúg)³Vݦe{-XÈI«‘r]ß j²+½!ÒMsÂÙI1Ñ1(’Îï ˆ�޹÷eÐÉ%q5�Á“*�>er§OQ±W9²mkƒ–òçì%ì;0ƒ÷š‡c·w9½‹<�\¼Á³:ý¦ýÆ¡-™zå46œÇZÅ= /фƅ¾äб-l¿1˜â×7²ù²Â#°>e %¨í�6i+›ŽYhTd›ö›ÑhÌKå2p:ú÷ÛˆŽŠÆ†[6]™0R¶¦?9u§¹ÄÊ£#©Q)ãRÑÜŒÐãž;£7™Ø6¢?ˆF_¤ Ó×N¥³oâ>ã×\aÒ¬½ÄdpO’ÁóXöÓ°w¸Ÿl�7aJš ÐÄ·�.Æp!ô:6|’y>Z¹pî"V4 ûR@hél—¶ KXlÍ™Ú ªg ‚')…Ét/±¥³wÈpå™B!zá*oÒ¥šRŒÿû C:T FI/†v¬Äo| ‰›äýz1cÎû”³·qåïwi3xã£Ë€ ã[È€†…Ðs¡i¿i¬B`·JØ©VÏ ""~?óþƒÕ¾ov)�þ+ßBˆäé Q´ °r6$…׬™Ðó—°¢aW°0ùRx!jŽÞ”oÒ•�ÆüEð±•ô+eDÝZǤ¹§HÕJÖ)2qíÈLÄõaOžÖ±0¾ùõ€"ênÔÃÊcEš6ʃf fó®(®lÙÈ ‹3µT»?_‰•ëÕÄÅzš-[/³{#;¢5<¥´Dx*é Þ?ÆVB΄${,”9–XsÖ—¸4lO XŽ3eôb®?q—ŠÈMC¨U°ïÌæd|vn9JК X1R㽯éè›4¤¸’�In3IFÏcÙNÃÕ-'z Ôí[ÜIzÄ›�‹3~ñAt�-‰›{4r5üŽãšã¥ÅpèÇŽt™x’DŸå5/êÔ+�+çƒVp4Ù¥l\ ^ÅÖÓÉ|(ÖS¼kê9Á�uóYºúOž±âÜ žÒ•{!^(ºüÔ©[ V.¬_ÇÉ侩ÆífÝÖH”fG•º5pˆ ãÈæÅÌXv$Ù* Í=€¶�ó¢ÃÆõ°ëÉ$\Tn§2±md{:¼5�>ú•½É~kLÐó�`v�¶€fOQ¿‚ ’¾ÔhZ�œ*’àíÛÙ°~ñÆÊÔ¯ýp&-—šõ¨bgæÀ–-ìØ´�*õ›Õ&m7l&›Î›Zuüîãµä[8ð•?9ì ¸¶ü�kY™¼ÈÙ‚�ý+ã Ù¸ú×{tÿ-ùÿßæósy»ûNG‡qæ¶=î™ÝUEr'Òèðòözôo>Îôÿm½W)¢²1ƒ“áóXösð)„·¬WB¹ðHÂ͈ÿËÍÉ«·q;h.+o=z¬­ÿÌcn°Í®¯´*zÿ5”Þvi î²\zL Áª¹RgÈç¼òÄU.Ó"ž‹!aØÐá]È'+z„BñÂ[Òµ:¹\íé0l¹\²pŽ›Ô²£ø[3™Ý¿ ê:AÚ0 (<Á=¥ß|›94,Ç~áƒ1ûYš8öøDz¿ÜŠ€Rþ Ü÷ÈtùÛÓ³E.´È †½7‡ó*Í_Ã[®� ‘ TìÖ‹NæÃãùlƹ$ËçÆrø—á̵¢ËÝ‚Þ ¡lWçÓ¯Y[;¿Í÷{î>šˆ‰=ÊÆW±iFüJ>ü§Œ4Àz�+WS[�“ƒ–úRÖâO»öß±î£ï±!«Þi Ën+ôùÚѳeîDWí]ê¾Dm'+¡Û'0o[4úõ¨›`B �wmê׳ã/Æo9‡Õ©Í깦*Ê”Çf ü=¨á¤a9úƒ'� aôæósøö'±àD�V�ÉÚõì(ÿÑT¾ªë†Îv•Uï7¤Q¿ßÙu5É7|kGç¡y�@æ…Z±+Þ›)?µÍXlº* Ìغ+ñ¹Á|‘eºòë­¸ë@ÅÜ <:»8?�e7C©Š”±×PqG9˜LFÖ±þ;ô­ä€º¹�Aýçr.ÁÄ*r/£ûŽb�IÃãåt/©Ïp»'2ßæôæ?úJeê~Ä5eG᎙ñ^É̽Þr’ƒÇâPš=e*drßB!Ä NΫÀ;¯VÈ¢¥ÒIËMãÑ {*€~A'˜Ø¥#¾Wðaù{%ðºB=øuì*꿽”-C¨°¾�š–#¯},—¯gþ¼uœ‰¶Ã¯×� ®�Ì š;­z´%ïÂ)\‰A—·�-r?gsñüÐïËøo–Óàã ,{»µÖ÷àõ:¾ä0_åØº¹L_q‚»†‚´ÿi,�îgQu…»1¼ï$ZŒÛÉ—õʲöÕ×h\±0¹lD…�dû’¿:iÆ®D?w.ðo&^s/IÉ¥Nü9Pµ(ᦠ‰^³*oµ®jÔÚK*>iK˜Ú4¦›ª]ÐEé¶ASzת^¯ŸÔÖ«–¤�Ô¹Ù]Uq'íßm�W­I;OŽMEùK}õfUÂÝNi$Ü' M¯\|ªª×>œ¨¶^y$Ú÷ì›*Ê -§ê0ÿÎ#[Üþ³�Ê¡¡À¨ª}wR%A܂ו£†Òû T;íæIc‹RÇÿ¨šOxŒ5¥s.¢½?S¹›ø?hZó–òÖ¡tyz«Õ¦d†bZ¯úæÓ)tªÇªä6xÛmudþת[}?•˨%:–šÎQå­ÜZ ˜¸U]N¦ëtÇf¹¤V|ÒPpÐìËYn7Rf½ð‹ªo—乜Â�ë³ÕÝTõjQÇ¿­ªŒš¦OP—’}}ÙTä¡iêÝú•“.ÁÿÃ�[•mû•Zu!¥¤£Ý¿ïU�ŽIÓ•cμªxµæ*pè$µölTŠïe;VVuq|#å¨iÊXí;u2é [!„i–0_£yô­Ðî]z Ÿúá“=§L¥Oï^iÏeQ?ÂFôÕÓüN´Í·¼¾øÎýä¢ÖЧt &…•æ‹=ûù²¢a ñt˜¹zŠÓ—"0é]ÈS¤¾yœžP Ï�Kç8wù&Q=ιóã[̇œ�™Årç"§Coƒk òÂ)­å&*žÛ—Îr5‚¨8 :7¼|ŠPØÛ%ÛK6Ÿ<63¡ÿpîÊÌŽ^ø–ôÅó‘õœŸ.[ÌuΟ½Àõ;&4G7òõ£P®¬[ÞÏz÷'O\à¶ÍÏ¢%ñórLTa¹{�ð8G<<\1f{yD:ÏcÙÌvqÍJ÷e]|U¾=¸“Á¥Rº�Isí4§Î]'FŸ“ÅKRÈ-5“¥·]6±çÛ•ølŸ=/M:ΊÞäÞ|!„"ƒ<{~σ|�$o^HVÎýÚ„ ïm‚Æã9Ô‡‚ò K!„Hƒ»lèW‘¦¿…’¿×2OnNÎg<á”u·—÷¢Ü«Ó¸Z¸kþL}—ìŽI!„xþ%LÞÈWöŽâNð·tûl3Ñúbôúì IÜ!„iæJƒÏGÒÎ[qqæP~Ø÷ìM¬üÔÄ3úÓY\VÞ´ÿî3êIâF!„Ètòµýa»¸’†¢_çÊ×ƶH{Ê}0…auŸ4-£B!’£åiÏOã»àc9Ę·Fü¸uáÿ³¢ÙùÕÛüxÄŠÏã×ÖK&*B!²€$o^¶ëÛ™öý÷ü6w;—Œ¾´¶„U#ëá&Ÿ°„BˆtÒÈóê¯ÌRý¡Qtyoײköla#lñ»ts£ÿ§üùKk¼äs…B‘%²{ÞIñ”*aýÉ®Ü4;’§PA<%o'„Bd˜–ƒZ_®åx§KÜQN-À3<¯pæ²`Wa K|‚›OI ¸JæF!„È*’¼yQè]ðö-…wvÇ!„Bü×èrâS:'>ÙÇSg‡{Ñ2¸gwB!Ä @Ê/„B!„B!ža’¼B!„B!„x†¥9yS©B…LÙqfõ#„B!„Bñ_–æäÍ�C‡2eÇ™Õ�B!„B!Ä™Ü6%„B!„Bñ “ä�B!„B!Ä3L’7B!„B!„Ï0IÞ!„B!„B<Ã$y#„B!„Bñ 3dwBñÌŠ»Å•›1(ƒ+^yrbÌîx„B!„/$©¼yÚT$!‡ö±wï~ÎÜ´>vSsø?ìß·—½ûrþ¶í)(„xÀÔŸ’>>ª;‚}æìŽF!„Bñ¢’ä pùò%¦ÏœÆœ¹³8þ\Öî̼�¯UÃß¿–G¢RÚìü«—¥ª Z¹‹XùW !„B!„/"É›¶l¤J¥*4{©9«V¯äÔ©“Ù�õâ"ú4ëÁÜyš�#h^J;dkHB!„B!„È&’¼b¢£±³·ÃÅÅ•no²~ãºlKàØ®®à½]™vÚ‚g“XõW?Ê9fK(B!„B!„xÈ„Å@Æ�Y´’V-[‘/oº½Èô™P¢Dɧ‡º±ŽA-;2ᨠ÷Fß±ráTt~|ëÝPöoÛÉÑÐpîZñ,\ŽšþvM�—SQ\áÓÓFË�Ó½ƒ g ”)…·TÈ !„B!²€|/|‹£I£¦,_±<Û8*b+Ÿ¿ÜŽ÷Ç�»Þ7¬Xô1U\ÓÀΖúÒgÄbNFÚÌ�£¡ËQ’¶_La‡µq×Ììþ¶þ¼EÎös83¯¹µdº<7™NU?f»­4Ÿí>Èמ��Ù´öjwZ„µÆ(öMÍÃèvý˜}2êa,šÏêý™ú×÷¼â£ÿ·]ü¦Ï©×v.ñ?sè»_ÎîH…¾`J·­†—1­ã{pï°wü»ôú|‡#,‰çÒ)ذ?¿üþ ¯2f¬�€-l)}¼Îïÿè(óÎBÖý\*»CB!„BüGÉmS÷•(QòßΕ°K�vOí*ÌÈW_eä®»ä¬3ŒeKS-G2Ù•ÜaÓà&4¼�SZY:�˜Íš�ûØ»}Ó‡·¥„í$ó¶à•Q‰ÐrÑ¢g{òëmÜ^5�ÅW“›&ÙÊÙEóÙc»*oҵ“ózz{;ô¨ð éÐ� yºñ쥬^³œÙcûRÇ nìG§ö£9’`¥ÍÁ{ Tô & þž£¹ëÒá­wxûõjxéÒ1¾{…ð…}yù½Ù6ãÕ!¿1wÙÖ­]É‚)_Ñ­ª —7|OÇ×F°/>#m„u{_´îÊïÿ(|ßœÁÊŸš“GÞM…B!„YÅ£ÇhåÑsŒòè9F¥Æ„ÉSRµÝÓê'­vìÜ®ÆýrˆwúôàÒ¥ ¬ß°žÖ­_Ëp¬‰™Ù5ì5V‡G�#�±×®ów¿|W*ˆ¡U3K±5”]»/cÅ@麵Ïùò€Þ�Z5½Ñï»Ä�]ˆ×ôøuéAƒ¯‚Y}x³öb¤ÿƒy\¬œX8ŸÃf/òŠç“H‰iöþÔ¯•L̺Tª”ýö‹„ŸÅî�xÇy$v¨Gñ\Ÿâz½>q?éi#^\*œÕ½L¯yÉð Ëæõ£¬¬'„B!„x ²-yÓ²y³lÙo͵¨Y£V²¿9r˜¥Ë—ð~ÿ°³³ãâ¥PæÌ�민F¹²å39·n*j XÈì¯Ê°±s]z/Ýΰ¶½ñÝ:“>)$ la\ºbÇnM…Éog dž"æò%nÚ ¿tùÚÑ£ÕPÖÎ;ÍÜÛæ_Ë1,8ŠYŸŸ¶Ý^"GG¢åöÁÇ9¹,‹OoOt\ÄqƒäK®æ”—|I+�Ò=>#þCþǰݯ1|ó&õmÌä÷Ü(R%€†�šÐ¬UkšW÷Á)ÑîÒÓF¼�Ô]‚G´aØoG‰s`äÿ>Áß5»ƒB!„B¼(^¸Û¦RrèðA-^x?qcÏÅ‹!̘1ƒW^nM¹r™�¸0Rí«ÍlÓš"ÎÅè>}.Ê;` ý“^m‡³#2¹I…�)^ e1—ì�rÍOQ__ŠºÛayÐVËM«íȧ·rqÁtÖEÝû³åÈ·`ðíD`@ÚK 4GRHpØÙï‡O|’!ivöØ%m—�ñi9kñÙÚ£ìžý ½›U �!’ó»–2uDÚÕ*JÁ*Ýø-8"ÑŠRéi#^<¶�ßùèëíܶ�ŠÛΟ-àŠ-»£B!„B¼(d"àĉãÌ_ðƒ ÁÎΞ Îó¿?¦Ñ¾]*”¯˜E{Õá™?ö÷ÓÜê3rÁOœªÛ‡å{GÒ>З­R4éHsÆÕEŒÔ¾�5}ò>:WËc85èA¿ßõÏRf­ºMËö.Z°�“V#庾AÕtÌß¡âb‰M!»kº¶“sê*X28> žTéô)“;}ŠŠ½Ê‘mëX´”?g/aß�¼×<»½Ëé]D—±6â…¢¬6rÕÊ´/Üø¡Ý'lš÷=êVdYßâÈ"òB!„Bˆ¬&ßF�«VÐñõŽ�FBCÏ3yÊÚµiO¥Š•žjF¿^̘ó>åìm\ùû]Ú ÞHDÒ¤ˆ¡0¾… hX=ú°ª&Õ;©B`·JØ©VÏ ""~?óþƒÕ¾ov)MzfxQ7/p):ùåǯ^ʆ!o¼SÓyFÇ—€æèMù&]ùhÌ_[I¿RFÔ­uLš{ k&¶ÿ}zŸÞÌYõ - à�q¯�‡›¬ø#÷ÅfwhB!„Bˆ€$o€˜˜nEDpòäqÆOœÀë¯w rå*Ù‰F®†ß±`\s¼´ýØ‘.OŸh/êÔ+�+çƒVpÔœ\?6®¯bëéˆd’zŠwíA='¸³n>KWÿÉÂ3Vœt£C:+KTü6l‹zôë?ì ¾… =Å+•Ã%5�¥w|±aÙ¼˜ËŽ“\·î´mœ6®‡]¿·BUzÚˆ“½+.F=…ÞœÄänEÐÇìaD×OXÿH†U!„B!2—$o€N;±uëffÏ�C·7»QµJêW¯Ê|vk&³û—ÁA]'h@…'˜sEOé7ߦA ˱_ø`Ì~’¦Mb�O¤÷Ë­(åÏÀmq�ìA—¿==[äB‹ bØ{s8¯rÑ<ð5¼Ó91¯¦ÂY0b,{¢_1†ß�˜ÑŒ¥yõÕÔVõ¤o|¶«óé׬-��ßæû=w�£&ö(w\Ŧñ+Y}:Û�æÅËãþàƒ²ö˜O�§{?™ÿF!„B‘µdÎÀ¯Xq>úEv‡ñ�–›Æ£0öTý‚N0±KG|7®àÃòè õà×±«¨ÿöR¶  ÂúNtjZ޼ö±\>¼žùóÖq&Ú¿^?2¸¶C2ý»ÓªG[ò.œÂ…�ty{Ø"wÚæ–I@ïû2/kciTuݺ¾DÙ<:Â/cÚÿÖj3R¤ûú—OýS-=ãÓîÆð¾“h1n'_Ö+ËÚW_£qÅÂäv°v’íKþ"褻ýܹÀ½¬ezÚh9øzÆçløŒ�ö¥gÝŠ,ëã'o¨B!„Bˆ¬áÑc´òè9Fyô£RcÂä)©ÚN¤À´Buw×)°W­þ¸¥l�ÙÔvcµêWÚ^ihÊèÛ]-¾bMØ‘ YùµêPÙKÙkÜ[ž šN9ûÔV�?nRaæÇűS ,nP WEÞ߬âÒ1”¸Å�•«†2¤v\Ú¨¾mSJåÔkÿÆ¢9äWïý©NÅ&Ùõš·”·¥ËÓ[­6¥`ÚÇg S›ÆtSµ º(}Â6hJïZXÕëõ“ÚzÕ’ñ6â…ñà9®÷¨vÆ'}Ô¬NOl®vY ô´B!„B!²†gÏïy�¯‘*ÿçžgïTò.‘†6VÎýñ³/Ùpiü=ÓpKSJÔý cì=|©èá›áþJÏøìÈY $• ¤e?éi#„B!„Bd=™Æã…£¸ü-Ý>ÛL´¾½>{ƒ‚ò,B!„B!žYRyó‚°]\ÉØ › ÙɲÅÛ¹`r üGSV×9»CB!„B!ÄcHòæa»¾�ißÏq‹†ÎÕ—VƒÇ3éÓz¸¥w‰)!„B!„B<’¼yA*aýÉ®Ü4;’§PA<3~¯”]ƒoÙ~` 6;/üdb_!„B!„"KHòæE¡wÁÛ·ޙإ–³å*ÊÄ…B!„B‘”LU+„B!„Bñ “ä�B!„B!Ä3,ÍÉ›J*dEB!„B!„"iNÞ8t(+âB!„B!„É�Û¦„B!„B!ža’¼B!„B!„x†IòF!„B!„â&É!„B!„Bˆg˜$o„B!„B!ža†ì@¤RÜ-®ÜŒA\ñÊ“cvÇ#„B!„Bˆ§B’7©¥" 9|šf•ü㚆ÞΙœù(˜7G¦XSPJ¶™CL±�l;6š’½B!„B!^’¼I-ó6¾jô2ÓnÚ¿�¦Ã1OyštîÏgCñw—;Ó„B!„B‘~’¼I3=yý[R«`ÒÒ…%6‚Ë'rèüA–ŽíEТÕL]?›7ŠÊaB!„B!Dú<7Y…™³¦sàà�4µ)[¶={fr$ª¼ûó»åBKöñ8.¬ùŽîo|͆�ùôïׄúË{á#8B!„B!„H‡ç&y3cÆL ù«ÅBœÉ„).ޏ8qqqÄÅÅaŠ3gzø·ØØXæÎ™›É›'q `ÓaÌú6˜½W¹áOV\íIŸ|÷R=Ö›g8tþ6Ê)?¥KçÅ1isÛ-Î/�?Áà·ÚÓÐ×%…åÄ3‰-ŒKWl€âøÏ­©0#ù4‘)<Š˜Ë—¸iƒürç”B!„BñÜxêwêÔ ;;;¦OŸþï啕¥jÆÌ?8xè`šöU¶LYztO_¢)ev4µ�¥Ýr%NÌÄìbH�zŒ:z�³ÞT*šÅ‰�)^ e1—BVÆ5?E]Áèn‡%«cB!„B!D¦Ê–Õ¦Ú¶mK||<@ª73g΢[÷7P(,f ñññLñ˜L¦D?±qqÌ�ûg$oRàTƒ¡?õaQÓ_8=­CÛìeB³\iOàØ¬ØÔ“7@sÆÕEŒÔ¾�5}òf}ÂH!„B!„OU¶-žÚ¤ÍE‹åãƒÒÔ&kæ¼I™kýáü¸„W¦žç÷~ŸÒfïo4uK˜NÑÐ4 P3–d’4Ö×¹‘ÚY… …ñ-d@;c!ô\(òbÌ„q!„B!„âÙñÜÌ~2iÒd®^½–¦Ÿ©SºAj¹h>b òiXÎM¡ßg빓$AãàâŒA[ø5­I;°quã:ޤöÞ&Í‹:õJcÀÊù 5'·‘�+Á«Øz:Bn™B!„B!žCÏMòæy¡y½Æ¨‘¯à©Y83ù]>ßIÂü�ѯÅ `»±–E›ï$zÌ|~~·›!µ7?é)ýæÛ4È¡a9ö ŒÙOT’-b�O¤÷Ë­(åÏÀmqœB!„B!žºl»mê¿KG�.cùzÎfÞY}š‰ï|A›àqÔÏqïQ}éöt®:ŠC;C˜Ò¡.×ßxÿüD…îbéŸqèû%]f~ÂÔ0¶TÜ>¥+Ôƒ_Ç®¢þÛKÙ24€ ë;Ñ©i9òÚÇrùðzæÏ[Ç™h;üzýÈàÚ²H¸B!„Bñ¼‘äMVСç¸Ï™Sí#¶ü3�w†·a÷Ø\ô¥xæ\êö“vañ/GXŒ†Î¹Í>YÊ´A.ü¸Pe"Δš™‹�øõü‹ùFóÉg¿ð÷ú©ŒXwÿ!M‡s�Z~=‚‘ýê‘Gf3B!„B!ž;šG�Ñ M@øÔŸØ`┩ôéý”VpúO³r÷Ò)N]¸E¼½EKÇÛ)£w±Ùˆ¾zšB‰¶Ùã–׿¹±—¤�B!„Bñ\ñìù=ò5Ry“mô¸(MÕ™Ù§gïTò.‘™� !„B!„"É„ÅB!„B!„Ï0IÞ!„B!„B<Ã$y#„B!„Bñ “ä�B!„B!Ä3L’7B!„B!„Ï0IÞ!„B!„B<Ã$y#„B!„Bñ Ksò¦R… ™²ãÝÁ{2¥!„B!„Bˆÿ²4'o:”);ά~„B!„B!þËä¶)!„B!„Bˆg˜$o„B!„B!ža’¼B!„B!„x†IòF!„B!„â&É!„B!„Bˆg˜!»B!‰»Å•›1(ƒ+^yrb̪ý˜nv# ›Î�¼nØgÕ~ÒãYŽ-;=­çFšÅqëÊMb”nÞž¸è³;ž§ÅÂÝë׸cÖpvÏG.‡ìŽG!„øï’äÍÓ¦" 9|šf ·"(æžò'‹í³:â’àQ}‰}[·rðÌu¢5¼ýªP/ "ÞOHt¤©Ý¿ïU*ÑŸ5M�ÁÞ 7¯üä÷rIÓ‡¾Ô+�›«ß§v÷ÅÄŒfãŠ�(�!„"Õ$yLXr˜Å[NóZ€}[—ÏÚ�™·ñU£—™vÓH«?ÂXÚ-Zr›�ŸC`£@æ†ØÈÛêWÖþU1kãB<*•¯×â7}F½6s¸k߆¹7ÒÑù©Ešˆ-ògÂlx-H®4}'UD™Åð�¿b꺳ܵ©G¶ÐtN¨ÈW¿|G·ò®�=é¦é1èõXõ:´$;HÿØž>ë�`þ÷õç|ÿÇzÎDZIz45CNüw瓯?'°jn¹�9+Y.³vä»ôû~§ïÚý/4Ç‚4ìÿ3S¾nM‘4'Ék>âõO7]rOîˆÏ¿9ÞhŽN{ŸÀ�ÓÙÓ’`ŸvyëÒÂtF¶.œLõP:Úýû^eK>LM‡}n_ª6hE‡}éÞÌ—”^¼i:Vz w�ÊŒà#4ÿmí?.Ç®_›’+KÞ„BˆÛ Ÿ¼9;/7g–ŒlÍô ŒœÌ�.Õ²5&ëÅEôiÖƒ¹!6ò4Gм>”–Rd!DªX82¦U¿ËÉ÷'7óA‘Ô§¢ƒ¿¡YÓáì¼£p.Ú€�ZR«L!Ü�t˜ï„ñϾµÌŸ½œÃ[ÆÓ³Á "61 læ—„Ø·™C¤yN2�¤lO—âîþŸèÜúV\ŠGiŽä­XŸ¦)’'†ØkœÞ¿‰ õ‡ø'h½6.!hüJfô(‰¼Õgu“ ÷óÚ„“˜ô^øwíE§ú%È­nrrÃ,¦üu€õ߷票åÿÚ·4$Ô­|üÖdÎPŠ�&E€ëƒGl„Îxƒ¦½ÿæªr£üëoñfÓ²xq�ƒË~gò²-Œ}½qËvðKÓÜ ’ ém÷€ž¼þ-©UðAjGa‰½Ãõ §8zò ÛüÈö…¿1ºÑ'ü>ý šæKò10=ÇJs£Ñ·“軦 ¿Lz‹�-ö3¥er± !„"C-Ï«µ}`)eÔt*o×EêF‚7[Äõf^�B禎9¢b6³ÝQÛWRŽš¦Œe†ª`SÆÛ¥æ½*þúAµð›öª´«¦@Sö%z«%a‰Ç›þceS׿uPytš2–¤v& \!„é•0_óÂVÞŒœL>OW^¯WœÍÇ®cfá0z¶(äeG²¥GÝXÇ –™pÔ„{£ïX¹ð*>á¶ ëÝPöoÛÉÑÐpîZñ,\ŽšþvMpEZEqñè)®™4\ –¥„W WÊl—£P9Š{>ã÷$ñ2ß8ÁŽm{9yñ&±Úƒy$jPÒ#å w•£»ƒ9zþ‘&Nîù)^©U|Ý”O*î„âÌÕí‹G©(.ÙËÞ›z¼KR¦€ó㯄ÇìfSp,JçÎ+ô¡œSò›òµbÔ¨^üö4 Û¸n‡Î8Ç-åHþҥɛt΋Ø+?~…ìð*^Ž‚®I"±Üàôáî�ƒBåŠã}Žgo¡ì½)Y¦ÎZÚÆ~œí[öp:,³£~UëQ¯‚wÊ“þjÚ½ö*ŠÐ]ëÙ|(”ÛV'¼ŠU¥^ýŠäMËlÁ*œƒ>bñ+šÇKŒ[·„wK%ß�cá–|½l 4`ÄþãLõêô$‚¢tÇf#êÂ~vì>ʹ«wˆ×»àY¨ ÕëV£hŽG+–Ôí{Ç×”/î�AEºk›…pÛê„gÑÊÔkP™|™Ó.¡T�ÇÒÍ¡¿—rÖ¢°«ýß´/˜¤äØŽ’½úÑòË Ì¹½Ÿ]L¼W8u“¶¨«ñÝ”“X åyûã—qÿ÷I¨¸±t*‹¯Ú0‹oû•%Q�Zjþ‚¶¿·eÖ‰éüoËçø7vÈ@»Ô1zV Í§óhÒì^k6˜õ§~§×»œß•|ºŒ+ ¯×Ò«ÔBFŸÌw >dñy¤úF!„ÈL/båÍ·³v«ßWWÑqµbïeµ`ûµp{¨šµñ¬Z¸=DEÅšÕè?÷fMN WÇl·¶¨OkäT:tʽ޷j÷�'\ã·^W›GµU¥r蔊4¥ËQJµÿaÛ뀶[j~G¥C§rµÿSÝL¡kë™1ª¶�¦0”QŸí3'¿‘/’̬¼‰=­æX_pм^ïýhùU½óÕé¸$ml·Õž_»¨ ¹ I^ç(4GU°Ñ µ$äAùAœZ˜ûÑíЫbïPO,R¸3S½â€Bç¥z¬L®NäéÝ‚ IDAT1̇԰ò…–Ku^t÷‘‡#tTnÚ½˜_šöÈqŒßù±*¦Gé õW›LJÅ-x]9&ª®HåØâCÔ’A Tû$ÇX³Sy>R‹Ï'> ª[ô>ýÔúKÔ°†Þʨ%~?u(òš8õeÖ3cU{M¡9©ºcO+K*ÚÜÝ¿PÍX}TÝH^Fb³…oQ£Ú”T9tIŸk÷Î~Þ£’žbâ–½©ri(»º?ª3WÖ«/<º?ûB¯¨_ÆdJ»{+ ç±ûKGå�ùî5zê�Ú&…×püVõA½BsP¯ÎŽLn‹dXÕéj);MSõ~V!‰ X¢Õß]s) ½*øÞæ^{·Õܶ.JàŠÚu¿Â%½íTß«¬êòŒW•‡…¡´º÷áž2v¬¬êìØÚÊ^Ó”}í±êìÓ¬ÊB!þ£ækžÕ ²ÌÈÙÁxär¦C?‚ö_ææ]mkùЦVAªs'üN‹w„Òçåò iŒœœå1©È`F¾ú*#wÝ%g�a,[2˜j9s½JÝaÓà&4¼�SZY:�˜Íš�ûØ»}Ó‡·¥„í$ó¶à•Q‰ÐrÑ¢g{òëmÜ^5�ÅW�„¬œ]4Ÿ=f°«ò&]+¼°EYBd>u•Eo7¦Ó�›¹âT™î£æ²fç^öí\ËÜQ�Tr có¸Î4}gáÿ¾<á ûòò{³9l.Æ«C~cî²5¬[»’S¾¢[U.oøžŽ¯�`_<€‘òÝbòèΔ0?:ŒœÌ”)“ÑÞ—'®\ìT–Š~°Ý`ñ¨1ì¾�ÜûD ¥hÒ¨ zÉŽ-1'z0ž=¶qW瀣�‰àM;ˆNô¸•s›6jÕáÞ°þÉ ¥bl*œåï6¦ý÷›¸š«o�šÆ¢+YüÇH«¸pmëX:¼4€µÉLÂlw…o¼ÎĘ–|5íoV¯]Å‚‰iêcÄtþo>|ëWNZSs l„­YÁžx…æÜ�ž]SqÜ—Jmx£iÜ“)vLslÖ³LèÔš!‹N_¤%C&-dÍ–­l^ý?÷¯‹WÌIæ}Кw‡'žˆÖh‡Qyˆqotdr\+¾žö7«×±pò`š4ºŒ�oÿ’hém—æóX\¼(X¼<•|“Ÿp\Ý8Îñ«6ÐûR¶d*—J²…°lñ^̩ں> ?MYÏqäX e*”NarAÊ”/†+¡‡�¡2Ð.Ítä{}� éÁò/:Œåþ#;V: ¿ü*•�Šø½‹YšÂäÉB!„HŸ©òfü߇Ԅ%‡Õݘx5}ýY5~å)5eÍiõ¿µgÔª}—”RJý²ô˜ú~Áa5qÅqu;ʤFÌÜ­~[|0ó‚Hzu,ê€ÛÄSéÐ)·šŸ«­·žtm_©ø½Ÿ©rFMiv¥Õ"’\³©ëKU!=Jsm¦¦\¼é+~�RÊ ÐTÀ¸sê‘ b–“ê»jF¥iNªÑø �>.Ä‹(“*ob6½§ŠêQš±ŒúhË�G^³·ÖôUÅô(ÍPJ Ùóà*x„šýš³Ò0ªªß´‚#&X -ï œ<««áÁ+å¬~QõíP¤y^«ºüg•Oo> ;oÕáãÕÜõGTXô“û‰ ꥼu(c•êxÂ`ÍûÔ§e ÊPæMXÃNé Þ«®y8ü05ù%G¥i9Uûy·•RÉUÞêä¿ÇòAu‹¦éTîÆãÔñ$•OQëßUEô÷ö76UÇÒ¤V÷Σt ŒÕG©S©)»I©§tÆfÞý‰*a@a(¯>ߟt²œHµúíBJ�¦�W— )áþr%·¿µ}U!= »Ú‰ö—Þvé:�©ôUÞ<–íŽÚøAIeÔ4åTëu2•ÿ3Û­™ªµ³¦0”Pƒƒ“TªšÖ¨·òè:OÕsUJÙTøïÍ•=(Cùaê 9í”Jó{ÕÃ*MÙ¿4E]{rƒÔ+ó.5ÐO¯Ð\Ôk³#RÑ©B!ç…­¼Y´å4]š”$hÿe®FÄ`2[‰3Yˆ5YhV9?+ö\$.ÞJ´ÉÂÑÐf®ÿ‡>­+°xËé,‰GÅcBÇ \ŽMçNÃwúPë‰ëkƳkæ,Ž›Á¹é@†ÔwKruLóå@Þú?{ç^EÑàwoIo�¡„Ыôz ˆ ˆ"‚t”ª¢¢€ú�ØETD�bPiRC'ôÒkèH¿å|? 7¹ ¹›„"ó>ÏýÙræ´™9;;[ՌĬdƼ3ØÌÕèÞ£n$²aÚ ö§yŠl;8—ÙÛ-àׂЍOÖ*$ñÏàRä "(“_áns‰Iwn"kgÎæ¸Mãñ †Ô÷K³yš½D¯jfÄzˆßçîH~ n¿Á•« ³›[ú§àžµ½-†Ø Y+'VÊ(Ôé;OíM�@#–s›ùõ³!tn^‰By‚(Y§ =ÞËŒU¹jM¶gÝGiì§aÝ»šµ·—a?ÁªCvëv¤KXaˆZCÄÁT (f=+#À³>�5ñÓ){güÊa+ø´H¿JŽû€hþM<ò^è?€…Ò¬ 1” Ç¨þ¤ÝšÆ;¬ µ<5°�äØÉ¬,½‰ãü¹kØÑ0 ¥pV–ÝÜWe3V|…y[6ñÏtVI»ŒÉ—-ë⥠–ƒ{ù×I“ÄPŒîÿë—þ~u›PÛCÛ)§ºpí<�ýXޓđé½éöõA¬ÞµöÕÊfÑfÖý;Ø“ hV>MüÙ¯}C@óÆÇ;£>]ÃÛÇ �ëÑ\—lœ§ 7BB aD°Ÿ?Ëù;*8‹º2U z%w4‰g÷öébM¡P( …~îé»1“¦~›íkT«Z…:µje騧–bÂ;éÿde¦¯<Â�x &ƒMƒOçìæZ\W®'r=6‘Â�^tiVš‰ìä©F¥³-gz,lùK.^ů@~âÏ_àÏA�ø¸übFÔÈd—bÛ 6n:ƒ ÖKµAb*Œ¥©W7ãÖÓl߸�¤�!x`¤t—^4É’]?óó¶7ø¨ÖÍ5ú6öÏ�Í.‹� 'zÐ6ŸÚbP¡pDHºq…ËzNµeó–KØ1Rª^œUF�%¨]+†-g9¾}'W¤ù ÁÔ®SSÄA6}ЙÞñj§Æ”És;m�9PpÀ›J=§Ùþ VÌþ…ßæ-béêmœ¸v•£‘ 9¹�ŸÆ Å3¤=Þþ”÷úÔ&ðf{|Ѳ®'¿-ÞLÄÆ8ú¶ó„+«W°ÝâE‹Æõ¨ã†ï¸ß‰X…½Rr‘8iëJÖ^·­h¤3÷ØN¹% &ÊÔ¬ŽºË)Ûõ3&wu~ºæYƒzÕœ¼¯eò'ÀGƒ¸8ââ³0K+kòqFw÷é`]•Mó¦l•`Ê:ÈeÇj±`µZ‰7zà©Al|Κ¤yÔ nu'» ›ó�ÇWƒxçºpé<ÝýX"7Ø1±O™ÇiSzþ8›5²øÊ�xê8Qv0,FѴͶ[±Ù0aÎd߃ٌQ‹ÕšR°Õyž.4Læd›[fîí’®<(Z¼ Žuü$I„¡>} P( EÎpO‹7ýúö¹«÷ëß® ýÉÄy;éÿd¦.ù—«7‰M°0îÅ0ž³ »](èÅðg«2ñÏ�hš0 ]•\�ÆÎ•ËBØ�¹ü2º"+ŸkHß¿Ö1²}_J®™N§� &eö(NŸµ¾¯ž¤Ê4çÇ%^¼ˆ!îÌi.Û¡° …:Ðëñ,ýõ3§­cd­&Ƀaë^æÌÙƒÅX˜öÝEï³o…â¿‹;�M=Æï]ódzTâüž„tšÅ�Ôÿi‹âÌ9`¦`‘Bì�b$¸PŒœÅ~>Š vÈo4Skø÷ŒÜô£"63¹8S^  x�F4kÞ‚V�?ÉcuBðÊ…Z«Á¯4á½GÞ{Øb8µ{#ë×®%bÅbæ/‰äô©¾éׄÕ{þ$b\ËäÉ·D³Gk`^¼žõÛ±´k€™8Ö/ß@‚¹ �ëàãÞˆšn³ˆ\¹Ž:á�•ý«Ve3QõÑŽ_Yr{§£ì€‰|Áù\^9¨yùáë´74bL¹X–8h^øxÑ,×®'àžMûè’-ö0‹¿›È® rÏÎ^Ž%ÉîxTF:Ò¼ýñw:ÛÎ\.�—�~,GH:ÁŸ¯=M�‰Û¸á[‹!3ÿäÓÇ2ŠMgׯDc0ä $ ­\F7ÜLX’HLÌø*Ö„Ä䢉›{ò—Ðôž§ ;W/]A£_N>@–ŒËº2�'okôUnd¸ˆH¡P( …K™]óæ§É]–Ó…ó²Ó�e¹²žOÚÖ£ã„í$„>ÍøUËù̥ €�˜�ˆš»inÈK`CòkP×2zÉNôÕhì€!oy Ù8Oö(ví>� >¥Ê¤|*jt~‹)�ßBâϱ{í2–.þ‹Y¿Ìcëöi¼ôØEܶüMßâw§oÊW‡A?L`çú6|{ö+VÃV£4FÀX¶á¡ï²sïjÖ]F™ +‰8#õhÂ#&€²4ªŒ6y «öZi^|-«¶Y0 çÑJÙèŽnéØNlL,vîÑ“ 3�Ô­…¿áWŽ/fáž�«–…vI,—¯ ̛݃YûA?Æm�ÅX¼ ?-ý–çJ:^3音Lþy qÙ¼S¶Èf?¦ûù%¼Þº#_n�%°Á[Ìš=Šæô” 5Ü=RŠ­I‰$¦-P‹R2Ô§â8yâvBœø£�“GOaCóXIŠMçy:°ŸœÇï‘м©ß´Nº<úu%$&&¶ îÙ^y¦P( …â6ÝÊ›› ïRM„‰î`x§*„•Ëψg«1áÏw¡pãsé>L›ñ2•Üíœýs O[™þ3 ¦b” 5¡aåÄÑ®?�4× G÷j¸ÉU–üº˜«IÛ˜=÷_lîatëRAÿ“o…Bác(%Š+Ç�Ï f-œ8vnE‹Q(ƒ@Ô<ƒ©Ü¢+¯�ý�Ƚ TÞŒ\YÆä™ÉÒ—¬3$‘ó»W0gêX¾YuçÍa=‹Q²°bnÄÜ^ùc®JËæÐ#‰ØÃÙÕ+Ùoõ¦^ÓÚ)û•¸Q½q]|l‡X½æ4q›V²>V#¨yFŸÏ"Æ¢):¶qüðq§ºK<ñ–Ü_àÓ¬#­ƒ `ÝÇÔOÿàÂo)\_5œzEKÑhÀ/HÊÆÍ­{XüÏIl˜ {é=ž-™¶$\>~<›ÜæÙíÇt ×7ðî“ÏðåöxŠ<9�•‹ßÓY¸Ðð ðǨ�D_áZZ}ŠP½zAŒXÙ¹�xg—°Ÿ!2ò$6LŠÍ«­ûfIÊŒÛf¢òó½óÒ°î™À°ÉûI-½åØ >üþV¼{<œÜý ž•_û–Ñ 0ØÏ±èåf4ôÏ¥™áÛ®²göpkЃ_OØp+Ó—©ãÚgO6CB‹ Û×ltì,§˜?¤+__)B $îcïU'ûý˜+Ä,ÉËÓO ùÚñå�ƒy$>[e*_•Šî’°‡N*²žMпšry.o žÉÑTËõ-|Úÿ6'j=1„žåŒÙ>ïŽX¢9ñ##ÚV§ák‹9/n{vÓ^*çðþ|¶ue=À޽ ˆæNÅ*åÎwó …B¡È%T¿ hW%—¾(¥-/áŸÎáóƒ�´x?“º§sJÕP¬;£úO¦õ—x·ñ#,m÷áU‹‘×ÃNLÔÖÍû�Å,¸•İçŠÜªÄk�å(WÀȲ“G™Ò·7ÂC!è1Þ{ë±L µÞá·‰‡h3p6G §e©O(^­5Ê%ÐÛˆ5ö2§neãÖcD[ÁÔ�·g|Îy/ª6¥eM7¬ù›%…:6¦BêžÆTžF À¤EÌ¿ ¸5z”æN¿�žLÛVf_¿¿�ð×—³ä¥ºTû»�×*ŒñÂÎ^Àž+B`ÓwÛ+4÷ŸZxVáõy‹ k'ÞYx’�úPoòk«\•2…pK¼È‘ÛØ!Ñ ä­5˜ïf�¥Mv«JÆ’´¾1ïoZÆñÉÏû"ÏÔÈC™ݬœ;‡Õ‰møiþ£ÌlЋ¿bW1nè—Ø[†ÑªC]s¦åY&ÛýXV‘ËüñõtNØ€˜ÕŒ¨W‚·2̺õQØ«§ÙŸÆT‰!“G±8|kf>OÕMSiÝü­§Ù²x1›Ï&b íÌø/žu|p¢÷¼[$±âõ*y[±%píâE®'Ú“÷Õr+Ló×§ðèÖ8|Ø2te?»žuGlhæÊ4ªë¯Æ …B¡Pä$A½>• Þc%¨÷XÉ ßL™š¥ãîÖu8HÏ@ƒ€»<þã±gr¨ýÒTÁ]441—ì)œµ¥¾�_øžtªž_Ü5’?Û‚fï�úÒã‹UeÉLŽ 2´ŒIÀ(Å_Ž�„jžBñŸÂ…xIøã9ñÕ<ž–™1iÿ#ûg •ÖeÄä³R°vWùdéiIJ{Š5JV�í.õ‹úˆ1õ9hbô-&�ûŒ“5ç¬iO’£¿t•2^Ú­c=›O”S¶´w†]®îþMFwk*eÝD#õ=4£ø„Ô”§^�$kΦ“öÖý÷¾_CÌ hþÒiöµtGDÏê ~f©ýñIÛ‚„9ψ§†K• ·¹SÛbd߬¡òX™Ô:ÖÄà]\š¿<]vßp´`â?/H°1è+K�4%q¹ô/d AÒk‘³î€=ZvÏ~Oº7)-yÌšƒ.5ƒ§¬þ¤ ™´FÎ8¹´nÙ¬§eÁ›Í¤ˆ‡–ê^ÞR,ü ùóX¢ˆ\—õï5’üfM@sÉ×dm’þûeO‡®÷c7c,½od€í´LhææèÇþ4ñë:/‹ý¡Uö}XSÌš&žáßÈi§ñe—ë;��MŠŠ—!•=Lyå‘ö£eÑÉŒ ã¼[¹*}»4ƒY<ý J™Ú�I�“eé‘ç¹,Ûº²É©‰ÍÅSÓÄ\ûc9�6° …B¡P¸Lêz�ÔëSAK~ôrñÛWïXì™4õ[úõíãz•(—®£°{îÿ¿H¬Ý�€‚%)],ï�¿ðóý*´frTþ·yïVU‹°Š»ƒ…è9tú*‰F /KÉ^wX ’ĵÓG9zæ21V#Þy S²Tþ™ì�b½vŠC'¢Á·¡¡ùñru¹‰$}ú(ÇÏ]%&ÁŠÁ#€ü!Å)ìsÏ—lÞ¹m®žø—£g¯añÌOÉr%É—î{Îw{ÜŽ9É…k‰hž,QšÐ<¹÷y?Û�ÓØ’h»'ùJ”£t~O‡UÖ¸˜àIP�/æ{¾> «ÆÛ[Ýytò>ô-¢ÞÍW( …"›äë=†›õU¼y(±qôëTyi„Odïâ~U#,…B¡P(\à+U¥å„î3Ÿ]SÃÿ>/8åBôß}¨ÔîÎÄÒ_ÑÄç^ˤP( ŃOêâ�š²?t×"?¤ûÛÄKÑçíçUáF¡P( —ñ¥é;Ñ!X85}ŸmÍÞÆÊ4ñ‘|úÖÏœ‘`:~ü6�UáF¡P(ŠGMÛì§òÙˆ7ô\#*7ÉÚëîTze*#zßkÑ …B¡x Ñ tdÜÄ.„Xw2ö…ˆÌì»ðÿYbÙ0úE¾Øm#äù‰|Ù>¿Ú¨X¡P(Š\@oìÖñØ1L˜¹ŽÓæ’<>r‹>jL€a) …B¡�í¾fæðšw~B——æsþ^}�ýž`'ê��t»s­·˜5þIò«q…B¡P(¹Â½ÞwRq—0UÎò]¹lñ¤@hQ‚Fo …B¡P( …B¡P(îc\.ÞT«R%GnœS×Q( …B¡P( …B¡ø/ãrñfûÎ�9r㜺ŽB¡P( …B¡P( ÅõÚ”B¡P( …B¡P( Å}Œ*Þ( …B¡P( …B¡PÜǨâ�B¡P( …B¡P( Å}Œ*Þ( …B¡P( …B¡PÜǨâ�B¡P( …B¡P( Å}Œé^  P( \9{™xÍ› ‚¸'Fu)»Á'ùß÷Z¼{F½$\áìå8ÄäKþþ˜ïµx®�%ÙÓ´÷.‹˜b‰%úzfß|Ü´{-Žâ^ðÀÄ^r ʼnß|Áø»åìuï‹Ø|`l‘šÊå¹Úö{hãÒ¦6éú5eƒœG�eõqõ¦VÞÜmä:ÇwneË–-Yÿmû—‹–{-¸BñpcÛ7–ÅŠP¢ýwœ¶CÒê7©^4„¢ÕÞ "é^KwïH«—ÄŃ)BhÃØú€å­¬Èž¶½Žñçö°úïY|ÿÍx¾üâKÆó=3æ­dû©ÒžÄíâÛžµ(äçK`P^üòwã¯ÄܸÑ@ýëÖ­ÛÙ¹ç '.Ä`½×2æ"Lì%.bPÙBB0zKÎ z?Åæc‹TäT.O\ПR¹ÔöÌmœ»<ˆ6}`É _ËMßJGêþdë~Î%dñ´'Ùµ5¹ïÙv𷇇qœÙ»•-[¶²íðelwº�=šcÛ“�ßuò¢»!™£Æ²ú¸—zS+oõaâÜ IDAT€3gN³lÅRÌ&3uÃêQ¼x‰Ü»™e-£›?Á—]èuÜš0þðr…ü÷kmöë§9e'_‰¢äQ%uÅ}ƒ�³+–±×j¢t³¦„È�‰øGz½Üq@ò@“¾½É×wÿ̨×Góí²#ܰ§fi/Š4èÁèñÓ½²/9³6ÆÆÞ/{1ð§­XŒù¨Òº9«‘/E®‡.ŸÞ©Õ ¸ç-Iͦ�Ó©Wz¶*��Z¤ôá~‹Í�Ìåš“шÍh@ËQefdcÅ‹Lúµ\ó-'¤îO4_Ú|÷/ó{ß!?ØØÿÕÓÔ|g+·úcÙ¿úUJÌĬFË——íU�×­`XåŒÖkØ82åYj\ÂU¯0Þ[½’ÊEsº�ŠU¼V­^I�j5(T¨0³~›Ió¦á”-[.—ïj¤@ÕæÔ,œ…µ¹Å<†á„•Ýc[Sócƈà•âªgVÜ'ÈUV-ÝB’¡ MÂÁ¨8Õ˺x㤽±‘ïÓªå(6\¼K4¥Wç6Ô«J —˵(þݺ”Ù¿üÍ®ÕéÝt?W#3ä‘xWD.±.bIb¤X¿_Y?¾)ž·þø0çS#kµ¡^Ñ›ý«`�¿Æ…“Ùsà0ëæ|Áº¹ø´ù›|÷ÓÿhYH …xî·Ø|ÐÈÁ\îþô ®[fä¤tÉd`cÅŒÌúµÜò­ÌÐ44bX1m6'º¦Xf]©e;¿ü²+š–¶Pl¦ì€ï·²=~ßÀèžÐlÍhj{¥¿Œõà^¾”+Ðìýx£šGN¶Hñ€£r‹›»>>¾t¾?Mÿ — 8&j½2‹¿ºçyHŸò8A.³yÓ!lÔ¼×’(ŽÄ­céº8´€v´¨õì3âaÓ‹³öÚ�óð�Ùx ò†�eÕ¼!TJ;ë6€7ßœÏÀf˜zp£†þD‡}ÉöbJûu®]·&JV(‹Ãðî¡Î§&j ü‘ÙNúWËÅ�ÌŸòï|2‡}ËÞ§m³sü¶jmƒ¦âÖ�û-64„\þ ȨÈ>™õk÷c*–:ÊÞu?1ãÀFT0fxh↟™ù¯� 2e�C¹žöCQºNšÌÊmíùqû§ôú_8>k„oêc’ö2®ïÛ¬Œ†|OŒå»AåÔÞ> TñhÖ,œE‹òx›Ç)T°È],à¸NÒ…ƒì9y1æ¥D•äI7ÀbNíáàùDð¦\Å"x§½Únœ`ÛÚ ì9q‘6Oò«DÝFµ(æ›ùh%éâ>Ö­ÞÌ¡¨ëX<óSºfcW N·I“íòav‹F¼ S¡BÁTO‚S°_áÈŽ£\/ U¨@!OáÚñ�>·žÅ[“‰áÔî-l¹lÄ#¸‹x; ÀõʯPè%ióR"¢ÏÖ-¨Ÿvð¯iÉþ)1œØ¸œˆ�'ˆ¶y‘¿TM7©JÁLv1³\ÚÏúµ[8pê2ñš�!å¨U?ŒrAé¦}”íG®€o1*— ”xŽíË—yø2VŸÂTlØ‚F¥ýomdf3Ë–oåØ5Á¿He·¨G±LÞÑW™ê%\i·Ãý²˜ƒnc'æä6ÖoÚÃÑs×H2ú�/´"uÖ¦„ŸëùÂi{ã6±*21Òö•~é'‡)˜ =Î'ŸôaLJ‡(ZÌÎ…DI—³ªáÚ±�¾x”Ó1’ÜÎS»Ù²å,c^ò\çây'ù´@0žÏqU<)\¡ÓÞ?þ,ûö�%7ò—©DQß4þb½Ä¡]ǹ†¡•Ê�ïÖˆÒ5=ËÕ#l?rü’}Ùrb-ÿ³ƒK¾µiß©6ùSÝ6§ó½9_ž~ëWZ´úŒ§Z cùÁïè3°;fw¥�“KfÉr•£Û�r%‡ô›&Ö%†W±ó8Ñ6/ò•¨Nã¦Õ)¤cV£/ötÆ‘-šCëV°nß®‹/!�4 YýRøßAFI8ÇžM‘ì9vžë‰¼ S¦Z5Jd8h½b3«èÍM¹kYÊå–Kì]½‚MÎk H¶gX üÒÌeoöUâî8Mׇ¹èיɨÇg’›ôßµé�p½?Íæ˜åŽöά_ ¤dÕâø_sî[·UË©mkذ÷4×ì~„VoLã*p'�sû÷r:ÎDPéÊósá±¹!˜æ-ýøwüv~ž¾�¡ÕÊ ˜ËÊé³9!yéиKÿ=èô(-ß|ñà 6=:Ž}_õæÍ‘Lxô惆DvŽíÃȵ70îÌ„É=(–q­(S\¶¯î±¬‹þ›Í<�çÊüñ.Íêõ©õ+A½ÇJVøfÊÔ,w·®“S8°_ÆO'ÇŽ‘ÄÄD‰‰¹!¾/ìÏÙ%.�ž�wyüÇ+bwñtÛéÒ± A0J›o�‹-Íßí—HïP£ ùJƒOvI¢ÃÉ$â“öRÞÏ ·~šüÊKÇÏÖÊ%g%—yo4•"îZªs47)Øè5ùãXRj äÊ��‹;ˆ¹ê»²ËêäzÑÓ¥­‚©’üo‡EDäïyÓÈ„€QJ½¾^n]]¯ü E¶°ÈÖ·*ŠIs“FãnÇ\â?/H°1† ’å§WÈÈfÁbÖýÒ£øS2qW\úKÆ’Ù¯6‘"ib Dó(,�‡Ì–C ާ$Ìï&y4Ä­áòïáÙÒ÷o‡8ÐLÁ>f‹ÄدËÖ¯ÚI1‡xÕÄ­HùzW|zYtÇ•s½$üñœøjˆ±ôPÙ�”æísP2ö‹«å“§Ë‰Ÿ!í½’ÛÕé«Ír-M»2•=ƒöʵ”|fÈ/½:ÑoVqI7 2¯«Ÿ“œ‰h>�ä­ç3ȧ¯N“w*›-�<÷û�t"\Ÿó¬hš§<:%*]ÿ”´áu)eDŒ¡ƒeUb6ôü{gñÑ·Æ_Éþ ïJ¿äs�E˪›z×ã—.õ¯693­�LdÄ–4wÅ–�22õš:ÖŸ].ÿkš>·¸‡¶•ñ;sKnÄžûŠˆ$ž%/T Cj¹5£ä©Þ_æ˜-Ïùj‚±¤¼º.• öhÙüu©’Ç”Þ5O)Úü ™w<}¬ß_±™Lf¶Ð«Ó\‹µ;ärSÙ7dÕŽ©Ò¹ŒcŸƒf”¼5ÊœcÇ{ÎyF<�´]¯_g&£nŸùÏÛ4tô§Ù³dÍÞ™õk�å÷„Œ}KD$éÈlX;HŒš£kó±¬=¿AÞ(c …eÀòDÉ7û·†2vɇRÛMcè@Y‘Q*¹:G:Ä�¯«Ìú©³øjˆ[ý±r$íDMDDâdó¨Zâ­ib,Ú]þ8Ÿlä¸-£¤¦—&𩤼°ð’ËsÄdE¸fßìŒeuùo6ò€nçÂüñnÏR×kTñ&w¥€“Íâ�ˆ]Îýþ¼„Cþ§eúéTYÁ-K–“f�€æ_É�Ôý©=ZV­"^bð¯,Ï}ð‹ü³a«lY·H~ÕAÊûh‚æ'õ>Ú.yÉ~Aæ÷-%nš&¦àúòÂ'?Èï Ê?~$=j惦‰[™�òÏû-ù\/ÞØädÄt™úésRÖ„`*-�>š"S§~'¿n:ŸÜIë•_¡È.¶C2¦®›`®"ï¦r蛉ÛTòiéÞ4H „õ–�~üS–,]$s& •–!n¢¡‰Gا²?uØ£dn·P1išòÖ�žŸÌ”6l‘­–ÊÌOzHõ<A3Kñ^É…T "qqÉo@Ì•»Jïú¥BÇQòýŸ‹eÉŸ?ÈÈv¥ÄCC4Ïúòö¸žR<¨ºtÿhšüµd±üñíiš,‹OËÉr*õ@";q•�^2àêl·ë9HD¬‡eBx1 ‰GÉÇeøä¹òÏê5±ä7ùjp# 6i‚¡�t™{Á!g:ùÍ ½bÙ.ÿ«d0HžÆïËÆ«:†[.ëÆ&'Vþ$ßNù@:”0 ˜¤ÂóŸÉ”©SåÛ—ˆ•åÓÓ²zH 1b”b¯¬‘4C8Y> ˆ�âén�<ÏÍÇ2„U|TKÌ$Ï› ='.ì)�Ä\³¿¼ÔØG¼‹5’N/ �¯O—}VÑï—®ö¯ òRñý�Ø"·ºL—í‘$ksP¯·b½JÔ<Ÿ×í#ÿø§,YºXæN&�MÉ-u>qÈ-9{:í+ ‘òvÑÐÄ»ü3òÁ¬å²ik¤Dü9Q†4/"ÕHuŸ´Å»\˜ÝY‚ ˆæSNž>AfÎÿG–-](s¦Ž–îµò‰QÓijÚHÙ’vîu_Åæl¡W§¹k™èïVñ¦D3iQÆK Ôë#ýð»,Zü·üòyiPÀ$šxÕþPv¥.Òd0ÁÖë×˨Óg›f„žþ4»c–,Û;³~m…·eR¼‰ß(#*'ç�â­åÍ)Ȳ•Kdöø—¥iÉ×êyilŒÅeÈš¬T¸$Uñ¦®|v`¿Œ©ë.š¡€tÿëº3ÅÊ…iOŠŸf�‚½È¥9�Ä+Óâ�ˆ$í“/›ˆƒì8CN]ß(#ªzˆ¦¹KÅ×"œûîˆûêËêõ_½y@¯�siþxwçö‡»x³~Ã:ùò«±²~Ã:§ÿÞ·¯|ùÕX9vìð­ÎW_!ûöíͲ]¼û%ù»Oq1i)Ôù79—r‘«_•òfM A­eêQÇ ž´åm©dÖDs« ¯¬¸šæ¾v¹0¯‡„Í·•LM5»KX?TÊš4ѼÂäƒ�Žnm�^&KÍ]ê|r@¬)×r½x“Œíäxiâ†àÖ@¾8ê˜íôʯPd{ÔyÔScñW$up3qkšAò†)ûÒTÉc–”âÆdþ<•?Ç­zIJÍ\Q^[}-�/_ù§¿”2"𩼠ß|û†·ïg”�®soŽˆˆÄ.“¡FAÓD3•–�Ëcäú_Ý“Ïõ~Jf\»ýÿÙ‰«Œô’ÑWo»]ÏA"–Mo¦.*Ë;ÛÒÎô®Ë’Cň&Í'Jêúw¦OV3h¯ˆMÎÌê$…Œš€&nÁµ¤Óë_ÈÌå»%*6k¹H¯nÄzP>©cp—ðIŽ+:2ʧq‹ûH°1×øÀq oÙ*oU4‰©b7éæ–ü7Í„gÊ£ž¢iþÒñ×èäStê9qI_)`@ þy¥@õ7em´c‹uû¥Ëýk¬üÙ5�hhâþèTIyø©Ë9©×Ô¹%�³Ü²´¿„Üê;ä–œŽ=}öµËå™$@C4¿21ÍXDöȧ RVp8o®Ê/Oy‹†Yj~¸OÒ â"eDeñÊWGFE:®ô¸c3#[è�™ÜеÌôw³  ‰oã±²7­nxS*™5ÁP@z.ˆ¹}^FÅ�~�±Œú|æa°iFèéO³?fqÑÞ™ôkÎ}Ë.n'~¢ù6•q‡óƒåøOòT°Q4ÍÉj¿Ì¸ÙŸ˜ÃdÌ¡$9õM¸xiš<ýKúU¶S2©…—hÆb2xU¼Ä§È™iñFD¬Ç”v ‚!¯T­™\tñª9J6;[|–ôØWïXV·ÿêò ý6έùãÝ�\u(Þø5lh÷ÅdzOý’d§ÿÌ> x·Êð&i6qÔÈ×f(/T5#1+™1ïLÊg�“Ø8ãW[Á§å@úUr|QóoÂà‘¯ðBÿ´(”€%‡5”}ùŠìs}õR6&h6iA '/:‹¡=Fõ§|š÷Z½ÃšPËSÛIŽ�¼ùÝŽDÖΜÍq›†GãA ©ï—Ηó4{‰^Ṏõ¿ÏÝ�5íýŒåéñj[ ¤>Ñ«õªšÑD0ÕìËËibħv=*™A’Îp2ê¦,Ù‹«;éŽíÖ—ƒŒ_aÞ–�Dü3��UÒ¾;ìKƒ–uñÒËÁ½ü›ÅOªdÜ^…:}Ç⩽©hÄrn3¿~6„ÎÍ+Q(O%ë´¡Çc™±ê WÓ3[ºÑ‡gÝGiì§aÝ»šµåÖÿÛOE°ê��ÀºéV¢Öq0•rbÖ³22<ëóX? zNyGÜ~šF=ÿÔ-¾›ùÞ��ÐBìçÏrÞzí‘“z½‰ŠÑýýÒç–ºM¨í¡�íTªÜ’úýKŸ}ãYý÷r®‰†oËÞ|¹f$ƒó³‚�Âzð¨\[òsÏ:ö:ö£¿1}u<Æ2�y¾žG–?Dc íÆ¤IÏj¸ÊŽ-‡±ø6佇SÓÉž[w&{s6ׯ²Ùg¹æzmœû㉻2°;Öîé†Å“¦~›íkT«Z…:µjeùøÚµÂ7þsj× súï={w³k÷Nô ÀéÓ'Y¾b9O>ùT¶euÄÎÕ#[ØtäNǹ“ï¢ká|øíˬl1–Ÿ_y�2mwóå…;�gB—"8Tål'ظé 6LThX�@gYÅXšzuƒ1n=Íö�ÛI‚‡í‘[¢°a¢LÍêé[)Ûõ3&wu¹ñ®¡Wþ\Kñ0�ÀÆ¥k¸�7ÍÃë:õ)ͳõª9Ù\ÌäO€�qqÄŧt(¶£lÞr ;FJÕ £€³ò¹±µkåðå,Ç·ïäŠÔrØ€PóªLõòiS·;þþ@y+U!4Í|Ió HŽ_I >á¦,Ù‰«;ëŽí¶ëËAšw0e«S6õЫłÕj%Þè�§±ñqÄgi'Æ,9‘Ç2m×1öî�C0Q¾fU'9ÇHé6m¨ð¿HvdãÉ®ôÝÛæcÞÏü4ë(}^+•2ײ±oæt"“LT~® Õ͸ð€EÃ+0_ò¦ßV’íoש‹lÎÙ\Ë’}ÿuÉ/ôÚø.Œ'îÊÀìxiäËqúõís×ïY7¬uÃê9ý÷îÝ»øëïy¼<øÜÜÜ8uú3fΠ]Û§¨ôHå–Ä�æ_låÇwúgÞ´•Âd|¾Ëw¯/§É‡Óxkœ†©x/¾מàtO´¢8}Öû¾z’*Óœo]žxñ"v„¸3§¹l‡Âö(NG%®/_p>îÙ2-½ò?tëÊ9Že;KW]DÜ›ÞØù IóòÃ×i&5bLñÁ[ý–-Š3çl€™‚E áÜ“�*€‘³ØÏGqÁùS¨ùøálc|Í`4|ü|ÓËi0¤üŸÜ–%;q•½8 ·ÝÙÉA±‡YüÝD~øs‘{Žpör,IiEY¾^Ûkð+MxïQ„÷¶NíÞÈúµk‰X±˜ùK"9}*‚oú5aõž?‰×2y ‘>áZÍ­�yñzÖGlÇÒ®fâX¿| æ*4®€�{#jºÍ"rå:n è„?Vö¯ZM”ÍDÕG[8æÖlèYó*H¡žÂÎ];øóÏ?xíÕ×qssçÔ©ãL›>�§ŸnO¥J9]¸IÆ3O! É“õªy:¼¨Þ€"oç°Mïb}ªæur5I"1)y#k±&’��A(ù¦„/˜Ý’�$‘˜˜¼æÇl6gCÎl¢W~…"›Ø.gÅ ¦*Íiœ�ß¹I$&%Ÿäîîd™w f·ä*¾XIJ×[j™ÞR˪<Ùˆ«,éÅ�íÖ™ƒäÒR^où4_l�ÏÂToò-J$�·f³É|1} qY¼žëíŒ>„T §SÕp: ÅW71iÀs¼6÷(û¾ÂçÝwòA 9ã®` ¤y *˜Ö°wíÛPÞ¾�k¢1”lDÚVŸ†åM¬X¿ŠÍ‰�7ŸeõªØL¥iÙ²Ô­Gvõ¬¹¹ã–¶Áw3ßۣصû<6 ø—*“ò©p½öÈ9½ÞBË<Ö³†~ÿÒe_I áfÌ:{•ÀhÂdHÿÍ¿o/ÝÃc³§0yÚlæGìæØÆ¿øvã_|ûá«>Ç»“¾d@íÛã¦-6õÆL®ÄYÓŸæá‰G�wsOžTHRRÖó’‹~�™Œ®ûÌߦ ª§?Í}åHËILÉ9·åH‡ÙÏä�Ξ�ºól©©|º÷¦EŽà³zn$¬›Î¯‡lxµxžgŠ»P2±ŸaÖÀ¾|ÄNþv_²ð‡P¾¬×’/·}L¯‘ÍY?¦!¾®—Ý9›‹'d{œåŠ_èµ±Þñ„ý›çNã§ciÞ÷2–$°ÏÅ›»?PÅöïßÇì9¿1ì�ḹ¹sòä1¾ÿñ:vèD•ÊUïµx"×VòNÿI¡!…£9½ð úýЄy½‹;5o|}4ÀLÝQëø§_Á¬ùšæ…·—؉�‰ÅN@ά¾±ÛpiU ^ùŠlaçÌÊeì³)Ö´¥õ®tHÍ­˜âb㜭ªâcã’_•ôòIÿ¤9§ÐW:ô¢·ÝºrP"k?èǸí±‹wá§¥ßò\IÇE°IÿœeòÏY-Þ䌘òÕaÐع¾ ßž=ÄŠǰÕ(�ñø„±l ÂCßeçÞÕ¬»4Œ2VqFêÑ„GLeiT?mòVíµÒ¼øZVm³`(Σ•Rí‘£zNá.æ{ûÉyüiÍ›úMëàÙŠÑœÑk£»=:í«yàé‘|¿„ø„ô«9$ö1¶ ¦|ÔèüS:¿…ÄŸc÷Úe,]ü³~™ÇÖíÓx鱋¸mù›¾Å a®JËæÐ#‰ØÃÙÕ+Ùoõ¦^ÓÚ)C"7ª7®‹�í«×œ&nÓJÖÇj5oE­›½rZÏ7¹[ù^®°øýÏY/‚ÚÒ£mPò *;öÈ ½æ4zÛ£×¾†ÌŸüNTÔé³NcÖvìih:Có ¦r‹®¼6ö7"÷.dPy3re“gL¾îƒ›zuš[±–Å\.—Or*í$H¶q64L‹œ}•‹ýÍ}æ¿nÓÌÐÓŸÞOc–Œ0ä¿�sN9Ï9–½;Ø—#_U1R¡KwÂÜíD-øƒõ—Wðëü �¯-ÝÌr¡%açz¼ùW´PºMüŠŽ“§ã>õG2õõª¸[3¹ï«üuÁÐ5gÓÉÝö_½6Ö;žÐ©Üª=:tpüµoEe§çd‘Š'U¼âââ¸rõ*ìcâ¤oxæ™NT¯^ã^‹• Â¥¿_§ßÔ#HÑîŒÿø1 ×Τ×*㽜}Ʊ7õ²1-? WÀ„�c‹°Çi³s6rk]½íL†`ê5(� '—/e_:/³²}t-üÜMø¶ùŽó)Aêáã�IûÅó\Lavέ\ÆîL#(Õ¾Ù‘_¡ÈqkYº.ü–CÛ_ Ó a©”˜ZÆgΚ°‰ek®#š5†9Ýð3GÐWzô¢·Ýzr�\çÚu;` °“w£-ûøéû5áößÐ IDAT$ YYdÚÞDÖ~Ô‘N/ å•×¾fK|æ—’K‘lŠÍ«­§R@ëù6¹˜ï-ÑŠø‘m«ÓðµÅœ7Š=;‰i/•KõD?{öȶ^s�íÑm_O>ÙŠ@ƒ�1žÏVG;ŒýÀð¯vb7:Žìçf3¨U{z<÷"c6ßH_pŒßÃÊõç°kfJ—+�‘06õê4—b-«¹\“‹Ìùàs¶8ÜX¸ð÷X¾ßcA3W ]» l¾™=2“Q�Ïü×mš9zÆô÷Ó˜%#–á½[H)MÐÜ¥tß¿äœÃ5ãeÇçÍ%È€h)ת·¼þÎÿäÍÛJ¥¼FÑ0H`Ó±²3!Õ)Ö}òi]/Ñ@ •ä©Áïȇ #ú?!�äñ‘š#>“>!FÁTQÞÞfI¥›U2¨¨QÀ ~ÛÊ‹/–ß[˜ÒF½ò+z°È–Ä„YêŽ9$6'G$þó‚C�¾²$ÑÙË¥!ƒ`’^‹R/»>o&�D3哚Ͻ)ŸNœ"“Æ�–ÁO”?¢™‹Ê3?«³ûê/ËÓÝ/Aþî‘W4ŒRêõõɹÂáϳ¥£‚©’üoGª˜s9®î¬—„?ž_ 1–*Ñ×n×s�MŽL? ÑŒù¥N÷wdìWŸËoö”ðR¾âò¬ÌÜñƒ´õÑÍGªõþ\¾ÿu½œµ9“ýÎíI�ß=#%=4D3H‰Ú�JÇn}¥_ÿ~Ò§[GiU§„˜4MŒA edÄeqLS:uc=(ŸÔ1 ¸Kø¤(ÇkfšOEÄvB¾jì.šÁ Í E,G·J”eý ‹A3ˆÑ ‰{“ñrÒAúõ|ÇØÑ›ïSõ¯^A!zëW´Hñw7ˆ–üáÑÜ Kó ädº`Ɇ=rD¯úsKÎÆž~ûŠe¯|ÞØ_ šW iÞûMyïÃ÷dØ m¤B€YBž}Ež 1 ÆâòÊšAíѲbHñÐͳ¨Ôïü²Œüä 7n¬|0¬¯´.ï/M÷rƒåŸ+v¹ßcÓ¹-ôê47b- ¹|î³â­!¦r¤[ýñ+ÛF¿÷•Lžòµ|0èQ)é¥ šYŠ÷™/—R)-aÎ3âéÄ]÷ë;Èè²Ïü×mštŒé³;fquŒ”I¿–‘o‰e¿Œož79縔ZO÷‘—_ ]Ãˈ¯© ´�ð¹<ë¯ Æ’òê:§I߉|)ý‰9LÆJ“éo,�^ ˆ©Ê(ÙiqüóM9Ýê�•#·×&§gv’ÂFDó¨*Ã7ÄdvsÙ3¦¡øjˆ! ¹|uÀ’ɱ©qݾú씋þ›‘_è¶qîÌïêÀ-©ë5ªxs·¹5¸Ä…ŸA ö[*‰b“?<)ù ˆ±p™sÞ™—Ý�5¯W7M÷НËêë7—ã ß“NÕó‹»–êúšA¼CêK�/VI”Óü#ûf •ÇʈéÖyš¼‹Kó—§ËîéåH<ü›¼T¿Pªûhbð.!­G¯�ó ‘2¬¬I0–’ײ¯UŽþÒUÊxi·Îñl>QNÝJ|zåW(\Äú¯|fLä­­Î�J≑ý³†J벩c Aó�‚µ»Ê'KO§+ÀäNñFÄ¥¸Ê‚^2ž@êk÷Íó\ÊAÖÓ²àÍfRÄC»uÍà-ÅÂß�?�%ŠÈuYÿ^#ÉoNž´™K¾&k“œÈž…ö&c—«»“ÑÝšJÙ@·[‚Ûí3ŠOHMyêÕI²ælFGºÉ¬xsÇ|j•½ï×3š¿tš}-�Dѳ:ˆŸ†€Yj| }¡B§ž³6ùБï3é_5ƒY<ý J™Ú�I�“eé‘É|œ¦×W³¯×œ/Þèl�NûŠˆØ/®‘1‘<¦Tçºå—Z}¾—ÝÑ›eD“`((/.M=i‹’Uc»Ký¢>bL-#š}‹Iã>ãd͹mÝç±™¡-ôê4§c- ú»þK;ñ yzèÜjù¤}yñ7¦º¿GaiôÒ,9Ÿ¦í9U¼ÉŠ�]ñ™ÿºM³Œëcúl�YîFñFDìW·ÉwƒZH™¸ŽËÿ%"[îŽ Õk ÐÙŠO§5)�F´½^ :5™©kú¼cJýxHjd§¥#×Önö�Ûgújôôy[Õuðeôi|]ïeø±e1õkºi¿¢ë¸¤×ߟ¼†þ€'ñÞ0ÆcŒ1Æ+s(ûþ»t×S\Ú¹A¡ç¹(~ˆêáóq˾ÖÜÞˆþn%“N&ÞË^Çùƒ7¥*XÊcŒ1ÆcŒC3=›·C÷ý1uOŠîë³ÎaÞ׫p[#�[Ç^èàZR©dæà:~æeØ7ÆcŒ1Æcì#‹ï¬GŸåW± G=œêñ:Ú…xBšzG·mÂÁÙ¼:cÚô7áÍ�X(“¸ŽŸáà cŒ1ÆcŒ±²GðAÏÅ‘ØQc ¾œ¿ '6ü‚;4èý >Ÿ>¯û$VZq?ÅÁÆcŒ1Æce“,áW"|â2¤ß½…;³¡µu‡…¸ó/š¼¸Žpð†1ÆcŒ1ÆX™'‡‹¸ø—t:˜õ¼ÜuÌ,fŒ1ÆcŒ1Æ+Å8xÃcŒ1ÆcŒ1VŠ™¼iP¯žENl©ÏaŒ1ÆcŒ1Æ{‘™¼9sîœENl©ÏaŒ1ÆcŒ1Æ{‘ñmSŒ1ÆcŒ1Æc¥ocŒ1ÆcŒ1ÆJ1Þ0ÆcŒ1ÆcŒ•b¼aŒ1ÆcŒ1Æ+Å8xÃcŒ1ÆcŒ1VŠÉJ:Œ1V6(ððîäŽðôsƒ­2‰)™ÐJœòþ]ÒÉ+1ÊEñwdƒdÎðöq…¼¤“g £Ò^ ¿Ï9‰†�* ©é¹�;»ÁÉF(éä°’Pfú^^Ê&)œ½|ájcÙÏ-}³ÌÔE~Ë­š÷¬ã2Y§e[¡y�ë@¯�ÿy-,ŽåÆ;ož7JGܹSˆŽŽ6þïôHV•tÂ{¹i.ÍBÇŠ�¨Ü{´@nä$4¬PLDDnI§®ä,å®P£|yµž†SelÜ2&íó«‹�“ƒÈþÀo æã§9?aþ‚ß°vËœ¹�‰Bo·„ìóX:8þ.Îðð,ïw±Ui�•æ×S§Îà\ÌUÄßÏ„º¤ÓhEe¦ï)wâýêåQ>¨¾‰¶\BKSß,3u‘�¥ÆråöQ¨j¥¼]ÇÖUë´Ì20¯Y³mEq—oÇ¿-À¼Ÿæâ—EËñçŽ#¸’\B“n)˜ÿy-,Ž9åÆ;oܹ“€½û÷@.“£y³¨T©²õN¦:Œo:¼Šß˜0ëØ´Åükûð~ù?Ö¦MOÀµD-¼*W€;‡ÔY©¡ÅÝý{qQ-Cpûv’À:âeNárÑ”t’¬ªp~óÒ/¬ÆÔñß`éÞëÈÐR¡#‰[ Â7ó¿ÇÀºÎ°Ìwc\üiƬ8•Ô õºv@ˆGx=N×K7ž7¿ Ø–«‚Æíº£ï�QÜ%N¼IéQÚúfYcÁ±\�B&•B#•@°haªcöb)b^³ZÛ*&E)QøíÛ/ðÃò}¸–®AÁQD�¹"8|0&}û5.÷œvFðüÿ²âà €ƒ‘ШA#øûà�¿Ö¡C»pT¯^ÃÊg•§~40¢GÉë ¢ý˰œP㬮hü½+~¸��+ñÌÌJ z„ƒ{¢‘+ñCÛðÚ�à/ ·\^èà�žü@VÔÿÐ¥ÓTK#8Vn‡!ý»¡E­ x8H JKħö`ýšp>òW mw�"valm Ü+B)8ƒ\’¢âÈ?qt~;Ø?}ñeO¥ð 톞̯uNîßºŠ˜+×pdÃÙø fv˜„e+¾D'^ •y¥­o–5Ëm{­Eºj­%S—Ç@³LQóšµÚ–áÄ ãô\ è9 ÛrA‚=üê·E§6õQÉDzœ{ˆ=}»ö�û~°[°ë×X9¤쬞4žÿ_V<öÈÎÊ‚�­ œœœ1ð�AX±j9X9€#CèÇ`ë@÷—ô[=èNžˆ…�K:%ŒéÊ>‚=G²!¸½†Ž¡/áÂÞ�—­\ôåW‡ß'�ãi@¹ðY8¸e,ê88îÝј4iÆ´K®ÄÔ +ðÆöá0{3¥6iéZ2T ©®»X|©ÇS�YŽõzæWUò9l[< _ÌØ€K{ÿ‡í“ð×Á…èáË‹Û2­´õͲ¦,Œåe!�Ì|EÍkÏ;)·Ö`ð«ã±ý®RÿÎøò÷E˜Ð)¨Pšrâ¶ã»!C1ýàMlý*T=†Û8[9q<ÿ¿¬8x }ûpìܵÝ»u‡¿_às à˜.÷þUÄÜÊIË¡r½Êp/´À dÞŽÁÕ{JÀÎ5j±ÀêU“�Ó‡�!&>{xU¬ƒæmBQѹèÕJnò%‰<‰ØÄt¨ì½Ü8 aõ| =dIóàÎÝL9 $Ä/_$ø1íC\?{�Èþ!!ð·'¤Å�õ¤£Øu*D™¸}!Ѥ°ó­�Z�Ž: p±égL¬Ü“{‘J°ïÚ- .þ!¯}R&â�ïCĹx¤jà]µ1ÂÚÖ‡_O!S¥\ÆÑÃѸrûrx”¯�ЖÍPóð”RoàÌõ‡€sEÔ­æ ™2 göíEÔµP; VëŽhìút»nÎ�“Ø»ïn¦\ë"¬c T,â1ýªÈr)‚)ùÖ9Ÿ‘cÐ3ZdÞ:�£'bp#) ¹R'xÕBÓÖMPÙÅôñBo~³Oà`THâ��,|qø˜Ì¿;f̆³ßÅ¢BE-î+�ò…Gcˆ�vó®%ß@B&ååóöDGß…DZ^néH¾§g<õñ…}r‘=BBàWðü9wqéÒ]dÃÞÕê ‚s�ö¢NAìù8¤ÁAuªÁëéÆQÓÊ™]Ç™ë�—¼¶¬Š?ŒvŸEŠsôîÛÞùNkéñ^îU½>û»üˆ×»Lƾ«Ë0lLœ]ÿ6üõ|¤QõA�pãÌ <´P¹zfè딉øãûq.©xUnˆ°v á/âªF\ßÙ�4©ˆ=²G.ÝA:9£|íVhß²*\‹I#)’s" 17ï!])�ƒGª5h†FUÜ .ZKOß4–رÉ:}ͨ±\•‚‹‘ûqâJ²dnyõÙ¬2\¤Îùx®"[Ý5h¡9ÌÄv]TÅ´™¼,½¸uZÓçS3×,ÅÖwQóšªÔ¯×4ýmëYQfáöéC8v1iZ5 CX=ØB�¤Ë‘�-ƒgp]Tt1¢�(&ŽÃ滞�ñÓÞ-SSéØWì†o·mڴôӗ°dÆ_Ûj($¦Ô—±í@äü¯çzª(&·ÑkaÛ¿™ãˆ9mÄ*ןbÊÍsÈLò:‹<‡Î"c,X¼Ä¨÷=¯Ï±”+W.Óü_æÒ͸ë¤T*)33ƒ~Y0Ÿ®\¹lÙ)·Ó` ¶Ô}ùCÒšx¸&a-õñ“$Ômii ¼®}°�†I ‚3µšqž”:ß§ˆ½©¦‹„€ðôO ‰KMêóãaJÑ— Ü8Ú2±Ú ùŽA°!¿6ãhóÍÜü) ‡Ë»“-@òú_ÓyµžÏK]E=ì@�Õ¡/ϪˆHAÿ *W M @JUÇ¥§Ÿ.6ýŒ™EE§>«E2Á†ÚÌ}Öç”»G�¯$-ÿ>íKØO_µ÷%¹ Û.í*½N¿žÏ.ü‘9±´þ“¶hW O$ØPØØõ«Ð=D±í]r@6­çÐ×ÖÓðÚŽ:ý@�ùRøÑ”©M§Só^£Š:ýU ›ÀnôóùœÂiݯô—‹bór@Òà t,·À!"òMD&ŽAy´É‘4£W r‘ ƒOÊ]L»4i~ÕÐ�•¯‘§Y}] ÂM©Õ9úʂ嚿¯_»»�¾lWxl± êAóÏêŽ-Öè{bê—ˆ(÷Ú4¢�Iò§[�’{ÃQ´áÊzà,¤Uè“#ùªM¥“?¿EõÜe…Û¯`O:L¤-q…ûzéê›yŠª ±ejµ¾VÌX.«>‘ž]Bý«éÎ9¤T®ñÚpS¥{Î o’½ž¼‹m×E¥Qt›yáë´"æSs×,ÆÕwQóZÚ¤0ܶˆˆr¯¯§1MÌY ‹jÿfŒ#¢Ûˆ®?M-·üñÞäó\8foˆ´”´é*/I¼{Ѫ„|ám*íS•d‚„Ü:Ì£+ùçSm*˜P��ĵ. ˜¶†v;EÑGvÒŠ©oPM'� ¸P‹égHg‰£½OÛ†W%A ™oK1ãwÚ´}m^>�5.GA ›jch÷CíÓô™¼ÑЭˆU´dæª.AL}§/¦%K–ÑŸ'îåMÒbÓϘ¹4±ôCs‚¼}�¯A?xeUzÑÀvžäÓl(M_þ7ý»g'mX8�:•·!Ù5›I—ó÷m"m|7ˆd‚@’r�hðŒu´ûX4�:¶‡ÖÍD Ý%AN•†l¥ûùå®aä-Éë¾MC[úQHŸ©ôÛß»èß¿§¯^«JvH°oIŸÏL•<ÒÀé+ië¿»hóÒO©kP^Zœ:-¢Ûù#¾æô+åbp�+2ߦ�AD¤¾F¿„»“ÙUéNSm¤Ý‘‡(âß¿hÞmÈW&$þôÖÆû:cp‘¿òKª3ôerû$"‚lrÙh(þÀ Zºx½QYJ€ŒBÞù‘/YBK—ï£c �§ 9¶2I!¥Š*°�SÒ¾Ñ�$•Ú‘½­„Ül$Ý0„š®L%9$ä=x;e™QÎʃÉC’7E†9‘cÅ6ÔwÄh=~]R“øviêüªˆ +=.¿O£éé”ir}äÒa –ëÓ¾^o½ßÁ‹|›£ï—ÿMÿîÙEO¦W*<[šÎÐ[,Þ÷DÖ/)¢èózv$@ ÇšoÒ´?öщSQñ÷¯4¶C ¹5hE � o´t}ò•€§ôú”_hݶݴwÏÚ°äêERA û_QtÁk¯RÕ7‹© ±ej­¾VDù= ÞTnO«9�O‹a4ý÷M´s×?´fö(jå##94ùŽÎç¿X5p�-¶]N£È6ó2Ô©!bæSs×,F×wQóÚ~ŠÓ¼É9NŸÖÍsì*u¥I‹7ÓÞÿÒúùQ»@;òêòu󕤕hì!cBJøµÙ Á©;-¿/bìxRÅÕ—Éí@ìü¯Ðþ…ˆh¢×ÂbÛ¿ØqDl±Òõ§©åöRoŽ;B?Í›EG�ÑûïK—/ÒOófÑ͛מpæý<‡.]ºh™˜¼!"m ý3¬É ù÷ÿ‹’HFä'TS.�ij+-¹¡;‚çFNuä 6!ôñþGΫ¥û[Q�$8w¡%ù®îG'Pu™@‚C3švN·YjS÷Ò˜ªR‚`KMg\y•¼É£¹5ŸÚÚ€`ÓŠæÜÐbĦŸ1siSg{�¤•>¦üãù“�W$T.ü'ºTà[§Ì}c¨’4¯=ÏÎמ³~H•¥ A^‹ÆE¦jËw�¢ªR� «ISN>;á³óI©üÛŸö{""ÊÚK£ƒ¤A ALcöêö‘ô­óŽu|�Ö¦=ûsú•¡r1´À›oÓÇ "Õ‰I�.ué‹Ó¯ôÒéß÷‚H �ì:üJùãßE~³j ¿DºóG_ò— dãJ}ÇÏ¡uû.Pb–qc‘ز!õUšÑTN€-…/ÔÝÑah<ÍÞ5Œ|% y£iº }Õ)ú¬–ŒdµÞ¥AÍlò¾,pÁ³¸³= ‚+õù35ï‘å¬üw8ùH@×räÓpNÕͱèviòüšE¿íN²í¼„î=>@L}X²\ó�-îúÆ–=£(H ‚MK�±ÅÒ}O\ýjéÁº7ÈM .é×kRÄÐÌV�wpèoÑš×I€œw©ð·ÜÙQôi];rðjJS£twz”ƾi¨.Äökõµ¢ÊïI�œÃfÑÅ‚íðØ$ª#¼=óÙq†‚7"Ûµá4Šk3/C�"f>5Íbb}1¯éo[ZJ^ý¹ Á¹Í�ÕTq+èu_) ‚žÝ~)éßá>$HÞt]5fÛ�¡O*¦¾Ä¶1óqÄ´±kaÑí_T»ßF¬uýij¹å�×¼t ‰:y}ð ¢N×ûïš5BP½Z ìúw'@.·A³¦Í°qÓz §D…#ßvBófÍЬȿ6·#C÷PÁ]XŒ‘ÁR$þ5“¶¥@›}ÓÆüŒ+¼6g†TÊr.ޝZ�K*À±ÓLiëVàžG^Ý&`D}9(óÖn¹óøg�sq|ퟸ¦œ:�ÁÈ:º7 ®mñÁWcĨÑè诀ÊÂ%d~ú3_zäWðhÛ�ôü8I*cÐÔQ(x+´c³¶µÍ-ܼõäw;”8¼n=â4ìÂÞÇØ–.…Ú²{û1¤�¤ŽÅ¦�g¡.x>iM ú¤|òèŠõåˆ k<è#NMZ Ž Ü;¸•ø$-æõ«âÊE—Ø|‹ƒ¤µ>Æ–èãˆØ½ cê¼ß­:5‡ƒ@P]½ˆÿŒüIÃù•À¿ï2ìZ2�<¤P%�ÄŸ?ŽEÿuàïî‰*M»aÐÄYX{ð*­œÜ) IDAT¬L³ÊFûæ�æ"@}1‡“ééÿkoGà`¬Íûà­f@â!D\ÍW8™Gq JØ·Ä+m]˜QÎ�ïñÖfí¦LF ×ü9~žã½ ÊùC ‚öÞ]ÜÓbëÃ’åúI*bà—# �-ÍÛ¢‰�hnç[ ß¾ÄÕo"ÿÙ‡4àÜi(T*ð@ÛZña7¸ >N›�‡�T �ÛØ~.ƒ}(¾9�‰¬ûÇñU¨îSLÊRßÛg¬Ó׊+¿Ç$>è3i$B ¶Ã&ïap9 MÁÞ�'�^Ši×zÓ(ªÍ¼uªŸ˜ùÔk‹ŒcEÉFäöÈ ®]GcPUÝñAô¾û¨ä ÇëÿÌ{IiÐB€,0Òâ�0¨˜ú²ÆzEó®ùL[ ›ŸoÓÚ•Ø6býõˆ©å”à‹Ëbá’¥fNƒúõÐ44Ôè÷7 m†¹óg£Ih3½ÿ޹xç/œÃè‘naßþ}èÙóu³ÓªK‹G×£qâzqï³…W²è4Á-ß-ý:ÎÂê�Ç¡Z� ø)Fƒ€þóñË[�ЉÊiâqüÄh CHëðÐ7ÎKƒÑ¢¹/¤§pæøäŽ);M<¢¢¡� Õ7,¼Ø‚Õßþ‹Þ69ó¦›~+'‹½ 8¾ç2àˆáÍõ¶)Á¾Z4ÐópC™+Üœ ;Ù9�'Í œŒN�RTmÑ >úÂçÒÊhêIô]Ä�9‡‡ªóBÁ¡.Ö,8tÛÂÕÕ@.ÊÕ©‡  ÁÅ-¯ÿ’9Š'i1§__.:Äæ[+n }Q½ž/ªçÿOÒB­RA­V#Gj{ÈÊÉFŽQë¹âòëˆ:ƒ— ª÷Dì_¿mÙ‰=‘§Ÿö7¢vàFÔ¬øaìË·Á ÏgâÛaMàñ¤ ,Ð&LâÜ�šÛã¯]'q<Ã_s@x¹gTèÖMšÁyî&DJ„¶NÞ|’{ê§6­º ƒgÞÉÍ.gy#´k媻z®ã½™<¯/‘F A|}X°\Ÿ¦Î®š7Ôó´B¹;Ü� 'ߨbˆíKTýjn"æR&27¨ '=§snÔµäáHþõ¨ÄMšV‚,â*NLë�ÑŽÓñIß0Ts6ÖI¥ú® ÊVßÛg¬Ò׌*?@°iŒ°fzžà, Dƒ>�¹�ûW® …ÚÂψqÉôvm �bÚÌKQ§ˆYÓ[bÍb‰q¬È|ÝÄÅËÙ ÈP³q}=cŽÁݺ!äË(œ5öÊšÔP©óÒ$µµµÌŲ�ú²üzE$3¯ùLZ Ãü|›Ô®Ä¶‘ç°1µÜ€ Þt{¥K‰œ·y³hÞ¬…Þ_¸p[ÿÙ‚�>ø666¸��µëÖⵯ£NíºN‰-:Ì9…åo÷» ìËŒôåqný5–�߇¶ß­ÄgsÈ* Á‚¹½á[è­D$ÜÕ \š×õVê!+““¡!ûNh�m"ó~†ÎË× %¶MKlú_º}eÌâTg°ç`2ȶ-ÂÃô/’8ëI¥�>nƒO‡]M"î$iÈáèý-Y _HqÚ{‰¸¯¼ó½Qpr�¾Û  N.Î…Ó)‘<þ?z–sú•å¢Cl¾Íƒ²®aײ_ñûßûswd!W«;ýyFæWâŒð¡S>t* ÉÄí ÇqôðaDìß…mÿF!ávŒl‹È˜¿1·SÞBÀmÂ$‚'Úwnù®£8qª×ZAŽlÝw y=„µtƒ“m4¶ùQŽ ct_¸B�Ë#‘¨‘¡~玺c«å,8øÁß½@i>×ñ^‹G)A¤.np‘P‹­ —+ÁÑ®zwµé[ 1·}™Z¿ÚÜKyÜg}<õÖ½ÄÇ?ï"PçËD9B§ü†¯N¼Ž©'±hT8è†J�Ú }‡ŽèÒ½'^iZ…~û½ öM±}ÆÒ} 0nŽó¨€ÀB?ë“w6//HpÚ‡)x¨üŒ—Ln×Ó(¢Í¼ ujˆ˜ùÔkKŒcEѦàþ-9¼ý¼õæKZ©*ËœÍ5ò389J!€ JKC6¶b¿0yú‘EÔ—%×+b™yÍgÒZø sÚ¿)íJl»¡X¬›<ÿ&ˆJ¼ÑåÓéèWõÙçˆ)7þ©ðÇÎ�?‹¿ÿÞŒqŸŒ‡��-nߎÃÊU«Ð«WoÔ©céÀM{wº5/Ä!á­øý\Óp©ÕõËéù4Ê…27ïáÕ¤VB¡0МPÙ�{Øäm{¤\(•y{~är¹é4“Øô3f&ÍÕ}د�¬^´õ5ÐîLê¹Pæædk«g›÷cr›¼(<©”È-4Û EžR06=fô+£ÊE‡È|‹ƒ(eÆwê…9g2û4lû*:Võƒ»£är9$ñÛ1gU4²�ü<Óó @ê„òõÃÑ·~8ú¾?ó’O`áè·ñ.-‹ÙÏaZ#,Ó&L!Aù";„‹‡ᚦjjOcÿ¡THª´AëòBK´®)Ãþ£qRÙáò»ˆ¯KIŽ • A,ÔWcpU 4+ööð¢ª/K¯WD3÷šÏÄÌη)íJl»ÑÞÇÉ�+±âf�û½¤Uà1lšNðFLçàà €Ë—/aý†¿0yâØØØâÖ­›ømùïèóF_Ô«[¿¤“g¥À£â:|P>  ;&bäïm±eh%ÝE àg'€ͧÁî‘~ƵÁŽ-²2³ …›e"¿Z ´¦\|ˆM?cfÑâÎ�½¸¤–¢b»ö6çžç'žö)BvV6úvÕr²²ón•tp*üM³¥ˆîW"ÊEl¾E�AJž6sÏdAZé-¬Ø³ªènbÍÝ}‹V»²L;�y5Åû¿ÿ‚sG»aéÝXìßšFÁ�–@›�Vïˆð ¯qîb$ޤLFµûq‡à9¨-jË :Ú´ô…°è^T£C¥Ã8xZI`8:×É÷ì‹–ócÏq¼×ÞÚ‚MQ*@pDËvMa ˜ÕG-S®&:?"ëW°ƒ½]Þù9  ïæ ¬ dj ,d^hÔÿ3,îÿ(' ïÅž][ñÇš-8uf%>|%6Ñÿ`x% Ê^ßÛg¬Ô׌,?Rä@a º9J€ààh¥¹Êˆ4šÒf^ø:-‚˜ù´4­Y ¦ñɘ(r€¾›VrÒ�¦2åÂCŽÚÍCá*‰Åø]Ø3Í1FS<’£œ±7Δ@;0ÄZ×|z=ç|‹m#¢¯Ÿk`Я¢EfÁÏsBµêæÏõ|c €í;·£ß›ý —Ë‹—,Á½ú Aý%�4ÃèvO�_®j4ø7Û4õm`ç„X[à{HYET ’A€ñ7â�ÿ–RZ•+Hhw-úž“Eªäè4vÂãh(©UPë+5)÷‘bÊ�ĦŸ1sÐ#Ü�\ÁíÂëY&Ò- zܧԈ»g -«3°©Pþ–é#¶_‰)±ù3©c°k÷-h G³¿E¿*'iƒ¸8¤»Ž+2¿JÜ»°–Ì‚}‰Å?¨Î¾"ªH232ó¶Â–D›�×G§>”Qˆ8ž‰»‘pYíˆíš<^ÒØ aXs8iby(Ù'àh–Ï]úäK+K—óÏk¼§‡Øõ¿Ù8”C�xöÀ žy‹2sêÃåjibó#¶~%>ðóλ'*1á®Þ>«¹‹‚_Hê#Øû¢nÇ·1nÖ_ˆº¸ï×”ƒîÅ¢uWó>·¬õM±ej­¾fäXNnávÁ‹yuœ Èüák�¹ÊÄù¦Ø6ó¢×iQÄ̧¥iÍbˆÄûÙ˜s[ÿ˜£ºx—LüU§ö}ÐÕS¨/aÉÌ͸_l]ÒNA‹ UÑfô\1f—OI´CD]ó‰ô¼ó-¶�ˆ]�¨Û¥7Þxã Ý¿Þ]PWïƒsLÃÁÙÙÙxøè®\¹„_.À›oöEÆ�J:YE ¤ü3#—\Uˆùß¿‚€&S°p\]ؤî̤̾âbþACðF«°È ÁÍ]Û£wÓânÔNŠ}ô¬qJ|Ñ¢U0dÐàÖ¾=¸T¨Õªqæ›P¸ØÊàÜmî=îdvNŽ� €6ù’ õ-’ìÅ…"{@¾çr˜“~ÆÌ‘}{Žä.­ÞÌB�¿– Uëª�ûÔ^\Ñ×X'°÷P:H°A£ÖÍô>ðÓ"Äö+1å"6ßbÆ JGZº€Þ¾zîmV]ŠßAIȈ•A‘ùUâðô>è;b>÷3¢sŠþ(J‰ÂñX5 Ø¢rp…¼’VoÆS€šu ƒ+¥#êÈìßw ¹ò†hÛòÙ¯95C#ÎDFâèÁÃH!´íÒO[jér~âyŒ÷”�Ó?½…!¿ÇA#8£Õ”/Ðãɳ̪ ”«¥‰Í�Øú•¡nmWH Áµc'ÿ‚W~ÄîÙƒkÓ‘“ˆ ›±r۽ߴ mÐ;Ühq?ñ~^0¦¬õM±ej­¾fäXN¹Q8p$³ð š«8õZHQ­AëÌUE¥QL›yÑë´(bæÓÒ´f1DZuj¹B5.=Ž”BÅ•‰ˆ5›oê/5¹vÅ„ÂNÐ"é¯1øýíì ÕÍuxoðÄf%âZª-<Œ¹ÍÊêí@ßüo€Èk>QžwûÛFJéõ'oôïׇE`ͺµøî@4ndü¯W•º· �^�8âíy3ÐÍC`�&Ÿ.ÄØ:6È8ô†þpЧGHòî{hç"@}q>>žu§áœK 1üÕîhS3?9R†ºï A3ê˜_0yÑå|Ÿ ¨n®Åw¿]�hÖ=^�×¾òàš¨*´){°)"MgàPÝ\‹O¾?­LÏýî29dÍ=ÜMÊ߃ĦŸ1ñr£ö "•`×4­�-õ©2Ô8 ͨÎÿŠÏWÞ(ðs‹98?*VÆk )×ÃûYq�ׯĕ‹Ø|‹ƒ$� ”PáÌ¡ãºyRÝÆ¶±oãç‡�ð�”�‚䬢Eç×ÝÆŽBm[ ÷üx£Ï÷Ø{Kÿø“·SûOÀ¶T‚Ôÿ íVîñö[ë´ Ããi§Ö�ÑÒAƒø# ðçá,H«‡¡µÿ³O–ø¶D«jRdý ¿Fހơº„å+ —ó3VïU©ˆ�XŽO{4Dëq»p�lP±ßB¬ü°F¾oôÍ«³ËÕâDæGtýÚ£uÏ.ð�”óñcdªÎ@û;¦Ì;­Tw  MZ�÷»ôÆ ïᇓ…/8rbpàh´‚Á5*CŠ2Ø7Å–©•úš±c¹@ÉØ0m6¢uNL¸ÿÏ,ü£‚ Ák¯…x˜­yŠJ£˜6ó¢×iÑĬéKÓšÅ{´~-oÌÉÙ;Ó<Ì×T¸ý÷'øð¯48ËMÝñ`ƒºã–â›Ön�h“°ó£öèðþ2O*°¥Fó1ë§à•Vƒðg¼6Õ†cÉÜÞO¯‰Šd¥vPÜü¯Ÿ¸k>Qž{ûÛFJéõ§ç�™ä9ty�EÆX°x‰Qïc(·Ó` Ùºz“���~Twb$åihm?’@J�ïl¢ûZÝ�Ï<2‘jÛ$Ø7 ÏOdå{%—þ[Ú“ü¥Ap¤ÊáÃè³™séç¹ßÓ”¡©ª“@l)xøVJÒùÌ:;»yJ@‚Ä•jtJã¿ø’&½×ƒê”“’ y´›EçùQ_¢™ÍHHâV‡^ÿà úîûiôé¨W©¶»5þôGV^J�Õ¢ÏO«ò•ÍAz¿‚” ¹ÔêAï}ô½÷íŽÇy›~ÆÄPQô§!$ƒœšÿK=ïPîA¾�Äg8ý«Ô÷†}4Ê_B�xÒ��ùß�Cçg·' H�yQã“h毋iáÜoèƒWk’‹$È+Л«o’ZßùüGѾBçSÐ?ƒÊ‘)U4o¬Ðyy=õ±AV‡¾<›¯Ï™Ü¯Š/Åæä,€¤Áè˜NBÄåÛô1HC× '$H½©éÀ/hÖ¼Ù4mÒ` ¯êL6åûѺ³¿S'� 8Qƒ¡³é·?�Ò]�¾´Ÿ_"]Yö&U± r7ªÜ¤3õyw8�5’†½Û‡º4­Ln2��¤ž­é«ˆ¤;L‰,õUšÑTN€-…/LÔýÌ"ÇS"ÒÄÓ¼0[$’ ½�t›•’öŽ ‰ !©D Û¶óé–Nˆ/çbûŽØñ>ßüêàYž‚‚‚žþUô!W[ y?Ü@‚Muøt;Ý*ÔY̨‹”«ø±Å²}O|ý’ê"Ís% @‚Ceê0t}ûÝ·4yD7 q“Sù~S¿òR‚´}|èqBµ©´lÙ Á¾µìÿ}5cÍ�;‹¦MN]kº’DȶÆ´û¡–J{ßÔ_bËÔ}͈±|c?r@²oл-ÝÈ¥z7úàÛy´hñÏ4íýÎTÅA rª4l¥ä+4ņ7É^O;4½]“F“ÛÌ‹^§Æ±¦7wÍbꩈyÍPÛ"Õešß¡\Þ˜cëG¡½†ÑG�¦·Ã«‘³Ì�zü2›ú¹ iúäˆÞAß í£c4³[²Ï2WªÔ0Œ:¿Ú“^íÔ‚B¼íòæABåB?¤Íq*�ã‹.3ÆYsæƒLoâêÙŠíßP»ÝF¬sýij>òÇk8xó¼=]\„? ù�ÜCJÒPüï=É[’¼Eîék%th|-²²­5ž"ÓuNNq;¾¥¾ ½ŸBx<à8–oIƒæ¤D•ž�¤LºôÇz¥šÉž'�ıuøh]È(œ嵿èÖþùÎ#�ı2uýf?ÝSDÑäê2‚´*�×}ÕtcÍÛTÍAxzŒ}‡_éöÓ[lú3‘ú?šÙLN�…Ðg§ô7*ñÁ"¢LºüÇêZ=ŸA°#¿&oÓŒ= …0Ö Þ™Ô¯Œ(Ã�âòýä8“Æ umŸÔží„§ç$ŽT1|"ý}SIDétôÛ6ä-Ï»h“WG‡sõ¤ÝˆüæÑÒ£ Ñ7ï¶£ê6OÏò'%§ò�éõOÒ¡»†Ž"ʦ¨Å[±ã©š.þ¯É‚àJ}×§JQêo�‹äÔäû+…"ËÙ¸‹ã}ó« ‘“½«Ukò útí¹žIE¯³Ä¶UóËÕòÁ‘ùY¿DDÚäCôCŸÚä.Ëw¬�7…û�.¤ž¤OCd‰½·'ÿE["œ5�ZVp"iþ4B ©sE 6—%=.­RÞ7 Ö…Ø2µt_3¢üÒ×¼FvÙ´œE±I‘4£wMr•æ;¿]µùðºšS ï– ÞSǦ´™½N�fúšÞ¬5ËóÞ‘öÑiZö~Gªæ.' AbO~�Þ ¯¶\£Åzûñ…ù¸£¦oò><•.¬ÿ–¶ &w¹ 3†{òkØ“Æ.•ª£Š�C ÝÏjD¿²X¹ˆÍ·ic�&#W.ßBªÖ^•k ØÛ^ç—Ô÷‘¬°‡§§3ô_ÊEj Ä%=B¦B ‰�¼ËWBE_'#zmÙ6Qüxj>³Ë¹H%=Þ—¦>j ¦çÇœúÍ}pW®'!ά^A®Æô‚\¤%ÜÀ�;�©–±\ªT-×üÏ�(ã}Sl™Z¬¯‰Ë•®ãò‰È–»£Bõt¶âÓiMJ£mF¯¨NMfêš>ï˜R?’Ùiéȵu…›ýãö™¾=}ÞÁVu|}_×ÿÚìû¸yýî§)!Ø»Á¯r0‚ÜÍâ¼5Ú�yó¿˜öaºiÿ¢ÛHÉ­G¼†þ€'ñÞ0ÆcŒ1Æ+s(ûþ»t×S\Ú¹A¡ç±(~ˆêáóq˾ÖÜÞˆþn%“NVrÊzɼ)UÁRÆcŒ1ÆcÌê˜9èÙ¼º÷è�©{Rt^�uó¾^…Û Ü:öB×’J%+I/R¿oŒ1ÆcŒ1Æ+!òб˜ñÎzôY~ zÔ鯣]ˆ'¤©7ptÛ&¼‘ Á«3¦MÞüˆ…—Ò‹ÔF8xÃcŒ1Æc¬ì|Ðsq$vÔ˜‚/ço‰ ¿à€ÁÎ z‚ϧOÁëÁÅ>‰½¨^ 6ÂÁÆcŒ1Æce“,áW"|â2¤ß½…;³¡µu‡…¸ó/š0à…i#¼aŒ1ÆcŒ1VÆÉáâ_.þ%�Vz•í6Â,fŒ1ÆcŒ1Æ+Å8xÃcŒ1ÆcŒ1VŠ™¼iP¯ž5ÒÁcŒ1ÆcŒ1Æô09xsæÜ9k¤ƒ1ÆcŒ1ÆcŒéÁ·M1ÆcŒ1ÆcŒ•b¼aŒ1ÆcŒ1Æ+Å8xÃcŒ1ÆcŒ1VŠqð†1ÆcŒ1Æc¬ãà cŒ1ÆcŒ1ÆX)&+é0#)âîƒl�ÌÞ>®�—tzcŒ1ÆcŒ1ö\pðÆX”ޏó±HQ‘þ×RG¸zú£‚Ÿ‹Å V¹ëÔèµÙU'àðÅ™hÆÑÆcŒ1Æcì¥ÀÁc©ã›¯â÷Ú¢ß'H`ïS|€Ï?„P¾3�1ÆcŒ1ÆcâqðÆdRø…vC‹ ·¾Ô9�pçÊYœ»y[gîMÿbé¾5x§23cŒ1ÆcŒ1ÆÄ)3Q…U«WàÌÙ3&S»v 4ÔÂ)‘¡Ñ˜åX?ЂÞ׸µû{ ~ç[ì�[�Þÿ CyÞ€ÃcŒ1ÆcŒ1ÊLðfåÊU˜8e<4j5J%”  %  ” %Êgÿ—““ƒuk×Y!xS;TèôV…êÃw"}ÿØž4#ýóB=š×pîf*È!!!~°/x¸ö!®Ÿ½�Gäÿ�øzƒašŒxœ>| 1ñÉÈÐØÃ«b4oŠŠÎ9bŒ1ÆcŒ1ÆÊª2¼©R¥*Þé?Фcºwïn¥ÔG€w³–íÄiMâ4€¿ !ýŸ±h1èhë�SÑ_¢Ž´À¡;ðIËw°U]_FŸÆ×õŒ¨"m2"…‘Ó6ãJºÏ©,@âR½¿\‚Ÿ´„‡þ­BŒ1ÆcŒ1Æ+ÅÊLðfá‚…X¸`aI'ÃhÚ´T¤iHœàâlŨ ¥áàäŽèöã9(\ê¢ÿ´IÔ¾ÊiïãâžeøþÇ�X?¡+î¨"°or}ØY/%Œ1ÆcŒ1Ƴ‚ç¼Y·nÖ­[gÔ{ €~ýúúÿ•«W଩ϼ©UC?ïÛ¦ÐCì]¾ q@Ø-+Ü^c9ªÓ?âßÎ#G‚�6G`v;·§ÏâiÔ¢3^i0¡½–ãØwS°úííÈ·P1ÆcŒ1ÆceÉs¹’ïß¿?ú÷ï_ìû n`ÕÊUhÛ® Ú´m�fÍ›¢AÃú©UUªVF`ùxzyÂÙÅ r9´Z ²²²ŒYŒ& ‰vaþðްì&4w´Ÿø!ZÙZ넹8¾j5.©ÇN0¥­[�‡( ðê6#êËA™°vËóCçŒ1ÆcŒ1Æ+eDí¼Y¸d©ÞÿoP¿š††ê}íIðÆP@¥ÿþ7P¥rŒ:ʤtZç™7¹Ø>Ô r=zH«…–òž8#Ø ü³ÕX;ª*¬¶ïF�ã'î@BZ·ÐÿLi0Z4÷…ôTÎ?ƒÜ1åùÖ)ÆcŒ1Æc¬ ¼9|˜¨“ à³3gáÂEX¸p‘¨óZšƒgø:Ø´¤x€[wS¡•ú!|Ü4LÑí«8ø9q Ñ&"á®áÒ¼ž¨·R˜H™œ -Ùwð@ ð�SŒ1ÆcŒ1ÆX™ñÜXÜ¿ØØØ`ÅŠOÿmÌ-U+W-ÇÙsgM:WíZµ1d°¸@“a6h7ã¶t× ÌdÇ”fa˜s×ù¢Ae+n€r¡Ì%R+¡PˆÊ8 ²3 ÷°�ÚÚibŒ1ÆcŒ1ƘE•ȯMõîݹ¹¹`TàV­Z��ƒß� V©‘››ûìO™ ¥R©ó—£P`ݺ?¬¼1À¡>�;›:ÍGìïïãÓ^ÑXÐÅÝôŽV-ÿ6€àg'€ͧÁî‘~Ö1ÆcŒ1Æcì¹*±Ÿ 76hóDåJ•1~ìD“ޱÎ3o sn;smA�¥7±ìýÏÐ+útrËN ¤VA­'H£I¹�cŸ…f‹Š IDAT*,«ˆ*A2×Ôˆ¿5ü ·@>cŒ1ÆcŒ1Vz”™§Ÿ,Z´II÷Lú[ºtÙóM¤àŽW¦ÍB_êKðþçû�V @cçä™h“ï!YSð´H:°Œ½·IðF«°È ÁÍ]Û£Ò÷&-îFíÄ¡ØG|ËcŒ1ÆcŒ1V•™àMY!x¿ŽÓ{ÀKPãÚâ1øâ@:òÇoäÁ5QUhSö`SDšÎkª›kñÉ÷G •{ó“!ヌv.ÔçããY§‘Yà9—bø«ÝѦf(&V˜—9ÆcŒ1ÆcŒ=w%vÛÔ‹K‚À·fãÛµýo,Žþ½¢~B[—¼W¥!}0 ñ œ;‡%}[ãþ;¯!4À™ñDZõ�°õ5ÞZ5 KµÐqû”$h~ž½mßÛŠÈOÛ Þ¾þèß©ülspçü>¬ÿs/®eÙ xØLnÉ?ÎcŒ1ÆcŒ•5¼±i% ýé ¬m2‘ÿ-À詽pbv8€´&>Zµ ?Æ¢£°yþl†‰c%t™´¿Otœ�@J(”Æ<¹XŽà¡á¨ÿLLú|>þÞ·Óö>~I�À1°}; Ó߃?͘1ÆcŒ1Æ+sÏ!3 ‚�¼ô“bX¸d)FN¿àôBÓ #á*®Þzˆ\[OT®Y ¾æÞŦEVR,þ‹KF–Ön~U\±l9hÃcŒ1ÆcŒ•)^CÀ“x ï¼)1R8† q %?SGßêhà[Ý’ÊcŒ1ÆcŒ±Ä,fŒ1ÆcŒ1Æ+Å8xÃcŒ1ÆcŒ1VŠqð†1ÆcŒ1Æc¬ãà cŒ1ÆcŒ1ÆX)ÆÁÆcŒ1ÆcŒ±RŒƒ7Œ1ÆcŒ1Æc¥ocŒ1ÆcŒ1ÆJ1“ƒ7 êճȉOD�´Èç0ÆcŒ1ÆcŒ½ÈLÞœ9wÎ"'¶Ôç0ÆcŒ1ÆcŒ½Èø¶)ÆcŒ1ÆcŒ±RŒƒ7Œ1ÆcŒ1Æc¥ocŒ1ÆcŒ1ÆJ1Þ0ÆcŒ1ÆcŒ•b¼aŒ1ÆcŒ1Æ+Åd%�ÆcL‡â!î>ÈÉœáíã ¹µÎ£LEbJ&´'xú¹ÁÖZç£4§­$=¯¶a2Þ}€l²�›¯œ¤%�žçE�Œû÷�¦àèáw»’NcŒ1öââàÍóFéˆ;‹•·JõPÕÃð O•ü.ÜJ‡2xT©‹Jn¼QбçÊ„þ ”zg¯?€FpG•úUà^f»,!'é"NFÇàÚíd¤+4�Ú¹Àÿj6 E½òNVݶ©Ü> Uûü…ܪpøâL4³Òznä$4ì²÷½†cç­Åèdc�ó@q—£OâÜ·p?=R{Wx–F½Ðƨá¥?,óÜÒVÆ(w}€½Ö"[dÛÈM¾„cGNájÂ#(eÎðª…&-£’‹9-:gèŠö“ÁéÍÕ8²ºœò½JY 8uèÎ^»�,Á ¾Á�Ö¦>|‹ t˜tÜÓ±Štþ[¤�Ù:ÀÍ;ÞN&-úŒ++þý-o†¢ÍLØ>uíM8 cŒ1ÆŒÆÁ ¶œÇæÈX¼Þ&£zÖµîÉT‡ñM‡Wñû9º/OÄÖ�îô½íæZ ê0ëâ´ðëþ3öüUߺébŒfd}"÷àçëµ¶½°.e#ú9>·”êЦ'àZ¢^•+Àݤ‹[Bú…Õ˜:þ,Ý{Z*ôAâ€ÀVƒðÍüï1°®s‘å!š …L*…F*�PàâóöüiR¢ðÛ·_à‡åûp-]ƒ‚¥)È\>“¾ýƒ—ãû˜­)ó"VM‰IK� Q™¿&Hœª ÛøŸñëg�hòªˆðh÷8¼ùY²jŒÅß‹û¡üÓob~ÿƒ&¬Àéê|õ/ÀƯ5>X°Ó{VÔ³{HÄqOÇ*­þd Ø–«‚Æíº£ï�QÜ%N†:¯Ie%EÅ·—beÔ¼òËô_Çîw« Œ1ÆØËí¥ÞL_o7Gl™Þ+v]Æô5Q˜òV“M“æö&Œì2ëâ´ðyå'ìús$Bx+2cÌ(j\˜Õ�¿wÅW"ðq%ãCYQÿC—NSq,�àX¹†ô‚àá �*-ÿ�ÚƒõkþÁùÈ_1´Ýe<ŠØ…±µ-¿%Ķ×Z¤«ÖêyE|Þž/BÆé¹Ðs¶'ä‚{øÕo‹Nm꣒� d9÷{ú ví;‡ÿvý„a¶`ׯ;°rH ðPoêÿ°°O;ŒÙ• 8×@÷÷¢kÃ@8*q~Ï*,Ûƒm_÷Äõôq|VœMøhz¸ãG,Æ5ÔĸÅß ÍÓƒµˆ_ù: ÿI䆺oŽÀ»�jÃ÷pvÛ2,Þ‰Ùov�bÛQÌïT._TìqOHáÚ -*< íÔ9i¸ë*b®\Ñ spdã/˜Ùa–­ø�ü ,Å”•à†ß-¨Ý1ÑLèzKºéKcŒ1ÆÌâ9d&y�EžCg‘1,^bÔûž×ç˜ã»Õ'è÷]—(K¡¢ƒ)K©¦y›ÎÒw«OXï¤Êí4ØCB€-u_þ�´^Ö$þC£kÛ“ HÉ»Ó:“i½¤0ÆŠQL-H±y9 Øõ¢u%ÕwµI´¤³ 6­hÎ �ñÇinÒüv$@BåÂgÓù,ýoSÝÙJ#ªÛ��\º,¦[&œÂlbóf€r÷ò•€$>Ãé_¥Ò÷˜&~õö—’�dþ�é›ã(GÏû²oþCŸ·ó!©lkѸˆt«§­¬{ÒǤÁèX®1Gh)å�7ÉC\ZÓôÓ;f�þ_sr@‚CGZ˜`J»Ê¦#j’\��ßÛ›(%ß¡}´…Þõ“$nÔ~ÖÊÖIRžÜ€ì�äµ>¥(¥ùÇ3VåÞ?KÿׇBœ²­>œ¶$æÏ¯9e¥¥{ö%‰@ò�‰t,›cŒ1fùã5/íΛék¢àïåŒ7ê!ââ=¤g«°ÿ\"†v­…EÛ.”ÈJÙ‹‰ÝúaAŒ¾ÇŽ�£~1·]h2âqúð1ÄÄ'#Cc¯ŠuмM(*:çûFš2q;æ*î)8W¨�êÞ¾)Ï÷>— :¨æUÊïI`¬ R¥\ÆÑÃѸrûrx”¯�ЖÍPÃÓðR$!æDbnÞCºR�TkÐ �ª¸åÛ>IH‹;‡kIG±ëT.ˆ2qûB4¢Haç[µ‹þ&<ûFå€$èññHÔqÐÿ6™w̘1 g¿‹E…ŠZÜWåíáÆ™xHö �_Ág^äÜÅ¥Kw‘ xW«ƒ ÎR¢NAìù8¤ÁAuªÁ3ëÎ\²õE�Z�pLË[nò%‰<‰ØÄt¨ì½Ü8 aõ| ?ôWòާLÄ߇ˆsñHÕ8À»jc„µ­?SžLÉØ0q6ßÕ@ð쌟önÁ˜šú?À¾b7|»m Ц¦�¾„%3þÂØVC óH±iÓ"óÖi=ƒIiÈ•:Á+¨š¶n‚ÊzžïB©ye犨[Í2ÊDüñýˆ8‡T�¼*7DX»†ð·³Ìqù5�‰–ƒÃÛöà¡Vß7?ÃG Nª¨?z:|w[§qâ¼ï·›Œ’þÂ÷K®@-«‹÷Æ¿ �§���²u)6'i!«6ß½_:]BpAËÉ_¢÷²ÞX}y~‹ü¡ávfg¹W=ôúìOtìò#^ï2û®.ð1mpvýÛð—˜[V¼_Ÿ€a57b򴁿~Ã'ØüŽï¾aŒ1Æ,éeÜyóÝê´lÇ%ÊR¨i{ôÚpäm<O«\§�Gâ(3GE3ÿˆ¶ÎߎiFÒgÍ\I y„}G'ÒŠùŽ_sŸ"fô¦š.ÂÓ?�$.5©Ï�‡Ÿ} ¨}Hëûy’rïó=0ðÑšk³¨¥�@�Õ¢ÏO©,•cÆÊ.Kî¼É‰¥õŸ´¥@;!_Íûì(lìzŠU8F›J'~‹ê¹Ë ôs{ªÐa"m‰{²ý@Aÿ *Wø}�RÕñG©ØM i«¨‡o²Cß>‘"¨ÎÑWueÁ�lÊ(ôrú†~ä&䥹óâÄBå˜{l;or3ÐݸXº™\°ƒ=)ì�4ÔSBÜià6ï)œxŠý±ÙÙ…Í£8� ;Yô÷Ûî$@J>Œ0Ð÷Ri]o' £j�“ʬãÈıJCwV¾Fžd!ôiô“3™[Vº>»%Ù Ù¶œMןç®<Æcì•?^SZ`5Ó×DÁÓÝ}Ûc×é;x�¡DïåÑ«E4®ê�ä46�ÇÈW낀髣¬ž&J�Âô×^Ãôãpmõ¶m™Œ&.E|_Ei88¹#^™¼W…Úè?m v;…è#;±bjoT×^Áú ]ÑcÆY(@pGס} Õ"uç lN*üR@ƒë›Ö㤠°iô.Þ®÷ÒnÊbÌò( ›Þ Gÿ9¸ëЃg¬ÃîcÑ8ulÖÍ„ö‰ˆøi:�Þ†ä§Ý“�¼q^ýp Ϋªâµ)¿`Ý¶ÝØ»g6,ù;áÎþÐïõi8• rÔ<‹g@uY0úN_Œ%KcZŸ*(ö—‹j£~° Ц`óŒY8‘ªoœ0@V;T€”Òq4ò,T:/æâäþÃÈ�ØÁÞF‰¨ƒG‘¥óº7F ^#�Gû.Õ»éÁˆ¼Q2þŽ>?D’{ Œ˜ñ;6mß�Í˧cP#'Ü;4};�ý{÷^E•¸qü�[Ò¤„PC‡ôB HQ”Ū ŠòÃÆ*ØÅuU\;bYw+¬(+ ÒAºÒz ½$@é·ýþHÀHB€�ý~žÇÉÜ3sÎáÞ;3oÎ9£9ÇKX„Ùë€Æõ¿KÿÎî¡W¾øA³çü¤Iÿ~F7Õ·+o×öi³«,áÖÁŸghE¾G†ÿ z°_ú]R@\õ¿)RÕKìXvè_w÷Öð)[”ߨ‡†�™¬Ÿ-ÖÂÙÿÕC:ªföfM|²·ý>õŒ” »—ì†äÉX§Ñýÿ¬Or{êÕ/~Ðì9³4ù“¿ª{¨]ù»§é™Ážq¼Š–+÷y¬Â Ùý«©vƒ¦jX£äaJŽ�¿iEº[†w´â"Ë8âÔ�¢i߯”CvµîÝSõ‹^M¹v*yC¦<²)26¢”ÅÓT6¹´;i½Ž{. \¹YT管º§�UrnÕS’ä”tá}eQÃ^·ª•Ý£ü•ßkêîRORî;ô�š5+åÀ•µŸò˜²h»ÂB««[›Z�|X’TÅÏ®é+ö«F�—[+9å˜òný²v¿†ÜÖR“nÓäEÛt{§f•S ã5i�¨ÄVµ¶I9Û4ñÅ—4#?L7ýÍO±îÖ]ï}¢'âNMŽ¿¶«n¹á5=ð×:<ç+ý<0F·Ô´Èïú!~g’ÆíÎÒÊEõ@ß:g>ÙĽ_Ë6ÛŸx�⟠fe¹ã®vÅ?¯ça©ÖT ‰‰Ê¶7Wõ"°¼µßhÂöÚJhß^wø‰oùÇ4ŸV‰7ªÇõ8tŠöo™ I›»ë‘p›¤,­YyH�ÚtP÷GÆëÓûùÌv×íýïPâCkbÚ>­ÝáR|¸Uõ;õÓÀ>Z3m§ª*V·Ý÷ úÖ)cFo‹Ñ�QÕê—~QZÞ =Óo‡®ëÖU�Ô*ª¡ªûœk?vµîû�º-Ÿªé;´ßÝA O½ÜµKÛÒ(±ï uó›«ŸRS´Í!Å�^O5]›ù©u»ÔùÞNò“ä¨ÖLmå¨ZøDËyÛæØ0Qã7+þºë5xì?5 é©¨»zßÞEQ<¡Iû“4qÆ^ÝØ/TIF•ÆŠOLÔ1Ï!ŒúHËÞí«†§êÕ¥›nŽQ¿'&é€u‡Öv+ì¼}éÒ¾ÞŠo›(Kd_u®^ñI#­›kËl-Ìi¡6í›jàçŸkPó?n°;ÝÔCmêÞ«a?ÖÞù‹•vk6ɨZðÞ=æÙª-ê·¢ÇSWuoYM÷<9E‡Š¯¢å*r“þøŒåž~o\·²vý¢�F-–BGÝqÛ›z aÙ>/ž¬­:䯶×Ö×=ÝB‹�O³e¯� Dß uˆ¨RÊÔ!‹ê·ê¬ÄD¹kx”î–‚+ZΪrWÉ»�npƒVÌÊ”-k¿NzâÏ󄨲õ•¥QwÝÓû{yöÙth[¶Ô( „}€Š(õ Ÿ™™©”Ý{ävŸù›“¤äõjÒ¸ñ¸²öSŒŸ¯7wÔ˜IóuàhŽì6‹¬C† ÝÞ>Tÿúo’Re*×áRzfžV¯õ×Mñõ5bì\5«šW9•p¬WRòz%�°*påTýýýµ4Mnã]ß§™<)”tîhíèwôãšCònß[qö%'{IP¬罫Ÿ“¶è�öTè!²È­ú¡Nmšž¤�o�R×°ûÕ¸Èu—{×W=y­¶øtÒ­ÁG´>9µrÚ \ÉN^=Út˜&ØÏs·èÈVFŽC{ %%¯Wˆ¯$9ôû»höº£²'ܬc×ÙŸYï5Èÿ‡fnÚ¤ã~¯ÄGÂeuÖ’¥kµ.YrmÚ¢¤ä̳%�øô‡ºÖb‘œ›”T¸O÷áÂ:˪¤äõ ?ZŽ–!·h`Ï�ùÑ %''kÕ‚ï4J’aT�fÑŠ�‹WÛk;¨]l¨‹¼YwlКMã5~@+õ. .ܾ՗3“µ¯{ÕvVÒ‚ÿè«]dmRX¯ìúbâj%9Ú©§}—’’ 9’ Úà8^ð§Ûv¾¶9´æÝÑš¹öˆ|:õQ“ì­§û£€—Z´‰Rãõnù\¥ÕÉò’Nç¨êéîÇš+cóú3¿=v9¶nPR^ªfÍMRDÜùnŠ3µ`Á2­MvÈ»FšnX¯ô²÷þ*Z7ON¤ú{RÇ2¼š³¥X?H†Ÿ¡­ë“•{xš¦l®x[ñãÕUßGJ:ž—œ%¯bå*zûãx¹ÅÞeæÚ®)¯�ÑÒã¹Ê8’¢í)G•ÐH�úÑ .JY¿¾L»q&¯ïW&ë€w°rOn:³Ÿó—ë×åÉJʯ¥ðm”ä_r%ó¶oWròz9Ó–é·¤Då¸+XΦ3¯-’×+©~àyÖ›qépêa­OÞ)#w�$5V“â_ê«låeoUrR¾ŽMž®»jGñXSW‹Å¢† B@(�˧Ôsêž½{Ï n*Û÷?N½à}4oÞL‘ááezíõ-ëiÒÂmêÓ±©f�ܯì<§¬†E2¤ÿÌÛ¡Ì<‡2²ÊÊÉWpum]_“lÓuqõ/¸žgsiýØ¿jYz†ü«UUÞ±ãZôî�oøž„_í³÷!mØ�*·¬jÔ2ZUJº:³ÔWtTuY6Ñ– [å¼#D^²¨^מjõùF-ß>K³·ô+üí¾$¹•2ÿmwZT¥Cu¼†%�3yäÈÎЉŠuïצÍérË¢zÑQªVR–b©£ˆðkdÙ”¦ƒ[¶)ꊈ¬-ëš=Úøå‹zÛ÷QÝÝ%N¡ER‹¥²g¾úªIÏáú¬s?­š7[¿,úM¿¯Ý¢C™'µãRí߸T3¿þHÞ!-ÕãþÇõ·D¨Ê©*øÅ©m´·~Y¶Ik6äªw'_Ie¬]©­Noµ‰‹V¤O¤üþ»@kÖ¦ÉݤfÁÍøæUJÊ’l±‰J(ñ ­ ܇´qóQ¹eUhx‹FdXÚmˆžëVrqÃ;LÑÍK˜.c P Ÿ!åå)7¯ óS›êÇå{•‘�¯Ü|§†Þ¥—¿^-·Û£à*>ð§æš¼p› ÃSyS¦ÎàVÆ �"ÿüº^ÔX«_zX¯/NÒØá¯«î¿ÿ®.!¥Ü”¹�êHjÁ¿É®ÿ>«þ?•|•ü¸<ò(/õˆN¸¥`‹d©qƒzµÿ·VÌÝ«Ÿg&éÁðVî�š7§œ–`u¾¹­Îó€+à�]í†OÑÝ‚Îùªü%#Õ{Äeý¡+M©GÝ’¬ªQ³ÆY£g XU­F5Y”&ϱ4÷HU ›Âï¡7<§O×lÒo Ñ�£T',Nñ­Û(±}Gµ‹ ‘ÏEÈZ-þõ•Ðë!%ôzHrçèðŽõJ^·NkV.Ó’åuäðMyëQ­Ýù¦>Ú¶àæÛ¨¢ø¶a²-KRòê­rvŠ•M¹J^¹^ù¶fŠ‹ �¯WœÂmsµqu’²o”²z­ÒÜV5Olsz O¹¹�êHZA_S½j¹ŸpcøøË¯Ä¯R‹,…;+ÓÒ"†�|}­2ä�3+S¹é|ƒµ.JÝröiÙ´Éš¾h•6îØ§´Œ\9ŠÝ�—ÖÕ†O€J¼28w_”«ÜœÇ.˜-B÷½÷™zæå++ý v¬Y ©?~£Qs'é»n/è½þ¤:ç q<ÊÊ8)—G²鬇bYí²Y ÉéP¾£ÄH’œùùry$Ùíç⊖«·N¦gÈ#Éê ¿’Þ§ê+‹ƒe‘GΓ'•í‘|ù}€«€ÅbQhý‹ñ } ìJ oqÖÏwìÜ©˜è¨ >peí§¼Þ‰ŽÒ¸Ùµý¸¡ê®ñó¶ëpzŽ&¯ËSdD„j^ã{:¸i©ûºEVnЉŽÒžE>ü•>ÐX^’º~7E�� Ó7Ûiú„eúÓ‡ƒí_Â�#GaáQŠ©é‘oµÚªVêUQ3EK²µˆSdt”j^\6>D RPZÚå5½O­}%×Ößt4 \qÝûixÿx•u½FàªwúójU˸xÅÇŸ{*‚#+Z1Ñ•m�RLt”b|%92¥˜Z6ÅÇÇ)6º¤á¶n]Ó*N1Ñ^ò4n¡ð¨(µ°JR”Þ›ß]ƒçý fÎÓ’5;t,ï¸RVÍVÊê¹ú©ÙMz蹡º=â�z¹knVLt”œ*¬CY×¼9—Øý©OÁÿºÒ7èû·_Òó÷˹ímðº_‡ÜÁEù? [ŽÕ.�KÕ"£ÔнVó\ Û­Ÿúw‰Q¸á¯ûzý¬ÏŽçË¥ëamq*ªewÝ÷`7µ,Ü�#-J1чå¨WІ¨SÓ¦Jk›#§ �ƒmjײ”>>›#'J1ÑÛuüšÂýÿîsä*&:JÛ�l�>ß—£S–›:kRê^)ÈOU"þ¨{yU´nžôßõáoéÛ­9’w=u¼«§ZÔ«¡@_/Ùl6Y.Õ7³6)/èÌýþq¼èr¯Bå.à<æ8¥˜èÊ-öÞ(—˜6Eþò”^z~’ž{ø=-Û?C³RîѨ[CJ · ¸u`C ÅDçJ±ñj¥ÚE 8êØ>Z‡�ø©q£ÈRÞ7n¥nm¨èè£ò„wPûØ(5tW°œEg|Wôóy¦M¹k‹_EE‡(¨ûͺ16ªä ¨Ü}åVõøVŠ�¶IaÍU¬o@…5¾å‘QpÁ¼çƒÁ—¹:ò±Nå5ü>ÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄoLŒðÀÄl—»®,Kw¹ôÝê|«ý.EkF?¯Ï-Ô“�¯¶0á2´ßsT+–o“K­Ë· €©Þ¸ä,×ÄêÁ·‡éëþ¢…ykµ|mžÔØ·„Wº•¹gµ–._¯�‡N(ß à‘jÛ±��;ìÈOݨ_­Ð¶ƒrøÖT³Ö×éºØZò.g]�iÛ”´û„ÜòW½ÈpÕò)çJp¾ö»Žn׺]éòøÕUDDm�Õ3îcÚ±v§Ž{üT'"Bu|=:‘²NÛ-Õ¬Uùòx2µ7y¥VµÊ§V Õsn׎·…)²žÿá’#m“–.Y©Í{�*ÇðSõúaJhŸ¨°^gµÃ“¾Skv“*¦y Ù<™Ú½lž®KQºËOÁ�[éºÎ­T§ú ø_FxರT¯©VCrXdµž=gÈ“¶Xoþ?½öÃe¸‹.þkȦ;GŽÓ'�·>{º‘c·¦Žx@�½¿@ûòŠ”3¼T»ã}üÕ뺵aÙ|qœªG:ߥ϶ZùèdÍý ¼ü -Eéí÷(cúP]{ÿt¹[¾¬U+ÿ¦èâOg?9SÃÚ÷×Tg´þ¶rµ^ŽuiÉË7ª×—ÇTÐâµÕ»­Fɪ¦OÏÓ;i·é¶·-ÖÆ·ÛÛêQ“ûÆiæûÝR‰3»ÎÙþr³+æ�÷õIÄOzçù Ú¢fêûê3êRê ˜æj™[Ú¶&²J’ç�¦ Çï‘»j+=ðòÓº»S3U×qm]ôµÞ~cœ޾G7�ðÖòO{)¸°ë »—ì†äÉX§Ñýÿ¡I¹½õê=W×G™»èÓ‘£4k÷4=3øCuùõÙ l#ð¿‹ðÀ¥å<®-s>ÕðÇÇh—;H ÏŽTÿúg¦"ÎUcõÁ‚ãrÛbôÌw“õJÜáF§›º©E~´n³G“?ž¤7o}Du ‹ç-{[O±Cß¶9{®ž�95_§»zßš ÿÖ]õÏmŸêűCtó-T|@Ëi9Éú o½¾2Gõn«Ÿ>¹CõK}qå·¿ü,ªß©Ÿ6J××#&h‹B”Ø÷A=tzQâsm“r½®g¾Þ-—-RÃ~˜§·;�ÄZ%Þ¨®q¾jÓý_Ú1î9½÷H7ý£uáÈ%‹EIΤqúúÆQúuþ ?=2§«º6:¡ÈnÿÒî5SõÓž§/°�Àÿ.ÂI¾~¥ú/áâÎ×ÉcGu2ߪêQ7ëéq/ë…{cå_¬¤5òIý¸ò6>櫱ÅG¥ªÃMíä÷ÉneoÙ ­.†7ùZ6a¢¶;¥€ž�éáè3Z1ª\¯!/=)ÇonÕ¬“+‡TrxãLÑ„�½ôôœc î6Z3Çݯ¦Sñö_ZyZòÍwJqòéü¸†¶*¶À²¡ª7üEã>Õó+·iÊäµz¥uÂ'�¥¡üíá"ÁMÿv׫�Ï¿µ;w¯víq]ü¦W)Â�37S™®¢Q€[N·$�SǶÿ¦™ã>Ví:/ê±ê©h>bø×R‹ØZjQtg·œ‡œN§r¬>ò5¤¬œlåœZ_ŵ[¿¯<(—ljÞº•ªœ5+ʪýÞј~稰'U³Ÿê¥‡&îUP§‘š6ñqE]ÀR-mÿ%åÚ©+Óä–UM¯M,yj˜µ±Ú$˲ò€RÖ¬Ó1O‚ji–á¯v­JX Ú^UU )'[Ù9ž³·(“«íÙ¼LÃK]?NÑñôt¥Ÿþ/CYy9:¶ë7M|ñ:¹–ŽÕS]Ûê®O·ÉQ¼xÖvÍú`˜úÞÐR�jÊÛf“ÝÛG¾þªqë—:â.öz÷Aí;è–dQp­àò¹yNê÷×úèÏÿ\¯\ŸúÛçÏ)!°¢m—.¸ý—Šë örI²ªv½:¥L%³ªV�Y%¹<«ï ÿ*ªRâÐVY ÿ!ˆn€Šcä €KËðÒ5 ÛêŽáߪmÈ-Š4CÓž®ïz§{ WÂõ¤ÍÑÓ7õÑ{k2%ߺju}/ý©imUõ÷‘Ýn—e÷ ½7~¥²‹îד¯¼<�$Cv»]ç^Žølî”ÏôÔ«N9=’rÕ;#&éÎÿÜ¥:•q—¡ý—V¾òò%É�··W©ýf÷*äqä)¿xcåîoeÇÈ—‰Eõné£D»ä>>_s~?5ö$OK^{Xï¯É’µÑ½úOòv­œ9AŸ|ð®Þ|ý5�|åïqoœüЧ†Ÿüý Ineef©øÀœóñ¸ÜªÚñyMŸû¶®¯âѾ‰�jà˜­qDLií/·KîÊÊrºß<ÊÎÊ.e„ŒG9…Û ¿€³ûÀEExÀr••]¸ ­s½fý¼G.Ù•ø—Wõç&>Å^ëÑÑ”eO¬¡jj•äRÊö•´<®Ç‘£GÉñ„µþ Møi¤zÜ8T_޾E!:ªŸŸé¯×Wå\`ÛÊ¢HûeÈ(Éâq: FãJ;¢´ò¦S¥±6(ì7§Rv¤ÈYâ‹Ú½kŸ\2äÚPu*ëÉ[Ê„ðÀeâQꜙúÝ!ÉÚXaÍ MñdèDFÁÚ55kÕ<ûKʱQ_}¾XyIž"Ɇ¥–®íÐL6¹´ç—9ÚxV áÔšWämS`�Ït¸x(⨻$YÕà¾1úd@#Y³Wèµ~Ïé—ãcÅ–RÚ/É'À_6Cr§VêY)”[‡æÏUrÉ)Ëé}—^ãbÛ,uÕ¡cÓÂ~›«Í%í7w¹æ.Î�ÇðR|ÇDœ¯i*á €KÎ�µOËÇÕ­C¾×Q·¡ÀƒÔ?ºp .K=5¨g•äКÅË”Y´ c¯¦ í§�ŽÕSu‹äÉNSjÖ©(¦˜þ•ègȹþŸúë˜MÊ-Zt×ýãóÍrÊO‰=»èœËË5Õkô—z2Ê[Ž-ë�Ç'é@e�t9_û%Ù›…«©Mr§ÍÑ”…'Î[»&hØ¿Êm;»†Í.›!ÉuX¹Ê¸Í¦–R¢Ÿ!GÒÇ1ng±©b9Júðï·Û%Kµ›5¨oNÀ%Æ‚Å.’|Í{:V�^*z«ï‘+/SÇÒŽ+Ûé‘ ‹ªÄ=ª/Æ=¦f§¦âX›èöþ×iäò¹Js�ºd Ö]ñU•»?Yó'OÒ¢¼újZW}Óa ¦f-ÐûÏŒ–û¦Du»£�j7T�œ©.Oÿ¢Ùi§¸éw¨gB]Y�¬ÕÌïfhý1�ªw~Yï<auÒ«ã^Ô¯�Fè·oу[jÚÃÍÊñ¥YÁöK²FÜ©{Z¿©u¿¥hlߎ:ÒÿV%ÔõQæîešúí|ù<ò²îÿœ>=è–»H¨dTSXˆUs÷ìÔ'ƒîÐÉ. ¤Ýõê Ý|®mÍÑÇ#§«óÓó4mp¢®ýe îêÐDAŽCÚ0÷}5c“NÚBuçû£tw-¼.5‰GÙi{µ;­È� CV»Ÿ‚j6WtËkÕõÎ5øžöªãU´œE�©oöܧÁïÏ×ò¯^Õò¯$Ãâ¯7<¦ÿŽ}U½æ©Ás_hÙ+‹µæ³§4xÁ0Í¿­�j[|;ôG-ªó²žúÛXÍ™ý™Þ™%I†,þ uïhôÈ{å]¶ø´|VãÞ^¢v�þ¤ÙÏô×mækD+ß‹Ü~IÖp=1þKíð¤Æ,MÖ÷&ë{²ø7R·ç¦ê‹gôÞdCòä)7¯È¸¯öúÝúyÐ×ÚºaªÆl0ä{c¸F<žm†�¢‡NÕ’:/ë©—ÆêçoÞÔÊ §êì£Ú ýôÂkohh—º¥ --help` to see the arguments to any of the commands. ## Solaar settings Solaar supports at least the following settings: Setting | Description ---------------------------------|------------ Hand Detection | Turn on backlight when your hands hover over the keyboard Scroll Wheel Smooth Scrolling | Higher-speed vertical scrolling Side Scrolling | When off, side scrolling sends custom button events Scroll Wheel High Resolution | Higher-speed vertical scrolling Scroll Wheel HID++ Scrolling | When on, vertical scrolling uses HID++ events Scroll Wheel Direction | Reverse direction of vertical scrolling Scroll Wheel Resolution | Higher-speed vertical scrolling (use with caution) Scroll Wheel Rachet | Shift wheel ratchet on and off based on wheel speed Thumb Wheel HID++ Scrolling | When on, thumb-wheel scrolling uses HID++ events Thumb Wheel Direction | Reverse direction of thumb-wheel scrolling Sensitivity (DPI) | Mouse movement sensitivity Sensitivity (Pointer Speed) | Mouse movement sensitivity Backlight | Turn on backlight Swap Fx function | Change Fn keys to normally do their special action DPI Sliding Adjustment | Change Sensitivity (DPI) by holding a button and moving the mouse Mouse Gestures | Create HID++ events by holding a button and moving the mouse Key/Button Actions | Change what a key or button does Key/Button Diversion | Divert keys and buttons to create HID++ events Divert crown events | Divert crown actions to create HID++ events Divert G Keys | Divert G keys to create HID++ events Disable keys | Disable one or more keys Set OS | Change keys to match OS Change Host | Connect to a different host Gestures | Turn on and off various (mostly touchpad) gestures Gesture params | Modify parameters for gestures HID++ events are mostly not processed by Linux input drivers. Settings that involve sending HID++ events exist so that these events can be processed by Solaar rules instead of by Linux. Different Logitech devices may implement the same functionality in different ways, thus the different settings that do the same thing. Solaar-1.1.20/docs/usb.ids.txt000066400000000000000000000276231522022367600160730ustar00rootroot00000000000000# # List of USB ID's # # Maintained by Stephen J. Gowdy # If you have any new entries, please submit them via # http://www.linux-usb.org/usb-ids.html # or send entries as patches (diff -u old new) in the # body of your email (a bot will attempt to deal with it). # The latest version can be obtained from # http://www.linux-usb.org/usb.ids # # Version: 2019.11.05 # Date: 2019-11-05 20:34:06 # # Vendors, devices and interfaces. Please keep sorted. # Syntax: # vendor vendor_name # device device_name <-- single tab # interface interface_name <-- two tabs 046d Logitech, Inc. 0082 Acer Aspire 5672 Webcam 0200 WingMan Extreme Joystick 0203 M2452 Keyboard 0242 Chillstream for Xbox 360 0301 M4848 Mouse 0401 HP PageScan 0402 NEC PageScan 040f Logitech/Storm PageScan 0430 Mic (Cordless) 0801 QuickCam Home 0802 Webcam C200 0804 Webcam C250 0805 Webcam C300 0807 Webcam B500 0808 Webcam C600 0809 Webcam Pro 9000 080a Portable Webcam C905 080f Webcam C120 0810 QuickCam Pro 0819 Webcam C210 081a Webcam C260 081b Webcam C310 081d HD Webcam C510 0820 QuickCam VC 0821 HD Webcam C910 0823 HD Webcam B910 0825 Webcam C270 0826 HD Webcam C525 0828 HD Webcam B990 082b Webcam C170 082c HD Webcam C615 082d HD Pro Webcam C920 0830 QuickClip 0836 B525 HD Webcam 0837 BCC950 ConferenceCam 0840 QuickCam Express 0843 Webcam C930e 0850 QuickCam Web 085c C922 Pro Stream Webcam 0870 QuickCam Express 0890 QuickCam Traveler 0892 OrbiCam 0894 CrystalCam 0895 QuickCam for Dell Notebooks 0896 OrbiCam 0897 QuickCam for Dell Notebooks 0899 QuickCam for Dell Notebooks 089d QuickCam E2500 series 08a0 QuickCam IM 08a1 QuickCam IM with sound 08a2 Labtec Webcam Pro 08a3 QuickCam QuickCam Chat 08a6 QuickCam IM 08a7 QuickCam Image 08a9 Notebook Deluxe 08aa Labtec Notebooks 08ac QuickCam Cool 08ad QuickCam Communicate STX 08ae QuickCam for Notebooks 08af QuickCam Easy/Cool 08b0 QuickCam 3000 Pro [pwc] 08b1 QuickCam Notebook Pro 08b2 QuickCam Pro 4000 08b3 QuickCam Zoom 08b4 QuickCam Zoom 08b5 QuickCam Sphere 08b9 QuickCam IM 08bd Microphone (Pro 4000) 08c0 QuickCam Pro 3000 08c1 QuickCam Fusion 08c2 QuickCam PTZ 08c3 Camera (Notebooks Pro) 08c5 QuickCam Pro 5000 08c6 QuickCam for DELL Notebooks 08c7 QuickCam OEM Cisco VT Camera II 08c9 QuickCam Ultra Vision 08ca Mic (Fusion) 08cb Mic (Notebooks Pro) 08cc Mic (PTZ) 08ce QuickCam Pro 5000 08cf QuickCam UpdateMe 08d0 QuickCam Express 08d7 QuickCam Communicate STX 08d8 QuickCam for Notebook Deluxe 08d9 QuickCam IM/Connect 08da QuickCam Messenger 08dd QuickCam for Notebooks 08e0 QuickCam Express 08e1 Labtec Webcam 08f0 QuickCam Messenger 08f1 QuickCam Express 08f2 Microphone (Messenger) 08f3 QuickCam Express 08f4 Labtec Webcam 08f5 QuickCam Messenger Communicate 08f6 QuickCam Messenger Plus 0900 ClickSmart 310 0901 ClickSmart 510 0903 ClickSmart 820 0905 ClickSmart 820 0910 QuickCam Cordless 0920 QuickCam Express 0921 Labtec Webcam 0922 QuickCam Live 0928 QuickCam Express 0929 Labtec Webcam Pro 092a QuickCam for Notebooks 092b Labtec Webcam Plus 092c QuickCam Chat 092d QuickCam Express / Go 092e QuickCam Chat 092f QuickCam Express Plus 0950 Pocket Camera 0960 ClickSmart 420 0970 Pocket750 0990 QuickCam Pro 9000 0991 QuickCam Pro for Notebooks 0992 QuickCam Communicate Deluxe 0994 QuickCam Orbit/Sphere AF 09a1 QuickCam Communicate MP/S5500 09a2 QuickCam Communicate Deluxe/S7500 09a4 QuickCam E 3500 09a5 Quickcam 3000 For Business 09a6 QuickCam Vision Pro 09b0 Acer OrbiCam 09b2 Fujitsu Webcam 09c0 QuickCam for Dell Notebooks Mic 09c1 QuickCam Deluxe for Notebooks 0a01 USB Headset 0a02 Premium Stereo USB Headset 350 0a03 Logitech USB Microphone 0a04 V20 portable speakers (USB powered) 0a07 Z-10 Speakers 0a0b ClearChat Pro USB 0a0c Clear Chat Comfort USB Headset 0a13 Z-5 Speakers 0a14 USB Headset 0a15 G35 Headset 0a17 G330 Headset 0a1f G930 0a29 H600 [Wireless Headset] 0a37 USB Headset H540 0a38 Headset H340 0a44 Headset H390 0a45 960 Headset 0a4d G430 Surround Sound Gaming Headset 0a5b G933 Wireless Headset Dongle 0a66 [G533 Wireless Headset Dongle] 0b02 C-UV35 [Bluetooth Mini-Receiver] (HID proxy mode) 8801 Video Camera b014 Bluetooth Mouse M336/M337/M535 b305 BT Mini-Receiver bfe4 Premium Optical Wheel Mouse c000 N43 [Pilot Mouse] c001 N48/M-BB48/M-UK96A [FirstMouse Plus] c002 M-BA47 [MouseMan Plus] c003 MouseMan c004 WingMan Gaming Mouse c005 WingMan Gaming Wheel Mouse c00b MouseMan Wheel c00c Optical Wheel Mouse c00d MouseMan Wheel+ c00e M-BJ58/M-BJ69 Optical Wheel Mouse c00f MouseMan Traveler/Mobile c011 Optical MouseMan c012 Mouseman Dual Optical c014 Corded Workstation Mouse c015 Corded Workstation Mouse c016 Optical Wheel Mouse c018 Optical Wheel Mouse c019 Optical Tilt Wheel Mouse c01a M-BQ85 Optical Wheel Mouse c01b MX310 Optical Mouse c01c Optical Mouse c01d MX510 Optical Mouse c01e MX518 Optical Mouse c024 MX300 Optical Mouse c025 MX500 Optical Mouse c030 iFeel Mouse c031 iFeel Mouse+ c032 MouseMan iFeel c033 iFeel MouseMan+ c034 MouseMan Optical c035 Mouse c036 Mouse c037 Mouse c038 Mouse c03d M-BT96a Pilot Optical Mouse c03e Premium Optical Wheel Mouse (M-BT58) c03f M-BT85 [UltraX Optical Mouse] c040 Corded Tilt-Wheel Mouse c041 G5 Laser Mouse c042 G3 Laser Mouse c043 MX320/MX400 Laser Mouse c044 LX3 Optical Mouse c045 Optical Mouse c046 RX1000 Laser Mouse c047 Laser Mouse M-UAL120 c048 G9 Laser Mouse c049 G5 Laser Mouse c050 RX 250 Optical Mouse c051 G3 (MX518) Optical Mouse c053 Laser Mouse c054 Bluetooth mini-receiver c058 M115 Mouse c05a M90/M100 Optical Mouse c05b M-U0004 810-001317 [B110 Optical USB Mouse] c05d Optical Mouse c05f M115 Optical Mouse c061 RX1500 Laser Mouse c062 M-UAS144 [LS1 Laser Mouse] c063 DELL Laser Mouse c064 M110 corded optical mouse (M-B0001) c066 G9x Laser Mouse c068 G500 Laser Mouse c069 M-U0007 [Corded Mouse M500] c06a USB Optical Mouse c06b G700 Wireless Gaming Mouse c06c Optical Mouse c077 M105 Optical Mouse c07c M-R0017 [G700s Rechargeable Gaming Mouse] c07d G502 Mouse c07e G402 Gaming Mouse c080 G303 Gaming Mouse c083 G403 Prodigy Gaming Mouse c084 G203 Gaming Mouse c101 UltraX Media Remote c110 Harmony 785/880/885 Remote c111 Harmony 525 Remote c112 Harmony 890 Remote c11f Harmony 900/1100 Remote c121 Harmony One Remote c122 Harmony 650/700 Remote c124 Harmony 300/350 Remote c125 Harmony 200 Remote c126 Harmony Link c129 Harmony Hub c12b Harmony Touch/Ultimate Remote c201 WingMan Extreme Joystick with Throttle c202 WingMan Formula c207 WingMan Extreme Digital 3D c208 WingMan Gamepad Extreme c209 WingMan Gamepad c20a WingMan RumblePad c20b WingMan Action Pad c20c WingMan Precision c20d WingMan Attack 2 c20e WingMan Formula GP c211 iTouch Cordless Receiver c212 WingMan Extreme Digital 3D c213 J-UH16 (Freedom 2.4 Cordless Joystick) c214 ATK3 (Attack III Joystick) c215 Extreme 3D Pro c216 F310 Gamepad [DirectInput Mode] c218 F510 Gamepad [DirectInput Mode] c219 F710 Gamepad [DirectInput Mode] c21a Precision Gamepad c21c G13 Advanced Gameboard c21d F310 Gamepad [XInput Mode] c21e F510 Gamepad [XInput Mode] c21f F710 Wireless Gamepad [XInput Mode] c221 G11/G15 Keyboard / Keyboard c222 G15 Keyboard / LCD c223 G11/G15 Keyboard / USB Hub c225 G11/G15 Keyboard / G keys c226 G15 Refresh Keyboard c227 G15 Refresh Keyboard c228 G19 Gaming Keyboard c229 G19 Gaming Keyboard Macro Interface c22a Gaming Keyboard G110 c22b Gaming Keyboard G110 G-keys c22d G510 Gaming Keyboard c22e G510 Gaming Keyboard onboard audio c231 G13 Virtual Mouse c245 G400 Optical Mouse c246 Gaming Mouse G300 c248 G105 Gaming Keyboard c24a G600 Gaming Mouse c24c G400s Optical Mouse c24d G710 Gaming Keyboard c24e G500s Laser Gaming Mouse c281 WingMan Force c283 WingMan Force 3D c285 WingMan Strike Force 3D c286 Force 3D Pro c287 Flight System G940 c291 WingMan Formula Force c293 WingMan Formula Force GP c294 Driving Force c295 Momo Force Steering Wheel c298 Driving Force Pro c299 G25 Racing Wheel c29b G27 Racing Wheel c29c Speed Force Wireless Wheel for Wii c2a0 Wingman Force Feedback Mouse c2a1 WingMan Force Feedback Mouse c2ab G13 Joystick c301 iTouch Keyboard c302 iTouch Pro Keyboard c303 iTouch Keyboard c305 Internet Keyboard c307 Internet Keyboard c308 Internet Navigator Keyboard c309 Y-BF37 [Internet Navigator Keyboard] c30a iTouch Composite c30b NetPlay Keyboard c30c Internet Keys (X) c30d Internet Keys c30e UltraX Keyboard (Y-BL49) c30f Logicool HID-Compliant Keyboard (106 key) c311 Y-UF49 [Internet Pro Keyboard] c312 DeLuxe 250 Keyboard c313 Internet 350 Keyboard c315 Classic Keyboard 200 c316 HID-Compliant Keyboard c317 Wave Corded Keyboard c318 Illuminated Keyboard c31a Comfort Wave 450 c31b Compact Keyboard K300 c31c Keyboard K120 c31d Media Keyboard K200 c31f Comfort Keyboard K290 c326 Washable Keyboard K310 c328 Corded Keyboard K280e c332 G502 Proteus Spectrum Optical Mouse c335 G910 Orion Spectrum Mechanical Keyboard c33a G413 Gaming Keyboard c401 TrackMan Marble Wheel c402 Marble Mouse (2-button) c403 Turbo TrackMan Marble FX c404 TrackMan Wheel c408 Marble Mouse (4-button) c501 Cordless Mouse Receiver c502 Cordless Mouse & iTouch Keys c503 Cordless Mouse+Keyboard Receiver c504 Cordless Mouse+Keyboard Receiver c505 Cordless Mouse+Keyboard Receiver c506 MX700 Cordless Mouse Receiver c508 Cordless Trackball c509 Cordless Keyboard & Mouse c50a Cordless Mouse c50b Cordless Desktop Optical c50c Cordless Desktop S510 c50d Cordless Mouse c50e Cordless Mouse Receiver c510 Cordless Mouse c512 LX-700 Cordless Desktop Receiver c513 MX3000 Cordless Desktop Receiver c514 Cordless Mouse c515 Cordless 2.4 GHz Presenter Presentation remote control c517 LX710 Cordless Desktop Laser c518 MX610 Laser Cordless Mouse c51a MX Revolution/G7 Cordless Mouse c51b V220 Cordless Optical Mouse for Notebooks c521 Cordless Mouse Receiver c525 MX Revolution Cordless Mouse c526 Nano Receiver c529 Logitech Keyboard + Mice c52b Unifying Receiver c52d R700 Remote Presenter receiver c52e MK260 Wireless Combo Receiver c52f Unifying Receiver c531 C-U0007 [Unifying Receiver] c532 Unifying Receiver c534 Unifying Receiver c603 3Dconnexion Spacemouse Plus XT c605 3Dconnexion CADman c606 3Dconnexion Spacemouse Classic c621 3Dconnexion Spaceball 5000 c623 3Dconnexion Space Traveller 3D Mouse c625 3Dconnexion Space Pilot 3D Mouse c626 3Dconnexion Space Navigator 3D Mouse c627 3Dconnexion Space Explorer 3D Mouse c628 3Dconnexion Space Navigator for Notebooks c629 3Dconnexion SpacePilot Pro 3D Mouse c62b 3Dconnexion Space Mouse Pro c640 NuLOOQ navigator c702 Cordless Presenter c703 Elite Keyboard Y-RP20 + Mouse MX900 (Bluetooth) c704 diNovo Wireless Desktop c705 MX900 Bluetooth Wireless Hub (C-UJ16A) c707 Bluetooth wireless hub c708 Bluetooth wireless hub c709 BT Mini-Receiver (HCI mode) c70a MX5000 Cordless Desktop c70b BT Mini-Receiver (HID proxy mode) c70c BT Mini-Receiver (HID proxy mode) c70d Bluetooth wireless hub c70e MX1000 Bluetooth Laser Mouse c70f Bluetooth wireless hub c712 Bluetooth wireless hub c714 diNovo Edge Keyboard c715 Bluetooth wireless hub c71a Bluetooth wireless hub c71d Bluetooth wireless hub c71f diNovo Mini Wireless Keyboard c720 Bluetooth wireless hub ca03 MOMO Racing ca04 Formula Vibration Feedback Wheel ca84 Cordless Controller for Xbox ca88 Thunderpad for Xbox ca8a Precision Vibration Feedback Wheel for Xbox caa3 DriveFX Racing Wheel cab1 Cordless Keyboard for Wii HID Receiver d001 QuickCam Pro f301 Controller Solaar-1.1.20/lib/000077500000000000000000000000001522022367600135675ustar00rootroot00000000000000Solaar-1.1.20/lib/hid_parser/000077500000000000000000000000001522022367600157075ustar00rootroot00000000000000Solaar-1.1.20/lib/hid_parser/__init__.py000066400000000000000000001031401522022367600200170ustar00rootroot00000000000000# SPDX-License-Identifier: MIT from __future__ import annotations # noqa:F407 import functools import struct import sys import textwrap import typing import warnings from typing import Any from typing import Dict from typing import Iterable from typing import Iterator from typing import List from typing import Literal from typing import Optional from typing import Sequence from typing import TextIO from typing import Tuple from typing import Union import hid_parser.data __version__ = "0.0.3" class HIDWarning(Warning): pass class HIDComplianceWarning(HIDWarning): pass class HIDReportWarning(HIDWarning): pass class HIDUnsupportedWarning(HIDWarning): pass class Type: MAIN = 0 GLOBAL = 1 LOCAL = 2 class TagMain: INPUT = 0b1000 OUTPUT = 0b1001 FEATURE = 0b1011 COLLECTION = 0b1010 END_COLLECTION = 0b1100 class TagGlobal: USAGE_PAGE = 0b0000 LOGICAL_MINIMUM = 0b0001 LOGICAL_MAXIMUM = 0b0010 PHYSICAL_MINIMUM = 0b0011 PHYSICAL_MAXIMUM = 0b0100 UNIT_EXPONENT = 0b0101 UNIT = 0b0110 REPORT_SIZE = 0b0111 REPORT_ID = 0b1000 REPORT_COUNT = 0b1001 PUSH = 0b1010 POP = 0b1011 class TagLocal: USAGE = 0b0000 USAGE_MINIMUM = 0b0001 USAGE_MAXIMUM = 0b0010 DESIGNATOR_INDEX = 0b0011 DESIGNATOR_MINIMUM = 0b0100 DESIGNATOR_MAXIMUM = 0b0101 STRING_INDEX = 0b0111 STRING_MINIMUM = 0b1000 STRING_MAXIMUM = 0b1001 DELIMITER = 0b1010 def _data_bit_shift(data: Sequence[int], offset: int, length: int) -> Sequence[int]: if not length > 0: raise ValueError(f"Invalid specified length: {length}") left_extra = offset % 8 right_extra = 8 - (offset + length) % 8 start_offset = offset // 8 end_offset = (offset + length - 1) // 8 byte_length = (length - 1) // 8 + 1 if not end_offset < len(data): raise ValueError(f"Invalid data length: {len(data)} (expecting {end_offset + 1})") shifted = [0] * byte_length if right_extra == 8: right_extra = 0 i = end_offset shifted_offset = byte_length - 1 while shifted_offset >= 0: shifted[shifted_offset] = data[i] >> right_extra if i - start_offset >= 0: shifted[shifted_offset] |= (data[i - 1] & (0xFF >> (8 - right_extra))) << (8 - right_extra) shifted_offset -= 1 i -= 1 shifted[0] &= 0xFF >> ((left_extra + right_extra) % 8) if not len(shifted) == byte_length: raise ValueError("Invalid data") return shifted class BitNumber(int): def __init__(self, value: int): self._value = value def __int__(self) -> int: return self._value def __eq__(self, other: Any) -> bool: try: return self._value == int(other) except: # noqa: E722 return False @property def byte(self) -> int: """ Number of bytes """ return self._value // 8 @property def bit(self) -> int: """ Number of unaligned bits n.byte * 8 + n.bits = n """ if self.byte == 0: return self._value return self._value % (self.byte * 8) @staticmethod def _param_repr(value: int, unit: str) -> str: if value != 1: unit += "s" return f"{value}{unit}" def __repr__(self) -> str: byte_str = self._param_repr(self.byte, "byte") bit_str = self._param_repr(self.bit, "bit") if self.byte == 0 and self.bit == 0: return bit_str parts = [] if self.byte != 0: parts.append(byte_str) if self.bit != 0: parts.append(bit_str) return " ".join(parts) class Usage: def __init__( self, page: Optional[int] = None, usage: Optional[int] = None, *, extended_usage: Optional[int] = None ) -> None: if extended_usage and page and usage: raise ValueError("You need to specify either the usage page and usage or the extended usage") if extended_usage is not None: self.page = extended_usage >> (2 * 8) self.usage = extended_usage & 0xFFFF elif page is not None and usage is not None: self.page = page self.usage = usage else: raise ValueError("No usage specified") def __int__(self) -> int: return self.page << (2 * 8) | self.usage def __eq__(self, other: Any) -> bool: if not isinstance(other, self.__class__): return False return self.page == other.page and self.usage == other.usage def __hash__(self) -> int: return self.usage << (2 * 8) + self.page def __repr__(self) -> str: try: page_str = hid_parser.data.UsagePages.get_description(self.page) except KeyError: page_str = f"0x{self.page:04x}" usage_str = f"0x{self.usage:04x}" else: try: page = hid_parser.data.UsagePages.get_subdata(self.page) usage_str = page.get_description(self.usage) except (KeyError, ValueError): usage_str = f"0x{self.usage:04x}" return f"Usage(page={page_str}, usage={usage_str})" @property def usage_types(self) -> Tuple[hid_parser.data.UsageTypes]: subdata = hid_parser.data.UsagePages.get_subdata(self.page).get_subdata(self.usage) if isinstance(subdata, tuple): types = subdata else: types = (subdata,) for typ in types: if not isinstance(typ, hid_parser.data.UsageTypes): raise ValueError(f"Expecting usage type but got '{type(typ)}'") return typing.cast(Tuple[hid_parser.data.UsageTypes], types) class UsageValue: def __init__(self, item: MainItem, value: int): self._item = item self._value = value def __int__(self) -> int: return self.value def __repr__(self) -> str: return repr(self.value) @property def value(self) -> Union[int, bool]: return self._value @property def constant(self) -> bool: return self._item.constant @property def data(self) -> bool: return self._item.data @property def relative(self) -> bool: return self._item.relative @property def absolute(self) -> bool: return self._item.absolute class VendorUsageValue(UsageValue): def __init__( self, item: MainItem, *, value: Optional[int] = None, value_list: Optional[List[int]] = None, ): self._item = item if value: self._list = [value] elif value_list: self._list = value_list else: self._list = [] def __int__(self) -> int: return self.value def __iter__(self) -> Iterator[int]: return iter(self.list) @property def value(self) -> Union[int, bool]: return int.from_bytes(self._list, byteorder="little") @property def list(self) -> List[int]: return self._list class BaseItem: def __init__(self, offset: int, size: int): self._offset = BitNumber(offset) self._size = BitNumber(size) @property def offset(self) -> BitNumber: return self._offset @property def size(self) -> BitNumber: return self._size def __repr__(self) -> str: return f"{self.__class__.__name__}(offset={self.offset}, size={self.size})" class PaddingItem(BaseItem): pass class MainItem(BaseItem): def __init__( self, offset: int, size: int, flags: int, logical_min: int, logical_max: int, physical_min: Optional[int] = None, physical_max: Optional[int] = None, ): super().__init__(offset, size) self._flags = flags self._logical_min = logical_min self._logical_max = logical_max self._physical_min = physical_min self._physical_max = physical_max # TODO: unit @property def offset(self) -> BitNumber: return self._offset @property def size(self) -> BitNumber: return self._size @property def logical_min(self) -> int: return self._logical_min @property def logical_max(self) -> int: return self._logical_max @property def physical_min(self) -> Optional[int]: return self._physical_min @property def physical_max(self) -> Optional[int]: return self._physical_max # flags @property def constant(self) -> bool: return self._flags & (1 << 0) != 0 @property def data(self) -> bool: return self._flags & (1 << 0) == 0 @property def relative(self) -> bool: return self._flags & (1 << 2) != 0 @property def absolute(self) -> bool: return self._flags & (1 << 2) == 0 class VariableItem(MainItem): _INCOMPATIBLE_TYPES = ( # array types hid_parser.data.UsageTypes.SELECTOR, # collection types hid_parser.data.UsageTypes.NAMED_ARRAY, hid_parser.data.UsageTypes.COLLECTION_APPLICATION, hid_parser.data.UsageTypes.COLLECTION_LOGICAL, hid_parser.data.UsageTypes.COLLECTION_PHYSICAL, hid_parser.data.UsageTypes.USAGE_SWITCH, hid_parser.data.UsageTypes.USAGE_MODIFIER, ) def __init__( self, offset: int, size: int, flags: int, usage: Usage, logical_min: int, logical_max: int, physical_min: Optional[int] = None, physical_max: Optional[int] = None, ): super().__init__(offset, size, flags, logical_min, logical_max, physical_min, physical_max) self._usage = usage try: if all(usage_type in self._INCOMPATIBLE_TYPES for usage_type in usage.usage_types): warnings.warn(HIDComplianceWarning(f"{usage} has no compatible usage types with a variable item")) # noqa except (KeyError, ValueError): pass def __repr__(self) -> str: return f"VariableItem(offset={self.offset}, size={self.size}, usage={self.usage})" def parse(self, data: Sequence[int]) -> UsageValue: data = _data_bit_shift(data, self.offset, self.size) if hid_parser.data.UsageTypes.LINEAR_CONTROL in self.usage.usage_types or any( usage_type in hid_parser.data.UsageTypesData and usage_type != hid_parser.data.UsageTypes.SELECTOR for usage_type in self.usage.usage_types ): # int value = int.from_bytes(data, byteorder="little") elif ( hid_parser.data.UsageTypes.ON_OFF_CONTROL in self.usage.usage_types and not self.preferred_state and self.logical_min == -1 and self.logical_max == 1 ): # bool - -1 is false value = int.from_bytes(data, byteorder="little") == 1 else: # bool value = bool.from_bytes(data, byteorder="little") return UsageValue(self, value) @property def usage(self) -> Usage: return self._usage # flags (variable only, see HID spec 1.11 page 32) @property def wrap(self) -> bool: return self._flags & (1 << 3) != 0 @property def linear(self) -> bool: return self._flags & (1 << 4) != 0 @property def preferred_state(self) -> bool: return self._flags & (1 << 5) != 0 @property def null_state(self) -> bool: return self._flags & (1 << 6) != 0 @property def buffered_bytes(self) -> bool: return self._flags & (1 << 7) != 0 @property def bitfield(self) -> bool: return self._flags & (1 << 7) == 0 class ArrayItem(MainItem): _INCOMPATIBLE_TYPES = ( # variable types hid_parser.data.UsageTypes.LINEAR_CONTROL, hid_parser.data.UsageTypes.ON_OFF_CONTROL, hid_parser.data.UsageTypes.MOMENTARY_CONTROL, hid_parser.data.UsageTypes.ONE_SHOT_CONTROL, hid_parser.data.UsageTypes.RE_TRIGGER_CONTROL, hid_parser.data.UsageTypes.STATIC_VALUE, hid_parser.data.UsageTypes.STATIC_FLAG, hid_parser.data.UsageTypes.DYNAMIC_VALUE, hid_parser.data.UsageTypes.DYNAMIC_FLAG, # collection types hid_parser.data.UsageTypes.NAMED_ARRAY, hid_parser.data.UsageTypes.COLLECTION_APPLICATION, hid_parser.data.UsageTypes.COLLECTION_LOGICAL, hid_parser.data.UsageTypes.COLLECTION_PHYSICAL, hid_parser.data.UsageTypes.USAGE_SWITCH, hid_parser.data.UsageTypes.USAGE_MODIFIER, ) _IGNORE_USAGE_VALUES = ((hid_parser.data.UsagePages.KEYBOARD_KEYPAD_PAGE, hid_parser.data.KeyboardKeypad.NO_EVENT),) def __init__( self, offset: int, size: int, count: int, flags: int, usages: List[Usage], logical_min: int, logical_max: int, physical_min: Optional[int] = None, physical_max: Optional[int] = None, ): super().__init__(offset, size, flags, logical_min, logical_max, physical_min, physical_max) self._count = count self._usages = usages self._page = self._usages[0].page if usages else None for usage in self._usages: if usage.page != self._page: raise ValueError(f"Mismatching usage page in usage: {usage} (expecting {self._usages[0]})") try: if all(usage_type in self._INCOMPATIBLE_TYPES for usage_type in usage.usage_types): warnings.warn(HIDComplianceWarning(f"{usage} has no compatible usage types with an array item")) # noqa except (KeyError, ValueError): pass self._ignore_usages: List[Usage] = [] for page, usage_id in self._IGNORE_USAGE_VALUES: assert isinstance(page, int) and isinstance(usage_id, int) self._ignore_usages.append(Usage(page, usage_id)) def __repr__(self) -> str: return ( textwrap.dedent( """ ArrayItem( offset={}, size={}, count={}, usages=[ {}, ], ) """ ) .strip() .format( self.offset, self.size, self.count, ",\n ".join(repr(usage) for usage in self.usages), ) ) def parse(self, data: Sequence[int]) -> Dict[Usage, UsageValue]: usage_values: Dict[Usage, UsageValue] = {} for i in range(self.count): aligned_data = _data_bit_shift(data, self.offset + i * 8, self.size) usage = Usage(self._page, int.from_bytes(aligned_data, byteorder="little")) if usage in self._ignore_usages: continue # vendor usages don't have usage any standard type - just save the raw data if usage.page in hid_parser.data.UsagePages.VENDOR_PAGE: if usage not in usage_values: usage_values[usage] = VendorUsageValue( self, value=int.from_bytes(aligned_data, byteorder="little"), ) typing.cast(VendorUsageValue, usage_values[usage]).list.append( int.from_bytes(aligned_data, byteorder="little") ) continue not_incompatible_type = all(usage_type not in self._INCOMPATIBLE_TYPES for usage_type in usage.usage_types) if usage in self._usages and not_incompatible_type: usage_values[usage] = UsageValue(self, True) return usage_values @property def count(self) -> int: return self._count @property def usages(self) -> List[Usage]: return self._usages class InvalidReportDescriptor(Exception): pass # report ID (None for no report ID), item list _ITEM_POOL = Dict[Optional[int], List[BaseItem]] class ReportDescriptor: def __init__(self, data: Sequence[int]) -> None: self._data = data for byte in data: if byte < 0 or byte > 255: raise InvalidReportDescriptor( f"A report descriptor should be represented by a list of bytes: found value {byte}" ) self._input: _ITEM_POOL = {} self._output: _ITEM_POOL = {} self._feature: _ITEM_POOL = {} self._parse() @property def data(self) -> Sequence[int]: return self._data @property def input_report_ids(self) -> List[Optional[int]]: return list(self._input.keys()) @property def output_report_ids(self) -> List[Optional[int]]: return list(self._output.keys()) @property def feature_report_ids(self) -> List[Optional[int]]: return list(self._feature.keys()) def _get_report_size(self, items: List[BaseItem]) -> BitNumber: size = 0 for item in items: if isinstance(item, ArrayItem): size += item.size * item.count else: size += item.size return BitNumber(size) def get_input_items(self, report_id: Optional[int] = None) -> List[BaseItem]: return self._input[report_id] @functools.lru_cache(maxsize=16) # noqa def get_input_report_size(self, report_id: Optional[int] = None) -> BitNumber: return self._get_report_size(self.get_input_items(report_id)) def get_output_items(self, report_id: Optional[int] = None) -> List[BaseItem]: return self._output[report_id] @functools.lru_cache(maxsize=16) # noqa def get_output_report_size(self, report_id: Optional[int] = None) -> BitNumber: return self._get_report_size(self.get_output_items(report_id)) def get_feature_items(self, report_id: Optional[int] = None) -> List[BaseItem]: return self._feature[report_id] @functools.lru_cache(maxsize=16) # noqa def get_feature_report_size(self, report_id: Optional[int] = None) -> BitNumber: return self._get_report_size(self.get_feature_items(report_id)) def _parse_report_items(self, items: List[BaseItem], data: Sequence[int]) -> Dict[Usage, UsageValue]: parsed: Dict[Usage, UsageValue] = {} for item in items: if isinstance(item, VariableItem): parsed[item.usage] = item.parse(data) elif isinstance(item, ArrayItem): usage_values = item.parse(data) for usage in usage_values: if usage in parsed: warnings.warn(HIDReportWarning(f"Overriding usage: {usage}")) # noqa parsed.update(usage_values) elif isinstance(item, PaddingItem): pass else: raise TypeError(f"Unknown item: {item}") return parsed def _parse_report(self, item_poll: _ITEM_POOL, data: Sequence[int]) -> Dict[Usage, UsageValue]: if None in item_poll: # unnumbered reports return self._parse_report_items(item_poll[None], data) else: # numbered reports return self._parse_report_items(item_poll[data[0]], data[1:]) def parse_input_report(self, data: Sequence[int]) -> Dict[Usage, UsageValue]: return self._parse_report(self._input, data) def parse_output_report(self, data: Sequence[int]) -> Dict[Usage, UsageValue]: return self._parse_report(self._output, data) def parse_feature_report(self, data: Sequence[int]) -> Dict[Usage, UsageValue]: return self._parse_report(self._feature, data) def _iterate_raw(self) -> Iterable[Tuple[int, int, Optional[int]]]: i = 0 while i < len(self.data): prefix = self.data[i] tag = (prefix & 0b11110000) >> 4 typ = (prefix & 0b00001100) >> 2 size = prefix & 0b00000011 if size == 3: # 6.2.2.2 size = 4 if size == 0: data = None elif size == 1: if i + 1 >= len(self.data): raise InvalidReportDescriptor(f"Invalid size: expecting >={i + 1}, got {len(self.data)}") data = self.data[i + 1] else: if i + 1 + size >= len(self.data): raise InvalidReportDescriptor(f"Invalid size: expecting >={i + 1 + size}, got {len(self.data)}") if size == 2: pack_type = "H" elif size == 4: pack_type = "L" else: raise ValueError(f"Invalid item size: {size}") data = struct.unpack(f"<{pack_type}", bytes(self.data[i + 1 : i + 1 + size]))[0] yield typ, tag, data i += size + 1 def _append_item( self, offset_list: Dict[Optional[int], int], pool: _ITEM_POOL, report_id: Optional[int], item: BaseItem, ) -> None: offset_list[report_id] += item.size if report_id in pool: pool[report_id].append(item) else: pool[report_id] = [item] def _append_items( self, offset_list: Dict[Optional[int], int], pool: _ITEM_POOL, report_id: Optional[int], report_count: int, report_size: int, usages: List[Usage], flags: int, data: Dict[str, Any], ) -> None: item: BaseItem is_array = flags & (1 << 1) == 0 # otherwise variable """ HID 1.11, 6.2.2.9 says reports can be byte aligned by declaring a main item without usage. A main item can have multiple usages, as I interpret it, items are only considered padding when they have NO usages. """ if len(usages) == 0 or not usages: for _ in range(report_count): item = PaddingItem(offset_list[report_id], report_size) self._append_item(offset_list, pool, report_id, item) return if is_array: item = ArrayItem( offset=offset_list[report_id], size=report_size, usages=usages, count=report_count, flags=flags, **data, ) self._append_item(offset_list, pool, report_id, item) else: if len(usages) != report_count: error_str = f"Expecting {report_count} usages but got {len(usages)}" if len(usages) == 1: warnings.warn(HIDComplianceWarning(error_str)) # noqa usages *= report_count else: raise InvalidReportDescriptor(error_str) for usage in usages: item = VariableItem( offset=offset_list[report_id], size=report_size, usage=usage, flags=flags, **data, ) self._append_item(offset_list, pool, report_id, item) def _parse(self, level: int = 0, file: TextIO = sys.stdout) -> None: # noqa: C901 offset_input: Dict[Optional[int], int] = { None: 0, } offset_output: Dict[Optional[int], int] = { None: 0, } offset_feature: Dict[Optional[int], int] = { None: 0, } report_id: Optional[int] = None report_count: Optional[int] = None report_size: Optional[int] = None usage_page: Optional[int] = None usages: List[Usage] = [] usage_min: Optional[int] = None glob: Dict[str, Any] = {} local: Dict[str, Any] = {} for typ, tag, data in self._iterate_raw(): if typ == Type.MAIN: if tag in (TagMain.COLLECTION, TagMain.END_COLLECTION): usages = [] # we only care about input, output and features for now if tag not in (TagMain.INPUT, TagMain.OUTPUT, TagMain.FEATURE): continue if report_count is None: raise InvalidReportDescriptor("Trying to append an item but no report count given") if report_size is None: raise InvalidReportDescriptor("Trying to append an item but no report size given") if tag == TagMain.INPUT: if data is None: raise InvalidReportDescriptor("Invalid input item") self._append_items( offset_input, self._input, report_id, report_count, report_size, usages, data, {**glob, **local} ) elif tag == TagMain.OUTPUT: if data is None: raise InvalidReportDescriptor("Invalid output item") self._append_items( offset_output, self._output, report_id, report_count, report_size, usages, data, {**glob, **local}, ) elif tag == TagMain.FEATURE: if data is None: raise InvalidReportDescriptor("Invalid feature item") self._append_items( offset_feature, self._feature, report_id, report_count, report_size, usages, data, {**glob, **local}, ) # clear local usages = [] usage_min = None local = {} # we don't care about collections for now, maybe in the future... elif typ == Type.GLOBAL: if tag == TagGlobal.USAGE_PAGE: usage_page = data elif tag == TagGlobal.LOGICAL_MINIMUM: glob["logical_min"] = data elif tag == TagGlobal.LOGICAL_MAXIMUM: glob["logical_max"] = data elif tag == TagGlobal.PHYSICAL_MINIMUM: glob["physical_min"] = data elif tag == TagGlobal.PHYSICAL_MAXIMUM: glob["physical_max"] = data elif tag == TagGlobal.REPORT_SIZE: report_size = data elif tag == TagGlobal.REPORT_ID: if not report_id and (self._input or self._output or self._feature): raise InvalidReportDescriptor("Tried to set a report ID in a report that does not use them") report_id = data # initialize the item offset for this report ID for offset_list in (offset_input, offset_output, offset_feature): if report_id not in offset_list: offset_list[report_id] = 0 elif tag in (TagGlobal.UNIT, TagGlobal.UNIT_EXPONENT): warnings.warn( # noqa HIDUnsupportedWarning("Data specifies a unit or unit exponent, but we don't support those yet") ) elif tag in (TagGlobal.PUSH, TagGlobal.POP): warnings.warn(HIDUnsupportedWarning("Push and pop are not supported yet")) # noqa elif tag == TagGlobal.REPORT_COUNT: report_count = data else: raise NotImplementedError(f"Unsupported global tag: {bin(tag)}") elif typ == Type.LOCAL: if tag == TagLocal.USAGE: if usage_page is None: raise InvalidReportDescriptor("Usage field found but no usage page") usages.append(Usage(usage_page, data)) elif tag == TagLocal.USAGE_MINIMUM: usage_min = data elif tag == TagLocal.USAGE_MAXIMUM: if usage_min is None: raise InvalidReportDescriptor("Usage maximum set but no usage minimum") if data is None: raise InvalidReportDescriptor("Invalid usage maximum value") for i in range(usage_min, data + 1): usages.append(Usage(usage_page, i)) usage_min = None elif tag in (TagLocal.STRING_INDEX, TagLocal.STRING_MINIMUM, TagLocal.STRING_MAXIMUM): pass # we don't care about this information to parse the reports else: raise NotImplementedError(f"Unsupported local tag: {bin(tag)}") @staticmethod def _get_main_item_desc(value: int) -> str: fields = [ "Constant" if value & (1 << 0) else "Data", "Variable" if value & (1 << 1) else "Array", "Relative" if value & (1 << 2) else "Absolute", ] if value & (1 << 1): # variable only fields += [ "Wrap" if value & (1 << 3) else "No Wrap", "Non Linear" if value & (1 << 4) else "Linear", "No Preferred State" if value & (1 << 5) else "Preferred State", "Null State" if value & (1 << 6) else "No Null position", "Buffered Bytes" if value & (1 << 8) else "Bit Field", ] return ", ".join(fields) def print(self, level: int = 0, file: TextIO = sys.stdout) -> None: # noqa: C901 def printl(string: str) -> None: print(" " * level + string, file=file) usage_data: Union[Literal[False], Optional[hid_parser.data._Data]] = False for typ, tag, data in self._iterate_raw(): if typ == Type.MAIN: if tag == TagMain.INPUT: if data is None: raise InvalidReportDescriptor("Invalid input item") printl(f"Input ({self._get_main_item_desc(data)})") elif tag == TagMain.OUTPUT: if data is None: raise InvalidReportDescriptor("Invalid output item") printl(f"Output ({self._get_main_item_desc(data)})") elif tag == TagMain.FEATURE: if data is None: raise InvalidReportDescriptor("Invalid feature item") printl(f"Feature ({self._get_main_item_desc(data)})") elif tag == TagMain.COLLECTION: printl(f"Collection ({hid_parser.data.Collections.get_description(data)})") level += 1 elif tag == TagMain.END_COLLECTION: level -= 1 printl("End Collection") elif typ == Type.GLOBAL: if tag == TagGlobal.USAGE_PAGE: try: printl(f"Usage Page ({hid_parser.data.UsagePages.get_description(data)})") try: usage_data = hid_parser.data.UsagePages.get_subdata(data) except ValueError: usage_data = None except KeyError: printl(f"Usage Page (Unknown 0x{data:04x})") elif tag == TagGlobal.LOGICAL_MINIMUM: printl(f"Logical Minimum ({data})") elif tag == TagGlobal.LOGICAL_MAXIMUM: printl(f"Logical Maximum ({data})") elif tag == TagGlobal.PHYSICAL_MINIMUM: printl(f"Physical Minimum ({data})") elif tag == TagGlobal.PHYSICAL_MAXIMUM: printl(f"Physical Maximum ({data})") elif tag == TagGlobal.UNIT_EXPONENT: printl(f"Unit Exponent (0x{data:04x})") elif tag == TagGlobal.UNIT: printl(f"Unit (0x{data:04x})") elif tag == TagGlobal.REPORT_SIZE: printl(f"Report Size ({data})") elif tag == TagGlobal.REPORT_ID: printl(f"Report ID (0x{data:02x})") elif tag == TagGlobal.REPORT_COUNT: printl(f"Report Count ({data})") elif tag == TagGlobal.PUSH: printl(f"Push ({data})") elif tag == TagGlobal.POP: printl(f"Pop ({data})") elif typ == Type.LOCAL: if tag == TagLocal.USAGE: if usage_data is False: raise InvalidReportDescriptor("Usage field found but no usage page") if usage_data: try: printl(f"Usage ({usage_data.get_description(data)})") except KeyError: printl(f"Usage (Unknown, 0x{data:04x})") else: printl(f"Usage (0x{data:04x})") elif tag == TagLocal.USAGE_MINIMUM: printl(f"Usage Minimum ({data})") elif tag == TagLocal.USAGE_MAXIMUM: printl(f"Usage Maximum ({data})") elif tag == TagLocal.DESIGNATOR_INDEX: printl(f"Designator Index ({data})") elif tag == TagLocal.DESIGNATOR_MINIMUM: printl(f"Designator Minimum ({data})") elif tag == TagLocal.DESIGNATOR_MAXIMUM: printl(f"Designator Maximum ({data})") elif tag == TagLocal.STRING_INDEX: printl(f"String Index ({data})") elif tag == TagLocal.STRING_MINIMUM: printl(f"String Minimum ({data})") elif tag == TagLocal.STRING_MAXIMUM: printl(f"String Maximum ({data})") elif tag == TagLocal.DELIMITER: printl(f"Delemiter ({data})") Solaar-1.1.20/lib/hid_parser/data.py000066400000000000000000001604651522022367600172060ustar00rootroot00000000000000# SPDX-License-Identifier: MIT import enum from typing import Any from typing import Dict from typing import List from typing import Optional from typing import Tuple class _DataMeta(type): """ This metaclass populates _single and _range, following the structure described bellow The class should declare data as follows MY_DATA_VALUE = 0x01, 'Data description' or, for ranges, MY_DATA_RANGE = 0x02, ..., 0x06, 'Data range description' _single and _range will then be populated with MY_DATA_VALUE = 0x01 _single[0x01] = ('Data description', None) MY_DATA_RANGE = range(0x02, 0x06+1) _range.append(tuple(0x02, 0x06, ('Data range description', None))) As you can see, for single data insertions, the variable will be kept with the first value of the tuple. Both single and range data insertions will register the data into the correspondent data holders. You can also define subdata, MY_DATA_VALUE = 0x01, 'Data description', OTHER_DATA_TYPE MY_DATA_RANGE = 0x02, ..., 0x06, 'Data range description', YET_OTHER_DATA_TYPE Which will result in MY_DATA_VALUE = 0x01 _single[0x01] = ('Data description', OTHER_DATA_TYPE) _range.append(tuple(0x02, 0x06, ('Data range description', YET_OTHER_DATA_TYPE))) This metaclass also does some verification to prevent duplicated data. """ def __new__(mcs, name: str, bases: Tuple[Any], dic: Dict[str, Any]): # type: ignore dic["_single"] = {} dic["_range"] = [] # allow constructing data via a data dictionary as opposed to directly in the object body if "data" in dic: data = dic.pop("data") else: data = dic for attr in data: if not attr.startswith("_") and isinstance(data[attr], tuple): if len(data[attr]) == 2 or len(data[attr]) == 4: # missing sub data data[attr] = data[attr] + (None,) if len(data[attr]) == 3: # single num, desc, sub = data[attr] if not isinstance(num, int): raise TypeError(f"First element of '{attr}' should be an int") if not isinstance(desc, str): raise TypeError(f"Second element of '{attr}' should be a string") if num in dic["_single"]: raise ValueError(f"Duplicated value in '{attr}' ({num})") for nmin, nmax, _ in dic["_range"]: if nmin <= num <= nmax: raise ValueError(f"Duplicated value in '{attr}' ({num})") dic[attr] = num dic["_single"][num] = desc, sub elif len(data[attr]) == 5: # range nmin, el, nmax, desc, sub = data[attr] if not el == Ellipsis: raise TypeError(f"Second element of '{attr}' should be an ellipsis (...)") if not isinstance(nmin, int): raise TypeError(f"First element of '{attr}' should be an int") if not isinstance(nmax, int): raise TypeError(f"Third element of '{attr}' should be an int") if not isinstance(desc, str): raise TypeError(f"Fourth element of '{attr}' should be a string") for num in dic["_single"]: if nmin <= num <= nmax: raise ValueError(f"Duplicated value in '{attr}' ({num})") dic[attr] = range(nmin, nmax + 1) dic["_range"].append((nmin, nmax, (desc, sub))) else: raise ValueError(f"Invalid field: {attr}") return super().__new__(mcs, name, bases, dic) class _Data(metaclass=_DataMeta): """ This class provides a get_description method to get data out of _single and _range. See the _DataMeta documentation for more information. """ _DATA = Tuple[str, Optional[Any]] _single: Dict[int, _DATA] _range: List[Tuple[int, int, _DATA]] @classmethod def _get_data(cls, num: Optional[int]) -> _DATA: if num is None: raise KeyError("Data index is not an int") if num in cls._single: return cls._single[num] for nmin, nmax, data in cls._range: if nmin <= num <= nmax: return data raise KeyError(f"Data not found for index 0x{num:02x} in {cls.__name__}") @classmethod def get_description(cls, num: Optional[int]) -> str: return cls._get_data(num)[0] @classmethod def get_subdata(cls, num: Optional[int]) -> Any: subdata = cls._get_data(num)[1] if not subdata: raise ValueError("Sub-data not available") return subdata class UsageTypes(enum.Enum): # controls LINEAR_CONTROL = LC = 0 ON_OFF_CONTROL = OOC = 1 MOMENTARY_CONTROL = MC = 2 ONE_SHOT_CONTROL = OSC = 3 RE_TRIGGER_CONTROL = RTC = 4 # data SELECTOR = SEL = 5 STATIC_VALUE = SV = 6 STATIC_FLAG = SF = 7 DYNAMIC_FLAG = DF = 8 DYNAMIC_VALUE = DV = 9 # collection NAMED_ARRAY = NARY = 10 COLLECTION_APPLICATION = CA = 11 COLLECTION_LOGICAL = CL = 12 COLLECTION_PHYSICAL = CP = 13 USAGE_SWITCH = US = 14 USAGE_MODIFIER = UM = 15 UsageTypesControls = ( UsageTypes.LINEAR_CONTROL, UsageTypes.ON_OFF_CONTROL, UsageTypes.ONE_SHOT_CONTROL, UsageTypes.RE_TRIGGER_CONTROL, ) UsageTypesData = ( UsageTypes.SELECTOR, UsageTypes.STATIC_VALUE, UsageTypes.STATIC_FLAG, UsageTypes.DYNAMIC_VALUE, UsageTypes.DYNAMIC_FLAG, ) UsageTypesCollection = ( UsageTypes.NAMED_ARRAY, UsageTypes.COLLECTION_APPLICATION, UsageTypes.COLLECTION_LOGICAL, UsageTypes.COLLECTION_PHYSICAL, UsageTypes.USAGE_SWITCH, UsageTypes.USAGE_MODIFIER, ) class Collections(_Data): PHYSICAL = 0x00, "Physical" APPLICATION = 0x01, "Application" LOGICAL = 0x02, "Logical" REPORT = 0x03, "Report" NAMED_ARRAY = 0x04, "Named Array" USAGE_SWITCH = 0x05, "Usage Switch" USAGE_MODIFIER = 0x06, "Usage Modifier" VENDOR = 0x80, ..., 0xFF, "Vendor" class GenericDesktopControls(_Data): POINTER = 0x01, "Pointer", UsageTypes.CP MOUSE = 0x02, "Mouse", UsageTypes.CA JOYSTICK = 0x04, "Joystick", UsageTypes.CA GAMEPAD = 0x05, "Game Pad", UsageTypes.CA KEYBOARD = 0x06, "Keyboard", UsageTypes.CA KEYPAD = 0x07, "Keypad", UsageTypes.CA MULTI_AXIS_CONTROLLER = 0x08, "Multi-axis Controller", UsageTypes.CA TABLET_PC_SYSTEM_CONTROLS = 0x09, "Tablet PC System Controls", UsageTypes.CA X = 0x30, "X", UsageTypes.DV Y = 0x31, "Y", UsageTypes.DV Z = 0x32, "Z", UsageTypes.DV RX = 0x33, "Rx", UsageTypes.DV RY = 0x34, "Ry", UsageTypes.DV RZ = 0x35, "Rz", UsageTypes.DV SLIDER = 0x36, "Slider", UsageTypes.DV DIAL = 0x37, "Dial", UsageTypes.DV WHEEL = 0x38, "Wheel", UsageTypes.DV HAT_SWITCH = 0x39, "Hat switch", UsageTypes.DV COUNTED_BUFFER = 0x3A, "Counted Buffer", UsageTypes.CL BYTE_COUNT = 0x3B, "Byte Count", UsageTypes.DV MOTION_WAKEUP = 0x3C, "Motion Wakeup", UsageTypes.OSC START = 0x3D, "Start", UsageTypes.OOC SELECT = 0x3E, "Select", UsageTypes.OOC VX = 0x40, "Vx", UsageTypes.DV VY = 0x41, "Vy", UsageTypes.DV VZ = 0x42, "Vz", UsageTypes.DV VBRX = 0x43, "Vbrx", UsageTypes.DV VBRY = 0x44, "Vbry", UsageTypes.DV VBRZ = 0x45, "Vbrz", UsageTypes.DV VNO = 0x46, "Vno", UsageTypes.DV FEATURE_NOTIFICATION = 0x47, "Feature Notification", (UsageTypes.DV, UsageTypes.DF) RESOLUTION_MULTIPLIER = 0x48, "Resolution Multiplier", UsageTypes.DV SYSTEM_CONTROL = 0x80, "System Control", UsageTypes.CA SYSTEM_POWER_CONTROL = 0x81, "System Power Down", UsageTypes.OSC SYSTEM_SLEEP = 0x82, "System Sleep", UsageTypes.OSC SYSTEM_WAKE_UP = 0x83, "System Wake Up", UsageTypes.OSC SYSTEM_CONTEXT_MENU = 0x84, "System Context Menu", UsageTypes.OSC SYSTEM_MAIN_MENU = 0x85, "System Main Menu", UsageTypes.OSC SYSTEM_APP_MENU = 0x86, "System App Menu", UsageTypes.OSC SYSTEM_MENU_HELP = 0x87, "System Menu Help", UsageTypes.OSC SYSTEM_MENU_EXIT = 0x88, "System Menu Exit", UsageTypes.OSC SYSTEM_MENU_SELECT = 0x89, "System Menu Select", UsageTypes.OSC SYSTEM_MENU_RIGHT = 0x8A, "System Menu Right", UsageTypes.RTC SYSTEM_MENU_LEFT = 0x8B, "System Menu Left", UsageTypes.RTC SYSTEM_MENU_UP = 0x8C, "System Menu Up", UsageTypes.RTC SYSTEM_MENU_DOWN = 0x8D, "System Menu Down", UsageTypes.RTC SYSTEM_COLD_RESTART = 0x8E, "System Cold Restart", UsageTypes.OSC SYSTEM_WARM_RESTART = 0x8F, "System Warm Restart", UsageTypes.OSC DPAD_UP = 0x90, "D-pad Up", UsageTypes.OOC DPAD_DOWN = 0x91, "D-pad Down", UsageTypes.OOC DPAD_RIGHT = 0x92, "D-pad Right", UsageTypes.OOC DPAD_LEFT = 0x93, "D-pad Left", UsageTypes.OOC SYSTEM_DOCK = 0xA0, "System Dock", UsageTypes.OSC SYSTEM_UNDOCK = 0xA1, "System Undock", UsageTypes.OSC SYSTEM_SETUP = 0xA2, "System Setup", UsageTypes.OSC SYSTEM_BREAK = 0xA3, "System Break", UsageTypes.OSC SYSTEM_DEBBUGER_BREAK = 0xA4, "System Debugger Break", UsageTypes.OSC APPLICATION_BREAK = 0xA5, "Application Break", UsageTypes.OSC APPLICATION_DEBBUGER_BREAK = 0xA6, "Application Debugger Break", UsageTypes.OSC SYSTEM_SPEAKER_MUTE = 0xA7, "System Speaker Mute", UsageTypes.OSC SYSTEM_HIBERNATE = 0xA8, "System Hibernate", UsageTypes.OSC SYSTEM_DISPLAY_INVERT = 0xB0, "System Display Invert", UsageTypes.OSC SYSTEM_DISPLAY_INTERNAL = 0xB1, "System Display Internal", UsageTypes.OSC SYSTEM_DISPLAY_EXTERNAL = 0xB2, "System Display External", UsageTypes.OSC SYSTEM_DISPLAY_BOTH = 0xB3, "System Display Both", UsageTypes.OSC SYSTEM_DISPLAY_DUAL = 0xB4, "System Display Dual", UsageTypes.OSC SYSTEM_DISPLAY_TOGGLE = 0xB5, "System Display Toggle Int/Ext", UsageTypes.OSC SYSTEM_DISPLAY_SWAP = 0xB6, "System Display Swap Primary/Secondary", UsageTypes.OSC SYSTEM_DISPLAY_LCD_AUTOSCALE = 0xB7, "System Display LCD Autoscale", UsageTypes.OSC class KeyboardKeypad(_Data): NO_EVENT = 0x00, "No event indicated", UsageTypes.SEL KEYBOARD_ERROR_ROLL_OVER = 0x01, "Keyboard ErrorRollOver", UsageTypes.SEL KEYBOARD_POST = 0x02, "Keyboard POSTFail", UsageTypes.SEL KEYBOARD_ERROR_UNDEFINED = 0x03, "Keyboard ErrorUndefined", UsageTypes.SEL KEYBOARD_A = 0x04, "Keyboard a and A", UsageTypes.SEL KEYBOARD_B = 0x05, "Keyboard b and B", UsageTypes.SEL KEYBOARD_C = 0x06, "Keyboard c and C", UsageTypes.SEL KEYBOARD_D = 0x07, "Keyboard d and D", UsageTypes.SEL KEYBOARD_E = 0x08, "Keyboard e and E", UsageTypes.SEL KEYBOARD_F = 0x09, "Keyboard f and F", UsageTypes.SEL KEYBOARD_G = 0x0A, "Keyboard g and G", UsageTypes.SEL KEYBOARD_H = 0x0B, "Keyboard h and H", UsageTypes.SEL KEYBOARD_I = 0x0C, "Keyboard i and I", UsageTypes.SEL KEYBOARD_J = 0x0D, "Keyboard j and J", UsageTypes.SEL KEYBOARD_K = 0x0E, "Keyboard k and K", UsageTypes.SEL KEYBOARD_L = 0x0F, "Keyboard l and L", UsageTypes.SEL KEYBOARD_M = 0x10, "Keyboard m and M", UsageTypes.SEL KEYBOARD_N = 0x11, "Keyboard n and N", UsageTypes.SEL KEYBOARD_O = 0x12, "Keyboard o and O", UsageTypes.SEL KEYBOARD_P = 0x13, "Keyboard p and P", UsageTypes.SEL KEYBOARD_Q = 0x14, "Keyboard q and Q", UsageTypes.SEL KEYBOARD_R = 0x15, "Keyboard r and R", UsageTypes.SEL KEYBOARD_S = 0x16, "Keyboard s and S", UsageTypes.SEL KEYBOARD_T = 0x17, "Keyboard t and T", UsageTypes.SEL KEYBOARD_U = 0x18, "Keyboard u and U", UsageTypes.SEL KEYBOARD_V = 0x19, "Keyboard v and V", UsageTypes.SEL KEYBOARD_W = 0x1A, "Keyboard w and W", UsageTypes.SEL KEYBOARD_X = 0x1B, "Keyboard x and X", UsageTypes.SEL KEYBOARD_Y = 0x1C, "Keyboard y and Y", UsageTypes.SEL KEYBOARD_Z = 0x1D, "Keyboard z and Z", UsageTypes.SEL KEYBOARD_1 = 0x1E, "Keyboard 1 and !", UsageTypes.SEL KEYBOARD_2 = 0x1F, "Keyboard 2 and @", UsageTypes.SEL KEYBOARD_3 = 0x20, "Keyboard 3 and #", UsageTypes.SEL KEYBOARD_4 = 0x21, "Keyboard 4 and $", UsageTypes.SEL KEYBOARD_5 = 0x22, "Keyboard 5 and %", UsageTypes.SEL KEYBOARD_6 = 0x23, "Keyboard 6 and ^", UsageTypes.SEL KEYBOARD_7 = 0x24, "Keyboard 7 and &", UsageTypes.SEL KEYBOARD_8 = 0x25, "Keyboard 8 and *", UsageTypes.SEL KEYBOARD_9 = 0x26, "Keyboard 9 and (", UsageTypes.SEL KEYBOARD_0 = 0x27, "Keyboard 0 and )", UsageTypes.SEL KEYBOARD_ENTER = 0x28, "Keyboard Return (ENTER)", UsageTypes.SEL KEYBOARD_ESCAPE = 0x29, "Keyboard ESCAPE", UsageTypes.SEL KEYBOARD_DELETE = 0x2A, "Keyboard DELETE (Backspace)", UsageTypes.SEL KEYBOARD_TAB = 0x2B, "Keyboard Tab", UsageTypes.SEL KEYBOARD_SPACEBAR = 0x2C, "Keyboard Spacebar", UsageTypes.SEL KEYBOARD_MINUS = 0x2D, "Keyboard - and (underscore)", UsageTypes.SEL KEYBOARD_PLUS = 0x2E, "Keyboard = and +", UsageTypes.SEL KEYBOARD_LEFT_BRACKET = 0x2F, "Keyboard [ and {", UsageTypes.SEL KEYBOARD_RIGHT_BRACKET = 0x30, "Keyboard ] and }", UsageTypes.SEL KEYBOARD_BACKSLASH = 0x31, "Keyboard \\ and |", UsageTypes.SEL KEYBOARD_CARDINAL = 0x32, "Keyboard Non-US # and ~", UsageTypes.SEL KEYBOARD_SEMICOLON = 0x33, "Keyboard ; and :", UsageTypes.SEL KEYBOARD_QUOTE = 0x34, "Keyboard ' and \"", UsageTypes.SEL KEYBOARD_GRAVE = 0x35, "Keyboard Grave Accent and Tilde", UsageTypes.SEL KEYBOARD_COMMA = 0x36, "Keyboard , and <", UsageTypes.SEL KEYBOARD_DOT = 0x37, "Keyboard . and >", UsageTypes.SEL KEYBOARD_SLASH = 0x38, "Keyboard / and ?", UsageTypes.SEL KEYBOARD_CAPS_LOCK = 0x39, "Keyboard Caps Lock", UsageTypes.SEL KEYBOARD_F1 = 0x3A, "Keyboard F1", UsageTypes.SEL KEYBOARD_F2 = 0x3B, "Keyboard F2", UsageTypes.SEL KEYBOARD_F3 = 0x3C, "Keyboard F3", UsageTypes.SEL KEYBOARD_F4 = 0x3D, "Keyboard F4", UsageTypes.SEL KEYBOARD_F5 = 0x3E, "Keyboard F5", UsageTypes.SEL KEYBOARD_F6 = 0x3F, "Keyboard F6", UsageTypes.SEL KEYBOARD_F7 = 0x40, "Keyboard F7", UsageTypes.SEL KEYBOARD_F8 = 0x41, "Keyboard F8", UsageTypes.SEL KEYBOARD_F9 = 0x42, "Keyboard F9", UsageTypes.SEL KEYBOARD_F10 = 0x43, "Keyboard F10", UsageTypes.SEL KEYBOARD_F11 = 0x44, "Keyboard F11", UsageTypes.SEL KEYBOARD_F12 = 0x45, "Keyboard F12", UsageTypes.SEL KEYBOARD_PRINTSCREEN = 0x46, "Keyboard PrintScreen", UsageTypes.SEL KEYBOARD_SCROLL_LOCK = 0x47, "Keyboard Scroll Lock", UsageTypes.SEL KEYBOARD_PAUSE = 0x48, "Keyboard Pause", UsageTypes.SEL KEYBOARD_INSERT = 0x49, "Keyboard Insert", UsageTypes.SEL KEYBOARD_HOME = 0x4A, "Keyboard Home", UsageTypes.SEL KEYBOARD_PAGE_UP = 0x4B, "Keyboard PageUp", UsageTypes.SEL KEYBOARD_DELETE_FORWARD = 0x4C, "Keyboard Delete Forward", UsageTypes.SEL KEYBOARD_END = 0x4D, "Keyboard End", UsageTypes.SEL KEYBOARD_PAGE_DOWN = 0x4E, "Keyboard PageDown", UsageTypes.SEL KEYBOARD_RIGHT_ARROW = 0x4F, "Keyboard RightArrow", UsageTypes.SEL KEYBOARD_LEFT_ARROW = 0x50, "Keyboard LeftArrow", UsageTypes.SEL KEYBOARD_UP_ARROW = 0x51, "Keyboard DownArrow", UsageTypes.SEL KEYBOARD_DOWN_ARROW = 0x52, "Keyboard UpArrow", UsageTypes.SEL KEYBOARD_NUM_LOCK = 0x53, "Keypad Num Lock and Clear", UsageTypes.SEL KEYPAD_SLASH = 0x54, "Keypad /", UsageTypes.SEL KEYPAD_ASTERISK = 0x55, "Keypad *", UsageTypes.SEL KEYPAD_MINUS = 0x56, "Keypad -", UsageTypes.SEL KEYPAD_PLUS = 0x57, "Keypad +", UsageTypes.SEL KEYPAD_ENTER = 0x58, "Keypad ENTER", UsageTypes.SEL KEYPAD_1 = 0x59, "Keypad 1 and End", UsageTypes.SEL KEYPAD_2 = 0x5A, "Keypad 2 and Down Arrow", UsageTypes.SEL KEYPAD_3 = 0x5B, "Keypad 3 and PageDn", UsageTypes.SEL KEYPAD_4 = 0x5C, "Keypad 4 and Left Arrow", UsageTypes.SEL KEYPAD_5 = 0x5D, "Keypad 5", UsageTypes.SEL KEYPAD_6 = 0x5E, "Keypad 6 and Right Arrow", UsageTypes.SEL KEYPAD_7 = 0x5F, "Keypad 7 and Home", UsageTypes.SEL KEYPAD_8 = 0x60, "Keypad 8 and Up Arrow", UsageTypes.SEL KEYPAD_9 = 0x61, "Keypad 9 and PageUp", UsageTypes.SEL KEYPAD_0 = 0x62, "Keypad 0 and Insert", UsageTypes.SEL KEYPAD_DOT = 0x63, "Keypad . and Delete", UsageTypes.SEL KEYPAD_BACKSLASH = 0x64, "Keyboard Non-US \\ and |", UsageTypes.SEL KEYPAD_APPLICATION = 0x65, "Keyboard Application", UsageTypes.SEL KEYPAD_POWER = 0x66, "Keyboard Power", UsageTypes.SEL KEYPAD_EQUALS = 0x67, "Keypad =", UsageTypes.SEL KEYBOARD_F13 = 0x68, "Keyboard F13", UsageTypes.SEL KEYBOARD_F14 = 0x69, "Keyboard F14", UsageTypes.SEL KEYBOARD_F15 = 0x6A, "Keyboard F15", UsageTypes.SEL KEYBOARD_F16 = 0x6B, "Keyboard F16", UsageTypes.SEL KEYBOARD_F17 = 0x6C, "Keyboard F17", UsageTypes.SEL KEYBOARD_F18 = 0x6D, "Keyboard F18", UsageTypes.SEL KEYBOARD_F19 = 0x6E, "Keyboard F19", UsageTypes.SEL KEYBOARD_F20 = 0x6F, "Keyboard F20", UsageTypes.SEL KEYBOARD_F21 = 0x70, "Keyboard F21", UsageTypes.SEL KEYBOARD_F22 = 0x71, "Keyboard F22", UsageTypes.SEL KEYBOARD_F23 = 0x72, "Keyboard F23", UsageTypes.SEL KEYBOARD_F24 = 0x73, "Keyboard F24", UsageTypes.SEL KEYBOARD_EXECUTE = 0x74, "Keyboard Execute", UsageTypes.SEL KEYBOARD_HELP = 0x75, "Keyboard Help", UsageTypes.SEL KEYBOARD_MENU = 0x76, "Keyboard Menu", UsageTypes.SEL KEYBOARD_SELECT = 0x77, "Keyboard Select", UsageTypes.SEL KEYBOARD_STOP = 0x78, "Keyboard Stop", UsageTypes.SEL KEYBOARD_AGAIN = 0x79, "Keyboard Again", UsageTypes.SEL KEYBOARD_UNDO = 0x7A, "Keyboard Undo", UsageTypes.SEL KEYBOARD_CUT = 0x7B, "Keyboard Cut", UsageTypes.SEL KEYBOARD_COPY = 0x7C, "Keyboard Copy", UsageTypes.SEL KEYBOARD_PASTE = 0x7D, "Keyboard Paste", UsageTypes.SEL KEYBOARD_FIND = 0x7E, "Keyboard Find", UsageTypes.SEL KEYBOARD_MUTE = 0x7F, "Keyboard Mute", UsageTypes.SEL KEYBOARD_VOLUME_UP = 0x80, "Keyboard Volume Up", UsageTypes.SEL KEYBOARD_VOLUME_DOWN = 0x81, "Keyboard Volume Down", UsageTypes.SEL KEYBOARD_LOCKING_CAPS_LOCK = 0x82, "Keyboard Locking Caps Lock", UsageTypes.SEL KEYBOARD_LOCKING_NUM_LOCK = 0x83, "Keyboard Locking Num Lock", UsageTypes.SEL KEYBOARD_LOCKING_SCROLL_LOCK = 0x84, "Keyboard Locking Scroll Lock", UsageTypes.SEL KEYPAD_COMMA = 0x85, "Keypad Comma", UsageTypes.SEL KEYPAD_EQUALS_SIGN = 0x86, "Keypad Equal Sign", UsageTypes.SEL KEYBOARD_INTERNATIONAL1 = 0x87, "Keyboard International1", UsageTypes.SEL KEYBOARD_INTERNATIONAL2 = 0x88, "Keyboard International2", UsageTypes.SEL KEYBOARD_INTERNATIONAL3 = 0x89, "Keyboard International3", UsageTypes.SEL KEYBOARD_INTERNATIONAL4 = 0x8A, "Keyboard International4", UsageTypes.SEL KEYBOARD_INTERNATIONAL5 = 0x8B, "Keyboard International5", UsageTypes.SEL KEYBOARD_INTERNATIONAL6 = 0x8C, "Keyboard International6", UsageTypes.SEL KEYBOARD_INTERNATIONAL7 = 0x8D, "Keyboard International7", UsageTypes.SEL KEYBOARD_INTERNATIONAL8 = 0x8E, "Keyboard International8", UsageTypes.SEL KEYBOARD_INTERNATIONAL9 = 0x8F, "Keyboard International9", UsageTypes.SEL KEYBOARD_LANG1 = 0x90, "Keyboard LANG1", UsageTypes.SEL KEYBOARD_LANG2 = 0x91, "Keyboard LANG2", UsageTypes.SEL KEYBOARD_LANG3 = 0x92, "Keyboard LANG3", UsageTypes.SEL KEYBOARD_LANG4 = 0x93, "Keyboard LANG4", UsageTypes.SEL KEYBOARD_LANG5 = 0x94, "Keyboard LANG5", UsageTypes.SEL KEYBOARD_LANG6 = 0x95, "Keyboard LANG6", UsageTypes.SEL KEYBOARD_LANG7 = 0x96, "Keyboard LANG7", UsageTypes.SEL KEYBOARD_LANG8 = 0x97, "Keyboard LANG8", UsageTypes.SEL KEYBOARD_LANG9 = 0x98, "Keyboard LANG9", UsageTypes.SEL KEYBOARD_ALTERNATE_ERASE = 0x99, "Keyboard Alternate Erase", UsageTypes.SEL KEYBOARD_SYSREQ_ATTENTION = 0x9A, "Keyboard SysReq/Attention", UsageTypes.SEL KEYBOARD_CANCEL = 0x9B, "Keyboard Cancel", UsageTypes.SEL KEYBOARD_CLEAR = 0x9C, "Keyboard Clear", UsageTypes.SEL KEYBOARD_PRIOR = 0x9D, "Keyboard Prior", UsageTypes.SEL KEYBOARD_RETURN = 0x9E, "Keyboard Return", UsageTypes.SEL KEYBOARD_SEPARATOE = 0x9F, "Keyboard Separator", UsageTypes.SEL KEYBOARD_OUT = 0xA0, "Keyboard Out", UsageTypes.SEL KEYBOARD_OPER = 0xA1, "Keyboard Oper", UsageTypes.SEL KEYBOARD_CLEAR_AGAIN = 0xA2, "Keyboard Clear/Again", UsageTypes.SEL KEYBOARD_CRSEL_PROPS = 0xA3, "Keyboard CrSel/Props", UsageTypes.SEL KEYBOARD_EXSELL = 0xA4, "Keyboard ExSel", UsageTypes.SEL KEYPAD_ZERO_ZERO = 0xB0, "Keypad 00", UsageTypes.SEL KEYPAD_ZERO_ZERO_ZERO = 0xB1, "Keypad 000", UsageTypes.SEL THOUSANDS_SEPARATOR = 0xB2, "Thousands Separator", UsageTypes.SEL DECIMAL_SEPARATOR = 0xB3, "Decimal Separator", UsageTypes.SEL CURRENCY_UNIT = 0xB4, "Currency Unit", UsageTypes.SEL CURRENCY_SUBUNIT = 0xB5, "Currency Sub-unit", UsageTypes.SEL KEYPAD_LEFT_PARENTHESIS = 0xB6, "Keypad (", UsageTypes.SEL KEYPAD_RIGHT_PARENTHESIS = 0xB7, "Keypad )", UsageTypes.SEL KEYPAD_LEFT_CURLY_BRACKET = 0xB8, "Keypad {", UsageTypes.SEL KEYPAD_RIGHT_CURLY_BRACKET = 0xB9, "Keypad }", UsageTypes.SEL KEYPAD_TAB = 0xBA, "Keypad Tab", UsageTypes.SEL KEYPAD_BACKSPACE = 0xBB, "Keypad Backspace", UsageTypes.SEL KEYPAD_A = 0xBC, "Keypad A", UsageTypes.SEL KEYPAD_B = 0xBD, "Keypad B", UsageTypes.SEL KEYPAD_C = 0xBE, "Keypad C", UsageTypes.SEL KEYPAD_D = 0xBF, "Keypad D", UsageTypes.SEL KEYPAD_E = 0xC0, "Keypad E", UsageTypes.SEL KEYPAD_F = 0xC1, "Keypad F", UsageTypes.SEL KEYPAD_XOR = 0xC2, "Keypad XOR", UsageTypes.SEL KEYPAD_AND = 0xC3, "Keypad ^", UsageTypes.SEL KEYPAD_PERCENTAGE = 0xC4, "Keypad %", UsageTypes.SEL KEYPAD_LESS_THAN = 0xC5, "Keypad <", UsageTypes.SEL KEYPAD_MORE_THAN = 0xC6, "Keypad >", UsageTypes.SEL KEYPAD_AMPERSAND = 0xC7, "Keypad &", UsageTypes.SEL KEYPAD_2_AMPERSAND = 0xC8, "Keypad &&", UsageTypes.SEL KEYPAD_VERTICAL_BAR = 0xC9, "Keypad |", UsageTypes.SEL KEYPAD_2_VERTICAL_BAR = 0xCA, "Keypad ||", UsageTypes.SEL KEYPAD_COLON = 0xCB, "Keypad :", UsageTypes.SEL KEYPAD_CARDINAL = 0xCC, "Keypad #", UsageTypes.SEL KEYPAD_SPACE = 0xCD, "Keypad Space", UsageTypes.SEL KEYPAD_AT = 0xCE, "Keypad @", UsageTypes.SEL KEYPAD_EXCLAMATION = 0xCF, "Keypad !", UsageTypes.SEL KEYPAD_MEMORY_STORE = 0xD0, "Keypad Memory Store", UsageTypes.SEL KEYPAD_MEMORY_RECALL = 0xD1, "Keypad Memory Recall", UsageTypes.SEL KEYPAD_MEMORY_CLEAR = 0xD2, "Keypad Memory Clear", UsageTypes.SEL KEYPAD_MEMORY_ADD = 0xD3, "Keypad Memory Add", UsageTypes.SEL KEYPAD_MEMORY_SUBTRACT = 0xD4, "Keypad Memory Subtract", UsageTypes.SEL KEYPAD_MEMORY_MULTIPLY = 0xD5, "Keypad Memory Multiply", UsageTypes.SEL KEYPAD_MEMORY_DIVIDE = 0xD6, "Keypad Memory Divide", UsageTypes.SEL KEYPAD_PLUS_MINUS = 0xD7, "Keypad +/-", UsageTypes.SEL KEYPAD_CLEAR = 0xD8, "Keypad Clear", UsageTypes.SEL KEYPAD_CLEAR_ENTRY = 0xD9, "Keypad Clear Entry", UsageTypes.SEL KEYPAD_BINARY = 0xDA, "Keypad Binary", UsageTypes.SEL KEYPAD_OCTAL = 0xDB, "Keypad Octal", UsageTypes.SEL KEYPAD_DECIMAL = 0xDC, "Keypad Decimal", UsageTypes.SEL KEYPAD_HEXADECIMAL = 0xDD, "Keypad Hexadecimal", UsageTypes.DV KEYBOARD_LEFT_CONTROL = 0xE0, "Keyboard LeftControl", UsageTypes.DV KEYBOARD_LEFT_SHIFT = 0xE1, "Keyboard LeftShift", UsageTypes.DV KEYBOARD_LEFT_ALT = 0xE2, "Keyboard LeftAlt", UsageTypes.DV KEYBOARD_LEFT_GUI = 0xE3, "Keyboard Left GUI", UsageTypes.DV KEYBOARD_RIGHT_CONTROL = 0xE4, "Keyboard RightControl", UsageTypes.DV KEYBOARD_RIGHT_SHIFT = 0xE5, "Keyboard RightShift", UsageTypes.DV KEYBOARD_RIGHT_ALT = 0xE6, "Keyboard RightAlt", UsageTypes.DV KEYBOARD_RIGHT_GUI = 0xE7, "Keyboard Right GUI", UsageTypes.DV class Led(_Data): NUM_LOCK = 0x01, "Num Lock", UsageTypes.OOC CAPS_LOCK = 0x02, "Caps Lock", UsageTypes.OOC SCROLL_LOCK = 0x03, "Scroll Lock", UsageTypes.OOC COMPOSE = 0x04, "Compose", UsageTypes.OOC KANA = 0x05, "Kana", UsageTypes.OOC POWER = 0x06, "Power", UsageTypes.OOC SHIFT = 0x07, "Shift", UsageTypes.OOC DO_NOT_DISTURB = 0x08, "Do Not Disturb", UsageTypes.OOC MUTE = 0x09, "Mute", UsageTypes.OOC TONE_ENABLE = 0x0A, "Tone Enable", UsageTypes.OOC HIGH_CUT_FILTER = 0x0B, "High Cut Filter", UsageTypes.OOC LOW_CUT_FILTER = 0x0C, "Low Cut Filter", UsageTypes.OOC EQUALIZER_ENABLE = 0x0D, "Equalizer Enable", UsageTypes.OOC SOUND_FIELD_ON = 0x0E, "Sound Field On", UsageTypes.OOC SURROUND_ON = 0x0F, "Surround On", UsageTypes.OOC REPEAR = 0x10, "Repeat", UsageTypes.OOC STEREO = 0x11, "Stereo", UsageTypes.OOC SAMPLING_RATE_DETECT = 0x12, "Sampling Rate Detect", UsageTypes.OOC SPINNING = 0x13, "Spinning", UsageTypes.OOC CAV = 0x14, "CAV", UsageTypes.OOC CLV = 0x15, "CLV", UsageTypes.OOC RECORDING_FORMAT_DETECT = 0x16, "Recording Format Detect", UsageTypes.OOC OFF_HOOK = 0x17, "Off-Hook", UsageTypes.OOC RING = 0x18, "Ring", UsageTypes.OOC MESSAGE_WAITING = 0x19, "Message Waiting", UsageTypes.OOC DATA_MODE = 0x1A, "Data Mode", UsageTypes.OOC BATTERY_OPERATION = 0x1B, "Battery Operation", UsageTypes.OOC BATTERY_OK = 0x1C, "Battery OK", UsageTypes.OOC BATTERY_LOW = 0x1D, "Battery Low", UsageTypes.OOC SPEAKER = 0x1E, "Speaker", UsageTypes.OOC HEAD_SET = 0x1F, "Head Set", UsageTypes.OOC HOLD = 0x20, "Hold", UsageTypes.OOC MICROPHONE = 0x21, "Microphone", UsageTypes.OOC COVERAGE = 0x22, "Coverage", UsageTypes.OOC NIGHT_MODE = 0x23, "Night Mode", UsageTypes.OOC SEND_CALLS = 0x24, "Send Calls", UsageTypes.OOC CALL_PICKUP = 0x25, "Call Pickup", UsageTypes.OOC CONFERENCE = 0x26, "Conference", UsageTypes.OOC STAND_BY = 0x27, "Stand-by", UsageTypes.OOC CAMERA_ON = 0x28, "Camera On", UsageTypes.OOC CAMERA_OFF = 0x29, "Camera Off", UsageTypes.OOC ON_LINE = 0x2A, "On-Line", UsageTypes.OOC OFF_LINE = 0x2B, "Off-Line", UsageTypes.OOC BUSY = 0x2C, "Busy", UsageTypes.OOC READY = 0x2D, "Ready", UsageTypes.OOC PAPER_OUT = 0x2E, "Paper-Out", UsageTypes.OOC PAPER_JAM = 0x2F, "Paper-Jam", UsageTypes.OOC REMOTE = 0x30, "Remote", UsageTypes.OOC FORWARD = 0x31, "Forward", UsageTypes.OOC REVERSE = 0x32, "Reverse", UsageTypes.OOC STOP = 0x33, "Stop", UsageTypes.OOC REWIND = 0x34, "Rewind", UsageTypes.OOC FAST_FORWARD = 0x35, "Fast Forward", UsageTypes.OOC PLAY = 0x36, "Play", UsageTypes.OOC PAUSE = 0x37, "Pause", UsageTypes.OOC RECORD = 0x38, "Record", UsageTypes.OOC ERROR = 0x39, "Error", UsageTypes.OOC USAGE_SELECTED_INDICATOR = 0x3A, "Usage Selected Indicator", UsageTypes.US USAGE_IN_USE_INDICATOR = 0x3B, "Usage In Use Indicator", UsageTypes.US USAGE_MULTI_MODE_INDICATOR = 0x3C, "Usage Multi Mode Indicator", UsageTypes.UM INDICATOR_ON = 0x3D, "Indicator On", UsageTypes.SEL INDICATOR_FLASH = 0x3E, "Indicator Flash", UsageTypes.SEL INDICATOR_SLOW_BLINK = 0x3F, "Indicator Slow Blink", UsageTypes.SEL INDICATOR_FAST_BLINK = 0x40, "Indicator Fast Blink", UsageTypes.SEL INDICATOR_OFF = 0x41, "Indicator Off", UsageTypes.SEL FLASH_ON_TIME = 0x42, "Flash On Time", UsageTypes.DV SLOW_BLINK_ON_TIME = 0x43, "Slow Blink On Time", UsageTypes.DV SLOW_BLINK_OFF_TIME = 0x44, "Slow Blink Off Time", UsageTypes.DV FAST_BLINK_ON_TIME = 0x45, "Fast Blink On Time", UsageTypes.DV FAST_BLINK_OFF_TIME = 0x46, "Fast Blink Off Time", UsageTypes.DV USAGE_INDICATOR_COLOR = 0x47, "Usage Indicator Color", UsageTypes.UM INDICATOR_RED = 0x48, "Indicator Red", UsageTypes.SEL INDICATOR_GREEN = 0x49, "Indicator Green", UsageTypes.SEL INDICATOR_AMBER = 0x4A, "Indicator Amber", UsageTypes.SEL GENERIC_INDICATOR = 0x4B, "Generic Indicator", UsageTypes.OOC SYSTEM_SUSPEND = 0x4C, "System Suspend", UsageTypes.OOC EXTERNAL_POWER_CONNECTED = 0x4D, "External Power Connected", UsageTypes.OOC class Button(_Data): _USAGE_TYPES = ( UsageTypes.SEL, UsageTypes.OOC, UsageTypes.MC, UsageTypes.OSC, ) data = { "NO_BUTTON": (0x0000, "Button 1 (primary/trigger)", _USAGE_TYPES), "BUTTON_1": (0x0001, "Button 1 (primary/trigger)", _USAGE_TYPES), "BUTTON_2": (0x0002, "Button 2 (secondary)", _USAGE_TYPES), "BUTTON_3": (0x0003, "Button 3 (tertiary)", _USAGE_TYPES), } for _i in range(0x0004, 0xFFFF): data[f"BUTTON_{_i}"] = _i, f"Button {_i}", _USAGE_TYPES class Consumer(_Data): CONSUMER_CONTROL = 0x0001, "Consumer Control", UsageTypes.CA NUMERIC_KEY_PAD = 0x0002, "Numeric Key Pad", UsageTypes.NARY PROGRAMMABLE_BUTTONS = 0x0003, "Programmable Buttons", UsageTypes.NARY MICROPHONE = 0x0004, "Microphone", UsageTypes.CA HEADPHONE = 0x0005, "Headphone", UsageTypes.CA GRAPHIC_EQUALIZER = 0x0006, "Graphic Equalizer", UsageTypes.CA PLUS10 = 0x0020, "+10", UsageTypes.OSC PULS100 = 0x0021, "+100", UsageTypes.OSC AM_PM = 0x0022, "AM/PM", UsageTypes.OSC POWER = 0x0030, "Power", UsageTypes.OOC REST = 0x0031, "Reset", UsageTypes.OSC SLEEP = 0x0032, "Sleep", UsageTypes.OSC SLEEP_AFTER = 0x0033, "Sleep After", UsageTypes.OSC SLEEP_MODE = 0x0034, "Sleep Mode", UsageTypes.RTC ILLUMINATION = 0x0035, "Illumination", UsageTypes.OOC FUNCTION_BUTTONS = 0x0036, "Function Buttons", UsageTypes.NARY MENU = 0x0040, "Menu", UsageTypes.OOC MENU_PICK = 0x0041, "Menu Pick", UsageTypes.OSC MENU_UP = 0x0042, "Menu Up", UsageTypes.OSC MENU_DOWN = 0x0043, "Menu Down", UsageTypes.OSC MENU_LEFT = 0x0044, "Menu Left", UsageTypes.OSC MENU_RIGHT = 0x0045, "Menu Right", UsageTypes.OSC MENU_ESCAPE = 0x0046, "Menu Escape", UsageTypes.OSC MENU_VALUE_INCREASE = 0x0047, "Menu Value Increase", UsageTypes.OSC MENU_VALUE_DECREASE = 0x0048, "Menu Value Decrease", UsageTypes.OSC DATA_ON_SCREEN = 0x0060, "Data On Screen", UsageTypes.OOC CLOSED_CAPTION = 0x0061, "Closed Caption", UsageTypes.OOC CLOSED_CAPTION_SELECT = 0x0062, "Closed Caption Select", UsageTypes.OOC VCR_TV = 0x0063, "VCR/TV", UsageTypes.OSC BROADCAST_MODE = 0x0064, "Broadcast Mode", UsageTypes.OOC SNAPSHOT = 0x0065, "Snapshot", UsageTypes.OOC STILL = 0x0066, "Still", UsageTypes.OOC SELECTION = 0x0080, "Selection", UsageTypes.NARY ASSIGN_SELECTION = 0x0081, "Assign Selection", UsageTypes.OSC MODE_STEP = 0x0082, "Mode Step", UsageTypes.OSC RECALL_LAST = 0x0083, "Recall Last", UsageTypes.OSC ENTER_CHANNEL = 0x0084, "Enter Channel", UsageTypes.OSC ORDER_MOVIE = 0x0085, "Order Movie", UsageTypes.OSC CHANNEL = 0x0086, "Channel", UsageTypes.LC MEDIA_SELECTION = 0x0087, "Media Selection", UsageTypes.NARY MEDIA_SELECT_COMPUTER = 0x0088, "Media Select Computer", UsageTypes.SEL MEDIA_SELECT_TV = 0x0089, "Media Select TV", UsageTypes.SEL MEDIA_SELECT_WWW = 0x008A, "Media Select WWW", UsageTypes.SEL MEDIA_SELECT_DVD = 0x008B, "Media Select DVD", UsageTypes.SEL MEDIA_SELECT_TELEPHONE = 0x008C, "Media Select Telephone", UsageTypes.SEL MEDIA_SELECT_PROGRAM_GUIDE = 0x008D, "Media Select Program Guide", UsageTypes.SEL MEDIA_SELECT_VIDEO_PHONE = 0x008E, "Media Select Video Phone", UsageTypes.SEL MEDIA_SELECT_GAMES = 0x008F, "Media Select Games", UsageTypes.SEL MEDIA_SELECT_MESSAGES = 0x0090, "Media Select Messages", UsageTypes.SEL MEDIA_SELECT_CD = 0x0091, "Media Select CD ", UsageTypes.SEL MEDIA_SELECT_VCR = 0x0092, "Media Select VCR", UsageTypes.SEL MEDIA_SELECT_TUNER = 0x0093, "Media Select Tuner", UsageTypes.SEL QUIT = 0x0094, "Quit", UsageTypes.OSC HELP = 0x0095, "Help", UsageTypes.OOC MEDIA_SELECT_TAPE = 0x0096, "Media Select Tape", UsageTypes.SEL MEDIA_SELECT_CABLE = 0x0097, "Media Select Cable", UsageTypes.SEL MEDIA_SELECT_SATELLITE = 0x0098, "Media Select Satellite", UsageTypes.SEL MEDIA_SELECT_SECURITY = 0x0099, "Media Select Security", UsageTypes.SEL MEDIA_SELECT_HOME = 0x009A, "Media Select Home", UsageTypes.SEL MEDIA_SELECT_CALL = 0x009B, "Media Select Call", UsageTypes.SEL CHANNEL_INCREMENT = 0x009C, "Channel Increment", UsageTypes.OSC CHANNEL_DECREMENT = 0x009D, "Channel Decrement", UsageTypes.OSC MEDIA_SELECT_SAP = 0x009E, "Media Select SAP", UsageTypes.SEL VCR_PLUS = 0x00A0, "VCR Plus", UsageTypes.OSC ONCE = 0x00A1, "Once", UsageTypes.OSC DAILY = 0x00A2, "Daily", UsageTypes.OSC WEEKLY = 0x00A3, "Weekly", UsageTypes.OSC MONTHLY = 0x00A4, "Monthly", UsageTypes.OSC PLAY = 0x00B0, "Play", UsageTypes.OOC PAUSE = 0x00B1, "Pause", UsageTypes.OOC RECORD = 0x00B2, "Record", UsageTypes.OOC FAST_FORWARD = 0x00B3, "Fast Forward", UsageTypes.OOC REWIND = 0x00B4, "Rewind", UsageTypes.OOC SCAN_NEXT_TRACK = 0x00B5, "Scan Next Track", UsageTypes.OSC SCAN_PREVIOUS_TRACK = 0x00B6, "Scan Previous Track", UsageTypes.OSC STOP = 0x00B7, "Stop", UsageTypes.OSC EJECT = 0x00B8, "Eject", UsageTypes.OSC RANDOM_PLAY = 0x00B9, "Random Play", UsageTypes.OOC SELECT_DISC = 0x00BA, "Select Disc", UsageTypes.NARY ENTER_DISC = 0x00BB, "Enter Disc", UsageTypes.MC REPEAT = 0x00BC, "Repeat", UsageTypes.OSC TRACKING = 0x00BD, "Tracking", UsageTypes.LC TRACK_NORMAL = 0x00BE, "Track Normal", UsageTypes.OSC SLOW_TRACKING = 0x00BF, "Slow Tracking", UsageTypes.LC FRAME_FORWARD = 0x00C0, "Frame Forward", UsageTypes.RTC FRAME_BACK = 0x00C1, "Frame Back", UsageTypes.RTC MARK = 0x00C2, "Mark", UsageTypes.OSC CLEAR_MARK = 0x00C3, "Clear Mark", UsageTypes.OSC REPEAT_FROM_MARK = 0x00C4, "Repeat From Mark", UsageTypes.OOC RETURN_TO_MARK = 0x00C5, "Return To Mark", UsageTypes.OSC SEARCH_MARK_FORWARD = 0x00C6, "Search Mark Forward", UsageTypes.OSC SEARCH_MARK_BACKWARDS = 0x00C7, "Search Mark Backwards", UsageTypes.OSC COUNTER_RESET = 0x00C8, "Counter Reset", UsageTypes.OSC SHOW_COUNTER = 0x00C9, "Show Counter", UsageTypes.OSC TRACKING_INCREMENT = 0x00CA, "Tracking Increment", UsageTypes.RTC TRACKING_DECREMENT = 0x00CB, "Tracking Decrement", UsageTypes.RTC STOP_EJECT = 0x00CC, "Stop/Eject", UsageTypes.OSC PLAY_PAUSE = 0x00CD, "Play/Pause", UsageTypes.OSC PLAY_SKIP = 0x00CE, "Play/Skip", UsageTypes.OSC VOLUME = 0x00E0, "Volume", UsageTypes.LC BALANCE = 0x00E1, "Balance", UsageTypes.LC MUTE = 0x00E2, "Mute", UsageTypes.OOC BASS = 0x00E3, "Bass", UsageTypes.LC TREBLE = 0x00E4, "Treble", UsageTypes.LC BASS_BOOST = 0x00E5, "Bass Boost", UsageTypes.OOC SURROUND_MODE = 0x00E6, "Surround Mode", UsageTypes.OSC LOUDNESS = 0x00E7, "Loudness", UsageTypes.OOC MPX = 0x00E8, "MPX", UsageTypes.OOC VOLUME_INCREMENT = 0x00E9, "Volume Increment", UsageTypes.RTC VOLUME_DECREMENT = 0x00EA, "Volume Decrement", UsageTypes.RTC SPEED_SELECT = 0x00F0, "Speed Select", UsageTypes.OSC PLAYBACK_SPEED = 0x00F1, "Playback Speed", UsageTypes.NARY STANDARD_PLAY = 0x00F2, "Standard Play", UsageTypes.SEL LONG_PLAY = 0x00F3, "Long Play", UsageTypes.SEL EXTENDED_PLAY = 0x00F4, "Extended Play", UsageTypes.SEL SLOW = 0x00F5, "Slow", UsageTypes.OSC FAN_ENABLE = 0x0100, "Fan Enable", UsageTypes.OOC FAN_SPEED = 0x0101, "Fan Speed", UsageTypes.LC LIGHT_ENABLE = 0x0102, "Light Enable", UsageTypes.OOC LIGHT_ILLUMINATION_LEVEL = 0x0103, "Light Illumination Level", UsageTypes.LC CLIMATE_CONTROL_ENABLE = 0x0104, "Climate Control Enable", UsageTypes.OOC ROOM_TEMPERATURE = 0x0105, "Room Temperature", UsageTypes.LC SECURITY_ENABLE = 0x0106, "Security Enable", UsageTypes.OOC FIRE_ALARM = 0x0107, "Fire Alarm", UsageTypes.OSC POLICE_ALARM = 0x0108, "Police Alarm", UsageTypes.OSC PROXIMITY = 0x0109, "Proximity", UsageTypes.LC MOTION = 0x010A, "Motion", UsageTypes.OSC DURESS_ALARM = 0x010B, "Duress Alarm", UsageTypes.OSC HOLDUP_ALARM = 0x010C, "Holdup Alarm", UsageTypes.OSC MEDICAL_ALARM = 0x010D, "Medical Alarm", UsageTypes.OSC BALANCE_RIGHT = 0x0150, "Balance Right", UsageTypes.RTC BALANCE_LEFT = 0x0151, "Balance Left", UsageTypes.RTC BASS_INCREMENT = 0x0152, "Bass Increment", UsageTypes.RTC BASS_DECREMENT = 0x0153, "Bass Decrement", UsageTypes.RTC TREBLE_INCREMENT = 0x0154, "Treble Increment", UsageTypes.RTC TREBLE_DECREMENT = 0x0155, "Treble Decrement", UsageTypes.RTC SPEAKER_SYSTEM = 0x0160, "Speaker System", UsageTypes.CL CHANNEL_LEFT = 0x0161, "Channel Left", UsageTypes.CL CHANNEL_RIGHT = 0x0162, "Channel Right", UsageTypes.CL CHANNEL_CENTER = 0x0163, "Channel Center", UsageTypes.CL CHANNEL_FRONT = 0x0164, "Channel Front", UsageTypes.CL CHANNEL_CENTER_FRONT = 0x0165, "Channel Center Front", UsageTypes.CL CHANNEL_SIDE = 0x0166, "Channel Side", UsageTypes.CL CHANNEL_SURROUND = 0x0167, "Channel Surround", UsageTypes.CL CHANNEL_LOW_FREQUENCY_ENHANCEMENT = 0x0168, "Channel Low Frequency Enhancement", UsageTypes.CL CHANNEL_TOP = 0x0169, "Channel Top", UsageTypes.CL CHANNEL_UNKNOWN = 0x016A, "Channel Unknown", UsageTypes.CL SUBCHANNEL = 0x0170, "Sub-channel", UsageTypes.LC SUBCHANNEL_INCREMENT = 0x0171, "Sub-channel Increment", UsageTypes.OSC SUBCHANNEL_DECREMENT = 0x0172, "Sub-channel Decrement", UsageTypes.OSC ALTERNATE_AUDIO_INCREMENT = 0x0173, "Alternate Audio Increment", UsageTypes.OSC ALTERNATE_AUDIO_DECREMENT = 0x0174, "Alternate Audio Decrement", UsageTypes.OSC APPLICATION_LAUNCH_BUTTONS = 0x0180, "Application Launch Buttons", UsageTypes.NARY AL_LAUCH_BUTTON_CONFIGURATION_TOOL = 0x0181, "AL Launch Button Configuration Tool", UsageTypes.SEL AL_PROGRAMMABLE_BUTTON_CONFIGURATION = 0x0182, "AL Programmable Button Configuration", UsageTypes.SEL AL_CONSUMER_CONTROL_CONFIGURATION = 0x0183, "AL Consumer Control Configuration", UsageTypes.SEL AL_WORD_PROCESSOR = 0x0184, "AL Word Processor", UsageTypes.SEL AL_TEXT_EDITOR = 0x0185, "AL Text Editor", UsageTypes.SEL AL_SPREADSHEET = 0x0186, "AL Spreadsheet", UsageTypes.SEL AL_GRAPHICS_EDITOR = 0x0187, "AL Graphics Editor", UsageTypes.SEL AL_PRESENTATION_APP = 0x0188, "AL Presentation App", UsageTypes.SEL AL_DATABASE_APP = 0x0189, "AL Database App", UsageTypes.SEL AL_EMAIL_READER = 0x018A, "AL Email Reader", UsageTypes.SEL AL_NEWSREADER = 0x018B, "AL Newsreader", UsageTypes.SEL AL_VOICEMAIL = 0x018C, "AL Voicemail", UsageTypes.SEL AL_CONTACTS_ADDRESS_BOOK = 0x018D, "AL Contacts/Address Book", UsageTypes.SEL AL_CALENDAR_SCHEDULE = 0x018E, "AL Calendar/Schedule", UsageTypes.SEL AL_TASK_PROJECT_MANAGER = 0x018F, "AL Task/Project Manager", UsageTypes.SEL AL_LOG_JOURNAL_TIMECARD = 0x0190, "AL Log/Journal/Timecard", UsageTypes.SEL AL_CHECKBOOK_FINANCE = 0x0191, "AL Checkbook/Finance", UsageTypes.SEL AL_CALCULATOR = 0x0192, "AL Calculator", UsageTypes.SEL AL_AV_CAPTURE_PLAYBACK = 0x0193, "AL A/V Capture/Playback", UsageTypes.SEL AL_LOCAL_MACHINE_BROWSER = 0x0194, "AL Local Machine Browser", UsageTypes.SEL AL_LAN_WAN_BROWSER = 0x0195, "AL LAN/WAN Browser", UsageTypes.SEL AL_INTERNET_BROWSER = 0x0196, "AL Internet Browser", UsageTypes.SEL AL_REMOTE_NETWORKING_ISP_CONNECT = 0x0197, "AL Remote Networking/ISP Connect", UsageTypes.SEL AL_NETWORK_CONFERENCE = 0x0198, "AL Network Conference", UsageTypes.SEL AL_NETWORK_CHAT = 0x0199, "AL Network Chat", UsageTypes.SEL AL_TELEPHONY_DIALER = 0x019A, "AL Telephony/Dialer", UsageTypes.SEL AL_LOGON = 0x019B, "AL Logon", UsageTypes.SEL AL_LOGOFF = 0x019C, "AL Logoff", UsageTypes.SEL AL_LOGON_LOGOFF = 0x019D, "AL Logon/Logoff", UsageTypes.SEL AL_LOCK_SCREEN_SAVER = 0x019E, "AL Terminal Lock/Screensaver", UsageTypes.SEL AL_CONTROL_PANEL = 0x019F, "AL Control Panel", UsageTypes.SEL AL_COMMAND_LINE_PROCESSOR_RUN = 0x01A0, "AL Command Line Processor/Run", UsageTypes.SEL AL_PROCESS_TASK_MANAGER = 0x01A1, "AL Process/Task Manager", UsageTypes.SEL AL_SELECT_TASK_APPLICATION = 0x01A2, "AL Select Task/Application", UsageTypes.SEL AL_NEXT_TASK_APPLICATION = 0x01A3, "AL Next Task/Application", UsageTypes.SEL AL_PREVIOUS_TASK_APPLICATION = 0x01A4, "AL Previous Task/Application", UsageTypes.SEL AL_HALT_TASK_APPLICATION = 0x01A5, "AL Preemptive Halt Task/Application", UsageTypes.SEL AL_INTEGRATED_HELP_CENTER = 0x01A6, "AL Integrated Help Center", UsageTypes.SEL AL_DOCUMENTS = 0x01A7, "AL Documents", UsageTypes.SEL AL_THESAURUS = 0x01A8, "AL Thesaurus", UsageTypes.SEL AL_DICTIONARY = 0x01A9, "AL Dictionary", UsageTypes.SEL AL_DESKTOP = 0x01AA, "AL Desktop", UsageTypes.SEL AL_SPELL_CHECK = 0x01AB, "AL Spell Check", UsageTypes.SEL AL_GRAMMAR_CHECK = 0x01AC, "AL Grammar Check", UsageTypes.SEL AL_WIRELESS_STATUS = 0x01AD, "AL Wireless Status", UsageTypes.SEL AL_KEYBOARD_LAYOUT = 0x01AE, "AL Keyboard Layout", UsageTypes.SEL AL_VIRUS_PROTECTION = 0x01AF, "AL Virus Protection", UsageTypes.SEL AL_ENCRYPTION = 0x01B0, "AL Encryption", UsageTypes.SEL AL_SCREEN_SAVER = 0x01B1, "AL Screen Saver", UsageTypes.SEL AL_ALARMS = 0x01B2, "AL Alarms", UsageTypes.SEL AL_CLOCK = 0x01B3, "AL Clock", UsageTypes.SEL AL_FILE_BROWSER = 0x01B4, "AL File Browser", UsageTypes.SEL AL_POWER_STATUS = 0x01B5, "AL Power Status", UsageTypes.SEL AL_IMAGE_BROWSER = 0x01B6, "AL Image Browser", UsageTypes.SEL AL_AUDIO_BROWSER = 0x01B7, "AL Audio Browser", UsageTypes.SEL AL_VIDEO_BROWSER = 0x01B8, "AL Movie Browser", UsageTypes.SEL AL_DIGITAL_RIGHTS_MANAGER = 0x01B9, "AL Digital Rights Manager", UsageTypes.SEL AL_DIGITAL_WALLET = 0x01BA, "AL Digital Wallet", UsageTypes.SEL AL_INSTANT_MESSAGING = 0x01BC, "AL Instant Messaging", UsageTypes.SEL AL_OEM_FEATURES_TIPS_TUTORIAL_BROWSER = 0x01BD, "AL OEM Features/ Tips/Tutorial Browser", UsageTypes.SEL AL_OEM_HELP = 0x01BE, "AL OEM Help", UsageTypes.SEL AL_ONLINE_COMMUNITY = 0x01BF, "AL Online Community", UsageTypes.SEL AL_ENTERTAINMENT_CONTENT_BROWSER = 0x01C0, "AL Entertainment Content Browser", UsageTypes.SEL AL_ONLINE_SHOPPING_BROWSER = 0x01C1, "AL Online Shopping Browser", UsageTypes.SEL AL_SMARTCARD_INFORMATION_HELP = 0x01C2, "AL SmartCard Information/Help", UsageTypes.SEL AL_MARKET_MONITOR_FINANCE_BROWSER = 0x01C3, "AL Market Monitor/Finance Browser", UsageTypes.SEL AL_CUSTOMIZED_CORPORATE_NEWS_BROWSER = 0x01C4, "AL Customized Corporate News Browser", UsageTypes.SEL AL_ONLINE_ACTIVITY_BROWSER = 0x01C5, "AL Online Activity Browser", UsageTypes.SEL AL_RESEARCH_SEARCH_BROWSER = 0x01C6, "AL Research/Search Browser", UsageTypes.SEL AL_AUDIO_PLAYER = 0x01C7, "AL Audio Player", UsageTypes.SEL GENERIC_GUI_APPLICATION_CONTROLS = 0x0200, "Generic GUI Application Controls", UsageTypes.NARY AC_NEW = 0x0201, "AC New", UsageTypes.SEL AC_OPEN = 0x0202, "AC Open", UsageTypes.SEL AC_CLOSE = 0x0203, "AC Close", UsageTypes.SEL AC_EXIT = 0x0204, "AC Exit", UsageTypes.SEL AC_MAXIMIZE = 0x0205, "AC Maximize", UsageTypes.SEL AC_MINIMIZE = 0x0206, "AC Minimize", UsageTypes.SEL AC_SAVE = 0x0207, "AC Save", UsageTypes.SEL AC_PRINT = 0x0208, "AC Print", UsageTypes.SEL AC_PROPERTIES = 0x0209, "AC Properties", UsageTypes.SEL AC_UNDO = 0x021A, "AC Undo", UsageTypes.SEL AC_COPY = 0x021B, "AC Copy", UsageTypes.SEL AC_CUT = 0x021C, "AC Cut", UsageTypes.SEL AC_PASTE = 0x021D, "AC Paste", UsageTypes.SEL AC_SELECT_ALL = 0x021E, "AC Select All", UsageTypes.SEL AC_FIND = 0x021F, "AC Find", UsageTypes.SEL AC_FIND_AND_REPLACE = 0x0220, "AC Find and Replace", UsageTypes.SEL AC_SEARCH = 0x0221, "AC Search", UsageTypes.SEL AC_GO_TO = 0x0222, "AC Go To", UsageTypes.SEL AC_HOME = 0x0223, "AC Home", UsageTypes.SEL AC_BACK = 0x0224, "AC Back", UsageTypes.SEL AC_FORWARD = 0x0225, "AC Forward", UsageTypes.SEL AC_STOP = 0x0226, "AC Stop", UsageTypes.SEL AC_REFRESH = 0x0227, "AC Refresh", UsageTypes.SEL AC_PREVIOUS_LINK = 0x0228, "AC Previous Link", UsageTypes.SEL AC_NEXT_LINK = 0x0229, "AC Next Link", UsageTypes.SEL AC_BOOKMARKS = 0x022A, "AC Bookmarks", UsageTypes.SEL AC_HISTORY = 0x022B, "AC History", UsageTypes.SEL AC_SUBSCRIPTIONS = 0x022C, "AC Subscriptions", UsageTypes.SEL AC_ZOOM_IN = 0x022D, "AC Zoom In", UsageTypes.SEL AC_ZOOM_OUT = 0x022E, "AC Zoom Out", UsageTypes.SEL AC_ZOOM = 0x022F, "AC Zoom", UsageTypes.LC AC_FULL_SCREEN_VIEW = 0x0230, "AC Full Screen View", UsageTypes.SEL AC_NORMAL_VIEW = 0x0231, "AC Normal View", UsageTypes.SEL AC_VIEW_TOGGLE = 0x0232, "AC View Toggle", UsageTypes.SEL AC_SCROLL_UP = 0x0233, "AC Scroll Up", UsageTypes.SEL AC_SCROLL_DOWN = 0x0234, "AC Scroll Down", UsageTypes.SEL AC_SCROLL = 0x0235, "AC Scroll", UsageTypes.LC AC_PAN_LEFT = 0x0236, "AC Pan Left", UsageTypes.SEL AC_PAN_RIGHT = 0x0237, "AC Pan Right", UsageTypes.SEL AC_PAN = 0x0238, "AC Pan", UsageTypes.LC AC_NEW_WINDOWS = 0x0239, "AC New Window", UsageTypes.SEL AC_TILE_HORIZONTALLY = 0x023A, "AC Tile Horizontally", UsageTypes.SEL AC_TILE_VERTICALLY = 0x023B, "AC Tile Vertically", UsageTypes.SEL AC_FORMAT = 0x023C, "AC Format", UsageTypes.SEL AC_EDIT = 0x023D, "AC Edit", UsageTypes.SEL AC_BOLD = 0x023E, "AC Bold", UsageTypes.SEL AC_ITALICS = 0x023F, "AC Italics", UsageTypes.SEL AC_UNDERLINE = 0x0240, "AC Underline", UsageTypes.SEL AC_STRIKETHROUGH = 0x0241, "AC Strikethrough", UsageTypes.SEL AC_SUBSCRIPT = 0x0242, "AC Subscript", UsageTypes.SEL AC_SUPERSCRIPT = 0x0243, "AC Superscript", UsageTypes.SEL AC_ALL_CAPS = 0x0244, "AC All Caps", UsageTypes.SEL AC_ROTATE = 0x0245, "AC Rotate", UsageTypes.SEL AC_RESIZE = 0x0246, "AC Resize", UsageTypes.SEL AC_FLIP_HORIZONTAL = 0x0247, "AC Flip horizontal", UsageTypes.SEL AC_FLIP_VERTICAL = 0x0248, "AC Flip Vertical", UsageTypes.SEL AC_MIRROR_HORIZONTAL = 0x0249, "AC Mirror Horizontal", UsageTypes.SEL AC_MIRROR_VERTICAL = 0x024A, "AC Mirror Vertical", UsageTypes.SEL AC_FONT_SELECT = 0x024B, "AC Font Select", UsageTypes.SEL AC_FONT_COLOR = 0x024C, "AC Font Color", UsageTypes.SEL AC_FONT_SIZE = 0x024D, "AC Font Size", UsageTypes.SEL AC_JUSTIFY_LEFT = 0x024E, "AC Justify Left", UsageTypes.SEL AC_JUSTIFY_CENTER_H = 0x024F, "AC Justify Center H", UsageTypes.SEL AC_JUSTIFY_RIGHT = 0x0250, "AC Justify Right", UsageTypes.SEL AC_JUSTIFY_BLOCK_H = 0x0251, "AC Justify Block H", UsageTypes.SEL AC_JUSTIFY_TOP = 0x0252, "AC Justify Top", UsageTypes.SEL AC_JUSTIFY_CENTER_V = 0x0253, "AC Justify Center V", UsageTypes.SEL AC_JUSTIFY_BOTTOM = 0x0254, "AC Justify Bottom", UsageTypes.SEL AC_JUSTIFY_BLOCK_V = 0x0255, "AC Justify Block V", UsageTypes.SEL AC_INDENT_INCREASE = 0x0256, "AC Indent Decrease", UsageTypes.SEL AC_INDENT_DECREASE = 0x0257, "AC Indent Increase", UsageTypes.SEL AC_NUMBERED_LIST = 0x0258, "AC Numbered List", UsageTypes.SEL AC_RESTART_NUMBERING = 0x0259, "AC Restart Numbering", UsageTypes.SEL AC_BULLETED_LIST = 0x025A, "AC Bulleted List", UsageTypes.SEL AC_PROMOTE = 0x025B, "AC Promote", UsageTypes.SEL AC_DEMOTE = 0x025C, "AC Demote", UsageTypes.SEL AC_YES = 0x025D, "AC Yes", UsageTypes.SEL AC_NO = 0x025E, "AC No", UsageTypes.SEL AC_CANCEL = 0x025F, "AC Cancel", UsageTypes.SEL AC_CATALOG = 0x0260, "AC Catalog", UsageTypes.SEL AC_BUY_CHECKOUT = 0x0261, "AC Buy/Checkout", UsageTypes.SEL AC_ADD_TO_CART = 0x0262, "AC Add to Cart", UsageTypes.SEL AC_EXPAND = 0x0263, "AC Expand", UsageTypes.SEL AC_EXPAND_ALL = 0x0264, "AC Expand All", UsageTypes.SEL AC_COLLAPSE = 0x0265, "AC Collapse", UsageTypes.SEL AC_COLLAPSE_ALL = 0x0266, "AC Collapse All", UsageTypes.SEL AC_PRINT_PREVIEW = 0x0267, "AC Print Preview", UsageTypes.SEL AC_PASTE_SPECIAL = 0x0268, "AC Paste Special", UsageTypes.SEL AC_INSER_MODE = 0x0269, "AC Insert Mode", UsageTypes.SEL AC_DELETE = 0x026A, "AC Delete", UsageTypes.SEL AC_LOCK = 0x026B, "AC Lock", UsageTypes.SEL AC_UNLOCK = 0x026C, "AC Unlock", UsageTypes.SEL AC_PROTECT = 0x026D, "AC Protect", UsageTypes.SEL AC_UNPROTECT = 0x026E, "AC Unprotect", UsageTypes.SEL AC_ATTACH_COMMENT = 0x026F, "AC Attach Comment", UsageTypes.SEL AC_DELETE_COMMENT = 0x0270, "AC Delete Comment", UsageTypes.SEL AC_VIEW_COMMENT = 0x0271, "AC View Comment", UsageTypes.SEL AC_SELECT_WORD = 0x0272, "AC Select Word", UsageTypes.SEL AC_SELECT_SENTENCE = 0x0273, "AC Select Sentence", UsageTypes.SEL AC_SELECT_PARAGRAPH = 0x0274, "AC Select Paragraph", UsageTypes.SEL AC_SELECT_COLUMN = 0x0275, "AC Select Column", UsageTypes.SEL AC_SELECT_ROW = 0x0276, "AC Select Row", UsageTypes.SEL AC_SELECT_TABLE = 0x0277, "AC Select Table", UsageTypes.SEL AC_SELECT_OBJECT = 0x0278, "AC Select Object", UsageTypes.SEL AC_REDO_REPEAT = 0x0279, "AC Redo/Repeat", UsageTypes.SEL AC_SORT = 0x027A, "AC Sort", UsageTypes.SEL AC_SORT_ASCENDING = 0x027B, "AC Sort Ascending", UsageTypes.SEL AC_SORT_DESCENDING = 0x027C, "AC Sort Descending", UsageTypes.SEL AC_FILTER = 0x027D, "AC Filter", UsageTypes.SEL AC_SET_CLOCK = 0x027E, "AC Set Clock", UsageTypes.SEL AC_VIEW_CLOCK = 0x027F, "AC View Clock", UsageTypes.SEL AC_SELECT_TIME_ZONE = 0x0280, "AC Select Time Zone", UsageTypes.SEL AC_EDIT_TIME_ZONES = 0x0281, "AC Edit Time Zones", UsageTypes.SEL AC_SET_ALARM = 0x0282, "AC Set Alarm", UsageTypes.SEL AC_CLEAR_ALARM = 0x0283, "AC Clear Alarm", UsageTypes.SEL AC_SNOOZE_ALARM = 0x0284, "AC Snooze Alarm", UsageTypes.SEL AC_RESET_ALARM = 0x0285, "AC Reset Alarm", UsageTypes.SEL AC_SYNCHRONIZE = 0x0286, "AC Synchronize", UsageTypes.SEL AC_SEND_RECEIVE = 0x0287, "AC Send/Receive", UsageTypes.SEL AC_SEND_TO = 0x0288, "AC Send To", UsageTypes.SEL AC_REPLY = 0x0289, "AC Reply", UsageTypes.SEL AC_REPLY_ALL = 0x028A, "AC Reply All", UsageTypes.SEL AC_FORWARD_MSG = 0x028B, "AC Forward Msg", UsageTypes.SEL AC_SEND = 0x028C, "AC Send", UsageTypes.SEL AC_ATTACH_FILE = 0x028D, "AC Attach File", UsageTypes.SEL AC_UPLOAD = 0x028E, "AC Upload", UsageTypes.SEL AC_DOWNLOAD = 0x028F, "AC Download (Save Target As)", UsageTypes.SEL AC_SET_BORDERS = 0x0290, "AC Set Borders", UsageTypes.SEL AC_INSERT_ROW = 0x0291, "AC Insert Row", UsageTypes.SEL AC_INSERT_COLUMN = 0x0292, "AC Insert Column", UsageTypes.SEL AC_INSERT_FILE = 0x0293, "AC Insert File", UsageTypes.SEL AC_INSERT_PICTURE = 0x0294, "AC Insert Picture", UsageTypes.SEL AC_INSERT_OBJECT = 0x0295, "AC Insert Object", UsageTypes.SEL AC_INSERT_SYMBOL = 0x0296, "AC Insert Symbol", UsageTypes.SEL AC_SAVE_AND_CLOSE = 0x0297, "AC Save and Close", UsageTypes.SEL AC_RENAME = 0x0298, "AC Rename", UsageTypes.SEL AC_MERGE = 0x0299, "AC Merge", UsageTypes.SEL AC_SPLIT = 0x029A, "AC Split", UsageTypes.SEL AC_DISTRIBUTE_HORIZONTICALLY = 0x029B, "AC Disribute Horizontally", UsageTypes.SEL AC_DISTRIBUTE_VERTICALLY = 0x029C, "AC Distribute Vertically", UsageTypes.SEL class PowerDevice(_Data): INAME = 0x01, "iName", UsageTypes.SV PRESENT_STATUS = 0x02, "PresentStatus", UsageTypes.CL CHARGED_STATUS = 0x03, "ChangedStatus", UsageTypes.CL UPS = 0x04, "UPS", UsageTypes.CA POWER_SUPPLY = 0x05, "PowerSupply", UsageTypes.CA BATTERY_SYSTEM = 0x10, "BatterySystem", UsageTypes.CP BATTERY_SYSTEM_ID = 0x11, "BatterySystemID", UsageTypes.SV BATTERY = 0x12, "Battery", UsageTypes.CP BATTERY_ID = 0x13, "BatteryID", UsageTypes.SV CHARGER = 0x14, "Charger", UsageTypes.CP CHARGER_ID = 0x15, "ChargerID", UsageTypes.SV POWER_CONVERTER = 0x16, "PowerConverter", UsageTypes.CP POWER_CONVERTER_ID = 0x17, "PowerConverterID", UsageTypes.SV OUTLET_SYSTEM = 0x18, "OutletSystem", UsageTypes.CP OUTLET_SYSTEM_ID = 0x19, "OutletSystemID", UsageTypes.SV INPUT = 0x1A, "Input", UsageTypes.CP INPUT_ID = 0x1B, "InputID", UsageTypes.SV OUTPUT = 0x1C, "Output", UsageTypes.CP OUTPUT_ID = 0x1D, "OutputID", UsageTypes.SV FLOW = 0x1E, "Flow", UsageTypes.CP FLOW_ID = 0x1F, "FlowID", UsageTypes.SV OUTLET = 0x20, "Outlet", UsageTypes.CP OUTLET_ID = 0x21, "OutletID", UsageTypes.SV GANG = 0x22, "Gang", UsageTypes.CP GANG_ID = 0x23, "GangID", UsageTypes.SV POWER_SUMMARY = 0x24, "PowerSummary", UsageTypes.CP POWER_SUMMARY_ID = 0x25, "PowerSummaryID", UsageTypes.SV VOLTAGE = 0x30, "Voltage", UsageTypes.DV CURRENT = 0x31, "Current", UsageTypes.DV FREQUENCY = 0x32, "Frequency", UsageTypes.DV APPARENT_POWER = 0x33, "ApparentPower", UsageTypes.DV ACTIVE_POWER = 0x34, "ActivePower", UsageTypes.DV PERCENT_LOAD = 0x35, "PercentLoad", UsageTypes.DV TEMPERATURE = 0x36, "Temperature", UsageTypes.DV HUMIFITY = 0x37, "Humidity", UsageTypes.DV BAD_COUNT = 0x38, "BadCount", UsageTypes.DV CONFIG_VOLTAGE = 0x40, "ConfigVoltage", (UsageTypes.SV, UsageTypes.DV) CONFIG_CURRENT = 0x41, "ConfigCurrent", (UsageTypes.SV, UsageTypes.DV) CONFIG_FREQUENCY = 0x42, "ConfigFrequency", (UsageTypes.SV, UsageTypes.DV) CONFIG_APPARENT_POWER = 0x43, "ConfigApparentPower", (UsageTypes.SV, UsageTypes.DV) CONFIG_ACTIVE_POWER = 0x44, "ConfigActivePower", (UsageTypes.SV, UsageTypes.DV) CONFIG_PERCENT_LOAD = 0x45, "ConfigPercentLoad", (UsageTypes.SV, UsageTypes.DV) CONFIG_TEMPERATURE = 0x46, "ConfigTemperature", (UsageTypes.SV, UsageTypes.DV) CONFIG_HUMIFITY = 0x47, "ConfigHumidity", (UsageTypes.SV, UsageTypes.DV) SWITCH_ON_CONTROL = 0x50, "SwitchOnControl", UsageTypes.DV SWITCH_OFF_CONTROL = 0x51, "SwitchOffControl", UsageTypes.DV TOGGLE_CONTROL = 0x52, "ToggleControl", UsageTypes.DV LOW_VOLTAGE_TRANSFER = 0x53, "LowVoltageTransfer", UsageTypes.DV HIGH_VOLTAGE_TRANSFER = 0x54, "HighVoltageTransfer", UsageTypes.DV DELAY_BEFORE_REBOOT = 0x55, "DelayBeforeReboot", UsageTypes.DV DELAY_BEFORE_STARTUP = 0x56, "DelayBeforeStartup", UsageTypes.DV DELAY_BEFORE_SHUTDOWN = 0x57, "DelayBeforeShutdown", UsageTypes.DV TEST = 0x58, "Test", UsageTypes.DV MODULE_RESET = 0x59, "ModuleReset", UsageTypes.DV AUDIBLE_ALARM_CONTROL = 0x5A, "AudibleAlarmControl", UsageTypes.DV PRESENT = 0x60, "Present", UsageTypes.DF GOOD = 0x61, "Good", UsageTypes.DF INTERNAL_FAILURE = 0x62, "InternalFailure", UsageTypes.DF VOLTAGE_OUT_OF_RANGE = 0x63, "VoltageOutOfRange", UsageTypes.DF FREQUENCY_OUT_OF_RANGE = 0x64, "FrequencyOutOfRange", UsageTypes.DF OVERLOAD = 0x65, "Overload", UsageTypes.DF OVERCHARGED = 0x66, "OverCharged", UsageTypes.DF OVER_TEMPERATURE = 0x67, "OverTemperature", UsageTypes.DF SHUTDOWN_REQUESTED = 0x68, "ShutdownRequested", UsageTypes.DF SHUTDOWN_IMMINEBT = 0x69, "ShutdownImminent", UsageTypes.DF SWITCH_ON_OFF = 0x6B, "SwitchOn/Off", UsageTypes.DF SWITCHABLE = 0x6C, "Switchable", UsageTypes.DF USED = 0x6D, "Used", UsageTypes.DF BOOST = 0x6E, "Boost", UsageTypes.DF BUCK = 0x6F, "Buck", UsageTypes.DF INITIALIZED = 0x70, "Initialized", UsageTypes.DF TESTED = 0x71, "Tested", UsageTypes.DF AWAITING_POWER = 0x72, "AwaitingPower", UsageTypes.DF COMMUNICATION_LOST = 0x73, "CommunicationLost", UsageTypes.DF IMANUFACTURER = 0xFD, "iManufacturer", UsageTypes.SV IPRODUCT = 0xFE, "iProduct", UsageTypes.SV ISERIALNUMBER = 0xFF, "iSerialNumber", UsageTypes.SV class FIDO(_Data): U2F_AUTHENTICATOR_DEVICEM = 0x01, "U2F Authenticator Device" INPUT_REPORT_DATA = 0x20, "Input Report Data" OUTPUT_REPORT_DATA = 0x21, "Output Report Data" class UsagePages(_Data): GENERIC_DESKTOP_CONTROLS_PAGE = 0x01, "Generic Desktop Controls", GenericDesktopControls SIMULATION_CONTROLS_PAGE = 0x02, "Simulation Controls" VR_CONTROLS_PAGE = 0x03, "VR Controls" SPORT_CONTROLS_PAGE = 0x04, "Sport Controls" GAME_CONTROLS_PAGE = 0x05, "Game Controls" GENERIC_DEVICE_CONTROLS_PAGE = 0x06, "Generic Device Controls" KEYBOARD_KEYPAD_PAGE = 0x07, "Keyboard/Keypad", KeyboardKeypad LED_PAGE = 0x08, "LED", Led BUTTON_PAGE = 0x09, "Button", Button ORDINAL_PAGE = 0x0A, "Ordinal" TELEPHONY_PAGE = 0x0B, "Telephony" CONSUMER_PAGE = 0x0C, "Consumer", Consumer DIGITIZER_PAGE = 0x0D, "Digitizer" HAPTICS_PAGE = 0x0E, "Haptics" PID_PAGE = 0x0F, "PID" UNICODE_PAGE = 0x10, "Unicode" EYE_AND_HEAD_TRACKER_PAGE = 0x12, "Eye and Head Tracker" ALPHANUMERIC_DISPLAY_PAGE = 0x14, "Alphanumeric Display" SENSOR_PAGE = 0x20, "Sensor" MEDICAL_INSTRUMENTS_PAGE = 0x40, "Medical Instruments" BRAILLE_DISPLAY_PAGE = 0x41, "Braillie" LIGHTING_AND_ILLUMINATION_PAGE = 0x59, "Lighting and Illumination" USB_MONITOR_PAGE = 0x80, "USB Monitor" USB_ENUMERATED_VALUES_PAGE = 0x81, "USB Enumerated Values" VESA_VIRTUAL_CONTROLS_PAGE = 0x82, "VESA Virtual Controls" POWER_DEVICE_PAGE = 0x84, "Power Device", PowerDevice BATTERY_SYSTEM_PAGE = 0x85, "Battery System" BARCODE_SCANNER_PAGE = 0x8C, "Barcode Scanner" WEIGHING_PAGE = 0x8D, "Weighing" MSR_PAGE = 0x8E, "MSR" RESERVED_POS_PAGE = 0x8F, "Reserved POS" CAMERA_CONTROL_PAGE = 0x90, "Camera Control" ARCADE_PAGE = 0x91, "Arcade" GAMING_DEVICE_PAGE = 0x92, "Gaming Device" FIDO_ALLIANCE_PAGE = 0xF1D0, "FIDO Alliance", FIDO VENDOR_PAGE = 0xFF00, ..., 0xFFFF, "Vendor Page" Solaar-1.1.20/lib/hidapi/000077500000000000000000000000001522022367600150255ustar00rootroot00000000000000Solaar-1.1.20/lib/hidapi/__init__.py000066400000000000000000000000001522022367600171240ustar00rootroot00000000000000Solaar-1.1.20/lib/hidapi/common.py000066400000000000000000000007701522022367600166730ustar00rootroot00000000000000from __future__ import annotations import dataclasses @dataclasses.dataclass class DeviceInfo: path: str bus_id: str | None vendor_id: str product_id: str interface: str | None driver: str | None manufacturer: str | None product: str | None serial: str | None release: str | None isDevice: bool hidpp_short: str | None hidpp_long: str | None centurion: bool = False centurion_report_id: int | None = None # 0x50 or 0x51 when centurion=True Solaar-1.1.20/lib/hidapi/hidapi_impl.py000066400000000000000000000451431522022367600176650ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Generic Human Interface Device API. This provides a python interface to libusb's hidapi library which, unlike udev, is available for non-linux platforms. See https://github.com/libusb/hidapi for how to obtain binaries. Parts of this code are adapted from https://github.com/apmorton/pyhidapi which is MIT licensed. """ from __future__ import annotations import atexit import ctypes import logging import platform import typing from threading import Thread from time import sleep from typing import Any from typing import Callable from hidapi.common import DeviceInfo LOGITECH_VENDOR_ID = 0x046D if typing.TYPE_CHECKING: import gi gi.require_version("Gdk", "3.0") from gi.repository import GLib # NOQA: E402 logger = logging.getLogger(__name__) ACTION_ADD = "add" ACTION_REMOVE = "remove" # Global handle to hidapi _hidapi = None # hidapi binary names for various platforms _library_paths = ( "libhidapi-hidraw.so", "libhidapi-hidraw.so.0", "libhidapi-libusb.so", "libhidapi-libusb.so.0", "libhidapi-iohidmanager.so", "libhidapi-iohidmanager.so.0", "libhidapi.dylib", "hidapi.dll", "libhidapi-0.dll", ) for lib in _library_paths: try: _hidapi = ctypes.cdll.LoadLibrary(lib) break except OSError: pass else: raise ImportError(f"Unable to load hidapi library, tried: {' '.join(_library_paths)}") # Retrieve version of hdiapi library class _cHidApiVersion(ctypes.Structure): _fields_ = [ ("major", ctypes.c_int), ("minor", ctypes.c_int), ("patch", ctypes.c_int), ] _hidapi.hid_version.argtypes = [] _hidapi.hid_version.restype = ctypes.POINTER(_cHidApiVersion) _hid_version = _hidapi.hid_version() # Construct device info struct based on API version class _cDeviceInfo(ctypes.Structure): def as_dict(self): return {name: getattr(self, name) for name, _t in self._fields_ if name != "next"} # Low level hdiapi device info struct # See https://github.com/libusb/hidapi/blob/master/hidapi/hidapi.h#L143 _cDeviceInfo_fields = [ ("path", ctypes.c_char_p), ("vendor_id", ctypes.c_ushort), ("product_id", ctypes.c_ushort), ("serial_number", ctypes.c_wchar_p), ("release_number", ctypes.c_ushort), ("manufacturer_string", ctypes.c_wchar_p), ("product_string", ctypes.c_wchar_p), ("usage_page", ctypes.c_ushort), ("usage", ctypes.c_ushort), ("interface_number", ctypes.c_int), ("next", ctypes.POINTER(_cDeviceInfo)), ] if _hid_version.contents.major >= 0 and _hid_version.contents.minor >= 13: _cDeviceInfo_fields.append(("bus_type", ctypes.c_int)) _cDeviceInfo._fields_ = _cDeviceInfo_fields # Set up hidapi functions _hidapi.hid_init.argtypes = [] _hidapi.hid_init.restype = ctypes.c_int _hidapi.hid_exit.argtypes = [] _hidapi.hid_exit.restype = ctypes.c_int _hidapi.hid_enumerate.argtypes = [ctypes.c_ushort, ctypes.c_ushort] _hidapi.hid_enumerate.restype = ctypes.POINTER(_cDeviceInfo) _hidapi.hid_free_enumeration.argtypes = [ctypes.POINTER(_cDeviceInfo)] _hidapi.hid_free_enumeration.restype = None _hidapi.hid_open.argtypes = [ctypes.c_ushort, ctypes.c_ushort, ctypes.c_wchar_p] _hidapi.hid_open.restype = ctypes.c_void_p _hidapi.hid_open_path.argtypes = [ctypes.c_char_p] _hidapi.hid_open_path.restype = ctypes.c_void_p _hidapi.hid_write.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t] _hidapi.hid_write.restype = ctypes.c_int _hidapi.hid_read_timeout.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t, ctypes.c_int] _hidapi.hid_read_timeout.restype = ctypes.c_int _hidapi.hid_read.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t] _hidapi.hid_read.restype = ctypes.c_int _hidapi.hid_get_input_report.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t] _hidapi.hid_get_input_report.restype = ctypes.c_int _hidapi.hid_set_nonblocking.argtypes = [ctypes.c_void_p, ctypes.c_int] _hidapi.hid_set_nonblocking.restype = ctypes.c_int _hidapi.hid_send_feature_report.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int] _hidapi.hid_send_feature_report.restype = ctypes.c_int _hidapi.hid_get_feature_report.argtypes = [ctypes.c_void_p, ctypes.c_char_p, ctypes.c_size_t] _hidapi.hid_get_feature_report.restype = ctypes.c_int _hidapi.hid_close.argtypes = [ctypes.c_void_p] _hidapi.hid_close.restype = None _hidapi.hid_get_manufacturer_string.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t] _hidapi.hid_get_manufacturer_string.restype = ctypes.c_int _hidapi.hid_get_product_string.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t] _hidapi.hid_get_product_string.restype = ctypes.c_int _hidapi.hid_get_serial_number_string.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_size_t] _hidapi.hid_get_serial_number_string.restype = ctypes.c_int _hidapi.hid_get_indexed_string.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_wchar_p, ctypes.c_size_t] _hidapi.hid_get_indexed_string.restype = ctypes.c_int _hidapi.hid_error.argtypes = [ctypes.c_void_p] _hidapi.hid_error.restype = ctypes.c_wchar_p # Initialize hidapi _hidapi.hid_init() atexit.register(_hidapi.hid_exit) # Solaar opens the same device more than once which will fail unless we # allow non-exclusive opening. On windows opening with shared access is # the default, for macOS we need to set it explicitly. if platform.system() == "Darwin": _hidapi.hid_darwin_set_open_exclusive.argtypes = [ctypes.c_int] _hidapi.hid_darwin_set_open_exclusive.restype = None _hidapi.hid_darwin_set_open_exclusive(0) class HIDError(Exception): pass def _enumerate_devices(): """Returns all HID devices which are potentially useful to us""" devices = [] c_devices = _hidapi.hid_enumerate(0, 0) p = c_devices while p: devices.append(p.contents.as_dict()) p = p.contents.next _hidapi.hid_free_enumeration(c_devices) unique_devices = {} for device in devices: # hidapi returns separate entries for each usage page of a device. # Deduplicate by path to only keep one device entry. if device["path"] not in unique_devices: unique_devices[device["path"]] = device unique_devices = unique_devices.values() # print("Unique devices:\n" + '\n'.join([f"{dev}" for dev in unique_devices])) return unique_devices # Use a separate thread to check if devices have been removed or connected class _DeviceMonitor(Thread): def __init__(self, device_callback, polling_delay=5.0): self.device_callback = device_callback self.polling_delay = polling_delay self.prev_devices = None # daemon threads are automatically killed when main thread exits super().__init__(daemon=True) def run(self): # Populate initial set of devices so startup doesn't cause any callbacks self.prev_devices = {tuple(dev.items()): dev for dev in _enumerate_devices()} # Continously enumerate devices and raise callback for changes while True: current_devices = {tuple(dev.items()): dev for dev in _enumerate_devices()} for key, device in self.prev_devices.items(): if key not in current_devices: self.device_callback(ACTION_REMOVE, device) for key, device in current_devices.items(): if key not in self.prev_devices: self.device_callback(ACTION_ADD, device) self.prev_devices = current_devices sleep(self.polling_delay) def _match( action: str, device: dict[str, Any], filter_func: Callable[[int, int, int, bool, bool], dict[str, Any]], ): """ The filter_func is used to determine whether this is a device of interest to Solaar. It is given the bus id, vendor id, and product id and returns a dictionary with the required hid_driver and usb_interface and whether this is a receiver or device. """ vid = device["vendor_id"] pid = device["product_id"] hid_bus_type = device["bus_type"] # Translate hidapi bus_type to the bus_id values Solaar expects if device.get("bus_type") == 0x01: bus_id = 0x03 # USB elif device.get("bus_type") == 0x02: bus_id = 0x05 # Bluetooth else: bus_id = None logger.info(f"Device {device['path']} has an unsupported bus type {hid_bus_type:02X}") return None # Skip unlikely devices with all-zero VID PID or unsupported bus IDs if vid == 0 and pid == 0: logger.info(f"Device {device['path']} has all-zero VID and PID") logger.info(f"Skipping unlikely device {device['path']} ({bus_id}/{vid:04X}/{pid:04X})") return None # Skip Logitech webcams to prevent them from locking up during hidpp checks # (product IDs range for webcams from docs/usb.ids.txt) if vid == LOGITECH_VENDOR_ID and 0x0800 <= pid <= 0x09FF: logger.info(f"Skipping Logitech webcam {device['path']} ({bus_id}/{vid:04X}/{pid:04X})") return None # Check for hidpp support device["hidpp_short"] = False device["hidpp_long"] = False device_handle = None def check_hidpp_short(): report = _get_input_report(device_handle, 0x10, 32) if len(report) == 1 + 6 and report[0] == 0x10: device["hidpp_short"] = True def check_hidpp_long(): report = _get_input_report(device_handle, 0x11, 32) if len(report) == 1 + 19 and report[0] == 0x11: device["hidpp_long"] = True try: device_handle = open_path(device["path"]) for check_func in (check_hidpp_short, check_hidpp_long): try: check_func() except HIDError as e: logger.info( f"Error while {check_func.__name__}" f"on device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}" ) except HIDError as e: logger.info(f"Error opening device {device['path']} ({bus_id}/{vid:04X}/{pid:04X}) for hidpp check: {e}") finally: if device_handle: close(device_handle) logger.info( "Found device BID %s VID %04X PID %04X HID++ SHORT %s LONG %s", bus_id, vid, pid, device["hidpp_short"], device["hidpp_long"], ) if not device["hidpp_short"] and not device["hidpp_long"]: return None filtered_result = filter_func(bus_id, vid, pid, device["hidpp_short"], device["hidpp_long"]) if not filtered_result: return is_device = filtered_result.get("isDevice") if action == ACTION_ADD: d_info = DeviceInfo( path=device["path"].decode(), bus_id=bus_id, vendor_id=f"{vid:04X}", # noqa product_id=f"{pid:04X}", # noqa interface=None, driver=None, manufacturer=device["manufacturer_string"], product=device["product_string"], serial=device["serial_number"], release=device["release_number"], isDevice=is_device, hidpp_short=device["hidpp_short"], hidpp_long=device["hidpp_long"], ) return d_info elif action == ACTION_REMOVE: d_info = DeviceInfo( path=device["path"].decode(), bus_id=None, vendor_id=f"{vid:04X}", # noqa product_id=f"{pid:04X}", # noqa interface=None, driver=None, manufacturer=None, product=None, serial=None, release=None, isDevice=is_device, hidpp_short=None, hidpp_long=None, ) return d_info logger.info(f"Finished checking HIDPP support for device {device['path']} ({bus_id}/{vid:04X}/{pid:04X})") def find_paired_node(receiver_path: str, index: int, timeout: int): """Find the node of a device paired with a receiver""" return None def find_paired_node_wpid(receiver_path: str, index: int): """Find the node of a device paired with a receiver, get wpid from udev""" return None def monitor_glib( glib: GLib, callback: Callable, filter_func: Callable[[int, int, int, bool, bool], dict[str, Any]], ) -> None: """Monitor GLib. Parameters ---------- glib GLib instance. callback Called when device found. filter_func Filter devices callback. """ def device_callback(action: str, device): if action == ACTION_ADD: d_info = _match(action, device, filter_func) if d_info: glib.idle_add(callback, action, d_info) elif action == ACTION_REMOVE: # Removed devices will be detected by Solaar directly pass monitor = _DeviceMonitor(device_callback=device_callback) monitor.start() def enumerate(filter_func) -> DeviceInfo: """Enumerate the HID Devices. List all the HID devices attached to the system, optionally filtering by vendor_id, product_id, and/or interface_number. :returns: a list of matching ``DeviceInfo`` tuples. """ for device in _enumerate_devices(): d_info = _match(ACTION_ADD, device, filter_func) if d_info: yield d_info def open(vendor_id, product_id, serial=None): """Open a HID device by its Vendor ID, Product ID and optional serial number. If no serial is provided, the first device with the specified IDs is opened. :returns: an opaque device handle, or ``None``. """ if serial is not None: serial = ctypes.create_unicode_buffer(serial) device_handle = _hidapi.hid_open(vendor_id, product_id, serial) if device_handle is None: raise HIDError(_hidapi.hid_error(None)) return device_handle def open_path(device_path: str) -> int: """Open a HID device by its path name. :param device_path: the path of a ``DeviceInfo`` tuple returned by enumerate(). :returns: an opaque device handle, or ``None``. """ if not isinstance(device_path, bytes): device_path = device_path.encode() device_handle = _hidapi.hid_open_path(device_path) if device_handle is None: raise HIDError(_hidapi.hid_error(None)) return device_handle def close(device_handle) -> None: """Close a HID device. :param device_handle: a device handle returned by open() or open_path(). """ assert device_handle _hidapi.hid_close(device_handle) def write(device_handle: int, data: bytes) -> int: """Write an Output report to a HID device. :param device_handle: a device handle returned by open() or open_path(). :param data: the data bytes to send including the report number as the first byte. The first byte of data[] must contain the Report ID. For devices which only support a single report, this must be set to 0x0. The remaining bytes contain the report data. Since the Report ID is mandatory, calls to hid_write() will always contain one more byte than the report contains. For example, if a hid report is 16 bytes long, 17 bytes must be passed to hid_write(), the Report ID (or 0x0, for devices with a single report), followed by the report data (16 bytes). In this example, the length passed in would be 17. write() will send the data on the first OUT endpoint, if one exists. If it does not, it will send the data through the Control Endpoint (Endpoint 0). """ assert device_handle assert data assert isinstance(data, bytes), (repr(data), type(data)) bytes_written = _hidapi.hid_write(device_handle, data, len(data)) if bytes_written < 0: raise HIDError(_hidapi.hid_error(device_handle)) return bytes_written def read(device_handle, bytes_count, timeout_ms=None): """Read an Input report from a HID device. :param device_handle: a device handle returned by open() or open_path(). :param bytes_count: maximum number of bytes to read. :param timeout_ms: can be -1 (default) to wait for data indefinitely, 0 to read whatever is in the device's input buffer, or a positive integer to wait that many milliseconds. Input reports are returned to the host through the INTERRUPT IN endpoint. The first byte will contain the Report number if the device uses numbered reports. :returns: the data packet read, an empty bytes string if a timeout was reached, or None if there was an error while reading. """ assert device_handle data = ctypes.create_string_buffer(bytes_count) if timeout_ms is None or timeout_ms < 0: bytes_read = _hidapi.hid_read(device_handle, data, bytes_count) else: bytes_read = _hidapi.hid_read_timeout(device_handle, data, bytes_count, timeout_ms) if bytes_read < 0: raise HIDError(_hidapi.hid_error(device_handle)) return data.raw[:bytes_read] def _get_input_report(device_handle, report_id, size): assert device_handle data = ctypes.create_string_buffer(size) data[0] = bytearray((report_id,)) size = _hidapi.hid_get_input_report(device_handle, data, size) if size < 0: raise HIDError(_hidapi.hid_error(device_handle)) return data.raw[:size] def _readstring(device_handle, func, max_length=255): assert device_handle buf = ctypes.create_unicode_buffer(max_length) ret = func(device_handle, buf, max_length) if ret < 0: raise HIDError("Error reading device property") return buf.value def get_manufacturer(device_handle): """Get the Manufacturer String from a HID device. :param device_handle: a device handle returned by open() or open_path(). """ return _readstring(device_handle, _hidapi.get_manufacturer_string) def get_product(device_handle): """Get the Product String from a HID device. :param device_handle: a device handle returned by open() or open_path(). """ return _readstring(device_handle, _hidapi.get_product_string) def get_serial(device_handle): """Get the serial number from a HID device. :param device_handle: a device handle returned by open() or open_path(). """ return _readstring(device_handle, _hidapi.get_serial_number_string) Solaar-1.1.20/lib/hidapi/hidconsole.py000066400000000000000000000203411522022367600175260ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import argparse import os import os.path import platform import readline import sys import time from binascii import hexlify from binascii import unhexlify from select import select from threading import Lock from threading import Thread if platform.system() == "Linux": import hidapi.udev_impl as hidapi else: import hidapi.hidapi_impl as hidapi LOGITECH_VENDOR_ID = 0x046D interactive = os.isatty(0) prompt = "?? Input: " if interactive else "" start_time = time.time() def strhex(d): return hexlify(d).decode("ascii").upper() print_lock = Lock() def _print(marker, data, scroll=False): t = time.time() - start_time if isinstance(data, str): s = f"{marker} {data}" else: hexs = strhex(data) s = "%s (% 8.3f) [%s %s %s %s] %s" % (marker, t, hexs[0:2], hexs[2:4], hexs[4:8], hexs[8:], repr(data)) with print_lock: # allow only one thread at a time to write to the console, otherwise # the output gets garbled, especially with ANSI codes. if interactive and scroll: # scroll the entire screen above the current line up by 1 line sys.stdout.write( "\033[s" # save cursor position "\033[S" # scroll up "\033[A" # cursor up "\033[L" # insert 1 line "\033[G" ) # move cursor to column 1 sys.stdout.write(s) if interactive and scroll: # restore cursor position sys.stdout.write("\033[u") else: sys.stdout.write("\n") # flush stdout manually... # because trying to open stdin/out unbuffered programmatically # works much too differently in Python 2/3 sys.stdout.flush() def _error(text, scroll=False): _print("!!", text, scroll) def _continuous_read(handle, timeout=2000): while True: try: reply = hidapi.read(handle, 128, timeout) except OSError as e: _error(f"Read failed, aborting: {str(e)}", True) break assert reply is not None if reply: _print(">>", reply, True) def _validate_input(line, hidpp=False): try: data = unhexlify(line.encode("ascii")) except Exception as e: _error(f"Invalid input: {str(e)}") return None if hidpp: if len(data) < 4: _error("Invalid HID++ request: need at least 4 bytes") return None if data[:1] not in b"\x10\x11": _error("Invalid HID++ request: first byte must be 0x10 or 0x11") return None if data[1:2] not in b"\xff\x00\x01\x02\x03\x04\x05\x06\x07": _error("Invalid HID++ request: second byte must be 0xFF or one of 0x00..0x07") return None if data[:1] == b"\x10": if len(data) > 7: _error("Invalid HID++ request: maximum length of a 0x10 request is 7 bytes") return None while len(data) < 7: data = (data + b"\x00" * 7)[:7] elif data[:1] == b"\x11": if len(data) > 20: _error("Invalid HID++ request: maximum length of a 0x11 request is 20 bytes") return None while len(data) < 20: data = (data + b"\x00" * 20)[:20] return data def _open(args): def matchfn(bid, vid, pid, _a, _b): if vid == LOGITECH_VENDOR_ID: return {"vid": vid} device = args.path d = None if not device: for d in hidapi.enumerate(matchfn): if (d.hidpp_short or d.hidpp_long) and (args.id is None or args.id.lower() == d.product_id.lower()): device = d.path break if not device: sys.exit("!! No HID++ receiver found.") if not device: sys.exit("!! Device path required.") handle = hidapi.open_path(device) if not handle: sys.exit(f"!! Failed to open {device}, aborting.") print( ".. Opened device %r, vendor %r product %r serial %r." % ( device, hidapi.get_manufacturer(handle) or d.vendor_id if d else None, hidapi.get_product(handle) or d.product_id if d else None, hidapi.get_serial(handle), ) ) if args.hidpp: if hidapi.get_manufacturer(handle) is not None and hidapi.get_manufacturer(handle) != b"Logitech": sys.exit("!! Only Logitech devices support the HID++ protocol.") print(".. HID++ validation enabled.") else: if hidapi.get_manufacturer(handle) == b"Logitech" and b"Receiver" in hidapi.get_product(handle): args.hidpp = True print(".. Logitech receiver detected, HID++ validation enabled.") return handle def _parse_arguments(): arg_parser = argparse.ArgumentParser() arg_parser.add_argument("--history", help="history file (default ~/.hidconsole-history)") arg_parser.add_argument("--hidpp", action="store_true", help="ensure input data is a valid HID++ request") arg_parser.add_argument("command", nargs="?", help="command to send (otherwise get commands from input)") group = arg_parser.add_mutually_exclusive_group() group.add_argument("-p", "--path", help="HID raw device to connect to (/dev/hidrawX); ") group.add_argument("-i", "--id", help="product ID of device to connect to (XXXX)") return arg_parser.parse_args() def main(): args = _parse_arguments() handle = _open(args) if args.command: # send a command data = _validate_input(args.command, args.hidpp) if data: hidapi.write(handle, data) reply = hidapi.read(handle, 128, 1) if reply: hexs = strhex(reply) s = "[%s %s %s %s] %s" % (hexs[0:2], hexs[2:4], hexs[4:8], hexs[8:], repr(data)) print(s) exit() if interactive: print(".. Press ^C/^D to exit, or type hex bytes to write to the device.") if args.history is None: args.history = os.path.join(os.path.expanduser("~"), ".hidconsole-history") try: readline.read_history_file(args.history) except Exception: # file may not exist yet pass try: t = Thread(target=_continuous_read, args=(handle,)) t.daemon = True t.start() if interactive: # move the cursor at the bottom of the screen sys.stdout.write("\033[300B") # move cusor at most 300 lines down, don't scroll while t.is_alive(): line = input(prompt) line = line.strip().replace(" ", "") # print ("line", line) if not line: continue data = _validate_input(line, args.hidpp) if data is None: continue _print("<<", data) hidapi.write(handle, data) # wait for some kind of reply if args.hidpp and not interactive: rlist, wlist, xlist = select([handle], [], [], 1) if data[1:2] == b"\xff": # the receiver will reply very fast, in a few milliseconds time.sleep(0.010) else: # the devices might reply quite slow time.sleep(0.700) except EOFError: if interactive: print("") else: time.sleep(1) finally: hidapi.close(handle) if interactive: readline.write_history_file(args.history) if __name__ == "__main__": main() Solaar-1.1.20/lib/hidapi/udev_impl.py000066400000000000000000000413221522022367600173650ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Generic Human Interface Device API. It is currently a partial pure-Python implementation of the native HID API implemented by signal11 (https://github.com/signal11/hidapi), and requires ``pyudev``. The docstrings are mostly copied from the hidapi API header, with changes where necessary. """ from __future__ import annotations import errno import logging import os import typing import warnings # the tuple object we'll expose when enumerating devices from select import select from time import sleep from time import time from typing import Callable import pyudev from hidapi.common import DeviceInfo if typing.TYPE_CHECKING: import gi gi.require_version("Gdk", "3.0") from gi.repository import GLib # NOQA: E402 logger = logging.getLogger(__name__) fileopen = open ACTION_ADD = "add" ACTION_REMOVE = "remove" # # exposed API # docstrings mostly copied from hidapi.h # def init(): """This function is a no-op, and exists only to match the native hidapi implementation. :returns: ``True``. """ return True def exit(): """This function is a no-op, and exists only to match the native hidapi implementation. :returns: ``True``. """ return True def _match(action: str, device, filter_func: typing.Callable[[int, int, int, bool, bool], dict[str, typing.Any]]): """ The filter_func is used to determine whether this is a device of interest to Solaar. It is given the bus id, vendor id, and product id and returns a dictionary with the required hid_driver and usb_interface and whether this is a receiver or device.""" logger.debug(f"Dbus event {action} {device}") hid_device = device.find_parent("hid") if hid_device is None: # only HID devices are of interest to Solaar return hid_id = hid_device.properties.get("HID_ID") if not hid_id: return # there are reports that sometimes the id isn't set up right so be defensive bid, vid, pid = hid_id.split(":") hid_hid_device = hid_device.find_parent("hid") if hid_hid_device is not None: return # these are devices connected through a receiver so don't pick them up here try: # if report descriptor does not indicate HID++ capabilities then this device is not of interest to Solaar from hid_parser import ReportDescriptor hidpp_short = hidpp_long = centurion = False centurion_report_id = None devfile = "/sys" + hid_device.properties.get("DEVPATH") + "/report_descriptor" with fileopen(devfile, "rb") as fd: with warnings.catch_warnings(): warnings.simplefilter("ignore") rd = ReportDescriptor(fd.read()) hidpp_short = 0x10 in rd.input_report_ids and 6 * 8 == int(rd.get_input_report_size(0x10)) # and _Usage(0xFF00, 0x0001) in rd.get_input_items(0x10)[0].usages # be more permissive hidpp_long = 0x11 in rd.input_report_ids and 19 * 8 == int(rd.get_input_report_size(0x11)) # and _Usage(0xFF00, 0x0002) in rd.get_input_items(0x11)[0].usages # be more permissive # Centurion transport: 63-byte reports on usage page 0xFFA0 (both input and output) # 0x51 = PRO X 2 LIGHTSPEED variant, 0x50 = G522 LIGHTSPEED variant (with device address byte) if 0x51 in rd.input_report_ids and 63 * 8 == int(rd.get_input_report_size(0x51)) and 0x51 in rd.output_report_ids: centurion_report_id = 0x51 elif ( 0x50 in rd.input_report_ids and 63 * 8 == int(rd.get_input_report_size(0x50)) and 0x50 in rd.output_report_ids ): centurion_report_id = 0x50 centurion = centurion_report_id is not None if not hidpp_short and not hidpp_long and not centurion: return except Exception as e: # if can't process report descriptor fall back to old scheme hidpp_short = None hidpp_long = None centurion = False centurion_report_id = None logger.info( "Report Descriptor not processed for DEVICE %s BID %s VID %s PID %s: %s", device.device_node, bid, vid, pid, e, ) filtered_result = filter_func(int(bid, 16), int(vid, 16), int(pid, 16), hidpp_short or centurion, hidpp_long or centurion) if not filtered_result: return interface_number = filtered_result.get("usb_interface") isDevice = filtered_result.get("isDevice") if action == ACTION_ADD: hid_driver_name = hid_device.properties.get("DRIVER") intf_device = device.find_parent("usb", "usb_interface") usb_interface = None if intf_device is None else intf_device.attributes.asint("bInterfaceNumber") # print('*** usb interface', action, device, 'usb_interface:', intf_device, usb_interface, interface_number) logger.info( "Found device %s BID %s VID %s PID %s HID++ %s %s USB %s %s", device.device_node, bid, vid, pid, hidpp_short, hidpp_long, usb_interface, interface_number, ) if not (hidpp_short or hidpp_long or interface_number is None or interface_number == usb_interface): return attrs = intf_device.attributes if intf_device is not None else None d_info = DeviceInfo( path=device.device_node, bus_id=int(bid, 16), vendor_id=vid[-4:], product_id=pid[-4:], interface=usb_interface, driver=hid_driver_name, manufacturer=attrs.get("manufacturer") if attrs else None, product=attrs.get("product") if attrs else None, serial=hid_device.properties.get("HID_UNIQ"), release=attrs.get("bcdDevice") if attrs else None, isDevice=isDevice, hidpp_short=hidpp_short, hidpp_long=hidpp_long, centurion=centurion if centurion else False, centurion_report_id=centurion_report_id, ) return d_info elif action == ACTION_REMOVE: d_info = DeviceInfo( path=device.device_node, bus_id=None, vendor_id=vid[-4:], product_id=pid[-4:], interface=None, driver=None, manufacturer=None, product=None, serial=None, release=None, isDevice=isDevice, hidpp_short=None, hidpp_long=None, ) return d_info def find_paired_node(receiver_path: str, index: int, timeout: int): """Find the node of a device paired with a receiver""" context = pyudev.Context() receiver_phys = pyudev.Devices.from_device_file(context, receiver_path).find_parent("hid").get("HID_PHYS") if not receiver_phys: return None phys = f"{receiver_phys}:{index}" # noqa: E231 timeout += time() delta = time() while delta < timeout: for dev in context.list_devices(subsystem="hidraw"): dev_phys = dev.find_parent("hid").get("HID_PHYS") if dev_phys and dev_phys == phys: return dev.device_node delta = time() return None def find_paired_node_wpid(receiver_path: str, index: int): """Find the node of a device paired with a receiver, get wpid from udev""" context = pyudev.Context() receiver_phys = pyudev.Devices.from_device_file(context, receiver_path).find_parent("hid").get("HID_PHYS") if not receiver_phys: return None phys = f"{receiver_phys}:{index}" # noqa: E231 for dev in context.list_devices(subsystem="hidraw"): dev_phys = dev.find_parent("hid").get("HID_PHYS") if dev_phys and dev_phys == phys: # get hid id like 0003:0000046D:00000065 hid_id = dev.find_parent("hid").get("HID_ID") # get wpid - last 4 symbols udev_wpid = hid_id[-4:] return udev_wpid return None def monitor_glib(glib: GLib, callback: Callable, filter_func: Callable): """Monitor GLib. Parameters ---------- glib GLib instance. """ c = pyudev.Context() m = pyudev.Monitor.from_netlink(c) m.filter_by(subsystem="hidraw") def _process_udev_event(monitor, condition, cb, filter_func): if condition == glib.IO_IN: event = monitor.receive_device() if event: action, device = event # print ("***", action, device) if action == ACTION_ADD: d_info = _match(action, device, filter_func) if d_info: glib.idle_add(cb, action, d_info) elif action == ACTION_REMOVE: # the GLib notification does _not_ match! pass return True try: # io_add_watch_full may not be available... glib.io_add_watch_full(m, glib.PRIORITY_LOW, glib.IO_IN, _process_udev_event, callback, filter_func) except AttributeError: try: # and the priority parameter appeared later in the API glib.io_add_watch(m, glib.PRIORITY_LOW, glib.IO_IN, _process_udev_event, callback, filter_func) except Exception: glib.io_add_watch(m, glib.IO_IN, _process_udev_event, callback, filter_func) logger.debug("Starting dbus monitoring") m.start() def enumerate(filter_func: typing.Callable[[int, int, int, bool, bool], dict[str, typing.Any]]): """Enumerate the HID Devices. List all the HID devices attached to the system, optionally filtering by vendor_id, product_id, and/or interface_number. :returns: a list of matching ``DeviceInfo`` tuples. """ logger.debug("Starting dbus enumeration") for dev in pyudev.Context().list_devices(subsystem="hidraw"): dev_info = _match(ACTION_ADD, dev, filter_func) if dev_info: yield dev_info def open(vendor_id, product_id, serial=None): """Open a HID device by its Vendor ID, Product ID and optional serial number. If no serial is provided, the first device with the specified IDs is opened. :returns: an opaque device handle, or ``None``. """ def matchfn(bid, vid, pid): return vid == vendor_id and pid == product_id for device in enumerate(matchfn): if serial is None or serial == device.serial: return open_path(device.path) def open_path(device_path): """Open a HID device by its path name. :param device_path: the path of a ``DeviceInfo`` tuple returned by enumerate(). :returns: an opaque device handle, or ``None``. """ assert device_path assert device_path.startswith("/dev/hidraw") logger.info("OPEN PATH %s", device_path) retrycount = 0 while retrycount < 3: retrycount += 1 try: return os.open(device_path, os.O_RDWR | os.O_SYNC) except OSError as e: logger.info("OPEN PATH FAILED %s ERROR %s %s", device_path, e.errno, e) if e.errno == errno.EACCES: sleep(0.1) else: raise e def close(device_handle) -> None: """Close a HID device. :param device_handle: a device handle returned by open() or open_path(). """ assert device_handle os.close(device_handle) def write(device_handle, data): """Write an Output report to a HID device. :param device_handle: a device handle returned by open() or open_path(). :param data: the data bytes to send including the report number as the first byte. The first byte of data[] must contain the Report ID. For devices which only support a single report, this must be set to 0x0. The remaining bytes contain the report data. Since the Report ID is mandatory, calls to hid_write() will always contain one more byte than the report contains. For example, if a hid report is 16 bytes long, 17 bytes must be passed to hid_write(), the Report ID (or 0x0, for devices with a single report), followed by the report data (16 bytes). In this example, the length passed in would be 17. write() will send the data on the first OUT endpoint, if one exists. If it does not, it will send the data through the Control Endpoint (Endpoint 0). """ assert device_handle assert data assert isinstance(data, bytes), (repr(data), type(data)) retrycount = 0 bytes_written = 0 while retrycount < 3: try: retrycount += 1 bytes_written = os.write(device_handle, data) except OSError as e: if e.errno == errno.EPIPE: sleep(0.1) else: break if bytes_written != len(data): raise OSError(errno.EIO, f"written {int(bytes_written)} bytes out of expected {len(data)}") def read(device_handle, bytes_count, timeout_ms=-1): """Read an Input report from a HID device. :param device_handle: a device handle returned by open() or open_path(). :param bytes_count: maximum number of bytes to read. :param timeout_ms: can be -1 (default) to wait for data indefinitely, 0 to read whatever is in the device's input buffer, or a positive integer to wait that many milliseconds. Input reports are returned to the host through the INTERRUPT IN endpoint. The first byte will contain the Report number if the device uses numbered reports. :returns: the data packet read, an empty bytes string if a timeout was reached, or None if there was an error while reading. """ assert device_handle timeout = None if timeout_ms < 0 else timeout_ms / 1000.0 rlist, wlist, xlist = select([device_handle], [], [device_handle], timeout) if xlist: assert xlist == [device_handle] raise OSError(errno.EIO, f"exception on file descriptor {int(device_handle)}") if rlist: assert rlist == [device_handle] data = os.read(device_handle, bytes_count) assert data is not None assert isinstance(data, bytes), (repr(data), type(data)) if not data: # empty read when select() said readable means EOF (device removed) raise OSError(errno.EIO, f"device disconnected on file descriptor {int(device_handle)}") return data else: return b"" _DEVICE_STRINGS = { 0: "manufacturer", 1: "product", 2: "serial", } def get_manufacturer(device_handle): """Get the Manufacturer String from a HID device. :param device_handle: a device handle returned by open() or open_path(). """ return get_indexed_string(device_handle, 0) def get_product(device_handle): """Get the Product String from a HID device. :param device_handle: a device handle returned by open() or open_path(). """ return get_indexed_string(device_handle, 1) def get_serial(device_handle): """Get the serial number from a HID device. :param device_handle: a device handle returned by open() or open_path(). """ serial = get_indexed_string(device_handle, 2) return serial def get_indexed_string(device_handle, index): """Get a string from a HID device, based on its string index. Note: currently not working in the ``hidraw`` native implementation. :param device_handle: a device handle returned by open() or open_path(). :param index: the index of the string to get. :returns: the value corresponding to index, or None if no value found :rtype: bytes or NoneType """ try: key = _DEVICE_STRINGS[index] except KeyError: return None assert device_handle stat = os.fstat(device_handle) try: dev = pyudev.Devices.from_device_number(pyudev.Context(), "char", stat.st_rdev) except (pyudev.DeviceNotFoundError, ValueError): return None hid_dev = dev.find_parent("hid") if hid_dev: assert "HID_ID" in hid_dev bus, _ignore, _ignore = hid_dev["HID_ID"].split(":") if bus == "0003": # USB usb_dev = dev.find_parent("usb", "usb_device") assert usb_dev return usb_dev.attributes.get(key) elif bus == "0005": # BLUETOOTH # TODO pass Solaar-1.1.20/lib/keysyms/000077500000000000000000000000001522022367600152735ustar00rootroot00000000000000Solaar-1.1.20/lib/keysyms/__init__.py000066400000000000000000000000001522022367600173720ustar00rootroot00000000000000Solaar-1.1.20/lib/keysyms/generate.py000077500000000000000000000023171522022367600174450ustar00rootroot00000000000000#!/usr/bin/env python3 """Extract key symbol encodings from X11 header files.""" from pathlib import Path from pprint import pprint from re import findall from subprocess import run from tempfile import TemporaryDirectory repo = "https://gitlab.freedesktop.org/xorg/proto/xorgproto.git" pattern = r"#define XK_(\w+)\s+0x(\w+)(?:\s+/\*\s+U\+(\w+))?" xf86pattern = r"#define XF86XK_(\w+)\s+0x(\w+)(?:\s+/\*\s+U\+(\w+))?" def main(): keysymdef = {} keysym_files = [ ("include/X11/keysymdef.h", pattern, ""), ("include/X11/XF86keysym.h", xf86pattern, "XF86_"), ] with TemporaryDirectory() as temp: run(["git", "clone", repo, "."], cwd=temp) for filename, extraction_pattern, prefix in keysym_files: text = Path(temp, filename).read_text() for name, sym, _ in findall(extraction_pattern, text): sym = int(sym, 16) if keysymdef.get(f"{prefix}{name}", None): print(f"KEY DUP {prefix}{name}") keysymdef[f"{prefix}{name}"] = sym with open("keysymdef.py", "w") as f: f.write("# flake8: noqa\nkey_symbols = \\\n") pprint(keysymdef, f) if __name__ == "__main__": main() Solaar-1.1.20/lib/keysyms/keysymdef.py000066400000000000000000001705701522022367600176570ustar00rootroot00000000000000# flake8: noqa key_symbols = { "0": 48, "1": 49, "2": 50, "3": 51, "3270_AltCursor": 64784, "3270_Attn": 64782, "3270_BackTab": 64773, "3270_ChangeScreen": 64793, "3270_Copy": 64789, "3270_CursorBlink": 64783, "3270_CursorSelect": 64796, "3270_DeleteWord": 64794, "3270_Duplicate": 64769, "3270_Enter": 64798, "3270_EraseEOF": 64774, "3270_EraseInput": 64775, "3270_ExSelect": 64795, "3270_FieldMark": 64770, "3270_Ident": 64787, "3270_Jump": 64786, "3270_KeyClick": 64785, "3270_Left2": 64772, "3270_PA1": 64778, "3270_PA2": 64779, "3270_PA3": 64780, "3270_Play": 64790, "3270_PrintScreen": 64797, "3270_Quit": 64777, "3270_Record": 64792, "3270_Reset": 64776, "3270_Right2": 64771, "3270_Rule": 64788, "3270_Setup": 64791, "3270_Test": 64781, "4": 52, "5": 53, "6": 54, "7": 55, "8": 56, "9": 57, "A": 65, "AE": 198, "Aacute": 193, "Abelowdot": 16785056, "Abreve": 451, "Abreveacute": 16785070, "Abrevebelowdot": 16785078, "Abrevegrave": 16785072, "Abrevehook": 16785074, "Abrevetilde": 16785076, "AccessX_Enable": 65136, "AccessX_Feedback_Enable": 65137, "Acircumflex": 194, "Acircumflexacute": 16785060, "Acircumflexbelowdot": 16785068, "Acircumflexgrave": 16785062, "Acircumflexhook": 16785064, "Acircumflextilde": 16785066, "Adiaeresis": 196, "Agrave": 192, "Ahook": 16785058, "Alt_L": 65513, "Alt_R": 65514, "Amacron": 960, "Aogonek": 417, "Arabic_0": 16778848, "Arabic_1": 16778849, "Arabic_2": 16778850, "Arabic_3": 16778851, "Arabic_4": 16778852, "Arabic_5": 16778853, "Arabic_6": 16778854, "Arabic_7": 16778855, "Arabic_8": 16778856, "Arabic_9": 16778857, "Arabic_ain": 1497, "Arabic_alef": 1479, "Arabic_alefmaksura": 1513, "Arabic_beh": 1480, "Arabic_comma": 1452, "Arabic_dad": 1494, "Arabic_dal": 1487, "Arabic_damma": 1519, "Arabic_dammatan": 1516, "Arabic_ddal": 16778888, "Arabic_farsi_yeh": 16778956, "Arabic_fatha": 1518, "Arabic_fathatan": 1515, "Arabic_feh": 1505, "Arabic_fullstop": 16778964, "Arabic_gaf": 16778927, "Arabic_ghain": 1498, "Arabic_ha": 1511, "Arabic_hah": 1485, "Arabic_hamza": 1473, "Arabic_hamza_above": 16778836, "Arabic_hamza_below": 16778837, "Arabic_hamzaonalef": 1475, "Arabic_hamzaonwaw": 1476, "Arabic_hamzaonyeh": 1478, "Arabic_hamzaunderalef": 1477, "Arabic_heh": 1511, "Arabic_heh_doachashmee": 16778942, "Arabic_heh_goal": 16778945, "Arabic_jeem": 1484, "Arabic_jeh": 16778904, "Arabic_kaf": 1507, "Arabic_kasra": 1520, "Arabic_kasratan": 1517, "Arabic_keheh": 16778921, "Arabic_khah": 1486, "Arabic_lam": 1508, "Arabic_madda_above": 16778835, "Arabic_maddaonalef": 1474, "Arabic_meem": 1509, "Arabic_noon": 1510, "Arabic_noon_ghunna": 16778938, "Arabic_peh": 16778878, "Arabic_percent": 16778858, "Arabic_qaf": 1506, "Arabic_question_mark": 1471, "Arabic_ra": 1489, "Arabic_rreh": 16778897, "Arabic_sad": 1493, "Arabic_seen": 1491, "Arabic_semicolon": 1467, "Arabic_shadda": 1521, "Arabic_sheen": 1492, "Arabic_sukun": 1522, "Arabic_superscript_alef": 16778864, "Arabic_switch": 65406, "Arabic_tah": 1495, "Arabic_tatweel": 1504, "Arabic_tcheh": 16778886, "Arabic_teh": 1482, "Arabic_tehmarbuta": 1481, "Arabic_thal": 1488, "Arabic_theh": 1483, "Arabic_tteh": 16778873, "Arabic_veh": 16778916, "Arabic_waw": 1512, "Arabic_yeh": 1514, "Arabic_yeh_baree": 16778962, "Arabic_zah": 1496, "Arabic_zain": 1490, "Aring": 197, "Armenian_AT": 16778552, "Armenian_AYB": 16778545, "Armenian_BEN": 16778546, "Armenian_CHA": 16778569, "Armenian_DA": 16778548, "Armenian_DZA": 16778561, "Armenian_E": 16778551, "Armenian_FE": 16778582, "Armenian_GHAT": 16778562, "Armenian_GIM": 16778547, "Armenian_HI": 16778565, "Armenian_HO": 16778560, "Armenian_INI": 16778555, "Armenian_JE": 16778571, "Armenian_KE": 16778580, "Armenian_KEN": 16778559, "Armenian_KHE": 16778557, "Armenian_LYUN": 16778556, "Armenian_MEN": 16778564, "Armenian_NU": 16778566, "Armenian_O": 16778581, "Armenian_PE": 16778570, "Armenian_PYUR": 16778579, "Armenian_RA": 16778572, "Armenian_RE": 16778576, "Armenian_SE": 16778573, "Armenian_SHA": 16778567, "Armenian_TCHE": 16778563, "Armenian_TO": 16778553, "Armenian_TSA": 16778558, "Armenian_TSO": 16778577, "Armenian_TYUN": 16778575, "Armenian_VEV": 16778574, "Armenian_VO": 16778568, "Armenian_VYUN": 16778578, "Armenian_YECH": 16778549, "Armenian_ZA": 16778550, "Armenian_ZHE": 16778554, "Armenian_accent": 16778587, "Armenian_amanak": 16778588, "Armenian_apostrophe": 16778586, "Armenian_at": 16778600, "Armenian_ayb": 16778593, "Armenian_ben": 16778594, "Armenian_but": 16778589, "Armenian_cha": 16778617, "Armenian_da": 16778596, "Armenian_dza": 16778609, "Armenian_e": 16778599, "Armenian_exclam": 16778588, "Armenian_fe": 16778630, "Armenian_full_stop": 16778633, "Armenian_ghat": 16778610, "Armenian_gim": 16778595, "Armenian_hi": 16778613, "Armenian_ho": 16778608, "Armenian_hyphen": 16778634, "Armenian_ini": 16778603, "Armenian_je": 16778619, "Armenian_ke": 16778628, "Armenian_ken": 16778607, "Armenian_khe": 16778605, "Armenian_ligature_ew": 16778631, "Armenian_lyun": 16778604, "Armenian_men": 16778612, "Armenian_nu": 16778614, "Armenian_o": 16778629, "Armenian_paruyk": 16778590, "Armenian_pe": 16778618, "Armenian_pyur": 16778627, "Armenian_question": 16778590, "Armenian_ra": 16778620, "Armenian_re": 16778624, "Armenian_se": 16778621, "Armenian_separation_mark": 16778589, "Armenian_sha": 16778615, "Armenian_shesht": 16778587, "Armenian_tche": 16778611, "Armenian_to": 16778601, "Armenian_tsa": 16778606, "Armenian_tso": 16778625, "Armenian_tyun": 16778623, "Armenian_verjaket": 16778633, "Armenian_vev": 16778622, "Armenian_vo": 16778616, "Armenian_vyun": 16778626, "Armenian_yech": 16778597, "Armenian_yentamna": 16778634, "Armenian_za": 16778598, "Armenian_zhe": 16778602, "Atilde": 195, "AudibleBell_Enable": 65146, "B": 66, "Babovedot": 16784898, "BackSpace": 65288, "Begin": 65368, "BounceKeys_Enable": 65140, "Break": 65387, "Byelorussian_SHORTU": 1726, "Byelorussian_shortu": 1710, "C": 67, "CH": 65186, "C_H": 65189, "C_h": 65188, "Cabovedot": 709, "Cacute": 454, "Cancel": 65385, "Caps_Lock": 65509, "Ccaron": 456, "Ccedilla": 199, "Ccircumflex": 710, "Ch": 65185, "Clear": 65291, "Codeinput": 65335, "ColonSign": 16785569, "Control_L": 65507, "Control_R": 65508, "CruzeiroSign": 16785570, "Cyrillic_A": 1761, "Cyrillic_BE": 1762, "Cyrillic_CHE": 1790, "Cyrillic_CHE_descender": 16778422, "Cyrillic_CHE_vertstroke": 16778424, "Cyrillic_DE": 1764, "Cyrillic_DZHE": 1727, "Cyrillic_E": 1788, "Cyrillic_EF": 1766, "Cyrillic_EL": 1772, "Cyrillic_EM": 1773, "Cyrillic_EN": 1774, "Cyrillic_EN_descender": 16778402, "Cyrillic_ER": 1778, "Cyrillic_ES": 1779, "Cyrillic_GHE": 1767, "Cyrillic_GHE_bar": 16778386, "Cyrillic_HA": 1768, "Cyrillic_HARDSIGN": 1791, "Cyrillic_HA_descender": 16778418, "Cyrillic_I": 1769, "Cyrillic_IE": 1765, "Cyrillic_IO": 1715, "Cyrillic_I_macron": 16778466, "Cyrillic_JE": 1720, "Cyrillic_KA": 1771, "Cyrillic_KA_descender": 16778394, "Cyrillic_KA_vertstroke": 16778396, "Cyrillic_LJE": 1721, "Cyrillic_NJE": 1722, "Cyrillic_O": 1775, "Cyrillic_O_bar": 16778472, "Cyrillic_PE": 1776, "Cyrillic_SCHWA": 16778456, "Cyrillic_SHA": 1787, "Cyrillic_SHCHA": 1789, "Cyrillic_SHHA": 16778426, "Cyrillic_SHORTI": 1770, "Cyrillic_SOFTSIGN": 1784, "Cyrillic_TE": 1780, "Cyrillic_TSE": 1763, "Cyrillic_U": 1781, "Cyrillic_U_macron": 16778478, "Cyrillic_U_straight": 16778414, "Cyrillic_U_straight_bar": 16778416, "Cyrillic_VE": 1783, "Cyrillic_YA": 1777, "Cyrillic_YERU": 1785, "Cyrillic_YU": 1760, "Cyrillic_ZE": 1786, "Cyrillic_ZHE": 1782, "Cyrillic_ZHE_descender": 16778390, "Cyrillic_a": 1729, "Cyrillic_be": 1730, "Cyrillic_che": 1758, "Cyrillic_che_descender": 16778423, "Cyrillic_che_vertstroke": 16778425, "Cyrillic_de": 1732, "Cyrillic_dzhe": 1711, "Cyrillic_e": 1756, "Cyrillic_ef": 1734, "Cyrillic_el": 1740, "Cyrillic_em": 1741, "Cyrillic_en": 1742, "Cyrillic_en_descender": 16778403, "Cyrillic_er": 1746, "Cyrillic_es": 1747, "Cyrillic_ghe": 1735, "Cyrillic_ghe_bar": 16778387, "Cyrillic_ha": 1736, "Cyrillic_ha_descender": 16778419, "Cyrillic_hardsign": 1759, "Cyrillic_i": 1737, "Cyrillic_i_macron": 16778467, "Cyrillic_ie": 1733, "Cyrillic_io": 1699, "Cyrillic_je": 1704, "Cyrillic_ka": 1739, "Cyrillic_ka_descender": 16778395, "Cyrillic_ka_vertstroke": 16778397, "Cyrillic_lje": 1705, "Cyrillic_nje": 1706, "Cyrillic_o": 1743, "Cyrillic_o_bar": 16778473, "Cyrillic_pe": 1744, "Cyrillic_schwa": 16778457, "Cyrillic_sha": 1755, "Cyrillic_shcha": 1757, "Cyrillic_shha": 16778427, "Cyrillic_shorti": 1738, "Cyrillic_softsign": 1752, "Cyrillic_te": 1748, "Cyrillic_tse": 1731, "Cyrillic_u": 1749, "Cyrillic_u_macron": 16778479, "Cyrillic_u_straight": 16778415, "Cyrillic_u_straight_bar": 16778417, "Cyrillic_ve": 1751, "Cyrillic_ya": 1745, "Cyrillic_yeru": 1753, "Cyrillic_yu": 1728, "Cyrillic_ze": 1754, "Cyrillic_zhe": 1750, "Cyrillic_zhe_descender": 16778391, "D": 68, "Dabovedot": 16784906, "Dcaron": 463, "Delete": 65535, "DongSign": 16785579, "Down": 65364, "Dstroke": 464, "E": 69, "ENG": 957, "ETH": 208, "EZH": 16777655, "Eabovedot": 972, "Eacute": 201, "Ebelowdot": 16785080, "Ecaron": 460, "Ecircumflex": 202, "Ecircumflexacute": 16785086, "Ecircumflexbelowdot": 16785094, "Ecircumflexgrave": 16785088, "Ecircumflexhook": 16785090, "Ecircumflextilde": 16785092, "EcuSign": 16785568, "Ediaeresis": 203, "Egrave": 200, "Ehook": 16785082, "Eisu_Shift": 65327, "Eisu_toggle": 65328, "Emacron": 938, "End": 65367, "Eogonek": 458, "Escape": 65307, "Eth": 208, "Etilde": 16785084, "EuroSign": 8364, "Execute": 65378, "F": 70, "F1": 65470, "F10": 65479, "F11": 65480, "F12": 65481, "F13": 65482, "F14": 65483, "F15": 65484, "F16": 65485, "F17": 65486, "F18": 65487, "F19": 65488, "F2": 65471, "F20": 65489, "F21": 65490, "F22": 65491, "F23": 65492, "F24": 65493, "F25": 65494, "F26": 65495, "F27": 65496, "F28": 65497, "F29": 65498, "F3": 65472, "F30": 65499, "F31": 65500, "F32": 65501, "F33": 65502, "F34": 65503, "F35": 65504, "F4": 65473, "F5": 65474, "F6": 65475, "F7": 65476, "F8": 65477, "F9": 65478, "FFrancSign": 16785571, "Fabovedot": 16784926, "Farsi_0": 16778992, "Farsi_1": 16778993, "Farsi_2": 16778994, "Farsi_3": 16778995, "Farsi_4": 16778996, "Farsi_5": 16778997, "Farsi_6": 16778998, "Farsi_7": 16778999, "Farsi_8": 16779000, "Farsi_9": 16779001, "Farsi_yeh": 16778956, "Find": 65384, "First_Virtual_Screen": 65232, "G": 71, "Gabovedot": 725, "Gbreve": 683, "Gcaron": 16777702, "Gcedilla": 939, "Gcircumflex": 728, "Georgian_an": 16781520, "Georgian_ban": 16781521, "Georgian_can": 16781546, "Georgian_char": 16781549, "Georgian_chin": 16781545, "Georgian_cil": 16781548, "Georgian_don": 16781523, "Georgian_en": 16781524, "Georgian_fi": 16781558, "Georgian_gan": 16781522, "Georgian_ghan": 16781542, "Georgian_hae": 16781552, "Georgian_har": 16781556, "Georgian_he": 16781553, "Georgian_hie": 16781554, "Georgian_hoe": 16781557, "Georgian_in": 16781528, "Georgian_jhan": 16781551, "Georgian_jil": 16781547, "Georgian_kan": 16781529, "Georgian_khar": 16781541, "Georgian_las": 16781530, "Georgian_man": 16781531, "Georgian_nar": 16781532, "Georgian_on": 16781533, "Georgian_par": 16781534, "Georgian_phar": 16781540, "Georgian_qar": 16781543, "Georgian_rae": 16781536, "Georgian_san": 16781537, "Georgian_shin": 16781544, "Georgian_tan": 16781527, "Georgian_tar": 16781538, "Georgian_un": 16781539, "Georgian_vin": 16781525, "Georgian_we": 16781555, "Georgian_xan": 16781550, "Georgian_zen": 16781526, "Georgian_zhar": 16781535, "Greek_ALPHA": 1985, "Greek_ALPHAaccent": 1953, "Greek_BETA": 1986, "Greek_CHI": 2007, "Greek_DELTA": 1988, "Greek_EPSILON": 1989, "Greek_EPSILONaccent": 1954, "Greek_ETA": 1991, "Greek_ETAaccent": 1955, "Greek_GAMMA": 1987, "Greek_IOTA": 1993, "Greek_IOTAaccent": 1956, "Greek_IOTAdiaeresis": 1957, "Greek_IOTAdieresis": 1957, "Greek_KAPPA": 1994, "Greek_LAMBDA": 1995, "Greek_LAMDA": 1995, "Greek_MU": 1996, "Greek_NU": 1997, "Greek_OMEGA": 2009, "Greek_OMEGAaccent": 1963, "Greek_OMICRON": 1999, "Greek_OMICRONaccent": 1959, "Greek_PHI": 2006, "Greek_PI": 2000, "Greek_PSI": 2008, "Greek_RHO": 2001, "Greek_SIGMA": 2002, "Greek_TAU": 2004, "Greek_THETA": 1992, "Greek_UPSILON": 2005, "Greek_UPSILONaccent": 1960, "Greek_UPSILONdieresis": 1961, "Greek_XI": 1998, "Greek_ZETA": 1990, "Greek_accentdieresis": 1966, "Greek_alpha": 2017, "Greek_alphaaccent": 1969, "Greek_beta": 2018, "Greek_chi": 2039, "Greek_delta": 2020, "Greek_epsilon": 2021, "Greek_epsilonaccent": 1970, "Greek_eta": 2023, "Greek_etaaccent": 1971, "Greek_finalsmallsigma": 2035, "Greek_gamma": 2019, "Greek_horizbar": 1967, "Greek_iota": 2025, "Greek_iotaaccent": 1972, "Greek_iotaaccentdieresis": 1974, "Greek_iotadieresis": 1973, "Greek_kappa": 2026, "Greek_lambda": 2027, "Greek_lamda": 2027, "Greek_mu": 2028, "Greek_nu": 2029, "Greek_omega": 2041, "Greek_omegaaccent": 1979, "Greek_omicron": 2031, "Greek_omicronaccent": 1975, "Greek_phi": 2038, "Greek_pi": 2032, "Greek_psi": 2040, "Greek_rho": 2033, "Greek_sigma": 2034, "Greek_switch": 65406, "Greek_tau": 2036, "Greek_theta": 2024, "Greek_upsilon": 2037, "Greek_upsilonaccent": 1976, "Greek_upsilonaccentdieresis": 1978, "Greek_upsilondieresis": 1977, "Greek_xi": 2030, "Greek_zeta": 2022, "H": 72, "Hangul": 65329, "Hangul_A": 3775, "Hangul_AE": 3776, "Hangul_AraeA": 3830, "Hangul_AraeAE": 3831, "Hangul_Banja": 65337, "Hangul_Cieuc": 3770, "Hangul_Codeinput": 65335, "Hangul_Dikeud": 3751, "Hangul_E": 3780, "Hangul_EO": 3779, "Hangul_EU": 3793, "Hangul_End": 65331, "Hangul_Hanja": 65332, "Hangul_Hieuh": 3774, "Hangul_I": 3795, "Hangul_Ieung": 3767, "Hangul_J_Cieuc": 3818, "Hangul_J_Dikeud": 3802, "Hangul_J_Hieuh": 3822, "Hangul_J_Ieung": 3816, "Hangul_J_Jieuj": 3817, "Hangul_J_Khieuq": 3819, "Hangul_J_Kiyeog": 3796, "Hangul_J_KiyeogSios": 3798, "Hangul_J_KkogjiDalrinIeung": 3833, "Hangul_J_Mieum": 3811, "Hangul_J_Nieun": 3799, "Hangul_J_NieunHieuh": 3801, "Hangul_J_NieunJieuj": 3800, "Hangul_J_PanSios": 3832, "Hangul_J_Phieuf": 3821, "Hangul_J_Pieub": 3812, "Hangul_J_PieubSios": 3813, "Hangul_J_Rieul": 3803, "Hangul_J_RieulHieuh": 3810, "Hangul_J_RieulKiyeog": 3804, "Hangul_J_RieulMieum": 3805, "Hangul_J_RieulPhieuf": 3809, "Hangul_J_RieulPieub": 3806, "Hangul_J_RieulSios": 3807, "Hangul_J_RieulTieut": 3808, "Hangul_J_Sios": 3814, "Hangul_J_SsangKiyeog": 3797, "Hangul_J_SsangSios": 3815, "Hangul_J_Tieut": 3820, "Hangul_J_YeorinHieuh": 3834, "Hangul_Jamo": 65333, "Hangul_Jeonja": 65336, "Hangul_Jieuj": 3768, "Hangul_Khieuq": 3771, "Hangul_Kiyeog": 3745, "Hangul_KiyeogSios": 3747, "Hangul_KkogjiDalrinIeung": 3827, "Hangul_Mieum": 3761, "Hangul_MultipleCandidate": 65341, "Hangul_Nieun": 3748, "Hangul_NieunHieuh": 3750, "Hangul_NieunJieuj": 3749, "Hangul_O": 3783, "Hangul_OE": 3786, "Hangul_PanSios": 3826, "Hangul_Phieuf": 3773, "Hangul_Pieub": 3762, "Hangul_PieubSios": 3764, "Hangul_PostHanja": 65339, "Hangul_PreHanja": 65338, "Hangul_PreviousCandidate": 65342, "Hangul_Rieul": 3753, "Hangul_RieulHieuh": 3760, "Hangul_RieulKiyeog": 3754, "Hangul_RieulMieum": 3755, "Hangul_RieulPhieuf": 3759, "Hangul_RieulPieub": 3756, "Hangul_RieulSios": 3757, "Hangul_RieulTieut": 3758, "Hangul_RieulYeorinHieuh": 3823, "Hangul_Romaja": 65334, "Hangul_SingleCandidate": 65340, "Hangul_Sios": 3765, "Hangul_Special": 65343, "Hangul_SsangDikeud": 3752, "Hangul_SsangJieuj": 3769, "Hangul_SsangKiyeog": 3746, "Hangul_SsangPieub": 3763, "Hangul_SsangSios": 3766, "Hangul_Start": 65330, "Hangul_SunkyeongeumMieum": 3824, "Hangul_SunkyeongeumPhieuf": 3828, "Hangul_SunkyeongeumPieub": 3825, "Hangul_Tieut": 3772, "Hangul_U": 3788, "Hangul_WA": 3784, "Hangul_WAE": 3785, "Hangul_WE": 3790, "Hangul_WEO": 3789, "Hangul_WI": 3791, "Hangul_YA": 3777, "Hangul_YAE": 3778, "Hangul_YE": 3782, "Hangul_YEO": 3781, "Hangul_YI": 3794, "Hangul_YO": 3787, "Hangul_YU": 3792, "Hangul_YeorinHieuh": 3829, "Hangul_switch": 65406, "Hankaku": 65321, "Hcircumflex": 678, "Hebrew_switch": 65406, "Help": 65386, "Henkan": 65315, "Henkan_Mode": 65315, "Hiragana": 65317, "Hiragana_Katakana": 65319, "Home": 65360, "Hstroke": 673, "Hyper_L": 65517, "Hyper_R": 65518, "I": 73, "ISO_Center_Object": 65075, "ISO_Continuous_Underline": 65072, "ISO_Discontinuous_Underline": 65073, "ISO_Emphasize": 65074, "ISO_Enter": 65076, "ISO_Fast_Cursor_Down": 65071, "ISO_Fast_Cursor_Left": 65068, "ISO_Fast_Cursor_Right": 65069, "ISO_Fast_Cursor_Up": 65070, "ISO_First_Group": 65036, "ISO_First_Group_Lock": 65037, "ISO_Group_Latch": 65030, "ISO_Group_Lock": 65031, "ISO_Group_Shift": 65406, "ISO_Last_Group": 65038, "ISO_Last_Group_Lock": 65039, "ISO_Left_Tab": 65056, "ISO_Level2_Latch": 65026, "ISO_Level3_Latch": 65028, "ISO_Level3_Lock": 65029, "ISO_Level3_Shift": 65027, "ISO_Level5_Latch": 65042, "ISO_Level5_Lock": 65043, "ISO_Level5_Shift": 65041, "ISO_Lock": 65025, "ISO_Move_Line_Down": 65058, "ISO_Move_Line_Up": 65057, "ISO_Next_Group": 65032, "ISO_Next_Group_Lock": 65033, "ISO_Partial_Line_Down": 65060, "ISO_Partial_Line_Up": 65059, "ISO_Partial_Space_Left": 65061, "ISO_Partial_Space_Right": 65062, "ISO_Prev_Group": 65034, "ISO_Prev_Group_Lock": 65035, "ISO_Release_Both_Margins": 65067, "ISO_Release_Margin_Left": 65065, "ISO_Release_Margin_Right": 65066, "ISO_Set_Margin_Left": 65063, "ISO_Set_Margin_Right": 65064, "Iabovedot": 681, "Iacute": 205, "Ibelowdot": 16785098, "Ibreve": 16777516, "Icircumflex": 206, "Idiaeresis": 207, "Igrave": 204, "Ihook": 16785096, "Imacron": 975, "Insert": 65379, "Iogonek": 967, "Itilde": 933, "J": 74, "Jcircumflex": 684, "K": 75, "KP_0": 65456, "KP_1": 65457, "KP_2": 65458, "KP_3": 65459, "KP_4": 65460, "KP_5": 65461, "KP_6": 65462, "KP_7": 65463, "KP_8": 65464, "KP_9": 65465, "KP_Add": 65451, "KP_Begin": 65437, "KP_Decimal": 65454, "KP_Delete": 65439, "KP_Divide": 65455, "KP_Down": 65433, "KP_End": 65436, "KP_Enter": 65421, "KP_Equal": 65469, "KP_F1": 65425, "KP_F2": 65426, "KP_F3": 65427, "KP_F4": 65428, "KP_Home": 65429, "KP_Insert": 65438, "KP_Left": 65430, "KP_Multiply": 65450, "KP_Next": 65435, "KP_Page_Down": 65435, "KP_Page_Up": 65434, "KP_Prior": 65434, "KP_Right": 65432, "KP_Separator": 65452, "KP_Space": 65408, "KP_Subtract": 65453, "KP_Tab": 65417, "KP_Up": 65431, "Kana_Lock": 65325, "Kana_Shift": 65326, "Kanji": 65313, "Kanji_Bangou": 65335, "Katakana": 65318, "Kcedilla": 979, "Korean_Won": 3839, "L": 76, "L1": 65480, "L10": 65489, "L2": 65481, "L3": 65482, "L4": 65483, "L5": 65484, "L6": 65485, "L7": 65486, "L8": 65487, "L9": 65488, "Lacute": 453, "Last_Virtual_Screen": 65236, "Lbelowdot": 16784950, "Lcaron": 421, "Lcedilla": 934, "Left": 65361, "Linefeed": 65290, "LiraSign": 16785572, "Lstroke": 419, "M": 77, "Mabovedot": 16784960, "Macedonia_DSE": 1717, "Macedonia_GJE": 1714, "Macedonia_KJE": 1724, "Macedonia_dse": 1701, "Macedonia_gje": 1698, "Macedonia_kje": 1708, "Mae_Koho": 65342, "Massyo": 65324, "Menu": 65383, "Meta_L": 65511, "Meta_R": 65512, "MillSign": 16785573, "Mode_switch": 65406, "MouseKeys_Accel_Enable": 65143, "MouseKeys_Enable": 65142, "Muhenkan": 65314, "Multi_key": 65312, "MultipleCandidate": 65341, "N": 78, "Nacute": 465, "NairaSign": 16785574, "Ncaron": 466, "Ncedilla": 977, "NewSheqelSign": 16785578, "Next": 65366, "Next_Virtual_Screen": 65234, "Ntilde": 209, "Num_Lock": 65407, "O": 79, "OE": 5052, "Oacute": 211, "Obarred": 16777631, "Obelowdot": 16785100, "Ocaron": 16777681, "Ocircumflex": 212, "Ocircumflexacute": 16785104, "Ocircumflexbelowdot": 16785112, "Ocircumflexgrave": 16785106, "Ocircumflexhook": 16785108, "Ocircumflextilde": 16785110, "Odiaeresis": 214, "Odoubleacute": 469, "Ograve": 210, "Ohook": 16785102, "Ohorn": 16777632, "Ohornacute": 16785114, "Ohornbelowdot": 16785122, "Ohorngrave": 16785116, "Ohornhook": 16785118, "Ohorntilde": 16785120, "Omacron": 978, "Ooblique": 216, "Oslash": 216, "Otilde": 213, "Overlay1_Enable": 65144, "Overlay2_Enable": 65145, "P": 80, "Pabovedot": 16784982, "Page_Down": 65366, "Page_Up": 65365, "Pause": 65299, "PesetaSign": 16785575, "Pointer_Accelerate": 65274, "Pointer_Button1": 65257, "Pointer_Button2": 65258, "Pointer_Button3": 65259, "Pointer_Button4": 65260, "Pointer_Button5": 65261, "Pointer_Button_Dflt": 65256, "Pointer_DblClick1": 65263, "Pointer_DblClick2": 65264, "Pointer_DblClick3": 65265, "Pointer_DblClick4": 65266, "Pointer_DblClick5": 65267, "Pointer_DblClick_Dflt": 65262, "Pointer_DfltBtnNext": 65275, "Pointer_DfltBtnPrev": 65276, "Pointer_Down": 65251, "Pointer_DownLeft": 65254, "Pointer_DownRight": 65255, "Pointer_Drag1": 65269, "Pointer_Drag2": 65270, "Pointer_Drag3": 65271, "Pointer_Drag4": 65272, "Pointer_Drag5": 65277, "Pointer_Drag_Dflt": 65268, "Pointer_EnableKeys": 65273, "Pointer_Left": 65248, "Pointer_Right": 65249, "Pointer_Up": 65250, "Pointer_UpLeft": 65252, "Pointer_UpRight": 65253, "Prev_Virtual_Screen": 65233, "PreviousCandidate": 65342, "Print": 65377, "Prior": 65365, "Q": 81, "R": 82, "R1": 65490, "R10": 65499, "R11": 65500, "R12": 65501, "R13": 65502, "R14": 65503, "R15": 65504, "R2": 65491, "R3": 65492, "R4": 65493, "R5": 65494, "R6": 65495, "R7": 65496, "R8": 65497, "R9": 65498, "Racute": 448, "Rcaron": 472, "Rcedilla": 931, "Redo": 65382, "RepeatKeys_Enable": 65138, "Return": 65293, "Right": 65363, "Romaji": 65316, "RupeeSign": 16785576, "S": 83, "SCHWA": 16777615, "Sabovedot": 16784992, "Sacute": 422, "Scaron": 425, "Scedilla": 426, "Scircumflex": 734, "Scroll_Lock": 65300, "Select": 65376, "Serbian_DJE": 1713, "Serbian_DZE": 1727, "Serbian_JE": 1720, "Serbian_LJE": 1721, "Serbian_NJE": 1722, "Serbian_TSHE": 1723, "Serbian_dje": 1697, "Serbian_dze": 1711, "Serbian_je": 1704, "Serbian_lje": 1705, "Serbian_nje": 1706, "Serbian_tshe": 1707, "Shift_L": 65505, "Shift_Lock": 65510, "Shift_R": 65506, "SingleCandidate": 65340, "Sinh_a": 16780677, "Sinh_aa": 16780678, "Sinh_aa2": 16780751, "Sinh_ae": 16780679, "Sinh_ae2": 16780752, "Sinh_aee": 16780680, "Sinh_aee2": 16780753, "Sinh_ai": 16780691, "Sinh_ai2": 16780763, "Sinh_al": 16780746, "Sinh_au": 16780694, "Sinh_au2": 16780766, "Sinh_ba": 16780726, "Sinh_bha": 16780727, "Sinh_ca": 16780704, "Sinh_cha": 16780705, "Sinh_dda": 16780713, "Sinh_ddha": 16780714, "Sinh_dha": 16780719, "Sinh_dhha": 16780720, "Sinh_e": 16780689, "Sinh_e2": 16780761, "Sinh_ee": 16780690, "Sinh_ee2": 16780762, "Sinh_fa": 16780742, "Sinh_ga": 16780700, "Sinh_gha": 16780701, "Sinh_h2": 16780675, "Sinh_ha": 16780740, "Sinh_i": 16780681, "Sinh_i2": 16780754, "Sinh_ii": 16780682, "Sinh_ii2": 16780755, "Sinh_ja": 16780706, "Sinh_jha": 16780707, "Sinh_jnya": 16780709, "Sinh_ka": 16780698, "Sinh_kha": 16780699, "Sinh_kunddaliya": 16780788, "Sinh_la": 16780733, "Sinh_lla": 16780741, "Sinh_lu": 16780687, "Sinh_lu2": 16780767, "Sinh_luu": 16780688, "Sinh_luu2": 16780787, "Sinh_ma": 16780728, "Sinh_mba": 16780729, "Sinh_na": 16780721, "Sinh_ndda": 16780716, "Sinh_ndha": 16780723, "Sinh_ng": 16780674, "Sinh_ng2": 16780702, "Sinh_nga": 16780703, "Sinh_nja": 16780710, "Sinh_nna": 16780715, "Sinh_nya": 16780708, "Sinh_o": 16780692, "Sinh_o2": 16780764, "Sinh_oo": 16780693, "Sinh_oo2": 16780765, "Sinh_pa": 16780724, "Sinh_pha": 16780725, "Sinh_ra": 16780731, "Sinh_ri": 16780685, "Sinh_rii": 16780686, "Sinh_ru2": 16780760, "Sinh_ruu2": 16780786, "Sinh_sa": 16780739, "Sinh_sha": 16780737, "Sinh_ssha": 16780738, "Sinh_tha": 16780717, "Sinh_thha": 16780718, "Sinh_tta": 16780711, "Sinh_ttha": 16780712, "Sinh_u": 16780683, "Sinh_u2": 16780756, "Sinh_uu": 16780684, "Sinh_uu2": 16780758, "Sinh_va": 16780736, "Sinh_ya": 16780730, "SlowKeys_Enable": 65139, "StickyKeys_Enable": 65141, "Super_L": 65515, "Super_R": 65516, "Sys_Req": 65301, "T": 84, "THORN": 222, "Tab": 65289, "Tabovedot": 16785002, "Tcaron": 427, "Tcedilla": 478, "Terminate_Server": 65237, "Thai_baht": 3551, "Thai_bobaimai": 3514, "Thai_chochan": 3496, "Thai_chochang": 3498, "Thai_choching": 3497, "Thai_chochoe": 3500, "Thai_dochada": 3502, "Thai_dodek": 3508, "Thai_fofa": 3517, "Thai_fofan": 3519, "Thai_hohip": 3531, "Thai_honokhuk": 3534, "Thai_khokhai": 3490, "Thai_khokhon": 3493, "Thai_khokhuat": 3491, "Thai_khokhwai": 3492, "Thai_khorakhang": 3494, "Thai_kokai": 3489, "Thai_lakkhangyao": 3557, "Thai_lekchet": 3575, "Thai_lekha": 3573, "Thai_lekhok": 3574, "Thai_lekkao": 3577, "Thai_leknung": 3569, "Thai_lekpaet": 3576, "Thai_leksam": 3571, "Thai_leksi": 3572, "Thai_leksong": 3570, "Thai_leksun": 3568, "Thai_lochula": 3532, "Thai_loling": 3525, "Thai_lu": 3526, "Thai_maichattawa": 3563, "Thai_maiek": 3560, "Thai_maihanakat": 3537, "Thai_maihanakat_maitho": 3550, "Thai_maitaikhu": 3559, "Thai_maitho": 3561, "Thai_maitri": 3562, "Thai_maiyamok": 3558, "Thai_moma": 3521, "Thai_ngongu": 3495, "Thai_nikhahit": 3565, "Thai_nonen": 3507, "Thai_nonu": 3513, "Thai_oang": 3533, "Thai_paiyannoi": 3535, "Thai_phinthu": 3546, "Thai_phophan": 3518, "Thai_phophung": 3516, "Thai_phosamphao": 3520, "Thai_popla": 3515, "Thai_rorua": 3523, "Thai_ru": 3524, "Thai_saraa": 3536, "Thai_saraaa": 3538, "Thai_saraae": 3553, "Thai_saraaimaimalai": 3556, "Thai_saraaimaimuan": 3555, "Thai_saraam": 3539, "Thai_sarae": 3552, "Thai_sarai": 3540, "Thai_saraii": 3541, "Thai_sarao": 3554, "Thai_sarau": 3544, "Thai_saraue": 3542, "Thai_sarauee": 3543, "Thai_sarauu": 3545, "Thai_sorusi": 3529, "Thai_sosala": 3528, "Thai_soso": 3499, "Thai_sosua": 3530, "Thai_thanthakhat": 3564, "Thai_thonangmontho": 3505, "Thai_thophuthao": 3506, "Thai_thothahan": 3511, "Thai_thothan": 3504, "Thai_thothong": 3512, "Thai_thothung": 3510, "Thai_topatak": 3503, "Thai_totao": 3509, "Thai_wowaen": 3527, "Thai_yoyak": 3522, "Thai_yoying": 3501, "Thorn": 222, "Touroku": 65323, "Tslash": 940, "U": 85, "Uacute": 218, "Ubelowdot": 16785124, "Ubreve": 733, "Ucircumflex": 219, "Udiaeresis": 220, "Udoubleacute": 475, "Ugrave": 217, "Uhook": 16785126, "Uhorn": 16777647, "Uhornacute": 16785128, "Uhornbelowdot": 16785136, "Uhorngrave": 16785130, "Uhornhook": 16785132, "Uhorntilde": 16785134, "Ukrainian_GHE_WITH_UPTURN": 1725, "Ukrainian_I": 1718, "Ukrainian_IE": 1716, "Ukrainian_YI": 1719, "Ukrainian_ghe_with_upturn": 1709, "Ukrainian_i": 1702, "Ukrainian_ie": 1700, "Ukrainian_yi": 1703, "Ukranian_I": 1718, "Ukranian_JE": 1716, "Ukranian_YI": 1719, "Ukranian_i": 1702, "Ukranian_je": 1700, "Ukranian_yi": 1703, "Umacron": 990, "Undo": 65381, "Uogonek": 985, "Up": 65362, "Uring": 473, "Utilde": 989, "V": 86, "VoidSymbol": 16777215, "W": 87, "Wacute": 16785026, "Wcircumflex": 16777588, "Wdiaeresis": 16785028, "Wgrave": 16785024, "WonSign": 16785577, "X": 88, "XF86_AddFavorite": 269025081, "XF86_ApplicationLeft": 269025104, "XF86_ApplicationRight": 269025105, "XF86_AudioCycleTrack": 269025179, "XF86_AudioForward": 269025175, "XF86_AudioLowerVolume": 269025041, "XF86_AudioMedia": 269025074, "XF86_AudioMicMute": 269025202, "XF86_AudioMute": 269025042, "XF86_AudioNext": 269025047, "XF86_AudioPause": 269025073, "XF86_AudioPlay": 269025044, "XF86_AudioPreset": 269025206, "XF86_AudioPrev": 269025046, "XF86_AudioRaiseVolume": 269025043, "XF86_AudioRandomPlay": 269025177, "XF86_AudioRecord": 269025052, "XF86_AudioRepeat": 269025176, "XF86_AudioRewind": 269025086, "XF86_AudioStop": 269025045, "XF86_Away": 269025165, "XF86_Back": 269025062, "XF86_BackForward": 269025087, "XF86_Battery": 269025171, "XF86_Blue": 269025190, "XF86_Bluetooth": 269025172, "XF86_Book": 269025106, "XF86_BrightnessAdjust": 269025083, "XF86_CD": 269025107, "XF86_Calculater": 269025108, "XF86_Calculator": 269025053, "XF86_Calendar": 269025056, "XF86_Clear": 269025109, "XF86_ClearGrab": 269024801, "XF86_Close": 269025110, "XF86_Community": 269025085, "XF86_ContrastAdjust": 269025058, "XF86_Copy": 269025111, "XF86_Cut": 269025112, "XF86_CycleAngle": 269025180, "XF86_DOS": 269025114, "XF86_Display": 269025113, "XF86_Documents": 269025115, "XF86_Eject": 269025068, "XF86_Excel": 269025116, "XF86_Explorer": 269025117, "XF86_Favorites": 269025072, "XF86_Finance": 269025084, "XF86_Forward": 269025063, "XF86_FrameBack": 269025181, "XF86_FrameForward": 269025182, "XF86_FullScreen": 269025208, "XF86_Game": 269025118, "XF86_Go": 269025119, "XF86_Green": 269025188, "XF86_Hibernate": 269025192, "XF86_History": 269025079, "XF86_HomePage": 269025048, "XF86_HotLinks": 269025082, "XF86_KbdBrightnessDown": 269025030, "XF86_KbdBrightnessUp": 269025029, "XF86_KbdLightOnOff": 269025028, "XF86_Keyboard": 269025203, "XF86_Launch0": 269025088, "XF86_Launch1": 269025089, "XF86_Launch2": 269025090, "XF86_Launch3": 269025091, "XF86_Launch4": 269025092, "XF86_Launch5": 269025093, "XF86_Launch6": 269025094, "XF86_Launch7": 269025095, "XF86_Launch8": 269025096, "XF86_Launch9": 269025097, "XF86_LaunchA": 269025098, "XF86_LaunchB": 269025099, "XF86_LaunchC": 269025100, "XF86_LaunchD": 269025101, "XF86_LaunchE": 269025102, "XF86_LaunchF": 269025103, "XF86_LightBulb": 269025077, "XF86_LogGrabInfo": 269024805, "XF86_LogOff": 269025121, "XF86_LogWindowTree": 269024804, "XF86_MacroRecordStart": 268964528, "XF86_Mail": 269025049, "XF86_MailForward": 269025168, "XF86_Market": 269025122, "XF86_Meeting": 269025123, "XF86_Memo": 269025054, "XF86_MenuKB": 269025125, "XF86_MenuPB": 269025126, "XF86_Messenger": 269025166, "XF86_ModeLock": 269025025, "XF86_MonBrightnessCycle": 269025031, "XF86_MonBrightnessDown": 269025027, "XF86_MonBrightnessUp": 269025026, "XF86_Music": 269025170, "XF86_MyComputer": 269025075, "XF86_MySites": 269025127, "XF86_New": 269025128, "XF86_News": 269025129, "XF86_Next_VMode": 269024802, "XF86_OfficeHome": 269025130, "XF86_Open": 269025131, "XF86_OpenURL": 269025080, "XF86_Option": 269025132, "XF86_Paste": 269025133, "XF86_Phone": 269025134, "XF86_Pictures": 269025169, "XF86_PowerDown": 269025057, "XF86_PowerOff": 269025066, "XF86_Prev_VMode": 269024803, "XF86_Q": 269025136, "XF86_RFKill": 269025205, "XF86_Red": 269025187, "XF86_Refresh": 269025065, "XF86_Reload": 269025139, "XF86_Reply": 269025138, "XF86_RockerDown": 269025060, "XF86_RockerEnter": 269025061, "XF86_RockerUp": 269025059, "XF86_RotateWindows": 269025140, "XF86_RotationKB": 269025142, "XF86_RotationLockToggle": 269025207, "XF86_RotationPB": 269025141, "XF86_Save": 269025143, "XF86_ScreenSaver": 269025069, "XF86_ScrollClick": 269025146, "XF86_ScrollDown": 269025145, "XF86_ScrollUp": 269025144, "XF86_Search": 269025051, "XF86_Select": 269025184, "XF86_Send": 269025147, "XF86_Shop": 269025078, "XF86_Sleep": 269025071, "XF86_Spell": 269025148, "XF86_SplitScreen": 269025149, "XF86_Standby": 269025040, "XF86_Start": 269025050, "XF86_Stop": 269025064, "XF86_Subtitle": 269025178, "XF86_Support": 269025150, "XF86_Suspend": 269025191, "XF86_Switch_VT_1": 269024769, "XF86_Switch_VT_10": 269024778, "XF86_Switch_VT_11": 269024779, "XF86_Switch_VT_12": 269024780, "XF86_Switch_VT_2": 269024770, "XF86_Switch_VT_3": 269024771, "XF86_Switch_VT_4": 269024772, "XF86_Switch_VT_5": 269024773, "XF86_Switch_VT_6": 269024774, "XF86_Switch_VT_7": 269024775, "XF86_Switch_VT_8": 269024776, "XF86_Switch_VT_9": 269024777, "XF86_TaskPane": 269025151, "XF86_Terminal": 269025152, "XF86_Time": 269025183, "XF86_ToDoList": 269025055, "XF86_Tools": 269025153, "XF86_TopMenu": 269025186, "XF86_TouchpadOff": 269025201, "XF86_TouchpadOn": 269025200, "XF86_TouchpadToggle": 269025193, "XF86_Travel": 269025154, "XF86_UWB": 269025174, "XF86_Ungrab": 269024800, "XF86_User1KB": 269025157, "XF86_User2KB": 269025158, "XF86_UserPB": 269025156, "XF86_VendorHome": 269025076, "XF86_Video": 269025159, "XF86_View": 269025185, "XF86_WLAN": 269025173, "XF86_WWAN": 269025204, "XF86_WWW": 269025070, "XF86_WakeUp": 269025067, "XF86_WebCam": 269025167, "XF86_WheelButton": 269025160, "XF86_Word": 269025161, "XF86_Xfer": 269025162, "XF86_Yellow": 269025189, "XF86_ZoomIn": 269025163, "XF86_ZoomOut": 269025164, "XF86_iTouch": 269025120, "Xabovedot": 16785034, "Y": 89, "Yacute": 221, "Ybelowdot": 16785140, "Ycircumflex": 16777590, "Ydiaeresis": 5054, "Ygrave": 16785138, "Yhook": 16785142, "Ytilde": 16785144, "Z": 90, "Zabovedot": 431, "Zacute": 428, "Zcaron": 430, "Zen_Koho": 65341, "Zenkaku": 65320, "Zenkaku_Hankaku": 65322, "Zstroke": 16777653, "a": 97, "aacute": 225, "abelowdot": 16785057, "abovedot": 511, "abreve": 483, "abreveacute": 16785071, "abrevebelowdot": 16785079, "abrevegrave": 16785073, "abrevehook": 16785075, "abrevetilde": 16785077, "acircumflex": 226, "acircumflexacute": 16785061, "acircumflexbelowdot": 16785069, "acircumflexgrave": 16785063, "acircumflexhook": 16785065, "acircumflextilde": 16785067, "acute": 180, "adiaeresis": 228, "ae": 230, "agrave": 224, "ahook": 16785059, "amacron": 992, "ampersand": 38, "aogonek": 433, "apostrophe": 39, "approxeq": 16785992, "approximate": 2248, "aring": 229, "asciicircum": 94, "asciitilde": 126, "asterisk": 42, "at": 64, "atilde": 227, "b": 98, "babovedot": 16784899, "backslash": 92, "ballotcross": 2804, "bar": 124, "because": 16785973, "blank": 2527, "botintegral": 2213, "botleftparens": 2220, "botleftsqbracket": 2216, "botleftsummation": 2226, "botrightparens": 2222, "botrightsqbracket": 2218, "botrightsummation": 2230, "bott": 2550, "botvertsummationconnector": 2228, "braceleft": 123, "braceright": 125, "bracketleft": 91, "bracketright": 93, "braille_blank": 16787456, "braille_dot_1": 65521, "braille_dot_10": 65530, "braille_dot_2": 65522, "braille_dot_3": 65523, "braille_dot_4": 65524, "braille_dot_5": 65525, "braille_dot_6": 65526, "braille_dot_7": 65527, "braille_dot_8": 65528, "braille_dot_9": 65529, "braille_dots_1": 16787457, "braille_dots_12": 16787459, "braille_dots_123": 16787463, "braille_dots_1234": 16787471, "braille_dots_12345": 16787487, "braille_dots_123456": 16787519, "braille_dots_1234567": 16787583, "braille_dots_12345678": 16787711, "braille_dots_1234568": 16787647, "braille_dots_123457": 16787551, "braille_dots_1234578": 16787679, "braille_dots_123458": 16787615, "braille_dots_12346": 16787503, "braille_dots_123467": 16787567, "braille_dots_1234678": 16787695, "braille_dots_123468": 16787631, "braille_dots_12347": 16787535, "braille_dots_123478": 16787663, "braille_dots_12348": 16787599, "braille_dots_1235": 16787479, "braille_dots_12356": 16787511, "braille_dots_123567": 16787575, "braille_dots_1235678": 16787703, "braille_dots_123568": 16787639, "braille_dots_12357": 16787543, "braille_dots_123578": 16787671, "braille_dots_12358": 16787607, "braille_dots_1236": 16787495, "braille_dots_12367": 16787559, "braille_dots_123678": 16787687, "braille_dots_12368": 16787623, "braille_dots_1237": 16787527, "braille_dots_12378": 16787655, "braille_dots_1238": 16787591, "braille_dots_124": 16787467, "braille_dots_1245": 16787483, "braille_dots_12456": 16787515, "braille_dots_124567": 16787579, "braille_dots_1245678": 16787707, "braille_dots_124568": 16787643, "braille_dots_12457": 16787547, "braille_dots_124578": 16787675, "braille_dots_12458": 16787611, "braille_dots_1246": 16787499, "braille_dots_12467": 16787563, "braille_dots_124678": 16787691, "braille_dots_12468": 16787627, "braille_dots_1247": 16787531, "braille_dots_12478": 16787659, "braille_dots_1248": 16787595, "braille_dots_125": 16787475, "braille_dots_1256": 16787507, "braille_dots_12567": 16787571, "braille_dots_125678": 16787699, "braille_dots_12568": 16787635, "braille_dots_1257": 16787539, "braille_dots_12578": 16787667, "braille_dots_1258": 16787603, "braille_dots_126": 16787491, "braille_dots_1267": 16787555, "braille_dots_12678": 16787683, "braille_dots_1268": 16787619, "braille_dots_127": 16787523, "braille_dots_1278": 16787651, "braille_dots_128": 16787587, "braille_dots_13": 16787461, "braille_dots_134": 16787469, "braille_dots_1345": 16787485, "braille_dots_13456": 16787517, "braille_dots_134567": 16787581, "braille_dots_1345678": 16787709, "braille_dots_134568": 16787645, "braille_dots_13457": 16787549, "braille_dots_134578": 16787677, "braille_dots_13458": 16787613, "braille_dots_1346": 16787501, "braille_dots_13467": 16787565, "braille_dots_134678": 16787693, "braille_dots_13468": 16787629, "braille_dots_1347": 16787533, "braille_dots_13478": 16787661, "braille_dots_1348": 16787597, "braille_dots_135": 16787477, "braille_dots_1356": 16787509, "braille_dots_13567": 16787573, "braille_dots_135678": 16787701, "braille_dots_13568": 16787637, "braille_dots_1357": 16787541, "braille_dots_13578": 16787669, "braille_dots_1358": 16787605, "braille_dots_136": 16787493, "braille_dots_1367": 16787557, "braille_dots_13678": 16787685, "braille_dots_1368": 16787621, "braille_dots_137": 16787525, "braille_dots_1378": 16787653, "braille_dots_138": 16787589, "braille_dots_14": 16787465, "braille_dots_145": 16787481, "braille_dots_1456": 16787513, "braille_dots_14567": 16787577, "braille_dots_145678": 16787705, "braille_dots_14568": 16787641, "braille_dots_1457": 16787545, "braille_dots_14578": 16787673, "braille_dots_1458": 16787609, "braille_dots_146": 16787497, "braille_dots_1467": 16787561, "braille_dots_14678": 16787689, "braille_dots_1468": 16787625, "braille_dots_147": 16787529, "braille_dots_1478": 16787657, "braille_dots_148": 16787593, "braille_dots_15": 16787473, "braille_dots_156": 16787505, "braille_dots_1567": 16787569, "braille_dots_15678": 16787697, "braille_dots_1568": 16787633, "braille_dots_157": 16787537, "braille_dots_1578": 16787665, "braille_dots_158": 16787601, "braille_dots_16": 16787489, "braille_dots_167": 16787553, "braille_dots_1678": 16787681, "braille_dots_168": 16787617, "braille_dots_17": 16787521, "braille_dots_178": 16787649, "braille_dots_18": 16787585, "braille_dots_2": 16787458, "braille_dots_23": 16787462, "braille_dots_234": 16787470, "braille_dots_2345": 16787486, "braille_dots_23456": 16787518, "braille_dots_234567": 16787582, "braille_dots_2345678": 16787710, "braille_dots_234568": 16787646, "braille_dots_23457": 16787550, "braille_dots_234578": 16787678, "braille_dots_23458": 16787614, "braille_dots_2346": 16787502, "braille_dots_23467": 16787566, "braille_dots_234678": 16787694, "braille_dots_23468": 16787630, "braille_dots_2347": 16787534, "braille_dots_23478": 16787662, "braille_dots_2348": 16787598, "braille_dots_235": 16787478, "braille_dots_2356": 16787510, "braille_dots_23567": 16787574, "braille_dots_235678": 16787702, "braille_dots_23568": 16787638, "braille_dots_2357": 16787542, "braille_dots_23578": 16787670, "braille_dots_2358": 16787606, "braille_dots_236": 16787494, "braille_dots_2367": 16787558, "braille_dots_23678": 16787686, "braille_dots_2368": 16787622, "braille_dots_237": 16787526, "braille_dots_2378": 16787654, "braille_dots_238": 16787590, "braille_dots_24": 16787466, "braille_dots_245": 16787482, "braille_dots_2456": 16787514, "braille_dots_24567": 16787578, "braille_dots_245678": 16787706, "braille_dots_24568": 16787642, "braille_dots_2457": 16787546, "braille_dots_24578": 16787674, "braille_dots_2458": 16787610, "braille_dots_246": 16787498, "braille_dots_2467": 16787562, "braille_dots_24678": 16787690, "braille_dots_2468": 16787626, "braille_dots_247": 16787530, "braille_dots_2478": 16787658, "braille_dots_248": 16787594, "braille_dots_25": 16787474, "braille_dots_256": 16787506, "braille_dots_2567": 16787570, "braille_dots_25678": 16787698, "braille_dots_2568": 16787634, "braille_dots_257": 16787538, "braille_dots_2578": 16787666, "braille_dots_258": 16787602, "braille_dots_26": 16787490, "braille_dots_267": 16787554, "braille_dots_2678": 16787682, "braille_dots_268": 16787618, "braille_dots_27": 16787522, "braille_dots_278": 16787650, "braille_dots_28": 16787586, "braille_dots_3": 16787460, "braille_dots_34": 16787468, "braille_dots_345": 16787484, "braille_dots_3456": 16787516, "braille_dots_34567": 16787580, "braille_dots_345678": 16787708, "braille_dots_34568": 16787644, "braille_dots_3457": 16787548, "braille_dots_34578": 16787676, "braille_dots_3458": 16787612, "braille_dots_346": 16787500, "braille_dots_3467": 16787564, "braille_dots_34678": 16787692, "braille_dots_3468": 16787628, "braille_dots_347": 16787532, "braille_dots_3478": 16787660, "braille_dots_348": 16787596, "braille_dots_35": 16787476, "braille_dots_356": 16787508, "braille_dots_3567": 16787572, "braille_dots_35678": 16787700, "braille_dots_3568": 16787636, "braille_dots_357": 16787540, "braille_dots_3578": 16787668, "braille_dots_358": 16787604, "braille_dots_36": 16787492, "braille_dots_367": 16787556, "braille_dots_3678": 16787684, "braille_dots_368": 16787620, "braille_dots_37": 16787524, "braille_dots_378": 16787652, "braille_dots_38": 16787588, "braille_dots_4": 16787464, "braille_dots_45": 16787480, "braille_dots_456": 16787512, "braille_dots_4567": 16787576, "braille_dots_45678": 16787704, "braille_dots_4568": 16787640, "braille_dots_457": 16787544, "braille_dots_4578": 16787672, "braille_dots_458": 16787608, "braille_dots_46": 16787496, "braille_dots_467": 16787560, "braille_dots_4678": 16787688, "braille_dots_468": 16787624, "braille_dots_47": 16787528, "braille_dots_478": 16787656, "braille_dots_48": 16787592, "braille_dots_5": 16787472, "braille_dots_56": 16787504, "braille_dots_567": 16787568, "braille_dots_5678": 16787696, "braille_dots_568": 16787632, "braille_dots_57": 16787536, "braille_dots_578": 16787664, "braille_dots_58": 16787600, "braille_dots_6": 16787488, "braille_dots_67": 16787552, "braille_dots_678": 16787680, "braille_dots_68": 16787616, "braille_dots_7": 16787520, "braille_dots_78": 16787648, "braille_dots_8": 16787584, "breve": 418, "brokenbar": 166, "c": 99, "c_h": 65187, "cabovedot": 741, "cacute": 486, "careof": 2744, "caret": 2812, "caron": 439, "ccaron": 488, "ccedilla": 231, "ccircumflex": 742, "cedilla": 184, "cent": 162, "ch": 65184, "checkerboard": 2529, "checkmark": 2803, "circle": 3023, "club": 2796, "colon": 58, "combining_acute": 16777985, "combining_belowdot": 16778019, "combining_grave": 16777984, "combining_hook": 16777993, "combining_tilde": 16777987, "comma": 44, "containsas": 16785931, "copyright": 169, "cr": 2532, "crossinglines": 2542, "cuberoot": 16785947, "currency": 164, "cursor": 2815, "d": 100, "dabovedot": 16784907, "dagger": 2801, "dcaron": 495, "dead_A": 65153, "dead_E": 65155, "dead_I": 65157, "dead_O": 65159, "dead_SCHWA": 65163, "dead_U": 65161, "dead_a": 65152, "dead_abovecomma": 65124, "dead_abovedot": 65110, "dead_abovereversedcomma": 65125, "dead_abovering": 65112, "dead_acute": 65105, "dead_belowbreve": 65131, "dead_belowcircumflex": 65129, "dead_belowcomma": 65134, "dead_belowdiaeresis": 65132, "dead_belowdot": 65120, "dead_belowmacron": 65128, "dead_belowring": 65127, "dead_belowtilde": 65130, "dead_breve": 65109, "dead_capital_schwa": 65163, "dead_caron": 65114, "dead_cedilla": 65115, "dead_circumflex": 65106, "dead_currency": 65135, "dead_dasia": 65125, "dead_diaeresis": 65111, "dead_doubleacute": 65113, "dead_doublegrave": 65126, "dead_e": 65154, "dead_grave": 65104, "dead_greek": 65164, "dead_hamza": 65165, "dead_hook": 65121, "dead_horn": 65122, "dead_i": 65156, "dead_invertedbreve": 65133, "dead_iota": 65117, "dead_macron": 65108, "dead_o": 65158, "dead_ogonek": 65116, "dead_perispomeni": 65107, "dead_psili": 65124, "dead_schwa": 65162, "dead_semivoiced_sound": 65119, "dead_small_schwa": 65162, "dead_stroke": 65123, "dead_tilde": 65107, "dead_u": 65160, "dead_voiced_sound": 65118, "decimalpoint": 2749, "degree": 176, "diaeresis": 168, "diamond": 2797, "digitspace": 2725, "dintegral": 16785964, "division": 247, "dollar": 36, "doubbaselinedot": 2735, "doubleacute": 445, "doubledagger": 2802, "doublelowquotemark": 2814, "downarrow": 2302, "downcaret": 2984, "downshoe": 3030, "downstile": 3012, "downtack": 3010, "dstroke": 496, "e": 101, "eabovedot": 1004, "eacute": 233, "ebelowdot": 16785081, "ecaron": 492, "ecircumflex": 234, "ecircumflexacute": 16785087, "ecircumflexbelowdot": 16785095, "ecircumflexgrave": 16785089, "ecircumflexhook": 16785091, "ecircumflextilde": 16785093, "ediaeresis": 235, "egrave": 232, "ehook": 16785083, "eightsubscript": 16785544, "eightsuperior": 16785528, "elementof": 16785928, "ellipsis": 2734, "em3space": 2723, "em4space": 2724, "emacron": 954, "emdash": 2729, "emfilledcircle": 2782, "emfilledrect": 2783, "emopencircle": 2766, "emopenrectangle": 2767, "emptyset": 16785925, "emspace": 2721, "endash": 2730, "enfilledcircbullet": 2790, "enfilledsqbullet": 2791, "eng": 959, "enopencircbullet": 2784, "enopensquarebullet": 2785, "enspace": 2722, "eogonek": 490, "equal": 61, "eth": 240, "etilde": 16785085, "exclam": 33, "exclamdown": 161, "ezh": 16777874, "f": 102, "fabovedot": 16784927, "femalesymbol": 2808, "ff": 2531, "figdash": 2747, "filledlefttribullet": 2780, "filledrectbullet": 2779, "filledrighttribullet": 2781, "filledtribulletdown": 2793, "filledtribulletup": 2792, "fiveeighths": 2757, "fivesixths": 2743, "fivesubscript": 16785541, "fivesuperior": 16785525, "fourfifths": 2741, "foursubscript": 16785540, "foursuperior": 16785524, "fourthroot": 16785948, "function": 2294, "g": 103, "gabovedot": 757, "gbreve": 699, "gcaron": 16777703, "gcedilla": 955, "gcircumflex": 760, "grave": 96, "greater": 62, "greaterthanequal": 2238, "guillemetleft": 171, "guillemetright": 187, "guillemotleft": 171, "guillemotright": 187, "h": 104, "hairspace": 2728, "hcircumflex": 694, "heart": 2798, "hebrew_aleph": 3296, "hebrew_ayin": 3314, "hebrew_bet": 3297, "hebrew_beth": 3297, "hebrew_chet": 3303, "hebrew_dalet": 3299, "hebrew_daleth": 3299, "hebrew_doublelowline": 3295, "hebrew_finalkaph": 3306, "hebrew_finalmem": 3309, "hebrew_finalnun": 3311, "hebrew_finalpe": 3315, "hebrew_finalzade": 3317, "hebrew_finalzadi": 3317, "hebrew_gimel": 3298, "hebrew_gimmel": 3298, "hebrew_he": 3300, "hebrew_het": 3303, "hebrew_kaph": 3307, "hebrew_kuf": 3319, "hebrew_lamed": 3308, "hebrew_mem": 3310, "hebrew_nun": 3312, "hebrew_pe": 3316, "hebrew_qoph": 3319, "hebrew_resh": 3320, "hebrew_samech": 3313, "hebrew_samekh": 3313, "hebrew_shin": 3321, "hebrew_taf": 3322, "hebrew_taw": 3322, "hebrew_tet": 3304, "hebrew_teth": 3304, "hebrew_waw": 3301, "hebrew_yod": 3305, "hebrew_zade": 3318, "hebrew_zadi": 3318, "hebrew_zain": 3302, "hebrew_zayin": 3302, "hexagram": 2778, "horizconnector": 2211, "horizlinescan1": 2543, "horizlinescan3": 2544, "horizlinescan5": 2545, "horizlinescan7": 2546, "horizlinescan9": 2547, "hstroke": 689, "ht": 2530, "hyphen": 173, "i": 105, "iacute": 237, "ibelowdot": 16785099, "ibreve": 16777517, "icircumflex": 238, "identical": 2255, "idiaeresis": 239, "idotless": 697, "ifonlyif": 2253, "igrave": 236, "ihook": 16785097, "imacron": 1007, "implies": 2254, "includedin": 2266, "includes": 2267, "infinity": 2242, "integral": 2239, "intersection": 2268, "iogonek": 999, "itilde": 949, "j": 106, "jcircumflex": 700, "jot": 3018, "k": 107, "kana_A": 1201, "kana_CHI": 1217, "kana_E": 1204, "kana_FU": 1228, "kana_HA": 1226, "kana_HE": 1229, "kana_HI": 1227, "kana_HO": 1230, "kana_HU": 1228, "kana_I": 1202, "kana_KA": 1206, "kana_KE": 1209, "kana_KI": 1207, "kana_KO": 1210, "kana_KU": 1208, "kana_MA": 1231, "kana_ME": 1234, "kana_MI": 1232, "kana_MO": 1235, "kana_MU": 1233, "kana_N": 1245, "kana_NA": 1221, "kana_NE": 1224, "kana_NI": 1222, "kana_NO": 1225, "kana_NU": 1223, "kana_O": 1205, "kana_RA": 1239, "kana_RE": 1242, "kana_RI": 1240, "kana_RO": 1243, "kana_RU": 1241, "kana_SA": 1211, "kana_SE": 1214, "kana_SHI": 1212, "kana_SO": 1215, "kana_SU": 1213, "kana_TA": 1216, "kana_TE": 1219, "kana_TI": 1217, "kana_TO": 1220, "kana_TSU": 1218, "kana_TU": 1218, "kana_U": 1203, "kana_WA": 1244, "kana_WO": 1190, "kana_YA": 1236, "kana_YO": 1238, "kana_YU": 1237, "kana_a": 1191, "kana_closingbracket": 1187, "kana_comma": 1188, "kana_conjunctive": 1189, "kana_e": 1194, "kana_fullstop": 1185, "kana_i": 1192, "kana_middledot": 1189, "kana_o": 1195, "kana_openingbracket": 1186, "kana_switch": 65406, "kana_tsu": 1199, "kana_tu": 1199, "kana_u": 1193, "kana_ya": 1196, "kana_yo": 1198, "kana_yu": 1197, "kappa": 930, "kcedilla": 1011, "kra": 930, "l": 108, "lacute": 485, "latincross": 2777, "lbelowdot": 16784951, "lcaron": 437, "lcedilla": 950, "leftanglebracket": 2748, "leftarrow": 2299, "leftcaret": 2979, "leftdoublequotemark": 2770, "leftmiddlecurlybrace": 2223, "leftopentriangle": 2764, "leftpointer": 2794, "leftradical": 2209, "leftshoe": 3034, "leftsinglequotemark": 2768, "leftt": 2548, "lefttack": 3036, "less": 60, "lessthanequal": 2236, "lf": 2533, "logicaland": 2270, "logicalor": 2271, "lowleftcorner": 2541, "lowrightcorner": 2538, "lstroke": 435, "m": 109, "mabovedot": 16784961, "macron": 175, "malesymbol": 2807, "maltesecross": 2800, "marker": 2751, "masculine": 186, "minus": 45, "minutes": 2774, "mu": 181, "multiply": 215, "musicalflat": 2806, "musicalsharp": 2805, "n": 110, "nabla": 2245, "nacute": 497, "ncaron": 498, "ncedilla": 1009, "ninesubscript": 16785545, "ninesuperior": 16785529, "nl": 2536, "nobreakspace": 160, "notapproxeq": 16785991, "notelementof": 16785929, "notequal": 2237, "notidentical": 16786018, "notsign": 172, "ntilde": 241, "numbersign": 35, "numerosign": 1712, "o": 111, "oacute": 243, "obarred": 16777845, "obelowdot": 16785101, "ocaron": 16777682, "ocircumflex": 244, "ocircumflexacute": 16785105, "ocircumflexbelowdot": 16785113, "ocircumflexgrave": 16785107, "ocircumflexhook": 16785109, "ocircumflextilde": 16785111, "odiaeresis": 246, "odoubleacute": 501, "oe": 5053, "ogonek": 434, "ograve": 242, "ohook": 16785103, "ohorn": 16777633, "ohornacute": 16785115, "ohornbelowdot": 16785123, "ohorngrave": 16785117, "ohornhook": 16785119, "ohorntilde": 16785121, "omacron": 1010, "oneeighth": 2755, "onefifth": 2738, "onehalf": 189, "onequarter": 188, "onesixth": 2742, "onesubscript": 16785537, "onesuperior": 185, "onethird": 2736, "ooblique": 248, "openrectbullet": 2786, "openstar": 2789, "opentribulletdown": 2788, "opentribulletup": 2787, "ordfeminine": 170, "ordmasculine": 186, "oslash": 248, "otilde": 245, "overbar": 3008, "overline": 1150, "p": 112, "pabovedot": 16784983, "paragraph": 182, "parenleft": 40, "parenright": 41, "partdifferential": 16785922, "partialderivative": 2287, "percent": 37, "period": 46, "periodcentered": 183, "permille": 2773, "phonographcopyright": 2811, "plus": 43, "plusminus": 177, "prescription": 2772, "prolongedsound": 1200, "punctspace": 2726, "q": 113, "quad": 3020, "question": 63, "questiondown": 191, "quotedbl": 34, "quoteleft": 96, "quoteright": 39, "r": 114, "racute": 480, "radical": 2262, "rcaron": 504, "rcedilla": 947, "registered": 174, "rightanglebracket": 2750, "rightarrow": 2301, "rightcaret": 2982, "rightdoublequotemark": 2771, "rightmiddlecurlybrace": 2224, "rightmiddlesummation": 2231, "rightopentriangle": 2765, "rightpointer": 2795, "rightshoe": 3032, "rightsinglequotemark": 2769, "rightt": 2549, "righttack": 3068, "s": 115, "sabovedot": 16784993, "sacute": 438, "scaron": 441, "scedilla": 442, "schwa": 16777817, "scircumflex": 766, "script_switch": 65406, "seconds": 2775, "section": 167, "semicolon": 59, "semivoicedsound": 1247, "seveneighths": 2758, "sevensubscript": 16785543, "sevensuperior": 16785527, "signaturemark": 2762, "signifblank": 2732, "similarequal": 2249, "singlelowquotemark": 2813, "sixsubscript": 16785542, "sixsuperior": 16785526, "slash": 47, "soliddiamond": 2528, "space": 32, "squareroot": 16785946, "ssharp": 223, "sterling": 163, "stricteq": 16786019, "t": 116, "tabovedot": 16785003, "tcaron": 443, "tcedilla": 510, "telephone": 2809, "telephonerecorder": 2810, "therefore": 2240, "thinspace": 2727, "thorn": 254, "threeeighths": 2756, "threefifths": 2740, "threequarters": 190, "threesubscript": 16785539, "threesuperior": 179, "tintegral": 16785965, "topintegral": 2212, "topleftparens": 2219, "topleftradical": 2210, "topleftsqbracket": 2215, "topleftsummation": 2225, "toprightparens": 2221, "toprightsqbracket": 2217, "toprightsummation": 2229, "topt": 2551, "topvertsummationconnector": 2227, "trademark": 2761, "trademarkincircle": 2763, "tslash": 956, "twofifths": 2739, "twosubscript": 16785538, "twosuperior": 178, "twothirds": 2737, "u": 117, "uacute": 250, "ubelowdot": 16785125, "ubreve": 765, "ucircumflex": 251, "udiaeresis": 252, "udoubleacute": 507, "ugrave": 249, "uhook": 16785127, "uhorn": 16777648, "uhornacute": 16785129, "uhornbelowdot": 16785137, "uhorngrave": 16785131, "uhornhook": 16785133, "uhorntilde": 16785135, "umacron": 1022, "underbar": 3014, "underscore": 95, "union": 2269, "uogonek": 1017, "uparrow": 2300, "upcaret": 2985, "upleftcorner": 2540, "uprightcorner": 2539, "upshoe": 3011, "upstile": 3027, "uptack": 3022, "uring": 505, "utilde": 1021, "v": 118, "variation": 2241, "vertbar": 2552, "vertconnector": 2214, "voicedsound": 1246, "vt": 2537, "w": 119, "wacute": 16785027, "wcircumflex": 16777589, "wdiaeresis": 16785029, "wgrave": 16785025, "x": 120, "xabovedot": 16785035, "y": 121, "yacute": 253, "ybelowdot": 16785141, "ycircumflex": 16777591, "ydiaeresis": 255, "yen": 165, "ygrave": 16785139, "yhook": 16785143, "ytilde": 16785145, "z": 122, "zabovedot": 447, "zacute": 444, "zcaron": 446, "zerosubscript": 16785536, "zerosuperior": 16785520, "zstroke": 16777654, } Solaar-1.1.20/lib/logitech_receiver/000077500000000000000000000000001522022367600172515ustar00rootroot00000000000000Solaar-1.1.20/lib/logitech_receiver/__init__.py000066400000000000000000000017311522022367600213640ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Low-level interface for devices using Logitech HID++ protocol. Uses the HID api exposed through hidapi_impl.py, a Python thin layer over a native implementation. """ import logging logger = logging.getLogger(__name__) Solaar-1.1.20/lib/logitech_receiver/advanced_para_eq.py000066400000000000000000000411421522022367600230620ustar00rootroot00000000000000## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """AdvancedParaEQ (0x020D) helpers. The device handles biquad coefficient computation — we transmit only per-band filter-type + frequency + gain; the DSP does the rest. V0/V1 wire format: 3-byte band stride [freq_hi, freq_lo, gain_i8], gain is whole dB; getEQInfos returns 5 bytes [bandCount, dbRange, caps, dbMin, dbMax]. V2 wire format: 1-byte header [direction_echo], then N × 5-byte band stride [freq_hi, freq_lo, filter_type, gain_hi, gain_lo], with 0..3 trailer bytes (opaque, ignored). The parser consumes 5-byte chunks until <5 bytes remain or a freq=0 sentinel is hit. Frequency u16 BE in Hz; gain u16 BE in **offset-binary**: raw 0..(steps-1) maps linearly to gain_min..gain_max (so on G522 with steps=241 / gain=[-6..6], raw=120 = 0 dB). getEQInfos returns 13 bytes with gain bounds + step count, format enum, XY-support flag, and onboard preset counts. (The protocol spec lists a 2-byte header [dir_echo, slot_echo] for getCustomEQ, but G522 firmware via the centurion bridge omits the slot_echo and emits a 1-byte header that matches getEQDefaults. Verified against pcap traces of LGHUB ↔ G522 LIGHTSPEED traffic.) """ from __future__ import annotations import logging import struct from .hidpp20_constants import SupportedFeature logger = logging.getLogger(__name__) DIRECTION_PLAYBACK = 0 DIRECTION_CAPTURE = 1 # V2 filter-type taxonomy (byte [+0] of each band). 0x16 is observed on # G522 for every band of its factory custom slot at ISO third-octave # centers, treated as peaking. Other filter kinds (LP, shelf, notch …) # need a live probe per device firmware to enumerate. FILTER_TYPE_HP = 0x00 FILTER_TYPE_PEAKING_G522 = 0x16 FILTER_TYPE_PEAKING = 0x78 FILTER_TYPE_NAMES = { FILTER_TYPE_HP: "HP", FILTER_TYPE_PEAKING_G522: "peaking", FILTER_TYPE_PEAKING: "peaking", } def _get_version(device) -> int: return device.features.get_feature_version(SupportedFeature.HEADSET_ADVANCED_PARA_EQ) or 0 def get_advanced_eq_info(device): """Query getEQInfos (function 0). Returns a dict or None. Common fields: version int feature version (0, 1, 2) gain_min_db int signed whole-dB min gain_max_db int signed whole-dB max step_db float dB per raw LSB (1.0 on V0/V1) V0/V1 only: band_count int number of bands (from wire byte 0) db_range int raw byte 1 capabilities int raw byte 2 V2 only: gain_steps int discrete gain positions format int 0=CLASSIC, 1=STYLES supports_xy bool onboard_ro_preset_count int factory preset slots onboard_custom_preset_count int user-writable preset slots """ version = _get_version(device) result = device.feature_request(SupportedFeature.HEADSET_ADVANCED_PARA_EQ, 0x00) if result is None: logger.debug("AdvancedParaEQ getEQInfos V%d: feature_request returned None", version) return None if version >= 2: if len(result) < 13: logger.debug("AdvancedParaEQ getEQInfos V2: short response len=%d %s", len(result), result.hex()) return None gain_min = struct.unpack("b", bytes([result[2]]))[0] gain_max = struct.unpack("b", bytes([result[3]]))[0] gain_steps = struct.unpack(">H", result[4:6])[0] fmt = result[6] supports_xy = bool(result[7]) ro_presets = result[9] custom_presets = result[10] step_db = (gain_max - gain_min) / max(1, gain_steps - 1) info = { "version": 2, "gain_min_db": gain_min, "gain_max_db": gain_max, "gain_steps": gain_steps, "step_db": step_db, "format": fmt, "supports_xy": supports_xy, "onboard_ro_preset_count": ro_presets, "onboard_custom_preset_count": custom_presets, } logger.debug( "AdvancedParaEQ getEQInfos V2: gain=[%d,%d] steps=%d step_db=%.4f format=%d xy=%s " "presets_ro=%d presets_custom=%d", gain_min, gain_max, gain_steps, step_db, fmt, supports_xy, ro_presets, custom_presets, ) device._advanced_eq_info = info return info # V0 / V1 if len(result) < 5: logger.debug("AdvancedParaEQ getEQInfos V%d: short response len=%d %s", version, len(result), result.hex()) return None band_count = result[0] db_range = result[1] caps = result[2] gain_min = struct.unpack("b", bytes([result[3]]))[0] gain_max = struct.unpack("b", bytes([result[4]]))[0] info = { "version": version, "band_count": band_count, "db_range": db_range, "capabilities": caps, "gain_min_db": gain_min, "gain_max_db": gain_max, "step_db": 1.0, } logger.debug( "AdvancedParaEQ getEQInfos V%d: bands=%d dbRange=%d caps=0x%02X gain=[%d,%d]", version, band_count, db_range, caps, gain_min, gain_max, ) device._advanced_eq_info = info return info def get_advanced_eq_active_slot(device, direction=DIRECTION_PLAYBACK): """Query getActiveEQ (function 3). Returns the active slot index, or None.""" result = device.feature_request(SupportedFeature.HEADSET_ADVANCED_PARA_EQ, 0x30, direction) if result is None: logger.debug("AdvancedParaEQ getActiveEQ(dir=%d): feature_request returned None", direction) return None if len(result) < 1: logger.debug("AdvancedParaEQ getActiveEQ(dir=%d): empty response", direction) return None logger.debug("AdvancedParaEQ getActiveEQ(dir=%d): slot=%d", direction, result[0]) return result[0] def parse_v2_bands(result: bytes, info: dict | None): """Parse a V2 getCustomEQ / getEQDefaults response. Wire layout (see module docstring): [direction_echo] (1-byte header) N × [freq_hi, freq_lo, filter_type, gain_hi, gain_lo] (5 bytes) [trailer …] (0..3 bytes, ignored) Gain is offset-binary against `info`'s gain bounds: gain_db = gain_min + (gain_max - gain_min) * raw / (steps - 1) `info` is the dict returned by `get_advanced_eq_info`. If absent we fall back to step_db=1.0 (and log via the caller, not here) which is wrong but won't crash. Returns list of (filter_type_byte, freq_hz, gain_db) tuples, or None if the payload is too short to contain a header. Empty payload with valid header returns []. Bands with freq=0 are treated as the end-of-bands sentinel (matches V0/V1 behavior at lines below). """ if result is None or len(result) < 1: return None payload = result[1:] # skip [dir_echo] band_size = 5 if info: gain_min = info.get("gain_min_db", -6) gain_max = info.get("gain_max_db", 6) steps = info.get("gain_steps", 241) else: gain_min, gain_max, steps = 0, 0, 1 # produces gain_db=0 for any raw bands = [] for i in range(len(payload) // band_size): e = payload[i * band_size : (i + 1) * band_size] freq_hz = (e[0] << 8) | e[1] filter_type = e[2] gain_raw = (e[3] << 8) | e[4] if freq_hz == 0: break # disabled band — end-of-bands sentinel if steps > 1: gain_db = gain_min + (gain_max - gain_min) * gain_raw / (steps - 1) else: gain_db = 0.0 bands.append((filter_type, freq_hz, float(gain_db))) return bands def _band_label(filter_type_byte: int, freq_hz: int) -> str: kind = FILTER_TYPE_NAMES.get(filter_type_byte, f"type-0x{filter_type_byte:02X}") if filter_type_byte == FILTER_TYPE_HP: return f"HP {freq_hz} Hz" return f"{freq_hz} Hz" if kind == "peaking" else f"{kind} {freq_hz} Hz" def get_advanced_eq_defaults(device, direction=DIRECTION_PLAYBACK, slot=0): """Query getEQDefaults (function 5). Same per-band layout as getCustomEQ. Returns list of (filter_type_byte, freq_hz, gain_db) tuples, or None. V0/V1 callers receive (FILTER_TYPE_PEAKING, freq_hz, gain_db) for compatibility with the V2 tuple shape. """ version = _get_version(device) result = device.feature_request(SupportedFeature.HEADSET_ADVANCED_PARA_EQ, 0x50, direction, slot) if result is None: logger.debug( "AdvancedParaEQ getEQDefaults V%d (dir=%d slot=%d): feature_request returned None", version, direction, slot, ) return None if version >= 2: info = getattr(device, "_advanced_eq_info", None) bands = parse_v2_bands(result, info) if bands is None: logger.debug( "AdvancedParaEQ getEQDefaults V2 (dir=%d slot=%d): payload too short raw=%s", direction, slot, result.hex(), ) return None logger.debug( "AdvancedParaEQ getEQDefaults V2 (dir=%d slot=%d): %d band(s) raw=%s %s", direction, slot, len(bands), result.hex(), [_band_label(t, f) + f" {round(g, 2)}dB" for t, f, g in bands], ) return bands # V0/V1 legacy 3-byte stride. bands = [] offset = 0 while offset + 3 <= len(result): freq = struct.unpack(">H", result[offset : offset + 2])[0] if freq == 0: break gain_db = struct.unpack("b", bytes([result[offset + 2]]))[0] bands.append((FILTER_TYPE_PEAKING, freq, float(gain_db))) offset += 3 logger.debug( "AdvancedParaEQ getEQDefaults V%d (dir=%d slot=%d): %d band(s)", version, direction, slot, len(bands), ) return bands def get_advanced_eq_friendly_name(device, direction=DIRECTION_PLAYBACK, slot=0): """Query getEQFriendlyName (function 6). Returns the UTF-8 preset name or None.""" result = device.feature_request(SupportedFeature.HEADSET_ADVANCED_PARA_EQ, 0x60, direction, slot) if result is None or len(result) < 1: return None name_len = result[0] if 1 + name_len > len(result): name_len = len(result) - 1 try: name = bytes(result[1 : 1 + name_len]).decode("utf-8", errors="replace") except Exception: name = result[1 : 1 + name_len].hex() return name def probe_advanced_eq_slots(device, direction=DIRECTION_PLAYBACK, info=None): """Probe every advertised EQ slot via getCustomEQ and cache which respond. Some firmware (G522) advertises N slots via getEQInfos but only honors a subset for getCustomEQ / setActiveEQ — the rest return 0x0B NOT_SUPPORTED. This iterates 0..total-1 and records which slots actually have data. Result is cached on `device._advanced_eq_working_slots` as a list of `(slot_index, name, bands)` tuples. The HeadsetActiveEQPreset selector builds its choices from this list; the HeadsetAdvancedEQ panel uses it to skip dead slots in its diagnostic output. Logs each working slot's bands at INFO and a summary line indicating how many of the advertised slots are actually accessible. """ cached = getattr(device, "_advanced_eq_working_slots", None) if cached is not None: return cached if info is None: info = getattr(device, "_advanced_eq_info", None) or get_advanced_eq_info(device) if not info: return [] ro_count = info.get("onboard_ro_preset_count", 0) or 0 custom_count = info.get("onboard_custom_preset_count", 0) or 0 total = ro_count + custom_count if total == 0: return [] def probe(slot): bands = get_advanced_eq_params(device, direction=direction, slot=slot) if bands is None: return None name = get_advanced_eq_friendly_name(device, direction=direction, slot=slot) kind = "factory" if slot < ro_count else "custom" logger.debug( "AdvancedParaEQ %s preset slot=%d (dir=%d) name=%r: %s", kind, slot, direction, name, [f"{_band_label(t, f)} {round(g, 2)}dB" for t, f, g in bands], ) return (slot, name, bands) working = [] # Slot 0 is canonical. If it fails the device is unusable; bail. entry = probe(0) if entry is None: device._advanced_eq_working_slots = working return working working.append(entry) # Slot 1 acts as a "multi-slot capable?" canary. G522 firmware # advertises 16 slots but only honors slot 0; LGHUB itself never # touches slots > 0 on this device. When the canary fails, skip the # remaining 14 NOT_SUPPORTED probes. if total > 1: entry = probe(1) if entry is None: logger.debug( "AdvancedParaEQ: slot 1 returned NOT_SUPPORTED; " "firmware advertises %d slots but only honors slot 0", total, ) device._advanced_eq_working_slots = working return working working.append(entry) for slot in range(2, total): entry = probe(slot) if entry is not None: working.append(entry) device._advanced_eq_working_slots = working logger.debug( "AdvancedParaEQ working slots on dir=%d: %d of %d advertised %s", direction, len(working), total, [w[0] for w in working], ) return working # Backward-compat alias kept until external callers are migrated. probe_all_presets = probe_advanced_eq_slots def get_advanced_eq_params(device, direction=DIRECTION_PLAYBACK, slot=0): """Query getCustomEQ (function 1). Returns list of (filter_type, freq_hz, gain_db) or None. V0/V1: filter_type is always FILTER_TYPE_PEAKING (synthesized), freq is raw Hz from wire, gain is whole dB. V2: filter_type comes from the wire (0x00=HP, 0x78=peaking), freq is raw Hz, gain is int16 × step_db. step_db for V2 is cached on the device by get_advanced_eq_info. """ version = _get_version(device) result = device.feature_request(SupportedFeature.HEADSET_ADVANCED_PARA_EQ, 0x10, direction, slot) if result is None: logger.debug( "AdvancedParaEQ getCustomEQ V%d (dir=%d slot=%d): feature_request returned None", version, direction, slot, ) return None if version >= 2: info = getattr(device, "_advanced_eq_info", None) if not info: logger.warning("AdvancedParaEQ getCustomEQ V2: no cached getEQInfos — gain values will be wrong") bands = parse_v2_bands(result, info) if bands is None: logger.debug( "AdvancedParaEQ getCustomEQ V2 (dir=%d slot=%d): payload too short raw=%s", direction, slot, result.hex(), ) return None step_db = info["step_db"] if info and "step_db" in info else 1.0 # Log raw=... too so we can compare wire shapes across firmware # variants and across get-fns (getCustomEQ vs getEQDefaults). logger.debug( "AdvancedParaEQ getCustomEQ V2 (dir=%d slot=%d): %d band(s) step_db=%.4f raw=%s %s", direction, slot, len(bands), step_db, result.hex(), [f"{_band_label(t, f)} {round(g, 2)}dB" for t, f, g in bands], ) return bands # V0 / V1 bands = [] offset = 0 while offset + 3 <= len(result): freq = struct.unpack(">H", result[offset : offset + 2])[0] if freq == 0: break gain_db = struct.unpack("b", bytes([result[offset + 2]]))[0] bands.append((FILTER_TYPE_PEAKING, freq, float(gain_db))) offset += 3 logger.debug( "AdvancedParaEQ getCustomEQ V%d (dir=%d slot=%d): parsed %d band(s) %s", version, direction, slot, len(bands), bands, ) return bands Solaar-1.1.20/lib/logitech_receiver/base.py000066400000000000000000001052671522022367600205500ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Base low-level functions as API for upper layers.""" from __future__ import annotations import dataclasses import logging import platform import struct import threading import typing from contextlib import contextmanager from random import getrandbits from time import time from typing import Any from typing import Callable from . import base_usb from . import common from . import descriptors from . import exceptions from .common import LOGITECH_VENDOR_ID from .common import BusID from .hidpp10_constants import ErrorCode as Hidpp10ErrorCode from .hidpp20_constants import ErrorCode as Hidpp20ErrorCode if typing.TYPE_CHECKING: import gi from hidapi.common import DeviceInfo gi.require_version("Gdk", "3.0") from gi.repository import GLib # NOQA: E402 if platform.system() == "Linux": import hidapi.udev_impl as hidapi else: import hidapi.hidapi_impl as hidapi logger = logging.getLogger(__name__) class HIDProtocol(typing.Protocol): def find_paired_node_wpid(self, receiver_path: str, index: int): ... def find_paired_node(self, receiver_path: str, index: int, timeout: int): ... def open(self, vendor_id, product_id, serial=None): ... def open_path(self, path) -> int: ... def enumerate(self, filter_func: Callable[[int, int, int, bool, bool], dict[str, typing.Any]]) -> DeviceInfo: ... def monitor_glib( self, glib: GLib, callback: Callable, filter_func: Callable[[int, int, int, bool, bool], dict[str, typing.Any]] ) -> None: ... def read(self, device_handle, bytes_count, timeout_ms): ... def write(self, device_handle: int, data: bytes) -> int: ... def close(self, device_handle) -> None: ... SHORT_MESSAGE_SIZE = 7 _LONG_MESSAGE_SIZE = 20 _MEDIUM_MESSAGE_SIZE = 15 _MAX_READ_SIZE = 32 HIDPP_SHORT_MESSAGE_ID = 0x10 HIDPP_LONG_MESSAGE_ID = 0x11 DJ_MESSAGE_ID = 0x20 # Centurion transport (used by PRO X 2 LIGHTSPEED headset and similar) # Two variants exist, distinguished by report ID: # 0x51 (PRO X 2): [0x51, cpl_length, flags, feat_idx, func_sw, params..., pad] # 0x50 (G522): [0x50, device_addr, cpl_length, flags, feat_idx, func_sw, params..., pad] # The 0x50 variant adds a device_addr byte at position [1], shifting all CPL fields by +1. # cpl_length = number of bytes from flags to end of meaningful data (includes flags byte). # The device_index byte from standard HID++ is NOT present in Centurion framing. CENTURION_REPORT_ID = 0x51 CENTURION_ADDRESSED_REPORT_ID = 0x50 # addressed variant with device_addr byte at frame[1] (G522 etc.) CENTURION_FRAME_SIZE = 64 # 1 byte report ID + 63 bytes payload _CENTURION_MSG_SIZE = 63 # max reconstructed message size after unwrapping (2 + 61 payload bytes) @dataclasses.dataclass class CenturionHandleState: """Per-handle state for Centurion devices.""" report_id: int = CENTURION_REPORT_ID # 0x50 or 0x51 device_addr: int | None = None # learned from first RX (0x50 only) protocol_version: tuple[int, int] | None = None # from ping response # All centurion per-handle state in a single dict. # Membership test (ihandle in _centurion_handles) gates centurion-specific code paths. _centurion_handles: dict[int, CenturionHandleState] = {} """Default timeout on read (in seconds).""" DEFAULT_TIMEOUT = 4 # the receiver itself should reply very fast, within 500ms _RECEIVER_REQUEST_TIMEOUT = 0.9 # devices may reply a lot slower, as the call has to go wireless to them and come back _DEVICE_REQUEST_TIMEOUT = DEFAULT_TIMEOUT # when pinging, be extra patient (no longer) _PING_TIMEOUT = DEFAULT_TIMEOUT hidapi = typing.cast(HIDProtocol, hidapi) request_lock = threading.Lock() # serialize all requests handles_lock = {} @dataclasses.dataclass class HIDPPNotification: report_id: int devnumber: int sub_id: int address: int data: bytes def __str__(self): text_as_hex = common.strhex(self.data) return f"Notification({self.report_id:02x},{self.devnumber},{self.sub_id:02X},{self.address:02X},{text_as_hex})" def _usb_device(product_id: int, usb_interface: int) -> dict[str, Any]: return { "vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "bus_id": BusID.USB, "usb_interface": usb_interface, "isDevice": True, } def _bluetooth_device(product_id: int) -> dict[str, Any]: return {"vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "bus_id": BusID.BLUETOOTH, "isDevice": True} KNOWN_DEVICE_IDS = [] for _ignore, d in descriptors.DEVICES.items(): if d.usbid: usb_interface = d.interface if d.interface else 2 KNOWN_DEVICE_IDS.append(_usb_device(d.usbid, usb_interface)) if d.btid: KNOWN_DEVICE_IDS.append(_bluetooth_device(d.btid)) def product_information(usb_id: int) -> dict[str, Any]: """Returns hardcoded information from USB receiver.""" return base_usb.get_receiver_info(usb_id) def receivers(): """Enumerate all the receivers attached to the machine.""" yield from hidapi.enumerate(get_known_receiver_info) def filter_products_of_interest( bus_id: int, vendor_id: int, product_id: int, hidpp_short: bool = False, hidpp_long: bool = False ) -> dict[str, Any] | None: """Check that this product is of interest and if so return the device record for further checking""" recv = get_known_receiver_info(bus_id, vendor_id, product_id, hidpp_short, hidpp_long) if recv: # known or unknown receiver return recv device = get_known_device_info(bus_id, vendor_id, product_id) if device: return device if hidpp_short or hidpp_long: return get_unknown_hid_device_info(bus_id, vendor_id, product_id) if hidpp_short is None and hidpp_long is None: return get_unknown_logitech_device_info(bus_id, vendor_id, product_id) return None def get_known_device_info(bus_id: int, vendor_id: int, product_id: int) -> dict[str, Any]: for recv in KNOWN_DEVICE_IDS: if _match_device(recv, bus_id, vendor_id, product_id): return recv def get_unknown_hid_device_info(bus_id: int, vendor_id: int, product_id: int) -> dict[str, Any]: return {"vendor_id": vendor_id, "product_id": product_id, "bus_id": bus_id, "isDevice": True} def get_unknown_logitech_device_info(bus_id: int, vendor_id: int, product_id: int) -> dict[str, Any] | None: """Get info from unknown device in Logitech product range. Check whether product is a Logitech USB-connected or Bluetooth device based on bus, vendor, and product ID. This allows Solaar to support receiverless HID++ 2.0 devices that it knows nothing about. """ if vendor_id != LOGITECH_VENDOR_ID: return None if bus_id == BusID.USB.value and (0xC07D <= product_id <= 0xC094 or 0xC32B <= product_id <= 0xC344): device_info = _usb_device(product_id, 2) return device_info elif bus_id == BusID.BLUETOOTH.value and (0xB012 <= product_id <= 0xB0FF or 0xB317 <= product_id <= 0xB3FF): device_info = _bluetooth_device(product_id) return device_info return None def _match_device(record: dict[str, Any], bus_id: int, vendor_id: int, product_id: int): return ( (record.get("bus_id") is None or record.get("bus_id") == bus_id) and (record.get("vendor_id") is None or record.get("vendor_id") == vendor_id) and (record.get("product_id") is None or record.get("product_id") == product_id) ) def get_known_receiver_info( bus_id: int, vendor_id: int, product_id: int, _hidpp_short: bool = False, _hidpp_long: bool = False ) -> dict[str, Any]: """Check that this product is a Logitech receiver and return it. Filters based on bus_id, vendor_id and product_id. If so return the receiver record for further checking. """ try: record = base_usb.get_receiver_info(product_id) if _match_device(record, bus_id, vendor_id, product_id): return record except ValueError: pass if vendor_id == LOGITECH_VENDOR_ID and 0xC500 <= product_id <= 0xC5FF: # unknown receiver return {"vendor_id": vendor_id, "product_id": product_id, "bus_id": bus_id, "isDevice": False} return None def receivers_and_devices(): """Enumerate all the receivers and devices directly attached to the machine.""" yield from hidapi.enumerate(filter_products_of_interest) def notify_on_receivers_glib(glib: GLib, callback: Callable): """Watch for matching devices and notifies the callback on the GLib thread. Parameters ---------- glib GLib instance. """ return hidapi.monitor_glib(glib, callback, filter_products_of_interest) def open_path(path) -> int: """Checks if the given Linux device path points to the right UR device. :param path: the Linux device path. The UR physical device may expose multiple linux devices with the same interface, so we have to check for the right one. At this moment the only way to distinguish betheen them is to do a test ping on an invalid (attached) device number (i.e., 0), expecting a 'ping failed' reply. :returns: an open receiver handle if this is the right Linux device, or ``None``. """ return hidapi.open_path(path) def open(): """Opens the first Logitech Unifying Receiver found attached to the machine. :returns: An open file handle for the found receiver, or ``None``. """ for rawdevice in receivers(): handle = open_path(rawdevice.path) if handle: return handle def close(handle): """Closes a HID device handle.""" if handle: try: if isinstance(handle, int): _centurion_handles.pop(handle, None) hidapi.close(handle) else: handle.close() return True except Exception: pass return False def _centurion_frame_header(state: CenturionHandleState, cpl_length: int, flags: int) -> bytes: """Build the fixed prefix of a centurion frame. 0x51: [0x51, cpl_length, flags] (3 bytes) 0x50: [0x50, device_addr, cpl_length, flags] (4 bytes) """ if state.report_id == CENTURION_ADDRESSED_REPORT_ID: device_addr = state.device_addr if state.device_addr is not None else 0x00 return struct.pack("!BBBB", CENTURION_ADDRESSED_REPORT_ID, device_addr, cpl_length, flags) return struct.pack("!BBB", CENTURION_REPORT_ID, cpl_length, flags) _CENTURION_REPORT_IDS = (CENTURION_REPORT_ID, CENTURION_ADDRESSED_REPORT_ID) # Per-candidate read timeout (ms) for the device_addr probe. # USB round-trip is <1ms; 5ms gives 5x margin. _CENTURION_PROBE_PER_ADDR_TIMEOUT_MS = 5 def probe_centurion_device_addr(handle, state: CenturionHandleState) -> bool: """Brute-force probe the device address byte for a 0x50-variant Centurion handle. Sends a ROOT.GetProtocolVersion request for each candidate device_addr (0x00–0xFF), reading briefly after each write. The dongle silently ignores wrong addresses and responds only to the correct one. Stops on first hit. Worst case (no response): 256 × 5ms = ~1.3s. Typical G522 (addr=0x23): 36 × 5ms = ~180ms. No-op for 0x51 (no device_addr byte) or when an address is already known. Returns True if the address was learned. """ if state.report_id != CENTURION_ADDRESSED_REPORT_ID or state.device_addr is not None: return False ihandle = int(handle) logger.debug("(%s) probing centurion device_addr: scanning 0x00-0xFF", handle) # ROOT.GetProtocolVersion: feat_idx=0x00, func=0x10, 3 zero param bytes payload = bytes([0x00, 0x10, 0x00, 0x00, 0x00]) cpl_length = len(payload) + 1 # +1 for flags byte write_errors = 0 for addr in range(256): frame = struct.pack("!BBBB", CENTURION_ADDRESSED_REPORT_ID, addr, cpl_length, 0x00) + payload frame = frame + b"\x00" * (CENTURION_FRAME_SIZE - len(frame)) try: hidapi.write(ihandle, frame) except Exception: write_errors += 1 if write_errors > 3: logger.debug("(%s) centurion device_addr probe: too many write failures, aborting", handle) return False continue try: data = hidapi.read(ihandle, CENTURION_FRAME_SIZE, _CENTURION_PROBE_PER_ADDR_TIMEOUT_MS) except Exception as reason: logger.debug("(%s) centurion device_addr probe read failed at addr 0x%02X: %s", handle, addr, reason) return False if data and len(data) >= 2 and ord(data[:1]) == state.report_id: state.device_addr = ord(data[1:2]) logger.debug( "(%s) probed centurion device addr 0x%02X (after %d candidates)", handle, state.device_addr, addr + 1, ) return True logger.debug("(%s) centurion device_addr probe: no response from any of 256 candidates", handle) return False def _unwrap_centurion_frame(data: bytes, ihandle: int, handle) -> bytes: """Unwrap a Centurion CPL frame (0x50 or 0x51) into a standard HID++ long message. Auto-detects the variant from the raw report ID byte (self-describing), matching how _read() handles 0x10 vs 0x11. For 0x50, learns the device address from byte[1] on first receive. """ raw_report_id = ord(data[:1]) if raw_report_id == CENTURION_ADDRESSED_REPORT_ID: # 0x50: [report_id, device_addr, cpl_length, flags, feat_idx, func_sw, data...] device_addr = ord(data[1:2]) state = _centurion_handles.get(ihandle) if state is not None and state.device_addr is None: state.device_addr = device_addr if logger.isEnabledFor(logging.DEBUG): logger.debug("(%s) learned centurion device addr 0x%02X", handle, device_addr) cpl_length = ord(data[2:3]) inner_payload = data[4 : 3 + cpl_length] # cpl_length - 1 bytes (skip flags) elif raw_report_id == CENTURION_REPORT_ID: # 0x51: [report_id, cpl_length, flags, feat_idx, func_sw, data...] cpl_length = ord(data[1:2]) inner_payload = data[3 : 2 + cpl_length] # cpl_length - 1 bytes (skip flags) else: return data # not a centurion frame data = bytes([HIDPP_LONG_MESSAGE_ID, 0xFF]) + inner_payload # Pad to a valid message size: standard long (20) or Centurion extended (63) if len(data) <= _LONG_MESSAGE_SIZE: data = data + b"\x00" * (_LONG_MESSAGE_SIZE - len(data)) elif len(data) <= _CENTURION_MSG_SIZE: data = data + b"\x00" * (_CENTURION_MSG_SIZE - len(data)) else: data = data[:_CENTURION_MSG_SIZE] return data def write(handle, devnumber, data, long_message=False): """Writes some data to the receiver, addressed to a certain device. :param handle: an open UR handle. :param devnumber: attached device number. :param data: data to send, up to 5 bytes. The first two (required) bytes of data must be the SubId and address. :raises NoReceiver: if the receiver is no longer available, i.e. has been physically removed from the machine, or the kernel driver has been unloaded. The handle will be closed automatically. """ # the data is padded to either 5 or 18 bytes assert data is not None assert isinstance(data, bytes), (repr(data), type(data)) if long_message or len(data) > SHORT_MESSAGE_SIZE - 2 or data[:1] == b"\x82": wdata = struct.pack("!BB18s", HIDPP_LONG_MESSAGE_ID, devnumber, data) else: wdata = struct.pack("!BB5s", HIDPP_SHORT_MESSAGE_ID, devnumber, data) ihandle = int(handle) if ihandle in _centurion_handles: # Centurion CPL framing — strip device_index from HID++ and wrap in CPL header. # cpl_length = len(meaningful_payload) + 1 (the +1 counts the flags byte). state = _centurion_handles[ihandle] payload = wdata[2:] # skip report_id and devnumber from standard frame cpl_length = len(data) + 1 # data is the unpadded payload; +1 for flags byte wdata = _centurion_frame_header(state, cpl_length, 0x00) + payload wdata = wdata + b"\x00" * (CENTURION_FRAME_SIZE - len(wdata)) if logger.isEnabledFor(logging.DEBUG): logger.debug( "(%s) <= w[%02X %02X %s %s]", handle, ord(wdata[:1]), devnumber, common.strhex(wdata[2:4]), common.strhex(wdata[4:]), ) try: hidapi.write(ihandle, wdata) except Exception as reason: logger.error("write failed, assuming handle %r no longer available", handle) close(handle) raise exceptions.NoReceiver(reason=reason) from reason def write_centurion_cpl(handle, layer3_payload, flags=0x00): """Send a Centurion CPL frame with the given Layer 3+ payload. Builds the appropriate header for the handle's report ID variant: 0x51: [0x51, cpl_length, flags, layer3_payload..., pad to 64] 0x50: [0x50, device_addr, cpl_length, flags, layer3_payload..., pad to 64] where cpl_length = len(layer3_payload) + 1 (the +1 counts the flags byte). For multi-fragment sends, flags encodes fragment index and continuation: flags = (fragment_index << 1) | (1 if more_fragments else 0) Single-frame messages use flags=0x00 (default). """ ihandle = int(handle) if ihandle not in _centurion_handles: raise ValueError("write_centurion_cpl called on non-Centurion handle") state = _centurion_handles[ihandle] cpl_length = len(layer3_payload) + 1 # +1 for flags byte header = _centurion_frame_header(state, cpl_length, flags) wdata = header + layer3_payload wdata = wdata + b"\x00" * (CENTURION_FRAME_SIZE - len(wdata)) if logger.isEnabledFor(logging.DEBUG): logger.debug("(%s) <= centurion_cpl[%s]", handle, common.strhex(wdata[: len(header) + cpl_length - 1])) try: hidapi.write(ihandle, wdata) except Exception as reason: logger.error("write failed, assuming handle %r no longer available", handle) close(handle) raise exceptions.NoReceiver(reason=reason) from reason def read(handle, timeout=DEFAULT_TIMEOUT): """Read some data from the receiver. Usually called after a write (feature call), to get the reply. :param: handle open handle to the receiver :param: timeout how long to wait for a reply, in seconds :returns: a tuple of (devnumber, message data), or `None` :raises NoReceiver: if the receiver is no longer available, i.e. has been physically removed from the machine, or the kernel driver has been unloaded. The handle will be closed automatically. """ reply = _read(handle, timeout) if reply: return reply def _is_relevant_message(data: bytes) -> bool: """Checks if given id is a HID++ or DJ message. Applies sanity checks on message report ID and message size. """ assert isinstance(data, bytes), (repr(data), type(data)) # mapping from report_id to accepted message lengths report_lengths = { HIDPP_SHORT_MESSAGE_ID: (SHORT_MESSAGE_SIZE,), HIDPP_LONG_MESSAGE_ID: (_LONG_MESSAGE_SIZE, _CENTURION_MSG_SIZE), DJ_MESSAGE_ID: (_MEDIUM_MESSAGE_SIZE,), 0x21: (_MAX_READ_SIZE,), } report_id = ord(data[:1]) if report_id in report_lengths: if len(data) in report_lengths[report_id]: return True else: logger.warning(f"unexpected message size: report_id {report_id:02X} message {common.strhex(data)}") return False def _read(handle, timeout) -> tuple[int, int, bytes]: """Read an incoming packet from the receiver. :returns: a tuple of (report_id, devnumber, data), or `None`. :raises NoReceiver: if the receiver is no longer available, i.e. has been physically removed from the machine, or the kernel driver has been unloaded. The handle will be closed automatically. """ ihandle = int(handle) is_centurion = ihandle in _centurion_handles read_size = CENTURION_FRAME_SIZE if is_centurion else _MAX_READ_SIZE try: # convert timeout to milliseconds, the hidapi expects it timeout = int(timeout * 1000) data = hidapi.read(ihandle, read_size, timeout) except Exception as reason: logger.warning("read failed, assuming handle %r no longer available", handle) close(handle) raise exceptions.NoReceiver(reason=reason) from reason if data and is_centurion and ord(data[:1]) in _CENTURION_REPORT_IDS: data = _unwrap_centurion_frame(data, ihandle, handle) if data and _is_relevant_message(data): # ignore messages that fail check report_id = ord(data[:1]) devnumber = ord(data[1:2]) if logger.isEnabledFor(logging.DEBUG) and ( report_id != DJ_MESSAGE_ID or ord(data[2:3]) > 0x10 ): # ignore DJ input messages logger.debug( "(%s) => r[%02X %02X %s %s]", handle, report_id, devnumber, common.strhex(data[2:4]), common.strhex(data[4:]), ) return report_id, devnumber, data[2:] def make_notification(report_id: int, devnumber: int, data: bytes) -> HIDPPNotification | None: """Guess if this is a notification (and not just a request reply), and return a Notification if it is.""" sub_id = ord(data[:1]) if sub_id & 0x80 == 0x80: # this is either a HID++1.0 register r/w, or an error reply return None # DJ input records are not notifications if report_id == DJ_MESSAGE_ID and (sub_id < 0x10): return None address = ord(data[1:2]) if sub_id == 0x00 and (address & 0x0F == 0x00): # this is a no-op notification - don't do anything with it return None if ( # standard HID++ 1.0 notification, SubId may be 0x40 - 0x7F (sub_id >= 0x40) # noqa: E131 or # custom HID++1.0 battery events, where SubId is 0x07/0x0D (sub_id in (0x07, 0x0D) and len(data) == 5 and data[4:5] == b"\x00") or # custom HID++1.0 illumination event, where SubId is 0x17 (sub_id == 0x17 and len(data) == 5) or # HID++ 2.0 feature notifications have the SoftwareID 0 (address & 0x0F == 0x00) ): # noqa: E129 return HIDPPNotification(report_id, devnumber, sub_id, address, data[2:]) return None def handle_lock(handle): with request_lock: if handles_lock.get(handle) is None: if logger.isEnabledFor(logging.INFO): logger.info("New lock %s", repr(handle)) handles_lock[handle] = threading.Lock() # Serialize requests on the handle return handles_lock[handle] # context manager for locks with a timeout @contextmanager def acquire_timeout(lock, handle, timeout): result = lock.acquire(timeout=timeout) try: if not result: logger.error("lock on handle %d not acquired, probably due to timeout", int(handle)) yield result finally: if result: lock.release() def find_paired_node(receiver_path: str, index: int, timeout: int): """Find the node of a device paired with a receiver.""" return hidapi.find_paired_node(receiver_path, index, timeout) def find_paired_node_wpid(receiver_path: str, index: int): """Find the node of a device paired with a receiver. Get wpid from udev. """ return hidapi.find_paired_node_wpid(receiver_path, index) # a very few requests (e.g., host switching) do not expect a reply, but use no_reply=True with extreme caution def request( handle, devnumber, request_id: int, *params, no_reply: bool = False, return_error: bool = False, long_message: bool = False, protocol: float = 1.0, ): """Makes a feature call to a device and waits for a matching reply. :param handle: an open UR handle. :param devnumber: attached device number. :param request_id: a 16-bit integer. :param params: parameters for the feature call, 3 to 16 bytes. :returns: the reply data, or ``None`` if some error occurred. or no reply expected """ with acquire_timeout(handle_lock(handle), handle, 10.0): assert isinstance(request_id, int) if (devnumber != 0xFF or protocol >= 2.0) and request_id < 0x8000: # Always set the most significant bit (8) in SoftwareId, # to make notifications easier to distinguish from request replies. # This only applies to peripheral requests, ofc. sw_id = _get_next_sw_id() request_id = (request_id & 0xFFF0) | sw_id # was 0x08 | getrandbits(3) timeout = _RECEIVER_REQUEST_TIMEOUT if devnumber == 0xFF else _DEVICE_REQUEST_TIMEOUT # be extra patient on long register read if request_id & 0xFF00 == 0x8300: timeout *= 2 if params: params = b"".join(struct.pack("B", p) if isinstance(p, int) else p for p in params) else: params = b"" request_data = struct.pack("!H", request_id) + params ihandle = int(handle) notifications_hook = getattr(handle, "notifications_hook", None) try: _read_input_buffer(handle, ihandle, notifications_hook) except exceptions.NoReceiver: logger.warning("device or receiver disconnected") return None write(ihandle, devnumber, request_data, long_message) if no_reply: return None # we consider timeout from this point request_started = time() delta = 0 while delta < timeout: reply = _read(handle, timeout) if reply: report_id, reply_devnumber, reply_data = reply if reply_devnumber == devnumber or reply_devnumber == devnumber ^ 0xFF: # BT device returning 0x00 if ( report_id == HIDPP_SHORT_MESSAGE_ID and reply_data[:1] == b"\x8f" and reply_data[1:3] == request_data[:2] ): error = ord(reply_data[3:4]) if logger.isEnabledFor(logging.DEBUG): logger.debug( "(%s) device 0x%02X error on request {%04X}: %d = %s", handle, devnumber, request_id, error, Hidpp10ErrorCode(error), ) return Hidpp10ErrorCode(error) if return_error else None if reply_data[:1] == b"\xff" and reply_data[1:3] == request_data[:2]: # a HID++ 2.0 feature call returned with an error error = ord(reply_data[3:4]) try: error_name = Hidpp20ErrorCode(error) except ValueError: error_name = f"unknown:{error:02X}" logger.error( "(%s) device %d error on feature request {%04X}: %d = %s", handle, devnumber, request_id, error, error_name, ) raise exceptions.FeatureCallError( number=devnumber, request=request_id, error=error, params=params, ) if reply_data[:2] == request_data[:2]: if devnumber == 0xFF: if request_id == 0x83B5 or request_id == 0x81F1: # these replies have to match the first parameter as well if reply_data[2:3] == params[:1]: return reply_data[2:] else: # hm, not matching my request, and certainly not a notification continue else: return reply_data[2:] else: return reply_data[2:] else: # a reply was received, but did not match our request in any way # reset the timeout starting point request_started = time() if notifications_hook: n = make_notification(report_id, reply_devnumber, reply_data) if n: notifications_hook(n) delta = time() - request_started logger.warning( "timeout (%0.2f/%0.2f) on device %d request {%04X} params [%s]", delta, timeout, devnumber, request_id, common.strhex(params), ) # raise DeviceUnreachable(number=devnumber, request=request_id) def ping(handle, devnumber, long_message: bool = False): """Check if a device is connected to the receiver. :returns: The HID protocol supported by the device, as a floating point number, if the device is active. """ if logger.isEnabledFor(logging.DEBUG): logger.debug("(%s) pinging device %d", handle, devnumber) with acquire_timeout(handle_lock(handle), handle, 10.0): notifications_hook = getattr(handle, "notifications_hook", None) try: _read_input_buffer(handle, int(handle), notifications_hook) except exceptions.NoReceiver: logger.warning("device or receiver disconnected") return # randomize the mark byte to be able to identify the ping reply sw_id = _get_next_sw_id() request_id = 0x0010 | sw_id # was 0x0018 | getrandbits(3) request_data = struct.pack("!HBBB", request_id, 0, 0, getrandbits(8)) write(int(handle), devnumber, request_data, long_message) request_started = time() # we consider timeout from this point delta = 0 while delta < _PING_TIMEOUT: reply = _read(handle, _PING_TIMEOUT) if reply: report_id, reply_devnumber, reply_data = reply if reply_devnumber == devnumber or reply_devnumber == devnumber ^ 0xFF: # BT device returning 0x00 is_centurion = int(handle) in _centurion_handles mark_ok = is_centurion or reply_data[4:5] == request_data[-1:] if reply_data[:2] == request_data[:2] and mark_ok: # HID++ 2.0+ device, currently connected major = ord(reply_data[2:3]) minor = ord(reply_data[3:4]) if is_centurion: _centurion_handles[int(handle)].protocol_version = (major, minor) return major + minor / 10.0 if ( report_id == HIDPP_SHORT_MESSAGE_ID and reply_data[:1] == b"\x8f" and reply_data[1:3] == request_data[:2] ): # error response error = ord(reply_data[3:4]) if error == Hidpp10ErrorCode.INVALID_SUB_ID_COMMAND: # a valid reply from a HID++ 1.0 device return 1.0 if error in [Hidpp10ErrorCode.RESOURCE_ERROR, Hidpp10ErrorCode.CONNECTION_REQUEST_FAILED]: return # device unreachable if error == Hidpp10ErrorCode.UNKNOWN_DEVICE: # no device with that number currently accessible logger.info("(%s) device %d error on ping request: unknown device", handle, devnumber) raise exceptions.NoSuchDevice(number=devnumber, request=request_id) if notifications_hook: n = make_notification(report_id, reply_devnumber, reply_data) if n: notifications_hook(n) delta = time() - request_started logger.warning("(%s) timeout (%0.2f/%0.2f) on device %d ping", handle, delta, _PING_TIMEOUT, devnumber) def _read_input_buffer(handle, ihandle, notifications_hook): """Consume anything already in the input buffer. Used by request() and ping() before their write. """ is_centurion = ihandle in _centurion_handles read_size = CENTURION_FRAME_SIZE if is_centurion else _MAX_READ_SIZE while True: try: # read whatever is already in the buffer, if any data = hidapi.read(ihandle, read_size, 0) except Exception as reason: logger.error("read failed, assuming receiver %s no longer available", handle) close(handle) raise exceptions.NoReceiver(reason=reason) from reason if data: if is_centurion and ord(data[:1]) in _CENTURION_REPORT_IDS: data = _unwrap_centurion_frame(data, ihandle, handle) if _is_relevant_message(data): # only process messages that pass check # report_id = ord(data[:1]) if notifications_hook: n = make_notification(ord(data[:1]), ord(data[1:2]), data[2:]) if n: notifications_hook(n) else: # nothing in the input buffer, we're done return # HID++ Software ID claimed by Solaar. Fixed (not rotated) so cooperative # userspace HID++ clients sharing the same device can pick a different value # and reliably filter Solaar's traffic out of their reply stream. # # Known values in use by other tools at the time of writing: # # 0x07 OpenRGB # 0x0A LGSTrayEx # 0x0D Logitech G HUB (host-side) # 0x0F Logitech firmware (sub-device self-enumeration on wired transports) # # 0x0B avoids those and keeps the high bit set so notifications (sw_id=0) # remain trivially distinguishable from replies. SOLAAR_SOFTWARE_ID = 0x0B def _get_next_sw_id() -> int: """Return Solaar's HID++ Software ID (fixed, see SOLAAR_SOFTWARE_ID).""" return SOLAAR_SOFTWARE_ID Solaar-1.1.20/lib/logitech_receiver/base_usb.py000066400000000000000000000166631522022367600214220ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Collection of known Logitech product IDs. According to Logitech, they use the following product IDs (as of September 2020) USB product IDs for receivers: 0xC526 - 0xC5xx Wireless PIDs for hidpp10 devices: 0x2006 - 0x2019 Wireless PIDs for hidpp20 devices: 0x4002 - 0x4097, 0x4101 - 0x4102 USB product IDs for hidpp20 devices: 0xC07D - 0xC094, 0xC32B - 0xC344 Bluetooth product IDs (for hidpp20 devices): 0xB012 - 0xB0xx, 0xB32A - 0xB3xx USB ids of Logitech wireless receivers. Only receivers supporting the HID++ protocol can go in here. """ from __future__ import annotations from typing import Any from solaar.i18n import _ # max_devices is only used for receivers that do not support reading from Registers.RECEIVER_INFO offset 0x03, default # to 1. # may_unpair is only used for receivers that do not support reading from Registers.RECEIVER_INFO offset 0x03, # default to False. # unpair is for receivers that do support reading from Registers.RECEIVER_INFO offset 0x03, no default. ## should this last be changed so that may_unpair is used for all receivers? writing to Registers.RECEIVER_PAIRING ## doesn't seem right LOGITECH_VENDOR_ID = 0x046D def _bolt_receiver(product_id: int) -> dict: return { "vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "usb_interface": 2, "name": _("Bolt Receiver"), "receiver_kind": "bolt", "max_devices": 6, "may_unpair": True, } def _unifying_receiver(product_id: int) -> dict: return { "vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "usb_interface": 2, "name": _("Unifying Receiver"), "receiver_kind": "unifying", "may_unpair": True, } def _nano_receiver(product_id: int) -> dict: return { "vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "usb_interface": 1, "name": _("Nano Receiver"), "receiver_kind": "nano", "may_unpair": False, "re_pairs": True, } def _nano_receiver_no_unpair(product_id: int) -> dict: return { "vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "usb_interface": 1, "name": _("Nano Receiver"), "receiver_kind": "nano", "may_unpair": False, "unpair": False, "re_pairs": True, } def _nano_receiver_max2(product_id: int) -> dict: return { "vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "usb_interface": 1, "name": _("Nano Receiver"), "receiver_kind": "nano", "max_devices": 2, "may_unpair": False, "re_pairs": True, } def _lenovo_receiver(product_id: int) -> dict: return { "vendor_id": 6127, "product_id": product_id, "usb_interface": 1, "name": _("Nano Receiver"), "receiver_kind": "nano", "may_unpair": False, } def _lightspeed_receiver(product_id: int) -> dict: return { "vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "usb_interface": 2, "receiver_kind": "lightspeed", "name": _("Lightspeed Receiver"), "may_unpair": True, "re_pairs": False, } def _ex100_receiver(product_id: int) -> dict: return { "vendor_id": LOGITECH_VENDOR_ID, "product_id": product_id, "usb_interface": 1, "name": _("EX100 Receiver 27 Mhz"), "receiver_kind": "27Mhz", "max_devices": 4, "may_unpair": False, "re_pairs": True, } # Receivers added here should also be listed in # share/solaar/io.github.pwr_solaar.solaar.meta-info.xml # Look in https://github.com/torvalds/linux/blob/master/drivers/hid/hid-ids.h # Bolt receivers (marked with the yellow lightning bolt logo) BOLT_RECEIVER_C548 = _bolt_receiver(0xC548) # standard Unifying receivers (marked with the orange Unifying logo) UNIFYING_RECEIVER_C52B = _unifying_receiver(0xC52B) UNIFYING_RECEIVER_C532 = _unifying_receiver(0xC532) # Nano receivers (usually sold with low-end devices) NANO_RECEIVER_ADVANCED = _nano_receiver_no_unpair(0xC52F) NANO_RECEIVER_C518 = _nano_receiver(0xC518) NANO_RECEIVER_C51A = _nano_receiver(0xC51A) NANO_RECEIVER_C51B = _nano_receiver(0xC51B) NANO_RECEIVER_C521 = _nano_receiver(0xC521) NANO_RECEIVER_C525 = _nano_receiver(0xC525) NANO_RECEIVER_C526 = _nano_receiver(0xC526) NANO_RECEIVER_C52E = _nano_receiver_no_unpair(0xC52E) NANO_RECEIVER_C531 = _nano_receiver(0xC531) NANO_RECEIVER_C534 = _nano_receiver_max2(0xC534) NANO_RECEIVER_C535 = _nano_receiver(0xC535) # branded as Dell NANO_RECEIVER_C537 = _nano_receiver(0xC537) NANO_RECEIVER_6042 = _lenovo_receiver(0x6042) # Lightspeed receivers (usually sold with gaming devices) LIGHTSPEED_RECEIVER_C539 = _lightspeed_receiver(0xC539) LIGHTSPEED_RECEIVER_C53A = _lightspeed_receiver(0xC53A) LIGHTSPEED_RECEIVER_C53D = _lightspeed_receiver(0xC53D) LIGHTSPEED_RECEIVER_C53F = _lightspeed_receiver(0xC53F) LIGHTSPEED_RECEIVER_C541 = _lightspeed_receiver(0xC541) LIGHTSPEED_RECEIVER_C545 = _lightspeed_receiver(0xC545) LIGHTSPEED_RECEIVER_C547 = _lightspeed_receiver(0xC547) LIGHTSPEED_RECEIVER_C54D = _lightspeed_receiver(0xC54D) # EX100 old style receiver pre-unifying protocol EX100_27MHZ_RECEIVER_C517 = _ex100_receiver(0xC517) KNOWN_RECEIVERS = { 0xC548: BOLT_RECEIVER_C548, 0xC52B: UNIFYING_RECEIVER_C52B, 0xC532: UNIFYING_RECEIVER_C532, 0xC52F: NANO_RECEIVER_ADVANCED, 0xC518: NANO_RECEIVER_C518, 0xC51A: NANO_RECEIVER_C51A, 0xC51B: NANO_RECEIVER_C51B, 0xC521: NANO_RECEIVER_C521, 0xC525: NANO_RECEIVER_C525, 0xC526: NANO_RECEIVER_C526, 0xC52E: NANO_RECEIVER_C52E, 0xC531: NANO_RECEIVER_C531, 0xC534: NANO_RECEIVER_C534, 0xC535: NANO_RECEIVER_C535, 0xC537: NANO_RECEIVER_C537, 0x6042: NANO_RECEIVER_6042, 0xC539: LIGHTSPEED_RECEIVER_C539, 0xC53A: LIGHTSPEED_RECEIVER_C53A, 0xC53D: LIGHTSPEED_RECEIVER_C53D, 0xC53F: LIGHTSPEED_RECEIVER_C53F, 0xC541: LIGHTSPEED_RECEIVER_C541, 0xC545: LIGHTSPEED_RECEIVER_C545, 0xC547: LIGHTSPEED_RECEIVER_C547, 0xC54D: LIGHTSPEED_RECEIVER_C54D, 0xC517: EX100_27MHZ_RECEIVER_C517, } def get_receiver_info(product_id: int) -> dict[str, Any]: """Returns hardcoded information about a Logitech receiver. Parameters ---------- product_id Product ID (pid) of the receiver, e.g. 0xC548 for a Logitech Bolt receiver. Returns ------- dict[str, Any] Receiver info with mandatory fields: - vendor_id - product_id Raises ------ ValueError If the product ID is unknown. """ try: return KNOWN_RECEIVERS[product_id] except KeyError: pass raise ValueError(f"Unknown product ID '0x{product_id:02X}'") Solaar-1.1.20/lib/logitech_receiver/centurion.py000066400000000000000000000541221522022367600216350ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Centurion device protocol — receiver class, factory, device info/firmware/battery queries. CenturionReceiver is a lightweight receiver-like container for Centurion (PRO X 2 LIGHTSPEED and similar) dongles. Protocol functions query device info, firmware, serial, name, and battery via Centurion-specific HID++ features. """ from __future__ import annotations import errno import logging import struct from typing import Callable from solaar import configuration from . import base from . import exceptions from . import hidpp10 from . import hidpp10_constants from .centurion_constants import CenturionCoreFeature from .common import Alert from .common import Battery from .common import BatteryStatus from .common import FirmwareKind from .common import _read_usb_product_string from .hidpp20_constants import SupportedFeature logger = logging.getLogger(__name__) # --- Centurion protocol functions (standalone, operate on any device-like object) --- def get_firmware_centurion(device): """Reads firmware info from a Centurion device via DeviceInfo (0x0100) function 1.""" from . import common fw = [] seen = set() # track response signatures to detect duplicates for index in range(0, 8): # try up to 8 entities try: report = device.feature_request(SupportedFeature.CENTURION_DEVICE_INFO, 0x10, index) except exceptions.FeatureCallError: break if not report or len(report) < 5: break # Dedup: parent device returns the same response for every entity index sig = bytes(report[: 5 + report[4]]) if sig in seen: break seen.add(sig) fw_type = report[0] version = struct.unpack("!H", report[2:4])[0] name_len = report[4] name = report[5 : 5 + name_len].decode("ascii", errors="replace").rstrip("\x00") if name_len else "" version_str = f"{version >> 8}.{version & 0xFF:02d}" kind = FirmwareKind(fw_type) if fw_type <= 3 else FirmwareKind.Other fw.append(common.FirmwareInfo(kind, name, version_str, None)) return tuple(fw) if fw else None def get_serial_centurion(device): """Reads the serial number from a Centurion device via DeviceInfo (0x0100) function 2.""" try: report = device.feature_request(SupportedFeature.CENTURION_DEVICE_INFO, 0x20) except exceptions.FeatureCallError: return None if not report or len(report) < 2: return None str_len = report[0] return report[1 : 1 + str_len].decode("ascii", errors="replace").rstrip("\x00") def get_hardware_info_centurion(device): """Reads hardware info from a Centurion device via DeviceInfo (0x0100) function 0. Returns (modelId, hardwareRevision, productId) or None. """ try: report = device.feature_request(SupportedFeature.CENTURION_DEVICE_INFO) except exceptions.FeatureCallError: return None if not report or len(report) < 4: return None model_id = report[0] hw_revision = report[1] product_id = struct.unpack("!H", report[2:4])[0] return model_id, hw_revision, product_id def _centurion_sub_device_info_request(device, function=0x00, *params): """Send a DeviceInfo (0x0100) request to the sub-device via bridge.""" sub_indices = getattr(device, "_centurion_sub_indices", {}) sub_idx = sub_indices.get(SupportedFeature.CENTURION_DEVICE_INFO) if sub_idx is None: return None return device.centurion_bridge_request(sub_idx, function, *params) def get_firmware_centurion_sub(device): """Reads firmware info from the Centurion sub-device (headset) via bridge.""" from . import common fw = [] seen = set() for index in range(0, 8): report = _centurion_sub_device_info_request(device, 0x10, index) if not report or len(report) < 5: break sig = bytes(report[: 5 + report[4]]) if sig in seen: break seen.add(sig) fw_type = report[0] version = struct.unpack("!H", report[2:4])[0] name_len = report[4] name = report[5 : 5 + name_len].decode("ascii", errors="replace").rstrip("\x00") if name_len else "" version_str = f"{version >> 8}.{version & 0xFF:02d}" kind = FirmwareKind(fw_type) if fw_type <= 3 else FirmwareKind.Other fw.append(common.FirmwareInfo(kind, name, version_str, None)) return tuple(fw) if fw else None def get_serial_centurion_sub(device): """Reads the serial number from the Centurion sub-device (headset) via bridge.""" report = _centurion_sub_device_info_request(device, 0x20) if not report or len(report) < 2: return None str_len = report[0] return report[1 : 1 + str_len].decode("ascii", errors="replace").rstrip("\x00") def get_hardware_info_centurion_sub(device): """Reads hardware info from the Centurion sub-device (headset) via bridge. Returns (modelId, hardwareRevision, productId) or None. """ report = _centurion_sub_device_info_request(device) if not report or len(report) < 4: return None model_id = report[0] hw_revision = report[1] product_id = struct.unpack("!H", report[2:4])[0] return model_id, hw_revision, product_id def get_name_centurion(device): """Reads a Centurion device's name via DeviceName (0x0101). Tries two response formats: 1. Inline: function 0 returns [name_len, name_bytes...] (like serial) 2. Chunked: function 0 returns [name_len], function 1 returns [name_bytes...] (like standard DeviceName) """ try: reply = device.feature_request(SupportedFeature.CENTURION_DEVICE_NAME) except exceptions.FeatureCallError: return None if not reply: return None name_length = reply[0] if name_length == 0: return None # If the full name is inline (length + name bytes in one response) if len(reply) >= 1 + name_length: return reply[1 : 1 + name_length].decode("utf-8", errors="replace").rstrip("\x00") # Otherwise, fetch name in chunks via function 1 (like standard DEVICE_NAME) name = b"" while len(name) < name_length: try: fragment = device.feature_request(SupportedFeature.CENTURION_DEVICE_NAME, 0x10, len(name)) except exceptions.FeatureCallError: break if fragment: name += fragment[: name_length - len(name)] else: break return name.decode("utf-8", errors="replace").rstrip("\x00") if name else None def get_battery_centurion(device): """Query battery via CENTURION_BATTERY_SOC.""" try: report = device.feature_request(SupportedFeature.CENTURION_BATTERY_SOC) if report is not None: return decipher_battery_centurion(report) except exceptions.FeatureCallError: if SupportedFeature.CENTURION_BATTERY_SOC in device.features: return SupportedFeature.CENTURION_BATTERY_SOC return None def decipher_battery_centurion(report) -> tuple[SupportedFeature, Battery]: """Decipher CENTURION_BATTERY_SOC (0x0104) response. Response format (3 bytes): Byte 0: Battery Percentage (0-100) Byte 1: Battery Percentage (duplicate) Byte 2: Charging Status (0=discharging, 1=charging, 2=charging via USB, 3=charge complete) """ if len(report) < 1: return SupportedFeature.CENTURION_BATTERY_SOC, Battery(None, None, BatteryStatus.DISCHARGING, None) soc = report[0] logger.debug("centurion battery SOC raw: %s", report[:8].hex()) charging_status = report[2] if len(report) >= 3 else 0 if charging_status in (1, 2): status = BatteryStatus.RECHARGING elif charging_status == 3: status = BatteryStatus.FULL else: status = BatteryStatus.DISCHARGING return SupportedFeature.CENTURION_BATTERY_SOC, Battery(soc, None, status, None) # --- CenturionReceiver class --- class CenturionReceiver: """A lightweight receiver-like container for Centurion (PRO X 2 LIGHTSPEED) dongles. Provides the Receiver interface to the UI so the dongle appears as a parent with the headset as an indented child device. NOT a subclass of Receiver — Receiver's __init__ does HID++ 1.0 register reads and pairing setup that don't apply to Centurion. All centurion communication (bridge, features, settings, battery) lives in the child Device; this class is just a UI container + handle owner. """ read_register: Callable = hidpp10.read_register write_register: Callable = hidpp10.write_register number = 0xFF kind = None isDevice = False may_unpair = False re_pairs = False max_devices = 1 def __init__(self, low_level, handle, device_info, setting_callback=None): assert handle self.low_level = low_level self.handle = handle self.path = device_info.path self.product_id = device_info.product_id self.setting_callback = setting_callback self.status_callback = None self.notification_flags = None self._devices = {} self._firmware = None self._dongle_features = None # independently probed dongle features self._pending = False # True when device_addr unknown; deferred init completes on first RX self.cleanups = [] # Receiver identity self.serial = None self._usb_name = getattr(device_info, "product", None) if not self._usb_name and self.path: self._usb_name = _read_usb_product_string(self.path) # User-facing name: "Centurion" is Logitech's internal codename for this # headset-dongle transport, kept in code/logs but not shown to users. self.name = "Lightspeed Headset Receiver" # Dummy pairing object — lock_open stays False from .receiver import Pairing self.pairing = Pairing() # Discover dongle features independently self._discover_dongle_features() # Read serial from dongle's CENTURION_DEVICE_INFO if available if self.serial is None: try: s = get_serial_centurion(self) if s and s.strip() and s.strip().isprintable(): self.serial = s.strip() except Exception: pass def enable_connection_notifications(self, enable=True): return False def remaining_pairings(self, cache=True): return None def device_codename(self, n): return self._usb_name def request(self, request_id, *params, no_reply=False): """Send an HID++ request directly to the dongle (not through bridge).""" if self.handle: return self.low_level.request( self.handle, 0xFF, request_id, *params, no_reply=no_reply, long_message=True, protocol=2.0 ) def feature_request(self, feature, function=0x00, *params, no_reply=False): """Send a feature request to the dongle using discovered feature indices.""" if self._dongle_features is None: self._discover_dongle_features() feature_int = int(feature) for _feat, feat_id, index in self._dongle_features or []: if feat_id == feature_int: request_id = (index << 8) | (function & 0xFF) return self.request(request_id, *params, no_reply=no_reply) raise exceptions.FeatureNotSupported(feature=feature) def _discover_dongle_features(self): """Independently discover features on the dongle hardware.""" self._dongle_features = [] try: # Query ROOT for FEATURE_SET index response = self.request(0x0000, 0x00, 0x01) if response is None or response[0] == 0: return fs_index = response[0] # Get feature count count_resp = self.request(fs_index << 8) if count_resp is None: return feature_count = count_resp[0] # Enumerate features via CenturionFeatureSet (func 1 = 0x10, per-index query) for idx in range(feature_count): resp = self.request((fs_index << 8) | 0x10, idx) if resp is None or len(resp) < 3: continue feat_id = struct.unpack("!H", resp[1:3])[0] try: feature = SupportedFeature(feat_id) except ValueError: feature = f"unknown:{feat_id:04X}" self._dongle_features.append((feature, feat_id, idx)) if logger.isEnabledFor(logging.DEBUG): logger.debug("Centurion dongle features: %s", self._dongle_features) except Exception: logger.debug("Centurion dongle feature discovery failed", exc_info=True) @property def dongle_features(self): """Return list of (feature, feat_id, index) tuples for dongle features.""" if self._dongle_features is None: self._discover_dongle_features() return self._dongle_features def count(self): return len([d for d in self._devices.values() if d is not None]) @property def firmware(self): if self._firmware is None and self.handle and not self._pending: self._firmware = get_firmware_centurion(self) return self._firmware or () def _complete_deferred_init(self): """Re-run feature discovery after device_addr has been learned. Called once from the notification handler when the first 0x50 frame arrives on a pending CenturionReceiver. """ if not self._pending: return False self._pending = False ihandle = int(self.handle) state = base._centurion_handles.get(ihandle) learned_addr = state.device_addr if state else None logger.debug( "CenturionReceiver %s: completing deferred init (device_addr=0x%02X)", self.path, learned_addr or 0, ) self._dongle_features = None self._discover_dongle_features() logger.debug( "CenturionReceiver %s: deferred discovery found %d feature(s): %s", self.path, len(self._dongle_features or []), [(f"{feat_id:#06x}", idx) for _, feat_id, idx in (self._dongle_features or [])], ) if self.serial is None: try: s = get_serial_centurion(self) if s and s.strip() and s.strip().isprintable(): self.serial = s.strip() except Exception: pass has_bridge = any(feat_id == CenturionCoreFeature.CENT_PP_BRIDGE for _, feat_id, _ in (self._dongle_features or [])) if has_bridge: self.notify_devices() return True logger.warning( "CenturionReceiver %s: deferred init completed but no bridge found " "(features: %s)", self.path, [f"{feat_id:#06x}" for _, feat_id, _ in (self._dongle_features or [])], ) return False def notify_devices(self): """Create child Device for the headset and trigger its initialization.""" # Import Device locally to avoid circular import (centurion.py ↔ device.py) from .device import Device if self._pending: # Don't create children yet — feature discovery hasn't succeeded. # Signal receiver to UI so the tray entry exists. self.changed(alert=Alert.NONE) return # Signal receiver to UI first — tray/window need the receiver entry # before a child device can be added under it. self.changed(alert=Alert.NONE) # Create child Device with receiver=self, number=1 pairing_info = { "wpid": self.product_id, "kind": hidpp10_constants.DEVICE_KIND.headset, # every Centurion-transport device so far is a headset "serial": None, "polling": None, "power_switch": None, } dev = Device( self.low_level, self, 1, None, pairing_info=pairing_info, setting_callback=self.setting_callback, ) # Set centurion attributes on the child dev.centurion = True dev.product_id = self.product_id dev.hidpp_long = True dev._centurion_usb_name = self._usb_name # Pre-set bridge index from dongle features so ping can probe the headset for _feat, feat_id, idx in self._dongle_features or []: if feat_id == CenturionCoreFeature.CENT_PP_BRIDGE: dev._centurion_bridge_index = idx break self._devices[1] = dev configuration.attach_to(dev) dev.status_callback = self.status_callback # Ping to determine online status. # Notify UI either way — offline devices show as greyed out (matching receiver behavior). online = dev.ping() logger.debug( "CenturionReceiver %s: child device created, bridge_idx=%s, online=%s, protocol=%s", self.path, getattr(dev, "_centurion_bridge_index", None), online, dev._protocol, ) dev.changed(active=online) if self.status_callback is not None: self.status_callback(dev) def changed(self, alert=Alert.NOTIFICATION, reason=None): if self.status_callback is not None: self.status_callback(self, alert=alert, reason=reason) def status_string(self): count = self.count() if count == 0: return "No devices." return f"{count} device connected." def close(self): handle, self.handle = self.handle, None for _n, d in self._devices.items(): if d: d.close() self._devices.clear() for cleanup in self.cleanups: cleanup(self) return handle and self.low_level.close(handle) def __del__(self): self.close() def __iter__(self): for dev in self._devices.values(): if dev is not None: yield dev def __getitem__(self, key): dev = self._devices.get(key) if dev is not None: return dev raise IndexError(key) def __len__(self): return len([d for d in self._devices.values() if d is not None]) def __contains__(self, dev): if isinstance(dev, int): return self._devices.get(dev) is not None return self.__contains__(dev.number) def __bool__(self): return self.handle is not None __nonzero__ = __bool__ def __eq__(self, other): return other is not None and self.kind == other.kind and self.path == other.path def __ne__(self, other): return other is None or self.kind != other.kind or self.path != other.path def __hash__(self): return self.path.__hash__() def __str__(self): return "<%s(%s,%s%s)>" % ( self.name.replace(" ", "") if self.name else "CenturionReceiver", self.path, "" if isinstance(self.handle, int) else "T", self.handle, ) __repr__ = __str__ def create_centurion_receiver(low_level, device_info, setting_callback=None): """Opens a Centurion dongle and wraps it as a receiver-like container. Creates a CenturionReceiver, discovers its features, then checks if CentPPBridge (0x0003) is among them. If not, this is a direct-connected device — wired headset, or a Bluetooth-paired Centurion headset where there is no separate dongle. Close and return None so the caller can fall back to create_device(). :returns: A CenturionReceiver, or None. """ try: handle = low_level.open_path(device_info.path) if handle: report_id = getattr(device_info, "centurion_report_id", None) or base.CENTURION_REPORT_ID state = base.CenturionHandleState(report_id=report_id) base._centurion_handles[int(handle)] = state base.probe_centurion_device_addr(handle, state) cr = CenturionReceiver(low_level, handle, device_info, setting_callback) # Check if any discovered feature is CentPPBridge (0x0003) has_bridge = any(feat_id == CenturionCoreFeature.CENT_PP_BRIDGE for _, feat_id, _ in (cr.dongle_features or [])) if has_bridge: return cr # No bridge found. Distinguish "silent 0x50 dongle" (device_addr # unknown, headset not yet powered on) from "wired 0x50 device" # (responded to probe, features found, but no bridge). is_0x50 = state.report_id == base.CENTURION_ADDRESSED_REPORT_ID if is_0x50 and state.device_addr is None and not cr.dongle_features: logger.debug( "Centurion 0x50 device %s: probe and discovery failed, " "deferring init until first RX frame", device_info.path, ) cr._pending = True return cr logger.info("Centurion device %s has no bridge, treating as direct device", device_info.path) base._centurion_handles.pop(int(handle), None) cr.handle = None # prevent __del__ from double-closing low_level.close(handle) return None except OSError as e: logger.exception("open %s", device_info) if e.errno == errno.EACCES: raise e except Exception as e: logger.exception("open %s", device_info) raise e Solaar-1.1.20/lib/logitech_receiver/centurion_constants.py000066400000000000000000000020341522022367600237240ustar00rootroot00000000000000"""Centurion transport-specific constants. Feature IDs that collide with HID++ 2.0 core features live here so they can coexist with SupportedFeature (which requires unique values). """ from __future__ import annotations from enum import IntEnum from .hidpp20_constants import SupportedFeature class CenturionCoreFeature(IntEnum): """Centurion transport-specific features that collide with HID++ 2.0 core IDs.""" CENTURION_ROOT = 0x0000 CENTURION_FEATURE_SET = 0x0001 CENT_PP_BRIDGE = 0x0003 MULTI_HOST_CONTROL = 0x0005 KEEP_ALIVE = 0x0007 def __str__(self): return self.name.replace("_", " ") def resolve_feature(feat_id: int, centurion: bool = False): """Resolve a feature ID to the appropriate enum, checking centurion-specific features first when on the centurion transport.""" if centurion: try: return CenturionCoreFeature(feat_id) except ValueError: pass try: return SupportedFeature(feat_id) except ValueError: return None Solaar-1.1.20/lib/logitech_receiver/common.py000066400000000000000000000456211522022367600211230ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import binascii import dataclasses import typing from enum import Flag from enum import IntEnum from typing import Generator from typing import Iterable from typing import Optional from typing import Union import yaml from solaar.i18n import _ if typing.TYPE_CHECKING: from logitech_receiver.hidpp20_constants import FirmwareKind LOGITECH_VENDOR_ID = 0x046D def crc16(data: bytes): """ CRC-16 (CCITT) implemented with a precomputed lookup table """ table = [ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0, ] crc = 0xFFFF for byte in data: crc = (crc << 8) ^ table[(crc >> 8) ^ byte] crc &= 0xFFFF # important, crc must stay 16bits all the way through return crc class NamedInt(int): """A regular Python integer with an attached name. Caution: comparison with strings will also match this NamedInt's name (case-insensitive).""" def __new__(cls, value, name): assert isinstance(name, str) obj = int.__new__(cls, value) obj.name = str(name) return obj def bytes(self, count=2): return int2bytes(self, count) def __eq__(self, other): if other is None: return False if isinstance(other, NamedInt): return int(self) == int(other) and self.name == other.name if isinstance(other, int): return int(self) == int(other) if isinstance(other, str): return self.name.lower() == other.lower() # this should catch comparisons with bytes in Py3 if other is not None: raise TypeError(f"Unsupported type {str(type(other))}") def __ne__(self, other): return not self.__eq__(other) def __hash__(self): return int(self) def __str__(self): return self.name def __repr__(self): return f"NamedInt({int(self)}, {self.name!r})" @classmethod def from_yaml(cls, loader, node): args = loader.construct_mapping(node) return cls(value=args["value"], name=args["name"]) @classmethod def to_yaml(cls, dumper, data): return dumper.represent_mapping("!NamedInt", {"value": int(data), "name": data.name}, flow_style=True) yaml.SafeLoader.add_constructor("!NamedInt", NamedInt.from_yaml) yaml.add_representer(NamedInt, NamedInt.to_yaml) class ColorInt(int): """A 24-bit RGB color (``0x000000``-``0xFFFFFF``) as an int subclass. Renders as ``0xrrggbb`` in ``str()`` / ``repr()`` and as a YAML hex int literal in dumped configs (e.g. ``color: 0xfc3300``), which loads back natively as a plain int via YAML 1.1's hex int parsing — so the value round-trips cleanly with no special loader registration. The constructor accepts both ints and hex strings (``0xfc3300`` or ``#fc3300``) so configs saved before this type existed continue to load unchanged. Negative or out-of-range values fall back to plain decimal formatting so sentinels like ``COLORSPLUS["No change"] = -1`` keep their natural display. """ def __new__(cls, value): if isinstance(value, str): s = value.strip().lower() if s.startswith("#"): value = int(s[1:], 16) elif s.startswith(("0x", "0X")): value = int(s, 16) else: value = int(s) else: value = int(value) return super().__new__(cls, value) def __str__(self): v = int(self) if 0 <= v <= 0xFFFFFF: return "0x%06x" % v return str(v) def __repr__(self): return self.__str__() def color_int_representer(dumper, data): v = int(data) if 0 <= v <= 0xFFFFFF: return dumper.represent_scalar("tag:yaml.org,2002:int", "0x%06x" % v) return dumper.represent_scalar("tag:yaml.org,2002:int", str(v)) yaml.add_representer(ColorInt, color_int_representer) class NamedInts: """An ordered set of NamedInt values. Indexing can be made by int or string, and will return the corresponding NamedInt if it exists in this set, or `None`. Extracting slices will return all present NamedInts in the given interval (extended slices are not supported). Assigning a string to an indexed int will create a new NamedInt in this set; if the value already exists in the set (int or string), ValueError will be raised. """ __slots__ = ("__dict__", "_values", "_indexed", "_fallback", "_is_sorted") def __init__(self, dict_=None, **kwargs): def _readable_name(n): return n.replace("__", "/").replace("_", " ") # print (repr(kwargs)) elements = dict_ if dict_ else kwargs values = {k: NamedInt(v, _readable_name(k)) for (k, v) in elements.items()} self.__dict__ = values self._is_sorted = False self._values = list(values.values()) self._sort_values() self._indexed = {int(v): v for v in self._values} # assert len(values) == len(self._indexed) # "(%d) %r\n=> (%d) %r" % (len(values), values, len(self._indexed), self._indexed) self._fallback = None @classmethod def list(cls, items, name_generator=lambda x: str(x)): # noqa: B008 values = {name_generator(x): x for x in items} return NamedInts(**values) @classmethod def range(cls, from_value, to_value, name_generator=lambda x: str(x), step=1): # noqa: B008 values = {name_generator(x): x for x in range(from_value, to_value + 1, step)} return NamedInts(**values) def flag_names(self, value): unknown_bits = value for k in self._indexed: assert bin(k).count("1") == 1 if k & value == k: unknown_bits &= ~k yield str(self._indexed[k]) if unknown_bits: yield f"unknown:{unknown_bits:06X}" def _sort_values(self): self._values = sorted(self._values) self._is_sorted = True def __getitem__(self, index): if isinstance(index, int): if index in self._indexed: return self._indexed[int(index)] if self._fallback: value = NamedInt(index, self._fallback(index)) self._indexed[index] = value self._values.append(value) self._is_sorted = False self._sort_values() return value elif isinstance(index, str): if index in self.__dict__: return self.__dict__[index] return next((x for x in self._values if str(x) == index), None) elif isinstance(index, slice): values = self._values if self._is_sorted else sorted(self._values) if index.start is None and index.stop is None: return values[:] v_start = int(values[0]) if index.start is None else int(index.start) v_stop = (values[-1] + 1) if index.stop is None else int(index.stop) if v_start > v_stop or v_start > values[-1] or v_stop <= values[0]: return [] if v_start <= values[0] and v_stop > values[-1]: return values[:] start_index = 0 stop_index = len(values) for i, value in enumerate(values): if value < v_start: start_index = i + 1 elif index.stop is None: break if value >= v_stop: stop_index = i break return values[start_index:stop_index] def __setitem__(self, index, name): assert isinstance(index, int), type(index) if isinstance(name, NamedInt): assert int(index) == int(name), f"{repr(index)} {repr(name)}" value = name elif isinstance(name, str): value = NamedInt(index, name) else: raise TypeError("name must be a string") if str(value) in self.__dict__: raise ValueError(f"{value} ({int(value)}) already known") if int(value) in self._indexed: raise ValueError(f"{int(value)} ({value}) already known") self._values.append(value) self._is_sorted = False self._sort_values() self.__dict__[str(value)] = value self._indexed[int(value)] = value def __contains__(self, value): if isinstance(value, NamedInt): return self[value] == value elif isinstance(value, int): return value in self._indexed elif isinstance(value, str): return value in self.__dict__ or value in self._values def __iter__(self): yield from self._values def __len__(self): return len(self._values) def __repr__(self): return f"NamedInts({', '.join(repr(v) for v in self._values)})" def __or__(self, other): return NamedInts(**self.__dict__, **other.__dict__) def __eq__(self, other): return isinstance(other, self.__class__) and self._values == other._values def flag_names(enum_class: Iterable, value: int) -> Generator[str]: """Extracts single bit flags from a (binary) number. Parameters ---------- enum_class Enum class to extract flags from. value Number to extract binary flags from. """ indexed = {item.value: item.name for item in enum_class} unknown_bits = value for k in indexed: # Ensure that the key (flag value) is a power of 2 (a single bit flag) assert bin(k).count("1") == 1 if k & value == k: unknown_bits &= ~k yield indexed[k].lower() # Yield any remaining unknown bits if unknown_bits != 0: yield f"unknown:{unknown_bits:06X}" class UnsortedNamedInts(NamedInts): def _sort_values(self): pass def __or__(self, other): c = UnsortedNamedInts if isinstance(other, UnsortedNamedInts) else NamedInts return c(**self.__dict__, **other.__dict__) def strhex(x): assert x is not None """Produce a hex-string representation of a sequence of bytes.""" return binascii.hexlify(x).decode("ascii").upper() def bytes2int(x, signed=False): return int.from_bytes(x, signed=signed, byteorder="big") def int2bytes(x, count=None, signed=False): if count: return x.to_bytes(length=count, byteorder="big", signed=signed) else: return x.to_bytes(length=8, byteorder="big", signed=signed).lstrip(b"\x00") class KwException(Exception): """An exception that remembers all arguments passed to the constructor. They can be later accessed by simple member access. """ def __init__(self, **kwargs): super().__init__(kwargs) def __getattr__(self, k): try: return super().__getattr__(k) except AttributeError: return self.args[0].get(k) # was self.args[0][k] class FirmwareKind(IntEnum): Firmware = 0x00 Bootloader = 0x01 Hardware = 0x02 Other = 0x03 @dataclasses.dataclass class FirmwareInfo: kind: FirmwareKind name: str version: str extras: str | None class BatteryStatus(Flag): DISCHARGING = 0x00 RECHARGING = 0x01 ALMOST_FULL = 0x02 FULL = 0x03 SLOW_RECHARGE = 0x04 INVALID_BATTERY = 0x05 THERMAL_ERROR = 0x06 # Solaar internal — not a HID++ protocol value OFFLINE = 0xFF class BatteryLevelApproximation(IntEnum): EMPTY = 0 CRITICAL = 5 LOW = 20 GOOD = 50 FULL = 90 @dataclasses.dataclass class Battery: """Information about the current state of a battery""" ATTENTION_LEVEL = 5 level: Optional[Union[BatteryLevelApproximation, int]] next_level: Optional[Union[NamedInt, int]] status: Optional[BatteryStatus] voltage: Optional[int] light_level: Optional[int] = None # light level for devices with solaar recharging def __post_init__(self): if self.level is None: # infer level from status if needed and possible if self.status == BatteryStatus.FULL: self.level = BatteryLevelApproximation.FULL elif self.status in (BatteryStatus.ALMOST_FULL, BatteryStatus.RECHARGING): self.level = BatteryLevelApproximation.GOOD elif self.status == BatteryStatus.SLOW_RECHARGE: self.level = BatteryLevelApproximation.LOW def ok(self) -> bool: return self.status not in (BatteryStatus.INVALID_BATTERY, BatteryStatus.THERMAL_ERROR) and ( self.level is None or self.level > Battery.ATTENTION_LEVEL ) def charging(self) -> bool: return self.status in ( BatteryStatus.RECHARGING, BatteryStatus.ALMOST_FULL, BatteryStatus.FULL, BatteryStatus.SLOW_RECHARGE, ) def to_str(self) -> str: if isinstance(self.level, BatteryLevelApproximation): level = self.level.name.lower() status = self.status.name.lower().replace("_", " ") if self.status is not None else "Unknown" return _("Battery: %(level)s (%(status)s)") % {"level": _(level), "status": _(status)} elif isinstance(self.level, int): status = self.status.name.lower().replace("_", " ") if self.status is not None else "Unknown" return _("Battery: %(percent)d%% (%(status)s)") % {"percent": self.level, "status": _(status)} return "" class Alert(IntEnum): NONE = 0x00 NOTIFICATION = 0x01 SHOW_WINDOW = 0x02 ATTENTION = 0x04 ALL = 0xFF class Notification(IntEnum): NO_OPERATION = 0x00 CONNECT_DISCONNECT = 0x40 DJ_PAIRING = 0x41 CONNECTED = 0x42 RAW_INPUT = 0x49 PAIRING_LOCK = 0x4A POWER = 0x4B class BusID(IntEnum): USB = 0x03 BLUETOOTH = 0x05 def _read_usb_product_string(hidraw_path): """Read the USB product string from sysfs for a hidraw device path.""" import pathlib try: # /sys/class/hidraw/hidrawN/device/../../product → USB device product string hidraw_name = pathlib.Path(hidraw_path).name product_path = pathlib.Path("/sys/class/hidraw") / hidraw_name / "device" / ".." / ".." / "product" product = product_path.read_text().strip() return product if product else None except (OSError, ValueError): return None Solaar-1.1.20/lib/logitech_receiver/descriptors.py000066400000000000000000000434041522022367600221710ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Devices (not receivers) known to Solaar. Solaar can handle many recent devices without having any entry here. An entry should only be added to fix problems, such as - the device's device ID or WPID falls outside the range that Solaar searches - the device uses a USB interface other than 2 - the name or codename should be different from what the device reports """ from .hidpp10_constants import DEVICE_KIND from .hidpp10_constants import Registers as Reg class _DeviceDescriptor: def __init__( self, name=None, kind=None, wpid=None, codename=None, protocol=None, registers=None, usbid=None, interface=None, btid=None, ): self.name = name self.kind = kind self.wpid = wpid self.codename = codename self.protocol = protocol self.registers = registers self.usbid = usbid self.interface = interface self.btid = btid self.settings = None DEVICES_WPID = {} DEVICES = {} def _D( name, codename=None, kind=None, wpid=None, protocol=None, registers=None, settings=None, usbid=None, interface=None, btid=None, ): if kind is None: kind = ( DEVICE_KIND.mouse if "Mouse" in name else DEVICE_KIND.keyboard if "Keyboard" in name else DEVICE_KIND.numpad if "Number Pad" in name else DEVICE_KIND.touchpad if "Touchpad" in name else DEVICE_KIND.trackball if "Trackball" in name else None ) assert kind is not None, f"descriptor for {name} does not have kind set" if protocol is not None: if wpid: for w in wpid if isinstance(wpid, tuple) else (wpid,): if protocol > 1.0: assert w[0:1] == "4", f"{name} has protocol {protocol:0.1f}, wpid {w}" else: if w[0:1] == "1": assert kind == DEVICE_KIND.mouse, f"{name} has protocol {protocol:0.1f}, wpid {w}" elif w[0:1] == "2": assert kind in ( DEVICE_KIND.keyboard, DEVICE_KIND.numpad, ), f"{name} has protocol {protocol:0.1f}, wpid {w}" device_descriptor = _DeviceDescriptor( name=name, kind=kind, wpid=wpid, codename=codename, protocol=protocol, registers=registers, usbid=usbid, interface=interface, btid=btid, ) if usbid: found = get_usbid(usbid) assert found is None, f"duplicate usbid in device descriptors: {found}" if btid: found = get_btid(btid) assert found is None, f"duplicate btid in device descriptors: {found}" assert codename not in DEVICES, f"duplicate codename in device descriptors: {DEVICES[codename]}" if codename: DEVICES[codename] = device_descriptor if wpid: for w in wpid if isinstance(wpid, tuple) else (wpid,): assert w not in DEVICES_WPID, f"duplicate wpid in device descriptors: {DEVICES_WPID[w]}" DEVICES_WPID[w] = device_descriptor def get_wpid(wpid): return DEVICES_WPID.get(wpid) def get_codename(codename): return DEVICES.get(codename) def get_usbid(usbid): if isinstance(usbid, str): usbid = int(usbid, 16) found = next((x for x in DEVICES.values() if x.usbid == usbid), None) return found def get_btid(btid): if isinstance(btid, str): btid = int(btid, 16) found = next((x for x in DEVICES.values() if x.btid == btid), None) return found # Some HID++1.0 registers and HID++2.0 features can be discovered at run-time, # so they are not specified here. # # State registers (battery, leds, some features, etc) are only used by # HID++ 1.0 devices, while HID++ 2.0 devices use features for the same # functionalities. # Well-known registers (in hex): # * 00 - notification flags (all devices) # 01 - mice: smooth scrolling # 07 - battery status # 09 - keyboards: FN swap (if it has the FN key) # 0D - battery charge # a device may have either the 07 or 0D register available; # no known device uses both # 51 - leds # 63 - mice: DPI # * F1 - firmware info # Some registers appear to be universally supported, no matter the HID++ version # (marked with *). The rest may or may not be supported, and their values may or # may not mean the same thing across different devices. # The 'codename' and 'kind' fields are usually guessed from the device name, # but in some cases (like the Logitech Cube) that heuristic fails and they have # to be specified. # # The 'protocol' and 'wpid' fields are optional (they can be discovered at # runtime), but specifying them here speeds up device discovery and reduces the # USB traffic Solaar has to do to fully identify peripherals. # # The 'registers' field indicates read-only registers, specifying a state. These # are valid (AFAIK) only to HID++ 1.0 devices. # The 'settings' field indicates a read/write register; based on them Solaar # generates, at runtime, the settings controls in the device panel. # Solaar now sets up this field in settings_templates.py to eliminate a imports loop. # HID++ 1.0 devices may only have register-based settings; HID++ 2.0 devices may only have # feature-based settings. # Devices are organized by kind # Within kind devices are sorted by wpid, then by usbid, then by btid, with missing values sorted later # Keyboards _D("Wireless Keyboard EX110", codename="EX110", protocol=1.0, wpid="0055", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Keyboard S510", codename="S510", protocol=1.0, wpid="0056", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Wave Keyboard K550", codename="K550", protocol=1.0, wpid="0060", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Keyboard EX100", codename="EX100", protocol=1.0, wpid="0065", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Keyboard MK300", codename="MK300", protocol=1.0, wpid="0068", registers=(Reg.BATTERY_STATUS,)) _D("Number Pad N545", codename="N545", protocol=1.0, wpid="2006", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Compact Keyboard K340", codename="K340", protocol=1.0, wpid="2007", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Keyboard MK700", codename="MK700", protocol=1.0, wpid="2008", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Wave Keyboard K350", codename="K350", protocol=1.0, wpid="200A", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Keyboard MK320", codename="MK320", protocol=1.0, wpid="200F", registers=(Reg.BATTERY_STATUS,)) _D( "Wireless Illuminated Keyboard K800", codename="K800", protocol=1.0, wpid="2010", registers=(Reg.BATTERY_STATUS, Reg.THREE_LEDS), ) _D("Wireless Keyboard K520", codename="K520", protocol=1.0, wpid="2011", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Solar Keyboard K750", codename="K750", protocol=2.0, wpid="4002") _D("Wireless Keyboard K270 (unifying)", codename="K270", protocol=2.0, wpid="4003") # incorrect _D("Wireless Keyboard K360", codename="K360", protocol=2.0, wpid="4004") _D("Wireless Keyboard K230", codename="K230", protocol=2.0, wpid="400D") _D("Wireless Touch Keyboard K400", codename="K400", protocol=2.0, wpid=("400E", "4024")) _D("Wireless Keyboard MK270", codename="MK270", protocol=2.0, wpid="4023") _D("Illuminated Living-Room Keyboard K830", codename="K830", protocol=2.0, wpid="4032") _D("Wireless Touch Keyboard K400 Plus", codename="K400 Plus", protocol=2.0, wpid="404D") _D("Wireless Multi-Device Keyboard K780", codename="K780", protocol=4.5, wpid="405B") _D("Wireless Keyboard K375s", codename="K375s", protocol=2.0, wpid="4061") _D("Craft Advanced Keyboard", codename="Craft", protocol=4.5, wpid="4066", btid=0xB350) _D("Wireless Illuminated Keyboard K800 new", codename="K800 new", protocol=4.5, wpid="406E") _D("Wireless Keyboard K470", codename="K470", protocol=4.5, wpid="4075") _D("MX Keys Keyboard", codename="MX Keys", protocol=4.5, wpid="408A", btid=0xB35B) _D( "G915 TKL LIGHTSPEED Wireless RGB Mechanical Gaming Keyboard", codename="G915 TKL", protocol=4.2, wpid="408E", usbid=0xC343, ) _D("Illuminated Keyboard", codename="Illuminated", protocol=1.0, usbid=0xC318, interface=1) _D("G213 Prodigy Gaming Keyboard", codename="G213", usbid=0xC336, interface=1) _D("G512 RGB Mechanical Gaming Keyboard", codename="G512", usbid=0xC33C, interface=1) _D("G815 Mechanical Keyboard", codename="G815", usbid=0xC33F, interface=1) _D("diNovo Edge Keyboard", codename="diNovo", protocol=1.0, wpid="C714") _D("K845 Mechanical Keyboard", codename="K845", usbid=0xC341, interface=1) # Mice _D("LX5 Cordless Mouse", codename="LX5", protocol=1.0, wpid="0036", registers=(Reg.BATTERY_STATUS,)) _D("LX7 Cordless Laser Mouse", codename="LX7", protocol=1.0, wpid="0039", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Wave Mouse M550", codename="M550", protocol=1.0, wpid="003C", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Mouse EX100", codename="EX100m", protocol=1.0, wpid="003F", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Mouse M30", codename="M30", protocol=1.0, wpid="0085", registers=(Reg.BATTERY_STATUS,)) _D("MX610 Laser Cordless Mouse", codename="MX610", protocol=1.0, wpid="1001", registers=(Reg.BATTERY_STATUS,)) _D("G7 Cordless Laser Mouse", codename="G7", protocol=1.0, wpid="1002", registers=(Reg.BATTERY_STATUS,)) _D("V400 Laser Cordless Mouse", codename="V400", protocol=1.0, wpid="1003", registers=(Reg.BATTERY_STATUS,)) _D("MX610 Left-Handled Mouse", codename="MX610L", protocol=1.0, wpid="1004", registers=(Reg.BATTERY_STATUS,)) _D("V450 Laser Cordless Mouse", codename="V450", protocol=1.0, wpid="1005", registers=(Reg.BATTERY_STATUS,)) _D( "VX Revolution", codename="VX Revolution", kind=DEVICE_KIND.mouse, protocol=1.0, wpid=("1006", "100D", "0612"), registers=(Reg.BATTERY_CHARGE,), ) _D( "MX Air", codename="MX Air", protocol=1.0, kind=DEVICE_KIND.mouse, wpid=("1007", "100E"), registers=Reg.BATTERY_CHARGE, ) _D( "MX Revolution", codename="MX Revolution", protocol=1.0, kind=DEVICE_KIND.mouse, wpid=("1008", "100C"), registers=(Reg.BATTERY_CHARGE,), ) _D( "MX620 Laser Cordless Mouse", codename="MX620", protocol=1.0, wpid=("100A", "1016"), registers=(Reg.BATTERY_CHARGE,), ) _D( "VX Nano Cordless Laser Mouse", codename="VX Nano", protocol=1.0, wpid=("100B", "100F"), registers=(Reg.BATTERY_CHARGE,), ) _D( "V450 Nano Cordless Laser Mouse", codename="V450 Nano", protocol=1.0, wpid="1011", registers=(Reg.BATTERY_CHARGE,), ) _D( "V550 Nano Cordless Laser Mouse", codename="V550 Nano", protocol=1.0, wpid="1013", registers=(Reg.BATTERY_CHARGE,), ) _D( "MX 1100 Cordless Laser Mouse", codename="MX 1100", protocol=1.0, kind=DEVICE_KIND.mouse, wpid="1014", registers=(Reg.BATTERY_CHARGE,), ) _D("Anywhere Mouse MX", codename="Anywhere MX", protocol=1.0, wpid="1017", registers=(Reg.BATTERY_CHARGE,)) _D( "Performance Mouse MX", codename="Performance MX", protocol=1.0, wpid="101A", registers=(Reg.BATTERY_STATUS, Reg.THREE_LEDS), ) _D( "Marathon Mouse M705 (M-R0009)", codename="M705 (M-R0009)", protocol=1.0, wpid="101B", registers=(Reg.BATTERY_CHARGE,), ) _D( "Wireless Mouse M350", codename="M350", protocol=1.0, wpid="101C", registers=(Reg.BATTERY_CHARGE,), ) _D( "Wireless Mouse M505", codename="M505/B605", protocol=1.0, wpid="101D", registers=(Reg.BATTERY_CHARGE,), ) _D( "Wireless Mouse M305", codename="M305", protocol=1.0, wpid="101F", registers=(Reg.BATTERY_STATUS,), ) _D( "Wireless Mouse M215", codename="M215", protocol=1.0, wpid="1020", ) _D( "G700 Gaming Mouse", codename="G700", protocol=1.0, wpid="1023", usbid=0xC06B, interface=1, registers=( Reg.BATTERY_STATUS, Reg.THREE_LEDS, ), ) _D("Wireless Mouse M310", codename="M310", protocol=1.0, wpid="1024", registers=(Reg.BATTERY_STATUS,)) _D("Wireless Mouse M510", codename="M510", protocol=1.0, wpid="1025", registers=(Reg.BATTERY_STATUS,)) _D("Fujitsu Sonic Mouse", codename="Sonic", protocol=1.0, wpid="1029") _D( "G700s Gaming Mouse", codename="G700s", protocol=1.0, wpid="102A", usbid=0xC07C, interface=1, registers=( Reg.BATTERY_STATUS, Reg.THREE_LEDS, ), ) _D("Couch Mouse M515", codename="M515", protocol=2.0, wpid="4007") # _D("Wireless Mouse M175", codename="M175", protocol=2.0, wpid="4008") _D("Wireless Mouse M325", codename="M325", protocol=2.0, wpid="400A") _D("Wireless Mouse M525", codename="M525", protocol=2.0, wpid="4013") _D("Wireless Mouse M345", codename="M345", protocol=2.0, wpid="4017") _D("Wireless Mouse M187", codename="M187", protocol=2.0, wpid="4019") _D("Touch Mouse M600", codename="M600", protocol=2.0, wpid="401A") _D("Wireless Mouse M150", codename="M150", protocol=2.0, wpid="4022") _D("Wireless Mouse M185", codename="M185", protocol=2.0, wpid="4038") _D("Wireless Mouse MX Master", codename="MX Master", protocol=4.5, wpid="4041", btid=0xB012) _D("Anywhere Mouse MX 2", codename="Anywhere MX 2", protocol=4.5, wpid="404A") _D("Wireless Mouse M510", codename="M510v2", protocol=2.0, wpid="4051") _D("Wireless Mouse M185 new", codename="M185n", protocol=4.5, wpid="4054") _D("Wireless Mouse M185/M235/M310", codename="M185/M235/M310", protocol=4.5, wpid="4055") _D("Wireless Mouse MX Master 2S", codename="MX Master 2S", protocol=4.5, wpid="4069", btid=0xB019) _D("Multi Device Silent Mouse M585/M590", codename="M585/M590", protocol=4.5, wpid="406B") _D( "Marathon Mouse M705 (M-R0073)", codename="M705 (M-R0073)", protocol=4.5, wpid="406D", ) _D("MX Vertical Wireless Mouse", codename="MX Vertical", protocol=4.5, wpid="407B", btid=0xB020, usbid=0xC08A) _D("Wireless Mouse Pebble M350", codename="Pebble", protocol=2.0, wpid="4080") _D("MX Master 3 Wireless Mouse", codename="MX Master 3", protocol=4.5, wpid="4082", btid=0xB023) _D("PRO X Wireless", kind="mouse", codename="PRO X", wpid="4093", usbid=0xC094) _D("G9 Laser Mouse", codename="G9", usbid=0xC048, interface=1, protocol=1.0) _D("G9x Laser Mouse", codename="G9x", usbid=0xC066, interface=1, protocol=1.0) _D("G502 Gaming Mouse", codename="G502", usbid=0xC07D, interface=1) _D("G402 Gaming Mouse", codename="G402", usbid=0xC07E, interface=1) _D("G900 Chaos Spectrum Gaming Mouse", codename="G900", usbid=0xC081) _D("G403 Gaming Mouse", codename="G403", usbid=0xC082) _D("G903 Lightspeed Gaming Mouse", codename="G903", usbid=0xC086) _D("G703 Lightspeed Gaming Mouse", codename="G703", usbid=0xC087) _D("GPro Gaming Mouse", codename="GPro", usbid=0xC088) _D("G502 SE Hero Gaming Mouse", codename="G502 Hero", usbid=0xC08B, interface=1) _D("G502 Lightspeed Gaming Mouse", codename="G502 Lightspeed", usbid=0xC08D) _D("MX518 Gaming Mouse", codename="MX518", usbid=0xC08E, interface=1) _D("G703 Hero Gaming Mouse", codename="G703 Hero", usbid=0xC090) _D("G903 Hero Gaming Mouse", codename="G903 Hero", usbid=0xC091) _D(None, kind=DEVICE_KIND.mouse, usbid=0xC092, interface=1) # two mice share this ID _D("M500S Mouse", codename="M500S", usbid=0xC093, interface=1) # _D('G600 Gaming Mouse', codename='G600 Gaming', usbid=0xc24a, interface=1) # not an HID++ device _D("G500 Gaming Mouse", codename="G500 Gaming", usbid=0xC068, interface=1, protocol=1.0) _D("G500s Gaming Mouse", codename="G500s Gaming", usbid=0xC24E, interface=1, protocol=1.0) _D("G502 Proteus Spectrum Optical Mouse", codename="G502 Proteus Spectrum", usbid=0xC332, interface=1) _D("Logitech PRO Gaming Keyboard", codename="PRO Gaming Keyboard", usbid=0xC339, interface=1) _D("Logitech MX Revolution Mouse M-RCL 124", codename="M-RCL 124", btid=0xB007, interface=1) # Trackballs _D("Wireless Trackball M570", codename="M570") # Touchpads _D("Wireless Touchpad", codename="Wireless Touch", protocol=2.0, wpid="4011") _D("Wireless Rechargeable Touchpad T650", codename="T650", protocol=2.0, wpid="4101") _D( "G Powerplay", codename="Powerplay", protocol=2.0, kind=DEVICE_KIND.touchpad, wpid="405F" ) # To override self-identification # Headset _D("G533 Gaming Headset", codename="G533 Headset", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0A66) _D("G535 Gaming Headset", codename="G535 Headset", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0AC4) _D("G935 Gaming Headset", codename="G935 Headset", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0A87) _D("G733 Gaming Headset", codename="G733 Headset", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0AB5) _D( "G733 Gaming Headset", codename="G733 Headset New", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0AFE, ) _D( "PRO X Wireless Gaming Headset", codename="PRO Headset", protocol=2.0, interface=3, kind=DEVICE_KIND.headset, usbid=0x0ABA, ) # PRO X 2 LIGHTSPEED Gaming Headset (0x0AF7) — fully probed via Centurion transport, no static descriptor needed # G522 LIGHTSPEED Gaming Headset (0x0B18 dongle, 0x0B19 wired) — Centurion 0x50 variant, no static descriptor needed Solaar-1.1.20/lib/logitech_receiver/desktop_notifications.py000066400000000000000000000110561522022367600242300ustar00rootroot00000000000000## Copyright (C) 2024 Solaar contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Implements the desktop notification service.""" import importlib import logging logger = logging.getLogger(__name__) def notifications_available(): """Checks if notification service is available.""" notifications_supported = False try: import gi gi.require_version("Notify", "0.7") gi.require_version("Gtk", "3.0") importlib.util.find_spec("gi.repository.GLib") importlib.util.find_spec("gi.repository.Gtk") importlib.util.find_spec("gi.repository.Notify") notifications_supported = True except ValueError as e: logger.warning(f"Notification service is not available: {e}") return notifications_supported available = notifications_available() if available: from gi.repository import GLib from gi.repository import Gtk from gi.repository import Notify # cache references to shown notifications here to allow reuse _notifications = {} _ICON_LISTS = {} def init(): """Initialize desktop notifications.""" global available if available: if not Notify.is_initted(): if logger.isEnabledFor(logging.INFO): logger.info("starting desktop notifications") try: return Notify.init("solaar") # replace with better name later except Exception: logger.exception("initializing desktop notifications") available = False return available and Notify.is_initted() def uninit(): """Stop desktop notifications.""" if available and Notify.is_initted(): if logger.isEnabledFor(logging.INFO): logger.info("stopping desktop notifications") _notifications.clear() Notify.uninit() def show(dev, message: str, icon=None): """Show a notification with title and text.""" if available and (Notify.is_initted() or init()): summary = dev.name n = _notifications.get(summary) # reuse notification of same name if n is None: n = _notifications[summary] = Notify.Notification() icon_name = device_icon_name(dev.name, dev.kind) if icon is None else icon n.update(summary, message, icon_name) n.set_urgency(Notify.Urgency.NORMAL) n.set_hint("desktop-entry", GLib.Variant("s", "solaar")) # replace with better name late try: return n.show() except Exception: logger.exception(f"showing {n}") def device_icon_list(name="_", kind=None): icon_list = _ICON_LISTS.get(name) if icon_list is None: # names of possible icons, in reverse order of likelihood # the theme will hopefully pick up the most appropriate icon_list = ["preferences-desktop-peripherals"] kind = str(kind) if kind: if kind == "numpad": icon_list += ("input-keyboard", "input-dialpad") elif kind == "touchpad": icon_list += ("input-mouse", "input-tablet") elif kind == "trackball": icon_list += ("input-mouse",) elif kind == "headset": icon_list += ("audio-headphones", "audio-headset") icon_list += (f"input-{kind}",) _ICON_LISTS[name] = icon_list return icon_list def device_icon_name(name, kind=None): _default_theme = Gtk.IconTheme.get_default() icon_list = device_icon_list(name, kind) for n in reversed(icon_list): if _default_theme.has_icon(n): return n else: def init(): return False def uninit(): return None def show(dev, reason=None): return None Solaar-1.1.20/lib/logitech_receiver/device.py000066400000000000000000001445261522022367600210760ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import errno import logging import struct import threading import time import typing from typing import Callable from typing import Optional from typing import Protocol from solaar import configuration from . import base from . import descriptors from . import exceptions from . import hidpp10 from . import hidpp10_constants from . import hidpp20 from . import settings from . import settings_templates from .common import Alert from .common import Battery from .common import BatteryStatus from .common import _read_usb_product_string from .hidpp10_constants import NotificationFlag from .hidpp20_constants import SupportedFeature if typing.TYPE_CHECKING: from logitech_receiver import common logger = logging.getLogger(__name__) _hidpp10 = hidpp10.Hidpp10() _hidpp20 = hidpp20.Hidpp20() class LowLevelInterface(Protocol): def open_path(self, path) -> int: ... def find_paired_node(self, receiver_path: str, index: int, timeout: int): ... def ping(self, handle, number, long_message: bool): ... def request(self, handle, devnumber, request_id, *params, **kwargs): ... def close(self, handle, *args, **kwargs) -> bool: ... def create_device(low_level: LowLevelInterface, device_info, setting_callback=None): """Opens a Logitech Device found attached to the machine, by Linux device path. :returns: An open file handle for the found receiver, or None. """ try: handle = low_level.open_path(device_info.path) if handle: if getattr(device_info, "centurion", False): report_id = getattr(device_info, "centurion_report_id", None) or base.CENTURION_REPORT_ID state = base.CenturionHandleState(report_id=report_id) base._centurion_handles[int(handle)] = state base.probe_centurion_device_addr(handle, state) # a direct connected device might not be online (as reported by user) return Device( low_level, None, None, None, handle=handle, device_info=device_info, setting_callback=setting_callback, ) except OSError as e: logger.exception("open %s", device_info) if e.errno == errno.EACCES: raise e except Exception as e: logger.exception("open %s", device_info) raise e class Device: instances = [] read_register: Callable = hidpp10.read_register write_register: Callable = hidpp10.write_register def __init__( self, low_level: LowLevelInterface, receiver, number, online, pairing_info=None, handle=None, device_info=None, setting_callback=None, ): assert receiver or device_info if receiver: assert 0 < number <= 15 # some receivers have devices past their max # of devices self.low_level = low_level self.number = number # will be None at this point for directly connected devices self.online = online # is the device online? - gates many atempts to contact the device self.descriptor = None self.isDevice = True # some devices act as receiver so we need a property to distinguish them self.may_unpair = False self.receiver = receiver self.handle = handle self.path = device_info.path if device_info else None self.product_id = device_info.product_id if device_info else None self.hidpp_short = device_info.hidpp_short if device_info else None self.hidpp_long = device_info.hidpp_long if device_info else None self.centurion = device_info.centurion if device_info else False self._centurion_usb_name = None if self.centurion: self.hidpp_long = True # Centurion devices always use long HID++ messages # Read USB product string for device name — avoids slow bridge probe via CENTURION_DEVICE_NAME. # device_info.product is often None (udev reads USB interface attrs, not device attrs), # so fall back to reading from sysfs. self._centurion_usb_name = getattr(device_info, "product", None) if device_info else None if not self._centurion_usb_name and self.path: self._centurion_usb_name = _read_usb_product_string(self.path) self.bluetooth = device_info.bus_id == 0x0005 if device_info else False # Bluetooth needs long messages self.hid_serial = device_info.serial if device_info else None self.setting_callback = setting_callback # for changes to settings self.status_callback = None # for changes to other potentially visible aspects self.wpid = pairing_info["wpid"] if pairing_info else None # the Wireless PID is unique per device model self._kind = pairing_info["kind"] if pairing_info else None # mouse, keyboard, etc (see hidpp10.DEVICE_KIND) if self._kind is None and self.centurion: self._kind = hidpp10_constants.DEVICE_KIND.headset # every Centurion-transport device so far is a headset self._serial = pairing_info["serial"] if pairing_info else None # serial number (an 8-char hex string) self._polling_rate = pairing_info["polling"] if pairing_info else None self._power_switch = pairing_info["power_switch"] if pairing_info else None self._name = None # the full name of the model self._codename = None # Unifying peripherals report a codename. self._protocol = None # HID++ protocol version, 1.0 or 2.0 self._unitId = None # unit id (distinguishes within a model - generally the same as serial) self._modelId = None # model id (contains identifiers for the transports of the device) self._tid_map = None # map from transports to product identifiers self._persister = None # persister holds settings self._led_effects = self._firmware = self._keys = self._remap_keys = self._gestures = self._force_buttons = None self._keyboard_layout = None # lazy: country code from HID++ 0x4540, None if unsupported self._profiles = self._backlight = self._settings = None self.registers = [] self.notification_flags = None self.battery_info = None self.link_encrypted = None self._active = None # lags self.online - is used to help determine when to setup devices self.present = True # used for devices that are integral with their receiver but that separately be disconnected self._feature_settings_checked = False self._gestures_lock = threading.Lock() self._settings_lock = threading.Lock() self._persister_lock = threading.Lock() self._simple_lock = threading.Lock() self._notification_handlers = {} # See `add_notification_handler` self.cleanups = [] # functions to run on the device when it is closed if not self.path: self.path = self.low_level.find_paired_node(receiver.path, number, 1) if receiver else None if not self.handle: try: self.handle = self.low_level.open_path(self.path) if self.path else None except Exception: # maybe the device wasn't set up try: time.sleep(1) self.handle = self.low_level.open_path(self.path) if self.path else None except Exception: # give up self.handle = None # should this give up completely? if receiver: if not self.wpid: raise exceptions.NoSuchDevice( number=number, receiver=receiver, error="no wpid for device connected to receiver" ) self.descriptor = descriptors.get_wpid(self.wpid) if self.descriptor is None: codename = self.receiver.device_codename(self.number) # Last chance to get a descriptor, may fail if codename: self._codename = codename self.descriptor = descriptors.get_codename(self._codename) else: self.descriptor = ( descriptors.get_btid(self.product_id) if self.bluetooth else descriptors.get_usbid(self.product_id) ) # for direct-connected devices get 'number' from descriptor protocol else use 0xFF self.number = 0x00 if self.descriptor and self.descriptor.protocol and self.descriptor.protocol < 2.0 else 0xFF try: # determine whether a direct-connected device is online self.ping() except exceptions.NoSuchDevice as e: if self.number == 0xFF: # guessed wrong number? self.number = 0x00 self.ping() else: raise e if self.descriptor: self._name = self.descriptor.name if self._codename is None: self._codename = self.descriptor.codename if self._kind is None: self._kind = self.descriptor.kind self._protocol = self.descriptor.protocol if self.descriptor.protocol else None self.registers = self.descriptor.registers if self.descriptor.registers else [] # Centurion devices always use HID++ 2.0 features regardless of the # protocol version the dongle reports (e.g. G522 reports 1.1). if self._protocol is not None and not self.centurion: self.features = {} if self._protocol < 2.0 else hidpp20.FeaturesArray(self) else: self.features = hidpp20.FeaturesArray(self) # may be a 2.0 device; if not, it will fix itself later Device.instances.append(self) def find(self, id): # find a device by serial number or unit ID or name or codename assert id, "need id to find a device" for device in Device.instances: if device.online and (device.unitId == id or device.serial == id or device.name == id or device.codename == id): return device @property def protocol(self): if not self._protocol: try: self.ping() except exceptions.NoSuchDevice: logger.warning("device %s inaccessible - no protocol set", self) result = self._protocol or 0 # Centurion devices always use HID++ 2.0 features regardless of the # protocol version the dongle reports (e.g. G522 reports 1.1). # Ensure all `protocol < 2.0` gates route through the 2.0 code path. if self.centurion and result < 2.0: return 2.0 return result @property def codename(self): if not self._codename: if self.online and self.protocol >= 2.0: if not self.centurion: self._codename = _hidpp20.get_friendly_name(self) if not self._codename and self.name: # Use the full live name; only drop a leading "Logitech". # Truncating at the first space mangled good names like # "G502 X PLUS" (direct USB connection, no friendly name). names = self.name.split(" ") if not self.centurion and len(names) > 1 and names[0] == "Logitech": self._codename = " ".join(names[1:]) else: self._codename = self.name if not self._codename and self.receiver: codename = self.receiver.device_codename(self.number) if codename: self._codename = codename elif self.protocol < 2.0: self._codename = "? (%s)" % (self.wpid or self.product_id) return self._codename or f"?? ({self.wpid or self.product_id})" @property def name(self): if not self._name: with self._simple_lock: if self._name is None: if self.online and self.centurion: self._name = _hidpp20.get_name_centurion(self) or getattr(self, "_centurion_usb_name", None) if not self._name: self._name = f"Unknown device {self.wpid or self.product_id}" elif self.online and self.protocol >= 2.0: self._name = _hidpp20.get_name(self) return self._name or self._codename or f"Unknown device {self.wpid or self.product_id}" def get_ids(self): if self.centurion: self._get_ids_centurion() return ids = _hidpp20.get_ids(self) if ids: self._unitId, self._modelId, self._tid_map = ids if logger.isEnabledFor(logging.INFO) and self._serial and self._serial != self._unitId: logger.info("%s: unitId %s does not match serial %s", self, self._unitId, self._serial) def _get_ids_centurion(self): if getattr(self, "_centurion_ids_done", False): return self._centurion_ids_done = True serial = _hidpp20.get_serial_centurion(self) if not serial or not serial.strip() or not serial.strip().isprintable(): serial = _hidpp20.get_serial_centurion_sub(self) if serial and serial.strip() and serial.strip().isprintable(): self._serial = serial.strip() self._unitId = self._serial hw_info = _hidpp20.get_hardware_info_centurion(self) if hw_info: model_id, hw_revision, product_id = hw_info # modelId is the stable per-model disambiguator (G522 0x32, G325 # 0x44). productId is shared across the headset family and varies # by firmware (G522 0x0508 -> 0x0509), so it must NOT key modelId. self._modelId = f"{model_id:02X}" self._tid_map = {"usbid": f"{product_id:04X}"} @property def unitId(self): if not self._unitId and self.online and self.protocol >= 2.0: self.get_ids() return self._unitId @property def modelId(self): if not self._modelId and self.online and self.protocol >= 2.0: self.get_ids() return self._modelId @property def tid_map(self): if not self._tid_map and self.online and self.protocol >= 2.0: self.get_ids() return self._tid_map @property def kind(self): # Centurion devices are seeded with kind=headset at construction, so # this online lookup only runs for descriptor-less HID++ 2.0 devices. if not self._kind and self.online and self.protocol >= 2.0: self._kind = _hidpp20.get_kind(self) return self._kind or "?" @property def firmware(self) -> tuple[common.FirmwareInfo]: if self._firmware is None and self.online: if self.centurion: self._firmware = _hidpp20.get_firmware_centurion_sub(self) or _hidpp20.get_firmware_centurion(self) elif self.protocol >= 2.0: self._firmware = _hidpp20.get_firmware(self) else: self._firmware = _hidpp10.get_firmware(self) return self._firmware or () @property def serial(self): if not self._serial and self.online and self.centurion: self.get_ids() return self._serial or "" @property def id(self): return self.unitId or self.serial @property def power_switch_location(self): return self._power_switch @property def polling_rate(self): if self.online and self.protocol >= 2.0: rate = _hidpp20.get_polling_rate(self) self._polling_rate = rate if rate else self._polling_rate return self._polling_rate @property def keyboard_layout(self): if self._keyboard_layout is None and self.online and self.protocol >= 2.0: if SupportedFeature.KEYBOARD_LAYOUT_2 in self.features: self._keyboard_layout = _hidpp20.get_keyboard_layout(self) return self._keyboard_layout @property def led_effects(self): if not self._led_effects and self.online and self.protocol >= 2.0: if SupportedFeature.COLOR_LED_EFFECTS in self.features: self._led_effects = hidpp20.LEDEffectsInfo(self) elif SupportedFeature.RGB_EFFECTS in self.features: self._led_effects = hidpp20.RGBEffectsInfo(self) return self._led_effects @property def keys(self): if not self._keys: if self.online and self.protocol >= 2.0: self._keys = _hidpp20.get_keys(self) or () return self._keys @property def remap_keys(self): if self._remap_keys is None: if self.online and self.protocol >= 2.0: self._remap_keys = _hidpp20.get_remap_keys(self) or () return self._remap_keys @property def gestures(self): if self._gestures is None: with self._gestures_lock: if self._gestures is None: if self.online and self.protocol >= 2.0: self._gestures = _hidpp20.get_gestures(self) or () return self._gestures @property def backlight(self): if self._backlight is None: if self.online and self.protocol >= 2.0: self._backlight = _hidpp20.get_backlight(self) return self._backlight @property def profiles(self): if self._profiles is None: if self.online and self.protocol >= 2.0: self._profiles = _hidpp20.get_profiles(self) return self._profiles def force_buttons(self): if self._force_buttons is None: if self.online and self.protocol >= 2.0: self._force_buttons = _hidpp20.get_force_buttons(self) or () return self._force_buttons def set_configuration(self, configuration_, no_reply=False): if self.online and self.protocol >= 2.0: _hidpp20.config_change(self, configuration_, no_reply=no_reply) def signal_configuration_complete(self, cookie=None): """SetComplete on ConfigChange to ack end of configuration. With no cookie, sends the host's session counter (see Hidpp20.set_configuration_complete).""" if self.online and self.protocol >= 2.0: _hidpp20.set_configuration_complete(self, cookie=cookie) def _record_config_cookie(self): """After a successful apply, SetComplete with the next session cookie and persist it so the dedup gate in apply_settings_if_needed can detect drift on follow-up reconfig notifications within this session.""" if self.protocol < 2.0: return if not (self.features and SupportedFeature.CONFIG_CHANGE in self.features): return cookie = _hidpp20.next_session_cookie() self.signal_configuration_complete(cookie=cookie) if self.persister is not None: self.persister["_config_cookie"] = [cookie[0], cookie[1]] def apply_settings_if_needed(self): """Cookie-gated dedup helper for repeat WIRELESS_DEVICE_STATUS reconfig notifications on an already-active device. Skips when the live ConfigChange cookie matches the value stored by the most recent apply, otherwise applies and re-records. Must NOT be used as the initial-activation apply path — across power cycles, devices whose firmware resets the cookie to a fixed value would falsely match a stored cookie from a prior session and skip the apply the device actually needs. Returns True if apply ran, False if it was skipped.""" if not self.online: return False if self.protocol >= 2.0 and self.features and SupportedFeature.CONFIG_CHANGE in self.features: live = _hidpp20.get_configuration_cookie(self) if live and len(live) >= 2: stored = self.persister.get("_config_cookie") if self.persister else None live_pair = [live[0], live[1]] if stored == live_pair: if logger.isEnabledFor(logging.INFO): logger.info( "%s: config cookie %02X%02X matches stored — skip apply_all_settings", self, live[0], live[1], ) return False if logger.isEnabledFor(logging.INFO): logger.info( "%s: config cookie live=%02X%02X stored=%s — apply_all_settings", self, live[0], live[1], "%02X%02X" % (stored[0], stored[1]) if stored else "None", ) settings.apply_all_settings(self) self._record_config_cookie() return True def reset(self, no_reply=False): self.set_configuration(0, no_reply) @property def persister(self): if not self._persister: with self._persister_lock: if not self._persister: self._persister = configuration.persister(self) return self._persister @property def settings(self): if not self._settings: with self._settings_lock: if not self._settings: settings = [] if self.persister and self.descriptor and self.descriptor.settings: for sclass in self.descriptor.settings: try: setting = sclass.build(self) except Exception as e: # Do nothing if the device is offline setting = None if self.online: raise e if setting is not None: settings.append(setting) self._settings = settings if not self._feature_settings_checked: with self._settings_lock: if not self._feature_settings_checked: self._feature_settings_checked = settings_templates.check_feature_settings(self, self._settings) return self._settings def battery(self): # None or level, next, status, voltage if self.protocol < 2.0: if self.centurion: logger.debug( "%s: battery() dispatching HID++ 1.0 path for a Centurion device " "(protocol=%s, _protocol=%s) — device_addr probe likely failed, " "expect INVALID_SUB_ID_COMMAND", self, self.protocol, self._protocol, ) return _hidpp10.get_battery(self) else: battery_feature = self.persister.get("_battery", None) if self.persister else None if battery_feature != 0: result = _hidpp20.get_battery(self, battery_feature) try: feature, battery = result if self.persister and battery_feature is None: self.persister["_battery"] = feature.value return battery except Exception: if self.persister and battery_feature is None and result is not None and result != 0: self.persister["_battery"] = result.value def set_battery_info(self, info): """Update battery information for device, calling changed callback if necessary""" if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: battery %s, %s", self, info.level, info.status) if info.level is None and self.battery_info: # use previous level if missing from new information info.level = self.battery_info.level changed = self.battery_info != info self.battery_info, old_info = info, self.battery_info if old_info is None: old_info = Battery(None, None, None, None) alert, reason = Alert.NONE, None if not info.ok(): logger.warning("%s: battery %d%%, ALERT %s", self, info.level, info.status) if old_info.status != info.status: alert = Alert.NOTIFICATION | Alert.ATTENTION reason = info.to_str() if changed or reason: # update the leds on the device, if any _hidpp10.set_3leds(self, info.level, charging=info.charging(), warning=bool(alert)) self.changed(active=True, alert=alert, reason=reason) # Retrieve and regularize battery status def read_battery(self): if self.online: battery = self.battery() self.set_battery_info(battery if battery is not None else Battery(None, None, None, None)) def changed(self, active=None, alert=Alert.NONE, reason=None, push=False): """The status of the device had changed, so invoke the status callback. Also push notifications and settings to the device when necessary.""" if logger.isEnabledFor(logging.DEBUG): logger.debug("device %d changing: active=%s %s present=%s", self.number, active, self._active, self.present) if active is not None: self.online = active was_active, self._active = self._active, active if active: # Push settings for new devices when devices request software reconfiguration # and when devices become active if they don't have wireless device status feature, if ( was_active is None or not was_active or push and (not self.features or SupportedFeature.WIRELESS_DEVICE_STATUS not in self.features) ): if logger.isEnabledFor(logging.INFO): logger.info("%s pushing device settings %s", self, self.settings) # Activation apply must be unconditional — across power # cycles, the device may have lost state while its cookie # reset to a value that happens to match what we stored # last session. Cookie comparison is only a valid dedup # signal for repeat reconfig notifications within an # already-active session (see apply_settings_if_needed). settings.apply_all_settings(self) self._record_config_cookie() if not was_active: if self.protocol < 2.0: # Make sure to set notification flags on the device self.notification_flags = self.enable_connection_notifications() self.read_battery() # battery information may have changed so try to read it now elif was_active and self.receiver and not isinstance(self.receiver, CenturionReceiver): hidpp10.set_configuration_pending_flags(self.receiver, 0xFF) if not active and self.receiver and self.battery_info is not None and self.battery_info.level is not None: self.battery_info = Battery( self.battery_info.level, self.battery_info.next_level, BatteryStatus.OFFLINE, self.battery_info.voltage, self.battery_info.light_level, ) if logger.isEnabledFor(logging.DEBUG): logger.debug("device %d changed: active=%s %s", self.number, self._active, self.battery_info) if self.status_callback is not None: self.status_callback(self, alert, reason) def enable_connection_notifications(self, enable=True): """Enable or disable device (dis)connection notifications on this receiver.""" if not bool(self.receiver) or self.protocol >= 2.0: return False if enable: set_flag_bits = NotificationFlag.BATTERY_STATUS | NotificationFlag.UI | NotificationFlag.CONFIGURATION_COMPLETE else: set_flag_bits = 0 ok = _hidpp10.set_notification_flags(self, set_flag_bits) if not ok: logger.warning("%s: failed to %s device notifications", self, "enable" if enable else "disable") flag_bits = _hidpp10.get_notification_flags(self) if logger.isEnabledFor(logging.INFO): if flag_bits is None: flag_names = None else: flag_names = hidpp10_constants.NotificationFlag.flag_names(flag_bits) is_enabled = "enabled" if enable else "disabled" logger.info(f"{self}: device notifications {is_enabled} {flag_names}") return flag_bits if ok else None def add_notification_handler(self, id: str, fn): """Adds the notification handling callback `fn` to this device under name `id`. If a callback has already been registered under this name, it's replaced with the argument. The callback will be invoked whenever the device emits an event message, and the resulting notification hasn't been handled by another handler on this device (order is not guaranteed, so handlers should not overlap in functionality). The callback should have type `(PairedDevice, Notification) -> Optional[bool]`. It should return `None` if it hasn't handled the notification, return `True` if it did so successfully and return `False` if an error should be reported (malformed notification, etc). """ self._notification_handlers[id] = fn def remove_notification_handler(self, id: str): """Unregisters the notification handler under name `id`.""" if id not in self._notification_handlers and logger.isEnabledFor(logging.INFO): logger.info(f"Tried to remove nonexistent notification handler {id} from device {self}.") else: del self._notification_handlers[id] def handle_notification(self, n) -> Optional[bool]: for h in self._notification_handlers.values(): ret = h(self, n) if ret is not None: return ret return None def request(self, request_id, *params, no_reply=False): if self: long = self.hidpp_long is True or ( self.hidpp_long is None and (self.bluetooth or self._protocol is not None and self._protocol >= 2.0) ) # Centurion child: CPL framing strips devnumber and responses always # have devnumber=0xFF, so we must send 0xFF to match responses. devnumber = 0xFF if (self.centurion and self.receiver and not self.handle) else self.number return self.low_level.request( self.handle or (self.receiver.handle if self.receiver else None), devnumber, request_id, *params, no_reply=no_reply, long_message=long, protocol=self.protocol, ) if logger.isEnabledFor(logging.WARN): logger.warning( "%s: request failure for device %s %s %s", self, self.handle, self.receiver, self.receiver._devices if self.receiver else None, ) def feature_request(self, feature, function=0x00, *params, no_reply=False): if self.protocol >= 2.0: if self.centurion: # Ensure sub-device features are discovered before routing decision if self.features is not None: self.features._check() # Guard against Centurion/HID++ 2.0 feature ID collisions. IntEnum # members with the same int value hash equal, so a dict lookup for # SupportedFeature.DEVICE_NAME (0x0005) succeeds even when the # device actually has CenturionCoreFeature.MULTI_HOST_CONTROL at # that slot. If the type of the stored enum differs from what the # caller asked for, treat the feature as unsupported. if self.features is not None: idx = self.features.get(feature) if idx is not None: stored = self.features.inverse.get(idx) if stored is not None and type(stored) is not type(feature): return None if feature in getattr(self, "_centurion_sub_features", ()): sub_idx = self.features.get(feature) if sub_idx is not None: return self.centurion_bridge_request(sub_idx, function, *params, no_reply=no_reply) return hidpp20.feature_request(self, feature, function, *params, no_reply=no_reply) if logger.isEnabledFor(logging.WARN): logger.warning("%s: feature request failure for device with protocol %s", self, self.protocol) # Max sub-message bytes in the first bridge fragment (for 0x51): # 64 - 1 (report ID) - 1 (cpl_len) - 1 (flags) - 2 (bridge prefix) - 2 (bridge hdr) = 57; # one byte of conservative margin gives 56. For 0x50 the device_addr byte # eats one more, so first_chunk = 55 (handled dynamically below). _BRIDGE_FIRST_CHUNK = 56 # Continuation fragments carry raw sub_msg data (no bridge prefix/hdr): # 64 - 1 (report ID) - 1 (cpl_len) - 1 (flags) = 61; one byte of margin # gives 60. _BRIDGE_CONT_CHUNK = 60 def centurion_bridge_request(self, sub_feat_idx, sub_function=0x00, *params, no_reply=False): """Send a request to a Centurion sub-device via CentPPBridge. Builds the 4-layer nested message: Layer 1: [report_id] (0x51 or 0x50) Layer 2: [device_addr (0x50 only),] cpl_length, flags Layer 3: [bridge_idx, sendFragment_func|swid, bridge_hdr...] Layer 4: [sub_cpl=0x00, sub_feat_idx, sub_func|swid, params...] For multi-fragment sends, only the first fragment includes the bridge prefix and header. Continuation fragments carry raw sub_msg data. The CPL flags byte encodes fragment index and continuation: flags = (fragment_index << 1) | (1 if more_fragments else 0) Single-frame messages use flags=0x00. Returns the sub-device response data (after bridge header), or None. """ if not getattr(self, "centurion", False): raise ValueError("centurion_bridge_request called on non-Centurion device") bridge_idx = getattr(self, "_centurion_bridge_index", None) if bridge_idx is None: raise ValueError("CentPPBridge index not discovered yet") handle = self.handle or (self.receiver.handle if self.receiver else None) if not handle: return None # Adjust bridge chunk sizes for 0x50 variant (device_addr byte takes 1 frame byte) cent_state = base._centurion_handles.get(int(handle)) addr_overhead = 1 if cent_state and cent_state.report_id == base.CENTURION_ADDRESSED_REPORT_ID else 0 first_chunk = self._BRIDGE_FIRST_CHUNK - addr_overhead cont_chunk = self._BRIDGE_CONT_CHUNK - addr_overhead sw_id = base._get_next_sw_id() # Build sub-device message: [sub_cpl=0x00, sub_feat_idx, sub_func|swid, params...] # sub_function is in standard HID++ format: func_number << 4 (e.g. 0x10 for function 1) sub_params = b"".join(struct.pack("B", p) if isinstance(p, int) else p for p in params) if params else b"" sub_msg = struct.pack("BBB", 0x00, sub_feat_idx, (sub_function & 0xF0) | sw_id) + sub_params # Build bridge header: [device_id<<4 | len_hi, len_lo] # device_id=0 for the headset, len is the total sub-message length sub_len = len(sub_msg) bridge_hdr = struct.pack("BB", (0x00 << 4) | ((sub_len >> 8) & 0x0F), sub_len & 0xFF) bridge_prefix = struct.pack("BB", bridge_idx, (0x01 << 4) | sw_id) timeout = base.DEFAULT_TIMEOUT with base.acquire_timeout(base.handle_lock(handle), handle, timeout): if logger.isEnabledFor(logging.DEBUG): logger.debug( "bridge TX: sub_idx=%d func=0x%02X sw_id=%d payload=%s", sub_feat_idx, sub_function, sw_id, sub_params.hex() if sub_params else "", ) if sub_len <= first_chunk: # Single-frame path layer3 = bridge_prefix + bridge_hdr + sub_msg base.write_centurion_cpl(handle, layer3) else: # Multi-fragment send # Fragment 0: bridge_prefix + bridge_hdr + first chunk of sub_msg # Fragments 1+: raw sub_msg continuation data (no bridge overhead) # CPL flags = (frag_index << 1) | (1 if more_fragments else 0) # All fragments are sent back-to-back without waiting for # intermediate ACKs. The device reassembles internally and # sends a single ACK + MessageEvent after the last fragment. frag_index = 0 offset = 0 while offset < sub_len: if frag_index == 0: chunk_size = first_chunk chunk = sub_msg[offset : offset + chunk_size] layer3 = bridge_prefix + bridge_hdr + chunk else: chunk_size = cont_chunk chunk = sub_msg[offset : offset + chunk_size] layer3 = chunk has_more = (offset + chunk_size) < sub_len flags = (frag_index << 1) | (1 if has_more else 0) base.write_centurion_cpl(handle, layer3, flags=flags) offset += len(chunk) frag_index += 1 if no_reply: return None # The device echoes our exact sub-device function+swid byte in # MessageEvent responses. Match on that to reject cross-contamination # from late-arriving responses to other function calls on the same # feature (e.g. GetRGBZoneInfo response showing up on a later # GetHostModeState read). expected_sub_func_sw = (sub_function & 0xF0) | sw_id # Read ACK + MessageEvent response request_started = time.time() ack_received = False while time.time() - request_started < timeout: reply = base._read(handle, timeout) if not reply: continue _report_id, _devnumber, reply_data = reply # ACK: short response echoing feat_idx and func|swid if len(reply_data) >= 2 and reply_data[0] == bridge_idx: func_sw = reply_data[1] if (func_sw >> 4) == 0x01 and (func_sw & 0x0F) == sw_id: ack_received = True break if (func_sw >> 4) == 0x01 and (func_sw & 0x0F) == 0: # MessageEvent arrived before ACK — validate it's for our request if self._is_bridge_response_for(reply_data, sub_feat_idx, expected_sub_func_sw): if logger.isEnabledFor(logging.DEBUG): logger.debug("bridge idx=%d fn=0x%02X -> OK", sub_feat_idx, sub_function) return self._parse_bridge_response(reply_data) if logger.isEnabledFor(logging.DEBUG): logger.debug( "bridge skipping reply (pre-ACK): got sub_cpl=0x%02X sub_idx=0x%02X func_sw=0x%02X" " (expected idx=0x%02X func_sw=0x%02X) data=%s", reply_data[4] if len(reply_data) > 4 else 0, reply_data[5] if len(reply_data) > 5 else 0, reply_data[6] if len(reply_data) > 6 else 0, sub_feat_idx, expected_sub_func_sw, reply_data.hex(), ) if not ack_received: logger.warning("centurion_bridge_request: no ACK received") return None # Read MessageEvent response (bridge function 1 with SW ID 0 = event) while time.time() - request_started < timeout: reply = base._read(handle, timeout) if not reply: continue _report_id, _devnumber, reply_data = reply if len(reply_data) >= 2 and reply_data[0] == bridge_idx: func_sw = reply_data[1] if (func_sw >> 4) == 0x01 and (func_sw & 0x0F) == 0: if self._is_bridge_response_for(reply_data, sub_feat_idx, expected_sub_func_sw): if logger.isEnabledFor(logging.DEBUG): logger.debug("bridge idx=%d fn=0x%02X -> OK", sub_feat_idx, sub_function) return self._parse_bridge_response(reply_data) if logger.isEnabledFor(logging.DEBUG): logger.debug( "bridge skipping reply (post-ACK): got sub_cpl=0x%02X sub_idx=0x%02X func_sw=0x%02X" " (expected idx=0x%02X func_sw=0x%02X) data=%s", reply_data[4] if len(reply_data) > 4 else 0, reply_data[5] if len(reply_data) > 5 else 0, reply_data[6] if len(reply_data) > 6 else 0, sub_feat_idx, expected_sub_func_sw, reply_data.hex(), ) logger.warning("centurion_bridge_request: no MessageEvent received") return None @staticmethod def _wait_for_bridge_ack(handle, bridge_idx, sw_id, timeout): """Wait for a bridge ACK response between multi-fragment sends.""" started = time.time() while time.time() - started < timeout: reply = base._read(handle, timeout) if not reply: continue _report_id, _devnumber, reply_data = reply if len(reply_data) >= 2 and reply_data[0] == bridge_idx: func_sw = reply_data[1] if (func_sw >> 4) == 0x01 and (func_sw & 0x0F) == sw_id: return True return False @staticmethod def _is_bridge_response_for(reply_data, expected_sub_feat_idx, expected_sub_func_sw=None): """Check if a bridge MessageEvent is a response for our specific sub-feature request. Accepts both normal responses (sub_feat_idx matches) and error responses (sub_feat_idx=0xFF with original feat_idx in next byte). Unsolicited notifications (sub_cpl=0xFF) are rejected. If `expected_sub_func_sw` is provided, also matches on the echoed sub-device function byte (`(function << 4) | sw_id`). This prevents cross-talk between different function calls on the SAME feature, which can happen when a late-arriving response for one function gets picked up by a later request on the same feature (observed on G522 where a GetRGBZoneInfo response contaminated a subsequent GetHostModeState). """ if len(reply_data) < 6: return False sub_cpl = reply_data[4] sub_feat_idx = reply_data[5] # Notifications have sub_cpl=0xFF; our responses have sub_cpl=0x00 if sub_cpl != 0x00: return False if sub_feat_idx == expected_sub_feat_idx: if expected_sub_func_sw is not None and len(reply_data) >= 7: if reply_data[6] != expected_sub_func_sw: return False return True # Error response: sub_feat_idx=0xFF, next byte is the original feat_idx that errored if sub_feat_idx == 0xFF and len(reply_data) >= 7 and reply_data[6] == expected_sub_feat_idx: if expected_sub_func_sw is not None and len(reply_data) >= 8: if reply_data[7] != expected_sub_func_sw: return False return True return False @staticmethod def _parse_bridge_response(reply_data): """Extract sub-device response from a CentPPBridge MessageEvent. reply_data layout (after report_id and devnumber have been stripped): [bridge_idx, func_sw, dev_id<<4|len_hi, len_lo, sub_cpl, sub_feat_idx, sub_func_sw, data...] Returns the sub-device data starting from sub_feat_idx onward. Error responses have sub_feat_idx=0xFF: [... sub_cpl, 0xFF, orig_feat_idx, orig_func_sw, error_code] These return None. """ if len(reply_data) < 7: return None sub_feat_idx = reply_data[5] # Error response from sub-device if sub_feat_idx == 0xFF: # Error frame layout after sub_cpl: [0xFF, orig_feat_idx, orig_func_sw, error_code, ...] orig_feat_idx = reply_data[6] if len(reply_data) > 6 else 0 orig_func_sw = reply_data[7] if len(reply_data) > 7 else 0 error_code = reply_data[8] if len(reply_data) > 8 else 0 logger.debug( "bridge sub-device error: orig_feat_idx=%d orig_func=0x%02X error=0x%02X", orig_feat_idx, orig_func_sw, error_code, ) return None return reply_data[7:] # response data after sub_cpl, sub_feat_idx, sub_func_sw def _record_ping_protocol(self, handle, protocol): """Record a successful ping's protocol version, including raw Centurion (major, minor).""" self._protocol = protocol cent_state = base._centurion_handles.get(int(handle)) if cent_state and cent_state.protocol_version: self._centurion_protocol = cent_state.protocol_version def ping(self): """Checks if the device is online and present, returns True of False. Some devices are integral with their receiver but may not be present even if the receiver responds to ping.""" if self.centurion and self.receiver and not self.handle: # Centurion child: first check if dongle is reachable handle = self.receiver.handle try: protocol = self.low_level.ping(handle, 0xFF, long_message=True) except exceptions.NoReceiver: self.online = False return False if protocol: self._record_ping_protocol(handle, protocol) # Dongle responded — now check if headset is actually on by probing through bridge. # Send ROOT.GetFeature(0x0001) to the sub-device via CentPPBridge. bridge_idx = getattr(self, "_centurion_bridge_index", None) if bridge_idx is not None: try: result = self.centurion_bridge_request(0, 0x00, 0x00, 0x01) self.online = result is not None and self.present except Exception: self.online = False else: self.online = False return self.online long = self.hidpp_long is True or ( self.hidpp_long is None and (self.bluetooth or self._protocol is not None and self._protocol >= 2.0) ) handle = self.handle or self.receiver.handle try: protocol = self.low_level.ping(handle, self.number, long_message=long) except exceptions.NoReceiver: # if ping fails, device is offline protocol = None self.online = protocol is not None and self.present if protocol: self._record_ping_protocol(handle, protocol) if logger.isEnabledFor(logging.DEBUG): logger.debug("pinged %s: online %s protocol %s present %s", self.number, self.online, protocol, self.present) return self.online def notify_devices(self): # no need to notify, as there are none pass def close(self): # Run device.cleanups before clearing self.handle — cleanup callbacks # typically need to issue final feature_request() writes (e.g. release # SW control, restore device-side state) and feature_request() relies # on self.handle being set. if hasattr(self, "cleanups"): for cleanup in self.cleanups: cleanup(self) handle, self.handle = self.handle, None if self in Device.instances: Device.instances.remove(self) return handle and self.low_level.close(handle) def __index__(self): return self.number __int__ = __index__ def __eq__(self, other): return other is not None and self._kind == other._kind and self.wpid == other.wpid def __ne__(self, other): return other is None or self.kind != other.kind or self.wpid != other.wpid def __hash__(self): return self.wpid.__hash__() def __bool__(self): return self.wpid is not None and self.number in self.receiver if self.receiver else self.handle is not None __nonzero__ = __bool__ def status_string(self): return self.battery_info.to_str() if self.battery_info is not None else "" def __str__(self): try: name = self._name or self._codename or "?" except exceptions.NoSuchDevice: name = "name not available" return f"" __repr__ = __str__ def __del__(self): self.close() # Re-export from centurion.py — must be after Device class to avoid circular import from .centurion import CenturionReceiver # noqa: E402,F401 from .centurion import create_centurion_receiver # noqa: E402,F401 Solaar-1.1.20/lib/logitech_receiver/device_quirks.py000066400000000000000000000101551522022367600224620ustar00rootroot00000000000000"""Per-device-model quirks for RGB lighting. Keyed by ``device.modelId``. For normal HID++ devices that is the string Logitech composes by concatenating every transport PID (btid + btleid + wpid + usbid) — one entry covers the model on any transport. For Centurion headsets it is the firmware-stable model byte (G522 ``"32"``, G325 ``"44"``); see ``device._get_ids_centurion``. Two postures, by feature class: * **Effect parameters that do NOT persist** (zone effects, LED directions) — default-ALLOW. Those are validated and low-harm (a wrong value is cosmetic and transient). They use blocklists elsewhere, e.g. ``LedDirectionBlocklist`` in ``hidpp20.py``. Nothing of that kind lives here. * **NVconfig-saved colors** (0x8071 RGBEffects boot effects, 0x0622 HeadsetRGB signature effects) — default-DENY. Those writes persist to non-volatile storage, so an unvalidated control can durably misconfigure a device. Every field is hidden and every slot suppressed unless the exact model is listed here as known-good. Setting ``SOLAAR_EXPERIMENTAL`` truthy bypasses the allowlists entirely — for testers / reverse-engineering on devices not yet validated. Entries are hand-curated; document the observation in a comment. """ from __future__ import annotations import os _ALL_NVCONFIG_FIELDS = {"color1", "color2", "speed"} def _experimental() -> bool: """True when SOLAAR_EXPERIMENTAL is set truthy — bypasses allowlist masking.""" return os.environ.get("SOLAAR_EXPERIMENTAL", "").strip().lower() in ("1", "true", "yes", "on") # Feature 0x8071 RGBEffects, Function 3 NvConfig — persistent boot/shutdown # effects. Default-DENY allowlist: modelId -> cap_id -> set of color fields # the firmware is KNOWN to honor. A listed cap shows the setting (its On/Off # toggle plus the listed color pickers); an empty set shows the toggle only. # An unlisted cap or unlisted model suppresses the setting entirely. RGB_EFFECTS_NVCONFIG_ALLOWED: dict[str, dict[int, set[str]]] = { # G502 X PLUS — startup (0x0001): color bytes are inert, only the enabled # flag is honored, so no color fields are allowed (toggle only). Shutdown # (0x0040) is not supported and is suppressed by build()-time probe anyway. "4099C0950000": {0x0001: set()}, # G515 LIGHTSPEED TKL — startup and shutdown both honor both colors. "B38940B4C355": {0x0001: {"color1", "color2"}, 0x0040: {"color1", "color2"}}, } # Feature 0x0622 HeadsetRGB signature effects — persistent startup / shutdown # / passive effects. Default-DENY allowlist: modelId -> effect_id -> set of # fields the firmware is KNOWN to honor. An unlisted effect_id or model # suppresses that signature-effect setting entirely. HEADSET_SIGNATURE_EFFECTS_ALLOWED: dict[str, dict[int, set[str]]] = { # G522 LIGHTSPEED (Centurion model byte 0x32, from DeviceInfo func 0; # confirmed against multiple diagnostic logs). Verified against user # reports: startup honors only the primary color (secondary unused, speed # has no effect); shutdown honors both colors (speed has no effect). The # passive slot (effect_id 2) is omitted — its behavior is not understood, # so the whole passive setting is suppressed. "32": { 0: {"color1"}, 1: {"color1", "color2"}, }, } def rgb_effects_nvconfig_allowed_fields(device, cap_id: int) -> set[str] | None: """Color fields to expose for an 0x8071 NvConfig boot effect. Returns the allowed field set (possibly empty — On/Off toggle only), or ``None`` to suppress the setting entirely. """ if _experimental(): return set(_ALL_NVCONFIG_FIELDS) model_id = getattr(device, "modelId", None) or "" return RGB_EFFECTS_NVCONFIG_ALLOWED.get(model_id, {}).get(cap_id) def headset_signature_allowed_fields(device, effect_id: int) -> set[str] | None: """Fields to expose for an 0x0622 signature effect slot. Returns the allowed field set, or ``None`` to suppress the slot entirely. """ if _experimental(): return set(_ALL_NVCONFIG_FIELDS) model_id = getattr(device, "modelId", None) or "" return HEADSET_SIGNATURE_EFFECTS_ALLOWED.get(model_id, {}).get(effect_id) Solaar-1.1.20/lib/logitech_receiver/diversion.py000066400000000000000000001566361522022367600216460ustar00rootroot00000000000000## Copyright (C) 2020 Peter Patel-Schneider ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import ctypes import logging import math import numbers import os import platform import socket import struct import subprocess import sys import time import typing from typing import Any from typing import Dict from typing import Tuple import gi import psutil import yaml from keysyms import keysymdef # There is no evdev on macOS or Windows. Diversion will not work without # it but other Solaar functionality is available. if platform.system() in ("Darwin", "Windows"): evdev = None else: import evdev from .common import NamedInt from .hidpp20 import SupportedFeature from .special_keys import CONTROL gi.require_version("Gdk", "3.0") # isort:skip from gi.repository import Gdk, GLib # NOQA: E402 # isort:skip if typing.TYPE_CHECKING: from .base import HIDPPNotification logger = logging.getLogger(__name__) # # See docs/rules.md for documentation # # Several capabilities of rules depend on aspects of GDK, X11, or XKB # As the Solaar GUI uses GTK, Glib and GDK are always available and are obtained from gi.repository # # Process condition depends on X11 from python-xlib, and is probably not possible at all in Wayland # MouseProcess condition depends on X11 from python-xlib, and is probably not possible at all in Wayland # Modifiers condition depends only on GDK # KeyPress action determines whether a keysym is a currently-down modifier using get_modifier_mapping from python-xlib; # under Wayland no modifier keys are considered down so all modifier keys are pressed, potentially leading to problems # KeyPress action translates key names to keysysms using the local file described for GUI keyname determination # KeyPress action gets the current keyboard group using XkbGetState from libX11.so using ctypes definitions # under Wayland the keyboard group is None resulting in using the first keyboard group # KeyPress action translates keysyms to keycodes using the GDK keymap # KeyPress, MouseScroll, and MouseClick actions use uinput. # For uinput to work the user must have write access for /dev/uinput. # The Solaar udev rule should set this up # Otherwise run sudo setfacl -m u:${user}:rw /dev/uinput # # Rule GUI keyname determination uses a local file generated # from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h # and http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h # because there does not seem to be a non-X11 file for this set of key names # Setting up is complex because there are several systems that each provide partial facilities: # GDK - always available (when running with a window system) but only provides access to keymap # X11 - provides access to active process and process with window under mouse and current modifier keys # uinput and evdev - provides input simulation XK_KEYS: Dict[str, int] = keysymdef.key_symbols # Event codes - can't use Xlib.X codes because Xlib might not be available _KEY_RELEASE = 0 _KEY_PRESS = 1 _BUTTON_RELEASE = 2 _BUTTON_PRESS = 3 CLICK, DEPRESS, RELEASE = "click", "depress", "release" gdisplay = Gdk.Display.get_default() # can be None if Solaar is run without a full window system gkeymap = Gdk.Keymap.get_for_display(gdisplay) if gdisplay else None if logger.isEnabledFor(logging.INFO): logger.info("GDK Keymap %sset up", "" if gkeymap else "not ") wayland = os.getenv("WAYLAND_DISPLAY") # is this Wayland? if wayland: logger.warning( "rules cannot access modifier keys in Wayland, " "accessing process only works on GNOME with Solaar Gnome extension installed" ) try: _x11 = None # X11 might be available except Exception: _x11 = False # X11 is not available # Globals xdisplay = None Xkbdisplay = None # xkb might be available X11Lib = None modifier_keycodes = [] XkbUseCoreKbd = 0x100 NET_ACTIVE_WINDOW = None NET_WM_PID = None WM_CLASS = None udevice = None key_down = None key_up = None keys_down = [] g_keys_down = 0 m_keys_down = 0 mr_key_down = False thumb_wheel_displacement = 0 _dbus_interface = None class XkbDisplay(ctypes.Structure): """opaque struct""" class XkbStateRec(ctypes.Structure): _fields_ = [ ("group", ctypes.c_ubyte), ("locked_group", ctypes.c_ubyte), ("base_group", ctypes.c_ushort), ("latched_group", ctypes.c_ushort), ("mods", ctypes.c_ubyte), ("base_mods", ctypes.c_ubyte), ("latched_mods", ctypes.c_ubyte), ("locked_mods", ctypes.c_ubyte), ("compat_state", ctypes.c_ubyte), ("grab_mods", ctypes.c_ubyte), ("compat_grab_mods", ctypes.c_ubyte), ("lookup_mods", ctypes.c_ubyte), ("compat_lookup_mods", ctypes.c_ubyte), ("ptr_buttons", ctypes.c_ushort), ] # something strange is happening here but it is not being used def x11_setup(): global _x11, xdisplay, modifier_keycodes, NET_ACTIVE_WINDOW, NET_WM_PID, WM_CLASS if _x11 is not None: return _x11 try: from Xlib.display import Display xdisplay = Display() modifier_keycodes = xdisplay.get_modifier_mapping() # there should be a way to do this in Gdk NET_ACTIVE_WINDOW = xdisplay.intern_atom("_NET_ACTIVE_WINDOW") NET_WM_PID = xdisplay.intern_atom("_NET_WM_PID") WM_CLASS = xdisplay.intern_atom("WM_CLASS") _x11 = True # X11 available if logger.isEnabledFor(logging.INFO): logger.info("X11 library loaded and display set up") except Exception: logger.warning("X11 not available - some rule capabilities inoperable", exc_info=sys.exc_info()) _x11 = False return _x11 def gnome_dbus_interface_setup(): global _dbus_interface if _dbus_interface is not None: return _dbus_interface try: import dbus bus = dbus.SessionBus() remote_object = bus.get_object("org.gnome.Shell", "/io/github/pwr_solaar/solaar") _dbus_interface = dbus.Interface(remote_object, "io.github.pwr_solaar.solaar") except dbus.exceptions.DBusException: logger.warning( "Solaar Gnome extension not installed - some rule capabilities inoperable", exc_info=sys.exc_info(), ) _dbus_interface = False return _dbus_interface def xkb_setup(): global X11Lib, Xkbdisplay if Xkbdisplay is not None: return Xkbdisplay try: # set up to get keyboard state using ctypes interface to libx11 X11Lib = ctypes.cdll.LoadLibrary("libX11.so") X11Lib.XOpenDisplay.restype = ctypes.POINTER(XkbDisplay) X11Lib.XkbGetState.argtypes = [ctypes.POINTER(XkbDisplay), ctypes.c_uint, ctypes.POINTER(XkbStateRec)] Xkbdisplay = X11Lib.XOpenDisplay(None) if logger.isEnabledFor(logging.INFO): logger.info("XKB display set up") except Exception: logger.warning("XKB display not available - rules cannot access keyboard group", exc_info=sys.exc_info()) Xkbdisplay = False return Xkbdisplay if evdev: buttons = { "unknown": (None, None), "left": (1, evdev.ecodes.ecodes["BTN_LEFT"]), "middle": (2, evdev.ecodes.ecodes["BTN_MIDDLE"]), "right": (3, evdev.ecodes.ecodes["BTN_RIGHT"]), "scroll_up": (4, evdev.ecodes.ecodes["BTN_4"]), "scroll_down": (5, evdev.ecodes.ecodes["BTN_5"]), "scroll_left": (6, evdev.ecodes.ecodes["BTN_6"]), "scroll_right": (7, evdev.ecodes.ecodes["BTN_7"]), "button8": (8, evdev.ecodes.ecodes["BTN_8"]), "button9": (9, evdev.ecodes.ecodes["BTN_9"]), "back": (10, evdev.ecodes.ecodes["BTN_SIDE"]), "forward": (11, evdev.ecodes.ecodes["BTN_EXTRA"]), } # uinput capability for keyboard keys, mouse buttons, and scrolling key_events = [c for n, c in evdev.ecodes.ecodes.items() if n.startswith("KEY") and n != "KEY_CNT"] for _, evcode in buttons.values(): if evcode: key_events.append(evcode) devicecap = { evdev.ecodes.EV_KEY: key_events, evdev.ecodes.EV_REL: [evdev.ecodes.REL_WHEEL, evdev.ecodes.REL_HWHEEL], } else: # Just mock these since they won't be useful without evdev anyway buttons = {} key_events = [] devicecap = {} def setup_uinput(): global udevice if udevice is not None: return udevice try: udevice = evdev.uinput.UInput(events=devicecap, name="solaar-keyboard") if logger.isEnabledFor(logging.INFO): logger.info("uinput device set up") return True except Exception as e: logger.warning("cannot create uinput device: %s", e) def kbdgroup(): if xkb_setup(): state = XkbStateRec() X11Lib.XkbGetState(Xkbdisplay, XkbUseCoreKbd, ctypes.pointer(state)) return state.group else: return None def modifier_code(keycode): if wayland or not x11_setup() or keycode == 0: return None for m in range(0, len(modifier_keycodes)): if keycode in modifier_keycodes[m]: return m def signed(bytes_: bytes) -> int: return int.from_bytes(bytes_, "big", signed=True) def xy_direction(_x, _y): # normalize x and y m = math.sqrt((_x * _x) + (_y * _y)) if m == 0: return "noop" x = round(_x / m) y = round(_y / m) if x < 0 and y < 0: return "Mouse Up-left" elif x > 0 > y: return "Mouse Up-right" elif x < 0 < y: return "Mouse Down-left" elif x > 0 and y > 0: return "Mouse Down-right" elif x > 0: return "Mouse Right" elif x < 0: return "Mouse Left" elif y > 0: return "Mouse Down" elif y < 0: return "Mouse Up" else: return "noop" def simulate_uinput(what, code, arg): global udevice if setup_uinput(): try: udevice.write(what, code, arg) udevice.syn() if logger.isEnabledFor(logging.DEBUG): logger.debug("uinput simulated input %s %s %s", what, code, arg) return True except Exception as e: udevice = None logger.warning("uinput write failed: %s", e) def simulate_key(code, event): # X11 keycode but Solaar event code if evdev and simulate_uinput(evdev.ecodes.EV_KEY, code - 8, event): return True logger.warning("no way to simulate key input") def click_uinput(button, count): if isinstance(count, int): for _ in range(count): if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 1): return False if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 0): return False else: if count != RELEASE: if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 1): return False if count != DEPRESS: if not simulate_uinput(evdev.ecodes.EV_KEY, button[1], 0): return False return True def click(button, count): if click_uinput(button, count): return True logger.warning("no way to simulate mouse click") return False def simulate_scroll(dx, dy): if setup_uinput(): success = True if dx: success = simulate_uinput(evdev.ecodes.EV_REL, evdev.ecodes.REL_HWHEEL, dx) if dy and success: success = simulate_uinput(evdev.ecodes.EV_REL, evdev.ecodes.REL_WHEEL, dy) if success: return True logger.warning("no way to simulate scrolling") def thumb_wheel_up(f, r, d, a): global thumb_wheel_displacement if f != SupportedFeature.THUMB_WHEEL or r != 0: return False if a is None: return signed(d[0:2]) < 0 and signed(d[0:2]) elif thumb_wheel_displacement <= -a: thumb_wheel_displacement += a return 1 else: return False def thumb_wheel_down(f, r, d, a): global thumb_wheel_displacement if f != SupportedFeature.THUMB_WHEEL or r != 0: return False if a is None: return signed(d[0:2]) > 0 and signed(d[0:2]) elif thumb_wheel_displacement >= a: thumb_wheel_displacement -= a return 1 else: return False def charging(f, r, d, _a): if ( (f == SupportedFeature.BATTERY_STATUS and r == 0 and 1 <= d[2] <= 4) or (f == SupportedFeature.BATTERY_VOLTAGE and r == 0 and d[2] & (1 << 7)) or (f == SupportedFeature.UNIFIED_BATTERY and r == 0 and 1 <= d[2] <= 3) ): return 1 else: return False TESTS = { "crown_right": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[1] < 128 and d[1], False], "crown_left": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[1] >= 128 and 256 - d[1], False], "crown_right_ratchet": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[2] < 128 and d[2], False], "crown_left_ratchet": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[2] >= 128 and 256 - d[2], False], "crown_tap": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[5] == 0x01 and d[5], False], "crown_start_press": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[6] == 0x01 and d[6], False], "crown_end_press": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and d[6] == 0x05 and d[6], False], "crown_pressed": [lambda f, r, d, a: f == SupportedFeature.CROWN and r == 0 and 0x01 <= d[6] <= 0x04 and d[6], False], "thumb_wheel_up": [thumb_wheel_up, True], "thumb_wheel_down": [thumb_wheel_down, True], "lowres_wheel_up": [ lambda f, r, d, a: f == SupportedFeature.LOWRES_WHEEL and r == 0 and signed(d[0:1]) > 0 and signed(d[0:1]), False, ], "lowres_wheel_down": [ lambda f, r, d, a: f == SupportedFeature.LOWRES_WHEEL and r == 0 and signed(d[0:1]) < 0 and signed(d[0:1]), False, ], "hires_wheel_up": [ lambda f, r, d, a: f == SupportedFeature.HIRES_WHEEL and r == 0 and signed(d[1:3]) > 0 and signed(d[1:3]), False, ], "hires_wheel_down": [ lambda f, r, d, a: f == SupportedFeature.HIRES_WHEEL and r == 0 and signed(d[1:3]) < 0 and signed(d[1:3]), False, ], "charging": [charging, False], "False": [lambda f, r, d, a: False, False], "True": [lambda f, r, d, a: True, False], } MOUSE_GESTURE_TESTS = { "mouse-down": ["Mouse Down"], "mouse-up": ["Mouse Up"], "mouse-left": ["Mouse Left"], "mouse-right": ["Mouse Right"], "mouse-noop": [], } # COMPONENTS = {} class RuleComponent: def compile(self, c): if isinstance(c, RuleComponent): return c elif isinstance(c, dict) and len(c) == 1: k, v = next(iter(c.items())) if k in COMPONENTS: return COMPONENTS[k](v) logger.warning("illegal component in rule: %s", c) return Condition() def _evaluate(components, feature, notification: HIDPPNotification, device, result) -> Any: res = True for component in components: res = component.evaluate(feature, notification, device, result) if not isinstance(component, Action) and res is None: return None if isinstance(component, Condition) and not res: return res return res class Rule(RuleComponent): def __init__(self, args, source=None, warn=True): self.components = [self.compile(a) for a in args] self.source = source def __str__(self): source = f"({self.source})" if self.source else "" return f"Rule{source}[{', '.join([c.__str__() for c in self.components])}]" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate rule: %s", self) return _evaluate(self.components, feature, notification, device, True) def once(self, feature, notification: HIDPPNotification, device, last_result): self.evaluate(feature, notification, device, last_result) return False def data(self): return {"Rule": [c.data() for c in self.components]} class Condition(RuleComponent): def __init__(self, *args): pass def __str__(self): return "CONDITION" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return False class Not(Condition): def __init__(self, op, warn=True): if isinstance(op, list) and len(op) == 1: op = op[0] self.op = op self.component = self.compile(op) def __str__(self): return f"Not: {str(self.component)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) result = self.component.evaluate(feature, notification, device, last_result) return None if result is None else not result def data(self): return {"Not": self.component.data()} class Or(Condition): def __init__(self, args, warn=True): self.components = [self.compile(a) for a in args] def __str__(self): return "Or: [" + ", ".join(str(c) for c in self.components) + "]" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) result = False for component in self.components: result = component.evaluate(feature, notification, device, last_result) if not isinstance(component, Action) and result is None: return None if isinstance(component, Condition) and result: return result return result def data(self): return {"Or": [c.data() for c in self.components]} class And(Condition): def __init__(self, args, warn=True): self.components = [self.compile(a) for a in args] def __str__(self): return "And: [" + ", ".join(str(c) for c in self.components) + "]" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return _evaluate(self.components, feature, notification, device, last_result) def data(self): return {"And": [c.data() for c in self.components]} def x11_focus_prog(): if not x11_setup(): return None pid = wm_class = None window = xdisplay.get_input_focus().focus while window: pid = window.get_full_property(NET_WM_PID, 0) wm_class = window.get_wm_class() if wm_class and pid: break window = window.query_tree().parent try: name = psutil.Process(pid.value[0]).name() if pid else "" except Exception: name = "" return (wm_class[0], wm_class[1], name) if wm_class else (name,) def x11_pointer_prog(): if not x11_setup(): return None pid = wm_class = None window = xdisplay.screen().root.query_pointer().child for child in reversed(window.query_tree().children): pid = child.get_full_property(NET_WM_PID, 0) wm_class = child.get_wm_class() if wm_class: break name = psutil.Process(pid.value[0]).name() if pid else "" return (wm_class[0], wm_class[1], name) if wm_class else (name,) def gnome_dbus_focus_prog(): if not gnome_dbus_interface_setup(): return None wm_class = _dbus_interface.ActiveWindow() return (wm_class,) if wm_class else None def gnome_dbus_pointer_prog(): if not gnome_dbus_interface_setup(): return None wm_class = _dbus_interface.PointerOverWindow() return (wm_class,) if wm_class else None class Process(Condition): def __init__(self, process, warn=True): self.process = process if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()): if warn: logger.warning( "rules can only access active process in X11 or in Wayland under GNOME with Solaar Gnome " "extension - %s", self, ) if not isinstance(process, str): if warn: logger.warning("rule Process argument not a string: %s", process) self.process = str(process) def __str__(self): return f"Process: {str(self.process)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) if not isinstance(self.process, str): return False focus = x11_focus_prog() if not wayland else gnome_dbus_focus_prog() result = any(bool(s and s.startswith(self.process)) for s in focus) if focus else None return result def data(self): return {"Process": str(self.process)} class MouseProcess(Condition): def __init__(self, process, warn=True): self.process = process if (not wayland and not x11_setup()) or (wayland and not gnome_dbus_interface_setup()): if warn: logger.warning( "rules cannot access active mouse process " "in X11 or in Wayland under GNOME with Solaar Extension for GNOME - %s", self, ) if not isinstance(process, str): if warn: logger.warning("rule MouseProcess argument not a string: %s", process) self.process = str(process) def __str__(self): return f"MouseProcess: {str(self.process)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) if not isinstance(self.process, str): return False pointer_focus = x11_pointer_prog() if not wayland else gnome_dbus_pointer_prog() result = any(bool(s and s.startswith(self.process)) for s in pointer_focus) if pointer_focus else None return result def data(self): return {"MouseProcess": str(self.process)} class Feature(Condition): def __init__(self, feature: str, warn: bool = True): try: self.feature = SupportedFeature[feature.replace(" ", "_")] except KeyError: self.feature = None if warn: logger.warning("rule Feature argument not name of a feature: %s", feature) def __str__(self): return f"Feature: {str(self.feature)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return feature == self.feature def data(self): return {"Feature": str(self.feature)} class Report(Condition): def __init__(self, report, warn=True): if not (isinstance(report, int)): if warn: logger.warning("rule Report argument not an integer: %s", report) self.report = -1 else: self.report = report def __str__(self): return f"Report: {str(self.report)}" def evaluate(self, report, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return (notification.address >> 4) == self.report def data(self): return {"Report": self.report} # Setting(device, setting, [key], value...) class Setting(Condition): def __init__(self, args, warn=True): if not (isinstance(args, list) and len(args) > 2): if warn: logger.warning("rule Setting argument not list with minimum length 3: %s", args) self.args = [] else: self.args = args def __str__(self): return "Setting: " + " ".join([str(a) for a in self.args]) def evaluate(self, report, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) if len(self.args) < 3: return None dev = device.find(self.args[0]) if self.args[0] is not None else device if dev is None: logger.warning("Setting condition: device %s is not known", self.args[0]) return False setting = next((s for s in dev.settings if s.name == self.args[1]), None) if setting is None: logger.warning("Setting condition: setting %s is not the name of a setting for %s", self.args[1], dev.name) return None # should the value argument be checked to be sure it is acceptable?? needs to be careful about boolean toggle # TODO add compare methods for more validators try: result = setting.compare(self.args[2:], setting.read()) except Exception as e: logger.warning("Setting condition: error when checking setting %s: %s", self.args, e) result = False return result def data(self): return {"Setting": self.args[:]} MODIFIERS = { "Shift": int(Gdk.ModifierType.SHIFT_MASK), "Control": int(Gdk.ModifierType.CONTROL_MASK), "Alt": int(Gdk.ModifierType.MOD1_MASK), "Super": int(Gdk.ModifierType.MOD4_MASK), } MODIFIER_MASK = MODIFIERS["Shift"] + MODIFIERS["Control"] + MODIFIERS["Alt"] + MODIFIERS["Super"] class Modifiers(Condition): def __init__(self, modifiers, warn=True): modifiers = [modifiers] if isinstance(modifiers, str) else modifiers self.desired = 0 self.modifiers = [] for k in modifiers: if k in MODIFIERS: self.desired += MODIFIERS.get(k, 0) self.modifiers.append(k) else: if warn: logger.warning("unknown rule Modifier value: %s", k) def __str__(self): return f"Modifiers: {str(self.desired)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) if gkeymap: current = gkeymap.get_modifier_state() # get the current keyboard modifier return self.desired == (current & MODIFIER_MASK) else: logger.warning("no keymap so cannot determine modifier keys") return False def data(self): return {"Modifiers": [str(m) for m in self.modifiers]} class Key(Condition): DOWN = "pressed" UP = "released" def __init__(self, args, warn=True): default_key = 0 default_action = self.DOWN key, action = None, None if not args or not isinstance(args, (list, str)): if warn: logger.warning(f"rule Key arguments unknown: {args}") key = default_key action = default_action elif isinstance(args, str): logger.debug(f'rule Key assuming action "{default_action}" for "{args}"') key = args action = default_action elif isinstance(args, list): if len(args) == 1: logger.debug(f'rule Key assuming action "{default_action}" for "{args}"') key, action = args[0], default_action elif len(args) >= 2: key, action = args[:2] if isinstance(key, str) and key in CONTROL: self.key = CONTROL[key] elif isinstance(key, str) and key.startswith("unknown:"): logger.info(f"rule Key key name currently unknown: {key}") self.key = CONTROL[int(key[-4:], 16)] else: if warn: logger.warning(f"rule Key key name not name of a Logitech key: {key}") self.key = default_key if isinstance(action, str) and action in (self.DOWN, self.UP): self.action = action else: if warn: logger.warning(f"rule Key action unknown: {action}, assuming {default_action}") self.action = default_action def __str__(self): return f"Key: {str(self.key) if self.key else 'None'} ({self.action})" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return bool(self.key and self.key == (key_down if self.action == self.DOWN else key_up)) def data(self): return {"Key": [str(self.key), self.action]} class KeyIsDown(Condition): def __init__(self, args, warn=True): default_key = 0 key = None if not args or not isinstance(args, str): if warn: logger.warning(f"rule KeyDown arguments unknown: {args}") key = default_key elif isinstance(args, str): key = args if isinstance(key, str) and key in CONTROL: self.key = CONTROL[key] else: if warn: logger.warning(f"rule Key key name not name of a Logitech key: {key}") self.key = default_key def __str__(self): return f"KeyIsDown: {str(self.key) if self.key else 'None'}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return key_is_down(self.key) def data(self): return {"KeyIsDown": str(self.key)} def bit_test(start, end, bits): return lambda f, r, d: int.from_bytes(d[start:end], byteorder="big", signed=True) & bits def range_test(start, end, min, max): def range_test_helper(_f, _r, d): value = int.from_bytes(d[start:end], byteorder="big", signed=True) return min <= value <= max and (value if value else True) return range_test_helper class Test(Condition): def __init__(self, test, warn=True): self.test = "" self.parameter = None if isinstance(test, str): test = [test] if isinstance(test, list) and all(isinstance(t, int) for t in test): if warn: logger.warning("Test rules consisting of numbers are deprecated, converting to a TestBytes condition") self.__class__ = TestBytes self.__init__(test, warn=warn) elif isinstance(test, list): if test[0] in MOUSE_GESTURE_TESTS: if warn: logger.warning("mouse movement test %s deprecated, converting to a MouseGesture", test) self.__class__ = MouseGesture self.__init__(MOUSE_GESTURE_TESTS[0][test], warn=warn) elif test[0] in TESTS: self.test = test[0] self.function = TESTS[test[0]][0] self.parameter = test[1] if len(test) > 1 else None else: if warn: logger.warning("rule Test name not name of a test: %s", test) self.test = "False" self.function = TESTS["False"][0] else: if warn: logger.warning("rule Test argument not valid %s", test) def __str__(self): return f"Test: {str(self.test)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return self.function(feature, notification.address, notification.data, self.parameter) def data(self): return {"Test": ([self.test, self.parameter] if self.parameter is not None else [self.test])} class TestBytes(Condition): def __init__(self, test, warn=True): self.test = test if ( isinstance(test, list) and 2 < len(test) <= 4 and all(isinstance(t, int) for t in test) and 0 <= test[0] <= 16 and 0 <= test[1] <= 16 and test[0] < test[1] ): self.function = bit_test(*test) if len(test) == 3 else range_test(*test) else: if warn: logger.warning("rule TestBytes argument not valid %s", test) def __str__(self): return f"TestBytes: {str(self.test)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return self.function(feature, notification.address, notification.data) def data(self): return {"TestBytes": self.test[:]} class MouseGesture(Condition): MOVEMENTS = [ "Mouse Up", "Mouse Down", "Mouse Left", "Mouse Right", "Mouse Up-left", "Mouse Up-right", "Mouse Down-left", "Mouse Down-right", ] def __init__(self, movements, warn=True): if isinstance(movements, str): movements = [movements] for x in movements: if x not in self.MOVEMENTS and x not in CONTROL: if warn: logger.warning("rule Mouse Gesture argument not direction or name of a Logitech key: %s", x) self.movements = movements def __str__(self): return "MouseGesture: " + " ".join(self.movements) def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) if feature == SupportedFeature.MOUSE_GESTURE: d = notification.data data = struct.unpack("!" + (int(len(d) / 2) * "h"), d) data_offset = 1 movement_offset = 0 if self.movements and self.movements[0] not in self.MOVEMENTS: # matching against initiating key movement_offset = 1 if self.movements[0] != str(CONTROL[data[0]]): return False for m in self.movements[movement_offset:]: if data_offset >= len(data): return False if data[data_offset] == 0: direction = xy_direction(data[data_offset + 1], data[data_offset + 2]) if m != direction: return False data_offset += 3 elif data[data_offset] == 1: if m != str(CONTROL[data[data_offset + 1]]): return False data_offset += 2 return data_offset == len(data) return False def data(self): return {"MouseGesture": [str(m) for m in self.movements]} class Active(Condition): def __init__(self, devID, warn=True): if not (isinstance(devID, str)): if warn: logger.warning("rule Active argument not a string: %s", devID) self.devID = "" self.devID = devID def __str__(self): return f"Active: {str(self.devID)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) dev = device.find(self.devID) return bool(dev and dev.ping()) def data(self): return {"Active": self.devID} class Device(Condition): def __init__(self, devID, warn=True): if not (isinstance(devID, str)): if warn: logger.warning("rule Device argument not a string: %s", devID) self.devID = "" self.devID = devID def __str__(self): return f"Device: {str(self.devID)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) return ( device.unitId == self.devID or device.serial == self.devID or device.codename == self.devID or device.name == self.devID ) def data(self): return {"Device": self.devID} class Host(Condition): def __init__(self, host, warn=True): if not (isinstance(host, str)): if warn: logger.warning("rule Host Name argument not a string: %s", host) self.host = "" self.host = host def __str__(self): return f"Host: {str(self.host)}" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluate condition: %s", self) hostname = socket.getfqdn() return hostname.startswith(self.host) def data(self): return {"Host": self.host} class Action(RuleComponent): def __init__(self, *args): pass def evaluate(self, feature, notification: HIDPPNotification, device, last_result): return None def keysym_to_keycode(keysym, _modifiers) -> Tuple[int, int]: # maybe should take shift into account """Reverse the keycode to keysym mapping. Warning: This is an attempt to reverse the keycode to keysym mappping in XKB. It may not be completely general. """ group = kbdgroup() or 0 keycodes = gkeymap.get_entries_for_keyval(keysym) (keycode, level) = (None, None) for k in keycodes.keys: # mappings that have the correct group if group == k.group and k.keycode < 256 and (level is None or k.level < level): keycode = k.keycode level = k.level if keycode or group == 0: return keycode, level for k in keycodes.keys: # mappings for group 0 where keycode only has group 0 mappings if 0 == k.group and k.keycode < 256 and (level is None or k.level < level): (a, m, vs) = gkeymap.get_entries_for_keycode(k.keycode) if a and all(mk.group == 0 for mk in m): keycode = k.keycode level = k.level return keycode, level class KeyPress(Action): def __init__(self, args, warn=True): self.key_names, self.action = self.regularize_args(args) if not isinstance(self.key_names, list): if warn: logger.warning("rule KeyPress keys not key names %s", self.keys_names) self.key_symbols = [] else: self.key_symbols = [XK_KEYS.get(k, None) for k in self.key_names] if not all(self.key_symbols): if warn: logger.warning("rule KeyPress keys not key names %s", self.key_names) self.key_symbols = [] def regularize_args(self, args): action = CLICK if not isinstance(args, list): args = [args] keys = args if len(args) == 2 and args[1] in [CLICK, DEPRESS, RELEASE]: keys = [args[0]] if isinstance(args[0], str) else args[0] action = args[1] return keys, action def __str__(self): return "KeyPress: " + " ".join(self.key_names) + " " + self.action def needed(self, k, modifiers): code = modifier_code(k) return not (code is not None and modifiers & (1 << code)) def mods(self, level, modifiers, direction): if level == 2 or level == 3: (sk, _) = keysym_to_keycode(XK_KEYS.get("ISO_Level3_Shift", None), modifiers) if sk and self.needed(sk, modifiers): simulate_key(sk, direction) if level == 1 or level == 3: (sk, _) = keysym_to_keycode(XK_KEYS.get("Shift_L", None), modifiers) if sk and self.needed(sk, modifiers): simulate_key(sk, direction) def keyDown(self, keysyms_, modifiers): for k in keysyms_: (keycode, level) = keysym_to_keycode(k, modifiers) if keycode is None: logger.warning("rule KeyPress key symbol not currently available %s", self) elif self.action != CLICK or self.needed(keycode, modifiers): # only check needed when clicking self.mods(level, modifiers, _KEY_PRESS) simulate_key(keycode, _KEY_PRESS) def keyUp(self, keysyms_, modifiers): for k in keysyms_: (keycode, level) = keysym_to_keycode(k, modifiers) if keycode and (self.action != CLICK or self.needed(keycode, modifiers)): # only check needed when clicking simulate_key(keycode, _KEY_RELEASE) self.mods(level, modifiers, _KEY_RELEASE) def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if gkeymap: current = gkeymap.get_modifier_state() if logger.isEnabledFor(logging.INFO): logger.info( "KeyPress action: %s %s, group %s, modifiers %s", self.key_names, self.action, kbdgroup(), current, ) if self.action != RELEASE: self.keyDown(self.key_symbols, current) if self.action != DEPRESS: self.keyUp(reversed(self.key_symbols), current) time.sleep(0.01) else: logger.warning("no keymap so cannot determine which keycode to send") return None def data(self): return {"KeyPress": [[str(k) for k in self.key_names], self.action]} # KeyDown is dangerous as the key can auto-repeat and make your system unusable # class KeyDown(KeyPress): # def evaluate(self, feature, notification: HIDPPNotification, device, last_result): # super().keyDown(self.keys, current_key_modifiers) # class KeyUp(KeyPress): # def evaluate(self, feature, notification: HIDPPNotification, device, last_result): # super().keyUp(self.keys, current_key_modifiers) class MouseScroll(Action): def __init__(self, amounts, warn=True): if len(amounts) == 1 and isinstance(amounts[0], list): amounts = amounts[0] if not (len(amounts) == 2 and all([isinstance(a, numbers.Number) for a in amounts])): if warn: logger.warning("rule MouseScroll argument not two numbers %s", amounts) amounts = [0, 0] self.amounts = amounts def __str__(self): return "MouseScroll: " + " ".join([str(a) for a in self.amounts]) def evaluate(self, feature, notification: HIDPPNotification, device, last_result): amounts = self.amounts if isinstance(last_result, numbers.Number): amounts = [math.floor(last_result * a) for a in self.amounts] if logger.isEnabledFor(logging.INFO): logger.info("MouseScroll action: %s %s %s", self.amounts, last_result, amounts) dx, dy = amounts simulate_scroll(dx, dy) time.sleep(0.01) return None def data(self): return {"MouseScroll": self.amounts[:]} class MouseClick(Action): def __init__(self, args, warn=True): if len(args) == 1 and isinstance(args[0], list): args = args[0] if not isinstance(args, list): args = [args] self.button = str(args[0]) if len(args) >= 0 else None if self.button not in buttons: if warn: logger.warning("rule MouseClick action: button %s not known", self.button) self.button = None count = args[1] if len(args) >= 2 else 1 try: self.count = int(count) except (ValueError, TypeError): if count in [CLICK, DEPRESS, RELEASE]: self.count = count elif warn: logger.warning( "rule MouseClick action: argument %s should be an integer or click, depress, or release", count, ) self.count = 1 def __str__(self): return f"MouseClick: {self.button} ({str(self.count)})" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.INFO): logger.info(f"MouseClick action: {str(self.count)} {self.button}") if self.button and self.count: click(buttons[self.button], self.count) time.sleep(0.01) return None def data(self): return {"MouseClick": [self.button, self.count]} class Set(Action): def __init__(self, args, warn=True): if not (isinstance(args, list) and len(args) > 2): if warn: logger.warning("rule Set argument not list with minimum length 3: %s", args) self.args = [] else: self.args = args def __str__(self): return "Set: " + " ".join([str(a) for a in self.args]) def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if len(self.args) < 3: return None if logger.isEnabledFor(logging.INFO): logger.info("Set action: %s", self.args) dev = device.find(self.args[0]) if self.args[0] is not None else device if dev is None: logger.warning("Set action: device %s is not known", self.args[0]) return None setting = next((s for s in dev.settings if s.name == self.args[1]), None) if setting is None: logger.warning("Set action: setting %s is not the name of a setting for %s", self.args[1], dev.name) return None args = setting.acceptable(self.args[2:], setting.read()) if args is None: logger.warning( "Set Action: invalid args %s for setting %s of %s", self.args[2:], self.args[1], self.args[0], ) return None if len(args) > 1: setting.write_key_value(args[0], args[1]) else: setting.write(args[0]) if device.setting_callback: device.setting_callback(device, type(setting), args) return None def data(self): return {"Set": self.args[:]} class Execute(Action): def __init__(self, args, warn=True): if isinstance(args, str): args = [args] if not (isinstance(args, list) and all(isinstance(arg), str) for arg in args): if warn: logger.warning("rule Execute argument not list of strings: %s", args) self.args = [] else: self.args = args def __str__(self): return "Execute: " + " ".join([a for a in self.args]) def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if logger.isEnabledFor(logging.INFO): logger.info("Execute action: %s", self.args) subprocess.Popen(self.args) return None def data(self): return {"Execute": self.args[:]} class Later(Action): def __init__(self, args, warn=True): self.delay = 0 self.rule = Rule([]) self.components = [] if not (isinstance(args, list)): args = [args] if not (isinstance(args, list) and len(args) >= 1): if warn: logger.warning("rule Later argument not list with minimum length 1: %s", args) elif not (isinstance(args[0], (int, float))) or not 0.01 <= args[0] <= 100: if warn: logger.warning("rule Later delay not between 0.01 and 100: %s", args) else: self.delay = args[0] self.rule = Rule(args[1:], warn=warn) self.components = self.rule.components def __str__(self): return f"Later: [{str(self.delay)}, " + ", ".join(str(c) for c in self.components) + "]" def evaluate(self, feature, notification: HIDPPNotification, device, last_result): if self.delay and self.rule: if self.delay >= 1: GLib.timeout_add_seconds(int(self.delay), Rule.once, self.rule, feature, notification, device, last_result) else: GLib.timeout_add(int(self.delay * 1000), Rule.once, self.rule, feature, notification, device, last_result) return None def data(self): data = [c.data() for c in self.components] data.insert(0, self.delay) return {"Later": data} COMPONENTS = { "Rule": Rule, "Not": Not, "Or": Or, "And": And, "Process": Process, "MouseProcess": MouseProcess, "Feature": Feature, "Report": Report, "Setting": Setting, "Modifiers": Modifiers, "Key": Key, "KeyIsDown": KeyIsDown, "Test": Test, "TestBytes": TestBytes, "MouseGesture": MouseGesture, "Active": Active, "Device": Device, "Host": Host, "KeyPress": KeyPress, "MouseScroll": MouseScroll, "MouseClick": MouseClick, "Set": Set, "Execute": Execute, "Later": Later, } built_in_rules = Rule( [ { "Rule": [ # Implement problematic keys for Craft and MX Master {"Rule": [{"Key": ["Brightness Down", "pressed"]}, {"KeyPress": "XF86_MonBrightnessDown"}]}, {"Rule": [{"Key": ["Brightness Up", "pressed"]}, {"KeyPress": "XF86_MonBrightnessUp"}]}, ] }, ] ) def key_is_down(key: NamedInt) -> bool: """Checks if given key is pressed or not.""" if key == CONTROL.MR: return mr_key_down elif CONTROL.M1 <= key <= CONTROL.M8: return bool(m_keys_down & (0x01 << (key - CONTROL.M1))) elif CONTROL.G1 <= key <= CONTROL.G32: return bool(g_keys_down & (0x01 << (key - CONTROL.G1))) return key in keys_down def evaluate_rules(feature, notification: HIDPPNotification, device): if logger.isEnabledFor(logging.DEBUG): logger.debug("evaluating rules on %s %s", feature, notification) rules.evaluate(feature, notification, device, True) def process_notification(device, notification: HIDPPNotification, feature) -> None: """Processes HID++ notifications.""" global keys_down, g_keys_down, m_keys_down, mr_key_down, key_down, key_up, thumb_wheel_displacement key_down, key_up = None, None # need to keep track of keys that are down to find a new key down if notification.address == 0x00: if feature == SupportedFeature.REPROG_CONTROLS_V4: new_keys_down = struct.unpack("!4H", notification.data[:8]) for key in new_keys_down: if key and key not in keys_down: key_down = key for key in keys_down: if key and key not in new_keys_down: key_up = key keys_down = new_keys_down # and also G keys down elif feature == SupportedFeature.GKEY: new_g_keys_down = struct.unpack(" Rule: loaded_rules = [] try: with open(file_path) as config_file: loaded_rules = [] for loaded_rule in yaml.safe_load_all(config_file): rule = Rule(loaded_rule, source=file_path) if logger.isEnabledFor(logging.DEBUG): logger.debug("load rule: %s", rule) loaded_rules.append(rule) if logger.isEnabledFor(logging.INFO): logger.info("loaded %d rules from %s", len(loaded_rules), config_file.name) except Exception as e: logger.error("failed to load from %s\n%s", file_path, e) return Rule([Rule(loaded_rules, source=file_path), built_in_rules]) load_config_rule_file() Solaar-1.1.20/lib/logitech_receiver/exceptions.py000066400000000000000000000032761522022367600220140ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from .common import KwException """Exceptions that may be raised by this API.""" class NoReceiver(KwException): """Raised when trying to talk through a previously open handle, when the receiver is no longer available. Should only happen if the receiver is physically disconnected from the machine, or its kernel driver module is unloaded.""" pass class NoSuchDevice(KwException): """Raised when trying to reach a device number not paired to the receiver.""" pass class DeviceUnreachable(KwException): """Raised when a request is made to an unreachable (turned off) device.""" pass class FeatureNotSupported(KwException): """Raised when trying to request a feature not supported by the device.""" pass class FeatureCallError(KwException): """Raised if the device replied to a feature call with an error.""" pass Solaar-1.1.20/lib/logitech_receiver/headset_rgb.py000066400000000000000000000175001522022367600220750ustar00rootroot00000000000000## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Shared helpers for devices exposing Feature 0x0620 HEADSET_RGB_HOSTMODE. The G522 is currently the only Solaar-supported device advertising this feature, but anything else presenting 0x0620 will pick the same code path automatically. The module deliberately avoids G522-specific assumptions so future RGB-capable headsets can reuse it. Two entry points the settings templates rely on: - `discover_zones(device)` — one-shot zone enumeration run at setting build time. Briefly claims Solaar host control so GetRGBZoneInfo returns a non-empty zone list, then restores the previous host-mode state. Result is cached on the device. - `write_zone_map(device, zone_color_map)` — the shared write path used by both the "LEDs Primary" and "Per-zone Lighting" settings. Groups zones by final RGB color and emits one SetRgbZonesSingleValue per unique color, then a single FrameEnd to commit. """ from __future__ import annotations import logging from typing import Iterable from .hidpp20_constants import SupportedFeature logger = logging.getLogger(__name__) # Function IDs on Feature 0x0620 we actually use. FN_GET_RGB_ZONE_INFO = 0x10 FN_SET_RGB_ZONES_SINGLE = 0x50 FN_FRAME_END = 0x60 FN_GET_HOST_MODE_STATE = 0x70 FN_SET_HOST_MODE_STATE = 0x80 # Frame type sent with FrameEnd. 0x01 = transient commit (re-applies on the # next refresh). 0x02 would be persistent, but G522 firmware rejects it # with LOGITECH_INTERNAL (0x05) unless an onboard profile precondition we # haven't mapped yet is satisfied. FRAME_TYPE_TRANSIENT = 0x01 _HOST_MODE_SOLAAR = 1 _HOST_MODE_DEVICE = 0 def _device_cache_attr() -> str: return "_headset_rgb_zone_ids" def _read_host_mode(device) -> int | None: """Read the current host-mode state byte, or None on any failure.""" try: resp = device.feature_request(SupportedFeature.HEADSET_RGB_HOSTMODE, FN_GET_HOST_MODE_STATE) except Exception as e: logger.debug("headset_rgb: GetHostModeState raised %s", e) return None if not resp or len(resp) < 1: return None return resp[0] def _set_host_mode(device, value: int) -> bool: try: device.feature_request(SupportedFeature.HEADSET_RGB_HOSTMODE, FN_SET_HOST_MODE_STATE, bytes([value & 0xFF])) except Exception as e: logger.debug("headset_rgb: SetHostModeState(%d) raised %s", value, e) return False return True def _parse_zone_info(resp: bytes) -> list[int]: """Parse a GetRGBZoneInfo response into a zone-id list. Two formats observed: "tight" ([count, zone_ids...]) on G522, and the canonical protocol-doc layout (3-byte gap + 1-byte reserved before zone IDs). Both are tried; whichever yields exactly `count` IDs wins. Zone id 0 isn't filtered — some devices may use it. """ if not resp or len(resp) < 1: return [] zone_count = resp[0] tight = list(resp[1 : 1 + zone_count]) if 1 <= zone_count <= len(resp) - 1 else [] if tight and len(tight) == zone_count: return tight gap = list(resp[5 : 5 + zone_count]) if len(resp) >= 5 + zone_count else [] if gap and len(gap) == zone_count: return gap return [] def discover_zones(device) -> list[int] | None: """Return the list of RGB zone IDs on `device`, or None on failure. Caches the result on `device._headset_rgb_zone_ids` so subsequent callers don't repeat the round-trip. Briefly claims Solaar host mode if needed — GetRGBZoneInfo has been observed to return count=0 when the device is still under firmware control — and restores the prior state afterward so user-configured onboard effects resume. """ cached = getattr(device, _device_cache_attr(), None) if cached: return cached if not getattr(device, "online", False): return None prior_mode = _read_host_mode(device) claimed = False if prior_mode != _HOST_MODE_SOLAAR: if not _set_host_mode(device, _HOST_MODE_SOLAAR): return None claimed = True try: try: resp = device.feature_request(SupportedFeature.HEADSET_RGB_HOSTMODE, FN_GET_RGB_ZONE_INFO) except Exception as e: logger.debug("headset_rgb: GetRGBZoneInfo raised %s", e) return None zones = _parse_zone_info(bytes(resp) if resp else b"") if not zones: logger.debug( "headset_rgb: GetRGBZoneInfo returned no zones (raw=%s)", resp.hex() if resp else resp, ) return None logger.debug("headset_rgb: discovered %d zone(s) %s", len(zones), [f"0x{z:02X}" for z in zones]) setattr(device, _device_cache_attr(), zones) return zones finally: if claimed and prior_mode is not None: _set_host_mode(device, prior_mode) def _split_rgb(color_int: int) -> tuple[int, int, int]: return (color_int >> 16) & 0xFF, (color_int >> 8) & 0xFF, color_int & 0xFF def write_zone_map(device, zone_color_map: dict) -> bool: """Apply a zone->RGB mapping to the device. `zone_color_map` maps zone id (int) to 24-bit RGB color (int, `(r<<16)|(g<<8)|b`). Claims host mode, groups zones by color, emits one SetRgbZonesSingleValue per unique color, then a single FrameEnd. Returns True on success, False on any transport error. """ if not zone_color_map: return False if not getattr(device, "online", False): logger.debug("headset_rgb: device offline, skipping write") return False # Group zones by color for batched writes. groups: dict[int, list[int]] = {} for zone, color in zone_color_map.items(): groups.setdefault(int(color), []).append(int(zone)) try: _set_host_mode(device, _HOST_MODE_SOLAAR) for color_int, zones in groups.items(): r, g, b = _split_rgb(color_int) # SetRgbZonesSingleValue: [R, G, B, count, zone_ids...] payload = bytes([r, g, b, len(zones)]) + bytes(zones) device.feature_request(SupportedFeature.HEADSET_RGB_HOSTMODE, FN_SET_RGB_ZONES_SINGLE, payload) logger.debug( "headset_rgb: set (%02X,%02X,%02X) on %d zone(s) %s", r, g, b, len(zones), [f"0x{z:02X}" for z in zones], ) # FrameEnd commits the pending per-zone updates. Transient commit # only — persistent (0x02) requires onboard-profile preconditions # that aren't mapped yet. device.feature_request( SupportedFeature.HEADSET_RGB_HOSTMODE, FN_FRAME_END, bytes([FRAME_TYPE_TRANSIENT, 0x00, 0x00, 0x00]), ) except Exception as e: logger.warning("headset_rgb: write_zone_map failed: %s", e) return False return True def zone_named_ints(zones: Iterable[int]): """Build a list of NamedInt keys suitable for a ChoicesMap setting. Factored out so settings code can import without pulling common.NamedInt at module-load time if preferred. """ from . import common return [common.NamedInt(int(z), f"Zone {int(z)}") for z in zones] Solaar-1.1.20/lib/logitech_receiver/hidpp10.py000066400000000000000000000246061522022367600211000ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import logging from typing import Any from typing_extensions import Protocol from . import common from .common import Battery from .common import BatteryLevelApproximation from .common import BatteryStatus from .common import FirmwareKind from .hidpp10_constants import NotificationFlag from .hidpp10_constants import Registers logger = logging.getLogger(__name__) class Device(Protocol): def request(self, request_id, *params): ... @property def kind(self) -> Any: ... @property def online(self) -> bool: ... @property def protocol(self) -> Any: ... @property def registers(self) -> list: ... def read_register(device: Device, register: Registers | int, *params) -> Any: assert device is not None, f"tried to read register {register:02X} from invalid device {device}" # support long registers by adding a 2 in front of the register number request_id = 0x8100 | (int(register) & 0x2FF) return device.request(request_id, *params) def write_register(device: Device, register: Registers | int, *value) -> Any: assert device is not None, f"tried to write register {register:02X} to invalid device {device}" # support long registers by adding a 2 in front of the register number request_id = 0x8000 | (int(register) & 0x2FF) return device.request(request_id, *value) def get_configuration_pending_flags(receiver): assert not receiver.isDevice result = read_register(receiver, Registers.DEVICES_CONFIGURATION) if result is not None: return ord(result[:1]) def set_configuration_pending_flags(receiver, devices): assert not receiver.isDevice result = write_register(receiver, Registers.DEVICES_CONFIGURATION, devices) return result is not None class Hidpp10: def get_battery(self, device: Device): assert device is not None assert device.kind is not None if not device.online: return """Reads a device's battery level, if provided by the HID++ 1.0 protocol.""" if device.protocol and device.protocol >= 2.0: # let's just assume HID++ 2.0 devices do not provide the battery info in a register return for r in (Registers.BATTERY_STATUS, Registers.BATTERY_CHARGE): if r in device.registers: reply = read_register(device, r) if reply: return parse_battery_status(r, reply) return # the descriptor does not tell us which register this device has, try them both reply = read_register(device, Registers.BATTERY_CHARGE) if reply: # remember this for the next time device.registers.append(Registers.BATTERY_CHARGE) return parse_battery_status(Registers.BATTERY_CHARGE, reply) reply = read_register(device, Registers.BATTERY_STATUS) if reply: # remember this for the next time device.registers.append(Registers.BATTERY_STATUS) return parse_battery_status(Registers.BATTERY_STATUS, reply) def get_firmware(self, device: Device) -> tuple[common.FirmwareInfo] | None: assert device is not None firmware = [None, None, None] reply = read_register(device, Registers.FIRMWARE, 0x01) if not reply: # won't be able to read any of it now... return fw_version = common.strhex(reply[1:3]) fw_version = f"{fw_version[0:2]}.{fw_version[2:4]}" reply = read_register(device, Registers.FIRMWARE, 0x02) if reply: fw_version += ".B" + common.strhex(reply[1:3]) fw = common.FirmwareInfo(FirmwareKind.Firmware, "", fw_version, None) firmware[0] = fw reply = read_register(device, Registers.FIRMWARE, 0x04) if reply: bl_version = common.strhex(reply[1:3]) bl_version = f"{bl_version[0:2]}.{bl_version[2:4]}" bl = common.FirmwareInfo(FirmwareKind.Bootloader, "", bl_version, None) firmware[1] = bl reply = read_register(device, Registers.FIRMWARE, 0x03) if reply: o_version = common.strhex(reply[1:3]) o_version = f"{o_version[0:2]}.{o_version[2:4]}" o = common.FirmwareInfo(FirmwareKind.Other, "", o_version, None) firmware[2] = o if any(firmware): return tuple(f for f in firmware if f) def set_3leds(self, device: Device, battery_level=None, charging=None, warning=None): assert device is not None assert device.kind is not None if not device.online: return if Registers.THREE_LEDS not in device.registers: return if battery_level is not None: if battery_level < BatteryLevelApproximation.CRITICAL: # 1 orange, and force blink v1, v2 = 0x22, 0x00 warning = True elif battery_level < BatteryLevelApproximation.LOW: # 1 orange v1, v2 = 0x22, 0x00 elif battery_level < BatteryLevelApproximation.GOOD: # 1 green v1, v2 = 0x20, 0x00 elif battery_level < BatteryLevelApproximation.FULL: # 2 greens v1, v2 = 0x20, 0x02 else: # all 3 green v1, v2 = 0x20, 0x22 if warning: # set the blinking flag for the leds already set v1 |= v1 >> 1 v2 |= v2 >> 1 elif charging: # blink all green v1, v2 = 0x30, 0x33 elif warning: # 1 red v1, v2 = 0x02, 0x00 else: # turn off all leds v1, v2 = 0x11, 0x11 write_register(device, Registers.THREE_LEDS, v1, v2) def get_notification_flags(self, device: Device): flags = self._get_register(device, Registers.NOTIFICATIONS) if flags is not None: return NotificationFlag(flags) def set_notification_flags(self, device: Device, *flag_bits: NotificationFlag): assert device is not None # Avoid a call if the device is not online, # or the device does not support registers. if device.kind is not None: # peripherals with protocol >= 2.0 don't support registers if device.protocol and device.protocol >= 2.0: return flag_bits = sum(int(b.value) for b in flag_bits) assert flag_bits & 0x00FFFFFF == flag_bits result = write_register(device, Registers.NOTIFICATIONS, common.int2bytes(flag_bits, 3)) return result is not None def get_device_features(self, device: Device): return self._get_register(device, Registers.MOUSE_BUTTON_FLAGS) def _get_register(self, device: Device, register: Registers | int): assert device is not None # Avoid a call if the device is not online, # or the device does not support registers. if device.kind is not None: # peripherals with protocol >= 2.0 don't support registers if device.protocol and device.protocol >= 2.0: return flags = read_register(device, register) if flags is not None: assert len(flags) == 3 return common.bytes2int(flags) def parse_battery_status(register: Registers | int, reply) -> Battery | None: def status_byte_to_charge(status_byte_: int) -> BatteryLevelApproximation: if status_byte_ == 7: charge_ = BatteryLevelApproximation.FULL elif status_byte_ == 5: charge_ = BatteryLevelApproximation.GOOD elif status_byte_ == 3: charge_ = BatteryLevelApproximation.LOW elif status_byte_ == 1: charge_ = BatteryLevelApproximation.CRITICAL else: # pure 'charging' notifications may come without a status charge_ = BatteryLevelApproximation.EMPTY return charge_ def status_byte_to_battery_status(status_byte_: int) -> BatteryStatus: if status_byte_ == 0x30: status_text_ = BatteryStatus.DISCHARGING elif status_byte_ == 0x50: status_text_ = BatteryStatus.RECHARGING elif status_byte_ == 0x90: status_text_ = BatteryStatus.FULL else: status_text_ = None return status_text_ def charging_byte_to_status_text(charging_byte_: int) -> BatteryStatus: if charging_byte_ == 0x00: status_text_ = BatteryStatus.DISCHARGING elif charging_byte_ & 0x21 == 0x21: status_text_ = BatteryStatus.RECHARGING elif charging_byte_ & 0x22 == 0x22: status_text_ = BatteryStatus.FULL else: logger.warning("could not parse 0x07 battery status: %02X (level %02X)", charging_byte_, status_byte) status_text_ = None return status_text_ if register == Registers.BATTERY_CHARGE: charge = ord(reply[:1]) status_byte = ord(reply[2:3]) & 0xF0 battery_status = status_byte_to_battery_status(status_byte) return Battery(charge, None, battery_status, None) if register == Registers.BATTERY_STATUS: status_byte = ord(reply[:1]) charging_byte = ord(reply[1:2]) status_text = charging_byte_to_status_text(charging_byte) charge = status_byte_to_charge(status_byte) if charging_byte & 0x03 and status_byte == 0: # some 'charging' notifications may come with no battery level information charge = None # Return None for next charge level and voltage as these are not in HID++ 1.0 spec return Battery(charge, None, status_text, None) Solaar-1.1.20/lib/logitech_receiver/hidpp10_constants.py000066400000000000000000000200511522022367600231620ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations from enum import IntEnum from enum import IntFlag from typing import List from .common import NamedInts """HID constants for HID++ 1.0. Most of them as defined by the official Logitech HID++ 1.0 documentation, some of them guessed. """ DEVICE_KIND = NamedInts( unknown=0x00, keyboard=0x01, mouse=0x02, numpad=0x03, presenter=0x04, remote=0x07, trackball=0x08, touchpad=0x09, tablet=0x0A, gamepad=0x0B, joystick=0x0C, headset=0x0D, # not from Logitech documentation remote_control=0x0E, # for compatibility with HID++ 2.0 receiver=0x0F, # for compatibility with HID++ 2.0 ) class PowerSwitchLocation(IntEnum): UNKNOWN = 0x00 BASE = 0x01 TOP_CASE = 0x02 EDGE_OF_TOP_RIGHT_CORNER = 0x03 TOP_LEFT_CORNER = 0x05 BOTTOM_LEFT_CORNER = 0x06 TOP_RIGHT_CORNER = 0x07 BOTTOM_RIGHT_CORNER = 0x08 TOP_EDGE = 0x09 RIGHT_EDGE = 0x0A LEFT_EDGE = 0x0B BOTTOM_EDGE = 0x0C @classmethod def location(cls, loc: int) -> PowerSwitchLocation: try: return cls(loc) except ValueError: return cls.UNKNOWN class NotificationFlag(IntFlag): """Some flags are used both by devices and receivers. The Logitech documentation mentions that the first and last (third) byte are used for devices while the second is used for the receiver. In practise, the second byte is also used for some device-specific notifications (keyboard illumination level). Do not simply set all notification bits if the software does not support it. For example, enabling keyboard_sleep_raw makes the Sleep key a no-operation unless the software is updated to handle that event. Observations: - wireless and software present seen on receivers, reserved_r1b4 as well - the rest work only on devices as far as we can tell right now In the future would be useful to have separate enums for receiver and device notification flags, but right now we don't know enough. Additional flags taken from https://drive.google.com/file/d/0BxbRzx7vEV7eNDBheWY0UHM5dEU/view?usp=sharing """ @classmethod def flag_names(cls, flags) -> List[str]: """Extract the names of the flags from the integer.""" if flags is None: return [] if flags.name is not None: return flags.name.replace("_", " ").lower().split("|") # Python < 3.11: .name is None for composite flags, decompose manually return [m.name.replace("_", " ").lower() for m in cls if m.value and m in flags] NUMPAD_NUMERICAL_KEYS = 0x800000 F_LOCK_STATUS = 0x400000 ROLLER_H = 0x200000 BATTERY_STATUS = 0x100000 # send battery charge notifications (0x07 or 0x0D) MOUSE_EXTRA_BUTTONS = 0x080000 ROLLER_V = 0x040000 POWER_KEYS = 0x020000 # system control keys such as Sleep KEYBOARD_MULTIMEDIA_RAW = 0x010000 # consumer controls such as Mute and Calculator MULTI_TOUCH = 0x001000 # notify on multi-touch changes SOFTWARE_PRESENT = 0x000800 # software is controlling part of device behaviour LINK_QUALITY = 0x000400 # notify on link quality changes UI = 0x000200 # notify on UI changes WIRELESS = 0x000100 # notify when the device wireless goes on/off-line CONFIGURATION_COMPLETE = 0x000004 VOIP_TELEPHONY = 0x000002 THREED_GESTURE = 0x000001 def flags_to_str(flags, fallback: str) -> str: flag_names = [] if flags is not None and flags is not False: if flags.value == 0: flag_names = (fallback,) else: flag_names = NotificationFlag.flag_names(flags) return f"\n{' ':15}".join(sorted(flag_names)) class ErrorCode(IntEnum): INVALID_SUB_ID_COMMAND = 0x01 INVALID_ADDRESS = 0x02 INVALID_VALUE = 0x03 CONNECTION_REQUEST_FAILED = 0x04 TOO_MANY_DEVICES = 0x05 ALREADY_EXISTS = 0x06 BUSY = 0x07 UNKNOWN_DEVICE = 0x08 RESOURCE_ERROR = 0x09 REQUEST_UNAVAILABLE = 0x0A UNSUPPORTED_PARAMETER_VALUE = 0x0B WRONG_PIN_CODE = 0x0C class PairingError(IntEnum): DEVICE_TIMEOUT = 0x01 DEVICE_NOT_SUPPORTED = 0x02 TOO_MANY_DEVICES = 0x03 SEQUENCE_TIMEOUT = 0x06 @property def label(self) -> str: return self.name.lower().replace("_", " ") class BoltPairingError(IntEnum): DEVICE_TIMEOUT = 0x01 FAILED = 0x02 @property def label(self) -> str: return self.name.lower().replace("_", " ") class Registers(IntEnum): """Known HID registers. Devices usually have a (small) sub-set of these. Some registers are only applicable to certain device kinds (e.g. smooth_scroll only applies to mice). """ # Generally applicable NOTIFICATIONS = 0x00 FIRMWARE = 0xF1 # only apply to receivers RECEIVER_CONNECTION = 0x02 RECEIVER_PAIRING = 0xB2 DEVICES_ACTIVITY = 0x2B3 RECEIVER_INFO = 0x2B5 BOLT_DEVICE_DISCOVERY = 0xC0 BOLT_PAIRING = 0x2C1 BOLT_UNIQUE_ID = 0x02FB # only apply to devices MOUSE_BUTTON_FLAGS = 0x01 KEYBOARD_HAND_DETECTION = 0x01 DEVICES_CONFIGURATION = 0x03 BATTERY_STATUS = 0x07 KEYBOARD_FN_SWAP = 0x09 BATTERY_CHARGE = 0x0D KEYBOARD_ILLUMINATION = 0x17 THREE_LEDS = 0x51 MOUSE_DPI = 0x63 # notifications PASSKEY_REQUEST_NOTIFICATION = 0x4D PASSKEY_PRESSED_NOTIFICATION = 0x4E DEVICE_DISCOVERY_NOTIFICATION = 0x4F DISCOVERY_STATUS_NOTIFICATION = 0x53 PAIRING_STATUS_NOTIFICATION = 0x54 # Subregisters for receiver_info register class InfoSubRegisters(IntEnum): SERIAL_NUMBER = 0x01 # not found on many receivers FW_VERSION = 0x02 RECEIVER_INFORMATION = 0x03 PAIRING_INFORMATION = 0x20 # 0x2N, by connected device EXTENDED_PAIRING_INFORMATION = 0x30 # 0x3N, by connected device DEVICE_NAME = 0x40 # 0x4N, by connected device BOLT_PAIRING_INFORMATION = 0x50 # 0x5N, by connected device BOLT_DEVICE_NAME = 0x60 # 0x6N01, by connected device class DeviceFeature(IntFlag): """Features for devices. Flags taken from https://drive.google.com/file/d/0BxbRzx7vEV7eNDBheWY0UHM5dEU/view?usp=sharing """ @classmethod def flag_names(cls, flag_bits: int) -> List[str]: """Extract the names of the flags from the integer.""" indexed = {item.value: item.name for item in cls} flag_names = [] unknown_bits = flag_bits for k in indexed: # Ensure that the key (flag value) is a power of 2 (a single bit flag) assert bin(k).count("1") == 1 if k & flag_bits == k: unknown_bits &= ~k flag_names.append(indexed[k].replace("_", " ").lower()) # Yield any remaining unknown bits if unknown_bits != 0: flag_names.append(f"unknown:{unknown_bits:06X}") return flag_names RESERVED1 = 0x010000 SPECIAL_BUTTONS = 0x020000 ENHANCED_KEY_USAGE = 0x040000 FAST_FW_REV = 0x080000 RESERVED2 = 0x100000 RESERVED3 = 0x200000 SCROLL_ACCEL = 0x400000 BUTTONS_CONTROL_RESOLUTION = 0x800000 INHIBIT_LOCK_KEY_SOUND = 0x000001 RESERVED4 = 0x000002 MX_AIR_3D_ENGINE = 0x000004 HOST_CONTROL_LEDS = 0x000008 RESERVED5 = 0x000010 RESERVED6 = 0x000020 RESERVED7 = 0x000040 RESERVED8 = 0x000080 Solaar-1.1.20/lib/logitech_receiver/hidpp20.py000066400000000000000000003026601522022367600211000ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import logging import socket import struct import threading from collections import UserDict from enum import Flag from enum import IntEnum from random import getrandbits from typing import Any from typing import Dict from typing import Generator from typing import Optional from typing import Tuple import yaml from solaar.i18n import _ from typing_extensions import Protocol from . import centurion as _centurion from . import common from . import exceptions from . import hidpp10_constants from . import special_keys from .centurion_constants import CenturionCoreFeature from .centurion_constants import resolve_feature from .common import Battery from .common import BatteryLevelApproximation from .common import BatteryStatus from .common import FirmwareKind from .common import NamedInt from .hidpp20_constants import DEVICE_KIND from .hidpp20_constants import ChargeLevel from .hidpp20_constants import ChargeType from .hidpp20_constants import ErrorCode from .hidpp20_constants import FeatureFlag from .hidpp20_constants import GestureId from .hidpp20_constants import ParamId from .hidpp20_constants import SupportedFeature logger = logging.getLogger(__name__) FixedBytes5 = bytes KIND_MAP = {kind: hidpp10_constants.DEVICE_KIND[str(kind)] for kind in DEVICE_KIND} class Device(Protocol): def feature_request(self, feature, function=0x00, *params, no_reply=False) -> Any: ... @property def features(self) -> Any: ... @property def _gestures(self) -> Any: ... @property def _backlight(self) -> Any: ... @property def _profiles(self) -> Any: ... # pfps: Consider adding a class method that sanitizes inputs by removing unknown bits. class KeyFlag(Flag): """Capabilities and desired software handling for a control. Ref: https://drive.google.com/file/d/10imcbmoxTJ1N510poGdsviEhoFfB_Ua4/view We treat bytes 4 and 8 of `getCidInfo` as a single bitfield. """ UNUSED_8000 = 0x8000 UNUSED_4000 = 0x4000 UNUSED_2000 = 0x2000 UNUSED_1000 = 0x1000 RAW_WHEEL = 0x800 ANALYTICS_KEY_EVENTS = 0x400 FORCE_RAW_XY = 0x200 RAW_XY = 0x100 VIRTUAL = 0x80 PERSISTENTLY_DIVERTABLE = 0x40 DIVERTABLE = 0x20 REPROGRAMMABLE = 0x10 FN_SENSITIVE = 0x08 NONSTANDARD = 0x04 IS_FN = 0x02 MSE = 0x01 class MappingFlag(Flag): """Flags describing the reporting method of a control. We treat bytes 2 and 5 of `get/setCidReporting` as a single bitfield """ UNUSED_4000 = 0x4000 UNUSED_1000 = 0x1000 RAW_WHEEL = 0x400 UNKNOWN_200 = 0x200 # seen on a Wireless Mouse M510 WPID 4004 ANALYTICS_KEY_EVENTS_REPORTING = 0x100 FORCE_RAW_XY_DIVERTED = 0x40 RAW_XY_DIVERTED = 0x10 PERSISTENTLY_DIVERTED = 0x04 DIVERTED = 0x01 class ChargeStatus(Flag): CHARGING = 0x00 FULL = 0x01 NOT_CHARGING = 0x02 ERROR = 0x07 class FeaturesArray(dict): def __init__(self, device): assert device is not None self.supported = True # Actually don't know whether it is supported yet self.device = device self.inverse = {} self.sub_inverse = {} self.version = {} self.flags = {} self.count = 0 def _check(self) -> bool: if not self.device.online: return False if self.supported is False: return False if self.device.protocol and self.device.protocol < 2.0: self.supported = False return False if self.count > 0: return True reply = self.device.request(0x0000, struct.pack("!H", SupportedFeature.FEATURE_SET)) if reply is not None: fs_index = reply[0] if fs_index: count = self.device.request(fs_index << 8) if count is None: logger.warning("FEATURE_SET found, but failed to read features count") return False else: self[SupportedFeature.ROOT] = 0 self[SupportedFeature.FEATURE_SET] = fs_index if getattr(self.device, "centurion", False): self._check_centurion(fs_index, count) else: self.count = count[0] + 1 # ROOT feature not included in count return True else: self.supported = False return False def _check_centurion(self, fs_index, count_response): """Enumerate features on a Centurion device (parent + sub-device via CentPPBridge). Phase A: Enumerate parent device features via CenturionFeatureSet. Find the CentPPBridge index (feature ID 0x0003 on Centurion = CentPPBridge). Phase B: Route through CentPPBridge to discover sub-device features. Use CenturionFeatureSet bulk query to get all sub-device features. Store sub-device features keyed by SupportedFeature enum. """ # Phase A: Parent features feature_count = count_response[0] # includes ROOT on Centurion self.count = feature_count bridge_index = None for index in range(feature_count): if self.inverse.get(index) is not None: continue # already registered (ROOT=0, FEATURE_SET=fs_index) response = self.device.request((fs_index << 8) | 0x10, index) if response is None or len(response) < 3: continue # Centurion FeatureSet response: [remaining_count, feat_hi, feat_lo, type, version] feat_id = struct.unpack("!H", response[1:3])[0] feat_type = response[3] if len(response) > 3 else 0 feat_version = response[4] if len(response) > 4 else 0 feature = resolve_feature(feat_id, centurion=True) if feature is None: feature = f"unknown:{feat_id:04X}" self[feature] = index self.inverse[index] = feature # Record version/flags so version-gated settings (sidetone, auto-sleep) # use the correct payload format on direct USB Centurion devices too. self.version[feature] = feat_version self.flags[feature] = feat_type if logger.isEnabledFor(logging.DEBUG): logger.debug( "Centurion parent feature: %s at index %d, version=%d, flags=0x%02X", feature, index, feat_version, feat_type, ) if feature is CenturionCoreFeature.CENT_PP_BRIDGE: bridge_index = index if bridge_index is not None: self.device._centurion_bridge_index = bridge_index self.device._centurion_sub_features = set() self.device._centurion_sub_indices = {} self._discover_sub_device_features(bridge_index) def _discover_sub_device_features(self, bridge_index): """Phase B: Discover sub-device features via CentPPBridge. Uses per-index queries: GetCount (func 0) returns total count, then GetFeatureId (func 1) returns one feature per call. Avoids the single-frame truncation of bulk queries — a Centurion frame is 64 bytes so a bulk reply can only fit ~13 features regardless of how many the sub-device actually has. """ # First, find the sub-device's FeatureSet index via CenturionRoot (sub_feat_idx=0) # Query: CenturionRoot.GetFeature(0x0001) to find FeatureSet index on sub-device fs_id_hi = (SupportedFeature.FEATURE_SET >> 8) & 0xFF fs_id_lo = SupportedFeature.FEATURE_SET & 0xFF response = self.device.centurion_bridge_request(0x00, 0x00, fs_id_hi, fs_id_lo) if response is None or len(response) < 1: logger.warning("Failed to find FeatureSet on Centurion sub-device") return sub_fs_index = response[0] if sub_fs_index == 0: logger.warning("Sub-device FeatureSet not found (index=0)") return # Query feature count (function 0 = GetCount). Response: [count, ...]. count_resp = self.device.centurion_bridge_request(sub_fs_index, 0x00) if count_resp is None or len(count_resp) < 1: logger.warning("Failed to read Centurion sub-device feature count") return total_count = count_resp[0] if logger.isEnabledFor(logging.DEBUG): logger.debug("Centurion sub-device: FeatureSet reports %d features", total_count) # Per-index query: GetFeatureId (function 1 = 0x10). # Response: [remaining, feat_hi, feat_lo, type, version]. # We now also record `type` (flags) and `version` for each feature so # version-gated settings (sidetone, auto-sleep, etc.) can use the # correct payload format instead of defaulting to V0. sub_feat_idx = 0 for idx in range(total_count): response = self.device.centurion_bridge_request(sub_fs_index, 0x10, idx) if response is None or len(response) < 3: logger.debug("Centurion sub-device: no response at index %d", idx) continue feat_id = struct.unpack("!H", response[1:3])[0] feat_type = response[3] if len(response) > 3 else 0 feat_version = response[4] if len(response) > 4 else 0 try: feature = SupportedFeature(feat_id) except ValueError: feature = f"unknown:{feat_id:04X}" self.device._centurion_sub_indices[feature] = sub_feat_idx if dict.get(self, feature) is None: dict.__setitem__(self, feature, sub_feat_idx) self.device._centurion_sub_features.add(feature) self.sub_inverse[sub_feat_idx] = feature # Record version/flags so downstream settings can version-gate their # payload format. get_feature_version(feature) reads self.version[feature]. self.version[feature] = feat_version self.flags[feature] = feat_type if logger.isEnabledFor(logging.DEBUG): logger.debug( "Centurion sub-device feature: %s at sub-index %d, version=%d, flags=0x%02X", feature, sub_feat_idx, feat_version, feat_type, ) sub_feat_idx += 1 self._sub_feature_count = sub_feat_idx if logger.isEnabledFor(logging.DEBUG): logger.debug("Centurion sub-device: discovered %d features total", sub_feat_idx) def get_feature(self, index: int) -> SupportedFeature | None: feature = self.inverse.get(index) if feature is not None: return feature # Sub-device index; bridge unwrap offsets by 0x100 (see listener). if index >= 0x100: return self.sub_inverse.get(index - 0x100) elif self._check(): feature = self.inverse.get(index) if feature is not None: return feature # On Centurion devices, all features are discovered upfront (parent + sub-device) if getattr(self.device, "centurion", False): return None try: response = self.device.feature_request(SupportedFeature.FEATURE_SET, 0x10, index) except exceptions.FeatureCallError: logger.warning("failed to retrieve feature at index %d", index) return None if response: data = struct.unpack("!H", response[:2])[0] try: feature = SupportedFeature(data) except ValueError: feature = f"unknown:{data:04X}" self[feature] = index self.version[feature] = response[3] self.flags[feature] = response[2] return feature def enumerate(self): # return all features and their index, ordered by index if self._check(): for index in range(self.count): feature = self.get_feature(index) if feature is not None: yield feature, index # Also yield sub-device features for Centurion devices sub_count = getattr(self, "_sub_feature_count", 0) for sub_idx in range(sub_count): feature = self.sub_inverse.get(sub_idx) if feature is not None: yield feature, sub_idx def get_feature_version(self, feature: NamedInt) -> Optional[int]: if self[feature]: return self.version.get(feature, 0) def get_flags(self, feature: NamedInt) -> Optional[int]: if self[feature]: return self.flags.get(feature, 0) def get_hidden(self, feature: NamedInt) -> Optional[bool]: if self[feature]: return self.flags.get(feature, 0) & FeatureFlag.INTERNAL return True def __contains__(self, feature: NamedInt) -> bool: try: index = self.__getitem__(feature) return index is not None and index is not False except exceptions.FeatureCallError: return False def __getitem__(self, feature: NamedInt) -> Optional[int]: index = super().get(feature) if index is not None: return index elif self._check(): index = super().get(feature) if index is not None: return index # Centurion devices enumerate all features upfront in _check_centurion(). # If the feature isn't in the dict after _check(), it genuinely doesn't # exist — skip the raw ROOT.GetFeature query that the dongle rejects # with LOGITECH_ERROR and that creates cycling log spam during settings init. if getattr(self.device, "centurion", False): return None try: response = self.device.request(0x0000, struct.pack("!H", feature)) except exceptions.FeatureCallError: return None if response: index = response[0] self[feature] = index if index else False self.version[feature] = response[2] self.flags[feature] = response[1] return index if index else False def __setitem__(self, feature, index): if isinstance(super().get(feature), int): self.inverse.pop(super().get(feature)) super().__setitem__(feature, index) if index is not False: self.inverse[index] = feature def __delitem__(self, feature): raise ValueError("Don't delete features from FeatureArray") def __len__(self) -> int: return self.count + getattr(self, "_sub_feature_count", 0) __bool__ = __nonzero__ = _check class ReprogrammableKey: """Information about a control present on a device with the `REPROG_CONTROLS` feature. Read-only properties: - index -- index in the control ID table - key -- the name of this control - default_task -- the native function of this control - flags -- capabilities and desired software handling of the control Ref: https://drive.google.com/file/d/0BxbRzx7vEV7eU3VfMnRuRXktZ3M/view """ def __init__(self, device: Device, index: int, cid: int, task_id: int, flags: int): self._device = device self.index = index self._cid = cid self._tid = task_id self._flags = flags @property def key(self) -> NamedInt: return special_keys.CONTROL[self._cid] @property def default_task(self) -> NamedInt: """NOTE: This NamedInt is a bit mixed up, because its value is the Control ID while the name is the Control ID's native task. But this makes more sense than presenting details of controls vs tasks in the interface. The same convention applies to `mapped_to`, `remappable_to`, `remap` in `ReprogrammableKeyV4`.""" try: task = str(special_keys.Task(self._tid)) except ValueError: task = f"unknown:{self._tid:04X}" return NamedInt(self._cid, task) @property def flags(self) -> KeyFlag: return KeyFlag(self._flags) class ReprogrammableKeyV4(ReprogrammableKey): """Information about a control present on a device with the `REPROG_CONTROLS_V4` feature. Ref (v2): https://lekensteyn.nl/files/logitech/x1b04_specialkeysmsebuttons.html Ref (v4): https://drive.google.com/file/d/10imcbmoxTJ1N510poGdsviEhoFfB_Ua4/view Contains all the functionality of `ReprogrammableKey` plus remapping keys and /diverting/ them in order to handle keypresses in a custom way. Additional read-only properties: - pos {int} -- position of this control on the device; 1-16 for FN-keys, otherwise 0 - group {int} -- the group this control belongs to; other controls with this group in their `group_mask` can be remapped to this control - group_mask {List[str]} -- this control can be remapped to any control ID in these groups - mapped_to {NamedInt} -- which action this control is mapped to; usually itself - remappable_to {List[NamedInt]} -- list of actions which this control can be remapped to - mapping_flags {List[str]} -- mapping flags set on the control """ def __init__(self, device: Device, index, cid, task_id, flags, pos, group, gmask): ReprogrammableKey.__init__(self, device, index, cid, task_id, flags) self.pos = pos self.group = group self._gmask = gmask self._mapping_flags = None self._mapped_to = None @property def group_mask(self) -> Generator[str]: return common.flag_names(special_keys.CIDGroupBit, self._gmask) @property def mapped_to(self) -> NamedInt: if self._mapped_to is None: self._getCidReporting() self._device.keys._ensure_all_keys_queried() try: task = str(special_keys.Task(self._device.keys.cid_to_tid[self._mapped_to])) except ValueError: task = f"Unknown_{self._mapped_to:x}" return NamedInt(self._mapped_to, task) @property def remappable_to(self): self._device.keys._ensure_all_keys_queried() ret = common.UnsortedNamedInts() if self.group_mask: # only keys with a non-zero gmask are remappable ret[self.default_task] = self.default_task # it should always be possible to map the key to itself for g in self.group_mask: g = special_keys.CidGroup[str(g)] for tgt_cid in self._device.keys.group_cids[g]: cid = self._device.keys.cid_to_tid[tgt_cid] try: tgt_task = str(special_keys.Task(cid)) except ValueError: tgt_task = f"unknown:{cid:04X}" tgt_task = NamedInt(tgt_cid, tgt_task) if tgt_task != self.default_task: # don't put itself in twice ret[tgt_task] = tgt_task return ret @property def mapping_flags(self) -> MappingFlag: if self._mapping_flags is None: self._getCidReporting() return MappingFlag(self._mapping_flags) def set_diverted(self, value: bool) -> None: """If set, the control is diverted temporarily and reports presses as HID++ events.""" flags = {MappingFlag.DIVERTED: value} self._setCidReporting(flags=flags) def set_persistently_diverted(self, value: bool) -> None: """If set, the control is diverted permanently and reports presses as HID++ events.""" flags = {MappingFlag.PERSISTENTLY_DIVERTED: value} self._setCidReporting(flags=flags) def set_rawXY_reporting(self, value: bool) -> None: """If set, the mouse temporarily reports all its raw XY events while this control is pressed as HID++ events.""" flags = {MappingFlag.RAW_XY_DIVERTED: value} self._setCidReporting(flags=flags) def remap(self, to: NamedInt): """Temporarily remaps this control to another action.""" self._setCidReporting(remap=int(to)) def _getCidReporting(self): try: mapped_data = self._device.feature_request( SupportedFeature.REPROG_CONTROLS_V4, 0x20, *tuple(struct.pack("!H", self._cid)), ) if mapped_data: cid, mapping_flags_1, mapped_to = struct.unpack("!HBH", mapped_data[:5]) if cid != self._cid and logger.isEnabledFor(logging.WARNING): logger.warning( f"REPROG_CONTROLS_V4 endpoint getCidReporting on device {self._device} replied " + f"with a different control ID ({cid}) than requested ({self._cid})." ) self._mapped_to = mapped_to if mapped_to != 0 else self._cid if len(mapped_data) > 5: (mapping_flags_2,) = struct.unpack("!B", mapped_data[5:6]) else: mapping_flags_2 = 0 self._mapping_flags = mapping_flags_1 | (mapping_flags_2 << 8) else: raise exceptions.FeatureCallError(msg="No reply from device.") except exceptions.FeatureCallError: # if the key hasn't ever been configured only produce a warning if logger.isEnabledFor(logging.WARNING): logger.warning( f"Feature Call Error in _getCidReporting on device {self._device} for cid {self._cid} - use defaults" ) # Clear flags and set mapping target to self self._mapping_flags = 0 self._mapped_to = self._cid def _setCidReporting(self, flags: Dict[NamedInt, bool] = None, remap: int = 0): """Sends a `setCidReporting` request with the given parameters. Raises an exception if the parameters are invalid. Parameters ---------- flags A dictionary of which mapping flags to set/unset. remap Which control ID to remap to; or 0 to keep current mapping. """ flags = flags if flags else {} # See flake8 B006 # The capability required to set a given reporting flag. FLAG_TO_CAPABILITY = { MappingFlag.DIVERTED: KeyFlag.DIVERTABLE, MappingFlag.PERSISTENTLY_DIVERTED: KeyFlag.PERSISTENTLY_DIVERTABLE, MappingFlag.ANALYTICS_KEY_EVENTS_REPORTING: KeyFlag.ANALYTICS_KEY_EVENTS, MappingFlag.FORCE_RAW_XY_DIVERTED: KeyFlag.FORCE_RAW_XY, MappingFlag.RAW_XY_DIVERTED: KeyFlag.RAW_XY, } bfield = 0 for mapping_flag, activated in flags.items(): key_flag = FLAG_TO_CAPABILITY[mapping_flag] if activated and key_flag not in self.flags: raise exceptions.FeatureNotSupported( msg=f'Tried to set mapping flag "{mapping_flag}" on control "{self.key}" ' + f'which does not support "{key_flag}" on device {self._device}.' ) bfield |= mapping_flag.value if activated else 0 bfield |= mapping_flag.value << 1 # The 'Xvalid' bit if self._mapping_flags: # update flags if already read if activated: self._mapping_flags |= mapping_flag.value else: self._mapping_flags &= ~mapping_flag.value if remap != 0 and remap not in self.remappable_to: raise exceptions.FeatureNotSupported( msg=f'Tried to remap control "{self.key}" to a control ID {remap} which it is not remappable to ' + f"on device {self._device}." ) if remap != 0: # update mapping if changing (even if not already read) self._mapped_to = remap pkt = tuple(struct.pack("!HBH", self._cid, bfield & 0xFF, remap)) # TODO: to fully support version 4 of REPROG_CONTROLS_V4, append `(bfield >> 8) & 0xff` here. # But older devices might behave oddly given that byte, so we don't send it. ret = self._device.feature_request(SupportedFeature.REPROG_CONTROLS_V4, 0x30, *pkt) if ret is None or struct.unpack("!BBBBB", ret[:5]) != pkt and logger.isEnabledFor(logging.DEBUG): logger.debug(f"REPROG_CONTROLS_v4 setCidReporting on device {self._device} didn't echo request packet.") class PersistentRemappableAction: def __init__(self, device, index, cid, actionId, remapped, modifierMask, cidStatus): self._device = device self.index = index self._cid = cid self.actionId = actionId self.remapped = remapped self._modifierMask = modifierMask self.cidStatus = cidStatus @property def key(self) -> NamedInt: return special_keys.CONTROL[self._cid] @property def actionType(self) -> NamedInt: return special_keys.ACTIONID[self.actionId] @property def action(self): if self.actionId == special_keys.ACTIONID.Empty: return None elif self.actionId == special_keys.ACTIONID.Key: return f"Key: {str(self.modifiers)}{str(self.remapped)}" elif self.actionId == special_keys.ACTIONID.Mouse: return f"Mouse Button: {str(self.remapped)}" elif self.actionId == special_keys.ACTIONID.Xdisp: return f"X Displacement {str(self.remapped)}" elif self.actionId == special_keys.ACTIONID.Ydisp: return f"Y Displacement {str(self.remapped)}" elif self.actionId == special_keys.ACTIONID.Vscroll: return f"Vertical Scroll {str(self.remapped)}" elif self.actionId == special_keys.ACTIONID.Hscroll: return f"Horizontal Scroll: {str(self.remapped)}" elif self.actionId == special_keys.ACTIONID.Consumer: return f"Consumer: {str(self.remapped)}" elif self.actionId == special_keys.ACTIONID.Internal: return f"Internal Action {str(self.remapped)}" elif self.actionId == special_keys.ACTIONID.Internal: return f"Power {str(self.remapped)}" else: return "Unknown" @property def modifiers(self): return special_keys.modifiers[self._modifierMask] @property def data_bytes(self): return ( common.int2bytes(self.actionId, 1) + common.int2bytes(self.remapped, 2) + common.int2bytes(self._modifierMask, 1) ) def remap(self, data_bytes): cid = common.int2bytes(self._cid, 2) if common.bytes2int(data_bytes) == special_keys.KEYS_Default: # map back to default self._device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x50, cid, 0xFF) self._device.remap_keys._query_key(self.index) return self._device.remap_keys.keys[self.index].data_bytes else: self.actionId, self.remapped, self._modifierMask = struct.unpack("!BHB", data_bytes) self.cidStatus = 0x01 self._device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x40, cid, 0xFF, data_bytes) return True class KeysArray: """A sequence of key mappings supported by a HID++ 2.0 device.""" def __init__(self, device, count, version): assert device is not None self.device = device self.lock = threading.Lock() if SupportedFeature.REPROG_CONTROLS_V4 in self.device.features: self.keyversion = SupportedFeature.REPROG_CONTROLS_V4 elif SupportedFeature.REPROG_CONTROLS_V2 in self.device.features: self.keyversion = SupportedFeature.REPROG_CONTROLS_V2 else: if logger.isEnabledFor(logging.ERROR): logger.error(f"Trying to read keys on device {device} which has no REPROG_CONTROLS(_VX) support.") self.keyversion = None self.keys = [None] * count def _ensure_all_keys_queried(self): """The retrieval of key information is lazy, but for certain functionality we need to know all keys. This function makes sure that's the case.""" with self.lock: # don't want two threads doing this for i, k in enumerate(self.keys): if k is None: self._query_key(i) def __getitem__(self, index): if isinstance(index, int): if index < 0 or index >= len(self.keys): raise IndexError(index) if self.keys[index] is None: self._query_key(index) return self.keys[index] elif isinstance(index, slice): indices = index.indices(len(self.keys)) return [self.__getitem__(i) for i in range(*indices)] def index(self, value): self._ensure_all_keys_queried() for index, k in enumerate(self.keys): if k is not None and int(value) == int(k.key): return index def __iter__(self): for k in range(0, len(self.keys)): yield self.__getitem__(k) def __len__(self): return len(self.keys) class KeysArrayV2(KeysArray): def __init__(self, device: Device, count, version=1): super().__init__(device, count, version) """The mapping from Control IDs to their native Task IDs. For example, Control "Left Button" is mapped to Task "Left Click". When remapping controls, we point the control we want to remap at a target Control ID rather than a target Task ID. This has the effect of performing the native task of the target control, even if the target itself is also remapped. So remapping is not recursive.""" self.cid_to_tid = {} """The mapping from Control ID groups to Controls IDs that belong to it. A key k can only be remapped to targets in groups within k.group_mask.""" self.group_cids = {g: [] for g in special_keys.CidGroup} def _query_key(self, index: int): if index < 0 or index >= len(self.keys): raise IndexError(index) keydata = self.device.feature_request(SupportedFeature.REPROG_CONTROLS, 0x10, index) if keydata: cid, task_id, flags = struct.unpack("!HHB", keydata[:5]) self.keys[index] = ReprogrammableKey(self.device, index, cid, task_id, flags) self.cid_to_tid[cid] = task_id elif logger.isEnabledFor(logging.WARNING): logger.warning(f"Key with index {index} was expected to exist but device doesn't report it.") class KeysArrayV4(KeysArrayV2): def __init__(self, device, count): super().__init__(device, count, 4) def _query_key(self, index: int): if index < 0 or index >= len(self.keys): raise IndexError(index) keydata = self.device.feature_request(SupportedFeature.REPROG_CONTROLS_V4, 0x10, index) if keydata: cid, task_id, flags1, pos, group, gmask, flags2 = struct.unpack("!HHBBBBB", keydata[:9]) flags = flags1 | (flags2 << 8) self.keys[index] = ReprogrammableKeyV4(self.device, index, cid, task_id, flags, pos, group, gmask) self.cid_to_tid[cid] = task_id if group != 0: # 0 = does not belong to a group self.group_cids[special_keys.CidGroup(group)].append(cid) elif logger.isEnabledFor(logging.WARNING): logger.warning(f"Key with index {index} was expected to exist but device doesn't report it.") # we are only interested in the current host, so use 0xFF for the host throughout class KeysArrayPersistent(KeysArray): def __init__(self, device, count): super().__init__(device, count, 5) self._capabilities = None @property def capabilities(self): if self._capabilities is None and self.device.online: capabilities = self.device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x00) assert capabilities, "Oops, persistent remappable key capabilities cannot be retrieved!" self._capabilities = struct.unpack("!H", capabilities[:2])[0] # flags saying what the mappings are possible return self._capabilities def _query_key(self, index: int): if index < 0 or index >= len(self.keys): raise IndexError(index) keydata = self.device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x20, index, 0xFF) if keydata: key = struct.unpack("!H", keydata[:2])[0] mapped_data = self.device.feature_request( SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x30, key >> 8, key & 0xFF, 0xFF, ) if mapped_data: _ignore, _ignore, actionId, remapped, modifiers, status = struct.unpack("!HBBHBB", mapped_data[:8]) else: actionId = remapped = modifiers = status = 0 actionId = special_keys.ACTIONID[actionId] if actionId == special_keys.ACTIONID.Key: remapped = special_keys.USB_HID_KEYCODES[remapped] elif actionId == special_keys.ACTIONID.Mouse: remapped = special_keys.MOUSE_BUTTONS[remapped] elif actionId == special_keys.ACTIONID.Hscroll: try: remapped = special_keys.HorizontalScroll(remapped) except ValueError: remapped = f"unknown horizontal scroll:{remapped:04X}" elif actionId == special_keys.ACTIONID.Consumer: remapped = special_keys.HID_CONSUMERCODES[remapped] elif actionId == special_keys.ACTIONID.Empty: # purge data from empty value remapped = modifiers = 0 self.keys[index] = PersistentRemappableAction( self.device, index, key, actionId, remapped, modifiers, status, ) elif logger.isEnabledFor(logging.WARNING): logger.warning(f"Key with index {index} was expected to exist but device doesn't report it.") class SubParam: __slots__ = ("id", "length", "minimum", "maximum", "widget") def __init__(self, id, length, minimum=None, maximum=None, widget=None): self.id = id self.length = length self.minimum = minimum if minimum is not None else 0 self.maximum = maximum if maximum is not None else ((1 << 8 * length) - 1) self.widget = widget if widget is not None else "Scale" def __str__(self): return self.id def __repr__(self): return self.id SUB_PARAM = { # (byte count, minimum, maximum) ParamId.EXTRA_CAPABILITIES: None, # ignore ParamId.PIXEL_ZONE: ( # TODO: replace min and max with the correct values SubParam("left", 2, 0x0000, 0xFFFF, "SpinButton"), SubParam("bottom", 2, 0x0000, 0xFFFF, "SpinButton"), SubParam("width", 2, 0x0000, 0xFFFF, "SpinButton"), SubParam("height", 2, 0x0000, 0xFFFF, "SpinButton"), ), ParamId.RATIO_ZONE: ( # TODO: replace min and max with the correct values SubParam("left", 1, 0x00, 0xFF, "SpinButton"), SubParam("bottom", 1, 0x00, 0xFF, "SpinButton"), SubParam("width", 1, 0x00, 0xFF, "SpinButton"), SubParam("height", 1, 0x00, 0xFF, "SpinButton"), ), ParamId.SCALE_FACTOR: (SubParam("scale", 2, 0x002E, 0x01FF, "Scale"),), } class SpecGesture(IntEnum): """Spec IDs for feature GESTURE_2.""" DVI_FIELD_WIDTH = 1 FIELD_WIDTHS = 2 PERIOD_UNIT = 3 RESOLUTION = 4 MULTIPLIER = 5 SENSOR_SIZE = 6 FINGER_WIDTH_AND_HEIGHT = 7 FINGER_MAJOR_MINOR_AXIS = 8 FINGER_FORCE = 9 ZONE = 10 def __str__(self): return f"{self.name.replace('_', ' ').lower()}" class ActionId(IntEnum): """Action IDs for feature GESTURE_2.""" MOVE_POINTER = 1 SCROLL_HORIZONTAL = 2 WHEEL_SCROLLING = 3 SCROLL_VERTICAL = 4 SCROLL_OR_PAGE_XY = 5 SCROLL_OR_PAGE_HORIZONTAL = 6 PAGE_SCREEN = 7 DRAG = 8 SECONDARY_DRAG = 9 ZOOM = 10 SCROLL_HORIZONTAL_ONLY = 11 SCROLL_VERTICAL_ONLY = 12 class Gesture: def __init__(self, device, low, high, next_index, next_diversion_index): self._device = device self.id = low self.gesture = GestureId(low) self.can_be_enabled = high & 0x01 self.can_be_diverted = high & 0x02 self.show_in_ui = high & 0x04 self.desired_software_default = high & 0x08 self.persistent = high & 0x10 self.default_enabled = high & 0x20 self.index = next_index if self.can_be_enabled or self.default_enabled else None self.diversion_index = next_diversion_index if self.can_be_diverted else None self._enabled = None self._diverted = None def _offset_mask(self, index): # offset and mask if index is not None: offset = index >> 3 # 8 gestures per byte mask = 0x1 << (index % 8) return offset, mask else: return None, None def enable_offset_mask(self): return self._offset_mask(self.index) def diversion_offset_mask(self): return self._offset_mask(self.diversion_index) def enabled(self): # is the gesture enabled? if self._enabled is None and self.index is not None: offset, mask = self.enable_offset_mask() result = self._device.feature_request(SupportedFeature.GESTURE_2, 0x10, offset, 0x01, mask) self._enabled = bool(result[0] & mask) if result else None return self._enabled def set(self, enable): # enable or disable the gesture if not self.can_be_enabled: return None if self.index is not None: offset, mask = self.enable_offset_mask() reply = self._device.feature_request( SupportedFeature.GESTURE_2, 0x20, offset, 0x01, mask, mask if enable else 0x00 ) return reply def diverted(self): # is the gesture diverted? if self._diverted is None and self.diversion_index is not None: offset, mask = self.diversion_offset_mask() result = self._device.feature_request(SupportedFeature.GESTURE_2, 0x30, offset, 0x01, mask) self._diverted = bool(result[0] & mask) if result else None return self._diverted def divert(self, diverted): # divert or undivert the gesture if not self.can_be_diverted: return None if self.diversion_index is not None: offset, mask = self.diversion_offset_mask() reply = self._device.feature_request( SupportedFeature.GESTURE_2, 0x40, offset, 0x01, mask, mask if diverted else 0x00, ) return reply def as_int(self): return self.gesture def __int__(self): return self.id def __repr__(self): return f"" # allow a gesture to be used as a settings reader/writer to enable and disable the gesture read = enabled write = set class Param: def __init__(self, device, low: int, high, next_param_index): self._device = device self.id = low self.param = ParamId(low) self.size = high & 0x0F self.show_in_ui = bool(high & 0x1F) self._value = None self._default_value = None self.index = next_param_index @property def sub_params(self): return SUB_PARAM.get(self.id, None) @property def value(self): return self._value if self._value is not None else self.read() def read(self): # returns the bytes for the parameter result = self._device.feature_request(SupportedFeature.GESTURE_2, 0x70, self.index, 0xFF) if result: self._value = common.bytes2int(result[: self.size]) return self._value @property def default_value(self): if self._default_value is None: self._default_value = self._read_default() return self._default_value def _read_default(self): result = self._device.feature_request(SupportedFeature.GESTURE_2, 0x60, self.index, 0xFF) if result: self._default_value = common.bytes2int(result[: self.size]) return self._default_value def write(self, bytes): self._value = bytes return self._device.feature_request(SupportedFeature.GESTURE_2, 0x80, self.index, bytes, 0xFF) def __str__(self): return str(self.param) def __int__(self): return self.id class Spec: def __init__(self, device, low: int, high): self._device = device self.id = low try: self.spec = SpecGesture(low) except ValueError: self.spec = f"unknown:{low:04X}" self.byte_count = high & 0x0F self._value = None @property def value(self): if self._value is None: self._value = self.read() return self._value def read(self): try: value = self._device.feature_request(SupportedFeature.GESTURE_2, 0x50, self.id, 0xFF) except exceptions.FeatureCallError: # some calls produce an error (notably spec 5 multiplier on K400Plus) if logger.isEnabledFor(logging.WARNING): logger.warning( f"Feature Call Error reading Gesture Spec on device {self._device} for spec {self.id} - use None" ) return None return common.bytes2int(value[: self.byte_count]) def __repr__(self): return f"[{self.spec}={self.value}]" class Gestures: """Information about the gestures that a device supports. Right now only some information fields are supported. WARNING: Assumes that parameters are always global, which is not the case. """ def __init__(self, device): self.device = device self.gestures = {} self.params = {} self.specs = {} index = 0 next_gesture_index = next_divsn_index = next_param_index = 0 field_high = 0x00 while field_high != 0x01: # end of fields # retrieve the next eight fields fields = device.feature_request(SupportedFeature.GESTURE_2, 0x00, index >> 8, index & 0xFF) if not fields: break for offset in range(8): field_high = fields[offset * 2] field_low = fields[offset * 2 + 1] if field_high == 0x1: # end of fields break elif field_high & 0x80: gesture = Gesture(device, field_low, field_high, next_gesture_index, next_divsn_index) next_gesture_index = next_gesture_index if gesture.index is None else next_gesture_index + 1 next_divsn_index = next_divsn_index if gesture.diversion_index is None else next_divsn_index + 1 self.gestures[gesture.gesture] = gesture elif field_high & 0xF0 == 0x30 or field_high & 0xF0 == 0x20: param = Param(device, field_low, field_high, next_param_index) next_param_index = next_param_index + 1 self.params[param.param] = param elif field_high == 0x04: if field_low != 0x00: logger.error(f"Unimplemented GESTURE_2 grouping {field_low} {field_high} found.") elif field_high & 0xF0 == 0x40: spec = Spec(device, field_low, field_high) self.specs[spec.spec] = spec else: logger.warning(f"Unimplemented GESTURE_2 field {field_low} {field_high} found.") index += 1 def gesture(self, gesture): return self.gestures.get(gesture, None) def gesture_enabled(self, gesture): # is the gesture enabled? g = self.gestures.get(gesture, None) return g.enabled() if g else None def enable_gesture(self, gesture): g = self.gestures.get(gesture, None) return g.set(True) if g else None def disable_gesture(self, gesture): g = self.gestures.get(gesture, None) return g.set(False) if g else None def param(self, param): return self.params.get(param, None) def get_param(self, param): g = self.params.get(param, None) return g.read() if g else None def set_param(self, param, value): g = self.params.get(param, None) return g.write(value) if g else None class Backlight: """Information about the current settings of x1982 Backlight2 v3, but also works for previous versions""" def __init__(self, device): response = device.feature_request(SupportedFeature.BACKLIGHT2, 0x00) if not response: raise exceptions.FeatureCallError(msg="No reply from device.") self.device = device self.enabled, self.options, supported, effects, self.level, self.dho, self.dhi, self.dpow = struct.unpack( "> 3) & 0x03 def write(self): self.options = (self.options & 0x07) | (self.mode << 3) level = self.level if self.mode == 0x3 else 0 data_bytes = struct.pack(" Button: behavior = bytes_[0] >> 4 if behavior == ButtonBehavior.MACRO_EXECUTE or behavior == ButtonBehavior.MACRO_STOP: sector = ((bytes_[0] & 0x0F) << 8) + bytes_[1] address = (bytes_[2] << 8) + bytes_[3] result = cls(behavior=behavior, sector=sector, address=address) elif behavior == ButtonBehavior.SEND: try: mapping_type = ButtonMappingType(bytes_[1]).value if mapping_type == ButtonMappingType.BUTTON: value = ButtonButtons[(bytes_[2] << 8) + bytes_[3]] result = cls(behavior=behavior, type=mapping_type, value=value) elif mapping_type == ButtonMappingType.MODIFIER_AND_KEY: modifiers = bytes_[2] value = ButtonKeys[bytes_[3]] result = cls(behavior=behavior, type=mapping_type, modifiers=modifiers, value=value) elif mapping_type == ButtonMappingType.CONSUMER_KEY: value = ButtonConsumerKeys[(bytes_[2] << 8) + bytes_[3]] result = cls(behavior=behavior, type=mapping_type, value=value) elif mapping_type == ButtonMappingType.NO_ACTION: result = cls(behavior=behavior, type=mapping_type) except Exception: pass elif behavior == ButtonBehavior.FUNCTION: second_byte = bytes_[1] try: btn_func = ButtonFunctions(second_byte).value except ValueError: btn_func = second_byte data = bytes_[3] result = cls(behavior=behavior, value=btn_func, data=data) else: result = cls(behavior=bytes_[0] >> 4, bytes=bytes_) return result def to_bytes(self): bytes = common.int2bytes(self.behavior << 4, 1) if self.behavior is not None else None if self.behavior == ButtonBehavior.MACRO_EXECUTE.value or self.behavior == ButtonBehavior.MACRO_STOP.value: bytes = common.int2bytes((self.behavior << 12) + self.sector, 2) + common.int2bytes(self.address, 2) elif self.behavior == ButtonBehavior.SEND.value: bytes += common.int2bytes(self.type, 1) if self.type == ButtonMappingType.BUTTON: bytes += common.int2bytes(self.value, 2) elif self.type == ButtonMappingType.MODIFIER_AND_KEY: bytes += common.int2bytes(self.modifiers, 1) bytes += common.int2bytes(self.value, 1) elif self.type == ButtonMappingType.CONSUMER_KEY: bytes += common.int2bytes(self.value, 2) elif self.type == ButtonMappingType.NO_ACTION: bytes += b"\xff\xff" elif self.behavior == ButtonBehavior.FUNCTION: data = common.int2bytes(self.data, 1) if self.data else b"\x00" bytes += common.int2bytes(self.value, 1) + b"\xff" + data else: bytes = self.bytes if self.bytes else b"\xff\xff\xff\xff" return bytes def __repr__(self): return "%s{%s}" % ( self.__class__.__name__, ", ".join([f"{str(key)}:{str(val)}" for key, val in self.__dict__.items()]), ) yaml.SafeLoader.add_constructor("!Button", Button.from_yaml) yaml.add_representer(Button, Button.to_yaml) class OnboardProfile: """A single onboard profile""" def __init__(self, **kwargs): for key, val in kwargs.items(): setattr(self, key, val) @classmethod def from_yaml(cls, loader, node): args = loader.construct_mapping(node) return cls(**args) @classmethod def to_yaml(cls, dumper, data): return dumper.represent_mapping("!OnboardProfile", data.__dict__) @classmethod def from_bytes(cls, sector, enabled, buttons, gbuttons, bytes): return cls( sector=sector, enabled=enabled, report_rate=bytes[0], resolution_default_index=bytes[1], resolution_shift_index=bytes[2], resolutions=[struct.unpack(" list[tuple[int, int]]: """Returns profile headers. Returns ------- list[tuple[int, int]] Tuples contain (sector, enabled). """ i = 0 headers = [] chunk = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, 0, 0, 0, i) s = 0x00 if chunk[0:4] == b"\x00\x00\x00\x00" or chunk[0:4] == b"\xff\xff\xff\xff": # look in ROM instead chunk = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, 0x01, 0, 0, i) s = 0x01 while chunk[0:2] != b"\xff\xff": sector, enabled = struct.unpack("!HB", chunk[0:3]) headers.append((sector, enabled)) i += 1 chunk = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, s, 0, 0, i * 4) return headers @classmethod def from_device(cls, device): if not device.online: # wake the device up if necessary device.ping() response = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x00) memory, profile, _macro = struct.unpack("!BBB", response[0:3]) if memory != 0x01 or profile > 0x05: return count, oob, buttons, sectors, size, shift = struct.unpack("!BBBBHB", response[3:10]) gbuttons = buttons if (shift & 0x3 == 0x2) else 0 headers = OnboardProfiles.get_profile_headers(device) profiles = {} for i, (sector, enabled) in enumerate(headers, start=1): profiles[i] = OnboardProfile.from_dev(device, i, sector, size, enabled, buttons, gbuttons) return cls( version=OnboardProfilesVersion, name=device.name, count=count, buttons=buttons, gbuttons=gbuttons, sectors=sectors, size=size, profiles=profiles, ) def to_bytes(self): bytes = b"" for i in range(1, len(self.profiles) + 1): profiles_sector = common.int2bytes(self.profiles[i].sector, 2) profiles_enabled = common.int2bytes(self.profiles[i].enabled, 1) bytes += profiles_sector + profiles_enabled + b"\x00" bytes += b"\xff\xff\x00\x00" # marker after last profile while len(bytes) < self.size - 2: # leave room for CRC bytes += b"\xff" bytes += common.int2bytes(common.crc16(bytes), 2) return bytes @classmethod def read_sector(cls, dev, sector, s): # doesn't check for valid sector or size bytes = b"" o = 0 while o < s - 15: chunk = dev.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x50, sector >> 8, sector & 0xFF, o >> 8, o & 0xFF) bytes += chunk o += 16 chunk = dev.feature_request( SupportedFeature.ONBOARD_PROFILES, 0x50, sector >> 8, sector & 0xFF, (s - 16) >> 8, (s - 16) & 0xFF, ) bytes += chunk[16 + o - s :] # the last chunk has to be read in an awkward way return bytes @classmethod def write_sector(cls, device, s, bs): # doesn't check for valid sector or size rbs = OnboardProfiles.read_sector(device, s, len(bs)) if rbs[:-2] == bs[:-2]: return False device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x60, s >> 8, s & 0xFF, 0, 0, len(bs) >> 8, len(bs) & 0xFF) o = 0 while o < len(bs) - 1: device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x70, bs[o : o + 16]) o += 16 device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x80) return True def write(self, device): try: written = 1 if OnboardProfiles.write_sector(device, 0, self.to_bytes()) else 0 except Exception as e: logger.warning("Exception writing onboard profile control sector") raise e for p in self.profiles.values(): try: if p.sector >= self.sectors: raise Exception(f"Sector {p.sector} not a writable sector") written += 1 if OnboardProfiles.write_sector(device, p.sector, p.to_bytes(self.size)) else 0 except Exception as e: logger.warning(f"Exception writing onboard profile sector {p.sector}") raise e return written def show(self): print(yaml.dump(self)) yaml.SafeLoader.add_constructor("!OnboardProfiles", OnboardProfiles.from_yaml) yaml.add_representer(OnboardProfiles, OnboardProfiles.to_yaml) def feature_request(device, feature, function=0x00, *params, no_reply=False): if device.online and device.features: if feature in device.features: feature_index = device.features[feature] return device.request((feature_index << 8) + (function & 0xFF), *params, no_reply=no_reply) if logger.isEnabledFor(logging.WARN): logger.warning( "%s: feature request failure for device online %s and features %s", device, device.online, device.features ) class Hidpp20: # Host-side counter for SetComplete cookies (see set_configuration_complete). # Seeded to a non-zero random 16-bit value at import so successive sessions # don't trivially collide; we just need to never send 0x0000. _session_cookie = getrandbits(16) or 1 def get_firmware(self, device) -> tuple[common.FirmwareInfo] | None: """Reads a device's firmware info. :returns: a list of FirmwareInfo tuples, ordered by firmware layer. """ count = device.feature_request(SupportedFeature.DEVICE_FW_VERSION) if count: count = ord(count[:1]) fw = [] for index in range(0, count): fw_info = device.feature_request(SupportedFeature.DEVICE_FW_VERSION, 0x10, index) if fw_info: level = ord(fw_info[:1]) & 0x0F if level == 0 or level == 1: name, version_major, version_minor, build = struct.unpack("!3sBBH", fw_info[1:8]) version = f"{version_major:02X}.{version_minor:02X}" if build: version += f".B{build:04X}" extras = fw_info[9:].rstrip(b"\x00") or None fw_info = common.FirmwareInfo(FirmwareKind(level), name.decode("ascii"), version, extras) elif level == FirmwareKind.Hardware: fw_info = common.FirmwareInfo(FirmwareKind.Hardware, "", str(ord(fw_info[1:2])), None) else: fw_info = common.FirmwareInfo(FirmwareKind.Other, "", "", None) fw.append(fw_info) return tuple(fw) def get_firmware_centurion(self, device): return _centurion.get_firmware_centurion(device) def get_serial_centurion(self, device): return _centurion.get_serial_centurion(device) def get_hardware_info_centurion(self, device): return _centurion.get_hardware_info_centurion(device) def _centurion_sub_device_info_request(self, device, function=0x00, *params): return _centurion._centurion_sub_device_info_request(device, function, *params) def get_firmware_centurion_sub(self, device): return _centurion.get_firmware_centurion_sub(device) def get_serial_centurion_sub(self, device): return _centurion.get_serial_centurion_sub(device) def get_hardware_info_centurion_sub(self, device): return _centurion.get_hardware_info_centurion_sub(device) def get_ids(self, device): """Reads a device's ids (unit and model numbers)""" ids = device.feature_request(SupportedFeature.DEVICE_FW_VERSION) if ids: unitId = ids[1:5] modelId = ids[7:13] transport_bits = ord(ids[6:7]) offset = 0 tid_map = {} for transport, flag in [("btid", 0x1), ("btleid", 0x02), ("wpid", 0x04), ("usbid", 0x08)]: if transport_bits & flag: tid_map[transport] = modelId[offset : offset + 2].hex().upper() offset = offset + 2 return unitId.hex().upper(), modelId.hex().upper(), tid_map def get_kind(self, device: Device): """Reads a device's type. :see DEVICE_KIND: :returns: a string describing the device type, or ``None`` if the device is not available or does not support the ``DEVICE_NAME`` feature. """ kind = device.feature_request(SupportedFeature.DEVICE_NAME, 0x20) if kind: kind = ord(kind[:1]) try: return KIND_MAP[DEVICE_KIND[kind]] except Exception: return None def get_name(self, device: Device): """Reads a device's name. :returns: a string with the device name, or ``None`` if the device is not available or does not support the ``DEVICE_NAME`` feature. """ name_length = device.feature_request(SupportedFeature.DEVICE_NAME) if name_length: name_length = ord(name_length[:1]) name = b"" while len(name) < name_length: fragment = device.feature_request(SupportedFeature.DEVICE_NAME, 0x10, len(name)) if fragment: name += fragment[: name_length - len(name)] else: logger.error("failed to read whole name of %s (expected %d chars)", device, name_length) return None return name.decode("utf-8") def get_name_centurion(self, device): return _centurion.get_name_centurion(device) def get_friendly_name(self, device: Device): """Reads a device's friendly name. :returns: a string with the device name, or ``None`` if the device is not available or does not support the ``DEVICE_NAME`` feature. """ name_length = device.feature_request(SupportedFeature.DEVICE_FRIENDLY_NAME) if name_length: name_length = ord(name_length[:1]) name = b"" while len(name) < name_length: fragment = device.feature_request(SupportedFeature.DEVICE_FRIENDLY_NAME, 0x10, len(name)) if fragment: name += fragment[1 : name_length - len(name) + 1] else: logger.error("failed to read whole name of %s (expected %d chars)", device, name_length) return None return name.decode("utf-8") def get_battery_status(self, device: Device): report = device.feature_request(SupportedFeature.BATTERY_STATUS) if report: return decipher_battery_status(report) def get_battery_unified(self, device: Device): report = device.feature_request(SupportedFeature.UNIFIED_BATTERY, 0x10) if report is not None: return decipher_battery_unified(report) def get_battery_voltage(self, device: Device): report = device.feature_request(SupportedFeature.BATTERY_VOLTAGE) if report is not None: return decipher_battery_voltage(report) def get_adc_measurement(self, device: Device): try: # this feature call produces an error for headsets that are connected but inactive report = device.feature_request(SupportedFeature.ADC_MEASUREMENT) if report is not None: return decipher_adc_measurement(report) except exceptions.FeatureCallError: return SupportedFeature.ADC_MEASUREMENT if SupportedFeature.ADC_MEASUREMENT in device.features else None def get_battery_centurion(self, device: Device): return _centurion.get_battery_centurion(device) def get_battery(self, device, feature): """Return battery information - feature, approximate level, next, charging, voltage or battery feature if there is one but it is not responding or None for no battery feature""" if feature is not None: battery_function = battery_functions.get(feature, None) if battery_function: result = battery_function(self, device) if result: return result else: for battery_function in battery_functions.values(): result = battery_function(self, device) if result: return result return 0 def get_keys(self, device: Device): # TODO: add here additional variants for other REPROG_CONTROLS count = None if device.features and SupportedFeature.REPROG_CONTROLS_V2 in device.features: count = device.feature_request(SupportedFeature.REPROG_CONTROLS_V2) return KeysArrayV2(device, ord(count[:1])) elif device.features and SupportedFeature.REPROG_CONTROLS_V4 in device.features: count = device.feature_request(SupportedFeature.REPROG_CONTROLS_V4) return KeysArrayV4(device, ord(count[:1])) return None def get_remap_keys(self, device: Device): count = device.feature_request(SupportedFeature.PERSISTENT_REMAPPABLE_ACTION, 0x10) if count: return KeysArrayPersistent(device, ord(count[:1])) def get_gestures(self, device: Device): if getattr(device, "_gestures", None) is not None: return device._gestures if SupportedFeature.GESTURE_2 in device.features: return Gestures(device) def get_backlight(self, device: Device): if getattr(device, "_backlight", None) is not None: return device._backlight if SupportedFeature.BACKLIGHT2 in device.features: return Backlight(device) def get_force_buttons(self, device: Device): if getattr(device, "_force_buttons", None) is not None: return device._force_buttons if SupportedFeature.FORCE_SENSING_BUTTON in device.features: return ForceSensingButtonArray(device) def get_profiles(self, device: Device): if getattr(device, "_profiles", None) is not None: return device._profiles if SupportedFeature.ONBOARD_PROFILES in device.features: return OnboardProfiles.from_device(device) def get_mouse_pointer_info(self, device: Device): pointer_info = device.feature_request(SupportedFeature.MOUSE_POINTER) if pointer_info: dpi, flags = struct.unpack("!HB", pointer_info[:3]) acceleration = ("none", "low", "med", "high")[flags & 0x3] suggest_os_ballistics = (flags & 0x04) != 0 suggest_vertical_orientation = (flags & 0x08) != 0 return { "dpi": dpi, "acceleration": acceleration, "suggest_os_ballistics": suggest_os_ballistics, "suggest_vertical_orientation": suggest_vertical_orientation, } def get_vertical_scrolling_info(self, device: Device): vertical_scrolling_info = device.feature_request(SupportedFeature.VERTICAL_SCROLLING) if vertical_scrolling_info: roller, ratchet, lines = struct.unpack("!BBB", vertical_scrolling_info[:3]) roller_type = ( "reserved", "standard", "reserved", "3G", "micro", "normal touch pad", "inverted touch pad", "reserved", )[roller] return {"roller": roller_type, "ratchet": ratchet, "lines": lines} def get_hi_res_scrolling_info(self, device: Device): hi_res_scrolling_info = device.feature_request(SupportedFeature.HI_RES_SCROLLING) if hi_res_scrolling_info: mode, resolution = struct.unpack("!BB", hi_res_scrolling_info[:2]) return mode, resolution def get_pointer_speed_info(self, device: Device): pointer_speed_info = device.feature_request(SupportedFeature.POINTER_SPEED) if pointer_speed_info: pointer_speed_hi, pointer_speed_lo = struct.unpack("!BB", pointer_speed_info[:2]) # if pointer_speed_lo > 0: # pointer_speed_lo = pointer_speed_lo return pointer_speed_hi + pointer_speed_lo / 256 def get_lowres_wheel_status(self, device: Device): lowres_wheel_status = device.feature_request(SupportedFeature.LOWRES_WHEEL) if lowres_wheel_status: wheel_flag = struct.unpack("!B", lowres_wheel_status[:1])[0] wheel_reporting = ("HID", "HID++")[wheel_flag & 0x01] return wheel_reporting def get_hires_wheel(self, device: Device): caps = device.feature_request(SupportedFeature.HIRES_WHEEL, 0x00) mode = device.feature_request(SupportedFeature.HIRES_WHEEL, 0x10) ratchet = device.feature_request(SupportedFeature.HIRES_WHEEL, 0x030) if caps and mode and ratchet: # Parse caps multi, flags = struct.unpack("!BB", caps[:2]) has_invert = (flags & 0x08) != 0 has_ratchet = (flags & 0x04) != 0 # Parse mode wheel_mode, reserved = struct.unpack("!BB", mode[:2]) target = (wheel_mode & 0x01) != 0 res = (wheel_mode & 0x02) != 0 inv = (wheel_mode & 0x04) != 0 # Parse Ratchet switch ratchet_mode, reserved = struct.unpack("!BB", ratchet[:2]) ratchet = (ratchet_mode & 0x01) != 0 return multi, has_invert, has_ratchet, inv, res, target, ratchet def get_new_fn_inversion(self, device: Device): state = device.feature_request(SupportedFeature.NEW_FN_INVERSION, 0x00) if state: inverted, default_inverted = struct.unpack("!BB", state[:2]) inverted = (inverted & 0x01) != 0 default_inverted = (default_inverted & 0x01) != 0 return inverted, default_inverted def get_host_names(self, device: Device): state = device.feature_request(SupportedFeature.HOSTS_INFO, 0x00) host_names = {} if state: capability_flags, _ignore, numHosts, currentHost = struct.unpack("!BBBB", state[:4]) if capability_flags & 0x01: # device can get host names for host in range(0, numHosts): hostinfo = device.feature_request(SupportedFeature.HOSTS_INFO, 0x10, host) _ignore, status, _ignore, _ignore, nameLen, _ignore = struct.unpack("!BBBBBB", hostinfo[:6]) name = "" remaining = nameLen while remaining > 0: name_piece = device.feature_request(SupportedFeature.HOSTS_INFO, 0x30, host, nameLen - remaining) if name_piece: name += name_piece[2 : 2 + min(remaining, 14)].decode() remaining = max(0, remaining - 14) else: remaining = 0 host_names[host] = (bool(status), name) if host_names: # update the current host's name if it doesn't match the system name hostname = socket.gethostname().partition(".")[0] if host_names[currentHost][1] != hostname: self.set_host_name(device, hostname, host_names[currentHost][1]) host_names[currentHost] = (host_names[currentHost][0], hostname) return host_names def set_host_name(self, device: Device, name, currentName=""): name = bytearray(name, "utf-8") currentName = bytearray(currentName, "utf-8") if logger.isEnabledFor(logging.INFO): logger.info("Setting host name to %s", name) state = device.feature_request(SupportedFeature.HOSTS_INFO, 0x00) if state: flags, _ignore, _ignore, currentHost = struct.unpack("!BBBB", state[:4]) if flags & 0x02: hostinfo = device.feature_request(SupportedFeature.HOSTS_INFO, 0x10, currentHost) _ignore, _ignore, _ignore, _ignore, _ignore, maxNameLen = struct.unpack("!BBBBBB", hostinfo[:6]) if name[:maxNameLen] == currentName[:maxNameLen] and False: return True length = min(maxNameLen, len(name)) chunk = 0 while chunk < length: response = device.feature_request( SupportedFeature.HOSTS_INFO, 0x40, currentHost, chunk, name[chunk : chunk + 14] ) if not response: return False chunk += 14 return True def get_onboard_mode(self, device: Device): state = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x20) if state: mode = struct.unpack("!B", state[:1])[0] return mode def set_onboard_mode(self, device: Device, mode): state = device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x10, mode) return state def get_polling_rate(self, device: Device): state = device.feature_request(SupportedFeature.REPORT_RATE, 0x10) if state: rate = struct.unpack("!B", state[:1])[0] return f"{str(rate)}ms" else: rates = ["8ms", "4ms", "2ms", "1ms", "500us", "250us", "125us"] state = device.feature_request(SupportedFeature.EXTENDED_ADJUSTABLE_REPORT_RATE, 0x20) if state: rate = struct.unpack("!B", state[:1])[0] return rates[rate] def get_remaining_pairing(self, device: Device): result = device.feature_request(SupportedFeature.REMAINING_PAIRING, 0x0) if result: result = struct.unpack("!B", result[:1])[0] SupportedFeature._fallback = lambda x: f"unknown:{x:04X}" return result def get_keyboard_layout(self, device: Device): """Return the device's keyboard layout country code, or None. Country code semantics match the HID HUT keyboard country codes that Logitech's KEYBOARD_LAYOUT_2 (0x4540) feature reports in the first byte. Used by the per-key painter to pick the matching regional layout. """ result = device.feature_request(SupportedFeature.KEYBOARD_LAYOUT_2, 0x00) if result: return struct.unpack("!B", result[:1])[0] return None def get_configuration_cookie(self, device: Device): """ConfigChange (0x0020) GetCookie — read the device's current configuration cookie.""" response = device.feature_request(SupportedFeature.CONFIG_CHANGE, 0x00) return response[:2] if response else None def next_session_cookie(self): """Bump and return the host-side counter used as the SetComplete cookie.""" Hidpp20._session_cookie = (Hidpp20._session_cookie + 1) & 0xFFFF or 1 return bytes([Hidpp20._session_cookie >> 8, Hidpp20._session_cookie & 0xFF]) def set_configuration_complete(self, device: Device, cookie=None, no_reply=False): """ConfigChange (0x0020) SetComplete — acknowledge host has synced with device configuration. Sends a host-side monotonic counter, incremented per call and always non-zero. Cookie 0x0000 has been observed to release the SW effect-engine claim on at least the G515 LS TKL; we avoid it.""" if cookie is None: cookie = self.next_session_cookie() if cookie and len(cookie) >= 2: return device.feature_request(SupportedFeature.CONFIG_CHANGE, 0x10, cookie[0], cookie[1], no_reply=no_reply) def config_change(self, device: Device, configuration, no_reply=False): """Deprecated — use set_configuration_complete() instead.""" return device.feature_request(SupportedFeature.CONFIG_CHANGE, 0x10, configuration, no_reply=no_reply) battery_functions = { SupportedFeature.BATTERY_STATUS: Hidpp20.get_battery_status, SupportedFeature.BATTERY_VOLTAGE: Hidpp20.get_battery_voltage, SupportedFeature.UNIFIED_BATTERY: Hidpp20.get_battery_unified, SupportedFeature.ADC_MEASUREMENT: Hidpp20.get_adc_measurement, SupportedFeature.CENTURION_BATTERY_SOC: Hidpp20.get_battery_centurion, } def decipher_battery_status(report: FixedBytes5) -> Tuple[Any, Battery]: battery_discharge_level, battery_discharge_next_level, battery_status = struct.unpack("!BBB", report[:3]) if battery_discharge_level == 0: battery_discharge_level = None try: status = BatteryStatus(battery_status) except ValueError: status = None logger.debug(f"Unknown battery status byte 0x{battery_status:02X}") if logger.isEnabledFor(logging.DEBUG): logger.debug( "battery status %s%% charged, next %s%%, status %s", battery_discharge_level, battery_discharge_next_level, status ) return SupportedFeature.BATTERY_STATUS, Battery(battery_discharge_level, battery_discharge_next_level, status, None) def decipher_battery_voltage(report: bytes): voltage, flags = struct.unpack(">HB", report[:3]) status = BatteryStatus.DISCHARGING charge_sts = ErrorCode.UNKNOWN charge_lvl = ChargeLevel.AVERAGE charge_type = ChargeType.STANDARD if flags & (1 << 7): status = BatteryStatus.RECHARGING charge_sts = ChargeStatus(flags & 0x03) if charge_sts is None: charge_sts = ErrorCode.UNKNOWN elif isinstance(charge_sts, ChargeStatus) and ChargeStatus.FULL in charge_sts: charge_lvl = ChargeLevel.FULL status = BatteryStatus.FULL if flags & (1 << 3): charge_type = ChargeType.FAST elif flags & (1 << 4): charge_type = ChargeType.SLOW status = BatteryStatus.SLOW_RECHARGE elif flags & (1 << 5): charge_lvl = ChargeLevel.CRITICAL charge_level = estimate_battery_level_percentage(voltage) if charge_level: charge_lvl = charge_level if logger.isEnabledFor(logging.DEBUG): logger.debug( "battery voltage %d mV, charging %s, status %d = %s, level %s, type %s", voltage, status, (flags & 0x03), charge_sts, charge_lvl, charge_type, ) return SupportedFeature.BATTERY_VOLTAGE, Battery(charge_lvl, None, status, voltage) def decipher_battery_unified(report) -> tuple[SupportedFeature, Battery]: discharge, level, status_byte, _ignore = struct.unpack("!BBBB", report[:4]) try: status = BatteryStatus(status_byte) except ValueError: status = None logger.debug(f"Unknown battery status byte 0x{status_byte:02X}") if logger.isEnabledFor(logging.DEBUG): logger.debug("battery unified %s%% charged, level %s, charging %s", discharge, level, status) if level == 8: approx_level = BatteryLevelApproximation.FULL elif level == 4: approx_level = BatteryLevelApproximation.GOOD elif level == 2: approx_level = BatteryLevelApproximation.LOW elif level == 1: approx_level = BatteryLevelApproximation.CRITICAL else: approx_level = BatteryLevelApproximation.EMPTY return SupportedFeature.UNIFIED_BATTERY, Battery(discharge if discharge else approx_level, None, status, None) decipher_battery_centurion = _centurion.decipher_battery_centurion def decipher_adc_measurement(report) -> tuple[SupportedFeature, Battery]: # partial implementation - needs mapping to levels adc_voltage, flags = struct.unpack("!HB", report[:3]) charge_level = estimate_battery_level_percentage(adc_voltage) if flags & 0x01: status = BatteryStatus.RECHARGING if flags & 0x02 else BatteryStatus.DISCHARGING return SupportedFeature.ADC_MEASUREMENT, Battery(charge_level, None, status, adc_voltage) def estimate_battery_level_percentage(value_millivolt: int) -> int | None: """Estimate battery level percentage based on battery voltage. Uses linear approximation to estimate the battery level in percent. Parameters ---------- value_millivolt Measured battery voltage in millivolt. """ battery_voltage_to_percentage = [ (4186, 100), (4067, 90), (3989, 80), (3922, 70), (3859, 60), (3811, 50), (3778, 40), (3751, 30), (3717, 20), (3671, 10), (3646, 5), (3579, 2), (3500, 0), ] if value_millivolt >= battery_voltage_to_percentage[0][0]: return battery_voltage_to_percentage[0][1] if value_millivolt <= battery_voltage_to_percentage[-1][0]: return battery_voltage_to_percentage[-1][1] for i in range(len(battery_voltage_to_percentage) - 1): v_high, p_high = battery_voltage_to_percentage[i] v_low, p_low = battery_voltage_to_percentage[i + 1] if v_low <= value_millivolt <= v_high: # Linear interpolation percent = p_low + (p_high - p_low) * (value_millivolt - v_low) / (v_high - v_low) return round(percent) return 0 class ForceSensingButton: """A button that has a force value at which to trigger the button""" @classmethod def create(cls, device, number: int): buttondata = device.feature_request(SupportedFeature.FORCE_SENSING_BUTTON, 0x10, number) buttoncurrent = device.feature_request(SupportedFeature.FORCE_SENSING_BUTTON, 0x20, number) if buttondata is not None and buttoncurrent is not None: changeable, default, max_value, min_value = struct.unpack("!HHHH", buttondata[:8]) changeable = changeable & 0x01 current = struct.unpack("!H", buttoncurrent[:2])[0] return cls(device, number, changeable, default, max_value, min_value, current) def __init__(self, device, number: int, changeable: bool, default: int, max_value: int, min_value: int, current: int): self._device = device self.number = number self.changeable = changeable self.default = default self.min_value = min_value self.max_value = max_value self._current = current def get_current(self) -> int: return self._current def set_current(self, current: int) -> None: if not self.changeable: logger.warning(f"FORCE_SENSING_BUTTON on device {self._device} does not allow changing force.") if self.min_value <= current <= self.max_value: ret = self._device.feature_request( SupportedFeature.FORCE_SENSING_BUTTON, 0x30, struct.pack("!BH", self.number, current) ) if ret is None and logger.isEnabledFor(logging.DEBUG): logger.debug(f"FORCE_SENSING_BUTTON setButtonConfig on device {self._device} didn't respond.") def acceptable_current(self, value: int) -> bool: return self.min_value <= value <= self.max_value class ForceSensingButtonArray(UserDict): """A map of buttons supporting force sensing""" def __new__(cls, device: Device): assert device is not None count = device.feature_request(SupportedFeature.FORCE_SENSING_BUTTON, 0x00) if count: instance = super().__new__(cls) instance._count = ord(count[:1]) return instance def __init__(self, device: Device): super().__init__(self) self.device = device for index in range(0, self._count): self[index] = None def __getitem__(self, index: int): item = super().__getitem__(index) if item is None: self.query_key(index) return super().__getitem__(index) def query_key(self, index): if index not in self: raise IndexError(index) button = ForceSensingButton.create(self.device, index) if button: self[index] = button return button def query(self): for index in self: button = ForceSensingButton.create(self.device, index) if button: self[index] = button return self # interface for single force button def get_current(self): return self[0].get_current() def set_current(self, current: int) -> None: self[0].set_current(current) def acceptable(self, value: int) -> bool: return self[0].acceptable(value) def acceptable_current_key(self, index: int, value: int) -> bool: return self[index].acceptable(value) # --- OnboardEQ (0x0636) — re-exported from onboard_eq.py --- # --- AdvancedParaEQ (0x020D) — re-exported from advanced_para_eq.py --- from .advanced_para_eq import FILTER_TYPE_HP # noqa: E402, F401 from .advanced_para_eq import FILTER_TYPE_PEAKING # noqa: E402, F401 from .advanced_para_eq import FILTER_TYPE_PEAKING_G522 # noqa: E402, F401 from .advanced_para_eq import get_advanced_eq_active_slot # noqa: E402, F401 from .advanced_para_eq import get_advanced_eq_defaults # noqa: E402, F401 from .advanced_para_eq import get_advanced_eq_friendly_name # noqa: E402, F401 from .advanced_para_eq import get_advanced_eq_info # noqa: E402, F401 from .advanced_para_eq import get_advanced_eq_params # noqa: E402, F401 from .advanced_para_eq import parse_v2_bands # noqa: E402, F401 from .advanced_para_eq import probe_advanced_eq_slots # noqa: E402, F401 from .advanced_para_eq import probe_all_presets as probe_advanced_eq_presets # noqa: E402, F401 from .onboard_eq import _build_set_eq_payload # noqa: E402, F401 from .onboard_eq import get_onboard_eq_info # noqa: E402, F401 from .onboard_eq import get_onboard_eq_params # noqa: E402, F401 from .onboard_eq import set_onboard_eq_params # noqa: E402, F401 Solaar-1.1.20/lib/logitech_receiver/hidpp20_constants.py000066400000000000000000000263201522022367600231700ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from enum import IntEnum from enum import IntFlag from .common import NamedInts # /,/p}' | sort -t= -k2 # additional features names taken from https://github.com/cvuchener/hidpp and # https://github.com/Logitech/cpg-docs/tree/master/hidpp20 """Possible features available on a Logitech device. A particular device might not support all these features, and may support other unknown features as well. """ class SupportedFeature(IntEnum): ROOT = 0x0000 FEATURE_SET = 0x0001 FEATURE_INFO = 0x0002 # Common DEVICE_FW_VERSION = 0x0003 DEVICE_UNIT_ID = 0x0004 DEVICE_NAME = 0x0005 DEVICE_GROUPS = 0x0006 DEVICE_FRIENDLY_NAME = 0x0007 KEEP_ALIVE = 0x0008 PROPERTY_ACCESS = 0x0011 CONFIG_CHANGE = 0x0020 CRYPTO_ID = 0x0021 TARGET_SOFTWARE = 0x0030 WIRELESS_SIGNAL_STRENGTH = 0x0080 DFUCONTROL_LEGACY = 0x00C0 DFUCONTROL_UNSIGNED = 0x00C1 DFUCONTROL_SIGNED = 0x00C2 DFUCONTROL = 0x00C3 DFU = 0x00D0 BATTERY_STATUS = 0x1000 BATTERY_VOLTAGE = 0x1001 UNIFIED_BATTERY = 0x1004 CHARGING_CONTROL = 0x1010 LED_CONTROL = 0x1300 FORCE_PAIRING = 0x1500 GENERIC_TEST = 0x1800 DEVICE_RESET = 0x1802 OOBSTATE = 0x1805 CONFIG_DEVICE_PROPS = 0x1806 CHANGE_HOST = 0x1814 HOSTS_INFO = 0x1815 BLE_PRO_PRE_PAIRING = 0x1816 BACKLIGHT = 0x1981 BACKLIGHT2 = 0x1982 BACKLIGHT3 = 0x1983 ILLUMINATION = 0x1990 FORCE_SENSING_BUTTON = 0x19C0 HAPTIC = 0x19B0 PRESENTER_CONTROL = 0x1A00 SENSOR_3D = 0x1A01 REPROG_CONTROLS = 0x1B00 REPROG_CONTROLS_V2 = 0x1B01 REPROG_CONTROLS_V2_2 = 0x1B02 # LogiOptions 2.10.73 features.xml REPROG_CONTROLS_V3 = 0x1B03 REPROG_CONTROLS_V4 = 0x1B04 ANALOG_BUTTONS = 0x1B0C # Analog button tuning (actuation point, rapid trigger, haptics) FULL_KEY_CUSTOMIZATION = 0x1B05 CONTROL_LIST = 0x1B10 SWITCH_SWAPABILITY = 0x1B20 DEVICE_MODE = 0x1B30 REPORT_HID_USAGE = 0x1BC0 PERSISTENT_REMAPPABLE_ACTION = 0x1C00 WIRELESS_DEVICE_STATUS = 0x1D4B REMAINING_PAIRING = 0x1DF0 ENABLE_HIDDEN_FEATURES = 0x1E00 FIRMWARE_PROPERTIES = 0x1F1F ADC_MEASUREMENT = 0x1F20 # Mouse LEFT_RIGHT_SWAP = 0x2001 SWAP_BUTTON_CANCEL = 0x2005 POINTER_AXIS_ORIENTATION = 0x2006 VERTICAL_SCROLLING = 0x2100 SMART_SHIFT = 0x2110 SMART_SHIFT_ENHANCED = 0x2111 HI_RES_SCROLLING = 0x2120 HIRES_WHEEL = 0x2121 LOWRES_WHEEL = 0x2130 THUMB_WHEEL = 0x2150 MOUSE_POINTER = 0x2200 ADJUSTABLE_DPI = 0x2201 EXTENDED_ADJUSTABLE_DPI = 0x2202 POINTER_SPEED = 0x2205 ANGLE_SNAPPING = 0x2230 SURFACE_TUNING = 0x2240 XY_STATS = 0x2250 WHEEL_STATS = 0x2251 HYBRID_TRACKING = 0x2400 # Keyboard FN_INVERSION = 0x40A0 NEW_FN_INVERSION = 0x40A2 K375S_FN_INVERSION = 0x40A3 ENCRYPTION = 0x4100 LOCK_KEY_STATE = 0x4220 SOLAR_DASHBOARD = 0x4301 KEYBOARD_LAYOUT = 0x4520 KEYBOARD_DISABLE_KEYS = 0x4521 KEYBOARD_DISABLE_BY_USAGE = 0x4522 KEYBOARD_DISABLE_CONTROLS = 0x4523 DUALPLATFORM = 0x4530 MULTIPLATFORM = 0x4531 KEYBOARD_LAYOUT_2 = 0x4540 CROWN = 0x4600 # Touchpad TOUCHPAD_FW_ITEMS = 0x6010 TOUCHPAD_SW_ITEMS = 0x6011 TOUCHPAD_WIN8_FW_ITEMS = 0x6012 TAP_ENABLE = 0x6020 TAP_ENABLE_EXTENDED = 0x6021 CURSOR_BALLISTIC = 0x6030 TOUCHPAD_RESOLUTION = 0x6040 TOUCHPAD_RAW_XY = 0x6100 TOUCHMOUSE_RAW_POINTS = 0x6110 TOUCHMOUSE_6120 = 0x6120 GESTURE = 0x6500 GESTURE_2 = 0x6501 # Gaming Devices GKEY = 0x8010 MKEYS = 0x8020 MR = 0x8030 BRIGHTNESS_CONTROL = 0x8040 LOGI_MODIFIERS = 0x8051 REPORT_RATE = 0x8060 EXTENDED_ADJUSTABLE_REPORT_RATE = 0x8061 COLOR_LED_EFFECTS = 0x8070 RGB_EFFECTS = 0x8071 RPM_INDICATOR = 0x807A RPM_LED_PATTERN = 0x807B PER_KEY_LIGHTING = 0x8080 PER_KEY_LIGHTING_V2 = 0x8081 MODE_STATUS = 0x8090 LEGACY_AXIS_RESPONSE_CURVE = 0x80A3 AXIS_RESPONSE_CURVE = 0x80A4 BANDED_AXIS = 0x80B1 COMBINED_PEDALS = 0x80D0 BUNNY_HOPPING = 0x80E0 ONBOARD_PROFILES = 0x8100 PROFILE_MANAGEMENT = 0x8101 MOUSE_BUTTON_SPY = 0x8110 LATENCY_MONITORING = 0x8111 GAMING_ATTACHMENTS = 0x8120 FORCE_FEEDBACK = 0x8123 DUAL_CLUTCH = 0x8127 WHEEL_CENTER_POSITION = 0x812C DISPLAY_GAME_DATA = 0x8130 CENTER_SPRING = 0x8131 AXIS_MAPPING = 0x8132 GLOBAL_DAMPING = 0x8133 BRAKE_FORCE = 0x8134 PEDAL_STATUS = 0x8135 TORQUE_LIMIT = 0x8136 CONFIGURATION_PROFILES = 0x8137 OPERATING_RANGE = 0x8138 TRUE_FORCE = 0x8139 FFB_FILTER = 0x8140 # Headsets SIDETONE = 0x8300 EQUALIZER = 0x8310 HEADSET_OUT = 0x8320 # Centurion core CENTURION_DEVICE_INFO = 0x0100 CENTURION_DEVICE_NAME = 0x0101 CENTURION_ROOT = 0x0102 CENTURION_MEMFAULT = 0x0103 CENTURION_BATTERY_SOC = 0x0104 CENTURION_AUTO_SLEEP = 0x0108 CENTURION_GENERIC_DFU = 0x010A CENTURION_LED_BRIGHTNESS = 0x0110 CENTURION_EU_POWER_MODE = 0x0115 CENTURION_DEVICE_BOOL_STATE = 0x0116 # Headsets (Centurion-era) HEADSET_VOLUME = 0x0200 HEADSET_EQ = 0x0201 HEADSET_ADVANCED_PARA_EQ = 0x020D HEADSET_MIC_TEST = 0x020E HEADSET_EQ_STYLES = 0x0213 BT_HOST_INFO = 0x0305 LIGHTSPEED_PAIRING = 0x0309 BT_GAMING_MODE = 0x030A HEADSET_RGB_EFFECTS = 0x0600 HEADSET_MIC_MUTE = 0x0601 HEADSET_MIC_SNR = 0x0602 HEADSET_AUDIO_SIDETONE = 0x0604 HEADSET_HOST_SWITCH = 0x0607 HEADSET_MIX = 0x0609 HEADSET_TONES = 0x060B HEADSET_NOISE_EXPOSURE = 0x060D HEADSET_AI_NOISE_REDUCTION = 0x060E HEADSET_MIC_GAIN = 0x0611 HEADSET_USAGE_TRACKING = 0x0617 HEADSET_BATTERY_SAVER = 0x0618 HEADSET_RGB_HOSTMODE = 0x0620 HEADSET_RGB_ONBOARD_EFFECTS = 0x0621 HEADSET_RGB_SIGNATURE_EFFECTS = 0x0622 HEADSET_DO_NOT_DISTURB = 0x0631 CENTURION_ONBOARD_PROFILES = 0x0634 HEADSET_RGB_STREAMING = 0x0635 HEADSET_ONBOARD_EQ = 0x0636 # Audio mixing / LogiVoice MIXER_AUDIO = 0x0800 MIXER_MIC = 0x0801 LOGIVOICE = 0x0900 LOGIVOICE_NOISE_REDUCTION = 0x0901 LOGIVOICE_NOISE_GATE = 0x0902 LOGIVOICE_COMPRESSOR = 0x0903 LOGIVOICE_DE_ESSER = 0x0904 LOGIVOICE_DE_POPPER = 0x0905 LOGIVOICE_LIMITER = 0x0906 LOGIVOICE_HIGH_PASS_FILTER = 0x0907 LOGIVOICE_EQUALIZER = 0x0908 LOGIVOICE_AINR = 0x0909 METERING = 0x0B01 MIC_GAIN_AUTO_MODE = 0x0B02 # Fake features for Solaar internal use MOUSE_GESTURE = 0xFE00 def __str__(self): return self.name.replace("_", " ") class FeatureFlag(IntFlag): """Single bit flags.""" INTERNAL = 0x20 HIDDEN = 0x40 OBSOLETE = 0x80 DEVICE_KIND = NamedInts( keyboard=0x00, remote_control=0x01, numpad=0x02, mouse=0x03, touchpad=0x04, trackball=0x05, presenter=0x06, receiver=0x07, ) class OnboardMode(IntEnum): MODE_NO_CHANGE = 0x00 MODE_ONBOARD = 0x01 MODE_HOST = 0x02 class ChargeLevel(IntEnum): AVERAGE = 50 FULL = 90 CRITICAL = 5 class ChargeType(IntEnum): STANDARD = 0x00 FAST = 0x01 SLOW = 0x02 class ErrorCode(IntEnum): UNKNOWN = 0x01 INVALID_ARGUMENT = 0x02 OUT_OF_RANGE = 0x03 HARDWARE_ERROR = 0x04 LOGITECH_ERROR = 0x05 INVALID_FEATURE_INDEX = 0x06 INVALID_FUNCTION = 0x07 BUSY = 0x08 UNSUPPORTED = 0x09 class GestureId(IntEnum): """Gesture IDs for feature GESTURE_2.""" TAP_1_FINGER = 1 # task Left_Click TAP_2_FINGER = 2 # task Right_Click TAP_3_FINGER = 3 CLICK_1_FINGER = 4 # task Left_Click CLICK_2_FINGER = 5 # task Right_Click CLICK_3_FINGER = 6 DOUBLE_TAP_1_FINGER = 10 DOUBLE_TAP_2_FINGER = 11 DOUBLE_TAP_3_FINGER = 12 TRACK_1_FINGER = 20 # action MovePointer TRACKING_ACCELERATION = 21 TAP_DRAG_1_FINGER = 30 # action Drag TAP_DRAG_2_FINGER = 31 # action SecondaryDrag DRAG_3_FINGER = 32 TAP_GESTURES = 33 # group all tap gestures under a single UI setting FN_CLICK_GESTURE_SUPPRESSION = 34 # suppresses Tap and Edge gestures, toggled by Fn+Click SCROLL_1_FINGER = 40 # action ScrollOrPageXY / ScrollHorizontal SCROLL_2_FINGER = 41 # action ScrollOrPageXY / ScrollHorizontal SCROLL_2_FINGER_HORIZONTAL = 42 # action ScrollHorizontal SCROLL_2_FINGER_VERTICAL = 43 # action WheelScrolling SCROLL_2_FINGER_STATELESS = 44 NATURAL_SCROLLING = 45 # affects native HID wheel reporting by gestures, not when diverted THUMBWHEEL = (46,) # action WheelScrolling V_SCROLL_INTERTIA = 48 V_SCROLL_BALLISTICS = 49 SWIPE_2_FINGER_HORIZONTAL = 50 # action PageScreen SWIPE_3_FINGER_HORIZONTAL = 51 # action PageScreen SWIPE_4_FINGER_HORIZONTAL = 52 # action PageScreen SWIPE_3_FINGER_VERTICAL = 53 SWIPE_4_FINGER_VERTICAL = 54 LEFT_EDGE_SWIPE_1_FINGER = 60 RIGHT_EDGE_SWIPE_1_FINGER = 61 BOTTOM_EDGE_SWIPE_1_FINGER = 62 TOP_EDGE_SWIPE_1_FINGER = 63 LEFT_EDGE_SWIPE_1_FINGER_2 = 64 # task HorzScrollNoRepeatSet RIGHT_EDGE_SWIPE_1_FINGER_2 = 65 BOTTOM_EDGE_SWIPE_1_FINGER_2 = 66 TOP_EDGE_SWIPE_1_FINGER_2 = 67 LEFT_EDGE_SWIPE_2_FINGER = 70 RIGHT_EDGE_SWIPE_2_FINGER = 71 BottomEdgeSwipe2Finger = 72 BOTTOM_EDGE_SWIPE_2_FINGER = 72 TOP_EDGE_SWIPE_2_FINGER = 73 ZOOM_2_FINGER = 80 # action Zoom ZOOM_2_FINGER_PINCH = 81 # ZoomBtnInSet ZOOM_2_FINGER_SPREAD = 82 # ZoomBtnOutSet ZOOM_3_FINGER = 83 ZOOM_2_FINGER_STATELESS = 84 TWO_FINGERS_PRESENT = 85 ROTATE_2_FINGER = 87 FINGER_1 = 90 FINGER_2 = 91 FINGER_3 = 92 FINGER_4 = 93 FINGER_5 = 94 FINGER_6 = 95 FINGER_7 = 96 FINGER_8 = 97 FINGER_9 = 98 FINGER_10 = 99 DEVICE_SPECIFIC_RAW_DATA = 100 class ParamId(IntEnum): """Param Ids for feature GESTURE_2""" EXTRA_CAPABILITIES = 1 # not suitable for use PIXEL_ZONE = 2 # 4 2-byte integers, left, bottom, width, height; pixels RATIO_ZONE = 3 # 4 bytes, left, bottom, width, height; unit 1/240 pad size SCALE_FACTOR = 4 # 2-byte integer, with 256 as normal scale HapticWaveForms = NamedInts( SHARP_STATE_CHANGE=0x00, DAMP_STATE_CHANGE=0x01, SHARP_COLLISION=0x02, DAMP_COLLISION=0x03, SUBTLE_COLLISION=0x04, HAPPY_ALERT=0x05, ANGRY_ALERT=0x06, COMPLETED=0x07, SQUARE=0x08, WAVE=0x09, FIREWORK=0x0A, MAD=0x0B, KNOCK=0x0C, JINGLE=0x0D, RINGING=0xE, WHISPER_COLLISION=0x1B, ) Solaar-1.1.20/lib/logitech_receiver/i18n.py000066400000000000000000000042441522022367600204060ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. # Translation support for the Logitech receivers library import gettext _ = gettext.gettext ngettext = gettext.ngettext # A few common strings, not always accessible as such in the code. _DUMMY = ( # approximative battery levels _("empty"), _("critical"), _("low"), _("average"), _("good"), _("full"), # battery charging statuses _("discharging"), _("recharging"), _("charging"), _("not charging"), _("almost full"), _("charged"), _("slow recharge"), _("invalid battery"), _("thermal error"), _("error"), _("standard"), _("fast"), _("slow"), # pairing errors _("device timeout"), _("device not supported"), _("too many devices"), _("sequence timeout"), # firmware kinds _("Firmware"), _("Bootloader"), _("Hardware"), _("Other"), # common button and task names (from special_keys.py) _("Left Button"), _("Right Button"), _("Middle Button"), _("Back Button"), _("Forward Button"), _("Mouse Gesture Button"), _("Smart Shift"), _("DPI Switch"), _("Left Tilt"), _("Right Tilt"), _("Left Click"), _("Right Click"), _("Mouse Middle Button"), _("Mouse Back Button"), _("Mouse Forward Button"), _("Gesture Button Navigation"), _("Mouse Scroll Left Button"), _("Mouse Scroll Right Button"), # key/button statuses _("pressed"), _("released"), ) Solaar-1.1.20/lib/logitech_receiver/listener.py000066400000000000000000000155061522022367600214570ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import dataclasses import logging import queue import threading from . import base from . import exceptions logger = logging.getLogger(__name__) class _ThreadedHandle: """A thread-local wrapper with different open handles for each thread. Closing a ThreadedHandle will close all handles. """ __slots__ = ("path", "_local", "_handles", "_listener") def __init__(self, listener, path, handle): assert listener is not None assert path is not None assert handle is not None assert isinstance(handle, int) self._listener = listener self.path = path self._local = threading.local() # take over the current handle for the thread doing the replacement self._local.handle = handle self._handles = [handle] def _open(self): handle = base.open_path(self.path) if handle is None: logger.error("%r failed to open new handle", self) else: # if logger.isEnabledFor(logging.DEBUG): # logger.debug("%r opened new handle %d", self, handle) # If original handle was centurion, copy state to new per-thread handle for h in self._handles: if h in base._centurion_handles: base._centurion_handles[handle] = dataclasses.replace(base._centurion_handles[h]) break self._local.handle = handle self._handles.append(handle) return handle def close(self): if self._local: self._local = None handles, self._handles = self._handles, [] if logger.isEnabledFor(logging.DEBUG): logger.debug("%r closing %s", self, handles) for h in handles: base.close(h) @property def notifications_hook(self): if self._listener: assert isinstance(self._listener, threading.Thread) if threading.current_thread() == self._listener: return self._listener._notifications_hook def __del__(self): self._listener = None self.close() def __index__(self): if self._local: try: return self._local.handle except Exception: return self._open() else: return -1 __int__ = __index__ def __str__(self): if self._local: return str(int(self)) else: return "None" def __repr__(self): return f"<_ThreadedHandle({self.path})>" def __bool__(self): return bool(self._local) __nonzero__ = __bool__ # How long to wait during a read for the next packet, in seconds. # Ideally this should be rather long (10s ?), but the read is blocking and this means that when the thread # is signalled to stop, it would take a while for it to acknowledge it. # Forcibly closing the file handle on another thread does _not_ interrupt the read on Linux systems. _EVENT_READ_TIMEOUT = 1.0 # in seconds class EventsListener(threading.Thread): """Listener thread for notifications from the Unifying Receiver. Incoming packets will be passed to the callback function in sequence. """ def __init__(self, receiver, notifications_callback): try: path_name = receiver.path.split("/")[2] except IndexError: path_name = receiver.path super().__init__(name=f"{self.__class__.__name__}:{path_name}") self.daemon = True self._active = False self.receiver = receiver self._queued_notifications = queue.Queue(16) self._notifications_callback = notifications_callback def run(self): self._active = True # replace the handle with a threaded one self.receiver.handle = _ThreadedHandle(self, self.receiver.path, self.receiver.handle) if logger.isEnabledFor(logging.INFO): logger.info("started with %s (%d)", self.receiver, int(self.receiver.handle)) self.has_started() if self.receiver.isDevice: # ping (wired or BT) devices to see if they are really online if self.receiver.ping(): self.receiver.changed(active=True, reason="initialization") while self._active: if self._queued_notifications.empty(): try: n = base.read(self.receiver.handle, _EVENT_READ_TIMEOUT) except exceptions.NoReceiver: logger.warning("%s disconnected", self.receiver.name) self.receiver.close() break if n: report_id, devnumber, data = n n = base.make_notification(report_id, devnumber, data) else: n = self._queued_notifications.get() # deliver any queued notifications if n: try: self._notifications_callback(n) except Exception: logger.exception("processing %s", n) del self._queued_notifications self.has_stopped() def stop(self): """Tells the listener to stop as soon as possible.""" self._active = False def has_started(self): """Called right after the thread has started, and before it starts reading notification packets.""" pass def has_stopped(self): """Called right before the thread stops.""" pass def _notifications_hook(self, n): # Only consider unhandled notifications that were sent from this thread, # i.e. triggered by a callback handling a previous notification. assert threading.current_thread() == self if self._active: # and threading.current_thread() == self: # if logger.isEnabledFor(logging.DEBUG): # logger.debug("queueing unhandled %s", n) if not self._queued_notifications.full(): self._queued_notifications.put(n) def __bool__(self): return bool(self._active and self.receiver) __nonzero__ = __bool__ Solaar-1.1.20/lib/logitech_receiver/logivoice.py000066400000000000000000000302301522022367600216010ustar00rootroot00000000000000## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """LogiVoice (0x0900 + 0x0901-0x0907) read helpers. Each LogiVoice processing module exposes the same 5-function API: fn 0 SetState fn 1 GetState -> u8 state (boolean) fn 2 SetParameters fn 3 GetParameters -> module-specific payload (see PARAMETERS_FIELDS) fn 4 GetInfo -> per-field [min, max] bounds (see parse_info) All multi-byte integers on the wire are big-endian. Parameters layouts are module-specific; PARAMETERS_FIELDS encodes per-field offset / width / signedness / range / label metadata. The first field is at offset 0 — there is no leading "state" byte (the state toggle is on fn 0/1 only). Writes are NOT implemented yet. State toggles via fn 0x00/0x10 are shipping as boolean settings; per-field Parameters writes need a live round-trip verification before they're safe to expose. """ from __future__ import annotations import logging import struct from typing import Iterable from .hidpp20_constants import SupportedFeature logger = logging.getLogger(__name__) # Wire function IDs (standard across all LogiVoice modules). FN_SET_STATE = 0x00 FN_GET_STATE = 0x10 FN_SET_PARAMETERS = 0x20 FN_GET_PARAMETERS = 0x30 FN_GET_INFO = 0x40 # Human-readable names for the modules Solaar may see on a LogiVoice device. MODULE_NAMES = { SupportedFeature.LOGIVOICE: "LogiVoice", SupportedFeature.LOGIVOICE_NOISE_REDUCTION: "Noise Reduction", SupportedFeature.LOGIVOICE_NOISE_GATE: "Noise Gate", SupportedFeature.LOGIVOICE_COMPRESSOR: "Compressor", SupportedFeature.LOGIVOICE_DE_ESSER: "De-esser", SupportedFeature.LOGIVOICE_DE_POPPER: "De-popper", SupportedFeature.LOGIVOICE_LIMITER: "Limiter", SupportedFeature.LOGIVOICE_HIGH_PASS_FILTER: "High Pass Filter", } # Short slugs used in Solaar setting IDs (`logivoice--`). MODULE_SLUGS = { SupportedFeature.LOGIVOICE_NOISE_REDUCTION: "nr", SupportedFeature.LOGIVOICE_NOISE_GATE: "ng", SupportedFeature.LOGIVOICE_COMPRESSOR: "comp", SupportedFeature.LOGIVOICE_DE_ESSER: "deesser", SupportedFeature.LOGIVOICE_DE_POPPER: "depopper", SupportedFeature.LOGIVOICE_LIMITER: "limiter", SupportedFeature.LOGIVOICE_HIGH_PASS_FILTER: "hpf", } class Field: """Metadata for one decoded Parameters field. offset: byte offset within the GetParameters payload. byte_count: width (1 or 2 for fields we currently decode). signed: whether to interpret as signed int. min_value/max_value: range for the Solaar slider validator. For opaque fields, use the full representable range (0..255 or 0..65535). label: human-readable name for UI. opaque: True if the field's wire encoding isn't pinned down — label shows raw units and the caller should treat as round-trip. """ def __init__(self, name, offset, byte_count, signed, min_value, max_value, label, opaque=False): self.name = name self.offset = offset self.byte_count = byte_count self.signed = signed self.min_value = min_value self.max_value = max_value self.label = label self.opaque = opaque # Per-module field layout for GetParameters / SetParameters payload. Each # module's struct is the union of named fields below; there is no separate # "state" byte at offset 0 — that toggle is only on fn 0x00/0x10. Field # encodings (signedness, byte order, units) and value ranges come from the # device's GetInfo response (see parse_info) and are confirmed against # captured bring-up bytes; ranges hardcoded here are the bounds the device # reports and the values it ships as factory defaults. # # `opaque=True` is reserved for fields whose unit scale isn't pinned down # (currently width_q on De-esser / De-popper — the host-side scale constant # is loaded at runtime and not statically resolvable). Treat opaque values # as monotonic raw integers until a live probe anchors the units. PARAMETERS_FIELDS: dict[SupportedFeature, list[Field]] = { SupportedFeature.LOGIVOICE_NOISE_REDUCTION: [ Field("sensitivity", 0, 1, False, 0, 40, "Sensitivity"), Field("release", 1, 2, False, 1, 1000, "Release (ms)"), Field("bias", 3, 1, False, 0, 5, "Bias"), Field("attenuation", 4, 1, True, -20, 0, "Attenuation (dB)"), ], SupportedFeature.LOGIVOICE_NOISE_GATE: [ Field("threshold", 0, 1, True, -60, -35, "Threshold (dB)"), Field("attenuation", 1, 1, True, -50, -3, "Attenuation (dB)"), Field("attack", 2, 2, False, 1, 200, "Attack (ms)"), Field("hold", 4, 2, False, 1, 1000, "Hold (ms)"), Field("release", 6, 2, False, 1, 1000, "Release (ms)"), ], SupportedFeature.LOGIVOICE_COMPRESSOR: [ Field("threshold", 0, 1, True, -40, 0, "Threshold (dB)"), Field("attack", 1, 2, False, 1, 200, "Attack (ms)"), Field("release", 3, 2, False, 50, 1000, "Release (ms)"), Field("post_gain", 5, 1, True, -12, 12, "Post Gain (dB)"), Field("pre_gain", 6, 1, True, -12, 12, "Pre Gain (dB)"), # Ratio reports min=1 max=20 from GetInfo; whether the device interprets # it as a literal X:1 ratio or a curve-table index is unconfirmed. Field("ratio", 7, 1, False, 1, 20, "Ratio"), ], SupportedFeature.LOGIVOICE_DE_ESSER: [ Field("threshold", 0, 1, True, -50, 0, "Threshold (dB)"), Field("frequency", 1, 2, False, 1000, 10000, "Frequency (Hz)"), # width_q is a Q-format quantization with a device-loaded scale we # don't know; range/default come straight from GetInfo. Field("width_q", 3, 1, False, 2, 120, "Width/Q", opaque=True), Field("attack", 4, 2, False, 1, 200, "Attack (ms)"), Field("release", 6, 2, False, 20, 1000, "Release (ms)"), Field("attenuation", 8, 1, True, -40, 0, "Attenuation (dB)"), ], SupportedFeature.LOGIVOICE_DE_POPPER: [ Field("threshold", 0, 1, True, -50, 0, "Threshold (dB)"), Field("frequency", 1, 2, False, 60, 500, "Frequency (Hz)"), Field("width_q", 3, 1, False, 2, 120, "Width/Q", opaque=True), Field("attack", 4, 2, False, 1, 200, "Attack (ms)"), Field("release", 6, 2, False, 20, 1000, "Release (ms)"), Field("attenuation", 8, 1, True, -40, 0, "Attenuation (dB)"), ], SupportedFeature.LOGIVOICE_LIMITER: [ Field("boost", 0, 1, True, -128, 127, "Boost (dB)"), Field("attack", 1, 2, False, 1, 65535, "Attack (ms)"), Field("release", 3, 2, False, 1, 65535, "Release (ms)"), ], SupportedFeature.LOGIVOICE_HIGH_PASS_FILTER: [ Field("frequency", 0, 2, False, 60, 300, "Cutoff (Hz)"), ], } def expected_payload_length(feature: SupportedFeature) -> int: fields = PARAMETERS_FIELDS.get(feature) if not fields: return 0 return max(f.offset + f.byte_count for f in fields) def get_state(device, feature: SupportedFeature): """Read the module's on/off state via fn 1. Returns int 0-255 or None.""" result = device.feature_request(feature, FN_GET_STATE) if result is None or len(result) < 1: return None return result[0] def get_parameters(device, feature: SupportedFeature): """Read the module's Parameters struct via fn 3. Returns raw bytes or None.""" result = device.feature_request(feature, FN_GET_PARAMETERS) if result is None: return None return bytes(result) def get_info(device, feature: SupportedFeature): """Read module capability info via fn 4. Returns raw bytes or None. Decoded per-field bounds are available via parse_info(). """ result = device.feature_request(feature, FN_GET_INFO) if result is None: return None return bytes(result) def _decode_field(chunk: bytes, byte_count: int, signed: bool) -> int: """Decode `byte_count` bytes from `chunk` as an integer per the field's wire encoding. Multi-byte values are big-endian (matches Parameters).""" if byte_count == 1: return struct.unpack("b" if signed else "B", chunk[:1])[0] if byte_count == 2: return struct.unpack(">h" if signed else ">H", chunk[:2])[0] return int.from_bytes(chunk[:byte_count], "big", signed=signed) def parse_info(feature: SupportedFeature, payload: bytes) -> dict: """Decode a GetInfo response into per-field {min, max} bounds. Layout: for each field in PARAMETERS_FIELDS in order, the payload carries [min_value, max_value] back-to-back using the field's wire encoding (so a u16 field contributes 4 bytes — 2 for min, 2 for max). Trailing bytes in the response are pad/zero. Returns a dict mapping field name to {"min": int, "max": int}. Fields that don't fit in the payload are omitted. """ fields = PARAMETERS_FIELDS.get(feature) if not fields or not payload: return {} out = {} offset = 0 for f in fields: end = offset + 2 * f.byte_count if end > len(payload): break min_val = _decode_field(payload[offset : offset + f.byte_count], f.byte_count, f.signed) max_val = _decode_field(payload[offset + f.byte_count : end], f.byte_count, f.signed) out[f.name] = {"min": min_val, "max": max_val} offset = end return out def parse_parameters(feature: SupportedFeature, payload: bytes) -> dict: """Decode Parameters bytes into a dict per the per-module field table. Returns {} on unknown feature or short payload — caller still has the raw hex via get_parameters() for corpus logging. """ fields = PARAMETERS_FIELDS.get(feature) if not fields or payload is None: return {} parsed = {} for f in fields: end = f.offset + f.byte_count if end > len(payload): continue chunk = payload[f.offset : end] if f.byte_count == 1: val = struct.unpack("b" if f.signed else "B", chunk)[0] elif f.byte_count == 2: val = struct.unpack(">h" if f.signed else ">H", chunk)[0] else: val = int.from_bytes(chunk, "big", signed=f.signed) parsed[f.name] = val return parsed def probe_module(device, feature: SupportedFeature) -> None: """One-shot corpus probe. Logs state + raw parameters + parsed + raw info + decoded info bounds.""" name = MODULE_NAMES.get(feature, f"0x{int(feature):04X}") state = get_state(device, feature) params = get_parameters(device, feature) info = get_info(device, feature) logger.debug( "LogiVoice %s [0x%04X]: state=%s parameters=%s info=%s", name, int(feature), state, params.hex() if params else None, info.hex() if info else None, ) parsed = parse_parameters(feature, params) if params else {} if parsed: logger.debug("LogiVoice %s parsed: %s", name, parsed) bounds = parse_info(feature, info) if info else {} if bounds: logger.debug("LogiVoice %s info bounds: %s", name, bounds) def probe_all_modules(device, features: Iterable[SupportedFeature]) -> None: """Probe every LogiVoice module present on the device. Call once at device-bring-up so the -dd corpus has a full snapshot. Caller passes whichever subset of LogiVoice features are actually discovered (usually derived from device.features). """ for feature in features: if feature not in PARAMETERS_FIELDS and feature != SupportedFeature.LOGIVOICE: continue try: probe_module(device, feature) except Exception as e: logger.debug("LogiVoice probe_module(%s) raised %s", feature, e) Solaar-1.1.20/lib/logitech_receiver/notifications.py000066400000000000000000000654211522022367600225040ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Handles incoming events from the receiver/devices, updating the object as appropriate. """ from __future__ import annotations import logging import struct import threading import typing from solaar.i18n import _ from . import base from . import common from . import diversion from . import hidpp10 from . import hidpp10_constants from . import hidpp20 from . import rgb_power from . import settings_templates from .common import Alert from .common import BatteryStatus from .common import Notification from .hidpp10_constants import Registers from .hidpp20_constants import SupportedFeature if typing.TYPE_CHECKING: from .base import HIDPPNotification from .device import Device from .receiver import Receiver logger = logging.getLogger(__name__) NotificationHandler = typing.Callable[["Receiver", "HIDPPNotification"], bool] _hidpp10 = hidpp10.Hidpp10() _hidpp20 = hidpp20.Hidpp20() notification_lock = threading.Lock() def process(device: Device | Receiver, notification: HIDPPNotification): """Handle incoming events (notification) from device or receiver.""" assert device assert notification if not device.isDevice: return process_receiver_notification(device, notification) return process_device_notification(device, notification) def process_receiver_notification(receiver: Receiver, notification: HIDPPNotification) -> bool | None: """Process event messages from receivers.""" event_handler_mapping: dict[int, NotificationHandler] = { Notification.PAIRING_LOCK: handle_pairing_lock, Registers.DEVICE_DISCOVERY_NOTIFICATION: handle_device_discovery, Registers.DISCOVERY_STATUS_NOTIFICATION: handle_discovery_status, Registers.PAIRING_STATUS_NOTIFICATION: handle_pairing_status, Registers.PASSKEY_PRESSED_NOTIFICATION: handle_passkey_pressed, Registers.PASSKEY_REQUEST_NOTIFICATION: handle_passkey_request, } try: handler_func = event_handler_mapping[notification.sub_id] return handler_func(receiver, notification) except KeyError: pass assert notification.sub_id in [ Notification.CONNECT_DISCONNECT, Notification.DJ_PAIRING, Notification.CONNECTED, Notification.RAW_INPUT, Notification.POWER, ] logger.warning(f"{receiver}: unhandled notification {notification}") def process_device_notification(device: Device, notification: HIDPPNotification): """Process event messages from devices.""" # incoming packets with SubId >= 0x80 are supposedly replies from HID++ 1.0 requests, should never get here assert notification.sub_id & 0x80 == 0 if notification.sub_id == Notification.NO_OPERATION: # dispose it return False # Allow the device object to handle the notification using custom per-device state. handling_ret = device.handle_notification(notification) if handling_ret is not None: return handling_ret # 0x40 to 0x7F appear to be HID++ 1.0 or DJ notifications if notification.sub_id >= 0x40: if notification.report_id == base.DJ_MESSAGE_ID: return _process_dj_notification(device, notification) else: return _process_hidpp10_notification(device, notification) # These notifications are from the device itself, so it must be active device.online = True # At this point, we need to know the device's protocol, otherwise it's possible to not know how to handle it. assert device.protocol is not None # some custom battery events for HID++ 1.0 devices if device.protocol < 2.0: return _process_hidpp10_custom_notification(device, notification) # assuming 0x00 to 0x3F are feature (HID++ 2.0) notifications if not device.features: logger.warning("%s: feature notification but features not set up: %02X %s", device, notification.sub_id, notification) return False return _process_feature_notification(device, notification) def _process_dj_notification(device: Device, notification: HIDPPNotification): if logger.isEnabledFor(logging.DEBUG): logger.debug("%s (%s) DJ %s", device, device.protocol, notification) if notification.sub_id == Notification.CONNECT_DISCONNECT: # do all DJ paired notifications also show up as HID++ 1.0 notifications? if logger.isEnabledFor(logging.INFO): logger.info("%s: ignoring DJ unpaired: %s", device, notification) return True if notification.sub_id == Notification.DJ_PAIRING: # do all DJ paired notifications also show up as HID++ 1.0 notifications? if logger.isEnabledFor(logging.INFO): logger.info("%s: ignoring DJ paired: %s", device, notification) return True if notification.sub_id == Notification.CONNECTED: connected = not notification.address & 0x01 if logger.isEnabledFor(logging.INFO): logger.info("%s: DJ connection: %s %s", device, connected, notification) device.changed(active=connected, alert=Alert.NONE, reason=_("connected") if connected else _("disconnected")) return True logger.warning("%s: unrecognized DJ %s", device, notification) def _process_hidpp10_custom_notification(device: Device, notification: HIDPPNotification): if logger.isEnabledFor(logging.DEBUG): logger.debug("%s (%s) custom notification %s", device, device.protocol, notification) if notification.sub_id in (Registers.BATTERY_STATUS, Registers.BATTERY_CHARGE): assert notification.data[-1:] == b"\x00" data = chr(notification.address).encode() + notification.data device.set_battery_info(hidpp10.parse_battery_status(notification.sub_id, data)) return True logger.warning("%s: unrecognized %s", device, notification) def _process_hidpp10_notification(device: Device, notification: HIDPPNotification): if notification.sub_id == Notification.CONNECT_DISCONNECT: # device unpairing if notification.address == 0x02: # device un-paired device.wpid = None if device.number in device.receiver: del device.receiver[device.number] device.changed(active=False, alert=Alert.ALL, reason=_("unpaired")) ## device.status = None else: logger.warning("%s: disconnection with unknown type %02X: %s", device, notification.address, notification) return True if notification.sub_id == Notification.DJ_PAIRING: # device connection (and disconnection) flags = ord(notification.data[:1]) & 0xF0 if notification.address == 0x02: # very old 27 MHz protocol wpid = "00" + common.strhex(notification.data[2:3]) link_established = True link_encrypted = bool(flags & 0x80) elif notification.address > 0x00: # all other protocols are supposed to be almost the same wpid = common.strhex(notification.data[2:3] + notification.data[1:2]) link_established = not (flags & 0x40) link_encrypted = bool(flags & 0x20) or notification.address == 0x10 # Bolt protocol always encrypted else: logger.warning( "%s: connection notification with unknown protocol %02X: %s", device.number, notification.address, notification ) return True if wpid != device.wpid: logger.warning("%s wpid mismatch, got %s", device, wpid) if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: protocol %s connection notification: software=%s, encrypted=%s, link=%s, payload=%s", device, notification.address, bool(flags & 0x10), link_encrypted, link_established, bool(flags & 0x80), ) device.link_encrypted = link_encrypted if not link_established and device.receiver: hidpp10.set_configuration_pending_flags(device.receiver, 0xFF) device.changed(active=link_established) return True if notification.sub_id == Notification.RAW_INPUT: # raw input event? just ignore it # if notification.address == 0x01, no idea what it is, but they keep on coming # if notification.address == 0x03, appears to be an actual input event, because they only come when input happents return True if notification.sub_id == Notification.POWER: if notification.address == 0x01: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: device powered on", device) reason = device.status_string() or _("powered on") device.changed(active=True, alert=Alert.NOTIFICATION, reason=reason) else: logger.warning("%s: unknown %s", device, notification) return True logger.warning("%s: unrecognized %s", device, notification) def _process_feature_notification(device: Device, notification: HIDPPNotification): old_present, device.present = device.present, True # the device is generating a feature notification so it must be present try: feature = device.features.get_feature(notification.sub_id) except IndexError: logger.warning("%s: notification from invalid feature index %02X: %s", device, notification.sub_id, notification) return False if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: notification for feature %s, report %s, data %s", device, feature, notification.address >> 4, common.strhex(notification.data), ) if feature == SupportedFeature.BATTERY_STATUS: if notification.address == 0x00: device.set_battery_info(hidpp20.decipher_battery_status(notification.data)[1]) elif notification.address == 0x10: if logger.isEnabledFor(logging.INFO): logger.info("%s: spurious BATTERY status %s", device, notification) else: logger.warning("%s: unknown BATTERY %s", device, notification) elif feature == SupportedFeature.BATTERY_VOLTAGE: if notification.address == 0x00: device.set_battery_info(hidpp20.decipher_battery_voltage(notification.data)[1]) else: logger.warning("%s: unknown VOLTAGE %s", device, notification) elif feature == SupportedFeature.UNIFIED_BATTERY: if notification.address == 0x00: device.set_battery_info(hidpp20.decipher_battery_unified(notification.data)[1]) else: logger.warning("%s: unknown UNIFIED BATTERY %s", device, notification) elif feature == SupportedFeature.ADC_MEASUREMENT: if notification.address == 0x00: result = hidpp20.decipher_adc_measurement(notification.data) if result: # if good data and the device was not present then a push is needed device.set_battery_info(result[1]) device.changed(active=True, alert=Alert.NONE, reason=_("ADC measurement notification"), push=not old_present) else: # this feature is also used to signal device becoming inactive device.present = False # exception to device presence device.changed(active=False) else: logger.warning("%s: unknown ADC MEASUREMENT %s", device, notification) elif feature == SupportedFeature.CENTURION_BATTERY_SOC: device.set_battery_info(hidpp20.decipher_battery_centurion(notification.data)[1]) elif feature == SupportedFeature.SOLAR_DASHBOARD: if notification.data[5:9] == b"GOOD": charge, lux, adc = struct.unpack("!BHH", notification.data[:5]) # guesstimate the battery voltage, emphasis on 'guess' # status_text = '%1.2fV' % (adc * 2.67793237653 / 0x0672) status_text = BatteryStatus.DISCHARGING if notification.address == 0x00: device.set_battery_info(common.Battery(charge, None, status_text, None)) elif notification.address == 0x10: if lux > 200: status_text = BatteryStatus.RECHARGING device.set_battery_info(common.Battery(charge, None, status_text, None, lux)) elif notification.address == 0x20: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: Light Check button pressed", device) device.changed(alert=Alert.SHOW_WINDOW) # first cancel any reporting # device.feature_request(SupportedFeature.SOLAR_DASHBOARD) # trigger a new report chain reports_count = 15 reports_period = 2 # seconds device.feature_request(SupportedFeature.SOLAR_DASHBOARD, 0x00, reports_count, reports_period) else: logger.warning("%s: unknown SOLAR CHARGE %s", device, notification) else: logger.warning("%s: SOLAR CHARGE not GOOD? %s", device, notification) elif feature == SupportedFeature.WIRELESS_DEVICE_STATUS: if notification.address == 0x00: if logger.isEnabledFor(logging.DEBUG): logger.debug("wireless status: %s", notification) reason = "powered on" if notification.data[2] == 1 else None if notification.data[1] == 1: # device is asking for software reconfiguration alert = Alert.NONE device.changed(active=True, alert=alert, reason=reason) # changed(active=True) already runs apply_settings_if_needed on # the first transition; for follow-up reconfig notifications # on an already-active device, fire the gate here so the # cookie comparison decides whether to re-push. device.apply_settings_if_needed() else: logger.warning("%s: unknown WIRELESS %s", device, notification) elif feature == SupportedFeature.TOUCHMOUSE_RAW_POINTS: if notification.address == 0x00: if logger.isEnabledFor(logging.INFO): logger.info("%s: TOUCH MOUSE points %s", device, notification) elif notification.address == 0x10: touch = ord(notification.data[:1]) button_down = bool(touch & 0x02) mouse_lifted = bool(touch & 0x01) if logger.isEnabledFor(logging.INFO): logger.info("%s: TOUCH MOUSE status: button_down=%s mouse_lifted=%s", device, button_down, mouse_lifted) else: logger.warning("%s: unknown TOUCH MOUSE %s", device, notification) # TODO: what are REPROG_CONTROLS_V{2,3}? elif feature == SupportedFeature.REPROG_CONTROLS: if notification.address == 0x00: if logger.isEnabledFor(logging.INFO): logger.info("%s: reprogrammable key: %s", device, notification) else: logger.warning("%s: unknown REPROG_CONTROLS %s", device, notification) elif feature == SupportedFeature.BACKLIGHT2: if notification.address == 0x00: level = struct.unpack("!B", notification.data[1:2])[0] if device.setting_callback: device.setting_callback(device, settings_templates.Backlight2Level, [level]) elif feature == SupportedFeature.REPROG_CONTROLS_V4: if notification.address == 0x00: if logger.isEnabledFor(logging.DEBUG): cid1, cid2, cid3, cid4 = struct.unpack("!HHHH", notification.data[:8]) logger.debug("%s: diverted controls pressed: 0x%x, 0x%x, 0x%x, 0x%x", device, cid1, cid2, cid3, cid4) elif notification.address == 0x10: if logger.isEnabledFor(logging.DEBUG): dx, dy = struct.unpack("!hh", notification.data[:4]) logger.debug("%s: rawXY dx=%i dy=%i", device, dx, dy) elif notification.address == 0x20: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: received analyticsKeyEvents", device) elif logger.isEnabledFor(logging.INFO): logger.info("%s: unknown REPROG_CONTROLS_V4 %s", device, notification) elif feature == SupportedFeature.HIRES_WHEEL: if notification.address == 0x00: if logger.isEnabledFor(logging.INFO): flags, delta_v = struct.unpack(">bh", notification.data[:3]) high_res = (flags & 0x10) != 0 periods = flags & 0x0F logger.info("%s: WHEEL: res: %d periods: %d delta V:%-3d", device, high_res, periods, delta_v) elif notification.address == 0x10: ratchet = notification.data[0] if logger.isEnabledFor(logging.INFO): logger.info("%s: WHEEL: ratchet: %d", device, ratchet) if ratchet < 2: # don't process messages with unusual ratchet values if device.setting_callback: device.setting_callback(device, settings_templates.ScrollRatchet, [2 if ratchet else 1]) else: if logger.isEnabledFor(logging.INFO): logger.info("%s: unknown WHEEL %s", device, notification) elif feature == SupportedFeature.ONBOARD_PROFILES: if notification.address > 0x10: if logger.isEnabledFor(logging.INFO): logger.info("%s: unknown ONBOARD PROFILES %s", device, notification) else: if notification.address == 0x00: profile_sector = struct.unpack("!H", notification.data[:2])[0] if profile_sector: settings_templates.profile_change(device, profile_sector) elif notification.address == 0x10: resolution_index = struct.unpack("!B", notification.data[:1])[0] profile_sector = struct.unpack("!H", device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x40)[:2])[0] if device.setting_callback: for profile in device.profiles.profiles.values() if device.profiles else []: if profile.sector == profile_sector: device.setting_callback( device, settings_templates.AdjustableDpi, [profile.resolutions[resolution_index]] ) break elif feature == SupportedFeature.BRIGHTNESS_CONTROL: if notification.address > 0x10: if logger.isEnabledFor(logging.INFO): logger.info("%s: unknown BRIGHTNESS CONTROL %s", device, notification) else: if notification.address == 0x00: brightness = struct.unpack("!H", notification.data[:2])[0] device.setting_callback(device, settings_templates.BrightnessControl, [brightness]) elif notification.address == 0x10: brightness = notification.data[0] & 0x01 if brightness: brightness = struct.unpack("!H", device.feature_request(SupportedFeature.BRIGHTNESS_CONTROL, 0x10)[:2])[0] device.setting_callback(device, settings_templates.BrightnessControl, [brightness]) elif feature == SupportedFeature.RGB_EFFECTS: fn = notification.address >> 4 if fn == 1: # onUserActivity: type=0 is IDLE, type!=0 is ACTIVE activity_type = notification.data[0] if notification.data else 0xFF rgb_power.on_user_activity(device, activity_type) if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: RGB_EFFECTS notification addr=%02x: %s", device, notification.address, notification) elif feature == SupportedFeature.HEADSET_ADVANCED_PARA_EQ: # G522 emits change events with the same payload shape as the # corresponding setter request: # fn 0 — band change (3-byte header [dir, slot, pad] + bands) # fn 2 — friendly-name change (header + nameLen + name) # fn 3 — UUID change (header + 16-byte UUID) # Low nibble of `address` is the swid the firmware echoes back — # match on the function index only. fn = notification.address >> 4 if fn == 0: info = getattr(device, "_advanced_eq_info", None) payload = notification.data[3:] if notification.data else b"" if info and len(payload) >= 5: bands = hidpp20.parse_v2_bands(b"\x00" + payload, info) if bands and device.setting_callback: band_map = {i: int(round(g)) for i, (_t, _f, g) in enumerate(bands)} device.setting_callback(device, settings_templates.HeadsetAdvancedEQ, [band_map]) elif logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: HEADSET_ADVANCED_PARA_EQ band-change event with no parseable payload %s", device, notification ) elif fn in (2, 3) and logger.isEnabledFor(logging.DEBUG): logger.debug("%s: HEADSET_ADVANCED_PARA_EQ fn=%d change event %s", device, fn, notification) elif logger.isEnabledFor(logging.DEBUG): logger.debug("%s: unknown HEADSET_ADVANCED_PARA_EQ %s", device, notification) elif feature == SupportedFeature.HEADSET_MIC_MUTE: # G522 emits state-change events on two function indices, both carrying # the new state in data[0] (0 = unmuted, 1 = muted): # fn 0 — physical mute switch press # fn 1 — echo following a host-driven SetState (fn 2) write # Low nibble of `address` is the swid the firmware echoes back, which # varies with the request — match on the function index only. fn = notification.address >> 4 if fn in (0, 1) and notification.data: muted = bool(notification.data[0]) if device.setting_callback: device.setting_callback(device, settings_templates.HeadsetMicMute, [muted]) elif logger.isEnabledFor(logging.DEBUG): logger.debug("%s: unknown HEADSET_MIC_MUTE %s", device, notification) diversion.process_notification(device, notification, feature) return True def handle_pairing_lock(receiver: Receiver, notification: HIDPPNotification) -> bool: receiver.pairing.lock_open = bool(notification.address & 0x01) reason = _("pairing lock is open") if receiver.pairing.lock_open else _("pairing lock is closed") if logger.isEnabledFor(logging.INFO): logger.info("%s: %s", receiver, reason) receiver.pairing.error = None if receiver.pairing.lock_open: receiver.pairing.new_device = None pair_error = ord(notification.data[:1]) if pair_error: error_string = hidpp10_constants.PairingError(pair_error).label receiver.pairing.error = error_string receiver.pairing.new_device = None logger.warning("pairing error %d: %s", pair_error, error_string) receiver.changed(reason=reason) return True def handle_discovery_status(receiver: Receiver, notification: HIDPPNotification) -> bool: with notification_lock: receiver.pairing.discovering = notification.address == 0x00 reason = _("discovery lock is open") if receiver.pairing.discovering else _("discovery lock is closed") if logger.isEnabledFor(logging.INFO): logger.info("%s: %s", receiver, reason) receiver.pairing.error = None if receiver.pairing.discovering: receiver.pairing.counter = receiver.pairing.device_address = None receiver.pairing.device_authentication = receiver.pairing.device_name = None receiver.pairing.device_passkey = None discover_error = ord(notification.data[:1]) if discover_error: receiver.pairing.error = discover_string = hidpp10_constants.BoltPairingError(discover_error).label logger.warning("bolt discovering error %d: %s", discover_error, discover_string) receiver.changed(reason=reason) return True def handle_device_discovery(receiver: Receiver, notification: HIDPPNotification) -> bool: with notification_lock: counter = notification.address + notification.data[0] * 256 # notification counter if receiver.pairing.counter is None: receiver.pairing.counter = counter else: if not receiver.pairing.counter == counter: return None if notification.data[1] == 0: receiver.pairing.device_kind = notification.data[3] receiver.pairing.device_address = notification.data[6:12] receiver.pairing.device_authentication = notification.data[14] elif notification.data[1] == 1: receiver.pairing.device_name = notification.data[3 : 3 + notification.data[2]].decode("utf-8") return True def handle_pairing_status(receiver: Receiver, notification: HIDPPNotification) -> bool: with notification_lock: receiver.pairing.device_passkey = None receiver.pairing.lock_open = notification.address == 0x00 reason = _("pairing lock is open") if receiver.pairing.lock_open else _("pairing lock is closed") if logger.isEnabledFor(logging.INFO): logger.info("%s: %s", receiver, reason) receiver.pairing.error = None if not receiver.pairing.lock_open: receiver.pairing.counter = None receiver.pairing.device_address = None receiver.pairing.device_authentication = None receiver.pairing.device_name = None pair_error = notification.data[0] if receiver.pairing.lock_open: receiver.pairing.new_device = None elif notification.address == 0x02 and not pair_error: receiver.pairing.new_device = receiver.register_new_device(notification.data[7]) if pair_error: receiver.pairing.error = error_string = hidpp10_constants.BoltPairingError(pair_error).label receiver.pairing.new_device = None logger.warning("pairing error %d: %s", pair_error, error_string) receiver.changed(reason=reason) return True def handle_passkey_request(receiver: Receiver, notification: HIDPPNotification) -> bool: with notification_lock: receiver.pairing.device_passkey = notification.data[0:6].decode("utf-8") return True def handle_passkey_pressed(_receiver: Receiver, _hidpp_notification: HIDPPNotification) -> bool: return True Solaar-1.1.20/lib/logitech_receiver/onboard_eq.py000066400000000000000000000154151522022367600217420ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """OnboardEQ (0x0636) biquad coefficient math and payload builders. Pure computation — no device or transport dependencies beyond feature_request(). """ from __future__ import annotations import math import struct from .hidpp20_constants import SupportedFeature # Opaque bytes observed between band params and coefficient header. First # byte matches band_count; bytes 2-3 look like LE16 coeff blob size. Keep # verbatim until a device counter-example forces a re-derivation. _EQ_MYSTERY_BYTES = b"\x05\x5a\xe3\x00" def _peaking_eq_biquad(freq_hz, gain_db, Q, sample_rate=48000.0): """Compute peaking EQ biquad coefficients (Audio EQ Cookbook). Returns (b0/a0, b1/a0, b2/a0, a1/a0, a2/a0) normalised coefficients. """ A = 10.0 ** (gain_db / 40.0) w0 = 2.0 * math.pi * freq_hz / sample_rate cos_w0 = math.cos(w0) alpha = math.sin(w0) / (2.0 * Q) a0 = 1.0 + alpha / A return ( (1.0 + alpha * A) / a0, (-2.0 * cos_w0) / a0, (1.0 - alpha * A) / a0, (-2.0 * cos_w0) / a0, (1.0 - alpha / A) / a0, ) def _quantize_coeffs(b0, b1, b2, a1, a2): """Quantize biquad coefficients to mixed Q1.31 / Q2.30 fixed-point. b0, b2, a2 use Q1.31 (x 2^31); b1, a1 use Q2.30 (x 2^30). Values are truncated to 24-bit precision (low byte zeroed) matching the device DSP's internal format. Returns list of 10 uint16 values (5 coefficients x 2 LE words each, high word first). """ scales = [2**31, 2**30, 2**31, 2**30, 2**31] # b0, b1, b2, a1, a2 words = [] for val, scale in zip([b0, b1, b2, a1, a2], scales): q = int(round(val * scale)) q = max(-(1 << 31), min((1 << 31) - 1, q)) q = q & 0xFFFFFF00 # 24-bit precision (low byte always zero) words.append((q >> 16) & 0xFFFF) # high word words.append(q & 0xFFFF) # low word return words def _build_coeff_section(bands, sample_rate, section_type=1): """Build one coefficient section for a DSP processing block. Returns bytes: 4-byte section header + coefficient data as LE uint16 words. Section header: [type, 0x00, count_lo, count_hi]. Coefficients are normalized by a rescale factor to prevent Q1.31 overflow. Only feedforward coefficients (b0, b1, b2) are divided by rescale; feedback coefficients (a1, a2) are left unchanged. The DSP multiplies the output by rescale to restore correct gain. """ _HEADROOM = 1.19 # 19% headroom margin before quantization num_bands = len(bands) all_words = [num_bands] # first uint16 = num_bands # First pass: compute raw biquad coefficients for all bands raw_coeffs = [] for freq, gain, Q in bands: raw_coeffs.append(_peaking_eq_biquad(freq, gain, max(Q, 0.1), sample_rate)) # Compute rescale: ensure max |b0| fits in Q1.31 with headroom max_b0 = max(abs(c[0]) for c in raw_coeffs) rescale = max(1.0, max_b0) * _HEADROOM # Second pass: normalize b-coefficients and quantize for b0, b1, b2, a1, a2 in raw_coeffs: all_words.extend(_quantize_coeffs(b0 / rescale, b1 / rescale, b2 / rescale, a1, a2)) # Rescale factor as Q6.26, 24-bit precision rs = int(round(rescale * (1 << 26))) rs = max(-(1 << 31), min((1 << 31) - 1, rs)) & 0xFFFFFF00 all_words.append((rs >> 16) & 0xFFFF) all_words.append(rs & 0xFFFF) coeff_count = num_bands * 10 + 3 # num_bands word + 10 per band + 2 rescale words hdr = bytes([section_type, 0x00, coeff_count & 0xFF, (coeff_count >> 8) & 0xFF]) data = struct.pack(f"<{len(all_words)}H", *all_words) return hdr + data def _build_eq_coeffs_payload(bands): """Build the full EQCoeffs wire payload for SetEQParameters. Two coefficient sections: type=1 (48 kHz playback) and type=2 (16 kHz mic). Returns bytes: 7-byte header + sections (no trailing padding). """ section_count = 2 header = bytes([0x03, 0x0E, 0x00, section_count, 0x00, 0x00, 0x00]) sections = _build_coeff_section(bands, 48000.0, section_type=1) sections += _build_coeff_section(bands, 16000.0, section_type=2) return header + sections def _build_set_eq_payload(slot, bands): """Build complete SetEQParameters payload: band params + biquad coefficients. bands: list of (freq_hz, gain_db, Q) tuples. Returns bytes ready to send as sub-device params. """ params = bytes([slot, len(bands)]) for freq, gain, Q in bands: params += struct.pack(">H", freq) + bytes([gain & 0xFF, Q & 0xFF]) params += _EQ_MYSTERY_BYTES params += _build_eq_coeffs_payload(bands) return params def get_onboard_eq_info(device): """Query HEADSET_ONBOARD_EQ GetEQInfos (function 0). Returns (has_hw_eq, num_bands) or None. """ result = device.feature_request(SupportedFeature.HEADSET_ONBOARD_EQ, 0x00) if result is None or len(result) < 5: return None has_hw_eq = bool(result[0] & 0x80) num_bands = result[4] return (has_hw_eq, num_bands) def get_onboard_eq_params(device, slot=0x00): """Query HEADSET_ONBOARD_EQ GetEQParameters (function 0x10). Returns list of (freq_hz, gain_db, q) tuples, or None. """ result = device.feature_request(SupportedFeature.HEADSET_ONBOARD_EQ, 0x10, slot) if result is None or len(result) < 2: return None band_count = result[1] bands = [] offset = 2 for _i in range(band_count): if offset + 4 > len(result): break freq_hz = struct.unpack(">H", result[offset : offset + 2])[0] gain_db = struct.unpack("b", bytes([result[offset + 2]]))[0] # signed q = result[offset + 3] bands.append((freq_hz, gain_db, q)) offset += 4 return bands def set_onboard_eq_params(device, bands, slot=0x00): """Send HEADSET_ONBOARD_EQ SetEQParameters (function 0x20). bands: list of (freq_hz, gain_db, Q) tuples. Returns response or None. """ payload = _build_set_eq_payload(slot, bands) return device.feature_request(SupportedFeature.HEADSET_ONBOARD_EQ, 0x20, payload) Solaar-1.1.20/lib/logitech_receiver/receiver.py000066400000000000000000000600111522022367600214250ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import errno import logging import time import typing from dataclasses import dataclass from typing import Callable from typing import Optional from typing import Protocol from solaar.i18n import _ from solaar.i18n import ngettext from . import exceptions from . import hidpp10 from . import hidpp10_constants from .common import Alert from .common import Notification from .device import Device from .hidpp10_constants import InfoSubRegisters from .hidpp10_constants import NotificationFlag from .hidpp10_constants import Registers if typing.TYPE_CHECKING: from logitech_receiver import common from .base import HIDPPNotification logger = logging.getLogger(__name__) _hidpp10 = hidpp10.Hidpp10() class LowLevelInterface(Protocol): def open_path(self, path): ... def find_paired_node_wpid(self, receiver_path: str, index: int): ... def ping(self, handle, number, long_message=False): ... def request(self, handle, devnumber, request_id, *params, **kwargs): ... def close(self, handle): ... @dataclass class Pairing: """Information about the current or most recent pairing""" lock_open: bool = False discovering: bool = False counter: Optional[int] = None device_address: Optional[bytes] = None device_authentication: Optional[int] = None device_kind: Optional[int] = None device_name: Optional[str] = None device_passkey: Optional[str] = None new_device: Optional[Device] = None error: Optional[any] = None def extract_serial(response: bytes) -> str: """Extracts serial number from receiver response.""" return response.hex().upper() def extract_max_devices(response: bytes) -> int: """Extracts maximum number of supported devices from response.""" max_devices = response[6] return int(max_devices) def extract_remaining_pairings(response: bytes) -> int: ps = ord(response[2:3]) remaining_pairings = ps - 5 if ps >= 5 else -1 return int(remaining_pairings) def extract_codename(response: bytes) -> str: codename = response[2 : 2 + ord(response[1:2])] return codename.decode("ascii") def extract_power_switch_location(response: bytes) -> str: """Extracts power switch location from response.""" index = response[9] & 0x0F return hidpp10_constants.PowerSwitchLocation.location(index).name.lower() def extract_connection_count(response: bytes) -> int: """Extract connection count from receiver response.""" return ord(response[1:2]) def extract_wpid(response: bytes) -> str: """Extract wpid from receiver response.""" return response.hex().upper() def extract_polling_rate(response: bytes) -> int: """Returns polling rate in milliseconds.""" return int(response[2]) def extract_device_kind(response: int) -> str: return hidpp10_constants.DEVICE_KIND[response] class Receiver: """A generic Receiver instance, mostly implementing the interface used on Unifying, Nano, and LightSpeed receivers" The paired devices are available through the sequence interface. """ read_register: Callable = hidpp10.read_register write_register: Callable = hidpp10.write_register number = 0xFF kind = None def __init__( self, low_level: LowLevelInterface, receiver_kind, product_info, handle, path, product_id, setting_callback=None, ): assert handle self.low_level = low_level self.isDevice = False # some devices act as receiver so we need a property to distinguish them self.handle = handle self.path = path self.product_id = product_id self.setting_callback = setting_callback # for changes to settings self.status_callback = None # for changes to other potentially visible aspects self.receiver_kind = receiver_kind self.serial = None self.max_devices = None self._firmware = None self._remaining_pairings = None self._devices = {} self.name = product_info.get("name", "Receiver") self.may_unpair = product_info.get("may_unpair", False) self.re_pairs = product_info.get("re_pairs", False) self.notification_flags = None self.pairing = Pairing() self.initialize(product_info) hidpp10.set_configuration_pending_flags(self, 0xFF) if logger.isEnabledFor(logging.INFO): logger.info("%s: init receiver: handle %s, path %s, serial %s", self, self.handle, self.path, self.serial) def initialize(self, product_info: dict): # read the receiver information subregister, so we can find out max_devices serial_reply = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.RECEIVER_INFORMATION) if serial_reply: self.serial = extract_serial(serial_reply[1:5]) self.max_devices = extract_max_devices(serial_reply) if not (1 <= self.max_devices <= 6): self.max_devices = product_info.get("max_devices", 1) else: # handle receivers that don't have a serial number specially (i.e., c534) self.serial = None self.max_devices = product_info.get("max_devices", 1) def close(self): if logger.isEnabledFor(logging.INFO): logger.info("%s: closing - handle %s %s", self, type(self.handle), self.handle) handle, self.handle = self.handle, None for _n, d in self._devices.items(): if d: d.close() self._devices.clear() return handle and self.low_level.close(handle) def __del__(self): self.close() def changed(self, alert=Alert.NOTIFICATION, reason=None): """The status of the device had changed, so invoke the status callback""" if self.status_callback is not None: self.status_callback(self, alert=alert, reason=reason) @property def firmware(self) -> tuple[common.FirmwareInfo]: if self._firmware is None and self.handle: self._firmware = _hidpp10.get_firmware(self) return self._firmware # how many pairings remain (None for unknown, -1 for unlimited) def remaining_pairings(self, cache=True): if self._remaining_pairings is None or not cache: ps = self.read_register(Registers.RECEIVER_CONNECTION) if ps is not None: self._remaining_pairings = extract_remaining_pairings(ps) return self._remaining_pairings def enable_connection_notifications(self, enable=True): """Enable or disable device (dis)connection notifications on this receiver.""" if not self.handle: return False if enable: set_flag_bits = NotificationFlag.WIRELESS | NotificationFlag.SOFTWARE_PRESENT else: set_flag_bits = 0 ok = _hidpp10.set_notification_flags(self, set_flag_bits) if ok is None: logger.warning("%s: failed to %s receiver notifications", self, "enable" if enable else "disable") return None flag_bits = _hidpp10.get_notification_flags(self) if flag_bits is None: flag_names = None else: flag_names = hidpp10_constants.NotificationFlag.flag_names(flag_bits) if logger.isEnabledFor(logging.INFO): logger.info("%s: receiver notifications %s => %s", self, "enabled" if enable else "disabled", flag_names) return flag_bits def device_codename(self, n): codename = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.DEVICE_NAME + n - 1) if codename: return extract_codename(codename) def notify_devices(self): """Scan all devices.""" if self.handle: if not self.write_register(Registers.RECEIVER_CONNECTION, 0x02): logger.warning("%s: failed to trigger device link notifications", self) def notification_information(self, number, notification: HIDPPNotification) -> tuple[bool, bool, typing.Any, str]: """Extract information from unifying-style notification""" assert notification.address != 0x02 online = not bool(notification.data[0] & 0x40) encrypted = bool(notification.data[0] & 0x20) or notification.address == 0x10 kind = extract_device_kind(notification.data[0] & 0x0F) wpid = extract_wpid(notification.data[2:3] + notification.data[1:2]) return online, encrypted, wpid, kind def device_pairing_information(self, n: int) -> dict: """Return information from pairing registers (and elsewhere when necessary)""" polling_rate = "" serial = None power_switch = "(unknown)" pair_info = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.PAIRING_INFORMATION + n - 1) if pair_info: # a receiver that uses Unifying-style pairing registers wpid = extract_wpid(pair_info[3:5]) kind = extract_device_kind(pair_info[7] & 0x0F) polling_rate_ms = extract_polling_rate(pair_info) polling_rate = f"{polling_rate_ms}ms" elif not self.receiver_kind == "unifying": # may be an old Nano receiver device_info = self.read_register(Registers.RECEIVER_INFO, 0x04) # undocumented if device_info: logger.warning("using undocumented register for device wpid") wpid = extract_wpid(device_info[3:5]) kind = extract_device_kind(0x00) # unknown kind else: raise exceptions.NoSuchDevice(number=n, receiver=self, error="read pairing information - non-unifying") else: raise exceptions.NoSuchDevice(number=n, receiver=self, error="read pairing information") pair_info = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.EXTENDED_PAIRING_INFORMATION + n - 1) if pair_info: power_switch = extract_power_switch_location(pair_info) serial = extract_serial(pair_info[1:5]) else: # some Nano receivers? pair_info = self.read_register(0x2D5) # undocumented and questionable if pair_info: logger.warning("using undocumented register for device serial number") serial = extract_serial(pair_info[1:5]) return {"wpid": wpid, "kind": kind, "polling": polling_rate, "serial": serial, "power_switch": power_switch} def register_new_device(self, number, notification=None): if self._devices.get(number) is not None: raise IndexError(f"{self}: device number {int(number)} already registered") assert notification is None or notification.devnumber == number assert notification is None or notification.sub_id == Notification.DJ_PAIRING try: time.sleep(0.05) # let receiver settle info = self.device_pairing_information(number) if notification is not None: online, _e, nwpid, nkind = self.notification_information(number, notification) if info["wpid"] is None: info["wpid"] = nwpid elif nwpid is not None and info["wpid"] != nwpid: logger.warning("mismatch on device WPID %s %s", info["wpid"], nwpid) if info["kind"] is None: info["kind"] = nkind elif nkind is not None and info["kind"] != nkind: logger.warning("mismatch on device kind %s %s", info["kind"], nkind) else: online = True dev = Device(self.low_level, self, number, online, pairing_info=info, setting_callback=self.setting_callback) if logger.isEnabledFor(logging.INFO): logger.info("%s: found new device %d (%s)", self, number, dev.wpid) self._devices[number] = dev return dev except exceptions.NoSuchDevice as e: logger.warning("register new device failed for %s device %d error %s", e.receiver, e.number, e.error) logger.warning("%s: looked for device %d, not found", self, number) self._devices[number] = None def set_lock(self, lock_closed=True, device=0, timeout=0): if self.handle: action = 0x02 if lock_closed else 0x01 reply = self.write_register(Registers.RECEIVER_PAIRING, action, device, timeout) if reply: return True logger.warning("%s: failed to %s the receiver lock", self, "close" if lock_closed else "open") def count(self): count = self.read_register(Registers.RECEIVER_CONNECTION) if count is None: return 0 return extract_connection_count(count) def request(self, request_id, *params): if bool(self): return self.low_level.request(self.handle, 0xFF, request_id, *params) def reset_pairing(self): self.pairing = Pairing() def __iter__(self): connected_devices = self.count() found_devices = 0 for number in range(1, 8): # some receivers have devices past their max # devices if found_devices >= connected_devices: return if number in self._devices: dev = self._devices[number] else: dev = self.__getitem__(number) if dev is not None: found_devices += 1 yield dev def __getitem__(self, key): if not bool(self): return None dev = self._devices.get(key) if dev is not None: return dev if not isinstance(key, int): raise TypeError("key must be an integer") if key < 1 or key > 15: # some receivers have devices past their max # devices raise IndexError(key) return self.register_new_device(key) def __delitem__(self, key): self._unpair_device(key, False) def _unpair_device(self, key, force=False): key = int(key) if self._devices.get(key) is None: raise IndexError(key) dev = self._devices[key] if not dev: if key in self._devices: del self._devices[key] return if self.re_pairs and not force: # invalidate the device, but these receivers don't unpair per se dev.online = False dev.wpid = None if key in self._devices: del self._devices[key] logger.warning("%s removed device %s", self, dev) else: reply = self._unpair_device_per_receiver(key) if reply: # invalidate the device dev.online = False dev.wpid = None if key in self._devices: del self._devices[key] if logger.isEnabledFor(logging.INFO): logger.info("%s unpaired device %s", self, dev) else: logger.error("%s failed to unpair device %s", self, dev) raise Exception(f"failed to unpair device {dev.name}: {key}") def _unpair_device_per_receiver(self, key): """Receiver specific unpairing.""" return self.write_register(Registers.RECEIVER_PAIRING, 0x03, key) def force_unpair_slot(self, slot: int) -> bool: """Force-unpair a slot by writing the unpair register, ignoring cache state. Intended for clearing stale pairings on receivers (Lightspeed in particular) where Solaar cannot read pairing info for a slot. Bypasses the ``may_unpair`` and ``re_pairs`` gates that ``_unpair_device`` applies. Returns True if the register write was acknowledged by the receiver. """ if not self.handle: return False slot = int(slot) reply = self._unpair_device_per_receiver(slot) if reply: cached = self._devices.get(slot) if cached: cached.online = False cached.wpid = None if slot in self._devices: del self._devices[slot] if logger.isEnabledFor(logging.INFO): logger.info("%s force-unpaired slot %d", self, slot) return True logger.warning("%s failed to force-unpair slot %d", self, slot) return False def __len__(self): return len([d for d in self._devices.values() if d is not None]) def __contains__(self, dev): if isinstance(dev, int): return self._devices.get(dev) is not None return self.__contains__(dev.number) def __eq__(self, other): return other is not None and self.kind == other.kind and self.path == other.path def __ne__(self, other): return other is None or self.kind != other.kind or self.path != other.path def __hash__(self): return self.path.__hash__() def status_string(self): count = len(self) return ( _("No paired devices.") if count == 0 else ngettext("%(count)s paired device.", "%(count)s paired devices.", count) % {"count": count} ) def __str__(self): return "<%s(%s,%s%s)>" % ( self.name.replace(" ", ""), self.path, "" if isinstance(self.handle, int) else "T", self.handle, ) __repr__ = __str__ __bool__ = __nonzero__ = lambda self: self.handle is not None class BoltReceiver(Receiver): """Bolt receivers use a different pairing prototol and have different pairing registers""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def initialize(self, product_info: dict): serial_reply = self.read_register(Registers.BOLT_UNIQUE_ID) self.serial = extract_serial(serial_reply) self.max_devices = product_info.get("max_devices", 1) def device_codename(self, n): codename = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.BOLT_DEVICE_NAME + n, 0x01) if codename: codename = codename[3 : 3 + min(14, ord(codename[2:3]))] return codename.decode("ascii") def device_pairing_information(self, n: int) -> dict: pair_info = self.read_register(Registers.RECEIVER_INFO, InfoSubRegisters.BOLT_PAIRING_INFORMATION + n) if pair_info: wpid = extract_wpid(pair_info[3:4] + pair_info[2:3]) kind = extract_device_kind(pair_info[1] & 0x0F) serial = extract_serial(pair_info[4:8]) return {"wpid": wpid, "kind": kind, "polling": None, "serial": serial, "power_switch": "(unknown)"} else: raise exceptions.NoSuchDevice(number=n, receiver=self, error="can't read Bolt pairing register") def discover(self, cancel=False, timeout=30): """Discover Logitech Bolt devices.""" if self.handle: action = 0x02 if cancel else 0x01 reply = self.write_register(Registers.BOLT_DEVICE_DISCOVERY, timeout, action) if reply: return True logger.warning("%s: failed to %s device discovery", self, "cancel" if cancel else "start") def pair_device(self, pair=True, slot=0, address=b"\0\0\0\0\0\0", authentication=0x00, entropy=20): """Pair a Bolt device.""" if self.handle: action = 0x01 if pair is True else 0x03 if pair is False else 0x02 reply = self.write_register(Registers.BOLT_PAIRING, action, slot, address, authentication, entropy) if reply: return True logger.warning("%s: failed to %s device %s", self, "pair" if pair else "unpair", address) def _unpair_device_per_receiver(self, key): """Receiver specific unpairing.""" return self.write_register(Registers.BOLT_PAIRING, 0x03, key) class UnifyingReceiver(Receiver): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class NanoReceiver(Receiver): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class LightSpeedReceiver(Receiver): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) class Ex100Receiver(Receiver): """A very old style receiver, somewhat different from newer receivers""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def initialize(self, product_info: dict): self.serial = None self.max_devices = product_info.get("max_devices", 1) def notification_information(self, number, notification): """Extract information from 27Mz-style notification and device index""" assert notification.address == 0x02 online = True encrypted = bool(notification.data[0] & 0x80) kind = extract_device_kind(_get_kind_from_index(self, number)) wpid = "00" + extract_wpid(notification.data[2:3]) return online, encrypted, wpid, kind def device_pairing_information(self, number: int) -> dict: # extract WPID from udev path wpid = self.low_level.find_paired_node_wpid(self.path, number) if not wpid: logger.error("Unable to get wpid from udev for device %d of %s", number, self) raise exceptions.NoSuchDevice(number=number, receiver=self, error="Not present 27Mhz device") kind = extract_device_kind(_get_kind_from_index(self, number)) return {"wpid": wpid, "kind": kind, "polling": "", "serial": None, "power_switch": "(unknown)"} def _get_kind_from_index(receiver, index: int) -> int: """Get device kind from 27Mhz device index""" # From drivers/hid/hid-logitech-dj.c if index == 1: # mouse kind = 2 elif index == 2: # mouse kind = 2 elif index == 3: # keyboard kind = 1 elif index == 4: # numpad kind = 3 else: # unknown device number on 27Mhz receiver logger.error("failed to calculate device kind for device %d of %s", index, receiver) raise exceptions.NoSuchDevice(number=index, receiver=receiver, error="Unknown 27Mhz device number") return kind receiver_class_mapping = { "bolt": BoltReceiver, "unifying": UnifyingReceiver, "lightspeed": LightSpeedReceiver, "nano": NanoReceiver, "27Mhz": Ex100Receiver, } def create_receiver(low_level: LowLevelInterface, device_info, setting_callback=None) -> Optional[Receiver]: """Opens a Logitech Receiver found attached to the machine, by Linux device path.""" try: handle = low_level.open_path(device_info.path) if logger.isEnabledFor(logging.INFO): logger.info("create receiver %s %s", handle, device_info) if handle: usb_id = device_info.product_id if isinstance(usb_id, str): usb_id = int(usb_id, 16) try: product_info = low_level.product_information(usb_id) except ValueError: product_info = {} kind = product_info.get("receiver_kind", "unknown") rclass = receiver_class_mapping.get(kind, Receiver) return rclass( low_level, kind, product_info, handle, device_info.path, device_info.product_id, setting_callback, ) except OSError as e: logger.exception("open %s", device_info) if e.errno == errno.EACCES: raise e except Exception: logger.exception("open %s", device_info) Solaar-1.1.20/lib/logitech_receiver/rgb_effects_probe.py000066400000000000000000000205431522022367600232670ustar00rootroot00000000000000"""Read-only corpus probe for the headset RGB feature pair: - HEADSET_RGB_ONBOARD_EFFECTS (0x0621) - HEADSET_RGB_SIGNATURE_EFFECTS (0x0622) Logs raw response bytes and lengths at INFO so field testers without ``-dd`` can still capture the data. All calls are strictly read-side — no setters are invoked. If a feature isn't present the probe short-circuits cleanly. Pcap analysis of G HUB's color-set traffic confirmed that on 0x0621, ``setRGBClusterEffect`` (fn 0x30) takes a 10-byte payload ``[cluster, effect_id_BE_u16, R, G, B, ...]`` where ``effect_id=0x0000`` means "Static (with RGB)" — this is also the slot-0 entry in the fn 0x10 ``getRGBClusterInfo`` reply, which we decode structurally so the test corpus shows effect-id semantics in plaintext. """ from __future__ import annotations import logging from . import exceptions from .hidpp20_constants import SupportedFeature logger = logging.getLogger(__name__) def _hex_or_none(data) -> str | None: return data.hex() if data else None def _format_feature(feat) -> str: """Render a feature for the log: 0x{id:04X}{:NAME} when known, else raw. Unknown features are stored as the string "unknown:HHHH" by the feature discovery code, so handle that shape explicitly — int(feat) on those raises ValueError. Wrap the rest in a broad except so a future unhandled feature shape can't kill the whole table dump. """ if feat is None: return "?" if isinstance(feat, str): if feat.startswith("unknown:") and len(feat) > 8: return f"0x{feat[8:].upper()}" return feat try: return f"0x{int(feat):04X}:{feat.name}" except (AttributeError, TypeError, ValueError): try: return f"0x{int(feat):04X}" except (TypeError, ValueError): return repr(feat) def _log_feature_table(device) -> None: if not device.features: return try: # Parent features live in FeaturesArray.inverse, indexed by their # parent feature-set position. On Centurion devices these are the # ones the dongle itself exposes (typically 5-6 entries). parent = [] for idx in range(len(device.features)): parent.append(f"{idx}:{_format_feature(device.features[idx])}") logger.debug("RGB probe: parent features for %s: %s", device, ", ".join(parent)) # Centurion sub-device features live in FeaturesArray.sub_inverse, # keyed by sub-device feature index. These are where the actual # headset features (0x0620/0x0621/0x0622, LogiVoice, EQ, mic mute, # …) live — without dumping them the log shows only the dongle's # parent features and gives the wrong impression that the device # has nothing else. sub_inverse = getattr(device.features, "sub_inverse", None) if sub_inverse: sub = [f"{idx}:{_format_feature(feat)}" for idx, feat in sorted(sub_inverse.items())] logger.debug("RGB probe: sub-device features for %s: %s", device, ", ".join(sub)) except Exception as e: logger.debug("RGB probe: feature-table dump failed: %s", e) def _call(device, feature: SupportedFeature, fn: int, *params): """Wrap feature_request with uniform INFO logging. Returns the raw bytes on success, None on transport/no-feature, and doesn't raise — FeatureCallError is caught and logged as an error code. """ label = f"0x{int(feature):04X}.fn{fn:02X}" if params: label += "(" + ",".join(f"{b:02X}" for b in params) + ")" try: resp = device.feature_request(feature, fn, *params) except exceptions.FeatureCallError as e: logger.debug("RGB probe: %s err=0x%02X", label, getattr(e, "error", 0) & 0xFF) return None except Exception as e: logger.debug("RGB probe: %s raised %r", label, e) return None if resp is None: logger.debug("RGB probe: %s no reply (feature unsupported or transport failure)", label) return None logger.debug("RGB probe: %s resp=%s len=%d", label, _hex_or_none(resp), len(resp)) return resp # Names for known effect_ids on the headset RGB cluster. Confirmed via # pcap analysis of G HUB color-set traffic: setRGBClusterEffect with # effect_id=0x0000 + RGB writes a static color, so 0x0000 is "Static" # rather than the "Off / Disabled" we'd guessed from cluster ordering. # Other ids haven't been observed on the wire yet — names are placeholder # until further pcap traffic confirms them. _EFFECT_ID_NAMES = { 0x0000: "Static", 0x0001: "Effect 0x0001", 0x0006: "Effect 0x0006", 0x0007: "Effect 0x0007", 0x000F: "Effect 0x000F", 0x007F: "Effect 0x007F", } def _decode_cluster_info(resp) -> str | None: """Decode a 0x0621 fn 0x10 getRGBClusterInfo reply into a readable summary. Best-effort — returns None on unexpected length/shape. Observed shape on G522: 4-byte records (effect_id LE u16, slot_idx LE u16). The effect_id at slot 0 is 0x0000 = "Static" (with RGB), confirmed by pcap of G HUB color-set traffic. Records continue until trailing-zero padding. Note: most HID++ multi-byte fields are BE, but this particular response uses LE — confirmed against captured factory-default bytes on G522 where the values 0x0001 / 0x000F / 0x007F appear at byte 0 of each record with byte 1 = 0x00 (consistent with LE u16). """ if not resp or len(resp) < 4: return None effects = [] seen_static = False for i in range(0, len(resp) - 3, 4): eid = resp[i] | (resp[i + 1] << 8) slot = resp[i + 2] | (resp[i + 3] << 8) # Skip purely-zero padding once we've seen the (effect=0, slot=0) entry. if eid == 0 and slot == 0: if seen_static: continue seen_static = True name = _EFFECT_ID_NAMES.get(eid, f"0x{eid:04X}") effects.append(f"slot={slot}:{name}") return ", ".join(effects) if effects else None def probe_onboard_effects(device) -> None: """Probe 0x0621 RGBOnboardEffects read-side functions.""" feature = SupportedFeature.HEADSET_RGB_ONBOARD_EFFECTS if not device.features or feature not in device.features: return logger.debug("RGB probe: 0x0621 HEADSET_RGB_ONBOARD_EFFECTS present on %s", device) # fn 0x00 getInfo — empty payload _call(device, feature, 0x00) # fn 0x10 getRGBClusterInfo — iterate cluster indexes 0..7, stop on error. for cluster_idx in range(8): resp = _call(device, feature, 0x10, cluster_idx) if resp is None: break decoded = _decode_cluster_info(resp) if decoded: logger.debug("RGB probe: 0x0621.fn10(%02X) decoded: %s", cluster_idx, decoded) # fn 0x20 getRGBClusterEffect — current state per cluster. for cluster_idx in range(8): resp = _call(device, feature, 0x20, cluster_idx) if resp is None: break # fn 0x40 getRGBCustomEffectName — single call, documented. _call(device, feature, 0x40) def probe_signature_effects(device) -> None: """Probe 0x0622 RGBSignatureEffects read-side functions.""" feature = SupportedFeature.HEADSET_RGB_SIGNATURE_EFFECTS if not device.features or feature not in device.features: return logger.debug("RGB probe: 0x0622 HEADSET_RGB_SIGNATURE_EFFECTS present on %s", device) # fn 0x00 getSignatureEffectsInfo. _call(device, feature, 0x00) # fn 0x10 getSignatureEffectParams — iterate effectId 0..2 (Startup/Shutdown/Passive). # effectId is u16 BE. for eid in range(3): _call(device, feature, 0x10, (eid >> 8) & 0xFF, eid & 0xFF) # fn 0x30 getSignatureEffectState — same effectId range. for eid in range(3): _call(device, feature, 0x30, (eid >> 8) & 0xFF, eid & 0xFF) def probe(device) -> None: """Run both read-only RGB-effects probes once per device. Gated via ``_rgb_effects_probed`` so re-entry on reconnect / setting rebuild doesn't spam the log with duplicate corpus dumps. """ if getattr(device, "_rgb_effects_probed", False): return device._rgb_effects_probed = True _log_feature_table(device) try: probe_onboard_effects(device) except Exception as e: logger.debug("RGB probe: onboard-effects probe raised %r", e) try: probe_signature_effects(device) except Exception as e: logger.debug("RGB probe: signature-effects probe raised %r", e) Solaar-1.1.20/lib/logitech_receiver/rgb_power.py000066400000000000000000001222251522022367600216150ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Software-driven RGB power management for devices that hand off LED control to the host (RGB_EFFECTS / 0x8071). Handles the firmware onUserActivity events, the two-stage idle effect (smooth dim ramp or animation), and the software sleep timer that fires after idle_timeout has elapsed. """ from __future__ import annotations import logging from time import sleep from . import exceptions from . import hidpp20_constants from . import settings from . import special_keys from .hidpp20_constants import SupportedFeature logger = logging.getLogger(__name__) try: from gi.repository import GLib _has_glib = True except ImportError: _has_glib = False # SetSWControl flag bits for RGB_EFFECTS (0x8071). FLAG_EFFECT = 0x01 FLAG_POWER = 0x02 FLAG_NVCONFIG = 0x04 # SetSWControl payloads: [subfn=set, mode=3, flags] SW_ACTIVE = bytes([0x01, 0x03, FLAG_NVCONFIG]) # firmware monitors idle SW_IDLE = bytes([0x01, 0x03, FLAG_POWER]) # firmware monitors activity SW_RELEASE = bytes([0x01, 0x00, 0x00]) _managers = {} # keyed by id(device) def get_manager(device): """Return the active RGBPowerManager for `device`, or None.""" return _managers.get(id(device)) def on_user_activity(device, activity_type): """Dispatch firmware onUserActivity events to the device's power manager.""" mgr = _managers.get(id(device)) if mgr: mgr.on_user_activity(activity_type) def translate_color_for_display(color, state, dim_pct, dim_step, dim_steps): """Map a saved (undimmed) color to the display color for `state`. Returns None for SLEEPING.""" if state == RGBPowerManager.ACTIVE: return color if state == RGBPowerManager.SLEEPING: return None target = RGBPowerManager._compute_dim_color(color, dim_pct) if state == RGBPowerManager.IDLE: return target # DIMMING — interpolate from saved toward dimmed target by ramp progress. t = (dim_step / dim_steps) if dim_steps else 1.0 return RGBPowerManager._interpolate_color(color, target, t) def translate_for_device(device, color): """Translate `color` through the device's RGBPowerManager state, or return it unchanged when no manager is registered. None signals SLEEPING.""" mgr = _managers.get(id(device)) if mgr is None: return color return mgr.translate_color(color) _EFFECT_STATIC = 0x01 def perkey_has_paint(device): """Return ``(perkey_setting, has_paint)``. has_paint is True when the per-key buffer has at least one real color and the user hasn't opted out via the lock icon (sensitivity == IGNORE). The locked-but-applied state (False) still counts as paint.""" perkey = None for s in getattr(device, "settings", []) or []: if s.name == "per-key-lighting": perkey = s break if perkey is None: return None, False validator = getattr(perkey, "_validator", None) choices = getattr(validator, "choices", None) if not choices: return perkey, False # Apply path runs rgb_zone_ before per-key, so _value may still be None # when this gate is consulted — fall back to the persister. value = getattr(perkey, "_value", None) persister = getattr(device, "persister", None) if value is None and persister is not None: value = persister.get("per-key-lighting") if not value: return perkey, False no_change = special_keys.COLORSPLUS["No change"] if not any(c != no_change and isinstance(c, int) and c >= 0 for c in value.values()): return perkey, False if persister is not None and persister.get_sensitivity("per-key-lighting") == settings.SENSITIVITY_IGNORE: return perkey, False return perkey, True def zone_effect_is_static(device): """True when the persisted zone effect is Static, or when no rgb_zone_* setting exists at all (per-key-only hardware).""" has_zone = False persister = getattr(device, "persister", None) for s in getattr(device, "settings", []) or []: if s.name.startswith("rgb_zone_"): has_zone = True value = getattr(s, "_value", None) if value is None and persister is not None: value = persister.get(s.name) if value is not None and int(getattr(value, "ID", 0) or 0) == _EFFECT_STATIC: return True return not has_zone def zone_effect_is_ignored(device): """True when every rgb_zone_* setting on `device` is marked SENSITIVITY_IGNORE in the persister.""" persister = getattr(device, "persister", None) if persister is None: return False zones = [s for s in getattr(device, "settings", []) or [] if s.name.startswith("rgb_zone_")] if not zones: return False return all(persister.get_sensitivity(s.name) == settings.SENSITIVITY_IGNORE for s in zones) def effective_zone_base_color(device): """Color to use for per-key unset cells: 0 (off/black) when the zone effect is ignored (or unavailable), the persisted zone color otherwise. Reads through the persister so we still get the saved color even before apply has populated _value. During an idle-Static transition the saved color is substituted with the idle effect's color so unset cells track the idle primary. Reverts on wake when state returns to ACTIVE.""" if zone_effect_is_ignored(device): return 0 mgr = _managers.get(id(device)) if mgr is not None and mgr._state == RGBPowerManager.IDLE and mgr._idle_effect_id() == 0x01: return int(getattr(mgr._idle_effect, "color", 0) or 0) persister = getattr(device, "persister", None) for s in getattr(device, "settings", []) or []: if not s.name.startswith("rgb_zone_"): continue value = getattr(s, "_value", None) if value is None and persister is not None: value = persister.get(s.name) if value is not None: color = getattr(value, "color", None) if isinstance(color, int): return int(color) return 0 _RETRY_BUSY_BACKOFF_MS = (30, 60, 90) def feature_request_acked(device, feature, function, data=b"", retries=3): """feature_request with BUSY/timeout retries. Returns reply bytes on ACK, None on hard failure (logged WARNING).""" busy_attempt = 0 max_busy = len(_RETRY_BUSY_BACKOFF_MS) for attempt in range(retries + 1): try: reply = device.feature_request(feature, function, data) except exceptions.FeatureCallError as e: if getattr(e, "error", None) == hidpp20_constants.ErrorCode.BUSY and busy_attempt < max_busy: delay_ms = _RETRY_BUSY_BACKOFF_MS[busy_attempt] busy_attempt += 1 if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: feature 0x%04x fn 0x%02x BUSY, retry %d/%d after %dms", device, int(feature), function, busy_attempt, max_busy, delay_ms, ) sleep(delay_ms / 1000.0) continue logger.warning("%s: feature 0x%04x fn 0x%02x rejected: %s", device, int(feature), function, e) return None if reply is not None: if (attempt > 0 or busy_attempt > 0) and logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: feature 0x%04x fn 0x%02x succeeded after %d timeout retries, %d BUSY retries", device, int(feature), function, attempt, busy_attempt, ) return reply if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: feature 0x%04x fn 0x%02x timed out (attempt %d/%d)", device, int(feature), function, attempt + 1, retries + 1, ) logger.warning("%s: feature 0x%04x fn 0x%02x no ACK after %d attempts", device, int(feature), function, retries + 1) return None def _probe_tmpl_bytes(device): """GetEffectSpecificInfo page 1: returns (tmpl_0, tmpl_1) or (None, None) if the device has no firmware effect cards.""" try: reply = device.feature_request(SupportedFeature.RGB_EFFECTS, 0x00, 0xFF, 0x00, 0x01, 0x00, 0x01) except exceptions.FeatureCallError: return (None, None) if reply is None or len(reply) < 12: return (None, None) return (reply[10], reply[11]) def push_artanis_perkey_prep(device): """Disable the firmware effects engine on mice with firmware effect cards. Returns True if the call ACKed.""" infos = getattr(device, "led_effects", None) if not infos or not infos.zones: return False num_effects = len(infos.zones[0].effects) # SetEffectByIndex: cluster + effectIdx + 10 param bytes + persist. # Shipping with call 2 only — sufficient on tested hardware (G502 X PLUS). # Call 1 (TMPL-handshake) left commented for reactivation if broader # testing turns up a device that needs it; uncomment the _probe_tmpl_bytes # use and the call1 block together. # tmpl_0, tmpl_1 = _probe_tmpl_bytes(device) # if tmpl_0 is None: # return False # call1 = b"\xff\x02" + b"\x00" * 6 + bytes([tmpl_0, tmpl_1]) + b"\x00\x00" + b"\x01" # if feature_request_acked(device, SupportedFeature.RGB_EFFECTS, 0x10, call1) is None: # return False call2 = b"\xff" + bytes([num_effects]) + b"\x00" * 10 + b"\x01" return feature_request_acked(device, SupportedFeature.RGB_EFFECTS, 0x10, call2) is not None def start(device): """Begin software RGB power management for `device`. No-op without GLib.""" if not _has_glib: return key = id(device) if key not in _managers: mgr = RGBPowerManager(device) _managers[key] = mgr mgr.start() else: mgr = _managers[key] mgr.reset() # Push persisted settings into the manager. Settings marked ignore via the # lock icon are skipped so the manager keeps its built-in default. from . import hidpp20 persister = getattr(device, "persister", None) def _ignored(name): return persister is not None and persister.get_sensitivity(name) == settings.SENSITIVITY_IGNORE for s in device.settings: if _ignored(s.name): continue if s.name == "rgb_idle_timeout": val = s._value if s._value is not None else 60 mgr.set_idle_timeout(int(val)) elif s.name == "rgb_sleep_timeout": val = s._value if s._value is not None else 300 mgr.set_sleep_timeout(int(val)) elif s.name == "rgb_idle_effect": val = s._value if s._value is not None else hidpp20.LEDEffectSetting(ID=0x80, intensity=50) mgr.set_idle_effect(val) def stop(device): """End software RGB power management for `device`.""" key = id(device) mgr = _managers.pop(key, None) if mgr: mgr.stop() def cleanup(device): """device.cleanups handler — restore firmware control on device close. On devices that support NvConfig cap 0x0040 (shutdown effect), also fires SetRgbPowerMode(0) as the final step so the firmware plays the configured shutdown animation during the active→off transition. If the cap is disabled, the firmware powers down LEDs silently. Matches LGHUB exit. See solaar_shutdown_effect_trigger_spec.md. rgb_control is the gate: when LED Control is off, skip every wire write here. We never claimed, so there's nothing to release; firing the shutdown animation would visibly contradict the user's "leave my lighting alone". """ stop(device) if any(s.name == "rgb_control" and not s._value for s in getattr(device, "settings", []) or []): return try: device.feature_request(SupportedFeature.RGB_EFFECTS, 0x50, SW_RELEASE) if device.features and SupportedFeature.PROFILE_MANAGEMENT in device.features: device.feature_request(SupportedFeature.PROFILE_MANAGEMENT, 0x60, b"\x03") elif device.features and SupportedFeature.ONBOARD_PROFILES in device.features: device.feature_request(SupportedFeature.ONBOARD_PROFILES, 0x10, b"\x01") except Exception: pass # Device may already be offline if getattr(device, "_rgb_has_shutdown_cap", False): try: # SetRgbPowerMode(set=1, mode=0) — firmware off transition. # no_reply: device goes offline; don't block waiting for an ACK. device.feature_request(SupportedFeature.RGB_EFFECTS, 0x90, b"\x01\x00", no_reply=True) except Exception: pass class RGBPowerManager: """Two-stage idle handler driven by firmware onUserActivity events. State machine: ACTIVE → DIMMING → IDLE → SLEEPING. Stage 1 (idle) runs a host-side dim ramp or hands off to a firmware animation. Stage 2 (sleep) is a software timer that fires sleep_timeout - idle_timeout after IDLE. """ ACTIVE = 0 DIMMING = 1 IDLE = 2 SLEEPING = 3 _DIM_INTERVAL_MS = 200 _DIM_STEPS = 25 # ~5s dim ramp def __init__(self, device): self._device = device self._state = self.ACTIVE self._idle_timeout = 60 self._sleep_timeout = 300 # LEDEffectSetting with ID in {0x00 Disabled, 0x80 Dim, 0x0A # Breathe, 0x0B Ripple}. Populated by start() from the persister. self._idle_effect = None self._sleep_timer_id = None self._dim_timer_id = None self._dim_step = 0 self._dim_zones = [] self._dim_perkey = None def start(self): self._state = self.ACTIVE self._read_firmware_timers() if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: RGB power manager started (firmware idle=%ds, sleep=%ds)", self._device, self._idle_timeout, self._sleep_timeout, ) def stop(self): self._cancel_dim_timer() self._cancel_sleep_timer() if self._state != self.ACTIVE: try: self._wake() except Exception: pass # Best effort during shutdown if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: RGB power manager stopped", self._device) def reset(self): """Reset to ACTIVE on device reconnect. Re-reads firmware timers so externally-updated values (other tool wrote NV between sessions) are picked up even when our settings are ignored.""" self._cancel_dim_timer() self._cancel_sleep_timer() self._state = self.ACTIVE self._read_firmware_timers() if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: RGB power manager reset to ACTIVE", self._device) def set_idle_timeout(self, seconds): self._idle_timeout = seconds self._cancel_sleep_timer() if seconds == 0 and self._state in (self.DIMMING, self.IDLE): self._wake() self._write_firmware_idle_timeout(seconds) if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: RGB idle timeout set to %ss", self._device, seconds) def set_sleep_timeout(self, seconds): """0 disables sleep.""" self._sleep_timeout = seconds self._cancel_sleep_timer() if seconds == 0 and self._state == self.SLEEPING: self._wake() if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: RGB sleep timeout set to %ss", self._device, seconds) def set_idle_effect(self, effect): """`effect` is an LEDEffectSetting. Wake immediately if the user switched to Disabled while we're mid-idle.""" self._idle_effect = effect if self._idle_effect_id() == 0x00 and self._state in (self.DIMMING, self.IDLE): self._wake() if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: RGB idle effect set to ID=0x%02X (period=%s, intensity=%s)", self._device, self._idle_effect_id(), getattr(self._idle_effect, "period", None), getattr(self._idle_effect, "intensity", None), ) def _idle_effect_id(self): """Return the ID of the current idle effect, or 0 if unset.""" return int(getattr(self._idle_effect, "ID", 0) or 0) # --- Firmware activity events --- def on_user_activity(self, activity_type): """Handle firmware onUserActivity event from RGB_EFFECTS (0x8071). activity_type=0: IDLE — user stopped typing, firmware idle timer expired. activity_type!=0: ACTIVE — user resumed typing after being idle. The firmware sends a burst of ~8 events with exponential backoff. Only the first event matters; subsequent events for the same transition are ignored. """ if not self._device.online: return if activity_type == 0: # IDLE event — firmware detected inactivity at idle_timeout if self._state != self.ACTIVE: return # Already idle/dimming/sleeping, ignore burst if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: firmware IDLE event — starting idle sequence", self._device) # Switch to flags=3 so firmware monitors for activity during dim/idle try: self._device.feature_request(SupportedFeature.RGB_EFFECTS, 0x50, SW_IDLE) except Exception: pass idle_enabled = self._idle_effect_id() != 0 and self._idle_timeout > 0 and not self._is_ignored("rgb_idle_effect") if idle_enabled: self._start_idle_effect() else: self._state = self.IDLE # Sleep is host-driven only — schedule whenever _sleep_timeout > 0, # regardless of the setting's ignore flag (which only blocks pushing # the user value to firmware, see start()). sleep_enabled = self._sleep_timeout > 0 if sleep_enabled: delay = max(self._sleep_timeout - self._idle_timeout, 0) if delay == 0: self._start_sleep() else: self._sleep_timer_id = GLib.timeout_add_seconds(delay, self._sleep_timer_fired) if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: sleep timer scheduled in %ds", self._device, delay) else: # ACTIVE event — user resumed typing if self._state == self.ACTIVE: return # Already active, ignore burst if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: firmware ACTIVE event — waking", self._device) self._cancel_sleep_timer() self._wake() def _sleep_timer_fired(self): """GLib callback — software sleep timer expired after IDLE.""" self._sleep_timer_id = None if self._state in (self.IDLE, self.DIMMING) and self._device.online: self._start_sleep() return False # One-shot timer def _cancel_sleep_timer(self): if self._sleep_timer_id is not None: GLib.source_remove(self._sleep_timer_id) self._sleep_timer_id = None def _read_firmware_timers(self): """Read idle/sleep timeouts from firmware as the manager's defaults.""" try: resp = self._device.feature_request(SupportedFeature.RGB_EFFECTS, 0x70, b"\x00") if resp and len(resp) >= 7: idle_s = (resp[3] << 8) | resp[4] sleep_s = (resp[5] << 8) | resp[6] if idle_s > 0: self._idle_timeout = idle_s if sleep_s > 0: self._sleep_timeout = sleep_s if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: firmware timers: idle=%ds, sleep=%ds", self._device, idle_s, sleep_s, ) except Exception as e: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: could not read firmware timers, using defaults: %s", self._device, e) def _write_firmware_idle_timeout(self, seconds): """Push idle/sleep timeouts back to firmware so it fires IDLE on time.""" try: idle_hi = (seconds >> 8) & 0xFF idle_lo = seconds & 0xFF sleep_hi = (self._sleep_timeout >> 8) & 0xFF sleep_lo = self._sleep_timeout & 0xFF payload = bytes([0x01, 0x00, 0x00, idle_hi, idle_lo, sleep_hi, sleep_lo]) self._device.feature_request(SupportedFeature.RGB_EFFECTS, 0x70, payload) except Exception as e: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: could not write firmware idle timeout: %s", self._device, e) # --- Idle effect --- def _start_idle_effect(self): idle_id = self._idle_effect_id() if idle_id == 0x80: # Dim dim_pct = int(getattr(self._idle_effect, "intensity", 50) or 50) self._start_dim_ramp(dim_pct) elif idle_id == 0x01: # Static — snap to idle color self._start_static_idle() elif idle_id != 0x00: self._apply_animation(idle_id) def _start_static_idle(self): """Snap to the idle effect's color exactly as if the user had set the active Static zone color to it. Per-key paint continues to display; unset cells repaint to the idle primary color via effective_zone_base_color's IDLE-state substitution. No animation — instant transition. Wake reverts via _restore_colors().""" idle_color = int(getattr(self._idle_effect, "color", 0) or 0) infos = getattr(self._device, "led_effects", None) if not infos or not infos.zones: self._state = self.IDLE return self._state = self.IDLE perkey_setting, has_paint = perkey_has_paint(self._device) perkey_dominates = has_paint and zone_effect_is_static(self._device) if perkey_dominates and perkey_setting is not None: # Per-key is the visible layer — repaint unset cells with the # idle color (effective_zone_base_color now returns it because # state == IDLE and idle effect ID == Static). try: if perkey_setting._fill_unset_zones_with_base_color(): perkey_setting._send_with_retry(0x70, b"\x00") # FrameEnd except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: static idle per-key repaint failed: %s", self._device, e) return # Zone is the visible layer — push Static at idle.color to each zone. for zone in infos.zones: if 0x01 in (e.ID for e in zone.effects): try: self._push_static_effect(zone, idle_color) except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: static idle zone push failed: %s", self._device, e) def _start_dim_ramp(self, dim_pct): """Smooth ~5s dim ramp. Dims the per-key buffer when it's the visible layer (any real per-key paint), otherwise the zone effect.""" infos = getattr(self._device, "led_effects", None) if not infos or not infos.zones: self._state = self.IDLE return perkey_setting, has_paint = perkey_has_paint(self._device) # Per-key only dominates when zone is Static. Under animations, the # firmware engine owns the visible layer — dim the zone instead. perkey_active = has_paint and zone_effect_is_static(self._device) self._dim_perkey = None if perkey_active: self._dim_zones = [] self._dim_perkey = self._build_full_perkey_dim_map(perkey_setting, dim_pct) if self._dim_perkey: # Push base color to unset cells first so they don't start from stale. self._init_unset_perkey_zones(perkey_setting) else: self._dim_zones = [] for zone in infos.zones: if 0x01 in (e.ID for e in zone.effects): start_color = self._get_zone_color(zone) target_color = self._compute_dim_color(start_color, dim_pct) self._dim_zones.append((zone, start_color, target_color)) if not self._dim_zones and not self._dim_perkey: self._state = self.IDLE return self._dim_step = 0 self._state = self.DIMMING self._dim_timer_id = GLib.timeout_add(self._DIM_INTERVAL_MS, self._dim_ramp_step) if logger.isEnabledFor(logging.DEBUG): n_zones = len(self._dim_zones) n_perkey = len(self._dim_perkey) if self._dim_perkey else 0 logger.debug( "%s: starting dim ramp to %d%% brightness (%d zones, %d per-key%s)", self._device, dim_pct, n_zones, n_perkey, ", per-key masking zones" if perkey_active else "", ) def _dim_ramp_step(self): if self._state != self.DIMMING or not self._device.online: self._dim_timer_id = None return False self._dim_step += 1 t = self._dim_step / self._DIM_STEPS for zone, start_color, target_color in self._dim_zones: try: self._push_static_effect(zone, self._interpolate_color(start_color, target_color, t)) except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: dim ramp step failed for zone %s: %s", self._device, zone.index, e) if self._dim_perkey: try: self._push_perkey_dimmed(t) except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: dim ramp step failed for per-key: %s", self._device, e) if self._dim_step >= self._DIM_STEPS: self._state = self.IDLE self._dim_timer_id = None return False return True def _push_static_effect(self, zone, color): """Non-persistent Static effect, one zone.""" static_effect = next((e for e in zone.effects if e.ID == 0x01), None) if static_effect is None: return r = (color >> 16) & 0xFF g = (color >> 8) & 0xFF b = color & 0xFF params = bytes([r, g, b, 0, 0, 0, 0, 0, 0, 0]) payload = bytes([zone.index, static_effect.index]) + params + b"\x01" self._device.feature_request(SupportedFeature.RGB_EFFECTS, 0x10, payload) def _push_perkey_dimmed(self, t): """Push interpolated per-key colors for one dim ramp step. Groups keys by their interpolated color and uses SetRgbZonesSingleValue (0x8081 function 6) for efficient bulk writes — up to 13 zone IDs per HID message when multiple keys share the same dimmed color. """ # Build color -> [zone_ids] map for this interpolation step color_groups = {} for zone_id, (start_color, target_color) in self._dim_perkey.items(): color = self._interpolate_color(start_color, target_color, t) if color not in color_groups: color_groups[color] = [] color_groups[color].append(zone_id) feat = SupportedFeature.PER_KEY_LIGHTING_V2 for color, zone_ids in color_groups.items(): r = (color >> 16) & 0xFF g = (color >> 8) & 0xFF b = color & 0xFF # Function 6: SetRgbZonesSingleValue — color(3) + zone_ids (up to 13 per report) while zone_ids: batch = zone_ids[:13] zone_ids = zone_ids[13:] data = bytes([r, g, b]) + bytes(batch) self._device.feature_request(feat, 0x60, data) # Commit the frame self._device.feature_request(feat, 0x70, b"\x00\x00\x00\x00\x00") def _apply_animation(self, effect_id): """Hand off to a firmware animation. Generic over any effect in hidpp20.LEDEffects: builds the 10-byte param block from the effect's param map, sourcing color from the zone and other params from the persisted _idle_effect.""" from . import hidpp20 infos = getattr(self._device, "led_effects", None) if not infos or not infos.zones: self._state = self.IDLE return entry = hidpp20.LEDEffects.get(effect_id) if entry is None: self._state = self.IDLE return param_map = entry[1] for zone in infos.zones: effect_info = next((e for e in zone.effects if e.ID == effect_id), None) if effect_info is None: continue color = self._get_zone_color(zone) params = bytearray(10) if hidpp20.LEDParam.color in param_map: offset = param_map[hidpp20.LEDParam.color] params[offset] = (color >> 16) & 0xFF params[offset + 1] = (color >> 8) & 0xFF params[offset + 2] = color & 0xFF for pname, poff in param_map.items(): if pname == hidpp20.LEDParam.color: continue psize = hidpp20.LEDParamSize.get(pname, 1) user_val = getattr(self._idle_effect, str(pname), None) if user_val is None: user_val = effect_info.period or 3000 if pname == hidpp20.LEDParam.period else 0 params[poff : poff + psize] = int(user_val).to_bytes(psize, "big") if effect_id == 0x01: params[3] = 0x02 # Static fixed-color marker payload = bytes([zone.index, effect_info.index]) + bytes(params) + b"\x01" try: self._device.feature_request(SupportedFeature.RGB_EFFECTS, 0x10, payload) except Exception as exc: if logger.isEnabledFor(logging.WARNING): logger.warning( "%s: failed to apply animation 0x%02x to zone %d: %s", self._device, effect_id, zone.index, exc, ) self._state = self.IDLE # --- Sleep --- def _start_sleep(self): """Enter firmware-managed sleep. Firmware fades from current level.""" self._cancel_dim_timer() try: self._device.feature_request(SupportedFeature.RGB_EFFECTS, 0x80, b"\x01\x03\x00") self._state = self.SLEEPING if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: RGB entering sleep (firmware power-down)", self._device) except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: failed to enter RGB sleep: %s", self._device, e) # --- Wake --- def _wake(self): """Restore full lighting from any non-ACTIVE state.""" if self._state == self.ACTIVE: return prev_state = self._state self._cancel_dim_timer() self._cancel_sleep_timer() # State must be ACTIVE before _restore_colors() — the paint paths # translate through it, and writes would otherwise go at the old dim. self._state = self.ACTIVE try: if prev_state == self.SLEEPING: self._set_power_mode_with_retry(1) # Re-claim full LED pipeline control self._device.feature_request(SupportedFeature.RGB_EFFECTS, 0x50, SW_ACTIVE) # Firmware engine has re-engaged during sleep — re-arm per-key # one-shots so the next write re-fires the prep + double-send. for s in self._device.settings: if s.name == "per-key-lighting": s._frame_settled = False s._prep_pushed = False break self._restore_colors() if logger.isEnabledFor(logging.DEBUG): state_names = {self.DIMMING: "dimming", self.IDLE: "idle", self.SLEEPING: "sleep"} logger.debug("%s: RGB woken from %s", self._device, state_names.get(prev_state, "unknown")) except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: failed to wake RGB LEDs: %s", self._device, e) def _cancel_dim_timer(self): if self._dim_timer_id is not None: GLib.source_remove(self._dim_timer_id) self._dim_timer_id = None def _get_zone_color(self, zone): location = int(zone.location) setting_name = f"rgb_zone_{location}" for s in self._device.settings: if s.name == setting_name and s._value is not None: return getattr(s._value, "color", 0xFFFFFF) return 0xFFFFFF def _get_zone_base_color(self): """Color used as the base for unset per-key cells. Black when the zone effect is marked ignore, the saved zone color otherwise.""" return effective_zone_base_color(self._device) @staticmethod def _has_real_perkey_colors(perkey_setting): if not perkey_setting._value: return False no_change = special_keys.COLORSPLUS["No change"] return any(color != no_change and isinstance(color, int) and color >= 0 for color in perkey_setting._value.values()) def _build_full_perkey_dim_map(self, perkey_setting, dim_pct): """{zone_id: (start, target)} for every zone — user-set keys from their color, unset from the zone base.""" no_change = special_keys.COLORSPLUS["No change"] zone_base = self._get_zone_base_color() user_colors = {int(k): c for k, c in perkey_setting._value.items() if c != no_change and isinstance(c, int) and c >= 0} return { int(k): (start, self._compute_dim_color(start, dim_pct)) for k in perkey_setting._validator.choices for start in (user_colors.get(int(k), zone_base),) } def _init_unset_perkey_zones(self, perkey_setting): """Push the zone base color to per-key cells the user hasn't painted — avoids the white-default flash when per-key takes over the buffer.""" no_change = special_keys.COLORSPLUS["No change"] zone_base = self._get_zone_base_color() r = (zone_base >> 16) & 0xFF g = (zone_base >> 8) & 0xFF b = zone_base & 0xFF user_set = {int(k) for k, c in perkey_setting._value.items() if c != no_change and isinstance(c, int) and c >= 0} unset_zones = [int(k) for k in perkey_setting._validator.choices if int(k) not in user_set] if not unset_zones: return feat = SupportedFeature.PER_KEY_LIGHTING_V2 remaining = list(unset_zones) try: while remaining: batch = remaining[:13] remaining = remaining[13:] self._device.feature_request(feat, 0x60, bytes([r, g, b]) + bytes(batch)) self._device.feature_request(feat, 0x70, b"\x00\x00\x00\x00\x00") except exceptions.FeatureCallError as e: logger.warning("%s: per-key zone init failed (device busy?): %s", self._device, e) @staticmethod def _compute_dim_color(color, dim_pct): r = ((color >> 16) & 0xFF) * dim_pct // 100 g = ((color >> 8) & 0xFF) * dim_pct // 100 b = (color & 0xFF) * dim_pct // 100 return (r << 16) | (g << 8) | b @staticmethod def _interpolate_color(start, target, t): r_s, g_s, b_s = (start >> 16) & 0xFF, (start >> 8) & 0xFF, start & 0xFF r_t, g_t, b_t = (target >> 16) & 0xFF, (target >> 8) & 0xFF, target & 0xFF r = int(r_s + (r_t - r_s) * t) g = int(g_s + (g_t - g_s) * t) b = int(b_s + (b_t - b_s) * t) return (r << 16) | (g << 8) | b def _current_dim_pct(self): """100 unless we're in Dim mode — animations run at firmware brightness.""" if self._idle_effect_id() != 0x80: return 100 return int(getattr(self._idle_effect, "intensity", 50) or 50) def translate_color(self, color): """Map a saved (undimmed) per-key color to what should be displayed on the device right now, given the current power-management state. Returns None to signal SLEEPING — caller should persist and skip the wire write; _restore_colors on wake will re-push the saved value.""" # Static idle is a color swap, not a brightness change — user-painted # cells render their saved color unchanged, and the unset-cell # substitution happens upstream via effective_zone_base_color. if self._state == self.IDLE and self._idle_effect_id() == 0x01: return color return translate_color_for_display(color, self._state, self._current_dim_pct(), self._dim_step, self._DIM_STEPS) def notify_perkey_changed(self, zone_id, new_color): """Resync a per-key zone's dim ramp entry to a user-repainted color.""" if self._state != self.DIMMING or not self._dim_perkey or zone_id not in self._dim_perkey: return self._dim_perkey[zone_id] = ( new_color, self._compute_dim_color(new_color, self._current_dim_pct()), ) def notify_perkey_bulk_changed(self, color_map): """Bulk notify_perkey_changed, skipping 'No change' entries.""" if self._state != self.DIMMING or not self._dim_perkey: return no_change = special_keys.COLORSPLUS["No change"] for zone_id, color in color_map.items(): if color == no_change or not isinstance(color, int) or color < 0: continue self.notify_perkey_changed(int(zone_id), int(color)) def notify_zone_changed(self, cluster_index, new_color): """Resync a zone-effect dim ramp entry to a user-repainted color.""" if self._state != self.DIMMING or not self._dim_zones: return dim_pct = self._current_dim_pct() for i, (zone, _start, _target) in enumerate(self._dim_zones): if int(zone.index) == int(cluster_index): self._dim_zones[i] = (zone, new_color, self._compute_dim_color(new_color, dim_pct)) return def _set_power_mode_with_retry(self, mode): """First command after wake may fail; retry.""" params = bytes([0x01, mode, 0x00]) for attempt in range(3): try: self._device.feature_request(SupportedFeature.RGB_EFFECTS, 0x80, params) return except Exception: if attempt == 2: raise import time as _time _time.sleep(0.1) def _is_ignored(self, setting_name): """True if marked ignore via the lock icon.""" persister = getattr(self._device, "persister", None) if persister is None: return False return persister.get_sensitivity(setting_name) == settings.SENSITIVITY_IGNORE def _restore_colors(self): """Re-push lighting state after waking. Per-key dominates only when zone is Static — under animations, the zone wire push goes through and per-key is skipped.""" _perkey_setting, has_paint = perkey_has_paint(self._device) zone_static = zone_effect_is_static(self._device) perkey_dominates = has_paint and zone_static for s in self._device.settings: if s._value is None: continue if self._is_ignored(s.name): continue if s.name == "per-key-lighting": if not self._has_real_perkey_colors(s): continue if not zone_static: continue # firmware animation owns the visible layer elif s.name.startswith("rgb_zone_"): if perkey_dominates: continue else: continue try: s.write(s._value, save=False) if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: restored %s after wake", self._device, s.name) except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: failed to restore %s: %s", self._device, s.name, e) Solaar-1.1.20/lib/logitech_receiver/settings.py000066400000000000000000001102121522022367600214600ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import logging import struct import time from enum import IntEnum from typing import Any from solaar.i18n import _ from . import common from . import hidpp20_constants from . import settings_validator from .centurion_constants import CenturionCoreFeature from .common import NamedInt logger = logging.getLogger(__name__) SENSITIVITY_IGNORE = "ignore" class Kind(IntEnum): NONE = 0 TOGGLE = 0x01 CHOICE = 0x02 RANGE = 0x04 MAP_CHOICE = 0x0A MULTIPLE_TOGGLE = 0x10 PACKED_RANGE = 0x20 GRAPHIC_EQ = 0x21 MULTIPLE_RANGE = 0x40 HETERO = 0x80 MAP_RANGE = 0x102 COLOR = 0x200 class Setting: """A setting descriptor. Needs to be instantiated for each specific device.""" name = label = description = "" feature = register = kind = None min_version = 0 persist = True rw_options = {} validator_class = None validator_options = {} display = True # display setting in UI # Set False for settings whose value cannot be read back from the device # (e.g. PerKeyLighting — the 0x8081 protocol has no GetIndividualRgbZones). # `solaar show` uses this to suppress the "(live)" output line that would # otherwise print a fabricated value misleadingly. live_readable = True # Optional UI editor override as "module.path:ClassName". Resolved by the # config panel before the Kind dispatch. Kept as a string so this module # stays free of GTK imports — the FE/BE seam is preserved. editor_class: str | None = None def __init__(self, device, rw, validator): self._device = device self._rw = rw self._validator = validator self.kind = getattr(self._validator, "kind", None) self._value = None @classmethod def build(cls, device): assert cls.feature or cls.register, "Settings require either a feature or a register" rw_class = cls.rw_class if hasattr(cls, "rw_class") else FeatureRW if cls.feature else RegisterRW rw = rw_class(cls.feature if cls.feature else cls.register, **cls.rw_options) p = device.protocol if p == 1.0: # HID++ 1.0 devices do not support features assert rw.kind == RegisterRW.kind elif p >= 2.0: # HID++ 2.0 devices do not support registers assert rw.kind == FeatureRW.kind validator_class = cls.validator_class validator = validator_class.build(cls, device, **cls.validator_options) if validator: assert cls.kind is None or cls.kind & validator.kind != 0 return cls(device, rw, validator) def val_to_string(self, value): return self._validator.to_string(value) @property def choices(self): assert hasattr(self, "_value") assert hasattr(self, "_device") return self._validator.choices if self._validator and self._validator.kind & Kind.CHOICE else None @property def range(self): assert hasattr(self, "_value") assert hasattr(self, "_device") if self._validator.kind == Kind.RANGE: return self._validator.min_value, self._validator.max_value def _pre_read(self, cached, key=None): if self.persist and self._value is None and getattr(self._device, "persister", None): # We haven't read a value from the device yet, # maybe we have something in the configuration. self._value = self._device.persister.get(self.name) if cached and self._value is not None: if getattr(self._device, "persister", None) and self.name not in self._device.persister: # If this is a new device (or a new setting for an old device), # make sure to save its current value for the next time. self._device.persister[self.name] = self._value if self.persist else None def read(self, cached=True): assert hasattr(self, "_value") assert hasattr(self, "_device") self._pre_read(cached) if cached and self._value is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: cached value %r on %s", self.name, self._value, self._device) return self._value if self._device.online: reply = self._rw.read(self._device) if reply: self._value = self._validator.validate_read(reply) if self._value is not None and self._device.persister and self.name not in self._device.persister: # Don't update the persister if it already has a value, # otherwise the first read might overwrite the value we wanted. self._device.persister[self.name] = self._value if self.persist else None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: read value %r on %s", self.name, self._value, self._device) return self._value def _pre_write(self, save=True): # Remember the value we're trying to set, even if the write fails. # This way even if the device is offline or some other error occurs, # the last value we've tried to write is remembered in the configuration. if self._device.persister and save: self._device.persister[self.name] = self._value if self.persist else None def update(self, value, save=True): self._value = value self._pre_write(save) def write(self, value, save=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert value is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: write %r to %s", self.name, value, self._device) if self._device.online: if self._value != value: self.update(value, save) current_value = None if self._validator.needs_current_value: # the _validator needs the current value, possibly to merge flag values current_value = self._rw.read(self._device) if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: current value %r on %s", self.name, current_value, self._device) data_bytes = self._validator.prepare_write(value, current_value) if data_bytes is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: prepare write(%s) => %r", self.name, value, data_bytes) reply = self._rw.write(self._device, data_bytes) # HID++ 2.0 "set" operations often return an empty ACK (b""). # Treating empty bytes as failure (`not reply`) would misreport # successful writes as errors to the GUI. Only report failure # when the transport actually returned None (error or timeout). if reply is None: logger.info( "%s: write on %s returned no reply (transport error/timeout)", self.name, self._device, ) return None return value def acceptable(self, args, current): return self._validator.acceptable(args, current) if self._validator else None def compare(self, args, current): return self._validator.compare(args, current) if self._validator else None def apply(self): assert hasattr(self, "_value") assert hasattr(self, "_device") if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: apply (%s)", self.name, self._device) try: value = self.read(self.persist) # Don't use persisted value if setting doesn't persist if self.persist and value is not None: # If setting doesn't persist no need to write value just read self.write(value, save=False) except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: error applying %s so ignore it (%s): %s", self.name, self._value, self._device, repr(e)) def __str__(self): if hasattr(self, "_value"): assert hasattr(self, "_device") return "" % ( self._rw.kind, self._validator.kind if self._validator else None, self._device.codename, self.name, self._value, ) return f"" __repr__ = __str__ class Settings(Setting): """A setting descriptor for multiple choices, being a map from keys to values. Needs to be instantiated for each specific device.""" def read(self, cached=True): assert hasattr(self, "_value") assert hasattr(self, "_device") if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r from %s", self.name, self._value, self._device) self._pre_read(cached) if cached and self._value is not None: return self._value if self._device.online: reply_map = {} for key in self._validator.choices: reply = self._rw.read(self._device, key) if reply: reply_map[int(key)] = self._validator.validate_read(reply, key) self._value = reply_map if getattr(self._device, "persister", None) and self.name not in self._device.persister: # Don't update the persister if it already has a value, # otherwise the first read might overwrite the value we wanted. self._device.persister[self.name] = self._value if self.persist else None return self._value def read_key(self, key, cached=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert key is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r key %r from %s", self.name, self._value, key, self._device) self._pre_read(cached) if cached and self._value is not None: return self._value[int(key)] if self._device.online: reply = self._rw.read(self._device, key) if reply: self._value[int(key)] = self._validator.validate_read(reply, key) if getattr(self._device, "persister", None) and self.name not in self._device.persister: self._device.persister[self.name] = self._value if self.persist else None return self._value[int(key)] def write(self, map, save=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert map is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings write %r to %s", self.name, map, self._device) if self._device.online: self.update(map, save) for key, value in map.items(): data_bytes = self._validator.prepare_write(int(key), value) if data_bytes is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings prepare map write(%s,%s) => %r", self.name, key, value, data_bytes) reply = self._rw.write(self._device, int(key), data_bytes) if not reply: return None return map def update_key_value(self, key, value, save=True): self._value[int(key)] = value self._pre_write(save) def write_key_value(self, key, value, save=True) -> Any | None: assert hasattr(self, "_value") assert hasattr(self, "_device") assert key is not None assert value is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings write key %r value %r to %s", self.name, key, value, self._device) if self._device.online: if not self._value: self.read() try: data_bytes = self._validator.prepare_write(int(key), value) # always need to write to configuration because dictionary is shared and could have changed self.update_key_value(key, value, save) except ValueError: data_bytes = value = None if data_bytes is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings prepare key value write(%s,%s) => %r", self.name, key, value, data_bytes) reply = self._rw.write(self._device, int(key), data_bytes) if not reply: return None return value class LongSettings(Setting): """A setting descriptor for multiple choices, being a map from keys to values. Allows multiple write requests, if the options don't fit in 16 bytes. The validator must return a list. Needs to be instantiated for each specific device.""" def read(self, cached=True): assert hasattr(self, "_value") assert hasattr(self, "_device") if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r from %s", self.name, self._value, self._device) self._pre_read(cached) if cached and self._value is not None: return self._value if self._device.online: reply_map = {} # Reading one item at a time. This can probably be optimised for item in self._validator.items: r = self._validator.prepare_read_item(item) reply = self._rw.read(self._device, r) if reply: reply_map[int(item)] = self._validator.validate_read_item(reply, item) self._value = reply_map if getattr(self._device, "persister", None) and self.name not in self._device.persister: # Don't update the persister if it already has a value, # otherwise the first read might overwrite the value we wanted. self._device.persister[self.name] = self._value if self.persist else None return self._value def read_item(self, item, cached=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert item is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r item %r from %s", self.name, self._value, item, self._device) self._pre_read(cached) if cached and self._value is not None: return self._value[int(item)] if self._device.online: r = self._validator.prepare_read_item(item) reply = self._rw.read(self._device, r) if reply: self._value[int(item)] = self._validator.validate_read_item(reply, item) if getattr(self._device, "persister", None) and self.name not in self._device.persister: self._device.persister[self.name] = self._value if self.persist else None return self._value[int(item)] def write(self, map, save=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert map is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: long settings write %r to %s", self.name, map, self._device) if self._device.online: self.update(map, save) for item, value in map.items(): data_bytes_list = self._validator.prepare_write(self._value) if data_bytes_list is not None: for data_bytes in data_bytes_list: if data_bytes is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings prepare map write(%s,%s) => %r", self.name, item, value, data_bytes) reply = self._rw.write(self._device, data_bytes) if not reply: return None return map def update_key_value(self, key, value, save=True): self._value[int(key)] = value self._pre_write(save) def write_key_value(self, item, value, save=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert item is not None assert value is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: long settings write item %r value %r to %s", self.name, item, value, self._device) if self._device.online: if not self._value: self.read() data_bytes = self._validator.prepare_write_item(item, value) self.update_key_value(item, value, save) if data_bytes is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings prepare item value write(%s,%s) => %r", self.name, item, value, data_bytes) reply = self._rw.write(self._device, data_bytes) if not reply: return None return value class BitFieldSetting(Setting): """A setting descriptor for a set of choices represented by one bit each, being a map from options to booleans. Needs to be instantiated for each specific device.""" def read(self, cached=True): assert hasattr(self, "_value") assert hasattr(self, "_device") if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r from %s", self.name, self._value, self._device) self._pre_read(cached) if cached and self._value is not None: return self._value if self._device.online: reply_map = {} reply = self._do_read() if reply: reply_map = self._validator.validate_read(reply) self._value = reply_map if getattr(self._device, "persister", None) and self.name not in self._device.persister: # Don't update the persister if it already has a value, # otherwise the first read might overwrite the value we wanted. self._device.persister[self.name] = self._value if self.persist else None return self._value def _do_read(self): return self._rw.read(self._device) def read_key(self, key, cached=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert key is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r key %r from %s", self.name, self._value, key, self._device) self._pre_read(cached) if cached and self._value is not None: return self._value[int(key)] if self._device.online: reply = self._do_read_key(key) if reply: self._value = self._validator.validate_read(reply) if getattr(self._device, "persister", None) and self.name not in self._device.persister: self._device.persister[self.name] = self._value if self.persist else None return self._value[int(key)] def _do_read_key(self, key): return self._rw.read(self._device, key) def write(self, map, save=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert map is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: bit field settings write %r to %s", self.name, map, self._device) if self._device.online: self.update(map, save) data_bytes = self._validator.prepare_write(self._value) if data_bytes is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings prepare map write(%s) => %r", self.name, self._value, data_bytes) # if prepare_write returns a list, write one item at a time seq = data_bytes if isinstance(data_bytes, list) else [data_bytes] for b in seq: reply = self._rw.write(self._device, b) if not reply: return None return map def update_key_value(self, key, value, save=True): self._value[int(key)] = value self._pre_write(save) def write_key_value(self, key, value, save=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert key is not None assert value is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: bit field settings write key %r value %r to %s", self.name, key, value, self._device) if self._device.online: if not self._value: self.read() value = bool(value) self.update_key_value(key, value, save) data_bytes = self._validator.prepare_write(self._value) if data_bytes is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings prepare key value write(%s,%s) => %r", self.name, key, str(value), data_bytes) # if prepare_write returns a list, write one item at a time seq = data_bytes if isinstance(data_bytes, list) else [data_bytes] for b in seq: reply = self._rw.write(self._device, b) if not reply: return None return value class BitFieldWithOffsetAndMaskSetting(BitFieldSetting): """A setting descriptor for a set of choices represented by one bit each, each one having an offset, being a map from options to booleans. Needs to be instantiated for each specific device.""" def _do_read(self): return {r: self._rw.read(self._device, r) for r in self._validator.prepare_read()} def _do_read_key(self, key): r = self._validator.prepare_read_key(key) return {r: self._rw.read(self._device, r)} class RangeFieldSetting(Setting): """A setting descriptor for a set of choices represented by one field each, with map from option names to range(0,n). Needs to be instantiated for each specific device.""" def read(self, cached=True): assert hasattr(self, "_value") assert hasattr(self, "_device") if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r from %s", self.name, self._value, self._device) self._pre_read(cached) if cached and self._value is not None: return self._value if self._device.online: reply_map = {} reply = self._do_read() if reply: reply_map = self._validator.validate_read(reply) self._value = reply_map if getattr(self._device, "persister", None) and self.name not in self._device.persister: # Don't update the persister if it already has a value, # otherwise the first read might overwrite the value we wanted. self._device.persister[self.name] = self._value if self.persist else None return self._value def _do_read(self): return self._rw.read(self._device) def read_key(self, key, cached=True): return self.read(cached)[int(key)] def write(self, map, save=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert map is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: range field setting write %r to %s", self.name, map, self._device) if self._device.online: self.update(map, save) data_bytes = self._validator.prepare_write(self._value) if data_bytes is not None: if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: range field setting prepare map write(%s) => %r", self.name, self._value, data_bytes) reply = self._rw.write(self._device, data_bytes) if not reply: return None elif logger.isEnabledFor(logging.WARNING): logger.warning("%s: range field setting no data to write", self.name) return map def write_key_value(self, key, value, save=True): assert key is not None assert value is not None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: range field setting write key %r value %r to %s", self.name, key, value, self._device) if self._device.online: if not self._value: self.read() map = self._value map[int(key)] = value self.write(map, save) return value # # read/write low-level operators # class RegisterRW: __slots__ = ("register",) kind = NamedInt(0x01, _("register")) def __init__(self, register: int): assert isinstance(register, int) self.register = register def read(self, device): return device.read_register(self.register) def write(self, device, data_bytes): return device.write_register(self.register, data_bytes) class FeatureRW: kind = NamedInt(0x02, _("feature")) default_read_fnid = 0x00 default_write_fnid = 0x10 def __init__( self, feature: hidpp20_constants.SupportedFeature, read_fnid=0x00, write_fnid=0x10, prefix=b"", suffix=b"", read_prefix=b"", no_reply=False, ): assert isinstance(feature, (hidpp20_constants.SupportedFeature, CenturionCoreFeature)) self.feature = feature self.read_fnid = read_fnid self.write_fnid = write_fnid self.no_reply = no_reply self.prefix = prefix self.suffix = suffix self.read_prefix = read_prefix def read(self, device, data_bytes=b""): assert self.feature is not None if self.read_fnid is not None: return device.feature_request(self.feature, self.read_fnid, self.prefix, self.read_prefix, data_bytes) else: return b"" def write(self, device, data_bytes): assert self.feature is not None write_bytes = self.prefix + (data_bytes.to_bytes(1) if isinstance(data_bytes, int) else data_bytes) + self.suffix reply = device.feature_request(self.feature, self.write_fnid, write_bytes, no_reply=self.no_reply) return reply if not self.no_reply else True class FeatureRWMap(FeatureRW): kind = NamedInt(0x02, _("feature")) default_read_fnid = 0x00 default_write_fnid = 0x10 default_key_byte_count = 1 def __init__( self, feature: hidpp20_constants.SupportedFeature, read_fnid=default_read_fnid, write_fnid=default_write_fnid, key_byte_count=default_key_byte_count, no_reply=False, ): assert isinstance(feature, (hidpp20_constants.SupportedFeature, CenturionCoreFeature)) self.feature = feature self.read_fnid = read_fnid self.write_fnid = write_fnid self.key_byte_count = key_byte_count self.no_reply = no_reply def read(self, device, key): assert self.feature is not None key_bytes = common.int2bytes(key, self.key_byte_count) return device.feature_request(self.feature, self.read_fnid, key_bytes) def write(self, device, key, data_bytes): assert self.feature is not None key_bytes = common.int2bytes(key, self.key_byte_count) reply = device.feature_request(self.feature, self.write_fnid, key_bytes, data_bytes, no_reply=self.no_reply) return reply if not self.no_reply else True class ActionSettingRW: """Special RW class for settings that turn on and off special processing when a key or button is depressed""" def __init__(self, feature, name="", divert_setting_name="divert-keys"): self.feature = feature # not used? self.name = name self.divert_setting_name = divert_setting_name self.kind = FeatureRW.kind # pretend to be FeatureRW as required for HID++ 2.0 devices self.device = None self.key = None self.active = False self.pressed = False def activate_action(self): # action to take when setting is activated (write non-false) pass def deactivate_action(self): # action to take when setting is deactivated (write false) pass def press_action(self): # action to take when key is pressed pass def release_action(self): # action to take when key is released pass def move_action(self, dx, dy): # action to take when mouse is moved while key is down pass def key_action(self, key): # acction to take when some other diverted key is pressed pass def read(self, device): # need to return bytes, as if read from device return common.int2bytes(self.key.key, 2) if self.active and self.key else b"\x00\x00" def write(self, device, data_bytes): def handler(device, n): # Called on notification events from the device if ( n.sub_id < 0x40 and device.features.get_feature(n.sub_id) == hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4 ): if n.address == 0x00: cids = struct.unpack("!HHHH", n.data[:8]) if not self.pressed and int(self.key.key) in cids: # trigger key pressed self.pressed = True self.press_action() elif self.pressed: if int(self.key.key) not in cids: # trigger key released self.pressed = False self.release_action() else: for key in cids: if key and not key == self.key.key: # some other diverted key pressed self.key_action(key) elif n.address == 0x10: if self.pressed: dx, dy = struct.unpack("!hh", n.data[:4]) self.move_action(dx, dy) divertSetting = next(filter(lambda s: s.name == self.divert_setting_name, device.settings), None) if divertSetting is None: logger.warning("setting %s not found on %s", self.divert_setting_name, device.name) return None self.device = device key = common.bytes2int(data_bytes) if key: # Enable self.key = next((k for k in device.keys if k.key == key), None) if self.key: self.active = True if divertSetting: divertSetting.write_key_value(int(self.key.key), 1) if self.device.setting_callback: self.device.setting_callback(device, type(divertSetting), [self.key.key, 1]) device.add_notification_handler(self.name, handler) self.activate_action() else: logger.error("cannot enable %s on %s for key %s", self.name, device, key) else: # Disable if self.active: self.active = False if divertSetting: divertSetting.write_key_value(int(self.key.key), 0) if self.device.setting_callback: self.device.setting_callback(device, type(divertSetting), [self.key.key, 0]) try: device.remove_notification_handler(self.name) except Exception: if logger.isEnabledFor(logging.WARNING): logger.warning("cannot disable %s on %s", self.name, device) self.deactivate_action() return data_bytes class RawXYProcessing: """Special class for processing RawXY action messages initiated by pressing a key with rawXY diversion capability""" def __init__(self, device, name=""): self.device = device self.name = name self.keys = [] # the keys that can initiate processing self.initiating_key = None # the key that did initiate processing self.active = False self.feature_offset = device.features[hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4] assert self.feature_offset is not False def handler(self, device, n): # Called on notification events from the device if n.sub_id < 0x40 and device.features.get_feature(n.sub_id) == hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4: if n.address == 0x00: cids = struct.unpack("!HHHH", n.data[:8]) ## generalize to list of keys if not self.initiating_key: # no initiating key pressed for k in self.keys: if int(k.key) in cids: # initiating key that was pressed self.initiating_key = k if self.initiating_key: self.press_action(self.initiating_key) else: if int(self.initiating_key.key) not in cids: # initiating key released self.initiating_key = None self.release_action() else: for key in cids: if key and key != self.initiating_key.key: self.key_action(key) elif n.address == 0x10: if self.initiating_key: dx, dy = struct.unpack("!hh", n.data[:4]) self.move_action(dx, dy) def start(self, key): device_key = next((k for k in self.device.keys if k.key == key), None) if device_key: self.keys.append(device_key) if not self.active: self.active = True self.activate_action() self.device.add_notification_handler(self.name, self.handler) device_key.set_rawXY_reporting(True) def stop(self, key): # only stop if this is the active key if self.active: processing_key = next((k for k in self.keys if k.key == key), None) if processing_key: processing_key.set_rawXY_reporting(False) self.keys.remove(processing_key) if not self.keys: try: self.device.remove_notification_handler(self.name) except Exception: if logger.isEnabledFor(logging.WARNING): logger.warning("cannot disable %s on %s", self.name, self.device) self.deactivate_action() self.active = False def activate_action(self): # action to take when processing is activated pass def deactivate_action(self): # action to take when processing is deactivated pass def press_action(self, key): # action to take when an initiating key is pressed pass def release_action(self): # action to take when key is released pass def move_action(self, dx, dy): # action to take when mouse is moved while key is down pass def key_action(self, key): # acction to take when some other diverted key is pressed pass def apply_all_settings(device): if device.features and hidpp20_constants.SupportedFeature.HIRES_WHEEL in device.features: time.sleep(0.2) # delay to try to get out of race condition with Linux HID++ driver persister = getattr(device, "persister", None) sensitives = persister.get("_sensitive", {}) if persister else {} for s in device.settings: ignore = sensitives.get(s.name, False) if ignore != SENSITIVITY_IGNORE: s.apply() Setting.validator_class = settings_validator.BooleanValidator Solaar-1.1.20/lib/logitech_receiver/settings_new.py000066400000000000000000000224461522022367600223440ustar00rootroot00000000000000## Copyright (C) 2025 Solaar contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. ## A new way of supporting settings, using a feature-specifi device class to store, read, and write relevant information ## The setting uses the device class to interact with the device feature. ## The setting uses a persist class to keep track of the setting. ## Interface: import logging from .settings import Kind logger = logging.getLogger(__name__) class Setting: name = None # Solaar internal name for the setting label = None # Solaar user name for the setting (translatable) description = None # Solaar extra desciption for the setting (translatable) feature = None # Logitech feature that the setting uses min_version = 0 # Minimum version of the feature needed setup = None # method name on Device class to get the device object get = None # method name on the device object to get the setting value set = None # method name on the device object to set the setting value acceptable = None # method name on the device object to check for acceptable values choices_universe = None # All possible acceptable keys, for settings with keys kind = Kind.NONE # What GUI interface to use persist = True # Whether to remember the setting display = True # display setting in UI _device = None # The device that this setting is for _device_object = None # The object that interacts with the feature for the device _value = None # Stored value as maintained by Solaar, used for persistence def __init__(self, device, device_object): self._device = device self._device_object = device_object @classmethod def build(cls, device): cls.check_properties(cls) device_object = getattr(device, cls.setup)() if device_object: setting = cls(device, device_object) return setting @classmethod def check_properties(cl, cls): assert cls.name and cls.label and cls.description, "New settings require a name, label, and description" assert cls.feature, "New settings require a feature" assert cls.setup, "New settings require a setup device method" assert cls.get and cls.set and cls.acceptable, "New settings require get, set, and acceptable methods" def setup_from_class(self, clss): """Copy settings methods for a new setting from a settting class""" self.name = clss.name self.label = clss.label self.description = clss.description self.feature = clss.feature self.min_version = clss.min_version self.setup = clss.setup self.get = clss.get self.set = clss.set self.acceptable = clss.acceptable self.choices_universe = clss.choices_universe self.kind = clss.kind self.persist = clss.persist def _pre_read(self, cached): """Get information from and save information to the persister""" # Get the persister map if available and not done already if self.persist and self._value is None and getattr(self._device, "persister", None): self._value = self._device.persister.get(self.name) # If this is new save its current value for the next time if cached and self._value is not None: if getattr(self._device, "persister", None) and self.name not in self._device.persister: self._device.persister[self.name] = self._value if self.persist else None def read(self, cached=True): """Get all the data for the setting. If cached is True the data in the _value can be used.""" self._pre_read(cached) if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: setting read %r from %s", self.name, self._value, self._device) if cached and self._value is not None: return self._value if cached: self._value = getattr(self._device_object, self.get)() return self._value if self._device.online: self._value = getattr(self._device_object.query(), self.get)() return self._value def write(self, value, save=True): """Write the value to the device. If saved is True also save in the persister""" pass ## fill out def apply(self): """Write saved data to the device, using persisted data if available""" if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: apply (%s)", self.name, self._device) value = None try: value = self.read(self.persist) # Don't use persisted value if setting doesn't persist if self.persist and value is not None: # If setting doesn't persist no need to write value just read self.write(value, save=False) except Exception as e: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: error applying %s so ignore it (%s): %s", self.name, value, self._device, repr(e)) @property def range(self): if self.kind == Kind.RANGE: return self.min_value, self.max_value def val_to_string(self, value): return str(value) ## key mapping from symbols to values???? class Settings(Setting): """A setting descriptor for multiple keys. Supported by a class that provides the interface to the device, see ForceSensingButtonArray in hidpp20.py Picks out a field from the mapped device feature objects.""" # setup creates a dictionary with entries for all the keys # _value is a map from keys to values # get, set, and acceptable are methods of dict value objects, not of the device object itself #### FIX THIS! MAYBE?? def __init__(self, device, device_object): super().__init__(device, device_object) self._value = {} def read(self, cached=True): self._pre_read(cached) if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r from %s", self.name, self._value, self._device) for key in self._device_object: self.read_key(key, cached) return self._value def read_key(self, key, cached=True): """Get the data for the key. If cached is True the data in the device_object can be used.""" self._pre_read(cached) if key not in self._device_object: logger.error("%s: settings illegal read key %r for %s", self.name, key, self._device) return None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings key %r read %r from %s", self.name, key, self._value, self._device) if cached and key in self._value and self._value[key] is not None: return self._value[key] if cached: data = self._device_object[key] self._value[key] = getattr(data, self.get)() return self._value[key] if self._device.online: data = self._device_object.query_key(key) self._value[key] = getattr(data, self.get)() return self._value[key] def write(self, value, save=True): if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings read %r from %s", self.name, self._value, self._device) if isinstance(value, dict): for key, val in value.items(): self.write_key_value(key, val, save) else: # to mimic interface for non-dict setting key = next(iter(self._device_object)) self.write_key_value(key, value, save) return value def write_key_value(self, key, value, save=True): """Write the data for the key. If saved is True also save in the persister""" if key not in self._device_object: logger.error("%s: settings illegal write key %r for %s", self.name, key, self._device) return None if logger.isEnabledFor(logging.DEBUG): logger.debug("%s: settings write key %r value %r to %s", self.name, key, value, self._device) if self._device.online: if self._device_object[key] is None: self.read_key(key) if self._device_object[key] is None: logger.error("%s: settings illegal write key %r for %s", self.name, key, self._device) return None if not getattr(self._device_object[key], self.acceptable)(value): logger.error("%s: settings illegal write key %r value %r for %s", self.name, key, value, self._device) return None self._value[key] = value if self._device.persister and self.persist and save: self._device.persister[self.name][key] = value getattr(self._device_object[key], self.set)(value) return value Solaar-1.1.20/lib/logitech_receiver/settings_templates.py000066400000000000000000006235501522022367600235540ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import enum import logging import socket import struct import traceback from time import sleep from time import time from typing import Callable from typing import Protocol import yaml from solaar.i18n import _ from . import base from . import common from . import descriptors from . import desktop_notifications from . import device_quirks from . import diversion from . import exceptions from . import headset_rgb from . import hidpp10_constants from . import hidpp20 from . import hidpp20_constants from . import logivoice from . import rgb_effects_probe from . import rgb_power from . import settings from . import settings_new from . import settings_validator from . import special_keys from .hidpp10_constants import Registers from .hidpp20 import KeyFlag from .hidpp20 import MappingFlag from .hidpp20_constants import GestureId from .hidpp20_constants import ParamId logger = logging.getLogger(__name__) _hidpp20 = hidpp20.Hidpp20() _F = hidpp20_constants.SupportedFeature def halving_marks(max_value, step_count): """Halving series from max_value down by powers of two, plus 0. For max=100, count=5 → [0, 13, 25, 50, 100], matching the G515 FN-F8 cycle. """ if step_count < 2 or max_value <= 0: return [] levels = [-(-max_value // (1 << i)) for i in range(step_count - 1)] return sorted({0, *levels}) def auto_step_count(max_value, low_pct=10): """Step count for halving_marks that stops before dropping below low_pct of max.""" if max_value <= 0: return 0 threshold = max(1, max_value * low_pct // 100) n = 0 while -(-max_value // (1 << n)) >= threshold: n += 1 return n + 1 def _possible_fields_with_direction_filter(device, possible_fields, direction_field): """Filter direction_field's choices against the per-device blocklist for Wave directions the firmware accepts but doesn't render.""" blocked = hidpp20.LedDirectionBlocklist.get(device.wpid) if not blocked: return possible_fields filtered = common.NamedInts() for v in hidpp20.LedDirectionChoices: if int(v) not in blocked: filtered[int(v)] = str(v) device_direction_field = dict(direction_field, choices=filtered) return [device_direction_field if f is direction_field else f for f in possible_fields] class State(enum.Enum): IDLE = "idle" PRESSED = "pressed" MOVED = "moved" # Setting classes are used to control the settings that the Solaar GUI shows and manipulates. # Each setting class has to several class variables: # name, which is used as a key when storing information about the setting, # setting classes can have the same name, as long as devices only have one setting with the same name; # label, which is shown in the Solaar main window; # description, which is shown when the mouse hovers over the setting in the main window; # either register or feature, the register or feature that the setting uses; # rw_class, the class of the reader/writer (if it is not the standard one), # rw_options, a dictionary of options for the reader/writer. # validator_class, the class of the validator (default settings.BooleanValidator) # validator_options, a dictionary of options for the validator # persist (inherited True), which is whether to store the value and apply it when setting up the device. # # The different setting classes imported from settings.py are for different numbers and kinds of arguments. # Setting is for settings with a single value (boolean, number in a range, and symbolic choice). # Settings is for settings that are maps from keys to values # and permit reading or writing the entire map or just one key/value pair. # The BitFieldSetting class is for settings that have multiple boolean values packed into a bit field. # BitFieldWithOffsetAndMaskSetting is similar. # The RangeFieldSetting class is for settings that have multiple ranges packed into a byte string. # LongSettings is for settings that have an even more complex structure. # # When settings are created a reader/writer and a validator are created. # If the setting class has a value for rw_class then an instance of that class is created. # Otherwise if the setting has a register then an instance of RegisterRW is created. # and if the setting has a feature then an instance of FeatureRW is created. # The instance is created with the register or feature as the first argument and rw_options as keyword arguments. # RegisterRW doesn't use any options. # FeatureRW options include # read_fnid - the feature function (times 16) to read the value (default 0x00), # write_fnid - the feature function (times 16) to write the value (default 0x10), # prefix - a prefix to add to the data being written and the read request (default b''), used for features # that provide and set multiple settings (e.g., to read and write function key inversion for current host) # no_reply - whether to wait for a reply (default false) (USE WITH EXTREME CAUTION). # # There are three simple validator classes - BooleanV, RangeValidator, and ChoicesValidator # BooleanV is for boolean values and is the default. It takes # true_value is the raw value for true (default 0x01), this can be an integer or a byte string, # false_value is the raw value for false (default 0x00), this can be an integer or a byte string, # mask is used to keep only some bits from a sequence of bits, this can be an integer or a byte string, # read_skip_byte_count is the number of bytes to ignore at the beginning of the read value (default 0), # write_prefix_bytes is a byte string to write before the value (default empty). # RangeValidator is for an integer in a range. It takes # byte_count is number of bytes that the value is stored in (defaults to size of max_value). # read_skip_byte_count is as for BooleanV # write_prefix_bytes is as for BooleanV # RangeValidator uses min_value and max_value from the setting class as minimum and maximum. # ChoicesValidator is for symbolic choices. It takes one positional and three keyword arguments: # choices is a list of named integers that are the valid choices, # byte_count is the number of bytes for the integer (default size of largest choice integer), # read_skip_byte_count is as for BooleanV, # write_prefix_bytes is as for BooleanV. # Settings that use ChoicesValidator should have a choices_universe class variable of the potential choices, # or None for no limitation and optionally a choices_extra class variable with an extra choice. # The choices_extra is so that there is no need to specially extend a large existing NamedInts. # ChoicesMapValidator validator is for map settings that map onto symbolic choices. It takes # choices_map is a map from keys to possible values # byte_count is as for ChoicesValidator, # read_skip_byte_count is as for ChoicesValidator, # write_prefix_bytes is as for ChoicesValidator, # key_byte_count is the number of bytes for the key integer (default size of largest key), # extra_default is an extra raw value that is used as a default value (default None). # Settings that use ChoicesValidator should have keys_universe and choices_universe class variable of # the potential keys and potential choices or None for no limitation. # BitFieldValidator validator is for bit field settings. It takes one positional and one keyword argument # the positional argument is the number of bits in the bit field # byte_count is the size of the bit field (default size of the bit field) # # A few settings work very differently. They divert a key, which is then used to start and stop some special action. # These settings have reader/writer classes that perform special processing instead of sending commands to the device. class FnSwapVirtual(settings.Setting): # virtual setting to hold fn swap strings name = "fn-swap" label = _("Swap Fx function") description = ( _( "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." ) + "\n\n" + _( "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." ) ) class RegisterHandDetection(settings.Setting): name = "hand-detection" label = _("Hand Detection") description = _("Turn on illumination when the hands hover over the keyboard.") register = Registers.KEYBOARD_HAND_DETECTION validator_options = {"true_value": b"\x00\x00\x00", "false_value": b"\x00\x00\x30", "mask": b"\x00\x00\xff"} class RegisterSmoothScroll(settings.Setting): name = "smooth-scroll" label = _("Scroll Wheel Smooth Scrolling") description = _("High-sensitivity mode for vertical scroll with the wheel.") register = Registers.MOUSE_BUTTON_FLAGS validator_options = {"true_value": 0x40, "mask": 0x40} class RegisterSideScroll(settings.Setting): name = "side-scroll" label = _("Side Scrolling") description = _( "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." ) register = Registers.MOUSE_BUTTON_FLAGS validator_options = {"true_value": 0x02, "mask": 0x02} # different devices have different sets of permissible dpis, so this should be subclassed class RegisterDpi(settings.Setting): name = "dpi-old" label = _("Sensitivity (DPI - older mice)") description = _("Mouse movement sensitivity") register = Registers.MOUSE_DPI choices_universe = common.NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100)) validator_class = settings_validator.ChoicesValidator validator_options = {"choices": choices_universe} class RegisterFnSwap(FnSwapVirtual): register = Registers.KEYBOARD_FN_SWAP validator_options = {"true_value": b"\x00\x01", "mask": b"\x00\x01"} class _PerformanceMXDpi(RegisterDpi): choices_universe = common.NamedInts.range(0x81, 0x8F, lambda x: str((x - 0x80) * 100)) validator_options = {"choices": choices_universe} # set up register settings for devices - this is done here to break up an import loop descriptors.get_wpid("0060").settings = [RegisterFnSwap] descriptors.get_wpid("2008").settings = [RegisterFnSwap] descriptors.get_wpid("2010").settings = [RegisterFnSwap, RegisterHandDetection] descriptors.get_wpid("2011").settings = [RegisterFnSwap] descriptors.get_usbid(0xC318).settings = [RegisterFnSwap] descriptors.get_wpid("C714").settings = [RegisterFnSwap] descriptors.get_wpid("100B").settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("100F").settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("1013").settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("1014").settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("1017").settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("1023").settings = [RegisterSmoothScroll, RegisterSideScroll] # somehow messed up ? descriptors.get_wpid("4004").settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("101A").settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("101B").settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("101D").settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("101F").settings = [RegisterSideScroll] descriptors.get_usbid(0xC06B).settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_wpid("1025").settings = [RegisterSideScroll] descriptors.get_wpid("102A").settings = [RegisterSmoothScroll, RegisterSideScroll] descriptors.get_usbid(0xC048).settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll] descriptors.get_usbid(0xC066).settings = [_PerformanceMXDpi, RegisterSmoothScroll, RegisterSideScroll] # ignore the capabilities part of the feature - all devices should be able to swap Fn state # can't just use the first byte = 0xFF (for current host) because of a bug in the firmware of the MX Keys S class K375sFnSwap(FnSwapVirtual): feature = _F.K375S_FN_INVERSION validator_options = {"true_value": b"\x01", "false_value": b"\x00", "read_skip_byte_count": 1} class rw_class(settings.FeatureRW): def find_current_host(self, device): if not self.prefix: response = device.feature_request(_F.HOSTS_INFO, 0x00) self.prefix = response[3:4] if response else b"\xff" def read(self, device, data_bytes=b""): self.find_current_host(device) return super().read(device, data_bytes) def write(self, device, data_bytes): self.find_current_host(device) return super().write(device, data_bytes) class FnSwap(FnSwapVirtual): feature = _F.FN_INVERSION class NewFnSwap(FnSwapVirtual): feature = _F.NEW_FN_INVERSION class Backlight(settings.Setting): name = "backlight-qualitative" label = _("Backlight Timed") description = _("Set illumination time for keyboard.") feature = _F.BACKLIGHT choices_universe = common.NamedInts(Off=0, Varying=2, VeryShort=5, Short=10, Medium=20, Long=60, VeryLong=180) validator_class = settings_validator.ChoicesValidator validator_options = {"choices": choices_universe} # MX Keys S requires some extra values, as in 11 02 0c1a 000dff000b000b003c00000000000000 # on/off options (from current) effect (FF-no change) level (from current) durations[6] (from current) class Backlight2(settings.Setting): name = "backlight" label = _("Backlight") description = _("Illumination level on keyboard. Changes made are only applied in Manual mode.") feature = _F.BACKLIGHT2 choices_universe = common.NamedInts(Disabled=0xFF, Enabled=0x00, Automatic=0x01, Manual=0x02) min_version = 0 class rw_class: def __init__(self, feature): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device): backlight = device.backlight if not backlight.enabled: return b"\xff" else: return common.int2bytes(backlight.mode, 1) def write(self, device, data_bytes): backlight = device.backlight backlight.enabled = data_bytes[0] != 0xFF if data_bytes[0] != 0xFF: backlight.mode = data_bytes[0] backlight.write() return True class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): backlight = device.backlight choices = common.NamedInts() choices[0xFF] = _("Disabled") if backlight.auto_supported: choices[0x1] = _("Automatic") if backlight.perm_supported: choices[0x3] = _("Manual") if not (backlight.auto_supported or backlight.temp_supported or backlight.perm_supported): choices[0x0] = _("Enabled") return cls(choices=choices, byte_count=1) class Backlight2Level(settings.Setting): name = "backlight_level" label = _("Backlight Level") description = _("Illumination level on keyboard when in Manual mode.") feature = _F.BACKLIGHT2 min_version = 3 class rw_class: def __init__(self, feature): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device): backlight = device.backlight return common.int2bytes(backlight.level, 1) def write(self, device, data_bytes): if device.backlight.level != common.bytes2int(data_bytes): device.backlight.level = common.bytes2int(data_bytes) device.backlight.write() return True class validator_class(settings_validator.RangeValidator): @classmethod def build(cls, setting_class, device): reply = device.feature_request(_F.BACKLIGHT2, 0x20) assert reply, "Oops, backlight range cannot be retrieved!" if reply[0] > 1: return cls(min_value=0, max_value=reply[0] - 1, byte_count=1) class Backlight2Duration(settings.Setting): feature = _F.BACKLIGHT2 min_version = 3 validator_class = settings_validator.RangeValidator min_value = 1 max_value = 600 # 10 minutes - actual maximum is 2 hours validator_options = {"byte_count": 2} class rw_class: def __init__(self, feature, field): self.feature = feature self.kind = settings.FeatureRW.kind self.field = field def read(self, device): backlight = device.backlight return common.int2bytes(getattr(backlight, self.field) * 5, 2) # use seconds instead of 5-second units def write(self, device, data_bytes): backlight = device.backlight new_duration = (int.from_bytes(data_bytes, byteorder="big") + 4) // 5 # use ceiling in 5-second units if new_duration != getattr(backlight, self.field): setattr(backlight, self.field, new_duration) backlight.write() return True class Backlight2DurationHandsOut(Backlight2Duration): name = "backlight_duration_hands_out" label = _("Backlight Delay Hands Out") description = _("Delay in seconds until backlight fades out with hands away from keyboard.") feature = _F.BACKLIGHT2 validator_class = settings_validator.RangeValidator rw_options = {"field": "dho"} class Backlight2DurationHandsIn(Backlight2Duration): name = "backlight_duration_hands_in" label = _("Backlight Delay Hands In") description = _("Delay in seconds until backlight fades out with hands near keyboard.") feature = _F.BACKLIGHT2 validator_class = settings_validator.RangeValidator rw_options = {"field": "dhi"} class Backlight2DurationPowered(Backlight2Duration): name = "backlight_duration_powered" label = _("Backlight Delay Powered") description = _("Delay in seconds until backlight fades out with external power.") feature = _F.BACKLIGHT2 validator_class = settings_validator.RangeValidator rw_options = {"field": "dpow"} class Backlight3(settings.Setting): name = "backlight-timed" label = _("Backlight (Seconds)") description = _("Set illumination time for keyboard.") feature = _F.BACKLIGHT3 rw_options = {"read_fnid": 0x10, "write_fnid": 0x20, "suffix": b"\x09"} validator_class = settings_validator.RangeValidator min_value = 0 max_value = 1000 validator_options = {"byte_count": 2} class HiResScroll(settings.Setting): name = "hi-res-scroll" label = _("Scroll Wheel High Resolution") description = ( _("High-sensitivity mode for vertical scroll with the wheel.") + "\n" + _("Set to ignore if scrolling is abnormally fast or slow") ) feature = _F.HI_RES_SCROLLING class LowresMode(settings.Setting): name = "lowres-scroll-mode" label = _("Scroll Wheel Diversion") description = _( "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger Solaar rules but are otherwise ignored)." ) feature = _F.LOWRES_WHEEL class HiresSmoothInvert(settings.Setting): name = "hires-smooth-invert" label = _("Scroll Wheel Direction") description = _("Invert direction for vertical scroll with wheel.") feature = _F.HIRES_WHEEL rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_options = {"true_value": 0x04, "mask": 0x04} class HiresSmoothResolution(settings.Setting): name = "hires-smooth-resolution" label = _("Scroll Wheel Resolution") description = ( _("High-sensitivity mode for vertical scroll with the wheel.") + "\n" + _("Set to ignore if scrolling is abnormally fast or slow") ) feature = _F.HIRES_WHEEL rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_options = {"true_value": 0x02, "mask": 0x02} class HiresMode(settings.Setting): name = "hires-scroll-mode" label = _("Scroll Wheel Diversion") description = _( "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar rules but are otherwise ignored)." ) feature = _F.HIRES_WHEEL rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_options = {"true_value": 0x01, "mask": 0x01} class PointerSpeed(settings.Setting): name = "pointer_speed" label = _("Sensitivity (Pointer Speed)") description = _("Speed multiplier for mouse (256 is normal multiplier).") feature = _F.POINTER_SPEED validator_class = settings_validator.RangeValidator min_value = 0x002E max_value = 0x01FF validator_options = {"byte_count": 2} class ThumbMode(settings.Setting): name = "thumb-scroll-mode" label = _("Thumb Wheel Diversion") description = _( "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar rules but are otherwise ignored)." ) feature = _F.THUMB_WHEEL rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_options = {"true_value": b"\x01\x00", "false_value": b"\x00\x00", "mask": b"\x01\x00"} class ThumbInvert(settings.Setting): name = "thumb-scroll-invert" label = _("Thumb Wheel Direction") description = _("Invert thumb wheel scroll direction.") feature = _F.THUMB_WHEEL rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_options = {"true_value": b"\x00\x01", "false_value": b"\x00\x00", "mask": b"\x00\x01"} # change UI to show result of onboard profile change def profile_change(device, profile_sector): if device.setting_callback: device.setting_callback(device, OnboardProfiles, [profile_sector]) for profile in device.profiles.profiles.values() if device.profiles else []: if profile.sector == profile_sector: resolution_index = profile.resolution_default_index device.setting_callback(device, AdjustableDpi, [profile.resolutions[resolution_index]]) device.setting_callback(device, ReportRate, [profile.report_rate]) break class OnboardProfiles(settings.Setting): name = "onboard_profiles" label = _("Onboard Profiles") description = _("Enable an onboard profile, which controls report rate, sensitivity, and button actions") feature = _F.ONBOARD_PROFILES choices_universe = common.NamedInts(Disabled=0) for i in range(1, 16): choices_universe[i] = f"Profile {i}" choices_universe[i + 0x100] = f"Read-Only Profile {i}" validator_class = settings_validator.ChoicesValidator class rw_class: def __init__(self, feature): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device): enabled = device.feature_request(_F.ONBOARD_PROFILES, 0x20)[0] if enabled == 0x01: active = device.feature_request(_F.ONBOARD_PROFILES, 0x40) return active[:2] else: return b"\x00\x00" def write(self, device, data_bytes): if data_bytes == b"\x00\x00": result = device.feature_request(_F.ONBOARD_PROFILES, 0x10, b"\x02") else: device.feature_request(_F.ONBOARD_PROFILES, 0x10, b"\x01") result = device.feature_request(_F.ONBOARD_PROFILES, 0x30, data_bytes) profile_change(device, common.bytes2int(data_bytes)) return result class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): headers = hidpp20.OnboardProfiles.get_profile_headers(device) profiles_list = [setting_class.choices_universe[0]] if headers: for sector, enabled in headers: if enabled and setting_class.choices_universe[sector]: profiles_list.append(setting_class.choices_universe[sector]) return cls(choices=common.NamedInts.list(profiles_list), byte_count=2) if len(profiles_list) > 1 else None class ReportRate(settings.Setting): name = "report_rate" label = _("Report Rate") description = ( _("Frequency of device movement reports") + "\n" + _("May need Onboard Profiles set to Disable to be effective.") ) feature = _F.REPORT_RATE rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} choices_universe = common.NamedInts() choices_universe[1] = "1ms" choices_universe[2] = "2ms" choices_universe[3] = "3ms" choices_universe[4] = "4ms" choices_universe[5] = "5ms" choices_universe[6] = "6ms" choices_universe[7] = "7ms" choices_universe[8] = "8ms" class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): # if device.wpid == '408E': # return None # host mode borks the function keys on the G915 TKL keyboard reply = device.feature_request(_F.REPORT_RATE, 0x00) assert reply, "Oops, report rate choices cannot be retrieved!" rate_list = [] rate_flags = common.bytes2int(reply[0:1]) for i in range(0, 8): if (rate_flags >> i) & 0x01: rate_list.append(setting_class.choices_universe[i + 1]) return cls(choices=common.NamedInts.list(rate_list), byte_count=1) if rate_list else None class ExtendedReportRate(settings.Setting): name = "report_rate_extended" label = _("Report Rate") description = ( _("Frequency of device movement reports") + "\n" + _("May need Onboard Profiles set to Disable to be effective.") ) feature = _F.EXTENDED_ADJUSTABLE_REPORT_RATE rw_options = {"read_fnid": 0x20, "write_fnid": 0x30} choices_universe = common.NamedInts() choices_universe[0] = "8ms" choices_universe[1] = "4ms" choices_universe[2] = "2ms" choices_universe[3] = "1ms" choices_universe[4] = "500us" choices_universe[5] = "250us" choices_universe[6] = "125us" class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): reply = device.feature_request(_F.EXTENDED_ADJUSTABLE_REPORT_RATE, 0x10) assert reply, "Oops, report rate choices cannot be retrieved!" rate_list = [] rate_flags = common.bytes2int(reply[0:2]) for i in range(0, 7): if rate_flags & (0x01 << i): rate_list.append(setting_class.choices_universe[i]) return cls(choices=common.NamedInts.list(rate_list), byte_count=1) if rate_list else None class DivertCrown(settings.Setting): name = "divert-crown" label = _("Divert crown events") description = _("Make crown send CROWN HID++ notifications (which trigger Solaar rules but are otherwise ignored).") feature = _F.CROWN rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_options = {"true_value": 0x02, "false_value": 0x01, "mask": 0xFF} class CrownSmooth(settings.Setting): name = "crown-smooth" label = _("Crown smooth scroll") description = _("Set crown smooth scroll") feature = _F.CROWN rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_options = {"true_value": 0x01, "false_value": 0x02, "read_skip_byte_count": 1, "write_prefix_bytes": b"\x00"} class DivertGkeys(settings.Setting): name = "divert-gkeys" label = _("Divert G and M Keys") description = _("Make G and M keys send HID++ notifications (which trigger Solaar rules but are otherwise ignored).") feature = _F.GKEY validator_options = {"true_value": 0x01, "false_value": 0x00, "mask": 0xFF} class rw_class(settings.FeatureRW): def __init__(self, feature): super().__init__(feature, write_fnid=0x20) def read(self, device): # no way to read, so just assume not diverted return b"\x00" class ScrollRatchet(settings.Setting): name = "scroll-ratchet" label = _("Scroll Wheel Ratcheted") description = _("Switch the mouse wheel between speed-controlled ratcheting and always freespin.") feature = _F.SMART_SHIFT choices_universe = common.NamedInts(**{_("Freespinning"): 1, _("Ratcheted"): 2}) validator_class = settings_validator.ChoicesValidator validator_options = {"choices": choices_universe} class SmartShift(settings.Setting): name = "smart-shift" label = _("Scroll Wheel Ratchet Speed") description = _( "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." ) feature = _F.SMART_SHIFT rw_options = {"read_fnid": 0x00, "write_fnid": 0x10} class rw_class(settings.FeatureRW): MIN_VALUE = 1 MAX_VALUE = 50 def __init__(self, feature, read_fnid, write_fnid): super().__init__(feature, read_fnid, write_fnid) def read(self, device): value = super().read(device) if common.bytes2int(value[0:1]) == 1: # Mode = Freespin, map to minimum return common.int2bytes(self.MIN_VALUE, count=1) else: # Mode = smart shift, map to the value, capped at maximum threshold = min(common.bytes2int(value[1:2]), self.MAX_VALUE) return common.int2bytes(threshold, count=1) def write(self, device, data_bytes): threshold = common.bytes2int(data_bytes) # Freespin at minimum mode = 0 # 1 if threshold <= self.MIN_VALUE else 2 # Ratchet at maximum if threshold >= self.MAX_VALUE: threshold = 255 data = common.int2bytes(mode, count=1) + common.int2bytes(max(0, threshold), count=1) return super().write(device, data) min_value = rw_class.MIN_VALUE max_value = rw_class.MAX_VALUE validator_class = settings_validator.RangeValidator class SmartShiftEnhanced(SmartShift): feature = _F.SMART_SHIFT_ENHANCED rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} class ScrollRatchetEnhanced(ScrollRatchet): feature = _F.SMART_SHIFT_ENHANCED rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} class ScrollRatchetTorque(settings.Setting): name = "scroll-ratchet-torque" label = _("Scroll Wheel Ratchet Torque") description = _("Change the torque needed to overcome the ratchet.") feature = _F.SMART_SHIFT_ENHANCED min_value = 1 max_value = 100 rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} class rw_class(settings.FeatureRW): def write(self, device, data_bytes): ratchetSetting = next(filter(lambda s: s.name == "scroll-ratchet", device.settings), None) if ratchetSetting: # for MX Master 4, the ratchet setting needs to be written for changes to take effect ratchet_value = ratchetSetting.read(True) data_bytes = ratchet_value.to_bytes(1, "big") + data_bytes[1:] result = super().write(device, data_bytes) return result class validator_class(settings_validator.RangeValidator): @classmethod def build(cls, setting_class, device): reply = device.feature_request(_F.SMART_SHIFT_ENHANCED, 0x00) if reply[0] & 0x01: # device supports tunable torque return cls( min_value=setting_class.min_value, max_value=setting_class.max_value, byte_count=1, write_prefix_bytes=b"\x00\x00", # don't change mode or disengage, but see above read_skip_byte_count=2, ) # the keys for the choice map are Logitech controls (from special_keys) # each choice value is a NamedInt with the string from a task (to be shown to the user) # and the integer being the control number for that task (to be written to the device) # Solaar only remaps keys (controlled by key gmask and group), not other key reprogramming class ReprogrammableKeys(settings.Settings): name = "reprogrammable-keys" label = _("Key/Button Actions") description = ( _("Change the action for the key or button.") + " " + _("Overridden by diversion.") + "\n" + _("Changing important actions (such as for the left mouse button) can result in an unusable system.") ) feature = _F.REPROG_CONTROLS_V4 keys_universe = special_keys.CONTROL choices_universe = special_keys.CONTROL class rw_class: def __init__(self, feature): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device, key): key_index = device.keys.index(key) key_struct = device.keys[key_index] return b"\x00\x00" + common.int2bytes(int(key_struct.mapped_to), 2) def write(self, device, key, data_bytes): key_index = device.keys.index(key) key_struct = device.keys[key_index] key_struct.remap(special_keys.CONTROL[common.bytes2int(data_bytes)]) return True class validator_class(settings_validator.ChoicesMapValidator): @classmethod def build(cls, setting_class, device): choices = {} if device.keys: for k in device.keys: tgts = k.remappable_to if len(tgts) > 1: choices[k.key] = tgts return cls(choices, key_byte_count=2, byte_count=2, extra_default=0) if choices else None class DpiSlidingXY(settings.RawXYProcessing): def __init__( self, *args, show_notification: Callable[[str, str], bool], **kwargs, ): super().__init__(*args, **kwargs) self.fsmState = None self._show_notification = show_notification def activate_action(self): self.dpiSetting = next(filter(lambda s: s.name == "dpi" or s.name == "dpi_extended", self.device.settings), None) self.dpiChoices = list(self.dpiSetting.choices) self.otherDpiIdx = self.device.persister.get("_dpi-sliding", -1) if self.device.persister else -1 if not isinstance(self.otherDpiIdx, int) or self.otherDpiIdx < 0 or self.otherDpiIdx >= len(self.dpiChoices): self.otherDpiIdx = self.dpiChoices.index(self.dpiSetting.read()) self.fsmState = State.IDLE self.dx = 0.0 self.movingDpiIdx = None def setNewDpi(self, newDpiIdx): newDpi = self.dpiChoices[newDpiIdx] self.dpiSetting.write(newDpi) if self.device.setting_callback: self.device.setting_callback(self.device, type(self.dpiSetting), [newDpi]) def displayNewDpi(self, newDpiIdx): selected_dpi = self.dpiChoices[newDpiIdx] min_dpi = self.dpiChoices[0] max_dpi = self.dpiChoices[-1] reason = f"DPI {selected_dpi} [min {min_dpi}, max {max_dpi}]" self._show_notification(self.device, reason) def press_action(self, key): # start tracking self.starting = True if self.fsmState == State.IDLE: self.fsmState = State.PRESSED self.dx = 0.0 # While in 'moved' state, the index into 'dpiChoices' of the currently selected DPI setting self.movingDpiIdx = None def release_action(self): # adjust DPI and stop tracking if self.fsmState == State.PRESSED: # Swap with other DPI thisIdx = self.dpiChoices.index(self.dpiSetting.read()) newDpiIdx, self.otherDpiIdx = self.otherDpiIdx, thisIdx if self.device.persister: self.device.persister["_dpi-sliding"] = self.otherDpiIdx self.setNewDpi(newDpiIdx) self.displayNewDpi(newDpiIdx) elif self.fsmState == State.MOVED: # Set DPI according to displacement self.setNewDpi(self.movingDpiIdx) self.fsmState = State.IDLE def move_action(self, dx, dy): if self.device.features.get_feature_version(_F.REPROG_CONTROLS_V4) >= 5 and self.starting: self.starting = False # hack to ignore strange first movement report from MX Master 3S return currDpi = self.dpiSetting.read() self.dx += float(dx) / float(currDpi) * 15.0 # yields a more-or-less DPI-independent dx of about 5/cm if self.fsmState == State.PRESSED: if abs(self.dx) >= 1.0: self.fsmState = State.MOVED self.movingDpiIdx = self.dpiChoices.index(currDpi) elif self.fsmState == State.MOVED: currIdx = self.dpiChoices.index(self.dpiSetting.read()) newMovingDpiIdx = min(max(currIdx + int(self.dx), 0), len(self.dpiChoices) - 1) if newMovingDpiIdx != self.movingDpiIdx: self.movingDpiIdx = newMovingDpiIdx self.displayNewDpi(newMovingDpiIdx) class MouseGesturesXY(settings.RawXYProcessing): def activate_action(self): self.dpiSetting = next(filter(lambda s: s.name == "dpi" or s.name == "dpi_extended", self.device.settings), None) self.fsmState = State.IDLE self.initialize_data() def initialize_data(self): self.dx = 0.0 self.dy = 0.0 self.lastEv = None self.data = [] def press_action(self, key): self.starting = True if self.fsmState == State.IDLE: self.fsmState = State.PRESSED self.initialize_data() self.data = [key.key] def release_action(self): if self.fsmState == State.PRESSED: # emit mouse gesture notification self.push_mouse_event() if logger.isEnabledFor(logging.INFO): logger.info("mouse gesture notification %s", self.data) payload = struct.pack("!" + (len(self.data) * "h"), *self.data) notification = base.HIDPPNotification(0, 0, 0, 0, payload) diversion.process_notification(self.device, notification, _F.MOUSE_GESTURE) self.fsmState = State.IDLE def move_action(self, dx, dy): if self.fsmState == State.PRESSED: now = time() * 1000 # time_ns() / 1e6 if self.device.features.get_feature_version(_F.REPROG_CONTROLS_V4) >= 5 and self.starting: self.starting = False # hack to ignore strange first movement report from MX Master 3S return if self.lastEv is not None and now - self.lastEv > 200.0: self.push_mouse_event() dpi = self.dpiSetting.read() if self.dpiSetting else 1000 dx = float(dx) / float(dpi) * 15.0 # This multiplier yields a more-or-less DPI-independent dx of about 5/cm self.dx += dx dy = float(dy) / float(dpi) * 15.0 # This multiplier yields a more-or-less DPI-independent dx of about 5/cm self.dy += dy self.lastEv = now def key_action(self, key): self.push_mouse_event() self.data.append(1) self.data.append(key) self.lastEv = time() * 1000 # time_ns() / 1e6 if logger.isEnabledFor(logging.DEBUG): logger.debug("mouse gesture key event %d %s", key, self.data) def push_mouse_event(self): x = int(self.dx) y = int(self.dy) if x == 0 and y == 0: return self.data.append(0) self.data.append(x) self.data.append(y) self.dx = 0.0 self.dy = 0.0 if logger.isEnabledFor(logging.DEBUG): logger.debug("mouse gesture move event %d %d %s", x, y, self.data) class DivertKeys(settings.Settings): name = "divert-keys" label = _("Key/Button Diversion") description = _("Make the key or button send HID++ notifications (Diverted) or initiate Mouse Gestures or Sliding DPI") feature = _F.REPROG_CONTROLS_V4 keys_universe = special_keys.CONTROL choices_universe = common.NamedInts(**{_("Regular"): 0, _("Diverted"): 1, _("Mouse Gestures"): 2, _("Sliding DPI"): 3}) choices_gesture = common.NamedInts(**{_("Regular"): 0, _("Diverted"): 1, _("Mouse Gestures"): 2}) choices_divert = common.NamedInts(**{_("Regular"): 0, _("Diverted"): 1}) class rw_class: def __init__(self, feature): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device, key): key_index = device.keys.index(key) key_struct = device.keys[key_index] return b"\x00\x00\x01" if MappingFlag.DIVERTED in key_struct.mapping_flags else b"\x00\x00\x00" def write(self, device, key, data_bytes): key_index = device.keys.index(key) key_struct = device.keys[key_index] key_struct.set_diverted(common.bytes2int(data_bytes) != 0) # not regular return True class validator_class(settings_validator.ChoicesMapValidator): def __init__(self, choices, key_byte_count=2, byte_count=1, mask=0x01): super().__init__(choices, key_byte_count, byte_count, mask) def prepare_write(self, key, new_value): if self.gestures and new_value != 2: # mouse gestures self.gestures.stop(key) if self.sliding and new_value != 3: # sliding DPI self.sliding.stop(key) if self.gestures and new_value == 2: # mouse gestures self.gestures.start(key) if self.sliding and new_value == 3: # sliding DPI self.sliding.start(key) return super().prepare_write(key, new_value) @classmethod def build(cls, setting_class, device): sliding = gestures = None choices = {} if device.keys: for key in device.keys: if KeyFlag.DIVERTABLE in key.flags and KeyFlag.VIRTUAL not in key.flags: if KeyFlag.RAW_XY in key.flags: choices[key.key] = setting_class.choices_gesture if gestures is None: gestures = MouseGesturesXY(device, name="MouseGestures") if _F.ADJUSTABLE_DPI in device.features: choices[key.key] = setting_class.choices_universe if sliding is None: sliding = DpiSlidingXY( device, name="DpiSliding", show_notification=desktop_notifications.show ) else: choices[key.key] = setting_class.choices_divert if not choices: return None validator = cls(choices, key_byte_count=2, byte_count=1, mask=0x01) validator.sliding = sliding validator.gestures = gestures return validator def produce_dpi_list(feature, function, ignore, device, direction): dpi_bytes = b"" for i in range(0, 0x100): # there will be only a very few iterations performed reply = device.feature_request(feature, function, 0x00, direction, i) assert reply, "Oops, DPI list cannot be retrieved!" dpi_bytes += reply[ignore:] if dpi_bytes[-2:] == b"\x00\x00": break dpi_list = [] i = 0 while i < len(dpi_bytes): val = common.bytes2int(dpi_bytes[i : i + 2]) if val == 0: break if val >> 13 == 0b111: step = val & 0x1FFF last = common.bytes2int(dpi_bytes[i + 2 : i + 4]) assert len(dpi_list) > 0 and last > dpi_list[-1], f"Invalid DPI list item: {val!r}" dpi_list += range(dpi_list[-1] + step, last + 1, step) i += 4 else: dpi_list.append(val) i += 2 return dpi_list class AdjustableDpi(settings.Setting): name = "dpi" label = _("Sensitivity (DPI)") description = _("Mouse movement sensitivity") + "\n" + _("May need Onboard Profiles set to Disable to be effective.") feature = _F.ADJUSTABLE_DPI rw_options = {"read_fnid": 0x20, "write_fnid": 0x30} choices_universe = common.NamedInts.range(100, 4000, str, 50) class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): dpilist = produce_dpi_list(setting_class.feature, 0x10, 1, device, 0) setting = ( cls(choices=common.NamedInts.list(dpilist), byte_count=2, write_prefix_bytes=b"\x00") if dpilist else None ) setting.dpilist = dpilist return setting def validate_read(self, reply_bytes): # special validator to use default DPI if needed reply_value = common.bytes2int(reply_bytes[1:3]) if reply_value == 0: # use default value instead reply_value = common.bytes2int(reply_bytes[3:5]) valid_value = self.choices[reply_value] assert valid_value is not None, f"{self.__class__.__name__}: failed to validate read value {reply_value:02X}" return valid_value class ExtendedAdjustableDpi(settings.Setting): # the extended version allows for two dimensions, longer dpi descriptions, but still assume only one sensor name = "dpi_extended" label = _("Sensitivity (DPI)") description = _("Mouse movement sensitivity") + "\n" + _("May need Onboard Profiles set to Disable to be effective.") feature = _F.EXTENDED_ADJUSTABLE_DPI rw_options = {"read_fnid": 0x50, "write_fnid": 0x60} keys_universe = common.NamedInts(X=0, Y=1, LOD=2) choices_universe = common.NamedInts.range(100, 4000, str, 50) choices_universe[1] = "LOW" choices_universe[2] = "MEDIUM" choices_universe[3] = "HIGH" keys = common.NamedInts(X=0, Y=1, LOD=2) def write_key_value(self, key, value, save=True): # Force a read to populate the full X/Y/LOD dictionary if it's missing (fixes CLI) if not isinstance(self._value, dict): self.read() if isinstance(self._value, dict): self._value[key] = value else: self._value = {key: value} result = self.write(self._value, save) return result[key] if isinstance(result, dict) else result class validator_class(settings_validator.ChoicesMapValidator): @classmethod def build(cls, setting_class, device): reply = device.feature_request(setting_class.feature, 0x10, 0x00) y = bool(reply[2] & 0x01) lod = bool(reply[2] & 0x02) choices_map = {} dpilist_x = produce_dpi_list(setting_class.feature, 0x20, 3, device, 0) choices_map[setting_class.keys["X"]] = common.NamedInts.list(dpilist_x) if y: dpilist_y = produce_dpi_list(setting_class.feature, 0x20, 3, device, 1) choices_map[setting_class.keys["Y"]] = common.NamedInts.list(dpilist_y) if lod: choices_map[setting_class.keys["LOD"]] = common.NamedInts(LOW=0, MEDIUM=1, HIGH=2) validator = cls(choices_map=choices_map, byte_count=2, write_prefix_bytes=b"\x00") validator.y = y validator.lod = lod validator.keys = setting_class.keys return validator def validate_read(self, reply_bytes): # special validator to read entire setting dpi_x = common.bytes2int(reply_bytes[3:5]) if reply_bytes[1:3] == 0 else common.bytes2int(reply_bytes[1:3]) assert dpi_x in self.choices[0], f"{self.__class__.__name__}: failed to validate dpi_x value {dpi_x:04X}" value = {self.keys["X"]: dpi_x} if self.y: dpi_y = common.bytes2int(reply_bytes[7:9]) if reply_bytes[5:7] == 0 else common.bytes2int(reply_bytes[5:7]) assert dpi_y in self.choices[1], f"{self.__class__.__name__}: failed to validate dpi_y value {dpi_y:04X}" value[self.keys["Y"]] = dpi_y if self.lod: lod = reply_bytes[9] assert lod in self.choices[2], f"{self.__class__.__name__}: failed to validate lod value {lod:02X}" value[self.keys["LOD"]] = lod return value def prepare_write(self, new_value, current_value=None): # special preparer to write entire setting data_bytes = self._write_prefix_bytes if new_value[self.keys["X"]] not in self.choices[self.keys["X"]]: raise ValueError(f"invalid value {new_value!r}") data_bytes += common.int2bytes(new_value[0], 2) if self.y: if new_value[self.keys["Y"]] not in self.choices[self.keys["Y"]]: raise ValueError(f"invalid value {new_value!r}") data_bytes += common.int2bytes(new_value[self.keys["Y"]], 2) else: data_bytes += b"\x00\x00" if self.lod: if new_value[self.keys["LOD"]] not in self.choices[self.keys["LOD"]]: raise ValueError(f"invalid value {new_value!r}") data_bytes += common.int2bytes(new_value[self.keys["LOD"]], 1) else: data_bytes += b"\x00" return data_bytes class SpeedChange(settings.Setting): """Implements the ability to switch Sensitivity by clicking on the DPI_Change button.""" name = "speed-change" label = _("Sensitivity Switching") description = _( "Switch the current sensitivity and the remembered sensitivity when the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" ) choices_universe = special_keys.CONTROL choices_extra = common.NamedInt(0, _("Off")) feature = _F.POINTER_SPEED rw_options = {"name": "speed change"} class rw_class(settings.ActionSettingRW): def press_action(self): # switch sensitivity currentSpeed = self.device.persister.get("pointer_speed", None) if self.device.persister else None newSpeed = self.device.persister.get("_speed-change", None) if self.device.persister else None speed_setting = next(filter(lambda s: s.name == "pointer_speed", self.device.settings), None) if newSpeed is not None: if speed_setting: speed_setting.write(newSpeed) if self.device.setting_callback: self.device.setting_callback(self.device, type(speed_setting), [newSpeed]) else: logger.error("cannot save sensitivity setting on %s", self.device) if self.device.persister: self.device.persister["_speed-change"] = currentSpeed class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): key_index = device.keys.index(special_keys.CONTROL.DPI_Change) key = device.keys[key_index] if key_index is not None else None if key is not None and KeyFlag.DIVERTABLE in key.flags: keys = [setting_class.choices_extra, key.key] return cls(choices=common.NamedInts.list(keys), byte_count=2) class DisableKeyboardKeys(settings.BitFieldSetting): name = "disable-keyboard-keys" label = _("Disable keys") description = _("Disable specific keyboard keys.") feature = _F.KEYBOARD_DISABLE_KEYS rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} _labels = {k: (None, _("Disables the %s key.") % k) for k in special_keys.DISABLE} choices_universe = special_keys.DISABLE class validator_class(settings_validator.BitFieldValidator): @classmethod def build(cls, setting_class, device): mask = device.feature_request(_F.KEYBOARD_DISABLE_KEYS, 0x00)[0] options = [special_keys.DISABLE[1 << i] for i in range(8) if mask & (1 << i)] return cls(options) if options else None class Multiplatform(settings.Setting): name = "multiplatform" label = _("Set OS") description = _("Change keys to match OS.") feature = _F.MULTIPLATFORM rw_options = {"read_fnid": 0x00, "write_fnid": 0x30} choices_universe = common.NamedInts(**{"OS " + str(i + 1): i for i in range(8)}) # multiplatform OS bits OSS = [ ("Linux", 0x0400), ("MacOS", 0x2000), ("Windows", 0x0100), ("iOS", 0x4000), ("Android", 0x1000), ("WebOS", 0x8000), ("Chrome", 0x0800), ("WinEmb", 0x0200), ("Tizen", 0x0001), ] # the problem here is how to construct the right values for the rules Set GUI, # as, for example, the integer value for 'Windows' can be different on different devices class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): def _str_os_versions(low, high): def _str_os_version(version): if version == 0: return "" elif version & 0xFF: return f"{str(version >> 8)}.{str(version & 0xFF)}" else: return str(version >> 8) return "" if low == 0 and high == 0 else f" {_str_os_version(low)}-{_str_os_version(high)}" infos = device.feature_request(_F.MULTIPLATFORM) assert infos, "Oops, multiplatform count cannot be retrieved!" flags, _ignore, num_descriptors = struct.unpack("!BBB", infos[:3]) if not (flags & 0x02): # can't set platform so don't create setting return [] descriptors = [] for index in range(0, num_descriptors): descriptor = device.feature_request(_F.MULTIPLATFORM, 0x10, index) platform, _ignore, os_flags, low, high = struct.unpack("!BBHHH", descriptor[:8]) descriptors.append((platform, os_flags, low, high)) choices = common.NamedInts() for os_name, os_bit in setting_class.OSS: for platform, os_flags, low, high in descriptors: os = os_name + _str_os_versions(low, high) if os_bit & os_flags and platform not in choices and os not in choices: choices[platform] = os return cls(choices=choices, read_skip_byte_count=6, write_prefix_bytes=b"\xff") if choices else None class DualPlatform(settings.Setting): name = "multiplatform" label = _("Set OS") description = _("Change keys to match OS.") choices_universe = common.NamedInts() choices_universe[0x00] = "iOS, MacOS" choices_universe[0x01] = "Android, Windows" feature = _F.DUALPLATFORM rw_options = {"read_fnid": 0x00, "write_fnid": 0x20} validator_class = settings_validator.ChoicesValidator validator_options = {"choices": choices_universe} class ChangeHost(settings.Setting): name = "change-host" label = _("Change Host") description = _("Switch connection to a different host") persist = False # persisting this setting is harmful feature = _F.CHANGE_HOST rw_options = {"read_fnid": 0x00, "write_fnid": 0x10, "no_reply": True} choices_universe = common.NamedInts(**{"Host " + str(i + 1): i for i in range(3)}) class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): infos = device.feature_request(_F.CHANGE_HOST) assert infos, "Oops, host count cannot be retrieved!" numHosts, currentHost = struct.unpack("!BB", infos[:2]) hostNames = _hidpp20.get_host_names(device) hostNames = hostNames if hostNames is not None else {} if currentHost not in hostNames or hostNames[currentHost][1] == "": hostNames[currentHost] = (True, socket.gethostname().partition(".")[0]) choices = common.NamedInts() for host in range(0, numHosts): paired, hostName = hostNames.get(host, (True, "")) choices[host] = f"{str(host + 1)}:{hostName}" if hostName else str(host + 1) return cls(choices=choices, read_skip_byte_count=1) if choices and len(choices) > 1 else None _GESTURE2_GESTURES_LABELS = { GestureId.TAP_1_FINGER: (_("Single tap"), _("Performs a left click.")), GestureId.TAP_2_FINGER: (_("Single tap with two fingers"), _("Performs a right click.")), GestureId.TAP_3_FINGER: (_("Single tap with three fingers"), None), GestureId.CLICK_1_FINGER: (None, None), GestureId.CLICK_2_FINGER: (None, None), GestureId.CLICK_3_FINGER: (None, None), GestureId.DOUBLE_TAP_1_FINGER: (_("Double tap"), _("Performs a double click.")), GestureId.DOUBLE_TAP_2_FINGER: (_("Double tap with two fingers"), None), GestureId.DOUBLE_TAP_3_FINGER: (_("Double tap with three fingers"), None), GestureId.TRACK_1_FINGER: (None, None), GestureId.TRACKING_ACCELERATION: (None, None), GestureId.TAP_DRAG_1_FINGER: (_("Tap and drag"), _("Drags items by dragging the finger after double tapping.")), GestureId.TAP_DRAG_2_FINGER: ( _("Tap and drag with two fingers"), _("Drags items by dragging the fingers after double tapping."), ), GestureId.DRAG_3_FINGER: (_("Tap and drag with three fingers"), None), GestureId.TAP_GESTURES: (None, None), GestureId.FN_CLICK_GESTURE_SUPPRESSION: ( _("Suppress tap and edge gestures"), _("Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)."), ), GestureId.SCROLL_1_FINGER: (_("Scroll with one finger"), _("Scrolls.")), GestureId.SCROLL_2_FINGER: (_("Scroll with two fingers"), _("Scrolls.")), GestureId.SCROLL_2_FINGER_HORIZONTAL: (_("Scroll horizontally with two fingers"), _("Scrolls horizontally.")), GestureId.SCROLL_2_FINGER_VERTICAL: (_("Scroll vertically with two fingers"), _("Scrolls vertically.")), GestureId.SCROLL_2_FINGER_STATELESS: (_("Scroll with two fingers"), _("Scrolls.")), GestureId.NATURAL_SCROLLING: (_("Natural scrolling"), _("Inverts the scrolling direction.")), GestureId.THUMBWHEEL: (_("Thumbwheel"), _("Enables the thumbwheel.")), GestureId.V_SCROLL_INTERTIA: (None, None), GestureId.V_SCROLL_BALLISTICS: (None, None), GestureId.SWIPE_2_FINGER_HORIZONTAL: (None, None), GestureId.SWIPE_3_FINGER_HORIZONTAL: (None, None), GestureId.SWIPE_4_FINGER_HORIZONTAL: (None, None), GestureId.SWIPE_3_FINGER_VERTICAL: (None, None), GestureId.SWIPE_4_FINGER_VERTICAL: (None, None), GestureId.LEFT_EDGE_SWIPE_1_FINGER: (None, None), GestureId.RIGHT_EDGE_SWIPE_1_FINGER: (None, None), GestureId.BOTTOM_EDGE_SWIPE_1_FINGER: (None, None), GestureId.TOP_EDGE_SWIPE_1_FINGER: (_("Swipe from the top edge"), None), GestureId.LEFT_EDGE_SWIPE_1_FINGER_2: (_("Swipe from the left edge"), None), GestureId.RIGHT_EDGE_SWIPE_1_FINGER_2: (_("Swipe from the right edge"), None), GestureId.BOTTOM_EDGE_SWIPE_1_FINGER_2: (_("Swipe from the bottom edge"), None), GestureId.TOP_EDGE_SWIPE_1_FINGER_2: (_("Swipe from the top edge"), None), GestureId.LEFT_EDGE_SWIPE_2_FINGER: (_("Swipe two fingers from the left edge"), None), GestureId.RIGHT_EDGE_SWIPE_2_FINGER: (_("Swipe two fingers from the right edge"), None), GestureId.BOTTOM_EDGE_SWIPE_2_FINGER: (_("Swipe two fingers from the bottom edge"), None), GestureId.TOP_EDGE_SWIPE_2_FINGER: (_("Swipe two fingers from the top edge"), None), GestureId.ZOOM_2_FINGER: (_("Zoom with two fingers."), _("Pinch to zoom out; spread to zoom in.")), GestureId.ZOOM_2_FINGER_PINCH: (_("Pinch to zoom out."), _("Pinch to zoom out.")), GestureId.ZOOM_2_FINGER_SPREAD: (_("Spread to zoom in."), _("Spread to zoom in.")), GestureId.ZOOM_3_FINGER: (_("Zoom with three fingers."), None), GestureId.ZOOM_2_FINGER_STATELESS: (_("Zoom with two fingers"), _("Pinch to zoom out; spread to zoom in.")), GestureId.TWO_FINGERS_PRESENT: (None, None), GestureId.ROTATE_2_FINGER: (None, None), GestureId.FINGER_1: (None, None), GestureId.FINGER_2: (None, None), GestureId.FINGER_3: (None, None), GestureId.FINGER_4: (None, None), GestureId.FINGER_5: (None, None), GestureId.FINGER_6: (None, None), GestureId.FINGER_7: (None, None), GestureId.FINGER_8: (None, None), GestureId.FINGER_9: (None, None), GestureId.FINGER_10: (None, None), GestureId.DEVICE_SPECIFIC_RAW_DATA: (None, None), } _GESTURE2_PARAMS_LABELS = { ParamId.EXTRA_CAPABILITIES: (None, None), # not supported ParamId.PIXEL_ZONE: (_("Pixel zone"), None), # TO DO: replace None with a short description ParamId.RATIO_ZONE: (_("Ratio zone"), None), # TO DO: replace None with a short description ParamId.SCALE_FACTOR: (_("Scale factor"), _("Sets the cursor speed.")), } _GESTURE2_PARAMS_LABELS_SUB = { "left": (_("Left"), _("Left-most coordinate.")), "bottom": (_("Bottom"), _("Bottom coordinate.")), "width": (_("Width"), _("Width.")), "height": (_("Height"), _("Height.")), "scale": (_("Scale"), _("Cursor speed.")), } class Gesture2Gestures(settings.BitFieldWithOffsetAndMaskSetting): name = "gesture2-gestures" label = _("Gestures") description = _("Tweak the mouse/touchpad behaviour.") feature = _F.GESTURE_2 rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_options = {"om_method": hidpp20.Gesture.enable_offset_mask} choices_universe = hidpp20_constants.GestureId _labels = _GESTURE2_GESTURES_LABELS class validator_class(settings_validator.BitFieldWithOffsetAndMaskValidator): @classmethod def build(cls, setting_class, device, om_method=None): options = [g for g in device.gestures.gestures.values() if g.can_be_enabled or g.default_enabled] return cls(options, om_method=om_method) if options else None class Gesture2Divert(settings.BitFieldWithOffsetAndMaskSetting): name = "gesture2-divert" label = _("Gestures Diversion") description = _("Divert mouse/touchpad gestures.") feature = _F.GESTURE_2 rw_options = {"read_fnid": 0x30, "write_fnid": 0x40} validator_options = {"om_method": hidpp20.Gesture.diversion_offset_mask} choices_universe = hidpp20_constants.GestureId _labels = _GESTURE2_GESTURES_LABELS class validator_class(settings_validator.BitFieldWithOffsetAndMaskValidator): @classmethod def build(cls, setting_class, device, om_method=None): options = [g for g in device.gestures.gestures.values() if g.can_be_diverted] return cls(options, om_method=om_method) if options else None class Gesture2Params(settings.LongSettings): name = "gesture2-params" label = _("Gesture params") description = _("Change numerical parameters of a mouse/touchpad.") feature = _F.GESTURE_2 rw_options = {"read_fnid": 0x70, "write_fnid": 0x80} choices_universe = hidpp20_constants.ParamId sub_items_universe = hidpp20.SUB_PARAM # item (NamedInt) -> list/tuple of objects that have the following attributes # .id (sub-item text), .length (in bytes), .minimum and .maximum _labels = _GESTURE2_PARAMS_LABELS _labels_sub = _GESTURE2_PARAMS_LABELS_SUB class validator_class(settings_validator.MultipleRangeValidator): @classmethod def build(cls, setting_class, device): params = _hidpp20.get_gestures(device).params.values() items = [i for i in params if i.sub_params] if not items: return None sub_items = {i: i.sub_params for i in items} return cls(items, sub_items) class MKeyLEDs(settings.BitFieldSetting): name = "m-key-leds" label = _("M-Key LEDs") description = ( _("Control the M-Key LEDs.") + "\n" + _("May need Onboard Profiles set to Disable to be effective.") + "\n" + _("May need G Keys diverted to be effective.") ) feature = _F.MKEYS choices_universe = common.NamedInts() for i in range(8): choices_universe[1 << i] = "M" + str(i + 1) _labels = {k: (None, _("Lights up the %s key.") % k) for k in choices_universe} class rw_class(settings.FeatureRW): def __init__(self, feature): super().__init__(feature, write_fnid=0x10) def read(self, device): # no way to read, so just assume off return b"\x00" class validator_class(settings_validator.BitFieldValidator): @classmethod def build(cls, setting_class, device): number = device.feature_request(setting_class.feature, 0x00)[0] options = [setting_class.choices_universe[1 << i] for i in range(number)] return cls(options) if options else None class MRKeyLED(settings.Setting): name = "mr-key-led" label = _("MR-Key LED") description = ( _("Control the MR-Key LED.") + "\n" + _("May need Onboard Profiles set to Disable to be effective.") + "\n" + _("May need G Keys diverted to be effective.") ) feature = _F.MR class rw_class(settings.FeatureRW): def __init__(self, feature): super().__init__(feature, write_fnid=0x00) def read(self, device): # no way to read, so just assume off return b"\x00" ## Only implemented for devices that can produce Key and Consumer Codes (e.g., Craft) ## and devices that can produce Key, Mouse, and Horizontal Scroll (e.g., M720) ## Only interested in current host, so use 0xFF for it class PersistentRemappableAction(settings.Settings): name = "persistent-remappable-keys" label = _("Persistent Key/Button Mapping") description = ( _("Permanently change the mapping for the key or button.") + "\n" + _("Changing important keys or buttons (such as for the left mouse button) can result in an unusable system.") ) persist = False # This setting is persistent in the device so no need to persist it here feature = _F.PERSISTENT_REMAPPABLE_ACTION keys_universe = special_keys.CONTROL choices_universe = special_keys.KEYS class rw_class: def __init__(self, feature): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device, key): ks = device.remap_keys[device.remap_keys.index(key)] return b"\x00\x00" + ks.data_bytes def write(self, device, key, data_bytes): ks = device.remap_keys[device.remap_keys.index(key)] v = ks.remap(data_bytes) return v class validator_class(settings_validator.ChoicesMapValidator): @classmethod def build(cls, setting_class, device): remap_keys = device.remap_keys if not remap_keys: return None capabilities = device.remap_keys.capabilities if capabilities & 0x0041 == 0x0041: # Key and Consumer Codes keys = special_keys.KEYS_KEYS_CONSUMER elif capabilities & 0x0023 == 0x0023: # Key, Mouse, and HScroll Codes keys = special_keys.KEYS_KEYS_MOUSE_HSCROLL else: if logger.isEnabledFor(logging.WARNING): logger.warning("%s: unimplemented Persistent Remappable capability %s", device.name, hex(capabilities)) return None choices = {} for k in remap_keys: if k is not None: key = special_keys.CONTROL[k.key] choices[key] = keys # TO RECOVER FROM BAD VALUES use special_keys.KEYS return cls(choices, key_byte_count=2, byte_count=4) if choices else None def validate_read(self, reply_bytes, key): start = self._key_byte_count + self._read_skip_byte_count end = start + self._byte_count reply_value = common.bytes2int(reply_bytes[start:end]) & self.mask # Craft keyboard has a value that isn't valid so fudge these values if reply_value not in self.choices[key]: if logger.isEnabledFor(logging.WARNING): logger.warning("unusual persistent remappable action mapping %x: use Default", reply_value) reply_value = special_keys.KEYS_Default return reply_value class Sidetone(settings.Setting): name = "sidetone" label = _("Sidetone") description = _("Set sidetone level.") feature = _F.SIDETONE validator_class = settings_validator.RangeValidator min_value = 0 max_value = 100 class Equalizer(settings.RangeFieldSetting): name = "equalizer" label = _("Equalizer") description = _("Set equalizer levels.") feature = _F.EQUALIZER rw_options = {"read_fnid": 0x20, "write_fnid": 0x30, "read_prefix": b"\x00"} keys_universe = [] class validator_class(settings_validator.PackedRangeValidator): @classmethod def build(cls, setting_class, device): data = device.feature_request(_F.EQUALIZER, 0x00) if not data: return None count, dbRange, _x, dbMin, dbMax = struct.unpack("!BBBBB", data[:5]) if dbMin == 0: dbMin = -dbRange if dbMax == 0: dbMax = dbRange map = common.NamedInts() for g in range((count + 6) // 7): freqs = device.feature_request(_F.EQUALIZER, 0x10, g * 7) for b in range(7): if g * 7 + b >= count: break map[g * 7 + b] = str(int.from_bytes(freqs[2 * b + 1 : 2 * b + 3], "big")) + _("Hz") return cls(map, min_value=dbMin, max_value=dbMax, count=count, write_prefix_bytes=b"\x02") class ADCPower(settings.Setting): name = "adc_power_management" label = _("Power Management") description = _("Power off in minutes (0 for never).") feature = _F.ADC_MEASUREMENT min_version = 2 # documentation for version 1 does not mention this capability rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_class = settings_validator.RangeValidator min_value = 0x00 max_value = 0xFF validator_options = {"byte_count": 1} class HeadsetEcoMode(settings.Setting): name = "headset-eco-mode" label = _("Eco Mode") description = _("Battery saver mode.") feature = _F.HEADSET_BATTERY_SAVER validator_class = settings_validator.BooleanValidator @classmethod def build(cls, device): # G522 firmware rejects no-op writes with device-specific NACK 0x0B. # BooleanValidator.prepare_write already skips writes that match the # current value when needs_current_value=True; default-mask (0xFF) # BooleanValidators get needs_current_value=False, so flip it here. rw = settings.FeatureRW(cls.feature) validator = settings_validator.BooleanValidator() validator.needs_current_value = True return cls(device, rw, validator) class HeadsetDoNotDisturb(settings.Setting): name = "headset-do-not-disturb" label = _("Do Not Disturb") description = _("Suppress notification sounds.") feature = _F.HEADSET_DO_NOT_DISTURB validator_class = settings_validator.BooleanValidator class HeadsetMicMute(settings.Setting): name = "headset-mic-mute" label = _("Mic Mute") description = _("Mute the microphone.") feature = _F.HEADSET_MIC_MUTE validator_class = settings_validator.BooleanValidator # HEADSET_MIC_MUTE (0x0601) doesn't follow the typical fn 0 GetState / # fn 1 SetState pattern that BooleanValidator defaults to. Function # layout (confirmed via G HUB pcap on G522): # fn 0 — physical-mute-switch state-change events from the device # fn 1 — state-change events emitted as the device's echo of a # host-driven SetState; also serves as the host-callable # GetState read # fn 2 — host-callable SetState (single byte: 0=unmuted, 1=muted) # The standard fn 0/1 write path returns 0x0A UNSUPPORTED. State-change # events from both fn 0 and fn 1 are handled by _process_feature_notification # so the toggle reflects physical mute presses too. rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} class HeadsetMicSNR(settings.Setting): name = "headset-mic-snr" label = _("Mic SNR") description = _("Microphone signal-to-noise ratio enhancement.") feature = _F.HEADSET_MIC_SNR validator_class = settings_validator.BooleanValidator class HeadsetAINR(settings.Setting): name = "headset-ai-nr" label = _("AI Noise Reduction") description = _("Enable AI noise reduction.") feature = _F.HEADSET_AI_NOISE_REDUCTION validator_class = settings_validator.BooleanValidator class HeadsetAINRLevel(settings.Setting): name = "headset-ai-nr-level" label = _("AI Noise Reduction Level") description = _("AI noise reduction intensity.") feature = _F.HEADSET_AI_NOISE_REDUCTION rw_options = {"read_fnid": 0x20, "write_fnid": 0x30} validator_class = settings_validator.ChoicesValidator choices_universe = common.NamedInts(Off=0, Low=1, Medium=2, High=3) class HeadsetSidetone(settings.Setting): name = "headset-sidetone" label = _("Headset Sidetone") description = _("Sidetone level (0 = off, 100 = max).") feature = _F.HEADSET_AUDIO_SIDETONE rw_options = {"read_fnid": 0x00, "write_fnid": 0x10} min_value = 0 max_value = 100 class validator_class(settings_validator.RangeValidator): """UI value is 0-100 percent; the wire level is a gain-step index 0..N-1. N (gain_steps) comes from getSidetoneLevelSettings on V2 devices, or defaults to 101 on V1 — which makes step == percent, so V1 round-trips unchanged. The firmware silently ignores out-of-range step writes, so writes are clamped to N-1.""" gain_steps = 101 def _level_bytes(self, raw): return common.bytes2int(raw[self.read_skip_byte_count : self.read_skip_byte_count + self._byte_count]) def validate_read(self, reply_bytes): level = self._level_bytes(reply_bytes) steps = self.gain_steps return int(round(level * 100 / (steps - 1))) if steps > 1 else level def prepare_write(self, new_value, current_value=None): steps = self.gain_steps level = int(round((steps - 1) * new_value / 100)) if steps > 1 else new_value level = max(0, min((steps - 1) if steps > 1 else self.max_value, level)) to_write = self.write_prefix_bytes + common.int2bytes(level, self._byte_count) if current_value is not None and self._level_bytes(current_value) == level: return None return to_write @classmethod def build(cls, device): # Version <= 1: GetSidetone returns [mic_count, mic_id, level]; SetSidetone takes [mic_id, level] # Version > 1: GetSidetone returns [mic_count, mic_id, reserved, level]; SetSidetone takes [mic_id, 0xFF, level] version = device.features.get_feature_version(cls.feature) or 0 if version > 1: skip, prefix = 3, b"\x01\xff" else: skip, prefix = 2, b"\x01" # V2 getSidetoneLevelSettings (fn 2) reply byte 2 is the gain-step count N. # V1 has no such call — N stays 101 (step == percent). Raw reply still # logged at debug so a G HUB setpoint correlation can refine the layout. gain_steps = 101 if version > 1: try: reply = device.feature_request(cls.feature, 0x20) except Exception as e: reply = None logger.debug("%s: getSidetoneLevelSettings probe raised %s", cls.name, e) logger.debug("%s: getSidetoneLevelSettings raw reply: %s", cls.name, reply.hex() if reply else reply) if reply is not None and len(reply) >= 3 and reply[2] > 1: gain_steps = reply[2] rw = settings.FeatureRW(cls.feature, **cls.rw_options) validator = cls.validator_class.build(cls, device, read_skip_byte_count=skip, write_prefix_bytes=prefix) if validator: validator.gain_steps = gain_steps return cls(device, rw, validator) class HeadsetMicGain(settings.Setting): name = "headset-mic-gain" label = _("Mic Gain") description = _("Microphone gain level.") feature = _F.HEADSET_MIC_GAIN rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_class = settings_validator.RangeValidator # Fallback range covers int8; build() overrides with device-reported bounds # from GetInfo (fn 0) so SetMicGain doesn't get device-specific # out-of-range NACK (error 0x0B) on devices that use a small signed range # (e.g. G522 reports a narrow window like -12..+12). min_value = -128 max_value = 127 validator_options = {"byte_count": 1, "signed": True} @classmethod def build(cls, device): # GetInfo (function 0) returns [min_gain (int8), max_gain (int8)]. # Query once at build time so the slider range reflects the device's # actual supported range rather than a generic int8 window. try: info = device.feature_request(cls.feature, 0x00) except Exception as e: logger.debug("HeadsetMicGain: GetInfo raised %s, using fallback int8 range", e) info = None if info and len(info) >= 2: min_gain = struct.unpack("b", bytes([info[0]]))[0] max_gain = struct.unpack("b", bytes([info[1]]))[0] if max_gain <= min_gain: # sanity — fall back to class defaults logger.debug( "HeadsetMicGain: GetInfo returned nonsense range [%d, %d] (hex=%s), using fallback int8 range", min_gain, max_gain, info.hex(), ) min_gain, max_gain = cls.min_value, cls.max_value elif logger.isEnabledFor(logging.DEBUG): logger.debug( "HeadsetMicGain: device reports gain range [%d, %d]", min_gain, max_gain, ) else: logger.debug( "HeadsetMicGain: GetInfo returned %s, using fallback int8 range", info.hex() if info else info, ) min_gain, max_gain = cls.min_value, cls.max_value rw = settings.FeatureRW(cls.feature, **cls.rw_options) validator = settings_validator.RangeValidator(min_value=min_gain, max_value=max_gain, byte_count=1, signed=True) return cls(device, rw, validator) class HeadsetMixBalance(settings.Setting): name = "headset-mix-balance" label = _("Audio Mix Balance") description = _("Balance between game and chat audio.") feature = _F.HEADSET_MIX validator_class = settings_validator.RangeValidator min_value = 0 max_value = 255 validator_options = {"byte_count": 1} class _AutoSleepRangeValidator(settings_validator.RangeValidator): """Single-slot read-modify-write validator for HID++ 0x0108 AutoSleep. 0x0108 is not a single timer: V3 has two uint8 bytes, V4+ has three. Each byte is an independent timer slot. Solaar exposes only the user-facing slot today and preserves the others via RMW; writing zero into the other slots causes the firmware to reject the request. Wire byte layout per feature version: V<3: [timer] V3: [reserved, timer] — preserve byte[0] V4+: [timer_a, timer_b, timer_c] — preserve byte[1], byte[2] """ def __init__(self, byte_count, **kwargs): super().__init__(byte_count=byte_count, **kwargs) # V3 sources the user-controllable timer from byte[1] per LGHUB. self._slot = 1 if byte_count == 2 else 0 def validate_read(self, reply_bytes): if len(reply_bytes) <= self._slot: raise AssertionError( f"{self.__class__.__name__}: read returned {len(reply_bytes)} bytes, expected ≥ {self._slot + 1}" ) return reply_bytes[self._slot] def prepare_write(self, new_value, current_value=None): if new_value < self.min_value or new_value > self.max_value: raise ValueError(f"invalid choice {new_value!r}") if current_value is None: payload = bytearray(self._byte_count) else: payload = bytearray(current_value[: self._byte_count]) if len(payload) < self._byte_count: payload.extend(b"\x00" * (self._byte_count - len(payload))) if payload[self._slot] == new_value: return None payload[self._slot] = new_value return bytes(payload) class HeadsetAutoSleep(settings.Setting): name = "headset-auto-sleep" label = _("Auto Sleep Timeout") description = _("Idle time in minutes before the headset enters sleep mode (0 = disabled).") feature = _F.CENTURION_AUTO_SLEEP rw_options = {"read_fnid": 0x00, "write_fnid": 0x10} validator_class = _AutoSleepRangeValidator min_value = 0 max_value = 255 # uint8 slot validator_options = {"byte_count": 1} @classmethod def build(cls, device): version = device.features.get_feature_version(cls.feature) or 0 if version >= 4: byte_count = 3 elif version >= 3: byte_count = 2 else: byte_count = 1 rw = settings.FeatureRW(cls.feature, **cls.rw_options) validator = _AutoSleepRangeValidator(min_value=0, max_value=cls.max_value, byte_count=byte_count) return cls(device, rw, validator) class HeadsetOnboardEQ(settings.RangeFieldSetting): name = "headset-onboard-eq" label = _("Headset Equalizer") description = _("Set equalizer levels.") feature = _F.HEADSET_ONBOARD_EQ rw_options = {"read_fnid": 0x10, "write_fnid": 0x20, "read_prefix": b"\x00"} keys_universe = [] class validator_class(settings_validator.PackedRangeValidator): kind = settings.Kind.GRAPHIC_EQ @classmethod def build(cls, setting_class, device): info = hidpp20.get_onboard_eq_info(device) if not info: logger.debug("HeadsetOnboardEQ.build: getEQInfo failed, no panel will be built") return None _has_hw_eq, num_bands = info bands = hidpp20.get_onboard_eq_params(device, slot=0x00) if not bands: logger.debug("HeadsetOnboardEQ.build: getEQParameters returned no bands, no panel will be built") return None if len(bands) != num_bands: logger.debug( "HeadsetOnboardEQ.build: band count mismatch — EQInfo=%d getEQParameters=%d; skipping", num_bands, len(bands), ) return None keys = common.NamedInts() for i, (freq, _gain, _q) in enumerate(bands): keys[i] = str(freq) + _("Hz") v = cls(keys, min_value=-12, max_value=12, count=num_bands, byte_count=1) v._band_freqs = [freq for freq, _g, _q in bands] v._band_qs = [q for _f, _g, q in bands] logger.debug("HeadsetOnboardEQ.build: panel built with %d band(s)", num_bands) return v def validate_read(self, reply_bytes): if reply_bytes is None or len(reply_bytes) < 2: return {} band_count = reply_bytes[1] result = {} offset = 2 for i in range(band_count): if offset + 4 > len(reply_bytes): break freq = struct.unpack(">H", reply_bytes[offset : offset + 2])[0] gain = struct.unpack("b", bytes([reply_bytes[offset + 2]]))[0] q = reply_bytes[offset + 3] result[i] = gain # Update stored freq/Q arrays if they exist if hasattr(self, "_band_freqs") and i < len(self._band_freqs): self._band_freqs[i] = freq if hasattr(self, "_band_qs") and i < len(self._band_qs): self._band_qs[i] = q offset += 4 return result def prepare_write(self, new_values): if not hasattr(self, "_band_freqs") or not hasattr(self, "_band_qs"): return None bands = [] for i in range(self.count): freq = self._band_freqs[i] if i < len(self._band_freqs) else 1000 q = self._band_qs[i] if i < len(self._band_qs) else 10 gain = new_values.get(i, 0) bands.append((freq, gain, q)) self._pending_bands = bands # stash for persist step return hidpp20._build_set_eq_payload(0x00, bands) def write(self, map, save=True): result = super().write(map, save) # Also persist to device flash (slot 0x80) so EQ survives power cycle if result is not None and hasattr(self._validator, "_pending_bands"): bands = self._validator._pending_bands del self._validator._pending_bands try: self._device.feature_request(_F.HEADSET_ONBOARD_EQ, 0x20, hidpp20._build_set_eq_payload(0x80, bands)) except Exception: logger.warning("HeadsetOnboardEQ: failed to persist EQ to slot 0x80") return result class HeadsetAdvancedEQ(settings.RangeFieldSetting): """Per-band gain editor for the headset's active AdvancedParaEQ (0x020D) slot. V2 wire format (pcap-verified against G522 LIGHTSPEED): getCustomEQ response: [dir_echo] + N × [freq_hi, freq_lo, filter, gain_hi, gain_lo] setCustomEQ request: [dir, slot, pad=0] + N × [freq_hi, freq_lo, filter, gain_hi, gain_lo] Gain is offset-binary against gain_min..gain_max with `gain_steps` discrete positions (raw=120 ≈ 0 dB on G522's [-6, +6] / 241-step grid). Frequency and filter type are read at build time and not user-editable today — UI only exposes per-band gain. """ name = "headset-advanced-eq" label = _("Headset Advanced EQ") description = _("Per-band gain for the headset's active parametric EQ.") feature = _F.HEADSET_ADVANCED_PARA_EQ rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} keys_universe = [] class rw_class(settings.FeatureRW): """get/setCustomEQ both take [direction, slot]; on writes the device additionally expects a single 0x00 padding byte before the band payload. The slot is the *active* EQ preset, which the device may have switched while we weren't looking — re-query it on every read and write instead of caching at build time. Direction is hardcoded to 0 (playback); mic-side EQ isn't exposed yet. """ def read(self, device, data_bytes=b""): active_slot = hidpp20.get_advanced_eq_active_slot(device, direction=0) self.read_prefix = bytes([0, active_slot if active_slot is not None else 0]) return super().read(device, data_bytes) def write(self, device, data_bytes): active_slot = hidpp20.get_advanced_eq_active_slot(device, direction=0) slot = active_slot if active_slot is not None else 0 write_bytes = bytes([0, slot, 0]) + data_bytes return device.feature_request(self.feature, self.write_fnid, write_bytes) class validator_class(settings_validator.PackedRangeValidator): kind = settings.Kind.GRAPHIC_EQ @classmethod def build(cls, setting_class, device): info = hidpp20.get_advanced_eq_info(device) if not info: logger.debug("HeadsetAdvancedEQ.build: getEQInfos failed, no panel will be built") return None device._advanced_eq_info = info version = info["version"] gain_min = info["gain_min_db"] gain_max = info["gain_max_db"] step_db = info["step_db"] active_slot = hidpp20.get_advanced_eq_active_slot(device, direction=0) or 0 bands = hidpp20.get_advanced_eq_params(device, direction=0, slot=active_slot) if not bands: logger.debug("HeadsetAdvancedEQ.build: getCustomEQ returned no bands, no panel will be built") return None band_count = len(bands) expected = info.get("band_count") if expected is not None and expected != band_count: logger.debug( "HeadsetAdvancedEQ.build: V%d band count mismatch — EQInfos=%d getCustomEQ=%d; trusting getCustomEQ", version, expected, band_count, ) keys = common.NamedInts() for i, (filter_type, freq_hz, _gain_db) in enumerate(bands): if filter_type == hidpp20.FILTER_TYPE_HP: keys[i] = "HP " + str(freq_hz) + _("Hz") else: keys[i] = str(freq_hz) + _("Hz") v = cls( keys, min_value=int(round(gain_min)), max_value=int(round(gain_max)), count=band_count, byte_count=1, ) v._version = version v._step_db = step_db v._gain_min = gain_min v._gain_max = gain_max v._gain_steps = info.get("gain_steps", 241) v._band_types = [band[0] for band in bands] v._band_freqs = [band[1] for band in bands] v._active_slot = active_slot logger.debug( "HeadsetAdvancedEQ.build: panel built V%d with %d band(s), slot=%d, range=[%d,%d], step_db=%.4f", version, band_count, active_slot, gain_min, gain_max, step_db, ) # One-shot per-slot probe — logs band data for each slot the # firmware actually honors and caches the working-slot list on # `device._advanced_eq_working_slots`. Cheap if HeadsetActiveEQPreset # already populated the cache (it usually has at this point); # otherwise this is the first-time probe. if version >= 2: try: hidpp20.probe_advanced_eq_slots(device, direction=0, info=info) except Exception as e: logger.debug("HeadsetAdvancedEQ.build: preset corpus probe failed: %s", e) return v def validate_read(self, reply_bytes): if reply_bytes is None: return {} version = getattr(self, "_version", 0) if version >= 2: info = { "gain_min_db": getattr(self, "_gain_min", -6), "gain_max_db": getattr(self, "_gain_max", 6), "gain_steps": getattr(self, "_gain_steps", 241), "step_db": getattr(self, "_step_db", 0.05), } bands = hidpp20.parse_v2_bands(reply_bytes, info) if bands is None: return {} result = {} for i, (filter_type, freq_hz, gain_db) in enumerate(bands): if i >= self.count: break result[i] = int(round(gain_db)) if hasattr(self, "_band_types") and i < len(self._band_types): self._band_types[i] = filter_type if hasattr(self, "_band_freqs") and i < len(self._band_freqs): self._band_freqs[i] = freq_hz return result # V0/V1: 3-byte stride. result = {} offset = 0 i = 0 while offset + 3 <= len(reply_bytes) and i < self.count: freq = struct.unpack(">H", reply_bytes[offset : offset + 2])[0] if freq == 0: break gain = struct.unpack("b", bytes([reply_bytes[offset + 2]]))[0] result[i] = gain if hasattr(self, "_band_freqs") and i < len(self._band_freqs): self._band_freqs[i] = freq offset += 3 i += 1 return result def prepare_write(self, new_values): """Encode N × [freq_hi, freq_lo, filter, gain_hi, gain_lo]. new_values is {band_idx: int_gain_dB}. freq and filter type come from the cache captured at build time; gain is mapped from integer dB back to the device's offset-binary raw u16 against the [_gain_min, _gain_max] / _gain_steps grid. """ version = getattr(self, "_version", 0) if version < 2: return None gain_min = getattr(self, "_gain_min", -6) gain_max = getattr(self, "_gain_max", 6) steps = getattr(self, "_gain_steps", 241) freqs = getattr(self, "_band_freqs", None) or [] types = getattr(self, "_band_types", None) or [] if not freqs or not types: return None span = gain_max - gain_min payload = bytearray() for i in range(self.count): freq = freqs[i] if i < len(freqs) else 0 filt = types[i] if i < len(types) else hidpp20.FILTER_TYPE_PEAKING_G522 gain_db = new_values.get(i, 0) if steps > 1 and span > 0: raw = int(round((gain_db - gain_min) / span * (steps - 1))) else: raw = 0 raw = max(0, min(steps - 1, raw)) payload += bytes([(freq >> 8) & 0xFF, freq & 0xFF, filt & 0xFF, (raw >> 8) & 0xFF, raw & 0xFF]) return bytes(payload) def write(self, map, save=True): # RangeFieldSetting.write treats an empty-bytes reply (`not reply`) # as failure, but setCustomEQ returns an empty ACK on success. # Override to treat only `reply is None` (transport error/timeout) # as failure. assert hasattr(self, "_value") assert hasattr(self, "_device") assert map is not None if self._device.online: self.update(map, save) data_bytes = self._validator.prepare_write(self._value) if data_bytes is not None: reply = self._rw.write(self._device, data_bytes) if reply is None: return None return map def _is_valid_persisted_value(self, value): """True iff `value` is a well-formed band-gain dict for the current validator: a dict with exactly `count` int keys covering [0, count), each mapped to an int within [min_value, max_value]. Used to detect stale persister entries from older Solaar builds whose V2 parser had a different stride/header (commits prior to 7c73c888) and produced partial dicts or out-of-range gain values.""" validator = getattr(self, "_validator", None) if not isinstance(value, dict) or validator is None: return False count = getattr(validator, "count", 0) if count == 0 or len(value) != count: return False mn = getattr(validator, "min_value", None) mx = getattr(validator, "max_value", None) if mn is None or mx is None: return False for i in range(count): if i not in value: return False v = value[i] if not isinstance(v, int) or v < mn or v > mx: return False return True def apply(self): """Validate the persisted EQ against the live device state before pushing. Setting.apply uses cached=True so the persister is treated as authoritative — that's wrong here because (a) the EQ can be changed externally (LGHUB, onboard preset buttons) and (b) older Solaar V2 parsers stored partial/out-of-range dicts that prepare_write silently fills with 0 dB, overwriting user EQ with zeros. Strategy: if the persisted value is well-formed, apply it normally (matches existing Solaar semantics). If it's corrupt, treat the device's live read as truth and reseed the persister from it without writing back. If both are invalid, skip this setting only — apply_all_settings keeps going.""" assert hasattr(self, "_value") assert hasattr(self, "_device") if not self._device.online: return persister = getattr(self._device, "persister", None) persisted = persister.get(self.name) if persister else None persisted_valid = self._is_valid_persisted_value(persisted) try: live = self.read(cached=False) except Exception as e: logger.warning("%s: live EQ read failed during apply (%s): %s", self.name, self._device, repr(e)) live = None live_valid = self._is_valid_persisted_value(live) if persisted_valid: try: self.write(persisted, save=False) except Exception as e: logger.warning("%s: error applying %s (%s): %s", self.name, persisted, self._device, repr(e)) elif live_valid: logger.info( "%s: rejecting stale persister value %r; reseeding from device live %r", self.name, persisted, live, ) self._value = live if persister is not None: persister[self.name] = live else: logger.warning( "%s: both persisted (%r) and live (%r) values invalid; skipping apply", self.name, persisted, live, ) class HeadsetActiveEQPreset(settings.Setting): """Choose which AdvancedParaEQ slot drives live audio. Activation works for any slot — read-only factory presets and user-custom slots alike. The "(factory)" tag in the slot label distinguishes the read-only ones; that distinction matters for band-editing (not supported yet), not for activation today. """ name = "headset-eq-active-preset" label = _("EQ Preset") description = _("Switch the active EQ preset. Factory presets are read-only.") feature = _F.HEADSET_ADVANCED_PARA_EQ rw_options = {"read_fnid": 0x30, "write_fnid": 0x40, "prefix": b"\x00"} validator_class = settings_validator.ChoicesValidator @classmethod def build(cls, device): info = getattr(device, "_advanced_eq_info", None) or hidpp20.get_advanced_eq_info(device) if not info: return None ro_count = info.get("onboard_ro_preset_count", 0) or 0 # Probe each advertised slot — getEQInfos may report capacity that # the firmware doesn't actually back (G522 advertises 16 slots but # only honors slot 0). Only include slots that responded with band # data; the result is cached on device._advanced_eq_working_slots # so HeadsetAdvancedEQ.build can reuse it without re-probing. working = hidpp20.probe_advanced_eq_slots(device, direction=0, info=info) if len(working) <= 1: # One option (or zero) is meaningless as a selector — there's # nothing for the user to choose between. The active EQ is # whatever slot 0 has, no preset switching is available. return None choices = common.NamedInts() for slot, slot_name, _bands in working: if not slot_name: slot_name = _("Slot") + " " + str(slot) if slot < ro_count: slot_name = slot_name + " " + _("(factory)") choices[slot] = slot_name rw = settings.FeatureRW(cls.feature, **cls.rw_options) validator = settings_validator.ChoicesValidator(choices=choices) return cls(device, rw, validator) def write(self, value, save=True): result = super().write(value, save) if result is not None: # After setActiveEQ, repopulate the AdvancedParaEQ band-display # cache so the panel reflects the newly-active slot. Force a # fresh read so _value is a real dict — leaving it as None # would let a UI band-click hit `_value[item]` on None and # crash (config_panel.py:589 'NoneType' is not subscriptable). # The visible widget redraw still waits for a manual refresh / # panel reopen — auto-redraw would need UI-side plumbing. eq_panel = _headset_setting_by_name(self._device, HeadsetAdvancedEQ.name) if eq_panel is not None: try: eq_panel._value = None eq_panel.read(cached=False) except Exception as e: logger.debug("HeadsetActiveEQPreset: failed to refresh EQ panel: %s", e) return result _NO_CHANGE_COLOR = int(special_keys.COLORSPLUS["No change"]) def _headset_setting_by_name(device, name): for s in getattr(device, "settings", None) or []: if getattr(s, "name", None) == name: return s return None def _headset_primary_color(device, default=0xFFFFFF): """The headset's base color — the 0x0621 onboard Fixed-effect color. Per-zone 'No change' cells resolve against this. Returns `default` when the onboard-effect setting is absent or not currently on Fixed.""" s = _headset_setting_by_name(device, HeadsetOnboardEffect.name) value = getattr(s, "_value", None) if s is not None else None if value is not None and int(getattr(value, "ID", -1)) == 0: return int(getattr(value, "color1", default)) return default def _headset_cluster_effect_is_fixed(device): """True when the 0x0621 onboard effect is Fixed (the Static analog), or when the device has no onboard-effect setting. A non-Fixed cluster animation masks the per-zone buffer, so per-zone writes are suppressed while one runs.""" s = _headset_setting_by_name(device, HeadsetOnboardEffect.name) if s is None: return True value = getattr(s, "_value", None) if value is None: persister = getattr(device, "persister", None) value = persister.get(HeadsetOnboardEffect.name) if persister else None if value is None: return True return int(getattr(value, "ID", 0)) == 0 def _headset_per_zone_overrides(device): """Return `{zone_id: color_int}` for zones with explicit (non-'No change') colors set via the Per-zone Lighting setting, or `None` if the setting isn't built/present.""" s = _headset_setting_by_name(device, HeadsetPerZoneLighting.name) if s is None: return None value = getattr(s, "_value", None) if not isinstance(value, dict): return None overrides = {} for zone, color in value.items(): try: color_int = int(color) except (TypeError, ValueError): continue if color_int != _NO_CHANGE_COLOR: overrides[int(zone)] = color_int return overrides def _headset_reassert_zone_layer(device): """Re-paint the per-zone layer: every zone to the LEDs Primary color, then the explicit per-zone overrides on top. The headset firmware drops the host-painted per-zone buffer whenever a cluster layer is (re)written — so any path that re-asserts a cluster layer (LED Control re-claim, onboard Static color change) must call this to restore the per-zone paint. No-op unless the onboard effect is Fixed; a non-Static animation owns the LEDs and masks per-zone anyway. """ if not _headset_cluster_effect_is_fixed(device): return zones = headset_rgb.discover_zones(device) if not zones: return zone_map = {int(z): _headset_primary_color(device) for z in zones} zone_map.update(_headset_per_zone_overrides(device) or {}) headset_rgb.write_zone_map(device, zone_map) def _headset_led_control_on(device): """True when the headset LED Control is on (Solaar drives the LEDs). When off, the firmware owns the LEDs and host color writes are suppressed — the value is still persisted so it re-applies on switch-on. Reads setting._value first, then the persister; accepts a bool or a legacy int 0/1 from the old ChoicesValidator era.""" s = _headset_setting_by_name(device, HeadsetLEDControl.name) v = getattr(s, "_value", None) if s is not None else None if v is None: persister = getattr(device, "persister", None) v = persister.get(HeadsetLEDControl.name) if persister else None if v is None: return True # unknown — don't suppress return bool(v) class HeadsetLEDControl(settings.Setting): """Whether Solaar holds the headset's live-coloring claim. Mirrors the `RGBControl` pattern for keyboards and mice. On = Solaar may drive the LEDs — the 0x0621 onboard effect and 0x0620 per-zone painting are both live LED control; off = Solaar releases the LEDs so another app (e.g. OpenRGB) can drive them. The 0x0622 signature effects are stored settings (startup/shutdown colors), not live coloring, and stay editable either way. """ name = "headset_led_control" label = _("LED Control") description = _("Allow Solaar to control the headset LED zones.") feature = _F.HEADSET_RGB_HOSTMODE rw_options = {"read_fnid": 0x70, "write_fnid": 0x80} # Two-state — render as a Gtk.Switch. Wire byte: 1 = Solaar (host) control, # 0 = Device (firmware) control. validator_class = settings_validator.BooleanValidator validator_options = {"true_value": 1, "false_value": 0} def _pre_read(self, cached, key=None): # Migrate legacy int values (0/1 from the old ChoicesValidator) to bool. super()._pre_read(cached, key) if isinstance(self._value, int) and not isinstance(self._value, bool): self._value = self._value != 0 @classmethod def build(cls, device): # One-shot read-only probe of 0x0621 / 0x0622 — logs the data the RE # pass needs to pin down RGB onboard/signature effect structures. # Skip cleanly if neither feature is exposed. try: rgb_effects_probe.probe(device) except Exception as e: logger.debug("RGB effects probe raised %r", e) return super().build(device) def write(self, value, save=True): # On re-claim the firmware drops our colors; reassert the dominant # layer — per-zone when the onboard effect is Static, else the effect. result = super().write(value, save) if result is not None and value and self._device.online: if _headset_cluster_effect_is_fixed(self._device): _headset_reassert_zone_layer(self._device) else: onboard = next((s for s in self._device.settings if s.name == "headset-onboard-effect"), None) if onboard is not None and onboard._value is not None: onboard.write(onboard._value, save=False) return result class HeadsetPerZoneLighting(settings.Settings): """Per-zone LED color overrides. Mirrors `PerKeyLighting` — keys are firmware zone IDs, values are 24-bit RGB ints with the `-1` sentinel meaning "inherit the current `LEDs Primary` color." Surfaces in the UI via the per-key painter. """ name = "headset_per_zone_lighting" label = _("Per-zone Lighting") description = _( "Override individual zone colors. 'No change' inherits the LEDs Primary color.\n" "LED Control needs to be set to Solaar to be effective." ) feature = _F.HEADSET_RGB_HOSTMODE persist = True editor_class = "solaar.ui.perkey.control:PerKeyControl" class rw_class(settings.FeatureRWMap): pass class validator_class(settings_validator.MapRangeValidator): _COLOR_RANGE = settings_validator.Range(min=0, max=0xFFFFFF, byte_count=3) @classmethod def build(cls, setting_class, device): zones = headset_rgb.discover_zones(device) if not zones: return None choices_map = {common.NamedInt(int(z), _("Zone") + " " + str(int(z))): cls._COLOR_RANGE for z in zones} return cls(choices_map) if choices_map else None def read(self, cached=True): self._pre_read(cached) if cached and self._value is not None: return self._value # Device doesn't expose current per-zone state; default every # zone to "No change" so the primary color shows through. reply_map = {int(key): _NO_CHANGE_COLOR for key in self._validator.choices} self._value = reply_map return reply_map def _resolve_zone_map(self, map_, primary): """Substitute 'No change' entries with the primary color.""" resolved = {} for key, value in map_.items(): try: v = int(value) except (TypeError, ValueError): continue resolved[int(key)] = primary if v == _NO_CHANGE_COLOR else v return resolved def write(self, map_, save=True): device = self._device if not device.online: return None self.update(map_, save) # Gate the wire on both conditions, like keyboard per-key (needs # rgb_control on + zone Static): LED Control on, cluster effect Fixed. if not _headset_led_control_on(device) or not _headset_cluster_effect_is_fixed(device): return map_ # value stored, skip the wire primary = _headset_primary_color(device) zone_map = self._resolve_zone_map(map_, primary) if not zone_map: return map_ headset_rgb.write_zone_map(device, zone_map) return map_ def write_key_value(self, key, value, save=True): result = super().write_key_value(int(key), value, save) device = self._device if not device.online: return result if not _headset_led_control_on(device) or not _headset_cluster_effect_is_fixed(device): return result # value stored, skip the wire try: v = int(value) except (TypeError, ValueError): return result effective = _headset_primary_color(device) if v == _NO_CHANGE_COLOR else v headset_rgb.write_zone_map(device, {int(key): int(effective)}) return result class _HeadsetSignatureEffect: """A 0x0622 signature-effect slot value: an enable byte, two colors and a speed. Synthetic 8-byte form [ID, R1,G1,B1, R2,G2,B2, speed] — ID is 0x01 on / 0x02 off. The rw_class splits it across get/setSignatureEffectParams (colors + speed) and get/setSignatureEffectState (the enable byte).""" def __init__(self, ID=1, color1=0, color2=0, speed=0): self.ID = int(ID) self.speed = max(0, min(100, int(speed))) for k, v in (("color1", color1), ("color2", color2)): setattr(self, k, common.ColorInt(int(v) & 0xFFFFFF)) @classmethod def from_bytes(cls, data, options=None): if data is None or len(data) < 8: return cls() c1 = (data[1] << 16) | (data[2] << 8) | data[3] c2 = (data[4] << 16) | (data[5] << 8) | data[6] return cls(ID=data[0], color1=c1, color2=c2, speed=data[7]) def to_bytes(self, options=None): return bytes( [ self.ID & 0xFF, (self.color1 >> 16) & 0xFF, (self.color1 >> 8) & 0xFF, self.color1 & 0xFF, (self.color2 >> 16) & 0xFF, (self.color2 >> 8) & 0xFF, self.color2 & 0xFF, self.speed & 0xFF, ] ) def __eq__(self, other): return isinstance(other, self.__class__) and self.to_bytes() == other.to_bytes() def __str__(self): return yaml.dump(self, width=float("inf")).rstrip("\n") @classmethod def from_yaml(cls, loader, node): return cls(**loader.construct_mapping(node)) @classmethod def to_yaml(cls, dumper, data): return dumper.represent_mapping("!HeadsetSignatureEffect", data.__dict__, flow_style=True) yaml.SafeLoader.add_constructor("!HeadsetSignatureEffect", _HeadsetSignatureEffect.from_yaml) yaml.add_representer(_HeadsetSignatureEffect, _HeadsetSignatureEffect.to_yaml) class _HeadsetSignatureEffectSetting(settings.Setting): """One firmware signature-effect slot on HEADSET_RGB_SIGNATURE_EFFECTS (0x0622). Subclasses set effect_id (0 startup, 1 shutdown, 2 passive). Build probes the slot via getSignatureEffectState and suppresses the setting if the device doesn't expose it. These run autonomously on the device firmware, so — like the keyboard boot animations — they are not gated on host LED control.""" feature = _F.HEADSET_RGB_SIGNATURE_EFFECTS effect_id: int = 0 _ENABLED_CHOICES = common.NamedInts(**{"On": 1, "Off": 2}) _COLOR1_FIELD = {"name": "color1", "kind": settings.Kind.COLOR, "label": _("Primary")} _COLOR2_FIELD = {"name": "color2", "kind": settings.Kind.COLOR, "label": _("Secondary")} _SPEED_FIELD = {"name": "speed", "kind": settings.Kind.RANGE, "label": _("Speed"), "min": 0, "max": 100} class rw_class: kind = settings.FeatureRW.kind def __init__(self, feature, effect_id): self.feature = feature self._eid = bytes([(effect_id >> 8) & 0xFF, effect_id & 0xFF]) def read(self, device): params = device.feature_request(self.feature, 0x10, self._eid) # getSignatureEffectParams state = device.feature_request(self.feature, 0x30, self._eid) # getSignatureEffectState if params is None or len(params) < 9 or state is None or len(state) < 3: return None # params: [effectId, R1,G1,B1, R2,G2,B2, speed]; state: [effectId, enabled] return bytes([state[2]]) + params[2:9] def write(self, device, data_bytes): # data_bytes: [enabled, R1,G1,B1, R2,G2,B2, speed] params = device.feature_request(self.feature, 0x20, self._eid + data_bytes[1:8]) state = device.feature_request(self.feature, 0x40, self._eid + data_bytes[0:1]) return data_bytes if params is not None and state is not None else None @classmethod def build(cls, device): eid = bytes([(cls.effect_id >> 8) & 0xFF, cls.effect_id & 0xFF]) try: state = device.feature_request(cls.feature, 0x30, eid) # probe: is this slot present? except exceptions.FeatureCallError: return None if state is None or len(state) < 3: return None # NVconfig-saved colors are default-DENY: signature effects persist to # device storage, so a slot is shown only on models explicitly known- # good. allowed is None on an unlisted model/slot (suppress the whole # setting), else the set of fields the firmware honors. The G522 # passive slot is deliberately unlisted — its behavior is unknown. # SOLAAR_EXPERIMENTAL unmasks everything. allowed = device_quirks.headset_signature_allowed_fields(device, cls.effect_id) if allowed is None: return None # Log getSignatureEffectsInfo (fn 0) once per device — its byte layout # isn't pinned down, so slot discovery uses per-slot probing for now. if not getattr(device, "_headset_sig_info_logged", False): device._headset_sig_info_logged = True try: info = device.feature_request(cls.feature, 0x00) logger.debug("%s: getSignatureEffectsInfo raw reply: %s", cls.name, info.hex() if info else info) except Exception as e: logger.debug("%s: getSignatureEffectsInfo probe raised %s", cls.name, e) rw = cls.rw_class(cls.feature, cls.effect_id) validator = settings_validator.HeteroValidator(data_class=_HeadsetSignatureEffect, options=None) setting = cls(device, rw, validator) # Enable byte as a right-aligned Gtk.Switch (on=1 / off=2); colors and # speed stay visible in both states so toggling Off keeps them. id_field = {"name": "ID", "kind": settings.Kind.TOGGLE, "label": None, "on_value": 1, "off_value": 2} setting.possible_fields = [id_field, cls._COLOR1_FIELD, cls._COLOR2_FIELD, cls._SPEED_FIELD] visible = {f: 1 for f in ("color1", "color2", "speed") if f in allowed} setting.fields_map = { int(cls._ENABLED_CHOICES["On"]): (cls._ENABLED_CHOICES["On"], visible), int(cls._ENABLED_CHOICES["Off"]): (cls._ENABLED_CHOICES["Off"], visible), } return setting class HeadsetSignatureStartupEffect(_HeadsetSignatureEffectSetting): name = "headset-signature-startup" label = _("Startup Effect") description = ( _("Firmware lighting effect played when the headset powers on or wakes.") + "\n" + _("Device default: Primary #00B8FC, Secondary #FF00AB, Speed 100.") ) effect_id = 0 class HeadsetSignatureShutdownEffect(_HeadsetSignatureEffectSetting): name = "headset-signature-shutdown" label = _("Shutdown Effect") description = ( _("Firmware lighting effect played when the headset powers off or sleeps.") + "\n" + _("Device default: Primary #00B8FC, Secondary #FF00AB, Speed 100.") ) effect_id = 1 class HeadsetSignaturePassiveEffect(_HeadsetSignatureEffectSetting): name = "headset-signature-passive" label = _("Passive Effect") description = ( _("Firmware lighting effect played while the headset is idle.") + "\n" + _("Device default: Primary #00B8FC, Secondary #FF00AB, Speed 75.") ) effect_id = 2 class _HeadsetOnboardEffect: """A 0x0621 onboard RGB effect: an effect ID plus the parameters that effect uses. Synthetic form [effectId_u16_BE, 7 param bytes]; to_bytes / from_bytes encode the per-effect parameter layout (the rw_class adds the leading clusterIndex). intensity is a 0-100 percent; saturation is a raw 0-255 byte (same as the keyboard RGB effects).""" # Per-effect default parameter values, applied only to fields left # unset (passed as None). An explicit value is always honored — passing # 0 means the caller chose 0, e.g. a black Static color1 turns the LEDs # off. Only a genuinely absent field falls back to the default (a fresh # effect-pick seeds its RANGE widgets UI-side via _apply_id_defaults). # Defaults confirmed against the LGHUB binary decode of 0x0621. _DEFAULTS = { 0: {"color1": 0xFFFFFF}, # Static / Fixed 1: {"intensity": 100, "saturation": 255, "period": 5000}, # Color Cycle 2: {"intensity": 100, "saturation": 255, "period": 5000}, # Color Wave 3: {"color1": 0xFFFFFF, "intensity": 100, "period": 5000}, # Breathing 4: {"color1": 0xFFFFFF, "color2": 0x0000FF, "intensity": 100}, # Dual Color } # speed is accepted only to load configs persisted before the 0x0621 # decode (DualColor byte 6 was mislabelled "speed"; it is intensity). def __init__(self, ID=0, color1=None, color2=None, intensity=None, saturation=None, period=None, speed=0, direction=None): self.ID = int(ID) defaults = self._DEFAULTS.get(self.ID, {}) color1 = defaults.get("color1", 0) if color1 is None else color1 color2 = defaults.get("color2", 0) if color2 is None else color2 intensity = defaults.get("intensity", 0) if intensity is None else intensity saturation = defaults.get("saturation", 0) if saturation is None else saturation period = defaults.get("period", 0) if period is None else period direction = defaults.get("direction", 0) if direction is None else direction self.intensity = max(0, min(100, int(intensity))) self.saturation = max(0, min(255, int(saturation))) self.period = max(0, min(0xFFFF, int(period))) self.direction = max(0, min(3, int(direction))) for k, v in (("color1", color1), ("color2", color2)): setattr(self, k, common.ColorInt(int(v) & 0xFFFFFF)) @classmethod def from_bytes(cls, data, options=None): if data is None or len(data) < 9: return cls() eid = (data[0] << 8) | data[1] p = data[2:9] kw = {"ID": eid} if eid == 0: # Fixed kw["color1"] = (p[0] << 16) | (p[1] << 8) | p[2] elif eid in (1, 2): # ColorCycle / ColorWave kw["intensity"] = p[0] kw["period"] = (p[1] << 8) | p[2] kw["saturation"] = p[3] if eid == 2: kw["direction"] = p[4] elif eid == 3: # Breathing: R, G, B, intensity, period u16 BE kw["color1"] = (p[0] << 16) | (p[1] << 8) | p[2] kw["intensity"] = p[3] kw["period"] = (p[4] << 8) | p[5] elif eid == 4: # DualColor: R1, G1, B1, R2, G2, B2, intensity kw["color1"] = (p[0] << 16) | (p[1] << 8) | p[2] kw["color2"] = (p[3] << 16) | (p[4] << 8) | p[5] kw["intensity"] = p[6] return cls(**kw) def to_bytes(self, options=None): eid = self.ID p = bytearray(7) c1, c2 = int(self.color1), int(self.color2) if eid == 0: # Fixed: R, G, B p[0], p[1], p[2] = (c1 >> 16) & 0xFF, (c1 >> 8) & 0xFF, c1 & 0xFF elif eid in (1, 2): # ColorCycle / ColorWave p[0] = self.intensity p[1], p[2] = (self.period >> 8) & 0xFF, self.period & 0xFF p[3] = self.saturation if eid == 2: p[4] = self.direction elif eid == 3: # Breathing: R, G, B, intensity, period u16 BE, pad p[0], p[1], p[2] = (c1 >> 16) & 0xFF, (c1 >> 8) & 0xFF, c1 & 0xFF p[3] = self.intensity p[4], p[5] = (self.period >> 8) & 0xFF, self.period & 0xFF elif eid == 4: # DualColor: R1,G1,B1, R2,G2,B2, intensity p[0], p[1], p[2] = (c1 >> 16) & 0xFF, (c1 >> 8) & 0xFF, c1 & 0xFF p[3], p[4], p[5] = (c2 >> 16) & 0xFF, (c2 >> 8) & 0xFF, c2 & 0xFF p[6] = self.intensity return bytes([(eid >> 8) & 0xFF, eid & 0xFF]) + bytes(p) def __eq__(self, other): return isinstance(other, self.__class__) and self.to_bytes() == other.to_bytes() def __str__(self): return yaml.dump(self, width=float("inf")).rstrip("\n") @classmethod def from_yaml(cls, loader, node): return cls(**loader.construct_mapping(node)) @classmethod def to_yaml(cls, dumper, data): return dumper.represent_mapping("!HeadsetOnboardEffect", data.__dict__, flow_style=True) yaml.SafeLoader.add_constructor("!HeadsetOnboardEffect", _HeadsetOnboardEffect.from_yaml) yaml.add_representer(_HeadsetOnboardEffect, _HeadsetOnboardEffect.to_yaml) class HeadsetOnboardEffect(settings.Setting): """The RGB effect the headset shows on its primary lighting cluster (HEADSET_RGB_ONBOARD_EFFECTS, 0x0621). Build reads the cluster's supported-effect set so the picker offers only those. This is live LED control, like per-zone painting — gated on Solaar holding the LED-control claim: writes are skipped and the row greys out when the claim is released. Multi-cluster devices (none seen yet) drive only cluster 0.""" name = "headset-onboard-effect" label = _("Onboard Effect") description = _("Firmware RGB effect the headset plays on its own.") feature = _F.HEADSET_RGB_ONBOARD_EFFECTS _CLUSTER = 0 # Custom (5) is intentionally absent — it is a stored card-reference # effect, not a parametric one; it cannot be set via setRGBClusterEffect. _ALL_EFFECTS = ( ("Static", 0), ("Color Cycle", 1), ("Color Wave", 2), ("Breathing", 3), ("Dual Color", 4), ) _EFFECT_FIELDS = { 0: ("color1",), 1: ("intensity", "period", "saturation"), 2: ("intensity", "period", "saturation", "direction"), 3: ("color1", "intensity", "period"), 4: ("color1", "color2", "intensity"), } _DIRECTIONS = common.NamedInts(**{"Horizontal": 0, "Vertical": 1, "Reverse Horizontal": 2, "Reverse Vertical": 3}) class rw_class: kind = settings.FeatureRW.kind def __init__(self, feature, cluster): self.feature = feature self._cluster = cluster def read(self, device): reply = device.feature_request(self.feature, 0x20, bytes([self._cluster])) # getRGBClusterEffect if reply is None or len(reply) < 10: return None return reply[1:10] # strip clusterIndex -> [effectId_u16, 7 param bytes] def write(self, device, data_bytes): # data_bytes is [effectId_u16, 7 param bytes]; prepend clusterIndex. # The onboard effect is live LED control — skip the wire when Solaar # doesn't hold the claim; the value is still persisted. if not _headset_led_control_on(device): return data_bytes reply = device.feature_request(self.feature, 0x30, bytes([self._cluster]) + bytes(data_bytes)) return data_bytes if reply is not None else None @classmethod def build(cls, device): try: info = device.feature_request(cls.feature, 0x10, bytes([cls._CLUSTER])) # getRGBClusterInfo except exceptions.FeatureCallError: return None if info is None or len(info) < 1: return None # [count, count x {effectId_u16_BE, caps_u16_BE}] — take effectId of each entry supported = [] for i in range(info[0]): off = 1 + i * 4 if off + 2 > len(info): break eid = (info[off] << 8) | info[off + 1] if 0 <= eid <= 4 and eid not in supported: supported.append(eid) if not supported: # Unparseable reply — offer the five parametric effects; the # firmware rejects any it doesn't support. Custom (5) is never # offered here. See the 0x0621 fallback note in protocol RE. supported = [0, 1, 2, 3, 4] rw = cls.rw_class(cls.feature, cls._CLUSTER) validator = settings_validator.HeteroValidator(data_class=_HeadsetOnboardEffect, options=None) setting = cls(device, rw, validator) id_choices = common.NamedInts(**{name: eid for name, eid in cls._ALL_EFFECTS if eid in supported}) id_field = {"name": "ID", "kind": settings.Kind.CHOICE, "label": None, "choices": id_choices} setting.possible_fields = [ id_field, {"name": "color1", "kind": settings.Kind.COLOR, "label": _("Primary")}, {"name": "color2", "kind": settings.Kind.COLOR, "label": _("Secondary")}, {"name": "intensity", "kind": settings.Kind.RANGE, "label": _("Intensity"), "min": 0, "max": 100}, {"name": "saturation", "kind": settings.Kind.RANGE, "label": _("Saturation"), "min": 0, "max": 255}, { "name": "period", "kind": settings.Kind.RANGE, "label": _("Period"), "min": 1000, "max": 20000, "display_seconds": True, }, {"name": "direction", "kind": settings.Kind.CHOICE, "label": _("Direction"), "choices": cls._DIRECTIONS}, ] setting.fields_map = {eid: (id_choices[eid], {field: 1 for field in cls._EFFECT_FIELDS[eid]}) for eid in supported} return setting def write(self, value, save=True): # Writing the 0x0621 cluster effect re-fills every LED uniformly; the # firmware treats that as dropping the host per-zone buffer. After a # Static write, re-overlay the per-zone paint so individually-colored # zones survive a LEDs Primary change. _headset_reassert_zone_layer is # a no-op for non-Static effects (the animation masks per-zone). result = super().write(value, save) if result is not None and self._device.online and _headset_led_control_on(self._device): _headset_reassert_zone_layer(self._device) return result # ---------------------------------------------------------------------------- # LogiVoice (0x0900 + 0x0901..0x0907) — read-only presentation pass. # # Per module we auto-generate two settings: # 1. A flat State toggle — reads GetState (fn 1), renders as a boolean. # Top-level so users see a direct on/off indicator at a glance. # 2. A collapsible "Parameters" panel — one MULTIPLE_RANGE-kind setting # that reads GetParameters (fn 3) once and distributes the bytes to # per-field sliders. The existing MultipleRangeControl widget is # collapsible by default, so the field-level clutter stays folded. # # Writes are disabled — the Parameters struct carries fields whose wire # encodings are still ambiguous (see logivoice.py) and a SetParameters # write must bundle all fields at once. A write pass can be added once # each field's encoding is confirmed live. # ---------------------------------------------------------------------------- class _LogiVoiceStateSetting(settings.Setting): """Per-module State toggle. Reads GetState (fn 1) and writes SetState (fn 0). State wire format is unambiguous (one byte: 0 = off, 1 = on), so this is the one piece of the LogiVoice surface we enable for writes. The per-module Parameters struct stays read-only until each field's encoding is confirmed. """ rw_options = {"read_fnid": logivoice.FN_GET_STATE, "write_fnid": logivoice.FN_SET_STATE} validator_class = settings_validator.BooleanValidator @classmethod def build(cls, device): # Corpus probe runs here (once per module) so -dd users get a full # snapshot of state + raw Parameters + raw Info for future decoding. try: logivoice.probe_module(device, cls.feature) except Exception as e: logger.debug("LogiVoice probe_module(%s) raised %s", cls.feature, e) return super().build(device) class _LogiVoiceModuleItem: """Top-level MULTIPLE_RANGE item representing one LogiVoice module. One `item` per setting — the module itself. `__int__` returns the feature id so the Setting's reply dict is keyed predictably. """ def __init__(self, feature: hidpp20_constants.SupportedFeature): self._feature = feature self.id = logivoice.MODULE_SLUGS.get(feature, f"0x{int(feature):04X}") self.index = 0 def __int__(self): return int(self._feature) def __str__(self): return logivoice.MODULE_NAMES.get(self._feature, f"0x{int(self._feature):04X}") class _LogiVoiceFieldSubItem: """MULTIPLE_RANGE sub-item wrapping one decoded Parameters field. MultipleRangeControl reads minimum/maximum/length/widget/str(). We pick SpinButton for wide ranges (0..65535) where a 64k-step slider is useless, and Scale for small ranges (e.g. signed int8 thresholds). """ def __init__(self, field: logivoice.Field): self._field = field self.id = field.name self.minimum = field.min_value self.maximum = field.max_value self.length = field.byte_count self.widget = "SpinButton" if (field.max_value - field.min_value) > 512 else "Scale" def __int__(self): return hash(self.id) & 0xFFFFFF def __str__(self): return self._field.label + (" (raw)" if self._field.opaque else "") class _LogiVoiceParametersValidator(settings_validator.MultipleRangeValidator): """Reads the whole GetParameters struct once and distributes bytes to fields. MULTIPLE_RANGE's default read loop fires prepare_read_item once per top- level item; we have exactly one item (the module), so this issues a single GetParameters call. validate_read_item parses the shared reply into a {field_name: value} dict. Writes are blocked. """ def __init__(self, feature: hidpp20_constants.SupportedFeature): fields = logivoice.PARAMETERS_FIELDS.get(feature, []) self._fields = list(fields) item = _LogiVoiceModuleItem(feature) sub_items = {item: [_LogiVoiceFieldSubItem(f) for f in fields]} super().__init__(items=[item], sub_items=sub_items) def prepare_read_item(self, item): return b"" # GetParameters takes no wire arguments def validate_read(self, reply_bytes): # Setting.read() calls validate_read with the raw GetParameters reply. # MultipleRangeValidator only defines validate_read_item, so wrap that # call — we have a single item (the module) so one call suffices. item = self.items[0] return {int(item): self.validate_read_item(reply_bytes, item)} def validate_read_item(self, reply_bytes, item): parsed = {} # Key by str(sub_item) so MultipleRangeControl.set_value can look up # values via v[str(sub_item)] — the UI uses the label as the dict key. for sub in self.sub_items[item]: f = sub._field end = f.offset + f.byte_count if end > len(reply_bytes): continue chunk = reply_bytes[f.offset : end] if f.byte_count == 1: v = struct.unpack("b" if f.signed else "B", chunk)[0] elif f.byte_count == 2: v = struct.unpack(">h" if f.signed else ">H", chunk)[0] else: v = int.from_bytes(chunk, "big", signed=f.signed) parsed[str(sub)] = v return parsed def prepare_write_item(self, item, value): return None def prepare_write(self, value): return None class _LogiVoiceParametersSetting(settings.Setting): """Collapsible read-only display of one module's GetParameters struct.""" rw_options = {"read_fnid": logivoice.FN_GET_PARAMETERS} persist = False kind = settings.Kind.MULTIPLE_RANGE @classmethod def build(cls, device): if not logivoice.PARAMETERS_FIELDS.get(cls.feature): return None rw = settings.FeatureRW(cls.feature, **cls.rw_options) validator = _LogiVoiceParametersValidator(cls.feature) return cls(device, rw, validator) def write(self, map, save=True): return None def _logivoice_make_state_class(feature: hidpp20_constants.SupportedFeature): slug = logivoice.MODULE_SLUGS.get(feature) if not slug: return None module_name = logivoice.MODULE_NAMES.get(feature, f"0x{int(feature):04X}") attrs = { "name": f"logivoice-{slug}-state", "label": f"LogiVoice {module_name}", "description": f"Enable the headset {module_name} processing block.", "feature": feature, } return type(f"LogiVoice_{slug}_State", (_LogiVoiceStateSetting,), attrs) def _logivoice_make_parameters_class(feature: hidpp20_constants.SupportedFeature): slug = logivoice.MODULE_SLUGS.get(feature) if not slug or not logivoice.PARAMETERS_FIELDS.get(feature): return None module_name = logivoice.MODULE_NAMES.get(feature, f"0x{int(feature):04X}") attrs = { "name": f"logivoice-{slug}-parameters", "label": f"LogiVoice {module_name}: Parameters (read-only)", "description": ( f"Decoded {module_name} GetParameters fields. " "Opaque raw values shown where the wire encoding isn't confirmed yet." ), "feature": feature, } return type(f"LogiVoice_{slug}_Parameters", (_LogiVoiceParametersSetting,), attrs) _LOGIVOICE_SETTINGS: list[type] = [] for _feature in logivoice.PARAMETERS_FIELDS: _state_cls = _logivoice_make_state_class(_feature) if _state_cls is not None: _LOGIVOICE_SETTINGS.append(_state_cls) # Parameters panels are read-only and the wire encoding is only # partially decoded — hide from the UI until we can write them back. # _params_cls = _logivoice_make_parameters_class(_feature) # if _params_cls is not None: # _LOGIVOICE_SETTINGS.append(_params_cls) class BrightnessControl(settings.Setting): name = "brightness_control" label = _("Brightness Control") description = _("Control overall brightness") feature = _F.BRIGHTNESS_CONTROL rw_options = {"read_fnid": 0x10, "write_fnid": 0x20} validator_class = settings_validator.RangeValidator def __init__(self, device, rw, validator): super().__init__(device, rw, validator) rw.on_off = validator.on_off rw.min_nonzero_value = validator.min_value validator.min_value = 0 if validator.on_off else validator.min_value def write(self, value, save=True): # Snap to firmware-driven halving levels (off only at exact 0). steps = getattr(self._validator, "steps", 0) marks = halving_marks(self._validator.max_value, steps) if value is not None and marks: if value <= 0: value = 0 else: nonzero = [m for m in marks if m > 0] if nonzero: value = min(reversed(nonzero), key=lambda m: abs(m - value)) return super().write(value, save) class rw_class(settings.FeatureRW): def read(self, device, data_bytes=b""): if self.on_off: reply = device.feature_request(self.feature, 0x30) if not reply[0] & 0x01: return b"\x00\x00" return super().read(device, data_bytes) def write(self, device, data_bytes): if self.on_off: off = int.from_bytes(data_bytes, byteorder="big") < self.min_nonzero_value reply = device.feature_request(self.feature, 0x40, b"\x00" if off else b"\x01", no_reply=False) if off: return reply return super().write(device, data_bytes) class validator_class(settings_validator.RangeValidator): @classmethod def build(cls, setting_class, device): reply = device.feature_request(_F.BRIGHTNESS_CONTROL) assert reply, "Oops, brightness range cannot be retrieved!" if reply: max_value = int.from_bytes(reply[0:2], byteorder="big") steps_and_flags = reply[2] caps = reply[3] min_value = int.from_bytes(reply[4:6], byteorder="big") on_off = bool(caps & 0x04) if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s BrightnessControl getInfo: %s — max=%d min=%d steps_and_flags=0x%02x caps=0x%02x on_off=%s", device, reply[:8].hex(), max_value, min_value, steps_and_flags, caps, on_off, ) validator = cls(min_value=min_value, max_value=max_value, byte_count=2) validator.on_off = on_off validator.steps = steps_and_flags & 0x0F device._brightness_steps = validator.steps # for sibling settings (e.g. idle Dim) return validator class LEDControl(settings.Setting): name = "led_control" label = _("LED Control") description = _("Allow Solaar to control LED zones.") feature = _F.COLOR_LED_EFFECTS rw_options = {"read_fnid": 0x70, "write_fnid": 0x80} # Two-state setting — render as a Gtk.Switch rather than a 2-option combo. # true_value=1 / false_value=0 are the wire bytes for Solaar / Device mode. validator_class = settings_validator.BooleanValidator validator_options = {"true_value": 1, "false_value": 0} def _pre_read(self, cached, key=None): # Migrate legacy int values (0/1) stored under the old ChoicesValidator # to bool so the switch widget gets a value it can set_state() on. super()._pre_read(cached, key) if isinstance(self._value, int) and not isinstance(self._value, bool): self._value = self._value != 0 colors = special_keys.COLORS _LEDP = hidpp20.LEDParam # an LED Zone has an index, a set of possible LED effects, and an LED effect setting class LEDZoneSetting(settings.Setting): name = "led_zone_" # the trailing underscore signals that this setting creates other settings label = _("LED Zone Effects") description = _("Set effect for LED Zone") + "\n" + _("LED Control needs to be enabled.") feature = _F.COLOR_LED_EFFECTS color_field = {"name": _LEDP.color, "kind": settings.Kind.COLOR, "label": _("Color")} speed_field = {"name": _LEDP.speed, "kind": settings.Kind.RANGE, "label": _("Speed"), "min": 0, "max": 255} period_field = { "name": _LEDP.period, "kind": settings.Kind.RANGE, "label": _("Period"), "min": 1000, "max": 20000, "display_seconds": True, } intensity_field = {"name": _LEDP.intensity, "kind": settings.Kind.RANGE, "label": _("Intensity"), "min": 0, "max": 100} ramp_field = {"name": _LEDP.ramp, "kind": settings.Kind.CHOICE, "label": _("Ramp"), "choices": hidpp20.LedRampChoice} saturation_field = {"name": _LEDP.saturation, "kind": settings.Kind.RANGE, "label": _("Saturation"), "min": 0, "max": 255} form_field = {"name": _LEDP.form, "kind": settings.Kind.CHOICE, "label": _("Waveform"), "choices": hidpp20.LedFormChoices} direction_field = { "name": _LEDP.direction, "kind": settings.Kind.CHOICE, "label": _("Direction"), "choices": hidpp20.LedDirectionChoices, } # Per-widget visibility driven by LEDEffects[ID][1]; RGBEffectSetting # overrides this list to drop ramp/form on 0x8071. possible_fields = [ color_field, speed_field, period_field, intensity_field, ramp_field, saturation_field, form_field, direction_field, ] @classmethod def setup(cls, device, read_fnid, write_fnid, suffix): infos = device.led_effects possible_fields = cls._device_possible_fields(device) settings_ = [] for zone in infos.zones: prefix = common.int2bytes(zone.index, 1) rw = settings.FeatureRW(cls.feature, read_fnid, write_fnid, prefix=prefix, suffix=suffix) validator = settings_validator.HeteroValidator( data_class=hidpp20.LEDEffectSetting, options=zone.effects, readable=infos.readable and read_fnid is not None ) setting = cls(device, rw, validator) setting.name = cls.name + str(int(zone.location)) setting.label = _("LEDs") + " " + str(hidpp20.LEDZoneLocations[zone.location]) choices = [hidpp20.LEDEffects[e.ID][0] for e in zone.effects if e.ID in hidpp20.LEDEffects] ID_field = {"name": "ID", "kind": settings.Kind.CHOICE, "label": None, "choices": choices} setting.possible_fields = [ID_field] + possible_fields setting.fields_map = hidpp20.LEDEffects settings_.append(setting) return settings_ @classmethod def _device_possible_fields(cls, device): return _possible_fields_with_direction_filter(device, cls.possible_fields, cls.direction_field) @classmethod def build(cls, device): return cls.setup(device, 0xE0, 0x30, b"") class RGBControl(settings.Setting): name = "rgb_control" label = _("LED Control") description = _("Allow Solaar to control LED zones.") feature = _F.RGB_EFFECTS rw_options = {"read_fnid": 0x50, "write_fnid": 0x50} # Two-state setting — render as a Gtk.Switch rather than a 2-option combo. # true_value=3 / false_value=0 are the wire bytes for Solaar / Device mode # returned by GetSWControl after the 1-byte sub-fn echo. Mode 3 is the # full SW takeover the claim handshake below expects. validator_class = settings_validator.BooleanValidator validator_options = {"true_value": 3, "false_value": 0, "write_prefix_bytes": b"\x01", "read_skip_byte_count": 1} def _pre_read(self, cached, key=None): # Migrate legacy int values (0/3) stored under the old ChoicesValidator # to bool so the switch widget gets a value it can set_state() on. super()._pre_read(cached, key) if isinstance(self._value, int) and not isinstance(self._value, bool): self._value = self._value != 0 def write(self, value, save=True): assert hasattr(self, "_value") assert hasattr(self, "_device") assert value is not None device = self._device if not device.online: return None if self._value != value: self.update(value, save) claiming = int(value) != 0 # any non-zero value is a Solaar-side claim if claiming: self._claim_sw_control(device) else: self._release_sw_control(device) return value def _claim_sw_control(self, device): # Disable firmware power management via profile management or onboard profiles if device.features and _F.PROFILE_MANAGEMENT in device.features: device.feature_request(_F.PROFILE_MANAGEMENT, 0x60, b"\x05") elif device.features and _F.ONBOARD_PROFILES in device.features: device.feature_request(_F.ONBOARD_PROFILES, 0x10, b"\x02") # Claim LED pipeline: SetSWControl(mode=3, flags=5) device.feature_request(_F.RGB_EFFECTS, 0x50, rgb_power.SW_ACTIVE) # Reset per-key one-shot flags so the first write after this claim # re-fires the prep + double-send. for s in device.settings: if s.name == "per-key-lighting": s._frame_settled = False s._prep_pushed = False break # Start software power management rgb_power.start(device) # Register cleanup for graceful release on device close if rgb_power.cleanup not in device.cleanups: device.cleanups.append(rgb_power.cleanup) # Repaint LEDs with Solaar's saved state. Without this the firmware's # last-active onboard profile keeps showing until the user changes # something — the takeover would look like it did nothing. self._repaint_after_claim(device) def _repaint_after_claim(self, device): """Push saved zone effects and (if opted in) per-key buffer to the device after a fresh SW claim. Best-effort: individual failures get logged but don't abort the rest of the repaint.""" for s in device.settings: if s.name.startswith("rgb_zone_") and s._value is not None: try: s.write(s._value, save=False) except Exception as e: logger.warning("%s: post-claim repaint of %s failed: %s", device, s.name, e) perkey, has_paint = rgb_power.perkey_has_paint(device) if has_paint and perkey._value is not None: try: perkey.write(perkey._value, save=False) except Exception as e: logger.warning("%s: post-claim per-key repaint failed: %s", device, e) def _release_sw_control(self, device): # If we never claimed in this session, don't touch the device at all. # The presence of an RGBPowerManager is the canonical "we claimed" signal # — _claim_sw_control creates it via rgb_power.start, and stop() pops it. had_claim = rgb_power.get_manager(device) is not None rgb_power.stop(device) if not had_claim: return # Release LED pipeline: SetSWControl(mode=0, flags=0) device.feature_request(_F.RGB_EFFECTS, 0x50, rgb_power.SW_RELEASE) # Restore firmware power management if device.features and _F.PROFILE_MANAGEMENT in device.features: device.feature_request(_F.PROFILE_MANAGEMENT, 0x60, b"\x03") elif device.features and _F.ONBOARD_PROFILES in device.features: device.feature_request(_F.ONBOARD_PROFILES, 0x10, b"\x01") # Keep cleanup registered on devices that support the shutdown effect # cap — it also fires the firmware shutdown animation trigger on exit. if not getattr(device, "_rgb_has_shutdown_cap", False): if rgb_power.cleanup in device.cleanups: device.cleanups.remove(rgb_power.cleanup) class RGBIdleTimeout(settings.Setting): name = "rgb_idle_timeout" label = _("Idle Timeout") description = _("Time without input before LED idle effect starts.") + "\n" + _("LED Control needs to be enabled.") feature = _F.RGB_EFFECTS choices_universe = common.NamedInts( **{ "Disabled": 0, "15 Seconds": 15, "30 Seconds": 30, "1 Minute": 60, "2 Minutes": 120, "5 Minutes": 300, } ) validator_class = settings_validator.ChoicesValidator validator_options = {"choices": choices_universe} class rw_class: def __init__(self, feature, **kwargs): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device): return common.int2bytes(60, 2) # default 1 minute def write(self, device, data_bytes): timeout = int.from_bytes(data_bytes, byteorder="big") mgr = rgb_power.get_manager(device) if mgr: mgr.set_idle_timeout(timeout) return True class RGBIdleEffect(settings.Setting): """Idle-effect setting with per-effect sub-widgets. Persisted value is an LEDEffectSetting; legacy bare-int values are migrated in `_pre_read`.""" name = "rgb_idle_effect" label = _("Idle Effect") description = ( _("What happens to LEDs when idle — dim to a percentage, change the base color, or play an animation.") + "\n" + _("LED Control needs to be enabled.") ) feature = _F.RGB_EFFECTS # Reuse zone fields so idle controls match the active-zone setup exactly. # Idle-specific intensity override carries the halving marks for Dim. intensity_field = {**LEDZoneSetting.intensity_field, "halving": True} period_field = LEDZoneSetting.period_field saturation_field = LEDZoneSetting.saturation_field speed_field = LEDZoneSetting.speed_field direction_field = LEDZoneSetting.direction_field color_field = LEDZoneSetting.color_field possible_fields = [color_field, speed_field, period_field, intensity_field, saturation_field, direction_field] class rw_class: def __init__(self, feature, **kwargs): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device): return hidpp20.LEDEffectSetting(ID=0x80, intensity=50).to_bytes() def write(self, device, data_bytes): value = hidpp20.LEDEffectSetting.from_bytes(data_bytes) mgr = rgb_power.get_manager(device) if mgr: mgr.set_idle_effect(value) return True def _pre_read(self, cached, key=None): """Migrate legacy bare-int values to LEDEffectSetting on first read.""" super()._pre_read(cached, key) if self._value is None or isinstance(self._value, hidpp20.LEDEffectSetting): return if not isinstance(self._value, int): return legacy = self._value if legacy == 0: migrated = hidpp20.LEDEffectSetting(ID=0x00) elif legacy in (25, 50, 75): migrated = hidpp20.LEDEffectSetting(ID=0x80, intensity=legacy) elif legacy == 0x0A: migrated = hidpp20.LEDEffectSetting(ID=0x0A, period=3000, intensity=100) elif legacy == 0x0B: migrated = hidpp20.LEDEffectSetting(ID=0x0B, period=3000) else: return # unrecognized — leave alone, write() will error informatively if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: migrating legacy bare-int %s to LEDEffectSetting on %s", self.name, legacy, self._device, ) self._value = migrated if getattr(self._device, "persister", None) is not None: self._device.persister[self.name] = self._value # Ripple needs keyboard input to animate so it can't run while idle. # Disabled (0x00) and Dim (0x80) are seeded into choice_ids directly. # Static (0x01) is also seeded so it appears right below Dim regardless # of probe-derived ID ordering. _IDLE_EXCLUDED_IDS = frozenset({0x00, 0x0B, 0x17}) @classmethod def build(cls, device): rw = cls.rw_class(cls.feature) # No change → Dim → Static, then any probed device-specific effects. choice_ids = [0x00, 0x80, 0x01] probed = set() try: infos = device.led_effects if infos and infos.zones: probed = {int(e.ID) for e in infos.zones[0].effects} except Exception: pass for eid in sorted(probed): if eid in cls._IDLE_EXCLUDED_IDS or eid in choice_ids: continue if eid not in hidpp20.LEDEffects: continue choice_ids.append(eid) idle_disabled = common.NamedInt(0x00, _("No change")) choices = [idle_disabled if i == 0x00 else hidpp20.LEDEffects[i][0] for i in choice_ids] ID_field = {"name": "ID", "kind": settings.Kind.CHOICE, "label": None, "choices": choices} fields_map = { 0x00: [idle_disabled, {}], 0x80: [ hidpp20.LEDEffects[0x80][0], {hidpp20.LEDParam.intensity: 0}, {hidpp20.LEDParam.intensity: 50}, ], } for eid in choice_ids: if eid not in fields_map: fields_map[eid] = hidpp20.LEDEffects[eid] validator = settings_validator.HeteroValidator(data_class=hidpp20.LEDEffectSetting, options=None, readable=True) setting = cls(device, rw, validator) setting.possible_fields = [ID_field] + _possible_fields_with_direction_filter( device, cls.possible_fields, cls.direction_field ) setting.fields_map = fields_map return setting class RGBSleepTimeout(settings.Setting): name = "rgb_sleep_timeout" label = _("Sleep Timeout") description = _("Time without input before LEDs fade off completely.") + "\n" + _("LED Control needs to be enabled.") feature = _F.RGB_EFFECTS choices_universe = common.NamedInts( **{ "Disabled": 0, "2 Minutes": 120, "5 Minutes": 300, "10 Minutes": 600, "15 Minutes": 900, "30 Minutes": 1800, } ) validator_class = settings_validator.ChoicesValidator validator_options = {"choices": choices_universe} class rw_class: def __init__(self, feature, **kwargs): self.feature = feature self.kind = settings.FeatureRW.kind def read(self, device): return common.int2bytes(300, 2) # default 5 minutes def write(self, device, data_bytes): timeout = int.from_bytes(data_bytes, byteorder="big") mgr = rgb_power.get_manager(device) if mgr: mgr.set_sleep_timeout(timeout) return True class _RgbBootEffect: """NvConfig persistent boot/shutdown effect payload on RGBEffects (0x8071). Wire format (7 bytes, NvConfig cap 0x0001 startup / 0x0040 shutdown): [enabled, R1, G1, B1, R2, G2, B2] enabled: 0x01 on, 0x02 off. Colors are kept editable in both states so toggling Off doesn't lose the user's chosen color. """ _COLOR_ATTRS = ("color1", "color2") def __init__(self, ID=1, color1=0, color2=0): self.ID = int(ID) for k, v in (("color1", color1), ("color2", color2)): iv = int(v) & 0xFFFFFF setattr(self, k, common.ColorInt(iv)) @classmethod def from_bytes(cls, data, options=None): if data is None or len(data) < 7: return cls() c1 = (data[1] << 16) | (data[2] << 8) | data[3] c2 = (data[4] << 16) | (data[5] << 8) | data[6] return cls(ID=data[0], color1=c1, color2=c2) def to_bytes(self, options=None): return bytes( [ self.ID & 0xFF, (self.color1 >> 16) & 0xFF, (self.color1 >> 8) & 0xFF, self.color1 & 0xFF, (self.color2 >> 16) & 0xFF, (self.color2 >> 8) & 0xFF, self.color2 & 0xFF, ] ) def __eq__(self, other): return isinstance(other, self.__class__) and self.to_bytes() == other.to_bytes() def __str__(self): return yaml.dump(self, width=float("inf")).rstrip("\n") @classmethod def from_yaml(cls, loader, node): return cls(**loader.construct_mapping(node)) @classmethod def to_yaml(cls, dumper, data): return dumper.represent_mapping("!RgbBootEffect", data.__dict__, flow_style=True) yaml.SafeLoader.add_constructor("!RgbBootEffect", _RgbBootEffect.from_yaml) yaml.add_representer(_RgbBootEffect, _RgbBootEffect.to_yaml) class _RgbBootEffectSetting(settings.Setting): """Base for NvConfig persistent effect toggles on RGBEffects (0x8071). Subclasses set cap_id (0x0001 startup, 0x0040 shutdown). Build probes the cap once and suppresses the setting if the device doesn't answer — so the setting auto-appears on any 0x8071 device that supports the cap, without needing per-model gating. """ feature = _F.RGB_EFFECTS cap_id: int = 0 _ENABLED_CHOICES = common.NamedInts(**{"On": 1, "Off": 2}) _COLOR1_FIELD = {"name": "color1", "kind": settings.Kind.COLOR, "label": _("Primary")} _COLOR2_FIELD = {"name": "color2", "kind": settings.Kind.COLOR, "label": _("Secondary")} class rw_class: kind = settings.FeatureRW.kind def __init__(self, feature, cap_id): self.feature = feature self.cap_id = cap_id self._cap_bytes = bytes([(cap_id >> 8) & 0xFF, cap_id & 0xFF]) def read(self, device): reply = device.feature_request(self.feature, 0x30, b"\x00" + self._cap_bytes) if reply is None or len(reply) < 10: return None return reply[3:10] # strip [sub-fn, capHi, capLo] echo def write(self, device, data_bytes): return device.feature_request(self.feature, 0x30, b"\x01" + self._cap_bytes + bytes(data_bytes)) @classmethod def build(cls, device): cap_bytes = bytes([(cls.cap_id >> 8) & 0xFF, cls.cap_id & 0xFF]) try: reply = device.feature_request(_F.RGB_EFFECTS, 0x30, b"\x00" + cap_bytes) except exceptions.FeatureCallError: return None # device rejects this cap — gate the setting off if reply is None or len(reply) < 10: return None # Register the firmware shutdown trigger on cap 0x0040 devices so the # animation plays on Solaar exit. This depends only on the device # having the cap (probe above), not on the UI control being shown — # so it runs before the allowlist gate below. rgb_power.cleanup fires # mode 0 at its end when _rgb_has_shutdown_cap is set. See # solaar_shutdown_effect_trigger_spec.md. if cls.cap_id == 0x0040: device._rgb_has_shutdown_cap = True if rgb_power.cleanup not in device.cleanups: device.cleanups.append(rgb_power.cleanup) # NVconfig-saved colors are default-DENY: the boot-effect setting is # shown only on models explicitly known-good. allowed is None on an # unlisted model/cap (suppress), or a (possibly empty) set of color # fields the firmware honors. SOLAAR_EXPERIMENTAL unmasks everything. allowed = device_quirks.rgb_effects_nvconfig_allowed_fields(device, cls.cap_id) if allowed is None: return None rw = cls.rw_class(cls.feature, cls.cap_id) validator = settings_validator.HeteroValidator(data_class=_RgbBootEffect, options=None) setting = cls(device, rw, validator) # Render the enabled byte as a right-aligned Gtk.Switch (like a plain # TOGGLE setting) rather than an inline Off/On combo. on_value/off_value # carry the wire-format byte (0x01 = on, 0x02 = off) through to the # data class without changing the byte semantics. id_field = {"name": "ID", "kind": settings.Kind.TOGGLE, "label": None, "on_value": 1, "off_value": 2} # Keep all color widgets in possible_fields so reads still populate # them and writes still carry their values — the firmware may store # bytes it doesn't visibly use. fields_map controls UI visibility. setting.possible_fields = [id_field, cls._COLOR1_FIELD, cls._COLOR2_FIELD] # An empty allowed set shows the On/Off toggle only (cap works, colors # don't); a non-empty set adds the listed color pickers. visible = {n: o for n, o in (("color1", 1), ("color2", 4)) if n in allowed} # Both On/Off map to the same visible field set so colors stay editable # when the effect is Off (pre-stages them for next enable). setting.fields_map = { int(cls._ENABLED_CHOICES["On"]): (cls._ENABLED_CHOICES["On"], visible), int(cls._ENABLED_CHOICES["Off"]): (cls._ENABLED_CHOICES["Off"], visible), } return setting class RgbStartupAnimation(_RgbBootEffectSetting): name = "rgb_startup_animation" label = _("Startup Animation") description = ( _( "Firmware-played animation when the keyboard wakes from deep sleep or powers on.\n" "Setting persists on the device (non-volatile)." ) + "\n" + _("Device default: Primary #FF0081, Secondary #80AAFF.") ) cap_id = 0x0001 class RgbShutdownAnimation(_RgbBootEffectSetting): name = "rgb_shutdown_animation" label = _("Shutdown Animation") description = ( _("Firmware-played animation when the keyboard powers off.\n" "Setting persists on the device (non-volatile).") + "\n" + _("Device default: Primary #FF0081, Secondary #80AAFF.") ) cap_id = 0x0040 class RGBEffectSetting(LEDZoneSetting): name = "rgb_zone_" # the trailing underscore signals that this setting creates other settings label = _("LED Zone Effects") description = _("Set effect for LED Zone") + "\n" + _("LED Control needs to be enabled.") feature = _F.RGB_EFFECTS # 0x8071 firmware-fixes ramp/form bytes; drop those widgets here. possible_fields = [ LEDZoneSetting.color_field, LEDZoneSetting.speed_field, LEDZoneSetting.period_field, LEDZoneSetting.intensity_field, LEDZoneSetting.saturation_field, LEDZoneSetting.direction_field, ] @classmethod def build(cls, device): return cls.setup(device, None, 0x10, b"\x01") def write(self, value, save=True): """Push zone effect to wire unless per-key is the dominant layer. Per-key acts as a multi-color sub-mode of Static: when zone is Static and per-key is opted in with paint, per-key owns the visible layer. Non-Static zone effects (animations) always go to the wire — per-key defers to the firmware animation. Transitions into Static still push the Static wire so any running animation stops. """ assert hasattr(self, "_value") assert hasattr(self, "_device") assert value is not None device = self._device if not device.online: return None perkey, has_paint = rgb_power.perkey_has_paint(device) new_is_static = int(getattr(value, "ID", 0) or 0) == rgb_power._EFFECT_STATIC old_value = self._value old_is_static = old_value is None or int(getattr(old_value, "ID", 0) or 0) == rgb_power._EFFECT_STATIC if has_paint and new_is_static and old_is_static: if save: changed = old_value != value self.update(value, save) if changed and perkey._fill_unset_zones_with_base_color(): perkey._send_with_retry(0x70, b"\x00") # FrameEnd # Resync the dim ramp's start colors for unset cells. mgr = rgb_power.get_manager(device) if mgr is not None: new_base = int(getattr(value, "color", 0) or 0) unset_zones = perkey._unset_zone_ids() if unset_zones: mgr.notify_perkey_bulk_changed({z: new_base for z in unset_zones}) return value # Persist undimmed value first (single source of truth). if self._value != value: self.update(value, save) # rgb_control gate: skip wire when the user has LED Control off. rgb_ctrl = next((s for s in device.settings if s.name == "rgb_control"), None) if rgb_ctrl is not None and not rgb_ctrl._value: return value wire_value = self._translate_for_wire(value) if wire_value is None: # SLEEPING — _wake() will re-push at full brightness. return value current_value = None if self._validator.needs_current_value: current_value = self._rw.read(device) data_bytes = self._validator.prepare_write(wire_value, current_value) if data_bytes is None: return None reply = self._rw.write(device, data_bytes) if not reply: return None # Animation → Static transition with per-key paint: the Static wire # we just pushed stops the animation; now repaint the per-key # multi-color overlay on top so the user gets a seamless switch. if has_paint and new_is_static and perkey is not None: try: perkey.write(perkey._value, save=False) except Exception as e: logger.warning("%s: per-key repaint after Static restore failed: %s", device, e) # Resync any in-flight dim ramp to the new color. mgr = rgb_power.get_manager(device) if mgr is not None and getattr(value, "color", None) is not None and self._rw.prefix: mgr.notify_zone_changed(self._rw.prefix[0], int(value.color)) return value def _translate_for_wire(self, value): """Clone `value` with `.color` translated through rgb_power state. Returns None for SLEEPING.""" saved_color = getattr(value, "color", None) if saved_color is None: return value wire_color = rgb_power.translate_for_device(self._device, int(saved_color)) if wire_color is None: return None if int(wire_color) == int(saved_color): return value # ACTIVE or no-op translation; reuse original # Build a shallow clone with translated color so the persister and the # in-memory _value keep the undimmed source-of-truth color. wire_attrs = dict(value.__dict__) wire_attrs["color"] = int(wire_color) return hidpp20.LEDEffectSetting(**wire_attrs) class PerKeyLighting(settings.Settings): name = "per-key-lighting" label = _("Per-key Lighting") description = ( _("Control per-key lighting.") + "\n" + _("LED Control needs to be enabled and the zone effect set to Static for per-key paint to be visible.") ) feature = _F.PER_KEY_LIGHTING_V2 keys_universe = special_keys.KEYCODES editor_class = "solaar.ui.perkey.control:PerKeyControl" # 0x8081 has no GetIndividualRgbZones — there's no way to ask the device # what colors are currently on the per-key buffer. read() returns the # canonical in-memory map for callers that need a value, but `solaar show` # honors this flag and skips its live-read line to avoid misleading output. live_readable = False @staticmethod def _wrap_color(value): # Wrap raw 24-bit-range ints in ColorInt so saved configs render as # ``0xrrggbb`` hex literals and `solaar show` prints hex. Sentinels # (NamedInt "No change" = -1) and existing ColorInt values pass # through untouched. # type(value) is int — exact match excludes NamedInt sentinels like # COLORSPLUS["No change"] = -1 and avoids re-wrapping ColorInts. if type(value) is int and 0 <= value <= 0xFFFFFF: # noqa: E721 return common.ColorInt(value) return value def update(self, value, save=True): if isinstance(value, dict): value = {k: self._wrap_color(v) for k, v in value.items()} super().update(value, save) def update_key_value(self, key, value, save=True): super().update_key_value(key, self._wrap_color(value), save) def _sw_control_held(self): """Return True if it's safe to push LED bytes to the wire. rgb_control is the gate: when the user has it off, LED writes must be silent no-ops at the wire. Never auto-flip it on from here — doing so rewrites the persister and turns the user-facing toggle into a lie.""" if getattr(self, "_has_rgb_effects", None) is None: self._has_rgb_effects = bool(self._device.features and _F.RGB_EFFECTS in self._device.features) if not self._has_rgb_effects: return True # No autonomous effect engine, no gate needed for s in self._device.settings: if s.name == "rgb_control": # _value may be bool (current) or int 3/0 (legacy persister value # before BooleanValidator migration); both coerce cleanly. return bool(s._value) return True # rgb_control not on this device → no gate to enforce # BUSY-retry backoff (ms). _BUSY_BACKOFF_MS = (30, 60, 90) def _send_with_retry(self, function, data, retries=3): # Retry on BUSY and timeout (both transient). Other FeatureCallError # codes abort — they're real bugs we shouldn't paper over. busy_attempt = 0 max_busy = len(self._BUSY_BACKOFF_MS) for attempt in range(retries + 1): try: reply = self._device.feature_request(self.feature, function, data) except exceptions.FeatureCallError as e: if getattr(e, "error", None) == hidpp20_constants.ErrorCode.BUSY and busy_attempt < max_busy: delay_ms = self._BUSY_BACKOFF_MS[busy_attempt] busy_attempt += 1 if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: per-key 0x%02x BUSY, retry %d/%d after %dms", self._device, function, busy_attempt, max_busy, delay_ms, ) sleep(delay_ms / 1000.0) continue logger.warning("%s: per-key 0x%02x rejected by device", self._device, function) return False if reply is not None: if (attempt > 0 or busy_attempt > 0) and logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: per-key 0x%02x succeeded after %d timeout retries, %d BUSY retries", self._device, function, attempt, busy_attempt, ) return True if logger.isEnabledFor(logging.DEBUG): logger.debug( "%s: per-key 0x%02x timed out (attempt %d/%d)", self._device, function, attempt + 1, retries + 1, ) return False def _zone_base_color(self): """Color used to fill per-key unset cells. Defers to rgb_power.effective_zone_base_color which returns black when the zone effect is ignored, otherwise the saved zone color.""" return rgb_power.effective_zone_base_color(self._device) def _send_zone_color(self, zone_id, wire_color): """Emit a single-zone color update (fn 0x10). `wire_color` is the already-translated color that should appear on the device.""" r = (wire_color >> 16) & 0xFF g = (wire_color >> 8) & 0xFF b = wire_color & 0xFF return self._send_with_retry(0x10, bytes([zone_id, r, g, b])) def _unset_zone_ids(self): """Per-key zone IDs that don't have a user-painted color.""" no_change = special_keys.COLORSPLUS["No change"] user_set = set() if self._value: for key, color in self._value.items(): if color != no_change and isinstance(color, int) and color >= 0: user_set.add(int(key)) return [int(k) for k in self._validator.choices if int(k) not in user_set] def _fill_unset_zones_with_base_color(self): """Push the zone base color (translated for current power state) to any per-key cell the user hasn't painted. Caller commits FrameEnd.""" if not self._has_rgb_effects: return True zone_base = self._zone_base_color() wire_base = rgb_power.translate_for_device(self._device, zone_base) if wire_base is None: return True # SLEEPING — caller defers wire entirely r = (wire_base >> 16) & 0xFF g = (wire_base >> 8) & 0xFF b = wire_base & 0xFF unset_zones = self._unset_zone_ids() if not unset_zones: return True remaining = list(unset_zones) ok = True while remaining: batch = remaining[:13] remaining = remaining[13:] if not self._send_with_retry(0x60, bytes([r, g, b]) + bytes(batch)): ok = False return ok def read(self, cached=True): # The 0x8081 protocol has no GetIndividualRgbZones — the device cannot # report its current per-key buffer back. So a "live" read is fictional: # we either return what we last wrote (the persisted/in-memory map, # which is the canonical truth for this setting) or, on a fresh device # with no persisted state, fabricate an all-"No change" sentinel map # as the starting point. Returning the cached value unconditionally # also fixes `solaar show` showing every key as "No change" on the # live line — it now matches what's actually on the keyboard. self._pre_read(cached) if self._value is not None: return self._value reply_map = {} for key in self._validator.choices: reply_map[int(key)] = special_keys.COLORSPLUS["No change"] # starting state, no per-key write yet self._value = reply_map return reply_map def _send_perkey_frame(self, map, no_change): """Send all per-key sub-packets for `map`, fill unset cells with the zone base color, and commit with FrameEnd. Returns True on success.""" # Bucket by color; single-bucket allows the range-update fast path. table = {} for key, value in map.items(): if value in table: table[value].append(key) else: table[value] = [key] ok = True if len(table) == 1: # use range update for value, keys in table.items(): # only one, of course if value != no_change: # this signals no change, so don't update at all wire = rgb_power.translate_for_device(self._device, int(value)) data_bytes = keys[0].to_bytes(1, "big") + keys[-1].to_bytes(1, "big") + wire.to_bytes(3, "big") if not self._send_with_retry(0x50, data_bytes): # range update command to update all keys ok = False else: data_bytes = b"" for value, keys in table.items(): if value != no_change: # this signals no change, so ignore it wire = rgb_power.translate_for_device(self._device, int(value)) while len(keys) > 3: # use an optimized update command that can update up to 13 keys data = wire.to_bytes(3, "big") + b"".join([key.to_bytes(1, "big") for key in keys[0:13]]) if not self._send_with_retry(0x60, data): # single-value multiple-keys update ok = False keys = keys[13:] for key in keys: data_bytes += key.to_bytes(1, "big") + wire.to_bytes(3, "big") if len(data_bytes) >= 16: # up to four values are packed into a regular update if not self._send_with_retry(0x10, data_bytes): ok = False data_bytes = b"" if len(data_bytes) > 0: # update any remaining keys if not self._send_with_retry(0x10, data_bytes): ok = False # Fill unset zones before FrameEnd so the frame commits atomically. if not self._fill_unset_zones_with_base_color(): ok = False # Suppress FrameEnd on partial failure to avoid a visibly wrong commit. if ok: if not self._send_with_retry(0x70, b"\x00"): logger.warning("%s: per-key FrameEnd failed; frame not committed", self._device) ok = False else: logger.warning( "%s: per-key frame had failed sub-packets; suppressing FrameEnd to avoid partial commit", self._device, ) return ok def write(self, map, save=True): if self._device.online: # Persist undimmed (single source of truth). self.update(map, save) if not self._sw_control_held(): return map # gate is off — keep state in memory, skip the wire # Per-key is a sub-mode of Static — when zone is animating, the # firmware engine owns the visible layer. if not rgb_power.zone_effect_is_static(self._device): return map no_change = special_keys.COLORSPLUS["No change"] # SLEEPING — defer wire to wake. for value in map.values(): if value != no_change and rgb_power.translate_for_device(self._device, int(value)) is None: return map # Mouse-only prep, one-shot per claim — keyboards don't need it. if ( getattr(self, "_has_rgb_effects", False) and not getattr(self, "_prep_pushed", False) and int(getattr(self._device, "kind", -1) or -1) == int(hidpp10_constants.DEVICE_KIND.mouse) ): if rgb_power.push_artanis_perkey_prep(self._device): self._prep_pushed = True ok = self._send_perkey_frame(map, no_change) # First frame after a claim sometimes lands before the firmware # has fully transitioned out of onboard mode — replay it once. if ok and not getattr(self, "_frame_settled", False): self._send_perkey_frame(map, no_change) self._frame_settled = True if ok: mgr = rgb_power.get_manager(self._device) if mgr is not None: mgr.notify_perkey_bulk_changed(map) return map def write_key_value(self, key, value, save=True): no_change = special_keys.COLORSPLUS["No change"] zone_id = int(key) if value != no_change: self.update_key_value(zone_id, value, save) if not self._device.online: return value if not self._sw_control_held(): return value # gate is off — state stored, no wire push # Per-key is a sub-mode of Static — defer to firmware animation. if not rgb_power.zone_effect_is_static(self._device): return value wire = rgb_power.translate_for_device(self._device, int(value)) if wire is None: return value # SLEEPING — wake re-pushes ok = True # Fill unset zones once so they don't show white-default. if not getattr(self, "_base_filled", False): if self._fill_unset_zones_with_base_color(): self._base_filled = True else: ok = False if ok and not self._send_zone_color(zone_id, wire): ok = False if ok: mgr = rgb_power.get_manager(self._device) if mgr is not None: mgr.notify_perkey_changed(zone_id, int(value)) if not self._send_with_retry(0x70, b"\x00"): logger.warning("%s: per-key FrameEnd failed; frame not committed", self._device) else: logger.warning("%s: per-key write failed; suppressing FrameEnd", self._device) return value else: # Un-set: store "No change", push the zone base color to that cell. self.update_key_value(zone_id, no_change, save) if not self._device.online: return no_change if not self._sw_control_held(): return no_change # gate is off — state stored, no wire push if not rgb_power.zone_effect_is_static(self._device): return no_change zone_base = self._zone_base_color() wire_base = rgb_power.translate_for_device(self._device, zone_base) if wire_base is None: return no_change if self._send_zone_color(zone_id, wire_base): mgr = rgb_power.get_manager(self._device) if mgr is not None: mgr.notify_perkey_changed(zone_id, zone_base) if not self._send_with_retry(0x70, b"\x00"): logger.warning("%s: per-key FrameEnd failed; frame not committed", self._device) else: logger.warning("%s: per-key un-set write failed; suppressing FrameEnd", self._device) return no_change class rw_class(settings.FeatureRWMap): pass class validator_class(settings_validator.MapRangeValidator): _COLOR_RANGE = settings_validator.Range(min=0, max=0xFFFFFF, byte_count=3, value_type=common.ColorInt) @classmethod def build(cls, setting_class, device): choices_map = {} key_bitmap = device.feature_request(setting_class.feature, 0x00, 0x00, 0x00)[2:] key_bitmap += device.feature_request(setting_class.feature, 0x00, 0x00, 0x01)[2:] key_bitmap += device.feature_request(setting_class.feature, 0x00, 0x00, 0x02)[2:] for i in range(1, 255): if (key_bitmap[i // 8] >> i % 8) & 0x01: key = ( setting_class.keys_universe[i] if i in setting_class.keys_universe else common.NamedInt(i, f"KEY {str(i)}") ) choices_map[key] = cls._COLOR_RANGE return cls(choices_map) if choices_map else None # Allow changes to force sensing buttons class ForceSensing(settings_new.Settings): name = "force-sensing" label = _("Force Sensing Buttons") description = _("Change the force required to activate button.") feature = _F.FORCE_SENSING_BUTTON setup = "force_buttons" get = "get_current" set = "set_current" acceptable = "acceptable_current_key" choices_universe = list(range(0, 256)) kind = settings.Kind.MAP_RANGE @classmethod def build(cls, device): cls.check_properties(cls) device_object = getattr(device, cls.setup)() if device_object: setting = cls(device, device_object) if setting and len(device_object) == 1: ## If there is only one force button a simpler interface can be used setting.label = _("Force Sensing Button") setting.acceptable = "acceptable_current" setting.min_value = device_object[0].min_value setting.max_value = device_object[0].max_value setting.kind = settings.Kind.RANGE return setting # Analog button tuning settings (actuation point, rapid trigger, haptics) # # Bytes 1 (actuation), 2 (rapid trigger), 3 (haptics) of the 0x1B0C config struct # pack a logical value in bits 7..2 (i.e. wire = logical << 2). Byte 2 bit 0 is a # firmware-managed sensitivityFlag that must be preserved across writes; all other # low-order bits are reserved and must be zero. Sending a wire byte that doesn't # match this layout produces INVALID_ARGUMENT — see issue #3202. class _AnalogButtonActuationRW(settings.FeatureRW): """RW for analog button actuation point per button.""" def __init__(self, feature, button_index): super().__init__(feature, read_fnid=0x20, write_fnid=0x10) self.button_index = button_index def read(self, device, data_bytes=b""): res = device.feature_request(self.feature, 0x20, self.button_index) if not res: return b"\x05" # default mid-point (logical) return bytes([res[1] >> 2]) def write(self, device, data_bytes): current = device.feature_request(self.feature, 0x20, self.button_index) if not current: return None wire_act = (data_bytes[0] & 0x3F) << 2 return device.feature_request(self.feature, 0x10, self.button_index, wire_act, current[2], current[3]) class _AnalogButtonRapidTriggerRW(settings.FeatureRW): """RW for analog button rapid trigger sensitivity per button.""" def __init__(self, feature, button_index): super().__init__(feature, read_fnid=0x20, write_fnid=0x10) self.button_index = button_index def read(self, device, data_bytes=b""): res = device.feature_request(self.feature, 0x20, self.button_index) if not res: return b"\x03" # default mid-point (logical) return bytes([res[2] >> 2]) def write(self, device, data_bytes): current = device.feature_request(self.feature, 0x20, self.button_index) if not current: return None # Preserve the firmware-managed sensitivityFlag (byte 2 bit 0). wire_rt = ((data_bytes[0] & 0x3F) << 2) | (current[2] & 0x01) return device.feature_request(self.feature, 0x10, self.button_index, current[1], wire_rt, current[3]) class _AnalogButtonHapticsRW(settings.FeatureRW): """RW for analog button click haptics per button.""" def __init__(self, feature, button_index): super().__init__(feature, read_fnid=0x20, write_fnid=0x10) self.button_index = button_index def read(self, device, data_bytes=b""): res = device.feature_request(self.feature, 0x20, self.button_index) if not res: return b"\x03" # default mid-point (logical) return bytes([res[3] >> 2]) def write(self, device, data_bytes): current = device.feature_request(self.feature, 0x20, self.button_index) if not current: return None wire_haptics = (data_bytes[0] & 0x3F) << 2 return device.feature_request(self.feature, 0x10, self.button_index, current[1], current[2], wire_haptics) class _AnalogButtonSetting(settings.Setting): """Setting subclass that migrates legacy raw-byte persisted values. Solaar 1.1.19 stored the wire byte (logical value × 4) under these names. After the encoding fix, the same key holds the logical value. If a stored value is above the new max but a divide-by-4 lands inside the valid range, treat it as legacy raw and migrate in place — this prevents apply() from raising INVALID_ARGUMENT/ValueError on first run after upgrade. """ def _pre_read(self, cached, key=None): super()._pre_read(cached, key) if self._value is None or not isinstance(self._value, int): return validator = self._validator if self._value > validator.max_value and (self._value & 0x03) == 0: migrated = self._value >> 2 if validator.min_value <= migrated <= validator.max_value: if logger.isEnabledFor(logging.INFO): logger.info( "%s: migrating legacy raw value %d to logical %d on %s", self.name, self._value, migrated, self._device, ) self._value = migrated if getattr(self._device, "persister", None) is not None: self._device.persister[self.name] = self._value class AnalogButtonTuning(settings.Setting): """Analog button tuning: actuation point, rapid trigger, and haptics configuration.""" name = "analog-button-tuning" label = _("Analog Button Tuning") description = _("Configure analog button settings including actuation point, rapid trigger, and haptics.") feature = _F.ANALOG_BUTTONS @classmethod def build(cls, device): if cls.feature not in device.features: return None # Capabilities: [flags, button_count, max_act<<2, max_rt<<2, max_haptics<<2, ...] caps = device.feature_request(cls.feature, 0x00) if not caps or len(caps) < 5: return None button_count = min(caps[1], 2) # firmware reports 3; only L/R are user-accessible max_actuation = (caps[2] >> 2) if caps[2] > 0 else 10 max_rt_level = (caps[3] >> 2) if caps[3] > 0 else 5 max_haptics = (caps[4] >> 2) if caps[4] > 0 else 5 if button_count == 0: return None button_names = [_("Left Button"), _("Right Button")] all_settings = [] for i in range(button_count): btn_name = button_names[i] if i < len(button_names) else f"Button {i}" rw_act = _AnalogButtonActuationRW(cls.feature, i) val_act = settings_validator.RangeValidator(min_value=1, max_value=max_actuation) s_act = _AnalogButtonSetting(device, rw_act, val_act) s_act.name = f"analog-button-tuning_actuation-{i}" s_act.label = f"{btn_name} Actuation Point" s_act.description = _("Actuation point depth (1=shallow, %d=deep).") % max_actuation all_settings.append(s_act) rw_rt = _AnalogButtonRapidTriggerRW(cls.feature, i) val_rt = settings_validator.RangeValidator(min_value=1, max_value=max_rt_level) s_rt = _AnalogButtonSetting(device, rw_rt, val_rt) s_rt.name = f"analog-button-tuning_rapid-trigger-{i}" s_rt.label = f"{btn_name} Rapid Trigger" s_rt.description = _("Rapid trigger sensitivity (1..%d).") % max_rt_level all_settings.append(s_rt) rw_haptics = _AnalogButtonHapticsRW(cls.feature, i) val_haptics = settings_validator.RangeValidator(min_value=0, max_value=max_haptics) s_haptics = _AnalogButtonSetting(device, rw_haptics, val_haptics) s_haptics.name = f"analog-button-tuning_haptics-{i}" s_haptics.label = f"{btn_name} Click Haptics" s_haptics.description = _("Click haptic feedback intensity (0=off, %d=max).") % max_haptics all_settings.append(s_haptics) return all_settings if all_settings else None class HapticLevel(settings.Setting): name = "haptic-level" label = _("Haptic Feedback Level") description = _("Change power of haptic feedback. (Zero to turn off.)") feature = _F.HAPTIC choices_universe = common.NamedInts(Off=0, Low=25, Medium=50, High=75, Maximum=100) min_value = 0 max_value = 100 class rw_class(settings.FeatureRW): def __init__(self, feature): super().__init__(feature, read_fnid=0x10, write_fnid=0x20) def read(self, device, data_bytes=b""): result = device.feature_request(self.feature, 0x10) if result[0] & 0x01 == 0: # disabled, return 0 return b"\x00" else: # enabled, return second byte return result[1:2] def write(self, device, data_bytes): if data_bytes == b"\x00": write_bytes = b"\x00\x32" # disable, at 50 percent else: write_bytes = b"\x01" + data_bytes reply = device.feature_request(self.feature, 0x20, write_bytes) return reply @classmethod def build(cls, device): response = device.feature_request(cls.feature, 0x10) if response: rw = cls.rw_class(cls.feature) levels = response[2] & 0x01 if levels: # device only has four levels validator = settings_validator.ChoicesValidator(choices=cls.choices_universe) else: # device has all levels validator = settings_validator.RangeValidator(min_value=cls.min_value, max_value=cls.max_value) return cls(device, rw, validator) # This setting is not displayed in the UI # Use `solaar config haptic-play

` to play a haptic form class PlayHapticWaveForm(settings.Setting): name = "haptic-play" label = _("Play Haptic Waveform") description = _("Tell device to play a haptic waveform.") feature = _F.HAPTIC choices_universe = hidpp20_constants.HapticWaveForms rw_options = {"read_fnid": None, "write_fnid": 0x40} # nothing to read persist = False # persisting this setting is useless display = False # don't display in UI, interact using `solaar config ...` class validator_class(settings_validator.ChoicesValidator): @classmethod def build(cls, setting_class, device): response = device.feature_request(_F.HAPTIC, 0x00) if response: waves = common.NamedInts() waveforms = int.from_bytes(response[4:8]) for waveform in hidpp20_constants.HapticWaveForms: if (1 << int(waveform)) & waveforms: waves[int(waveform)] = str(waveform) return cls(choices=waves, byte_count=1) SETTINGS: list[settings.Setting] = [ RegisterHandDetection, # simple RegisterSmoothScroll, # simple RegisterSideScroll, # simple RegisterDpi, RegisterFnSwap, # working HiResScroll, # simple LowresMode, # simple HiresSmoothInvert, # working HiresSmoothResolution, # working HiresMode, # simple ScrollRatchet, # simple ScrollRatchetTorque, SmartShift, # working ScrollRatchetEnhanced, SmartShiftEnhanced, # simple ThumbInvert, # working ThumbMode, # working OnboardProfiles, ReportRate, # working ExtendedReportRate, PointerSpeed, # simple AdjustableDpi, # working ExtendedAdjustableDpi, SpeedChange, # Backlight, # not working - disabled temporarily Backlight2, # working Backlight2Level, Backlight2DurationHandsOut, Backlight2DurationHandsIn, Backlight2DurationPowered, Backlight3, LEDControl, LEDZoneSetting, RGBControl, RGBEffectSetting, PerKeyLighting, BrightnessControl, RGBIdleEffect, RGBIdleTimeout, RGBSleepTimeout, RgbStartupAnimation, RgbShutdownAnimation, FnSwap, # simple NewFnSwap, # simple K375sFnSwap, # working ReprogrammableKeys, # working PersistentRemappableAction, DivertKeys, # working DisableKeyboardKeys, # working ForceSensing, CrownSmooth, # working DivertCrown, # working DivertGkeys, # working MKeyLEDs, # working MRKeyLED, # working Multiplatform, # working DualPlatform, # simple ChangeHost, # working Gesture2Gestures, # working Gesture2Divert, Gesture2Params, # working AnalogButtonTuning, HapticLevel, PlayHapticWaveForm, Sidetone, Equalizer, ADCPower, HeadsetEcoMode, HeadsetDoNotDisturb, HeadsetMicMute, HeadsetMicSNR, HeadsetAINR, HeadsetAINRLevel, HeadsetSidetone, HeadsetMicGain, HeadsetMixBalance, HeadsetAutoSleep, HeadsetOnboardEQ, HeadsetActiveEQPreset, HeadsetAdvancedEQ, HeadsetLEDControl, HeadsetOnboardEffect, HeadsetPerZoneLighting, HeadsetSignatureStartupEffect, HeadsetSignatureShutdownEffect, HeadsetSignaturePassiveEffect, *_LOGIVOICE_SETTINGS, ] class SettingsProtocol(Protocol): @property def name(self): ... @property def label(self): ... @property def description(self): ... @property def feature(self): ... @property def register(self): ... @property def kind(self): ... @property def min_version(self): ... @property def persist(self): ... @property def rw_options(self): ... @property def validator_class(self): ... @property def validator_options(self): ... @classmethod def build(cls, device): ... def val_to_string(self, value): ... @property def choices(self): ... @property def range(self): ... def _pre_read(self, cached, key=None): ... def read(self, cached=True): ... def _pre_write(self, save=True): ... def update(self, value, save=True): ... def write(self, value, save=True): ... def acceptable(self, args, current): ... def compare(self, args, current): ... def apply(self): ... def __str__(self): ... def check_feature(device, settings_class: SettingsProtocol) -> None | bool | SettingsProtocol: if settings_class.feature not in device.features: return if settings_class.min_version > device.features.get_feature_version(settings_class.feature): logger.debug( "check_feature %s [%s]: min_version=%d > device feature version=%d; skipping", settings_class.name, settings_class.feature, settings_class.min_version, device.features.get_feature_version(settings_class.feature) or 0, ) return if device.features.get_hidden(settings_class.feature): flags = device.features.flags.get(settings_class.feature, 0) logger.debug( "check_feature %s [%s]: feature has INTERNAL flag set (flags=0x%02X); skipping", settings_class.name, settings_class.feature, flags, ) return try: detected = settings_class.build(device) if logger.isEnabledFor(logging.DEBUG): logger.debug("check_feature %s [%s] detected", settings_class.name, settings_class.feature) return detected except Exception as e: logger.error( "check_feature %s [%s] error %s\n%s", settings_class.name, settings_class.feature, e, traceback.format_exc() ) raise e # differentiate from an error-free determination that the setting is not supported def check_feature_settings(device, already_known) -> bool: """Auto-detect device settings by the HID++ 2.0 features they have. Returns ------- bool True, if device was fully queried to find features, False otherwise. """ if not device.features or not device.online: return False if device.protocol and device.protocol < 2.0: return False absent = device.persister.get("_absent", []) if device.persister else [] new_absent = [] for sclass in SETTINGS: if sclass.feature: if device.persister: if sclass.name.endswith("_"): # Multi-setting prototype (e.g. rgb_zone_); persister stores child keys # like rgb_zone_1, never the prototype name itself. known_present = any(k.startswith(sclass.name) for k in device.persister) else: known_present = sclass.name in device.persister else: known_present = False already = any(s.name == sclass.name for s in already_known) if already: continue if not known_present and sclass.name in absent: # Silent-skip cache from an earlier run's failed build(). If the # feature is actually present on this device now, the cache is # stale (e.g. from a prior build that returned None for a # feature that currently works) — drop it and retry the probe. if sclass.feature in device.features: logger.debug( "check_feature_settings: retrying %s — cached in _absent but feature %s is present now", sclass.name, sclass.feature, ) absent.remove(sclass.name) if device.persister: device.persister["_absent"] = absent else: continue try: setting = check_feature(device, sclass) except Exception as err: # on an internal HID++ error, assume offline and stop further checking if isinstance(err, exceptions.FeatureCallError) and err.error == hidpp20_constants.ErrorCode.LOGITECH_ERROR: logger.warning(f"HID++ internal error checking feature {sclass.name}: make device not present") device.online = False device.present = False return False else: logger.warning(f"ignore feature {sclass.name} because of error {err}") if isinstance(setting, list): for s in setting: already_known.append(s) if sclass.name in new_absent: new_absent.remove(sclass.name) elif setting: already_known.append(setting) if sclass.name in new_absent: new_absent.remove(sclass.name) elif setting is None: if sclass.name not in new_absent and sclass.name not in absent and sclass.name not in device.persister: new_absent.append(sclass.name) if device.persister and new_absent: absent.extend(new_absent) device.persister["_absent"] = absent return True def check_feature_setting(device, setting_name: str) -> settings.Setting | None: for sclass in SETTINGS: if ( sclass.feature and device.features and (sclass.name == setting_name or sclass.name.endswith("_") and setting_name.startswith(sclass.name)) ): try: setting = check_feature(device, sclass) except Exception: return None if isinstance(setting, list): for s in setting: if s.name == setting_name: return s elif setting: return setting Solaar-1.1.20/lib/logitech_receiver/settings_validator.py000066400000000000000000001021751522022367600235360ustar00rootroot00000000000000from __future__ import annotations import logging import math from dataclasses import dataclass from enum import IntEnum from logitech_receiver import common from logitech_receiver.common import NamedInt from logitech_receiver.common import NamedInts logger = logging.getLogger(__name__) def bool_or_toggle(current: bool | str, new: bool | str) -> bool: if isinstance(new, bool): return new try: return bool(int(new)) except (TypeError, ValueError): new = str(new).lower() if new in ("true", "yes", "on", "t", "y"): return True if new in ("false", "no", "off", "f", "n"): return False if new in ("~", "toggle"): return not current return None class Kind(IntEnum): TOGGLE = 0x01 CHOICE = 0x02 RANGE = 0x04 MAP_CHOICE = 0x0A MULTIPLE_TOGGLE = 0x10 PACKED_RANGE = 0x20 MULTIPLE_RANGE = 0x40 HETERO = 0x80 class Validator: @classmethod def build(cls, setting_class, device, **kwargs) -> Validator: return cls(**kwargs) @classmethod def to_string(cls, value) -> str: return str(value) def compare(self, args, current): if len(args) != 1: return False return args[0] == current class BooleanValidator(Validator): __slots__ = ("true_value", "false_value", "read_skip_byte_count", "write_prefix_bytes", "mask", "needs_current_value") kind = Kind.TOGGLE default_true = 0x01 default_false = 0x00 # mask specifies all the affected bits in the value default_mask = 0xFF def __init__( self, true_value=default_true, false_value=default_false, mask=default_mask, read_skip_byte_count=0, write_prefix_bytes=b"", ): if isinstance(true_value, int): assert isinstance(false_value, int) if mask is None: mask = self.default_mask else: assert isinstance(mask, int) assert true_value & false_value == 0 assert true_value & mask == true_value assert false_value & mask == false_value self.needs_current_value = mask != self.default_mask elif isinstance(true_value, bytes): if false_value is None or false_value == self.default_false: false_value = b"\x00" * len(true_value) else: assert isinstance(false_value, bytes) if mask is None or mask == self.default_mask: mask = b"\xff" * len(true_value) else: assert isinstance(mask, bytes) assert len(mask) == len(true_value) == len(false_value) tv = common.bytes2int(true_value) fv = common.bytes2int(false_value) mv = common.bytes2int(mask) assert tv != fv # true and false might be something other than bit values assert tv & mv == tv assert fv & mv == fv self.needs_current_value = any(m != 0xFF for m in mask) else: raise Exception(f"invalid mask '{mask!r}', type {type(mask)}") self.true_value = true_value self.false_value = false_value self.mask = mask self.read_skip_byte_count = read_skip_byte_count self.write_prefix_bytes = write_prefix_bytes def validate_read(self, reply_bytes): reply_bytes = reply_bytes[self.read_skip_byte_count :] if isinstance(self.mask, int): reply_value = ord(reply_bytes[:1]) & self.mask if logger.isEnabledFor(logging.DEBUG): logger.debug("BooleanValidator: validate read %r => %02X", reply_bytes, reply_value) if reply_value == self.true_value: return True if reply_value == self.false_value: return False logger.warning( "BooleanValidator: reply %02X mismatched %02X/%02X/%02X", reply_value, self.true_value, self.false_value, self.mask, ) return False count = len(self.mask) mask = common.bytes2int(self.mask) reply_value = common.bytes2int(reply_bytes[:count]) & mask true_value = common.bytes2int(self.true_value) if reply_value == true_value: return True false_value = common.bytes2int(self.false_value) if reply_value == false_value: return False logger.warning( "BooleanValidator: reply %r mismatched %r/%r/%r", reply_bytes, self.true_value, self.false_value, self.mask ) return False def prepare_write(self, new_value, current_value=None): if new_value is None: new_value = False else: assert isinstance(new_value, bool), f"New value {new_value} for boolean setting is not a boolean" to_write = self.true_value if new_value else self.false_value if isinstance(self.mask, int): if current_value is not None and self.needs_current_value: to_write |= ord(current_value[:1]) & (0xFF ^ self.mask) if current_value is not None and to_write == ord(current_value[:1]): return None to_write = bytes([to_write]) else: to_write = bytearray(to_write) count = len(self.mask) for i in range(0, count): b = ord(to_write[i : i + 1]) m = ord(self.mask[i : i + 1]) assert b & m == b # b &= m if current_value is not None and self.needs_current_value: b |= ord(current_value[i : i + 1]) & (0xFF ^ m) to_write[i] = b to_write = bytes(to_write) if current_value is not None and to_write == current_value[: len(to_write)]: return None if logger.isEnabledFor(logging.DEBUG): logger.debug("BooleanValidator: prepare_write(%s, %s) => %r", new_value, current_value, to_write) return self.write_prefix_bytes + to_write def acceptable(self, args, current): if len(args) != 1: return None val = bool_or_toggle(current, args[0]) return [val] if val is not None else None class BitFieldValidator(Validator): __slots__ = ("byte_count", "options") kind = Kind.MULTIPLE_TOGGLE def __init__(self, options, byte_count=None): assert isinstance(options, list) self.options = options self.byte_count = (max(x.bit_length() for x in options) + 7) // 8 if byte_count: assert isinstance(byte_count, int) and byte_count >= self.byte_count self.byte_count = byte_count def to_string(self, value) -> str: def element_to_string(key, val): k = next((k for k in self.options if int(key) == k), None) return str(k) + ":" + str(val) if k is not None else "?" return "{" + ", ".join([element_to_string(k, value[k]) for k in value]) + "}" def validate_read(self, reply_bytes): r = common.bytes2int(reply_bytes[: self.byte_count]) value = {int(k): False for k in self.options} m = 1 for _ignore in range(8 * self.byte_count): if m in self.options: value[int(m)] = bool(r & m) m <<= 1 return value def prepare_write(self, new_value): assert isinstance(new_value, dict) w = 0 for k, v in new_value.items(): if v: w |= int(k) return common.int2bytes(w, self.byte_count) def get_options(self): return self.options def acceptable(self, args, current): if len(args) != 2: return None key = next((key for key in self.options if key == args[0]), None) if key is None: return None val = bool_or_toggle(current[int(key)], args[1]) return None if val is None else [int(key), val] def compare(self, args, current): if len(args) != 2: return False key = next((key for key in self.options if key == args[0]), None) if key is None: return False return args[1] == current[int(key)] class BitFieldWithOffsetAndMaskValidator(Validator): __slots__ = ("byte_count", "options", "_option_from_key", "_mask_from_offset", "_option_from_offset_mask") kind = Kind.MULTIPLE_TOGGLE sep = 0x01 def __init__(self, options, om_method=None, byte_count=None): assert isinstance(options, list) # each element of options is an instance of a class # that has an id (which is used as an index in other dictionaries) # and where om_method is a method that returns a byte offset and byte mask # that says how to access and modify the bit toggle for the option self.options = options self.om_method = om_method # to retrieve the options efficiently: self._option_from_key = {} self._mask_from_offset = {} self._option_from_offset_mask = {} for opt in options: offset, mask = om_method(opt) self._option_from_key[int(opt)] = opt try: self._mask_from_offset[offset] |= mask except KeyError: self._mask_from_offset[offset] = mask try: mask_to_opt = self._option_from_offset_mask[offset] except KeyError: mask_to_opt = {} self._option_from_offset_mask[offset] = mask_to_opt mask_to_opt[mask] = opt self.byte_count = (max(om_method(x)[1].bit_length() for x in options) + 7) // 8 # is this correct?? if byte_count: assert isinstance(byte_count, int) and byte_count >= self.byte_count self.byte_count = byte_count def prepare_read(self): r = [] for offset, mask in self._mask_from_offset.items(): b = offset << (8 * (self.byte_count + 1)) b |= (self.sep << (8 * self.byte_count)) | mask r.append(common.int2bytes(b, self.byte_count + 2)) return r def prepare_read_key(self, key): option = self._option_from_key.get(key, None) if option is None: return None offset, mask = option.om_method(option) b = offset << (8 * (self.byte_count + 1)) b |= (self.sep << (8 * self.byte_count)) | mask return common.int2bytes(b, self.byte_count + 2) def validate_read(self, reply_bytes_dict): values = {int(k): False for k in self.options} for query, b in reply_bytes_dict.items(): offset = common.bytes2int(query[0:1]) b += (self.byte_count - len(b)) * b"\x00" value = common.bytes2int(b[: self.byte_count]) mask_to_opt = self._option_from_offset_mask.get(offset, {}) m = 1 for _ignore in range(8 * self.byte_count): if m in mask_to_opt: values[int(mask_to_opt[m])] = bool(value & m) m <<= 1 return values def prepare_write(self, new_value): assert isinstance(new_value, dict) w = {} for k, v in new_value.items(): option = self._option_from_key[int(k)] offset, mask = self.om_method(option) if offset not in w: w[offset] = 0 if v: w[offset] |= mask return [ common.int2bytes( (offset << (8 * (2 * self.byte_count + 1))) | (self.sep << (16 * self.byte_count)) | (self._mask_from_offset[offset] << (8 * self.byte_count)) | value, 2 * self.byte_count + 2, ) for offset, value in w.items() ] def get_options(self): return [int(opt) if isinstance(opt, int) else opt.as_int() for opt in self.options] def acceptable(self, args, current): if len(args) != 2: return None key = next((option.id for option in self.options if option.as_int() == args[0]), None) if key is None: return None val = bool_or_toggle(current[int(key)], args[1]) return None if val is None else [int(key), val] def compare(self, args, current): if len(args) != 2: return False key = next((option.id for option in self.options if option.as_int() == args[0]), None) if key is None: return False return args[1] == current[int(key)] class ChoicesValidator(Validator): """Translates between NamedInts and a byte sequence. :param choices: a list of NamedInts :param byte_count: the size of the derived byte sequence. If None, it will be calculated from the choices.""" kind = Kind.CHOICE def __init__(self, choices=None, byte_count=None, read_skip_byte_count=0, write_prefix_bytes=b""): assert choices is not None assert isinstance(choices, NamedInts) assert len(choices) > 1 self.choices = choices self.needs_current_value = False max_bits = max(x.bit_length() for x in choices) self._byte_count = (max_bits // 8) + (1 if max_bits % 8 else 0) if byte_count: assert self._byte_count <= byte_count self._byte_count = byte_count assert self._byte_count < 8 self._read_skip_byte_count = read_skip_byte_count self._write_prefix_bytes = write_prefix_bytes if write_prefix_bytes else b"" assert self._byte_count + self._read_skip_byte_count <= 14 assert self._byte_count + len(self._write_prefix_bytes) <= 14 def to_string(self, value) -> str: return str(self.choices[value]) if isinstance(value, int) else str(value) def validate_read(self, reply_bytes): reply_value = common.bytes2int(reply_bytes[self._read_skip_byte_count : self._read_skip_byte_count + self._byte_count]) valid_value = self.choices[reply_value] assert valid_value is not None, f"{self.__class__.__name__}: failed to validate read value {reply_value:02X}" return valid_value def prepare_write(self, new_value, current_value=None): if new_value is None: value = self.choices[:][0] else: value = self.choice(new_value) if value is None: raise ValueError(f"invalid choice {new_value!r}") assert isinstance(value, NamedInt) return self._write_prefix_bytes + value.bytes(self._byte_count) def choice(self, value): if isinstance(value, int): return self.choices[value] try: int(value) if int(value) in self.choices: return self.choices[int(value)] except Exception: pass if value in self.choices: return self.choices[value] else: return None def acceptable(self, args, current): choice = self.choice(args[0]) if len(args) == 1 else None return None if choice is None else [choice] class ChoicesMapValidator(ChoicesValidator): kind = Kind.MAP_CHOICE def __init__( self, choices_map, key_byte_count=0, key_postfix_bytes=b"", byte_count=0, read_skip_byte_count=0, write_prefix_bytes=b"", extra_default=None, mask=-1, activate=0, ): assert choices_map is not None assert isinstance(choices_map, dict) max_key_bits = 0 max_value_bits = 0 for key, choices in choices_map.items(): assert isinstance(key, NamedInt) assert isinstance(choices, NamedInts) max_key_bits = max(max_key_bits, key.bit_length()) for key_value in choices: assert isinstance(key_value, NamedInt) max_value_bits = max(max_value_bits, key_value.bit_length()) self._key_byte_count = (max_key_bits + 7) // 8 if key_byte_count: assert self._key_byte_count <= key_byte_count self._key_byte_count = key_byte_count self._byte_count = (max_value_bits + 7) // 8 if byte_count: assert self._byte_count <= byte_count self._byte_count = byte_count self.choices = choices_map self.needs_current_value = False self.extra_default = extra_default self._key_postfix_bytes = key_postfix_bytes self._read_skip_byte_count = read_skip_byte_count if read_skip_byte_count else 0 self._write_prefix_bytes = write_prefix_bytes if write_prefix_bytes else b"" self.activate = activate self.mask = mask assert self._byte_count + self._read_skip_byte_count + self._key_byte_count <= 14 assert self._byte_count + len(self._write_prefix_bytes) + self._key_byte_count <= 14 def to_string(self, value) -> str: def element_to_string(key, val): k, c = next(((k, c) for k, c in self.choices.items() if int(key) == k), (None, None)) return str(k) + ":" + str(c[val]) if k is not None else "?" return "{" + ", ".join([element_to_string(k, value[k]) for k in sorted(value)]) + "}" def validate_read(self, reply_bytes, key): start = self._key_byte_count + self._read_skip_byte_count end = start + self._byte_count reply_value = common.bytes2int(reply_bytes[start:end]) & self.mask # reprogrammable keys starts out as 0, which is not a choice, so don't use assert here if self.extra_default is not None and self.extra_default == reply_value: return int(self.choices[key][0]) if reply_value not in self.choices[key]: assert reply_value in self.choices[key], "%s: failed to validate read value %02X" % ( self.__class__.__name__, reply_value, ) return reply_value def prepare_key(self, key): return key.to_bytes(self._key_byte_count, "big") + self._key_postfix_bytes def prepare_write(self, key, new_value): choices = self.choices.get(key) if choices is None or (new_value not in choices and new_value != self.extra_default): logger.error("invalid choice %r for %s", new_value, key) return None new_value = new_value | self.activate return self._write_prefix_bytes + new_value.to_bytes(self._byte_count, "big") def acceptable(self, args, current): if len(args) != 2: return None key, choices = next(((key, item) for key, item in self.choices.items() if key == args[0]), (None, None)) if choices is None or args[1] not in choices: return None choice = next((item for item in choices if item == args[1]), None) return [int(key), int(choice)] if choice is not None else None def compare(self, args, current): if len(args) != 2: return False key = next((key for key in self.choices if key == int(args[0])), None) if key is None: return False return args[1] == current[int(key)] class RangeValidator(Validator): kind = Kind.RANGE """Translates between integers and a byte sequence. :param min_value: minimum accepted value (inclusive) :param max_value: maximum accepted value (inclusive) :param byte_count: the size of the derived byte sequence. If None, it will be calculated from the range.""" min_value = 0 max_value = 255 @classmethod def build(cls, setting_class, device, **kwargs): kwargs["min_value"] = setting_class.min_value kwargs["max_value"] = setting_class.max_value return cls(**kwargs) def __init__(self, min_value=0, max_value=255, byte_count=1, read_skip_byte_count=0, write_prefix_bytes=b"", signed=False): assert max_value > min_value self.min_value = min_value self.max_value = max_value self.read_skip_byte_count = read_skip_byte_count self.write_prefix_bytes = write_prefix_bytes self._signed = signed self.needs_current_value = True # read and check before write (needed for ADC power and probably a good idea anyway) self._byte_count = math.ceil(math.log(max_value + 1, 256)) if byte_count: assert self._byte_count <= byte_count self._byte_count = byte_count assert self._byte_count < 8 def validate_read(self, reply_bytes): reply_value = common.bytes2int( reply_bytes[self.read_skip_byte_count : self.read_skip_byte_count + self._byte_count], signed=self._signed ) assert reply_value >= self.min_value, f"{self.__class__.__name__}: failed to validate read value {reply_value:02X}" assert reply_value <= self.max_value, f"{self.__class__.__name__}: failed to validate read value {reply_value:02X}" return reply_value def prepare_write(self, new_value, current_value=None): if new_value < self.min_value or new_value > self.max_value: raise ValueError(f"invalid choice {new_value!r}") current_value = self.validate_read(current_value) if current_value is not None else None to_write = self.write_prefix_bytes + common.int2bytes(new_value, self._byte_count, signed=self._signed) # current value is known and same as value to be written return None to signal not to write it return None if current_value is not None and current_value == new_value else to_write def acceptable(self, args, current): arg = args[0] # None if len(args) != 1 or type(arg) != int or arg < self.min_value or arg > self.max_value else args) return None if len(args) != 1 or not isinstance(arg, int) or arg < self.min_value or arg > self.max_value else args def compare(self, args, current): if len(args) == 1: return args[0] == current elif len(args) == 2: return args[0] <= current <= args[1] else: return False class HeteroValidator(Validator): kind = Kind.HETERO @classmethod def build(cls, setting_class, device, **kwargs): return cls(**kwargs) def __init__(self, data_class=None, options=None, readable=True): # options=None for purely host-side settings — data_class handles bytes[0] as the ID. assert data_class is not None self.data_class = data_class self.options = options self.readable = readable self.needs_current_value = False def validate_read(self, reply_bytes): if self.readable: reply_value = self.data_class.from_bytes(reply_bytes, options=self.options) return reply_value def prepare_write(self, new_value, current_value=None): to_write = new_value.to_bytes(options=self.options) return to_write def acceptable(self, args, current): # should this actually do some checking? return True class PackedRangeValidator(Validator): kind = Kind.PACKED_RANGE """Several range values, all the same size, all the same min and max""" min_value = 0 max_value = 255 count = 1 rsbc = 0 write_prefix_bytes = b"" def __init__( self, keys, min_value=0, max_value=255, count=1, byte_count=1, read_skip_byte_count=0, write_prefix_bytes=b"" ): assert max_value > min_value self.needs_current_value = True self.keys = keys self.min_value = min_value self.max_value = max_value self.count = count self.bc = math.ceil(math.log(max_value + 1 - min(0, min_value), 256)) if byte_count: assert self.bc <= byte_count self.bc = byte_count assert self.bc * self.count self.rsbc = read_skip_byte_count self.write_prefix_bytes = write_prefix_bytes def validate_read(self, reply_bytes): rvs = { n: common.bytes2int(reply_bytes[self.rsbc + n * self.bc : self.rsbc + (n + 1) * self.bc], signed=True) for n in range(self.count) } for n in range(self.count): assert rvs[n] >= self.min_value, f"{self.__class__.__name__}: failed to validate read value {rvs[n]:02X}" assert rvs[n] <= self.max_value, f"{self.__class__.__name__}: failed to validate read value {rvs[n]:02X}" return rvs def prepare_write(self, new_values): if len(new_values) != self.count: raise ValueError(f"wrong number of values {new_values!r}") for new_value in new_values.values(): if new_value < self.min_value or new_value > self.max_value: raise ValueError(f"invalid value {new_value!r}") bytes = self.write_prefix_bytes + b"".join( common.int2bytes(new_values[n], self.bc, signed=True) for n in range(self.count) ) return bytes def acceptable(self, args, current): if len(args) != 2 or int(args[0]) < 0 or int(args[0]) >= self.count: return None return None if not isinstance(args[1], int) or args[1] < self.min_value or args[1] > self.max_value else args def compare(self, args, current): logger.warning("compare not implemented for packed range settings") return False class MultipleRangeValidator(Validator): kind = Kind.MULTIPLE_RANGE def __init__(self, items, sub_items): assert isinstance(items, list) # each element must have .index and its __int__ must return its id (not its index) assert isinstance(sub_items, dict) # sub_items: items -> class with .minimum, .maximum, .length (in bytes), .id (a string) and .widget (e.g. 'Scale') self.items = items self.keys = NamedInts(**{str(item): int(item) for item in items}) self._item_from_id = {int(k): k for k in items} self.sub_items = sub_items def prepare_read_item(self, item): return common.int2bytes((self._item_from_id[int(item)].index << 1) | 0xFF, 2) def validate_read_item(self, reply_bytes, item): item = self._item_from_id[int(item)] start = 0 value = {} for sub_item in self.sub_items[item]: r = reply_bytes[start : start + sub_item.length] if len(r) < sub_item.length: r += b"\x00" * (sub_item.length - len(value)) v = common.bytes2int(r) if not (sub_item.minimum < v < sub_item.maximum): logger.warning( f"{self.__class__.__name__}: failed to validate read value for {item}.{sub_item}: " + f"{v} not in [{sub_item.minimum}..{sub_item.maximum}]" ) value[str(sub_item)] = v start += sub_item.length return value def prepare_write(self, value): seq = [] w = b"" for item in value.keys(): _item = self._item_from_id[int(item)] b = common.int2bytes(_item.index, 1) for sub_item in self.sub_items[_item]: try: v = value[int(item)][str(sub_item)] except KeyError: return None if not (sub_item.minimum <= v <= sub_item.maximum): raise ValueError( f"invalid choice for {item}.{sub_item}: {v} not in [{sub_item.minimum}..{sub_item.maximum}]" ) b += common.int2bytes(v, sub_item.length) if len(w) + len(b) > 15: seq.append(b + b"\xff") w = b"" w += b seq.append(w + b"\xff") return seq def prepare_write_item(self, item, value): _item = self._item_from_id[int(item)] w = common.int2bytes(_item.index, 1) for sub_item in self.sub_items[_item]: try: v = value[str(sub_item)] except KeyError: return None if not (sub_item.minimum <= v <= sub_item.maximum): raise ValueError(f"invalid choice for {item}.{sub_item}: {v} not in [{sub_item.minimum}..{sub_item.maximum}]") w += common.int2bytes(v, sub_item.length) return w + b"\xff" def acceptable(self, args, current): # just one item, with at least one sub-item if not isinstance(args, list) or len(args) != 2 or not isinstance(args[1], dict): return None item = next((p for p in self.items if p.id == args[0] or str(p) == args[0]), None) if not item: return None for sub_key, value in args[1].items(): sub_item = next((it for it in self.sub_items[item] if it.id == sub_key), None) if not sub_item: return None if not isinstance(value, int) or not (sub_item.minimum <= value <= sub_item.maximum): return None return [int(item), {**args[1]}] def compare(self, args, current): logger.warning("compare not implemented for multiple range settings") return False @dataclass(frozen=True) class Range: """Inclusive integer range used as the value side of a MapRangeValidator. `byte_count` is the wire encoding width. `signed` selects two's-complement. `value_type` is the int factory used to wrap values returned from `validate_read` — defaults to `int`, but settings that store RGB colors pass `common.ColorInt` so the values self-format as ``0xrrggbb`` in `solaar show` output and the YAML config file. Settings whose value space is a continuous integer range (e.g. per-key RGB colors as 24-bit ints) use this in place of a NamedInts choice list. """ min: int max: int byte_count: int = 1 signed: bool = False value_type: type = int def contains(self, value: int) -> bool: return isinstance(value, int) and self.min <= value <= self.max class MapRangeValidator(Validator): """Map of keys → integer in a per-key Range. Open value space (no choice list). Reports `kind = Kind.MAP_CHOICE` so the existing config-panel/CLI/rule-engine dispatch keeps routing without new branches; consumers that need to tell "choice list" from "open range" check `isinstance(setting.choices[k], Range)`. TODO: complete `Kind.MAP_RANGE` infrastructure (UI dispatch, generic rule-UI handling, generalize `cli/config.py:299`) and migrate this validator's `kind` over. Today MAP_RANGE is only honored by `ForceSensing` via the `settings_new` framework; bridging both frameworks is a separate task. """ kind = Kind.MAP_CHOICE def __init__(self, choices_map, key_byte_count=1, write_prefix_bytes=b""): assert isinstance(choices_map, dict) for k, v in choices_map.items(): assert isinstance(k, NamedInt), f"MapRangeValidator key must be NamedInt, got {type(k).__name__}" assert isinstance(v, Range), f"MapRangeValidator value must be Range, got {type(v).__name__}" self.choices = choices_map self.needs_current_value = False self._key_byte_count = key_byte_count self._write_prefix_bytes = write_prefix_bytes def to_string(self, value) -> str: if not isinstance(value, dict): return str(value) # Persisted dicts loaded from YAML come back as plain ints regardless # of the choice's `value_type`. Re-wrap raw ints through the configured # value_type (e.g. ColorInt) so they self-format consistently here and # in `solaar show`. Skip wrapping for NamedInt sentinels / subclasses # (`type(v) is int` is the exact-match guard). rng_by_int_key = {int(k): rng for k, rng in self.choices.items()} def _fmt(k): v = value[k] rng = rng_by_int_key.get(int(k)) if rng is not None and type(v) is int and rng.value_type is not int: # noqa: E721 try: v = rng.value_type(v) except Exception: pass return f"{k}:{v}" return "{" + ", ".join(_fmt(k) for k in sorted(value)) + "}" def validate_read(self, reply_bytes, key): rng = self.choices.get(key) if rng is None: return None end = self._key_byte_count + rng.byte_count return rng.value_type(common.bytes2int(reply_bytes[self._key_byte_count : end], signed=rng.signed)) def prepare_key(self, key): return int(key).to_bytes(self._key_byte_count, "big") def prepare_write(self, key, new_value): rng = self.choices.get(key) if rng is None: logger.error("invalid key %r for map-range setting", key) return None if not rng.contains(new_value): logger.error("value %r out of range [%d, %d] for key %s", new_value, rng.min, rng.max, key) return None return self._write_prefix_bytes + int(new_value).to_bytes(rng.byte_count, "big", signed=rng.signed) def acceptable(self, args, current): if not isinstance(args, list) or len(args) != 2: return None key = next((k for k in self.choices if int(k) == int(args[0])), None) if key is None: return None rng = self.choices[key] if not rng.contains(args[1]): return None return [int(key), int(args[1])] def compare(self, args, current): if not isinstance(args, list) or len(args) != 2 or not isinstance(current, dict): return False key = next((k for k in self.choices if int(k) == int(args[0])), None) if key is None: return False return current.get(int(key)) == args[1] Solaar-1.1.20/lib/logitech_receiver/special_keys.py000066400000000000000000001365261522022367600223130ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. # Reprogrammable keys information # Mostly from Logitech documentation, but with some edits for better Linux compatibility import os from enum import IntEnum import yaml from .common import NamedInts from .common import UnsortedNamedInts _XDG_CONFIG_HOME = os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser(os.path.join("~", ".config")) _keys_file_path = os.path.join(_XDG_CONFIG_HOME, "solaar", "keys.yaml") # Original set done as # tasks.py SWITCH_PRESENTATION_SWITCH_SCREEN = 0x0093 # on K400 Plus MINIMIZE_WINDOW = 0x0094 MAXIMIZE_WINDOW = 0x0095 # on K400 Plus MULTI_PLATFORM_APP_SWITCH = 0x0096 MULTI_PLATFORM_HOME = 0x0097 MULTI_PLATFORM_MENU = 0x0098 MULTI_PLATFORM_BACK = 0x0099 SWITCH_LANGUAGE = 0x009A # Mac_switch_language SCREEN_CAPTURE = 0x009B # Mac_screen_Capture, on Craft Keyboard GESTURE_BUTTON = 0x009C SMART_SHIFT = 0x009D APP_EXPOSE = 0x009E SMART_ZOOM = 0x009F LOOKUP = 0x00A0 MICROPHEON_ON_OFF = 0x00A1 WIFI_ON_OFF = 0x00A2 BRIGHTNESS_DOWN = 0x00A3 BRIGHTNESS_UP = 0x00A4 DISPLAY_OUT = 0x00A5 VIEW_OPEN_APPS = 0x00A6 VIEW_ALL_OPEN_APPS = 0x00A7 APP_SWITCH = 0x00A8 GESTURE_BUTTON_NAVIGATION = 0x00A9 # Mouse_Thumb_Button on MX Master FN_INVERSION = 0x00AA MULTI_PLATFORM_BACK_2 = 0x00AB # Alternative MULTI_PLATFORM_FORWARD = 0x00AC MULTI_PLATFORM_Gesture_Button = 0x00AD HostSwitch_Channel_1 = 0x00AE HostSwitch_Channel_2 = 0x00AF HostSwitch_Channel_3 = 0x00B0 MULTI_PLATFORM_SEARCH = 0x00B1 MULTI_PLATFORM_HOME_MISSION_CONTROL = 0x00B2 MULTI_PLATFORM_MENU_LAUNCHPAD = 0x00B3 VIRTUAL_GESTURE_BUTTON = 0x00B4 CURSOR = 0x00B5 KEYBOARD_RIGHT_ARROW = 0x00B6 SW_CUSTOM_HIGHLIGHT = 0x00B7 KEYBOARD_LEFT_ARROW = 0x00B8 TBD = 0x00B9 MULTI_PLATFORM_Language_Switch = 0x00BA SW_CUSTOM_HIGHLIGHT_2 = 0x00BB FAST_FORWARD = 0x00BC FAST_BACKWARD = 0x00BD SWITCH_HIGHLIGHTING = 0x00BE MISSION_CONTROL_TASK_VIEW = 0x00BF # Switch_Workspace on Craft Keyboard DASHBOARD_LAUNCHPAD_ACTION_CENTER = 0x00C0 # Application_Launcher on Craft # Keyboard BACKLIGHT_DOWN = 0x00C1 # Backlight_Down_FW_internal_function BACKLIGHT_UP = 0x00C2 # Backlight_Up_FW_internal_function RIGHT_CLICK_APP_CONTEXT_MENU = 0x00C3 # Context_Menu on Craft Keyboard DPI_Change = 0x00C4 NEW_TAB = 0x00C5 F2 = 0x00C6 F3 = 0x00C7 F4 = 0x00C8 F5 = 0x00C9 F6 = 0x00CA F7 = 0x00CB F8 = 0x00CC F1 = 0x00CD LASER_BUTTON = 0x00CE LASER_BUTTON_LONG_PRESS = 0x00CF START_PRESENTATION = 0x00D0 BLANK_SCREEN = 0x00D1 DPI_Switch = 0x00D2 # AdjustDPI on MX Vertical HOME_SHOW_DESKTOP = 0x00D3 APP_SWITCH_DASHBOARD = 0x00D4 APP_SWITCH_2 = 0x00D5 # Alternative FN_INVERSION_2 = 0x00D6 # Alternative LEFT_AND_RIGHT_CLICK = 0x00D7 VOICE_DICTATION = 0x00D8 EMOJI_SMILING_FACE_WITH_HEART_SHAPED_EYES = 0x00D9 EMOJI_LOUDLY_CRYING_FACE = 0x00DA EMOJI_SMILEY = 0x00DB EMOJI_SMILE_WITH_TEARS = 0x00DC OPEN_EMOJI_PANEL = 0x00DD MULTI_PLATFORM_APP_SWITCH_LAUNCHPAD = 0x00DE SNIPPING_TOOL = 0x00DF GRAVE_ACCENT = 0x00E0 STANDARD_TAB_KEY = 0x00E1 CAPS_LOCK = 0x00E2 LEFT_SHIFT = 0x00E3 LEFT_CONTROL = 0x00E4 LEFT_OPTION_START = 0x00E5 LEFT_COMMAND_ALT = 0x00E6 RIGHT_COMMAND_ALT = 0x00E7 RIGHT_OPTION_START = 0x00E8 RIGHT_CONTROL = 0x00E9 RIGHT_SHIFT = 0x0EA INSERT = 0x00EB DELETE = 0x00EC HOME = 0x00ED END = 0x00EE PAGE_UP_2 = 0x00EF # Alternative PAGE_DOWN_2 = 0x00F0 # Alternative MUTE_MICROPHONE = 0x00F1 DO_NOT_DISTURB = 0x00F2 BACKSLASH = 0x00F3 REFRESH = 0x00F4 CLOSE_TAB = 0x00F5 LANG_SWITCH = 0x00F6 STANDARD_ALPHABETICAL_KEY = 0x00F7 RRIGH_OPTION_START_2 = 0x00F8 LEFT_OPTION = 0x00F9 RIGHT_OPTION = 0x00FA LEFT_CMD = 0x00FB RIGHT_CMD = 0x00FC def __str__(self): return self.name.replace("_", " ").title() class CIDGroupBit(IntEnum): g1 = 0x01 g2 = 0x02 g3 = 0x04 g4 = 0x08 g5 = 0x10 g6 = 0x20 g7 = 0x40 g8 = 0x80 class CidGroup(IntEnum): g1 = 1 g2 = 2 g3 = 3 g4 = 4 g5 = 5 g6 = 6 g7 = 7 g8 = 8 DISABLE = NamedInts( Caps_Lock=0x01, Num_Lock=0x02, Scroll_Lock=0x04, Insert=0x08, Win=0x10, # aka Super ) DISABLE._fallback = lambda x: f"unknown:{x:02X}" # HID USB Keycodes from https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf # Modified by information from Linux HID driver linux/drivers/hid/hid-input.c USB_HID_KEYCODES = NamedInts( A=0x04, B=0x05, C=0x06, D=0x07, E=0x08, F=0x09, G=0x0A, H=0x0B, I=0x0C, J=0x0D, K=0x0E, L=0x0F, M=0x10, N=0x11, O=0x12, P=0x13, Q=0x14, R=0x15, S=0x16, T=0x17, U=0x18, V=0x19, W=0x1A, X=0x1B, Y=0x1C, Z=0x1D, ENTER=0x28, ESC=0x29, BACKSPACE=0x2A, TAB=0x2B, SPACE=0x2C, MINUS=0x2D, EQUAL=0x2E, LEFTBRACE=0x2F, RIGHTBRACE=0x30, BACKSLASH=0x31, HASHTILDE=0x32, SEMICOLON=0x33, APOSTROPHE=0x34, GRAVE=0x35, COMMA=0x36, DOT=0x37, SLASH=0x38, CAPSLOCK=0x39, F1=0x3A, F2=0x3B, F3=0x3C, F4=0x3D, F5=0x3E, F6=0x3F, F7=0x40, F8=0x41, F9=0x42, F10=0x43, F11=0x44, F12=0x45, SYSRQ=0x46, SCROLLLOCK=0x47, PAUSE=0x48, INSERT=0x49, HOME=0x4A, PAGEUP=0x4B, DELETE=0x4C, END=0x4D, PAGEDOWN=0x4E, RIGHT=0x4F, LEFT=0x50, DOWN=0x51, UP=0x52, NUMLOCK=0x53, KPSLASH=0x54, KPASTERISK=0x55, KPMINUS=0x56, KPPLUS=0x57, KPENTER=0x58, KP1=0x59, KP2=0x5A, KP3=0x5B, KP4=0x5C, KP5=0x5D, KP6=0x5E, KP7=0x5F, KP8=0x60, KP9=0x61, KP0=0x62, KPDOT=0x63, COMPOSE=0x65, POWER=0x66, KPEQUAL=0x67, F13=0x68, F14=0x69, F15=0x6A, F16=0x6B, F17=0x6C, F18=0x6D, F19=0x6E, F20=0x6F, F21=0x70, F22=0x71, F23=0x72, F24=0x73, OPEN=0x74, HELP=0x75, PROPS=0x76, FRONT=0x77, STOP=0x78, AGAIN=0x79, UNDO=0x7A, CUT=0x7B, COPY=0x7C, PASTE=0x7D, FIND=0x7E, MUTE=0x7F, VOLUMEUP=0x80, VOLUMEDOWN=0x81, KPCOMMA=0x85, RO=0x87, KATAKANAHIRAGANA=0x88, YEN=0x89, HENKAN=0x8A, MUHENKAN=0x8B, KPJPCOMMA=0x8C, HANGEUL=0x90, HANJA=0x91, KATAKANA=0x92, HIRAGANA=0x93, ZENKAKUHANKAKU=0x94, KPLEFTPAREN=0xB6, KPRIGHTPAREN=0xB7, LEFTCTRL=0xE0, LEFTSHIFT=0xE1, LEFTALT=0xE2, LEFTWINDOWS=0xE3, RIGHTCTRL=0xE4, RIGHTSHIFT=0xE5, RIGHTALT=0xE6, RIGHTMETA=0xE7, MEDIA_PLAYPAUSE=0xE8, MEDIA_STOPCD=0xE9, MEDIA_PREVIOUSSONG=0xEA, MEDIA_NEXTSONG=0xEB, MEDIA_EJECTCD=0xEC, MEDIA_VOLUMEUP=0xED, MEDIA_VOLUMEDOWN=0xEE, MEDIA_MUTE=0xEF, MEDIA_WWW=0xF0, MEDIA_BACK=0xF1, MEDIA_FORWARD=0xF2, MEDIA_STOP=0xF3, MEDIA_FIND=0xF4, MEDIA_SCROLLUP=0xF5, MEDIA_SCROLLDOWN=0xF6, MEDIA_EDIT=0xF7, MEDIA_SLEEP=0xF8, MEDIA_COFFEE=0xF9, MEDIA_REFRESH=0xFA, MEDIA_CALC=0xFB, ) USB_HID_KEYCODES[0] = "No Output" USB_HID_KEYCODES[0x1E] = "1" USB_HID_KEYCODES[0x1F] = "2" USB_HID_KEYCODES[0x20] = "3" USB_HID_KEYCODES[0x21] = "4" USB_HID_KEYCODES[0x22] = "5" USB_HID_KEYCODES[0x23] = "6" USB_HID_KEYCODES[0x24] = "7" USB_HID_KEYCODES[0x25] = "8" USB_HID_KEYCODES[0x26] = "9" USB_HID_KEYCODES[0x27] = "0" USB_HID_KEYCODES[0x64] = "102ND" HID_CONSUMERCODES = NamedInts( { # Unassigned=0x00, # Consumer_Control=0x01, # Numeric_Key_Pad=0x02, # Programmable_Buttons=0x03, # Microphone=0x04, # Headphone=0x05, # Graphic_Equalizer=0x06, # AM__PM=0x22, "Power": 0x30, "Reset": 0x31, "Sleep": 0x32, "Sleep_After": 0x33, "Sleep_Mode": 0x34, "Illumination": 0x35, "Function_Buttons": 0x36, "Menu": 0x40, "Menu__Pick": 0x41, "Menu_Up": 0x42, "Menu_Down": 0x43, "Menu_Left": 0x44, "Menu_Right": 0x45, "Menu_Escape": 0x46, "Menu_Value_Increase": 0x47, "Menu_Value_Decrease": 0x48, "Data_On_Screen": 0x60, "Closed_Caption": 0x61, # Closed_Caption_Select=0x62, "VCR__TV": 0x63, # Broadcast_Mode=0x64, "Snapshot": 0x65, # Still=0x66, "Red": 0x69, "Green": 0x6A, "Blue": 0x6B, "Yellow": 0x6C, "Aspect_Ratio": 0x6D, "Brightness_Up": 0x6F, "Brightness_Down": 0x70, "Brightness_Toggle": 0x72, "Brightness_Min": 0x73, "Brightness_Max": 0x74, "Brightness_Auto": 0x75, "Keyboard_Illumination_Up": 0x79, "Keyboard_Illumination_Down": 0x7A, "Keyboard_Illumination_Toggle": 0x7C, # Selection=0x80, # Assign_Selection=0x81, "Mode_Step": 0x82, "Recall_Last": 0x83, "Enter_Channel": 0x84, # Order_Movie=0x85, # Channel=0x86, # Media_Selection=0x87, "Media_Select_Computer": 0x88, "Media_Select_TV": 0x89, "Media_Select_WWW": 0x8A, "Media_Select_DVD": 0x8B, "Media_Select_Telephone": 0x8C, "Media_Select_Program_Guide": 0x8D, "Media_Select_Video_Phone": 0x8E, "Media_Select_Games": 0x8F, "Media_Select_Messages": 0x90, "Media_Select_CD": 0x91, "Media_Select_VCR": 0x92, "Media_Select_Tuner": 0x93, "Quit": 0x94, "Help": 0x95, "Media_Select_Tape": 0x96, "Media_Select_Cable": 0x97, "Media_Select_Satellite": 0x98, "Media_Select_Security": 0x99, "Media_Select_Home": 0x9A, # Media_Select_Call=0x9B, "Channel_Increment": 0x9C, "Channel_Decrement": 0x9D, # Media_Select_SAP=0x9E, "VCR_Plus": 0xA0, # Once=0xA1, # Daily=0xA2, # Weekly=0xA3, # Monthly=0xA4, "Play": 0xB0, "Pause": 0xB1, "Record": 0xB2, "Fast_Forward": 0xB3, "Rewind": 0xB4, "Scan_Next_Track": 0xB5, "Scan_Previous_Track": 0xB6, "Stop": 0xB7, "Eject": 0xB8, "Random_Play": 0xB9, "Select_DisC": 0xBA, "Enter_Disc": 0xBB, "Repeat": 0xBC, "Tracking": 0xBD, "Track_Normal": 0xBE, "Slow_Tracking": 0xBF, # Frame_Forward=0xC0, # Frame_Back=0xC1, # Mark=0xC2, # Clear_Mark=0xC3, # Repeat_From_Mark=0xC4, # Return_To_Mark=0xC5, # Search_Mark_Forward=0xC6, # Search_Mark_Backwards=0xC7, # Counter_Reset=0xC8, # Show_Counter=0xC9, # Tracking_Increment=0xCA, # Tracking_Decrement=0xCB, # Stop__Eject=0xCC, "Play__Pause": 0xCD, # Play__Skip=0xCE, "Volume": 0xE0, # Balance=0xE1, "Mute": 0xE2, # Bass=0xE3, # Treble=0xE4, "Bass_Boost": 0xE5, # Surround_Mode=0xE6, # Loudness=0xE7, # MPX=0xE8, "Volume_Up": 0xE9, "Volume_Down": 0xEA, # Speed_Select=0xF0, # Playback_Speed=0xF1, # Standard_Play=0xF2, # Long_Play=0xF3, # Extended_Play=0xF4, "Slow": 0xF5, "Fan_Enable": 0x100, "Fan_Speed": 0x101, "Light": 0x102, "Light_Illumination_Level": 0x103, "Climate_Control_Enable": 0x104, "Room_Temperature": 0x105, "Security_Enable": 0x106, "Fire_Alarm": 0x107, "Police_Alarm": 0x108, "Proximity": 0x109, "Motion": 0x10A, "Duress_Alarm": 0x10B, "Holdup_Alarm": 0x10C, "Medical_Alarm": 0x10D, "Balance_Right": 0x150, "Balance_Left": 0x151, "Bass_Increment": 0x152, "Bass_Decrement": 0x153, "Treble_Increment": 0x154, "Treble_Decrement": 0x155, "Speaker_System": 0x160, "Channel_Left": 0x161, "Channel_Right": 0x162, "Channel_Center": 0x163, "Channel_Front": 0x164, "Channel_Center_Front": 0x165, "Channel_Side": 0x166, "Channel_Surround": 0x167, "Channel_Low_Frequency_Enhancement": 0x168, "Channel_Top": 0x169, "Channel_Unknown": 0x16A, "Subchannel": 0x170, "Subchannel_Increment": 0x171, "Subchannel_Decrement": 0x172, "Alternate_Audio_Increment": 0x173, "Alternate_Audio_Decrement": 0x174, "Application_Launch_Buttons": 0x180, "AL_Launch_Button_Configuration_Tool": 0x181, "AL_Programmable_Button_Configuration": 0x182, "AL_Consumer_Control_Configuration": 0x183, "AL_Word_Processor": 0x184, "AL_Text_Editor": 0x185, "AL_Spreadsheet": 0x186, "AL_Graphics_Editor": 0x187, "AL_Presentation_App": 0x188, "AL_Database_App": 0x189, "AL_Email_Reader": 0x18A, "AL_Newsreader": 0x18B, "AL_Voicemail": 0x18C, "AL_Contacts__Address_Book": 0x18D, "AL_Calendar__Schedule": 0x18E, "AL_Task__Project_Manager": 0x18F, "AL_Log__Journal__Timecard": 0x190, "AL_Checkbook__Finance": 0x191, "AL_Calculator": 0x192, "AL_A__V_Capture__Playback": 0x193, "AL_Local_Machine_Browser": 0x194, "AL_LAN__WAN_Browser": 0x195, "AL_Internet_Browser": 0x196, "AL_Remote_Networking__ISP_Connect": 0x197, "AL_Network_Conference": 0x198, "AL_Network_Chat": 0x199, "AL_Telephony__Dialer": 0x19A, "AL_Logon": 0x19B, "AL_Logoff": 0x19C, "AL_Logon__Logoff": 0x19D, "AL_Terminal_Lock__Screensaver": 0x19E, "AL_Control_Panel": 0x19F, "AL_Command_Line_Processor__Run": 0x1A0, "AL_Process__Task_Manager": 0x1A1, "AL_Select_Tast__Application": 0x1A2, "AL_Next_Task__Application": 0x1A3, "AL_Previous_Task__Application": 0x1A4, "AL_Preemptive_Halt_Task__Application": 0x1A5, "AL_Integrated_Help_Center": 0x1A6, "AL_Documents": 0x1A7, "AL_Thesaurus": 0x1A8, "AL_Dictionary": 0x1A9, "AL_Desktop": 0x1AA, "AL_Spell_Check": 0x1AB, "AL_Grammar_Check": 0x1AC, "AL_Wireless_Status": 0x1AD, "AL_Keyboard_Layout": 0x1AE, "AL_Virus_Protection": 0x1AF, "AL_Encryption": 0x1B0, "AL_Screen_Saver": 0x1B1, "AL_Alarms": 0x1B2, "AL_Clock": 0x1B3, "AL_File_Browser": 0x1B4, "AL_Power_Status": 0x1B5, "AL_Image_Browser": 0x1B6, "AL_Audio_Browser": 0x1B7, "AL_Movie_Browser": 0x1B8, "AL_Digital_Rights_Manager": 0x1B9, "AL_Digital_Wallet": 0x1BA, "AL_Instant_Messaging": 0x1BC, "AL_OEM_Features___Tips__Tutorial_Browser": 0x1BD, "AL_OEM_Help": 0x1BE, "AL_Online_Community": 0x1BF, "AL_Entertainment_Content_Browser": 0x1C0, "AL_Online_Shopping_Browser": 0x1C1, "AL_SmartCard_Information__Help": 0x1C2, "AL_Market_Monitor__Finance_Browser": 0x1C3, "AL_Customized_Corporate_News_Browser": 0x1C4, "AL_Online_Activity_Browser": 0x1C5, "AL_Research__Search_Browser": 0x1C6, "AL_Audio_Player": 0x1C7, "Generic_GUI_Application_Controls": 0x200, "AC_New": 0x201, "AC_Open": 0x202, "AC_Close": 0x203, "AC_Exit": 0x204, "AC_Maximize": 0x205, "AC_Minimize": 0x206, "AC_Save": 0x207, "AC_Print": 0x208, "AC_Properties": 0x209, "AC_Undo": 0x21A, "AC_Copy": 0x21B, "AC_Cut": 0x21C, "AC_Paste": 0x21D, "AC_Select_All": 0x21E, "AC_Find": 0x21F, "AC_Find_and_Replace": 0x220, "AC_Search": 0x221, "AC_Go_To": 0x222, "AC_Home": 0x223, "AC_Back": 0x224, "AC_Forward": 0x225, "AC_Stop": 0x226, "AC_Refresh": 0x227, "AC_Previous_Link": 0x228, "AC_Next_Link": 0x229, "AC_Bookmarks": 0x22A, "AC_History": 0x22B, "AC_Subscriptions": 0x22C, "AC_Zoom_In": 0x22D, "AC_Zoom_Out": 0x22E, "AC_Zoom": 0x22F, "AC_Full_Screen_View": 0x230, "AC_Normal_View": 0x231, "AC_View_Toggle": 0x232, "AC_Scroll_Up": 0x233, "AC_Scroll_Down": 0x234, "AC_Scroll": 0x235, "AC_Pan_Left": 0x236, "AC_Pan_Right": 0x237, "AC_Pan": 0x238, "AC_New_Window": 0x239, "AC_Tile_Horizontally": 0x23A, "AC_Tile_Vertically": 0x23B, "AC_Format": 0x23C, "AC_Edit": 0x23D, "AC_Bold": 0x23E, "AC_Italics": 0x23F, "AC_Underline": 0x240, "AC_Strikethrough": 0x241, "AC_Subscript": 0x242, "AC_Superscript": 0x243, "AC_All_Caps": 0x244, "AC_Rotate": 0x245, "AC_Resize": 0x246, "AC_Flip_horizontal": 0x247, "AC_Flip_Vertical": 0x248, "AC_Mirror_Horizontal": 0x249, "AC_Mirror_Vertical": 0x24A, "AC_Font_Select": 0x24B, "AC_Font_Color": 0x24C, "AC_Font_Size": 0x24D, "AC_Justify_Left": 0x24E, "AC_Justify_Center_H": 0x24F, "AC_Justify_Right": 0x250, "AC_Justify_Block_H": 0x251, "AC_Justify_Top": 0x252, "AC_Justify_Center_V": 0x253, "AC_Justify_Bottom": 0x254, "AC_Justify_Block_V": 0x255, "AC_Indent_Decrease": 0x256, "AC_Indent_Increase": 0x257, "AC_Numbered_List": 0x258, "AC_Restart_Numbering": 0x259, "AC_Bulleted_List": 0x25A, "AC_Promote": 0x25B, "AC_Demote": 0x25C, "AC_Yes": 0x25D, "AC_No": 0x25E, "AC_Cancel": 0x25F, "AC_Catalog": 0x260, "AC_Buy__Checkout": 0x261, "AC_Add_to_Cart": 0x262, "AC_Expand": 0x263, "AC_Expand_All": 0x264, "AC_Collapse": 0x265, "AC_Collapse_All": 0x266, "AC_Print_Preview": 0x267, "AC_Paste_Special": 0x268, "AC_Insert_Mode": 0x269, "AC_Delete": 0x26A, "AC_Lock": 0x26B, "AC_Unlock": 0x26C, "AC_Protect": 0x26D, "AC_Unprotect": 0x26E, "AC_Attach_Comment": 0x26F, "AC_Delete_Comment": 0x270, "AC_View_Comment": 0x271, "AC_Select_Word": 0x272, "AC_Select_Sentence": 0x273, "AC_Select_Paragraph": 0x274, "AC_Select_Column": 0x275, "AC_Select_Row": 0x276, "AC_Select_Table": 0x277, "AC_Select_Object": 0x278, "AC_Redo__Repeat": 0x279, "AC_Sort": 0x27A, "AC_Sort_Ascending": 0x27B, "AC_Sort_Descending": 0x27C, "AC_Filter": 0x27D, "AC_Set_Clock": 0x27E, "AC_View_Clock": 0x27F, "AC_Select_Time_Zone": 0x280, "AC_Edit_Time_Zones": 0x281, "AC_Set_Alarm": 0x282, "AC_Clear_Alarm": 0x283, "AC_Snooze_Alarm": 0x284, "AC_Reset_Alarm": 0x285, "AC_Synchronize": 0x286, "AC_Send__Receive": 0x287, "AC_Send_To": 0x288, "AC_Reply": 0x289, "AC_Reply_All": 0x28A, "AC_Forward_Msg": 0x28B, "AC_Send": 0x28C, "AC_Attach_File": 0x28D, "AC_Upload": 0x28E, "AC_Download_Save_Target_As": 0x28F, "AC_Set_Borders": 0x290, "AC_Insert_Row": 0x291, "AC_Insert_Column": 0x292, "AC_Insert_File": 0x293, "AC_Insert_Picture": 0x294, "AC_Insert_Object": 0x295, "AC_Insert_Symbol": 0x296, "AC_Save_and_Close": 0x297, "AC_Rename": 0x298, "AC_Merge": 0x299, "AC_Split": 0x29A, "AC_Distribute_Horizontally": 0x29B, "AC_Distribute_Vertically": 0x29C, } ) HID_CONSUMERCODES[0x20] = "+10" HID_CONSUMERCODES[0x21] = "+100" HID_CONSUMERCODES._fallback = lambda x: f"unknown:{x:04X}" ## Information for x1c00 Persistent from https://drive.google.com/drive/folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28 KEYMOD = NamedInts(CTRL=0x01, SHIFT=0x02, ALT=0x04, META=0x08, RCTRL=0x10, RSHIFT=0x20, RALT=0x40, RMETA=0x80) ACTIONID = NamedInts( Empty=0x00, Key=0x01, Mouse=0x02, Xdisp=0x03, Ydisp=0x04, Vscroll=0x05, Hscroll=0x06, Consumer=0x07, Internal=0x08, Power=0x09, ) MOUSE_BUTTONS = NamedInts( Mouse_Button_Left=0x0001, Mouse_Button_Right=0x0002, Mouse_Button_Middle=0x0004, Mouse_Button_Back=0x0008, Mouse_Button_Forward=0x0010, Mouse_Button_6=0x0020, Mouse_Button_Scroll_Left=0x0040, Mouse_Button_Scroll_Right=0x0080, Mouse_Button_9=0x0100, Mouse_Button_10=0x0200, Mouse_Button_11=0x0400, Mouse_Button_12=0x0800, Mouse_Button_13=0x1000, Mouse_Button_DPI=0x2000, Mouse_Button_15=0x4000, Mouse_Button_16=0x8000, ) MOUSE_BUTTONS._fallback = lambda x: f"unknown mouse button:{x:04X}" class HorizontalScroll(IntEnum): Left = 0x4000 Right = 0x8000 # Construct universe for Persistent Remappable Keys setting (only for supported values) KEYS = UnsortedNamedInts() KEYS_Default = 0x7FFFFFFF # Special value to reset key to default - has to be different from all others KEYS[KEYS_Default] = "Default" # Value to reset to default KEYS[0] = "None" # Value for no output # Add HID keys plus modifiers modifiers = { 0x00: "", 0x01: "Cntrl+", 0x02: "Shift+", 0x04: "Alt+", 0x08: "Meta+", 0x03: "Cntrl+Shift+", 0x05: "Alt+Cntrl+", 0x09: "Meta+Cntrl+", 0x06: "Alt+Shift+", 0x0A: "Meta+Shift+", 0x0C: "Meta+Alt+", } for val, name in modifiers.items(): for key in USB_HID_KEYCODES: KEYS[(ACTIONID.Key << 24) + (int(key) << 8) + val] = name + str(key) # Add HID Consumer Codes for code in HID_CONSUMERCODES: KEYS[(ACTIONID.Consumer << 24) + (int(code) << 8)] = str(code) # Add Mouse Buttons for code in MOUSE_BUTTONS: KEYS[(ACTIONID.Mouse << 24) + (int(code) << 8)] = str(code) # Add Horizontal Scroll for code in HorizontalScroll: KEYS[(ACTIONID.Hscroll << 24) + (int(code) << 8)] = str(code) # Construct subsets for known devices def persistent_keys(action_ids): keys = UnsortedNamedInts() keys[KEYS_Default] = "Default" # Value to reset to default keys[0] = "No Output (only as default)" for key in KEYS: if (int(key) >> 24) in action_ids: keys[int(key)] = str(key) return keys KEYS_KEYS_CONSUMER = persistent_keys([ACTIONID.Key, ACTIONID.Consumer]) KEYS_KEYS_MOUSE_HSCROLL = persistent_keys([ACTIONID.Key, ACTIONID.Mouse, ACTIONID.Hscroll]) COLORS = UnsortedNamedInts( { # from Xorg rgb.txt,v 1.3 2000/08/17 "red": 0xFF0000, "orange": 0xFFA500, "yellow": 0xFFFF00, "green": 0x00FF00, "blue": 0x0000FF, "purple": 0xA020F0, "violet": 0xEE82EE, "black": 0x000000, "white": 0xFFFFFF, "gray": 0xBEBEBE, "brown": 0xA52A2A, "cyan": 0x00FFFF, "magenta": 0xFF00FF, "pink": 0xFFC0CB, "maroon": 0xB03060, "turquoise": 0x40E0D0, "gold": 0xFFD700, "tan": 0xD2B48C, "snow": 0xFFFAFA, "ghost white": 0xF8F8FF, "white smoke": 0xF5F5F5, "gainsboro": 0xDCDCDC, "floral white": 0xFFFAF0, "old lace": 0xFDF5E6, "linen": 0xFAF0E6, "antique white": 0xFAEBD7, "papaya whip": 0xFFEFD5, "blanched almond": 0xFFEBCD, "bisque": 0xFFE4C4, "peach puff": 0xFFDAB9, "navajo white": 0xFFDEAD, "moccasin": 0xFFE4B5, "cornsilk": 0xFFF8DC, "ivory": 0xFFFFF0, "lemon chiffon": 0xFFFACD, "seashell": 0xFFF5EE, "honeydew": 0xF0FFF0, "mint cream": 0xF5FFFA, "azure": 0xF0FFFF, "alice blue": 0xF0F8FF, "lavender": 0xE6E6FA, "lavender blush": 0xFFF0F5, "misty rose": 0xFFE4E1, "dark slate gray": 0x2F4F4F, "dim gray": 0x696969, "slate gray": 0x708090, "light slate gray": 0x778899, "light gray": 0xD3D3D3, "midnight blue": 0x191970, "navy blue": 0x000080, "cornflower blue": 0x6495ED, "dark slate blue": 0x483D8B, "slate blue": 0x6A5ACD, "medium slate blue": 0x7B68EE, "light slate blue": 0x8470FF, "medium blue": 0x0000CD, "royal blue": 0x4169E1, "dodger blue": 0x1E90FF, "deep sky blue": 0x00BFFF, "sky blue": 0x87CEEB, "light sky blue": 0x87CEFA, "steel blue": 0x4682B4, "light steel blue": 0xB0C4DE, "light blue": 0xADD8E6, "powder blue": 0xB0E0E6, "pale turquoise": 0xAFEEEE, "dark turquoise": 0x00CED1, "medium turquoise": 0x48D1CC, "light cyan": 0xE0FFFF, "cadet blue": 0x5F9EA0, "medium aquamarine": 0x66CDAA, "aquamarine": 0x7FFFD4, "dark green": 0x006400, "dark olive green": 0x556B2F, "dark sea green": 0x8FBC8F, "sea green": 0x2E8B57, "medium sea green": 0x3CB371, "light sea green": 0x20B2AA, "pale green": 0x98FB98, "spring green": 0x00FF7F, "lawn green": 0x7CFC00, "chartreuse": 0x7FFF00, "medium spring green": 0x00FA9A, "green yellow": 0xADFF2F, "lime green": 0x32CD32, "yellow green": 0x9ACD32, "forest green": 0x228B22, "olive drab": 0x6B8E23, "dark khaki": 0xBDB76B, "khaki": 0xF0E68C, "pale goldenrod": 0xEEE8AA, "light goldenrod yellow": 0xFAFAD2, "light yellow": 0xFFFFE0, "light goldenrod": 0xEEDD82, "goldenrod": 0xDAA520, "dark goldenrod": 0xB8860B, "rosy brown": 0xBC8F8F, "indian red": 0xCD5C5C, "saddle brown": 0x8B4513, "sienna": 0xA0522D, "peru": 0xCD853F, "burlywood": 0xDEB887, "beige": 0xF5F5DC, "wheat": 0xF5DEB3, "sandy brown": 0xF4A460, "chocolate": 0xD2691E, "firebrick": 0xB22222, "dark salmon": 0xE9967A, "salmon": 0xFA8072, "light salmon": 0xFFA07A, "dark orange": 0xFF8C00, "coral": 0xFF7F50, "light coral": 0xF08080, "tomato": 0xFF6347, "orange red": 0xFF4500, "hot pink": 0xFF69B4, "deep pink": 0xFF1493, "light pink": 0xFFB6C1, "pale violet red": 0xDB7093, "medium violet red": 0xC71585, "violet red": 0xD02090, "plum": 0xDDA0DD, "orchid": 0xDA70D6, "medium orchid": 0xBA55D3, "dark orchid": 0x9932CC, "dark violet": 0x9400D3, "blue violet": 0x8A2BE2, "medium purple": 0x9370DB, "thistle": 0xD8BFD8, "dark gray": 0xA9A9A9, "dark blue": 0x00008B, "dark cyan": 0x008B8B, "dark magenta": 0x8B008B, "dark red": 0x8B0000, "light green": 0x90EE90, } ) COLORSPLUS = UnsortedNamedInts({"No change": -1}) for i in COLORS: COLORSPLUS[int(i)] = str(i) KEYCODES = NamedInts( { "A": 1, "B": 2, "C": 3, "D": 4, "E": 5, "F": 6, "G": 7, "H": 8, "I": 9, "J": 10, "K": 11, "L": 12, "M": 13, "N": 14, "O": 15, "P": 16, "Q": 17, "R": 18, "S": 19, "T": 20, "U": 21, "V": 22, "W": 23, "X": 24, "Y": 25, "Z": 26, "1": 27, "2": 28, "3": 29, "4": 30, "5": 31, "6": 32, "7": 33, "8": 34, "9": 35, "0": 36, "ENTER": 37, "ESC": 38, "BACKSPACE": 39, "TAB": 40, "SPACE": 41, "-": 42, "=": 43, "[": 44, "]": 45, "\\": 45, "~": 47, ";": 48, "'": 49, "`": 50, ",": 51, ".": 52, "/": 53, "CAPS LOCK": 54, "F1": 55, "F2": 56, "F3": 57, "F4": 58, "F5": 59, "F6": 60, "F7": 61, "F8": 62, "F9": 63, "F10": 64, "F11": 65, "F12": 66, "PRINT": 67, "SCROLL LOCK": 68, "PASTE": 69, "INSERT": 70, "HOME": 71, "PAGE UP": 72, "DELETE": 73, "END": 74, "PAGE DOWN": 75, "RIGHT": 76, "LEFT": 77, "DOWN": 78, "UP": 79, "NUMLOCK": 80, "KEYPAD /": 81, "KEYPAD *": 82, "KEYPAD -": 83, "KEYPAD +": 84, "KEYPAD ENTER": 85, "KEYPAD 1": 86, "KEYPAD 2": 87, "KEYPAD 3": 88, "KEYPAD 4": 89, "KEYPAD 5": 90, "KEYPAD 6": 91, "KEYPAD 7": 92, "KEYPAD 8": 93, "KEYPAD 9": 94, "KEYPAD 0": 95, "KEYPAD .": 96, "COMPOSE": 98, "POWER": 99, "LEFT CTRL": 104, "LEFT SHIFT": 105, "LEFT ALT": 106, "LEFT WINDOWS": 107, "RIGHT CTRL": 108, "RIGHT SHIFT": 109, "RIGHT ALTGR": 110, "RIGHT WINDOWS": 111, "BRIGHTNESS": 153, "PAUSE": 155, "MUTE": 156, "NEXT": 157, "PREVIOUS": 158, "G1": 180, "G2": 181, "G3": 182, "G4": 183, "G5": 184, "LOGO": 210, } ) # load in override dictionary for KEYCODES try: if os.path.isfile(_keys_file_path): with open(_keys_file_path) as keys_file: keys = yaml.safe_load(keys_file) if isinstance(keys, dict): keys = NamedInts(**keys) for k in KEYCODES: if int(k) not in keys and str(k) not in keys: keys[int(k)] = str(k) KEYCODES = keys except Exception as e: print(e) Solaar-1.1.20/lib/solaar/000077500000000000000000000000001522022367600150505ustar00rootroot00000000000000Solaar-1.1.20/lib/solaar/__init__.py000066400000000000000000000024371522022367600171670ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import pkgutil import subprocess import sys NAME = "Solaar" try: __version__ = ( subprocess.check_output( [ "git", "describe", "--always", ], cwd=sys.path[0], stderr=subprocess.DEVNULL, ) .strip() .decode() ) except Exception: try: __version__ = pkgutil.get_data("solaar", "commit").strip().decode() except Exception: __version__ = pkgutil.get_data("solaar", "version").strip().decode() Solaar-1.1.20/lib/solaar/cli/000077500000000000000000000000001522022367600156175ustar00rootroot00000000000000Solaar-1.1.20/lib/solaar/cli/__init__.py000066400000000000000000000217251522022367600177370ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import argparse import logging import sys from importlib import import_module from traceback import extract_tb from traceback import format_exc from logitech_receiver import base from logitech_receiver import device from logitech_receiver import receiver from solaar import NAME logger = logging.getLogger(__name__) def _create_parser(): parser = argparse.ArgumentParser( prog=NAME.lower(), add_help=False, epilog=f"For details on individual actions, run `{NAME.lower()} --help`.", ) subparsers = parser.add_subparsers(title="actions", help="command-line action to perform") sp = subparsers.add_parser("show", description="Show information about device or all devices.") sp.add_argument( "device", nargs="?", default="all", help="device to show information about; may be a device number (1..6), a serial number, " 'a substring of a device\'s name, or "all" (the default)', ) sp.set_defaults(action="show") sp = subparsers.add_parser("probe", description="Probe a receiver (debugging use only).") sp.add_argument( "receiver", nargs="?", help="select receiver by name substring or serial number when more than one is present" ) sp.set_defaults(action="probe") sp = subparsers.add_parser( "profiles", description="Print or load YAML dump of profiles.", epilog="Only works on active devices.", ) sp.add_argument( "device", help="device to read or load profiles; may be a device number (1..6), a serial number, " "or a substring of a device's name", ) sp.add_argument("profiles", nargs="?", help="file containing YAML dump of profiles to load") sp.set_defaults(action="profiles") sp = subparsers.add_parser( "config", description="Print or load device-specific settings. Only some settings can be loaded. " "Loading complex settings uses the same syntax as in ~/.config/solaar/config.yaml", epilog="Please note that configuration only works on active devices.", ) sp.add_argument( "device", help="device to configure; may be a device number (1..6), a serial number, or a substring of a device's name", ) sp.add_argument("setting", nargs="?", help="device-specific setting; leave empty to list available settings") sp.add_argument("value_key", nargs="?", help="new value for the setting or key for keyed settings") sp.add_argument("extra_subkey", nargs="?", help="value for keyed or subkey for subkeyed settings") sp.add_argument("extra2", nargs="?", help="value for subkeyed settings") sp.set_defaults(action="config") sp = subparsers.add_parser( "pair", description="Pair a new device with a receiver. The device has to be compatible with the receiver.", epilog="The Logitech Unifying Receiver supports up to 6 paired devices at the same time.", ) sp.add_argument( "receiver", nargs="?", help="select receiver by name substring or serial number when more than one is present" ) sp.set_defaults(action="pair") sp = subparsers.add_parser("unpair", description="Unpair a device from its receiver. Not all receivers allow unpairing.") sp.add_argument( "device", nargs="?", help="device to unpair; may be a device number (1..6), a serial number, " "or a substring of a device's name. Omit when using --slot.", ) sp.add_argument( "--receiver", help="select receiver by name substring or serial number when more than one is present; " "required with --slot if multiple receivers are attached.", ) sp.add_argument( "--slot", type=int, help="force-unpair a specific slot number directly, even if Solaar has no cached device there " "or the device is currently reachable. Lightspeed receivers only. The slot contents are " "printed before the write so you can confirm what is about to be cleared.", ) sp.add_argument( "--dry-run", action="store_true", help="with --slot, run all safety checks but do not issue the unpair register write. " "Use to verify the active-device guard before committing to a real write.", ) sp.set_defaults(action="unpair") return parser, subparsers.choices _cli_parser, actions = _create_parser() print_help = _cli_parser.print_help def _receivers(dev_path=None): for dev_info in base.receivers(): if dev_path is not None and dev_path != dev_info.path: continue try: r = receiver.create_receiver(base, dev_info) logger.debug("[%s] => %s", dev_info.path, r) if r: yield r except Exception as e: logger.exception("opening " + str(dev_info)) sys.exit(f"{NAME.lower()}: error: {str(e)}") def _receivers_and_devices(dev_path=None): for dev_info in base.receivers_and_devices(): if dev_path is not None and dev_path != dev_info.path: continue try: if dev_info.isDevice: if getattr(dev_info, "centurion", False): d = device.create_centurion_receiver(base, dev_info) if d is not None: d.notify_devices() else: d = device.create_device(base, dev_info) else: d = device.create_device(base, dev_info) else: d = receiver.create_receiver(base, dev_info) logger.debug("[%s] => %s", dev_info.path, d) if d is not None: yield d except Exception as e: logger.exception("opening " + str(dev_info)) sys.exit(f"{NAME.lower()}: error: {str(e)}") def _find_receiver(receivers, name): assert receivers assert name for r in receivers: if name in r.name.lower() or (r.serial is not None and name == r.serial.lower()): return r def _find_device(receivers, name): assert receivers assert name number = None if len(name) == 1: try: number = int(name) except Exception: pass else: assert not (number < 0) if number > 6: number = None for r in receivers: if not r.isDevice: # look for nth device of receiver if number: dev = r[number] if dev: yield dev count = r.count() else: # wired device, make a device list from it r.ping() r = [r] count = 1 for dev in r: if ( name == dev.serial.lower() or name == dev.codename.lower() or name == str(dev.kind).lower() or name in dev.name.lower() ): yield dev count -= 1 if not count: break def run(cli_args=None, hidraw_path=None): if cli_args: action = cli_args[0] args = _cli_parser.parse_args(cli_args) else: args = _cli_parser.parse_args() # Python 3 has an undocumented 'feature' that breaks parsing empty args # http://bugs.python.org/issue16308 if "cmd" not in args: _cli_parser.print_usage(sys.stderr) sys.stderr.write(f"{NAME.lower()}: error: too few arguments\n") sys.exit(2) action = args.action assert action in actions try: if action == "show" or action == "probe" or action == "config" or action == "profiles": c = list(_receivers_and_devices(hidraw_path)) else: c = list(_receivers(hidraw_path)) if not c: raise Exception( 'No supported device found. Use "lsusb" and "bluetoothctl devices Connected" to list connected devices.' ) m = import_module("." + action, package=__name__) m.run(c, args, _find_receiver, _find_device) except AssertionError: tb_last = extract_tb(sys.exc_info()[2])[-1] sys.exit(f"{NAME.lower()}: assertion failed: {tb_last[0]} line {int(tb_last[1])}") except Exception: sys.exit(f"{NAME.lower()}: error: {format_exc()}") Solaar-1.1.20/lib/solaar/cli/config.py000066400000000000000000000332701522022367600174430ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import yaml from logitech_receiver import settings from logitech_receiver import settings_templates from logitech_receiver.common import NamedInts from logitech_receiver.settings_templates import SettingsProtocol from logitech_receiver.settings_validator import Range from solaar import configuration APP_ID = "io.github.pwr_solaar.solaar" def _parse_int_or_hex(s) -> int | None: """Parse 0xRRGGBB / #RRGGBB / decimal int. Returns None on bad input.""" if not isinstance(s, str): return None s = s.strip() try: if s.startswith("#"): return int(s[1:], 16) if s.lower().startswith("0x"): return int(s, 16) return int(s, 10) except ValueError: return None def _print_setting(s, verbose=True): print("#", s.label) if verbose: if s.description: print("#", s.description.replace("\n", " ")) if s.kind == settings.Kind.TOGGLE: print("# possible values: on/true/t/yes/y/1 or off/false/f/no/n/0 or Toggle/~") elif s.kind == settings.Kind.CHOICE: print( "# possible values: one of [", ", ".join(str(v) for v in s.choices), "], or higher/lower/highest/max/lowest/min", ) else: # wtf? pass value = s.read(cached=False) if value is None: print(s.name, "= ? (failed to read from device)") else: print(s.name, "=", s.val_to_string(value)) def _print_setting_keyed(s, key, verbose=True): print("#", s.label) if verbose: if s.description: print("#", s.description.replace("\n", " ")) if s.kind == settings.Kind.MULTIPLE_TOGGLE: k = next((k for k in s._labels if key == k), None) if k is None: print(s.name, "=? (key not found)") else: print("# possible values: on/true/t/yes/y/1 or off/false/f/no/n/0 or Toggle/~") value = s.read(cached=False) if value is None: print(s.name, "= ? (failed to read from device)") else: print(s.name, s.val_to_string({k: value[str(int(k))]})) elif s.kind == settings.Kind.MAP_CHOICE: k = next((k for k in s.choices.keys() if key == k), None) if k is None: print(s.name, "=? (key not found)") else: value_space = s.choices[k] if isinstance(value_space, Range): print(f"# possible values: integer in [{value_space.min}, {value_space.max}] (decimal or 0xHEX)") else: print("# possible values: one of [", ", ".join(str(v) for v in value_space), "]") value = s.read(cached=False) if value is None: print(s.name, "= ? (failed to read from device)") else: print(s.name, s.val_to_string({k: value[int(k)]})) def to_int(s): try: return int(s) except ValueError: return None def select_choice(value, choices, setting, key): lvalue = value.lower() ivalue = to_int(value) val = None for choice in choices: if value == str(choice): val = choice break if val is not None: value = val elif ivalue is not None and 1 <= ivalue <= len(choices): value = choices[ivalue - 1] elif lvalue in ("higher", "lower"): old_value = setting.read() if key is None else setting.read_key(key) if old_value is None: raise Exception(f"{setting.name}: could not read current value") if lvalue == "lower": lower_values = choices[:old_value] value = lower_values[-1] if lower_values else choices[:][0] elif lvalue == "higher": higher_values = choices[old_value + 1 :] value = higher_values[0] if higher_values else choices[:][-1] elif lvalue in ("highest", "max", "first"): value = choices[:][-1] elif lvalue in ("lowest", "min", "last"): value = choices[:][0] else: raise Exception(f"{setting.name}: possible values are [{', '.join(str(v) for v in choices)}]") return value def select_toggle(value, setting, key=None): if value.lower() in ("toggle", "~"): value = not (setting.read() if key is None else setting.read()[str(int(key))]) else: try: value = bool(int(value)) except Exception as exc: if value.lower() in ("true", "yes", "on", "t", "y"): value = True elif value.lower() in ("false", "no", "off", "f", "n"): value = False else: raise Exception(f"{setting.name}: don't know how to interpret '{value}' as boolean") from exc return value def select_range(value, setting): try: value = int(value) except ValueError as exc: raise Exception(f"{setting.name}: can't interpret '{value}' as integer") from exc minimum, maximum = setting.range if value < minimum or value > maximum: raise Exception(f"{setting.name}: value '{value}' out of bounds") return value def run(receivers, args, _find_receiver, find_device): assert receivers assert args.device device_name = args.device.lower() dev = None for dev in find_device(receivers, device_name): if dev.ping(): break dev = None if not dev: raise Exception(f"no online device found matching '{device_name}'") if not args.setting: # print all settings, so first set them all up if not dev.settings: raise Exception(f"no settings for {dev.name}") configuration.attach_to(dev) print(dev.name, f"({dev.codename}) [{dev.wpid}:{dev.serial}]") for s in dev.settings: print("") _print_setting(s) return setting_name = args.setting.lower() setting = settings_templates.check_feature_setting(dev, setting_name) if not setting and dev.descriptor and dev.descriptor.settings: for sclass in dev.descriptor.settings: if sclass.register and sclass.name == setting_name: try: setting = sclass.build(dev) except Exception: setting = None if setting is None: raise Exception(f"no setting '{args.setting}' for {dev.name}") if args.value_key is None: _print_setting(setting) return remote = False try: import gi gi.require_version("Gtk", "3.0") from gi.repository import Gio from gi.repository import Gtk if Gtk.init_check()[0]: # can Gtk be initialized? application = Gtk.Application.new(APP_ID, Gio.ApplicationFlags.HANDLES_COMMAND_LINE) application.register() remote = application.get_is_remote() except Exception: pass # don't save configuration here because we might want the Solaar GUI to make the change result, message, value = set(dev, setting, args, False) if message is not None: print(message) if result is None: raise Exception(f"{setting.name}: failed to set value '{str(value)}' [{value!r}]") # if the Solaar UI is running tell it to also perform the set, otherwise save the change in the configuration file if remote: argl = ["config", dev.serial or dev.unitId, setting.name] argl.extend([a for a in [args.value_key, args.extra_subkey, args.extra2] if a is not None]) args = yaml.dump(argl) application.run([args]) else: if dev.persister and setting.persist: dev.persister[setting.name] = setting._value def set(dev, setting: SettingsProtocol, args, save): if setting.kind == settings.Kind.TOGGLE: value = select_toggle(args.value_key, setting) args.value_key = value message = f"Setting {setting.name} of {dev.name} to {value}" result = setting.write(value, save=save) elif setting.kind == settings.Kind.RANGE: value = select_range(args.value_key, setting) args.value_key = value message = f"Setting {setting.name} of {dev.name} to {value}" result = setting.write(value, save=save) elif setting.kind == settings.Kind.CHOICE: value = select_choice(args.value_key, setting.choices, setting, None) args.value_key = int(value) message = f"Setting {setting.name} of {dev.name} to {value}" result = setting.write(value, save=save) elif setting.kind == settings.Kind.MAP_CHOICE: if args.extra_subkey is None: _print_setting_keyed(setting, args.value_key) return None, None, None key = args.value_key ikey = to_int(key) k = next((k for k in setting.choices.keys() if key == k), None) if k is None and ikey is not None: k = next((k for k in setting.choices.keys() if ikey == k), None) if k is None: raise Exception(f"{setting.name}: key '{key}' not in setting") value_space = setting.choices[k] if isinstance(value_space, Range): ivalue = _parse_int_or_hex(args.extra_subkey) if ivalue is None or not value_space.contains(ivalue): raise Exception( f"{setting.name}: value '{args.extra_subkey}' must be an integer in " f"[{value_space.min}, {value_space.max}] (decimal or 0xHEX / #HEX)" ) value = ivalue else: value = select_choice(args.extra_subkey, value_space, setting, key) args.extra_subkey = int(value) args.value_key = str(int(k)) message = f"Setting {setting.name} of {dev.name} key {k!r} to {value!r}" result = setting.write_key_value(int(k), value, save=save) elif setting.kind == settings.Kind.MULTIPLE_TOGGLE: if args.extra_subkey is None: _print_setting_keyed(setting, args.value_key) return None, None, None key = args.value_key all_keys = getattr(setting, "choices_universe", None) ikey = all_keys[int(key) if key.isdigit() else key] if isinstance(all_keys, NamedInts) else to_int(key) k = next((k for k in setting._labels if key == k), None) if k is None and ikey is not None: k = next((k for k in setting._labels if ikey == k), None) if k is not None: value = select_toggle(args.extra_subkey, setting, key=k) args.extra_subkey = value args.value_key = str(int(k)) else: raise Exception(f"{setting.name}: key '{key}' not in setting") message = f"Setting {setting.name} key {k!r} to {value!r}" result = setting.write_key_value(str(int(k)), value, save=save) elif setting.kind == settings.Kind.MULTIPLE_RANGE: if args.extra_subkey is None: raise Exception(f"{setting.name}: setting needs both key and value to set") key = args.value_key all_keys = getattr(setting, "choices_universe", None) ikey = all_keys[int(key) if key.isdigit() else key] if isinstance(all_keys, NamedInts) else to_int(key) if args.extra2 is None or to_int(args.extra2) is None: raise Exception(f"{setting.name}: setting needs an integer value, not {args.extra2}") if not setting._value: # ensure that there are values to look through setting.read() k = next((k for k in setting._value if key == ikey or key.isdigit() and ikey == int(key)), None) if k is None and ikey is not None: k = next((k for k in setting._value if ikey == k), None) item = setting._value[k] if args.extra_subkey in item.keys(): item[args.extra_subkey] = to_int(args.extra2) args.value_key = str(int(k)) else: raise Exception(f"{setting.name}: key '{key}' not in setting") message = f"Setting {setting.name} key {k} parameter {args.extra_subkey} to {item[args.extra_subkey]!r}" result = setting.write_key_value(int(k), item, save=save) value = item elif setting.kind == settings.Kind.MAP_RANGE: if args.extra_subkey is None: _print_setting_keyed(setting, args.value_key) return None, None, None key = int(args.value_key) value = int(args.extra_subkey) if key not in setting._device_object: raise Exception(f"{setting.name}: key '{key}' not in setting") message = f"Setting {setting.name} of {dev.name} key {key} to {value}" result = setting.write_key_value(key, value, save=save) elif setting.kind == settings.Kind.HETERO: value = yaml.safe_load(args.value_key) args.value_key = value message = f"Setting {setting.name} of {dev.name} to {value}" result = setting.write(value, save=save) else: print(f"Setting {setting.name}, with kind {setting.kind.name}, not implemented") raise Exception("NotImplemented") return result, message, value Solaar-1.1.20/lib/solaar/cli/pair.py000066400000000000000000000147401522022367600171320ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from time import time from logitech_receiver import base from logitech_receiver import hidpp10 from logitech_receiver import hidpp10_constants from logitech_receiver import notifications _hidpp10 = hidpp10.Hidpp10() def run(receivers, args, find_receiver, _ignore): assert receivers if args.receiver: receiver_name = args.receiver.lower() receiver = find_receiver(receivers, receiver_name) if not receiver: raise Exception(f"no receiver found matching '{receiver_name}'") else: receiver = receivers[0] assert receiver # check if it's necessary to set the notification flags old_notification_flags = _hidpp10.get_notification_flags(receiver) if not (old_notification_flags & hidpp10_constants.NotificationFlag.WIRELESS): _hidpp10.set_notification_flags(receiver, old_notification_flags | hidpp10_constants.NotificationFlag.WIRELESS) # get all current devices known_devices = [dev.number for dev in receiver] class _HandleWithNotificationHook(int): def notifications_hook(self, n): nonlocal known_devices assert n if n.devnumber == 0xFF: notifications.process(receiver, n) elif n.sub_id == 0x41 and len(n.data) == base.SHORT_MESSAGE_SIZE - 4: kd, known_devices = known_devices, None # only process one connection notification if kd is not None: if n.devnumber not in kd: receiver.pairing.new_device = receiver.register_new_device(n.devnumber, n) elif receiver.re_pairs: del receiver[n.devnumber] # get rid of information on device re-paired away receiver.pairing.new_device = receiver.register_new_device(n.devnumber, n) timeout = 30 # seconds receiver.handle = _HandleWithNotificationHook(receiver.handle) if receiver.receiver_kind == "bolt": # Bolt receivers require authentication to pair a device receiver.discover(timeout=timeout) print("Bolt Pairing: long-press the pairing key or button on your device (timing out in", timeout, "seconds).") pairing_start = time() patience = 5 # the discovering notification may come slightly later, so be patient while receiver.pairing.discovering or time() - pairing_start < patience: if receiver.pairing.device_address and receiver.pairing.device_authentication and receiver.pairing.device_name: break n = base.read(receiver.handle) n = base.make_notification(*n) if n else None if n: receiver.handle.notifications_hook(n) address = receiver.pairing.device_address name = receiver.pairing.device_name authentication = receiver.pairing.device_authentication kind = receiver.pairing.device_kind if authentication is None: # no compatible device stepped forward print("No Bolt-compatible device requested pairing.") else: print(f"Bolt Pairing: discovered {name}") receiver.pair_device( address=address, authentication=authentication, entropy=20 if kind == hidpp10_constants.DEVICE_KIND.keyboard else 10, ) pairing_start = time() patience = 5 # the discovering notification may come slightly later, so be patient while receiver.pairing.lock_open or time() - pairing_start < patience: if receiver.pairing.device_passkey: break n = base.read(receiver.handle) n = base.make_notification(*n) if n else None if n: receiver.handle.notifications_hook(n) if authentication & 0x01: print(f"Bolt Pairing: type passkey {receiver.pairing.device_passkey} and then press the enter key") else: passkey = f"{int(receiver.pairing.device_passkey):010b}" passkey = ", ".join(["right" if bit == "1" else "left" for bit in passkey]) print(f"Bolt Pairing: press {passkey}") print("and then press left and right buttons simultaneously") while receiver.pairing.lock_open: n = base.read(receiver.handle) n = base.make_notification(*n) if n else None if n: receiver.handle.notifications_hook(n) else: receiver.set_lock(False, timeout=timeout) print("Pairing: Turn your device on or press, hold, and release") print("a channel button or the channel switch button.") print("Timing out in", timeout, "seconds.") pairing_start = time() patience = 5 # the lock-open notification may come slightly later, wait for it a bit while receiver.pairing.lock_open or time() - pairing_start < patience: n = base.read(receiver.handle) if n: n = base.make_notification(*n) if n: receiver.handle.notifications_hook(n) if not (old_notification_flags & hidpp10_constants.NotificationFlag.WIRELESS): # only clear the flags if they weren't set before, otherwise a # concurrently running Solaar app might stop working properly _hidpp10.set_notification_flags(receiver, old_notification_flags) if receiver.pairing.new_device: dev = receiver.pairing.new_device print(f"Paired device {int(dev.number)}: {dev.name} ({dev.codename}) [{dev.wpid}:{dev.serial}]") else: error = receiver.pairing.error if error: raise Exception(f"pairing failed: {error}") else: print("Paired device") # this is better than an error Solaar-1.1.20/lib/solaar/cli/probe.py000066400000000000000000000111731522022367600173030ustar00rootroot00000000000000## Copyright (C) 2020 ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from logitech_receiver import base from logitech_receiver.common import strhex from logitech_receiver.hidpp10_constants import ErrorCode from logitech_receiver.hidpp10_constants import Registers from solaar.cli.show import _print_device from solaar.cli.show import _print_receiver def run(receivers, args, find_receiver, _ignore): assert receivers if args.receiver: receiver_name = args.receiver.lower() receiver = find_receiver(receivers, receiver_name) if not receiver: raise Exception(f"no receiver found matching '{receiver_name}'") else: receiver = receivers[0] assert receiver is not None if receiver.isDevice: _print_device(receiver, 1) return _print_receiver(receiver) print("") print(" Register Dump") rgst = receiver.read_register(Registers.NOTIFICATIONS) print(" Notifications %#04x: %s" % (Registers.NOTIFICATIONS % 0x100, f"0x{strhex(rgst)}" if rgst else "None")) rgst = receiver.read_register(Registers.RECEIVER_CONNECTION) print( " Connection State %#04x: %s" % (Registers.RECEIVER_CONNECTION % 0x100, f"0x{strhex(rgst)}" if rgst else "None") ) rgst = receiver.read_register(Registers.DEVICES_ACTIVITY) print( " Device Activity %#04x: %s" % (Registers.DEVICES_ACTIVITY % 0x100, f"0x{strhex(rgst)}" if rgst else "None") ) for sub_reg in range(0, 16): rgst = receiver.read_register(Registers.RECEIVER_INFO, sub_reg) print( " Pairing Register %#04x %#04x: %s" % (Registers.RECEIVER_INFO % 0x100, sub_reg, f"0x{strhex(rgst)}" if rgst else "None") ) for device in range(0, 7): for sub_reg in [0x10, 0x20, 0x30, 0x50]: rgst = receiver.read_register(Registers.RECEIVER_INFO, sub_reg + device) print( " Pairing Register %#04x %#04x: %s" % (Registers.RECEIVER_INFO % 0x100, sub_reg + device, f"0x{strhex(rgst)}" if rgst else "None") ) rgst = receiver.read_register(Registers.RECEIVER_INFO, 0x40 + device) print( " Pairing Name %#04x %#02x: %s" % (Registers.RECEIVER_INFO % 0x100, 0x40 + device, rgst[2 : 2 + ord(rgst[1:2])] if rgst else "None") ) for part in range(1, 4): rgst = receiver.read_register(Registers.RECEIVER_INFO, 0x60 + device, part) print( " Pairing Name %#04x %#02x %#02x: %2d %s" % ( Registers.RECEIVER_INFO % 0x100, 0x60 + device, part, ord(rgst[2:3]) if rgst else 0, rgst[3 : 3 + ord(rgst[2:3])] if rgst else "None", ) ) for sub_reg in range(0, 5): rgst = receiver.read_register(Registers.FIRMWARE, sub_reg) print( " Firmware %#04x %#04x: %s" % (Registers.FIRMWARE % 0x100, sub_reg, f"0x{strhex(rgst)}" if rgst is not None else "None") ) print("") for reg in range(0, 0xFF): for offset, reg_type in [(0x00, "Short"), (0x200, "Long")]: last = None for sub in range(0, 0xFF): rgst = base.request(receiver.handle, 0xFF, 0x8100 | (offset + reg), sub, return_error=True) if isinstance(rgst, int) and rgst == ErrorCode.INVALID_ADDRESS: break elif isinstance(rgst, int) and rgst == ErrorCode.INVALID_VALUE: continue else: if not isinstance(last, bytes) or not isinstance(rgst, bytes) or last != rgst: print( " Register %s %#04x %#04x: %s" % (reg_type, reg, sub, "0x" + strhex(rgst) if isinstance(rgst, bytes) else str(rgst)) ) last = rgst Solaar-1.1.20/lib/solaar/cli/profiles.py000066400000000000000000000052141522022367600200160ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import traceback import yaml from logitech_receiver.hidpp20 import OnboardProfiles from logitech_receiver.hidpp20 import OnboardProfilesVersion def run(receivers, args, find_receiver, find_device): assert receivers assert args.device device_name = args.device.lower() profiles_file = args.profiles dev = None for dev in find_device(receivers, device_name): if dev.ping(): break dev = None if not dev: raise Exception(f"no online device found matching '{device_name}'") if not dev.online: print(f"Device {dev.name} is offline.") elif not dev.profiles: print(f"Device {dev.name} has no onboard profiles that Solaar supports.") elif not profiles_file: print(f"#Dumping profiles from {dev.name}") print(yaml.dump(dev.profiles)) else: try: with open(profiles_file, "r") as f: print(f"Reading profiles from {profiles_file}") profiles = yaml.safe_load(f) if not isinstance(profiles, OnboardProfiles): print("Profiles file does not contain current onboard profiles") elif getattr(profiles, "version", None) != OnboardProfilesVersion: version = getattr(profiles, "version", None) print(f"Missing or incorrect profile version {version} in loaded profile") elif getattr(profiles, "name", None) != dev.name: name = getattr(profiles, "name", None) print(f"Different device name {name} in loaded profile") else: print(f"Loading profiles into {dev.name}") written = profiles.write(dev) print(f"Wrote {written} sectors to {dev.name}") except Exception as exc: print("Profiles not written:", exc) print(traceback.format_exc()) Solaar-1.1.20/lib/solaar/cli/show.py000066400000000000000000000606301522022367600171560ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from logitech_receiver import common from logitech_receiver import exceptions from logitech_receiver import hidpp10 from logitech_receiver import hidpp10_constants from logitech_receiver import hidpp20 from logitech_receiver import hidpp20_constants from logitech_receiver import receiver from logitech_receiver import settings_templates from logitech_receiver.common import LOGITECH_VENDOR_ID from logitech_receiver.common import NamedInt from logitech_receiver.common import strhex from logitech_receiver.device import CenturionReceiver from logitech_receiver.hidpp20_constants import SupportedFeature from solaar import NAME from solaar import __version__ _hidpp10 = hidpp10.Hidpp10() _hidpp20 = hidpp20.Hidpp20() def _print_receiver(receiver): is_centurion = isinstance(receiver, CenturionReceiver) paired_count = receiver.count() print(receiver.name) print(" Device path :", receiver.path) print(f" USB id : {LOGITECH_VENDOR_ID:04x}:{receiver.product_id}") if is_centurion: print(" Protocol : Centurion") if receiver.serial: print(" Serial :", receiver.serial) if not is_centurion: pending = hidpp10.get_configuration_pending_flags(receiver) if pending: print(f" C Pending : {pending:02x}") if receiver.firmware: for f in receiver.firmware: print(" %-11s: %s" % (f.kind, f.version)) if is_centurion: print(" Has", paired_count, f"device(s) out of a maximum of {int(receiver.max_devices)}.") else: print(" Has", paired_count, f"paired device(s) out of a maximum of {int(receiver.max_devices)}.") if receiver.remaining_pairings() and receiver.remaining_pairings() >= 0: print(f" Has {int(receiver.remaining_pairings())} successful pairing(s) remaining.") if is_centurion: _print_centurion_dongle_features(receiver) else: notification_flags = _hidpp10.get_notification_flags(receiver) if notification_flags is not None: if notification_flags: notification_names = hidpp10_constants.NotificationFlag.flag_names(notification_flags) print(f" Notifications: {', '.join(notification_names)} (0x{notification_flags.value:06X})") else: print(" Notifications: (none)") activity = receiver.read_register(hidpp10_constants.Registers.DEVICES_ACTIVITY) if activity: activity = [(d, ord(activity[d - 1 : d])) for d in range(1, receiver.max_devices)] activity_text = ", ".join(f"{int(d)}={int(a)}" for d, a in activity if a > 0) print(" Device activity counters:", activity_text or "(empty)") def _print_centurion_dongle_features(receiver): """Print dongle-level features, probed independently on the dongle hardware.""" features = receiver.dongle_features if not features: return print(f" Supports {len(features)} dongle features:") for feature, feat_id, index in features: display_name = "CENTPP BRIDGE" if feat_id == 0x0003 else feature feat_bytes = feat_id.to_bytes(2, byteorder="big") try: flags_resp = receiver.request(0x0000, feat_bytes[0], feat_bytes[1]) except Exception: flags_resp = None if flags_resp is not None and len(flags_resp) >= 2: flags = flags_resp[1] flag_names = common.flag_names(hidpp20_constants.FeatureFlag, flags) print(" %2d: %-22s {%04X} %s " % (index, display_name, feat_id, ", ".join(flag_names))) else: print(" %2d: %-22s {%04X}" % (index, display_name, feat_id)) if feature == SupportedFeature.CENTURION_DEVICE_INFO: fw_list = _hidpp20.get_firmware_centurion(receiver) serial = _hidpp20.get_serial_centurion(receiver) hw_info = _hidpp20.get_hardware_info_centurion(receiver) if fw_list: for fw in fw_list: print(f" Firmware: {(str(fw.kind) + ' ' + fw.name).strip()} {fw.version}") if serial and serial.strip() and serial.strip().isprintable(): print(f" Serial: {serial}") if hw_info: model_id, hw_rev, product_id = hw_info print(f" Hardware: model {model_id}" f" rev {hw_rev} product {product_id:04X}") _LED_CAPS_BITS = ((0x0001, "color"), (0x0002, "fade"), (0x0004, "period"), (0x0010, "direction"), (0xC000, "fw")) def _decode_led_caps(caps): names = [name for mask, name in _LED_CAPS_BITS if caps & mask] other = caps & ~sum(m for m, _ in _LED_CAPS_BITS) if other: names.append(f"+{other:#06x}") return f"0x{caps:04x}=" + ("+".join(names) if names else "none") def _battery_text(level) -> str: if level is None: return "N/A" elif isinstance(level, NamedInt): return str(level) else: return f"{int(level)}%" def _battery_line(dev): battery = dev.battery() if battery is not None: level, nextLevel, status, voltage = battery.level, battery.next_level, battery.status, battery.voltage text = _battery_text(level) if voltage is not None: text = f"{text} {voltage}mV " nextText = "" if nextLevel is None else f", next level {_battery_text(nextLevel)}" print(f" Battery: {text}, {status}{nextText}.") else: print(" Battery status unavailable.") def _print_device(dev, num=None): assert dev is not None is_centurion = getattr(dev, "centurion", False) is_centurion_child = is_centurion and isinstance(getattr(dev, "receiver", None), CenturionReceiver) # try to ping the device to see if it actually exists and to wake it up try: online = dev.ping() except exceptions.NoSuchDevice: print(f" {num}: Device not found" or dev.number) return if num or dev.number < 8: print(f" {int(num or dev.number)}: {dev.name}") else: print(f"{dev.name}") if not online: print(" Device is offline.") return # Centurion child has no separate hidraw path — show receiver's path device_path = dev.path or (dev.receiver.path if is_centurion_child else None) print(" Device path :", device_path) if dev.wpid and not is_centurion_child: print(f" WPID : {dev.wpid}") if dev.product_id: print(f" USB id : {LOGITECH_VENDOR_ID:04x}:{dev.product_id}") print(" Codename :", dev.codename) print(" Kind :", dev.kind) if dev.protocol: proto_name = "Centurion" if is_centurion else "HID++" cent_proto = getattr(dev, "_centurion_protocol", None) if cent_proto: print(f" Protocol : {proto_name} {cent_proto[0]}.{cent_proto[1]}") else: print(f" Protocol : {proto_name} {dev.protocol:1.1f}") else: print(" Protocol : unknown (device is offline)") if not is_centurion and dev.polling_rate: print(" Report Rate :", dev.polling_rate) print(" Serial number:", dev.serial) if dev.modelId: print(" Model ID: ", dev.modelId) if dev.unitId: print(" Unit ID: ", dev.unitId) if dev.firmware: for fw in dev.firmware: print(f" {fw.kind:11}:", (fw.name + " " + fw.version).strip()) if dev.power_switch_location: print(f" The power switch is located on the {dev.power_switch_location}.") # Skip HID++ 1.0 register reads for centurion devices — they don't support these if dev.online and not is_centurion: notification_flags = _hidpp10.get_notification_flags(dev) if notification_flags is not None: if notification_flags: notification_names = hidpp10_constants.NotificationFlag.flag_names(notification_flags) print(f" Notifications: {', '.join(notification_names)} (0x{notification_flags.value:06X}).") else: print(" Notifications: (none).") device_features = _hidpp10.get_device_features(dev) if device_features is not None: if device_features: device_features_names = hidpp10_constants.DeviceFeature.flag_names(device_features) print(f" Features: {', '.join(device_features_names)} (0x{device_features:06X})") else: print(" Features: (none)") if dev.online and dev.features: is_centurion = getattr(dev, "centurion", False) parent_count = dev.features.count sub_count = getattr(dev.features, "_sub_feature_count", 0) # For centurion child devices, dongle features are shown on the receiver — # only show sub-device (headset) features here. if is_centurion_child and sub_count > 0: print(f" Supports {sub_count} HID++ 2.0 features:") elif is_centurion and sub_count > 0: print(f" Supports {parent_count} dongle + {sub_count} headset features:") else: print(f" Supports {len(dev.features)} HID++ 2.0 features:") dev_settings = [] settings_templates.check_feature_settings(dev, dev_settings) feature_num = 0 in_sub_device = False for feature, index in dev.features.enumerate(): if is_centurion and not in_sub_device and feature_num >= parent_count: in_sub_device = True if not is_centurion_child: print(" Headset (via CentPPBridge):") feature_num += 1 # For centurion child, skip dongle features (already shown on the receiver) if is_centurion_child and not in_sub_device: continue if isinstance(feature, str): feature_bytes = bytes.fromhex(feature[-4:]) else: feature_bytes = feature.to_bytes(2, byteorder="little") feature_int = int.from_bytes(feature_bytes, byteorder="little") display_name = feature if is_centurion_child and in_sub_device: # Use cached version — skip slow bridge ROOT queries version = dev.features.get_feature_version(feature_int) or 0 print(" %2d: %-22s {%04X} V%s" % (index, display_name, feature_int, version)) else: try: flags = dev.request(0x0000, feature_bytes) except Exception: flags = None if flags is not None: flags = ord(flags[1:2]) flag_names = common.flag_names(hidpp20_constants.FeatureFlag, flags) version = dev.features.get_feature_version(feature_int) version = version if version else 0 print( " %2d: %-22s {%04X} V%s %s " % (index, display_name, feature_int, version, ", ".join(flag_names)) ) else: print(" %2d: %-22s {%04X}" % (index, display_name, feature_int)) if feature == SupportedFeature.HIRES_WHEEL: wheel = _hidpp20.get_hires_wheel(dev) if wheel: multi, has_invert, has_switch, inv, res, target, ratchet = wheel print(f" Multiplier: {multi}") if has_invert: print(" Has invert:", "Inverse wheel motion" if inv else "Normal wheel motion") if has_switch: print(" Has ratchet switch:", "Normal wheel mode" if ratchet else "Free wheel mode") if res: print(" High resolution mode") else: print(" Low resolution mode") if target: print(" HID++ notification") else: print(" HID notification") elif feature == SupportedFeature.MOUSE_POINTER: mouse_pointer = _hidpp20.get_mouse_pointer_info(dev) if mouse_pointer: print(f" DPI: {mouse_pointer['dpi']}") print(f" Acceleration: {mouse_pointer['acceleration']}") if mouse_pointer["suggest_os_ballistics"]: print(" Use OS ballistics") else: print(" Override OS ballistics") if mouse_pointer["suggest_vertical_orientation"]: print(" Provide vertical tuning, trackball") else: print(" No vertical tuning, standard mice") elif feature == SupportedFeature.VERTICAL_SCROLLING: vertical_scrolling_info = _hidpp20.get_vertical_scrolling_info(dev) if vertical_scrolling_info: print(f" Roller type: {vertical_scrolling_info['roller']}") print(f" Ratchet per turn: {vertical_scrolling_info['ratchet']}") print(f" Scroll lines: {vertical_scrolling_info['lines']}") elif feature == SupportedFeature.HI_RES_SCROLLING: scrolling_mode, scrolling_resolution = _hidpp20.get_hi_res_scrolling_info(dev) if scrolling_mode: print(" Hi-res scrolling enabled") else: print(" Hi-res scrolling disabled") if scrolling_resolution: print(f" Hi-res scrolling multiplier: {scrolling_resolution}") elif feature == SupportedFeature.POINTER_SPEED: pointer_speed = _hidpp20.get_pointer_speed_info(dev) if pointer_speed: print(f" Pointer Speed: {pointer_speed}") elif feature == SupportedFeature.LOWRES_WHEEL: wheel_status = _hidpp20.get_lowres_wheel_status(dev) if wheel_status: print(f" Wheel Reports: {wheel_status}") elif feature == SupportedFeature.NEW_FN_INVERSION: inversion = _hidpp20.get_new_fn_inversion(dev) if inversion: inverted, default_inverted = inversion print(" Fn-swap:", "enabled" if inverted else "disabled") print(" Fn-swap default:", "enabled" if default_inverted else "disabled") elif feature == SupportedFeature.HOSTS_INFO: host_names = _hidpp20.get_host_names(dev) for host, (paired, name) in host_names.items(): print(f" Host {host} ({'paired' if paired else 'unpaired'}): {name}") elif feature == SupportedFeature.DEVICE_NAME: print(f" Name: {_hidpp20.get_name(dev)}") print(f" Kind: {_hidpp20.get_kind(dev)}") elif feature == SupportedFeature.DEVICE_FRIENDLY_NAME: print(f" Friendly Name: {_hidpp20.get_friendly_name(dev)}") elif feature == SupportedFeature.CENTURION_DEVICE_INFO: if in_sub_device: # Use cached device properties to avoid redundant bridge requests fw_list = dev.firmware serial = dev.serial hw_info = _hidpp20.get_hardware_info_centurion_sub(dev) else: fw_list = _hidpp20.get_firmware_centurion(dev) serial = _hidpp20.get_serial_centurion(dev) hw_info = _hidpp20.get_hardware_info_centurion(dev) if fw_list: for fw in fw_list: print(f" Firmware: {(str(fw.kind) + ' ' + fw.name).strip()} {fw.version}") if serial and serial.strip() and serial.strip().isprintable(): print(f" Serial: {serial}") if hw_info: model_id, hw_rev, product_id = hw_info print(f" Hardware: model {model_id}" f" rev {hw_rev} product {product_id:04X}") elif isinstance(feature, SupportedFeature) and feature == SupportedFeature.DEVICE_FW_VERSION: for fw in _hidpp20.get_firmware(dev): extras = strhex(fw.extras) if fw.extras else "" print(f" Firmware: {fw.kind} {fw.name} {fw.version} {extras}") ids = _hidpp20.get_ids(dev) if ids: unitId, modelId, tid_map = ids print(f" Unit ID: {unitId} Model ID: {modelId} Transport IDs: {tid_map}") elif feature == SupportedFeature.REPORT_RATE or feature == SupportedFeature.EXTENDED_ADJUSTABLE_REPORT_RATE: print(f" Report Rate: {_hidpp20.get_polling_rate(dev)}") elif feature == SupportedFeature.CONFIG_CHANGE: response = dev.feature_request(SupportedFeature.CONFIG_CHANGE, 0x00) print(f" Configuration: {response.hex()}") elif feature == SupportedFeature.REMAINING_PAIRING: print(f" Remaining Pairings: {int(_hidpp20.get_remaining_pairing(dev))}") elif feature == SupportedFeature.ONBOARD_PROFILES: if _hidpp20.get_onboard_mode(dev) == hidpp20_constants.OnboardMode.MODE_HOST: mode = "Host" else: mode = "On-Board" print(f" Device Mode: {mode}") elif feature == SupportedFeature.HEADSET_ONBOARD_EQ: bands = hidpp20.get_onboard_eq_params(dev) if bands: print(f" EQ: {', '.join(f'{f}Hz:{g:+d}dB' for f, g, _q in bands)}") elif feature == SupportedFeature.RGB_EFFECTS or feature == SupportedFeature.COLOR_LED_EFFECTS: try: infos = dev.led_effects except Exception as e: print(f" Effect enumeration failed: {e}") infos = None if infos and infos.zones: for zone in infos.zones: print(f" Zone {int(zone.index)} ({zone.location}): {len(zone.effects)} effect(s)") for e in zone.effects: entry = hidpp20.LEDEffects.get(e.ID) name = entry[0].name if entry else f"Unknown(0x{e.ID:02x})" caps = _decode_led_caps(e.capabilities) params = ", ".join(str(p) for p in entry[1]) if entry and entry[1] else "—" print( f" [{e.index}] 0x{e.ID:02x} {name:<14} " f"caps {caps:<28} default {e.period}ms params: {params}" ) elif hidpp20.battery_functions.get(feature, None): print("", end=" ") _battery_line(dev) for setting in dev_settings: if setting.feature == feature: if ( setting._device and getattr(setting._device, "persister", None) and setting._device.persister.get(setting.name) is not None ): v = setting.val_to_string(setting._device.persister.get(setting.name)) print(f" {setting.label} (saved): {v}") # Settings whose value cannot be read back from the device # (e.g. PerKeyLighting — 0x8081 has no GetIndividualRgbZones) # suppress the live-read line; the saved line above is the # authoritative record. See Setting.live_readable. if getattr(setting, "live_readable", True): try: v = setting.read(False) v = setting.val_to_string(v) except exceptions.FeatureCallError as e: v = "HID++ error " + str(e) except AssertionError as e: v = "AssertionError " + str(e) print(f" {setting.label} : {v}") if dev.online and dev.keys: print(f" Has {len(dev.keys)} reprogrammable keys:") for k in dev.keys: # TODO: add here additional variants for other REPROG_CONTROLS if dev.keys.keyversion == SupportedFeature.REPROG_CONTROLS_V2: print(" %2d: %-26s => %-27s %s" % (k.index, k.key, k.default_task, ", ".join(k.flags))) if dev.keys.keyversion == SupportedFeature.REPROG_CONTROLS_V4: print(" %2d: %-26s, default: %-27s => %-26s" % (k.index, k.key, k.default_task, k.mapped_to)) gmask_fmt = ",".join(k.group_mask) gmask_fmt = gmask_fmt if gmask_fmt else "empty" flag_names = list(common.flag_names(hidpp20.KeyFlag, k.flags.value)) print( f" {', '.join(flag_names)}, pos:{int(k.pos)}, group:{int(k.group):1}, group mask:{gmask_fmt}" ) report_fmt = list(common.flag_names(hidpp20.MappingFlag, k.mapping_flags.value)) report_fmt = report_fmt if report_fmt else "default" print(f" reporting: {report_fmt}") if dev.online and dev.remap_keys: print(f" Has {len(dev.remap_keys)} persistent remappable keys:") for k in dev.remap_keys: print(" %2d: %-26s => %s%s" % (k.index, k.key, k.action, " (remapped)" if k.cidStatus else "")) if dev.online and dev.gestures: print( " Has %d gesture(s), %d param(s) and %d spec(s):" % (len(dev.gestures.gestures), len(dev.gestures.params), len(dev.gestures.specs)) ) for k in dev.gestures.gestures.values(): print( " %-26s Enabled(%4s): %-5s Diverted:(%4s) %s" % (k.gesture, k.index, k.enabled(), k.diversion_index, k.diverted()) ) for k in dev.gestures.params.values(): print(" %-26s Value (%4s): %s [Default: %s]" % (k.param, k.index, k.value, k.default_value)) for k in dev.gestures.specs.values(): print(" %-26s Spec (%4s): %s" % (k.spec, k.id, k.value)) if dev.online: _battery_line(dev) else: print(" Battery: unknown (device is offline).") def run(devices, args, find_receiver, find_device): assert devices assert args.device print(f"{NAME.lower()} version {__version__}") print("") device_name = args.device.lower() if device_name == "all": for d in devices: if isinstance(d, (receiver.Receiver, CenturionReceiver)): _print_receiver(d) count = d.count() if count: for dev in d: print("") _print_device(dev, dev.number) count -= 1 if not count: break print("") else: _print_device(d) print("") return dev = find_receiver(devices, device_name) if dev and not dev.isDevice: _print_receiver(dev) return dev = next(find_device(devices, device_name), None) if not dev: raise Exception(f"no device found matching '{device_name}'") _print_device(dev) Solaar-1.1.20/lib/solaar/cli/unpair.py000066400000000000000000000071121522022367600174700ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. def run(receivers, args, find_receiver, find_device): assert receivers if getattr(args, "slot", None) is not None: _run_slot_unpair(receivers, args, find_receiver) return assert args.device, "unpair requires a device name, or use --slot" device_name = args.device.lower() dev = next(find_device(receivers, device_name), None) if not dev: raise Exception(f"no device found matching '{device_name}'") if not dev.receiver.may_unpair: print( f"Receiver with USB id {dev.receiver.product_id} for {dev.name} [{dev.wpid}:{dev.serial}] does not unpair,", "but attempting anyway.", ) try: # query these now, it's last chance to get them number, codename, wpid, serial = dev.number, dev.codename, dev.wpid, dev.serial dev.receiver._unpair_device(number, True) # force an unpair print(f"Unpaired {int(number)}: {dev.name} ({codename}) [{wpid}:{serial}]") except Exception as e: raise e def _run_slot_unpair(receivers, args, find_receiver): if args.receiver: rcv = find_receiver(receivers, args.receiver.lower()) if not rcv: raise Exception(f"no receiver found matching '{args.receiver}'") elif len(receivers) == 1: rcv = receivers[0] else: names = ", ".join(f"{r.name} [{r.serial}]" for r in receivers) raise Exception(f"multiple receivers present, pass --receiver to pick one (found: {names})") if rcv.receiver_kind != "lightspeed": raise Exception( f"--slot unpair is currently only supported on Lightspeed receivers " f"(this is a {rcv.receiver_kind or 'unknown'} receiver: {rcv.name})" ) slot = int(args.slot) max_slots = rcv.max_devices or 1 if slot < 1 or slot > max_slots: raise Exception(f"--slot {slot} out of range (valid: 1..{max_slots} on {rcv.name})") # Populate the cache from the receiver's pairing registers so we can report # what the slot currently holds. Truthy cache does NOT imply the device is # reachable on RF — it only means the pairing registers are readable. list(rcv) cached = rcv._devices.get(slot) if cached: slot_desc = f"{cached.name} [{cached.wpid}:{cached.serial}]" elif slot in rcv._devices: slot_desc = "cached None sentinel (pairing info unreadable)" else: slot_desc = "no pairing info cached" print(f"Slot {slot} on {rcv.name} [{rcv.serial}]: {slot_desc}") if getattr(args, "dry_run", False): print(f"[dry-run] would force-unpair slot {slot} — no register write issued") return ok = rcv.force_unpair_slot(slot) if ok: print(f"Slot {slot} unpair register write acknowledged by receiver") else: print(f"Slot {slot} unpair register write was not acknowledged (may be a no-op)") Solaar-1.1.20/lib/solaar/configuration.py000066400000000000000000000236271522022367600203030ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import json import logging import os import threading import yaml from logitech_receiver.common import NamedInt from solaar import __version__ logger = logging.getLogger(__name__) _XDG_CONFIG_HOME = os.environ.get("XDG_CONFIG_HOME") or os.path.expanduser(os.path.join("~", ".config")) _yaml_file_path = os.path.join(_XDG_CONFIG_HOME, "solaar", "config.yaml") _json_file_path = os.path.join(_XDG_CONFIG_HOME, "solaar", "config.json") _KEY_VERSION = "_version" _KEY_NAME = "_NAME" _KEY_WPID = "_wpid" _KEY_SERIAL = "_serial" _KEY_MODEL_ID = "_modelId" _KEY_UNIT_ID = "_unitId" _KEY_ABSENT = "_absent" _KEY_SENSITIVE = "_sensitive" _config = [] def _load(): loaded_config = [] if os.path.isfile(_yaml_file_path): path = _yaml_file_path try: with open(_yaml_file_path) as config_file: loaded_config = yaml.safe_load(config_file) except Exception as e: logger.error("failed to load from %s: %s", _yaml_file_path, e) elif os.path.isfile(_json_file_path): path = _json_file_path try: with open(_json_file_path) as config_file: loaded_config = json.load(config_file) except Exception as e: logger.error("failed to load from %s: %s", _json_file_path, e) loaded_config = _convert_json(loaded_config) else: path = None logger.debug("load => %s", loaded_config) global _config _config = _parse_config(loaded_config, path) def _parse_config(loaded_config, config_path): current_version = __version__ parsed_config = [current_version] try: if not loaded_config: return parsed_config loaded_version = loaded_config[0] discard_derived_properties = loaded_version != current_version if discard_derived_properties: logger.info( "config file '%s' was generated by another version of solaar " "(config: %s, current: %s). refreshing detected device capabilities", config_path, loaded_version, current_version, ) for device in loaded_config[1:]: assert isinstance(device, dict) parsed_config.append(_device_entry_from_config_dict(device, discard_derived_properties)) except Exception as e: logger.warning("Exception processing config file '%s', ignoring contents: %s", config_path, e) return parsed_config def _device_entry_from_config_dict(data, discard_derived_properties): divert = data.get("divert-keys") if divert: sliding = data.get("dpi-sliding") if sliding: # convert old-style dpi-sliding setting to divert-keys entry divert[int(sliding)] = 3 data.pop("dpi-sliding", None) gestures = data.get("mouse-gestures") if gestures: # convert old-style mouse-gestures setting to divert-keys entry divert[int(gestures)] = 2 data.pop("mouse-gestures", None) # remove any string entries (from bad conversions) data["divert-keys"] = {k: v for k, v in divert.items() if isinstance(k, int)} if data.get("_sensitive", None) is None: # make scroll wheel settings default to ignore data["_sensitive"] = { "hires-smooth-resolution": "ignore", "hires-smooth-invert": "ignore", "hires-scroll-mode": "ignore", } if discard_derived_properties: data.pop("_absent", None) data.pop("_battery", None) return _DeviceEntry(**data) save_timer = None configuration_lock = threading.Lock() defer_saves = False # don't allow configuration saves to be deferred def save(defer=False): global save_timer if not _config: return dirname = os.path.dirname(_yaml_file_path) if not os.path.isdir(dirname): try: os.makedirs(dirname) except Exception: logger.error("failed to create %s", dirname) return if not defer or not defer_saves: do_save() else: with configuration_lock: if not save_timer: save_timer = threading.Timer(5.0, do_save) save_timer.start() def do_save(): global save_timer with configuration_lock: if save_timer: save_timer.cancel() save_timer = None try: with open(_yaml_file_path, "w") as config_file: yaml.dump(_config, config_file, default_flow_style=None, width=150) logger.info("saved %s to %s", _config, _yaml_file_path) except Exception as e: logger.error("failed to save to %s: %s", _yaml_file_path, e) def _convert_json(json_dict): config = [json_dict.get(_KEY_VERSION)] for key, dev in json_dict.items(): key = key.split(":") if len(key) == 2: dev[_KEY_WPID] = dev.get(_KEY_WPID) if dev.get(_KEY_WPID) else key[0] dev[_KEY_SERIAL] = dev.get(_KEY_SERIAL) if dev.get(_KEY_SERIAL) else key[1] for k, v in dev.items(): if isinstance(k, str) and not k.startswith("_") and isinstance(v, dict): # convert string keys to ints v = {int(dk) if isinstance(dk, str) else dk: dv for dk, dv in v.items()} dev[k] = v for k in ["mouse-gestures", "dpi-sliding"]: v = dev.get(k, None) if v is True or v is False: dev.pop(k) if "_name" in dev: dev[_KEY_NAME] = dev["_name"] dev.pop("_name") config.append(dev) return config class _DeviceEntry(dict): def __init__(self, **kwargs): super().__init__(**kwargs) def __setitem__(self, key, value): super().__setitem__(key, value) save(defer=True) def update(self, name, wpid, serial, modelId, unitId): if name and name != self.get(_KEY_NAME): super().__setitem__(_KEY_NAME, name) if wpid and wpid != self.get(_KEY_WPID): super().__setitem__(_KEY_WPID, wpid) if serial and serial != self.get(_KEY_SERIAL): super().__setitem__(_KEY_SERIAL, serial) if modelId and modelId != self.get(_KEY_MODEL_ID): super().__setitem__(_KEY_MODEL_ID, modelId) if unitId and unitId != self.get(_KEY_UNIT_ID): super().__setitem__(_KEY_UNIT_ID, unitId) def get_sensitivity(self, name): return self.get(_KEY_SENSITIVE, {}).get(name, False) def set_sensitivity(self, name, value): sensitives = self.get(_KEY_SENSITIVE, {}) if sensitives.get(name) != value: sensitives[name] = value self.__setitem__(_KEY_SENSITIVE, sensitives) def device_representer(dumper, data): return dumper.represent_mapping("tag:yaml.org,2002:map", data) yaml.add_representer(_DeviceEntry, device_representer) def named_int_representer(dumper, data): return dumper.represent_scalar("tag:yaml.org,2002:int", str(int(data))) yaml.add_representer(NamedInt, named_int_representer) # A device can be identified by a combination of WPID and serial number (for receiver-connected devices) # or a combination of modelId and unitId (for direct-connected devices). # But some devices have empty (all zero) modelIds and unitIds. Use the device name as a backup for the modelId. # The worst situation is a receiver-connected device that Solaar has never seen on-line # that is directly connected. Here there is no way to realize that the two devices are the same. # So new entries are not created for unseen off-line receiver-connected devices def persister(device): def match(wpid, serial, modelId, unitId, c): return ( (wpid and wpid == c.get(_KEY_WPID) and serial and serial == c.get(_KEY_SERIAL)) or (modelId and modelId == c.get(_KEY_MODEL_ID) and unitId and unitId == c.get(_KEY_UNIT_ID)) or ( c.get(_KEY_WPID) is None and c.get(_KEY_SERIAL) is None and c.get(_KEY_UNIT_ID) is None and modelId and modelId == c.get(_KEY_MODEL_ID) ) ) with configuration_lock: if not _config: _load() entry = None # some devices report modelId and unitId as zero so use name and serial for them modelId = device.modelId if device.modelId != "000000000000" else device._name if device._name else None unitId = device.unitId if device.unitId != "00000000" else device._serial if device._serial else None for c in _config: if isinstance(c, _DeviceEntry) and match(device.wpid, device._serial, modelId, unitId, c): entry = c break if not entry: if not device.online: # don't create entry for offline devices logger.info("not setting up persister for offline device %s", device._name) return logger.info("setting up persister for device %s", device.name) entry = _DeviceEntry() _config.append(entry) entry.update(device.name, device.wpid, device.serial, modelId, unitId) return entry def attach_to(device): pass Solaar-1.1.20/lib/solaar/custom_logger.py000066400000000000000000000015521522022367600202760ustar00rootroot00000000000000import logging class CustomLogger(logging.Logger): """Logger, that avoids unnecessary string computations. Does not compute messages for disabled log levels. """ def debug(self, msg, *args, **kwargs): if self.isEnabledFor(logging.DEBUG): super().debug(msg, *args, **kwargs) def info(self, msg, *args, **kwargs): if self.isEnabledFor(logging.INFO): super().info(msg, *args, **kwargs) def warning(self, msg, *args, **kwargs): if self.isEnabledFor(logging.WARNING): super().warning(msg, *args, **kwargs) def error(self, msg, *args, **kwargs): if self.isEnabledFor(logging.ERROR): super().error(msg, *args, **kwargs) def critical(self, msg, *args, **kwargs): if self.isEnabledFor(logging.CRITICAL): super().critical(msg, *args, **kwargs) Solaar-1.1.20/lib/solaar/dbus.py000066400000000000000000000056351522022367600163700ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import logging from typing import Callable logger = logging.getLogger(__name__) try: import dbus from dbus.mainloop.glib import DBusGMainLoop # integration into the main GLib loop DBusGMainLoop(set_as_default=True) bus = dbus.SystemBus() assert bus except Exception: # Either the dbus library is not available or the system dbus is not running logger.warning("failed to set up dbus") bus = None _suspend_callback = None _resume_callback = None def _suspend_or_resume(suspend): if suspend and _suspend_callback: _suspend_callback() if not suspend and _resume_callback: _resume_callback() _LOGIND_PATH = "/org/freedesktop/login1" _LOGIND_INTERFACE = "org.freedesktop.login1.Manager" def watch_suspend_resume( on_resume_callback: Callable[[], None] | None = None, on_suspend_callback: Callable[[], None] | None = None, ): """Register callback for suspend/resume events. They are called only if the system DBus is running, and the Login daemon is available.""" global _resume_callback, _suspend_callback _suspend_callback = on_suspend_callback _resume_callback = on_resume_callback if bus is not None and on_resume_callback is not None or on_suspend_callback is not None: bus.add_signal_receiver( _suspend_or_resume, "PrepareForSleep", dbus_interface=_LOGIND_INTERFACE, path=_LOGIND_PATH, ) logger.info("connected to system dbus, watching for suspend/resume events") _BLUETOOTH_PATH_PREFIX = "/org/bluez/hci0/dev_" _BLUETOOTH_INTERFACE = "org.freedesktop.DBus.Properties" _bluetooth_callbacks = {} def watch_bluez_connect(serial, callback=None): if _bluetooth_callbacks.get(serial): _bluetooth_callbacks.get(serial).remove() path = _BLUETOOTH_PATH_PREFIX + serial.replace(":", "_").upper() if bus is not None and callback is not None: _bluetooth_callbacks[serial] = bus.add_signal_receiver( callback, "PropertiesChanged", path=path, dbus_interface=_BLUETOOTH_INTERFACE ) Solaar-1.1.20/lib/solaar/gtk.py000077500000000000000000000162171522022367600162210ustar00rootroot00000000000000#!/usr/bin/env python3 ## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import argparse import faulthandler import importlib import locale import logging import os.path import platform import signal import sys import tempfile from traceback import format_exc from solaar import NAME from solaar import __version__ from solaar import cli from solaar import configuration from solaar import dbus from solaar import listener from solaar import ui from solaar.custom_logger import CustomLogger logging.setLoggerClass(CustomLogger) logger = logging.getLogger(__name__) def _require(module, os_package, gi=None, gi_package=None, gi_version=None): try: if gi is not None: gi.require_version(gi_package, gi_version) return importlib.import_module(module) except (ImportError, ValueError): sys.exit(f"{NAME.lower()}: missing required system package {os_package}") battery_icons_style = "regular" tray_icon_size = None temp = tempfile.NamedTemporaryFile(prefix="Solaar_", mode="w", delete=True) def create_parser(): arg_parser = argparse.ArgumentParser( prog=NAME.lower(), description="Solaar is a program to manage many Logitech devices, " "changing how they operate and maintaining the changes whenever the device connects.", epilog="For more information see https://pwr-solaar.github.io/Solaar", ) arg_parser.add_argument( "-d", "--debug", action="count", default=0, help="print logging messages, for debugging purposes (may be repeated for extra verbosity)", ) arg_parser.add_argument( "-D", "--hidraw", action="store", dest="hidraw_path", metavar="PATH", help="device or receiver path to use if needed. Example: /dev/hidraw2", ) arg_parser.add_argument( "--restart-on-wake-up", action="store_true", help="restart Solaar on sleep wake-up (experimental)", ) arg_parser.add_argument( "-w", "--window", choices=("show", "hide", "only"), help="start with window showing / hidden / only (no tray icon)", ) arg_parser.add_argument( "-b", "--battery-icons", choices=("regular", "symbolic", "solaar"), help="prefer regular battery / symbolic battery / solaar icons", ) arg_parser.add_argument("--tray-icon-size", type=int, help="explicit size for tray icons") arg_parser.add_argument("-V", "--version", action="version", version="%(prog)s " + __version__) arg_parser.add_argument("--help-actions", action="store_true", help="describe the command-line actions") arg_parser.add_argument( "action", nargs=argparse.REMAINDER, choices=cli.actions, help="command-line action to perform (optional); append ' --help' to show args", ) return arg_parser def _parse_arguments(): arg_parser = create_parser() args = arg_parser.parse_args() if args.help_actions: cli.print_help() return if args.window is None: args.window = "show" # default behaviour is to show main window global battery_icons_style battery_icons_style = args.battery_icons if args.battery_icons is not None else "regular" global tray_icon_size tray_icon_size = args.tray_icon_size log_format = "%(asctime)s,%(msecs)03d %(levelname)8s [%(threadName)s] %(name)s: %(message)s" log_level = logging.ERROR - 10 * args.debug logging.getLogger("").setLevel(min(log_level, logging.WARNING)) file_handler = logging.StreamHandler(temp) file_handler.setLevel(max(min(log_level, logging.WARNING), logging.INFO)) file_handler.setFormatter(logging.Formatter(log_format)) logging.getLogger("").addHandler(file_handler) if args.debug > 0: stream_handler = logging.StreamHandler() stream_handler.setFormatter(logging.Formatter(log_format)) stream_handler.setLevel(log_level) logging.getLogger("").addHandler(stream_handler) if not args.action: language, encoding = locale.getlocale() logger.info("version %s, language %s (%s)", __version__, language, encoding) return args # On first SIGINT, dump threads to stderr; on second, exit def _handlesig(signl, stack): signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGTERM, signal.SIG_DFL) if signl == int(signal.SIGINT): if logger.isEnabledFor(logging.INFO): faulthandler.dump_traceback() sys.exit(f"{NAME.lower()}: exit due to keyboard interrupt") else: sys.exit(0) def main(): if platform.system() not in ("Darwin", "Windows"): _require("pyudev", "python3-pyudev") args = _parse_arguments() if not args: # explicit close before return temp.close() return if args.action: # if any argument, run comandline and exit result = cli.run(args.action, args.hidraw_path) # explicit close before return temp.close() return result gi = _require("gi", "python3-gi (in Ubuntu) or python3-gobject (in Fedora)") _require("gi.repository.Gtk", "gir1.2-gtk-3.0", gi, "Gtk", "3.0") # handle ^C in console signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGINT, _handlesig) signal.signal(signal.SIGTERM, _handlesig) udev_file = "42-logitech-unify-permissions.rules" if ( platform.system() == "Linux" and logger.isEnabledFor(logging.WARNING) and not os.path.isfile("/etc/udev/rules.d/" + udev_file) and not os.path.isfile("/usr/lib/udev/rules.d/" + udev_file) and not os.path.isfile("/usr/local/lib/udev/rules.d/" + udev_file) ): logger.warning("Solaar udev file not found in expected location") logger.warning("See https://pwr-solaar.github.io/Solaar/installation for more information") try: listener.setup_scanner(ui.status_changed, ui.setting_changed, ui.common.error_dialog) if args.restart_on_wake_up: dbus.watch_suspend_resume(listener.start_all, listener.stop_all) else: dbus.watch_suspend_resume(lambda: listener.ping_all(True)) configuration.defer_saves = True # allow configuration saves to be deferred # main UI event loop ui.run_loop(listener.start_all, listener.stop_all, args.window != "only", args.window != "hide") except Exception: sys.exit(f"{NAME.lower()}: error: {format_exc()}") temp.close() if __name__ == "__main__": main() Solaar-1.1.20/lib/solaar/i18n.py000066400000000000000000000046111522022367600162030ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import gettext import locale import logging import os import sys from glob import glob from solaar import NAME _LOCALE_DOMAIN = NAME.lower() logger = logging.getLogger(__name__) def _find_locale_path(locale_domain: str) -> str: prefix_share = os.path.normpath(os.path.join(os.path.realpath(sys.path[0]), "..")) src_share = os.path.normpath(os.path.join(os.path.realpath(sys.path[0]), "..", "share")) for location in prefix_share, src_share: mo_files = glob(os.path.join(location, "locale", "*", "LC_MESSAGES", f"{locale_domain}.mo")) if mo_files: return os.path.join(location, "locale") raise FileNotFoundError(f"Could not find locale path for {locale_domain}") def set_locale_to_system_default() -> None: """Sets locale for translations to the system default. If locale is unsupported, fallback to standard English without translation 'C'. Set LC_ALL environment variable to enforce a locale setting e.g. 'de_DE.UTF-8'. Run Solaar with your desired localization, for German use: 'LC_ALL=de_DE.UTF-8 solaar' """ try: locale.setlocale(locale.LC_ALL, "") # system default except locale.Error: logger.error("User locale not supported by system, using no translation.") locale.setlocale(locale.LC_ALL, "C") # untranslated (English) return try: path = _find_locale_path(_LOCALE_DOMAIN) except FileNotFoundError: path = None gettext.bindtextdomain(_LOCALE_DOMAIN, path) gettext.textdomain(_LOCALE_DOMAIN) gettext.install(_LOCALE_DOMAIN) set_locale_to_system_default() _ = gettext.gettext ngettext = gettext.ngettext Solaar-1.1.20/lib/solaar/listener.py000066400000000000000000000526031522022367600172550ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import errno import logging import subprocess import time import typing from collections import namedtuple from functools import partial from typing import Callable import gi import logitech_receiver from logitech_receiver import base from logitech_receiver import exceptions from logitech_receiver import hidpp10_constants from logitech_receiver import listener from logitech_receiver import notifications from . import configuration from . import dbus from . import i18n from .ui import common if typing.TYPE_CHECKING: from hidapi.common import DeviceInfo gi.require_version("Gtk", "3.0") # NOQA: E402 from gi.repository import GLib # NOQA: E402 # isort:skip if typing.TYPE_CHECKING: from logitech_receiver.device import Device logger = logging.getLogger(__name__) ACTION_ADD = "add" _GHOST_DEVICE = namedtuple("_GHOST_DEVICE", ("receiver", "number", "name", "kind", "online", "path")) _GHOST_DEVICE.__bool__ = lambda self: False _GHOST_DEVICE.__nonzero__ = _GHOST_DEVICE.__bool__ def _ghost(device): return _GHOST_DEVICE( receiver=device.receiver, number=device.number, name=device.name, kind=device.kind, online=False, path=None ) class SolaarListener(listener.EventsListener): """Keeps the status of a Receiver or Device (member name is receiver but it can also be a device).""" def __init__(self, receiver, status_changed_callback): assert status_changed_callback super().__init__(receiver, self._notifications_handler) self.status_changed_callback = status_changed_callback receiver.status_callback = self._status_changed def has_started(self): logger.info("%s: notifications listener has started (%s)", self.receiver, self.receiver.handle) nfs = self.receiver.enable_connection_notifications() if not self.receiver.isDevice and (not nfs or not (nfs & hidpp10_constants.NotificationFlag.WIRELESS)): logger.warning( "Receiver on %s might not support connection notifications, GUI might not show its devices", self.receiver.path, ) self.receiver.notification_flags = nfs self.receiver.notify_devices() self._status_changed(self.receiver) def has_stopped(self): r, self.receiver = self.receiver, None assert r is not None logger.info("%s: notifications listener has stopped", r) # because udev is not notifying us about device removal, make sure to clean up in _all_listeners _all_listeners.pop(r.path, None) # this causes problems but what is it doing (pfps) - r.status = _('The receiver was unplugged.') if r: try: r.close() except Exception: logger.exception(f"closing receiver {r.path}") self.status_changed_callback(r) def _status_changed(self, device, alert=None, reason=None): assert device is not None if logger.isEnabledFor(logging.INFO): try: if device.kind is None: logger.info( "status_changed %r: %s (%X) %s", device, "present" if bool(device) else "removed", alert if alert is not None else 0, reason or "", ) else: logger.info( "status_changed %r: %s %s (%X) %s", device, "paired" if bool(device) else "unpaired", "online" if device.online else "offline", alert if alert is not None else 0, reason or "", ) except Exception as e: logger.info("status_changed for unknown device: %s", e) if device.kind is None: assert device == self.receiver # the status of the receiver changed self.status_changed_callback(device, alert, reason) return # not true for wired devices - assert device.receiver == self.receiver if not device: # Device was unpaired, and isn't valid anymore. # We replace it with a ghost so that the UI has something to work with while cleaning up. logger.info("device %s was unpaired, ghosting", device) device = _ghost(device) self.status_changed_callback(device, alert, reason) if not device: # the device was just unpaired, need to update the status of the receiver as well self.status_changed_callback(self.receiver) def _notifications_handler(self, n): assert self.receiver if n.devnumber == 0xFF: # For CenturionReceiver, intercept bridge notifications and dispatch to child device from logitech_receiver.device import CenturionReceiver if isinstance(self.receiver, CenturionReceiver): if self.receiver._pending: ihandle = int(self.receiver.handle) state = base._centurion_handles.get(ihandle) if state and state.device_addr is not None: self.receiver._complete_deferred_init() self._status_changed(self.receiver) self._handle_centurion_notification(n) return # a receiver notification notifications.process(self.receiver, n) return # a notification that came in to the device listener - strange, but nothing needs to be done here if self.receiver.isDevice: logger.debug("Notification %s via device %s being ignored.", n, self.receiver) return # DJ pairing notification - ignore - hid++ 1.0 pairing notification is all that is needed if n.sub_id == 0x41 and n.report_id == base.DJ_MESSAGE_ID: logger.info("ignoring DJ pairing notification %s", n) return # a device notification if not (0 < n.devnumber <= 16): # some receivers have devices past their max # devices logger.warning("Unexpected device number (%s) in notification %s.", n.devnumber, n) return already_known = n.devnumber in self.receiver # FIXME: hacky fix for kernel/hardware race condition # If the device was just turned on or woken up from sleep, it may not be ready to receive commands. # The "payload" bit of the wireless status notification seems to tell us this. If this is the case, we # must wait a short amount of time to avoid causing a broken pipe error. device_ready = not bool(ord(n.data[0:1]) & 0x80) or n.sub_id != 0x41 if not device_ready: time.sleep(0.01) if n.sub_id == 0x40 and not already_known: return # disconnecting something that is not known - nothing to do if n.sub_id == 0x41: if not already_known: if n.address == 0x0A and not self.receiver.receiver_kind == "bolt": # some Nanos send a notification even if no new pairing - check that there really is a device there if ( self.receiver.read_register( hidpp10_constants.Registers.RECEIVER_INFO, hidpp10_constants.InfoSubRegisters.PAIRING_INFORMATION + n.devnumber - 1, ) is None ): return dev = self.receiver.register_new_device(n.devnumber, n) elif self.receiver.pairing.lock_open and self.receiver.re_pairs and not ord(n.data[0:1]) & 0x40: dev = self.receiver[n.devnumber] del self.receiver[n.devnumber] # get rid of information on device re-paired away self._status_changed(dev) # signal that this device has changed dev = self.receiver.register_new_device(n.devnumber, n) self.receiver.pairing.new_device = self.receiver[n.devnumber] else: dev = self.receiver[n.devnumber] else: dev = self.receiver[n.devnumber] if not dev: logger.warning("%s: received %s for invalid device %d: %r", self.receiver, n, n.devnumber, dev) return # Apply settings every time the device connects if n.sub_id == 0x41: logger.info("connection %s for device wpid %s kind %s serial %s", n, dev.wpid, dev.kind, dev._serial) # If there are saved configs, bring the device's settings up-to-date. # They will be applied when the device is marked as online. configuration.attach_to(dev) dev.status_callback = self._status_changed # the receiver changed status as well self._status_changed(self.receiver) notifications.process(dev, n) if self.receiver.pairing.lock_open and not already_known: # this should be the first notification after a device was paired logger.warning("first notification was not a connection notification") logger.info("%s: pairing detected new device", self.receiver) self.receiver.pairing.new_device = dev elif dev.online is None: dev.ping() def _handle_centurion_notification(self, n): """Handle notifications from a CenturionReceiver dongle. Bridge events have sub_id == bridge_index. The event function number is in bits 7-4 of n.address: - Function 0: ConnectionStateChangedEvent — sub-device connect/disconnect - Function 1: MessageEvent — wrapped sub-device HID++ notification ConnectionStateChangedEvent payload (same format as getConnectionInfo): n.data[0]: high nibble = connection type, low nibble = len_hi n.data[1]: len_lo n.data[2+]: sub-device descriptors (if any) Empty sub-device list (length=0) means disconnected. MessageEvent data layout: n.data[0:2] = dev_id<<4|len_hi, len_lo n.data[2] = sub_cpl (0x00 for both responses and notifications) n.data[3] = sub_feat_idx n.data[4] = sub_func_sw (sw_id=0 for unsolicited notifications) n.data[5:] = payload """ child = self.receiver._devices.get(1) if not child: if logger.isEnabledFor(logging.DEBUG): logger.debug("CenturionReceiver: notification ignored (no child device): %s", n) return bridge_idx = getattr(child, "_centurion_bridge_index", None) if bridge_idx is None or n.sub_id != bridge_idx: if logger.isEnabledFor(logging.DEBUG): logger.debug( "CenturionReceiver: non-bridge notification sub_id=%d addr=0x%02X data=%s", n.sub_id, n.address, n.data[:12].hex() if n.data else "", ) return event_func = (n.address >> 4) & 0x0F if event_func == 0: # ConnectionStateChangedEvent — parse sub-device list length if len(n.data) < 2: return data_len = ((n.data[0] & 0x0F) << 8) | n.data[1] if data_len > 0 and not child.online: if logger.isEnabledFor(logging.INFO): logger.info("CenturionReceiver: headset connected (ConnectionStateChangedEvent, len=%d)", data_len) child.changed(active=True) self._status_changed(child) elif data_len == 0 and child.online: if logger.isEnabledFor(logging.INFO): logger.info("CenturionReceiver: headset disconnected (ConnectionStateChangedEvent, len=0)") child.changed(active=False) self._status_changed(child) return if event_func == 1: # MessageEvent — unwrap sub-device notification # n.data layout: [dev_id<<4|len_hi, len_lo, sub_cpl, sub_feat_idx, sub_func_sw, payload...] if len(n.data) < 5: return # A MessageEvent from the headset proves it's online. If we missed the # ConnectionStateChangedEvent (e.g. cold-start power-on), bring it online now. if not child.online: if logger.isEnabledFor(logging.INFO): logger.info("CenturionReceiver: headset online (MessageEvent received while offline)") child.changed(active=True) self._status_changed(child) sub_feat_idx = n.data[3] sub_func_sw = n.data[4] payload = n.data[5:] if logger.isEnabledFor(logging.DEBUG): logger.debug( "CenturionReceiver: bridge MessageEvent sub_feat=%d func=0x%02X payload=%s -> child %s", sub_feat_idx, sub_func_sw, payload[:8].hex() if payload else "", child, ) # Create synthetic notification and dispatch directly to feature processing. # Sub-device features use 0x100 offset in FeaturesArray.inverse. synthetic = base.HIDPPNotification(n.report_id, child.number, sub_feat_idx + 0x100, sub_func_sw, payload) child.online = True if child.features: notifications._process_feature_notification(child, synthetic) return if logger.isEnabledFor(logging.DEBUG): logger.debug( "CenturionReceiver: unhandled bridge event func=%d addr=0x%02X data=%s", event_func, n.address, n.data[:12].hex() if n.data else "", ) def __str__(self): return f"" def _process_bluez_dbus(device: Device, path, dictionary: dict, signature): """Process bluez dbus property changed signals for device status changes to discover disconnections and connections. """ if device: if dictionary.get("Connected") is not None: connected = dictionary.get("Connected") logger.info("bluez dbus for %s: %s", device, "CONNECTED" if connected else "DISCONNECTED") device.changed(connected, reason=i18n._("connected") if connected else i18n._("disconnected")) elif device is not None: logger.info("bluez cleanup for %s", device) _cleanup_bluez_dbus(device) def _cleanup_bluez_dbus(device: Device): """Remove dbus signal receiver for device""" logger.info("bluez cleanup for %s", device) dbus.watch_bluez_connect(device.hid_serial, None) _all_listeners = {} # all known receiver listeners, listeners that stop on their own may remain here def _post_attach_device(device): """Shared post-create_device wiring: hook configuration up to the new Device, and if it's BT-paired, install the bluez-dbus connect watcher so disconnect/reconnect events propagate to the UI without a restart. Both the Centurion-direct fallback (no-dongle device, e.g. BT-paired G522 / PRO X 2) and the regular non-Centurion device path call this — previously only the latter wired the bluez watcher, so a BT-paired Centurion device wouldn't see reconnect events.""" configuration.attach_to(device) if device.bluetooth and device.hid_serial: dbus.watch_bluez_connect(device.hid_serial, partial(_process_bluez_dbus, device)) device.cleanups.append(_cleanup_bluez_dbus) def _start(device_info: DeviceInfo): assert _status_callback and _setting_callback if not device_info.isDevice: receiver_ = logitech_receiver.receiver.create_receiver(base, device_info, _setting_callback) elif getattr(device_info, "centurion", False): receiver_ = logitech_receiver.device.create_centurion_receiver(base, device_info, _setting_callback) if receiver_ is None: # No bridge found — treat as a direct-connected centurion device # (wired headset, or BT-paired headset with no LIGHTSPEED dongle). receiver_ = logitech_receiver.device.create_device(base, device_info, _setting_callback) if receiver_: _post_attach_device(receiver_) else: receiver_ = logitech_receiver.device.create_device(base, device_info, _setting_callback) if receiver_: _post_attach_device(receiver_) if receiver_: rl = SolaarListener(receiver_, _status_callback) rl.start() _all_listeners[device_info.path] = rl return rl logger.warning("failed to open %s", device_info) def start_all(): stop_all() # just in case this it called twice in a row... logger.info("starting receiver listening threads") for device_info in base.receivers_and_devices(): _process_receiver_event(ACTION_ADD, device_info) def stop_all(): listeners = list(_all_listeners.values()) _all_listeners.clear() if listeners: logger.info("stopping receiver listening threads %s", listeners) for listener_thread in listeners: listener_thread.stop() configuration.save() if listeners: for listener_thread in listeners: listener_thread.join() # after a resume, the device may have been off so mark its saved status to ensure # that the status is pushed to the device when it comes back def ping_all(resuming=False): logger.info("ping all devices%s", " when resuming" if resuming else "") for listener_thread in _all_listeners.values(): if listener_thread.receiver.isDevice: if resuming: listener_thread.receiver._active = None # ensure that settings are pushed if listener_thread.receiver.ping(): listener_thread.receiver.changed(active=True, push=True) listener_thread._status_changed(listener_thread.receiver) else: count = listener_thread.receiver.count() if count: for dev in listener_thread.receiver: if resuming: dev._active = None # ensure that settings are pushed count -= 1 try: # sometimes the device is not set up already, it should come back later if dev.ping(): dev.changed(active=True, push=True) listener_thread._status_changed(dev) except exceptions.NoSuchDevice: logger.debug("can't ping device on resume: %s", dev) if not count: break _status_callback = None # GUI callback to change UI in response to changes to receiver or device status _setting_callback = None # GUI callback to change UI in response to changes to status _error_callback = None # GUI callback to report errors def setup_scanner(status_changed_callback: Callable, setting_changed_callback: Callable, error_callback: Callable): global _status_callback, _error_callback, _setting_callback assert _status_callback is None, "scanner was already set-up" _status_callback = status_changed_callback _setting_callback = setting_changed_callback _error_callback = error_callback base.notify_on_receivers_glib(GLib, _process_receiver_event) def _process_add(device_info: DeviceInfo, retry): try: _start(device_info) except OSError as e: if e.errno == errno.EACCES: try: output = subprocess.check_output(["getfacl", "-p", device_info.path], text=True) logger.warning("Missing permissions on %s\n%s.", device_info.path, output) except Exception: pass if retry: GLib.timeout_add(2000.0, _process_add, device_info, retry - 1) else: _error_callback(common.ErrorReason.PERMISSIONS, device_info.path) else: _error_callback(common.ErrorReason.NO_DEVICE, device_info.path) except exceptions.NoReceiver: _error_callback(common.ErrorReason.NO_DEVICE, device_info.path) # receiver add/remove events will start/stop listener threads def _process_receiver_event(action, device_info): assert action is not None assert device_info is not None assert _error_callback logger.info("receiver event %s %s", action, device_info) # whatever the action, stop any previous receivers at this path listener_thread = _all_listeners.pop(device_info.path, None) if listener_thread is not None: assert isinstance(listener_thread, SolaarListener) listener_thread.stop() if action == ACTION_ADD: _process_add(device_info, 3) return False Solaar-1.1.20/lib/solaar/tasks.py000066400000000000000000000033441522022367600165530ustar00rootroot00000000000000#!/usr/bin/env python3 ## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import logging from threading import Thread logger = logging.getLogger(__name__) try: from Queue import Queue except ImportError: from queue import Queue class TaskRunner(Thread): def __init__(self, name): super().__init__(name=name) self.daemon = True self.queue = Queue(16) self.alive = False def __call__(self, function, *args, **kwargs): task = (function, args, kwargs) self.queue.put(task) def stop(self): self.alive = False self.queue.put(None) def run(self): self.alive = True logger.debug("started") while self.alive: task = self.queue.get() if task: function, args, kwargs = task assert function try: function(*args, **kwargs) except Exception: logger.exception("calling %s", function) logger.debug("stopped") Solaar-1.1.20/lib/solaar/ui/000077500000000000000000000000001522022367600154655ustar00rootroot00000000000000Solaar-1.1.20/lib/solaar/ui/__init__.py000066400000000000000000000107701522022367600176030ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import logging from enum import Enum from typing import Callable import gi import yaml from logitech_receiver.common import Alert from solaar.i18n import _ from solaar.ui.config_panel import change_setting from solaar.ui.config_panel import record_setting from solaar.ui.window import find_device from . import common from . import desktop_notifications from . import diversion_rules from . import tray from . import window gi.require_version("Gtk", "3.0") from gi.repository import Gio # NOQA: E402 from gi.repository import GLib # NOQA: E402 from gi.repository import Gtk # NOQA: E402 logger = logging.getLogger(__name__) assert Gtk.get_major_version() > 2, "Solaar requires Gtk 3 python bindings" APP_ID = "io.github.pwr_solaar.solaar" class GtkSignal(Enum): ACTIVATE = "activate" COMMAND_LINE = "command-line" SHUTDOWN = "shutdown" def _startup(app, startup_hook, use_tray, show_window): logger.debug("startup registered=%s, remote=%s", app.get_is_registered(), app.get_is_remote()) common.start_async() desktop_notifications.init() if use_tray: tray.init(lambda _ignore: window.destroy()) window.init(show_window, use_tray) startup_hook() def _activate(app): logger.debug("activate") if app.get_windows(): window.popup() else: app.add_window(window._window) def _command_line(app, command_line): args = command_line.get_arguments() args = yaml.safe_load("".join(args)) if args else args if not args: _activate(app) elif args[0] == "config": # config call from remote instance logger.info("remote command line %s", args) dev = find_device(args[1]) if dev: setting = next((s for s in dev.settings if s.name == args[2]), None) if setting: change_setting(dev, setting, args[3:]) return 0 def _shutdown(_app, shutdown_hook): logger.debug("shutdown") shutdown_hook() common.stop_async() tray.destroy() desktop_notifications.uninit() def run_loop( startup_hook: Callable[[], None], shutdown_hook: Callable[[], None], use_tray: bool, show_window: bool, ): assert use_tray or show_window, "need either tray or visible window" application = Gtk.Application.new(APP_ID, Gio.ApplicationFlags.HANDLES_COMMAND_LINE) application.connect( "startup", lambda app, startup_hook: _startup(app, startup_hook, use_tray, show_window), startup_hook, ) application.connect(GtkSignal.COMMAND_LINE.value, _command_line) application.connect(GtkSignal.ACTIVATE.value, _activate) application.connect(GtkSignal.SHUTDOWN.value, _shutdown, shutdown_hook) application.register() if application.get_is_remote(): print(_("Another Solaar process is already running so just expose its window")) application.run() def _status_changed(device, alert, reason, refresh=False): if device is None: logger.debug("status changed on nil device: %s (%s) %s", device, alert, reason) return logger.debug("status changed: %s (%s) %s", device, alert, reason) if alert is None: alert = Alert.NONE tray.update(device) if alert & Alert.ATTENTION: tray.attention(reason) need_popup = alert & Alert.SHOW_WINDOW window.update(device, need_popup, refresh) diversion_rules.update_devices() if alert & (Alert.NOTIFICATION | Alert.ATTENTION): desktop_notifications.show(device, reason) def status_changed(device, alert=Alert.NONE, reason=None, refresh=False): GLib.idle_add(_status_changed, device, alert, reason, refresh) def setting_changed(device, setting_class, vals): record_setting(device, setting_class, vals) Solaar-1.1.20/lib/solaar/ui/about/000077500000000000000000000000001522022367600165775ustar00rootroot00000000000000Solaar-1.1.20/lib/solaar/ui/about/__init__.py000066400000000000000000000000001522022367600206760ustar00rootroot00000000000000Solaar-1.1.20/lib/solaar/ui/about/about.py000066400000000000000000000023071522022367600202650ustar00rootroot00000000000000## Copyright (C) Solaar Contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from solaar.ui.about.model import AboutModel from solaar.ui.about.presenter import Presenter from solaar.ui.about.view import AboutView def show(_=None, model=None, view=None): """Opens the About dialog.""" if model is None: model = AboutModel() if view is None: view = AboutView() presenter = Presenter(model, view) presenter.run() if __name__ == "__main__": from gi.repository import Gtk show(None) Gtk.main() Solaar-1.1.20/lib/solaar/ui/about/model.py000066400000000000000000000057121522022367600202560ustar00rootroot00000000000000## Copyright (C) Solaar Contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations from datetime import datetime from typing import List from typing import Tuple from solaar import __version__ from solaar.i18n import _ def _get_current_year() -> int: return datetime.now().year class AboutModel: def get_version(self) -> str: return __version__ def get_description(self) -> str: return _("Manages Logitech receivers,\nkeyboards, mice, and tablets.") def get_copyright(self) -> str: return f"© 2012-{_get_current_year()} Daniel Pavel and contributors to the Solaar project" def get_authors(self) -> List[str]: return [ "Daniel Pavel http://github.com/pwr", ] def get_translators(self) -> List[str]: return [ "gogo (croatian)", "Papoteur, David Geiger, Damien Lallement (français)", "Michele Olivo (italiano)", "Adrian Piotrowicz (polski)", "Drovetto, JrBenito (Portuguese-BR)", "Daniel Pavel (română)", "Daniel Zippert, Emelie Snecker (svensk)", "Dimitriy Ryazantcev (Russian)", "El Jinete Sin Cabeza (Español)", "Ferdina Kusumah (Indonesia)", "John Erling Blad (Norwegian Bokmål, Norwegian Nynorsk)", "Oleksandr Afanasiev (Ukrainian)", ] def get_credit_sections(self) -> List[Tuple[str, List[str]]]: return [ (_("Additional Programming"), ["Filipe Laíns", "Peter F. Patel-Schneider", "Ken Sanislo"]), (_("GUI design"), ["Julien Gascard", "Daniel Pavel"]), ( _("Testing"), [ "Douglas Wagner", "Julien Gascard", "Peter Wu http://www.lekensteyn.nl/logitech-unifying.html", ], ), ( _("Logitech documentation"), [ "Julien Danjou http://julien.danjou.info/blog/2012/logitech-unifying-upower", "Nestor Lopez Casado http://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28", ], ), ] def get_website(self): return "https://pwr-solaar.github.io/Solaar" Solaar-1.1.20/lib/solaar/ui/about/presenter.py000066400000000000000000000055521522022367600211670ustar00rootroot00000000000000## Copyright (C) Solaar Contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations from typing_extensions import Protocol from solaar.ui.about.model import AboutModel class AboutViewProtocol(Protocol): def init_ui(self) -> None: ... def update_version_info(self, version: str) -> None: ... def update_description(self, comments: str) -> None: ... def update_copyright(self, copyright_text: str) -> None: ... def update_authors(self, authors: list[str]) -> None: ... def update_translators(self, translators: list[str]) -> None: ... def update_website(self, website): ... def update_credits(self, credit_sections: list[tuple[str, list[str]]]) -> None: ... def show(self) -> None: ... class Presenter: def __init__(self, model: AboutModel, view: AboutViewProtocol) -> None: self.model = model self.view = view def update_version_info(self) -> None: version = self.model.get_version() self.view.update_version_info(version) def update_credits(self) -> None: credit_sections = self.model.get_credit_sections() self.view.update_credits(credit_sections) def update_description(self) -> None: comments = self.model.get_description() self.view.update_description(comments) def update_copyright(self) -> None: copyright_text = self.model.get_copyright() self.view.update_copyright(copyright_text) def update_authors(self) -> None: authors = self.model.get_authors() self.view.update_authors(authors) def update_translators(self) -> None: translators = self.model.get_translators() self.view.update_translators(translators) def update_website(self) -> None: website = self.model.get_website() self.view.update_website(website) def run(self) -> None: self.view.init_ui() self.update_version_info() self.update_description() self.update_website() self.update_copyright() self.update_authors() self.update_credits() self.update_translators() self.view.show() Solaar-1.1.20/lib/solaar/ui/about/view.py000066400000000000000000000045301522022367600201250ustar00rootroot00000000000000## Copyright (C) Solaar Contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from enum import Enum from typing import List from typing import Tuple from typing import Union from gi.repository import Gtk from solaar import NAME class GtkSignal(Enum): RESPONSE = "response" class AboutView: def __init__(self) -> None: self.view: Union[Gtk.AboutDialog, None] = None def init_ui(self) -> None: self.view = Gtk.AboutDialog() self.view.set_program_name(NAME) self.view.set_logo_icon_name(NAME.lower()) self.view.set_license_type(Gtk.License.GPL_2_0) self.view.connect(GtkSignal.RESPONSE.value, lambda x, y: self.handle_close(x)) def update_version_info(self, version: str) -> None: self.view.set_version(version) def update_description(self, comments: str) -> None: self.view.set_comments(comments) def update_copyright(self, copyright_text: str): self.view.set_copyright(copyright_text) def update_authors(self, authors: List[str]) -> None: self.view.set_authors(authors) def update_credits(self, credit_sections: List[Tuple[str, List[str]]]) -> None: for section_name, people in credit_sections: self.view.add_credit_section(section_name, people) def update_translators(self, translators: List[str]) -> None: translator_credits = "\n".join(translators) self.view.set_translator_credits(translator_credits) def update_website(self, website): self.view.set_website_label(NAME) self.view.set_website(website) def show(self) -> None: self.view.present() def handle_close(self, event) -> None: event.hide() Solaar-1.1.20/lib/solaar/ui/action.py000066400000000000000000000072161522022367600173220ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from enum import Enum from gi.repository import Gdk from gi.repository import Gtk from solaar.i18n import _ from solaar.ui import common from . import pair_window class GtkSignal(Enum): ACTIVATE = "activate" def make_image_menu_item(label, icon_name, function, *args): box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 6) label = Gtk.Label(label=label) icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.LARGE_TOOLBAR) if icon_name is not None else Gtk.Image() box.add(icon) box.add(label) menu_item = Gtk.MenuItem() menu_item.add(box) menu_item.show_all() menu_item.connect(GtkSignal.ACTIVATE.value, function, *args) menu_item.label = label menu_item.icon = icon return menu_item def make(name, label, function, stock_id=None, *args): action = Gtk.Action(name=name, label=label, tooltip=label, stock_id=None) action.set_icon_name(name) if stock_id is not None: action.set_stock_id(stock_id) if function: action.connect(GtkSignal.ACTIVATE.value, function, *args) return action def make_toggle(name, label, function, stock_id=None, *args): action = Gtk.ToggleAction(name=name, label=label, tooltip=label, stock_id=None) action.set_icon_name(name) if stock_id is not None: action.set_stock_id(stock_id) action.connect(GtkSignal.ACTIVATE.value, function, *args) return action def pair(window, receiver): assert receiver assert receiver.kind is None pair_dialog = pair_window.create(receiver) pair_dialog.set_transient_for(window) pair_dialog.set_destroy_with_parent(True) pair_dialog.set_modal(True) pair_dialog.set_type_hint(Gdk.WindowTypeHint.DIALOG) pair_dialog.set_position(Gtk.WindowPosition.CENTER) pair_dialog.present() def unpair(window, device): assert device assert device.kind is not None qdialog = Gtk.MessageDialog( transient_for=window, flags=0, message_type=Gtk.MessageType.QUESTION, buttons=Gtk.ButtonsType.NONE, text=_("Unpair") + " " + device.name + " ?", ) qdialog.set_icon_name("remove") qdialog.add_button(_("Cancel"), Gtk.ResponseType.CANCEL) qdialog.add_button(_("Unpair"), Gtk.ResponseType.ACCEPT) choice = qdialog.run() qdialog.destroy() if choice == Gtk.ResponseType.ACCEPT: receiver = device.receiver assert receiver device_number = device.number try: # force=True ensures the unpair register write is issued even on # re_pairs receivers (Lightspeed, Nano); otherwise _unpair_device # short-circuits to cache-invalidation only and the slot stays # bound on the hardware. receiver._unpair_device(device_number, True) except Exception: common.error_dialog(common.ErrorReason.UNPAIR, device) Solaar-1.1.20/lib/solaar/ui/common.py000066400000000000000000000062701522022367600173340ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import logging from enum import Enum from typing import Tuple import gi from solaar.i18n import _ from solaar.tasks import TaskRunner gi.require_version("Gtk", "3.0") from gi.repository import GLib # NOQA: E402 from gi.repository import Gtk # NOQA: E402 logger = logging.getLogger(__name__) class ErrorReason(Enum): PERMISSIONS = "Permissions" NO_DEVICE = "No device" UNPAIR = "Unpair" def _create_error_text(reason: ErrorReason, object_) -> Tuple[str, str]: if reason == ErrorReason.PERMISSIONS: title = _("Permissions error") text = ( _("Found a Logitech receiver or device (%s), but did not have permission to open it.") % object_ + "\n\n" + _("If you've just installed Solaar, try disconnecting the receiver or device and then reconnecting it.") ) elif reason == ErrorReason.NO_DEVICE: title = _("Cannot connect to device error") text = ( _("Found a Logitech receiver or device at %s, but encountered an error connecting to it.") % object_ + "\n\n" + _("Try disconnecting the device and then reconnecting it or turning it off and then on.") ) elif reason == ErrorReason.UNPAIR: title = _("Unpairing failed") text = ( _("Failed to unpair %{device} from %{receiver}.").format( device=object_.name, receiver=object_.receiver.name, ) + "\n\n" + _("The receiver returned an error, with no further details.") ) else: raise Exception("ui.error_dialog: don't know how to handle (%s, %s)", reason.name, object_) return title, text def _error_dialog(reason: ErrorReason, object_): logger.error("error: %s %s", reason, object_) title, text = _create_error_text(reason, object_) m = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, text) m.set_title(title) m.run() m.destroy() def error_dialog(reason: ErrorReason, object_): GLib.idle_add(_error_dialog, reason, object_) _task_runner = None def start_async(): global _task_runner _task_runner = TaskRunner("AsyncUI") _task_runner.start() def stop_async(): global _task_runner _task_runner.stop() _task_runner = None def ui_async(function, *args, **kwargs): """Runs a function asynchronously.""" if _task_runner: _task_runner(function, *args, **kwargs) Solaar-1.1.20/lib/solaar/ui/config_panel.py000066400000000000000000001420461522022367600204720ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import logging from enum import Enum from threading import Timer import gi from logitech_receiver import hidpp20 from logitech_receiver import settings from logitech_receiver import settings_templates from solaar.i18n import _ from solaar.i18n import ngettext from .common import ui_async gi.require_version("Gtk", "3.0") from gi.repository import Gdk # NOQA: E402 from gi.repository import GLib # NOQA: E402 from gi.repository import Gtk # NOQA: E402 logger = logging.getLogger(__name__) class GtkSignal(Enum): ACTIVATE = "activate" CHANGED = "changed" CLICKED = "clicked" MATCH_SELECTED = "match_selected" NOTIFY_ACTIVE = "notify::active" TOGGLED = "toggled" VALUE_CHANGED = "value-changed" COLOR_SET = "color-set" def _read_async(setting, force_read, sbox, device_is_online, sensitive): def _do_read(s, force, sb, online, sensitive): try: v = s.read(not force) except Exception as e: v = None logger.warning("%s: error reading so use None (%s): %s", s.name, s._device, repr(e)) null_okay = not getattr(getattr(s, "_validator", None), "readable", True) GLib.idle_add(_update_setting_item, sb, v, online, sensitive, null_okay, priority=99) ui_async(_do_read, setting, force_read, sbox, device_is_online, sensitive) def _write_async(setting, value, sbox, sensitive=True, key=None): def _do_write(_s, v, sb, key): try: if key is None: v = setting.write(v) else: v = setting.write_key_value(key, v) v = {key: v} except Exception: v = None if sb: GLib.idle_add(_update_setting_item, sb, v, True, sensitive, priority=99) if sbox: sbox._control.set_sensitive(False) sbox._failed.set_visible(False) sbox._spinner.set_visible(True) sbox._spinner.start() ui_async(_do_write, setting, value, sbox, key) class ComboBoxText(Gtk.ComboBoxText): def get_value(self): return int(self.get_active_id()) def set_value(self, value): return self.set_active_id(str(int(value))) class Scale(Gtk.Scale): def get_value(self): return int(super().get_value()) class Control: def __init__(self, **kwargs): self.sbox = None self.delegate = None def init(self, sbox, delegate): self.sbox = sbox self.delegate = delegate if delegate else self def changed(self, *args): if self.get_sensitive(): self.delegate.update() def update(self): _write_async(self.sbox.setting, self.get_value(), self.sbox) def layout(self, sbox, label, change, spinner, failed): sbox.pack_start(label, False, False, 0) sbox.pack_end(change, False, False, 0) fill = sbox.setting.kind == settings.Kind.RANGE or sbox.setting.kind == settings.Kind.HETERO sbox.pack_end(self, fill, fill, 0) sbox.pack_end(spinner, False, False, 0) sbox.pack_end(failed, False, False, 0) return self class ToggleControl(Gtk.Switch, Control): def __init__(self, sbox, delegate=None): super().__init__(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER) self.init(sbox, delegate) self.connect(GtkSignal.NOTIFY_ACTIVE.value, self.changed) def set_value(self, value): if value is not None: self.set_state(value) def get_value(self): return self.get_state() class SliderControl(Gtk.Scale, Control): def __init__(self, sbox, delegate=None): super().__init__(halign=Gtk.Align.FILL) self.init(sbox, delegate) self.timer = None self.set_range(*self.sbox.setting.range) self.set_round_digits(0) self.set_digits(0) self.set_increments(1, 5) # Halving tick marks are an intensity-slider feature only. if self.sbox.setting.name == "brightness_control": validator = getattr(self.sbox.setting, "_validator", None) steps = getattr(validator, "steps", 0) if validator is not None else 0 if steps: for mark in settings_templates.halving_marks(validator.max_value, steps): self.add_mark(mark, Gtk.PositionType.BOTTOM, None) self.connect(GtkSignal.VALUE_CHANGED.value, self.changed) def set_value(self, value): if isinstance(value, dict): value = next(iter(value.values())) return super().set_value(value) def get_value(self): return int(super().get_value()) def changed(self, *args): if self.get_sensitive(): if self.timer: self.timer.cancel() self.timer = Timer(0.5, lambda: GLib.idle_add(self.do_change)) self.timer.start() def do_change(self): self.timer.cancel() self.update() def _create_choice_control(sbox, delegate=None, choices=None): if 50 > len(choices if choices else sbox.setting.choices): return ChoiceControlLittle(sbox, choices=choices, delegate=delegate) else: return ChoiceControlBig(sbox, choices=choices, delegate=delegate) # GTK boxes have property lists, but the keys must be strings class ChoiceControlLittle(Gtk.ComboBoxText, Control): def __init__(self, sbox, delegate=None, choices=None): super().__init__(halign=Gtk.Align.FILL) self.init(sbox, delegate) self.choices = choices if choices is not None else sbox.setting.choices for entry in self.choices: self.append(str(int(entry)), str(entry)) self.connect(GtkSignal.CHANGED.value, self.changed) def get_value(self): return int(self.get_active_id()) if self.get_active_id() is not None else None def set_value(self, value): if value is not None: self.set_active_id(str(int(value))) def get_choice(self): id = self.get_value() return next((x for x in self.choices if x == id), None) def set_choices(self, choices): self.remove_all() for choice in choices: self.append(str(int(choice)), _(str(choice))) class ChoiceControlBig(Gtk.Entry, Control): def __init__(self, sbox, delegate=None, choices=None): super().__init__(halign=Gtk.Align.FILL) self.init(sbox, delegate) self.choices = choices if choices is not None else sbox.setting.choices self.value = None self.set_width_chars(max([len(str(x)) for x in self.choices]) + 5) liststore = Gtk.ListStore(int, str) for v in self.choices: liststore.append((int(v), str(v))) completion = Gtk.EntryCompletion() completion.set_model(liststore) def norm(s): return s.replace("_", "").replace(" ", "").lower() completion.set_match_func(lambda completion, key, it: norm(key) in norm(completion.get_model()[it][1])) completion.set_text_column(1) self.set_completion(completion) self.connect(GtkSignal.CHANGED.value, self.changed) self.connect(GtkSignal.ACTIVATE.value, self.activate) completion.connect(GtkSignal.MATCH_SELECTED.value, self.select) def get_value(self): choice = self.get_choice() return int(choice) if choice is not None else None def set_value(self, value): if value is not None: self.set_text(str(next((x for x in self.choices if x == value), None))) def get_choice(self): key = self.get_text() return next((x for x in self.choices if x == key), None) def set_choices(self, choices): self.choices = choices def changed(self, *args): self.value = self.get_choice() icon = "dialog-warning" if self.value is None else "dialog-question" if self.get_sensitive() else "" self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) tooltip = _("Incomplete") if self.value is None else _("Complete - ENTER to change") self.set_icon_tooltip_text(Gtk.EntryIconPosition.SECONDARY, tooltip) def activate(self, *_args): if self.value is not None and self.get_sensitive(): self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "") self.delegate.update() def select(self, _completion, model, iter): self.set_value(model.get(iter, 0)[0]) if self.value and self.get_sensitive(): self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, "") self.delegate.update() class MapChoiceControl(Gtk.HBox, Control): def __init__(self, sbox, delegate=None): super().__init__(homogeneous=False, spacing=6) self.init(sbox, delegate) self.keyBox = Gtk.ComboBoxText() for entry in sbox.setting.choices: self.keyBox.append(str(int(entry)), _(str(entry))) self.keyBox.set_active(0) key_choice = int(self.keyBox.get_active_id()) self.value_choices = self.sbox.setting.choices[key_choice] self.valueBox = _create_choice_control(sbox.setting, choices=self.value_choices, delegate=self) self.pack_start(self.keyBox, False, False, 0) self.pack_end(self.valueBox, False, False, 0) self.keyBox.connect(GtkSignal.CHANGED.value, self.map_value_notify_key) def get_value(self): key_choice = int(self.keyBox.get_active_id()) if key_choice is not None and self.valueBox.get_value() is not None: return self.valueBox.get_value() def set_value(self, value): if value is None: return self.valueBox.set_sensitive(self.get_sensitive()) key = int(self.keyBox.get_active_id()) if value.get(key) is not None: self.valueBox.set_value(value.get(key)) self.valueBox.set_sensitive(True) def map_populate_value_box(self, key_choice): choices = self.sbox.setting.choices[key_choice] if choices != self.value_choices: self.value_choices = choices self.valueBox.set_choices(choices) current = self.sbox.setting._value.get(key_choice) if self.sbox.setting._value else None if current is not None: self.valueBox.set_value(current) def map_value_notify_key(self, *_args): key_choice = int(self.keyBox.get_active_id()) if self.keyBox.get_sensitive(): self.map_populate_value_box(key_choice) def update(self): key_choice = int(self.keyBox.get_active_id()) value = self.get_value() if value is not None and self.valueBox.get_sensitive() and self.sbox.setting._value.get(key_choice) != value: self.sbox.setting._value[int(key_choice)] = value _write_async(self.sbox.setting, value, self.sbox, key=int(key_choice)) class MultipleControl(Gtk.ListBox, Control): def __init__(self, sbox, change, button_label="...", delegate=None): super().__init__() self.init(sbox, delegate) self.set_selection_mode(Gtk.SelectionMode.NONE) self.set_no_show_all(True) self._showing = True self.setup(sbox.setting) # set up the data and boxes for the sub-controls btn = Gtk.Button(label=button_label) btn.connect(GtkSignal.CLICKED.value, self.toggle_display) self._button = btn hbox = Gtk.HBox(homogeneous=False, spacing=6) hbox.pack_end(change, False, False, 0) hbox.pack_end(btn, False, False, 0) self._header = hbox vbox = Gtk.VBox(homogeneous=False, spacing=6) vbox.pack_start(hbox, True, True, 0) vbox.pack_end(self, True, True, 0) self.vbox = vbox self.toggle_display() _disable_listbox_highlight_bg(self) def layout(self, sbox, label, change, spinner, failed): self._header.pack_start(label, False, False, 0) self._header.pack_end(spinner, False, False, 0) self._header.pack_end(failed, False, False, 0) sbox.pack_start(self.vbox, True, True, 0) sbox._button = self._button return True def toggle_display(self, *_args): self._showing = not self._showing if not self._showing: for c in self.get_children(): c.hide() self.hide() else: self.show() for c in self.get_children(): c.show_all() class MultipleToggleControl(MultipleControl): def setup(self, setting): self._label_control_pairs = [] for k in setting._validator.get_options(): h = Gtk.HBox(homogeneous=False, spacing=0) lbl_text = str(k) lbl_tooltip = None if hasattr(setting, "_labels"): l1, l2 = setting._labels.get(k, (None, None)) lbl_text = l1 if l1 else lbl_text lbl_tooltip = l2 if l2 else lbl_tooltip lbl = Gtk.Label(label=lbl_text) h.set_tooltip_text(lbl_tooltip or " ") control = Gtk.Switch() control._setting_key = int(k) control.connect(GtkSignal.NOTIFY_ACTIVE.value, self.toggle_notify) h.pack_start(lbl, False, False, 0) h.pack_end(control, False, False, 0) lbl.set_margin_start(30) self.add(h) self._label_control_pairs.append((lbl, control)) def toggle_notify(self, switch, _active): if switch.get_sensitive(): key = switch._setting_key new_state = switch.get_state() if self.sbox.setting._value[key] != new_state: self.sbox.setting._value[key] = new_state _write_async(self.sbox.setting, new_state, self.sbox, key=int(key)) def set_value(self, value): if value is None: return active = 0 total = len(self._label_control_pairs) to_join = [] for lbl, elem in self._label_control_pairs: v = value.get(elem._setting_key, None) if v is not None: elem.set_state(v) if elem.get_state(): active += 1 to_join.append(f"{lbl.get_text()}: {str(elem.get_state())}") b = ", ".join(to_join) self._button.set_label(f"{active} / {total}") self._button.set_tooltip_text(b) class MultipleRangeControl(MultipleControl): def setup(self, setting): self._items = [] for item in setting._validator.items: lbl_text = str(item) lbl_tooltip = None if hasattr(setting, "_labels"): l1, l2 = setting._labels.get(int(item), (None, None)) lbl_text = l1 if l1 else lbl_text lbl_tooltip = l2 if l2 else lbl_tooltip item_lbl = Gtk.Label(label=lbl_text) self.add(item_lbl) self.set_tooltip_text(lbl_tooltip or " ") item_lb = Gtk.ListBox() item_lb.set_selection_mode(Gtk.SelectionMode.NONE) item_lb._sub_items = [] for sub_item in setting._validator.sub_items[item]: h = Gtk.HBox(homogeneous=False, spacing=20) lbl_text = str(sub_item) lbl_tooltip = None if hasattr(setting, "_labels_sub"): l1, l2 = setting._labels_sub.get(str(sub_item), (None, None)) lbl_text = l1 if l1 else lbl_text lbl_tooltip = l2 if l2 else lbl_tooltip sub_item_lbl = Gtk.Label(label=lbl_text) h.set_tooltip_text(lbl_tooltip or " ") h.pack_start(sub_item_lbl, False, False, 0) sub_item_lbl.set_margin_start(30) if sub_item.widget == "Scale": control = Gtk.Scale.new_with_range( Gtk.Orientation.HORIZONTAL, sub_item.minimum, sub_item.maximum, 1, ) control.set_round_digits(0) control.set_digits(0) h.pack_end(control, True, True, 0) elif sub_item.widget == "SpinButton": control = Gtk.SpinButton.new_with_range(sub_item.minimum, sub_item.maximum, 1) control.set_digits(0) h.pack_end(control, False, False, 0) else: raise NotImplementedError control.connect(GtkSignal.VALUE_CHANGED.value, self.changed, item, sub_item) item_lb.add(h) h._setting_sub_item = sub_item h._label, h._control = sub_item_lbl, control item_lb._sub_items.append(h) item_lb._setting_item = item _disable_listbox_highlight_bg(item_lb) self.add(item_lb) self._items.append(item_lb) def changed(self, control, item, sub_item): if control.get_sensitive(): if hasattr(control, "_timer"): control._timer.cancel() control._timer = Timer(0.5, lambda: GLib.idle_add(self._write, control, item, sub_item)) control._timer.start() def _write(self, control, item, sub_item): control._timer.cancel() delattr(control, "_timer") new_state = int(control.get_value()) if self.sbox.setting._value[int(item)][str(sub_item)] != new_state: self.sbox.setting._value[int(item)][str(sub_item)] = new_state _write_async(self.sbox.setting, self.sbox.setting._value[int(item)], self.sbox, key=int(item)) def set_value(self, value): if value is None: return b = "" n = 0 for ch in self._items: item = ch._setting_item v = value.get(int(item), None) if v is not None: b += f"{str(item)}: (" to_join = [] for c in ch._sub_items: sub_item = c._setting_sub_item try: sub_item_value = v[str(sub_item)] except KeyError: sub_item_value = c._control.get_value() c._control.set_value(sub_item_value) n += 1 to_join.append(f"{str(sub_item)}={sub_item_value}") b += ", ".join(to_join) + ") " lbl_text = ngettext("%d value", "%d values", n) % n self._button.set_label(lbl_text) self._button.set_tooltip_text(b) class PackedRangeControl(MultipleRangeControl): def setup(self, setting): self._items = [] validator = setting._validator for item in range(validator.count): h = Gtk.HBox(homogeneous=False, spacing=0) lbl = Gtk.Label(label=str(validator.keys[item])) control = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, validator.min_value, validator.max_value, 1) control.set_round_digits(0) control.set_digits(0) control.connect(GtkSignal.VALUE_CHANGED.value, self.changed, validator.keys[item]) h.pack_start(lbl, False, False, 0) h.pack_end(control, True, True, 0) h._setting_item = validator.keys[item] h.control = control lbl.set_margin_start(30) self.add(h) self._items.append(h) def changed(self, control, item): if control.get_sensitive(): if hasattr(control, "_timer"): control._timer.cancel() control._timer = Timer(0.5, lambda: GLib.idle_add(self._write, control, item)) control._timer.start() def _write(self, control, item): control._timer.cancel() delattr(control, "_timer") new_state = int(control.get_value()) if self.sbox.setting._value[int(item)] != new_state: self.sbox.setting._value[int(item)] = new_state _write_async(self.sbox.setting, self.sbox.setting._value[int(item)], self.sbox, key=int(item)) def set_value(self, value): if value is None: return b = "" n = len(self._items) for h in self._items: item = h._setting_item v = value.get(int(item), None) if v is not None: h.control.set_value(v) else: v = self.sbox.setting._value[int(item)] b += f"{str(item)}: ({str(v)}) " lbl_text = ngettext("%d value", "%d values", n) % n self._button.set_label(lbl_text) self._button.set_tooltip_text(b) class GraphicEQControl(MultipleControl): def setup(self, setting): self._items = [] validator = setting._validator row = Gtk.ListBoxRow() hbox = Gtk.HBox(homogeneous=True, spacing=8) for item in range(validator.count): vbox = Gtk.VBox(homogeneous=False, spacing=2) scale = Gtk.Scale.new_with_range(Gtk.Orientation.VERTICAL, validator.min_value, validator.max_value, 1) scale.set_inverted(True) scale.set_round_digits(0) scale.set_digits(0) scale.set_draw_value(True) scale.connect("format-value", lambda s, v: f"{int(v)} dB") scale.set_has_origin(True) scale.set_size_request(-1, 150) scale.add_mark(0, Gtk.PositionType.LEFT, "0") scale.connect(GtkSignal.VALUE_CHANGED.value, self._changed, validator.keys[item]) lbl = Gtk.Label(label=str(validator.keys[item])) lbl.set_line_wrap(True) lbl.set_justify(Gtk.Justification.CENTER) vbox.pack_start(scale, True, True, 0) vbox.pack_end(lbl, False, False, 0) vbox._setting_item = validator.keys[item] vbox.control = scale hbox.pack_start(vbox, True, True, 0) self._items.append(vbox) row.add(hbox) self.add(row) def _changed(self, control, item): if control.get_sensitive(): if hasattr(control, "_timer"): control._timer.cancel() control._timer = Timer(0.5, lambda: GLib.idle_add(self._write, control, item)) control._timer.start() def _write(self, control, item): control._timer.cancel() delattr(control, "_timer") new_state = int(control.get_value()) value = self.sbox.setting._value if not isinstance(value, dict): return if value.get(int(item)) != new_state: value[int(item)] = new_state _write_async(self.sbox.setting, value[int(item)], self.sbox, key=int(item)) def set_value(self, value): if value is None: return b = "" n = len(self._items) stored = self.sbox.setting._value if isinstance(self.sbox.setting._value, dict) else {} for vbox in self._items: item = vbox._setting_item v = value.get(int(item)) if v is not None: vbox.control.set_value(v) else: v = stored.get(int(item), 0) b += f"{str(item)}: ({str(v)}) " lbl_text = ngettext("%d value", "%d values", n) % n self._button.set_label(lbl_text) self._button.set_tooltip_text(b) # control with an ID key that determines what else to show class _HeteroToggleSwitch(Gtk.Switch): """Gtk.Switch with int-valued get/set_value for HeteroKeyControl. Maps switch True/False to the field's wire on/off integer values so the surrounding control machinery (changed handler, get_value, set_value) can stay int-based like every other field kind. """ def __init__(self, on_value: int = 1, off_value: int = 2, **kwargs): super().__init__(**kwargs) self._on = int(on_value) self._off = int(off_value) def get_value(self) -> int: return self._on if self.get_state() else self._off def set_value(self, value) -> None: self.set_state(int(value) == self._on) class HeteroKeyControl(Gtk.HBox, Control): def __init__(self, sbox, delegate=None): super().__init__(homogeneous=False, spacing=6) self.init(sbox, delegate) self._items = {} for item in sbox.setting.possible_fields: if item["label"]: item_lblbox = Gtk.Label(label=item["label"]) self.pack_start(item_lblbox, False, False, 0) item_lblbox.set_visible(False) else: item_lblbox = None item_box = ComboBoxText() if item["kind"] == settings.Kind.CHOICE: for entry in item["choices"]: item_box.append(str(int(entry)), str(entry)) item_box.set_active(0) item_box.connect(GtkSignal.CHANGED.value, self.changed) self.pack_start(item_box, False, False, 0) elif item["kind"] == settings.Kind.TOGGLE: # Right-align like standard TOGGLE settings — pack_end so the # switch hugs the right edge while other fields stay left. item_box = _HeteroToggleSwitch( on_value=item.get("on_value", 1), off_value=item.get("off_value", 2), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, ) item_box.connect(GtkSignal.NOTIFY_ACTIVE.value, self.changed) self.pack_end(item_box, False, False, 0) elif item["kind"] == settings.Kind.COLOR: item_box = Gtk.ColorButton() item_box.connect(GtkSignal.COLOR_SET.value, self.changed) self.pack_start(item_box, False, False, 0) elif item["kind"] == settings.Kind.RANGE: item_box = Scale() item_box.set_range(item["min"], item["max"]) item_box.set_round_digits(0) item_box.set_digits(0) item_box.set_increments(1, 5) # Halving tick marks are an intensity-slider feature only. if item.get("halving") and str(item.get("name")) == str(hidpp20.LEDParam.intensity): steps = getattr(sbox.setting._device, "_brightness_steps", 0) or settings_templates.auto_step_count( item["max"] ) for mark in settings_templates.halving_marks(item["max"], steps): item_box.add_mark(mark, Gtk.PositionType.BOTTOM, None) if item.get("display_seconds", False): item_box.connect("format-value", lambda _s, v: f"{int(v) / 1000:.2f}s") item_box.connect(GtkSignal.VALUE_CHANGED.value, self.changed) self.pack_start(item_box, True, True, 0) item_box.set_visible(False) self._items[str(item["name"])] = (item_lblbox, item_box) def get_value(self): result = {} for k, (_lblbox, box) in self._items.items(): if isinstance(box, Gtk.ColorButton): rgba = box.get_rgba() r = int(rgba.red * 255) g = int(rgba.green * 255) b = int(rgba.blue * 255) result[str(k)] = (r << 16) | (g << 8) | b else: result[str(k)] = box.get_value() data_class = getattr(self.sbox.setting._validator, "data_class", hidpp20.LEDEffectSetting) result = data_class(**result) return result def set_value(self, value): self.set_sensitive(False) id_ = value.ID if value is not None else 0 self._apply_id_ranges(id_) if value is not None: for k, v in value.__dict__.items(): if k in self._items: (lblbox, box) = self._items[k] if isinstance(box, Gtk.ColorButton): rgba = Gdk.RGBA() color_string = f"#{v:06X}" # e.g. "#FF0000" rgba.parse(color_string) box.set_rgba(rgba) else: box.set_value(v) self.setup_visibles(id_) def setup_visibles(self, id_): fields = self.sbox.setting.fields_map[id_][1] if id_ in self.sbox.setting.fields_map else {} for name, (lblbox, box) in self._items.items(): visible = name in fields or name == "ID" if lblbox: lblbox.set_visible(visible) box.set_visible(visible) def changed(self, control, *_args): # *_args swallows the extra GParamSpec passed by Gtk.Switch's # "notify::active" signal — other field signals pass just (widget,). if self.get_sensitive() and control.get_sensitive(): if "ID" in self._items and control == self._items["ID"][1]: new_id = int(self._items["ID"][1].get_value()) self.setup_visibles(new_id) self._apply_id_ranges(new_id) self._apply_id_defaults(new_id) if hasattr(control, "_timer"): control._timer.cancel() control._timer = Timer(0.3, lambda: GLib.idle_add(self._write, control)) control._timer.start() def _apply_id_ranges(self, id_): """Reset every RANGE widget to its field's global min/max, then apply per-effect overrides from fields_map[id_][3]. Reset-first ensures switching from an override (e.g. Ripple 2-200) to an effect without one restores the global range instead of inheriting the narrow one.""" fields_map = getattr(self.sbox.setting, "fields_map", None) entry = fields_map.get(id_) if fields_map else None ranges = entry[3] if entry and len(entry) > 3 else {} for field in self.sbox.setting.possible_fields: if field.get("kind") != settings.Kind.RANGE: continue name = str(field["name"]) if name not in self._items: continue _, box = self._items[name] lo, hi = ranges.get(field["name"], (field.get("min", 0), field.get("max", 0))) box.set_range(lo, hi) def _apply_id_defaults(self, id_): """Apply fields_map[id_][2] defaults to RANGE widgets sitting at min.""" fields_map = getattr(self.sbox.setting, "fields_map", None) if not fields_map or id_ not in fields_map: return entry = fields_map[id_] if len(entry) < 3: return defaults = entry[2] ranges = entry[3] if len(entry) > 3 else {} field_by_name = {str(f["name"]): f for f in self.sbox.setting.possible_fields} for param_name, default_value in defaults.items(): name = str(param_name) if name not in self._items: continue field = field_by_name.get(name) if field is None or field.get("kind") != settings.Kind.RANGE: continue _, box = self._items[name] effective_min = ranges[param_name][0] if param_name in ranges else field.get("min", 0) if box.get_value() == effective_min: box.set_value(default_value) def _write(self, control): control._timer.cancel() delattr(control, "_timer") new_state = self.get_value() if self.sbox.setting._value != new_state: _write_async(self.sbox.setting, new_state, self.sbox) _allowables_icons = {True: "changes-allow", False: "changes-prevent", settings.SENSITIVITY_IGNORE: "dialog-error"} _allowables_tooltips = { True: _("Changes allowed"), False: _("No changes allowed"), settings.SENSITIVITY_IGNORE: _("Ignore this setting"), } _next_allowable = {True: False, False: settings.SENSITIVITY_IGNORE, settings.SENSITIVITY_IGNORE: True} _icons_allowables = {v: k for k, v in _allowables_icons.items()} # clicking on the lock icon changes from changeable to unchangeable to ignore # Settings whose operation depends on LED Control being set to Solaar. # Zone settings (rgb_zone_*) are matched by prefix because their name carries # the zone index (rgb_zone_1, rgb_zone_2, ...). _SW_CONTROL_DEPENDENT_NAMES = ("rgb_idle_timeout", "rgb_idle_effect", "rgb_sleep_timeout") _SW_CONTROL_DEPENDENT_PREFIXES = ("rgb_zone_",) # headset_led_control = whether Solaar holds the live-coloring claim (off lets # another app drive the LEDs). The 0x0620 per-zone painting and the 0x0621 # onboard effect are both live LED control, so both need the claim; per-zone # additionally needs the onboard effect on Static (the per-key analog of # needs-rgb_control + zone-Static). The 0x0622 signature effects are stored # settings (startup/shutdown colors) and stay ungated. _HEADSET_LED_DEPENDENT_NAMES = ("headset_per_zone_lighting", "headset-onboard-effect") def _sw_control_blocked(device): """True when LED Control is not Solaar. Reads from setting._value first, then the persister, so the gate is right at panel load before live reads have populated. Accepts either the current bool (BooleanValidator) or the legacy int 3/0 (older ChoicesValidator persister entries).""" persister = getattr(device, "persister", None) if persister is None: return False value = None for s in getattr(device, "settings", []) or []: if s.name == "rgb_control": value = s._value break if value is None: value = persister.get("rgb_control") if value is None: return False # Solaar = bool True or legacy int 3; everything else (False, 0, …) blocks. return value not in (True, 3) def _headset_led_blocked(device): """True when the headset's LED Control is off (Device/firmware mode). Reads setting._value first, then the persister; accepts the current bool or a legacy int 0/1 from the old ChoicesValidator persister entries.""" persister = getattr(device, "persister", None) if persister is None: return False value = None for s in getattr(device, "settings", []) or []: if s.name == "headset_led_control": value = s._value break if value is None: value = persister.get("headset_led_control") if value is None: return False return value not in (True, 1) def _cluster_effect_blocks_perzone(device): """True when the headset's 0x0621 onboard effect is not Fixed — a non-Fixed cluster animation masks the per-zone buffer. Mirrors `_zone_effect_blocks_perkey`. False when the device has no onboard-effect setting (nothing to mask against).""" persister = getattr(device, "persister", None) value = None for s in getattr(device, "settings", []) or []: if s.name == "headset-onboard-effect": value = s._value if s._value is not None else (persister.get(s.name) if persister else None) break else: return False if value is None: return False return int(getattr(value, "ID", 0)) != 0 def _zone_effect_blocks_perkey(device): """True when any zone effect's saved ID is not Static (0x01) — zone animations mask the per-key buffer regardless of SW control state.""" persister = getattr(device, "persister", None) if persister is None: return False for s in getattr(device, "settings", []) or []: if not s.name.startswith("rgb_zone_"): continue v = s._value if s._value is not None else persister.get(s.name) if v is None: continue if int(getattr(v, "ID", 0) or 0) != 0x01: return True return False def _set_row_sensitive(device, name, can_function): """Apply sensitivity to a single setting's control row. Combines the user's lock-icon opt-in (persister sensitivity) with the can-function gate so neither alone can override the other.""" device_id = (device.receiver.path if device.receiver else device.path, device.number) sbox = _items.get((device_id[0], device_id[1], name)) if sbox is None or not hasattr(sbox, "_control"): return persister = getattr(device, "persister", None) user_allowed = persister.get_sensitivity(name) if persister else True sbox._control.set_sensitive(user_allowed is True and can_function) def _gate_blocks(device, name): """Single source of truth for "is this setting's row gated off?". Used by `_apply_rgb_gates` to grey rows and by `_update_setting_item` so async-read completions can't undo the grey-out when their callbacks land later.""" if name in _SW_CONTROL_DEPENDENT_NAMES or any(name.startswith(p) for p in _SW_CONTROL_DEPENDENT_PREFIXES): return _sw_control_blocked(device) if name == "per-key-lighting": return _sw_control_blocked(device) or _zone_effect_blocks_perkey(device) if name in _HEADSET_LED_DEPENDENT_NAMES: if _headset_led_blocked(device): return True # Per-zone painting additionally needs the onboard effect on Static. return name == "headset_per_zone_lighting" and _cluster_effect_blocks_perzone(device) return False def _apply_rgb_gates(device): """Grey out RGB settings whose prerequisites aren't met. Visual-only: leaves persister _sensitive flags (user lock-icon opt-ins) intact. - rgb_zone_* and rgb_idle_*/rgb_sleep_timeout need LED Control = Solaar (rgb_control == 3). - per-key-lighting needs LED Control = Solaar AND every zone effect on Static (0x01), because non-Static zone animations mask per-key writes. """ for s in getattr(device, "settings", []) or []: name = s.name if ( name in _SW_CONTROL_DEPENDENT_NAMES or any(name.startswith(p) for p in _SW_CONTROL_DEPENDENT_PREFIXES) or name == "per-key-lighting" or name in _HEADSET_LED_DEPENDENT_NAMES ): _set_row_sensitive(device, name, not _gate_blocks(device, name)) def _change_click(button, sbox): icon = button.get_children()[0] icon_name, _ = icon.get_icon_name() allowed = _icons_allowables.get(icon_name, True) new_allowed = _next_allowable[allowed] sbox._control.set_sensitive(new_allowed is True) _change_icon(new_allowed, icon) if sbox.setting._device.persister: # remember the new setting sensitivity sbox.setting._device.persister.set_sensitivity(sbox.setting.name, new_allowed) if allowed == settings.SENSITIVITY_IGNORE: # update setting if it was being ignored setting = next((s for s in sbox.setting._device.settings if s.name == sbox.setting.name), None) if setting: persisted = sbox.setting._device.persister.get(setting.name) if sbox.setting._device.persister else None if setting.persist and persisted is not None: _write_async(setting, persisted, sbox) else: _read_async(setting, True, sbox, bool(sbox.setting._device.online), sbox._control.get_sensitive()) elif new_allowed == settings.SENSITIVITY_IGNORE and sbox.setting.name == "per-key-lighting": # User just opted out of per-key lighting. The firmware effect engine # is currently in its OOR "direct mode" slot showing the per-key buffer # (entered when the prep sequence wrote effectIdx=numEffects via # SetEffectByIndex on 0x8071). Writing a regular in-range effectIdx # with persist=1 displaces that slot and the saved zone effect becomes # the visible layer again. See LOGITECH_HIDPP2_PROTOCOL.md # "Per-key prep sequence" and 0x8071 SetEffectByIndex persist=1 # requirement. device = sbox.setting._device for s in device.settings: if s.name.startswith("rgb_zone_") and s._value is not None: _write_async(s, s._value, None) break # one zone-effect write is enough to flip the engine if sbox.setting.name.startswith("rgb_zone_"): # Toggling zone-effect sensitivity changes the effective base color # for per-key unset cells (zone color ↔ black). When per-key is # opted-in, repaint it so the unset cells pick up the new base. from logitech_receiver import rgb_power device = sbox.setting._device perkey, has_paint = rgb_power.perkey_has_paint(device) if has_paint: _write_async(perkey, perkey._value, None) # The lock icon on rgb_control, any zone, per-key, or headset_led_control # can change whether a dependent row is functional — re-evaluate the gate. name = sbox.setting.name if name in ("rgb_control", "per-key-lighting", "headset_led_control", "headset-onboard-effect") or name.startswith( "rgb_zone_" ): _apply_rgb_gates(sbox.setting._device) return True def _change_icon(allowed, icon): if allowed in _allowables_icons: icon._allowed = allowed icon.set_from_icon_name(_allowables_icons[allowed], Gtk.IconSize.LARGE_TOOLBAR) icon.set_tooltip_text(_allowables_tooltips[allowed]) def _create_sbox(s, _device): if not s.display: return sbox = Gtk.HBox(homogeneous=False, spacing=6) sbox.setting = s sbox.kind = s.kind if s.description: sbox.set_tooltip_text(s.description) lbl = Gtk.Label(label=s.label) label = Gtk.EventBox() label.add(lbl) spinner = Gtk.Spinner() spinner.set_tooltip_text(_("Working") + "...") sbox._spinner = spinner failed = Gtk.Image.new_from_icon_name("dialog-warning", Gtk.IconSize.SMALL_TOOLBAR) failed.set_tooltip_text(_("Read/write operation failed.")) sbox._failed = failed change_icon = Gtk.Image.new_from_icon_name("changes-prevent", Gtk.IconSize.LARGE_TOOLBAR) sbox._change_icon = change_icon _change_icon(False, change_icon) change = Gtk.Button() change.set_relief(Gtk.ReliefStyle.NONE) change.add(change_icon) change.set_sensitive(True) change.connect(GtkSignal.CLICKED.value, _change_click, sbox) editor_path = getattr(s, "editor_class", None) if editor_path: try: mod_name, _sep, cls_name = editor_path.partition(":") import importlib mod = importlib.import_module(mod_name) cls = getattr(mod, cls_name) control = cls(sbox) except Exception as e: logger.warning("setting %s editor_class %r failed (%s); falling back to default", s.name, editor_path, repr(e)) control = None else: control = None if control is not None: pass elif s.kind == settings.Kind.TOGGLE: control = ToggleControl(sbox) elif s.kind == settings.Kind.RANGE: control = SliderControl(sbox) elif s.kind == settings.Kind.CHOICE: control = _create_choice_control(sbox) elif s.kind == settings.Kind.MAP_CHOICE: control = MapChoiceControl(sbox) elif s.kind == settings.Kind.MULTIPLE_TOGGLE: control = MultipleToggleControl(sbox, change) elif s.kind == settings.Kind.MULTIPLE_RANGE: control = MultipleRangeControl(sbox, change) elif s.kind == settings.Kind.PACKED_RANGE: control = PackedRangeControl(sbox, change) elif s.kind == settings.Kind.GRAPHIC_EQ: control = GraphicEQControl(sbox, change) elif s.kind == settings.Kind.HETERO: control = HeteroKeyControl(sbox, change) else: logger.warning("setting %s display not implemented", s.label) return None control.set_sensitive(False) # the first read will enable it control.layout(sbox, label, change, spinner, failed) sbox._control = control sbox.show_all() spinner.start() # the first read will stop it failed.set_visible(False) return sbox def _update_setting_item(sbox, value, is_online=True, sensitive=True, null_okay=False): sbox._spinner.stop() sensitive = sbox._change_icon._allowed if sensitive is None else sensitive name = sbox.setting.name can_function = not _gate_blocks(sbox.setting._device, name) if value is None and not null_okay: sbox._control.set_sensitive(sensitive is True and can_function) _change_icon(sensitive, sbox._change_icon) sbox._failed.set_visible(is_online) return sbox._failed.set_visible(False) sbox._control.set_sensitive(False) try: # a call was producing a TypeError so guard against that sbox._control.set_value(value) except TypeError as e: logger.warning("%s: error setting control value (%s): %s", sbox.setting.name, sbox.setting._device, repr(e)) sbox._control.set_sensitive(sensitive is True and can_function) _change_icon(sensitive, sbox._change_icon) # rgb_control / rgb_zone_* gate per-key; headset_led_control and the # headset-onboard-effect gate the per-zone row — re-evaluate on a change. if name in ("rgb_control", "headset_led_control", "headset-onboard-effect") or name.startswith("rgb_zone_"): _apply_rgb_gates(sbox.setting._device) def _disable_listbox_highlight_bg(lb): colour = Gdk.RGBA() colour.parse("rgba(0,0,0,0)") for child in lb.get_children(): child.override_background_color(Gtk.StateFlags.PRELIGHT, colour) # config panel _box = None _items = {} def create(): global _box assert _box is None _box = Gtk.VBox(homogeneous=False, spacing=4) _box._last_device = None config_scroll = Gtk.ScrolledWindow() config_scroll.add(_box) config_scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) config_scroll.set_shadow_type(Gtk.ShadowType.NONE) # was IN config_scroll.set_size_request(0, 350) # ask for enough vertical space for about eight settings return config_scroll def update(device, is_online=None): assert _box is not None assert device device_id = (device.receiver.path if device.receiver else device.path, device.number) if is_online is None: is_online = bool(device.online) # if the device changed since last update, clear the box first if device_id != _box._last_device: _box.set_visible(False) _box._last_device = device_id # hide controls belonging to other devices for k, sbox in _items.items(): sbox = _items[k] sbox.set_visible(k[0:2] == device_id) for s in device.settings: k = (device_id[0], device_id[1], s.name) if k in _items: sbox = _items[k] sbox.setting = s # use setting from current version of device else: sbox = _create_sbox(s, device) if sbox is None: continue _items[k] = sbox _box.pack_start(sbox, False, False, 0) sensitive = device.persister.get_sensitivity(s.name) if device.persister else True _read_async(s, False, sbox, is_online, sensitive) _apply_rgb_gates(device) _box.set_visible(True) def clean(device): """Remove the controls for a given device serial. Needed after the device has been unpaired. """ assert _box is not None device_id = (device.receiver.path if device.receiver else device.path, device.number) for k in list(_items.keys()): if k[0:2] == device_id: _box.remove(_items[k]) del _items[k] def destroy(): global _box _box = None _items.clear() def change_setting(device, setting, values): """External interface to change a setting and have the GUI show the change""" assert device == setting._device GLib.idle_add(_change_setting, device, setting, values, priority=99) def _change_setting(device, setting, values): device_path = device.receiver.path if device.receiver else device.path if (device_path, device.number, setting.name) in _items: sbox = _items[(device_path, device.number, setting.name)] else: sbox = None _write_async(setting, values[-1], sbox, None, key=values[0] if len(values) > 1 else None) def record_setting(device, setting, values): """External interface to have the GUI show a change to a setting. Doesn't write to the device""" GLib.idle_add(_record_setting, device, setting, values, priority=99) def _record_setting(device, setting_class, values): logger.debug("on %s changing setting %s to %s", device, setting_class.name, values) setting = next((s for s in device.settings if s.name == setting_class.name), None) if setting is None: logger.debug( "No setting for %s found on %s when trying to record a change made elsewhere", setting_class.name, device, ) if setting: assert device == setting._device if len(values) > 1: setting.update_key_value(values[0], values[-1]) value = {values[0]: values[-1]} else: setting.update(values[-1]) value = values[-1] device_path = device.receiver.path if device.receiver else device.path if (device_path, device.number, setting.name) in _items: sbox = _items[(device_path, device.number, setting.name)] if sbox: _update_setting_item(sbox, value, sensitive=None) Solaar-1.1.20/lib/solaar/ui/desktop_notifications.py000066400000000000000000000112441522022367600224430ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import importlib # Optional desktop notifications. import logging from solaar import NAME from solaar.i18n import _ from . import icons logger = logging.getLogger(__name__) def notifications_available(): """Checks if notification service is available.""" notifications_supported = False try: import gi gi.require_version("Notify", "0.7") importlib.util.find_spec("gi.repository.GLib") importlib.util.find_spec("gi.repository.Notify") notifications_supported = True except ValueError as e: logger.warning(f"Notification service is not available: {e}") return notifications_supported available = notifications_available() if available: from gi.repository import GLib from gi.repository import Notify # cache references to shown notifications here, so if another status comes # while its notification is still visible we don't create another one _notifications = {} def init(): """Initialize desktop notifications.""" global available if available: if not Notify.is_initted(): logger.info("starting desktop notifications") try: return Notify.init(NAME.lower()) except Exception: logger.exception("initializing desktop notifications") available = False return available and Notify.is_initted() def uninit(): """Stop desktop notifications.""" if available and Notify.is_initted(): logger.info("stopping desktop notifications") _notifications.clear() Notify.uninit() def alert(reason, icon=None): assert reason if available and Notify.is_initted(): n = _notifications.get(NAME.lower()) if n is None: n = _notifications[NAME.lower()] = Notify.Notification() # we need to use the filename here because the notifications daemon # is an external application that does not know about our icon sets icon_file = icons.icon_file(NAME.lower()) if icon is None else icons.icon_file(icon) n.update(NAME.lower(), reason, icon_file) n.set_urgency(Notify.Urgency.NORMAL) n.set_hint("desktop-entry", GLib.Variant("s", NAME.lower())) try: n.show() except Exception: logger.exception("showing %s", n) def show(dev, reason=None, icon=None, progress=None): """Show a notification with title and text. Optionally displays the `progress` integer value in [0, 100] as a progress bar.""" if available and Notify.is_initted(): summary = dev.name # if a notification with same name is already visible, reuse it to avoid spamming n = _notifications.get(summary) if n is None: n = _notifications[summary] = Notify.Notification() if reason: message = reason else: message = _("unspecified reason") # we need to use the filename here because the notifications daemon # is an external application that does not know about our icon sets icon_file = icons.device_icon_file(dev.name, dev.kind) if icon is None else icons.icon_file(icon) n.update(summary, message, icon_file) n.set_urgency(Notify.Urgency.NORMAL) n.set_hint("desktop-entry", GLib.Variant("s", NAME.lower())) if progress: n.set_hint("value", GLib.Variant("i", progress)) try: return n.show() except Exception: logger.exception(f"showing {n}") else: def init(): return False def uninit(): return None # toggle = lambda action: False def alert(reason): return None def show(dev, reason=None): return None Solaar-1.1.20/lib/solaar/ui/diversion_rules.py000066400000000000000000002260361522022367600212640ustar00rootroot00000000000000## Copyright (C) Solaar Contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from __future__ import annotations import dataclasses import logging import string import threading from collections import defaultdict from copy import copy from dataclasses import dataclass from dataclasses import field from enum import Enum from shlex import quote as shlex_quote from typing import Any from typing import Callable from typing import Dict from typing import Optional from gi.repository import Gdk from gi.repository import GObject from gi.repository import Gtk from logitech_receiver import diversion from logitech_receiver.common import NamedInt from logitech_receiver.common import NamedInts from logitech_receiver.common import UnsortedNamedInts from logitech_receiver.settings import Kind from logitech_receiver.settings import Setting from logitech_receiver.settings_templates import SETTINGS from logitech_receiver.settings_validator import Range from solaar.i18n import _ from solaar.ui import rule_actions from solaar.ui import rule_conditions from solaar.ui.rule_base import RuleComponentUI from solaar.ui.rule_base import norm from solaar.ui.rule_conditions import ConditionUI logger = logging.getLogger(__name__) _diversion_dialog = None _rule_component_clipboard = None class GtkSignal(Enum): ACTIVATE = "activate" BUTTON_RELEASE_EVENT = "button-release-event" CHANGED = "changed" CLICKED = "clicked" DELETE_EVENT = "delete-event" KEY_PRESS_EVENT = "key-press-event" NOTIFY_ACTIVE = "notify::active" TOGGLED = "toggled" VALUE_CHANGED = "value_changed" def create_all_settings(all_settings: list[Setting]) -> dict[str, list[Setting]]: settings = {} for s in sorted(all_settings, key=lambda setting: setting.label): if s.name not in settings: settings[s.name] = [s] else: prev_setting = settings[s.name][0] prev_kind = prev_setting.validator_class.kind if prev_kind != s.validator_class.kind: logger.warning( "ignoring setting {} - same name of {}, but different kind ({} != {})".format( s.__name__, prev_setting.__name__, prev_kind, s.validator_class.kind ) ) continue settings[s.name].append(s) return settings ALL_SETTINGS = create_all_settings(SETTINGS) class RuleComponentWrapper(GObject.GObject): def __init__(self, component, level=0, editable=False): self.component = component self.level = level self.editable = editable GObject.GObject.__init__(self) def display_left(self): if isinstance(self.component, diversion.Rule): if self.level == 0: return _("Built-in rules") if not self.editable else _("User-defined rules") if self.level == 1: return " " + _("Rule") return " " + _("Sub-rule") if self.component is None: return _("[empty]") return " " + self.__component_ui().left_label(self.component) def display_right(self): if self.component is None: return "" return self.__component_ui().right_label(self.component) def display_icon(self): if self.component is None: return "" if isinstance(self.component, diversion.Rule) and self.level == 0: return "emblem-system" if not self.editable else "avatar-default" return self.__component_ui().icon_name() def __component_ui(self): return COMPONENT_UI.get(type(self.component), UnsupportedRuleComponentUI) def _create_close_dialog(window: Gtk.Window) -> Gtk.MessageDialog: """Creates rule editor close dialog, when unsaved changes are present.""" dialog = Gtk.MessageDialog( window, type=Gtk.MessageType.QUESTION, title=_("Make changes permanent?"), flags=Gtk.DialogFlags.MODAL, ) dialog.set_default_size(400, 100) dialog.add_buttons( _("Yes"), Gtk.ResponseType.YES, _("No"), Gtk.ResponseType.NO, _("Cancel"), Gtk.ResponseType.CANCEL, ) dialog.set_markup(_("If you choose No, changes will be lost when Solaar is closed.")) return dialog def _create_selected_rule_edit_panel() -> Gtk.Grid: """Creates the edit Condition/Actions panel for a rule. Shows the UI for the selected rule component. """ grid = Gtk.Grid() grid.set_margin_start(10) grid.set_margin_end(10) grid.set_row_spacing(10) grid.set_column_spacing(10) grid.set_halign(Gtk.Align.CENTER) grid.set_valign(Gtk.Align.CENTER) grid.set_size_request(0, 120) return grid def _populate_model( model: Gtk.TreeStore, it: Gtk.TreeIter, rule_component: Any, level: int = 0, pos: int = -1, editable: Optional[bool] = None, ): if isinstance(rule_component, list): for c in rule_component: _populate_model(model, it, c, level=level, pos=pos, editable=editable) if pos >= 0: pos += 1 return if editable is None: editable = model[it][0].editable if it is not None else False if isinstance(rule_component, diversion.Rule): editable = editable or (rule_component.source is not None) wrapped = RuleComponentWrapper(rule_component, level, editable=editable) piter = model.insert(it, pos, (wrapped,)) if isinstance(rule_component, (diversion.Rule, diversion.And, diversion.Or, diversion.Later)): for c in rule_component.components: ed = editable or (isinstance(c, diversion.Rule) and c.source is not None) _populate_model(model, piter, c, level + 1, editable=ed) if len(rule_component.components) == 0: _populate_model(model, piter, None, level + 1, editable=editable) elif isinstance(rule_component, diversion.Not): _populate_model(model, piter, rule_component.component, level + 1, editable=editable) @dataclasses.dataclass class AllowedActions: c: Any copy: bool delete: bool flatten: bool insert: bool insert_only_rule: bool insert_root: bool wrap: bool def allowed_actions(m: Gtk.TreeStore, it: Gtk.TreeIter) -> AllowedActions: row = m[it] wrapped = row[0] c = wrapped.component parent_it = m.iter_parent(it) parent_c = m[parent_it][0].component if wrapped.level > 0 else None can_wrap = wrapped.editable and wrapped.component is not None and wrapped.level >= 2 can_delete = wrapped.editable and not isinstance(parent_c, diversion.Not) and c is not None and wrapped.level >= 1 can_insert = wrapped.editable and not isinstance(parent_c, diversion.Not) and wrapped.level >= 2 can_insert_only_rule = wrapped.editable and wrapped.level == 1 can_flatten = ( wrapped.editable and not isinstance(parent_c, diversion.Not) and isinstance(c, (diversion.Rule, diversion.And, diversion.Or)) and wrapped.level >= 2 and len(c.components) ) can_copy = wrapped.level >= 1 can_insert_root = wrapped.editable and wrapped.level == 0 return AllowedActions( c, can_copy, can_delete, can_flatten, can_insert, can_insert_only_rule, can_insert_root, can_wrap, ) class ActionMenu: def __init__( self, window: Gtk.Window, tree_view: Gtk.TreeView, populate_model_func: Callable, on_update: Callable, ): self.window = window self.tree_view = tree_view self._populate_model_func = populate_model_func self._on_update = on_update def create_menu_event_button_released(self, v, e): if e.button == Gdk.BUTTON_SECONDARY: # right click menu = Gtk.Menu() m, it = v.get_selection().get_selected() enabled_actions = allowed_actions(m, it) for item in self.get_insert_menus(m, it, enabled_actions): menu.append(item) if enabled_actions.flatten: menu.append(self._menu_flatten(m, it)) if enabled_actions.wrap: menu.append(self._menu_wrap(m, it)) menu.append(self._menu_negate(m, it)) if menu.get_children(): menu.append(Gtk.SeparatorMenuItem(visible=True)) if enabled_actions.delete: menu.append(self._menu_cut(m, it)) if enabled_actions.copy and enabled_actions.c is not None: menu.append(self._menu_copy(m, it)) if enabled_actions.insert and _rule_component_clipboard is not None: p = self._menu_paste(m, it) menu.append(p) if enabled_actions.c is None: # just a placeholder p.set_label(_("Paste here")) else: p.set_label(_("Paste above")) p2 = self._menu_paste(m, it, below=True) p2.set_label(_("Paste below")) menu.append(p2) elif enabled_actions.insert_only_rule and isinstance(_rule_component_clipboard, diversion.Rule): p = self._menu_paste(m, it) menu.append(p) if enabled_actions.c is None: p.set_label(_("Paste rule here")) else: p.set_label(_("Paste rule above")) p2 = self._menu_paste(m, it, below=True) p2.set_label(_("Paste rule below")) menu.append(p2) elif enabled_actions.insert_root and isinstance(_rule_component_clipboard, diversion.Rule): p = self._menu_paste(m, m.iter_nth_child(it, 0)) p.set_label(_("Paste rule")) menu.append(p) if menu.get_children() and enabled_actions.delete: menu.append(Gtk.SeparatorMenuItem(visible=True)) if enabled_actions.delete: menu.append(self._menu_delete(m, it)) if menu.get_children(): menu.popup_at_pointer(e) def get_insert_menus(self, m, it, enabled_actions: AllowedActions): items = [] if enabled_actions.insert: ins = self._menu_insert(m, it) items.append(ins) if enabled_actions.c is None: # just a placeholder ins.set_label(_("Insert here")) else: ins.set_label(_("Insert above")) ins2 = self._menu_insert(m, it, below=True) ins2.set_label(_("Insert below")) items.append(ins2) elif enabled_actions.insert_only_rule: ins = self._menu_create_rule(m, it) items.append(ins) if enabled_actions.c is None: ins.set_label(_("Insert new rule here")) else: ins.set_label(_("Insert new rule above")) ins2 = self._menu_create_rule(m, it, below=True) ins2.set_label(_("Insert new rule below")) items.append(ins2) elif enabled_actions.insert_root: ins = self._menu_create_rule(m, m.iter_nth_child(it, 0)) items.append(ins) return items def menu_do_flatten(self, _mitem, m, it): wrapped = m[it][0] c = wrapped.component parent_it = m.iter_parent(it) parent_c = m[parent_it][0].component idx = parent_c.components.index(c) if isinstance(c, diversion.Not): parent_c.components = [*parent_c.components[:idx], c.component, *parent_c.components[idx + 1 :]] children = [next(m[it].iterchildren())[0].component] else: parent_c.components = [*parent_c.components[:idx], *c.components, *parent_c.components[idx + 1 :]] children = [child[0].component for child in m[it].iterchildren()] m.remove(it) self._populate_model_func(m, parent_it, children, level=wrapped.level, pos=idx) new_iter = m.iter_nth_child(parent_it, idx) self.tree_view.expand_row(m.get_path(parent_it), True) self.tree_view.get_selection().select_iter(new_iter) self._on_update() def _menu_flatten(self, m, it): menu_flatten = Gtk.MenuItem(_("Flatten")) menu_flatten.connect(GtkSignal.ACTIVATE.value, self.menu_do_flatten, m, it) menu_flatten.show() return menu_flatten def _menu_do_insert(self, _mitem, m, it, new_c, below=False): wrapped = m[it][0] c = wrapped.component parent_it = m.iter_parent(it) parent_c = m[parent_it][0].component if len(parent_c.components) == 0: # we had only a placeholder idx = 0 else: idx = parent_c.components.index(c) if isinstance(new_c, diversion.Rule) and wrapped.level == 1: new_c.source = diversion._file_path # new rules will be saved to the YAML file idx += int(below) parent_c.components.insert(idx, new_c) self._populate_model_func(m, parent_it, new_c, level=wrapped.level, pos=idx) self._on_update() if len(parent_c.components) == 1: m.remove(it) # remove placeholder in the end new_iter = m.iter_nth_child(parent_it, idx) self.tree_view.get_selection().select_iter(new_iter) if isinstance(new_c, (diversion.Rule, diversion.And, diversion.Or, diversion.Not)): self.tree_view.expand_row(m.get_path(new_iter), True) def _menu_do_insert_new(self, _mitem, m, it, cls, initial_value, below=False): new_c = cls(initial_value, warn=False) return self._menu_do_insert(_mitem, m, it, new_c, below=below) def _menu_insert(self, m, it, below=False): elements = [ _("Insert"), [ (_("Sub-rule"), diversion.Rule, []), (_("Or"), diversion.Or, []), (_("And"), diversion.And, []), [ _("Condition"), [ (_("Feature"), diversion.Feature, rule_conditions.FeatureUI.FEATURES_WITH_DIVERSION[0]), (_("Report"), diversion.Report, 0), (_("Process"), diversion.Process, ""), (_("Mouse process"), diversion.MouseProcess, ""), (_("Modifiers"), diversion.Modifiers, []), (_("Key"), diversion.Key, ""), (_("KeyIsDown"), diversion.KeyIsDown, ""), (_("Active"), diversion.Active, ""), (_("Device"), diversion.Device, ""), (_("Host"), diversion.Host, ""), (_("Setting"), diversion.Setting, [None, "", None]), (_("Test"), diversion.Test, next(iter(diversion.TESTS))), (_("Test bytes"), diversion.TestBytes, [0, 1, 0]), (_("Mouse Gesture"), diversion.MouseGesture, ""), ], ], [ _("Action"), [ (_("Key press"), diversion.KeyPress, "space"), (_("Mouse scroll"), diversion.MouseScroll, [0, 0]), (_("Mouse click"), diversion.MouseClick, ["left", 1]), (_("Set"), diversion.Set, [None, "", None]), (_("Execute"), diversion.Execute, [""]), (_("Later"), diversion.Later, [1]), ], ], ], ] def build(spec): if isinstance(spec, list): # has sub-menu label, children = spec item = Gtk.MenuItem(label) submenu = Gtk.Menu() item.set_submenu(submenu) for child in children: submenu.append(build(child)) return item elif isinstance(spec, tuple): # has click action label, feature, *args = spec item = Gtk.MenuItem(label) args = [a.copy() if isinstance(a, list) else a for a in args] item.connect(GtkSignal.ACTIVATE.value, self._menu_do_insert_new, m, it, feature, *args, below) return item else: return None menu_insert = build(elements) menu_insert.show_all() return menu_insert def _menu_create_rule(self, m, it, below=False) -> Gtk.MenuItem: menu_create_rule = Gtk.MenuItem(_("Insert new rule")) menu_create_rule.connect(GtkSignal.ACTIVATE.value, self._menu_do_insert_new, m, it, diversion.Rule, [], below) menu_create_rule.show() return menu_create_rule def menu_do_delete(self, _mitem, m, it): wrapped = m[it][0] c = wrapped.component parent_it = m.iter_parent(it) parent_c = m[parent_it][0].component idx = parent_c.components.index(c) parent_c.components.pop(idx) if len(parent_c.components) == 0: # placeholder self._populate_model_func(m, parent_it, None, level=wrapped.level) m.remove(it) self.tree_view.get_selection().select_iter(m.iter_nth_child(parent_it, max(0, min(idx, len(parent_c.components) - 1)))) self._on_update() return c def _menu_delete(self, m, it) -> Gtk.MenuItem: menu_delete = Gtk.MenuItem(_("Delete")) menu_delete.connect(GtkSignal.ACTIVATE.value, self.menu_do_delete, m, it) menu_delete.show() return menu_delete def menu_do_negate(self, _mitem, m, it): wrapped = m[it][0] c = wrapped.component parent_it = m.iter_parent(it) parent_c = m[parent_it][0].component if isinstance(c, diversion.Not): # avoid double negation self.menu_do_flatten(_mitem, m, it) self.tree_view.expand_row(m.get_path(parent_it), True) elif isinstance(parent_c, diversion.Not): # avoid double negation self.menu_do_flatten(_mitem, m, parent_it) else: idx = parent_c.components.index(c) self._menu_do_insert_new(_mitem, m, it, diversion.Not, c, below=True) self.menu_do_delete(_mitem, m, m.iter_nth_child(parent_it, idx)) self._on_update() def _menu_negate(self, m, it) -> Gtk.MenuItem: menu_negate = Gtk.MenuItem(_("Negate")) menu_negate.connect(GtkSignal.ACTIVATE.value, self.menu_do_negate, m, it) menu_negate.show() return menu_negate def menu_do_wrap(self, _mitem, m, it, cls): wrapped = m[it][0] c = wrapped.component parent_it = m.iter_parent(it) parent_c = m[parent_it][0].component if isinstance(parent_c, diversion.Not): new_c = cls([c], warn=False) parent_c.component = new_c m.remove(it) self._populate_model_func(m, parent_it, new_c, level=wrapped.level, pos=0) self.tree_view.expand_row(m.get_path(parent_it), True) self.tree_view.get_selection().select_iter(m.iter_nth_child(parent_it, 0)) else: idx = parent_c.components.index(c) self._menu_do_insert_new(_mitem, m, it, cls, [c], below=True) self.menu_do_delete(_mitem, m, m.iter_nth_child(parent_it, idx)) self._on_update() def _menu_wrap(self, m, it) -> Gtk.MenuItem: menu_wrap = Gtk.MenuItem(_("Wrap with")) submenu_wrap = Gtk.Menu() menu_sub_rule = Gtk.MenuItem(_("Sub-rule")) menu_and = Gtk.MenuItem(_("And")) menu_or = Gtk.MenuItem(_("Or")) menu_sub_rule.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.Rule) menu_and.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.And) menu_or.connect(GtkSignal.ACTIVATE.value, self.menu_do_wrap, m, it, diversion.Or) submenu_wrap.append(menu_sub_rule) submenu_wrap.append(menu_and) submenu_wrap.append(menu_or) menu_wrap.set_submenu(submenu_wrap) menu_wrap.show_all() return menu_wrap def menu_do_copy(self, _mitem: Gtk.MenuItem, m: Gtk.TreeStore, it: Gtk.TreeIter): global _rule_component_clipboard wrapped = m[it][0] c = wrapped.component _rule_component_clipboard = diversion.RuleComponent().compile(c.data()) def menu_do_cut(self, _mitem, m, it): global _rule_component_clipboard c = self.menu_do_delete(_mitem, m, it) self._on_update() _rule_component_clipboard = c def _menu_cut(self, m, it): menu_cut = Gtk.MenuItem(_("Cut")) menu_cut.connect(GtkSignal.ACTIVATE.value, self.menu_do_cut, m, it) menu_cut.show() return menu_cut def menu_do_paste(self, _mitem, m, it, below=False): global _rule_component_clipboard c = _rule_component_clipboard _rule_component_clipboard = None if c: _rule_component_clipboard = diversion.RuleComponent().compile(c.data()) self._menu_do_insert(_mitem, m, it, new_c=c, below=below) self._on_update() def _menu_paste(self, m, it, below=False): menu_paste = Gtk.MenuItem(_("Paste")) menu_paste.connect(GtkSignal.ACTIVATE.value, self.menu_do_paste, m, it, below) menu_paste.show() return menu_paste def _menu_copy(self, m, it): menu_copy = Gtk.MenuItem(_("Copy")) menu_copy.connect(GtkSignal.ACTIVATE.value, self.menu_do_copy, m, it) menu_copy.show() return menu_copy class DiversionDialog: def __init__(self, action_menu): window = Gtk.Window() window.set_title(_("Solaar Rule Editor")) window.connect(GtkSignal.DELETE_EVENT.value, self._closing) vbox = Gtk.VBox() self.top_panel, self.view = self._create_top_panel() for col in self._create_view_columns(): self.view.append_column(col) vbox.pack_start(self.top_panel, True, True, 0) self._action_menu = action_menu( window, self.view, populate_model_func=_populate_model, on_update=self.on_update, ) self.dirty = False # if dirty, there are pending changes to be saved self.type_ui = {} self.update_ui = {} self.selected_rule_edit_panel = _create_selected_rule_edit_panel() self.ui = defaultdict(lambda: UnsupportedRuleComponentUI(self.selected_rule_edit_panel)) self.ui.update( { # one instance per type rc_class: rc_ui_class(self.selected_rule_edit_panel, on_update=self.on_update) for rc_class, rc_ui_class in COMPONENT_UI.items() } ) vbox.pack_start(self.selected_rule_edit_panel, False, False, 10) self.model = self._create_model() self.view.set_model(self.model) self.view.expand_all() window.add(vbox) geometry = Gdk.Geometry() geometry.min_width = 600 # don't ask for so much space geometry.min_height = 400 window.set_geometry_hints(None, geometry, Gdk.WindowHints.MIN_SIZE) window.set_position(Gtk.WindowPosition.CENTER) window.show_all() window.connect(GtkSignal.DELETE_EVENT.value, lambda w, e: w.hide_on_delete() or True) style = window.get_style_context() style.add_class("solaar") self.window = window self._editing_component = None def _closing(self, window: Gtk.Window, e: Gdk.Event): if self.dirty: dialog = _create_close_dialog(window) response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.NO: window.hide() elif response == Gtk.ResponseType.YES: self._save_yaml_file() window.hide() else: # don't close return True else: window.hide() def _reload_yaml_file(self): self.discard_btn.set_sensitive(False) self.save_btn.set_sensitive(False) self.dirty = False for c in self.selected_rule_edit_panel.get_children(): self.selected_rule_edit_panel.remove(c) diversion.load_config_rule_file() self.model = self._create_model() self.view.set_model(self.model) self.view.expand_all() def _save_yaml_file(self): if diversion._save_config_rule_file(): self.dirty = False self.save_btn.set_sensitive(False) self.discard_btn.set_sensitive(False) def _create_top_panel(self): sw = Gtk.ScrolledWindow() sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS) view = Gtk.TreeView() view.set_headers_visible(False) view.set_enable_tree_lines(True) view.set_reorderable(False) view.connect(GtkSignal.KEY_PRESS_EVENT.value, self._event_key_pressed) view.connect(GtkSignal.BUTTON_RELEASE_EVENT.value, self._event_button_released) view.get_selection().connect(GtkSignal.CHANGED.value, self._selection_changed) sw.add(view) sw.set_size_request(0, 300) # don't ask for so much height button_box = Gtk.HBox(spacing=20) self.save_btn = Gtk.Button.new_from_icon_name("document-save", Gtk.IconSize.BUTTON) self.save_btn.set_label(_("Save changes")) self.save_btn.set_always_show_image(True) self.save_btn.set_sensitive(False) self.save_btn.set_valign(Gtk.Align.CENTER) self.discard_btn = Gtk.Button.new_from_icon_name("document-revert", Gtk.IconSize.BUTTON) self.discard_btn.set_label(_("Discard changes")) self.discard_btn.set_always_show_image(True) self.discard_btn.set_sensitive(False) self.discard_btn.set_valign(Gtk.Align.CENTER) self.save_btn.connect(GtkSignal.CLICKED.value, lambda *_args: self._save_yaml_file()) self.discard_btn.connect(GtkSignal.CLICKED.value, lambda *_args: self._reload_yaml_file()) button_box.pack_start(self.save_btn, False, False, 0) button_box.pack_start(self.discard_btn, False, False, 0) button_box.set_halign(Gtk.Align.CENTER) button_box.set_valign(Gtk.Align.CENTER) button_box.set_size_request(0, 50) vbox = Gtk.VBox() vbox.pack_start(button_box, False, False, 0) vbox.pack_start(sw, True, True, 0) return vbox, view def _create_model(self): model = Gtk.TreeStore(RuleComponentWrapper) if len(diversion.rules.components) == 1: # only built-in rules - add empty user rule list diversion.rules.components.insert(0, diversion.Rule([], source=diversion._file_path)) _populate_model(model, None, diversion.rules.components) return model def _create_view_columns(self): cell_icon = Gtk.CellRendererPixbuf() cell1 = Gtk.CellRendererText() col1 = Gtk.TreeViewColumn("Type") col1.pack_start(cell_icon, False) col1.pack_start(cell1, True) col1.set_cell_data_func(cell1, lambda _c, c, m, it, _d: c.set_property("text", m.get_value(it, 0).display_left())) cell2 = Gtk.CellRendererText() col2 = Gtk.TreeViewColumn("Summary") col2.pack_start(cell2, True) col2.set_cell_data_func(cell2, lambda _c, c, m, it, _d: c.set_property("text", m.get_value(it, 0).display_right())) col2.set_cell_data_func( cell_icon, lambda _c, c, m, it, _d: c.set_property("icon-name", m.get_value(it, 0).display_icon()) ) return col1, col2 def on_update(self): self.view.queue_draw() self.dirty = True self.save_btn.set_sensitive(True) self.discard_btn.set_sensitive(True) def _selection_changed(self, selection): self.selected_rule_edit_panel.set_sensitive(False) (model, it) = selection.get_selected() if it is None: return wrapped = model[it][0] component = wrapped.component self._editing_component = component self.ui[type(component)].show(component, wrapped.editable) self.selected_rule_edit_panel.set_sensitive(wrapped.editable) def _event_key_pressed(self, v, e): """ Shortcuts: Ctrl + I insert component Ctrl + Delete delete row & wrap with And | wrap with Or Shift + R wrap with Rule ! negate Ctrl + X cut Ctrl + C copy Ctrl + V paste below (or here if empty) Ctrl + Shift + V paste above * flatten Ctrl + S save changes """ state = e.state & (Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK) m, it = v.get_selection().get_selected() enabled_actions = allowed_actions(m, it) if state & Gdk.ModifierType.CONTROL_MASK: if enabled_actions.delete and e.keyval in [Gdk.KEY_x, Gdk.KEY_X]: self._action_menu.menu_do_cut(None, m, it) elif enabled_actions.copy and e.keyval in [Gdk.KEY_c, Gdk.KEY_C] and enabled_actions.c is not None: self._action_menu.menu_do_copy(None, m, it) elif enabled_actions.insert and _rule_component_clipboard is not None and e.keyval in [Gdk.KEY_v, Gdk.KEY_V]: self._action_menu.menu_do_paste( None, m, it, below=enabled_actions.c is not None and not (state & Gdk.ModifierType.SHIFT_MASK) ) elif ( enabled_actions.insert_only_rule and isinstance(_rule_component_clipboard, diversion.Rule) and e.keyval in [Gdk.KEY_v, Gdk.KEY_V] ): self._action_menu.menu_do_paste( None, m, it, below=enabled_actions.c is not None and not (state & Gdk.ModifierType.SHIFT_MASK) ) elif ( enabled_actions.insert_root and isinstance(_rule_component_clipboard, diversion.Rule) and e.keyval in [Gdk.KEY_v, Gdk.KEY_V] ): self._action_menu.menu_do_paste(None, m, m.iter_nth_child(it, 0)) elif enabled_actions.delete and e.keyval in [Gdk.KEY_KP_Delete, Gdk.KEY_Delete]: self._action_menu.menu_do_delete(None, m, it) elif (enabled_actions.insert or enabled_actions.insert_only_rule or enabled_actions.insert_root) and e.keyval in [ Gdk.KEY_i, Gdk.KEY_I, ]: menu = Gtk.Menu() for item in self._action_menu.get_insert_menus( m, it, enabled_actions, ): menu.append(item) menu.show_all() rect = self.view.get_cell_area(m.get_path(it), self.view.get_column(1)) menu.popup_at_rect(self.window.get_window(), rect, Gdk.Gravity.WEST, Gdk.Gravity.CENTER, e) elif self.dirty and e.keyval in [Gdk.KEY_s, Gdk.KEY_S]: self._save_yaml_file() else: if enabled_actions.wrap: if e.keyval == Gdk.KEY_exclam: self._action_menu.menu_do_negate(None, m, it) elif e.keyval == Gdk.KEY_ampersand: self._action_menu.menu_do_wrap(None, m, it, diversion.And) elif e.keyval == Gdk.KEY_bar: self._action_menu.menu_do_wrap(None, m, it, diversion.Or) elif e.keyval in [Gdk.KEY_r, Gdk.KEY_R] and (state & Gdk.ModifierType.SHIFT_MASK): self._action_menu.menu_do_wrap(None, m, it, diversion.Rule) if enabled_actions.flatten and e.keyval in [Gdk.KEY_asterisk, Gdk.KEY_KP_Multiply]: self._action_menu.menu_do_flatten(None, m, it) def _event_button_released(self, v, e): self._action_menu.create_menu_event_button_released(v, e) def update_devices(self): for rc in self.ui.values(): rc.update_devices() self.view.queue_draw() class CompletionEntry(Gtk.Entry): def __init__(self, values, *args, **kwargs): super().__init__(*args, **kwargs) CompletionEntry.add_completion_to_entry(self, values) @classmethod def add_completion_to_entry(cls, entry, values): completion = entry.get_completion() if not completion: liststore = Gtk.ListStore(str) completion = Gtk.EntryCompletion() completion.set_model(liststore) completion.set_match_func(lambda completion, key, it: norm(key) in norm(completion.get_model()[it][0])) completion.set_text_column(0) entry.set_completion(completion) else: liststore = completion.get_model() liststore.clear() for v in sorted(set(values), key=str.casefold): liststore.append((v,)) class SmartComboBox(Gtk.ComboBox): """A custom ComboBox with some extra features. The constructor requires a collection of allowed values. Each element must be a single value or a non-empty tuple containing: - a value (any hashable object) - a name (optional; str(value) is used if not provided) - alternative names. Example: (some_object, 'object name', 'other name', 'also accept this'). It is assumed that the same string cannot be the name or an alternative name of more than one value. The widget displays the names, but the alternative names are also suggested and accepted as input. If `has_entry` is `True`, then the user can insert arbitrary text (possibly with auto-complete if `completion` is True). Otherwise, only a drop-down list is shown, with an extra blank item in the beginning (correspondent to `None`). The display text of the blank item is defined by the parameter `blank`. If `case_insensitive` is `True`, then upper-case and lower-case letters are treated as equal. If `replace_with_default_name`, then the field text is immediately replaced with the default name of a value as soon as the user finishes typing any accepted name. """ def __init__( self, all_values, blank="", completion=False, case_insensitive=False, replace_with_default_name=False, **kwargs ): super().__init__(**kwargs) self._name_to_idx = {} self._value_to_idx = {} self._hidden_idx = set() self._all_values = [] self._blank = blank self._model = None self._completion = completion self._case_insensitive = case_insensitive self._norm = lambda s: None if s is None else s if not case_insensitive else str(s).upper() self._replace_with_default_name = replace_with_default_name def replace_with(value): if self.get_has_entry() and self._replace_with_default_name and value is not None: item = self._all_values[self._value_to_idx[value]] name = item[1] if len(item) > 1 else str(item[0]) if name != self.get_child().get_text(): self.get_child().set_text(name) self.connect(GtkSignal.CHANGED.value, lambda *a: replace_with(self.get_value(invalid_as_str=False))) self.set_id_column(0) if self.get_has_entry(): self.set_entry_text_column(1) else: renderer = Gtk.CellRendererText() self.pack_start(renderer, True) self.add_attribute(renderer, "text", 1) self.set_all_values(all_values) self.set_active_id("") @classmethod def new_model(cls): model = Gtk.ListStore(str, str, bool) # (index: int converted to str, name: str, visible: bool) filtered_model = model.filter_new() filtered_model.set_visible_column(2) return model, filtered_model def set_all_values(self, all_values, visible_fn=(lambda value: True)): old_value = self.get_value() self._name_to_idx = {} self._value_to_idx = {} self._hidden_idx = set() self._all_values = [v if isinstance(v, tuple) else (v,) for v in all_values] model, filtered_model = SmartComboBox.new_model() # creating a new model seems to be necessary to avoid firing 'changed' event once per inserted item model.append(("", self._blank, True)) self._model = model to_complete = [self._blank] for idx, item in enumerate(self._all_values): value, *names = item if isinstance(item, tuple) else (item,) visible = visible_fn(value) self._include(model, idx, value, visible, *names) if visible: to_complete += names if names else [str(value).strip()] self.set_model(filtered_model) if self.get_has_entry() and self._completion: CompletionEntry.add_completion_to_entry(self.get_child(), to_complete) if self._find_idx(old_value) is not None: self.set_value(old_value) else: self.set_value(self._blank) self.queue_draw() def _include(self, model, idx, value, visible, *names): name = str(names[0]) if names else str(value).strip() self._name_to_idx[self._norm(name)] = idx if isinstance(value, NamedInt): self._name_to_idx[self._norm(str(name))] = idx model.append((str(idx), name, visible)) for alt in names[1:]: self._name_to_idx[self._norm(str(alt).strip())] = idx self._value_to_idx[value] = idx if self._case_insensitive and isinstance(value, str): self._name_to_idx[self._norm(value)] = idx def get_value(self, invalid_as_str=True, accept_hidden=True): """Return the selected value or the typed text. If the typed or selected text corresponds to one of the allowed values (or their names and alternative names), then the value is returned. Otherwise, the raw text is returned as string if the widget has an entry and `invalid_as_str` is `True`; if the widget has no entry or `invalid_as_str` is `False`, then `None` is returned. """ tree_iter = self.get_active_iter() if tree_iter is not None: t = self.get_model()[tree_iter] number = t[0] return self._all_values[int(number)][0] if number != "" and (accept_hidden or t[2]) else None elif self.get_has_entry(): text = self.get_child().get_text().strip() if text == self._blank: return None idx = self._find_idx(text) if idx is None: return text if invalid_as_str else None item = self._all_values[idx] return item[0] return None def _find_idx(self, search): if search == self._blank: return None try: return self._value_to_idx[search] except KeyError: pass try: return self._name_to_idx[self._norm(search)] except KeyError: pass return None def set_value(self, value, accept_invalid=True): """Set a specific value. Raw values, their names and alternative names are accepted. Base-10 representations of int values as strings are also accepted. The actual value is used in all cases. If `value` is invalid, then the entry text is set to the provided value if the widget has an entry and `accept_invalid` is True, or else the blank value is set. """ idx = self._find_idx(value) if value != self._blank else "" if idx is not None: self.set_active_id(str(idx)) else: if self.get_has_entry() and accept_invalid: self.get_child().set_text(str(value or "") if value != "" else self._blank) else: self.set_active_id("") def show_only(self, only, include_new=False): """Hide items not present in `only`. Only values are accepted (not their names and alternative names). If `include_new` is True, then the values in `only` not currently present are included with their string representation as names; otherwise, they are ignored. If `only` is new, then the visibility status is reset and all values are shown. """ values = self._all_values[:] if include_new and only is not None: values += [v for v in only if v not in self._value_to_idx] self.set_all_values(values, (lambda v: only is None or (v in only))) @dataclass class DeviceInfo: serial: str = "" unitId: str = "" codename: str = "" settings: Dict[str, Setting] = field(default_factory=dict) def __post_init__(self): if self.serial is None or self.serial == "?": self.serial = "" if self.unitId is None or self.unitId == "?": self.unitId = "" @property def id(self) -> str: return self.serial or self.unitId or "" @property def identifiers(self) -> list[str]: return [id for id in (self.serial, self.unitId) if id] @property def display_name(self) -> str: return f"{self.codename} ({self.id})" def matches(self, search: str) -> bool: return search and search in (self.serial, self.unitId, self.display_name) def update(self, device: DeviceInfo) -> None: for k in ("serial", "unitId", "codename", "settings"): if not getattr(self, k, None): v = getattr(device, k, None) if v and v != "?": setattr(self, k, copy(v) if k != "settings" else {s.name: s for s in v}) class DeviceInfoFactory: @classmethod def create_device_info(cls, device) -> DeviceInfo: d = DeviceInfo() d.update(device) return d class AllDevicesInfo: def __init__(self): self._devices: list[DeviceInfo] = [] self._lock = threading.Lock() def __iter__(self): return iter(self._devices) def __getitem__(self, search): if not search: return search assert isinstance(search, str) # linear search - ok because it is always a small list return next((d for d in self._devices if d.matches(search)), None) def refresh(self): updated = False def dev_in_row(_store, _treepath, row): nonlocal updated device = _dev_model.get_value(row, 7) if device and device.kind and (device.serial and device.serial != "?" or device.unitId and device.unitId != "?"): existing = self[device.serial] or self[device.unitId] if not existing: updated = True device_info = DeviceInfoFactory.create_device_info(device) self._devices.append(device_info) elif not existing.settings and device.settings: updated = True existing.update(device) with self._lock: _dev_model.foreach(dev_in_row) return updated class UnsupportedRuleComponentUI(RuleComponentUI): CLASS = None def create_widgets(self): self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True) self.label.set_text(_("This editor does not support the selected rule component yet.") if self.component else "") self.widgets[self.label] = (0, 0, 1, 1) def collect_value(self): return self.component.components[:] # not editable on the bottom panel @classmethod def right_label(cls, component): return str(component) class RuleUI(RuleComponentUI): CLASS = diversion.Rule def create_widgets(self): self.widgets = {} def collect_value(self): return self.component.components[:] # not editable on the bottom panel @classmethod def left_label(cls, component): return _("Rule") @classmethod def icon_name(cls): return "format-justify-fill" class AndUI(RuleComponentUI): CLASS = diversion.And def create_widgets(self): self.widgets = {} def collect_value(self): return self.component.components[:] # not editable on the bottom panel @classmethod def left_label(cls, component): return _("And") class OrUI(RuleComponentUI): CLASS = diversion.Or def create_widgets(self): self.widgets = {} def collect_value(self): return self.component.components[:] # not editable on the bottom panel @classmethod def left_label(cls, component): return _("Or") class LaterUI(RuleComponentUI): CLASS = diversion.Later MIN_VALUE = 0.01 MAX_VALUE = 100 def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True) self.label.set_text(_("Number of seconds to delay. Delay between 0 and 1 is done with higher precision.")) self.widgets[self.label] = (0, 0, 1, 1) self.field = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1) self.field.set_digits(3) self.field.set_halign(Gtk.Align.CENTER) self.field.set_valign(Gtk.Align.CENTER) self.field.set_hexpand(True) self.field.connect(GtkSignal.VALUE_CHANGED.value, self._on_update) self.widgets[self.field] = (0, 1, 1, 1) def show(self, component, editable): super().show(component, editable) with self.ignore_changes(): self.field.set_value(component.delay) def collect_value(self): return [float(int((self.field.get_value() + 0.0001) * 1000)) / 1000] + self.component.components @classmethod def left_label(cls, component): return _("Later") @classmethod def right_label(cls, component): return str(component.delay) class NotUI(RuleComponentUI): CLASS = diversion.Not def create_widgets(self): self.widgets = {} def collect_value(self): return self.component.component # not editable on the bottom panel @classmethod def left_label(cls, component): return _("Not") class ActionUI(RuleComponentUI): CLASS = diversion.Action @classmethod def icon_name(cls): return "go-next" def _from_named_ints(v, all_values): """Obtain a NamedInt from NamedInts given its numeric value (as int) or name.""" if all_values and (v in all_values): return all_values[v] return v class SetValueControlKinds(Enum): TOGGLE = "toggle" RANGE = "range" RANGE_WITH_KEY = "range_with_key" CHOICE = "choice" class SetValueControl(Gtk.HBox): def __init__(self, on_change, *args, accept_toggle=True, **kwargs): super().__init__(*args, **kwargs) self.on_change = on_change self.toggle_widget = SmartComboBox( [ *([("Toggle", _("Toggle"), "~")] if accept_toggle else []), (True, _("True"), "True", "yes", "on", "t", "y"), (False, _("False"), "False", "no", "off", "f", "n"), ], case_insensitive=True, ) self.toggle_widget.connect(GtkSignal.CHANGED.value, self._changed) self.range_widget = Gtk.SpinButton.new_with_range(0, 0xFFFF, 1) self.range_widget.connect(GtkSignal.VALUE_CHANGED.value, self._changed) self.choice_widget = SmartComboBox( [], completion=True, has_entry=True, case_insensitive=True, replace_with_default_name=True ) self.choice_widget.connect(GtkSignal.CHANGED.value, self._changed) self.sub_key_widget = SmartComboBox([]) self.sub_key_widget.connect(GtkSignal.CHANGED.value, self._changed) self.unsupported_label = Gtk.Label(label=_("Unsupported setting")) self.pack_start(self.sub_key_widget, False, False, 0) self.sub_key_widget.set_hexpand(False) self.sub_key_widget.set_size_request(120, 0) self.sub_key_widget.hide() for w in [self.toggle_widget, self.range_widget, self.choice_widget, self.unsupported_label]: self.pack_end(w, True, True, 0) w.hide() self.unsupp_value = None self.current_kind: Optional[SetValueControlKinds] = None self.sub_key_range_items = None def _changed(self, widget, *args): if widget.get_visible(): value = self.get_value() if self.current_kind == SetValueControlKinds.CHOICE: value = widget.get_value() icon = "dialog-warning" if widget._allowed_values and (value not in widget._allowed_values) else "" widget.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) elif self.current_kind == SetValueControlKinds.RANGE_WITH_KEY and widget == self.sub_key_widget: key = self.sub_key_widget.get_value() selected_item = ( next((item for item in self.sub_key_range_items if key == item.id), None) if self.sub_key_range_items else None ) (minimum, maximum) = (selected_item.minimum, selected_item.maximum) if selected_item else (0, 0xFFFF) self.range_widget.set_range(minimum, maximum) self.on_change(value) def _hide_all(self): for w in self.get_children(): w.hide() def get_value(self): if self.current_kind == SetValueControlKinds.TOGGLE: return self.toggle_widget.get_value() if self.current_kind == SetValueControlKinds.RANGE: return int(self.range_widget.get_value()) if self.current_kind == SetValueControlKinds.RANGE_WITH_KEY: return {self.sub_key_widget.get_value(): int(self.range_widget.get_value())} if self.current_kind == SetValueControlKinds.CHOICE: return self.choice_widget.get_value() return self.unsupp_value def set_value(self, value): if self.current_kind == SetValueControlKinds.TOGGLE: self.toggle_widget.set_value(value if value is not None else "") elif self.current_kind == SetValueControlKinds.RANGE: minimum, maximum = self.range_widget.get_range() try: v = round(float(value)) except (ValueError, TypeError): v = minimum self.range_widget.set_value(max(minimum, min(maximum, v))) elif self.current_kind == SetValueControlKinds.RANGE_WITH_KEY: if not (isinstance(value, dict) and len(value) == 1): value = {None: None} key = next(iter(value.keys())) selected_item = ( next((item for item in self.sub_key_range_items if key == item.id), None) if self.sub_key_range_items else None ) (minimum, maximum) = (selected_item.minimum, selected_item.maximum) if selected_item else (0, 0xFFFF) try: v = round(float(next(iter(value.values())))) except (ValueError, TypeError): v = minimum self.sub_key_widget.set_value(key or "") self.range_widget.set_value(max(minimum, min(maximum, v))) elif self.current_kind == SetValueControlKinds.CHOICE: self.choice_widget.set_value(value) else: self.unsupp_value = value if value is None or value == "": # reset all self.range_widget.set_range(0x0000, 0xFFFF) self.range_widget.set_value(0) self.toggle_widget.set_active_id("") self.sub_key_widget.set_value("") self.choice_widget.set_value("") def make_toggle(self): self.current_kind = SetValueControlKinds.TOGGLE self._hide_all() self.toggle_widget.show() def make_range(self, minimum, maximum): self.current_kind = SetValueControlKinds.RANGE self._hide_all() self.range_widget.set_range(minimum, maximum) self.range_widget.show() def make_range_with_key(self, items, labels=None): self.current_kind = SetValueControlKinds.RANGE_WITH_KEY self._hide_all() self.sub_key_range_items = items or None if not labels: labels = {} self.sub_key_widget.set_all_values( map(lambda item: (item.id, labels.get(item.id, [str(item.id)])[0]), items) if items else [] ) self.sub_key_widget.show() self.range_widget.show() def make_choice(self, values, extra=None): # if extra is not in values, it is ignored self.current_kind = SetValueControlKinds.CHOICE self._hide_all() sort_key = int if all((v == extra or str(v).isdigit()) for v in values) else str if extra is not None and extra in values: values = [extra] + sorted((v for v in values if v != extra), key=sort_key) else: values = sorted(values, key=sort_key) self.choice_widget.set_all_values(values) self.choice_widget._allowed_values = values self.choice_widget.show() def make_unsupported(self): self.current_kind = None self._hide_all() self.unsupported_label.show() class _DeviceUI: label_text = "" def show(self, component, editable): super().show(component, editable) with self.ignore_changes(): same = not component.devID device = _all_devices[component.devID] self.device_field.set_value(device.id if device else "" if same else component.devID or "") def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True) self.label.set_text(self.label_text) self.widgets[self.label] = (0, 0, 5, 1) lbl = Gtk.Label(label=_("Device"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True) self.widgets[lbl] = (0, 1, 1, 1) self.device_field = SmartComboBox( [], completion=True, has_entry=True, blank=_("Originating device"), case_insensitive=True, replace_with_default_name=True, ) self.device_field.set_value("") self.device_field.set_valign(Gtk.Align.CENTER) self.device_field.set_size_request(400, 0) self.device_field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.device_field] = (1, 1, 1, 1) def update_devices(self): self._update_device_list() def _update_device_list(self): with self.ignore_changes(): self.device_field.set_all_values([(d.id, d.display_name, *d.identifiers[1:]) for d in _all_devices]) def collect_value(self): device_str = self.device_field.get_value() same = device_str in ["", _("Originating device")] device = None if same else _all_devices[device_str] device_value = device.id if device else None if same else device_str return device_value @classmethod def right_label(cls, component): device = _all_devices[component.devID] return device.display_name if device else shlex_quote(component.devID) class ActiveUI(_DeviceUI, ConditionUI): CLASS = diversion.Active label_text = _("Device is active and its settings can be changed.") @classmethod def left_label(cls, component): return _("Active") class DeviceUI(_DeviceUI, ConditionUI): CLASS = diversion.Device label_text = _("Device that originated the current notification.") @classmethod def left_label(cls, component): return _("Device") class HostUI(ConditionUI): CLASS = diversion.Host def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True) self.label.set_text(_("Name of host computer.")) self.widgets[self.label] = (0, 0, 1, 1) self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True) self.field.set_size_request(600, 0) self.field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.field] = (0, 1, 1, 1) def show(self, component, editable): super().show(component, editable) with self.ignore_changes(): self.field.set_text(component.host) def collect_value(self): return self.field.get_text() @classmethod def left_label(cls, component): return _("Host") @classmethod def right_label(cls, component): return str(component.host) class _SettingWithValueUI: MULTIPLE = [Kind.MULTIPLE_TOGGLE, Kind.MAP_CHOICE, Kind.MULTIPLE_RANGE] ACCEPT_TOGGLE = True label_text = "" def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True) self.label.set_text(self.label_text) self.widgets[self.label] = (0, 0, 5, 1) m = 20 lbl = Gtk.Label(label=_("Device"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True, margin_top=m) self.widgets[lbl] = (0, 1, 1, 1) self.device_field = SmartComboBox( [], completion=True, has_entry=True, blank=_("Originating device"), case_insensitive=True, replace_with_default_name=True, ) self.device_field.set_value("") self.device_field.set_valign(Gtk.Align.CENTER) self.device_field.set_size_request(400, 0) self.device_field.set_margin_top(m) self.device_field.connect(GtkSignal.CHANGED.value, self._changed_device) self.device_field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.device_field] = (1, 1, 1, 1) lbl = Gtk.Label( label=_("Setting"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True, vexpand=False, ) self.widgets[lbl] = (0, 2, 1, 1) self.setting_field = SmartComboBox([(s[0].name, s[0].label) for s in ALL_SETTINGS.values()]) self.setting_field.set_valign(Gtk.Align.CENTER) self.setting_field.connect(GtkSignal.CHANGED.value, self._changed_setting) self.setting_field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.setting_field] = (1, 2, 1, 1) self.value_lbl = Gtk.Label( label=_("Value"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True, vexpand=False ) self.widgets[self.value_lbl] = (2, 2, 1, 1) self.value_field = SetValueControl(self._on_update, accept_toggle=self.ACCEPT_TOGGLE) self.value_field.set_valign(Gtk.Align.CENTER) self.value_field.set_size_request(250, 35) self.widgets[self.value_field] = (3, 2, 1, 1) self.key_lbl = Gtk.Label( label=_("Item"), halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True, vexpand=False, margin_top=m ) self.key_lbl.hide() self.widgets[self.key_lbl] = (2, 1, 1, 1) self.key_field = SmartComboBox( [], has_entry=True, completion=True, case_insensitive=True, replace_with_default_name=True ) self.key_field.set_margin_top(m) self.key_field.hide() self.key_field.set_valign(Gtk.Align.CENTER) self.key_field.connect(GtkSignal.CHANGED.value, self._changed_key) self.key_field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.key_field] = (3, 1, 1, 1) @classmethod def _all_choices(cls, setting): # choice and map-choice """Return a NamedInts instance with the choices for a setting. If the argument `setting` is a Setting instance or subclass, then the choices are taken only from it. If instead it is a name, then the function returns the union of the choices for each setting with that name. Only one label per number is kept. The function returns a 2-tuple whose first element is a NamedInts instance with the possible choices (including the extra value if it exists) and the second element is the extra value to be pinned to the start of the list (or `None` if there is no extra value). """ if isinstance(setting, Setting): setting = type(setting) if isinstance(setting, type) and issubclass(setting, Setting): choices = UnsortedNamedInts() universe = getattr(setting, "choices_universe", None) if universe: choices |= universe extra = getattr(setting, "choices_extra", None) if extra is not None: choices |= NamedInts(**{str(extra): int(extra)}) return choices, extra settings = ALL_SETTINGS.get(setting, []) choices = UnsortedNamedInts() extra = None for s in settings: ch, ext = cls._all_choices(s) choices |= ch if ext is not None: extra = ext return choices, extra @classmethod def _setting_attributes(cls, setting_name, device=None): if device and setting_name in device.settings: setting = device.settings.get(setting_name, None) settings = [type(setting)] if setting else None else: settings = ALL_SETTINGS.get(setting_name, [None]) setting = settings[0] # if settings have the same name, use the first one to get the basic data val_class = setting.validator_class if setting else None kind = val_class.kind if val_class else None if kind in cls.MULTIPLE: keys = UnsortedNamedInts() for s in settings: universe = getattr(s, "keys_universe" if kind == Kind.MAP_CHOICE else "choices_universe", None) if universe: keys |= universe # only one key per number is used else: keys = None return setting, val_class, kind, keys def _changed_device(self, *args): device = _all_devices[self.device_field.get_value()] setting_name = self.setting_field.get_value() if not device or not device.settings or setting_name in device.settings: kind = self._setting_attributes(setting_name, device)[2] key = self.key_field.get_value() if kind in self.MULTIPLE else None else: setting_name = kind = key = None with self.ignore_changes(): self._update_setting_list(device) self._update_key_list(setting_name, device) self._update_value_list(setting_name, device, key) def _changed_setting(self, *args): with self.ignore_changes(): device = _all_devices[self.device_field.get_value()] setting_name = self.setting_field.get_value() self._update_key_list(setting_name, device) key = self.key_field.get_value() self._update_value_list(setting_name, device, key) def _changed_key(self, *args): with self.ignore_changes(): setting_name = self.setting_field.get_value() device = _all_devices[self.device_field.get_value()] key = self.key_field.get_value() self._update_value_list(setting_name, device, key) def update_devices(self): self._update_device_list() def _update_device_list(self): with self.ignore_changes(): self.device_field.set_all_values([(d.id, d.display_name, *d.identifiers[1:]) for d in _all_devices]) def _update_setting_list(self, device=None): supported_settings = device.settings.keys() if device else {} with self.ignore_changes(): self.setting_field.show_only(supported_settings or None) def _update_key_list(self, setting_name, device=None): setting, val_class, kind, keys = self._setting_attributes(setting_name, device) multiple = kind in self.MULTIPLE self.key_field.set_visible(multiple) self.key_lbl.set_visible(multiple) if not multiple: return labels = getattr(setting, "_labels", {}) def item(k): lbl = labels.get(k, None) if lbl and isinstance(lbl, tuple) and lbl[0]: label = lbl[0] else: label = str(k) return k, label with self.ignore_changes(): self.key_field.set_all_values(sorted(map(item, keys), key=lambda k: k[1])) ds = device.settings if device else {} device_setting = ds.get(setting_name, None) supported_keys = None if device_setting: val = device_setting._validator if device_setting.kind == Kind.MULTIPLE_TOGGLE: supported_keys = val.get_options() or None elif device_setting.kind == Kind.MAP_CHOICE: choices = val.choices or None supported_keys = choices.keys() if choices else None elif device_setting.kind == Kind.MULTIPLE_RANGE: supported_keys = val.keys self.key_field.show_only(supported_keys, include_new=True) self._update_validation() def _update_value_list(self, setting_name, device=None, key=None): setting, val_class, kind, keys = self._setting_attributes(setting_name, device) ds = device.settings if device else {} device_setting = ds.get(setting_name, None) if kind in (Kind.TOGGLE, Kind.MULTIPLE_TOGGLE): self.value_field.make_toggle() elif kind in (Kind.CHOICE, Kind.MAP_CHOICE): # Open-value-space MAP_CHOICE settings (per-key RGB) have a Range # rather than a NamedInts value list — there's no meaningful value # picker to render in the rule editor, so fall through to unsupported. if kind == Kind.MAP_CHOICE and device_setting: val = device_setting._validator choices = getattr(val, "choices", None) if isinstance(choices, dict) and any(isinstance(v, Range) for v in choices.values()): self.value_field.make_unsupported() return all_values, extra = self._all_choices(device_setting or setting_name) self.value_field.make_choice(all_values, extra) supported_values = None if device_setting: val = device_setting._validator choices = getattr(val, "choices", None) or None if kind == Kind.CHOICE: supported_values = choices elif kind == Kind.MAP_CHOICE and isinstance(choices, dict): supported_values = choices.get(key, None) or None self.value_field.choice_widget.show_only(supported_values, include_new=True) self._update_validation() elif kind == Kind.RANGE: self.value_field.make_range(val_class.min_value, val_class.max_value) elif kind == Kind.MULTIPLE_RANGE: self.value_field.make_range_with_key( getattr(setting, "sub_items_universe", {}).get(key, {}) if setting else {}, getattr(setting, "_labels_sub", None) if setting else None, ) else: self.value_field.make_unsupported() def _on_update(self, *_args): if not self._ignore_changes and self.component: self._update_validation() def _update_validation(self): device_str = self.device_field.get_value() device = _all_devices[device_str] if device_str and not device: icon = ( "dialog-question" if len(device_str) == 8 and all(c in string.hexdigits for c in device_str) else "dialog-warning" ) else: icon = "" self.device_field.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) setting_name = self.setting_field.get_value() setting, val_class, kind, keys = self._setting_attributes(setting_name, device) multiple = kind in self.MULTIPLE if multiple: key = self.key_field.get_value(invalid_as_str=False, accept_hidden=False) icon = "dialog-warning" if key is None else "" self.key_field.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) if kind in (Kind.CHOICE, Kind.MAP_CHOICE): value = self.value_field.choice_widget.get_value(invalid_as_str=False, accept_hidden=False) icon = "dialog-warning" if value is None else "" self.value_field.choice_widget.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) def show(self, component, editable): a = iter(component.args) with self.ignore_changes(): device_str = next(a, None) same = not device_str device = _all_devices[device_str] self.device_field.set_value(device.id if device else "" if same else device_str or "") setting_name = next(a, "") setting, _v, kind, keys = self._setting_attributes(setting_name, device) self.setting_field.set_value(setting.name if setting else "") self._changed_setting() key = None if kind in self.MULTIPLE or kind is None and len(self.component.args) > 3: key = _from_named_ints(next(a, ""), keys) self.key_field.set_value(key) self.value_field.set_value(next(a, "")) self._update_validation() def collect_value(self): device_str = self.device_field.get_value() same = device_str in ["", _("Originating device")] device = None if same else _all_devices[device_str] device_value = device.id if device else None if same else device_str setting_name = self.setting_field.get_value() setting, val_class, kind, keys = self._setting_attributes(setting_name, device) key_value = [] if kind in self.MULTIPLE or kind is None and len(self.component.args) > 3: key = self.key_field.get_value() key = _from_named_ints(key, keys) key_value.append(key) key_value.append(self.value_field.get_value()) return [device_value, setting_name, *key_value] @classmethod def right_label(cls, component): a = iter(component.args) device_str = next(a, None) device = None if not device_str else _all_devices[device_str] device_disp = _("Originating device") if not device_str else device.display_name if device else shlex_quote(device_str) setting_name = next(a, None) setting, val_class, kind, keys = cls._setting_attributes(setting_name, device) device_setting = (device.settings if device else {}).get(setting_name, None) disp = [setting.label or setting.name if setting else setting_name] key = None if kind in cls.MULTIPLE: key = next(a, None) key = _from_named_ints(key, keys) if keys else key key_label = getattr(setting, "_labels", {}).get(key, [None])[0] if setting else None disp.append(key_label or key) value = next(a, None) if setting and (kind in (Kind.CHOICE, Kind.MAP_CHOICE)): all_values = cls._all_choices(setting or setting_name)[0] supported_values = None if device_setting: val = device_setting._validator choices = getattr(val, "choices", None) or None if kind == Kind.CHOICE: supported_values = choices elif kind == Kind.MAP_CHOICE and isinstance(choices, dict): supported_values = choices.get(key, None) or None if supported_values and isinstance(supported_values, NamedInts): value = supported_values[value] if not supported_values and all_values and isinstance(all_values, NamedInts): value = all_values[value] disp.append(value) elif kind == Kind.MULTIPLE_RANGE and isinstance(value, dict) and len(value) == 1: k, v = next(iter(value.items())) k = (getattr(setting, "_labels_sub", {}).get(k, (None,))[0] if setting else None) or k disp.append(f"{k}={v}") elif kind in (Kind.TOGGLE, Kind.MULTIPLE_TOGGLE): disp.append(_(str(value))) else: disp.append(value) return device_disp + " " + " ".join(map(lambda s: shlex_quote(str(s)), [*disp, *a])) class SetUI(_SettingWithValueUI, ActionUI): CLASS = diversion.Set ACCEPT_TOGGLE = True label_text = _("Change setting on device") def show(self, component, editable): ActionUI.show(self, component, editable) _SettingWithValueUI.show(self, component, editable) def _on_update(self, *_args): if not self._ignore_changes and self.component: ActionUI._on_update(self, *_args) _SettingWithValueUI._on_update(self, *_args) class SettingUI(_SettingWithValueUI, ConditionUI): CLASS = diversion.Setting ACCEPT_TOGGLE = False label_text = _("Setting on device") def show(self, component, editable): ConditionUI.show(self, component, editable) _SettingWithValueUI.show(self, component, editable) def _on_update(self, *_args): if not self._ignore_changes and self.component: ConditionUI._on_update(self, *_args) _SettingWithValueUI._on_update(self, *_args) COMPONENT_UI: dict[Any, RuleComponentUI] = { diversion.Rule: RuleUI, diversion.Not: NotUI, diversion.Or: OrUI, diversion.And: AndUI, diversion.Later: LaterUI, diversion.Process: rule_conditions.ProcessUI, diversion.MouseProcess: rule_conditions.MouseProcessUI, diversion.Active: ActiveUI, diversion.Device: DeviceUI, diversion.Host: HostUI, diversion.Feature: rule_conditions.FeatureUI, diversion.Report: rule_conditions.ReportUI, diversion.Modifiers: rule_conditions.ModifiersUI, diversion.Key: rule_conditions.KeyUI, diversion.KeyIsDown: rule_conditions.KeyIsDownUI, diversion.Test: rule_conditions.TestUI, diversion.TestBytes: rule_conditions.TestBytesUI, diversion.Setting: SettingUI, diversion.MouseGesture: rule_conditions.MouseGestureUI, diversion.KeyPress: rule_actions.KeyPressUI, diversion.MouseScroll: rule_actions.MouseScrollUI, diversion.MouseClick: rule_actions.MouseClickUI, diversion.Execute: rule_actions.ExecuteUI, diversion.Set: SetUI, # type(None): RuleComponentUI, # placeholders for empty rule/And/Or } _all_devices = AllDevicesInfo() _dev_model = None def update_devices(): global _dev_model global _all_devices global _diversion_dialog if _dev_model and _all_devices.refresh() and _diversion_dialog: _diversion_dialog.update_devices() def show_window(model: Gtk.TreeStore): GObject.type_register(RuleComponentWrapper) global _diversion_dialog global _dev_model _dev_model = model if _diversion_dialog is None: _diversion_dialog = DiversionDialog(ActionMenu) update_devices() _diversion_dialog.window.present() Solaar-1.1.20/lib/solaar/ui/icons.py000066400000000000000000000142531522022367600171570ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import logging from gi.repository import Gtk import solaar.gtk as gtk logger = logging.getLogger(__name__) LARGE_SIZE = Gtk.IconSize.DIALOG # was 64 TRAY_INIT = "solaar-init" TRAY_OKAY = "solaar" TRAY_ATTENTION = "solaar-attention" _default_theme = None _has_level_icons = False _has_padded_level_icons = False def _init_icon_paths(): global _default_theme, _has_level_icons, _has_padded_level_icons if _default_theme: return _default_theme = Gtk.IconTheme.get_default() logger.debug("icon theme paths: %s", _default_theme.get_search_path()) if gtk.battery_icons_style == "symbolic": global TRAY_OKAY TRAY_OKAY = TRAY_INIT # use monochrome tray icon if not _default_theme.has_icon("battery-good-symbolic"): logger.warning("failed to detect symbolic icons") gtk.battery_icons_style = "regular" if gtk.battery_icons_style == "regular": if not _default_theme.has_icon("battery-good"): logger.warning("failed to detect icons") gtk.battery_icons_style = "solaar" suffix = "-symbolic" if gtk.battery_icons_style == "symbolic" else "" _has_level_icons = _default_theme.has_icon(f"battery-level-50{suffix}") _has_padded_level_icons = not _has_level_icons and _default_theme.has_icon(f"battery-050{suffix}") logger.debug("battery level icons available: %s (padded scheme: %s)", _has_level_icons, _has_padded_level_icons) def battery(level=None, charging=False): icon_name = _battery_icon_name(level, charging) if not _default_theme.has_icon(icon_name): logger.warning("icon %s not found in current theme", icon_name) return TRAY_OKAY # use Solaar icon if battery icon not available logger.debug("battery icon for %s:%s = %s", level, charging, icon_name) return icon_name # return first res where val >= guard # _first_res(val,((guard,res),...)) def _first_res(val, pairs): return next((res for guard, res in pairs if val >= guard), None) def _battery_icon_name(level, charging): _init_icon_paths() suffix = "-symbolic" if gtk.battery_icons_style == "symbolic" else "" if level is None or level < 0: return f"battery-missing{suffix}" rounded = min(100, max(0, round(level / 10) * 10)) # Try precise level icons (battery-level-N or battery-0N0 naming scheme) if _has_level_icons or _has_padded_level_icons: if charging and rounded == 100: charging_str = "-charged" elif charging: charging_str = "-charging" else: charging_str = "" if _has_level_icons: icon_name = f"battery-level-{rounded}{charging_str}{suffix}" else: icon_name = f"battery-{rounded:03}{charging_str}{suffix}" if _default_theme.has_icon(icon_name): logger.debug("battery level icon for %s:%s = %s", level, charging, icon_name) return icon_name # Fall back to semantic names level_name = _first_res(level, ((90, "full"), (60, "good"), (20, "low"), (5, "caution"), (0, "empty"))) if level_name: if charging: charging_str = "-charging" else: charging_str = "" icon_name = f"battery-{level_name}{charging_str}{suffix}" if _default_theme.has_icon(icon_name): logger.debug("battery semantic icon for %s:%s = %s", level, charging, icon_name) return icon_name # Last resort: plain battery icon icon_name = f"battery{suffix}" logger.debug("battery generic icon for %s:%s = %s", level, charging, icon_name) return icon_name def lux(level=None): if level is None or level < 0: return "light_unknown" return f"solaar-light_{int(20 * ((level + 50) // 100)):03}" _ICON_SETS = {} def device_icon_set(name="_", kind=None): icon_set = _ICON_SETS.get(name) if icon_set is None: # names of possible icons, in reverse desirability icon_set = ["preferences-desktop-peripherals"] if kind: if str(kind) == "numpad": icon_set += ("input-keyboard", "input-dialpad") elif str(kind) == "touchpad": icon_set += ("input-mouse", "input-tablet") elif str(kind) == "trackball": icon_set += ("input-mouse",) elif str(kind) == "headset": icon_set += ("audio-headphones", "audio-headset") icon_set += (f"input-{str(kind)}",) # icon_set += (name.replace(' ', '-'),) _ICON_SETS[name] = icon_set return icon_set def device_icon_file(name, kind=None, size=LARGE_SIZE): icon_name = device_icon_name(name, kind) return _default_theme.lookup_icon(icon_name, size, 0).get_filename() if icon_name is not None else None def device_icon_name(name, kind=None): _init_icon_paths() icon_set = device_icon_set(name, kind) assert icon_set for n in reversed(icon_set): if _default_theme.has_icon(n): return n def icon_file(name, size=LARGE_SIZE): _init_icon_paths() # has_icon() somehow returned False while lookup_icon returns non-None. # I guess it happens because share/solaar/icons/ has no hicolor and resolution subdirs theme_icon = _default_theme.lookup_icon(name, size, 0) if theme_icon: file_name = theme_icon.get_filename() return file_name logger.warning("icon %s(%d) not found in current theme", name, size) Solaar-1.1.20/lib/solaar/ui/pair_window.py000066400000000000000000000256101522022367600203650ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import logging from enum import Enum from gi.repository import GLib from gi.repository import Gtk from logitech_receiver import hidpp10_constants from solaar.i18n import _ from solaar.i18n import ngettext from . import icons logger = logging.getLogger(__name__) _PAIRING_TIMEOUT = 30 # seconds _STATUS_CHECK = 500 # milliseconds class GtkSignal(Enum): CANCEL = "cancel" CLOSE = "close" def create(receiver): receiver.reset_pairing() # clear out any information on previous pairing title = _("%(receiver_name)s: pair new device") % {"receiver_name": receiver.name} if receiver.receiver_kind == "bolt": text = _("Bolt receivers are only compatible with Bolt devices.") text += "\n\n" text += _("Press a pairing button or key until the pairing light flashes quickly.") else: if receiver.receiver_kind == "unifying": text = _("Unifying receivers are only compatible with Unifying devices.") else: text = _("Other receivers are only compatible with a few devices.") text += "\n\n" text += _("For most devices, turn on the device you want to pair.") text += _("If the device is already turned on, turn it off and on again.") text += "\n" text += _("The device must not be paired with a nearby powered-on receiver.") text += "\n" text += _( "For devices with multiple channels, " "press, hold, and release the button for the channel you wish to pair" "\n" "or use the channel switch button to select a channel " "and then press, hold, and release the channel switch button." ) text += "\n" text += _("The channel indicator light should be blinking rapidly.") if receiver.remaining_pairings() and receiver.remaining_pairings() >= 0: text += ( ngettext( "\n\nThis receiver has %d pairing remaining.", "\n\nThis receiver has %d pairings remaining.", receiver.remaining_pairings(), ) % receiver.remaining_pairings() ) text += _("\nCancelling at this point will not use up a pairing.") ok = prepare(receiver) assistant = _create_assistant(receiver, ok, _finish, title, text) if ok: GLib.timeout_add(_STATUS_CHECK, check_lock_state, assistant, receiver) return assistant def prepare(receiver): if receiver.receiver_kind == "bolt": if receiver.discover(timeout=_PAIRING_TIMEOUT): return True else: receiver.pairing.error = "discovery did not start" return False elif receiver.set_lock(False, timeout=_PAIRING_TIMEOUT): return True else: receiver.pairing.error = "the pairing lock did not open" return False def check_lock_state(assistant, receiver, count=2): if not assistant.is_drawable(): logger.debug("assistant %s destroyed, bailing out", assistant) return False return _check_lock_state(assistant, receiver, count) def _check_lock_state(assistant, receiver, count): if receiver.pairing.error: _pairing_failed(assistant, receiver, receiver.pairing.error) return False elif receiver.pairing.new_device: receiver.remaining_pairings(False) # Update remaining pairings _pairing_succeeded(assistant, receiver, receiver.pairing.new_device) return False elif not receiver.pairing.lock_open and not receiver.pairing.discovering: if count > 0: # the actual device notification may arrive later so have a little patience GLib.timeout_add(_STATUS_CHECK, check_lock_state, assistant, receiver, count - 1) else: _pairing_failed(assistant, receiver, "failed to open pairing lock") return False elif receiver.pairing.lock_open and receiver.pairing.device_passkey: _show_passcode(assistant, receiver, receiver.pairing.device_passkey) return True elif receiver.pairing.discovering and receiver.pairing.device_address and receiver.pairing.device_name: add = receiver.pairing.device_address ent = 20 if receiver.pairing.device_kind == hidpp10_constants.DEVICE_KIND.keyboard else 10 if receiver.pair_device(address=add, authentication=receiver.pairing.device_authentication, entropy=ent): return True else: _pairing_failed(assistant, receiver, "failed to open pairing lock") return False return True def _pairing_failed(assistant, receiver, error): assistant.remove_page(0) # needed to reset the window size logger.debug("%s fail: %s", receiver, error) _create_failure_page(assistant, error) def _pairing_succeeded(assistant, receiver, device): assistant.remove_page(0) # needed to reset the window size logger.debug("%s success: %s", receiver, device) _create_success_page(assistant, device) def _finish(assistant, receiver): logger.debug("finish %s", assistant) assistant.destroy() receiver.pairing.new_device = None if receiver.pairing.lock_open: if receiver.receiver_kind == "bolt": receiver.pair_device("cancel") else: receiver.set_lock() if receiver.pairing.discovering: receiver.discover(True) if not receiver.pairing.lock_open and not receiver.pairing.discovering: receiver.pairing.error = None def _show_passcode(assistant, receiver, passkey): logger.debug("%s show passkey: %s", receiver, passkey) name = receiver.pairing.device_name authentication = receiver.pairing.device_authentication intro_text = _("%(receiver_name)s: pair new device") % {"receiver_name": receiver.name} page_text = _("Enter passcode on %(name)s.") % {"name": name} page_text += "\n" if authentication & 0x01: page_text += _("Type %(passcode)s and then press the enter key.") % { "passcode": receiver.pairing.device_passkey, } else: passcode = ", ".join( [_("right") if bit == "1" else _("left") for bit in f"{int(receiver.pairing.device_passkey):010b}"] ) page_text += _("Press %(code)s\nand then press left and right buttons simultaneously.") % {"code": passcode} page = _create_page( assistant, Gtk.AssistantPageType.PROGRESS, intro_text, "preferences-desktop-peripherals", page_text, ) assistant.set_page_complete(page, True) assistant.next_page() def _create_assistant(receiver, ok, finish, title, text): assistant = Gtk.Assistant() assistant.set_title(title) assistant.set_icon_name("list-add") assistant.set_size_request(400, 240) assistant.set_resizable(False) assistant.set_role("pair-device") if ok: page_intro = _create_page( assistant, Gtk.AssistantPageType.PROGRESS, title, "preferences-desktop-peripherals", text, ) spinner = Gtk.Spinner() spinner.set_visible(True) spinner.start() page_intro.pack_end(spinner, True, True, 24) assistant.set_page_complete(page_intro, True) else: page_intro = _create_failure_page(assistant, receiver.pairing.error) assistant.connect(GtkSignal.CANCEL.value, finish, receiver) assistant.connect(GtkSignal.CLOSE.value, finish, receiver) return assistant def _create_success_page(assistant, device): def _check_encrypted(device, assistant, hbox): if assistant.is_drawable() and device.link_encrypted is False: hbox.pack_start(Gtk.Image.new_from_icon_name("security-low", Gtk.IconSize.MENU), False, False, 0) hbox.pack_start(Gtk.Label(label=_("The wireless link is not encrypted")), False, False, 0) hbox.show_all() return False page = _create_page(assistant, Gtk.AssistantPageType.SUMMARY) header = Gtk.Label(label=_("Found a new device:")) page.pack_start(header, False, False, 0) device_icon = Gtk.Image() icon_name = icons.device_icon_name(device.name, device.kind) device_icon.set_from_icon_name(icon_name, icons.LARGE_SIZE) page.pack_start(device_icon, True, True, 0) device_label = Gtk.Label() device_label.set_markup(f"{device.name}") page.pack_start(device_label, True, True, 0) hbox = Gtk.HBox(homogeneous=False, spacing=8) hbox.pack_start(Gtk.Label(label=" "), False, False, 0) hbox.set_property("expand", False) hbox.set_property("halign", Gtk.Align.CENTER) page.pack_start(hbox, False, False, 0) GLib.timeout_add(_STATUS_CHECK, _check_encrypted, device, assistant, hbox) # wait a bit to check link status page.show_all() assistant.next_page() assistant.commit() def _create_failure_page(assistant, error) -> None: header = _("Pairing failed") + ": " + _(str(error)) + "." if "timeout" in str(error): text = _("Make sure your device is within range, and has a decent battery charge.") elif str(error) == "device not supported": text = _("A new device was detected, but it is not compatible with this receiver.") elif "many" in str(error): text = _("More paired devices than receiver can support.") else: text = _("No further details are available about the error.") _create_page(assistant, Gtk.AssistantPageType.SUMMARY, header, "dialog-error", text) assistant.next_page() assistant.commit() def _create_page(assistant, kind, header=None, icon_name=None, text=None) -> Gtk.VBox: p = Gtk.VBox(homogeneous=False, spacing=8) assistant.append_page(p) assistant.set_page_type(p, kind) if header: item = Gtk.HBox(homogeneous=False, spacing=16) p.pack_start(item, False, True, 0) label = Gtk.Label(label=header) label.set_line_wrap(True) item.pack_start(label, True, True, 0) if icon_name: icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.DIALOG) item.pack_start(icon, False, False, 0) if text: label = Gtk.Label(label=text) label.set_line_wrap(True) p.pack_start(label, False, False, 0) p.show_all() return p Solaar-1.1.20/lib/solaar/ui/perkey/000077500000000000000000000000001522022367600167645ustar00rootroot00000000000000Solaar-1.1.20/lib/solaar/ui/perkey/__init__.py000066400000000000000000000017311522022367600210770ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from .layout import Cell from .layout import Layout from .layouts import layout_for from .layouts import register_layout __all__ = ("Cell", "Layout", "layout_for", "register_layout") Solaar-1.1.20/lib/solaar/ui/perkey/_icons.py000066400000000000000000000121451522022367600206130ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Theme-aware loader for Solaar's per-key UI icons. Loads SVG icons from ``share/solaar/icons/`` and recolors them at load time to match the active GTK theme's text foreground, by substituting ``currentColor`` in the SVG before passing it to GdkPixbuf. GTK's stock symbolic loader is bypassed because it only recolors specific palette fill stand-ins and ignores ``stroke="currentColor"``. """ from __future__ import annotations import logging from pathlib import Path import gi gi.require_version("Gtk", "3.0") from gi.repository import GdkPixbuf # NOQA: E402 from gi.repository import Gio # NOQA: E402 from gi.repository import Gtk # NOQA: E402 logger = logging.getLogger(__name__) ICON_PIXEL_SIZE = 22 _search_path_added = False def ensure_icon_path() -> None: """Register share/solaar/icons with the default GtkIconTheme so our custom symbolic tool icons resolve by name. Idempotent.""" global _search_path_added if _search_path_added: return theme = Gtk.IconTheme.get_default() existing = set(theme.get_search_path() or []) # _icons.py: lib/solaar/ui/perkey/_icons.py -> parents[4] = repo root candidates = [ Path(__file__).resolve().parents[4] / "share" / "solaar" / "icons", ] for c in candidates: if c.is_dir() and str(c) not in existing: theme.append_search_path(str(c)) _search_path_added = True def themed_icon_image(icon_name: str, style_widget: Gtk.Widget) -> Gtk.Image | None: """Load a Solaar tool icon and recolor it to match the given widget's text foreground color, so the icons follow the active GTK theme (light / dark / custom). Returns None if the icon can't be loaded. """ ensure_icon_path() theme = Gtk.IconTheme.get_default() icon_info = theme.lookup_icon(icon_name, ICON_PIXEL_SIZE, Gtk.IconLookupFlags.FORCE_SIZE) if icon_info is None: return None path = icon_info.get_filename() if not path: return None fg = style_widget.get_style_context().get_color(Gtk.StateFlags.NORMAL) color = f"#{int(fg.red * 255):02x}{int(fg.green * 255):02x}{int(fg.blue * 255):02x}" try: with open(path, "r", encoding="utf-8") as f: svg = f.read() svg = svg.replace("currentColor", color) stream = Gio.MemoryInputStream.new_from_data(svg.encode("utf-8")) pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, ICON_PIXEL_SIZE, ICON_PIXEL_SIZE, True) return Gtk.Image.new_from_pixbuf(pixbuf) except Exception as e: logger.debug("recolor failed for %s: %s", icon_name, e) return None def _fg_color_key(widget: Gtk.Widget) -> tuple[float, float, float]: fg = widget.get_style_context().get_color(Gtk.StateFlags.NORMAL) return (round(fg.red, 3), round(fg.green, 3), round(fg.blue, 3)) def attach_themed_icon(button: Gtk.Container, icon_name: str) -> int | None: """Add a themed icon to `button` and re-render it whenever the active GTK theme changes the button's foreground color. Returns the style-updated signal handler ID, or None if the icon couldn't be loaded (in which case the button is left unchanged so the caller can fall back to a text label). Listening to the button's own ``style-updated`` signal — instead of ``Gtk.Settings notify::gtk-theme-name`` — means we read the foreground color *after* GTK has re-resolved CSS for the new theme. Subscribing to the Settings notify fires too early; it returns the stale (pre-switch) color and produces icons that all settle on the previous theme's tone. We guard the rebuild with a per-button color key so unrelated style updates (hover, focus, active) don't trigger needless re-renders. """ image = themed_icon_image(icon_name, button) if image is None: return None button.add(image) image.show() state = {"color_key": _fg_color_key(button)} def _refresh(_widget) -> None: new_key = _fg_color_key(button) if new_key == state["color_key"]: return state["color_key"] = new_key new_image = themed_icon_image(icon_name, button) if new_image is None: return old = button.get_child() if old is not None: button.remove(old) button.add(new_image) new_image.show() return button.connect("style-updated", _refresh) Solaar-1.1.20/lib/solaar/ui/perkey/binding.py000066400000000000000000000052201522022367600207470ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Bind a Layout to a sink's reported zone list. Cells whose `zone_id` the device reports are marked bound. Cells whose zone the device does not report stay disabled (greyed). Device-reported zones not covered by any cell get synthesized as strip cells using the sink's labels — this catches G-keys, logo, media keys and any device-specific extras. """ from __future__ import annotations from collections.abc import Callable from .layout import BoundCell from .layout import BoundLayout from .layout import Cell from .layout import Layout def bind(layout: Layout, zones: list[int], label_for: Callable[[int], str]) -> BoundLayout: reported = set(zones) claimed: set[int] = set() matrix: list[BoundCell] = [] strip: list[BoundCell] = [] for c in layout.matrix_cells(): bound = c.zone_id in reported if bound: claimed.add(c.zone_id) matrix.append(BoundCell(cell=c, bound=bound)) for c in layout.strip_cells(): bound = c.zone_id in reported if bound: claimed.add(c.zone_id) strip.append(BoundCell(cell=c, bound=bound)) unmapped_all = tuple(z for z in zones if z not in claimed) # Filter unmapped zones through the layout's curated allowlist. Without # this, firmware-reported phantoms (G515 reports 47, 97, 99-103, 254) # would surface as paintable strip cells that don't address any LED. if layout.extra_zones is None: showable = unmapped_all else: showable = tuple(z for z in unmapped_all if z in layout.extra_zones) next_col = max((bc.cell.col for bc in strip), default=-1) + 1 for z in showable: synth = Cell(zone_id=z, row=0, col=next_col, group="strip", label=label_for(z)) strip.append(BoundCell(cell=synth, bound=True)) next_col += 1 return BoundLayout(matrix=tuple(matrix), strip=tuple(strip), unmapped=unmapped_all) Solaar-1.1.20/lib/solaar/ui/perkey/canvas.py000066400000000000000000000424131522022367600206150ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Cairo-rendered keyboard canvas. Renders a BoundLayout as colored rectangles and dispatches paint events through a configurable Tool to the editor. """ from __future__ import annotations import logging from enum import Enum from typing import Callable import gi gi.require_version("Gtk", "3.0") from gi.repository import Gdk # NOQA: E402 from gi.repository import GObject # NOQA: E402 from gi.repository import Gtk # NOQA: E402 from .layout import BoundCell # NOQA: E402 from .layout import BoundLayout # NOQA: E402 from .layout import Cell # NOQA: E402 from .tools import TOOLS # NOQA: E402 from .tools import ToolContext # NOQA: E402 logger = logging.getLogger(__name__) class GtkSignal(Enum): DRAW = "draw" BUTTON_PRESS_EVENT = "button-press-event" BUTTON_RELEASE_EVENT = "button-release-event" MOTION_NOTIFY_EVENT = "motion-notify-event" LEAVE_NOTIFY_EVENT = "leave-notify-event" CELL_PX = 36 GUTTER_PX = 4 STRIP_GAP_PX = 16 PADDING_PX = 8 class KeyboardCanvas(Gtk.DrawingArea): __gsignals__ = { # Emitted on stroke release. delta is dict[zone_id, color]. "paint": (GObject.SignalFlags.RUN_FIRST, None, (object,)), } def __init__(self) -> None: super().__init__() self._bound: BoundLayout | None = None self._colors: dict[int, int] = {} # zone_id -> packed RGB or -1 (unset) self._active_color: int = 0xFF0000 self._gradient_colors_source: Callable[[], tuple[int, int]] | None = None self._zone_base_color: int | None = None self._tool_name: str = "single" self._press_cell: BoundCell | None = None self._motion_cell: BoundCell | None = None self._brush_path: list[int] = [] self._dragging: bool = False self.set_can_focus(True) self.add_events( Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK | Gdk.EventMask.POINTER_MOTION_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK ) self.connect(GtkSignal.DRAW.value, self._on_draw) self.connect(GtkSignal.BUTTON_PRESS_EVENT.value, self._on_press) self.connect(GtkSignal.BUTTON_RELEASE_EVENT.value, self._on_release) self.connect(GtkSignal.MOTION_NOTIFY_EVENT.value, self._on_motion) self.connect(GtkSignal.LEAVE_NOTIFY_EVENT.value, self._on_leave) # ---- public API ---- def set_layout(self, bound: BoundLayout) -> None: self._bound = bound self._update_size() self.queue_draw() def set_colors(self, colors: dict[int, int]) -> None: self._colors = dict(colors) self.queue_draw() def update_colors(self, deltas: dict[int, int]) -> None: self._colors.update(deltas) self.queue_draw() def set_active_color(self, color: int) -> None: self._active_color = int(color) def set_gradient_colors_source(self, source: Callable[[], tuple[int, int]] | None) -> None: self._gradient_colors_source = source def set_zone_base_color(self, color: int | None) -> None: self._zone_base_color = None if color is None else int(color) self.queue_draw() def set_tool(self, name: str) -> None: if name in TOOLS: self._tool_name = name # ---- size / hit-test ---- def _matrix_size(self) -> tuple[int, int]: if not self._bound: return 0, 0 max_col = 0 max_row = 0 for bc in self._bound.matrix: c = bc.cell max_col = max(max_col, c.col + int(round(c.width))) max_row = max(max_row, c.row + int(round(c.height))) return max_row, max_col def _strip_size(self) -> int: if not self._bound: return 0 return len(self._bound.strip) def _update_size(self) -> None: rows, cols = self._matrix_size() strip_n = self._strip_size() w = PADDING_PX * 2 + cols * CELL_PX + max(0, cols - 1) * GUTTER_PX matrix_h = rows * CELL_PX + max(0, rows - 1) * GUTTER_PX strip_h = (CELL_PX + STRIP_GAP_PX) if strip_n else 0 h = PADDING_PX * 2 + matrix_h + strip_h # widen if strip is wider than matrix if strip_n: sw = PADDING_PX * 2 + strip_n * CELL_PX + max(0, strip_n - 1) * GUTTER_PX w = max(w, sw) self.set_size_request(w, h) def _cell_rect(self, bc: BoundCell) -> tuple[float, float, float, float]: c = bc.cell if self._bound is not None and bc in self._bound.strip: # strip cells: laid out in a flat row beneath the matrix rows, _cols = self._matrix_size() matrix_h = rows * CELL_PX + max(0, rows - 1) * GUTTER_PX strip_idx = self._bound.strip.index(bc) x = PADDING_PX + strip_idx * (CELL_PX + GUTTER_PX) y = PADDING_PX + matrix_h + STRIP_GAP_PX return (x, y, CELL_PX, CELL_PX) x = PADDING_PX + c.col * (CELL_PX + GUTTER_PX) y = PADDING_PX + c.row * (CELL_PX + GUTTER_PX) w = c.width * CELL_PX + max(0.0, c.width - 1.0) * GUTTER_PX h = c.height * CELL_PX + max(0.0, c.height - 1.0) * GUTTER_PX return (x, y, w, h) def _cell_at(self, x: float, y: float) -> BoundCell | None: if not self._bound: return None for bc in list(self._bound.matrix) + list(self._bound.strip): cx, cy, cw, ch = self._cell_rect(bc) if cx <= x < cx + cw and cy <= y < cy + ch: return bc # Phantom anchor for gaps in the matrix grid — gives rect/gradient # drags a valid endpoint where no real cell exists. rows, cols = self._matrix_size() matrix_w = cols * CELL_PX + max(0, cols - 1) * GUTTER_PX matrix_h = rows * CELL_PX + max(0, rows - 1) * GUTTER_PX if PADDING_PX <= x < PADDING_PX + matrix_w and PADDING_PX <= y < PADDING_PX + matrix_h: col = int((x - PADDING_PX) // (CELL_PX + GUTTER_PX)) row = int((y - PADDING_PX) // (CELL_PX + GUTTER_PX)) if 0 <= col < cols and 0 <= row < rows: return BoundCell(cell=Cell(zone_id=-1, row=row, col=col), bound=False) return None # ---- draw ---- def _on_draw(self, _widget, cr) -> bool: if not self._bound: return False for bc in self._bound.matrix: self._draw_cell(cr, bc) for bc in self._bound.strip: self._draw_cell(cr, bc) if self._dragging and self._press_cell and self._motion_cell: tool = TOOLS.get(self._tool_name) if tool is not None: if tool.overlay_shape == "rect": self._draw_rect_overlay(cr, self._press_cell, self._motion_cell) elif tool.overlay_shape == "line": self._draw_line_overlay(cr, self._press_cell, self._motion_cell) return False def _draw_cell(self, cr, bc: BoundCell) -> None: x, y, w, h = self._cell_rect(bc) color = self._colors.get(bc.cell.zone_id, -1) # background if not bc.bound: cr.set_source_rgba(0.18, 0.18, 0.20, 1.0) elif color is None or color < 0: self._fill_checker(cr, x, y, w, h) cr.set_source_rgba(0, 0, 0, 0) # no overlay fill else: r = ((color >> 16) & 0xFF) / 255.0 g = ((color >> 8) & 0xFF) / 255.0 b = (color & 0xFF) / 255.0 cr.set_source_rgba(r, g, b, 1.0) if bc.bound and (color is not None and color >= 0): self._round_rect(cr, x, y, w, h, 4) cr.fill_preserve() elif not bc.bound: self._round_rect(cr, x, y, w, h, 4) cr.fill_preserve() else: self._round_rect(cr, x, y, w, h, 4) # border cr.set_source_rgba(0, 0, 0, 0.55) cr.set_line_width(1.0) cr.stroke() # label label = bc.cell.label or str(bc.cell.zone_id) cr.set_source_rgba(*self._label_color(color, bc.bound)) cr.select_font_face("Sans") cr.set_font_size(11.0 if len(label) <= 3 else 9.0) try: extents = cr.text_extents(label) tx = x + (w - extents.width) / 2 - extents.x_bearing ty = y + (h + extents.height) / 2 - extents.y_bearing - extents.height cr.move_to(tx, ty) cr.show_text(label) except Exception as e: logger.debug("text rendering failed for %r: %s", label, e) def _fill_checker(self, cr, x, y, w, h) -> None: # Diagonal hash for "no change" cells. The background is the zone # base color (what these cells actually display on the keyboard). # Stripes alternate darker / lighter than base in equal measure so # the cell's perceived average stays at the base color, instead of # being uniformly biased toward black or white as a single-overlay # stripe would. cr.save() self._round_rect(cr, x, y, w, h, 4) cr.clip() base = self._zone_base_color if base is not None and base >= 0: r = ((base >> 16) & 0xFF) / 255.0 g = ((base >> 8) & 0xFF) / 255.0 b = (base & 0xFF) / 255.0 cr.set_source_rgba(r, g, b, 1.0) cr.rectangle(x, y, w, h) cr.fill() # Per-channel ±offset. When a channel is too close to 0 or 1 to # fit the full offset, halve the offset on the constrained side # (per spec: average drifts at the limits, but stays centered on # base elsewhere). offset = 0.22 def _shift(v: float) -> tuple[float, float]: down_off = offset if (v - offset) >= 0.0 else offset / 2.0 up_off = offset if (v + offset) <= 1.0 else offset / 2.0 return max(0.0, v - down_off), min(1.0, v + up_off) rd, ru = _shift(r) gd, gu = _shift(g) bd, bu = _shift(b) # Interleave darker and lighter stripes (period = step per set, # other-color set offset by step/2). Equal coverage of the two # colors keeps the perceived average at base. cr.set_line_width(1.5) step = 6 half = step // 2 d_max = int(w + h) cr.set_source_rgba(rd, gd, bd, 1.0) d = -int(h) while d <= d_max: cr.move_to(x + d, y + h) cr.line_to(x + d + h, y) cr.stroke() d += step cr.set_source_rgba(ru, gu, bu, 1.0) d = -int(h) + half while d <= d_max: cr.move_to(x + d, y + h) cr.line_to(x + d + h, y) cr.stroke() d += step else: # No zone base color known — fall back to a neutral dark bg with # medium-gray stripes; "average = base" doesn't apply since there # is no expected color to preserve. cr.set_source_rgba(0.30, 0.30, 0.32, 1.0) cr.rectangle(x, y, w, h) cr.fill() cr.set_source_rgba(0.55, 0.55, 0.60, 1.0) cr.set_line_width(1.5) step = 5 d_max = int(w + h) d = -int(h) while d <= d_max: cr.move_to(x + d, y + h) cr.line_to(x + d + h, y) cr.stroke() d += step cr.restore() def _round_rect(self, cr, x, y, w, h, r) -> None: cr.new_sub_path() cr.arc(x + w - r, y + r, r, -1.5708, 0) cr.arc(x + w - r, y + h - r, r, 0, 1.5708) cr.arc(x + r, y + h - r, r, 1.5708, 3.1416) cr.arc(x + r, y + r, r, 3.1416, 4.7124) cr.close_path() def _label_color(self, color: int, bound: bool) -> tuple[float, float, float, float]: if not bound: return (0.50, 0.50, 0.52, 1.0) if color is None or color < 0: return (0.85, 0.85, 0.88, 1.0) # luminance heuristic r = ((color >> 16) & 0xFF) / 255.0 g = ((color >> 8) & 0xFF) / 255.0 b = (color & 0xFF) / 255.0 lum = 0.299 * r + 0.587 * g + 0.114 * b return (0, 0, 0, 1.0) if lum > 0.55 else (1, 1, 1, 1.0) def _draw_rect_overlay(self, cr, a: BoundCell, b: BoundCell) -> None: ax, ay, aw, ah = self._cell_rect(a) bx, by, bw, bh = self._cell_rect(b) x0 = min(ax, bx) - 2 y0 = min(ay, by) - 2 x1 = max(ax + aw, bx + bw) + 2 y1 = max(ay + ah, by + bh) + 2 cr.set_source_rgba(0.30, 0.65, 1.0, 0.85) cr.set_line_width(1.5) cr.set_dash([4.0, 3.0]) cr.rectangle(x0, y0, x1 - x0, y1 - y0) cr.stroke() cr.set_dash([]) def _draw_line_overlay(self, cr, a: BoundCell, b: BoundCell) -> None: ax, ay, aw, ah = self._cell_rect(a) bx, by, bw, bh = self._cell_rect(b) ax_c, ay_c = ax + aw / 2, ay + ah / 2 bx_c, by_c = bx + bw / 2, by + bh / 2 cr.set_source_rgba(0.30, 0.65, 1.0, 0.95) cr.set_line_width(2.0) cr.set_dash([5.0, 3.0]) cr.move_to(ax_c, ay_c) cr.line_to(bx_c, by_c) cr.stroke() cr.set_dash([]) # endpoint dots — solid so the anchors read clearly for cx, cy in ((ax_c, ay_c), (bx_c, by_c)): cr.arc(cx, cy, 4.0, 0, 6.283) cr.fill() # ---- input ---- def _on_press(self, _w, event: Gdk.EventButton) -> bool: if event.button != 1: return False bc = self._cell_at(event.x, event.y) if bc is None: return False tool = TOOLS.get(self._tool_name) # Endpoint tools (rect/gradient) anchor on cell centers regardless of # bind state; brush/bucket need a real key to paint/flood. if not (tool and tool.overlay_shape) and not bc.bound: return False self._press_cell = bc self._motion_cell = bc self._dragging = True self._brush_path = [bc.cell.zone_id] if tool is not None and tool.is_brush: self.update_colors({bc.cell.zone_id: self._active_color}) else: self.queue_draw() return True def _on_motion(self, _w, event: Gdk.EventMotion) -> bool: if not self._dragging: return False bc = self._cell_at(event.x, event.y) if bc is None: return False tool = TOOLS.get(self._tool_name) if not (tool and tool.overlay_shape) and not bc.bound: return False if bc is self._motion_cell: return False self._motion_cell = bc if tool is not None and tool.is_brush: if bc.cell.zone_id not in self._brush_path: self._brush_path.append(bc.cell.zone_id) self.update_colors({bc.cell.zone_id: self._active_color}) else: self.queue_draw() return True def _on_release(self, _w, event: Gdk.EventButton) -> bool: if event.button != 1 or not self._dragging: return False self._dragging = False if self._press_cell is None: return False if self._bound: bound_zones = {bc.cell.zone_id: bc for bc in list(self._bound.matrix) + list(self._bound.strip)} strip_zones = frozenset(bc.cell.zone_id for bc in self._bound.strip) else: bound_zones = {} strip_zones = frozenset() if self._tool_name == "gradient" and self._gradient_colors_source is not None: grad_active, grad_previous = self._gradient_colors_source() ctx = ToolContext( active_color=int(grad_active), last_color=int(grad_previous), cells_by_zone=bound_zones, strip_zones=strip_zones, current_colors=dict(self._colors), ) else: ctx = ToolContext( active_color=self._active_color, last_color=self._active_color, cells_by_zone=bound_zones, strip_zones=strip_zones, current_colors=dict(self._colors), ) tool = TOOLS.get(self._tool_name) delta: dict[int, int] = {} if tool is not None: delta = tool.compute(self._press_cell, self._motion_cell, list(self._brush_path), ctx) self._press_cell = None self._motion_cell = None self._brush_path = [] self.queue_draw() if delta: self.update_colors(delta) self.emit("paint", delta) return True def _on_leave(self, _w, _event) -> bool: # don't cancel drags on leave; let the user re-enter return False Solaar-1.1.20/lib/solaar/ui/perkey/control.py000066400000000000000000000234051522022367600210220ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Inline placeholder control replacing MapChoiceControl for opted-in settings. Renders a summary line + button. Click opens the per-key editor dialog, backed by a SettingSink adapter that bridges the editor protocol to the Solaar Setting object. The editor never touches the Setting directly. """ from __future__ import annotations import logging from enum import Enum import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # NOQA: E402 from solaar.i18n import _ # NOQA: E402 from . import dialog as dialog_mod # NOQA: E402 from .layouts import layout_for # NOQA: E402 logger = logging.getLogger(__name__) class GtkSignal(Enum): CLICKED = "clicked" # Sentinel matching special_keys.COLORSPLUS["No change"]. NO_CHANGE = -1 class _SettingSink: """Bridge between a Solaar Setting and the editor's PerKeyColorSink protocol.""" def __init__(self, setting, sbox) -> None: self._setting = setting self._sbox = sbox self._listeners: list = [] @property def title(self) -> str: device = getattr(self._setting, "_device", None) name = getattr(device, "name", None) or getattr(device, "codename", None) or "" return name or self._setting.label @property def zones(self) -> list[int]: return [int(k) for k in self._setting.choices] @property def current(self) -> dict[int, int]: return dict(self._setting._value or {}) def label(self, zone: int) -> str: for k in self._setting.choices: if int(k) == int(zone): return str(k) return f"KEY {zone}" def write_one(self, zone: int, color: int) -> None: if self._setting._value is None: self._setting._value = {} self._setting._value[int(zone)] = int(color) # Lazy import to avoid a circular module-load between config_panel and perkey. from solaar.ui.config_panel import _write_async _write_async(self._setting, int(color), self._sbox, key=int(zone)) self._notify() def write_bulk(self, deltas: dict[int, int]) -> None: if not deltas: return if self._setting._value is None: self._setting._value = {} merged = dict(self._setting._value) merged.update({int(k): int(v) for k, v in deltas.items()}) self._setting._value = merged from solaar.ui.config_panel import _write_async _write_async(self._setting, merged, self._sbox, key=None) self._notify() def subscribe(self, listener): self._listeners.append(listener) def unsubscribe() -> None: # Idempotent: the editor calls this on shutdown, but the listener # may already be gone if the sink itself was torn down first. try: self._listeners.remove(listener) except ValueError: pass return unsubscribe def _palette_key(self) -> str: return f"_palette:{self._setting.name}" def palette_state(self) -> tuple[int, int] | None: device = getattr(self._setting, "_device", None) persister = getattr(device, "persister", None) if persister is None: return None entry = persister.get(self._palette_key()) if not isinstance(entry, dict): return None active = entry.get("active") previous = entry.get("previous", active) if not isinstance(active, int) or not isinstance(previous, int): return None return (int(active), int(previous)) def set_palette_state(self, active: int, previous: int) -> None: device = getattr(self._setting, "_device", None) persister = getattr(device, "persister", None) if persister is None: return persister[self._palette_key()] = {"active": int(active), "previous": int(previous)} def zone_base_color(self) -> int | None: """Color used to render per-key unset cells in the editor. Matches rgb_power.effective_zone_base_color: black when zone is ignored, the saved zone color otherwise.""" device = getattr(self._setting, "_device", None) if device is None: return None from logitech_receiver import rgb_power return int(rgb_power.effective_zone_base_color(device)) def _notify(self) -> None: snapshot = self.current for cb in list(self._listeners): try: cb(snapshot) except Exception as e: logger.warning("perkey listener raised: %s", e) def push_external_value(self, value) -> None: """Called from the inline control when the framework reports a value change.""" if isinstance(value, dict): self._notify() class PerKeyControl(Gtk.Box): """Replaces MapChoiceControl for per-key color settings. Ducktypes the four `Control` methods (`set_sensitive`, `set_value`, `get_value`, `layout`) used by `_create_sbox` / `_update_setting_item`. """ def __init__(self, sbox) -> None: super().__init__(orientation=Gtk.Orientation.HORIZONTAL, spacing=8) self.sbox = sbox self._setting = sbox.setting self._value: dict | None = None self._sink = _SettingSink(self._setting, sbox) self._summary = Gtk.Label(label=_("(not loaded)")) self._summary.set_xalign(0.0) self.pack_start(self._summary, True, True, 0) self._open_btn = Gtk.Button(label=_("Open editor…")) self._open_btn.set_tooltip_text(_("Paint key colors on a keyboard layout")) self._open_btn.connect(GtkSignal.CLICKED.value, self._on_open) self.pack_end(self._open_btn, False, False, 0) # ---- Control protocol ---- def set_sensitive(self, sensitive: bool) -> None: super().set_sensitive(bool(sensitive)) self._open_btn.set_sensitive(bool(sensitive)) def set_value(self, value) -> None: if value is None: return if not isinstance(value, dict): return # _write_async wraps single-key writes as `{key: written_value}` so # MapChoiceControl can update one combo cell. We need to keep the # full picture for the summary count, so merge instead of replace # when a partial dict comes in. existing = self._setting._value if isinstance(self._setting._value, dict) else None if existing and len(value) < len(existing): merged = dict(existing) merged.update(value) self._value = merged else: self._value = value self._sink.push_external_value(self._value) self._refresh_summary() def get_value(self): return self._value def layout(self, sbox, label, change, spinner, failed) -> bool: # Match the standard Control packing order so our button sits where # every other setting's widget sits, just left of spinner/change-icon. sbox.pack_start(label, False, False, 0) sbox.pack_end(change, False, False, 0) sbox.pack_end(self, False, False, 0) sbox.pack_end(spinner, False, False, 0) sbox.pack_end(failed, False, False, 0) return self # ---- internal ---- def _refresh_summary(self) -> None: if not isinstance(self._value, dict): self._summary.set_text(_("(no zones)")) return total = len(self._value) painted = sum(1 for v in self._value.values() if isinstance(v, int) and v != NO_CHANGE and v >= 0) self._summary.set_text(_("{painted} / {total} keys painted").format(painted=painted, total=total)) def _on_open(self, _btn) -> None: feature = getattr(self._setting, "feature", None) feature_int = int(feature) if feature is not None else 0 device = getattr(self._setting, "_device", None) kind_obj = getattr(device, "kind", None) kind_str = str(kind_obj).lower() if kind_obj is not None else "" hint = { "kind": kind_str if kind_str else None, "wpid": getattr(device, "wpid", None), "codename": getattr(device, "codename", None), "name": getattr(device, "name", None), "keyboard_layout": getattr(device, "keyboard_layout", None), "zones": list(self._sink.zones), "zone_count": len(self._sink.zones), } layout = layout_for(feature_int, hint) # Stable per-device key so the same physical device on USB and on # the receiver shares a single dialog. unitId is read from the # device firmware (via DeviceInformation) and is the same across # transports; serial is per-pairing-slot. id(self._sink) is a # last-resort fallback that should never be hit in practice. key = ( getattr(device, "unitId", None) or getattr(device, "serial", None) or getattr(device, "hid_serial", None) or getattr(device, "codename", None) or id(self._sink) ) dlg = dialog_mod.get_dialog(key) dlg.present(self._sink, layout) Solaar-1.1.20/lib/solaar/ui/perkey/dialog.py000066400000000000000000000110461522022367600205770ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Per-device dialogs hosting a PerKeyEditor. One dialog instance is kept per device key (firmware unit-id, falling back to other stable identifiers — see ``get_dialog``). The same physical device on different transports (receiver vs direct USB) shares a key so it doesn't open two windows. """ from __future__ import annotations from enum import Enum from typing import Hashable import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # NOQA: E402 from solaar.i18n import _ # NOQA: E402 from .editor import PerKeyEditor # NOQA: E402 from .layout import Layout # NOQA: E402 from .protocol import PerKeyColorSink # NOQA: E402 class GtkSignal(Enum): DELETE_EVENT = "delete-event" _dialogs: dict[Hashable, "PerKeyEditorDialog"] = {} class PerKeyEditorDialog: def __init__(self, key: Hashable) -> None: self._key = key self._window: Gtk.Window | None = None self._wrapper: Gtk.Box | None = None self._editor: PerKeyEditor | None = None self._sink: PerKeyColorSink | None = None def _on_delete(self, _w, _e) -> bool: self._destroy() _dialogs.pop(self._key, None) return True def _destroy(self) -> None: if self._editor is not None: self._editor.shutdown() self._editor = None if self._window is not None: self._window.destroy() self._window = None self._wrapper = None self._sink = None def present(self, sink: PerKeyColorSink, layout: Layout | None) -> None: # Re-opening for the same sink while the window is already open: # just raise it (no rebuild flicker, preserves any in-progress # interaction state). if self._window is not None and self._sink is sink: self._window.present() return # Otherwise build a fresh window. We always recreate rather than # swap content in place because Gtk.Window.resize() after first # show is unreliable across X11/Wayland WMs — the WM often keeps # the original geometry — and a new window picks up the layout's # natural size cleanly on first show. self._destroy() self._sink = sink self._window = Gtk.Window() self._window.set_title(_("Per-key Lighting") + " — " + sink.title) self._window.connect(GtkSignal.DELETE_EVENT.value, self._on_delete) self._wrapper = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) self._wrapper.set_border_width(8) self._window.add(self._wrapper) self._editor = PerKeyEditor(sink, layout) self._wrapper.pack_start(self._editor, True, True, 0) self._wrapper.show_all() # Ask GTK what the wrapper actually wants to be — the canvas's # size_request propagates up through ScrolledWindow + editor VBox # (toolbar + scrolled canvas) + the wrapper's border, so the # natural size already accounts for every layout contribution. _min, nat = self._wrapper.get_preferred_size() if nat.width > 0 and nat.height > 0: self._window.resize(nat.width, nat.height) self._window.present() def get_dialog(key: Hashable) -> PerKeyEditorDialog: """Return the dialog for `key`, creating one if none is open. `key` should be a stable per-device identifier. The caller (control.py) builds it from `device.unitId` first — that's read from the device firmware via the DeviceInformation feature and is the same regardless of whether the device is on a receiver or plugged directly via USB, so the same physical device doesn't open two windows when its transport changes. """ d = _dialogs.get(key) if d is None: d = PerKeyEditorDialog(key) _dialogs[key] = d return d Solaar-1.1.20/lib/solaar/ui/perkey/editor.py000066400000000000000000000204721522022367600206310ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Editor widget: combines toolbar + palette + canvas into one VBox. The editor consumes only the PerKeyColorSink protocol — no device imports, no Setting imports — preserving the FE/BE seam. """ from __future__ import annotations import logging from enum import Enum import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # NOQA: E402 from solaar.i18n import _ # NOQA: E402 from . import binding # NOQA: E402 from ._icons import attach_themed_icon # NOQA: E402 from .canvas import KeyboardCanvas # NOQA: E402 from .layout import Layout # NOQA: E402 from .palette import GradientSwatch # NOQA: E402 from .palette import Palette # NOQA: E402 from .protocol import PerKeyColorSink # NOQA: E402 logger = logging.getLogger(__name__) class GtkSignal(Enum): COLOR_CHANGED = "color-changed" PAINT = "paint" TOGGLED = "toggled" _TOOL_LABELS = { "single": (_("Brush"), _("Click or drag to paint individual keys")), "rect": (_("Rect"), _("Drag to select a rectangle of keys, painted on release")), "bucket": (_("Fill"), _("Flood-fill connected keys of the same color with the active color")), } _TOOL_TOOLTIPS = { "gradient": _("Drag to fade from previous color to active color"), } _TOOL_ICON_NAMES = { "single": "solaar-tool-brush-symbolic", "rect": "solaar-tool-rect-symbolic", "bucket": "solaar-tool-bucket-symbolic", } class PerKeyEditor(Gtk.Box): def __init__(self, sink: PerKeyColorSink, layout: Layout | None = None) -> None: super().__init__(orientation=Gtk.Orientation.VERTICAL, spacing=8) self._sink = sink self._layout = layout self._unsubscribe = None # toolbar row toolbar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8) self._tool_buttons: dict[str, Gtk.RadioButton] = {} self._gradient_swatch: GradientSwatch | None = None first: Gtk.RadioButton | None = None supported = layout.supported_tools if layout else ("single", "rect", "bucket", "gradient") for name in supported: if name == "gradient": btn = Gtk.RadioButton.new_from_widget(first) btn.set_mode(False) self._gradient_swatch = GradientSwatch() btn.add(self._gradient_swatch) btn.set_tooltip_text(_TOOL_TOOLTIPS["gradient"]) else: label, tip = _TOOL_LABELS.get(name, (name, "")) icon_name = _TOOL_ICON_NAMES.get(name) btn = Gtk.RadioButton.new_from_widget(first) btn.set_mode(False) # render as toggle button rather than radio if icon_name and attach_themed_icon(btn, icon_name) is not None: btn.set_tooltip_text(tip or label) btn.get_accessible().set_name(label) else: btn.set_label(label) btn.set_tooltip_text(tip) btn.connect(GtkSignal.TOGGLED.value, self._on_tool_toggled, name) if first is None: first = btn toolbar.pack_start(btn, False, False, 0) self._tool_buttons[name] = btn initial_active, initial_previous = 0xFF0000, 0xFF0000 try: persisted = sink.palette_state() except Exception as e: logger.debug("palette_state read failed: %s", e) persisted = None if persisted is not None: initial_active, initial_previous = persisted self._palette = Palette(active=initial_active, previous=initial_previous) self._palette.connect(GtkSignal.COLOR_CHANGED.value, self._on_color_changed) toolbar.pack_end(self._palette, False, False, 0) if self._gradient_swatch is not None: self._gradient_swatch.update(self._palette.get_color(), self._palette.get_last_color()) self.pack_start(toolbar, False, False, 0) # canvas inside a scrolled window so wide layouts can scroll if the # window is shrunk below content size. propagate_natural_size lets the # window auto-fit small layouts (e.g. an 8-LED mouse) without forcing # an oversized minimum. scroll = Gtk.ScrolledWindow() scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scroll.set_propagate_natural_width(True) scroll.set_propagate_natural_height(True) # Inset frame around the keyboard so it reads as a distinct panel # rather than floating flat against the dialog background. scroll.set_shadow_type(Gtk.ShadowType.IN) self._canvas = KeyboardCanvas() self._canvas.connect(GtkSignal.PAINT.value, self._on_canvas_paint) scroll.add(self._canvas) self.pack_start(scroll, True, True, 0) self._canvas.set_active_color(self._palette.get_color()) if self._gradient_swatch is not None: self._canvas.set_gradient_colors_source(self._gradient_swatch.get_colors) try: base = sink.zone_base_color() except Exception as e: logger.debug("zone_base_color read failed: %s", e) base = None self._canvas.set_zone_base_color(base) self._refresh_layout() self._sync_from_sink() self._unsubscribe = sink.subscribe(self._on_sink_update) def shutdown(self) -> None: if self._unsubscribe: try: self._unsubscribe() except Exception as e: logger.debug("perkey sink unsubscribe failed: %s", e) self._unsubscribe = None try: self._palette.shutdown() except Exception as e: logger.debug("palette shutdown failed: %s", e) def _refresh_layout(self) -> None: if self._layout is None: # No registered layout: lay out all reported zones as a flat strip. from .layout import Cell zones = list(self._sink.zones) cells = tuple(Cell(zone_id=z, row=0, col=i, group="strip", label=self._sink.label(z)) for i, z in enumerate(zones)) self._layout = Layout(cells=cells, rows=1, cols=max(1, len(zones)), description=f"flat strip ({len(zones)} zones)") bound = binding.bind( self._layout, list(self._sink.zones), self._sink.label, ) self._canvas.set_layout(bound) def _sync_from_sink(self) -> None: self._canvas.set_colors(dict(self._sink.current)) def _on_sink_update(self, current: dict[int, int]) -> None: self._canvas.set_colors(dict(current)) def _on_color_changed(self, _palette, color: int) -> None: self._canvas.set_active_color(color) # Gradient swatch tracks only real picker colors; toggling unset # leaves it alone so the gradient setup isn't disturbed. picker = self._palette.get_picker_color() if self._gradient_swatch is not None: self._gradient_swatch.update(picker, self._palette.get_last_color()) try: self._sink.set_palette_state(picker, self._palette.get_last_color()) except Exception as e: logger.debug("set_palette_state failed: %s", e) def _on_tool_toggled(self, btn: Gtk.RadioButton, name: str) -> None: if btn.get_active(): self._canvas.set_tool(name) def _on_canvas_paint(self, _canvas, delta: dict) -> None: if not delta: return if len(delta) == 1: zone, color = next(iter(delta.items())) self._sink.write_one(int(zone), int(color)) else: self._sink.write_bulk({int(z): int(c) for z, c in delta.items()}) Solaar-1.1.20/lib/solaar/ui/perkey/layout.py000066400000000000000000000067521522022367600206650ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Visual layout primitives for the per-key color editor. This module is pure data. It does not import GTK and does not import from `lib.logitech_receiver`. It is therefore relocatable into a shared package when the frontend/backend split happens. """ from __future__ import annotations from dataclasses import dataclass from dataclasses import field @dataclass(frozen=True) class Cell: """One paintable cell in a layout. `zone_id` is the firmware identifier the device uses for this LED. It is matched against the device's reported zone list at bind time; cells with no matching device zone are drawn disabled. """ zone_id: int row: int col: int width: float = 1.0 height: float = 1.0 group: str = "main" label: str = "" x: float | None = None y: float | None = None @dataclass(frozen=True) class Layout: """A device-class visual layout. Cells in `strip_groups` are rendered as a flat row beneath the matrix region, regardless of their row/col fields. Cells outside `strip_groups` are placed by row/col on the main matrix. `extra_zones` is a curated allowlist of zone ids that may appear in the bottom strip when the device reports them but they are not covered by a layout cell. Zones outside the allowlist are dropped — Logitech firmware bitmaps enumerate phantom/reserved slots (e.g. G515 reports 47, 97, 99-103, 254) that aren't physical keys. Set to `None` to disable filtering. """ cells: tuple[Cell, ...] rows: int cols: int strip_groups: tuple[str, ...] = ("strip",) supported_tools: tuple[str, ...] = ("single", "rect", "bucket", "gradient") extra_zones: frozenset[int] | None = None description: str = "" def matrix_cells(self) -> tuple[Cell, ...]: return tuple(c for c in self.cells if c.group not in self.strip_groups) def strip_cells(self) -> tuple[Cell, ...]: return tuple(c for c in self.cells if c.group in self.strip_groups) def by_zone(self) -> dict[int, Cell]: return {c.zone_id: c for c in self.cells} @dataclass(frozen=True) class BoundCell: """A Cell augmented with bind state, returned by `binding.bind`.""" cell: Cell bound: bool @dataclass(frozen=True) class BoundLayout: """Result of binding a Layout against a sink's reported zones. `matrix` and `strip` are tuples of BoundCell in render order. `unmapped` holds zones the device reported that no Layout cell claimed; these get appended to the strip with synthesized cells. """ matrix: tuple[BoundCell, ...] = field(default_factory=tuple) strip: tuple[BoundCell, ...] = field(default_factory=tuple) unmapped: tuple[int, ...] = field(default_factory=tuple) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/000077500000000000000000000000001522022367600204645ustar00rootroot00000000000000Solaar-1.1.20/lib/solaar/ui/perkey/layouts/__init__.py000066400000000000000000000117421522022367600226020ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Registry of per-key layouts, keyed by feature + a device-class match. Layouts register themselves with a matcher callable. `layout_for(feature, hint)` returns the first matching layout, or None when no model-specific layout is known — in which case the editor renders a flat strip of all reported zones. """ from __future__ import annotations from collections.abc import Callable from ..layout import Layout from . import headset_g522 from . import keyboard_ansi from . import keyboard_iso_azerty from . import keyboard_iso_qwerty from . import keyboard_iso_qwertz from . import keyboard_jis from . import mouse_g502x # (feature_id, matcher, layout). Matcher receives a `hint` dict the editor # assembles from the device (kind, wpid, codename, name, zones list, etc.). _REGISTRY: list[tuple[int, Callable[[dict], bool], Layout]] = [] def register_layout(feature: int, matcher: Callable[[dict], bool], layout: Layout) -> None: _REGISTRY.append((feature, matcher, layout)) def layout_for(feature: int, hint: dict) -> Layout | None: for f, match, layout in _REGISTRY: if f == feature and match(hint): return layout return None def _name_contains(*needles: str) -> Callable[[dict], bool]: """Build a matcher that returns True if any needle is a substring of the device's name or codename (case-insensitive). Useful for device-family layouts where multiple wpids share an LED arrangement. """ folded = tuple(n.upper() for n in needles) def match(hint: dict) -> bool: for field in ("codename", "name"): value = hint.get(field) if not value: continue up = str(value).upper() if any(n in up for n in folded): return True return False return match # --- Keyboard region routing --- # Country code → layout family. Codes from HID++ feature 0x4540 KeyboardLayout. _KEYBOARD_FAMILY_BY_COUNTRY: dict[int, str] = { 1: "ansi", # ISO QWERTY (UK + ES/IT/PT/BE/Nordic — same shape, different keycap legends) 2: "iso_qwerty", 5: "iso_qwerty", 8: "iso_qwerty", 0x0B: "iso_qwerty", 0x0D: "iso_qwerty", 0x0E: "iso_qwerty", 0x0F: "iso_qwerty", 0x16: "iso_qwerty", 0x1D: "iso_qwerty", 0x21: "iso_qwerty", 0x24: "iso_qwerty", # ISO QWERTZ (DE/Swiss) 3: "iso_qwertz", 7: "iso_qwertz", # ISO AZERTY (FR) 4: "iso_azerty", # JIS 9: "jis", 0x3E: "jis", } _FAMILY_LAYOUTS = { "ansi": (keyboard_ansi.LAYOUT_FULL, keyboard_ansi.LAYOUT_TKL), "iso_qwerty": (keyboard_iso_qwerty.LAYOUT_FULL, keyboard_iso_qwerty.LAYOUT_TKL), "iso_qwertz": (keyboard_iso_qwertz.LAYOUT_FULL, keyboard_iso_qwertz.LAYOUT_TKL), "iso_azerty": (keyboard_iso_azerty.LAYOUT_FULL, keyboard_iso_azerty.LAYOUT_TKL), "jis": (keyboard_jis.LAYOUT_FULL, keyboard_jis.LAYOUT_TKL), } def _has_numpad(hint: dict) -> bool: """Numpad presence is read from the device's reported zone bitmap rather than counting zones — G515 reports phantom zones (47, 97, 99-103, 254) that diverge from the keycap count. """ zones = set(hint.get("zones", ())) return 80 in zones or 95 in zones def _keyboard_family(hint: dict) -> str: """Pick a layout family from the device's HID++ keyboard layout country code. Defaults to "ansi" when the code is missing or unknown. """ code = hint.get("keyboard_layout") if code is None: return "ansi" return _KEYBOARD_FAMILY_BY_COUNTRY.get(int(code), "ansi") def _keyboard_matcher(family: str, full_size: bool) -> Callable[[dict], bool]: def match(hint: dict) -> bool: if hint.get("kind") != "keyboard": return False if _has_numpad(hint) != full_size: return False return _keyboard_family(hint) == family return match # PER_KEY_LIGHTING_V2 = 0x8081 for _family, (_full, _tkl) in _FAMILY_LAYOUTS.items(): register_layout(0x8081, _keyboard_matcher(_family, full_size=True), _full) register_layout(0x8081, _keyboard_matcher(_family, full_size=False), _tkl) register_layout(0x8081, _name_contains("G502 X"), mouse_g502x.LAYOUT) # HEADSET_RGB_HOSTMODE = 0x0620 register_layout(0x0620, _name_contains("G522"), headset_g522.LAYOUT) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/_keyboard_base.py000066400000000000000000000261151522022367600237740ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Shared building blocks for regional keyboard layouts. Each region (ANSI, ISO_QWERTY, ISO_QWERTZ, ISO_AZERTY, JIS) shares the function row, nav-cluster, and numpad blocks; only the main alpha block differs (ANSI includes the row 2 col 13 backslash, ISO doesn't). Regional label overrides on top of either main block produce the final layout. Cell positions and groupings adapted from OpenRGB's KeyboardLayoutManager. Zone IDs are firmware values reported by Logitech HID++ feature 0x8081 (PER_KEY_LIGHTING_V2). """ from __future__ import annotations from ..layout import Cell from ..layout import Layout # --- Function row: ESC + F1..F12 (shared across all regions). FN_ROW: tuple[Cell, ...] = ( Cell(zone_id=38, row=0, col=0, group="fn_row", label="Esc"), Cell(zone_id=55, row=0, col=2, group="fn_row", label="F1"), Cell(zone_id=56, row=0, col=3, group="fn_row", label="F2"), Cell(zone_id=57, row=0, col=4, group="fn_row", label="F3"), Cell(zone_id=58, row=0, col=5, group="fn_row", label="F4"), Cell(zone_id=59, row=0, col=6, group="fn_row", label="F5"), Cell(zone_id=60, row=0, col=7, group="fn_row", label="F6"), Cell(zone_id=61, row=0, col=8, group="fn_row", label="F7"), Cell(zone_id=62, row=0, col=9, group="fn_row", label="F8"), Cell(zone_id=63, row=0, col=10, group="fn_row", label="F9"), Cell(zone_id=64, row=0, col=11, group="fn_row", label="F10"), Cell(zone_id=65, row=0, col=12, group="fn_row", label="F11"), Cell(zone_id=66, row=0, col=13, group="fn_row", label="F12"), ) # --- Nav cluster + arrows (shared). EXTRAS: tuple[Cell, ...] = ( Cell(zone_id=67, row=0, col=14, group="extras", label="PrtSc"), Cell(zone_id=68, row=0, col=15, group="extras", label="ScrLk"), Cell(zone_id=69, row=0, col=16, group="extras", label="Pause"), Cell(zone_id=70, row=1, col=14, group="extras", label="Ins"), Cell(zone_id=71, row=1, col=15, group="extras", label="Home"), Cell(zone_id=72, row=1, col=16, group="extras", label="PgUp"), Cell(zone_id=73, row=2, col=14, group="extras", label="Del"), Cell(zone_id=74, row=2, col=15, group="extras", label="End"), Cell(zone_id=75, row=2, col=16, group="extras", label="PgDn"), Cell(zone_id=79, row=4, col=15, group="extras", label="↑"), Cell(zone_id=77, row=5, col=14, group="extras", label="�"), Cell(zone_id=78, row=5, col=15, group="extras", label="↓"), Cell(zone_id=76, row=5, col=16, group="extras", label="→"), ) # --- Numpad block (only on full-size keyboards). NUMPAD: tuple[Cell, ...] = ( Cell(zone_id=80, row=1, col=17, group="numpad", label="Num"), Cell(zone_id=81, row=1, col=18, group="numpad", label="/"), Cell(zone_id=82, row=1, col=19, group="numpad", label="*"), Cell(zone_id=83, row=1, col=20, group="numpad", label="-"), Cell(zone_id=92, row=2, col=17, group="numpad", label="7"), Cell(zone_id=93, row=2, col=18, group="numpad", label="8"), Cell(zone_id=94, row=2, col=19, group="numpad", label="9"), Cell(zone_id=84, row=2, col=20, height=2.0, group="numpad", label="+"), Cell(zone_id=89, row=3, col=17, group="numpad", label="4"), Cell(zone_id=90, row=3, col=18, group="numpad", label="5"), Cell(zone_id=91, row=3, col=19, group="numpad", label="6"), Cell(zone_id=86, row=4, col=17, group="numpad", label="1"), Cell(zone_id=87, row=4, col=18, group="numpad", label="2"), Cell(zone_id=88, row=4, col=19, group="numpad", label="3"), Cell(zone_id=85, row=4, col=20, height=2.0, group="numpad", label="Enter"), Cell(zone_id=95, row=5, col=17, width=2.0, group="numpad", label="0"), Cell(zone_id=96, row=5, col=19, group="numpad", label="."), ) # --- Main alpha block, ANSI (104-key). Includes row 2 col 13 backslash and # omits POUND (row 3 col 12) + ISO_BACKSLASH (row 4 col 1). MAIN_ANSI: tuple[Cell, ...] = ( # Row 1: backtick + numbers + minus/equals + backspace Cell(zone_id=50, row=1, col=0, group="main", label="`"), Cell(zone_id=27, row=1, col=1, group="main", label="1"), Cell(zone_id=28, row=1, col=2, group="main", label="2"), Cell(zone_id=29, row=1, col=3, group="main", label="3"), Cell(zone_id=30, row=1, col=4, group="main", label="4"), Cell(zone_id=31, row=1, col=5, group="main", label="5"), Cell(zone_id=32, row=1, col=6, group="main", label="6"), Cell(zone_id=33, row=1, col=7, group="main", label="7"), Cell(zone_id=34, row=1, col=8, group="main", label="8"), Cell(zone_id=35, row=1, col=9, group="main", label="9"), Cell(zone_id=36, row=1, col=10, group="main", label="0"), Cell(zone_id=42, row=1, col=11, group="main", label="-"), Cell(zone_id=43, row=1, col=12, group="main", label="="), Cell(zone_id=39, row=1, col=13, group="main", label="Bksp"), # Row 2: tab + qwerty + brackets + backslash Cell(zone_id=40, row=2, col=0, group="main", label="Tab"), Cell(zone_id=17, row=2, col=1, group="main", label="Q"), Cell(zone_id=23, row=2, col=2, group="main", label="W"), Cell(zone_id=5, row=2, col=3, group="main", label="E"), Cell(zone_id=18, row=2, col=4, group="main", label="R"), Cell(zone_id=20, row=2, col=5, group="main", label="T"), Cell(zone_id=25, row=2, col=6, group="main", label="Y"), Cell(zone_id=21, row=2, col=7, group="main", label="U"), Cell(zone_id=9, row=2, col=8, group="main", label="I"), Cell(zone_id=15, row=2, col=9, group="main", label="O"), Cell(zone_id=16, row=2, col=10, group="main", label="P"), Cell(zone_id=44, row=2, col=11, group="main", label="["), Cell(zone_id=45, row=2, col=12, group="main", label="]"), Cell(zone_id=46, row=2, col=13, group="main", label="\\"), # Row 3: caps + asdf-row + semi/quote + enter Cell(zone_id=54, row=3, col=0, group="main", label="Caps"), Cell(zone_id=1, row=3, col=1, group="main", label="A"), Cell(zone_id=19, row=3, col=2, group="main", label="S"), Cell(zone_id=4, row=3, col=3, group="main", label="D"), Cell(zone_id=6, row=3, col=4, group="main", label="F"), Cell(zone_id=7, row=3, col=5, group="main", label="G"), Cell(zone_id=8, row=3, col=6, group="main", label="H"), Cell(zone_id=10, row=3, col=7, group="main", label="J"), Cell(zone_id=11, row=3, col=8, group="main", label="K"), Cell(zone_id=12, row=3, col=9, group="main", label="L"), Cell(zone_id=48, row=3, col=10, group="main", label=";"), Cell(zone_id=49, row=3, col=11, group="main", label="'"), Cell(zone_id=37, row=3, col=13, group="main", label="Enter"), # Row 4: shift + zxcv-row + comma/period/slash + rshift Cell(zone_id=105, row=4, col=0, group="main", label="Shift"), Cell(zone_id=26, row=4, col=2, group="main", label="Z"), Cell(zone_id=24, row=4, col=3, group="main", label="X"), Cell(zone_id=3, row=4, col=4, group="main", label="C"), Cell(zone_id=22, row=4, col=5, group="main", label="V"), Cell(zone_id=2, row=4, col=6, group="main", label="B"), Cell(zone_id=14, row=4, col=7, group="main", label="N"), Cell(zone_id=13, row=4, col=8, group="main", label="M"), Cell(zone_id=51, row=4, col=9, group="main", label=","), Cell(zone_id=52, row=4, col=10, group="main", label="."), Cell(zone_id=53, row=4, col=11, group="main", label="/"), Cell(zone_id=109, row=4, col=13, group="main", label="Shift"), # Row 5: bottom row. Space spans cols 3..9 visually. Cell(zone_id=104, row=5, col=0, group="main", label="Ctrl"), Cell(zone_id=107, row=5, col=1, group="main", label="Win"), Cell(zone_id=106, row=5, col=2, group="main", label="Alt"), Cell(zone_id=41, row=5, col=3, width=7.0, group="main", label="Space"), Cell(zone_id=110, row=5, col=10, group="main", label="AltGr"), Cell(zone_id=111, row=5, col=11, group="main", label="Win"), Cell(zone_id=98, row=5, col=12, group="main", label="Menu"), Cell(zone_id=108, row=5, col=13, group="main", label="Ctrl"), ) # --- Main alpha block, ISO. Drops the row 2 col 13 backslash (zone 46 is the # upper half of the L-shape Enter on ISO, addressed by zone 37) and adds # the two ISO-only keys: POUND (zone 47) at row 3 col 12 between ' and # Enter, and ISO_BACKSLASH (zone 97) at row 4 col 1 between Shift and Z. # Regional layouts override the labels to match local keycaps (# / < on # QWERTZ, # / \ on UK QWERTY, * / < on AZERTY). _ISO_EXTRA_KEYS: tuple[Cell, ...] = ( Cell(zone_id=47, row=3, col=12, group="main", label="#"), Cell(zone_id=97, row=4, col=1, group="main", label="\\"), ) MAIN_ISO: tuple[Cell, ...] = tuple(c for c in MAIN_ANSI if not (c.row == 2 and c.col == 13)) + _ISO_EXTRA_KEYS # --- Curated allowlist for unmapped device zones surfaced in the bottom strip. # G-keys, logo, media, brightness — the canonical "extras" Logitech firmware # actually addresses. Phantom zones (e.g. G515's 47, 97, 99-103, 254) drop. EXTRAS_ALLOWLIST: frozenset[int] = frozenset( { 153, # Brightness 155, # Play/Pause 156, # Mute 157, # Next 158, # Previous 180, # G1 181, # G2 182, # G3 183, # G4 184, # G5 210, # Logo } ) def _relabel(cells: tuple[Cell, ...], overrides: dict[int, str]) -> tuple[Cell, ...]: """Return a new tuple where any cell whose zone_id is in `overrides` has its label replaced. Unaffected cells pass through unchanged. """ if not overrides: return cells return tuple( Cell( zone_id=c.zone_id, row=c.row, col=c.col, width=c.width, height=c.height, group=c.group, label=overrides[c.zone_id] if c.zone_id in overrides else c.label, x=c.x, y=c.y, ) for c in cells ) def build_layout( main_cells: tuple[Cell, ...], *, include_numpad: bool, label_overrides: dict[int, str] | None = None, description: str = "", ) -> Layout: """Assemble a regional keyboard layout from a chosen main block + the shared fn-row / extras / (optionally) numpad blocks. Apply per-zone label overrides to every cell whose zone matches. """ cells = FN_ROW + main_cells + EXTRAS if include_numpad: cells = cells + NUMPAD cells = _relabel(cells, label_overrides or {}) cols = 21 if include_numpad else 17 return Layout( cells=cells, rows=6, cols=cols, extra_zones=EXTRAS_ALLOWLIST, description=description, ) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/headset_g522.py000066400000000000000000000043511522022367600232150ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """LED layout for the G522 LIGHTSPEED headset. Eight LEDs in two 2×2 grids — one per earcup, viewed from outside: Left earcup Right earcup ┌─────┬─────� ┌─────┬─────� │ 8 │ 7 │ │ 6 │ 5 │ ├─────┼─────┤ ├─────┼─────┤ │ 4 │ 3 │ │ 2 │ 1 │ └─────┴─────┘ └─────┴─────┘ """ from __future__ import annotations from ..layout import Cell from ..layout import Layout _CELLS: tuple[Cell, ...] = ( # Left earcup (cols 0-1, outer view): top-left=8, top-right=7, bottom-left=4, bottom-right=3 Cell(zone_id=8, row=0, col=0, group="main", label="8"), Cell(zone_id=7, row=0, col=1, group="main", label="7"), Cell(zone_id=4, row=1, col=0, group="main", label="4"), Cell(zone_id=3, row=1, col=1, group="main", label="3"), # Right earcup (cols 3-4, outer view): top-left=6, top-right=5, bottom-left=2, bottom-right=1 Cell(zone_id=6, row=0, col=3, group="main", label="6"), Cell(zone_id=5, row=0, col=4, group="main", label="5"), Cell(zone_id=2, row=1, col=3, group="main", label="2"), Cell(zone_id=1, row=1, col=4, group="main", label="1"), ) LAYOUT: Layout = Layout( cells=_CELLS, rows=2, cols=5, description="Logitech G522 LIGHTSPEED headset (8 LEDs, 4 per earcup)", ) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/keyboard_ansi.py000066400000000000000000000030161522022367600236500ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """ANSI QWERTY keyboard layouts (full 104-key and TKL). Cell positions and groupings derived from OpenRGB's KeyboardLayoutManager (KeyboardLayoutManager.cpp), Copyright (C) Chris M (Dr_No), licensed under GPL-2.0-or-later. This file ports the static ANSI data only; the runtime opcode interpreter for regional overlays is intentionally not included. """ from __future__ import annotations from ..layout import Layout from ._keyboard_base import MAIN_ANSI from ._keyboard_base import build_layout LAYOUT_FULL: Layout = build_layout( MAIN_ANSI, include_numpad=True, description="ANSI QWERTY 104-key full-size", ) LAYOUT_TKL: Layout = build_layout( MAIN_ANSI, include_numpad=False, description="ANSI QWERTY tenkeyless", ) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/keyboard_iso_azerty.py000066400000000000000000000047231522022367600251140ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """ISO AZERTY layout (FR). ISO shape plus French label overrides — A↔Q, W↔Z, M repositioned, French digit-row symbols (& é " ' ( - è _ ç à ). Adapted from OpenRGB. """ from __future__ import annotations from ..layout import Layout from ._keyboard_base import MAIN_ISO from ._keyboard_base import build_layout # zone_id → French label _OVERRIDES: dict[int, str] = { # Row 1 (digit row → French symbols) 50: "²", # backtick → super-2 27: "&", # 1 28: "é", # 2 29: '"', # 3 30: "'", # 4 31: "(", # 5 32: "-", # 6 33: "è", # 7 34: "_", # 8 35: "ç", # 9 36: "à", # 0 42: ")", # minus → close-paren # Row 2 — Q/A and W/Z swaps, brackets relabeled 17: "A", # Q-position → A 23: "Z", # W-position → Z 44: "^", # [-position → caret 45: "$", # ]-position → dollar # Row 3 — A → Q; M moves up to ; position 1: "Q", # A-position → Q 48: "M", # ;-position → M 49: "ù", # '-position → ù # Row 4 — Z-position becomes W; comma row shifts 26: "W", # Z-position → W 13: ",", # M-position → comma 51: ";", # ,-position → semicolon 52: ":", # .-position → colon 53: "!", # /-position → exclamation 47: "*", # POUND key (row 3 col 12) — French * / µ 97: "<", # ISO_BACKSLASH (row 4 col 1), between Shift and W } LAYOUT_FULL: Layout = build_layout( MAIN_ISO, include_numpad=True, label_overrides=_OVERRIDES, description="ISO AZERTY (FR) full-size", ) LAYOUT_TKL: Layout = build_layout( MAIN_ISO, include_numpad=False, label_overrides=_OVERRIDES, description="ISO AZERTY (FR) tenkeyless", ) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/keyboard_iso_qwerty.py000066400000000000000000000033401522022367600251230ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """ISO_QWERTY keyboard layouts (UK English ISO + other QWERTY ISO regions). Same English keycap legends as ANSI; differs only in shape — the row 2 col 13 backslash on ANSI doesn't exist on ISO (that position is the upper half of the L-shape Enter, addressed by zone 37). Used for UK and any other region whose country code maps to "iso_qwerty" without a more specific layout (Spanish, Italian, Portuguese, Belgian, Nordic — those keyboards have the same shape as UK ISO; only their physical keycap legends differ, which our painter doesn't reproduce verbatim). """ from __future__ import annotations from ..layout import Layout from ._keyboard_base import MAIN_ISO from ._keyboard_base import build_layout LAYOUT_FULL: Layout = build_layout( MAIN_ISO, include_numpad=True, description="ISO QWERTY 103-key full-size", ) LAYOUT_TKL: Layout = build_layout( MAIN_ISO, include_numpad=False, description="ISO QWERTY tenkeyless", ) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/keyboard_iso_qwertz.py000066400000000000000000000036471522022367600251360ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """ISO QWERTZ layout (DE / CH). ISO shape plus German label overrides (Y/Z swap, Ü/Ö/Ä/ß placement). Adapted from OpenRGB. """ from __future__ import annotations from ..layout import Layout from ._keyboard_base import MAIN_ISO from ._keyboard_base import build_layout # zone_id → German label _OVERRIDES: dict[int, str] = { 50: "^", # row 1 col 0 — caret/degree (DE keycap) 42: "ß", # row 1 col 11 — eszett 43: "´", # row 1 col 12 — acute accent 25: "Z", # row 2 col 6 — Y/Z swap 44: "Ü", # row 2 col 11 45: "+", # row 2 col 12 48: "Ö", # row 3 col 10 49: "Ä", # row 3 col 11 26: "Y", # row 4 col 2 — Y/Z swap 53: "-", # row 4 col 11 47: "#", # POUND key (row 3 col 12), between Ä and Enter 97: "<", # ISO_BACKSLASH (row 4 col 1), between Shift and Y } LAYOUT_FULL: Layout = build_layout( MAIN_ISO, include_numpad=True, label_overrides=_OVERRIDES, description="ISO QWERTZ (DE/CH) full-size", ) LAYOUT_TKL: Layout = build_layout( MAIN_ISO, include_numpad=False, label_overrides=_OVERRIDES, description="ISO QWERTZ (DE/CH) tenkeyless", ) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/keyboard_jis.py000066400000000000000000000033371522022367600235110ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """JIS layout (JP). ISO shape with Japanese keycap relabels for the bracket / colon positions. Adapted from OpenRGB. JIS keyboards also have additional kana-control keys near the spacebar (henkan/muhenkan/kana) that aren't represented here — matches OpenRGB's coverage. """ from __future__ import annotations from ..layout import Layout from ._keyboard_base import MAIN_ISO from ._keyboard_base import build_layout # zone_id → JIS label _OVERRIDES: dict[int, str] = { 44: "@", # row 2 col 11 — bracket-position becomes at-sign 45: "[", # row 2 col 12 — bracket shifts left 49: ":", # row 3 col 11 — quote-position becomes colon } LAYOUT_FULL: Layout = build_layout( MAIN_ISO, include_numpad=True, label_overrides=_OVERRIDES, description="JIS (JP) full-size", ) LAYOUT_TKL: Layout = build_layout( MAIN_ISO, include_numpad=False, label_overrides=_OVERRIDES, description="JIS (JP) tenkeyless", ) Solaar-1.1.20/lib/solaar/ui/perkey/layouts/mouse_g502x.py000066400000000000000000000034051522022367600231150ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """LED layout for the G502 X family (G502 X, G502 X PLUS, G502 X LIGHTSPEED). Eight LEDs reported as zones 1..8 by the firmware. Positions may need revision per actual hardware. Row 0: 3 . . . . . 2 Row 1: . 4 8 7 6 5 . Row 2: . . . . . . 1 """ from __future__ import annotations from ..layout import Cell from ..layout import Layout _CELLS: tuple[Cell, ...] = ( Cell(zone_id=1, row=2, col=6, group="main", label="1"), Cell(zone_id=2, row=0, col=6, group="main", label="2"), Cell(zone_id=3, row=0, col=0, group="main", label="3"), Cell(zone_id=4, row=1, col=1, group="main", label="4"), Cell(zone_id=5, row=1, col=5, group="main", label="5"), Cell(zone_id=6, row=1, col=4, group="main", label="6"), Cell(zone_id=7, row=1, col=3, group="main", label="7"), Cell(zone_id=8, row=1, col=2, group="main", label="8"), ) LAYOUT: Layout = Layout( cells=_CELLS, rows=3, cols=7, description="Logitech G502 X family", ) Solaar-1.1.20/lib/solaar/ui/perkey/palette.py000066400000000000000000000215701522022367600210010ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Palette: active-color picker + a small gradient swatch widget. The picker (`Palette`) is just a wrapped `Gtk.ColorButton` that emits `color-changed` and remembers the previous active color. The previous color is surfaced visually by the gradient tool button, not in the palette itself — see `GradientSwatch` below, used by `editor.py`. """ from __future__ import annotations from enum import Enum import gi gi.require_version("Gtk", "3.0") from gi.repository import Gdk # NOQA: E402 from gi.repository import GObject # NOQA: E402 from gi.repository import Gtk # NOQA: E402 from solaar.i18n import _ # NOQA: E402 from ._icons import attach_themed_icon # NOQA: E402 _UNSET_ICON_NAME = "solaar-tool-palette-off-symbolic" class GtkSignal(Enum): DRAW = "draw" COLOR_SET = "color-set" TOGGLED = "toggled" def _rgb_to_int(rgba: Gdk.RGBA) -> int: r = max(0, min(255, int(round(rgba.red * 255)))) g = max(0, min(255, int(round(rgba.green * 255)))) b = max(0, min(255, int(round(rgba.blue * 255)))) return (r << 16) | (g << 8) | b def _int_to_rgba(c: int) -> Gdk.RGBA: rgba = Gdk.RGBA() if c is None or c < 0: rgba.red = rgba.green = rgba.blue = 0.5 rgba.alpha = 1.0 return rgba rgba.red = ((c >> 16) & 0xFF) / 255.0 rgba.green = ((c >> 8) & 0xFF) / 255.0 rgba.blue = (c & 0xFF) / 255.0 rgba.alpha = 1.0 return rgba # Sentinel for "no change" / unset paint. Matches special_keys.COLORSPLUS["No change"]. UNSET_COLOR = -1 class Palette(Gtk.Box): __gsignals__ = { "color-changed": (GObject.SignalFlags.RUN_FIRST, None, (int,)), } def __init__(self, active: int = 0xFF0000, previous: int = 0xFF0000) -> None: super().__init__(orientation=Gtk.Orientation.HORIZONTAL, spacing=8) # _color/_last_color are always real RGB values; the unset toggle is # a separate channel so the gradient swatch (which mirrors these) is # unaffected by switching to "no change" paint mode. self._color: int = int(active) self._last_color: int = int(previous) self._unset_mode: bool = False self._color_btn = Gtk.ColorButton() self._color_btn.set_use_alpha(False) self._color_btn.set_rgba(_int_to_rgba(self._color)) self._color_btn.set_tooltip_text(_("Active color")) self._color_btn.connect(GtkSignal.COLOR_SET.value, self._on_color_set) self.pack_start(self._color_btn, False, False, 0) self._unset_btn = Gtk.ToggleButton() self._unset_btn.set_tooltip_text(_("Paint as 'no change' — clears the cell to the zone base color")) unset_label = _("Unset") if attach_themed_icon(self._unset_btn, _UNSET_ICON_NAME) is not None: self._unset_btn.get_accessible().set_name(unset_label) else: self._unset_btn.set_label(unset_label) self._unset_btn.connect(GtkSignal.TOGGLED.value, self._on_unset_toggled) self.pack_start(self._unset_btn, False, False, 0) def shutdown(self) -> None: # attach_themed_icon connects to the button's own style-updated # signal; GTK disconnects it automatically when the button is # destroyed, so there is nothing to clean up here. pass def _on_color_set(self, btn: Gtk.ColorButton) -> None: c = _rgb_to_int(btn.get_rgba()) unset_was_on = self._unset_mode if c == self._color and not unset_was_on: return if c != self._color: self._last_color = self._color self._color = c if unset_was_on: self._unset_mode = False self._unset_btn.set_active(False) self.emit("color-changed", self.get_color()) def _on_unset_toggled(self, btn: Gtk.ToggleButton) -> None: new_state = bool(btn.get_active()) if new_state == self._unset_mode: return self._unset_mode = new_state self.emit("color-changed", self.get_color()) def get_color(self) -> int: return UNSET_COLOR if self._unset_mode else self._color def get_picker_color(self) -> int: """The most recent real RGB pick — independent of the unset toggle. Use this for visuals that should always reflect actual colors (e.g. the gradient swatch). """ return self._color def get_last_color(self) -> int: return self._last_color def is_unset(self) -> bool: return self._unset_mode class GradientSwatch(Gtk.DrawingArea): """Small icon: diagonal gradient from `previous` (bottom-left) to `active` (top-right). Used as the visual on the gradient tool button so the user can see at a glance which two colors the next gradient stroke will fade between. """ SIZE = 22 def __init__(self) -> None: super().__init__() self.set_size_request(self.SIZE, self.SIZE) self._active: int = 0xFF0000 self._previous: int = 0xFF0000 self.connect(GtkSignal.DRAW.value, self._on_draw) # Re-render when the GTK theme changes, so the rounded-square # outline (drawn in the theme foreground color) stays in sync # with the tool icons next to it. self.connect("style-updated", lambda w: w.queue_draw()) def update(self, active: int, previous: int) -> None: self._active = int(active) self._previous = int(previous) self.queue_draw() def get_active(self) -> int: return self._active def get_previous(self) -> int: return self._previous def get_colors(self) -> tuple[int, int]: """Return (active, previous) — the colors the gradient tool will paint with.""" return (self._active, self._previous) @staticmethod def _rounded_rect_path(cr, x: float, y: float, w: float, h: float, r: float) -> None: cr.new_sub_path() cr.arc(x + w - r, y + r, r, -1.5708, 0) cr.arc(x + w - r, y + h - r, r, 0, 1.5708) cr.arc(x + r, y + h - r, r, 1.5708, 3.1416) cr.arc(x + r, y + r, r, 3.1416, 4.7124) cr.close_path() def _on_draw(self, _w, cr) -> None: import cairo # local: keeps the module light when GradientSwatch isn't built def rgb(c: int) -> tuple[float, float, float]: if c is None or c < 0: return (0.5, 0.5, 0.5) return (((c >> 16) & 0xFF) / 255.0, ((c >> 8) & 0xFF) / 255.0, (c & 0xFF) / 255.0) # Render in Tabler "square" coordinates (24x24 viewBox, rounded # rect from (3,3) to (21,21), corner radius 2, stroke 2) and let # cairo scale to the swatch's pixel size. Matches the outline # style of the tool icons exactly. cr.save() cr.scale(self.SIZE / 24.0, self.SIZE / 24.0) # Build the rounded-square path once, clip+fill the gradient # inside it, then re-build and stroke the outline in the theme # foreground color. self._rounded_rect_path(cr, 3, 3, 18, 18, 2) cr.save() cr.clip() # Top-left (previous, gradient start) → bottom-right (active, end). # Matches the directional behavior of dragging the line tool TL → BR. # Endpoints are shifted inward by the arc inset (corner radius * (1 # - 1/sqrt(2)), ~0.586 for r=2) so t=0 lands on the actual visible # TL corner pixel of the rounded rect — without this, the rendered # corners sample at t≈0.033/0.967 and the displayed colors are # ~8 RGB units short of the true endpoint colors. inset = 2 * (1 - 1 / (2**0.5)) pat = cairo.LinearGradient(3 + inset, 3 + inset, 21 - inset, 21 - inset) pat.add_color_stop_rgb(0.0, *rgb(self._previous)) pat.add_color_stop_rgb(1.0, *rgb(self._active)) cr.set_source(pat) cr.rectangle(3, 3, 18, 18) cr.fill() cr.restore() # drop clip self._rounded_rect_path(cr, 3, 3, 18, 18, 2) fg = self.get_style_context().get_color(Gtk.StateFlags.NORMAL) cr.set_source_rgba(fg.red, fg.green, fg.blue, fg.alpha) cr.set_line_width(2) cr.set_line_join(cairo.LINE_JOIN_ROUND) cr.set_line_cap(cairo.LINE_CAP_ROUND) cr.stroke() cr.restore() Solaar-1.1.20/lib/solaar/ui/perkey/protocol.py000066400000000000000000000047261522022367600212100ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Narrow contract between the per-key editor and any color-map setting. The editor consumes only this protocol, never `lib.logitech_receiver` directly. This is the seam where a future frontend/backend split would cut cleanly. """ from __future__ import annotations from typing import Callable from typing import Protocol class PerKeyColorSink(Protocol): """A device's per-key color buffer, exposed without device internals. Colors are 24-bit packed RGB ints (0xRRGGBB). The sentinel value -1 means "no change" / "unset" (matches `special_keys.COLORSPLUS["No change"]`). """ @property def title(self) -> str: ... @property def zones(self) -> list[int]: ... @property def current(self) -> dict[int, int]: ... def label(self, zone: int) -> str: ... def write_one(self, zone: int, color: int) -> None: ... def write_bulk(self, deltas: dict[int, int]) -> None: ... def subscribe(self, listener: Callable[[dict[int, int]], None]) -> Callable[[], None]: """Register a callback for current-value changes; return an unsubscribe handle.""" ... def palette_state(self) -> tuple[int, int] | None: """Return the persisted (active_color, previous_color) for this device's palette, or None.""" ... def set_palette_state(self, active: int, previous: int) -> None: """Persist the palette's active and previous colors for this device.""" ... def zone_base_color(self) -> int | None: """Return the zone base color (what 'no change' cells actually display on the keyboard), or None if the device has no zone effect. """ ... Solaar-1.1.20/lib/solaar/ui/perkey/tools.py000066400000000000000000000170141522022367600205010ustar00rootroot00000000000000## Copyright (C) 2026 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """Paint tools for the per-key editor. Each tool is a stateless policy object. The Canvas owns per-stroke state (press cell, motion cell, brush path) and asks the active tool for the final delta on release. """ from __future__ import annotations from dataclasses import dataclass from typing import Iterable from typing import Protocol from .layout import BoundCell from .layout import Cell @dataclass class ToolContext: active_color: int last_color: int cells_by_zone: dict[int, BoundCell] # zone ids that live in the bottom strip (e.g. logo, G-keys); kept separate # because their on-screen position is decoupled from the matrix grid. strip_zones: frozenset = frozenset() # zone_id -> current packed RGB (or -1 sentinel for unset). Used by tools # that need to compare colors, like the flood-fill bucket. current_colors: dict = None # type: ignore[assignment] def __post_init__(self) -> None: if self.current_colors is None: self.current_colors = {} def bound_cells(self) -> list[BoundCell]: return list(self.cells_by_zone.values()) def matrix_cells(self) -> list[BoundCell]: cells = [bc for bc in self.cells_by_zone.values() if bc.bound and bc.cell.zone_id not in self.strip_zones] if cells: return cells # No matrix region (e.g. a mouse, where every zone lives in the # strip). Fall back to all bound cells so directional tools still # have something to project across. return [bc for bc in self.cells_by_zone.values() if bc.bound] def cells_in_bbox(self, a: BoundCell, b: BoundCell) -> list[BoundCell]: cx_a, cy_a = _cell_center(a.cell) cx_b, cy_b = _cell_center(b.cell) x0, x1 = (cx_a, cx_b) if cx_a <= cx_b else (cx_b, cx_a) y0, y1 = (cy_a, cy_b) if cy_a <= cy_b else (cy_b, cy_a) result = [] for bc in self.cells_by_zone.values(): if not bc.bound: continue cx, cy = _cell_center(bc.cell) if x0 <= cx <= x1 and y0 <= cy <= y1: result.append(bc) return result def cells_in_bbox_ordered(self, a: BoundCell, b: BoundCell) -> list[BoundCell]: cells = self.cells_in_bbox(a, b) return sorted(cells, key=lambda c: (c.cell.row, c.cell.col)) def cells_in_group(self, group: str) -> list[BoundCell]: return [bc for bc in self.cells_by_zone.values() if bc.bound and bc.cell.group == group] def _cell_center(cell: Cell) -> tuple[float, float]: return (cell.col + cell.width / 2.0, cell.row + cell.height / 2.0) def _cells_touch(a: Cell, b: Cell) -> bool: """Bounding-box edge adjacency in grid units. Handles variable widths (Space spans multiple cols, Numpad+ spans multiple rows). """ a_c1, a_r1 = a.col + a.width, a.row + a.height b_c1, b_r1 = b.col + b.width, b.row + b.height rows_overlap = a.row < b_r1 and b.row < a_r1 cols_overlap = a.col < b_c1 and b.col < a_c1 if (a_c1 == b.col or b_c1 == a.col) and rows_overlap: return True if (a_r1 == b.row or b_r1 == a.row) and cols_overlap: return True return False class Tool(Protocol): name: str is_brush: bool overlay_shape: str # "" | "rect" def compute( self, start: BoundCell | None, end: BoundCell | None, path: Iterable[int], ctx: ToolContext, ) -> dict[int, int]: ... class SingleTool: name = "single" is_brush = True overlay_shape = "" def compute(self, start, end, path, ctx): return {z: ctx.active_color for z in path} class RectTool: name = "rect" is_brush = False overlay_shape = "rect" def compute(self, start, end, path, ctx): if start is None or end is None: return {} return {bc.cell.zone_id: ctx.active_color for bc in ctx.cells_in_bbox(start, end)} class BucketTool: """Flood-fill: replace the clicked cell's color in every connected cell of the same color (4-adjacent on the matrix grid). Strip cells aren't on the matrix grid, so clicking one paints just that cell. """ name = "bucket" is_brush = False overlay_shape = "" def compute(self, start, end, path, ctx): if start is None: return {} new_color = ctx.active_color target = ctx.current_colors.get(start.cell.zone_id, -1) if target == new_color: return {} if start.cell.zone_id in ctx.strip_zones: return {start.cell.zone_id: new_color} # BFS over matrix cells cells_by_id = {z: bc for z, bc in ctx.cells_by_zone.items() if bc.bound and z not in ctx.strip_zones} visited = {start.cell.zone_id} stack = [start] result: dict[int, int] = {} while stack: bc = stack.pop() result[bc.cell.zone_id] = new_color for other in cells_by_id.values(): if other.cell.zone_id in visited: continue if ctx.current_colors.get(other.cell.zone_id, -1) != target: continue if not _cells_touch(bc.cell, other.cell): continue visited.add(other.cell.zone_id) stack.append(other) return result class GradientTool: """Directional gradient: drag a line from A to B, the whole matrix gets a gradient at that angle. Cells projecting before A clamp to the previous color; cells past B clamp to the active color. """ name = "gradient" is_brush = False overlay_shape = "line" def compute(self, start, end, path, ctx): if start is None or end is None: return {} ax, ay = _cell_center(start.cell) bx, by = _cell_center(end.cell) vx, vy = bx - ax, by - ay length_sq = vx * vx + vy * vy if length_sq == 0: return {start.cell.zone_id: ctx.active_color} result: dict[int, int] = {} for bc in ctx.matrix_cells(): cx, cy = _cell_center(bc.cell) t = ((cx - ax) * vx + (cy - ay) * vy) / length_sq t = 0.0 if t < 0.0 else 1.0 if t > 1.0 else t result[bc.cell.zone_id] = _lerp_rgb(ctx.last_color, ctx.active_color, t) return result def _lerp_rgb(c0: int, c1: int, t: float) -> int: if c0 < 0: c0 = c1 if c1 < 0: c1 = c0 r0, g0, b0 = (c0 >> 16) & 0xFF, (c0 >> 8) & 0xFF, c0 & 0xFF r1, g1, b1 = (c1 >> 16) & 0xFF, (c1 >> 8) & 0xFF, c1 & 0xFF r = int(round(r0 + (r1 - r0) * t)) g = int(round(g0 + (g1 - g0) * t)) b = int(round(b0 + (b1 - b0) * t)) return (r << 16) | (g << 8) | b TOOLS: dict[str, Tool] = { "single": SingleTool(), "rect": RectTool(), "bucket": BucketTool(), "gradient": GradientTool(), } Solaar-1.1.20/lib/solaar/ui/rule_actions.py000066400000000000000000000324501522022367600205320ustar00rootroot00000000000000## Copyright (C) Solaar Contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from enum import Enum from shlex import quote as shlex_quote from gi.repository import Gtk from logitech_receiver import diversion from logitech_receiver.diversion import CLICK from logitech_receiver.diversion import DEPRESS from logitech_receiver.diversion import RELEASE from logitech_receiver.diversion import XK_KEYS from logitech_receiver.diversion import buttons from solaar.i18n import _ from solaar.ui.rule_base import CompletionEntry from solaar.ui.rule_base import RuleComponentUI class GtkSignal(Enum): CHANGED = "changed" CLICKED = "clicked" TOGGLED = "toggled" class ActionUI(RuleComponentUI): CLASS = diversion.Action @classmethod def icon_name(cls): return "go-next" class KeyPressUI(ActionUI): CLASS = diversion.KeyPress KEY_NAMES = [k[3:] if k.startswith("XK_") else k for k, v in XK_KEYS.items() if isinstance(v, int)] def create_widgets(self): self.widgets = {} self.fields = [] self.label = Gtk.Label( label=_("Simulate a chorded key click or depress or release.\nOn Wayland requires write access to /dev/uinput."), halign=Gtk.Align.CENTER, justify=Gtk.Justification.CENTER, ) self.widgets[self.label] = (0, 0, 5, 1) self.del_btns = [] self.add_btn = Gtk.Button(label=_("Add key"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True) self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add) self.widgets[self.add_btn] = (1, 1, 1, 1) self.action_clicked_radio = Gtk.RadioButton.new_with_label_from_widget(None, _("Click")) self.action_clicked_radio.connect(GtkSignal.TOGGLED.value, self._on_update, CLICK) self.widgets[self.action_clicked_radio] = (0, 3, 1, 1) self.action_pressed_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_clicked_radio, _("Depress")) self.action_pressed_radio.connect(GtkSignal.TOGGLED.value, self._on_update, DEPRESS) self.widgets[self.action_pressed_radio] = (1, 3, 1, 1) self.action_released_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_pressed_radio, _("Release")) self.action_released_radio.connect(GtkSignal.TOGGLED.value, self._on_update, RELEASE) self.widgets[self.action_released_radio] = (2, 3, 1, 1) def _create_field(self): field_entry = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True) field_entry.connect(GtkSignal.CHANGED.value, self._on_update) field_entry.set_size_request(250, -1) self.fields.append(field_entry) self.widgets[field_entry] = (len(self.fields) - 1, 1, 1, 1) return field_entry def _create_del_btn(self): btn = Gtk.Button(label=_("Delete"), halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True) self.del_btns.append(btn) self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1) btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1) return btn def _clicked_add(self, _btn): keys, action = self.component.regularize_args(self.collect_value()) self.component.__init__([keys + [""], action], warn=False) self.show(self.component, editable=True) self.fields[len(self.component.key_names) - 1].grab_focus() def _clicked_del(self, _btn, pos): keys, action = self.component.regularize_args(self.collect_value()) keys.pop(pos) self.component.__init__([keys, action], warn=False) self.show(self.component, editable=True) self._on_update_callback() def _on_update(self, *args): super()._on_update(*args) for i, f in enumerate(self.fields): if f.get_visible(): icon = ( "dialog-warning" if i < len(self.component.key_names) and self.component.key_names[i] not in self.KEY_NAMES else "" ) f.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) def show(self, component, editable=True): n = len(component.key_names) while len(self.fields) < n: self._create_field() self._create_del_btn() self.widgets[self.add_btn] = (n, 1, 1, 1) super().show(component, editable) for i in range(n): field_entry = self.fields[i] with self.ignore_changes(): field_entry.set_text(component.key_names[i]) field_entry.show_all() self.del_btns[i].show() for i in range(n, len(self.fields)): self.fields[i].hide() self.del_btns[i].hide() def collect_value(self): action = ( CLICK if self.action_clicked_radio.get_active() else DEPRESS if self.action_pressed_radio.get_active() else RELEASE ) return [[f.get_text().strip() for f in self.fields if f.get_visible()], action] @classmethod def left_label(cls, component): return _("Key press") @classmethod def right_label(cls, component): return " + ".join(component.key_names) + (f" ({component.action})" if component.action != CLICK else "") class MouseScrollUI(ActionUI): CLASS = diversion.MouseScroll MIN_VALUE = -2000 MAX_VALUE = 2000 def create_widgets(self): self.widgets = {} self.label = Gtk.Label( label=_("Simulate a mouse scroll.\nOn Wayland requires write access to /dev/uinput."), halign=Gtk.Align.CENTER, justify=Gtk.Justification.CENTER, ) self.widgets[self.label] = (0, 0, 4, 1) self.label_x = Gtk.Label(label="x", halign=Gtk.Align.END, valign=Gtk.Align.END, hexpand=True) self.label_y = Gtk.Label(label="y", halign=Gtk.Align.END, valign=Gtk.Align.END, hexpand=True) self.field_x = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1) self.field_y = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1) for f in [self.field_x, self.field_y]: f.set_halign(Gtk.Align.CENTER) f.set_valign(Gtk.Align.START) self.field_x.connect(GtkSignal.CHANGED.value, self._on_update) self.field_y.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.label_x] = (0, 1, 1, 1) self.widgets[self.field_x] = (1, 1, 1, 1) self.widgets[self.label_y] = (2, 1, 1, 1) self.widgets[self.field_y] = (3, 1, 1, 1) @classmethod def __parse(cls, v): try: # allow floats, but round them down return int(float(v)) except (TypeError, ValueError): return 0 def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): self.field_x.set_value(self.__parse(component.amounts[0] if len(component.amounts) >= 1 else 0)) self.field_y.set_value(self.__parse(component.amounts[1] if len(component.amounts) >= 2 else 0)) def collect_value(self): return [int(self.field_x.get_value()), int(self.field_y.get_value())] @classmethod def left_label(cls, component): return _("Mouse scroll") @classmethod def right_label(cls, component): x = y = 0 x = cls.__parse(component.amounts[0] if len(component.amounts) >= 1 else 0) y = cls.__parse(component.amounts[1] if len(component.amounts) >= 2 else 0) return f"{x}, {y}" class MouseClickUI(ActionUI): CLASS = diversion.MouseClick MIN_VALUE = 1 MAX_VALUE = 9 BUTTONS = list(buttons.keys()) ACTIONS = [CLICK, DEPRESS, RELEASE] def create_widgets(self): self.widgets = {} self.label = Gtk.Label( label=_("Simulate a mouse click.\nOn Wayland requires write access to /dev/uinput."), halign=Gtk.Align.CENTER, justify=Gtk.Justification.CENTER, ) self.widgets[self.label] = (0, 0, 4, 1) self.label_b = Gtk.Label(label=_("Button"), halign=Gtk.Align.END, valign=Gtk.Align.CENTER, hexpand=True) self.label_c = Gtk.Label( label=_("Action (and Count, if click)"), halign=Gtk.Align.END, valign=Gtk.Align.CENTER, hexpand=True ) self.field_b = CompletionEntry(self.BUTTONS) self.field_c = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1) self.field_d = CompletionEntry(self.ACTIONS) for f in [self.field_b, self.field_c]: f.set_halign(Gtk.Align.CENTER) f.set_valign(Gtk.Align.START) self.field_b.connect(GtkSignal.CHANGED.value, self._on_update) self.field_c.connect(GtkSignal.CHANGED.value, self._on_update) self.field_d.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.label_b] = (0, 1, 1, 1) self.widgets[self.field_b] = (1, 1, 1, 1) self.widgets[self.label_c] = (2, 1, 1, 1) self.widgets[self.field_c] = (4, 1, 1, 1) self.widgets[self.field_d] = (3, 1, 1, 1) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): self.field_b.set_text(component.button) if isinstance(component.count, int): self.field_c.set_value(component.count) self.field_d.set_text(CLICK) else: self.field_c.set_value(1) self.field_d.set_text(component.count) def collect_value(self): b, c, d = self.field_b.get_text(), int(self.field_c.get_value()), self.field_d.get_text() if b not in self.BUTTONS: b = "unknown" if d != CLICK: c = d return [b, c] @classmethod def left_label(cls, component): return _("Mouse click") @classmethod def right_label(cls, component): return f'{component.button} ({"x" if isinstance(component.count, int) else ""}{component.count})' class ExecuteUI(ActionUI): CLASS = diversion.Execute def create_widgets(self): self.widgets = {} self.label = Gtk.Label( label=_("Execute a command with arguments."), halign=Gtk.Align.CENTER, justify=Gtk.Justification.CENTER ) self.widgets[self.label] = (0, 0, 5, 1) self.fields = [] self.add_btn = Gtk.Button(label=_("Add argument"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True) self.del_btns = [] self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add) self.widgets[self.add_btn] = (1, 1, 1, 1) def _create_field(self): field_entry = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True) field_entry.set_size_request(150, 0) field_entry.connect(GtkSignal.CHANGED.value, self._on_update) self.fields.append(field_entry) self.widgets[field_entry] = (len(self.fields) - 1, 1, 1, 1) return field_entry def _create_del_btn(self): btn = Gtk.Button(label=_("Delete"), halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True) btn.set_size_request(150, 0) self.del_btns.append(btn) self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1) btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1) return btn def _clicked_add(self, *_args): self.component.__init__(self.collect_value() + [""], warn=False) self.show(self.component, editable=True) self.fields[len(self.component.args) - 1].grab_focus() def _clicked_del(self, _btn, pos): v = self.collect_value() v.pop(pos) self.component.__init__(v, warn=False) self.show(self.component, editable=True) self._on_update_callback() def show(self, component, editable=True): n = len(component.args) while len(self.fields) < n: self._create_field() self._create_del_btn() for i in range(n): field_entry = self.fields[i] with self.ignore_changes(): field_entry.set_text(component.args[i]) self.del_btns[i].show() self.widgets[self.add_btn] = (n + 1, 1, 1, 1) super().show(component, editable) for i in range(n, len(self.fields)): self.fields[i].hide() self.del_btns[i].hide() self.add_btn.set_valign(Gtk.Align.END if n >= 1 else Gtk.Align.CENTER) def collect_value(self): return [f.get_text() for f in self.fields if f.get_visible()] @classmethod def left_label(cls, component): return _("Execute") @classmethod def right_label(cls, component): return " ".join([shlex_quote(a) for a in component.args]) Solaar-1.1.20/lib/solaar/ui/rule_base.py000066400000000000000000000070561522022367600200100ustar00rootroot00000000000000## Copyright (C) Solaar Contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import abc from contextlib import contextmanager as contextlib_contextmanager from typing import Any from typing import Callable from gi.repository import Gtk from logitech_receiver import diversion def norm(s): return s.replace("_", "").replace(" ", "").lower() class CompletionEntry(Gtk.Entry): def __init__(self, values, *args, **kwargs): super().__init__(*args, **kwargs) CompletionEntry.add_completion_to_entry(self, values) @classmethod def add_completion_to_entry(cls, entry, values): completion = entry.get_completion() if not completion: liststore = Gtk.ListStore(str) completion = Gtk.EntryCompletion() completion.set_model(liststore) completion.set_match_func(lambda completion, key, it: norm(key) in norm(completion.get_model()[it][0])) completion.set_text_column(0) entry.set_completion(completion) else: liststore = completion.get_model() liststore.clear() for v in sorted(set(values), key=str.casefold): liststore.append((v,)) class RuleComponentUI(abc.ABC): CLASS = diversion.RuleComponent def __init__(self, panel, on_update: Callable = None): self.panel = panel self.widgets = {} # widget -> coord. in grid self.component = None self._ignore_changes = 0 self._on_update_callback = (lambda: None) if on_update is None else on_update self.create_widgets() @abc.abstractmethod def create_widgets(self) -> dict: pass def show(self, component, editable=True): self._show_widgets(editable) self.component = component @abc.abstractmethod def collect_value(self) -> Any: pass @contextlib_contextmanager def ignore_changes(self): self._ignore_changes += 1 yield None self._ignore_changes -= 1 def _on_update(self, *_args): if not self._ignore_changes and self.component is not None: value = self.collect_value() self.component.__init__(value, warn=False) self._on_update_callback() return value return None def _show_widgets(self, editable): self._remove_panel_items() for widget, coord in self.widgets.items(): self.panel.attach(widget, *coord) widget.set_sensitive(editable) widget.show() @classmethod def left_label(cls, component) -> str: return type(component).__name__ @classmethod def right_label(cls, _component) -> str: return "" @classmethod def icon_name(cls) -> str: return "" def _remove_panel_items(self): for c in self.panel.get_children(): self.panel.remove(c) def update_devices(self): # noqa: B027 pass Solaar-1.1.20/lib/solaar/ui/rule_conditions.py000066400000000000000000000567161522022367600212560ustar00rootroot00000000000000## Copyright (C) Solaar Contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from dataclasses import dataclass from enum import Enum from gi.repository import Gtk from logitech_receiver import diversion from logitech_receiver.diversion import Key from logitech_receiver.hidpp20 import SupportedFeature from logitech_receiver.special_keys import CONTROL from solaar.i18n import _ from solaar.ui.rule_base import CompletionEntry from solaar.ui.rule_base import RuleComponentUI class GtkSignal(Enum): CHANGED = "changed" CLICKED = "clicked" NOTIFY_ACTIVE = "notify::active" TOGGLED = "toggled" VALUE_CHANGED = "value-changed" class ConditionUI(RuleComponentUI): CLASS = diversion.Condition @classmethod def icon_name(cls): return "dialog-question" class ProcessUI(ConditionUI): CLASS = diversion.Process def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text(_("X11 active process. For use in X11 only.")) self.widgets[self.label] = (0, 0, 1, 1) self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True) self.field.set_size_request(600, 0) self.field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.field] = (0, 1, 1, 1) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): self.field.set_text(component.process) def collect_value(self): return self.field.get_text() @classmethod def left_label(cls, component): return _("Process") @classmethod def right_label(cls, component): return str(component.process) class MouseProcessUI(ConditionUI): CLASS = diversion.MouseProcess def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text(_("X11 mouse process. For use in X11 only.")) self.widgets[self.label] = (0, 0, 1, 1) self.field = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True) self.field.set_size_request(600, 0) self.field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.field] = (0, 1, 1, 1) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): self.field.set_text(component.process) def collect_value(self): return self.field.get_text() @classmethod def left_label(cls, component): return _("MouseProcess") @classmethod def right_label(cls, component): return str(component.process) class FeatureUI(ConditionUI): CLASS = diversion.Feature FEATURES_WITH_DIVERSION = [ str(SupportedFeature.CROWN), str(SupportedFeature.THUMB_WHEEL), str(SupportedFeature.LOWRES_WHEEL), str(SupportedFeature.HIRES_WHEEL), str(SupportedFeature.GESTURE_2), str(SupportedFeature.REPROG_CONTROLS_V4), str(SupportedFeature.GKEY), str(SupportedFeature.MKEYS), str(SupportedFeature.MR), ] def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text(_("Feature name of notification triggering rule processing.")) self.widgets[self.label] = (0, 0, 1, 1) self.field = Gtk.ComboBoxText.new_with_entry() self.field.append("", "") for feature in self.FEATURES_WITH_DIVERSION: self.field.append(feature, feature) self.field.set_valign(Gtk.Align.CENTER) self.field.set_size_request(600, 0) self.field.connect(GtkSignal.CHANGED.value, self._on_update) all_features = [str(f) for f in SupportedFeature] CompletionEntry.add_completion_to_entry(self.field.get_child(), all_features) self.widgets[self.field] = (0, 1, 1, 1) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): f = str(component.feature) if component.feature else "" self.field.set_active_id(f) if f not in self.FEATURES_WITH_DIVERSION: self.field.get_child().set_text(f) def collect_value(self): return (self.field.get_active_text() or "").strip() def _on_update(self, *args): super()._on_update(*args) icon = "dialog-warning" if not self.component.feature else "" self.field.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) @classmethod def left_label(cls, component): return _("Feature") @classmethod def right_label(cls, component): return f"{str(component.feature)} ({int(component.feature or 0):04X})" class ReportUI(ConditionUI): CLASS = diversion.Report MIN_VALUE = -1 # for invalid values MAX_VALUE = 15 def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text(_("Report number of notification triggering rule processing.")) self.widgets[self.label] = (0, 0, 1, 1) self.field = Gtk.SpinButton.new_with_range(self.MIN_VALUE, self.MAX_VALUE, 1) self.field.set_halign(Gtk.Align.CENTER) self.field.set_valign(Gtk.Align.CENTER) self.field.set_hexpand(True) self.field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.field] = (0, 1, 1, 1) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): self.field.set_value(component.report) def collect_value(self): return int(self.field.get_value()) @classmethod def left_label(cls, component): return _("Report") @classmethod def right_label(cls, component): return str(component.report) class ModifiersUI(ConditionUI): CLASS = diversion.Modifiers def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text(_("Active keyboard modifiers. Not always available in Wayland.")) self.widgets[self.label] = (0, 0, 5, 1) self.labels = {} self.switches = {} for i, m in enumerate(diversion.MODIFIERS): switch = Gtk.Switch(halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True) label = Gtk.Label(label=m, halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True) self.widgets[label] = (i, 1, 1, 1) self.widgets[switch] = (i, 2, 1, 1) self.labels[m] = label self.switches[m] = switch switch.connect(GtkSignal.NOTIFY_ACTIVE.value, self._on_update) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): for m in diversion.MODIFIERS: self.switches[m].set_active(m in component.modifiers) def collect_value(self): return [m for m, s in self.switches.items() if s.get_active()] @classmethod def left_label(cls, component): return _("Modifiers") @classmethod def right_label(cls, component): return "+".join(component.modifiers) or "None" class KeyUI(ConditionUI): CLASS = diversion.Key KEY_NAMES = map(str, CONTROL) def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text( _( "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons." ) ) self.widgets[self.label] = (0, 0, 5, 1) self.key_field = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True) self.key_field.set_size_request(600, 0) self.key_field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.key_field] = (0, 1, 2, 1) self.action_pressed_radio = Gtk.RadioButton.new_with_label_from_widget(None, _("Key down")) self.action_pressed_radio.connect(GtkSignal.TOGGLED.value, self._on_update, Key.DOWN) self.widgets[self.action_pressed_radio] = (2, 1, 1, 1) self.action_released_radio = Gtk.RadioButton.new_with_label_from_widget(self.action_pressed_radio, _("Key up")) self.action_released_radio.connect(GtkSignal.TOGGLED.value, self._on_update, Key.UP) self.widgets[self.action_released_radio] = (3, 1, 1, 1) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): self.key_field.set_text(str(component.key) if self.component.key else "") if not component.action or component.action == Key.DOWN: self.action_pressed_radio.set_active(True) else: self.action_released_radio.set_active(True) def collect_value(self): action = Key.UP if self.action_released_radio.get_active() else Key.DOWN return [self.key_field.get_text(), action] def _on_update(self, *args): super()._on_update(*args) icon = "dialog-warning" if not self.component.key or not self.component.action else "" self.key_field.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) @classmethod def left_label(cls, component): return _("Key") @classmethod def right_label(cls, component): return f"{str(component.key)} ({int(component.key):04X}) ({_(component.action)})" if component.key else "None" class KeyIsDownUI(ConditionUI): CLASS = diversion.KeyIsDown KEY_NAMES = map(str, CONTROL) def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text( _( "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons." ) ) self.widgets[self.label] = (0, 0, 5, 1) self.key_field = CompletionEntry(self.KEY_NAMES, halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, hexpand=True) self.key_field.set_size_request(600, 0) self.key_field.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.key_field] = (0, 1, 1, 1) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): self.key_field.set_text(str(component.key) if self.component.key else "") def collect_value(self): return self.key_field.get_text() def _on_update(self, *args): super()._on_update(*args) icon = "dialog-warning" if not self.component.key else "" self.key_field.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) @classmethod def left_label(cls, component): return _("KeyIsDown") @classmethod def right_label(cls, component): return f"{str(component.key)} ({int(component.key):04X})" if component.key else "None" class TestUI(ConditionUI): CLASS = diversion.Test def create_widgets(self): self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text(_("Test condition on notification triggering rule processing.")) self.widgets[self.label] = (0, 0, 4, 1) lbl = Gtk.Label(label=_("Test"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=False, vexpand=False) self.widgets[lbl] = (0, 1, 1, 1) lbl = Gtk.Label(label=_("Parameter"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=False, vexpand=False) self.widgets[lbl] = (2, 1, 1, 1) self.test = Gtk.ComboBoxText.new_with_entry() self.test.append("", "") for t in diversion.TESTS: self.test.append(t, t) self.test.set_halign(Gtk.Align.END) self.test.set_valign(Gtk.Align.CENTER) self.test.set_hexpand(False) self.test.set_size_request(300, 0) CompletionEntry.add_completion_to_entry(self.test.get_child(), diversion.TESTS) self.test.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.test] = (1, 1, 1, 1) self.parameter = Gtk.Entry(halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True) self.parameter.set_size_request(150, 0) self.parameter.connect(GtkSignal.CHANGED.value, self._on_update) self.widgets[self.parameter] = (3, 1, 1, 1) def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): self.test.set_active_id(component.test) self.parameter.set_text(str(component.parameter) if component.parameter is not None else "") if component.test not in diversion.TESTS: self.test.get_child().set_text(component.test) self._change_status_icon() def collect_value(self): try: param = int(self.parameter.get_text()) if self.parameter.get_text() else None except Exception: param = self.parameter.get_text() test = (self.test.get_active_text() or "").strip() return [test, param] if param is not None else [test] def _on_update(self, *args): super()._on_update(*args) self._change_status_icon() def _change_status_icon(self): icon = "dialog-warning" if (self.test.get_active_text() or "").strip() not in diversion.TESTS else "" self.test.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) @classmethod def left_label(cls, component): return _("Test") @classmethod def right_label(cls, component): return component.test + (f" {repr(component.parameter)}" if component.parameter is not None else "") @dataclass class TestBytesElement: id: str label: str min: int max: int @dataclass class TestBytesMode: label: str elements: list label_fn: callable class TestBytesUI(ConditionUI): CLASS = diversion.TestBytes _common_elements = [ TestBytesElement("begin", _("begin (inclusive)"), 0, 16), TestBytesElement("end", _("end (exclusive)"), 0, 16), ] _global_min = -(2**31) _global_max = 2**31 - 1 _modes = { "range": TestBytesMode( _("range"), _common_elements + [ TestBytesElement("minimum", _("minimum"), _global_min, _global_max), # uint32 TestBytesElement("maximum", _("maximum"), _global_min, _global_max), ], lambda e: _("bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" % {str(i): v for i, v in enumerate(e)}), ), "mask": TestBytesMode( _("mask"), _common_elements + [TestBytesElement("mask", _("mask"), _global_min, _global_max)], lambda e: _("bytes %(0)d to %(1)d, mask %(2)d" % {str(i): v for i, v in enumerate(e)}), ), } def create_widgets(self): self.fields = {} self.field_labels = {} self.widgets = {} self.label = Gtk.Label(valign=Gtk.Align.CENTER, hexpand=True, justify=Gtk.Justification.CENTER) self.label.set_text(_("Bit or range test on bytes in notification message triggering rule processing.")) self.widgets[self.label] = (0, 0, 5, 1) col = 0 mode_col = 2 self.mode_field = Gtk.ComboBox.new_with_model(Gtk.ListStore(str, str)) mode_renderer = Gtk.CellRendererText() self.mode_field.set_id_column(0) self.mode_field.pack_start(mode_renderer, True) self.mode_field.add_attribute(mode_renderer, "text", 1) self.widgets[self.mode_field] = (mode_col, 2, 1, 1) mode_label = Gtk.Label(label=_("type"), margin_top=20) self.widgets[mode_label] = (mode_col, 1, 1, 1) for mode_id, mode in TestBytesUI._modes.items(): self.mode_field.get_model().append([mode_id, mode.label]) for element in mode.elements: if element.id not in self.fields: field = Gtk.SpinButton.new_with_range(element.min, element.max, 1) field.set_value(0) field.set_size_request(150, 0) field.connect(GtkSignal.VALUE_CHANGED.value, self._on_update) label = Gtk.Label(label=element.label, margin_top=20) self.fields[element.id] = field self.field_labels[element.id] = label self.widgets[label] = (col, 1, 1, 1) self.widgets[field] = (col, 2, 1, 1) col += 1 if col != mode_col - 1 else 2 self.mode_field.connect(GtkSignal.CHANGED.value, lambda cb: (self._on_update(), self._only_mode(cb.get_active_id()))) self.mode_field.set_active_id("range") def show(self, component, editable=True): super().show(component, editable) with self.ignore_changes(): mode_id = {3: "mask", 4: "range"}.get(len(component.test), None) self._only_mode(mode_id) if not mode_id: return self.mode_field.set_active_id(mode_id) if mode_id: mode = TestBytesUI._modes[mode_id] for i, element in enumerate(mode.elements): self.fields[element.id].set_value(component.test[i]) def collect_value(self): mode_id = self.mode_field.get_active_id() return [self.fields[element.id].get_value_as_int() for element in TestBytesUI._modes[mode_id].elements] def _only_mode(self, mode_id): if not mode_id: return keep = {element.id for element in TestBytesUI._modes[mode_id].elements} for element_id, f in self.fields.items(): visible = element_id in keep f.set_visible(visible) self.field_labels[element_id].set_visible(visible) def _on_update(self, *args): super()._on_update(*args) if not self.component: return begin, end, *etc = self.component.test icon = "dialog-warning" if end <= begin else "" self.fields["end"].set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) if len(self.component.test) == 4: *etc, minimum, maximum = self.component.test icon = "dialog-warning" if maximum < minimum else "" self.fields["maximum"].set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) @classmethod def left_label(cls, component): return _("Test bytes") @classmethod def right_label(cls, component): mode_id = {3: "mask", 4: "range"}.get(len(component.test), None) if not mode_id: return str(component.test) return TestBytesUI._modes[mode_id].label_fn(component.test) class MouseGestureUI(ConditionUI): CLASS = diversion.MouseGesture MOUSE_GESTURE_NAMES = [ "Mouse Up", "Mouse Down", "Mouse Left", "Mouse Right", "Mouse Up-left", "Mouse Up-right", "Mouse Down-left", "Mouse Down-right", ] MOVE_NAMES = list(map(str, CONTROL)) + MOUSE_GESTURE_NAMES def create_widgets(self): self.widgets = {} self.fields = [] self.label = Gtk.Label( label=_("Mouse gesture with optional initiating button followed by zero or more mouse movements."), halign=Gtk.Align.CENTER, justify=Gtk.Justification.CENTER, ) self.widgets[self.label] = (0, 0, 5, 1) self.del_btns = [] self.add_btn = Gtk.Button(label=_("Add movement"), halign=Gtk.Align.CENTER, valign=Gtk.Align.END, hexpand=True) self.add_btn.connect(GtkSignal.CLICKED.value, self._clicked_add) self.widgets[self.add_btn] = (1, 1, 1, 1) def _create_field(self): field = Gtk.ComboBoxText.new_with_entry() for g in self.MOUSE_GESTURE_NAMES: field.append(g, g) CompletionEntry.add_completion_to_entry(field.get_child(), self.MOVE_NAMES) field.connect(GtkSignal.CHANGED.value, self._on_update) self.fields.append(field) self.widgets[field] = (len(self.fields) - 1, 1, 1, 1) return field def _create_del_btn(self): btn = Gtk.Button(label=_("Delete"), halign=Gtk.Align.CENTER, valign=Gtk.Align.START, hexpand=True) self.del_btns.append(btn) self.widgets[btn] = (len(self.del_btns) - 1, 2, 1, 1) btn.connect(GtkSignal.CLICKED.value, self._clicked_del, len(self.del_btns) - 1) return btn def _clicked_add(self, _btn): self.component.__init__(self.collect_value() + [""], warn=False) self.show(self.component, editable=True) self.fields[len(self.component.movements) - 1].grab_focus() def _clicked_del(self, _btn, pos): v = self.collect_value() v.pop(pos) self.component.__init__(v, warn=False) self.show(self.component, editable=True) self._on_update_callback() def _on_update(self, *args): super()._on_update(*args) for i, f in enumerate(self.fields): if f.get_visible(): icon = ( "dialog-warning" if i < len(self.component.movements) and self.component.movements[i] not in self.MOVE_NAMES else "" ) f.get_child().set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, icon) def show(self, component, editable=True): n = len(component.movements) while len(self.fields) < n: self._create_field() self._create_del_btn() self.widgets[self.add_btn] = (n + 1, 1, 1, 1) super().show(component, editable) for i in range(n): field = self.fields[i] with self.ignore_changes(): field.get_child().set_text(component.movements[i]) field.show_all() self.del_btns[i].show() for i in range(n, len(self.fields)): self.fields[i].hide() self.del_btns[i].hide() self.add_btn.set_valign(Gtk.Align.END if n >= 1 else Gtk.Align.CENTER) def collect_value(self): return [f.get_active_text().strip() for f in self.fields if f.get_visible()] @classmethod def left_label(cls, component): return _("Mouse Gesture") @classmethod def right_label(cls, component): if len(component.movements) == 0: return "No-op" else: return " -> ".join(component.movements) Solaar-1.1.20/lib/solaar/ui/tray.py000066400000000000000000000403371522022367600170250ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import logging import os from enum import Enum from time import time import gi from gi.repository import GLib from gi.repository import Gtk from gi.repository.Gdk import ScrollDirection import solaar.gtk as gtk from solaar import NAME from solaar.i18n import _ from . import action from . import icons from . import window from .about import about logger = logging.getLogger(__name__) _TRAY_ICON_SIZE = 48 _MENU_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR class GtkSignal(Enum): ACTIVATE = "activate" SCROLL_EVENT = "scroll-event" def _create_menu(quit_handler): # per-device menu entries will be generated as-needed menu = Gtk.Menu() no_receiver = Gtk.MenuItem.new_with_label(_("No supported device found")) no_receiver.set_sensitive(False) menu.append(no_receiver) menu.append(Gtk.SeparatorMenuItem.new()) menu.append(action.make_image_menu_item(_("About %s") % NAME, "help-about", about.show)) menu.append(action.make_image_menu_item(_("Quit %s") % NAME, "application-exit", quit_handler)) menu.show_all() return menu _last_scroll = 0 def _scroll(tray_icon, event, direction=None): if direction is None: direction = event.direction now = event.time / 1000.0 else: now = None if direction != ScrollDirection.UP and direction != ScrollDirection.DOWN: # ignore all other directions return # don't bother even trying to scroll if less than two devices if sum(map(lambda i: i[1] is not None, _devices_info)) < 2: return # scroll events come way too fast (at least 5-6 at once) so take a little break between them global _last_scroll now = now or time() if now - _last_scroll < 0.33: # seconds return _last_scroll = now global _picked_device candidate = None if _picked_device is None: for info in _devices_info: # pick first peripheral found if info[1] is not None: candidate = info break else: found = False for info in _devices_info: if not info[1]: # only conside peripherals continue # compare peripherals if info[0:2] == _picked_device[0:2]: if direction == ScrollDirection.UP and candidate: # select previous device break found = True else: if found: candidate = info if direction == ScrollDirection.DOWN: break # if direction is up, but no candidate found before _picked, # let it run through all candidates, will get stuck with the last one else: if direction == ScrollDirection.DOWN: # only use the first one, in case no candidates are after _picked if candidate is None: candidate = info else: candidate = info # if the last _picked_device is gone, clear it # the candidate will be either the first or last one remaining, # depending on the scroll direction if not found: _picked_device = None _picked_device = candidate or _picked_device logger.debug("scroll: picked %s", _picked_device) _update_tray_icon() try: try: gi.require_version("AyatanaAppIndicator3", "0.1") from gi.repository import AyatanaAppIndicator3 as AppIndicator3 ayatana_appindicator_found = True except ValueError: try: gi.require_version("AppIndicator3", "0.1") from gi.repository import AppIndicator3 ayatana_appindicator_found = False except ValueError as exc: # treat unavailable versions the same as unavailable packages raise ImportError from exc logger.debug(f"using {'Ayatana ' if ayatana_appindicator_found else ''}AppIndicator3") # Defense against AppIndicator3 bug that treats files in current directory as icon files # https://bugs.launchpad.net/ubuntu/+source/libappindicator/+bug/1363277 # Defense against bug that shows up in XFCE 4.16 where icons are not upscaled def _icon_file(icon_name): if gtk.tray_icon_size is None and not os.path.isfile(icon_name): return icon_name icon_info = Gtk.IconTheme.get_default().lookup_icon( icon_name, gtk.tray_icon_size or _TRAY_ICON_SIZE, Gtk.IconLookupFlags.FORCE_SVG ) return icon_info.get_filename() if icon_info else icon_name def _create(menu): icons._init_icon_paths() ind = AppIndicator3.Indicator.new( "indicator-solaar", _icon_file(icons.TRAY_INIT), AppIndicator3.IndicatorCategory.HARDWARE ) ind.set_title(NAME) ind.set_status(AppIndicator3.IndicatorStatus.ACTIVE) # ind.set_attention_icon_full(_icon_file(icons.TRAY_ATTENTION), '') # works poorly for XFCE 16 # ind.set_label(NAME.lower(), NAME.lower()) ind.set_menu(menu) ind.connect(GtkSignal.SCROLL_EVENT.value, _scroll) return ind def _hide(indicator): indicator.set_status(AppIndicator3.IndicatorStatus.PASSIVE) def _show(indicator): indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE) def _update_tray_icon(): if _picked_device and gtk.battery_icons_style != "solaar": _ignore, _ignore, name, device = _picked_device battery_level = device.battery_info.level if device.battery_info is not None else None battery_charging = device.battery_info.charging() if device.battery_info is not None else None tray_icon_name = icons.battery(battery_level, battery_charging) description = f"{name}: {device.status_string()}" else: # there may be a receiver, but no peripherals tray_icon_name = icons.TRAY_OKAY if _devices_info else icons.TRAY_INIT description_lines = _generate_description_lines() description = "\n".join(description_lines).rstrip("\n") # icon_file = icons.icon_file(icon_name, _TRAY_ICON_SIZE) _icon.set_icon_full(_icon_file(tray_icon_name), description) def attention(reason=None): if _icon.get_status() != AppIndicator3.IndicatorStatus.ATTENTION: # _icon.set_attention_icon_full(_icon_file(icons.TRAY_ATTENTION), reason or '') # works poorly for XFCe 16 _icon.set_status(AppIndicator3.IndicatorStatus.ATTENTION) GLib.timeout_add(10 * 1000, _icon.set_status, AppIndicator3.IndicatorStatus.ACTIVE) except ImportError: logger.debug("using StatusIcon") def _create(menu): icon = Gtk.StatusIcon.new_from_icon_name(icons.TRAY_INIT) icon.set_name(NAME.lower()) icon.set_title(NAME) icon.set_tooltip_text(NAME) icon.connect(GtkSignal.ACTIVATE.value, window.toggle) icon.connect(GtkSignal.SCROLL_EVENT.value, _scroll) icon.connect( "popup-menu", lambda icon, button, time: menu.popup(None, None, icon.position_menu, icon, button, time), ) return icon def _hide(icon): icon.set_visible(False) def _show(icon): icon.set_visible(True) def _update_tray_icon(): tooltip_lines = _generate_tooltip_lines() tooltip = "\n".join(tooltip_lines).rstrip("\n") _icon.set_tooltip_markup(tooltip) if _picked_device and gtk.battery_icons_style != "solaar": _ignore, _ignore, name, device = _picked_device battery_level = device.battery_info.level if device.battery_info is not None else None battery_charging = device.battery_info.charging() if device.battery_info is not None else None tray_icon_name = icons.battery(battery_level, battery_charging) else: # there may be a receiver, but no peripherals tray_icon_name = icons.TRAY_OKAY if _devices_info else icons.TRAY_ATTENTION _icon.set_from_icon_name(tray_icon_name) _icon_before_attention = None def _blink(count): global _icon_before_attention if count % 2: _icon.set_from_icon_name(icons.TRAY_ATTENTION) else: _icon.set_from_icon_name(_icon_before_attention) if count > 0: GLib.timeout_add(1000, _blink, count - 1) else: _icon_before_attention = None def attention(reason=None): global _icon_before_attention if _icon_before_attention is None: _icon_before_attention = _icon.get_icon_name() GLib.idle_add(_blink, 9) def _generate_tooltip_lines(): if not _devices_info: yield f"{NAME}: " + _("no receiver") return yield from _generate_description_lines() def _generate_description_lines(): if not _devices_info: yield _("no receiver") return for _ignore, number, name, device in _devices_info: if number is None: # receiver continue p = device.status_string() if p: # does it have any properties to print? yield f"{name}" if device.online: yield f"\t{p}" else: yield f"\t{p} (" + _("offline") + ")" else: if device.online: yield f"{name} (" + _("no status") + ")" else: yield f"{name} (" + _("offline") + ")" def _pick_device_with_lowest_battery(): if not _devices_info: return None picked = None picked_level = 1000 for info in _devices_info: if info[1] is None: # is receiver continue level = info[-1].battery_info.level if info[-1].battery_info is not None else None if level is not None and picked_level > level: picked = info picked_level = level or 0 logger.debug("picked device with lowest battery: %s", picked) return picked def _add_device(device): assert device index = 0 receiver_path = device.receiver.path if device.receiver is not None else device.path if device.receiver is not None: # if receiver insert into devices for the receiver in device number order for idx, (path, _ignore, _ignore, _ignore) in enumerate(_devices_info): if path and path == receiver_path: index = idx + 1 # the first entry matching the receiver serial should be for the receiver itself break while index < len(_devices_info): path, number, _ignore, _ignore = _devices_info[index] if not path == receiver_path: break assert number != device.number if number > device.number: break index = index + 1 new_device_info = (receiver_path, device.number, device.name, device) _devices_info.insert(index, new_device_info) label = (" " if device.number else "") + device.name new_menu_item = action.make_image_menu_item(label, None, window.popup, receiver_path, device.number) _menu.insert(new_menu_item, index) return index def _remove_device(index): assert index is not None menu_items = _menu.get_children() _menu.remove(menu_items[index]) removed_device = _devices_info.pop(index) global _picked_device if _picked_device and _picked_device[0:2] == removed_device[0:2]: # the current pick was unpaired _picked_device = None def _add_receiver(receiver): index = len(_devices_info) new_receiver_info = (receiver.path, None, receiver.name, None) _devices_info.insert(index, new_receiver_info) icon_name = icons.device_icon_name(receiver.name, receiver.kind) new_menu_item = action.make_image_menu_item(receiver.name, icon_name, window.popup, receiver.path) _menu.insert(new_menu_item, index) return 0 def _remove_receiver(receiver): index = 0 # remove all entries in devices_info that match this receiver while index < len(_devices_info): path, _ignore, _ignore, _ignore = _devices_info[index] if path == receiver.path: _remove_device(index) else: index += 1 def _update_menu_item(index, device): if device is None: logger.warning("updating an inactive device %s, assuming disconnected", device) return None menu_items = _menu.get_children() menu_item = menu_items[index] level = device.battery_info.level if device.battery_info is not None else None charging = device.battery_info.charging() if device.battery_info is not None else None icon_name = icons.battery(level, charging) menu_item.label.set_label((" " if 0 < device.number <= 6 else "") + device.name + ": " + device.status_string()) image_widget = menu_item.icon image_widget.set_sensitive(bool(device.online)) image_widget.set_from_icon_name(icon_name, _MENU_ICON_SIZE) # for which device to show the battery info in systray, if more than one # it's actually an entry in _devices_info _picked_device = None # cached list of devices and some of their properties # contains tuples of (receiver path, device number, name, device) _devices_info = [] _menu = None _icon = None def init(_quit_handler): global _menu, _icon assert _menu is None _menu = _create_menu(_quit_handler) assert _icon is None _icon = _create(_menu) update() def destroy(): global _icon, _menu, _devices_info if _icon is not None: i, _icon = _icon, None _hide(i) i = None _icon = None _menu = None _devices_info = None def update(device=None): if _icon is None: return if device is not None: if device.kind is None: # receiver is_alive = bool(device) receiver_path = device.path if is_alive: index = None for idx, (path, _ignore, _ignore, _ignore) in enumerate(_devices_info): if path == receiver_path: index = idx break if index is None: _add_receiver(device) else: _remove_receiver(device) else: # peripheral is_paired = bool(device) receiver_path = device.receiver.path if device.receiver is not None else device.path index = None for idx, (path, number, _ignore, _ignore) in enumerate(_devices_info): if path == receiver_path and number == device.number: index = idx if is_paired: if index is None: index = _add_device(device) _update_menu_item(index, device) else: # was just unpaired or unplugged if index is not None: _remove_device(index) menu_items = _menu.get_children() no_receivers_index = len(_devices_info) menu_items[no_receivers_index].set_visible(not _devices_info) global _picked_device if (not _picked_device or _last_scroll == 0) and device is not None and device.kind is not None: # if it's just a receiver update, it's unlikely the picked device would change _picked_device = _pick_device_with_lowest_battery() _update_tray_icon() if _icon: if not _devices_info: _hide(_icon) else: _show(_icon) Solaar-1.1.20/lib/solaar/ui/window.py000066400000000000000000000767561522022367600173730ustar00rootroot00000000000000## Copyright (C) 2012-2013 Daniel Pavel ## Copyright (C) 2014-2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import logging from enum import Enum from enum import IntEnum import gi from gi.repository.GObject import TYPE_PYOBJECT from logitech_receiver import hidpp10_constants from logitech_receiver.common import LOGITECH_VENDOR_ID from logitech_receiver.common import NamedInt from solaar import NAME from solaar.i18n import _ from solaar.i18n import ngettext from . import action from . import config_panel from . import diversion_rules from . import icons from .about import about from .common import ui_async gi.require_version("Gdk", "3.0") from gi.repository import Gdk # NOQA: E402 from gi.repository import GLib # NOQA: E402 from gi.repository import Gtk # NOQA: E402 logger = logging.getLogger(__name__) _SMALL_BUTTON_ICON_SIZE = Gtk.IconSize.MENU _NORMAL_BUTTON_ICON_SIZE = Gtk.IconSize.BUTTON _TREE_ICON_SIZE = Gtk.IconSize.BUTTON _INFO_ICON_SIZE = Gtk.IconSize.LARGE_TOOLBAR _DEVICE_ICON_SIZE = Gtk.IconSize.DND try: gi.check_version("3.7.4") _CAN_SET_ROW_NONE = None except (ValueError, AttributeError): _CAN_SET_ROW_NONE = "" class Column(IntEnum): """Columns of tree model.""" PATH = 0 NUMBER = 1 ACTIVE = 2 NAME = 3 ICON = 4 STATUS_TEXT = 5 STATUS_ICON = 6 DEVICE = 7 _COLUMN_TYPES = (str, int, bool, str, str, str, str, TYPE_PYOBJECT) _TREE_SEPATATOR = (None, 0, False, None, None, None, None, None) assert len(_TREE_SEPATATOR) == len(_COLUMN_TYPES) assert len(_COLUMN_TYPES) == len(Column) class GtkSignal(Enum): CHANGED = "changed" CLICKED = "clicked" DELETE_EVENT = "delete-event" def _new_button(label, icon_name=None, icon_size=_NORMAL_BUTTON_ICON_SIZE, tooltip=None, toggle=False, clicked=None): b = Gtk.ToggleButton() if toggle else Gtk.Button() c = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 5) if icon_name: c.pack_start(Gtk.Image.new_from_icon_name(icon_name, icon_size), True, True, 0) if label: c.pack_start(Gtk.Label(label=label), True, True, 0) b.add(c) if clicked is not None: b.connect(GtkSignal.CLICKED.value, clicked) if tooltip: b.set_tooltip_text(tooltip) if not label and icon_size < _NORMAL_BUTTON_ICON_SIZE: b.set_relief(Gtk.ReliefStyle.NONE) b.set_focus_on_click(False) return b def _create_receiver_panel(): p = Gtk.Box.new(Gtk.Orientation.VERTICAL, 4) p._count = Gtk.Label() p._count.set_margin_top(24) p.pack_start(p._count, True, True, 0) p._scanning = Gtk.Label(label=_("Scanning") + "...") p._spinner = Gtk.Spinner() bp = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8) bp.pack_start(Gtk.Label(label=" "), True, True, 0) bp.pack_start(p._scanning, False, False, 0) bp.pack_end(p._spinner, False, False, 0) p.pack_end(bp, False, False, 0) return p def _create_device_panel(): p = Gtk.Box.new(Gtk.Orientation.VERTICAL, 4) def _status_line(label_text): b = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8) b.set_size_request(10, 28) b._label = Gtk.Label(label=label_text) b._label.set_size_request(170, 10) b.pack_start(b._label, False, False, 0) b._icon = Gtk.Image() b.pack_start(b._icon, False, False, 0) b._text = Gtk.Label() b.pack_start(b._text, False, False, 0) return b p._battery = _status_line(_("Battery")) p.pack_start(p._battery, False, False, 0) p._secure = _status_line(_("Wireless Link")) p._secure._icon.set_from_icon_name("dialog-warning", _INFO_ICON_SIZE) p.pack_start(p._secure, False, False, 0) p._lux = _status_line(_("Lighting")) p.pack_start(p._lux, False, False, 0) p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, 0) # spacer p._config = config_panel.create() p.pack_end(p._config, True, True, 4) return p def _create_details_panel(): p = Gtk.Frame() p.set_shadow_type(Gtk.ShadowType.NONE) p.set_size_request(240, 0) p.set_state_flags(Gtk.StateFlags.ACTIVE, True) p._text = Gtk.Label() p._text.set_margin_start(6) p._text.set_margin_end(4) p._text.set_selectable(True) p.add(p._text) return p def _create_buttons_box(): bb = Gtk.HButtonBox() bb.set_layout(Gtk.ButtonBoxStyle.END) bb._details = _new_button( None, "dialog-information", _SMALL_BUTTON_ICON_SIZE, tooltip=_("Show Technical Details"), toggle=True, clicked=_update_details, ) bb.add(bb._details) bb.set_child_secondary(bb._details, True) bb.set_child_non_homogeneous(bb._details, True) def _pair_new_device(trigger): assert _find_selected_device_id() is not None receiver = _find_selected_device() assert receiver is not None assert bool(receiver) assert receiver.kind is None action.pair(_window, receiver) bb._pair = _new_button(_("Pair new device"), "list-add", clicked=_pair_new_device) bb.add(bb._pair) def _unpair_current_device(trigger): assert _find_selected_device_id() is not None device = _find_selected_device() assert device is not None assert device.kind is not None action.unpair(_window, device) bb._unpair = _new_button(_("Unpair"), "edit-delete", clicked=_unpair_current_device) bb.add(bb._unpair) return bb def _create_empty_panel(): p = Gtk.Label() p.set_markup("" + _("Select a device") + "") p.set_sensitive(False) return p def _create_info_panel(): p = Gtk.Box.new(Gtk.Orientation.VERTICAL, 4) p._title = Gtk.Label(label=" ") p._icon = Gtk.Image() b1 = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 4) b1.pack_start(p._title, True, True, 0) b1.pack_start(p._icon, False, False, 0) p.pack_start(b1, False, False, 0) p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, 0) # spacer p._receiver = _create_receiver_panel() p.pack_start(p._receiver, True, True, 0) p._device = _create_device_panel() p.pack_start(p._device, True, True, 0) p.pack_start(Gtk.Separator.new(Gtk.Orientation.HORIZONTAL), False, False, 0) # spacer p._buttons = _create_buttons_box() p.pack_end(p._buttons, False, False, 0) return p def _create_tree(model): tree = Gtk.TreeView() tree.set_size_request(330, 0) # enough width for simple setups tree.set_headers_visible(False) tree.set_show_expanders(False) tree.set_level_indentation(20) tree.set_enable_tree_lines(True) tree.set_reorderable(False) tree.set_enable_search(False) tree.set_model(model) def _is_separator(model, item, _ignore=None): return model.get_value(item, Column.PATH) is None tree.set_row_separator_func(_is_separator, None) icon_cell_renderer = Gtk.CellRendererPixbuf() icon_cell_renderer.set_property("stock-size", _TREE_ICON_SIZE) icon_column = Gtk.TreeViewColumn("Icon", icon_cell_renderer) icon_column.add_attribute(icon_cell_renderer, "sensitive", Column.ACTIVE) icon_column.add_attribute(icon_cell_renderer, "icon-name", Column.ICON) tree.append_column(icon_column) name_cell_renderer = Gtk.CellRendererText() name_column = Gtk.TreeViewColumn("device name", name_cell_renderer) name_column.add_attribute(name_cell_renderer, "sensitive", Column.ACTIVE) name_column.add_attribute(name_cell_renderer, "text", Column.NAME) name_column.set_expand(True) tree.append_column(name_column) tree.set_expander_column(name_column) status_cell_renderer = Gtk.CellRendererText() status_cell_renderer.set_property("scale", 0.85) status_cell_renderer.set_property("xalign", 1) status_column = Gtk.TreeViewColumn("status text", status_cell_renderer) status_column.add_attribute(status_cell_renderer, "sensitive", Column.ACTIVE) status_column.add_attribute(status_cell_renderer, "text", Column.STATUS_TEXT) status_column.set_expand(True) tree.append_column(status_column) battery_cell_renderer = Gtk.CellRendererPixbuf() battery_cell_renderer.set_property("stock-size", _TREE_ICON_SIZE) battery_column = Gtk.TreeViewColumn("status icon", battery_cell_renderer) battery_column.add_attribute(battery_cell_renderer, "sensitive", Column.ACTIVE) battery_column.add_attribute(battery_cell_renderer, "icon-name", Column.STATUS_ICON) tree.append_column(battery_column) return tree def _create_window_layout(): assert _tree is not None assert _details is not None assert _info is not None assert _empty is not None assert _tree.get_selection().get_mode() == Gtk.SelectionMode.SINGLE _tree.get_selection().connect(GtkSignal.CHANGED.value, _device_selected) tree_scroll = Gtk.ScrolledWindow() tree_scroll.add(_tree) tree_scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) tree_scroll.set_shadow_type(Gtk.ShadowType.IN) tree_panel = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) tree_panel.set_homogeneous(False) tree_panel.pack_start(tree_scroll, True, True, 0) tree_panel.pack_start(_details, False, False, 0) panel = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 16) panel.pack_start(tree_panel, False, False, 0) panel.pack_start(_info, True, True, 0) panel.pack_start(_empty, True, True, 0) bottom_buttons_box = Gtk.HButtonBox() bottom_buttons_box.set_layout(Gtk.ButtonBoxStyle.START) bottom_buttons_box.set_spacing(20) quit_button = _new_button(_("Quit %s") % NAME, "application-exit", _SMALL_BUTTON_ICON_SIZE, clicked=destroy) bottom_buttons_box.add(quit_button) about_button = _new_button(_("About %s") % NAME, "help-about", _SMALL_BUTTON_ICON_SIZE, clicked=about.show) bottom_buttons_box.add(about_button) diversion_button = _new_button( _("Rule Editor"), "", _SMALL_BUTTON_ICON_SIZE, clicked=lambda *_trigger: diversion_rules.show_window(_model) ) bottom_buttons_box.add(diversion_button) bottom_buttons_box.set_child_secondary(diversion_button, True) vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8) vbox.set_border_width(8) vbox.pack_start(panel, True, True, 0) vbox.pack_end(bottom_buttons_box, False, False, 0) vbox.show_all() _details.set_visible(False) _info.set_visible(False) return vbox def _create(delete_action): window = Gtk.Window() window.set_title(NAME) window.set_role("status-window") window.connect(GtkSignal.DELETE_EVENT.value, delete_action) vbox = _create_window_layout() window.add(vbox) geometry = Gdk.Geometry() geometry.min_width = 600 geometry.min_height = 320 window.set_geometry_hints(vbox, geometry, Gdk.WindowHints.MIN_SIZE) window.set_position(Gtk.WindowPosition.CENTER) style = window.get_style_context() style.add_class("solaar") return window def _find_selected_device(): selection = _tree.get_selection() model, item = selection.get_selected() return model.get_value(item, Column.DEVICE) if item else None def _find_selected_device_id(): selection = _tree.get_selection() model, item = selection.get_selected() if item: return _model.get_value(item, Column.PATH), _model.get_value(item, Column.NUMBER) # triggered by changing selection in the tree def _device_selected(selection): model, item = selection.get_selected() device = model.get_value(item, Column.DEVICE) if item else None if device: _update_info_panel(device, full=True) else: # When removing a receiver, one of its children may get automatically selected # before the tree had time to remove them as well. # Rather than chase around for another device to select, just clear the selection. _tree.get_selection().unselect_all() _update_info_panel(None, full=True) def _receiver_row(receiver_path, receiver=None): assert receiver_path r = _model.get_iter_first() while r: r = _model.iter_next(r) item = _model.get_iter_first() while item: # first row matching the path must be the receiver one if _model.get_value(item, Column.PATH) == receiver_path: return item item = _model.iter_next(item) if not item and receiver: icon_name = icons.device_icon_name(receiver.name) status_text = None status_icon = None row_data = (receiver_path, 0, True, receiver.name, icon_name, status_text, status_icon, receiver) assert len(row_data) == len(_TREE_SEPATATOR) logger.debug("new receiver row %s", row_data) item = _model.append(None, row_data) if _TREE_SEPATATOR: _model.append(None, _TREE_SEPATATOR) return item or None def _device_row(receiver_path, device_number, device=None): assert device_number is not None if receiver_path is None: return None receiver_row = _receiver_row(receiver_path, None if device is None else device.receiver) if device_number == 0xFF or device_number == 0x0: # direct-connected device, receiver row is device row if receiver_row: return receiver_row item = None new_child_index = 0 else: item = _model.iter_children(receiver_row) new_child_index = 0 while item: if _model.get_value(item, Column.PATH) != receiver_path: logger.warning( "path for device row %s different from path for receiver %s", _model.get_value(item, Column.PATH), receiver_path, ) item_number = _model.get_value(item, Column.NUMBER) if item_number == device_number: return item if item_number > device_number: item = None break new_child_index += 1 item = _model.iter_next(item) if not item and device: icon_name = icons.device_icon_name(device.name, device.kind) status_text = None status_icon = None row_data = ( receiver_path, device_number, bool(device.online), device.codename, icon_name, status_text, status_icon, device, ) assert len(row_data) == len(_TREE_SEPATATOR) logger.debug("new device row %s at index %d", row_data, new_child_index) item = _model.insert(receiver_row, new_child_index, row_data) return item or None def select(receiver_path, device_number=None): assert _window assert receiver_path is not None if device_number is None: item = _receiver_row(receiver_path) else: item = _device_row(receiver_path, device_number) if item: selection = _tree.get_selection() selection.select_iter(item) else: logger.warning("select(%s, %s) failed to find an item", receiver_path, device_number) def _hide(w, _ignore=None): assert w == _window # some window managers move the window to 0,0 after hide() # so try to remember the last position position = _window.get_position() _window.hide() _window.move(*position) return True def popup(trigger=None, receiver_path=None, device_id=None): if receiver_path: select(receiver_path, device_id) _window.present() return True def toggle(trigger=None): if _window.get_visible(): _hide(_window) else: _window.present() def _update_details(button): assert button visible = button.get_active() if visible: # _details._text.set_markup('reading...') def _details_items(device, read_all=False): # If read_all is False, only return stuff that is ~100% already # cached, and involves no HID++ calls. yield _("Path"), device.path if device.kind is None: yield _("USB ID"), f"{LOGITECH_VENDOR_ID:04x}:" + device.product_id if read_all: yield _("Serial"), device.serial else: yield _("Serial"), "..." else: # yield ('Codename', device.codename) yield _("Index"), device.number if device.wpid: yield _("Wireless PID"), device.wpid if device.product_id: yield _("Product ID"), f"{LOGITECH_VENDOR_ID:04x}:" + device.product_id hid_version = device.protocol cent_proto = getattr(device, "_centurion_protocol", None) if cent_proto: yield _("Protocol"), f"Centurion {cent_proto[0]}.{cent_proto[1]}" elif hid_version: yield _("Protocol"), f"HID++ {hid_version:1.1f}" else: yield _("Protocol"), _("Unknown") if read_all and device.polling_rate: yield _("Polling rate"), device.polling_rate if read_all or not device.online: yield _("Serial"), device.serial else: yield _("Serial"), "..." if read_all and device.unitId and device.unitId != device.serial: yield _("Unit ID"), device.unitId if read_all: if device.firmware: for fw in list(device.firmware): yield " " + _(str(fw.kind)), (fw.name + " " + fw.version).strip() elif device.kind is None or device.online: yield f" {_('Firmware')}", "..." flag_bits = device.notification_flags if flag_bits is not None: flag_names = hidpp10_constants.flags_to_str(flag_bits, fallback=f"({_('none')})") yield _("Notifications"), flag_names def _set_details(text): _details._text.set_markup(text) def _make_text(items): text = "\n".join("%-13s: %s" % (name, value) for name, value in items) return f"{text}" def _displayable_items(items): for name, value in items: value = GLib.markup_escape_text(str(value).replace("\x00", "")).strip() if value: yield name, value def _read_slow(device): items = _details_items(selected_device, True) items = _displayable_items(items) text = _make_text(items) if device == _details._current_device: GLib.idle_add(_set_details, text) selected_device = _find_selected_device() assert selected_device _details._current_device = selected_device read_all = not (selected_device.kind is None or selected_device.online) items = _details_items(selected_device, read_all) _set_details(_make_text(items)) if read_all: _details._current_device = None else: ui_async(_read_slow, selected_device) _details.set_visible(visible) def _update_receiver_panel(receiver, panel, buttons, full=False): assert receiver devices_count = len(receiver) paired_text = ( _(_("No device paired.")) if devices_count == 0 else ngettext("%(count)s paired device.", "%(count)s paired devices.", devices_count) % {"count": devices_count} ) if receiver.max_devices > 0: paired_text += ( "\n\n%s" % ngettext( "Up to %(max_count)s device can be paired to this receiver.", "Up to %(max_count)s devices can be paired to this receiver.", receiver.max_devices, ) % {"max_count": receiver.max_devices} ) elif devices_count > 0: paired_text += f"\n\n{_('Only one device can be paired to this receiver.')}" pairings = receiver.remaining_pairings() if pairings is not None and pairings >= 0: paired_text += "\n%s" % ( ngettext("This receiver has %d pairing remaining.", "This receiver has %d pairings remaining.", pairings) % pairings ) panel._count.set_markup(paired_text) is_pairing = receiver.pairing.lock_open if is_pairing: panel._scanning.set_visible(True) if not panel._spinner.get_visible(): panel._spinner.start() panel._spinner.set_visible(True) else: panel._scanning.set_visible(False) if panel._spinner.get_visible(): panel._spinner.stop() panel._spinner.set_visible(False) panel.set_visible(True) # b._insecure.set_visible(False) buttons._unpair.set_visible(False) if ( not is_pairing and (receiver.remaining_pairings() is None or receiver.remaining_pairings() != 0) and (receiver.re_pairs or devices_count < receiver.max_devices) ): buttons._pair.set_sensitive(True) else: buttons._pair.set_sensitive(False) buttons._pair.set_visible(True) def _update_device_panel(device, panel, buttons, full=False): assert device is_online = bool(device.online) panel.set_sensitive(is_online) if device.battery_info is None or device.battery_info.level is None: device.read_battery() battery_level = device.battery_info.level if device.battery_info is not None else None battery_voltage = device.battery_info.voltage if device.battery_info is not None else None if battery_level is None and battery_voltage is None: panel._battery.set_visible(False) else: panel._battery.set_visible(True) battery_next_level = device.battery_info.next_level charging = device.battery_info.charging() if device.battery_info is not None else None icon_name = icons.battery(battery_level, charging) panel._battery._icon.set_from_icon_name(icon_name, _INFO_ICON_SIZE) panel._battery._icon.set_sensitive(True) panel._battery._text.set_sensitive(is_online) if battery_voltage is not None: panel._battery._label.set_text(_("Battery Voltage")) text = f"{int(battery_voltage)}mV" tooltip_text = _("Voltage reported by battery") else: panel._battery._label.set_text(_("Battery Level")) text = "" tooltip_text = _("Approximate level reported by battery") if battery_voltage is not None and battery_level is not None: text += ", " if battery_level is not None: text += _(str(battery_level)) if isinstance(battery_level, NamedInt) else f"{int(battery_level)}%" if battery_next_level is not None and not charging: if isinstance(battery_next_level, NamedInt): text += " (" + _("next reported ") + _(str(battery_next_level)) + ")" else: text += " (" + _("next reported ") + f"{int(battery_next_level)}%" + ")" tooltip_text = tooltip_text + _(" and next level to be reported.") if is_online: if charging: text += f" ({_('charging')})" else: text += f" ({_('last known')})" panel._battery._text.set_markup(text) panel._battery.set_tooltip_text(tooltip_text) if device.link_encrypted is None: panel._secure.set_visible(False) elif is_online: panel._secure.set_visible(True) panel._secure._icon.set_visible(True) if device.link_encrypted is True: panel._secure._text.set_text(_("encrypted")) panel._secure._icon.set_from_icon_name("security-high", _INFO_ICON_SIZE) panel._secure.set_tooltip_text(_("The wireless link between this device and its receiver is encrypted.")) else: panel._secure._text.set_text(_("not encrypted")) panel._secure._icon.set_from_icon_name("security-low", _INFO_ICON_SIZE) panel._secure.set_tooltip_text( _( "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue for text-input devices." ) ) else: panel._secure.set_visible(True) panel._secure._icon.set_visible(False) panel._secure._text.set_markup(f"{_('offline')}") panel._secure.set_tooltip_text("") if is_online: light_level = device.battery_info.light_level if device.battery_info is not None else None if light_level is None: panel._lux.set_visible(False) else: panel._lux._icon.set_from_icon_name(icons.lux(light_level), _INFO_ICON_SIZE) panel._lux._text.set_text(_("%(light_level)d lux") % {"light_level": light_level}) panel._lux.set_visible(True) else: panel._lux.set_visible(False) buttons._pair.set_visible(False) buttons._unpair.set_sensitive(device.receiver.may_unpair if device.receiver else False) buttons._unpair.set_visible(True) panel.set_visible(True) if full: config_panel.update(device, is_online) def _update_info_panel(device, full=False): if device is None: # no selected device, show the 'empty' panel _details.set_visible(False) _info.set_visible(False) _empty.set_visible(True) return # a receiver must be valid # a device must be paired assert device _info._title.set_markup(f"{device.name}") icon_name = icons.device_icon_name(device.name, device.kind) _info._icon.set_from_icon_name(icon_name, _DEVICE_ICON_SIZE) if device.kind is None: _info._device.set_visible(False) _info._icon.set_sensitive(True) _info._title.set_sensitive(True) _update_receiver_panel(device, _info._receiver, _info._buttons, full) else: _info._receiver.set_visible(False) is_online = bool(device.online) _info._icon.set_sensitive(is_online) _info._title.set_sensitive(is_online) _update_device_panel(device, _info._device, _info._buttons, full) _empty.set_visible(False) _info.set_visible(True) if full: _update_details(_info._buttons._details) # window layout: # +--------------------------------+ # | tree | receiver | empty | # | | or device | | # |------------| status | | # | details | | | # |--------------------------------| # | (about) | # +--------------------------------| # either the status or empty panel is visible at any point # the details panel can be toggle on/off _model = None _tree = None _details = None _info = None _empty = None _window = None def init(show_window, hide_on_close): Gtk.Window.set_default_icon_name(NAME.lower()) global _model, _tree, _details, _info, _empty, _window _model = Gtk.TreeStore(*_COLUMN_TYPES) _tree = _create_tree(_model) _details = _create_details_panel() _info = _create_info_panel() _empty = _create_empty_panel() _window = _create(_hide if hide_on_close else destroy) if show_window: _window.present() def destroy(_ignore1=None, _ignore2=None): global _model, _tree, _details, _info, _empty, _window w, _window = _window, None w.destroy() w = None config_panel.destroy() _empty = None _info = None _details = None _tree = None _model = None def update(device, need_popup=False, refresh=False): if _window is None: return assert device is not None if need_popup: popup() selected_device_id = _find_selected_device_id() if device.kind is None: # receiver # receiver is_alive = bool(device) item = _receiver_row(device.path, device if is_alive else None) if is_alive and item: was_pairing = bool(_model.get_value(item, Column.STATUS_ICON)) is_pairing = (not device.isDevice) and bool(device.pairing.lock_open) _model.set_value(item, Column.STATUS_ICON, "network-wireless" if is_pairing else _CAN_SET_ROW_NONE) if selected_device_id == (device.path, 0): full_update = need_popup or was_pairing != is_pairing _update_info_panel(device, full=full_update) elif item: if _TREE_SEPATATOR: separator = _model.iter_next(item) if separator: _model.remove(separator) _model.remove(item) else: path = device.receiver.path if device.receiver is not None else device.path assert device.number is not None and device.number >= 0, f"invalid device number{str(device.number)}" item = _device_row(path, device.number, device if bool(device) else None) if bool(device) and item: update_device(device, item, selected_device_id, need_popup, full=refresh) elif item: _model.remove(item) config_panel.clean(device) # make sure all rows are visible _tree.expand_all() def update_device(device, item, selected_device_id, need_popup, full=False): was_online = _model.get_value(item, Column.ACTIVE) is_online = bool(device.online) _model.set_value(item, Column.ACTIVE, is_online) battery_level = device.battery_info.level if device.battery_info is not None else None battery_voltage = device.battery_info.voltage if device.battery_info is not None else None if battery_level is None: _model.set_value(item, Column.STATUS_TEXT, _CAN_SET_ROW_NONE) _model.set_value(item, Column.STATUS_ICON, _CAN_SET_ROW_NONE) else: if battery_voltage is not None and False: # Use levels instead of voltage here status_text = f"{int(battery_voltage)}mV" elif isinstance(battery_level, NamedInt): status_text = _(str(battery_level)) else: status_text = f"{int(battery_level)}%" _model.set_value(item, Column.STATUS_TEXT, status_text) charging = device.battery_info.charging() if device.battery_info is not None else None icon_name = icons.battery(battery_level, charging) _model.set_value(item, Column.STATUS_ICON, icon_name) _model.set_value(item, Column.NAME, device.codename) if selected_device_id is None or need_popup: select(device.receiver.path if device.receiver else device.path, device.number) elif selected_device_id == (device.receiver.path if device.receiver else device.path, device.number): full_update = full or was_online != is_online _update_info_panel(device, full=full_update) def find_device(serial): assert serial, "need serial number or unit ID to find a device" result = None def check(_store, _treepath, row): nonlocal result device = _model.get_value(row, Column.DEVICE) if device and device.kind and (device.unitId == serial or device.serial == serial): result = device return True _model.foreach(check) return result Solaar-1.1.20/lib/solaar/version000066400000000000000000000000071522022367600164550ustar00rootroot000000000000001.1.20 Solaar-1.1.20/mkdocs.yml000066400000000000000000000014071522022367600150260ustar00rootroot00000000000000site_name: Solaar Documentation site_description: Linux Device Manager for Logitech Unifying Receivers and Devices. site_author: pwr-Solaar repo_url: https://github.com/pwr-Solaar/Solaar repo_name: Solaar theme: name: readthedocs docs_dir: docs nav: - Solaar: index.md - Usage: usage.md - Capabilities: capabilities.md - Issues: issues.md - Rules: rules.md - Installation: installation.md - Uninstallation: uninstallation.md - Translation: i18n.md - Features: features.md - Devices: devices.md - Implementation: implementation.md - Debian: debian.md plugins: - search # - mkdocstrings: # handlers: # python: # setup_commands: # - python -m pip install . - mermaid2 markdown_extensions: - pymdownx.superfences Solaar-1.1.20/po/000077500000000000000000000000001522022367600134375ustar00rootroot00000000000000Solaar-1.1.20/po/README000066400000000000000000000001141522022367600143130ustar00rootroot00000000000000See docs/i18n.md for instructions about creating or updating a translation. Solaar-1.1.20/po/bg.po000066400000000000000000002175121522022367600143770ustar00rootroot00000000000000# Bulgarian translations for solaar package. # Copyright (C) 2026 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2026. # msgid "" msgstr "" "Project-Id-Version: solaar 1.1.19\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-04-04 20:19+0300\n" "PO-Revision-Date: 2026-04-05 03:37+0300\n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.8\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Bolt Приемник" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Unifying Приемник" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Nano Приемник" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Logitech Приемник" #: lib/logitech_receiver/base_usb.py:136 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 Приемник 27 мегахерца" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Батери�: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Батери�: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1049 lib/logitech_receiver/settings_templates.py:299 msgid "Disabled" msgstr "Деактивиран" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Static" msgstr "Статичен" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Pulse" msgstr "Пул�" #: lib/logitech_receiver/hidpp20.py:1052 msgid "Cycle" msgstr "Цикъл" #: lib/logitech_receiver/hidpp20.py:1053 msgid "Boot" msgstr "Зареждане" #: lib/logitech_receiver/hidpp20.py:1054 msgid "Demo" msgstr "Демон�траци�" #: lib/logitech_receiver/hidpp20.py:1056 msgid "Breathe" msgstr "Дишане" #: lib/logitech_receiver/hidpp20.py:1059 msgid "Ripple" msgstr "Прекъ�ване" #: lib/logitech_receiver/hidpp20.py:1060 msgid "Decomposition" msgstr "Разпадане" #: lib/logitech_receiver/hidpp20.py:1061 msgid "Signature1" msgstr "Подпи�1" #: lib/logitech_receiver/hidpp20.py:1062 msgid "Signature2" msgstr "Подпи�2" #: lib/logitech_receiver/hidpp20.py:1063 msgid "CycleS" msgstr "Цикли" #: lib/logitech_receiver/hidpp20.py:1127 msgid "Unknown Location" msgstr "�еизве�тно Ме�тонахождение" #: lib/logitech_receiver/hidpp20.py:1128 msgid "Primary" msgstr "Първичен" #: lib/logitech_receiver/hidpp20.py:1129 msgid "Logo" msgstr "Лого" #: lib/logitech_receiver/hidpp20.py:1130 msgid "Left Side" msgstr "Л�ва Страна" #: lib/logitech_receiver/hidpp20.py:1131 msgid "Right Side" msgstr "Д��на Страна" #: lib/logitech_receiver/hidpp20.py:1132 msgid "Combined" msgstr "Комбиниран" #: lib/logitech_receiver/hidpp20.py:1133 msgid "Primary 1" msgstr "Първичен 1" #: lib/logitech_receiver/hidpp20.py:1134 msgid "Primary 2" msgstr "Първичен 2" #: lib/logitech_receiver/hidpp20.py:1135 msgid "Primary 3" msgstr "Първичен 3" #: lib/logitech_receiver/hidpp20.py:1136 msgid "Primary 4" msgstr "Първичен 4" #: lib/logitech_receiver/hidpp20.py:1137 msgid "Primary 5" msgstr "Първичен 5" #: lib/logitech_receiver/hidpp20.py:1138 msgid "Primary 6" msgstr "Първичен 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "празен" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "критично" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "ни�ко" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "�редно" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "добро" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "пълно" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "разреждане" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "презареждане" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "зареждане" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "не �е зарежда" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "почти пълно" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "заредено" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "бавно презареждане" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "неправилна батери�" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "температурна грешка" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "грешка" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "�тандартно" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "бърз" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "бавен" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "изтекло време за операци�" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "у�трой�тво което не �е потдържа" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "твърде много у�трой�тва" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "изтекло време за поредица от операции" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "Фърмуеър" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Бутлоудър" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Хардуер" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Друг" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Л�в Бутон" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Де�ен Бутон" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Среден Бутон" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Бутон за �азад" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Бутон за �апред" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Бутон за же�тове � мишката" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Умно преме�тване" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Превключване на чув�твително�тта (DPI)" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Л�в �аклон" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Де�ен �аклон" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Л�в Клик" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Де�ен Клик" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Среден Бутон на Мишката" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Бутон за �азад на Мишката" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Бутон за �апред на Мишката" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "�авигационен Бутон за Же�товете" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Бутон на Мишката за Скролиране �ал�во" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Бутон на Мишката за Скролиране �ад��но" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "нати�тнат" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "�вободен" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "�вързан" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "не е �вързан" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "не е �двоен" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "включен" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "изве�тие за измерване на ADC" #: lib/logitech_receiver/notifications.py:428 lib/logitech_receiver/notifications.py:484 msgid "pairing lock is closed" msgstr "заключване на �дво�ването е затворено" #: lib/logitech_receiver/notifications.py:428 lib/logitech_receiver/notifications.py:484 msgid "pairing lock is open" msgstr "заключване на �дво�ването е отворено" #: lib/logitech_receiver/notifications.py:447 msgid "discovery lock is closed" msgstr "заключване на откриваемо�тта е затворено" #: lib/logitech_receiver/notifications.py:447 msgid "discovery lock is open" msgstr "заключване на откриваемо�тта е отворено" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "��ма �двоени у�трой�тва." #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s �двоени у�трой�тва." msgstr[1] "%(count)s �двоени у�трой�тва." #: lib/logitech_receiver/settings.py:602 msgid "register" msgstr "реги�триране" #: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654 msgid "feature" msgstr "функционално�ти" #: lib/logitech_receiver/settings_templates.py:138 msgid "Swap Fx function" msgstr "Разм�на Fх функци�" #: lib/logitech_receiver/settings_templates.py:141 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Когато е активиран бутоните F1..F12 ще изпълн�ват �воите �пециални функции,\n" "и тр�бва да нати�нете Fn бутона, за да активирате техните нормални функции." #: lib/logitech_receiver/settings_templates.py:146 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Когато не е активиран, бутоните F1..F12 ще изпълн�ват �воите нормални функции,\n" "и тр�бва да нати�нете Fn бутона за да активирате техните �пециални функции." #: lib/logitech_receiver/settings_templates.py:154 msgid "Hand Detection" msgstr "Разоизнаване на ръка" #: lib/logitech_receiver/settings_templates.py:155 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Включване на о�ветлението когато ръцете �а над клавиатурата." #: lib/logitech_receiver/settings_templates.py:162 msgid "Scroll Wheel Smooth Scrolling" msgstr "Скрол Плавно �кролиране/превъртане" #: lib/logitech_receiver/settings_templates.py:163 lib/logitech_receiver/settings_templates.py:410 #: lib/logitech_receiver/settings_templates.py:439 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Ви�око-чув�твителен режим за вертикално �кролиране/превъртане �ъ� �кролът." #: lib/logitech_receiver/settings_templates.py:170 msgid "Side Scrolling" msgstr "Странично Скролиране/превъртане" #: lib/logitech_receiver/settings_templates.py:172 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Когато е деактивиран, �траничното нати�кане на �кролът, изпраща модифицирана команда\n" "вме�то �тандартното �транично �кролиране/превъртане." #: lib/logitech_receiver/settings_templates.py:182 msgid "Sensitivity (DPI - older mice)" msgstr "Чув�твително�т (DPI - за по-�тарите мишки )" #: lib/logitech_receiver/settings_templates.py:183 lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 msgid "Mouse movement sensitivity" msgstr "Чув�твително�т при движение на мишката" #: lib/logitech_receiver/settings_templates.py:256 msgid "Backlight Timed" msgstr "Време на Под�ветката" #: lib/logitech_receiver/settings_templates.py:257 lib/logitech_receiver/settings_templates.py:397 msgid "Set illumination time for keyboard." msgstr "Задаване на време на о�вет�ване на клавиатурата." #: lib/logitech_receiver/settings_templates.py:268 msgid "Backlight" msgstr "Под�ветка" #: lib/logitech_receiver/settings_templates.py:269 msgid "Illumination level on keyboard. Changes made are only applied in Manual mode." msgstr "�иво на о�ветено�т на клавиатурата. �аправените промени �а приложими �амо в Ръчен режим." #: lib/logitech_receiver/settings_templates.py:301 msgid "Automatic" msgstr "�втоматично" #: lib/logitech_receiver/settings_templates.py:303 msgid "Manual" msgstr "Ръчно" #: lib/logitech_receiver/settings_templates.py:305 msgid "Enabled" msgstr "�ктивно" #: lib/logitech_receiver/settings_templates.py:311 msgid "Backlight Level" msgstr "�иво на Под�ветка" #: lib/logitech_receiver/settings_templates.py:312 msgid "Illumination level on keyboard when in Manual mode." msgstr "�иво на под�ветка в Ръчен режим." #: lib/logitech_receiver/settings_templates.py:369 msgid "Backlight Delay Hands Out" msgstr "Закъ�нение на под�ветката при премахване на ръцете" #: lib/logitech_receiver/settings_templates.py:370 msgid "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "Закъ�нение в �екунди докато под�ветката изга�не � премахване на ръцете от клавиатурата." #: lib/logitech_receiver/settings_templates.py:378 msgid "Backlight Delay Hands In" msgstr "Закъ�нение на под�ветката при за�ичане на ръце" #: lib/logitech_receiver/settings_templates.py:379 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "Закъ�нение в �екунди докато под�ветката изга�не � при за�ичане на ръце около клавиатурата." #: lib/logitech_receiver/settings_templates.py:387 msgid "Backlight Delay Powered" msgstr "Закъ�нение на под�ветката при Включване" #: lib/logitech_receiver/settings_templates.py:388 msgid "Delay in seconds until backlight fades out with external power." msgstr "Закъ�нение в �екунди докато под�ветката изга�не � външно захранване." #: lib/logitech_receiver/settings_templates.py:396 msgid "Backlight (Seconds)" msgstr "Под�ветка (Секунди)" #: lib/logitech_receiver/settings_templates.py:408 msgid "Scroll Wheel High Resolution" msgstr "Колело за �кролиране/превъртане � Ви�ока Резолюци�" #: lib/logitech_receiver/settings_templates.py:412 lib/logitech_receiver/settings_templates.py:441 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Игнориране ако �кролирането е извънредно бързо или бавно" #: lib/logitech_receiver/settings_templates.py:419 lib/logitech_receiver/settings_templates.py:450 msgid "Scroll Wheel Diversion" msgstr "Отклонение на Скролиращото Колело" #: lib/logitech_receiver/settings_templates.py:421 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger Solaar rules but are " "otherwise ignored)." msgstr "" "Скролиращото колело изпраща LOWRES_WHEEL HID++ изве�тие ( задей�тващо правилата на Solaar, което " "иначе е игнорирано)." #: lib/logitech_receiver/settings_templates.py:428 msgid "Scroll Wheel Direction" msgstr "По�ока на Скролиращото Колело" #: lib/logitech_receiver/settings_templates.py:429 msgid "Invert direction for vertical scroll with wheel." msgstr "Обръщане на по�оката на вертикално �кролиране/превъртане � колелото." #: lib/logitech_receiver/settings_templates.py:437 msgid "Scroll Wheel Resolution" msgstr "Чув�твително�т на Скролиращото/Превъртащото Колело" #: lib/logitech_receiver/settings_templates.py:452 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar rules but are " "otherwise ignored)." msgstr "" "Скролиращото колело изпраща HIRES_WHEEL HID++ изве�тие ( задей�тващо правилата на Solaar, което " "иначе е игнорирано)." #: lib/logitech_receiver/settings_templates.py:461 msgid "Sensitivity (Pointer Speed)" msgstr "Чув�твително�т (Скоро�т на кур�ора)" #: lib/logitech_receiver/settings_templates.py:462 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Множител на �коро�тта за мишка (256 е нормални� множител)." #: lib/logitech_receiver/settings_templates.py:472 msgid "Thumb Wheel Diversion" msgstr "Колелото на Палеца Отклон�ване" #: lib/logitech_receiver/settings_templates.py:474 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar rules but are " "otherwise ignored)." msgstr "" "Колелото на Палеца изпраща THUMB_WHEEL HID++ изве�тие ( задей�тващо правилата на Solaar, което " "иначе е игнорирано )." #: lib/logitech_receiver/settings_templates.py:483 msgid "Thumb Wheel Direction" msgstr "По�ока на Колелото на Палеца" #: lib/logitech_receiver/settings_templates.py:484 msgid "Invert thumb wheel scroll direction." msgstr "Обръщане на по�оката на колелото на палеца." #: lib/logitech_receiver/settings_templates.py:504 msgid "Onboard Profiles" msgstr "Вградени Профили" #: lib/logitech_receiver/settings_templates.py:505 msgid "Enable an onboard profile, which controls report rate, sensitivity, and button actions" msgstr "" "�ктивиране на вградените профили, които контролират бързината на рапортуване, чув�твително�т, и " "реакциите на бутоните" #: lib/logitech_receiver/settings_templates.py:549 lib/logitech_receiver/settings_templates.py:582 msgid "Report Rate" msgstr "Бързина на рапортуване" #: lib/logitech_receiver/settings_templates.py:551 lib/logitech_receiver/settings_templates.py:584 msgid "Frequency of device movement reports" msgstr "Че�тота на рапортите за движение на у�трой�твото" #: lib/logitech_receiver/settings_templates.py:551 lib/logitech_receiver/settings_templates.py:584 #: lib/logitech_receiver/settings_templates.py:1019 lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1421 lib/logitech_receiver/settings_templates.py:1452 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "За по-добра ефективно�т, е възможно да �е наложи да Деактивирате Вградените Профили." #: lib/logitech_receiver/settings_templates.py:612 msgid "Divert crown events" msgstr "Събити� за отклонение на короната" #: lib/logitech_receiver/settings_templates.py:613 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but are otherwise ignored)." msgstr "" "Короната изпраща CROWN HID++ изве�тие ( задей�тващо правилата на Solaar, което иначе е игнорирано)." #: lib/logitech_receiver/settings_templates.py:621 msgid "Crown smooth scroll" msgstr "Плавно �кролиране � Корона" #: lib/logitech_receiver/settings_templates.py:622 msgid "Set crown smooth scroll" msgstr "Задаване на плавно �кролиране � корона" #: lib/logitech_receiver/settings_templates.py:630 msgid "Divert G and M Keys" msgstr "Отклонение на клавиши G и M" #: lib/logitech_receiver/settings_templates.py:631 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but are otherwise ignored)." msgstr "" "Клавишите G и M изпращат HID++ изве�тие ( задей�тващо правилата на Solaar, което иначе е " "игнорирано)." #: lib/logitech_receiver/settings_templates.py:645 msgid "Scroll Wheel Ratcheted" msgstr "Тре�чотъчно Скролиращо Колело" #: lib/logitech_receiver/settings_templates.py:646 msgid "Switch the mouse wheel between speed-controlled ratcheting and always freespin." msgstr "" "См�на на режима на �кролиращото колело на мишката, между контрол � тре�чотъчно въртене и �вободно " "въртене." #: lib/logitech_receiver/settings_templates.py:648 msgid "Freespinning" msgstr "Свободно въртене" #: lib/logitech_receiver/settings_templates.py:648 msgid "Ratcheted" msgstr "Тре�чотъчно" #: lib/logitech_receiver/settings_templates.py:655 msgid "Scroll Wheel Ratchet Speed" msgstr "Скоро�т на Тре�чтотъчно Скролиране" #: lib/logitech_receiver/settings_templates.py:657 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Използване на колелото на мишката, за �м�на между тре�чотъчно и �вободно въртене. \n" "Движението на колелото е винаги тре�чотъчно на 50." #: lib/logitech_receiver/settings_templates.py:707 msgid "Scroll Wheel Ratchet Torque" msgstr "Тре�чотъчно У�илие на Скролиращото Колело" #: lib/logitech_receiver/settings_templates.py:708 msgid "Change the torque needed to overcome the ratchet." msgstr "Пром�на на у�илието, нужно за преодол�ване на тре�чотката." #: lib/logitech_receiver/settings_templates.py:743 msgid "Key/Button Actions" msgstr "Дей�тви� на Клавиши / Бутони" #: lib/logitech_receiver/settings_templates.py:745 msgid "Change the action for the key or button." msgstr "Пром�на дей�твието за клавиш или бутон." #: lib/logitech_receiver/settings_templates.py:747 msgid "Overridden by diversion." msgstr "Управл�вано от отклонение." #: lib/logitech_receiver/settings_templates.py:749 msgid "" "Changing important actions (such as for the left mouse button) can result in an unusable system." msgstr "" "Пром�на на важни дей�тви� ( като това за л�в бутон на мишката ) може да доведе до неизползваема " "�и�тема." #: lib/logitech_receiver/settings_templates.py:924 msgid "Key/Button Diversion" msgstr "Отклон�ване на Клавиши / Бутони" #: lib/logitech_receiver/settings_templates.py:925 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse Gestures or Sliding " "DPI" msgstr "" "Клавиш или бутон изпраща HID++ изве�тие (Отклонено) или инициира Же�т на Мишката или Скролиране DPI" #: lib/logitech_receiver/settings_templates.py:928 lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Diverted" msgstr "Отклонени" #: lib/logitech_receiver/settings_templates.py:928 lib/logitech_receiver/settings_templates.py:929 msgid "Mouse Gestures" msgstr "Же�тове на Мишката" #: lib/logitech_receiver/settings_templates.py:928 lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Regular" msgstr "Обичайни" #: lib/logitech_receiver/settings_templates.py:928 msgid "Sliding DPI" msgstr "Скролиране DPI" #: lib/logitech_receiver/settings_templates.py:1018 lib/logitech_receiver/settings_templates.py:1046 msgid "Sensitivity (DPI)" msgstr "Чув�твително�т DPI" #: lib/logitech_receiver/settings_templates.py:1123 msgid "Sensitivity Switching" msgstr "Превключване на Чув�твително�т" #: lib/logitech_receiver/settings_templates.py:1125 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Превключване между на�то�щата и запаметена чув�твително�т, когато клавиш или бутон е нати�нат.\n" "�ко в�е още н�ма запаметена чув�твително�т, запаметете на�то�щата" #: lib/logitech_receiver/settings_templates.py:1129 msgid "Off" msgstr "Изключване" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Disable keys" msgstr "Деактивиране Клавиши" #: lib/logitech_receiver/settings_templates.py:1161 msgid "Disable specific keyboard keys." msgstr "Деактивиране на �пецифични клавиши от клавиатура." #: lib/logitech_receiver/settings_templates.py:1164 #, python-format msgid "Disables the %s key." msgstr "Деактивиране на %s клавиш." #: lib/logitech_receiver/settings_templates.py:1177 lib/logitech_receiver/settings_templates.py:1234 msgid "Set OS" msgstr "Задаване на Операционна Си�тема" #: lib/logitech_receiver/settings_templates.py:1178 lib/logitech_receiver/settings_templates.py:1235 msgid "Change keys to match OS." msgstr "Пром�на на клавишите за да �ъответ�тват на Операционната Си�тема." #: lib/logitech_receiver/settings_templates.py:1247 msgid "Change Host" msgstr "Пром�на на Хо�т" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Switch connection to a different host" msgstr "См�на на връзката на друг Хо�т" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Performs a left click." msgstr "Изпълн�ва л�в клик." #: lib/logitech_receiver/settings_templates.py:1272 msgid "Single tap" msgstr "Единично почукване" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Performs a right click." msgstr "Изпълн�ва де�ен клик." #: lib/logitech_receiver/settings_templates.py:1273 msgid "Single tap with two fingers" msgstr "Единично почукване � два пръ�та" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Single tap with three fingers" msgstr "Единично почукване � три пръ�та" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Double tap" msgstr "Двойно почукване" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Performs a double click." msgstr "Изпълн�ва двойно кликане." #: lib/logitech_receiver/settings_templates.py:1279 msgid "Double tap with two fingers" msgstr "Двойно почукване � два пръ�та" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Double tap with three fingers" msgstr "Двойно почукване � три пръ�та" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Drags items by dragging the finger after double tapping." msgstr "Издърпва неща чрез издърпване на пръ�т �лед двойно почукване." #: lib/logitech_receiver/settings_templates.py:1283 msgid "Tap and drag" msgstr "Почукване и издърпване" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Tap and drag with two fingers" msgstr "Почукване и издърпване � два пръ�та" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Drags items by dragging the fingers after double tapping." msgstr "Издърпва неща чрез издърпване на пръ�ти �лед двойно почукване." #: lib/logitech_receiver/settings_templates.py:1288 msgid "Tap and drag with three fingers" msgstr "Почукване и издърпване � три пръ�та" #: lib/logitech_receiver/settings_templates.py:1291 msgid "Suppress tap and edge gestures" msgstr "Подти�кане на почукване и же�тове по ръба(перифери�та)" #: lib/logitech_receiver/settings_templates.py:1292 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Деактивиране на почукване и же�тове по перифери�та (равно�илни на нати�кане на Fn+л�в клик)." #: lib/logitech_receiver/settings_templates.py:1294 msgid "Scroll with one finger" msgstr "Скролиране � един пръ�т" #: lib/logitech_receiver/settings_templates.py:1294 lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scrolls." msgstr "Скролове." #: lib/logitech_receiver/settings_templates.py:1295 lib/logitech_receiver/settings_templates.py:1298 msgid "Scroll with two fingers" msgstr "Скролиране � два пръ�та" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scroll horizontally with two fingers" msgstr "Хоризонтално �кролиране � два пръ�та" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scrolls horizontally." msgstr "Хоризонтално �кролиране." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scroll vertically with two fingers" msgstr "Вертикално �кролиране � два пръ�та" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scrolls vertically." msgstr "Вертикално �кролиране." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Inverts the scrolling direction." msgstr "Обръщане на по�оката на �кролиране/превъртане." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Natural scrolling" msgstr "�атурално �кролиране" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Enables the thumbwheel." msgstr "�ктивиране на колелото на палеца." #: lib/logitech_receiver/settings_templates.py:1300 msgid "Thumbwheel" msgstr "Колело на палеца" #: lib/logitech_receiver/settings_templates.py:1311 lib/logitech_receiver/settings_templates.py:1315 msgid "Swipe from the top edge" msgstr "Превъртане от горни� ръб" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Swipe from the left edge" msgstr "Плъзгане от леви� ръб" #: lib/logitech_receiver/settings_templates.py:1313 msgid "Swipe from the right edge" msgstr "Плъзгане от де�ни� ръб" #: lib/logitech_receiver/settings_templates.py:1314 msgid "Swipe from the bottom edge" msgstr "Плъзгане от долни� ръб" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Swipe two fingers from the left edge" msgstr "Плъзгане � два пръ�та от леви� ръб" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Swipe two fingers from the right edge" msgstr "Плъзгане � два пръ�та от де�ни� ръб" #: lib/logitech_receiver/settings_templates.py:1318 msgid "Swipe two fingers from the bottom edge" msgstr "Плъзгане � два пръ�та от долни� ръб" #: lib/logitech_receiver/settings_templates.py:1319 msgid "Swipe two fingers from the top edge" msgstr "Плъзгане � два пръ�та от горни� ръб" #: lib/logitech_receiver/settings_templates.py:1320 lib/logitech_receiver/settings_templates.py:1324 msgid "Pinch to zoom out; spread to zoom in." msgstr "Щипнване за отдалечаване; раздел�не на пръ�ти за приближаване." #: lib/logitech_receiver/settings_templates.py:1320 msgid "Zoom with two fingers." msgstr "Прближаване � два пръ�та." #: lib/logitech_receiver/settings_templates.py:1321 msgid "Pinch to zoom out." msgstr "Щипване за отдалечаване." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Spread to zoom in." msgstr "Раздел�не на пръ�ти за приближаване." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Zoom with three fingers." msgstr "Приближаване � три пръ�та." #: lib/logitech_receiver/settings_templates.py:1324 msgid "Zoom with two fingers" msgstr "Приближаване � два пръ�та" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Pixel zone" msgstr "Зона на пик�ели" #: lib/logitech_receiver/settings_templates.py:1343 msgid "Ratio zone" msgstr "Съотношение на зона" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scale factor" msgstr "Коефициент на мащабиране" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Sets the cursor speed." msgstr "Задаване на �коро�т на кур�ора." #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left" msgstr "Л�во" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left-most coordinate." msgstr "Крайни леви координати." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom" msgstr "Долу" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom coordinate." msgstr "Долни координати." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width" msgstr "Широчина" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width." msgstr "Широчина." #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height" msgstr "Ви�очина" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height." msgstr "Ви�очина." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Cursor speed." msgstr "Скоро�т на кур�ора." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Scale" msgstr "Мащабиране" #: lib/logitech_receiver/settings_templates.py:1358 msgid "Gestures" msgstr "Же�тове" #: lib/logitech_receiver/settings_templates.py:1359 msgid "Tweak the mouse/touchpad behaviour." msgstr "�а�тройка на поведението на мишка/тъчпад." #: lib/logitech_receiver/settings_templates.py:1375 msgid "Gestures Diversion" msgstr "Отклонение на Же�тове" #: lib/logitech_receiver/settings_templates.py:1376 msgid "Divert mouse/touchpad gestures." msgstr "Отклон�ване на же�тове на мишка/тъчпад." #: lib/logitech_receiver/settings_templates.py:1392 msgid "Gesture params" msgstr "Параметри на же�товете" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Пром�на на чи�лените параметри на мишка/тъчпад." #: lib/logitech_receiver/settings_templates.py:1417 msgid "M-Key LEDs" msgstr "M-клавиш Светодиоди" #: lib/logitech_receiver/settings_templates.py:1419 msgid "Control the M-Key LEDs." msgstr "Контрол на M-клавиш Светодиоди." #: lib/logitech_receiver/settings_templates.py:1423 lib/logitech_receiver/settings_templates.py:1454 msgid "May need G Keys diverted to be effective." msgstr "Възможно е да има нужда от отклон�ване на G-клавиш за ефективно�т." #: lib/logitech_receiver/settings_templates.py:1429 #, python-format msgid "Lights up the %s key." msgstr "О�вет�ване на %s клавиш." #: lib/logitech_receiver/settings_templates.py:1448 msgid "MR-Key LED" msgstr "MR-клавиш Светодиод" #: lib/logitech_receiver/settings_templates.py:1450 msgid "Control the MR-Key LED." msgstr "Контрол на MR-клавиш Светодиод." #: lib/logitech_receiver/settings_templates.py:1471 msgid "Persistent Key/Button Mapping" msgstr "При�ъ�твие на Пренареждане на клавиш/бутон" #: lib/logitech_receiver/settings_templates.py:1473 msgid "Permanently change the mapping for the key or button." msgstr "Перманентна пром�на на пренареждане за клавиш или бутон." #: lib/logitech_receiver/settings_templates.py:1475 msgid "" "Changing important keys or buttons (such as for the left mouse button) can result in an unusable " "system." msgstr "" "Пром�на на важни клавиши или бутони ( например леви�т бутон на мишката ) може да доведе до " "неизползваема �и�тема." #: lib/logitech_receiver/settings_templates.py:1532 msgid "Sidetone" msgstr "Страничен камък" #: lib/logitech_receiver/settings_templates.py:1533 msgid "Set sidetone level." msgstr "Задаване на ниво на �траничен камък." #: lib/logitech_receiver/settings_templates.py:1542 msgid "Equalizer" msgstr "Еквалайзер (Изравнител)" #: lib/logitech_receiver/settings_templates.py:1543 msgid "Set equalizer levels." msgstr "Задаване на нива за еквалайзер (изравнител)." #: lib/logitech_receiver/settings_templates.py:1565 msgid "Hz" msgstr "Херц" #: lib/logitech_receiver/settings_templates.py:1571 msgid "Power Management" msgstr "Управление на Мощно�тта" #: lib/logitech_receiver/settings_templates.py:1572 msgid "Power off in minutes (0 for never)." msgstr "Изключване �лед минути (0 за никога)." #: lib/logitech_receiver/settings_templates.py:1584 msgid "Brightness Control" msgstr "Контрол на О�ветено�т" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Control overall brightness" msgstr "Контрол на обща о�ветено�т" #: lib/logitech_receiver/settings_templates.py:1628 lib/logitech_receiver/settings_templates.py:1681 msgid "LED Control" msgstr "Светодиоден Контрол" #: lib/logitech_receiver/settings_templates.py:1629 lib/logitech_receiver/settings_templates.py:1682 msgid "Switch control of LED zones between device and Solaar" msgstr "Превключване контрола на �ветодиодните зони между у�трой�тво и Solaar" #: lib/logitech_receiver/settings_templates.py:1644 lib/logitech_receiver/settings_templates.py:1692 msgid "LED Zone Effects" msgstr "Ефекти за Светодиодни Зони" #: lib/logitech_receiver/settings_templates.py:1645 lib/logitech_receiver/settings_templates.py:1693 msgid "LED Control needs to be set to Solaar to be effective." msgstr "�ужно е контрола на �ветодиодите да бъде зададен от Solaar за да бъде ефективно." #: lib/logitech_receiver/settings_templates.py:1645 lib/logitech_receiver/settings_templates.py:1693 msgid "Set effect for LED Zone" msgstr "Задаване на ефект на �ветодиодни зони" #: lib/logitech_receiver/settings_templates.py:1647 msgid "Color" msgstr "Цв�т" #: lib/logitech_receiver/settings_templates.py:1648 msgid "Speed" msgstr "Скоро�т" #: lib/logitech_receiver/settings_templates.py:1649 msgid "Period" msgstr "Период" #: lib/logitech_receiver/settings_templates.py:1650 msgid "Intensity" msgstr "Интензитет" #: lib/logitech_receiver/settings_templates.py:1651 msgid "Ramp" msgstr "Ограничение" #: lib/logitech_receiver/settings_templates.py:1666 msgid "LEDs" msgstr "Светодиоди" #: lib/logitech_receiver/settings_templates.py:1703 msgid "Per-key Lighting" msgstr "О�вет�ване �поред клавиш" #: lib/logitech_receiver/settings_templates.py:1704 msgid "Control per-key lighting." msgstr "Контрол на о�вет�ване �поред клавиш." #: lib/logitech_receiver/settings_templates.py:1786 msgid "Force Sensing Buttons" msgstr "Чув�твително�т към Сила на бутони" #: lib/logitech_receiver/settings_templates.py:1787 msgid "Change the force required to activate button." msgstr "Пром�на на �илата необходима за активиране на бутон." #: lib/logitech_receiver/settings_templates.py:1804 msgid "Force Sensing Button" msgstr "Чув�твително�т на �ила на Бутон" #: lib/logitech_receiver/settings_templates.py:1814 msgid "Haptic Feedback Level" msgstr "�иво на Обратна връзка" #: lib/logitech_receiver/settings_templates.py:1815 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "Пром�на на мощно�тта на обратната връзка. (нула за изключване.)" #: lib/logitech_receiver/settings_templates.py:1857 msgid "Play Haptic Waveform" msgstr "Форма на вълната на обратната връзка" #: lib/logitech_receiver/settings_templates.py:1858 msgid "Tell device to play a haptic waveform." msgstr "Команда към у�трой�тво да възпроизведе обратна връзка." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "Друго подпроце� на Solaar е �тартира, за това про�то използвайте негови� прозорец" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Управл�ва Logitech приемници,\n" "клавиатури, мишки и таблети." #: lib/solaar/ui/about/model.py:64 msgid "Additional Programming" msgstr "Допълнително Програмиране" #: lib/solaar/ui/about/model.py:65 msgid "GUI design" msgstr "Дизай на графичен интерфей�" #: lib/solaar/ui/about/model.py:67 msgid "Testing" msgstr "Те�тване" #: lib/solaar/ui/about/model.py:75 msgid "Logitech documentation" msgstr "Logitech документаци�" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Раз�дво�ване" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "Отказ" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Грешка в правата" #: lib/solaar/ui/common.py:44 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have permission to open it." msgstr "Открит е Logitech приемник или у�трой�тво (%s), но н�мате права да го отворите." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device and then reconnecting it." msgstr "" "�ко Solaar е ново ин�талиран, опитайте да премахнете приемника или у�трой�твото и �лед това да го " "включите отново." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Грешка! �е може да �е о�ъще�тви �вързване � у�трой�тво" #: lib/solaar/ui/common.py:51 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error connecting to it." msgstr "Открит е Logitech приемник или у�трой�тво %s, но възникна грешка при �вързването." #: lib/solaar/ui/common.py:53 msgid "Try disconnecting the device and then reconnecting it or turning it off and then on." msgstr "Опитайте да разкачите и включите у�трой�твото от USB-то или от �амото у�трой�тво." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "�еу�пешно раз�дво�ване" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "�еу�пех при раз�дво�ването %{device} от %{receiver}." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Приемникът връща грешка, без допълнителни детайли." #: lib/solaar/ui/config_panel.py:245 msgid "Complete - ENTER to change" msgstr "Готово - Влезте за пром�на" #: lib/solaar/ui/config_panel.py:245 msgid "Incomplete" msgstr "�едовършено" #: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d �тойно�т" msgstr[1] "%d �тойно�т" #: lib/solaar/ui/config_panel.py:642 msgid "Changes allowed" msgstr "Промените �а разрешени" #: lib/solaar/ui/config_panel.py:643 msgid "No changes allowed" msgstr "Промените �а забранени" #: lib/solaar/ui/config_panel.py:644 msgid "Ignore this setting" msgstr "Игнориране на тази на�тройка" #: lib/solaar/ui/config_panel.py:690 msgid "Working" msgstr "Работа" #: lib/solaar/ui/config_panel.py:693 msgid "Read/write operation failed." msgstr "Read/write неу�пешна операци�." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "неопределена причина" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "Вградени правила" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "Правила дефинирани от потребител�" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "Правило" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "Под-правило" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "(празно)" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "Да направ� ли промените по�то�нни ?" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "Да" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "�е" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "�ко изберете �е, промените ще бъдат загубени и Solaar затворен." #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "По�тавете тук" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "По�тавете отгоре" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "По�тавете отдолу" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "По�тавете правило тук" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "По�тавете правило отгоре" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "По�тавете правило отдолу" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "По�тавете правило" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "Вмъкнете тук" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "Вмъкнете отгоре" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "Вмъкнете отдолу" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "Вмъкнете ново правило тук" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "Вмъкнете ново правило отгоре" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "Вмъкнете ново правило отдолу" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "Заравнен" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "Вмъкнете" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "Или" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "И" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "Съ�то�ние" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Функци�" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Рапорт" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Проце�" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "Проце� на мишка" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Мидификатори" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Клавиш" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "�ати�нат клавиш" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "�ктивен" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "У�трой�тво" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "Хо�т" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "�а�тройки" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "Те�т" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Те�т битове" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Же�т � мишка" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "Дей�твие" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "�ати�кане клавиш" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Скрол на мишка" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Клик на мишка" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "Задаване" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "Изпълнение" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "По-къ�но" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "Вмъкнете ново правило" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Изтриване" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "Отричане" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "Ограждане �" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "Изр�зване" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "По�тав�не" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "Копиране" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "Solaar Редактор на правила" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "Запазване на промените" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "Отхвърл�не на промените" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "Този редактор не поддържа в�е още този компонент." #: lib/solaar/ui/diversion_rules.py:1169 msgid "Number of seconds to delay. Delay between 0 and 1 is done with higher precision." msgstr "" "Стойно�т в �екунди за закъ�нение. Закъ�нение между 0 и 1 �е изпълн�ва � по-гол�ма прецизно�т." #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "�е" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "Пром�на �ъ�то�ние" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "В�рно" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "Грешно" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "�еподдържана на�тройка" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "Ориентаци� на у�трой�тво" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "У�трой�твото е активно и на�тройката му може да бъде променена." #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "У�трой�твото от което произлиза текущото изве�тие." #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "Има на хо�т компютъра." #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "Стойно�т" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "�ртикул" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "Пром�на на на�тройки за у�трой�тво" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "�а�тройване на у�трой�тво" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: �дво�ване на ново у�трой�тво" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt приемниците �а �ъвме�тими �амо � Bolt у�трой�тва." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "�ати�нете бутона за �дво�ване докато �ветлинни� индикатор започне да премигва бързо." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Unifyng приемниците �а �ъвме�тими �амо � Unifying у�трой�тва." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "Други приемници �а �ъвме�тими � н�колко у�трой�ва." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "За повечето у�трой�тва, включете у�трой�твото което и�кате да �двоите." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "�ко у�трой�твото е вече включено, изключете го и го включете отново." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "У�трой�твото не бива да е �двоено � включен приемник наоколо." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for the channel you wish " "to pair\n" "or use the channel switch button to select a channel and then press, hold, and release the channel " "switch button." msgstr "" "За у�трой�тва � повече от един канал, нати�нете, задръжте и пу�ната бутона за избор на каналите, " "на у�трой�твото което желаете да �двоите\n" "или използвайте бутона за каналите за да изберете канал, �лед това нати�нете, задръжте и пу�нене " "бутона." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Индикаторът за каналите тр�бва да мига бързо." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Този приемник има %d възможни �дво�вани�." msgstr[1] "" "\n" "\n" "Този приемник има %d възможни �дво�вани�." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Отказ в този момент, н�ма да изразходи �дво�ване." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Въведете парола за %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Въведете %(passcode)s и нати�нете клавиш enter." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "л�во" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "д��но" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "�ати�нете %(code)s\n" "и нати�нете леви� и де�ни� бутан едновременно." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "Безжичната връзка не е криптирана" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Открито е ново у�трой�тво:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "�еу�пешно �дво�ване" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "Уверете �е че у�трой�твото ви е в рамките на обхвата и има добър зар�д на батери�та." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "Открито е ново у�трой�тво, но не е �ъвме�тимо � този приемник." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "Бро� �двоени у�трой�тва надхвърл� лимита на приемника." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "��ма повече налични детайи, за тази грешка." #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Симулиране на клик на кабелен клавиш или нати�кане или пу�кане.\n" "В Wayland �а нужни права за запи� в /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Добави клавиш" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Клик" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "�ати�кане" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Отпу�кане" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "Симулиране на �крол на мишка. В Wayland �а нужни права за запи� в /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Симулиране на клик на мишка\n" "В Wayland �а нужни права за запи� в /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Бутон" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Дей�твие ( и броене, ако кликне)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Изоълнение на команда � аргументи." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Добавиете аргумент" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "X11 активен проце�. Само за използване в X11." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "Х11 проце� мишка. Само за използване в Х11." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "Проце� мишка" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "Обработка на име на функци�та �тартираща правило." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "Рапорт за бро� на изве�ти�та, активиращи обработка на правилата." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "�ктивни модификатори на клавиатура. �е винаги �а възможни в Wayland." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons." msgstr "" "Отклонен клавиш или нати�нат или о�вободен бутон.\n" "Използвайте на�тройката за отклон�ване на клавиш/бутон и отклон�ването на клавиш-G за да отклоните " "клавиши или бутони." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Клавиш долу" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Клавиш горе" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons." msgstr "" "Отклонен клавиш или бутон пона�то�щем е долу.\n" "Използвайте на�тройката за отклон�ване на клавиш/бутон и отклон�ването на клавиш-G за да отклоните " "клавиши или бутони." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "Те�т на �ъ�то�нието на изве�тие активиращо правило за обработка." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Параметър" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "начало (включително)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "край (изключаещо)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "обхват" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "минимум" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "мак�имум" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "байтове от %(0)d до %(1)d, обхващащи от %(2)d до %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "ма�ка" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "байтове от %(0)d от %(1)d, ма�ка %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "Bit or range test on bytes in notification message triggering rule processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "тип" #: lib/solaar/ui/rule_conditions.py:535 msgid "Mouse gesture with optional initiating button followed by zero or more mouse movements." msgstr "Же�т на мишката � опционално инициращ бутон по�ледвано от нола или повече движени� на мишка." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Добав�не движение" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Открито е непотдържано у�трой�тво" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "Отно�но %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Спиране на „%s“" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "н�ма приемник" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 lib/solaar/ui/window.py:728 msgid "offline" msgstr "офлайн" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "без �тату�" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Сканиране" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Батери�" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Безжична връзка" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "О�ветление" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Покажи Техниче�ки Детайли" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Сдво�ване на ново у�трой�тво" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Избор на у�трой�тво" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Редактор за правила" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Път" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "USB идентификатор" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 lib/solaar/ui/window.py:544 #: lib/solaar/ui/window.py:546 msgid "Serial" msgstr "Сериен номер" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "Индек�" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "Безжичен PID" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "Идентификатор на продукта" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "Протокол" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "�еизве�тно" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "Идентификатор на единица(unit)" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "н�ма" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "Изве�ти�" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "��ма �двоено у�трой�тво." #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "С този приемник могат да бъдат �двоени %(max_count)s у�трой�тва." msgstr[1] "С този приемник могат да бъдат �двоени %(max_count)s у�трой�тва." #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "Само едно у�трой�тво може да бъде �двоено � този приемник." #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "О�тават %d �дво�вани� � този приемник." msgstr[1] "О�тават %d �дво�вани� � този приемник." #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "Волтаж на батери�" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "Волтаж рапортуван от батери�та" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "�иво на батери�та" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "Приблизително ниво рапортувано от батери�та" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "�ледващ рапортуван " #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr " Очаква �е �ледващ рапорт за ниво." #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "по�ледно изве�тно" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "криптирано" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Безжичната връ�ка между това у�трой�тво и негови�т приемник е криптирана." #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "не криптирано" #: lib/solaar/ui/window.py:721 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue for text-input devices." msgstr "" "Безжичната връзка между това у�трой�тво и негови�т приемник не е криптирана\n" "Това е �ериозна заплаха за �игурно�тта за кур�орни у�трой�тва и гол�ма заплаха за �игурно�тта на " "тек�тово-въвеждащи у�трой�тва." #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "" Solaar-1.1.20/po/ca.po000066400000000000000000001571271522022367600143770ustar00rootroot00000000000000# Catalan translations for Solaar package. # Copyright (C) 2021 THE Solaar's COPYRIGHT HOLDER. # This file is distributed under the same license as the Solaar package. # Marc Serra , 2021. # msgid "" msgstr "Project-Id-Version: solaar 0.9.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2021-10-22 19:19+0200\n" "Last-Translator: \n" "Language-Team: none\n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.3\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "Receptor Unifying" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "Receptor Nano" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "Receptor Lightspeed" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "Receptor EX100 27 Mhz" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "buida" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "crítica" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "baixa" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "mitja" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "bona" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "plena" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "descarregant" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "recarregant" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "carregant" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "no carregant" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "quasi plena" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "carregant" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "recàrrega lenta" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "bateria no vàlida" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "error tèrmic" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "error" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "estàndard" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "ràpid" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "lent" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "temps exhaurit pel dispositiu" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "dispositiu no suportat" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "masses dispositius" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "temps de seqüència exhaurit" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Gestor d'arrencada" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Altres" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "Botó Esquerra" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "Botó Dret" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "Botó Central" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "Botó Endarrere" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "Botó Endavant" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "Botó Gestos Ratolí" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "Canvi intel·ligent" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "Selector DPI" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "Inclinació a l'Esquerra" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "Inclinació a la Dreta" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "Clic Esquerra" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "Clic Dreta" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "Clic Central Ratolí" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "Clic Endarrere Ratolí" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "Clik Endavant Ratolí" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "Navegació amb el Botó de Gestos" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "Botó Scroll a l'esquerra" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "Botó Scroll a la dreta" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "pressionat" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "alliberat" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "el bloqueig de vinculació està tancat" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "el bloqueig de vinculació està obert" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "connectat" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "desconnectat" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "desvinculat" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "alimentat" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "registrar" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "característica" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Intercanviar funció Fx" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Al activar-se, les tecles F1..F12 activaran les seves funcions " "especials,\n" "i s'ha de mantenir pressionada la tecla FN per activar la seva " "funció estàndard." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Al desactivar-se, les tecles F1..F12 activaran les seves funcions " "estàndard,\n" "i s'ha de mantenir pressionada la tecla FN per activar la seva " "funció especial." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Detecció de mans" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Encendra la i·il·luminació quan les mans passin pel damunt el teclat." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "Suavitat Scroll Rodeta" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Mode d'alta sensibilitat per l'scroll vertical amb la rodeta." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Scroll Lateral" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Al desactivar-se, pressionar la rodeta lateralment envia " "esdeveniments de botons personalitzats\n" "en lloc dels esdeveniments estàndard d'scroll lateral." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "Sensibilitat del moviment del ratolí" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Retroiluminació" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "Encendre o apagar la il·luminació del teclat." #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "Rodeta d'Alta Resolució" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "Desviar Rodeta" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "Direcció Desplaçament Rodeta" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "Invertir direcció del desplaçament vertical amb la rodeta." #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "Resolució Rodeta Desplaçament" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Sensibilitat (Velocitat del punter)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Multiplicador de velocitat pel ratolí (256 és un multiplicador " "normal)" #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "Desviament de la Rodeta del Polze" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "Direcció de la Rodeta del Polze" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "Invertir la direcció de desplaçament de la rodeta del polze." #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "Taxa de Sondeig (ms)" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "Freqüència de sondeig del dispositiu, en milisegons" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "Desviar esdeveniments de la corona" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Fer que la corona enviï notificacions de CROWN HID ++ (que activen " "les regles de Solaar, del contrari s'ignoren)." #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "Desviar Tecles G" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Fer que les tecles G enviïn notificacions GKEY HID ++ (que activen " "les regles de Solaar, del contrari, s'ignoren)." #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "Accions de Tecla/Botó" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Canviar l'acció per la tecla o botó." #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "Canviar accions importants (per exemple el botó esquerra del ratolí) " "pot deixar el sistema inservible." #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "Desviament de Tecla/Botó" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "Desviat" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "Gestos de Ratolí" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "Normal" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Sensibilitat (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "Off" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Desactivar tecles" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Desactivar tecles específiques del teclat." #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "Desactiva la tecla %s." #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Especificar S.O." #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Canviar tecles per coincidir amb el S.O." #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Canviar Host" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Canviar connexió a un host diferent" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "Realitza un clic esquerra." #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "Un toc" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "Realitza un clic dret." #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "Un toc amb dos dits" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "Un toc amb tres dits" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "Doble toc" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "Realitza un clic doble." #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "Doble toc amb dos dits" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "Doble toc amb tres dits" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "Arrossega elements arrossegant el dit després de tocar dues vegades." #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "Tocar i arrossegar" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "Arrossega elements arrossegant els dits després de tocar dues " "vegades." #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "Tocar i arrossegar amb dos dits" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "Tocar i arrossegar amb tres dits" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Desactiva els gestos de toc i marge (equivalent a pressionar " "FN+LeftClick)." #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "Elimina els gestos de toc i marge" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "Desplaça amb un dit" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "Desplaçament." #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "Desplaça amb dos dits" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "Desplaça horitzontalment amb dos dits" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "Desplaça horitzontalment." #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "Desplaçar verticalment amb dos dits" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "Desplaça verticalment." #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "Invertir la direcció de desplaçament." #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "Desplaçament natural" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "Activa la rodeta del polze." #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "Rodeta del polze" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "Lliscar des del marge superior" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "Lliscar des del marge esquerra" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "Lliscar des del marge dret" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "Lliscar des del marge inferior" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "Lliscar dos dits des del marge esquerra" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "Lliscar dos dits des del marge dret" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "Lliscar dos dits des del marge inferior" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "Lliscar dos dits des del marge superior" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "Pessigar per allunyar; Expandir per acostar." #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "Zoom amb dos dits." #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "Pessigar per allunyar." #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "Expandir per acostar." #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "Zoom amb tres dits." #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "Zoom amb dos dits" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "Zona de píxels" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "Zona de relació" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Factor d'escalat" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "Estableix la velocitat del cursor." #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "Esquerra" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "Coordenada més a la esquerra." #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Amplada" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "Amplada." #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Alçada" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "Alçada." #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "Velocitat del cursor." #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "Escala" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gestos" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "Modificar el comportament del ratolí/panell tàctil." #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "Paràmetres de gestos" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Canviar paràmetres numèrics de un ratolí/panell tàctil." #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Cap dispositiu connectat." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s dispositiu vinculat." msgstr[1] "%(count)s dispositius vinculats." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Bateria: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Bateria: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Il·luminació: %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Bateria: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Bateria: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Error de permisos" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "Error al connectar al dispositiu" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "S'ha trobat un receptor o dispositiu Logitech a %s, però s'ha " "produït un error al connectar-se." #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Ha fallat la desvinculació" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Error al desvincular %{device} de %{receiver}." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "El receptor ha tornat un error, sense detalls addicionals." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "Gestiona receptors Logitech,\n" "teclats, ratolins i tauletes." #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "Programació addicional" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "Disseny de la interfície gràfica" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Provant" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Documentació de Logitech" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Desvincular" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "Cancel·lar" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d valor" msgstr[1] "%d valors" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "Canvis permesos" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "Canvis no permesos" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "Ignorar aquesta opció" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Funcionant" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Ha fallat l'operació de lectura/escriptura." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "Regles integrades" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "Regles definides per l'usuari" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "Regla" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "Sub-regla" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[buit]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Editor de Regles Solaar" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "¿Fer els canvis permanents?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Si�" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "No" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Si escull No, els canvis es perdran quan es tanqui Solaar." #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "Guardar canvis" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "Descartar canvis" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "Inserir aquí" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "Inserir a dalt" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "Inserir a baix" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "Inserir nova regla aquí" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "Inserir nova regla a dalt" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "Inserir nova regla a baix" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "Enganxar aquí" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "Enganxar a dalt" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "Enganxar a baix" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "Enganxar regla aquí" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "Enganxar regla a dalt" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "Enganxar regla a baix" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "Enganxar regla" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "Aplanar" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "Insertar" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "O" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "I" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "Condició" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "Característica" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "Informar" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Procés" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "Modificadors" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "Tecla" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Actiu" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "Gest de Ratolí" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Accio�" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "Pulsació de tecla" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "Desplaçament rodeta del ratolí" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "Clic del ratolí" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "Executar" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "Afegir nova regla" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "Esborrar" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "Negar" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "Embolicar amb" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Tallar" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Enganxar" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Copiar" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "Aquest editor encara no és compatible amb el component de regla " "seleccionat." #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "" #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "No" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "ProcésRatolí" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "Tecla avall" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "Tecla amunt" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "Afegir tecla" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "Botó" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "Afegir argument" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Valor" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "desconectat" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: vincular nou dispositiu" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "" #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Ha falla la vinculació" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Asseguri's que el seu dispositiu estigui dins l'abast del receptor i " "que la bateria tingui suficient càrrega." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "S'ha detectat un nou dispositiu, però no és compatible amb aquest " "receptor." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "Més dispositius emparellats de els que admet el receptor." #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "No hi ha més detalls disponibles sobre aquest error." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "S'ha trobat un nou dispositiu:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "La connexió sense fils no és xifrada" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Engegui el dispositiu que vol vincular." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "Si el dispositiu ja està encès, apagui'l i torni'l a encendre." #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "Aquest receptor té %d aparellament restant." msgstr[1] "\n" "\n" "Aquest receptor té %d aparellaments restants." #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Si cancel·la en aquest punt no es farà servir un aparellament." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "Sobre %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Sortir %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "sense receptor" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "sense estat" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Explorant" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Bateria" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Enllaç sense fils" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Il·luminació" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Mostrar detalls tècnics" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Vincular nou dispositiu" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Seleccionar un dispositiu" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "Editor de Regles" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Ruta" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "ID USB" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Serial" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "�ndex" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "PID sense fils" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "ID del producte" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protocol" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Desconegut" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Taxa de sondeig" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "ID Unitat" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "cap" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Notificacions" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "No hi ha dispositius vinculats." #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Es pot vincular fins a %(max_count)s dispositiu a aquest " "receptor." msgstr[1] "Es pot vincular fins a %(max_count)s dispositius a aquest " "receptor." #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "Només es pot vincular un dispositiu a aquest receptor." #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Aquest receptor té %d aparellament restant." msgstr[1] "Aquest receptor té %d aparellaments restants." #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "Voltatge de la bateria" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "Voltatge informat per la bateria" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "Nivell de Bateria" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "Nivell aproximat informat per la bateria" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "següent informe " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " i següent nivell que serà informat." #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "últim conegut" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "xifrat" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "La connexió sense fils entre el dispositiu i el seu receptor està " "xifrada." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "no xifrat" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "\n" #~ "\n" #~ "This receiver has %d pairing(s) remaining." #~ msgstr "\n" #~ "\n" #~ "Aquest receptor té %d aparellament(s) disponibles." #~ msgid "%(battery_level)s" #~ msgstr "%(battery_level)s" #~ msgid "%(battery_percent)d%%" #~ msgstr "%(battery_percent)d%%" #~ msgid "Add action" #~ msgstr "Afegir acció" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the button down." #~ msgstr "Ajustar els DPI lliscant el ratolí horitzontalment mentre es " #~ "manté el botó pressionat." #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always locked at 50" #~ msgstr "Canvia automàticament el mode de la rodeta del ratolí entre " #~ "bloquejat i gir lliure.\n" #~ "La rodeta del ratolí sempre està lliure a 0 i sempre bloquejat a 50" #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "Canviar automàticament la rodeta del ratolí entre el mode de " #~ "trinquet i el mode de gir lliure.\n" #~ "La rodeta del ratolí sempre està lliure a 0 i sempre amb trinquet a " #~ "50" #~ msgid "Battery information unknown." #~ msgstr "Informació de la bateria desconeguda." #~ msgid "Count" #~ msgstr "Conta" #~ msgid "DPI Sliding Adjustment" #~ msgstr "Ajustar DPI lliscant" #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Desactiva eficaçment el desplaçament amb el polze en Linux." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Desactiva eficaçment l'scroll de la rodeta amb Linux." #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "S'ha trobat receptor Logitech (%s), però no té permisos per " #~ "obrir-lo." #~ msgid "HID++ Scrolling" #~ msgstr "Desplaçament HID++" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "Mode HID++ per desplaçament horitzontal amb la rodeta del " #~ "polze." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "Mode HID++ pel desplaçament vertical amb la rodeta." #~ msgid "High Resolution Scrolling" #~ msgstr "Desplaçament d'alta resolució" #~ msgid "High Resolution Wheel Invert" #~ msgstr "Invertir rodeta a l'alta resolució " #~ msgid "High-sensitivity wheel invert mode for vertical scroll." #~ msgstr "Mode invers d'alta resolució a la rodeta per desplaçament " #~ "vertical." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Si el dispositiu ja està encès, apagui'l i torni'l a " #~ "encendre." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Si acaba d'instal·lar Solaar, intenta treure el receptor i " #~ "connectar-lo de nou." #~ msgid "Make the key or button send HID++ notifications (which " #~ "trigger Solaar rules but are otherwise ignored)." #~ msgstr "Fer que la tecla o el botó enviï notificacions HID ++ (que " #~ "activen les regles de Solaar, del contrari s'ignoren)." #~ msgid "No Logitech receiver found" #~ msgstr "No s'ha trobat cap receptor Logitech" #~ msgid "Scroll Wheel Rachet" #~ msgstr "Trinquet Rodeta Desplaçament" #~ msgid "Send a gesture by sliding the mouse while holding the button " #~ "down." #~ msgstr "Enviar un gest lliscant el ratolí mentre manté pressionat el " #~ "botó." #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Mostrar l'estat de dispositius connectats\n" #~ "mitjançant receptors sense fils Logitech." #~ msgid "Smooth Scrolling" #~ msgstr "Desplaçament suau" #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "El receptor només soporta %d dispositiu(s) aparellats(s)." #~ msgid "The receiver was unplugged." #~ msgstr "El receptor s'ha desconnectat." #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "La conexió inalámbrica entre el dispositiu i el receptor no " #~ "està cifrada.\n" #~ "\n" #~ "Per dispositius apuntadors (ratolins, trackballs, trackpads), aquest " #~ "és un problema menor de seguretat.\n" #~ "\n" #~ "Tot i això, per dispositius d'entrada de text (teclats, teclats " #~ "numèrics) sí que és un problema greu,\n" #~ "doncs el text introduït pot ser capturat de forma inadvertida per " #~ "tercers que estiguin aprop." #~ msgid "This receiver has %d pairing(s) remaining." #~ msgstr "Este receptor té %d aparellament(s) disponibles." #~ msgid "Top-most coordinate." #~ msgstr "Coordenada superior." #~ msgid "Try removing the device and plugging it back in or turning " #~ "it off and then on." #~ msgstr "Intenti treure el dispositiu i tornar a endollar-lo o apagar-" #~ "lo i encendre'l." #~ msgid "USB id" #~ msgstr "id USB" #~ msgid "Wheel Resolution" #~ msgstr "Resolució de la rodeta" #~ msgid "height" #~ msgstr "alçada" #~ msgid "top" #~ msgstr "superior" #~ msgid "unknown" #~ msgstr "desconegut" #~ msgid "width" #~ msgstr "amplada" Solaar-1.1.20/po/cs.po000066400000000000000000002404651522022367600144170ustar00rootroot00000000000000# Czech translations for solaar package. # Copyright (C) 2020 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # # Automatically generated, 2020. # SPDX-FileCopyrightText: 2020, 2026 Marián Kyral msgid "" msgstr "" "Project-Id-Version: solaar 1.0.4\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-05-22 18:55+0200\n" "PO-Revision-Date: 2026-05-22 19:15+0200\n" "Last-Translator: Marián Kyral \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Lokalize 26.04.1\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Přijíma� Bolt" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Přijíma� Unifying" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Přijíma� Nano" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Přijíma� Lightspeed" #: lib/logitech_receiver/base_usb.py:136 msgid "EX100 Receiver 27 Mhz" msgstr "Přijíma� EX100 27 Mhz" #: lib/logitech_receiver/common.py:698 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Baterie: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:701 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Baterie: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1189 lib/logitech_receiver/hidpp20.py:1222 #: lib/logitech_receiver/hidpp20.py:1250 msgid "Cycle" msgstr "Cyklické" #: lib/logitech_receiver/hidpp20.py:1190 msgid "Right" msgstr "Vpravo" #: lib/logitech_receiver/hidpp20.py:1191 msgid "Down" msgstr "Dolů" #: lib/logitech_receiver/hidpp20.py:1192 msgid "Center Out" msgstr "Ze středu" #: lib/logitech_receiver/hidpp20.py:1193 msgid "In" msgstr "Dovnitř" #: lib/logitech_receiver/hidpp20.py:1194 msgid "Out" msgstr "Ven" #: lib/logitech_receiver/hidpp20.py:1195 #: lib/logitech_receiver/settings_templates.py:1398 msgid "Left" msgstr "Vlevo" #: lib/logitech_receiver/hidpp20.py:1196 msgid "Up" msgstr "Nahoru" #: lib/logitech_receiver/hidpp20.py:1197 msgid "Center In" msgstr "Do středu" #: lib/logitech_receiver/hidpp20.py:1218 #: lib/logitech_receiver/settings_templates.py:344 msgid "Disabled" msgstr "Zakázáno" #: lib/logitech_receiver/hidpp20.py:1219 msgid "Static" msgstr "Statické" #: lib/logitech_receiver/hidpp20.py:1220 msgid "Pulse" msgstr "Pulzní" #: lib/logitech_receiver/hidpp20.py:1229 lib/logitech_receiver/hidpp20.py:1255 msgid "Wave" msgstr "Vlna" #: lib/logitech_receiver/hidpp20.py:1233 msgid "Boot" msgstr "Spuštění" #: lib/logitech_receiver/hidpp20.py:1234 msgid "Demo" msgstr "Ukázka" #: lib/logitech_receiver/hidpp20.py:1236 msgid "Breathe" msgstr "Dech" #: lib/logitech_receiver/hidpp20.py:1241 lib/logitech_receiver/hidpp20.py:1262 msgid "Ripple" msgstr "Vlnění" #: lib/logitech_receiver/hidpp20.py:1246 msgid "Decomposition" msgstr "Dekompozice" #: lib/logitech_receiver/hidpp20.py:1247 msgid "Signature1" msgstr "Podpis1" #: lib/logitech_receiver/hidpp20.py:1248 msgid "Signature2" msgstr "Podpis2" #: lib/logitech_receiver/hidpp20.py:1268 msgid "Dim" msgstr "Ztlumeno" #: lib/logitech_receiver/hidpp20.py:1340 msgid "Unknown Location" msgstr "Neznámé místo" #: lib/logitech_receiver/hidpp20.py:1341 #: lib/logitech_receiver/settings_templates.py:2619 #: lib/logitech_receiver/settings_templates.py:2907 #: lib/logitech_receiver/settings_templates.py:3647 msgid "Primary" msgstr "Primární" #: lib/logitech_receiver/hidpp20.py:1342 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:1343 msgid "Left Side" msgstr "Levá strana" #: lib/logitech_receiver/hidpp20.py:1344 msgid "Right Side" msgstr "Pravá strana" #: lib/logitech_receiver/hidpp20.py:1345 msgid "Combined" msgstr "Kombinováno" #: lib/logitech_receiver/hidpp20.py:1346 msgid "Primary 1" msgstr "Primární 1" #: lib/logitech_receiver/hidpp20.py:1347 msgid "Primary 2" msgstr "Primární 2" #: lib/logitech_receiver/hidpp20.py:1348 msgid "Primary 3" msgstr "Primární 3" #: lib/logitech_receiver/hidpp20.py:1349 msgid "Primary 4" msgstr "Primární 4" #: lib/logitech_receiver/hidpp20.py:1350 msgid "Primary 5" msgstr "Primární 5" #: lib/logitech_receiver/hidpp20.py:1351 msgid "Primary 6" msgstr "Primární 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "prázdná" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "kritická" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "nízká" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "průměrná" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "dobrá" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "plně nabito" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "vybíjení" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "nabíjení" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:706 msgid "charging" msgstr "nabíjení" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "nenabíjí" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "téměř nabito" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "nabito" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "pomalé nabíjení" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "nesprávná baterie" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "teplotní chyba" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "chyba" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "standard" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "rychle" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "pomalu" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "vypršel �asový limit zařízení" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "nepodporované zařízení" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "příliš mnoho zařízení" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "vypršel �asový limit sekvence" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:561 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Další" #: lib/logitech_receiver/i18n.py:59 #: lib/logitech_receiver/settings_templates.py:4336 msgid "Left Button" msgstr "Levé tla�ítko" #: lib/logitech_receiver/i18n.py:60 #: lib/logitech_receiver/settings_templates.py:4336 msgid "Right Button" msgstr "Pravé tla�ítko" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Prostřední tla�ítko" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Tla�ítko Zpět" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Tla�ítko Vpřed" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Tla�ítko Gesta myši" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Chytrý přepína�" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Přepína� DPI" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Levé naklonění" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Pravé naklonění" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Levý klik" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Pravý klik" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Prostřední tla�ítko myši" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Tla�ítko myši Zpět" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Tla�ítko myši Vpřed" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Tla�ítko navigace gesty" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Levé Rolovací tla�ítko myši" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Pravé Rolovací tla�ítko myši" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "stisknuto" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "uvolněno" #: lib/logitech_receiver/notifications.py:157 lib/solaar/listener.py:350 msgid "connected" msgstr "připojeno" #: lib/logitech_receiver/notifications.py:157 lib/solaar/listener.py:350 msgid "disconnected" msgstr "odpojeno" #: lib/logitech_receiver/notifications.py:183 msgid "unpaired" msgstr "nespárováno" #: lib/logitech_receiver/notifications.py:232 msgid "powered on" msgstr "zapnuto" #: lib/logitech_receiver/notifications.py:284 msgid "ADC measurement notification" msgstr "ADC měřící oznámení" #: lib/logitech_receiver/notifications.py:486 #: lib/logitech_receiver/notifications.py:542 msgid "pairing lock is closed" msgstr "zámek párování je uzamknut" #: lib/logitech_receiver/notifications.py:486 #: lib/logitech_receiver/notifications.py:542 msgid "pairing lock is open" msgstr "zámek párování je odemknut" #: lib/logitech_receiver/notifications.py:505 msgid "discovery lock is closed" msgstr "zámek vyhledávání je uzamknut" #: lib/logitech_receiver/notifications.py:505 msgid "discovery lock is open" msgstr "zámek vyhledávání je odemknut" #: lib/logitech_receiver/receiver.py:462 msgid "No paired devices." msgstr "Nespárované zařízení." #: lib/logitech_receiver/receiver.py:464 lib/solaar/ui/window.py:612 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s spárované zařízení." msgstr[1] "%(count)s spárovaná zařízení." msgstr[2] "%(count)s spárovaných zařízení." #: lib/logitech_receiver/settings.py:621 msgid "register" msgstr "registrace" #: lib/logitech_receiver/settings.py:635 lib/logitech_receiver/settings.py:673 msgid "feature" msgstr "vlastnost" #: lib/logitech_receiver/settings_templates.py:183 msgid "Swap Fx function" msgstr "Přepnout Fx funkci" #: lib/logitech_receiver/settings_templates.py:186 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Pokud je nastaveno, budou klávesy F1..F12 spouštět jejich speciální " "funkce\n" "a musíte držet Fn klávesu pro aktivaci jejich standardní funkce." #: lib/logitech_receiver/settings_templates.py:191 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Pokud není nastaveno, budou klávesy F1..F12 spouštět jejich " "standardní funkce\n" "a musíte držet Fn pro aktivaci jejich speciální funkce." #: lib/logitech_receiver/settings_templates.py:199 msgid "Hand Detection" msgstr "Detekce rukou" #: lib/logitech_receiver/settings_templates.py:200 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Zapne podsvícení pokud se ruce objeví nad klávesnicí." #: lib/logitech_receiver/settings_templates.py:207 msgid "Scroll Wheel Smooth Scrolling" msgstr "Plynulý posuv kole�ka" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:455 #: lib/logitech_receiver/settings_templates.py:484 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Vysoce citlivý režim svislého posuvu kole�kem." #: lib/logitech_receiver/settings_templates.py:215 msgid "Side Scrolling" msgstr "Bo�ní posun" #: lib/logitech_receiver/settings_templates.py:217 msgid "" "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "" "Pokud je zakázáno, bo�ní stla�ení kole�ka pošle vlastní události " "tla�ítek\n" "místo standardních událostí bo�ního posuvu." #: lib/logitech_receiver/settings_templates.py:227 msgid "Sensitivity (DPI - older mice)" msgstr "Citlivost (DPI - starší myši)" #: lib/logitech_receiver/settings_templates.py:228 #: lib/logitech_receiver/settings_templates.py:1064 #: lib/logitech_receiver/settings_templates.py:1092 msgid "Mouse movement sensitivity" msgstr "Citlivost pohybu myši" #: lib/logitech_receiver/settings_templates.py:301 msgid "Backlight Timed" msgstr "Doba podsvícení" #: lib/logitech_receiver/settings_templates.py:302 #: lib/logitech_receiver/settings_templates.py:442 msgid "Set illumination time for keyboard." msgstr "Nastavit dobu podsvícení klávesnice." #: lib/logitech_receiver/settings_templates.py:313 msgid "Backlight" msgstr "Podsvícení" #: lib/logitech_receiver/settings_templates.py:314 msgid "" "Illumination level on keyboard. Changes made are only applied in " "Manual mode." msgstr "" "Úroveň osvětlení kláves. Změny jsou aplikovány pouze v manuálním " "režimu." #: lib/logitech_receiver/settings_templates.py:346 msgid "Automatic" msgstr "Automatický" #: lib/logitech_receiver/settings_templates.py:348 msgid "Manual" msgstr "Manuální" #: lib/logitech_receiver/settings_templates.py:350 msgid "Enabled" msgstr "Zapnuto" #: lib/logitech_receiver/settings_templates.py:356 msgid "Backlight Level" msgstr "Úroveň podsvícení" #: lib/logitech_receiver/settings_templates.py:357 msgid "Illumination level on keyboard when in Manual mode." msgstr "Úroveň podsvícení klávesnice v manuálním režimu." #: lib/logitech_receiver/settings_templates.py:414 msgid "Backlight Delay Hands Out" msgstr "Zpoždění vypnutí podsvícení" #: lib/logitech_receiver/settings_templates.py:415 msgid "" "Delay in seconds until backlight fades out with hands away from " "keyboard." msgstr "" "Zpoždění v sekundách, po kterém se podsvícení zhasne, pokud ruce " "opustí prostor klávesnice." #: lib/logitech_receiver/settings_templates.py:423 msgid "Backlight Delay Hands In" msgstr "Zpoždění zapnutí podsvícení" #: lib/logitech_receiver/settings_templates.py:424 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Zpoždění v sekundách, po kterém se podsvícení zhasne, když jsou ruce " "přiblíží klávesnice." #: lib/logitech_receiver/settings_templates.py:432 msgid "Backlight Delay Powered" msgstr "Zpoždění podsvícení při napájení" #: lib/logitech_receiver/settings_templates.py:433 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Zpoždění v sekundách, po kterém podsvícení při napájení z externího " "zdroje postupně zhasne." #: lib/logitech_receiver/settings_templates.py:441 msgid "Backlight (Seconds)" msgstr "Podsvíceni (sekundy)" #: lib/logitech_receiver/settings_templates.py:453 msgid "Scroll Wheel High Resolution" msgstr "Vysoké rozlišení posuvného kole�ka" #: lib/logitech_receiver/settings_templates.py:457 #: lib/logitech_receiver/settings_templates.py:486 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Nastavte na ignorovat pokud je rolování nezvykle rychle nebo pomalé" #: lib/logitech_receiver/settings_templates.py:464 #: lib/logitech_receiver/settings_templates.py:495 msgid "Scroll Wheel Diversion" msgstr "Odklonění rolovacího kole�ka" #: lib/logitech_receiver/settings_templates.py:466 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" "Nastaví rolovací kole�ko aby posílalo LOWRES_WHEEL HID++ oznámení " "(které spustí Solaar pravidla, ale jinak je ignorováno)." #: lib/logitech_receiver/settings_templates.py:473 msgid "Scroll Wheel Direction" msgstr "Směr kole�ka" #: lib/logitech_receiver/settings_templates.py:474 msgid "Invert direction for vertical scroll with wheel." msgstr "Mění směr svislého otá�ení kole�ka." #: lib/logitech_receiver/settings_templates.py:482 msgid "Scroll Wheel Resolution" msgstr "Rozlišení kole�ka" #: lib/logitech_receiver/settings_templates.py:497 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" "Nastaví rolovací kole�ko aby posílalo HIRES_WHEEL HID++ oznámení " "(které spustí Solaar pravidla, ale jinak je ignorováno)." #: lib/logitech_receiver/settings_templates.py:506 msgid "Sensitivity (Pointer Speed)" msgstr "Citlivost (rychlost kurzoru)" #: lib/logitech_receiver/settings_templates.py:507 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Rychlostní násobitel myši (256 je běžný násobitel)." #: lib/logitech_receiver/settings_templates.py:517 msgid "Thumb Wheel Diversion" msgstr "Odklonění kole�ka palce" #: lib/logitech_receiver/settings_templates.py:519 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Nastaví kole�ko palce aby posílalo THUMB_WHEEL HID++ oznámení (které " "spustí Solaar pravidla, ale jinak je ignorováno)." #: lib/logitech_receiver/settings_templates.py:528 msgid "Thumb Wheel Direction" msgstr "Směr kole�ka palce" #: lib/logitech_receiver/settings_templates.py:529 msgid "Invert thumb wheel scroll direction." msgstr "Mění směr otá�ení kole�ka palce." #: lib/logitech_receiver/settings_templates.py:549 msgid "Onboard Profiles" msgstr "Vestavěné profily" #: lib/logitech_receiver/settings_templates.py:550 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, " "and button actions" msgstr "" "Povolit vestavěný profil který nastavuje �etnost hlášením, citlivost " "a akce tla�ítek" #: lib/logitech_receiver/settings_templates.py:594 #: lib/logitech_receiver/settings_templates.py:627 msgid "Report Rate" msgstr "Četnost hlášení" #: lib/logitech_receiver/settings_templates.py:596 #: lib/logitech_receiver/settings_templates.py:629 msgid "Frequency of device movement reports" msgstr "Frekvence hlášení pohybu zařízení" #: lib/logitech_receiver/settings_templates.py:596 #: lib/logitech_receiver/settings_templates.py:629 #: lib/logitech_receiver/settings_templates.py:1064 #: lib/logitech_receiver/settings_templates.py:1092 #: lib/logitech_receiver/settings_templates.py:1471 #: lib/logitech_receiver/settings_templates.py:1502 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "Může vyžadovat deaktivaci Vestavěných profilů aby se změna projevila." #: lib/logitech_receiver/settings_templates.py:657 msgid "Divert crown events" msgstr "Odklonění událostí korunky" #: lib/logitech_receiver/settings_templates.py:658 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Korunka bude zasílat CROWN HID++ oznámení (která spustí Solaar " "pravidla, ale jinak budou ignorována)." #: lib/logitech_receiver/settings_templates.py:666 msgid "Crown smooth scroll" msgstr "Plynulý posun korunky" #: lib/logitech_receiver/settings_templates.py:667 msgid "Set crown smooth scroll" msgstr "Nastaví plynulý posun korunky" #: lib/logitech_receiver/settings_templates.py:675 msgid "Divert G and M Keys" msgstr "Odklonění G a M kláves" #: lib/logitech_receiver/settings_templates.py:676 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Nastaví G a M klávesy aby posílaly HID++ oznámení (která spustí " "Solaar pravidla, ale jinak budou ignorována)." #: lib/logitech_receiver/settings_templates.py:690 msgid "Scroll Wheel Ratcheted" msgstr "Krokování rolovacího kole�ka" #: lib/logitech_receiver/settings_templates.py:691 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" "Přepíná kole�ko myši mezi rychlostně omezeným krokováním a volnou " "rotací." #: lib/logitech_receiver/settings_templates.py:693 msgid "Freespinning" msgstr "Volná rotace" #: lib/logitech_receiver/settings_templates.py:693 msgid "Ratcheted" msgstr "Krokování" #: lib/logitech_receiver/settings_templates.py:700 msgid "Scroll Wheel Ratchet Speed" msgstr "Rychlost krokování kole�ka" #: lib/logitech_receiver/settings_templates.py:702 msgid "" "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Rychlost rotace kole�ka při které se přepne mezi krokováním a volným " "posunem.\n" "Hodnota 50 vždy přepne na krokování." #: lib/logitech_receiver/settings_templates.py:752 msgid "Scroll Wheel Ratchet Torque" msgstr "Moment změny krokování kole�ka" #: lib/logitech_receiver/settings_templates.py:753 msgid "Change the torque needed to overcome the ratchet." msgstr "Změní moment nutný k překonání krokování." #: lib/logitech_receiver/settings_templates.py:788 msgid "Key/Button Actions" msgstr "Akce klávesy/tla�ítka" #: lib/logitech_receiver/settings_templates.py:790 msgid "Change the action for the key or button." msgstr "Změní akci klávesy nebo tla�ítka." #: lib/logitech_receiver/settings_templates.py:792 msgid "Overridden by diversion." msgstr "Zrušeno odklonění." #: lib/logitech_receiver/settings_templates.py:794 msgid "" "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Změna důležité akce (například pro levé tla�ítko myši) může vést k " "nepoužitelnému systému." #: lib/logitech_receiver/settings_templates.py:969 msgid "Key/Button Diversion" msgstr "Odklonění klávesy/tla�ítka" #: lib/logitech_receiver/settings_templates.py:970 msgid "" "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" "Nastaví G klávesy aby posílaly HID++ oznámení (Odkloněno) nebo " "spustí gesta myši �i plynulé nastavení DPI" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 #: lib/logitech_receiver/settings_templates.py:975 msgid "Diverted" msgstr "Odkloněno" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 msgid "Mouse Gestures" msgstr "Gesta myši" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 #: lib/logitech_receiver/settings_templates.py:975 msgid "Regular" msgstr "Běžné" #: lib/logitech_receiver/settings_templates.py:973 msgid "Sliding DPI" msgstr "Plynulé nastavení DPI" #: lib/logitech_receiver/settings_templates.py:1063 #: lib/logitech_receiver/settings_templates.py:1091 msgid "Sensitivity (DPI)" msgstr "Citlivost (DPI)" #: lib/logitech_receiver/settings_templates.py:1173 msgid "Sensitivity Switching" msgstr "Přepnutí citlivosti" #: lib/logitech_receiver/settings_templates.py:1175 msgid "" "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" "Přepnutí sou�asné a uložené citlivosti při stisku tla�ítka �i " "klávesy.\n" "Pokud není citlivost uložena, uloží sou�asnou citlivost." #: lib/logitech_receiver/settings_templates.py:1179 msgid "Off" msgstr "Vypnuto" #: lib/logitech_receiver/settings_templates.py:1210 msgid "Disable keys" msgstr "Zakázat klávesy" #: lib/logitech_receiver/settings_templates.py:1211 msgid "Disable specific keyboard keys." msgstr "Zakáže specifické klávesy." #: lib/logitech_receiver/settings_templates.py:1214 #, python-format msgid "Disables the %s key." msgstr "Zakáže %s klávesu." #: lib/logitech_receiver/settings_templates.py:1227 #: lib/logitech_receiver/settings_templates.py:1284 msgid "Set OS" msgstr "Nastavit OS" #: lib/logitech_receiver/settings_templates.py:1228 #: lib/logitech_receiver/settings_templates.py:1285 msgid "Change keys to match OS." msgstr "Změní klávesy dle opera�ního systému." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Change Host" msgstr "Změnit hostitele" #: lib/logitech_receiver/settings_templates.py:1298 msgid "Switch connection to a different host" msgstr "Přepnout spojení na jiného hostitele" #: lib/logitech_receiver/settings_templates.py:1322 msgid "Performs a left click." msgstr "Provede levý klik." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Single tap" msgstr "Jednoduché klepnutí" #: lib/logitech_receiver/settings_templates.py:1323 msgid "Performs a right click." msgstr "Provede pravý klik." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Single tap with two fingers" msgstr "Jedno klepnutí dvěma prsty" #: lib/logitech_receiver/settings_templates.py:1324 msgid "Single tap with three fingers" msgstr "Jedno klepnutí třemi prsty" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Double tap" msgstr "Dvojklepnutí" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Performs a double click." msgstr "Provede dvouklik." #: lib/logitech_receiver/settings_templates.py:1329 msgid "Double tap with two fingers" msgstr "Dvojité klepnutí dvěma prsty" #: lib/logitech_receiver/settings_templates.py:1330 msgid "Double tap with three fingers" msgstr "Dvojité klepnutí třemi prsty" #: lib/logitech_receiver/settings_templates.py:1333 msgid "Drags items by dragging the finger after double tapping." msgstr "Táhnutí položek tažením prstu po dvojitém poklepání." #: lib/logitech_receiver/settings_templates.py:1333 msgid "Tap and drag" msgstr "Klepni a táhni" #: lib/logitech_receiver/settings_templates.py:1335 msgid "Tap and drag with two fingers" msgstr "Klepni a táhni dvěma prsty" #: lib/logitech_receiver/settings_templates.py:1336 msgid "Drags items by dragging the fingers after double tapping." msgstr "Táhnutí položek tažením prstů po dvojitém poklepání." #: lib/logitech_receiver/settings_templates.py:1338 msgid "Tap and drag with three fingers" msgstr "Klepnutí a táhnutí třemi prsty" #: lib/logitech_receiver/settings_templates.py:1341 msgid "Suppress tap and edge gestures" msgstr "Potla�it gesta klepnutí a hrany" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Potla�í gesta klepnutí a hrany (ekvivalent stisknutí Fn + Levý klik)." #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scroll with one finger" msgstr "Posuv jedním prstem." #: lib/logitech_receiver/settings_templates.py:1344 #: lib/logitech_receiver/settings_templates.py:1345 #: lib/logitech_receiver/settings_templates.py:1348 msgid "Scrolls." msgstr "Posuvy." #: lib/logitech_receiver/settings_templates.py:1345 #: lib/logitech_receiver/settings_templates.py:1348 msgid "Scroll with two fingers" msgstr "Posuv dvěma prsty" #: lib/logitech_receiver/settings_templates.py:1346 msgid "Scroll horizontally with two fingers" msgstr "Vodorovný posuv dvěma prsty" #: lib/logitech_receiver/settings_templates.py:1346 msgid "Scrolls horizontally." msgstr "Vodorovný posuv." #: lib/logitech_receiver/settings_templates.py:1347 msgid "Scroll vertically with two fingers" msgstr "Svislý posuv dvěma prsty" #: lib/logitech_receiver/settings_templates.py:1347 msgid "Scrolls vertically." msgstr "Svislý posuv." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Inverts the scrolling direction." msgstr "Mění směr otá�ení." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Natural scrolling" msgstr "Přirozený posuv" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Enables the thumbwheel." msgstr "Povolí kole�ko palce." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Thumbwheel" msgstr "Kole�ko palce" #: lib/logitech_receiver/settings_templates.py:1361 #: lib/logitech_receiver/settings_templates.py:1365 msgid "Swipe from the top edge" msgstr "Táhnutí z horní hrany" #: lib/logitech_receiver/settings_templates.py:1362 msgid "Swipe from the left edge" msgstr "Táhnutí z levé hrany" #: lib/logitech_receiver/settings_templates.py:1363 msgid "Swipe from the right edge" msgstr "Táhnutí z pravé hrany" #: lib/logitech_receiver/settings_templates.py:1364 msgid "Swipe from the bottom edge" msgstr "Táhnutí ze spodní hrany" #: lib/logitech_receiver/settings_templates.py:1366 msgid "Swipe two fingers from the left edge" msgstr "Táhnutí dvěma prsty z levé hrany" #: lib/logitech_receiver/settings_templates.py:1367 msgid "Swipe two fingers from the right edge" msgstr "Táhnutí dvěma prsty z pravé hrany" #: lib/logitech_receiver/settings_templates.py:1368 msgid "Swipe two fingers from the bottom edge" msgstr "Táhnutí dvěma prsty ze spodní hrany" #: lib/logitech_receiver/settings_templates.py:1369 msgid "Swipe two fingers from the top edge" msgstr "Táhnutí dvěma prsty z horní hrany" #: lib/logitech_receiver/settings_templates.py:1370 #: lib/logitech_receiver/settings_templates.py:1374 msgid "Pinch to zoom out; spread to zoom in." msgstr "Sevření pro přiblížení; rozevření pro oddálení." #: lib/logitech_receiver/settings_templates.py:1370 msgid "Zoom with two fingers." msgstr "Přiblížení dvěma prsty." #: lib/logitech_receiver/settings_templates.py:1371 msgid "Pinch to zoom out." msgstr "Sevřít pro přiblížení." #: lib/logitech_receiver/settings_templates.py:1372 msgid "Spread to zoom in." msgstr "Rozevřít pro oddálení." #: lib/logitech_receiver/settings_templates.py:1373 msgid "Zoom with three fingers." msgstr "Přiblížení třemi prsty." #: lib/logitech_receiver/settings_templates.py:1374 msgid "Zoom with two fingers" msgstr "Přiblížení dvěma prsty" #: lib/logitech_receiver/settings_templates.py:1392 msgid "Pixel zone" msgstr "Pixelová zóna" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Ratio zone" msgstr "Poměrová zóna" #: lib/logitech_receiver/settings_templates.py:1394 msgid "Scale factor" msgstr "Faktor škálování" #: lib/logitech_receiver/settings_templates.py:1394 msgid "Sets the cursor speed." msgstr "Nastaví rychlost kurzoru." #: lib/logitech_receiver/settings_templates.py:1398 msgid "Left-most coordinate." msgstr "Souřadnice nejvíce vlevo." #: lib/logitech_receiver/settings_templates.py:1399 msgid "Bottom" msgstr "Dole" #: lib/logitech_receiver/settings_templates.py:1399 msgid "Bottom coordinate." msgstr "Spodní souřadnice." #: lib/logitech_receiver/settings_templates.py:1400 msgid "Width" msgstr "Šířka" #: lib/logitech_receiver/settings_templates.py:1400 msgid "Width." msgstr "Šířka." #: lib/logitech_receiver/settings_templates.py:1401 msgid "Height" msgstr "Výška" #: lib/logitech_receiver/settings_templates.py:1401 msgid "Height." msgstr "Výška." #: lib/logitech_receiver/settings_templates.py:1402 msgid "Cursor speed." msgstr "Rychlost kurzoru." #: lib/logitech_receiver/settings_templates.py:1402 msgid "Scale" msgstr "Měřítko" #: lib/logitech_receiver/settings_templates.py:1408 msgid "Gestures" msgstr "Gesta" #: lib/logitech_receiver/settings_templates.py:1409 msgid "Tweak the mouse/touchpad behaviour." msgstr "Ladí chování myši/touchpadu." #: lib/logitech_receiver/settings_templates.py:1425 msgid "Gestures Diversion" msgstr "Gesto odklonění" #: lib/logitech_receiver/settings_templates.py:1426 msgid "Divert mouse/touchpad gestures." msgstr "Odkloní gesta myši/touchpadu." #: lib/logitech_receiver/settings_templates.py:1442 msgid "Gesture params" msgstr "Parametry gesta" #: lib/logitech_receiver/settings_templates.py:1443 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Změňte �íselné parametry myši/touchpadu." #: lib/logitech_receiver/settings_templates.py:1467 msgid "M-Key LEDs" msgstr "M-Key LEDky" #: lib/logitech_receiver/settings_templates.py:1469 msgid "Control the M-Key LEDs." msgstr "Ovládání LEDek M-Key." #: lib/logitech_receiver/settings_templates.py:1473 #: lib/logitech_receiver/settings_templates.py:1504 msgid "May need G Keys diverted to be effective." msgstr "Může vyžadovat odklonění G kláves aby se projevilo." #: lib/logitech_receiver/settings_templates.py:1479 #, python-format msgid "Lights up the %s key." msgstr "Osvětlení %s klávesy." #: lib/logitech_receiver/settings_templates.py:1498 msgid "MR-Key LED" msgstr "MR-Key LED" #: lib/logitech_receiver/settings_templates.py:1500 msgid "Control the MR-Key LED." msgstr "Ovládání MR-Key LEDky." #: lib/logitech_receiver/settings_templates.py:1521 msgid "Persistent Key/Button Mapping" msgstr "Trvalé mapování Klávesy/Tla�ítka" #: lib/logitech_receiver/settings_templates.py:1523 msgid "Permanently change the mapping for the key or button." msgstr "Trvale změní mapování klávesy nebo tla�ítka." #: lib/logitech_receiver/settings_templates.py:1525 msgid "" "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" "Změna důležité klávesy nebo tla�ítka (například levé tla�ítko myši) " "může vést k nepoužitelnému systému." #: lib/logitech_receiver/settings_templates.py:1582 msgid "Sidetone" msgstr "Zpětná vazba" #: lib/logitech_receiver/settings_templates.py:1583 msgid "Set sidetone level." msgstr "Nastavení úrovně zpětné vazby." #: lib/logitech_receiver/settings_templates.py:1592 msgid "Equalizer" msgstr "Ekvalizér" #: lib/logitech_receiver/settings_templates.py:1593 #: lib/logitech_receiver/settings_templates.py:1902 msgid "Set equalizer levels." msgstr "Nastavení úrovní ekvalizéru." #: lib/logitech_receiver/settings_templates.py:1615 #: lib/logitech_receiver/settings_templates.py:1930 #: lib/logitech_receiver/settings_templates.py:2056 #: lib/logitech_receiver/settings_templates.py:2058 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1621 msgid "Power Management" msgstr "Správa napájení" #: lib/logitech_receiver/settings_templates.py:1622 msgid "Power off in minutes (0 for never)." msgstr "Vypnutí po minutách (0 pro nikdy)." #: lib/logitech_receiver/settings_templates.py:1634 msgid "Eco Mode" msgstr "Eko režim" #: lib/logitech_receiver/settings_templates.py:1635 msgid "Battery saver mode." msgstr "Režim šetření baterie." #: lib/logitech_receiver/settings_templates.py:1653 msgid "Do Not Disturb" msgstr "Nerušit" #: lib/logitech_receiver/settings_templates.py:1654 msgid "Suppress notification sounds." msgstr "Potla�it zvuk oznámení." #: lib/logitech_receiver/settings_templates.py:1661 msgid "Mic Mute" msgstr "Ztlumit mikrofon." #: lib/logitech_receiver/settings_templates.py:1662 msgid "Mute the microphone." msgstr "Ztlumení mikrofonu." #: lib/logitech_receiver/settings_templates.py:1681 msgid "Mic SNR" msgstr "SNR mikrofonu" #: lib/logitech_receiver/settings_templates.py:1682 msgid "Microphone signal-to-noise ratio enhancement." msgstr "Rozšíření poměru signál-šum mikrofonu." #: lib/logitech_receiver/settings_templates.py:1689 msgid "AI Noise Reduction" msgstr "AI redukce šumu" #: lib/logitech_receiver/settings_templates.py:1690 msgid "Enable AI noise reduction." msgstr "Povolí AI redukci šumu." #: lib/logitech_receiver/settings_templates.py:1697 msgid "AI Noise Reduction Level" msgstr "Úroveň AI omezení šumu." #: lib/logitech_receiver/settings_templates.py:1698 msgid "AI noise reduction intensity." msgstr "Intenzita AI omezení šumu." #: lib/logitech_receiver/settings_templates.py:1707 msgid "Headset Sidetone" msgstr "Zpětná vazba náhlavní soupravy" #: lib/logitech_receiver/settings_templates.py:1708 msgid "Sidetone level (0 = off, 100 = max)." msgstr "Úroveň zpětné vazby (0 = vypnuto, 100 = max)." #: lib/logitech_receiver/settings_templates.py:1771 msgid "Mic Gain" msgstr "Zesílení mikrofonu" #: lib/logitech_receiver/settings_templates.py:1772 msgid "Microphone gain level." msgstr "Úroveň zesílení mikrofonu." #: lib/logitech_receiver/settings_templates.py:1824 msgid "Audio Mix Balance" msgstr "Vyvážení zvuku" #: lib/logitech_receiver/settings_templates.py:1825 msgid "Balance between game and chat audio." msgstr "Vyvážení zvuku mezi hrou a mluvením." #: lib/logitech_receiver/settings_templates.py:1876 msgid "Auto Sleep Timeout" msgstr "Časový limit pro automatické uspání" #: lib/logitech_receiver/settings_templates.py:1877 msgid "" "Idle time in minutes before the headset enters sleep mode (0 = " "disabled)." msgstr "" "Doba ne�innosti v minutách, po které se sluchátka přepnou do režimu " "spánku (0 = vypnuto)." #: lib/logitech_receiver/settings_templates.py:1901 msgid "Headset Equalizer" msgstr "Ekvalizér sluchátek" #: lib/logitech_receiver/settings_templates.py:1996 msgid "Headset Advanced EQ" msgstr "Pokro�ilý EQ sluchátek" #: lib/logitech_receiver/settings_templates.py:1997 msgid "Per-band gain for the headset's active parametric EQ." msgstr "" "Zesílení jednotlivých pásem u aktivního parametrického ekvalizéru sluchátek." #: lib/logitech_receiver/settings_templates.py:2268 msgid "EQ Preset" msgstr "Přednastavení ekvalizéru" #: lib/logitech_receiver/settings_templates.py:2269 msgid "Switch the active EQ preset. Factory presets are read-only." msgstr "" "Přepne aktivní přednastavení ekvalizéru. Tovární přednastavení jsou pouze pro " "�tení." #: lib/logitech_receiver/settings_templates.py:2294 msgid "Slot" msgstr "Pozice" #: lib/logitech_receiver/settings_templates.py:2296 msgid "(factory)" msgstr "(tovární)" #: lib/logitech_receiver/settings_templates.py:2429 #: lib/logitech_receiver/settings_templates.py:3206 #: lib/logitech_receiver/settings_templates.py:3298 msgid "LED Control" msgstr "Ovládání LED" #: lib/logitech_receiver/settings_templates.py:2430 msgid "Allow Solaar to control the headset LED zones." msgstr "Povolit Solaaru kontrolovat LED zóny." #: lib/logitech_receiver/settings_templates.py:2478 msgid "Per-zone Lighting" msgstr "Zónové osvětlení" #: lib/logitech_receiver/settings_templates.py:2480 msgid "" "Override individual zone colors. 'No change' inherits the LEDs " "Primary color.\n" "LED Control needs to be set to Solaar to be effective." msgstr "" "Přepsání barev jednotlivých zón. Volba „Bez změny“ převezme primární barvu LED" " diod.\n" "Aby bylo ovládání LED funk�ní musí být nastaveno na Solaar." #: lib/logitech_receiver/settings_templates.py:2498 msgid "Zone" msgstr "Zóna" #: lib/logitech_receiver/settings_templates.py:2620 #: lib/logitech_receiver/settings_templates.py:2908 #: lib/logitech_receiver/settings_templates.py:3648 msgid "Secondary" msgstr "Sekundární" #: lib/logitech_receiver/settings_templates.py:2621 #: lib/logitech_receiver/settings_templates.py:3234 msgid "Speed" msgstr "Rychlost" #: lib/logitech_receiver/settings_templates.py:2688 msgid "Startup Effect" msgstr "Efekt při zapnutí" #: lib/logitech_receiver/settings_templates.py:2690 msgid "Firmware lighting effect played when the headset powers on or wakes." msgstr "" "Světelný efekt firmwaru, který se spustí při zapnutí nebo probuzení sluchátek." #: lib/logitech_receiver/settings_templates.py:2692 #: lib/logitech_receiver/settings_templates.py:2703 msgid "Device default: Primary #00B8FC, Secondary #FF00AB, Speed 100." msgstr "" "Výchozí v zařízení: Primární #00B8FC, Sekundární #FF00AB, Rychlost 100." #: lib/logitech_receiver/settings_templates.py:2699 msgid "Shutdown Effect" msgstr "Efekt při vypnutí" #: lib/logitech_receiver/settings_templates.py:2701 msgid "" "Firmware lighting effect played when the headset powers off or " "sleeps." msgstr "" "Světelný efekt firmwaru, který se spustí při vypnutí nebo uspání sluchátek." #: lib/logitech_receiver/settings_templates.py:2710 msgid "Passive Effect" msgstr "Efekt při ne�innosti" #: lib/logitech_receiver/settings_templates.py:2712 msgid "Firmware lighting effect played while the headset is idle." msgstr "Světelný efekt firmwaru, který se spustí při neaktivitě sluchátek." #: lib/logitech_receiver/settings_templates.py:2714 msgid "Device default: Primary #00B8FC, Secondary #FF00AB, Speed 75." msgstr "Výchozí v zařízení: Primární #00B8FC, Sekundární #FF00AB, Rychlost 75." #: lib/logitech_receiver/settings_templates.py:2833 msgid "Onboard Effect" msgstr "Vestavěný efekt" #: lib/logitech_receiver/settings_templates.py:2834 msgid "Firmware RGB effect the headset plays on its own." msgstr "RGB efekt firmware, který sluchátka přehrají samy od sebe." #: lib/logitech_receiver/settings_templates.py:2909 #: lib/logitech_receiver/settings_templates.py:3243 msgid "Intensity" msgstr "Intenzita" #: lib/logitech_receiver/settings_templates.py:2910 #: lib/logitech_receiver/settings_templates.py:3245 msgid "Saturation" msgstr "Sytost" #: lib/logitech_receiver/settings_templates.py:2914 #: lib/logitech_receiver/settings_templates.py:3238 msgid "Period" msgstr "Období" #: lib/logitech_receiver/settings_templates.py:2919 #: lib/logitech_receiver/settings_templates.py:3250 msgid "Direction" msgstr "Směr" #: lib/logitech_receiver/settings_templates.py:3134 msgid "Brightness Control" msgstr "Nastavení jasu" #: lib/logitech_receiver/settings_templates.py:3135 msgid "Control overall brightness" msgstr "Nastavení celkového jasu" #: lib/logitech_receiver/settings_templates.py:3207 #: lib/logitech_receiver/settings_templates.py:3299 msgid "Allow Solaar to control LED zones." msgstr "Povolit Sollaru kontrolovat LED zóny." #: lib/logitech_receiver/settings_templates.py:3230 #: lib/logitech_receiver/settings_templates.py:3744 msgid "LED Zone Effects" msgstr "LED zónové efekty" #: lib/logitech_receiver/settings_templates.py:3231 #: lib/logitech_receiver/settings_templates.py:3399 #: lib/logitech_receiver/settings_templates.py:3439 #: lib/logitech_receiver/settings_templates.py:3546 #: lib/logitech_receiver/settings_templates.py:3745 msgid "LED Control needs to be enabled." msgstr "Ovládání LED musí být povoleno." #: lib/logitech_receiver/settings_templates.py:3231 #: lib/logitech_receiver/settings_templates.py:3745 msgid "Set effect for LED Zone" msgstr "Nastavit efekt pro zónu LED" #: lib/logitech_receiver/settings_templates.py:3233 msgid "Color" msgstr "Barva" #: lib/logitech_receiver/settings_templates.py:3244 #, fuzzy msgid "Ramp" msgstr "Rampa" #: lib/logitech_receiver/settings_templates.py:3246 msgid "Waveform" msgstr "Forma vlny" #: lib/logitech_receiver/settings_templates.py:3279 msgid "LEDs" msgstr "LEDky" #: lib/logitech_receiver/settings_templates.py:3398 msgid "Idle Timeout" msgstr "Limit ne�innosti" #: lib/logitech_receiver/settings_templates.py:3399 msgid "Time without input before LED idle effect starts." msgstr "Doba v klidu předtím než se spustí efekt ne�innosti." #: lib/logitech_receiver/settings_templates.py:3435 msgid "Idle Effect" msgstr "Efekt při ne�innosti" #: lib/logitech_receiver/settings_templates.py:3437 msgid "" "What happens to LEDs when idle — dim to a percentage, change the " "base color, or play an animation." msgstr "" "Co se má stít s LED během ne�innosti — ztlumit na procenta, změnit " "základní barvu nebo přehrát animaci." #: lib/logitech_receiver/settings_templates.py:3520 msgid "No change" msgstr "Beze změny" #: lib/logitech_receiver/settings_templates.py:3545 msgid "Sleep Timeout" msgstr "Časový limit pro uspání" #: lib/logitech_receiver/settings_templates.py:3546 msgid "Time without input before LEDs fade off completely." msgstr "Doba v klidu předtím než LEDky kompletně zhasnou." #: lib/logitech_receiver/settings_templates.py:3719 msgid "Startup Animation" msgstr "Úvodní animace" #: lib/logitech_receiver/settings_templates.py:3722 msgid "" "Firmware-played animation when the keyboard wakes from deep sleep or " "powers on.\n" "Setting persists on the device (non-volatile)." msgstr "" "Animace přehrávaná firmwarem při probuzení klávesnice z režimu " "hlubokého spánku nebo při zapnutí.\n" "Nastavení zůstává uloženo v zařízení (trvale)." #: lib/logitech_receiver/settings_templates.py:3726 #: lib/logitech_receiver/settings_templates.py:3737 msgid "Device default: Primary #FF0081, Secondary #80AAFF." msgstr "Výchozí v zařízení: Primární #FF0081, Sekundární #80AAFF." #: lib/logitech_receiver/settings_templates.py:3733 msgid "Shutdown Animation" msgstr "Vypínací animace" #: lib/logitech_receiver/settings_templates.py:3735 msgid "" "Firmware-played animation when the keyboard powers off.\n" "Setting persists on the device (non-volatile)." msgstr "" "Animace spouštěná firmwarem při vypnutí klávesnice.\n" "Nastavení zůstává uloženo v zařízení (trvale)." #: lib/logitech_receiver/settings_templates.py:3847 #: lib/solaar/ui/perkey/dialog.py:87 msgid "Per-key Lighting" msgstr "Osvětlení jednotlivých kláves" #: lib/logitech_receiver/settings_templates.py:3849 msgid "Control per-key lighting." msgstr "Ovládání podsvícení jednotlivých kláves." #: lib/logitech_receiver/settings_templates.py:3851 msgid "" "LED Control needs to be enabled and the zone effect set to Static " "for per-key paint to be visible." msgstr "" "Aby bylo možné zobrazit barvy jednotlivých kláves, je třeba povolit " "ovládání LED a nastavit efekt zóny na „Statický“." #: lib/logitech_receiver/settings_templates.py:4182 msgid "Force Sensing Buttons" msgstr "Tla�ítka se sníma�em tlaku" #: lib/logitech_receiver/settings_templates.py:4183 msgid "Change the force required to activate button." msgstr "Změňte sílu potřebnou pro aktivaci tla�ítka." #: lib/logitech_receiver/settings_templates.py:4200 msgid "Force Sensing Button" msgstr "Tla�ítko se sníma�em tlaku" #: lib/logitech_receiver/settings_templates.py:4316 msgid "Analog Button Tuning" msgstr "Nastavení analogového tla�ítka" #: lib/logitech_receiver/settings_templates.py:4317 msgid "" "Configure analog button settings including actuation point, rapid " "trigger, and haptics." msgstr "" "Nastavte parametry analogových tla�ítek, v�etně bodu stisknutí, " "rychlého spouštění a haptické zpětné vazby." #: lib/logitech_receiver/settings_templates.py:4347 #, python-format msgid "Actuation point depth (1=shallow, %d=deep)." msgstr "Hloubka bodu aktivace (1=mělký, %d=hluboký)." #: lib/logitech_receiver/settings_templates.py:4355 #, python-format msgid "Rapid trigger sensitivity (1..%d)." msgstr "Citlivost spouště (1..%d)." #: lib/logitech_receiver/settings_templates.py:4363 #, python-format msgid "Click haptic feedback intensity (0=off, %d=max)." msgstr "Intenzita haptické odezvy na kliknutí (0=vypnuto, %d=max)." #: lib/logitech_receiver/settings_templates.py:4371 msgid "Haptic Feedback Level" msgstr "Úroveň haptické odezvy" #: lib/logitech_receiver/settings_templates.py:4372 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "Změní sílu haptické odezvy. (Nula pro vypnutí.)" #: lib/logitech_receiver/settings_templates.py:4414 msgid "Play Haptic Waveform" msgstr "Přehrát haptickou odezvu" #: lib/logitech_receiver/settings_templates.py:4415 msgid "Tell device to play a haptic waveform." msgstr "Řekne zařízení aby přehrálo haptickou odezvu." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "Další proces Solaar již běží takže pouze zobrazíme jeho okno" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Správa Logitech přijíma�ů,\n" "klávesnic, myší a tabletů." #: lib/solaar/ui/about/model.py:64 msgid "Additional Programming" msgstr "Dodate�né programování" #: lib/solaar/ui/about/model.py:65 msgid "GUI design" msgstr "Vzhled aplikace" #: lib/solaar/ui/about/model.py:67 msgid "Testing" msgstr "Testování" #: lib/solaar/ui/about/model.py:75 msgid "Logitech documentation" msgstr "Dokumentace Logitechu" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Zrušit párování" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:142 msgid "Cancel" msgstr "Zrušit" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Chyba oprávnění" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" "Nalezen přijíma� Logitech nebo zařízení (%s), ale chybí oprávnění " "pro jeho otevření." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" "Pokud jste právě nainstalovali Solaar, zkuste přijíma� nebo zařízení " "odpojit a poté jej znovu připojit." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Chyba nelze se připojit k zařízení" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Nalezen přijíma� Logitech nebo zařízení (%s), ale při pokusu o " "připojení se k němu se vyskytla chyba." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" "Zkuste zařízení odpojit a znovu připojit nebo ho vypnout a znovu " "zapnout." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "Párování selhalo" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Selhalo odpojení %{device} od %{receiver}." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Přijíma� vrátil chybu bez dalších detailů." #: lib/solaar/ui/config_panel.py:254 msgid "Complete - ENTER to change" msgstr "Kompletní - ENTER pro změnu" #: lib/solaar/ui/config_panel.py:254 msgid "Incomplete" msgstr "Nekompletní" #: lib/solaar/ui/config_panel.py:500 lib/solaar/ui/config_panel.py:552 #: lib/solaar/ui/config_panel.py:619 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d hodnota" msgstr[1] "%d hodnoty" msgstr[2] "%d hodnot" #: lib/solaar/ui/config_panel.py:805 msgid "Changes allowed" msgstr "Změny povoleny" #: lib/solaar/ui/config_panel.py:806 msgid "No changes allowed" msgstr "Změny nejsou povoleny" #: lib/solaar/ui/config_panel.py:807 msgid "Ignore this setting" msgstr "Ignorovat toto nastavení" #: lib/solaar/ui/config_panel.py:1022 msgid "Working" msgstr "Pracuji" #: lib/solaar/ui/config_panel.py:1025 msgid "Read/write operation failed." msgstr "Operace �tení/zápisu selhala." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "nespecifikovaný důvod" #: lib/solaar/ui/diversion_rules.py:104 msgid "Built-in rules" msgstr "Zabudovaná pravidla" #: lib/solaar/ui/diversion_rules.py:104 msgid "User-defined rules" msgstr "Uživatelem definovaná pravidla" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:1127 msgid "Rule" msgstr "Pravidlo" #: lib/solaar/ui/diversion_rules.py:107 lib/solaar/ui/diversion_rules.py:383 #: lib/solaar/ui/diversion_rules.py:510 msgid "Sub-rule" msgstr "Podpravidlo" #: lib/solaar/ui/diversion_rules.py:109 msgid "[empty]" msgstr "[prázdné]" #: lib/solaar/ui/diversion_rules.py:133 msgid "Make changes permanent?" msgstr "Nastavit změnu jako trvalou?" #: lib/solaar/ui/diversion_rules.py:138 msgid "Yes" msgstr "Ano" #: lib/solaar/ui/diversion_rules.py:140 msgid "No" msgstr "Ne" #: lib/solaar/ui/diversion_rules.py:145 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Pokud vyberete Ne, budou změny po ukon�ení aplikace Solaar ztraceny." #: lib/solaar/ui/diversion_rules.py:274 msgid "Paste here" msgstr "Vložit tady" #: lib/solaar/ui/diversion_rules.py:276 msgid "Paste above" msgstr "Vložit nad" #: lib/solaar/ui/diversion_rules.py:278 msgid "Paste below" msgstr "Vložit pod" #: lib/solaar/ui/diversion_rules.py:284 msgid "Paste rule here" msgstr "Vložit pravidlo tady" #: lib/solaar/ui/diversion_rules.py:286 msgid "Paste rule above" msgstr "Vložit pravidlo nad" #: lib/solaar/ui/diversion_rules.py:288 msgid "Paste rule below" msgstr "Vložit pravidlo pod" #: lib/solaar/ui/diversion_rules.py:292 msgid "Paste rule" msgstr "Vložit pravidlo" #: lib/solaar/ui/diversion_rules.py:307 msgid "Insert here" msgstr "Vložit tady" #: lib/solaar/ui/diversion_rules.py:309 msgid "Insert above" msgstr "Vložit nad" #: lib/solaar/ui/diversion_rules.py:311 msgid "Insert below" msgstr "Vložit pod" #: lib/solaar/ui/diversion_rules.py:317 msgid "Insert new rule here" msgstr "Vložit nové pravidlo tady" #: lib/solaar/ui/diversion_rules.py:319 msgid "Insert new rule above" msgstr "Vložit nové pravidlo nad" #: lib/solaar/ui/diversion_rules.py:321 msgid "Insert new rule below" msgstr "Vložit nové pravidlo pod" #: lib/solaar/ui/diversion_rules.py:348 msgid "Flatten" msgstr "Srovnání" #: lib/solaar/ui/diversion_rules.py:381 msgid "Insert" msgstr "Vložit" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:512 #: lib/solaar/ui/diversion_rules.py:1159 msgid "Or" msgstr "Nebo" #: lib/solaar/ui/diversion_rules.py:385 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1145 msgid "And" msgstr "A" #: lib/solaar/ui/diversion_rules.py:387 msgid "Condition" msgstr "Podmínka" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Vlastnost" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Hlášení" #: lib/solaar/ui/diversion_rules.py:391 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Proces" #: lib/solaar/ui/diversion_rules.py:392 msgid "Mouse process" msgstr "Proces myši" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Modifikátory" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Klávesa" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "Klávesa zmá�knuta" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1433 msgid "Active" msgstr "Aktivní" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1391 #: lib/solaar/ui/diversion_rules.py:1442 lib/solaar/ui/diversion_rules.py:1488 msgid "Device" msgstr "Zařízení" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1468 msgid "Host" msgstr "Hostitel" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/diversion_rules.py:1507 msgid "Setting" msgstr "Nastavení" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Test bajty" #: lib/solaar/ui/diversion_rules.py:402 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Gesto myši" #: lib/solaar/ui/diversion_rules.py:406 msgid "Action" msgstr "Akce" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "Stisknutí klávesy" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Oto�ení kole�kem" #: lib/solaar/ui/diversion_rules.py:410 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Kliknutí myši" #: lib/solaar/ui/diversion_rules.py:411 msgid "Set" msgstr "Nastavit" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "Vykonat" #: lib/solaar/ui/diversion_rules.py:413 lib/solaar/ui/diversion_rules.py:1190 msgid "Later" msgstr "Zpoždění" #: lib/solaar/ui/diversion_rules.py:442 msgid "Insert new rule" msgstr "Vložit nové pravidlo" #: lib/solaar/ui/diversion_rules.py:462 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Smazat" #: lib/solaar/ui/diversion_rules.py:484 msgid "Negate" msgstr "Negovat" #: lib/solaar/ui/diversion_rules.py:508 msgid "Wrap with" msgstr "Obalit s" #: lib/solaar/ui/diversion_rules.py:538 msgid "Cut" msgstr "Vyjmout" #: lib/solaar/ui/diversion_rules.py:554 msgid "Paste" msgstr "Vložit" #: lib/solaar/ui/diversion_rules.py:560 msgid "Copy" msgstr "Kopírovat" #: lib/solaar/ui/diversion_rules.py:569 msgid "Solaar Rule Editor" msgstr "Editor pravidel Solaar" #: lib/solaar/ui/diversion_rules.py:669 msgid "Save changes" msgstr "Uložit změny" #: lib/solaar/ui/diversion_rules.py:674 msgid "Discard changes" msgstr "Zahodit změny" #: lib/solaar/ui/diversion_rules.py:1105 msgid "This editor does not support the selected rule component yet." msgstr "Vybraná komponenta pravidla není editorem zatím podporována." #: lib/solaar/ui/diversion_rules.py:1170 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with " "higher precision." msgstr "" "Po�et sekund pro zpoždění. Zpoždění mezi 0 a 1 bude s větší " "přesností." #: lib/solaar/ui/diversion_rules.py:1208 msgid "Not" msgstr "Opak" #: lib/solaar/ui/diversion_rules.py:1239 msgid "Toggle" msgstr "Přepnout" #: lib/solaar/ui/diversion_rules.py:1240 msgid "True" msgstr "Pravda" #: lib/solaar/ui/diversion_rules.py:1241 msgid "False" msgstr "Nepravda" #: lib/solaar/ui/diversion_rules.py:1254 msgid "Unsupported setting" msgstr "Nepodporované nastavení" #: lib/solaar/ui/diversion_rules.py:1397 lib/solaar/ui/diversion_rules.py:1416 #: lib/solaar/ui/diversion_rules.py:1494 lib/solaar/ui/diversion_rules.py:1758 #: lib/solaar/ui/diversion_rules.py:1776 msgid "Originating device" msgstr "Výchozí zařízení" #: lib/solaar/ui/diversion_rules.py:1429 msgid "Device is active and its settings can be changed." msgstr "Zařízení je aktivní a jeho nastavení může být změněno." #: lib/solaar/ui/diversion_rules.py:1438 msgid "Device that originated the current notification." msgstr "Zařízení které odeslalo aktuální oznámení. " #: lib/solaar/ui/diversion_rules.py:1451 msgid "Name of host computer." msgstr "Jméno hostitelského po�íta�e." #: lib/solaar/ui/diversion_rules.py:1521 msgid "Value" msgstr "Hodnota" #: lib/solaar/ui/diversion_rules.py:1530 msgid "Item" msgstr "Položka" #: lib/solaar/ui/diversion_rules.py:1818 msgid "Change setting on device" msgstr "Změní nastavení na zařízení" #: lib/solaar/ui/diversion_rules.py:1834 msgid "Setting on device" msgstr "Nastavení na zařízení" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: párování nového zařízení" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Přijíma�e Bolt jsou kompatibilní pouze s Bolt zařízeními." #: lib/solaar/ui/pair_window.py:48 msgid "" "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" "Držte párovací tla�ítko nebo klávesu dokud neza�ne indikátor " "párování rychle blikat." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Přijíma�e Unifying jsou kompatibilní pouze s Unifying zařízeními." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "Další přijíma�e jsou kompatibilní pouze s několika zařízeními." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "Pro většinu zařízení, zapněte zařízení, které chcete spárovat." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "Pokud je zařízení již zapnuto, vypněte jej a znova zapněte." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "Zařízení nesmí být spárováno s blízkým zapnutým přijíma�em." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the " "button for the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, " "hold, and release the channel switch button." msgstr "" "Pro zařízení s více kanály, stiskněte, podržte a pusťte tla�ítko " "kanálu, který chcete napárovat\n" "nebo použijte tla�ítko na přepínaní kanálů, vyberte kanál a pak " "stiskněte, podržte a pusťte tla�ítko přepínání kanálu." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Indikátor kanálu by měl rychle blikat." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "K přijíma�i lze napárovat ještě %d zařízení." msgstr[1] "" "\n" "\n" "K přijíma�i lze napárovat ještě %d zařízení." msgstr[2] "" "\n" "\n" "K přijíma�i lze napárovat ještě %d zařízení." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Zrušení v tomto okamžiku nezvýší po�et napárovaných." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Vložte kód do %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Vložte %(passcode)s a pak stiskněte klávesu enter." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "vlevo" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "vpravo" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Stiskněte %(code)s\n" "a pak zároveň stiskněte levé a pravé tla�ítko." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "Bezdrátové spojení není šifrováno" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Nalezeno nové zařízení:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Připojení selhalo." #: lib/solaar/ui/pair_window.py:249 msgid "" "Make sure your device is within range, and has a decent battery " "charge." msgstr "Ujistěte se, že je zařízení v dosahu a je dostate�ně nabito." #: lib/solaar/ui/pair_window.py:251 msgid "" "A new device was detected, but it is not compatible with this " "receiver." msgstr "" "Nové zařízení bylo detekováno, ale není kompatibilní s tímto " "přijíma�em." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "Více připojených zařízení než přijíma� dokáže zvládnout." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Další detaily o chybě nejsou dostupné." #: lib/solaar/ui/perkey/control.py:178 msgid "(not loaded)" msgstr "(nena�teno)" #: lib/solaar/ui/perkey/control.py:182 msgid "Open editor…" msgstr "Otevřít editor…" #: lib/solaar/ui/perkey/control.py:183 msgid "Paint key colors on a keyboard layout" msgstr "Vyzna�ení hlavních barev na rozložení klávesnice" #: lib/solaar/ui/perkey/control.py:229 msgid "(no zones)" msgstr "(bez zón)" #: lib/solaar/ui/perkey/control.py:233 #, python-brace-format msgid "{painted} / {total} keys painted" msgstr "{painted} / {total} kláves zbarveno" #: lib/solaar/ui/perkey/editor.py:54 msgid "Brush" msgstr "Štětec" #: lib/solaar/ui/perkey/editor.py:54 msgid "Click or drag to paint individual keys" msgstr "Kliknout a táhnout pro obarvení jednotlivých kláves" #: lib/solaar/ui/perkey/editor.py:55 msgid "Drag to select a rectangle of keys, painted on release" msgstr "Táhněte pro výběr obdélníku kláves, budou nabarveny po uvolnění" #: lib/solaar/ui/perkey/editor.py:55 msgid "Rect" msgstr "Obdélník" #: lib/solaar/ui/perkey/editor.py:56 msgid "Fill" msgstr "Výplň" #: lib/solaar/ui/perkey/editor.py:56 msgid "Flood-fill connected keys of the same color with the active color" msgstr "Vyplnit aktivní barvou klávesy propojené stejnou barvou" #: lib/solaar/ui/perkey/editor.py:59 msgid "Drag to fade from previous color to active color" msgstr "Táhněte pro plynulou změnu z předchozí na aktivní barvu" #: lib/solaar/ui/perkey/palette.py:90 msgid "Active color" msgstr "Aktivní barva" #: lib/solaar/ui/perkey/palette.py:95 msgid "Paint as 'no change' — clears the cell to the zone base color" msgstr "" "Překreslení výběrem „beze změny“ — nastaví buňce základní barvu " "oblasti" #: lib/solaar/ui/perkey/palette.py:96 msgid "Unset" msgstr "Nenastaveno" #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuluje kliknutí nebo zmá�knutí nebo uvolnění propojené klávesy.\n" "Na Waylandu vyžaduje právo zápisu do /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Přidat klávesu" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Kliknutí" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Stisknout" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Uvolnit" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simulace posunu kole�ka myši.\n" "Na Waylandu vyžaduje právo zápisu do /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simulace kliknutí tla�ítkem myši.\n" "Na Waylandu vyžaduje právo zápisu do /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Tla�ítko" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Akce (a po�et, pokud bylo kliknuto)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Vykonat příkaz s parametry." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Přidat parametr" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "X11 aktivní proces. Pouze pro X11." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "X11 proces myši. Pouze pro X11." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "ProcesMyši" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "Název funkce, která spouští zpracování pravidla pro oznámení." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "Po�et oznámení, která vedla ke spuštění zpracování pravidla." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Aktivní klávesové modifikátory. Ne vždy dostupné ve Waylandu." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" "Odkloněná klávesa nebo tla�ítko stištěné �i uvolněné.\n" "Použijte nastavení odklonění Klávesy/Tla�ítka a G kláves pro " "odklonění kláves a tla�ítek." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Klávesa dolů" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Klávesa nahoru" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" "Odkloněná klávesa nebo tla�ítko je momentálně dole.\n" "Použijte nastavení odklonění Klávesy/Tla�ítka a G kláves pro " "odklonění kláves a tla�ítek." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "Testovat podmínky oznámení spouštějící zpracování pravidel." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Parametr" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "za�átek (v�etně)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "konec (bez)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "rozsah" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "maximum" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "bajty %(0)d do %(1)d, v rozmezí od %(2)d do %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "maska" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "bajty %(0)d do %(1)d, maska %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Bitový nebo rozsahový test na bajtech v oznamovací zprávě, která " "spouští zpracování pravidla." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "type" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" "Gesto myší s volitelným spouštěcím tla�ítkem, po kterém následuje " "žádný nebo více pohybů myší." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Přidat pohyb" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Nenalezeno podporované zařízení" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "O aplikaci %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Ukon�it %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "bez přijíma�e" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:734 msgid "offline" msgstr "vypnuto" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "bez statusu" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Skenování" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Baterie" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Bezdrátové propojení" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "Osvětlení" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Ukázat technické detaily" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Připojit nové zařízení" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Vyberte zařízení" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Editor pravidel" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Cesta" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:550 lib/solaar/ui/window.py:552 msgid "Serial" msgstr "Sériové �íslo" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "Bezdrát. PID" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "ID výrobku" #: lib/solaar/ui/window.py:541 lib/solaar/ui/window.py:543 #: lib/solaar/ui/window.py:545 msgid "Protocol" msgstr "Protokol" #: lib/solaar/ui/window.py:545 msgid "Unknown" msgstr "Neznámý" #: lib/solaar/ui/window.py:547 msgid "Polling rate" msgstr "Četn. dotazů" #: lib/solaar/ui/window.py:554 msgid "Unit ID" msgstr "Číslo jednotky" #: lib/solaar/ui/window.py:565 msgid "none" msgstr "žádný" #: lib/solaar/ui/window.py:566 msgid "Notifications" msgstr "Oznámení" #: lib/solaar/ui/window.py:610 msgid "No device paired." msgstr "Žádné připojené zařízení." #: lib/solaar/ui/window.py:619 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "K přijíma�i může být připojeno %(max_count)s zařízení." msgstr[1] "K přijíma�i můžou být připojena až %(max_count)s zařízení." msgstr[2] "K přijíma�i může být připojeno až %(max_count)s zařízení." #: lib/solaar/ui/window.py:626 msgid "Only one device can be paired to this receiver." msgstr "K tomuto přijíma�i je možné připojit jen jedno zařízení." #: lib/solaar/ui/window.py:630 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "K přijíma�i je možné připojit ještě %d zařízení." msgstr[1] "K přijíma�i je možné připojit ještě %d zařízení." msgstr[2] "K přijíma�i je možné připojit ještě %d zařízení." #: lib/solaar/ui/window.py:687 msgid "Battery Voltage" msgstr "Napětí baterie" #: lib/solaar/ui/window.py:689 msgid "Voltage reported by battery" msgstr "Napětí hlášené baterií" #: lib/solaar/ui/window.py:691 msgid "Battery Level" msgstr "Úroveň baterie" #: lib/solaar/ui/window.py:693 msgid "Approximate level reported by battery" msgstr "Přibližná úroveň hlášená baterií" #: lib/solaar/ui/window.py:700 lib/solaar/ui/window.py:702 msgid "next reported " msgstr "další hlášené " #: lib/solaar/ui/window.py:703 msgid " and next level to be reported." msgstr " a další úroveň pro hlášení." #: lib/solaar/ui/window.py:708 msgid "last known" msgstr "poslední známý" #: lib/solaar/ui/window.py:719 msgid "encrypted" msgstr "šifrováno" #: lib/solaar/ui/window.py:721 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Bezdrátové spojení mezi zařízením a přijíma�em je šifrováno." #: lib/solaar/ui/window.py:723 msgid "not encrypted" msgstr "nešifrováno" #: lib/solaar/ui/window.py:727 msgid "" "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" "Bezdrátové spojení mezi zařízením a jeho přijíma�em není šifrováno.\n" "To je bezpe�nostní problém pro polohovací zařízení a významný " "bezpe�nostní problém pro zařízení vkládající text." #: lib/solaar/ui/window.py:743 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #, python-format #~ msgid "%(rate)d ms (%(rate_hz)dHz)" #~ msgstr "%(rate)d ms (%(rate_hz)dHz)" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the DPI button." #~ msgstr "Přizpůsobení DPI vodorovného posunu myši při sou�asném " #~ "držením stisku DPI tla�ítka." #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "Automatické přepíná režim kole�ka myši mezi krokováním a " #~ "volným otá�ením.\n" #~ "Kole�ko je při hodnotě 0 vždy volné a při hodnotě 50 vždy krokuje." #~ msgid "Battery information unknown." #~ msgstr "Informace o baterii nejsou známy." #, python-format #~ msgid "Battery: %(level)s" #~ msgstr "Baterie: %(level)s" #, python-format #~ msgid "Battery: %(percent)d%%" #~ msgstr "Baterie: %(percent)d%%" #~ msgid "Click to allow changes." #~ msgstr "Klikněte pro povolení změn." #~ msgid "Click to prevent changes." #~ msgstr "Klikněte pro zakázání změn." #~ msgid "Count" #~ msgstr "Po�et" #~ msgid "CycleS" #~ msgstr "CyklyS" #~ msgid "DPI Sliding Adjustment" #~ msgstr "Úprava DPI klouzání" #~ msgid "Divert G Keys" #~ msgstr "Odklonění G kláves" #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Efektivně vypne rolování palcem v Linuxu." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Efektivně vypne posuv kole�kem v Linuxu." #~ msgid "Enable onboard profiles, which often control report rate and " #~ "keyboard lighting" #~ msgstr "Povolí vestavěné profily které �asto kontrolují frekvenci " #~ "odesílání a podsvícení klávesnice" #~ msgid "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "Další instala�ní informace pro Solaar naleznete na \n" #~ "https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Nalezen přijíma� Logitech (%s), ale chybí práva pro jeho " #~ "otevření." #~ msgid "Frequency of device polling, in milliseconds" #~ msgstr "Frekvence snímání zařízení v milisekundách" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID++ režim pro vodorovný posun pomocí kole�ka." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++ režim pro svislý posuv kole�kem." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Pokud je zařízení zapnuto, vypněte jej a znovu zapněte" #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Pokud jste Solaar právě nainstalovali, zkuste přijíma� " #~ "odpojit a znova připojit." #~ msgid "LED Control needs to be set to Solaar to be effective." #~ msgstr "Aby bylo ovládání LED funk�ní musí být nastaveno na Solaar." #, python-format #~ msgid "Lighting: %(level)s lux" #~ msgstr "Osvětlení: %(level)s lux" #~ msgid "Make G keys send GKEY HID++ notifications (which trigger " #~ "Solaar rules but are otherwise ignored)." #~ msgstr "Nastaví G klávesy aby posílaly GKEY HID++ oznámení (která " #~ "spustí Solaar pravidla, ale jinak je ignorováno)." #~ msgid "Make the key or button send HID++ notifications (which " #~ "trigger Solaar rules but are otherwise ignored)." #~ msgstr "Klávesa nebo tla�ítko budou zasílat HID++ oznámení (která " #~ "spustí Solaar pravidla, ale jinak budou ignorována)." #~ msgid "May also make M keys and MR key send HID++ notifications" #~ msgstr "Také může nastavit M a MR klávesy, aby zasílaly HID++ " #~ "oznámení" #~ msgid "No Logitech receiver found" #~ msgstr "Logitech přijíma� nebyl nalezen" #~ msgid "Polling Rate (ms)" #~ msgstr "Frekvence snímání (ms)" #~ msgid "Scroll Wheel HID++ Scrolling" #~ msgstr "HID++ posuv kole�ka" #~ msgid "Scroll Wheel Rachet" #~ msgstr "Krokování kole�ka" #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Zobrazí stav zařízení připojených\n" #~ "přes bezdrátový přijíma� Logitech." #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar závisí na udev souboru, který chybí" #~ msgid "Switch control of LED zones between device and Solaar" #~ msgstr "Přepínání ovládání zón LED mezi zařízením a Solaar" #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "Bezdrátové spojení mezi zařízením a přijíma�em není " #~ "šifrováno.\n" #~ "\n" #~ "U ukazovacích zařízení (myši, trackbally, trackpady) je to jen " #~ "drobný bezpe�nostní problém.\n" #~ "\n" #~ "Ovšem pro textové vstupní zařízení (klávesnice, numerické " #~ "klávesnice) se jedná\n" #~ "o významný bezpe�nostní problém, protože psaný text může být\n" #~ "nepozorovaně odposlechnut třetí stranou, pokud je v dosahu." #~ msgid "Thumb Wheel HID++ Scrolling" #~ msgstr "HID++ posun kole�kem" #~ msgid "Top-most coordinate." #~ msgstr "Nejvyšší souřadnice." #~ msgid "Turn illumination on or off on keyboard." #~ msgstr "Vypne/zapne podsvícení klávesnice." #~ msgid "Turn on the device you want to pair." #~ msgstr "Zapněte zařízení které chcete připojit." #~ msgid "height" #~ msgstr "výška" #~ msgid "top" #~ msgstr "nahoře" #~ msgid "unknown" #~ msgstr "neznámý" #~ msgid "width" #~ msgstr "šířka" Solaar-1.1.20/po/da.po000066400000000000000000001434571522022367600144010ustar00rootroot00000000000000# Danish translations for solaar package. # Copyright (C) 2020 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2020. # msgid "" msgstr "Project-Id-Version: solaar 1.0.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2020-08-03 02:47+0200\n" "Last-Translator: John Erling Blad \n" "Language-Team: none\n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.3\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "tom" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "kritisk" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "lav" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "god" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "fuld" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "afladning" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "genopladning" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "opladning" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "næsten fuld" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "opladt" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "langsom opladning" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "batterifejl" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "termisk fejl" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "enheden svarede ikke" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "enhed understøttes ikke" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "for mange enheder" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "sekvens timeout" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Opstartsindlæser" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Andet" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "Smart skift" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "parlåsen er lukket" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "parlåsen er åben" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "tilsluttet" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "uparret" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "tændt" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Byt Fx-funktion" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Hvis aktiveret, vil F1–F12-tastene aktivere sin spesialfunksjon,\n" "og du må holde FN-tasten nede for at aktivere jeres standardfunktion." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Hvis deaktiveret, vil F1–F12-tastene aktivere sin standardfunktion,\n" "og du må holde FN-tasten nede for at aktivere deres spesialfunktion." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Hånddetektion" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Tænd belysning når hænderne er over tastaturet." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Højfølsom tilstand til lodret rulling med hjulet." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Siderulling" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Når deaktiveret, sender et tryk på hjulet sidelæns brugerdefinerede " "knaphændelser\n" "i stedet for standard siderullehændelser." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Bagbelysning" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "Tænd eller sluk for belysning på tastaturet." #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Følsomhed (pegerhastighed)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Hastighedsmultiplikator for mus (256 er normal multiplikator)." #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Skift handlingen for tasten eller knappen." #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "Ændring af vigtige handlinger (for eksempel venstre museknap) kan " "resultere i et ubrugeligt system." #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Følsomhed (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Deaktiver taster" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Deaktiver specifikke tastaturtaster." #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Indstil OS" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Skift taster for at matche OS." #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Indstil vært" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Skift forbindelse til en anden vært" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "" #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "" #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "" #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "" #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "" #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "" #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Skaleringsfaktor" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Bredde" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Højde" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "" #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gestusser" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "" #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "" #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Ingen forbundne enheder." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s parret enhed." msgstr[1] "%(count)s parrede enheder." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Batteri: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Batteri: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Belysning: %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batteri: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batteri: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Tilladelsesfejl" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Frakobling mislykkedes" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Mislykkedes med at bryde paret %{device} og %{receiver}." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "Modtageren returnerede en fejl uden yderligere detaljer." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "GUI-design" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Testing" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Logitech-dokumentation" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Fjern parring" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Succes" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Læse-/skriveoperationen mislykkedes." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Ja" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "" #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Aktiv" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Handling" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Klip" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Indsæt" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Kopiér" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "" #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "" #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Værdi" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "afslået" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: parre ny enhed" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "" #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Parring mislykkedes" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Sørg for, at din enhed er inden for rækkevidde og har en anstændig " "batteriopladning." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Der blev fundet en ny enhed, men den er ikke kompatibel med denne " "modtager." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "Flere parrede enheder end modtageren kan understøtte." #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Ingen yderligere oplysninger er tilgængelige om fejlen." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "Fandt en ny enhed:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "Den trådløse tilslutningen er ukryptert" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Tænd for den enhed, du vil parre." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "Denne modtager har %d parring tilbage." msgstr[1] "\n" "\n" "Denne modtager har %d parringer tilbage." #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Annullering på dette tidspunkt bruger ikke en parring." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "Om %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Afslut %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "ingen modtager" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "ingen status" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Søger" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Batteri" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Trådløs tilslutning" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Belysning" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Vis tekniske detaljer" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Parre ny enhed" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Vælg en enhed" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Sti" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Seriel" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Indeks" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "Trådløs-PID" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "Produkt-id" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protokol" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Ukendt" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Spørgerate" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "ingen" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Varsler" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "Ingen enhed parret." #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Op til %(max_count)s enhed kan parres med denne modtager." msgstr[1] "Op til %(max_count)s enheder kan parres med denne modtager." #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "Kun en enhed kan parres med denne modtager." #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Denne modtager har %d parring tilbage." msgstr[1] "Denne modtager har %d parringer tilbage." #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "" #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr "" #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "sidst kendt" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "kryptert" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Den trådløse forbindelse mellem denne enhed og dens modtager er " "krypteret." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "ukrypteret" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "\n" #~ "\n" #~ "This receiver has %d pairing(s) remaining." #~ msgstr "\n" #~ "\n" #~ "Denne modtager har %d parring(er) tilbage." #~ msgid "Actions" #~ msgstr "Handlinger" #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always locked at 50" #~ msgstr "Skift automatisk musehjulet mellem skralde og freespin-" #~ "tilstand.\n" #~ "Musehjulet er altid frit ved 0, og altid låst ved 50" #~ msgid "Count" #~ msgstr "Antal" #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Slår i praksis af tommelrulling i Linux." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Slår i praksis af hjulrulling i Linux." #~ msgid "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "Yderligere oplysninger finder du i Installationsvejledningen " #~ "til Solaar\n" #~ "på https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Fundet en Logitech-modtager (%s), men havde ikke tilladelse " #~ "til at åbne den." #~ msgid "HID++ Scrolling" #~ msgstr "HID++ rulling" #~ msgid "HID++ Thumb Scrolling" #~ msgstr "HID++ tommelrulling" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID ++ -tilstand til vandret rulling med tommelhjulet." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++ tilstand til lodret rulling med hjulet." #~ msgid "High Resolution Scrolling" #~ msgstr "Høyfølsom rulling" #~ msgid "High Resolution Wheel Invert" #~ msgstr "Inverter høyfølsom rulling" #~ msgid "High-sensitivity wheel invert direction for vertical scroll." #~ msgstr "Inverter retning til høyfølsom lodret rulling med hjulet." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Hvis enheden allerede er tændt, slå den fra og til igen." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Hvis du lige har installeret Solaar, kan du prøve at fjerne " #~ "modtageren og tilslutte den igen." #~ msgid "Invert thumb scroll direction." #~ msgstr "Inverter retning på tommelrulling." #~ msgid "No Logitech receiver found" #~ msgstr "Der blev ikke fundet nogen Logitech-modtager" #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Viser status for enheder, der er tilsluttet\n" #~ "via trådløse Logitech-modtagere." #~ msgid "Smooth Scrolling" #~ msgstr "Glat rulling" #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar er afhængig af en udev-fil, der ikke er til stede" #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Modtageren understøtter kun %d parrede enhed(er)." #~ msgid "The receiver was unplugged." #~ msgstr "Mottakeren fjernedes." #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "Den trådløse forbindelse mellem denne enhed og dens modtager " #~ "er ikke krypteret.\n" #~ "\n" #~ "For pegeenheder (mus, trackballs, pegefelter) er dette et mindre " #~ "sikkerhedsproblem.\n" #~ "\n" #~ "Det er imidlertid et vigtigt sikkerhedsproblem for tekstinputenheder " #~ "(tastaturer, numpads),\n" #~ "fordi maskinskrevet tekst kan sniffes upåfaldende af 3rd parter " #~ "inden for rækkevidde." #~ msgid "This receiver has %d pairing(s) remaining." #~ msgstr "Denne modtager har %d parring(er) tilbage." #~ msgid "Thumb Scroll Invert" #~ msgstr "Inverter tommelrulling" #~ msgid "USB id" #~ msgstr "USB-id" #~ msgid "Unexpected device number (%s) in notification %s." #~ msgstr "Uventet enhedsnummer (%s) i varsel %s." #~ msgid "Wheel Resolution" #~ msgstr "Hjulopløsning" #~ msgid "height" #~ msgstr "højde" #~ msgid "next " #~ msgstr "næste " #~ msgid "unknown" #~ msgstr "ukendt" #~ msgid "width" #~ msgstr "bredde" Solaar-1.1.20/po/de.po000066400000000000000000001700121522022367600143700ustar00rootroot00000000000000# German translations for solaar package. # Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2014. # msgid "" msgstr "Project-Id-Version: solaar 1.0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-05-11 19:38+0200\n" "PO-Revision-Date: 2026-05-11 19:35+0200\n" "Last-Translator: Daniel Frost \n" "Language-Team: none\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Launchpad-Export-Date: 2021-04-17 16:52+0000\n" "X-Generator: Poedit 3.4.2\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "Bolt Empfänger" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "Unifying Empfänger" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "Nano Empfänger" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "Lightspeed Empfänger" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 Empfänger 27 Mhz" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "entladen" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "kritisch" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "niedrig" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "mittel" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "gut" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "voll" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "entlädt" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "lädt wieder auf" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "lädt" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "lädt nicht" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "nahezu voll" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "geladen" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "langsames Aufladen" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "unzulässiger/defekter Akku" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "thermischer Fehler" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "Fehler" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "standard" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "schnell" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "langsam" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "Geräte Zeitüberschreitung" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "nicht unterstütztes Gerät" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "zu viele Geräte" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "Zeitüberschreitung im Ablauf" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Andere" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "Linke Taste" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "Rechte Taste" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "Mittlere Taste" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "Zurück Taste" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "Vorwärts Taste" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "Gestentaste" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "Smart Shift" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "DPI Schalter" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "Links kippen" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "Rechts kippen" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "Linksklick" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "Rechtsklick" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "Maus mittlere Taste" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "Maus \"Zurück\" Taste" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "Maus \"Vorwärts\"\n" " Taste" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "Gestentaste-Navigation" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "Maus \"Links scrollen\" Taste" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "Maus \"Rechts scrollen\" Taste" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "gedrückt" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "losgelassen" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "Koppelsperre ist inaktiv" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "Koppelsperre ist aktiv" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "Entdeckungssperre ist inaktiv" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "Entdeckungssperre ist aktiv" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "verbunden" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "nicht verbunden" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "nicht gekoppelt" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "eingeschaltet" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "registrieren" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "Feature" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Fn-Tastenbelegung umkehren" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Wenn aktiviert, dann behalten die Tasten F1-F12 ihre " "Sonderbelegung.\n" "Die jeweilige Standardbelegung kann über die FN-Taste aktiviert " "werden." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Wenn nicht aktiviert, dann behalten die Tasten F1-F12 ihre " "Standardbelegung.\n" "Die jeweilige Sonderbelegung kann über die FN-Taste aktiviert werden." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Handerkennung" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Schaltet die Beleuchtung ein, wenn sich die Hand über der Tastatur " "befindet." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "Weiches Mausrad-Scrollen" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Hohe Empfindlichkeit für vertikales Scrollen mit dem Mausrad." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Seitliches Scrollen" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Wenn ausgeschaltet, werden durch seitliches Kippen des Mausrads " "benutzer-\n" "definierte Maustastenereignisse gesendet, anstatt der vorgegebenen " "Seitlich-Scrollen-\n" "Ereignisse." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "Empfindlichkeit (DPI - ältere Mäuse)" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "Mauszeigerempfindlichkeit" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Hintergrundbeleuchtung" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "Die Beleuchtungszeit für die Tastatur einstellen." #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "Schaltet die Tastaturbeleuchtung an oder aus." #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "Hohe Auflösung für Mausrad-Scrollen" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Aktivieren zum Ignorieren, falls Scrollen ungewöhnlich langsam oder " "schnell ist" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "Mausrad Umleitung" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "Lasse das Mausrad LOWRES_WHEEL HID++ Nachrichten senden (diese lösen " "Solaar Regeln aus, werden sonst aber ignoriert)." #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "Mausrad-Scroll-Richtung" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "Kehrt die vertikale Scroll-Richtung des Mausrads um." #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "Auflösung für Mausrad-Scrollen" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "Lasse das Mausrad HIRES_WHEEL HID++ Nachrichten senden (diese lösen " "Solaar Regeln aus, werden sonst aber ignoriert)." #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Empfindlichkeit (Zeigergeschwindigkeit)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Geschwindigkeits-Multiplikator für die Maus (256 ist der normale " "Multiplikator)." #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "Daumenrad Umleitung" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "Lasse das Daumenrad THUMB_WHEEL HID++ Nachrichten senden (diese " "lösen Solaar Regeln aus, werden sonst aber ignoriert)." #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "Daumenrad-Scroll-Richtung" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "Kehrt die Scroll-Richtung des Daumenrads um." #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "Onboard-Profile" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "Schaltet Onboard-Profile an, welche oft die Wiederholrate und die " "Tastenbeleuchtung steuern" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "Abtastrate (ms)" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "Frequenz der Geräteabtastung, in Millisekunden" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "Onboard-Profile müssen eventuell deaktivert sein damit dies " "funktioniert." #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "Drehregler-Ereignisse umleiten" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Das Senden von CROWN-HID++-Mitteilungen beim Bedienen des " "Drehreglers erzwingen (diese lösen Solaar Regeln aus, werden sonst " "aber ignoriert)." #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "Crown weiches scrollen" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "Aktiviere Crown weiches scrollen" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "G-Tasten umleiten" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Das Senden von GKEY-HID++-Mitteilungen beim Drücken der G-Tasten " "erzwingen (diese lösen Solaar Regeln aus, werden sonst aber " "ignoriert)." #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "Die M und MR Tasten senden ggf. auch HID++ Benachrichtigungen" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "Mausrad-Rastfunktion" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "Schaltet beim Mausrad um zwischen geschwindigkeitskontrolliert mit " "einrasten und immer freilaufend." #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "Freilaufen" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "Einrastend" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "Mausrad-Rastgeschwindigkeit" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "Mausrad automatisch zwischen einrastendem und freilaufendem Modus " "umschalten.\n" "Das Mausrad läuft bei 0 stets frei und verhält sich bei 50 stets " "einrastend." #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "Tasten-/Maustastenaktionen" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Die Aktion für die Taste oder die Maustaste ändern." #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "Durch Umleitung überschrieben." #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "Das Ändern wichtiger Aktionen (wie z.B. für die linke Maustaste) " "kann zu einem unbenutzbaren System führen." #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "Taste/Maustaste umleiten" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "Die Taste/Maustaste sendet HID++-Mitteilungen (umgeleitet) oder " "initiiert Mausgesten oder Gleiten DPI" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "Umgeleitet" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "Mausgesten" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "Normal" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "Gleiten DPI" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Empfindlichkeit (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "Umschaltung Empfindlichkeit" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "Tauscht die aktuelle Empfindlichkeit und die abgespeicherte " "Empfindlichkeit wenn die Taste gedrückt wird.\n" "Falls keine gespeicherte Empfindlichkeit vorhanden ist, wird die " "aktuelle Empfindlichkeit abgespeichert" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "Aus" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Tasten abschalten" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Bestimmte Tastatur-Tasten abschalten." #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "Deaktiviert die %s-Taste." #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Betriebssystem auswählen" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Ändert Tasten so, dass Sie zum BS passen." #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Anderen Empfänger wählen" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Verbindung zu einem anderen Empfänger umschalten" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "Führt einen Linksklick aus." #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "Einfaches Tippen" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "Führt einen Rechtsklick aus." #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "Einfaches Tippen mit zwei Fingern" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "Einfaches Tippen mit drei Fingern" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "Doppeltes Tippen" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "Führt einen Doppelklick aus." #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "Doppeltes Tippen mit zwei Fingern" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "Doppeltes Tippen mit drei Fingern" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "Zieht Objekte durch Ziehen des Fingers nach doppeltem Tippen." #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "Tippen-und-Ziehen" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "Zieht Objekte durch Ziehen der Finger nach doppeltem Tippen." #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "Tippen und mit zwei Fingern ziehen" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "Tippen und mit drei Fingern ziehen" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Schaltet Tipp- und Bildschirmrand-Gesten ab (entspricht dem Drücken " "von Fn+Linksklick)." #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "Tipp- und Bildschirmrand-Gesten abschalten" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "Mit einem Finger scrollen" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "Scrollt." #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "Mit zwei Fingern scrollen" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "Horizontales Scrollen mit zwei Fingern" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "Scrollt horizontal." #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "Vertikales Scrollen mit zwei Fingern" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "Scrollt vertikal." #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "Kehrt die Scroll-Richtung um." #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "Natürlicher Bildlauf" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "Aktiviert das Daumenrad." #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "Daumenrad" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "Vom oberen Bildschirmrand wischen" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "Vom linken Bildschirmrand wischen" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "Vom rechten Bildschirmrand wischen" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "Vom unteren Bildschirmrand wischen" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "Mit zwei Fingern vom linken Bildschirmrand wischen" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "Mit zwei Fingern vom rechten Bildschirmrand wischen" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "Mit zwei Fingern vom unteren Bildschirmrand wischen" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "Mit zwei Fingern vom oberen Bildschirmrand wischen" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "Zusammenziehen-Geste zum Verkleinern; Auseinanderbewegen-Geste zum " "Vergrößern." #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "Zoom mit zwei Fingern." #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "Zusammenziehen-Geste zum Verkleinern." #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "Auseinanderbewegen-Geste zum Vergrößern." #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "Zoom mit drei Fingern." #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "Zoom mit zwei Fingern" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "Pixel Zone" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "Verhältnis Zone" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Skalierungsfaktor" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "Stellt die Cursorgeschwindigkeit ein." #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "Links" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "Äußerste linke Koordinate." #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "Ende" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "Ende Koordinate." #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Breite" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "Breite." #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Höhe" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "Höhe." #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "Zeigergeschwindigkeit." #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "Skalierung" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gesten" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "Das Maus-/Tastfeldverhalten einstellen." #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "Gesten Umleitung" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "Maus/Tastfeldgesten umleiten." #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "Gestenparameter" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Numerische Parameter einer Maus/eines Tastfelds ändern." #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "M-Taste LED's" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "Steuert die M-Tasten LED's." #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "G Tasten müssen evtl. umgeleitet sein um zu funktionieren." #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "Beleuchtet die %s Tasten." #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "MR-Taste LED" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "Steuert die MR-Taste LED." #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "Dauerhafte Tasten-/Maustastenzuordnung" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "Ändert die Zuordung für die Taste/Maustaste dauerhaft." #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "Änderungen an wichtigen Tasten oder Maustasten (wie an der linken " "Maustaste) können zu einem unbenutzbaren System führen." #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "Nebenton" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "Setze Nebentonlautstärke." #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "Equalizer" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "Setze Equalizerlautstärke." #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "Energieverwaltung" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "Ausschalten in Minuten (0 für nie)" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Keine gekoppelten Geräte." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s gekoppeltes Gerät." msgstr[1] "%(count)s gekoppelte Geräte." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Akku: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Akku: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Beleuchtung: %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Akku: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Akku: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Zugriffsfehler" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "Es wurde ein Logitech Empfänger oder Gerät (%s) gefunden, aber es " "fehlen die Berechtigungen dieses zu öffnen." #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "Falls du Solaar gerade erst installiert hast, versuche den Empfänger " "oder das Geräte zu trennen und dann erneut zu verbinden." #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "Kann nicht mit dem Gerät verbinden Fehler" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "Ein Logitech Empfänger oder Gerät wurde auf %s gefunden, aber beim " "Verbinden ist ein Fehler aufgetreten." #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "Versuche die Verbindung zu dem Geräte zu trennen und neu zu " "verbinden oder dieses aus- und wieder einzuschalten." #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Entkopplung fehlgeschlagen" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Kopplung zwischen Gerät %{device} und Empfänger %{receiver} konnte " "nicht gelöst werden." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "Der Empfänger gab einen Fehler zurück, ohne weitere Details." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "Ein anderer Solaar-Prozess läuft bereits deshalb nur dessen Fenster " "in den Vordergrund holen" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "Verwaltet Logitech Empfänger, Tastaturen, Mäuse und Grafiktablets." #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "Zusätzliche Programmierung" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "GUI Design" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Tester" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Logitech-Dokumentation" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Entkoppeln" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "Abbrechen" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "Abgeschlossen - ENTER zu ändern" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "Unvollständig" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d Wert" msgstr[1] "%d Werte" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "Änderungen erlaubt" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "Änderungen nicht erlaubt" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "Diese Einstellung ignorieren" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Beschäftigt" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Lese-/Schreiboperation fehlgeschlagen." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "Integrierte Regeln" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "Benutzerdefinierte Regeln" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "Regel" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "Unterregel" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[leer]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Solaar-Regelbearbeitung" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "Änderungen dauerhaft anwenden?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Ja" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "Nein" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Wenn Sie »Nein« wählen, gehen alle Änderungen beim Schließen von " "Solaar verloren." #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "Änderungen speichern" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "Änderungen verwerfen" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "Hier hinzufügen" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "Darüber hinzufügen" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "Darunter hinzufügen" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "Neue Regel hier hinzufügen" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "Neue Regel darüber hinzufügen" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "Neue Regel darunter hinzufügen" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "Hier einfügen" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "Darüber einfügen" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "Darunter einfügen" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "Regel hier einfügen" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "Regel darüber einfügen" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "Regel darunter einfügen" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "Regel einfügen" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "Einrückung aufheben" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "Hinzufügen" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "Oder" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "Und" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "Bedingung" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "Funktion" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "Rückgabewert" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Prozessname (Anwendung)" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "Maus Prozess" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "Zusatztasten" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "Taste" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "TasteIstGedrückt" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Aktiv" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "Gerät" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "Host" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "Einstellung" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "Prüfwert/Ereignis" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "Prüfwert Bytes" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "Mausgeste" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Aktion" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "Tastendruck" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "Mausrad-Scrollen" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "Mausklick" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "Aktivieren" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "Ausführen" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "Später" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "Neue Regel hinzufügen" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "Löschen" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "Negieren" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "Einrücken unter" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Ausschneiden" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Einfügen" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Kopieren" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "Diese Regelbearbeitung unterstützt die ausgewählte Regelkomponente " "noch nicht." #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "Angabe der Sekunden für die Verzögerung." #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "Nicht" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "Aktiver X11 Prozess. Nur zur Verwendung mit X11." #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "X11 Mausprozess. Nur zur Verwendung mit X11." #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "Mausprozess" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "Funktionsname der Benachrichtigung, die die Regelverarbeitung " "auslöst." #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Aktive Keyboardanpassung. Unter Wayland nicht immer verfügbar." #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "Umgeleitete Taste oder Maustaste ist gedrückt oder losgelassen.\n" "Verwende die Tasten-/Maustastenumleitungs- und G " "Tastenumleitungseinstellungen um Tasten sowie Maustasten umzuleiten." #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "Taste gedrückt" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "Taste losgelassen" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "Umgeleitete Taste oder Maustaste ist unten. Verwende die Tasten-/" "Maustastenumleitungs- und G Tastenumleitungseinstellungen um Tasten " "sowie Maustasten umzuleiten." #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "Parameter" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "Anfang (inklusive)" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "Ende (exklusive)" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "Bereich" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "Minimum" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "Maximum" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "Bytes %(0)d bis %(1)d, beginnend von %(2)d bis %(3)d" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "Maske" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "Bytes %(0)d bis %(1)d, Maske %(2)d" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "Typ" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "Mausgeste mit optionaler initiierender Maustaste gefolgt von keiner " "oder mehreren Bewegungen." #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "Bewegung hinzufügen" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simuliert einen kombinierten Mausklick oder Tastendruck bzw. " "loslassen einer Taste.\n" "Benötigt unter Wayland Schreibzugriff auf /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "Weitere Taste hinzufügen" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "Linksklick" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "Abgesenkt" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "Loslassen" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simuliert eine Mausradbewegung. Benötigt unter Wayland " "Schreibzugriff auf /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simuliert einen Mausklick. Benötigt unter Wayland Schreibzugriff " "auf /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "Maustaste" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "Anzahl und Aktion" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "Einen Befehl mit Parametern ausführen." #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "Argument hinzufügen" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "Umschalten" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "Wahr" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "Falsch" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "Nicht unterstützte Einstellung" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "Quellgerät" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "Das Gerät ist aktiv und die Einstellungen können geändert werden." #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "Gerät, von dem die aktuelle Benachrichtigung stammt." #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "Name des Host-Computers." #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Wert" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "Item" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "Einstellung auf dem Gerät ändern" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "Einstellung auf dem Gerät" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "offline" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: neues Gerät koppeln" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "Gib das Passwort ein auf %(name)s." #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Gib %(passcode)s ein und drücke die ENTER Taste." #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "links" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "rechts" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "Drücke %(code)s\n" "und drücke dann die links und rechts Tasten gleichzeitig." #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Kopplung fehlgeschlagen" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Überprüfen Sie, ob sich das Gerät in Reichweite befindet und der " "Akku ausreichend geladen bzw. die Batterie voll genug ist." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Es wurde ein neues Gerät festgestellt, aber es ist nicht mit diesem " "Empfänger kompatibel." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "Es sind mehr Geräte gekoppelt als der Empfänger unterstützt." #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Es gibt keine näheren Informationen zu diesem Fehler." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "Neues Gerät gefunden:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "Die drahtlose Verbindung ist nicht verschlüsselt" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Unifying Empfänger sind nur mit Unifying Geräten kompatibel." #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt Empfänger sind nur mit Bolt Geräten kompatibel." #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "Andere Empfänger sind nur mit wenigen Geräten kompatibel." #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "Das Gerät darf nicht mit mit anderen, eingeschalteten Empfängern in " "der Nähe gekoppelt sein." #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "Drücke die Kopplungstaste bis das Kopplungslicht schnell blinkt." #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "Eventuell muss das Gerät dazu aus- und wieder eingeschaltet werden." #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Schalten Sie das zu koppelnde Gerät ein." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "Falls das Gerät eingeschaltet ist, schalte es aus und wieder ein." #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "Dieser Empfänger kann an %d weiteres Gerät gekoppelt werden." msgstr[1] "\n" "\n" "Dieser Empfänger kann an %d weitere Geräte gekoppelt werden." #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Ein Abbruch zu diesem Zeitpunkt wird keine Kopplung aufbrauchen." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "Kein unterstütztes Gerät gefunden" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "Info zu %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "%s beenden" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "kein Empfänger" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "kein Status" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Scanne" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Akku" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Drahtlose Verbindung" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Beleuchtung" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Technische Details anzeigen" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Neues Gerät koppeln" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Gerät auswählen" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "Regeln bearbeiten" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Pfad" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "USB-ID" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Seriennummer" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "Wireless PID" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "Produkt-ID" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protokoll" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Unbekannt" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Abfragerate" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "Geräte ID" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "keine" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Mitteilungen" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "Kein Gerät gekoppelt." #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Nur %(max_count)s Gerät kann an diesen Empfänger gekoppelt " "werden." msgstr[1] "Bis zu %(max_count)s Geräte können an diesen Empfänger " "gekoppelt werden." #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "An diesen Empfänger kann nur ein Gerät gekoppelt werden." #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Dieser Empfänger kann an %d weiteres Gerät gekoppelt werden." msgstr[1] "Dieser Empfänger kann an %d weitere Geräte gekoppelt werden." #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "Akkuspannung" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "Spannung, die vom Akku gemeldet wird" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "Akkuladung" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "Ungefährer Ladezustand des Akkus, den das Gerät meldet" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "nächste Meldung bei " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " und der nächste, der vom Gerät mitgeteilt werden wird." #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "letzte bekannte" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "verschlüsselt" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Die drahtlose Verbindung zwischen diesem Gerät und dem Empfänger ist " "verschlüsselt." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "nicht verschlüsselt" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "Die drahtlose Verbindung zwischen diesem Gerät und dem Empfänger ist " "nicht verschlüsselt.\n" "Dies ist ein Sicherheitsproblem für Zeigegeräte, aber ein großes " "Sicherheitsrisiko für Texteingabegeräte." #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d Lux" #~ msgid "About" #~ msgstr "Über" #~ msgid "Add action" #~ msgstr "Aktion hinzufügen" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the DPI button." #~ msgstr "Die Empfindlichkeit (in DPI) durch seitliches Bewegen der " #~ "Maus ändern, während der DPI-Knopf gehalten wird." #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the button down." #~ msgstr "Passe die DPI an durch horizontale Mausbewegung bei " #~ "gleichzeitig gedrückter Taste." #~ msgid "Battery information unknown." #~ msgstr "Akkuzustand unbekannt." #~ msgid "Click to allow changes." #~ msgstr "Anklicken, um Änderungen zuzulassen." #~ msgid "Click to prevent changes." #~ msgstr "Anklicken, um Änderungen zu verhindern." #~ msgid "Count" #~ msgstr "Klickanzahl" #~ msgid "DPI Sliding Adjustment" #~ msgstr "DPI-Anpassung durch seitliches Bewegen" #~ msgid "Diverted key or button depressed or released.\n" #~ "Use the Key/Button Diversion setting to divert keys and buttons." #~ msgstr "Umgeleitete Taste oder Maustaste gedrückt bzw. losgelassen.\n" #~ "Verwende die Einstellungen für Tasten-/Maustastenumleitung um Tasten " #~ "oder Maustasten umzuleiten." #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Schaltet das Scrollen mit dem Daumen unter Linux faktisch " #~ "aus." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Schaltet das Scrollen mit dem Mausrad unter Linux faktisch " #~ "aus." #~ msgid "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "Weitere Informationen erhalten Sie in den Solaar-" #~ "Installationshinweisen\n" #~ "unter https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Ein Logitech-Empfänger (%s) wurde gefunden, wegen fehlender " #~ "Berechtigung kann aber nicht darauf zugegriffen werden." #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID++-Modus für horizontales Scrollen mit dem Daumenrad." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++ Modus für vertikales Mausrad-Scrollen." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Wenn das Gerät bereits eingeschaltet ist, schalte es aus und " #~ "wieder ein." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Wenn Sie Solaar gerade neu installiert haben, versuchen Sie " #~ "den Empfänger aus- und wieder einzustecken." #~ msgid "No Logitech receiver found" #~ msgstr "Kein Logitech-Empfänger gefunden" #~ msgid "Quit" #~ msgstr "Beenden" #~ msgid "Scroll Wheel HID++ Scrolling" #~ msgstr "Mausrad-HID++-Scrollen" #~ msgid "Send a gesture by sliding the mouse while holding the button " #~ "down." #~ msgstr "Erstelle eine Geste durch Mausbewegung bei gleichzeitig " #~ "gedrückter Taste." #~ msgid "Set to ignore if unusual device behaviour is experienced" #~ msgstr "Aktivieren zum Ignorieren, falls das Gerät sich ungewöhnlich " #~ "verhält" #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Zeigt den Status von Geräten an, die über\n" #~ "Logitech-Empfänger drahtlos verbunden sind." #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar benötigt eine udev-Datei, die nicht gefunden wurde" #~ msgid "Thumb Wheel HID++ Scrolling" #~ msgstr "Daumenrad-HID++-Scrollen" #~ msgid "Top-most coordinate." #~ msgstr "Äußerste obere Koordinate." #~ msgid "Try removing the device and plugging it back in or turning " #~ "it off and then on." #~ msgstr "Versuche das Gerät herauszuziehen und neu einzustecken bzw. " #~ "es aus und wieder an zuschalten." #~ msgid "height" #~ msgstr "Höhe" #~ msgid "top" #~ msgstr "oben" #~ msgid "unknown" #~ msgstr "unbekannt" #~ msgid "width" #~ msgstr "Breite" Solaar-1.1.20/po/el.po000066400000000000000000002242121522022367600144020ustar00rootroot00000000000000# Greek translations for solaar package. # Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2014. # Giannis Tsagatakis # Vangelis Skarmoutsos , 2017 # Athanasios Nektarios Karachalios Stagkas 2023-2024 msgid "" msgstr "" "Project-Id-Version: solaar 0.9.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-03-14 13:23+0700\n" "PO-Revision-Date: 2024-04-01 03:51+0300\n" "Last-Translator: Vangelis Skarmoutsos \n" "Language-Team: none\n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.4.2\n" #: lib/logitech_receiver/base_usb.py:45 msgid "Bolt Receiver" msgstr "Δέκτης Bolt" #: lib/logitech_receiver/base_usb.py:58 msgid "Unifying Receiver" msgstr "Δέκτης Unifying" #: lib/logitech_receiver/base_usb.py:70 lib/logitech_receiver/base_usb.py:83 #: lib/logitech_receiver/base_usb.py:97 lib/logitech_receiver/base_usb.py:111 #: lib/logitech_receiver/base_usb.py:125 msgid "Nano Receiver" msgstr "Δέκτης Nano" #: lib/logitech_receiver/base_usb.py:138 msgid "Lightspeed Receiver" msgstr "Δέκτης Lightspeed" #: lib/logitech_receiver/base_usb.py:149 msgid "EX100 Receiver 27 Mhz" msgstr "Δέκτης EX100 27 Mhz" #: lib/logitech_receiver/common.py:604 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Μπατα�ία: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:606 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Μπατα�ία: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:926 #: lib/logitech_receiver/settings_templates.py:291 msgid "Disabled" msgstr "Απενε�γοποιημένο" #: lib/logitech_receiver/hidpp20.py:927 msgid "Static" msgstr "Στατικό" #: lib/logitech_receiver/hidpp20.py:928 msgid "Pulse" msgstr "Παλμός" #: lib/logitech_receiver/hidpp20.py:929 msgid "Cycle" msgstr "Κ�κλος" #: lib/logitech_receiver/hidpp20.py:930 msgid "Boot" msgstr "Εκκίνηση" #: lib/logitech_receiver/hidpp20.py:931 msgid "Demo" msgstr "�τέμο" #: lib/logitech_receiver/hidpp20.py:932 msgid "Breathe" msgstr "Αναπνοή" #: lib/logitech_receiver/hidpp20.py:933 msgid "Ripple" msgstr "Κυματισμός" #: lib/logitech_receiver/hidpp20.py:994 msgid "Unknown Location" msgstr "Άγνωστη τοποθεσία" #: lib/logitech_receiver/hidpp20.py:995 msgid "Primary" msgstr "Π�ωτε�ον" #: lib/logitech_receiver/hidpp20.py:996 msgid "Logo" msgstr "Λογότυπο" #: lib/logitech_receiver/hidpp20.py:997 msgid "Left Side" msgstr "Α�ιστε�ή Πλε�ση" #: lib/logitech_receiver/hidpp20.py:998 msgid "Right Side" msgstr "Δεξιά Πλε�ση" #: lib/logitech_receiver/hidpp20.py:999 msgid "Combined" msgstr "Συνδυασμένο" #: lib/logitech_receiver/hidpp20.py:1000 msgid "Primary 1" msgstr "Π�ωτε�ον 1" #: lib/logitech_receiver/hidpp20.py:1001 msgid "Primary 2" msgstr "Π�ωτε�ον 2" #: lib/logitech_receiver/hidpp20.py:1002 msgid "Primary 3" msgstr "Π�ωτε�ον 3" #: lib/logitech_receiver/hidpp20.py:1003 msgid "Primary 4" msgstr "Π�ωτε�ον 4" #: lib/logitech_receiver/hidpp20.py:1004 msgid "Primary 5" msgstr "Π�ωτε�ον 5" #: lib/logitech_receiver/hidpp20.py:1005 msgid "Primary 6" msgstr "Π�ωτε�ον 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "άδεια" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "κ�ίσιμη" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "χαμηλή" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "μέση τιμή" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "καλή" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "γεμάτη" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "εκφο�τίζεται" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "επαναφο�τίζεται" #: lib/logitech_receiver/i18n.py:37 msgid "charging" msgstr "φο�τίζεται" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "χω�ίς φό�τιση" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "σχεδόν γεμάτη" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "φο�τισμένο" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "α�γή επαναφό�τιση" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "μη έγκυ�η μπατα�ία" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "θε�μικό σφάλμα" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "σφάλμα" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "π�ότυπο" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "γ�ήγο�ο" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "α�γό" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "ο�ίου χ�όνου συσκευής" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "η συσκευή δεν υποστη�ίζεται" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "πά�α πολλές συσκευές" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "ο�ίου χ�όνου ακολουθίας" #: lib/logitech_receiver/i18n.py:54 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Υλισμικό" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Άλλο" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Α�ιστε�ό κουμπί" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Δεξί κουμπί" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Κεντ�ικό κουμπί" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Πίσω κουμπί" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Εμπ�ός Κουμπί" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Κουμπί χει�ονομιών ποντικιο�" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Έξυπνος Διακόπτης" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Διακόπτης DPI" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Α�ιστε�ή κλίση" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Δεξιά κλίση" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Α�ιστε�ό κλικ" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Δεξί κλικ" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Μεσαίο κουμπί ποντικιο�" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Πίσω κουμπί ποντικιο�" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Εμπ�ός κουμπί ποντικιο�" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Πλοήγηση με κουμπιά χει�ονομιών" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Κ�λιση ποντικιο� Α�ιστε�ό κουμπί" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Κ�λιση ποντικιο� Δεξί κουμπί" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "πατημένο" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "αφημένο" #: lib/logitech_receiver/notifications.py:63 #: lib/logitech_receiver/notifications.py:115 msgid "pairing lock is closed" msgstr "η δικλείδα σ�ζευξης είναι κλειστή" #: lib/logitech_receiver/notifications.py:63 #: lib/logitech_receiver/notifications.py:115 msgid "pairing lock is open" msgstr "η δικλείδα σ�ζευξης είναι ανοιχτή" #: lib/logitech_receiver/notifications.py:80 msgid "discovery lock is closed" msgstr "η δικλείδα ανακάλυψης είναι κλειστή" #: lib/logitech_receiver/notifications.py:80 msgid "discovery lock is open" msgstr "η δικλείδα ανακάλυψης είναι ανοιχτή" #: lib/logitech_receiver/notifications.py:207 msgid "connected" msgstr "συνδεμένη" #: lib/logitech_receiver/notifications.py:207 msgid "disconnected" msgstr "αποσυνδεδεμένη" #: lib/logitech_receiver/notifications.py:233 msgid "unpaired" msgstr "διαχω�ισμένη" #: lib/logitech_receiver/notifications.py:280 msgid "powered on" msgstr "ανοιχτή" #: lib/logitech_receiver/receiver.py:345 msgid "No paired devices." msgstr "Δεν έχω συνται�ιασμένες συσκευές." #: lib/logitech_receiver/receiver.py:347 lib/solaar/ui/window.py:630 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s συζευγμένη συσκευή." msgstr[1] "%(count)s συζευγμένες συσκευές." #: lib/logitech_receiver/settings.py:617 msgid "register" msgstr "καταχώ�ηση" #: lib/logitech_receiver/settings.py:631 lib/logitech_receiver/settings.py:658 msgid "feature" msgstr "χα�ακτη�ιστικό" #: lib/logitech_receiver/settings_templates.py:144 msgid "Swap Fx function" msgstr "Αντιστ�οφή λειτου�γιών Fx" #: lib/logitech_receiver/settings_templates.py:147 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Όταν είναι ο�ισμένο, τα πλήκτ�α F1..F12 θα ενε�γοποιήσουν τις ειδικές τους " "λειτου�γίες,\n" "και π�έπει να κ�ατήσετε το πλήκτ�ο FN για να ενε�γοποιήσετε την τυπική " "λειτου�γία τους." #: lib/logitech_receiver/settings_templates.py:152 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Όταν δεν είναι ο�ισμένο, τα πλήκτ�α F1..F12 θα ενε�γοποιήσουν την τυπική " "λειτου�γία τους,\n" "και π�έπει να κ�ατήσετε το πλήκτ�ο FN για να ενε�γοποιήσετε την ειδική " "λειτου�γία τους." #: lib/logitech_receiver/settings_templates.py:160 msgid "Hand Detection" msgstr "Ανίχνευση χε�ιο�" #: lib/logitech_receiver/settings_templates.py:161 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Άνοιγμα φωτισμο� όταν τα χέ�ια β�εθο�ν πάνω από το πληκτ�ολόγιο." #: lib/logitech_receiver/settings_templates.py:168 msgid "Scroll Wheel Smooth Scrolling" msgstr "Ομαλή κ�λιση του τ�οχο� κ�λισης" #: lib/logitech_receiver/settings_templates.py:169 #: lib/logitech_receiver/settings_templates.py:402 #: lib/logitech_receiver/settings_templates.py:431 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Κατάσταση υψηλής ευαισθησίας για κατακό�υφη ολίσθηση με τον τ�οχό." #: lib/logitech_receiver/settings_templates.py:176 msgid "Side Scrolling" msgstr "Πλάγια κ�λιση" #: lib/logitech_receiver/settings_templates.py:178 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Όταν είναι απενε�γοποιημένο, πιέζοντας τον τ�οχό στο πλάι στέλνει " "π�οσα�μοσμένα γεγονότα κουμπιο�\n" "αντί των τυπικών γεγονότων πλάγιας ολίσθησης." #: lib/logitech_receiver/settings_templates.py:188 msgid "Sensitivity (DPI - older mice)" msgstr "Ευαισθησία (DPI - παλαιά ποντίκια)" #: lib/logitech_receiver/settings_templates.py:189 #: lib/logitech_receiver/settings_templates.py:958 msgid "Mouse movement sensitivity" msgstr "Ευαισθησία κίνησης ποντικιο�" #: lib/logitech_receiver/settings_templates.py:249 #: lib/logitech_receiver/settings_templates.py:261 #: lib/logitech_receiver/settings_templates.py:388 msgid "Backlight" msgstr "Οπίσθιος φωτισμός" #: lib/logitech_receiver/settings_templates.py:250 #: lib/logitech_receiver/settings_templates.py:389 msgid "Set illumination time for keyboard." msgstr "Ρ�θμιση χ�όνου φωτισμο� για το πληκτ�ολόγιο." #: lib/logitech_receiver/settings_templates.py:262 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Επίπεδο φωτισμο� στο πληκτ�ολόγιο. Οι αλλαγές που π�αγματοποιο�νται " "εφα�μόζονται μόνο στη χει�οκίνητη λειτου�γία." #: lib/logitech_receiver/settings_templates.py:293 msgid "Automatic" msgstr "Αυτόματο" #: lib/logitech_receiver/settings_templates.py:295 msgid "Manual" msgstr "Χει�οκίνητο" #: lib/logitech_receiver/settings_templates.py:297 msgid "Enabled" msgstr "Ενε�γοποιημένο" #: lib/logitech_receiver/settings_templates.py:303 msgid "Backlight Level" msgstr "Επίπεδο οπίσθιου φωτισμο�" #: lib/logitech_receiver/settings_templates.py:304 msgid "Illumination level on keyboard when in Manual mode." msgstr "" "Επίπεδο φωτισμο� στο πληκτ�ολόγιο όταν β�ίσκεται σε χει�οκίνητη λειτου�γία." #: lib/logitech_receiver/settings_templates.py:361 msgid "Backlight Delay Hands Out" msgstr "Καθυστέ�ηση οπίσθιου φωτισμο� Χέ�ια Εκτός" #: lib/logitech_receiver/settings_templates.py:362 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Καθυστέ�ηση σε δευτε�όλεπτα μέχ�ι να σβήσει ο οπίσθιος φωτισμός με τα χέ�ια " "μακ�ιά από το πληκτ�ολόγιο." #: lib/logitech_receiver/settings_templates.py:370 msgid "Backlight Delay Hands In" msgstr "Καθυστέ�ηση οπίσθιου φωτισμο� Χέ�ια Eντός" #: lib/logitech_receiver/settings_templates.py:371 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Καθυστέ�ηση σε δευτε�όλεπτα μέχ�ι να σβήσει ο οπίσθιος φωτισμός με τα χέ�ια " "κοντά στο πληκτ�ολόγιο." #: lib/logitech_receiver/settings_templates.py:379 msgid "Backlight Delay Powered" msgstr "Καθυστέ�ηση οπίσθιου φωτισμο� Με τ�οφοδοσία" #: lib/logitech_receiver/settings_templates.py:380 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Καθυστέ�ηση σε δευτε�όλεπτα μέχ�ι να σβήσει ο οπίσθιος φωτισμός με εξωτε�ική " "τ�οφοδοσία." #: lib/logitech_receiver/settings_templates.py:400 msgid "Scroll Wheel High Resolution" msgstr "Τ�οχός κ�λισης υψηλής ανάλυσης" #: lib/logitech_receiver/settings_templates.py:404 #: lib/logitech_receiver/settings_templates.py:433 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Ρ�θμιση για να αγνοείται εάν η κ�λιση είναι ασυνήθιστα γ�ήγο�η ή α�γή" #: lib/logitech_receiver/settings_templates.py:411 #: lib/logitech_receiver/settings_templates.py:442 msgid "Scroll Wheel Diversion" msgstr "Εκτ�οπή τ�οχο� κ�λισης" #: lib/logitech_receiver/settings_templates.py:413 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Κάντε τον τ�οχό κ�λισης να στέλνει ειδοποιήσεις LOWRES_WHEEL HID++ (οι " "οποίες ενε�γοποιο�ν τους κανόνες Solaar αλλά αγνοο�νται κατά τα άλλα)." #: lib/logitech_receiver/settings_templates.py:420 msgid "Scroll Wheel Direction" msgstr "Κατε�θυνση τ�οχο� κ�λισης" #: lib/logitech_receiver/settings_templates.py:421 msgid "Invert direction for vertical scroll with wheel." msgstr "Αντιστ�οφή κατε�θυνσης για κάθετη κ�λιση με τον τ�οχό." #: lib/logitech_receiver/settings_templates.py:429 msgid "Scroll Wheel Resolution" msgstr "Ανάλυση τ�οχο� κ�λισης" #: lib/logitech_receiver/settings_templates.py:444 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Κάντε τον τ�οχό κ�λισης να στέλνει ειδοποιήσεις HIRES_WHEEL HID++ (οι οποίες " "ενε�γοποιο�ν τους κανόνες Solaar αλλά αγνοο�νται διαφο�ετικά)." #: lib/logitech_receiver/settings_templates.py:453 msgid "Sensitivity (Pointer Speed)" msgstr "Ευαισθησία (ταχ�τητα δείκτη)" #: lib/logitech_receiver/settings_templates.py:454 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "" "Πολλαπλασιαστής ταχ�τητας για το ποντίκι (256 είναι ο κανονικός " "πολλαπλασιαστής)." #: lib/logitech_receiver/settings_templates.py:464 msgid "Thumb Wheel Diversion" msgstr "Εκτ�οπή τ�οχο� αντίχει�α" #: lib/logitech_receiver/settings_templates.py:466 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Κάντε τον τ�οχό αντίχει�α να στέλνει ειδοποιήσεις THUMB_WHEEL HID++ (οι " "οποίες ενε�γοποιο�ν τους κανόνες του Solaar αλλά αγνοο�νται διαφο�ετικά)." #: lib/logitech_receiver/settings_templates.py:475 msgid "Thumb Wheel Direction" msgstr "Κατε�θυνση τ�οχο� αντίχει�α" #: lib/logitech_receiver/settings_templates.py:476 msgid "Invert thumb wheel scroll direction." msgstr "Αντιστ�οφή της κατε�θυνσης κ�λισης του τ�οχο� αντίχει�α." #: lib/logitech_receiver/settings_templates.py:496 msgid "Onboard Profiles" msgstr "Ενσωματωμένα Π�οφίλ" #: lib/logitech_receiver/settings_templates.py:497 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Ενε�γοποιήστε ένα ενσωματωμένο π�οφίλ, το οποίο ελέγχει το �υθμό αναφο�άς, " "την ευαισθησία και τις ενέ�γειες των κουμπιών" #: lib/logitech_receiver/settings_templates.py:541 #: lib/logitech_receiver/settings_templates.py:581 msgid "Report Rate" msgstr "Ρυθμός αναφο�άς" #: lib/logitech_receiver/settings_templates.py:543 #: lib/logitech_receiver/settings_templates.py:583 msgid "Frequency of device movement reports" msgstr "Συχνότητα των αναφο�ών κίνησης της συσκευής" #: lib/logitech_receiver/settings_templates.py:543 #: lib/logitech_receiver/settings_templates.py:583 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1326 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "Ενδέχεται να χ�ειαστεί να θέσετε τα Π�οφίλ Ενσωματωμένου σε Απενε�γοποίηση " "για να είναι αποτελεσματικά." #: lib/logitech_receiver/settings_templates.py:623 msgid "Divert crown events" msgstr "Εκτ�οπή εκδηλώσεων crown" #: lib/logitech_receiver/settings_templates.py:624 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Κάντε το crown να στέλνει ειδοποιήσεις CROWN HID++ (οι οποίες ενε�γοποιο�ν " "τους κανόνες Solaar αλλά αγνοο�νται κατά τα άλλα)." #: lib/logitech_receiver/settings_templates.py:632 msgid "Crown smooth scroll" msgstr "Ομαλή κ�λιση Crown" #: lib/logitech_receiver/settings_templates.py:633 msgid "Set crown smooth scroll" msgstr "Ρ�θμιση ομαλής κ�λισης Crown" #: lib/logitech_receiver/settings_templates.py:641 msgid "Divert G and M Keys" msgstr "Εκτ�οπή πλήκτ�ων G και M" #: lib/logitech_receiver/settings_templates.py:642 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Κάντε τα πλήκτ�α G και M να στέλνουν ειδοποιήσεις HID++ (οι οποίες " "ενε�γοποιο�ν τους κανόνες Solaar αλλά αγνοο�νται κατά τα άλλα)." #: lib/logitech_receiver/settings_templates.py:656 msgid "Scroll Wheel Ratcheted" msgstr "Τ�οχός κ�λισης Αγκιστ�ωμένος" #: lib/logitech_receiver/settings_templates.py:657 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Αλλάξτε τον τ�οχό του ποντικιο� μεταξ� �υθμιζόμενης ταχ�τητας Αγκιστ�ωμένου " "και πάντα ελε�θε�ης πε�ιστ�οφής." #: lib/logitech_receiver/settings_templates.py:659 msgid "Freespinning" msgstr "Ελε�θε�η πε�ιστ�οφή" #: lib/logitech_receiver/settings_templates.py:659 msgid "Ratcheted" msgstr "Αγκιστ�ωμένη" #: lib/logitech_receiver/settings_templates.py:666 msgid "Scroll Wheel Ratchet Speed" msgstr "Ταχ�τητα Αγκιστ�ωμένου Τ�οχο� Κ�λισης" #: lib/logitech_receiver/settings_templates.py:668 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Χ�ησιμοποιήστε την ταχ�τητα του τ�οχο� του ποντικιο� για να εναλλάσσεστε " "ανάμεσα σε Αγκιστ�ωμένου και ελε�θε�η πε�ιστ�οφή.\n" "Ο τ�οχός του ποντικιο� είναι πάντα �υθμισμένος στο 50." #: lib/logitech_receiver/settings_templates.py:717 msgid "Key/Button Actions" msgstr "Ενέ�γειες πλήκτ�ων/κουμπιών" #: lib/logitech_receiver/settings_templates.py:719 msgid "Change the action for the key or button." msgstr "Αλλαγή της ενέ�γειας για το πλήκτ�ο ή το κουμπί." #: lib/logitech_receiver/settings_templates.py:721 msgid "Overridden by diversion." msgstr "Πα�ακάμπτεται από εκτ�οπή." #: lib/logitech_receiver/settings_templates.py:723 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Η αλλαγή σημαντικών ενε�γειών (όπως για το α�ιστε�ό κουμπί του ποντικιο�) " "μπο�εί να οδηγήσει σε ένα σ�στημα που δεν μπο�εί να χ�ησιμοποιηθεί." #: lib/logitech_receiver/settings_templates.py:886 msgid "Key/Button Diversion" msgstr "Εκτ�οπή πλήκτ�ων/κουμπιών" #: lib/logitech_receiver/settings_templates.py:887 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "Κάντε το πλήκτ�ο ή το κουμπί να στέλνει ειδοποιήσεις HID++ (εκτ�οπή) ή να " "ξεκινάει χει�ονομίες ποντικιο� ή συ�όμενο DPI" #: lib/logitech_receiver/settings_templates.py:890 #: lib/logitech_receiver/settings_templates.py:891 #: lib/logitech_receiver/settings_templates.py:892 msgid "Diverted" msgstr "Εκτ�επόμενο" #: lib/logitech_receiver/settings_templates.py:890 #: lib/logitech_receiver/settings_templates.py:891 msgid "Mouse Gestures" msgstr "Χει�ονομίες ποντικιο�" #: lib/logitech_receiver/settings_templates.py:890 #: lib/logitech_receiver/settings_templates.py:891 #: lib/logitech_receiver/settings_templates.py:892 msgid "Regular" msgstr "Κανονικό" #: lib/logitech_receiver/settings_templates.py:890 msgid "Sliding DPI" msgstr "Ολίσθαινόμενο DPI" #: lib/logitech_receiver/settings_templates.py:957 msgid "Sensitivity (DPI)" msgstr "Ευαισθησία (DPI)" #: lib/logitech_receiver/settings_templates.py:997 msgid "Sensitivity Switching" msgstr "Εναλλαγή ευαισθησίας" #: lib/logitech_receiver/settings_templates.py:999 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Εναλλαγή της τ�έχουσας ευαισθησίας και της ευαισθησίας που έχει " "απομνημονευθεί όταν πατηθεί το πλήκτ�ο ή το κουμπί.\n" "Εάν δεν υπά�χει απομνημονευμένη ευαισθησία, απλά θυμηθείτε την τ�έχουσα " "ευαισθησία" #: lib/logitech_receiver/settings_templates.py:1003 msgid "Off" msgstr "Απενε�γοποίηση" #: lib/logitech_receiver/settings_templates.py:1034 msgid "Disable keys" msgstr "Απενε�γοποίηση πλήκτ�ων" #: lib/logitech_receiver/settings_templates.py:1035 msgid "Disable specific keyboard keys." msgstr "Απενε�γοποίηση συγκεκ�ιμένων πλήκτ�ων πληκτ�ολογίου." #: lib/logitech_receiver/settings_templates.py:1038 #, python-format msgid "Disables the %s key." msgstr "Απενε�γοποίηση του πλήκτ�ου %s." #: lib/logitech_receiver/settings_templates.py:1051 #: lib/logitech_receiver/settings_templates.py:1108 msgid "Set OS" msgstr "Ο�ισμός λειτου�γικο� συστήματος" #: lib/logitech_receiver/settings_templates.py:1052 #: lib/logitech_receiver/settings_templates.py:1109 msgid "Change keys to match OS." msgstr "Αλλάξτε τα πλήκτ�α για να ται�ιάζουν με το λειτου�γικό σ�στημα." #: lib/logitech_receiver/settings_templates.py:1121 msgid "Change Host" msgstr "Αλλαγή κεντ�ικο� υπολογιστή" #: lib/logitech_receiver/settings_templates.py:1122 msgid "Switch connection to a different host" msgstr "Αλλαγή σ�νδεσης σε διαφο�ετικό κεντ�ικό υπολογιστή" #: lib/logitech_receiver/settings_templates.py:1146 msgid "Performs a left click." msgstr "Π�αγματοποιεί α�ιστε�ό κλικ." #: lib/logitech_receiver/settings_templates.py:1146 msgid "Single tap" msgstr "Απλό πάτημα" #: lib/logitech_receiver/settings_templates.py:1147 msgid "Performs a right click." msgstr "Π�αγματοποιεί δεξί κλικ." #: lib/logitech_receiver/settings_templates.py:1147 msgid "Single tap with two fingers" msgstr "Απλό πάτημα με δ�ο δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1148 msgid "Single tap with three fingers" msgstr "Απλό πάτημα με τ�ία δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1152 msgid "Double tap" msgstr "Διπλό πάτημα" #: lib/logitech_receiver/settings_templates.py:1152 msgid "Performs a double click." msgstr "Π�αγματοποιεί διπλό κλικ." #: lib/logitech_receiver/settings_templates.py:1153 msgid "Double tap with two fingers" msgstr "Διπλό πάτημα με δ�ο δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1154 msgid "Double tap with three fingers" msgstr "Διπλό πάτημα με τ�ία δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Drags items by dragging the finger after double tapping." msgstr "Σ��ετε αντικείμενα σ��οντας το δάχτυλο μετά από διπλό πάτημα." #: lib/logitech_receiver/settings_templates.py:1157 msgid "Tap and drag" msgstr "Πάτημα και σ��σιμο" #: lib/logitech_receiver/settings_templates.py:1159 msgid "Tap and drag with two fingers" msgstr "Πάτημα και σ��σιμο με δ�ο δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Drags items by dragging the fingers after double tapping." msgstr "Σ��ετε αντικείμενα σ��οντας τα δάχτυλα μετά από διπλό πάτημα." #: lib/logitech_receiver/settings_templates.py:1162 msgid "Tap and drag with three fingers" msgstr "Πάτημα και σ��σιμο με τ�ία δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1165 msgid "Suppress tap and edge gestures" msgstr "Καταστολή χει�ονομιών tap και edge" #: lib/logitech_receiver/settings_templates.py:1166 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "Απενε�γοποιεί τις χει�ονομίες tap και edge (ισοδ�ναμο με το πάτημα των " "πλήκτ�ων Fn+LeftClick)." #: lib/logitech_receiver/settings_templates.py:1168 msgid "Scroll with one finger" msgstr "Κ�λιση με ένα δάχτυλο" #: lib/logitech_receiver/settings_templates.py:1168 #: lib/logitech_receiver/settings_templates.py:1169 #: lib/logitech_receiver/settings_templates.py:1172 msgid "Scrolls." msgstr "Κ�λιση." #: lib/logitech_receiver/settings_templates.py:1169 #: lib/logitech_receiver/settings_templates.py:1172 msgid "Scroll with two fingers" msgstr "Κ�λιση με δ�ο δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1170 msgid "Scroll horizontally with two fingers" msgstr "Ο�ιζόντια κ�λιση με δ�ο δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1170 msgid "Scrolls horizontally." msgstr "Κ�λιση ο�ιζόντια." #: lib/logitech_receiver/settings_templates.py:1171 msgid "Scroll vertically with two fingers" msgstr "Κατακό�υφη κ�λιση με δ�ο δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1171 msgid "Scrolls vertically." msgstr "Κατακό�υφη Κ�λιση." #: lib/logitech_receiver/settings_templates.py:1173 msgid "Inverts the scrolling direction." msgstr "Αναστ�οφή της κατε�θυνσης κ�λισης." #: lib/logitech_receiver/settings_templates.py:1173 msgid "Natural scrolling" msgstr "Φυσική κ�λιση" #: lib/logitech_receiver/settings_templates.py:1174 msgid "Enables the thumbwheel." msgstr "Ενε�γοποίηση του τ�οχο� αντίχει�α." #: lib/logitech_receiver/settings_templates.py:1174 msgid "Thumbwheel" msgstr "Τ�οχός Αντίχει�α" #: lib/logitech_receiver/settings_templates.py:1185 #: lib/logitech_receiver/settings_templates.py:1189 msgid "Swipe from the top edge" msgstr "Σ��σιμο από την επάνω άκ�η" #: lib/logitech_receiver/settings_templates.py:1186 msgid "Swipe from the left edge" msgstr "Σ��σιμο από την α�ιστε�ή άκ�η" #: lib/logitech_receiver/settings_templates.py:1187 msgid "Swipe from the right edge" msgstr "Σ��σιμο από τη δεξιά άκ�η" #: lib/logitech_receiver/settings_templates.py:1188 msgid "Swipe from the bottom edge" msgstr "Σ��σιμο από την κάτω άκ�η" #: lib/logitech_receiver/settings_templates.py:1190 msgid "Swipe two fingers from the left edge" msgstr "Σ��σιμο δ�ο δάχτυλων από την α�ιστε�ή άκ�η" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Swipe two fingers from the right edge" msgstr "Σ��σιμο δ�ο δάχτυλων από τη δεξιά άκ�η" #: lib/logitech_receiver/settings_templates.py:1192 msgid "Swipe two fingers from the bottom edge" msgstr "Σ��σιμο δ�ο δάχτυλων από την κάτω άκ�η" #: lib/logitech_receiver/settings_templates.py:1193 msgid "Swipe two fingers from the top edge" msgstr "Σ��σιμο δ�ο δάχτυλων από την επάνω άκ�η" #: lib/logitech_receiver/settings_templates.py:1194 #: lib/logitech_receiver/settings_templates.py:1198 msgid "Pinch to zoom out; spread to zoom in." msgstr "Τσιμπήστε για σμίκ�υνση, απλώστε για μεγέθυνση." #: lib/logitech_receiver/settings_templates.py:1194 msgid "Zoom with two fingers." msgstr "Ζουμ με δ�ο δάχτυλα." #: lib/logitech_receiver/settings_templates.py:1195 msgid "Pinch to zoom out." msgstr "Τσιμπήστε για σμίκ�υνση." #: lib/logitech_receiver/settings_templates.py:1196 msgid "Spread to zoom in." msgstr "Απλώστε για μεγέθυνση." #: lib/logitech_receiver/settings_templates.py:1197 msgid "Zoom with three fingers." msgstr "Ζουμ με τ�ία δάχτυλα." #: lib/logitech_receiver/settings_templates.py:1198 msgid "Zoom with two fingers" msgstr "Ζουμ με δ�ο δάχτυλα" #: lib/logitech_receiver/settings_templates.py:1216 msgid "Pixel zone" msgstr "Ζώνη pixel" #: lib/logitech_receiver/settings_templates.py:1217 msgid "Ratio zone" msgstr "Ζώνη αναλογίας" #: lib/logitech_receiver/settings_templates.py:1218 msgid "Scale factor" msgstr "Συντελεστής κλίμακας" #: lib/logitech_receiver/settings_templates.py:1218 msgid "Sets the cursor speed." msgstr "Ο�ίζει την ταχ�τητα του δ�ομέα." #: lib/logitech_receiver/settings_templates.py:1222 msgid "Left" msgstr "Α�ιστε�ά" #: lib/logitech_receiver/settings_templates.py:1222 msgid "Left-most coordinate." msgstr "Α�ιστε�ότε�η συντεταγμένη." #: lib/logitech_receiver/settings_templates.py:1223 msgid "Bottom" msgstr "Κάτω" #: lib/logitech_receiver/settings_templates.py:1223 msgid "Bottom coordinate." msgstr "Κάτωθεν συντεταγμένη." #: lib/logitech_receiver/settings_templates.py:1224 msgid "Width" msgstr "Πλάτος" #: lib/logitech_receiver/settings_templates.py:1224 msgid "Width." msgstr "Πλάτος." #: lib/logitech_receiver/settings_templates.py:1225 msgid "Height" msgstr "Ύψος" #: lib/logitech_receiver/settings_templates.py:1225 msgid "Height." msgstr "Ύψος." #: lib/logitech_receiver/settings_templates.py:1226 msgid "Cursor speed." msgstr "Ταχ�τητα δ�ομέα." #: lib/logitech_receiver/settings_templates.py:1226 msgid "Scale" msgstr "Κλίμακα" #: lib/logitech_receiver/settings_templates.py:1232 msgid "Gestures" msgstr "Χει�ονομίες" #: lib/logitech_receiver/settings_templates.py:1233 msgid "Tweak the mouse/touchpad behaviour." msgstr "Ρ�θμιση της συμπε�ιφο�άς του ποντικιο�/του touchpad." #: lib/logitech_receiver/settings_templates.py:1249 msgid "Gestures Diversion" msgstr "Χει�ονομίες εκτ�οπής" #: lib/logitech_receiver/settings_templates.py:1250 msgid "Divert mouse/touchpad gestures." msgstr "Εκτ�οπή χει�ονομιών του ποντικιο�/του touchpad." #: lib/logitech_receiver/settings_templates.py:1266 msgid "Gesture params" msgstr "Πα�άμετ�οι χει�ονομιών" #: lib/logitech_receiver/settings_templates.py:1267 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Αλλαγή των α�ιθμητικών πα�αμέτ�ων ενός ποντικιο�/του touchpad." #: lib/logitech_receiver/settings_templates.py:1291 msgid "M-Key LEDs" msgstr "Λυχνίες LED M-Key" #: lib/logitech_receiver/settings_templates.py:1293 msgid "Control the M-Key LEDs." msgstr "Έλεγχος των λυχνιών LED του M-Key." #: lib/logitech_receiver/settings_templates.py:1297 #: lib/logitech_receiver/settings_templates.py:1328 msgid "May need G Keys diverted to be effective." msgstr "" "Μπο�εί να χ�ειαστεί εκτ�οπή των πλήκτ�ων G για να είναι αποτελεσματική." #: lib/logitech_receiver/settings_templates.py:1303 #, python-format msgid "Lights up the %s key." msgstr "Ανάβει το πλήκτ�ο %s." #: lib/logitech_receiver/settings_templates.py:1322 msgid "MR-Key LED" msgstr "MR-Πλήκτ�ο LED" #: lib/logitech_receiver/settings_templates.py:1324 msgid "Control the MR-Key LED." msgstr "Έλεγχος της λυχνίας LED πλήκτ�ου MR." #: lib/logitech_receiver/settings_templates.py:1345 msgid "Persistent Key/Button Mapping" msgstr "Μόνιμη αντιστοίχιση πλήκτ�ων/κουμπιών" #: lib/logitech_receiver/settings_templates.py:1347 msgid "Permanently change the mapping for the key or button." msgstr "Μόνιμη αλλαγή της αντιστοίχισης για το πλήκτ�ο ή το κουμπί." #: lib/logitech_receiver/settings_templates.py:1349 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Η αλλαγή σημαντικών πλήκτ�ων ή κουμπιών (όπως για πα�άδειγμα του α�ιστε�ο� " "κουμπιο� του ποντικιο�) μπο�εί να οδηγήσει σε ένα άχ�ηστο σ�στημα." #: lib/logitech_receiver/settings_templates.py:1406 msgid "Sidetone" msgstr "Sidetone" #: lib/logitech_receiver/settings_templates.py:1407 msgid "Set sidetone level." msgstr "Ο�ισμός επιπέδου sidetone." #: lib/logitech_receiver/settings_templates.py:1416 msgid "Equalizer" msgstr "Ισοσταθμιστής" #: lib/logitech_receiver/settings_templates.py:1417 msgid "Set equalizer levels." msgstr "Ρ�θμιση επιπέδων ισοσταθμιστή." #: lib/logitech_receiver/settings_templates.py:1439 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1445 msgid "Power Management" msgstr "Διαχεί�ιση ενέ�γειας" #: lib/logitech_receiver/settings_templates.py:1446 msgid "Power off in minutes (0 for never)." msgstr "Απενε�γοποίηση σε λεπτά (0 για ποτέ)." #: lib/logitech_receiver/settings_templates.py:1457 msgid "LED Control" msgstr "Έλεγχος LED" #: lib/logitech_receiver/settings_templates.py:1458 msgid "Switch control of LEDs between device and Solaar" msgstr "Εναλλαγή ελέγχου των LED μεταξ� συσκευής και Solaar" #: lib/logitech_receiver/settings_templates.py:1473 msgid "LED Zone Effects" msgstr "Εφέ ζώνης LED" #: lib/logitech_receiver/settings_templates.py:1474 msgid "Set effect for LED Zone" msgstr "Ρ�θμιση εφέ για τη ζώνη LED" #: lib/logitech_receiver/settings_templates.py:1477 msgid "Speed" msgstr "Ταχ�τητα" #: lib/logitech_receiver/settings_templates.py:1478 msgid "Period" msgstr "Πε�ίοδος" #: lib/logitech_receiver/settings_templates.py:1479 msgid "Intensity" msgstr "Ένταση" #: lib/logitech_receiver/settings_templates.py:1480 msgid "Ramp" msgstr "Κλίμακα" #: lib/logitech_receiver/settings_templates.py:1494 msgid "LEDs" msgstr "Λυχνίες LED" #: lib/solaar/ui/__init__.py:112 msgid "Another Solaar process is already running so just expose its window" msgstr "" "Μια άλλη διε�γασία Solaar εκτελείται ήδη, οπότε απλά ανοίξτε το πα�άθυ�ό της" #: lib/solaar/ui/about.py:38 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Διαχει�ίζεται δέκτες Logitech,\n" "πληκτ�ολόγια, ποντίκια και τάμπλετ." #: lib/solaar/ui/about.py:46 msgid "Additional Programming" msgstr "Π�όσθετος π�ογ�αμματισμός" #: lib/solaar/ui/about.py:47 msgid "GUI design" msgstr "Σχεδιασμός GUI" #: lib/solaar/ui/about.py:49 msgid "Testing" msgstr "Δοκιμές" #: lib/solaar/ui/about.py:57 msgid "Logitech documentation" msgstr "Τεκμη�ίωση Logitech" #: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87 #: lib/solaar/ui/window.py:199 msgid "Unpair" msgstr "Διαχω�ισμός" #: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:104 msgid "Cancel" msgstr "Ακ��ωση" #: lib/solaar/ui/common.py:35 msgid "Permissions error" msgstr "Σφάλμα δικαιωμάτων" #: lib/solaar/ui/common.py:37 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Β�έθηκε ένας δέκτης ή μια συσκευή Logitech (%s), αλλά δεν είχατε την άδεια " "να την ανοίξετε." #: lib/solaar/ui/common.py:39 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Εάν μόλις εγκαταστήσατε το Solaar, δοκιμάστε να αποσυνδέσετε το δέκτη ή τη " "συσκευή και στη συνέχεια να το επανασυνδέσετε." #: lib/solaar/ui/common.py:42 msgid "Cannot connect to device error" msgstr "Δεν είναι δυνατή η σ�νδεση σφάλμα συσκευής" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Β�έθηκε ένας δέκτης ή μια συσκευή Logitech στη διε�θυνση %s, αλλά " "πα�ουσιάστηκε σφάλμα σ�νδεσης." #: lib/solaar/ui/common.py:46 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Δοκιμάστε να αποσυνδέσετε τη συσκευή και στη συνέχεια να την επανασυνδέσετε " "ή να την απενε�γοποιήσετε και στη συνέχεια να την ενε�γοποιήσετε." #: lib/solaar/ui/common.py:49 msgid "Unpairing failed" msgstr "Αποτυχία διαχω�ισμο�" #: lib/solaar/ui/common.py:51 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Απέτυχα να διαχω�ίσω την συσκευή %{device} από τον %{receiver}." #: lib/solaar/ui/common.py:53 msgid "The receiver returned an error, with no further details." msgstr "Ο δέκτης επέστ�εψε ένα λάθος, χω�ίς άλλες πλη�οφο�ίες." #: lib/solaar/ui/config_panel.py:231 msgid "Complete - ENTER to change" msgstr "Ολοκλή�ωση - ENTER για αλλαγή" #: lib/solaar/ui/config_panel.py:231 msgid "Incomplete" msgstr "Ελλιπής" #: lib/solaar/ui/config_panel.py:476 lib/solaar/ui/config_panel.py:529 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d Τιμή" msgstr[1] "%d τιμές" #: lib/solaar/ui/config_panel.py:612 msgid "Changes allowed" msgstr "Επιτ�επτές αλλαγές" #: lib/solaar/ui/config_panel.py:613 msgid "No changes allowed" msgstr "Μη επιτ�επτές αλλαγές" #: lib/solaar/ui/config_panel.py:614 msgid "Ignore this setting" msgstr "Αγνόηση αυτής της ��θμισης" #: lib/solaar/ui/config_panel.py:659 msgid "Working" msgstr "Ε�γάζεται" #: lib/solaar/ui/config_panel.py:662 msgid "Read/write operation failed." msgstr "Αποτυχία λειτου�γίας ανάγνωσης/εγγ�αφής." #: lib/solaar/ui/diversion_rules.py:66 msgid "Built-in rules" msgstr "Ενσωματωμένοι κανόνες" #: lib/solaar/ui/diversion_rules.py:66 msgid "User-defined rules" msgstr "Κανόνες που ο�ίζονται από το χ�ήστη" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:1089 msgid "Rule" msgstr "Κανόνας" #: lib/solaar/ui/diversion_rules.py:69 lib/solaar/ui/diversion_rules.py:538 #: lib/solaar/ui/diversion_rules.py:665 msgid "Sub-rule" msgstr "Υποκανόνας" #: lib/solaar/ui/diversion_rules.py:71 msgid "[empty]" msgstr "[κενό]" #: lib/solaar/ui/diversion_rules.py:95 msgid "Make changes permanent?" msgstr "�α κάνετε τις αλλαγές μόνιμες;" #: lib/solaar/ui/diversion_rules.py:100 msgid "Yes" msgstr "�αι" #: lib/solaar/ui/diversion_rules.py:102 msgid "No" msgstr "Όχι" #: lib/solaar/ui/diversion_rules.py:107 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Αν επιλέξετε Όχι, οι αλλαγές θα χαθο�ν όταν κλείσει το Solaar." #: lib/solaar/ui/diversion_rules.py:138 msgid "Solaar Rule Editor" msgstr "Συντάκτης κανόνων Solaar" #: lib/solaar/ui/diversion_rules.py:231 msgid "Save changes" msgstr "Αποθήκευση αλλαγών" #: lib/solaar/ui/diversion_rules.py:236 msgid "Discard changes" msgstr "Από��ιψη αλλαγών" #: lib/solaar/ui/diversion_rules.py:397 msgid "Insert here" msgstr "Εισαγωγή εδώ" #: lib/solaar/ui/diversion_rules.py:399 msgid "Insert above" msgstr "Εισαγωγή επάνω" #: lib/solaar/ui/diversion_rules.py:401 msgid "Insert below" msgstr "Εισαγωγή από κάτω" #: lib/solaar/ui/diversion_rules.py:407 msgid "Insert new rule here" msgstr "Εισαγωγή νέου κανόνα εδώ" #: lib/solaar/ui/diversion_rules.py:409 msgid "Insert new rule above" msgstr "Εισαγωγή νέου κανόνα επάνω" #: lib/solaar/ui/diversion_rules.py:411 msgid "Insert new rule below" msgstr "Εισαγωγή νέου κανόνα από κάτω" #: lib/solaar/ui/diversion_rules.py:456 msgid "Paste here" msgstr "Επικόλληση εδώ" #: lib/solaar/ui/diversion_rules.py:458 msgid "Paste above" msgstr "Επικόλληση επάνω" #: lib/solaar/ui/diversion_rules.py:460 msgid "Paste below" msgstr "Επικόλληση από κάτω" #: lib/solaar/ui/diversion_rules.py:466 msgid "Paste rule here" msgstr "Επικόλληση κανόνα εδώ" #: lib/solaar/ui/diversion_rules.py:468 msgid "Paste rule above" msgstr "Επικόλληση κανόνα επάνω" #: lib/solaar/ui/diversion_rules.py:470 msgid "Paste rule below" msgstr "Επικόλληση κανόνα από κάτω" #: lib/solaar/ui/diversion_rules.py:474 msgid "Paste rule" msgstr "Επικόλληση κανόνα" #: lib/solaar/ui/diversion_rules.py:503 msgid "Flatten" msgstr "Ισοπέδωση" #: lib/solaar/ui/diversion_rules.py:536 msgid "Insert" msgstr "Εισαγωγή" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:667 #: lib/solaar/ui/diversion_rules.py:1129 msgid "Or" msgstr "Ή" #: lib/solaar/ui/diversion_rules.py:540 lib/solaar/ui/diversion_rules.py:666 #: lib/solaar/ui/diversion_rules.py:1115 msgid "And" msgstr "Και" #: lib/solaar/ui/diversion_rules.py:542 msgid "Condition" msgstr "Συνθήκη" #: lib/solaar/ui/diversion_rules.py:544 lib/solaar/ui/diversion_rules.py:1290 msgid "Feature" msgstr "Χα�ακτη�ιστικό" #: lib/solaar/ui/diversion_rules.py:545 lib/solaar/ui/diversion_rules.py:1325 msgid "Report" msgstr "Αναφο�ά" #: lib/solaar/ui/diversion_rules.py:546 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Διε�γασία" #: lib/solaar/ui/diversion_rules.py:547 msgid "Mouse process" msgstr "Διε�γασία ποντικιο�" #: lib/solaar/ui/diversion_rules.py:548 lib/solaar/ui/diversion_rules.py:1362 msgid "Modifiers" msgstr "Τ�οποποιητικοί Πα�άγοντες" #: lib/solaar/ui/diversion_rules.py:549 lib/solaar/ui/diversion_rules.py:1414 msgid "Key" msgstr "Πλήκτ�ο" #: lib/solaar/ui/diversion_rules.py:550 lib/solaar/ui/diversion_rules.py:1455 msgid "KeyIsDown" msgstr "ΤοΠλήκτ�οΕίναιΠατημένο" #: lib/solaar/ui/diversion_rules.py:551 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Ενε�γό" #: lib/solaar/ui/diversion_rules.py:552 lib/solaar/ui/diversion_rules.py:2217 #: lib/solaar/ui/diversion_rules.py:2269 lib/solaar/ui/diversion_rules.py:2319 msgid "Device" msgstr "Συσκευή" #: lib/solaar/ui/diversion_rules.py:553 lib/solaar/ui/diversion_rules.py:2295 msgid "Host" msgstr "ΟικοδεσπότηςΥποδοχέας" #: lib/solaar/ui/diversion_rules.py:554 lib/solaar/ui/diversion_rules.py:2337 msgid "Setting" msgstr "Ρ�θμιση" #: lib/solaar/ui/diversion_rules.py:555 lib/solaar/ui/diversion_rules.py:1470 #: lib/solaar/ui/diversion_rules.py:1519 msgid "Test" msgstr "Δοκιμή" #: lib/solaar/ui/diversion_rules.py:556 lib/solaar/ui/diversion_rules.py:1633 msgid "Test bytes" msgstr "Δοκιμαστικά bytes" #: lib/solaar/ui/diversion_rules.py:557 lib/solaar/ui/diversion_rules.py:1734 msgid "Mouse Gesture" msgstr "Χει�ονομία ποντικιο�" #: lib/solaar/ui/diversion_rules.py:561 msgid "Action" msgstr "Ενέ�γεια" #: lib/solaar/ui/diversion_rules.py:563 lib/solaar/ui/diversion_rules.py:1844 msgid "Key press" msgstr "Πάτημα πλήκτ�ου" #: lib/solaar/ui/diversion_rules.py:564 lib/solaar/ui/diversion_rules.py:1895 msgid "Mouse scroll" msgstr "Κ�λιση ποντικιο�" #: lib/solaar/ui/diversion_rules.py:565 lib/solaar/ui/diversion_rules.py:1956 msgid "Mouse click" msgstr "Κλικ ποντικιο�" #: lib/solaar/ui/diversion_rules.py:566 msgid "Set" msgstr "Ο�ισμός" #: lib/solaar/ui/diversion_rules.py:567 lib/solaar/ui/diversion_rules.py:2026 msgid "Execute" msgstr "Εκτέλεση" #: lib/solaar/ui/diversion_rules.py:568 lib/solaar/ui/diversion_rules.py:1160 msgid "Later" msgstr "Α�γότε�α" #: lib/solaar/ui/diversion_rules.py:597 msgid "Insert new rule" msgstr "Εισαγωγή νέου κανόνα" #: lib/solaar/ui/diversion_rules.py:617 lib/solaar/ui/diversion_rules.py:1681 #: lib/solaar/ui/diversion_rules.py:1786 lib/solaar/ui/diversion_rules.py:1985 msgid "Delete" msgstr "Διαγ�αφή" #: lib/solaar/ui/diversion_rules.py:639 msgid "Negate" msgstr "Α�νηση" #: lib/solaar/ui/diversion_rules.py:663 msgid "Wrap with" msgstr "Τ�λιγμα με" #: lib/solaar/ui/diversion_rules.py:685 msgid "Cut" msgstr "Αποκοπή" #: lib/solaar/ui/diversion_rules.py:700 msgid "Paste" msgstr "Επικόλληση" #: lib/solaar/ui/diversion_rules.py:706 msgid "Copy" msgstr "Αντιγ�αφή" #: lib/solaar/ui/diversion_rules.py:1070 msgid "This editor does not support the selected rule component yet." msgstr "" "Αυτός ο συντάκτης δεν υποστη�ίζει ακόμη την επιλεγμένη συνιστώσα κανόνα." #: lib/solaar/ui/diversion_rules.py:1140 msgid "Number of seconds to delay." msgstr "Α�ιθμός δευτε�ολέπτων καθυστέ�ησης." #: lib/solaar/ui/diversion_rules.py:1178 msgid "Not" msgstr "Μη" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "Ενε�γή διαδικασία X11. Για χ�ήση μόνο στο X11." #: lib/solaar/ui/diversion_rules.py:1217 msgid "X11 mouse process. For use in X11 only." msgstr "Διαδικασία ποντικιο� X11. Για χ�ήση μόνο στο X11." #: lib/solaar/ui/diversion_rules.py:1234 msgid "MouseProcess" msgstr "ΔιαδικασίαΠοντικιο�" #: lib/solaar/ui/diversion_rules.py:1258 msgid "Feature name of notification triggering rule processing." msgstr "" "Όνομα χα�ακτη�ιστικο� της ειδοποίησης που ενε�γοποιεί την επεξε�γασία κανόνα." #: lib/solaar/ui/diversion_rules.py:1305 msgid "Report number of notification triggering rule processing." msgstr "" "Α�ιθμός αναφο�άς της ειδοποίησης που ενε�γοποιεί την επεξε�γασία του κανόνα." #: lib/solaar/ui/diversion_rules.py:1338 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" "Ενε�γοί τ�οποποιο�μενοι πα�άγοντες πληκτ�ολογίου. Δεν είναι πάντα διαθέσιμο " "στο Wayland." #: lib/solaar/ui/diversion_rules.py:1378 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Εκτ�οπή πλήκτ�ου ή κουμπιο� πατημένο ή απελευθε�ωμένο.\n" "Χ�ησιμοποιήστε τις �υθμίσεις εκτ�οπής πλήκτ�ων/κουμπιών και εκτ�οπής " "πλήκτ�ων G για να εκτ�έψετε πλήκτ�α και κουμπιά." #: lib/solaar/ui/diversion_rules.py:1387 msgid "Key down" msgstr "Πλήκτ�ο κάτω" #: lib/solaar/ui/diversion_rules.py:1390 msgid "Key up" msgstr "Πλήκτ�ο πάνω" #: lib/solaar/ui/diversion_rules.py:1430 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Το πλήκτ�ο ή το κουμπί εκτ�οπής είναι π�ος το πα�όν κατεβασμένο.\n" "Χ�ησιμοποιήστε τις �υθμίσεις εκτ�οπής πλήκτ�ων/κουμπιών και εκτ�οπής " "πλήκτ�ων G για να εκτ�έψετε πλήκτ�α και κουμπιά." #: lib/solaar/ui/diversion_rules.py:1468 msgid "Test condition on notification triggering rule processing." msgstr "" "Συνθήκη δοκιμής για την ειδοποίηση που ενε�γοποιεί την επεξε�γασία κανόνα." #: lib/solaar/ui/diversion_rules.py:1472 msgid "Parameter" msgstr "Πα�άμετ�ος" #: lib/solaar/ui/diversion_rules.py:1534 msgid "begin (inclusive)" msgstr "α�χή ( συμπε�ιλαμβανομένου)" #: lib/solaar/ui/diversion_rules.py:1535 msgid "end (exclusive)" msgstr "τέλος ( αποκλειστικό)" #: lib/solaar/ui/diversion_rules.py:1543 msgid "range" msgstr "ε��ος" #: lib/solaar/ui/diversion_rules.py:1546 msgid "minimum" msgstr "ελάχιστο" #: lib/solaar/ui/diversion_rules.py:1547 msgid "maximum" msgstr "μέγιστο" #: lib/solaar/ui/diversion_rules.py:1549 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "bytes %(0)d έως %(1)d, από %(2)d έως %(3)d" #: lib/solaar/ui/diversion_rules.py:1552 lib/solaar/ui/diversion_rules.py:1553 msgid "mask" msgstr "μάσκα" #: lib/solaar/ui/diversion_rules.py:1554 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "bytes %(0)d έως %(1)d, μάσκα %(2)d" #: lib/solaar/ui/diversion_rules.py:1563 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Δοκιμή bit ή ε��ους σε bytes στο μήνυμα ειδοποίησης που ενε�γοποιεί την " "επεξε�γασία κανόνα." #: lib/solaar/ui/diversion_rules.py:1573 msgid "type" msgstr "τ�πος" #: lib/solaar/ui/diversion_rules.py:1661 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Χει�ονομία ποντικιο� με π�οαι�ετικό κουμπί εκκίνησης που ακολουθείται από " "μηδέν ή πε�ισσότε�ες κινήσεις του ποντικιο�." #: lib/solaar/ui/diversion_rules.py:1666 msgid "Add movement" msgstr "Π�οσθήκη κίνησης" #: lib/solaar/ui/diversion_rules.py:1760 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Π�οσομοίωση ενός χο�δισμένου πλήκτ�ου κλικ ή πάτημα ή απελευθέ�ωση.\n" "Στο Wayland απαιτεί π�όσβαση εγγ�αφής στο /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1765 msgid "Add key" msgstr "Π�οσθήκη πλήκτ�ου" #: lib/solaar/ui/diversion_rules.py:1768 msgid "Click" msgstr "Κλικ" #: lib/solaar/ui/diversion_rules.py:1771 msgid "Depress" msgstr "Απελευθέ�ωση" #: lib/solaar/ui/diversion_rules.py:1774 msgid "Release" msgstr "Αποδέσμευση" #: lib/solaar/ui/diversion_rules.py:1859 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Π�οσομοίωση κ�λισης ποντικιο�.\n" "Στο Wayland απαιτεί π�όσβαση εγγ�αφής στο /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1915 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Π�οσομοίωση ενός κλικ του ποντικιο�.\n" "Στο Wayland απαιτεί π�όσβαση εγγ�αφής στο /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1918 msgid "Button" msgstr "Κουμπί" #: lib/solaar/ui/diversion_rules.py:1919 msgid "Count and Action" msgstr "Καταμέτ�ηση και Δ�άση" #: lib/solaar/ui/diversion_rules.py:1968 msgid "Execute a command with arguments." msgstr "Εκτέλεση μιας εντολής με ο�ίσματα." #: lib/solaar/ui/diversion_rules.py:1971 msgid "Add argument" msgstr "Π�οσθήκη ο�ίσματος" #: lib/solaar/ui/diversion_rules.py:2046 msgid "Toggle" msgstr "Εναλλαγή" #: lib/solaar/ui/diversion_rules.py:2047 msgid "True" msgstr "Αληθές" #: lib/solaar/ui/diversion_rules.py:2048 msgid "False" msgstr "Ψευδές" #: lib/solaar/ui/diversion_rules.py:2061 msgid "Unsupported setting" msgstr "Μη υποστη�ιζόμενη ��θμιση" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2243 #: lib/solaar/ui/diversion_rules.py:2325 lib/solaar/ui/diversion_rules.py:2568 #: lib/solaar/ui/diversion_rules.py:2586 msgid "Originating device" msgstr "Συσκευή π�οέλευσης" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "Η συσκευή είναι ενε�γή και οι �υθμίσεις της μπο�ο�ν να αλλάξουν." #: lib/solaar/ui/diversion_rules.py:2265 msgid "Device that originated the current notification." msgstr "Συσκευή από την οποία π�οήλθε η τ�έχουσα ειδοποίηση." #: lib/solaar/ui/diversion_rules.py:2278 msgid "Name of host computer." msgstr "Όνομα του υπολογιστή υποδοχής." #: lib/solaar/ui/diversion_rules.py:2345 msgid "Value" msgstr "Τιμή" #: lib/solaar/ui/diversion_rules.py:2353 msgid "Item" msgstr "Στοιχείο" #: lib/solaar/ui/diversion_rules.py:2627 msgid "Change setting on device" msgstr "Αλλαγή ��θμισης στη συσκευή" #: lib/solaar/ui/diversion_rules.py:2643 msgid "Setting on device" msgstr "Ρ�θμιση στη συσκευή" #: lib/solaar/ui/notify.py:118 msgid "unspecified reason" msgstr "αδιευκ�ίνιστος λόγος" #: lib/solaar/ui/pair_window.py:126 lib/solaar/ui/pair_window.py:260 #: lib/solaar/ui/pair_window.py:296 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: ζε�ξη νέας συσκευής" #: lib/solaar/ui/pair_window.py:127 #, python-format msgid "Enter passcode on %(name)s." msgstr "Πληκτ�ολογήστε τον κωδικό π�όσβασης στο %(name)s." #: lib/solaar/ui/pair_window.py:130 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" "Πληκτ�ολογήστε %(passcode)s και, στη συνέχεια, πατήστε το πλήκτ�ο enter." #: lib/solaar/ui/pair_window.py:133 msgid "left" msgstr "α�ιστε�ά" #: lib/solaar/ui/pair_window.py:133 msgid "right" msgstr "δεξιά" #: lib/solaar/ui/pair_window.py:135 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Πατήστε %(code)s\n" "και στη συνέχεια πατήστε ταυτόχ�ονα το α�ιστε�ό και το δεξί κουμπί." #: lib/solaar/ui/pair_window.py:192 msgid "Pairing failed" msgstr "Αποτυχία συνται�ίασματος" #: lib/solaar/ui/pair_window.py:194 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Σιγου�έψου ότι η συσκευή είναι εντός εμβέλειας, και έχει επα�κώς φο�τισμένη " "μπατα�ία." #: lib/solaar/ui/pair_window.py:196 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "Εντοπίστηκε μια συσκευή, αλλά δεν είναι συμβατή με αυτόν τον δέκτη." #: lib/solaar/ui/pair_window.py:198 msgid "More paired devices than receiver can support." msgstr "" "Πε�ισσότε�ες συζευγμένες συσκευές από όσες μπο�εί να υποστη�ίξει ο δέκτης." #: lib/solaar/ui/pair_window.py:200 msgid "No further details are available about the error." msgstr "Δεν υπά�χουν άλλες πλη�οφο�ίες για το σφάλμα." #: lib/solaar/ui/pair_window.py:214 msgid "Found a new device:" msgstr "Β�ήκα μια νέα συσκευή:" #: lib/solaar/ui/pair_window.py:239 msgid "The wireless link is not encrypted" msgstr "Η ασ��ματη σ�νδεση είναι χω�ίς κ�υπτογ�άφηση" #: lib/solaar/ui/pair_window.py:268 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Οι δέκτες Unifying είναι συμβατοί μόνο με συσκευές Unifying." #: lib/solaar/ui/pair_window.py:270 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Οι δέκτες Bolt είναι συμβατοί μόνο με συσκευές Bolt." #: lib/solaar/ui/pair_window.py:272 msgid "Other receivers are only compatible with a few devices." msgstr "Άλλοι δέκτες είναι συμβατοί μόνο με λίγες συσκευές." #: lib/solaar/ui/pair_window.py:274 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" "Η συσκευή δεν π�έπει να είναι συνδεδεμένη με έναν κοντινό ενε�γοποιημένο " "δέκτη." #: lib/solaar/ui/pair_window.py:278 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Πιέστε ένα κουμπί ή πλήκτ�ο ζε�ξης μέχ�ι να αναβοσβήσει γ�ήγο�α η φωτεινή " "ένδειξη ζε�ξης." #: lib/solaar/ui/pair_window.py:280 msgid "You may have to first turn the device off and on again." msgstr "" "Ίσως χ�ειαστεί π�ώτα να απενε�γοποιήσετε και να ενε�γοποιήσετε ξανά τη " "συσκευή." #: lib/solaar/ui/pair_window.py:282 msgid "Turn on the device you want to pair." msgstr "Άνοιξε την συσκευή που θέλεις να συνται�ιάξεις." #: lib/solaar/ui/pair_window.py:284 msgid "If the device is already turned on, turn it off and on again." msgstr "" "Εάν η συσκευή είναι ήδη ενε�γοποιημένη, απενε�γοποιήστε την και " "ενε�γοποιήστε την ξανά." #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Αυτός ο δέκτης έχει %d ζε�ξη που απομένει." msgstr[1] "" "\n" "\n" "Αυτός ο δέκτης έχει %d ζε�ξεις που απομένουν." #: lib/solaar/ui/pair_window.py:294 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Η ακ��ωση σε αυτό το σημείο δεν θα χ�ησιμοποιήσει μια αντιστοίχιση." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "Δεν β�έθηκε υποστη�ιζόμενη συσκευή" #: lib/solaar/ui/tray.py:63 lib/solaar/ui/window.py:321 #, python-format msgid "About %s" msgstr "Πε�ί %s" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "Quit %s" msgstr "Έξοδος %s" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:302 msgid "no receiver" msgstr "χω�ίς δέκτη" #: lib/solaar/ui/tray.py:315 lib/solaar/ui/tray.py:320 msgid "offline" msgstr "εκτός σ�νδεσης" #: lib/solaar/ui/tray.py:318 msgid "no status" msgstr "χω�ίς κατάσταση" #: lib/solaar/ui/window.py:99 msgid "Scanning" msgstr "Σά�ωση" #: lib/solaar/ui/window.py:132 msgid "Battery" msgstr "Μπατα�ία" #: lib/solaar/ui/window.py:135 msgid "Wireless Link" msgstr "Ασ��ματη ζε�ξη" #: lib/solaar/ui/window.py:139 msgid "Lighting" msgstr "Φωτισμός" #: lib/solaar/ui/window.py:173 msgid "Show Technical Details" msgstr "Εμφάνιση τεχνικών λεπτομε�ειών" #: lib/solaar/ui/window.py:189 msgid "Pair new device" msgstr "Συνταί�ιασμα νέας συσκευής" #: lib/solaar/ui/window.py:207 msgid "Select a device" msgstr "Επέλεξε μια συσκευή" #: lib/solaar/ui/window.py:324 msgid "Rule Editor" msgstr "Συντάκτης κανόνων" #: lib/solaar/ui/window.py:543 msgid "Path" msgstr "Διαδ�ομή" #: lib/solaar/ui/window.py:546 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:549 lib/solaar/ui/window.py:551 #: lib/solaar/ui/window.py:566 lib/solaar/ui/window.py:568 msgid "Serial" msgstr "Serial" #: lib/solaar/ui/window.py:555 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:557 msgid "Wireless PID" msgstr "Wireless PID" #: lib/solaar/ui/window.py:559 msgid "Product ID" msgstr "Αναγνω�ιστικό π�οϊόντος" #: lib/solaar/ui/window.py:561 msgid "Protocol" msgstr "Π�ωτόκολλο" #: lib/solaar/ui/window.py:561 msgid "Unknown" msgstr "Άγνωστο" #: lib/solaar/ui/window.py:563 msgid "Polling rate" msgstr "Ρυθμός ανανέωσης" #: lib/solaar/ui/window.py:570 msgid "Unit ID" msgstr "Unit ID" #: lib/solaar/ui/window.py:584 msgid "Notifications" msgstr "Ειδοποιήσεις" #: lib/solaar/ui/window.py:628 msgid "No device paired." msgstr "Δεν υπά�χει αντιστοιχισμένη συσκευή." #: lib/solaar/ui/window.py:637 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "" "Έως και %(max_count)s συσκευή μπο�εί να συνδεθεί με αυτόν τον δέκτη." msgstr[1] "" "Έως και %(max_count)s συσκευές μπο�ο�ν να αντιστοιχιστο�ν σε αυτόν τον δέκτη." #: lib/solaar/ui/window.py:648 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Αυτός ο δέκτης έχει %d ζε�ξη που απομένει." msgstr[1] "Αυτός ο δέκτης έχει %d ζε�ξεις που απομένουν." #: lib/solaar/ui/window.py:705 msgid "Battery Voltage" msgstr "Τάση μπατα�ίας" #: lib/solaar/ui/window.py:707 msgid "Voltage reported by battery" msgstr "Τάση που αναφέ�εται από την μπατα�ία" #: lib/solaar/ui/window.py:709 msgid "Battery Level" msgstr "Στάθμη μπατα�ίας" #: lib/solaar/ui/window.py:711 msgid "Approximate level reported by battery" msgstr "Π�οσεγγιστικό επίπεδο που αναφέ�εται από την μπατα�ία" #: lib/solaar/ui/window.py:718 lib/solaar/ui/window.py:720 msgid "next reported " msgstr "επόμενο αναφε�όμενο " #: lib/solaar/ui/window.py:721 msgid " and next level to be reported." msgstr " και το επόμενο επίπεδο που θα αναφε�θεί." #: lib/solaar/ui/window.py:737 msgid "encrypted" msgstr "κ�υπτογ�αφημένη" #: lib/solaar/ui/window.py:739 msgid "The wireless link between this device and its receiver is encrypted." msgstr "" "Η ασ��ματη ζε�ξη μεταξ� αυτής της συσκευής και του δέκτη είναι " "κ�υπτογ�αφημένη." #: lib/solaar/ui/window.py:741 msgid "not encrypted" msgstr "χω�ίς κ�υπτογ�άφηση" #: lib/solaar/ui/window.py:745 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "Η ασ��ματη σ�νδεση μεταξ� αυτής της συσκευής και του δέκτη της δεν είναι " "κ�υπτογ�αφημένη.\n" "Αυτό είναι ένα ζήτημα ασφάλειας για τις συσκευές επισήμανσης και ένα " "σημαντικό ζήτημα ασφάλειας για τις συσκευές εισαγωγής κειμένου." #: lib/solaar/ui/window.py:761 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "Turn illumination on or off on keyboard." #~ msgstr "Ενε�γοποίηση ή απενε�γοποίηση του φωτισμο� στο πληκτ�ολόγιο." #~ msgid "Polling Rate (ms)" #~ msgstr "Ρυθμός κλήσεων (ms)" #~ msgid "May also make M keys and MR key send HID++ notifications" #~ msgstr "" #~ "Μπο�εί επίσης να κάνει τα κλειδιά M και MR να στέλνουν ειδοποιήσεις HID++" #, python-format #~ msgid "Battery: %(level)s" #~ msgstr "Μπατα�ία: %(level)s" #, python-format #~ msgid "Battery: %(percent)d%%" #~ msgstr "Μπατα�ία: %(percent)d%%" #, python-format #~ msgid "Lighting: %(level)s lux" #~ msgstr "Φωτισμός: %(level)s lux" #, python-format #~ msgid "%(rate)d ms (%(rate_hz)dHz)" #~ msgstr "%(rate)d ms (%(rate_hz)dHz)" #~ msgid "none" #~ msgstr "καμία" #~ msgid "Only one device can be paired to this receiver." #~ msgstr "Μόνο μία συσκευή μπο�εί να συνδεθεί με αυτόν τον δέκτη." #~ msgid "last known" #~ msgstr "τελευταία γνωστή" #~ msgid " paired devices." #~ msgstr " συνται�ιασμένες συσκευές." #~ msgid "1 paired device." #~ msgstr "Μία συνται�ιασμένη συσκευή" #~ msgid "Count" #~ msgstr "Πλήθος" #~ msgid "Device originated the current notification." #~ msgstr "Η συσκευή από την οποία π�οήλθε η τ�έχουσα ειδοποίηση." #, python-format #~ msgid "" #~ "Found a Logitech Receiver (%s), but did not have permission to open it." #~ msgstr "" #~ "Β�έθηκε ένας δέκτης Logitech (%s), αλλά δεν έχετε δικαίωμα να τον " #~ "ανοίξετε." #~ msgid "Found a new device" #~ msgstr "Β�έθηκε νέα συσκευή" #~ msgid "" #~ "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "" #~ "Αν η συσκευή είναι ήδη ανοικτή,\n" #~ "κλείσε την και μετά άνοιξε την ξανά." #~ msgid "" #~ "If you've just installed Solaar, try removing the receiver and plugging " #~ "it back in." #~ msgstr "" #~ "Εάν μόλις κάνατε εγκατάσταση του Solaar, δοκιμάστε να αφαι�έσετε τον " #~ "δέκτη και να τον ξανασυνδέσετε." #~ msgid "No Logitech device found" #~ msgstr "Δεν β�έθηκε συσκευή Logitech" #~ msgid "No Logitech receiver found" #~ msgstr "Δεν β�έθηκε δέκτης Logitech" #~ msgid "No device paired" #~ msgstr "Χω�ίς συνται�ιασμένες συσκευές" #~ msgid "Only one device can be paired to this receiver" #~ msgstr "Μόνο μία συσκευή μπο�εί να συνται�ιαστεί σε αυτόν τον δέκτη" #~ msgid "" #~ "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "" #~ "Δείχνει την κατάσταση των συσκευών που συνδέονται\n" #~ "ασ��ματα σε δέκτες Logitech." #~ msgid "Smooth Scrolling" #~ msgstr "Ομαλή κ�λιση" #, python-format #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Ο δέκτης υποστη�ίζει μέχ�ι %d συνται�ιασμένες συσκευές." #~ msgid "The receiver was unplugged." #~ msgstr "Ο δέκτης αποσυνδέθηκε." #~ msgid "" #~ "The wireless link between this device and its receiver is not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices (keyboards, " #~ "numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties within " #~ "range." #~ msgstr "" #~ "Η ασ��ματη ζε�ξη μεταξ� αυτής της συσκευής και του δέκτη της είναι χω�ίς " #~ "κ�υπτογ�άφηση.\n" #~ "\n" #~ "Για συσκευές κατάδειξης (ποντίκια, ιχνόσφαι�ες, επιφάνειες αφής), αυτό " #~ "είναι ένα μικ�ό π�όβλημα ασφάλειας.\n" #~ "\n" #~ "Είναι όμως μεγάλο π�όβλημα ασφάλειας για συσκευές εισαγωγής κειμένου " #~ "(πληκτ�ολόγια),\n" #~ "μιας και το κείμενο μπο�εί να υποκλαπεί από κακόβουλους εντός εμβέλειας." #~ msgid "USB id" #~ msgstr "USB id" #~ msgid "Up to %d devices can be paired to this receiver" #~ msgstr "Μέχ�ι %d συσκευές μπο�ο�ν να συνται�ιαστο�ν σε αυτόν τον δέκτη" #~ msgid "closed" #~ msgstr "κλειστή" #~ msgid "height" #~ msgstr "�ψος" #~ msgid "lux" #~ msgstr "lux" #~ msgid "open" #~ msgstr "ανοιχτή" #~ msgid "pair new device" #~ msgstr "συνταί�ιασε μια νέα συσκευή" #~ msgid "paired devices" #~ msgstr "συνται�ιασμένες συσκευές" #~ msgid "pairing lock is " #~ msgstr "το κλείδωμα ται�ιάσματος είναι" #~ msgid "unknown" #~ msgstr "άγνωστο" #~ msgid "width" #~ msgstr "πλάτος" Solaar-1.1.20/po/es.po000066400000000000000000001665641522022367600144300ustar00rootroot00000000000000# Spanish translations for Solaar package. # Copyright (C) 2021 THE Solaar's COPYRIGHT HOLDER. # This file is distributed under the same license as the Solaar package. # Marc Serra , 2021. # msgid "" msgstr "" "Project-Id-Version: solaar 1.1.7\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2023-12-28 18:53+0100\n" "Last-Translator: Jose Luis Tirado \n" "Language-Team: none\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.4.1\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "Receptor Bolt" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "Receptor Unifying" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "Receptor Nano" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "Receptor Lightspeed" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "Receptor EX100 27 Mhz" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "vacía" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "crítica" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "baja" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "media" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "buena" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "llena" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "descargando" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "recargando" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "cargando" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "no cargando" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "casi llena" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "cargado" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "recarga lenta" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "batería no válida" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "error térmico" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "error" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "estándar" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "rápido" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "lento" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "tiempo agotado para el dispositivo" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "dispositivo no soportado" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "demasiados dispositivos" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "tiempo agotado de secuencia" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Gestor de arranque" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Otros" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "Botón Izquierdo" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "Botón Derecho" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "Botón Central" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "Botón Atrás" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "Botón Adelante" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "Botón Gestos Ratón" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "Cambio inteligente" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "Selector DPI" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "Inclinación a la Izquierda" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "Inclinación a la Derecha" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "Clic Izquierdo" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "Clic Derecho" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "Clic Central Ratón" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "Clic Atrás Ratón" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "Clic Adelante Ratón" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "Navegación con Botón de Gestos" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "Botón desplazamiento a la Izquierda" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "Botón de desplazamiento a la Derecha" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "pulsado" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "liberado" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "el bloqueo de vinculación está cerrado" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "el bloqueo de vinculación está abierto" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "el bloqueo de descubrimiento está cerrado" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "el bloqueo de detección está abierto" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "conectado" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "desconectado" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "desvinculado" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "encendido" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "registrar" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "característica" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Intercambiar función Fx" #: lib/logitech_receiver/settings_templates.py:140 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Al activarse, las teclas F1..F12 activarán sus funciones especiales,\n" "y debe mantener pulsada la tecla FN para activar su función estándar." #: lib/logitech_receiver/settings_templates.py:142 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Al desactivarse, las teclas F1..F12 activarán sus funciones estándar,\n" "y debe mantener pulsada la tecla FN para activar su función especial." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Detección de manos" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Encender la iluminación cuando las manos pasen sobre el teclado." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "Desplazamiento suave de la rueda de desplazamiento" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Modo de alta sensibilidad para desplazamiento vertical con la rueda." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Desplazamiento lateral" #: lib/logitech_receiver/settings_templates.py:167 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Al desactivarse, presionar la rueda lateralmente envía eventos de botones " "personalizados\n" "en vez de los eventos estándar de desplazamiento lateral." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "Sensibilidad (DPI - ratones más viejos)" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "Sensibildad de movimientro del ratón" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Retroiluminación" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "Establecer el tiempo de iluminación para el teclado." #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "Encencer o apagar la iluminación del teclado." #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "Rueda de Desplazamiento de Alta Resolución" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" "Establecido para ignorar si el desplazamiento es anormalmente rápido o lento" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "Desvío de la Rueda de Desplazamiento" #: lib/logitech_receiver/settings_templates.py:249 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Hacer que la rueda de desplazamiento envíe notificaciones HID++ de " "LOWRES_WHEEL (que activan reglas de Solaar, pero que, por lo demás, se " "ignoran)." #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "Dirección de la Rueda de Desplazamiento" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "Invertir dirección para desplazamiento vertical con la rueda." #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "Resolución de la Rueda de Desplazamiento" #: lib/logitech_receiver/settings_templates.py:279 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Hacer que la rueda de desplazamiento envíe notificaciones HID++ de " "HIRES_WHEEL (que activan las reglas de Solaar, pero que, por lo demás, se " "ignoran)." #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Sensibilidad (Velocidad del puntero)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "" "Multiplicador de velocidad para el ratón (256 es un multiplicador normal)" #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "Desvío de la Rueda del Pulgar" #: lib/logitech_receiver/settings_templates.py:301 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Hacer que la rueda del pulgar envíe notificaciones THUMB_WHEEL HID++ (que " "desencadenan reglas de Solaar, pero que, por lo demás, se ignoran)." #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "Dirección de la Rueda del Pulgar" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "Invertir la dirección de desplazamiento de la rueda del pulgar." #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "Perfiles integrados" #: lib/logitech_receiver/settings_templates.py:320 msgid "" "Enable onboard profiles, which often control report rate and keyboard " "lighting" msgstr "" "Habilite los perfiles integrados, que a menudo controlan la tasa de informes " "y iluminación del teclado" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "Tasa de Sondeo (ms)" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "Frecuencia de sondeo del dispositivo, en milisegundos" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "Es posible que los Perfiles integrados se desactiven para que sean efectivos." #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "Desviar eventos de la corona" #: lib/logitech_receiver/settings_templates.py:366 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Hacer que la corona envíe notificaciones de CROWN HID ++ (que activan las " "reglas de Solaar, pero que, por lo demás, se ignoran)." #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "Desplazamiento suave de la corona" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "Establecer desplazamiento suave de la corona" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "Desviar Teclas G" #: lib/logitech_receiver/settings_templates.py:385 msgid "" "Make G keys send GKEY HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Hacer que las teclas G envíen notificaciones GKEY HID ++ (que activan las " "reglas de Solaar, pero que, por lo demás, se ignoran)." #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "También puede hacer que las teclas M y MR envíen notificaciones HID++" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "Rueda de desplazamiento con carraca" #: lib/logitech_receiver/settings_templates.py:403 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Cambie la rueda del ratón entre carraca controlada por velocidad y siempre " "giro libre." #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "Giro libre" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "Carraca" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "Rueda de desplazamiento Velocidad de carraca" #: lib/logitech_receiver/settings_templates.py:414 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Utilice la velocidad de la rueda del ratón para cambiar entre carraca y giro " "libre.\n" "La rueda del mouse siempre está ajustada a 50." #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "Acciones de Tecla/Botón" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Cambiar la acción para la tecla o botón." #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "Anulado por la diversión." #: lib/logitech_receiver/settings_templates.py:466 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Cambiar acciones importantes (por ejemplo el botón izquierdo del ratón) " "puede dejar su sistema inutilizable." #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "Desvio de Tecla/Botón" #: lib/logitech_receiver/settings_templates.py:640 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "Haga que la tecla o el botón envíe notificaciones HID++ (Desviado) o iniciar " "gestos de mouse o DPI deslizante" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "Desviado" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "Gestos de Ratón" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "Normal" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "DPI deslizante" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Sensibilidad (PPP)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "Cambio de sensibilidad" #: lib/logitech_receiver/settings_templates.py:754 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Cambie la sensibilidad actual y la sensibilidad recordada cuando se presiona " "la tecla o el botón.\n" "Si no hay sensibilidad recordada, solo recuerde la corriente sensibilidad" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "Off" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Desactivar teclas" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Desactivar teclas específicas del teclado." #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "Desactiva la tecla %s." #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Especificar SO" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Cambiar teclas para coincidir son el S.O." #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Cambiar Equipo" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Cambiar la conexión a un equipo diferente" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "Realiza un clic izquierdo." #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "Un toque" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "Realiza un click derecho." #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "Un toque con dos dedos" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "Un toque con tres dedos" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "Doble toque" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "Realiza un click doble." #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "Doble toque con dos dedos" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "Doble toque con tres dedos" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "Arrastra elementos arrastrando el dedo después de tocar dos veces." #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "Tocar y arrastrar" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "Arrastra elementos arrastrando los dedos después de tocar dos veces." #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "Tocar y arrastrar con dos dedos" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "Tocar y arrastrar con tres dedos" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "Desactiva los gestos de toque y borde (equivalente a pulsar " "Fn+ClicIzquierdo)." #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "Elimina los gestos de toque y borde" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "Desplaza con un dedo" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "Desplazamiento." #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "Desplaza con dos dedos" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "Desplaza horizontalmente con dos dedos" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "Desplaza horizontalmente." #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "Desplazar verticalmente con dos dedos" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "Desplaza verticalmente." #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "Invierte la dirección de desplazamiento." #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "Desplazamiento natural" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "Activa la rueda del pulgar." #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "Rueda del pulgar" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "Deslizar desde el borde superior" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "Deslizar desde el borde izquierdo" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "Deslizar desde el borde derecho" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "Deslizar desde el borde inferior" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "Deslizar dos dedos desde el borde izquierdo" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "Deslizar dos dedos desde el borde derecho" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "Deslizar dos dedos desde el borde inferior" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "Deslizar dos dedos desde el borde superior" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "Pellizcar para alejar; Extender para acercar." #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "Zoom con dos dedos." #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "Pellizcar para alejar." #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "Extender para acercar." #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "Zoom con tres dedos." #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "Zoom con dos dedos" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "Zona de píxeles" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "Zona de relación" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Factor de escalado" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "Establece la velocidad del cursor." #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "Izquierda" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "Coordenada más a la izquierda." #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "Abajo" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "Coordenada inferior." #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Anchura" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "Anchura." #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Altura" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "Altura." #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "Velocidad del cursor." #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "Escala" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gestos" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "Modificar el comportamiento del mouse/panel táctil." #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "Desvío de gestos" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "Desviar los gestos del mouse/panel táctil." #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "Parámetros de gestos" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Cambiar parámetros numéricos de un mouse/panel táctil." #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "LEDs de teclas M" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "Control de los LEDs de teclas M." #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "Puede necesitar desviar las llaves G para ser efectiva." #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "Se enciende la tecla %s." #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "MR-Key LED" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "Controle el LED MR-Key." #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "Asignación persistente de teclas/botones" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "Cambie permanentemente la asignación de la tecla o el botón." #: lib/logitech_receiver/settings_templates.py:1098 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Cambiar teclas o botones importantes (como el botón izquierdo del ratón) " "puede resultar en un sistema inutilizable." #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "Tono lateral" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "Establezca el nivel de tono lateral." #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "Ecualizador" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "Establecer niveles del ecualizador." #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "Gestión de energía" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "Apagar a los minutos (0 para nunca)" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Ningún dispositivo conectado." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s dispositivo vinculado." msgstr[1] "%(count)s dispositivos vinculados." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Batería: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Batería: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Iluminación: %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batería: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batería: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Error de permisos" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Se ha encontrado un receptor Logitech o dispositivo (%s), pero no se dispone " "de permisos para abrirlo." #: lib/solaar/ui/__init__.py:55 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Si acaba de instalar Solaar, pruebe a desconectar y volver a conectar el " "receptor o dispositivo." #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "Error al conectar al dispositivo" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Se encontró un receptor o dispositivo Logitech en %s, pero se produjo un " "error al conectarse." #: lib/solaar/ui/__init__.py:61 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Pruebe a desconectar y volver a conectar el dispositivo o a apagarlo y " "encenderlo de nuevo." #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Desvinculación fallida" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Fallo al desvincular %{device} de %{receiver}." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "El receptor devolvió un error, sin detalles adicionales." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "" "Ya se está ejecutando otro proceso de Solaar, así que simplemente se muestra " "su ventana" #: lib/solaar/ui/about.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Gestiona receptores Logitech,\n" "teclados, ratones y tabletas." #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "Programación adicional" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "Diseño de la interfaz gráfica" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Prueba" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Documentación de Logitech" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Desvincular" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "Cancelar" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "Completa - ENTER para cambiar" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "Incompleta" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d valor" msgstr[1] "%d valores" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "Cambios permitidos" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "Cambios no permitidos" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "Ignorar esta opción" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Funcionando" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Operación de lectura/escritura fallida." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "Reglas integradas" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "Reglas definidas por el usuario" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "Regla" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "Subregla" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[vacío]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Editor de Reglas Solaar" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "¿Hacer los cambios permanentes?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Si�" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "No" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Si elige No, los cambios se perderán cuando se cierre Solaar." #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "Guardar cambios" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "Descartar cambios" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "Insertar aquí" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "Insertar encima" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "Insertar debajo" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "Insertar nueva regla aquí" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "Insertar nueva regla encima" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "Insertar nueva regla debajo" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "Pegar aquí" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "Pegar encima" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "Pegar debajo" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "Pegar regla aquí" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "Pegar regla encima" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "Pegar regla debajo" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "Pegar regla" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "Aplanar" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "Insertar" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "O" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "Y" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "Condición" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "Característica" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "Informar" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Proceso" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "Proceso de ratón" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "Modificadores" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "Tecla" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "TeclaPulsada" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Activo" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "Dispositivo" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "Equipo" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "Ajuste" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "Prueba" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "Bytes de prueba" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "Gesto de Ratón" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Accio�n" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "Pulsación de tecla" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "Desplazamiento rueda del ratón" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "Click del ratón" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "Establecer" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "Ejecutar" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "Luego" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "Añadir nueva regla" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "Borrar" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "Negar" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "Envolver con" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Cortar" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Pegar" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Copiar" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "" "Este editor aún no es compatible con el componente de regla seleccionado." #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "Número de segundos a retrasar." #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "No" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "Proceso activo X11. Solo para uso en X11." #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "Proceso de ratón X11. Solo para uso en X11." #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "ProcesoRatón" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" "Nombre de la característica del procesamiento de la regla de activación de " "notificaciones." #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" "Número de informe de procesamiento de regla de activación de notificación." #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Modificadores de teclado activos. No siempre disponible en Wayland." #: lib/solaar/ui/diversion_rules.py:1383 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Tecla desviada o botón pulsado o liberado.\n" "Use Desvío de Tecla/Botón y Desviar de Teclas G para desviar teclas y " "botones." #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "Tecla abajo" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "Tecla arriba" #: lib/solaar/ui/diversion_rules.py:1436 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "La tecla o botón desviado está actualmente pulsado.\n" "Use los ajustes Desvío de Tecla/Botón y Desviar Teclas G para desviar teclas " "y botones." #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" "Condición de prueba en el procesamiento de la regla de activación de " "notificación." #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "Parámetro" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "inicio (incluido)" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "fin (excluido)" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "rango" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "mínimo" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "máximo" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "bytes %(0)d a %(1)d, que van desde %(2)d a %(3)d" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "máscara" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "bytes %(0)d a %(1)d, máscara %(2)d" #: lib/solaar/ui/diversion_rules.py:1573 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Prueba de bit o rango en bytes en el mensaje de notificación que activa el " "procesamiento de reglas." #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "tipo" #: lib/solaar/ui/diversion_rules.py:1666 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Gesto del mouse con botón de inicio opcional seguido de cero o más " "movimientos del mouse." #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "Añadir movimiento" #: lib/solaar/ui/diversion_rules.py:1764 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simular un clic de teclas combinadas o pulsación o liberación.\n" "En Wayland requiere acceso de escritura a /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "Añadir tecla" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "Hacer clic" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "Pulsar" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "Liberar" #: lib/solaar/ui/diversion_rules.py:1861 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simular un desplazamiento del ratón.\n" "En Wayland requiere acceso de escritura a /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1918 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simular un clic del ratón.\n" "En Wayland requiere acceso de escritura a /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "Botón" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "Pulsaciones y Acción" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "Ejecutar un comando con parámetros." #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "Añadir parámetro" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "Invertir" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "Verdadero" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "Falso" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "Configuración no admitida" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "Dispositivo emisor" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "El dispositivo está activo y su configuración se puede cambiar." #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "Dispositivo que ha causado la notificación actual." #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "Nombre del equipo." #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Valor" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "Artículo" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "Cambiar la configuración en el dispositivo" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "Configuración en el dispositivo" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "desconectado" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: vincular nuevo dispositivo" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "Introduzca el código de acceso en %(name)s." #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Escriba %(passcode)s y luego presione la tecla Enter." #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "izquierda" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "derecha" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Pulse %(code)s\n" "y luego los botones izquierdo y derecho simultáneamente." #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Vinculación fallida" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Asegúrese de que su dispositivo esté dentro del alcance del receptor y que " "la batería tenga suficiente carga." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "" "Se detectó un nuevo dispositivo, pero no es compatible con este receptor." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "Más dispositivos emparejados de los que admite el receptor." #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "No hay más detalles disponibles sobre este error." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "Se encontró un nuevo dispositivo:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "La conexión inalámbrica no está cifrada" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" "Los receptores Unifying solo son compatibles con dispositivos Unifying." #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Los receptores Bolt solo son compatibles con dispositivos Bolt." #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "Otros receptores son solo compatibles con unos pocos dispositivos." #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" "El dispositivo no se debe estar emparejado con un receptor cercano encendido." #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Presione un botón o tecla de emparejamiento hasta que la luz de " "emparejamiento parpadee rápidamente." #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "" "Es posible que primero deba apagar el dispositivo y volver a encenderlo." #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Encienda el dispositivo que desea vincular." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "Si el dispositivo ya está encendido, apague y vuelva a encenderlo." #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Este receptor tiene %d emparejamiento restante." msgstr[1] "" "\n" "\n" "Este receptor tiene %d emparejamientos restantes." #: lib/solaar/ui/pair_window.py:286 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Si cancela en este punto no se usará un vínculo." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "No se ha encontrado ningún dispositivo compatible" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "Acerca de %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Salir de %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "sin receptor" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "sin estado" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Explorando" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Batería" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Enlace inalámbrico" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Iluminación" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Mostrar detalles técnicos" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Vincular nuevo dispositivo" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Seleccionar un dispositivo" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "Editor de Reglas" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Ruta" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "ID USB" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Serie" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "�ndice" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "PID inalámbrico" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "ID del producto" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protocolo" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Desconocido" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Tasa de sondeo" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "ID Unidad" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "ninguno" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Notificaciones" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "No hay dispositivos vinculados." #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Se puede vincular hasta %(max_count)s dispositivo a este receptor." msgstr[1] "" "Se pueden vincular hasta %(max_count)s dispositivos a este receptor." #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "Solo un dispositivo se puede vincular a este receptor." #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Este receptor tiene %d emparejamiento restante." msgstr[1] "Este receptor tiene %d emparejamientos restantes." #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "Voltaje de la batería" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "Voltaje informado por la batería" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "Nivel de Batería" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "Nivel aproximado informado por batería" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "siguiente informe " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " y siguiente nivel que será reportado." #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "último conocido" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "cifrado" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "" "La conexión inalámbrica entre el dispositivo y su receptor está cifrada." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "no cifrado" #: lib/solaar/ui/window.py:732 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "El enlace inalámbrico entre este dispositivo y su receptor no está " "encriptado.\n" "Este es un problema de seguridad para los dispositivos señaladores y un " "problema de seguridad importante para los dispositivos de entrada de texto." #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "" #~ "\n" #~ "\n" #~ "This receiver has %d pairing(s) remaining." #~ msgstr "" #~ "\n" #~ "\n" #~ "Este receptor tiene %d vínculo(s) disponibles." #~ msgid "%(battery_level)s" #~ msgstr "%(battery_level)s" #~ msgid "%(battery_percent)d%%" #~ msgstr "%(battery_percent)d%%" #~ msgid "Add action" #~ msgstr "Añadir acción" #~ msgid "" #~ "Adjust the DPI by sliding the mouse horizontally while holding the button " #~ "down." #~ msgstr "" #~ "Ajustar los DPI deslizando el ratón horizontalmente mientras se mantiene " #~ "el botón presionado." #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always locked at 50" #~ msgstr "" #~ "Cambia automáticamente el modo de la rueda del ratón entre bloqueado y " #~ "giro libre.\n" #~ "La rueda del ratón siempre está libre a 0 y siempre bloqueado a 50" #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "" #~ "Cambiar automáticamente la rueda del mouse entre el modo de trinquete y " #~ "el modo de giro libre.\n" #~ "La rueda del mouse siempre está libre en 0 y siempre con trinquete en 50" #~ msgid "Battery information unknown." #~ msgstr "Información de la batería desconocida." #~ msgid "Count" #~ msgstr "Cuenta" #~ msgid "DPI Sliding Adjustment" #~ msgstr "Ajustar DPI deslizando" #~ msgid "" #~ "Diverted key or button depressed or released.\n" #~ "Use the Key/Button Diversion setting to divert keys and buttons." #~ msgstr "" #~ "Tecla desviada o botón presionado o liberado.\n" #~ "Use la configuración Desvío de teclas/botones para desviar teclas y " #~ "botones." #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Desactiva eficazmente el desplazamiento con el pulgar en Linux." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Desactiva eficazmente el desplazamiento de la rueda en Linux." #, python-format #~ msgid "" #~ "Found a Logitech Receiver (%s), but did not have permission to open it." #~ msgstr "" #~ "Se encontró un receptor Logitech (%s), pero no tiene permisos para " #~ "abrirlo." #~ msgid "HID++ Scrolling" #~ msgstr "Desplazamiento HID++" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "Modo HID++ para desplazamientor horizontal con la rueda del pulgar." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "Modo HID++ para el desplazamiento vertical con la rueda." #~ msgid "High Resolution Scrolling" #~ msgstr "Desplazamiento de alta resolución" #~ msgid "High Resolution Wheel Invert" #~ msgstr "Invertir rueda en alta resolución " #~ msgid "High-sensitivity wheel invert mode for vertical scroll." #~ msgstr "" #~ "Modo inverso de alta resolución en la rueda para desplazamiento vertical." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "" #~ "Si el dispositivo ya está encendido, apáguelo y vuelva a encenderlo." #~ msgid "" #~ "If you've just installed Solaar, try removing the receiver and plugging " #~ "it back in." #~ msgstr "" #~ "Si acaba de instalar Solaar, intente quitar el receptor y conectarlo de " #~ "nuevo." #~ msgid "" #~ "Make the key or button send HID++ notifications (which trigger Solaar " #~ "rules but are otherwise ignored)." #~ msgstr "" #~ "Haga que la tecla o el botón envíe notificaciones HID ++ (que activan las " #~ "reglas de Solaar, de lo contrario se ignoran)." #~ msgid "No Logitech device found" #~ msgstr "No se encontró ningún dispositivo Logitech" #~ msgid "No Logitech receiver found" #~ msgstr "No se encontró ningún receptor Logitech" #~ msgid "Scroll Wheel Rachet" #~ msgstr "Trinquete Rueda Desplazamiento" #~ msgid "Send a gesture by sliding the mouse while holding the button down." #~ msgstr "" #~ "Envíe un gesto deslizando el ratón mientras mantiene presionado el botón." #~ msgid "" #~ "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "" #~ "Mostrar el estado de dispositivos conectados\n" #~ "mediante receptores inalámbricos Logitech." #~ msgid "Smooth Scrolling" #~ msgstr "Desplazamiento suave" #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "El receptor solo soporta %d dispositivo(s) vinculado(s)." #~ msgid "The receiver was unplugged." #~ msgstr "El receptor se desconectó." #~ msgid "" #~ "The wireless link between this device and its receiver is not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices (keyboards, " #~ "numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties within " #~ "range." #~ msgstr "" #~ "La conexión inalámbrica entre el dispositivo y su receptor no está " #~ "cifrada.\n" #~ "\n" #~ "Para dispositivos apuntadores (ratones, trackballs, trackpads), este es " #~ "un problema menor de seguridad.\n" #~ "\n" #~ "Sin embargo, para dispositivos de entrada de texto (teclados, teclados " #~ "numéricos) sí es un problema grave,\n" #~ "pues el texto introducido puede ser capturado de forma inadvertida por " #~ "terceros que estén cerca." #~ msgid "This receiver has %d pairing(s) remaining." #~ msgstr "Este receptor tiene %d vínculo(s) disponibles." #~ msgid "Top-most coordinate." #~ msgstr "Coordenada superior." #~ msgid "" #~ "Try removing the device and plugging it back in or turning it off and " #~ "then on." #~ msgstr "" #~ "Intente quitar el dispositivo y volver a enchufarlo o apagarlo y " #~ "encenderlo." #~ msgid "USB id" #~ msgstr "id USB" #~ msgid "Wheel Resolution" #~ msgstr "Resolución de la rueda" #~ msgid "height" #~ msgstr "altura" #~ msgid "top" #~ msgstr "superior" #~ msgid "unknown" #~ msgstr "desconocido" #~ msgid "width" #~ msgstr "anchura" Solaar-1.1.20/po/fi.po000066400000000000000000001766771522022367600144250ustar00rootroot00000000000000# Finnish translations for solaar package. # Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2013. # msgid "" msgstr "" "Project-Id-Version: solaar 0.9.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-03-05 13:08+0200\n" "PO-Revision-Date: 2013-08-05 18:49+0300\n" "Last-Translator: Niko Savola\n" "Language-Team: none\n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Bolt-vastaanotin" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Unifying-vastaanotin" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Nano-vastaanotin" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Lightspeed-vastaanotin" #: lib/logitech_receiver/base_usb.py:136 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 27 MHz -vastaanotin" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Akku: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Akku: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1048 #: lib/logitech_receiver/settings_templates.py:299 msgid "Disabled" msgstr "Pois käytöstä" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Static" msgstr "Muuttumaton" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Pulse" msgstr "Pulssi" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Cycle" msgstr "Jakso" #: lib/logitech_receiver/hidpp20.py:1052 msgid "Boot" msgstr "Käynnistys" #: lib/logitech_receiver/hidpp20.py:1053 msgid "Demo" msgstr "Esittely" #: lib/logitech_receiver/hidpp20.py:1055 msgid "Breathe" msgstr "Hengitys" #: lib/logitech_receiver/hidpp20.py:1058 msgid "Ripple" msgstr "Väreily" #: lib/logitech_receiver/hidpp20.py:1059 msgid "Decomposition" msgstr "Hajoaminen" #: lib/logitech_receiver/hidpp20.py:1060 msgid "Signature1" msgstr "Allekirjoitus1" #: lib/logitech_receiver/hidpp20.py:1061 msgid "Signature2" msgstr "Allekirjoitus2" #: lib/logitech_receiver/hidpp20.py:1062 msgid "CycleS" msgstr "SykliS" #: lib/logitech_receiver/hidpp20.py:1126 msgid "Unknown Location" msgstr "Tuntematon sijainti" #: lib/logitech_receiver/hidpp20.py:1127 msgid "Primary" msgstr "Ensisijainen" #: lib/logitech_receiver/hidpp20.py:1128 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:1129 msgid "Left Side" msgstr "Vasen puoli" #: lib/logitech_receiver/hidpp20.py:1130 msgid "Right Side" msgstr "Oikea puoli" #: lib/logitech_receiver/hidpp20.py:1131 msgid "Combined" msgstr "Yhdistetty" #: lib/logitech_receiver/hidpp20.py:1132 msgid "Primary 1" msgstr "Ensisijainen 1" #: lib/logitech_receiver/hidpp20.py:1133 msgid "Primary 2" msgstr "Ensisijainen 2" #: lib/logitech_receiver/hidpp20.py:1134 msgid "Primary 3" msgstr "Ensisijainen 3" #: lib/logitech_receiver/hidpp20.py:1135 msgid "Primary 4" msgstr "Ensisijainen 4" #: lib/logitech_receiver/hidpp20.py:1136 msgid "Primary 5" msgstr "Ensisijainen 5" #: lib/logitech_receiver/hidpp20.py:1137 msgid "Primary 6" msgstr "Ensisijainen 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "tyhjä" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "kriittinen" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "matala" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "keskiarvo" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "hyvä" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "täysi" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "tyhjenee" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "latautuu" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "lataa" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "ei latauksessa" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "lähes täysi" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "ladattu" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "hidas lataus" #: lib/logitech_receiver/i18n.py:42 #, fuzzy msgid "invalid battery" msgstr "virheellinen akku" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "lämpötilasta johtuva virhe" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "virhe" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "vakio" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "nopea" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "hidas" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "laitteen aikakatkaisu" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "laite ei ole tuettu" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "liian monta laitetta" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "sarjan aikakatkaisu" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "Laiteohjelmisto" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Alkulatausohjelma" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Laitteisto" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Muu" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Vasen painike" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Oikea painike" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Keskipainike" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Edellinen-painike" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Seuraava-painike" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Hiiren elepainike" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Smart Shift" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "DPI-kytkin" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Kallistus vasemmalle" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Kallistus oikealle" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Vasen napsautus" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Oikea napsautus" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Hiiren keskipainike" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Hiiren edellinen-painike" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Hiiren seuraava-painike" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Elepainikkeen navigointi" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Hiiren vieritys vasemmalle -painike" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Hiiren vieritys oikealle -painike" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "painettu" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "vapautettu" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "yhdistetty" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "yhteys katkaistu" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "parittamaton" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "virta päällä" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "ADC-mittausilmoitus" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:484 msgid "pairing lock is closed" msgstr "parituslukko on suljettu" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:484 msgid "pairing lock is open" msgstr "parituslukko on auki" #: lib/logitech_receiver/notifications.py:447 msgid "discovery lock is closed" msgstr "etsintälukko on suljettu" #: lib/logitech_receiver/notifications.py:447 msgid "discovery lock is open" msgstr "etsintälukko on auki" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "Ei paritettuja laitteita." #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s paritettu laite." msgstr[1] "%(count)s paritettua laitetta." #: lib/logitech_receiver/settings.py:602 msgid "register" msgstr "rekisteri" #: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654 msgid "feature" msgstr "ominaisuus" #: lib/logitech_receiver/settings_templates.py:138 msgid "Swap Fx function" msgstr "Vaihda Fx" #: lib/logitech_receiver/settings_templates.py:141 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Asetettu: F1..F12 näppäimet aktivoivat erityistoimintonsa ja \n" "FN-näppäintä on painettava, jotta ne aktivoisivat normaalin\n" "toimintonsa." #: lib/logitech_receiver/settings_templates.py:146 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Ei asetettu: F1..F12 näppäimet aktivoivat tavallisen toimintonsa\n" "ja FN-näppäintä on painettava, jotta ne aktivoisivat\n" "erityistoimintonsa." #: lib/logitech_receiver/settings_templates.py:154 msgid "Hand Detection" msgstr "Käsien tunnistus" #: lib/logitech_receiver/settings_templates.py:155 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Käynnistä valaistus, kun kädet ovat näppämistön yläpuolella." #: lib/logitech_receiver/settings_templates.py:162 msgid "Scroll Wheel Smooth Scrolling" msgstr "Vierityspyörän sulava vieritys" #: lib/logitech_receiver/settings_templates.py:163 #: lib/logitech_receiver/settings_templates.py:410 #: lib/logitech_receiver/settings_templates.py:439 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Korkean herkkyyden tila pystyvieritykseen hiiren rullalla." #: lib/logitech_receiver/settings_templates.py:170 msgid "Side Scrolling" msgstr "Sivuttaisvieritys" #: lib/logitech_receiver/settings_templates.py:172 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Pois päältä ollessaan, rullan painaminen sivuttain lähettää muokattuja\n" "toimintoja normaalien sivuttaisvieritystoimintojen sijaan." #: lib/logitech_receiver/settings_templates.py:182 msgid "Sensitivity (DPI - older mice)" msgstr "Herkkyys (DPI - vanhemmat hiiret)" #: lib/logitech_receiver/settings_templates.py:183 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 msgid "Mouse movement sensitivity" msgstr "Hiiren liikkeen herkkyys" #: lib/logitech_receiver/settings_templates.py:256 msgid "Backlight Timed" msgstr "Ajastettu taustavalo" #: lib/logitech_receiver/settings_templates.py:257 #: lib/logitech_receiver/settings_templates.py:397 msgid "Set illumination time for keyboard." msgstr "Aseta näppäimistön valaistusaika." #: lib/logitech_receiver/settings_templates.py:268 msgid "Backlight" msgstr "Taustavalo" #: lib/logitech_receiver/settings_templates.py:269 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Näppäimistön valaistustaso. Tehdyt muutokset otetaan käyttöön vain " "manuaalisessa tilassa." #: lib/logitech_receiver/settings_templates.py:301 msgid "Automatic" msgstr "Automaattinen" #: lib/logitech_receiver/settings_templates.py:303 msgid "Manual" msgstr "Manuaalinen" #: lib/logitech_receiver/settings_templates.py:305 msgid "Enabled" msgstr "Käytössä" #: lib/logitech_receiver/settings_templates.py:311 msgid "Backlight Level" msgstr "Taustavalon taso" #: lib/logitech_receiver/settings_templates.py:312 msgid "Illumination level on keyboard when in Manual mode." msgstr "Näppäimistön valaistustaso manuaalisessa tilassa." #: lib/logitech_receiver/settings_templates.py:369 msgid "Backlight Delay Hands Out" msgstr "Taustavalon viive, kädet poissa" #: lib/logitech_receiver/settings_templates.py:370 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "Taustavalon viive sekunneissa, kun kädet ovat poissa näppäimistöltä." #: lib/logitech_receiver/settings_templates.py:378 msgid "Backlight Delay Hands In" msgstr "Taustavalon viive, kädet lähellä" #: lib/logitech_receiver/settings_templates.py:379 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "Taustavalon viive sekunneissa, kun kädet ovat näppäimistön lähellä." #: lib/logitech_receiver/settings_templates.py:387 msgid "Backlight Delay Powered" msgstr "Taustavalon viive kytkettynä" #: lib/logitech_receiver/settings_templates.py:388 msgid "Delay in seconds until backlight fades out with external power." msgstr "Taustavalon viive sekunneissa ulkoiseen virtaan kytkettynä." #: lib/logitech_receiver/settings_templates.py:396 msgid "Backlight (Seconds)" msgstr "Taustavalo (sekuntia)" #: lib/logitech_receiver/settings_templates.py:408 msgid "Scroll Wheel High Resolution" msgstr "Vierityspyörän korkea resoluutio" #: lib/logitech_receiver/settings_templates.py:412 #: lib/logitech_receiver/settings_templates.py:441 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Aseta sivuuttamaan, jos vieritys on epänormaalin nopeaa tai hidasta" #: lib/logitech_receiver/settings_templates.py:419 #: lib/logitech_receiver/settings_templates.py:450 msgid "Scroll Wheel Diversion" msgstr "Vierityspyörän uudelleenohjaus" #: lib/logitech_receiver/settings_templates.py:421 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Aseta vierityspyörä lähettämään LOWRES_WHEEL HID++ -ilmoituksia (jotka " "laukaisevat Solaar-sääntöjä mutta muuten ohitetaan)." #: lib/logitech_receiver/settings_templates.py:428 msgid "Scroll Wheel Direction" msgstr "Vierityspyörän suunta" #: lib/logitech_receiver/settings_templates.py:429 msgid "Invert direction for vertical scroll with wheel." msgstr "Käännä vierityspyörän pystysuuntainen vierityssuunta." #: lib/logitech_receiver/settings_templates.py:437 msgid "Scroll Wheel Resolution" msgstr "Vierityspyörän resoluutio" #: lib/logitech_receiver/settings_templates.py:452 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar" " rules but are otherwise ignored)." msgstr "" "Aseta vierityspyörä lähettämään HIRES_WHEEL HID++ -ilmoituksia (jotka " "laukaisevat Solaar-sääntöjä mutta muuten ohitetaan)." #: lib/logitech_receiver/settings_templates.py:461 msgid "Sensitivity (Pointer Speed)" msgstr "Herkkyys (osoittimen nopeus)" #: lib/logitech_receiver/settings_templates.py:462 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Hiiren nopeuskerroin (256 on tavallinen kerroin)." #: lib/logitech_receiver/settings_templates.py:472 msgid "Thumb Wheel Diversion" msgstr "Peukalopyörän uudelleenohjaus" #: lib/logitech_receiver/settings_templates.py:474 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Aseta peukalopyörä lähettämään THUMB_WHEEL HID++ -ilmoituksia (jotka " "laukaisevat Solaar-sääntöjä mutta muuten ohitetaan)." #: lib/logitech_receiver/settings_templates.py:483 msgid "Thumb Wheel Direction" msgstr "Peukalopyörän suunta" #: lib/logitech_receiver/settings_templates.py:484 msgid "Invert thumb wheel scroll direction." msgstr "Käännä peukalopyörän vierityssuunta." #: lib/logitech_receiver/settings_templates.py:504 msgid "Onboard Profiles" msgstr "Laitteen omat profiilit" #: lib/logitech_receiver/settings_templates.py:505 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Ota käyttöön laitteen oma profiili, joka hallitsee päivitysnopeutta, " "herkkyyttä ja painiketoimintoja" #: lib/logitech_receiver/settings_templates.py:549 #: lib/logitech_receiver/settings_templates.py:582 msgid "Report Rate" msgstr "Päivitysnopeus" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 msgid "Frequency of device movement reports" msgstr "Laitteen liikeraporttien taajuus" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1421 #: lib/logitech_receiver/settings_templates.py:1452 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "Voi edellyttää, että Laitteen omat profiilit -asetus on pois käytöstä " "ollakseen voimassa." #: lib/logitech_receiver/settings_templates.py:612 msgid "Divert crown events" msgstr "Uudelleenohjaa kruunun tapahtumat" #: lib/logitech_receiver/settings_templates.py:613 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Aseta kruunu lähettämään CROWN HID++ -ilmoituksia (jotka laukaisevat Solaar-" "sääntöjä mutta muuten ohitetaan)." #: lib/logitech_receiver/settings_templates.py:621 msgid "Crown smooth scroll" msgstr "Kruunun sulava vieritys" #: lib/logitech_receiver/settings_templates.py:622 msgid "Set crown smooth scroll" msgstr "Aseta kruunun sulava vieritys" #: lib/logitech_receiver/settings_templates.py:630 msgid "Divert G and M Keys" msgstr "Uudelleenohjaa G- ja M-näppäimet" #: lib/logitech_receiver/settings_templates.py:631 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Aseta G- ja M-näppäimet lähettämään HID++ -ilmoituksia (jotka laukaisevat " "Solaar-sääntöjä mutta muuten ohitetaan)." #: lib/logitech_receiver/settings_templates.py:645 msgid "Scroll Wheel Ratcheted" msgstr "Vierityspyörän pykäläinen asetus" #: lib/logitech_receiver/settings_templates.py:646 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Vaihda hiiren pyörää nopeusohjatun pykäläisen ja aina vapaasti pyörivän " "välillä." #: lib/logitech_receiver/settings_templates.py:648 msgid "Freespinning" msgstr "Vapaasti pyörivä" #: lib/logitech_receiver/settings_templates.py:648 msgid "Ratcheted" msgstr "Pykäläinen" #: lib/logitech_receiver/settings_templates.py:655 msgid "Scroll Wheel Ratchet Speed" msgstr "Vierityspyörän pykäläisen asetuksen nopeus" #: lib/logitech_receiver/settings_templates.py:657 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Käytä hiiren pyörän nopeutta vaihtaaksesi pykäläisen ja vapaasti pyörivän välillä.\n" "Hiiren pyörä on aina pykäläinen nopeudella 50." #: lib/logitech_receiver/settings_templates.py:707 msgid "Scroll Wheel Ratchet Torque" msgstr "Vierityspyörän pykälän vääntömomentti" #: lib/logitech_receiver/settings_templates.py:708 msgid "Change the torque needed to overcome the ratchet." msgstr "Muuta pykälän ylittämiseen tarvittavaa vääntömomenttia." #: lib/logitech_receiver/settings_templates.py:743 msgid "Key/Button Actions" msgstr "Näppäin-/painiketoiminnot" #: lib/logitech_receiver/settings_templates.py:745 msgid "Change the action for the key or button." msgstr "Muuta näppäimen tai painikkeen toimintoa." #: lib/logitech_receiver/settings_templates.py:747 msgid "Overridden by diversion." msgstr "Uudelleenohjauksen ohittama." #: lib/logitech_receiver/settings_templates.py:749 msgid "" "Changing important actions (such as for the left mouse button) can result in" " an unusable system." msgstr "" "Tärkeiden toimintojen (kuten hiiren vasemman painikkeen) muuttaminen voi " "johtaa käyttökelvottomaan järjestelmään." #: lib/logitech_receiver/settings_templates.py:924 msgid "Key/Button Diversion" msgstr "Näppäimen/painikkeen uudelleenohjaus" #: lib/logitech_receiver/settings_templates.py:925 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse" " Gestures or Sliding DPI" msgstr "" "Aseta näppäin tai painike lähettämään HID++ -ilmoituksia (Uudelleenohjattu) " "tai aloita hiirieleet tai liukuva DPI" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Diverted" msgstr "Uudelleenohjattu" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 msgid "Mouse Gestures" msgstr "Hiirieleet" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Regular" msgstr "Säännöllinen" #: lib/logitech_receiver/settings_templates.py:928 msgid "Sliding DPI" msgstr "Liukuva DPI" #: lib/logitech_receiver/settings_templates.py:1018 #: lib/logitech_receiver/settings_templates.py:1046 msgid "Sensitivity (DPI)" msgstr "Herkkyys (DPI)" #: lib/logitech_receiver/settings_templates.py:1123 msgid "Sensitivity Switching" msgstr "Herkkyyden vaihtaminen" #: lib/logitech_receiver/settings_templates.py:1125 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Vaihda nykyinen herkkyys ja muistettu herkkyys, kun näppäintä tai painiketta painetaan.\n" "Jos muistettua herkkyyttä ei ole, muista vain nykyinen herkkyys" #: lib/logitech_receiver/settings_templates.py:1129 msgid "Off" msgstr "Pois" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Disable keys" msgstr "Poista näppäimiä käytöstä" #: lib/logitech_receiver/settings_templates.py:1161 msgid "Disable specific keyboard keys." msgstr "Poista tiettyjä näppäimistön näppäimiä käytöstä." #: lib/logitech_receiver/settings_templates.py:1164 #, python-format msgid "Disables the %s key." msgstr "Poistaa %s-näppäimen käytöstä." #: lib/logitech_receiver/settings_templates.py:1177 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Set OS" msgstr "Aseta käyttöjärjestelmä" #: lib/logitech_receiver/settings_templates.py:1178 #: lib/logitech_receiver/settings_templates.py:1235 msgid "Change keys to match OS." msgstr "Muuta näppäimet vastaamaan käyttöjärjestelmää." #: lib/logitech_receiver/settings_templates.py:1247 msgid "Change Host" msgstr "Vaihda isäntälaitetta" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Switch connection to a different host" msgstr "Vaihda yhteys toiseen isäntälaitteeseen" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Performs a left click." msgstr "Suorittaa vasemman napsautuksen." #: lib/logitech_receiver/settings_templates.py:1272 msgid "Single tap" msgstr "Yksi napautus" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Performs a right click." msgstr "Suorittaa oikean napsautuksen." #: lib/logitech_receiver/settings_templates.py:1273 msgid "Single tap with two fingers" msgstr "Yksi napautus kahdella sormella" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Single tap with three fingers" msgstr "Yksi napautus kolmella sormella" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Double tap" msgstr "Kaksoisnapautus" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Performs a double click." msgstr "Suorittaa kaksoisnapsautuksen." #: lib/logitech_receiver/settings_templates.py:1279 msgid "Double tap with two fingers" msgstr "Kaksoisnapautus kahdella sormella" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Double tap with three fingers" msgstr "Kaksoisnapautus kolmella sormella" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Drags items by dragging the finger after double tapping." msgstr "Raahaa kohteita vetämällä sormea kaksoisnapautuksen jälkeen." #: lib/logitech_receiver/settings_templates.py:1283 msgid "Tap and drag" msgstr "Napauta ja raahaa" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Tap and drag with two fingers" msgstr "Napauta ja raahaa kahdella sormella" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Drags items by dragging the fingers after double tapping." msgstr "Raahaa kohteita vetämällä sormia kaksoisnapautuksen jälkeen." #: lib/logitech_receiver/settings_templates.py:1288 msgid "Tap and drag with three fingers" msgstr "Napauta ja raahaa kolmella sormella" #: lib/logitech_receiver/settings_templates.py:1291 msgid "Suppress tap and edge gestures" msgstr "Estä napautus- ja reunaeleet" #: lib/logitech_receiver/settings_templates.py:1292 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Poistaa napautus- ja reunaeleet käytöstä (vastaa Fn+Vasen napsautus)." #: lib/logitech_receiver/settings_templates.py:1294 msgid "Scroll with one finger" msgstr "Vieritä yhdellä sormella" #: lib/logitech_receiver/settings_templates.py:1294 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scrolls." msgstr "Vierittää." #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scroll with two fingers" msgstr "Vieritä kahdella sormella" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scroll horizontally with two fingers" msgstr "Vieritä vaakasuunnassa kahdella sormella" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scrolls horizontally." msgstr "Vierittää vaakasuunnassa." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scroll vertically with two fingers" msgstr "Vieritä pystysuunnassa kahdella sormella" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scrolls vertically." msgstr "Vierittää pystysuunnassa." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Inverts the scrolling direction." msgstr "Kääntää vierityssuunnan." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Natural scrolling" msgstr "Luonnollinen vieritys" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Enables the thumbwheel." msgstr "Ottaa peukalopyörän käyttöön." #: lib/logitech_receiver/settings_templates.py:1300 msgid "Thumbwheel" msgstr "Peukalopyörä" #: lib/logitech_receiver/settings_templates.py:1311 #: lib/logitech_receiver/settings_templates.py:1315 msgid "Swipe from the top edge" msgstr "Pyyhkäise yläreunasta" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Swipe from the left edge" msgstr "Pyyhkäise vasemmasta reunasta" #: lib/logitech_receiver/settings_templates.py:1313 msgid "Swipe from the right edge" msgstr "Pyyhkäise oikeasta reunasta" #: lib/logitech_receiver/settings_templates.py:1314 msgid "Swipe from the bottom edge" msgstr "Pyyhkäise alareunasta" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Swipe two fingers from the left edge" msgstr "Pyyhkäise kahdella sormella vasemmasta reunasta" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Swipe two fingers from the right edge" msgstr "Pyyhkäise kahdella sormella oikeasta reunasta" #: lib/logitech_receiver/settings_templates.py:1318 msgid "Swipe two fingers from the bottom edge" msgstr "Pyyhkäise kahdella sormella alareunasta" #: lib/logitech_receiver/settings_templates.py:1319 msgid "Swipe two fingers from the top edge" msgstr "Pyyhkäise kahdella sormella yläreunasta" #: lib/logitech_receiver/settings_templates.py:1320 #: lib/logitech_receiver/settings_templates.py:1324 msgid "Pinch to zoom out; spread to zoom in." msgstr "Nipistä loitontaaksesi; levitä lähentääksesi." #: lib/logitech_receiver/settings_templates.py:1320 msgid "Zoom with two fingers." msgstr "Zoomaa kahdella sormella." #: lib/logitech_receiver/settings_templates.py:1321 msgid "Pinch to zoom out." msgstr "Nipistä loitontaaksesi." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Spread to zoom in." msgstr "Levitä lähentääksesi." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Zoom with three fingers." msgstr "Zoomaa kolmella sormella." #: lib/logitech_receiver/settings_templates.py:1324 msgid "Zoom with two fingers" msgstr "Zoomaa kahdella sormella" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Pixel zone" msgstr "Pikselialue" #: lib/logitech_receiver/settings_templates.py:1343 msgid "Ratio zone" msgstr "Suhdealue" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scale factor" msgstr "Skaalauskerroin" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Sets the cursor speed." msgstr "Asettaa osoittimen nopeuden." #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left" msgstr "Vasen" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left-most coordinate." msgstr "Vasemmanpuoleisin koordinaatti." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom" msgstr "Alareuna" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom coordinate." msgstr "Alakoordinaatti." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width" msgstr "Leveys" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width." msgstr "Leveys." #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height" msgstr "Korkeus" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height." msgstr "Korkeus." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Cursor speed." msgstr "Osoittimen nopeus." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Scale" msgstr "Skaala" #: lib/logitech_receiver/settings_templates.py:1358 msgid "Gestures" msgstr "Eleet" #: lib/logitech_receiver/settings_templates.py:1359 msgid "Tweak the mouse/touchpad behaviour." msgstr "Säädä hiiren/kosketuslevyn toimintaa." #: lib/logitech_receiver/settings_templates.py:1375 msgid "Gestures Diversion" msgstr "Eleiden uudelleenohjaus" #: lib/logitech_receiver/settings_templates.py:1376 msgid "Divert mouse/touchpad gestures." msgstr "Uudelleenohjaa hiiren/kosketuslevyn eleet." #: lib/logitech_receiver/settings_templates.py:1392 msgid "Gesture params" msgstr "Eleiden parametrit" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Muuta hiiren/kosketuslevyn numeerisia parametreja." #: lib/logitech_receiver/settings_templates.py:1417 msgid "M-Key LEDs" msgstr "M-näppäinten LEDit" #: lib/logitech_receiver/settings_templates.py:1419 msgid "Control the M-Key LEDs." msgstr "Hallitse M-näppäinten LEDejä." #: lib/logitech_receiver/settings_templates.py:1423 #: lib/logitech_receiver/settings_templates.py:1454 msgid "May need G Keys diverted to be effective." msgstr "Saattaa edellyttää G-näppäinten uudelleenohjausta toimiakseen." #: lib/logitech_receiver/settings_templates.py:1429 #, python-format msgid "Lights up the %s key." msgstr "Sytyttää %s-näppäimen." #: lib/logitech_receiver/settings_templates.py:1448 msgid "MR-Key LED" msgstr "MR-näppäimen LED" #: lib/logitech_receiver/settings_templates.py:1450 msgid "Control the MR-Key LED." msgstr "Hallitse MR-näppäimen LEDiä." #: lib/logitech_receiver/settings_templates.py:1471 msgid "Persistent Key/Button Mapping" msgstr "Pysyvä näppäin-/painikemääritys" #: lib/logitech_receiver/settings_templates.py:1473 msgid "Permanently change the mapping for the key or button." msgstr "Muuta näppäimen tai painikkeen määritystä pysyvästi." #: lib/logitech_receiver/settings_templates.py:1475 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Tärkeiden näppäinten tai painikkeiden (kuten hiiren vasemman painikkeen) " "muuttaminen voi johtaa käyttökelvottomaan järjestelmään." #: lib/logitech_receiver/settings_templates.py:1532 msgid "Sidetone" msgstr "Sivuääni" #: lib/logitech_receiver/settings_templates.py:1533 msgid "Set sidetone level." msgstr "Aseta sivuäänen taso." #: lib/logitech_receiver/settings_templates.py:1542 msgid "Equalizer" msgstr "Taajuuskorjain" #: lib/logitech_receiver/settings_templates.py:1543 msgid "Set equalizer levels." msgstr "Aseta taajuuskorjaimen tasot." #: lib/logitech_receiver/settings_templates.py:1565 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1571 msgid "Power Management" msgstr "Virranhallinta" #: lib/logitech_receiver/settings_templates.py:1572 msgid "Power off in minutes (0 for never)." msgstr "Virrankatkaisu minuuteissa (0 = ei koskaan)." #: lib/logitech_receiver/settings_templates.py:1584 msgid "Brightness Control" msgstr "Kirkkauden säätö" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Control overall brightness" msgstr "Hallitse yleistä kirkkautta" #: lib/logitech_receiver/settings_templates.py:1628 #: lib/logitech_receiver/settings_templates.py:1681 msgid "LED Control" msgstr "LED-hallinta" #: lib/logitech_receiver/settings_templates.py:1629 #: lib/logitech_receiver/settings_templates.py:1682 msgid "Switch control of LED zones between device and Solaar" msgstr "Vaihda LED-alueiden hallintaa laitteen ja Solaarin välillä" #: lib/logitech_receiver/settings_templates.py:1644 #: lib/logitech_receiver/settings_templates.py:1692 msgid "LED Zone Effects" msgstr "LED-alueiden efektit" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "LED Control needs to be set to Solaar to be effective." msgstr "LED-hallinta on asetettava Solaariin ollakseen voimassa." #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "Set effect for LED Zone" msgstr "Aseta efekti LED-alueelle" #: lib/logitech_receiver/settings_templates.py:1647 msgid "Color" msgstr "Väri" #: lib/logitech_receiver/settings_templates.py:1648 msgid "Speed" msgstr "Nopeus" #: lib/logitech_receiver/settings_templates.py:1649 msgid "Period" msgstr "Jakso" #: lib/logitech_receiver/settings_templates.py:1650 msgid "Intensity" msgstr "Voimakkuus" #: lib/logitech_receiver/settings_templates.py:1651 msgid "Ramp" msgstr "Nousu" #: lib/logitech_receiver/settings_templates.py:1666 msgid "LEDs" msgstr "LEDit" #: lib/logitech_receiver/settings_templates.py:1703 msgid "Per-key Lighting" msgstr "Näppäinkohtainen valaistus" #: lib/logitech_receiver/settings_templates.py:1704 msgid "Control per-key lighting." msgstr "Hallitse näppäinkohtaista valaistusta." #: lib/logitech_receiver/settings_templates.py:1786 msgid "Force Sensing Buttons" msgstr "Voimaa tunnistavat painikkeet" #: lib/logitech_receiver/settings_templates.py:1787 msgid "Change the force required to activate button." msgstr "Muuta painikkeen aktivointiin tarvittavaa voimaa." #: lib/logitech_receiver/settings_templates.py:1804 msgid "Force Sensing Button" msgstr "Voimaa tunnistava painike" #: lib/logitech_receiver/settings_templates.py:1814 msgid "Haptic Feedback Level" msgstr "Haptisen palautteen taso" #: lib/logitech_receiver/settings_templates.py:1815 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "Muuta haptisen palautteen voimakkuutta. (Nolla poistaa käytöstä.)" #: lib/logitech_receiver/settings_templates.py:1857 msgid "Play Haptic Waveform" msgstr "Toista haptinen aaltomuoto" #: lib/logitech_receiver/settings_templates.py:1858 msgid "Tell device to play a haptic waveform." msgstr "Käske laitetta toistamaan haptinen aaltomuoto." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "" "Toinen Solaar-prosessi on jo käynnissä, joten sen ikkuna tuodaan näkyviin" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Hallitsee Logitech-vastaanottimia,\n" "näppäimistöjä, hiiriä ja piirtopöytiä." #: lib/solaar/ui/about/model.py:64 msgid "Additional Programming" msgstr "Lisäohjelmointi" #: lib/solaar/ui/about/model.py:65 msgid "GUI design" msgstr "Käyttöliittymäsuunnittelu" #: lib/solaar/ui/about/model.py:67 msgid "Testing" msgstr "Testaus" #: lib/solaar/ui/about/model.py:75 #, fuzzy msgid "Logitech documentation" msgstr "Logitechin dokumentointi" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Poista paritus" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "Peruuta" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Virheelliset käyttöoikeudet" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Löydettiin Logitech-vastaanotin tai -laite (%s), mutta siihen ei ollut " "avaamisoikeutta." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Jos asensit Solaarin juuri, kokeile irrottaa vastaanotin tai laite ja " "yhdistää se sitten uudelleen." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Virhe yhdistettäessä laitteeseen" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Löydettiin Logitech-vastaanotin tai -laite polusta %s, mutta ilmeni virhe " "yhdistettäessä siihen." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Kokeile laitteen irrottamista ja yhdistämistä uudelleen tai sen " "sammuttamista ja käynnistämistä uudelleen." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "Parituksen poisto epäonnistui" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "%{device}n parituksen poisto epäonnistui %{receiver}sta." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Vastaanotin palautti virheen ilman lisätietoja." #: lib/solaar/ui/config_panel.py:245 msgid "Complete - ENTER to change" msgstr "Valmis - paina ENTER muuttaaksesi" #: lib/solaar/ui/config_panel.py:245 msgid "Incomplete" msgstr "Keskeneräinen" #: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d arvo" msgstr[1] "%d arvoa" #: lib/solaar/ui/config_panel.py:642 msgid "Changes allowed" msgstr "Muutokset sallittu" #: lib/solaar/ui/config_panel.py:643 msgid "No changes allowed" msgstr "Ei muutoksia sallittu" #: lib/solaar/ui/config_panel.py:644 msgid "Ignore this setting" msgstr "Ohita tämä asetus" #: lib/solaar/ui/config_panel.py:690 msgid "Working" msgstr "Työskentelee" #: lib/solaar/ui/config_panel.py:693 msgid "Read/write operation failed." msgstr "Luku/kirjoitus operaatio epäonnistui." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "määrittämätön syy" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "Sisäänrakennetut säännöt" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "Käyttäjän määrittämät säännöt" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "Sääntö" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "Alisääntö" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "[tyhjä]" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "Tehdäänkö muutoksista pysyviä?" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "Kyllä" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "Ei" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Jos valitset Ei, muutokset menetetään, kun Solaar suljetaan." #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "Liitä tähän" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "Liitä yläpuolelle" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "Liitä alapuolelle" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "Liitä sääntö tähän" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "Liitä sääntö yläpuolelle" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "Liitä sääntö alapuolelle" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "Liitä sääntö" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "Lisää tähän" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "Lisää yläpuolelle" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "Lisää alapuolelle" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "Lisää uusi sääntö tähän" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "Lisää uusi sääntö yläpuolelle" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "Lisää uusi sääntö alapuolelle" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "Litistä" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "Lisää" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "Tai" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "Ja" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "Ehto" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Ominaisuus" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Raportti" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Prosessi" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "Hiiriprosessi" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Muuntajat" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Näppäin" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "Näppäin on painettu" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "Aktiivinen" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "Laite" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "Isäntä" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "Asetus" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "Testi" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Testaa tavut" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Hiiriele" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "Toiminto" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "Näppäimen painallus" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Hiiren vieritys" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Hiiren napsautus" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "Aseta" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "Suorita" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "Myöhemmin" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "Lisää uusi sääntö" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Poista" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "Käännä" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "Kääri" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "Leikkaa" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "Liitä" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "Kopioi" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "Solaarin sääntöeditori" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "Tallenna muutokset" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "Hylkää muutokset" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "Tämä editori ei vielä tue valittua sääntökomponenttia." #: lib/solaar/ui/diversion_rules.py:1169 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Viive sekunteina. Viive 0:n ja 1:n välillä tehdään suuremmalla " "tarkkuudella." #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "Ei" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "Vaihda" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "Tosi" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "Epätosi" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "Ei tuettu asetus" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "Alkuperäinen laite" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "Laite on aktiivinen ja sen asetuksia voidaan muuttaa." #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "Laite, josta nykyinen ilmoitus on peräisin." #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "Isäntätietokoneen nimi." #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "Arvo" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "Kohde" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "Muuta asetusta laitteessa" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "Asetus laitteessa" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: parita uusi laite" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt-vastaanottimet ovat yhteensopivia vain Bolt-laitteiden kanssa." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Paina parituspainiketta tai -näppäintä, kunnes paritusvalo vilkkuu nopeasti." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" "Unifying-vastaanottimet ovat yhteensopivia vain Unifying-laitteiden kanssa." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "" "Muut vastaanottimet ovat yhteensopivia vain joidenkin laitteiden kanssa." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "Useimmissa laitteissa kytke päälle laite, jonka haluat parittaa." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "Jos laite on jo päällä, sammuta se ja käynnistä uudelleen." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" "Laitetta ei saa olla paritettu lähellä olevaan päällä olevaan " "vastaanottimeen." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, and release the channel switch button." msgstr "" "Jos laitteessa on useita kanavia, paina, pidä painettuna ja vapauta sen kanavan painike, jonka haluat parittaa\n" "tai käytä kanavanvaihtopainiketta valitaksesi kanavan ja paina, pidä painettuna ja vapauta sitten kanavanvaihtopainike." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Kanavan merkkivalon pitäisi vilkkua nopeasti." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Tässä vastaanottimessa on %d paritus jäljellä." msgstr[1] "" "\n" "\n" "Tässä vastaanottimessa on %d paritusta jäljellä." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Peruuttaminen tässä vaiheessa ei kuluta paritusta." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Anna pääsykoodi laitteella %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Kirjoita %(passcode)s ja paina sitten enter-näppäintä." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "vasen" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "oikea" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Paina %(code)s\n" "ja paina sitten vasenta ja oikeaa painiketta samanaikaisesti." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "Langaton yhteys ei ole salattu" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Löytyi uusi laite:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Paritus epäonnistui." #: lib/solaar/ui/pair_window.py:249 msgid "" "Make sure your device is within range, and has a decent battery charge." msgstr "" "Varmista, että laitteesi on kantaman sisällä ja siinä on riittävä lataus." #: lib/solaar/ui/pair_window.py:251 msgid "" "A new device was detected, but it is not compatible with this receiver." msgstr "" "Uusi laite tunnistettiin, mutta se ei ole yhteensopiva käytetyn " "vastaanottimen kanssa." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "Enemmän paritettuja laitteita kuin vastaanotin tukee." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Virheestä ei ole saatavilla enempää tietoja." #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuloi sointunäppäimen napsautusta, painallusta tai vapautusta.\n" "Waylandissa vaatii kirjoitusoikeuden laitteeseen /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Lisää näppäin" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Napsautus" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Paina" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Vapauta" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuloi hiiren vieritystä.\n" "Waylandissa vaatii kirjoitusoikeuden laitteeseen /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuloi hiiren napsautusta.\n" "Waylandissa vaatii kirjoitusoikeuden laitteeseen /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Painike" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Toiminto (ja määrä, jos napsautus)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Suorita komento argumenteilla." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Lisää argumentti" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "X11 aktiivinen prosessi. Vain X11-käyttöön." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "X11 hiiriprosessi. Vain X11-käyttöön." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "Hiiriprosessi" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "Säännönkäsittelyn laukaisevan ilmoituksen ominaisuuden nimi." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "Säännönkäsittelyn laukaisevan ilmoituksen raporttinumero." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" "Aktiiviset näppäimistön muuntajat. Eivät ole aina saatavilla Waylandissa." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons." msgstr "" "Uudelleenohjattu näppäin tai painike painettu tai vapautettu.\n" "Käytä näppäimen/painikkeen uudelleenohjaus- ja uudelleenohjaa G-näppäimet -asetuksia ohjataksesi näppäimiä ja painikkeita." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Näppäin painettuna" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Näppäin vapautettuna" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and buttons." msgstr "" "Uudelleenohjattu näppäin tai painike on parhaillaan painettuna.\n" "Käytä näppäimen/painikkeen uudelleenohjaus- ja uudelleenohjaa G-näppäimet -asetuksia ohjataksesi näppäimiä ja painikkeita." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "Testaa ehto säännönkäsittelyn laukaisevassa ilmoituksessa." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Parametri" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "alku (sisältyy)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "loppu (ei sisälly)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "alue" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "minimi" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "maksimi" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "tavut %(0)d - %(1)d, väliltä %(2)d - %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "maski" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "tavut %(0)d - %(1)d, maski %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Bitti- tai aluetesti tavuille säännönkäsittelyn laukaisevassa " "ilmoitusviestissä." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "tyyppi" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse" " movements." msgstr "" "Hiiriele valinnaisella aloituspainikkeella, jota seuraa nolla tai useampi " "hiiriliike." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Lisää liike" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Ei löydetty tuettua laitetta" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "Tietoja %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Lopeta %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "ei vastaanotinta" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:728 msgid "offline" msgstr "ei yhdistetty" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "ei tietoja" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Skannataan" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Akku" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Langaton yhteys" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "Valaistus" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Näytä tekniset tiedot" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Parita uusi laite" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Valitse laite" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Sääntöeditori" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Polku" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "USB-tunnus" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546 msgid "Serial" msgstr "Sarjanumero" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "Järjestysnumero" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "Langaton PID" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "Tuotteen tunnistekoodi" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "Yhteyskäytäntö" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "Tuntematon" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "Päivitysnopeus" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "Yksikön tunnus" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "ei mitään" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "Ilmoitukset" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "Ei paritettua laitetta." #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "" "Enintään %(max_count)s laite voidaan parittaa tähän vastaanottimeen." msgstr[1] "" "Enintään %(max_count)s laitetta voidaan parittaa tähän vastaanottimeen." #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "Vain yksi laite voidaan parittaa tähän vastaanottimeen." #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Tässä vastaanottimessa on %d paritus jäljellä." msgstr[1] "Tässä vastaanottimessa on %d paritusta jäljellä." #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "Akun jännite" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "Akun ilmoittama jännite" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "Akun taso" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "Akun ilmoittama arvioitu taso" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "seuraavaksi ilmoitettu " #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr " ja seuraava ilmoitettava taso." #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "viimeisin tunnettu" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "salattu" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Langaton yhteys laitteen ja vastaanottimen välillä on salattu." #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "salaamaton" #: lib/solaar/ui/window.py:721 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue for text-input devices." msgstr "" "Langaton yhteys tämän laitteen ja sen vastaanottimen välillä ei ole salattu.\n" "Tämä on tietoturvaongelma osoitinlaitteille ja suuri tietoturvariski tekstinsyöttölaitteille." #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d luksia" #~ msgid " paired devices." #~ msgstr " paritettua laitetta" #~ msgid "1 paired device." #~ msgstr "Yksi paritettu laite." #, python-format #~ msgid "" #~ "Found a Logitech Receiver (%s), but did not have permission to open it." #~ msgstr "" #~ "Logitechin vastaanotin (%s) löydettiin, mutta sitä ei ollut oikeutta avata." #~ msgid "Found a new device" #~ msgstr "Löydetty uusi laite." #~ msgid "" #~ "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "" #~ "Jos laite on jo päällä, sammuta se\n" #~ "ja kytke virta uudelleen päälle." #~ msgid "" #~ "If you've just installed Solaar, try removing the receiver and plugging it " #~ "back in." #~ msgstr "" #~ "Jos olet juuri asentanut Solaarin, yritä vastaanottimen irroittamista ja " #~ "liittämistä uudelleen." #~ msgid "No Logitech receiver found" #~ msgstr "Ei löydetty Logitechin vastaanottimia." #~ msgid "No device paired" #~ msgstr "Ei paritettuja laitteita" #~ msgid "Only one device can be paired to this receiver" #~ msgstr "Vain yksi laite voidaan parittaa tähän vastaanottimeen" #~ msgid "" #~ "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "" #~ "Näyttää Logitechin langattoman \n" #~ "vastaanottimen kautta liitettyjen\n" #~ "laitteiden tilan." #~ msgid "Smooth Scrolling" #~ msgstr "Sulava vieritys" #, python-format #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Vastaanotin tukee vain %d liitettyä laitetta." #~ msgid "The receiver was unplugged." #~ msgstr "Vastaanotin irroitettiin." #~ msgid "" #~ "The wireless link between this device and its receiver is not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices (keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties within range." #~ msgstr "" #~ "Langaton yhteys laitteen ja vastaanottimen välillä ei ole salattu.\n" #~ "\n" #~ "Osoitinlaitteita (hiiret, ohjainpallot, tasohiiret) käytettäessä se on pieni tietoturvallisuusriski.\n" #~ "\n" #~ "Kuitenkin, näppäimistöjen kanssa se on suuri tietoturvallisuusriski sillä kolmannet osapuolet\n" #~ "voivat lukea huomaamattomasti kirjoitetun tekstin yhteyden kantaman sisällä." #~ msgid "Turn on the device you want to pair." #~ msgstr "Käynnistä laite, jonka haluat parittaa." #~ msgid "USB id" #~ msgstr "USB-tunnus" #~ msgid "Up to %d devices can be paired to this receiver" #~ msgstr "Korkeintaan %d laitetta voidaan parittaa tähän vastaanottimeen" #~ msgid "closed" #~ msgstr "suljettu" #~ msgid "height" #~ msgstr "korkeus" #~ msgid "lux" #~ msgstr "luksia" #~ msgid "open" #~ msgstr "avoin" #~ msgid "pair new device" #~ msgstr "liitä uusi laite" #~ msgid "paired devices" #~ msgstr "paritettua laitetta" #~ msgid "pairing lock is " #~ msgstr "parituslukko on " #~ msgid "unknown" #~ msgstr "tuntematon" #~ msgid "width" #~ msgstr "leveys" Solaar-1.1.20/po/fr.po000066400000000000000000002234501522022367600144140ustar00rootroot00000000000000# French translations for solaar package. # Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2013. # msgid "" msgstr "" "Project-Id-Version: solaar 1.1.20\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-06-17 17:17+0200\n" "PO-Revision-Date: 2026-06-17 21:06+0200\n" "Last-Translator: David Geiger \n" "Language-Team: Language: fr\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.8\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Récepteur Bolt" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Récepteur Unifying" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Récepteur Nano" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Récepteur Lightspeed" #: lib/logitech_receiver/base_usb.py:136 msgid "EX100 Receiver 27 Mhz" msgstr "Récepteur EX100 27 Mhz" #: lib/logitech_receiver/common.py:698 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batterie : %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:701 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batterie : %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1189 lib/logitech_receiver/hidpp20.py:1222 #: lib/logitech_receiver/hidpp20.py:1250 msgid "Cycle" msgstr "Cycle" #: lib/logitech_receiver/hidpp20.py:1190 msgid "Right" msgstr "Droit" #: lib/logitech_receiver/hidpp20.py:1191 msgid "Down" msgstr "En bas" #: lib/logitech_receiver/hidpp20.py:1192 msgid "Center Out" msgstr "Centrer dehors" #: lib/logitech_receiver/hidpp20.py:1193 msgid "In" msgstr "Dedans" #: lib/logitech_receiver/hidpp20.py:1194 msgid "Out" msgstr "Dehors" #: lib/logitech_receiver/hidpp20.py:1195 #: lib/logitech_receiver/settings_templates.py:1398 msgid "Left" msgstr "Gauche" #: lib/logitech_receiver/hidpp20.py:1196 msgid "Up" msgstr "En haut" #: lib/logitech_receiver/hidpp20.py:1197 msgid "Center In" msgstr "Centrer dedans" #: lib/logitech_receiver/hidpp20.py:1218 #: lib/logitech_receiver/settings_templates.py:344 msgid "Disabled" msgstr "Désactivé" #: lib/logitech_receiver/hidpp20.py:1219 msgid "Static" msgstr "Statique" #: lib/logitech_receiver/hidpp20.py:1220 msgid "Pulse" msgstr "Pulsation" #: lib/logitech_receiver/hidpp20.py:1229 lib/logitech_receiver/hidpp20.py:1255 msgid "Wave" msgstr "" #: lib/logitech_receiver/hidpp20.py:1233 msgid "Boot" msgstr "Boot" #: lib/logitech_receiver/hidpp20.py:1234 msgid "Demo" msgstr "Démo" #: lib/logitech_receiver/hidpp20.py:1236 msgid "Breathe" msgstr "" #: lib/logitech_receiver/hidpp20.py:1241 lib/logitech_receiver/hidpp20.py:1262 msgid "Ripple" msgstr "" #: lib/logitech_receiver/hidpp20.py:1246 msgid "Decomposition" msgstr "Décomposition" #: lib/logitech_receiver/hidpp20.py:1247 msgid "Signature1" msgstr "Signature 1" #: lib/logitech_receiver/hidpp20.py:1248 msgid "Signature2" msgstr "Signature 2" #: lib/logitech_receiver/hidpp20.py:1268 msgid "Dim" msgstr "Sombre" #: lib/logitech_receiver/hidpp20.py:1340 msgid "Unknown Location" msgstr "Emplacement inconnu" #: lib/logitech_receiver/hidpp20.py:1341 #: lib/logitech_receiver/settings_templates.py:2619 #: lib/logitech_receiver/settings_templates.py:2907 #: lib/logitech_receiver/settings_templates.py:3647 msgid "Primary" msgstr "Primaire" #: lib/logitech_receiver/hidpp20.py:1342 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:1343 msgid "Left Side" msgstr "Côté gauche" #: lib/logitech_receiver/hidpp20.py:1344 msgid "Right Side" msgstr "Côté droit" #: lib/logitech_receiver/hidpp20.py:1345 msgid "Combined" msgstr "Combiné" #: lib/logitech_receiver/hidpp20.py:1346 msgid "Primary 1" msgstr "Primaire 1" #: lib/logitech_receiver/hidpp20.py:1347 msgid "Primary 2" msgstr "Primaire 2" #: lib/logitech_receiver/hidpp20.py:1348 msgid "Primary 3" msgstr "Primaire 3" #: lib/logitech_receiver/hidpp20.py:1349 msgid "Primary 4" msgstr "Primaire 4" #: lib/logitech_receiver/hidpp20.py:1350 msgid "Primary 5" msgstr "Primaire 5" #: lib/logitech_receiver/hidpp20.py:1351 msgid "Primary 6" msgstr "Primaire 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "vide" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "critique" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "faible" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "moyenne" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "bonne" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "pleine" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "En décharge" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "En charge" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:706 msgid "charging" msgstr "en charge" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "pas en charge" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "presque pleine" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "chargée" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "recharge lente" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "batterie invalide" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "erreur thermique" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "erreur" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "standard" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "rapide" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "lente" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "le périphérique ne répond pas" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "périphérique non pris en charge" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "trop de périphériques" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "délai dépassé" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:561 msgid "Firmware" msgstr "Micrologiciel" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Chargeur d'amorçage" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Matériel" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Autre" #: lib/logitech_receiver/i18n.py:59 #: lib/logitech_receiver/settings_templates.py:4336 msgid "Left Button" msgstr "Bouton gauche" #: lib/logitech_receiver/i18n.py:60 #: lib/logitech_receiver/settings_templates.py:4336 msgid "Right Button" msgstr "Bouton droit" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Bouton central" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Bouton retour" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Bouton avant" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Bouton gestuel de la souris" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Changement intelligent" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Commutateur DPI" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Inclinaison à gauche" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Inclinaison à droite" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Clic gauche" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Clic droit" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Bouton central de la souris" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Bouton de retour de la souris" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Bouton avant de la souris" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Navigation par bouton de gestuelle" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Bouton de défilement vers la gauche de la souris" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Bouton de défilement vers la droite de la souris" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "pressé" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "relâché" #: lib/logitech_receiver/notifications.py:157 lib/solaar/listener.py:350 msgid "connected" msgstr "connecté" #: lib/logitech_receiver/notifications.py:157 lib/solaar/listener.py:350 msgid "disconnected" msgstr "déconnecté" #: lib/logitech_receiver/notifications.py:183 msgid "unpaired" msgstr "non jumelé" #: lib/logitech_receiver/notifications.py:232 msgid "powered on" msgstr "sous tension" #: lib/logitech_receiver/notifications.py:284 msgid "ADC measurement notification" msgstr "Notification de mesure ADC" #: lib/logitech_receiver/notifications.py:486 #: lib/logitech_receiver/notifications.py:542 msgid "pairing lock is closed" msgstr "le verrou de jumelage est fermé" #: lib/logitech_receiver/notifications.py:486 #: lib/logitech_receiver/notifications.py:542 msgid "pairing lock is open" msgstr "le verrou de jumelage est ouvert" #: lib/logitech_receiver/notifications.py:505 msgid "discovery lock is closed" msgstr "le verrou de détection est fermé" #: lib/logitech_receiver/notifications.py:505 msgid "discovery lock is open" msgstr "le verrou de détection est ouvert" #: lib/logitech_receiver/receiver.py:466 msgid "No paired devices." msgstr "Aucun périphérique jumelé." #: lib/logitech_receiver/receiver.py:468 lib/solaar/ui/window.py:612 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s périphérique jumelé." msgstr[1] "%(count)s périphériques jumelés." #: lib/logitech_receiver/settings.py:621 msgid "register" msgstr "registre" #: lib/logitech_receiver/settings.py:635 lib/logitech_receiver/settings.py:673 msgid "feature" msgstr "fonctionnalité" #: lib/logitech_receiver/settings_templates.py:183 msgid "Swap Fx function" msgstr "Fonction Swap Fx" #: lib/logitech_receiver/settings_templates.py:186 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Lorsque défini, les touches F1..F12 activeront leurs fonctions spéciales,\n" "et vous devez maintenir la touche FN pour activer leurs fonctions standards." #: lib/logitech_receiver/settings_templates.py:191 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Lorsque non défini, les touches F1..F12 activeront leurs fonctions " "standards,\n" "et vous devez maintenir la touche FN pour activer leurs fonctions spéciales." #: lib/logitech_receiver/settings_templates.py:199 msgid "Hand Detection" msgstr "Détection manuelle" #: lib/logitech_receiver/settings_templates.py:200 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Allume l'éclairage lorsque les mains passent au-dessus du clavier." #: lib/logitech_receiver/settings_templates.py:207 msgid "Scroll Wheel Smooth Scrolling" msgstr "Défilement fluide à la molette" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:455 #: lib/logitech_receiver/settings_templates.py:484 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Mode haute sensibilité pour défilement vertical avec la roulette." #: lib/logitech_receiver/settings_templates.py:215 msgid "Side Scrolling" msgstr "Défilement latéral" #: lib/logitech_receiver/settings_templates.py:217 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Lorsque désactivé, l'appui sur les côtés de la roulette envoie des " "évènements\n" " de bouton personnalisés à la place des évènements standards de défilement " "latéral." #: lib/logitech_receiver/settings_templates.py:227 msgid "Sensitivity (DPI - older mice)" msgstr "Sensibilité (DPI - souris plus anciennne)" #: lib/logitech_receiver/settings_templates.py:228 #: lib/logitech_receiver/settings_templates.py:1064 #: lib/logitech_receiver/settings_templates.py:1092 msgid "Mouse movement sensitivity" msgstr "Sensibilité du mouvement de la souris" #: lib/logitech_receiver/settings_templates.py:301 msgid "Backlight Timed" msgstr "Rétroéclairage chronométré" #: lib/logitech_receiver/settings_templates.py:302 #: lib/logitech_receiver/settings_templates.py:442 msgid "Set illumination time for keyboard." msgstr "Définir le temps d'éclairage du clavier." #: lib/logitech_receiver/settings_templates.py:313 msgid "Backlight" msgstr "Rétroéclairage" #: lib/logitech_receiver/settings_templates.py:314 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Niveau d'éclairage du clavier. Les modifications apportées ne sont " "appliquées qu'en mode manuel." #: lib/logitech_receiver/settings_templates.py:346 msgid "Automatic" msgstr "Automatique" #: lib/logitech_receiver/settings_templates.py:348 msgid "Manual" msgstr "Manuel" #: lib/logitech_receiver/settings_templates.py:350 msgid "Enabled" msgstr "Activé" #: lib/logitech_receiver/settings_templates.py:356 msgid "Backlight Level" msgstr "Niveau de rétroéclairage" #: lib/logitech_receiver/settings_templates.py:357 msgid "Illumination level on keyboard when in Manual mode." msgstr "Niveau d'éclairage du clavier en mode manuel." #: lib/logitech_receiver/settings_templates.py:414 msgid "Backlight Delay Hands Out" msgstr "Délai de rétroéclairage sans les mains" #: lib/logitech_receiver/settings_templates.py:415 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Délai jusqu'à ce que le rétroéclairage s'éteigne avec les mains éloignées du " "clavier." #: lib/logitech_receiver/settings_templates.py:423 msgid "Backlight Delay Hands In" msgstr "Délai de rétroéclairage avec les mains" #: lib/logitech_receiver/settings_templates.py:424 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Délai jusqu'à ce que le rétroéclairage s'éteigne avec les mains près du " "clavier." #: lib/logitech_receiver/settings_templates.py:432 msgid "Backlight Delay Powered" msgstr "Délai de rétroéclairage alimenté" #: lib/logitech_receiver/settings_templates.py:433 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Délai jusqu'à ce que le rétroéclairage s'éteigne avec une alimentation " "externe." #: lib/logitech_receiver/settings_templates.py:441 msgid "Backlight (Seconds)" msgstr "Rétroéclairage (Secondes)" #: lib/logitech_receiver/settings_templates.py:453 msgid "Scroll Wheel High Resolution" msgstr "Molette haute résolution" #: lib/logitech_receiver/settings_templates.py:457 #: lib/logitech_receiver/settings_templates.py:486 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Définir pour ignorer si le défilement est anormalement rapide ou lent" #: lib/logitech_receiver/settings_templates.py:464 #: lib/logitech_receiver/settings_templates.py:495 msgid "Scroll Wheel Diversion" msgstr "Interception de la molette" #: lib/logitech_receiver/settings_templates.py:466 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Active l'envoi par la molette de notifications LOWRES_WHEEL HID++ (ce qui " "déclenche les règles Solaar qui sont ignorées sinon)." #: lib/logitech_receiver/settings_templates.py:473 msgid "Scroll Wheel Direction" msgstr "Direction de la molette" #: lib/logitech_receiver/settings_templates.py:474 msgid "Invert direction for vertical scroll with wheel." msgstr "Direction inversée pour le défilement vertical avec la molette." #: lib/logitech_receiver/settings_templates.py:482 msgid "Scroll Wheel Resolution" msgstr "Résolution de la molette" #: lib/logitech_receiver/settings_templates.py:497 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Active l'envoi par la molette de notifications HIRES_WHEEL HID++ (ce qui " "déclenche les règles Solaar qui sont ignorées sinon)." #: lib/logitech_receiver/settings_templates.py:506 msgid "Sensitivity (Pointer Speed)" msgstr "Sensibilité (vitesse du pointeur)" #: lib/logitech_receiver/settings_templates.py:507 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "" "Multiplicateur de vitesse pour la souris (256 est le multiplicateur normal)." #: lib/logitech_receiver/settings_templates.py:517 msgid "Thumb Wheel Diversion" msgstr "Interception de la molette de pouce" #: lib/logitech_receiver/settings_templates.py:519 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Active l'envoi par la molette de pouce de notifications THUMB_WHEEL HID++ " "(ce qui déclenche les règles Solaar qui sont ignorées sinon)." #: lib/logitech_receiver/settings_templates.py:528 msgid "Thumb Wheel Direction" msgstr "Direction de la molette de pouce" #: lib/logitech_receiver/settings_templates.py:529 msgid "Invert thumb wheel scroll direction." msgstr "Inverser la direction du défilement de la molette de pouce." #: lib/logitech_receiver/settings_templates.py:549 msgid "Onboard Profiles" msgstr "Profils embarqués" #: lib/logitech_receiver/settings_templates.py:550 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Activer un profil embarqué, qui contrôle le taux de rapport, la sensibilité " "et les actions des boutons" #: lib/logitech_receiver/settings_templates.py:594 #: lib/logitech_receiver/settings_templates.py:627 msgid "Report Rate" msgstr "Taux de rapport" #: lib/logitech_receiver/settings_templates.py:596 #: lib/logitech_receiver/settings_templates.py:629 msgid "Frequency of device movement reports" msgstr "Fréquence des rapports de mouvement des périphériques" #: lib/logitech_receiver/settings_templates.py:596 #: lib/logitech_receiver/settings_templates.py:629 #: lib/logitech_receiver/settings_templates.py:1064 #: lib/logitech_receiver/settings_templates.py:1092 #: lib/logitech_receiver/settings_templates.py:1471 #: lib/logitech_receiver/settings_templates.py:1502 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "Peut nécessiter de désactiver les profils embarqués pour être effectif." #: lib/logitech_receiver/settings_templates.py:657 msgid "Divert crown events" msgstr "Définir les évènements de la couronne" #: lib/logitech_receiver/settings_templates.py:658 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Active l'envoi par la couronne de notifications CROWN HID++ (ce qui " "déclenche les règles Solaar qui sont ignorées sinon)." #: lib/logitech_receiver/settings_templates.py:666 msgid "Crown smooth scroll" msgstr "Défilement fluide de la couronne" #: lib/logitech_receiver/settings_templates.py:667 msgid "Set crown smooth scroll" msgstr "Définir le défilement fluide de la couronne" #: lib/logitech_receiver/settings_templates.py:675 msgid "Divert G and M Keys" msgstr "Interception des touches G et M" #: lib/logitech_receiver/settings_templates.py:676 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Active l'envoi par les touches G et M de notifications HID++ (ce qui " "déclenche les règles Solaar qui sont ignorées sinon)." #: lib/logitech_receiver/settings_templates.py:690 msgid "Scroll Wheel Ratcheted" msgstr "Molette mode cliquet" #: lib/logitech_receiver/settings_templates.py:691 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Basculez la molette de la souris entre le mode cliquet à vitesse contrôlée " "et toujours en roue libre." #: lib/logitech_receiver/settings_templates.py:693 msgid "Freespinning" msgstr "Roue libre" #: lib/logitech_receiver/settings_templates.py:693 msgid "Ratcheted" msgstr "Cliquet" #: lib/logitech_receiver/settings_templates.py:700 msgid "Scroll Wheel Ratchet Speed" msgstr "Vitesse de la molette mode cliquet" #: lib/logitech_receiver/settings_templates.py:702 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Utilisez la vitesse de la molette de la souris pour basculer entre le mode " "cliquet et le mode roue libre.\n" "La molette est toujours en mode cliquet à 50." #: lib/logitech_receiver/settings_templates.py:752 msgid "Scroll Wheel Ratchet Torque" msgstr "Couple de la molette mode cliquet" #: lib/logitech_receiver/settings_templates.py:753 msgid "Change the torque needed to overcome the ratchet." msgstr "Modifiez le couple nécessaire pour vaincre le mode cliquet." #: lib/logitech_receiver/settings_templates.py:788 msgid "Key/Button Actions" msgstr "Actions des boutons" #: lib/logitech_receiver/settings_templates.py:790 msgid "Change the action for the key or button." msgstr "Modifiez l'action pour la touche ou pour le bouton." #: lib/logitech_receiver/settings_templates.py:792 msgid "Overridden by diversion." msgstr "Remplacé par interception." #: lib/logitech_receiver/settings_templates.py:794 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "La modification d'importantes actions (comme le bouton gauche de la souris) " "pourrait rendre le système inutilisable." #: lib/logitech_receiver/settings_templates.py:969 msgid "Key/Button Diversion" msgstr "Interception des boutons/touches" #: lib/logitech_receiver/settings_templates.py:970 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "Active l'envoi par la touche ou le bouton de notifications HID++ " "(interception), ou une gestuelle de souris ou l'échelle de déplacement" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 #: lib/logitech_receiver/settings_templates.py:975 msgid "Diverted" msgstr "Interception" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 msgid "Mouse Gestures" msgstr "Gestuelle à la souris" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 #: lib/logitech_receiver/settings_templates.py:975 msgid "Regular" msgstr "Normal" #: lib/logitech_receiver/settings_templates.py:973 msgid "Sliding DPI" msgstr "Amplification du déplacement" #: lib/logitech_receiver/settings_templates.py:1063 #: lib/logitech_receiver/settings_templates.py:1091 msgid "Sensitivity (DPI)" msgstr "Sensibilité (DPI)" #: lib/logitech_receiver/settings_templates.py:1173 msgid "Sensitivity Switching" msgstr "Basculement de la sensibilité" #: lib/logitech_receiver/settings_templates.py:1175 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Bascule la sensibilité actuelle et la sensibilité enregistrée quand la " "touche ou le bouton sont appuyés.\n" "S'il n'y aucune sensibilité enregistrée, rappelle uniquement la sensibilité " "courante" #: lib/logitech_receiver/settings_templates.py:1179 msgid "Off" msgstr "Eteint" #: lib/logitech_receiver/settings_templates.py:1210 msgid "Disable keys" msgstr "Désactiver les touches" #: lib/logitech_receiver/settings_templates.py:1211 msgid "Disable specific keyboard keys." msgstr "Désactiver des touches spécifiques du clavier." #: lib/logitech_receiver/settings_templates.py:1214 #, python-format msgid "Disables the %s key." msgstr "Désactive la touche %s." #: lib/logitech_receiver/settings_templates.py:1227 #: lib/logitech_receiver/settings_templates.py:1284 msgid "Set OS" msgstr "Définir le système d'exploitation" #: lib/logitech_receiver/settings_templates.py:1228 #: lib/logitech_receiver/settings_templates.py:1285 msgid "Change keys to match OS." msgstr "Modifier les touches pour correspondre au système d'exploitation." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Change Host" msgstr "Changer d'hôte" #: lib/logitech_receiver/settings_templates.py:1298 msgid "Switch connection to a different host" msgstr "Commuter la connexion vers un autre hôte" #: lib/logitech_receiver/settings_templates.py:1322 msgid "Performs a left click." msgstr "Réalise un clic gauche." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Single tap" msgstr "Une tape simple" #: lib/logitech_receiver/settings_templates.py:1323 msgid "Performs a right click." msgstr "Réalise un clic droit." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Single tap with two fingers" msgstr "Une tape simple avec deux doigts" #: lib/logitech_receiver/settings_templates.py:1324 msgid "Single tap with three fingers" msgstr "Une tape simple avec trois doigts" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Double tap" msgstr "Une double tape" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Performs a double click." msgstr "Réalise un double clic." #: lib/logitech_receiver/settings_templates.py:1329 msgid "Double tap with two fingers" msgstr "Une double tape avec deux doigts" #: lib/logitech_receiver/settings_templates.py:1330 msgid "Double tap with three fingers" msgstr "Une double tape avec trois doigts" #: lib/logitech_receiver/settings_templates.py:1333 msgid "Drags items by dragging the finger after double tapping." msgstr "Déplace des items en faisant glisser le doigt après la double tape." #: lib/logitech_receiver/settings_templates.py:1333 msgid "Tap and drag" msgstr "Taper-glisser" #: lib/logitech_receiver/settings_templates.py:1335 msgid "Tap and drag with two fingers" msgstr "Taper-glisser avec deux doigts" #: lib/logitech_receiver/settings_templates.py:1336 msgid "Drags items by dragging the fingers after double tapping." msgstr "Déplace des items en faisant glisser les doigts après la double tape." #: lib/logitech_receiver/settings_templates.py:1338 msgid "Tap and drag with three fingers" msgstr "Taper-glisser avec trois doigts" #: lib/logitech_receiver/settings_templates.py:1341 msgid "Suppress tap and edge gestures" msgstr "Supprimer les tapes et les gestes" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "Désactive les tapes et les gestes de bords (équivaut à presser " "Fn+ClicGauche)." #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scroll with one finger" msgstr "Défilement à un doigt" #: lib/logitech_receiver/settings_templates.py:1344 #: lib/logitech_receiver/settings_templates.py:1345 #: lib/logitech_receiver/settings_templates.py:1348 msgid "Scrolls." msgstr "Défilements." #: lib/logitech_receiver/settings_templates.py:1345 #: lib/logitech_receiver/settings_templates.py:1348 msgid "Scroll with two fingers" msgstr "Défilement à deux doigts" #: lib/logitech_receiver/settings_templates.py:1346 msgid "Scroll horizontally with two fingers" msgstr "Défilement horizontal à deux doigts" #: lib/logitech_receiver/settings_templates.py:1346 msgid "Scrolls horizontally." msgstr "Défile horizontalement." #: lib/logitech_receiver/settings_templates.py:1347 msgid "Scroll vertically with two fingers" msgstr "Défilement vertical à deux doigts" #: lib/logitech_receiver/settings_templates.py:1347 msgid "Scrolls vertically." msgstr "Défile verticalement." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Inverts the scrolling direction." msgstr "Inverse la direction de défilement." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Natural scrolling" msgstr "Défilement naturel" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Enables the thumbwheel." msgstr "Active la molette de pouce." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Thumbwheel" msgstr "Molette de pouce" #: lib/logitech_receiver/settings_templates.py:1361 #: lib/logitech_receiver/settings_templates.py:1365 msgid "Swipe from the top edge" msgstr "Glissement depuis le bord supérieur" #: lib/logitech_receiver/settings_templates.py:1362 msgid "Swipe from the left edge" msgstr "Glissement depuis le bord gauche" #: lib/logitech_receiver/settings_templates.py:1363 msgid "Swipe from the right edge" msgstr "Glissement depuis le bord droit" #: lib/logitech_receiver/settings_templates.py:1364 msgid "Swipe from the bottom edge" msgstr "Glissement depuis le bord inférieur" #: lib/logitech_receiver/settings_templates.py:1366 msgid "Swipe two fingers from the left edge" msgstr "Glissement à deux doigts depuis le bord gauche" #: lib/logitech_receiver/settings_templates.py:1367 msgid "Swipe two fingers from the right edge" msgstr "Glissement à deux doigts depuis le bord droit" #: lib/logitech_receiver/settings_templates.py:1368 msgid "Swipe two fingers from the bottom edge" msgstr "Glissement à deux doigts depuis le bord inférieur" #: lib/logitech_receiver/settings_templates.py:1369 msgid "Swipe two fingers from the top edge" msgstr "Glissement à deux doigts depuis le bord supérieur" #: lib/logitech_receiver/settings_templates.py:1370 #: lib/logitech_receiver/settings_templates.py:1374 msgid "Pinch to zoom out; spread to zoom in." msgstr "Pincer pour réduire le zoom; écarter pour agrandir le zoom." #: lib/logitech_receiver/settings_templates.py:1370 msgid "Zoom with two fingers." msgstr "Zoom à deux doigts." #: lib/logitech_receiver/settings_templates.py:1371 msgid "Pinch to zoom out." msgstr "Pincer pour réduire le zoom." #: lib/logitech_receiver/settings_templates.py:1372 msgid "Spread to zoom in." msgstr "Écarter pour agrandir le zoom." #: lib/logitech_receiver/settings_templates.py:1373 msgid "Zoom with three fingers." msgstr "Zoom à trois doigts." #: lib/logitech_receiver/settings_templates.py:1374 msgid "Zoom with two fingers" msgstr "Zoom à deux doigts" #: lib/logitech_receiver/settings_templates.py:1392 msgid "Pixel zone" msgstr "Zone de pixels" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Ratio zone" msgstr "Zone de rapport" #: lib/logitech_receiver/settings_templates.py:1394 msgid "Scale factor" msgstr "Facteur d’échelle" #: lib/logitech_receiver/settings_templates.py:1394 msgid "Sets the cursor speed." msgstr "Définit la vitesse du curseur." #: lib/logitech_receiver/settings_templates.py:1398 msgid "Left-most coordinate." msgstr "Coordonnée la plus à gauche." #: lib/logitech_receiver/settings_templates.py:1399 msgid "Bottom" msgstr "Bas" #: lib/logitech_receiver/settings_templates.py:1399 msgid "Bottom coordinate." msgstr "Coordonnée du bas." #: lib/logitech_receiver/settings_templates.py:1400 msgid "Width" msgstr "Largeur" #: lib/logitech_receiver/settings_templates.py:1400 msgid "Width." msgstr "Largeur." #: lib/logitech_receiver/settings_templates.py:1401 msgid "Height" msgstr "Hauteur" #: lib/logitech_receiver/settings_templates.py:1401 msgid "Height." msgstr "Hauteur." #: lib/logitech_receiver/settings_templates.py:1402 msgid "Cursor speed." msgstr "Vitesse du curseur." #: lib/logitech_receiver/settings_templates.py:1402 msgid "Scale" msgstr "Échelle" #: lib/logitech_receiver/settings_templates.py:1408 msgid "Gestures" msgstr "Gestes" #: lib/logitech_receiver/settings_templates.py:1409 msgid "Tweak the mouse/touchpad behaviour." msgstr "Personnaliser le comportement de la souris ou du pavé tactile." #: lib/logitech_receiver/settings_templates.py:1425 msgid "Gestures Diversion" msgstr "Interception de la gestuelle" #: lib/logitech_receiver/settings_templates.py:1426 msgid "Divert mouse/touchpad gestures." msgstr "Interception de la gestuelle de la souris ou du pavé tactile." #: lib/logitech_receiver/settings_templates.py:1442 msgid "Gesture params" msgstr "Paramètres de la gestuelle" #: lib/logitech_receiver/settings_templates.py:1443 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Modifier les paramètres numérique de la souris ou du pavé tactile." #: lib/logitech_receiver/settings_templates.py:1467 msgid "M-Key LEDs" msgstr "LEDs de touche M" #: lib/logitech_receiver/settings_templates.py:1469 msgid "Control the M-Key LEDs." msgstr "Contrôler les LEDs de touche M." #: lib/logitech_receiver/settings_templates.py:1473 #: lib/logitech_receiver/settings_templates.py:1504 msgid "May need G Keys diverted to be effective." msgstr "" "Peut nécessiter que les touches G soient interceptées pour être effectif." #: lib/logitech_receiver/settings_templates.py:1479 #, python-format msgid "Lights up the %s key." msgstr "Allume la touche %s." #: lib/logitech_receiver/settings_templates.py:1498 msgid "MR-Key LED" msgstr "LED de touche MR" #: lib/logitech_receiver/settings_templates.py:1500 msgid "Control the MR-Key LED." msgstr "Contrôler la LED de touche MR." #: lib/logitech_receiver/settings_templates.py:1521 msgid "Persistent Key/Button Mapping" msgstr "Mappage touche/bouton persistant" #: lib/logitech_receiver/settings_templates.py:1523 msgid "Permanently change the mapping for the key or button." msgstr "Modifiez de manière permanente le mappage de la touche ou du bouton." #: lib/logitech_receiver/settings_templates.py:1525 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "La modification de touches ou de boutons importants (comme le bouton gauche " "de la souris) pourrait rendre le système inutilisable." #: lib/logitech_receiver/settings_templates.py:1582 msgid "Sidetone" msgstr "Tonalité latérale" #: lib/logitech_receiver/settings_templates.py:1583 msgid "Set sidetone level." msgstr "Régler le niveau de tonalité latérale." #: lib/logitech_receiver/settings_templates.py:1592 msgid "Equalizer" msgstr "Égaliseur" #: lib/logitech_receiver/settings_templates.py:1593 #: lib/logitech_receiver/settings_templates.py:1902 msgid "Set equalizer levels." msgstr "Définir les niveaux de l'égaliseur." #: lib/logitech_receiver/settings_templates.py:1615 #: lib/logitech_receiver/settings_templates.py:1930 #: lib/logitech_receiver/settings_templates.py:2056 #: lib/logitech_receiver/settings_templates.py:2058 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1621 msgid "Power Management" msgstr "Gestion de l'alimentation" #: lib/logitech_receiver/settings_templates.py:1622 msgid "Power off in minutes (0 for never)." msgstr "Éteindre en quelques minutes (0 pour jamais)." #: lib/logitech_receiver/settings_templates.py:1634 msgid "Eco Mode" msgstr "Mode éco" #: lib/logitech_receiver/settings_templates.py:1635 msgid "Battery saver mode." msgstr "Mode économie d'énergie." #: lib/logitech_receiver/settings_templates.py:1653 msgid "Do Not Disturb" msgstr "Ne pas déranger" #: lib/logitech_receiver/settings_templates.py:1654 msgid "Suppress notification sounds." msgstr "Supprimer les notifications sonores." #: lib/logitech_receiver/settings_templates.py:1661 msgid "Mic Mute" msgstr "Mise en sourdine du micro" #: lib/logitech_receiver/settings_templates.py:1662 msgid "Mute the microphone." msgstr "Coupez le son du micro." #: lib/logitech_receiver/settings_templates.py:1681 msgid "Mic SNR" msgstr "Rapport signal/bruit du micro" #: lib/logitech_receiver/settings_templates.py:1682 msgid "Microphone signal-to-noise ratio enhancement." msgstr "Amélioration du rapport signal/bruit du micro." #: lib/logitech_receiver/settings_templates.py:1689 msgid "AI Noise Reduction" msgstr "Réduction du bruit par IA" #: lib/logitech_receiver/settings_templates.py:1690 msgid "Enable AI noise reduction." msgstr "Activer la réduction du bruit par IA." #: lib/logitech_receiver/settings_templates.py:1697 msgid "AI Noise Reduction Level" msgstr "Niveau de réduction du bruit par IA" #: lib/logitech_receiver/settings_templates.py:1698 msgid "AI noise reduction intensity." msgstr "Intensité de réduction du bruit par IA." #: lib/logitech_receiver/settings_templates.py:1707 msgid "Headset Sidetone" msgstr "Retour audio du casque" #: lib/logitech_receiver/settings_templates.py:1708 msgid "Sidetone level (0 = off, 100 = max)." msgstr "Niveau de retour audio (0 = désactivé, 100 = maximum)." #: lib/logitech_receiver/settings_templates.py:1771 msgid "Mic Gain" msgstr "Gain du micro" #: lib/logitech_receiver/settings_templates.py:1772 msgid "Microphone gain level." msgstr "Niveau de gain du microphone." #: lib/logitech_receiver/settings_templates.py:1824 msgid "Audio Mix Balance" msgstr "Équilibrage du mixage audio" #: lib/logitech_receiver/settings_templates.py:1825 msgid "Balance between game and chat audio." msgstr "Équilibre entre le son du jeu et celui du chat." #: lib/logitech_receiver/settings_templates.py:1876 msgid "Auto Sleep Timeout" msgstr "Délai de mise en veille automatique" #: lib/logitech_receiver/settings_templates.py:1877 msgid "" "Idle time in minutes before the headset enters sleep mode (0 = disabled)." msgstr "" "Temps d'inactivité en minutes avant que le casque ne passe en mode veille (0 " "= désactivé)." #: lib/logitech_receiver/settings_templates.py:1901 msgid "Headset Equalizer" msgstr "Égaliseur du casque" #: lib/logitech_receiver/settings_templates.py:1996 msgid "Headset Advanced EQ" msgstr "Égaliseur avancé du casque" #: lib/logitech_receiver/settings_templates.py:1997 msgid "Per-band gain for the headset's active parametric EQ." msgstr "Gain par bande pour l'égaliseur paramétrique actif du casque." #: lib/logitech_receiver/settings_templates.py:2268 msgid "EQ Preset" msgstr "Préréglage de l'égaliseur" #: lib/logitech_receiver/settings_templates.py:2269 msgid "Switch the active EQ preset. Factory presets are read-only." msgstr "" "Basculer le préréglage d'égalisation actif. Les préréglages d'usine sont en " "lecture seule." #: lib/logitech_receiver/settings_templates.py:2294 msgid "Slot" msgstr "" #: lib/logitech_receiver/settings_templates.py:2296 msgid "(factory)" msgstr "(usine)" #: lib/logitech_receiver/settings_templates.py:2429 #: lib/logitech_receiver/settings_templates.py:3206 #: lib/logitech_receiver/settings_templates.py:3298 msgid "LED Control" msgstr "Contrôle de LED" #: lib/logitech_receiver/settings_templates.py:2430 msgid "Allow Solaar to control the headset LED zones." msgstr "Autoriser Solaar à contrôler les zones de LED du casque." #: lib/logitech_receiver/settings_templates.py:2478 msgid "Per-zone Lighting" msgstr "Éclairage par zone" #: lib/logitech_receiver/settings_templates.py:2480 msgid "" "Override individual zone colors. 'No change' inherits the LEDs Primary " "color.\n" "LED Control needs to be set to Solaar to be effective." msgstr "" "Remplacer les couleurs de chaque zone individuellement. L'option « Aucun " "changement » conserve la couleur principale des LEDs.\n" "Le contrôle de LED doit être défini sur Solaar pour être effectif." #: lib/logitech_receiver/settings_templates.py:2498 msgid "Zone" msgstr "Zone" #: lib/logitech_receiver/settings_templates.py:2620 #: lib/logitech_receiver/settings_templates.py:2908 #: lib/logitech_receiver/settings_templates.py:3648 msgid "Secondary" msgstr "Dérivé" #: lib/logitech_receiver/settings_templates.py:2621 #: lib/logitech_receiver/settings_templates.py:3234 msgid "Speed" msgstr "Vitesse" #: lib/logitech_receiver/settings_templates.py:2688 msgid "Startup Effect" msgstr "Effet de démarrage" #: lib/logitech_receiver/settings_templates.py:2690 msgid "Firmware lighting effect played when the headset powers on or wakes." msgstr "" #: lib/logitech_receiver/settings_templates.py:2692 #: lib/logitech_receiver/settings_templates.py:2703 msgid "Device default: Primary #00B8FC, Secondary #FF00AB, Speed 100." msgstr "" #: lib/logitech_receiver/settings_templates.py:2699 msgid "Shutdown Effect" msgstr "Effet de fermeture" #: lib/logitech_receiver/settings_templates.py:2701 msgid "Firmware lighting effect played when the headset powers off or sleeps." msgstr "" #: lib/logitech_receiver/settings_templates.py:2710 msgid "Passive Effect" msgstr "Effet passif" #: lib/logitech_receiver/settings_templates.py:2712 msgid "Firmware lighting effect played while the headset is idle." msgstr "" #: lib/logitech_receiver/settings_templates.py:2714 msgid "Device default: Primary #00B8FC, Secondary #FF00AB, Speed 75." msgstr "" #: lib/logitech_receiver/settings_templates.py:2833 msgid "Onboard Effect" msgstr "Effet embarqué" #: lib/logitech_receiver/settings_templates.py:2834 msgid "Firmware RGB effect the headset plays on its own." msgstr "" #: lib/logitech_receiver/settings_templates.py:2909 #: lib/logitech_receiver/settings_templates.py:3243 msgid "Intensity" msgstr "Intensité" #: lib/logitech_receiver/settings_templates.py:2910 #: lib/logitech_receiver/settings_templates.py:3245 msgid "Saturation" msgstr "Saturation" #: lib/logitech_receiver/settings_templates.py:2914 #: lib/logitech_receiver/settings_templates.py:3238 msgid "Period" msgstr "Période" #: lib/logitech_receiver/settings_templates.py:2919 #: lib/logitech_receiver/settings_templates.py:3250 msgid "Direction" msgstr "Direction" #: lib/logitech_receiver/settings_templates.py:3134 msgid "Brightness Control" msgstr "Contrôle de la luminosité" #: lib/logitech_receiver/settings_templates.py:3135 msgid "Control overall brightness" msgstr "Contrôle de la luminosité globale" #: lib/logitech_receiver/settings_templates.py:3207 #: lib/logitech_receiver/settings_templates.py:3299 msgid "Allow Solaar to control LED zones." msgstr "Autoriser Solaar à contrôler les zones de LED." #: lib/logitech_receiver/settings_templates.py:3230 #: lib/logitech_receiver/settings_templates.py:3744 msgid "LED Zone Effects" msgstr "Effet de zone de LED" #: lib/logitech_receiver/settings_templates.py:3231 #: lib/logitech_receiver/settings_templates.py:3399 #: lib/logitech_receiver/settings_templates.py:3439 #: lib/logitech_receiver/settings_templates.py:3546 #: lib/logitech_receiver/settings_templates.py:3745 msgid "LED Control needs to be enabled." msgstr "Le contrôle de LED doit être activé." #: lib/logitech_receiver/settings_templates.py:3231 #: lib/logitech_receiver/settings_templates.py:3745 msgid "Set effect for LED Zone" msgstr "Définir l'effet pour la zone de LED" #: lib/logitech_receiver/settings_templates.py:3233 msgid "Color" msgstr "Couleur" #: lib/logitech_receiver/settings_templates.py:3244 msgid "Ramp" msgstr "" #: lib/logitech_receiver/settings_templates.py:3246 msgid "Waveform" msgstr "" #: lib/logitech_receiver/settings_templates.py:3279 msgid "LEDs" msgstr "LEDs" #: lib/logitech_receiver/settings_templates.py:3398 msgid "Idle Timeout" msgstr "Délai d'inactivité" #: lib/logitech_receiver/settings_templates.py:3399 msgid "Time without input before LED idle effect starts." msgstr "" "Délai d'inactivité avant le déclenchement de l'effet de veille de la LED." #: lib/logitech_receiver/settings_templates.py:3435 msgid "Idle Effect" msgstr "Effet d'inactivité" #: lib/logitech_receiver/settings_templates.py:3437 msgid "" "What happens to LEDs when idle — dim to a percentage, change the base color, " "or play an animation." msgstr "" "Ce qu'il se passe lorsque les LEDs sont inactives — elles s'assombrissent à " "un certain pourcentage, leurs couleurs de base changent ou elles lancent une " "animation." #: lib/logitech_receiver/settings_templates.py:3520 msgid "No change" msgstr "Aucun changement" #: lib/logitech_receiver/settings_templates.py:3545 msgid "Sleep Timeout" msgstr "Délai de mise en veille" #: lib/logitech_receiver/settings_templates.py:3546 msgid "Time without input before LEDs fade off completely." msgstr "Durée d'inactivité avant l'extinction complète des LEDs." #: lib/logitech_receiver/settings_templates.py:3719 msgid "Startup Animation" msgstr "Animation de démarrage" #: lib/logitech_receiver/settings_templates.py:3722 msgid "" "Firmware-played animation when the keyboard wakes from deep sleep or powers " "on.\n" "Setting persists on the device (non-volatile)." msgstr "" #: lib/logitech_receiver/settings_templates.py:3726 #: lib/logitech_receiver/settings_templates.py:3737 msgid "Device default: Primary #FF0081, Secondary #80AAFF." msgstr "" #: lib/logitech_receiver/settings_templates.py:3733 msgid "Shutdown Animation" msgstr "Animation de fermeture" #: lib/logitech_receiver/settings_templates.py:3735 msgid "" "Firmware-played animation when the keyboard powers off.\n" "Setting persists on the device (non-volatile)." msgstr "" #: lib/logitech_receiver/settings_templates.py:3847 #: lib/solaar/ui/perkey/dialog.py:87 msgid "Per-key Lighting" msgstr "Éclairage par touche" #: lib/logitech_receiver/settings_templates.py:3849 msgid "Control per-key lighting." msgstr "Contrôler l’éclairage par touche." #: lib/logitech_receiver/settings_templates.py:3851 msgid "" "LED Control needs to be enabled and the zone effect set to Static for per-" "key paint to be visible." msgstr "" #: lib/logitech_receiver/settings_templates.py:4182 msgid "Force Sensing Buttons" msgstr "Boutons à détection de pression" #: lib/logitech_receiver/settings_templates.py:4183 msgid "Change the force required to activate button." msgstr "Modifier la force nécessaire pour activer le bouton." #: lib/logitech_receiver/settings_templates.py:4200 msgid "Force Sensing Button" msgstr "Bouton à détection de pression" #: lib/logitech_receiver/settings_templates.py:4316 msgid "Analog Button Tuning" msgstr "" #: lib/logitech_receiver/settings_templates.py:4317 msgid "" "Configure analog button settings including actuation point, rapid trigger, " "and haptics." msgstr "" #: lib/logitech_receiver/settings_templates.py:4347 #, python-format msgid "Actuation point depth (1=shallow, %d=deep)." msgstr "" #: lib/logitech_receiver/settings_templates.py:4355 #, python-format msgid "Rapid trigger sensitivity (1..%d)." msgstr "Sensibilité de déclenchement rapide (1..%d)." #: lib/logitech_receiver/settings_templates.py:4363 #, python-format msgid "Click haptic feedback intensity (0=off, %d=max)." msgstr "Intensité du retour haptique par clic (0=désactivé, %d=max)." #: lib/logitech_receiver/settings_templates.py:4371 msgid "Haptic Feedback Level" msgstr "Niveau de retour haptique" #: lib/logitech_receiver/settings_templates.py:4372 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "Modifiez l'intensité du retour haptique. (Zéro pour éteindre.)" #: lib/logitech_receiver/settings_templates.py:4414 msgid "Play Haptic Waveform" msgstr "" #: lib/logitech_receiver/settings_templates.py:4415 msgid "Tell device to play a haptic waveform." msgstr "" #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "" "Un autre processus Solaar est déjà en cours d'exécution, il suffit donc " "d'afficher sa fenêtre" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Gère les récepteurs, claviers,\n" "souris et tablettes Logitech." #: lib/solaar/ui/about/model.py:64 msgid "Additional Programming" msgstr "Programmation supplémentaire" #: lib/solaar/ui/about/model.py:65 msgid "GUI design" msgstr "Interface graphique" #: lib/solaar/ui/about/model.py:67 msgid "Testing" msgstr "Testeur" #: lib/solaar/ui/about/model.py:75 msgid "Logitech documentation" msgstr "Documentațion Logitech" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Déconnecter" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:142 msgid "Cancel" msgstr "Annuler" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Erreur de permissions" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Un récepteur ou un périphérique Logitech (%s) a été trouvé, mais sans " "l'autorisation de l'ouvrir." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Si vous venez d'installer Solaar, essayez de déconnecter le récepteur ou le " "périphérique, puis de le reconnecter." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Impossible de se connecter au périphérique" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Un récepteur ou un périphérique Logitech a été trouvé à %s, mais une erreur " "s'est produite lors de la connexion." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Essayez de déconnecter le périphérique, puis de le reconnecter ou de " "l'éteindre puis de le rallumer." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "La déconnexion a échouée" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Impossible de dissocier %{device} de %{receiver}." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Le récepteur a retourné une erreur, sans plus de détails." #: lib/solaar/ui/config_panel.py:254 msgid "Complete - ENTER to change" msgstr "Complet - ENTRER pour modifier" #: lib/solaar/ui/config_panel.py:254 msgid "Incomplete" msgstr "Incomplet" #: lib/solaar/ui/config_panel.py:500 lib/solaar/ui/config_panel.py:552 #: lib/solaar/ui/config_panel.py:619 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "valeur %d" msgstr[1] "valeurs %d" #: lib/solaar/ui/config_panel.py:805 msgid "Changes allowed" msgstr "Modifications autorisées" #: lib/solaar/ui/config_panel.py:806 msgid "No changes allowed" msgstr "Aucune modification autorisée" #: lib/solaar/ui/config_panel.py:807 msgid "Ignore this setting" msgstr "Ignorer ce réglage" #: lib/solaar/ui/config_panel.py:1022 msgid "Working" msgstr "En fonctionnement" #: lib/solaar/ui/config_panel.py:1025 msgid "Read/write operation failed." msgstr "Les opérations de lecture/écriture ont échouée." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "raison non précisée" #: lib/solaar/ui/diversion_rules.py:104 msgid "Built-in rules" msgstr "Règles pré-définies" #: lib/solaar/ui/diversion_rules.py:104 msgid "User-defined rules" msgstr "Règles définies par l'utilisateur" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:1127 msgid "Rule" msgstr "Règle" #: lib/solaar/ui/diversion_rules.py:107 lib/solaar/ui/diversion_rules.py:383 #: lib/solaar/ui/diversion_rules.py:510 msgid "Sub-rule" msgstr "Sous-règle" #: lib/solaar/ui/diversion_rules.py:109 msgid "[empty]" msgstr "[vide]" #: lib/solaar/ui/diversion_rules.py:133 msgid "Make changes permanent?" msgstr "Rendre les modifications permanentes ?" #: lib/solaar/ui/diversion_rules.py:138 msgid "Yes" msgstr "Oui" #: lib/solaar/ui/diversion_rules.py:140 msgid "No" msgstr "Non" #: lib/solaar/ui/diversion_rules.py:145 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "" "Si vous choisissez Non, les changements seront perdus à la fermeture de " "Solaar." #: lib/solaar/ui/diversion_rules.py:274 msgid "Paste here" msgstr "Coller ici" #: lib/solaar/ui/diversion_rules.py:276 msgid "Paste above" msgstr "Coller ci-dessus" #: lib/solaar/ui/diversion_rules.py:278 msgid "Paste below" msgstr "Coller ci-dessous" #: lib/solaar/ui/diversion_rules.py:284 msgid "Paste rule here" msgstr "Coller la règle ici" #: lib/solaar/ui/diversion_rules.py:286 msgid "Paste rule above" msgstr "Coller la règle ci-dessus" #: lib/solaar/ui/diversion_rules.py:288 msgid "Paste rule below" msgstr "Coller la règle ci-dessous" #: lib/solaar/ui/diversion_rules.py:292 msgid "Paste rule" msgstr "Coller la règle" #: lib/solaar/ui/diversion_rules.py:307 msgid "Insert here" msgstr "Insérer ici" #: lib/solaar/ui/diversion_rules.py:309 msgid "Insert above" msgstr "Insérer ci-dessus" #: lib/solaar/ui/diversion_rules.py:311 msgid "Insert below" msgstr "Insérer ci-dessous" #: lib/solaar/ui/diversion_rules.py:317 msgid "Insert new rule here" msgstr "Insérer une nouvelle règle ici" #: lib/solaar/ui/diversion_rules.py:319 msgid "Insert new rule above" msgstr "Insérer une nouvelle règle ci-dessus" #: lib/solaar/ui/diversion_rules.py:321 msgid "Insert new rule below" msgstr "Insérer une nouvelle règle ci-dessous" #: lib/solaar/ui/diversion_rules.py:348 msgid "Flatten" msgstr "Aplanir" #: lib/solaar/ui/diversion_rules.py:381 msgid "Insert" msgstr "Insérer" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:512 #: lib/solaar/ui/diversion_rules.py:1159 msgid "Or" msgstr "Ou" #: lib/solaar/ui/diversion_rules.py:385 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1145 msgid "And" msgstr "Et" #: lib/solaar/ui/diversion_rules.py:387 msgid "Condition" msgstr "Condition" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Fonctionnalité" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Rapport" #: lib/solaar/ui/diversion_rules.py:391 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Processus" #: lib/solaar/ui/diversion_rules.py:392 msgid "Mouse process" msgstr "Processus de la souris" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Modificateurs" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Touche" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1433 msgid "Active" msgstr "Actif" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1391 #: lib/solaar/ui/diversion_rules.py:1442 lib/solaar/ui/diversion_rules.py:1488 msgid "Device" msgstr "Périphérique" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1468 msgid "Host" msgstr "Hôte" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/diversion_rules.py:1507 msgid "Setting" msgstr "Réglage" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Octets de test" #: lib/solaar/ui/diversion_rules.py:402 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Geste à la souris" #: lib/solaar/ui/diversion_rules.py:406 msgid "Action" msgstr "Action" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "Appui de touche" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Défilement de la souris" #: lib/solaar/ui/diversion_rules.py:410 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Clic de la souris" #: lib/solaar/ui/diversion_rules.py:411 msgid "Set" msgstr "Définir" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "Exécuter" #: lib/solaar/ui/diversion_rules.py:413 lib/solaar/ui/diversion_rules.py:1190 msgid "Later" msgstr "Plus tard" #: lib/solaar/ui/diversion_rules.py:442 msgid "Insert new rule" msgstr "Insérer nouvelle règle" #: lib/solaar/ui/diversion_rules.py:462 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Effacer" #: lib/solaar/ui/diversion_rules.py:484 msgid "Negate" msgstr "Nier" #: lib/solaar/ui/diversion_rules.py:508 msgid "Wrap with" msgstr "Entoure" #: lib/solaar/ui/diversion_rules.py:538 msgid "Cut" msgstr "Couper" #: lib/solaar/ui/diversion_rules.py:554 msgid "Paste" msgstr "Coller" #: lib/solaar/ui/diversion_rules.py:560 msgid "Copy" msgstr "Copier" #: lib/solaar/ui/diversion_rules.py:569 msgid "Solaar Rule Editor" msgstr "Éditeur de règle Solaar" #: lib/solaar/ui/diversion_rules.py:669 msgid "Save changes" msgstr "Sauvegarder les modifications" #: lib/solaar/ui/diversion_rules.py:674 msgid "Discard changes" msgstr "Annuler les modifications" #: lib/solaar/ui/diversion_rules.py:1105 msgid "This editor does not support the selected rule component yet." msgstr "Cet éditeur ne gère pas encore le composant de règle sélectionné." #: lib/solaar/ui/diversion_rules.py:1170 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Nombre de secondes de report. Le délai entre 0 et 1 est effectué avec une " "plus grande précision." #: lib/solaar/ui/diversion_rules.py:1208 msgid "Not" msgstr "Non" #: lib/solaar/ui/diversion_rules.py:1239 msgid "Toggle" msgstr "Basculer" #: lib/solaar/ui/diversion_rules.py:1240 msgid "True" msgstr "Vrai" #: lib/solaar/ui/diversion_rules.py:1241 msgid "False" msgstr "Faux" #: lib/solaar/ui/diversion_rules.py:1254 msgid "Unsupported setting" msgstr "Réglage non pris en charge" #: lib/solaar/ui/diversion_rules.py:1397 lib/solaar/ui/diversion_rules.py:1416 #: lib/solaar/ui/diversion_rules.py:1494 lib/solaar/ui/diversion_rules.py:1758 #: lib/solaar/ui/diversion_rules.py:1776 msgid "Originating device" msgstr "Périphérique d'origine" #: lib/solaar/ui/diversion_rules.py:1429 msgid "Device is active and its settings can be changed." msgstr "Le périphérique est actif et ses paramètres peuvent être modifiés." #: lib/solaar/ui/diversion_rules.py:1438 msgid "Device that originated the current notification." msgstr "Périphérique à l’origine de la notification actuelle." #: lib/solaar/ui/diversion_rules.py:1451 msgid "Name of host computer." msgstr "Nom de l'ordinateur hôte." #: lib/solaar/ui/diversion_rules.py:1521 msgid "Value" msgstr "Valeur" #: lib/solaar/ui/diversion_rules.py:1530 msgid "Item" msgstr "Item" #: lib/solaar/ui/diversion_rules.py:1818 msgid "Change setting on device" msgstr "Modifier le réglage sur le périphérique" #: lib/solaar/ui/diversion_rules.py:1834 msgid "Setting on device" msgstr "Réglage sur le périphérique" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s : jumele le nouveau périphérique" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" "Les récepteurs Bolt ne sont compatibles qu'avec des périphériques Bolt." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Appuyez sur un bouton ou une touche d'appairage jusqu'à ce que le voyant " "clignote rapidement." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" "Les récepteurs Unifying ne sont compatibles qu'avec des périphériques " "Unifying." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "" "Les autres récepteurs sont uniquement compatibles avec quelques " "périphériques." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "" "Pour la plupart des périphériques, allumez le périphérique que vous " "souhaitez jumeler." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "" "Si le périphérique est déjà allumé, éteignez-le et rallumez-le à nouveau." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" "Le périphérique doit être jumelé avec un récepteur de proximité allumé." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "Pour les périphériques disposant de plusieurs canaux, appuyez sur le bouton " "du canal que vous souhaitez appairer, maintenez-le enfoncé, puis relâchez-" "le.\n" "\n" "Ou utilisez le bouton de changement de canal pour sélectionner un canal, " "puis appuyez sur le bouton de changement de canal, maintenez-le enfoncé, " "puis relâchez-le." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Le voyant indicateur du canal doit clignoter rapidement." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Ce récepteur a %d jumelage restant." msgstr[1] "" "\n" "\n" "Ce récepteur a %d jumelages restants." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "L'annulation à ce stade n'utilisera pas de jumelage." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Entrer le mot de passe sur %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Taper %(passcode)s puis appuyez sur la touche Entrée." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "gauche" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "droit" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Appuyez %(code)s\n" "puis appuyez simultanément sur les boutons gauche et droit." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "La connexion sans fil n'est pas chiffrée" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Nouveau périphérique disponible :" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Le jumelage a échoué" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Assurez-vous que votre périphérique soit à portée, et que sa batterie soit " "suffisamment chargée." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "" "Un nouveau périphérique a été détecté, mais il n'est pas compatible avec ce " "récepteur." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "" "Il y a plus de périphériques jumelés que le récepteur ne peut en supporter." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Aucun autre détail n'est disponible à propos de l'erreur." #: lib/solaar/ui/perkey/control.py:178 msgid "(not loaded)" msgstr "(non chargé)" #: lib/solaar/ui/perkey/control.py:182 msgid "Open editor…" msgstr "Ouvrir l'éditeur…" #: lib/solaar/ui/perkey/control.py:183 msgid "Paint key colors on a keyboard layout" msgstr "" #: lib/solaar/ui/perkey/control.py:229 msgid "(no zones)" msgstr "(aucune zones)" #: lib/solaar/ui/perkey/control.py:233 #, python-brace-format msgid "{painted} / {total} keys painted" msgstr "" #: lib/solaar/ui/perkey/editor.py:54 msgid "Brush" msgstr "" #: lib/solaar/ui/perkey/editor.py:54 msgid "Click or drag to paint individual keys" msgstr "Cliquez ou faites glisser pour colorer les touches individuellement" #: lib/solaar/ui/perkey/editor.py:55 msgid "Drag to select a rectangle of keys, painted on release" msgstr "" #: lib/solaar/ui/perkey/editor.py:55 msgid "Rect" msgstr "" #: lib/solaar/ui/perkey/editor.py:56 msgid "Fill" msgstr "Remplir" #: lib/solaar/ui/perkey/editor.py:56 msgid "Flood-fill connected keys of the same color with the active color" msgstr "" #: lib/solaar/ui/perkey/editor.py:59 msgid "Drag to fade from previous color to active color" msgstr "" #: lib/solaar/ui/perkey/palette.py:90 msgid "Active color" msgstr "Couleur active" #: lib/solaar/ui/perkey/palette.py:95 msgid "Paint as 'no change' — clears the cell to the zone base color" msgstr "" #: lib/solaar/ui/perkey/palette.py:96 msgid "Unset" msgstr "Non défini" #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simule un clic combiné ou une pression ou un relâchement.\n" "Sous Wayland cela nécessite un accès en écriture au périphérique /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Ajouter une touche" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Clic" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Appuyer" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Relâcher" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simule un défilement de souris.\n" "Sous Wayland cela nécessite un accès en écriture au périphérique /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simule un clic de souris.\n" "Sous Wayland cela nécessite un accès en écriture au périphérique /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Bouton" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Action (et nombre, en cas de clic)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Exécuter une commande avec paramètres." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Ajouter un paramètre" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "Processus actif X11. Pour une utilisation dans X11 uniquement." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "Processus de la souris X11. Pour une utilisation dans X11 uniquement." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "Processus de la souris" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "" "Nom de la fonction de notification déclenchant le traitement de la règle." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "" "Indique le nombre de notifications déclenchant le traitement de la règle." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Modificateurs de clavier actifs. Pas toujours disponible sous Wayland." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Interception de touche ou bouton appuyé ou relâché.\n" "Utiliser l'interception de touche/bouton et les paramètres Interception des " "touches G pour intercepter les touches et les boutons." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Enfoncement de touche" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Relâchement de touche" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "La touche/le bouton intercepté est actuellement enfoncé.\n" "Utiliser l'interception de touche/bouton et les paramètres Interception des " "touches G pour intercepter les touches et les boutons." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "" "Condition de test déclenchant le traitement de la règle en cas de " "notification." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Paramètre" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "début (inclusif)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "fin (exclusif)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "plage" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "maximum" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "octets %(0)d à %(1)d, allant de %(2)d à %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "masque" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "octets %(0)d à %(1)d, masque %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Bit ou plage d'octets dans un message de notification déclenchant le " "traitement d'une règle." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "type" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Geste de la souris avec bouton d'initialisation optionnel suivi ou non par " "des déplacements de souris." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Ajouter un mouvement" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Aucun périphérique pris en charge trouvé" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "À propos de %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Quitter %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "aucun récepteur" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:734 msgid "offline" msgstr "non connecté" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "aucun statut" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Balayage" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Batterie" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Connexion sans fil" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "Éclairage" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Afficher les détails techniques" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Jumeler un nouveau périphérique" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Sélectionner un périphérique" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Éditeur de règles" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Chemin" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "ID USB" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:550 lib/solaar/ui/window.py:552 msgid "Serial" msgstr "Numéro de série" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "PID sans fil" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "Identifiant produit" #: lib/solaar/ui/window.py:541 lib/solaar/ui/window.py:543 #: lib/solaar/ui/window.py:545 msgid "Protocol" msgstr "Protocole" #: lib/solaar/ui/window.py:545 msgid "Unknown" msgstr "Inconnu" #: lib/solaar/ui/window.py:547 msgid "Polling rate" msgstr "Taux de scrutation" #: lib/solaar/ui/window.py:554 msgid "Unit ID" msgstr "ID d'unité" #: lib/solaar/ui/window.py:565 msgid "none" msgstr "aucun" #: lib/solaar/ui/window.py:566 msgid "Notifications" msgstr "Notifications" #: lib/solaar/ui/window.py:610 msgid "No device paired." msgstr "Aucun périphérique jumelé." #: lib/solaar/ui/window.py:619 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Jusqu'à %(max_count)s périphérique peut être jumelé à ce récepteur." msgstr[1] "" "Jusqu'à %(max_count)s périphériques peuvent être jumelés à ce récepteur." #: lib/solaar/ui/window.py:626 msgid "Only one device can be paired to this receiver." msgstr "Un seul périphérique peut être jumelé à ce récepteur." #: lib/solaar/ui/window.py:630 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Ce récepteur a %d jumelage restant." msgstr[1] "Ce récepteur a %d jumelages restants." #: lib/solaar/ui/window.py:687 msgid "Battery Voltage" msgstr "Tension de la batterie" #: lib/solaar/ui/window.py:689 msgid "Voltage reported by battery" msgstr "Tension indiquée par la batterie" #: lib/solaar/ui/window.py:691 msgid "Battery Level" msgstr "Niveau de la batterie" #: lib/solaar/ui/window.py:693 msgid "Approximate level reported by battery" msgstr "Niveau approximatif indiqué par la batterie" #: lib/solaar/ui/window.py:700 lib/solaar/ui/window.py:702 msgid "next reported " msgstr "prochain rapport " #: lib/solaar/ui/window.py:703 msgid " and next level to be reported." msgstr " et prochain niveau à rapporter." #: lib/solaar/ui/window.py:708 msgid "last known" msgstr "dernière valeur connue" #: lib/solaar/ui/window.py:719 msgid "encrypted" msgstr "chiffrée" #: lib/solaar/ui/window.py:721 msgid "The wireless link between this device and its receiver is encrypted." msgstr "" "La connexion sans fil entre ce périphérique et son récepteur est chiffrée." #: lib/solaar/ui/window.py:723 msgid "not encrypted" msgstr "non chiffrée" #: lib/solaar/ui/window.py:727 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "La connexion sans fil entre ce périphérique et son récepteur n'est pas " "chiffrée.\n" "Ceci est un problème de sécurité pour les dispositifs de pointage, et un " "problème majeur pour les périphériques de saisie de texte." #: lib/solaar/ui/window.py:743 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" Solaar-1.1.20/po/ga.po000066400000000000000000002256551522022367600144050ustar00rootroot00000000000000# Irish translations for solaar package. # Copyright (C) 2026 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2026. # # Aindriú Mac Giolla Eoin , 2026. msgid "" msgstr "" "Project-Id-Version: solaar 1.1.20rc2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-06-11 16:38+0100\n" "PO-Revision-Date: 2026-06-11 17:04+0000\n" "Last-Translator: Aindriú Mac Giolla Eoin \n" "Language-Team: Irish \n" "Language: ga\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;\n" "X-Generator: Weblate 2026.6.1\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Glacadóir Bolt" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Glacadóir Aontaitheach" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Glacadóir Nano" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Glacadóir Lightspeed" #: lib/logitech_receiver/base_usb.py:136 msgid "EX100 Receiver 27 Mhz" msgstr "Glacadóir EX100 27 Mhz" #: lib/logitech_receiver/common.py:698 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Ceallraí: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:701 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Ceallraí: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1189 lib/logitech_receiver/hidpp20.py:1222 #: lib/logitech_receiver/hidpp20.py:1250 msgid "Cycle" msgstr "Timthriall" #: lib/logitech_receiver/hidpp20.py:1190 msgid "Right" msgstr "Ar dheis" #: lib/logitech_receiver/hidpp20.py:1191 msgid "Down" msgstr "Síos" #: lib/logitech_receiver/hidpp20.py:1192 msgid "Center Out" msgstr "Lár Amach" #: lib/logitech_receiver/hidpp20.py:1193 msgid "In" msgstr "Isteach" #: lib/logitech_receiver/hidpp20.py:1194 msgid "Out" msgstr "Amach" #: lib/logitech_receiver/hidpp20.py:1195 #: lib/logitech_receiver/settings_templates.py:1398 msgid "Left" msgstr "Ar chlé" #: lib/logitech_receiver/hidpp20.py:1196 msgid "Up" msgstr "Suas" #: lib/logitech_receiver/hidpp20.py:1197 msgid "Center In" msgstr "Lár Isteach" #: lib/logitech_receiver/hidpp20.py:1218 #: lib/logitech_receiver/settings_templates.py:344 msgid "Disabled" msgstr "Míchumasaithe" #: lib/logitech_receiver/hidpp20.py:1219 msgid "Static" msgstr "Statach" #: lib/logitech_receiver/hidpp20.py:1220 msgid "Pulse" msgstr "Bíog" #: lib/logitech_receiver/hidpp20.py:1229 lib/logitech_receiver/hidpp20.py:1255 msgid "Wave" msgstr "Tonn" #: lib/logitech_receiver/hidpp20.py:1233 msgid "Boot" msgstr "Buatais" #: lib/logitech_receiver/hidpp20.py:1234 msgid "Demo" msgstr "Taispeántas" #: lib/logitech_receiver/hidpp20.py:1236 msgid "Breathe" msgstr "Análaigh" #: lib/logitech_receiver/hidpp20.py:1241 lib/logitech_receiver/hidpp20.py:1262 msgid "Ripple" msgstr "Tonnóg" #: lib/logitech_receiver/hidpp20.py:1246 msgid "Decomposition" msgstr "Dianscaoileadh" #: lib/logitech_receiver/hidpp20.py:1247 msgid "Signature1" msgstr "Síniú1" #: lib/logitech_receiver/hidpp20.py:1248 msgid "Signature2" msgstr "Síniú2" #: lib/logitech_receiver/hidpp20.py:1268 msgid "Dim" msgstr "Lag" #: lib/logitech_receiver/hidpp20.py:1340 msgid "Unknown Location" msgstr "Suíomh Anaithnid" #: lib/logitech_receiver/hidpp20.py:1341 #: lib/logitech_receiver/settings_templates.py:2619 #: lib/logitech_receiver/settings_templates.py:2907 #: lib/logitech_receiver/settings_templates.py:3647 msgid "Primary" msgstr "Príomhúil" #: lib/logitech_receiver/hidpp20.py:1342 msgid "Logo" msgstr "Lógó" #: lib/logitech_receiver/hidpp20.py:1343 msgid "Left Side" msgstr "Taobh Clé" #: lib/logitech_receiver/hidpp20.py:1344 msgid "Right Side" msgstr "Taobh Deas" #: lib/logitech_receiver/hidpp20.py:1345 msgid "Combined" msgstr "Comhcheangailte" #: lib/logitech_receiver/hidpp20.py:1346 msgid "Primary 1" msgstr "Bunscoil 1" #: lib/logitech_receiver/hidpp20.py:1347 msgid "Primary 2" msgstr "Bunscoil 2" #: lib/logitech_receiver/hidpp20.py:1348 msgid "Primary 3" msgstr "Bunscoil 3" #: lib/logitech_receiver/hidpp20.py:1349 msgid "Primary 4" msgstr "Bunscoil 4" #: lib/logitech_receiver/hidpp20.py:1350 msgid "Primary 5" msgstr "Bunscoil 5" #: lib/logitech_receiver/hidpp20.py:1351 msgid "Primary 6" msgstr "Bunscoil 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "folamh" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "criticiúil" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "íseal" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "meán" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "maith" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "lán" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "ag scaoileadh" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "athluchtú" #: lib/logitech_receiver/i18n.py:37 msgid "charging" msgstr "muirearú" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "gan muirearú" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "beagnach lán" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "cúisithe" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "athluchtú mall" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "ceallraí neamhbhailí" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "earráid theirmeach" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "earráid" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "caighdeánach" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "tapa" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "mall" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "am scoir gléas" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "ní thacaítear leis an ngléas" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "an iomarca gléasanna" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "am scoir seicheamh" #: lib/logitech_receiver/i18n.py:54 msgid "Firmware" msgstr "Dochtearraí" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Tosaitheoir" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Crua-earraí" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Eile" #: lib/logitech_receiver/i18n.py:59 #: lib/logitech_receiver/settings_templates.py:4336 msgid "Left Button" msgstr "Cnaipe Clé" #: lib/logitech_receiver/i18n.py:60 #: lib/logitech_receiver/settings_templates.py:4336 msgid "Right Button" msgstr "Cnaipe Deas" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Cnaipe Lárnach" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Cnaipe Ar Ais" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Cnaipe Ar Aghaidh" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Cnaipe Gotha Luiche" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Aistriú Cliste" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Lasc DPI" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Claonadh ar Chlé" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Claonadh ar Dheis" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Cliceáil ar Chlé" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Cliceáil ar Dheis" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Cnaipe Lárnach na Luiche" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Cnaipe Ar Ais Luiche" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Cnaipe Ar Aghaidh Luiche" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Nascleanúint Cnaipe Gotha" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Cnaipe Scrollaigh Clé Luiche" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Cnaipe Scrollaigh ar Dheis na Luiche" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "brúite" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "scaoilte" #: lib/logitech_receiver/notifications.py:157 lib/solaar/listener.py:350 msgid "connected" msgstr "ceangailte" #: lib/logitech_receiver/notifications.py:157 lib/solaar/listener.py:350 msgid "disconnected" msgstr "dícheangailte" #: lib/logitech_receiver/notifications.py:183 msgid "unpaired" msgstr "neamhphéireáilte" #: lib/logitech_receiver/notifications.py:232 msgid "powered on" msgstr "cumhachtaithe air" #: lib/logitech_receiver/notifications.py:284 msgid "ADC measurement notification" msgstr "Fógra tomhais ADC" #: lib/logitech_receiver/notifications.py:486 #: lib/logitech_receiver/notifications.py:542 msgid "pairing lock is closed" msgstr "Tá an glas péireála dúnta" #: lib/logitech_receiver/notifications.py:486 #: lib/logitech_receiver/notifications.py:542 msgid "pairing lock is open" msgstr "Tá an glas péireála oscailte" #: lib/logitech_receiver/notifications.py:505 msgid "discovery lock is closed" msgstr "Tá an glas fionnachtana dúnta" #: lib/logitech_receiver/notifications.py:505 msgid "discovery lock is open" msgstr "Tá an glas fionnachtana oscailte" #: lib/logitech_receiver/receiver.py:466 msgid "No paired devices." msgstr "Gan aon ghléasanna péireáilte." #: lib/logitech_receiver/receiver.py:468 lib/solaar/ui/window.py:612 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s gléas péireáilte." msgstr[1] "%(count)s gléasanna péireáilte." msgstr[2] "%(count)s gléasanna péireáilte." #: lib/logitech_receiver/settings.py:621 msgid "register" msgstr "cláraigh" #: lib/logitech_receiver/settings.py:635 lib/logitech_receiver/settings.py:673 msgid "feature" msgstr "gné" #: lib/logitech_receiver/settings_templates.py:183 msgid "Swap Fx function" msgstr "Feidhm Malartaithe Fx" #: lib/logitech_receiver/settings_templates.py:186 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Nuair a bheidh siad socraithe, cuirfidh na heochracha F1..F12 a bhfeidhm " "speisialta i ngníomh,\n" "agus ní mór duit an eochair FN a shealbhú síos chun a bhfeidhm chaighdeánach " "a ghníomhachtú." #: lib/logitech_receiver/settings_templates.py:191 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Nuair nach mbíonn siad socraithe, cuirfidh na heochracha F1..F12 a bhfeidhm " "chaighdeánach i ngníomh,\n" "agus ní mór duit an eochair FN a shealbhú síos chun a bhfeidhm speisialta a " "ghníomhachtú." #: lib/logitech_receiver/settings_templates.py:199 msgid "Hand Detection" msgstr "Brath Láimhe" #: lib/logitech_receiver/settings_templates.py:200 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "" "Cuir an soilsiú ar siúl nuair a bhíonn na lámha ag luascadh os cionn an " "mhéarchláir." #: lib/logitech_receiver/settings_templates.py:207 msgid "Scroll Wheel Smooth Scrolling" msgstr "Roth Scrollaigh Scrollú Réidh" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:455 #: lib/logitech_receiver/settings_templates.py:484 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Mód ard-íogaireachta le haghaidh scrolla ingearach leis an roth." #: lib/logitech_receiver/settings_templates.py:215 msgid "Side Scrolling" msgstr "Scrolláil Taobh" #: lib/logitech_receiver/settings_templates.py:217 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Nuair a bhíonn sé díchumasaithe, seoltar imeachtaí cnaipe saincheaptha nuair " "a bhrúitear an roth\n" "ar thaobh seachas na himeachtaí scrollaigh taobh caighdeánacha." #: lib/logitech_receiver/settings_templates.py:227 msgid "Sensitivity (DPI - older mice)" msgstr "�ogaireacht (DPI - lucha níos sine)" #: lib/logitech_receiver/settings_templates.py:228 #: lib/logitech_receiver/settings_templates.py:1064 #: lib/logitech_receiver/settings_templates.py:1092 msgid "Mouse movement sensitivity" msgstr "�ogaireacht ghluaiseacht luiche" #: lib/logitech_receiver/settings_templates.py:301 msgid "Backlight Timed" msgstr "Soilsiú Cúlra Amaithe" #: lib/logitech_receiver/settings_templates.py:302 #: lib/logitech_receiver/settings_templates.py:442 msgid "Set illumination time for keyboard." msgstr "Socraigh am soilsithe don mhéarchlár." #: lib/logitech_receiver/settings_templates.py:313 msgid "Backlight" msgstr "Cúlsholas" #: lib/logitech_receiver/settings_templates.py:314 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Leibhéal soilsithe ar an méarchlár. Ní chuirtear na hathruithe a dhéantar i " "bhfeidhm ach amháin sa mhodh Láimhe." #: lib/logitech_receiver/settings_templates.py:346 msgid "Automatic" msgstr "Uathoibríoch" #: lib/logitech_receiver/settings_templates.py:348 msgid "Manual" msgstr "Lámhleabhar" #: lib/logitech_receiver/settings_templates.py:350 msgid "Enabled" msgstr "Cumasaithe" #: lib/logitech_receiver/settings_templates.py:356 msgid "Backlight Level" msgstr "Leibhéal an tSolais Chúlra" #: lib/logitech_receiver/settings_templates.py:357 msgid "Illumination level on keyboard when in Manual mode." msgstr "Leibhéal soilsithe ar an méarchlár nuair a bhíonn sé i mód Láimhe." #: lib/logitech_receiver/settings_templates.py:414 msgid "Backlight Delay Hands Out" msgstr "Moill ar Sholas Cúlra Lámha Amach" #: lib/logitech_receiver/settings_templates.py:415 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Moill i soicindí go dtí go n-imíonn an cúlsholas agus na lámha ar shiúl ón " "méarchlár." #: lib/logitech_receiver/settings_templates.py:423 msgid "Backlight Delay Hands In" msgstr "Moill ar Sholas Cúlra Lámha Isteach" #: lib/logitech_receiver/settings_templates.py:424 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Moill i soicindí go dtí go n-imíonn an cúlra agus na lámha in aice leis an " "méarchlár." #: lib/logitech_receiver/settings_templates.py:432 msgid "Backlight Delay Powered" msgstr "Moill ar Shoilse Cúltaca Cumhachtaithe" #: lib/logitech_receiver/settings_templates.py:433 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Moill i soicindí go dtí go n-imíonn an cúlsholas le cumhacht sheachtrach." #: lib/logitech_receiver/settings_templates.py:441 msgid "Backlight (Seconds)" msgstr "Solas Cúil (Soicindí)" #: lib/logitech_receiver/settings_templates.py:453 msgid "Scroll Wheel High Resolution" msgstr "Roth Scrollaigh Ardtaifigh" #: lib/logitech_receiver/settings_templates.py:457 #: lib/logitech_receiver/settings_templates.py:486 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" "Socraigh chun neamhaird a dhéanamh má tá an scrollú thar a bheith gasta nó " "mall" #: lib/logitech_receiver/settings_templates.py:464 #: lib/logitech_receiver/settings_templates.py:495 msgid "Scroll Wheel Diversion" msgstr "Atreorú Roth Scrollaigh" #: lib/logitech_receiver/settings_templates.py:466 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Cuir fógraí LOWRES_WHEEL HID++ ar an roth scrollála (a spreagann rialacha " "Solaar ach a ndéantar neamhaird orthu murach sin)." #: lib/logitech_receiver/settings_templates.py:473 msgid "Scroll Wheel Direction" msgstr "Treo Roth Scrollaigh" #: lib/logitech_receiver/settings_templates.py:474 msgid "Invert direction for vertical scroll with wheel." msgstr "Inbhéartaigh an treo le haghaidh scrolla ingearach le roth." #: lib/logitech_receiver/settings_templates.py:482 msgid "Scroll Wheel Resolution" msgstr "Rún Roth Scrollaigh" #: lib/logitech_receiver/settings_templates.py:497 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Cuir fógraí HIRES_WHEEL HID++ ar an roth scrollála (a spreagann rialacha " "Solaar ach a ndéantar neamhaird orthu murach sin)." #: lib/logitech_receiver/settings_templates.py:506 msgid "Sensitivity (Pointer Speed)" msgstr "�ogaireacht (Luas an Phointeora)" #: lib/logitech_receiver/settings_templates.py:507 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Iolraitheoir luais don luch (is gnách go mbíonn 256 ina iolraitheoir)." #: lib/logitech_receiver/settings_templates.py:517 msgid "Thumb Wheel Diversion" msgstr "Atreorú Roth Ordóige" #: lib/logitech_receiver/settings_templates.py:519 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Cuir fógraí THUMB_WHEEL HID++ chuig roth an ordóige (a spreagann rialacha " "Solaar ach a ndéantar neamhaird orthu murach sin)." #: lib/logitech_receiver/settings_templates.py:528 msgid "Thumb Wheel Direction" msgstr "Treo Roth Ordóige" #: lib/logitech_receiver/settings_templates.py:529 msgid "Invert thumb wheel scroll direction." msgstr "Inbhéartaigh treo scrolla roth an ordóige." #: lib/logitech_receiver/settings_templates.py:549 msgid "Onboard Profiles" msgstr "Próifílí Ar Bord" #: lib/logitech_receiver/settings_templates.py:550 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Cumasaigh próifíl ar bord, a rialaíonn ráta tuairiscithe, íogaireacht agus " "gníomhartha cnaipe" #: lib/logitech_receiver/settings_templates.py:594 #: lib/logitech_receiver/settings_templates.py:627 msgid "Report Rate" msgstr "Ráta Tuairiscithe" #: lib/logitech_receiver/settings_templates.py:596 #: lib/logitech_receiver/settings_templates.py:629 msgid "Frequency of device movement reports" msgstr "Minicíocht tuairiscí gluaiseachta gléasanna" #: lib/logitech_receiver/settings_templates.py:596 #: lib/logitech_receiver/settings_templates.py:629 #: lib/logitech_receiver/settings_templates.py:1064 #: lib/logitech_receiver/settings_templates.py:1092 #: lib/logitech_receiver/settings_templates.py:1471 #: lib/logitech_receiver/settings_templates.py:1502 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "B’fhéidir go mbeadh gá le Próifílí Ar Bord a shocrú go Díchumasaigh le go " "mbeidh siad éifeachtach." #: lib/logitech_receiver/settings_templates.py:657 msgid "Divert crown events" msgstr "Imeachtaí corónach a atreorú" #: lib/logitech_receiver/settings_templates.py:658 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Cuir fógraí CROWN HID++ chuig an gcoróin (a spreagann rialacha Solaar ach a " "ndéantar neamhaird orthu murach sin)." #: lib/logitech_receiver/settings_templates.py:666 msgid "Crown smooth scroll" msgstr "Scrolla réidh na Corónach" #: lib/logitech_receiver/settings_templates.py:667 msgid "Set crown smooth scroll" msgstr "Socraigh scrolla réidh an choróin" #: lib/logitech_receiver/settings_templates.py:675 msgid "Divert G and M Keys" msgstr "Eochracha G agus M a atreorú" #: lib/logitech_receiver/settings_templates.py:676 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Cuir fógraí HID++ ar na heochracha G agus M (a spreagann rialacha Solaar ach " "a ndéantar neamhaird orthu murach sin)." #: lib/logitech_receiver/settings_templates.py:690 msgid "Scroll Wheel Ratcheted" msgstr "Roth Scrollaigh Céimnithe" #: lib/logitech_receiver/settings_templates.py:691 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Athraigh roth na luiche idir raicéadú rialaithe luais agus casadh saor in " "aisce i gcónaí." #: lib/logitech_receiver/settings_templates.py:693 msgid "Freespinning" msgstr "Sníomh saor in aisce" #: lib/logitech_receiver/settings_templates.py:693 msgid "Ratcheted" msgstr "Céimnithe" #: lib/logitech_receiver/settings_templates.py:700 msgid "Scroll Wheel Ratchet Speed" msgstr "Luas Raicéad Roth Scrollaigh" #: lib/logitech_receiver/settings_templates.py:702 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Bain úsáid as luas roth na luiche chun aistriú idir luas raicéadaithe agus " "luas saor-sníomhach.\n" "Bíonn luas raicéadaithe 50 ar roth na luiche i gcónaí." #: lib/logitech_receiver/settings_templates.py:752 msgid "Scroll Wheel Ratchet Torque" msgstr "Chasmhóiminte Raicéad Roth Scrollaigh" #: lib/logitech_receiver/settings_templates.py:753 msgid "Change the torque needed to overcome the ratchet." msgstr "Athraigh an chasmhóimint atá riachtanach chun an raicéad a shárú." #: lib/logitech_receiver/settings_templates.py:788 msgid "Key/Button Actions" msgstr "Gníomhartha Eochracha/Cnaipí" #: lib/logitech_receiver/settings_templates.py:790 msgid "Change the action for the key or button." msgstr "Athraigh an gníomh don eochair nó don chnaipe." #: lib/logitech_receiver/settings_templates.py:792 msgid "Overridden by diversion." msgstr "Sáraithe ag atreorú." #: lib/logitech_receiver/settings_templates.py:794 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Is féidir go mbeadh córas neamhúsáideach mar thoradh ar ghníomhartha " "tábhachtacha a athrú (mar shampla an cnaipe luiche ar chlé)." #: lib/logitech_receiver/settings_templates.py:969 msgid "Key/Button Diversion" msgstr "Atreorú Eochrach/Cnaipe" #: lib/logitech_receiver/settings_templates.py:970 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "Cuir an eochair nó an cnaipe ag seoladh fógraí HID++ (Atreoraithe) nó cuir " "tús le Gothaí Luiche nó DPI Sleamhnáin" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 #: lib/logitech_receiver/settings_templates.py:975 msgid "Diverted" msgstr "Atreoraithe" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 msgid "Mouse Gestures" msgstr "Gothaí Luiche" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 #: lib/logitech_receiver/settings_templates.py:975 msgid "Regular" msgstr "Rialta" #: lib/logitech_receiver/settings_templates.py:973 msgid "Sliding DPI" msgstr "DPI sleamhnáin" #: lib/logitech_receiver/settings_templates.py:1063 #: lib/logitech_receiver/settings_templates.py:1091 msgid "Sensitivity (DPI)" msgstr "�ogaireacht (DPI)" #: lib/logitech_receiver/settings_templates.py:1173 msgid "Sensitivity Switching" msgstr "Athrú �ogaireachta" #: lib/logitech_receiver/settings_templates.py:1175 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Athraigh an íogaireacht reatha agus an íogaireacht mheabhraithe nuair a " "bhrúitear an eochair nó an cnaipe.\n" "Mura bhfuil aon íogaireacht mheabhraithe ann, cuimhnigh ar an íogaireacht " "reatha amháin" #: lib/logitech_receiver/settings_templates.py:1179 msgid "Off" msgstr "As" #: lib/logitech_receiver/settings_templates.py:1210 msgid "Disable keys" msgstr "Díchumasaigh eochracha" #: lib/logitech_receiver/settings_templates.py:1211 msgid "Disable specific keyboard keys." msgstr "Díchumasaigh eochracha sonracha ar an méarchlár." #: lib/logitech_receiver/settings_templates.py:1214 #, python-format msgid "Disables the %s key." msgstr "Díchumasaíonn sé an eochair %s." #: lib/logitech_receiver/settings_templates.py:1227 #: lib/logitech_receiver/settings_templates.py:1284 msgid "Set OS" msgstr "Socraigh OS" #: lib/logitech_receiver/settings_templates.py:1228 #: lib/logitech_receiver/settings_templates.py:1285 msgid "Change keys to match OS." msgstr "Athraigh eochracha chun go n-oirfidh siad don chóras oibriúcháin." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Change Host" msgstr "Athraigh Óstach" #: lib/logitech_receiver/settings_templates.py:1298 msgid "Switch connection to a different host" msgstr "Athraigh nasc chuig óstach difriúil" #: lib/logitech_receiver/settings_templates.py:1322 msgid "Performs a left click." msgstr "Déanann cliceáil ar chlé." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Single tap" msgstr "Tapáil aonair" #: lib/logitech_receiver/settings_templates.py:1323 msgid "Performs a right click." msgstr "Déanann cliceáil ar dheis." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Single tap with two fingers" msgstr "Tapáil aonair le dhá mhéar" #: lib/logitech_receiver/settings_templates.py:1324 msgid "Single tap with three fingers" msgstr "Tapáil aonair le trí mhéar" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Double tap" msgstr "Tapáil faoi dhó" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Performs a double click." msgstr "Déanann cliceáil dhúbailte." #: lib/logitech_receiver/settings_templates.py:1329 msgid "Double tap with two fingers" msgstr "Tapáil faoi dhó le dhá mhéar" #: lib/logitech_receiver/settings_templates.py:1330 msgid "Double tap with three fingers" msgstr "Tapáil faoi dhó le trí mhéar" #: lib/logitech_receiver/settings_templates.py:1333 msgid "Drags items by dragging the finger after double tapping." msgstr "" "Tarraingíonn sé míreanna tríd an méar a tharraingt tar éis tapáil faoi dhó." #: lib/logitech_receiver/settings_templates.py:1333 msgid "Tap and drag" msgstr "Tapáil agus tarraing" #: lib/logitech_receiver/settings_templates.py:1335 msgid "Tap and drag with two fingers" msgstr "Tapáil agus tarraing le dhá mhéar" #: lib/logitech_receiver/settings_templates.py:1336 msgid "Drags items by dragging the fingers after double tapping." msgstr "" "Tarraingíonn sé míreanna trí na méara a tharraingt tar éis dóibh tapáil faoi " "dhó." #: lib/logitech_receiver/settings_templates.py:1338 msgid "Tap and drag with three fingers" msgstr "Tapáil agus tarraing le trí mhéar" #: lib/logitech_receiver/settings_templates.py:1341 msgid "Suppress tap and edge gestures" msgstr "Coisc gothaí tapála agus imeall" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "Díchumasaíonn sé gothaí tapála agus imeall (comhionann le brúigh Fn+Cliceáil " "Ar Chlé)." #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scroll with one finger" msgstr "Scrollaigh le méar amháin" #: lib/logitech_receiver/settings_templates.py:1344 #: lib/logitech_receiver/settings_templates.py:1345 #: lib/logitech_receiver/settings_templates.py:1348 msgid "Scrolls." msgstr "Scrollaí." #: lib/logitech_receiver/settings_templates.py:1345 #: lib/logitech_receiver/settings_templates.py:1348 msgid "Scroll with two fingers" msgstr "Scrollaigh le dhá mhéar" #: lib/logitech_receiver/settings_templates.py:1346 msgid "Scroll horizontally with two fingers" msgstr "Scrollaigh go cothrománach le dhá mhéar" #: lib/logitech_receiver/settings_templates.py:1346 msgid "Scrolls horizontally." msgstr "Scrollaíonn go cothrománach." #: lib/logitech_receiver/settings_templates.py:1347 msgid "Scroll vertically with two fingers" msgstr "Scrollaigh go hingearach le dhá mhéar" #: lib/logitech_receiver/settings_templates.py:1347 msgid "Scrolls vertically." msgstr "Scrollaíonn go hingearach." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Inverts the scrolling direction." msgstr "Déanann sé treo an scrollaigh a aisiompú." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Natural scrolling" msgstr "Scrolláil nádúrtha" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Enables the thumbwheel." msgstr "Cumasaíonn sé an roth ordóige." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Thumbwheel" msgstr "Roth ordóige" #: lib/logitech_receiver/settings_templates.py:1361 #: lib/logitech_receiver/settings_templates.py:1365 msgid "Swipe from the top edge" msgstr "Svaidhpeáil ón imeall uachtarach" #: lib/logitech_receiver/settings_templates.py:1362 msgid "Swipe from the left edge" msgstr "Svaidhpeáil ón imeall clé" #: lib/logitech_receiver/settings_templates.py:1363 msgid "Swipe from the right edge" msgstr "Svaidhpeáil ón imeall deas" #: lib/logitech_receiver/settings_templates.py:1364 msgid "Swipe from the bottom edge" msgstr "Svaidhpeáil ón imeall bun" #: lib/logitech_receiver/settings_templates.py:1366 msgid "Swipe two fingers from the left edge" msgstr "Svaidhpeáil dhá mhéar ón imeall clé" #: lib/logitech_receiver/settings_templates.py:1367 msgid "Swipe two fingers from the right edge" msgstr "Svaidhpeáil dhá mhéar ón imeall deas" #: lib/logitech_receiver/settings_templates.py:1368 msgid "Swipe two fingers from the bottom edge" msgstr "Svaidhpeáil dhá mhéar ón imeall bun" #: lib/logitech_receiver/settings_templates.py:1369 msgid "Swipe two fingers from the top edge" msgstr "Svaidhpeáil dhá mhéar ón imeall uachtarach" #: lib/logitech_receiver/settings_templates.py:1370 #: lib/logitech_receiver/settings_templates.py:1374 msgid "Pinch to zoom out; spread to zoom in." msgstr "Brúigh le zúmáil amach; scaip le zúmáil isteach." #: lib/logitech_receiver/settings_templates.py:1370 msgid "Zoom with two fingers." msgstr "Zúmáil le dhá mhéar." #: lib/logitech_receiver/settings_templates.py:1371 msgid "Pinch to zoom out." msgstr "Brúigh chun zúmáil amach." #: lib/logitech_receiver/settings_templates.py:1372 msgid "Spread to zoom in." msgstr "Scaip chun zúmáil isteach." #: lib/logitech_receiver/settings_templates.py:1373 msgid "Zoom with three fingers." msgstr "Zúmáil le trí mhéar." #: lib/logitech_receiver/settings_templates.py:1374 msgid "Zoom with two fingers" msgstr "Zúmáil le dhá mhéar" #: lib/logitech_receiver/settings_templates.py:1392 msgid "Pixel zone" msgstr "Crios picteilíní" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Ratio zone" msgstr "Crios cóimheasa" #: lib/logitech_receiver/settings_templates.py:1394 msgid "Scale factor" msgstr "Fachtóir scála" #: lib/logitech_receiver/settings_templates.py:1394 msgid "Sets the cursor speed." msgstr "Socraíonn sé luas an chúrsóra." #: lib/logitech_receiver/settings_templates.py:1398 msgid "Left-most coordinate." msgstr "Comhordanáid is faide ar chlé." #: lib/logitech_receiver/settings_templates.py:1399 msgid "Bottom" msgstr "Bun" #: lib/logitech_receiver/settings_templates.py:1399 msgid "Bottom coordinate." msgstr "Comhordanáid bun." #: lib/logitech_receiver/settings_templates.py:1400 msgid "Width" msgstr "Leithead" #: lib/logitech_receiver/settings_templates.py:1400 msgid "Width." msgstr "Leithead." #: lib/logitech_receiver/settings_templates.py:1401 msgid "Height" msgstr "Airde" #: lib/logitech_receiver/settings_templates.py:1401 msgid "Height." msgstr "Airde." #: lib/logitech_receiver/settings_templates.py:1402 msgid "Cursor speed." msgstr "Luas an chúrsóra." #: lib/logitech_receiver/settings_templates.py:1402 msgid "Scale" msgstr "Scála" #: lib/logitech_receiver/settings_templates.py:1408 msgid "Gestures" msgstr "Gothaí" #: lib/logitech_receiver/settings_templates.py:1409 msgid "Tweak the mouse/touchpad behaviour." msgstr "Coigeartaigh iompar na luiche/an tadhaill." #: lib/logitech_receiver/settings_templates.py:1425 msgid "Gestures Diversion" msgstr "Gothaí a atreorú" #: lib/logitech_receiver/settings_templates.py:1426 msgid "Divert mouse/touchpad gestures." msgstr "Atreoraigh gothaí luiche/tadhallcheap." #: lib/logitech_receiver/settings_templates.py:1442 msgid "Gesture params" msgstr "Paraiméadair gotha" #: lib/logitech_receiver/settings_templates.py:1443 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Athraigh paraiméadair uimhriúla luiche/tadhallcheap." #: lib/logitech_receiver/settings_templates.py:1467 msgid "M-Key LEDs" msgstr "LED M-Eochair" #: lib/logitech_receiver/settings_templates.py:1469 msgid "Control the M-Key LEDs." msgstr "Rialú na soilse LED M-Key." #: lib/logitech_receiver/settings_templates.py:1473 #: lib/logitech_receiver/settings_templates.py:1504 msgid "May need G Keys diverted to be effective." msgstr "" "B’fhéidir go mbeadh gá le heochracha G a atreorú le go mbeidh siad " "éifeachtach." #: lib/logitech_receiver/settings_templates.py:1479 #, python-format msgid "Lights up the %s key." msgstr "Lasann an eochair %s suas." #: lib/logitech_receiver/settings_templates.py:1498 msgid "MR-Key LED" msgstr "LED MR-Key" #: lib/logitech_receiver/settings_templates.py:1500 msgid "Control the MR-Key LED." msgstr "Rialú an LED MR-Key." #: lib/logitech_receiver/settings_templates.py:1521 msgid "Persistent Key/Button Mapping" msgstr "Mapáil Eochrach/Cnaipe Buan" #: lib/logitech_receiver/settings_templates.py:1523 msgid "Permanently change the mapping for the key or button." msgstr "Athraigh mapáil na heochrach nó an chnaipe go buan." #: lib/logitech_receiver/settings_templates.py:1525 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Is féidir go mbeadh córas neamhúsáideach mar thoradh ar eochracha nó cnaipí " "tábhachtacha a athrú (mar shampla an cnaipe luiche clé)." #: lib/logitech_receiver/settings_templates.py:1582 msgid "Sidetone" msgstr "Taobh-thon" #: lib/logitech_receiver/settings_templates.py:1583 msgid "Set sidetone level." msgstr "Socraigh leibhéal taobh-thon." #: lib/logitech_receiver/settings_templates.py:1592 msgid "Equalizer" msgstr "Cothromóir" #: lib/logitech_receiver/settings_templates.py:1593 #: lib/logitech_receiver/settings_templates.py:1902 msgid "Set equalizer levels." msgstr "Socraigh leibhéil cothromóra." #: lib/logitech_receiver/settings_templates.py:1615 #: lib/logitech_receiver/settings_templates.py:1930 #: lib/logitech_receiver/settings_templates.py:2056 #: lib/logitech_receiver/settings_templates.py:2058 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1621 msgid "Power Management" msgstr "Bainistíocht Cumhachta" #: lib/logitech_receiver/settings_templates.py:1622 msgid "Power off in minutes (0 for never)." msgstr "Múch an chumhacht i nóiméid (0 le haghaidh riamh)." #: lib/logitech_receiver/settings_templates.py:1634 msgid "Eco Mode" msgstr "Mód Éicea" #: lib/logitech_receiver/settings_templates.py:1635 msgid "Battery saver mode." msgstr "Mód sábhála ceallraí." #: lib/logitech_receiver/settings_templates.py:1653 msgid "Do Not Disturb" msgstr "Ná Cuir Isteach" #: lib/logitech_receiver/settings_templates.py:1654 msgid "Suppress notification sounds." msgstr "Cuir fuaimeanna fógra faoi chois." #: lib/logitech_receiver/settings_templates.py:1661 msgid "Mic Mute" msgstr "Micreafón Balbhaigh" #: lib/logitech_receiver/settings_templates.py:1662 msgid "Mute the microphone." msgstr "Balbhaigh an micreafón." #: lib/logitech_receiver/settings_templates.py:1681 msgid "Mic SNR" msgstr "SNR micreafóin" #: lib/logitech_receiver/settings_templates.py:1682 msgid "Microphone signal-to-noise ratio enhancement." msgstr "Feabhsú cóimheas comhartha-go-torann micreafóin." #: lib/logitech_receiver/settings_templates.py:1689 msgid "AI Noise Reduction" msgstr "Laghdú Torainn AI" #: lib/logitech_receiver/settings_templates.py:1690 msgid "Enable AI noise reduction." msgstr "Cumasaigh laghdú torainn AI." #: lib/logitech_receiver/settings_templates.py:1697 msgid "AI Noise Reduction Level" msgstr "Leibhéal Laghdaithe Torainn AI" #: lib/logitech_receiver/settings_templates.py:1698 msgid "AI noise reduction intensity." msgstr "Déine laghdaithe torainn AI." #: lib/logitech_receiver/settings_templates.py:1707 msgid "Headset Sidetone" msgstr "Taobh-thon na gCluasán" #: lib/logitech_receiver/settings_templates.py:1708 msgid "Sidetone level (0 = off, 100 = max)." msgstr "Leibhéal taobh-thon (0 = múchta, 100 = uasmhéid)." #: lib/logitech_receiver/settings_templates.py:1771 msgid "Mic Gain" msgstr "Gnóthachan Micreafóin" #: lib/logitech_receiver/settings_templates.py:1772 msgid "Microphone gain level." msgstr "Leibhéal gnóthachain micreafóin." #: lib/logitech_receiver/settings_templates.py:1824 msgid "Audio Mix Balance" msgstr "Cothromaíocht Meascáin Fuaime" #: lib/logitech_receiver/settings_templates.py:1825 msgid "Balance between game and chat audio." msgstr "Cothromaíocht idir fuaim an chluiche agus an chomhrá." #: lib/logitech_receiver/settings_templates.py:1876 msgid "Auto Sleep Timeout" msgstr "Am Teorann Codlata Uathoibríoch" #: lib/logitech_receiver/settings_templates.py:1877 msgid "" "Idle time in minutes before the headset enters sleep mode (0 = disabled)." msgstr "" "Am díomhaoin i nóiméid sula dtéann an cluasán isteach i mód codlata (0 = " "díchumasaithe)." #: lib/logitech_receiver/settings_templates.py:1901 msgid "Headset Equalizer" msgstr "Cothromóir Cluasán" #: lib/logitech_receiver/settings_templates.py:1996 msgid "Headset Advanced EQ" msgstr "Cothromóir Ardleibhéil Cluasán" #: lib/logitech_receiver/settings_templates.py:1997 msgid "Per-band gain for the headset's active parametric EQ." msgstr "" "Gnóthachan in aghaidh an bhanda do chothromóir paraiméadrach gníomhach na " "gcluasán." #: lib/logitech_receiver/settings_templates.py:2268 msgid "EQ Preset" msgstr "Réamhshocrú Cothromóra" #: lib/logitech_receiver/settings_templates.py:2269 msgid "Switch the active EQ preset. Factory presets are read-only." msgstr "" "Athraigh an réamhshocrú cothromóra gníomhach. Is inléite amháin atá " "réamhshocruithe monarchan." #: lib/logitech_receiver/settings_templates.py:2294 msgid "Slot" msgstr "Sliotán" #: lib/logitech_receiver/settings_templates.py:2296 msgid "(factory)" msgstr "(monarcha)" #: lib/logitech_receiver/settings_templates.py:2429 #: lib/logitech_receiver/settings_templates.py:3206 #: lib/logitech_receiver/settings_templates.py:3298 msgid "LED Control" msgstr "Rialú LED" #: lib/logitech_receiver/settings_templates.py:2430 msgid "Allow Solaar to control the headset LED zones." msgstr "Lig do Solaar criosanna LED na gcluasán a rialú." #: lib/logitech_receiver/settings_templates.py:2478 msgid "Per-zone Lighting" msgstr "Soilsiú in aghaidh an chrios" #: lib/logitech_receiver/settings_templates.py:2480 msgid "" "Override individual zone colors. 'No change' inherits the LEDs Primary " "color.\n" "LED Control needs to be set to Solaar to be effective." msgstr "" "Sáraigh dathanna criosanna aonair. Faigheann 'Gan athrú' dath príomhúil na " "soilse LED mar oidhreacht.\n" "Ní mór Rialú LED a shocrú go Solaar le go mbeidh sé éifeachtach." #: lib/logitech_receiver/settings_templates.py:2498 msgid "Zone" msgstr "Crios" #: lib/logitech_receiver/settings_templates.py:2620 #: lib/logitech_receiver/settings_templates.py:2908 #: lib/logitech_receiver/settings_templates.py:3648 msgid "Secondary" msgstr "Tánaisteach" #: lib/logitech_receiver/settings_templates.py:2621 #: lib/logitech_receiver/settings_templates.py:3234 msgid "Speed" msgstr "Luas" #: lib/logitech_receiver/settings_templates.py:2688 msgid "Startup Effect" msgstr "Éifeacht Tosaithe" #: lib/logitech_receiver/settings_templates.py:2690 msgid "Firmware lighting effect played when the headset powers on or wakes." msgstr "" "Éifeacht soilsithe dochtearraí a sheinmtear nuair a chuirtear na cluasáin ar " "siúl nó nuair a dhúisítear iad." #: lib/logitech_receiver/settings_templates.py:2692 #: lib/logitech_receiver/settings_templates.py:2703 msgid "Device default: Primary #00B8FC, Secondary #FF00AB, Speed 100." msgstr "Réamhshocrú gléis: Príomhghléas #00B8FC, Meánghléas #FF00AB, Luas 100." #: lib/logitech_receiver/settings_templates.py:2699 msgid "Shutdown Effect" msgstr "Éifeacht Múchta" #: lib/logitech_receiver/settings_templates.py:2701 msgid "Firmware lighting effect played when the headset powers off or sleeps." msgstr "" "Éifeacht soilsithe dochtearraí a sheinntear nuair a mhúchtar na cluasáin nó " "nuair a théann siad i gcodladh." #: lib/logitech_receiver/settings_templates.py:2710 msgid "Passive Effect" msgstr "Éifeacht Éighníomhach" #: lib/logitech_receiver/settings_templates.py:2712 msgid "Firmware lighting effect played while the headset is idle." msgstr "Éifeacht soilsithe dochtearraí á seinnt agus an cluasán díomhaoin." #: lib/logitech_receiver/settings_templates.py:2714 msgid "Device default: Primary #00B8FC, Secondary #FF00AB, Speed 75." msgstr "Réamhshocrú gléis: Príomhghléas #00B8FC, Meánghléas #FF00AB, Luas 75." #: lib/logitech_receiver/settings_templates.py:2833 msgid "Onboard Effect" msgstr "Éifeacht Ar Bord" #: lib/logitech_receiver/settings_templates.py:2834 msgid "Firmware RGB effect the headset plays on its own." msgstr "Éifeacht RGB Dochtearraí a sheinneann an cluasán leis féin." #: lib/logitech_receiver/settings_templates.py:2909 #: lib/logitech_receiver/settings_templates.py:3243 msgid "Intensity" msgstr "Déine" #: lib/logitech_receiver/settings_templates.py:2910 #: lib/logitech_receiver/settings_templates.py:3245 msgid "Saturation" msgstr "Sáithiú" #: lib/logitech_receiver/settings_templates.py:2914 #: lib/logitech_receiver/settings_templates.py:3238 msgid "Period" msgstr "Tréimhse" #: lib/logitech_receiver/settings_templates.py:2919 #: lib/logitech_receiver/settings_templates.py:3250 msgid "Direction" msgstr "Treo" #: lib/logitech_receiver/settings_templates.py:3134 msgid "Brightness Control" msgstr "Rialú Gile" #: lib/logitech_receiver/settings_templates.py:3135 msgid "Control overall brightness" msgstr "Rialú gile iomlán" #: lib/logitech_receiver/settings_templates.py:3207 #: lib/logitech_receiver/settings_templates.py:3299 msgid "Allow Solaar to control LED zones." msgstr "Lig do Solaar criosanna LED a rialú." #: lib/logitech_receiver/settings_templates.py:3230 #: lib/logitech_receiver/settings_templates.py:3744 msgid "LED Zone Effects" msgstr "Éifeachtaí Crios LED" #: lib/logitech_receiver/settings_templates.py:3231 #: lib/logitech_receiver/settings_templates.py:3399 #: lib/logitech_receiver/settings_templates.py:3439 #: lib/logitech_receiver/settings_templates.py:3546 #: lib/logitech_receiver/settings_templates.py:3745 msgid "LED Control needs to be enabled." msgstr "Ní mór Rialú LED a chumasú." #: lib/logitech_receiver/settings_templates.py:3231 #: lib/logitech_receiver/settings_templates.py:3745 msgid "Set effect for LED Zone" msgstr "Socraigh éifeacht don Chrios LED" #: lib/logitech_receiver/settings_templates.py:3233 msgid "Color" msgstr "Dath" #: lib/logitech_receiver/settings_templates.py:3244 msgid "Ramp" msgstr "Rampa" #: lib/logitech_receiver/settings_templates.py:3246 msgid "Waveform" msgstr "Tonnfhoirm" #: lib/logitech_receiver/settings_templates.py:3279 msgid "LEDs" msgstr "LEDanna" #: lib/logitech_receiver/settings_templates.py:3398 msgid "Idle Timeout" msgstr "Am Teorann Díomhaoin" #: lib/logitech_receiver/settings_templates.py:3399 msgid "Time without input before LED idle effect starts." msgstr "Am gan ionchur sula dtosaíonn éifeacht dhíomhaoin LED." #: lib/logitech_receiver/settings_templates.py:3435 msgid "Idle Effect" msgstr "Éifeacht Díomhaoin" #: lib/logitech_receiver/settings_templates.py:3437 msgid "" "What happens to LEDs when idle — dim to a percentage, change the base color, " "or play an animation." msgstr "" "Cad a tharlaíonn do na soilse LED nuair a bhíonn siad díomhaoin — laghdaigh " "go céatadán, athraigh an dath bonn, nó seinn beochan." #: lib/logitech_receiver/settings_templates.py:3520 msgid "No change" msgstr "Gan athrú" #: lib/logitech_receiver/settings_templates.py:3545 msgid "Sleep Timeout" msgstr "Sos Codlata" #: lib/logitech_receiver/settings_templates.py:3546 msgid "Time without input before LEDs fade off completely." msgstr "Am gan ionchur sula múchann na soilse LED go hiomlán." #: lib/logitech_receiver/settings_templates.py:3719 msgid "Startup Animation" msgstr "Beochan Tosaithe" #: lib/logitech_receiver/settings_templates.py:3722 msgid "" "Firmware-played animation when the keyboard wakes from deep sleep or powers " "on.\n" "Setting persists on the device (non-volatile)." msgstr "" "Beochan a sheinnear le firmware nuair a dhúisíonn an méarchlár ó chodladh " "domhain nó nuair a chuirtear ar siúl é.\n" "Fanann an socrú ar an ngléas (neamh-luaineach)." #: lib/logitech_receiver/settings_templates.py:3726 #: lib/logitech_receiver/settings_templates.py:3737 msgid "Device default: Primary #FF0081, Secondary #80AAFF." msgstr "Réamhshocrú gléis: Príomhúil #FF0081, Tánaisteach #80AAFF." #: lib/logitech_receiver/settings_templates.py:3733 msgid "Shutdown Animation" msgstr "Beochan Múchta" #: lib/logitech_receiver/settings_templates.py:3735 msgid "" "Firmware-played animation when the keyboard powers off.\n" "Setting persists on the device (non-volatile)." msgstr "" "Beochan a sheinneadh le dochtearraí nuair a mhúchtar an méarchlár.\n" "Fanann an socrú ar an ngléas (neamh-luaineach)." #: lib/logitech_receiver/settings_templates.py:3847 #: lib/solaar/ui/perkey/dialog.py:87 msgid "Per-key Lighting" msgstr "Soilsiú in aghaidh an eochrach" #: lib/logitech_receiver/settings_templates.py:3849 msgid "Control per-key lighting." msgstr "Rialú soilsiú in aghaidh an eochrach." #: lib/logitech_receiver/settings_templates.py:3851 msgid "" "LED Control needs to be enabled and the zone effect set to Static for per-" "key paint to be visible." msgstr "" "Ní mór Rialú LED a chumasú agus éifeacht an chrios a shocrú go Statach le go " "mbeidh péint in aghaidh an eochrach le feiceáil." #: lib/logitech_receiver/settings_templates.py:4182 msgid "Force Sensing Buttons" msgstr "Cnaipí Braite Fórsa" #: lib/logitech_receiver/settings_templates.py:4183 msgid "Change the force required to activate button." msgstr "Athraigh an fórsa atá ag teastáil chun an cnaipe a ghníomhachtú." #: lib/logitech_receiver/settings_templates.py:4200 msgid "Force Sensing Button" msgstr "Cnaipe Braite Fórsa" #: lib/logitech_receiver/settings_templates.py:4316 msgid "Analog Button Tuning" msgstr "Tiúnáil Cnaipe Analógach" #: lib/logitech_receiver/settings_templates.py:4317 msgid "" "Configure analog button settings including actuation point, rapid trigger, " "and haptics." msgstr "" "Cumraigh socruithe cnaipe analógacha lena n-áirítear pointe gníomhachtaithe, " "spreagadh tapa, agus haptics." #: lib/logitech_receiver/settings_templates.py:4347 #, python-format msgid "Actuation point depth (1=shallow, %d=deep)." msgstr "Doimhneacht phointe gníomhachtaithe (1=éadomhain, %d=doimhneacht)." #: lib/logitech_receiver/settings_templates.py:4355 #, python-format msgid "Rapid trigger sensitivity (1..%d)." msgstr "�ogaireacht thapa spreagtha (1..%d)." #: lib/logitech_receiver/settings_templates.py:4363 #, python-format msgid "Click haptic feedback intensity (0=off, %d=max)." msgstr "Déine aiseolais haptic cliceáil (0=as, %d=uas)." #: lib/logitech_receiver/settings_templates.py:4371 msgid "Haptic Feedback Level" msgstr "Leibhéal Aiseolais Haptic" #: lib/logitech_receiver/settings_templates.py:4372 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "Athraigh cumhacht an aiseolais haptic. (Nialas chun é a mhúchadh.)" #: lib/logitech_receiver/settings_templates.py:4414 msgid "Play Haptic Waveform" msgstr "Seinn Tonnfhorm Haptic" #: lib/logitech_receiver/settings_templates.py:4415 msgid "Tell device to play a haptic waveform." msgstr "Abair leis an ngléas tonnfhoirm haptic a sheinm." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "" "Tá próiseas Solaar eile ag rith cheana féin mar sin níl le déanamh ach a " "fhuinneog a nochtadh" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Bainistíonn glacadóirí, méarchláir,\n" "lucha agus táibléid Logitech." #: lib/solaar/ui/about/model.py:64 msgid "Additional Programming" msgstr "Cláreagrú Breise" #: lib/solaar/ui/about/model.py:65 msgid "GUI design" msgstr "Dearadh GUI" #: lib/solaar/ui/about/model.py:67 msgid "Testing" msgstr "Tástáil" #: lib/solaar/ui/about/model.py:75 msgid "Logitech documentation" msgstr "Doiciméadú Logitech" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Díphéireáil" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:142 msgid "Cancel" msgstr "Cealaigh" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Earráid ceadanna" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Fuarthas glacadóir nó gléas Logitech (%s), ach ní raibh cead agam é a " "oscailt." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Má tá Solaar suiteáilte agat díreach, déan iarracht an glacadóir nó an gléas " "a dhícheangal agus ansin é a athcheangal." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Ní féidir ceangal leis an ngléas earráide" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Fuarthas glacadóir nó gléas Logitech ag %s, ach tháinig earráid ar an " "gceangal leis." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Bain triail as an ngléas a dhícheangal agus ansin é a athcheangal nó é a " "mhúchadh agus a chur air arís." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "Theip ar dhíphéireáil" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Theip ar %{device} a dhíphéireáil ó %{receiver}." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Thug an glacadóir earráid ar ais, gan aon sonraí breise." #: lib/solaar/ui/config_panel.py:254 msgid "Complete - ENTER to change" msgstr "Críochnaithe - ENTER le hathrú" #: lib/solaar/ui/config_panel.py:254 msgid "Incomplete" msgstr "Neamhchríochnaithe" #: lib/solaar/ui/config_panel.py:500 lib/solaar/ui/config_panel.py:552 #: lib/solaar/ui/config_panel.py:619 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d luach" msgstr[1] "%d luachanna" msgstr[2] "%d luachanna" #: lib/solaar/ui/config_panel.py:805 msgid "Changes allowed" msgstr "Athruithe ceadaithe" #: lib/solaar/ui/config_panel.py:806 msgid "No changes allowed" msgstr "Ní cheadaítear aon athruithe" #: lib/solaar/ui/config_panel.py:807 msgid "Ignore this setting" msgstr "Déan neamhaird den socrú seo" #: lib/solaar/ui/config_panel.py:1022 msgid "Working" msgstr "Ag obair" #: lib/solaar/ui/config_panel.py:1025 msgid "Read/write operation failed." msgstr "Theip ar an oibríocht léigh/scríbhneoireachta." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "cúis neamhshonraithe" #: lib/solaar/ui/diversion_rules.py:104 msgid "Built-in rules" msgstr "Rialacha ionsuite" #: lib/solaar/ui/diversion_rules.py:104 msgid "User-defined rules" msgstr "Rialacha sainmhínithe ag an úsáideoir" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:1127 msgid "Rule" msgstr "Riail" #: lib/solaar/ui/diversion_rules.py:107 lib/solaar/ui/diversion_rules.py:383 #: lib/solaar/ui/diversion_rules.py:510 msgid "Sub-rule" msgstr "Fo-riail" #: lib/solaar/ui/diversion_rules.py:109 msgid "[empty]" msgstr "[folamh]" #: lib/solaar/ui/diversion_rules.py:133 msgid "Make changes permanent?" msgstr "Déan athruithe buana?" #: lib/solaar/ui/diversion_rules.py:138 msgid "Yes" msgstr "Tá" #: lib/solaar/ui/diversion_rules.py:140 msgid "No" msgstr "Níl" #: lib/solaar/ui/diversion_rules.py:145 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Mura roghnaíonn tú Níl, caillfear na hathruithe nuair a dhúnfar Solaar." #: lib/solaar/ui/diversion_rules.py:274 msgid "Paste here" msgstr "Greamaigh anseo" #: lib/solaar/ui/diversion_rules.py:276 msgid "Paste above" msgstr "Greamaigh thuas" #: lib/solaar/ui/diversion_rules.py:278 msgid "Paste below" msgstr "Greamaigh thíos" #: lib/solaar/ui/diversion_rules.py:284 msgid "Paste rule here" msgstr "Greamaigh riail anseo" #: lib/solaar/ui/diversion_rules.py:286 msgid "Paste rule above" msgstr "Greamaigh an riail thuas" #: lib/solaar/ui/diversion_rules.py:288 msgid "Paste rule below" msgstr "Greamaigh riail thíos" #: lib/solaar/ui/diversion_rules.py:292 msgid "Paste rule" msgstr "Riail ghreamaithe" #: lib/solaar/ui/diversion_rules.py:307 msgid "Insert here" msgstr "Cuir isteach anseo" #: lib/solaar/ui/diversion_rules.py:309 msgid "Insert above" msgstr "Cuir isteach thuas" #: lib/solaar/ui/diversion_rules.py:311 msgid "Insert below" msgstr "Cuir isteach thíos" #: lib/solaar/ui/diversion_rules.py:317 msgid "Insert new rule here" msgstr "Cuir riail nua isteach anseo" #: lib/solaar/ui/diversion_rules.py:319 msgid "Insert new rule above" msgstr "Cuir riail nua isteach thuas" #: lib/solaar/ui/diversion_rules.py:321 msgid "Insert new rule below" msgstr "Cuir riail nua isteach thíos" #: lib/solaar/ui/diversion_rules.py:348 msgid "Flatten" msgstr "Leacaigh" #: lib/solaar/ui/diversion_rules.py:381 msgid "Insert" msgstr "Cuir isteach" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:512 #: lib/solaar/ui/diversion_rules.py:1159 msgid "Or" msgstr "Nó" #: lib/solaar/ui/diversion_rules.py:385 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1145 msgid "And" msgstr "Agus" #: lib/solaar/ui/diversion_rules.py:387 msgid "Condition" msgstr "Coinníoll" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Gné" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Tuairisc" #: lib/solaar/ui/diversion_rules.py:391 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Próiseas" #: lib/solaar/ui/diversion_rules.py:392 msgid "Mouse process" msgstr "Próiseas luiche" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Modhnóirí" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Eochair" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "EochairIsSíos" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1433 msgid "Active" msgstr "Gníomhach" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1391 #: lib/solaar/ui/diversion_rules.py:1442 lib/solaar/ui/diversion_rules.py:1488 msgid "Device" msgstr "Gléas" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1468 msgid "Host" msgstr "Óstach" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/diversion_rules.py:1507 msgid "Setting" msgstr "Socrú" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "Tástáil" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Bheiteanna tástála" #: lib/solaar/ui/diversion_rules.py:402 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Gotha Luiche" #: lib/solaar/ui/diversion_rules.py:406 msgid "Action" msgstr "Gníomh" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "Brúigh eochair" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Scrollaigh luiche" #: lib/solaar/ui/diversion_rules.py:410 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Cliceáil luiche" #: lib/solaar/ui/diversion_rules.py:411 msgid "Set" msgstr "Socraigh" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "Forghníomhaigh" #: lib/solaar/ui/diversion_rules.py:413 lib/solaar/ui/diversion_rules.py:1190 msgid "Later" msgstr "Níos déanaí" #: lib/solaar/ui/diversion_rules.py:442 msgid "Insert new rule" msgstr "Cuir riail nua isteach" #: lib/solaar/ui/diversion_rules.py:462 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Scrios" #: lib/solaar/ui/diversion_rules.py:484 msgid "Negate" msgstr "Néig" #: lib/solaar/ui/diversion_rules.py:508 msgid "Wrap with" msgstr "Fillte le" #: lib/solaar/ui/diversion_rules.py:538 msgid "Cut" msgstr "Gearr" #: lib/solaar/ui/diversion_rules.py:554 msgid "Paste" msgstr "Greamaigh" #: lib/solaar/ui/diversion_rules.py:560 msgid "Copy" msgstr "Cóipeáil" #: lib/solaar/ui/diversion_rules.py:569 msgid "Solaar Rule Editor" msgstr "Eagarthóir Rialacha Solaar" #: lib/solaar/ui/diversion_rules.py:669 msgid "Save changes" msgstr "Sábháil athruithe" #: lib/solaar/ui/diversion_rules.py:674 msgid "Discard changes" msgstr "Scrios athruithe" #: lib/solaar/ui/diversion_rules.py:1105 msgid "This editor does not support the selected rule component yet." msgstr "" "Ní thacaíonn an t-eagarthóir seo leis an gcomhpháirt riail roghnaithe go " "fóill." #: lib/solaar/ui/diversion_rules.py:1170 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Líon na soicindí le moill. Déantar moill idir 0 agus 1 le cruinneas níos " "airde." #: lib/solaar/ui/diversion_rules.py:1208 msgid "Not" msgstr "Ní" #: lib/solaar/ui/diversion_rules.py:1239 msgid "Toggle" msgstr "Scoránaigh" #: lib/solaar/ui/diversion_rules.py:1240 msgid "True" msgstr "Fíor" #: lib/solaar/ui/diversion_rules.py:1241 msgid "False" msgstr "Bréagach" #: lib/solaar/ui/diversion_rules.py:1254 msgid "Unsupported setting" msgstr "Socrú gan tacaíocht" #: lib/solaar/ui/diversion_rules.py:1397 lib/solaar/ui/diversion_rules.py:1416 #: lib/solaar/ui/diversion_rules.py:1494 lib/solaar/ui/diversion_rules.py:1758 #: lib/solaar/ui/diversion_rules.py:1776 msgid "Originating device" msgstr "Gléas tionscnaimh" #: lib/solaar/ui/diversion_rules.py:1429 msgid "Device is active and its settings can be changed." msgstr "Tá an gléas gníomhach agus is féidir a shocruithe a athrú." #: lib/solaar/ui/diversion_rules.py:1438 msgid "Device that originated the current notification." msgstr "An gléas a chuir an fógra reatha ar bun." #: lib/solaar/ui/diversion_rules.py:1451 msgid "Name of host computer." msgstr "Ainm an ríomhaire óstach." #: lib/solaar/ui/diversion_rules.py:1521 msgid "Value" msgstr "Luach" #: lib/solaar/ui/diversion_rules.py:1530 msgid "Item" msgstr "Mír" #: lib/solaar/ui/diversion_rules.py:1818 msgid "Change setting on device" msgstr "Athraigh an socrú ar an ngléas" #: lib/solaar/ui/diversion_rules.py:1834 msgid "Setting on device" msgstr "Socrú ar an ngléas" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: péireáil gléas nua" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Níl glacadóirí Bolt comhoiriúnach ach le gléasanna Bolt." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Brúigh cnaipe nó eochair péireála go dtí go splancann an solas péireála go " "tapa." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Níl glacadóirí Unifying comhoiriúnach ach le gléasanna Unifying." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "Níl glacadóirí eile comhoiriúnach ach le cúpla gléas." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "" "I gcás fhormhór na ngléasanna, cuir an gléas ar siúl is mian leat a " "phéireáil." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "Má tá an gléas casta air cheana féin, múch é agus cuir air arís é." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" "Ní mór an gléas a bheith péireáilte le glacadóir atá ar siúl in aice láimhe." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "I gcás gléasanna a bhfuil ilchainéil acu, brúigh, coinnigh síos agus scaoil " "an cnaipe don chainéal is mian leat a phéireáil\n" "nó bain úsáid as an gcnaipe athraithe cainéal chun cainéal a roghnú agus " "ansin brúigh, coinnigh síos agus scaoil an cnaipe athraithe cainéal." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Ba chóir go mbeadh solas táscaire an chainéil ag splancadh go tapa." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Tá %d péireáil fágtha ag an nglacadóir seo." msgstr[1] "" "\n" "\n" "Tá %d péirí fágtha ag an nglacadóir seo." msgstr[2] "" "\n" "\n" "Tá %d péirí fágtha ag an nglacadóir seo." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Ní úsáidfear péireáil má chealaítear ag an bpointe seo." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Cuir isteach an pasfhocal ar %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Clóscríobh %(passcode)s agus ansin brúigh an eochair iontrála." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "ar chlé" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "ar dheis" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Brúigh %(code)s\n" "agus ansin brúigh na cnaipí clé agus deas ag an am céanna." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "Níl an nasc gan sreang criptithe" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Fuarthas gléas nua:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Theip ar an bpéireáil" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Cinntigh go bhfuil do ghléas laistigh de raon, agus go bhfuil muirear " "ceallraí réasúnta air." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "Braitheadh gléas nua, ach níl sé comhoiriúnach leis an nglacadóir seo." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "" "Níos mó gléasanna péireáilte ná mar is féidir leis an nglacadóir tacú leo." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Níl aon sonraí breise ar fáil faoin earráid." #: lib/solaar/ui/perkey/control.py:178 msgid "(not loaded)" msgstr "(gan luchtú)" #: lib/solaar/ui/perkey/control.py:182 msgid "Open editor…" msgstr "Oscail an t-eagarthóir…" #: lib/solaar/ui/perkey/control.py:183 msgid "Paint key colors on a keyboard layout" msgstr "Péinteáil dathanna eochracha ar leagan amach méarchláir" #: lib/solaar/ui/perkey/control.py:229 msgid "(no zones)" msgstr "(gan criosanna)" #: lib/solaar/ui/perkey/control.py:233 #, python-brace-format msgid "{painted} / {total} keys painted" msgstr "{painted} / {total} eochracha péinteáilte" #: lib/solaar/ui/perkey/editor.py:54 msgid "Brush" msgstr "Scuab" #: lib/solaar/ui/perkey/editor.py:54 msgid "Click or drag to paint individual keys" msgstr "Cliceáil nó tarraing chun eochracha aonair a phéinteáil" #: lib/solaar/ui/perkey/editor.py:55 msgid "Drag to select a rectangle of keys, painted on release" msgstr "" "Tarraing chun dronuilleog eochracha a roghnú, péinteáilte nuair a scaoiltear " "iad" #: lib/solaar/ui/perkey/editor.py:55 msgid "Rect" msgstr "Dronuilleog" #: lib/solaar/ui/perkey/editor.py:56 msgid "Fill" msgstr "Líon" #: lib/solaar/ui/perkey/editor.py:56 msgid "Flood-fill connected keys of the same color with the active color" msgstr "" "Líon isteach eochracha ceangailte den dath céanna leis an dath gníomhach" #: lib/solaar/ui/perkey/editor.py:59 msgid "Drag to fade from previous color to active color" msgstr "Tarraing chun céimniú ón dath roimhe seo go dtí an dath gníomhach" #: lib/solaar/ui/perkey/palette.py:90 msgid "Active color" msgstr "Dath gníomhach" #: lib/solaar/ui/perkey/palette.py:95 msgid "Paint as 'no change' — clears the cell to the zone base color" msgstr "" "Péinteáil mar 'gan athrú' — glanann sé an chill go dtí an dath bonn crios" #: lib/solaar/ui/perkey/palette.py:96 msgid "Unset" msgstr "Díshuiteáil" #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Insamhladh cliceáil nó brú nó scaoileadh eochrach corda.\n" "Ar Wayland, teastaíonn rochtain scríbhneoireachta chuig /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Cuir eochair leis" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Cliceáil" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Dúlagar" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Scaoileadh" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Insamhladh scrolla luiche.\n" "Ar Wayland, teastaíonn rochtain scríbhneoireachta chuig /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Insamhlaigh cliceáil luiche.\n" "Éilíonn Wayland rochtain scríbhneoireachta chuig /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Cnaipe" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Gníomh (agus Líon, má chliceálann tú)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Forghníomhaigh ordú le hargóintí." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Cuir argóint leis" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "Próiseas gníomhach X11. Le húsáid in X11 amháin." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "Próiseas luiche X11. Le húsáid in X11 amháin." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "Próiseas Luiche" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "Ainm gné den phróiseáil rialach a spreagann fógra." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "Tuairiscigh líon na bhfógraí a spreagann próiseáil rialacha." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" "Mionathraitheoirí méarchláir ghníomhacha. Ní bhíonn siad ar fáil i gcónaí i " "Wayland." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Eochair nó cnaipe atreoraithe brúite nó scaoilte.\n" "Úsáid na socruithe Atreorú Eochrach/Cnaipe agus Atreorú Eochracha G chun " "eochracha agus cnaipí a atreorú." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Eochair síos" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Eochair suas" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Tá an eochair nó an cnaipe atreoraithe síos faoi láthair.\n" "Bain úsáid as na socruithe Atreorú Eochrach/Cnaipe agus Atreorú Eochracha G " "chun eochracha agus cnaipí a atreorú." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "Coinníoll tástála ar phróiseáil rialach a spreagann fógra." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Paraiméadar" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "tús (san áireamh)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "deireadh (eisiach)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "raon" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "íosmhéid" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "uasmhéid" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "beart %(0)d go %(1)d, idir %(2)d agus %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "masc" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "beart %(0)d go %(1)d, masc %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Tástáil giotán nó raoin ar bhearta i dteachtaireacht fógra a spreagann " "próiseáil rialacha." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "cineál" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Gotha luiche le cnaipe tosaithe roghnach agus gan aon ghluaiseacht luiche nó " "níos mó ina dhiaidh." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Cuir gluaiseacht leis" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Níor aimsíodh aon ghléas tacaithe" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "Maidir le %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Scoir %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "gan aon ghlacadóir" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 msgid "offline" msgstr "as líne" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "gan stádas" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Scanadh" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Ceallraí" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Nasc Gan Sreang" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "Soilsiú" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Taispeáin Sonraí Teicniúla" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Péireáil gléas nua" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Roghnaigh gléas" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Eagarthóir Rialacha" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Cosán" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "Aitheantas USB" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:550 lib/solaar/ui/window.py:552 msgid "Serial" msgstr "Sraitheach" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "Innéacs" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "PID Gan Sreang" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "Aitheantas Táirge" #: lib/solaar/ui/window.py:541 lib/solaar/ui/window.py:543 #: lib/solaar/ui/window.py:545 msgid "Protocol" msgstr "Prótacal" #: lib/solaar/ui/window.py:545 msgid "Unknown" msgstr "Anaithnid" #: lib/solaar/ui/window.py:547 msgid "Polling rate" msgstr "Ráta faireachán" #: lib/solaar/ui/window.py:554 msgid "Unit ID" msgstr "Aitheantas Aonaid" #: lib/solaar/ui/window.py:566 msgid "Notifications" msgstr "Fógraí" #: lib/solaar/ui/window.py:610 msgid "No device paired." msgstr "Níl aon ghléas péireáilte." #: lib/solaar/ui/window.py:619 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "" "Is féidir suas le %(max_count)s gléas a phéireáil leis an nglacadóir seo." msgstr[1] "" "Is féidir suas le %(max_count)s gléasanna a phéireáil leis an nglacadóir seo." msgstr[2] "" "Is féidir suas le %(max_count)s gléasanna a phéireáil leis an nglacadóir seo." #: lib/solaar/ui/window.py:630 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Tá %d péireáil fágtha ag an nglacadóir seo." msgstr[1] "Tá %d péireáil fágtha ag an nglacadóir seo." msgstr[2] "Tá %d péireáil fágtha ag an nglacadóir seo." #: lib/solaar/ui/window.py:687 msgid "Battery Voltage" msgstr "Voltas Ceallraí" #: lib/solaar/ui/window.py:689 msgid "Voltage reported by battery" msgstr "Voltas tuairiscithe ag ceallraí" #: lib/solaar/ui/window.py:691 msgid "Battery Level" msgstr "Leibhéal Ceallraí" #: lib/solaar/ui/window.py:693 msgid "Approximate level reported by battery" msgstr "Leibhéal garbh a tuairiscíodh ag an gceallraí" #: lib/solaar/ui/window.py:700 lib/solaar/ui/window.py:702 msgid "next reported " msgstr "an chéad tuairisc eile " #: lib/solaar/ui/window.py:703 msgid " and next level to be reported." msgstr " agus an chéad leibhéal eile le tuairisciú." #: lib/solaar/ui/window.py:719 msgid "encrypted" msgstr "criptithe" #: lib/solaar/ui/window.py:721 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Tá an nasc gan sreang idir an gléas seo agus a ghlacadóir criptithe." #: lib/solaar/ui/window.py:723 msgid "not encrypted" msgstr "gan criptiú" #: lib/solaar/ui/window.py:727 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "Níl an nasc gan sreang idir an gléas seo agus a ghlacadóir criptithe.\n" "Is fadhb slándála í seo do ghléasanna pointeála, agus fadhb mhór slándála do " "ghléasanna ionchuir téacs." #: lib/solaar/ui/window.py:743 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" Solaar-1.1.20/po/hr.po000066400000000000000000001713421522022367600144200ustar00rootroot00000000000000# Croatian translations for solaar package # Copyright (C) YEAR THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # gogo , 2014. # msgid "" msgstr "Project-Id-Version: solaar 1.0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2022-10-28 10:37+0200\n" "Last-Translator: gogo \n" "Language-Team: Croatian \n" "Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 " "&& n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.0.1\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "Bolt prijemnik" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "Unifying prijemnik" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "Nano prijemnik" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "Lightspeed prijemnik" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 prijemnik 27 Mhz" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "prazna" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "kriti�no" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "slaba" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "prosje�na" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "dobra" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "napunjena" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "pražnjenje" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "punjenje" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "punjenje" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "ne puni se" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "uskoro puno" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "napunjena" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "sporo punjenje" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "neispravna baterija" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "toplinska greška" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "greška" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "standardno" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "brzo" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "sporo" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "istek �ekanja uređaja" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "uređaj nije podržan" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "previše uređaja" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "redoslijed isteka vremena" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmver" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "U�ita� pokretanja" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardver" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Ostalo" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "Lijeva tipka" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "Desna tipka" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "Srednja tipka" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "Tipka za natrag" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "Tipka za naprijed" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "Tipka gesta miša" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "Pametan pomak" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "DPI prebaciva�" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "Lijevi nagib" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "Desni nagib" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "Lijevi klik" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "Desni klik" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "Srednja tipka miša" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "Tipka miša za natrag" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "Tipka miša za naprijed" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "Tipka navigacije gesta" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "Lijeva tipka pomicanja miša" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "Desna tipka pomicanja miša" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "pritisak" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "otpuštanje" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "uparivanje je zatvoreno" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "uparivanje je otvoreno" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "otkrivanje je zatvoreno" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "otkrivanje je otvoreno" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "povezano" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "nije povezano" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "neupareno" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "uklju�en" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "registar" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "zna�ajka" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Zamijeni Fx funkciju" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Kada je omogućeno, tipke F1..F12 će aktivirati svoje dodatne " "funkcije,\n" "a za aktivaciju njihovih osnovnih funkcija morate držati FN tipku." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Kada nije omogućeno, tipke F1..F12 će aktivirati svoje osnovne " "funkcije,\n" "a za aktivaciju njihovih dodatnih funkcija morate držati FN tipku." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Otkrivanje ruku" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Uklju�ite osvjetljenje kada ruke lebde nad tipkovnicom." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "Glatko pomicanje kota�ićem" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Visokoosjetljivi na�in okomitog pomicanja kota�ićem." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Bo�no pomicanje kota�ićem" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Kad je onemogućeno, guranje kota�ića ustranu šalje prilagođeni " "događaj tipke\n" "umjesto uobi�ajanog događaja bo�nog pomicanja." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "Osjetljivost (DPI - stariji miševi)" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "Osjetljivost pomicanja miša" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Osvjetljenje" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "Postavite vrijeme osvjetljenja tipkovnice." #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "Uklju�ite ili isklju�ite osvjetljenje tipkovnice." #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "Visokoosjetljivi na�in pomicanja kota�ićem" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Postavite na zanemareno ako je pomicanje prebrzo ili presporo" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "Preusmjeravanje pomicanja kota�ića" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "Neka kota�ić pomicanja šalje LOWRES_WHEEL HID++ obavijesti (što " "pokreće Solaar pravila, u suprotnome ih zanemaruje)." #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "Smjer pomicanja kota�ića" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "Obrnuti smjer za okomito pomicanje kota�ićem." #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "Osjetljivost pomicanja kota�ićem" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "Neka kota�ić pomicanja šalje HIRES_WHEEL HID++ obavijesti (što " "pokreće Solaar pravila, u suprotnome ih zanemaruje)." #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Osjetljivost (Brzina pokaziva�a)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Množitelj brzine za miš (256 je normalan množitelj)." #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "Preusmjeravanje pomicanja kota�ića palca" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "Neka kota�ić palca šalje THUMB_WHEEL HID++ obavijesti (što pokreće " "Solaar pravila, u suprotnome ih zanemaruje)." #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "Smjer pomicanja kota�ića palca" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "Obrnuti smjer pomicanja kota�ića palca." #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "Onboard profili" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "Omogućite onboard profile, koji naj�ešće upravljaju brzinom " "pozivanja i osvjetljenjem tipkovnice" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "Brzina pozivanja (ms)" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "U�estalost pozivanja uređaja, u milisekundama" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "Možda je potrebno postaviti Onboard profile na 'Onemogućeno' kako bi " "bili u�inkoviti." #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "Preusmjeri crown događaje" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Neka crown šalje CROWN HID++ obavijesti (što pokreće Solaar pravila, " "u suprotnome ih zanemaruje)." #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "Crown glatko pomicanje" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "Postavite Crown glatko pomicanje" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "Preusmjeri G tipke" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Neka G tipke šalju GKEY HID++ obavijesti (što pokreće Solaar " "pravila, u suprotnome ih zanemaruje)." #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "Neka isto M tipke i MR tipka šalje HID++ obavijesti" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "Ustavljanje pomicanja kota�ića" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "Prebaci kota�ić miša između ustavlja�kog brzinom upravljanog na�ina " "i slobodnog na�ina vrtnje kota�ića." #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "Slobodna vrtnja" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "Ustavljanje" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "Brzina ustavljanja pomicanja kota�ića" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "Koristite brzinu kota�ića miša za prebacivanje između ustavlja�kog i " "slobodnog na�ina vrtnje kota�ića.\n" "Kota�ić miša je uvijek ustavljen pri 50." #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "Radnje tipki" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Promijeni radnju za tipku." #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "Preusmjereno skretanjem." #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "Promjena bitnih radnji (poput lijeve tipke miša) može prouzrokovati " "nestabilnosti u sustavu." #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "Preusmjeravanje tipki" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "Neka tipka ili šalje HID++ obavijesti (preusmjerene) ili pokreće " "gete mišem ili klizni DPI" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "Preusmjerno" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "Geste miša" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "Normalna" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "Klizni DPI" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Osjetljivost (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "Prebacivanje osjetljivosti" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "Prebacivanje trenutne osjetljivosti i zapamćene osjetljivosti kada " "se tipka pritisne.\n" "Ako ne postoji zapamćena osjetljivost, zapamti trenutnu osjetljivost" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "Isklju�eno" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Onemogući tipke" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Onemogući određene tipke tipkovnice." #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "Onemogućuje %s tipku." #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Postavi OS" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Promijeni tipke tako da se podudaraju sa OS-om." #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Promijeni ra�unalo" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Prebaci povezivanje na drugo ra�unalo" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "Izvodi lijevi klik." #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "Jednostruki dodir" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "Izvodi desni klik." #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "Jednostruki dodir s dva prsta" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "Jednostruki dodir s tri prsta" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "Dvostruki dodir" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "Izvodi dvostruki klik." #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "Dvostruki dodir s dva prsta" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "Dvostruki dodir s tri prsta" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "Povla�ite stavke povla�enjem prsta nakon dvostrukog dodira." #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "Dodirni i povuci" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "Povla�ite stavke povla�enjem prsta nakon dvostrukog dodira." #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "Dodirni i povuci s dva prsta" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "Dodirni i povuci s tri prsta" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Onemogućuje dodir i rubne geste (ekvivalent pritiska na Fn+Lijevi " "klik)" #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "Onemogući dodir i rubne geste" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "Pomicanje s jednim prstom" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "Pomicanje." #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "Pomicanje s dva prsta" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "Vodoravno pomicanje s dva prsta" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "Vodoravno pomicanje." #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "Okomito pomicanje s dva prsta" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "Okomito pomicanje." #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "Obrnite smjer pomicanja." #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "Prirodno pomicanje" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "Omogućite kota�ić palca." #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "Kota�ić palca" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "Prijeđite prstom od gornjeg ruba" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "Prijeđite prstom od lijevog ruba" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "Prijeđite prstom od desnog ruba" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "Prijeđite prstom od donjeg ruba" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "Prijeđite s dva prsta od lijevog ruba" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "Prijeđite s dva prsta od desnog ruba" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "Prijeđite s dva prsta od donjeg ruba" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "Prijeđite s dva prsta od gornjeg ruba" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "Skupite prste za smanjivanje; raširite prste za uvećanje." #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "Uvećanje/Smanjenje s dva prsta." #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "Skupite prste za smanjivanje." #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "Raširite prste za uvećanje." #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "Uvećanje/Smanjenje s tri prsta." #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "Uvećanje/Smanjenje s dva prsta" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "Zona piksela" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "Zona omjera" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Faktor veli�ine" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "Postavlja brzinu pokaziva�a." #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "Lijevo" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "Naj�ešća lijeva koordinata." #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "Dno" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "Koordinata na dnu." #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Širina" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "Širina." #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Visina" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "Visina." #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "Brzina pokaziva�a." #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "Prilagodba veli�ine" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Geste" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "Prilagodite ponašanje miša/touchpada." #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "Preusmjeravanje gesta" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "Preusmjerite ponašanje miša/touchpada." #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "Parametri gesta" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Promijenite broj�ane parametre miša/touchpada." #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "LED osvjetljenje M-tipke" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "Upravljajte LED osvjetljenjem M-tipke." #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "Možda je potrebno preusmjeravanje G tipka kako bi bile u�inkovite." #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "Osvijetli %s tipku." #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "LED osvjetljenje MR-tipke" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "Upravljajte LED osvjetljenjem MR-tipke." #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "Trajno mapiranje tipka" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "Trajno promijenite mapiranje za tipku." #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "Promjena bitnih tipka (poput lijeve tipke miša) može prouzrokovati " "nestabilnosti u sustavu." #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "Bo�ni ton" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "Postavi razinu bo�nog tona." #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "Ekvalizator" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "Postavi razine ekvilizatora." #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Nema uparenih uređaja." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s upareni uređaj." msgstr[1] "%(count)s uparena uređaja." msgstr[2] "%(count)s uparenih uređaj." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Baterija: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Baterija: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Osvjetljenje: %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Baterija: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Baterija: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Greška dozvole" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "Nemoguće povezivanje s uređajem, greška" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "Pronađen je Logitech prijemnik ili uređaj na %s, ali je naišao na " "grešku pri povezivanju." #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Uparivanje neuspjelo" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Neuspjelo uparivanje %{device} s %{receiver}." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "Došlo je do greške kod prijemnika, bez više pojedinosti." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "Drugi Solaar proces je već pokrenut stoga samo prikaži njegov prozor" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "Upravljajte Logitechovim prijemnicima,\n" "tipkovnicama, miševima, i tabletima." #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "Dodatno programiranje" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "GUI dizajn" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Testiranje" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Logitech dokumentacija" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Odpari" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "Odustani" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "Potpuno - ENTER za promjenu" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "Nepotpuno" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d vrijednost" msgstr[1] "%d vrijednosti" msgstr[2] "%d vrijednosti" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "Promjene su dopuštene" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "Promjene nisu dopuštene" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "Zanemari ovu postavku" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Izvodi se" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Radnja �itanja/pisanja neuspjela." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "Ugrađena pravila" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "Korisni�ki određena pravila" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "Pravilo" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "Podpravilo" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[prazno]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Solaar uređiva� pravila" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "U�ini promjene trajnima?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Da" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "Ne" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Ako odaberete 'Ne', promjene će biti izgubljene kada se Solaar " "zatvori." #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "Spremi promjene" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "Odbaci promjene" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "Umetni ovdje" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "Umetni iznad" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "Umetni ispod" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "Umetni novo pravilo ovdje" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "Umetni novo pravilo iznad" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "Umetni novo pravilo ispod" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "Zalijepi ovdje" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "Zalijepi iznad" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "Zalijepi ispod" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "Zalijepi pravilo ovdje" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "Zalijepi pravilo iznad" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "Zalijepi pravilo ispod" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "Zalijepi pravilo" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "Poravnaj" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "Umetni" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "Ili" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "I" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "Stanje" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "Zna�ajka" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "Prijavak" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Proces" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "Proces miša" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "Tipkovni�ki izmjenjiva�i" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "Klju�" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Aktivan" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "Uređaj" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "Postavka" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "Testni bajtovi" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "Gesta miša" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Radnja" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "Pritisak tipke" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "Pomicanje kota�ića" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "Klik kota�ića" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "Postavka" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "Pokretanje" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "Odgoda" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "Umetni novo pravilo" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "Obriši" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "Negacija" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "Umetni iznad" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Izreži" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Zalijepi" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Kopiraj" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "Ovaj uređiva� još ne podržava komponentu odabira pravila." #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "Broj sekundi odgode." #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "Ne" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "X11 aktivni proces. Samo za korištenje u X11." #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "X11 proces miša. Samo za korištenje u X11." #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "Proces miša" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "Naziv zna�ajke obrade pravila za pokretanje obavijesti." #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "Prijavi broj obrade pravila za pokretanje obavijesti." #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Aktivni tipkovni�ki izmjenjiva�i. Nije uvijek dostupno u Waylandu." #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "Tipka za dolje" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "Tipka za gore" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "Uvjet testiranja za obradu pravila pokretanja obavijesti." #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "po�etak (uklju�iv)" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "završetak (isklju�iv)" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "raspon" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "maksimum" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "bajtovi %(0)d do %(1)d, u rasponu od %(2)d do %(3)d" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "maska" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "bajtovi %(0)d to %(1)d, maska %(2)d" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "Test bita ili raspona na bajtovima u poruci obavijesti koja pokreće " "obradu pravila." #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "vrsta" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "Geste mišem s neobaveznom tipkom pokretanja nakon kojeg slijedi nula " "ili više pokreta mišem." #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "Dodaj pokret" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simuliraj klik tipke s akordima ili pritisnite ili pustite.\n" "Na Waylandu je potrebna dozvola pisanje u /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "Dodaj tipku" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "Klik" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "Pritisak" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "Otpuštanje" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simuliraj pomicanje kota�ića miša.\n" "Na Waylandu je potrebna dozvola pisanje u /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simuliraj klik miša.\n" "Na Waylandu je potrebna dozvola pisanje u /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "Tipka" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "Pokreni naredbu s argumentima." #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "Dodaj argument" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "Uklj/Isklj" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "Istina" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "Laž" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "Nepodržana postavka" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "Izvorni uređaj" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "Uređaj je aktivan i njegove postavke se mogu promijeniti." #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Vrijednost" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "Stavka" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "Promjena postavke na uređaju" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "Postavka na uređaju" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "nespojivo" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: upari novi uređaj" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "Upišite lozinku na %(name)s." #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Upišite %(passcode)s i zatim pritisnite Enter tipku." #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "lijevo" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "desno" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "Pritisnite %(code)s\n" "i zatim istovremeno pritisnite lijevu i desnu tipku." #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Neuspjelo uparivanje" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Pobrinite se da je vaš uređaj u dometu beži�nog povezivanja i da je " "dovoljno napunjen." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Novi uređaj je otkriven, ali nije kompatibilan s ovim uređajem." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "Postoji više uparenih uređaja nego što prijemnik podržava." #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Nema dostupnih više pojedinosti o ovoj grešci." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "Novi uređaj je pronađen:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "Beži�no povezivanje nije šifrirano" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "Pritisnite tipku uparivanja sve dok svjetlo uparivanja ne po�ne brzo " "treptati." #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "Možda trebate prvo isklju�iti uređaj pa ponovno uklju�iti." #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Uklju�ite uređaj koji želite upariti." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "Ako je uređaj već uklju�en, isklju�ite ga i ponovno uklju�ite." #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "Ovaj prijemnik ima još %d preostalo uparivanje." msgstr[1] "\n" "\n" "Ovaj prijemnik ima još %d preostala uparivanja." msgstr[2] "\n" "\n" "Ovaj prijemnik ima još %d preostalih uparivanja." #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Prekidanje u ovom trenutku neće izvršiti uparivanje." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "O %su" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Zatvori %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "nema prijemnika" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "bez stanja" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Pretraživanje" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Baterija" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Beži�no povezivanje" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Osvjetljenje" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Prikaži tehni�ke pojedinosti" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Upari novi uređaj" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Odaberi uređaj" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "Uređiva� pravila" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Putanja" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Serijski broj" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Indeks" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "PID beži�ne mreže" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "ID proizvoda" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protokol" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Nepoznato" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Cikli�ko osvježavanje" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "ID jedinice" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "nepoznato" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Obavijesti" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "Nema uparenih uređaja." #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Najviše %(max_count)s uređaj može biti uparen s ovim " "prijemnikom." msgstr[1] "Najviše %(max_count)s uređaja može biti upareno s ovim " "prijemnikom." msgstr[2] "Najviše %(max_count)s uređaja može biti upareno s ovim " "prijemnikom." #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "Samo jedan uređaj može biti uparen s ovim prijemnikom." #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Ovaj prijemnik ima još %d preostalo uparivanje." msgstr[1] "Ovaj prijemnik ima još %d preostala uparivanja." msgstr[2] "Ovaj prijemnik ima još %d preostalih uparivanja." #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "Napon baterije" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "Napon prijavljen od strane baterije" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "Razina baterije" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "Približna razina prijavljena od strane baterije" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "sljedeće poznato " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " i sljedeća razina za prijaviti." #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "posljednje poznato" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "šifrirano" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Beži�no povezivanje između ovog uređaja i njegovog prijemnika je " "šifrirano." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "nije šifrirano" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "Beži�no povezivanje između ovog uređaja i njegovog prijemnika nije " "šifrirano.\n" "Ovo je sigurnosni problem za pokaziva�ke uređaje i veliki sigurnosni " "problem za uređaje za unos teksta." #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid " paired devices." #~ msgstr " uparena uređaja." #~ msgid "%(battery_level)s" #~ msgstr "%(battery_level)s" #~ msgid "%(battery_percent)d%%" #~ msgstr "%(battery_percent)d%%" #~ msgid "1 paired device." #~ msgstr "1 upareni uređaj." #~ msgid "Actions" #~ msgstr "Radnje" #~ msgid "Add action" #~ msgstr "Dodaj radnju" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the button down." #~ msgstr "Prilagodite DPI pomicanjem miša vodoravno držeći pritisnutu " #~ "tipku." #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always locked at 50" #~ msgstr "Automatski prebaci kota�ić miša između ustavlja�kog i " #~ "slobodnog na�ina vrtnje kota�ića.\n" #~ "Kota�ić miša je uvijek slobodan pri 0 i uvijek zaklju�an pri 50" #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "Automatski prebaci kota�ić miša između ustavlja�kog i " #~ "slobodnog na�ina vrtnje kota�ića.\n" #~ "Kota�ić miša je uvijek slobodan pri 0 i uvijek zaklju�an pri 50" #~ msgid "Battery information unknown." #~ msgstr "Informacije baterije nepoznate." #~ msgid "Count" #~ msgstr "Broja�" #~ msgid "DPI Sliding Adjustment" #~ msgstr "Prilagodba DPI pomicanjem" #~ msgid "Diverted key or button depressed or released.\n" #~ "Use the Key/Button Diversion setting to divert keys and buttons." #~ msgstr "Preusmjerena tipka pritisnuta ili otpuštena.\n" #~ "Koristite postavku Preusmjeravanje tipke za preusmjeravanje tipki." #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "U�inkovito isklju�uje pomicanje palcem u Linuxu." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "U�inkovito isklju�uje pomicanje kota�ića u Linuxu." #~ msgid "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "Za više informacija pogledajte upute Solaar instalacije\n" #~ "na https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Pronađen je (%s) Logitech Receiver, ali nemate ovlasti za " #~ "otvoriti ga." #~ msgid "HID++ Scrolling" #~ msgstr "HID++ Scrolling" #~ msgid "HID++ Thumb Scrolling" #~ msgstr "HID++ pomicanje palcem" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID++ na�in rada za okomito pomicanje kota�ića palca." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++ na�in rada za okomito pomicanje kota�ića." #~ msgid "High Resolution Scrolling" #~ msgstr "Pomicanje kota�ićem visoke razlu�ivosti" #~ msgid "High Resolution Wheel Invert" #~ msgstr "Obrnuto pomicanje kota�ićem visoke razlu�ivosti" #~ msgid "High-sensitivity wheel invert direction for vertical scroll." #~ msgstr "Obrnuti visoko osjetljivi smjer kota�ića za okomito " #~ "pomicanje." #~ msgid "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "Ako je uređaj već uklju�en,\n" #~ "isklju�ite ga i ponovno uklju�ite." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Ako je uređaj već uklju�en, isklju�ite ga i ponovno " #~ "uklju�ite." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Ako ste upravo instalirali Solaar, pokušajte odspojiti " #~ "prijemnik i ponovno ga spojiti." #~ msgid "Invert thumb scroll direction." #~ msgstr "Obrnuti smjer pomicanja kota�ića palca." #~ msgid "Make the key or button send HID++ notifications (which " #~ "trigger Solaar rules but are otherwise ignored)." #~ msgstr "Neka tipka šalje HID++ obavijesti (što pokreće Solaar " #~ "pravila, u suprotnome ih zanemaruje)." #~ msgid "No Logitech device found" #~ msgstr "Nema pronađenih Logitechovih uređaja" #~ msgid "Scroll Wheel Rachet" #~ msgstr "Ustavljanje pomicanja kota�ića" #~ msgid "Send a gesture by sliding the mouse while holding the button " #~ "down." #~ msgstr "Prilagodite geste pomicanjem miša držeći pritisnutu tipku." #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Prikazuje stanje uređaja povezanih\n" #~ "putem Logitech beži�nih prijemnika." #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar ovisi o udev datoteci koja nije prisutna" #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Prijemnik samo podržava %d upareni uređaj(e)." #~ msgid "The receiver was unplugged." #~ msgstr "Prijemnik je odspojen." #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "Beži�no povezivanje između ovog uređaja i njegovog " #~ "prijemnika nije šifrirano.\n" #~ "\n" #~ "Za uređaje s pokaziva�em (miš, trackballs, trackpads), to je manji " #~ "sigurnosni problem.\n" #~ "\n" #~ "A za uređaje za unos teksta, je veći sigurnosni problem (tipkovnice, " #~ "numpads),\n" #~ "zato jer upisani tekst može biti neprimjentno nadziran u dometu " #~ "treće strane." #~ msgid "Thumb Scroll Invert" #~ msgstr "Obrnuto pomicanje kota�ića palca" #~ msgid "Try removing the device and plugging it back in or turning " #~ "it off and then on." #~ msgstr "Pokušajte uređaj ukloniti pa ponovno priklju�iti s ra�unalom " #~ "ili ga isklju�iti pa ponovno uklju�iti." #~ msgid "USB id" #~ msgstr "USB id" #~ msgid "Wheel Resolution" #~ msgstr "Pomicanje kota�ićem" #~ msgid "closed" #~ msgstr "završeno" #~ msgid "lux" #~ msgstr "lux" #~ msgid "next " #~ msgstr "sljedeće " #~ msgid "open" #~ msgstr "pokrenuto" #~ msgid "paired devices" #~ msgstr "upareni uređaji" #~ msgid "unknown" #~ msgstr "nepoznato" Solaar-1.1.20/po/id.po000066400000000000000000001620101522022367600143730ustar00rootroot00000000000000# Indonesian translations for solaar package. # Copyright (C) 2024 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Ferdina kusumah , 2024. # msgid "" msgstr "Project-Id-Version: solaar 1.1.11\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-03-14 13:11+0700\n" "PO-Revision-Date: 2024-03-14 09:00+0700\n" "Last-Translator: Ferdina Kusumah \n" "Language-Team: none\n" "Language: id\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.0\n" #: lib/logitech_receiver/base_usb.py:45 msgid "Bolt Receiver" msgstr "Reseptor bolt" #: lib/logitech_receiver/base_usb.py:58 msgid "Unifying Receiver" msgstr "Reseptor unifying" #: lib/logitech_receiver/base_usb.py:70 lib/logitech_receiver/base_usb.py:83 #: lib/logitech_receiver/base_usb.py:97 lib/logitech_receiver/base_usb.py:111 #: lib/logitech_receiver/base_usb.py:125 msgid "Nano Receiver" msgstr "Reseptor nano" #: lib/logitech_receiver/base_usb.py:138 msgid "Lightspeed Receiver" msgstr "Reseptor lightspeed" #: lib/logitech_receiver/base_usb.py:149 msgid "EX100 Receiver 27 Mhz" msgstr "Reseptor EX100 27 Mhz" #: lib/logitech_receiver/common.py:604 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Baterai: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:606 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Baterai: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:926 #: lib/logitech_receiver/settings_templates.py:291 msgid "Disabled" msgstr "Dinonaktifkan" #: lib/logitech_receiver/hidpp20.py:927 msgid "Static" msgstr "" #: lib/logitech_receiver/hidpp20.py:928 msgid "Pulse" msgstr "Pulsa" #: lib/logitech_receiver/hidpp20.py:929 msgid "Cycle" msgstr "" #: lib/logitech_receiver/hidpp20.py:930 msgid "Boot" msgstr "" #: lib/logitech_receiver/hidpp20.py:931 msgid "Demo" msgstr "" #: lib/logitech_receiver/hidpp20.py:932 msgid "Breathe" msgstr "" #: lib/logitech_receiver/hidpp20.py:933 msgid "Ripple" msgstr "" #: lib/logitech_receiver/hidpp20.py:994 msgid "Unknown Location" msgstr "Lokasi tidak ditemukan" #: lib/logitech_receiver/hidpp20.py:995 msgid "Primary" msgstr "Utama" #: lib/logitech_receiver/hidpp20.py:996 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:997 msgid "Left Side" msgstr "Sisi kiri" #: lib/logitech_receiver/hidpp20.py:998 msgid "Right Side" msgstr "Sisi kanan" #: lib/logitech_receiver/hidpp20.py:999 msgid "Combined" msgstr "Kombinasi" #: lib/logitech_receiver/hidpp20.py:1000 msgid "Primary 1" msgstr "Utama 1" #: lib/logitech_receiver/hidpp20.py:1001 msgid "Primary 2" msgstr "Utama 2" #: lib/logitech_receiver/hidpp20.py:1002 msgid "Primary 3" msgstr "Utama 3" #: lib/logitech_receiver/hidpp20.py:1003 msgid "Primary 4" msgstr "Utama 4" #: lib/logitech_receiver/hidpp20.py:1004 msgid "Primary 5" msgstr "Utama 5" #: lib/logitech_receiver/hidpp20.py:1005 msgid "Primary 6" msgstr "Utama 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "habis" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "hampir habis" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "rendah" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "setengah" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "baik" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "penuh" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "pemakaian" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "pengisian ulang" #: lib/logitech_receiver/i18n.py:37 msgid "charging" msgstr "pengisian daya" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "tidak mengisi daya" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "hampir penuh" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "mengisi" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "pengisian lambat" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "baterai tidak valid" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "kesalahan termal" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "cepat" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "lambat" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "batas waktu perangkat habis" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "perangkat tidak didukung" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "terlalu banyak perangkat" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "batas waktu urutan habis" #: lib/logitech_receiver/i18n.py:54 msgid "Firmware" msgstr "" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Perangkat keras" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Lainnya" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Tombol Kiri" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Tombol Kanan" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Tombol Tengah" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Tombol kembali" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Tombol Depan" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Tombol Gerakan Mouse" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Pergeseran Cerdas" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Kemiringan Kiri" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Kemiringan Kanan" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Klik Kiri" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Klik Kanan" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Tombol Tengah Mouse" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Tombol Kembali Mouse" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Tombol Depan Mouse" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Navigasi Tombol Gerakan" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Tombol Gulir Kiri Mouse" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Tombol Gulir Kanan Mouse" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "ditekan" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "dilepaskan" #: lib/logitech_receiver/notifications.py:63 #: lib/logitech_receiver/notifications.py:115 msgid "pairing lock is closed" msgstr "kunci penyandingan ditutup" #: lib/logitech_receiver/notifications.py:63 #: lib/logitech_receiver/notifications.py:115 msgid "pairing lock is open" msgstr "kunci penyandingan terbuka" #: lib/logitech_receiver/notifications.py:80 msgid "discovery lock is closed" msgstr "kunci penemuan ditutup" #: lib/logitech_receiver/notifications.py:80 msgid "discovery lock is open" msgstr "kunci penemuan terbuka" #: lib/logitech_receiver/notifications.py:207 msgid "connected" msgstr "terhubung" #: lib/logitech_receiver/notifications.py:207 msgid "disconnected" msgstr "terputus" #: lib/logitech_receiver/notifications.py:233 msgid "unpaired" msgstr "tidak berpasangan" #: lib/logitech_receiver/notifications.py:280 msgid "powered on" msgstr "dihidupkan" #: lib/logitech_receiver/receiver.py:345 msgid "No paired devices." msgstr "Tidak ada perangkat yang dipasangkan" #: lib/logitech_receiver/receiver.py:347 lib/solaar/ui/window.py:630 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s perangkat yang dipasangkan." #: lib/logitech_receiver/settings.py:617 msgid "register" msgstr "daftar" #: lib/logitech_receiver/settings.py:631 lib/logitech_receiver/settings.py:658 msgid "feature" msgstr "fitur" #: lib/logitech_receiver/settings_templates.py:144 msgid "Swap Fx function" msgstr "Tukar fungsi Fx" #: lib/logitech_receiver/settings_templates.py:147 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Jika disetel, tombol F1..F12 akan mengaktifkan fungsi khususnya,\n" "dan Anda harus menahan tombol FN untuk mengaktifkan fungsi " "standarnya." #: lib/logitech_receiver/settings_templates.py:152 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Jika tidak disetel, tombol F1..F12 akan mengaktifkan fungsi " "standarnya,\n" "dan Anda harus menahan tombol FN untuk mengaktifkan fungsi khususnya." #: lib/logitech_receiver/settings_templates.py:160 msgid "Hand Detection" msgstr "Deteksi Tangan" #: lib/logitech_receiver/settings_templates.py:161 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Nyalakan penerangan saat tangan melayang di atas keyboard." #: lib/logitech_receiver/settings_templates.py:168 msgid "Scroll Wheel Smooth Scrolling" msgstr "Roda Gulir Pengguliran Halus" #: lib/logitech_receiver/settings_templates.py:169 #: lib/logitech_receiver/settings_templates.py:402 #: lib/logitech_receiver/settings_templates.py:431 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Mode sensitivitas tinggi untuk gulir vertikal dengan roda." #: lib/logitech_receiver/settings_templates.py:176 msgid "Side Scrolling" msgstr "Menggulir Sisi" #: lib/logitech_receiver/settings_templates.py:178 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Saat dinonaktifkan, mendorong roda ke samping akan mengirimkan " "tombol khususacara\n" "bukannya acara side-scrolling standar." #: lib/logitech_receiver/settings_templates.py:188 msgid "Sensitivity (DPI - older mice)" msgstr "Sensitivitas (DPI - older mouse)" #: lib/logitech_receiver/settings_templates.py:189 #: lib/logitech_receiver/settings_templates.py:958 msgid "Mouse movement sensitivity" msgstr "Sensitivitas gerakan mouse" #: lib/logitech_receiver/settings_templates.py:249 #: lib/logitech_receiver/settings_templates.py:261 #: lib/logitech_receiver/settings_templates.py:388 msgid "Backlight" msgstr "Lampu latar" #: lib/logitech_receiver/settings_templates.py:250 #: lib/logitech_receiver/settings_templates.py:389 msgid "Set illumination time for keyboard." msgstr "Atur waktu penerangan untuk keyboard." #: lib/logitech_receiver/settings_templates.py:262 msgid "Illumination level on keyboard. Changes made are only applied in " "Manual mode." msgstr "Tingkat penerangan pada keyboard. Perubahan yang dilakukan hanya " "diterapkan di Mode manual." #: lib/logitech_receiver/settings_templates.py:293 msgid "Automatic" msgstr "Otomatis" #: lib/logitech_receiver/settings_templates.py:295 msgid "Manual" msgstr "" #: lib/logitech_receiver/settings_templates.py:297 msgid "Enabled" msgstr "Difungsikan" #: lib/logitech_receiver/settings_templates.py:303 msgid "Backlight Level" msgstr "Tingkat Lampu Latar" #: lib/logitech_receiver/settings_templates.py:304 msgid "Illumination level on keyboard when in Manual mode." msgstr "Tingkat penerangan pada keyboard saat dalam mode Manual." #: lib/logitech_receiver/settings_templates.py:361 msgid "Backlight Delay Hands Out" msgstr "Penundaan Lampu Latar Hands Out" #: lib/logitech_receiver/settings_templates.py:362 msgid "Delay in seconds until backlight fades out with hands away from " "keyboard." msgstr "Tunda dalam hitungan detik hingga cahaya latar memudar dengan tangan " "menjauhipapan ketik." #: lib/logitech_receiver/settings_templates.py:370 msgid "Backlight Delay Hands In" msgstr "Penundaan Lampu Latar Masuk" #: lib/logitech_receiver/settings_templates.py:371 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "Tunda dalam hitungan detik hingga lampu latar memudar dengan tangan " "di dekat keyboard." #: lib/logitech_receiver/settings_templates.py:379 msgid "Backlight Delay Powered" msgstr "Penundaan Lampu Latar Didukung" #: lib/logitech_receiver/settings_templates.py:380 msgid "Delay in seconds until backlight fades out with external power." msgstr "Penundaan dalam hitungan detik hingga lampu latar memudar dengan " "daya eksternal." #: lib/logitech_receiver/settings_templates.py:400 msgid "Scroll Wheel High Resolution" msgstr "Resolusi Tinggi Scroll Wheel" #: lib/logitech_receiver/settings_templates.py:404 #: lib/logitech_receiver/settings_templates.py:433 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Setel ke abaikan jika pengguliran terlalu cepat atau lambat" #: lib/logitech_receiver/settings_templates.py:411 #: lib/logitech_receiver/settings_templates.py:442 msgid "Scroll Wheel Diversion" msgstr "Pengalihan Scroll Wheel" #: lib/logitech_receiver/settings_templates.py:413 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "Buat roda gulir mengirimkan notifikasi LOWRES_WHEEL HID++ (yang mana " "memicu aturan Solaar tetapi sebaliknya diabaikan)." #: lib/logitech_receiver/settings_templates.py:420 msgid "Scroll Wheel Direction" msgstr "Arah Scroll Wheel" #: lib/logitech_receiver/settings_templates.py:421 msgid "Invert direction for vertical scroll with wheel." msgstr "Balikkan arah untuk gulir vertikal scroll with wheel." #: lib/logitech_receiver/settings_templates.py:429 msgid "Scroll Wheel Resolution" msgstr "Resolusi Scroll Wheel" #: lib/logitech_receiver/settings_templates.py:444 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "Buat roda gulir mengirimkan notifikasi HIRES_WHEEL HID++ (yang mana " "memicu aturan Solaar tetapi sebaliknya diabaikan)." #: lib/logitech_receiver/settings_templates.py:453 msgid "Sensitivity (Pointer Speed)" msgstr "Sensitivitas (Kecepatan Pointer)" #: lib/logitech_receiver/settings_templates.py:454 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Pengganda kecepatan untuk mouse (256 adalah pengganda normal)." #: lib/logitech_receiver/settings_templates.py:464 msgid "Thumb Wheel Diversion" msgstr "Pengalihan Roda Jempol" #: lib/logitech_receiver/settings_templates.py:466 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "Buat roda jempol mengirimkan notifikasi THUMB_WHEEL HID++ (yang " "memicuPeraturan Solar tetapi sebaliknya diabaikan)." #: lib/logitech_receiver/settings_templates.py:475 msgid "Thumb Wheel Direction" msgstr "Arah Roda Ibu Jari" #: lib/logitech_receiver/settings_templates.py:476 msgid "Invert thumb wheel scroll direction." msgstr "Balikkan arah gulir roda ibu jari." #: lib/logitech_receiver/settings_templates.py:496 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:497 msgid "Enable an onboard profile, which controls report rate, sensitivity, " "and button actions" msgstr "Aktifkan profil onboard, yang mengontrol kecepatan laporan, " "sensitivitas, dan tindakan tombol" #: lib/logitech_receiver/settings_templates.py:541 #: lib/logitech_receiver/settings_templates.py:581 msgid "Report Rate" msgstr "Tingkat Laporan" #: lib/logitech_receiver/settings_templates.py:543 #: lib/logitech_receiver/settings_templates.py:583 msgid "Frequency of device movement reports" msgstr "Frekuensi laporan pergerakan perangkat" #: lib/logitech_receiver/settings_templates.py:543 #: lib/logitech_receiver/settings_templates.py:583 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1326 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "Mungkin perlu Profil Onboard diatur ke Nonaktifkan agar efektif." #: lib/logitech_receiver/settings_templates.py:623 msgid "Divert crown events" msgstr "Alihkan acara mahkota" #: lib/logitech_receiver/settings_templates.py:624 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Buat mahkota mengirimkan notifikasi CROWN HID++ (yang memicu " "Solaarperaturan tetapi sebaliknya diabaikan)." #: lib/logitech_receiver/settings_templates.py:632 msgid "Crown smooth scroll" msgstr "Gulir halus mahkota" #: lib/logitech_receiver/settings_templates.py:633 msgid "Set crown smooth scroll" msgstr "Setel mahkota gulir halus" #: lib/logitech_receiver/settings_templates.py:641 msgid "Divert G and M Keys" msgstr "Alihkan Tombol G dan M" #: lib/logitech_receiver/settings_templates.py:642 msgid "Make G and M keys send HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Buat kunci G dan M mengirimkan notifikasi HID++ (yang memicu " "Solaarperaturan tetapi sebaliknya diabaikan)." #: lib/logitech_receiver/settings_templates.py:656 msgid "Scroll Wheel Ratcheted" msgstr "Roda Gulir Bergerigi" #: lib/logitech_receiver/settings_templates.py:657 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "Ganti roda mouse antara ratcheting yang dikontrol kecepatan dan " "selalu berputar bebas." #: lib/logitech_receiver/settings_templates.py:659 msgid "Freespinning" msgstr "Putar bebas" #: lib/logitech_receiver/settings_templates.py:659 msgid "Ratcheted" msgstr "Digeser" #: lib/logitech_receiver/settings_templates.py:666 msgid "Scroll Wheel Ratchet Speed" msgstr "Kecepatan Ratchet Roda Gulir" #: lib/logitech_receiver/settings_templates.py:668 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "Gunakan kecepatan roda mouse untuk beralih antara ratcheted dan " "berputar bebas.\n" "Roda tikus selalu diputar pada kecepatan 50." #: lib/logitech_receiver/settings_templates.py:717 msgid "Key/Button Actions" msgstr "Tindakan Kunci/Tombol" #: lib/logitech_receiver/settings_templates.py:719 msgid "Change the action for the key or button." msgstr "Ubah tindakan untuk kunci atau tombol tersebut." #: lib/logitech_receiver/settings_templates.py:721 msgid "Overridden by diversion." msgstr "Ditimpa oleh pengalihan." #: lib/logitech_receiver/settings_templates.py:723 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "Mengubah tindakan penting (misalnya tombol kiri mouse) dapat " "menghasilkan sistem yang tidak dapat digunakan." #: lib/logitech_receiver/settings_templates.py:886 msgid "Key/Button Diversion" msgstr "Pengalihan Kunci/Tombol" #: lib/logitech_receiver/settings_templates.py:887 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "Buat kunci atau tombol mengirimkan notifikasi HID++ (Dialihkan) " "ataumemulai Gerakan Mouse atau DPI Geser" #: lib/logitech_receiver/settings_templates.py:890 #: lib/logitech_receiver/settings_templates.py:891 #: lib/logitech_receiver/settings_templates.py:892 msgid "Diverted" msgstr "Dialihkan" #: lib/logitech_receiver/settings_templates.py:890 #: lib/logitech_receiver/settings_templates.py:891 msgid "Mouse Gestures" msgstr "Gerakan Mouse" #: lib/logitech_receiver/settings_templates.py:890 #: lib/logitech_receiver/settings_templates.py:891 #: lib/logitech_receiver/settings_templates.py:892 msgid "Regular" msgstr "" #: lib/logitech_receiver/settings_templates.py:890 msgid "Sliding DPI" msgstr "DPI geser" #: lib/logitech_receiver/settings_templates.py:957 msgid "Sensitivity (DPI)" msgstr "Sensitivitas (DPI)" #: lib/logitech_receiver/settings_templates.py:997 msgid "Sensitivity Switching" msgstr "Peralihan Sensitivitas" #: lib/logitech_receiver/settings_templates.py:999 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "Ganti sensitivitas saat ini dan sensitivitas yang diingat ketika " "tombol atau tombol ditekan.\n" "Jika tidak ada kepekaan yang diingat, ingat saja arusnyakepekaan" #: lib/logitech_receiver/settings_templates.py:1003 msgid "Off" msgstr "Mati" #: lib/logitech_receiver/settings_templates.py:1034 msgid "Disable keys" msgstr "Nonaktifkan kunci" #: lib/logitech_receiver/settings_templates.py:1035 msgid "Disable specific keyboard keys." msgstr "Nonaktifkan tombol keyboard tertentu." #: lib/logitech_receiver/settings_templates.py:1038 #, python-format msgid "Disables the %s key." msgstr "Menonaktifkan kunci %s." #: lib/logitech_receiver/settings_templates.py:1051 #: lib/logitech_receiver/settings_templates.py:1108 msgid "Set OS" msgstr "Atur OS" #: lib/logitech_receiver/settings_templates.py:1052 #: lib/logitech_receiver/settings_templates.py:1109 msgid "Change keys to match OS." msgstr "Ubah kunci agar sesuai dengan OS." #: lib/logitech_receiver/settings_templates.py:1121 msgid "Change Host" msgstr "Ganti Host" #: lib/logitech_receiver/settings_templates.py:1122 msgid "Switch connection to a different host" msgstr "Alihkan koneksi ke host lain" #: lib/logitech_receiver/settings_templates.py:1146 msgid "Performs a left click." msgstr "Melakukan klik kiri." #: lib/logitech_receiver/settings_templates.py:1146 msgid "Single tap" msgstr "Ketuk sekali" #: lib/logitech_receiver/settings_templates.py:1147 msgid "Performs a right click." msgstr "Melakukan klik kanan." #: lib/logitech_receiver/settings_templates.py:1147 msgid "Single tap with two fingers" msgstr "Ketuk satu kali dengan dua jari" #: lib/logitech_receiver/settings_templates.py:1148 msgid "Single tap with three fingers" msgstr "Ketuk satu kali dengan tiga jari" #: lib/logitech_receiver/settings_templates.py:1152 msgid "Double tap" msgstr "Ketuk dua kali" #: lib/logitech_receiver/settings_templates.py:1152 msgid "Performs a double click." msgstr "Melakukan klik dua kali." #: lib/logitech_receiver/settings_templates.py:1153 msgid "Double tap with two fingers" msgstr "Ketuk dua kali dengan dua jari" #: lib/logitech_receiver/settings_templates.py:1154 msgid "Double tap with three fingers" msgstr "Ketuk dua kali dengan tiga jari" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Drags items by dragging the finger after double tapping." msgstr "Menyeret item dengan menyeret jari setelah mengetuk dua kali." #: lib/logitech_receiver/settings_templates.py:1157 msgid "Tap and drag" msgstr "Ketuk dan seret" #: lib/logitech_receiver/settings_templates.py:1159 msgid "Tap and drag with two fingers" msgstr "Ketuk dan seret dengan dua jari" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Drags items by dragging the fingers after double tapping." msgstr "Menyeret item dengan menyeret jari setelah mengetuk dua kali." #: lib/logitech_receiver/settings_templates.py:1162 msgid "Tap and drag with three fingers" msgstr "Ketuk dan seret dengan tiga jari" #: lib/logitech_receiver/settings_templates.py:1165 msgid "Suppress tap and edge gestures" msgstr "Menekan gerakan ketuk dan tepi" #: lib/logitech_receiver/settings_templates.py:1166 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Menonaktifkan gerakan ketuk dan tepi (setara dengan menekan Fn+Klik " "Kiri)." #: lib/logitech_receiver/settings_templates.py:1168 msgid "Scroll with one finger" msgstr "Gulir dengan satu jari" #: lib/logitech_receiver/settings_templates.py:1168 #: lib/logitech_receiver/settings_templates.py:1169 #: lib/logitech_receiver/settings_templates.py:1172 msgid "Scrolls." msgstr "Penggulir" #: lib/logitech_receiver/settings_templates.py:1169 #: lib/logitech_receiver/settings_templates.py:1172 msgid "Scroll with two fingers" msgstr "Gulir dengan dua jari" #: lib/logitech_receiver/settings_templates.py:1170 msgid "Scroll horizontally with two fingers" msgstr "Gulir secara horizontal dengan dua jari" #: lib/logitech_receiver/settings_templates.py:1170 msgid "Scrolls horizontally." msgstr "Menggulir secara horizontal." #: lib/logitech_receiver/settings_templates.py:1171 msgid "Scroll vertically with two fingers" msgstr "Gulir secara vertikal dengan dua jari" #: lib/logitech_receiver/settings_templates.py:1171 msgid "Scrolls vertically." msgstr "Gulir secara vertikal." #: lib/logitech_receiver/settings_templates.py:1173 msgid "Inverts the scrolling direction." msgstr "Membalikkan arah pengguliran." #: lib/logitech_receiver/settings_templates.py:1173 msgid "Natural scrolling" msgstr "Pengguliran alami" #: lib/logitech_receiver/settings_templates.py:1174 msgid "Enables the thumbwheel." msgstr "Mengaktifkan roda jempol." #: lib/logitech_receiver/settings_templates.py:1174 msgid "Thumbwheel" msgstr "Roda jempol" #: lib/logitech_receiver/settings_templates.py:1185 #: lib/logitech_receiver/settings_templates.py:1189 msgid "Swipe from the top edge" msgstr "Geser dari tepi atas" #: lib/logitech_receiver/settings_templates.py:1186 msgid "Swipe from the left edge" msgstr "Geser dari tepi kiri" #: lib/logitech_receiver/settings_templates.py:1187 msgid "Swipe from the right edge" msgstr "Geser dari tepi kanan" #: lib/logitech_receiver/settings_templates.py:1188 msgid "Swipe from the bottom edge" msgstr "Geser dari tepi bawah" #: lib/logitech_receiver/settings_templates.py:1190 msgid "Swipe two fingers from the left edge" msgstr "Geser dua jari dari tepi kiri" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Swipe two fingers from the right edge" msgstr "Geser dua jari dari tepi kanan" #: lib/logitech_receiver/settings_templates.py:1192 msgid "Swipe two fingers from the bottom edge" msgstr "Geser dua jari dari tepi bawah" #: lib/logitech_receiver/settings_templates.py:1193 msgid "Swipe two fingers from the top edge" msgstr "Geser dua jari dari tepi atas" #: lib/logitech_receiver/settings_templates.py:1194 #: lib/logitech_receiver/settings_templates.py:1198 msgid "Pinch to zoom out; spread to zoom in." msgstr "Jepit untuk memperkecil; sebarkan untuk memperbesar." #: lib/logitech_receiver/settings_templates.py:1194 msgid "Zoom with two fingers." msgstr "Perbesar dengan dua jari." #: lib/logitech_receiver/settings_templates.py:1195 msgid "Pinch to zoom out." msgstr "Jepit untuk memperkecil." #: lib/logitech_receiver/settings_templates.py:1196 msgid "Spread to zoom in." msgstr "Sebarkan untuk memperbesar." #: lib/logitech_receiver/settings_templates.py:1197 msgid "Zoom with three fingers." msgstr "Perbesar dengan tiga jari." #: lib/logitech_receiver/settings_templates.py:1198 msgid "Zoom with two fingers" msgstr "Zoom dengan dua jari" #: lib/logitech_receiver/settings_templates.py:1216 msgid "Pixel zone" msgstr "Zona piksel" #: lib/logitech_receiver/settings_templates.py:1217 msgid "Ratio zone" msgstr "Zona rasio" #: lib/logitech_receiver/settings_templates.py:1218 msgid "Scale factor" msgstr "Faktor skala" #: lib/logitech_receiver/settings_templates.py:1218 msgid "Sets the cursor speed." msgstr "Mengatur kecepatan kursor." #: lib/logitech_receiver/settings_templates.py:1222 msgid "Left" msgstr "Kiri" #: lib/logitech_receiver/settings_templates.py:1222 msgid "Left-most coordinate." msgstr "Koordinat paling kiri." #: lib/logitech_receiver/settings_templates.py:1223 msgid "Bottom" msgstr "Dasar" #: lib/logitech_receiver/settings_templates.py:1223 msgid "Bottom coordinate." msgstr "Koordinat bawah." #: lib/logitech_receiver/settings_templates.py:1224 msgid "Width" msgstr "Lebar" #: lib/logitech_receiver/settings_templates.py:1224 msgid "Width." msgstr "" #: lib/logitech_receiver/settings_templates.py:1225 msgid "Height" msgstr "Tinggi" #: lib/logitech_receiver/settings_templates.py:1225 msgid "Height." msgstr "" #: lib/logitech_receiver/settings_templates.py:1226 msgid "Cursor speed." msgstr "Kecepatan kursor." #: lib/logitech_receiver/settings_templates.py:1226 msgid "Scale" msgstr "Skala" #: lib/logitech_receiver/settings_templates.py:1232 msgid "Gestures" msgstr "Gestur" #: lib/logitech_receiver/settings_templates.py:1233 msgid "Tweak the mouse/touchpad behaviour." msgstr "Sesuaikan perilaku mouse/touchpad." #: lib/logitech_receiver/settings_templates.py:1249 msgid "Gestures Diversion" msgstr "Pengalihan Gerakan" #: lib/logitech_receiver/settings_templates.py:1250 msgid "Divert mouse/touchpad gestures." msgstr "Alihkan gerakan mouse/touchpad." #: lib/logitech_receiver/settings_templates.py:1266 msgid "Gesture params" msgstr "Param isyarat" #: lib/logitech_receiver/settings_templates.py:1267 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Ubah parameter numerik mouse/touchpad." #: lib/logitech_receiver/settings_templates.py:1291 msgid "M-Key LEDs" msgstr "LED M-Key" #: lib/logitech_receiver/settings_templates.py:1293 msgid "Control the M-Key LEDs." msgstr "Kontrol LED M-Key." #: lib/logitech_receiver/settings_templates.py:1297 #: lib/logitech_receiver/settings_templates.py:1328 msgid "May need G Keys diverted to be effective." msgstr "Mungkin perlu tombol G dialihkan agar efektif." #: lib/logitech_receiver/settings_templates.py:1303 #, python-format msgid "Lights up the %s key." msgstr "Nyalakan tombol %s." #: lib/logitech_receiver/settings_templates.py:1322 msgid "MR-Key LED" msgstr "LED Kunci MR" #: lib/logitech_receiver/settings_templates.py:1324 msgid "Control the MR-Key LED." msgstr "Kontrol LED MR-Key." #: lib/logitech_receiver/settings_templates.py:1345 msgid "Persistent Key/Button Mapping" msgstr "Pemetaan Kunci/Tombol Persisten" #: lib/logitech_receiver/settings_templates.py:1347 msgid "Permanently change the mapping for the key or button." msgstr "Ubah pemetaan kunci atau tombol secara permanen." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "Mengganti tombol atau tombol penting (misalnya untuk mouse sebelah " "kiritombol) dapat mengakibatkan sistem tidak dapat digunakan." #: lib/logitech_receiver/settings_templates.py:1406 msgid "Sidetone" msgstr "Nada samping" #: lib/logitech_receiver/settings_templates.py:1407 msgid "Set sidetone level." msgstr "Setel level nada samping." #: lib/logitech_receiver/settings_templates.py:1416 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1417 msgid "Set equalizer levels." msgstr "Tetapkan level equalizer." #: lib/logitech_receiver/settings_templates.py:1439 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1445 msgid "Power Management" msgstr "Manajemen daya" #: lib/logitech_receiver/settings_templates.py:1446 msgid "Power off in minutes (0 for never)." msgstr "Matikan dalam hitungan menit (0 untuk tidak pernah)." #: lib/logitech_receiver/settings_templates.py:1457 msgid "LED Control" msgstr "Kontrol LED" #: lib/logitech_receiver/settings_templates.py:1458 msgid "Switch control of LEDs between device and Solaar" msgstr "Ganti kontrol LED antara perangkat dan Solar" #: lib/logitech_receiver/settings_templates.py:1473 msgid "LED Zone Effects" msgstr "Efek Zona LED" #: lib/logitech_receiver/settings_templates.py:1474 msgid "Set effect for LED Zone" msgstr "Atur efek untuk Zona LED" #: lib/logitech_receiver/settings_templates.py:1477 msgid "Speed" msgstr "Kecepatan" #: lib/logitech_receiver/settings_templates.py:1478 msgid "Period" msgstr "Periode" #: lib/logitech_receiver/settings_templates.py:1479 msgid "Intensity" msgstr "Intensitas" #: lib/logitech_receiver/settings_templates.py:1480 msgid "Ramp" msgstr "" #: lib/logitech_receiver/settings_templates.py:1494 msgid "LEDs" msgstr "" #: lib/solaar/ui/__init__.py:112 msgid "Another Solaar process is already running so just expose its window" msgstr "Proses Solaar lain sudah berjalan jadi buka saja jendelanya" #: lib/solaar/ui/about.py:38 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "Mengelola receiver Logitech,\n" "keyboard, mouse, dan tablet." #: lib/solaar/ui/about.py:46 msgid "Additional Programming" msgstr "Pemrograman Tambahan" #: lib/solaar/ui/about.py:47 msgid "GUI design" msgstr "desain GUI" #: lib/solaar/ui/about.py:49 msgid "Testing" msgstr "Pengujian" #: lib/solaar/ui/about.py:57 msgid "Logitech documentation" msgstr "Dokumentasi Logitech" #: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87 #: lib/solaar/ui/window.py:199 msgid "Unpair" msgstr "Lepaskan pasangan" #: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:104 msgid "Cancel" msgstr "Membatalkan" #: lib/solaar/ui/common.py:35 msgid "Permissions error" msgstr "Kesalahan izin" #: lib/solaar/ui/common.py:37 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "Menemukan receiver atau perangkat Logitech (%s), namun tidak " "memiliki izin untuk membukanya." #: lib/solaar/ui/common.py:39 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "Kalau baru install Solaar, coba cabut receivernya atauperangkat dan " "kemudian menyambungkannya kembali." #: lib/solaar/ui/common.py:42 msgid "Cannot connect to device error" msgstr "Tidak dapat terhubung ke perangkat kesalahan" #: lib/solaar/ui/common.py:44 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "Menemukan receiver atau perangkat Logitech di %s, namun mengalami " "kesalahanmenghubungkannya." #: lib/solaar/ui/common.py:46 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "Coba putuskan sambungan perangkat lalu sambungkan kembali atau " "putarmati lalu hidupkan." #: lib/solaar/ui/common.py:49 msgid "Unpairing failed" msgstr "Pembatalan pasangan gagal" #: lib/solaar/ui/common.py:51 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Gagal melepaskan pasangan %{device} dari %{receiver}." #: lib/solaar/ui/common.py:53 msgid "The receiver returned an error, with no further details." msgstr "Penerima mengembalikan kesalahan, tanpa rincian lebih lanjut." #: lib/solaar/ui/config_panel.py:231 msgid "Complete - ENTER to change" msgstr "Selesai - ENTER untuk mengubah" #: lib/solaar/ui/config_panel.py:231 msgid "Incomplete" msgstr "Tidak lengkap" #: lib/solaar/ui/config_panel.py:476 lib/solaar/ui/config_panel.py:529 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d nilai" #: lib/solaar/ui/config_panel.py:612 msgid "Changes allowed" msgstr "Perubahan diperbolehkan" #: lib/solaar/ui/config_panel.py:613 msgid "No changes allowed" msgstr "Tidak ada perubahan yang diizinkan" #: lib/solaar/ui/config_panel.py:614 msgid "Ignore this setting" msgstr "Abaikan pengaturan ini" #: lib/solaar/ui/config_panel.py:659 msgid "Working" msgstr "Bekerja" #: lib/solaar/ui/config_panel.py:662 msgid "Read/write operation failed." msgstr "Operasi baca/tulis gagal." #: lib/solaar/ui/diversion_rules.py:66 msgid "Built-in rules" msgstr "Aturan bawaan" #: lib/solaar/ui/diversion_rules.py:66 msgid "User-defined rules" msgstr "Aturan yang ditentukan pengguna" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:1089 msgid "Rule" msgstr "Aturan" #: lib/solaar/ui/diversion_rules.py:69 lib/solaar/ui/diversion_rules.py:538 #: lib/solaar/ui/diversion_rules.py:665 msgid "Sub-rule" msgstr "Sub-aturan" #: lib/solaar/ui/diversion_rules.py:71 msgid "[empty]" msgstr "[kosong]" #: lib/solaar/ui/diversion_rules.py:95 msgid "Make changes permanent?" msgstr "Membuat perubahan permanen?" #: lib/solaar/ui/diversion_rules.py:100 msgid "Yes" msgstr "Ya" #: lib/solaar/ui/diversion_rules.py:102 msgid "No" msgstr "Tidak" #: lib/solaar/ui/diversion_rules.py:107 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Jika Anda memilih Tidak, perubahan akan hilang saat Solaar ditutup." #: lib/solaar/ui/diversion_rules.py:138 msgid "Solaar Rule Editor" msgstr "Editor Aturan Surya" #: lib/solaar/ui/diversion_rules.py:231 msgid "Save changes" msgstr "Simpan perubahan" #: lib/solaar/ui/diversion_rules.py:236 msgid "Discard changes" msgstr "Membuang perubahan" #: lib/solaar/ui/diversion_rules.py:397 msgid "Insert here" msgstr "Masukkan di sini" #: lib/solaar/ui/diversion_rules.py:399 msgid "Insert above" msgstr "Masukkan di atas" #: lib/solaar/ui/diversion_rules.py:401 msgid "Insert below" msgstr "Masuk di bawah" #: lib/solaar/ui/diversion_rules.py:407 msgid "Insert new rule here" msgstr "Masukkan aturan baru di sini" #: lib/solaar/ui/diversion_rules.py:409 msgid "Insert new rule above" msgstr "Masukkan aturan baru di atas" #: lib/solaar/ui/diversion_rules.py:411 msgid "Insert new rule below" msgstr "Masukkan aturan baru di bawah" #: lib/solaar/ui/diversion_rules.py:456 msgid "Paste here" msgstr "Tempel di sini" #: lib/solaar/ui/diversion_rules.py:458 msgid "Paste above" msgstr "Tempel di atas" #: lib/solaar/ui/diversion_rules.py:460 msgid "Paste below" msgstr "Tempel di bawah" #: lib/solaar/ui/diversion_rules.py:466 msgid "Paste rule here" msgstr "Tempel aturan di sini" #: lib/solaar/ui/diversion_rules.py:468 msgid "Paste rule above" msgstr "Tempel aturan di atas" #: lib/solaar/ui/diversion_rules.py:470 msgid "Paste rule below" msgstr "Tempel aturan di bawah" #: lib/solaar/ui/diversion_rules.py:474 msgid "Paste rule" msgstr "Tempel aturan" #: lib/solaar/ui/diversion_rules.py:503 msgid "Flatten" msgstr "Meratakan" #: lib/solaar/ui/diversion_rules.py:536 msgid "Insert" msgstr "Menyisipkan" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:667 #: lib/solaar/ui/diversion_rules.py:1129 msgid "Or" msgstr "Atau" #: lib/solaar/ui/diversion_rules.py:540 lib/solaar/ui/diversion_rules.py:666 #: lib/solaar/ui/diversion_rules.py:1115 msgid "And" msgstr "Dan" #: lib/solaar/ui/diversion_rules.py:542 msgid "Condition" msgstr "Kondisi" #: lib/solaar/ui/diversion_rules.py:544 lib/solaar/ui/diversion_rules.py:1290 msgid "Feature" msgstr "Fitur" #: lib/solaar/ui/diversion_rules.py:545 lib/solaar/ui/diversion_rules.py:1325 msgid "Report" msgstr "Laporan" #: lib/solaar/ui/diversion_rules.py:546 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Proses" #: lib/solaar/ui/diversion_rules.py:547 msgid "Mouse process" msgstr "Proses tikus" #: lib/solaar/ui/diversion_rules.py:548 lib/solaar/ui/diversion_rules.py:1362 msgid "Modifiers" msgstr "Pengubah" #: lib/solaar/ui/diversion_rules.py:549 lib/solaar/ui/diversion_rules.py:1414 msgid "Key" msgstr "Kunci" #: lib/solaar/ui/diversion_rules.py:550 lib/solaar/ui/diversion_rules.py:1455 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:551 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Aktif" #: lib/solaar/ui/diversion_rules.py:552 lib/solaar/ui/diversion_rules.py:2217 #: lib/solaar/ui/diversion_rules.py:2269 lib/solaar/ui/diversion_rules.py:2319 msgid "Device" msgstr "Perangkat" #: lib/solaar/ui/diversion_rules.py:553 lib/solaar/ui/diversion_rules.py:2295 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:554 lib/solaar/ui/diversion_rules.py:2337 msgid "Setting" msgstr "Pengaturan" #: lib/solaar/ui/diversion_rules.py:555 lib/solaar/ui/diversion_rules.py:1470 #: lib/solaar/ui/diversion_rules.py:1519 msgid "Test" msgstr "" #: lib/solaar/ui/diversion_rules.py:556 lib/solaar/ui/diversion_rules.py:1633 msgid "Test bytes" msgstr "Uji byte" #: lib/solaar/ui/diversion_rules.py:557 lib/solaar/ui/diversion_rules.py:1734 msgid "Mouse Gesture" msgstr "Gerakan Mouse" #: lib/solaar/ui/diversion_rules.py:561 msgid "Action" msgstr "Aksi" #: lib/solaar/ui/diversion_rules.py:563 lib/solaar/ui/diversion_rules.py:1844 msgid "Key press" msgstr "Tekan tombol" #: lib/solaar/ui/diversion_rules.py:564 lib/solaar/ui/diversion_rules.py:1895 msgid "Mouse scroll" msgstr "Gulir mouse" #: lib/solaar/ui/diversion_rules.py:565 lib/solaar/ui/diversion_rules.py:1956 msgid "Mouse click" msgstr "Klik mouse" #: lib/solaar/ui/diversion_rules.py:566 msgid "Set" msgstr "Mengatur" #: lib/solaar/ui/diversion_rules.py:567 lib/solaar/ui/diversion_rules.py:2026 msgid "Execute" msgstr "Menjalankan" #: lib/solaar/ui/diversion_rules.py:568 lib/solaar/ui/diversion_rules.py:1160 msgid "Later" msgstr "Nanti" #: lib/solaar/ui/diversion_rules.py:597 msgid "Insert new rule" msgstr "Masukkan aturan baru" #: lib/solaar/ui/diversion_rules.py:617 lib/solaar/ui/diversion_rules.py:1681 #: lib/solaar/ui/diversion_rules.py:1786 lib/solaar/ui/diversion_rules.py:1985 msgid "Delete" msgstr "Menghapus" #: lib/solaar/ui/diversion_rules.py:639 msgid "Negate" msgstr "Meniadakan" #: lib/solaar/ui/diversion_rules.py:663 msgid "Wrap with" msgstr "Bungkus dengan" #: lib/solaar/ui/diversion_rules.py:685 msgid "Cut" msgstr "Potong" #: lib/solaar/ui/diversion_rules.py:700 msgid "Paste" msgstr "Tempel" #: lib/solaar/ui/diversion_rules.py:706 msgid "Copy" msgstr "Salin" #: lib/solaar/ui/diversion_rules.py:1070 msgid "This editor does not support the selected rule component yet." msgstr "Editor ini belum mendukung komponen aturan yang dipilih." #: lib/solaar/ui/diversion_rules.py:1140 msgid "Number of seconds to delay." msgstr "Jumlah detik untuk ditunda." #: lib/solaar/ui/diversion_rules.py:1178 msgid "Not" msgstr "Bukan" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "Proses aktif X11. Hanya untuk digunakan di X11." #: lib/solaar/ui/diversion_rules.py:1217 msgid "X11 mouse process. For use in X11 only." msgstr "Proses mouse X11. Hanya untuk digunakan di X11." #: lib/solaar/ui/diversion_rules.py:1234 msgid "MouseProcess" msgstr "Proses Tikus" #: lib/solaar/ui/diversion_rules.py:1258 msgid "Feature name of notification triggering rule processing." msgstr "Nama fitur notifikasi yang memicu pemrosesan aturan." #: lib/solaar/ui/diversion_rules.py:1305 msgid "Report number of notification triggering rule processing." msgstr "Laporkan jumlah pemberitahuan yang memicu pemrosesan aturan." #: lib/solaar/ui/diversion_rules.py:1338 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Pengubah keyboard aktif. Tidak selalu tersedia di Wayland." #: lib/solaar/ui/diversion_rules.py:1378 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "Tombol atau tombol yang dialihkan ditekan atau dilepaskan.\n" "Gunakan pengaturan Pengalihan Tombol/Tombol dan Pengalihan Tombol G " "untuk mengalihkankunci dan tombol." #: lib/solaar/ui/diversion_rules.py:1387 msgid "Key down" msgstr "Kunci bawah" #: lib/solaar/ui/diversion_rules.py:1390 msgid "Key up" msgstr "Kunci atas" #: lib/solaar/ui/diversion_rules.py:1430 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "Tombol atau tombol yang dialihkan sedang tidak aktif.\n" "Gunakan pengaturan Pengalihan Tombol/Tombol dan Pengalihan Tombol G " "untuk mengalihkankunci dan tombol." #: lib/solaar/ui/diversion_rules.py:1468 msgid "Test condition on notification triggering rule processing." msgstr "Uji kondisi pada notifikasi yang memicu pemrosesan aturan." #: lib/solaar/ui/diversion_rules.py:1472 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1534 msgid "begin (inclusive)" msgstr "mulai (inklusif)" #: lib/solaar/ui/diversion_rules.py:1535 msgid "end (exclusive)" msgstr "akhir (eksklusif)" #: lib/solaar/ui/diversion_rules.py:1543 msgid "range" msgstr "jangkauan" #: lib/solaar/ui/diversion_rules.py:1546 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/diversion_rules.py:1547 msgid "maximum" msgstr "maksimum" #: lib/solaar/ui/diversion_rules.py:1549 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "byte %(0)d hingga %(1)d, mulai dari %(2)d hingga %(3)d" #: lib/solaar/ui/diversion_rules.py:1552 lib/solaar/ui/diversion_rules.py:1553 msgid "mask" msgstr "" #: lib/solaar/ui/diversion_rules.py:1554 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "byte %(0)d hingga %(1)d, sembunyikan %(2)d" #: lib/solaar/ui/diversion_rules.py:1563 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "Pengujian bit atau rentang pada byte dalam aturan pemicu pesan " "notifikasipengolahan." #: lib/solaar/ui/diversion_rules.py:1573 msgid "type" msgstr "jenis" #: lib/solaar/ui/diversion_rules.py:1661 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "Gerakan mouse dengan tombol memulai opsional diikuti dengan nol atau " "lebih banyak gerakan tikus." #: lib/solaar/ui/diversion_rules.py:1666 msgid "Add movement" msgstr "Tambahkan gerakan" #: lib/solaar/ui/diversion_rules.py:1760 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simulasikan klik atau tekan atau lepaskan kunci chord.\n" "On Wayland memerlukan akses tulis ke /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1765 msgid "Add key" msgstr "Tambahkan kunci" #: lib/solaar/ui/diversion_rules.py:1768 msgid "Click" msgstr "Klik" #: lib/solaar/ui/diversion_rules.py:1771 msgid "Depress" msgstr "Menekan" #: lib/solaar/ui/diversion_rules.py:1774 msgid "Release" msgstr "Melepaskan" #: lib/solaar/ui/diversion_rules.py:1859 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simulasikan gulir mouse.\n" "On Wayland memerlukan akses tulis ke /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1915 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "Simulasikan klik mouse.\n" "On Wayland memerlukan akses tulis ke /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1918 msgid "Button" msgstr "Tombol" #: lib/solaar/ui/diversion_rules.py:1919 msgid "Count and Action" msgstr "Hitungan dan Tindakan" #: lib/solaar/ui/diversion_rules.py:1968 msgid "Execute a command with arguments." msgstr "Jalankan perintah dengan argumen." #: lib/solaar/ui/diversion_rules.py:1971 msgid "Add argument" msgstr "Tambahkan argumen" #: lib/solaar/ui/diversion_rules.py:2046 msgid "Toggle" msgstr "Beralih" #: lib/solaar/ui/diversion_rules.py:2047 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:2048 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:2061 msgid "Unsupported setting" msgstr "Pengaturan tidak didukung" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2243 #: lib/solaar/ui/diversion_rules.py:2325 lib/solaar/ui/diversion_rules.py:2568 #: lib/solaar/ui/diversion_rules.py:2586 msgid "Originating device" msgstr "Perangkat asal" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "Perangkat aktif dan pengaturannya dapat diubah." #: lib/solaar/ui/diversion_rules.py:2265 msgid "Device that originated the current notification." msgstr "Perangkat yang memunculkan notifikasi saat ini." #: lib/solaar/ui/diversion_rules.py:2278 msgid "Name of host computer." msgstr "Nama komputer induk." #: lib/solaar/ui/diversion_rules.py:2345 msgid "Value" msgstr "Nilai" #: lib/solaar/ui/diversion_rules.py:2353 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:2627 msgid "Change setting on device" msgstr "Ubah pengaturan pada perangkat" #: lib/solaar/ui/diversion_rules.py:2643 msgid "Setting on device" msgstr "Pengaturan pada perangkat" #: lib/solaar/ui/notify.py:118 msgid "unspecified reason" msgstr "alasan yang tidak ditentukan" #: lib/solaar/ui/pair_window.py:126 lib/solaar/ui/pair_window.py:260 #: lib/solaar/ui/pair_window.py:296 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: memasangkan perangkat baru" #: lib/solaar/ui/pair_window.py:127 #, python-format msgid "Enter passcode on %(name)s." msgstr "Masukkan kode sandi pada %(name)s." #: lib/solaar/ui/pair_window.py:130 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Ketik %(passcode)s lalu tekan tombol enter." #: lib/solaar/ui/pair_window.py:133 msgid "left" msgstr "Kiri" #: lib/solaar/ui/pair_window.py:133 msgid "right" msgstr "Kanan" #: lib/solaar/ui/pair_window.py:135 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "Tekan %(code)s\n" "lalu tekan tombol kiri dan kanan secara bersamaan." #: lib/solaar/ui/pair_window.py:192 msgid "Pairing failed" msgstr "Pemasangan gagal" #: lib/solaar/ui/pair_window.py:194 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Pastikan perangkat Anda berada dalam jangkauan dan memiliki baterai " "yang layakmengenakan biaya." #: lib/solaar/ui/pair_window.py:196 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Perangkat baru terdeteksi, tetapi tidak kompatibel dengan " "inipenerima." #: lib/solaar/ui/pair_window.py:198 msgid "More paired devices than receiver can support." msgstr "Lebih banyak perangkat berpasangan daripada yang dapat didukung oleh " "receiver." #: lib/solaar/ui/pair_window.py:200 msgid "No further details are available about the error." msgstr "Tidak ada rincian lebih lanjut yang tersedia tentang kesalahan " "tersebut." #: lib/solaar/ui/pair_window.py:214 msgid "Found a new device:" msgstr "Menemukan perangkat baru:" #: lib/solaar/ui/pair_window.py:239 msgid "The wireless link is not encrypted" msgstr "Tautan nirkabel tidak dienkripsi" #: lib/solaar/ui/pair_window.py:268 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Penerima Unifying hanya kompatibel dengan perangkat Unifying." #: lib/solaar/ui/pair_window.py:270 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Penerima Bolt hanya kompatibel dengan perangkat Bolt." #: lib/solaar/ui/pair_window.py:272 msgid "Other receivers are only compatible with a few devices." msgstr "Receiver lain hanya kompatibel dengan beberapa perangkat." #: lib/solaar/ui/pair_window.py:274 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "Perangkat tidak boleh dipasangkan dengan receiver terdekat yang " "aktif." #: lib/solaar/ui/pair_window.py:278 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "Tekan tombol atau kunci penyandingan hingga lampu penyandingan " "berkedipdengan cepat." #: lib/solaar/ui/pair_window.py:280 msgid "You may have to first turn the device off and on again." msgstr "Anda mungkin harus mematikan dan menghidupkan kembali perangkat " "terlebih dahulu." #: lib/solaar/ui/pair_window.py:282 msgid "Turn on the device you want to pair." msgstr "Nyalakan perangkat yang ingin Anda pasangkan." #: lib/solaar/ui/pair_window.py:284 msgid "If the device is already turned on, turn it off and on again." msgstr "Jika perangkat sudah dihidupkan, matikan dan hidupkan kembali." #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "Penerima ini memiliki %d sisa penyandingan." #: lib/solaar/ui/pair_window.py:294 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Membatalkan pada saat ini tidak akan menghabiskan pasangan." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "Tidak ditemukan perangkat yang didukung" #: lib/solaar/ui/tray.py:63 lib/solaar/ui/window.py:321 #, python-format msgid "About %s" msgstr "Tentang %s" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "Quit %s" msgstr "Keluar %s" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:302 msgid "no receiver" msgstr "tidak ada penerima" #: lib/solaar/ui/tray.py:315 lib/solaar/ui/tray.py:320 msgid "offline" msgstr "" #: lib/solaar/ui/tray.py:318 msgid "no status" msgstr "tidak ada status" #: lib/solaar/ui/window.py:99 msgid "Scanning" msgstr "Memindai" #: lib/solaar/ui/window.py:132 msgid "Battery" msgstr "Baterai" #: lib/solaar/ui/window.py:135 msgid "Wireless Link" msgstr "Tautan Nirkabel" #: lib/solaar/ui/window.py:139 msgid "Lighting" msgstr "" #: lib/solaar/ui/window.py:173 msgid "Show Technical Details" msgstr "Tampilkan Detail Teknis" #: lib/solaar/ui/window.py:189 msgid "Pair new device" msgstr "Pasangkan perangkat baru" #: lib/solaar/ui/window.py:207 msgid "Select a device" msgstr "Pilih perangkat" #: lib/solaar/ui/window.py:324 msgid "Rule Editor" msgstr "Editor Aturan" #: lib/solaar/ui/window.py:543 msgid "Path" msgstr "Path" #: lib/solaar/ui/window.py:546 msgid "USB ID" msgstr "ID USB" #: lib/solaar/ui/window.py:549 lib/solaar/ui/window.py:551 #: lib/solaar/ui/window.py:566 lib/solaar/ui/window.py:568 msgid "Serial" msgstr "" #: lib/solaar/ui/window.py:555 msgid "Index" msgstr "Indeks" #: lib/solaar/ui/window.py:557 msgid "Wireless PID" msgstr "PID Nirkabel" #: lib/solaar/ui/window.py:559 msgid "Product ID" msgstr "ID Produk" #: lib/solaar/ui/window.py:561 msgid "Protocol" msgstr "Protokol" #: lib/solaar/ui/window.py:561 msgid "Unknown" msgstr "Tidak Diketahui" #: lib/solaar/ui/window.py:563 msgid "Polling rate" msgstr "Tingkat pemungutan suara" #: lib/solaar/ui/window.py:570 msgid "Unit ID" msgstr "ID Satuan" #: lib/solaar/ui/window.py:584 msgid "Notifications" msgstr "Pemberitahuan" #: lib/solaar/ui/window.py:628 msgid "No device paired." msgstr "Tidak ada perangkat yang dipasangkan." #: lib/solaar/ui/window.py:637 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Hingga %(max_count)s perangkat dapat dipasangkan ke receiver " "ini." #: lib/solaar/ui/window.py:648 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Penerima ini memiliki %d sisa penyandingan." #: lib/solaar/ui/window.py:705 msgid "Battery Voltage" msgstr "Tegangan Baterai" #: lib/solaar/ui/window.py:707 msgid "Voltage reported by battery" msgstr "Tegangan dilaporkan oleh baterai" #: lib/solaar/ui/window.py:709 msgid "Battery Level" msgstr "Tingkat Baterai" #: lib/solaar/ui/window.py:711 msgid "Approximate level reported by battery" msgstr "Perkiraan level yang dilaporkan oleh baterai" #: lib/solaar/ui/window.py:718 lib/solaar/ui/window.py:720 msgid "next reported " msgstr "selanjutnya dilaporkan " #: lib/solaar/ui/window.py:721 msgid " and next level to be reported." msgstr " dan tingkat selanjutnya yang akan dilaporkan." #: lib/solaar/ui/window.py:737 msgid "encrypted" msgstr "terenkripsi" #: lib/solaar/ui/window.py:739 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Hubungan nirkabel antara perangkat ini dan penerimanya dienkripsi." #: lib/solaar/ui/window.py:741 msgid "not encrypted" msgstr "tidak dienkripsi" #: lib/solaar/ui/window.py:745 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "Hubungan nirkabel antara perangkat ini dan penerimanya tidak " "terenkripsi.\n" "Ini adalah masalah keamanan untuk perangkat penunjuk, dan merupakan " "masalah keamanan utamamasalah untuk perangkat input teks." #: lib/solaar/ui/window.py:761 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d mewah" Solaar-1.1.20/po/it.po000066400000000000000000001461461522022367600144270ustar00rootroot00000000000000# Italian translations for solaar package. # Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2013. # msgid "" msgstr "Project-Id-Version: solaar 0.9.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2021-01-28 19:21+0000\n" "Last-Translator: Lorenzo \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Launchpad-Export-Date: 2021-02-17 00:56+0000\n" "X-Generator: Launchpad (build " "b3a93345a124168b715ec9ae0945884caa15f58f)\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "vuoto" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "critico" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "bassa" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "buono" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "piena" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "in scarica" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "in ricarica" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "in ricarica" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "quasi piena" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "carico" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "ricarica lenta" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "batteria non valida" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "errore di temperatura" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "timeout del dispositivo" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "dispositivo non supportato" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "troppe periferiche" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "timeout della sequenza" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Altro" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "connesso" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "disconnesso" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "non associato" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "acceso" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Inverti funzioni Fx" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Quando abilitato, i tasti F1..F12 attivano le funzioni speciali,\n" "e dovrai tenere premuto il tasto FN per attivare le funzioni " "standard." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Quando disabilitato, i tasti F1..F12 attivano le funzioni standard,\n" "dovrai tenere premuto il tasto FN per attivare le funzioni speciali." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Rilevamento mano" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Accendi l'illuminazione quando le mani sono sopra la tastiera." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Modalità di alta sensibilità per lo scorrimento verticale con la " "rotella." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Scorrimento Laterale" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Quando disabilitato, spingendo la rotella lateralmente vengono " "inviati eventi personalizzati\n" "invece degli eventi standard di scorrimento laterale." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "Sensibilità al movimento del mouse" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Retroilluminazione" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "Accendi o spegni l'illuminazione della tastiera" #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "Direzione di scorrimento con la rotella" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "Inverti la direzione per lo scorrimento verticale con la rotella" #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "Risoluzione dello scorrimento con la rotella" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Sensibilità (velocità del puntatore)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Moltiplicatore della velocità del mouse (256 è il moltiplicatore " "normale)" #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "Azioni tasto/pulsante" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Cambia l'azione per il tasto o il pulsante" #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "Cambiare azioni importanti (come per il bottone sinistro del mouse) " "può rendere inutilizzabile il sistema" #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Sensibilità (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Disabilita i pulsanti" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Disabilita dei pulsanti specifici della tastiera" #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "Disabilita il tasto %s" #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Specifica il sistema operativo" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Cambia i pulsanti in funzione del sistema operativo" #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Cambia Host" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Connetti ad un host differente" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "Clicca con il pulsante sinistro" #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "tocco singolo" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "Clicca con il pulsante destro" #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "tocco singolo con due dita" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "tocco singolo con tre dita" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "doppio tocco" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "Esegue un doppio click" #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "doppio tocco con due dita" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "doppio tocco con tre dita" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "Trascina gli elementi muovendo il dito dopo aver fatto un doppio tap" #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "tocca e trascina" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "Trascina gli elementi muovendo il dito dopo aver fatto un doppio tap" #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "tocca e trascina con due dita" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "tocca e trascina con tre dita" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "scorri con un dito" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "Scorre." #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "scorri con due dita" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "scorri orizzontalmente con due dita" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "scorre orizzontalmente" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "scorri verticalmente con due dita" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "scorre verticalmente" #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "inverte la direzione di scorrimento" #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "Scorrimento naturale" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "scorri dal bordo superiore" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "scorri dal bordo sinistro" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "scorri dal bordo destro" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "scorri dal bordo inferiore" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "scorri con due dita dal bordo sinistro" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "scorri con due dita dal bordo detro" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "scorri con due dita dal bordo inferiore" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "scorri con due dita dal bordo superiore" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "fai lo zoom con due dita" #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "pizzica per rimpicciolire" #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "fai lo zoom con tre dita" #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "fai lo zoom con due dita" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Fattore di scala" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "Sinistra" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Larghezza" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "Larghezza" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Altezza" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "Altezza" #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "Velocità del cursore" #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "Scala" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gesti" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "Personalizza il comportamento del mouse/touchpad" #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Cambia i paramentri numerici di un mouse/touchpad" #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Nessun dispositivo associato." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s dispositivo connesso." msgstr[1] "%(count)s dispositivi connessi." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Batteria: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Batteria: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Illuminazione: %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batteria: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batteria: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Errore di permessi" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Disassociazione fallita" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Disassociazione fallita di %{device} da %{receiver}." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "Il ricevitore ha ritornato un errore senza ulteriori dettagli." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "GUI design" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Testing" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Documentazione Logitech" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Disassocia" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d valore" msgstr[1] "%d valori" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Lavorando" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Operazione di Lettura/Scrittura fallita." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "Regole integrate" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "Regole definite dall'utente" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "Regola" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[vuoto]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Editor di regole di Solaar" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "Rendi le modifiche permanenti?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Sì" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Se scegli No, le modifiche saranno perse quando Solaar viene chiuso" #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "Inserisci qui" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "Inserisci sopra" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "Inserisci sotto" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "Inserisci una nuova regola qui" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "Inserisci una nuova regola sopra" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "Inserisci una nuova regola sotto" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "Incolla qui" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "Incolla sopra" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "Incolla sotto" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "Incolla la regola qui" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "Incolla la regola sopra" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "Incolla la regola sotto" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "Incolla la regola" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "Appiattisci" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "Inserisci" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "Oppure" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "E" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "Condizione" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "Funzionalità" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "Segnala" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Processo" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "Modificatori" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "Chiave" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Attivo" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Azione" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "Pressione del tasto" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "Scorrimento del mouse" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "Click del mouse" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "Esegui" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "Inserisci una nuova regola" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "Elimina" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "Nega" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Taglia" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Incolla" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Copia" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "Questo editor ancora non supporta la componente selezionata" #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "" #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "Aggiungi chiave" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "Pulsante" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Valore" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "disconnesso" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: accoppia un nuovo dispositivo" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "" #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Associazione fallita" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Assicurati che il dispositivo sia vicino al ricevitore e che abbia " "le batterie cariche." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Un nuovo dispositivo è stato rilevato, ma non è compatibile con " "questo ricevitore." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "Più dispositivi accoppiati di quanti il ricevitore possa supportarne" #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Non sono disponibili ulteriori dettagli per l'errore." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "Trovato un nuovo dispositivo:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "Il collegamento wireless non è ciftrato." #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Accendi il dispositivo che vuoi associare." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "Questo ricevitore ha %d accoppiamento rimanente." msgstr[1] "\n" "\n" "Questo ricevitore ha %d accoppiamenti rimanenti." #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Annullando a questo punto non costerà un accoppiamento" #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "Informazioni %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Esci %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "nessun ricevitore" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "nessuno stato" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Ricerca" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Batteria" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Collegamento Wireless" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Luminosità" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Mostra Dettagli Tecnici" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Associa un nuovo dispositivo" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Seleziona un dispositivo" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "Editor regole" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Percorso" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "ID USB" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Seriale" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Indice" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "PID Wireless" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "ID Prodotto" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protocollo" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Sconosciuto" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Frequenza di aggiornamento" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "ID unità" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "nessuno" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Notifiche" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "Nessun dispositivo accoppiato" #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Fino a %(max_count)s dispositivo può essere accoppiato con " "questo ricevitore" msgstr[1] "Fino a %(max_count)s dispositivi possono essere accoppiati " "con questo ricevitore" #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "Solo un dispositivo può essere collegato a questo ricevitore" #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Questo ricevitore ha %d accoppiamento rimanente" msgstr[1] "Questo ricevitore ha %d accoppiamenti rimanenti" #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "Tensione della batteria" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "Tensione riportata dalla batteria" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "Livello batteria" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "Livello approssimativo riportato dalla batteria" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "Prossimo livello " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " e il prossimo livello che verrà riportato" #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "ultimo conosciuto" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "cifrato" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Il collegamento wireless tra il dispositivo e il suo ricevitore è " "cifrato." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "non cifrato" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the DPI button." #~ msgstr "Modifica i DPI facendo scorrere il mouse orizzontalmente " #~ "mentre si preme il pulsante DPI" #~ msgid "Battery information unknown." #~ msgstr "Informazioni sulla batteria sconosciute" #~ msgid "Click to allow changes." #~ msgstr "Premi per consentire modifiche" #~ msgid "Click to prevent changes." #~ msgstr "Clicca per evitare modifiche" #~ msgid "Count" #~ msgstr "Numero" #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Di fatto in Linux disattiva lo scorrimento con la rotella" #~ msgid "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "Per ulteriori informazioni consulta le istruzioni " #~ "all'installazione di Solaar\n" #~ "su https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Rilevato un ricevitore Logitech (%s), ma non si hanno i " #~ "permessi per aprirlo." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "Modalità HID++ per lo scorrimento verticale con la rotella" #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Se il dispositivo è già acceso, spegnilo e accendilo " #~ "nuovamente." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Se hai appena installato Solaar prova a scollegare e " #~ "ricollegare il ricevitore." #~ msgid "No Logitech receiver found" #~ msgstr "Nessun ricevitore Logitech trovato" #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Mostra lo stato dei dispositivi connessi\n" #~ "attraverso i ricevitori Logitech." #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar dipende da un file udev non presente" #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "Il collegamento wireless tra il dispositivo e il suo " #~ "ricevitore non è cifrato.\n" #~ "\n" #~ "Per i dispositivi di puntamento (mouse, trackball, trackpad) non è " #~ "un grave problema.\n" #~ "\n" #~ "E' un problema maggiore per i dispositivi di immissione di testo " #~ "(tastiera, numpad),\n" #~ "perché il testo digitato potrebbe essere intercettato da dispositivi " #~ "di terze parti vicini." #~ msgid "Thumb Wheel HID++ Scrolling" #~ msgstr "Rotella di scorrimento Scorrimento HID++" #~ msgid "height" #~ msgstr "altezza" #~ msgid "top" #~ msgstr "in alto" #~ msgid "unknown" #~ msgstr "sconosciuto" #~ msgid "width" #~ msgstr "larghezza" Solaar-1.1.20/po/ja.po000066400000000000000000001523731522022367600144040ustar00rootroot00000000000000# Japanese translations for solaar package # Copyright (C) 2021 SOLAAR'S COPYRIGHT HOLDER # This file is distributed under the same license as the Solaar package. # msgid "" msgstr "Project-Id-Version: solaar 1.0.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2021-09-24 00:25+0900\n" "Last-Translator: Ryunosuke Toda \n" "Language-Team: \n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.0\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "Unifying レシー�ー" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "Nano レシー�ー" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "Lightspeed レシー�ー" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 レシー�ー 27 Mhz" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "空" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "���" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "低" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "中" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "良好" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "満充電" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "低下" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "�充電中" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "充電中" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "充電�����ん" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "��満充電" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "充電完了" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "低速充電" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "�ッテリー�正" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "温度エラー" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "エラー" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "標準" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "高速" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "低速" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "デ�イス応答��" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "�対応�デ�イス" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "デ�イス数超�" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "シーケンス応答��" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Other" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "左ボタン" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "�ボタン" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "中ボタン" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "戻るボタン" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "進むボタン" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "マウスジェス�ャーボタン" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "SmartShift" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "DPIスイッ�" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "左�ルト" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "��ルト" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "左クリック" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "�クリック" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "マウス中ボタン" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "マウス戻るボタン" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "マウス進むボタン" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "ペアリング試行終了" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "ペアリング試行開始" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "接続" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "切断" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "ペアリング解除" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "電�オン" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "ファンクションキー動作を入替" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "オン��る��F1〜F12をカスタマイズキー���使用���。\n" "標準�ファンクションキー���使用�る���fnキーを押���ら�作�" "��。" #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "オフ��る��F1〜F12を標準�ファンクションキー���使用���。\n" "カスタマイズキー���使用�る���fnキーを押���ら�作���。" #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "手�検出" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "手�キーボード�上��る��照明をオン����。" #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "ホイール縦スクロール高感度モード。" #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "サイドスクロール" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "" #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "マウス�動��感度" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "�ックライト" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "�ックライト�ON/OFFを切り替���。" #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "高解�度スクロールホイール" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "スクロールホイール迂回" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "ホイール�スクロール方�" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "ホイール��縦スクロール方�を逆����。" #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "ホイール�スクロール解�度" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "感度(�インタ速度)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "マウス速度��率(256�標準)。" #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "サムホイール�方�" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "サムホイール�スクロール方�を�転���。" #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "�ーリングレート(ミリ秒)" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "クラウンをルール�迂回" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Crown�CROWNHID++通知を�信����(Solaarルールをトリガー�����" "�れ以外�場��無視�れ��)。" #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "キー/ボタン動作" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "キーやボタン�動作を変更���。" #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "���アクション(マウス�左ボタン��)を変更�る��システム�使用" "�����る�能性��り��。" #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "キー/ボタンをルール�迂回" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "迂回�る" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "マウスジェス�ャー" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "通常通り" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "感度(DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "オフ" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "無効キー" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "特定�キーを無効����。" #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "キー %s を無効��る。" #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "OS設定" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "OS�����キー�変更���。" #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "ホスト変更" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "接続を他�ホスト�切り替���" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "" #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "" #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "" #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "タップ�よ�エッジジェス�ャを無効����(Fn + LeftClickを押���" "�等)。" #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "タップ�エッジジェス�ャー�無効化" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "" #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "" #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "" #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "カーソル速度を設定���。" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "幅" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "高�" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "" #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "カーソル速度。" #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "ジェス�ャー" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "マウス/タッ�パッド�動作を微調整���。" #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "ジェス�ャーパラメータ" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "マウス/タッ�パッド�数値パラメータを変更���。" #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "ペアリング�れ�デ�イス��り��ん。" #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s デ�イス�ペアリング�れ����。" #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "�ッテリー残�: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "�ッテリー残�: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "照明: %(level)s ルクス" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "�ッテリー残�: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "�ッテリー残�: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "権�エラー" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "デ�イス�接続����ん" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "%s � Logitech �レシー�ー���デ�イス�見��り�����接続中�" "エラー�発生����。" #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "ペアリング解除失敗" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "%{receiver} �ら� %{device} �ペアリング解除�失敗����。" #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "レシー�ー��れ以上�詳細���エラーを返����。" #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "Logitech�レシー�ー�キーボード�\n" "マウス�タブレットを管�。" #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "追加�プログラミング" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "GUIデザイン" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "テスト" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "ペアリング解除" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "キャンセル" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "変更を許��る" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "変更を許����" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "��設定を無視�る" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "処�中" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "読����書込処��失敗����。" #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "組�込��ルール" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "ユーザー定義�ルール" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "ルール" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "サブルール" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[空]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Solaarルールエディタ" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "変更を�存����?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "��" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "���" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "[���]を�択�る��Solaarを閉�る���変更�失�れ��。" #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "�存" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "変更を破棄" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "���挿入" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "上�挿入" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "下�挿入" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "新��ルールを���挿入" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "新��ルールを上�挿入" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "新��ルールを下�挿入" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "���貼り付�" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "上�貼り付�" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "下�貼り付�" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "���ルールを貼り付�" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "上�ルールを貼り付�" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "下�ルールを貼り付�" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "ルールを貼り付�" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "フラット化" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "挿入" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "�れ�" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "���" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "状態" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "機能" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "通知" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "プロセス" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "修飾キー" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "キー" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "有効" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "評価" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "マウスジェス�ャー" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "アクション" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "キー押下" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "マウススクロール" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "マウスクリック" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "実行" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "新��ルールを挿入" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "削除" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "�" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "次�覆�" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "切り�り" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "貼り付�" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "コピー" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "��エディタ���択��ルールコン�ー�ントを��サ�ート�����" "ん。" #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "" #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "�" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "マウスプロセス" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "押�" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "離�" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "キー追加" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "ボタン" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "引数を追加" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "値" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "未接続" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: 新��デ�イスをペアリング" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "" #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "ペアリング失敗" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "デ�イス�範囲内��り��切��ッテリー充電�行�れ��る��を確�" "������。" #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "新��デ�イス�検出�れ�������レシー�ー�互�性��り��" "ん。" #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "レシー�ー�サ�ートより多�ペアリング�れ�デ�イス。" #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "エラー�関�る�れ以上�詳細��り��ん。" #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "新��デ�イス�見��り���:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "��無線通信�暗�化�れ����ん" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "ペアリング���デ�イス�電�を入れ�下��。" #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "デ�イス�電��既�オン�����る場��オフ����らも�一度オン" "����。" #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "��レシー�ー��� %d デ�イス�ペアリング����。" #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "" #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "%s����" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "%sを終了" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "レシー�ー��" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "ステータス��" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "スキャン中" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "�ッテリー" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "無線通信" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "照明" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "技術的�詳細を表示" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "デ�イス�追加" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "デ�イスを�択��下��" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "ルールエディタ" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Path" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Serial" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "Wireless PID" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "Product ID" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protocol" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Unknown" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Polling rate" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "Unit ID" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "none" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Notifications" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "ペアリング�れ�デ�イス��り��ん。" #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "��レシー�ー�最大 %(max_count)s デ�イス�ペアリング���" "�。" #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "��レシー�ー�1��デ�イス���ペアリング����。" #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "��レシー�ー��� %d デ�イス�ペアリング����。" #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "�ッテリー電圧" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "�ッテリー�ら報告�れ�電圧" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "�ッテリー残�" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "�ッテリー�ら報告�れ���よ��残�" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "〜 " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " � 次�報告�れる残�。" #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "最後��識�れ�値" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "暗�化�り" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "��デ�イス�レシー�ー間�通信�暗�化�れ����。" #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "暗�化��" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d ルクス" #~ msgid "Add action" #~ msgstr "�作追加" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the button down." #~ msgstr "ボタンを押����マウスを横�動�����感度(DPI)を調整��" #~ "�。" #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "マウスホイール�ラ�ェットモード�フリースピンモードを自動的" #~ "�切り替���。\n" #~ "0�常�フリー�50�常�ラ�ェットモード��り��" #~ msgid "Battery information unknown." #~ msgstr "�ッテリー情報��明��。" #~ msgid "Count" #~ msgstr "回数" #~ msgid "DPI Sliding Adjustment" #~ msgstr "DPIスライディング調整" #~ msgid "ERROR: " #~ msgstr "エラー: " #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "事実上�Linux�サムスクロールをオフ����。" #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "事実上Linux��ホイールスクロールを無効����。" #~ msgid "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "詳細������下記よりSolaar�インストール手順を�照���" #~ "���\n" #~ "https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Logitechレシー�ー (%s) �見��り�����開�権���り�" #~ "�ん���。" #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "ホイール��HID++モード縦スクロール。" #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Solaarをインストール����り�場���レシー�ーを�り外�" #~ "����接続��������。" #~ msgid "Make the key or button send HID++ notifications (which " #~ "trigger Solaar rules but are otherwise ignored)." #~ msgstr "キー���ボタン�HID ++通知を�信����(Solaarルールをト" #~ "リガー������れ以外�場��無視�れ��)。" #~ msgid "No Logitech receiver found" #~ msgstr "Logitechレシー�ー�見��り��ん" #~ msgid "Scroll Wheel HID++ Scrolling" #~ msgstr "HID++スクロールホイール" #~ msgid "Scroll Wheel Rachet" #~ msgstr "スクロールホイールラ�ェット" #~ msgid "Send a gesture by sliding the mouse while holding the button " #~ "down." #~ msgstr "ボタンを押����マウスをスライド��る���任��ジェス" #~ "�ャーを�信���。" #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar�存在���udevファイル��存�����" #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "��デ�イス�レシー�ー間�無線通信�暗�化�れ����" #~ "ん。\n" #~ "\n" #~ "�インティングデ�イス(マウス�トラックボール�トラックパッド)�場" #~ "���大���り��ん�セキュリティ��題��り��。\n" #~ "\n" #~ "テキスト入力デ�イス(キーボード�テンキー)�場�����セキュリ" #~ "ティ��題��り��。\n" #~ "入力��文字��範囲内�第三者�よ��盗��れる�能性��り��。" #~ msgid "Try removing the device and plugging it back in or turning " #~ "it off and then on." #~ msgstr "デ�イスを�り外���度接続�る��電�をオフ����らオン" #~ "���������。" #~ msgid "height" #~ msgstr "高�" #~ msgid "unknown" #~ msgstr "�明" #~ msgid "width" #~ msgstr "幅" Solaar-1.1.20/po/ka.po000066400000000000000000002471721522022367600144070ustar00rootroot00000000000000# translation of solaar to Georgian # Copyright (C) 2026 solaar's authors # This file is distributed under the same license as the solaar package. # Ekaterine Papava , 2026. # msgid "" msgstr "" "Project-Id-Version: solaar 1.1.17rc3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-12-01 21:43+0300\n" "PO-Revision-Date: 2026-01-07 16:55+0100\n" "Last-Translator: Ekaterine Papava \n" "Language-Team: Georgian <(nothing)>\n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.8\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Bolt მიმღები" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Unifying მიმღები" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Nano მიმღები" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Lightspeed მიმღები" #: lib/logitech_receiver/base_usb.py:135 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 მიმღები 27 მჰც" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "ელემენტი: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "ელემენტი: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1048 #: lib/logitech_receiver/settings_templates.py:299 msgid "Disabled" msgstr "გ�მ�რთული�" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Static" msgstr "სტ�ტიკური" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Pulse" msgstr "პულსი" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Cycle" msgstr "ციკლი" #: lib/logitech_receiver/hidpp20.py:1052 msgid "Boot" msgstr "ჩ�ტვირთვ�" #: lib/logitech_receiver/hidpp20.py:1053 msgid "Demo" msgstr "დემ�" #: lib/logitech_receiver/hidpp20.py:1055 msgid "Breathe" msgstr "სუნთქვ�" #: lib/logitech_receiver/hidpp20.py:1058 msgid "Ripple" msgstr "ჭ�ვლი" #: lib/logitech_receiver/hidpp20.py:1059 msgid "Decomposition" msgstr "დ�შლ�" #: lib/logitech_receiver/hidpp20.py:1060 msgid "Signature1" msgstr "ხელმ�წერ�1" #: lib/logitech_receiver/hidpp20.py:1061 msgid "Signature2" msgstr "ხელმ�წერ�2" #: lib/logitech_receiver/hidpp20.py:1062 msgid "CycleS" msgstr "ციკლები" #: lib/logitech_receiver/hidpp20.py:1126 msgid "Unknown Location" msgstr "უცნ�ბი მდებ�რე�ბ�" #: lib/logitech_receiver/hidpp20.py:1127 msgid "Primary" msgstr "ძირით�დი" #: lib/logitech_receiver/hidpp20.py:1128 msgid "Logo" msgstr "ლ�გ�" #: lib/logitech_receiver/hidpp20.py:1129 msgid "Left Side" msgstr "მ�რცხენ� მხ�რე" #: lib/logitech_receiver/hidpp20.py:1130 msgid "Right Side" msgstr "მ�რჯვენ� მხ�რე" #: lib/logitech_receiver/hidpp20.py:1131 msgid "Combined" msgstr "კ�მბინირებული" #: lib/logitech_receiver/hidpp20.py:1132 msgid "Primary 1" msgstr "ძირით�დი 1" #: lib/logitech_receiver/hidpp20.py:1133 msgid "Primary 2" msgstr "ძირით�დი 2" #: lib/logitech_receiver/hidpp20.py:1134 msgid "Primary 3" msgstr "ძირით�დი 3" #: lib/logitech_receiver/hidpp20.py:1135 msgid "Primary 4" msgstr "ძირით�დი 4" #: lib/logitech_receiver/hidpp20.py:1136 msgid "Primary 5" msgstr "ძირით�დი 5" #: lib/logitech_receiver/hidpp20.py:1137 msgid "Primary 6" msgstr "ძირით�დი 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "ც�რიელი�" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "კრიტიკული" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "დ�ბ�ლი" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "ს�შუ�ლ�" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "კ�რგი" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "მთლი�ნი" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "იცლებ�" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "თ�ვიდ�ნ დ�ტენვ�" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "იტენებ�" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "�რ იტენებ�" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "თითქმის ს�ვსე�" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "დ�მუხტული" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "ნელი თ�ვიდ�ნ დ�ტენვ�" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "�რ�სწ�რი ელემენტი" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "თერმ�ლის შეცდ�მ�" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "შეცდ�მ�" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "სტ�ნდ�რტული" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "სწრ�ფი" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "ნელი" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "მ�წყ�ბილ�ბის მ�ლ�დინის დრ� �მ�იწურ�" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "მ�წყ�ბილ�ბ� მხ�რდ�ჭერილი �რ��" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "მეტისმეტ�დ ბევრი მ�წყ�ბილ�ბ�" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "მიმდევრ�ბის მ�ლ�დინის ვ�დ� �მ�იწურ�" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "მიკრ�კ�დი" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "ჩ�მტვირთ�ვი" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "�პ�რ�ტურ�" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "სხვ�" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "მ�რცხენ� ღილ�კი" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "მ�რჯვენ� ღილ�კი" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "შუ� ღილ�კი" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "ღილ�კი უკ�ნ" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "ღილ�კი წინ" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "თ�გუნ�ს ჟესტის ღილ�კი" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "ჭკვი�ნი გ�დ�სვლ�" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "DPI გ�დ�მრთველი" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "მ�რცხნივ დ�ხრ�" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "მ�რჯვნივ დ�ხრ�" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "მ�რცხენ�-წკ�პი" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "მ�რჯვენ�-წკ�პი" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "თ�გუნ�ს შუ� ღილ�კი" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "თ�გუნ�ს ღილ�კი 'უკ�ნ'" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "თ�გუნ�ს ღილ�კი 'წუნ'" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "ნ�ვიგ�ცი� ჟესტის ღილ�კით" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "თ�გუნ�ს მ�რცხნივ გ�დ�ხვევის ღილ�კი" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "თ�გუნ�ს მ�რჯვნივ გ�დ�ხვევის ღილ�კი" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "დ�წ�ლილი" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "�შვებული�" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "დ�კ�ვშირებული�" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "გ�თიშული�" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "დ�უწყვილებელი�" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "ჩ�რთული�" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "ADC გ�ზ�მვის გ�ფრთხილებ�" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is closed" msgstr "დ�წყვილებ� დ�ბლ�კილი�" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is open" msgstr "დ�წყვილებ� ჩ�რთული�" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is closed" msgstr "�ღმ�ჩენ� დ�ბლ�კილი�" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is open" msgstr "�ღმ�ჩენ� ჩ�რთული�" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "შეწყვილებული მ�წყ�ბილ�ბების გ�რეშე." #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s დ�წყვილებული მ�წყ�ბილ�ბ�." msgstr[1] "%(count)s დ�წყვილებული მ�წყ�ბილ�ბ�." #: lib/logitech_receiver/settings.py:602 msgid "register" msgstr "რეგისტრ�ცი�" #: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654 msgid "feature" msgstr "თვისებ�" #: lib/logitech_receiver/settings_templates.py:138 msgid "Swap Fx function" msgstr "Fx-ის ფუნქციის გ�ცვლ�" #: lib/logitech_receiver/settings_templates.py:141 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "რ�ც� დ�ყენებული�, ღილ�კები F1..F12 თ�ვი�ნთ სპეცი�ლურ ფუნქცი�ს გ���ქტიურებენ\n" "დ� თქვენ უნდ� გეჭირ�თ FN ღილ�კზე, რ�მ მ�თი სტ�ნდ�რტული ფუნქცი� გ���ქტიურ�თ." #: lib/logitech_receiver/settings_templates.py:146 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "რ�ც� დ�ყენებული�, ღილ�კები F1..F12 თ�ვი�ნთ სტ�ნდ�რტული ფუნქცი�ს " "გ���ქტიურებენ\n" "დ� თქვენ უნდ� გეჭირ�თ FN ღილ�კზე, რ�მ მ�თი სპეცი�ლურ ფუნქცი� გ���ქტიურ�თ." #: lib/logitech_receiver/settings_templates.py:154 msgid "Hand Detection" msgstr "ხელის �მ�ცნ�ბ�" #: lib/logitech_receiver/settings_templates.py:155 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "ილუმინ�ციის ჩ�რთვ�, რ�ც� ხელებს კლ�ვი�ტურ�ზე გ��ჩერებთ." #: lib/logitech_receiver/settings_templates.py:162 msgid "Scroll Wheel Smooth Scrolling" msgstr "გლუვი გ�დ�ხვევ� თ�გუნ�ს ბ�რბლით" #: lib/logitech_receiver/settings_templates.py:163 #: lib/logitech_receiver/settings_templates.py:410 #: lib/logitech_receiver/settings_templates.py:439 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "მ�ღ�ლი მგრძნ�ბელ�ბის რეჟიმი ბ�რბლით ვერტიკ�ლური გ�დ�ხვევისთვის." #: lib/logitech_receiver/settings_templates.py:170 msgid "Side Scrolling" msgstr "გვერდზე გ�დ�ხვევ�" #: lib/logitech_receiver/settings_templates.py:172 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "რ�ც� გ�მ�რთული�, ბ�რბლის გვერდზე დ�ჭერ� მ�მხმ�რებლის ღილ�კის მ�ვლენებს\n" "�გზ�ვნის სტ�ნდ�რტული გვერდზე გ�დ�ხვევის მ�ვლენების მ�გიერ." #: lib/logitech_receiver/settings_templates.py:182 msgid "Sensitivity (DPI - older mice)" msgstr "მგრძნ�ბელ�ბ� (DPI - ძველი თ�გუნები)" #: lib/logitech_receiver/settings_templates.py:183 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 msgid "Mouse movement sensitivity" msgstr "თ�გუნ�ს მ�ძრ��ბის მგრძნ�ბელ�ბ�" #: lib/logitech_receiver/settings_templates.py:256 msgid "Backlight Timed" msgstr "შენ�თების დრ�" #: lib/logitech_receiver/settings_templates.py:257 #: lib/logitech_receiver/settings_templates.py:397 msgid "Set illumination time for keyboard." msgstr "გ�ნ�თების დრ�ის დ�ყენებ� კლ�ვი�ტურისთვის." #: lib/logitech_receiver/settings_templates.py:268 msgid "Backlight" msgstr "შენ�თებ�" #: lib/logitech_receiver/settings_templates.py:269 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "გ�ნ�თების დ�ნე კლ�ვი�ტურ�ზე. ცვლილებები ძ�ლ�ში, მხ�ლ�დ, 'ხელით' რეჟიმში " "შედის." #: lib/logitech_receiver/settings_templates.py:301 msgid "Automatic" msgstr "�ვტ�მ�ტური" #: lib/logitech_receiver/settings_templates.py:303 msgid "Manual" msgstr "ხელით" #: lib/logitech_receiver/settings_templates.py:305 msgid "Enabled" msgstr "ჩ�რთული�" #: lib/logitech_receiver/settings_templates.py:311 msgid "Backlight Level" msgstr "შენ�თების დ�ნე" #: lib/logitech_receiver/settings_templates.py:312 msgid "Illumination level on keyboard when in Manual mode." msgstr "გ�ნ�თების დ�ნე კლ�ვი�ტურ�ზე რეჟიმში 'ხელით'." #: lib/logitech_receiver/settings_templates.py:369 msgid "Backlight Delay Hands Out" msgstr "შენ�თების დ�ყ�ვნებ� ხელების გ�წევის�ს" #: lib/logitech_receiver/settings_templates.py:370 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "დ�ყ�ვნებ� წ�მებში, ს�ნ�მ მ�ხდებ� შენ�თების მინ�ვლებ�, რ�ც� ხელებს " "კლ�ვი�ტურიდ�ნ შ�რს წ�იღებთ." #: lib/logitech_receiver/settings_templates.py:378 msgid "Backlight Delay Hands In" msgstr "შენ�თების დ�ყ�ვნებ� ხელების მი�ხლ�ების�ს" #: lib/logitech_receiver/settings_templates.py:379 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "დ�ყ�ვნებ� წ�მებში, ს�ნ�მ მ�ხდებ� შენ�თების გ�მ�ჩენ�, რ�ც� ხელებს " "კლ�ვი�ტურ�სთ�ნ მიიტ�ნთ." #: lib/logitech_receiver/settings_templates.py:387 msgid "Backlight Delay Powered" msgstr "შენ�თების ჩ�რთვის დ�ყ�ვნებ�" #: lib/logitech_receiver/settings_templates.py:388 msgid "Delay in seconds until backlight fades out with external power." msgstr "დ�ყ�ვნებ� წ�მებში, ს�ნ�მ მ�ხდებ� შენ�თების მინ�ვლებ� გ�რე კვებით." #: lib/logitech_receiver/settings_templates.py:396 msgid "Backlight (Seconds)" msgstr "შენ�თებ� (წმ)" #: lib/logitech_receiver/settings_templates.py:408 msgid "Scroll Wheel High Resolution" msgstr "გ�დ�ხვევის ბ�რბლის მ�ღ�ლი გ�რჩევ�დ�ბ�" #: lib/logitech_receiver/settings_templates.py:412 #: lib/logitech_receiver/settings_templates.py:441 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "დ��ყენეთ დ�იგნ�რებ�ზე, თუ გ�დ�ხვევ� �რ�ნ�რმ�ლურ�დ სწრ�ფი, �ნ ნელი�" #: lib/logitech_receiver/settings_templates.py:419 #: lib/logitech_receiver/settings_templates.py:450 msgid "Scroll Wheel Diversion" msgstr "გ�დ�ხვევის ბ�რბლის ქცევ�" #: lib/logitech_receiver/settings_templates.py:421 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "ბ�რბლისთვის LOWRES_WHEEL HID++ გ�ფრთხილების გ�გზ�ვნის იძულებ� (რ�მელიც " "გ�უშვებს Solaar-ის წესებს, მ�გრ�მ სხვ�გვ�რ�დ ყურ�დღებ�ს �რ�ფერი �ქცევს)." #: lib/logitech_receiver/settings_templates.py:428 msgid "Scroll Wheel Direction" msgstr "გ�დ�ხვევის ბ�რბლის მიმ�რთულებ�" #: lib/logitech_receiver/settings_templates.py:429 msgid "Invert direction for vertical scroll with wheel." msgstr "ბ�რბლით ვერტიკ�ლური გ�დ�ხვევის მიმ�რთულების ინვერსი�." #: lib/logitech_receiver/settings_templates.py:437 msgid "Scroll Wheel Resolution" msgstr "გ�დ�ხვევის ბ�რბლის გ�რჩევ�დ�ბ�" #: lib/logitech_receiver/settings_templates.py:452 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "ბ�რბლისთვის HIRES_WHEEL HID++ გ�ფრთხილების გ�გზ�ვნის იძულებ� (რ�მელიც " "გ�უშვებს Solaar-ის წესებს, მ�გრ�მ სხვ�გვ�რ�დ ყურ�დღებ�ს �რ�ფერი �ქცევს)." #: lib/logitech_receiver/settings_templates.py:461 msgid "Sensitivity (Pointer Speed)" msgstr "მგრძნ�ბელ�ბ� (მ�ჩვენებლის სიჩქ�რე)" #: lib/logitech_receiver/settings_templates.py:462 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "სიჩქ�რის მ�მრ�ვლი თ�გუნ�სთვის (256 ნ�რმ�ლური მ�მრ�ვლი�)." #: lib/logitech_receiver/settings_templates.py:472 msgid "Thumb Wheel Diversion" msgstr "ცერ� თითის ბ�რბლის ქცევ�" #: lib/logitech_receiver/settings_templates.py:474 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "ბ�რბლისთვის THUMB_WHEEL HID++ გ�ფრთხილების გ�გზ�ვნის იძულებ� (რ�მელიც " "გ�უშვებს Solaar-ის წესებს, მ�გრ�მ სხვ�გვ�რ�დ ყურ�დღებ�ს �რ�ფერი �ქცევს)." #: lib/logitech_receiver/settings_templates.py:483 msgid "Thumb Wheel Direction" msgstr "ცერ� თითის ბ�რბლის მიმ�რთულებ�" #: lib/logitech_receiver/settings_templates.py:484 msgid "Invert thumb wheel scroll direction." msgstr "ცერ� თითის ბ�რბლით გ�დ�ხვევის მიმ�რთულების ინვერსი�." #: lib/logitech_receiver/settings_templates.py:504 msgid "Onboard Profiles" msgstr "ჩ�შენებული პრ�ფილები" #: lib/logitech_receiver/settings_templates.py:505 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "ჩ�შენებული პრ�ფილის ჩ�რთვ�, რ�მელიც მ�რთ�ვს �ნგ�რიშების სიხშირეს, " "მგრძნ�ბელ�ბ�ს დ� ღილ�კის ქმედებებს" #: lib/logitech_receiver/settings_templates.py:549 #: lib/logitech_receiver/settings_templates.py:582 msgid "Report Rate" msgstr "�ნგ�რიშის სიხშირე" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 msgid "Frequency of device movement reports" msgstr "მ�წყ�ბილ�ბის მ�ძრ��ბის �ნგ�რიშების სიხშირე" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1421 #: lib/logitech_receiver/settings_templates.py:1452 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "იმის�თვის, რ�მ ეფექტური იყ�ს, შეიძლებ�, ჩ�შენებული პრ�ფილების გ�მ�რთვ� " "დ�სჭირდეს." #: lib/logitech_receiver/settings_templates.py:612 msgid "Divert crown events" msgstr "ვენიერის ქცევ�" #: lib/logitech_receiver/settings_templates.py:613 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "ვერნიერისთვის CROWN WHEEL HID++ გ�ფრთხილების გ�გზ�ვნის იძულებ� (რ�მელიც " "გ�უშვებს Solaar-ის წესებს, მ�გრ�მ სხვ�გვ�რ�დ ყურ�დღებ�ს �რ�ფერი �ქცევს)." #: lib/logitech_receiver/settings_templates.py:621 msgid "Crown smooth scroll" msgstr "ვენიერის გლუვი გ�დ�ხვევ�" #: lib/logitech_receiver/settings_templates.py:622 msgid "Set crown smooth scroll" msgstr "ვენიერის გლუვი გ�დ�ხვევის დ�ყენებ�" #: lib/logitech_receiver/settings_templates.py:630 msgid "Divert G and M Keys" msgstr "G დ� M ღილ�კების გ�დ�მის�მ�რთებ�" #: lib/logitech_receiver/settings_templates.py:631 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "G დ� M ღილ�კებისთვის WHEEL HID++ გ�ფრთხილების გ�გზ�ვნის იძულებ� (რ�მელიც " "გ�უშვებს Solaar-ის წესებს, მ�გრ�მ სხვ�გვ�რ�დ ყურ�დღებ�ს �რ�ფერი �ქცევს)." #: lib/logitech_receiver/settings_templates.py:645 msgid "Scroll Wheel Ratcheted" msgstr "ხრუტუნ� მექ�ნიზმით გ�დ�ხვევის ბ�რბ�ლი" #: lib/logitech_receiver/settings_templates.py:646 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "თ�გუნ�ს ბ�რბლის გ�დ�რთვ� სიჩქ�რით მ�რთულ ხრუტუნ� მექ�ნიზმს� დ� ყ�ველთვის " "თ�ვისუფ�ლ ტრი�ლს შ�რის." #: lib/logitech_receiver/settings_templates.py:648 msgid "Freespinning" msgstr "თ�ვისუფ�ლი ბრუნვ�" #: lib/logitech_receiver/settings_templates.py:648 msgid "Ratcheted" msgstr "ბრუნვ� ხრუტუნ� მექ�ნიზმით" #: lib/logitech_receiver/settings_templates.py:655 msgid "Scroll Wheel Ratchet Speed" msgstr "თ�გუნ�ს ბ�რბლის ტრი�ლის სიჩქ�რე" #: lib/logitech_receiver/settings_templates.py:657 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "თ�გუნ�ს ბ�რბლის სიჩქ�რის გ�მ�ყენებ� ხრუტუნ� მექ�ნიზმს� დ� თ�ვისუფლ�დ ტრი�ლს " "შ�რის გ�დ�ს�რთ�ვ�დ.\n" "თ�გუნ�ს ბ�რბლის ხრუტუნ� მექ�ნიზმის სიჩქ�რე ყ�ველთვის 50-ს უდრის." #: lib/logitech_receiver/settings_templates.py:707 msgid "Scroll Wheel Ratchet Torque" msgstr "ხრუტუნ� ბ�რბლით გ�დ�ხვევის მ�ჭიდებ�" #: lib/logitech_receiver/settings_templates.py:708 msgid "Change the torque needed to overcome the ratchet." msgstr "ხრუტუნ� ბ�რბლის გ�დ�ს�ფ�რ�დ მ�ჭიდების შეცვლ�� ს�წირ�." #: lib/logitech_receiver/settings_templates.py:743 msgid "Key/Button Actions" msgstr "ღილ�კის ქმედებები" #: lib/logitech_receiver/settings_templates.py:745 msgid "Change the action for the key or button." msgstr "ქმედების შეცვლ� ღილ�კისთვის." #: lib/logitech_receiver/settings_templates.py:747 msgid "Overridden by diversion." msgstr "გ�დ�ფ�რული� გ�დ�მის�მ�რტებით." #: lib/logitech_receiver/settings_templates.py:749 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "მნიშვნელ�ვ�ნი ქმედებების შეცვლ�მ (მ�გ: მ�რცხენ� თ�გუნ�ს ღილ�კისთვის), " "შეიძლებ�, სისტემის �რ�სტ�ბილურ�ბ�მდე მიგიყვ�ნ�თ." #: lib/logitech_receiver/settings_templates.py:924 msgid "Key/Button Diversion" msgstr "ღილ�კის გ�დ�მის�მ�რთებ�" #: lib/logitech_receiver/settings_templates.py:925 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "ღილ�კისთვის იძულებ�, HD++ გ�ფრთხილებები გ��გზ�ვნ�ს (გ�დ�მის�მ�რთებული) �ნ " "მ��ხდინ�ს თ�გუნ�ს ჟესტების ინიცი�ცი�, �ნ სრი�ლ� DPI-ის" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Diverted" msgstr "გ�დ�მის�მ�რთებული�" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 msgid "Mouse Gestures" msgstr "თ�გუნ�ს ჟესტები" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Regular" msgstr "ჩვეულებრივი" #: lib/logitech_receiver/settings_templates.py:928 msgid "Sliding DPI" msgstr "მცურ�ვი DPI" #: lib/logitech_receiver/settings_templates.py:1018 #: lib/logitech_receiver/settings_templates.py:1046 msgid "Sensitivity (DPI)" msgstr "მგრძნ�ბელ�ბ� (DPI)" #: lib/logitech_receiver/settings_templates.py:1123 msgid "Sensitivity Switching" msgstr "მგრძნ�ბელ�ბის გ�დ�რთვ�" #: lib/logitech_receiver/settings_templates.py:1125 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "მიმდინ�რე მგრძნ�ბელ�ბ�ს� დ� დ�მ�ხს�ვრებულ მგრძნ�ბელ�ბ�ს შ�რის გ�დ�რთვ�, რ�ც� " "ღილ�კს დ��წვებით.\n" "თუ დ�მ�ხს�ვრებული მგრძნ�ბელ�ბ� �რ �რსებ�ბს, მ�ხდებ� მიმდინ�რე მგრძნ�ბელ�ბის " "დ�მ�ხს�ვრებ�" #: lib/logitech_receiver/settings_templates.py:1129 msgid "Off" msgstr "გ�მ�რთ" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Disable keys" msgstr "ღილ�კების გ�თიშვ�" #: lib/logitech_receiver/settings_templates.py:1161 msgid "Disable specific keyboard keys." msgstr "მითითებული კლ�ვი�ტურის ღილ�კების გ�მ�რთვ�." #: lib/logitech_receiver/settings_templates.py:1164 #, python-format msgid "Disables the %s key." msgstr "გ�მ�რთ�ვს ღილ�კს %s." #: lib/logitech_receiver/settings_templates.py:1177 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Set OS" msgstr "�პერ�ციული სისტემ�" #: lib/logitech_receiver/settings_templates.py:1178 #: lib/logitech_receiver/settings_templates.py:1235 msgid "Change keys to match OS." msgstr "ღილ�კების შეცვლ� �ს-თ�ნ შეს�ბ�მის�დ." #: lib/logitech_receiver/settings_templates.py:1247 msgid "Change Host" msgstr "ჰ�სტის შეცვლ�" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Switch connection to a different host" msgstr "კ�ვშირის გ�დ�რთვ� სხვ� ჰ�სტზე" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Performs a left click." msgstr "შე�სრულებს მ�რცხენ� წკ�პს." #: lib/logitech_receiver/settings_templates.py:1272 msgid "Single tap" msgstr "ერთი ტყ�პი" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Performs a right click." msgstr "შე�სრულებს მ�რჯვენ� წკ�პს." #: lib/logitech_receiver/settings_templates.py:1273 msgid "Single tap with two fingers" msgstr "ერთი ტყ�პი �რი თითით" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Single tap with three fingers" msgstr "ერთი ტყ�პი ს�მი თითით" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Double tap" msgstr "�რმ�გი ტყ�პი" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Performs a double click." msgstr "შე�სრულებს �რმ�გ წკ�პს." #: lib/logitech_receiver/settings_templates.py:1279 msgid "Double tap with two fingers" msgstr "�რმ�გი ტყ�პი �რი თითით" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Double tap with three fingers" msgstr "�რმ�გი ტყ�პი ს�მი თითით" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Drags items by dragging the finger after double tapping." msgstr "ელემენტების გ�დ�თრევ� თითის გ�წევით �რი ტყ�პის შემდეგ." #: lib/logitech_receiver/settings_templates.py:1283 msgid "Tap and drag" msgstr "დ�ტყ�პუნებ� დ� გ�დ�თრევ�" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Tap and drag with two fingers" msgstr "დ�ტყ�პუნებ� დ� გ�დ�თრევ� �რი თითით" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Drags items by dragging the fingers after double tapping." msgstr "გ�დ��თრიეთ ელემენტები თითების გ�დ�თრევით �რმ�გი დ�ტყ�პუნების შემდეგ." #: lib/logitech_receiver/settings_templates.py:1288 msgid "Tap and drag with three fingers" msgstr "დ�ტყ�პუნებ� დ� გ�დ�თრევ� ს�მი თითით" #: lib/logitech_receiver/settings_templates.py:1291 msgid "Suppress tap and edge gestures" msgstr "ტყ�პუნის დ� წიბ�ს ჟესტების ჩ�ხშ�ბ�" #: lib/logitech_receiver/settings_templates.py:1292 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "გ�მ�რთ�ვს დ�ტყ�პუნების დ� წიბ�ს ჟესტებს (იგივე�, რ�ც Fn+მ�რცხენ�წკ�პი)." #: lib/logitech_receiver/settings_templates.py:1294 msgid "Scroll with one finger" msgstr "გ�დ�ხვევ� ერთი თითით" #: lib/logitech_receiver/settings_templates.py:1294 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scrolls." msgstr "ვერტიკ�ლური გ�დ�ხვევ�." #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scroll with two fingers" msgstr "გ�დ�ხვევ� �რი თითით" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scroll horizontally with two fingers" msgstr "ჰ�რიზ�ნტ�ლური გ�დ�ხვევ� �რი თითით" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scrolls horizontally." msgstr "ჰ�რიზ�ნტ�ლური გ�დ�ხვევ�." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scroll vertically with two fingers" msgstr "ვერტიკ�ლური გ�დ�ხვევ� �რი თითით" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scrolls vertically." msgstr "ვერტიკ�ლური გ�დ�ხვევ�." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Inverts the scrolling direction." msgstr "გ�დ�ხვევის მიმ�რთულების ინვერსი�." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Natural scrolling" msgstr "ჩვეულებრივი გ�დ�ხვევ�" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Enables the thumbwheel." msgstr "ჩ�რთ�ვს ცერ� თითის ბ�რბ�ლს." #: lib/logitech_receiver/settings_templates.py:1300 msgid "Thumbwheel" msgstr "ცერ� თითის ბ�რბ�ლი" #: lib/logitech_receiver/settings_templates.py:1311 #: lib/logitech_receiver/settings_templates.py:1315 msgid "Swipe from the top edge" msgstr "გ�სმ� ზედ� წიბ�დ�ნ" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Swipe from the left edge" msgstr "გ�სმ� მ�რცხენ� წიბ�დ�ნ" #: lib/logitech_receiver/settings_templates.py:1313 msgid "Swipe from the right edge" msgstr "გ�სმ� მ�რჯვენ� წიბ�დ�ნ" #: lib/logitech_receiver/settings_templates.py:1314 msgid "Swipe from the bottom edge" msgstr "გ�სმ� ქვედ� წიბ�დ�ნ" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Swipe two fingers from the left edge" msgstr "�რი თითის გ�სმ� მ�რცხენ� წიბ�დ�ნ" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Swipe two fingers from the right edge" msgstr "�რი თითის გ�სმ� მ�რჯვენ� წიბ�დ�ნ" #: lib/logitech_receiver/settings_templates.py:1318 msgid "Swipe two fingers from the bottom edge" msgstr "�რი თითის გ�სმ� ქვედ� წიბ�დ�ნ" #: lib/logitech_receiver/settings_templates.py:1319 msgid "Swipe two fingers from the top edge" msgstr "�რი თითის გ�სმ� ზედ� წიბ�დ�ნ" #: lib/logitech_receiver/settings_templates.py:1320 #: lib/logitech_receiver/settings_templates.py:1324 msgid "Pinch to zoom out; spread to zoom in." msgstr "ჩქმეტ� დ�ს�პ�ტ�რ�ვებლ�დ. გ�წევ� გ�ს�დიდებლ�დ." #: lib/logitech_receiver/settings_templates.py:1320 msgid "Zoom with two fingers." msgstr "გ�დიდებ� �რი თითით." #: lib/logitech_receiver/settings_templates.py:1321 msgid "Pinch to zoom out." msgstr "ჩქმეტ� დ�ს�პ�ტ�რ�ვებლ�დ." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Spread to zoom in." msgstr "გ�დ�შლ� გ�ს�დიდებლ�დ." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Zoom with three fingers." msgstr "გ�დიდებ� ს�მი თითით." #: lib/logitech_receiver/settings_templates.py:1324 msgid "Zoom with two fingers" msgstr "გ�დიდებ� �რი თითით" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Pixel zone" msgstr "პიქსელების ზ�ნ�" #: lib/logitech_receiver/settings_templates.py:1343 msgid "Ratio zone" msgstr "ფ�რდ�ბის დ�ნე" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scale factor" msgstr "გ�დიდების კ�ეფიციენტი" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Sets the cursor speed." msgstr "�ყენებს კურს�რის სიჩქ�რეს." #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left" msgstr "მ�რცხენ�" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left-most coordinate." msgstr "ყველ�ზე მ�რცხენ� კ��რდინ�ტი." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom" msgstr "ქვემ�თ" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom coordinate." msgstr "ქვედ� კ��რდინ�ტი." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width" msgstr "სიგ�ნე" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width." msgstr "სიგ�ნე." #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height" msgstr "სიმ�ღლე" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height." msgstr "სიმ�ღლე." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Cursor speed." msgstr "კურს�რის სიჩქ�რე." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Scale" msgstr "მ�სშტ�ბი" #: lib/logitech_receiver/settings_templates.py:1358 msgid "Gestures" msgstr "ჟესტები" #: lib/logitech_receiver/settings_templates.py:1359 msgid "Tweak the mouse/touchpad behaviour." msgstr "თ�გუნ�ს/თ�ჩპედის ქცევის შეცვლ�." #: lib/logitech_receiver/settings_templates.py:1375 msgid "Gestures Diversion" msgstr "ჟესტების ქცევ�" #: lib/logitech_receiver/settings_templates.py:1376 msgid "Divert mouse/touchpad gestures." msgstr "თ�ჩპედის/თ�გუნ�ს ჟესტების მ�რგებ�." #: lib/logitech_receiver/settings_templates.py:1392 msgid "Gesture params" msgstr "ჟესტის პ�რ�მეტრები" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Change numerical parameters of a mouse/touchpad." msgstr "თ�გუნ�ს/თ�ჩპედის რიცხვითი პ�რ�მეტრების შეცვლ�." #: lib/logitech_receiver/settings_templates.py:1417 msgid "M-Key LEDs" msgstr "M-ღილ�კის LED-ები" #: lib/logitech_receiver/settings_templates.py:1419 msgid "Control the M-Key LEDs." msgstr "M-ღილ�კის LED-ების მ�რთვ�." #: lib/logitech_receiver/settings_templates.py:1423 #: lib/logitech_receiver/settings_templates.py:1454 msgid "May need G Keys diverted to be effective." msgstr "" "შეიძლებ�, იმის�თვის, რ�მ ეფექტური იყ�ს, G ღილ�კების გ�დ�მის�მ�რთებ� " "დ�გჭირდეთ." #: lib/logitech_receiver/settings_templates.py:1429 #, python-format msgid "Lights up the %s key." msgstr "��ნთებს ღილ�კს %s." #: lib/logitech_receiver/settings_templates.py:1448 msgid "MR-Key LED" msgstr "MR ღილ�კის LED" #: lib/logitech_receiver/settings_templates.py:1450 msgid "Control the MR-Key LED." msgstr "MR ღილ�კის LED-ის მ�რთვ�." #: lib/logitech_receiver/settings_templates.py:1471 msgid "Persistent Key/Button Mapping" msgstr "მუდმივი ღილ�კის �ს�ხვ�" #: lib/logitech_receiver/settings_templates.py:1473 msgid "Permanently change the mapping for the key or button." msgstr "ღილ�კის �ს�ხვის მუდმივ�დ შეცვლ�." #: lib/logitech_receiver/settings_templates.py:1475 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "მნიშვნელ�ვ�ნი ღილ�კების შეცვლ�მ (მ�გ: მ�რცხენ� თ�გუნ�ს ღილ�კისთვის), " "შეიძლებ�, სისტემის �რ�სტ�ბილურ�ბ�მდე მიგიყვ�ნ�თ." #: lib/logitech_receiver/settings_templates.py:1532 msgid "Sidetone" msgstr "თვითმ�სმენ�" #: lib/logitech_receiver/settings_templates.py:1533 msgid "Set sidetone level." msgstr "თვითმ�სმენის დ�ნის დ�ყენებ�." #: lib/logitech_receiver/settings_templates.py:1542 msgid "Equalizer" msgstr "ეკვ�ლ�იზერი" #: lib/logitech_receiver/settings_templates.py:1543 msgid "Set equalizer levels." msgstr "ეკვ�ლ�იზერის დ�ნეების დ�ყენებ�." #: lib/logitech_receiver/settings_templates.py:1565 msgid "Hz" msgstr "ჰც" #: lib/logitech_receiver/settings_templates.py:1571 msgid "Power Management" msgstr "კვების მ�რთვ�" #: lib/logitech_receiver/settings_templates.py:1572 msgid "Power off in minutes (0 for never)." msgstr "კვების გ�მ�რთვ� მითითებულ წუთში (0 ნიშნ�ვს '�რ�სდრ�ს')." #: lib/logitech_receiver/settings_templates.py:1584 msgid "Brightness Control" msgstr "სიკ�შკ�შის კ�ნტრ�ლი" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Control overall brightness" msgstr "ს�ერთ� სიკ�შკ�შის მ�რთვ�" #: lib/logitech_receiver/settings_templates.py:1628 #: lib/logitech_receiver/settings_templates.py:1681 msgid "LED Control" msgstr "LED-ების მ�რთვ�" #: lib/logitech_receiver/settings_templates.py:1629 #: lib/logitech_receiver/settings_templates.py:1682 msgid "Switch control of LED zones between device and Solaar" msgstr "LED-ის ზ�ნების კ�ნტრ�ლის გ�დ�რთვ� მ�წყ�ბილ�ბ�ს� დ� Solaar-ს შ�რის" #: lib/logitech_receiver/settings_templates.py:1644 #: lib/logitech_receiver/settings_templates.py:1692 msgid "LED Zone Effects" msgstr "LED-ის ზ�ნის ეფექტები" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "LED Control needs to be set to Solaar to be effective." msgstr "იმის�თვის, რ�მ ეფექტური იყ�ს, LED-ის მ�რთვ� Solaar-ზე უნდ� დ��ყენ�თ." #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "Set effect for LED Zone" msgstr "ეფექტის დ�ყენებ� LED ზ�ნისთვის" #: lib/logitech_receiver/settings_templates.py:1647 msgid "Color" msgstr "ფერი" #: lib/logitech_receiver/settings_templates.py:1648 msgid "Speed" msgstr "სიჩქ�რე" #: lib/logitech_receiver/settings_templates.py:1649 msgid "Period" msgstr "პერი�დი" #: lib/logitech_receiver/settings_templates.py:1650 msgid "Intensity" msgstr "ინტენსივ�ბ�" #: lib/logitech_receiver/settings_templates.py:1651 msgid "Ramp" msgstr "პ�ნდუსი" #: lib/logitech_receiver/settings_templates.py:1666 msgid "LEDs" msgstr "LED-ები" #: lib/logitech_receiver/settings_templates.py:1703 msgid "Per-key Lighting" msgstr "ინდივიდუ�ლური გ�ნ�თებ� ღილ�კებისთვის" #: lib/logitech_receiver/settings_templates.py:1704 msgid "Control per-key lighting." msgstr "ინდივიდუ�ლური გ�ნ�თების კ�ნტრ�ლი ღილ�კებისთვის." #: lib/logitech_receiver/settings_templates.py:1786 msgid "Force Sensing Buttons" msgstr "დ�ჭერის სენს�რის მქ�ნე ღილ�კები" #: lib/logitech_receiver/settings_templates.py:1787 msgid "Change the force required to activate button." msgstr "�ირჩიეთ ძ�ლ�, რ�მელიც ს�ჭირ�� ღილ�კის გ�ს��ქტიურებლ�დ." #: lib/logitech_receiver/settings_templates.py:1804 msgid "Force Sensing Button" msgstr "დ�ჭერის სენს�რის მქ�ნე ღილ�კი" #: lib/logitech_receiver/settings_templates.py:1814 msgid "Haptic Feeback Level" msgstr "ტ�ქტილური უკუკ�ვშირის დ�ნე" #: lib/logitech_receiver/settings_templates.py:1815 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "ტ�ქტილური უკუკ�ვშირის სიმძლ�ვრის შეცვლ�. (0 გ�მ�ს�რთ�ვ�დ.)" #: lib/logitech_receiver/settings_templates.py:1857 msgid "Play Haptic Waveform" msgstr "სიგნ�ლის ტ�ქტილური ფ�რმის დ�კვრ�" #: lib/logitech_receiver/settings_templates.py:1858 msgid "Tell device to play a haptic waveform." msgstr "მ�წყ�ბილ�ბისთვის ტ�ქტილური ფ�რმის სიგნ�ლის ბრძ�ნების გ�დ�ცემ�." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "" "უკვე გ�შვებული� Solaar-ის სხვ� პრ�ცესი, �სე რ�მ, უბრ�ლ�დ �მ�კეცეთ ის ფ�ნჯ�რ�" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "მ�რთ�ვს Logitech-ის მიმღებებს,\n" "კლ�ვი�ტურებს, თ�გუნებს დ� ტ�ბლეტებს." #: lib/solaar/ui/about/model.py:63 msgid "Additional Programming" msgstr "დ�მ�ტებითი პრ�გრ�მირებ�" #: lib/solaar/ui/about/model.py:64 msgid "GUI design" msgstr "GUI-ის დიზ�ინი" #: lib/solaar/ui/about/model.py:66 msgid "Testing" msgstr "ტესტირებ�" #: lib/solaar/ui/about/model.py:74 msgid "Logitech documentation" msgstr "Logitech-ის დ�კუმენტ�ცი�" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "დ�წყვილების მ�ხსნ�" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "გ�უქმებ�" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "წვდ�მების შეცდ�მ�" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "�ღმ�ჩენილი� Logitech-ის მიმღები, �ნ მ�წყ�ბილ�ბ� (%s), მ�გრ�მ მისი გ�ხსნის " "უფლებ� �რ მ�ქვს." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "თუ Solaar �ხლ�ხ�ნ დ��ყენეთ, სც�დეთ, გ�თიშ�თ მიმღები, �ნ მ�წყ�ბილ�ბ� დ� " "შემდეგ თ�ვიდ�ნ მი�ერთეთ." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "მ�წყ�ბილ�ბ�სთ�ნ დ�კ�ვშირების შეცდ�მ�" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "ვიპ�ვნე Logitech მიმღები �ნ მ�წყ�ბილ�ბ� %s-ზე, მ�გრ�მ დ�კ�ვშირების�ს " "�ღმ�ჩენილი� შეცდ�მ�." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "სც�დეთ, გ�თიშ�თ მ�წყ�ბილ�ბ� დ� თ�ვიდ�ნ მი�ერთ�თ, �ნ გ�მ�რთეთ ის დ� თ�ვიდ�ნ " "ჩ�რთეთ." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "დ�წყვილების გ�უქმებ� ჩ�ვ�რდ�" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "%{receiver}-დ�ნ %{device}-ის დ�წყვილების გ�უმების შეცდ�მ�." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "მიმღებმ� დ��ბრუნ� შეცდ�მ�, მ�გრ�მ დეტ�ლების გ�რეშე." #: lib/solaar/ui/config_panel.py:245 msgid "Complete - ENTER to change" msgstr "დ�სრულდ� - Enter შეს�ცვლელ�დ" #: lib/solaar/ui/config_panel.py:245 msgid "Incomplete" msgstr "�რ�სრული" #: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d მნიშვნელ�ბ�" msgstr[1] "%d მნიშვნელ�ბ�" #: lib/solaar/ui/config_panel.py:642 msgid "Changes allowed" msgstr "ცვლილებები დ�შვებული�" #: lib/solaar/ui/config_panel.py:643 msgid "No changes allowed" msgstr "ცვლილებები დ�შვებული �რ��" #: lib/solaar/ui/config_panel.py:644 msgid "Ignore this setting" msgstr "�მ პ�რ�მეტრის გ�მ�ტ�ვებ�" #: lib/solaar/ui/config_panel.py:690 msgid "Working" msgstr "მუშ��ბს" #: lib/solaar/ui/config_panel.py:693 msgid "Read/write operation failed." msgstr "წ�კითხვ�/ჩ�წერის �პერ�ცი� ჩ�ვ�რდ�." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "დ�უზუსტებელი მიზეზი" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "ჩ�შენებული წესები" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "მ�მხმ�რებლის �ღწერილი წესები" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "წესი" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "ქვეწესი" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "[ც�რიელი]" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "გ�ხდეს ცვლილებები მუდმივი?" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "დი�ხ" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "�რ�" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "თუ �ირჩევთ '�რ�ს', ცვლილებები დ�იკ�რგებ�, რ�ც� Solaar-ს დ�ხურ�ვთ." #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "�ქ ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "ზემ�თ ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "ქვემ�თ ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "წესის ჩ�სმ� �ქ" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "წესის ჩ�სმ� ზემ�თ" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "წესის ჩ�სმ� ქვემ�თ" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "წესის ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "�ქ ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "ზემ�თ ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "ქვემ�თ ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "�ხ�ლი წესის ჩ�სმ� �ქ" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "�ხ�ლი წესის ჩ�სმ� ზემ�თ" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "�ხ�ლი წესის ჩ�სმ� ქვემ�თ" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "გ�ბრტყელებ�" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "�ნ" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "დ�" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "პირ�ბ�" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "თვისებ�" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "�ნგ�რიში" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "პრ�ცესი" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "თ�გუნ�ს ქმედებ�" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "მ�დიფიკ�ტ�რები" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "ღილ�კი" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "ღილ�კი დ�ჭერილი�" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "�ქტიური" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "მ�წყ�ბილ�ბ�" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "ჰ�სტი" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "პ�რ�მეტრი" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "შემ�წმებ�" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "ს�ტესტ� ბ�იტები" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "თ�გუნ�ს ჟესტი" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "ქმედებ�" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "ღილ�კის დ�წ�ლ�" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "გ�დ�ხვევ� თ�გუნ�თი" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "თ�გუნ�ს წკ�პი" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "დ�ყენებ�" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "შესრულებ�" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "მ�გვი�ნებით" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "�ხ�ლი წესის ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "წ�შლ�" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "უ�რყ�ფ�" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "ჩ�კეცვ� ს�დ" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "�მ�ჭრ�" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "ჩ�სმ�" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "კ�პირებ�" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "Solaar-ის წესების რედ�ქტ�რი" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "ცვლილებების შენ�ხვ�" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "ცვლილებების გ�უქმებ�" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "�მ რედ�ქტ�რს ჯერ �რ �ქვს მ�ნიშნული წესის კ�მპ�ნენტის მხ�რდ�ჭერ�." #: lib/solaar/ui/diversion_rules.py:1169 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "დ�ყ�ვნების დრ� წ�მებში. დ�ყ�ვნებ� 0-ს� დ� 1-ს შ�რის უფრ� დიდი სიზუსტით " "ხდებ�." #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "�რ" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "გ�დ�რთვ�" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "ჭეშმ�რიტი" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "მცდ�რი" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "მხ�რდ�უჭერელი პ�რ�მეტრი" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "წყ�რ� მ�წყ�ბილ�ბ�" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "მ�წყ�ბილ�ბ� �ქტიური� დ� შეგიძლი�თ, მისი პ�რ�მეტრები შეცვ�ლ�თ." #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "მ�წყ�ბილ�ბ�, რ�მელიც მიმდინ�რე გ�ფრთხილებიდ�ნ დ�იწყ�." #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "მთ�ვ�რი კ�მპიუტერის ს�ხელი." #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "მნიშვნელ�ბ�" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "ელემენტი" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "პ�რ�მეტრის შეცვლ� მ�წყ�ბილ�ბ�ზე" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "პ�რ�მეტრი მ�წყ�ბილ�ბ�ზე" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: �ხ�ლი მ�წყ�ბილ�ბის დ�წყვილებ�" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "�რივე მიმღები, მხ�ლ�დ, Bolt მ�წყ�ბილ�ბ�სთ�ნ�� თ�ვსებ�დი." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "დ��ჭირეთ დ�წყვილების ღილ�კს, ს�ნ�მ დ�წყვილების ნ�თურ� სწრ�ფ�დ �რ �ციმციმდებ�." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" "გ�ერთი�ნებული მიმღებები, მხ�ლ�დ, გ�ერთი�ნებულ მ�წყ�ბილ�ბებთ�ნ�� თ�ვსებ�დი." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "სხვ� მიმღებები, მხ�ლ�დ, რ�მდენიმე მ�წყ�ბილ�ბ�სთ�ნ�� თ�ვსებ�დი." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "" "მ�წყ�ბილ�ბების უმრ�ვლეს�ბისთვის, უბრ�ლ�დ ჩ�რთეთ მ�წყ�ბილ�ბ�, რ�მლის " "დ�წყვილებ�ც გნებ�ვთ." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "თუ მ�წყ�ბილ�ბ� უკვე ჩ�რთული�, გ�მ�რთეთ დ� ისევ ჩ�რთეთ." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "მ�წყ�ბილ�ბ� �რ უნდ� იყ�ს დ�წყვილებული �ხლ�მდებ�რე ჩ�რთულ მიმღებთ�ნ." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "მრ�ვ�ლი �რხის მქ�ნე მ�წყ�ბილ�ბებისთვის დ��ჭირეთ ღილ�კს, გ��ჩერეთ დ� �უშვით " "ღილ�კს იმ �რხისთვის, რ�მლის დ�წყვილებ�ც გსურთ\n" "�ნ გ�მ�იყენეთ �რხის გ�დ�მრთველი ღილ�კი �რხის �ს�რჩევ�დ დ� შემდეგ დ��ჭირეთ " "ღილ�კს დ� �უშვით �რხის გ�დ�რთვის ღილ�კს." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "�რხის ინდიკ�ტ�რის სინ�თლე სწრ�ფ�დ უნდ� ციმციმებდეს." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "�მ მიმღებს %d დ�წყვილებ� დ�რჩ�." msgstr[1] "" "\n" "\n" "�მ მიმღებს %d დ�წყვილებ� დ�რჩ�." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "�მ მ�მენტში გ�უქმებ� დ�წყვილებ�ს �რ გ�მ�იყენებს." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "შეიყვ�ნეთ პ�რ�ლი %(name)s-ზე." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "�კრიფეთ %(passcode)s დ� შემდეგ დ��ჭირეთ ღილ�კს Enter." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "მ�რცხენ�" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "მ�რჯვენ�" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "დ��ჭირეთ ღილ�კს %(code)s\n" "დ� შემდეგ დ��ჭირეთ მ�რცხენ� დ� მ�რჯვენ� ღილ�კებს ერთდრ�ულ�დ." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "უს�დენ� კ�ვშირი დ�შიფრული �რ��" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "�ღმ�ჩენილი� �ხ�ლი მ�წყ�ბილ�ბ�:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "დ�წყვილებ� ჩ�ვ�რდ�" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "დ�რწმუნდით, რ�მ თქვენი მ�წყ�ბილ�ბ� ხელმის�წვდ�მ დ�შ�რებ�ზე� დ� �ქვს ელემენტი " "ს�კმ�რის�დ�� დ�მუხტული." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "" "�ღმ�ჩენილი� �ხ�ლი მ�წყ�ბილ�ბ�, მ�გრ�მ ის �რ �რის თ�ვსებ�დი �მ მიმღებთ�ნ." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "უფრ� მეტი დ�წყვილებული მ�წყ�ბილ�ბ�, ვიდრე მიმღებს შეუძლი� მხ�რდ�ჭერ�." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "შეცდ�მის შეს�ხებ დ�მ�ტებითი დეტ�ლები ხელმის�წვდ�მი �რ��." #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "�კ�რდული ღილ�კის დ�წკ�პუნების, დ�ჭერის �ნ �შვების სიმულ�ცი�.\n" "Wayland-ზე სჭირდებ� ჩ�წერის უფლებ� სპეცი�ლურ ფ�ილში /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "გ�ს�ღების დ�მ�ტებ�" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "წკ�პი" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "გ�ჭყლეტ�" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "რელიზი" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "თ�გუნ�ს გ�დ�ხვევის სიმულ�ცი�.\n" "Wayland-ზე სჭირდებ� ჩ�წერის უფლებ� სპეცი�ლურ ფ�ილში /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "თ�გუნ�ს დ�წკ�პუნების სიმულ�ცი�.\n" "Wayland-ზე სჭირდებ� ჩ�წერის უფლებ� სპეცი�ლურ ფ�ილში /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "ღილ�კი" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "ქმედებ� (დ� რ��დენ�ბ�, თუ წკ�პი�)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "ბრძ�ნების შესრულებ� �რგუმენტებით." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "�რგუმენტის დ�მ�ტებ�" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "X11-ის �ქტიური პრ�ცესი. გ�მ�იყენებ�, მხ�ლ�დ, X11-ში." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "X11-ის თ�გუნ�ს პრ�ცესი. გ�მ�იყენებ�, მხ�ლ�დ, X11-ში." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "თ�გუნ�ს ქმედებ�" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "შეტყ�ბინების ფუნქციის ს�ხელი, რ�მელიც იწვევს წესის დ�მუშ�ვებ�ს." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "წესის დ�მუშ�ვების დ�მ�ტრიგერებელი გ�ფრთხილებების რ��დენ�ბის გ�დ�ცემ�." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" "�ქტიური კლ�ვი�ტურის მ�დიფიკ�ტ�რების. Wayland-ზე ყ�ველთვის ხელმის�წვდ�მი �რ��." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "გ�დ�მის�მ�რთებულ ღილ�კს დ��წვნენ, �ნ �უშვეს.\n" "ღილ�კის გ�დ�მის�მ�რთების დ� G ღილ�კის პ�რ�მეტრების გ�მ�ყენებ� ღილ�კების " "გ�დ�მის�მ�რთებისთვის." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "ღილ�კის დ�ჭერ�" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "ღილ�კის გ�შვებ�" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "გ�დ�მის�მ�რთებული ღილ�კი �მჟ�მ�დ დ�ჭერილი�.\n" "ღილ�კის გ�დ�მის�მ�რთების დ� G ღილ�კის პ�რ�მეტრების გ�მ�ყენებ� ღილ�კების " "გ�დ�მის�მ�რთებისთვის." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "ს�ტესტ� პირ�ბ� წესის დ�მუშ�ვების გ�ფრთხილებ�ზე." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "პ�რ�მეტრი" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "დ�ს�წყისი (ჩ�თვლით)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "დ�ს�სრული (მხ�ლ�დ)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "შუ�ლედი" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "მინიმუმი" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "მ�ქსიმუმი" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "ბ�იტი %(0)d-დ�ნ %(1)d-მდე, დ�წყებული %(2)d-დ�ნ %(3)d-მდე" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "ნიღ�ბი" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "ბ�იტი %(0)d-დ�ნ %(1)d-მდე, ნიღ�ბი %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "ბიტის �ნ დი�პ�ზ�ნის ტესტი ბ�იტებზე შეტყ�ბინებების შეტყ�ბინების გ�მ�მწვევი " "წესის დ�მუშ�ვებ�ში." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "ტიპი" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "თ�გუნ�ს ჟესტი �რ�ს�ვ�ლდებულ� გ�მშვები ღილ�კით, რ�მელს�ც 0, �ნ მეტი თ�გუნ�ს " "მ�ძრ��ბ� მ�ჰყვებ�." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "მ�ძრ��ბის დ�მ�ტებ�" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "მხ�რდ�ჭერილი მ�წყ�ბილ�ბ� �ღმ�ჩენილი �რ��" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "%s-ის შეს�ხებ" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "%s-დ�ნ გ�სვლ�" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "მიმღების გ�რეშე" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:728 msgid "offline" msgstr "გ�თიშული" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "სტ�ტუსის გ�რეშე" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "სკ�ნირებ�" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "ელემენტი" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "უს�დენ� კ�ვშირი" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "გ�ნ�თებ�" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "ტექნიკური დეტ�ლების ჩვენებ�" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "�ხ�ლი მ�წყ�ბილ�ბის დ�წყვილებ�" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "�ირჩიეთ მ�წყ�ბილ�ბ�" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "წესების რედ�ქტ�რი" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "ბილიკი" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546 msgid "Serial" msgstr "სერიული" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "ინდექსი" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "უს�დენ� PID" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "პრ�დუქტის ID" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "პრ�ტ�კ�ლი" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "უცნ�ბი" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "გ�მ�კითხვის სიხშირე" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "ერთეულის ID" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "�რცერთი" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "შეტყ�ბინებები" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "დ�წყვილებული მ�წყ�ბილ�ბების გ�რეშე." #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "" "�მ მიმღებთ�ნ, მ�ქსიმუმ, %(max_count)s მ�წყ�ბილ�ბის დ�წყვილებ� შეიძლებ�." msgstr[1] "" "�მ მიმღებთ�ნ, მ�ქსიმუმ, %(max_count)s მ�წყ�ბილ�ბის დ�წყვილებ� შეიძლებ�." #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "�მ მიმღებთ�ნ, მ�ქს., ერთი მ�წყ�ბილ�ბის დ�წყვილებ�� შეს�ძლებელი." #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "�მ მიმღებს %d დ�წყვილებ� �ქვს დ�რჩენილი." msgstr[1] "�მ მიმღებს %d დ�წყვილებ� �ქვს დ�რჩენილი." #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "ელემენტის ვ�ლტ�ჟი" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "ელემენტის მიერ მ�წ�დებული ძ�ბვ�" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "ელემენტის მუხტის დ�ნე" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "დ�ნის მიერ მუხტის მ�წ�დებული დ��ხლ�ებითი დ�ნე" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "შემდეგი �ნგ�რიში " #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr " დ� შემდეგი დ�ნე გ�დ�ს�ცემ�დ." #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "ბ�ლ� ცნ�ბილი" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "დ�შიფრული�" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "უს�დენ� კ�ვშირი �მ მ�წყ�ბილ�ბ�ს� დ� მის მიმღებს შ�რის დ�შიფრული�." #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "დ�შიფრული �რ��" #: lib/solaar/ui/window.py:721 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "უს�დენ� კ�ვშირი �მ მ�წყ�ბილ�ბ�ს� დ� მის მიმღებს შ�რის დ�შიფრული �რ��.\n" "ეს უს�ფრთხ�ების პრ�ბლემ�� მ�ჩვენებელი მ�წყ�ბილ�ბებისთვის დ� უს�ფრთხ�ების " "დიდი პრ�ბლემ�� ტექსტის შეყვ�ნის მ�წყ�ბილ�ბებისთვის." #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d ლუქსი" Solaar-1.1.20/po/nb.po000066400000000000000000002015211522022367600143770ustar00rootroot00000000000000# Norwegian Bokmal translations for solaar package. # Copyright (C) 2020 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2020. # John Erling Blad , 2020-2024. # msgid "" msgstr "" "Project-Id-Version: solaar 1.0.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-24 03:15+0200\n" "PO-Revision-Date: 2024-10-31 02:21+0100\n" "Last-Translator: John Erling Blad \n" "Language-Team: \n" "Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1)\n" "X-Generator: Gtranslator 47.0\n" #: lib/logitech_receiver/base_usb.py:48 msgid "Bolt Receiver" msgstr "Bolt mottaker" #: lib/logitech_receiver/base_usb.py:60 msgid "Unifying Receiver" msgstr "Unifying mottaker" #: lib/logitech_receiver/base_usb.py:71 lib/logitech_receiver/base_usb.py:83 #: lib/logitech_receiver/base_usb.py:96 lib/logitech_receiver/base_usb.py:109 msgid "Nano Receiver" msgstr "Nano mottaker" #: lib/logitech_receiver/base_usb.py:121 msgid "Lightspeed Receiver" msgstr "Lightspeed mottaker" #: lib/logitech_receiver/base_usb.py:131 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 mottaker 27 Mhz mottaker" #: lib/logitech_receiver/common.py:648 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batteri: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:651 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batteri: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:962 #: lib/logitech_receiver/settings_templates.py:294 msgid "Disabled" msgstr "Avslått" #: lib/logitech_receiver/hidpp20.py:963 msgid "Static" msgstr "Statisk" #: lib/logitech_receiver/hidpp20.py:964 msgid "Pulse" msgstr "Puls" #: lib/logitech_receiver/hidpp20.py:965 msgid "Cycle" msgstr "Syklus" #: lib/logitech_receiver/hidpp20.py:966 msgid "Boot" msgstr "Boot" #: lib/logitech_receiver/hidpp20.py:967 msgid "Demo" msgstr "Demo" #: lib/logitech_receiver/hidpp20.py:969 msgid "Breathe" msgstr "Pust" #: lib/logitech_receiver/hidpp20.py:972 msgid "Ripple" msgstr "Krusning" #: lib/logitech_receiver/hidpp20.py:973 msgid "Decomposition" msgstr "Dekomponering" #: lib/logitech_receiver/hidpp20.py:974 msgid "Signature1" msgstr "Signatur1" #: lib/logitech_receiver/hidpp20.py:975 msgid "Signature2" msgstr "Signatur2" #: lib/logitech_receiver/hidpp20.py:976 msgid "CycleS" msgstr "SyklusS" #: lib/logitech_receiver/hidpp20.py:1040 msgid "Unknown Location" msgstr "Ukjent lokasjon" #: lib/logitech_receiver/hidpp20.py:1041 msgid "Primary" msgstr "Primær" #: lib/logitech_receiver/hidpp20.py:1042 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:1043 msgid "Left Side" msgstr "Venstre side" #: lib/logitech_receiver/hidpp20.py:1044 msgid "Right Side" msgstr "Høyre side" #: lib/logitech_receiver/hidpp20.py:1045 msgid "Combined" msgstr "Kombinert" #: lib/logitech_receiver/hidpp20.py:1046 msgid "Primary 1" msgstr "Primær 1" #: lib/logitech_receiver/hidpp20.py:1047 msgid "Primary 2" msgstr "Primær 2" #: lib/logitech_receiver/hidpp20.py:1048 msgid "Primary 3" msgstr "Primær 3" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Primary 4" msgstr "Primær 4" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Primary 5" msgstr "Primær 5" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Primary 6" msgstr "Primær 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "tom" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "kritisk" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "lav" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "middels" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "god" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "full" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "utlading" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "opplading" #: lib/logitech_receiver/i18n.py:37 msgid "charging" msgstr "lader" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "lader ikke" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "nesten full" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "ladet" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "langsom lading" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "batterifeil" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "termisk feil" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "feil" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "standard" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "rask" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "langsom" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "enheten svarte ikke" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "enheten er ikke støttet" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "for mange enheter" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "sekvens timeout" #: lib/logitech_receiver/i18n.py:54 msgid "Firmware" msgstr "Fastvare" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Oppstartslaster" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Maskinvare" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Annet" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Venstreknapp" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Høyreknapp" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Midtknapp" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Tilbakeknapp" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Foroverknapp" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Bevegelsesknapp" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Smart skift" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "DPI-bryter" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Venstre-tilt" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Høyre-tilt" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Venstre-klikk" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Høyre-klikk" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Midtknapp for mus" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Tilbakeknapp for mus" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Foroverknapp for mus" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Navigering med bevegelsesknapp" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Venstre rulleknapp for mus" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Høyre rulleknapp for mus" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "nedtrykt" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "utløst" #: lib/logitech_receiver/notifications.py:86 #: lib/logitech_receiver/notifications.py:138 msgid "pairing lock is closed" msgstr "parlåsen er lukket" #: lib/logitech_receiver/notifications.py:86 #: lib/logitech_receiver/notifications.py:138 msgid "pairing lock is open" msgstr "parlåsen er åpen" #: lib/logitech_receiver/notifications.py:103 msgid "discovery lock is closed" msgstr "oppdagelseslåsen er lukket" #: lib/logitech_receiver/notifications.py:103 msgid "discovery lock is open" msgstr "oppdagelseslåsen er åpen" #: lib/logitech_receiver/notifications.py:232 lib/solaar/listener.py:247 msgid "connected" msgstr "tilkoblet" #: lib/logitech_receiver/notifications.py:232 lib/solaar/listener.py:247 msgid "disconnected" msgstr "frakoblet" #: lib/logitech_receiver/notifications.py:258 msgid "unpaired" msgstr "uparet" #: lib/logitech_receiver/notifications.py:305 msgid "powered on" msgstr "påslått" #: lib/logitech_receiver/receiver.py:383 msgid "No paired devices." msgstr "Ingen paret enhet." #: lib/logitech_receiver/receiver.py:385 lib/solaar/ui/window.py:590 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s paret enhet." msgstr[1] "%(count)s parede enheter." #: lib/logitech_receiver/settings.py:614 msgid "register" msgstr "register" #: lib/logitech_receiver/settings.py:628 lib/logitech_receiver/settings.py:663 msgid "feature" msgstr "karakteristikk" #: lib/logitech_receiver/settings_templates.py:133 msgid "Swap Fx function" msgstr "Bytt Fx-funksjon" #: lib/logitech_receiver/settings_templates.py:136 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Hvis aktivert, vil F1–F12-tastene aktivere sin spesialfunksjon,\n" "og du må holde FN-tasten nede for å aktivere deres standardfunksjon." #: lib/logitech_receiver/settings_templates.py:141 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Hvis deaktivert, vil F1–F12-tastene aktivere sin standardfunksjon,\n" "og du må holde FN-tasten nede for å aktivere deres spesialfunksjon." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Håndpåvisning" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Slå på belysning når hendene er over tastaturet." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "Myk rulling med rullehjul" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:405 #: lib/logitech_receiver/settings_templates.py:434 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Høysensitiv modus for vertikal rulling med hjulet." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Siderulling" #: lib/logitech_receiver/settings_templates.py:167 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Hvis avslått; trykkes hjulet sideveis så sendes en tilpasset knappehendelse\n" "istedenfor standard siderulling." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "Følsomhet (DPI – eldre mus)" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:977 #: lib/logitech_receiver/settings_templates.py:1005 msgid "Mouse movement sensitivity" msgstr "Følsomhet for musbevegelser" #: lib/logitech_receiver/settings_templates.py:251 msgid "Backlight Timed" msgstr "Tidsbestemt bakgrunnslys" #: lib/logitech_receiver/settings_templates.py:252 #: lib/logitech_receiver/settings_templates.py:392 msgid "Set illumination time for keyboard." msgstr "Still inn belysningstid for tastatur." #: lib/logitech_receiver/settings_templates.py:263 msgid "Backlight" msgstr "Bakbelysning" #: lib/logitech_receiver/settings_templates.py:264 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Lysnivå på tastaturet. Endringer som er gjort, brukes kun i manuell modus." #: lib/logitech_receiver/settings_templates.py:296 msgid "Automatic" msgstr "Automatisk" #: lib/logitech_receiver/settings_templates.py:298 msgid "Manual" msgstr "Manuell" #: lib/logitech_receiver/settings_templates.py:300 msgid "Enabled" msgstr "Påslått" #: lib/logitech_receiver/settings_templates.py:306 msgid "Backlight Level" msgstr "Bakgrunnslysnivå" #: lib/logitech_receiver/settings_templates.py:307 msgid "Illumination level on keyboard when in Manual mode." msgstr "Lysnivå på tastaturet i manuell modus." #: lib/logitech_receiver/settings_templates.py:364 msgid "Backlight Delay Hands Out" msgstr "Forsinkelse på bakgrunnsbelysning når hendene fjernes" #: lib/logitech_receiver/settings_templates.py:365 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Forsinkelse i sekunder til bakgrunnsbelysningen toner ut når hendene er " "borte fra tastaturet." #: lib/logitech_receiver/settings_templates.py:373 msgid "Backlight Delay Hands In" msgstr "Forsinkelse på bakgrunnsbelysning når hendene er nære" #: lib/logitech_receiver/settings_templates.py:374 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Forsinkelse i sekunder til bakgrunnsbelysningen toner ut når hendene er nære " "tastaturet." #: lib/logitech_receiver/settings_templates.py:382 msgid "Backlight Delay Powered" msgstr "Forsinkelse på bakgrunnsbelysning når strømforsynt" #: lib/logitech_receiver/settings_templates.py:383 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Forsinkelse i sekunder til bakgrunnsbelysningen toner ut med ekstern " "strømforsyning." #: lib/logitech_receiver/settings_templates.py:391 msgid "Backlight (Seconds)" msgstr "Bakgrunnslys (sekunder)" #: lib/logitech_receiver/settings_templates.py:403 msgid "Scroll Wheel High Resolution" msgstr "Høyoppløselig rullehjul" #: lib/logitech_receiver/settings_templates.py:407 #: lib/logitech_receiver/settings_templates.py:436 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Sett til å ignorere hvis rullingen er unormalt rask eller sakte" #: lib/logitech_receiver/settings_templates.py:414 #: lib/logitech_receiver/settings_templates.py:445 msgid "Scroll Wheel Diversion" msgstr "Omdirigering for rullehjul" #: lib/logitech_receiver/settings_templates.py:416 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Få rullehjulet til å sende LOWRES_WHEEL HID++-varsler (som utløser Solaar-" "regler, men som ellers ignoreres)." #: lib/logitech_receiver/settings_templates.py:423 msgid "Scroll Wheel Direction" msgstr "Retning på rullehjul" #: lib/logitech_receiver/settings_templates.py:424 msgid "Invert direction for vertical scroll with wheel." msgstr "Inverter retning for vertikal rulling med hjul." #: lib/logitech_receiver/settings_templates.py:432 msgid "Scroll Wheel Resolution" msgstr "Oppløsning på rullehjul" #: lib/logitech_receiver/settings_templates.py:447 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Få rullehjulet til å sende HIRES_WHEEL HID++-varsler (som utløser Solaar-" "regler, men som ellers ignoreres)." #: lib/logitech_receiver/settings_templates.py:456 msgid "Sensitivity (Pointer Speed)" msgstr "Følsomhet (pekerfart)" #: lib/logitech_receiver/settings_templates.py:457 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Fartsmultiplikator for mus (256 er normal multiplikator)." #: lib/logitech_receiver/settings_templates.py:467 msgid "Thumb Wheel Diversion" msgstr "Omdirigering for tommelhjul" #: lib/logitech_receiver/settings_templates.py:469 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Få tommelhjulet til å sende THUMB_WHEEL HID++-varsler (som utløser Solaar-" "regler, men som ellers ignoreres)." #: lib/logitech_receiver/settings_templates.py:478 msgid "Thumb Wheel Direction" msgstr "Retning på tommelhjul" #: lib/logitech_receiver/settings_templates.py:479 msgid "Invert thumb wheel scroll direction." msgstr "Inverter rulleretning for tommelhjul." #: lib/logitech_receiver/settings_templates.py:499 msgid "Onboard Profiles" msgstr "Innebygde profiler" #: lib/logitech_receiver/settings_templates.py:500 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Aktiver en innebygd profil, som kontrollerer rapporthyppighet, følsomhet og " "knappehandlinger" #: lib/logitech_receiver/settings_templates.py:544 #: lib/logitech_receiver/settings_templates.py:577 msgid "Report Rate" msgstr "Rapporthyppighet" #: lib/logitech_receiver/settings_templates.py:546 #: lib/logitech_receiver/settings_templates.py:579 msgid "Frequency of device movement reports" msgstr "Frekvensen til rapporter om enhetsbevegelser" #: lib/logitech_receiver/settings_templates.py:546 #: lib/logitech_receiver/settings_templates.py:579 #: lib/logitech_receiver/settings_templates.py:1005 #: lib/logitech_receiver/settings_templates.py:1379 #: lib/logitech_receiver/settings_templates.py:1410 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "Kan trenge at innebygde profiler settes til avslått for å være effektive." #: lib/logitech_receiver/settings_templates.py:607 msgid "Divert crown events" msgstr "Omdiriger krone-hendelser" #: lib/logitech_receiver/settings_templates.py:608 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Få kronen til å sende CROWN HID++-varsler (som utløser Solaar-regler, men " "som ellers ignoreres)." #: lib/logitech_receiver/settings_templates.py:616 msgid "Crown smooth scroll" msgstr "Glatt krone-rulling" #: lib/logitech_receiver/settings_templates.py:617 msgid "Set crown smooth scroll" msgstr "Still inn glatt krone-rulling" #: lib/logitech_receiver/settings_templates.py:625 msgid "Divert G and M Keys" msgstr "Omdiriger G- og M-taster" #: lib/logitech_receiver/settings_templates.py:626 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Få G- og M-tastene til å sende HID++-varsler (som utløser Solaar-regler, men " "som ellers ignoreres)." #: lib/logitech_receiver/settings_templates.py:640 msgid "Scroll Wheel Ratcheted" msgstr "Rullehjul sperrehaket" #: lib/logitech_receiver/settings_templates.py:641 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Bytt musehjulet mellom hastighetskontrollert sperrehake og alltid " "frittløpende." #: lib/logitech_receiver/settings_templates.py:643 msgid "Freespinning" msgstr "Frittløpende" #: lib/logitech_receiver/settings_templates.py:643 msgid "Ratcheted" msgstr "Sperrehake" #: lib/logitech_receiver/settings_templates.py:650 msgid "Scroll Wheel Ratchet Speed" msgstr "Rullehjul sperrehakefart" #: lib/logitech_receiver/settings_templates.py:652 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Bruk musehjulfarten til å bytte mellom sperrehake og frittløpende.\n" "Musehjulet er alltid satt til 50." #: lib/logitech_receiver/settings_templates.py:701 msgid "Key/Button Actions" msgstr "Taste-/knappehandling" #: lib/logitech_receiver/settings_templates.py:703 msgid "Change the action for the key or button." msgstr "Endre handling for en tast eller knapp." #: lib/logitech_receiver/settings_templates.py:705 msgid "Overridden by diversion." msgstr "Overstyrt av omdirigering." #: lib/logitech_receiver/settings_templates.py:707 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Endring av viktige handlinger (for eksempel venstre musknapp) kan resultere " "i et ubrukbart system." #: lib/logitech_receiver/settings_templates.py:882 msgid "Key/Button Diversion" msgstr "Taste-/knappeomdirigering" #: lib/logitech_receiver/settings_templates.py:883 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "Få nøkkelen eller knappen til å sende HID++-varsler (omdirigert) eller " "initier musebevegelser eller glidende DPI" #: lib/logitech_receiver/settings_templates.py:886 #: lib/logitech_receiver/settings_templates.py:887 #: lib/logitech_receiver/settings_templates.py:888 msgid "Diverted" msgstr "Omdirigert" #: lib/logitech_receiver/settings_templates.py:886 #: lib/logitech_receiver/settings_templates.py:887 msgid "Mouse Gestures" msgstr "Musebevegelser" #: lib/logitech_receiver/settings_templates.py:886 #: lib/logitech_receiver/settings_templates.py:887 #: lib/logitech_receiver/settings_templates.py:888 msgid "Regular" msgstr "Vanlig" #: lib/logitech_receiver/settings_templates.py:886 msgid "Sliding DPI" msgstr "Glidende DPI" #: lib/logitech_receiver/settings_templates.py:976 #: lib/logitech_receiver/settings_templates.py:1004 msgid "Sensitivity (DPI)" msgstr "Følsomhet (DPI)" #: lib/logitech_receiver/settings_templates.py:1081 msgid "Sensitivity Switching" msgstr "Følsomhetsbytte" #: lib/logitech_receiver/settings_templates.py:1083 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Bytt gjeldende følsomhet og tidligere følsomhet når tasten eller knappen " "trykkes.\n" "Hvis det ikke er noen tidligere følsomhet, sett kun gjeldende følsomhet" #: lib/logitech_receiver/settings_templates.py:1087 msgid "Off" msgstr "Av" #: lib/logitech_receiver/settings_templates.py:1118 msgid "Disable keys" msgstr "Slå av taster" #: lib/logitech_receiver/settings_templates.py:1119 msgid "Disable specific keyboard keys." msgstr "Slå av spesifikke tastaturtaster." #: lib/logitech_receiver/settings_templates.py:1122 #, python-format msgid "Disables the %s key." msgstr "Slår av %s-tasten." #: lib/logitech_receiver/settings_templates.py:1135 #: lib/logitech_receiver/settings_templates.py:1192 msgid "Set OS" msgstr "Still OS" #: lib/logitech_receiver/settings_templates.py:1136 #: lib/logitech_receiver/settings_templates.py:1193 msgid "Change keys to match OS." msgstr "Endre taster så de stemmer med OS." #: lib/logitech_receiver/settings_templates.py:1205 msgid "Change Host" msgstr "Endre tjener" #: lib/logitech_receiver/settings_templates.py:1206 msgid "Switch connection to a different host" msgstr "Endre koblingen til en annen tjener" #: lib/logitech_receiver/settings_templates.py:1230 msgid "Performs a left click." msgstr "Utfører et venstreklikk." #: lib/logitech_receiver/settings_templates.py:1230 msgid "Single tap" msgstr "Enkeltklikk" #: lib/logitech_receiver/settings_templates.py:1231 msgid "Performs a right click." msgstr "Utfører et høyreklikk." #: lib/logitech_receiver/settings_templates.py:1231 msgid "Single tap with two fingers" msgstr "Enkelt trykk med to fingre" #: lib/logitech_receiver/settings_templates.py:1232 msgid "Single tap with three fingers" msgstr "Enkelt trykk med tre fingre" #: lib/logitech_receiver/settings_templates.py:1236 msgid "Double tap" msgstr "Dobbeltklikk" #: lib/logitech_receiver/settings_templates.py:1236 msgid "Performs a double click." msgstr "Utfører et dobbeltklikk." #: lib/logitech_receiver/settings_templates.py:1237 msgid "Double tap with two fingers" msgstr "Dobbeltklikk med to fingre" #: lib/logitech_receiver/settings_templates.py:1238 msgid "Double tap with three fingers" msgstr "Dobbeltklikk med tre fingre" #: lib/logitech_receiver/settings_templates.py:1241 msgid "Drags items by dragging the finger after double tapping." msgstr "Dra elementer med fingeren etter dobbeltklikk." #: lib/logitech_receiver/settings_templates.py:1241 msgid "Tap and drag" msgstr "Klikk og dra" #: lib/logitech_receiver/settings_templates.py:1243 msgid "Tap and drag with two fingers" msgstr "Klikk og dra med to fingre" #: lib/logitech_receiver/settings_templates.py:1244 msgid "Drags items by dragging the fingers after double tapping." msgstr "Dra elementer med fingrene etter dobbeltklikk." #: lib/logitech_receiver/settings_templates.py:1246 msgid "Tap and drag with three fingers" msgstr "Klikk og dra med tre fingre" #: lib/logitech_receiver/settings_templates.py:1249 msgid "Suppress tap and edge gestures" msgstr "Undertrykk klikk- og kantbevegelser" #: lib/logitech_receiver/settings_templates.py:1250 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Slår av klikk- og kantbevegelser (tilsvarer å trykke Fn+Venstreklikk)." #: lib/logitech_receiver/settings_templates.py:1252 msgid "Scroll with one finger" msgstr "Rull med en finger" #: lib/logitech_receiver/settings_templates.py:1252 #: lib/logitech_receiver/settings_templates.py:1253 #: lib/logitech_receiver/settings_templates.py:1256 msgid "Scrolls." msgstr "Ruller." #: lib/logitech_receiver/settings_templates.py:1253 #: lib/logitech_receiver/settings_templates.py:1256 msgid "Scroll with two fingers" msgstr "Rull med to fingre" #: lib/logitech_receiver/settings_templates.py:1254 msgid "Scroll horizontally with two fingers" msgstr "Rull horisontalt med to fingre" #: lib/logitech_receiver/settings_templates.py:1254 msgid "Scrolls horizontally." msgstr "Rull horisontalt." #: lib/logitech_receiver/settings_templates.py:1255 msgid "Scroll vertically with two fingers" msgstr "Rull vertikalt med to fingre" #: lib/logitech_receiver/settings_templates.py:1255 msgid "Scrolls vertically." msgstr "Rull vertikalt." #: lib/logitech_receiver/settings_templates.py:1257 msgid "Inverts the scrolling direction." msgstr "Inverterer rulleretningen." #: lib/logitech_receiver/settings_templates.py:1257 msgid "Natural scrolling" msgstr "Naturlig rulling" #: lib/logitech_receiver/settings_templates.py:1258 msgid "Enables the thumbwheel." msgstr "Aktiverer tommelhjulet." #: lib/logitech_receiver/settings_templates.py:1258 msgid "Thumbwheel" msgstr "Tommelhjul" #: lib/logitech_receiver/settings_templates.py:1269 #: lib/logitech_receiver/settings_templates.py:1273 msgid "Swipe from the top edge" msgstr "Sveip fra øvre kant" #: lib/logitech_receiver/settings_templates.py:1270 msgid "Swipe from the left edge" msgstr "Sveip fra venstre kant" #: lib/logitech_receiver/settings_templates.py:1271 msgid "Swipe from the right edge" msgstr "Sveip fra høyre kant" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Swipe from the bottom edge" msgstr "Sveip fra nedre kant" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Swipe two fingers from the left edge" msgstr "Sveip to fingre fra venstre kant" #: lib/logitech_receiver/settings_templates.py:1275 msgid "Swipe two fingers from the right edge" msgstr "Sveip to fingre fra høyre kant" #: lib/logitech_receiver/settings_templates.py:1276 msgid "Swipe two fingers from the bottom edge" msgstr "Sveip to fingre fra nedre kant" #: lib/logitech_receiver/settings_templates.py:1277 msgid "Swipe two fingers from the top edge" msgstr "Sveip to fingre fra øvre kant" #: lib/logitech_receiver/settings_templates.py:1278 #: lib/logitech_receiver/settings_templates.py:1282 msgid "Pinch to zoom out; spread to zoom in." msgstr "Knip for å zoome ut; spre for å zoome inn." #: lib/logitech_receiver/settings_templates.py:1278 msgid "Zoom with two fingers." msgstr "Zoom med to fingre." #: lib/logitech_receiver/settings_templates.py:1279 msgid "Pinch to zoom out." msgstr "Knip for å zoome ut." #: lib/logitech_receiver/settings_templates.py:1280 msgid "Spread to zoom in." msgstr "Spre for å zoome inn." #: lib/logitech_receiver/settings_templates.py:1281 msgid "Zoom with three fingers." msgstr "Zoom med tre fingre." #: lib/logitech_receiver/settings_templates.py:1282 msgid "Zoom with two fingers" msgstr "Zoom med to fingre" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Pixel zone" msgstr "Pikselsone" #: lib/logitech_receiver/settings_templates.py:1301 msgid "Ratio zone" msgstr "Forholdssone" #: lib/logitech_receiver/settings_templates.py:1302 msgid "Scale factor" msgstr "Skalafaktor" #: lib/logitech_receiver/settings_templates.py:1302 msgid "Sets the cursor speed." msgstr "Still inn markørhastigheten." #: lib/logitech_receiver/settings_templates.py:1306 msgid "Left" msgstr "Venstre" #: lib/logitech_receiver/settings_templates.py:1306 msgid "Left-most coordinate." msgstr "Koordinat lengst til venstre." #: lib/logitech_receiver/settings_templates.py:1307 msgid "Bottom" msgstr "Nederst" #: lib/logitech_receiver/settings_templates.py:1307 msgid "Bottom coordinate." msgstr "Nederste koordinat." #: lib/logitech_receiver/settings_templates.py:1308 msgid "Width" msgstr "Bredde" #: lib/logitech_receiver/settings_templates.py:1308 msgid "Width." msgstr "Bredde." #: lib/logitech_receiver/settings_templates.py:1309 msgid "Height" msgstr "Høyde" #: lib/logitech_receiver/settings_templates.py:1309 msgid "Height." msgstr "Høyde." #: lib/logitech_receiver/settings_templates.py:1310 msgid "Cursor speed." msgstr "Markørhastighet." #: lib/logitech_receiver/settings_templates.py:1310 msgid "Scale" msgstr "Skala" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Gestures" msgstr "Bevegelser" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Tweak the mouse/touchpad behaviour." msgstr "Juster musens/berøringsplatens oppførsel." #: lib/logitech_receiver/settings_templates.py:1333 msgid "Gestures Diversion" msgstr "Omdirigering av bevegelser" #: lib/logitech_receiver/settings_templates.py:1334 msgid "Divert mouse/touchpad gestures." msgstr "Omdiriger musens/berøringsflatens bevegelser." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Gesture params" msgstr "Parametre for bevegelser" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Endre numeriske parametere for en mus/berøringsplate." #: lib/logitech_receiver/settings_templates.py:1375 msgid "M-Key LEDs" msgstr "M-tast LED-ene" #: lib/logitech_receiver/settings_templates.py:1377 msgid "Control the M-Key LEDs." msgstr "Kontroller M-tast LED-ene." #: lib/logitech_receiver/settings_templates.py:1381 #: lib/logitech_receiver/settings_templates.py:1412 msgid "May need G Keys diverted to be effective." msgstr "Kan trenge omdirigering av G-taster for å være effektivt." #: lib/logitech_receiver/settings_templates.py:1387 #, python-format msgid "Lights up the %s key." msgstr "Lyser opp %s-tasten." #: lib/logitech_receiver/settings_templates.py:1406 msgid "MR-Key LED" msgstr "MR-tast LED" #: lib/logitech_receiver/settings_templates.py:1408 msgid "Control the MR-Key LED." msgstr "Kontroller MR-tast LED." #: lib/logitech_receiver/settings_templates.py:1429 msgid "Persistent Key/Button Mapping" msgstr "Vedvarende tast-/knapptilordning" #: lib/logitech_receiver/settings_templates.py:1431 msgid "Permanently change the mapping for the key or button." msgstr "Endre tilordningen for tasten eller knappen permanent." #: lib/logitech_receiver/settings_templates.py:1433 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Endring av viktige taster eller knapper (som venstre museknapp) kan " "resultere i et ubrukelig system." #: lib/logitech_receiver/settings_templates.py:1490 msgid "Sidetone" msgstr "Sidetone" #: lib/logitech_receiver/settings_templates.py:1491 msgid "Set sidetone level." msgstr "Still inn sidetone nivå." #: lib/logitech_receiver/settings_templates.py:1500 msgid "Equalizer" msgstr "Equalizer" #: lib/logitech_receiver/settings_templates.py:1501 msgid "Set equalizer levels." msgstr "Still inn equalizer nivå." #: lib/logitech_receiver/settings_templates.py:1523 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1529 msgid "Power Management" msgstr "Strømstyring" #: lib/logitech_receiver/settings_templates.py:1530 msgid "Power off in minutes (0 for never)." msgstr "Slå av i minutter (0 for aldri)." #: lib/logitech_receiver/settings_templates.py:1541 msgid "Brightness Control" msgstr "Lysstyrkekontroll" #: lib/logitech_receiver/settings_templates.py:1542 msgid "Control overall brightness" msgstr "Kontroller den generelle lysstyrken" #: lib/logitech_receiver/settings_templates.py:1585 #: lib/logitech_receiver/settings_templates.py:1639 msgid "LED Control" msgstr "LED-kontroll" #: lib/logitech_receiver/settings_templates.py:1586 #: lib/logitech_receiver/settings_templates.py:1640 msgid "Switch control of LED zones between device and Solaar" msgstr "Bytt kontroll av LED-soner mellom enhet og Solaar" #: lib/logitech_receiver/settings_templates.py:1601 #: lib/logitech_receiver/settings_templates.py:1650 msgid "LED Zone Effects" msgstr "LED-soneeffekter" #: lib/logitech_receiver/settings_templates.py:1602 #: lib/logitech_receiver/settings_templates.py:1651 msgid "LED Control needs to be set to Solaar to be effective." msgstr "LED-kontroll må settes til Solaar for å være effektiv." #: lib/logitech_receiver/settings_templates.py:1602 #: lib/logitech_receiver/settings_templates.py:1651 msgid "Set effect for LED Zone" msgstr "Still inn effekt for LED-sone" #: lib/logitech_receiver/settings_templates.py:1605 msgid "Speed" msgstr "Hastighet" #: lib/logitech_receiver/settings_templates.py:1606 msgid "Period" msgstr "Periode" #: lib/logitech_receiver/settings_templates.py:1607 msgid "Intensity" msgstr "Intensitet" #: lib/logitech_receiver/settings_templates.py:1608 msgid "Ramp" msgstr "Stigning" #: lib/logitech_receiver/settings_templates.py:1624 msgid "LEDs" msgstr "LEDs" #: lib/logitech_receiver/settings_templates.py:1661 msgid "Per-key Lighting" msgstr "Lys for hver tast" #: lib/logitech_receiver/settings_templates.py:1662 msgid "Control per-key lighting." msgstr "Kontroller lys for hver tast." #: lib/solaar/ui/__init__.py:117 msgid "Another Solaar process is already running so just expose its window" msgstr "En annen Solaar-prosess kjører allerede, så bare vis vinduet" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Administrerer Logitech-mottakere,\n" "tastaturer, mus og nettbrett." #: lib/solaar/ui/about/model.py:62 msgid "Additional Programming" msgstr "Ekstra programmering" #: lib/solaar/ui/about/model.py:63 msgid "GUI design" msgstr "GUI utseende" #: lib/solaar/ui/about/model.py:65 msgid "Testing" msgstr "Testing" #: lib/solaar/ui/about/model.py:73 msgid "Logitech documentation" msgstr "Logitech dokumentasjon" #: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87 #: lib/solaar/ui/window.py:188 msgid "Unpair" msgstr "Fjern paring" #: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:107 msgid "Cancel" msgstr "Avbryt" #: lib/solaar/ui/common.py:35 msgid "Permissions error" msgstr "Rettighetsfeil" #: lib/solaar/ui/common.py:37 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Fant en Logitech-mottaker eller enhet (%s), men hadde ikke tillatelse til å " "åpne den." #: lib/solaar/ui/common.py:39 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Hvis du nettopp har installert Solaar, kan du prøve å koble fra mottakeren " "eller enheten og deretter koble den til igjen." #: lib/solaar/ui/common.py:42 msgid "Cannot connect to device error" msgstr "Kan ikke koble til enhet-feil" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Fant en Logitech-mottaker eller -enhet på %s, men oppdaget en feil når den " "ble tilkoblet." #: lib/solaar/ui/common.py:46 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Prøv å koble fra enheten og deretter koble den til igjen eller slå den av og " "på igjen." #: lib/solaar/ui/common.py:49 msgid "Unpairing failed" msgstr "Kunne ikke bryte paringen" #: lib/solaar/ui/common.py:51 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Mislyktes med å bryte paret %{device} og %{receiver}." #: lib/solaar/ui/common.py:56 msgid "The receiver returned an error, with no further details." msgstr "Mottakeren rapporterte en feil, uten flere detaljer." #: lib/solaar/ui/config_panel.py:228 msgid "Complete - ENTER to change" msgstr "Fullfør - ENTER for å endre" #: lib/solaar/ui/config_panel.py:228 msgid "Incomplete" msgstr "Ufullstendig" #: lib/solaar/ui/config_panel.py:475 lib/solaar/ui/config_panel.py:527 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d verdi" msgstr[1] "%d verdier" #: lib/solaar/ui/config_panel.py:609 msgid "Changes allowed" msgstr "Endringer tillatt" #: lib/solaar/ui/config_panel.py:610 msgid "No changes allowed" msgstr "Ingen endringer tillatt" #: lib/solaar/ui/config_panel.py:611 msgid "Ignore this setting" msgstr "Ignorer denne innstillingen" #: lib/solaar/ui/config_panel.py:655 msgid "Working" msgstr "Suksess" #: lib/solaar/ui/config_panel.py:658 msgid "Read/write operation failed." msgstr "Lese-/skriveoperasjonen mislyktes." #: lib/solaar/ui/desktop_notifications.py:114 msgid "unspecified reason" msgstr "uspesifisert årsak" #: lib/solaar/ui/diversion_rules.py:69 msgid "Built-in rules" msgstr "Faste regler" #: lib/solaar/ui/diversion_rules.py:69 msgid "User-defined rules" msgstr "Brukerdefinerte regler" #: lib/solaar/ui/diversion_rules.py:71 lib/solaar/ui/diversion_rules.py:1089 msgid "Rule" msgstr "Regel" #: lib/solaar/ui/diversion_rules.py:72 lib/solaar/ui/diversion_rules.py:348 #: lib/solaar/ui/diversion_rules.py:475 msgid "Sub-rule" msgstr "Underregel" #: lib/solaar/ui/diversion_rules.py:74 msgid "[empty]" msgstr "[tom]" #: lib/solaar/ui/diversion_rules.py:98 msgid "Make changes permanent?" msgstr "Gjøre endringer permanente?" #: lib/solaar/ui/diversion_rules.py:103 msgid "Yes" msgstr "Ja" #: lib/solaar/ui/diversion_rules.py:105 msgid "No" msgstr "Nei" #: lib/solaar/ui/diversion_rules.py:110 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Hvis du velger Nei, vil endringer gå tapt når Solaar lukkes." #: lib/solaar/ui/diversion_rules.py:239 msgid "Paste here" msgstr "Lim inn her" #: lib/solaar/ui/diversion_rules.py:241 msgid "Paste above" msgstr "Lim inn ovenfor" #: lib/solaar/ui/diversion_rules.py:243 msgid "Paste below" msgstr "Lim inn nedenfor" #: lib/solaar/ui/diversion_rules.py:249 msgid "Paste rule here" msgstr "Lim inn regel her" #: lib/solaar/ui/diversion_rules.py:251 msgid "Paste rule above" msgstr "Lim inn regel ovenfor" #: lib/solaar/ui/diversion_rules.py:253 msgid "Paste rule below" msgstr "Lim inn regel nedenfor" #: lib/solaar/ui/diversion_rules.py:257 msgid "Paste rule" msgstr "Lim inn regel" #: lib/solaar/ui/diversion_rules.py:272 msgid "Insert here" msgstr "Sett inn her" #: lib/solaar/ui/diversion_rules.py:274 msgid "Insert above" msgstr "Sett inn ovenfor" #: lib/solaar/ui/diversion_rules.py:276 msgid "Insert below" msgstr "Sett inn nedenfor" #: lib/solaar/ui/diversion_rules.py:282 msgid "Insert new rule here" msgstr "Sett inn ny regel her" #: lib/solaar/ui/diversion_rules.py:284 msgid "Insert new rule above" msgstr "Sett inn ny regel ovenfor" #: lib/solaar/ui/diversion_rules.py:286 msgid "Insert new rule below" msgstr "Sett inn ny regel nedenfor" #: lib/solaar/ui/diversion_rules.py:313 msgid "Flatten" msgstr "Utflate" #: lib/solaar/ui/diversion_rules.py:346 msgid "Insert" msgstr "Sett inn" #: lib/solaar/ui/diversion_rules.py:349 lib/solaar/ui/diversion_rules.py:477 #: lib/solaar/ui/diversion_rules.py:1121 msgid "Or" msgstr "Eller" #: lib/solaar/ui/diversion_rules.py:350 lib/solaar/ui/diversion_rules.py:476 #: lib/solaar/ui/diversion_rules.py:1107 msgid "And" msgstr "Og" #: lib/solaar/ui/diversion_rules.py:352 msgid "Condition" msgstr "Betingelse" #: lib/solaar/ui/diversion_rules.py:354 lib/solaar/ui/rule_conditions.py:145 msgid "Feature" msgstr "Karakteristikk" #: lib/solaar/ui/diversion_rules.py:355 lib/solaar/ui/rule_conditions.py:179 msgid "Report" msgstr "Rapport" #: lib/solaar/ui/diversion_rules.py:356 lib/solaar/ui/rule_conditions.py:60 msgid "Process" msgstr "Prosess" #: lib/solaar/ui/diversion_rules.py:357 msgid "Mouse process" msgstr "Musprosess" #: lib/solaar/ui/diversion_rules.py:358 lib/solaar/ui/rule_conditions.py:216 msgid "Modifiers" msgstr "Modifikatorer" #: lib/solaar/ui/diversion_rules.py:359 lib/solaar/ui/rule_conditions.py:268 msgid "Key" msgstr "Tast" #: lib/solaar/ui/diversion_rules.py:360 lib/solaar/ui/rule_conditions.py:309 msgid "KeyIsDown" msgstr "TastErNede" #: lib/solaar/ui/diversion_rules.py:361 lib/solaar/ui/diversion_rules.py:1414 msgid "Active" msgstr "Aktiv" #: lib/solaar/ui/diversion_rules.py:362 lib/solaar/ui/diversion_rules.py:1372 #: lib/solaar/ui/diversion_rules.py:1423 lib/solaar/ui/diversion_rules.py:1470 msgid "Device" msgstr "Enhet" #: lib/solaar/ui/diversion_rules.py:363 lib/solaar/ui/diversion_rules.py:1449 msgid "Host" msgstr "Vert" #: lib/solaar/ui/diversion_rules.py:364 lib/solaar/ui/diversion_rules.py:1489 msgid "Setting" msgstr "Innstilling" #: lib/solaar/ui/diversion_rules.py:365 lib/solaar/ui/rule_conditions.py:324 #: lib/solaar/ui/rule_conditions.py:373 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:366 lib/solaar/ui/rule_conditions.py:498 msgid "Test bytes" msgstr "Test bytes" #: lib/solaar/ui/diversion_rules.py:367 lib/solaar/ui/rule_conditions.py:599 msgid "Mouse Gesture" msgstr "Musebevegelse" #: lib/solaar/ui/diversion_rules.py:371 msgid "Action" msgstr "Handling" #: lib/solaar/ui/diversion_rules.py:373 lib/solaar/ui/rule_actions.py:131 msgid "Key press" msgstr "Tastetrykk" #: lib/solaar/ui/diversion_rules.py:374 lib/solaar/ui/rule_actions.py:182 msgid "Mouse scroll" msgstr "Muserulling" #: lib/solaar/ui/diversion_rules.py:375 lib/solaar/ui/rule_actions.py:243 msgid "Mouse click" msgstr "Museklikk" #: lib/solaar/ui/diversion_rules.py:376 msgid "Set" msgstr "Still inn" #: lib/solaar/ui/diversion_rules.py:377 lib/solaar/ui/rule_actions.py:313 msgid "Execute" msgstr "Utfør" #: lib/solaar/ui/diversion_rules.py:378 lib/solaar/ui/diversion_rules.py:1152 msgid "Later" msgstr "Senere" #: lib/solaar/ui/diversion_rules.py:407 msgid "Insert new rule" msgstr "Sett inn ny regel" #: lib/solaar/ui/diversion_rules.py:427 lib/solaar/ui/rule_actions.py:74 #: lib/solaar/ui/rule_actions.py:272 lib/solaar/ui/rule_conditions.py:546 msgid "Delete" msgstr "Slett" #: lib/solaar/ui/diversion_rules.py:449 msgid "Negate" msgstr "Omvendt" #: lib/solaar/ui/diversion_rules.py:473 msgid "Wrap with" msgstr "Pakk inn med" #: lib/solaar/ui/diversion_rules.py:503 msgid "Cut" msgstr "Klipp ut" #: lib/solaar/ui/diversion_rules.py:519 msgid "Paste" msgstr "Lim inn" #: lib/solaar/ui/diversion_rules.py:525 msgid "Copy" msgstr "Kopier" #: lib/solaar/ui/diversion_rules.py:534 msgid "Solaar Rule Editor" msgstr "Solaar regel editor" #: lib/solaar/ui/diversion_rules.py:634 msgid "Save changes" msgstr "Lagre endringer" #: lib/solaar/ui/diversion_rules.py:639 msgid "Discard changes" msgstr "Forkast endringer" #: lib/solaar/ui/diversion_rules.py:1070 msgid "This editor does not support the selected rule component yet." msgstr "Denne editoren støtter foreløpig ikke den valgte regelkomponenten." #: lib/solaar/ui/diversion_rules.py:1132 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Antall sekunder med forsinkelse. Forsinkelse mellom 0 og 1 gjøres med høyere " "presisjon." #: lib/solaar/ui/diversion_rules.py:1170 msgid "Not" msgstr "Ikke" #: lib/solaar/ui/diversion_rules.py:1201 msgid "Toggle" msgstr "Veksle" #: lib/solaar/ui/diversion_rules.py:1202 msgid "True" msgstr "Sann" #: lib/solaar/ui/diversion_rules.py:1203 msgid "False" msgstr "Falsk" #: lib/solaar/ui/diversion_rules.py:1216 msgid "Unsupported setting" msgstr "Innstillingen støttes ikke" #: lib/solaar/ui/diversion_rules.py:1378 lib/solaar/ui/diversion_rules.py:1397 #: lib/solaar/ui/diversion_rules.py:1476 lib/solaar/ui/diversion_rules.py:1731 #: lib/solaar/ui/diversion_rules.py:1749 msgid "Originating device" msgstr "Kildeenhet" #: lib/solaar/ui/diversion_rules.py:1410 msgid "Device is active and its settings can be changed." msgstr "Enheten er aktiv og innstillingene kan endres." #: lib/solaar/ui/diversion_rules.py:1419 msgid "Device that originated the current notification." msgstr "Enheten som ga det gjeldende varselet." #: lib/solaar/ui/diversion_rules.py:1432 msgid "Name of host computer." msgstr "Navn på vertsmaskin." #: lib/solaar/ui/diversion_rules.py:1503 msgid "Value" msgstr "Verdi" #: lib/solaar/ui/diversion_rules.py:1512 msgid "Item" msgstr "Punkt" #: lib/solaar/ui/diversion_rules.py:1791 msgid "Change setting on device" msgstr "Endre innstilling på enhet" #: lib/solaar/ui/diversion_rules.py:1807 msgid "Setting on device" msgstr "Innstilling på enhet" #: lib/solaar/ui/pair_window.py:37 lib/solaar/ui/pair_window.py:165 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: par ny enhet" #: lib/solaar/ui/pair_window.py:39 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt-mottakere er kun kompatible med Bolt-enheter." #: lib/solaar/ui/pair_window.py:41 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Trykk på sammenkoblingsknappen eller -tasten til sammenkoblingslampen " "blinker raskt." #: lib/solaar/ui/pair_window.py:44 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Unifying-mottakere er bare kompatible med Unifying-enheter." #: lib/solaar/ui/pair_window.py:46 msgid "Other receivers are only compatible with a few devices." msgstr "Andre mottakere er kun kompatible med noen få enheter." #: lib/solaar/ui/pair_window.py:48 msgid "For most devices, turn on the device you want to pair." msgstr "For de fleste enheter slår du på enheten du vil pare." #: lib/solaar/ui/pair_window.py:49 msgid "If the device is already turned on, turn it off and on again." msgstr "Hvis enheten allerede er påslått, slå den av og på igjen." #: lib/solaar/ui/pair_window.py:51 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "Enheten må ikke pares med en påslått mottaker i nærheten." #: lib/solaar/ui/pair_window.py:54 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "For enheter med flere kanaler, trykk, hold og slipp knappen for kanalen du " "ønsker å pare\n" "eller bruk kanalbryterknappen for å velge en kanal og trykk, hold og slipp " "kanalbryterknappen." #: lib/solaar/ui/pair_window.py:61 msgid "The channel indicator light should be blinking rapidly." msgstr "Kanalindikatorlampen skal blinke raskt." #: lib/solaar/ui/pair_window.py:65 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Denne mottakeren har %d gjenstående paring." msgstr[1] "" "\n" "\n" "Denne mottakeren har %d gjenstående paringer." #: lib/solaar/ui/pair_window.py:71 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Kansellering nå vil ikke bruke opp en paring." #: lib/solaar/ui/pair_window.py:166 #, python-format msgid "Enter passcode on %(name)s." msgstr "Skriv inn passordet på %(name)s." #: lib/solaar/ui/pair_window.py:169 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Skriv inn %(passcode)s og trykk deretter på enter-tasten." #: lib/solaar/ui/pair_window.py:174 msgid "left" msgstr "venstre" #: lib/solaar/ui/pair_window.py:174 msgid "right" msgstr "høyre" #: lib/solaar/ui/pair_window.py:176 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Trykk %(code)s\n" "og trykk deretter på venstre og høyre knapp samtidig." #: lib/solaar/ui/pair_window.py:219 msgid "The wireless link is not encrypted" msgstr "Den trådløse koblingen er ukryptert" #: lib/solaar/ui/pair_window.py:224 msgid "Found a new device:" msgstr "Fant ny enhet:" #: lib/solaar/ui/pair_window.py:245 msgid "Pairing failed" msgstr "Paringen feilet" #: lib/solaar/ui/pair_window.py:247 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Forsikre deg om at enheten er innen rekkevidde, og at den er tilstrekkelig " "oppladet." #: lib/solaar/ui/pair_window.py:249 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "En ny enhet ble påvist, men den er ukompatibel med denne mottakeren." #: lib/solaar/ui/pair_window.py:251 msgid "More paired devices than receiver can support." msgstr "Fler parede enheter enn mottakeren kan støtte." #: lib/solaar/ui/pair_window.py:253 msgid "No further details are available about the error." msgstr "Ingen ytterligere detaljer er tilgjengelig om feilen." #: lib/solaar/ui/rule_actions.py:48 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuler en chorded (?) tast, klikk eller trykk ned eller slipp.\n" "På Wayland krever dette skrivetilgang til /dev/uinput." #: lib/solaar/ui/rule_actions.py:53 msgid "Add key" msgstr "Legg til tast" #: lib/solaar/ui/rule_actions.py:56 msgid "Click" msgstr "Klikk" #: lib/solaar/ui/rule_actions.py:59 msgid "Depress" msgstr "Nedtrykk" #: lib/solaar/ui/rule_actions.py:62 msgid "Release" msgstr "Utløs" #: lib/solaar/ui/rule_actions.py:146 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuler en muserulling.\n" "På Wayland krever dette skrivetilgang til /dev/uinput." #: lib/solaar/ui/rule_actions.py:202 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuler et museklikk.\n" "På Wayland krever dette skrivetilgang til /dev/uinput." #: lib/solaar/ui/rule_actions.py:205 msgid "Button" msgstr "Knapp" #: lib/solaar/ui/rule_actions.py:206 msgid "Count and Action" msgstr "Antall og handling" #: lib/solaar/ui/rule_actions.py:255 msgid "Execute a command with arguments." msgstr "Utfør en kommando med argumenter." #: lib/solaar/ui/rule_actions.py:258 msgid "Add argument" msgstr "Legg til argument" #: lib/solaar/ui/rule_conditions.py:43 msgid "X11 active process. For use in X11 only." msgstr "X11 aktiv prosess. Kun til bruk i X11." #: lib/solaar/ui/rule_conditions.py:73 msgid "X11 mouse process. For use in X11 only." msgstr "X11-museprosess. Kun til bruk i X11." #: lib/solaar/ui/rule_conditions.py:90 msgid "MouseProcess" msgstr "MusProsess" #: lib/solaar/ui/rule_conditions.py:114 msgid "Feature name of notification triggering rule processing." msgstr "Funksjonsnavn på varsel som utløste regelbehandling." #: lib/solaar/ui/rule_conditions.py:160 msgid "Report number of notification triggering rule processing." msgstr "Rapportnummer for varsling som utløser regelbehandling." #: lib/solaar/ui/rule_conditions.py:192 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Aktive tastaturmodifikatorer. Ikke alltid tilgjengelig i Wayland." #: lib/solaar/ui/rule_conditions.py:232 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Omdirigert tast eller knapp som er trykket eller sluppet.\n" "Bruk innstillingene for omdirigering av tast/knapp og omdiriger G-taster for " "å videresende taster og knapper." #: lib/solaar/ui/rule_conditions.py:241 msgid "Key down" msgstr "Tast ned" #: lib/solaar/ui/rule_conditions.py:244 msgid "Key up" msgstr "Tast opp" #: lib/solaar/ui/rule_conditions.py:284 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Omdirigert tast eller knapp er nede.\n" "Bruk innstillingene for omdirigering av tast/knapp og omdirigerte G-taster " "for å videresende taster og knapper." #: lib/solaar/ui/rule_conditions.py:322 msgid "Test condition on notification triggering rule processing." msgstr "Testbetingelse på varsel som utløser regelbehandling." #: lib/solaar/ui/rule_conditions.py:326 msgid "Parameter" msgstr "Parameter" #: lib/solaar/ui/rule_conditions.py:399 msgid "begin (inclusive)" msgstr "begynn (inklusiv)" #: lib/solaar/ui/rule_conditions.py:400 msgid "end (exclusive)" msgstr "slutt (eksklusiv)" #: lib/solaar/ui/rule_conditions.py:408 msgid "range" msgstr "område" #: lib/solaar/ui/rule_conditions.py:411 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/rule_conditions.py:412 msgid "maximum" msgstr "maksimum" #: lib/solaar/ui/rule_conditions.py:414 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "byte %(0)d til %(1)d, fra %(2)d til %(3)d" #: lib/solaar/ui/rule_conditions.py:417 lib/solaar/ui/rule_conditions.py:418 msgid "mask" msgstr "maske" #: lib/solaar/ui/rule_conditions.py:419 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "byte %(0)d til %(1)d, maske %(2)d" #: lib/solaar/ui/rule_conditions.py:428 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Bit- eller områdetest på bytes i varselmelding som utløste regelbehandling." #: lib/solaar/ui/rule_conditions.py:438 msgid "type" msgstr "type" #: lib/solaar/ui/rule_conditions.py:526 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Musebevegelse med valgfri startknapp etterfulgt av null eller flere " "musebevegelser." #: lib/solaar/ui/rule_conditions.py:531 msgid "Add movement" msgstr "Legg til bevegelse" #: lib/solaar/ui/tray.py:49 msgid "No supported device found" msgstr "Ingen støttede enheter er funnet" #: lib/solaar/ui/tray.py:54 lib/solaar/ui/window.py:308 #, python-format msgid "About %s" msgstr "Om %s" #: lib/solaar/ui/tray.py:55 lib/solaar/ui/window.py:306 #, python-format msgid "Quit %s" msgstr "Avslutt %s" #: lib/solaar/ui/tray.py:270 lib/solaar/ui/tray.py:278 msgid "no receiver" msgstr "ingen mottaker" #: lib/solaar/ui/tray.py:291 lib/solaar/ui/tray.py:296 msgid "offline" msgstr "avslått" #: lib/solaar/ui/tray.py:294 msgid "no status" msgstr "ingen status" #: lib/solaar/ui/window.py:90 msgid "Scanning" msgstr "Søker" #: lib/solaar/ui/window.py:121 msgid "Battery" msgstr "Batteri" #: lib/solaar/ui/window.py:124 msgid "Wireless Link" msgstr "Trådløs kobling" #: lib/solaar/ui/window.py:128 msgid "Lighting" msgstr "Belysning" #: lib/solaar/ui/window.py:162 msgid "Show Technical Details" msgstr "Vis tekniske detaljer" #: lib/solaar/ui/window.py:178 msgid "Pair new device" msgstr "Par ny enhet" #: lib/solaar/ui/window.py:196 msgid "Select a device" msgstr "Velg en enhet" #: lib/solaar/ui/window.py:311 msgid "Rule Editor" msgstr "Regel editor" #: lib/solaar/ui/window.py:504 msgid "Path" msgstr "Sti" #: lib/solaar/ui/window.py:506 msgid "USB ID" msgstr "USB-ID" #: lib/solaar/ui/window.py:509 lib/solaar/ui/window.py:511 #: lib/solaar/ui/window.py:526 lib/solaar/ui/window.py:528 msgid "Serial" msgstr "Seriell" #: lib/solaar/ui/window.py:515 msgid "Index" msgstr "Indeks" #: lib/solaar/ui/window.py:517 msgid "Wireless PID" msgstr "Trådløs-PID" #: lib/solaar/ui/window.py:519 msgid "Product ID" msgstr "Produkt-ID" #: lib/solaar/ui/window.py:521 msgid "Protocol" msgstr "Protokoll" #: lib/solaar/ui/window.py:521 msgid "Unknown" msgstr "Ukjent" #: lib/solaar/ui/window.py:523 msgid "Polling rate" msgstr "Spørrerate" #: lib/solaar/ui/window.py:530 msgid "Unit ID" msgstr "Enhets-ID" #: lib/solaar/ui/window.py:544 msgid "Notifications" msgstr "Varsler" #: lib/solaar/ui/window.py:588 msgid "No device paired." msgstr "Ingen enhet paret." #: lib/solaar/ui/window.py:597 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Inntil %(max_count)s enhet kan bli paret med denne mottakeren." msgstr[1] "Inntil %(max_count)s enheter kan bli paret med denne mottakeren." #: lib/solaar/ui/window.py:608 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Denne mottakeren har %d gjenstående paring." msgstr[1] "Denne mottakeren har %d gjenstående paringer." #: lib/solaar/ui/window.py:665 msgid "Battery Voltage" msgstr "Batterispenning" #: lib/solaar/ui/window.py:667 msgid "Voltage reported by battery" msgstr "Spenning rapportert av batteri" #: lib/solaar/ui/window.py:669 msgid "Battery Level" msgstr "Batterinivå" #: lib/solaar/ui/window.py:671 msgid "Approximate level reported by battery" msgstr "Omtrentlig nivå rapportert fra batteri" #: lib/solaar/ui/window.py:678 lib/solaar/ui/window.py:680 msgid "next reported " msgstr "neste rapportert " #: lib/solaar/ui/window.py:681 msgid " and next level to be reported." msgstr " og neste nivå som blir rapportert." #: lib/solaar/ui/window.py:697 msgid "encrypted" msgstr "kryptert" #: lib/solaar/ui/window.py:699 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Den trådløse tilkoblingen mellom enheten og mottakeren er kryptert." #: lib/solaar/ui/window.py:701 msgid "not encrypted" msgstr "ukryptert" #: lib/solaar/ui/window.py:705 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "Den trådløse koblingen mellom denne enheten og mottakeren er ikke kryptert.\n" "Dette er et sikkerhetsproblem for pekeenheter, og et stort sikkerhetsproblem " "for enheter for tekstinndata." #: lib/solaar/ui/window.py:721 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "" #~ "\n" #~ "\n" #~ "This receiver has %d pairing(s) remaining." #~ msgstr "" #~ "\n" #~ "\n" #~ "Denne mottakeren har %d gjenstående paringer." #, python-format #~ msgid "%(rate)d ms (%(rate_hz)dHz)" #~ msgstr "%(rate)d ms (%(rate_hz)dHz)" #~ msgid "Actions" #~ msgstr "Handlinger" #~ msgid "Add action" #~ msgstr "Legg til handling" #~ msgid "" #~ "Adjust the DPI by sliding the mouse horizontally while holding the button " #~ "down." #~ msgstr "" #~ "Juster DPI ved å skyve musen horisontalt mens du holder knappen nede." #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always locked at 50" #~ msgstr "" #~ "Bytt mushjulet automatisk mellom sperre- og frispinnmodus.\n" #~ "Mushjulet er alltid fritt på 0, og låses alltid på 50" #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "" #~ "Bytt automatisk rullehjulet mellom skralle- og frispinn-modus.\n" #~ "Rullehjulet er alltid fritt ved 0, og med skralle ved 50" #~ msgid "Battery information unknown." #~ msgstr "Ukjent batteriinformasjon" #, python-format #~ msgid "Battery: %(level)s" #~ msgstr "Batteri: %(level)s" #, python-format #~ msgid "Battery: %(percent)d%%" #~ msgstr "Batteri: %(percent)d%%" #~ msgid "Count" #~ msgstr "Antall" #~ msgid "DPI Sliding Adjustment" #~ msgstr "DPI-glidejustering" #~ msgid "Divert G Keys" #~ msgstr "Omdiriger G-taster" #~ msgid "" #~ "Diverted key or button depressed or released.\n" #~ "Use the Key/Button Diversion setting to divert keys and buttons." #~ msgstr "" #~ "Omdirigert tast eller knapp, trykket eller sluppet.\n" #~ "Bruk innstillingen for omdirigering av tast/knapp for å viderekoble " #~ "taster og knapper." #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Slår i praksis av tommelrulling i Linux." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Slår i praksis av hjulrulling i Linux." #~ msgid "" #~ "Enable onboard profiles, which often control report rate and keyboard " #~ "lighting" #~ msgstr "" #~ "Aktiver innebygde profiler, som ofte kontrollerer rapporthastighet og " #~ "tastaturbelysning" #~ msgid "" #~ "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "" #~ "For mer informasjon, se Solaar-installasjonsanvisningene\n" #~ "på https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "" #~ "Found a Logitech Receiver (%s), but did not have permission to open it." #~ msgstr "" #~ "Fant en Logitech-mottaker (%s), men mangler rettigheter til å åpne den." #~ msgid "Frequency of device polling, in milliseconds" #~ msgstr "Frekvens på enhetsspørring, i millisekunder" #~ msgid "HID++ Scrolling" #~ msgstr "HID++ rulling" #~ msgid "HID++ Thumb Scrolling" #~ msgstr "HID++ tommelrulling" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID++ modus for horisontal rulling med tommelhjulet." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++ modus for vertikal rulling med hjulet." #~ msgid "High Resolution Scrolling" #~ msgstr "Høyoppløselig rulling" #~ msgid "High Resolution Wheel Invert" #~ msgstr "Inverter høy rulleoppløsning" #~ msgid "High-sensitivity wheel invert direction for vertical scroll." #~ msgstr "Inverter retning for høy vertikal rulleoppløsning." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Hvis enheten allerede er slått på, slå den av og på igjen." #~ msgid "" #~ "If you've just installed Solaar, try removing the receiver and plugging " #~ "it back in." #~ msgstr "" #~ "Hvis du nettopp har installert Solaar, forsøk å fjerne mottakeren og " #~ "plugg den inn igjen." #~ msgid "Invert thumb scroll direction." #~ msgstr "Inverter retning på tommelrulling." #, python-format #~ msgid "Lighting: %(level)s lux" #~ msgstr "Belysning: %(level)s lux" #~ msgid "" #~ "Make G keys send GKEY HID++ notifications (which trigger Solaar rules but " #~ "are otherwise ignored)." #~ msgstr "" #~ "Få G-taster til å sende GKEY HID++-varsler (som utløser Solaar-regler, " #~ "men som ellers ignoreres)." #~ msgid "" #~ "Make the key or button send HID++ notifications (which trigger Solaar " #~ "rules but are otherwise ignored)." #~ msgstr "" #~ "Få tasten eller knappen til å sende HID++-varsler (som utløser Solaar-" #~ "regler, men ellers ignoreres)." #~ msgid "May also make M keys and MR key send HID++ notifications" #~ msgstr "Kan også få M-taster og MR-taster til å sende HID++-varsler" #~ msgid "No Logitech device found" #~ msgstr "Finner ingen Logitech-enhet" #~ msgid "No Logitech receiver found" #~ msgstr "Ingen Logitech-mottaker funnet" #~ msgid "Only one device can be paired to this receiver." #~ msgstr "Kun én enhet kan pares med denne mottakeren." #~ msgid "Polling Rate (ms)" #~ msgstr "Spørrerate (ms)" #~ msgid "Report number of notification triggering rule processing." #~ msgstr "Rapportnummer på varsel som utløste regelbehandling." #~ msgid "Scroll Wheel Rachet" #~ msgstr "Skrallen for rullehjulet" #~ msgid "Send a gesture by sliding the mouse while holding the button down." #~ msgstr "Send en bevegelse ved å skyve musen mens du holder knappen nede." #~ msgid "" #~ "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "" #~ "Viser status for enheter tilkoblet\n" #~ "via trådløse Logitech-mottakere." #~ msgid "Smooth Scrolling" #~ msgstr "Myk rulling" #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar er avhengig av en udev-fil som ikke finnes" #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Mottakeren kan kun støtte %d parede enhet(er)." #~ msgid "The receiver was unplugged." #~ msgstr "Mottakeren ble fjernet." #~ msgid "" #~ "The wireless link between this device and its receiver is not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices (keyboards, " #~ "numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties within " #~ "range." #~ msgstr "" #~ "Den trådløse koblingen mellom denne enheten og mottakeren er ukryptert.\n" #~ "\n" #~ "For pekeenheter (mus, styrekuler, styreflater) er dette en mindre " #~ "sikkerhetsproblem.\n" #~ "\n" #~ "Det er imidlertid et viktig sikkerhetsproblem for tekstinndataenheter " #~ "(tastaturer, numpads),\n" #~ "fordi maskinskrevet tekst kan bli sniffet ubemerket av tredjeparter innen " #~ "rekkevidde." #~ msgid "This receiver has %d pairing(s) remaining." #~ msgstr "Denne mottakeren har %d gjenstående paring(er)." #~ msgid "Thumb Scroll Invert" #~ msgstr "Inverter tommelrulling" #~ msgid "Top-most coordinate." #~ msgstr "Koordinat lengst oppe." #~ msgid "" #~ "Try removing the device and plugging it back in or turning it off and " #~ "then on." #~ msgstr "" #~ "Prøv å fjerne enheten og koble den til igjen eller slå den av og på." #~ msgid "Turn illumination on or off on keyboard." #~ msgstr "Slå på eller av belysning for tastaturet." #~ msgid "Turn on the device you want to pair." #~ msgstr "Slå på enheten du ønsker å pare." #~ msgid "USB id" #~ msgstr "USB-id" #~ msgid "Unexpected device number (%s) in notification %s." #~ msgstr "Uventet enhetsnummer (%s) i varsel %s." #~ msgid "Wheel Resolution" #~ msgstr "Hjuloppløsning" #~ msgid "You may have to first turn the device off and on again." #~ msgstr "Først må du kanskje slå enheten av og på igjen." #~ msgid "height" #~ msgstr "høyde" #~ msgid "last known" #~ msgstr "sist kjent" #~ msgid "next " #~ msgstr "neste " #~ msgid "none" #~ msgstr "ingen" #~ msgid "top" #~ msgstr "top" #~ msgid "unknown" #~ msgstr "ukjent" #~ msgid "width" #~ msgstr "bredde" Solaar-1.1.20/po/nl.po000066400000000000000000001536561522022367600144300ustar00rootroot00000000000000# Dutch translations for solaar package # Copyright (C) 2021 SOLAAR'S COPYRIGHT HOLDER # This file is distributed under the same license as the Solaar package. # msgid "" msgstr "Project-Id-Version: solaar 1.0.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2021-01-15 22:03+0100\n" "Last-Translator: Heimen Stoffels \n" "Language-Team: \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.4.2\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "leeg" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "bijna leeg" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "laag" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "goed" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "opgeladen" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "bezig met ontladen" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "bezig met opladen" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "bezig met opladen" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "bijna opgeladen" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "opgeladen" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "langzaam opladen" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "verkeerde batterij" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "temperatuurfout" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "time-out opgetreden" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "apparaat wordt niet ondersteund" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "te veel apparaten" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "meerdere time-outs" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Opstartlader" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Overig" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "Slim schakelen" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "koppelvergendeling ingeschakeld" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "koppelvergendeling uitgeschakeld" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "verbonden" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "verbinding verbroken" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "niet gekoppeld" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "ingeschakeld" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Fx-functies omdraaien" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Schakel dit in om de speciale functies van F1-F12 te gebruiken -\n" "de standaard functies kunnen worden geactiveerd met Fn + F1-F12." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Schakel dit in om de standaard functies van F1-F12 te gebruiken -\n" "de speciale functies kunnen worden geactiveerd met Fn + F1-F12." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Handpalmdetectie" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Schakelt de verlichting in als u beide handen boven het toetsenbord " "houdt." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "Vloeiend scrollen" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Hogegevoeligheidsmodus voor verticaal scrollen." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Zijwaarts scrollen" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Schakel dit uit om aangepaste knopgebeurtenissen te versturen als u " "het scrollwiel\n" "opzijduwt in plaats van de standaard gebeurtenissen." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "Muisgevoeligheid" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Achtergrondverlichting" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "Schakel de toetsenbordverlichting in of uit." #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "Scrollen met hoge resolutie" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "Scrollrichting" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "Keer de modus van verticaal scrollen met het scrollwiel om." #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "Scrollresolutie" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Gevoeligheid (cursorsnelheid)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Muisversnelling (256 is de standaard versnelling)." #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "Duimwielrichting" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "Keer de scrollrichting van het duimwiel om." #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "Kroongebeurtenissen omleiden" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Laat de kroon een HID++-melding versturen (welke Solaar's regels " "volgen, maar verder genegeerd worden)." #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "G-toetsen omleiden" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Laat de G-toetsen een HID++-melding versturen (welke Solaar's regels " "volgen, maar verder genegeerd worden)." #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "Toets-/Knopacties" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Pas de actie van een toets of knop aan." #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "Let op: het aanpassen van belangrijke acties (zoals die van de " "linkermuisknop) kan leiden tot een onbruikbaar systeem." #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "Toets-/Knopomleiding" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Gevoeligheid (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Toetsen uitschakelen" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Schakel specifieke toetsen op het toetsenbord uit." #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "Schakelt de %s-toets uit." #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Besturingssysteem instellen" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Pas de toetsen aan aan het besturingssysteem." #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Host veranderen" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Schakel over naar een andere host." #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "Voert een linkermuisklik uit." #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "Eenmaal tikken" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "Voert een rechtermuisklik uit." #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "Eenmaal tikken met twee vingers" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "Eenmaal tikken met drie vingers" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "Dubbeltikken" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "Voert een dubbele klik uit." #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "Dubbeltikken met twee vingers" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "Dubbeltikken met drie vingers" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "Verplaats items door na het dubbeltikken uw vinger te verplaatsen." #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "Tikken-en-slepen" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "Verplaats items door na het dubbeltikken uw vingers te verplaatsen." #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "Tikken-en-slepen met twee vingers" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "Tikken-en-slepen met drie vingers" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Schakel tik- en randgebaren uit (gelijk aan Fn+linkermuisklik)." #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "Tik- en randgebaren uitschakelen" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "Scrollen met één vinger" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "Scrollt." #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "Scrollen met twee vingers" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "Horizontaal scrollen met twee vingers" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "Scrollt horizontaal." #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "Verticaal scrollen met twee vingers" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "Scrollt verticaal." #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "Draai de scrollrichting om." #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "Natuurlijk scrollen" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "Schakel het duimwiel in." #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "Duimwiel" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "Vegen vanaf bovenkant" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "Vegen vanaf linkerkant" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "Vegen vanaf rechterkant" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "Vegen vanaf onderkant" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "Vegen vanaf linkerkant (twee vingers)" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "Vegen vanaf rechterkant (twee vingers)" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "Vegen vanaf onderkant (twee vingers)" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "Vegen vanaf bovenkant (twee vingers)" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "Knijp om uit te zoomen; spreid om in te zoomen." #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "Zoomen met twee vingers." #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "Knijp om uit te zoomen." #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "Spreid om in te zoomen." #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "Zoomen met drie vingers." #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "Zoomen met twee vingers" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Schaalfactor" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "Links" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "Het meest linker coördinaat." #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Breedte" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "Breedte." #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Hoogte" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "Hoogte." #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "Cursorsnelheid." #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "Schaal" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gebaren" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "Pas het gedrag van het trackpad/de muis aan." #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "Gebarenwaarden" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Pas de numerieke waarden van het trackpad/de muis aan." #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Geen apparaten gekoppeld." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s gekoppeld apparaat." msgstr[1] "%(count)s gekoppelde apparaten." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Batterijniveau: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Batterijniveau: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Verlichting: %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batterijniveau: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batterijniveau: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Machtigingsfout" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Loskoppelen mislukt" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "'%{device}' kan niet worden losgekoppeld van '%{receiver}'." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "Er is een fout opgetreden zonder nadere informatie." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "Toepassingsontwerp" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Testen" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Logitech-documentatie" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Loskoppelen" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d waarde" msgstr[1] "%d waarden" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Aan het werk" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Uitlezen/Wegschrijven mislukt." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "Meegeleverde regels" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "Eigen regels" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "Regel" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "Aanvullende regel" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[leeg]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Solaar-regelbewerker" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "Wilt u de wijzigingen permanent opslaan?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Ja" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Als u 'Nee' kiest, dan worden ze verworpen nadat Solaar is " "afgesloten." #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "Hier invoegen" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "Hierboven invoegen" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "Hieronder invoegen" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "Nieuwe regel hier invoegen" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "Nieuwe regel hierboven invoegen" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "Nieuwe regel hieronder invoegen" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "Hier plakken" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "Hierboven plakken" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "Hieronder plakken" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "Regel hier plakken" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "Regel hierboven plakken" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "Regel hieronder plakken" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "Regel plakken" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "Vlakmaken" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "Invoegen" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "Of" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "En" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "Omstandigheid" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "Functie" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "Melden" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Proces" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "Sneltoetsen" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "Toets" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Actief" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "Testen" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Actie" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "Toetsaanslag" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "Scrollbeweging" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "Muisklik" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "Uitvoeren" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "Nieuwe regel invoegen" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "Verwijderen" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "Negeren" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "Omslaan met" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Knippen" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Plakken" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Kopiëren" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "Deze bewerker heeft nog geen ondersteuning voor het geselecteerde " "onderdeel." #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "" #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "Niet" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "Toets toevoegen" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "Knop" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "Aanvullende optie toevoegen" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Waarde" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "offline" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: nieuw apparaat aankoppelen" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "" #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Koppelen mislukt" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Zorg er voor dat het apparaat binnen handbereik is en voldoende is " "opgeladen." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Er is een nieuw apparaat aangetroffen dat niet compatibel is met " "deze ontvanger." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "Er zijn meer gekoppelde apparaten dan de ontvanger aankan." #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Er is een fout opgetreden zonder nadere informatie." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "Nieuw apparaat aangetroffen:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "De draadloze verbinding is onversleuteld" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Schakel het te koppelen apparaat in." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "Er kan nog %d apparaat worden gekoppeld aan deze ontvanger." msgstr[1] "\n" "\n" "Er kunnen nog %d apparaten worden gekoppeld aan deze ontvanger." #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Als u nu afbreekt, kunt u nog steeds iets koppelen." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "Info %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "%s afsluiten" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "geen ontvanger" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "geen status" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Bezig met zoeken..." #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Batterij" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Draadloze verbinding" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Verlichting" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Technische informatie tonen" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Nieuw apparaat aankoppelen" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Kies een apparaat" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "Regelbewerker" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Pad" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "USB-id" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Serie" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "Draadloze pid" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "Product-id" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protocol" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Onbekend" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Controlesnelheid" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "Apparaat-id" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "geen" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Meldingen" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "Geen apparaat gekoppeld." #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Er kan slechts %(max_count)s apparaat worden gekoppeld aan " "deze ontvanger." msgstr[1] "Er kunnen slechts %(max_count)s apparaten worden gekoppeld " "aan deze ontvanger." #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "Er kan slechts één apparaat worden gekoppeld aan deze ontvanger." #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Er kan nog %d apparaat worden gekoppeld aan deze ontvanger." msgstr[1] "Er kunnen nog %d apparaten worden gekoppeld aan deze " "ontvanger." #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "Batterijvoltage" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "Het door de batterij gemelde voltage" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "Batterijniveau" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "Het door de batterij geschatte niveau" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "volgende melding " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " en het volgende te melden niveau." #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "laatst bekend" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "versleuteld" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "De draadloze verbinding tussen dit apparaat en de ontvanger is " "versleuteld." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "onversleuteld" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #, python-format #~ msgid "%(battery_level)s" #~ msgstr "%(battery_level)s" #, python-format #~ msgid "%(battery_percent)d%%" #~ msgstr "%(battery_percent)d%%" #~ msgid "About" #~ msgstr "Over" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the DPI button." #~ msgstr "Pas het aantal dpi aan door de dpi-knop ingedrukt te houden " #~ "en de muis horizontaal te verplaatsen." #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "Schakel het scrollwiel automatisch over van regel-voor-" #~ "regelmodus naar vrij scrollen.\n" #~ "Bij een waarde van 0 is vrij scrollen altijd ingeschakeld; bij een " #~ "waarde van 50 nooit." #~ msgid "Battery information unknown." #~ msgstr "Geen batterij-informatie beschikbaar." #~ msgid "Click to allow changes." #~ msgstr "Klik om wijzigingen toe te staan." #~ msgid "Click to prevent changes." #~ msgstr "Klik om wijzigingen te voorkomen." #~ msgid "Count" #~ msgstr "Teller" #~ msgid "DPI Sliding Adjustment" #~ msgstr "DPI aanpassen middels verplaatsen" #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Schakelt scrollen met het duimwiel op Linux uit." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Schakelt scrollen met het scrollwiel op Linux uit." #~ msgid "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "Bekijk voor meer informatie de installatiehulp op https://" #~ "pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Er is een Logitech-ontvanger aangetroffen ('%s'), maar " #~ "Solaar is niet gemachtigd om deze te tonen." #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID++-modus voor horizontaal scrollen met het duimwiel." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++-modus voor verticaal scrollen." #~ msgid "High Resolution Scrolling" #~ msgstr "Scrollen met hoge resolutie" #~ msgid "High Resolution Wheel Invert" #~ msgstr "Andersom scrollen met hoge resolutie" #~ msgid "High-sensitivity wheel invert mode for vertical scroll." #~ msgstr "Hogegevoeligheidsmodus voor andersom verticaal scrollen." #~ msgid "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "Als het apparaat reeds is ingeschakeld,\n" #~ "schakel het dan uit en weer in." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Als het apparaat al is ingeschakeld, schakel het dan uit en " #~ "weer in." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Als u Solaar nét heeft geïnstalleerd, plug dan de ontvanger " #~ "opnieuw in." #~ msgid "Make the key or button send HID++ notifications (which " #~ "trigger Solaar rules but are otherwise ignored)." #~ msgstr "Laat de toets of knop een HID++-melding versturen (welke " #~ "Solaar's regels volgen, maar verder genegeerd worden)." #~ msgid "No Logitech receiver found" #~ msgstr "Geen Logitech-ontvanger aangetroffen" #~ msgid "Quit" #~ msgstr "Afsluiten" #~ msgid "Scroll Wheel HID++ Scrolling" #~ msgstr "HID++-scrollen" #~ msgid "Scroll Wheel Rachet" #~ msgstr "Vrij scrollen" #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Toont de status van apparaten die verbonden\n" #~ "zijn middels draadloze Logitech-ontvangers." #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar is afhankelijk van een udev-bestand dat niet aanwezig " #~ "is" #, python-format #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Dit apparaat ondersteunt slechts %d gekoppeld apparaat/" #~ "apparaten." #~ msgid "The receiver was unplugged." #~ msgstr "De ontvanger is niet meer aanwezig." #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "De draadloze verbinding tussen dit apparaat en de ontvanger " #~ "is onversleuteld.\n" #~ "\n" #~ "Bij aanwijsapparaten (zoals muizen, trackballs en trackpads) vormt " #~ "dit een heel klein veiligheidsrisico.\n" #~ "\n" #~ "Echter, bij tekstinvoerapparaten (zoals (numerieke) toetsenborden) " #~ "vormt dit een groot probleem\n" #~ "omdat ingevoerde tekst stiekem kan worden uitgelezen door derden " #~ "binnen handbereik." #~ msgid "Thumb Wheel HID++ Scrolling" #~ msgstr "HID++-scrollen met duimwiel" #~ msgid "Top-most coordinate." #~ msgstr "Het bovenste coördinaat." #~ msgid "height" #~ msgstr "hoogte" #~ msgid "top" #~ msgstr "boven" #~ msgid "unknown" #~ msgstr "onbekend" #~ msgid "width" #~ msgstr "breedte" Solaar-1.1.20/po/nn.po000066400000000000000000001753311522022367600144240ustar00rootroot00000000000000# Norwegian Nynorsk translations for solaar package. # Copyright (C) 2020 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2020. # John Erling Blad , 2020-2024. # msgid "" msgstr "" "Project-Id-Version: solaar 1.0.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-31 01:42+0100\n" "PO-Revision-Date: 2024-10-31 02:20+0100\n" "Last-Translator: John Erling Blad \n" "Language-Team: \n" "Language: nb\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1)\n" "X-Generator: Gtranslator 47.0\n" #: lib/logitech_receiver/base_usb.py:48 msgid "Bolt Receiver" msgstr "Bolt mottakar" #: lib/logitech_receiver/base_usb.py:60 msgid "Unifying Receiver" msgstr "Unifying mottakar" #: lib/logitech_receiver/base_usb.py:71 lib/logitech_receiver/base_usb.py:83 #: lib/logitech_receiver/base_usb.py:96 lib/logitech_receiver/base_usb.py:109 msgid "Nano Receiver" msgstr "Nano mottakar" #: lib/logitech_receiver/base_usb.py:121 msgid "Lightspeed Receiver" msgstr "Lightspeed mottakar" #: lib/logitech_receiver/base_usb.py:131 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 27 Mhz mottakar" #: lib/logitech_receiver/common.py:648 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batteri: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:651 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batteri: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:962 #: lib/logitech_receiver/settings_templates.py:294 msgid "Disabled" msgstr "Avslått" #: lib/logitech_receiver/hidpp20.py:963 msgid "Static" msgstr "Statisk" #: lib/logitech_receiver/hidpp20.py:964 msgid "Pulse" msgstr "Puls" #: lib/logitech_receiver/hidpp20.py:965 msgid "Cycle" msgstr "Syklus" #: lib/logitech_receiver/hidpp20.py:966 msgid "Boot" msgstr "Boot" #: lib/logitech_receiver/hidpp20.py:967 msgid "Demo" msgstr "Demo" #: lib/logitech_receiver/hidpp20.py:969 msgid "Breathe" msgstr "Pust" #: lib/logitech_receiver/hidpp20.py:972 msgid "Ripple" msgstr "Krusning" #: lib/logitech_receiver/hidpp20.py:973 msgid "Decomposition" msgstr "Dekomponering" #: lib/logitech_receiver/hidpp20.py:974 msgid "Signature1" msgstr "Signatur1" #: lib/logitech_receiver/hidpp20.py:975 msgid "Signature2" msgstr "Signatur2" #: lib/logitech_receiver/hidpp20.py:976 msgid "CycleS" msgstr "SyklusS" #: lib/logitech_receiver/hidpp20.py:1040 msgid "Unknown Location" msgstr "Ukjend lokasjon" #: lib/logitech_receiver/hidpp20.py:1041 msgid "Primary" msgstr "Primær" #: lib/logitech_receiver/hidpp20.py:1042 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:1043 msgid "Left Side" msgstr "Venstre side" #: lib/logitech_receiver/hidpp20.py:1044 msgid "Right Side" msgstr "Høgre side" #: lib/logitech_receiver/hidpp20.py:1045 msgid "Combined" msgstr "Kombinert" #: lib/logitech_receiver/hidpp20.py:1046 msgid "Primary 1" msgstr "Primær 1" #: lib/logitech_receiver/hidpp20.py:1047 msgid "Primary 2" msgstr "Primær 2" #: lib/logitech_receiver/hidpp20.py:1048 msgid "Primary 3" msgstr "Primær 3" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Primary 4" msgstr "Primær 4" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Primary 5" msgstr "Primær 5" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Primary 6" msgstr "Primær 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "tom" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "kritisk" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "låg" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "middels" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "god" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "full" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "utlading" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "opplading" #: lib/logitech_receiver/i18n.py:37 msgid "charging" msgstr "lader" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "lader ikkje" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "nesten full" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "ladet" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "langsom lading" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "batterifeil" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "termisk feil" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "feil" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "standard" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "rask" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "langsom" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "eininga svarte ikkje" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "eininga er ikkje støtta" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "for mange einingar" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "sekvens timeout" #: lib/logitech_receiver/i18n.py:54 msgid "Firmware" msgstr "Fastvare" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Oppstartslaster" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Maskinvare" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Anna" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Venstreknapp" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Høgreknapp" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Midtknapp" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Tlbakeknapp" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Framoverknapp" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Rørsleknapp" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Smart skift" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "DPI-bryter" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Venstre-tilt" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Høgre-tilt" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Venstre-klikk" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Høgre-klikk" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Midtknapp for mus" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Tilbakeknapp for mus" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Framoverknapp for mus" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Navigering med rørsleknapp" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Venstre rulleknapp for mus" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Høgre rulleknapp for mus" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "nedtrykt" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "utløyst" #: lib/logitech_receiver/notifications.py:86 #: lib/logitech_receiver/notifications.py:138 msgid "pairing lock is closed" msgstr "parlåsen er lukka" #: lib/logitech_receiver/notifications.py:86 #: lib/logitech_receiver/notifications.py:138 msgid "pairing lock is open" msgstr "parlåsen er open" #: lib/logitech_receiver/notifications.py:103 msgid "discovery lock is closed" msgstr "oppdagelseslåsen er lukka" #: lib/logitech_receiver/notifications.py:103 msgid "discovery lock is open" msgstr "oppdagelseslåsen er open" #: lib/logitech_receiver/notifications.py:232 lib/solaar/listener.py:247 msgid "connected" msgstr "tilkopla" #: lib/logitech_receiver/notifications.py:232 lib/solaar/listener.py:247 msgid "disconnected" msgstr "fråkopla" #: lib/logitech_receiver/notifications.py:258 msgid "unpaired" msgstr "upara" #: lib/logitech_receiver/notifications.py:305 msgid "powered on" msgstr "påslått" #: lib/logitech_receiver/receiver.py:383 msgid "No paired devices." msgstr "Inga para eining." #: lib/logitech_receiver/receiver.py:385 lib/solaar/ui/window.py:590 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s para eining." msgstr[1] "%(count)s para einingar." #: lib/logitech_receiver/settings.py:614 msgid "register" msgstr "register" #: lib/logitech_receiver/settings.py:628 lib/logitech_receiver/settings.py:663 msgid "feature" msgstr "karakteristikk" #: lib/logitech_receiver/settings_templates.py:133 msgid "Swap Fx function" msgstr "Bytt Fx-funksjon" #: lib/logitech_receiver/settings_templates.py:136 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Viss aktivert, vil F1–F12-tastane aktivera sin spesialfunksjon,\n" "og du må halda FN-tasten nede for å aktivera deira standardfunksjon." #: lib/logitech_receiver/settings_templates.py:141 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Viss deaktivert, vil F1–F12-tastane aktivera sin standardfunksjon,\n" "og du må holde FN-tasten nede for å aktivere deira spesialfunksjon." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Håndpåvisning" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Slå på belysning når hendene er over tastaturet." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "Mjuk rulling med rullehjul" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:405 #: lib/logitech_receiver/settings_templates.py:434 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Høgsensitiv modus for vertikal rulling med hjulet." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Siderulling" #: lib/logitech_receiver/settings_templates.py:167 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Viss deaktivert; blir trykt hjula sidevegs så sendast ein tilpassa " "knapphending\n" "i staden for standard siderulling." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "Følsomhet (DPI – eldre mus)" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:977 #: lib/logitech_receiver/settings_templates.py:1005 msgid "Mouse movement sensitivity" msgstr "Sensibilitet for musrørsler" #: lib/logitech_receiver/settings_templates.py:251 msgid "Backlight Timed" msgstr "Tidfesta bakgrunnslys" #: lib/logitech_receiver/settings_templates.py:252 #: lib/logitech_receiver/settings_templates.py:392 msgid "Set illumination time for keyboard." msgstr "Still inn belysningstid for tastatur." #: lib/logitech_receiver/settings_templates.py:263 msgid "Backlight" msgstr "Bakbelysning" #: lib/logitech_receiver/settings_templates.py:264 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Lysnivå på tastaturet. Endringar som er gjorde, blir berre brukte i manuell " "modus." #: lib/logitech_receiver/settings_templates.py:296 msgid "Automatic" msgstr "Automatisk" #: lib/logitech_receiver/settings_templates.py:298 msgid "Manual" msgstr "Manuell" #: lib/logitech_receiver/settings_templates.py:300 msgid "Enabled" msgstr "Påslått" #: lib/logitech_receiver/settings_templates.py:306 msgid "Backlight Level" msgstr "Bakgrunnslysnivå" #: lib/logitech_receiver/settings_templates.py:307 msgid "Illumination level on keyboard when in Manual mode." msgstr "Lysnivå på tastaturet i manuell modus." #: lib/logitech_receiver/settings_templates.py:364 msgid "Backlight Delay Hands Out" msgstr "Forseinking på bakgrunnsbelysning når hendene blir fjerna" #: lib/logitech_receiver/settings_templates.py:365 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Forseinking i sekund til bakgrunnsbelysninga tonar ut når hendene er borte " "frå tastaturet." #: lib/logitech_receiver/settings_templates.py:373 msgid "Backlight Delay Hands In" msgstr "Forseinking på bakgrunnsbelysning når hendene er nære" #: lib/logitech_receiver/settings_templates.py:374 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Forseinking i sekund til bakgrunnsbelysninga tonar ut når hendene er nære " "tastaturet." #: lib/logitech_receiver/settings_templates.py:382 msgid "Backlight Delay Powered" msgstr "Forseinking på bakgrunnsbelysning når straumforsynt" #: lib/logitech_receiver/settings_templates.py:383 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Forseinking i sekund til bakgrunnsbelysninga tonar ut med ekstern " "straumforsyning." #: lib/logitech_receiver/settings_templates.py:391 msgid "Backlight (Seconds)" msgstr "Bakgrunnslys (sekund)" #: lib/logitech_receiver/settings_templates.py:403 msgid "Scroll Wheel High Resolution" msgstr "Høgopplausleg rullehjul" #: lib/logitech_receiver/settings_templates.py:407 #: lib/logitech_receiver/settings_templates.py:436 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Sett til å ignorera viss rullinga er unormalt rask eller sakte" #: lib/logitech_receiver/settings_templates.py:414 #: lib/logitech_receiver/settings_templates.py:445 msgid "Scroll Wheel Diversion" msgstr "Omdirigering for rullehjul" #: lib/logitech_receiver/settings_templates.py:416 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Få rullehjulet til å senda LOWRES_WHEEL HID++-varslar (som utløyser Solaar-" "reglar, men som elles blir ignorert)." #: lib/logitech_receiver/settings_templates.py:423 msgid "Scroll Wheel Direction" msgstr "Retning på rullehjul" #: lib/logitech_receiver/settings_templates.py:424 msgid "Invert direction for vertical scroll with wheel." msgstr "Inverter retning for vertikal rulling med hjul." #: lib/logitech_receiver/settings_templates.py:432 msgid "Scroll Wheel Resolution" msgstr "Oppløysing på rullehjul" #: lib/logitech_receiver/settings_templates.py:447 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Få rullehjulet til å senda HIRS_WHEEL HID++-varslar (som utløyser Solaar-" "reglar, men som elles blir ignorert)." #: lib/logitech_receiver/settings_templates.py:456 msgid "Sensitivity (Pointer Speed)" msgstr "Følsomhet (pekerfart)" #: lib/logitech_receiver/settings_templates.py:457 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Fartsmultiplikator for mus (256 er normal multiplikator)." #: lib/logitech_receiver/settings_templates.py:467 msgid "Thumb Wheel Diversion" msgstr "Omdirigering for tommelhjul" #: lib/logitech_receiver/settings_templates.py:469 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Få tommelhjulet til å senda THUMB_WHEEL HID++-varslar (som utløyser Solaar-" "reglar, men som elles blir ignorert)." #: lib/logitech_receiver/settings_templates.py:478 msgid "Thumb Wheel Direction" msgstr "Retning på tommelhjul" #: lib/logitech_receiver/settings_templates.py:479 msgid "Invert thumb wheel scroll direction." msgstr "Inverter rulleretning for tommelhjul." #: lib/logitech_receiver/settings_templates.py:499 msgid "Onboard Profiles" msgstr "Innebygde profilar" #: lib/logitech_receiver/settings_templates.py:500 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Aktiver ein innebygd profil, som kontrollerer rapporthyppigheit, " "sensibilitet og knappehandlingar" #: lib/logitech_receiver/settings_templates.py:544 #: lib/logitech_receiver/settings_templates.py:577 msgid "Report Rate" msgstr "Rapporthyppigheit" #: lib/logitech_receiver/settings_templates.py:546 #: lib/logitech_receiver/settings_templates.py:579 msgid "Frequency of device movement reports" msgstr "Frekvensen til rapportar om einingsrørsler" #: lib/logitech_receiver/settings_templates.py:546 #: lib/logitech_receiver/settings_templates.py:579 #: lib/logitech_receiver/settings_templates.py:1005 #: lib/logitech_receiver/settings_templates.py:1379 #: lib/logitech_receiver/settings_templates.py:1410 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "Kan trenga at innebygde profilar blir sette til avslått for å vera effektive." #: lib/logitech_receiver/settings_templates.py:607 msgid "Divert crown events" msgstr "Omdiriger krone-hendingar" #: lib/logitech_receiver/settings_templates.py:608 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Få krona til å senda CROWN HID++-varslar (som utløyser Solaar-reglar, men " "som elles blir ignorert)." #: lib/logitech_receiver/settings_templates.py:616 msgid "Crown smooth scroll" msgstr "Glatt krone-rulling" #: lib/logitech_receiver/settings_templates.py:617 msgid "Set crown smooth scroll" msgstr "Still inn glatt krone-rulling" #: lib/logitech_receiver/settings_templates.py:625 msgid "Divert G and M Keys" msgstr "Omdiriger G- og M-tastar" #: lib/logitech_receiver/settings_templates.py:626 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Få G- og M-tastane til å senda HID++-varslar (som utløyser Solaar-reglar, " "men som elles blir ignorerte)." #: lib/logitech_receiver/settings_templates.py:640 msgid "Scroll Wheel Ratcheted" msgstr "Rullehjul sperrehaka" #: lib/logitech_receiver/settings_templates.py:641 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Byt musehjulet mellom fartskontrollert sperrehake og alltid frittløpende." #: lib/logitech_receiver/settings_templates.py:643 msgid "Freespinning" msgstr "Frittløpende" #: lib/logitech_receiver/settings_templates.py:643 msgid "Ratcheted" msgstr "Sperrehake" #: lib/logitech_receiver/settings_templates.py:650 msgid "Scroll Wheel Ratchet Speed" msgstr "Rullehjul sperrehakefart" #: lib/logitech_receiver/settings_templates.py:652 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Bruk musehjulfarten til å byta mellom sperrehake og frittløpende.\n" "Musehjulet er alltid sett til 50." #: lib/logitech_receiver/settings_templates.py:701 msgid "Key/Button Actions" msgstr "Taste-/knappehandling" #: lib/logitech_receiver/settings_templates.py:703 msgid "Change the action for the key or button." msgstr "Endre handlinga for ein tast eller knapp." #: lib/logitech_receiver/settings_templates.py:705 msgid "Overridden by diversion." msgstr "Overstyrt av omdirigering." #: lib/logitech_receiver/settings_templates.py:707 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Endring av viktige handlingar (til dømes venstre musknapp) kan resultera i " "eit ubrukande system." #: lib/logitech_receiver/settings_templates.py:882 msgid "Key/Button Diversion" msgstr "Taste-/knappeomdirigering" #: lib/logitech_receiver/settings_templates.py:883 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "Få nøkkelen eller knappen til å senda HID++-varslar (omdirigert) eller " "initier muserørsler eller glidande Dpi" #: lib/logitech_receiver/settings_templates.py:886 #: lib/logitech_receiver/settings_templates.py:887 #: lib/logitech_receiver/settings_templates.py:888 msgid "Diverted" msgstr "Omdirigert" #: lib/logitech_receiver/settings_templates.py:886 #: lib/logitech_receiver/settings_templates.py:887 msgid "Mouse Gestures" msgstr "Muserørsler" #: lib/logitech_receiver/settings_templates.py:886 #: lib/logitech_receiver/settings_templates.py:887 #: lib/logitech_receiver/settings_templates.py:888 msgid "Regular" msgstr "Vanleg" #: lib/logitech_receiver/settings_templates.py:886 msgid "Sliding DPI" msgstr "Glidande DPI" #: lib/logitech_receiver/settings_templates.py:976 #: lib/logitech_receiver/settings_templates.py:1004 msgid "Sensitivity (DPI)" msgstr "Følsomheit (DPI)" #: lib/logitech_receiver/settings_templates.py:1081 msgid "Sensitivity Switching" msgstr "Følsomheitsbyte" #: lib/logitech_receiver/settings_templates.py:1083 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Byt gjeldande følsomheit og tidlegare følsomheit når tasten eller knappen " "blir trykt.\n" "Viss det ikkje er nokon tidlegare følsomheit, sett berre gjeldande følsomheit" #: lib/logitech_receiver/settings_templates.py:1087 msgid "Off" msgstr "Av" #: lib/logitech_receiver/settings_templates.py:1118 msgid "Disable keys" msgstr "Slå av tastar" #: lib/logitech_receiver/settings_templates.py:1119 msgid "Disable specific keyboard keys." msgstr "Slå av spesifikke tastaturtastar." #: lib/logitech_receiver/settings_templates.py:1122 #, python-format msgid "Disables the %s key." msgstr "Slår av %s-tasten." #: lib/logitech_receiver/settings_templates.py:1135 #: lib/logitech_receiver/settings_templates.py:1192 msgid "Set OS" msgstr "Sett OS" #: lib/logitech_receiver/settings_templates.py:1136 #: lib/logitech_receiver/settings_templates.py:1193 msgid "Change keys to match OS." msgstr "Endre tastar så dei stemmer med OS-et." #: lib/logitech_receiver/settings_templates.py:1205 msgid "Change Host" msgstr "Endre tjener" #: lib/logitech_receiver/settings_templates.py:1206 msgid "Switch connection to a different host" msgstr "Endre koplinga til ein annan tenar" #: lib/logitech_receiver/settings_templates.py:1230 msgid "Performs a left click." msgstr "Utfører eit venstreklikk." #: lib/logitech_receiver/settings_templates.py:1230 msgid "Single tap" msgstr "Enkeltklikk" #: lib/logitech_receiver/settings_templates.py:1231 msgid "Performs a right click." msgstr "Utfører eit høgreklikk." #: lib/logitech_receiver/settings_templates.py:1231 msgid "Single tap with two fingers" msgstr "Enkelt trykk med to fingrar" #: lib/logitech_receiver/settings_templates.py:1232 msgid "Single tap with three fingers" msgstr "Enkelt trykk med tre fingrar" #: lib/logitech_receiver/settings_templates.py:1236 msgid "Double tap" msgstr "Dobbeltklikk" #: lib/logitech_receiver/settings_templates.py:1236 msgid "Performs a double click." msgstr "Utfører eit dobbeltklikk" #: lib/logitech_receiver/settings_templates.py:1237 msgid "Double tap with two fingers" msgstr "Dobbeltklikk med to fingrar" #: lib/logitech_receiver/settings_templates.py:1238 msgid "Double tap with three fingers" msgstr "Dobbeltklikk med to fingrar" #: lib/logitech_receiver/settings_templates.py:1241 msgid "Drags items by dragging the finger after double tapping." msgstr "Dra element med fingeren etter dobbeltklikk." #: lib/logitech_receiver/settings_templates.py:1241 msgid "Tap and drag" msgstr "Klikk og dra" #: lib/logitech_receiver/settings_templates.py:1243 msgid "Tap and drag with two fingers" msgstr "Klikk og dra med to fingrar" #: lib/logitech_receiver/settings_templates.py:1244 msgid "Drags items by dragging the fingers after double tapping." msgstr "Dra element med fingrane etter dobbeltklikk." #: lib/logitech_receiver/settings_templates.py:1246 msgid "Tap and drag with three fingers" msgstr "Klikk og dra med tre fingrar" #: lib/logitech_receiver/settings_templates.py:1249 msgid "Suppress tap and edge gestures" msgstr "Undertrykk klikk- og kantrørsler" #: lib/logitech_receiver/settings_templates.py:1250 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Slår av klikk- og kantrørsler (svarer til å trykkja Fn+Venstreklikk)." #: lib/logitech_receiver/settings_templates.py:1252 msgid "Scroll with one finger" msgstr "Rull med ein finger" #: lib/logitech_receiver/settings_templates.py:1252 #: lib/logitech_receiver/settings_templates.py:1253 #: lib/logitech_receiver/settings_templates.py:1256 msgid "Scrolls." msgstr "Rullar" #: lib/logitech_receiver/settings_templates.py:1253 #: lib/logitech_receiver/settings_templates.py:1256 msgid "Scroll with two fingers" msgstr "Rull med to fingre" #: lib/logitech_receiver/settings_templates.py:1254 msgid "Scroll horizontally with two fingers" msgstr "Rull horisontalt med to fingrar" #: lib/logitech_receiver/settings_templates.py:1254 msgid "Scrolls horizontally." msgstr "Rull horisontalt." #: lib/logitech_receiver/settings_templates.py:1255 msgid "Scroll vertically with two fingers" msgstr "Rull vertikalt med to fingrar" #: lib/logitech_receiver/settings_templates.py:1255 msgid "Scrolls vertically." msgstr "Rull vertikalt." #: lib/logitech_receiver/settings_templates.py:1257 msgid "Inverts the scrolling direction." msgstr "Inverterer rulleretninga." #: lib/logitech_receiver/settings_templates.py:1257 msgid "Natural scrolling" msgstr "Naturleg rulling" #: lib/logitech_receiver/settings_templates.py:1258 msgid "Enables the thumbwheel." msgstr "Aktiverer tommelhjulet." #: lib/logitech_receiver/settings_templates.py:1258 msgid "Thumbwheel" msgstr "Tommelhjul" #: lib/logitech_receiver/settings_templates.py:1269 #: lib/logitech_receiver/settings_templates.py:1273 msgid "Swipe from the top edge" msgstr "Sveip frå øvre kant" #: lib/logitech_receiver/settings_templates.py:1270 msgid "Swipe from the left edge" msgstr "Sveip frå venstre kant" #: lib/logitech_receiver/settings_templates.py:1271 msgid "Swipe from the right edge" msgstr "Sveip frå høgre kant" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Swipe from the bottom edge" msgstr "Sveip frå nedre kant" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Swipe two fingers from the left edge" msgstr "Sveip to fingrar frå venstre kant" #: lib/logitech_receiver/settings_templates.py:1275 msgid "Swipe two fingers from the right edge" msgstr "Sveip to fingrar frå høgre kant" #: lib/logitech_receiver/settings_templates.py:1276 msgid "Swipe two fingers from the bottom edge" msgstr "Sveip to fingrar frå nedre kant" #: lib/logitech_receiver/settings_templates.py:1277 msgid "Swipe two fingers from the top edge" msgstr "Sveip to fingrar frå øvre kant" #: lib/logitech_receiver/settings_templates.py:1278 #: lib/logitech_receiver/settings_templates.py:1282 msgid "Pinch to zoom out; spread to zoom in." msgstr "Knip for å zooma ut; sprei for å zooma inn." #: lib/logitech_receiver/settings_templates.py:1278 msgid "Zoom with two fingers." msgstr "Zoom med to fingrar." #: lib/logitech_receiver/settings_templates.py:1279 msgid "Pinch to zoom out." msgstr "Knip for å zooma ut." #: lib/logitech_receiver/settings_templates.py:1280 msgid "Spread to zoom in." msgstr "Sprei for å zooma inn." #: lib/logitech_receiver/settings_templates.py:1281 msgid "Zoom with three fingers." msgstr "Zoom med tre fingrar." #: lib/logitech_receiver/settings_templates.py:1282 msgid "Zoom with two fingers" msgstr "Zoom med to fingrar" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Pixel zone" msgstr "Pikselsone" #: lib/logitech_receiver/settings_templates.py:1301 msgid "Ratio zone" msgstr "Forholdssone" #: lib/logitech_receiver/settings_templates.py:1302 msgid "Scale factor" msgstr "Skalafaktor" #: lib/logitech_receiver/settings_templates.py:1302 msgid "Sets the cursor speed." msgstr "Still inn markørfarten." #: lib/logitech_receiver/settings_templates.py:1306 msgid "Left" msgstr "Venstre" #: lib/logitech_receiver/settings_templates.py:1306 msgid "Left-most coordinate." msgstr "Koordinat lengst til venstre." #: lib/logitech_receiver/settings_templates.py:1307 msgid "Bottom" msgstr "Nederst" #: lib/logitech_receiver/settings_templates.py:1307 msgid "Bottom coordinate." msgstr "Nederste koordinat." #: lib/logitech_receiver/settings_templates.py:1308 msgid "Width" msgstr "Breidde" #: lib/logitech_receiver/settings_templates.py:1308 msgid "Width." msgstr "Breidde." #: lib/logitech_receiver/settings_templates.py:1309 msgid "Height" msgstr "Høgde" #: lib/logitech_receiver/settings_templates.py:1309 msgid "Height." msgstr "Høgde." #: lib/logitech_receiver/settings_templates.py:1310 msgid "Cursor speed." msgstr "Markørhastigheit." #: lib/logitech_receiver/settings_templates.py:1310 msgid "Scale" msgstr "Skala" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Gestures" msgstr "Rørsler" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Tweak the mouse/touchpad behaviour." msgstr "Juster musas/berøringsplata åtferd." #: lib/logitech_receiver/settings_templates.py:1333 msgid "Gestures Diversion" msgstr "Omdirigering av rørsler" #: lib/logitech_receiver/settings_templates.py:1334 msgid "Divert mouse/touchpad gestures." msgstr "Omdiriger musas/berøringsflatas rørsler." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Gesture params" msgstr "Parametrar for rørsler" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Endre numeriske parametrar for ei mus/berøringsplate." #: lib/logitech_receiver/settings_templates.py:1375 msgid "M-Key LEDs" msgstr "M-tast LED-ene" #: lib/logitech_receiver/settings_templates.py:1377 msgid "Control the M-Key LEDs." msgstr "Kontroller M-tast LED-ene." #: lib/logitech_receiver/settings_templates.py:1381 #: lib/logitech_receiver/settings_templates.py:1412 msgid "May need G Keys diverted to be effective." msgstr "Kan trenga omdirigering av G-tastar for å vera effektivt." #: lib/logitech_receiver/settings_templates.py:1387 #, python-format msgid "Lights up the %s key." msgstr "Lyser opp %s-tasten." #: lib/logitech_receiver/settings_templates.py:1406 msgid "MR-Key LED" msgstr "MR-tast LED" #: lib/logitech_receiver/settings_templates.py:1408 msgid "Control the MR-Key LED." msgstr "Kontroller MR-tast LED." #: lib/logitech_receiver/settings_templates.py:1429 msgid "Persistent Key/Button Mapping" msgstr "Vedvarande tast-/knapptilordning" #: lib/logitech_receiver/settings_templates.py:1431 msgid "Permanently change the mapping for the key or button." msgstr "Endre tilordninga for tasten eller knappen permanent." #: lib/logitech_receiver/settings_templates.py:1433 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Endring av viktige tastar eller knappar (som venstre museknapp) kan " "resultera i eit ubrukeleg system." #: lib/logitech_receiver/settings_templates.py:1490 msgid "Sidetone" msgstr "Sidetone" #: lib/logitech_receiver/settings_templates.py:1491 msgid "Set sidetone level." msgstr "Still inn sidetone nivå." #: lib/logitech_receiver/settings_templates.py:1500 msgid "Equalizer" msgstr "Equalizer" #: lib/logitech_receiver/settings_templates.py:1501 msgid "Set equalizer levels." msgstr "Still inn equalizer nivå." #: lib/logitech_receiver/settings_templates.py:1523 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1529 msgid "Power Management" msgstr "Strømstyring" #: lib/logitech_receiver/settings_templates.py:1530 msgid "Power off in minutes (0 for never)." msgstr "Slå av i minutt (0 for aldri)." #: lib/logitech_receiver/settings_templates.py:1541 msgid "Brightness Control" msgstr "Lysstyrkekontroll" #: lib/logitech_receiver/settings_templates.py:1542 msgid "Control overall brightness" msgstr "Kontroller den generelle lysstyrken" #: lib/logitech_receiver/settings_templates.py:1585 #: lib/logitech_receiver/settings_templates.py:1639 msgid "LED Control" msgstr "LED-kontroll" #: lib/logitech_receiver/settings_templates.py:1586 #: lib/logitech_receiver/settings_templates.py:1640 msgid "Switch control of LED zones between device and Solaar" msgstr "Byt kontroll av LED-soner mellom eining og Solaar" #: lib/logitech_receiver/settings_templates.py:1601 #: lib/logitech_receiver/settings_templates.py:1650 msgid "LED Zone Effects" msgstr "LED-soneeffektar" #: lib/logitech_receiver/settings_templates.py:1602 #: lib/logitech_receiver/settings_templates.py:1651 msgid "LED Control needs to be set to Solaar to be effective." msgstr "LED-kontroll må setjast til Solaar for å vera effektiv." #: lib/logitech_receiver/settings_templates.py:1602 #: lib/logitech_receiver/settings_templates.py:1651 msgid "Set effect for LED Zone" msgstr "Still inn effekt for LED-sone" #: lib/logitech_receiver/settings_templates.py:1605 msgid "Speed" msgstr "Fart" #: lib/logitech_receiver/settings_templates.py:1606 msgid "Period" msgstr "Periode" #: lib/logitech_receiver/settings_templates.py:1607 msgid "Intensity" msgstr "Intensitet" #: lib/logitech_receiver/settings_templates.py:1608 msgid "Ramp" msgstr "Stigning" #: lib/logitech_receiver/settings_templates.py:1624 msgid "LEDs" msgstr "LEDs" #: lib/logitech_receiver/settings_templates.py:1661 msgid "Per-key Lighting" msgstr "Lys for kvar tast" #: lib/logitech_receiver/settings_templates.py:1662 msgid "Control per-key lighting." msgstr "Kontrollar lys for kvar tast." #: lib/solaar/ui/__init__.py:117 msgid "Another Solaar process is already running so just expose its window" msgstr "Ein annan Solaar-prosess køyrer allereie, så berre vis vindauget" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Administrerer Logitech-mottakarar,\n" "tastatur, mus og nettbrett." #: lib/solaar/ui/about/model.py:62 msgid "Additional Programming" msgstr "Ekstra programmering" #: lib/solaar/ui/about/model.py:63 msgid "GUI design" msgstr "GUI utsjånad" #: lib/solaar/ui/about/model.py:65 msgid "Testing" msgstr "Testing" #: lib/solaar/ui/about/model.py:73 msgid "Logitech documentation" msgstr "Logitech dokumentasjon" #: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87 #: lib/solaar/ui/window.py:188 msgid "Unpair" msgstr "Fjern paring" #: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:107 msgid "Cancel" msgstr "Avbryt" #: lib/solaar/ui/common.py:35 msgid "Permissions error" msgstr "Rettighetsfeil" #: lib/solaar/ui/common.py:37 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Fann ein Logitech-mottakar eller eining (%s), men hadde ikkje løyve til å " "opna han." #: lib/solaar/ui/common.py:39 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Viss du nettopp har installert Solaar, kan du prøva å kopla frå mottakaren " "eller eininga og deretter kopla ho til igjen." #: lib/solaar/ui/common.py:42 msgid "Cannot connect to device error" msgstr "Kan ikkje kopla til eining-feil" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Fann ein Logitech-mottakar eller -eining på %s, men oppdaga ein feil når han " "vart tilkopla." #: lib/solaar/ui/common.py:46 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Prøv å kopla frå eininga og deretter kopla ho til igjen eller slå ho av og " "på igjen." #: lib/solaar/ui/common.py:49 msgid "Unpairing failed" msgstr "Kunne ikkje bryta paringa" #: lib/solaar/ui/common.py:51 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Mislykkast med å bryta paret %{device} og %{receiver}." #: lib/solaar/ui/common.py:56 msgid "The receiver returned an error, with no further details." msgstr "Mottakaren rapporterte ein feil, utan fleire detaljar." #: lib/solaar/ui/config_panel.py:228 msgid "Complete - ENTER to change" msgstr "Fullfør - ENTER for å endra" #: lib/solaar/ui/config_panel.py:228 msgid "Incomplete" msgstr "Ufullstendig" #: lib/solaar/ui/config_panel.py:475 lib/solaar/ui/config_panel.py:527 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d verdi" msgstr[1] "%d verdiar" #: lib/solaar/ui/config_panel.py:609 msgid "Changes allowed" msgstr "Endringar tillatne" #: lib/solaar/ui/config_panel.py:610 msgid "No changes allowed" msgstr "Ingen endringar tillatne" #: lib/solaar/ui/config_panel.py:611 msgid "Ignore this setting" msgstr "Ignorer denne innstillinga" #: lib/solaar/ui/config_panel.py:655 msgid "Working" msgstr "Suksess" #: lib/solaar/ui/config_panel.py:658 msgid "Read/write operation failed." msgstr "Lese-/skriveoperasjonen mislykkast." #: lib/solaar/ui/desktop_notifications.py:114 msgid "unspecified reason" msgstr "uspesifisert årsak" #: lib/solaar/ui/diversion_rules.py:69 msgid "Built-in rules" msgstr "Faste reglar" #: lib/solaar/ui/diversion_rules.py:69 msgid "User-defined rules" msgstr "Brukardefinerte reglar" #: lib/solaar/ui/diversion_rules.py:71 lib/solaar/ui/diversion_rules.py:1089 msgid "Rule" msgstr "Regel" #: lib/solaar/ui/diversion_rules.py:72 lib/solaar/ui/diversion_rules.py:348 #: lib/solaar/ui/diversion_rules.py:475 msgid "Sub-rule" msgstr "Underregel" #: lib/solaar/ui/diversion_rules.py:74 msgid "[empty]" msgstr "[tom]" #: lib/solaar/ui/diversion_rules.py:98 msgid "Make changes permanent?" msgstr "Gjera endringar permanente?" #: lib/solaar/ui/diversion_rules.py:103 msgid "Yes" msgstr "Ja" #: lib/solaar/ui/diversion_rules.py:105 msgid "No" msgstr "Nei" #: lib/solaar/ui/diversion_rules.py:110 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Viss du vel Nei, vil endringar gå tapt når Solaar blir lukka." #: lib/solaar/ui/diversion_rules.py:239 msgid "Paste here" msgstr "Lim inn her" #: lib/solaar/ui/diversion_rules.py:241 msgid "Paste above" msgstr "Lim inn ovanfor" #: lib/solaar/ui/diversion_rules.py:243 msgid "Paste below" msgstr "Lim inn nedanfor" #: lib/solaar/ui/diversion_rules.py:249 msgid "Paste rule here" msgstr "Lim inn regel her" #: lib/solaar/ui/diversion_rules.py:251 msgid "Paste rule above" msgstr "Lim inn regel ovanfor" #: lib/solaar/ui/diversion_rules.py:253 msgid "Paste rule below" msgstr "Lim inn regel nedanfor" #: lib/solaar/ui/diversion_rules.py:257 msgid "Paste rule" msgstr "Lim inn regel" #: lib/solaar/ui/diversion_rules.py:272 msgid "Insert here" msgstr "Set inn her" #: lib/solaar/ui/diversion_rules.py:274 msgid "Insert above" msgstr "Set inn ovanfor" #: lib/solaar/ui/diversion_rules.py:276 msgid "Insert below" msgstr "Set inn nedanfor" #: lib/solaar/ui/diversion_rules.py:282 msgid "Insert new rule here" msgstr "Set inn ny regel her" #: lib/solaar/ui/diversion_rules.py:284 msgid "Insert new rule above" msgstr "Set inn ny regel ovanfor" #: lib/solaar/ui/diversion_rules.py:286 msgid "Insert new rule below" msgstr "Set inn ny regel nedanfor" #: lib/solaar/ui/diversion_rules.py:313 msgid "Flatten" msgstr "Utfalte" #: lib/solaar/ui/diversion_rules.py:346 msgid "Insert" msgstr "Set inn" #: lib/solaar/ui/diversion_rules.py:349 lib/solaar/ui/diversion_rules.py:477 #: lib/solaar/ui/diversion_rules.py:1121 msgid "Or" msgstr "Eller" #: lib/solaar/ui/diversion_rules.py:350 lib/solaar/ui/diversion_rules.py:476 #: lib/solaar/ui/diversion_rules.py:1107 msgid "And" msgstr "Og" #: lib/solaar/ui/diversion_rules.py:352 msgid "Condition" msgstr "Vilkår" #: lib/solaar/ui/diversion_rules.py:354 lib/solaar/ui/rule_conditions.py:145 msgid "Feature" msgstr "Karakteristikk" #: lib/solaar/ui/diversion_rules.py:355 lib/solaar/ui/rule_conditions.py:179 msgid "Report" msgstr "Rapport" #: lib/solaar/ui/diversion_rules.py:356 lib/solaar/ui/rule_conditions.py:60 msgid "Process" msgstr "Prosess" #: lib/solaar/ui/diversion_rules.py:357 msgid "Mouse process" msgstr "Musprosess" #: lib/solaar/ui/diversion_rules.py:358 lib/solaar/ui/rule_conditions.py:216 msgid "Modifiers" msgstr "Modifikatorer" #: lib/solaar/ui/diversion_rules.py:359 lib/solaar/ui/rule_conditions.py:268 msgid "Key" msgstr "Tast" #: lib/solaar/ui/diversion_rules.py:360 lib/solaar/ui/rule_conditions.py:309 msgid "KeyIsDown" msgstr "TastErNede" #: lib/solaar/ui/diversion_rules.py:361 lib/solaar/ui/diversion_rules.py:1414 msgid "Active" msgstr "Aktiv" #: lib/solaar/ui/diversion_rules.py:362 lib/solaar/ui/diversion_rules.py:1372 #: lib/solaar/ui/diversion_rules.py:1423 lib/solaar/ui/diversion_rules.py:1470 msgid "Device" msgstr "Eining" #: lib/solaar/ui/diversion_rules.py:363 lib/solaar/ui/diversion_rules.py:1449 msgid "Host" msgstr "Vert" #: lib/solaar/ui/diversion_rules.py:364 lib/solaar/ui/diversion_rules.py:1489 msgid "Setting" msgstr "Innstilling" #: lib/solaar/ui/diversion_rules.py:365 lib/solaar/ui/rule_conditions.py:324 #: lib/solaar/ui/rule_conditions.py:373 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:366 lib/solaar/ui/rule_conditions.py:498 msgid "Test bytes" msgstr "Test bytes" #: lib/solaar/ui/diversion_rules.py:367 lib/solaar/ui/rule_conditions.py:599 msgid "Mouse Gesture" msgstr "Muserørsle" #: lib/solaar/ui/diversion_rules.py:371 msgid "Action" msgstr "Handling" #: lib/solaar/ui/diversion_rules.py:373 lib/solaar/ui/rule_actions.py:131 msgid "Key press" msgstr "Tastetrykk" #: lib/solaar/ui/diversion_rules.py:374 lib/solaar/ui/rule_actions.py:182 msgid "Mouse scroll" msgstr "Muserulling" #: lib/solaar/ui/diversion_rules.py:375 lib/solaar/ui/rule_actions.py:243 msgid "Mouse click" msgstr "Museklikk" #: lib/solaar/ui/diversion_rules.py:376 msgid "Set" msgstr "Still inn" #: lib/solaar/ui/diversion_rules.py:377 lib/solaar/ui/rule_actions.py:313 msgid "Execute" msgstr "Utfør" #: lib/solaar/ui/diversion_rules.py:378 lib/solaar/ui/diversion_rules.py:1152 msgid "Later" msgstr "Seinare" #: lib/solaar/ui/diversion_rules.py:407 msgid "Insert new rule" msgstr "Set inn ny regel" #: lib/solaar/ui/diversion_rules.py:427 lib/solaar/ui/rule_actions.py:74 #: lib/solaar/ui/rule_actions.py:272 lib/solaar/ui/rule_conditions.py:546 msgid "Delete" msgstr "Slett" #: lib/solaar/ui/diversion_rules.py:449 msgid "Negate" msgstr "Omvendt" #: lib/solaar/ui/diversion_rules.py:473 msgid "Wrap with" msgstr "Pakk inn med" #: lib/solaar/ui/diversion_rules.py:503 msgid "Cut" msgstr "KLipp ut" #: lib/solaar/ui/diversion_rules.py:519 msgid "Paste" msgstr "Lim inn" #: lib/solaar/ui/diversion_rules.py:525 msgid "Copy" msgstr "Kopier" #: lib/solaar/ui/diversion_rules.py:534 msgid "Solaar Rule Editor" msgstr "Solaar regel editor" #: lib/solaar/ui/diversion_rules.py:634 msgid "Save changes" msgstr "Lagre endringar" #: lib/solaar/ui/diversion_rules.py:639 msgid "Discard changes" msgstr "Forkast endringar" #: lib/solaar/ui/diversion_rules.py:1070 msgid "This editor does not support the selected rule component yet." msgstr "Denne editoren støttar førebels ikkje den valde regelkomponenten." #: lib/solaar/ui/diversion_rules.py:1132 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Talet på sekund med forseinking. Forseinking mellom 0 og 1 blir gjort med " "høgare presisjon." #: lib/solaar/ui/diversion_rules.py:1170 msgid "Not" msgstr "Ikkje" #: lib/solaar/ui/diversion_rules.py:1201 msgid "Toggle" msgstr "Veksle" #: lib/solaar/ui/diversion_rules.py:1202 msgid "True" msgstr "Sann" #: lib/solaar/ui/diversion_rules.py:1203 msgid "False" msgstr "Falsk" #: lib/solaar/ui/diversion_rules.py:1216 msgid "Unsupported setting" msgstr "Innstillinga blir ikkje støtta" #: lib/solaar/ui/diversion_rules.py:1378 lib/solaar/ui/diversion_rules.py:1397 #: lib/solaar/ui/diversion_rules.py:1476 lib/solaar/ui/diversion_rules.py:1731 #: lib/solaar/ui/diversion_rules.py:1749 msgid "Originating device" msgstr "Kildeeining" #: lib/solaar/ui/diversion_rules.py:1410 msgid "Device is active and its settings can be changed." msgstr "Eininga er aktiv og innstillingane kan endrast." #: lib/solaar/ui/diversion_rules.py:1419 msgid "Device that originated the current notification." msgstr "Eininga som gav det gjeldande varselet." #: lib/solaar/ui/diversion_rules.py:1432 msgid "Name of host computer." msgstr "Namn på vertsmaskin." #: lib/solaar/ui/diversion_rules.py:1503 msgid "Value" msgstr "Verdi" #: lib/solaar/ui/diversion_rules.py:1512 msgid "Item" msgstr "Punkt" #: lib/solaar/ui/diversion_rules.py:1791 msgid "Change setting on device" msgstr "Endre innstilling på eining" #: lib/solaar/ui/diversion_rules.py:1807 msgid "Setting on device" msgstr "Innstilling på eining" #: lib/solaar/ui/pair_window.py:37 lib/solaar/ui/pair_window.py:165 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: par ny eining" #: lib/solaar/ui/pair_window.py:39 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt-mottakarar er berre kompatible med Bolt-einingar." #: lib/solaar/ui/pair_window.py:41 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Trykk på samankoplingsknappen eller -tasten til samankoplingslampa blinkar " "raskt." #: lib/solaar/ui/pair_window.py:44 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Unifying-mottakarar er berre kompatible med Unifying-einingar." #: lib/solaar/ui/pair_window.py:46 msgid "Other receivers are only compatible with a few devices." msgstr "Andre mottakarar er berre kompatible med nokre få einingar." #: lib/solaar/ui/pair_window.py:48 msgid "For most devices, turn on the device you want to pair." msgstr "For dei fleste einingar slår du på eininga du vil para." #: lib/solaar/ui/pair_window.py:49 msgid "If the device is already turned on, turn it off and on again." msgstr "Viss eininga allereie er pålått, slå ho av og på igjen." #: lib/solaar/ui/pair_window.py:51 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "Eininga må ikkje parast med ein pålått mottakar i nærleiken." #: lib/solaar/ui/pair_window.py:54 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "For einingar med fleire kanalar, trykk, hald og slipp knappen for kanalen du " "ønskjer å para\n" "eller bruk kanalbrytarknappen for å velja ein kanal og trykk, hald og slepp " "kanalbrytarknappen." #: lib/solaar/ui/pair_window.py:61 msgid "The channel indicator light should be blinking rapidly." msgstr "Kanalindikatorlampa skal blinka raskt." #: lib/solaar/ui/pair_window.py:65 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Denne mottakaren har %d gjenståande paring." msgstr[1] "" "\n" "\n" "Denne mottakaren har %d gjenståande paringar." #: lib/solaar/ui/pair_window.py:71 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Kansellering no vil ikkje bruka opp ein paring." #: lib/solaar/ui/pair_window.py:166 #, python-format msgid "Enter passcode on %(name)s." msgstr "Skriv inn passordet på %(name)s." #: lib/solaar/ui/pair_window.py:169 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Skriv inn %(passcode)s og trykk deretter på enter-tasten." #: lib/solaar/ui/pair_window.py:174 msgid "left" msgstr "venstre" #: lib/solaar/ui/pair_window.py:174 msgid "right" msgstr "høgre" #: lib/solaar/ui/pair_window.py:176 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Trykk %(code)s\n" "og trykk deretter på venstre og høgre knapp samtidig." #: lib/solaar/ui/pair_window.py:219 msgid "The wireless link is not encrypted" msgstr "Den trådlause koplinga er ukryptert" #: lib/solaar/ui/pair_window.py:224 msgid "Found a new device:" msgstr "Fant ny eining:" #: lib/solaar/ui/pair_window.py:245 msgid "Pairing failed" msgstr "Paringa feila" #: lib/solaar/ui/pair_window.py:247 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Forsikre deg om at eininga er innan rekkevidde, og at den er tilstrekkeleg " "opplada." #: lib/solaar/ui/pair_window.py:249 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "" "Ei ny eining vart påvist, men ho er ikkje kompatibel med denne mottakaren." #: lib/solaar/ui/pair_window.py:251 msgid "More paired devices than receiver can support." msgstr "Fleir para einingar enn mottakaren kan støtte." #: lib/solaar/ui/pair_window.py:253 msgid "No further details are available about the error." msgstr "Ingen ytterligare detaljar er tilgjengeleg om feilen." #: lib/solaar/ui/rule_actions.py:48 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuler ein chorded (?) tast, klikk eller trykk ned eller slipp.\n" "På Wayland krev dette skrivetilgang til /dev/uinput." #: lib/solaar/ui/rule_actions.py:53 msgid "Add key" msgstr "Legg til tast" #: lib/solaar/ui/rule_actions.py:56 msgid "Click" msgstr "Klikk" #: lib/solaar/ui/rule_actions.py:59 msgid "Depress" msgstr "Nedtrykk" #: lib/solaar/ui/rule_actions.py:62 msgid "Release" msgstr "Utløs" #: lib/solaar/ui/rule_actions.py:146 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuler ei muserulling.\n" "På Wayland krev dette skrivetilgang til /dev/uinput." #: lib/solaar/ui/rule_actions.py:202 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simuler eit museklikk.\n" "På Wayland krev dette skrivetilgang til /dev/uinput." #: lib/solaar/ui/rule_actions.py:205 msgid "Button" msgstr "Knapp" #: lib/solaar/ui/rule_actions.py:206 msgid "Count and Action" msgstr "Antall og handling" #: lib/solaar/ui/rule_actions.py:255 msgid "Execute a command with arguments." msgstr "Utfør ein kommando med argument." #: lib/solaar/ui/rule_actions.py:258 msgid "Add argument" msgstr "Legg til argument" #: lib/solaar/ui/rule_conditions.py:43 msgid "X11 active process. For use in X11 only." msgstr "X11 aktiv prosess. Berre til bruk i X11." #: lib/solaar/ui/rule_conditions.py:73 msgid "X11 mouse process. For use in X11 only." msgstr "X11-museprosess. Berre til bruk i X11." #: lib/solaar/ui/rule_conditions.py:90 msgid "MouseProcess" msgstr "MusProsess" #: lib/solaar/ui/rule_conditions.py:114 msgid "Feature name of notification triggering rule processing." msgstr "Funksjonsnamn på varsel som utløyste regelbehandling." #: lib/solaar/ui/rule_conditions.py:160 msgid "Report number of notification triggering rule processing." msgstr "Rapportnummer for varsling som utløyser regelbehandling." #: lib/solaar/ui/rule_conditions.py:192 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Aktive tastaturmodifikatorer. Ikkje alltid tilgjengeleg i Wayland." #: lib/solaar/ui/rule_conditions.py:232 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Omdirigert tast eller knapp som er trykt eller sleppt.\n" "Bruk innstillingane for omdirigering av tast/knapp og omdiriger G-tastar for " "å vidaresenda tastar og knappar." #: lib/solaar/ui/rule_conditions.py:241 msgid "Key down" msgstr "Tast ned" #: lib/solaar/ui/rule_conditions.py:244 msgid "Key up" msgstr "Tast opp" #: lib/solaar/ui/rule_conditions.py:284 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Omdirigert tast eller knapp er nede.\n" "Bruk innstillingane for omdirigering av tast/knapp og omdirigerte G-tastar " "for å vidaresenda tastar og knappar." #: lib/solaar/ui/rule_conditions.py:322 msgid "Test condition on notification triggering rule processing." msgstr "Testvilkår på varsel som utløyser regelbehandling." #: lib/solaar/ui/rule_conditions.py:326 msgid "Parameter" msgstr "Parameter" #: lib/solaar/ui/rule_conditions.py:399 msgid "begin (inclusive)" msgstr "byrj (inklusiv)" #: lib/solaar/ui/rule_conditions.py:400 msgid "end (exclusive)" msgstr "slutt (eksklusiv)" #: lib/solaar/ui/rule_conditions.py:408 msgid "range" msgstr "område" #: lib/solaar/ui/rule_conditions.py:411 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/rule_conditions.py:412 msgid "maximum" msgstr "maksimum" #: lib/solaar/ui/rule_conditions.py:414 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "byte %(0)d til %(1)d, fra %(2)d til %(3)d" #: lib/solaar/ui/rule_conditions.py:417 lib/solaar/ui/rule_conditions.py:418 msgid "mask" msgstr "maske" #: lib/solaar/ui/rule_conditions.py:419 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "byte %(0)d til %(1)d, maske %(2)d" #: lib/solaar/ui/rule_conditions.py:428 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Bit- eller områdetest på bytes i varselmelding som utløyste regelbehandling." #: lib/solaar/ui/rule_conditions.py:438 msgid "type" msgstr "type" #: lib/solaar/ui/rule_conditions.py:526 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Muserørsle med valfri startknapp etterfølgd av null eller fleire muserørsler." #: lib/solaar/ui/rule_conditions.py:531 msgid "Add movement" msgstr "Legg til rørsle" #: lib/solaar/ui/tray.py:49 msgid "No supported device found" msgstr "Ingen støtta einingar er funne" #: lib/solaar/ui/tray.py:54 lib/solaar/ui/window.py:308 #, python-format msgid "About %s" msgstr "Om %s" #: lib/solaar/ui/tray.py:55 lib/solaar/ui/window.py:306 #, python-format msgid "Quit %s" msgstr "Avslutt %s" #: lib/solaar/ui/tray.py:270 lib/solaar/ui/tray.py:278 msgid "no receiver" msgstr "ingen mottakar" #: lib/solaar/ui/tray.py:291 lib/solaar/ui/tray.py:296 msgid "offline" msgstr "avslått" #: lib/solaar/ui/tray.py:294 msgid "no status" msgstr "ingen status" #: lib/solaar/ui/window.py:90 msgid "Scanning" msgstr "Søker" #: lib/solaar/ui/window.py:121 msgid "Battery" msgstr "Batteri" #: lib/solaar/ui/window.py:124 msgid "Wireless Link" msgstr "Trådlaus kopling" #: lib/solaar/ui/window.py:128 msgid "Lighting" msgstr "Belysning" #: lib/solaar/ui/window.py:162 msgid "Show Technical Details" msgstr "Vis tekniske detaljar" #: lib/solaar/ui/window.py:178 msgid "Pair new device" msgstr "Par ny eining" #: lib/solaar/ui/window.py:196 msgid "Select a device" msgstr "Vel ei eining" #: lib/solaar/ui/window.py:311 msgid "Rule Editor" msgstr "Regel editor" #: lib/solaar/ui/window.py:504 msgid "Path" msgstr "Sti" #: lib/solaar/ui/window.py:506 msgid "USB ID" msgstr "USB-ID" #: lib/solaar/ui/window.py:509 lib/solaar/ui/window.py:511 #: lib/solaar/ui/window.py:526 lib/solaar/ui/window.py:528 msgid "Serial" msgstr "Seriell" #: lib/solaar/ui/window.py:515 msgid "Index" msgstr "Indeks" #: lib/solaar/ui/window.py:517 msgid "Wireless PID" msgstr "Trådlaus-PID" #: lib/solaar/ui/window.py:519 msgid "Product ID" msgstr "Produkt-ID" #: lib/solaar/ui/window.py:521 msgid "Protocol" msgstr "Protokoll" #: lib/solaar/ui/window.py:521 msgid "Unknown" msgstr "Ukjend" #: lib/solaar/ui/window.py:523 msgid "Polling rate" msgstr "Spørjarate" #: lib/solaar/ui/window.py:530 msgid "Unit ID" msgstr "Einings-ID" #: lib/solaar/ui/window.py:544 msgid "Notifications" msgstr "Varslar" #: lib/solaar/ui/window.py:588 msgid "No device paired." msgstr "Inga eining para." #: lib/solaar/ui/window.py:597 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Inntil %(max_count)s eining kan bli para med denne mottakaren." msgstr[1] "Inntil %(max_count)s einingar kan bli para med denne mottakaren." #: lib/solaar/ui/window.py:608 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Denne mottakaren har %d gjenståande paring." msgstr[1] "Denne mottakaren har %d gjenståande paringer." #: lib/solaar/ui/window.py:665 msgid "Battery Voltage" msgstr "Batterispenning" #: lib/solaar/ui/window.py:667 msgid "Voltage reported by battery" msgstr "Spenning rapportert av batteri" #: lib/solaar/ui/window.py:669 msgid "Battery Level" msgstr "Batterinivå" #: lib/solaar/ui/window.py:671 msgid "Approximate level reported by battery" msgstr "Omtrentleg nivå rapportert frå batteri" #: lib/solaar/ui/window.py:678 lib/solaar/ui/window.py:680 msgid "next reported " msgstr "neste rapportert " #: lib/solaar/ui/window.py:681 msgid " and next level to be reported." msgstr " og neste nivå som blir rapportert." #: lib/solaar/ui/window.py:697 msgid "encrypted" msgstr "kryptert" #: lib/solaar/ui/window.py:699 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Den trådlause tilkoplinga mellom eininga og mottakaren er kryptert." #: lib/solaar/ui/window.py:701 msgid "not encrypted" msgstr "ikkje kryptert" #: lib/solaar/ui/window.py:705 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "Den trådlause koplinga mellom denne eininga og mottakaren er ikkje " "kryptert.\n" "Dette er eit tryggingsproblem for peikeeiningar, og eit stort " "tryggingsproblem for einingar for tekstinndata." #: lib/solaar/ui/window.py:721 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "" #~ "\n" #~ "\n" #~ "This receiver has %d pairing(s) remaining." #~ msgstr "" #~ "\n" #~ "\n" #~ "Denne mottakaren har %d gjenståande paringar." #, python-format #~ msgid "%(rate)d ms (%(rate_hz)dHz)" #~ msgstr "%(rate)d ms (%(rate_hz)dHz)" #~ msgid "Actions" #~ msgstr "Handlingar" #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always locked at 50" #~ msgstr "" #~ "Byt mushjulet automatisk mellom sperre- og frispinnmodus.\n" #~ "Mushjulet er alltid fritt på 0, og blir alltid låste på 50" #, python-format #~ msgid "Battery: %(level)s" #~ msgstr "Batteri: %(level)s" #, python-format #~ msgid "Battery: %(percent)d%%" #~ msgstr "Batteri: %(percent)d%%" #~ msgid "Divert G Keys" #~ msgstr "Omdiriger G tastar" #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Slår i praksis av tommelrulling i Linux." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Slår i praksis av hjulrulling i Linux." #~ msgid "" #~ "Enable onboard profiles, which often control report rate and keyboard " #~ "lighting" #~ msgstr "" #~ "Aktiver ein innebygd profil, som kontrollerer rapporthyppigheit, " #~ "følsomheit, og knappehandlingar" #~ msgid "" #~ "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "" #~ "For meir informasjon, sjå Solaar-installasjonsanvisningene\n" #~ "på https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "" #~ "Found a Logitech Receiver (%s), but did not have permission to open it." #~ msgstr "Fant ein Logitech-mottakar (%s), men manglar rettar til å opna den." #~ msgid "Frequency of device polling, in milliseconds" #~ msgstr "Frekvensen til rapportar om einingsrørsler" #~ msgid "HID++ Scrolling" #~ msgstr "HID++ rulling" #~ msgid "HID++ Thumb Scrolling" #~ msgstr "HID++ tommelrulling" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID++ modus for horisontal rulling med tommelhjulet." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++ modus for vertikal rulling med hjulet." #~ msgid "High Resolution Scrolling" #~ msgstr "Høgoppløyseleg rulling" #~ msgid "High Resolution Wheel Invert" #~ msgstr "Inverter høg rulleoppløysning" #~ msgid "High-sensitivity wheel invert direction for vertical scroll." #~ msgstr "Inverter retning for høg vertikal rulleoppløysning." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Viss eininga allereie er slått på, slå ho av og på igjen." #~ msgid "" #~ "If you've just installed Solaar, try removing the receiver and plugging " #~ "it back in." #~ msgstr "" #~ "Viss du nettopp har installert Solaar, forsøk å fjerna mottakaren og " #~ "plugg den inn igjen." #~ msgid "Invert thumb scroll direction." #~ msgstr "Inverter retning på tommelrulling." #, python-format #~ msgid "Lighting: %(level)s lux" #~ msgstr "Belysning: %(level)s lux" #~ msgid "" #~ "Make G keys send GKEY HID++ notifications (which trigger Solaar rules but " #~ "are otherwise ignored)." #~ msgstr "" #~ "Få G-tastane til å senda HID++-varslar (som utløyser Solaar-reglar, men " #~ "som elles blir ignorerte)." #~ msgid "No Logitech receiver found" #~ msgstr "Ingen Logitech-mottakar funnet" #~ msgid "Number of seconds to delay." #~ msgstr "Talet på sekund med forseinking." #~ msgid "Only one device can be paired to this receiver." #~ msgstr "Berre éi eining kan parast med denne mottakaren." #~ msgid "Polling Rate (ms)" #~ msgstr "Rapporthyppigheit" #~ msgid "" #~ "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "" #~ "Viser status for einingar tilkopla\n" #~ "via trådlause Logitech-mottakere." #~ msgid "Smooth Scrolling" #~ msgstr "Mjuk rulling" #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar er avhengig av ein udev-fil som ikkje finnast" #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Mottakaren kan kun støtte %d para eining(er)." #~ msgid "The receiver was unplugged." #~ msgstr "Mottakaren vart fjerna." #~ msgid "" #~ "The wireless link between this device and its receiver is not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices (keyboards, " #~ "numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties within " #~ "range." #~ msgstr "" #~ "Den trådlause koplinga mellom denne eininga og mottakaren er ukryptert.\n" #~ "\n" #~ "For peikeeeiningar (mus, styrekuler, styreflater) er dette eit mindre " #~ "tryggingsproblem.\n" #~ "\n" #~ "Det er likevel eit viktig tryggingsproblem for tekstinndataeiningar " #~ "(tastatur, numpads),\n" #~ "fordi maskinskriven tekst kan bli sniffa umerka av tredjepartar innan " #~ "rekkevidde." #~ msgid "This receiver has %d pairing(s) remaining." #~ msgstr "Denne mottakaren har %d gjenståande paring(er)." #~ msgid "Thumb Scroll Invert" #~ msgstr "Inverter tommelrulling" #~ msgid "Turn illumination on or off on keyboard." #~ msgstr "Slå belysning på eller av for tastaturet." #~ msgid "Turn on the device you want to pair." #~ msgstr "Slå på eininga du ynsker å pare." #~ msgid "USB id" #~ msgstr "USB-id" #~ msgid "Unexpected device number (%s) in notification %s." #~ msgstr "Uventa einingsnummer (%s) i varsel %s." #~ msgid "Wheel Resolution" #~ msgstr "Hjuloppløysning" #~ msgid "height" #~ msgstr "høgde" #~ msgid "last known" #~ msgstr "sist kjend" #~ msgid "next " #~ msgstr "neste " #~ msgid "none" #~ msgstr "ingen" #~ msgid "unknown" #~ msgstr "ukjend" #~ msgid "width" #~ msgstr "breidde" Solaar-1.1.20/po/pl.po000066400000000000000000002254371522022367600144270ustar00rootroot00000000000000# Polish translations for solaar package. # Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2013. # msgid "" msgstr "" "Project-Id-Version: solaar 1.1.18\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-05-24 20:04+0200\n" "PO-Revision-Date: 2026-05-24 20:43+0200\n" "Last-Translator: Matthaiks\n" "Language-Team: none\n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.9\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Odbiornik Bolt" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Odbiornik Unifying" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Odbiornik Nano" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Odbiornik Lightspeed" #: lib/logitech_receiver/base_usb.py:136 msgid "EX100 Receiver 27 Mhz" msgstr "Odbiornik EX100 27 MHz" #: lib/logitech_receiver/common.py:698 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Akumulator: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:701 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Akumulator: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1189 lib/logitech_receiver/hidpp20.py:1222 #: lib/logitech_receiver/hidpp20.py:1250 msgid "Cycle" msgstr "Cykl" #: lib/logitech_receiver/hidpp20.py:1190 msgid "Right" msgstr "W prawo" #: lib/logitech_receiver/hidpp20.py:1191 msgid "Down" msgstr "W dół" #: lib/logitech_receiver/hidpp20.py:1192 msgid "Center Out" msgstr "Ze środka" #: lib/logitech_receiver/hidpp20.py:1193 msgid "In" msgstr "Do wewnątrz" #: lib/logitech_receiver/hidpp20.py:1194 msgid "Out" msgstr "Na zewnątrz" #: lib/logitech_receiver/hidpp20.py:1195 #: lib/logitech_receiver/settings_templates.py:1398 msgid "Left" msgstr "W lewo" #: lib/logitech_receiver/hidpp20.py:1196 msgid "Up" msgstr "W górę" #: lib/logitech_receiver/hidpp20.py:1197 msgid "Center In" msgstr "Do środka" #: lib/logitech_receiver/hidpp20.py:1218 #: lib/logitech_receiver/settings_templates.py:344 msgid "Disabled" msgstr "Wyłączone" #: lib/logitech_receiver/hidpp20.py:1219 msgid "Static" msgstr "Statyczne" #: lib/logitech_receiver/hidpp20.py:1220 msgid "Pulse" msgstr "Puls" #: lib/logitech_receiver/hidpp20.py:1229 lib/logitech_receiver/hidpp20.py:1255 msgid "Wave" msgstr "Fala" #: lib/logitech_receiver/hidpp20.py:1233 msgid "Boot" msgstr "Rozruch" #: lib/logitech_receiver/hidpp20.py:1234 msgid "Demo" msgstr "Demo" #: lib/logitech_receiver/hidpp20.py:1236 msgid "Breathe" msgstr "Oddech" #: lib/logitech_receiver/hidpp20.py:1241 lib/logitech_receiver/hidpp20.py:1262 msgid "Ripple" msgstr "Plusk" #: lib/logitech_receiver/hidpp20.py:1246 msgid "Decomposition" msgstr "Dekompozycja" #: lib/logitech_receiver/hidpp20.py:1247 msgid "Signature1" msgstr "Podpis1" #: lib/logitech_receiver/hidpp20.py:1248 msgid "Signature2" msgstr "Podpis2" #: lib/logitech_receiver/hidpp20.py:1268 msgid "Dim" msgstr "Przyciemnienie" #: lib/logitech_receiver/hidpp20.py:1340 msgid "Unknown Location" msgstr "Nieznana lokalizacja" #: lib/logitech_receiver/hidpp20.py:1341 #: lib/logitech_receiver/settings_templates.py:2619 #: lib/logitech_receiver/settings_templates.py:2907 #: lib/logitech_receiver/settings_templates.py:3647 msgid "Primary" msgstr "Podstawowy" #: lib/logitech_receiver/hidpp20.py:1342 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:1343 msgid "Left Side" msgstr "Lewa strona" #: lib/logitech_receiver/hidpp20.py:1344 msgid "Right Side" msgstr "Prawa strona" #: lib/logitech_receiver/hidpp20.py:1345 msgid "Combined" msgstr "�ączony" #: lib/logitech_receiver/hidpp20.py:1346 msgid "Primary 1" msgstr "Podstawowy 1" #: lib/logitech_receiver/hidpp20.py:1347 msgid "Primary 2" msgstr "Podstawowy 2" #: lib/logitech_receiver/hidpp20.py:1348 msgid "Primary 3" msgstr "Podstawowy 3" #: lib/logitech_receiver/hidpp20.py:1349 msgid "Primary 4" msgstr "Podstawowy 4" #: lib/logitech_receiver/hidpp20.py:1350 msgid "Primary 5" msgstr "Podstawowy 5" #: lib/logitech_receiver/hidpp20.py:1351 msgid "Primary 6" msgstr "Podstawowy 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "pusty" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "krytyczny" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "niski" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "przeciętny" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "dobry" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "pełny" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "rozładowywanie" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "ładowanie" #: lib/logitech_receiver/i18n.py:37 msgid "charging" msgstr "ładowanie" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "brak ładowania" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "prawie pełny" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "naładowany" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "powolne ładowanie" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "nieodpowiedni akumulator" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "błąd termiczny" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "błąd" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "standardowe" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "szybkie" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "powolne" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "upłynął limit czasu urządzenia" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "urządzenie nie jest obsługiwane" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "za dużo urządzeń" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "upłynął limit czasu sekwencji" #: lib/logitech_receiver/i18n.py:54 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Sprzęt" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Inne" #: lib/logitech_receiver/i18n.py:59 #: lib/logitech_receiver/settings_templates.py:4336 msgid "Left Button" msgstr "Przycisk lewy" #: lib/logitech_receiver/i18n.py:60 #: lib/logitech_receiver/settings_templates.py:4336 msgid "Right Button" msgstr "Przycisk prawy" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Przycisk środkowy" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Przycisk wstecz" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Przycisk dalej" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Przycisk gestów myszy" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "SmartShift" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Przełącznik DPI" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Pochylenie w lewo" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Pochylenie w prawo" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Kliknięcie LPM" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Kliknięcie PPM" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Przycisk środkowy myszy" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Przycisk wstecz myszy" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Przycisk dalej myszy" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Nawigacja przyciskiem gestów" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Lewy przycisk kółka myszy" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Prawy przycisk kółka myszy" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "wciśnięty" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "zwolniony" #: lib/logitech_receiver/notifications.py:157 lib/solaar/listener.py:350 msgid "connected" msgstr "podłączone" #: lib/logitech_receiver/notifications.py:157 lib/solaar/listener.py:350 msgid "disconnected" msgstr "rozłączone" #: lib/logitech_receiver/notifications.py:183 msgid "unpaired" msgstr "niesparowane" #: lib/logitech_receiver/notifications.py:232 msgid "powered on" msgstr "włączone" #: lib/logitech_receiver/notifications.py:284 msgid "ADC measurement notification" msgstr "powiadomienie o pomiarze ADC" #: lib/logitech_receiver/notifications.py:486 #: lib/logitech_receiver/notifications.py:542 msgid "pairing lock is closed" msgstr "blokada sparowania jest zamknięta" #: lib/logitech_receiver/notifications.py:486 #: lib/logitech_receiver/notifications.py:542 msgid "pairing lock is open" msgstr "blokada sparowania jest otwarta" #: lib/logitech_receiver/notifications.py:505 msgid "discovery lock is closed" msgstr "blokada wykrywania jest zamknięta" #: lib/logitech_receiver/notifications.py:505 msgid "discovery lock is open" msgstr "blokada wykrywania jest otwarta" #: lib/logitech_receiver/receiver.py:462 msgid "No paired devices." msgstr "Brak sparowanych urządzeń." #: lib/logitech_receiver/receiver.py:464 lib/solaar/ui/window.py:612 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s sparowane urządzenie." msgstr[1] "%(count)s sparowane urządzenia." msgstr[2] "%(count)s sparowanych urządzeń." #: lib/logitech_receiver/settings.py:621 msgid "register" msgstr "rejestr" #: lib/logitech_receiver/settings.py:635 lib/logitech_receiver/settings.py:673 msgid "feature" msgstr "funkcja" #: lib/logitech_receiver/settings_templates.py:183 msgid "Swap Fx function" msgstr "Zamień funkcję Fx" #: lib/logitech_receiver/settings_templates.py:186 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Gdy włączona, po wciśnięciu klawiszy F1..F12 aktywowana zostanie\n" "ich funkcja pomocnicza. Aby aktywować funkcję standardową, należy\n" "przytrzymać klawisz FN." #: lib/logitech_receiver/settings_templates.py:191 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Gdy wyłączona, po wciśnięciu klawiszy F1..F12 aktywowana zostanie\n" "ich funkcja standardowa. Aby aktywować funkcję pomocniczą, należy\n" "przytrzymać klawisz FN." #: lib/logitech_receiver/settings_templates.py:199 msgid "Hand Detection" msgstr "Wykrywanie dłoni" #: lib/logitech_receiver/settings_templates.py:200 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Włącz podświetlenie, gdy dłonie znajdą się nad klawiaturą." #: lib/logitech_receiver/settings_templates.py:207 msgid "Scroll Wheel Smooth Scrolling" msgstr "Płynne przewijanie kółkiem przewijania" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:455 #: lib/logitech_receiver/settings_templates.py:484 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "" "Tryb wysokiej rozdzielczości do przewijania pionowego\n" "przy użyciu kółka myszy." #: lib/logitech_receiver/settings_templates.py:215 msgid "Side Scrolling" msgstr "Przewijanie na boki" #: lib/logitech_receiver/settings_templates.py:217 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Gdy wyłączone, przesuwanie kółka na boki powoduje wysyłanie " "niestandardowych\n" "zdarzeń przycisków zamiast standardowych zdarzeń przewijania na boki." #: lib/logitech_receiver/settings_templates.py:227 msgid "Sensitivity (DPI - older mice)" msgstr "Czułość (DPI - starsze myszy)" #: lib/logitech_receiver/settings_templates.py:228 #: lib/logitech_receiver/settings_templates.py:1064 #: lib/logitech_receiver/settings_templates.py:1092 msgid "Mouse movement sensitivity" msgstr "Czułość ruchu myszy" #: lib/logitech_receiver/settings_templates.py:301 msgid "Backlight Timed" msgstr "Podświetlenie czasowe" #: lib/logitech_receiver/settings_templates.py:302 #: lib/logitech_receiver/settings_templates.py:442 msgid "Set illumination time for keyboard." msgstr "Ustaw czas podświetlenia klawiatury." #: lib/logitech_receiver/settings_templates.py:313 msgid "Backlight" msgstr "Podświetlenie" #: lib/logitech_receiver/settings_templates.py:314 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Poziom podświetlenia klawiatury. Wprowadzone zmiany zostaną zastosowane " "wyłącznie w trybie ręcznym." #: lib/logitech_receiver/settings_templates.py:346 msgid "Automatic" msgstr "Automatyczne" #: lib/logitech_receiver/settings_templates.py:348 msgid "Manual" msgstr "Ręczne" #: lib/logitech_receiver/settings_templates.py:350 msgid "Enabled" msgstr "Włączone" #: lib/logitech_receiver/settings_templates.py:356 msgid "Backlight Level" msgstr "Poziom podświetlenia" #: lib/logitech_receiver/settings_templates.py:357 msgid "Illumination level on keyboard when in Manual mode." msgstr "Poziom podświetlenia klawiatury w trybie ręcznym." #: lib/logitech_receiver/settings_templates.py:414 msgid "Backlight Delay Hands Out" msgstr "Opóźnienie podświetlenia bez rąk" #: lib/logitech_receiver/settings_templates.py:415 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Opóźnienie w sekundach, aż podświetlenie zniknie, gdy ręce będą oddalone od " "klawiatury." #: lib/logitech_receiver/settings_templates.py:423 msgid "Backlight Delay Hands In" msgstr "Opóźnienie podświetlenia z rękoma" #: lib/logitech_receiver/settings_templates.py:424 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Opóźnienie w sekundach, aż podświetlenie zniknie, gdy ręce będą blisko " "klawiatury." #: lib/logitech_receiver/settings_templates.py:432 msgid "Backlight Delay Powered" msgstr "Opóźnienie podświetlenia z zasilanem" #: lib/logitech_receiver/settings_templates.py:433 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Opóźnienie w sekundach, aż podświetlenie zaniknie przy zasilaniu zewnętrznym." #: lib/logitech_receiver/settings_templates.py:441 msgid "Backlight (Seconds)" msgstr "Podświetlenie (sekundy)" #: lib/logitech_receiver/settings_templates.py:453 msgid "Scroll Wheel High Resolution" msgstr "Wysoka rozdzielczość kółka przewijania" #: lib/logitech_receiver/settings_templates.py:457 #: lib/logitech_receiver/settings_templates.py:486 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" "Ustaw, aby ignorować, jeśli przewijanie jest nienormalnie szybkie lub wolne" #: lib/logitech_receiver/settings_templates.py:464 #: lib/logitech_receiver/settings_templates.py:495 msgid "Scroll Wheel Diversion" msgstr "Przekierowanie kółka przewijania" #: lib/logitech_receiver/settings_templates.py:466 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Spraw, aby kółko przewijania wysyłało powiadomienia LOWRES_WHEEL HID++ " "(które wyzwalają reguły Solaar, ale w przeciwnym razie są ignorowane)." #: lib/logitech_receiver/settings_templates.py:473 msgid "Scroll Wheel Direction" msgstr "Kierunek kółka przewijania" #: lib/logitech_receiver/settings_templates.py:474 msgid "Invert direction for vertical scroll with wheel." msgstr "Odwróć kierunek przewijania w pionie za pomocą kółka." #: lib/logitech_receiver/settings_templates.py:482 msgid "Scroll Wheel Resolution" msgstr "Rozdzielczość kółka przewijania" #: lib/logitech_receiver/settings_templates.py:497 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Spraw, aby kółko przewijania wysyłało powiadomienia HIRES_WHEEL HID++ (które " "wyzwalają reguły Solaar, ale w przeciwnym razie są ignorowane)." #: lib/logitech_receiver/settings_templates.py:506 msgid "Sensitivity (Pointer Speed)" msgstr "Czułość (prędkość wskaźnika)" #: lib/logitech_receiver/settings_templates.py:507 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Mnożnik prędkości myszy (256 to normalny mnożnik)." #: lib/logitech_receiver/settings_templates.py:517 msgid "Thumb Wheel Diversion" msgstr "Przekierowanie kółka obsługiwanego kciukiem" #: lib/logitech_receiver/settings_templates.py:519 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Spraw, aby kółko obsługiwane kciukiem wysyłało powiadomienia THUMB_WHEEL HID+" "+ (które wyzwalają reguły Solaar, ale w przeciwnym razie są ignorowane)." #: lib/logitech_receiver/settings_templates.py:528 msgid "Thumb Wheel Direction" msgstr "Kierunek kółka obsługiwanego kciukiem" #: lib/logitech_receiver/settings_templates.py:529 msgid "Invert thumb wheel scroll direction." msgstr "Odwróć kierunek przewijania kółkiem obsługiwanym kciukiem." #: lib/logitech_receiver/settings_templates.py:549 msgid "Onboard Profiles" msgstr "Profile wbudowane" #: lib/logitech_receiver/settings_templates.py:550 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Włącz wbudowany profil, który kontroluje częstotliwość raportowania, czułość " "i czynności przycisków" #: lib/logitech_receiver/settings_templates.py:594 #: lib/logitech_receiver/settings_templates.py:627 msgid "Report Rate" msgstr "Szybkość raportów" #: lib/logitech_receiver/settings_templates.py:596 #: lib/logitech_receiver/settings_templates.py:629 msgid "Frequency of device movement reports" msgstr "Częstotliwość raportów o ruchu urządzenia" #: lib/logitech_receiver/settings_templates.py:596 #: lib/logitech_receiver/settings_templates.py:629 #: lib/logitech_receiver/settings_templates.py:1064 #: lib/logitech_receiver/settings_templates.py:1092 #: lib/logitech_receiver/settings_templates.py:1471 #: lib/logitech_receiver/settings_templates.py:1502 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "Aby działało, może być konieczne wyłączenie profili wbudowanych." #: lib/logitech_receiver/settings_templates.py:657 msgid "Divert crown events" msgstr "Przekieruj zdarzenia korony" #: lib/logitech_receiver/settings_templates.py:658 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Spraw, aby korona wysyłała powiadomienia CROWN HID++ (które wyzwalają reguły " "Solaar, ale w przeciwnym razie są ignorowane)." #: lib/logitech_receiver/settings_templates.py:666 msgid "Crown smooth scroll" msgstr "Płynne przewijanie koroną" #: lib/logitech_receiver/settings_templates.py:667 msgid "Set crown smooth scroll" msgstr "Ustaw płynne przewijanie koroną" #: lib/logitech_receiver/settings_templates.py:675 msgid "Divert G and M Keys" msgstr "Przekieruj klawisze G i M" #: lib/logitech_receiver/settings_templates.py:676 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Spraw, aby klawisze G i M wysyłały powiadomienia HID++ (które wyzwalają " "reguły Solaar, ale w przeciwnym razie są ignorowane)." #: lib/logitech_receiver/settings_templates.py:690 msgid "Scroll Wheel Ratcheted" msgstr "Zapadkowe kółko przewijania" #: lib/logitech_receiver/settings_templates.py:691 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Przełącz kółko myszy między zapadką z kontrolowaną prędkością a zawsze " "swobodnym obrotem." #: lib/logitech_receiver/settings_templates.py:693 msgid "Freespinning" msgstr "Obrót swobodny" #: lib/logitech_receiver/settings_templates.py:693 msgid "Ratcheted" msgstr "Obrót zapadkowy" #: lib/logitech_receiver/settings_templates.py:700 msgid "Scroll Wheel Ratchet Speed" msgstr "Prędkość zapadki kółka przewijania" #: lib/logitech_receiver/settings_templates.py:702 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Użyj prędkości kółka myszy, aby przełączać się między obrotem zapadkowym a " "swobodnym.\n" "Kółko myszy jest zawsze ustawione na 50." #: lib/logitech_receiver/settings_templates.py:752 msgid "Scroll Wheel Ratchet Torque" msgstr "Moment obrotowy zapadki kółka przewijania" #: lib/logitech_receiver/settings_templates.py:753 msgid "Change the torque needed to overcome the ratchet." msgstr "Zmień moment obrotowy potrzebny do przejścia zapadki." #: lib/logitech_receiver/settings_templates.py:788 msgid "Key/Button Actions" msgstr "Czynności klawiszy/przycisków" #: lib/logitech_receiver/settings_templates.py:790 msgid "Change the action for the key or button." msgstr "Zmień czynność klawisza lub przycisku." #: lib/logitech_receiver/settings_templates.py:792 msgid "Overridden by diversion." msgstr "Omijane przez przekierowanie." #: lib/logitech_receiver/settings_templates.py:794 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Zmiana ważnych czynności (np. lewego przycisku myszy) może spowodować, że " "system będzie nieużywalny." #: lib/logitech_receiver/settings_templates.py:969 msgid "Key/Button Diversion" msgstr "Przekierowanie klawiszy/przycisków" #: lib/logitech_receiver/settings_templates.py:970 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "Spraw, aby klawisz lub przycisk wysyłał powiadomienia HID++ (przekierowany) " "lub inicjował gesty myszy lub przesuwnie DPI" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 #: lib/logitech_receiver/settings_templates.py:975 msgid "Diverted" msgstr "Przekierowany" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 msgid "Mouse Gestures" msgstr "Gesty myszy" #: lib/logitech_receiver/settings_templates.py:973 #: lib/logitech_receiver/settings_templates.py:974 #: lib/logitech_receiver/settings_templates.py:975 msgid "Regular" msgstr "Zwykły" #: lib/logitech_receiver/settings_templates.py:973 msgid "Sliding DPI" msgstr "Przesuwnie DPI" #: lib/logitech_receiver/settings_templates.py:1063 #: lib/logitech_receiver/settings_templates.py:1091 msgid "Sensitivity (DPI)" msgstr "Czułość (DPI)" #: lib/logitech_receiver/settings_templates.py:1173 msgid "Sensitivity Switching" msgstr "Przełączanie czułości" #: lib/logitech_receiver/settings_templates.py:1175 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Przełącz bieżącą czułość i zapamiętaną czułość po naciśnięciu klawisza lub " "przycisku.\n" "Jeśli nie ma zapamiętanej czułości, po prostu zapamiętaj bieżącą czułość" #: lib/logitech_receiver/settings_templates.py:1179 msgid "Off" msgstr "Wyłączone" #: lib/logitech_receiver/settings_templates.py:1210 msgid "Disable keys" msgstr "Wyłącz klawisze" #: lib/logitech_receiver/settings_templates.py:1211 msgid "Disable specific keyboard keys." msgstr "Wyłącz określone klawisze klawiatury." #: lib/logitech_receiver/settings_templates.py:1214 #, python-format msgid "Disables the %s key." msgstr "Wyłącza klawisz %s." #: lib/logitech_receiver/settings_templates.py:1227 #: lib/logitech_receiver/settings_templates.py:1284 msgid "Set OS" msgstr "Ustaw system operacyjny" #: lib/logitech_receiver/settings_templates.py:1228 #: lib/logitech_receiver/settings_templates.py:1285 msgid "Change keys to match OS." msgstr "Zmień klawisze, aby pasowały do systemu operacyjnego." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Change Host" msgstr "Zmiana hosta" #: lib/logitech_receiver/settings_templates.py:1298 msgid "Switch connection to a different host" msgstr "Przełącz połączenie na innego hosta" #: lib/logitech_receiver/settings_templates.py:1322 msgid "Performs a left click." msgstr "Wykonuje kliknięcie lewym przyciskiem myszy." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Single tap" msgstr "Pojedyncze stuknięcie" #: lib/logitech_receiver/settings_templates.py:1323 msgid "Performs a right click." msgstr "Wykonuje kliknięcie prawym przyciskiem myszy." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Single tap with two fingers" msgstr "Pojedyncze stuknięcie dwoma palcami" #: lib/logitech_receiver/settings_templates.py:1324 msgid "Single tap with three fingers" msgstr "Pojedyncze stuknięcie trzema palcami" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Double tap" msgstr "Podwójne stuknięcie" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Performs a double click." msgstr "Wykonuje podwójne kliknięcie." #: lib/logitech_receiver/settings_templates.py:1329 msgid "Double tap with two fingers" msgstr "Podwójne stuknięcie dwoma palcami" #: lib/logitech_receiver/settings_templates.py:1330 msgid "Double tap with three fingers" msgstr "Podwójne stuknięcie trzema palcami" #: lib/logitech_receiver/settings_templates.py:1333 msgid "Drags items by dragging the finger after double tapping." msgstr "" "Przeciąga elementy poprzez przeciąganie palcem po dwukrotnym stuknięciu." #: lib/logitech_receiver/settings_templates.py:1333 msgid "Tap and drag" msgstr "Stuknięcie i przeciągnięcie" #: lib/logitech_receiver/settings_templates.py:1335 msgid "Tap and drag with two fingers" msgstr "Stuknięcie i przeciągnięcie dwoma palcami" #: lib/logitech_receiver/settings_templates.py:1336 msgid "Drags items by dragging the fingers after double tapping." msgstr "" "Przeciąga elementy poprzez przeciąganie palcami po dwukrotnym stuknięciu." #: lib/logitech_receiver/settings_templates.py:1338 msgid "Tap and drag with three fingers" msgstr "Stuknięcie i przeciągnięcie trzema palcami" #: lib/logitech_receiver/settings_templates.py:1341 msgid "Suppress tap and edge gestures" msgstr "Stłumienie gestów stukania i krawędziowych" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "Wyłącza gesty stukania i krawędziowe (odpowiednik naciśnięcia Fn + lewy " "przycisk myszy)." #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scroll with one finger" msgstr "Przewijanie jednym palcem" #: lib/logitech_receiver/settings_templates.py:1344 #: lib/logitech_receiver/settings_templates.py:1345 #: lib/logitech_receiver/settings_templates.py:1348 msgid "Scrolls." msgstr "Przewija." #: lib/logitech_receiver/settings_templates.py:1345 #: lib/logitech_receiver/settings_templates.py:1348 msgid "Scroll with two fingers" msgstr "Przewijanie dwoma palcami" #: lib/logitech_receiver/settings_templates.py:1346 msgid "Scroll horizontally with two fingers" msgstr "Przewijanie w poziomie dwoma palcami" #: lib/logitech_receiver/settings_templates.py:1346 msgid "Scrolls horizontally." msgstr "Przewija w poziomie." #: lib/logitech_receiver/settings_templates.py:1347 msgid "Scroll vertically with two fingers" msgstr "Przewijanie w pionie dwoma palcami" #: lib/logitech_receiver/settings_templates.py:1347 msgid "Scrolls vertically." msgstr "Przewija w pionie." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Inverts the scrolling direction." msgstr "Odwraca kierunek przewijania." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Natural scrolling" msgstr "Przewijanie naturalne" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Enables the thumbwheel." msgstr "Włącza kółko obsługiwane kciukiem." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Thumbwheel" msgstr "Kółko obsługiwane kciukiem" #: lib/logitech_receiver/settings_templates.py:1361 #: lib/logitech_receiver/settings_templates.py:1365 msgid "Swipe from the top edge" msgstr "Przesuwanie od górnej krawędzi" #: lib/logitech_receiver/settings_templates.py:1362 msgid "Swipe from the left edge" msgstr "Przesuwanie od lewej krawędzi" #: lib/logitech_receiver/settings_templates.py:1363 msgid "Swipe from the right edge" msgstr "Przesuwanie od prawej krawędzi" #: lib/logitech_receiver/settings_templates.py:1364 msgid "Swipe from the bottom edge" msgstr "Przesuwanie od dolnej krawędzi" #: lib/logitech_receiver/settings_templates.py:1366 msgid "Swipe two fingers from the left edge" msgstr "Przesuwanie dwoma palcami od lewej krawędzi" #: lib/logitech_receiver/settings_templates.py:1367 msgid "Swipe two fingers from the right edge" msgstr "Przesuwanie dwoma palcami od prawej krawędzi" #: lib/logitech_receiver/settings_templates.py:1368 msgid "Swipe two fingers from the bottom edge" msgstr "Przesuwanie dwoma palcami od dolnej krawędzi" #: lib/logitech_receiver/settings_templates.py:1369 msgid "Swipe two fingers from the top edge" msgstr "Przesuwanie dwoma palcami od górnej krawędzi" #: lib/logitech_receiver/settings_templates.py:1370 #: lib/logitech_receiver/settings_templates.py:1374 msgid "Pinch to zoom out; spread to zoom in." msgstr "Ściśnięcie, aby pomniejszyć; rozłożenie, aby powiększyć." #: lib/logitech_receiver/settings_templates.py:1370 msgid "Zoom with two fingers." msgstr "Zoom dwoma palcami." #: lib/logitech_receiver/settings_templates.py:1371 msgid "Pinch to zoom out." msgstr "Ściśnięcie, aby pomniejszyć." #: lib/logitech_receiver/settings_templates.py:1372 msgid "Spread to zoom in." msgstr "Rozłożenie, aby powiększyć." #: lib/logitech_receiver/settings_templates.py:1373 msgid "Zoom with three fingers." msgstr "Zoom trzema palcami." #: lib/logitech_receiver/settings_templates.py:1374 msgid "Zoom with two fingers" msgstr "Zoom dwoma palcami" #: lib/logitech_receiver/settings_templates.py:1392 msgid "Pixel zone" msgstr "Strefa pikseli" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Ratio zone" msgstr "Strefa współczynnika" #: lib/logitech_receiver/settings_templates.py:1394 msgid "Scale factor" msgstr "Współczynnik skalowania" #: lib/logitech_receiver/settings_templates.py:1394 msgid "Sets the cursor speed." msgstr "Ustawia szybkość kursora." #: lib/logitech_receiver/settings_templates.py:1398 msgid "Left-most coordinate." msgstr "Współrzędna najbardziej z lewej." #: lib/logitech_receiver/settings_templates.py:1399 msgid "Bottom" msgstr "Dół" #: lib/logitech_receiver/settings_templates.py:1399 msgid "Bottom coordinate." msgstr "Współrzędna dolna." #: lib/logitech_receiver/settings_templates.py:1400 msgid "Width" msgstr "Szerokość" #: lib/logitech_receiver/settings_templates.py:1400 msgid "Width." msgstr "Szerokość." #: lib/logitech_receiver/settings_templates.py:1401 msgid "Height" msgstr "Wysokość" #: lib/logitech_receiver/settings_templates.py:1401 msgid "Height." msgstr "Wysokość." #: lib/logitech_receiver/settings_templates.py:1402 msgid "Cursor speed." msgstr "Prędkość kursora." #: lib/logitech_receiver/settings_templates.py:1402 msgid "Scale" msgstr "Skala" #: lib/logitech_receiver/settings_templates.py:1408 msgid "Gestures" msgstr "Gesty" #: lib/logitech_receiver/settings_templates.py:1409 msgid "Tweak the mouse/touchpad behaviour." msgstr "Dostosuj zachowania myszy/panelu dotykowego." #: lib/logitech_receiver/settings_templates.py:1425 msgid "Gestures Diversion" msgstr "Przekierowanie gestów" #: lib/logitech_receiver/settings_templates.py:1426 msgid "Divert mouse/touchpad gestures." msgstr "Przekieruj gesty myszy/panelu dotykowego." #: lib/logitech_receiver/settings_templates.py:1442 msgid "Gesture params" msgstr "Parametry gestu" #: lib/logitech_receiver/settings_templates.py:1443 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Zmień parametry numeryczne myszy/panelu dotykowego." #: lib/logitech_receiver/settings_templates.py:1467 msgid "M-Key LEDs" msgstr "Diody LED klawiszy M" #: lib/logitech_receiver/settings_templates.py:1469 msgid "Control the M-Key LEDs." msgstr "Kontroluj diody LED klawiszy M." #: lib/logitech_receiver/settings_templates.py:1473 #: lib/logitech_receiver/settings_templates.py:1504 msgid "May need G Keys diverted to be effective." msgstr "Aby działało, może być konieczne włączenie przekierowania klawiszy G." #: lib/logitech_receiver/settings_templates.py:1479 #, python-format msgid "Lights up the %s key." msgstr "Zapala klawisz %s." #: lib/logitech_receiver/settings_templates.py:1498 msgid "MR-Key LED" msgstr "Dioda LED klawisza MR" #: lib/logitech_receiver/settings_templates.py:1500 msgid "Control the MR-Key LED." msgstr "Kontroluj diody LED klawiszy MR." #: lib/logitech_receiver/settings_templates.py:1521 msgid "Persistent Key/Button Mapping" msgstr "Trwałe mapowanie klawiszy/przycisków" #: lib/logitech_receiver/settings_templates.py:1523 msgid "Permanently change the mapping for the key or button." msgstr "Trwale zmień mapowania klawisza lub przycisku." #: lib/logitech_receiver/settings_templates.py:1525 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Zmiana ważnych klawiszy lub przycisków (takich jak lewy przycisk myszy) może " "spowodować, że system stanie się bezużyteczny." #: lib/logitech_receiver/settings_templates.py:1582 msgid "Sidetone" msgstr "Efekt lokalny" #: lib/logitech_receiver/settings_templates.py:1583 msgid "Set sidetone level." msgstr "Ustaw poziom efektu lokalnego." #: lib/logitech_receiver/settings_templates.py:1592 msgid "Equalizer" msgstr "Korektor" #: lib/logitech_receiver/settings_templates.py:1593 #: lib/logitech_receiver/settings_templates.py:1902 msgid "Set equalizer levels." msgstr "Ustaw poziomy korektora." #: lib/logitech_receiver/settings_templates.py:1615 #: lib/logitech_receiver/settings_templates.py:1930 #: lib/logitech_receiver/settings_templates.py:2056 #: lib/logitech_receiver/settings_templates.py:2058 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1621 msgid "Power Management" msgstr "Zarządzanie energią" #: lib/logitech_receiver/settings_templates.py:1622 msgid "Power off in minutes (0 for never)." msgstr "Wyłączenie zasilania w minutach (0 oznacza nigdy)." #: lib/logitech_receiver/settings_templates.py:1634 msgid "Eco Mode" msgstr "Tryb eko" #: lib/logitech_receiver/settings_templates.py:1635 msgid "Battery saver mode." msgstr "Tryb oszczędzania akumulatora." #: lib/logitech_receiver/settings_templates.py:1653 msgid "Do Not Disturb" msgstr "Nie przeszkadzać" #: lib/logitech_receiver/settings_templates.py:1654 msgid "Suppress notification sounds." msgstr "Wyłącz dźwięki powiadomień." #: lib/logitech_receiver/settings_templates.py:1661 msgid "Mic Mute" msgstr "Wyciszenie mikrofonu" #: lib/logitech_receiver/settings_templates.py:1662 msgid "Mute the microphone." msgstr "Wycisz mikrofon." #: lib/logitech_receiver/settings_templates.py:1681 msgid "Mic SNR" msgstr "SNR mikrofonu" #: lib/logitech_receiver/settings_templates.py:1682 msgid "Microphone signal-to-noise ratio enhancement." msgstr "Poprawa stosunku sygnału do szumu mikrofonu." #: lib/logitech_receiver/settings_templates.py:1689 msgid "AI Noise Reduction" msgstr "Redukcja szumów AI" #: lib/logitech_receiver/settings_templates.py:1690 msgid "Enable AI noise reduction." msgstr "Włącz redukcję szumów AI." #: lib/logitech_receiver/settings_templates.py:1697 msgid "AI Noise Reduction Level" msgstr "Poziom redukcji szumów AI" #: lib/logitech_receiver/settings_templates.py:1698 msgid "AI noise reduction intensity." msgstr "Intensywność redukcji szumów AI." #: lib/logitech_receiver/settings_templates.py:1707 msgid "Headset Sidetone" msgstr "Odsłuch zestawu słuchawkowego" #: lib/logitech_receiver/settings_templates.py:1708 msgid "Sidetone level (0 = off, 100 = max)." msgstr "Poziom odsłuchu (0 = wyłączony, 100 = maks.)." #: lib/logitech_receiver/settings_templates.py:1771 msgid "Mic Gain" msgstr "Wzmocnienie mikrofonu" #: lib/logitech_receiver/settings_templates.py:1772 msgid "Microphone gain level." msgstr "Poziom wzmocnienia mikrofonu." #: lib/logitech_receiver/settings_templates.py:1824 msgid "Audio Mix Balance" msgstr "Balans miksu dźwięku" #: lib/logitech_receiver/settings_templates.py:1825 msgid "Balance between game and chat audio." msgstr "Balans między dźwiękiem gry i czatu." #: lib/logitech_receiver/settings_templates.py:1876 msgid "Auto Sleep Timeout" msgstr "Limit czasu automatycznego uśpienia" #: lib/logitech_receiver/settings_templates.py:1877 msgid "" "Idle time in minutes before the headset enters sleep mode (0 = disabled)." msgstr "" "Czas bezczynności w minutach, po którym zestaw słuchawkowy przejdzie w tryb " "uśpienia (0 = wyłączony)." #: lib/logitech_receiver/settings_templates.py:1901 msgid "Headset Equalizer" msgstr "Korektor dźwięku zestawu słuchawkowego" #: lib/logitech_receiver/settings_templates.py:1996 msgid "Headset Advanced EQ" msgstr "Zaawansowany korektor dźwięku zestawu słuchawkowego" #: lib/logitech_receiver/settings_templates.py:1997 msgid "Per-band gain for the headset's active parametric EQ." msgstr "" "Wzmocnienie na pasmo aktywnego korektora parametrycznego zestawu " "słuchawkowego." #: lib/logitech_receiver/settings_templates.py:2268 msgid "EQ Preset" msgstr "Preset korektora" #: lib/logitech_receiver/settings_templates.py:2269 msgid "Switch the active EQ preset. Factory presets are read-only." msgstr "" "Zmień aktywny preset korektora. Ustawienia fabryczne są tylko do odczytu." #: lib/logitech_receiver/settings_templates.py:2294 msgid "Slot" msgstr "Gniazdo" #: lib/logitech_receiver/settings_templates.py:2296 msgid "(factory)" msgstr "(fabryczne)" #: lib/logitech_receiver/settings_templates.py:2429 #: lib/logitech_receiver/settings_templates.py:3206 #: lib/logitech_receiver/settings_templates.py:3298 msgid "LED Control" msgstr "Sterowanie diodami LED" #: lib/logitech_receiver/settings_templates.py:2430 msgid "Allow Solaar to control the headset LED zones." msgstr "Pozwól programowi Solaar sterować strefami LED zestawu słuchawkowego." #: lib/logitech_receiver/settings_templates.py:2478 msgid "Per-zone Lighting" msgstr "Oświetlenie przedstrefowe" #: lib/logitech_receiver/settings_templates.py:2480 msgid "" "Override individual zone colors. 'No change' inherits the LEDs Primary " "color.\n" "LED Control needs to be set to Solaar to be effective." msgstr "" "Zastąp kolory poszczególnych stref. Opcja „Bez zmian� dziedziczy kolor " "podstawowy diod LED.\n" "Należy ustawić je na Solaar, aby sterowanie diodami LED działało." #: lib/logitech_receiver/settings_templates.py:2498 msgid "Zone" msgstr "Strefa" #: lib/logitech_receiver/settings_templates.py:2620 #: lib/logitech_receiver/settings_templates.py:2908 #: lib/logitech_receiver/settings_templates.py:3648 msgid "Secondary" msgstr "Drugorzędny" #: lib/logitech_receiver/settings_templates.py:2621 #: lib/logitech_receiver/settings_templates.py:3234 msgid "Speed" msgstr "Szybkość" #: lib/logitech_receiver/settings_templates.py:2688 msgid "Startup Effect" msgstr "Efekt startowy" #: lib/logitech_receiver/settings_templates.py:2690 msgid "Firmware lighting effect played when the headset powers on or wakes." msgstr "" "Efekt świetlny oprogramowania sprzętowego jest odtwarzany po włączeniu lub " "wybudzeniu zestawu słuchawkowego." #: lib/logitech_receiver/settings_templates.py:2692 #: lib/logitech_receiver/settings_templates.py:2703 msgid "Device default: Primary #00B8FC, Secondary #FF00AB, Speed 100." msgstr "" "Domyślne urządzenie: podstawowe #00B8FC, drugorzędne #FF00AB, prędkość 100." #: lib/logitech_receiver/settings_templates.py:2699 msgid "Shutdown Effect" msgstr "Efekt wyłączenia" #: lib/logitech_receiver/settings_templates.py:2701 msgid "Firmware lighting effect played when the headset powers off or sleeps." msgstr "" "Efekt świetlny oprogramowania sprzętowego jest odtwarzany, gdy zestaw " "słuchawkowy wyłącza się lub przechodzi w tryb uśpienia." #: lib/logitech_receiver/settings_templates.py:2710 msgid "Passive Effect" msgstr "Efekt pasywny" #: lib/logitech_receiver/settings_templates.py:2712 msgid "Firmware lighting effect played while the headset is idle." msgstr "" "Efekt świetlny oprogramowania sprzętowego jest odtwarzany, gdy zestaw " "słuchawkowy jest bezczynny." #: lib/logitech_receiver/settings_templates.py:2714 msgid "Device default: Primary #00B8FC, Secondary #FF00AB, Speed 75." msgstr "" "Domyślne urządzenie: podstawowe #00B8FC, drugorzędne #FF00AB, prędkość 75." #: lib/logitech_receiver/settings_templates.py:2833 msgid "Onboard Effect" msgstr "Efekt pokładowy" #: lib/logitech_receiver/settings_templates.py:2834 msgid "Firmware RGB effect the headset plays on its own." msgstr "" "Efekt RGB oprogramowania sprzętowego zestawu słuchawkowego odtwarzany jest " "automatycznie." #: lib/logitech_receiver/settings_templates.py:2909 #: lib/logitech_receiver/settings_templates.py:3243 msgid "Intensity" msgstr "Intensywność" #: lib/logitech_receiver/settings_templates.py:2910 #: lib/logitech_receiver/settings_templates.py:3245 msgid "Saturation" msgstr "Nasycenie" #: lib/logitech_receiver/settings_templates.py:2914 #: lib/logitech_receiver/settings_templates.py:3238 msgid "Period" msgstr "Okres" #: lib/logitech_receiver/settings_templates.py:2919 #: lib/logitech_receiver/settings_templates.py:3250 msgid "Direction" msgstr "Kierunek" #: lib/logitech_receiver/settings_templates.py:3134 msgid "Brightness Control" msgstr "Sterowanie jasnością" #: lib/logitech_receiver/settings_templates.py:3135 msgid "Control overall brightness" msgstr "Steruj ogólną jasnością" #: lib/logitech_receiver/settings_templates.py:3207 #: lib/logitech_receiver/settings_templates.py:3299 msgid "Allow Solaar to control LED zones." msgstr "Pozwól programowi Solaar kontrolować strefy LED." #: lib/logitech_receiver/settings_templates.py:3230 #: lib/logitech_receiver/settings_templates.py:3744 msgid "LED Zone Effects" msgstr "Efekty strefowe diod LED" #: lib/logitech_receiver/settings_templates.py:3231 #: lib/logitech_receiver/settings_templates.py:3399 #: lib/logitech_receiver/settings_templates.py:3439 #: lib/logitech_receiver/settings_templates.py:3546 #: lib/logitech_receiver/settings_templates.py:3745 msgid "LED Control needs to be enabled." msgstr "Należy włączyć sterowanie diodami LED." #: lib/logitech_receiver/settings_templates.py:3231 #: lib/logitech_receiver/settings_templates.py:3745 msgid "Set effect for LED Zone" msgstr "Ustaw efekt dla strefy diod LED" #: lib/logitech_receiver/settings_templates.py:3233 msgid "Color" msgstr "Kolor" #: lib/logitech_receiver/settings_templates.py:3244 msgid "Ramp" msgstr "Narastanie" #: lib/logitech_receiver/settings_templates.py:3246 msgid "Waveform" msgstr "Kształt fali" #: lib/logitech_receiver/settings_templates.py:3279 msgid "LEDs" msgstr "Diody LED" #: lib/logitech_receiver/settings_templates.py:3398 msgid "Idle Timeout" msgstr "Limit czasu bezczynności" #: lib/logitech_receiver/settings_templates.py:3399 msgid "Time without input before LED idle effect starts." msgstr "Czas bezczynności przed rozpoczęciem efektu bezczynności diody LED." #: lib/logitech_receiver/settings_templates.py:3435 msgid "Idle Effect" msgstr "Efekt bezczynności" #: lib/logitech_receiver/settings_templates.py:3437 msgid "" "What happens to LEDs when idle — dim to a percentage, change the base color, " "or play an animation." msgstr "" "Co dzieje się z diodami LED, gdy są bezczynne — przyciemniają się do " "określonego poziomu, zmieniają kolor bazowy lub odtwarzają animację." #: lib/logitech_receiver/settings_templates.py:3520 msgid "No change" msgstr "Bez zmian" #: lib/logitech_receiver/settings_templates.py:3545 msgid "Sleep Timeout" msgstr "Limit czasu uśpienia" #: lib/logitech_receiver/settings_templates.py:3546 msgid "Time without input before LEDs fade off completely." msgstr "Czas bezczynności, po którym diody LED całkowicie gasną." #: lib/logitech_receiver/settings_templates.py:3719 msgid "Startup Animation" msgstr "Animacja startowa" #: lib/logitech_receiver/settings_templates.py:3722 msgid "" "Firmware-played animation when the keyboard wakes from deep sleep or powers " "on.\n" "Setting persists on the device (non-volatile)." msgstr "" "Animacja odtwarzana przez oprogramowanie sprzętowe podczas wybudzania " "klawiatury z trybu głębokiego uśpienia lub włączania.\n" "Ustawienie jest zachowywane na urządzeniu (trwale)." #: lib/logitech_receiver/settings_templates.py:3726 #: lib/logitech_receiver/settings_templates.py:3737 msgid "Device default: Primary #FF0081, Secondary #80AAFF." msgstr "Domyślne urządzenie: podstawowe #FF0081, drugorzędne #80AAFF." #: lib/logitech_receiver/settings_templates.py:3733 msgid "Shutdown Animation" msgstr "Animacja wyłączania" #: lib/logitech_receiver/settings_templates.py:3735 msgid "" "Firmware-played animation when the keyboard powers off.\n" "Setting persists on the device (non-volatile)." msgstr "" "Animacja odtwarzana przez oprogramowanie sprzętowe podczas wyłączania " "klawiatury.\n" "Ustawienie jest zachowywane na urządzeniu (trwale)." #: lib/logitech_receiver/settings_templates.py:3847 #: lib/solaar/ui/perkey/dialog.py:87 msgid "Per-key Lighting" msgstr "Podświetlenie poszczególnych klawiszy" #: lib/logitech_receiver/settings_templates.py:3849 msgid "Control per-key lighting." msgstr "Steruj podświetleniem poszczególnych klawiszy." #: lib/logitech_receiver/settings_templates.py:3851 msgid "" "LED Control needs to be enabled and the zone effect set to Static for per-" "key paint to be visible." msgstr "" "Należy włączyć sterowanie LED i ustawić opcję strefy na „Statyczne�, aby " "wyświetlanie kolorów poszczególnych klawiszy było widoczne." #: lib/logitech_receiver/settings_templates.py:4182 msgid "Force Sensing Buttons" msgstr "Przyciski wykrywające siłę" #: lib/logitech_receiver/settings_templates.py:4183 msgid "Change the force required to activate button." msgstr "Zmień siłę potrzebną do aktywowania przycisku." #: lib/logitech_receiver/settings_templates.py:4200 msgid "Force Sensing Button" msgstr "Przycisk wykrywający siłę" #: lib/logitech_receiver/settings_templates.py:4316 msgid "Analog Button Tuning" msgstr "Regulacja przycisków analogowych" #: lib/logitech_receiver/settings_templates.py:4317 msgid "" "Configure analog button settings including actuation point, rapid trigger, " "and haptics." msgstr "" "Skonfiguruj ustawienia przycisków analogowych, w tym punkt aktywacji, szybki " "spust i haptykę." #: lib/logitech_receiver/settings_templates.py:4347 #, python-format msgid "Actuation point depth (1=shallow, %d=deep)." msgstr "Głębokość punktu aktywacji (1=płytko, %d=głęboko)." #: lib/logitech_receiver/settings_templates.py:4355 #, python-format msgid "Rapid trigger sensitivity (1..%d)." msgstr "Czułość szybkiego spustu (1..%d)." #: lib/logitech_receiver/settings_templates.py:4363 #, python-format msgid "Click haptic feedback intensity (0=off, %d=max)." msgstr "Intensywność reakcji dotykowej kliknięcia (0=wył., %d=maks.)." #: lib/logitech_receiver/settings_templates.py:4371 msgid "Haptic Feedback Level" msgstr "Poziom haptycznego sprzężenia zwrotnego" #: lib/logitech_receiver/settings_templates.py:4372 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "" "Zmień moc haptycznego sprzężenia zwrotnego. (Zero powoduje wyłączenie.)" #: lib/logitech_receiver/settings_templates.py:4414 msgid "Play Haptic Waveform" msgstr "Odtwórz falę haptyczną" #: lib/logitech_receiver/settings_templates.py:4415 msgid "Tell device to play a haptic waveform." msgstr "Poleć urządzeniu odtworzenie fali haptycznej." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "Inny proces programu Solaar już działa, więc po prostu pokaż jego okno" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Zarządza odbiornikami, klawiaturami,\n" "myszami i tabletami firmy Logitech." #: lib/solaar/ui/about/model.py:64 msgid "Additional Programming" msgstr "Dodatkowe programowanie" #: lib/solaar/ui/about/model.py:65 msgid "GUI design" msgstr "Projekt GUI" #: lib/solaar/ui/about/model.py:67 msgid "Testing" msgstr "Testowanie" #: lib/solaar/ui/about/model.py:75 msgid "Logitech documentation" msgstr "Dokumentacja firmy Logitech" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Usuń sparowanie" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:142 msgid "Cancel" msgstr "Anuluj" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Błąd uprawnień" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Znaleziono odbiornik lub urządzenie firmy Logitech (%s), ale nie ma " "uprawnień do jego otwarcia." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Jeśli właśnie zainstalowano Solaar, spróbuj odłączyć odbiornik lub " "urządzenie, a następnie podłączyć je ponownie." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Błąd łączenia się z urządzeniem" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Znaleziono odbiornik lub urządzenie firmy Logitech w %s, ale wystąpił błąd " "podczas łączenia się z nim." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Spróbuj odłączyć urządzenie, a następnie podłączyć je ponownie lub wyłączyć " "i ponownie włączyć." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "Usunięcie sparowania nie powiodło się" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Nie udało się sparować %{device} z %{receiver}." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Odbiornik zwrócił błąd bez dodatkowych informacji." #: lib/solaar/ui/config_panel.py:254 msgid "Complete - ENTER to change" msgstr "Kompletne - ENTER, aby zmienić" #: lib/solaar/ui/config_panel.py:254 msgid "Incomplete" msgstr "Niekompletne" #: lib/solaar/ui/config_panel.py:500 lib/solaar/ui/config_panel.py:552 #: lib/solaar/ui/config_panel.py:619 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d wartość" msgstr[1] "%d wartości" msgstr[2] "%d wartości" #: lib/solaar/ui/config_panel.py:805 msgid "Changes allowed" msgstr "Zmiany dozwolone" #: lib/solaar/ui/config_panel.py:806 msgid "No changes allowed" msgstr "Zmiany niedozwolone" #: lib/solaar/ui/config_panel.py:807 msgid "Ignore this setting" msgstr "Ignoruj to ustawienie" #: lib/solaar/ui/config_panel.py:1022 msgid "Working" msgstr "Pracuję" #: lib/solaar/ui/config_panel.py:1025 msgid "Read/write operation failed." msgstr "Operacja odczytu/zapisu nie powiodła się." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "nieokreślony powód" #: lib/solaar/ui/diversion_rules.py:104 msgid "Built-in rules" msgstr "Wbudowane reguły" #: lib/solaar/ui/diversion_rules.py:104 msgid "User-defined rules" msgstr "Reguły zdefiniowane przez użytkownika" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:1127 msgid "Rule" msgstr "Reguła" #: lib/solaar/ui/diversion_rules.py:107 lib/solaar/ui/diversion_rules.py:383 #: lib/solaar/ui/diversion_rules.py:510 msgid "Sub-rule" msgstr "Reguła podrzędna" #: lib/solaar/ui/diversion_rules.py:109 msgid "[empty]" msgstr "[pusta]" #: lib/solaar/ui/diversion_rules.py:133 msgid "Make changes permanent?" msgstr "Wprowadzić zmiany na stałe?" #: lib/solaar/ui/diversion_rules.py:138 msgid "Yes" msgstr "Tak" #: lib/solaar/ui/diversion_rules.py:140 msgid "No" msgstr "Nie" #: lib/solaar/ui/diversion_rules.py:145 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Jeśli wybierzesz Nie, zmiany zostaną utracone po zamknięciu Solaar." #: lib/solaar/ui/diversion_rules.py:274 msgid "Paste here" msgstr "Wklej tutaj" #: lib/solaar/ui/diversion_rules.py:276 msgid "Paste above" msgstr "Wklej powyżej" #: lib/solaar/ui/diversion_rules.py:278 msgid "Paste below" msgstr "Wklej poniżej" #: lib/solaar/ui/diversion_rules.py:284 msgid "Paste rule here" msgstr "Wklej regułę tutaj" #: lib/solaar/ui/diversion_rules.py:286 msgid "Paste rule above" msgstr "Wklej regułę powyżej" #: lib/solaar/ui/diversion_rules.py:288 msgid "Paste rule below" msgstr "Wklej regułę poniżej" #: lib/solaar/ui/diversion_rules.py:292 msgid "Paste rule" msgstr "Wklej regułę" #: lib/solaar/ui/diversion_rules.py:307 msgid "Insert here" msgstr "Wstaw tutaj" #: lib/solaar/ui/diversion_rules.py:309 msgid "Insert above" msgstr "Wstaw powyżej" #: lib/solaar/ui/diversion_rules.py:311 msgid "Insert below" msgstr "Wstaw poniżej" #: lib/solaar/ui/diversion_rules.py:317 msgid "Insert new rule here" msgstr "Wstaw nową regułę tutaj" #: lib/solaar/ui/diversion_rules.py:319 msgid "Insert new rule above" msgstr "Wstaw nową regułę powyżej" #: lib/solaar/ui/diversion_rules.py:321 msgid "Insert new rule below" msgstr "Wstaw nową regułę poniżej" #: lib/solaar/ui/diversion_rules.py:348 msgid "Flatten" msgstr "Spłaszcz" #: lib/solaar/ui/diversion_rules.py:381 msgid "Insert" msgstr "Wstaw" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:512 #: lib/solaar/ui/diversion_rules.py:1159 msgid "Or" msgstr "Lub" #: lib/solaar/ui/diversion_rules.py:385 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1145 msgid "And" msgstr "Oraz" #: lib/solaar/ui/diversion_rules.py:387 msgid "Condition" msgstr "Warunek" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Funkcja" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Zgłoszenie" #: lib/solaar/ui/diversion_rules.py:391 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Proces" #: lib/solaar/ui/diversion_rules.py:392 msgid "Mouse process" msgstr "Proces myszy" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Modyfikatory" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Klawisz" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "KlawiszJestWciśnięty" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1433 msgid "Active" msgstr "Aktywny" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1391 #: lib/solaar/ui/diversion_rules.py:1442 lib/solaar/ui/diversion_rules.py:1488 msgid "Device" msgstr "Urządzenie" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1468 msgid "Host" msgstr "Host" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/diversion_rules.py:1507 msgid "Setting" msgstr "Ustawienie" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Bajty testowe" #: lib/solaar/ui/diversion_rules.py:402 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Gest myszy" #: lib/solaar/ui/diversion_rules.py:406 msgid "Action" msgstr "Czynność" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "Naciśnięcie klawisza" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Przewijanie myszą" #: lib/solaar/ui/diversion_rules.py:410 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Kliknięcie myszą" #: lib/solaar/ui/diversion_rules.py:411 msgid "Set" msgstr "Ustaw" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "Wykonaj" #: lib/solaar/ui/diversion_rules.py:413 lib/solaar/ui/diversion_rules.py:1190 msgid "Later" msgstr "Później" #: lib/solaar/ui/diversion_rules.py:442 msgid "Insert new rule" msgstr "Wstaw nową regułę" #: lib/solaar/ui/diversion_rules.py:462 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Usuń" #: lib/solaar/ui/diversion_rules.py:484 msgid "Negate" msgstr "Neguj" #: lib/solaar/ui/diversion_rules.py:508 msgid "Wrap with" msgstr "Obwiąż" #: lib/solaar/ui/diversion_rules.py:538 msgid "Cut" msgstr "Wytnij" #: lib/solaar/ui/diversion_rules.py:554 msgid "Paste" msgstr "Wklej" #: lib/solaar/ui/diversion_rules.py:560 msgid "Copy" msgstr "Skopiuj" #: lib/solaar/ui/diversion_rules.py:569 msgid "Solaar Rule Editor" msgstr "Edytor reguł Solaar" #: lib/solaar/ui/diversion_rules.py:669 msgid "Save changes" msgstr "Zapisz zmiany" #: lib/solaar/ui/diversion_rules.py:674 msgid "Discard changes" msgstr "Odrzuć zmiany" #: lib/solaar/ui/diversion_rules.py:1105 msgid "This editor does not support the selected rule component yet." msgstr "Ten edytor nie obsługuje jeszcze wybranego składnika reguły." #: lib/solaar/ui/diversion_rules.py:1170 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Liczba sekund opóźnienia. Opóźnienie pomiędzy 0 i 1 odbywa się z większą " "precyzją." #: lib/solaar/ui/diversion_rules.py:1208 msgid "Not" msgstr "Nie" #: lib/solaar/ui/diversion_rules.py:1239 msgid "Toggle" msgstr "Przełącz" #: lib/solaar/ui/diversion_rules.py:1240 msgid "True" msgstr "Prawda" #: lib/solaar/ui/diversion_rules.py:1241 msgid "False" msgstr "Fałsz" #: lib/solaar/ui/diversion_rules.py:1254 msgid "Unsupported setting" msgstr "Nieobsługiwane ustawienie" #: lib/solaar/ui/diversion_rules.py:1397 lib/solaar/ui/diversion_rules.py:1416 #: lib/solaar/ui/diversion_rules.py:1494 lib/solaar/ui/diversion_rules.py:1758 #: lib/solaar/ui/diversion_rules.py:1776 msgid "Originating device" msgstr "Urządzenie inicjujące" #: lib/solaar/ui/diversion_rules.py:1429 msgid "Device is active and its settings can be changed." msgstr "Urządzenie jest aktywne i można zmienić jego ustawienia." #: lib/solaar/ui/diversion_rules.py:1438 msgid "Device that originated the current notification." msgstr "Urządzenie, z którego pochodzi bieżące powiadomienie." #: lib/solaar/ui/diversion_rules.py:1451 msgid "Name of host computer." msgstr "Nazwa komputera hosta." #: lib/solaar/ui/diversion_rules.py:1521 msgid "Value" msgstr "Wartość" #: lib/solaar/ui/diversion_rules.py:1530 msgid "Item" msgstr "Pozycja" #: lib/solaar/ui/diversion_rules.py:1818 msgid "Change setting on device" msgstr "Zmień ustawienie w urządzeniu" #: lib/solaar/ui/diversion_rules.py:1834 msgid "Setting on device" msgstr "Ustawienie w urządzeniu" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: sparuj nowe urządzenie" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Odbiorniki Bolt są kompatybilne tylko z urządzeniami Bolt." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Naciśnij przycisk lub klawisz parowania, aż kontrolka parowania zacznie " "szybko migać." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Odbiorniki Unifying są kompatybilne tylko z urządzeniami Unifying." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "Inne odbiorniki są kompatybilne tylko z kilkoma urządzeniami." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "W przypadku większości urządzeń należy je włączyć do parowania." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "Jeśli urządzenie jest już włączone, wyłącz je i włącz ponownie." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" "Urządzenia nie można parować ze znajdującym się w pobliżu włączonym " "odbiornikiem." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "W przypadku urządzeń z wieloma kanałami naciśnij, przytrzymaj i zwolnij " "przycisk kanału do parowania\n" "lub użyj przycisku przełączania kanałów, aby wybrać kanał, a następnie " "naciśnij, przytrzymaj i zwolnij przycisk przełączania kanałów." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Kontrolka kanału powinna szybko migać." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Ten odbiornik ma jeszcze %d sparowanie." msgstr[1] "" "\n" "\n" "Ten odbiornik ma jeszcze %d sparowania." msgstr[2] "" "\n" "\n" "Ten odbiornik ma jeszcze %d sparowań." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Anulowanie w tym momencie nie spowoduje zużycia sparowania." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Wprowadź kod dostępu do %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Wpisz %(passcode)s i naciśnij klawisz Enter." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "lewo" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "prawo" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Naciśnij %(code)s\n" "i przyciśnij jednocześnie lewy i prawy przycisk." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "Połączenie nie jest szyfrowane" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Znaleziono nowe urządzenie:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Sparowanie nie powiodło się" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "Upewnij się, że urządzenie jest w zasięgu i ma naładowany akumulator." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "" "Wykryto nowe urządzenie, jednak nie jest ono kompatybilne z tym odbiornikiem." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "Więcej sparowanych urządzeń niż obsługuje odbiornik." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Brak dodatkowych informacji na temat błędu." #: lib/solaar/ui/perkey/control.py:178 msgid "(not loaded)" msgstr "(nie wczytano)" #: lib/solaar/ui/perkey/control.py:182 msgid "Open editor…" msgstr "Otwórz edytor…" #: lib/solaar/ui/perkey/control.py:183 msgid "Paint key colors on a keyboard layout" msgstr "Malowanie kolorów klawiszy na układzie klawiatury" #: lib/solaar/ui/perkey/control.py:229 msgid "(no zones)" msgstr "(brak stref)" #: lib/solaar/ui/perkey/control.py:233 #, python-brace-format msgid "{painted} / {total} keys painted" msgstr "Pomalowane klawisze: {painted} / {total}" #: lib/solaar/ui/perkey/editor.py:54 msgid "Brush" msgstr "Pędzel" #: lib/solaar/ui/perkey/editor.py:54 msgid "Click or drag to paint individual keys" msgstr "Kliknij lub przeciągnij, aby pomalować poszczególne klawisze" #: lib/solaar/ui/perkey/editor.py:55 msgid "Drag to select a rectangle of keys, painted on release" msgstr "Przeciągnij, aby wybrać prostokąt klawiszy, namalowany po zwolnieniu" #: lib/solaar/ui/perkey/editor.py:55 msgid "Rect" msgstr "Prostokąt" #: lib/solaar/ui/perkey/editor.py:56 msgid "Fill" msgstr "Wypełnianie" #: lib/solaar/ui/perkey/editor.py:56 msgid "Flood-fill connected keys of the same color with the active color" msgstr "Wypełnij połączone klawisze tego samego koloru aktywnym kolorem" #: lib/solaar/ui/perkey/editor.py:59 msgid "Drag to fade from previous color to active color" msgstr "Przeciągnij, aby przejść z poprzedniego koloru do aktywnego koloru" #: lib/solaar/ui/perkey/palette.py:90 msgid "Active color" msgstr "Kolor aktywny" #: lib/solaar/ui/perkey/palette.py:95 msgid "Paint as 'no change' — clears the cell to the zone base color" msgstr "Maluj jako „bez zmian� — czyści komórkę do koloru bazowego strefy" #: lib/solaar/ui/perkey/palette.py:96 msgid "Unset" msgstr "Wyłącz" #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Symuluj akordowe kliknięcie klawisza, wciśnięcie lub zwolnenie.\n" "W Wayland wymaga dostępu do zapisu w /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Dodaj klawisz" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Kliknij" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Wciśnij" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Zwolnij" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Symuluj przewijanie myszy.\n" "W Wayland wymaga dostępu do zapisu w /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Symuluj kliknięcie myszą.\n" "W Wayland wymaga dostępu do zapisu w /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Przycisk" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Czynność (i liczba, jeśli kliknięcie)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Wykonaj polecenie z argumentami." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Dodaj argument" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "Aktywny proces X11. Do użytku tylko w X11." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "Proces myszy X11. Do użytku tylko w X11." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "ProcesMyszy" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "Nazwa funkcji powiadomienia wyzwalająca przetwarzanie reguły." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "Numer zgłoszenia powiadomienia wyzwalającego przetwarzanie reguły." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Aktywne modyfikatory klawiatury. Nie zawsze dostępne w Wayland." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Przekierowany klawisz lub przycisk wciśnięto lub zwolniono.\n" "Użyj ustawień przekierowania klawiszy/przycisków oraz przekierowania " "klawiszy G, aby przekierować klawisze i przyciski." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Klawisz w dół" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Klawisz w górę" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Przekierowany klawisz lub przycisk jest obecnie wciśnięty.\n" "Użyj ustawień przekierowania klawiszy/przycisków oraz przekierowania " "klawiszy G, aby przekierować klawisze i przyciski." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "Warunek testowy przy powiadomieniu wyzwalający przetwarzanie reguły." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Parametr" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "rozpocznij (włącznie)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "zakończ (wyłącznie)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "zakres" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "maksimum" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "bajty %(0)d do %(1)d, począwszy od %(2)d do %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "maska" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "bajty %(0)d do %(1)d, maska %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Test bitowy lub zakresowy na bajtach w komunikacie powiadomienia " "uruchamiający przetwarzanie reguł." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "typ" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Gest myszy z opcjonalnym przyciskiem inicjującym, po którym następuje zero " "lub więcej ruchów myszy." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Dodaj ruch" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Nie znaleziono obsługiwanego urządzenia" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "O programie %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Zakończ %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "brak odbiornika" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 msgid "offline" msgstr "wyłączone" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "brak statusu" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Skanowanie" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Akumulator" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Połączenie bezprzewodowe" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "Podświetlenie" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Wyświetl szczegóły techniczne" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Sparuj nowe urządzenie" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Wybierz urządzenie" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Edytor reguł" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Ścieżka" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "ID USB" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:550 lib/solaar/ui/window.py:552 msgid "Serial" msgstr "Nr seryjny" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "Indeks" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "Prawo" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "ID produktu" #: lib/solaar/ui/window.py:541 lib/solaar/ui/window.py:543 #: lib/solaar/ui/window.py:545 msgid "Protocol" msgstr "Protokół" #: lib/solaar/ui/window.py:545 msgid "Unknown" msgstr "Nieznany" #: lib/solaar/ui/window.py:547 msgid "Polling rate" msgstr "Odpytywanie" #: lib/solaar/ui/window.py:554 msgid "Unit ID" msgstr "ID jednostki" #: lib/solaar/ui/window.py:566 msgid "Notifications" msgstr "Powiadomienia" #: lib/solaar/ui/window.py:610 msgid "No device paired." msgstr "Brak sparowanych urządzeń." #: lib/solaar/ui/window.py:619 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "" "Można sparować maksymalnie %(max_count)s urządzenie z tym odbiornikiem." msgstr[1] "" "Można sparować maksymalnie %(max_count)s urządzenia z tym odbiornikiem." msgstr[2] "" "Można sparować maksymalnie %(max_count)s urządzeń z tym odbiornikiem." #: lib/solaar/ui/window.py:630 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Ten odbiornik ma jeszcze %d sparowanie." msgstr[1] "Ten odbiornik ma jeszcze %d sparowania." msgstr[2] "Ten odbiornik ma jeszcze %d sparowań." #: lib/solaar/ui/window.py:687 msgid "Battery Voltage" msgstr "Napięcie akumulatora" #: lib/solaar/ui/window.py:689 msgid "Voltage reported by battery" msgstr "Napięcie zgłoszone przez akumulator" #: lib/solaar/ui/window.py:691 msgid "Battery Level" msgstr "Poziom akumulatora" #: lib/solaar/ui/window.py:693 msgid "Approximate level reported by battery" msgstr "Przybliżony poziom zgłoszony przez akumulator" #: lib/solaar/ui/window.py:700 lib/solaar/ui/window.py:702 msgid "next reported " msgstr "następny zgłoszony " #: lib/solaar/ui/window.py:703 msgid " and next level to be reported." msgstr " oraz następny poziom do zgłoszenia." #: lib/solaar/ui/window.py:719 msgid "encrypted" msgstr "szyfrowane" #: lib/solaar/ui/window.py:721 msgid "The wireless link between this device and its receiver is encrypted." msgstr "" "Połączenie bezprzewodowe pomiędzy tym urządzeniem i odbiornikiem jest " "szyfrowane." #: lib/solaar/ui/window.py:723 msgid "not encrypted" msgstr "nieszyfrowane" #: lib/solaar/ui/window.py:727 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "�ącze bezprzewodowe między tym urządzeniem a jego odbiornikiem nie jest " "szyfrowane.\n" "Jest to problem dotyczący zabezpieczeń urządzeń wskazujących i poważny " "problem dotyczący zabezpieczeń urządzeń do wprowadzania tekstu." #: lib/solaar/ui/window.py:743 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lx" Solaar-1.1.20/po/pt.po000066400000000000000000001372101522022367600144260ustar00rootroot00000000000000# Translation of solaar's ui's messages to European Portuguese # Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # # Américo Monteiro , 2014. msgid "" msgstr "Project-Id-Version: solaar 0.9.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2014-09-14 20:57+0100\n" "Last-Translator: Américo Monteiro \n" "Language-Team: Portuguese \n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 1.4\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "vazio" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "crítico" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "baixo" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "bom" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "cheio" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "a descarregar" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "a carregar" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "a carregar" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "quase cheiro" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "carga lenta" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "bateria inválida" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "erro térmico" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "tempo limite do dispositivo" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "dispositivo não suportado" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "demasiados dispositivos" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "tempo limite da sequência" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Gestor de arranque" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Outro" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "ligado" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "desemparelhado" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "com energia ligada" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Trocar função Fx" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Quando definido, as teclas F1..F12 irão activar as suas funções " "especiais,\n" "e você tem manter a tecla FN carregada para activar as suas funções " "standard." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Quando não definido, as teclas F1..F12 irão activar as suas funções " "standard,\n" "e você tem manter a tecla FN carregada para activar as suas funções " "especiais." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Detecção de Mão" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Liga a iluminação quando as mãos estão sobre o teclado." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Modo de alta-sensibilidade para deslocamento vertical com a roda." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Deslocamento Lateral" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Quando desactivado, premir a roda para os lados envia eventos de " "botões personalizados\n" "em vez dos eventos de deslocamento lateral standard." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "" #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Sensibilidade (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "" #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "" #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "" #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "" #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "" #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "" #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "" #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "" #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Fator de escala" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Largura" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Altura" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "" #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gestos" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "" #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "" #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Nenhum dispositivo emparelhado." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "" msgstr[1] "" #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Erro de permissões" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Desemparelhamento falhado" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "" #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "O receptor devolveu um erro, sem mais detalhes." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "Desenho da GUI" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "A testar" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Documentação da Logitech" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Desemparelhar" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "A funcionar" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Operação de leitura/escrita falhada." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Sim" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "" #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Ativo" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Ação" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Cortar" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Colar" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Copiar" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "" #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "" #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Valor" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "offline" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "" #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Emparelhamento falhado" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Certifique-se que o seu dispositivo está dentro do alcance, e tem " "uma carga de bateria decente." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Foi detectado um novo dispositivo, mas não é compatível com este " "receptor." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "" #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Não há mais detalhes disponíveis acerca do erro." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "A ligação sem fios não está encriptada" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Ligue o dispositivo que deseja emparelhar." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "" #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "Acerca de %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Terminar %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "nenhum receptor" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "nenhum estado" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "A sondar" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Bateria" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Ligação Sem Fios" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Iluminação" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Mostrar Detalhes Técnicos" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Emparelhar novo dispositivo" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Seleccionar um dispositivo" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Caminho" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Série" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "�ndice" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "PID de ligação sem fios" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "ID do produto" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protocolo" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Desconhecido" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Rácio de votações" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "nenhum" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Notificações" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "" #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "" #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "" #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr "" #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "último conhecido" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "encriptado" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "A ligação sem fios entre este dispositivo e o seu receptor está " "encriptada." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "não encriptado" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "" #~ msgid " paired devices." #~ msgstr " dispositivos emparelhados." #~ msgid "1 paired device." #~ msgstr "1 dispositivo emparelhado." #~ msgid "Count" #~ msgstr "Contagem" #, python-format #~ msgid "Failed to unpair %s from %s." #~ msgstr "Falha ao desemparelhar %s de %s." #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Encontrado um Receptor Logitech (%s), mas não teve " #~ "permissões para o abrir." #~ msgid "Found a new device" #~ msgstr "Encontrado um novo dispositivo" #~ msgid "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "Se o dispositivo já está ligado,\n" #~ "desligue-o e volte a ligá-lo." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Se você acabou de instalar o Solaar, tente remover o " #~ "receptor e ligá-lo de novo." #~ msgid "No Logitech receiver found" #~ msgstr "Nenhum receptor Logitech encontrado" #~ msgid "No device paired" #~ msgstr "Nenhum dispositivo emparelhado" #~ msgid "Only one device can be paired to this receiver" #~ msgstr "Apenas um dispositivo pode ser emparelhado com este receptor" #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Mostra o estado dos dispositivos ligados\n" #~ "através de receptores sem fio da Logitech." #~ msgid "Smooth Scrolling" #~ msgstr "Deslocamento de Ecrã Suave" #, python-format #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "O receptor apenas suporta %d dispositivo(s) emparelhados." #~ msgid "The receiver was unplugged." #~ msgstr "O receptor foi desligado." #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "A ligação sem fios entre este dispositivo e o seu receptor " #~ "não está encriptada.\n" #~ "\n" #~ "Para dispositivos apontadores (ratos, trackballs, trackpads), este é " #~ "um problema de segurança menor.\n" #~ "\n" #~ "No entanto, é um problema de segurança maior para dispositivos de " #~ "entrada de texto (teclados, teclados numéricos).\n" #~ "porque o texto teclado pode ser \"cheirado\" de modo imperceptível " #~ "por terceiros que estejam dentro do alcance da ligação." #~ msgid "USB id" #~ msgstr "id de USB" #, python-format #~ msgid "Up to %d devices can be paired to this receiver" #~ msgstr "Podem ser emparelhados até %d dispositivos com este receptor" #~ msgid "closed" #~ msgstr "fechado" #~ msgid "height" #~ msgstr "altura" #~ msgid "lux" #~ msgstr "lux" #~ msgid "open" #~ msgstr "aberto" #~ msgid "pair new device" #~ msgstr "emparelhar o novo dispositivo" #~ msgid "paired devices" #~ msgstr "dispositivos emparelhados" #~ msgid "pairing lock is " #~ msgstr "tranca de emparelhamento é " #~ msgid "unknown" #~ msgstr "desconhecido" #~ msgid "width" #~ msgstr "largura" Solaar-1.1.20/po/pt_BR.po000066400000000000000000002032401522022367600150060ustar00rootroot00000000000000# Portuguese translations for solaar package. # Copyright (C) 2015 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2015. # msgid "" msgstr "" "Project-Id-Version: solaar 0.9.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-01-08 19:37-0300\n" "PO-Revision-Date: 2026-01-08 22:37-0300\n" "Last-Translator: Mário Victor Ribeiro Silva \n" "Language-Team: Sídnei A. Drovetto Jr.\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Launchpad-Export-Date: 2020-10-21 16:52+0000\n" "X-Generator: Poedit 3.8\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Receptor Bolt" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Receptor Unifying" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Receptor Nano" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Receptor Lightspeed" #: lib/logitech_receiver/base_usb.py:136 msgid "EX100 Receiver 27 Mhz" msgstr "Receptor EX100 27 Mhz" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Bateria: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Bateria: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1048 #: lib/logitech_receiver/settings_templates.py:299 msgid "Disabled" msgstr "Desativado" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Static" msgstr "Estático" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Pulse" msgstr "Pulso" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Cycle" msgstr "Ciclo" #: lib/logitech_receiver/hidpp20.py:1052 msgid "Boot" msgstr "Inicialização" #: lib/logitech_receiver/hidpp20.py:1053 msgid "Demo" msgstr "Demonstração" #: lib/logitech_receiver/hidpp20.py:1055 msgid "Breathe" msgstr "Respirar" #: lib/logitech_receiver/hidpp20.py:1058 msgid "Ripple" msgstr "Ondulação" #: lib/logitech_receiver/hidpp20.py:1059 msgid "Decomposition" msgstr "Decomposição" #: lib/logitech_receiver/hidpp20.py:1060 msgid "Signature1" msgstr "Assinatura1" #: lib/logitech_receiver/hidpp20.py:1061 msgid "Signature2" msgstr "Assinatura2" #: lib/logitech_receiver/hidpp20.py:1062 msgid "CycleS" msgstr "CicloS" #: lib/logitech_receiver/hidpp20.py:1126 msgid "Unknown Location" msgstr "Localização Desconhecida" #: lib/logitech_receiver/hidpp20.py:1127 msgid "Primary" msgstr "Primário" #: lib/logitech_receiver/hidpp20.py:1128 msgid "Logo" msgstr "Logotipo" #: lib/logitech_receiver/hidpp20.py:1129 msgid "Left Side" msgstr "Lado esquerdo" #: lib/logitech_receiver/hidpp20.py:1130 msgid "Right Side" msgstr "Lado direito" #: lib/logitech_receiver/hidpp20.py:1131 msgid "Combined" msgstr "Combinado" #: lib/logitech_receiver/hidpp20.py:1132 msgid "Primary 1" msgstr "Primário 1" #: lib/logitech_receiver/hidpp20.py:1133 msgid "Primary 2" msgstr "Primário 2" #: lib/logitech_receiver/hidpp20.py:1134 msgid "Primary 3" msgstr "Primário 3" #: lib/logitech_receiver/hidpp20.py:1135 msgid "Primary 4" msgstr "Primário 4" #: lib/logitech_receiver/hidpp20.py:1136 msgid "Primary 5" msgstr "Primário 5" #: lib/logitech_receiver/hidpp20.py:1137 msgid "Primary 6" msgstr "Primário 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "vazia" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "crítica" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "fraca" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "média" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "boa" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "cheia" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "descarregando" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "recarregando" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "carregando" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "não carregando" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "quase cheia" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "carregada" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "recarga lenta" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "bateria inválida" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "erro térmico" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "erro" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "padrão" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "rápido" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "lento" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "tempo esgotado do dispositivo" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "dispositivo não suportado" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "número excessivo de dispositivos" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "tempo esgotado da sequência" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "Firmware" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Hardware" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Outro" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Botão da esquerda" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Botão da direita" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Botão do meio" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Botão Voltar" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Botão Avançar" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Botão de gestos do mouse" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Smart Shift" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Mudança de DPI" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Inclinação para a esquerda" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Inclinação para a direita" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Clique com o botão esquerdo" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Clique com o botão direito" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Botão do meio do mouse" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Botão de voltar do mouse" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Botão de avançar do mouse" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Botão de navegação por gestos" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Botão de rolagem esquerda do mouse" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Botão de rolagem direita do mouse" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "pressionada" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "liberada" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "conectado" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "desconectado" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "desemparelhado" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "ligado" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:484 msgid "pairing lock is closed" msgstr "trava de emparelhamento está fechada" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:484 msgid "pairing lock is open" msgstr "trava de emparelhamento está aberta" #: lib/logitech_receiver/notifications.py:447 msgid "discovery lock is closed" msgstr "bloqueio de descoberta está fechado" #: lib/logitech_receiver/notifications.py:447 msgid "discovery lock is open" msgstr "bloqueio de descoberta está aberto" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "Nenhum dispositivo emparelhado." #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s dispositivo emparelhado." msgstr[1] "%(count)s dispositivos emparelhados." #: lib/logitech_receiver/settings.py:602 msgid "register" msgstr "register" #: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654 msgid "feature" msgstr "feature" #: lib/logitech_receiver/settings_templates.py:138 msgid "Swap Fx function" msgstr "Trocar função de teclas Fx" #: lib/logitech_receiver/settings_templates.py:141 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Quando marcada, as teclas F1..F12 vão acionar sua função especial,\n" "e você precisa manter pressionada a tecla FN para acionar sua função padrão." #: lib/logitech_receiver/settings_templates.py:146 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Quando desmarcada, as teclas F1..F12 vão acionar sua função padrão,\n" "e você precisa pressionar a tecla FN para acionar sua função especial." #: lib/logitech_receiver/settings_templates.py:154 msgid "Hand Detection" msgstr "Detecção de Mão" #: lib/logitech_receiver/settings_templates.py:155 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Ligar a iluminação quando a mão estiver sobre o telcado." #: lib/logitech_receiver/settings_templates.py:162 msgid "Scroll Wheel Smooth Scrolling" msgstr "Rolagem suave com a roda" #: lib/logitech_receiver/settings_templates.py:163 #: lib/logitech_receiver/settings_templates.py:410 #: lib/logitech_receiver/settings_templates.py:439 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Modo de alta-sensibilidade para rolagem vertical com a roda." #: lib/logitech_receiver/settings_templates.py:170 msgid "Side Scrolling" msgstr "Rolagem Lateral" #: lib/logitech_receiver/settings_templates.py:172 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Quando desabilitado, pressionar a roda lateralmente envia eventos " "customizados\n" "ao invés dos eventos tradicionais de rolagem lateral." #: lib/logitech_receiver/settings_templates.py:182 msgid "Sensitivity (DPI - older mice)" msgstr "Sensibilidade (DPI - mouses antigos)" #: lib/logitech_receiver/settings_templates.py:183 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 msgid "Mouse movement sensitivity" msgstr "Sensibilidade do movimento do mouse" #: lib/logitech_receiver/settings_templates.py:256 msgid "Backlight Timed" msgstr "Temporizador de luz de fundo" #: lib/logitech_receiver/settings_templates.py:257 #: lib/logitech_receiver/settings_templates.py:397 msgid "Set illumination time for keyboard." msgstr "Defina o tempo de iluminação do teclado." #: lib/logitech_receiver/settings_templates.py:268 msgid "Backlight" msgstr "Luz de fundo" #: lib/logitech_receiver/settings_templates.py:269 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Nível de iluminação do teclado. As alterações feitas só se aplicam no modo " "Manual." #: lib/logitech_receiver/settings_templates.py:301 msgid "Automatic" msgstr "Automático" #: lib/logitech_receiver/settings_templates.py:303 msgid "Manual" msgstr "Manual" #: lib/logitech_receiver/settings_templates.py:305 msgid "Enabled" msgstr "Habilitado" #: lib/logitech_receiver/settings_templates.py:311 msgid "Backlight Level" msgstr "Nível de luz de fundo" #: lib/logitech_receiver/settings_templates.py:312 msgid "Illumination level on keyboard when in Manual mode." msgstr "Nível de iluminação do teclado no modo Manual." #: lib/logitech_receiver/settings_templates.py:369 msgid "Backlight Delay Hands Out" msgstr "Atraso da luz de fundo ao retirar as mãos" #: lib/logitech_receiver/settings_templates.py:370 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Tempo de atraso, em segundos, até que a luz de fundo se apague gradualmente " "quando as mãos forem retiradas do teclado." #: lib/logitech_receiver/settings_templates.py:378 msgid "Backlight Delay Hands In" msgstr "Atraso da luz de fundo ao colocar as mãos" #: lib/logitech_receiver/settings_templates.py:379 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Tempo de atraso, em segundos, até que a luz de fundo se apague com as mãos " "próximas ao teclado." #: lib/logitech_receiver/settings_templates.py:387 msgid "Backlight Delay Powered" msgstr "Atraso da luz de fundo Alimentado" #: lib/logitech_receiver/settings_templates.py:388 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Tempo de atraso, em segundos, até que a luz de fundo se apague com a " "alimentação externa." #: lib/logitech_receiver/settings_templates.py:396 msgid "Backlight (Seconds)" msgstr "Luz de fundo (segundos)" #: lib/logitech_receiver/settings_templates.py:408 msgid "Scroll Wheel High Resolution" msgstr "Alta resolução de rolagem com a roda" #: lib/logitech_receiver/settings_templates.py:412 #: lib/logitech_receiver/settings_templates.py:441 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Configure para ignorar se a rolagem for anormalmente rápida ou lenta" #: lib/logitech_receiver/settings_templates.py:419 #: lib/logitech_receiver/settings_templates.py:450 msgid "Scroll Wheel Diversion" msgstr "Desvio da roda de rolagem" #: lib/logitech_receiver/settings_templates.py:421 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:428 msgid "Scroll Wheel Direction" msgstr "Direção de rolagem" #: lib/logitech_receiver/settings_templates.py:429 msgid "Invert direction for vertical scroll with wheel." msgstr "Inverte a direção da rolagem vertical." #: lib/logitech_receiver/settings_templates.py:437 msgid "Scroll Wheel Resolution" msgstr "Resolução da roda de rolagem" #: lib/logitech_receiver/settings_templates.py:452 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:461 msgid "Sensitivity (Pointer Speed)" msgstr "Sensibilidade (Velocidade do Ponteiro)" #: lib/logitech_receiver/settings_templates.py:462 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Fator de multiplicação da velocidade do mouse (256 é o fator normal)." #: lib/logitech_receiver/settings_templates.py:472 msgid "Thumb Wheel Diversion" msgstr "Desvio da roda de polegar" #: lib/logitech_receiver/settings_templates.py:474 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:483 msgid "Thumb Wheel Direction" msgstr "Direção da rolagem com a roda" #: lib/logitech_receiver/settings_templates.py:484 msgid "Invert thumb wheel scroll direction." msgstr "Inverter a direção da rolagem com o polegar." #: lib/logitech_receiver/settings_templates.py:504 msgid "Onboard Profiles" msgstr "Perfis Embarcados" #: lib/logitech_receiver/settings_templates.py:505 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" #: lib/logitech_receiver/settings_templates.py:549 #: lib/logitech_receiver/settings_templates.py:582 msgid "Report Rate" msgstr "Taxa de relatório" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 msgid "Frequency of device movement reports" msgstr "Frequência de relatórios de movimentação de dispositivos" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1421 #: lib/logitech_receiver/settings_templates.py:1452 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:612 msgid "Divert crown events" msgstr "Desviar eventos da coroa" #: lib/logitech_receiver/settings_templates.py:613 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Faz a coroa enviar notificações HID++ CROWN (que desencadeiam regras do " "Solaar, mas são ignoradas fora disso)." #: lib/logitech_receiver/settings_templates.py:621 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:622 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:630 msgid "Divert G and M Keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:631 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:645 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:646 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:648 msgid "Freespinning" msgstr "Giro livre" #: lib/logitech_receiver/settings_templates.py:648 msgid "Ratcheted" msgstr "Ratcheted" #: lib/logitech_receiver/settings_templates.py:655 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:657 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:707 msgid "Scroll Wheel Ratchet Torque" msgstr "" #: lib/logitech_receiver/settings_templates.py:708 msgid "Change the torque needed to overcome the ratchet." msgstr "" #: lib/logitech_receiver/settings_templates.py:743 msgid "Key/Button Actions" msgstr "Ações das teclas/botões" #: lib/logitech_receiver/settings_templates.py:745 msgid "Change the action for the key or button." msgstr "Trocar a ação da tecla/botão." #: lib/logitech_receiver/settings_templates.py:747 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:749 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Trocar ações importantes (como a do botão esquerdo do mouse) pode tornar o " "sistema inutilizável." #: lib/logitech_receiver/settings_templates.py:924 msgid "Key/Button Diversion" msgstr "Desvio de Tecla/Botão" #: lib/logitech_receiver/settings_templates.py:925 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Diverted" msgstr "Desviado" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 msgid "Mouse Gestures" msgstr "Gestos do mouse" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Regular" msgstr "Regular" #: lib/logitech_receiver/settings_templates.py:928 msgid "Sliding DPI" msgstr "DPI deslizante" #: lib/logitech_receiver/settings_templates.py:1018 #: lib/logitech_receiver/settings_templates.py:1046 msgid "Sensitivity (DPI)" msgstr "Sensibilidade (DPI)" #: lib/logitech_receiver/settings_templates.py:1123 msgid "Sensitivity Switching" msgstr "Alternar sensibilidade" #: lib/logitech_receiver/settings_templates.py:1125 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:1129 msgid "Off" msgstr "Desativado" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Disable keys" msgstr "Desativar teclas" #: lib/logitech_receiver/settings_templates.py:1161 msgid "Disable specific keyboard keys." msgstr "Desativar teclas específicas do teclado." #: lib/logitech_receiver/settings_templates.py:1164 #, python-format msgid "Disables the %s key." msgstr "Desativa a tecla %s." #: lib/logitech_receiver/settings_templates.py:1177 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Set OS" msgstr "Definir SO" #: lib/logitech_receiver/settings_templates.py:1178 #: lib/logitech_receiver/settings_templates.py:1235 msgid "Change keys to match OS." msgstr "Trocar as teclas para corresponder ao SO." #: lib/logitech_receiver/settings_templates.py:1247 msgid "Change Host" msgstr "Trocar Hospedeiro" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Switch connection to a different host" msgstr "Trocar a conexão para um hospedeiro diferente" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Performs a left click." msgstr "Executa um clique com botão esquerdo." #: lib/logitech_receiver/settings_templates.py:1272 msgid "Single tap" msgstr "Toque único" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Performs a right click." msgstr "Executa um clique com botão direito." #: lib/logitech_receiver/settings_templates.py:1273 msgid "Single tap with two fingers" msgstr "Toque único com dois dedos" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Single tap with three fingers" msgstr "Toque único com três dedos" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Double tap" msgstr "Toque duplo" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Performs a double click." msgstr "Executa um clique duplo." #: lib/logitech_receiver/settings_templates.py:1279 msgid "Double tap with two fingers" msgstr "Toque duplo com dois dedos" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Double tap with three fingers" msgstr "Toque duplo com três dedos" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Drags items by dragging the finger after double tapping." msgstr "Deslizar itens arrastando o dedo após um toque duplo." #: lib/logitech_receiver/settings_templates.py:1283 msgid "Tap and drag" msgstr "Tocar e arrastar" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Tap and drag with two fingers" msgstr "Tocar e arrastar com dois dedos" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Drags items by dragging the fingers after double tapping." msgstr "Arrasta itens arrastando os dedos após um toque duplo." #: lib/logitech_receiver/settings_templates.py:1288 msgid "Tap and drag with three fingers" msgstr "Tocar e arrastar com três dedos" #: lib/logitech_receiver/settings_templates.py:1291 msgid "Suppress tap and edge gestures" msgstr "Impedir gestos de toque e borda" #: lib/logitech_receiver/settings_templates.py:1292 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "Desativa os gestos de toque e borda (equivalente a apertar Fn + clique " "esquerdo)." #: lib/logitech_receiver/settings_templates.py:1294 msgid "Scroll with one finger" msgstr "Rolar com um dedo" #: lib/logitech_receiver/settings_templates.py:1294 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scrolls." msgstr "Executa a rolagem." #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scroll with two fingers" msgstr "Rolar com dois dedos" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scroll horizontally with two fingers" msgstr "Rolar horizontalmente com dois dedos" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scrolls horizontally." msgstr "Faz rolagem horizontal." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scroll vertically with two fingers" msgstr "Rolar verticalmente com dois dedos" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scrolls vertically." msgstr "Faz rolagem vertical." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Inverts the scrolling direction." msgstr "Inverte a direção de rolagem." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Natural scrolling" msgstr "Rolagem natural" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Enables the thumbwheel." msgstr "Ativa a roda do polegar." #: lib/logitech_receiver/settings_templates.py:1300 msgid "Thumbwheel" msgstr "Roda do polegar" #: lib/logitech_receiver/settings_templates.py:1311 #: lib/logitech_receiver/settings_templates.py:1315 msgid "Swipe from the top edge" msgstr "Deslizar da borda superior" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Swipe from the left edge" msgstr "Deslizar da borda esquerda" #: lib/logitech_receiver/settings_templates.py:1313 msgid "Swipe from the right edge" msgstr "Deslizar da borda direita" #: lib/logitech_receiver/settings_templates.py:1314 msgid "Swipe from the bottom edge" msgstr "Deslizar da borda inferior" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Swipe two fingers from the left edge" msgstr "Deslizar dois dedos da borda esquerda" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Swipe two fingers from the right edge" msgstr "Deslizar dois dedos da borda direita" #: lib/logitech_receiver/settings_templates.py:1318 msgid "Swipe two fingers from the bottom edge" msgstr "Deslizar dois dedos da borda inferior" #: lib/logitech_receiver/settings_templates.py:1319 msgid "Swipe two fingers from the top edge" msgstr "Deslizar dois dedos da borda superior" #: lib/logitech_receiver/settings_templates.py:1320 #: lib/logitech_receiver/settings_templates.py:1324 msgid "Pinch to zoom out; spread to zoom in." msgstr "Aproximar os dedos para diminuir o zoom; afastá-los para aumentar." #: lib/logitech_receiver/settings_templates.py:1320 msgid "Zoom with two fingers." msgstr "Fazer zoom com dois dedos." #: lib/logitech_receiver/settings_templates.py:1321 msgid "Pinch to zoom out." msgstr "Aproximar os dedos para diminuir o zoom." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Spread to zoom in." msgstr "Afastar os dedos para aumentar o zoom." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Zoom with three fingers." msgstr "Fazer zoom com três dedos." #: lib/logitech_receiver/settings_templates.py:1324 msgid "Zoom with two fingers" msgstr "Fazer zoom com dois dedos" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Pixel zone" msgstr "Região de pixels" #: lib/logitech_receiver/settings_templates.py:1343 msgid "Ratio zone" msgstr "Região de proporção" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scale factor" msgstr "Fator de escala" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Sets the cursor speed." msgstr "Define a velocidade do cursor." #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left" msgstr "Esquerda" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left-most coordinate." msgstr "Coordenada do ponto mais à esquerda." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom" msgstr "Fundo" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom coordinate." msgstr "Coordenada inferior." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width" msgstr "Largura" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width." msgstr "Largura." #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height" msgstr "Altura" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height." msgstr "Altura." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Cursor speed." msgstr "Velocidade do cursor." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Scale" msgstr "Escala" #: lib/logitech_receiver/settings_templates.py:1358 msgid "Gestures" msgstr "Gestos" #: lib/logitech_receiver/settings_templates.py:1359 msgid "Tweak the mouse/touchpad behaviour." msgstr "Ajustar o comportamento do mouse/touchpad." #: lib/logitech_receiver/settings_templates.py:1375 msgid "Gestures Diversion" msgstr "Desvio de Gesto" #: lib/logitech_receiver/settings_templates.py:1376 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1392 msgid "Gesture params" msgstr "Parâmetros de gestos" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Alterar parâmetros numéricos de um mouse/touchpad." #: lib/logitech_receiver/settings_templates.py:1417 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1419 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1423 #: lib/logitech_receiver/settings_templates.py:1454 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1429 #, python-format msgid "Lights up the %s key." msgstr "Ilumina a tecla %s." #: lib/logitech_receiver/settings_templates.py:1448 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1450 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1471 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1473 msgid "Permanently change the mapping for the key or button." msgstr "Alterar permanentemente o mapeamento da tecla ou do botão." #: lib/logitech_receiver/settings_templates.py:1475 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Alterar teclas ou botões importantes (como o botão esquerdo do mouse) pode " "tornar o sistema inutilizável." #: lib/logitech_receiver/settings_templates.py:1532 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1533 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1542 msgid "Equalizer" msgstr "Equalizador" #: lib/logitech_receiver/settings_templates.py:1543 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1565 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1571 msgid "Power Management" msgstr "Gerenciamento de energia" #: lib/logitech_receiver/settings_templates.py:1572 msgid "Power off in minutes (0 for never)." msgstr "Desligamento em minutos (0 para nunca)." #: lib/logitech_receiver/settings_templates.py:1584 msgid "Brightness Control" msgstr "Controle de brilho" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Control overall brightness" msgstr "Controle o brilho geral" #: lib/logitech_receiver/settings_templates.py:1628 #: lib/logitech_receiver/settings_templates.py:1681 msgid "LED Control" msgstr "LED Control" #: lib/logitech_receiver/settings_templates.py:1629 #: lib/logitech_receiver/settings_templates.py:1682 msgid "Switch control of LED zones between device and Solaar" msgstr "Controle as zonas de LED alternando entre o dispositivo e o Solaar" #: lib/logitech_receiver/settings_templates.py:1644 #: lib/logitech_receiver/settings_templates.py:1692 msgid "LED Zone Effects" msgstr "" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "LED Control needs to be set to Solaar to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "Set effect for LED Zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1647 msgid "Color" msgstr "Cor" #: lib/logitech_receiver/settings_templates.py:1648 msgid "Speed" msgstr "Velocidade" #: lib/logitech_receiver/settings_templates.py:1649 msgid "Period" msgstr "Período" #: lib/logitech_receiver/settings_templates.py:1650 msgid "Intensity" msgstr "Intensity" #: lib/logitech_receiver/settings_templates.py:1651 msgid "Ramp" msgstr "Rampa" #: lib/logitech_receiver/settings_templates.py:1666 msgid "LEDs" msgstr "LEDs" #: lib/logitech_receiver/settings_templates.py:1703 msgid "Per-key Lighting" msgstr "Iluminação por tecla" #: lib/logitech_receiver/settings_templates.py:1704 msgid "Control per-key lighting." msgstr "Control per-key lighting." #: lib/logitech_receiver/settings_templates.py:1786 msgid "Force Sensing Buttons" msgstr "" #: lib/logitech_receiver/settings_templates.py:1787 msgid "Change the force required to activate button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1804 msgid "Force Sensing Button" msgstr "" #: lib/logitech_receiver/settings_templates.py:1814 msgid "Haptic Feeback Level" msgstr "Nível de feedback háptico" #: lib/logitech_receiver/settings_templates.py:1815 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "Alterar a intensidade do feedback tátil. (Zero para desligar.)" #: lib/logitech_receiver/settings_templates.py:1857 msgid "Play Haptic Waveform" msgstr "Reproduzir forma de onda háptica" #: lib/logitech_receiver/settings_templates.py:1858 msgid "Tell device to play a haptic waveform." msgstr "Diga ao dispositivo para reproduzir uma forma de onda háptica." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Gerencia receptores, teclados,\n" "mouses e tablets da Logitech." #: lib/solaar/ui/about/model.py:63 msgid "Additional Programming" msgstr "Programação adicional" #: lib/solaar/ui/about/model.py:64 msgid "GUI design" msgstr "Design da GUI" #: lib/solaar/ui/about/model.py:66 msgid "Testing" msgstr "Teste" #: lib/solaar/ui/about/model.py:74 msgid "Logitech documentation" msgstr "Documentação da Logitech" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Desemparelhar" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "Cancelar" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Erro de permissão" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Foi encontrado um receptor ou dispositivo Logitech (%s), mas não tinha " "permissão para abri-lo." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Se você acabou de instalar o Solaar, tente desconectar o receptor ou " "dispositivo e, em seguida, reconectá-lo." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Erro - não foi possível conectar-se ao dispositivo" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Foi encontrado um receptor ou dispositivo Logitech em %s, mas houve um erro " "ao conectar-se a ele." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Tente desconectar o dispositivo e reconectá-lo, ou desligá-lo e ligá-lo " "novamente." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "Desemparelhamento falhou" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Falha ao desemparelhar %{device} do %{receiver}." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "O receptor retornou um erro, sem maiores detalhes." #: lib/solaar/ui/config_panel.py:245 msgid "Complete - ENTER to change" msgstr "Completo - pressione ENTER para alterar" #: lib/solaar/ui/config_panel.py:245 msgid "Incomplete" msgstr "Incompleto" #: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d valor" msgstr[1] "%d valores" #: lib/solaar/ui/config_panel.py:642 msgid "Changes allowed" msgstr "Mudanças permitidas" #: lib/solaar/ui/config_panel.py:643 msgid "No changes allowed" msgstr "Mudanças não permitidas" #: lib/solaar/ui/config_panel.py:644 msgid "Ignore this setting" msgstr "Ignorar esta configuração" #: lib/solaar/ui/config_panel.py:690 msgid "Working" msgstr "Funcionando" #: lib/solaar/ui/config_panel.py:693 msgid "Read/write operation failed." msgstr "Operação de leitura/escrita falhou." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "razão não especificada" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "Regras predefinidas" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "Regras do usuário" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "Regra" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "Sub-regra" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "[vazio]" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "Tornar as alterações permanentes?" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "Sim" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "Não" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "" "Se você escolher Não, as alterações serão perdidas quando o Solaar for " "fechado." #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "Colar aqui" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "Colar acima" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "Colar abaixo" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "Colar regra aqui" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "Colar regra acima" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "Colar regra abaixo" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "Colar regra" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "Inserir aqui" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "Inserir acima" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "Inserir abaixo" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "Inserir nova regra aqui" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "Inserir nova regra acima" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "Inserir nova regra abaixo" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "Desaninhar" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "Inserir" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "Ou" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "E" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "Condição" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Feature" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Report" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Processo" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "Processo do mouse" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Teclas modificadoras" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Tecla" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "Tecla Pressionada" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "Ativo" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "Dispositivo" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "Host" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "Configuração" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "Teste" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Bytes de teste" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Gesto do mouse" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "Ação" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "Pressionamento de tecla" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Rolagem do mouse" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Clique do mouse" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "Definir" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "Executar" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "Mais tarde" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "Inserir nova regra" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Apagar" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "Negar" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "Envolver com" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "Recortar" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "Colar" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "Copiar" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "Editor de Regras do Solaar" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "Salvar alterações" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "Descartar alterações" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "Este editor ainda não suporta o componente de regra selecionado." #: lib/solaar/ui/diversion_rules.py:1169 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Número de segundos de atraso. Atrasos entre 0 e 1 são calculados com maior " "precisão." #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "Não" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "Alternar" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "Verdadeiro" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "Falso" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "Configuração não suportada" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "Dispositivo de origem" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "O dispositivo está ativo e suas configurações podem ser alteradas." #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "Dispositivo que originou a notificação atual." #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "Name of host computer." #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "Valor" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "Item" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "Alterar configuração no dispositivo" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "Configuração no dispositivo" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: new dispositivo emparelhado" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Os receptores Bolt são compatíveis apenas com dispositivos Bolt." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Pressione o botão ou tecla de emparelhamento até que a luz de emparelhamento " "pisque rapidamente." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" "Os receptores Unifying são compatíveis apenas com dispositivos Unifying." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "Outros receptores são compatíveis apenas com alguns dispositivos." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "" "Para a maioria dos dispositivos, ligue o dispositivo que deseja emparelhar." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "Se o dispositivo já estiver ligado, desligue-o e ligue-o novamente." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" "O dispositivo não deve estar emparelhado com um receptor ligado nas " "proximidades." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "A luz indicadora do canal deve estar piscando rapidamente." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Este dispositivo tem %d pareamento disponível." msgstr[1] "" "\n" "\n" "Este dispositivo tem %d pareamentos disponíveis." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Cancelar neste ponto não usará um pareamento." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Digite a senha em %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Digite %(passcode)s e então pressione a tecla Enter." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "esquerda" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "direita" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Pressione %(code)s\n" "e em seguida, pressione os botões esquerdo e direito simultaneamente." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "A conexão sem fio não é criptografada" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Encontrado um novo dispositivo:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Emparelhamento falhou" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Certifique-se de que o seu dispositivo esteja dentro do alcance e, que " "possui bateria com carga aceitável." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "" "Um novo dispositivo foi detectado, mas não é compatível com este receptor." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "Há mais dispositivos pareados do que o receptor suporta." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Sem maiores detalhes sobre o erro." #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simule um clique, pressionamento ou liberação de tecla em conjunto.\n" "No Wayland, requer acesso de gravação a /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Adicionar tecla" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Clique" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Pressionar" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Liberar" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simule a rolagem do mouse.\n" "Em Wayland, é necessário ter acesso de escrita a /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simule o clique do mouse.\r\n" "Em Wayland, é necessário ter acesso de escrita a /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Botão" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Ação (e contagem, se houver clique)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Executar um comando com argumentos." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Adicionar argumento" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "Processo ativo do X11. Para uso exclusivo no X11." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "Processo de mouse X11. Para uso exclusivo no X11." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "Processo (mouse)" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Tecla pressionada" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Tecla liberada" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Parâmetro" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "início (inclusivo)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "fim (exclusivo)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "faixa" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "mínimo" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "máximo" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "máscara" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "tipo" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Gesto do mouse com botão iniciador opcional, seguido por zero ou mais " "movimentos do mouse." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Adicionar movimento" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Nenhum dispositivo suportado encontrado" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "Sobre o %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Sair do %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "nenhum receptor" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:728 msgid "offline" msgstr "offline" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "sem status" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Procurando" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Bateria" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Conexão sem fio" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "Iluminação" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Mostrar detalhes técnicos" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Emparelhar novo dispositivo" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Selecione um dispositivo" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Editor de regras" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Caminho" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "ID USB" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546 msgid "Serial" msgstr "Número de série" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "�ndice" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "PID sem fio" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "ID do produto" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "Protocolo" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "Desconhecido" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "Taxa de sondagem" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "Unit ID" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "nenhum" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "Notificações" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "Nenhum dispositivo emparelhado." #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Até %(max_count)s dispositivo pode ser emparelhado neste receptor." msgstr[1] "" "Até %(max_count)s dispositivos podem ser emparelhados neste receptor." #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "Apenas um dispositivo pode ser emparelhado neste receptor." #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Este dispositivo tem %d pareamento disponível." msgstr[1] "Este dispositivo tem %d pareamentos disponíveis." #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "Tensão da Bateria" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "Tensão informada pela bateria" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "Nível de bateria" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "Nível aproximado informado pela bateria" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "próximo valor informado: " #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr " e o próximo nível que será informado." #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "último conhecido" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "criptografada" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "A conexão sem fio entre o dispositivo e seu receptor é criptografada." #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "não criptografada" #: lib/solaar/ui/window.py:721 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "A conexão sem fio entre este dispositivo e o seu receptor não está " "criptografada.\n" "Isso representa um problema de segurança para dispositivos apontadores e um " "problema de segurança grave para dispositivos de entrada de texto." #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid " paired devices." #~ msgstr " dispositivos emparelhados." #~ msgid "%(battery_level)s" #~ msgstr "%(battery_level)s" #~ msgid "%(battery_percent)d%%" #~ msgstr "%(battery_percent)d%%" #, python-format #~ msgid "%(rate)d ms (%(rate_hz)dHz)" #~ msgstr "%(rate)d ms (%(rate_hz)dHz)" #~ msgid "1 paired device." #~ msgstr "1 dispositivo emparelhado." #~ msgid "Add action" #~ msgstr "Adicionar ação" #~ msgid "" #~ "Adjust the DPI by sliding the mouse horizontally while holding the DPI " #~ "button." #~ msgstr "" #~ "Ajustar o DPI deslizando o mouse horizontalmente ao segurar o botão DPI." #~ msgid "" #~ "Adjust the DPI by sliding the mouse horizontally while holding the button " #~ "down." #~ msgstr "Ajustar DPI deslizando o mouse horizontalmente ao segurar o botão." #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always locked at 50" #~ msgstr "" #~ "Automaticamente alterna a roda do mouse entre modo catraca e modo livre.\n" #~ "A roda do mouse está sempre live em 0, e sempre em modo catraca em 50" #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "" #~ "Alternar automaticamente a roda do mouse entre o modo de catraca e o modo " #~ "de rotação livre.\n" #~ "A roda do mouse fica sempre livre no valor 0, e sempre no modo catraca no " #~ "valor 50" #~ msgid "Battery information unknown." #~ msgstr "A informação sobre a bateria é desconhecida." #, python-format #~ msgid "Battery: %(level)s" #~ msgstr "Bateria: %(level)s" #, python-format #~ msgid "Battery: %(percent)d%%" #~ msgstr "Bateria: %(percent)d%%" #~ msgid "Count" #~ msgstr "Número" #~ msgid "DPI Sliding Adjustment" #~ msgstr "Ajuste de DPI por deslizamento" #~ msgid "DPI Sliding Ajustment" #~ msgstr "Ajuste de DPI por deslizamento" #~ msgid "Divert G Keys" #~ msgstr "Desviar teclas G" #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Na prática, desativa a rolagem com o polegar no Linux." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Na prática, desativa a rolagem com a roda no Linux." #~ msgid "" #~ "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "" #~ "Para mais informações, consulte as instruções de instalação do Solaar\n" #~ "em https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "" #~ "Found a Logitech Receiver (%s), but did not have permission to open it." #~ msgstr "" #~ "Foi encontrado um Receptor da Logitech (%s), mas sem permissão para abri-" #~ "lo." #~ msgid "Found a new device" #~ msgstr "Novo dispositivo encontrado" #~ msgid "Frequency of device polling, in milliseconds" #~ msgstr "Frequência de sondagem, em milissegundos" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "Modo HID++ para a rolagem horizontal com o polegar." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "Modo HID++ para a rolagem vertical com a roda." #~ msgid "High Resolution Wheel Invert" #~ msgstr "Roda Invertida de Alta Resolução" #~ msgid "High-sensitivity wheel invert mode for vertical scroll." #~ msgstr "Roda invertida de alta sensibilidade para rolagem vertical." #~ msgid "" #~ "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "" #~ "Se o dispositivo já encontra-se ligado,\n" #~ "desligue-o e ligue-o novamente." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Se o dispositivo já estiver ligado, desligue-o e ligue-o novamente." #~ msgid "" #~ "If you've just installed Solaar, try removing the receiver and plugging " #~ "it back in." #~ msgstr "" #~ "Se você acabou de instalar o Solaar, tente retirar o receptor e conectá-" #~ "lo novamente." #, python-format #~ msgid "Lighting: %(level)s lux" #~ msgstr "Iluminação: %(level)s lux" #~ msgid "" #~ "Make G keys send GKEY HID++ notifications (which trigger Solaar rules but " #~ "are otherwise ignored)." #~ msgstr "" #~ "Fazer as teclas G enviarem notificações HID++ GKEY (que desencadeiam " #~ "regras do Solaar, mas são ignoradas fora disso)." #~ msgid "" #~ "Make the key or button send HID++ notifications (which trigger Solaar " #~ "rules but are otherwise ignored)." #~ msgstr "" #~ "Fazer as teclas ou botões enviarem notificações HID++ (que desencadeiam " #~ "regras do Solaar, mas são ignoradas fora disso)." #~ msgid "No Logitech receiver found" #~ msgstr "Nenhum receptor da Logitech encontrado" #~ msgid "No device paired" #~ msgstr "Nenhum dispositivo emparelhado" #~ msgid "Only one device can be paired to this receiver" #~ msgstr "Apenas um dispositivo pode ser emparelhado com este receptor" #~ msgid "Polling Rate (ms)" #~ msgstr "Taxa de Sondagem (ms)" #~ msgid "Scroll Wheel HID++ Scrolling" #~ msgstr "Rolagem com a roda usando HID++" #~ msgid "Scroll Wheel Rachet" #~ msgstr "Rolagem no modo catraca" #~ msgid "Send a gesture by sliding the mouse while holding the button down." #~ msgstr "Enviar um gesto deslizando o mouse ao segurar o botão." #~ msgid "" #~ "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "" #~ "Mostra o status dos dispositivos conectados\n" #~ "através de receptores sem fio da Logitech." #~ msgid "Smooth Scrolling" #~ msgstr "Rolagem suave" #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar depende de um arquivo udev que não está presente." #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "O receptor só suporta %d dispositivo(s) emparelhado(s)" #~ msgid "The receiver was unplugged." #~ msgstr "O receptor foi desplugado." #~ msgid "" #~ "The wireless link between this device and its receiver is not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices (keyboards, " #~ "numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties within " #~ "range." #~ msgstr "" #~ "A conexão sem fio entre o dispositivo e seu receptor não é " #~ "criptografada.\n" #~ "\n" #~ "Para dispositivos de apontamento (mouses, trackballs, trackpads), isto " #~ "não representa um grande problema de segurança.\n" #~ "\n" #~ "No entanto, é um grande problema de segurança para dispositivos de " #~ "entrada de texto (teclados, teclados numéricos), pois\n" #~ "o texto digitado pode ser capturado, de forma indetectável, por terceiros " #~ "que estejam dentro do alcance." #~ msgid "Thumb Wheel HID++ Scrolling" #~ msgstr "Rolagem com o polegar usando HID++" #~ msgid "Top-most coordinate." #~ msgstr "Coordenada do ponto mais acima." #~ msgid "Triple tap" #~ msgstr "Toque triplo" #~ msgid "" #~ "Try removing the device and plugging it back in or turning it off and " #~ "then on." #~ msgstr "" #~ "Tente remover o dispositivo e conectá-lo novamente, ou desligá-lo e ligá-" #~ "lo." #~ msgid "Turn illumination on or off on keyboard." #~ msgstr "Ativar ou desativar a iluminação do teclado." #~ msgid "Turn on the device you want to pair." #~ msgstr "Ligue o dispositivo que você quer emparelhar." #~ msgid "USB id" #~ msgstr "ID do USB" #~ msgid "Up to %d devices can be paired to this receiver" #~ msgstr "Até %d dispositivos podem ser emparelhados com este receptor" #~ msgid "Wheel Resolution" #~ msgstr "Resolução da Roda" #~ msgid "closed" #~ msgstr "fechado" #~ msgid "height" #~ msgstr "altura" #~ msgid "lux" #~ msgstr "lux" #~ msgid "open" #~ msgstr "aberto" #~ msgid "pair new device" #~ msgstr "emparelhar novo dispositivo" #~ msgid "paired devices" #~ msgstr "dispositivos emparelhados" #~ msgid "pairing lock is " #~ msgstr "trava de emparelhamento está " #~ msgid "top" #~ msgstr "topo" #~ msgid "unknown" #~ msgstr "desconhecida" #~ msgid "width" #~ msgstr "largura" Solaar-1.1.20/po/ro.po000066400000000000000000001351731522022367600144310ustar00rootroot00000000000000# Romanian translations for solaar package. # Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2013. # msgid "" msgstr "Project-Id-Version: solaar 0.9.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2013-07-17 20:27+0100\n" "Last-Translator: Daniel Pavel \n" "Language-Team: none\n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && " "n%100 < 20)) ? 1 : 2;\n" "X-Generator: Poedit 1.5.4\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "descărcată" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "aproape descărcată" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "joasă" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "bună" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "plină" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "în descarcare" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "re-încărcare" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "se încarcă" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "aproape plină" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "încarcare inceată" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "baterie necorespunzătoare" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "eroare termică" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "periferic incompatibil" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "prea multe periferice" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "conectat(ă)" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "deconectat(ă)" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "a pornit" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Inversează funcțiile Fx" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Când este activ, tastele F1..F12 vor opera funcțiile speciale,\n" "și trebuie să țineți apăsată tasta FN pentru a folosi funcțiile lor " "standard." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Când nu este activ, tastele F1..F12 vor opera functiile standard,\n" "și trebuie să țineți apăsată tasta FN pentru a folosi funcțiile lor " "speciale." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Senzitivitate crescută la derularea verticală cu rotița." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Derulare orizontală" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "" #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "" #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Sentivitivate (PPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "" #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "" #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "" #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "" #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "" #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "" #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "" #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "" #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Factor de scalare" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Lățime" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Înălțime" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "" #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gesturi" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "" #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "" #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Nici un periferic contectat." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "" msgstr[1] "" msgstr[2] "" #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Eroare de permisiuni" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Deconectare eșuată" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Deconectarea %{device} de la %{receiver} a eșuat." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "Receptorul a semnalat o eroare, fără alte detalii." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "Interfață grafica" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Testare" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Documentație Logitech" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Deconectează" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "" msgstr[1] "" msgstr[2] "" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Prelucrez" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Operațiunea a eșuat." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Da" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "" #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Activ" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Acțiune" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Taie" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Lipește" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Copiază" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "" #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "" #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Valoare" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "inactivă" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "" #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Conectare eșuată" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Asigurați-vă că dispozitivul este în apropiere, iar bateria este " "încarcată." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "A fost detectat un nou periferic, dar nu este compatibil cu acest " "receptor." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "" #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Alte detalii despre eroare nu sunt disponibile." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "Legătura fără fir nu este criptată" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Porniți dispozitivul pe care doriți să-l conectați." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" msgstr[1] "" msgstr[2] "" #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "" #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "Despre %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Ieșire %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "nici un receptor" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "stare necunoscută" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Caut" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Baterie" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Legatură fără fir" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Lumină" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Detalii tehnice" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Conectează periferic" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Selectați un dispozitiv" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Cale" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Serial" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "Cod WPID" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "ID produs" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protocol" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Necunoscut" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Rată acces" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "nici una" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Notificări" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "" #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "" msgstr[1] "" msgstr[2] "" #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "" #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "" msgstr[1] "" msgstr[2] "" #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "" #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr "" #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "ultima valoare" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "criptată" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Legătura fără fir este criptată." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "ne-criptată" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "" #~ msgid " paired devices." #~ msgstr " periferice contectate." #~ msgid "1 paired device." #~ msgstr "Un periferic contectat." #~ msgid "Count" #~ msgstr "Contor" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Receptor Logitech detectat (%s), dar nu am permisiunea să-l " #~ "deschid." #~ msgid "Found a new device" #~ msgstr "Periferic nou detectat" #~ msgid "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "Dacă dispozitivul este deja pornit,\n" #~ "opriți-l și porniți-l din nou." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Dacă tocmai ați instalat Solaar, scoateți receptorul și re-" #~ "introduceți-l." #~ msgid "No Logitech receiver found" #~ msgstr "Nu am găsit nici un receptor Logitech" #~ msgid "No device paired" #~ msgstr "Nici un periferic conectat" #~ msgid "Only one device can be paired to this receiver" #~ msgstr "Acest receptor suportă un singur periferic conectat" #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Afișează starea perifericelor conectate\n" #~ "printr-un receptor Logitech fără fir." #~ msgid "Smooth Scrolling" #~ msgstr "Derulare fină" #, python-format #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Receptorul suportă maxim %d periferic(e) contectate." #~ msgid "The receiver was unplugged." #~ msgstr "Receptor deconectat." #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "Legătura fără fir nu este criptată." #~ msgid "USB id" #~ msgstr "USB" #~ msgid "Up to %d devices can be paired to this receiver" #~ msgstr "Acest receptor suportă maxim %d periferice conectate" #~ msgid "closed" #~ msgstr "închis" #~ msgid "height" #~ msgstr "înălțime" #~ msgid "lux" #~ msgstr "lucși" #~ msgid "open" #~ msgstr "deschis" #~ msgid "pair new device" #~ msgstr "conectează periferic nou" #~ msgid "paired devices" #~ msgstr "periferice conectate" #~ msgid "pairing lock is " #~ msgstr "lacătul de contectare este " #~ msgid "unknown" #~ msgstr "necunoscută" #~ msgid "width" #~ msgstr "lățime" Solaar-1.1.20/po/ru.po000066400000000000000000002271201522022367600144310ustar00rootroot00000000000000# Russian translations for solaar package. # Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # # Automatically generated, 2013. # Dmitry Ryazantcev , 2013-2016. # Vadim Illarionov , 2021. # Olesya Gerasimenko , 2021, 2022. # MistificaT0r <0mistificator0@gmail.com>, 2024. msgid "" msgstr "Project-Id-Version: solaar 1.1.13\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-12-01 21:43+0300\n" "PO-Revision-Date: 2024-04-21 01:38+0300\n" "Last-Translator: MistificaT0r <0mistificator0@gmail.com>\n" "Language-Team: ru\n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 " "&& n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Lokalize 24.02.2\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Приёмник «Bolt»" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Приёмник «Unifying»" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Приёмник «Nano»" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Приёмник «Lightspeed»" #: lib/logitech_receiver/base_usb.py:135 msgid "EX100 Receiver 27 Mhz" msgstr "Приёмник «EX100» 27 МГц" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Батаре�: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Батаре�: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1048 #: lib/logitech_receiver/settings_templates.py:299 msgid "Disabled" msgstr "Отключено" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Static" msgstr "Статичный" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Pulse" msgstr "Пуль�" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Cycle" msgstr "Цикл" #: lib/logitech_receiver/hidpp20.py:1052 msgid "Boot" msgstr "Запу�к" #: lib/logitech_receiver/hidpp20.py:1053 msgid "Demo" msgstr "Демон�траци�" #: lib/logitech_receiver/hidpp20.py:1055 msgid "Breathe" msgstr "Дышать" #: lib/logitech_receiver/hidpp20.py:1058 msgid "Ripple" msgstr "Пуль�аци�" #: lib/logitech_receiver/hidpp20.py:1059 msgid "Decomposition" msgstr "Разложение" #: lib/logitech_receiver/hidpp20.py:1060 msgid "Signature1" msgstr "Подпи�ь1" #: lib/logitech_receiver/hidpp20.py:1061 msgid "Signature2" msgstr "Подпи�ь2" #: lib/logitech_receiver/hidpp20.py:1062 msgid "CycleS" msgstr "Циклы" #: lib/logitech_receiver/hidpp20.py:1126 msgid "Unknown Location" msgstr "�еизве�тное ме�тоположение" #: lib/logitech_receiver/hidpp20.py:1127 msgid "Primary" msgstr "Первичный" #: lib/logitech_receiver/hidpp20.py:1128 msgid "Logo" msgstr "Логотип" #: lib/logitech_receiver/hidpp20.py:1129 msgid "Left Side" msgstr "Лева� �торона" #: lib/logitech_receiver/hidpp20.py:1130 msgid "Right Side" msgstr "Права� �торона" #: lib/logitech_receiver/hidpp20.py:1131 msgid "Combined" msgstr "Комбинированный" #: lib/logitech_receiver/hidpp20.py:1132 msgid "Primary 1" msgstr "Первичный 1" #: lib/logitech_receiver/hidpp20.py:1133 msgid "Primary 2" msgstr "Первичный 2" #: lib/logitech_receiver/hidpp20.py:1134 msgid "Primary 3" msgstr "Первичный 3" #: lib/logitech_receiver/hidpp20.py:1135 msgid "Primary 4" msgstr "Первичный 4" #: lib/logitech_receiver/hidpp20.py:1136 msgid "Primary 5" msgstr "Первичный 5" #: lib/logitech_receiver/hidpp20.py:1137 msgid "Primary 6" msgstr "Первичный 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "пу�то" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "критиче�кий" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "низкий" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "�редний" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "нормальный" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "полный" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "разр�жает��" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "перезар�жает��" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "зар�жает��" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "не зар�жает��" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "почти полна�" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "зар�жено" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "медленна� разр�дка" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "недопу�тима� батаре�" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "теплова� ошибка" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "ошибка" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "�тандартно" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "бы�тро" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "медленно" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "тайм-аут у�трой�тва" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "у�трой�тво не поддерживает��" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "�лишком много у�трой�тв" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "тайм-аут по�ледовательно�ти" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "Прошивка" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Загрузчик" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Оборудование" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Другое" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Лева� кнопка" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Права� кнопка" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Средн�� кнопка" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Кнопка назад" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Кнопка вперёд" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Кнопка же�тов" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Умный Переход" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Переключатель чув�твительно�ти" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "�аклон влево" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "�аклон вправо" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Щелчок левой кнопкой" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Щелчок правой кнопкой" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Средн�� кнопка мыши" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Кнопка мыши �азад" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Кнопка мыши Вперед" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "�авигаци� кнопкой же�тов" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Кнопка прокрутки влево" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Кнопка прокрутки вправо" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "нажата" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "отпущена" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "�оединено" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "разъединено" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "не �опр�жено" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "включено" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "Уведомление об измерении ADC" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is closed" msgstr "�опр�жение заблокировано" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is open" msgstr "�опр�жение разблокировано" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is closed" msgstr "обнаружение заблокировано" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is open" msgstr "обнаружение разблокировано" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "�ет �опр�жённых у�трой�тв." #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s �опр�жённое у�трой�тво." msgstr[1] "%(count)s �опр�жённых у�трой�тва." msgstr[2] "%(count)s �опр�жённых у�трой�тв." #: lib/logitech_receiver/settings.py:602 msgid "register" msgstr "зареги�трировано" #: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654 msgid "feature" msgstr "о�обенно�ть" #: lib/logitech_receiver/settings_templates.py:138 msgid "Swap Fx function" msgstr "Сменить поведение Fx" #: lib/logitech_receiver/settings_templates.py:141 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Когда включено, кнопки F1..F12 работают по дополнительным функци�м,\n" "а выбор о�новных производит�� � зажатой кнопкой «FN»." #: lib/logitech_receiver/settings_templates.py:146 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Когда выключено, кнопки F1..F12 работают по о�новным функци�м,\n" "а выбор дополнительных производит�� � зажатой кнопкой «FN»." #: lib/logitech_receiver/settings_templates.py:154 msgid "Hand Detection" msgstr "Обнаружение рук" #: lib/logitech_receiver/settings_templates.py:155 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Включать под�ветку, когда руки над клавиатурой." #: lib/logitech_receiver/settings_templates.py:162 msgid "Scroll Wheel Smooth Scrolling" msgstr "Плавна� прокрутка коле�ом мыши" #: lib/logitech_receiver/settings_templates.py:163 #: lib/logitech_receiver/settings_templates.py:410 #: lib/logitech_receiver/settings_templates.py:439 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Режим вы�окой чув�твительно�ти дл� вертикальной прокрутки коле�ом." #: lib/logitech_receiver/settings_templates.py:170 msgid "Side Scrolling" msgstr "Горизонтальна� прокрутка" #: lib/logitech_receiver/settings_templates.py:172 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Когда отключено, нажатие на коле�о �боку\n" "вме�то �тандартных �обытий горизонтальной прокрутки\n" "будет отправл�ть пользователь�кие �обыти� нажати�." #: lib/logitech_receiver/settings_templates.py:182 msgid "Sensitivity (DPI - older mice)" msgstr "Чув�твительно�ть (тчк/дюйм — �тарые мыши)" #: lib/logitech_receiver/settings_templates.py:183 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 msgid "Mouse movement sensitivity" msgstr "Чув�твительно�ть перемещени� мыши" #: lib/logitech_receiver/settings_templates.py:256 msgid "Backlight Timed" msgstr "Под�ветка по времени" #: lib/logitech_receiver/settings_templates.py:257 #: lib/logitech_receiver/settings_templates.py:397 msgid "Set illumination time for keyboard." msgstr "�а�тройка времени под�ветки клавиатуры." #: lib/logitech_receiver/settings_templates.py:268 msgid "Backlight" msgstr "Под�ветка" #: lib/logitech_receiver/settings_templates.py:269 msgid "Illumination level on keyboard. Changes made are only applied in " "Manual mode." msgstr "Уровень под�ветки клавиатуры. Вне�енные изменени� примен�ют�� только " "в Ручном режиме." #: lib/logitech_receiver/settings_templates.py:301 msgid "Automatic" msgstr "�втоматиче�кий" #: lib/logitech_receiver/settings_templates.py:303 msgid "Manual" msgstr "Ручной" #: lib/logitech_receiver/settings_templates.py:305 msgid "Enabled" msgstr "Включенный" #: lib/logitech_receiver/settings_templates.py:311 msgid "Backlight Level" msgstr "Уровень под�ветки" #: lib/logitech_receiver/settings_templates.py:312 msgid "Illumination level on keyboard when in Manual mode." msgstr "Уровень о�вещенно�ти клавиатуры в ручном режиме." #: lib/logitech_receiver/settings_templates.py:369 msgid "Backlight Delay Hands Out" msgstr "Задержка под�ветки" #: lib/logitech_receiver/settings_templates.py:370 msgid "Delay in seconds until backlight fades out with hands away from " "keyboard." msgstr "Задержка в �екундах, пока под�ветка не пога�нет, е�ли руки не будут " "лежать на клавиатуре." #: lib/logitech_receiver/settings_templates.py:378 msgid "Backlight Delay Hands In" msgstr "Задержка под�ветки �трелок в" #: lib/logitech_receiver/settings_templates.py:379 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "Задержка в �екундах, пока под�ветка не пога�нет, е�ли руки наход�т�� " "р�дом � клавиатурой." #: lib/logitech_receiver/settings_templates.py:387 msgid "Backlight Delay Powered" msgstr "Включение под�ветки � задержкой" #: lib/logitech_receiver/settings_templates.py:388 msgid "Delay in seconds until backlight fades out with external power." msgstr "Задержка в �екундах до тех пор, пока под�ветка не пога�нет при " "включении внешнего питани�." #: lib/logitech_receiver/settings_templates.py:396 msgid "Backlight (Seconds)" msgstr "Под�ветка (�екунды)" #: lib/logitech_receiver/settings_templates.py:408 msgid "Scroll Wheel High Resolution" msgstr "Вы�окое разрешение коле�а прокрутки" #: lib/logitech_receiver/settings_templates.py:412 #: lib/logitech_receiver/settings_templates.py:441 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "�а�тройка игнорировани� �лишком бы�трой или медленной прокрутки" #: lib/logitech_receiver/settings_templates.py:419 #: lib/logitech_receiver/settings_templates.py:450 msgid "Scroll Wheel Diversion" msgstr "Поведение коле�а прокрутки" #: lib/logitech_receiver/settings_templates.py:421 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "За�тавить коле�о прокрутки отправл�ть уведомлени� LOWRES_WHEEL HID++ " "(которые запу�кают правила Solaar, но в о�тальном игнорируют��)." #: lib/logitech_receiver/settings_templates.py:428 msgid "Scroll Wheel Direction" msgstr "�аправление прокрутки" #: lib/logitech_receiver/settings_templates.py:429 msgid "Invert direction for vertical scroll with wheel." msgstr "Обратна� прокрутка коле�ом." #: lib/logitech_receiver/settings_templates.py:437 msgid "Scroll Wheel Resolution" msgstr "Разрешение прокрутки коле�ом" #: lib/logitech_receiver/settings_templates.py:452 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "За�тавить коле�о прокрутки отправл�ть уведомлени� HIRES_WHEEL HID++ " "(которые запу�кают правила Solaar, но в о�тальном игнорируют��)." #: lib/logitech_receiver/settings_templates.py:461 msgid "Sensitivity (Pointer Speed)" msgstr "Чув�твительно�ть (�коро�ть указател�)" #: lib/logitech_receiver/settings_templates.py:462 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Множитель �коро�ти мыши (обычно - 256)." #: lib/logitech_receiver/settings_templates.py:472 msgid "Thumb Wheel Diversion" msgstr "Поведение бокового коле�а" #: lib/logitech_receiver/settings_templates.py:474 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "За�тавить коле�о большого пальца отправл�ть уведомлени� THUMB_WHEEL " "HID++ (которые запу�кают Правила Solaar, но в о�тальном " "игнорируют��)." #: lib/logitech_receiver/settings_templates.py:483 msgid "Thumb Wheel Direction" msgstr "�аправление вращени� бокового коле�а" #: lib/logitech_receiver/settings_templates.py:484 msgid "Invert thumb wheel scroll direction." msgstr "Измен�ет направление вращени� бокового коле�а." #: lib/logitech_receiver/settings_templates.py:504 msgid "Onboard Profiles" msgstr "В�троенные профили" #: lib/logitech_receiver/settings_templates.py:505 msgid "Enable an onboard profile, which controls report rate, sensitivity, " "and button actions" msgstr "Включите в�троенный профиль, который контролирует ча�тоту отчетов, " "чув�твительно�ть, и дей�тви� кнопок" #: lib/logitech_receiver/settings_templates.py:549 #: lib/logitech_receiver/settings_templates.py:582 msgid "Report Rate" msgstr "Ча�тота отчетов" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 msgid "Frequency of device movement reports" msgstr "Ча�тота �ообщений о перемещении у�трой�тва" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1421 #: lib/logitech_receiver/settings_templates.py:1452 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "Дл� работы может потребовать�� отключить параметр «В�троенные " "профили»." #: lib/logitech_receiver/settings_templates.py:612 msgid "Divert crown events" msgstr "Поведение верньера" #: lib/logitech_receiver/settings_templates.py:613 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Включает отправку верньером оповещени� CROWN HID++ (применимо только " "к правилам Solaar, о�тальными игнорирует��)." #: lib/logitech_receiver/settings_templates.py:621 msgid "Crown smooth scroll" msgstr "Плавна� прокрутка верньера" #: lib/logitech_receiver/settings_templates.py:622 msgid "Set crown smooth scroll" msgstr "�а�тройка плавной прокрутки верньера" #: lib/logitech_receiver/settings_templates.py:630 msgid "Divert G and M Keys" msgstr "Перенаправление клавиш G и M" #: lib/logitech_receiver/settings_templates.py:631 msgid "Make G and M keys send HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "За�тавить клавиши G и M отправл�ть уведомлени� HID++ (которые " "запу�кают Solaar правила, но в о�тальном игнорируют��)." #: lib/logitech_receiver/settings_templates.py:645 msgid "Scroll Wheel Ratcheted" msgstr "Коле�о прокрутки � храповым механизмом" #: lib/logitech_receiver/settings_templates.py:646 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "Переключение коле�а мыши между вращением � храповым механизмом и " "�вободным вращением." #: lib/logitech_receiver/settings_templates.py:648 msgid "Freespinning" msgstr "Свободное вращение" #: lib/logitech_receiver/settings_templates.py:648 msgid "Ratcheted" msgstr "Вращение � храповым механизмом" #: lib/logitech_receiver/settings_templates.py:655 msgid "Scroll Wheel Ratchet Speed" msgstr "Скоро�ть вращени� коле�а прокрутки" #: lib/logitech_receiver/settings_templates.py:657 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "И�пользуйте �коро�ть вращени� коле�ика мыши дл� переключени� между " "вращением � храповым механизмом и �вободным вращением.\n" "Коле�о мыши в�егда вращает�� � храповым механизмом на 50 граду�ов." #: lib/logitech_receiver/settings_templates.py:707 msgid "Scroll Wheel Ratchet Torque" msgstr "Крут�щий момент храпового механизма прокручивающего коле�а" #: lib/logitech_receiver/settings_templates.py:708 msgid "Change the torque needed to overcome the ratchet." msgstr "Измените крут�щий момент, необходимый дл� преодолени� храпового механизма." #: lib/logitech_receiver/settings_templates.py:743 msgid "Key/Button Actions" msgstr "Дей�тви� � клавишами/кнопками" #: lib/logitech_receiver/settings_templates.py:745 msgid "Change the action for the key or button." msgstr "Изменить дей�твие кнопки или клавиши." #: lib/logitech_receiver/settings_templates.py:747 msgid "Overridden by diversion." msgstr "Отменено перенаправлением." #: lib/logitech_receiver/settings_templates.py:749 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "(изменение важных дей�твий — например, левой кнопки мыши - может " "выве�ти �и�тему из �тро�)." #: lib/logitech_receiver/settings_templates.py:924 msgid "Key/Button Diversion" msgstr "Поведение клавиш/кнопок" #: lib/logitech_receiver/settings_templates.py:925 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "За�тавьте клавишу или кнопку отправл�ть уведомлени� HID++ " "(перенаправленные) или инициировать же�ты мыши или �кольз�щее " "значение DPI" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Diverted" msgstr "Перенаправлено" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 msgid "Mouse Gestures" msgstr "Же�ты мышью" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Regular" msgstr "Обычное" #: lib/logitech_receiver/settings_templates.py:928 msgid "Sliding DPI" msgstr "Скольз�щий тчк/дюйм" #: lib/logitech_receiver/settings_templates.py:1018 #: lib/logitech_receiver/settings_templates.py:1046 msgid "Sensitivity (DPI)" msgstr "Чув�твительно�ть (тчк/дюйм)" #: lib/logitech_receiver/settings_templates.py:1123 msgid "Sensitivity Switching" msgstr "Переключение чув�твительно�ти" #: lib/logitech_receiver/settings_templates.py:1125 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "Переключение текущей чув�твительно�ти и �охранённой чув�твительно�ти " "при нажатии клавиши или кнопки.\n" "Е�ли �охранённой чув�твительно�ти нет, �охран�ет�� текуща� " "чув�твительно�ть" #: lib/logitech_receiver/settings_templates.py:1129 msgid "Off" msgstr "Откл" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Disable keys" msgstr "Отключить клавиши" #: lib/logitech_receiver/settings_templates.py:1161 msgid "Disable specific keyboard keys." msgstr "Отключение определённых клавиш клавиатуры." #: lib/logitech_receiver/settings_templates.py:1164 #, python-format msgid "Disables the %s key." msgstr "Отключение клавиши %s." #: lib/logitech_receiver/settings_templates.py:1177 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Set OS" msgstr "Операционна� �и�тема" #: lib/logitech_receiver/settings_templates.py:1178 #: lib/logitech_receiver/settings_templates.py:1235 msgid "Change keys to match OS." msgstr "Измен�ет назначение клавиш �оответ�твенно ОС." #: lib/logitech_receiver/settings_templates.py:1247 msgid "Change Host" msgstr "Подключено к" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Switch connection to a different host" msgstr "Переключает �оединение на выбранный хо�т." #: lib/logitech_receiver/settings_templates.py:1272 msgid "Performs a left click." msgstr "О�уще�твл�ет щелчок левой кнопкой." #: lib/logitech_receiver/settings_templates.py:1272 msgid "Single tap" msgstr "Одиночное ка�ание" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Performs a right click." msgstr "О�уще�твл�ет щелчок правой кнопкой." #: lib/logitech_receiver/settings_templates.py:1273 msgid "Single tap with two fingers" msgstr "Одиночное ка�ание двум� пальцами" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Single tap with three fingers" msgstr "Одиночное ка�ание трем� пальцами" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Double tap" msgstr "Двойное ка�ание" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Performs a double click." msgstr "О�уще�твление двойного щелчка." #: lib/logitech_receiver/settings_templates.py:1279 msgid "Double tap with two fingers" msgstr "Двойное ка�ание двум� пальцами" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Double tap with three fingers" msgstr "Двойное ка�ание трем� пальцами" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Drags items by dragging the finger after double tapping." msgstr "Перета�кивать объекты перемещением пальца по�ле двойного ка�ани�." #: lib/logitech_receiver/settings_templates.py:1283 msgid "Tap and drag" msgstr "Ка�ание и перета�кивание" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Tap and drag with two fingers" msgstr "Ка�ание и перета�кивание двум� пальцами" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Drags items by dragging the fingers after double tapping." msgstr "Перета�кивать объекты перемещением пальцев по�ле двойного ка�ани�." #: lib/logitech_receiver/settings_templates.py:1288 msgid "Tap and drag with three fingers" msgstr "Ка�ание и перета�кивание трем� пальцами" #: lib/logitech_receiver/settings_templates.py:1291 msgid "Suppress tap and edge gestures" msgstr "Подавление ка�аний и же�тов по кра�м" #: lib/logitech_receiver/settings_templates.py:1292 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Отключает ка�ани� и же�ты по кра�м (то же что FN+ЩелчокЛевойКнопкой)." #: lib/logitech_receiver/settings_templates.py:1294 msgid "Scroll with one finger" msgstr "Вертикальна� прокрутка одним пальцем" #: lib/logitech_receiver/settings_templates.py:1294 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scrolls." msgstr "Прокручивать вертикально." #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scroll with two fingers" msgstr "Вертикальна� прокрутка двум� пальцами" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scroll horizontally with two fingers" msgstr "Горизонтальна� прокрутка двум� пальцами" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scrolls horizontally." msgstr "Прокручивать горизонтально." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scroll vertically with two fingers" msgstr "Вертикальна� прокрутка двум� пальцами" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scrolls vertically." msgstr "Прокручивать вертикально." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Inverts the scrolling direction." msgstr "Инвертирует направлени� прокрутки." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Natural scrolling" msgstr "Е�те�твенна� прокрутка" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Enables the thumbwheel." msgstr "Включение бокового коле�а прокрутки." #: lib/logitech_receiver/settings_templates.py:1300 msgid "Thumbwheel" msgstr "Боковое коле�о прокрутки" #: lib/logitech_receiver/settings_templates.py:1311 #: lib/logitech_receiver/settings_templates.py:1315 msgid "Swipe from the top edge" msgstr "Ли�тание от верхнего кра�" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Swipe from the left edge" msgstr "Ли�тание от левого кра�" #: lib/logitech_receiver/settings_templates.py:1313 msgid "Swipe from the right edge" msgstr "Ли�тание от правого кра�" #: lib/logitech_receiver/settings_templates.py:1314 msgid "Swipe from the bottom edge" msgstr "Ли�тание от нижнего кра�" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Swipe two fingers from the left edge" msgstr "Ли�тание двум� пальцами от левого кра�" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Swipe two fingers from the right edge" msgstr "Ли�тание двум� пальцами от правого кра�" #: lib/logitech_receiver/settings_templates.py:1318 msgid "Swipe two fingers from the bottom edge" msgstr "Ли�тание двум� пальцами от нижнего кра�" #: lib/logitech_receiver/settings_templates.py:1319 msgid "Swipe two fingers from the top edge" msgstr "Ли�тание двум� пальцами от верхнего кра�" #: lib/logitech_receiver/settings_templates.py:1320 #: lib/logitech_receiver/settings_templates.py:1324 msgid "Pinch to zoom out; spread to zoom in." msgstr "Щипок - уменьшить, раздвинуть - увеличить." #: lib/logitech_receiver/settings_templates.py:1320 msgid "Zoom with two fingers." msgstr "Ма�штабирование двум� пальцами." #: lib/logitech_receiver/settings_templates.py:1321 msgid "Pinch to zoom out." msgstr "Щипок - уменьшить." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Spread to zoom in." msgstr "Раздвинуть - увеличить." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Zoom with three fingers." msgstr "Ма�штабирование трем� пальцами." #: lib/logitech_receiver/settings_templates.py:1324 msgid "Zoom with two fingers" msgstr "Ма�штабирование двум� пальцами" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Pixel zone" msgstr "Зона пик�елей" #: lib/logitech_receiver/settings_templates.py:1343 msgid "Ratio zone" msgstr "Зона ма�штаба" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scale factor" msgstr "Ко�ффициент ма�штабировани�" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Sets the cursor speed." msgstr "У�тановка �коро�ти кур�ора." #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left" msgstr "Лево" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left-most coordinate." msgstr "Сама� лева� позици�." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom" msgstr "�из" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom coordinate." msgstr "�ижн�� позици�." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width" msgstr "Ширина" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width." msgstr "Ширина." #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height" msgstr "Вы�ота" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height." msgstr "Вы�ота." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Cursor speed." msgstr "Скоро�ть кур�ора." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Scale" msgstr "Ма�штаб" #: lib/logitech_receiver/settings_templates.py:1358 msgid "Gestures" msgstr "Же�ты" #: lib/logitech_receiver/settings_templates.py:1359 msgid "Tweak the mouse/touchpad behaviour." msgstr "Регулировка поведени� мыши/�ен�орной панели." #: lib/logitech_receiver/settings_templates.py:1375 msgid "Gestures Diversion" msgstr "Поведение же�тов" #: lib/logitech_receiver/settings_templates.py:1376 msgid "Divert mouse/touchpad gestures." msgstr "Регулировка поведени� же�тов мыши/�ен�орной панели." #: lib/logitech_receiver/settings_templates.py:1392 msgid "Gesture params" msgstr "Параметры же�тов" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Изменение чи�ловых параметров мыши/�ен�орной панели." #: lib/logitech_receiver/settings_templates.py:1417 msgid "M-Key LEDs" msgstr "Светодиоды клавиш M" #: lib/logitech_receiver/settings_templates.py:1419 msgid "Control the M-Key LEDs." msgstr "Управление �ветодиодами клавиш M." #: lib/logitech_receiver/settings_templates.py:1423 #: lib/logitech_receiver/settings_templates.py:1454 msgid "May need G Keys diverted to be effective." msgstr "Возможно, дл� �ффективно�ти потребует�� перенаправить G-клавиши." #: lib/logitech_receiver/settings_templates.py:1429 #, python-format msgid "Lights up the %s key." msgstr "Под�ветка клавиши %s." #: lib/logitech_receiver/settings_templates.py:1448 msgid "MR-Key LED" msgstr "Светодиод клавиши MR" #: lib/logitech_receiver/settings_templates.py:1450 msgid "Control the MR-Key LED." msgstr "Управление �ветодиодом клавиши MR." #: lib/logitech_receiver/settings_templates.py:1471 msgid "Persistent Key/Button Mapping" msgstr "По�то�нное �опо�тавление клавиши или кнопки" #: lib/logitech_receiver/settings_templates.py:1473 msgid "Permanently change the mapping for the key or button." msgstr "�ав�егда изменить �опо�тавление дл� клавиши или кнопки." #: lib/logitech_receiver/settings_templates.py:1475 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "Изменение важных клавиш или кнопок (например, левой мыши кнопку) " "может приве�ти к выводу �и�темы из �тро�." #: lib/logitech_receiver/settings_templates.py:1532 msgid "Sidetone" msgstr "Самопро�лушивание" #: lib/logitech_receiver/settings_templates.py:1533 msgid "Set sidetone level." msgstr "У�тановите уровень �амопро�лушивани�." #: lib/logitech_receiver/settings_templates.py:1542 msgid "Equalizer" msgstr "Эквалайзер" #: lib/logitech_receiver/settings_templates.py:1543 msgid "Set equalizer levels." msgstr "У�тановите уровни �квалайзера." #: lib/logitech_receiver/settings_templates.py:1565 msgid "Hz" msgstr "Гц" #: lib/logitech_receiver/settings_templates.py:1571 msgid "Power Management" msgstr "Управление питанием" #: lib/logitech_receiver/settings_templates.py:1572 msgid "Power off in minutes (0 for never)." msgstr "Выключите питание через не�колько минут (0 означает \"никогда\")." #: lib/logitech_receiver/settings_templates.py:1584 msgid "Brightness Control" msgstr "Регулировка �рко�ти" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Control overall brightness" msgstr "Контролируйте общую �рко�ть" #: lib/logitech_receiver/settings_templates.py:1628 #: lib/logitech_receiver/settings_templates.py:1681 msgid "LED Control" msgstr "Светодиодное управление" #: lib/logitech_receiver/settings_templates.py:1629 #: lib/logitech_receiver/settings_templates.py:1682 msgid "Switch control of LED zones between device and Solaar" msgstr "Переключайте управление �ветодиодными зонами между у�трой�твом и " "Solaar" #: lib/logitech_receiver/settings_templates.py:1644 #: lib/logitech_receiver/settings_templates.py:1692 msgid "LED Zone Effects" msgstr "Эффекты �ветодиодной зоны" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "LED Control needs to be set to Solaar to be effective." msgstr "Дл� �ффективного управлени� �ветодиодом необходимо у�тановить режим " "Solaar." #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "Set effect for LED Zone" msgstr "У�тановите �ффект дл� �ветодиодной зоны" #: lib/logitech_receiver/settings_templates.py:1647 msgid "Color" msgstr "Цвет" #: lib/logitech_receiver/settings_templates.py:1648 msgid "Speed" msgstr "Скоро�ть" #: lib/logitech_receiver/settings_templates.py:1649 msgid "Period" msgstr "Период" #: lib/logitech_receiver/settings_templates.py:1650 msgid "Intensity" msgstr "Интен�ивно�ть" #: lib/logitech_receiver/settings_templates.py:1651 msgid "Ramp" msgstr "Рампа" #: lib/logitech_receiver/settings_templates.py:1666 msgid "LEDs" msgstr "Светодиоды" #: lib/logitech_receiver/settings_templates.py:1703 msgid "Per-key Lighting" msgstr "Индивидуальное о�вещение" #: lib/logitech_receiver/settings_templates.py:1704 msgid "Control per-key lighting." msgstr "Управление под�веткой каждой клавиши." #: lib/logitech_receiver/settings_templates.py:1786 msgid "Force Sensing Buttons" msgstr "Кнопки � датчиками �илы нажати�" #: lib/logitech_receiver/settings_templates.py:1787 msgid "Change the force required to activate button." msgstr "Измените у�илие, необходимое дл� активации кнопки." #: lib/logitech_receiver/settings_templates.py:1804 msgid "Force Sensing Button" msgstr "Кнопка измерени� у�или�" #: lib/logitech_receiver/settings_templates.py:1814 msgid "Haptic Feeback Level" msgstr "Уровень тактильной обратной �в�зи" #: lib/logitech_receiver/settings_templates.py:1815 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "Измените мощно�ть тактильной обратной �в�зи. (�оль - отключение.)" #: lib/logitech_receiver/settings_templates.py:1857 msgid "Play Haptic Waveform" msgstr "Во�произведение тактильной формы �игнала" #: lib/logitech_receiver/settings_templates.py:1858 msgid "Tell device to play a haptic waveform." msgstr "Дайте команду у�трой�тву во�произве�ти тактильный �игнал." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "Другой Solaar проце�� уже запущен, так что про�то откройте его окно" #: lib/solaar/ui/about/model.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "Управление приёмниками, клавиатурами,\n" "мышами и другими у�трой�твами Logitech." #: lib/solaar/ui/about/model.py:63 msgid "Additional Programming" msgstr "Дополнительные параметры" #: lib/solaar/ui/about/model.py:64 msgid "GUI design" msgstr "Дизайн интерфей�а" #: lib/solaar/ui/about/model.py:66 msgid "Testing" msgstr "Те�тирование" #: lib/solaar/ui/about/model.py:74 msgid "Logitech documentation" msgstr "Документаци� Logitech" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Отмена �опр�жени�" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "Отмена" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Ошибка до�тупа" #: lib/solaar/ui/common.py:44 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "�айден приёмник Logitech (%s), но нет прав до�туп открыть его." #: lib/solaar/ui/common.py:46 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "Е�ли вы только что у�тановили Solaar, попробуйте отключить и �нова " "подключить приёмник или у�трой�тво." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "�евозможно подключить�� к у�трой�тву" #: lib/solaar/ui/common.py:51 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "�айден приёмник или у�трой�тво Logitech на %s, но не удало�ь к нему " "подключить��." #: lib/solaar/ui/common.py:53 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "Попробуйте отключить и �нова подключить у�трой�тво или выключить и " "затем �нова включить его." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "Отмена �опр�жени� не удала�ь" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Отмена �опр�жени� %{device} � %{receiver} не удала�ь." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Приёмник вернул ошибку без дополнительных �ведений." #: lib/solaar/ui/config_panel.py:245 msgid "Complete - ENTER to change" msgstr "Завершено - «ВВОД» дл� изменени�" #: lib/solaar/ui/config_panel.py:245 msgid "Incomplete" msgstr "�езавершено" #: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d значение" msgstr[1] "%d значени�" msgstr[2] "%d значений" #: lib/solaar/ui/config_panel.py:642 msgid "Changes allowed" msgstr "Изменени� разрешены" #: lib/solaar/ui/config_panel.py:643 msgid "No changes allowed" msgstr "Изменени� запрещены" #: lib/solaar/ui/config_panel.py:644 msgid "Ignore this setting" msgstr "Игнорировать данный параметр" #: lib/solaar/ui/config_panel.py:690 msgid "Working" msgstr "Работает" #: lib/solaar/ui/config_panel.py:693 msgid "Read/write operation failed." msgstr "Операци� чтени�/запи�и не удала�ь." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "неу�тановленна� причина" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "В�троенные правила" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "Пользователь�кие правила" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "Правило" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "Подправило" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "[пу�то]" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "Сохранить изменени� нав�егда?" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "Да" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "�ет" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Е�ли выбрать «�ет», при закрытии программы изменени� пропадут." #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "Скопировать �юда" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "Скопировать выше" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "Скопировать ниже" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "Скопировать правило �юда" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "Скопировать правило выше" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "Скопировать правило ниже" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "Скопировать правило" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "В�тавить �юда" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "В�тавить выше" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "В�тавить ниже" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "В�тавить новое правило �юда" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "В�тавить новое правило выше" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "В�тавить новое правило ниже" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "Сн�ть обёртку" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "В�тавка" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "Или" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "И" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "Компонент" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Feature" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Отчёт" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Проце��" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "Дей�твие мыши" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Модификаторы" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Клавиша" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "Клавиша нажата" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "�ктивный" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "У�трой�тво" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "Хо�т" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "У�тановка" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "У�ловие" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Те�товые байты" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Же�т мышью" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "Дей�твие" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "�ажатие клавиши" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Прокрутка мышью" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Щелчок мышью" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "У�тановить" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "И�полнить" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "Задержка" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "Добавить правило" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Удалить" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "Инвертировать" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "Завернуть в" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "Вырезать" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "В�тавить" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "Копировать" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "Редактор правил" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "Сохранить изменени�" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "Отменить изменени�" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "Редактор пока не поддерживает выбранную компоненту правила." #: lib/solaar/ui/diversion_rules.py:1169 msgid "Number of seconds to delay. Delay between 0 and 1 is done with " "higher precision." msgstr "Количе�тво �екунд задержки. Задержка между 0 и 1 выполн�ет�� � " "помощью более вы�ока� точно�ть." #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "�е" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "Переключение" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "И�тина" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "Ложь" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "�еподдерживаемый параметр" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "И�ходное у�трой�тво" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "У�трой�тво активно, и его на�тройки могут быть изменены." #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "У�трой�тво, отправившее текущее уведомление." #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "Им� главного компьютера." #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "Значение" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "Элемент" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "Изменить на�тройку на у�трой�тве" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "�а�тройка на у�трой�тве" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: новое �опр�жённое у�трой�тво" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Приемники Bolt �овме�тимы только � у�трой�твами Bolt." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "�ажимайте кнопку или клавишу �опр�жени�, пока индикатор �опр�жени� " "не начнёт бы�тро мигать." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Приемники Unifying �овме�тимы только � у�трой�твами Unifying." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "Другие ре�иверы �овме�тимы только � некоторыми у�трой�твами." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "Обычно до�таточно включить у�трой�тво, � которым вы хотите " "у�тановить �оединение." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "Е�ли у�трой�тво включено, выключите его и включите �нова." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "У�трой�тво не должно быть �опр�жено � наход�щим�� поблизо�ти " "включенным приемником." #: lib/solaar/ui/pair_window.py:61 msgid "For devices with multiple channels, press, hold, and release the " "button for the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, " "hold, and release the channel switch button." msgstr "Дл� у�трой�тв � не�колькими каналами нажмите, удерживайте и " "отпу�тите кнопку �оответ�твующего канала, который требует�� " "подключить, или и�пользуйте кнопку переключени� каналов, чтобы " "выбрать нужный канал, затем нажмите, удерживайте и отпу�тите кнопку " "переключени� каналов." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Индикатор канала должен бы�тро мигать." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "Данному приёмнику до�тупно %d �опр�жение." msgstr[1] "\n" "Данному приёмнику до�тупно %d �опр�жени�." msgstr[2] "\n" "Данному приёмнику до�тупно %d �опр�жений." #: lib/solaar/ui/pair_window.py:78 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Прерывание в данный момент отменит �опр�жение." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Введите код до�тупа на %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Введите %(passcode)s и затем нажмите клавишу «Ввод»." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "�лева" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "�права" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "�ажмите %(code)s\n" "и затем нажмите одновременно левую и правую кнопки." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "Бе�проводное �оединение не зашифровано" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "�айдено новое у�трой�тво:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Сопр�жение не удало�ь" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Удо�товерьте�ь, что ваше у�трой�тво в радиу�е приёма и батаре� " "зар�жена." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Обнаружено новое у�трой�тво, не�овме�тимое � данным приёмником." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "Превышено чи�ло �опр�гаемых у�трой�тв, поддерживаемое приёмником." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Дополнительные �ведени� об �той ошибке от�ут�твуют." #: lib/solaar/ui/rule_actions.py:54 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "Имитируйте щелчок аккордовой клавиши, нажмите или отпу�тите.\n" "В Wayland требует�� до�туп на запи�ь в /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Добавить клавишу" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Щелчок" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Подавить" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Выпу�кать" #: lib/solaar/ui/rule_actions.py:153 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "Имитаци� прокрутки мыши.\n" "В Wayland требует�� до�туп на запи�ь в /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "Имитаци� щелчка мыши.В Wayland требует�� до�туп на запи�ь в /dev/" "uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Кнопка" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Дей�твие (и количе�тво, е�ли кликнуть)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Выполните команду � аргументами." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Добавить аргумент" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "�ктивный проце�� X11. Только дл� и�пользовани� в X11." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "Проце�� работы � мышью X11. Только дл� и�пользовани� в X11." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "Дей�твие мыши" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "�азвание функции обработки правила запу�ка уведомлени�." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "Сообщите номер уведомлени�, запу�кающего обработку правила." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "�ктивные модификаторы клавиатуры. �е в�егда до�тупны в Wayland." #: lib/solaar/ui/rule_conditions.py:241 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "Перенаправленна� клавиша или кнопка нажата или отпущена.\n" "Дл� переадре�ации и�пользуйте на�тройки «Переадре�аци� клавиш/" "кнопок» и «Переадре�аци� G-клавиш» ключи и кнопки." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "�ажать клавишу" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Отпу�тить клавишу" #: lib/solaar/ui/rule_conditions.py:293 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "Переадре�ованна� клавиша или кнопка в данный момент нажата.\n" "И�пользуйте на�тройки Переадре�ации клавиш/кнопок и Переадре�ации " "клавиш G дл� переадре�ации клавиш и кнопок." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "Те�товое у�ловие дл� обработки правила запу�ка уведомлени�." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Параметр" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "начало (включительно)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "конец (и�ключительно)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "диапазон" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "минимум" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "мак�имум" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "байты � %(0)d по %(1)d, в диапазоне от %(2)d до %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "ма�ка" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "байты � %(0)d по %(1)d, ма�ка %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "Проверка битов или диапазона на байтах в уведомительном �ообщении, " "запу�кающем обработку правила." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "тип" #: lib/solaar/ui/rule_conditions.py:535 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "Же�т мыши � дополнительной кнопкой запу�ка, за которым �ледует ноль " "или более движений мыши." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Добавить движение" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Поддерживаемое у�трой�тво не найдено" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "О программе %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Выйти из %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "от�ут�твует приёмник" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:728 msgid "offline" msgstr "нет �оединени�" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "от�ут�твует �тату�" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Сканирование" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Батаре�" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Бе�проводное �оединение" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "О�вещённо�ть" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Техниче�кие �ведени� об у�трой�тве" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "�овое �опр�женное у�трой�тво" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Выбор у�трой�тва" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Редактор правил" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Ра�положение" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "Идент. USB" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546 msgid "Serial" msgstr "Серийный №" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "Индек�" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "Б/проводн.PID" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "ID издели�" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "Протокол" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "�еизве�тен" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "Ча�т. опро�а" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "ID у�трой�тва" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "никто" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "Уведомлени�" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "�ет �опр�жённых у�трой�тв." #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "С �тим приёмником может быть �опр�жено до %(max_count)s " "у�трой�тва." msgstr[1] "С �тим приёмником может быть �опр�жено до %(max_count)s " "у�трой�тв." msgstr[2] "С �тим приёмником может быть �опр�жено до %(max_count)s " "у�трой�тв." #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "К �тому приемнику может быть подключено только одно у�трой�тво." #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Данному приёмнику до�тупно ещё %d �опр�жение." msgstr[1] "Данному приёмнику до�тупно ещё %d �опр�жени�." msgstr[2] "Данному приёмнику до�тупно ещё %d �опр�жений." #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "�апр�жение батареи" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "�апр�жение батареи" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "Уровень зар�да" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "Приблизительный уровень зар�да, cообщаемый батареей" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "�ледующий доклад на " #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr " \n" "(�ледующий уровень дл� отчёта)." #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "по�ледний изве�тный" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "зашифровано" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Бе�проводное �оединение между �тим у�трой�твом и его приёмником " "зашифровано." #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "не зашифровано" #: lib/solaar/ui/window.py:721 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "Бе�проводное �оединение между �тим у�трой�твом и его приёмником не " "зашифровано.\n" "Это проблема безопа�но�ти дл� указывающих у�трой�тв и �ерьезна� " "проблема безопа�но�ти дл� у�трой�тв ввода тек�та." #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d люк�" Solaar-1.1.20/po/sk.po000066400000000000000000001637071522022367600144320ustar00rootroot00000000000000# Slovak translations for solaar package. # Copyright (C) 2021 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2021. # # SPDX-FileCopyrightText: 2026 Miroslav Ďurian msgid "" msgstr "" "Project-Id-Version: solaar 1.0.6\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2026-01-15 13:17+0100\n" "Last-Translator: Miroslav Ďurian \n" "Language-Team: Slovak \n" "Language: sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Lokalize 25.12.0\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "Prijíma� Bolt" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "Prijíma� Unifying" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "Prijíma� Nano" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "Prijíma� Lightspeed" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "Prijíma� EX100 27 Mhz" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "prázdna" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "kritická" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "nízka" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "priemerná" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "dobrá" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "plná" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "vybíja sa" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "nabíja sa" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "nabíja sa" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "nenabíja sa" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "takmer nabitá" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "nabitá" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "pomalé nabíjanie" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "chybná batéria" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "teplotná chyba" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "chyba" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "štandardné" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "rýchle" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "pomalé" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "vypršal �asový limit zariadenia" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "nepodporované zariadenie" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "príliš veľa zariadení" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "vypršal �asový limit sekvencie" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmvér" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardvér" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Ďalší" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "Ľavé tla�idlo" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "Pravé tla�idlo" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "Stredné tla�idlo" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "Tla�idlo Späť" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "Tla�idlo Dopredu" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "Tla�idlo gesta myši" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "Inteligentné Prepínanie" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "Prepína� DPI" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "Náklon Vľavo" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "Náklon Vpravo" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "Ľavý klik" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "Pravý klik" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "Stredné tla�idlo myši" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "Tla�idlo Späť na myši" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "Tla�idlo Dopredu na myši" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "Tla�idlo navigácie gestami" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "Ľavé tla�idlo rolovania na myši" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "Pravé tla�idlo rolovania na myši" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "stla�nené" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "uvoľnené" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "zámok párovania bol uzatvorený" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "zámok párovania bol otvorený" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "zámok objavovania je uzatvorený" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "zámok objavovania je otvorený" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "pripojené" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "odpojené" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "nespárované" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "zapnuté" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "prihlásiť" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "vlastnosť" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Prepnúť funkciu Fx" #: lib/logitech_receiver/settings_templates.py:140 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Ak je nastavené, budú klávesy F1..F12 zapínať ich špeciálne " "funkcie.\n" "Pre aktiváciu ich štandardnej funkcie budete musieť sú�asne stla�iť " "Fn." #: lib/logitech_receiver/settings_templates.py:142 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Ak nie je nastavené, budú klávesy F1..F12 zapínať ich štandardné " "funkcie.\n" "Pre aktiváciu špeciálnych funkcií budete musieť sú�asne stla�iť Fn." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Detekcia rúk" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Zapne podsvietenie, ke� sa nad klávesnicou objavia ruky." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "Plynulé skrolovanie" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Vysokocitlivý režim zvislého posunu kolieska myši." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "Bo�né skrolovanie" #: lib/logitech_receiver/settings_templates.py:167 msgid "" "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "" "Ak je vypnuté, bo�né stla�enie kolieska vygeneruje vlastné udalosti " "tla�idiel\n" "namiesto štandardných udalostí skrolovania do strán." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "Citlivosť (DPI - staršie myši)" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "Citlivosť kurzora myši" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Podsvietenie" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "Nastaviť �as podsvietenia klávesnice" #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "Vypne/zapne podsvietenie klávesnice." #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "Vysoké rozlíšenie skrolovania myši" #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" "Nastavte na ignorovanie ak je rolovanie neprimerane rýchle alebo pomalé" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "Odklonenie rolovacieho kolieska" #: lib/logitech_receiver/settings_templates.py:249 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" "Nech rolovacie koliesko posiela LOWRES_WHEEL HID++ notifikácie (ktoré spúšťajú" " pravidlá v Solaare ale inak sú ignorované)." #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "Smer skrolovania" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "Zmeniť zmer zvislého skrolovania myši." #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "Rozlíšenie skrolovania myši" #: lib/logitech_receiver/settings_templates.py:279 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" "Nech rolovacie koliesko posiela HIRES_WHEEL HID++ notifikácie (ktoré spúšťajú " "pravidlá v Solaare ale inak sú ignorované)." #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Citlivosť (rýchlosť kurzora)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Násobi� rýchlosti myši (256 je bežný násobi�)." #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "Odchylka palcového kolieska" #: lib/logitech_receiver/settings_templates.py:301 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Nech rolovacie koliesko posiela THUMB_WHEEL HID++ notifikácie (ktoré spúšťajú " "pravidlá v Solaare ale inak sú ignorované)." #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "Smer posuvného kolieska" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "Zmeniť smer otá�ania kolieska." #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:320 msgid "" "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "Intenzita dopytovania (ms)" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "Frekvencia dopytov na zariadenie, v ms" #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "Odklonenie udalostí korunky" #: lib/logitech_receiver/settings_templates.py:366 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Korunka bude zasielať CROWN HID++ notifikácie (tie aktivujú Solaar " "pravidlá, ale inak budú ignorované)." #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "Hladké rolovanie korunky" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "Nastavuje hladké rolovanie korunky" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "Odkloniť G klávesy" #: lib/logitech_receiver/settings_templates.py:385 msgid "" "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "G klávesy budú zasielať GKEY HID++ notifikácie (tie aktivujú Solaar " "pravidlá, ale inak budú ignorované)." #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "Umožniť aj klávesom M a MR posielať HID++ upozornenia" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "Rapkavé rolovacie koliesko" #: lib/logitech_receiver/settings_templates.py:403 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" "Prepína koliesko myši medzi rapkaním v závislosti od rýchlosti a voľnobehom." #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "Voľnobeh" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "Rapkanie" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "Rýchlosť rapkania rolovacieho kolieska" #: lib/logitech_receiver/settings_templates.py:414 msgid "" "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Použiť rýchlosť kolieska myši na prepínanie medzi rapkaním a voľnobehom." #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "Akcie klávesu/tla�idla" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Zmeniť akciu klávesy alebo tla�idla." #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "Obídené nastavením odklonenia" #: lib/logitech_receiver/settings_templates.py:466 msgid "" "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Zmenou dôležitej akcie (napríklad pre ľavé tla�idlo myši) môžete " "systém uviesť do stavu, kedy sa nebude dať používať." #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "Odklonenie klávesu/tla�idla" #: lib/logitech_receiver/settings_templates.py:640 msgid "" "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" "Nech kláves alebo tla�idlo posiela HID++ upozornenia (Odklonené) alebo spustí " "gestá myši alebo posunie DPI" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "Odklonené" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "Gestá myši" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "Normálne" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "Posun DPI" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Citlivosť (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "Prepínanie citlivosti" #: lib/logitech_receiver/settings_templates.py:754 msgid "" "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" "Stla�ením klávesu alebo tla�idla, prepínať sú�asnú citlivosť a zapamätanú citl" "ivosť.\n" "Ak nie je zapamätaná citlivosť, tak si len zapamätá sú�asnú citlivosť." #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "Vyp" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Zakázať klávesy" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Zakázať špecifické klávesy." #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "Zakáže %s kláves." #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Nastaviť OS" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Zmeniť klávesy podľa opera�ného systému." #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Zmeniť hostiteľa" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Prepnúť spojenie na iného hostiteľa" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "Vykoná kliknutie ľavým tla�idlom." #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "Dotyk" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "Vykoná kliknutie pravým tla�idlom." #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "Dotyk dvoma prstami" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "Dotyk tromi prstami" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "Dvojdotyk" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "Vykoná dvojité kliknutie." #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "Dvojdotyk dvoma prstami" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "Dvojdotyk troma prstami" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "Presúvanie položiek ťahaním prstu po dvojdotyku." #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "Ťahaj a pusti" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "Presúvanie položiek ťahaním prstov po dvojdotyku." #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "Dotyk a ťahanie dvomi prstami" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "Dotyk a ťahanie tromi prstami" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "Vypnúť gestá dotyku a hrany (ekvivalent stla�enia Fn + ľavý klik)." #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "Potla�iť gestá dotyku a hrany" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "Skrolovanie jedným prstom" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "Skrolovania." #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "Skrolovanie dvoma prstami" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "Vodorovné skrolovanie dvoma prstami" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "Vodorovné skrolovanie." #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "Zvislé skrolovanie dvoma prstami" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "Zvislé skrolovanie." #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "Zmeniť smer otá�ania." #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "Prirodzené skrolovanie" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "Povoliť koliesko." #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "Koliesko" #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "Ťahanie z hornej hrany" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "Ťahanie z ľavej hrany" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "Ťahanie z pravej hrany" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "Ťahanie zo spodnej hrany" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "Ťahanie dvoma prstami z ľavej hrany" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "Ťahanie dvoma prstami z pravej hrany" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "Ťahanie dvoma prstami zo spodnej hrany" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "Ťahanie dvoma prstami z hornej hrany" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "Zovrieť pre priblíženie; rozovrieť pre oddialenie." #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "Priblíženie dvoma prstami." #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "Zovrieť pre priblíženie." #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "Rozovrieť pre oddialenie." #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "Priblíženie troma prstami." #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "Priblíženie dvoma pstami" #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "Pixlová oblasť" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "Pomerná oblasť" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Faktor mierky" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "Nastavuje rýchlosť kurzora." #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "Vľavo" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "Súradnica najviac vľavo." #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "Spodok" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "Úplne spodná súradnica." #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Šírka" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "Šírka." #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Výška" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "Výška." #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "Rýchlosť kurzora." #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "Mierka" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Gestá" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "Upraviť správanie myši/touchpadu." #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "Odklon gest" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "Odkloniť gestá myši/touchpadu." #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "Parametre gesta" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Zmeňte �íselné parametre myši/touchpadu." #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "LEDky M-Key" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "Ovládanie LED svetla klávesu M-Key" #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "Môže vyžadovať odklon G Klávesov aby to fungovalo." #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "Rozsvieti kláves %s." #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "MR-Key LED" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "Ovláda LEDky klávesu MR-Key." #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "Trvalé mapovanie Klávesov/Tla�idiel" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "Natrvalo zmeniť mapovanie pre kláves alebo tla�idlo." #: lib/logitech_receiver/settings_templates.py:1098 msgid "" "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" "Zmena dôležitých klávesov alebo tla�idiel (ako je Ľavé tla�idlo myši) môže sko" "n�iť nepoužiteľným systémom." #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "Bo�ný odtieň" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "Nastavenie bo�ného odtieňa." #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "Ekvalizér" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "Nastavenie úrovne ekvalizéru." #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "Správa napájania" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "Minúty do vypnutia (0 znamená nikdy)" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Žiadne spárované zariadenia." #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s spárované zariadenie." msgstr[1] "%(count)s spárované zariadenia." msgstr[2] "%(count)s spárovaných zariadení." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Batéria: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Batéria: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Osvetlenie: %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batéria: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batéria: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "Chyba oprávnenia" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" "Našiel sa prijíma� alebo zariadenie Logitech (%s), ale nemal oprávnenie na jeh" "o otvorenie." #: lib/solaar/ui/__init__.py:55 msgid "" "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" "Ak ste práve nainštalovali Solaar, skúste odpojiť prijíma� alebo zariadenie a " "znova ho pripojiť." #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "Chyba po�as pripájania k zariadeniu" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Našiel sa Logitech prijíma� alebo zariadenie na %s, ale pri pokuse o " "pripojenie nastala chyba." #: lib/solaar/ui/__init__.py:61 msgid "" "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" "Skúste odpojiť zariadenie a potom ho opätovne pripojiť alebo ho skúste vypnúť " "a zase zapnúť." #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Rušenie spárovania skon�ilo s chybou" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Zlyhalo zrušenie spárovania zariadenia %{device} k %{receiver}." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "Prijíma� vrátil chybu, ale nie sú dostupné žiadne podrobnosti o nej." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "Iný proces Solaaru uz beží, takže len odkryte jeho okno" #: lib/solaar/ui/about.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Správa prijíma�ov Logitech,\n" "klávesníc, myší a tabletov." #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "Dodato�né programovanie" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "Návrh GUI" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Testovanie" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Dokumentácia Logitechu" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Zrušiť párovanie" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "Zrušiť" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d hodnota" msgstr[1] "%d hodnoty" msgstr[2] "%d hodnôt" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "Zmeny sú povolené" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "Zmeny nie sú povolené" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "Ignorovať toto nastavenie" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Pracujem" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Operácia �ítania/zápisu zlyhala." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "Zabudované pravidlá" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "Používateľom definované pravidlá" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "Pravidlo" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "Podpravidlo" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[prázdne]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Editor pravidiel Solaar" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "Ozna�iť zmeny ako trvalé?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "�no" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "Nie" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "" "Ak vyberiete Nie, zmeny, ktoré ste vykonali sa po ukon�ení " "aplikácie, stratia." #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "Uložiť zmeny" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "Zahodiť zmeny" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "Vložiť sem" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "Vložiť nad" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "Vložiť pod" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "Vložiť nové pravidlo sem" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "Vložiť nové pravidlo nad" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "Vložiť nové pravidlo pod" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "Vložiť sem" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "Vložiť nad" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "Vložiť pod" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "Vložiť pravidlo sem" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "Vložiť pravidlo nad" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "Vložiť pravidlo pod" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "Vložiť pravidlo" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "Sploštiť" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "Vložiť" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "Alebo" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "A" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "Podmienka" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "Vlastnosť" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "Hlásenie" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Proces" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "Proces myši" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "Modifikátory" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "Kláves" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "KlávesJeStla�ený" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Aktívne" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "Zariadenie" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "Hostiteľ" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "Nastavenie" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "Test bajtov" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "Gesto myši" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Akcia" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "Stla�enie klávesu" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "Skrolovanie kolieskom" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "Kliknutie myšou" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "Nastaviť" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "Spustiť program" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "Neskôr" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "Vložiť nové pravidlo" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "Odstrániť" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "Negovať" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "Obaliť �ím" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Vystrihnúť" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Vložiť" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Kopírovať" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "Vybraný komponent nie je editorom ešte podporovaný." #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "Po�et sekúnd oneskorenia." #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "Opak" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "Aktývny proces X11. Len pre použitie v X11." #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "Proces myši X11. Len pre použitie v X11." #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "ProcesMyši" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "Názov funkcie upozornenia, ktorá spúšťa spracovanie pravidla." #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "Po�et upozornení, ktoré spúšťajú spracovanie pravidla." #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Aktívne modifikátory klávesnice. Vo Waylande nie sú vždy dostupné." #: lib/solaar/ui/diversion_rules.py:1383 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" "Odklonený kláves alebo tla�idlo stla�ené alebo uvoľnené.\n" "Použiť Odklonenie Klávesu/Tla�idla a Odkloniť nastavenie G Klávesov pre odklon" "enie klávesov a tla�idiel." #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "Kláves stla�ený" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "Kláves uvoľnený" #: lib/solaar/ui/diversion_rules.py:1436 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" "Odklonený kláves alebo tla�idlo je práve stla�ené.\n" "Použiť Odklon Klávesov/Tla�idiel a Odkloniť nastavenie G Klávesov na odkloneni" "e klávesov a tla�idiel." #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "Parameter" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "rozsah" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "maximum" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "maska" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/diversion_rules.py:1573 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "typ" #: lib/solaar/ui/diversion_rules.py:1666 msgid "" "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "Pridať pohyb" #: lib/solaar/ui/diversion_rules.py:1764 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "Pridať kláves" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "Kliknutie" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "Stla�iť" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "Uvoľniť" #: lib/solaar/ui/diversion_rules.py:1861 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simulovať rolovanie myši.\n" "Vo Waylande vyžaduje právo na zápis do /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1918 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simulovať kliknutie myši.\n" "Vo Waylande vyžaduje právo na zápis do /dev/uinput." #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "Tla�idlo" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "Po�et a Akcia" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "Vykonať príkaz s argumentami." #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "Pridať argument" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "Prepína�" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "Pravda" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "Nepravda" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "Nepodporované nastavenie" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "Zariadenie je aktívne a jeho nastavenia možno meniť." #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "Názov hostiteľského po�íta�a." #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Hodnota" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "Položka" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "Zmeniť nastavenie na zariadení" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "Nastavenie na zariadení" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "offline" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: spárovať nové zariadenie" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "Vložte tajný kód na %(name)s." #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Napíšte %(passcode)s a potom stla�te kláves Enter." #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "vľavo" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "vpravo" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Stla�te %(code)s\n" "a potom stla�te ľavé a pravé tla�idlo sú�asne." #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Párovanie skon�ilo s chybou" #: lib/solaar/ui/pair_window.py:190 msgid "" "Make sure your device is within range, and has a decent battery " "charge." msgstr "Uistite sa, že je zariadenie v dosahu a je dostato�ne nabité." #: lib/solaar/ui/pair_window.py:192 msgid "" "A new device was detected, but it is not compatible with this " "receiver." msgstr "" "Bolo zistené nové zariadenie, ale nie je kompatibilné s týmto " "prijíma�om." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "Viac pripojených zariadení ako dokáže prijíma� zvládnuť." #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Ďalšie podrobnosti o chybe nie sú dostupné." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "Nájdené nové zariadenie:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "Bezdrôtové pripojenie nepoužíva šifrovanie" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Unifying prijíma�e sú kompatibilné len s Unifying zariadeniami." #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt prijíma�e sú kompatibilné len s Bolt zariadeniami." #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "Ostatné prijíma�e sú kompatibilné len s máloktorými zariadeniami." #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "Zariadenie nesmie byť spárované s nedaľekým zapnutým prijíma�om." #: lib/solaar/ui/pair_window.py:274 msgid "" "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" "Stla�te párovacie tla�idlo alebo kláves kým rýchlo nezabliká párovacie svetlo." #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "Možno bude treba najprv zariadenie vypnuť a znova zapnúť." #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "Zapnite zariadenie, ktoré chcete spárovať." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "Ak je zariadenie už zapnuté, vypnite ho a opäť zapnite." #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Tomuto prijíma�u ostáva ešte %d párovanie." msgstr[1] "" "\n" "\n" "Tomuto prijíma�u ostáva ešte %d párovania." msgstr[2] "" "\n" "\n" "Tomuto prijíma�u ostáva ešte %d párovaní." #: lib/solaar/ui/pair_window.py:286 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Ak proces teraz zrušíte, spárovanie sa nespotrebuje." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "Nenašlo sa podporované zariadenie" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "O programe %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Ukon�iť %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "bez prijíma�a" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "žiaden stav" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Hľadá sa" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Batéria" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "Bezdrôtové prepojenie" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Osvetlenie" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Zobraziť technické podrobnosti" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Spárovať nové zariadenie" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Vyberte zariadenie" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "Editor pravidiel" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Cesta" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Sériové �íslo" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "Bezdrôt. PID" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "Identifikátor produktu" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protokol" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Neznámy" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Intenzita dopytovania" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "Číslo (ID) jednotky" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "žiadne" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "Notifikácie" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "Žiadne spárované zariadenie." #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "K tomuto prijíma�u môžete pripojiť %(max_count)s zariadenie." msgstr[1] "" "K tomuto prijíma�u môžete pripojiť až %(max_count)s " "zariadenia." msgstr[2] "" "K tomuto prijíma�u môžete pripojiť až %(max_count)s " "zariadení." #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "K tomuto prijíma�u sa dá pripojiť len jedno zariadenie." #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Tomuto prijíma�u ostáva %d párovanie." msgstr[1] "Tomuto prijíma�u ostávajú %d párovania." msgstr[2] "Tomuto prijíma�u ostáva %d párovaní." #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "Napätie batérie" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "Napätie hlásené batériou" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "Úroveň batérie" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "Približná úroveň hlásená batériou" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "�alšie hlásené " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " a �alšia úroveň, ktorá bude hlásená." #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "naposledy známa" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "šifrované" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Bezdrôtové spojenie medzi zariadením a prijíma�om je šifrované." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "bez šifrovania" #: lib/solaar/ui/window.py:732 msgid "" "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" "Bezdrôtové prepojenie tohto zariadenia s jeho prijíma�om nie je šifrované.\n" "To je bezpe�nostný problém pre ukazovacie zariadenia a závažný bezpe�nostný pr" "oblém pre textové vstupné zariadenia." #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "About" #~ msgstr "O programe" #~ msgid "Add action" #~ msgstr "Pridať akciu" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the DPI button." #~ msgstr "Upraviť DPI pohybom myši vo vodorovnom smere pri sú�asnom " #~ "držaní tla�idla DPI." #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the button down." #~ msgstr "Úprava DPI pohybom myši vo vodorovnom smere pri sú�asnom " #~ "držaní tla�idla." #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "Automaticky prepnúť režim kolieska myši medzi krokovaním a " #~ "voľným otá�aním.\n" #~ "Koliesko je pri hodnote 0 vždy voľné a pri hodnote 50 vždy krokuje" #~ msgid "Battery information unknown." #~ msgstr "Informácie o batérii nie sú známe." #~ msgid "Click to allow changes." #~ msgstr "Kliknite pre povolenie zmien." #~ msgid "Click to prevent changes." #~ msgstr "Kliknite pre zakázanie zmien." #~ msgid "Count" #~ msgstr "Po�et" #~ msgid "DPI Sliding Adjustment" #~ msgstr "Úprava DPI pomocou myši" #~ msgid "ERROR: " #~ msgstr "CHYBA: " #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Vypne skrolovanie palcom v Linuxe." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Vypne skrolovanie kolieskom myši v Linuxe." #~ msgid "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "Ďalšie informácie o inštalácii Solaaru nájdete na\n" #~ "https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "Nájdený prijíma� Logitech (%s), ale chýbajú práva na jeho " #~ "otvorenie." #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID++ režim pre vodorovný posun pomocou kolieska." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++ režim pre vertikálne skrolovanie myši." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Ak je zariadenie už zapnuté, vypnite ho a znovu zapnite." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Ak ste Solaar práve nainštalovali, skúste prijíma� odpojiť a " #~ "znova pripojiť." #~ msgid "Make the key or button send HID++ notifications (which " #~ "trigger Solaar rules but are otherwise ignored)." #~ msgstr "Kláves alebo tla�idlo budú zasielať HID++ notifikácie (tie " #~ "aktivujú Solaar pravidlá, ale inak budú ignorované)." #~ msgid "No Logitech receiver found" #~ msgstr "Nebol nájdený žiaden prijíma� Logitech" #~ msgid "Scroll Wheel HID++ Scrolling" #~ msgstr "HID++ skrolovanie" #~ msgid "Scroll Wheel Rachet" #~ msgstr "Krokovanie kolieska" #~ msgid "Send a gesture by sliding the mouse while holding the button " #~ "down." #~ msgstr "Pošlite gesto pohybom myši pri sú�asnom držaní tla�idla." #~ msgid "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "Zobrazí stav zariadení pripojených\n" #~ "pomocou bezdrôtového prijíma�a Logitech." #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar závisí na udev súbore, ktorý chýba" #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "Bezdrôtové spojenie medzi zariadením a prijíma�om nie je " #~ "šifrované.\n" #~ "\n" #~ "Pri ukazovacích zariadeniach (myši, trackbally, trackpady) to " #~ "nepredstavuje veľký bezpe�nostný problém.\n" #~ "\n" #~ "Avšak pri vstupných zariadeniach zadávajúcich text (klávesnica, " #~ "numerická \n" #~ "klávesnica) to predstavuje veľké riziko z hľadiska bezpe�nosti, " #~ "pretože \n" #~ "písaný text môže byť nepozorovane zachytený treťou stranou, ak je " #~ "signál v jej dosahu." #~ msgid "Thumb Wheel HID++ Scrolling" #~ msgstr "HID++ posun kolieskom" #~ msgid "Top-most coordinate." #~ msgstr "Najvyššia súradnica." #~ msgid "Try removing the device and plugging it back in or turning " #~ "it off and then on." #~ msgstr "Skúste zariadenie odpojiť a znovu ho pripojiť alebo ho " #~ "skúste vypnúť a opätovne zapnúť." #~ msgid "height" #~ msgstr "výška" #~ msgid "top" #~ msgstr "hore" #~ msgid "unknown" #~ msgstr "neznáme" #~ msgid "width" #~ msgstr "šírka" Solaar-1.1.20/po/solaar.pot000066400000000000000000001374111522022367600154530ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "Project-Id-Version: solaar 1.1.19\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2026-03-05 14:00+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "" #: lib/logitech_receiver/base_usb.py:136 msgid "EX100 Receiver 27 Mhz" msgstr "" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "" #: lib/logitech_receiver/hidpp20.py:1048 #: lib/logitech_receiver/settings_templates.py:299 msgid "Disabled" msgstr "" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Static" msgstr "" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Pulse" msgstr "" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Cycle" msgstr "" #: lib/logitech_receiver/hidpp20.py:1052 msgid "Boot" msgstr "" #: lib/logitech_receiver/hidpp20.py:1053 msgid "Demo" msgstr "" #: lib/logitech_receiver/hidpp20.py:1055 msgid "Breathe" msgstr "" #: lib/logitech_receiver/hidpp20.py:1058 msgid "Ripple" msgstr "" #: lib/logitech_receiver/hidpp20.py:1059 msgid "Decomposition" msgstr "" #: lib/logitech_receiver/hidpp20.py:1060 msgid "Signature1" msgstr "" #: lib/logitech_receiver/hidpp20.py:1061 msgid "Signature2" msgstr "" #: lib/logitech_receiver/hidpp20.py:1062 msgid "CycleS" msgstr "" #: lib/logitech_receiver/hidpp20.py:1126 msgid "Unknown Location" msgstr "" #: lib/logitech_receiver/hidpp20.py:1127 msgid "Primary" msgstr "" #: lib/logitech_receiver/hidpp20.py:1128 msgid "Logo" msgstr "" #: lib/logitech_receiver/hidpp20.py:1129 msgid "Left Side" msgstr "" #: lib/logitech_receiver/hidpp20.py:1130 msgid "Right Side" msgstr "" #: lib/logitech_receiver/hidpp20.py:1131 msgid "Combined" msgstr "" #: lib/logitech_receiver/hidpp20.py:1132 msgid "Primary 1" msgstr "" #: lib/logitech_receiver/hidpp20.py:1133 msgid "Primary 2" msgstr "" #: lib/logitech_receiver/hidpp20.py:1134 msgid "Primary 3" msgstr "" #: lib/logitech_receiver/hidpp20.py:1135 msgid "Primary 4" msgstr "" #: lib/logitech_receiver/hidpp20.py:1136 msgid "Primary 5" msgstr "" #: lib/logitech_receiver/hidpp20.py:1137 msgid "Primary 6" msgstr "" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:484 msgid "pairing lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:484 msgid "pairing lock is open" msgstr "" #: lib/logitech_receiver/notifications.py:447 msgid "discovery lock is closed" msgstr "" #: lib/logitech_receiver/notifications.py:447 msgid "discovery lock is open" msgstr "" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "" #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "" msgstr[1] "" #: lib/logitech_receiver/settings.py:602 msgid "register" msgstr "" #: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654 msgid "feature" msgstr "" #: lib/logitech_receiver/settings_templates.py:138 msgid "Swap Fx function" msgstr "" #: lib/logitech_receiver/settings_templates.py:141 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" #: lib/logitech_receiver/settings_templates.py:146 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" #: lib/logitech_receiver/settings_templates.py:154 msgid "Hand Detection" msgstr "" #: lib/logitech_receiver/settings_templates.py:155 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:162 msgid "Scroll Wheel Smooth Scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:163 #: lib/logitech_receiver/settings_templates.py:410 #: lib/logitech_receiver/settings_templates.py:439 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:170 msgid "Side Scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:172 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "" #: lib/logitech_receiver/settings_templates.py:182 msgid "Sensitivity (DPI - older mice)" msgstr "" #: lib/logitech_receiver/settings_templates.py:183 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 msgid "Mouse movement sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:256 msgid "Backlight Timed" msgstr "" #: lib/logitech_receiver/settings_templates.py:257 #: lib/logitech_receiver/settings_templates.py:397 msgid "Set illumination time for keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:268 msgid "Backlight" msgstr "" #: lib/logitech_receiver/settings_templates.py:269 msgid "Illumination level on keyboard. Changes made are only applied in " "Manual mode." msgstr "" #: lib/logitech_receiver/settings_templates.py:301 msgid "Automatic" msgstr "" #: lib/logitech_receiver/settings_templates.py:303 msgid "Manual" msgstr "" #: lib/logitech_receiver/settings_templates.py:305 msgid "Enabled" msgstr "" #: lib/logitech_receiver/settings_templates.py:311 msgid "Backlight Level" msgstr "" #: lib/logitech_receiver/settings_templates.py:312 msgid "Illumination level on keyboard when in Manual mode." msgstr "" #: lib/logitech_receiver/settings_templates.py:369 msgid "Backlight Delay Hands Out" msgstr "" #: lib/logitech_receiver/settings_templates.py:370 msgid "Delay in seconds until backlight fades out with hands away from " "keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:378 msgid "Backlight Delay Hands In" msgstr "" #: lib/logitech_receiver/settings_templates.py:379 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" #: lib/logitech_receiver/settings_templates.py:387 msgid "Backlight Delay Powered" msgstr "" #: lib/logitech_receiver/settings_templates.py:388 msgid "Delay in seconds until backlight fades out with external power." msgstr "" #: lib/logitech_receiver/settings_templates.py:396 msgid "Backlight (Seconds)" msgstr "" #: lib/logitech_receiver/settings_templates.py:408 msgid "Scroll Wheel High Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 #: lib/logitech_receiver/settings_templates.py:441 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "" #: lib/logitech_receiver/settings_templates.py:419 #: lib/logitech_receiver/settings_templates.py:450 msgid "Scroll Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:421 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:428 msgid "Scroll Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:429 msgid "Invert direction for vertical scroll with wheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:437 msgid "Scroll Wheel Resolution" msgstr "" #: lib/logitech_receiver/settings_templates.py:452 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:461 msgid "Sensitivity (Pointer Speed)" msgstr "" #: lib/logitech_receiver/settings_templates.py:462 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "" #: lib/logitech_receiver/settings_templates.py:472 msgid "Thumb Wheel Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:474 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:483 msgid "Thumb Wheel Direction" msgstr "" #: lib/logitech_receiver/settings_templates.py:484 msgid "Invert thumb wheel scroll direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:504 msgid "Onboard Profiles" msgstr "" #: lib/logitech_receiver/settings_templates.py:505 msgid "Enable an onboard profile, which controls report rate, sensitivity, " "and button actions" msgstr "" #: lib/logitech_receiver/settings_templates.py:549 #: lib/logitech_receiver/settings_templates.py:582 msgid "Report Rate" msgstr "" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 msgid "Frequency of device movement reports" msgstr "" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1421 #: lib/logitech_receiver/settings_templates.py:1452 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:612 msgid "Divert crown events" msgstr "" #: lib/logitech_receiver/settings_templates.py:613 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:621 msgid "Crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:622 msgid "Set crown smooth scroll" msgstr "" #: lib/logitech_receiver/settings_templates.py:630 msgid "Divert G and M Keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:631 msgid "Make G and M keys send HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" #: lib/logitech_receiver/settings_templates.py:645 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:646 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:648 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:648 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:655 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:657 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:707 msgid "Scroll Wheel Ratchet Torque" msgstr "" #: lib/logitech_receiver/settings_templates.py:708 msgid "Change the torque needed to overcome the ratchet." msgstr "" #: lib/logitech_receiver/settings_templates.py:743 msgid "Key/Button Actions" msgstr "" #: lib/logitech_receiver/settings_templates.py:745 msgid "Change the action for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:747 msgid "Overridden by diversion." msgstr "" #: lib/logitech_receiver/settings_templates.py:749 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:924 msgid "Key/Button Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:925 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Diverted" msgstr "" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 msgid "Mouse Gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Regular" msgstr "" #: lib/logitech_receiver/settings_templates.py:928 msgid "Sliding DPI" msgstr "" #: lib/logitech_receiver/settings_templates.py:1018 #: lib/logitech_receiver/settings_templates.py:1046 msgid "Sensitivity (DPI)" msgstr "" #: lib/logitech_receiver/settings_templates.py:1123 msgid "Sensitivity Switching" msgstr "" #: lib/logitech_receiver/settings_templates.py:1125 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "" #: lib/logitech_receiver/settings_templates.py:1129 msgid "Off" msgstr "" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Disable keys" msgstr "" #: lib/logitech_receiver/settings_templates.py:1161 msgid "Disable specific keyboard keys." msgstr "" #: lib/logitech_receiver/settings_templates.py:1164 #, python-format msgid "Disables the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1177 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Set OS" msgstr "" #: lib/logitech_receiver/settings_templates.py:1178 #: lib/logitech_receiver/settings_templates.py:1235 msgid "Change keys to match OS." msgstr "" #: lib/logitech_receiver/settings_templates.py:1247 msgid "Change Host" msgstr "" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Switch connection to a different host" msgstr "" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Performs a left click." msgstr "" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Single tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Performs a right click." msgstr "" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Single tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Single tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Double tap" msgstr "" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Performs a double click." msgstr "" #: lib/logitech_receiver/settings_templates.py:1279 msgid "Double tap with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Double tap with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Drags items by dragging the finger after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Tap and drag" msgstr "" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Tap and drag with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Drags items by dragging the fingers after double tapping." msgstr "" #: lib/logitech_receiver/settings_templates.py:1288 msgid "Tap and drag with three fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1291 msgid "Suppress tap and edge gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:1292 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" #: lib/logitech_receiver/settings_templates.py:1294 msgid "Scroll with one finger" msgstr "" #: lib/logitech_receiver/settings_templates.py:1294 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scrolls." msgstr "" #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scroll with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scroll horizontally with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scrolls horizontally." msgstr "" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scroll vertically with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scrolls vertically." msgstr "" #: lib/logitech_receiver/settings_templates.py:1299 msgid "Inverts the scrolling direction." msgstr "" #: lib/logitech_receiver/settings_templates.py:1299 msgid "Natural scrolling" msgstr "" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Enables the thumbwheel." msgstr "" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Thumbwheel" msgstr "" #: lib/logitech_receiver/settings_templates.py:1311 #: lib/logitech_receiver/settings_templates.py:1315 msgid "Swipe from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Swipe from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:1313 msgid "Swipe from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:1314 msgid "Swipe from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Swipe two fingers from the left edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Swipe two fingers from the right edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:1318 msgid "Swipe two fingers from the bottom edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:1319 msgid "Swipe two fingers from the top edge" msgstr "" #: lib/logitech_receiver/settings_templates.py:1320 #: lib/logitech_receiver/settings_templates.py:1324 msgid "Pinch to zoom out; spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:1320 msgid "Zoom with two fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:1321 msgid "Pinch to zoom out." msgstr "" #: lib/logitech_receiver/settings_templates.py:1322 msgid "Spread to zoom in." msgstr "" #: lib/logitech_receiver/settings_templates.py:1323 msgid "Zoom with three fingers." msgstr "" #: lib/logitech_receiver/settings_templates.py:1324 msgid "Zoom with two fingers" msgstr "" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Pixel zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1343 msgid "Ratio zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scale factor" msgstr "" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Sets the cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left" msgstr "" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left-most coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom" msgstr "" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom coordinate." msgstr "" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width" msgstr "" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width." msgstr "" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height" msgstr "" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height." msgstr "" #: lib/logitech_receiver/settings_templates.py:1352 msgid "Cursor speed." msgstr "" #: lib/logitech_receiver/settings_templates.py:1352 msgid "Scale" msgstr "" #: lib/logitech_receiver/settings_templates.py:1358 msgid "Gestures" msgstr "" #: lib/logitech_receiver/settings_templates.py:1359 msgid "Tweak the mouse/touchpad behaviour." msgstr "" #: lib/logitech_receiver/settings_templates.py:1375 msgid "Gestures Diversion" msgstr "" #: lib/logitech_receiver/settings_templates.py:1376 msgid "Divert mouse/touchpad gestures." msgstr "" #: lib/logitech_receiver/settings_templates.py:1392 msgid "Gesture params" msgstr "" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Change numerical parameters of a mouse/touchpad." msgstr "" #: lib/logitech_receiver/settings_templates.py:1417 msgid "M-Key LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1419 msgid "Control the M-Key LEDs." msgstr "" #: lib/logitech_receiver/settings_templates.py:1423 #: lib/logitech_receiver/settings_templates.py:1454 msgid "May need G Keys diverted to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1429 #, python-format msgid "Lights up the %s key." msgstr "" #: lib/logitech_receiver/settings_templates.py:1448 msgid "MR-Key LED" msgstr "" #: lib/logitech_receiver/settings_templates.py:1450 msgid "Control the MR-Key LED." msgstr "" #: lib/logitech_receiver/settings_templates.py:1471 msgid "Persistent Key/Button Mapping" msgstr "" #: lib/logitech_receiver/settings_templates.py:1473 msgid "Permanently change the mapping for the key or button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1475 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "" #: lib/logitech_receiver/settings_templates.py:1532 msgid "Sidetone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1533 msgid "Set sidetone level." msgstr "" #: lib/logitech_receiver/settings_templates.py:1542 msgid "Equalizer" msgstr "" #: lib/logitech_receiver/settings_templates.py:1543 msgid "Set equalizer levels." msgstr "" #: lib/logitech_receiver/settings_templates.py:1565 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1571 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1572 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/settings_templates.py:1584 msgid "Brightness Control" msgstr "" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Control overall brightness" msgstr "" #: lib/logitech_receiver/settings_templates.py:1628 #: lib/logitech_receiver/settings_templates.py:1681 msgid "LED Control" msgstr "" #: lib/logitech_receiver/settings_templates.py:1629 #: lib/logitech_receiver/settings_templates.py:1682 msgid "Switch control of LED zones between device and Solaar" msgstr "" #: lib/logitech_receiver/settings_templates.py:1644 #: lib/logitech_receiver/settings_templates.py:1692 msgid "LED Zone Effects" msgstr "" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "LED Control needs to be set to Solaar to be effective." msgstr "" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "Set effect for LED Zone" msgstr "" #: lib/logitech_receiver/settings_templates.py:1647 msgid "Color" msgstr "" #: lib/logitech_receiver/settings_templates.py:1648 msgid "Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:1649 msgid "Period" msgstr "" #: lib/logitech_receiver/settings_templates.py:1650 msgid "Intensity" msgstr "" #: lib/logitech_receiver/settings_templates.py:1651 msgid "Ramp" msgstr "" #: lib/logitech_receiver/settings_templates.py:1666 msgid "LEDs" msgstr "" #: lib/logitech_receiver/settings_templates.py:1703 msgid "Per-key Lighting" msgstr "" #: lib/logitech_receiver/settings_templates.py:1704 msgid "Control per-key lighting." msgstr "" #: lib/logitech_receiver/settings_templates.py:1786 msgid "Force Sensing Buttons" msgstr "" #: lib/logitech_receiver/settings_templates.py:1787 msgid "Change the force required to activate button." msgstr "" #: lib/logitech_receiver/settings_templates.py:1804 msgid "Force Sensing Button" msgstr "" #: lib/logitech_receiver/settings_templates.py:1814 msgid "Haptic Feedback Level" msgstr "" #: lib/logitech_receiver/settings_templates.py:1815 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "" #: lib/logitech_receiver/settings_templates.py:1857 msgid "Play Haptic Waveform" msgstr "" #: lib/logitech_receiver/settings_templates.py:1858 msgid "Tell device to play a haptic waveform." msgstr "" #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "" #: lib/solaar/ui/about/model.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" #: lib/solaar/ui/about/model.py:64 msgid "Additional Programming" msgstr "" #: lib/solaar/ui/about/model.py:65 msgid "GUI design" msgstr "" #: lib/solaar/ui/about/model.py:67 msgid "Testing" msgstr "" #: lib/solaar/ui/about/model.py:75 msgid "Logitech documentation" msgstr "" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "" #: lib/solaar/ui/common.py:44 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/common.py:46 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "" #: lib/solaar/ui/common.py:51 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" #: lib/solaar/ui/common.py:53 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "" #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "" #: lib/solaar/ui/config_panel.py:245 msgid "Complete - ENTER to change" msgstr "" #: lib/solaar/ui/config_panel.py:245 msgid "Incomplete" msgstr "" #: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/config_panel.py:642 msgid "Changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:643 msgid "No changes allowed" msgstr "" #: lib/solaar/ui/config_panel.py:644 msgid "Ignore this setting" msgstr "" #: lib/solaar/ui/config_panel.py:690 msgid "Working" msgstr "" #: lib/solaar/ui/config_panel.py:693 msgid "Read/write operation failed." msgstr "" #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "" #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "" #: lib/solaar/ui/diversion_rules.py:1169 msgid "Number of seconds to delay. Delay between 0 and 1 is done with " "higher precision." msgstr "" #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "" #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "" #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "" #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:61 msgid "For devices with multiple channels, press, hold, and release the " "button for the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, " "hold, and release the channel switch button." msgstr "" #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "" #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/pair_window.py:78 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "" #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "" #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "" #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "" #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "" #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "" #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "" #: lib/solaar/ui/rule_actions.py:54 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "" #: lib/solaar/ui/rule_actions.py:153 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/rule_actions.py:211 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/rule_conditions.py:241 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "" #: lib/solaar/ui/rule_conditions.py:293 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "" #: lib/solaar/ui/rule_conditions.py:437 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "" #: lib/solaar/ui/rule_conditions.py:535 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:728 msgid "offline" msgstr "" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546 msgid "Serial" msgstr "" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "" #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "" #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "" msgstr[1] "" #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "" #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr "" #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "" #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "" #: lib/solaar/ui/window.py:721 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "" Solaar-1.1.20/po/sr.po000066400000000000000000001547131522022367600144360ustar00rootroot00000000000000# Language rs translations for solaar package. # Copyright (C) 2022 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2022. # msgid "" msgstr "Project-Id-Version: solaar 1.1.4\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-12-28 17:40+0100\n" "PO-Revision-Date: 2022-08-09 17:35+0200\n" "Last-Translator: Automatically generated\n" "Language-Team: github.com/renatoka\n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: lib/logitech_receiver/base_usb.py:46 msgid "Bolt Receiver" msgstr "Bolt prijemnik" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "Unifying prijemnik" #: lib/logitech_receiver/base_usb.py:67 lib/logitech_receiver/base_usb.py:78 #: lib/logitech_receiver/base_usb.py:90 lib/logitech_receiver/base_usb.py:102 #: lib/logitech_receiver/base_usb.py:114 msgid "Nano Receiver" msgstr "Nano prijemnik" #: lib/logitech_receiver/base_usb.py:124 msgid "Lightspeed Receiver" msgstr "Lightspeed prijemnik" #: lib/logitech_receiver/base_usb.py:133 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 prijemnik 27 MHZ" #: lib/logitech_receiver/i18n.py:30 msgid "empty" msgstr "prazna" #: lib/logitech_receiver/i18n.py:31 msgid "critical" msgstr "kritiÄ�no" #: lib/logitech_receiver/i18n.py:32 msgid "low" msgstr "slabo" #: lib/logitech_receiver/i18n.py:33 msgid "average" msgstr "proseÄ�na" #: lib/logitech_receiver/i18n.py:34 msgid "good" msgstr "dobra" #: lib/logitech_receiver/i18n.py:35 msgid "full" msgstr "puna" #: lib/logitech_receiver/i18n.py:38 msgid "discharging" msgstr "pražnjenje" #: lib/logitech_receiver/i18n.py:39 msgid "recharging" msgstr "punjenje" #: lib/logitech_receiver/i18n.py:40 lib/solaar/ui/window.py:711 msgid "charging" msgstr "punjenje" #: lib/logitech_receiver/i18n.py:41 msgid "not charging" msgstr "ne puni se" #: lib/logitech_receiver/i18n.py:42 msgid "almost full" msgstr "skoro puna" #: lib/logitech_receiver/i18n.py:43 msgid "charged" msgstr "napunjeno" #: lib/logitech_receiver/i18n.py:44 msgid "slow recharge" msgstr "sporo punjenje" #: lib/logitech_receiver/i18n.py:45 msgid "invalid battery" msgstr "neispravna baterija" #: lib/logitech_receiver/i18n.py:46 msgid "thermal error" msgstr "toplotna greÅ¡ka" #: lib/logitech_receiver/i18n.py:47 msgid "error" msgstr "greÅ¡ka" #: lib/logitech_receiver/i18n.py:48 msgid "standard" msgstr "standardno" #: lib/logitech_receiver/i18n.py:49 msgid "fast" msgstr "brzo" #: lib/logitech_receiver/i18n.py:50 msgid "slow" msgstr "sporo" #: lib/logitech_receiver/i18n.py:53 msgid "device timeout" msgstr "istek Ä�ekanja ureÄ‘aja" #: lib/logitech_receiver/i18n.py:54 msgid "device not supported" msgstr "ureÄ‘aj nije podržan" #: lib/logitech_receiver/i18n.py:55 msgid "too many devices" msgstr "previÅ¡e ureÄ‘aja" #: lib/logitech_receiver/i18n.py:56 msgid "sequence timeout" msgstr "istek vremenske sekvence" #: lib/logitech_receiver/i18n.py:59 lib/solaar/ui/window.py:572 msgid "Firmware" msgstr "Firmver" #: lib/logitech_receiver/i18n.py:60 msgid "Bootloader" msgstr "Bootloader" #: lib/logitech_receiver/i18n.py:61 msgid "Hardware" msgstr "Hardver" #: lib/logitech_receiver/i18n.py:62 msgid "Other" msgstr "Ostalo" #: lib/logitech_receiver/i18n.py:65 msgid "Left Button" msgstr "Levo dugme" #: lib/logitech_receiver/i18n.py:66 msgid "Right Button" msgstr "Desno dugme" #: lib/logitech_receiver/i18n.py:67 msgid "Middle Button" msgstr "Srednje dugme" #: lib/logitech_receiver/i18n.py:68 msgid "Back Button" msgstr "Dugme za unazad" #: lib/logitech_receiver/i18n.py:69 msgid "Forward Button" msgstr "Dugme za unapred" #: lib/logitech_receiver/i18n.py:70 msgid "Mouse Gesture Button" msgstr "Dugme za pokrete miÅ¡a" #: lib/logitech_receiver/i18n.py:71 msgid "Smart Shift" msgstr "Pametan pomak" #: lib/logitech_receiver/i18n.py:72 msgid "DPI Switch" msgstr "DPI svitch" #: lib/logitech_receiver/i18n.py:73 msgid "Left Tilt" msgstr "Levi nagib" #: lib/logitech_receiver/i18n.py:74 msgid "Right Tilt" msgstr "Desni nagib" #: lib/logitech_receiver/i18n.py:75 msgid "Left Click" msgstr "Levi lik" #: lib/logitech_receiver/i18n.py:76 msgid "Right Click" msgstr "Desni klik" #: lib/logitech_receiver/i18n.py:77 msgid "Mouse Middle Button" msgstr "Srednje dugme miÅ¡a" #: lib/logitech_receiver/i18n.py:78 msgid "Mouse Back Button" msgstr "Dugme za povratak na miÅ¡u" #: lib/logitech_receiver/i18n.py:79 msgid "Mouse Forward Button" msgstr "Dugme za unapred na miÅ¡u" #: lib/logitech_receiver/i18n.py:80 msgid "Gesture Button Navigation" msgstr "Navigacija pomocÌ�u dugmadi" #: lib/logitech_receiver/i18n.py:81 msgid "Mouse Scroll Left Button" msgstr "Levo dugme za pomeranje miÅ¡a" #: lib/logitech_receiver/i18n.py:82 msgid "Mouse Scroll Right Button" msgstr "Desno dugme za pomeranje miÅ¡a" #: lib/logitech_receiver/i18n.py:85 msgid "pressed" msgstr "pritisnuto" #: lib/logitech_receiver/i18n.py:86 msgid "released" msgstr "otpuÅ¡teno" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is closed" msgstr "uparivanje je zatvoreno" #: lib/logitech_receiver/notifications.py:75 #: lib/logitech_receiver/notifications.py:126 msgid "pairing lock is open" msgstr "uparivanje je otvoreno" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is closed" msgstr "otkrivanje je otvoreno" #: lib/logitech_receiver/notifications.py:92 msgid "discovery lock is open" msgstr "otkrivanje je zatvoreno" #: lib/logitech_receiver/notifications.py:224 lib/solaar/ui/notify.py:122 msgid "connected" msgstr "povezano" #: lib/logitech_receiver/notifications.py:224 msgid "disconnected" msgstr "odspojeno" #: lib/logitech_receiver/notifications.py:262 lib/solaar/ui/notify.py:120 msgid "unpaired" msgstr "nije upareno" #: lib/logitech_receiver/notifications.py:304 msgid "powered on" msgstr "ukljuÄ�en" #: lib/logitech_receiver/settings.py:750 msgid "register" msgstr "registriraj se" #: lib/logitech_receiver/settings.py:764 lib/logitech_receiver/settings.py:791 msgid "feature" msgstr "znaÄ�ajka" #: lib/logitech_receiver/settings_templates.py:139 msgid "Swap Fx function" msgstr "Zameni Fx funkciju" #: lib/logitech_receiver/settings_templates.py:140 msgid "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "Kada su podeÅ¡eni, tasteri F1..F12 cÌ�e aktivirati svoju posebnu " "funkciju,\n" "i morate držati FN taster da biste aktivirali njihovu standardnu " "funkciju." #: lib/logitech_receiver/settings_templates.py:142 msgid "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "Kada nisu omogućeni, tasteri F1..F12 cÌ�e aktivirati svoju standardnu " "funkciju, \n" "i morate držati FN taster da biste aktivirali njihovu posebnu " "funkciju." #: lib/logitech_receiver/settings_templates.py:149 msgid "Hand Detection" msgstr "Detekcija ruku" #: lib/logitech_receiver/settings_templates.py:150 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "UkljuÄ�ite osvetljenje kada ruke lebde preko tastature." #: lib/logitech_receiver/settings_templates.py:157 msgid "Scroll Wheel Smooth Scrolling" msgstr "ToÄ�ak za pomeranje, glatko pomeranje" #: lib/logitech_receiver/settings_templates.py:158 #: lib/logitech_receiver/settings_templates.py:239 #: lib/logitech_receiver/settings_templates.py:267 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Režim visoke osetljivosti za vertikalno pomeranje pomocÌ�u toÄ�kicÌ�a." #: lib/logitech_receiver/settings_templates.py:165 msgid "Side Scrolling" msgstr "BoÄ�no pomeranje" #: lib/logitech_receiver/settings_templates.py:167 msgid "When disabled, pushing the wheel sideways sends custom button " "events\n" "instead of the standard side-scrolling events." msgstr "Kada je onemogucÌ�eno, pomeranje toÄ�kicÌ�a u stranu Å¡alje dogaÄ‘aje " "prilagoÄ‘enog dugmeta \n" "umesto standardnih dogaÄ‘aja boÄ�nog pomeranja." #: lib/logitech_receiver/settings_templates.py:177 msgid "Sensitivity (DPI - older mice)" msgstr "Osetljivost (DPI - stariji miÅ¡evi)" #: lib/logitech_receiver/settings_templates.py:178 #: lib/logitech_receiver/settings_templates.py:712 msgid "Mouse movement sensitivity" msgstr "Osetljivost pokreta miÅ¡a" #: lib/logitech_receiver/settings_templates.py:208 #: lib/logitech_receiver/settings_templates.py:218 #: lib/logitech_receiver/settings_templates.py:225 msgid "Backlight" msgstr "Pozadinsko osvetljenje" #: lib/logitech_receiver/settings_templates.py:209 #: lib/logitech_receiver/settings_templates.py:226 msgid "Set illumination time for keyboard." msgstr "Podesite vreme osvetljenja za tastaturu." #: lib/logitech_receiver/settings_templates.py:219 msgid "Turn illumination on or off on keyboard." msgstr "UkljuÄ�ite ili iskljuÄ�ite osvetljenje na tastaturi." #: lib/logitech_receiver/settings_templates.py:237 msgid "Scroll Wheel High Resolution" msgstr "Visoka rezolucija toÄ�kicÌ�a za pomeranje." #: lib/logitech_receiver/settings_templates.py:240 #: lib/logitech_receiver/settings_templates.py:268 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Podesite da ignoriÅ¡ete ako je pomeranje nenormalno brzo ili sporo" #: lib/logitech_receiver/settings_templates.py:247 #: lib/logitech_receiver/settings_templates.py:277 msgid "Scroll Wheel Diversion" msgstr "Preusmeravanje toÄ�kicÌ�a za pomeranje" #: lib/logitech_receiver/settings_templates.py:249 msgid "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "Neka toÄ�kicÌ� za pomeranje Å¡alje LOWRES_WHEEL HID++ obaveÅ¡tenja (koja " "pokrecÌ�uSolaar pravila, ali se inaÄ�e ignoriÅ¡u." #: lib/logitech_receiver/settings_templates.py:256 msgid "Scroll Wheel Direction" msgstr "Smer toÄ�kicÌ�a za pomeranje" #: lib/logitech_receiver/settings_templates.py:257 msgid "Invert direction for vertical scroll with wheel." msgstr "Obrni smer za vertikalno pomeranje sa toÄ�kom." #: lib/logitech_receiver/settings_templates.py:265 msgid "Scroll Wheel Resolution" msgstr "Rezolucija toÄ�kicÌ�a za pomeranje" #: lib/logitech_receiver/settings_templates.py:279 msgid "Make scroll wheel send HIRES_WHEEL HID++ notifications (which " "trigger Solaar rules but are otherwise ignored)." msgstr "Neka toÄ�kicÌ� za pomeranje Å¡alje HIRES_WHEEL HID++ obaveÅ¡tenja (koja " "pokrecÌ�uSolaar pravila, ali se inaÄ�e ignoriÅ¡u." #: lib/logitech_receiver/settings_templates.py:288 msgid "Sensitivity (Pointer Speed)" msgstr "Osetljivost (brzina pokazivaÄ�a)" #: lib/logitech_receiver/settings_templates.py:289 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Množilac brzine za miÅ¡ (256 je normalan množilac)." #: lib/logitech_receiver/settings_templates.py:299 msgid "Thumb Wheel Diversion" msgstr "Diverzija sa palcem" #: lib/logitech_receiver/settings_templates.py:301 msgid "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "Neka kotaÄ�ić palca Å¡alje THUMB_WHEEL HID++ obavijesti (Å¡to pokreće " "Solaar pravila, u suprotnome ih zanemaruje)." #: lib/logitech_receiver/settings_templates.py:310 msgid "Thumb Wheel Direction" msgstr "Preusmeravanje pomicanja kotaÄ�ića palca" #: lib/logitech_receiver/settings_templates.py:311 msgid "Invert thumb wheel scroll direction." msgstr "Obrnite smer pomeranja toÄ�kicÌ�a" #: lib/logitech_receiver/settings_templates.py:319 msgid "Onboard Profiles" msgstr "Onboard profili" #: lib/logitech_receiver/settings_templates.py:320 msgid "Enable onboard profiles, which often control report rate and " "keyboard lighting" msgstr "Omogućite onboard profile, koji najÄ�ešće kontroliÅ¡u brzinom " "pozivanja i osvetljenje tipkovnice" #: lib/logitech_receiver/settings_templates.py:330 msgid "Polling Rate (ms)" msgstr "Brzina pozivanja (ms)" #: lib/logitech_receiver/settings_templates.py:332 msgid "Frequency of device polling, in milliseconds" msgstr "Frekvencija brzine pozivanja ureÄ‘aja, u milisekundama." #: lib/logitech_receiver/settings_templates.py:333 #: lib/logitech_receiver/settings_templates.py:1046 #: lib/logitech_receiver/settings_templates.py:1076 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "Možda cÌ�e biti potrebni ugraÄ‘eni profili podeÅ¡eni na 'OnemogucÌ�eno' da " "bi bili efikasni." #: lib/logitech_receiver/settings_templates.py:365 msgid "Divert crown events" msgstr "Preusmerite crown dogaÄ‘aje" #: lib/logitech_receiver/settings_templates.py:366 msgid "Make crown send CROWN HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Neka crown Å¡alje CROWN HID++ obaveÅ¡tenja (koja pokrecÌ�u Solaar " "pravila, alineka se inaÄ�e ignoriÅ¡u." #: lib/logitech_receiver/settings_templates.py:374 msgid "Crown smooth scroll" msgstr "Crown glatko pomicanje" #: lib/logitech_receiver/settings_templates.py:375 msgid "Set crown smooth scroll" msgstr "Podesi Crown glatko pomicanje" #: lib/logitech_receiver/settings_templates.py:383 msgid "Divert G Keys" msgstr "Preusmeri G tastere" #: lib/logitech_receiver/settings_templates.py:385 msgid "Make G keys send GKEY HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "Neka G tasteri Å¡alju GKEY HID++ obaveÅ¡tenja (koja pokreću Solaar " "pravila, alineka se inaÄ�e ignoriÅ¡u." #: lib/logitech_receiver/settings_templates.py:386 msgid "May also make M keys and MR key send HID++ notifications" msgstr "TakoÄ‘e može da uÄ�ini da M i MR tasteri Å¡alju HID++ obaveÅ¡tenja" #: lib/logitech_receiver/settings_templates.py:402 msgid "Scroll Wheel Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:403 msgid "Switch the mouse wheel between speed-controlled ratcheting and " "always freespin." msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Freespinning" msgstr "" #: lib/logitech_receiver/settings_templates.py:405 msgid "Ratcheted" msgstr "" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Ratchet Speed" msgstr "" #: lib/logitech_receiver/settings_templates.py:414 msgid "Use the mouse wheel speed to switch between ratcheted and " "freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" #: lib/logitech_receiver/settings_templates.py:463 msgid "Key/Button Actions" msgstr "Radnje tastera" #: lib/logitech_receiver/settings_templates.py:465 msgid "Change the action for the key or button." msgstr "Promenite radnju za taster ili dugme." #: lib/logitech_receiver/settings_templates.py:465 msgid "Overridden by diversion." msgstr "Preusmjeravanje tipki." #: lib/logitech_receiver/settings_templates.py:466 msgid "Changing important actions (such as for the left mouse button) can " "result in an unusable system." msgstr "Promena važnih radnji (kao Å¡to je levi taster miÅ¡a) može dovesti do " "neupotrebljivosti sistem." #: lib/logitech_receiver/settings_templates.py:639 msgid "Key/Button Diversion" msgstr "Preusmeravanje tipki" #: lib/logitech_receiver/settings_templates.py:640 msgid "Make the key or button send HID++ notifications (Diverted) or " "initiate Mouse Gestures or Sliding DPI" msgstr "Neka taster ili dugme Å¡alje HID++ obaveÅ¡tenja (preusmereno) ili " "pokrenite miÅ¡ pokretom" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Diverted" msgstr "Preusmereno" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 msgid "Mouse Gestures" msgstr "Pokreti miÅ¡a" #: lib/logitech_receiver/settings_templates.py:643 #: lib/logitech_receiver/settings_templates.py:644 #: lib/logitech_receiver/settings_templates.py:645 msgid "Regular" msgstr "Redovno" #: lib/logitech_receiver/settings_templates.py:643 msgid "Sliding DPI" msgstr "Klizni DPI" #: lib/logitech_receiver/settings_templates.py:711 msgid "Sensitivity (DPI)" msgstr "Osetljivost (DPI)" #: lib/logitech_receiver/settings_templates.py:752 msgid "Sensitivity Switching" msgstr "Promena osetljivosti" #: lib/logitech_receiver/settings_templates.py:754 msgid "Switch the current sensitivity and the remembered sensitivity when " "the key or button is pressed.\n" "If there is no remembered sensitivity, just remember the current " "sensitivity" msgstr "Promenite trenutnu osetljivost i zapamcÌ�enu osetljivost kada " "pritisnete taster ili kada je dugme pritisnuto. \n" "Ako nema zapamcÌ�ene osetljivosti, samo zapamtite trenutnu osetljivost" #: lib/logitech_receiver/settings_templates.py:758 msgid "Off" msgstr "UgaÅ¡en" #: lib/logitech_receiver/settings_templates.py:791 msgid "Disable keys" msgstr "Onemogući tipke" #: lib/logitech_receiver/settings_templates.py:792 msgid "Disable specific keyboard keys." msgstr "Onemogući odreÄ‘ene tipke na tipkovnici." #: lib/logitech_receiver/settings_templates.py:795 #, python-format msgid "Disables the %s key." msgstr "Onemogućuje %s tipku." #: lib/logitech_receiver/settings_templates.py:809 #: lib/logitech_receiver/settings_templates.py:860 msgid "Set OS" msgstr "Postavi OS" #: lib/logitech_receiver/settings_templates.py:810 #: lib/logitech_receiver/settings_templates.py:861 msgid "Change keys to match OS." msgstr "Promeni tastere da se poklapaju sa OS." #: lib/logitech_receiver/settings_templates.py:873 msgid "Change Host" msgstr "Promeni raÄ�unalo" #: lib/logitech_receiver/settings_templates.py:874 msgid "Switch connection to a different host" msgstr "Prebaci vezu na drugo raÄ�unalo" #: lib/logitech_receiver/settings_templates.py:900 msgid "Performs a left click." msgstr "Izvodi levi klik." #: lib/logitech_receiver/settings_templates.py:900 msgid "Single tap" msgstr "Jedan dodir" #: lib/logitech_receiver/settings_templates.py:901 msgid "Performs a right click." msgstr "Izvodi desni klik." #: lib/logitech_receiver/settings_templates.py:901 msgid "Single tap with two fingers" msgstr "Jedan dodir sa dva prsta" #: lib/logitech_receiver/settings_templates.py:902 msgid "Single tap with three fingers" msgstr "Jedan dodir sa tri prsta" #: lib/logitech_receiver/settings_templates.py:906 msgid "Double tap" msgstr "Dvostruki dodir" #: lib/logitech_receiver/settings_templates.py:906 msgid "Performs a double click." msgstr "Izvodi dvostruki klik." #: lib/logitech_receiver/settings_templates.py:907 msgid "Double tap with two fingers" msgstr "Dvoklik sa dva prsta" #: lib/logitech_receiver/settings_templates.py:908 msgid "Double tap with three fingers" msgstr "Dvoklik sa tri prsta" #: lib/logitech_receiver/settings_templates.py:911 msgid "Drags items by dragging the finger after double tapping." msgstr "PrevlaÄ�i stavke prevlaÄ�enjem prsta nakon dvostrukog dodira." #: lib/logitech_receiver/settings_templates.py:911 msgid "Tap and drag" msgstr "Dodirnite i prevucite" #: lib/logitech_receiver/settings_templates.py:913 msgid "Drags items by dragging the fingers after double tapping." msgstr "PrevlaÄ�i stavke prevlaÄ�enjem prstiju nakon dvostrukog dodira." #: lib/logitech_receiver/settings_templates.py:913 msgid "Tap and drag with two fingers" msgstr "Dodirnite i prevucite sa dva prsta" #: lib/logitech_receiver/settings_templates.py:914 msgid "Tap and drag with three fingers" msgstr "Dodirnite i prevucite sa tri prsta" #: lib/logitech_receiver/settings_templates.py:917 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "OnemogucÌ�ava pokrete dodira i rubnih gesta (ekvivalentno pritiskanju " "Fn+LeftClick)." #: lib/logitech_receiver/settings_templates.py:917 msgid "Suppress tap and edge gestures" msgstr "Zaustavite pokrete dodira i ivica" #: lib/logitech_receiver/settings_templates.py:918 msgid "Scroll with one finger" msgstr "Pomerite se jednim prstom" #: lib/logitech_receiver/settings_templates.py:918 #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scrolls." msgstr "Pomeranje." #: lib/logitech_receiver/settings_templates.py:919 #: lib/logitech_receiver/settings_templates.py:922 msgid "Scroll with two fingers" msgstr "Pomeranje sa dva prsta" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scroll horizontally with two fingers" msgstr "Pomeranje horizontalno sa dva prsta" #: lib/logitech_receiver/settings_templates.py:920 msgid "Scrolls horizontally." msgstr "Pomeranje horizontalno." #: lib/logitech_receiver/settings_templates.py:921 msgid "Scroll vertically with two fingers" msgstr "Pomeranje vertikalno sa dva prsta" #: lib/logitech_receiver/settings_templates.py:921 msgid "Scrolls vertically." msgstr "Pomeranje vertikalno." #: lib/logitech_receiver/settings_templates.py:923 msgid "Inverts the scrolling direction." msgstr "ObrÄ�e smer pomeranja." #: lib/logitech_receiver/settings_templates.py:923 msgid "Natural scrolling" msgstr "Prirodno pomeranje" #: lib/logitech_receiver/settings_templates.py:924 msgid "Enables the thumbwheel." msgstr "OmogucÌ�ava toÄ�kicÌ�." #: lib/logitech_receiver/settings_templates.py:924 msgid "Thumbwheel" msgstr "KotaÄ�ić palca." #: lib/logitech_receiver/settings_templates.py:935 #: lib/logitech_receiver/settings_templates.py:939 msgid "Swipe from the top edge" msgstr "Povucite od gornjeg ruba" #: lib/logitech_receiver/settings_templates.py:936 msgid "Swipe from the left edge" msgstr "Povucite od levog ruba" #: lib/logitech_receiver/settings_templates.py:937 msgid "Swipe from the right edge" msgstr "Povucite od desnog ruba" #: lib/logitech_receiver/settings_templates.py:938 msgid "Swipe from the bottom edge" msgstr "Povucite od donjeg ruba" #: lib/logitech_receiver/settings_templates.py:940 msgid "Swipe two fingers from the left edge" msgstr "Povucite sa dva prsta od levog ruba" #: lib/logitech_receiver/settings_templates.py:941 msgid "Swipe two fingers from the right edge" msgstr "Povucite sa dva prsta od desnog ruba" #: lib/logitech_receiver/settings_templates.py:942 msgid "Swipe two fingers from the bottom edge" msgstr "Povucite sa dva prsta od donjeg ruba" #: lib/logitech_receiver/settings_templates.py:943 msgid "Swipe two fingers from the top edge" msgstr "Povucite sa dva prsta od gornjeg ruba" #: lib/logitech_receiver/settings_templates.py:944 #: lib/logitech_receiver/settings_templates.py:948 msgid "Pinch to zoom out; spread to zoom in." msgstr "Stisnite da biste umanjili; proÅ¡irite da biste uvecÌ�ali." #: lib/logitech_receiver/settings_templates.py:944 msgid "Zoom with two fingers." msgstr "Zumirajte sa dva prsta." #: lib/logitech_receiver/settings_templates.py:945 msgid "Pinch to zoom out." msgstr "Stisnite prste da biste umanjili prikaz." #: lib/logitech_receiver/settings_templates.py:946 msgid "Spread to zoom in." msgstr "RaÅ¡irite prste da biste uvecÌ�ali." #: lib/logitech_receiver/settings_templates.py:947 msgid "Zoom with three fingers." msgstr "Zumirajte sa tri prsta." #: lib/logitech_receiver/settings_templates.py:948 msgid "Zoom with two fingers" msgstr "Zumirajte sa dva prsta." #: lib/logitech_receiver/settings_templates.py:966 msgid "Pixel zone" msgstr "Zona piksela" #: lib/logitech_receiver/settings_templates.py:967 msgid "Ratio zone" msgstr "Zona omera" #: lib/logitech_receiver/settings_templates.py:968 msgid "Scale factor" msgstr "Faktor veliÄ�ine" #: lib/logitech_receiver/settings_templates.py:968 msgid "Sets the cursor speed." msgstr "PodeÅ¡ava brzinu pokazivaÄ�a." #: lib/logitech_receiver/settings_templates.py:972 msgid "Left" msgstr "Levo" #: lib/logitech_receiver/settings_templates.py:972 msgid "Left-most coordinate." msgstr "NajuÄ�estalija leva koordinata." #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom" msgstr "Dno" #: lib/logitech_receiver/settings_templates.py:973 msgid "Bottom coordinate." msgstr "Donja koordinata." #: lib/logitech_receiver/settings_templates.py:974 msgid "Width" msgstr "Å irina" #: lib/logitech_receiver/settings_templates.py:974 msgid "Width." msgstr "Å irina" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height" msgstr "Visina" #: lib/logitech_receiver/settings_templates.py:975 msgid "Height." msgstr "Visina." #: lib/logitech_receiver/settings_templates.py:976 msgid "Cursor speed." msgstr "Brzina kursora." #: lib/logitech_receiver/settings_templates.py:976 msgid "Scale" msgstr "Skala" #: lib/logitech_receiver/settings_templates.py:982 msgid "Gestures" msgstr "Geste" #: lib/logitech_receiver/settings_templates.py:983 msgid "Tweak the mouse/touchpad behaviour." msgstr "Podesite ponaÅ¡anje miÅ¡a/taÄ�peda." #: lib/logitech_receiver/settings_templates.py:1000 msgid "Gestures Diversion" msgstr "Preusmjeravanje gesta" #: lib/logitech_receiver/settings_templates.py:1001 msgid "Divert mouse/touchpad gestures." msgstr "Preusmeri ponaÅ¡anje miÅ¡a/taÄ�peda." #: lib/logitech_receiver/settings_templates.py:1018 msgid "Gesture params" msgstr "Parametri pokreta" #: lib/logitech_receiver/settings_templates.py:1019 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Promenite numeriÄ�ke parametre miÅ¡a/taÄ�peda." #: lib/logitech_receiver/settings_templates.py:1044 msgid "M-Key LEDs" msgstr "LED osvetljenje M-tastera" #: lib/logitech_receiver/settings_templates.py:1046 msgid "Control the M-Key LEDs." msgstr "KontroliÅ¡ite LED osvetljenje M-tastera." #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1077 msgid "May need G Keys diverted to be effective." msgstr "Možda cÌ�e biti potrebno ponovo preusmeriti taster G da bi bili " "efikasni." #: lib/logitech_receiver/settings_templates.py:1053 #, python-format msgid "Lights up the %s key." msgstr "Osvetli %s taster." #: lib/logitech_receiver/settings_templates.py:1074 msgid "MR-Key LED" msgstr "LED MR-tastera" #: lib/logitech_receiver/settings_templates.py:1076 msgid "Control the MR-Key LED." msgstr "KontroliÅ¡e LED osvetljenje MR-tastera." #: lib/logitech_receiver/settings_templates.py:1095 msgid "Persistent Key/Button Mapping" msgstr "Trajno mapiranje tastera/dugmada" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Permanently change the mapping for the key or button." msgstr "Trajno promenite mapiranje za taster ili dugme." #: lib/logitech_receiver/settings_templates.py:1098 msgid "Changing important keys or buttons (such as for the left mouse " "button) can result in an unusable system." msgstr "Promena važnih tastera ili dugmadi (kao Å¡to je levi taster miÅ¡a) " "može rezultiraju nestabilnim sistemom." #: lib/logitech_receiver/settings_templates.py:1157 msgid "Sidetone" msgstr "BoÄ�ni ton" #: lib/logitech_receiver/settings_templates.py:1158 msgid "Set sidetone level." msgstr "Podesite nivo boÄ�nih tonova." #: lib/logitech_receiver/settings_templates.py:1167 msgid "Equalizer" msgstr "Ekvilajzer" #: lib/logitech_receiver/settings_templates.py:1168 msgid "Set equalizer levels." msgstr "Podesite nivo ekvilajzera." #: lib/logitech_receiver/settings_templates.py:1191 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1197 msgid "Power Management" msgstr "" #: lib/logitech_receiver/settings_templates.py:1198 msgid "Power off in minutes (0 for never)." msgstr "" #: lib/logitech_receiver/status.py:114 msgid "No paired devices." msgstr "Nema uparenih ureÄ‘aja" #: lib/logitech_receiver/status.py:115 lib/solaar/ui/window.py:622 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s uparen ureÄ‘aj." msgstr[1] "%(count)s uparena ureÄ‘aja." #: lib/logitech_receiver/status.py:170 #, python-format msgid "Battery: %(level)s" msgstr "Baterija: %(level)s" #: lib/logitech_receiver/status.py:172 #, python-format msgid "Battery: %(percent)d%%" msgstr "Baterija: %(percent)d%%" #: lib/logitech_receiver/status.py:184 #, python-format msgid "Lighting: %(level)s lux" msgstr "Osvetljenje %(level)s lux" #: lib/logitech_receiver/status.py:239 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Baterija: %(level)s (%(status)s)" #: lib/logitech_receiver/status.py:241 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Baterija: %(percent)d%% (%(status)s)" #: lib/solaar/ui/__init__.py:52 msgid "Permissions error" msgstr "GreÅ¡ka u dozvolama" #: lib/solaar/ui/__init__.py:54 #, python-format msgid "Found a Logitech receiver or device (%s), but did not have " "permission to open it." msgstr "" #: lib/solaar/ui/__init__.py:55 msgid "If you've just installed Solaar, try disconnecting the receiver or " "device and then reconnecting it." msgstr "" #: lib/solaar/ui/__init__.py:58 msgid "Cannot connect to device error" msgstr "Ne mogu da se povežem sa ureÄ‘ajem, greÅ¡ka" #: lib/solaar/ui/__init__.py:60 #, python-format msgid "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "PronaÅ¡li smo Logitech prijemnik ili ureÄ‘aj na %s, ali smo naiÅ¡li na " "greÅ¡kuprilikom povezivanja." #: lib/solaar/ui/__init__.py:61 msgid "Try disconnecting the device and then reconnecting it or turning it " "off and then on." msgstr "" #: lib/solaar/ui/__init__.py:64 msgid "Unpairing failed" msgstr "Uparivanje neuspelo" #: lib/solaar/ui/__init__.py:66 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Odparivanje %{device} sa %{receiver} nije uspelo." #: lib/solaar/ui/__init__.py:67 msgid "The receiver returned an error, with no further details." msgstr "Prijemnik je vratio greÅ¡ku, bez dodatnih detalja." #: lib/solaar/ui/__init__.py:177 msgid "Another Solaar process is already running so just expose its window" msgstr "JoÅ¡ jedan Solaar proces je vecÌ� pokrenut, pa samo otvorite njegov " "prozor" #: lib/solaar/ui/about.py:36 msgid "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "Upravlja Logitech prijemnicima,\n" "tastature, miÅ¡evi i tableti." #: lib/solaar/ui/about.py:44 msgid "Additional Programming" msgstr "Dodatno programiranje" #: lib/solaar/ui/about.py:45 msgid "GUI design" msgstr "GUI dizajn" #: lib/solaar/ui/about.py:47 msgid "Testing" msgstr "Testiranje" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Logitech dokumentacija" #: lib/solaar/ui/action.py:85 lib/solaar/ui/action.py:89 #: lib/solaar/ui/window.py:197 msgid "Unpair" msgstr "Odspoji" #: lib/solaar/ui/action.py:88 lib/solaar/ui/diversion_rules.py:150 msgid "Cancel" msgstr "PoniÅ¡ti" #: lib/solaar/ui/config_panel.py:212 msgid "Complete - ENTER to change" msgstr "ZavrÅ¡eno - pritisnite ENTER da biste promenili" #: lib/solaar/ui/config_panel.py:212 msgid "Incomplete" msgstr "Nepotpuno" #: lib/solaar/ui/config_panel.py:455 lib/solaar/ui/config_panel.py:507 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d vrednost" msgstr[1] "%d vrednosti" #: lib/solaar/ui/config_panel.py:518 msgid "Changes allowed" msgstr "Promene dozvoljene" #: lib/solaar/ui/config_panel.py:519 msgid "No changes allowed" msgstr "Promene zabranjene" #: lib/solaar/ui/config_panel.py:520 msgid "Ignore this setting" msgstr "IgnoriÅ¡i ovu postavku" #: lib/solaar/ui/config_panel.py:565 msgid "Working" msgstr "Radim" #: lib/solaar/ui/config_panel.py:568 msgid "Read/write operation failed." msgstr "Operacija Ä�itanja/pisanja nije uspela." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "UgraÄ‘ena pravila" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "KorisniÄ�ki definisana pravila" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1083 msgid "Rule" msgstr "Pravilo" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:509 #: lib/solaar/ui/diversion_rules.py:636 msgid "Sub-rule" msgstr "Podpravilo" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[prazno]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Solaar Rule Editor" msgstr "Solaar ureÄ‘ivaÄ� pravila" #: lib/solaar/ui/diversion_rules.py:141 msgid "Make changes permanent?" msgstr "Želite li da promene budu trajne?" #: lib/solaar/ui/diversion_rules.py:146 msgid "Yes" msgstr "Da" #: lib/solaar/ui/diversion_rules.py:148 msgid "No" msgstr "Ne" #: lib/solaar/ui/diversion_rules.py:153 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Ako izaberete Ne, promene cÌ�e biti izgubljene kada se Solaar zatvori." #: lib/solaar/ui/diversion_rules.py:201 msgid "Save changes" msgstr "Spremi promene" #: lib/solaar/ui/diversion_rules.py:206 msgid "Discard changes" msgstr "Odbaci promene" #: lib/solaar/ui/diversion_rules.py:372 msgid "Insert here" msgstr "Unesi ovde" #: lib/solaar/ui/diversion_rules.py:374 msgid "Insert above" msgstr "Unesi iznad" #: lib/solaar/ui/diversion_rules.py:376 msgid "Insert below" msgstr "Unesi ispod" #: lib/solaar/ui/diversion_rules.py:382 msgid "Insert new rule here" msgstr "Unesi novo pravilo ovde" #: lib/solaar/ui/diversion_rules.py:384 msgid "Insert new rule above" msgstr "Unesi novo pravilo iznad" #: lib/solaar/ui/diversion_rules.py:386 msgid "Insert new rule below" msgstr "Unesi novo pravilo ispod" #: lib/solaar/ui/diversion_rules.py:427 msgid "Paste here" msgstr "Zalepi ovde" #: lib/solaar/ui/diversion_rules.py:429 msgid "Paste above" msgstr "Zalepi iznad" #: lib/solaar/ui/diversion_rules.py:431 msgid "Paste below" msgstr "Zalepi ispod" #: lib/solaar/ui/diversion_rules.py:437 msgid "Paste rule here" msgstr "Zalepi pravilo ovde" #: lib/solaar/ui/diversion_rules.py:439 msgid "Paste rule above" msgstr "Zalepi pravilo iznad" #: lib/solaar/ui/diversion_rules.py:441 msgid "Paste rule below" msgstr "Zalepi pravilo ispod" #: lib/solaar/ui/diversion_rules.py:445 msgid "Paste rule" msgstr "Zalepi pravilo" #: lib/solaar/ui/diversion_rules.py:474 msgid "Flatten" msgstr "Poravnaj" #: lib/solaar/ui/diversion_rules.py:507 msgid "Insert" msgstr "Unesi" #: lib/solaar/ui/diversion_rules.py:510 lib/solaar/ui/diversion_rules.py:638 #: lib/solaar/ui/diversion_rules.py:1126 msgid "Or" msgstr "Ili" #: lib/solaar/ui/diversion_rules.py:511 lib/solaar/ui/diversion_rules.py:637 #: lib/solaar/ui/diversion_rules.py:1111 msgid "And" msgstr "I" #: lib/solaar/ui/diversion_rules.py:513 msgid "Condition" msgstr "Stanje" #: lib/solaar/ui/diversion_rules.py:515 lib/solaar/ui/diversion_rules.py:1292 msgid "Feature" msgstr "ZnaÄ�ajka" #: lib/solaar/ui/diversion_rules.py:516 lib/solaar/ui/diversion_rules.py:1328 msgid "Report" msgstr "IzveÅ¡taj" #: lib/solaar/ui/diversion_rules.py:517 lib/solaar/ui/diversion_rules.py:1204 msgid "Process" msgstr "Proces" #: lib/solaar/ui/diversion_rules.py:518 msgid "Mouse process" msgstr "Proces miÅ¡a" #: lib/solaar/ui/diversion_rules.py:519 lib/solaar/ui/diversion_rules.py:1366 msgid "Modifiers" msgstr "Modifikatori" #: lib/solaar/ui/diversion_rules.py:520 lib/solaar/ui/diversion_rules.py:1419 msgid "Key" msgstr "Taster" #: lib/solaar/ui/diversion_rules.py:521 lib/solaar/ui/diversion_rules.py:1461 msgid "KeyIsDown" msgstr "" #: lib/solaar/ui/diversion_rules.py:522 lib/solaar/ui/diversion_rules.py:2260 msgid "Active" msgstr "Радан" #: lib/solaar/ui/diversion_rules.py:523 lib/solaar/ui/diversion_rules.py:2218 #: lib/solaar/ui/diversion_rules.py:2270 lib/solaar/ui/diversion_rules.py:2323 msgid "Device" msgstr "UreÄ‘aj" #: lib/solaar/ui/diversion_rules.py:524 lib/solaar/ui/diversion_rules.py:2297 msgid "Host" msgstr "" #: lib/solaar/ui/diversion_rules.py:525 lib/solaar/ui/diversion_rules.py:2339 msgid "Setting" msgstr "Postavka" #: lib/solaar/ui/diversion_rules.py:526 lib/solaar/ui/diversion_rules.py:1477 #: lib/solaar/ui/diversion_rules.py:1526 msgid "Test" msgstr "Test" #: lib/solaar/ui/diversion_rules.py:527 lib/solaar/ui/diversion_rules.py:1643 msgid "Test bytes" msgstr "Testiraj bajtove" #: lib/solaar/ui/diversion_rules.py:528 lib/solaar/ui/diversion_rules.py:1736 msgid "Mouse Gesture" msgstr "Gesta miÅ¡a" #: lib/solaar/ui/diversion_rules.py:532 msgid "Action" msgstr "Akcija" #: lib/solaar/ui/diversion_rules.py:534 lib/solaar/ui/diversion_rules.py:1845 msgid "Key press" msgstr "Pritisak tipke" #: lib/solaar/ui/diversion_rules.py:535 lib/solaar/ui/diversion_rules.py:1897 msgid "Mouse scroll" msgstr "Pomeranje miÅ¡a" #: lib/solaar/ui/diversion_rules.py:536 lib/solaar/ui/diversion_rules.py:1959 msgid "Mouse click" msgstr "Klik miÅ¡em" #: lib/solaar/ui/diversion_rules.py:537 msgid "Set" msgstr "Postavi" #: lib/solaar/ui/diversion_rules.py:538 lib/solaar/ui/diversion_rules.py:2030 msgid "Execute" msgstr "IzvrÅ¡i" #: lib/solaar/ui/diversion_rules.py:539 lib/solaar/ui/diversion_rules.py:1158 msgid "Later" msgstr "" #: lib/solaar/ui/diversion_rules.py:568 msgid "Insert new rule" msgstr "Unesi novo pravilo" #: lib/solaar/ui/diversion_rules.py:588 lib/solaar/ui/diversion_rules.py:1686 #: lib/solaar/ui/diversion_rules.py:1790 lib/solaar/ui/diversion_rules.py:1989 msgid "Delete" msgstr "ObriÅ¡i" #: lib/solaar/ui/diversion_rules.py:610 msgid "Negate" msgstr "Negiraj" #: lib/solaar/ui/diversion_rules.py:634 msgid "Wrap with" msgstr "Zamotajte sa" #: lib/solaar/ui/diversion_rules.py:656 msgid "Cut" msgstr "Izreži" #: lib/solaar/ui/diversion_rules.py:671 msgid "Paste" msgstr "Zalepi" #: lib/solaar/ui/diversion_rules.py:683 msgid "Copy" msgstr "Kopiraj" #: lib/solaar/ui/diversion_rules.py:1063 msgid "This editor does not support the selected rule component yet." msgstr "Ovaj tekstualni ureÄ‘ivaÄ� joÅ¡ uvek ne podržava izabranu komponentu " "pravila." #: lib/solaar/ui/diversion_rules.py:1138 msgid "Number of seconds to delay." msgstr "" #: lib/solaar/ui/diversion_rules.py:1177 msgid "Not" msgstr "Ne" #: lib/solaar/ui/diversion_rules.py:1187 msgid "X11 active process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1218 msgid "X11 mouse process. For use in X11 only." msgstr "" #: lib/solaar/ui/diversion_rules.py:1235 msgid "MouseProcess" msgstr "Proces miÅ¡a" #: lib/solaar/ui/diversion_rules.py:1260 msgid "Feature name of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1308 msgid "Report number of notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1342 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "" #: lib/solaar/ui/diversion_rules.py:1383 msgid "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1392 msgid "Key down" msgstr "Tipka za dolje" #: lib/solaar/ui/diversion_rules.py:1395 msgid "Key up" msgstr "Tipka za gore" #: lib/solaar/ui/diversion_rules.py:1436 msgid "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert " "keys and buttons." msgstr "" #: lib/solaar/ui/diversion_rules.py:1475 msgid "Test condition on notification triggering rule processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1479 msgid "Parameter" msgstr "" #: lib/solaar/ui/diversion_rules.py:1542 msgid "begin (inclusive)" msgstr "poÄ�etak (ukljuÄ�iv)" #: lib/solaar/ui/diversion_rules.py:1543 msgid "end (exclusive)" msgstr "zavrÅ¡etak (iskljuÄ�iv)" #: lib/solaar/ui/diversion_rules.py:1552 msgid "range" msgstr "domet" #: lib/solaar/ui/diversion_rules.py:1554 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/diversion_rules.py:1555 msgid "maximum" msgstr "maximum" #: lib/solaar/ui/diversion_rules.py:1557 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "bajtovi %(0)d do %(1)d, u dometu od %(2)d do %(3)d" #: lib/solaar/ui/diversion_rules.py:1562 msgid "mask" msgstr "mask" #: lib/solaar/ui/diversion_rules.py:1563 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "bajtovi %(0)d do %(1)d, maska %(2)d" #: lib/solaar/ui/diversion_rules.py:1573 msgid "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" #: lib/solaar/ui/diversion_rules.py:1583 msgid "type" msgstr "tip" #: lib/solaar/ui/diversion_rules.py:1666 msgid "Mouse gesture with optional initiating button followed by zero or " "more mouse movements." msgstr "" #: lib/solaar/ui/diversion_rules.py:1671 msgid "Add movement" msgstr "" #: lib/solaar/ui/diversion_rules.py:1764 msgid "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1769 msgid "Add key" msgstr "Dodaj tipku" #: lib/solaar/ui/diversion_rules.py:1772 msgid "Click" msgstr "Kliknite" #: lib/solaar/ui/diversion_rules.py:1775 msgid "Depress" msgstr "Odpustite" #: lib/solaar/ui/diversion_rules.py:1778 msgid "Release" msgstr "Odpustite" #: lib/solaar/ui/diversion_rules.py:1861 msgid "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1918 msgid "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" #: lib/solaar/ui/diversion_rules.py:1921 msgid "Button" msgstr "Taster" #: lib/solaar/ui/diversion_rules.py:1922 msgid "Count and Action" msgstr "" #: lib/solaar/ui/diversion_rules.py:1972 msgid "Execute a command with arguments." msgstr "" #: lib/solaar/ui/diversion_rules.py:1975 msgid "Add argument" msgstr "Dodajte argument" #: lib/solaar/ui/diversion_rules.py:2050 msgid "Toggle" msgstr "UkljuÄ�i/IskljuÄ�i" #: lib/solaar/ui/diversion_rules.py:2050 msgid "True" msgstr "Istina" #: lib/solaar/ui/diversion_rules.py:2051 msgid "False" msgstr "Laž" #: lib/solaar/ui/diversion_rules.py:2065 msgid "Unsupported setting" msgstr "Nepodržana postavka" #: lib/solaar/ui/diversion_rules.py:2223 lib/solaar/ui/diversion_rules.py:2242 #: lib/solaar/ui/diversion_rules.py:2328 lib/solaar/ui/diversion_rules.py:2570 #: lib/solaar/ui/diversion_rules.py:2588 msgid "Originating device" msgstr "Izvorni ureÄ‘aj" #: lib/solaar/ui/diversion_rules.py:2256 msgid "Device is active and its settings can be changed." msgstr "" #: lib/solaar/ui/diversion_rules.py:2266 msgid "Device that originated the current notification." msgstr "" #: lib/solaar/ui/diversion_rules.py:2280 msgid "Name of host computer." msgstr "" #: lib/solaar/ui/diversion_rules.py:2347 msgid "Value" msgstr "Vrednost" #: lib/solaar/ui/diversion_rules.py:2355 msgid "Item" msgstr "Stavka" #: lib/solaar/ui/diversion_rules.py:2630 msgid "Change setting on device" msgstr "" #: lib/solaar/ui/diversion_rules.py:2647 msgid "Setting on device" msgstr "" #: lib/solaar/ui/notify.py:124 lib/solaar/ui/tray.py:318 #: lib/solaar/ui/tray.py:323 lib/solaar/ui/window.py:739 msgid "offline" msgstr "ugaÅ¡eno" #: lib/solaar/ui/pair_window.py:122 lib/solaar/ui/pair_window.py:256 #: lib/solaar/ui/pair_window.py:288 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: uparite novi ureÄ‘aj" #: lib/solaar/ui/pair_window.py:123 #, python-format msgid "Enter passcode on %(name)s." msgstr "Unesite lozinku na %(name)s." #: lib/solaar/ui/pair_window.py:126 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Unesite %(passcode)s, a zatim pritisnite tipku enter." #: lib/solaar/ui/pair_window.py:129 msgid "left" msgstr "levo" #: lib/solaar/ui/pair_window.py:129 msgid "right" msgstr "desno" #: lib/solaar/ui/pair_window.py:131 #, python-format msgid "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "Pritisnite %(code)s\n" "a zatim istovremeno pritisnite levo i desno dugme." #: lib/solaar/ui/pair_window.py:188 msgid "Pairing failed" msgstr "Uparivanje neuspelo" #: lib/solaar/ui/pair_window.py:190 msgid "Make sure your device is within range, and has a decent battery " "charge." msgstr "Uverite se da je vaÅ¡ ureÄ‘aj u dometu i da ima pristojno punjenje " "baterije." #: lib/solaar/ui/pair_window.py:192 msgid "A new device was detected, but it is not compatible with this " "receiver." msgstr "Otkriven je novi ureÄ‘aj, ali nije kompatibilan sa ovim prijemnikom." #: lib/solaar/ui/pair_window.py:194 msgid "More paired devices than receiver can support." msgstr "ViÅ¡e uparenih ureÄ‘aja nego Å¡to prijemnik može da podrži." #: lib/solaar/ui/pair_window.py:196 msgid "No further details are available about the error." msgstr "Nisu dostupni dodatni detalji o greÅ¡ci." #: lib/solaar/ui/pair_window.py:210 msgid "Found a new device:" msgstr "PronaÄ‘en novi ureÄ‘aj:" #: lib/solaar/ui/pair_window.py:235 msgid "The wireless link is not encrypted" msgstr "BežiÄ�na veza nije Å¡ifrovana" #: lib/solaar/ui/pair_window.py:264 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "" #: lib/solaar/ui/pair_window.py:266 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "" #: lib/solaar/ui/pair_window.py:268 msgid "Other receivers are only compatible with a few devices." msgstr "" #: lib/solaar/ui/pair_window.py:270 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" #: lib/solaar/ui/pair_window.py:274 msgid "Press a pairing button or key until the pairing light flashes " "quickly." msgstr "Pritisnite dugme ili taster za uparivanje dok lampica za uparivanje " "ne poÄ�ne brzo da treperi." #: lib/solaar/ui/pair_window.py:276 msgid "You may have to first turn the device off and on again." msgstr "Možda cÌ�ete morati prvo da iskljuÄ�ite i ponovo ukljuÄ�ite ureÄ‘aj." #: lib/solaar/ui/pair_window.py:278 msgid "Turn on the device you want to pair." msgstr "UkljuÄ�ite ureÄ‘aj koji želite da uparite." #: lib/solaar/ui/pair_window.py:280 msgid "If the device is already turned on, turn it off and on again." msgstr "Ako je ureÄ‘aj vecÌ� ukljuÄ�en, iskljuÄ�ite ga i ponovo ukljuÄ�ite." #: lib/solaar/ui/pair_window.py:283 #, python-format msgid "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "\n" "\n" "Ovaj prijemnik ima joÅ¡ %d uparivanje." msgstr[1] "\n" "\n" "Ovaj prijemnik ima joÅ¡ %d uparivanja." #: lib/solaar/ui/pair_window.py:286 msgid "\n" "Cancelling at this point will not use up a pairing." msgstr "\n" "Otkazivanje u ovom trenutku necÌ�e potroÅ¡iti uparivanje." #: lib/solaar/ui/tray.py:58 msgid "No supported device found" msgstr "" #: lib/solaar/ui/tray.py:64 lib/solaar/ui/window.py:319 #, python-format msgid "About %s" msgstr "O %s" #: lib/solaar/ui/tray.py:65 lib/solaar/ui/window.py:317 #, python-format msgid "Quit %s" msgstr "Zatvori %s" #: lib/solaar/ui/tray.py:297 lib/solaar/ui/tray.py:305 msgid "no receiver" msgstr "nema prijemnika" #: lib/solaar/ui/tray.py:321 msgid "no status" msgstr "nema statusa" #: lib/solaar/ui/window.py:96 msgid "Scanning" msgstr "Skeniranje" #: lib/solaar/ui/window.py:129 msgid "Battery" msgstr "Baterija" #: lib/solaar/ui/window.py:132 msgid "Wireless Link" msgstr "BežiÄ�na veza" #: lib/solaar/ui/window.py:136 msgid "Lighting" msgstr "Osvetljenje" #: lib/solaar/ui/window.py:170 msgid "Show Technical Details" msgstr "Prikaži tehniÄ�ke detalje" #: lib/solaar/ui/window.py:186 msgid "Pair new device" msgstr "Uparite novi ureÄ‘aj" #: lib/solaar/ui/window.py:205 msgid "Select a device" msgstr "Odaberite ureÄ‘aj" #: lib/solaar/ui/window.py:322 msgid "Rule Editor" msgstr "Tekstualni ureÄ‘ivaÄ� prava" #: lib/solaar/ui/window.py:533 msgid "Path" msgstr "Put" #: lib/solaar/ui/window.py:536 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:539 lib/solaar/ui/window.py:541 #: lib/solaar/ui/window.py:561 lib/solaar/ui/window.py:563 msgid "Serial" msgstr "Serijski" #: lib/solaar/ui/window.py:545 msgid "Index" msgstr "Indeks" #: lib/solaar/ui/window.py:547 msgid "Wireless PID" msgstr "Wireless PID" #: lib/solaar/ui/window.py:549 msgid "Product ID" msgstr "Product ID" #: lib/solaar/ui/window.py:551 msgid "Protocol" msgstr "Protokol" #: lib/solaar/ui/window.py:551 msgid "Unknown" msgstr "Nepoznato" #: lib/solaar/ui/window.py:554 #, python-format msgid "%(rate)d ms (%(rate_hz)dHz)" msgstr "%(rate)d ms (%(rate_hz)dHz)" #: lib/solaar/ui/window.py:554 msgid "Polling rate" msgstr "Brzina pozivanja" #: lib/solaar/ui/window.py:565 msgid "Unit ID" msgstr "Unit ID" #: lib/solaar/ui/window.py:576 msgid "none" msgstr "nema" #: lib/solaar/ui/window.py:577 msgid "Notifications" msgstr "ObaveÅ¡tenja" #: lib/solaar/ui/window.py:621 msgid "No device paired." msgstr "Nijedan ureÄ‘aj nije uparen." #: lib/solaar/ui/window.py:628 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Do %(max_count)s ureÄ‘aj može da se upari sa ovim prijemnikom." msgstr[1] "Do %(max_count)s ureÄ‘aja može da se upari sa ovim " "prijemnikom." #: lib/solaar/ui/window.py:634 msgid "Only one device can be paired to this receiver." msgstr "Samo jedan ureÄ‘aj može biti uparen sa ovim prijemnikom." #: lib/solaar/ui/window.py:638 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Ovaj prijemnik ima joÅ¡ %d uparivanje." msgstr[1] "Ovaj prijemnik ima joÅ¡ %d uparivanja." #: lib/solaar/ui/window.py:692 msgid "Battery Voltage" msgstr "Voltaža baterije" #: lib/solaar/ui/window.py:694 msgid "Voltage reported by battery" msgstr "Napon koji javlja baterija" #: lib/solaar/ui/window.py:696 msgid "Battery Level" msgstr "Nivo baterije" #: lib/solaar/ui/window.py:698 msgid "Approximate level reported by battery" msgstr "Baterija prijavljuje približan nivo" #: lib/solaar/ui/window.py:705 lib/solaar/ui/window.py:707 msgid "next reported " msgstr "sledecÌ�i izveÅ¡taj " #: lib/solaar/ui/window.py:708 msgid " and next level to be reported." msgstr " i sledecÌ�i nivo koji treba izvesti." #: lib/solaar/ui/window.py:713 msgid "last known" msgstr "poslednje poznato" #: lib/solaar/ui/window.py:724 msgid "encrypted" msgstr "Å¡ifrovano" #: lib/solaar/ui/window.py:726 msgid "The wireless link between this device and its receiver is encrypted." msgstr "BežiÄ�na veza izmeÄ‘u ovog ureÄ‘aja i njegovog prijemnika je Å¡ifrovana." #: lib/solaar/ui/window.py:728 msgid "not encrypted" msgstr "nije Å¡ifrovano" #: lib/solaar/ui/window.py:732 msgid "The wireless link between this device and its receiver is not " "encrypted.\n" "This is a security issue for pointing devices, and a major security " "issue for text-input devices." msgstr "" #: lib/solaar/ui/window.py:748 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "Add action" #~ msgstr "Dodaj akciju" #~ msgid "Adjust the DPI by sliding the mouse horizontally while " #~ "holding the button down." #~ msgstr "Podesite DPI pomeranjem miÅ¡a horizontalno dok držite " #~ "tasterza dolje." #~ msgid "Automatically switch the mouse wheel between ratchet and " #~ "freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "Automatski prebacite toÄ�kicÌ� miÅ¡a izmeÄ‘u režima ratchet i " #~ "slobodnog naÄ�ina. \n" #~ "ToÄ�ak miÅ¡a je uvek slobodan na 0, i uvek zakljuÄ�an na 50" #~ msgid "Battery information unknown." #~ msgstr "Informacije o bateriji nepoznate." #~ msgid "Count" #~ msgstr "Brojilo" #~ msgid "DPI Sliding Adjustment" #~ msgstr "DPI klizno podeÅ¡avanje" #, python-format #~ msgid "Found a Logitech Receiver (%s), but did not have permission " #~ "to open it." #~ msgstr "PronaÅ¡ao sam Logitech prijemnik (%s), ali nisam imao dozvolu " #~ "da ga otvorim." #~ msgid "If you've just installed Solaar, try removing the receiver " #~ "and plugging it back in." #~ msgstr "Ako ste upravo instalirali Solaar, pokuÅ¡ajte da odspojite " #~ "prijemnik i prikljuÄ�ite gaponovo." #~ msgid "No Logitech device found" #~ msgstr "Nije pronaÄ‘en nijedan Logitech ureÄ‘aj" #~ msgid "Scroll Wheel Rachet" #~ msgstr "Ustavljanje pomicanja kotaÄ�ića" #~ msgid "Send a gesture by sliding the mouse while holding the button " #~ "down." #~ msgstr "PoÅ¡aljite pokret prevlaÄ�enjem miÅ¡a dok držite dugme za dole." #~ msgid "The wireless link between this device and its receiver is " #~ "not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices " #~ "(keyboards, numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties " #~ "within range." #~ msgstr "BežiÄ�na veza izmeÄ‘u ovog ureÄ‘aja i njegovog prijemnika nije " #~ "Å¡ifrovana.\n" #~ "\n" #~ "Za pokazivaÄ�ke ureÄ‘aje (miÅ¡evi, kuglice za pracÌ�enje, dodirne table) " #~ "ovo je manji bezbednosni problem.\n" #~ "MeÄ‘utim, to je glavni bezbednosni problem za ureÄ‘aje za unos teksta " #~ "(tastature, numeriÄ�ke podloge),\n" #~ "jer otkucani tekst mogu neprimetno da nanjuÅ¡e trecÌ�e strane u dometu" #~ msgid "Try removing the device and plugging it back in or turning " #~ "it off and then on." #~ msgstr "PokuÅ¡ajte da odspojite ureÄ‘aj i ponovo ga ukljuÄ�ite ili " #~ "iskljuÄ�ite, a zatimupalite." #~ msgid "unknown" #~ msgstr "nepoznato" Solaar-1.1.20/po/sv.po000066400000000000000000002060171522022367600144350ustar00rootroot00000000000000# Swedish translations for solaar package. # Copyright (C) 2013 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2013. # msgid "" msgstr "" "Project-Id-Version: solaar 1.0.3\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-12-01 21:43+0300\n" "PO-Revision-Date: 2026-04-21 21:46+0300\n" "Last-Translator: Karl Jonatan Nyberg\n" "Language-Team: none\n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Poedit-Basepath: /pwr/Solaar/po\n" "X-Generator: Poedit 3.6\n" "X-Poedit-SearchPath-0: /pwr/Solaar/po\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Bolt-mottagare" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Unifying-mottagare" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Nano-mottagare" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Lightspeed-mottagare" #: lib/logitech_receiver/base_usb.py:135 msgid "EX100 Receiver 27 Mhz" msgstr "EX100-mottagare 27 MHz" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Batteri: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Batteri: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1048 #: lib/logitech_receiver/settings_templates.py:299 msgid "Disabled" msgstr "Inaktiverad" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Static" msgstr "Statisk" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Pulse" msgstr "Pulsera" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Cycle" msgstr "Växla" #: lib/logitech_receiver/hidpp20.py:1052 msgid "Boot" msgstr "Boot" #: lib/logitech_receiver/hidpp20.py:1053 msgid "Demo" msgstr "Demo" #: lib/logitech_receiver/hidpp20.py:1055 msgid "Breathe" msgstr "Andas" #: lib/logitech_receiver/hidpp20.py:1058 msgid "Ripple" msgstr "Krusning" #: lib/logitech_receiver/hidpp20.py:1059 msgid "Decomposition" msgstr "Nedbrytning" #: lib/logitech_receiver/hidpp20.py:1060 msgid "Signature1" msgstr "Signatur1" #: lib/logitech_receiver/hidpp20.py:1061 msgid "Signature2" msgstr "Signatur2" #: lib/logitech_receiver/hidpp20.py:1062 msgid "CycleS" msgstr "CycleS" #: lib/logitech_receiver/hidpp20.py:1126 msgid "Unknown Location" msgstr "Okänd plats" #: lib/logitech_receiver/hidpp20.py:1127 msgid "Primary" msgstr "Primär" #: lib/logitech_receiver/hidpp20.py:1128 msgid "Logo" msgstr "Logotyp" #: lib/logitech_receiver/hidpp20.py:1129 msgid "Left Side" msgstr "Vänster sida" #: lib/logitech_receiver/hidpp20.py:1130 msgid "Right Side" msgstr "Höger sida" #: lib/logitech_receiver/hidpp20.py:1131 msgid "Combined" msgstr "Kombinerad" #: lib/logitech_receiver/hidpp20.py:1132 msgid "Primary 1" msgstr "Primär 1" #: lib/logitech_receiver/hidpp20.py:1133 msgid "Primary 2" msgstr "Primär 2" #: lib/logitech_receiver/hidpp20.py:1134 msgid "Primary 3" msgstr "Primär 3" #: lib/logitech_receiver/hidpp20.py:1135 msgid "Primary 4" msgstr "Primär 4" #: lib/logitech_receiver/hidpp20.py:1136 msgid "Primary 5" msgstr "Primär 5" #: lib/logitech_receiver/hidpp20.py:1137 msgid "Primary 6" msgstr "Primär 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "tom" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "kritisk" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "lÃ¥g" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "genomsnitt" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "god" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "full" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "urladdning" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "uppladdning" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "laddar" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "laddar inte" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "nästan full" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "laddad" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "lÃ¥ngsam laddning" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "batterifel" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "termiskt fel" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "fel" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "standard" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "snabb" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "lÃ¥ngsam" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "enheten svarade inte" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "enheten stöds inte" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "för mÃ¥nga enheter" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "tidsgräns för sekvens överskreds" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "Fast programvara" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Startladdare" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "HÃ¥rdvara" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Annan" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Vänster knapp" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Höger knapp" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Mittenknapp" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Tillbakaknapp" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "FramÃ¥tknapp" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Mus gestknapp" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Smart skift" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "DPI-växel" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Vänster lutning" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Höger lutning" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Vänsterklick" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Högerklick" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Mus mittenknapp" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Mus tillbakaknapp" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Mus framÃ¥tknapp" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Gestknapp navigering" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Vänster musrullningsknapp" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Höger musrullningsknapp" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "nedtryckt" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "släpptes" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "ansluten" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "frÃ¥nkopplad" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "inte parkopplad" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "pÃ¥slagen" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "ADC-mätningsmeddelande" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is closed" msgstr "parkopplingslÃ¥set är stängt" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is open" msgstr "parkopplingslÃ¥set är öppet" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is closed" msgstr "upptäcktslÃ¥set är stängt" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is open" msgstr "upptäcktslÃ¥set är öppet" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "Inga parkopplade enheter." #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s parkopplad enhet." msgstr[1] "%(count)s parkopplade enheter." #: lib/logitech_receiver/settings.py:602 msgid "register" msgstr "registrera" #: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654 msgid "feature" msgstr "funktion" #: lib/logitech_receiver/settings_templates.py:138 msgid "Swap Fx function" msgstr "Byt Fx-funktion" #: lib/logitech_receiver/settings_templates.py:141 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "När de är inställda kommer F1..F12-tangenterna att aktivera sin " "specialfunktion,\n" "och du mÃ¥ste hÃ¥lla ner FN-tangenten för att aktivera deras standardfunktion." #: lib/logitech_receiver/settings_templates.py:146 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "När de inte är inställda kommer F1..F12-tangenterna att aktivera sin " "standardfunktion,\n" "och du mÃ¥ste hÃ¥lla ner FN-tangenten för att aktivera deras specialfunktion." #: lib/logitech_receiver/settings_templates.py:154 msgid "Hand Detection" msgstr "Handavkänning" #: lib/logitech_receiver/settings_templates.py:155 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Tänd belysning när händerna hÃ¥lls över tangentbordet." #: lib/logitech_receiver/settings_templates.py:162 msgid "Scroll Wheel Smooth Scrolling" msgstr "Rullningshjul mjuk rullning" #: lib/logitech_receiver/settings_templates.py:163 #: lib/logitech_receiver/settings_templates.py:410 #: lib/logitech_receiver/settings_templates.py:439 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Högkänsligt läge för vertikal rullning med hjulet." #: lib/logitech_receiver/settings_templates.py:170 msgid "Side Scrolling" msgstr "Sidrullning" #: lib/logitech_receiver/settings_templates.py:172 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Vid inaktivering skickas anpassade knapphändelser om du trycker pÃ¥ hjulet i " "sidled\n" "istället för standardhändelserna för sidrullning." #: lib/logitech_receiver/settings_templates.py:182 msgid "Sensitivity (DPI - older mice)" msgstr "Känslighet (DPI - äldre möss)" #: lib/logitech_receiver/settings_templates.py:183 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 msgid "Mouse movement sensitivity" msgstr "Musrörelsekänslighet" #: lib/logitech_receiver/settings_templates.py:256 msgid "Backlight Timed" msgstr "Bakgrundsbelysning tidsinställd" #: lib/logitech_receiver/settings_templates.py:257 #: lib/logitech_receiver/settings_templates.py:397 msgid "Set illumination time for keyboard." msgstr "Ställ in belysningstid för tangentbordet." #: lib/logitech_receiver/settings_templates.py:268 msgid "Backlight" msgstr "Bakbelysning" #: lib/logitech_receiver/settings_templates.py:269 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "BelysningsnivÃ¥ pÃ¥ tangentbordet. Ändringar som görs tillämpas endast i " "manuellt läge." #: lib/logitech_receiver/settings_templates.py:301 msgid "Automatic" msgstr "Automatiskt" #: lib/logitech_receiver/settings_templates.py:303 msgid "Manual" msgstr "Manuellt" #: lib/logitech_receiver/settings_templates.py:305 msgid "Enabled" msgstr "Aktiverad" #: lib/logitech_receiver/settings_templates.py:311 msgid "Backlight Level" msgstr "BakgrundsbelysningsnivÃ¥" #: lib/logitech_receiver/settings_templates.py:312 msgid "Illumination level on keyboard when in Manual mode." msgstr "BelysningsnivÃ¥ pÃ¥ tangentbordet i manuellt läge." #: lib/logitech_receiver/settings_templates.py:369 msgid "Backlight Delay Hands Out" msgstr "Fördröjning av bakgrundsbelysning händer ute" #: lib/logitech_receiver/settings_templates.py:370 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Fördröjning i sekunder tills bakgrundsbelysningen tonar ut när händerna tas " "bort frÃ¥n tangentbordet." #: lib/logitech_receiver/settings_templates.py:378 msgid "Backlight Delay Hands In" msgstr "Fördröjning av bakgrundsbelysning händer inne" #: lib/logitech_receiver/settings_templates.py:379 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Fördröjning i sekunder tills bakgrundsbelysningen tonar ut när händerna är " "nära tangentbordet." #: lib/logitech_receiver/settings_templates.py:387 msgid "Backlight Delay Powered" msgstr "Fördröjning av bakgrundsbelysning extern ström" #: lib/logitech_receiver/settings_templates.py:388 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Fördröjning i sekunder tills bakgrundsbelysningen tonar ut med extern " "strömförsörjning." #: lib/logitech_receiver/settings_templates.py:396 msgid "Backlight (Seconds)" msgstr "Bakgrundsbelysning (sekunder)" #: lib/logitech_receiver/settings_templates.py:408 msgid "Scroll Wheel High Resolution" msgstr "Rullningshjul hög upplösning" #: lib/logitech_receiver/settings_templates.py:412 #: lib/logitech_receiver/settings_templates.py:441 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Ställ in att ignorera om rullningen är onormalt snabb eller lÃ¥ngsam" #: lib/logitech_receiver/settings_templates.py:419 #: lib/logitech_receiver/settings_templates.py:450 msgid "Scroll Wheel Diversion" msgstr "Rullhjulsavledning" #: lib/logitech_receiver/settings_templates.py:421 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "FÃ¥ rullhjulet att skicka LOWRES_WHEEL HID++-aviseringar (som utlöser Solaar-" "regler men som annars ignoreras)." #: lib/logitech_receiver/settings_templates.py:428 msgid "Scroll Wheel Direction" msgstr "Rullhjulets riktning" #: lib/logitech_receiver/settings_templates.py:429 msgid "Invert direction for vertical scroll with wheel." msgstr "Invertera riktning för vertikal rullning med hjul." #: lib/logitech_receiver/settings_templates.py:437 msgid "Scroll Wheel Resolution" msgstr "Rullhjulsupplösning" #: lib/logitech_receiver/settings_templates.py:452 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "FÃ¥ rullhjulet att skicka HIRES_WHEEL HID++-aviseringar (som utlöser Solaar-" "regler men som annars ignoreras)." #: lib/logitech_receiver/settings_templates.py:461 msgid "Sensitivity (Pointer Speed)" msgstr "Känslighet (pekarhastighet)" #: lib/logitech_receiver/settings_templates.py:462 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Hastighetsmultiplikator för mus (256 är normal multiplikator)." #: lib/logitech_receiver/settings_templates.py:472 msgid "Thumb Wheel Diversion" msgstr "Tumhjulsavledning" #: lib/logitech_receiver/settings_templates.py:474 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "FÃ¥ tumhjulet att skicka THUMB_WHEEL HID++-aviseringar (som utlöser Solaar-" "regler men som annars ignoreras)." #: lib/logitech_receiver/settings_templates.py:483 msgid "Thumb Wheel Direction" msgstr "Tumhjulets riktning" #: lib/logitech_receiver/settings_templates.py:484 msgid "Invert thumb wheel scroll direction." msgstr "Invertera tumhjulets rullningsriktning." #: lib/logitech_receiver/settings_templates.py:504 msgid "Onboard Profiles" msgstr "Inbyggda profiler" #: lib/logitech_receiver/settings_templates.py:505 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Aktivera en inbyggd profil som styr rapporteringsfrekvens, känslighet och " "knappfunktioner" #: lib/logitech_receiver/settings_templates.py:549 #: lib/logitech_receiver/settings_templates.py:582 msgid "Report Rate" msgstr "Rapporteringsfrekvens" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 msgid "Frequency of device movement reports" msgstr "Frekvens för rapporter om enhetsrörelser" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1421 #: lib/logitech_receiver/settings_templates.py:1452 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "Kan kräva att inbyggda profiler är inställda pÃ¥ inaktiverade för att fungera." #: lib/logitech_receiver/settings_templates.py:612 msgid "Divert crown events" msgstr "Avled kronhändelser" #: lib/logitech_receiver/settings_templates.py:613 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "FÃ¥ kronan att skicka CROWN HID++-meddelanden (som utlöser Solaar-regler men " "annars ignoreras)." #: lib/logitech_receiver/settings_templates.py:621 msgid "Crown smooth scroll" msgstr "Kronans mjuka rullning" #: lib/logitech_receiver/settings_templates.py:622 msgid "Set crown smooth scroll" msgstr "Ställ in kronans mjuka rullning" #: lib/logitech_receiver/settings_templates.py:630 msgid "Divert G and M Keys" msgstr "Omdirigera G- och M-tangenterna" #: lib/logitech_receiver/settings_templates.py:631 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "FÃ¥ tangenterna G och M att skicka HID++-meddelanden (som aktiverar Solaar-" "regler men annars ignoreras)." #: lib/logitech_receiver/settings_templates.py:645 msgid "Scroll Wheel Ratcheted" msgstr "Rullningshjul spärrat" #: lib/logitech_receiver/settings_templates.py:646 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Växla mushjulet mellan hastighetskontrollerad spärrning och alltid fri snurr." #: lib/logitech_receiver/settings_templates.py:648 msgid "Freespinning" msgstr "Fri snurrning" #: lib/logitech_receiver/settings_templates.py:648 msgid "Ratcheted" msgstr "Spärrad" #: lib/logitech_receiver/settings_templates.py:655 msgid "Scroll Wheel Ratchet Speed" msgstr "Rullningshjulets spärrhastighet" #: lib/logitech_receiver/settings_templates.py:657 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Använd mushjulets hastighet för att växla mellan spärrad och fri snurrning.\n" "Mushjulet är alltid spärrat till 50." #: lib/logitech_receiver/settings_templates.py:707 msgid "Scroll Wheel Ratchet Torque" msgstr "Vridmoment för rullhjulsspärr" #: lib/logitech_receiver/settings_templates.py:708 msgid "Change the torque needed to overcome the ratchet." msgstr "Ändra vridmomentet som behövs för att övervinna spärren." #: lib/logitech_receiver/settings_templates.py:743 msgid "Key/Button Actions" msgstr "Tangent-/knappÃ¥tgärder" #: lib/logitech_receiver/settings_templates.py:745 msgid "Change the action for the key or button." msgstr "Ändra Ã¥tgärden för tangenten eller knappen." #: lib/logitech_receiver/settings_templates.py:747 msgid "Overridden by diversion." msgstr "Ã…sidosatt av avledning." #: lib/logitech_receiver/settings_templates.py:749 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Ändring av viktiga Ã¥tgärder (som för vänster musknapp) kan resultera i ett " "oanvändbart system." #: lib/logitech_receiver/settings_templates.py:924 msgid "Key/Button Diversion" msgstr "Tangent/knapp avledning" #: lib/logitech_receiver/settings_templates.py:925 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "FÃ¥ tangenten eller knappen att skicka HID++-aviseringar (vidarekopplade) " "eller initiera musgester eller glidande DPI" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Diverted" msgstr "Avledd" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 msgid "Mouse Gestures" msgstr "Musgester" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Regular" msgstr "Regelbunden" #: lib/logitech_receiver/settings_templates.py:928 msgid "Sliding DPI" msgstr "Glidande DPI" #: lib/logitech_receiver/settings_templates.py:1018 #: lib/logitech_receiver/settings_templates.py:1046 msgid "Sensitivity (DPI)" msgstr "Känslighet (DPI)" #: lib/logitech_receiver/settings_templates.py:1123 msgid "Sensitivity Switching" msgstr "Känslighetsväxling" #: lib/logitech_receiver/settings_templates.py:1125 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Växla den aktuella känsligheten och den ihÃ¥gkomna känsligheten när knappen " "eller knappen trycks ned.\n" "Om det inte finns nÃ¥gon ihÃ¥gkommen känslighet, kom ihÃ¥g bara den aktuella " "känsligheten" #: lib/logitech_receiver/settings_templates.py:1129 msgid "Off" msgstr "Av" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Disable keys" msgstr "Inaktivera tangenter" #: lib/logitech_receiver/settings_templates.py:1161 msgid "Disable specific keyboard keys." msgstr "Inaktivera specifika tangentbordstangenter." #: lib/logitech_receiver/settings_templates.py:1164 #, python-format msgid "Disables the %s key." msgstr "Inaktiverar tangenten %s." #: lib/logitech_receiver/settings_templates.py:1177 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Set OS" msgstr "Ställ in OS" #: lib/logitech_receiver/settings_templates.py:1178 #: lib/logitech_receiver/settings_templates.py:1235 msgid "Change keys to match OS." msgstr "Ändra tangenter för att matcha OS." #: lib/logitech_receiver/settings_templates.py:1247 msgid "Change Host" msgstr "Byt värd" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Switch connection to a different host" msgstr "Byt anslutning till en annan värd" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Performs a left click." msgstr "Utför ett vänsterklick." #: lib/logitech_receiver/settings_templates.py:1272 msgid "Single tap" msgstr "Enkelt tryck" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Performs a right click." msgstr "Utför ett högerklick." #: lib/logitech_receiver/settings_templates.py:1273 msgid "Single tap with two fingers" msgstr "Enkelt tryck med tvÃ¥ fingrar" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Single tap with three fingers" msgstr "Enkelt tryck med tre fingrar" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Double tap" msgstr "Dubbeltryck" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Performs a double click." msgstr "Utför ett dubbelklick." #: lib/logitech_receiver/settings_templates.py:1279 msgid "Double tap with two fingers" msgstr "Dubbeltryck med tvÃ¥ fingrar" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Double tap with three fingers" msgstr "Dubbeltryck med tre fingrar" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Drags items by dragging the finger after double tapping." msgstr "Dra objekt genom att dra fingret efter att ha dubbelklickat." #: lib/logitech_receiver/settings_templates.py:1283 msgid "Tap and drag" msgstr "Tryck och dra" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Tap and drag with two fingers" msgstr "Tryck och dra med tvÃ¥ fingrar" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Drags items by dragging the fingers after double tapping." msgstr "Dra objekt genom att dra fingrarna efter att du dubbelklickat." #: lib/logitech_receiver/settings_templates.py:1288 msgid "Tap and drag with three fingers" msgstr "Tryck och dra med tre fingrar" #: lib/logitech_receiver/settings_templates.py:1291 msgid "Suppress tap and edge gestures" msgstr "Inaktivera tryck- och kantgester" #: lib/logitech_receiver/settings_templates.py:1292 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "Inaktiverade tryck- och kantgester (motsvarar att trycka pÃ¥ Fn+vänsterklick)." #: lib/logitech_receiver/settings_templates.py:1294 msgid "Scroll with one finger" msgstr "Bläddra med ett finger" #: lib/logitech_receiver/settings_templates.py:1294 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scrolls." msgstr "Rullningar." #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scroll with two fingers" msgstr "Rulla med tvÃ¥ fingrar" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scroll horizontally with two fingers" msgstr "Rulla horisontellt med tvÃ¥ fingrar" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scrolls horizontally." msgstr "Rullar horisontellt." #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scroll vertically with two fingers" msgstr "Rulla vertikalt med tvÃ¥ fingrar" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scrolls vertically." msgstr "Rullar vertikalt." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Inverts the scrolling direction." msgstr "Inverterar rullningsriktningen." #: lib/logitech_receiver/settings_templates.py:1299 msgid "Natural scrolling" msgstr "Naturlig rullning" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Enables the thumbwheel." msgstr "Aktiverar tumhjulet." #: lib/logitech_receiver/settings_templates.py:1300 msgid "Thumbwheel" msgstr "Tumhjul" #: lib/logitech_receiver/settings_templates.py:1311 #: lib/logitech_receiver/settings_templates.py:1315 msgid "Swipe from the top edge" msgstr "Svep frÃ¥n den övre kanten" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Swipe from the left edge" msgstr "Svep frÃ¥n vänstra kanten" #: lib/logitech_receiver/settings_templates.py:1313 msgid "Swipe from the right edge" msgstr "Svep frÃ¥n den högra kanten" #: lib/logitech_receiver/settings_templates.py:1314 msgid "Swipe from the bottom edge" msgstr "Svep frÃ¥n den nedre kanten" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Swipe two fingers from the left edge" msgstr "Svep tvÃ¥ fingrar frÃ¥n den vänstra kanten" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Swipe two fingers from the right edge" msgstr "Svep tvÃ¥ fingrar frÃ¥n den högra kanten" #: lib/logitech_receiver/settings_templates.py:1318 msgid "Swipe two fingers from the bottom edge" msgstr "Svep tvÃ¥ fingrar frÃ¥n den nedre kanten" #: lib/logitech_receiver/settings_templates.py:1319 msgid "Swipe two fingers from the top edge" msgstr "Svep tvÃ¥ fingrar frÃ¥n den övre kanten" #: lib/logitech_receiver/settings_templates.py:1320 #: lib/logitech_receiver/settings_templates.py:1324 msgid "Pinch to zoom out; spread to zoom in." msgstr "Nyp för att zooma ut; sprid för att zooma in." #: lib/logitech_receiver/settings_templates.py:1320 msgid "Zoom with two fingers." msgstr "Zooma med tvÃ¥ fingrar." #: lib/logitech_receiver/settings_templates.py:1321 msgid "Pinch to zoom out." msgstr "Nyp för att zooma ut." #: lib/logitech_receiver/settings_templates.py:1322 msgid "Spread to zoom in." msgstr "Sprid för att zooma in." #: lib/logitech_receiver/settings_templates.py:1323 msgid "Zoom with three fingers." msgstr "Zooma med tre fingrar." #: lib/logitech_receiver/settings_templates.py:1324 msgid "Zoom with two fingers" msgstr "Zooma med tvÃ¥ fingrar" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Pixel zone" msgstr "Pixelzon" #: lib/logitech_receiver/settings_templates.py:1343 msgid "Ratio zone" msgstr "Ratiozon" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scale factor" msgstr "Skalfaktor" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Sets the cursor speed." msgstr "Ställer in markörhastigheten." #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left" msgstr "Vänster" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left-most coordinate." msgstr "Koordinaten längst till vänster." #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom" msgstr "Nedre" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom coordinate." msgstr "Nedre koordinat." #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width" msgstr "Bredd" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width." msgstr "Bredd." #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height" msgstr "Höjd" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height." msgstr "Höjd." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Cursor speed." msgstr "Markörhastighet." #: lib/logitech_receiver/settings_templates.py:1352 msgid "Scale" msgstr "Skala" #: lib/logitech_receiver/settings_templates.py:1358 msgid "Gestures" msgstr "Gester" #: lib/logitech_receiver/settings_templates.py:1359 msgid "Tweak the mouse/touchpad behaviour." msgstr "Justera musens/pekplattans beteende." #: lib/logitech_receiver/settings_templates.py:1375 msgid "Gestures Diversion" msgstr "Avledning av gester" #: lib/logitech_receiver/settings_templates.py:1376 msgid "Divert mouse/touchpad gestures." msgstr "Avleda mus-/pekplattagester." #: lib/logitech_receiver/settings_templates.py:1392 msgid "Gesture params" msgstr "Gestparametrar" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Ändra numeriska parametrar för en mus/pekplatta." #: lib/logitech_receiver/settings_templates.py:1417 msgid "M-Key LEDs" msgstr "M-Key LED:ar" #: lib/logitech_receiver/settings_templates.py:1419 msgid "Control the M-Key LEDs." msgstr "Styr M-Key LED:ar." #: lib/logitech_receiver/settings_templates.py:1423 #: lib/logitech_receiver/settings_templates.py:1454 msgid "May need G Keys diverted to be effective." msgstr "Kan behöva omdirigera G-tangenter för att vara effektiva." #: lib/logitech_receiver/settings_templates.py:1429 #, python-format msgid "Lights up the %s key." msgstr "Lyser upp tangenten %s." #: lib/logitech_receiver/settings_templates.py:1448 msgid "MR-Key LED" msgstr "MR-Key LED" #: lib/logitech_receiver/settings_templates.py:1450 msgid "Control the MR-Key LED." msgstr "Styr MR-Key LED." #: lib/logitech_receiver/settings_templates.py:1471 msgid "Persistent Key/Button Mapping" msgstr "IhÃ¥llande nyckel/knappkartläggning" #: lib/logitech_receiver/settings_templates.py:1473 msgid "Permanently change the mapping for the key or button." msgstr "Ändra kartläggningen för nyckeln eller knappen permanent." #: lib/logitech_receiver/settings_templates.py:1475 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Att ändra viktiga tangenter eller knappar (som för vänster musknapp) kan " "resultera i ett oanvändbart system." #: lib/logitech_receiver/settings_templates.py:1532 msgid "Sidetone" msgstr "Sidoton" #: lib/logitech_receiver/settings_templates.py:1533 msgid "Set sidetone level." msgstr "Ställ in sidotonsnivÃ¥." #: lib/logitech_receiver/settings_templates.py:1542 msgid "Equalizer" msgstr "Utjämnare" #: lib/logitech_receiver/settings_templates.py:1543 msgid "Set equalizer levels." msgstr "Ställ in utjämningsnivÃ¥er." #: lib/logitech_receiver/settings_templates.py:1565 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1571 msgid "Power Management" msgstr "Strömhantering" #: lib/logitech_receiver/settings_templates.py:1572 msgid "Power off in minutes (0 for never)." msgstr "Stäng av pÃ¥ nÃ¥gra minuter (0 för aldrig)." #: lib/logitech_receiver/settings_templates.py:1584 msgid "Brightness Control" msgstr "Ljusstyrkekontroll" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Control overall brightness" msgstr "Kontrollera allmän ljusstyrka" #: lib/logitech_receiver/settings_templates.py:1628 #: lib/logitech_receiver/settings_templates.py:1681 msgid "LED Control" msgstr "LED-kontroll" #: lib/logitech_receiver/settings_templates.py:1629 #: lib/logitech_receiver/settings_templates.py:1682 msgid "Switch control of LED zones between device and Solaar" msgstr "Växla styrning av LED-zoner mellan enhet och Solaar" #: lib/logitech_receiver/settings_templates.py:1644 #: lib/logitech_receiver/settings_templates.py:1692 msgid "LED Zone Effects" msgstr "LED-zoneffekter" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "LED Control needs to be set to Solaar to be effective." msgstr "LED-kontrollen mÃ¥ste ställas in pÃ¥ Solaar för att fungera." #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "Set effect for LED Zone" msgstr "Ställ in effekt för LED-zon" #: lib/logitech_receiver/settings_templates.py:1647 msgid "Color" msgstr "Färg" #: lib/logitech_receiver/settings_templates.py:1648 msgid "Speed" msgstr "Hastighet" #: lib/logitech_receiver/settings_templates.py:1649 msgid "Period" msgstr "Period" #: lib/logitech_receiver/settings_templates.py:1650 msgid "Intensity" msgstr "Intensitet" #: lib/logitech_receiver/settings_templates.py:1651 msgid "Ramp" msgstr "Ramp" #: lib/logitech_receiver/settings_templates.py:1666 msgid "LEDs" msgstr "LED" #: lib/logitech_receiver/settings_templates.py:1703 msgid "Per-key Lighting" msgstr "Belysning per tangent" #: lib/logitech_receiver/settings_templates.py:1704 msgid "Control per-key lighting." msgstr "Kontrollera belysning per tangent." #: lib/logitech_receiver/settings_templates.py:1786 msgid "Force Sensing Buttons" msgstr "Kraftavkännande knappar" #: lib/logitech_receiver/settings_templates.py:1787 msgid "Change the force required to activate button." msgstr "Ändra den kraft som krävs för att aktivera knappen." #: lib/logitech_receiver/settings_templates.py:1804 msgid "Force Sensing Button" msgstr "Kraftavkännande knapp" #: lib/logitech_receiver/settings_templates.py:1814 msgid "Haptic Feeback Level" msgstr "Haptisk Ã¥terkopplingsnivÃ¥" #: lib/logitech_receiver/settings_templates.py:1815 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "" "Ändra styrkan pÃ¥ den haptiska Ã¥terkopplingen. (Noll för att stänga av.)" #: lib/logitech_receiver/settings_templates.py:1857 msgid "Play Haptic Waveform" msgstr "Spela upp haptisk vÃ¥gform" #: lib/logitech_receiver/settings_templates.py:1858 msgid "Tell device to play a haptic waveform." msgstr "Be enheten att spela upp en haptisk vÃ¥gform." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "En annan Solaar-process körs redan sÃ¥ bara exponera dess fönster" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Hanterar Logitech-mottagare,\n" "tangentbord, möss och surfplattor." #: lib/solaar/ui/about/model.py:63 msgid "Additional Programming" msgstr "Ytterligare programmering" #: lib/solaar/ui/about/model.py:64 msgid "GUI design" msgstr "Grafisk design av användargränssnitt" #: lib/solaar/ui/about/model.py:66 msgid "Testing" msgstr "Testning" #: lib/solaar/ui/about/model.py:74 msgid "Logitech documentation" msgstr "Logitech-dokumentation" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Bryt parkoppling" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "Avbryt" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Behörighetsfel" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Hittade en Logitech-mottagare eller enhet (%s), men hade inte behörighet att " "öppna den." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Om du precis har installerat Solaar, försök att koppla bort mottagaren eller " "enheten och sedan Ã¥teransluta den." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Kan inte ansluta till enhet-fel" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Hittade en Logitech-mottagare eller enhet pÃ¥ %s, men stötte pÃ¥ ett fel vid " "anslutning till den." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Försök att koppla bort enheten och sedan Ã¥teransluta den eller stänga av och " "sedan pÃ¥ den." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "Kunde inte bryta parkoppling" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Misslyckades att bryta parkoppling mellan %{device} och %{receiver}." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Mottagaren rapporterade ett fel, utan ytterligare detaljer." #: lib/solaar/ui/config_panel.py:245 msgid "Complete - ENTER to change" msgstr "Komplett - ENTER för att ändra" #: lib/solaar/ui/config_panel.py:245 msgid "Incomplete" msgstr "Ofullständig" #: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d värde" msgstr[1] "%d värden" #: lib/solaar/ui/config_panel.py:642 msgid "Changes allowed" msgstr "Ändringar tillÃ¥tna" #: lib/solaar/ui/config_panel.py:643 msgid "No changes allowed" msgstr "Inga ändringar tillÃ¥tna" #: lib/solaar/ui/config_panel.py:644 msgid "Ignore this setting" msgstr "Ignorera denna inställning" #: lib/solaar/ui/config_panel.py:690 msgid "Working" msgstr "Fungerar" #: lib/solaar/ui/config_panel.py:693 msgid "Read/write operation failed." msgstr "Läs-/skrivoperationen misslyckades." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "ospecificerad anledning" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "Inbyggda regler" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "Användardefinierade regler" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "Regel" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "Underregel" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "[tom]" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "Göra ändringarna permanenta?" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "Ja" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "Nej" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Om du väljer Nej kommer ändringar att gÃ¥ förlorade när Solaar stängs." #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "Klistra in här" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "Klistra in ovan" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "Klistra in nedan" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "Klistra in regeln här" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "Klistra in regeln ovan" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "Klistra in regeln nedan" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "Klistra in regel" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "Infoga här" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "Infoga ovan" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "Infoga nedan" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "Infoga ny regel här" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "Infoga ny regel ovan" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "Infoga ny regel nedan" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "Platta till" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "Infoga" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "Eller" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "Och" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "Villkor" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "Funktion" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Rapport" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "Process" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "Musprocess" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Modifierare" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Tangent" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "KeyIsDown" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "Aktiv" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "Enhet" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "Värd" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "Inställning" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "Testa" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "Testa byte" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "Musgest" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "Ã…tgärd" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "Knapptryckning" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "Musrullning" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "Musklick" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "Ställ in" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "Utför" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "Senare" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "Infoga ny regel" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Ta bort" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "Negera" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "Omslut med" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "Klipp ut" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "Klistra in" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "Kopiera" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "Solaar regelredigerare" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "Spara ändringar" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "Släng ändringar" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "Denna redigerare stöder inte den valda regelkomponenten ännu." #: lib/solaar/ui/diversion_rules.py:1169 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Antal sekunder att fördröja. Fördröjning mellan 0 och 1 görs med högre " "precision." #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "Inte" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "Växla" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "Sant" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "Falskt" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "Inställning som inte stöds" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "Ursprungsenhet" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "Enheten är aktiv och dess inställningar kan ändras." #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "Enhet som skapade det aktuella meddelandet." #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "Namn pÃ¥ värddator." #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "Värde" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "Objekt" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "Ändra inställning pÃ¥ enheten" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "Inställning pÃ¥ enheten" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: parkoppla ny enhet" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt-mottagare är endast kompatibla med Bolt-enheter." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Tryck pÃ¥ en parkopplingstangent eller -knapp tills parkopplingslampan " "blinkar snabbt." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Unifying-mottagare är endast kompatibla med Unifying-enheter." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "Andra mottagare är endast kompatibla med ett fÃ¥tal enheter." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "För de flesta enheter, slÃ¥ pÃ¥ den enhet du vill para ihop." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "Om enheten redan är pÃ¥slagen, stäng av och sätt pÃ¥ den igen." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "Enheten fÃ¥r inte parkopplas med en närliggande pÃ¥slagen mottagare." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "För enheter med flera kanaler, tryck, hÃ¥ll ned och släpp knappen för den " "kanal du vill para ihop eller använd\n" "kanalväxlingsknappen för att välja en kanal och tryck sedan, hÃ¥ll ned och " "släpp kanalväxlingsknappen." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Lampan för kanalindikator ska blinka snabbt." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Denna mottagare har %d parkoppling kvar." msgstr[1] "" "\n" "\n" "Denna mottagare har %d parkopplingar kvar." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Avbrytning vid detta tillfälle kommer inte att förbruka en parkoppling." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Ange lösenkoden pÃ¥ %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Skriv %(passcode)s och tryck sedan pÃ¥ enter-tangenten." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "vänster" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "höger" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Tryck pÃ¥ %(code)s\n" "och tryck sedan pÃ¥ vänster och höger knappar samtidigt." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "Den trÃ¥dlösa anslutningen är inte krypterad" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Hittade en ny enhet:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Parkoppling misslyckades" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Se till att din enhet är inom räckhÃ¥ll och har tillräckligt laddat batteri." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "" "En ny enhet upptäcktes, men den är inte kompatibel med denna mottagare." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "Fler parkopplade enheter än vad mottagaren kan stöda." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Inga ytterligare detaljer finns tillgängliga om felet." #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simulera ett ackorderat tangentklick eller tryck ner eller släpp.\n" "I Wayland krävs skrivÃ¥tkomst till /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Lägg till tangent" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Klick" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Tryck ned" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "Släppa" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simulera en musrullning.\n" "I Wayland krävs skrivÃ¥tkomst till /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Simulera ett musklick.\n" "I Wayland krävs skrivÃ¥tkomst till /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Knapp" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "Ã…tgärd (och räkna, om klick)" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "Utför ett kommando med argument." #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "Lägg till argument" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "X11 aktiv process. Endast för användning i X11." #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "X11 musprocess. Endast för användning i X11." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "MouseProcess" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "Funktionsnamn för avisering som utlöser regelbearbetning." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "Rapportnummer för avisering som utlöser regelbearbetning." #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Aktiva tangentbordsmodifierare. Inte alltid tillgängligt i Wayland." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Omdirigerad knapp eller knapp nedtryckt eller släppt.\n" "Använd inställningarna för vidarekoppling av tangent/knapp och " "vidarekoppling av G-tangenter för att vidarekoppla tangenter och knappar." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Tangent ner" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Tangent upp" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Vidarekopplad nyckel eller knapp är för närvarande nere.\n" "Använd inställningarna för vidarekoppling av tangent/knapp och " "vidarekoppling av G-tangenter för att vidarekoppla tangenter och knappar." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "Testvillkor för meddelande som utlöser regelbearbetning." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Parameter" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "börja (inklusive)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "slut (exklusivt)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "omfÃ¥ng" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "minimum" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "maximum" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "byte %(0)d till %(1)d, frÃ¥n %(2)d till %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "mask" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "byte %(0)d till %(1)d, mask %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Bit- eller omfÃ¥ngstest pÃ¥ byte i aviseringsmeddelande som utlöser " "regelbearbetning." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "typ" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Musgest med valfri initieringsknapp följt av noll eller fler musrörelser." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Lägg till rörelse" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Ingen enhet som stöds hittades" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "Om %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Avsluta %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "ingen mottagare" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:728 msgid "offline" msgstr "frÃ¥nkopplad" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "ingen status" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "Skannar" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "Batteri" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "TrÃ¥dlös anslutning" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "Belysning" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Visa tekniska detaljer" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Parkoppla ny enhet" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Välj en enhet" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Regelredigerare" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "Sökväg" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "USB-ID" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546 msgid "Serial" msgstr "Seriell" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "Index" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "TrÃ¥dlös-PID" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "Produkt-ID" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "Protokoll" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "Okänd" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "Uppdateringshastighet" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "Enhets-ID" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "ingen" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "Aviseringar" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "Ingen enhet parkopplad." #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "Upp till %(max_count)s enhet kan parkopplas med denna mottagare." msgstr[1] "Upp till %(max_count)s enheter kan parkopplas med denna mottagare." #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "Endast en enhet kan parkopplas ihop med denna mottagare." #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Denna mottagare har %d parkoppling kvar." msgstr[1] "Denna mottagare har %d parkopplingar kvar." #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "Batterispänning" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "Spänning rapporterad av batteri" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "BatterinivÃ¥" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "Ungefärlig nivÃ¥ rapporterad av batteriet" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "nästa rapporterade " #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr " och nästa nivÃ¥ som ska rapporteras." #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "senast kända" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "krypterad" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "" "Den trÃ¥dlösa anslutningen mellan denna enheten och dess mottagare är " "krypterad." #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "inte krypterad" #: lib/solaar/ui/window.py:721 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "Den trÃ¥dlösa anslutningen mellan den här enheten och dess mottagare är inte " "krypterad.\n" "Detta är ett säkerhetsproblem för pekdon och ett stort säkerhetsproblem för " "enheter för textinmatning." #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" #~ msgid "Turn illumination on or off on keyboard." #~ msgstr "SlÃ¥ pÃ¥ eller stäng av belysningen pÃ¥ tangentbordet." #~ msgid "" #~ "Enable onboard profiles, which often control report rate and keyboard " #~ "lighting" #~ msgstr "" #~ "Aktivera inbyggda profiler, som ofta styr rapporthastighet och " #~ "tangentbordsbelysning" #~ msgid "Polling Rate (ms)" #~ msgstr "Uppdateringsfrekvens (ms)" #~ msgid "Frequency of device polling, in milliseconds" #~ msgstr "Frekvens för enhetsavfrÃ¥gning, i millisekunder" #~ msgid "Divert G Keys" #~ msgstr "Avleda G-tangenter" #~ msgid "" #~ "Make G keys send GKEY HID++ notifications (which trigger Solaar rules but " #~ "are otherwise ignored)." #~ msgstr "" #~ "FÃ¥ G-tangenter att skicka GKEY HID++-aviseringar (som utlöser Solaar-" #~ "regler men som annars ignoreras)." #~ msgid "May also make M keys and MR key send HID++ notifications" #~ msgstr "" #~ "Kan ocksÃ¥ fÃ¥ M-tangenter och MR-tangenten att skicka HID++-aviseringar" #, python-format #~ msgid "Battery: %(level)s" #~ msgstr "Batteri: %(level)s" #, python-format #~ msgid "Battery: %(percent)d%%" #~ msgstr "Batteri: %(percent)d%%" #, python-format #~ msgid "Lighting: %(level)s lux" #~ msgstr "Belysning: %(level)s lux" #~ msgid "Number of seconds to delay." #~ msgstr "Antal sekunder att fördröja." #~ msgid "Count and Action" #~ msgstr "Antal och Ã¥tgärd" #~ msgid "You may have to first turn the device off and on again." #~ msgstr "Du kanske först mÃ¥ste stänga av enheten och slÃ¥ pÃ¥ den igen." #~ msgid "Turn on the device you want to pair." #~ msgstr "SlÃ¥ pÃ¥ enheten du vill parkoppla." #, python-format #~ msgid "%(rate)d ms (%(rate_hz)dHz)" #~ msgstr "%(rate)d ms (%(rate_hz)dHz)" #~ msgid "" #~ "\n" #~ "\n" #~ "This receiver has %d pairing(s) remaining." #~ msgstr "" #~ "\n" #~ "\n" #~ "Denna mottagare har %d parning(er) kvar." #~ msgid " paired devices." #~ msgstr "parkopplade enheter." #~ msgid "%(battery_level)s" #~ msgstr "%(battery_level)s" #~ msgid "%(battery_percent)d%%" #~ msgstr "%(battery_percent)d%%" #~ msgid "1 paired device." #~ msgstr "1 parkopplad enhet." #~ msgid "Actions" #~ msgstr "Ã…tgärder" #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always locked at 50" #~ msgstr "" #~ "Växla automatiskt mushjulet mellan spärr- och frispinn-läge.\n" #~ "Mushjulet är alltid fritt vid 0 och lÃ¥ses alltid vid 50" #~ msgid "Count" #~ msgstr "Antal" #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "Stänger effektivt av tumrullning i Linux." #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "Stänger effektivt av rullning i Linux." #~ msgid "" #~ "For more information see the Solaar installation directions\n" #~ "at https://pwr-solaar.github.io/Solaar/installation" #~ msgstr "" #~ "Mer information finns i Solaar-installationsanvisningarna\n" #~ "pÃ¥ https://pwr-solaar.github.io/Solaar/installation" #, python-format #~ msgid "" #~ "Found a Logitech Receiver (%s), but did not have permission to open it." #~ msgstr "" #~ "En Logitech mottagare hittades (%s), fast saknar behörighet till att " #~ "öppna den." #~ msgid "Found a new device" #~ msgstr "Ny enhet har hittats" #~ msgid "HID++ Scrolling" #~ msgstr "HID++ rullning" #~ msgid "HID++ Thumb Scrolling" #~ msgstr "HID++ thumrullning" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "HID ++ -läge för horisontell rullning med tumhjulet." #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "HID++ läge för vertikal rullning med hjulet." #~ msgid "High Resolution Scrolling" #~ msgstr "Rullning med hög upplösning" #~ msgid "High Resolution Wheel Invert" #~ msgstr "Invertera hög hjulupplösning" #~ msgid "High-sensitivity wheel invert direction for vertical scroll." #~ msgstr "Invertera riktning för vertikal rullning med hög känslighet." #~ msgid "High-sensitivity wheel invert mode for vertical scroll." #~ msgstr "Inverteringsläge med hög känslighet för vertikal rullning." #~ msgid "" #~ "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "" #~ "Om enheten redan är igÃ¥ng,\n" #~ "stäng av den och sätt pÃ¥ den igen." #~ msgid "If the device is already turned on, turn if off and on again." #~ msgstr "Om enheten redan är pÃ¥slagen, stäng av og slÃ¥ den pÃ¥ igen." #~ msgid "" #~ "If you've just installed Solaar, try removing the receiver and plugging " #~ "it back in." #~ msgstr "" #~ "Om du just installerade solaar, prova koppla ur mottagaren och anslut den " #~ "sedan igen." #~ msgid "Invert thumb scroll direction." #~ msgstr "Invertera tumrulleriktningen." #~ msgid "No Logitech receiver found" #~ msgstr "Ingen Logitech mottagare hittades" #~ msgid "No device paired" #~ msgstr "Inga enheter parkopplade" #~ msgid "Only one device can be paired to this receiver" #~ msgstr "Bara en enhet kan parkopplas till den här mottagaren" #~ msgid "" #~ "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "" #~ "Visar status för enheter kopplade till\n" #~ "din trÃ¥dlösa Logitech mottagare." #~ msgid "Smooth Scrolling" #~ msgstr "Mjuk rullning" #~ msgid "Solaar depends on a udev file that is not present" #~ msgstr "Solaar beror pÃ¥ en udev-fil som inte finns" #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "Mottagaren klarar bara %d parkopplad(e) enhet(er)." #~ msgid "The receiver was unplugged." #~ msgstr "Mottagaren kopplades ur." #~ msgid "" #~ "The wireless link between this device and its receiver is not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices (keyboards, " #~ "numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties within " #~ "range." #~ msgstr "" #~ "Den trÃ¥dlösa anslutningen mellan den här enheten och mottagaren är " #~ "okrypterad\n" #~ "\n" #~ "För pekdon (möss, styrkulor, pekplattor), är detta inget stort " #~ "säkerhetsproblem.\n" #~ "\n" #~ "Men för textinmatande enheter (tangentbord, numpads) är denna " #~ "säkerhetsbrist\n" #~ "allvarlig, eftersom skriven text obemärkt kan fÃ¥ngas upp av tredje part " #~ "som\n" #~ "befinner sig inom enhetens räckhÃ¥ll." #~ msgid "This receiver has %d pairing(s) remaining." #~ msgstr "Denna mottagare har %d parning(er) kvar." #~ msgid "Thumb Scroll Invert" #~ msgstr "Invertera tumrullningen" #~ msgid "USB id" #~ msgstr "USB-id" #~ msgid "Unexpected device number (%s) in notification %s." #~ msgstr "Oväntat enhetsnummer (%s) i meddelandet %s." #~ msgid "Up to %d devices can be paired to this receiver" #~ msgstr "Upp till %d enheter kan parkopplas till mottagaren" #~ msgid "Wheel Resolution" #~ msgstr "Hjulupplösning" #~ msgid "closed" #~ msgstr "inaktiverat" #~ msgid "height" #~ msgstr "höjd" #~ msgid "lux" #~ msgstr "lux" #~ msgid "next " #~ msgstr "nästa " #~ msgid "open" #~ msgstr "aktiverat" #~ msgid "pair new device" #~ msgstr "parkoppla ny enhet" #~ msgid "paired devices" #~ msgstr "parkopplade enheter" #~ msgid "pairing lock is " #~ msgstr "parkopplingslÃ¥set är " #~ msgid "unknown" #~ msgstr "okänd" #~ msgid "width" #~ msgstr "bredd" Solaar-1.1.20/po/tr.po000066400000000000000000001633021522022367600144310ustar00rootroot00000000000000# Turkish translations for solaar package. # Copyright (C) 2015 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2015. # # Behzat Erte, , 2015. # Osman Karagöz, , 2024. # msgid "" msgstr "" "Project-Id-Version: solaar 0.9.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-07-01 13:49+0800\n" "PO-Revision-Date: 2024-11-17 16:01+0300\n" "Last-Translator: Osman Karagöz \n" "Language-Team: \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.4.2\n" "X-Poedit-SourceCharset: UTF-8\n" #: lib/logitech_receiver/base_usb.py:45 msgid "Bolt Receiver" msgstr "Bolt Alıcı" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "Unifying Alıcı" #: lib/logitech_receiver/base_usb.py:68 lib/logitech_receiver/base_usb.py:80 #: lib/logitech_receiver/base_usb.py:93 lib/logitech_receiver/base_usb.py:106 #: lib/logitech_receiver/base_usb.py:119 msgid "Nano Receiver" msgstr "Nano Alıcı" #: lib/logitech_receiver/base_usb.py:131 msgid "Lightspeed Receiver" msgstr "Lightspeed Alıcı" #: lib/logitech_receiver/base_usb.py:141 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 27 Mhz Alıcı" #: lib/logitech_receiver/common.py:610 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "Pil: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:613 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "Pil: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:921 #: lib/logitech_receiver/settings_templates.py:283 msgid "Disabled" msgstr "Devredışı" #: lib/logitech_receiver/hidpp20.py:922 msgid "Static" msgstr "Sabit" #: lib/logitech_receiver/hidpp20.py:923 msgid "Pulse" msgstr "Nabız" #: lib/logitech_receiver/hidpp20.py:924 msgid "Cycle" msgstr "Döngü" #: lib/logitech_receiver/hidpp20.py:925 msgid "Boot" msgstr "Önyükleme" #: lib/logitech_receiver/hidpp20.py:926 msgid "Demo" msgstr "Demo" #: lib/logitech_receiver/hidpp20.py:927 msgid "Breathe" msgstr "Nefes" #: lib/logitech_receiver/hidpp20.py:928 msgid "Ripple" msgstr "Dalgalanma" #: lib/logitech_receiver/hidpp20.py:929 msgid "Decomposition" msgstr "Ayrışma" #: lib/logitech_receiver/hidpp20.py:930 msgid "Signature1" msgstr "İmza1" #: lib/logitech_receiver/hidpp20.py:931 msgid "Signature2" msgstr "İmza2" #: lib/logitech_receiver/hidpp20.py:932 msgid "CycleS" msgstr "DöngüS" #: lib/logitech_receiver/hidpp20.py:996 msgid "Unknown Location" msgstr "Bilinmeyen Konum" #: lib/logitech_receiver/hidpp20.py:997 msgid "Primary" msgstr "Birincil" #: lib/logitech_receiver/hidpp20.py:998 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:999 msgid "Left Side" msgstr "Sola Taraf" #: lib/logitech_receiver/hidpp20.py:1000 msgid "Right Side" msgstr "SaÄŸ Taraf" #: lib/logitech_receiver/hidpp20.py:1001 msgid "Combined" msgstr "BirleÅŸik" #: lib/logitech_receiver/hidpp20.py:1002 msgid "Primary 1" msgstr "Birincil 1" #: lib/logitech_receiver/hidpp20.py:1003 msgid "Primary 2" msgstr "Birincil 2" #: lib/logitech_receiver/hidpp20.py:1004 msgid "Primary 3" msgstr "Birincil 3" #: lib/logitech_receiver/hidpp20.py:1005 msgid "Primary 4" msgstr "Birincil 4" #: lib/logitech_receiver/hidpp20.py:1006 msgid "Primary 5" msgstr "Birincil 5" #: lib/logitech_receiver/hidpp20.py:1007 msgid "Primary 6" msgstr "Birincil 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "boÅŸ" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "kritik" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "az" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "ortalama" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "iyi" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "dolu" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "boÅŸalıyor" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "yeniden ÅŸarj ediliyor" #: lib/logitech_receiver/i18n.py:37 msgid "charging" msgstr "ÅŸarj ediliyor" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "ÅŸarj edilmiyor" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "nerdeyse dolu" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "ÅŸarj edildi" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "yavaÅŸ yeniden ÅŸarj edilme" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "geçersiz pil" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "sıcaklık hatası" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "hata" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "standart" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "hızlı" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "yavaÅŸ" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "aygıt zaman aşımı" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "aygıt desteklenmiyor" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "çok fazla aygıt" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "sıralama zaman aşımı" #: lib/logitech_receiver/i18n.py:54 msgid "Firmware" msgstr "Donanım Yazılımı" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Önyükleme Yazılımı" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "Donanım" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "DiÄŸer" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Sol Düğme" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Sag Düğme" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "Orta Düğme" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Geri Düğmesi" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "İleri Düğmesi" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Fare Hareketi Düğmesi" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Akıllı Kaydırma" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "DPI Anahtarı" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Sola EÄŸme" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "SaÄŸa EÄŸme" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Sol Tıklama" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "SaÄŸ Tıklama" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "Fare Orta Düğmesi" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Fare Geri Düğmesi" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Fare İleri Düğmesi" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Hareket Düğmesi Navigasyonu" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Fare TekerleÄŸi Sol Düğmesi" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Fare TekerleÄŸi SaÄŸ Düğmesi" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "basıldı" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "bırakıldı" #: lib/logitech_receiver/notifications.py:64 #: lib/logitech_receiver/notifications.py:116 msgid "pairing lock is closed" msgstr "eÅŸleÅŸtirme kilidi kapalı" #: lib/logitech_receiver/notifications.py:64 #: lib/logitech_receiver/notifications.py:116 msgid "pairing lock is open" msgstr "eÅŸleÅŸtirme kilidi açık" #: lib/logitech_receiver/notifications.py:81 msgid "discovery lock is closed" msgstr "keÅŸif kilidi kapalı" #: lib/logitech_receiver/notifications.py:81 msgid "discovery lock is open" msgstr "keÅŸif kilidi açık" #: lib/logitech_receiver/notifications.py:210 lib/solaar/listener.py:238 msgid "connected" msgstr "baÄŸlı" #: lib/logitech_receiver/notifications.py:210 lib/solaar/listener.py:238 msgid "disconnected" msgstr "baÄŸlantı kesildi" #: lib/logitech_receiver/notifications.py:236 msgid "unpaired" msgstr "eÅŸleÅŸmemiÅŸ" #: lib/logitech_receiver/notifications.py:283 msgid "powered on" msgstr "açık" #: lib/logitech_receiver/receiver.py:371 msgid "No paired devices." msgstr "EÅŸleÅŸmiÅŸ aygıt yok." #: lib/logitech_receiver/receiver.py:373 lib/solaar/ui/window.py:604 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s eÅŸleÅŸmiÅŸ aygıt." msgstr[1] "%(count)s eÅŸleÅŸmiÅŸ aygıt." #: lib/logitech_receiver/settings.py:611 msgid "register" msgstr "kaydet" #: lib/logitech_receiver/settings.py:625 lib/logitech_receiver/settings.py:651 msgid "feature" msgstr "özellik" #: lib/logitech_receiver/settings_templates.py:122 msgid "Swap Fx function" msgstr "Fx iÅŸlevlerini ters çevir" #: lib/logitech_receiver/settings_templates.py:125 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "F1..F12 tuÅŸları özel iÅŸlevler için ayarlandığında,\n" "FN tuÅŸuna basılı tutarak standart iÅŸlevlerini aktif edebilirsiniz." #: lib/logitech_receiver/settings_templates.py:130 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "F1..F12 tuÅŸları standart iÅŸlevler için ayarlandığında,\n" "FN tuÅŸuna basılı tutarak özel iÅŸlevlerini aktif edebilirsiniz." #: lib/logitech_receiver/settings_templates.py:138 msgid "Hand Detection" msgstr "El Algılama" #: lib/logitech_receiver/settings_templates.py:139 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Eller klavyenin üzerindeyken aydınlanmayı aç." #: lib/logitech_receiver/settings_templates.py:146 msgid "Scroll Wheel Smooth Scrolling" msgstr "Kaydırma TekerleÄŸi YumuÅŸak Kaydırma" #: lib/logitech_receiver/settings_templates.py:147 #: lib/logitech_receiver/settings_templates.py:394 #: lib/logitech_receiver/settings_templates.py:423 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "TekerleÄŸin dikey kaydırılması için yüksek hasasiyet modu." #: lib/logitech_receiver/settings_templates.py:154 msgid "Side Scrolling" msgstr "Yatay Kaydırma" #: lib/logitech_receiver/settings_templates.py:156 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Devredışı olduÄŸunda, tekerleÄŸin yanına basmak standart yatay kaydırma komutu " "yerine\n" "özel tuÅŸ komutunu gönderir." #: lib/logitech_receiver/settings_templates.py:166 msgid "Sensitivity (DPI - older mice)" msgstr "Hassasiyet (DPI - eski fare)" #: lib/logitech_receiver/settings_templates.py:167 #: lib/logitech_receiver/settings_templates.py:955 #: lib/logitech_receiver/settings_templates.py:983 msgid "Mouse movement sensitivity" msgstr "Fare hareketi hassasiyeti" #: lib/logitech_receiver/settings_templates.py:240 msgid "Backlight Timed" msgstr "Zamanlanmış Aydınlatma" #: lib/logitech_receiver/settings_templates.py:241 #: lib/logitech_receiver/settings_templates.py:381 msgid "Set illumination time for keyboard." msgstr "Klavye için aydınlatma zaman aşımı." #: lib/logitech_receiver/settings_templates.py:252 msgid "Backlight" msgstr "Aydınlatma" #: lib/logitech_receiver/settings_templates.py:253 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Klavyedeki aydınlatma düzeyi. DeÄŸiÅŸiklikler sadece Elle modunda uygulanır." #: lib/logitech_receiver/settings_templates.py:285 msgid "Automatic" msgstr "Otomatik" #: lib/logitech_receiver/settings_templates.py:287 msgid "Manual" msgstr "Elle" #: lib/logitech_receiver/settings_templates.py:289 msgid "Enabled" msgstr "Etkin" #: lib/logitech_receiver/settings_templates.py:295 msgid "Backlight Level" msgstr "Aydınlatma Düzeyi" #: lib/logitech_receiver/settings_templates.py:296 msgid "Illumination level on keyboard when in Manual mode." msgstr "Elle modundaki klavye aydınlatma düzeyi." #: lib/logitech_receiver/settings_templates.py:353 msgid "Backlight Delay Hands Out" msgstr "Eller ÇekildiÄŸinde Aydınlatma Gecikmesi" #: lib/logitech_receiver/settings_templates.py:354 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Eller klavyeden uzaklaÅŸtırıldığında aydınlatmanın solması için gecikme." #: lib/logitech_receiver/settings_templates.py:362 msgid "Backlight Delay Hands In" msgstr "Eller YaklaÅŸtırıldığında Aydıtlatma Gecikmesi" #: lib/logitech_receiver/settings_templates.py:363 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "Eller klavyeye yaklaÅŸtırıldığında aydınlatmanın solması için gecikme." #: lib/logitech_receiver/settings_templates.py:371 msgid "Backlight Delay Powered" msgstr "Güce BaÄŸlandığında Aydınlatma Gecikmesi" #: lib/logitech_receiver/settings_templates.py:372 msgid "Delay in seconds until backlight fades out with external power." msgstr "Güce baÄŸlandığında aydınlatmanın solması için gecikme." #: lib/logitech_receiver/settings_templates.py:380 msgid "Backlight (Seconds)" msgstr "Aydınlatma (Saniye)" #: lib/logitech_receiver/settings_templates.py:392 msgid "Scroll Wheel High Resolution" msgstr "Kaydırma TekerleÄŸi Yüksek Çözünürlük" #: lib/logitech_receiver/settings_templates.py:396 #: lib/logitech_receiver/settings_templates.py:425 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Kaydırma aşırı yavaÅŸ veya hızlıysa yoksaymak için ayarla" #: lib/logitech_receiver/settings_templates.py:403 #: lib/logitech_receiver/settings_templates.py:434 msgid "Scroll Wheel Diversion" msgstr "Kaydırma TekerleÄŸi Yönlendirme" #: lib/logitech_receiver/settings_templates.py:405 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "Kaydırma tekerleÄŸinin LOWRES_WHEEL HID++ bildirimler göndermesini saÄŸlar (bu " "bildirimler Solaar kurallarını tetikler, ancak diÄŸer durumlarda görmezden " "gelinir)." #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Direction" msgstr "Kaydırma TekerleÄŸi Yönü" #: lib/logitech_receiver/settings_templates.py:413 msgid "Invert direction for vertical scroll with wheel." msgstr "Kaydırma tekerleÄŸi ile dikey kaydırma yönünü tersine çevirir." #: lib/logitech_receiver/settings_templates.py:421 msgid "Scroll Wheel Resolution" msgstr "Kaydırma TekerleÄŸi Çözünürlüğü" #: lib/logitech_receiver/settings_templates.py:436 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "Kaydırma tekerleÄŸinin HIRES_WHEEL HID++ bildirimler göndermesini saÄŸlar (bu " "bildirimler Solaar kurallarını tetikler, ancak diÄŸer durumlarda görmezden " "gelinir)." #: lib/logitech_receiver/settings_templates.py:445 msgid "Sensitivity (Pointer Speed)" msgstr "Hassasiyet (İşaretçi Hızı)" #: lib/logitech_receiver/settings_templates.py:446 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Fare için hız çarpanı (256 normal çarpandır)." #: lib/logitech_receiver/settings_templates.py:456 msgid "Thumb Wheel Diversion" msgstr "BaÅŸparmak TekerleÄŸi Yönlendirme" #: lib/logitech_receiver/settings_templates.py:458 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "BaÅŸparmak tekerleÄŸinin THUMB_WHEEL HID++ bildirimler göndermesini saÄŸlar (bu " "bildirimler Solaar kurallarını tetikler, ancak diÄŸer durumlarda görmezden " "gelinir)." #: lib/logitech_receiver/settings_templates.py:467 msgid "Thumb Wheel Direction" msgstr "BaÅŸparmak TekerleÄŸi Yönü" #: lib/logitech_receiver/settings_templates.py:468 msgid "Invert thumb wheel scroll direction." msgstr "Kaydırma tekerleÄŸi ile baÅŸparmak kaydırma yönünü tersine çevirir." #: lib/logitech_receiver/settings_templates.py:488 msgid "Onboard Profiles" msgstr "YerleÅŸik Profiller" #: lib/logitech_receiver/settings_templates.py:489 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "YerleÅŸik profilleri etkinleÅŸtir, bu rapor hızını, hassasiyeti ve düğme " "etkinliÄŸini kontrol eder" #: lib/logitech_receiver/settings_templates.py:533 #: lib/logitech_receiver/settings_templates.py:566 msgid "Report Rate" msgstr "Rapor Hızı" #: lib/logitech_receiver/settings_templates.py:535 #: lib/logitech_receiver/settings_templates.py:568 msgid "Frequency of device movement reports" msgstr "Aygıt hareketlerinin rapor sıklığı" #: lib/logitech_receiver/settings_templates.py:535 #: lib/logitech_receiver/settings_templates.py:568 #: lib/logitech_receiver/settings_templates.py:983 #: lib/logitech_receiver/settings_templates.py:1357 #: lib/logitech_receiver/settings_templates.py:1388 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "" "Etkili olabilmesi için YerleÅŸik Profillerin devredışı bırakılması " "gerekebilir." #: lib/logitech_receiver/settings_templates.py:596 msgid "Divert crown events" msgstr "Kadran etkinliklerini yönlendir" #: lib/logitech_receiver/settings_templates.py:597 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "Kadranın CROWN HID++ bildirimler göndermesini saÄŸlar (bu bildirimler Solaar " "kurallarını tetikler, ancak diÄŸer durumlarda görmezden gelinir)." #: lib/logitech_receiver/settings_templates.py:605 msgid "Crown smooth scroll" msgstr "Kadran yumuÅŸak kaydırma" #: lib/logitech_receiver/settings_templates.py:606 msgid "Set crown smooth scroll" msgstr "Kadranın yumuÅŸak kaydırmasını ayarla" #: lib/logitech_receiver/settings_templates.py:614 msgid "Divert G and M Keys" msgstr "G ve M TuÅŸlarını Yönlendir" #: lib/logitech_receiver/settings_templates.py:615 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "G ve M TuÅŸlarının HID++ bildirimler göndermesini saÄŸlar (bu bildirimler " "Solaar kurallarını tetikler, ancak diÄŸer durumlarda görmezden gelinir)." #: lib/logitech_receiver/settings_templates.py:629 msgid "Scroll Wheel Ratcheted" msgstr "Kaydırma TekerleÄŸi Dönüşü" #: lib/logitech_receiver/settings_templates.py:630 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "Fare TekerleÄŸini, hız kontrollü diÅŸli kaydırma ile sürekli serbest dönüş " "arasında deÄŸiÅŸtir." #: lib/logitech_receiver/settings_templates.py:632 msgid "Freespinning" msgstr "Serbest Dönüş" #: lib/logitech_receiver/settings_templates.py:632 msgid "Ratcheted" msgstr "DiÅŸli" #: lib/logitech_receiver/settings_templates.py:639 msgid "Scroll Wheel Ratchet Speed" msgstr "Kaydırma TekerleÄŸi DiÅŸli Hızı" #: lib/logitech_receiver/settings_templates.py:641 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "Fare tekerleÄŸi hızını kullanarak diÅŸli kaydırma ile serbest dönüş arasında " "geçiÅŸ yap.\n" "Fare tekerleÄŸi, 50 hızda her zaman diÅŸli kaydırmalı olur." #: lib/logitech_receiver/settings_templates.py:690 msgid "Key/Button Actions" msgstr "TuÅŸ/Düğme Eylemleri" #: lib/logitech_receiver/settings_templates.py:692 msgid "Change the action for the key or button." msgstr "TuÅŸ veya düğmenin eylemini deÄŸiÅŸtirir." #: lib/logitech_receiver/settings_templates.py:694 msgid "Overridden by diversion." msgstr "Yönlendirmeyle geçersiz kılındı." #: lib/logitech_receiver/settings_templates.py:696 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Önemli eylemleri deÄŸiÅŸtirmek (farenin sol tuÅŸu gibi) sistemde " "kararsızlıklara yol açabilir." #: lib/logitech_receiver/settings_templates.py:862 msgid "Key/Button Diversion" msgstr "TuÅŸ/Düğme Yönlendirme" #: lib/logitech_receiver/settings_templates.py:863 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "" "TuÅŸ veya düğmenin HID++ bildirimleri (yönlendirmeler) veya Fare Hareketleri " "baÅŸlatmalar veya Kaydırma DPI'si" #: lib/logitech_receiver/settings_templates.py:866 #: lib/logitech_receiver/settings_templates.py:867 #: lib/logitech_receiver/settings_templates.py:868 msgid "Diverted" msgstr "YönlendirilmiÅŸ" #: lib/logitech_receiver/settings_templates.py:866 #: lib/logitech_receiver/settings_templates.py:867 msgid "Mouse Gestures" msgstr "Fare Hareketleri" #: lib/logitech_receiver/settings_templates.py:866 #: lib/logitech_receiver/settings_templates.py:867 #: lib/logitech_receiver/settings_templates.py:868 msgid "Regular" msgstr "Normal" #: lib/logitech_receiver/settings_templates.py:866 msgid "Sliding DPI" msgstr "Kaydırma DPI" #: lib/logitech_receiver/settings_templates.py:954 #: lib/logitech_receiver/settings_templates.py:982 msgid "Sensitivity (DPI)" msgstr "Hassasiyet (DPI)" #: lib/logitech_receiver/settings_templates.py:1059 msgid "Sensitivity Switching" msgstr "Hassasiyet DeÄŸiÅŸtirme" #: lib/logitech_receiver/settings_templates.py:1061 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "Åžuanki hassasiyeti ve hatırlanan hassasiyeti tuÅŸ veya düğmeye basıldığında " "deÄŸiÅŸtir.\n" "EÄŸer hatırlanan hassasiyet yoksa sadece ÅŸuanki hassasiyeti hatırla" #: lib/logitech_receiver/settings_templates.py:1065 msgid "Off" msgstr "Kapalı" #: lib/logitech_receiver/settings_templates.py:1096 msgid "Disable keys" msgstr "TuÅŸları devredışı bırak" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Disable specific keyboard keys." msgstr "Özel klavye tuÅŸlarını devredışı bırak." #: lib/logitech_receiver/settings_templates.py:1100 #, python-format msgid "Disables the %s key." msgstr "%s tuÅŸunu devredışı bırakır." #: lib/logitech_receiver/settings_templates.py:1113 #: lib/logitech_receiver/settings_templates.py:1170 msgid "Set OS" msgstr "İşletim Sistemi Ayarla" #: lib/logitech_receiver/settings_templates.py:1114 #: lib/logitech_receiver/settings_templates.py:1171 msgid "Change keys to match OS." msgstr "TuÅŸları eÅŸleÅŸen iÅŸletim sistemine göre deÄŸiÅŸtir." #: lib/logitech_receiver/settings_templates.py:1183 msgid "Change Host" msgstr "BaÄŸlanılan Bilgisayarı DeÄŸiÅŸtir" #: lib/logitech_receiver/settings_templates.py:1184 msgid "Switch connection to a different host" msgstr "BaÄŸlantıyı baÅŸka bilgisayara deÄŸiÅŸtir" #: lib/logitech_receiver/settings_templates.py:1208 msgid "Performs a left click." msgstr "Sol tıklama eylemi gerçekleÅŸtirir." #: lib/logitech_receiver/settings_templates.py:1208 msgid "Single tap" msgstr "Tek dokunma" #: lib/logitech_receiver/settings_templates.py:1209 msgid "Performs a right click." msgstr "SaÄŸ tıklama eylemi gerçekleÅŸtirir." #: lib/logitech_receiver/settings_templates.py:1209 msgid "Single tap with two fingers" msgstr "İki parmakla tek dokunma" #: lib/logitech_receiver/settings_templates.py:1210 msgid "Single tap with three fingers" msgstr "Üç parmakla tek dokunma" #: lib/logitech_receiver/settings_templates.py:1214 msgid "Double tap" msgstr "Çift dokunma" #: lib/logitech_receiver/settings_templates.py:1214 msgid "Performs a double click." msgstr "Çift tıklama eylemi gerçekleÅŸtirir." #: lib/logitech_receiver/settings_templates.py:1215 msgid "Double tap with two fingers" msgstr "İki parmakla çift dokunma" #: lib/logitech_receiver/settings_templates.py:1216 msgid "Double tap with three fingers" msgstr "Üç parmakla çift dokunma" #: lib/logitech_receiver/settings_templates.py:1219 msgid "Drags items by dragging the finger after double tapping." msgstr "Çift tıklama eylemi ile nesneleri taşı." #: lib/logitech_receiver/settings_templates.py:1219 msgid "Tap and drag" msgstr "Dokun ve taşı" #: lib/logitech_receiver/settings_templates.py:1221 msgid "Tap and drag with two fingers" msgstr "İki parmakla dokun ve taşı" #: lib/logitech_receiver/settings_templates.py:1222 msgid "Drags items by dragging the fingers after double tapping." msgstr "Çift tıklama eylemi ile nesneleri taşı." #: lib/logitech_receiver/settings_templates.py:1224 msgid "Tap and drag with three fingers" msgstr "Üç parmakla dokun ve taşı" #: lib/logitech_receiver/settings_templates.py:1227 msgid "Suppress tap and edge gestures" msgstr "Dokunma ve kenar hareketlerini baskıla" #: lib/logitech_receiver/settings_templates.py:1228 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "" "Dokunma ve kenar hareketlerini devredışı bırakır (Fn + SolTıklama ile " "aynıdır)." #: lib/logitech_receiver/settings_templates.py:1230 msgid "Scroll with one finger" msgstr "Bir parmakla kaydır" #: lib/logitech_receiver/settings_templates.py:1230 #: lib/logitech_receiver/settings_templates.py:1231 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Scrolls." msgstr "Kaydırır." #: lib/logitech_receiver/settings_templates.py:1231 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Scroll with two fingers" msgstr "İki parmakla kaydır" #: lib/logitech_receiver/settings_templates.py:1232 msgid "Scroll horizontally with two fingers" msgstr "İki parmakla yatay kaydır" #: lib/logitech_receiver/settings_templates.py:1232 msgid "Scrolls horizontally." msgstr "Yatay kaydırır." #: lib/logitech_receiver/settings_templates.py:1233 msgid "Scroll vertically with two fingers" msgstr "İki parmakla dikey kaydır" #: lib/logitech_receiver/settings_templates.py:1233 msgid "Scrolls vertically." msgstr "Dikey kaydırır." #: lib/logitech_receiver/settings_templates.py:1235 msgid "Inverts the scrolling direction." msgstr "Kaydırma yönünü ters çevir." #: lib/logitech_receiver/settings_templates.py:1235 msgid "Natural scrolling" msgstr "DoÄŸal kaydırma" #: lib/logitech_receiver/settings_templates.py:1236 msgid "Enables the thumbwheel." msgstr "BaÅŸparmak tekerleÄŸini etkinleÅŸtirir." #: lib/logitech_receiver/settings_templates.py:1236 msgid "Thumbwheel" msgstr "BaÅŸparmak TekerleÄŸi" #: lib/logitech_receiver/settings_templates.py:1247 #: lib/logitech_receiver/settings_templates.py:1251 msgid "Swipe from the top edge" msgstr "Üst kenardan vuruÅŸ" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Swipe from the left edge" msgstr "Sol kenardan vuruÅŸ" #: lib/logitech_receiver/settings_templates.py:1249 msgid "Swipe from the right edge" msgstr "SaÄŸ kenardan vuruÅŸ" #: lib/logitech_receiver/settings_templates.py:1250 msgid "Swipe from the bottom edge" msgstr "Alt kenardan vuruÅŸ" #: lib/logitech_receiver/settings_templates.py:1252 msgid "Swipe two fingers from the left edge" msgstr "Sol kenardan iki parmak vuruÅŸ" #: lib/logitech_receiver/settings_templates.py:1253 msgid "Swipe two fingers from the right edge" msgstr "SaÄŸ kenardan iki parmak vuruÅŸ" #: lib/logitech_receiver/settings_templates.py:1254 msgid "Swipe two fingers from the bottom edge" msgstr "Alt kenardan iki parmak vuruÅŸ" #: lib/logitech_receiver/settings_templates.py:1255 msgid "Swipe two fingers from the top edge" msgstr "Üst kenardan iki parmak vuruÅŸ" #: lib/logitech_receiver/settings_templates.py:1256 #: lib/logitech_receiver/settings_templates.py:1260 msgid "Pinch to zoom out; spread to zoom in." msgstr "UzaklaÅŸmak için sıkıştırın, yakınlaÅŸtırmak için yayın." #: lib/logitech_receiver/settings_templates.py:1256 msgid "Zoom with two fingers." msgstr "İki parmakla yakınlaÅŸtırma." #: lib/logitech_receiver/settings_templates.py:1257 msgid "Pinch to zoom out." msgstr "UzaklaÅŸtırmak için sıkıştırın." #: lib/logitech_receiver/settings_templates.py:1258 msgid "Spread to zoom in." msgstr "YakınlaÅŸtırmak için yayın." #: lib/logitech_receiver/settings_templates.py:1259 msgid "Zoom with three fingers." msgstr "Üç parmakla yakınlaÅŸtırma." #: lib/logitech_receiver/settings_templates.py:1260 msgid "Zoom with two fingers" msgstr "İki parmakla yakınlaÅŸtır" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Pixel zone" msgstr "Piksel alanı" #: lib/logitech_receiver/settings_templates.py:1279 msgid "Ratio zone" msgstr "Oran alanı" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Scale factor" msgstr "Ölçek katsayısı" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Sets the cursor speed." msgstr "İmleç hızını ayarla." #: lib/logitech_receiver/settings_templates.py:1284 msgid "Left" msgstr "Sol" #: lib/logitech_receiver/settings_templates.py:1284 msgid "Left-most coordinate." msgstr "En soldaki koordinat." #: lib/logitech_receiver/settings_templates.py:1285 msgid "Bottom" msgstr "Alt" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Bottom coordinate." msgstr "Alt koordinat." #: lib/logitech_receiver/settings_templates.py:1286 msgid "Width" msgstr "GeniÅŸlik" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Width." msgstr "GeniÅŸlik." #: lib/logitech_receiver/settings_templates.py:1287 msgid "Height" msgstr "Yükseklik" #: lib/logitech_receiver/settings_templates.py:1287 msgid "Height." msgstr "Yükseklik." #: lib/logitech_receiver/settings_templates.py:1288 msgid "Cursor speed." msgstr "İmleç hızı." #: lib/logitech_receiver/settings_templates.py:1288 msgid "Scale" msgstr "Ölçek" #: lib/logitech_receiver/settings_templates.py:1294 msgid "Gestures" msgstr "Hareketler" #: lib/logitech_receiver/settings_templates.py:1295 msgid "Tweak the mouse/touchpad behaviour." msgstr "Fare/dokunmatik yüzey davranışında ince ayar yapın." #: lib/logitech_receiver/settings_templates.py:1311 msgid "Gestures Diversion" msgstr "Hareketleri Yönlendir" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Divert mouse/touchpad gestures." msgstr "Fare/dokunmatik yüzey hareketlerini yönlendirir." #: lib/logitech_receiver/settings_templates.py:1328 msgid "Gesture params" msgstr "Hareket parametreleri" #: lib/logitech_receiver/settings_templates.py:1329 msgid "Change numerical parameters of a mouse/touchpad." msgstr "Fare/dokunmatik yüzey sayısal parametrelerini deÄŸiÅŸtir." #: lib/logitech_receiver/settings_templates.py:1353 msgid "M-Key LEDs" msgstr "M-TuÅŸu LED'leri" #: lib/logitech_receiver/settings_templates.py:1355 msgid "Control the M-Key LEDs." msgstr "M-TuÅŸu LED'lerini kontrol eder." #: lib/logitech_receiver/settings_templates.py:1359 #: lib/logitech_receiver/settings_templates.py:1390 msgid "May need G Keys diverted to be effective." msgstr "G TuÅŸlarını yönlendirmek etkili olabilir." #: lib/logitech_receiver/settings_templates.py:1365 #, python-format msgid "Lights up the %s key." msgstr "%s tuÅŸunu aydınlat." #: lib/logitech_receiver/settings_templates.py:1384 msgid "MR-Key LED" msgstr "MR-TuÅŸu LED'i" #: lib/logitech_receiver/settings_templates.py:1386 msgid "Control the MR-Key LED." msgstr "MR-TuÅŸu LED'inin kontrol eder." #: lib/logitech_receiver/settings_templates.py:1407 msgid "Persistent Key/Button Mapping" msgstr "Kalıcı TuÅŸ/Düğme Haritalama" #: lib/logitech_receiver/settings_templates.py:1409 msgid "Permanently change the mapping for the key or button." msgstr "TuÅŸ veya düğmenin haritalamasını kalıcı olarak deÄŸiÅŸtir." #: lib/logitech_receiver/settings_templates.py:1411 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "" "Önemli tuÅŸları veya düğmeleri deÄŸiÅŸtirmek (farenin sol tuÅŸu gibi) sistemde " "kararsızlıklara yol açabilir." #: lib/logitech_receiver/settings_templates.py:1468 msgid "Sidetone" msgstr "Yan ton" #: lib/logitech_receiver/settings_templates.py:1469 msgid "Set sidetone level." msgstr "Yan ton seviyesini ayarla." #: lib/logitech_receiver/settings_templates.py:1478 msgid "Equalizer" msgstr "Ekolayzer" #: lib/logitech_receiver/settings_templates.py:1479 msgid "Set equalizer levels." msgstr "Ekolayzer seviyesini ayarla." #: lib/logitech_receiver/settings_templates.py:1501 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1507 msgid "Power Management" msgstr "Güç Yönetimi" #: lib/logitech_receiver/settings_templates.py:1508 msgid "Power off in minutes (0 for never)." msgstr "Dakika cinsinden kapanma süresi (asla kapanmaması için 0)." #: lib/logitech_receiver/settings_templates.py:1519 msgid "Brightness Control" msgstr "Parlaklık Kontrolü" #: lib/logitech_receiver/settings_templates.py:1520 msgid "Control overall brightness" msgstr "Genel parlaklığı kontrol et" #: lib/logitech_receiver/settings_templates.py:1563 #: lib/logitech_receiver/settings_templates.py:1617 msgid "LED Control" msgstr "LED Kontrolü" #: lib/logitech_receiver/settings_templates.py:1564 #: lib/logitech_receiver/settings_templates.py:1618 msgid "Switch control of LED zones between device and Solaar" msgstr "LED bölgelerinin kontrolünü aygıt ile Solaar arasında deÄŸiÅŸtir" #: lib/logitech_receiver/settings_templates.py:1579 #: lib/logitech_receiver/settings_templates.py:1628 msgid "LED Zone Effects" msgstr "LED Bölge Efektleri" #: lib/logitech_receiver/settings_templates.py:1580 #: lib/logitech_receiver/settings_templates.py:1629 msgid "LED Control needs to be set to Solaar to be effective." msgstr "LED kontrolünün etkili olabilmesi için Solaar seçilmelidir." #: lib/logitech_receiver/settings_templates.py:1580 #: lib/logitech_receiver/settings_templates.py:1629 msgid "Set effect for LED Zone" msgstr "LED Bölgesi için efekt ayarla" #: lib/logitech_receiver/settings_templates.py:1583 msgid "Speed" msgstr "Hız" #: lib/logitech_receiver/settings_templates.py:1584 msgid "Period" msgstr "Sıklık" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Intensity" msgstr "YoÄŸunluk" #: lib/logitech_receiver/settings_templates.py:1586 msgid "Ramp" msgstr "EÄŸim" #: lib/logitech_receiver/settings_templates.py:1602 msgid "LEDs" msgstr "LEDler" #: lib/logitech_receiver/settings_templates.py:1639 msgid "Per-key Lighting" msgstr "TuÅŸ başına Aydınlatma" #: lib/logitech_receiver/settings_templates.py:1640 msgid "Control per-key lighting." msgstr "TuÅŸ başına aydınlatmayı kontrol et." #: lib/solaar/ui/__init__.py:103 msgid "Another Solaar process is already running so just expose its window" msgstr "BaÅŸka bir Solaar iÅŸlemi çalışıyor, sadece onun penceresini görünür yap" #: lib/solaar/ui/about.py:34 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Logitech alıcılarını, klavyelerini,\n" "farelerini ve tabletlerini yönetir." #: lib/solaar/ui/about.py:43 msgid "Additional Programming" msgstr "Ek Programlama" #: lib/solaar/ui/about.py:44 msgid "GUI design" msgstr "GUI tasarımı" #: lib/solaar/ui/about.py:46 msgid "Testing" msgstr "Sınama" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "Logitech belgeleri" #: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87 #: lib/solaar/ui/window.py:189 msgid "Unpair" msgstr "EÅŸleÅŸmeyi Kaldır" #: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:103 msgid "Cancel" msgstr "Vazgeç" #: lib/solaar/ui/common.py:35 msgid "Permissions error" msgstr "Yetki hatası" #: lib/solaar/ui/common.py:37 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "Bir Logitech aygıtı (%s) bulundu ama açmak için yetki yok." #: lib/solaar/ui/common.py:39 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "EÄŸer Solaar'ı yeni kurmuÅŸsanız, aygıtı veya alıcıyı tekrar baÄŸlamayı deneyin." #: lib/solaar/ui/common.py:42 msgid "Cannot connect to device error" msgstr "Aygıta baÄŸlanılamıyor" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "%s konumunda bir Logitech alıcısı veya aygıtı bulundu, ancak buna " "baÄŸlanırken bir hatayla karşılaşıldı." #: lib/solaar/ui/common.py:46 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "Aygıtı tekrar baÄŸlamayı deneyin veya kapatıp açın." #: lib/solaar/ui/common.py:49 msgid "Unpairing failed" msgstr "EÅŸleÅŸtirme kaldırılamadı" #: lib/solaar/ui/common.py:51 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "%{device} ve %{receiver} eÅŸleÅŸtirmesi kaldırılamadı." #: lib/solaar/ui/common.py:53 msgid "The receiver returned an error, with no further details." msgstr "Alıcı hata verdi, bu hata hakkında ayrıntı mevcut deÄŸil." #: lib/solaar/ui/config_panel.py:228 msgid "Complete - ENTER to change" msgstr "Tamamlanmış - DeÄŸiÅŸtirmek için ENTER'a basın" #: lib/solaar/ui/config_panel.py:228 msgid "Incomplete" msgstr "Tamamlanmamış" #: lib/solaar/ui/config_panel.py:470 lib/solaar/ui/config_panel.py:522 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d deÄŸer" msgstr[1] "%d deÄŸer" #: lib/solaar/ui/config_panel.py:603 msgid "Changes allowed" msgstr "DeÄŸiÅŸiklikler kabul ediliyor" #: lib/solaar/ui/config_panel.py:604 msgid "No changes allowed" msgstr "DeÄŸiÅŸiklik kabul edilmiyor" #: lib/solaar/ui/config_panel.py:605 msgid "Ignore this setting" msgstr "Bu ayarı görmezden gel" #: lib/solaar/ui/config_panel.py:649 msgid "Working" msgstr "Çalışıyor" #: lib/solaar/ui/config_panel.py:652 msgid "Read/write operation failed." msgstr "Okuma/yazma iÅŸlemi yapılamadı." #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "Varolan kurallar" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "Kullanıcı tanımlı kurallar" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1033 msgid "Rule" msgstr "Kural" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:545 #: lib/solaar/ui/diversion_rules.py:672 msgid "Sub-rule" msgstr "Alt Kural" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[boÅŸ]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Make changes permanent?" msgstr "DeÄŸiÅŸiklikleri kalıcı yap?" #: lib/solaar/ui/diversion_rules.py:99 msgid "Yes" msgstr "Evet" #: lib/solaar/ui/diversion_rules.py:101 msgid "No" msgstr "Hayır" #: lib/solaar/ui/diversion_rules.py:106 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Hayır'ı seçerseniz, Solaar kapatıldığında deÄŸiÅŸiklikler kaybolacaktır." #: lib/solaar/ui/diversion_rules.py:167 msgid "Solaar Rule Editor" msgstr "Solar Kural Editörü" #: lib/solaar/ui/diversion_rules.py:260 msgid "Save changes" msgstr "DeÄŸiÅŸiklikleri kaydet" #: lib/solaar/ui/diversion_rules.py:265 msgid "Discard changes" msgstr "DeÄŸiÅŸiklikleri gözardı et" #: lib/solaar/ui/diversion_rules.py:404 msgid "Insert here" msgstr "Buraya ekle" #: lib/solaar/ui/diversion_rules.py:406 msgid "Insert above" msgstr "Yukarıya ekle" #: lib/solaar/ui/diversion_rules.py:408 msgid "Insert below" msgstr "AÅŸağıya ekle" #: lib/solaar/ui/diversion_rules.py:414 msgid "Insert new rule here" msgstr "Buraya yeni kural ekle" #: lib/solaar/ui/diversion_rules.py:416 msgid "Insert new rule above" msgstr "Yukarıya yeni kural ekle" #: lib/solaar/ui/diversion_rules.py:418 msgid "Insert new rule below" msgstr "AÅŸağıya yeni kural ekle" #: lib/solaar/ui/diversion_rules.py:463 msgid "Paste here" msgstr "Buraya yapıştır" #: lib/solaar/ui/diversion_rules.py:465 msgid "Paste above" msgstr "Yukarı yapıştır" #: lib/solaar/ui/diversion_rules.py:467 msgid "Paste below" msgstr "AÅŸağıya yapıştır" #: lib/solaar/ui/diversion_rules.py:473 msgid "Paste rule here" msgstr "Kuralı buraya yapıştır" #: lib/solaar/ui/diversion_rules.py:475 msgid "Paste rule above" msgstr "Kuralı yukarı yapıştır" #: lib/solaar/ui/diversion_rules.py:477 msgid "Paste rule below" msgstr "Kuralı aÅŸağıya yapıştır" #: lib/solaar/ui/diversion_rules.py:481 msgid "Paste rule" msgstr "Kuralı yapıştır" #: lib/solaar/ui/diversion_rules.py:510 msgid "Flatten" msgstr "Kapsamdan çıkar" #: lib/solaar/ui/diversion_rules.py:543 msgid "Insert" msgstr "Ekle" #: lib/solaar/ui/diversion_rules.py:546 lib/solaar/ui/diversion_rules.py:674 #: lib/solaar/ui/diversion_rules.py:1065 msgid "Or" msgstr "Veya" #: lib/solaar/ui/diversion_rules.py:547 lib/solaar/ui/diversion_rules.py:673 #: lib/solaar/ui/diversion_rules.py:1051 msgid "And" msgstr "Ve" #: lib/solaar/ui/diversion_rules.py:549 msgid "Condition" msgstr "Durum" #: lib/solaar/ui/diversion_rules.py:551 lib/solaar/ui/rule_conditions.py:146 msgid "Feature" msgstr "Özellik" #: lib/solaar/ui/diversion_rules.py:552 lib/solaar/ui/rule_conditions.py:181 msgid "Report" msgstr "Rapor" #: lib/solaar/ui/diversion_rules.py:553 lib/solaar/ui/rule_conditions.py:60 msgid "Process" msgstr "İşlem" #: lib/solaar/ui/diversion_rules.py:554 msgid "Mouse process" msgstr "Fare İşlemi" #: lib/solaar/ui/diversion_rules.py:555 lib/solaar/ui/rule_conditions.py:218 msgid "Modifiers" msgstr "DeÄŸiÅŸtiriciler" #: lib/solaar/ui/diversion_rules.py:556 lib/solaar/ui/rule_conditions.py:270 msgid "Key" msgstr "TuÅŸ" #: lib/solaar/ui/diversion_rules.py:557 lib/solaar/ui/rule_conditions.py:311 msgid "KeyIsDown" msgstr "TuÅŸBasılı" #: lib/solaar/ui/diversion_rules.py:558 lib/solaar/ui/diversion_rules.py:1359 msgid "Active" msgstr "Etkin" #: lib/solaar/ui/diversion_rules.py:559 lib/solaar/ui/diversion_rules.py:1316 #: lib/solaar/ui/diversion_rules.py:1368 lib/solaar/ui/diversion_rules.py:1418 msgid "Device" msgstr "Aygıt" #: lib/solaar/ui/diversion_rules.py:560 lib/solaar/ui/diversion_rules.py:1394 msgid "Host" msgstr "Bilgisayar" #: lib/solaar/ui/diversion_rules.py:561 lib/solaar/ui/diversion_rules.py:1436 msgid "Setting" msgstr "Ayar" #: lib/solaar/ui/diversion_rules.py:562 lib/solaar/ui/rule_conditions.py:326 #: lib/solaar/ui/rule_conditions.py:375 msgid "Test" msgstr "Sınama" #: lib/solaar/ui/diversion_rules.py:563 lib/solaar/ui/rule_conditions.py:500 msgid "Test bytes" msgstr "Sınama baytları" #: lib/solaar/ui/diversion_rules.py:564 lib/solaar/ui/rule_conditions.py:601 msgid "Mouse Gesture" msgstr "Fare Hareketi" #: lib/solaar/ui/diversion_rules.py:568 msgid "Action" msgstr "Eylem" #: lib/solaar/ui/diversion_rules.py:570 lib/solaar/ui/rule_actions.py:132 msgid "Key press" msgstr "TuÅŸ basımı" #: lib/solaar/ui/diversion_rules.py:571 lib/solaar/ui/rule_actions.py:183 msgid "Mouse scroll" msgstr "Fare kaydırma" #: lib/solaar/ui/diversion_rules.py:572 lib/solaar/ui/rule_actions.py:244 msgid "Mouse click" msgstr "Fare tıklaması" #: lib/solaar/ui/diversion_rules.py:573 msgid "Set" msgstr "Belirle" #: lib/solaar/ui/diversion_rules.py:574 lib/solaar/ui/rule_actions.py:314 msgid "Execute" msgstr "Uygula" #: lib/solaar/ui/diversion_rules.py:575 lib/solaar/ui/diversion_rules.py:1096 msgid "Later" msgstr "Sonra" #: lib/solaar/ui/diversion_rules.py:604 msgid "Insert new rule" msgstr "Yeni kural ekle" #: lib/solaar/ui/diversion_rules.py:624 lib/solaar/ui/rule_actions.py:74 #: lib/solaar/ui/rule_actions.py:273 lib/solaar/ui/rule_conditions.py:548 msgid "Delete" msgstr "Sil" #: lib/solaar/ui/diversion_rules.py:646 msgid "Negate" msgstr "Olumsuzla" #: lib/solaar/ui/diversion_rules.py:670 msgid "Wrap with" msgstr "Kapsa" #: lib/solaar/ui/diversion_rules.py:692 msgid "Cut" msgstr "Kes" #: lib/solaar/ui/diversion_rules.py:707 msgid "Paste" msgstr "Yapıştır" #: lib/solaar/ui/diversion_rules.py:713 msgid "Copy" msgstr "Kopyala" #: lib/solaar/ui/diversion_rules.py:1014 msgid "This editor does not support the selected rule component yet." msgstr "Seçilen kural bileÅŸeni henüz desteklenmiyor." #: lib/solaar/ui/diversion_rules.py:1076 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "" "Saniye cinsinden gecikme süresi. 0 ile 1 arasındaki gecikmeler daha yüksek " "hassasiyetle yapılır." #: lib/solaar/ui/diversion_rules.py:1114 msgid "Not" msgstr "DeÄŸil" #: lib/solaar/ui/diversion_rules.py:1145 msgid "Toggle" msgstr "DeÄŸiÅŸtir" #: lib/solaar/ui/diversion_rules.py:1146 msgid "True" msgstr "DoÄŸru" #: lib/solaar/ui/diversion_rules.py:1147 msgid "False" msgstr "Yanlış" #: lib/solaar/ui/diversion_rules.py:1160 msgid "Unsupported setting" msgstr "Desteklenmeyen ayar" #: lib/solaar/ui/diversion_rules.py:1322 lib/solaar/ui/diversion_rules.py:1342 #: lib/solaar/ui/diversion_rules.py:1424 lib/solaar/ui/diversion_rules.py:1669 #: lib/solaar/ui/diversion_rules.py:1687 msgid "Originating device" msgstr "Kaynak aygıt" #: lib/solaar/ui/diversion_rules.py:1355 msgid "Device is active and its settings can be changed." msgstr "Aygıt etkin ve ayarları deÄŸiÅŸtirilebilir." #: lib/solaar/ui/diversion_rules.py:1364 msgid "Device that originated the current notification." msgstr "Mevcut bildirimin kaynağı olan aygıt." #: lib/solaar/ui/diversion_rules.py:1377 msgid "Name of host computer." msgstr "Bilgisayarın adı." #: lib/solaar/ui/diversion_rules.py:1445 msgid "Value" msgstr "DeÄŸer" #: lib/solaar/ui/diversion_rules.py:1454 msgid "Item" msgstr "Öge" #: lib/solaar/ui/diversion_rules.py:1728 msgid "Change setting on device" msgstr "Aygıtın ayarını deÄŸiÅŸtir" #: lib/solaar/ui/diversion_rules.py:1744 msgid "Setting on device" msgstr "Aygıtta ayar" #: lib/solaar/ui/notify.py:115 msgid "unspecified reason" msgstr "tanımlanmamış sebep" #: lib/solaar/ui/pair_window.py:37 lib/solaar/ui/pair_window.py:155 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: yeni aygıtı eÅŸleÅŸtir" #: lib/solaar/ui/pair_window.py:39 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt alıcılar sadece Bolt aygıtlarla uyumludur." #: lib/solaar/ui/pair_window.py:41 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "EÅŸleÅŸme ışığı hızlıca yanıp sönene kadar eÅŸleÅŸme düğmesi ya da tuÅŸuna basın." #: lib/solaar/ui/pair_window.py:44 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Unifying alıcılar sadece Unifying aygıtlarla uyumludur." #: lib/solaar/ui/pair_window.py:46 msgid "Other receivers are only compatible with a few devices." msgstr "DiÄŸer alıcılar sadece az miktarda aygıtla uyumludur." #: lib/solaar/ui/pair_window.py:48 msgid "Turn on the device you want to pair." msgstr "EÅŸleÅŸtirmek istediÄŸiniz aygıtı açın." #: lib/solaar/ui/pair_window.py:49 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "Aygıt yakınlarda açık olan bir alıcıyla eÅŸleÅŸmemiÅŸ olmalıdır." #: lib/solaar/ui/pair_window.py:51 msgid "If the device is already turned on, turn it off and on again." msgstr "Aygıt zaten açıksa, kapatıp tekrar açın." #: lib/solaar/ui/pair_window.py:55 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Bu alıcı %d aygıtla daha eÅŸleÅŸebilir." msgstr[1] "" "\n" "\n" "Bu alıcı %d aygıtla daha eÅŸleÅŸebilir." #: lib/solaar/ui/pair_window.py:61 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "Bu adımda vezgeçerseniz eÅŸleÅŸme kullanılamayacak." #: lib/solaar/ui/pair_window.py:156 #, python-format msgid "Enter passcode on %(name)s." msgstr "%(name)s üzerinde geçiÅŸ kodunu girin." #: lib/solaar/ui/pair_window.py:159 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "%(passcode)s yazın ve Enter tuÅŸuna basın." #: lib/solaar/ui/pair_window.py:162 msgid "left" msgstr "sol" #: lib/solaar/ui/pair_window.py:162 msgid "right" msgstr "saÄŸ" #: lib/solaar/ui/pair_window.py:164 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "%(code)s basın\n" "ve sonra saÄŸ ve sol tuÅŸlarına aynı anda basın." #: lib/solaar/ui/pair_window.py:195 msgid "The wireless link is not encrypted" msgstr "Kablosuz baÄŸlantı ÅŸifrelenmemiÅŸ" #: lib/solaar/ui/pair_window.py:200 msgid "Found a new device:" msgstr "Yeni bir aygıt bulundu:" #: lib/solaar/ui/pair_window.py:221 msgid "Pairing failed" msgstr "EÅŸleÅŸme baÅŸarısız" #: lib/solaar/ui/pair_window.py:223 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "Aygıtınızın kapsama alanı içerisinde olduÄŸundan, pilin çalıştığından veya " "ÅŸarjının tam olduÄŸundan emin olun." #: lib/solaar/ui/pair_window.py:225 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "Aygıt algılandı fakat bu alıcı ile uyumlu deÄŸil." #: lib/solaar/ui/pair_window.py:227 msgid "More paired devices than receiver can support." msgstr "Alıcının destekleyebileceÄŸinden daha fazla eÅŸleÅŸtirilmiÅŸ aygıt." #: lib/solaar/ui/pair_window.py:229 msgid "No further details are available about the error." msgstr "Hata hakkında daha fazla ayrıntı mevcut deÄŸil." #: lib/solaar/ui/rule_actions.py:48 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Akorlu tuÅŸ tıklaması, basması veya bırakması öykün.\n" "Wayland'da /dev/uinput'a yazma yetkisi gerektirir." #: lib/solaar/ui/rule_actions.py:53 msgid "Add key" msgstr "TuÅŸ ekle" #: lib/solaar/ui/rule_actions.py:56 msgid "Click" msgstr "Tıklama" #: lib/solaar/ui/rule_actions.py:59 msgid "Depress" msgstr "Basma" #: lib/solaar/ui/rule_actions.py:62 msgid "Release" msgstr "Bırakma" #: lib/solaar/ui/rule_actions.py:147 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Fare kayrıdması öykün.\n" "Wayland'da /dev/uinput'a yazma yetkisi gerektirir." #: lib/solaar/ui/rule_actions.py:203 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Fare tıklaması öykün.\n" "Wayland'da /dev/uinput'a yazma yetkisi gerektirir." #: lib/solaar/ui/rule_actions.py:206 msgid "Button" msgstr "Düğme" #: lib/solaar/ui/rule_actions.py:207 msgid "Count and Action" msgstr "Say ve İşle" #: lib/solaar/ui/rule_actions.py:256 msgid "Execute a command with arguments." msgstr "Argümanlarla bir komut çalıştır." #: lib/solaar/ui/rule_actions.py:259 msgid "Add argument" msgstr "Argüman ekle" #: lib/solaar/ui/rule_conditions.py:43 msgid "X11 active process. For use in X11 only." msgstr "X11 etkin iÅŸlem. Sadece X11'de kullanım için." #: lib/solaar/ui/rule_conditions.py:73 msgid "X11 mouse process. For use in X11 only." msgstr "X11 fare iÅŸlemi. Sadece X11'de kullanım için." #: lib/solaar/ui/rule_conditions.py:90 msgid "MouseProcess" msgstr "Fareİşlemi" #: lib/solaar/ui/rule_conditions.py:114 msgid "Feature name of notification triggering rule processing." msgstr "Bildirim tetikleme iÅŸlemi özelliÄŸi adı." #: lib/solaar/ui/rule_conditions.py:161 msgid "Report number of notification triggering rule processing." msgstr "Bildirim tetikleme iÅŸlemi rapor numarası." #: lib/solaar/ui/rule_conditions.py:194 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "Etkin klavye deÄŸiÅŸtiriciler. Wayland'da her zaman çalışmaz." #: lib/solaar/ui/rule_conditions.py:234 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "YönlendirilmiÅŸ tuÅŸ veya düğme basıldı veya bırakıldı.\n" "TuÅŸları ve düğmeleri yönlendirmek için TuÅŸ/Düğme Yönlendirme ve " "Yönlendirilen G TuÅŸları ayarlarını kullanın." #: lib/solaar/ui/rule_conditions.py:243 msgid "Key down" msgstr "TuÅŸ basılı" #: lib/solaar/ui/rule_conditions.py:246 msgid "Key up" msgstr "TuÅŸ serbest" #: lib/solaar/ui/rule_conditions.py:286 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "YönlendirilmiÅŸ tuÅŸ veya düğme ÅŸu anda basılı.\n" "TuÅŸları ve düğmeleri yönlendirmek için TuÅŸ/Düğme Yönlendirme ve " "Yönlendirilen G TuÅŸları ayarlarını kullanın." #: lib/solaar/ui/rule_conditions.py:324 msgid "Test condition on notification triggering rule processing." msgstr "Bildirim tetikleme iÅŸlemi test durumu." #: lib/solaar/ui/rule_conditions.py:328 msgid "Parameter" msgstr "Parametre" #: lib/solaar/ui/rule_conditions.py:401 msgid "begin (inclusive)" msgstr "baÅŸ (dahil edilen)" #: lib/solaar/ui/rule_conditions.py:402 msgid "end (exclusive)" msgstr "son (hariç tutulan)" #: lib/solaar/ui/rule_conditions.py:410 msgid "range" msgstr "aralık" #: lib/solaar/ui/rule_conditions.py:413 msgid "minimum" msgstr "en az" #: lib/solaar/ui/rule_conditions.py:414 msgid "maximum" msgstr "en çok" #: lib/solaar/ui/rule_conditions.py:416 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "%(0)d bayttan %(1)d bayta, %(2)d ile %(3)d arasında" #: lib/solaar/ui/rule_conditions.py:419 lib/solaar/ui/rule_conditions.py:420 msgid "mask" msgstr "maske" #: lib/solaar/ui/rule_conditions.py:421 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "%(0)d bayttan %(1)d bayta, %(2)d maskeleme" #: lib/solaar/ui/rule_conditions.py:430 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Bildirim mesajı tetikleyici kural iÅŸlemesinde baytlarda bit veya aralık " "testi." #: lib/solaar/ui/rule_conditions.py:440 msgid "type" msgstr "tür" #: lib/solaar/ui/rule_conditions.py:528 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "Sıfır veya daha fazla fare hareketinin ardından isteÄŸe baÄŸlı baÅŸlatma " "düğmesi ile fare hareketi." #: lib/solaar/ui/rule_conditions.py:533 msgid "Add movement" msgstr "Hareket ekle" #: lib/solaar/ui/tray.py:50 msgid "No supported device found" msgstr "Desteklenen aygıt bulunamadı" #: lib/solaar/ui/tray.py:55 lib/solaar/ui/window.py:310 #, python-format msgid "About %s" msgstr "%s Hakkında" #: lib/solaar/ui/tray.py:56 lib/solaar/ui/window.py:308 #, python-format msgid "Quit %s" msgstr "%s Çıkış" #: lib/solaar/ui/tray.py:267 lib/solaar/ui/tray.py:275 msgid "no receiver" msgstr "alıcı yok" #: lib/solaar/ui/tray.py:288 lib/solaar/ui/tray.py:293 msgid "offline" msgstr "çevrimdışı" #: lib/solaar/ui/tray.py:291 msgid "no status" msgstr "durum yok" #: lib/solaar/ui/window.py:91 msgid "Scanning" msgstr "Taranıyor" #: lib/solaar/ui/window.py:122 msgid "Battery" msgstr "Pil" #: lib/solaar/ui/window.py:125 msgid "Wireless Link" msgstr "Kablosuz BaÄŸlantı" #: lib/solaar/ui/window.py:129 msgid "Lighting" msgstr "Aydınlatma" #: lib/solaar/ui/window.py:163 msgid "Show Technical Details" msgstr "Teknik Ayrıntıları Göster" #: lib/solaar/ui/window.py:179 msgid "Pair new device" msgstr "Yeni aygıt eÅŸle" #: lib/solaar/ui/window.py:197 msgid "Select a device" msgstr "Aygıtı seç" #: lib/solaar/ui/window.py:313 msgid "Rule Editor" msgstr "Kural Düzenleyici" #: lib/solaar/ui/window.py:517 msgid "Path" msgstr "Yol" #: lib/solaar/ui/window.py:520 msgid "USB ID" msgstr "USB KimliÄŸi" #: lib/solaar/ui/window.py:523 lib/solaar/ui/window.py:525 #: lib/solaar/ui/window.py:540 lib/solaar/ui/window.py:542 msgid "Serial" msgstr "Seri" #: lib/solaar/ui/window.py:529 msgid "Index" msgstr "Dizin" #: lib/solaar/ui/window.py:531 msgid "Wireless PID" msgstr "Kablosuz baÄŸlantı kimliÄŸi" #: lib/solaar/ui/window.py:533 msgid "Product ID" msgstr "Ürün KimliÄŸi" #: lib/solaar/ui/window.py:535 msgid "Protocol" msgstr "İletiÅŸim kuralı" #: lib/solaar/ui/window.py:535 msgid "Unknown" msgstr "Bilinmeyen" #: lib/solaar/ui/window.py:537 msgid "Polling rate" msgstr "BaÄŸlantı sıklığı" #: lib/solaar/ui/window.py:544 msgid "Unit ID" msgstr "Birim KimliÄŸi" #: lib/solaar/ui/window.py:558 msgid "Notifications" msgstr "Bildirimler" #: lib/solaar/ui/window.py:602 msgid "No device paired." msgstr "EÅŸleÅŸtirilmiÅŸ aygıt yok." #: lib/solaar/ui/window.py:611 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "En fazla %(max_count)s aygıt bu alıcıyla eÅŸleÅŸebilir." msgstr[1] "En fazla %(max_count)s aygıt bu alıcıyla eÅŸleÅŸebilir." #: lib/solaar/ui/window.py:622 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Bu alıcı %d aygıtla daha eÅŸleÅŸebilir." msgstr[1] "Bu alıcı %d aygıtla daha eÅŸleÅŸebilir." #: lib/solaar/ui/window.py:679 msgid "Battery Voltage" msgstr "Pil Gerilimi" #: lib/solaar/ui/window.py:681 msgid "Voltage reported by battery" msgstr "Pil tarafından bildirilen gerilim" #: lib/solaar/ui/window.py:683 msgid "Battery Level" msgstr "Pil Düzeyi" #: lib/solaar/ui/window.py:685 msgid "Approximate level reported by battery" msgstr "Pil tarafından bildirilen yaklaşık düzeyi" #: lib/solaar/ui/window.py:692 lib/solaar/ui/window.py:694 msgid "next reported " msgstr "sonraki rapor " #: lib/solaar/ui/window.py:695 msgid " and next level to be reported." msgstr " ve sonraki seviye raporlanması." #: lib/solaar/ui/window.py:711 msgid "encrypted" msgstr "ÅŸifreli" #: lib/solaar/ui/window.py:713 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Bu aygıt ile alıcı arasındaki kablosuz baÄŸlantı ÅŸirelenmiÅŸtir." #: lib/solaar/ui/window.py:715 msgid "not encrypted" msgstr "ÅŸifresiz" #: lib/solaar/ui/window.py:719 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "Bu aygıt ile alıcı arasındaki kablosuz baÄŸlantı ÅŸirelenmemiÅŸtir.\n" "Bu iÅŸaretçi cihazlar için güvenlik açığı ve metin-giriÅŸ aygıtları için büyük " "bir güvenlik açığı." #: lib/solaar/ui/window.py:735 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lüks" Solaar-1.1.20/po/uk.po000066400000000000000000001523771522022367600144350ustar00rootroot00000000000000# Ukrainian translation for solaar # This file is distributed under the same license as the solaar package. # Kira, 2025. # msgid "" msgstr "" "Project-Id-Version: solaar 1.1.14\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-10-16 18:53+0300\n" "PO-Revision-Date: 2025-10-16 20:11+0300\n" "Last-Translator: ОлекÑ�андр Ð�фанаÑ�ьєв \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Приймач Bolt" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Приймач Unifying" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Ð�аноприймач" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Приймач Lightspeed" #: lib/logitech_receiver/base_usb.py:135 msgid "EX100 Receiver 27 Mhz" msgstr "Приймач EX100 27 МГц" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "БатареÑ�: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "БатареÑ�: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1023 #: lib/logitech_receiver/settings_templates.py:295 msgid "Disabled" msgstr "Вимкнено" #: lib/logitech_receiver/hidpp20.py:1024 msgid "Static" msgstr "Статичний" #: lib/logitech_receiver/hidpp20.py:1025 msgid "Pulse" msgstr "ПульÑ�аціÑ�" #: lib/logitech_receiver/hidpp20.py:1026 msgid "Cycle" msgstr "Цикл" #: lib/logitech_receiver/hidpp20.py:1027 msgid "Boot" msgstr "ЗавантаженнÑ�" #: lib/logitech_receiver/hidpp20.py:1028 msgid "Demo" msgstr "Демо" #: lib/logitech_receiver/hidpp20.py:1030 msgid "Breathe" msgstr "ДиханнÑ�" #: lib/logitech_receiver/hidpp20.py:1033 msgid "Ripple" msgstr "Брижі" #: lib/logitech_receiver/hidpp20.py:1034 msgid "Decomposition" msgstr "РозкладаннÑ�" #: lib/logitech_receiver/hidpp20.py:1035 msgid "Signature1" msgstr "ПідпиÑ�1" #: lib/logitech_receiver/hidpp20.py:1036 msgid "Signature2" msgstr "ПідпиÑ�2" #: lib/logitech_receiver/hidpp20.py:1037 msgid "CycleS" msgstr "ЦиклS" #: lib/logitech_receiver/hidpp20.py:1101 msgid "Unknown Location" msgstr "Ð�евідоме міÑ�це" #: lib/logitech_receiver/hidpp20.py:1102 msgid "Primary" msgstr "ОÑ�новний" #: lib/logitech_receiver/hidpp20.py:1103 msgid "Logo" msgstr "Логотип" #: lib/logitech_receiver/hidpp20.py:1104 msgid "Left Side" msgstr "Ліва Ñ�торона" #: lib/logitech_receiver/hidpp20.py:1105 msgid "Right Side" msgstr "Права Ñ�торона" #: lib/logitech_receiver/hidpp20.py:1106 msgid "Combined" msgstr "Комбінований" #: lib/logitech_receiver/hidpp20.py:1107 msgid "Primary 1" msgstr "ОÑ�новний 1" #: lib/logitech_receiver/hidpp20.py:1108 msgid "Primary 2" msgstr "ОÑ�новний 2" #: lib/logitech_receiver/hidpp20.py:1109 msgid "Primary 3" msgstr "ОÑ�новний 3" #: lib/logitech_receiver/hidpp20.py:1110 msgid "Primary 4" msgstr "ОÑ�новний 4" #: lib/logitech_receiver/hidpp20.py:1111 msgid "Primary 5" msgstr "ОÑ�новний 5" #: lib/logitech_receiver/hidpp20.py:1112 msgid "Primary 6" msgstr "ОÑ�новний 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "порожній" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "критичний" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "низький" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "Ñ�ередній" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "добрий" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "повний" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "розрÑ�джаєтьÑ�Ñ�" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "зарÑ�джаєтьÑ�Ñ�" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "зарÑ�джаєтьÑ�Ñ�" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "не зарÑ�джаєтьÑ�Ñ�" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "майже повний" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "зарÑ�джено" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "повільне зарÑ�джаннÑ�" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "неÑ�правна батареÑ�" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "термічна помилка" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "помилка" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "Ñ�тандартний" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "швидкий" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "повільний" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "тайм-аут приÑ�трою" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "приÑ�трій не підтримуєтьÑ�Ñ�" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "забагато приÑ�троїв" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "тайм-аут поÑ�лідовноÑ�ті" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "Мікропрограма" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "Завантажувач" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "ОбладнаннÑ�" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "Інше" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "Ліва кнопка" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "Права кнопка" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "СереднÑ� кнопка" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "Кнопка 'Ð�азад'" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "Кнопка 'Вперед'" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "Кнопка жеÑ�тів миші" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "Розумне перемиканнÑ�" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "Перемикач DPI" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "Ð�ахил вліво" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "Ð�ахил вправо" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "Лівий клік" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "Правий клік" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "СереднÑ� кнопка миші" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "Кнопка миші 'Ð�азад'" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "Кнопка миші 'Вперед'" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "Ð�авігаціÑ� кнопкою жеÑ�тів" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "Кнопка прокрутки миші вліво" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "Кнопка прокрутки миші вправо" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "натиÑ�нуто" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "відпущено" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "під'єднано" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "від'єднано" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "пару розірвано" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "увімкнено" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "Ñ�повіщеннÑ� про вимірюваннÑ� Ð�ЦП" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is closed" msgstr "блокуваннÑ� Ñ�твореннÑ� пари закрито" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is open" msgstr "блокуваннÑ� Ñ�твореннÑ� пари відкрито" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is closed" msgstr "блокуваннÑ� виÑ�вленнÑ� закрито" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is open" msgstr "блокуваннÑ� виÑ�вленнÑ� відкрито" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "Ð�емає під'єднаних приÑ�троїв." #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s під'єднаний приÑ�трій." msgstr[1] "%(count)s під'єднаних приÑ�троїв." msgstr[2] "%(count)s під'єднаних приÑ�троїв." #: lib/logitech_receiver/settings.py:598 msgid "register" msgstr "реєÑ�тр" #: lib/logitech_receiver/settings.py:612 lib/logitech_receiver/settings.py:650 msgid "feature" msgstr "функціÑ�" #: lib/logitech_receiver/settings_templates.py:134 msgid "Swap Fx function" msgstr "ПомінÑ�ти функцію Fx" #: lib/logitech_receiver/settings_templates.py:137 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "Якщо вÑ�тановлено, клавіші F1-F12 активуватимуть Ñ�вою Ñ�пеціальну функцію,\n" "Ñ– вам потрібно буде утримувати клавішу FN длÑ� активації Ñ�тандартної функції." #: lib/logitech_receiver/settings_templates.py:142 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "Якщо не вÑ�тановлено, клавіші F1-F12 активуватимуть Ñ�вою Ñ�тандартну функцію,\n" "Ñ– вам потрібно буде утримувати клавішу FN длÑ� активації Ñ�пеціальної функції." #: lib/logitech_receiver/settings_templates.py:150 msgid "Hand Detection" msgstr "ВиÑ�вленнÑ� рук" #: lib/logitech_receiver/settings_templates.py:151 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "Вмикати підÑ�вічуваннÑ�, коли руки знаходÑ�тьÑ�Ñ� над клавіатурою." #: lib/logitech_receiver/settings_templates.py:158 msgid "Scroll Wheel Smooth Scrolling" msgstr "Плавне прокручуваннÑ� коліщатка" #: lib/logitech_receiver/settings_templates.py:159 #: lib/logitech_receiver/settings_templates.py:406 #: lib/logitech_receiver/settings_templates.py:435 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "Режим виÑ�окої чутливоÑ�ті длÑ� вертикального прокручуваннÑ� коліщатком." #: lib/logitech_receiver/settings_templates.py:166 msgid "Side Scrolling" msgstr "Бічне прокручуваннÑ�" #: lib/logitech_receiver/settings_templates.py:168 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "Якщо вимкнено, натиÑ�каннÑ� коліщатка вбік надÑ�илає Ñ�пеціальні події кнопок\n" "заміÑ�ть Ñ�тандартних подій бічного прокручуваннÑ�." #: lib/logitech_receiver/settings_templates.py:178 msgid "Sensitivity (DPI - older mice)" msgstr "ЧутливіÑ�ть (DPI - длÑ� Ñ�тарих мишей)" #: lib/logitech_receiver/settings_templates.py:179 #: lib/logitech_receiver/settings_templates.py:983 #: lib/logitech_receiver/settings_templates.py:1011 msgid "Mouse movement sensitivity" msgstr "ЧутливіÑ�ть руху миші" #: lib/logitech_receiver/settings_templates.py:252 msgid "Backlight Timed" msgstr "ПідÑ�вічуваннÑ� за таймером" #: lib/logitech_receiver/settings_templates.py:253 #: lib/logitech_receiver/settings_templates.py:393 msgid "Set illumination time for keyboard." msgstr "Ð’Ñ�тановити чаÑ� підÑ�вічуваннÑ� клавіатури." #: lib/logitech_receiver/settings_templates.py:264 msgid "Backlight" msgstr "ПідÑ�вічуваннÑ�" #: lib/logitech_receiver/settings_templates.py:265 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "" "Рівень підÑ�вічуваннÑ� клавіатури. Зміни заÑ�тоÑ�овуютьÑ�Ñ� лише в ручному режимі." #: lib/logitech_receiver/settings_templates.py:297 msgid "Automatic" msgstr "Ð�втоматично" #: lib/logitech_receiver/settings_templates.py:299 msgid "Manual" msgstr "Вручну" #: lib/logitech_receiver/settings_templates.py:301 msgid "Enabled" msgstr "Увімкнено" #: lib/logitech_receiver/settings_templates.py:307 msgid "Backlight Level" msgstr "Рівень підÑ�вічуваннÑ�" #: lib/logitech_receiver/settings_templates.py:308 msgid "Illumination level on keyboard when in Manual mode." msgstr "Рівень підÑ�вічуваннÑ� клавіатури в ручному режимі." #: lib/logitech_receiver/settings_templates.py:365 msgid "Backlight Delay Hands Out" msgstr "Затримка підÑ�вічуваннÑ� (руки прибрано)" #: lib/logitech_receiver/settings_templates.py:366 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "" "Затримка в Ñ�екундах до згаÑ�аннÑ� підÑ�вічуваннÑ�, коли руки прибрані з " "клавіатури." #: lib/logitech_receiver/settings_templates.py:374 msgid "Backlight Delay Hands In" msgstr "Затримка підÑ�вічуваннÑ� (руки на клавіатурі)" #: lib/logitech_receiver/settings_templates.py:375 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "" "Затримка в Ñ�екундах до згаÑ�аннÑ� підÑ�вічуваннÑ�, коли руки білÑ� клавіатури." #: lib/logitech_receiver/settings_templates.py:383 msgid "Backlight Delay Powered" msgstr "Затримка підÑ�вічуваннÑ� (від живленнÑ�)" #: lib/logitech_receiver/settings_templates.py:384 msgid "Delay in seconds until backlight fades out with external power." msgstr "" "Затримка в Ñ�екундах до згаÑ�аннÑ� підÑ�вічуваннÑ� при зовнішньому живленні." #: lib/logitech_receiver/settings_templates.py:392 msgid "Backlight (Seconds)" msgstr "ПідÑ�вічуваннÑ� (Ñ�екунди)" #: lib/logitech_receiver/settings_templates.py:404 msgid "Scroll Wheel High Resolution" msgstr "ВиÑ�ока роздільна здатніÑ�ть коліщатка" #: lib/logitech_receiver/settings_templates.py:408 #: lib/logitech_receiver/settings_templates.py:437 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "Ігнорувати, Ñ�кщо прокручуваннÑ� ненормально швидке або повільне" #: lib/logitech_receiver/settings_templates.py:415 #: lib/logitech_receiver/settings_templates.py:446 msgid "Scroll Wheel Diversion" msgstr "ПеренаправленнÑ� коліщатка прокрутки" #: lib/logitech_receiver/settings_templates.py:417 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "ПримуÑ�ити коліщатко прокрутки надÑ�илати Ñ�повіщеннÑ� LOWRES_WHEEL HID++ (Ñ�кі " "запуÑ�кають правила Solaar, але в іншому випадку ігноруютьÑ�Ñ�)." #: lib/logitech_receiver/settings_templates.py:424 msgid "Scroll Wheel Direction" msgstr "Ð�апрÑ�мок прокручуваннÑ� коліщатка" #: lib/logitech_receiver/settings_templates.py:425 msgid "Invert direction for vertical scroll with wheel." msgstr "Інвертувати напрÑ�мок вертикального прокручуваннÑ� коліщатком." #: lib/logitech_receiver/settings_templates.py:433 msgid "Scroll Wheel Resolution" msgstr "Роздільна здатніÑ�ть коліщатка прокрутки" #: lib/logitech_receiver/settings_templates.py:448 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "ПримуÑ�ити коліщатко прокрутки надÑ�илати Ñ�повіщеннÑ� HIRES_WHEEL HID++ (Ñ�кі " "запуÑ�кають правила Solaar, але в іншому випадку ігноруютьÑ�Ñ�)." #: lib/logitech_receiver/settings_templates.py:457 msgid "Sensitivity (Pointer Speed)" msgstr "ЧутливіÑ�ть (швидкіÑ�ть вказівника)" #: lib/logitech_receiver/settings_templates.py:458 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "Множник швидкоÑ�ті длÑ� миші (256 — звичайний множник)." #: lib/logitech_receiver/settings_templates.py:468 msgid "Thumb Wheel Diversion" msgstr "ПеренаправленнÑ� коліщатка длÑ� великого пальцÑ�" #: lib/logitech_receiver/settings_templates.py:470 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "ПримуÑ�ити коліщатко длÑ� великого пальцÑ� надÑ�илати Ñ�повіщеннÑ� THUMB_WHEEL HID+" "+ (Ñ�кі запуÑ�кають правила Solaar, але в іншому випадку ігноруютьÑ�Ñ�)." #: lib/logitech_receiver/settings_templates.py:479 msgid "Thumb Wheel Direction" msgstr "Ð�апрÑ�мок коліщатка длÑ� великого пальцÑ�" #: lib/logitech_receiver/settings_templates.py:480 msgid "Invert thumb wheel scroll direction." msgstr "Інвертувати напрÑ�мок прокручуваннÑ� коліщатка длÑ� великого пальцÑ�." #: lib/logitech_receiver/settings_templates.py:500 msgid "Onboard Profiles" msgstr "Вбудовані профілі" #: lib/logitech_receiver/settings_templates.py:501 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "" "Увімкнути вбудований профіль, Ñ�кий контролює чаÑ�тоту опитуваннÑ�, чутливіÑ�ть " "та дії кнопок" #: lib/logitech_receiver/settings_templates.py:545 #: lib/logitech_receiver/settings_templates.py:578 msgid "Report Rate" msgstr "ЧаÑ�тота опитуваннÑ�" #: lib/logitech_receiver/settings_templates.py:547 #: lib/logitech_receiver/settings_templates.py:580 msgid "Frequency of device movement reports" msgstr "ЧаÑ�тота звітів про рух приÑ�трою" #: lib/logitech_receiver/settings_templates.py:547 #: lib/logitech_receiver/settings_templates.py:580 #: lib/logitech_receiver/settings_templates.py:1011 #: lib/logitech_receiver/settings_templates.py:1385 #: lib/logitech_receiver/settings_templates.py:1416 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "ДлÑ� ефективноÑ�ті може знадобитиÑ�Ñ� вимкнути вбудовані профілі." #: lib/logitech_receiver/settings_templates.py:608 msgid "Divert crown events" msgstr "ПеренаправлÑ�ти події коронки" #: lib/logitech_receiver/settings_templates.py:609 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "ПримуÑ�ити коронку надÑ�илати Ñ�повіщеннÑ� CROWN HID++ (Ñ�кі запуÑ�кають правила " "Solaar, але в іншому випадку ігноруютьÑ�Ñ�)." #: lib/logitech_receiver/settings_templates.py:617 msgid "Crown smooth scroll" msgstr "Плавне прокручуваннÑ� коронкою" #: lib/logitech_receiver/settings_templates.py:618 msgid "Set crown smooth scroll" msgstr "Ð’Ñ�тановити плавне прокручуваннÑ� коронкою" #: lib/logitech_receiver/settings_templates.py:626 msgid "Divert G and M Keys" msgstr "Перенаправити клавіші G та M" #: lib/logitech_receiver/settings_templates.py:627 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "ПримуÑ�ити клавіші G та M надÑ�илати Ñ�повіщеннÑ� HID++ (Ñ�кі запуÑ�кають правила " "Solaar, але в іншому випадку ігноруютьÑ�Ñ�)." #: lib/logitech_receiver/settings_templates.py:641 msgid "Scroll Wheel Ratcheted" msgstr "ТріÑ�качка коліщатка прокрутки" #: lib/logitech_receiver/settings_templates.py:642 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "" "ПеремиканнÑ� коліщатка миші між тріÑ�качкою з контролем швидкоÑ�ті та вільним " "обертаннÑ�м." #: lib/logitech_receiver/settings_templates.py:644 msgid "Freespinning" msgstr "Вільне обертаннÑ�" #: lib/logitech_receiver/settings_templates.py:644 msgid "Ratcheted" msgstr "ТріÑ�качка" #: lib/logitech_receiver/settings_templates.py:651 msgid "Scroll Wheel Ratchet Speed" msgstr "ШвидкіÑ�ть тріÑ�качки коліщатка прокрутки" #: lib/logitech_receiver/settings_templates.py:653 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "ВикориÑ�товуйте швидкіÑ�ть коліщатка миші длÑ� перемиканнÑ� між тріÑ�качкою та " "вільним обертаннÑ�м.\n" "Коліщатко миші завжди має тріÑ�качку на 50." #: lib/logitech_receiver/settings_templates.py:707 msgid "Key/Button Actions" msgstr "Дії клавіш/кнопок" #: lib/logitech_receiver/settings_templates.py:709 msgid "Change the action for the key or button." msgstr "Змінити дію длÑ� клавіші або кнопки." #: lib/logitech_receiver/settings_templates.py:711 msgid "Overridden by diversion." msgstr "Перевизначено перенаправленнÑ�м." #: lib/logitech_receiver/settings_templates.py:713 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "" "Зміна важливих дій (наприклад, длÑ� лівої кнопки миші) може призвеÑ�ти до " "непрацездатноÑ�ті Ñ�иÑ�теми." #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "Інший процеÑ� Solaar вже запущено, тому проÑ�то показуємо його вікно" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "Керує приймачами, клавіатурами,\n" "мишами та планшетами Logitech." #: lib/solaar/ui/about/model.py:63 msgid "Additional Programming" msgstr "Додаткове програмуваннÑ�" #: lib/solaar/ui/about/model.py:64 msgid "GUI design" msgstr "Дизайн GUI" #: lib/solaar/ui/about/model.py:66 msgid "Testing" msgstr "ТеÑ�туваннÑ�" #: lib/solaar/ui/about/model.py:74 msgid "Logitech documentation" msgstr "ДокументаціÑ� Logitech" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "Розірвати пару" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "СкаÑ�увати" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "Помилка дозволів" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "" "Знайдено приймач або приÑ�трій Logitech (%s), але немає дозволу на його " "відкриттÑ�." #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "" "Якщо ви щойно вÑ�тановили Solaar, Ñ�пробуйте від'єднати та знову під'єднати " "приймач або приÑ�трій." #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "Помилка підключеннÑ� до приÑ�трою" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "" "Знайдено приймач або приÑ�трій Logitech за адреÑ�ою %s, але виникла помилка " "при підключенні до нього." #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "" "Спробуйте від'єднати та знову під'єднати приÑ�трій або вимкнути та увімкнути " "його." #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "Ð�е вдалоÑ�Ñ� розірвати пару" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "Ð�е вдалоÑ�Ñ� розірвати пару між %{device} та %{receiver}." #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "Приймач повернув помилку без додаткових деталей." #: lib/solaar/ui/config_panel.py:241 msgid "Complete - ENTER to change" msgstr "Завершено - ENTER длÑ� зміни" #: lib/solaar/ui/config_panel.py:241 msgid "Incomplete" msgstr "Ð�е завершено" #: lib/solaar/ui/config_panel.py:487 lib/solaar/ui/config_panel.py:539 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d значеннÑ�" msgstr[1] "%d значеннÑ�" msgstr[2] "%d значень" #: lib/solaar/ui/config_panel.py:621 msgid "Changes allowed" msgstr "Зміни дозволено" #: lib/solaar/ui/config_panel.py:622 msgid "No changes allowed" msgstr "Зміни не дозволено" #: lib/solaar/ui/config_panel.py:623 msgid "Ignore this setting" msgstr "Ігнорувати це налаштуваннÑ�" #: lib/solaar/ui/config_panel.py:667 msgid "Working" msgstr "Працюю" #: lib/solaar/ui/config_panel.py:670 msgid "Read/write operation failed." msgstr "ОпераціÑ� читаннÑ�/запиÑ�у не вдалаÑ�Ñ�." #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "невідома причина" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "Вбудовані правила" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "Правила кориÑ�тувача" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "Правило" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "Підправило" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "[порожньо]" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "Зробити зміни поÑ�тійними?" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "Так" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "Ð�Ñ–" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "Якщо ви оберете 'Ð�Ñ–', зміни буде втрачено при закритті Solaar." #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "Ð’Ñ�тавити Ñ�юди" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "Ð’Ñ�тавити вище" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "Ð’Ñ�тавити нижче" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "Ð’Ñ�тавити правило Ñ�юди" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "Ð’Ñ�тавити правило вище" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "Ð’Ñ�тавити правило нижче" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "Ð’Ñ�тавити правило" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "Ð’Ñ�тавити Ñ�юди" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "Ð’Ñ�тавити вище" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "Ð’Ñ�тавити нижче" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "Ð’Ñ�тавити нове правило Ñ�юди" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "Ð’Ñ�тавити нове правило вище" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "Ð’Ñ�тавити нове правило нижче" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "Сплощити" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "Ð’Ñ�тавити" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "Ð�бо" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "І" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "Умова" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "ФункціÑ�" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "Звіт" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "ПроцеÑ�" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "ПроцеÑ� миші" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "Модифікатори" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "Клавіша" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "КлавішаÐ�атиÑ�нута" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "Ð�ктивний" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "ПриÑ�трій" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "ХоÑ�Ñ‚" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "Ð�алаштуваннÑ�" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "ТеÑ�Ñ‚" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "ТеÑ�тові байти" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "ЖеÑ�Ñ‚ миші" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "ДіÑ�" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "Ð�атиÑ�каннÑ� клавіші" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "ПрокручуваннÑ� миші" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:254 msgid "Mouse click" msgstr "Клік миші" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "Ð’Ñ�тановити" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:326 msgid "Execute" msgstr "Виконати" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "Пізніше" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "Ð’Ñ�тавити нове правило" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:285 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "Видалити" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "Заперечити" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "Огорнути в" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "Вирізати" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "Ð’Ñ�тавити" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "Копіювати" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "Редактор правил Solaar" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "Зберегти зміни" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "СкаÑ�увати зміни" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "Цей редактор ще не підтримує вибраний компонент правила." #: lib/solaar/ui/diversion_rules.py:1169 msgid "" "Number of seconds to delay.\n" "Delay between 0 and 1 is done with higher precision." msgstr "" "КількіÑ�ть Ñ�екунд длÑ� затримки.\n" "Затримка від 0 до 1 виконуєтьÑ�Ñ� з вищою точніÑ�тю." #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "Ð�е" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "Перемкнути" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "ІÑ�тина" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "Хиба" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "Ð�алаштуваннÑ� не підтримуєтьÑ�Ñ�" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "ПриÑ�трій-джерело" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "ПриÑ�трій активний, Ñ– його налаштуваннÑ� можна змінювати." #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "ПриÑ�трій, Ñ�кий надіÑ�лав поточне Ñ�повіщеннÑ�." #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "Ім'Ñ� комп'ютера-хоÑ�та." #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "ЗначеннÑ�" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "Елемент" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "Змінити налаштуваннÑ� на приÑ�трої" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "Ð�алаштуваннÑ� на приÑ�трої" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: Ñ�творити пару з новим приÑ�троєм" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Приймачі Bolt Ñ�уміÑ�ні лише з приÑ�троÑ�ми Bolt." #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "" "Ð�атиÑ�ніть кнопку або клавішу Ñ�твореннÑ� пари, доки індикатор не почне швидко " "блимати." #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Приймачі Unifying Ñ�уміÑ�ні лише з приÑ�троÑ�ми Unifying." #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "Інші приймачі Ñ�уміÑ�ні лише з кількома приÑ�троÑ�ми." #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "" "ДлÑ� більшоÑ�ті приÑ�троїв увімкніть приÑ�трій, з Ñ�ким хочете Ñ�творити пару." #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "Якщо приÑ�трій уже увімкнено, вимкніть його та увімкніть знову." #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "" "ПриÑ�трій не повинен бути з'єднаний з іншим увімкненим приймачем поблизу." #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "ДлÑ� приÑ�троїв з кількома каналами натиÑ�ніть, утримуйте та відпуÑ�тіть кнопку " "потрібного каналу\n" "або Ñ�кориÑ�тайтеÑ�Ñ� кнопкою перемиканнÑ� каналів, щоб вибрати канал, а потім " "натиÑ�ніть, утримуйте та відпуÑ�тіть Ñ—Ñ—." #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "Індикатор каналу повинен швидко блимати." #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "Цей приймач має ще %d Ñ�пробу Ñ�твореннÑ� пари." msgstr[1] "" "\n" "\n" "Цей приймач має ще %d Ñ�проби Ñ�твореннÑ� пари." msgstr[2] "" "\n" "\n" "Цей приймач має ще %d Ñ�проб Ñ�твореннÑ� пари." #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "СкаÑ�уваннÑ� на цьому етапі не викориÑ�тає Ñ�пробу Ñ�твореннÑ� пари." #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "Введіть пароль на %(name)s." #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "Введіть %(passcode)s, а потім натиÑ�ніть клавішу Enter." #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "ліва" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "права" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "Ð�атиÑ�ніть %(code)s\n" ", а потім одночаÑ�но натиÑ�ніть ліву та праву кнопки." #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "Бездротове з'єднаннÑ� не зашифроване" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "Знайдено новий приÑ�трій:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "Ð�е вдалоÑ�Ñ� Ñ�творити пару" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "" "ПереконайтеÑ�Ñ�, що ваш приÑ�трій знаходитьÑ�Ñ� в зоні доÑ�Ñ�жноÑ�ті та має " "доÑ�татній зарÑ�д батареї." #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "Було виÑ�влено новий приÑ�трій, але він не Ñ�уміÑ�ний з цим приймачем." #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "Більше під'єднаних приÑ�троїв, ніж може підтримувати приймач." #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "Додаткові відомоÑ�ті про помилку відÑ�утні." #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Імітувати натиÑ�каннÑ�, утриманнÑ� або відпуÑ�каннÑ� комбінації клавіш.\n" "У Wayland потрібен дозвіл на запиÑ� до /dev/uinput." #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "Додати клавішу" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "Клік" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "Ð�атиÑ�нути" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "ВідпуÑ�тити" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Імітувати прокручуваннÑ� миші.\n" "У Wayland потрібен дозвіл на запиÑ� до /dev/uinput." #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "Імітувати клік миші.\n" "У Wayland потрібен дозвіл на запиÑ� до /dev/uinput." #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "Кнопка" #: lib/solaar/ui/rule_actions.py:217 msgid "Count and Action" msgstr "КількіÑ�ть та діÑ�" #: lib/solaar/ui/rule_actions.py:267 msgid "Execute a command with arguments." msgstr "Виконати команду з аргументами." #: lib/solaar/ui/rule_actions.py:271 msgid "Add argument" msgstr "Додати аргумент" #: lib/solaar/ui/rule_conditions.py:52 msgid "" "X11 active process.\n" "For use in X11 only." msgstr "" "Ð�ктивний процеÑ� X11.\n" "ВикориÑ�товувати лише в X11." #: lib/solaar/ui/rule_conditions.py:82 msgid "" "X11 mouse process.\n" "For use in X11 only." msgstr "" "ПроцеÑ� миші X11.\n" "ВикориÑ�товувати лише в X11." #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "ПроцеÑ�Миші" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "Ð�азва функції Ñ�повіщеннÑ�, що запуÑ�кає обробку правила." #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "Ð�омер звіту Ñ�повіщеннÑ�, що запуÑ�кає обробку правила." #: lib/solaar/ui/rule_conditions.py:201 msgid "" "Active keyboard modifiers.\n" "Not always available in Wayland." msgstr "" "Ð�ктивні модифікатори клавіатури.\n" "Ð�е завжди доÑ�тупні у Wayland." #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Перенаправлена клавіша або кнопка натиÑ�нута чи відпущена.\n" "ВикориÑ�товуйте налаштуваннÑ� 'ПеренаправленнÑ� клавіш/кнопок' та " "'Перенаправити G-клавіші' длÑ� перенаправленнÑ�." #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "Клавішу натиÑ�нуто" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "Клавішу відпущено" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "Перенаправлена клавіша або кнопка зараз натиÑ�нута.\n" "ВикориÑ�товуйте налаштуваннÑ� 'ПеренаправленнÑ� клавіш/кнопок' та " "'Перенаправити G-клавіші' длÑ� перенаправленнÑ�." #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "Перевірка умови длÑ� Ñ�повіщеннÑ�, що запуÑ�кає обробку правила." #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "Параметр" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "початок (включно)" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "кінець (виключно)" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "діапазон" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "мінімум" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "макÑ�имум" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "байти від %(0)d до %(1)d, в діапазоні від %(2)d до %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "маÑ�ка" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "байти від %(0)d до %(1)d, маÑ�ка %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "" "Бітовий або діапазонний теÑ�Ñ‚ байтів у повідомленні-Ñ�повіщенні, що запуÑ�кає " "обробку правила." #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "тип" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "" "ЖеÑ�Ñ‚ миші з необов'Ñ�зковою кнопкою-ініціатором, за Ñ�кою Ñ�лідують нуль або " "більше рухів миші." #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "Додати рух" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "Ð�е знайдено підтримуваних приÑ�троїв" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "Про %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "Вийти з %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "немає приймача" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:728 msgid "offline" msgstr "офлайн" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "немає Ñ�татуÑ�у" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "СкануваннÑ�" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "БатареÑ�" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "Бездротове з'єднаннÑ�" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "ПідÑ�вічуваннÑ�" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "Показати технічні деталі" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "Створити пару з новим приÑ�троєм" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "Виберіть приÑ�трій" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "Редактор правил" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "ШлÑ�Ñ…" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546 msgid "Serial" msgstr "Серійний номер" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "ІндекÑ�" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "Бездротовий PID" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "ID продукту" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "Протокол" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "Ð�евідомо" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "ЧаÑ�тота опитуваннÑ�" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "ID одиниці" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "немає" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "СповіщеннÑ�" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "Ð�емає під'єднаних приÑ�троїв." #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "До цього приймача можна під'єднати до %(max_count)s приÑ�трою." msgstr[1] "До цього приймача можна під'єднати до %(max_count)s приÑ�троїв." msgstr[2] "До цього приймача можна під'єднати до %(max_count)s приÑ�троїв." #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "До цього приймача можна під'єднати лише один приÑ�трій." #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "Цей приймач має ще %d Ñ�пробу Ñ�твореннÑ� пари." msgstr[1] "Цей приймач має ще %d Ñ�проби Ñ�твореннÑ� пари." msgstr[2] "Цей приймач має ще %d Ñ�проб Ñ�твореннÑ� пари." #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "Ð�апруга батареї" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "Ð�апруга, що повідомлÑ�єтьÑ�Ñ� батареєю" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "Рівень зарÑ�ду батареї" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "Приблизний рівень, що повідомлÑ�єтьÑ�Ñ� батареєю" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "наÑ�тупний повідомлений " #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr " та наÑ�тупний рівень, що буде повідомлено." #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "оÑ�танній відомий" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "зашифровано" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "Бездротове з'єднаннÑ� між цим приÑ�троєм та його приймачем зашифроване." #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "не зашифровано" #: lib/solaar/ui/window.py:721 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "Бездротове з'єднаннÑ� між цим приÑ�троєм та його приймачем не зашифроване.\n" "Це проблема безпеки длÑ� вказівних приÑ�троїв та Ñ�ерйозна проблема безпеки длÑ� " "приÑ�троїв введеннÑ� текÑ�ту." #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d люкÑ�" Solaar-1.1.20/po/zh_CN.po000066400000000000000000001702121522022367600150030ustar00rootroot00000000000000# Chinese translations for solaar package # Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2014. # ZH , 2014. # Rongrong , 2022. msgid "" msgstr "" "Project-Id-Version: solaar 1.1.13\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-07-01 13:49+0800\n" "PO-Revision-Date: 2026-05-24 01:16+0800\n" "Last-Translator: Rongrong \n" "Language-Team: none\n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Language: zh_CN\n" "X-Source-Language: C\n" "X-Generator: Poedit 3.9\n" #: lib/logitech_receiver/base_usb.py:45 msgid "Bolt Receiver" msgstr "Bolt 接收器" #: lib/logitech_receiver/base_usb.py:57 msgid "Unifying Receiver" msgstr "优è�”接收器" #: lib/logitech_receiver/base_usb.py:68 lib/logitech_receiver/base_usb.py:80 #: lib/logitech_receiver/base_usb.py:93 lib/logitech_receiver/base_usb.py:106 #: lib/logitech_receiver/base_usb.py:119 msgid "Nano Receiver" msgstr "微型接收器" #: lib/logitech_receiver/base_usb.py:131 msgid "Lightspeed Receiver" msgstr "Lightspeed 接收器" #: lib/logitech_receiver/base_usb.py:141 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 接收器 (27MHz)" #: lib/logitech_receiver/common.py:610 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "电池: %(level)s (%(status)s)" #: lib/logitech_receiver/common.py:613 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "电池: %(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:921 #: lib/logitech_receiver/settings_templates.py:283 msgid "Disabled" msgstr "ç¦�用" #: lib/logitech_receiver/hidpp20.py:922 msgid "Static" msgstr "é�™æ€�" #: lib/logitech_receiver/hidpp20.py:923 msgid "Pulse" msgstr "脉冲" #: lib/logitech_receiver/hidpp20.py:924 msgid "Cycle" msgstr "循环" #: lib/logitech_receiver/hidpp20.py:925 msgid "Boot" msgstr "å�¯åЍ" #: lib/logitech_receiver/hidpp20.py:926 msgid "Demo" msgstr "演示" #: lib/logitech_receiver/hidpp20.py:927 msgid "Breathe" msgstr "呼å�¸" #: lib/logitech_receiver/hidpp20.py:928 msgid "Ripple" msgstr "涟漪" #: lib/logitech_receiver/hidpp20.py:929 msgid "Decomposition" msgstr "分解" #: lib/logitech_receiver/hidpp20.py:930 msgid "Signature1" msgstr "ç­¾å��1" #: lib/logitech_receiver/hidpp20.py:931 msgid "Signature2" msgstr "ç­¾å��2" #: lib/logitech_receiver/hidpp20.py:932 msgid "CycleS" msgstr "饱和度循环" #: lib/logitech_receiver/hidpp20.py:996 msgid "Unknown Location" msgstr "未知ä½�ç½®" #: lib/logitech_receiver/hidpp20.py:997 msgid "Primary" msgstr "主è¦�" #: lib/logitech_receiver/hidpp20.py:998 msgid "Logo" msgstr "标志" #: lib/logitech_receiver/hidpp20.py:999 msgid "Left Side" msgstr "左侧" #: lib/logitech_receiver/hidpp20.py:1000 msgid "Right Side" msgstr "å�³ä¾§" #: lib/logitech_receiver/hidpp20.py:1001 msgid "Combined" msgstr "å�ˆå¹¶" #: lib/logitech_receiver/hidpp20.py:1002 msgid "Primary 1" msgstr "主è¦� 1" #: lib/logitech_receiver/hidpp20.py:1003 msgid "Primary 2" msgstr "主è¦� 2" #: lib/logitech_receiver/hidpp20.py:1004 msgid "Primary 3" msgstr "主è¦� 3" #: lib/logitech_receiver/hidpp20.py:1005 msgid "Primary 4" msgstr "主è¦� 4" #: lib/logitech_receiver/hidpp20.py:1006 msgid "Primary 5" msgstr "主è¦� 5" #: lib/logitech_receiver/hidpp20.py:1007 msgid "Primary 6" msgstr "主è¦�6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "空" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "æž�低" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "低" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "å¹³å�‡" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "良好" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "全满" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "放电中" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "充电中" #: lib/logitech_receiver/i18n.py:37 msgid "charging" msgstr "正充电" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "未在充电" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "接近全满" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "已充满" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "慢速充电" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "电池无效" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "温度异常" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "异常" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "标准" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "快速" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "慢速" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "设备超时" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "ä¸�支æŒ�的设备" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "设备数é‡�太多" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "åº�列超时" #: lib/logitech_receiver/i18n.py:54 msgid "Firmware" msgstr "固件" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "å�¯åЍ噍" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "硬件" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "å…¶ä»–" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "左键" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "å�³é”®" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "中键" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "返回键" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "å‰�进键" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "鼠标手势按钮" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "SmartShift" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "DPI 切æ�¢" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "滚轮å�‘左倾斜" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "滚轮å�‘å�³å€¾æ–œ" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "左击" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "å�³å‡»" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "鼠标中键" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "鼠标返回键" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "é¼ æ ‡å‰�进键" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "手势按钮导航" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "é¼ æ ‡å�‘左滚动键" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "é¼ æ ‡å�‘å�³æ»šåЍ键" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "按下" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "释放" #: lib/logitech_receiver/notifications.py:64 #: lib/logitech_receiver/notifications.py:116 msgid "pairing lock is closed" msgstr "é…�对é”�已关闭" #: lib/logitech_receiver/notifications.py:64 #: lib/logitech_receiver/notifications.py:116 msgid "pairing lock is open" msgstr "é…�对é”�已打开" #: lib/logitech_receiver/notifications.py:81 msgid "discovery lock is closed" msgstr "å�‘现é”�已关闭" #: lib/logitech_receiver/notifications.py:81 msgid "discovery lock is open" msgstr "å�‘现é”�已打开" #: lib/logitech_receiver/notifications.py:210 lib/solaar/listener.py:238 msgid "connected" msgstr "已连接" #: lib/logitech_receiver/notifications.py:210 lib/solaar/listener.py:238 msgid "disconnected" msgstr "已断开" #: lib/logitech_receiver/notifications.py:236 msgid "unpaired" msgstr "未é…�对" #: lib/logitech_receiver/notifications.py:283 msgid "powered on" msgstr "已上电" #: lib/logitech_receiver/receiver.py:371 msgid "No paired devices." msgstr "æ— å·²é…�对设备。" #: lib/logitech_receiver/receiver.py:373 lib/solaar/ui/window.py:604 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s 个已é…�对设备。" #: lib/logitech_receiver/settings.py:611 msgid "register" msgstr "注册" #: lib/logitech_receiver/settings.py:625 lib/logitech_receiver/settings.py:651 msgid "feature" msgstr "特性" #: lib/logitech_receiver/settings_templates.py:122 msgid "Swap Fx function" msgstr "互æ�¢ Fx 键功能" #: lib/logitech_receiver/settings_templates.py:125 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "若开å�¯ï¼ŒF1 到 F12 键会激活特殊功能,\n" "使用标准功能请å�Œæ—¶æŒ‰ä½� FN 键。" #: lib/logitech_receiver/settings_templates.py:130 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "若关闭,F1 到 F12 键会激活标准功能,\n" "使用特殊功能请å�Œæ—¶æŒ‰ä½� FN 键。" #: lib/logitech_receiver/settings_templates.py:138 msgid "Hand Detection" msgstr "手掌识别" #: lib/logitech_receiver/settings_templates.py:139 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "手掌置于键盘上方时开å�¯ç…§æ˜Žã€‚" #: lib/logitech_receiver/settings_templates.py:146 msgid "Scroll Wheel Smooth Scrolling" msgstr "滚轮平滑滚动" #: lib/logitech_receiver/settings_templates.py:147 #: lib/logitech_receiver/settings_templates.py:394 #: lib/logitech_receiver/settings_templates.py:423 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "滚轮高分辨率滚动模å¼�。" #: lib/logitech_receiver/settings_templates.py:154 msgid "Side Scrolling" msgstr "ä¾§å�‘滚轮" #: lib/logitech_receiver/settings_templates.py:156 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "è‹¥ç¦�用,侧å�‘推动滚轮将å�‘é€�自定义按钮事件\n" "而ä¸�是标准侧å�‘滚动事件。" #: lib/logitech_receiver/settings_templates.py:166 msgid "Sensitivity (DPI - older mice)" msgstr "ç�µæ•�度 (DPI - 旧款鼠标)" #: lib/logitech_receiver/settings_templates.py:167 #: lib/logitech_receiver/settings_templates.py:955 #: lib/logitech_receiver/settings_templates.py:983 msgid "Mouse movement sensitivity" msgstr "鼠标移动ç�µæ•�度" #: lib/logitech_receiver/settings_templates.py:240 msgid "Backlight Timed" msgstr "定时背光" #: lib/logitech_receiver/settings_templates.py:241 #: lib/logitech_receiver/settings_templates.py:381 msgid "Set illumination time for keyboard." msgstr "为键盘设置背光时间。" #: lib/logitech_receiver/settings_templates.py:252 msgid "Backlight" msgstr "背光" #: lib/logitech_receiver/settings_templates.py:253 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "键盘亮度等级。仅在手动模å¼�下å�¯ç”¨" #: lib/logitech_receiver/settings_templates.py:285 msgid "Automatic" msgstr "自动" #: lib/logitech_receiver/settings_templates.py:287 msgid "Manual" msgstr "手动" #: lib/logitech_receiver/settings_templates.py:289 msgid "Enabled" msgstr "å·²å�¯ç”¨" #: lib/logitech_receiver/settings_templates.py:295 msgid "Backlight Level" msgstr "背光等级" #: lib/logitech_receiver/settings_templates.py:296 msgid "Illumination level on keyboard when in Manual mode." msgstr "手动模å¼�下的键盘亮度等级" #: lib/logitech_receiver/settings_templates.py:353 msgid "Backlight Delay Hands Out" msgstr "手离开键盘å�ŽèƒŒå…‰å…³é—­çš„延迟" #: lib/logitech_receiver/settings_templates.py:354 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "手离开键盘å�Žï¼ŒèƒŒå…‰æ¸�ç�­çš„延迟秒数" #: lib/logitech_receiver/settings_templates.py:362 msgid "Backlight Delay Hands In" msgstr "手é� è¿‘键盘å�ŽèƒŒå…‰äº®èµ·çš„延迟" #: lib/logitech_receiver/settings_templates.py:363 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "手é� è¿‘键盘å�Žï¼ŒèƒŒå…‰äº®èµ·çš„延迟秒数" #: lib/logitech_receiver/settings_templates.py:371 msgid "Backlight Delay Powered" msgstr "外接电æº�时的背光延迟" #: lib/logitech_receiver/settings_templates.py:372 msgid "Delay in seconds until backlight fades out with external power." msgstr "外接电æº�时背光æ¸�ç�­çš„延迟秒数" #: lib/logitech_receiver/settings_templates.py:380 msgid "Backlight (Seconds)" msgstr "背光(秒)" #: lib/logitech_receiver/settings_templates.py:392 msgid "Scroll Wheel High Resolution" msgstr "滚轮高分辨率" #: lib/logitech_receiver/settings_templates.py:396 #: lib/logitech_receiver/settings_templates.py:425 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "如果滚动异常地快或慢,请设置为忽略" #: lib/logitech_receiver/settings_templates.py:403 #: lib/logitech_receiver/settings_templates.py:434 msgid "Scroll Wheel Diversion" msgstr "滚轮é‡�定义" #: lib/logitech_receiver/settings_templates.py:405 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "使滚轮å�‘é€� LOWRES_WHEEL (低精度滚轮) HID++ 通告(如有 Solaar 规则,则被触å�‘)" #: lib/logitech_receiver/settings_templates.py:412 msgid "Scroll Wheel Direction" msgstr "滚轮方å�‘" #: lib/logitech_receiver/settings_templates.py:413 msgid "Invert direction for vertical scroll with wheel." msgstr "å��转滚轮的垂直滚动方å�‘。" #: lib/logitech_receiver/settings_templates.py:421 msgid "Scroll Wheel Resolution" msgstr "滚轮分辨率" #: lib/logitech_receiver/settings_templates.py:436 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "使滚轮å�‘é€� HIRES_WHEEL (高精度滚轮) HID++ 通告(如有 Solaar 规则,则被触å�‘)" #: lib/logitech_receiver/settings_templates.py:445 msgid "Sensitivity (Pointer Speed)" msgstr "ç�µæ•�度 (指针速度)" #: lib/logitech_receiver/settings_templates.py:446 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "鼠标速度å€�率 (256 为常规å€�率)。" #: lib/logitech_receiver/settings_templates.py:456 msgid "Thumb Wheel Diversion" msgstr "拇指滚轮é‡�定义" #: lib/logitech_receiver/settings_templates.py:458 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "使拇指滚轮å�‘é€� THUMB_WHEEL (拇指滚轮) HID++ 通告(如有 Solaar 规则,则被触" "å�‘)" #: lib/logitech_receiver/settings_templates.py:467 msgid "Thumb Wheel Direction" msgstr "拇指滚轮方å�‘" #: lib/logitech_receiver/settings_templates.py:468 msgid "Invert thumb wheel scroll direction." msgstr "å��转拇指滚轮的滚动方å�‘。" #: lib/logitech_receiver/settings_templates.py:488 msgid "Onboard Profiles" msgstr "æ�¿è½½é¢„设" #: lib/logitech_receiver/settings_templates.py:489 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "å�¯ç”¨æ�¿è½½é¢„设,用于控制回报率ã€�ç�µæ•�度å�ŠæŒ‰é’®åŠŸèƒ½" #: lib/logitech_receiver/settings_templates.py:533 #: lib/logitech_receiver/settings_templates.py:566 msgid "Report Rate" msgstr "回报率" #: lib/logitech_receiver/settings_templates.py:535 #: lib/logitech_receiver/settings_templates.py:568 msgid "Frequency of device movement reports" msgstr "设备移动事件的回报频率" #: lib/logitech_receiver/settings_templates.py:535 #: lib/logitech_receiver/settings_templates.py:568 #: lib/logitech_receiver/settings_templates.py:983 #: lib/logitech_receiver/settings_templates.py:1357 #: lib/logitech_receiver/settings_templates.py:1388 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "å�¯èƒ½éœ€è¦�ç¦�用æ�¿è½½é¢„设æ‰�能生效。" #: lib/logitech_receiver/settings_templates.py:596 msgid "Divert crown events" msgstr "é‡�定义旋钮事件" #: lib/logitech_receiver/settings_templates.py:597 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "使旋钮å�‘é€� CROWN (æ—‹é’®) HID++ 通告(如有 Solaar 规则,则被触å�‘)" #: lib/logitech_receiver/settings_templates.py:605 msgid "Crown smooth scroll" msgstr "旋钮平滑旋动" #: lib/logitech_receiver/settings_templates.py:606 msgid "Set crown smooth scroll" msgstr "设置旋钮的平滑旋动" #: lib/logitech_receiver/settings_templates.py:614 msgid "Divert G and M Keys" msgstr "é‡�定义 G é”®å�Š M é”®" #: lib/logitech_receiver/settings_templates.py:615 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "使 G é”®å�Š M é”®å�‘é€� HID++ 通告(如有 Solaar 规则,则被触å�‘)" #: lib/logitech_receiver/settings_templates.py:629 msgid "Scroll Wheel Ratcheted" msgstr "滚轮棘轮" #: lib/logitech_receiver/settings_templates.py:630 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "在滚速å“�应å¼�棘轮å�Šå¹³æ»‘滚动模å¼�间切æ�¢" #: lib/logitech_receiver/settings_templates.py:632 msgid "Freespinning" msgstr "平滑滚动" #: lib/logitech_receiver/settings_templates.py:632 msgid "Ratcheted" msgstr "棘轮å¼�" #: lib/logitech_receiver/settings_templates.py:639 msgid "Scroll Wheel Ratchet Speed" msgstr "滚轮棘轮速度" #: lib/logitech_receiver/settings_templates.py:641 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "æ ¹æ�®é¼ æ ‡æ»šè½®é€Ÿåº¦ï¼Œåœ¨æ£˜è½®æ¨¡å¼�和平滑滚动模å¼�间切æ�¢ã€‚\n" "50时将始终处于棘轮模å¼�。" #: lib/logitech_receiver/settings_templates.py:690 msgid "Key/Button Actions" msgstr "按键/按钮行为" #: lib/logitech_receiver/settings_templates.py:692 msgid "Change the action for the key or button." msgstr "更改按键或按钮的行为。" #: lib/logitech_receiver/settings_templates.py:694 msgid "Overridden by diversion." msgstr "会被é‡�定义é…�置覆盖。" #: lib/logitech_receiver/settings_templates.py:696 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "更改关键æ“�作 (如鼠标左键) å�¯èƒ½å¯¼è‡´ç³»ç»Ÿæ— æ³•使用。" #: lib/logitech_receiver/settings_templates.py:862 msgid "Key/Button Diversion" msgstr "按键/按钮é‡�定义" #: lib/logitech_receiver/settings_templates.py:863 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "使按键或按钮å�‘é€� HID++ (é‡�定义) 通告 ã€�触å�‘鼠标手势或滑动调节 DPI" #: lib/logitech_receiver/settings_templates.py:866 #: lib/logitech_receiver/settings_templates.py:867 #: lib/logitech_receiver/settings_templates.py:868 msgid "Diverted" msgstr "é‡�定义" #: lib/logitech_receiver/settings_templates.py:866 #: lib/logitech_receiver/settings_templates.py:867 msgid "Mouse Gestures" msgstr "鼠标手势" #: lib/logitech_receiver/settings_templates.py:866 #: lib/logitech_receiver/settings_templates.py:867 #: lib/logitech_receiver/settings_templates.py:868 msgid "Regular" msgstr "常规" #: lib/logitech_receiver/settings_templates.py:866 msgid "Sliding DPI" msgstr "滑动调节 DPI" #: lib/logitech_receiver/settings_templates.py:954 #: lib/logitech_receiver/settings_templates.py:982 msgid "Sensitivity (DPI)" msgstr "ç�µæ•�度 (DPI)" #: lib/logitech_receiver/settings_templates.py:1059 msgid "Sensitivity Switching" msgstr "ç�µæ•�度切æ�¢" #: lib/logitech_receiver/settings_templates.py:1061 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "切æ�¢å½“å‰�ç�µæ•�度,并记忆按键或按钮按下时的ç�µæ•�度。\n" "如果没有已记忆的ç�µæ•�度,就å�ªä¼šè®°å¿†å½“å‰�ç�µæ•�度" #: lib/logitech_receiver/settings_templates.py:1065 msgid "Off" msgstr "å…³" #: lib/logitech_receiver/settings_templates.py:1096 msgid "Disable keys" msgstr "ç¦�用按键" #: lib/logitech_receiver/settings_templates.py:1097 msgid "Disable specific keyboard keys." msgstr "ç¦�用特定的键盘按键。" #: lib/logitech_receiver/settings_templates.py:1100 #, python-format msgid "Disables the %s key." msgstr "ç¦�用 %s 按键。" #: lib/logitech_receiver/settings_templates.py:1113 #: lib/logitech_receiver/settings_templates.py:1170 msgid "Set OS" msgstr "设置æ“�作系统" #: lib/logitech_receiver/settings_templates.py:1114 #: lib/logitech_receiver/settings_templates.py:1171 msgid "Change keys to match OS." msgstr "改å�˜é”®ä½�以匹é…�æ“�作系统。" #: lib/logitech_receiver/settings_templates.py:1183 msgid "Change Host" msgstr "切æ�¢ä¸»æœº" #: lib/logitech_receiver/settings_templates.py:1184 msgid "Switch connection to a different host" msgstr "切æ�¢è¿žæŽ¥çš„主机" #: lib/logitech_receiver/settings_templates.py:1208 msgid "Performs a left click." msgstr "å�•击鼠标左键。" #: lib/logitech_receiver/settings_templates.py:1208 msgid "Single tap" msgstr "å�•指点击" #: lib/logitech_receiver/settings_templates.py:1209 msgid "Performs a right click." msgstr "å�•击鼠标å�³é”®ã€‚" #: lib/logitech_receiver/settings_templates.py:1209 msgid "Single tap with two fingers" msgstr "å�ŒæŒ‡ç‚¹å‡»" #: lib/logitech_receiver/settings_templates.py:1210 msgid "Single tap with three fingers" msgstr "三指点击" #: lib/logitech_receiver/settings_templates.py:1214 msgid "Double tap" msgstr "å�•指å�Œå‡»" #: lib/logitech_receiver/settings_templates.py:1214 msgid "Performs a double click." msgstr "å�Œå‡»ã€‚" #: lib/logitech_receiver/settings_templates.py:1215 msgid "Double tap with two fingers" msgstr "å�ŒæŒ‡å�Œå‡»" #: lib/logitech_receiver/settings_templates.py:1216 msgid "Double tap with three fingers" msgstr "三指å�Œå‡»" #: lib/logitech_receiver/settings_templates.py:1219 msgid "Drags items by dragging the finger after double tapping." msgstr "å�•指å�Œå‡»å�Žç§»åŠ¨æ‰‹æŒ‡æ�¥æ‹–动项目。" #: lib/logitech_receiver/settings_templates.py:1219 msgid "Tap and drag" msgstr "触摸并拖动" #: lib/logitech_receiver/settings_templates.py:1221 msgid "Tap and drag with two fingers" msgstr "å�ŒæŒ‡è§¦æ‘¸å¹¶æ‹–动" #: lib/logitech_receiver/settings_templates.py:1222 msgid "Drags items by dragging the fingers after double tapping." msgstr "多指å�Œå‡»å�Žç§»åŠ¨æ‰‹æŒ‡æ�¥æ‹–动项目。" #: lib/logitech_receiver/settings_templates.py:1224 msgid "Tap and drag with three fingers" msgstr "三指触摸并拖动" #: lib/logitech_receiver/settings_templates.py:1227 msgid "Suppress tap and edge gestures" msgstr "ç¦�用触摸和边缘手势" #: lib/logitech_receiver/settings_templates.py:1228 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "ç¦�用触摸和边缘手势 (等价于按下 Fn+左键å�•击)。" #: lib/logitech_receiver/settings_templates.py:1230 msgid "Scroll with one finger" msgstr "å�•指滚动" #: lib/logitech_receiver/settings_templates.py:1230 #: lib/logitech_receiver/settings_templates.py:1231 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Scrolls." msgstr "滚动。" #: lib/logitech_receiver/settings_templates.py:1231 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Scroll with two fingers" msgstr "å�ŒæŒ‡æ»šåЍ" #: lib/logitech_receiver/settings_templates.py:1232 msgid "Scroll horizontally with two fingers" msgstr "å�ŒæŒ‡æ°´å¹³æ»šåЍ" #: lib/logitech_receiver/settings_templates.py:1232 msgid "Scrolls horizontally." msgstr "水平滚动。" #: lib/logitech_receiver/settings_templates.py:1233 msgid "Scroll vertically with two fingers" msgstr "å�ŒæŒ‡åž‚直滚动" #: lib/logitech_receiver/settings_templates.py:1233 msgid "Scrolls vertically." msgstr "垂直滚动。" #: lib/logitech_receiver/settings_templates.py:1235 msgid "Inverts the scrolling direction." msgstr "å��转滚动方å�‘。" #: lib/logitech_receiver/settings_templates.py:1235 msgid "Natural scrolling" msgstr "自然滚动" #: lib/logitech_receiver/settings_templates.py:1236 msgid "Enables the thumbwheel." msgstr "å�¯ç”¨æ‹‡æŒ‡æ»šè½®ã€‚" #: lib/logitech_receiver/settings_templates.py:1236 msgid "Thumbwheel" msgstr "拇指滚轮" #: lib/logitech_receiver/settings_templates.py:1247 #: lib/logitech_receiver/settings_templates.py:1251 msgid "Swipe from the top edge" msgstr "从顶部边缘滑动" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Swipe from the left edge" msgstr "从左侧边缘滑动" #: lib/logitech_receiver/settings_templates.py:1249 msgid "Swipe from the right edge" msgstr "从å�³ä¾§è¾¹ç¼˜æ»‘动" #: lib/logitech_receiver/settings_templates.py:1250 msgid "Swipe from the bottom edge" msgstr "从底部边缘滑动" #: lib/logitech_receiver/settings_templates.py:1252 msgid "Swipe two fingers from the left edge" msgstr "从左侧边缘å�ŒæŒ‡æ»‘动" #: lib/logitech_receiver/settings_templates.py:1253 msgid "Swipe two fingers from the right edge" msgstr "从å�³ä¾§è¾¹ç¼˜å�ŒæŒ‡æ»‘动" #: lib/logitech_receiver/settings_templates.py:1254 msgid "Swipe two fingers from the bottom edge" msgstr "从底部边缘å�ŒæŒ‡æ»‘动" #: lib/logitech_receiver/settings_templates.py:1255 msgid "Swipe two fingers from the top edge" msgstr "从顶部边缘å�ŒæŒ‡æ»‘动" #: lib/logitech_receiver/settings_templates.py:1256 #: lib/logitech_receiver/settings_templates.py:1260 msgid "Pinch to zoom out; spread to zoom in." msgstr "通过æ��å�ˆæ‰‹æŒ‡ç¼©å°�;伸展手指以放大。" #: lib/logitech_receiver/settings_templates.py:1256 msgid "Zoom with two fingers." msgstr "å�ŒæŒ‡ç¼©æ”¾ã€‚" #: lib/logitech_receiver/settings_templates.py:1257 msgid "Pinch to zoom out." msgstr "æ��å�ˆæ‰‹æŒ‡ä»¥ç¼©å°�。" #: lib/logitech_receiver/settings_templates.py:1258 msgid "Spread to zoom in." msgstr "伸展手指以放大。" #: lib/logitech_receiver/settings_templates.py:1259 msgid "Zoom with three fingers." msgstr "三指缩放。" #: lib/logitech_receiver/settings_templates.py:1260 msgid "Zoom with two fingers" msgstr "å�ŒæŒ‡ç¼©æ”¾" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Pixel zone" msgstr "åƒ�素区" #: lib/logitech_receiver/settings_templates.py:1279 msgid "Ratio zone" msgstr "比例区" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Scale factor" msgstr "缩放比例" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Sets the cursor speed." msgstr "设置指针速度。" #: lib/logitech_receiver/settings_templates.py:1284 msgid "Left" msgstr "左侧" #: lib/logitech_receiver/settings_templates.py:1284 msgid "Left-most coordinate." msgstr "最左å��标。" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Bottom" msgstr "底部" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Bottom coordinate." msgstr "底部å��标。" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Width" msgstr "宽度" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Width." msgstr "宽度。" #: lib/logitech_receiver/settings_templates.py:1287 msgid "Height" msgstr "高度" #: lib/logitech_receiver/settings_templates.py:1287 msgid "Height." msgstr "高度。" #: lib/logitech_receiver/settings_templates.py:1288 msgid "Cursor speed." msgstr "指针速度。" #: lib/logitech_receiver/settings_templates.py:1288 msgid "Scale" msgstr "比例" #: lib/logitech_receiver/settings_templates.py:1294 msgid "Gestures" msgstr "手势" #: lib/logitech_receiver/settings_templates.py:1295 msgid "Tweak the mouse/touchpad behaviour." msgstr "调整鼠标或触摸æ�¿çš„行为。" #: lib/logitech_receiver/settings_templates.py:1311 msgid "Gestures Diversion" msgstr "手势é‡�定义" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Divert mouse/touchpad gestures." msgstr "é‡�定义鼠标或触摸æ�¿æ‰‹åŠ¿ã€‚" #: lib/logitech_receiver/settings_templates.py:1328 msgid "Gesture params" msgstr "手势å�‚æ•°" #: lib/logitech_receiver/settings_templates.py:1329 msgid "Change numerical parameters of a mouse/touchpad." msgstr "更改鼠标或触摸æ�¿çš„æ•°å€¼å�‚数。" #: lib/logitech_receiver/settings_templates.py:1353 msgid "M-Key LEDs" msgstr "M é”® LED" #: lib/logitech_receiver/settings_templates.py:1355 msgid "Control the M-Key LEDs." msgstr "控制 M 键的 LED。" #: lib/logitech_receiver/settings_templates.py:1359 #: lib/logitech_receiver/settings_templates.py:1390 msgid "May need G Keys diverted to be effective." msgstr "å�¯èƒ½éœ€è¦�å¼€å�¯ G é”®é‡�定义。" #: lib/logitech_receiver/settings_templates.py:1365 #, python-format msgid "Lights up the %s key." msgstr "点亮 %s 按键。" #: lib/logitech_receiver/settings_templates.py:1384 msgid "MR-Key LED" msgstr "MR é”® LED" #: lib/logitech_receiver/settings_templates.py:1386 msgid "Control the MR-Key LED." msgstr "控制 MR 键的 LED。" #: lib/logitech_receiver/settings_templates.py:1407 msgid "Persistent Key/Button Mapping" msgstr "æŒ�久化按键/按钮映射" #: lib/logitech_receiver/settings_templates.py:1409 msgid "Permanently change the mapping for the key or button." msgstr "永久更改按键或按钮的映射。" #: lib/logitech_receiver/settings_templates.py:1411 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "更改关键的按键或按钮 (如鼠标左键) å�¯èƒ½å¯¼è‡´ç³»ç»Ÿæ— æ³•使用。" #: lib/logitech_receiver/settings_templates.py:1468 msgid "Sidetone" msgstr "侧音 (麦克风回馈)" #: lib/logitech_receiver/settings_templates.py:1469 msgid "Set sidetone level." msgstr "设置侧音水平。" #: lib/logitech_receiver/settings_templates.py:1478 msgid "Equalizer" msgstr "å�‡è¡¡å™¨" #: lib/logitech_receiver/settings_templates.py:1479 msgid "Set equalizer levels." msgstr "设置å�‡è¡¡å™¨æ°´å¹³ã€‚" #: lib/logitech_receiver/settings_templates.py:1501 msgid "Hz" msgstr "" #: lib/logitech_receiver/settings_templates.py:1507 msgid "Power Management" msgstr "电æº�管ç�†" #: lib/logitech_receiver/settings_templates.py:1508 msgid "Power off in minutes (0 for never)." msgstr "分钟å�Žå…³æœºï¼ˆ0为ä¸�关机)" #: lib/logitech_receiver/settings_templates.py:1519 msgid "Brightness Control" msgstr "亮度控制" #: lib/logitech_receiver/settings_templates.py:1520 msgid "Control overall brightness" msgstr "全局亮度控制" #: lib/logitech_receiver/settings_templates.py:1563 #: lib/logitech_receiver/settings_templates.py:1617 msgid "LED Control" msgstr "LED控制" #: lib/logitech_receiver/settings_templates.py:1564 #: lib/logitech_receiver/settings_templates.py:1618 msgid "Switch control of LED zones between device and Solaar" msgstr "在设备和Solaar间切æ�¢LED区域控制" #: lib/logitech_receiver/settings_templates.py:1579 #: lib/logitech_receiver/settings_templates.py:1628 msgid "LED Zone Effects" msgstr "LED区域效果" #: lib/logitech_receiver/settings_templates.py:1580 #: lib/logitech_receiver/settings_templates.py:1629 msgid "LED Control needs to be set to Solaar to be effective." msgstr "LED 控制需è¦�设置到 Solaar æ‰�能生效" #: lib/logitech_receiver/settings_templates.py:1580 #: lib/logitech_receiver/settings_templates.py:1629 msgid "Set effect for LED Zone" msgstr "设置LED区域效果" #: lib/logitech_receiver/settings_templates.py:1583 msgid "Speed" msgstr "速度" #: lib/logitech_receiver/settings_templates.py:1584 msgid "Period" msgstr "周期" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Intensity" msgstr "强度" #: lib/logitech_receiver/settings_templates.py:1586 msgid "Ramp" msgstr "æ¸�å�˜" #: lib/logitech_receiver/settings_templates.py:1602 msgid "LEDs" msgstr "LED" #: lib/logitech_receiver/settings_templates.py:1639 msgid "Per-key Lighting" msgstr "按键独立ç�¯å…‰" #: lib/logitech_receiver/settings_templates.py:1640 msgid "Control per-key lighting." msgstr "设置æ¯�个按键的ç�¯å…‰" #: lib/solaar/ui/__init__.py:103 msgid "Another Solaar process is already running so just expose its window" msgstr "å�¦ä¸€ä¸ª Solaar 进程正在è¿�行,已唤醒窗å�£" #: lib/solaar/ui/about.py:34 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "管ç�†ç½—技接收器ã€�\n" "键盘ã€�鼠标和平æ�¿ç”µè„‘。" #: lib/solaar/ui/about.py:43 msgid "Additional Programming" msgstr "å��作研å�‘" #: lib/solaar/ui/about.py:44 msgid "GUI design" msgstr "界é�¢è®¾è®¡" #: lib/solaar/ui/about.py:46 msgid "Testing" msgstr "软件测试" #: lib/solaar/ui/about.py:54 msgid "Logitech documentation" msgstr "罗技文档" #: lib/solaar/ui/action.py:83 lib/solaar/ui/action.py:87 #: lib/solaar/ui/window.py:189 msgid "Unpair" msgstr "å�–消é…�对" #: lib/solaar/ui/action.py:86 lib/solaar/ui/diversion_rules.py:103 msgid "Cancel" msgstr "å�–消" #: lib/solaar/ui/common.py:35 msgid "Permissions error" msgstr "æ�ƒé™�错误" #: lib/solaar/ui/common.py:37 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "å�‘现罗技接收器或设备(%s),但无访问æ�ƒé™�" #: lib/solaar/ui/common.py:39 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "若您是刚安装Solaar,请æ�’拔一下罗技接收器或设备" #: lib/solaar/ui/common.py:42 msgid "Cannot connect to device error" msgstr "错误: 无法连接到设备" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "已在 %s 上å�‘现 1 个罗技接收器或设备,但连接时å�‘生错误。" #: lib/solaar/ui/common.py:46 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "请å°�试æ�’拔设备,或关闭å�Žé‡�新打开设备" #: lib/solaar/ui/common.py:49 msgid "Unpairing failed" msgstr "å�–消é…�对失败" #: lib/solaar/ui/common.py:51 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "å�–消 %{device} 到 %{receiver} çš„é…�对失败。" #: lib/solaar/ui/common.py:53 msgid "The receiver returned an error, with no further details." msgstr "接收器出现错误,无详细信æ�¯ã€‚" #: lib/solaar/ui/config_panel.py:228 msgid "Complete - ENTER to change" msgstr "完æˆ� - 按下 ENTER 键以进行更改" #: lib/solaar/ui/config_panel.py:228 msgid "Incomplete" msgstr "未完æˆ�" #: lib/solaar/ui/config_panel.py:470 lib/solaar/ui/config_panel.py:522 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d 个值" #: lib/solaar/ui/config_panel.py:603 msgid "Changes allowed" msgstr "å…�许更改" #: lib/solaar/ui/config_panel.py:604 msgid "No changes allowed" msgstr "ä¸�å…�许更改" #: lib/solaar/ui/config_panel.py:605 msgid "Ignore this setting" msgstr "忽略此设置" #: lib/solaar/ui/config_panel.py:649 msgid "Working" msgstr "工作中" #: lib/solaar/ui/config_panel.py:652 msgid "Read/write operation failed." msgstr "读写æ“�作失败。" #: lib/solaar/ui/diversion_rules.py:65 msgid "Built-in rules" msgstr "内置规则" #: lib/solaar/ui/diversion_rules.py:65 msgid "User-defined rules" msgstr "自定义规则" #: lib/solaar/ui/diversion_rules.py:67 lib/solaar/ui/diversion_rules.py:1033 msgid "Rule" msgstr "规则" #: lib/solaar/ui/diversion_rules.py:68 lib/solaar/ui/diversion_rules.py:545 #: lib/solaar/ui/diversion_rules.py:672 msgid "Sub-rule" msgstr "å­�规则" #: lib/solaar/ui/diversion_rules.py:70 msgid "[empty]" msgstr "[空]" #: lib/solaar/ui/diversion_rules.py:94 msgid "Make changes permanent?" msgstr "永久应用更改?" #: lib/solaar/ui/diversion_rules.py:99 msgid "Yes" msgstr "是" #: lib/solaar/ui/diversion_rules.py:101 msgid "No" msgstr "å�¦" #: lib/solaar/ui/diversion_rules.py:106 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "如果选择å�¦ï¼Œæ”¹åŠ¨ä¼šåœ¨ Solaar 关闭å�Žä¸¢å¤±ã€‚" #: lib/solaar/ui/diversion_rules.py:167 msgid "Solaar Rule Editor" msgstr "Solaar 规则编辑器" #: lib/solaar/ui/diversion_rules.py:260 msgid "Save changes" msgstr "ä¿�存更改" #: lib/solaar/ui/diversion_rules.py:265 msgid "Discard changes" msgstr "放弃更改" #: lib/solaar/ui/diversion_rules.py:404 msgid "Insert here" msgstr "æ�’å…¥" #: lib/solaar/ui/diversion_rules.py:406 msgid "Insert above" msgstr "在上方æ�’å…¥" #: lib/solaar/ui/diversion_rules.py:408 msgid "Insert below" msgstr "在下方æ�’å…¥" #: lib/solaar/ui/diversion_rules.py:414 msgid "Insert new rule here" msgstr "新建规则" #: lib/solaar/ui/diversion_rules.py:416 msgid "Insert new rule above" msgstr "在上方添加规则" #: lib/solaar/ui/diversion_rules.py:418 msgid "Insert new rule below" msgstr "在下方添加规则" #: lib/solaar/ui/diversion_rules.py:463 msgid "Paste here" msgstr "在此处粘贴" #: lib/solaar/ui/diversion_rules.py:465 msgid "Paste above" msgstr "在上方粘贴" #: lib/solaar/ui/diversion_rules.py:467 msgid "Paste below" msgstr "在下方粘贴" #: lib/solaar/ui/diversion_rules.py:473 msgid "Paste rule here" msgstr "在此处粘贴规则" #: lib/solaar/ui/diversion_rules.py:475 msgid "Paste rule above" msgstr "在上方粘贴规则" #: lib/solaar/ui/diversion_rules.py:477 msgid "Paste rule below" msgstr "在下方粘贴规则" #: lib/solaar/ui/diversion_rules.py:481 msgid "Paste rule" msgstr "粘贴规则" #: lib/solaar/ui/diversion_rules.py:510 msgid "Flatten" msgstr "展平" #: lib/solaar/ui/diversion_rules.py:543 msgid "Insert" msgstr "æ�’å…¥" #: lib/solaar/ui/diversion_rules.py:546 lib/solaar/ui/diversion_rules.py:674 #: lib/solaar/ui/diversion_rules.py:1065 msgid "Or" msgstr "或" #: lib/solaar/ui/diversion_rules.py:547 lib/solaar/ui/diversion_rules.py:673 #: lib/solaar/ui/diversion_rules.py:1051 msgid "And" msgstr "且" #: lib/solaar/ui/diversion_rules.py:549 msgid "Condition" msgstr "æ�¡ä»¶" #: lib/solaar/ui/diversion_rules.py:551 lib/solaar/ui/rule_conditions.py:146 msgid "Feature" msgstr "特性" #: lib/solaar/ui/diversion_rules.py:552 lib/solaar/ui/rule_conditions.py:181 msgid "Report" msgstr "报文" #: lib/solaar/ui/diversion_rules.py:553 lib/solaar/ui/rule_conditions.py:60 msgid "Process" msgstr "焦点所在进程" #: lib/solaar/ui/diversion_rules.py:554 msgid "Mouse process" msgstr "光标所在进程" #: lib/solaar/ui/diversion_rules.py:555 lib/solaar/ui/rule_conditions.py:218 msgid "Modifiers" msgstr "修饰键" #: lib/solaar/ui/diversion_rules.py:556 lib/solaar/ui/rule_conditions.py:270 msgid "Key" msgstr "按键" #: lib/solaar/ui/diversion_rules.py:557 lib/solaar/ui/rule_conditions.py:311 msgid "KeyIsDown" msgstr "按键正被按下" #: lib/solaar/ui/diversion_rules.py:558 lib/solaar/ui/diversion_rules.py:1359 msgid "Active" msgstr "活跃设备" #: lib/solaar/ui/diversion_rules.py:559 lib/solaar/ui/diversion_rules.py:1316 #: lib/solaar/ui/diversion_rules.py:1368 lib/solaar/ui/diversion_rules.py:1418 msgid "Device" msgstr "设备" #: lib/solaar/ui/diversion_rules.py:560 lib/solaar/ui/diversion_rules.py:1394 msgid "Host" msgstr "主机" #: lib/solaar/ui/diversion_rules.py:561 lib/solaar/ui/diversion_rules.py:1436 msgid "Setting" msgstr "设置" #: lib/solaar/ui/diversion_rules.py:562 lib/solaar/ui/rule_conditions.py:326 #: lib/solaar/ui/rule_conditions.py:375 msgid "Test" msgstr "测试" #: lib/solaar/ui/diversion_rules.py:563 lib/solaar/ui/rule_conditions.py:500 msgid "Test bytes" msgstr "字节检测" #: lib/solaar/ui/diversion_rules.py:564 lib/solaar/ui/rule_conditions.py:601 msgid "Mouse Gesture" msgstr "鼠标手势" #: lib/solaar/ui/diversion_rules.py:568 msgid "Action" msgstr "æ“�作" #: lib/solaar/ui/diversion_rules.py:570 lib/solaar/ui/rule_actions.py:132 msgid "Key press" msgstr "按下按键" #: lib/solaar/ui/diversion_rules.py:571 lib/solaar/ui/rule_actions.py:183 msgid "Mouse scroll" msgstr "鼠标滚轮滚动" #: lib/solaar/ui/diversion_rules.py:572 lib/solaar/ui/rule_actions.py:244 msgid "Mouse click" msgstr "鼠标点击" #: lib/solaar/ui/diversion_rules.py:573 msgid "Set" msgstr "更改设置" #: lib/solaar/ui/diversion_rules.py:574 lib/solaar/ui/rule_actions.py:314 msgid "Execute" msgstr "执行程åº�" #: lib/solaar/ui/diversion_rules.py:575 lib/solaar/ui/diversion_rules.py:1096 msgid "Later" msgstr "延迟" #: lib/solaar/ui/diversion_rules.py:604 msgid "Insert new rule" msgstr "æ�’入新规则" #: lib/solaar/ui/diversion_rules.py:624 lib/solaar/ui/rule_actions.py:74 #: lib/solaar/ui/rule_actions.py:273 lib/solaar/ui/rule_conditions.py:548 msgid "Delete" msgstr "删除" #: lib/solaar/ui/diversion_rules.py:646 msgid "Negate" msgstr "å�–å��" #: lib/solaar/ui/diversion_rules.py:670 msgid "Wrap with" msgstr "以…包裹" #: lib/solaar/ui/diversion_rules.py:692 msgid "Cut" msgstr "剪切" #: lib/solaar/ui/diversion_rules.py:707 msgid "Paste" msgstr "粘贴" #: lib/solaar/ui/diversion_rules.py:713 msgid "Copy" msgstr "å¤�制" #: lib/solaar/ui/diversion_rules.py:1014 msgid "This editor does not support the selected rule component yet." msgstr "此编辑器尚未支æŒ�所选的规则组件。" #: lib/solaar/ui/diversion_rules.py:1076 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "延迟秒数。0到1之间的延迟将通过高精度实现" #: lib/solaar/ui/diversion_rules.py:1114 msgid "Not" msgstr "é�ž" #: lib/solaar/ui/diversion_rules.py:1145 msgid "Toggle" msgstr "切æ�¢" #: lib/solaar/ui/diversion_rules.py:1146 msgid "True" msgstr "真" #: lib/solaar/ui/diversion_rules.py:1147 msgid "False" msgstr "å�‡" #: lib/solaar/ui/diversion_rules.py:1160 msgid "Unsupported setting" msgstr "ä¸�支æŒ�的设置" #: lib/solaar/ui/diversion_rules.py:1322 lib/solaar/ui/diversion_rules.py:1342 #: lib/solaar/ui/diversion_rules.py:1424 lib/solaar/ui/diversion_rules.py:1669 #: lib/solaar/ui/diversion_rules.py:1687 msgid "Originating device" msgstr "æº�设备" #: lib/solaar/ui/diversion_rules.py:1355 msgid "Device is active and its settings can be changed." msgstr "设备已激活,且å�¯æ›´æ”¹å…¶è®¾ç½®ã€‚" #: lib/solaar/ui/diversion_rules.py:1364 msgid "Device that originated the current notification." msgstr "å�‘出当å‰�通告的设备" #: lib/solaar/ui/diversion_rules.py:1377 msgid "Name of host computer." msgstr "主机å��" #: lib/solaar/ui/diversion_rules.py:1445 msgid "Value" msgstr "值" #: lib/solaar/ui/diversion_rules.py:1454 msgid "Item" msgstr "项目" #: lib/solaar/ui/diversion_rules.py:1728 msgid "Change setting on device" msgstr "更改设备上ä¿�存的设置" #: lib/solaar/ui/diversion_rules.py:1744 msgid "Setting on device" msgstr "设备上ä¿�存的设置" #: lib/solaar/ui/notify.py:115 msgid "unspecified reason" msgstr "未定原因" #: lib/solaar/ui/pair_window.py:37 lib/solaar/ui/pair_window.py:155 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s: é…�对新设备" #: lib/solaar/ui/pair_window.py:39 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt接收器仅适用于Bolt设备" #: lib/solaar/ui/pair_window.py:41 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "按ä½�é…�对按钮或按键直到é…�对指示ç�¯å¿«é€Ÿé—ªçƒ�。" #: lib/solaar/ui/pair_window.py:44 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "优è�”接收器仅适用于优è�”设备" #: lib/solaar/ui/pair_window.py:46 msgid "Other receivers are only compatible with a few devices." msgstr "其他接收器仅能用于少é‡�设备" #: lib/solaar/ui/pair_window.py:48 msgid "Turn on the device you want to pair." msgstr "打开需é…�对设备的电æº�。" #: lib/solaar/ui/pair_window.py:49 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "设备ä¸�å�¯ä¸Žé™„近已上电的接收器处于é…�对状æ€�" #: lib/solaar/ui/pair_window.py:51 msgid "If the device is already turned on, turn it off and on again." msgstr "如果设备电æº�å·²ç»�打开,请先关闭å†�é‡�新打开。" #: lib/solaar/ui/pair_window.py:55 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "此接收器还å�¯å†�与 %d 个设备é…�对。" #: lib/solaar/ui/pair_window.py:61 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "此时å�–消将ä¸�会使é…�对生效。" #: lib/solaar/ui/pair_window.py:156 #, python-format msgid "Enter passcode on %(name)s." msgstr "在 %(name)s 上输入密ç �。" #: lib/solaar/ui/pair_window.py:159 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "输入 %(passcode)s å�ŽæŒ‰ä¸‹å›žè½¦é”®ã€‚" #: lib/solaar/ui/pair_window.py:162 msgid "left" msgstr "左键" #: lib/solaar/ui/pair_window.py:162 msgid "right" msgstr "å�³é”®" #: lib/solaar/ui/pair_window.py:164 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "按下 %(code)s\n" "å�Žå�Œæ—¶æŒ‰ä¸‹å·¦é”®å’Œå�³é”®ã€‚" #: lib/solaar/ui/pair_window.py:195 msgid "The wireless link is not encrypted" msgstr "无线连接未加密" #: lib/solaar/ui/pair_window.py:200 msgid "Found a new device:" msgstr "å�‘现新设备:" #: lib/solaar/ui/pair_window.py:221 msgid "Pairing failed" msgstr "é…�对失败" #: lib/solaar/ui/pair_window.py:223 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "请确认您的设备已在范围内,并ä¿�è¯�其电é‡�充足。" #: lib/solaar/ui/pair_window.py:225 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "检测到 1 个新设备,但与此接收器ä¸�兼容。" #: lib/solaar/ui/pair_window.py:227 msgid "More paired devices than receiver can support." msgstr "å·²é…�对设备超出接收器所支æŒ�的数é‡�。" #: lib/solaar/ui/pair_window.py:229 msgid "No further details are available about the error." msgstr "无此错误的详细信æ�¯ã€‚" #: lib/solaar/ui/rule_actions.py:48 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "模拟å�Œæ—¶ç‚¹å‡»ã€�按ä½�或释放一个按键。\n" "在 Wayland 上需è¦�具备对 /dev/input 的写æ�ƒé™�。" #: lib/solaar/ui/rule_actions.py:53 msgid "Add key" msgstr "添加按键" #: lib/solaar/ui/rule_actions.py:56 msgid "Click" msgstr "点击" #: lib/solaar/ui/rule_actions.py:59 msgid "Depress" msgstr "按ä½�" #: lib/solaar/ui/rule_actions.py:62 msgid "Release" msgstr "释放" #: lib/solaar/ui/rule_actions.py:147 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "模拟一次鼠标滚轮滚动。\n" "在 Wayland 上需è¦�具备对 /dev/input 的写æ�ƒé™�。" #: lib/solaar/ui/rule_actions.py:203 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "模拟一次鼠标点击。\n" "在 Wayland 上需è¦�具备对 /dev/input 的写æ�ƒé™�。" #: lib/solaar/ui/rule_actions.py:206 msgid "Button" msgstr "按钮" #: lib/solaar/ui/rule_actions.py:207 msgid "Count and Action" msgstr "计数å�Šè¡Œä¸º" #: lib/solaar/ui/rule_actions.py:256 msgid "Execute a command with arguments." msgstr "è¿�行一æ�¡å¸¦æœ‰å�‚数的命令。" #: lib/solaar/ui/rule_actions.py:259 msgid "Add argument" msgstr "添加å�‚æ•°" #: lib/solaar/ui/rule_conditions.py:43 msgid "X11 active process. For use in X11 only." msgstr "X11 活动进程。仅在 X11 中å�¯ç”¨ã€‚" #: lib/solaar/ui/rule_conditions.py:73 msgid "X11 mouse process. For use in X11 only." msgstr "X11 光标所在进程。仅在 X11 中å�¯ç”¨ã€‚" #: lib/solaar/ui/rule_conditions.py:90 msgid "MouseProcess" msgstr "光标所在进程" #: lib/solaar/ui/rule_conditions.py:114 msgid "Feature name of notification triggering rule processing." msgstr "在处ç�†é€šå‘Šè§¦å�‘规则时,匹é…�特性å��称。" #: lib/solaar/ui/rule_conditions.py:161 msgid "Report number of notification triggering rule processing." msgstr "在处ç�†é€šå‘Šè§¦å�‘规则时,匹é…�报文编å�·ã€‚" #: lib/solaar/ui/rule_conditions.py:194 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "激活的键盘修饰键。在 Wayland 中ä¸�总是å�¯ç”¨ã€‚" #: lib/solaar/ui/rule_conditions.py:234 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "é‡�定义的键按下或æ�¾å¼€ã€‚\n" "请先é…�置“按键/按钮é‡�定义â€�和“é‡�定义 G é”®â€�。" #: lib/solaar/ui/rule_conditions.py:243 msgid "Key down" msgstr "按下" #: lib/solaar/ui/rule_conditions.py:246 msgid "Key up" msgstr "æ�¾å¼€" #: lib/solaar/ui/rule_conditions.py:286 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "é‡�定义的键正被按下。\n" "请先é…�置“按键/按钮é‡�定义â€�和“é‡�定义 G é”®â€�。" #: lib/solaar/ui/rule_conditions.py:324 msgid "Test condition on notification triggering rule processing." msgstr "在处ç�†é€šå‘Šè§¦å�‘规则时,进行æ�¡ä»¶æµ‹è¯•。" #: lib/solaar/ui/rule_conditions.py:328 msgid "Parameter" msgstr "å�‚æ•°" #: lib/solaar/ui/rule_conditions.py:401 msgid "begin (inclusive)" msgstr "èµ·å§‹ (å�«)" #: lib/solaar/ui/rule_conditions.py:402 msgid "end (exclusive)" msgstr "结æ�Ÿ (ä¸�å�«)" #: lib/solaar/ui/rule_conditions.py:410 msgid "range" msgstr "范围" #: lib/solaar/ui/rule_conditions.py:413 msgid "minimum" msgstr "最å°�值" #: lib/solaar/ui/rule_conditions.py:414 msgid "maximum" msgstr "最大值" #: lib/solaar/ui/rule_conditions.py:416 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "从%(0)d 到 %(1)d 字节,范围从 %(2)d 到 %(3)d" #: lib/solaar/ui/rule_conditions.py:419 lib/solaar/ui/rule_conditions.py:420 msgid "mask" msgstr "掩ç �" #: lib/solaar/ui/rule_conditions.py:421 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "从%(0)d 到 %(1)d 字节,掩ç �为 %(2)d" #: lib/solaar/ui/rule_conditions.py:430 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "在处ç�†é€šå‘Šè§¦å�‘规则时,对指定的字节进行比特ä½�或范围测试。" #: lib/solaar/ui/rule_conditions.py:440 msgid "type" msgstr "类型" #: lib/solaar/ui/rule_conditions.py:528 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "鼠标手势,å�¯æŒ‡å®šè§¦å�‘键,并å�¯è·Ÿéš�零个或多个鼠标移动轨迹。" #: lib/solaar/ui/rule_conditions.py:533 msgid "Add movement" msgstr "增加移动轨迹" #: lib/solaar/ui/tray.py:50 msgid "No supported device found" msgstr "未å�‘现支æŒ�的设备" #: lib/solaar/ui/tray.py:55 lib/solaar/ui/window.py:310 #, python-format msgid "About %s" msgstr "关于 %s" #: lib/solaar/ui/tray.py:56 lib/solaar/ui/window.py:308 #, python-format msgid "Quit %s" msgstr "退出 %s" #: lib/solaar/ui/tray.py:267 lib/solaar/ui/tray.py:275 msgid "no receiver" msgstr "无接收器" #: lib/solaar/ui/tray.py:288 lib/solaar/ui/tray.py:293 msgid "offline" msgstr "离线" #: lib/solaar/ui/tray.py:291 msgid "no status" msgstr "无状æ€�" #: lib/solaar/ui/window.py:91 msgid "Scanning" msgstr "扫æ��中" #: lib/solaar/ui/window.py:122 msgid "Battery" msgstr "电池" #: lib/solaar/ui/window.py:125 msgid "Wireless Link" msgstr "无线连接" #: lib/solaar/ui/window.py:129 msgid "Lighting" msgstr "照明" #: lib/solaar/ui/window.py:163 msgid "Show Technical Details" msgstr "显示技术细节" #: lib/solaar/ui/window.py:179 msgid "Pair new device" msgstr "é…�对新设备" #: lib/solaar/ui/window.py:197 msgid "Select a device" msgstr "选择 1 个设备" #: lib/solaar/ui/window.py:313 msgid "Rule Editor" msgstr "规则编辑器" #: lib/solaar/ui/window.py:517 msgid "Path" msgstr "路径" #: lib/solaar/ui/window.py:520 msgid "USB ID" msgstr "" #: lib/solaar/ui/window.py:523 lib/solaar/ui/window.py:525 #: lib/solaar/ui/window.py:540 lib/solaar/ui/window.py:542 msgid "Serial" msgstr "åº�列å�·" #: lib/solaar/ui/window.py:529 msgid "Index" msgstr "索引å�·" #: lib/solaar/ui/window.py:531 msgid "Wireless PID" msgstr "无线标示符" #: lib/solaar/ui/window.py:533 msgid "Product ID" msgstr "产å“� ID" #: lib/solaar/ui/window.py:535 msgid "Protocol" msgstr "å��è®®" #: lib/solaar/ui/window.py:535 msgid "Unknown" msgstr "未知" #: lib/solaar/ui/window.py:537 msgid "Polling rate" msgstr "轮询速率" #: lib/solaar/ui/window.py:544 msgid "Unit ID" msgstr "å�•å…ƒ ID" #: lib/solaar/ui/window.py:558 msgid "Notifications" msgstr "通告" #: lib/solaar/ui/window.py:602 msgid "No device paired." msgstr "没有已é…�对设备。" #: lib/solaar/ui/window.py:611 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "此接收器最多å�¯ä¸Ž %(max_count)s 个设备é…�对。" #: lib/solaar/ui/window.py:622 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "此接收器还å�¯å†�与 %d 个设备é…�对。" #: lib/solaar/ui/window.py:679 msgid "Battery Voltage" msgstr "电池电压" #: lib/solaar/ui/window.py:681 msgid "Voltage reported by battery" msgstr "电池报告的电压" #: lib/solaar/ui/window.py:683 msgid "Battery Level" msgstr "电é‡�" #: lib/solaar/ui/window.py:685 msgid "Approximate level reported by battery" msgstr "电池报告的大致电é‡�" #: lib/solaar/ui/window.py:692 lib/solaar/ui/window.py:694 msgid "next reported " msgstr "下次报告于 " #: lib/solaar/ui/window.py:695 msgid " and next level to be reported." msgstr " 以å�Šä¸‹ä¸€ä¸ªæŠ¥å‘Šç”µé‡�。" #: lib/solaar/ui/window.py:711 msgid "encrypted" msgstr "已加密" #: lib/solaar/ui/window.py:713 msgid "The wireless link between this device and its receiver is encrypted." msgstr "设备与接收器间的无线连接已加密。" #: lib/solaar/ui/window.py:715 msgid "not encrypted" msgstr "未加密" #: lib/solaar/ui/window.py:719 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "设备和接收器间的无线连接未加密。\n" "对于指针设备,这是一个安全问题;对于文本输入设备,这是一个严é‡�的安全问题。" #: lib/solaar/ui/window.py:735 #, python-format msgid "%(light_level)d lux" msgstr "" #~ msgid " paired devices." #~ msgstr " 个已é…�对设备。" #~ msgid "1 paired device." #~ msgstr "1 个已é…�对设备。" #~ msgid "About" #~ msgstr "关于" #~ msgid "Add action" #~ msgstr "添加动作" #~ msgid "" #~ "Adjust the DPI by sliding the mouse horizontally while holding the button " #~ "down." #~ msgstr "通过在按ä½�按钮的å�Œæ—¶æ»‘动鼠标æ�¥è°ƒèŠ‚ DPI。" #~ msgid "" #~ "Automatically switch the mouse wheel between ratchet and freespin mode.\n" #~ "The mouse wheel is always free at 0, and always ratcheted at 50" #~ msgstr "" #~ "自动切æ�¢æ»šè½®çš„æ®µè�½å’Œè‡ªç”±æ»šåŠ¨æ¨¡å¼�。\n" #~ "在 0 时,滚轮永远为自由滚动模å¼�;在 50 时,滚轮永远为段è�½æ¨¡å¼�" #~ msgid "Battery information unknown." #~ msgstr "电池信æ�¯æœªçŸ¥ã€‚" #~ msgid "Battery: %(level)s" #~ msgstr "电池: %(level)s" #~ msgid "Battery: %(percent)d%%" #~ msgstr "电池: %(percent)d%%" #~ msgid "Count" #~ msgstr "æ•°é‡�" #~ msgid "DPI Sliding Adjustment" #~ msgstr "DPI 滑动调节" #~ msgid "Divert G Keys" #~ msgstr "G é”®é‡�定义" #~ msgid "" #~ "Diverted key or button depressed or released.\n" #~ "Use the Key/Button Diversion setting to divert keys and buttons." #~ msgstr "" #~ "é‡�定义的按键或按钮未按下或已释放。\n" #~ "è¦�é‡�定义按键/按钮,请使用按键/按钮é‡�定义设置。" #~ msgid "Effectively turns off thumb scrolling in Linux." #~ msgstr "在 Linux 中有效关闭拇指滚轮滚动。" #~ msgid "Effectively turns off wheel scrolling in Linux." #~ msgstr "在 Linux 中有效关闭滚轮滚动。" #~ msgid "" #~ "Enable onboard profiles, which often control report rate and keyboard " #~ "lighting" #~ msgstr "å�¯ç”¨æ�¿è½½é¢„设,通常会接管回报率和键盘ç�¯å…‰" #~ msgid "" #~ "Found a Logitech Receiver (%s), but did not have permission to open it." #~ msgstr "å·²å�‘现 1 个罗技接收器 (%s),但您没有访问æ�ƒé™�。" #~ msgid "Found a new device" #~ msgstr "å�‘现 1 个新设备" #~ msgid "Frequency of device polling, in milliseconds" #~ msgstr "设备轮询频率,å�•ä½�为毫秒" #~ msgid "HID++ mode for horizontal scroll with the thumb wheel." #~ msgstr "为滚轮的水平滚动å�¯ç”¨ HID++ 模å¼�。" #~ msgid "HID++ mode for vertical scroll with the wheel." #~ msgstr "为滚轮的垂直滚动å�¯ç”¨ HID++ 模å¼�。" #~ msgid "" #~ "If the device is already turned on,\n" #~ "turn if off and on again." #~ msgstr "" #~ "若设备的电æº�å·²ç»�打开,\n" #~ "请先关闭å†�å¼€å�¯ã€‚" #~ msgid "" #~ "If you've just installed Solaar, try removing the receiver and plugging " #~ "it back in." #~ msgstr "若您刚刚安装 Solaar,请å°�试将接收器拔下å†�é‡�æ–°æ�’上。" #~ msgid "Lighting: %(level)s lux" #~ msgstr "照明: %(level)s lux" #~ msgid "" #~ "Make G keys send GKEY HID++ notifications (which trigger Solaar rules but " #~ "are otherwise ignored)." #~ msgstr "" #~ "使 G é”®å�‘é€� GKEY (G é”®) HID++ 通告 (这会触å�‘ Solaar 规则,但如果没有,就会" #~ "被忽略)" #~ msgid "" #~ "Make the key or button send HID++ notifications (which trigger Solaar " #~ "rules but are otherwise ignored)." #~ msgstr "" #~ "使按键或按钮å�‘é€� HID++ 通告 (这会触å�‘ Solaar 规则,但如果没有,就会被忽略)" #~ msgid "May also make M keys and MR key send HID++ notifications" #~ msgstr "å�Œæ ·ä¹Ÿä½¿ M 键和 MR é”®å�‘é€� HID++ 通告" #~ msgid "No Logitech device found" #~ msgstr "未å�‘现罗技设备" #~ msgid "No Logitech receiver found" #~ msgstr "未å�‘现罗技接收器" #~ msgid "No device paired" #~ msgstr "æ— å·²é…�对设备" #~ msgid "Only one device can be paired to this receiver" #~ msgstr "此接收器仅支æŒ�é…�对 1 个设备" #~ msgid "Only one device can be paired to this receiver." #~ msgstr "此接收器å�ªèƒ½ä¸Žä¸€ä¸ªè®¾å¤‡é…�对。" #~ msgid "Polling Rate (ms)" #~ msgstr "轮询速率 (ms)" #~ msgid "Quit" #~ msgstr "退出" #~ msgid "Scroll Wheel Rachet" #~ msgstr "滚轮段è�½æ¨¡å¼�" #~ msgid "Send a gesture by sliding the mouse while holding the button down." #~ msgstr "通过在按ä½�按钮的å�Œæ—¶æ»‘动鼠标æ�¥å�‘é€�手势。" #~ msgid "" #~ "Shows status of devices connected\n" #~ "through wireless Logitech receivers." #~ msgstr "" #~ "显示罗技接收器\n" #~ "已连接的设备状æ€�。" #~ msgid "Smooth Scrolling" #~ msgstr "平滑滚动" #~ msgid "The receiver only supports %d paired device(s)." #~ msgstr "此接收器仅支æŒ� %d 个é…�对设备。" #~ msgid "The receiver was unplugged." #~ msgstr "接收器被移除。" #~ msgid "" #~ "The wireless link between this device and its receiver is not encrypted.\n" #~ "\n" #~ "For pointing devices (mice, trackballs, trackpads), this is a minor " #~ "security issue.\n" #~ "\n" #~ "It is, however, a major security issue for text-input devices (keyboards, " #~ "numpads),\n" #~ "because typed text can be sniffed inconspicuously by 3rd parties within " #~ "range." #~ msgstr "" #~ "设备与接收器间的无线连接未加密。\n" #~ "\n" #~ "对定ä½�设备(如鼠标ã€�轨迹ç�ƒã€�触摸æ�¿ï¼‰æ�¥è¯´è¿™ä¸�是什么问题。\n" #~ "\n" #~ "然而这对于内容输入设备(如键盘ã€�数字键盘)å�´æ˜¯ä¸€ä¸ªé‡�大的安全问题,\n" #~ "您输入的内容有å�¯èƒ½è¢«ç¬¬ä¸‰æ–¹å�·å�·ç›‘å�¬åˆ°ã€‚" #~ msgid "" #~ "Try removing the device and plugging it back in or turning it off and " #~ "then on." #~ msgstr "请å°�试将设备拔下å†�é‡�æ–°æ�’上,或关闭电æº�å�Žé‡�新打开。" #~ msgid "Turn illumination on or off on keyboard." #~ msgstr "打开或关闭键盘背光。" #~ msgid "USB id" #~ msgstr "USB åº�å�·" #~ msgid "Up to %d devices can be paired to this receiver" #~ msgstr "此接收器å�¯é…�对至多 %d 个设备" #~ msgid "You may have to first turn the device off and on again." #~ msgstr "您å�¯èƒ½éœ€è¦�先关闭设备的电æº�å†�é‡�新打开。" #~ msgid "closed" #~ msgstr "关闭" #~ msgid "last known" #~ msgstr "最å�Žå·²çŸ¥" #~ msgid "lux" #~ msgstr "lux" #~ msgid "none" #~ msgstr "æ— " #~ msgid "open" #~ msgstr "å¼€å�¯" #~ msgid "pair new device" #~ msgstr "é…�对新设备" #~ msgid "paired devices" #~ msgstr "个已é…�对设备" #~ msgid "pairing lock is " #~ msgstr "é…�对é”�å·²" #~ msgid "unknown" #~ msgstr "未知的" Solaar-1.1.20/po/zh_TW.po000066400000000000000000001615551522022367600150470ustar00rootroot00000000000000# Chinese translations for solaar package # Copyright (C) 2014 THE solaar'S COPYRIGHT HOLDER # This file is distributed under the same license as the solaar package. # Automatically generated, 2014. # msgid "" msgstr "" "Project-Id-Version: solaar 0.9.2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2025-12-01 21:43+0300\n" "PO-Revision-Date: 2025-12-07 07:17+0800\n" "Last-Translator: Peter Dave Hello \n" "Language-Team: Peter Dave Hello \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Language: zh_TW\n" "X-Source-Language: C\n" "X-Generator: Poedit 3.0\n" #: lib/logitech_receiver/base_usb.py:52 msgid "Bolt Receiver" msgstr "Bolt 接收器" #: lib/logitech_receiver/base_usb.py:64 msgid "Unifying Receiver" msgstr "Unifying 接收器" #: lib/logitech_receiver/base_usb.py:75 lib/logitech_receiver/base_usb.py:87 #: lib/logitech_receiver/base_usb.py:100 lib/logitech_receiver/base_usb.py:113 msgid "Nano Receiver" msgstr "Nano 接收器" #: lib/logitech_receiver/base_usb.py:125 msgid "Lightspeed Receiver" msgstr "Lightspeed 接收器" #: lib/logitech_receiver/base_usb.py:135 msgid "EX100 Receiver 27 Mhz" msgstr "EX100 27 Mhz 接收器" #: lib/logitech_receiver/common.py:649 #, python-format msgid "Battery: %(level)s (%(status)s)" msgstr "é›»é‡�:%(level)s (%(status)s)" #: lib/logitech_receiver/common.py:652 #, python-format msgid "Battery: %(percent)d%% (%(status)s)" msgstr "é›»é‡�:%(percent)d%% (%(status)s)" #: lib/logitech_receiver/hidpp20.py:1048 #: lib/logitech_receiver/settings_templates.py:299 msgid "Disabled" msgstr "å·²å�œç”¨" #: lib/logitech_receiver/hidpp20.py:1049 msgid "Static" msgstr "é�œæ…‹" #: lib/logitech_receiver/hidpp20.py:1050 msgid "Pulse" msgstr "脈è¡�" #: lib/logitech_receiver/hidpp20.py:1051 msgid "Cycle" msgstr "循環" #: lib/logitech_receiver/hidpp20.py:1052 msgid "Boot" msgstr "開機" #: lib/logitech_receiver/hidpp20.py:1053 msgid "Demo" msgstr "示範" #: lib/logitech_receiver/hidpp20.py:1055 msgid "Breathe" msgstr "呼å�¸" #: lib/logitech_receiver/hidpp20.py:1058 msgid "Ripple" msgstr "漣漪" #: lib/logitech_receiver/hidpp20.py:1059 msgid "Decomposition" msgstr "分解" #: lib/logitech_receiver/hidpp20.py:1060 msgid "Signature1" msgstr "ç°½å��樣å¼� 1" #: lib/logitech_receiver/hidpp20.py:1061 msgid "Signature2" msgstr "ç°½å��樣å¼� 2" #: lib/logitech_receiver/hidpp20.py:1062 msgid "CycleS" msgstr "循環å¼�" #: lib/logitech_receiver/hidpp20.py:1126 msgid "Unknown Location" msgstr "未知ä½�ç½®" #: lib/logitech_receiver/hidpp20.py:1127 msgid "Primary" msgstr "主è¦�" #: lib/logitech_receiver/hidpp20.py:1128 msgid "Logo" msgstr "Logo" #: lib/logitech_receiver/hidpp20.py:1129 msgid "Left Side" msgstr "å·¦å�´" #: lib/logitech_receiver/hidpp20.py:1130 msgid "Right Side" msgstr "å�³å�´" #: lib/logitech_receiver/hidpp20.py:1131 msgid "Combined" msgstr "çµ�å�ˆ" #: lib/logitech_receiver/hidpp20.py:1132 msgid "Primary 1" msgstr "主è¦� 1" #: lib/logitech_receiver/hidpp20.py:1133 msgid "Primary 2" msgstr "主è¦� 2" #: lib/logitech_receiver/hidpp20.py:1134 msgid "Primary 3" msgstr "主è¦� 3" #: lib/logitech_receiver/hidpp20.py:1135 msgid "Primary 4" msgstr "主è¦� 4" #: lib/logitech_receiver/hidpp20.py:1136 msgid "Primary 5" msgstr "主è¦� 5" #: lib/logitech_receiver/hidpp20.py:1137 msgid "Primary 6" msgstr "主è¦� 6" #: lib/logitech_receiver/i18n.py:28 msgid "empty" msgstr "電池已耗盡" #: lib/logitech_receiver/i18n.py:29 msgid "critical" msgstr "極低" #: lib/logitech_receiver/i18n.py:30 msgid "low" msgstr "低" #: lib/logitech_receiver/i18n.py:31 msgid "average" msgstr "中等" #: lib/logitech_receiver/i18n.py:32 msgid "good" msgstr "良好" #: lib/logitech_receiver/i18n.py:33 msgid "full" msgstr "滿格" #: lib/logitech_receiver/i18n.py:35 msgid "discharging" msgstr "放電中" #: lib/logitech_receiver/i18n.py:36 msgid "recharging" msgstr "充電中" #: lib/logitech_receiver/i18n.py:37 lib/solaar/ui/window.py:700 msgid "charging" msgstr "充電中" #: lib/logitech_receiver/i18n.py:38 msgid "not charging" msgstr "未充電" #: lib/logitech_receiver/i18n.py:39 msgid "almost full" msgstr "å�³å°‡å……滿" #: lib/logitech_receiver/i18n.py:40 msgid "charged" msgstr "已充滿" #: lib/logitech_receiver/i18n.py:41 msgid "slow recharge" msgstr "慢速充電" #: lib/logitech_receiver/i18n.py:42 msgid "invalid battery" msgstr "電池無效" #: lib/logitech_receiver/i18n.py:43 msgid "thermal error" msgstr "溫度異常" #: lib/logitech_receiver/i18n.py:44 msgid "error" msgstr "錯誤" #: lib/logitech_receiver/i18n.py:45 msgid "standard" msgstr "標準" #: lib/logitech_receiver/i18n.py:46 msgid "fast" msgstr "快速" #: lib/logitech_receiver/i18n.py:47 msgid "slow" msgstr "æ…¢" #: lib/logitech_receiver/i18n.py:49 msgid "device timeout" msgstr "è£�置逾時" #: lib/logitech_receiver/i18n.py:50 msgid "device not supported" msgstr "ä¸�支æ�´æ­¤è£�ç½®" #: lib/logitech_receiver/i18n.py:51 msgid "too many devices" msgstr "è£�置數é‡�太多" #: lib/logitech_receiver/i18n.py:52 msgid "sequence timeout" msgstr "åº�列逾時" #: lib/logitech_receiver/i18n.py:54 lib/solaar/ui/window.py:555 msgid "Firmware" msgstr "韌體" #: lib/logitech_receiver/i18n.py:55 msgid "Bootloader" msgstr "開機載入程å¼�" #: lib/logitech_receiver/i18n.py:56 msgid "Hardware" msgstr "硬體" #: lib/logitech_receiver/i18n.py:57 msgid "Other" msgstr "å…¶ä»–" #: lib/logitech_receiver/i18n.py:59 msgid "Left Button" msgstr "å·¦é�µ" #: lib/logitech_receiver/i18n.py:60 msgid "Right Button" msgstr "å�³é�µ" #: lib/logitech_receiver/i18n.py:61 msgid "Middle Button" msgstr "中é�µ" #: lib/logitech_receiver/i18n.py:62 msgid "Back Button" msgstr "返回é�µ" #: lib/logitech_receiver/i18n.py:63 msgid "Forward Button" msgstr "å‰�進é�µ" #: lib/logitech_receiver/i18n.py:64 msgid "Mouse Gesture Button" msgstr "滑鼠手勢é�µ" #: lib/logitech_receiver/i18n.py:65 msgid "Smart Shift" msgstr "智慧切æ�›" #: lib/logitech_receiver/i18n.py:66 msgid "DPI Switch" msgstr "DPI 切æ�›" #: lib/logitech_receiver/i18n.py:67 msgid "Left Tilt" msgstr "å�‘左傾斜" #: lib/logitech_receiver/i18n.py:68 msgid "Right Tilt" msgstr "å�‘å�³å‚¾æ–œ" #: lib/logitech_receiver/i18n.py:69 msgid "Left Click" msgstr "å·¦é�µ" #: lib/logitech_receiver/i18n.py:70 msgid "Right Click" msgstr "å�³é�µ" #: lib/logitech_receiver/i18n.py:71 msgid "Mouse Middle Button" msgstr "滑鼠中é�µ" #: lib/logitech_receiver/i18n.py:72 msgid "Mouse Back Button" msgstr "滑鼠返回é�µ" #: lib/logitech_receiver/i18n.py:73 msgid "Mouse Forward Button" msgstr "滑鼠å‰�進é�µ" #: lib/logitech_receiver/i18n.py:74 msgid "Gesture Button Navigation" msgstr "手勢按鈕導覽" #: lib/logitech_receiver/i18n.py:75 msgid "Mouse Scroll Left Button" msgstr "滑鼠滾輪å�‘左按鈕" #: lib/logitech_receiver/i18n.py:76 msgid "Mouse Scroll Right Button" msgstr "滑鼠滾輪å�‘å�³æŒ‰éˆ•" #: lib/logitech_receiver/i18n.py:78 msgid "pressed" msgstr "按下" #: lib/logitech_receiver/i18n.py:79 msgid "released" msgstr "放開" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "connected" msgstr "已連線" #: lib/logitech_receiver/notifications.py:156 lib/solaar/listener.py:243 msgid "disconnected" msgstr "已斷線" #: lib/logitech_receiver/notifications.py:182 msgid "unpaired" msgstr "未é…�å°�" #: lib/logitech_receiver/notifications.py:231 msgid "powered on" msgstr "已啟動" #: lib/logitech_receiver/notifications.py:283 msgid "ADC measurement notification" msgstr "ADC é‡�測通知" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is closed" msgstr "é…�å°�鎖已關閉" #: lib/logitech_receiver/notifications.py:428 #: lib/logitech_receiver/notifications.py:483 msgid "pairing lock is open" msgstr "é…�å°�鎖已開啟" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is closed" msgstr "探索鎖已關閉" #: lib/logitech_receiver/notifications.py:446 msgid "discovery lock is open" msgstr "探索鎖已開啟" #: lib/logitech_receiver/receiver.py:437 msgid "No paired devices." msgstr "沒有已é…�å°�çš„è£�置。" #: lib/logitech_receiver/receiver.py:439 lib/solaar/ui/window.py:606 #, python-format msgid "%(count)s paired device." msgid_plural "%(count)s paired devices." msgstr[0] "%(count)s 個已é…�å°�è£�置。" #: lib/logitech_receiver/settings.py:602 msgid "register" msgstr "暫存器" #: lib/logitech_receiver/settings.py:616 lib/logitech_receiver/settings.py:654 msgid "feature" msgstr "功能" #: lib/logitech_receiver/settings_templates.py:138 msgid "Swap Fx function" msgstr "互æ�› Fx é�µåŠŸèƒ½" #: lib/logitech_receiver/settings_templates.py:141 msgid "" "When set, the F1..F12 keys will activate their special function,\n" "and you must hold the FN key to activate their standard function." msgstr "" "啟用後,F1 到 F12 é�µå°‡æœƒå•Ÿå‹•特殊功能,\n" "è‹¥è¦�使用標準功能請å�Œæ™‚按ä½� FN é�µã€‚" #: lib/logitech_receiver/settings_templates.py:146 msgid "" "When unset, the F1..F12 keys will activate their standard function,\n" "and you must hold the FN key to activate their special function." msgstr "" "å�œç”¨å¾Œï¼ŒF1 到 F12 é�µå°‡æœƒå•Ÿå‹•標準功能,\n" "è‹¥è¦�使用特殊功能請å�Œæ™‚按ä½� FN é�µã€‚" #: lib/logitech_receiver/settings_templates.py:154 msgid "Hand Detection" msgstr "手掌å�µæ¸¬" #: lib/logitech_receiver/settings_templates.py:155 msgid "Turn on illumination when the hands hover over the keyboard." msgstr "當手掌置於在é�µç›¤ä¸Šæ–¹æ™‚開啟照明。" #: lib/logitech_receiver/settings_templates.py:162 msgid "Scroll Wheel Smooth Scrolling" msgstr "滾輪平滑æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:163 #: lib/logitech_receiver/settings_templates.py:410 #: lib/logitech_receiver/settings_templates.py:439 msgid "High-sensitivity mode for vertical scroll with the wheel." msgstr "滾輪垂直æ�²å‹•的高é�ˆæ•�度模å¼�。" #: lib/logitech_receiver/settings_templates.py:170 msgid "Side Scrolling" msgstr "å�´é‚Šæ�²å‹•" #: lib/logitech_receiver/settings_templates.py:172 msgid "" "When disabled, pushing the wheel sideways sends custom button events\n" "instead of the standard side-scrolling events." msgstr "" "å�œç”¨å¾Œï¼Œå�‘å�´é‚ŠæŽ¨å‹•æ»¾è¼ªå°‡æœƒå‚³é€�自訂按鈕事件,\n" "而é�žæ¨™æº–çš„å�´é‚Šæ�²å‹•事件。" #: lib/logitech_receiver/settings_templates.py:182 msgid "Sensitivity (DPI - older mice)" msgstr "é�ˆæ•�度(DPI - 較舊的滑鼠)" #: lib/logitech_receiver/settings_templates.py:183 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 msgid "Mouse movement sensitivity" msgstr "滑鼠移動é�ˆæ•�度" #: lib/logitech_receiver/settings_templates.py:256 msgid "Backlight Timed" msgstr "背光計時" #: lib/logitech_receiver/settings_templates.py:257 #: lib/logitech_receiver/settings_templates.py:397 msgid "Set illumination time for keyboard." msgstr "設定é�µç›¤çš„照明時間。" #: lib/logitech_receiver/settings_templates.py:268 msgid "Backlight" msgstr "背光" #: lib/logitech_receiver/settings_templates.py:269 msgid "" "Illumination level on keyboard. Changes made are only applied in Manual " "mode." msgstr "é�µç›¤ä¸Šçš„亮度等級。僅在手動模å¼�下é�©ç”¨ã€‚" #: lib/logitech_receiver/settings_templates.py:301 msgid "Automatic" msgstr "自動" #: lib/logitech_receiver/settings_templates.py:303 msgid "Manual" msgstr "手動" #: lib/logitech_receiver/settings_templates.py:305 msgid "Enabled" msgstr "已啟用" #: lib/logitech_receiver/settings_templates.py:311 msgid "Backlight Level" msgstr "背光等級" #: lib/logitech_receiver/settings_templates.py:312 msgid "Illumination level on keyboard when in Manual mode." msgstr "手動模å¼�下的é�µç›¤ç…§æ˜Žç­‰ç´šã€‚" #: lib/logitech_receiver/settings_templates.py:369 msgid "Backlight Delay Hands Out" msgstr "手離開後背光延é�²" #: lib/logitech_receiver/settings_templates.py:370 msgid "" "Delay in seconds until backlight fades out with hands away from keyboard." msgstr "手離開é�µç›¤å¾Œï¼ŒèƒŒå…‰æ·¡å‡ºçš„å»¶é�²ç§’數。" #: lib/logitech_receiver/settings_templates.py:378 msgid "Backlight Delay Hands In" msgstr "手é� è¿‘後背光延é�²" #: lib/logitech_receiver/settings_templates.py:379 msgid "Delay in seconds until backlight fades out with hands near keyboard." msgstr "手é� è¿‘é�µç›¤å¾Œï¼ŒèƒŒå…‰æ·¡å‡ºçš„å»¶é�²ç§’數。" #: lib/logitech_receiver/settings_templates.py:387 msgid "Backlight Delay Powered" msgstr "供電後背光延é�²" #: lib/logitech_receiver/settings_templates.py:388 msgid "Delay in seconds until backlight fades out with external power." msgstr "外部供電時,背光淡出的延é�²ç§’數。" #: lib/logitech_receiver/settings_templates.py:396 msgid "Backlight (Seconds)" msgstr "背光(秒)" #: lib/logitech_receiver/settings_templates.py:408 msgid "Scroll Wheel High Resolution" msgstr "滾輪高解æž�度" #: lib/logitech_receiver/settings_templates.py:412 #: lib/logitech_receiver/settings_templates.py:441 msgid "Set to ignore if scrolling is abnormally fast or slow" msgstr "è‹¥æ�²å‹•速度異常快或慢,設定為忽略" #: lib/logitech_receiver/settings_templates.py:419 #: lib/logitech_receiver/settings_templates.py:450 msgid "Scroll Wheel Diversion" msgstr "滾輪轉å�‘" #: lib/logitech_receiver/settings_templates.py:421 msgid "" "Make scroll wheel send LOWRES_WHEEL HID++ notifications (which trigger " "Solaar rules but are otherwise ignored)." msgstr "" "使輪傳é€� LOWRES_WHEEL HID++ 通知(會觸發 Solaar è¦�則,但其他情æ³�下會被忽" "略)。" #: lib/logitech_receiver/settings_templates.py:428 msgid "Scroll Wheel Direction" msgstr "滾輪方å�‘" #: lib/logitech_receiver/settings_templates.py:429 msgid "Invert direction for vertical scroll with wheel." msgstr "å��轉滾輪的垂直æ�²å‹•æ–¹å�‘。" #: lib/logitech_receiver/settings_templates.py:437 msgid "Scroll Wheel Resolution" msgstr "滾輪解æž�度" #: lib/logitech_receiver/settings_templates.py:452 msgid "" "Make scroll wheel send HIRES_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "讓滾輪傳é€� HIRES_WHEEL HID++ 通知(會觸發 Solaar è¦�則,但其他情æ³�下會被忽" "略)。" #: lib/logitech_receiver/settings_templates.py:461 msgid "Sensitivity (Pointer Speed)" msgstr "é�ˆæ•�度(指標速度)" #: lib/logitech_receiver/settings_templates.py:462 msgid "Speed multiplier for mouse (256 is normal multiplier)." msgstr "滑鼠速度å€�數(256 為正常å€�數)。" #: lib/logitech_receiver/settings_templates.py:472 msgid "Thumb Wheel Diversion" msgstr "拇指滾輪轉å�‘" #: lib/logitech_receiver/settings_templates.py:474 msgid "" "Make thumb wheel send THUMB_WHEEL HID++ notifications (which trigger Solaar " "rules but are otherwise ignored)." msgstr "" "讓拇指滾輪傳é€� THUMB_WHEEL HID++ 通知(會觸發 Solaar è¦�則,但其他情æ³�下會被忽" "略)。" #: lib/logitech_receiver/settings_templates.py:483 msgid "Thumb Wheel Direction" msgstr "拇指滾輪方å�‘" #: lib/logitech_receiver/settings_templates.py:484 msgid "Invert thumb wheel scroll direction." msgstr "å��轉拇指滾輪æ�²å‹•æ–¹å�‘。" #: lib/logitech_receiver/settings_templates.py:504 msgid "Onboard Profiles" msgstr "內建設定檔" #: lib/logitech_receiver/settings_templates.py:505 msgid "" "Enable an onboard profile, which controls report rate, sensitivity, and " "button actions" msgstr "啟用內建設定檔,å�¯æŽ§åˆ¶å›žå ±é€Ÿçއã€�é�ˆæ•�度和按鈕動作" #: lib/logitech_receiver/settings_templates.py:549 #: lib/logitech_receiver/settings_templates.py:582 msgid "Report Rate" msgstr "回報速率" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 msgid "Frequency of device movement reports" msgstr "è£�置移動回報的頻率" #: lib/logitech_receiver/settings_templates.py:551 #: lib/logitech_receiver/settings_templates.py:584 #: lib/logitech_receiver/settings_templates.py:1019 #: lib/logitech_receiver/settings_templates.py:1047 #: lib/logitech_receiver/settings_templates.py:1421 #: lib/logitech_receiver/settings_templates.py:1452 msgid "May need Onboard Profiles set to Disable to be effective." msgstr "å�¯èƒ½éœ€è¦�將內建設定檔設為å�œç”¨æ‰�能生效。" #: lib/logitech_receiver/settings_templates.py:612 msgid "Divert crown events" msgstr "轉å�‘多功能旋鈕事件" #: lib/logitech_receiver/settings_templates.py:613 msgid "" "Make crown send CROWN HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "讓多功能旋鈕傳é€� CROWN HID++ 通知(會觸發 Solaar è¦�則,但其他情æ³�下會被忽" "略)。" #: lib/logitech_receiver/settings_templates.py:621 msgid "Crown smooth scroll" msgstr "多功能旋鈕平滑æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:622 msgid "Set crown smooth scroll" msgstr "設定多功能旋鈕平滑æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:630 msgid "Divert G and M Keys" msgstr "轉å�‘ G é�µå’Œ M é�µ" #: lib/logitech_receiver/settings_templates.py:631 msgid "" "Make G and M keys send HID++ notifications (which trigger Solaar rules but " "are otherwise ignored)." msgstr "" "讓 G é�µå’Œ M é�µå‚³é€� HID++ 通知(會觸發 Solaar è¦�則,但其他情æ³�下會被忽略)。" #: lib/logitech_receiver/settings_templates.py:645 msgid "Scroll Wheel Ratcheted" msgstr "滾輪棘輪" #: lib/logitech_receiver/settings_templates.py:646 msgid "" "Switch the mouse wheel between speed-controlled ratcheting and always " "freespin." msgstr "在速度控制的棘輪模å¼�和永é� è‡ªç”±æ�²å‹•之間切æ�›æ»‘鼠滾輪。" #: lib/logitech_receiver/settings_templates.py:648 msgid "Freespinning" msgstr "自由æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:648 msgid "Ratcheted" msgstr "棘輪å¼�" #: lib/logitech_receiver/settings_templates.py:655 msgid "Scroll Wheel Ratchet Speed" msgstr "滾輪棘輪速度" #: lib/logitech_receiver/settings_templates.py:657 msgid "" "Use the mouse wheel speed to switch between ratcheted and freespinning.\n" "The mouse wheel is always ratcheted at 50." msgstr "" "使用滑鼠滾輪速度在棘輪和自由æ�²å‹•之間切æ�›ã€‚\n" "滾輪在 50 時永é� è™•於棘輪狀態。" #: lib/logitech_receiver/settings_templates.py:707 msgid "Scroll Wheel Ratchet Torque" msgstr "滾輪棘輪扭矩" #: lib/logitech_receiver/settings_templates.py:708 msgid "Change the torque needed to overcome the ratchet." msgstr "變更克æœ�棘輪所需的扭矩。" #: lib/logitech_receiver/settings_templates.py:743 msgid "Key/Button Actions" msgstr "é�µ/按鈕動作" #: lib/logitech_receiver/settings_templates.py:745 msgid "Change the action for the key or button." msgstr "變更按é�µæˆ–按鈕的動作。" #: lib/logitech_receiver/settings_templates.py:747 msgid "Overridden by diversion." msgstr "已被轉å�‘覆寫。" #: lib/logitech_receiver/settings_templates.py:749 msgid "" "Changing important actions (such as for the left mouse button) can result in " "an unusable system." msgstr "變更é‡�è¦�動作(例如滑鼠左é�µï¼‰å�¯èƒ½æœƒå°Žè‡´ç³»çµ±ç„¡æ³•使用。" #: lib/logitech_receiver/settings_templates.py:924 msgid "Key/Button Diversion" msgstr "é�µ/按鈕轉æ�›" #: lib/logitech_receiver/settings_templates.py:925 msgid "" "Make the key or button send HID++ notifications (Diverted) or initiate Mouse " "Gestures or Sliding DPI" msgstr "讓按é�µæˆ–按鈕傳é€� HID++ 通知(已轉å�‘)或啟動滑鼠手勢或滑動 DPI。" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Diverted" msgstr "已轉å�‘" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 msgid "Mouse Gestures" msgstr "滑鼠手勢" #: lib/logitech_receiver/settings_templates.py:928 #: lib/logitech_receiver/settings_templates.py:929 #: lib/logitech_receiver/settings_templates.py:930 msgid "Regular" msgstr "一般" #: lib/logitech_receiver/settings_templates.py:928 msgid "Sliding DPI" msgstr "滑動 DPI" #: lib/logitech_receiver/settings_templates.py:1018 #: lib/logitech_receiver/settings_templates.py:1046 msgid "Sensitivity (DPI)" msgstr "é�ˆæ•�度 (DPI)" #: lib/logitech_receiver/settings_templates.py:1123 msgid "Sensitivity Switching" msgstr "é�ˆæ•�度切æ�›" #: lib/logitech_receiver/settings_templates.py:1125 msgid "" "Switch the current sensitivity and the remembered sensitivity when the key " "or button is pressed.\n" "If there is no remembered sensitivity, just remember the current sensitivity" msgstr "" "按下按é�µæˆ–按鈕時,切æ�›ç›®å‰�é�ˆæ•�度和已記憶的é�ˆæ•�度。\n" "若沒有已記憶的é�ˆæ•�度,則僅記ä½�ç›®å‰�çš„é�ˆæ•�度" #: lib/logitech_receiver/settings_templates.py:1129 msgid "Off" msgstr "關閉" #: lib/logitech_receiver/settings_templates.py:1160 msgid "Disable keys" msgstr "å�œç”¨æŒ‰é�µ" #: lib/logitech_receiver/settings_templates.py:1161 msgid "Disable specific keyboard keys." msgstr "å�œç”¨ç‰¹å®šé�µç›¤æŒ‰é�µã€‚" #: lib/logitech_receiver/settings_templates.py:1164 #, python-format msgid "Disables the %s key." msgstr "å�œç”¨ %s é�µã€‚" #: lib/logitech_receiver/settings_templates.py:1177 #: lib/logitech_receiver/settings_templates.py:1234 msgid "Set OS" msgstr "設定作業系統" #: lib/logitech_receiver/settings_templates.py:1178 #: lib/logitech_receiver/settings_templates.py:1235 msgid "Change keys to match OS." msgstr "變更按é�µä»¥ç¬¦å�ˆä½œæ¥­ç³»çµ±ã€‚" #: lib/logitech_receiver/settings_templates.py:1247 msgid "Change Host" msgstr "變更主機" #: lib/logitech_receiver/settings_templates.py:1248 msgid "Switch connection to a different host" msgstr "切æ�›é€£ç·šåˆ°ä¸�å�Œçš„主機" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Performs a left click." msgstr "執行左é�µé»žé�¸ã€‚" #: lib/logitech_receiver/settings_templates.py:1272 msgid "Single tap" msgstr "單次點é�¸" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Performs a right click." msgstr "執行å�³é�µé»žé�¸ã€‚" #: lib/logitech_receiver/settings_templates.py:1273 msgid "Single tap with two fingers" msgstr "用兩根手指單次點é�¸" #: lib/logitech_receiver/settings_templates.py:1274 msgid "Single tap with three fingers" msgstr "用三根手指單次點é�¸" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Double tap" msgstr "點兩下" #: lib/logitech_receiver/settings_templates.py:1278 msgid "Performs a double click." msgstr "執行點兩下。" #: lib/logitech_receiver/settings_templates.py:1279 msgid "Double tap with two fingers" msgstr "用兩根手指點兩下" #: lib/logitech_receiver/settings_templates.py:1280 msgid "Double tap with three fingers" msgstr "用三根手指點兩下" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Drags items by dragging the finger after double tapping." msgstr "點兩下後拖曳手指來拖曳項目。" #: lib/logitech_receiver/settings_templates.py:1283 msgid "Tap and drag" msgstr "點é�¸ä¸¦æ‹–曳" #: lib/logitech_receiver/settings_templates.py:1285 msgid "Tap and drag with two fingers" msgstr "用兩根手指點兩下並拖曳" #: lib/logitech_receiver/settings_templates.py:1286 msgid "Drags items by dragging the fingers after double tapping." msgstr "點兩下後拖曳手指來拖曳項目。" #: lib/logitech_receiver/settings_templates.py:1288 msgid "Tap and drag with three fingers" msgstr "用三根手指點é�¸ä¸¦æ‹–曳" #: lib/logitech_receiver/settings_templates.py:1291 msgid "Suppress tap and edge gestures" msgstr "å�œç”¨è¼•觸和邊緣手勢" #: lib/logitech_receiver/settings_templates.py:1292 msgid "Disables tap and edge gestures (equivalent to pressing Fn+LeftClick)." msgstr "å�œç”¨è¼•觸和邊緣手勢(相當於按下 Fn+å·¦é�µé»žé�¸ï¼‰ã€‚" #: lib/logitech_receiver/settings_templates.py:1294 msgid "Scroll with one finger" msgstr "用一根手指æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:1294 #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scrolls." msgstr "æ�²å‹•。" #: lib/logitech_receiver/settings_templates.py:1295 #: lib/logitech_receiver/settings_templates.py:1298 msgid "Scroll with two fingers" msgstr "用兩根手指æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scroll horizontally with two fingers" msgstr "用兩根手指水平æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:1296 msgid "Scrolls horizontally." msgstr "æ°´å¹³æ�²å‹•。" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scroll vertically with two fingers" msgstr "用兩根手指垂直æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:1297 msgid "Scrolls vertically." msgstr "垂直æ�²å‹•。" #: lib/logitech_receiver/settings_templates.py:1299 msgid "Inverts the scrolling direction." msgstr "å��轉æ�²å‹•æ–¹å�‘。" #: lib/logitech_receiver/settings_templates.py:1299 msgid "Natural scrolling" msgstr "自然æ�²å‹•" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Enables the thumbwheel." msgstr "啟用拇指滾輪。" #: lib/logitech_receiver/settings_templates.py:1300 msgid "Thumbwheel" msgstr "拇指滾輪" #: lib/logitech_receiver/settings_templates.py:1311 #: lib/logitech_receiver/settings_templates.py:1315 msgid "Swipe from the top edge" msgstr "從上緣滑動" #: lib/logitech_receiver/settings_templates.py:1312 msgid "Swipe from the left edge" msgstr "從左緣滑動" #: lib/logitech_receiver/settings_templates.py:1313 msgid "Swipe from the right edge" msgstr "從å�³ç·£æ»‘å‹•" #: lib/logitech_receiver/settings_templates.py:1314 msgid "Swipe from the bottom edge" msgstr "從下緣滑動" #: lib/logitech_receiver/settings_templates.py:1316 msgid "Swipe two fingers from the left edge" msgstr "從左緣滑動兩根手指" #: lib/logitech_receiver/settings_templates.py:1317 msgid "Swipe two fingers from the right edge" msgstr "從å�³ç·£æ»‘動兩根手指" #: lib/logitech_receiver/settings_templates.py:1318 msgid "Swipe two fingers from the bottom edge" msgstr "從下緣滑動兩根手指" #: lib/logitech_receiver/settings_templates.py:1319 msgid "Swipe two fingers from the top edge" msgstr "從上緣滑動兩根手指" #: lib/logitech_receiver/settings_templates.py:1320 #: lib/logitech_receiver/settings_templates.py:1324 msgid "Pinch to zoom out; spread to zoom in." msgstr "æ��å�ˆä»¥ç¸®å°�;張開以放大。" #: lib/logitech_receiver/settings_templates.py:1320 msgid "Zoom with two fingers." msgstr "用兩根手指縮放。" #: lib/logitech_receiver/settings_templates.py:1321 msgid "Pinch to zoom out." msgstr "æ��å�ˆä»¥ç¸®å°�。" #: lib/logitech_receiver/settings_templates.py:1322 msgid "Spread to zoom in." msgstr "張開以放大。" #: lib/logitech_receiver/settings_templates.py:1323 msgid "Zoom with three fingers." msgstr "用三根手指縮放。" #: lib/logitech_receiver/settings_templates.py:1324 msgid "Zoom with two fingers" msgstr "用兩根手指縮放" #: lib/logitech_receiver/settings_templates.py:1342 msgid "Pixel zone" msgstr "åƒ�ç´ å�€åŸŸ" #: lib/logitech_receiver/settings_templates.py:1343 msgid "Ratio zone" msgstr "比例å�€åŸŸ" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Scale factor" msgstr "縮放係數" #: lib/logitech_receiver/settings_templates.py:1344 msgid "Sets the cursor speed." msgstr "設定游標速度。" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left" msgstr "å·¦" #: lib/logitech_receiver/settings_templates.py:1348 msgid "Left-most coordinate." msgstr "最左邊的座標。" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom" msgstr "底部" #: lib/logitech_receiver/settings_templates.py:1349 msgid "Bottom coordinate." msgstr "底部座標。" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width" msgstr "寬度" #: lib/logitech_receiver/settings_templates.py:1350 msgid "Width." msgstr "寬度。" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height" msgstr "高度" #: lib/logitech_receiver/settings_templates.py:1351 msgid "Height." msgstr "高度。" #: lib/logitech_receiver/settings_templates.py:1352 msgid "Cursor speed." msgstr "游標速度。" #: lib/logitech_receiver/settings_templates.py:1352 msgid "Scale" msgstr "縮放" #: lib/logitech_receiver/settings_templates.py:1358 msgid "Gestures" msgstr "手勢" #: lib/logitech_receiver/settings_templates.py:1359 msgid "Tweak the mouse/touchpad behaviour." msgstr "調整滑鼠/觸控æ�¿è¡Œç‚ºã€‚" #: lib/logitech_receiver/settings_templates.py:1375 msgid "Gestures Diversion" msgstr "手勢轉æ�›" #: lib/logitech_receiver/settings_templates.py:1376 msgid "Divert mouse/touchpad gestures." msgstr "轉æ�›æ»‘é¼ /觸控æ�¿æ‰‹å‹¢ã€‚" #: lib/logitech_receiver/settings_templates.py:1392 msgid "Gesture params" msgstr "手勢å�ƒæ•¸" #: lib/logitech_receiver/settings_templates.py:1393 msgid "Change numerical parameters of a mouse/touchpad." msgstr "變更滑鼠/觸控æ�¿çš„æ•¸å€¼å�ƒæ•¸ã€‚" #: lib/logitech_receiver/settings_templates.py:1417 msgid "M-Key LEDs" msgstr "M é�µ LED" #: lib/logitech_receiver/settings_templates.py:1419 msgid "Control the M-Key LEDs." msgstr "控制 M é�µ LED。" #: lib/logitech_receiver/settings_templates.py:1423 #: lib/logitech_receiver/settings_templates.py:1454 msgid "May need G Keys diverted to be effective." msgstr "å�¯èƒ½éœ€è¦�轉å�‘ G é�µæ‰�能生效。" #: lib/logitech_receiver/settings_templates.py:1429 #, python-format msgid "Lights up the %s key." msgstr "點亮 %s é�µã€‚" #: lib/logitech_receiver/settings_templates.py:1448 msgid "MR-Key LED" msgstr "MR é�µ LED" #: lib/logitech_receiver/settings_templates.py:1450 msgid "Control the MR-Key LED." msgstr "控制 MR é�µ LED。" #: lib/logitech_receiver/settings_templates.py:1471 msgid "Persistent Key/Button Mapping" msgstr "æŒ�久按é�µ/按鈕å°�應" #: lib/logitech_receiver/settings_templates.py:1473 msgid "Permanently change the mapping for the key or button." msgstr "永久變更按é�µæˆ–按鈕的å°�應。" #: lib/logitech_receiver/settings_templates.py:1475 msgid "" "Changing important keys or buttons (such as for the left mouse button) can " "result in an unusable system." msgstr "變更é‡�è¦�的按é�µæˆ–按鈕(例如滑鼠左é�µï¼‰å�¯èƒ½æœƒå°Žè‡´ç³»çµ±ç„¡æ³•使用。" #: lib/logitech_receiver/settings_templates.py:1532 msgid "Sidetone" msgstr "å�´éŸ³" #: lib/logitech_receiver/settings_templates.py:1533 msgid "Set sidetone level." msgstr "設定å�´éŸ³ç­‰ç´šã€‚" #: lib/logitech_receiver/settings_templates.py:1542 msgid "Equalizer" msgstr "å�‡è¡¡å™¨" #: lib/logitech_receiver/settings_templates.py:1543 msgid "Set equalizer levels." msgstr "設定等化器等級。" #: lib/logitech_receiver/settings_templates.py:1565 msgid "Hz" msgstr "Hz" #: lib/logitech_receiver/settings_templates.py:1571 msgid "Power Management" msgstr "é›»æº�管ç�†" #: lib/logitech_receiver/settings_templates.py:1572 msgid "Power off in minutes (0 for never)." msgstr "幾分é�˜å¾Œé—œæ©Ÿï¼ˆ0 表示永ä¸�關機)。" #: lib/logitech_receiver/settings_templates.py:1584 msgid "Brightness Control" msgstr "亮度控制" #: lib/logitech_receiver/settings_templates.py:1585 msgid "Control overall brightness" msgstr "控制整體亮度" #: lib/logitech_receiver/settings_templates.py:1628 #: lib/logitech_receiver/settings_templates.py:1681 msgid "LED Control" msgstr "LED 控制" #: lib/logitech_receiver/settings_templates.py:1629 #: lib/logitech_receiver/settings_templates.py:1682 msgid "Switch control of LED zones between device and Solaar" msgstr "在è£�置與 Solaar 之間切æ�› LED å�€åŸŸæŽ§åˆ¶" #: lib/logitech_receiver/settings_templates.py:1644 #: lib/logitech_receiver/settings_templates.py:1692 msgid "LED Zone Effects" msgstr "LED å�€åŸŸæ•ˆæžœ" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "LED Control needs to be set to Solaar to be effective." msgstr "需è¦�å°‡ LED 控制設為 Solaar æ‰�能生效。" #: lib/logitech_receiver/settings_templates.py:1645 #: lib/logitech_receiver/settings_templates.py:1693 msgid "Set effect for LED Zone" msgstr "設定 LED å�€åŸŸçš„æ•ˆæžœ" #: lib/logitech_receiver/settings_templates.py:1647 msgid "Color" msgstr "é¡�色" #: lib/logitech_receiver/settings_templates.py:1648 msgid "Speed" msgstr "速度" #: lib/logitech_receiver/settings_templates.py:1649 msgid "Period" msgstr "週期" #: lib/logitech_receiver/settings_templates.py:1650 msgid "Intensity" msgstr "強度" #: lib/logitech_receiver/settings_templates.py:1651 msgid "Ramp" msgstr "漸變" #: lib/logitech_receiver/settings_templates.py:1666 msgid "LEDs" msgstr "LED 燈" #: lib/logitech_receiver/settings_templates.py:1703 msgid "Per-key Lighting" msgstr "å–®é�µç…§æ˜Ž" #: lib/logitech_receiver/settings_templates.py:1704 msgid "Control per-key lighting." msgstr "控制單é�µç…§æ˜Žã€‚" #: lib/logitech_receiver/settings_templates.py:1786 msgid "Force Sensing Buttons" msgstr "力é�“感測按鈕" #: lib/logitech_receiver/settings_templates.py:1787 msgid "Change the force required to activate button." msgstr "調整觸發按鈕所需的力é�“。" #: lib/logitech_receiver/settings_templates.py:1804 msgid "Force Sensing Button" msgstr "力é�“感測按鈕" #: lib/logitech_receiver/settings_templates.py:1814 msgid "Haptic Feeback Level" msgstr "觸覺回饋等級" #: lib/logitech_receiver/settings_templates.py:1815 msgid "Change power of haptic feedback. (Zero to turn off.)" msgstr "變更觸覺回饋的力度,設為 0 å�¯é—œé–‰ã€‚" #: lib/logitech_receiver/settings_templates.py:1857 msgid "Play Haptic Waveform" msgstr "播放觸覺波形" #: lib/logitech_receiver/settings_templates.py:1858 msgid "Tell device to play a haptic waveform." msgstr "指示è£�置播放觸覺波形。" #: lib/solaar/ui/__init__.py:120 msgid "Another Solaar process is already running so just expose its window" msgstr "已有å�¦ä¸€å€‹ Solaar 處ç�†ç¨‹åº�正在執行,因此將會顯示其視窗" #: lib/solaar/ui/about/model.py:36 msgid "" "Manages Logitech receivers,\n" "keyboards, mice, and tablets." msgstr "" "管ç�†ç¾…技接收器ã€�\n" "é�µç›¤ã€�滑鼠和平æ�¿é›»è…¦ã€‚" #: lib/solaar/ui/about/model.py:63 msgid "Additional Programming" msgstr "é¡�外程å¼�設計" #: lib/solaar/ui/about/model.py:64 msgid "GUI design" msgstr "圖形介é�¢è¨­è¨ˆ" #: lib/solaar/ui/about/model.py:66 msgid "Testing" msgstr "測試" #: lib/solaar/ui/about/model.py:74 msgid "Logitech documentation" msgstr "羅技說明文件" #: lib/solaar/ui/action.py:88 lib/solaar/ui/action.py:92 #: lib/solaar/ui/window.py:208 msgid "Unpair" msgstr "å�–消é…�å°�" #: lib/solaar/ui/action.py:91 lib/solaar/ui/diversion_rules.py:141 msgid "Cancel" msgstr "å�–消" #: lib/solaar/ui/common.py:42 msgid "Permissions error" msgstr "權é™�錯誤" #: lib/solaar/ui/common.py:44 #, python-format msgid "" "Found a Logitech receiver or device (%s), but did not have permission to " "open it." msgstr "找到羅技接收器或è£�ç½® (%s),但沒有權é™�開啟。" #: lib/solaar/ui/common.py:46 msgid "" "If you've just installed Solaar, try disconnecting the receiver or device " "and then reconnecting it." msgstr "若剛安è£� Solaar,請嘗試中斷接收器或è£�置的連線,然後é‡�新連接。" #: lib/solaar/ui/common.py:49 msgid "Cannot connect to device error" msgstr "無法連接到è£�置錯誤" #: lib/solaar/ui/common.py:51 #, python-format msgid "" "Found a Logitech receiver or device at %s, but encountered an error " "connecting to it." msgstr "在 %s 找到羅技接收器或è£�置,但連接時發生錯誤。" #: lib/solaar/ui/common.py:53 msgid "" "Try disconnecting the device and then reconnecting it or turning it off and " "then on." msgstr "請嘗試中斷è£�置連線然後é‡�新連接,或將其關閉後å†�開啟。" #: lib/solaar/ui/common.py:56 msgid "Unpairing failed" msgstr "å�–消é…�å°�失敗" #: lib/solaar/ui/common.py:58 #, python-brace-format msgid "Failed to unpair %{device} from %{receiver}." msgstr "無法å�–消 %{device} 與 %{receiver} çš„é…�å°�。" #: lib/solaar/ui/common.py:63 msgid "The receiver returned an error, with no further details." msgstr "接收器傳回錯誤,未æ��供進一步詳細資訊。" #: lib/solaar/ui/config_panel.py:245 msgid "Complete - ENTER to change" msgstr "完æˆ� - 按 ENTER é�µè®Šæ›´" #: lib/solaar/ui/config_panel.py:245 msgid "Incomplete" msgstr "未完æˆ�" #: lib/solaar/ui/config_panel.py:491 lib/solaar/ui/config_panel.py:543 #, python-format msgid "%d value" msgid_plural "%d values" msgstr[0] "%d 個值" #: lib/solaar/ui/config_panel.py:642 msgid "Changes allowed" msgstr "å…�許變更" #: lib/solaar/ui/config_panel.py:643 msgid "No changes allowed" msgstr "ä¸�å…�許變更" #: lib/solaar/ui/config_panel.py:644 msgid "Ignore this setting" msgstr "忽略此設定" #: lib/solaar/ui/config_panel.py:690 msgid "Working" msgstr "工作中" #: lib/solaar/ui/config_panel.py:693 msgid "Read/write operation failed." msgstr "讀å�–/寫入æ“�作失敗。" #: lib/solaar/ui/desktop_notifications.py:112 msgid "unspecified reason" msgstr "未指定原因" #: lib/solaar/ui/diversion_rules.py:103 msgid "Built-in rules" msgstr "內建è¦�則" #: lib/solaar/ui/diversion_rules.py:103 msgid "User-defined rules" msgstr "使用者定義è¦�則" #: lib/solaar/ui/diversion_rules.py:105 lib/solaar/ui/diversion_rules.py:1126 msgid "Rule" msgstr "è¦�則" #: lib/solaar/ui/diversion_rules.py:106 lib/solaar/ui/diversion_rules.py:382 #: lib/solaar/ui/diversion_rules.py:509 msgid "Sub-rule" msgstr "å­�è¦�則" #: lib/solaar/ui/diversion_rules.py:108 msgid "[empty]" msgstr "[空白]" #: lib/solaar/ui/diversion_rules.py:132 msgid "Make changes permanent?" msgstr "è¦�永久套用變更嗎?" #: lib/solaar/ui/diversion_rules.py:137 msgid "Yes" msgstr "是" #: lib/solaar/ui/diversion_rules.py:139 msgid "No" msgstr "å�¦" #: lib/solaar/ui/diversion_rules.py:144 msgid "If you choose No, changes will be lost when Solaar is closed." msgstr "è‹¥é�¸æ“‡å�¦ï¼Œé—œé–‰ Solaar 時將會é�ºå¤±è®Šæ›´ã€‚" #: lib/solaar/ui/diversion_rules.py:273 msgid "Paste here" msgstr "在此貼上" #: lib/solaar/ui/diversion_rules.py:275 msgid "Paste above" msgstr "在上方貼上" #: lib/solaar/ui/diversion_rules.py:277 msgid "Paste below" msgstr "在下方貼上" #: lib/solaar/ui/diversion_rules.py:283 msgid "Paste rule here" msgstr "在此貼上è¦�則" #: lib/solaar/ui/diversion_rules.py:285 msgid "Paste rule above" msgstr "在上方貼上è¦�則" #: lib/solaar/ui/diversion_rules.py:287 msgid "Paste rule below" msgstr "在下方貼上è¦�則" #: lib/solaar/ui/diversion_rules.py:291 msgid "Paste rule" msgstr "貼上è¦�則" #: lib/solaar/ui/diversion_rules.py:306 msgid "Insert here" msgstr "在此æ�’å…¥" #: lib/solaar/ui/diversion_rules.py:308 msgid "Insert above" msgstr "在上方æ�’å…¥" #: lib/solaar/ui/diversion_rules.py:310 msgid "Insert below" msgstr "在下方æ�’å…¥" #: lib/solaar/ui/diversion_rules.py:316 msgid "Insert new rule here" msgstr "在此æ�’入新è¦�則" #: lib/solaar/ui/diversion_rules.py:318 msgid "Insert new rule above" msgstr "在上方æ�’入新è¦�則" #: lib/solaar/ui/diversion_rules.py:320 msgid "Insert new rule below" msgstr "在下方æ�’入新è¦�則" #: lib/solaar/ui/diversion_rules.py:347 msgid "Flatten" msgstr "å¹³é�¢åŒ–" #: lib/solaar/ui/diversion_rules.py:380 msgid "Insert" msgstr "æ�’å…¥" #: lib/solaar/ui/diversion_rules.py:383 lib/solaar/ui/diversion_rules.py:511 #: lib/solaar/ui/diversion_rules.py:1158 msgid "Or" msgstr "或" #: lib/solaar/ui/diversion_rules.py:384 lib/solaar/ui/diversion_rules.py:510 #: lib/solaar/ui/diversion_rules.py:1144 msgid "And" msgstr "且" #: lib/solaar/ui/diversion_rules.py:386 msgid "Condition" msgstr "æ¢�ä»¶" #: lib/solaar/ui/diversion_rules.py:388 lib/solaar/ui/rule_conditions.py:154 msgid "Feature" msgstr "功能" #: lib/solaar/ui/diversion_rules.py:389 lib/solaar/ui/rule_conditions.py:188 msgid "Report" msgstr "回報" #: lib/solaar/ui/diversion_rules.py:390 lib/solaar/ui/rule_conditions.py:69 msgid "Process" msgstr "處ç�†ç¨‹åº�" #: lib/solaar/ui/diversion_rules.py:391 msgid "Mouse process" msgstr "滑鼠處ç�†ç¨‹åº�" #: lib/solaar/ui/diversion_rules.py:392 lib/solaar/ui/rule_conditions.py:225 msgid "Modifiers" msgstr "修飾é�µ" #: lib/solaar/ui/diversion_rules.py:393 lib/solaar/ui/rule_conditions.py:277 msgid "Key" msgstr "按é�µ" #: lib/solaar/ui/diversion_rules.py:394 lib/solaar/ui/rule_conditions.py:318 msgid "KeyIsDown" msgstr "按é�µè™•於按下狀態" #: lib/solaar/ui/diversion_rules.py:395 lib/solaar/ui/diversion_rules.py:1432 msgid "Active" msgstr "使用中" #: lib/solaar/ui/diversion_rules.py:396 lib/solaar/ui/diversion_rules.py:1390 #: lib/solaar/ui/diversion_rules.py:1441 lib/solaar/ui/diversion_rules.py:1487 msgid "Device" msgstr "è£�ç½®" #: lib/solaar/ui/diversion_rules.py:397 lib/solaar/ui/diversion_rules.py:1467 msgid "Host" msgstr "主機" #: lib/solaar/ui/diversion_rules.py:398 lib/solaar/ui/diversion_rules.py:1506 msgid "Setting" msgstr "設定" #: lib/solaar/ui/diversion_rules.py:399 lib/solaar/ui/rule_conditions.py:333 #: lib/solaar/ui/rule_conditions.py:382 msgid "Test" msgstr "測試" #: lib/solaar/ui/diversion_rules.py:400 lib/solaar/ui/rule_conditions.py:507 msgid "Test bytes" msgstr "測試ä½�元組" #: lib/solaar/ui/diversion_rules.py:401 lib/solaar/ui/rule_conditions.py:608 msgid "Mouse Gesture" msgstr "滑鼠手勢" #: lib/solaar/ui/diversion_rules.py:405 msgid "Action" msgstr "動作" #: lib/solaar/ui/diversion_rules.py:407 lib/solaar/ui/rule_actions.py:138 msgid "Key press" msgstr "按é�µæŒ‰ä¸‹" #: lib/solaar/ui/diversion_rules.py:408 lib/solaar/ui/rule_actions.py:191 msgid "Mouse scroll" msgstr "滑鼠æ�²å‹•" #: lib/solaar/ui/diversion_rules.py:409 lib/solaar/ui/rule_actions.py:256 msgid "Mouse click" msgstr "滑鼠點é�¸" #: lib/solaar/ui/diversion_rules.py:410 msgid "Set" msgstr "設定" #: lib/solaar/ui/diversion_rules.py:411 lib/solaar/ui/rule_actions.py:328 msgid "Execute" msgstr "執行" #: lib/solaar/ui/diversion_rules.py:412 lib/solaar/ui/diversion_rules.py:1189 msgid "Later" msgstr "ç¨�後" #: lib/solaar/ui/diversion_rules.py:441 msgid "Insert new rule" msgstr "æ�’入新è¦�則" #: lib/solaar/ui/diversion_rules.py:461 lib/solaar/ui/rule_actions.py:82 #: lib/solaar/ui/rule_actions.py:287 lib/solaar/ui/rule_conditions.py:556 msgid "Delete" msgstr "刪除" #: lib/solaar/ui/diversion_rules.py:483 msgid "Negate" msgstr "å�¦å®š" #: lib/solaar/ui/diversion_rules.py:507 msgid "Wrap with" msgstr "包è£�為" #: lib/solaar/ui/diversion_rules.py:537 msgid "Cut" msgstr "剪下" #: lib/solaar/ui/diversion_rules.py:553 msgid "Paste" msgstr "貼上" #: lib/solaar/ui/diversion_rules.py:559 msgid "Copy" msgstr "複製" #: lib/solaar/ui/diversion_rules.py:568 msgid "Solaar Rule Editor" msgstr "Solaar è¦�則編輯器" #: lib/solaar/ui/diversion_rules.py:668 msgid "Save changes" msgstr "儲存變更" #: lib/solaar/ui/diversion_rules.py:673 msgid "Discard changes" msgstr "æ�¨æ£„變更" #: lib/solaar/ui/diversion_rules.py:1104 msgid "This editor does not support the selected rule component yet." msgstr "此編輯器尚未支æ�´æ‰€é�¸çš„è¦�則元件。" #: lib/solaar/ui/diversion_rules.py:1169 msgid "" "Number of seconds to delay. Delay between 0 and 1 is done with higher " "precision." msgstr "å»¶é�²çš„秒數。0 到 1 秒之間的延é�²æœƒä»¥è¼ƒé«˜çš„精確度執行。" #: lib/solaar/ui/diversion_rules.py:1207 msgid "Not" msgstr "é�ž" #: lib/solaar/ui/diversion_rules.py:1238 msgid "Toggle" msgstr "切æ�›" #: lib/solaar/ui/diversion_rules.py:1239 msgid "True" msgstr "真" #: lib/solaar/ui/diversion_rules.py:1240 msgid "False" msgstr "å�‡" #: lib/solaar/ui/diversion_rules.py:1253 msgid "Unsupported setting" msgstr "ä¸�支æ�´çš„設定" #: lib/solaar/ui/diversion_rules.py:1396 lib/solaar/ui/diversion_rules.py:1415 #: lib/solaar/ui/diversion_rules.py:1493 lib/solaar/ui/diversion_rules.py:1748 #: lib/solaar/ui/diversion_rules.py:1766 msgid "Originating device" msgstr "來æº�è£�ç½®" #: lib/solaar/ui/diversion_rules.py:1428 msgid "Device is active and its settings can be changed." msgstr "è£�置處於使用中狀態,å�¯ä»¥è®Šæ›´å…¶è¨­å®šã€‚" #: lib/solaar/ui/diversion_rules.py:1437 msgid "Device that originated the current notification." msgstr "產生目å‰�通知的è£�置。" #: lib/solaar/ui/diversion_rules.py:1450 msgid "Name of host computer." msgstr "主機電腦å��稱。" #: lib/solaar/ui/diversion_rules.py:1520 msgid "Value" msgstr "值" #: lib/solaar/ui/diversion_rules.py:1529 msgid "Item" msgstr "é …ç›®" #: lib/solaar/ui/diversion_rules.py:1808 msgid "Change setting on device" msgstr "變更è£�置上的設定" #: lib/solaar/ui/diversion_rules.py:1824 msgid "Setting on device" msgstr "è£�置上的設定" #: lib/solaar/ui/pair_window.py:44 lib/solaar/ui/pair_window.py:167 #, python-format msgid "%(receiver_name)s: pair new device" msgstr "%(receiver_name)s:é…�å°�æ–°çš„è£�ç½®" #: lib/solaar/ui/pair_window.py:46 msgid "Bolt receivers are only compatible with Bolt devices." msgstr "Bolt 接收器僅相容於 Bolt è£�置。" #: lib/solaar/ui/pair_window.py:48 msgid "Press a pairing button or key until the pairing light flashes quickly." msgstr "請按ä½�é…�å°�按鈕或按é�µï¼Œç›´åˆ°é…�å°�指示燈快速閃çˆ�。" #: lib/solaar/ui/pair_window.py:51 msgid "Unifying receivers are only compatible with Unifying devices." msgstr "Unifying 接收器僅相容於 Unifying è£�置。" #: lib/solaar/ui/pair_window.py:53 msgid "Other receivers are only compatible with a few devices." msgstr "其他接收器僅支æ�´å°‘數è£�置。" #: lib/solaar/ui/pair_window.py:55 msgid "For most devices, turn on the device you want to pair." msgstr "多數è£�ç½®å�ªè¦�開啟想è¦�é…�å°�çš„è£�ç½®å�³å�¯ã€‚" #: lib/solaar/ui/pair_window.py:56 msgid "If the device is already turned on, turn it off and on again." msgstr "è‹¥è£�置已開啟,請將其關閉後å†�é‡�新開啟。" #: lib/solaar/ui/pair_window.py:58 msgid "The device must not be paired with a nearby powered-on receiver." msgstr "è£�ç½®ä¸�得與附近已開啟的接收器é…�å°�。" #: lib/solaar/ui/pair_window.py:61 msgid "" "For devices with multiple channels, press, hold, and release the button for " "the channel you wish to pair\n" "or use the channel switch button to select a channel and then press, hold, " "and release the channel switch button." msgstr "" "å°�於有多個通é�“çš„è£�置,請按ä½�並放開想è¦�é…�å°�通é�“的按鈕,\n" "或使用通é�“切æ�›æŒ‰éˆ•é�¸æ“‡é€šé�“後,å†�按ä½�並放開通é�“切æ�›æŒ‰éˆ•。" #: lib/solaar/ui/pair_window.py:68 msgid "The channel indicator light should be blinking rapidly." msgstr "通é�“指示燈應會快速閃çˆ�。" #: lib/solaar/ui/pair_window.py:72 #, python-format msgid "" "\n" "\n" "This receiver has %d pairing remaining." msgid_plural "" "\n" "\n" "This receiver has %d pairings remaining." msgstr[0] "" "\n" "\n" "此接收器剩餘 %d 次é…�å°�。" #: lib/solaar/ui/pair_window.py:78 msgid "" "\n" "Cancelling at this point will not use up a pairing." msgstr "" "\n" "在此階段å�–消ä¸�會消耗é…�å°�次數。" #: lib/solaar/ui/pair_window.py:168 #, python-format msgid "Enter passcode on %(name)s." msgstr "請在 %(name)s 上輸入密碼。" #: lib/solaar/ui/pair_window.py:171 #, python-format msgid "Type %(passcode)s and then press the enter key." msgstr "請輸入 %(passcode)s,然後按 Enter é�µã€‚" #: lib/solaar/ui/pair_window.py:176 msgid "left" msgstr "å·¦" #: lib/solaar/ui/pair_window.py:176 msgid "right" msgstr "å�³" #: lib/solaar/ui/pair_window.py:178 #, python-format msgid "" "Press %(code)s\n" "and then press left and right buttons simultaneously." msgstr "" "請按下 %(code)s\n" "然後å�Œæ™‚按下左é�µå’Œå�³é�µã€‚" #: lib/solaar/ui/pair_window.py:221 msgid "The wireless link is not encrypted" msgstr "無線連線未加密" #: lib/solaar/ui/pair_window.py:226 msgid "Found a new device:" msgstr "發ç�¾ä¸€å€‹æ–°è£�置:" #: lib/solaar/ui/pair_window.py:247 msgid "Pairing failed" msgstr "é…�å°�失敗" #: lib/solaar/ui/pair_window.py:249 msgid "Make sure your device is within range, and has a decent battery charge." msgstr "請確èª�è£�置在範åœ�內,且電池電é‡�充足。" #: lib/solaar/ui/pair_window.py:251 msgid "A new device was detected, but it is not compatible with this receiver." msgstr "å�µæ¸¬åˆ°æ–°è£�置,但與此接收器ä¸�相容。" #: lib/solaar/ui/pair_window.py:253 msgid "More paired devices than receiver can support." msgstr "å·²é…�å°�çš„è£�置數é‡�è¶…é�ŽæŽ¥æ”¶å™¨å�¯æ”¯æ�´çš„æ•¸é‡�。" #: lib/solaar/ui/pair_window.py:255 msgid "No further details are available about the error." msgstr "沒有關於此錯誤的進一步詳細資訊。" #: lib/solaar/ui/rule_actions.py:54 msgid "" "Simulate a chorded key click or depress or release.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "模擬組å�ˆé�µé»žé�¸æˆ–按下或放開。\n" "在 Wayland 上需è¦�å°� /dev/uinput 的寫入權é™�。" #: lib/solaar/ui/rule_actions.py:60 msgid "Add key" msgstr "新增按é�µ" #: lib/solaar/ui/rule_actions.py:63 msgid "Click" msgstr "點é�¸" #: lib/solaar/ui/rule_actions.py:66 msgid "Depress" msgstr "按下" #: lib/solaar/ui/rule_actions.py:69 msgid "Release" msgstr "放開" #: lib/solaar/ui/rule_actions.py:153 msgid "" "Simulate a mouse scroll.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "模擬滑鼠æ�²å‹•。\n" "在 Wayland 上需è¦�å°� /dev/uinput 的寫入權é™�。" #: lib/solaar/ui/rule_actions.py:211 msgid "" "Simulate a mouse click.\n" "On Wayland requires write access to /dev/uinput." msgstr "" "模擬滑鼠點é�¸ã€‚\n" "在 Wayland 上需è¦�å°� /dev/uinput 的寫入權é™�。" #: lib/solaar/ui/rule_actions.py:216 msgid "Button" msgstr "按鈕" #: lib/solaar/ui/rule_actions.py:218 msgid "Action (and Count, if click)" msgstr "動作(若為點é�¸å‰‡å�«æ¬¡æ•¸ï¼‰" #: lib/solaar/ui/rule_actions.py:269 msgid "Execute a command with arguments." msgstr "執行帶有å�ƒæ•¸çš„命令。" #: lib/solaar/ui/rule_actions.py:273 msgid "Add argument" msgstr "新增å�ƒæ•¸" #: lib/solaar/ui/rule_conditions.py:52 msgid "X11 active process. For use in X11 only." msgstr "X11 使用中處ç�†ç¨‹åº�。僅é�©ç”¨æ–¼ X11。" #: lib/solaar/ui/rule_conditions.py:82 msgid "X11 mouse process. For use in X11 only." msgstr "X11 滑鼠處ç�†ç¨‹åº�。僅é�©ç”¨æ–¼ X11。" #: lib/solaar/ui/rule_conditions.py:99 msgid "MouseProcess" msgstr "滑鼠處ç�†ç¨‹åº�" #: lib/solaar/ui/rule_conditions.py:123 msgid "Feature name of notification triggering rule processing." msgstr "觸發è¦�則處ç�†çš„通知功能å��稱。" #: lib/solaar/ui/rule_conditions.py:169 msgid "Report number of notification triggering rule processing." msgstr "回報觸發è¦�則處ç�†çš„通知數é‡�。" #: lib/solaar/ui/rule_conditions.py:201 msgid "Active keyboard modifiers. Not always available in Wayland." msgstr "使用中的é�µç›¤ä¿®é£¾é�µã€‚在 Wayland 中並é�žç¸½æ˜¯å�¯ç”¨ã€‚" #: lib/solaar/ui/rule_conditions.py:241 msgid "" "Diverted key or button depressed or released.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "轉å�‘按é�µæˆ–按鈕被按下或放開。\n" "使用按é�µ/按鈕轉å�‘和轉å�‘ G é�µè¨­å®šä¾†è½‰å�‘按é�µå’ŒæŒ‰éˆ•。" #: lib/solaar/ui/rule_conditions.py:250 msgid "Key down" msgstr "按é�µæŒ‰ä¸‹" #: lib/solaar/ui/rule_conditions.py:253 msgid "Key up" msgstr "按é�µé¬†é–‹" #: lib/solaar/ui/rule_conditions.py:293 msgid "" "Diverted key or button is currently down.\n" "Use the Key/Button Diversion and Divert G Keys settings to divert keys and " "buttons." msgstr "" "轉å�‘按é�µæˆ–按鈕目å‰�處於按下狀態。\n" "使用按é�µ/按鈕轉å�‘和轉å�‘ G é�µè¨­å®šä¾†è½‰å�‘按é�µå’ŒæŒ‰éˆ•。" #: lib/solaar/ui/rule_conditions.py:331 msgid "Test condition on notification triggering rule processing." msgstr "在通知觸發è¦�則處ç�†ä¸Šæ¸¬è©¦æ¢�件。" #: lib/solaar/ui/rule_conditions.py:335 msgid "Parameter" msgstr "å�ƒæ•¸" #: lib/solaar/ui/rule_conditions.py:408 msgid "begin (inclusive)" msgstr "開始(包å�«ï¼‰" #: lib/solaar/ui/rule_conditions.py:409 msgid "end (exclusive)" msgstr "çµ�æ�Ÿï¼ˆä¸�包å�«ï¼‰" #: lib/solaar/ui/rule_conditions.py:417 msgid "range" msgstr "範åœ�" #: lib/solaar/ui/rule_conditions.py:420 msgid "minimum" msgstr "最å°�值" #: lib/solaar/ui/rule_conditions.py:421 msgid "maximum" msgstr "最大值" #: lib/solaar/ui/rule_conditions.py:423 #, python-format msgid "bytes %(0)d to %(1)d, ranging from %(2)d to %(3)d" msgstr "ä½�元組 %(0)d 到 %(1)d,範åœ�從 %(2)d 到 %(3)d" #: lib/solaar/ui/rule_conditions.py:426 lib/solaar/ui/rule_conditions.py:427 msgid "mask" msgstr "é�®ç½©" #: lib/solaar/ui/rule_conditions.py:428 #, python-format msgid "bytes %(0)d to %(1)d, mask %(2)d" msgstr "ä½�元組 %(0)d 到 %(1)d,é�®ç½© %(2)d" #: lib/solaar/ui/rule_conditions.py:437 msgid "" "Bit or range test on bytes in notification message triggering rule " "processing." msgstr "在通知訊æ�¯è§¸ç™¼è¦�則處ç�†ä¸­å°�ä½�元組進行ä½�元或範åœ�測試。" #: lib/solaar/ui/rule_conditions.py:447 msgid "type" msgstr "類型" #: lib/solaar/ui/rule_conditions.py:535 msgid "" "Mouse gesture with optional initiating button followed by zero or more mouse " "movements." msgstr "滑鼠手勢,å�¯é�¸æ“‡æ€§åœ°å¸¶æœ‰èµ·å§‹æŒ‰éˆ•,後接零個或多個滑鼠移動。" #: lib/solaar/ui/rule_conditions.py:541 msgid "Add movement" msgstr "新增移動" #: lib/solaar/ui/tray.py:55 msgid "No supported device found" msgstr "找ä¸�到支æ�´çš„è£�ç½®" #: lib/solaar/ui/tray.py:60 lib/solaar/ui/window.py:328 #, python-format msgid "About %s" msgstr "關於 %s" #: lib/solaar/ui/tray.py:61 lib/solaar/ui/window.py:326 #, python-format msgid "Quit %s" msgstr "çµ�æ�Ÿ %s" #: lib/solaar/ui/tray.py:273 lib/solaar/ui/tray.py:281 msgid "no receiver" msgstr "無接收器" #: lib/solaar/ui/tray.py:294 lib/solaar/ui/tray.py:299 #: lib/solaar/ui/window.py:728 msgid "offline" msgstr "離線" #: lib/solaar/ui/tray.py:297 msgid "no status" msgstr "無狀態" #: lib/solaar/ui/window.py:110 msgid "Scanning" msgstr "掃æ��中" #: lib/solaar/ui/window.py:141 msgid "Battery" msgstr "電池" #: lib/solaar/ui/window.py:144 msgid "Wireless Link" msgstr "無線連線" #: lib/solaar/ui/window.py:148 msgid "Lighting" msgstr "亮度" #: lib/solaar/ui/window.py:182 msgid "Show Technical Details" msgstr "顯示技術細節" #: lib/solaar/ui/window.py:198 msgid "Pair new device" msgstr "é…�å°�æ–°è£�ç½®" #: lib/solaar/ui/window.py:216 msgid "Select a device" msgstr "è«‹é�¸æ“‡è£�ç½®" #: lib/solaar/ui/window.py:331 msgid "Rule Editor" msgstr "è¦�則編輯器" #: lib/solaar/ui/window.py:522 msgid "Path" msgstr "路徑" #: lib/solaar/ui/window.py:524 msgid "USB ID" msgstr "USB ID" #: lib/solaar/ui/window.py:527 lib/solaar/ui/window.py:529 #: lib/solaar/ui/window.py:544 lib/solaar/ui/window.py:546 msgid "Serial" msgstr "åº�號" #: lib/solaar/ui/window.py:533 msgid "Index" msgstr "索引" #: lib/solaar/ui/window.py:535 msgid "Wireless PID" msgstr "ç„¡ç·š PID" #: lib/solaar/ui/window.py:537 msgid "Product ID" msgstr "產å“� ID" #: lib/solaar/ui/window.py:539 msgid "Protocol" msgstr "通訊å�”定" #: lib/solaar/ui/window.py:539 msgid "Unknown" msgstr "ä¸�明" #: lib/solaar/ui/window.py:541 msgid "Polling rate" msgstr "輪詢速率" #: lib/solaar/ui/window.py:548 msgid "Unit ID" msgstr "å–®ä½� ID" #: lib/solaar/ui/window.py:559 msgid "none" msgstr "ç„¡" #: lib/solaar/ui/window.py:560 msgid "Notifications" msgstr "通知" #: lib/solaar/ui/window.py:604 msgid "No device paired." msgstr "沒有已é…�å°�çš„è£�置。" #: lib/solaar/ui/window.py:613 #, python-format msgid "Up to %(max_count)s device can be paired to this receiver." msgid_plural "Up to %(max_count)s devices can be paired to this receiver." msgstr[0] "此接收器最多å�¯é…�å°� %(max_count)s 個è£�置。" #: lib/solaar/ui/window.py:620 msgid "Only one device can be paired to this receiver." msgstr "此接收器å�ªèƒ½é…�å°�一個è£�ç½®" #: lib/solaar/ui/window.py:624 #, python-format msgid "This receiver has %d pairing remaining." msgid_plural "This receiver has %d pairings remaining." msgstr[0] "此接收器剩餘 %d 次é…�å°�。" #: lib/solaar/ui/window.py:681 msgid "Battery Voltage" msgstr "電池電壓" #: lib/solaar/ui/window.py:683 msgid "Voltage reported by battery" msgstr "電池回報的電壓" #: lib/solaar/ui/window.py:685 msgid "Battery Level" msgstr "電池電é‡�" #: lib/solaar/ui/window.py:687 msgid "Approximate level reported by battery" msgstr "電池回報的大約電é‡�" #: lib/solaar/ui/window.py:694 lib/solaar/ui/window.py:696 msgid "next reported " msgstr "下一次回報的 " #: lib/solaar/ui/window.py:697 msgid " and next level to be reported." msgstr " 以å�Šä¸‹ä¸€å€‹å°‡å›žå ±çš„等級。" #: lib/solaar/ui/window.py:702 msgid "last known" msgstr "最後已知" #: lib/solaar/ui/window.py:713 msgid "encrypted" msgstr "已加密" #: lib/solaar/ui/window.py:715 msgid "The wireless link between this device and its receiver is encrypted." msgstr "æ­¤è£�置與其接收器之間的無線連線已加密。" #: lib/solaar/ui/window.py:717 msgid "not encrypted" msgstr "未加密" #: lib/solaar/ui/window.py:721 msgid "" "The wireless link between this device and its receiver is not encrypted.\n" "This is a security issue for pointing devices, and a major security issue " "for text-input devices." msgstr "" "æ­¤è£�置與其接收器之間的無線連線未加密。\n" "這å°�指å�‘åž‹è£�置僅是安全性å•�題,å°�文字輸入è£�置則是é‡�大的安全性å•�題。" #: lib/solaar/ui/window.py:737 #, python-format msgid "%(light_level)d lux" msgstr "%(light_level)d lux" Solaar-1.1.20/pyproject.toml000066400000000000000000000004131522022367600157330ustar00rootroot00000000000000[tool.ruff] line-length = 127 target-version = "py37" [tool.ruff.lint] select = [ "F", # Pyflakes "E", # pycodestyle "W", # pycodestyle "B", # flake8-bugbear "I", # isort ] [tool.ruff.lint.isort] force-single-line = true lines-between-types = 1 Solaar-1.1.20/release.sh000077500000000000000000000121111522022367600147740ustar00rootroot00000000000000#!/usr/bin/env bash repo=pwr-Solaar/Solaar usage() { basename="$(basename $0)" cat </dev/null [ $? -eq 0 ] && prerelease=true stable_branch=stable ref=$(git symbolic-ref HEAD) [ $? -ne 0 ] && echo 'Error: Failed current branch' && exit 1 branch=${ref##*/} commit=$(git rev-list --max-count=1 HEAD) [ $? -ne 0 ] && echo 'Error: Failed to get HEAD' && exit 1 remote=$(git config --get branch.$branch.remote) [ $? -ne 0 ] && echo 'Error: Failed to get remote' && exit 1 remote_ref=$(git config --get branch.$branch.merge) [ $? -ne 0 ] && echo 'Error: Failed to get remote HEAD' && exit 1 remote_branch=${remote_ref##*/} github_token=$(cat ~/.github-token) [ $? -ne 0 ] && echo 'Error: Failed to get github token (check ~/.github_token)' && exit 1 jq -V >/dev/null [ $? -ne 0 ] && echo 'Error: jq is not installed' && exit 1 echo -e "\n\t** You are tagging a release for version $version **\n" echo "Version: $version" echo "Commit: $commit" echo "Pre-release: $prerelease" echo "Remote: $remote" if [ "$branch" == "$remote_branch" ]; then echo "Branch: $branch" else echo "Local branch: $branch" echo "Remote branch: $remote_branch" fi echo -e '\nPlease read RELEASE.md before continuing.\n' read -p 'Are you sure you want to proceed? (y/n) ' -n 1 -r < /dev/tty echo [[ ! $REPLY =~ ^[Yy]$ ]] && echo 'Release aborted.' && exit 1 read -p 'Are you *really* sure you want to proceed? (y/n) ' -n 1 -r < /dev/tty echo [[ ! $REPLY =~ ^[Yy]$ ]] && echo 'Release aborted.' && exit 1 # Check if version is in the changelog grep '^# '"$version" CHANGELOG.md >/dev/null [ $? -ne 0 ] && echo 'Error: Version is not present in the changelog' && exit 1 # Check for uncommitted changes git diff --quiet HEAD >/dev/null [ $? -ne 0 ] && echo -e '\nError: Uncommitted changes found' && exit 1 # Check if commit is a version bump git show -s --format=%B HEAD | grep "^release $version">/dev/null #[ $? -ne 0 ] && echo -e '\nError: Commit does not look like a version bump' && exit 1 # Check if commit has been pushed to remote remote_commit=$(git rev-list --max-count=1 $remote/$branch) [ $? -ne 0 ] && echo -e '\nError: Failed to get remote HEAD' && exit 1 [ "$commit" != "$remote_commit" ] && echo -e '\nError: Commit has not been pushed to the remote' && exit 1 # Check if tag already exists git rev-list --max-count=1 $version >/dev/null 2>/dev/null [ $? -eq 0 ] && echo -e '\nError: Tag already exists' && exit 1 # Check if tag already exists on remote git ls-remote $remote | grep "refs/tags/$version$" >/dev/null [ $? -eq 0 ] && echo -e '\nError: Tag already exists on remote' && exit 1 echo # Create tag echo 'Creating tag...' { echo "release $version" echo found=no while read -r line; do if [[ "$line" == "# "* ]]; then [ "$line" == "# $version" ] && found=yes || found=no fi [ "$found" == 'yes' ] && [ "${line:0:1}" == '*' ] && echo "$line" done < CHANGELOG.md } > /tmp/solaar-changelog [ -z "$DRY_RUN" ] && git tag -s $version -F /tmp/solaar-changelog >/dev/null || true [ $? -ne 0 ] && echo -e '\nError: Failed to create tag' && exit 1 # Push tag echo 'Pushing tag...' [ -z "$DRY_RUN" ] && git push $remote $version >/dev/null || true [ $? -ne 0 ] && echo -e '\nError: Failed to push tag' && exit 1 # Point stable branch to latest version tag echo 'Updating stable branch...' if [[ -z "$DRY_RUN" && $prerelease == "false" ]] then # Check if stable branch does not exist git rev-list --max-count=1 $stable_branch >/dev/null 2>/dev/null [ $? -ne 0 ] && echo -e '\nWarning: Creating stable branch for a first time' && git branch $stable_branch # Fast forward and push stable branch git checkout $stable_branch git merge --ff $version git push $remote $stable_branch >/dev/null || true git checkout $branch fi # Create github release body() { cat </dev/null | jq -r .html_url) [ -z "$DRY_RUN" ] && url=$(curl -H 'Authorization: $github_token' -X POST --data "$(body)" "https://api.github.com/repos/$repo/releases" 2>/dev/null | jq -r .html_url) [ -z "$DRY_RUN" ] && [ -z "$url" ] && echo -e '\nError: Failed to create a github release' && exit 1 [ -z "$DRY_RUN" ] && echo -e "\nRelease created: $url" rm /tmp/solaar-changelog Solaar-1.1.20/rules.d-uinput/000077500000000000000000000000001522022367600157175ustar00rootroot00000000000000Solaar-1.1.20/rules.d-uinput/42-logitech-unify-permissions.rules000066400000000000000000000016541522022367600245230ustar00rootroot00000000000000# This rule was added by Solaar. # # Allows non-root users to have raw access to Logitech devices. # Allowing users to write to the device is potentially dangerous # because they could perform firmware updates. KERNEL=="uinput", SUBSYSTEM=="misc", TAG+="uaccess", OPTIONS+="static_node=uinput" ACTION == "remove", GOTO="solaar_end" SUBSYSTEM != "hidraw", GOTO="solaar_end" # USB-connected Logitech receivers and devices ATTRS{idVendor}=="046d", GOTO="solaar_apply" # Lenovo nano receiver ATTRS{idVendor}=="17ef", ATTRS{idProduct}=="6042", GOTO="solaar_apply" # Bluetooth-connected Logitech devices KERNELS == "0005:046D:*", GOTO="solaar_apply" GOTO="solaar_end" LABEL="solaar_apply" # Allow any seated user to access the receiver. # uaccess: modern ACL-enabled udev TAG+="uaccess" # Grant members of the "plugdev" group access to receiver (useful for SSH users) #MODE="0660", GROUP="plugdev" LABEL="solaar_end" # vim: ft=udevrules Solaar-1.1.20/rules.d/000077500000000000000000000000001522022367600143755ustar00rootroot00000000000000Solaar-1.1.20/rules.d/42-logitech-unify-permissions.rules000066400000000000000000000016541522022367600232010ustar00rootroot00000000000000# This rule was added by Solaar. # # Allows non-root users to have raw access to Logitech devices. # Allowing users to write to the device is potentially dangerous # because they could perform firmware updates. KERNEL=="uinput", SUBSYSTEM=="misc", TAG+="uaccess", OPTIONS+="static_node=uinput" ACTION == "remove", GOTO="solaar_end" SUBSYSTEM != "hidraw", GOTO="solaar_end" # USB-connected Logitech receivers and devices ATTRS{idVendor}=="046d", GOTO="solaar_apply" # Lenovo nano receiver ATTRS{idVendor}=="17ef", ATTRS{idProduct}=="6042", GOTO="solaar_apply" # Bluetooth-connected Logitech devices KERNELS == "0005:046D:*", GOTO="solaar_apply" GOTO="solaar_end" LABEL="solaar_apply" # Allow any seated user to access the receiver. # uaccess: modern ACL-enabled udev TAG+="uaccess" # Grant members of the "plugdev" group access to receiver (useful for SSH users) #MODE="0660", GROUP="plugdev" LABEL="solaar_end" # vim: ft=udevrules Solaar-1.1.20/setup.py000077500000000000000000000066151522022367600145460ustar00rootroot00000000000000import subprocess import textwrap from glob import glob from os.path import dirname from pathlib import Path from setuptools import find_packages from setuptools import setup NAME = "Solaar" version = Path("lib/solaar/version").read_text().strip() try: # get commit from git describe commit = subprocess.check_output(["git", "describe", "--always"], stderr=subprocess.DEVNULL).strip().decode() Path("lib/solaar/commit").write_text(f"{commit}\n") except Exception: # get commit from Ubuntu dpkg-parsechangelog try: commit = ( subprocess.check_output(["dpkg-parsechangelog", "--show-field", "Version"], stderr=subprocess.DEVNULL) .strip() .decode() ) commit = commit.split("~") Path("lib/solaar/commit").write_text(f"{commit[0]}\n") except Exception as e: print("Exception using dpkg-parsechangelog", e) def _data_files(): yield "share/icons/hicolor/scalable/apps", glob("share/solaar/icons/solaar*.svg") yield "share/icons/hicolor/32x32/apps", glob("share/solaar/icons/solaar-light_*.png") for mo in glob("share/locale/*/LC_MESSAGES/solaar.mo"): yield dirname(mo), [mo] yield "share/applications", ["share/applications/solaar.desktop"] yield "lib/udev/rules.d", ["rules.d/42-logitech-unify-permissions.rules"] yield "share/metainfo", ["share/solaar/io.github.pwr_solaar.solaar.metainfo.xml"] setup( name=NAME.lower(), version=version, description="Linux device manager for Logitech receivers, keyboards, mice, and tablets.", long_description=textwrap.dedent( """ Solaar is a Linux device manager for many Logitech peripherals that connect through Unifying and other receivers or via USB or Bluetooth. Solaar is able to pair/unpair devices with receivers and show and modify some of the modifiable features of devices. For instructions on installing Solaar see https://pwr-solaar.github.io/Solaar/installation""" ), author="Daniel Pavel", license="GPLv2", url="http://pwr-solaar.github.io/Solaar/", classifiers=[ "Development Status :: 4 - Beta", "Environment :: X11 Applications :: GTK", "Environment :: Console", "Intended Audience :: End Users/Desktop", "License :: DFSG approved", "License :: OSI Approved :: GNU General Public License v2 (GPLv2)", "Natural Language :: English", "Programming Language :: Python :: 3 :: Only", "Operating System :: POSIX :: Linux", "Topic :: Utilities", ], platforms=["linux"], python_requires=">=3.8", install_requires=[ 'evdev (>= 1.1.2) ; platform_system=="Linux"', "pyudev (>= 0.13)", "PyYAML (>= 3.12)", "python-xlib (>= 0.27)", "psutil (>= 5.4.3)", 'dbus-python ; platform_system=="Linux"', "PyGObject", "pycairo", "typing_extensions", ], extras_require={ "report-descriptor": ["hid-parser"], "desktop-notifications": ["Notify (>= 0.7)"], "git-commit": ["python-git-info"], "test": ["pytest", "pytest-mock", "pytest-cov"], "dev": ["ruff"], }, package_dir={"": "lib"}, packages=find_packages(where="lib"), data_files=list(_data_files()), include_package_data=True, entry_points={ "console_scripts": [ "solaar = solaar.gtk:main", ], }, ) Solaar-1.1.20/share/000077500000000000000000000000001522022367600141235ustar00rootroot00000000000000Solaar-1.1.20/share/README000066400000000000000000000002231522022367600150000ustar00rootroot00000000000000Solaar application icon drawn by me, roughly guided by Logitech's Unifying logo. All other images are from the GNOME and Oxygen free icon themes. Solaar-1.1.20/share/applications/000077500000000000000000000000001522022367600166115ustar00rootroot00000000000000Solaar-1.1.20/share/applications/solaar.desktop000066400000000000000000000017251522022367600214720ustar00rootroot00000000000000[Desktop Entry] Name=Solaar Comment=Logitech Unifying Receiver peripherals manager Comment[fr]=Gestionnaire de périphériques pour les récepteurs Logitech Unifying Comment[hr]=Upravitelj Logitechovih ureÄ‘aja povezanih putem Unifying i Nano prijemnika Comment[ru]=Управление приёмником Logitech Unifying Receiver Comment[de]=Logitech Unifying Empfänger Geräteverwaltung Comment[es]=Administrador de periféricos de Logitech Receptor Unifying Comment[pl]=Menedżer urzÄ…dzeÅ„ peryferyjnych odbiornika Logitech Unifying Comment[sv]=Kringutrustningshanterare för Logitech Unifying-mottagare Comment[zh_CN]=罗技优è�”设备管ç�†å™¨ Comment[zh_TW]=羅技Unifying è£�置管ç�†å™¨ Comment[zh_HK]=羅技Unifying è£�置管ç�†å™¨ Exec=solaar Icon=solaar StartupNotify=true Terminal=false Type=Application Keywords=logitech;unifying;receiver;mouse;keyboard; Categories=Utility;GTK; #Categories=Utility;GTK;Settings;HardwareSettings; X-GNOME-UsesNotifications=true Solaar-1.1.20/share/autostart/000077500000000000000000000000001522022367600161515ustar00rootroot00000000000000Solaar-1.1.20/share/autostart/solaar.desktop000066400000000000000000000017041522022367600210270ustar00rootroot00000000000000[Desktop Entry] Name=Solaar Comment=Logitech Unifying Receiver peripherals manager Comment[fr]=Gestionnaire de périphériques pour les récepteurs Logitech Unifying Comment[hr]=Upravitelj Logitechovih ureÄ‘aja povezanih putem Unifying i Nano prijemnika Comment[ru]=Управление приёмником Logitech Unifying Receiver Comment[de]=Logitech Unifying Empfänger Geräteverwaltung Comment[es]=Administrador de periféricos de Logitech Receptor Unifying Comment[pl]=Menedżer urzÄ…dzeÅ„ peryferyjnych odbiornika Logitech Unifying Comment[sv]=Kringutrustningshanterare för Logitech Unifying-mottagare Comment[zh_CN]=罗技优è�”设备管ç�†å™¨ Comment[zh_TW]=羅技Unifying è£�置管ç�†å™¨ Comment[zh_HK]=羅技Unifying è£�置管ç�†å™¨ Exec=solaar --window=hide Icon=solaar StartupNotify=true Terminal=false Type=Application Keywords=logitech;unifying;receiver;mouse;keyboard; Categories=Utility;GTK; #Categories=Utility;GTK;Settings;HardwareSettings; Solaar-1.1.20/share/solaar-master.svg000066400000000000000000000134571522022367600174300ustar00rootroot00000000000000 Solaar master template image/svg+xml Solaar master template Daniel Pavel 2013-06-25 solaar-master Solaar-1.1.20/share/solaar/000077500000000000000000000000001522022367600154045ustar00rootroot00000000000000Solaar-1.1.20/share/solaar/icons/000077500000000000000000000000001522022367600165175ustar00rootroot00000000000000Solaar-1.1.20/share/solaar/icons/THIRD_PARTY.md000066400000000000000000000034501522022367600206740ustar00rootroot00000000000000# Third-party assets in this directory Solaar itself is licensed under GPL-2.0 (see `LICENSE.txt` at the repository root). Some icons in this directory are sourced from third-party projects under permissive licenses compatible with GPL-2.0. Their original license notices are preserved as comments inside each SVG file. ## Tabler Icons The following SVGs are derived from [Tabler Icons](https://tabler.io/icons), copyright (c) 2020-2024 PaweÅ‚ Kuna, distributed under the MIT License: - `solaar-tool-brush-symbolic.svg` — from `brush` - `solaar-tool-rect-symbolic.svg` — from `paint` - `solaar-tool-bucket-symbolic.svg` — from `bucket-droplet` - `solaar-tool-palette-off-symbolic.svg` — from `palette-off` ### MIT License (Tabler Icons) ``` MIT License Copyright (c) 2020-2024 PaweÅ‚ Kuna Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` Solaar-1.1.20/share/solaar/icons/solaar-attention-dark-filled.svg000066400000000000000000000331341522022367600247040ustar00rootroot00000000000000 Solaar attentionimage/svg+xmlSolaar attentionDaniel Pavel2013-06-25solaar-attention Solaar-1.1.20/share/solaar/icons/solaar-attention.svg000066400000000000000000000067341522022367600225360ustar00rootroot00000000000000 Solaar attention image/svg+xml Solaar attention Daniel Pavel 2013-06-25 solaar-attention Solaar-1.1.20/share/solaar/icons/solaar-filled.svg000066400000000000000000000241751522022367600217670ustar00rootroot00000000000000 Solaarimage/svg+xmlSolaarDaniel Pavel2013-06-25solaar Solaar-1.1.20/share/solaar/icons/solaar-init-dark-filled.svg000066400000000000000000000407631522022367600236500ustar00rootroot00000000000000 Solaar initimage/svg+xmlSolaar initDaniel Pavel2013-06-25solaar-init Solaar-1.1.20/share/solaar/icons/solaar-init-dark-rotate-filled.svg000066400000000000000000000522061522022367600251370ustar00rootroot00000000000000 Solaar initimage/svg+xmlSolaar initDaniel Pavel2013-06-25solaar-init Solaar-1.1.20/share/solaar/icons/solaar-init.svg000066400000000000000000000064011522022367600214630ustar00rootroot00000000000000 Solaar init image/svg+xml Solaar init Daniel Pavel 2013-06-25 solaar-init Solaar-1.1.20/share/solaar/icons/solaar-light_000.png000066400000000000000000000031711522022367600221740ustar00rootroot00000000000000‰PNG  IHDR szzô@IDATxíV°4g=_cl?Gqò[±]\Û¶mÛ¶m[…8y¶�Þ¸¹§îÚöÞª©ö½G_÷à_] Çò}_IOÀ—ߟ€áo©›nº)xÿûßÿü¾¾¾Ë÷îÝÛwÎ9ç„�@e~~~ô–[nùÖ›Þô¦Ÿ°þî\×Õïz×»ÞpìØ±:tè´öövض-×t]—ßÎΗ––žóà?ø‹œ¿ €¯ýë¡w¼ã¯ºüòËÑÑѡȭV Žã  "�£Ùl‚½aB¡>ýéO¿û‚ .x €úoøüç?�?UwÜq‡Á '‰R,ßzÏ»ßý `¡P�a•JEˆ K&“rž*¡ÑhÈ9ªƒ/|á ÛÛÞv±ä�)ðŒg÷y*¥Šu±^¯7º»º®0M³à°©Rš2 �žZ>eTžï¡X*ahh'Ÿ|²øÎ{eè/1�ž¤Àëdff[[[à¹äÚÚÚý¨ÂKøFgW÷™míOj¶Zæúæ¦�T~³ÙâÐÖÖ7�ÅüÃe5›Š“Àkà±0ëêêF:“ÁææÆÇư½½�ÕÕUÎ@beeËËËbCˆÛn» Tåz¯àm¥bN743¤L•Ïd±[©úŽë£V­©ÝZl¤’‰blÐÒuU«×¡) {ø#h‰¼oL– …"ƒöyPbÙeÈܲ_ƒwÞ)êÔjµÓ666Â*úåW\éì踯a˜F0Pš¦(³�݃ b.›R ¦Aû5åºh l4uaà֤ױXÉTćþ�ÓpJ_/Ž=†s÷ì{ŠÌhu°··÷µR7¸^—Ä¥p*Ù"ƒ^*ÓÐÅ “þóÙº’öp„©P>Ðh6ÅãAD£�úN9½üY–ƒõ�-Q)‰âÚë®ÇG?òLON ‘LzTÉK¿êÊ+ëò2kó<¿Ó0ô€eµ`2Pœ¢lÛ‚OKễ븊°l›k¼ K!R¸d;6�R7y_ >(,N?óLœÁ…ØÙÞ޸暫_ÅfSRøàKûöîýô9ž›°,¥B-ȤR°Øt{k[I‹`èš¼h¨¨šl#Ñ0gB^8üɪ@®†>÷y3·—ãÒ ëØ4Œ¯~õ« ´U^©¥’ñDƒL#Á 4ކC¶Z¯�…‡ø¾G†\§—`ÄÏqáz¾ $ x®'@f[„Ç>šT|¾T,$¿÷ƒF@úþƒ‡Ð¨Uíh<1 …lµV�1µ ²RlNvÒD^Bñh®ŒJ…«ƒ�¸t¡ÈˆNde¾”¤>A'PøKš–…íãeéc˜fpvnþ3#C«zO÷)|A”1<4:¿²ºôÙ «§»ûj°¥&”Y‘q½ÖÀN¹"C²é´Ô!{‹Ý0dëx64]—kж1chÑZËvÈz±˜ßKC~`œqöiøE]váùÖðøäwÖ76¿ÆtwpÈ–ãXGÈ0 ¨eµ$|·vË‚0¥9ÃGpu¸TÐÄ*MÓ Þ‘ŒP$Ø–ë€ÿ3ûÔžR©íÅêŸþ~»–æLŸO¹–íÇS‰GPò{’aIQžvøpÅu}� Os9Å™ *b@çÀZ½&¶ d’©…ᑦe[-'HP­D<~k<ùœzÛ;߃?R\2ë*Mš¾ë¸*LÚÁç]›6*»¹[X\Zz<—Ó=R©d¶§»G¾”\j ’-ªó~¶ßP·ì…ãå²2�€æØ–g;®ÀS/õëñ·ÔSžð599ýáx.¿ ý\žAªÒàGm‚ÿ–nã×±ú£Éþ•õÿðÿð/ðS5Å~ÿux�IEND®B`‚Solaar-1.1.20/share/solaar/icons/solaar-light_020.png000066400000000000000000000035471522022367600222050ustar00rootroot00000000000000‰PNG  IHDR szzô.IDATx•×”#KÀñ[]�tÇÆpmë³mÛ¶mÛ¶ý=Ûë݇µwœQ2£YÝU¯Ž'³Éow~äp©ë€Ã÷�†+ùл_Ãýóª;ÞœÍæ>ó–7¼<½aíJ�e±Àqˆ @,à—Q2OoÙ¼þ_úúŸpydüÚÁ�ÜoÀºb@.›„¥¼àYO䮺qÿ—V,_þÖx4ts(¯ézÌ!VIpew¶ÙÔwîØ¾} Œ|xl|b³ìÞæ’„8°”ÛöÞÿÖeÃÃoéËeZ¹Ó‡îÝ»bõúáHü‰Ñ Ø "©ÔµX¹f ùýXµr9/Â3'§òßøÊ§ßõI`¾üé÷B'ßÿù_“ÉÔ‡³™dA‘}€ Rª•n8!M/ìoŽqX�£LRâ[)àˆ‚À‡B!ghpÀðº^õ•ïþæz8Ø1À€N²™ô[DìÞøœ§îO�½TQ s§DQä¶�aŒ™?}Áì�Ñ6pü:J™‡L1Ú³ks@‘Eªú»^û’§ê´þýo{,fïÁc>›âÝÏ~úž“ét:Ó:x`¯,ËÔ `<σJ¬@ üâ„ÍÀ¡}¹. \_6MÆ#âød~ÝÏ÷ï4 ða1Œ±þX4|xóÆ [ÚíÖAÀçóч~Êr ‰1Dc€ ÆÀdŒu18®ƒjµæÂÚÕÃ+×®^Î��� w xh¥‹i´Úi‡Ø5ï�b©¤ªÞÍçóÙ`0Hü�PP± ­ø„�@)µ«åâ}Ñxz›CH  ë•jÍðùÖ¬È%Ç]‡ø Þ;ì°à1æ\]׿½•3Ah.—S3™ŒЦ˲geŸx€ã0nkz6—Û€¦·­¶(JÄе9×u·ü²†1�ð�1ǵîì¹ó÷Ûªy4�N[À +¼ ¬†8Nk·bŽK΃~]ä‘F*ø$‘1æ«5Â(}ºnmÄ!½c€w‹ ü3†Ižtúô™‰T2n+ŠÂ$Ÿ,ÊþðJ‘Çç…—0m{ÇÊDªÎƒF±0‰ÆR¦i�P(ˆZ­ÖH>?3‹9¾Ô1À;„Å|áãï.}ñ?3›-CJ&ÀB1ó( V CãÃá%Áu�ñ�›¶msÁP0Ô�!¶Y+ õc'N_ua$Ÿ^µrx®c€w‹¹êúÛeìäl±¼®/—l{q,ËÐMC»DIqˆ1@0c®ièš ˆ‚ ½]·‰ƒÊ•†lYöèT~ÖîàB'O|ÜÎcGî;¹e~¡‡B5I¢¬Õ¬WB•G�…cé8$!85«BЇšŒ¹N½V)˜¦Iªµ¦¼P®ù¢‘ðiXï @'sssøžñɹ§e’±¶Ï'YŽã0I’ØÄ|;[n;F0  ‰oA4¤°e˜«SJ‘¦é|~¶5LrÑ0ú’åj–ò�w¾jì§¿ý÷–‰ü|4 ,`Œ)BVƦ—÷ÇÚ²,ÏÎ�TDÔJ%•´Úm”Ÿ)†‹j•íܶñ\¿sÛXÊ©s£, Þ�Ÿ]xu.“¨‰¢`0�Z®ûŽŸ_Îaä†k÷ƾ*!Uªuarz>Áì{àÄ9÷ŠÞt¡Fˆ;23_ŠÆc!“yJÕ@®O™5m"é5]4MlÛ†ÂBEiifõ­¯}Át�Ëk_ÝøÏÕ·ó^õ+,ËQ9ÏÙˆ1—s0‡ÀC‰CùR¹v9úû¿]˺ ð¡#g�´—¯Ý¡k†-¤’¢)‰Á‹8Œy‡½/Àð@M¥…¢ªÖ*¥¯ ¯XO»ð†¡[…Ù±J¹ ö=ùq[ÆÜ~û�`Ù^ò’—Àk_ÿ:î3ŸúDÆÔ*Mèï]€nqGtCs«e•_±bµ²²òñv»�þ-0òãÿÿJ½ó�ï”ÆæéÏxÆŽmY?,«j[Ù6Ç1kªªú¿ÿ,I³Aø�0«º(ÀÊåË_úþ^}泟u7Ûí£[[['OŸ9ý¨_þò—ŸøÍo~ûS XÏ{Îs½É|ö(ÛViUV66Ö§iöu­Ƕm!@UYj–äy>É‹rLURe[z:�¾D]¾rZׯ_÷\×Ý ‚`ÿÙÏ~ö+÷÷÷ŸOô¡R¶ÚÞÞyéîîÞ«¾ÿýïüQ�~ÌÙñtú–º®ŸT×�´g&–ÕqZ-e‰H…A Ïò¦(+‹¤åzëI–oDA@p6èIªÛí¶m¥ŽàÄq<ô¡}êÑ£G^Aÿ‚�å8-!#”e ˲Ÿ8qòÍQ÷góù› êáaè çjþ·�5¥”ÞloX®Û²ø;PÐë7|‰ˆ6JdµMYVõØÇ=îu[›[/N³Ìš/²¾¶&d£¸EYJÓh³ }DÓ §²,ýB]•¶ãùÒ4•(Š„MA2š ‚ŸA P¥¬¯¯K‘ç’f)ç…àö �Ç¿Wí��‡ÅqèWl(bqr²M’aÓˆïyð}Iš‚þ�˱ã'2¡"f>‹úýž®0 Cɋ܀e6ÀyPʲšFÁヲ7ÌË/Ãák'ü¡JÓ¤ïy$}ƒp‘°b¢õ<×4 à‚ †Ónþã|¬®Ä [2�4•’ñxª©„Lf3]Õ ˜¡ªˆãèD§Û›l´W´ªªú*{�É3k>ˆžôÌ0Y˜÷ ðAh(çPÞÂ|¦*X[]Aà{Ró÷Étn¬kššê$€nÄó=MßuÈr�ìÊÕ«?K]¸xéM Î.=|›ziVÀu ü ôÏ4¤¦!Á‚þcFfÌ ; *0Ýàt@;,U¡ZK¾ G^VHF)Š|þû ^ÍÓôÙS§N €sgÏÜêt:ßámõPÏ÷w –½BIç“)øÎæ �N ši*–e„Q�iк6sðÌŠTuÉ5-@'´L�²ƒá8f0(.n¸«fR÷JnÄï:K3a�žaÐ`±LȬ�Ë�i C陡›Æ0f�Ò£¬¹žlé9�žrAÏa+fÓRýFÓ—?){ÿÈQÍ_X‰ãËe:ÊY¥WX‰#a€à»®ñym%¢üè-h•ñ_ z6_`0Ñ–9jZè³ÆfXOg&ÐhݾÝùïƒ!8`?íéOY/oܸõñËW.ÿxoo÷…ZÕà. of1%Ë0ÊóÂäBà…„9GN@5€+° >„ Q nÅ÷½qóæ™§ìG?æ±&\Ñlom�yæÛlbõºÝ[£Ñ°ÍûZM¦6Y˜»�¡d²—º6JjT´\.±LÐb£Ìr±�$ÃxÙðÿ” -Aõ˜0u”jc1›|Þœ²×¿þõø“â‚™µ±¹á\¾|9*€a�‹ç´´¶,&}-î*|å€ ôøF‚Ë´ÔÒÔ²ÈJq”hÑÆ S¬óçÏß©ãÀ€e®cùB…dIEND®B`‚Solaar-1.1.20/share/solaar/icons/solaar-light_060.png000066400000000000000000000044171522022367600222060ustar00rootroot00000000000000‰PNG  IHDR szzôÖIDATxíÓ˜+M—ðÿ)u'Ž2æåÚ¶mÛö>XÛÞ}üÙ¶ýÚ¶®ïx2™°YUg7YÛþ~1ºû�ð/ÄoûÂGnÃH=þ1 Ç®�0aÀ5¸uYÐvtBamÝ/(�€UƒÒÙׄ»?‹�¦…¾ñ ¦øo¨øý›§Ê…œ\åtvš8“(å'�Ù*2ž†èìú]2²!³^x×EŒ>+Àãç"¨x�|ìÛ €œâÿ¨ÒS_-0/\­ÚðÈÒµó9ÂZ›Ùy€ €Š“F×pÅñ[ŸšÞ<º·<%Þå‡[9ŠÊlm;>l]”½u�ÕŸéQzßGà|ÄýÆÞó•‘;™MtñiÍÊñfwgïlÒþ´Ïj~ÌW {€Ì@`€`36༆ޣ·$F½å®™�Ù÷rIâdö^ æèóÞØ)R(Êü£¾ÿ‡Y~äG$§?ê#?é[4™mÎð‡$WŸ-Ô/l-|öWI c� %�ñ+˜ð ¶p —tï¹Ó•çî»gjiñ­œ‹wûó×Û²ž{Â_ºéæD†âääø£> 9Õú°¹¹ù¯ L°âሠˆ…¤þõÛ0C¯AP1€Ñ �þ"uÀÞ[pjÁ¹…ŽÞò‚lé ê/ ëá-ÜWo§pçÈnAÑïÿþïŸòiŸúå�v§EÑ|¯×ËΞ=÷mQT:ë½A�Öš²4åÂä=é ‚ÃŸDcÚƒ…�A€À xççÀ…ƒK-| îx5ÒX>¼ñùò÷\(/Q¼^ ­µÕòòÊùÍõ�g/-.…GícŠªU6�¡"/�fŽ;'(—KlÆAd9H3$ £×^„¥MxjAÒã˜oÞ�(„�`x0;íàã]è0zÐ�·ÃÖ«Ãùw°nâ 1T«««�1e)5ëuŽb8ç)Žctû}dyFKAŒ¥i ç~žHv¥ÓÇ`·÷ ˜¶‚™fL øwÀî2t«ÐÝëIsfÆ/²�>ŒR~Xíîîlo�ÚÈ„�F•ÆÑ[ç ¥@T*avº�f£AÆhŒÖÈò‚J0š¡u¥ˆaðAèt¿Ö¿ib�gQ¸-ÀuØ¡Z½E'«cíðåÝû�.¶U–å‡RˆžÔ*3jµˆò¼€ p†(…J 0óäQ.—a‚RäEŽl˜! J¥Ê% ­>Ö} ´²èw�AÄ€‘È*ŸŽáÅOG%k‹–uF¸Räix ¿à‹¾dæ'•�ç´QsÆÂY­¥ÈyGEaÁÞƒ�C^Œg#Ÿ\)ey�þpçxrb)ŒR Â2´–`fH9~õøK…µ0F0Þ�<ËPX�YzæÂìŸù�ËmÁ6À wÛÇÇ¿“¦é3RŠ8*—AŒV“þF¥2Œ–˜oÍNæa”$èõû88<@šæ‹ãÇ�îäÂJ)DQ„pR™<EQ sÒ›l‘Òb:«Ø‡Ä†ü…�ÅGn݉—¾káñ÷¼û½/ÞÙÝ�9}ú3ÅŸg,@ÓFAK…^o€v§‹ÀhÔjUh¥'eÅ1¼÷“ÏBHxðä=�BÂZ7^kÏ è(þа{¹x¯ü‚Oø:ìînb­Òæ¯ùîoÏ\¡|«µôéγN²üH QqÌä�a|‚Q£Yo ^¯#&kˆÐ” ´3�ÿß“¡�lŒÖiV Irv® ”7ÛnAÒëßøfüMGG‚¥®%KÚ]öô_ô+Bê¯rL‘Ò [ä¤%ì�(¨€P@éÎŽPØ€ àó¤BÇ /•ÏŽº¢Ûë1¼M��ÞD¯ëðOyàñŽNF®þÙ›¸~e®umA¹ý½r˜lú�«ŸÛßÎNuS#RÃ@1çƒh%8ˆ§_Çv¦“õ �¼ÕU¹n>~2óè�3×"1Ìè7~ó7ñÏùéO½a,óW×0J¯ 63PéJÉy°XNÅê°“TŠ4³B‹¬ºXÖ‘©^C” i:È΋Ñ9·€]B@¹Q)äÄþi‹%´s‹¿¿ N;¸¼I@l¼Î?Õ혮ž]#e硆]È"ƒ“@È«¾7uÚjv/ ³ÜsyöŒðÓ¡›¢LG™‡¨K^ɈoÿHü³>þ>À`Œ]ü�Mg“CRÅ:íœð< ÓÙ…gÏLÕü ÒÆeXŽØØ}Lwër{ý1ÔH¢V0‡¿ 0×Ä?ëâgYü¥�®A¹Û£… üè”9äTv�é¹õ\’‚-ôNèòòuWÝiñôÞTÌ €#ü •Cü«ˆ¶ÆŽP±�¥}ÑŠ=\`(,R ƒLHú€÷]}G*³Y ðCÚ_M±00(Uÿ·hâ_έ«)Œ¶%6Ì: ÓíÞI±÷GÎ\_T ›­9»g𬾕¢= ¨ÜGÈ·¨6ÅDÓØÁ …;YÈÑ¥e$-ì ZÖ½¿ìùé–ÊëÈxÄ[²±ß%xM‹™‹s¦›¥äã�”ë·öë“{Gým·“îÜŠ­8tRˆ¿Ö2²ÿ—3k³ß‹ÕÒÛ–³Ðoi¹Ý4WwûÉ=ßÍý“œÁ„‚Äž½ÏÒ*Í“5Öbe_ã‚{´ðî}ñºšç£  …Áw& /}ûììºËߌK•ß`³ƒtjWýßjÐüõ§ÂQð–|A†R;4#aãéëŽÇ;ŸÈ¶}p{´0I‰,bTQp3žÒ¶ûw4ÝüÄü¾^á$¿¨»/4LÐ6Š &® €¸8æ-éoŸ�ð.Å\KIZåö�ƽèÌv7×Ç$&�kÀ(ˆ õc’ù¹jãÄÑ'ÖßSþÃÁ1 ëªÚŸWI+yÏ‹\~m;oª½[\ì-Œ E´™ {ú—ü#¥m]$^ÁÄ9eˆ‘ j¢žÕ8Üì€á•ä–|?�öŽ™lØ/™i+¯â\}+o¦¸í[ÍM…½ºÍA17é^Ô¯1%‡p ìfÔl@L1¤ Öa aˆ«ÞB²P$ýëãÝÓ ìEÆ: Õ(x‘Ã(oÆÉMÂòDÓv,~�z£)Wž2¶¼œè£á!,`£�X³ˆhq4J�¨G¶çnòncv8—´J.\1óŸé½á"”�_‚éÛ°€ôz=®]¹èjW~Zº~í©©…¬?SNÎOÙR+)Ýúé®Ç(Â5T:DiŒD»S ¡‹°Õ2hÉ šœ%o]M}£µùìù•kË_¸´8O?¸É(Äÿò]؇¾šN&“Ýív{¥Ñhdqor.L•2J¥ÒÔýFüV–÷éÈï´åLŒƒ ˆIÀztˆÏê'YCá§(º]\y]C�ù-†ïÇ™ýƒ‰÷í×~œw3Ïý0yá…oTüñÙÕéçf+•ò¬1[5RÉë…�OFƒ¥±q³ip}´8‚$Û1ñ6Ä쉱®‰Ò�C|“ÉÍÃ>NYöZ¹IQi‡lcY o¬5{Á, ·ÿþZ–e5©¤i:‡ãN§S×0š,Ì›ÔJy.‰²œàŽãÏuz'—JÖWÄ•#L#’"’�¦¨€†>EïaH×îlb9Õ]ž\M“s]ïÏúÜÖ~�‡íWË婎÷>¸éé鵫ŸuÎÍW«Õ ¬µ? aå×íÖhR®Ìôƒu‹E0.^ÿT{ìªï^Ú¨E‰–;�´7÷StºÀ|·´aÇqïí×ÓtËðìE?ؼ©¦Âd±^¯WWZ²:íbáÖÁ`P�L&Æ9---ß·o_y5d>²Ú ¸�ôºíµ¶X©f®½¡˜Œç|§>§Òu’McÌÌ ~Ø%to€™nUÖW­Ô'Ãá÷Ç•{Nû¼œ›D*Õæ’&6Ôôåò…³ÞÓÚ>:½¿ü©åác_Ýyö;œiäHdk+¨> Þ ¨†K²[¿qõ�‹É?K¶òϤåßú ×–!aäð' ĸ#ì €ñí‰Y;XÅÌ·³!ß4~­xvåÛs&>@¢;ÄĘ÷¡ò­p«5öðÂÃ÷.-ÖŸ]¼,¶q�+ëÿ×GÅôIÄ9"kQ r*ï6m gR-¤c«õXòÙYMŽ£ã7g›ý†IGHc’‰,b bP…0Ô˜º$ÙŠ™¼°xªØé>ÚèÍþ�Ír5´Ú½öþ¹†‰’C’xà’á70Y¼I¯‘TÞÚ…µ¬«°»Ùo ¿çöfˆ�"Qqb-bßKPð xŒ«Ñ¨BÜɪºñõì›Ï<»1·û«ÿ&ÅÆ«¤r/Dµ7ó¨ãú>Í�o5Zjjür¿|cŸß)‹VTLª®!öL¢Y7# ÿ{=i߸ta‚] ˆ&[Zgm â XÄ,�§å@EA=H@L FNk‰Á:$/F·[+ËW%*nÊÓóe”S®ÿM/âÿég£°’·$hG+·"„&OÅ唈€FÀFˆ‹ S @@A£¨3�åÚ“Z¬þ¼u?XÍ‚ÏfÑ�£Ìñ«Oby³*~å�©ó,tÖ^˜iÒÐ*¿"‰†Rê ª€é"ÒC$c@K�ÂÕTÑР%äªc±'·4Ö±ÕÃÂBàap<\÷]ޤ$BpA*o曹”$Í�Ñ$ß?!T5ú¿‹O€È&È*ªM$h4A ês´hYr�M¢#‰õ—Õ:˜¯ëêu­›‹Ü@é…«¾ö2dTñ ½šô¹ÔÔ²ªÍÃmÈlwÇ]š¾m/&óªé[%&m£¡�Ñ5Ðh0 KÀ¡¡@ý1¡á—%ÕI Ýh^“b¥A°kDáPn�K$kO�¥\ôÊ÷ày©mæ·×©âTŽºo‚£¨ÎÓ­Æn±¿ø^ÓÌ1I‰m4i ¬"f0‚�¡µ%?Ëð“‚2wƒ­Ö•�ŽÿÝNw_×ÙÊ2lÜsúèkMo*2W<þÐÈ\’7—¼pþ ¡šÆ¦F5{sðP»û…j«¼[>)fŒ‰�·…˜q)àNc½Ä/&Ô'CêÑ’ìž©Öéþ�QýS=~`â×§Ó»³oàXÞüž†ë^-yú5U>èùïtÁkê;ªþ¢÷ò‹÷.í£ Ùn²×&,¾3n…4Zë`[ÄÚÿ‹}=�PœÔÞ¦é�•óɯ7ÌæI^¦èG¨û/™]”¯yYh4Pˆ|½ô�gDê4tv´šß6µnáÂw3_™Ü2O'åƒuU*A��#\Ç {›�aÜ1wÉIÙ9ßkÔœKmƒº0F|ˆ„ü>Lí¦Ï—ÈÞõUSÕÃ0Š­»£®ØÓhܶ'[�k¨ûij;*UAÝY'­²l IüÄMÂìwdv®M‹cu6­‹ªŠì¢jÞƒ7æºç…C2{ñµˆùÁ> Á”ßdüÚQοjºñõJçŸ!¥¶#‘<Ó²»&Íbí\!ï±6ú3tum¾/ã8‘áx=㔽ôŸ%Da#´Æ3z‡ ûßÖÅÅ"¥‰ÔdcYœ”÷cÝ;º Ç{Ú8H¨ºû N6ÍþÓ7>s^ÀÉÓ|ªoüMÑ{ý…(y­·Dâ!¶²w‚Ìȯ”’¬F•'èòX“oæ]Y»w‹¸ì>…øý |sæm@;-¹¹½ô<â„`³é�ÐVS%œ¯ÕÉd_yH‹�ýXØ4w@ͧ�ê¸ËçáS xÞþñ�¼¸Úù³dRÖ×1@àsU¾"@ù‚þVù‚)9npdIEND®B`‚Solaar-1.1.20/share/solaar/icons/solaar-light_unknown.png000066400000000000000000000017571522022367600234040ustar00rootroot00000000000000‰PNG  IHDR szzô¶IDATxbñ€Š™€˜™Îvÿâ,@‚ˆ€XˆYèdù ~ Ä�ÀìåË—ùøø$¨e:ÐL‚bŸ>}z!..ÀÈÌÌöåË—•Ϊ¢¶ Ž+P"HEQ’¤¢P•TRJð‰ˆ¨(‚‰@ ˆP’J(¡©¢¢ª(• !½Þýo0ØcÝÒ°vß¶»sΜ¹§½½=¤§§G=hgïZC¿}g|(//GFFÆ?Jž†!ÒÒÒP\\l‰ÿ”µ ÔîßÝÝ�ëx<ž$ÈY/óí���aqqÓÓÓ˜™™ÁÒÒ...,©ï.Ïpfa`ˆ¼R ———Âøø8ŽŽŽôNOO199‰±±1ÜÜÜ`ss///°oÚÁ»r=‚ p"µÙìïïcnn%%%èïïGNNŽsæññ««« *|+á-deeÁB\äP‘õ"®¯¯1??�ÖÖVtww{ÕÉÎÎFff&îïïA‚‚‚XX5¾¿¿Ã@¼d¥—¬qii)ÉyÎëò••ÐÕÕÕ J[[[¼©Gð“ãYÓ÷÷wtuuñ¢C¬×ÖÖhBTUU¡³³ÍÍÍøøøÀÃÃ|HNNVp¬¬T””òªž6Pfzuu…ÊÊJ´··ó$ Ïãùù‚œ‹Åp~~ŽÏÏOIz�¦ñ|ÏÌ„hßÉ|{{···¨¨¨@SS“s7//� ‡Fã`½9ƒàZ $)ª··7äææZ/°;ò"×N&‡‡‡l((++CMM�j*wcbb©©©¨««sþ¦„$m¼¾¾âëë˶RJŒ�� ~÷ øx__ÐÓÓƒÞÞ^& U4Óèèèày‡\oXpÃÛNYcœœœXrÌÎÎÊ;NöÇÇÇT‡Ù;d6) M¯ÉPTT„‘‘zÁ’;Ù©Þ£££(,,„ä·—m;¶ßùÔÔZZZ@ˆ\^Ð�ц‡‡Áÿ¬ì :cÀsn Ô—mý5óA�-—½_¤,{Û5fC2ð—€Q l.\Óí¨­­E~~>(3A�°æü½¼¼Lr›ùï<`M¨™/`ww;;;xzzïµµµ�AÕ××C¾0ˆô€j%B ën­ID‰~«@Œ öíõõuÛí"Ç_Aåþ ªÿ/ Ð5¯Þ¼yó:33S‹¯a®E¡©€ áW@êÈF) 6bÀä�˜•�>à7?â3ŒÐ ³�³%}(ñ�Ѿá(�<Žšwï…™IEND®B`‚Solaar-1.1.20/share/solaar/icons/solaar-symbolic-dark-filled.svg000066400000000000000000000325331522022367600245220ustar00rootroot00000000000000 Solaarimage/svg+xmlSolaarDaniel Pavel2013-06-25solaar Solaar-1.1.20/share/solaar/icons/solaar-symbolic-filled.svg000066400000000000000000000325221522022367600236010ustar00rootroot00000000000000 Solaarimage/svg+xmlSolaarDaniel Pavel2013-06-25solaar Solaar-1.1.20/share/solaar/icons/solaar-symbolic.svg000066400000000000000000000063651522022367600223520ustar00rootroot00000000000000 Solaar image/svg+xml Solaar Daniel Pavel 2013-06-25 solaar Solaar-1.1.20/share/solaar/icons/solaar-tool-brush-symbolic.svg000066400000000000000000000011171522022367600244340ustar00rootroot00000000000000 Solaar-1.1.20/share/solaar/icons/solaar-tool-bucket-symbolic.svg000066400000000000000000000015671522022367600245770ustar00rootroot00000000000000 Solaar-1.1.20/share/solaar/icons/solaar-tool-palette-off-symbolic.svg000066400000000000000000000015001522022367600255130ustar00rootroot00000000000000 Solaar-1.1.20/share/solaar/icons/solaar-tool-rect-symbolic.svg000066400000000000000000000012341522022367600242460ustar00rootroot00000000000000 Solaar-1.1.20/share/solaar/icons/solaar.svg000066400000000000000000000063621522022367600205300ustar00rootroot00000000000000 Solaar image/svg+xml Solaar Daniel Pavel 2013-06-25 solaar Solaar-1.1.20/share/solaar/io.github.pwr_solaar.solaar.metainfo.xml000066400000000000000000000165411522022367600252560ustar00rootroot00000000000000 io.github.pwr_solaar.solaar Solaar Linux manager for Logitech keyboards, mice, and trackpads pwr-Solaar https://pwr-solaar.github.io/Solaar/ https://github.com/pwr-Solaar/Solaar pfpschneider_AT_gmail.com CC-BY-4.0 GPL-2.0-only pointing keyboard touch

Solaar is a Linux manager for many Logitech keyboards, mice, and trackpads that connect wirelessly to a USB, Lightspeed, or Nano receiver, connect directly via a USB cable, or connect via Bluetooth. Solaar does not work with peripherals from other companies.

Solaar can be used as a GUI application or via its command-line interface. Both interfaces are able to list the connected devices and show information about each device, often including battery status. Solaar is able to pair and unpair devices with receivers as supported by the device and receiver. Solaar can also control some changeable features of devices, such as smooth scrolling or function key behavior.

Solaar's GUI normally uses an icon in the system tray and starts with its main window visible.

solaar.desktop https://raw.githubusercontent.com/pwr-Solaar/Solaar/master/docs/screenshots/Solaar-main-window-button-actions.png https://raw.githubusercontent.com/pwr-Solaar/Solaar/master/docs/screenshots/Solaar-main-window-receiver.png https://raw.githubusercontent.com/pwr-Solaar/Solaar/master/docs/screenshots/Solaar-menu.png solaar usb:v17EFp6042d* usb:v046DpC517d* usb:v046DpC518d* usb:v046DpC51Ad* usb:v046DpC51Bd* usb:v046DpC521d* usb:v046DpC525d* usb:v046DpC526d* usb:v046DpC52Bd* usb:v046DpC52Ed* usb:v046DpC52Fd* usb:v046DpC531d* usb:v046DpC532d* usb:v046DpC534d* usb:v046DpC537d* usb:v046DpC539d* usb:v046DpC53Ad* usb:v046DpC53Dd* usb:v046DpC53Fd* usb:v046DpC541d* usb:v046DpC545d* usb:v046DpC547d* usb:v046DpC548d* usb:v046DpC06Bd* usb:v046DpC07Cd* usb:v046DpC07Dd* usb:v046DpC07Ed* usb:v046DpC07Fd* usb:v046DpC08*d* usb:v046DpC090d* usb:v046DpC091d* usb:v046DpC092d* usb:v046DpC093d* usb:v046DpC094d* usb:v046DpC32Bd* usb:v046DpC32Cd* usb:v046DpC32Dd* usb:v046DpC32Ed* usb:v046DpC32Fd* usb:v046DpC33*d* usb:v046DpC340d* usb:v046DpC341d* usb:v046DpC342d* usb:v046DpC343d* usb:v046DpC344d* usb:v046DpB012d* usb:v046DpB013d* usb:v046DpB014d* usb:v046DpB015d* usb:v046DpB016d* usb:v046DpB017d* usb:v046DpB018d* usb:v046DpB019d* usb:v046DpB01Ad* usb:v046DpB01Bd* usb:v046DpB01Cd* usb:v046DpB01Dd* usb:v046DpB01Ed* usb:v046DpB01Fd* usb:v046DpB02*d* usb:v046DpB03*d* usb:v046DpB04*d* usb:v046DpB05*d* usb:v046DpB06*d* usb:v046DpB07*d* usb:v046DpB08*d* usb:v046DpB09*d* usb:v046DpB0A*d* usb:v046DpB0B*d* usb:v046DpB0C*d* usb:v046DpB0D*d* usb:v046DpB0E*d* usb:v046DpB0F*d* usb:v046DpB32Ad* usb:v046DpB32Bd* usb:v046DpB32Cd* usb:v046DpB32Dd* usb:v046DpB32Ed* usb:v046DpB32Fd* usb:v046DpB33*d* usb:v046DpB34*d* usb:v046DpB35*d* usb:v046DpB36*d* usb:v046DpB37*d* usb:v046DpB38*d* usb:v046DpB39*d* usb:v046DpB3A*d* usb:v046DpB3B*d* usb:v046DpB3C*d* usb:v046DpB3D*d* usb:v046DpB3E*d* usb:v046DpB3F*d*
Solaar-1.1.20/tests/000077500000000000000000000000001522022367600141635ustar00rootroot00000000000000Solaar-1.1.20/tests/__init__.py000066400000000000000000000000001522022367600162620ustar00rootroot00000000000000Solaar-1.1.20/tests/conftest.py000066400000000000000000000035151522022367600163660ustar00rootroot00000000000000import importlib from unittest import mock import pytest @pytest.fixture(autouse=True) def isolate_solaar_configuration(tmp_path, monkeypatch): """Redirect solaar.configuration at a throwaway path for every test. Tests build FakeDevices named 'TestDevice'; any that touch device.settings or device.persister without mocking call the real configuration.persister(), which loads and rewrites ~/.config/solaar/config.yaml — appending a fresh un-matchable TestDevice entry on every run. Pointing the paths at tmp_path and clearing the cached _config keeps each test off the real config and isolated from every other test.""" from solaar import configuration monkeypatch.setattr(configuration, "_yaml_file_path", str(tmp_path / "config.yaml")) monkeypatch.setattr(configuration, "_json_file_path", str(tmp_path / "config.json")) monkeypatch.setattr(configuration, "_config", []) @pytest.fixture(autouse=True) def mock_desktop_notifications(monkeypatch): """Swap the libnotify backend for a mock in both desktop_notifications modules. Tests still exercise the real init/alert/show code paths, but Notification.show() never reaches the daemon — without this the suite raises real 'MockDevice' / 'unknown' notifications on every run. Returns the Notify mock so notification tests can assert against it.""" notify = mock.MagicMock(name="Notify") notify.is_initted.return_value = True notify.init.return_value = True for modname in ("solaar.ui.desktop_notifications", "logitech_receiver.desktop_notifications"): try: module = importlib.import_module(modname) except Exception: continue monkeypatch.setattr(module, "Notify", notify, raising=False) monkeypatch.setattr(module, "_notifications", {}, raising=False) return notify Solaar-1.1.20/tests/hid_parser/000077500000000000000000000000001522022367600163035ustar00rootroot00000000000000Solaar-1.1.20/tests/hid_parser/__init__.py000066400000000000000000000000001522022367600204020ustar00rootroot00000000000000Solaar-1.1.20/tests/hid_parser/test_data.py000066400000000000000000000004221522022367600206230ustar00rootroot00000000000000from hid_parser.data import Button from hid_parser.data import Consumer def test_consumer(): consumer = Consumer() assert consumer.PLAY_PAUSE == 0xCD def test_button(): button = Button() assert button.NO_BUTTON == 0x0 assert button.BUTTON_1 == 0x1 Solaar-1.1.20/tests/hidapi/000077500000000000000000000000001522022367600154215ustar00rootroot00000000000000Solaar-1.1.20/tests/hidapi/__init__.py000066400000000000000000000000001522022367600175200ustar00rootroot00000000000000Solaar-1.1.20/tests/hidapi/test_hidapi.py000066400000000000000000000003421522022367600202670ustar00rootroot00000000000000import platform from unittest import mock if platform.system() == "Linux": import hidapi.udev_impl as hidapi else: import hidapi.hidapi_impl as hidapi def test_find_paired_node(): hidapi.enumerate(mock.Mock()) Solaar-1.1.20/tests/logitech_receiver/000077500000000000000000000000001522022367600176455ustar00rootroot00000000000000Solaar-1.1.20/tests/logitech_receiver/__init__.py000066400000000000000000000000001522022367600217440ustar00rootroot00000000000000Solaar-1.1.20/tests/logitech_receiver/fake_hidpp.py000066400000000000000000000600111522022367600223070ustar00rootroot00000000000000## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """HID++ data and functions common to several logitech_receiver test files""" from __future__ import annotations import errno import threading from dataclasses import dataclass from dataclasses import field from struct import pack from typing import Any from typing import Optional from logitech_receiver import device from logitech_receiver import hidpp20 from solaar import configuration def open_path(path: Optional[str]) -> int: if path is None: raise OSError(errno.EACCES, "Fake access error") return int(path, 16) # can raise exception def ping(responses, handle, devnumber, long_message=False): for r in responses: if handle == r.handle and devnumber == r.devnumber and r.id == 0x0010: return r.response def request( responses, handle, devnumber, id, *params, no_reply=False, return_error=False, long_message=False, protocol=1.0, ): params = b"".join(pack("B", p) if isinstance(p, int) else p for p in params) print("REQUEST ", hex(handle), hex(devnumber), hex(id), params.hex()) for r in responses: if handle == r.handle and devnumber == r.devnumber and r.id == id and bytes.fromhex(r.params) == params: print("RESPONSE", hex(r.handle), hex(r.devnumber), hex(r.id), r.params, r.response) return bytes.fromhex(r.response) if r.response is not None else None @dataclass class Response: response: str | float id: int params: str = "" handle: int = 0x11 devnumber: int = 0xFF no_reply: bool = False def replace_number(responses, number): # change the devnumber for a list of responses return [Response(r.response, r.id, r.params, r.handle, number, r.no_reply) for r in responses] def adjust_responses_index(index, responses): # change index-4 responses to index return [Response(r.response, r.id - 0x400 + (index << 8), r.params, r.handle, r.devnumber, r.no_reply) for r in responses] r_empty = [ # a HID++ device with no responses except for ping Response(1.0, 0x0010), # ping ] r_keyboard_1 = [ # a HID++ 1.0 keyboard Response(1.0, 0x0010), # ping Response("001234", 0x81F1, "01"), # firmware Response("003412", 0x81F1, "02"), # firmware Response("002345", 0x81F1, "03"), # firmware Response("003456", 0x81F1, "04"), # firmware Response("050050", 0x8107), # battery status ] r_keyboard_2 = [ # a HID++ 2.0 keyboard Response(4.2, 0x0010), # ping Response("010001", 0x0000, "0001"), # feature set at 0x01 Response("020003", 0x0000, "0020"), # CONFIG_CHANGE at 0x02 Response("030001", 0x0000, "0003"), # device information at 0x03 Response("040003", 0x0000, "0100"), # unknown 0100 at 0x04 Response("050003", 0x0000, "1B04"), # reprogrammable keys V4 at 0x05 Response("060003", 0x0000, "0007"), # device friendly name at 0x06 Response("070003", 0x0000, "0005"), # device name at 0x07 Response("080003", 0x0000, "1000"), # battery status at 0x08 Response("08", 0x0100), # 8 features Response("00010001", 0x0110, "01"), # feature set at 0x01 Response("00200003", 0x0110, "02"), # CONFIG_CHANGE at 0x02 Response("00030001", 0x0110, "03"), # device information at 0x03 Response("01000003", 0x0110, "04"), # unknown 0100 at 0x04 Response("1B040003", 0x0110, "05"), # reprogrammable keys V4 at 0x05 Response("00070003", 0x0000, "06"), # device friendly name at 0x06 Response("00050003", 0x0000, "07"), # device name at 0x07 Response("10000001", 0x0110, "08"), # battery status at 0x02 Response("0212345678000D1234567890ABAA01", 0x0300), # device information Response("04", 0x0500), # reprogrammable keys V4 Response("00110012AB010203CD00", 0x0510, "00"), # reprogrammable keys V4 Response("01110022AB010203CD00", 0x0510, "01"), # reprogrammable keys V4 Response("00010111AB010203CD00", 0x0510, "02"), # reprogrammable keys V4 Response("03110032AB010204CD00", 0x0510, "03"), # reprogrammable keys V4 Response("00030333AB010203CD00", 0x0510, "04"), # reprogrammable keys V4 Response("12", 0x0600), # friendly namme Response("004142434445464748494A4B4C4D4E", 0x0610, "00"), Response("0E4F50515253000000000000000000", 0x0610, "0E"), Response("12", 0x0700), # name and kind Response("4142434445464748494A4B4C4D4E4F", 0x0710, "00"), Response("505152530000000000000000000000", 0x0710, "0F"), Response("00", 0x0720), Response("12345678", 0x0800), # battery status ] r_mouse_1 = [ # a HID++ 1.0 mouse Response(1.0, 0x0010), # ping ] r_mouse_2 = [ # a HID++ 2.0 mouse with few responses except for ping Response(4.2, 0x0010), # ping ] r_mouse_3 = [ # a HID++ 2.0 mouse Response(4.5, 0x0010), # ping Response("010001", 0x0000, "0001"), # feature set at 0x01 Response("020002", 0x0000, "8060"), # report rate at 0x02 Response("040001", 0x0000, "0003"), # device information at 0x04 Response("050002", 0x0000, "0005"), # device type and name at 0x05 Response("08", 0x0100), # 8 features Response("00010001", 0x0110, "01"), # feature set at 0x01 Response("80600002", 0x0110, "02"), # report rate at 0x02 Response("00030001", 0x0110, "04"), # device information at 0x04 Response("00050002", 0x0110, "05"), # device type and name at 0x05 Response("09", 0x0210), # report rate - current rate Response("03123456790008123456780000AA01", 0x0400), # device information Response("0141424302030100", 0x0410, "00"), # firmware 0 Response("0241", 0x0410, "01"), # firmware 1 Response("05", 0x0410, "02"), # firmware 2 Response("12", 0x0500), # name count - 18 characters Response("414241424142414241424142414241", 0x0510, "00"), # name - first 15 characters Response("444544000000000000000000000000", 0x0510, "0F"), # name - last 3 characters ] responses_key = [ # responses for Reprogrammable Keys V4 at 0x05 Response("08", 0x0500), # Reprogrammable Keys V4 count Response("00500038010001010400000000000000", 0x0510, "00"), # left button Response("00510039010001010400000000000000", 0x0510, "01"), # right button Response("0052003A310003070500000000000000", 0x0510, "02"), # middle button Response("0053003C710002030100000000000000", 0x0510, "03"), # back button Response("0056003E710002030100000000000000", 0x0510, "04"), # forward button Response("00C300A9310003070300000000000000", 0x0510, "05"), # smart shift? Response("00C4009D310003070500000000000000", 0x0510, "06"), # ? Response("00D700B4A00004000300000000000000", 0x0510, "07"), # ? Response("00500000000000000000000000000000", 0x0520, "0050"), # left button Response("00510000000000000000000000000000", 0x0520, "0051"), # ... Response("00520100500000000000000000000000", 0x0520, "0052"), Response("00530500000000000000000000000000", 0x0520, "0053"), Response("00561100000000000000000000000000", 0x0520, "0056"), Response("00C30000000000000000000000000000", 0x0520, "00C3"), Response("00C40000500000000000000000000000", 0x0520, "00C4"), Response("00D70000510000000000000000000000", 0x0520, "00D7"), Response("0041", 0x0400), # flags Response("0401", 0x0410), # count Response("0050", 0x0420, "00FF"), # left button Response("0051", 0x0420, "01FF"), # right button Response("0052", 0x0420, "02FF"), # middle button Response("0053", 0x0420, "03FF"), # back button Response("0050000100500000", 0x0430, "0050FF"), # left button current Response("0051000100500001", 0x0430, "0051FF"), # right button current Response("0052000100500001", 0x0430, "0052FF"), # middle button current Response("0053000100500001", 0x0430, "0053FF"), # back button current Response("0050FF01005000", 0x0440, "0050FF01005000"), # left button write Response("0051FF01005000", 0x0440, "0051FF01005000"), # right button write Response("0051FF01005100", 0x0440, "0051FF01005100"), # right button set write ] responses_remap = [ # responses for Persistent Remappable Actions at 0x04 and reprogrammable keys at 0x05 Response("0041", 0x0400), Response("03", 0x0410), Response("0301", 0x0410, "00"), Response("0050", 0x0420, "00FF"), Response("0050000200010001", 0x0430, "0050FF"), # Left Button Response("0051", 0x0420, "01FF"), Response("0051000200010000", 0x0430, "0051FF"), # Left Button Response("0052", 0x0420, "02FF"), Response("0052000100510000", 0x0430, "0052FF"), # key DOWN Response("050002", 0x0000, "1B04"), # REPROGRAMMABLE_KEYS_V4 ] + responses_key responses_gestures = [ # the commented-out messages are not used by either the setting or other testing Response("4203410141020400320480148C21A301", 0x0400, "0000"), # items Response("A302A11EA30A4105822C852DAD2AAD2B", 0x0400, "0008"), Response("8F408F418F434204AF54912282558264", 0x0400, "0010"), Response("01000000000000000000000000000000", 0x0400, "0018"), Response("01000000000000000000000000000000", 0x0410, "000101"), # enable # Response("02000000000000000000000000000000", 0x0410, "000102"), # Response("04000000000000000000000000000000", 0x0410, "000104"), # Response("08000000000000000000000000000000", 0x0410, "000108"), Response("00000000000000000000000000000000", 0x0410, "000110"), # Response("20000000000000000000000000000000", 0x0410, "000120"), # Response("40000000000000000000000000000000", 0x0410, "000140"), # Response("00000000000000000000000000000000", 0x0410, "000180"), # Response("00000000000000000000000000000000", 0x0410, "010101"), # Response("00000000000000000000000000000000", 0x0410, "010102"), # Response("04000000000000000000000000000000", 0x0410, "010104"), # Response("00000000000000000000000000000000", 0x0410, "010108"), Response("6F000000000000000000000000000000", 0x0410, "0001FF"), Response("04000000000000000000000000000000", 0x0410, "01010F"), Response("00000000000000000000000000000000", 0x0430, "000101"), # divert # Response("00000000000000000000000000000000", 0x0430, "000102"), # Response("00000000000000000000000000000000", 0x0430, "000104"), # Response("00000000000000000000000000000000", 0x0430, "000108"), Response("00000000000000000000000000000000", 0x0430, "000110"), # Response("00000000000000000000000000000000", 0x0430, "000120"), # Response("00000000000000000000000000000000", 0x0430, "000140"), # Response("00000000000000000000000000000000", 0x0430, "000180"), # Response("00000000000000000000000000000000", 0x0430, "010101"), # Response("00000000000000000000000000000000", 0x0430, "010102"), Response("00000000000000000000000000000000", 0x0430, "0001FF"), Response("00000000000000000000000000000000", 0x0430, "010103"), Response("08000000000000000000000000000000", 0x0450, "01FF"), Response("08000000000000000000000000000000", 0x0450, "02FF"), Response("08000000000000000000000000000000", 0x0450, "03FF"), Response("00040000000000000000000000000000", 0x0450, "04FF"), Response("5C020000000000000000000000000000", 0x0450, "05FF"), Response("01000000000000000000000000000000", 0x0460, "00FF"), Response("01000000000000000000000000000000", 0x0470, "00FF"), Response("01", 0x0420, "00010101"), # set index 1 Response("00", 0x0420, "00010100"), # unset index 1 Response("01", 0x0420, "00011010"), # set index 4 Response("00", 0x0420, "00011000"), # unset index 4 Response("01", 0x0440, "00010101"), # divert index 1 Response("00", 0x0440, "00010100"), # undivert index 1 Response("000080FF", 0x0480, "000080FF"), # write param 0 Response("000180FF", 0x0480, "000180FF"), # write param 0 ] zone_responses_1 = [ # responses for COLOR LED EFFECTS Response("00000102", 0x0710, "00FF00"), Response("0000000300040005", 0x0720, "000000"), Response("0001000B00080009", 0x0720, "000100"), ] zone_responses_2 = [ # responses for RGB EFFECTS Response("0000000102", 0x0700, "00FF00"), Response("0000000300040005", 0x0700, "000000"), Response("0001000200080009", 0x0700, "000100"), ] effects_responses_1 = [Response("0100000001", 0x0700)] + zone_responses_1 effects_responses_2 = [Response("FFFF0100000001", 0x0700, "FFFF00")] + zone_responses_2 responses_profiles = [ # OnboardProfile in RAM Response("0104010101020100FE0200", 0x0900), Response("000101FF", 0x0950, "00000000"), Response("FFFFFFFF", 0x0950, "00000004"), Response("01010290018003000700140028FFFFFF", 0x0950, "00010000"), Response("FFFF0000000000000000000000000000", 0x0950, "00010010"), Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "00010020"), Response("900aFF00800204548000FFFF900aFF00", 0x0950, "00010030"), Response("800204548000FFFF900aFF0080020454", 0x0950, "00010040"), Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "00010050"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010060"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010070"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010080"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "00010090"), Response("54004500370000000000000000000000", 0x0950, "000100A0"), Response("00000000000000000000000000000000", 0x0950, "000100B0"), Response("00000000000000000000000000000000", 0x0950, "000100C0"), Response("0A01020300500407000000FFFFFFFFFF", 0x0950, "000100D0"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "000100E0"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0950, "000100EE"), ] responses_profiles_rom = [ # OnboardProfile in ROM Response("0104010101020100FE0200", 0x0900), Response("00000000", 0x0950, "00000000"), Response("010101FF", 0x0950, "01000000"), Response("FFFFFFFF", 0x0950, "01000004"), Response("01010290018003000700140028FFFFFF", 0x0950, "01010000"), Response("FFFF0000000000000000000000000000", 0x0950, "01010010"), Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010020"), Response("900aFF00800204548000FFFF900aFF00", 0x0950, "01010030"), Response("800204548000FFFF900aFF0080020454", 0x0950, "01010040"), Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010050"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010060"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010070"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010080"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010090"), Response("54004500370000000000000000000000", 0x0950, "010100A0"), Response("00000000000000000000000000000000", 0x0950, "010100B0"), Response("00000000000000000000000000000000", 0x0950, "010100C0"), Response("0A01020300500407000000FFFFFFFFFF", 0x0950, "010100D0"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "010100E0"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0950, "010100EE"), ] responses_profiles_rom_2 = [ # OnboardProfile in ROM Response("0104010101020100FE0200", 0x0900), Response("FFFFFFFF", 0x0950, "00000000"), Response("010101FF", 0x0950, "01000000"), Response("FFFFFFFF", 0x0950, "01000004"), Response("01010290018003000700140028FFFFFF", 0x0950, "01010000"), Response("FFFF0000000000000000000000000000", 0x0950, "01010010"), Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010020"), Response("900aFF00800204548000FFFF900aFF00", 0x0950, "01010030"), Response("800204548000FFFF900aFF0080020454", 0x0950, "01010040"), Response("8000FFFF900aFF00800204548000FFFF", 0x0950, "01010050"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010060"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010070"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010080"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "01010090"), Response("54004500370000000000000000000000", 0x0950, "010100A0"), Response("00000000000000000000000000000000", 0x0950, "010100B0"), Response("00000000000000000000000000000000", 0x0950, "010100C0"), Response("0A01020300500407000000FFFFFFFFFF", 0x0950, "010100D0"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0950, "010100E0"), Response("FFFFFFFFFFFFFFFFFFFFFFFFFF7C81AB", 0x0950, "010100EE"), ] complex_responses_1 = [ # COLOR_LED_EFFECTS Response(4.2, 0x0010), # ping Response("010001", 0x0000, "0001"), # FEATURE SET at x01 Response("020001", 0x0000, "0020"), # CONFIG_CHANGE at x02 Response("0A", 0x0100), # 10 features Response("070001", 0x0000, "8070"), # COLOR_LED_EFFECTS at 0x07 *effects_responses_1, ] complex_responses_2 = [ # RGB_EFFECTS + reprogrammable keys + persistent actions Response(4.2, 0x0010), # ping Response("010001", 0x0000, "0001"), # FEATURE SET at x01 Response("020001", 0x0000, "0020"), # CONFIG_CHANGE at x02 Response("0A", 0x0100), # 10 features Response("070001", 0x0000, "8071"), # RGB_EFFECTS at 0x07 *effects_responses_2, Response("040001", 0x0000, "1C00"), # Persistent Remappable Actions at 0x04 *responses_remap, Response("080001", 0x0000, "6501"), # Gestures at 0x08 *adjust_responses_index(8, responses_gestures), Response("060003", 0x0000, "1982"), # Backlight 2 at 0x06 Response("010118000001020003000400", 0x0600), Response("090003", 0x0000, "8100"), # Onboard Profiles at 0x09 *responses_profiles, ] responses_speedchange = [ Response("0100", 0x0400), Response("010001", 0x0000, "0001"), # FEATURE SET at x01 Response("0A", 0x0100), # 10 features Response("0120", 0x0410, "0120"), Response("050001", 0x0000, "1B04"), # REPROG_CONTROLS_V4 Response("01", 0x0500), Response("00ED009D310003070500000000000000", 0x0510, "00"), # DPI Change Response("00ED0000000000000000000000000000", 0x0520, "00ED"), # DPI Change current Response("060000", 0x0000, "2205"), # POINTER_SPEED ] # A fake device that uses provided data (responses) to respond to HID++ commands. # Some methods from the real device are used to set up data structures needed for settings @dataclass class Device: name: str = "TESTD" online: bool = True protocol: float = 2.0 responses: Any = field(default_factory=list) codename: str = "TESTC" feature: Optional[int] = None offset: Optional[int] = 4 version: Optional[int] = 0 wpid: Optional[str] = "0000" setting_callback: Any = None centurion: bool = False path = None cleanups = None sliding = profiles = _backlight = _keys = _remap_keys = _led_effects = _gestures = None _gestures_lock = threading.Lock() number = "d1" present = True read_register = device.Device.read_register write_register = device.Device.write_register backlight = device.Device.backlight keys = device.Device.keys remap_keys = device.Device.remap_keys led_effects = device.Device.led_effects gestures = device.Device.gestures __hash__ = device.Device.__hash__ feature_request = device.Device.feature_request def __post_init__(self): self._name = self.name self._protocol = self.protocol self.persister = configuration._DeviceEntry() self.features = hidpp20.FeaturesArray(self) self.settings = [] self.cleanups = [] self.receiver = [] if self.feature is not None: self.features = hidpp20.FeaturesArray(self) self.responses = [ Response("010001", 0x0000, "0001"), Response("20", 0x0100), ] + self.responses self.responses.append( Response( f"{int(self.offset):0>2X}00{int(self.version):0>2X}", 0x0000, f"{int(self.feature):0>4X}", ) ) if self.setting_callback is None: self.setting_callback = lambda x, y, z: None self.add_notification_handler = lambda x, y: None # Centurion bridge responses: keyed by (sub_feat_idx, sub_function) -> response bytes if not hasattr(self, "_bridge_responses"): self._bridge_responses = {} def request(self, id, *params, no_reply=False, long_message=False, protocol=2.0): params = b"".join(pack("B", p) if isinstance(p, int) else p for p in params) print("REQUEST ", self._name, hex(id), params.hex().upper()) for r in self.responses: if id == r.id and params == bytes.fromhex(r.params): print("RESPONSE", self._name, hex(r.id), r.params, r.response) return bytes.fromhex(r.response) if isinstance(r.response, str) else r.response print("RESPONSE", self._name, None) def centurion_bridge_request(self, sub_feat_idx, sub_function=0x00, *params, no_reply=False): """Fake bridge request — looks up (sub_feat_idx, sub_function, params) in _bridge_responses.""" params_bytes = b"".join(pack("B", p) if isinstance(p, int) else p for p in params) if params else b"" key = (sub_feat_idx, sub_function, params_bytes.hex().upper()) print("BRIDGE ", self._name, f"sub_idx={sub_feat_idx} func={sub_function} params={params_bytes.hex().upper()}") result = self._bridge_responses.get(key) if result is not None: print("BRIDGE_R", self._name, result.hex().upper()) return result # Try without params for convenience key_no_params = (sub_feat_idx, sub_function, "") result = self._bridge_responses.get(key_no_params) if result is not None: print("BRIDGE_R", self._name, result.hex().upper()) return result print("BRIDGE_R", self._name, None) return None def ping(self, handle=None, devnumber=None, long_message=False): print("PING", self._protocol) return self._protocol def handle_notification(self, handle): pass def changed(self, *args, **kwargs): pass def set_battery_info(self, *args, **kwargs): pass def status_string(self): pass # Centurion headset (PRO X 2 LIGHTSPEED) parent device responses. # Parent has 5 features: ROOT(0), FeatureSet(1), DeviceInfo(2), CentPPBridge(3), GenericDFU(4) # Feature 0x0003 on Centurion = CentPPBridge (NOT FirmwareInfo). r_centurion_headset = [ Response(2.6, 0x0010), # ping (protocol 2.6) Response("010001", 0x0000, "0001"), # FeatureSet at index 1 Response("020001", 0x0000, "0100"), # DeviceInfo at index 2 Response("030001", 0x0000, "0003"), # CentPPBridge at index 3 Response("040001", 0x0000, "010A"), # GenericDFU at index 4 Response("05", 0x0100), # feature count = 5 (includes ROOT on Centurion) # FeatureSet.getFeatureID responses: [remaining_count, feat_hi, feat_lo, type, flags] Response("0400000000", 0x0110, "00"), # index 0: ROOT (0x0000) Response("0300010001", 0x0110, "01"), # index 1: FeatureSet (0x0001) Response("0201000001", 0x0110, "02"), # index 2: DeviceInfo (0x0100) Response("0100030001", 0x0110, "03"), # index 3: CentPPBridge (0x0003) Response("00010A0001", 0x0110, "04"), # index 4: GenericDFU (0x010A) ] def match_requests(number, responses, call_args_list): for i in range(0 - number, 0): param = b"".join(pack("B", p) if isinstance(p, int) else p for p in call_args_list[i][0][1:]).hex().upper() print("MATCH", i, hex(call_args_list[i][0][0]), param, hex(responses[i].id), responses[i].params) assert call_args_list[i][0][0] == responses[i].id assert param == responses[i].params Solaar-1.1.20/tests/logitech_receiver/test_base.py000066400000000000000000000412031522022367600221700ustar00rootroot00000000000000import struct import sys from typing import Union from unittest import mock import pytest from logitech_receiver import base from logitech_receiver import exceptions from logitech_receiver.base import CENTURION_ADDRESSED_REPORT_ID from logitech_receiver.base import CENTURION_REPORT_ID from logitech_receiver.base import HIDPP_SHORT_MESSAGE_ID from logitech_receiver.base import CenturionHandleState from logitech_receiver.common import LOGITECH_VENDOR_ID from logitech_receiver.common import BusID from logitech_receiver.hidpp10_constants import ErrorCode as Hidpp10Error from logitech_receiver.hidpp20_constants import ErrorCode as Hidpp20Error @pytest.mark.parametrize( "usb_id, expected_name, expected_receiver_kind", [ (0xC548, "Bolt Receiver", "bolt"), (0xC52B, "Unifying Receiver", "unifying"), (0xC531, "Nano Receiver", "nano"), (0xC53F, "Lightspeed Receiver", None), (0xC517, "EX100 Receiver 27 Mhz", "27Mhz"), ], ) def test_product_information(usb_id, expected_name, expected_receiver_kind): res = base.product_information(usb_id) assert res["name"] == expected_name assert isinstance(res["vendor_id"], int) assert isinstance(res["product_id"], int) if expected_receiver_kind: assert res["receiver_kind"] == expected_receiver_kind def test_filter_receivers_known(): bus_id = 2 product_id = 0xC548 receiver_info = base.get_known_receiver_info(bus_id, LOGITECH_VENDOR_ID, product_id) assert receiver_info["name"] == "Bolt Receiver" assert receiver_info["receiver_kind"] == "bolt" def test_filter_receivers_unknown(): bus_id = 1 product_id = 0xC500 receiver_info = base.get_known_receiver_info(bus_id, LOGITECH_VENDOR_ID, product_id) assert receiver_info["bus_id"] == bus_id assert receiver_info["product_id"] == product_id @pytest.mark.parametrize( "product_id, bus, hidpp_short, hidpp_long, expected", [ (0xC548, BusID.USB, True, False, {"name": "Bolt Receiver", "usb_interface": 2}), (0xC07D, BusID.USB, True, False, {"usb_interface": 1}), (0xC07E, BusID.USB, False, True, {"usb_interface": 1}), (0xC07E, BusID.BLUETOOTH, False, True, {"bus_id": 5}), (0xA07E, BusID.USB, False, True, {"product_id": 0xA07E}), (0xA07C, BusID.USB, False, False, None), (0xC07F, BusID.USB, None, None, {"usb_interface": 2}), (0xC07F, BusID.BLUETOOTH, None, None, None), (0xB013, BusID.BLUETOOTH, None, None, {"product_id": 0xB013}), ], ) def test_filter_products_of_interest(product_id, bus, hidpp_short, hidpp_long, expected): receiver_info = base.filter_products_of_interest( bus, LOGITECH_VENDOR_ID, product_id, hidpp_short=hidpp_short, hidpp_long=hidpp_long, ) if expected is None: assert receiver_info == expected else: assert all([receiver_info[key] == expected_value for key, expected_value in expected.items()]) assert receiver_info["vendor_id"] == LOGITECH_VENDOR_ID assert receiver_info["product_id"] def test_match(): record = {"vendor_id": LOGITECH_VENDOR_ID} res = base._match_device(record, 0, LOGITECH_VENDOR_ID, 0) assert res is True @pytest.mark.parametrize( "report_id, sub_id, address, valid_notification", [ (0x1, 0x72, 0x57, True), (0x1, 0x40, 0x63, True), (0x1, 0x40, 0x71, True), (0x1, 0x80, 0x71, False), (0x1, 0x00, 0x70, False), (0x20, 0x09, 0x71, False), (0x1, 0x37, 0x71, False), ], ) def test_make_notification(report_id, sub_id, address, valid_notification): devnumber = 123 data = bytes([sub_id, address, 0x02, 0x03, 0x04]) result = base.make_notification(report_id, devnumber, data) if valid_notification: assert isinstance(result, base.HIDPPNotification) assert result.report_id == report_id assert result.devnumber == devnumber assert result.sub_id == sub_id assert result.address == address assert result.data == bytes([0x02, 0x03, 0x04]) else: assert result is None def test_get_next_sw_id(): assert base._get_next_sw_id() == base.SOLAAR_SOFTWARE_ID assert base._get_next_sw_id() == base.SOLAAR_SOFTWARE_ID @pytest.mark.parametrize( "prefix, error_code, return_error, raise_exception", [ (b"\x8f", Hidpp10Error.INVALID_SUB_ID_COMMAND, False, False), (b"\x8f", Hidpp10Error.INVALID_SUB_ID_COMMAND, True, False), (b"\xff", Hidpp20Error.UNKNOWN, False, True), ], ) def test_request_errors( prefix: bytes, error_code: Union[Hidpp10Error, Hidpp20Error], return_error: bool, raise_exception: bool ): handle = 0 device_number = 66 next_sw_id = 0x02 reply_data_sw_id = struct.pack("!H", 0x0000 | next_sw_id) with mock.patch( "logitech_receiver.base._read", return_value=(HIDPP_SHORT_MESSAGE_ID, device_number, prefix + reply_data_sw_id + struct.pack("B", error_code)), ), mock.patch("logitech_receiver.base._read_input_buffer"), mock.patch( "logitech_receiver.base.write", return_value=None ), mock.patch("logitech_receiver.base._get_next_sw_id", return_value=next_sw_id): if raise_exception: with pytest.raises(exceptions.FeatureCallError) as context: base.request(handle, device_number, next_sw_id, return_error=return_error) assert context.value.number == device_number assert context.value.request == next_sw_id assert context.value.error == error_code assert context.value.params == b"" else: result = base.request(handle, device_number, next_sw_id, return_error=return_error) assert result == (error_code if return_error else None) @pytest.mark.skipif(sys.platform == "darwin", reason="Test only runs on Linux") @pytest.mark.parametrize( "simulated_error, expected_result", [ (Hidpp10Error.INVALID_SUB_ID_COMMAND, 1.0), (Hidpp10Error.RESOURCE_ERROR, None), (Hidpp10Error.CONNECTION_REQUEST_FAILED, None), (Hidpp10Error.UNKNOWN_DEVICE, exceptions.NoSuchDevice), ], ) def test_ping_errors(simulated_error: Hidpp10Error, expected_result): handle = 1 device_number = 1 next_sw_id = 0x05 reply_data_sw_id = struct.pack("!H", 0x0010 | next_sw_id) with mock.patch( "logitech_receiver.base._read", return_value=(HIDPP_SHORT_MESSAGE_ID, device_number, b"\x8f" + reply_data_sw_id + bytes([simulated_error])), ), mock.patch("logitech_receiver.base._read_input_buffer"), mock.patch( "logitech_receiver.base.write", return_value=None ), mock.patch("logitech_receiver.base._get_next_sw_id", return_value=next_sw_id): if isinstance(expected_result, type) and issubclass(expected_result, Exception): with pytest.raises(expected_result) as context: base.ping(handle=handle, devnumber=device_number) assert context.value.number == device_number assert context.value.request == struct.unpack("!H", reply_data_sw_id)[0] else: result = base.ping(handle=handle, devnumber=device_number) assert result == expected_result # --- Centurion transport tests --- class TestCenturionFrameHeader: """Test _centurion_frame_header builds correct headers for both variants.""" def test_0x51_header(self): state = CenturionHandleState(report_id=CENTURION_REPORT_ID) header = base._centurion_frame_header(state, cpl_length=5, flags=0x00) assert header == bytes([0x51, 5, 0x00]) def test_0x51_header_with_flags(self): state = CenturionHandleState(report_id=CENTURION_REPORT_ID) header = base._centurion_frame_header(state, cpl_length=10, flags=0x03) assert header == bytes([0x51, 10, 0x03]) def test_0x50_header_unknown_addr(self): state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID, device_addr=None) header = base._centurion_frame_header(state, cpl_length=5, flags=0x00) # device_addr defaults to 0x00 when unknown assert header == bytes([0x50, 0x00, 5, 0x00]) def test_0x50_header_known_addr(self): state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID, device_addr=0x23) header = base._centurion_frame_header(state, cpl_length=5, flags=0x00) assert header == bytes([0x50, 0x23, 5, 0x00]) def test_0x50_header_with_flags(self): state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID, device_addr=0x23) header = base._centurion_frame_header(state, cpl_length=10, flags=0x07) assert header == bytes([0x50, 0x23, 10, 0x07]) class TestUnwrapCenturionFrame: """Test _unwrap_centurion_frame for both 0x51 and 0x50 variants.""" HANDLE = 99 def setup_method(self): """Ensure no leftover centurion state between tests.""" base._centurion_handles.pop(self.HANDLE, None) def teardown_method(self): base._centurion_handles.pop(self.HANDLE, None) def test_unwrap_0x51_frame(self): """0x51 frame with feat_idx=0x02, func_sw=0x1A, 2 data bytes.""" # cpl_length = 1(flags) + 1(feat_idx) + 1(func_sw) + 2(data) = 5 raw = bytes([0x51, 5, 0x00, 0x02, 0x1A, 0xAA, 0xBB]) + b"\x00" * 57 result = base._unwrap_centurion_frame(raw, self.HANDLE, self.HANDLE) # Should reconstruct as [0x11, 0xFF, feat_idx, func_sw, data..., pad to 20] assert result[0] == 0x11 assert result[1] == 0xFF assert result[2] == 0x02 # feat_idx assert result[3] == 0x1A # func_sw assert result[4] == 0xAA assert result[5] == 0xBB assert len(result) == 20 # padded to standard long def test_unwrap_0x50_frame(self): """0x50 frame with device_addr=0x23, same payload as above.""" # Frame: [0x50, device_addr, cpl_length, flags, feat_idx, func_sw, data...] raw = bytes([0x50, 0x23, 5, 0x00, 0x02, 0x1A, 0xAA, 0xBB]) + b"\x00" * 56 base._centurion_handles[self.HANDLE] = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID) result = base._unwrap_centurion_frame(raw, self.HANDLE, self.HANDLE) assert result[0] == 0x11 assert result[1] == 0xFF assert result[2] == 0x02 # feat_idx assert result[3] == 0x1A # func_sw assert result[4] == 0xAA assert result[5] == 0xBB assert len(result) == 20 def test_0x50_learns_device_addr(self): """First RX on a 0x50 handle should learn the device address.""" base._centurion_handles[self.HANDLE] = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID) assert base._centurion_handles[self.HANDLE].device_addr is None raw = bytes([0x50, 0x23, 3, 0x00, 0x02, 0x1A]) + b"\x00" * 58 base._unwrap_centurion_frame(raw, self.HANDLE, self.HANDLE) assert base._centurion_handles[self.HANDLE].device_addr == 0x23 def test_0x50_does_not_overwrite_addr(self): """Once learned, device address should not be overwritten.""" base._centurion_handles[self.HANDLE] = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID, device_addr=0x23) raw = bytes([0x50, 0xFF, 3, 0x00, 0x02, 0x1A]) + b"\x00" * 58 base._unwrap_centurion_frame(raw, self.HANDLE, self.HANDLE) # Should keep the original address, not overwrite with 0xFF assert base._centurion_handles[self.HANDLE].device_addr == 0x23 def test_non_centurion_frame_passthrough(self): """Non-centurion report IDs should be returned unchanged.""" raw = bytes([0x11, 0x01, 0x02, 0x1A]) + b"\x00" * 16 result = base._unwrap_centurion_frame(raw, self.HANDLE, self.HANDLE) assert result == raw def test_unwrap_0x51_large_payload(self): """0x51 frame with payload large enough to need 63-byte padding.""" # cpl_length covers all 61 payload bytes + flags = 62 payload = bytes(range(61)) raw = bytes([0x51, 62, 0x00]) + payload result = base._unwrap_centurion_frame(raw, self.HANDLE, self.HANDLE) assert len(result) == 63 # padded to centurion extended assert result[0] == 0x11 assert result[1] == 0xFF assert result[2:63] == payload class TestProbeCenturionDeviceAddr: """Test probe_centurion_device_addr: brute-force write for all 256 addrs, then read.""" HANDLE = 101 def setup_method(self): base._centurion_handles.pop(self.HANDLE, None) def teardown_method(self): base._centurion_handles.pop(self.HANDLE, None) def test_learns_addr_on_first_hit(self): """Probe finds addr=0x23 on candidate #36 (0-indexed 0x23=35) and stops.""" state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID) reply = bytes([0x50, 0x23, 0x03, 0x00]) + b"\x00" * 60 def read_side_effect(_handle, _size, _timeout): # Return a response only after the write with addr=0x23 if mock_write.call_count == 0x24: # 0x23 is the 36th write (1-indexed) return reply return None with ( mock.patch.object(base.hidapi, "write") as mock_write, mock.patch.object(base.hidapi, "read", side_effect=read_side_effect), ): result = base.probe_centurion_device_addr(self.HANDLE, state) assert result is True assert state.device_addr == 0x23 # Short-circuit: stopped at candidate 0x23 (36 writes), not all 256 assert mock_write.call_count == 0x24 def test_skips_non_matching_read_until_match(self): """Non-0x50 frames in the read are ignored; next candidate's read succeeds.""" state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID) noise = b"\x11\xff" + b"\x00" * 62 match = bytes([0x50, 0x42, 0x03, 0x00]) + b"\x00" * 60 # Reads cycle: noise, noise, match — so addr is found on 3rd candidate with ( mock.patch.object(base.hidapi, "write"), mock.patch.object(base.hidapi, "read", side_effect=[noise, noise, match]), ): result = base.probe_centurion_device_addr(self.HANDLE, state) assert result is True assert state.device_addr == 0x42 def test_returns_false_when_no_response(self): state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID) with ( mock.patch.object(base.hidapi, "write"), mock.patch.object(base.hidapi, "read", return_value=None), ): result = base.probe_centurion_device_addr(self.HANDLE, state) assert result is False assert state.device_addr is None def test_noop_for_0x51_variant(self): state = CenturionHandleState(report_id=CENTURION_REPORT_ID) with ( mock.patch.object(base.hidapi, "write") as mock_write, mock.patch.object(base.hidapi, "read") as mock_read, ): result = base.probe_centurion_device_addr(self.HANDLE, state) assert result is False assert state.device_addr is None mock_write.assert_not_called() mock_read.assert_not_called() def test_noop_when_addr_already_known(self): state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID, device_addr=0x23) with ( mock.patch.object(base.hidapi, "write") as mock_write, mock.patch.object(base.hidapi, "read") as mock_read, ): result = base.probe_centurion_device_addr(self.HANDLE, state) assert result is False assert state.device_addr == 0x23 mock_write.assert_not_called() mock_read.assert_not_called() def test_aborts_on_repeated_write_failure(self): state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID) with ( mock.patch.object(base.hidapi, "write", side_effect=OSError("no device")), mock.patch.object(base.hidapi, "read") as mock_read, ): result = base.probe_centurion_device_addr(self.HANDLE, state) assert result is False assert state.device_addr is None mock_read.assert_not_called() def test_write_frames_have_sequential_addrs(self): """Verify each write uses a different device_addr from 0x00 to 0xFF.""" state = CenturionHandleState(report_id=CENTURION_ADDRESSED_REPORT_ID) with ( mock.patch.object(base.hidapi, "write") as mock_write, mock.patch.object(base.hidapi, "read", return_value=None), # no response → scans all 256 ): base.probe_centurion_device_addr(self.HANDLE, state) assert mock_write.call_count == 256 addrs_sent = [mock_write.call_args_list[i][0][1][1] for i in range(256)] assert addrs_sent == list(range(256)) Solaar-1.1.20/tests/logitech_receiver/test_base_usb.py000066400000000000000000000013561522022367600230460ustar00rootroot00000000000000import pytest from logitech_receiver import base_usb from logitech_receiver.common import LOGITECH_VENDOR_ID def test_ensure_known_receivers_mappings_are_valid(): for key, receiver in base_usb.KNOWN_RECEIVERS.items(): assert key == receiver["product_id"] def test_get_receiver_info(): expected = { "vendor_id": LOGITECH_VENDOR_ID, "product_id": 0xC548, "usb_interface": 2, "name": "Bolt Receiver", "receiver_kind": "bolt", "max_devices": 6, "may_unpair": True, } res = base_usb.get_receiver_info(0xC548) assert res == expected def test_get_receiver_info_unknown_device_fails(): with pytest.raises(ValueError): base_usb.get_receiver_info(0xC500) Solaar-1.1.20/tests/logitech_receiver/test_common.py000066400000000000000000000234201522022367600225470ustar00rootroot00000000000000from enum import IntFlag import pytest import yaml from logitech_receiver import common def test_crc16(): value = b"123456789" expected = 0x29B1 result = common.crc16(value) assert result == expected def test_named_int(): named_int = common.NamedInt(0x2, "pulse") assert named_int.name == "pulse" assert named_int == 2 assert repr(named_int) == "NamedInt(2, 'pulse')" def test_named_int_comparison(): named_int = common.NamedInt(0, "entry") named_int_equal = common.NamedInt(0, "entry") named_int_unequal_name = common.NamedInt(0, "unequal") named_int_unequal_value = common.NamedInt(5, "entry") named_int_unequal = common.NamedInt(2, "unequal") assert named_int == named_int_equal assert named_int != named_int_unequal_name assert named_int != named_int_unequal_value assert named_int != named_int_unequal assert named_int is not None assert named_int == 0 assert named_int == "entry" def test_named_int_comparison_exception(): named_int = common.NamedInt(0, "entry") with pytest.raises(TypeError): assert named_int == b"\x00" def test_named_int_conversions(): named_int = common.NamedInt(2, "two") assert named_int.bytes() == b"\x00\x02" assert str(named_int) == "two" def test_named_int_yaml(): named_int = common.NamedInt(2, "two") yaml_string = yaml.dump(named_int) # assert yaml_string == "!NamedInt {name: two, value: 2}\n" yaml_load = yaml.safe_load(yaml_string) assert yaml_load == named_int def test_color_int_str_and_repr(): c = common.ColorInt(0xFC3300) assert str(c) == "0xfc3300" assert repr(c) == "0xfc3300" assert int(c) == 0xFC3300 def test_color_int_equality_with_plain_int(): assert common.ColorInt(0xFC3300) == 0xFC3300 assert isinstance(common.ColorInt(0), int) def test_color_int_from_hex_string_prefixes(): assert common.ColorInt("0xfc3300") == 0xFC3300 assert common.ColorInt("0XFC3300") == 0xFC3300 assert common.ColorInt("#fc3300") == 0xFC3300 def test_color_int_from_int_passes_through(): assert common.ColorInt(0) == 0 assert common.ColorInt(0xFFFFFF) == 0xFFFFFF def test_color_int_out_of_range_falls_back_to_decimal(): # Sentinel values like COLORSPLUS["No change"] = -1 should still render # in their natural form when wrapped (though they normally aren't). assert str(common.ColorInt(-1)) == "-1" def test_color_int_yaml_dumps_as_hex_int_literal(): c = common.ColorInt(0xFC3300) dumped = yaml.dump(c).strip() assert dumped == "0xfc3300\n..." or dumped.startswith("0xfc3300") def test_color_int_yaml_roundtrips_to_plain_int(): # yaml.safe_load returns a plain int (yaml 1.1 hex literal parsing). # The value matches; type promotion to ColorInt happens lazily at # validator/setting boundaries. c = common.ColorInt(0xFC3300) loaded = yaml.safe_load(yaml.dump(c)) assert loaded == 0xFC3300 def test_color_int_in_dict_yaml_dumps_each_value_as_hex(): data = {1: common.ColorInt(0xFC3300), 2: common.ColorInt(0x00FF00), 3: -1} dumped = yaml.dump(data, default_flow_style=None, width=150).strip() assert "0xfc3300" in dumped assert "0x00ff00" in dumped assert "-1" in dumped # sentinel preserved def test_named_ints(): named_ints = common.NamedInts(empty=0, critical=5, low=20, good=50, full=90) assert named_ints.empty == 0 assert named_ints.empty.name == "empty" assert named_ints.critical == 5 assert named_ints.critical.name == "critical" assert named_ints.low == 20 assert named_ints.low.name == "low" assert named_ints.good == 50 assert named_ints.good.name == "good" assert named_ints.full == 90 assert named_ints.full.name == "full" assert len(named_ints) == 5 assert 5 in named_ints assert 6 not in named_ints assert "critical" in named_ints assert "easy" not in named_ints assert common.NamedInt(5, "critical") in named_ints assert common.NamedInt(5, "five") not in named_ints assert common.NamedInt(6, "critical") not in named_ints assert named_ints[5] == "critical" assert named_ints["critical"] == "critical" assert named_ints[66] is None assert named_ints["5"] is None assert len(named_ints[:]) == len(named_ints) assert len(named_ints[0:100]) == len(named_ints) assert len(named_ints[5:90]) == 3 assert len(named_ints[5:]) == 4 assert named_ints[90:5] == [] def test_named_ints_fallback(): named_ints = common.NamedInts(empty=0, critical=5, low=20, good=50, full=90) named_ints._fallback = lambda x: str(x) fallback = named_ints[80] assert fallback == common.NamedInt(80, "80") def test_named_ints_list(): named_ints_list = common.NamedInts.list([0, 5, 20, 50, 90]) assert len(named_ints_list) == 5 assert 50 in named_ints_list assert 60 not in named_ints_list def test_named_ints_range(): named_ints_range = common.NamedInts.range(0, 5) assert len(named_ints_range) == 6 assert 4 in named_ints_range assert 6 not in named_ints_range @pytest.mark.parametrize( "code, expected_flags", [ (0, []), (0b0010, ["two"]), (0b0101, ["one", "three"]), (0b1001, ["one", "unknown:000008"]), ], ) def test_named_ints_flag_names(code, expected_flags): named_ints_flag_bits = common.NamedInts(one=0b001, two=0b010, three=0b100) flags = list(named_ints_flag_bits.flag_names(code)) assert flags == expected_flags @pytest.mark.parametrize( "code, expected_flags", [ (0, []), (0b0010, ["two"]), (0b0101, ["one", "three"]), (0b1001, ["one", "unknown:000008"]), ], ) def test_flag_names(code, expected_flags): class ExampleFlag(IntFlag): one = 0x1 two = 0x2 three = 0x4 flags = common.flag_names(ExampleFlag, code) assert list(flags) == expected_flags def test_named_ints_setitem(): named_ints = common.NamedInts(empty=0, critical=5, low=20, good=50, full=90) named_ints[55] = "better" named_ints[60] = common.NamedInt(60, "sixty") with pytest.raises(TypeError): named_ints[70] = 70 with pytest.raises(ValueError): named_ints[70] = "empty" with pytest.raises(ValueError): named_ints[50] = "new" assert named_ints[55] == "better" assert named_ints[60] == "sixty" def test_named_ints_other(): named_ints = common.NamedInts(empty=0, critical=5) named_ints_2 = common.NamedInts(good=50) union = named_ints.__or__(named_ints_2) assert list(named_ints) == [common.NamedInt(0, "empty"), common.NamedInt(5, "critical")] assert len(named_ints) == 2 assert repr(named_ints) == "NamedInts(NamedInt(0, 'empty'), NamedInt(5, 'critical'))" assert len(union) == 3 assert list(union) == [common.NamedInt(0, "empty"), common.NamedInt(5, "critical"), common.NamedInt(50, "good")] def test_unsorted_named_ints(): named_ints = common.UnsortedNamedInts(critical=5, empty=0) named_ints_2 = common.UnsortedNamedInts(good=50) union = named_ints.__or__(named_ints_2) unionr = named_ints_2.__or__(named_ints) assert len(union) == 3 assert list(union) == [common.NamedInt(5, "critical"), common.NamedInt(0, "empty"), common.NamedInt(50, "good")] assert len(unionr) == 3 assert list(unionr) == [common.NamedInt(50, "good"), common.NamedInt(5, "critical"), common.NamedInt(0, "empty")] @pytest.mark.parametrize( "bytes_input, expected_output", [ (b"\x01\x02\x03\x04", "01020304"), (b"", ""), ], ) def test_strhex(bytes_input, expected_output): result = common.strhex(bytes_input) assert result == expected_output def test_bytest2int(): value = b"\x12\x34\x56\x78" expected = 0x12345678 result = common.bytes2int(value) assert result == expected def test_int2bytes(): value = 0x12345678 expected = b"\x12\x34\x56\x78" result = common.int2bytes(value) assert result == expected def test_kw_exception(): e = common.KwException(foo=0, bar="bar") assert e.foo == 0 assert e.bar == "bar" @pytest.mark.parametrize( "status, expected_level, expected_ok, expected_charging, expected_string", [ (common.BatteryStatus.FULL, common.BatteryLevelApproximation.FULL, True, True, "Battery: full (full)"), (common.BatteryStatus.ALMOST_FULL, common.BatteryLevelApproximation.GOOD, True, True, "Battery: good (almost full)"), (common.BatteryStatus.RECHARGING, common.BatteryLevelApproximation.GOOD, True, True, "Battery: good (recharging)"), ( common.BatteryStatus.SLOW_RECHARGE, common.BatteryLevelApproximation.LOW, True, True, "Battery: low (slow recharge)", ), (common.BatteryStatus.DISCHARGING, None, True, False, ""), (common.BatteryStatus.OFFLINE, None, True, False, ""), ], ) def test_battery(status, expected_level, expected_ok, expected_charging, expected_string): battery = common.Battery(None, None, status, None) assert battery.status == status assert battery.level == expected_level assert battery.ok() == expected_ok assert battery.charging() == expected_charging assert battery.to_str() == expected_string def test_battery_2(): battery = common.Battery(50, None, common.BatteryStatus.DISCHARGING, None) assert battery.status == common.BatteryStatus.DISCHARGING assert battery.level == 50 assert battery.ok() assert not battery.charging() assert battery.to_str() == "Battery: 50% (discharging)" def test_battery_offline(): battery = common.Battery(58, None, common.BatteryStatus.OFFLINE, None) assert battery.status == common.BatteryStatus.OFFLINE assert battery.level == 58 assert battery.ok() assert not battery.charging() assert battery.to_str() == "Battery: 58% (offline)" Solaar-1.1.20/tests/logitech_receiver/test_desktop_notifications.py000066400000000000000000000015351522022367600256640ustar00rootroot00000000000000from unittest import mock from logitech_receiver import desktop_notifications # The mock_desktop_notifications autouse fixture (tests/conftest.py) swaps the # libnotify backend for a mock, so these exercise the real code paths without # raising real desktop notifications. def test_init(): result = desktop_notifications.init() assert result == desktop_notifications.available def test_uninit(): assert desktop_notifications.uninit() is None class MockDevice(mock.Mock): name = "MockDevice" def close(): return True def test_show(mock_desktop_notifications): result = desktop_notifications.show(MockDevice(), "unknown") if desktop_notifications.available: assert result is not None mock_desktop_notifications.Notification.return_value.show.assert_called() else: assert result is None Solaar-1.1.20/tests/logitech_receiver/test_device.py000066400000000000000000000405541522022367600225250ustar00rootroot00000000000000## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. from dataclasses import dataclass from functools import partial from typing import Optional from unittest import mock import pytest from logitech_receiver import common from logitech_receiver import device from logitech_receiver import hidpp20 from logitech_receiver.common import BatteryLevelApproximation from logitech_receiver.common import BatteryStatus from . import fake_hidpp class LowLevelInterfaceFake: def __init__(self, responses=None): self.responses = responses def open_path(self, path) -> int: return fake_hidpp.open_path(path) def find_paired_node(self, receiver_path: str, index: int, timeout: int): return None def request(self, response, *args, **kwargs): func = partial(fake_hidpp.request, self.responses) return func(response, *args, **kwargs) def ping(self, response, *args, **kwargs): func = partial(fake_hidpp.ping, self.responses) return func(response, *args, **kwargs) def close(self, *args, **kwargs): pass @dataclass class DeviceInfoStub: path: str product_id: str vendor_id: int = 1133 hidpp_short: bool = False hidpp_long: bool = True bus_id: int = 0x0003 # USB serial: str = "aa:aa:aa;aa" centurion: bool = False centurion_report_id: int | None = None di_bad_handle = DeviceInfoStub(None, product_id="CCCC") di_error = DeviceInfoStub(11, product_id="CCCC") di_CCCC = DeviceInfoStub("11", product_id="CCCC") di_C318 = DeviceInfoStub("11", product_id="C318") di_B530 = DeviceInfoStub("11", product_id="B350", bus_id=0x0005) di_C068 = DeviceInfoStub("11", product_id="C06B") di_C08A = DeviceInfoStub("11", product_id="C08A") di_DDDD = DeviceInfoStub("11", product_id="DDDD") di_0AF7 = DeviceInfoStub("11", product_id="0AF7", centurion=True) @pytest.mark.parametrize( "device_info, responses, expected_success", [ (di_bad_handle, fake_hidpp.r_empty, None), (di_error, fake_hidpp.r_empty, False), (di_CCCC, fake_hidpp.r_empty, True), (di_0AF7, fake_hidpp.r_empty, True), ], ) def test_create_device(device_info, responses, expected_success): low_level_mock = LowLevelInterfaceFake(responses) if expected_success is None: with pytest.raises(PermissionError): device.create_device(low_level_mock, device_info) elif not expected_success: with pytest.raises(Exception): # noqa: B017 device.create_device(low_level_mock, device_info) else: test_device = device.create_device(low_level_mock, device_info) assert bool(test_device) == expected_success def test_create_centurion_device(): """Test that a centurion device gets hidpp_long forced to True and centurion flag set.""" from logitech_receiver import base with mock.patch.object(base, "probe_centurion_device_addr", return_value=False): low_level_mock = LowLevelInterfaceFake(fake_hidpp.r_empty) test_device = device.create_device(low_level_mock, di_0AF7) assert test_device is not None assert test_device.centurion is True assert test_device.hidpp_long is True assert int(test_device.handle) in base._centurion_handles state = base._centurion_handles[int(test_device.handle)] assert state.report_id == base.CENTURION_REPORT_ID # 0x51 default # kind is seeded at construction, so the headset icon shows even offline test_device.online = False assert test_device.kind == "headset" # Clean up base._centurion_handles.pop(int(test_device.handle), None) di_0B18 = DeviceInfoStub("11", product_id="0B18", centurion=True, centurion_report_id=0x50) def test_create_centurion_0x50_device(): """Test that a 0x50 centurion device gets the correct report ID registered.""" from logitech_receiver import base with mock.patch.object(base, "probe_centurion_device_addr", return_value=False): low_level_mock = LowLevelInterfaceFake(fake_hidpp.r_empty) test_device = device.create_device(low_level_mock, di_0B18) assert test_device is not None assert test_device.centurion is True assert test_device.hidpp_long is True assert int(test_device.handle) in base._centurion_handles state = base._centurion_handles[int(test_device.handle)] assert state.report_id == base.CENTURION_ADDRESSED_REPORT_ID # 0x50 assert state.device_addr is None # not yet learned # Clean up base._centurion_handles.pop(int(test_device.handle), None) @pytest.mark.parametrize( "device_info, responses, expected_codename, expected_name, expected_kind", [(di_CCCC, fake_hidpp.r_empty, "?? (CCCC)", "Unknown device CCCC", "?")], ) def test_device_name(device_info, responses, expected_codename, expected_name, expected_kind): low_level = LowLevelInterfaceFake(responses) test_device = device.create_device(low_level, device_info) assert test_device.codename == expected_codename assert test_device.name == expected_name assert test_device.kind == expected_kind def test_codename_uses_full_name(): """A direct-connected HID++ 2.0 device with no friendly name uses its full live name as the codename instead of truncating it at the first space.""" test_device = device.create_device(LowLevelInterfaceFake(fake_hidpp.r_empty), di_CCCC) test_device._protocol = 2.0 test_device.online = True test_device._codename = None test_device._name = "G502 X PLUS" assert test_device.codename == "G502 X PLUS" # a leading "Logitech" is still dropped test_device._codename = None test_device._name = "Logitech MX Master 3" assert test_device.codename == "MX Master 3" @pytest.mark.parametrize( "device_info, responses, handle, _name, _codename, number, protocol, registers", zip( [di_CCCC, di_C318, di_B530, di_C068, di_C08A, di_DDDD], [ fake_hidpp.r_empty, fake_hidpp.r_keyboard_1, fake_hidpp.r_keyboard_2, fake_hidpp.r_mouse_1, fake_hidpp.r_mouse_2, fake_hidpp.r_mouse_3, ], [0x11, 0x11, 0x11, 0x11, 0x11, 0x11], [None, "Illuminated Keyboard", "Craft Advanced Keyboard", "G700 Gaming Mouse", "MX Vertical Wireless Mouse", None], [None, "Illuminated", "Craft", "G700", "MX Vertical", None], [0xFF, 0x0, 0xFF, 0x0, 0xFF, 0xFF], [1.0, 1.0, 4.5, 1.0, 4.5, 4.5], [[], [], [], (common.NamedInt(7, "battery status"), common.NamedInt(81, "three leds")), [], []], ), ) def test_device_info(device_info, responses, handle, _name, _codename, number, protocol, registers): test_device = device.Device(LowLevelInterfaceFake(responses), None, None, None, handle=handle, device_info=device_info) assert test_device.handle == handle assert test_device._name == _name assert test_device._codename == _codename assert test_device.number == number assert test_device._protocol == protocol assert test_device.registers == registers assert bool(test_device) test_device.__del__() assert not bool(test_device) @dataclass class FakeReceiver: path: str = "11" handle: int = 0x11 codename: Optional[str] = None def device_codename(self, number): return self.codename def __contains__(self, dev): return True pi_CCCC = {"wpid": "CCCC", "kind": 0, "serial": None, "polling": "1ms", "power_switch": "top"} pi_2011 = {"wpid": "2011", "kind": 1, "serial": "1234", "polling": "2ms", "power_switch": "bottom"} pi_4066 = {"wpid": "4066", "kind": 1, "serial": "5678", "polling": "4ms", "power_switch": "left"} pi_1007 = {"wpid": "1007", "kind": 2, "serial": "1234", "polling": "8ms", "power_switch": "right"} pi_407B = {"wpid": "407B", "kind": 2, "serial": "5678", "polling": "1ms", "power_switch": "left"} pi_DDDD = {"wpid": "DDDD", "kind": 2, "serial": "1234", "polling": "2ms", "power_switch": "top"} @pytest.mark.parametrize( "number, pairing_info, responses, handle, _name, codename, p, p2, name", zip( range(1, 7), [pi_CCCC, pi_2011, pi_4066, pi_1007, pi_407B, pi_DDDD], [ fake_hidpp.r_empty, fake_hidpp.r_keyboard_1, fake_hidpp.r_keyboard_2, fake_hidpp.r_mouse_1, fake_hidpp.r_mouse_2, fake_hidpp.r_mouse_3, ], [0x11, 0x11, 0x11, 0x11, 0x11, 0x11], [None, "Wireless Keyboard K520", "Craft Advanced Keyboard", "MX Air", "MX Vertical Wireless Mouse", None], ["CODE", "K520", "Craft", "MX Air", "MX Vertical", "CODE"], [None, 1.0, 4.5, 1.0, 4.5, None], [1.0, 1.0, 4.5, 1.0, 4.5, 4.5], [ "CODE", "Wireless Keyboard K520", "Craft Advanced Keyboard", "MX Air", "MX Vertical Wireless Mouse", "ABABABABABABABADED", ], ), ) def test_device_receiver(number, pairing_info, responses, handle, _name, codename, p, p2, name): low_level = LowLevelInterfaceFake(responses) low_level.request = partial(fake_hidpp.request, fake_hidpp.replace_number(responses, number)) low_level.ping = partial(fake_hidpp.ping, fake_hidpp.replace_number(responses, number)) test_device = device.Device(low_level, FakeReceiver(codename="CODE"), number, True, pairing_info, handle=handle) test_device.receiver.device = test_device assert test_device.handle == handle assert test_device._name == _name assert test_device.codename == codename assert test_device.number == number assert test_device._protocol == p assert test_device.protocol == p2 assert test_device.codename == codename assert test_device.name == name assert test_device == test_device assert not (test_device != test_device) assert bool(test_device) test_device.__del__() @pytest.mark.parametrize( "number, info, responses, handle, unitId, modelId, task_id, kind, firmware, serial, id, psl, rate", zip( range(1, 7), [pi_CCCC, pi_2011, pi_4066, pi_1007, pi_407B, pi_DDDD], [ fake_hidpp.r_empty, fake_hidpp.r_keyboard_1, fake_hidpp.r_keyboard_2, fake_hidpp.r_mouse_1, fake_hidpp.r_mouse_2, fake_hidpp.r_mouse_3, ], [None, 0x11, 0x11, 0x11, 0x11, 0x11], [None, None, "12345678", None, None, "12345679"], # unitId [None, None, "1234567890AB", None, None, "123456780000"], # modelId [None, None, {"btid": "1234", "wpid": "5678", "usbid": "90AB"}, None, None, {"usbid": "1234"}], # tid_map ["?", 1, 1, 2, 2, 2], # kind [(), True, (), (), (), True], # firmware [None, "1234", "5678", "1234", "5678", "1234"], # serial ["", "1234", "12345678", "1234", "5678", "12345679"], # id ["top", "bottom", "left", "right", "left", "top"], # power switch location ["1ms", "2ms", "4ms", "8ms", "1ms", "9ms"], # polling rate ), ) def test_device_ids(number, info, responses, handle, unitId, modelId, task_id, kind, firmware, serial, id, psl, rate): low_level = LowLevelInterfaceFake(responses) low_level.request = partial(fake_hidpp.request, fake_hidpp.replace_number(responses, number)) low_level.ping = partial(fake_hidpp.ping, fake_hidpp.replace_number(responses, number)) test_device = device.Device(low_level, FakeReceiver(), number, True, info, handle=handle) assert test_device.unitId == unitId assert test_device.modelId == modelId assert test_device.tid_map == task_id assert test_device.kind == kind assert test_device.firmware == firmware or len(test_device.firmware) > 0 and firmware is True assert test_device.id == id assert test_device.power_switch_location == psl assert test_device.polling_rate == rate class FakeDevice(device.Device): # a fully functional Device but its HID++ functions look at local data def __init__(self, responses, *args, **kwargs): self.responses = responses super().__init__(LowLevelInterfaceFake(responses), *args, **kwargs) request = fake_hidpp.Device.request ping = fake_hidpp.Device.ping @pytest.mark.parametrize( "device_info, responses, protocol, led, keys, remap, gestures, backlight, profiles", [ (di_CCCC, fake_hidpp.r_empty, 1.0, type(None), None, None, None, None, None), (di_C318, fake_hidpp.r_empty, 1.0, type(None), None, None, None, None, None), (di_B530, fake_hidpp.r_keyboard_1, 1.0, type(None), None, None, None, None, None), (di_B530, fake_hidpp.r_keyboard_2, 2.0, type(None), 4, 0, 0, None, None), (di_B530, fake_hidpp.complex_responses_1, 4.5, hidpp20.LEDEffectsInfo, 0, 0, 0, None, None), (di_B530, fake_hidpp.complex_responses_2, 4.5, hidpp20.RGBEffectsInfo, 8, 3, 1, True, True), ], ) def test_device_complex(device_info, responses, protocol, led, keys, remap, gestures, backlight, profiles, mocker): test_device = FakeDevice(responses, None, None, True, device_info=device_info) test_device._name = "TestDevice" test_device._protocol = protocol spy_request = mocker.spy(test_device, "request") assert type(test_device.led_effects) == led if keys is None: assert test_device.keys == keys else: assert len(test_device.keys) == keys if remap is None: assert test_device.remap_keys == remap else: assert len(test_device.remap_keys) == remap assert (test_device.gestures is None) == (gestures is None) assert (test_device.backlight is None) == (backlight is None) assert (test_device.profiles is None) == (profiles is None) test_device.set_configuration(55) if protocol > 1.0: spy_request.assert_called_with(0x210, 55, no_reply=False) test_device.reset() if protocol > 1.0: spy_request.assert_called_with(0x210, 0, no_reply=False) @pytest.mark.parametrize( "device_info, responses, protocol, p, persister, settings", [ (di_CCCC, fake_hidpp.r_empty, 1.0, None, None, 0), (di_C318, fake_hidpp.r_empty, 1.0, {}, {}, 0), (di_C318, fake_hidpp.r_keyboard_1, 1.0, {"n": "n"}, {"n": "n"}, 1), (di_B530, fake_hidpp.r_keyboard_2, 4.5, {"m": "m"}, {"m": "m"}, 1), (di_C068, fake_hidpp.r_mouse_1, 1.0, {"o": "o"}, {"o": "o"}, 2), (di_C08A, fake_hidpp.r_mouse_2, 4.5, {"p": "p"}, {"p": "p"}, 0), ], ) def test_device_settings(device_info, responses, protocol, p, persister, settings, mocker): mocker.patch("solaar.configuration.persister", return_value=p) test_device = FakeDevice(responses, None, None, True, device_info=device_info) test_device._name = "TestDevice" test_device._protocol = protocol assert test_device.persister == persister assert len(test_device.settings) == settings @pytest.mark.parametrize( "device_info, responses, protocol, expected_battery, changed", [ (di_C318, fake_hidpp.r_empty, 1.0, None, {"active": True, "alert": 0, "reason": None}), ( di_C318, fake_hidpp.r_keyboard_1, 1.0, common.Battery(BatteryLevelApproximation.GOOD.value, None, BatteryStatus.DISCHARGING, None), {"active": True, "alert": 0, "reason": None}, ), ( di_B530, fake_hidpp.r_keyboard_2, 4.5, common.Battery(18, 52, None, None), {"active": True, "alert": 0, "reason": None}, ), ], ) def test_device_battery(device_info, responses, protocol, expected_battery, changed, mocker): test_device = FakeDevice(responses, None, None, online=True, device_info=device_info) test_device._name = "TestDevice" test_device._protocol = protocol spy_changed = mocker.spy(test_device, "changed") assert test_device.battery() == expected_battery test_device.read_battery() spy_changed.assert_called_with(**changed) Solaar-1.1.20/tests/logitech_receiver/test_diversion.py000066400000000000000000000067461522022367600232750ustar00rootroot00000000000000import textwrap from unittest import mock from unittest.mock import mock_open import pytest from logitech_receiver import diversion from logitech_receiver.base import HIDPPNotification from logitech_receiver.hidpp20_constants import SupportedFeature @pytest.fixture def rule_config(): rule_content = """ %YAML 1.3 --- - MouseGesture: Mouse Left - KeyPress: - [Control_L, Alt_L, Left] - click ... --- - MouseGesture: Mouse Up - KeyPress: - [Super_L, Up] - click ... --- - Test: [thumb_wheel_up, 10] - KeyPress: - [Control_L, Page_Down] - click ... --- """ return textwrap.dedent(rule_content) def test_load_rule_config(rule_config): expected_rules = [ [ diversion.MouseGesture, diversion.KeyPress, ], [diversion.MouseGesture, diversion.KeyPress], [diversion.Test, diversion.KeyPress], ] with mock.patch("builtins.open", new=mock_open(read_data=rule_config)): loaded_rules = diversion._load_rule_config(file_path=mock.Mock()) assert len(loaded_rules.components) == 2 # predefined and user configured rules user_configured_rules = loaded_rules.components[0] assert isinstance(user_configured_rules, diversion.Rule) for components, expected_components in zip(user_configured_rules.components, expected_rules): for component, expected_component in zip(components.components, expected_components): assert isinstance(component, expected_component) def test_diversion_rule(): args = [ { "Rule": [ # Implement problematic keys for Craft and MX Master {"Rule": [{"Key": ["Brightness Down", "pressed"]}, {"KeyPress": "XF86_MonBrightnessDown"}]}, {"Rule": [{"Key": ["Brightness Up", "pressed"]}, {"KeyPress": "XF86_MonBrightnessUp"}]}, ] }, ] rule = diversion.Rule(args) assert len(rule.components) == 1 root_rule = rule.components[0] assert isinstance(root_rule, diversion.Rule) assert len(root_rule.components) == 2 for component in root_rule.components: assert isinstance(component, diversion.Rule) assert len(component.components) == 2 key = component.components[0] assert isinstance(key, diversion.Key) key = component.components[1] assert isinstance(key, diversion.KeyPress) def test_key_is_down(): result = diversion.key_is_down(key=diversion.CONTROL.G2) assert result is False def test_feature(): expected_data = {"Feature": "CONFIG CHANGE"} result = diversion.Feature("CONFIG_CHANGE") assert result.data() == expected_data @pytest.mark.parametrize( "feature, data", [ ( SupportedFeature.REPROG_CONTROLS_V4, [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08], ), (SupportedFeature.GKEY, [0x01, 0x02, 0x03, 0x04]), (SupportedFeature.MKEYS, [0x01, 0x02, 0x03, 0x04]), (SupportedFeature.MR, [0x01, 0x02, 0x03, 0x04]), (SupportedFeature.THUMB_WHEEL, [0x01, 0x02, 0x03, 0x04, 0x05]), (SupportedFeature.DEVICE_UNIT_ID, [0x01, 0x02, 0x03, 0x04, 0x05]), ], ) def test_process_notification(feature, data): device_mock = mock.Mock() notification = HIDPPNotification( report_id=0x01, devnumber=1, sub_id=0x13, address=0x00, data=bytes(data), ) diversion.process_notification(device_mock, notification, feature) Solaar-1.1.20/tests/logitech_receiver/test_hidpp10.py000066400000000000000000000316311522022367600225270ustar00rootroot00000000000000from dataclasses import dataclass from dataclasses import field from typing import Any from typing import List from typing import Optional import pytest from logitech_receiver import common from logitech_receiver import hidpp10 from logitech_receiver import hidpp10_constants from logitech_receiver.hidpp10_constants import PairingError from logitech_receiver.hidpp10_constants import Registers _hidpp10 = hidpp10.Hidpp10() @dataclass class Response: response: Optional[str] request_id: int params: Any @dataclass class Device: name: str = "Device" online: bool = True kind: str = "fake" protocol: float = 1.0 isDevice: bool = False # incorrect, but useful here registers: List[Registers] = field(default_factory=list) responses: List[Response] = field(default_factory=list) def request(self, id, params=None, no_reply=False): if params is None: params = [] print("REQUEST ", self.name, hex(id), params) for r in self.responses: if id == r.request_id and params == r.params: print("RESPONSE", self.name, hex(r.request_id), r.params, r.response) return bytes.fromhex(r.response) if r.response is not None else None device_offline = Device("OFFLINE", False) device_leds = Device("LEDS", True, registers=[Registers.THREE_LEDS, Registers.BATTERY_STATUS]) device_features = Device("FEATURES", True, protocol=4.5) registers_standard = [Registers.BATTERY_STATUS, Registers.FIRMWARE] responses_standard = [ Response("555555", 0x8100 | Registers.BATTERY_STATUS, 0x00), Response("666666", 0x8100 | Registers.BATTERY_STATUS, 0x10), Response("777777", 0x8000 | Registers.BATTERY_STATUS, 0x00), Response("888888", 0x8000 | Registers.BATTERY_STATUS, 0x10), Response("052100", 0x8100 | Registers.BATTERY_STATUS, []), Response("ABCDEF", 0x8100 | Registers.FIRMWARE, 0x01), Response("ABCDEF", 0x8100 | Registers.FIRMWARE, 0x02), Response("ABCDEF", 0x8100 | Registers.FIRMWARE, 0x03), Response("ABCDEF", 0x8100 | Registers.FIRMWARE, 0x04), Response("000900", 0x8100 | Registers.NOTIFICATIONS, []), Response("101010", 0x8100 | Registers.MOUSE_BUTTON_FLAGS, []), Response("010101", 0x8100 | Registers.KEYBOARD_FN_SWAP, []), Response("020202", 0x8100 | Registers.DEVICES_CONFIGURATION, []), Response("030303", 0x8000 | Registers.DEVICES_CONFIGURATION, 0x00), ] device_standard = Device("STANDARD", True, registers=registers_standard, responses=responses_standard) @pytest.mark.parametrize( "device, register, param, expected_result", [ (device_offline, Registers.THREE_LEDS, 0x00, None), (device_standard, Registers.THREE_LEDS, 0x00, None), (device_standard, Registers.BATTERY_STATUS, 0x00, "555555"), (device_standard, Registers.BATTERY_STATUS, 0x10, "666666"), ], ) def test_read_register(device, register, param, expected_result, mocker): spy_request = mocker.spy(device, "request") result = hidpp10.read_register(device, register, param) assert result == (bytes.fromhex(expected_result) if expected_result else None) spy_request.assert_called_once_with(0x8100 | register, param) @pytest.mark.parametrize( "device, register, param, expected_result", [ (device_offline, Registers.THREE_LEDS, 0x00, None), (device_standard, Registers.THREE_LEDS, 0x00, None), (device_standard, Registers.BATTERY_STATUS, 0x00, "777777"), (device_standard, Registers.BATTERY_STATUS, 0x10, "888888"), ], ) def test_write_register(device, register, param, expected_result, mocker): spy_request = mocker.spy(device, "request") result = hidpp10.write_register(device, register, param) assert result == (bytes.fromhex(expected_result) if expected_result else None) spy_request.assert_called_once_with(0x8000 | register, param) def device_charge(name, response): responses = [Response(response, 0x8100 | Registers.BATTERY_CHARGE, [])] return Device(name, registers=[], responses=responses) device_charge1 = device_charge("DISCHARGING", "550030") device_charge2 = device_charge("RECHARGING", "440050") device_charge3 = device_charge("FULL", "600090") device_charge4 = device_charge("OTHER", "220000") def device_status(name, response): responses = [Response(response, 0x8100 | Registers.BATTERY_STATUS, [])] return Device(name, registers=[], responses=responses) device_status1 = device_status("FULL", "072200") device_status2 = device_status("GOOD", "052100") device_status3 = device_status("LOW", "032200") device_status4 = device_status("CRITICAL", "010100") device_status5 = device_status("EMPTY", "000000") device_status6 = device_status("NOSTATUS", "002200") @pytest.mark.parametrize( "device, expected_result, expected_register", [ (device_offline, None, None), (device_features, None, None), (device_leds, None, None), ( device_standard, common.Battery(common.BatteryLevelApproximation.GOOD, None, common.BatteryStatus.RECHARGING, None), Registers.BATTERY_STATUS, ), (device_charge1, common.Battery(0x55, None, common.BatteryStatus.DISCHARGING, None), Registers.BATTERY_CHARGE), ( device_charge2, common.Battery(0x44, None, common.BatteryStatus.RECHARGING, None), Registers.BATTERY_CHARGE, ), ( device_charge3, common.Battery(0x60, None, common.BatteryStatus.FULL, None), Registers.BATTERY_CHARGE, ), (device_charge4, common.Battery(0x22, None, None, None), Registers.BATTERY_CHARGE), ( device_status1, common.Battery(common.BatteryLevelApproximation.FULL, None, common.BatteryStatus.FULL, None), Registers.BATTERY_STATUS, ), ( device_status2, common.Battery(common.BatteryLevelApproximation.GOOD, None, common.BatteryStatus.RECHARGING, None), Registers.BATTERY_STATUS, ), ( device_status3, common.Battery(common.BatteryLevelApproximation.LOW, None, common.BatteryStatus.FULL, None), Registers.BATTERY_STATUS, ), ( device_status4, common.Battery(common.BatteryLevelApproximation.CRITICAL, None, None, None), Registers.BATTERY_STATUS, ), ( device_status5, common.Battery(common.BatteryLevelApproximation.EMPTY, None, common.BatteryStatus.DISCHARGING, None), Registers.BATTERY_STATUS, ), ( device_status6, common.Battery(None, None, common.BatteryStatus.FULL, None), Registers.BATTERY_STATUS, ), ], ) def test_hidpp10_get_battery(device, expected_result, expected_register): result = _hidpp10.get_battery(device) assert result == expected_result if expected_register is not None: assert expected_register in device.registers @pytest.mark.parametrize( "device, expected_firmwares", [ (device_offline, []), ( device_standard, [ common.FirmwareKind.Firmware, common.FirmwareKind.Bootloader, common.FirmwareKind.Other, ], ), ], ) def test_hidpp10_get_firmware(device, expected_firmwares): firmwares = _hidpp10.get_firmware(device) if not expected_firmwares: assert firmwares is None else: firmware_types = [firmware.kind for firmware in firmwares] assert firmware_types == expected_firmwares assert len(firmwares) == len(expected_firmwares) @pytest.mark.parametrize( "device, level, charging, warning, p1, p2", [ (device_leds, common.BatteryLevelApproximation.EMPTY, False, False, 0x33, 0x00), (device_leds, common.BatteryLevelApproximation.CRITICAL, False, False, 0x22, 0x00), (device_leds, common.BatteryLevelApproximation.LOW, False, False, 0x20, 0x00), (device_leds, common.BatteryLevelApproximation.GOOD, False, False, 0x20, 0x02), (device_leds, common.BatteryLevelApproximation.FULL, False, False, 0x20, 0x22), (device_leds, None, True, False, 0x30, 0x33), (device_leds, None, False, True, 0x02, 0x00), (device_leds, None, False, False, 0x11, 0x11), ], ) def test_set_3leds(device, level, charging, warning, p1, p2, mocker): spy_request = mocker.spy(device, "request") _hidpp10.set_3leds(device, level, charging, warning) spy_request.assert_called_once_with(0x8000 | Registers.THREE_LEDS, p1, p2) @pytest.mark.parametrize("device", [device_offline, device_features]) def test_set_3leds_missing(device, mocker): spy_request = mocker.spy(device, "request") _hidpp10.set_3leds(device) assert spy_request.call_count == 0 @pytest.mark.parametrize("device", [device_standard]) def test_get_notification_flags(device): result = _hidpp10.get_notification_flags(device) assert result == hidpp10_constants.NotificationFlag(int("000900", 16)) def test_set_notification_flags(mocker): device = device_standard spy_request = mocker.spy(device, "request") result = _hidpp10.set_notification_flags( device, hidpp10_constants.NotificationFlag.BATTERY_STATUS, hidpp10_constants.NotificationFlag.WIRELESS ) spy_request.assert_called_once_with(0x8000 | Registers.NOTIFICATIONS, b"\x10\x01\x00") assert result is not None def test_set_notification_flags_bad(mocker): device = device_features spy_request = mocker.spy(device, "request") result = _hidpp10.set_notification_flags( device, hidpp10_constants.NotificationFlag.BATTERY_STATUS, hidpp10_constants.NotificationFlag.WIRELESS ) assert spy_request.call_count == 0 assert result is None @pytest.mark.parametrize( "flag_bits, expected_names", [ # doesn't work in Python 3.8 and 3.10 for some reason (None, ""), (hidpp10_constants.NotificationFlag(0x0), "none"), (hidpp10_constants.NotificationFlag(0x001000), "multi touch"), (hidpp10_constants.NotificationFlag(0x080000), "mouse extra buttons"), ( hidpp10_constants.NotificationFlag(0x080400), ("link quality\n mouse extra buttons"), ), ], ) def test_notification_flag_str(flag_bits, expected_names): flag_names = hidpp10_constants.flags_to_str( hidpp10_constants.NotificationFlag(flag_bits) if flag_bits is not None else None, fallback="none" ) assert flag_names == expected_names @pytest.mark.parametrize( "flags, expected", [ (None, []), # composite flag, .name is None on Python < 3.11 (hidpp10_constants.NotificationFlag(0x000900), ["software present", "wireless"]), (hidpp10_constants.NotificationFlag(0x100000), ["battery status"]), (hidpp10_constants.NotificationFlag(0x080000), ["mouse extra buttons"]), ], ) def test_notification_flag_names(flags, expected): result = hidpp10_constants.NotificationFlag.flag_names(flags) assert result == expected def test_notification_flag_names_none_does_not_crash(): """Regression test for #3184: flag_names crashes with AttributeError when flags.name is None, which happens with certain receiver firmware versions (e.g. Nano C52F reporting 0x000900).""" flags_with_none_name = hidpp10_constants.NotificationFlag(0x000900) result = hidpp10_constants.NotificationFlag.flag_names(flags_with_none_name) assert "software present" in result assert "wireless" in result assert isinstance(result, list) def test_get_device_features(): result = _hidpp10.get_device_features(device_standard) assert result == int("101010", 16) @pytest.mark.parametrize( "device, register, expected_result", [ (device_standard, Registers.BATTERY_STATUS, "052100"), (device_standard, Registers.MOUSE_BUTTON_FLAGS, "101010"), (device_standard, Registers.KEYBOARD_ILLUMINATION, None), (device_features, Registers.KEYBOARD_ILLUMINATION, None), ], ) def test_get_register(device, register, expected_result): result = _hidpp10._get_register(device, register) assert result == (int(expected_result, 16) if expected_result is not None else None) @pytest.mark.parametrize( "device, expected_result", [ (device_standard, 2), (device_features, None), ], ) def test_get_configuration_pending_flags(device, expected_result): result = hidpp10.get_configuration_pending_flags(device) assert result == expected_result @pytest.mark.parametrize( "device, expected_result", [ (device_standard, True), (device_features, False), ], ) def test_set_configuration_pending_flags(device, expected_result): result = hidpp10.set_configuration_pending_flags(device, 0x00) assert result == expected_result def test_pairing_error(): expected_label = "device not supported" res = PairingError.DEVICE_NOT_SUPPORTED.label assert res == expected_label Solaar-1.1.20/tests/logitech_receiver/test_hidpp20_complex.py000066400000000000000000001422731522022367600242640ustar00rootroot00000000000000## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import pytest import yaml from logitech_receiver import common from logitech_receiver import exceptions from logitech_receiver import hidpp20 from logitech_receiver import hidpp20_constants from logitech_receiver import special_keys from logitech_receiver.device import CenturionReceiver from logitech_receiver.hidpp20 import KeyFlag from logitech_receiver.hidpp20 import MappingFlag from logitech_receiver.hidpp20_constants import GestureId from . import fake_hidpp _hidpp20 = hidpp20.Hidpp20() device_offline = fake_hidpp.Device("REGISTERS", False) device_registers = fake_hidpp.Device("OFFLINE", True, 1.0) device_nofeatures = fake_hidpp.Device("NOFEATURES", True, 4.5) device_zerofeatures = fake_hidpp.Device("ZEROFEATURES", True, 4.5, [fake_hidpp.Response("0000", 0x0000, "0001")]) device_broken = fake_hidpp.Device( "BROKEN", True, 4.5, [fake_hidpp.Response("0500", 0x0000, "0001"), fake_hidpp.Response(None, 0x0100)] ) device_standard = fake_hidpp.Device("STANDARD", True, 4.5, fake_hidpp.r_keyboard_2) @pytest.mark.parametrize( "device, expected_result, expected_count", [ (device_offline, False, 0), (device_registers, False, 0), (device_nofeatures, False, 0), (device_zerofeatures, False, 0), (device_broken, False, 0), (device_standard, True, 9), ], ) def test_FeaturesArray_check(device, expected_result, expected_count): featuresarray = hidpp20.FeaturesArray(device) result = featuresarray._check() result2 = featuresarray._check() assert result == expected_result assert result2 == expected_result assert (hidpp20_constants.SupportedFeature.ROOT in featuresarray) == expected_result assert len(featuresarray) == expected_count assert bool(featuresarray) == expected_result @pytest.mark.parametrize( "device, expected0, expected1, expected2, expected5, expected5v", [ (device_zerofeatures, None, None, None, None, None), (device_standard, 0x0000, 0x0001, 0x0020, hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, 3), ], ) def test_FeaturesArray_get_feature(device, expected0, expected1, expected2, expected5, expected5v): featuresarray = hidpp20.FeaturesArray(device) device.features = featuresarray result0 = featuresarray.get_feature(0) result1 = featuresarray.get_feature(1) result2 = featuresarray.get_feature(2) result5 = featuresarray.get_feature(5) result2r = featuresarray.get_feature(2) result5v = featuresarray.get_feature_version(hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4) assert result0 == expected0 assert result1 == expected1 assert result2 == expected2 assert result2r == expected2 assert result5 == expected5 assert result5v == expected5v @pytest.mark.parametrize( "device, expected_result", [ (device_zerofeatures, []), ( device_standard, [ (hidpp20_constants.SupportedFeature.ROOT, 0), (hidpp20_constants.SupportedFeature.FEATURE_SET, 1), (hidpp20_constants.SupportedFeature.CONFIG_CHANGE, 2), (hidpp20_constants.SupportedFeature.DEVICE_FW_VERSION, 3), (hidpp20_constants.SupportedFeature.CENTURION_DEVICE_INFO, 4), (hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, 5), # Indices 6 and 7 have no responses — get_feature returns None, enumerate skips them (hidpp20_constants.SupportedFeature.BATTERY_STATUS, 8), ], ), ], ) def test_FeaturesArray_enumerate(device, expected_result): featuresarray = hidpp20.FeaturesArray(device) result = list(featuresarray.enumerate()) assert result == expected_result def test_FeaturesArray_setitem(): featuresarray = hidpp20.FeaturesArray(device_standard) featuresarray[hidpp20_constants.SupportedFeature.ROOT] = 3 featuresarray[hidpp20_constants.SupportedFeature.FEATURE_SET] = 5 featuresarray[hidpp20_constants.SupportedFeature.FEATURE_SET] = 4 assert featuresarray[hidpp20_constants.SupportedFeature.FEATURE_SET] == 4 assert featuresarray.inverse[4] == hidpp20_constants.SupportedFeature.FEATURE_SET def test_FeaturesArray_delitem(): featuresarray = hidpp20.FeaturesArray(device_standard) with pytest.raises(ValueError): del featuresarray[5] @pytest.mark.parametrize( "device, expected0, expected1, expected2, expected1v", [(device_zerofeatures, None, None, None, None), (device_standard, 0, 5, None, 3)], ) def test_FeaturesArray_getitem(device, expected0, expected1, expected2, expected1v): featuresarray = hidpp20.FeaturesArray(device) device.features = featuresarray result_get0 = featuresarray[hidpp20_constants.SupportedFeature.ROOT] result_get1 = featuresarray[hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4] result_get2 = featuresarray[hidpp20_constants.SupportedFeature.GKEY] result_1v = featuresarray.get_feature_version(hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4) assert result_get0 == expected0 assert result_get1 == expected1 assert result_get2 == expected2 assert result_1v == expected1v @pytest.mark.parametrize( "device, index, cid, task_id, flags, default_task, expected_flags", [ (device_standard, 2, 1, 1, 0x30, "Volume Up", KeyFlag.REPROGRAMMABLE | KeyFlag.DIVERTABLE), (device_standard, 1, 2, 2, 0x20, "Volume Down", KeyFlag.DIVERTABLE), ], ) def test_reprogrammable_key_key(device, index, cid, task_id, flags, default_task, expected_flags): key = hidpp20.ReprogrammableKey(device, index, cid, task_id, flags) assert key._device == device assert key.index == index assert key._cid == cid assert key._tid == task_id assert key._flags == flags assert key.key == special_keys.CONTROL[cid] assert key.default_task == common.NamedInt(cid, default_task) assert key.flags == expected_flags @pytest.mark.parametrize( "device, index, cid, task_id, flags, pos, group, gmask, default_task, expected_flags, group_names", [ ( device_standard, 1, 0x51, 0x39, 0x60, 0, 1, 1, "Right Click", KeyFlag.DIVERTABLE | KeyFlag.PERSISTENTLY_DIVERTABLE, ["g1"], ), ( device_standard, 2, 0x52, 0x3A, 0x11, 1, 2, 3, "Mouse Middle Button", KeyFlag.MSE | KeyFlag.REPROGRAMMABLE, ["g1", "g2"], ), ( device_standard, 3, 0x53, 0x3C, 0x110, 2, 2, 7, "Mouse Back Button", KeyFlag.REPROGRAMMABLE | KeyFlag.RAW_XY, ["g1", "g2", "g3"], ), ], ) def test_reprogrammable_key_v4_key( device, index, cid, task_id, flags, pos, group, gmask, default_task, expected_flags, group_names ): key = hidpp20.ReprogrammableKeyV4(device, index, cid, task_id, flags, pos, group, gmask) assert key._device == device assert key.index == index assert key._cid == cid assert key._tid == task_id assert key._flags == flags assert key.pos == pos assert key.group == group assert key._gmask == gmask assert key.key == special_keys.CONTROL[cid] assert key.default_task == common.NamedInt(cid, default_task) assert key.flags == expected_flags assert list(key.group_mask) == group_names @pytest.mark.parametrize( "responses, index, mapped_to, remappable_to, expected_mapping_flags", [ (fake_hidpp.responses_key, 1, "Right Click", common.UnsortedNamedInts(Right_Click=81, Left_Click=80), MappingFlag(0)), (fake_hidpp.responses_key, 2, "Left Click", None, MappingFlag.DIVERTED), (fake_hidpp.responses_key, 3, "Mouse Back Button", None, MappingFlag.DIVERTED | MappingFlag.PERSISTENTLY_DIVERTED), (fake_hidpp.responses_key, 4, "Mouse Forward Button", None, MappingFlag.DIVERTED | MappingFlag.RAW_XY_DIVERTED), ], ) # these fields need access all the key data, so start by setting up a device and its key data def test_reprogrammable_key_v4_query(responses, index, mapped_to, remappable_to, expected_mapping_flags): device = fake_hidpp.Device( "KEY", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5 ) device._keys = _hidpp20.get_keys(device) key = device.keys[index] assert key.mapped_to == mapped_to assert (key.remappable_to == remappable_to) or remappable_to is None assert key.mapping_flags == expected_mapping_flags @pytest.mark.parametrize( "responses, index, diverted, persistently_diverted, rawXY_reporting, remap, sets", [ (fake_hidpp.responses_key, 1, True, False, True, 0x52, ["0051080000"]), (fake_hidpp.responses_key, 2, False, True, False, 0x51, ["0052020000", "0052200000", "0052000051"]), (fake_hidpp.responses_key, 3, False, True, True, 0x50, ["0053020000", "00530C0000", "0053300000", "0053000050"]), (fake_hidpp.responses_key, 4, False, False, False, 0x50, ["0056020000", "0056080000", "0056200000", "0056000050"]), ], ) def test_reprogrammable_key_v4_set(responses, index, diverted, persistently_diverted, rawXY_reporting, remap, sets, mocker): responses += [fake_hidpp.Response(r, 0x530, r) for r in sets] device = fake_hidpp.Device( "KEY", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5 ) device._keys = _hidpp20.get_keys(device) device._keys._ensure_all_keys_queried() # do this now so that the last requests are sets spy_request = mocker.spy(device, "request") key = device.keys[index] _mapping_flags = key.mapping_flags if hidpp20.KeyFlag.DIVERTABLE in key.flags or not diverted: key.set_diverted(diverted) else: with pytest.raises(exceptions.FeatureNotSupported): key.set_diverted(diverted) assert (MappingFlag.DIVERTED in key.mapping_flags) == (diverted and hidpp20.KeyFlag.DIVERTABLE in key.flags) if hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.flags or not persistently_diverted: key.set_persistently_diverted(persistently_diverted) else: with pytest.raises(exceptions.FeatureNotSupported): key.set_persistently_diverted(persistently_diverted) assert (hidpp20.MappingFlag.PERSISTENTLY_DIVERTED in key.mapping_flags) == ( persistently_diverted and hidpp20.KeyFlag.PERSISTENTLY_DIVERTABLE in key.flags ) if hidpp20.KeyFlag.RAW_XY in key.flags or not rawXY_reporting: key.set_rawXY_reporting(rawXY_reporting) else: with pytest.raises(exceptions.FeatureNotSupported): key.set_rawXY_reporting(rawXY_reporting) assert (MappingFlag.RAW_XY_DIVERTED in key.mapping_flags) == (rawXY_reporting and hidpp20.KeyFlag.RAW_XY in key.flags) if remap in key.remappable_to or remap == 0: key.remap(remap) else: with pytest.raises(exceptions.FeatureNotSupported): key.remap(remap) assert (key.mapped_to == remap) or (remap not in key.remappable_to and remap != 0) fake_hidpp.match_requests(len(sets), responses, spy_request.call_args_list) @pytest.mark.parametrize( "r, index, cid, actionId, remapped, mask, status, action, modifiers, byts, remap", [ (fake_hidpp.responses_key, 1, 0x0051, 0x02, 0x0002, 0x01, 0, "Mouse Button: 2", "Cntrl+", "02000201", "01000400"), (fake_hidpp.responses_key, 2, 0x0052, 0x01, 0x0001, 0x00, 1, "Key: 1", "", "01000100", "02005004"), (fake_hidpp.responses_key, 3, 0x0053, 0x02, 0x0001, 0x00, 1, "Mouse Button: 1", "", "02000100", "7FFFFFFF"), ], ) def test_remappable_action(r, index, cid, actionId, remapped, mask, status, action, modifiers, byts, remap, mocker): if int(remap, 16) == special_keys.KEYS_Default: responses = r + [ fake_hidpp.Response("040000", 0x0000, "1C00"), fake_hidpp.Response("00", 0x450, f"{cid:04X}" + "FF"), ] else: responses = r + [ fake_hidpp.Response("040000", 0x0000, "1C00"), fake_hidpp.Response("00", 0x440, f"{cid:04X}" + "FF" + remap), ] device = fake_hidpp.Device( "KEY", responses=responses, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5 ) key = hidpp20.PersistentRemappableAction(device, index, cid, actionId, remapped, mask, status) spy_request = mocker.spy(device, "request") assert key._device == device assert key.index == index assert key._cid == cid assert key.actionId == actionId assert key.remapped == remapped assert key._modifierMask == mask assert key.cidStatus == status assert key.key == special_keys.CONTROL[cid] assert key.actionType == special_keys.ACTIONID[actionId] assert key.action == action assert key.modifiers == modifiers assert key.data_bytes.hex().upper() == byts key.remap(bytes.fromhex(remap)) assert key.data_bytes.hex().upper() == (byts if int(remap, 16) == special_keys.KEYS_Default else remap) if int(remap, 16) != special_keys.KEYS_Default: fake_hidpp.match_requests(1, responses, spy_request.call_args_list) # KeysArray methods tested in KeysArrayV4 # KeysArrayV2 not tested as there is no documentation @pytest.mark.parametrize( "device, index", [(device_zerofeatures, -1), (device_zerofeatures, 5), (device_standard, -1), (device_standard, 6)] ) def test_KeysArrayV4_index_error(device, index): keysarray = hidpp20.KeysArrayV4(device, 5) with pytest.raises(IndexError): keysarray[index] with pytest.raises(IndexError): keysarray._query_key(index) @pytest.mark.parametrize("device, index, top, cid", [(device_standard, 0, 2, 0x0011), (device_standard, 4, 5, 0x0003)]) def test_KeysArrayV4_query_key(device, index, top, cid): keysarray = hidpp20.KeysArrayV4(device, 5) keysarray._query_key(index) assert keysarray.keys[index]._cid == cid assert len(keysarray[index:top]) == top - index assert len(list(keysarray)) == 5 @pytest.mark.parametrize( "device, count, index, cid, task_id, flags, pos, group, gmask", [ (device_standard, 4, 0, 0x0011, 0x0012, 0xCDAB, 1, 2, 3), (device_standard, 6, 1, 0x0111, 0x0022, 0xCDAB, 1, 2, 3), (device_standard, 8, 3, 0x0311, 0x0032, 0xCDAB, 1, 2, 4), ], ) def test_KeysArrayV4__getitem(device, count, index, cid, task_id, flags, pos, group, gmask): keysarray = hidpp20.KeysArrayV4(device, count) result = keysarray[index] assert result._device == device assert result.index == index assert result._cid == cid assert result._tid == task_id assert result._flags == flags assert result.pos == pos assert result.group == group assert result._gmask == gmask @pytest.mark.parametrize( "key, index", [(special_keys.CONTROL.Volume_Up_old, 2), (special_keys.CONTROL.Mute, 4), (special_keys.CONTROL.Next, None)] ) def test_KeysArrayV4_index(key, index): keysarray = hidpp20.KeysArrayV4(device_standard, 7) result = keysarray.index(key) assert result == index device_key = fake_hidpp.Device( "KEY", responses=fake_hidpp.responses_key, feature=hidpp20_constants.SupportedFeature.REPROG_CONTROLS_V4, offset=5 ) @pytest.mark.parametrize( "key, expected_index, expected_mapped_to, expected_remappable_to", [ ( special_keys.CONTROL.Left_Button, 0, common.NamedInt(0x50, "Left Click"), [common.NamedInt(0x50, "Left Click"), common.NamedInt(0x51, "Right Click")], ), ( special_keys.CONTROL.Right_Button, 1, common.NamedInt(0x51, "Right Click"), [common.NamedInt(0x51, "Right Click"), common.NamedInt(0x50, "Left Click")], ), (special_keys.CONTROL.Middle_Button, 2, common.NamedInt(0x50, "Left Click"), None), (special_keys.CONTROL.Back_Button, 3, common.NamedInt(0x53, "Mouse Back Button"), None), (special_keys.CONTROL.Forward_Button, 4, common.NamedInt(0x56, "Mouse Forward Button"), None), (special_keys.CONTROL.Mouse_Gesture_Button, 5, common.NamedInt(0xC3, "Gesture Button Navigation"), None), (special_keys.CONTROL.Smart_Shift, 6, common.NamedInt(0x50, "Left Click"), None), (special_keys.CONTROL.Virtual_Gesture_Button, 7, common.NamedInt(0x51, "Right Click"), None), ], ) def test_keys_array_v4_key(key, expected_index, expected_mapped_to, expected_remappable_to): device_key._keys = _hidpp20.get_keys(device_key) device_key._keys._ensure_all_keys_queried() index = device_key._keys.index(key) mapped_to = device_key._keys[expected_index].mapped_to remappable_to = device_key._keys[expected_index].remappable_to assert index == expected_index assert mapped_to == expected_mapped_to if expected_remappable_to is not None: assert list(remappable_to) == expected_remappable_to @pytest.mark.parametrize( "device, index", [(device_zerofeatures, -1), (device_zerofeatures, 5), (device_standard, -1), (device_standard, 6)] ) def test_KeysArrayPersistent_index_error(device, index): keysarray = hidpp20.KeysArrayPersistent(device, 5) with pytest.raises(IndexError): keysarray[index] with pytest.raises(IndexError): keysarray._query_key(index) @pytest.mark.parametrize( "responses, key, index, mapped_to, capabilities", [ (fake_hidpp.responses_remap, special_keys.CONTROL.Left_Button, 0, common.NamedInt(0x01, "Mouse Button Left"), 0x41), (fake_hidpp.responses_remap, special_keys.CONTROL.Right_Button, 1, common.NamedInt(0x01, "Mouse Button Left"), 0x41), (fake_hidpp.responses_remap, special_keys.CONTROL.Middle_Button, 2, common.NamedInt(0x51, "DOWN"), 0x41), ], ) def test_KeysArrayPersistent_key(responses, key, index, mapped_to, capabilities): device = fake_hidpp.Device( "REMAP", responses=responses, feature=hidpp20_constants.SupportedFeature.PERSISTENT_REMAPPABLE_ACTION ) device._remap_keys = _hidpp20.get_remap_keys(device) device._remap_keys._ensure_all_keys_queried() assert device._remap_keys.index(key) == index assert device._remap_keys[index].remapped == mapped_to assert device._remap_keys.capabilities == capabilities @pytest.mark.parametrize( "id, length, minimum, maximum, widget, min, max, wid, string", [ ("left", 1, 5, 8, "Widget", 5, 8, "Widget", "left"), ("left", 1, None, None, None, 0, 255, "Scale", "left"), ], ) def test_SubParam(id, length, minimum, maximum, widget, min, max, wid, string): subparam = hidpp20.SubParam(id, length, minimum, maximum, widget) assert subparam.id == id assert subparam.length == length assert subparam.minimum == min assert subparam.maximum == max assert subparam.widget == wid assert subparam.__str__() == string assert subparam.__repr__() == string @pytest.mark.parametrize( "device, low, high, next_index, next_diversion_index, name, cbe, si, sdi, eom, dom", [ (device_standard, 0x01, 0x01, 5, 10, GestureId.TAP_1_FINGER, True, 5, None, (0, 0x20), (None, None)), (device_standard, 0x03, 0x02, 6, 11, GestureId.TAP_3_FINGER, False, None, 11, (None, None), (1, 0x08)), ], ) def test_gesture(device, low, high, next_index, next_diversion_index, name, cbe, si, sdi, eom, dom): gesture = hidpp20.Gesture(device, low, high, next_index, next_diversion_index) assert gesture._device == device assert gesture.id == low assert gesture.gesture == name assert gesture.can_be_enabled == cbe assert gesture.can_be_enabled == cbe assert gesture.index == si assert gesture.diversion_index == sdi assert gesture.enable_offset_mask() == eom assert gesture.diversion_offset_mask() == dom assert gesture.as_int() == low assert int(gesture) == low @pytest.mark.parametrize( "responses, gest, enabled, diverted, set_result, unset_result, divert_result, undivert_result", [ (fake_hidpp.responses_gestures, 20, None, None, None, None, None, None), (fake_hidpp.responses_gestures, 1, True, False, "01", "00", "01", "00"), (fake_hidpp.responses_gestures, 45, False, None, "01", "00", None, None), ], ) def test_Gesture_set(responses, gest, enabled, diverted, set_result, unset_result, divert_result, undivert_result): device = fake_hidpp.Device("GESTURE", responses=responses, feature=hidpp20_constants.SupportedFeature.GESTURE_2) gestures = _hidpp20.get_gestures(device) gesture = gestures.gesture(gest) assert gesture.enabled() == enabled assert gesture.diverted() == diverted assert gesture.set(True) == (bytes.fromhex(set_result) if set_result is not None else None) assert gesture.set(False) == (bytes.fromhex(unset_result) if unset_result is not None else None) assert gesture.divert(True) == (bytes.fromhex(divert_result) if divert_result is not None else None) assert gesture.divert(False) == (bytes.fromhex(undivert_result) if undivert_result is not None else None) @pytest.mark.parametrize( "responses, prm, id, index, size, value, default_value, write1, write2", [ (fake_hidpp.responses_gestures, 4, hidpp20_constants.ParamId.SCALE_FACTOR, 0, 2, 256, 256, "0080", "0180"), ], ) def test_param(responses, prm, id, index, size, value, default_value, write1, write2): device = fake_hidpp.Device("GESTURE", responses=responses, feature=hidpp20_constants.SupportedFeature.GESTURE_2) gestures = _hidpp20.get_gestures(device) param = gestures.param(prm) assert param.id == id assert param.index == index assert param.size == size assert param.value == value assert param.default_value == default_value assert param.param == id assert int(param) == id assert param.write(bytes.fromhex(write1)).hex().upper() == f"{index:02X}" + write1 + "FF" assert param.write(bytes.fromhex(write2)).hex().upper() == f"{index:02X}" + write2 + "FF" @pytest.mark.parametrize( "responses, id, s, byte_count, expected_value, expected_string", [ (fake_hidpp.responses_gestures, 1, hidpp20.SpecGesture.DVI_FIELD_WIDTH, 1, 8, "[dvi field width=8]"), (fake_hidpp.responses_gestures, 2, hidpp20.SpecGesture.FIELD_WIDTHS, 1, 8, "[field widths=8]"), (fake_hidpp.responses_gestures, 3, hidpp20.SpecGesture.PERIOD_UNIT, 2, 2048, "[period unit=2048]"), ], ) def test_spec(responses, id, s, byte_count, expected_value, expected_string): device = fake_hidpp.Device("GESTURE", responses=responses, feature=hidpp20_constants.SupportedFeature.GESTURE_2) gestures = _hidpp20.get_gestures(device) spec = gestures.specs[id] assert spec.id == id assert spec.spec == s assert spec.byte_count == byte_count assert spec.value == expected_value assert repr(spec) == expected_string def test_Gestures(): device = fake_hidpp.Device( "GESTURES", responses=fake_hidpp.responses_gestures, feature=hidpp20_constants.SupportedFeature.GESTURE_2 ) gestures = _hidpp20.get_gestures(device) assert gestures assert len(gestures.gestures) == 17 assert gestures.gesture(20) == gestures.gestures[20] assert gestures.gesture_enabled(20) is None assert gestures.gesture_enabled(1) is True assert gestures.gesture_enabled(45) is False assert gestures.enable_gesture(20) is None assert gestures.enable_gesture(45) == bytes.fromhex("01") assert gestures.disable_gesture(20) is None assert gestures.disable_gesture(45) == bytes.fromhex("00") assert len(gestures.params) == 1 assert gestures.param(4) == gestures.params[4] assert gestures.get_param(4) == 256 assert gestures.set_param(4, 128) is None assert len(gestures.specs) == 5 assert gestures.specs[2].value == 8 assert gestures.specs[4].value == 4 responses_backlight = [ fake_hidpp.Response("010118000001020003000400", 0x0400), fake_hidpp.Response("0101FF00020003000400", 0x0410, "0101FF00020003000400"), ] device_backlight = fake_hidpp.Device( "BACKLIGHT", responses=responses_backlight, feature=hidpp20_constants.SupportedFeature.BACKLIGHT2 ) def test_Backlight(): backlight = _hidpp20.get_backlight(device_backlight) result = backlight.write() assert backlight assert backlight.auto_supported assert backlight.temp_supported assert not backlight.perm_supported assert backlight.dho == 0x0002 assert backlight.dhi == 0x0003 assert backlight.dpow == 0x0004 assert result is not None @pytest.mark.parametrize( "hex, ID, color, speed, period, intensity, ramp, form", [ ("FFFFFFFFFFFFFFFFFFFFFF", None, None, None, None, None, None, None), ("0000000000000000000000", common.NamedInt(0x0, "Disabled"), None, None, None, None, None, None), ("0120304010000000000000", common.NamedInt(0x1, "Static"), 0x203040, None, None, None, 0x10, None), ("0220304010000000000000", common.NamedInt(0x2, "Pulse"), 0x203040, 0x10, None, None, None, None), ("0800000000000000000000", common.NamedInt(0x8, "Boot"), None, None, None, None, None, None), ("0300000000005000000000", common.NamedInt(0x3, "Cycle"), None, None, 0x5000, 0x00, None, None), ("0A20304010005020000000", common.NamedInt(0xA, "Breathe"), 0x203040, None, 0x1000, 0x20, None, 0x50), ("0B20304000100000000000", common.NamedInt(0xB, "Ripple"), 0x203040, None, 0x1000, None, None, None), ("0A01020300500407000000", common.NamedInt(0xA, "Breathe"), 0x010203, None, 0x0050, 0x07, None, 0x04), ], ) def test_LEDEffectSetting(hex, ID, color, speed, period, intensity, ramp, form): byt = bytes.fromhex(hex) setting = hidpp20.LEDEffectSetting.from_bytes(byt) assert setting.ID == ID if ID is None: assert setting.bytes == byt else: assert getattr(setting, "color", None) == color assert getattr(setting, "speed", None) == speed assert getattr(setting, "period", None) == period assert getattr(setting, "intensity", None) == intensity assert getattr(setting, "ramp", None) == ramp assert getattr(setting, "form", None) == form assert setting.to_bytes() == byt assert yaml.safe_load(yaml.dump(setting)) == setting assert yaml.safe_load(str(setting)) == setting @pytest.mark.parametrize( "feature, function, response, ID, capabilities, period", [ [ hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, 0x20, fake_hidpp.Response("0102000300040005", 0x0420, "010200"), 3, 4, 5, ], [ hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, 0x20, fake_hidpp.Response("0102000700080009", 0x0420, "010200"), 7, 8, 9, ], ], ) def test_LEDEffectInfo(feature, function, response, ID, capabilities, period): device = fake_hidpp.Device(feature=feature, responses=[response]) info = hidpp20.LEDEffectInfo(feature, function, device, 1, 2) assert info.zindex == 1 assert info.index == 2 assert info.ID == ID assert info.capabilities == capabilities assert info.period == period @pytest.mark.parametrize( "feature, function, offset, effect_function, responses, index, location, count, id_1", [ [hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, 0x10, 0, 0x20, fake_hidpp.zone_responses_1, 0, 1, 2, 0xB], [hidpp20_constants.SupportedFeature.RGB_EFFECTS, 0x00, 1, 0x00, fake_hidpp.zone_responses_2, 0, 1, 2, 2], ], ) def test_LEDZoneInfo(feature, function, offset, effect_function, responses, index, location, count, id_1): device = fake_hidpp.Device(feature=feature, responses=responses, offset=0x07) zone = hidpp20.LEDZoneInfo(feature, function, offset, effect_function, device, index) assert zone.index == index assert zone.location == location assert zone.count == count assert len(zone.effects) == count assert zone.effects[1].ID == id_1 @pytest.mark.parametrize( "responses, setting, expected_command", [ [fake_hidpp.zone_responses_1, hidpp20.LEDEffectSetting(ID=0), None], [fake_hidpp.zone_responses_1, hidpp20.LEDEffectSetting(ID=3, period=0x20, intensity=0x50), "000000000000000020500000"], [ fake_hidpp.zone_responses_1, hidpp20.LEDEffectSetting(ID=0xB, color=0x808080, period=0x20), "000180808000002000000000", ], ], ) def test_LEDZoneInfo_to_command(responses, setting, expected_command): device = fake_hidpp.Device(feature=hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, responses=responses, offset=0x07) zone = hidpp20.LEDZoneInfo(hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, 0x10, 0, 0x20, device, 0) command = zone.to_command(setting) assert command == (bytes.fromhex(expected_command) if expected_command is not None else None) @pytest.mark.parametrize( "feature, cls, responses, readable, count, count_0", [ [ hidpp20_constants.SupportedFeature.COLOR_LED_EFFECTS, hidpp20.LEDEffectsInfo, fake_hidpp.effects_responses_1, 1, 1, 2, ], [hidpp20_constants.SupportedFeature.RGB_EFFECTS, hidpp20.RGBEffectsInfo, fake_hidpp.effects_responses_2, 1, 1, 2], ], ) def test_LED_RGB_EffectsInfo(feature, cls, responses, readable, count, count_0): device = fake_hidpp.Device(feature=feature, responses=responses, offset=0x07) effects = cls(device) assert effects.readable == readable assert effects.count == count assert effects.zones[0].count == count_0 @pytest.mark.parametrize( "hex, expected_behavior, sector, address, typ, val, modifiers, data, byt", [ ("05010203", 0x0, 0x501, 0x0203, None, None, None, None, None), ("15020304", 0x1, 0x502, 0x0304, None, None, None, None, None), ("8000FFFF", 0x8, None, None, 0x00, None, None, None, None), ("80010102", 0x8, None, None, 0x01, 0x0102, None, None, None), ("80020454", 0x8, None, None, 0x02, 0x54, 0x04, None, None), ("80030454", 0x8, None, None, 0x03, 0x0454, None, None, None), ("900AFF01", 0x9, None, None, None, 0x0A, None, 0x01, None), ("709090A0", 0x7, None, None, None, None, None, None, b"\x70\x90\x90\xa0"), ], ) def test_button_bytes(hex, expected_behavior, sector, address, typ, val, modifiers, data, byt): button = hidpp20.Button.from_bytes(bytes.fromhex(hex)) assert getattr(button, "behavior", None) == expected_behavior assert getattr(button, "sector", None) == sector assert getattr(button, "address", None) == address assert getattr(button, "type", None) == typ assert getattr(button, "value", None) == val assert getattr(button, "modifiers", None) == modifiers assert getattr(button, "data", None) == data assert getattr(button, "bytes", None) == byt assert button.to_bytes().hex().upper() == hex assert yaml.safe_load(yaml.dump(button)).to_bytes().hex().upper() == hex hex1 = ( "01010290018003000700140028FFFFFF" "FFFF0000000000000000000000000000" "8000FFFF900AFF00800204548000FFFF" "900AFF00800204548000FFFF900AFF00" "800204548000FFFF900AFF0080020454" "8000FFFF900AFF00800204548000FFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "54004500370000000000000000000000" "00000000000000000000000000000000" "00000000000000000000000000000000" "0A01020300500407000000FFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFF7C81" ) hex2 = ( "01010290018003000700140028FFFFFF" "FFFF0000000000000000000000000000" "8000FFFF900AFF00800204548000FFFF" "900AFF00800204548000FFFF900AFF00" "800204548000FFFF900AFF0080020454" "8000FFFF900AFF00800204548000FFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "0A01020300500407000000FFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFF27C9" ) hex3 = ( "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" "FFFFFFFFFFFFFFFFFFFFFFFFFF2307" ) @pytest.mark.parametrize( "hex, name, sector, enabled, buttons, gbuttons, resolutions, button, lighting", [ (hex1, "TE7", 2, 1, 16, 0, [0x0190, 0x0380, 0x0700, 0x1400, 0x2800], "8000FFFF", "0A01020300500407000000"), (hex2, "", 2, 1, 16, 0, [0x0190, 0x0380, 0x0700, 0x1400, 0x2800], "8000FFFF", "0A01020300500407000000"), (hex3, "", 2, 1, 16, 0, [0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF], "FFFFFFFF", "FFFFFFFFFFFFFFFFFFFFFF"), ], ) def test_onboard_profile_bytes(hex, name, sector, enabled, buttons, gbuttons, resolutions, button, lighting): profile = hidpp20.OnboardProfile.from_bytes(sector, enabled, buttons, gbuttons, bytes.fromhex(hex)) assert profile.name == name assert profile.sector == sector assert profile.resolutions == resolutions assert profile.buttons[0].to_bytes().hex().upper() == button assert profile.lighting[0].to_bytes().hex().upper() == lighting assert profile.to_bytes(len(hex) // 2).hex().upper() == hex assert yaml.safe_load(yaml.dump(profile)).to_bytes(len(hex) // 2).hex().upper() == hex @pytest.mark.parametrize( "responses, name, count, buttons, gbuttons, sectors, size", [ (fake_hidpp.responses_profiles, "ONB", 1, 2, 2, 1, 254), (fake_hidpp.responses_profiles_rom, "ONB", 1, 2, 2, 1, 254), (fake_hidpp.responses_profiles_rom_2, "ONB", 1, 2, 2, 1, 254), ], ) def test_onboard_profiles_device(responses, name, count, buttons, gbuttons, sectors, size): device = fake_hidpp.Device( name, True, 4.5, responses=responses, feature=hidpp20_constants.SupportedFeature.ONBOARD_PROFILES, offset=0x9 ) device._profiles = None profiles = _hidpp20.get_profiles(device) assert profiles assert profiles.version == hidpp20.OnboardProfilesVersion assert profiles.name == name assert profiles.count == count assert profiles.buttons == buttons assert profiles.gbuttons == gbuttons assert profiles.sectors == sectors assert profiles.size == size assert len(profiles.profiles) == count yml_dump = yaml.dump(profiles) assert yaml.safe_load(yml_dump).to_bytes().hex() == profiles.to_bytes().hex() # --- Centurion (PRO X 2 LIGHTSPEED headset) tests --- device_centurion = fake_hidpp.Device("CENTURION", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) def test_centurion_parent_feature_discovery(): """Parent feature enumeration discovers CentPPBridge at index 3 and stores bridge index.""" dev = fake_hidpp.Device("CENT_PARENT", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) featuresarray = hidpp20.FeaturesArray(dev) dev.features = featuresarray result = featuresarray._check() assert result is True assert featuresarray.count == 5 # Parent features registered assert featuresarray[hidpp20_constants.SupportedFeature.ROOT] == 0 assert featuresarray[hidpp20_constants.SupportedFeature.FEATURE_SET] == 1 assert featuresarray[hidpp20_constants.SupportedFeature.CENTURION_DEVICE_INFO] == 2 assert featuresarray[hidpp20_constants.SupportedFeature.CENTURION_GENERIC_DFU] == 4 # Feature 0x0003 = CentPPBridge on Centurion (stored as DEVICE_FW_VERSION since same ID) assert featuresarray[hidpp20_constants.SupportedFeature.DEVICE_FW_VERSION] == 3 # Bridge index stored on device assert dev._centurion_bridge_index == 3 assert hasattr(dev, "_centurion_sub_features") def test_centurion_sub_device_feature_discovery(): """Sub-device feature discovery routes through bridge and populates _centurion_sub_features.""" dev = fake_hidpp.Device("CENT_SUB", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) # Set up bridge responses for sub-device discovery: # 1. CenturionRoot.GetFeature(0x0001) -> FeatureSet at sub-index 1 # 2. CenturionFeatureSet.GetCount (func 0) -> total feature count # 3. CenturionFeatureSet.GetFeatureId (func 0x10) per-index -> one feature each dev._bridge_responses = { # CenturionRoot(idx=0).GetFeature(func=0) with feature_id=0x0001 -> sub_fs_index=1 (0x00, 0x00, "0001"): bytes([0x01, 0x00, 0x00]), # CenturionFeatureSet(idx=1).GetCount (func=0) -> 3 features (0x01, 0x00, ""): bytes([0x03, 0x00, 0x00]), # CenturionFeatureSet(idx=1).GetFeatureId (func=0x10, index=N) -> one feature per response. # Response format: [remaining, feat_hi, feat_lo, type, flags] (0x01, 0x10, "00"): bytes([0x02, 0x06, 0x04, 0x00, 0x00]), # HEADSET_AUDIO_SIDETONE at sub-idx 0 (0x01, 0x10, "01"): bytes([0x01, 0x06, 0x01, 0x00, 0x00]), # HEADSET_MIC_MUTE at sub-idx 1 (0x01, 0x10, "02"): bytes([0x00, 0x06, 0x11, 0x00, 0x00]), # HEADSET_MIC_GAIN at sub-idx 2 } featuresarray = hidpp20.FeaturesArray(dev) dev.features = featuresarray featuresarray._check() # Sub-device features should be discovered assert hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE in dev._centurion_sub_features assert hidpp20_constants.SupportedFeature.HEADSET_MIC_MUTE in dev._centurion_sub_features assert hidpp20_constants.SupportedFeature.HEADSET_MIC_GAIN in dev._centurion_sub_features # Sub-device features should be in features array with their sub-device indices assert featuresarray[hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE] == 0 assert featuresarray[hidpp20_constants.SupportedFeature.HEADSET_MIC_MUTE] == 1 assert featuresarray[hidpp20_constants.SupportedFeature.HEADSET_MIC_GAIN] == 2 # _centurion_sub_indices should map ALL sub-device features to their sub-device indices assert dev._centurion_sub_indices[hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE] == 0 assert dev._centurion_sub_indices[hidpp20_constants.SupportedFeature.HEADSET_MIC_MUTE] == 1 assert dev._centurion_sub_indices[hidpp20_constants.SupportedFeature.HEADSET_MIC_GAIN] == 2 def test_centurion_feature_request_routes_sub_device(): """feature_request() routes sub-device features through centurion_bridge_request().""" dev = fake_hidpp.Device("CENT_ROUTE", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) # Manually set up sub-device state (simulating completed discovery) dev.features.count = 5 # mark discovery as complete so _check() short-circuits dev._centurion_bridge_index = 3 dev._centurion_sub_features = {hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE} dev.features[hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE] = 7 # sub-device index # Set up bridge response for GetSidetoneLevel dev._bridge_responses = { (7, 0x00, ""): bytes([0x01, 0x00, 0x32]), # mic_id=1, mute=0, level=50 } result = dev.feature_request(hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE, 0x00) assert result is not None assert result == bytes([0x01, 0x00, 0x32]) def test_centurion_feature_request_parent_not_routed(): """feature_request() does NOT route parent features through bridge.""" dev = fake_hidpp.Device("CENT_PARENT2", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) dev._centurion_bridge_index = 3 dev._centurion_sub_features = {hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE} # FeatureSet is a parent feature — should go through normal request(), not bridge featuresarray = hidpp20.FeaturesArray(dev) dev.features = featuresarray featuresarray._check() # CENTURION_DEVICE_INFO is a parent feature at index 2 — requesting it should # NOT go through bridge, it should go through the normal hidpp20.feature_request path assert hidpp20_constants.SupportedFeature.CENTURION_DEVICE_INFO not in dev._centurion_sub_features def test_centurion_bridge_request_write(): """centurion_bridge_request with no_reply=True returns None immediately.""" dev = fake_hidpp.Device("CENT_WRITE", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) dev._centurion_bridge_index = 3 dev._centurion_sub_features = {hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE} dev.features[hidpp20_constants.SupportedFeature.HEADSET_AUDIO_SIDETONE] = 7 dev._bridge_responses = {} # no responses needed for no_reply result = dev.centurion_bridge_request(7, 0x10, 0x32, no_reply=True) assert result is None def test_centurion_firmware_dedup(): """get_firmware_centurion() deduplicates identical firmware entries.""" # Simulate parent device that returns the same firmware for every entity index fw_response = "00" + "00" + "0105" + "04" + "44303031" + "00" * 20 # type=0, ver=1.05, name="D001" responses = fake_hidpp.r_centurion_headset + [fake_hidpp.Response(fw_response, 0x0210, f"{i:02X}") for i in range(8)] dev = fake_hidpp.Device("CENT_DEDUP", True, 2.6, responses, centurion=True) fw = _hidpp20.get_firmware_centurion(dev) # Should only get 1 entry, not 8 assert fw is not None assert len(fw) == 1 assert fw[0].name == "D001" def test_centurion_sub_device_firmware(): """get_firmware_centurion_sub() queries sub-device firmware via bridge.""" dev = fake_hidpp.Device("CENT_SUBFW", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) dev._centurion_bridge_index = 3 dev._centurion_sub_features = set() dev._centurion_sub_indices = {hidpp20_constants.SupportedFeature.CENTURION_DEVICE_INFO: 2} # Sub-device firmware: type=0 (firmware), ver=3.02, name="H001" dev._bridge_responses = { (2, 0x10, "00"): bytes([0x00, 0x00, 0x03, 0x02, 0x04]) + b"H001", (2, 0x10, "01"): bytes([0x00, 0x00, 0x03, 0x02, 0x04]) + b"H001", # duplicate → dedup stops } fw = _hidpp20.get_firmware_centurion_sub(dev) assert fw is not None assert len(fw) == 1 assert fw[0].name == "H001" assert fw[0].version == "3.02" def test_centurion_sub_device_serial(): """get_serial_centurion_sub() queries sub-device serial via bridge.""" dev = fake_hidpp.Device("CENT_SUBSER", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) dev._centurion_bridge_index = 3 dev._centurion_sub_features = set() dev._centurion_sub_indices = {hidpp20_constants.SupportedFeature.CENTURION_DEVICE_INFO: 2} dev._bridge_responses = { (2, 0x20, ""): bytes([0x0C]) + b"ABC123DEF456", } serial = _hidpp20.get_serial_centurion_sub(dev) assert serial == "ABC123DEF456" def test_centurion_sub_device_hardware_info(): """get_hardware_info_centurion_sub() queries sub-device hardware info via bridge.""" dev = fake_hidpp.Device("CENT_SUBHW", True, 2.6, fake_hidpp.r_centurion_headset, centurion=True) dev._centurion_bridge_index = 3 dev._centurion_sub_features = set() dev._centurion_sub_indices = {hidpp20_constants.SupportedFeature.CENTURION_DEVICE_INFO: 2} dev._bridge_responses = { (2, 0x00, ""): bytes([0x01, 0x03, 0x0A, 0xF7]), } hw_info = _hidpp20.get_hardware_info_centurion_sub(dev) assert hw_info is not None model_id, hw_rev, product_id = hw_info assert model_id == 1 assert hw_rev == 3 assert product_id == 0x0AF7 # --- CenturionReceiver tests --- class FakeCenturionDeviceInfo: """Minimal device_info for CenturionReceiver tests.""" def __init__(self, path="/dev/hidraw99", product_id="0AF0", product=None, centurion=True): self.path = path self.product_id = product_id self.product = product self.centurion = centurion self.isDevice = True class FakeLowLevel: """Minimal low_level for CenturionReceiver tests.""" def __init__(self, ping_protocol=2.6): self.ping_protocol = ping_protocol self.opened_paths = [] self.closed_handles = [] def open_path(self, path): self.opened_paths.append(path) return 0x99 def ping(self, handle, number, long_message=False): return self.ping_protocol def request(self, handle, devnumber, request_id, *params, **kwargs): return None def close(self, handle, *args, **kwargs): self.closed_handles.append(handle) return True def find_paired_node(self, receiver_path, index, timeout): return None def test_centurion_receiver_attributes(): """CenturionReceiver has correct receiver-like attributes.""" info = FakeCenturionDeviceInfo(product="PRO X 2 LIGHTSPEED") recv = CenturionReceiver(FakeLowLevel(), 0x99, info) assert recv.kind is None assert recv.isDevice is False assert recv.number == 0xFF assert recv.max_devices == 1 assert recv.may_unpair is False assert recv.re_pairs is False assert recv.handle == 0x99 assert recv.path == "/dev/hidraw99" assert recv.product_id == "0AF0" assert recv.name == "Lightspeed Headset Receiver" assert recv.serial is None assert recv.pairing is not None assert recv.pairing.lock_open is False assert bool(recv) is True def test_centurion_receiver_container_empty(): """Empty CenturionReceiver has correct container behavior.""" info = FakeCenturionDeviceInfo() recv = CenturionReceiver(FakeLowLevel(), 0x99, info) assert len(recv) == 0 assert recv.count() == 0 assert 1 not in recv assert list(recv) == [] assert recv.status_string() == "No devices." def test_centurion_receiver_container_with_device(): """CenturionReceiver with a child device has correct container behavior.""" info = FakeCenturionDeviceInfo() recv = CenturionReceiver(FakeLowLevel(), 0x99, info) # Simulate adding a child device (a simple mock) class FakeChild: number = 1 def close(self): pass recv._devices[1] = FakeChild() assert len(recv) == 1 assert recv.count() == 1 assert 1 in recv assert 2 not in recv assert recv[1] is not None assert recv.status_string() == "1 device connected." with pytest.raises(IndexError): recv[2] def test_centurion_receiver_child_device_kind_headset(): """notify_devices() seeds the headset child with kind=headset via pairing_info, so the headphone icon shows even when the headset is powered off at startup.""" info = FakeCenturionDeviceInfo(product="PRO X 2 LIGHTSPEED") recv = CenturionReceiver(FakeLowLevel(), 0x99, info) recv._pending = False recv._dongle_features = [] recv.notify_devices() child = recv[1] child.online = False assert child.kind == "headset" def test_centurion_receiver_enable_connection_notifications(): """CenturionReceiver.enable_connection_notifications() returns False.""" info = FakeCenturionDeviceInfo() recv = CenturionReceiver(FakeLowLevel(), 0x99, info) assert recv.enable_connection_notifications() is False assert recv.remaining_pairings() is None def test_centurion_receiver_device_codename(): """CenturionReceiver.device_codename() returns USB product name.""" info = FakeCenturionDeviceInfo(product="PRO X 2 LIGHTSPEED") recv = CenturionReceiver(FakeLowLevel(), 0x99, info) assert recv.device_codename(1) == "PRO X 2 LIGHTSPEED" def test_centurion_receiver_close(): """CenturionReceiver.close() closes handle and clears devices.""" low_level = FakeLowLevel() info = FakeCenturionDeviceInfo() recv = CenturionReceiver(low_level, 0x99, info) class FakeChild: closed = False def close(self): self.closed = True child = FakeChild() recv._devices[1] = child recv.close() assert recv.handle is None assert len(recv._devices) == 0 assert child.closed is True assert 0x99 in low_level.closed_handles assert bool(recv) is False def test_centurion_receiver_changed_callback(): """CenturionReceiver.changed() invokes status_callback.""" info = FakeCenturionDeviceInfo() recv = CenturionReceiver(FakeLowLevel(), 0x99, info) calls = [] recv.status_callback = lambda *args, **kwargs: calls.append((args, kwargs)) recv.changed() assert len(calls) == 1 assert calls[0][0][0] is recv Solaar-1.1.20/tests/logitech_receiver/test_hidpp20_simple.py000066400000000000000000000413161522022367600241020ustar00rootroot00000000000000## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. import pytest from logitech_receiver import common from logitech_receiver import hidpp20 from logitech_receiver import hidpp20_constants from logitech_receiver.hidpp20_constants import SupportedFeature from . import fake_hidpp _hidpp20 = hidpp20.Hidpp20() def test_get_firmware(): responses = [ fake_hidpp.Response("02FFFF", 0x0400), fake_hidpp.Response("01414243030401000101000102030405", 0x0410, "00"), fake_hidpp.Response("02414243030401000101000102030405", 0x0410, "01"), ] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_FW_VERSION) result = _hidpp20.get_firmware(device) assert len(result) == 2 assert isinstance(result[0], common.FirmwareInfo) assert isinstance(result[1], common.FirmwareInfo) def test_get_ids(): responses = [fake_hidpp.Response("FF12345678000D123456789ABC", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_FW_VERSION) unitId, modelId, tid_map = _hidpp20.get_ids(device) assert unitId == "12345678" assert modelId == "123456789ABC" assert tid_map == {"btid": "1234", "wpid": "5678", "usbid": "9ABC"} def test_get_kind(): responses = [fake_hidpp.Response("00", 0x0420)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_NAME) result = _hidpp20.get_kind(device) assert result == "keyboard" assert result == 1 def test_get_name(): responses = [ fake_hidpp.Response("12", 0x0400), fake_hidpp.Response("4142434445464748494A4B4C4D4E4F", 0x0410, "00"), fake_hidpp.Response("505152530000000000000000000000", 0x0410, "0F"), ] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_NAME) result = _hidpp20.get_name(device) assert result == "ABCDEFGHIJKLMNOPQR" def test_get_friendly_name(): responses = [ fake_hidpp.Response("12", 0x0400), fake_hidpp.Response("004142434445464748494A4B4C4D4E", 0x0410, "00"), fake_hidpp.Response("0E4F50515253000000000000000000", 0x0410, "0E"), ] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.DEVICE_FRIENDLY_NAME) result = _hidpp20.get_friendly_name(device) assert result == "ABCDEFGHIJKLMNOPQR" def test_get_battery_status(): responses = [fake_hidpp.Response("502000FFFF", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.BATTERY_STATUS) feature, battery = _hidpp20.get_battery_status(device) assert feature == SupportedFeature.BATTERY_STATUS assert battery.level == 80 assert battery.next_level == 32 assert battery.status == common.BatteryStatus.DISCHARGING def test_get_battery_voltage(): responses = [fake_hidpp.Response("1000FFFFFF", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.BATTERY_VOLTAGE) feature, battery = _hidpp20.get_battery_voltage(device) assert feature == SupportedFeature.BATTERY_VOLTAGE assert battery.level == 92 assert common.BatteryStatus.RECHARGING in battery.status assert battery.voltage == 0x1000 def test_get_battery_unified(): responses = [fake_hidpp.Response("500100FFFF", 0x0410)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.UNIFIED_BATTERY) feature, battery = _hidpp20.get_battery_unified(device) assert feature == SupportedFeature.UNIFIED_BATTERY assert battery.level == 80 assert battery.status == common.BatteryStatus.DISCHARGING def test_get_adc_measurement(): responses = [fake_hidpp.Response("100003", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.ADC_MEASUREMENT) feature, battery = _hidpp20.get_adc_measurement(device) assert feature == SupportedFeature.ADC_MEASUREMENT assert battery.level == 92 assert battery.status == common.BatteryStatus.RECHARGING assert battery.voltage == 0x1000 def test_get_battery(): responses = [fake_hidpp.Response("502000FFFF", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.BATTERY_STATUS) feature, battery = _hidpp20.get_battery(device, SupportedFeature.BATTERY_STATUS) assert feature == SupportedFeature.BATTERY_STATUS assert battery.level == 80 assert battery.next_level == 32 assert battery.status == common.BatteryStatus.DISCHARGING def test_get_battery_none(): responses = [ fake_hidpp.Response(None, 0x0000, f"{int(SupportedFeature.BATTERY_STATUS):0>4X}"), fake_hidpp.Response(None, 0x0000, f"{int(SupportedFeature.BATTERY_VOLTAGE):0>4X}"), fake_hidpp.Response("500100ffff", 0x0410), ] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.UNIFIED_BATTERY) feature, battery = _hidpp20.get_battery(device, None) assert feature == SupportedFeature.UNIFIED_BATTERY assert battery.level == 80 assert battery.status == common.BatteryStatus.DISCHARGING # get_keys is in test_hidpp20_complex # get_remap_keys is in test_hidpp20_complex # TODO get_gestures is complex # get_backlight is in test_hidpp20_complex # get_profiles is in test_hidpp20_complex def test_get_mouse_pointer_info(): responses = [fake_hidpp.Response("01000A", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.MOUSE_POINTER) result = _hidpp20.get_mouse_pointer_info(device) assert result == { "dpi": 0x100, "acceleration": "med", "suggest_os_ballistics": False, "suggest_vertical_orientation": True, } def test_get_vertical_scrolling_info(): responses = [fake_hidpp.Response("01080C", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.VERTICAL_SCROLLING) result = _hidpp20.get_vertical_scrolling_info(device) assert result == {"roller": "standard", "ratchet": 8, "lines": 12} def test_get_hi_res_scrolling_info(): responses = [fake_hidpp.Response("0102", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.HI_RES_SCROLLING) mode, resolution = _hidpp20.get_hi_res_scrolling_info(device) assert mode == 1 assert resolution == 2 def test_get_pointer_speed_info(): responses = [fake_hidpp.Response("0102", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.POINTER_SPEED) result = _hidpp20.get_pointer_speed_info(device) assert result == 0x0102 / 256 def test_get_lowres_wheel_status(): responses = [fake_hidpp.Response("01", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.LOWRES_WHEEL) result = _hidpp20.get_lowres_wheel_status(device) assert result == "HID++" def test_get_hires_wheel(): responses = [ fake_hidpp.Response("010C", 0x0400), fake_hidpp.Response("05FF", 0x0410), fake_hidpp.Response("03FF", 0x0430), ] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.HIRES_WHEEL) multi, has_invert, has_ratchet, inv, res, target, ratchet = _hidpp20.get_hires_wheel(device) assert multi == 1 assert has_invert is True assert has_ratchet is True assert inv is True assert res is False assert target is True assert ratchet is True def test_get_new_fn_inversion(): responses = [fake_hidpp.Response("0300", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.NEW_FN_INVERSION) result = _hidpp20.get_new_fn_inversion(device) assert result == (True, False) @pytest.fixture def mock_gethostname(mocker): mocker.patch("socket.gethostname", return_value="ABCDEFG.foo.org") @pytest.mark.parametrize( "responses, expected_result", [ ([fake_hidpp.Response(None, 0x0400)], {}), ([fake_hidpp.Response("02000000", 0x0400)], {}), ( [ fake_hidpp.Response("03000200", 0x0400), fake_hidpp.Response("FF01FFFF05FFFF", 0x0410, "00"), fake_hidpp.Response("0000414243444500FFFFFFFFFF", 0x0430, "0000"), fake_hidpp.Response("FF01FFFF10FFFF", 0x0410, "01"), fake_hidpp.Response("01004142434445464748494A4B4C4D", 0x0430, "0100"), fake_hidpp.Response("01134E4F5000FFFFFFFFFFFFFFFFFF", 0x0430, "010E"), fake_hidpp.Response("000000000008", 0x0410, "00"), fake_hidpp.Response("0208", 0x0440, "000041424344454647"), ], {0: (True, "ABCDEFG"), 1: (True, "ABCDEFGHIJKLMNO")}, ), ], ) def test_get_host_names(responses, expected_result, mock_gethostname): device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.HOSTS_INFO) result = _hidpp20.get_host_names(device) assert result == expected_result @pytest.mark.parametrize( "responses, expected_result", [ ([fake_hidpp.Response(None, 0x0400)], None), ( [ fake_hidpp.Response("03000002", 0x0400), fake_hidpp.Response("000000000008", 0x0410, "02"), fake_hidpp.Response("020E", 0x0440, "02004142434445464748494A4B4C4D4E"), ], True, ), ( [ fake_hidpp.Response("03000002", 0x0400), fake_hidpp.Response("000000000014", 0x0410, "02"), fake_hidpp.Response("020E", 0x0440, "02004142434445464748494A4B4C4D4E"), fake_hidpp.Response("0214", 0x0440, "020E4F505152535455565758"), ], True, ), ], ) def test_set_host_name(responses, expected_result): device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.HOSTS_INFO) result = _hidpp20.set_host_name(device, "ABCDEFGHIJKLMNOPQRSTUVWX") assert result == expected_result def test_get_onboard_mode(): responses = [fake_hidpp.Response("03FFFFFFFF", 0x0420)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.ONBOARD_PROFILES) result = _hidpp20.get_onboard_mode(device) assert result == 0x3 def test_set_onboard_mode(): responses = [fake_hidpp.Response("03FFFFFFFF", 0x0410, "03")] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.ONBOARD_PROFILES) res = _hidpp20.set_onboard_mode(device, 0x3) assert res is not None @pytest.mark.parametrize( "responses, expected_result", [ ([fake_hidpp.Response("03FFFF", 0x0420)], "1ms"), ( [ fake_hidpp.Response(None, 0x0000, f"{int(SupportedFeature.REPORT_RATE):04X}"), fake_hidpp.Response("04FFFF", 0x0420), ], "500us", ), ], ) def test_get_polling_rate( responses, expected_result, ): device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.EXTENDED_ADJUSTABLE_REPORT_RATE) result = _hidpp20.get_polling_rate(device) assert result == expected_result def test_get_remaining_pairing(): responses = [fake_hidpp.Response("03FFFF", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.REMAINING_PAIRING) result = _hidpp20.get_remaining_pairing(device) assert result == 0x03 def test_config_change(): responses = [fake_hidpp.Response("03FFFF", 0x0410, "02")] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.CONFIG_CHANGE) result = _hidpp20.config_change(device, 0x2) assert result == bytes.fromhex("03FFFF") def test_get_configuration_cookie(): responses = [fake_hidpp.Response("12345678", 0x0400)] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.CONFIG_CHANGE) result = _hidpp20.get_configuration_cookie(device) assert result == bytes.fromhex("1234") def test_set_configuration_complete_explicit_cookie(): # An explicit cookie is sent unchanged. responses = [fake_hidpp.Response("00", 0x0410, "1234")] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.CONFIG_CHANGE) result = _hidpp20.set_configuration_complete(device, cookie=bytes.fromhex("1234")) assert result == bytes.fromhex("00") def test_set_configuration_complete_monotonic_counter(): # With no cookie, sends a host-side monotonic counter, +1 per call. hidpp20.Hidpp20._session_cookie = 0x1233 responses = [ fake_hidpp.Response("00", 0x0410, "1234"), fake_hidpp.Response("00", 0x0410, "1235"), ] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.CONFIG_CHANGE) assert _hidpp20.set_configuration_complete(device) == bytes.fromhex("00") assert _hidpp20.set_configuration_complete(device) == bytes.fromhex("00") def test_set_configuration_complete_skips_zero(): # Counter at 0xFFFF wraps to 1, never 0. hidpp20.Hidpp20._session_cookie = 0xFFFF responses = [fake_hidpp.Response("00", 0x0410, "0001")] device = fake_hidpp.Device(responses=responses, feature=SupportedFeature.CONFIG_CHANGE) assert _hidpp20.set_configuration_complete(device) == bytes.fromhex("00") def test_decipher_battery_status(): report = b"\x50\x20\x00\xff\xff" feature, battery = hidpp20.decipher_battery_status(report) assert feature == SupportedFeature.BATTERY_STATUS assert battery.level == 80 assert battery.next_level == 32 assert battery.status == common.BatteryStatus.DISCHARGING def test_decipher_battery_voltage(): report = b"\x10\x00\xff\xff\xff" feature, battery = hidpp20.decipher_battery_voltage(report) assert feature == SupportedFeature.BATTERY_VOLTAGE assert battery.level == 92 assert common.BatteryStatus.RECHARGING in battery.status assert battery.voltage == 0x1000 def test_decipher_battery_unified(): report = b"\x50\x01\x00\xff\xff" feature, battery = hidpp20.decipher_battery_unified(report) assert feature == SupportedFeature.UNIFIED_BATTERY assert battery.level == 80 assert battery.status == common.BatteryStatus.DISCHARGING def test_decipher_adc_measurement(): report = b"\x10\x00\x03" feature, battery = hidpp20.decipher_adc_measurement(report) assert feature == SupportedFeature.ADC_MEASUREMENT assert battery.level == 92 assert battery.status == common.BatteryStatus.RECHARGING assert battery.voltage == 0x1000 @pytest.mark.parametrize( "code, expected_flags", [ (0x01, ["unknown:000001"]), (0x0F, ["unknown:00000F"]), (0xF0, ["internal", "hidden", "obsolete", "unknown:000010"]), (0x20, ["internal"]), (0x33, ["internal", "unknown:000013"]), (0x3F, ["internal", "unknown:00001F"]), (0x40, ["hidden"]), (0x50, ["hidden", "unknown:000010"]), (0x5F, ["hidden", "unknown:00001F"]), (0x7F, ["internal", "hidden", "unknown:00001F"]), (0x80, ["obsolete"]), (0xA0, ["internal", "obsolete"]), (0xE0, ["internal", "hidden", "obsolete"]), (0xFF, ["internal", "hidden", "obsolete", "unknown:00001F"]), ], ) def test_feature_flag_names(code, expected_flags): flags = common.flag_names(hidpp20_constants.FeatureFlag, code) assert list(flags) == expected_flags @pytest.mark.parametrize( "code, expected_name", [ (0x00, "Unknown Location"), (0x03, "Left Side"), ], ) def test_led_zone_locations(code, expected_name): assert hidpp20.LEDZoneLocations[code] == expected_name @pytest.mark.parametrize( "millivolt, expected_percentage", [ (-1234, 0), (500, 0), (2000, 0), (3500, 0), (3519, 0), (3520, 1), (3559, 1), (3579, 2), (3646, 5), (3671, 10), (3717, 20), (3751, 30), (3778, 40), (3811, 50), (3859, 60), (3922, 70), (3989, 80), (4067, 90), (4180, 99), (4181, 100), (4186, 100), (4500, 100), ], ) def test_estimate_battery_level_percentage(millivolt, expected_percentage): percentage = hidpp20.estimate_battery_level_percentage(millivolt) assert percentage == expected_percentage Solaar-1.1.20/tests/logitech_receiver/test_notifications.py000066400000000000000000000322521522022367600241330ustar00rootroot00000000000000import pytest from logitech_receiver import notifications from logitech_receiver.base import HIDPPNotification from logitech_receiver.common import Notification from logitech_receiver.hidpp10_constants import BoltPairingError from logitech_receiver.hidpp10_constants import PairingError from logitech_receiver.hidpp10_constants import Registers from logitech_receiver.hidpp20_constants import SupportedFeature from logitech_receiver.receiver import Receiver from . import fake_hidpp class MockLowLevelInterface: def open_path(self, path): pass def find_paired_node_wpid(self, receiver_path: str, index: int): pass def ping(self, handle, number, long_message=False): pass def request(self, handle, devnumber, request_id, *params, **kwargs): pass def find_paired_node(self, receiver_path: str, index: int, timeout: int): return None def close(self, device_handle) -> None: pass @pytest.mark.parametrize( "sub_id, notification_data, expected_error, expected_new_device", [ (Registers.DISCOVERY_STATUS_NOTIFICATION, b"\x01", BoltPairingError.DEVICE_TIMEOUT, None), ( Registers.DEVICE_DISCOVERY_NOTIFICATION, b"\x01\x01\x01\x01\x01\x01\x01\x01\x01", None, None, ), (Registers.PAIRING_STATUS_NOTIFICATION, b"\x02", BoltPairingError.FAILED, None), (Notification.PAIRING_LOCK, b"\x01", PairingError.DEVICE_TIMEOUT, None), (Notification.PAIRING_LOCK, b"\x02", PairingError.DEVICE_NOT_SUPPORTED, None), (Notification.PAIRING_LOCK, b"\x03", PairingError.TOO_MANY_DEVICES, None), (Notification.PAIRING_LOCK, b"\x06", PairingError.SEQUENCE_TIMEOUT, None), (Registers.PASSKEY_REQUEST_NOTIFICATION, b"\x06", None, None), (Registers.PASSKEY_PRESSED_NOTIFICATION, b"\x06", None, None), ], ) def test_process_receiver_notification(sub_id, notification_data, expected_error, expected_new_device): receiver: Receiver = Receiver(MockLowLevelInterface(), None, {}, True, None, None) notification = HIDPPNotification(0, 0, sub_id, 0x02, notification_data) result = notifications.process_receiver_notification(receiver, notification) assert result assert receiver.pairing.error == (None if expected_error is None else expected_error.label) assert receiver.pairing.new_device is expected_new_device @pytest.mark.parametrize( "hidpp_notification, expected", [ (HIDPPNotification(0, 0, sub_id=Registers.BATTERY_STATUS, address=0, data=b"0x01"), False), (HIDPPNotification(0, 0, sub_id=Notification.NO_OPERATION, address=0, data=b"0x01"), False), (HIDPPNotification(0, 0, sub_id=0x40, address=0, data=b"0x01"), True), ], ) def test_process_device_notification(hidpp_notification, expected): device = fake_hidpp.Device() result = notifications.process_device_notification(device, hidpp_notification) assert result == expected @pytest.mark.parametrize( "hidpp_notification, expected", [ (HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.CONNECTED, address=0, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.RAW_INPUT, address=0, data=b"0x01"), None), ], ) def test_process_dj_notification(hidpp_notification, expected): device = fake_hidpp.Device() result = notifications._process_dj_notification(device, hidpp_notification) assert result == expected @pytest.mark.parametrize( "hidpp_notification, expected", [ (HIDPPNotification(0, 0, sub_id=Registers.BATTERY_STATUS, address=0, data=b"\x01\x00"), True), (HIDPPNotification(0, 0, sub_id=Registers.BATTERY_CHARGE, address=0, data=b"0x01\x00"), True), (HIDPPNotification(0, 0, sub_id=Notification.RAW_INPUT, address=0, data=b"0x01"), None), ], ) def test_process_hidpp10_custom_notification(hidpp_notification, expected): device = fake_hidpp.Device() result = notifications._process_hidpp10_custom_notification(device, hidpp_notification) assert result == expected @pytest.mark.parametrize( "hidpp_notification, expected", [ (HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0x00, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0x02, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0x03, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.DJ_PAIRING, address=0x03, data=b"0x4040"), True), (HIDPPNotification(0, 0, sub_id=Notification.RAW_INPUT, address=0x00, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.POWER, address=0x00, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.POWER, address=0x01, data=b"0x01"), True), (HIDPPNotification(0, 0, sub_id=Notification.PAIRING_LOCK, address=0x01, data=b"0x01"), None), ], ) def test_process_hidpp10_notification(hidpp_notification, expected): fake_device = fake_hidpp.Device() fake_device.receiver = ["rec1", "rec2"] result = notifications._process_hidpp10_notification(fake_device, hidpp_notification) assert result == expected @pytest.mark.parametrize( "hidpp_notification, feature", [ ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.BATTERY_STATUS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"0x01"), SupportedFeature.BATTERY_STATUS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.BATTERY_VOLTAGE, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x05, data=b"0x01"), SupportedFeature.BATTERY_VOLTAGE, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.UNIFIED_BATTERY, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"0x01"), SupportedFeature.UNIFIED_BATTERY, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.ADC_MEASUREMENT, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"0x01"), SupportedFeature.ADC_MEASUREMENT, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"01234GOOD"), SupportedFeature.SOLAR_DASHBOARD, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b"01234GOOD"), SupportedFeature.SOLAR_DASHBOARD, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x20, data=b"01234GOOD"), SupportedFeature.SOLAR_DASHBOARD, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"01234GOOD"), SupportedFeature.SOLAR_DASHBOARD, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"CHARGENOTGOOD"), SupportedFeature.SOLAR_DASHBOARD, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"\x01\x01\x02"), SupportedFeature.WIRELESS_DEVICE_STATUS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"0x01"), SupportedFeature.WIRELESS_DEVICE_STATUS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.TOUCHMOUSE_RAW_POINTS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b"0x01"), SupportedFeature.TOUCHMOUSE_RAW_POINTS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x05, data=b"0x01"), SupportedFeature.TOUCHMOUSE_RAW_POINTS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.REPROG_CONTROLS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"0x01"), SupportedFeature.REPROG_CONTROLS, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.BACKLIGHT2, ), ( HIDPPNotification( 0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"\x01\x01\x01\x01\x01\x01\x01\x01" ), SupportedFeature.REPROG_CONTROLS_V4, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b"0x01"), SupportedFeature.REPROG_CONTROLS_V4, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x20, data=b"0x01"), SupportedFeature.REPROG_CONTROLS_V4, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.HIRES_WHEEL, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b"0x01"), SupportedFeature.HIRES_WHEEL, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x02, data=b"0x01"), SupportedFeature.HIRES_WHEEL, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.ONBOARD_PROFILES, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x20, data=b"0x01"), SupportedFeature.ONBOARD_PROFILES, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x00, data=b"0x01"), SupportedFeature.BRIGHTNESS_CONTROL, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x10, data=b"0x01"), SupportedFeature.BRIGHTNESS_CONTROL, ), ( HIDPPNotification(0, 0, sub_id=Notification.CONNECT_DISCONNECT, address=0x20, data=b"0x01"), SupportedFeature.BRIGHTNESS_CONTROL, ), ], ) def test_process_feature_notification(mocker, hidpp_notification, feature): fake_device = fake_hidpp.Device() fake_device.receiver = ["rec1", "rec2"] result = notifications._process_feature_notification(fake_device, hidpp_notification) assert result is True def test_process_receiver_notification_invalid(mocker): invalid_sub_id = 0x30 notification_data = b"\x02" notification = HIDPPNotification(0, 0, invalid_sub_id, 0, notification_data) mock_receiver = mocker.Mock() with pytest.raises(AssertionError): notifications.process_receiver_notification(mock_receiver, notification) @pytest.mark.parametrize( "sub_id, notification_data, expected", [ (Notification.NO_OPERATION, b"\x00", False), ], ) def test_process_device_notification_extended(mocker, sub_id, notification_data, expected): device = mocker.Mock() device.handle_notification.return_value = None device.protocol = 2.0 notification = HIDPPNotification(0, 0, sub_id, 0, notification_data) result = notifications.process_device_notification(device, notification) assert result == expected def test_handle_device_discovery(): receiver: Receiver = Receiver(MockLowLevelInterface(), None, {}, True, None, None) sub_id = Registers.DISCOVERY_STATUS_NOTIFICATION data = b"\x01\x02\x03\x04\x05\x06" notification = HIDPPNotification(0, 0, sub_id, 0, data) result = notifications.handle_device_discovery(receiver, notification) assert result def test_handle_passkey_request(mocker): receiver_mock = mocker.Mock() data = b"\x01" notification = HIDPPNotification(0, 0, 0, 0, data) result = notifications.handle_passkey_request(receiver_mock, notification) assert result is True def test_handle_passkey_pressed(mocker): receiver = mocker.Mock() sub_id = Registers.DISCOVERY_STATUS_NOTIFICATION data = b"\x01\x02\x03\x04\x05\x06" notification = HIDPPNotification(0, 0, sub_id, 0, data) result = notifications.handle_passkey_pressed(receiver, notification) assert result is True Solaar-1.1.20/tests/logitech_receiver/test_receiver.py000066400000000000000000000274341522022367600230740ustar00rootroot00000000000000from dataclasses import dataclass from functools import partial from unittest import mock import pytest from logitech_receiver import base from logitech_receiver import common from logitech_receiver import exceptions from logitech_receiver import receiver from . import fake_hidpp @pytest.fixture def nano_recv(): device_info = DeviceInfo("12", product_id=0xC534) mock_low_level = LowLevelInterfaceFake(responses_lacking) yield receiver.create_receiver(mock_low_level, device_info, lambda x: x) class LowLevelInterfaceFake: def __init__(self, responses=None): self.responses = responses def open_path(self, path): return fake_hidpp.open_path(path) def product_information(self, usb_id: int) -> dict: return base.product_information(usb_id) def find_paired_node(self, receiver_path: str, index: int, timeout: int): return None def request(self, response, *args, **kwargs): func = partial(fake_hidpp.request, self.responses) return func(response, *args, **kwargs) def ping(self, response, *args, **kwargs): func = partial(fake_hidpp.ping, self.responses) return func(response, *args, **kwargs) def close(self, *args, **kwargs): pass @pytest.mark.parametrize( "index, expected_kind", [ (0, None), (1, 2), # mouse (2, 2), # mouse (3, 1), # keyboard (4, 3), # numpad (5, None), ], ) def test_get_kind_from_index(index, expected_kind): mock_receiver = mock.Mock() if expected_kind: assert receiver._get_kind_from_index(mock_receiver, index) == expected_kind else: with pytest.raises(exceptions.NoSuchDevice): receiver._get_kind_from_index(mock_receiver, index) @dataclass class DeviceInfo: path: str vendor_id: int = 1133 product_id: int = 0xC52B responses_unifying = [ fake_hidpp.Response("000000", 0x8003, "FF"), fake_hidpp.Response("000300", 0x8102), fake_hidpp.Response("0316CC9CB40506220000000000000000", 0x83B5, "03"), fake_hidpp.Response("20200840820402020700000000000000", 0x83B5, "20"), fake_hidpp.Response("21211420110400010D1A000000000000", 0x83B5, "21"), fake_hidpp.Response("22220840660402010700000000020000", 0x83B5, "22"), fake_hidpp.Response("30198E3EB80600000001000000000000", 0x83B5, "30"), fake_hidpp.Response("31811119511A40000002000000000000", 0x83B5, "31"), fake_hidpp.Response("32112C46EA1E40000003000000000000", 0x83B5, "32"), fake_hidpp.Response("400B4D58204D61737465722033000000", 0x83B5, "40"), fake_hidpp.Response("41044B35323020202020202020202020", 0x83B5, "41"), fake_hidpp.Response("42054372616674000000000000000000", 0x83B5, "42"), fake_hidpp.Response("012411", 0x81F1, "01"), fake_hidpp.Response("020036", 0x81F1, "02"), fake_hidpp.Response("03AAAC", 0x81F1, "03"), fake_hidpp.Response("040209", 0x81F1, "04"), ] responses_c534 = [ fake_hidpp.Response("000000", 0x8003, "FF", handle=0x12), fake_hidpp.Response("000209", 0x8102, handle=0x12), fake_hidpp.Response("0316CC9CB40502220000000000000000", 0x83B5, "03", handle=0x12), fake_hidpp.Response("00000445AB", 0x83B5, "04", handle=0x12), ] responses_unusual = [ fake_hidpp.Response("000000", 0x8003, "FF", handle=0x13), fake_hidpp.Response("000300", 0x8102, handle=0x13), fake_hidpp.Response("00000445AB", 0x83B5, "04", handle=0x13), fake_hidpp.Response("0326CC9CB40508220000000000000000", 0x83B5, "03", handle=0x13), ] responses_lacking = [ fake_hidpp.Response("000000", 0x8003, "FF", handle=0x14), fake_hidpp.Response("000300", 0x8102, handle=0x14), ] mouse_info = { "kind": common.NamedInt(2, "mouse"), "polling": "8ms", "power_switch": common.NamedInt(1, "base"), "serial": "198E3EB8", "wpid": "4082", } c534_info = {"kind": common.NamedInt(0, "unknown"), "polling": "", "power_switch": "(unknown)", "serial": None, "wpid": "45AB"} @pytest.mark.parametrize( "device_info, responses, handle, serial, max_devices, ", [ (DeviceInfo(path=None), [], False, None, None), (DeviceInfo(path=11), [], None, None, None), (DeviceInfo(path="11"), responses_unifying, 0x11, "16CC9CB4", 6), (DeviceInfo(path="12", product_id=0xC534), responses_c534, 0x12, "16CC9CB4", 2), (DeviceInfo(path="12", product_id=0xC539), responses_c534, 0x12, "16CC9CB4", 2), (DeviceInfo(path="13"), responses_unusual, 0x13, "26CC9CB4", 1), (DeviceInfo(path="14"), responses_lacking, 0x14, None, 1), ], ) def test_receiver_factory_create_receiver(device_info, responses, handle, serial, max_devices): mock_low_level = LowLevelInterfaceFake(responses) if handle is False: with pytest.raises(Exception): # noqa: B017 receiver.create_receiver(mock_low_level, device_info, lambda x: x) elif handle is None: r = receiver.create_receiver(mock_low_level, device_info, lambda x: x) assert r is None else: r = receiver.create_receiver(mock_low_level, device_info, lambda x: x) assert r.handle == handle assert r.serial == serial assert r.max_devices == max_devices @pytest.mark.parametrize( "device_info, responses, firmware, codename, remaining_pairings, pairing_info, count", [ (DeviceInfo("11"), responses_unifying, 3, "K520", -1, mouse_info, 3), (DeviceInfo("12", product_id=0xC534), responses_c534, None, None, 4, c534_info, 2), (DeviceInfo("13", product_id=0xCCCC), responses_unusual, None, None, -1, c534_info, 3), ], ) def test_receiver_factory_props(device_info, responses, firmware, codename, remaining_pairings, pairing_info, count): mock_low_level = LowLevelInterfaceFake(responses) r = receiver.create_receiver(mock_low_level, device_info, lambda x: x) assert len(r.firmware) == firmware if firmware is not None else firmware is None assert r.device_codename(2) == codename assert r.remaining_pairings() == remaining_pairings assert r.device_pairing_information(1) == pairing_info assert r.count() == count @pytest.mark.parametrize( "device_info, responses, status_str, strng", [ (DeviceInfo("11"), responses_unifying, "No paired devices.", ""), (DeviceInfo("12", product_id=0xC534), responses_c534, "No paired devices.", ""), (DeviceInfo("13", product_id=0xCCCC), responses_unusual, "No paired devices.", ""), ], ) def test_receiver_factory_string(device_info, responses, status_str, strng): mock_low_level = LowLevelInterfaceFake(responses) r = receiver.create_receiver(mock_low_level, device_info, lambda x: x) assert r.status_string() == status_str assert str(r) == strng @pytest.mark.parametrize( "device_info, responses", [ (DeviceInfo("14"), responses_lacking), (DeviceInfo("14", product_id="C534"), responses_lacking), ], ) def test_receiver_factory_no_device(device_info, responses): mock_low_level = LowLevelInterfaceFake(responses) r = receiver.create_receiver(mock_low_level, device_info, lambda x: x) with pytest.raises(exceptions.NoSuchDevice): r.device_pairing_information(1) @pytest.mark.parametrize( "address, data, expected_online, expected_encrypted", [ (0x03, b"\x01\x02\x03", True, False), (0x10, b"\x61\x02\x03", False, True), ], ) def test_notification_information_nano_receiver(nano_recv, address, data, expected_online, expected_encrypted): _number = 0 notification = base.HIDPPNotification( report_id=0x01, devnumber=0x52C, sub_id=0, address=address, data=data, ) online, encrypted, wpid, kind = nano_recv.notification_information(_number, notification) assert online == expected_online assert encrypted == expected_encrypted assert wpid == "0302" assert kind == "keyboard" def test_extract_serial_number(): response = b'\x03\x16\xcc\x9c\xb4\x05\x06"\x00\x00\x00\x00\x00\x00\x00\x00' serial_number = receiver.extract_serial(response[1:5]) assert serial_number == "16CC9CB4" def test_extract_max_devices(): response = b'\x03\x16\xcc\x9c\xb4\x05\x06"\x00\x00\x00\x00\x00\x00\x00\x00' max_devices = receiver.extract_max_devices(response) assert max_devices == 6 @pytest.mark.parametrize( "response, expected_remaining_pairings", [ (b"\x00\x03\x00", -1), (b"\x00\x02\t", 4), ], ) def test_extract_remaining_pairings(response, expected_remaining_pairings): remaining_pairings = receiver.extract_remaining_pairings(response) assert remaining_pairings == expected_remaining_pairings def test_extract_codename(): response = b"A\x04K520" codename = receiver.extract_codename(response) assert codename == "K520" @pytest.mark.parametrize( "power_switch_byte, expected_location", [ (b"\x01", "base"), (b"\x09", "top_edge"), (b"\x0c", "bottom_edge"), (b"\x00", "unknown"), (b"\x0f", "unknown"), ], ) def test_extract_power_switch_location(power_switch_byte, expected_location): response = b"\x19\x8e>\xb8\x06\x00\x00\x00\x00" + power_switch_byte + b"\x00\x00\x00\x00\x00" ps_location = receiver.extract_power_switch_location(response) assert ps_location == expected_location def test_extract_connection_count(): response = b"\x00\x03\x00" connection_count = receiver.extract_connection_count(response) assert connection_count == 3 def test_extract_wpid(): response = b"@\x82" res = receiver.extract_wpid(response) assert res == "4082" def test_extract_polling_rate(): response = b"\x08@\x82\x04\x02\x02\x07\x00\x00\x00\x00\x00\x00\x00" polling_rate = receiver.extract_polling_rate(response) assert polling_rate == 130 @pytest.mark.parametrize( "data, expected_device_kind", [ (0x00, "unknown"), (0x03, "numpad"), ], ) def test_extract_device_kind(data, expected_device_kind): device_kind = receiver.extract_device_kind(data) assert str(device_kind) == expected_device_kind def _make_fake_receiver(cached_devices=None): r = mock.Mock(spec=receiver.Receiver) r.handle = 0x12 r._devices = dict(cached_devices or {}) r.force_unpair_slot = partial(receiver.Receiver.force_unpair_slot, r) return r def test_force_unpair_slot_empty_slot_acknowledged(): r = _make_fake_receiver(cached_devices={}) r._unpair_device_per_receiver = mock.Mock(return_value=b"\x00") assert r.force_unpair_slot(2) is True r._unpair_device_per_receiver.assert_called_once_with(2) assert 2 not in r._devices def test_force_unpair_slot_stale_sentinel_cleared(): # "Device not found" state: slot present in cache but value is None. r = _make_fake_receiver(cached_devices={2: None}) r._unpair_device_per_receiver = mock.Mock(return_value=b"\x00") assert r.force_unpair_slot(2) is True assert 2 not in r._devices def test_force_unpair_slot_active_device_invalidated(): dev = mock.Mock() dev.online = True dev.wpid = "40B4" r = _make_fake_receiver(cached_devices={1: dev}) r._unpair_device_per_receiver = mock.Mock(return_value=b"\x00") assert r.force_unpair_slot(1) is True assert dev.online is False assert dev.wpid is None assert 1 not in r._devices def test_force_unpair_slot_register_write_failed(): r = _make_fake_receiver(cached_devices={2: None}) r._unpair_device_per_receiver = mock.Mock(return_value=None) assert r.force_unpair_slot(2) is False # On failure, cache state is preserved so Solaar's model stays honest. assert r._devices == {2: None} def test_force_unpair_slot_no_handle(): r = _make_fake_receiver() r.handle = None r._unpair_device_per_receiver = mock.Mock() assert r.force_unpair_slot(2) is False r._unpair_device_per_receiver.assert_not_called() Solaar-1.1.20/tests/logitech_receiver/test_rgb_power.py000066400000000000000000000574271522022367600232630ustar00rootroot00000000000000## Copyright (C) Solaar contributors ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. """Tests for the display-state-aware color translation in rgb_power. These cover the pure math (`translate_color_for_display`) and the small manager hooks that PerKeyLighting calls into (`translate_color`, `notify_perkey_changed`) without requiring a GLib main loop. """ import pytest from logitech_receiver import rgb_power M = rgb_power.RGBPowerManager # --- translate_color_for_display (pure function) ---------------------------- @pytest.mark.parametrize( "color", [0x000000, 0x123456, 0xFF0000, 0xFFFFFF], ) def test_translate_active_is_identity(color): assert rgb_power.translate_color_for_display(color, M.ACTIVE, 50, 0, 25) == color def test_translate_idle_50pct(): # 255 * 50 // 100 == 127 assert rgb_power.translate_color_for_display(0xFFFFFF, M.IDLE, 50, 0, 25) == 0x7F7F7F def test_translate_idle_25pct_on_ff8800(): # 0xFF * 25 // 100 = 63 (0x3F); 0x88 * 25 // 100 = 34 (0x22); 0 stays 0 assert rgb_power.translate_color_for_display(0xFF8800, M.IDLE, 25, 0, 25) == 0x3F2200 def test_translate_dimming_start_is_saved_color(): # t = 0/25 = 0 → interpolation returns the start (saved) color assert rgb_power.translate_color_for_display(0xABCDEF, M.DIMMING, 50, 0, 25) == 0xABCDEF def test_translate_dimming_end_equals_idle(): # t = 25/25 = 1 → interpolation returns the target (fully dimmed) idle = rgb_power.translate_color_for_display(0xFFFFFF, M.IDLE, 50, 0, 25) dimming_end = rgb_power.translate_color_for_display(0xFFFFFF, M.DIMMING, 50, 25, 25) assert dimming_end == idle def test_translate_dimming_midramp_between_full_and_dim(): # At t=12/25 (≈0.48), white interpolates between 0xFF and 0x7F (50% target). # Expected r = 255 + (127 - 255) * 12/25 = 255 - 61.44 → int(193.56) = 193 (0xC1) assert rgb_power.translate_color_for_display(0xFFFFFF, M.DIMMING, 50, 12, 25) == 0xC1C1C1 def test_translate_sleeping_returns_none(): assert rgb_power.translate_color_for_display(0xFFFFFF, M.SLEEPING, 50, 0, 25) is None # --- translate_for_device (manager lookup) ---------------------------------- def test_translate_for_device_no_manager_is_identity(): # An arbitrary object with no manager registered → returns input unchanged. fake = object() assert rgb_power.translate_for_device(fake, 0xABCDEF) == 0xABCDEF def _dim(intensity): """Shortcut: build a Dim-mode LEDEffectSetting for tests that used to pass a bare dim-percent int as `_idle_effect`.""" from logitech_receiver import hidpp20 return hidpp20.LEDEffectSetting(ID=0x80, intensity=intensity) def _install_manager(monkeypatch, state, idle_effect=None, dim_step=0): """Build an RGBPowerManager with state injected and register it for a fake device id. Cleanup happens via monkeypatch's _managers swap. `idle_effect` defaults to Dim 50%. Pass a bare int (legacy) and it will be wrapped as a Dim-mode LEDEffectSetting; pass an LEDEffectSetting directly to use as-is. """ from logitech_receiver import hidpp20 fake_device = object() class _Dev: pass mgr = M.__new__(M) # bypass __init__ (no GLib needed) mgr._device = _Dev() mgr._state = state if idle_effect is None: mgr._idle_effect = _dim(50) elif isinstance(idle_effect, int): mgr._idle_effect = _dim(idle_effect) else: mgr._idle_effect = idle_effect mgr._dim_step = dim_step mgr._dim_perkey = None # Avoid circular import surprise — make sure the LEDEffectSetting is # imported here so type checks in helpers don't crash. _ = hidpp20.LEDEffectSetting saved_managers = dict(rgb_power._managers) monkeypatch.setattr(rgb_power, "_managers", {id(fake_device): mgr}) yield_data = (fake_device, mgr, saved_managers) return yield_data def test_translate_for_device_idle_routes_through_manager(monkeypatch): fake_device, mgr, _ = _install_manager(monkeypatch, M.IDLE, idle_effect=50) assert rgb_power.translate_for_device(fake_device, 0xFFFFFF) == 0x7F7F7F def test_translate_for_device_sleeping_returns_none(monkeypatch): fake_device, _, _ = _install_manager(monkeypatch, M.SLEEPING) assert rgb_power.translate_for_device(fake_device, 0xFFFFFF) is None def test_current_dim_pct_falls_back_to_100_for_non_dim_effects(): from logitech_receiver import hidpp20 mgr = M.__new__(M) # Dim is the only host-side idle effect — it's the only one Solaar can # render itself (by interpolating colors toward a dimmer target on a # Static zone color or in the per-key buffer). Disabled does nothing. # Breathe and Ripple hand off to the firmware effect engine, which # runs the animation at its own brightness; Solaar applies no dim # translation in those cases, so _current_dim_pct returns 100. for fw_or_disabled in (0x00, 0x0A, 0x0B): mgr._idle_effect = hidpp20.LEDEffectSetting(ID=fw_or_disabled) assert mgr._current_dim_pct() == 100 # Dim mode — intensity carries the dim percentage. for dim_pct in (25, 50, 75): mgr._idle_effect = hidpp20.LEDEffectSetting(ID=0x80, intensity=dim_pct) assert mgr._current_dim_pct() == dim_pct # --- notify_perkey_changed -------------------------------------------------- def test_notify_perkey_changed_updates_dim_map_during_dimming(): mgr = M.__new__(M) mgr._state = M.DIMMING mgr._idle_effect = _dim(50) mgr._dim_perkey = {5: (0xFFFFFF, 0x7F7F7F)} mgr.notify_perkey_changed(5, 0x00FF00) start, target = mgr._dim_perkey[5] assert start == 0x00FF00 # target = dim(0x00FF00, 50) = (0, 0xFF*50//100, 0) = (0, 0x7F, 0) assert target == 0x007F00 def test_notify_perkey_changed_noop_when_not_dimming(): mgr = M.__new__(M) mgr._state = M.IDLE mgr._idle_effect = _dim(50) mgr._dim_perkey = {5: (0xFFFFFF, 0x7F7F7F)} mgr.notify_perkey_changed(5, 0x00FF00) assert mgr._dim_perkey[5] == (0xFFFFFF, 0x7F7F7F) def test_notify_perkey_changed_noop_for_unknown_zone(): mgr = M.__new__(M) mgr._state = M.DIMMING mgr._idle_effect = _dim(50) mgr._dim_perkey = {5: (0xFFFFFF, 0x7F7F7F)} mgr.notify_perkey_changed(99, 0x00FF00) # not in _dim_perkey assert mgr._dim_perkey == {5: (0xFFFFFF, 0x7F7F7F)} def test_notify_perkey_bulk_changed_skips_no_change(): from logitech_receiver import special_keys no_change = special_keys.COLORSPLUS["No change"] mgr = M.__new__(M) mgr._state = M.DIMMING mgr._idle_effect = _dim(50) mgr._dim_perkey = {5: (0xFFFFFF, 0x7F7F7F), 7: (0x000000, 0x000000)} mgr.notify_perkey_bulk_changed({5: 0x00FF00, 7: no_change}) # Zone 5 updated, zone 7 (No change) left alone. assert mgr._dim_perkey[5][0] == 0x00FF00 assert mgr._dim_perkey[7] == (0x000000, 0x000000) # --- notify_zone_changed (zone-effect dim ramp) ----------------------------- class _FakeZone: """Minimal stand-in for hidpp20.LEDZoneInfo — only `.index` is consulted by RGBPowerManager.notify_zone_changed.""" def __init__(self, index): self.index = index def test_notify_zone_changed_updates_matching_cluster_during_dimming(): mgr = M.__new__(M) mgr._state = M.DIMMING mgr._idle_effect = _dim(50) zone_a = _FakeZone(0) zone_b = _FakeZone(1) mgr._dim_zones = [ (zone_a, 0xFFFFFF, 0x7F7F7F), (zone_b, 0xFF0000, 0x7F0000), ] mgr.notify_zone_changed(1, 0x00FF00) # zone_a unchanged assert mgr._dim_zones[0] == (zone_a, 0xFFFFFF, 0x7F7F7F) # zone_b updated: new start + recomputed target at 50% zone, start, target = mgr._dim_zones[1] assert zone is zone_b assert start == 0x00FF00 # _compute_dim_color(0x00FF00, 50) = (0, 0xFF*50//100, 0) = (0, 0x7F, 0) assert target == 0x007F00 def test_notify_zone_changed_noop_when_not_dimming(): mgr = M.__new__(M) mgr._state = M.IDLE mgr._idle_effect = _dim(50) zone = _FakeZone(0) mgr._dim_zones = [(zone, 0xFFFFFF, 0x7F7F7F)] mgr.notify_zone_changed(0, 0x00FF00) assert mgr._dim_zones[0] == (zone, 0xFFFFFF, 0x7F7F7F) def test_notify_zone_changed_noop_for_unknown_cluster(): mgr = M.__new__(M) mgr._state = M.DIMMING mgr._idle_effect = _dim(50) zone = _FakeZone(0) mgr._dim_zones = [(zone, 0xFFFFFF, 0x7F7F7F)] mgr.notify_zone_changed(99, 0x00FF00) # cluster 99 not in _dim_zones assert mgr._dim_zones[0] == (zone, 0xFFFFFF, 0x7F7F7F) def test_notify_zone_changed_noop_when_dim_zones_empty(): mgr = M.__new__(M) mgr._state = M.DIMMING mgr._idle_effect = _dim(50) mgr._dim_zones = [] # e.g. per-key active, zone path skipped mgr.notify_zone_changed(0, 0x00FF00) # should not raise assert mgr._dim_zones == [] # --- perkey_has_paint / zone_effect_is_static (module-level predicates) ----- class _FakePerKey: """Minimal stand-in for PerKeyLighting: holds a _value map and a _validator with .choices that perkey_has_paint inspects.""" name = "per-key-lighting" def __init__(self, value, choices=(1, 2, 3)): self._value = value class _V: pass self._validator = _V() self._validator.choices = list(choices) class _FakeZoneSetting: """Minimal stand-in for an RGBEffectSetting child instance: holds a name starting with "rgb_zone_" and a _value with an .ID attribute.""" def __init__(self, name, value): self.name = name self._value = value class _ValueWithID: """Stand-in for hidpp20.LEDEffectSetting — only .ID is consulted by zone_effect_is_static.""" def __init__(self, ID): self.ID = ID class _FakePersister: def __init__(self, sensitivities=None): self._s = sensitivities or {} def get_sensitivity(self, name): return self._s.get(name, False) class _FakeDevice: def __init__(self, settings_list, persister=None): self.settings = settings_list self.persister = persister def test_perkey_has_paint_with_real_colors(): pk = _FakePerKey({1: 0xFF0000, 2: -1, 3: -1}) # one real color, rest "No change" dev = _FakeDevice([pk], _FakePersister({"per-key-lighting": True})) found, has_paint = rgb_power.perkey_has_paint(dev) assert found is pk assert has_paint is True def test_perkey_has_paint_with_locked_sensitivity(): # False (locked) still counts as paint — only IGNORE opts out. pk = _FakePerKey({1: 0xFF0000}) dev = _FakeDevice([pk], _FakePersister()) # sensitivity defaults to False _, has_paint = rgb_power.perkey_has_paint(dev) assert has_paint is True def test_perkey_has_paint_only_no_change(): pk = _FakePerKey({1: -1, 2: -1, 3: -1}) # all "No change" dev = _FakeDevice([pk]) found, has_paint = rgb_power.perkey_has_paint(dev) assert found is pk assert has_paint is False def test_perkey_has_paint_no_perkey_setting(): dev = _FakeDevice([]) found, has_paint = rgb_power.perkey_has_paint(dev) assert found is None assert has_paint is False def test_perkey_has_paint_validator_choices_empty(): pk = _FakePerKey({1: 0xFF0000}, choices=()) dev = _FakeDevice([pk]) found, has_paint = rgb_power.perkey_has_paint(dev) assert found is pk assert has_paint is False def test_perkey_has_paint_user_ignores_perkey(): from logitech_receiver import settings as _settings pk = _FakePerKey({1: 0xFF0000}) dev = _FakeDevice([pk], _FakePersister({"per-key-lighting": _settings.SENSITIVITY_IGNORE})) found, has_paint = rgb_power.perkey_has_paint(dev) assert found is pk assert has_paint is False def test_perkey_has_paint_with_no_persister(): # No persister, no IGNORE flag — treat as paint present. pk = _FakePerKey({1: 0xFF0000}) dev = _FakeDevice([pk], persister=None) _, has_paint = rgb_power.perkey_has_paint(dev) assert has_paint is True def test_zone_effect_is_static_true_for_static(): z = _FakeZoneSetting("rgb_zone_1", _ValueWithID(0x01)) assert rgb_power.zone_effect_is_static(_FakeDevice([z])) is True def test_zone_effect_is_static_false_for_animated(): for eff_id in (0x02, 0x03, 0x0A, 0x0B, 0x0E, 0x15): z = _FakeZoneSetting("rgb_zone_1", _ValueWithID(eff_id)) assert rgb_power.zone_effect_is_static(_FakeDevice([z])) is False, eff_id def test_zone_effect_is_static_false_for_disabled(): # Disabled (0x00) means the user wants no zone effect — including # suppressing the per-key paint, since per-key push would re-light # the device. z = _FakeZoneSetting("rgb_zone_1", _ValueWithID(0x00)) assert rgb_power.zone_effect_is_static(_FakeDevice([z])) is False def test_zone_effect_is_static_true_when_no_zone_setting(): # Devices that only enumerate PER_KEY_LIGHTING_V2 (no RGB_EFFECTS) have # no zone-effect setting at all — per-key paint should be free to drive. assert rgb_power.zone_effect_is_static(_FakeDevice([])) is True def test_zone_effect_is_static_true_when_any_zone_is_static(): # Multi-zone device with one Static and one Cycle zone — at least one # Static slot is enough for per-key to overlay on. a = _FakeZoneSetting("rgb_zone_1", _ValueWithID(0x01)) # Static b = _FakeZoneSetting("rgb_zone_2", _ValueWithID(0x03)) # Cycle assert rgb_power.zone_effect_is_static(_FakeDevice([a, b])) is True # --- RGBEffectSetting.write divert / push -------------------------------- def _make_rgb_effect_setting(device, current_value): """Build a partial RGBEffectSetting bound to `device` without running the setup classmethod (which requires a real led_effects descriptor). Only the fields touched by RGBEffectSetting.write are populated.""" from unittest.mock import MagicMock from logitech_receiver import settings_templates s = settings_templates.RGBEffectSetting.__new__(settings_templates.RGBEffectSetting) s._device = device s._value = current_value s._rw = MagicMock() s._rw.prefix = b"\x01" s._validator = MagicMock() s._validator.needs_current_value = False # update() persists onto _value; mimic with a simple assignment. s.update = lambda v, save=True: setattr(s, "_value", v) return s def test_rgb_effect_write_static_to_static_repaints_unset_zones(monkeypatch): """User tweaks the Static base color while per-key is the visible layer: persist, repaint per-key's unset zones, send FrameEnd. No SetEffectByIndex (would reclaim the engine and overwrite per-key). Also notifies any in-flight dim ramp so unset cells' start_color tracks the new base.""" from unittest.mock import MagicMock from logitech_receiver import hidpp20 perkey = MagicMock() perkey._fill_unset_zones_with_base_color.return_value = True perkey._send_with_retry.return_value = True perkey._unset_zone_ids.return_value = [5, 7, 9] device = MagicMock() device.online = True mgr = MagicMock() monkeypatch.setattr(rgb_power, "perkey_has_paint", lambda d: (perkey, True)) monkeypatch.setattr(rgb_power, "get_manager", lambda d: mgr) old = hidpp20.LEDEffectSetting(ID=1, color=0xFF0000) new = hidpp20.LEDEffectSetting(ID=1, color=0x00FF00) s = _make_rgb_effect_setting(device, old) result = s.write(new) assert result is new assert s._value is new perkey._fill_unset_zones_with_base_color.assert_called_once() perkey._send_with_retry.assert_called_once_with(0x70, b"\x00") s._rw.write.assert_not_called() # No follow-up per-key push — we were already in Static. perkey.write.assert_not_called() # In-flight dim ramp gets notified that unset cells now interpolate # from the new base (0x00FF00) rather than the old. mgr.notify_perkey_bulk_changed.assert_called_once_with({5: 0x00FF00, 7: 0x00FF00, 9: 0x00FF00}) def test_rgb_effect_write_static_to_static_no_notify_when_no_unset_zones(monkeypatch): """If every per-key cell is user-painted, _unset_zone_ids returns [] and the dim-ramp notification is skipped (nothing to update).""" from unittest.mock import MagicMock from logitech_receiver import hidpp20 perkey = MagicMock() perkey._fill_unset_zones_with_base_color.return_value = True perkey._send_with_retry.return_value = True perkey._unset_zone_ids.return_value = [] device = MagicMock() device.online = True mgr = MagicMock() monkeypatch.setattr(rgb_power, "perkey_has_paint", lambda d: (perkey, True)) monkeypatch.setattr(rgb_power, "get_manager", lambda d: mgr) old = hidpp20.LEDEffectSetting(ID=1, color=0xFF0000) new = hidpp20.LEDEffectSetting(ID=1, color=0x00FF00) s = _make_rgb_effect_setting(device, old) s.write(new) mgr.notify_perkey_bulk_changed.assert_not_called() def test_rgb_effect_write_static_to_static_unchanged_is_noop(monkeypatch): """Same value persisted: no repaint, no FrameEnd, no wire write.""" from unittest.mock import MagicMock from logitech_receiver import hidpp20 perkey = MagicMock() device = MagicMock() device.online = True monkeypatch.setattr(rgb_power, "perkey_has_paint", lambda d: (perkey, True)) same = hidpp20.LEDEffectSetting(ID=1, color=0xFF0000) s = _make_rgb_effect_setting(device, same) s.write(same) perkey._fill_unset_zones_with_base_color.assert_not_called() perkey._send_with_retry.assert_not_called() s._rw.write.assert_not_called() def test_rgb_effect_write_static_to_animation_pushes_wire(monkeypatch): """User switches the zone effect dropdown from Static to an animation while per-key has paint: push the new value to wire so the animation starts. Per-key is a sub-mode of Static — animations take over the visible layer when selected.""" from unittest.mock import MagicMock from logitech_receiver import hidpp20 perkey = MagicMock() perkey._value = {1: 0xFF0000} device = MagicMock() device.online = True monkeypatch.setattr(rgb_power, "perkey_has_paint", lambda d: (perkey, True)) monkeypatch.setattr(rgb_power, "translate_for_device", lambda d, c: c) monkeypatch.setattr(rgb_power, "get_manager", lambda d: None) old = hidpp20.LEDEffectSetting(ID=0x01, color=0xFF0000) new = hidpp20.LEDEffectSetting(ID=0x0A, color=0x00FF00) s = _make_rgb_effect_setting(device, old) s._validator.prepare_write.return_value = b"prepared" s._rw.write.return_value = b"ack" s.write(new) s._rw.write.assert_called_once() perkey._fill_unset_zones_with_base_color.assert_not_called() def test_rgb_effect_write_repaints_perkey_unset_on_color_change(monkeypatch): """When per-key has paint and the zone's color changes, repaint the per-key unset cells with the new base so the visible result tracks the user's color choice.""" from unittest.mock import MagicMock from logitech_receiver import hidpp20 perkey = MagicMock() perkey._value = {1: 0xFF0000, 2: -1} perkey._fill_unset_zones_with_base_color.return_value = True perkey._unset_zone_ids.return_value = [2] device = MagicMock() device.online = True monkeypatch.setattr(rgb_power, "perkey_has_paint", lambda d: (perkey, True)) monkeypatch.setattr(rgb_power, "translate_for_device", lambda d, c: c) monkeypatch.setattr(rgb_power, "get_manager", lambda d: None) old = hidpp20.LEDEffectSetting(ID=0x01, color=0xFF0000) new = hidpp20.LEDEffectSetting(ID=0x01, color=0x00FF00) s = _make_rgb_effect_setting(device, old) s._validator.prepare_write.return_value = b"prepared" s._rw.write.return_value = b"ack" s.write(new) s._rw.write.assert_not_called() perkey._fill_unset_zones_with_base_color.assert_called_once() perkey._send_with_retry.assert_called_once_with(0x70, b"\x00") def test_rgb_effect_write_apply_path_suppressed_when_perkey_has_paint(monkeypatch): """save=False is the apply_all_settings path. When per-key has paint and is opted in, per-key fully owns the visible layer — the zone wire push is suppressed here too, not just on the save path.""" from unittest.mock import MagicMock from logitech_receiver import hidpp20 perkey = MagicMock() device = MagicMock() device.online = True monkeypatch.setattr(rgb_power, "perkey_has_paint", lambda d: (perkey, True)) monkeypatch.setattr(rgb_power, "translate_for_device", lambda d, c: c) monkeypatch.setattr(rgb_power, "get_manager", lambda d: None) new = hidpp20.LEDEffectSetting(ID=0x01, color=0x00FF00) s = _make_rgb_effect_setting(device, None) s._validator.prepare_write.return_value = b"prepared" s._rw.write.return_value = b"ack" s.write(new, save=False) s._rw.write.assert_not_called() # Apply path doesn't repaint either — that's reserved for explicit user # color changes via save=True. perkey._fill_unset_zones_with_base_color.assert_not_called() def test_rgb_effect_write_inactive_perkey_falls_through(monkeypatch): """No per-key paint (or per-key feature absent): existing translate-through-power-state wire path runs unchanged.""" from unittest.mock import MagicMock from logitech_receiver import hidpp20 perkey = MagicMock() device = MagicMock() device.online = True monkeypatch.setattr(rgb_power, "perkey_has_paint", lambda d: (perkey, False)) monkeypatch.setattr(rgb_power, "translate_for_device", lambda d, c: c) monkeypatch.setattr(rgb_power, "get_manager", lambda d: None) new = hidpp20.LEDEffectSetting(ID=0x01, color=0x00FF00) s = _make_rgb_effect_setting(device, None) s._validator.prepare_write.return_value = b"prepared" s._rw.write.return_value = b"ack" s.write(new) s._rw.write.assert_called_once() perkey._fill_unset_zones_with_base_color.assert_not_called() perkey.write.assert_not_called() # --- PerKeyLighting.write defers to firmware animations ------------------- def test_perkey_write_skipped_when_zone_is_animation(monkeypatch): """Per-key is a sub-mode of Static. When the saved zone effect is an animation (Breathe etc.), the firmware engine owns the visible layer and per-key writes do not go to the wire.""" from unittest.mock import MagicMock from logitech_receiver import settings_templates breathe_zone = _FakeZoneSetting("rgb_zone_1", _ValueWithID(0x0A)) s = settings_templates.PerKeyLighting.__new__(settings_templates.PerKeyLighting) device = MagicMock() device.online = True device.settings = [breathe_zone] s._device = device s._value = {} s._has_rgb_effects = True s._send_with_retry = MagicMock(return_value=True) s._fill_unset_zones_with_base_color = MagicMock(return_value=True) monkeypatch.setattr(rgb_power, "translate_for_device", lambda d, c: c) monkeypatch.setattr(rgb_power, "get_manager", lambda d: None) s.update = lambda m, save=True: None s.write({1: 0xFF0000}) s._send_with_retry.assert_not_called() def test_perkey_write_key_value_skipped_when_zone_is_animation(monkeypatch): """Same: write_key_value defers to firmware animations.""" from unittest.mock import MagicMock from logitech_receiver import settings_templates breathe_zone = _FakeZoneSetting("rgb_zone_1", _ValueWithID(0x0A)) s = settings_templates.PerKeyLighting.__new__(settings_templates.PerKeyLighting) device = MagicMock() device.online = True device.settings = [breathe_zone] s._device = device s._value = {} s._has_rgb_effects = True s._send_with_retry = MagicMock(return_value=True) s._send_zone_color = MagicMock(return_value=True) s._fill_unset_zones_with_base_color = MagicMock(return_value=True) monkeypatch.setattr(rgb_power, "translate_for_device", lambda d, c: c) monkeypatch.setattr(rgb_power, "get_manager", lambda d: None) s.update_key_value = lambda k, v, save=True: None s.write_key_value(7, 0xFF0000) s._send_zone_color.assert_not_called() Solaar-1.1.20/tests/logitech_receiver/test_setting_templates.py000066400000000000000000001342761522022367600250260ustar00rootroot00000000000000## Copyright (C) 2024 Solaar Contributors https://pwr-solaar.github.io/Solaar/ ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU 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. """The tests work by creating a faked device (from the hidpp module) that uses provided data as responses to HID++ commands. The device uses some methods from the real device to set up data structures that are needed for some tests. """ from dataclasses import dataclass from typing import Any import pytest from logitech_receiver import common from logitech_receiver import hidpp20 from logitech_receiver import hidpp20_constants from logitech_receiver import settings_templates from logitech_receiver import settings_validator from logitech_receiver import special_keys from . import fake_hidpp # Per-key colors: any 24-bit RGB; matches PerKeyLighting.validator_class._COLOR_RANGE. _PERKEY_COLOR_RANGE = settings_validator.Range(min=0, max=0xFFFFFF, byte_count=3, value_type=common.ColorInt) # TODO action part of DpiSlidingXY, MouseGesturesXY class Setup: def __init__(self, test, *params): self.test = test self.responses = [r for r in params if isinstance(r, fake_hidpp.Response)] self.choices = None if isinstance(params[0], fake_hidpp.Response) else params[0] @dataclass class RegisterTest: sclass: Any initial_value: Any = False write_value: Any = True write_params: str = "01" register_tests = [ Setup( RegisterTest(settings_templates.RegisterHandDetection, False, True, [b"\x00\x00\x00"]), fake_hidpp.Response("000030", 0x8101), # keyboard_hand_detection fake_hidpp.Response("000000", 0x8001, "000000"), ), Setup( RegisterTest(settings_templates.RegisterHandDetection, True, False, [b"\x00\x00\x30"]), fake_hidpp.Response("000000", 0x8101), # keyboard_hand_detection fake_hidpp.Response("000030", 0x8001, "000030"), ), Setup( RegisterTest(settings_templates.RegisterSmoothScroll, False, True, [b"\x40"]), fake_hidpp.Response("00", 0x8101), # mouse_button_flags fake_hidpp.Response("40", 0x8001, "40"), ), Setup( RegisterTest(settings_templates.RegisterSideScroll, True, False, [b"\x00"]), fake_hidpp.Response("02", 0x8101), # mouse_button_flags fake_hidpp.Response("00", 0x8001, "00"), ), Setup( RegisterTest(settings_templates.RegisterFnSwap, False, True, [b"\x00\x01"]), fake_hidpp.Response("0000", 0x8109), # keyboard_fn_swap fake_hidpp.Response("0001", 0x8009, "0001"), ), Setup( RegisterTest( settings_templates._PerformanceMXDpi, common.NamedInt(0x88, "800"), common.NamedInt(0x89, "900"), [b"\x89"] ), fake_hidpp.Response("88", 0x8163), # mouse_dpi fake_hidpp.Response("89", 0x8063, "89"), ), ] @pytest.mark.parametrize("test", register_tests) def test_register_template(test, mocker): device = fake_hidpp.Device(protocol=1.0, responses=test.responses) spy_request = mocker.spy(device, "request") setting = test.test.sclass.build(device) value = setting.read(cached=False) cached_value = setting.read(cached=True) write_value = setting.write(test.test.write_value) assert setting is not None assert value == test.test.initial_value assert cached_value == test.test.initial_value assert write_value == test.test.write_value spy_request.assert_called_with(test.test.sclass.register + 0x8000, *test.test.write_params) @dataclass class FeatureTest: sclass: Any initial_value: Any = False write_value: Any = True matched_calls: int = 1 offset: int = 0x04 version: int = 0x00 rewrite: bool = False readable: bool = True simple_tests = [ Setup( FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06), fake_hidpp.Response("FF0001", 0x0600, "FF"), fake_hidpp.Response("FF0101", 0x0610, "FF01"), ), Setup( FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06), fake_hidpp.Response("050001", 0x0000, "1815"), # HOSTS_INFO fake_hidpp.Response("FF0001", 0x0600, "FF"), fake_hidpp.Response("FF0101", 0x0610, "FF01"), ), Setup( FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06), fake_hidpp.Response("050001", 0x0000, "1815"), # HOSTS_INFO fake_hidpp.Response("07050301", 0x0500), # current host is 0x01, i.e., host 2 fake_hidpp.Response("010001", 0x0600, "01"), fake_hidpp.Response("010101", 0x0610, "0101"), ), Setup( FeatureTest(settings_templates.FnSwap, True, False), fake_hidpp.Response("01", 0x0400), fake_hidpp.Response("00", 0x0410, "00"), ), Setup( FeatureTest(settings_templates.NewFnSwap, True, False), fake_hidpp.Response("01", 0x0400), fake_hidpp.Response("00", 0x0410, "00"), ), # Setup( # Backlight has caused problems # FeatureTest(settings_templates.Backlight, 0, 5, offset=0x06), # fake_hidpp.Response("00", 0x0600), # fake_hidpp.Response("05", 0x0610, "05"), # ), Setup( FeatureTest(settings_templates.Backlight2DurationHandsOut, 80, 160, version=0x03), fake_hidpp.Response("011830000000100040006000", 0x0400), fake_hidpp.Response("0118FF00200040006000", 0x0410, "0118FF00200040006000"), ), Setup( FeatureTest(settings_templates.Backlight2DurationHandsIn, 320, 160, version=0x03), fake_hidpp.Response("011830000000200040006000", 0x0400), fake_hidpp.Response("0118FF00200020006000", 0x0410, "0118FF00200020006000"), ), Setup( FeatureTest(settings_templates.Backlight2DurationPowered, 480, 80, version=0x03), fake_hidpp.Response("011830000000200040006000", 0x0400), fake_hidpp.Response("0118FF00200040001000", 0x0410, "0118FF00200040001000"), ), Setup( FeatureTest(settings_templates.Backlight3, 0x50, 0x70), fake_hidpp.Response("50", 0x0410), fake_hidpp.Response("70", 0x0420, "007009"), ), Setup( FeatureTest(settings_templates.HiResScroll, True, False), fake_hidpp.Response("01", 0x0400), fake_hidpp.Response("00", 0x0410, "00"), ), Setup( FeatureTest(settings_templates.LowresMode, False, True), fake_hidpp.Response("00", 0x0400), fake_hidpp.Response("01", 0x0410, "01"), ), Setup( FeatureTest(settings_templates.HiresSmoothInvert, True, False), fake_hidpp.Response("06", 0x0410), fake_hidpp.Response("02", 0x0420, "02"), ), Setup( FeatureTest(settings_templates.HiresSmoothResolution, True, False), fake_hidpp.Response("06", 0x0410), fake_hidpp.Response("04", 0x0420, "04"), ), Setup( FeatureTest(settings_templates.HiresMode, False, True), fake_hidpp.Response("06", 0x0410), fake_hidpp.Response("07", 0x0420, "07"), ), Setup( FeatureTest(settings_templates.PointerSpeed, 0x0100, 0x0120), fake_hidpp.Response("0100", 0x0400), fake_hidpp.Response("0120", 0x0410, "0120"), ), Setup( FeatureTest(settings_templates.ThumbMode, True, False), fake_hidpp.Response("0100", 0x0410), fake_hidpp.Response("0000", 0x0420, "0000"), ), Setup( FeatureTest(settings_templates.ThumbInvert, False, True), fake_hidpp.Response("0100", 0x0410), fake_hidpp.Response("0101", 0x0420, "0101"), ), Setup( FeatureTest(settings_templates.DivertCrown, False, True), fake_hidpp.Response("01", 0x0410), fake_hidpp.Response("02", 0x0420, "02"), ), Setup( FeatureTest(settings_templates.CrownSmooth, True, False), fake_hidpp.Response("0001", 0x0410), fake_hidpp.Response("0002", 0x0420, "0002"), ), Setup( FeatureTest(settings_templates.DivertGkeys, False, True), fake_hidpp.Response("01", 0x0420, "01"), ), Setup( FeatureTest(settings_templates.ScrollRatchet, 2, 1), fake_hidpp.Response("02", 0x0400), fake_hidpp.Response("01", 0x0410, "01"), ), Setup( FeatureTest(settings_templates.SmartShift, 1, 10), fake_hidpp.Response("0100", 0x0400), fake_hidpp.Response("000A", 0x0410, "000A"), ), Setup( FeatureTest(settings_templates.SmartShift, 5, 50), fake_hidpp.Response("0005", 0x0400), fake_hidpp.Response("00FF", 0x0410, "00FF"), ), Setup( FeatureTest(settings_templates.SmartShiftEnhanced, 5, 50), fake_hidpp.Response("0005", 0x0410), fake_hidpp.Response("00FF", 0x0420, "00FF"), ), Setup( FeatureTest(settings_templates.DisableKeyboardKeys, {1: True, 8: True}, {1: False, 8: True}), fake_hidpp.Response("09", 0x0400), fake_hidpp.Response("09", 0x0410), fake_hidpp.Response("08", 0x0420, "08"), ), Setup( FeatureTest(settings_templates.DualPlatform, 0, 1), fake_hidpp.Response("00", 0x0400), fake_hidpp.Response("01", 0x0420, "01"), ), Setup( FeatureTest(settings_templates.MKeyLEDs, {1: False, 2: False, 4: False}, {1: False, 2: True, 4: True}), fake_hidpp.Response("03", 0x0400), fake_hidpp.Response("06", 0x0410, "06"), ), Setup( FeatureTest(settings_templates.MRKeyLED, False, True), fake_hidpp.Response("01", 0x0400, "01"), ), Setup( FeatureTest(settings_templates.Sidetone, 5, 0xA), fake_hidpp.Response("05", 0x0400), fake_hidpp.Response("0A", 0x0410, "0A"), ), Setup( FeatureTest(settings_templates.ADCPower, 5, 0xA, version=0x03), fake_hidpp.Response("05", 0x0410), fake_hidpp.Response("0A", 0x0420, "0A"), ), Setup( FeatureTest(settings_templates.LEDControl, False, True), fake_hidpp.Response("00", 0x0470), fake_hidpp.Response("01", 0x0480, "01"), ), Setup( FeatureTest( settings_templates.LEDZoneSetting, hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x100), hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x101), ), fake_hidpp.Response("0100000001", 0x0400), fake_hidpp.Response("00000102", 0x0410, "00FF00"), fake_hidpp.Response("0000000300040005", 0x0420, "000000"), fake_hidpp.Response("0001000B00080009", 0x0420, "000100"), fake_hidpp.Response("000000000000010050", 0x04E0, "00"), fake_hidpp.Response("000000000000000101500000", 0x0430, "000000000000000101500000"), ), Setup( FeatureTest(settings_templates.RGBControl, False, True), fake_hidpp.Response("0000", 0x0450), fake_hidpp.Response("010304", 0x0450, "010304"), fake_hidpp.Response("00003C012C", 0x0470, "00"), # GetRgbPowerModeConfig: idle=60s, sleep=300s ), Setup( # RGBIdleEffect — software-only, no feature requests for read/write # The setting is a HeteroValidator carrying a LEDEffectSetting. # Default (read with empty persister) = Dim 50%. FeatureTest( settings_templates.RGBIdleEffect, hidpp20.LEDEffectSetting(ID=0x80, intensity=50), hidpp20.LEDEffectSetting(ID=0x80, intensity=75), 0, ), fake_hidpp.Response("00", 0xFFFF), # placeholder — no device requests needed ), Setup( # RGBIdleTimeout — software-only, no feature requests for read/write FeatureTest(settings_templates.RGBIdleTimeout, 60, 300, 0), fake_hidpp.Response("00", 0xFFFF), # placeholder — no device requests needed ), Setup( # RGBSleepTimeout — software-only, no feature requests for read/write FeatureTest(settings_templates.RGBSleepTimeout, 300, 600, 0), fake_hidpp.Response("00", 0xFFFF), # placeholder — no device requests needed ), Setup( FeatureTest( settings_templates.RGBEffectSetting, hidpp20.LEDEffectSetting(ID=3, intensity=0x50, period=0x100), hidpp20.LEDEffectSetting(ID=2, color=0x505050, speed=0x50), readable=False, ), fake_hidpp.Response("FFFF0100000001", 0x0400, "FFFF00"), fake_hidpp.Response("0000000102", 0x0400, "00FF00"), fake_hidpp.Response("0000000300040005", 0x0400, "000000"), fake_hidpp.Response("0001000200080009", 0x0400, "000100"), fake_hidpp.Response("000000000000010050", 0x04E0, "00"), fake_hidpp.Response("00015050505000000000000001", 0x0410, "00015050505000000000000001"), ), Setup( FeatureTest( settings_templates.RGBEffectSetting, None, hidpp20.LEDEffectSetting(ID=3, intensity=0x60, period=0x101), readable=False, ), fake_hidpp.Response("FFFF0100000001", 0x0400, "FFFF00"), fake_hidpp.Response("0000000102", 0x0400, "00FF00"), fake_hidpp.Response("0000000300040005", 0x0400, "000000"), fake_hidpp.Response("0001000200080009", 0x0400, "000100"), fake_hidpp.Response("00000000000000010160000001", 0x0410, "00000000000000010160000001"), ), Setup( FeatureTest( settings_templates.RGBEffectSetting, None, hidpp20.LEDEffectSetting(ID=3, intensity=0x60, period=0x101), readable=False, ), fake_hidpp.Response("FF000200020004000000000000000000", 0x0400, "FFFF00"), fake_hidpp.Response("00000002040000000000000000000000", 0x0400, "00FF00"), fake_hidpp.Response("00000000000000000000000000000000", 0x0400, "000000"), fake_hidpp.Response("00010001000000000000000000000000", 0x0400, "000100"), fake_hidpp.Response("00020003C00503E00000000000000000", 0x0400, "000200"), fake_hidpp.Response("0003000AC0011E0B0000000000000000", 0x0400, "000300"), fake_hidpp.Response("01000001070000000000000000000000", 0x0400, "01FF00"), fake_hidpp.Response("01000000000000000000000000000000", 0x0400, "010000"), fake_hidpp.Response("01010001000000000000000000000000", 0x0400, "010100"), fake_hidpp.Response("0102000AC0011E0B0000000000000000", 0x0400, "010200"), fake_hidpp.Response("01030003C00503E00000000000000000", 0x0400, "010300"), fake_hidpp.Response("01040004DCE1001E0000000000000000", 0x0400, "010400"), fake_hidpp.Response("0105000B000000320000000000000000", 0x0400, "010500"), fake_hidpp.Response("0106000C001B02340000000000000000", 0x0400, "010600"), fake_hidpp.Response("00020000000000010160000001", 0x0410, "00020000000000010160000001"), ), Setup( FeatureTest(settings_templates.Backlight2, 0xFF, 0x00), common.NamedInts(Disabled=0xFF, Enabled=0x00), fake_hidpp.Response("000201000000000000000000", 0x0400), fake_hidpp.Response("010201", 0x0410, "0102FF00000000000000"), ), Setup( FeatureTest(settings_templates.Backlight2, 0x03, 0xFF), common.NamedInts(Disabled=0xFF, Automatic=0x01, Manual=0x03), fake_hidpp.Response("011838000000000000000000", 0x0400), fake_hidpp.Response("001801", 0x0410, "0018FF00000000000000"), ), Setup( FeatureTest(settings_templates.Backlight2Level, 0, 3, version=0x03), [0, 4], fake_hidpp.Response("011830000000000000000000", 0x0400), fake_hidpp.Response("05", 0x0420), fake_hidpp.Response("01180103000000000000", 0x0410, "0118FF03000000000000"), ), Setup( FeatureTest(settings_templates.Backlight2Level, 0, 2, version=0x03), [0, 4], fake_hidpp.Response("011830000000000000000000", 0x0400), fake_hidpp.Response("05", 0x0420), fake_hidpp.Response("01180102000000000000", 0x0410, "0118FF02000000000000"), ), Setup( FeatureTest(settings_templates.OnboardProfiles, 0, 1, offset=0x0C), common.NamedInts(**{"Disabled": 0, "Profile 1": 1, "Profile 2": 2}), fake_hidpp.Response("01030001010101000101", 0x0C00), fake_hidpp.Response("00010100000201FFFFFFFFFFFFFFFFFF", 0x0C50, "00000000"), fake_hidpp.Response("000201FFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000004"), fake_hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000008"), fake_hidpp.Response("02", 0x0C20), fake_hidpp.Response("01", 0x0C10, "01"), fake_hidpp.Response("0001", 0x0C30, "0001"), ), Setup( FeatureTest(settings_templates.OnboardProfiles, 1, 0, offset=0x0C), common.NamedInts(**{"Disabled": 0, "Profile 1": 1, "Profile 2": 2}), fake_hidpp.Response("01030001010101000101", 0x0C00), fake_hidpp.Response("00010100000201FFFFFFFFFFFFFFFFFF", 0x0C50, "00000000"), fake_hidpp.Response("000201FFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000004"), fake_hidpp.Response("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 0x0C50, "00000008"), fake_hidpp.Response("01", 0x0C20), fake_hidpp.Response("0001", 0x0C40), fake_hidpp.Response("02", 0x0C10, "02"), ), Setup( FeatureTest(settings_templates.ReportRate, 1, 5, offset=0x0C), common.NamedInts(**{"1ms": 1, "2ms": 2, "5ms": 5, "6ms": 6}), fake_hidpp.Response("33", 0x0C00), fake_hidpp.Response("01", 0x0C10), fake_hidpp.Response("05", 0x0C20, "05"), ), Setup( FeatureTest(settings_templates.ExtendedReportRate, 1, 5, offset=0x0C), common.NamedInts(**{"8ms": 0, "4ms": 1, "500us": 4, "250us": 5}), fake_hidpp.Response("33", 0x0C10), fake_hidpp.Response("01", 0x0C20), fake_hidpp.Response("05", 0x0C30, "05"), ), Setup( FeatureTest(settings_templates.AdjustableDpi, 800, 400, version=0x03), common.NamedInts.list([400, 800, 1600]), fake_hidpp.Response("000190032006400000", 0x0410, "000000"), fake_hidpp.Response("000320", 0x0420), fake_hidpp.Response("000190", 0x0430, "000190"), ), Setup( FeatureTest(settings_templates.AdjustableDpi, 256, 512, version=0x03), common.NamedInts.list([256, 512]), fake_hidpp.Response("000100e10002000000", 0x0410, "000000"), fake_hidpp.Response("000100", 0x0420), fake_hidpp.Response("000200", 0x0430, "000200"), ), Setup( FeatureTest(settings_templates.AdjustableDpi, 400, 800, version=0x03), common.NamedInts.list([400, 800, 1200, 1600]), fake_hidpp.Response("000190E19006400000000000000000", 0x0410, "000000"), fake_hidpp.Response("000190", 0x0420), fake_hidpp.Response("000320", 0x0430, "000320"), ), Setup( FeatureTest(settings_templates.Multiplatform, 0, 1), common.NamedInts(**{"MacOS 0.1-0.5": 0, "iOS 0.1-0.7": 1, "Linux 0.2-0.9": 2, "Windows 0.3-0.9": 3}), fake_hidpp.Response("020004000001", 0x0400), fake_hidpp.Response("00FF200000010005", 0x0410, "00"), fake_hidpp.Response("01FF400000010007", 0x0410, "01"), fake_hidpp.Response("02FF040000020009", 0x0410, "02"), fake_hidpp.Response("03FF010000030009", 0x0410, "03"), fake_hidpp.Response("FF01", 0x0430, "FF01"), ), Setup( FeatureTest(settings_templates.ChangeHost, 1, 0), common.NamedInts(**{"1:ABCDEF": 0, "2:GHIJKL": 1}), fake_hidpp.Response("050003", 0x0000, "1815"), # HOSTS_INFO fake_hidpp.Response("01000200", 0x0500), fake_hidpp.Response("000100000600", 0x0510, "00"), fake_hidpp.Response("000041424344454600", 0x0530, "0000"), fake_hidpp.Response("000100000600", 0x0510, "01"), fake_hidpp.Response("00004748494A4B4C00", 0x0530, "0100"), fake_hidpp.Response("0201", 0x0400), fake_hidpp.Response(True, 0x0410, "00"), ), Setup( FeatureTest(settings_templates.BrightnessControl, 0x10, 0x20), [0, 80], fake_hidpp.Response("00505100000000", 0x0400), # 0 to 80, all acceptable, no separate on/off fake_hidpp.Response("10", 0x0410), # brightness 16 fake_hidpp.Response("0020", 0x0420, "0020"), # set brightness 32 ), Setup( FeatureTest(settings_templates.BrightnessControl, 0x10, 0x00), [0, 80], fake_hidpp.Response("00505104000000", 0x0400), # 0 to 80, all acceptable, separate on/off fake_hidpp.Response("10", 0x0410), # brightness 16 fake_hidpp.Response("01", 0x0430), # on fake_hidpp.Response("00", 0x0440), # set off fake_hidpp.Response("0000", 0x0420, "0000"), # set brightness 0 ), Setup( FeatureTest(settings_templates.BrightnessControl, 0x00, 0x20), [0, 80], fake_hidpp.Response("00505104000000", 0x0400), # 0 to 80, all acceptable, separate on/off fake_hidpp.Response("10", 0x0410), # brightness 16 fake_hidpp.Response("00", 0x0430), # off fake_hidpp.Response("01", 0x0440), # set on fake_hidpp.Response("0020", 0x0420, "0020"), # set brightness 32 ), Setup( FeatureTest(settings_templates.BrightnessControl, 0x20, 0x08), [0, 80], fake_hidpp.Response("00504104001000", 0x0400), # 16 to 80, all acceptable, separate on/off fake_hidpp.Response("20", 0x0410), # brightness 32 fake_hidpp.Response("01", 0x0430), # on fake_hidpp.Response("00", 0x0440, "00"), # set off ), Setup( FeatureTest(settings_templates.SpeedChange, 0, None, 0), # need to set up all settings to successfully write common.NamedInts(**{"Off": 0, "DPI Change": 0xED}), *fake_hidpp.responses_speedchange, ), ] @pytest.fixture def mock_gethostname(mocker): mocker.patch("socket.gethostname", return_value="ABCDEF.foo.org") @pytest.mark.parametrize("test", simple_tests) def test_simple_template(test, mocker, mock_gethostname): tst = test.test print("TEST", tst.sclass, tst.sclass.feature) device = fake_hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version) spy_request = mocker.spy(device, "request") setting = settings_templates.check_feature(device, tst.sclass) assert setting is not None if isinstance(setting, list): setting = setting[0] if isinstance(test.choices, list): assert setting._validator.min_value == test.choices[0] assert setting._validator.max_value == test.choices[1] elif test.choices is not None: assert setting.choices == test.choices if tst.readable: value = setting.read(cached=False) assert value == tst.initial_value cached_value = setting.read(cached=True) assert cached_value == tst.initial_value write_value = setting.write(tst.write_value) if tst.write_value is not None else None assert write_value == tst.write_value fake_hidpp.match_requests(tst.matched_calls, test.responses, spy_request.call_args_list) responses_reprog_controls = [ fake_hidpp.Response("03", 0x0500), fake_hidpp.Response("00500038010001010400000000000000", 0x0510, "00"), # left button fake_hidpp.Response("00510039010001010400000000000000", 0x0510, "01"), # right button fake_hidpp.Response("00C4009D310003070500000000000000", 0x0510, "02"), # smart shift fake_hidpp.Response("00500000000000000000000000000000", 0x0520, "0050"), # left button current fake_hidpp.Response("00510000500000000000000000000000", 0x0520, "0051"), # right button current fake_hidpp.Response("00C40000000000000000000000000000", 0x0520, "00C4"), # smart shift current fake_hidpp.Response("00500005000000000000000000000000", 0x0530, "0050000050"), # left button write fake_hidpp.Response("00510005000000000000000000000000", 0x0530, "0051000050"), # right button write fake_hidpp.Response("00C4000C400000000000000000000000", 0x0530, "00C40000C4"), # smart shift write ] key_tests = [ Setup( FeatureTest(settings_templates.ReprogrammableKeys, {0x50: 0x50, 0x51: 0x50, 0xC4: 0xC4}, {0x51: 0x51}, 4, offset=0x05), { common.NamedInt(0x50, "Left Button"): common.UnsortedNamedInts(Left_Click=0x50, Right_Click=0x51), common.NamedInt(0x51, "Right Button"): common.UnsortedNamedInts(Right_Click=0x51, Left_Click=0x50), common.NamedInt(0xC4, "Smart Shift"): common.UnsortedNamedInts(Smart_Shift=0xC4, Left_Click=80, Right_Click=81), }, *responses_reprog_controls, fake_hidpp.Response("0051000051", 0x0530, "0051000051"), # right button set write ), Setup( FeatureTest(settings_templates.DivertKeys, {0xC4: 0}, {0xC4: 1}, 2, offset=0x05), {common.NamedInt(0xC4, "Smart Shift"): common.NamedInts(Regular=0, Diverted=1, Mouse_Gestures=2)}, *responses_reprog_controls, fake_hidpp.Response("00C4020000", 0x0530, "00C4020000"), # Smart Shift write fake_hidpp.Response("00C4030000", 0x0530, "00C4030000"), # Smart Shift divert write ), Setup( FeatureTest(settings_templates.DivertKeys, {0xC4: 0}, {0xC4: 2}, 2, offset=0x05), {common.NamedInt(0xC4, "Smart Shift"): common.NamedInts(Regular=0, Diverted=1, Mouse_Gestures=2, Sliding_DPI=3)}, *responses_reprog_controls, fake_hidpp.Response("0A0001", 0x0000, "2201"), # ADJUSTABLE_DPI fake_hidpp.Response("00C4300000", 0x0530, "00C4300000"), # Smart Shift write fake_hidpp.Response("00C4030000", 0x0530, "00C4030000"), # Smart Shift divert write ), Setup( FeatureTest(settings_templates.PersistentRemappableAction, {80: 16797696, 81: 16797696}, {0x51: 16797952}, 3), { common.NamedInt(80, "Left Button"): special_keys.KEYS_KEYS_CONSUMER, common.NamedInt(81, "Right Button"): special_keys.KEYS_KEYS_CONSUMER, }, fake_hidpp.Response("050001", 0x0000, "1B04"), # REPROG_CONTROLS_V4 *responses_reprog_controls, fake_hidpp.Response("0041", 0x0400), fake_hidpp.Response("0201", 0x0410), fake_hidpp.Response("02", 0x0400), fake_hidpp.Response("0050", 0x0420, "00FF"), # left button fake_hidpp.Response("0051", 0x0420, "01FF"), # right button fake_hidpp.Response("0050000100500000", 0x0430, "0050FF"), # left button current fake_hidpp.Response("0051000100500001", 0x0430, "0051FF"), # right button current fake_hidpp.Response("0050FF01005000", 0x0440, "0050FF01005000"), # left button write fake_hidpp.Response("0051FF01005000", 0x0440, "0051FF01005000"), # right button write fake_hidpp.Response("0051FF01005100", 0x0440, "0051FF01005100"), # right button set write ), Setup( FeatureTest( settings_templates.Gesture2Gestures, { 1: True, 2: True, 30: True, 10: True, 45: False, 42: True, 43: True, 64: False, 65: False, 67: False, 84: True, 34: False, }, {45: True}, 4, ), *fake_hidpp.responses_gestures, fake_hidpp.Response("0001FF6F", 0x0420, "0001FF6F"), # write fake_hidpp.Response("01010F04", 0x0420, "01010F04"), fake_hidpp.Response("0001FF7F", 0x0420, "0001FF7F"), # write 45 fake_hidpp.Response("01010F04", 0x0420, "01010F04"), ), Setup( FeatureTest( settings_templates.Gesture2Divert, {1: False, 2: False, 10: False, 44: False, 64: False, 65: False, 67: False, 84: False, 85: False, 100: False}, {44: True}, 4, ), *fake_hidpp.responses_gestures, fake_hidpp.Response("0001FF00", 0x0440, "0001FF00"), # write fake_hidpp.Response("01010300", 0x0440, "01010300"), fake_hidpp.Response("0001FF08", 0x0440, "0001FF08"), # write 44 fake_hidpp.Response("01010300", 0x0440, "01010300"), ), Setup( FeatureTest(settings_templates.Gesture2Params, {4: {"scale": 256}}, {4: {"scale": 128}}, 2), *fake_hidpp.responses_gestures, fake_hidpp.Response("000100FF000000000000000000000000", 0x0480, "000100FF"), fake_hidpp.Response("000080FF000000000000000000000000", 0x0480, "000080FF"), ), Setup( FeatureTest(settings_templates.Equalizer, {0: -0x20, 1: 0x10}, {1: 0x18}, 2), [-32, 32], fake_hidpp.Response("0220000000", 0x0400), fake_hidpp.Response("0000800100000000000000", 0x0410, "00"), fake_hidpp.Response("E010", 0x0420, "00"), fake_hidpp.Response("E010", 0x0430, "02E010"), fake_hidpp.Response("E018", 0x0430, "02E018"), ), Setup( # HeadsetOnboardEQ: 2 bands, 128Hz/-2dB/Q10 and 256Hz/+3dB/Q10 FeatureTest(settings_templates.HeadsetOnboardEQ, {0: -2, 1: 3}, {1: 5}, 2), [-12, 12], fake_hidpp.Response("8000000002", 0x0400), # GetEQInfos: has_hw_eq, 2 bands fake_hidpp.Response("00020080FE0A0100030A", 0x0410, "00"), # GetEQParameters fake_hidpp.Response( # SetEQParameters: write initial values back (slot 0x00) "00", 0x0420, "00020080FE0A0100030A" "055AE300" # mystery bytes (from pcap) "030E00020000000100170002" "007A6B00D69D94008C516B00C82380005DC27F0075" "906B0022B6940002226B00B44080007EA37F00C1C3040044" "0200170002" "00506B00900F95006ED56A00D185800060477F00CA" "906B00229D950052496A00A12E810085EC7E0075C40400AC", ), fake_hidpp.Response( # SetEQParameters: persist initial values (slot 0x80) "00", 0x0420, "80020080FE0A0100030A" "055AE300" "030E00020000000100170002" "007A6B00D69D94008C516B00C82380005DC27F0075" "906B0022B6940002226B00B44080007EA37F00C1C3040044" "0200170002" "00506B00900F95006ED56A00D185800060477F00CA" "906B00229D950052496A00A12E810085EC7E0075C40400AC", ), fake_hidpp.Response( # SetEQParameters: write updated band 1 gain=5 (slot 0x00) "00", 0x0420, "00020080FE0A0100050A" "055AE300" "030E00020000000100170002" "006F6B00F5A894006A466B00EB2380005DC27F0075" "906B0022BC9400AA156B00613B80007CAD7F00C6C30400BF" "0200170002" "00306B00272F9500BAB56A008C85800060477F00CA" "906B0022B1950002226A000E1F8100AB0A7F004FC604001D", ), fake_hidpp.Response( # SetEQParameters: persist updated values (slot 0x80) "00", 0x0420, "80020080FE0A0100050A" "055AE300" "030E00020000000100170002" "006F6B00F5A894006A466B00EB2380005DC27F0075" "906B0022BC9400AA156B00613B80007CAD7F00C6C30400BF" "0200170002" "00306B00272F9500BAB56A008C85800060477F00CA" "906B0022B1950002226A000E1F8100AB0A7F004FC604001D", ), ), Setup( FeatureTest(settings_templates.PerKeyLighting, {1: -1, 2: -1, 9: -1, 10: -1, 113: -1}, {2: 0xFF0000}, 4, 4, 0, 1), { common.NamedInt(1, "A"): _PERKEY_COLOR_RANGE, common.NamedInt(2, "B"): _PERKEY_COLOR_RANGE, common.NamedInt(9, "I"): _PERKEY_COLOR_RANGE, common.NamedInt(10, "J"): _PERKEY_COLOR_RANGE, common.NamedInt(113, "KEY 113"): _PERKEY_COLOR_RANGE, }, fake_hidpp.Response("00000606000000000000000000000000", 0x0400, "0000"), # first group of keys fake_hidpp.Response("00000200000000000000000000000000", 0x0400, "0001"), # second group of keys fake_hidpp.Response("00000000000000000000000000000000", 0x0400, "0002"), # last group of keys fake_hidpp.Response("02FF0000", 0x0410, "02FF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("02FF0000", 0x0410, "02FF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish ), Setup( FeatureTest( settings_templates.PerKeyLighting, {1: -1, 2: -1, 9: -1, 10: -1, 113: -1}, {2: 0xFF0000, 9: 0xFF0000, 10: 0xFF0000}, 8, 4, 0, 1, ), { common.NamedInt(1, "A"): _PERKEY_COLOR_RANGE, common.NamedInt(2, "B"): _PERKEY_COLOR_RANGE, common.NamedInt(9, "I"): _PERKEY_COLOR_RANGE, common.NamedInt(10, "J"): _PERKEY_COLOR_RANGE, common.NamedInt(113, "KEY 113"): _PERKEY_COLOR_RANGE, }, fake_hidpp.Response("00000606000000000000000000000000", 0x0400, "0000"), # first group of keys fake_hidpp.Response("00000200000000000000000000000000", 0x0400, "0001"), # second group of keys fake_hidpp.Response("00000000000000000000000000000000", 0x0400, "0002"), # last group of keys fake_hidpp.Response("02FF0000", 0x0410, "02FF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("09FF0000", 0x0410, "09FF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("0AFF0000", 0x0410, "0AFF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("02FF000009FF00000AFF0000", 0x0410, "02FF000009FF00000AFF0000"), # write three values fake_hidpp.Response("00", 0x0470, "00"), # finish ), Setup( FeatureTest( settings_templates.PerKeyLighting, {1: -1, 2: -1, 9: -1, 10: -1, 113: -1, 114: -1}, {1: 0xFF0000, 2: 0xFF0000, 9: 0xFF0000, 10: 0xFF0000, 113: 0x00FF00, 114: 0xFF0000}, 15, 4, 0, 1, ), { common.NamedInt(1, "A"): _PERKEY_COLOR_RANGE, common.NamedInt(2, "B"): _PERKEY_COLOR_RANGE, common.NamedInt(9, "I"): _PERKEY_COLOR_RANGE, common.NamedInt(10, "J"): _PERKEY_COLOR_RANGE, common.NamedInt(113, "KEY 113"): _PERKEY_COLOR_RANGE, common.NamedInt(114, "KEY 114"): _PERKEY_COLOR_RANGE, }, fake_hidpp.Response("00000606000000000000000000000000", 0x0400, "0000"), # first group of keys fake_hidpp.Response("00000600000000000000000000000000", 0x0400, "0001"), # second group of keys fake_hidpp.Response("00000000000000000000000000000000", 0x0400, "0002"), # last group of keys fake_hidpp.Response("01FF0000", 0x0410, "01FF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("02FF0000", 0x0410, "02FF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("09FF0000", 0x0410, "09FF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("0AFF0000", 0x0410, "0AFF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("7100FF00", 0x0410, "7100FF00"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("72FF0000", 0x0410, "72FF0000"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish fake_hidpp.Response("FF00000102090A72", 0x460, "FF00000102090A72"), # write one value for five keys fake_hidpp.Response("7100FF00", 0x0410, "7100FF00"), # write one value fake_hidpp.Response("00", 0x0470, "00"), # finish ), Setup( FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 256}, {0: 512}, 2, offset=0x9), {common.NamedInt(0, "X"): common.NamedInts.list([256, 512])}, fake_hidpp.Response("000000", 0x0910, "00"), # no y direction, no lod fake_hidpp.Response("0000000100e10002000000", 0x0920, "000000"), fake_hidpp.Response("00010000000000000000", 0x0950), fake_hidpp.Response("000100000000", 0x0960, "000100000000"), fake_hidpp.Response("000200000000", 0x0960, "000200000000"), ), Setup( FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 0x64, 1: 0xE4}, {0: 0x164}, 2, offset=0x9), { common.NamedInt(0, "X"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164, 0x01C4]), common.NamedInt(1, "Y"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164]), }, fake_hidpp.Response("000001", 0x0910, "00"), # supports y direction, no lod fake_hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000000"), fake_hidpp.Response("000001E4E0400124E0400164E06001C4", 0x0920, "000001"), fake_hidpp.Response("00000000000000000000000000000000", 0x0920, "000002"), fake_hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000100"), fake_hidpp.Response("000001E4E0400124E040016400000000", 0x0920, "000101"), fake_hidpp.Response("000064007400E4007400", 0x0950), fake_hidpp.Response("00006400E400", 0x0960, "00006400E400"), fake_hidpp.Response("00016400E400", 0x0960, "00016400E400"), ), Setup( FeatureTest(settings_templates.ExtendedAdjustableDpi, {0: 0x64, 1: 0xE4, 2: 1}, {1: 0x164}, 2, offset=0x9), { common.NamedInt(0, "X"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164, 0x01C4]), common.NamedInt(1, "Y"): common.NamedInts.list([0x064, 0x074, 0x084, 0x0A4, 0x0C4, 0x0E4, 0x0124, 0x0164]), common.NamedInt(2, "LOD"): common.NamedInts(LOW=0, MEDIUM=1, HIGH=2), }, fake_hidpp.Response("000003", 0x0910, "00"), # supports y direction and lod fake_hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000000"), fake_hidpp.Response("000001E4E0400124E0400164E06001C4", 0x0920, "000001"), fake_hidpp.Response("00000000000000000000000000000000", 0x0920, "000002"), fake_hidpp.Response("0000000064E0100084E02000C4E02000", 0x0920, "000100"), fake_hidpp.Response("000001E4E0400124E040016400000000", 0x0920, "000101"), fake_hidpp.Response("000064007400E4007401", 0x0950), fake_hidpp.Response("00006400E401", 0x0960, "00006400E401"), fake_hidpp.Response("000064016401", 0x0960, "000064016401"), ), ] @pytest.mark.parametrize("test", key_tests) def test_key_template(test, mocker): tst = test.test device = fake_hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version) spy_request = mocker.spy(device, "request") print("FEATURE", tst.sclass.feature) setting = settings_templates.check_feature(device, tst.sclass) assert setting is not None if isinstance(setting, list): setting = setting[0] if isinstance(test.choices, list): assert setting._validator.min_value == test.choices[0] assert setting._validator.max_value == test.choices[1] elif test.choices is not None: assert setting.choices == test.choices value = setting.read(cached=False) assert value == tst.initial_value write_value = setting.write(value) assert write_value == tst.initial_value for key, val in tst.write_value.items(): write_value = setting.write_key_value(key, val) assert write_value == val value[key] = val if tst.rewrite: write_value = setting.write(value) fake_hidpp.match_requests(tst.matched_calls, test.responses, spy_request.call_args_list) @pytest.mark.parametrize( "responses, currentSpeed, newSpeed", [ (fake_hidpp.responses_speedchange, 100, 200), (fake_hidpp.responses_speedchange, None, 250), ], ) def test_SpeedChange_action(responses, currentSpeed, newSpeed, mocker): device = fake_hidpp.Device(responses=responses, feature=hidpp20_constants.SupportedFeature.POINTER_SPEED) spy_setting_callback = mocker.spy(device, "setting_callback") settings_templates.check_feature_settings(device, device.settings) # need to set up all the settings device.persister = {"pointer_speed": currentSpeed, "_speed-change": newSpeed} speed_setting = next(filter(lambda s: s.name == "speed-change", device.settings), None) pointer_setting = next(filter(lambda s: s.name == "pointer_speed", device.settings), None) speed_setting.write(237) speed_setting._rw.press_action() if newSpeed is not None and speed_setting is not None: spy_setting_callback.assert_any_call(device, type(pointer_setting), [newSpeed]) assert device.persister["_speed-change"] == currentSpeed assert device.persister["pointer_speed"] == newSpeed @pytest.mark.parametrize("test", simple_tests + key_tests) def test_check_feature_settings(test, mocker): tst = test.test device = fake_hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version) already_known = [] setting = settings_templates.check_feature_settings(device, already_known) assert setting is True assert already_known @pytest.mark.parametrize( "test", [ Setup( FeatureTest(settings_templates.K375sFnSwap, False, True, offset=0x06), fake_hidpp.Response("FF0001", 0x0600, "FF"), fake_hidpp.Response("FF0101", 0x0610, "FF01"), ) ], ) def test_check_feature_setting(test, mocker): tst = test.test device = fake_hidpp.Device(responses=test.responses, feature=tst.sclass.feature, offset=tst.offset, version=tst.version) setting = settings_templates.check_feature_setting(device, tst.sclass.name) assert setting # --- RGBIdleEffect._pre_read legacy bare-int migration --------------------- # Solaar versions before the HeteroValidator refactor stored # `rgb_idle_effect` as a bare int (0 / 25 / 50 / 75 / 0x0A / 0x0B). # On first read after upgrade, RGBIdleEffect._pre_read should map # each to the equivalent LEDEffectSetting and write the upgraded form # back to the persister so subsequent reads return it directly. def _idle_setting_with_persisted(value): """Build a minimally-scaffolded RGBIdleEffect with `value` already in the persister and `_value` unread. Returns (setting, device). Avoids RGBIdleEffect.build's led_effects probe (which needs a full device fixture); _pre_read is fully exercised regardless. """ from solaar import configuration class _Dev: pass device = _Dev() device.persister = configuration._DeviceEntry() if value is not None: device.persister[settings_templates.RGBIdleEffect.name] = value setting = settings_templates.RGBIdleEffect.__new__(settings_templates.RGBIdleEffect) setting._device = device setting._value = None return setting, device @pytest.mark.parametrize( "legacy, expected_id, expected_attrs", [ (0, 0x00, {}), # Disabled (25, 0x80, {"intensity": 25}), # Dim 25% (50, 0x80, {"intensity": 50}), # Dim 50% (75, 0x80, {"intensity": 75}), # Dim 75% (0x0A, 0x0A, {"period": 3000, "intensity": 100}), # Breathe (0x0B, 0x0B, {"period": 3000}), # Ripple ], ) def test_RGBIdleEffect_legacy_int_migration(legacy, expected_id, expected_attrs): setting, device = _idle_setting_with_persisted(legacy) setting._pre_read(cached=True) assert isinstance(setting._value, hidpp20.LEDEffectSetting) assert int(setting._value.ID) == expected_id for attr, val in expected_attrs.items(): assert getattr(setting._value, attr) == val # Persister was rewritten so subsequent reads return the migrated form. persisted = device.persister[setting.name] assert isinstance(persisted, hidpp20.LEDEffectSetting) assert int(persisted.ID) == expected_id def test_RGBIdleEffect_already_migrated_is_unchanged(): """A persisted LEDEffectSetting passes through _pre_read untouched — no double-migration on subsequent reads.""" pre_migrated = hidpp20.LEDEffectSetting(ID=0x80, intensity=42) setting, _ = _idle_setting_with_persisted(pre_migrated) setting._pre_read(cached=True) assert setting._value is pre_migrated # same instance, no rewrap def test_RGBIdleEffect_none_value_passes_through(): """Fresh install / nothing in persister: _pre_read leaves _value as None instead of crashing in the migration branch.""" setting, _ = _idle_setting_with_persisted(None) setting._pre_read(cached=True) assert setting._value is None def test_RGBIdleEffect_unrecognized_int_passes_through(): """An int outside the legacy mapping (corrupt config, future value) falls through _pre_read without touching _value or the persister.""" setting, device = _idle_setting_with_persisted(999) setting._pre_read(cached=True) assert setting._value == 999 assert device.persister[setting.name] == 999 def test_HeadsetOnboardEffect_explicit_black_is_honored(): """An explicit Static color1 of 0 (black) must survive: 0 is a real choice — it turns the LEDs off — not an absent field to seed white.""" effect = settings_templates._HeadsetOnboardEffect(ID=0, color1=0) assert int(effect.color1) == 0 assert effect.to_bytes()[2:5] == b"\x00\x00\x00" def test_HeadsetOnboardEffect_absent_color_seeds_default(): """A genuinely absent field (None) still falls back to the per-effect default — Static with no color1 given is white.""" effect = settings_templates._HeadsetOnboardEffect(ID=0) assert int(effect.color1) == 0xFFFFFF def test_HeadsetOnboardEffect_from_bytes_black_round_trips(): """A black Static frame read off the device round-trips to black rather than being rewritten to the white default.""" effect = settings_templates._HeadsetOnboardEffect.from_bytes(bytes(9)) assert effect.ID == 0 assert int(effect.color1) == 0 def test_HeadsetOnboardEffect_absent_animated_fields_seed_defaults(): """Animated effects with no params given still get sane defaults so the picker never emits a zero-intensity (LEDs-off) frame.""" effect = settings_templates._HeadsetOnboardEffect(ID=1) # Color Cycle assert effect.intensity == 100 assert effect.period == 5000 Solaar-1.1.20/tests/logitech_receiver/test_settings_validator.py000066400000000000000000000052311522022367600251640ustar00rootroot00000000000000import pytest from logitech_receiver import common from logitech_receiver import settings_validator @pytest.mark.parametrize( "current, new, expected", [ (False, "toggle", True), (True, "~", False), ("don't care", True, True), ("don't care", "true", True), ("don't care", "false", False), ("don't care", "no", False), ("don't care", "off", False), ("don't care", "True", True), ("don't care", "yes", True), ("don't care", "on", True), ("anything", "anything", None), ], ) def test_bool_or_toggle(current, new, expected): result = settings_validator.bool_or_toggle(current=current, new=new) assert result == expected def _color_validator(): rng = settings_validator.Range(min=0, max=0xFFFFFF, byte_count=3, value_type=common.ColorInt) choices = { common.NamedInt(1, "A"): rng, common.NamedInt(2, "B"): rng, common.NamedInt(3, "C"): rng, } return settings_validator.MapRangeValidator(choices) def test_map_range_to_string_formats_plain_int_through_value_type(): """Configs loaded from YAML come back as plain ints; to_string should re-wrap them via the choice's value_type so `solaar show` renders hex regardless of whether the dict came from a fresh read or a stale load.""" v = _color_validator() plain = {1: 12590120, 2: 12922150, 3: 16106001} # what YAML load produces rendered = v.to_string(plain) assert "0xc01c28" in rendered assert "0xc52d26" in rendered assert "0xf5c211" in rendered def test_map_range_to_string_passes_color_int_through(): v = _color_validator() wrapped = {1: common.ColorInt(0xFC3300), 2: common.ColorInt(0x00FF00)} rendered = v.to_string(wrapped) assert "0xfc3300" in rendered assert "0x00ff00" in rendered def test_map_range_to_string_preserves_sentinel_subclass(): """NamedInt 'No change' = -1 must not be re-wrapped (its name would be lost). The exact-type guard `type(v) is int` excludes it.""" v = _color_validator() mixed = {1: common.ColorInt(0xFC3300), 2: -1} rendered = v.to_string(mixed) assert "0xfc3300" in rendered assert "2:-1" in rendered def test_map_range_to_string_int_value_type_unchanged(): """When value_type is the default int, to_string emits decimal as before (no behavior change for non-color settings).""" rng = settings_validator.Range(min=0, max=255, byte_count=1) choices = {common.NamedInt(1, "A"): rng, common.NamedInt(2, "B"): rng} v = settings_validator.MapRangeValidator(choices) rendered = v.to_string({1: 42, 2: 200}) assert "1:42" in rendered assert "2:200" in rendered Solaar-1.1.20/tests/solaar/000077500000000000000000000000001522022367600154445ustar00rootroot00000000000000Solaar-1.1.20/tests/solaar/test_gtk.py000066400000000000000000000011011522022367600176330ustar00rootroot00000000000000from solaar.gtk import create_parser def test_arg_parse(): parser = create_parser() res = parser.parse_args([]) assert res.debug == 0 assert res.hidraw_path is None assert res.restart_on_wake_up is False assert res.window is None assert res.battery_icons is None assert res.tray_icon_size is None def test_arg_parse_debug(): parser = create_parser() res = parser.parse_args(["--debug"]) assert res.debug == 1 def test_arg_parse_version(): parser = create_parser() res = parser.parse_args(["version"]) assert res Solaar-1.1.20/tests/solaar/ui/000077500000000000000000000000001522022367600160615ustar00rootroot00000000000000Solaar-1.1.20/tests/solaar/ui/test_about_dialog.py000066400000000000000000000014421522022367600221240ustar00rootroot00000000000000from solaar.ui.about import about from solaar.ui.about.model import AboutModel def test_about_model(): expected_name = "Daniel Pavel" model = AboutModel() authors = model.get_authors() assert expected_name in authors[0] def test_about_dialog(mocker): view_mock = mocker.Mock() about.show(view=view_mock) assert view_mock.init_ui.call_count == 1 assert view_mock.update_version_info.call_count == 1 assert view_mock.update_description.call_count == 1 assert view_mock.update_authors.call_count == 1 assert view_mock.update_credits.call_count == 1 assert view_mock.update_copyright.call_count == 1 assert view_mock.update_translators.call_count == 1 assert view_mock.update_website.call_count == 1 assert view_mock.show.call_count == 1 Solaar-1.1.20/tests/solaar/ui/test_common.py000066400000000000000000000014341522022367600207640ustar00rootroot00000000000000from unittest import mock from unittest.mock import PropertyMock import pytest from solaar.ui import common @pytest.mark.parametrize( "reason, expected_in_title, expected_in_text", [ ( common.ErrorReason.PERMISSIONS, "Permissions error", "not have permission to open", ), (common.ErrorReason.NO_DEVICE, "connect to device error", "error connecting"), (common.ErrorReason.UNPAIR, "Unpairing failed", "receiver returned an error"), ], ) def test_create_error_text(reason, expected_in_title, expected_in_text): obj = mock.Mock() obj.name = PropertyMock(return_value="test") title, text = common._create_error_text(reason, obj) assert expected_in_title in title assert expected_in_text in text Solaar-1.1.20/tests/solaar/ui/test_desktop_notifications.py000066400000000000000000000020701522022367600240730ustar00rootroot00000000000000from unittest import mock from solaar.ui import desktop_notifications # The mock_desktop_notifications autouse fixture (tests/conftest.py) swaps the # libnotify backend for a mock, so these exercise the real code paths without # raising real desktop notifications. def test_init(): result = desktop_notifications.init() assert result == desktop_notifications.available def test_uninit(): assert desktop_notifications.uninit() is None def test_alert(mock_desktop_notifications): assert desktop_notifications.alert("unknown") is None if desktop_notifications.available: mock_desktop_notifications.Notification.return_value.show.assert_called() class MockDevice(mock.Mock): name = "MockDevice" def close(): return True def test_show(mock_desktop_notifications): result = desktop_notifications.show(MockDevice(), "unknown") if desktop_notifications.available: assert result is not None mock_desktop_notifications.Notification.return_value.show.assert_called() else: assert result is None Solaar-1.1.20/tests/solaar/ui/test_i18n.py000066400000000000000000000011471522022367600202540ustar00rootroot00000000000000import locale import os import platform import pytest from solaar import i18n @pytest.fixture def set_locale_de(): backup_lang = os.environ.get("LC_ALL", "") try: yield finally: os.environ["LC_ALL"] = backup_lang i18n.set_locale_to_system_default() @pytest.mark.skipif(platform.system() == "Linux", reason="Adapt test for Linux") def test_set_locale_to_system_default(set_locale_de): os.environ["LC_ALL"] = "de_DE.UTF-8" i18n.set_locale_to_system_default() language, encoding = locale.getlocale() assert language == "de_DE" assert encoding == "UTF-8" Solaar-1.1.20/tests/solaar/ui/test_pair_window.py000066400000000000000000000200461522022367600220160ustar00rootroot00000000000000from dataclasses import dataclass from dataclasses import field from typing import Any from typing import List from typing import Optional import gi import pytest from logitech_receiver import receiver from solaar.ui import pair_window gi.require_version("Gtk", "3.0") from gi.repository import Gtk # NOQA: E402 gtk_init = Gtk.init_check()[0] @dataclass class Device: name: str = "test device" kind: str = "test kind" @dataclass class Receiver: name: str receiver_kind: str _set_lock: bool = True pairing: receiver.Pairing = field(default_factory=receiver.Pairing) pairable: bool = True _remaining_pairings: Optional[int] = None def reset_pairing(self): self.receiver = receiver.Pairing() def remaining_pairings(self, cache=True): return self._remaining_pairings def set_lock(self, value=False, timeout=0): self.pairing.lock_open = self._set_lock return self._set_lock def discover(self, cancel=False, timeout=30): self.pairing.discovering = self._set_lock return self._set_lock def pair_device(self, pair=True, slot=0, address=b"\0\0\0\0\0\0", authentication=0x00, entropy=20, force=False): print("PD", self.pairable) return self.pairable @dataclass class Assistant: drawable: bool = True pages: List[Any] = field(default_factory=list) def is_drawable(self): return self.drawable def next_page(self): return True def set_page_complete(self, page, b): return True def commit(self): return True def append_page(self, page): self.pages.append(page) def remove_page(self, page): return True def set_page_type(self, page, type): return True def destroy(self): pass @pytest.mark.skipif(not gtk_init, reason="requires Gtk") @pytest.mark.parametrize( "receiver, lock_open, discovering, page_type", [ (Receiver("unifying", "unifying", True), True, False, Gtk.AssistantPageType.PROGRESS), (Receiver("unifying", "unifying", False), False, False, Gtk.AssistantPageType.SUMMARY), (Receiver("nano", "nano", True, _remaining_pairings=5), True, False, Gtk.AssistantPageType.PROGRESS), (Receiver("nano", "nano", False), False, False, Gtk.AssistantPageType.SUMMARY), (Receiver("bolt", "bolt", True), False, True, Gtk.AssistantPageType.PROGRESS), (Receiver("bolt", "bolt", False), False, False, Gtk.AssistantPageType.SUMMARY), ], ) def test_create(receiver, lock_open, discovering, page_type): assistant = pair_window.create(receiver) assert assistant is not None assert assistant.get_page_type(assistant.get_nth_page(0)) == page_type assert receiver.pairing.lock_open == lock_open assert receiver.pairing.discovering == discovering @pytest.mark.parametrize( "receiver, expected_result, expected_error", [ (Receiver("unifying", "unifying", True), True, False), (Receiver("unifying", "unifying", False), False, True), (Receiver("bolt", "bolt", True), True, False), (Receiver("bolt", "bolt", False), False, True), ], ) def test_prepare(receiver, expected_result, expected_error): result = pair_window.prepare(receiver) assert result == expected_result assert bool(receiver.pairing.error) == expected_error @pytest.mark.parametrize("assistant, expected_result", [(Assistant(True), True), (Assistant(False), False)]) def test_check_lock_state_drawable(assistant, expected_result): r = Receiver("succeed", "unifying", True, receiver.Pairing(lock_open=True)) result = pair_window.check_lock_state(assistant, r, 2) assert result == expected_result @pytest.mark.skipif(not gtk_init, reason="requires Gtk") @pytest.mark.parametrize( "receiver, count, expected_result", [ (Receiver("fail", "unifying", False, receiver.Pairing(lock_open=False)), 2, False), (Receiver("succeed", "unifying", True, receiver.Pairing(lock_open=True)), 1, True), (Receiver("error", "unifying", True, receiver.Pairing(error="error")), 0, False), (Receiver("new device", "unifying", True, receiver.Pairing(new_device=Device())), 2, False), (Receiver("closed", "unifying", True, receiver.Pairing()), 2, False), (Receiver("closed", "unifying", True, receiver.Pairing()), 1, False), (Receiver("closed", "unifying", True, receiver.Pairing()), 0, False), (Receiver("fail bolt", "bolt", False), 1, False), (Receiver("succeed bolt", "bolt", True, receiver.Pairing(lock_open=True)), 0, True), (Receiver("error bolt", "bolt", True, receiver.Pairing(error="error")), 2, False), (Receiver("new device", "bolt", True, receiver.Pairing(lock_open=True, new_device=Device())), 1, False), (Receiver("discovering", "bolt", True, receiver.Pairing(lock_open=True)), 1, True), (Receiver("closed", "bolt", True, receiver.Pairing()), 2, False), (Receiver("closed", "bolt", True, receiver.Pairing()), 1, False), (Receiver("closed", "bolt", True, receiver.Pairing()), 0, False), ( Receiver( "pass1", "bolt", True, receiver.Pairing(lock_open=True, device_passkey=50, device_authentication=0x01), ), 0, True, ), ( Receiver( "pass2", "bolt", True, receiver.Pairing(lock_open=True, device_passkey=50, device_authentication=0x02), ), 0, True, ), ( Receiver( "adt", "bolt", True, receiver.Pairing(discovering=True, device_address=2, device_name=5), pairable=True, ), 2, True, ), ( Receiver( "adf", "bolt", True, receiver.Pairing(discovering=True, device_address=2, device_name=5), pairable=False, ), 2, False, ), (Receiver("add fail", "bolt", False, receiver.Pairing(device_address=2, device_passkey=5)), 2, False), ], ) def test_check_lock_state(receiver, count, expected_result): assistant = Assistant(True) check_state = pair_window._check_lock_state(assistant, receiver, count) assert check_state == expected_result @pytest.mark.parametrize( "receiver, pair_device, set_lock, discover, error", [ ( Receiver("unifying", "unifying", pairing=receiver.Pairing(lock_open=False, error="error")), 0, 0, 0, None, ), ( Receiver("unifying", "unifying", pairing=receiver.Pairing(lock_open=True, error="error")), 0, 1, 0, "error", ), (Receiver("bolt", "bolt", pairing=receiver.Pairing(lock_open=False, error="error")), 0, 0, 0, None), (Receiver("bolt", "bolt", pairing=receiver.Pairing(lock_open=True, error="error")), 1, 0, 0, "error"), (Receiver("bolt", "bolt", pairing=receiver.Pairing(discovering=True, error="error")), 0, 0, 1, "error"), ], ) def test_finish(receiver, pair_device, set_lock, discover, error, mocker): spy_pair_device = mocker.spy(receiver, "pair_device") spy_set_lock = mocker.spy(receiver, "set_lock") spy_discover = mocker.spy(receiver, "discover") assistant = Assistant(True) pair_window._finish(assistant, receiver) assert spy_pair_device.call_count == pair_device assert spy_set_lock.call_count == set_lock assert spy_discover.call_count == discover assert receiver.pairing.error == error @pytest.mark.skipif(not gtk_init, reason="requires Gtk") @pytest.mark.parametrize("error", ["timeout", "device not supported", "too many devices"]) def test_create_failure_page(error, mocker): spy_create = mocker.spy(pair_window, "_create_page") pair_window._pairing_failed(Assistant(True), Receiver("nano", "nano"), error) assert spy_create.call_count == 1 Solaar-1.1.20/tests/solaar/ui/test_probe.py000066400000000000000000000036771522022367600206160ustar00rootroot00000000000000from unittest import mock from logitech_receiver.hidpp10_constants import ErrorCode from logitech_receiver.hidpp10_constants import Registers from solaar.cli.probe import run # Mock receiver class class MockReceiver: handle = 1 isDevice = False def read_register(self, register, *args): return 0 if register == Registers.RECEIVER_INFO else b"\x01\x03" def test_run_register_errors(): mock_args = mock.Mock() mock_args.receiver = False mock_receiver = MockReceiver() # Define expected addresses to be called in order expected_addresses = [] for reg in range(0, 0xFF): expected_addresses.append((0x8100 | reg, 0)) # First short call, returns invalid_value (continue) expected_addresses.append((0x8100 | reg, 1)) # Second short call, returns invalid_address (stop here) expected_addresses.append((0x8100 | (0x200 + reg), 0)) # First long call, returns invalid_value (continue) expected_addresses.append((0x8100 | (0x200 + reg), 1)) # Second long call, returns invalid_address (stop here) # To record the actual addresses called called_addresses = [] def mock_base_request(handle, devnumber, reg, sub, return_error=False): called_addresses.append((reg, sub)) if sub == 0: return ErrorCode.INVALID_VALUE elif sub == 1: return ErrorCode.INVALID_ADDRESS return b"\x01\x02" with mock.patch("logitech_receiver.base.request", side_effect=mock_base_request), mock.patch( "solaar.cli.probe._print_receiver", return_value=None ): # Call the run function with mocked receivers and args (passing real find_receiver function) run([mock_receiver], mock_args, None, None) # Evaluate that the addresses called match the expected addresses assert ( called_addresses == expected_addresses ), f"Called addresses {called_addresses} do not match expected {expected_addresses}" Solaar-1.1.20/tests/test_keysyms/000077500000000000000000000000001522022367600167265ustar00rootroot00000000000000Solaar-1.1.20/tests/test_keysyms/__init__.py000066400000000000000000000000001522022367600210250ustar00rootroot00000000000000Solaar-1.1.20/tests/test_keysyms/test_keysymdef.py000066400000000000000000000003051522022367600223350ustar00rootroot00000000000000from keysyms import keysymdef def test_keysymdef(): key_mapping = keysymdef.key_symbols assert key_mapping["0"] == 48 assert key_mapping["A"] == 65 assert key_mapping["a"] == 97 Solaar-1.1.20/tools/000077500000000000000000000000001522022367600141615ustar00rootroot00000000000000Solaar-1.1.20/tools/clean.sh000077500000000000000000000002661522022367600156060ustar00rootroot00000000000000#!/usr/bin/env sh cd "$(dirname "$0")/.." find . -type f -name '*.py[co]' -delete find . -type d -name '__pycache__' -delete rm --force po/*~ rm --force --recursive share/locale/ Solaar-1.1.20/tools/create-macos-app.sh000077500000000000000000000074021522022367600176440ustar00rootroot00000000000000#!/usr/bin/env bash # Helper to build a minimal macOS .app wrapper for Solaar. set -euo pipefail APP_ROOT=${1:-/Applications/Solaar.app} SOLAAR_PATH=${SOLAAR_PATH:-solaar} SOLAAR_RESOLVED_PATH=$(command -v "${SOLAAR_PATH}" 2>/dev/null || echo "") if [ -z "${SOLAAR_RESOLVED_PATH}" ]; then echo "Error: '${SOLAAR_PATH}' not found" >&2 exit 1 fi ICON_SOURCE=${ICON_SOURCE:-share/solaar/icons/solaar.svg} case "${APP_ROOT}" in ""|"/"|".") echo "Error: Refusing to create app bundle at unsafe location: \"${APP_ROOT}\"" >&2 exit 1 ;; esac echo "Creating Solaar app bundle at ${APP_ROOT}" rm -rf "${APP_ROOT}" APP_CONTENTS="${APP_ROOT}/Contents" MACOS_DIR="${APP_CONTENTS}/MacOS" RESOURCES_DIR="${APP_CONTENTS}/Resources" mkdir -p "${MACOS_DIR}" "${RESOURCES_DIR}" WRAPPER="${MACOS_DIR}/solaar-wrapper" cat > "${WRAPPER}" <