alacritty-0.13.2/.cargo_vcs_info.json0000644000000001470000000000100131150ustar { "git": { "sha1": "bb8ea18ea848f67ce981b0c2446d1eee2c49eada" }, "path_in_vcs": "alacritty" }alacritty-0.13.2/CHANGELOG.md000064400000000000000000001603131046102023000135200ustar 00000000000000# Changelog All notable changes to Alacritty are documented in this file. The sections should follow the order `Packaging`, `Added`, `Changed`, `Fixed` and `Removed`. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## 0.13.2 ### Added - Default `Home`/`End` bindings in Vi mode mapped to `First`/`Last` respectively ### Fixed - CLI env variables clearing configuration file variables - Vi inline search/semantic selection expanding across newlines - C0 and C1 codes being emitted in associated text when using kitty keyboard - Occasional hang on startup with some Wayland compositors - Missing key for `NumpadDecimal` in key bindings - Scrolling content upwards moving lines into history when it shouldn't - Sticky keys not working sometimes on X11 - Modifiers occasionally getting desynced on X11 - Autokey no longer working with alacritty on X11 - Freeze when moving window between monitors on Xfwm - Mouse cursor not changing on Wayland when cursor theme uses legacy cursor icon names - Config keys are available under proper names - Build failure when compiling with x11 feature on NetBSD - Hint `Select` action selecting the entire line for URL escapes - Kitty encoding used for regular keys when they don't carry text ### Changed - No unused-key warnings will be emitted for OS-specific config keys - Use built-in font for sextant symbols from `U+1FB00` to `U+1FB3B` - Kitty encoding is not used anymore for uncommon keys unless the protocol enabled ## 0.13.1 ### Added - Support for pasting in Vi + Search mode ### Changed - `alacritty migrate` will ignore null values in yaml instead of erroring out ### Fixed - `alacritty migrate` failing with nonexistent imports - `Alt` bindings requiring composed key rather than pre-composed one on macOS - `Alt + Control` bindings not working on Windows - `chars = "\u000A"` action in bindings inserting `\n` - Alternate keys not sent for `Shift + ` when using kitty protocol - Alternative keys being swapped in kitty protocol implementation - Powerline glyphs being cut for narrow fonts - Xmodmap not working on X11 - Occasional slow startup on some X11 window managers - Blurry window when using `window.dimensions` on some Wayland compositors - IME input lagging behind on X11 - xdotool modifiers input not working correctly on X11 - Parsing numbers fails for mouse bindings - Some config options overriding each other in CLI/IPC - Numpad `Left` used for numpad `Up` ## 0.13.0 ### Packaging - Minimum Rust version has been bumped to 1.70.0 - Manpages are now generated using `scdoc` (see `INSTALL.md`) ### Added - Warnings for unused configuration file options - Config option `persist` in `hints` config section - Support for dynamically loading conpty.dll on Windows - Support for keybindings with dead keys - `Back`/`Forward` mouse buttons support in bindings - Copy global IPC options (`-w -1`) for new windows - Bindings to create and navigate tabs on macOS - Support startup notify protocol to raise initial window on Wayland/X11 - Debug option `prefer_egl` to prioritize EGL over other display APIs - Inline vi-mode search using `f`/`F`/`t`/`T` - `window.blur` config option to request blur for transparent windows - `--option` argument for `alacritty msg create-window` - Support for `DECRQM`/`DECRPM` escape sequences - Support for kitty's keyboard protocol ### Changed - Mode-specific bindings can now be bound in any mode for easier macros - `--help` output is more compact now and uses more neutral palette - Configuration file now uses TOML instead of YAML Run `alacritty migrate` to automatically convert all configuration files - Deprecated config option `draw_bold_text_with_bright_colors`, use `colors.draw_bold_text_with_bright_colors` - Deprecated config option `key_bindings`, use `keyboard.bindings` - Deprecated config option `mouse_bindings`, use `mouse.bindings` - The default colorscheme is now based on base16 classic dark - IME popup now tries to not obscure the current cursor line - The double click threshold was raised to `400ms` - OSC 52 paste ability is now **disabled by default**; use `terminal.osc52` to adjust it - Apply `colors.transparent_background_colors` for selections, hints, and search matches - Underline full hint during keyboard selection - Synchronized updates now use `CSI 2026` instead of legacy `DCS` variant - In mouse mode with `Shift` pressed, mouse bindings without `Shift` are only triggered if no exact binding (i.e. one with `Shift`) is found. - Use built-in font for powerline symbols from `U+E0B0` to `U+E0B3` - Default `bell.animation` is now `Linear` - `IncreaseFontSize/DecreaseFontSize` step is now 1px - `font.size` precision was raised to 6 floating point digits - Default font size to `11.25` matching 15px - `Xft.dpi` is now reloaded when xsettingd change its value on X11 ### Fixed - Unconditional query of xdg-portal settings on Wayland - `Maximized` startup mode not filling the screen properly on GNOME Wayland - `OptionAsAlt` with `OnlyLeft`/`OnlyRight` settings not working properly on macOS - Default Vi key bindings for `Last`/`First` actions not working on X11/Wayland - Cut off wide characters in preedit string - Scrolling on touchscreens - Double clicking on CSD titlebar not always maximizing a window on Wayland - Excessive memory usage when using regexes with a large number of possible states - `window.decorations_theme_variant` not live reloading - Copy/Paste being truncated to 64KiB on Wayland - X11 clipboard lagging behind sometimes - High wakeup count on Wayland due to clipboard polling - Blocking paste freezing alacritty on Wayland - `Command` modifier persisting after `Cmd + Tab` on macOS - Crash on exit when using NVIDIA binary drivers on Wayland - `window.startup_mode` applied to window again when creating new tab - Crash when leaving search after resize - Cursor being hidden after reaching cursor blinking timeout - Message bar content getting stuck after closing with multiple messages on Wayland - Vi cursor position not redrawn on PageUp/PageDown without scrollback - Cursor not updating when blinking and viewport is scrolled - Failure to start with recent version of mesa's i915 driver - Error when using `chars` inside the mouse bindings ### Removed - Config option `background_opacity`, use `window.background_opacity` - Config option `colors.search.bar`, use `colors.footer_bar` instead - Config option `mouse.url`, use the `hints` config section - Config options `mouse.double_click` and `mouse.triple_click` ## 0.12.3 ### Fixed - Crash on macOS Sonoma due to change in macOS resize handling - Crash when Wayland compositor advertises `wl_compositor@v5` interface ## 0.12.2 ### Fixed - Hyperlink preview not being shown when the terminal has exactly 2 lines - Crash on Windows when changing display scale factor - Freeze with some drivers when using GLX - Crash when shrinking the terminal scrolled into the history ## 0.12.1 ### Fixed - Character `;` inside the `URI` in `OSC 8` sequence breaking the URI - Selection on last line not updating correctly on resize - Keyboard input not working on macOS with some IMEs like Fig.io - Very long startup times on Wayland systems with broken xdg-portal setup. - Error on startup with `GLX` when using old mesa platforms ## 0.12.0 ### Added - Uppercase `-T` short form for `--title` - Support for horizontal scrolling in mouse mode and alternative scrolling modes - Support for fractional scaling on Wayland with wp-fractional-scale protocol - Support for running on GLES context - Touchscreen input for click/scroll/select/zoom - `window.resize_increments` config option, disabled by default ### Changed - Always use sRGB color space on macOS - Erase in line after the last column will no longer clear the last column - Open new windows by default with macOS `Cmd`+`N` binding - The hint about window transparency is now properly issued on Wayland and macOS - `window.decorations_theme_variant` could now control theme on macOS and Windows - The IME purpose is now set to `Terminal` which could help with OSK - `window.decorations_theme_variant` is now using `Dark`, `Light`, and `None` values - Resize increments are now set on macOS and X11 to resize by cell sizes ### Fixed - `--help` output for `--class` does not match man pages - Cursor and underlines always being black on very old hardware - Crash when using very low negative `font.offset` - Startup failure on macOS with default config when system `/bin/sh` is `dash` - Artifacts in corners for maximized window with CSD on Wayland - Dotted underline not shown on macOS - Underline on macOS always being at the bottom of the cell - Crash with `OT-SVG` fonts on Linux/BSD - Crash during text compose on old GNOME under Wayland - Mouse cursor staying hidden after window regains focus on macOS Ventura - Blurry fonts when changing padding size at runtime - Crash while typing on Wayland - Multi-line semantic bracket selection - Reduced GPU memory usage - Low frame rate when multiple windows render at the same time - Redraw hanging until a keypress on X11 in rare cases - Window clipping when maximizing a window without decorations on Windows - Quadrants not aligned with half blocks with built-in font - EOT (`\x03`) escaping bracketed paste mode - Drag & Drop not working for the search bar - Simple-fullscreened window not resized when moving between monitors on macOS ### Removed - `window.gtk_theme_variant` config field; use `window.decorations_theme_variant` instead - `alt_send_esc` is now always set to `true` ## 0.11.0 ### Packaging - Minimum Rust version has been bumped to 1.60.0 ## 0.11.0 ### Packaging - Minimum Rust version has been bumped to 1.57.0 - Renamed `io.alacritty.Alacritty.appdata.xml` to `org.alacritty.Alacritty.appdata.xml` - Renamed `io.alacritty` to `org.alacritty` for `Alacritty.app` ### Added - Track and report surface damage information to Wayland compositors - Escape sequence for undercurl, dotted and dashed underlines (`CSI 4 : [3-5] m`) - `ToggleMaximized` key binding action to (un-)maximize the active window, not bound by default - Support for OpenGL ES 2.0 - Escape sequence to set underline color (`CSI 58 : 2 : Ps : Ps : Ps m`/`CSI 58 : 5 : Ps m`) - Escape sequence to reset underline color (`CSI 59 m`) - Vi mode keybinding (z) to center view around vi mode cursor - Accept hexadecimal values starting with `0x` for `--embed` - Config option `cursor.blink_timeout` to timeout cursor blinking after inactivity - Escape sequence to set hyperlinks (`OSC 8 ; params ; URI ST`) - Config `hints.enabled.hyperlinks` for hyperlink escape sequence hint highlight - `window.decorations_theme_variant` to control both Wayland CSD and GTK theme variant on X11 - Support for inline input method ### Changed - No longer renders to macos and x11 windows that are fully occluded / not directly visible - The `--help` output was reworked with a new colorful syntax - OSC 52 is now disabled on unfocused windows - `SpawnNewInstance` no longer inherits initial `--command` - Blinking cursor will timeout after `5` seconds by default - Deprecated `colors.search.bar`, use `colors.footer_bar` instead - On macOS, Alacritty now reads `AppleFontSmoothing` from user defaults to control font smoothing - Warn when either `columns` or `lines` is non-zero, but not both - Client side decorations should have proper text rendering now on Wayland - Config option `window.gtk_theme_variant`, you should use `window.decorations_theme_variant` instead - `--class` now sets both class part of WM_CLASS property and instance - `--class`'s `general` and `instance` options were swapped - Search bar is now respecting cursor thickness - On X11 the IME popup window is stuck at the bottom of the window due to Xlib limitations - IME no longer works in Vi mode when moving around ### Fixed - Creating the IPC socket failing if `WAYLAND_DISPLAY` contains an absolute path - Crash when resetting the terminal while in vi mode - `font.glyph_offset` not live reloading - Failure when running on 10-bit color system - The colors being slightly different when using srgb displays on macOS - Vi cursor blinking not reset when navigating in search - Scrolling and middle-clicking modifying the primary selection - Bottom gap for certain builtin box drawing characters - Incorrect built-in glyphs for `U+2567` and `U+2568` - Character mappings in the DEC special graphics character set (line drawing) - Window flickering on resize on Wayland - Unnecessary config reload when using `/dev/null` as a config file - Windows `Open Alacritty Here` on root of drive displaying error - On macOS, `font.use_thin_strokes` did not work since Big Sur - On macOS, trying to load a disabled font would crash - On macOS, Alacritty sessions did not appear in the list of tty sessions for `w` and `who` - Cursor not hiding on GNOME Wayland - Font having different scale factor after monitor powering off/on on X11 - Viewport not updating after opening a new tabbed window on macOS - Terminal not exiting sometimes after closing all windows on macOS - CPU usage spikes due to mouse movements for unfocused windows on X11/Windows - First window on macOS not tabbed with system prefer tabs setting - Window being treaten as focused by default on Wayland ### Removed - `font.use_thin_strokes` config field; to use thin strokes on macOS, set `AppleFontSmoothing` to 0 with `$ defaults write -g AppleFontSmoothing -int 0` ## 0.10.1 ### Added - Option `font.builtin_box_drawing` to disable the built-in font for drawing box characters ### Changed - Builtin font thickness is now based on cell width instead of underline thickness ### Fixed - OSC 4 not handling `?` - `?` in OSC strings reporting default colors instead of modified ones - OSC 104 not clearing colors when second parameter is empty - Builtin font lines not contiguous when `font.offset` is used - `font.glyph_offset` is no longer applied on builtin font - Buili-in font arcs alignment - Repeated permission prompts on M1 macs - Colors being slightly off when using `colors.transparent_background_colors` ## 0.10.0 ### Packaging - New `extra/alacritty-msg.man` manpage for the `alacritty msg` subcommand - Minimum Rust version has been bumped to 1.53.0 ### Added - Option `colors.transparent_background_colors` to allow applying opacity to all background colors - Support for running multiple windows from a single Alacritty instance (see docs/features.md) - Urgency support on Wayland via `xdg_activation_v1` ### Changed - `ExpandSelection` is now a configurable mouse binding action - Config option `background_opacity`, you should use `window.opacity` instead - Reload configuration files when their symbolic link is replaced - Strip trailing whitespaces when yanking from a block selection - Display area keeps history position when viewport is cleared - Commands spawn from the current directory of the foreground shell in Unix-like systems - Remove trailing newline from strings taken from hints or simple/semantic selections - Builtin font is now used for box drawing characters from `U+2500` to `U+259f` - Logs now print the time since startup instead of the local time ### Fixed - Line indicator obstructing vi mode cursor when scrolled into history - Vi mode search starting in the line below the vi cursor - Invisible cursor with matching foreground/background colors - Crash when hovering over a match emptied by post-processing - Crash when the vi cursor is on the scrollback and viewport clear is invoked - Freeze when the vi cursor is on the scrollback and scrollback clear is invoked - Vi cursor on topmost of the display moving downward when scrolled into history with active output - Input lag on Wayland with Nvidia binary driver - Crash when hovering the mouse over fullwidth characters - Do not create logfile if the file already exists ### Removed - Wayland client side decorations were simplified ## 0.9.0 ### Packaging - Minimum Rust version has been bumped to 1.46.0 ### Added - Support for `ipfs`/`ipns` URLs - Mode field for regex hint bindings ### Fixed - Regression in rendering performance with dense grids since 0.6.0 - Crash/Freezes with partially visible fullwidth characters due to alt screen resize - Incorrect vi cursor position after invoking `ScrollPage*` action - Slow PTY read performance with extremely dense grids - Crash when resizing during vi mode - Unintentional text selection range change after leaving vi mode - Deadlock on Windows during high frequency output - Search without vi mode not starting at the correct location when scrolled into history - Crash when starting a vi mode search from the bottommost line - Original scroll position not restored after canceling search - Clipboard copy skipping non-empty cells when encountering an interrupted tab character - Vi mode cursor moving downward when scrolled in history with active output - Crash when moving fullwidth characters off the side of the terminal in insert mode - Broken bitmap font rendering with FreeType 2.11+ - Crash with non-utf8 font paths on Linux - Newly installed fonts not rendering until Alacritty restart ## 0.8.0 ### Packaging - Minimum Rust version has been bumped to 1.45.0 ### Packaging - Updated shell completions - Added ARM executable to prebuilt macOS binaries ### Added - IME composition preview not appearing on Windows - Synchronized terminal updates using `DCS = 1 s ST`/`DCS = 2 s ST` - Regex terminal hints ([see features.md](./docs/features.md#hints)) - macOS keybinding (cmd+alt+H) hiding all windows other than Alacritty - Support for `magnet` URLs ### Changed - The vi mode cursor is now created in the top-left if the terminal cursor is invisible - Focused search match will use cell instead of match colors for CellForeground/CellBackground - URL highlighting has moved from `mouse.url` to the `hints` config section ### Fixed - Alacritty failing to start on X11 with invalid DPI reported by XRandr - Text selected after search without any match - Incorrect vi cursor position after leaving search - Clicking on URLs on Windows incorrectly opens File Explorer - Incorrect underline cursor thickness on wide cell - Viewport moving around when resizing while scrolled into history - Block cursor not expanding across fullwidth characters when on the right side of it - Overwriting fullwidth characters only clearing one of the involved cells ### Removed - Config field `visual_bell`, you should use `bell` instead ## 0.7.2 ### Packaging - Updated shell completions ### Fixed - Crash due to assertion failure on 32-bit architectures - Segmentation fault on shutdown with Wayland - Incorrect estimated DPR with Wayland - Consecutive clipboard stores dropped on Wayland until the application is refocused ## 0.7.1 ### Fixed - Jumping between matches in backward vi search ## 0.7.0 ### Added - Support for `~/` at the beginning of configuration file imports - New `cursor.style.blinking` option to set the default blinking state - New `cursor.blink_interval` option to configure the blinking frequency - Support for cursor blinking escapes (`CSI ? 12 h`, `CSI ? 12 l` and `CSI Ps SP q`) - IME support on Windows - Urgency support on Windows - Customizable keybindings for search - History for search mode, bound to ^P/^N/Up/Down by default - Default binding to cancel search on Ctrl+C - History position indicator for search and vi mode ### Changed - Nonexistent config imports are ignored instead of raising an error - Value for disabling logging with `config.log_level` is `Off` instead of `None` - Missing glyph symbols are no longer drawn for zerowidth characters ### Fixed - Wide characters sometimes being cut off - Preserve vi mode across terminal `reset` - Escapes `CSI Ps b` and `CSI Ps Z` with large parameters locking up Alacritty - Dimming colors which use the indexed `CSI 38 : 5 : Ps m` notation - Slow rendering performance with a lot of cells with underline/strikeout attributes - Performance of scrolling regions with offset from the bottom - Extra mouse buttons are no longer ignored on Wayland - Numpad arrow keys are now properly recognized on Wayland - Compilation when targeting aarch64-apple-darwin - Window not being completely opaque on Windows - Window being always on top during alt-tab on Windows - Cursor position not reported to apps when mouse is moved with button held outside of window - No live config update when starting Alacritty with a broken configuration file - PTY not drained to the end with the `--hold` flag enabled - High CPU usage on BSD with live config reload enabled - Alacritty not discarding invalid escape sequences starting with ESC - Crash due to clipboard not being properly released on Wayland - Shadow artifacts when resizing transparent windows on macOS - Missing glyph symbols not being rendered for missing glyphs on macOS and Windows - Underline cursor being obscured by underline - Cursor not being rendered with a lot of unicode glyphs visible - IME input swallowed after triggering a key binding - Crash on Wayland due to non-standard fontconfig configuration - Search without vi mode not jumping properly between all matches ### Removed - The following CLI arguments have been removed in favor of the `--option` flag: * `--persistent-logging` * `--live-config-reload` * `--no-live-config-reload` * `--dimensions` * `--position` - `live-shader-reload` feature - Config option `dynamic_title`, you should use `window.dynamic_title` instead - Config option `scrolling.faux_multiplier`, which was replaced by escape `CSI ? 1007 h/l` - WinPTY support on Windows ## 0.6.0 ### Packaging - Minimum Rust version has been bumped to 1.43.0 - The snapcraft.yaml file has been removed - Updated `setab`/`setaf` capabilities in `alacritty-direct` to use colons - WinPTY is now enabled only when targeting MSVC - Deprecated the WinPTY backend feature, disabling it by default ### Added - Secondary device attributes escape (`CSI > 0 c`) - Support for colon separated SGR 38/48 - New Ctrl+C binding to cancel search and leave vi mode - Escapes for double underlines (`CSI 4 : 2 m`) and underline reset (`CSI 4 : 0 m`) - Configuration file option for sourcing other files (`import`) - CLI parameter `--option`/`-o` to override any configuration field - Escape sequences to report text area size in pixels (`CSI 14 t`) and in characters (`CSI 18 t`) - Support for single line terminals dimensions - Right clicking on Wayland's client side decorations will show application menu - Escape sequences to enable and disable window urgency hints (`CSI ? 1042 h`, `CSI ? 1042 l`) ### Changed - Cursors are now inverted when their fixed color is similar to the cell's background - Use the working directory of the terminal foreground process, instead of the shell's working directory, for `SpawnNewInstance` action - Fallback to normal underline for unsupported underline types in `CSI 4 : ? m` escapes - The user's background color is now used as the foreground for the render timer - Use yellow/red from the config for error and warning messages instead of fixed colors - Existing CLI parameters are now passed to instances spawned using `SpawnNewInstance` - Wayland's Client side decorations now use the search bar colors - Reduce memory usage by up to at least 30% with a full scrollback buffer - The number of zerowidth characters per cell is no longer limited to 5 - `SpawnNewInstance` is now using the working directory of the terminal foreground process on macOS ### Fixed - Incorrect window location with negative `window.position` config options - Slow rendering performance with HiDPI displays, especially on macOS - Keys swallowed during search when pressing them right before releasing backspace - Crash when a wrapped line is rotated into the last line - Selection wrapping to the top when selecting below the error/warning bar - Pasting into clients only supporting `UTF8_STRING` mime type on Wayland - Crash when copying/pasting with neither pointer nor keyboard focus on Wayland - Crash due to fd leak on Wayland - IME window position with fullwidth characters in the search bar - Selection expanding over 2 characters when scrolled in history with fullwidth characters in use - Selection scrolling not starting when mouse is over the message bar - Incorrect text width calculation in message bar when the message contains multibyte characters - Remapped caps lock to escape not triggering escape bindings on Wayland - Crash when setting overly long title on Wayland - Switching in and out of various window states, like Fullscreen, not persisting window size on Wayland - Crash when providing 0 for `XCURSOR_SIZE` on Wayland - Gap between window and server side decorations on KWIN Wayland - Wayland's client side decorations not working after tty switch - `Fullscreen` startup mode not working on Wayland - Window not being rescaled when changing DPR of the current monitor on Wayland - Crash in some cases when pointer isn't presented upon startup on Wayland - IME not working on Wayland - Crash on startup on GNOME since its 3.37.90 version on Wayland - Touchpad scrolling scrolled less than it should on macOS/Wayland on scaled outputs - Incorrect modifiers at startup on X11 - `Add` and `Subtract` keys are now named `NumpadAdd` and `NumpadSubtract` respectively - Feature checking when cross compiling between different operating systems - Crash when writing to the clipboard fails on Wayland - Crash with large negative `font.offset.x/y` - Visual bell getting stuck on the first frame - Zerowidth characters in the last column of the line ## 0.5.0 ### Packaging - Minimum Rust version has been bumped to 1.41.0 - Prebuilt Linux binaries have been removed - Added manpage, terminfo, and completions to macOS application bundle - On Linux/BSD the build will fail without Fontconfig installed, instead of building it from source - Minimum FreeType version has been bumped to 2.8 on Linux/BSD ### Added - Default Command+N keybinding for SpawnNewInstance on macOS - Vi mode for regex search, copying text, and opening links - `CopySelection` action which copies into selection buffer on Linux/BSD - Option `cursor.thickness` to set terminal cursor thickness - Font fallback on Windows - Support for Fontconfig embolden and matrix options - Opt-out compilation flag `winpty` to disable WinPTY support - Scrolling during selection when mouse is at top/bottom of window - Expanding existing selections using single, double and triple click with the right mouse button - Support for `gopher` and `gemini` URLs - Unicode 13 support - Option to run command on bell which can be set in `bell.command` - Fallback to program specified in `$SHELL` variable on Linux/BSD if it is present - Ability to make selections while search is active ### Changed - Block cursor is no longer inverted at the start/end of a selection - Preserve selection on non-LMB or mouse mode clicks - Wayland client side decorations are now based on config colorscheme - Low resolution window decoration icon on Windows - Mouse bindings for additional buttons need to be specified as a number not a string - Don't hide cursor on modifier press with `mouse.hide_when_typing` enabled - `Shift + Backspace` now sends `^?` instead of `^H` - Default color scheme is now `Tomorrow Night` with the bright colors of `Tomorrow Night Bright` - Set IUTF8 termios flag for improved UTF8 input support - Dragging files into terminal now adds a space after each path - Default binding replacement conditions - Adjusted selection clearing granularity to more accurately match content - To use the cell's text color for selection with a modified background, the `color.selection.text` variable must now be set to `CellForeground` instead of omitting it - URLs are no longer highlighted without a clearly delimited scheme - Renamed config option `visual_bell` to `bell` - Moved config option `dynamic_title` to `window.dynamic_title` - When searching without vi mode, matches are only selected once search is cancelled ### Fixed - Selection not cleared when switching between main and alt grid - Freeze when application is invisible on Wayland - Paste from some apps on Wayland - Slow startup with Nvidia binary drivers on some X11 systems - Display not scrolling when printing new lines while scrolled in history - Regression in font rendering on macOS - Scroll down escape (`CSI Ps T`) incorrectly pulling lines from history - Dim escape (`CSI 2 m`) support for truecolor text - Incorrectly deleted lines when increasing width with a prompt wrapped using spaces - Documentation for class in `--help` missing information on setting general class - Linewrap tracking when switching between primary and alternate screen buffer - Preservation of the alternate screen's saved cursor when swapping to primary screen and back - Reflow of cursor during resize - Cursor color escape ignored when its color is set to inverted in the config - Fontconfig's `autohint` and `hinting` options being ignored - Ingoring of default FreeType properties - Alacritty crashing at startup when the configured font does not exist - Font size rounding error - Opening URLs while search is active ### Removed - Environment variable `RUST_LOG` for selecting the log level - Deprecated `window.start_maximized` config field - Deprecated `render_timer` config field - Deprecated `persistent_logging` config field ## 0.4.3 ### Fixed - Tabstops not being reset with `reset` - Fallback to `LC_CTYPE=UTF-8` on macOS without valid system locale - Resize lag on launch under some X11 wms - Increased input latency due to vsync behavior on X11 - Emoji colors blending with terminal background - Fix escapes prematurely terminated by terminators in unicode glyphs - Incorrect location when clicking inside an unfocused window on macOS - Startup mode `Maximized` on Windows - Crash when writing a fullwidth character in the last column with auto-wrap mode disabled - Crashing at startup on Windows ## 0.4.2 ### Packaging - Minimum Rust version has been bumped to 1.37.0 - Added Rust features `x11` and `wayland` to pick backends, with both enabled by default - Capitalized the Alacritty.desktop file ### Added - Live config reload for `window.title` ### Changed - Pressing additional modifiers for mouse bindings will no longer trigger them - Renamed `WINIT_HIDPI_FACTOR` environment variable to `WINIT_X11_SCALE_FACTOR` - Print an error instead of crashing, when startup working directory is invalid - Line selection will now expand across wrapped lines - The default value for `draw_bold_text_with_bright_colors` is now `false` - Mirror OSC query terminators instead of always using BEL - Increased Beam, Underline, and Hollow Block cursors' line widths - Dynamic title is not disabled anymore when `window.title` is set in config ### Fixed - Incorrect default config path in `--help` on Windows and macOS - Semantic selection stopping at full-width glyphs - Full-width glyphs cut off in last column - Crash when starting on some X11 systems - Font size resetting when Alacritty is moved between screens - Limited payload length in clipboard escape (used for Tmux copy/paste) - Alacritty not ignoring keyboard events for changing WM focus on X11 - Regression which added a UNC path prefix to the working directory on Windows - CLI parameters discarded when config is reload - Blurred icons in KDE task switcher (alacritty.ico is now high-res) - Consecutive builds failing on macOS due to preexisting `/Application` symlink - Block selection starting from first column after beginning leaves the scrollback - Incorrect selection status of the first cell when selection is off screen - Backwards bracket selection - Stack overflow when printing shader creation error - Underline position for bitmap fonts - Selection rotating outside of scrolling region - Throughput performance problems caused by excessive font metric queries - Unicode throughput performance on Linux/BSD - Resize of bitmap fonts - Crash when using bitmap font with `embeddedbitmap` set to `false` - Inconsistent fontconfig fallback - Handling of OpenType variable fonts - Expansion of block-selection on partially selected full-width glyphs - Minimize action only works with decorations on macOS - Window permanently vanishing after hiding on macOS - Handling of URLs with single quotes - Parser reset between DCS escapes - Parser stopping at unknown DEC private modes/SGR character attributes - Block selection appending duplicate newlines when last column is selected - Bitmap fonts being a bit smaller than they should be in some cases - Config reload creating alternate screen history instead of updating scrollback - Crash on Wayland compositors supporting `wl_seat` version 7+ - Message bar not hiding after fixing wrong color value in config - Tabstops cleared on resize - Tabstops not breaking across lines - Crash when parsing DCS escape with more than 16 parameters - Ignoring of slow touchpad scrolling - Selection invisible when starting above viewport and ending below it - Clipboard not working after TTY switch on Wayland - Crash when pasting non UTF-8 string advertised as UTF-8 string on Wayland - Incorrect modifiers tracking on X11 and macOS, leading to 'sticky' modifiers - Crash when starting on Windows with missing dark mode support - Variables `XCURSOR_THEME` and `XCURSOR_SIZE` ignored on Wayland - Low resolution mouse cursor and decorations on HiDPI Wayland outputs - Decorations visible when in fullscreen on Wayland - Window size not persisted correctly after fullscreening on macOS - Crash on startup with some locales on X11 - Shrinking terminal height in alt screen deleting primary screen content ### Removed - Config option `auto_scroll`, which is now always disabled - Config option `tabspaces`, which is now fixed at `8` ## 0.4.1 ### Packaging - Added compatibility logo variants for environments which can't render the default SVG ### Added - Terminal escape bindings with combined modifiers for Delete and Insert - /Applications symlink into OS X DMG for easier installation - Colored emojis on Linux/BSD - Value `randr` for `WINIT_HIDPI_FACTOR`, to ignore `Xft.dpi` and scale based on screen dimensions - `Minimize` key binding action, bound to `cmd + m` on macOS ### Changed - On Windows, the ConPTY backend will now be used by default if available - The `enable_experimental_conpty_backend` config option has been replaced with `winpty_backend` ### Fixed - URLs not truncated with non-matching single quote - Absolute file URLs (`file:///home`) not recognized because of leading `/` - Clipboard escape `OSC 52` not working with empty clipboard parameter - Direct escape input on Windows using alt - Incorrect window size on X11 when waking up from suspend - Width of Unicode 11/12 emojis - Minimize on windows causing layout issues - Performance bottleneck when clearing colored rows - Vague startup crash messages on Windows with WinPTY backend - Deadlock on Windows when closing Alacritty using the title bar "X" button (ConPTY backend) - Crash on `clear` when scrolled up in history - Entire screen getting underlined/stroke out when running `clear` - Slow startup on some Wayland compositors - Padding not consistently visible on macOS - Decorations ignoring Windows dark theme - Crash on macOS when starting maximized without decorations - Resize cursor not showing up on Wayland - Maximized windows spawning behind system panel on Gnome Wayland ### Removed - Support for 8-bit C1 escape sequences ## 0.4.0 ### Packaging - Minimum Rust version has been bumped to 1.36.0 - Config is not generated anymore, please consider distributing the alacritty.yml as documentation - Removed Alacritty terminfo from .deb in favor of ncurses provided one ### Added - Block selection mode when Control is held while starting a selection - Allow setting general window class on X11 using CLI or config (`window.class.general`) - Config option `window.gtk_theme_variant` to set GTK theme variant - Completions for `--class` and `-t` (short title) - Change the mouse cursor when hovering over the message bar and its close button - Support combined bold and italic text (with `font.bold_italic` to customize it) - Extra bindings for F13-F20 - Terminal escape bindings with combined modifiers - Bindings for ScrollToTop and ScrollToBottom actions - `ReceiveChar` key binding action to insert the key's text character - New CLI flag `--hold` for keeping Alacritty opened after its child process exits - Escape sequence to save and restore window title from stack - Alternate scroll escape sequence (`CSI ? 1007 h` / `CSI ? 1007 l`) - Print name of launch command if Alacritty failed to execute it - Live reload font settings from config - UTF-8 mouse mode escape sequence (`CSI ? 1005 h` / `CSI ? 1005 l`) - Escape for reading clipboard (`OSC 52 ; ; ? BEL`) - Set selection clipboard (`OSC 52 ; ; BEL`) ### Changed - On Windows, query DirectWrite for recommended anti-aliasing settings - Scroll lines out of the visible region instead of deleting them when clearing the screen ### Fixed - GUI programs launched by Alacritty starting in the background on X11 - Text Cursor position when scrolling - Performance issues while resizing Alacritty - First unfullscreen action ignored on window launched in fullscreen mode - The window is now filled with the background color before displaying - Cells sometimes not getting cleared correctly - X11 clipboard hanging when mime type is set - On macOS, Alacritty will now fallback to Menlo if a font specified in the config cannot be loaded - Debug ref tests are now written to disk regardless of shutdown method - Cursor color setting with escape sequence - Override default bindings with subset terminal mode match - On Linux, respect fontconfig's `embeddedbitmap` configuration option - Selecting trailing tab with semantic expansion - URL parser incorrectly handling Markdown URLs and angled brackets - Intermediate bytes of CSI sequences not checked - Wayland clipboard integration - Use text mouse cursor when mouse mode is temporarily disabled with shift - Wayland primary selection clipboard not storing text when selection is stopped outside of the window - Block URL highlight while a selection is active - Bindings for Alt + F1-F12 - Discard scrolling region escape with bottom above top - Opacity always applying to cells with their background color matching the teriminal background - Allow semicolons when setting titles using an OSC - Background always opaque on X11 - Skipping redraws on PTY update - Not redrawing while resizing on Windows/macOS - Decorations `none` launching an invisible window on Windows - Alacritty turning transparent when opening another window on macOS with chunkwm - Startup mode `Maximized` having no effect on Windows - Inserting Emojis using `Super+.` or compose sequences on Windows - Change mouse cursor depending on mode with Wayland - Hide mouse cursor when typing if the `mouse.hide_when_typing` option is set on Wayland - Glitches when DPI changes on Windows - Crash when resuming after suspension - Crash when trying to start on X11 with a Wayland compositor running - Crash with a virtual display connected on X11 - Use `\` instead of `\\` as path separators on Windows for logging config file location - Underline/strikeout drawn above visual bell - Terminal going transparent during visual bell - Selection not being cleared when sending chars through a binding - Mouse protocols/encodings not being mutually exclusive within themselves - Escape `CSI Ps M` deleting lines above cursor when at the bottom of the viewport - Cell reset not clearing underline, strikeout and foreground color - Escape `CSI Ps c` honored with a wrong `Ps` - Ignore `ESC` escapes with invalid intermediates - Blank lines after each line when pasting from GTK apps on Wayland ### Removed - Bindings for Super/Command + F1-F12 - Automatic config generation - Deprecated `scrolling.faux_multiplier`, the alternate scroll escape can now be used to disable it and `scrolling.multiplier` controls the number of scrolled lines ## 0.3.3 ### Packaging - Add appstream metadata, located at /extra/linux/io.alacritty.Alacritty.xml - The xclip dependency has been removed - On macOS, Alacritty now requests NSSystemAdministrationUsageDescription to avoid permission failures - Minimum Rust version has been bumped to 1.32.0 ### Added - Added ToggleFullscreen action - On macOS, there's a ToggleSimpleFullscreen action which allows switching to fullscreen without occupying another space - A new window option `window.startup_mode` which controls how the window is created - `_NET_WM_ICON` property is set on X11 now, allowing for WMs to show icons in titlebars - Current Git commit hash to `alacritty --version` - Config options `window.title` and `window.class` - Config option `working_directory` - Config group `debug` with the options `debug.log_level`, `debug.print_events` and `debug.ref_test` - Select until next matching bracket when double-clicking a bracket - Added foreground/background escape code request sequences - Escape sequences now support 1, 3, and 4 digit hex colors ### Changed - On Windows, Alacritty will now use the native DirectWrite font API - The `start_maximized` window option is now `startup_mode: Maximized` - Cells with identical foreground and background will now show their text upon selection/inversion - Default Window padding to 0x0 - Moved config option `render_timer` and `persistent_logging` to the `debug` group - When the cursor is in the selection, it will be inverted again, making it visible ### Fixed - Double-width characters in URLs only being highlit on the left half - PTY size not getting updated when message bar is shown - Text Cursor disappearing - Incorrect positioning of zero-width characters over double-width characters - Mouse mode generating events when the cell has not changed - Selections not automatically expanding across double-width characters - On macOS, automatic graphics switching has been enabled again - Text getting recognized as URLs without slashes separating the scheme - URL parser dropping trailing slashes from valid URLs - UTF-8 BOM skipped when reading config file - Terminfo backspace escape sequence (`kbs`) ### Removed - Deprecated `mouse.faux_scrollback_lines` config field - Deprecated `custom_cursor_colors` config field - Deprecated `hide_cursor_when_typing` config field - Deprecated `cursor_style` config field - Deprecated `unfocused_hollow_cursor` config field - Deprecated `dimensions` config field ## Version 0.3.2 ### Fixed - Panic on startup when using Conpty on Windows ## Version 0.3.1 ### Added - Added ScrollLineUp and ScrollLineDown actions for scrolling line by line - Native clipboard support on X11 and Wayland ### Changed - Alacritty now has a fixed minimum supported Rust version of 1.31.0 ### Fixed - Reset scrolling region when the RIS escape sequence is received - Subprocess spawning on macos - Unnecessary resize at startup - Text getting blurry after live-reloading shaders with padding active - Resize events are not send to the shell anymore if dimensions haven't changed - Minor performance issues with underline and strikeout checks - Rare bug which would extend underline and strikeout beyond the end of line - Cursors not spanning two lines when over double-width characters - Incorrect cursor dimensions if the font offset isn't `0` ## Version 0.3.0 ### Packaging - On Linux, the .desktop file now uses `Alacritty` as icon name, which can be found at `extra/logo/alacritty-term.svg` ### Added - MSI installer for Windows is now available - New default key bindings Alt+Home, Alt+End, Alt+PageUp and Alt+PageDown - Dynamic title support on Windows - Ability to specify starting position with the `--position` flag - New configuration field `window.position` allows specifying the starting position - Added the ability to change the selection color - Text will reflow instead of truncating when resizing Alacritty - Underline text and change cursor when hovering over URLs with required modifiers pressed ### Changed - Clicking on non-alphabetical characters in front of URLs will no longer open them - Command keybindings on Windows will no longer open new cmd.exe console windows - On macOS, automatic graphics switching has been temporarily disabled due to a macos bug ### Fixed - Fix panic which could occur when quitting Alacritty on Windows if using the Conpty backend - Automatic copying of selection to clipboard when mouse is released outside of Alacritty - Scrollback history live reload only working when shrinking lines - Crash when decreasing scrollback history in config while scrolled in history - Resetting the terminal while in the alt screen will no longer disable scrollback - Cursor jumping around when leaving alt screen while not in the alt screen - Text lingering around when resetting while scrolled up in the history - Terminfo support for extended capabilities - Allow mouse presses and beginning of mouse selection in padding - Windows: Conpty backend could close immediately on startup in certain situations - FreeBSD: SpawnNewInstance will now open new instances in the shell's current working directory as long as linprocfs(5) is mounted on `/compat/linux/proc` - Fix lingering Alacritty window after child process has exited - Growing the terminal while scrolled up will no longer move the content down - Support for alternate keyboard layouts on macOS - Slow startup time on some X11 systems - The AltGr key no longer sends escapes (like Alt) - Fixes increase/decrease font-size keybindings on international keyboards - On Wayland, the `--title` flag will set the Window title now - Parsing issues with URLs starting in the first or ending in the last column - URLs stopping at double-width characters - Fix `start_maximized` option on X11 - Error when parsing URLs ending with Unicode outside of the ascii range - On Windows, focusing a Window will no longer start a selection ## Version 0.2.9 ### Changed - Accept fonts which are smaller in width or height than a single pixel ### Fixed - Incorrect font spacing after moving Alacritty between displays ## Version 0.2.8 ### Added - Window class on Wayland is set to `Alacritty` by default - Log file location is stored in the `ALACRITTY_LOG` environment variable - Close button has been added to the error/warning messages ### Changed - Improve scrolling accuracy with devices sending fractional updates (like touchpads) - `scrolling.multiplier` now affects normal scrolling with touchpads - Error/Warning bar doesn't overwrite the terminal anymore - Full error/warning messages are displayed - Config error messages are automatically removed when the config is fixed - Scroll history on Shift+PgUp/PgDown when scrollback history is available ### Fixed - Resolved off-by-one issue with erasing characters in the last column - Excessive polling every 100ms with `live_config_reload` enabled - Unicode characters at the beginning of URLs are now properly ignored - Remove error message when reloading an empty config - Allow disabling URL launching by setting the value of `mouse.url.launcher` to `None` - Corrected the `window.decorations` config documentation for macOS - Fix IME position on HiDPI displays - URLs not opening while terminal is scrolled - Reliably remove log file when Alacritty is closed and persistent logging is disabled - Remove selections when clearing the screen partially (scrolling horizontally in less) - Crash/Freeze when shrinking the font size too far - Documentation of the `--dimensions` flag have been updated to display the correct default ### Removed - `clear` doesn't remove error/warning messages anymore ## Version 0.2.7 ### Fixed - Crash when trying to start Alacritty on Windows ## Version 0.2.6 ### Added - New `alt_send_esc` option for controlling if alt key should send escape sequences ### Changed - All options in the configuration file are now optional ### Fixed - Replaced `Command` with `Super` in the Linux and Windows config documentation - Prevent semantic and line selection from starting with the right or middle mouse button - Prevent Alacritty from crashing when started on a system without any free space - Resolve issue with high CPU usage after moving Alacritty between displays - Characters will no longer be deleted when using ncurses with the hard tab optimization - Crash on non-linux operating systems when using the `SpawnNewInstance` action ### Removed - Windows and macOS configuration files (`alacritty.yml` is now platform independent) ## Version 0.2.5 ### Added - New configuration field `visual_bell.color` allows changing the visual bell color - Crashes on Windows are now also reported with a popup in addition to stderr - Windows: New configuration field `enable_experimental_conpty_backend` which enables support for the Pseudoconsole API (ConPTY) added in Windows 10 October 2018 (1809) update - New mouse and key action `SpawnNewInstance` for launching another instance of Alacritty ### Changed - Log messages are now consistent in style, and some have been removed - Windows configuration location has been moved from %USERPROFILE%\alacritty.yml to %APPDATA%\alacritty\alacritty.yml - Windows default shell is now PowerShell instead of cmd - URL schemes have been limited to http, https, mailto, news, file, git, ssh and ftp ### Fixed - Fix color issue in ncurses programs by updating terminfo pairs from 0x10000 to 0x7FFF - Fix panic after quitting Alacritty on macOS - Tabs are no longer replaced by spaces when copying them to the clipboard - Alt modifier is no longer sent separately from the modified key - Various Windows issues, like color support and performance, through the new ConPTY - Fixed rendering non default mouse cursors in terminal mouse mode (linux) - Fix the `Copy` `mouse_bindings` action ([#1963](https://github.com/alacritty/alacritty/issues/1963)) - URLs are only launched when left-clicking - Removal of extra characters (like `,`) at the end of URLs has been improved - Single quotes (`'`) are removed from URLs when there is no matching opening quote - Precompiled binaries now work with macOS versions before 10.13 (10.11 and above) ## Version 0.2.4 ### Added - Option for evenly spreading extra padding around the terminal (`window.dynamic_padding`) - Option for maximizing alacritty on start (`window.start_maximized`) - Display notice about errors and warnings inside Alacritty - Log all messages to both stderr and a log file in the system's temporary directory - New configuration option `persistent_logging` and CLI flag `--persistent-logging`, for keeping the log file after closing Alacritty - `ClearLogNotice` action for removing the warning and error message - Terminal bells on macOS will now request the user's attention in the window - Alacritty now requests privacy permissions on macOS ### Changed - Extra padding is not evenly spread around the terminal by default anymore - When the config file is empty, Alacritty now logs an info instead of an error message ### Fixed - Fixed a bad type conversion which could cause underflow on a window resize - Alacritty now spawns a login shell on macOS, as with Terminal.app and iTerm2 - Fixed zombie processes sticking around after launching URLs - Zero-width characters are now properly rendered without progressing the cursor ## Version 0.2.3 ### Fixed - Mouse cursor alignment issues and truncated last line caused by incorrect padding calculations ## Version 0.2.2 ### Added - Add support for Windows - Add terminfo capabilities advertising support for changing the window title - Allow using scancodes in the key_bindings section - When `mouse.url.launcher` is set, clicking on URLs will now open them with the specified program - New `mouse.url.modifiers` option to specify keyboard modifiers for opening URLs on click - Binaries for macOS, Windows and Debian-based systems are now published with GitHub releases - The keys F16-F24 have been added as options for key bindings - DEB file adds Alacritty as option to `update-alternatives --config x-terminal-emulator` ### Changed - The `colors.cursor.text` and `colors.cursor.cursor` fields are optional now - Moved `cursor_style` to `cursor.style` - Moved `unfocused_hollow_cursor` to `cursor.unfocused_hollow` - Moved `hide_cursor_when_typing` to `mouse.hide_when_typing` - Mouse bindings now ignore additional modifiers - Extra padding is now spread evenly around the terminal grid - DEB file installs to `usr/bin` instead of `usr/local/bin` ### Fixed - Fixed erroneous results when using the `indexed_colors` config option - Fixed rendering cursors other than rectangular with the RustType backend - Selection memory leak and glitches in the alternate screen buffer - Invalid default configuration on macOS and Linux - Middle mouse pasting if mouse mode is enabled - Selections now properly update as you scroll the scrollback buffer while selecting - NUL character at the end of window titles - DPI Scaling when moving windows across monitors - On macOS, issues with Command-[KEY] and Control-Tab keybindings have been fixed - Incorrect number of columns/lines when using the `window.dimensions` option - On Wayland, windows will no longer be spawned outside of the visible region - Resizing of windows without decorations - On Wayland, key repetition works again - On macOS, Alacritty will now use the integrated GPU again when available - On Linux, the `WINIT_HIDPI_FACTOR` environment variable can be set from the config now ### Removed - The `custom_cursor_colors` config field was deleted, remove the `colors.cursor.*` options to achieve the same behavior as setting it to `false` - The `scale_with_dpi` configuration value has been removed, on Linux the env variable `WINIT_HIDPI_FACTOR=1` can be set instead to disable DPI scaling ## Version 0.2.1 ### Added - Implement the `hidden` escape sequence (`echo -e "\e[8mTEST"`) - Add support for macOS systemwide dark mode - Set the environment variable `COLORTERM="truecolor"` to advertise 24-bit color support - On macOS, there are two new values for the config option `window.decorations`: - `transparent` - This makes the title bar transparent and allows the viewport to extend to the top of the window. - `buttonless` - Similar to transparent but also removed the buttons. - Add support for changing the colors from 16 to 256 in the `indexed_colors` config section - Add `save_to_clipboard` configuration option for copying selected text to the system clipboard - New terminfo entry, `alacritty-direct`, that advertises 24-bit color support - Add support for CSI sequences Cursor Next Line (`\e[nE`) and Cursor Previous Line (`\e[nF`) ### Changed - Inverse/Selection color is now modelled after XTerm/VTE instead of URxvt to improve consistency - First click on unfocused Alacritty windows is no longer ignored on platforms other than macOS - Reduce memory usage significantly by only initializing part of the scrollback buffer at startup - The `alacritty` terminfo entry no longer requires the `xterm` definition to be present on the system - The default `TERM` value is no longer static; the `alacritty` entry is used if available, otherwise the `xterm-256color` entry is used instead - The values `true` and `false` for the config option `window.decorations` have been replaced with `full` and `none` ### Fixed - Rendering now occurs without the terminal locked which improves performance - Clear screen properly before rendering of content to prevent various graphical glitches - Fix build failure on 32-bit systems - Windows started as unfocused now show the hollow cursor if the setting is enabled - Empty lines in selections are now properly copied to the clipboard - Selection start point lagging behind initial cursor position - Rendering of selections which start above the visible area and end below it - Bracketed paste mode now filters escape sequences beginning with \x1b ### Removed - The terminfo entry `alacritty-256color`. It is replaced by the `alacritty` entry (which also advertises 256 colors) ## Version 0.2.0 ### Added - Add a scrollback history buffer (10_000 lines by default) - CHANGELOG has been added for documenting relevant user-facing changes - Add `ClearHistory` key binding action and the `Erase Saved Lines` control sequence - When growing the window height, Alacritty will now try to load additional lines out of the scrollback history - Support the dim foreground color (`echo -e '\033[2mDimmed Text'`) - Add support for the LCD-V pixel mode (vertical screens) - Pressing enter on the numpad should now insert a newline - The mouse bindings now support keyboard modifiers (shift/ctrl/alt/super) - Add support for the bright foreground color - Support for setting foreground, background colors in one escape sequence ### Changed - Multiple key/mouse bindings for a single key will now all be executed instead of picking one and ignoring the rest - Improve text scrolling performance (affects applications like `yes`, not scrolling the history) ### Fixed - Clear the visible region when the RIS escape sequence (`echo -ne '\033c'`) is received - Prevent logger from crashing Alacritty when stdout/stderr is not available - Fix a crash when sending the IL escape sequence with a large number of lines alacritty-0.13.2/Cargo.lock0000644000001702700000000000100110750ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", "once_cell", "version_check", "zerocopy", ] [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "alacritty" version = "0.13.2" dependencies = [ "ahash", "alacritty_config", "alacritty_config_derive", "alacritty_terminal", "bitflags 2.4.2", "clap", "clap_complete", "cocoa", "copypasta", "crossfont", "dirs", "embed-resource", "gl_generator", "glutin", "home", "libc", "log", "notify", "objc", "parking_lot", "png", "raw-window-handle", "serde", "serde_json", "serde_yaml", "toml", "unicode-width", "windows-sys 0.48.0", "winit", "xdg", ] [[package]] name = "alacritty_config" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e2e65ebcbd29555f9b7e54fa249cf09ce6e1e1c1f3c593f9b4b36869518b6b4" dependencies = [ "log", "serde", "toml", ] [[package]] name = "alacritty_config_derive" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53793d452a9851f62066585d716c5a579162a7167397586954797792c8e6645c" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "alacritty_terminal" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6d1ea4484c8676f295307a4892d478c70ac8da1dbd8c7c10830a504b7f1022f" dependencies = [ "base64", "bitflags 2.4.2", "home", "libc", "log", "miow", "parking_lot", "piper", "polling", "regex-automata", "rustix-openpty", "serde", "signal-hook", "unicode-width", "vte", "windows-sys 0.48.0", ] [[package]] name = "android-activity" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" dependencies = [ "android-properties", "bitflags 2.4.2", "cc", "cesu8", "jni", "jni-sys", "libc", "log", "ndk", "ndk-context", "ndk-sys", "num_enum", "thiserror", ] [[package]] name = "android-properties" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" [[package]] name = "anstream" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ "windows-sys 0.48.0", ] [[package]] name = "anstyle-wincon" version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" dependencies = [ "anstyle", "windows-sys 0.48.0", ] [[package]] name = "arrayref" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "as-raw-xcb-connection" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" [[package]] name = "atomic-waker" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" dependencies = [ "serde", ] [[package]] name = "block" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "block-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" dependencies = [ "objc-sys", ] [[package]] name = "block2" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" dependencies = [ "block-sys", "objc2", ] [[package]] name = "bumpalo" version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "bytemuck" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" [[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "calloop" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" dependencies = [ "bitflags 2.4.2", "log", "polling", "rustix", "slab", "thiserror", ] [[package]] name = "calloop-wayland-source" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0ea9b9476c7fad82841a8dbb380e2eae480c21910feba80725b46931ed8f02" dependencies = [ "calloop", "rustix", "wayland-backend", "wayland-client", ] [[package]] name = "cc" version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ "jobserver", "libc", ] [[package]] name = "cesu8" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "cgl" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" dependencies = [ "libc", ] [[package]] name = "clap" version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfaff671f6b22ca62406885ece523383b9b64022e341e53e009a62ebc47a45f2" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a216b506622bb1d316cd51328dce24e07bdff4a6128a47c7e7fad11878d5adbb" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", ] [[package]] name = "clap_complete" version = "4.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae" dependencies = [ "clap", ] [[package]] name = "clap_derive" version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", "syn", ] [[package]] name = "clap_lex" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "clipboard-win" version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fdf5e01086b6be750428ba4a40619f847eb2e95756eee84b18e06e5f0b50342" dependencies = [ "lazy-bytes-cast", "winapi", ] [[package]] name = "cmake" version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" dependencies = [ "cc", ] [[package]] name = "cocoa" version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" dependencies = [ "bitflags 1.3.2", "block", "cocoa-foundation", "core-foundation", "core-graphics", "foreign-types", "libc", "objc", ] [[package]] name = "cocoa-foundation" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" dependencies = [ "bitflags 1.3.2", "block", "core-foundation", "core-graphics-types", "libc", "objc", ] [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "combine" version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", "memchr", ] [[package]] name = "concurrent-queue" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" dependencies = [ "crossbeam-utils", ] [[package]] name = "copypasta" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb85422867ca93da58b7f95fb5c0c10f6183ed6e1ef8841568968a896d3a858" dependencies = [ "clipboard-win", "objc", "objc-foundation", "objc_id", "smithay-clipboard", "x11-clipboard", ] [[package]] name = "core-foundation" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "core-graphics" version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "970a29baf4110c26fedbc7f82107d42c23f7e88e404c4577ed73fe99ff85a212" dependencies = [ "bitflags 1.3.2", "core-foundation", "core-graphics-types", "foreign-types", "libc", ] [[package]] name = "core-graphics-types" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", "core-foundation", "libc", ] [[package]] name = "core-text" version = "20.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" dependencies = [ "core-foundation", "core-graphics", "foreign-types", "libc", ] [[package]] name = "crc32fast" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crossfont" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89c65306ecd118368d875f48d69394b5c3ff6bb7c57ae6deb638782735a093c" dependencies = [ "cocoa", "core-foundation", "core-foundation-sys", "core-graphics", "core-text", "dwrote", "foreign-types", "freetype-rs", "libc", "log", "objc", "once_cell", "pkg-config", "servo-fontconfig", "winapi", ] [[package]] name = "cursor-icon" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" dependencies = [ "serde", ] [[package]] name = "dirs" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", "redox_users", "windows-sys 0.48.0", ] [[package]] name = "dispatch" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] name = "dlib" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ "libloading", ] [[package]] name = "downcast-rs" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "dwrote" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b" dependencies = [ "lazy_static", "libc", "serde", "serde_derive", "winapi", "wio", ] [[package]] name = "embed-resource" version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6985554d0688b687c5cb73898a34fbe3ad6c24c58c238a4d91d5e840670ee9d" dependencies = [ "cc", "memchr", "rustc_version", "toml", "vswhom", "winreg", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8" dependencies = [ "libc", "windows-sys 0.48.0", ] [[package]] name = "expat-sys" version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa" dependencies = [ "cmake", "pkg-config", ] [[package]] name = "fastrand" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fdeflate" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" dependencies = [ "simd-adler32", ] [[package]] name = "filetime" version = "0.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0" dependencies = [ "cfg-if", "libc", "redox_syscall 0.3.5", "windows-sys 0.48.0", ] [[package]] name = "flate2" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" dependencies = [ "crc32fast", "miniz_oxide", ] [[package]] name = "foreign-types" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", "foreign-types-shared", ] [[package]] name = "foreign-types-macros" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "foreign-types-shared" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "freetype-rs" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb" dependencies = [ "bitflags 1.3.2", "freetype-sys", "libc", ] [[package]] name = "freetype-sys" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" dependencies = [ "cmake", "libc", "pkg-config", ] [[package]] name = "fsevent-sys" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" dependencies = [ "libc", ] [[package]] name = "futures-io" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "gethostname" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" dependencies = [ "libc", "windows-targets 0.48.5", ] [[package]] name = "getrandom" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "gl_generator" version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" dependencies = [ "khronos_api", "log", "xml-rs", ] [[package]] name = "glutin" version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18fcd4ae4e86d991ad1300b8f57166e5be0c95ef1f63f3f5b827f8a164548746" dependencies = [ "bitflags 2.4.2", "cfg_aliases", "cgl", "core-foundation", "dispatch", "glutin_egl_sys", "glutin_glx_sys", "glutin_wgl_sys", "icrate", "libloading", "objc2", "once_cell", "raw-window-handle", "wayland-sys", "windows-sys 0.48.0", "x11-dl", ] [[package]] name = "glutin_egl_sys" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77cc5623f5309ef433c3dd4ca1223195347fe62c413da8e2fdd0eb76db2d9bcd" dependencies = [ "gl_generator", "windows-sys 0.48.0", ] [[package]] name = "glutin_glx_sys" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a165fd686c10dcc2d45380b35796e577eacfd43d4660ee741ec8ebe2201b3b4f" dependencies = [ "gl_generator", "x11-dl", ] [[package]] name = "glutin_wgl_sys" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" dependencies = [ "gl_generator", ] [[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "home" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" dependencies = [ "windows-sys 0.48.0", ] [[package]] name = "icrate" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" dependencies = [ "block2", "dispatch", "objc2", ] [[package]] name = "indexmap" version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown", ] [[package]] name = "inotify" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" dependencies = [ "bitflags 1.3.2", "inotify-sys", "libc", ] [[package]] name = "inotify-sys" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" dependencies = [ "libc", ] [[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "jni" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ "cesu8", "cfg-if", "combine", "jni-sys", "log", "thiserror", "walkdir", "windows-sys 0.45.0", ] [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] [[package]] name = "js-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "khronos_api" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" [[package]] name = "kqueue" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" dependencies = [ "kqueue-sys", "libc", ] [[package]] name = "kqueue-sys" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" dependencies = [ "bitflags 1.3.2", "libc", ] [[package]] name = "lazy-bytes-cast" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10257499f089cd156ad82d0a9cd57d9501fa2c989068992a97eb3c27836f206b" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", "windows-targets 0.48.5", ] [[package]] name = "libredox" version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ "bitflags 2.4.2", "libc", "redox_syscall 0.4.1", ] [[package]] name = "libredox" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ "bitflags 2.4.2", "libc", "redox_syscall 0.4.1", ] [[package]] name = "linux-raw-sys" version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" dependencies = [ "serde", ] [[package]] name = "malloc_buf" version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" dependencies = [ "libc", ] [[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memmap2" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] [[package]] name = "miniz_oxide" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", "simd-adler32", ] [[package]] name = "mio" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "log", "wasi", "windows-sys 0.48.0", ] [[package]] name = "miow" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "359f76430b20a79f9e20e115b3428614e654f04fab314482fc0fda0ebd3c6044" dependencies = [ "windows-sys 0.48.0", ] [[package]] name = "ndk" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" dependencies = [ "bitflags 2.4.2", "jni-sys", "log", "ndk-sys", "num_enum", "raw-window-handle", "thiserror", ] [[package]] name = "ndk-context" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-sys" version = "0.5.0+25.2.9519653" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" dependencies = [ "jni-sys", ] [[package]] name = "notify" version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ "bitflags 2.4.2", "crossbeam-channel", "filetime", "fsevent-sys", "inotify", "kqueue", "libc", "log", "mio", "walkdir", "windows-sys 0.48.0", ] [[package]] name = "num_enum" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "syn", ] [[package]] name = "objc" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" dependencies = [ "malloc_buf", ] [[package]] name = "objc-foundation" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" dependencies = [ "block", "objc", "objc_id", ] [[package]] name = "objc-sys" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7c71324e4180d0899963fc83d9d241ac39e699609fc1025a850aadac8257459" [[package]] name = "objc2" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" dependencies = [ "objc-sys", "objc2-encode", ] [[package]] name = "objc2-encode" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" [[package]] name = "objc_id" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" dependencies = [ "objc", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "orbclient" version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" dependencies = [ "libredox 0.0.2", ] [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall 0.4.1", "smallvec", "windows-targets 0.48.5", ] [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "piper" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" dependencies = [ "atomic-waker", "fastrand", "futures-io", ] [[package]] name = "pkg-config" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "png" version = "0.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" dependencies = [ "bitflags 1.3.2", "crc32fast", "fdeflate", "flate2", "miniz_oxide", ] [[package]] name = "polling" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e53b6af1f60f36f8c2ac2aad5459d75a5a9b4be1e8cdd40264f315d78193e531" dependencies = [ "cfg-if", "concurrent-queue", "pin-project-lite", "rustix", "tracing", "windows-sys 0.48.0", ] [[package]] name = "proc-macro-crate" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ "toml_edit 0.21.1", ] [[package]] name = "proc-macro2" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "quick-xml" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" dependencies = [ "memchr", ] [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "raw-window-handle" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "redox_syscall" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_users" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" dependencies = [ "getrandom", "libredox 0.0.1", "thiserror", ] [[package]] name = "regex-automata" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustc_version" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] [[package]] name = "rustix" version = "0.38.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e" dependencies = [ "bitflags 2.4.2", "errno", "itoa", "libc", "linux-raw-sys", "windows-sys 0.48.0", ] [[package]] name = "rustix-openpty" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a25c3aad9fc1424eb82c88087789a7d938e1829724f3e4043163baf0d13cfc12" dependencies = [ "errno", "libc", "rustix", ] [[package]] name = "ryu" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "scoped-tls" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" dependencies = [ "crossfont", "log", "smithay-client-toolkit", "tiny-skia", ] [[package]] name = "semver" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_spanned" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] [[package]] name = "serde_yaml" version = "0.9.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" dependencies = [ "indexmap", "itoa", "ryu", "serde", "unsafe-libyaml", ] [[package]] name = "servo-fontconfig" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c" dependencies = [ "libc", "servo-fontconfig-sys", ] [[package]] name = "servo-fontconfig-sys" version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388" dependencies = [ "expat-sys", "freetype-sys", "pkg-config", ] [[package]] name = "signal-hook" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" dependencies = [ "libc", "signal-hook-registry", ] [[package]] name = "signal-hook-registry" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] name = "simd-adler32" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "smithay-client-toolkit" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "922fd3eeab3bd820d76537ce8f582b1cf951eceb5475c28500c7457d9d17f53a" dependencies = [ "bitflags 2.4.2", "calloop", "calloop-wayland-source", "cursor-icon", "libc", "log", "memmap2", "rustix", "thiserror", "wayland-backend", "wayland-client", "wayland-csd-frame", "wayland-cursor", "wayland-protocols", "wayland-protocols-wlr", "wayland-scanner", "xkeysym", ] [[package]] name = "smithay-clipboard" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c091e7354ea8059d6ad99eace06dd13ddeedbb0ac72d40a9a6e7ff790525882d" dependencies = [ "libc", "smithay-client-toolkit", "wayland-backend", ] [[package]] name = "smol_str" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" dependencies = [ "serde", ] [[package]] name = "strict-num" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "thiserror" version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "tiny-skia" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" dependencies = [ "arrayref", "arrayvec", "bytemuck", "cfg-if", "log", "tiny-skia-path", ] [[package]] name = "tiny-skia-path" version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" dependencies = [ "arrayref", "bytemuck", "strict-num", ] [[package]] name = "toml" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af06656561d28735e9c1cd63dfd57132c8155426aa6af24f36a00a351f88c48e" dependencies = [ "serde", "serde_spanned", "toml_datetime", "toml_edit 0.22.7", ] [[package]] name = "toml_datetime" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] [[package]] name = "toml_edit" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ "indexmap", "toml_datetime", "winnow 0.5.40", ] [[package]] name = "toml_edit" version = "0.22.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18769cd1cec395d70860ceb4d932812a0b4d06b1a4bb336745a4d21b9496e992" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", "winnow 0.6.5", ] [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "unsafe-libyaml" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "utf8parse" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vswhom" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" dependencies = [ "libc", "vswhom-sys", ] [[package]] name = "vswhom-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" dependencies = [ "cc", "libc", ] [[package]] name = "vte" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40eb22ae96f050e0c0d6f7ce43feeae26c348fc4dea56928ca81537cfaa6188b" dependencies = [ "bitflags 2.4.2", "cursor-icon", "log", "serde", "utf8parse", "vte_generate_state_changes", ] [[package]] name = "vte_generate_state_changes" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" dependencies = [ "proc-macro2", "quote", ] [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "wayland-backend" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" dependencies = [ "cc", "downcast-rs", "rustix", "scoped-tls", "smallvec", "wayland-sys", ] [[package]] name = "wayland-client" version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" dependencies = [ "bitflags 2.4.2", "rustix", "wayland-backend", "wayland-scanner", ] [[package]] name = "wayland-csd-frame" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ "bitflags 2.4.2", "cursor-icon", "wayland-backend", ] [[package]] name = "wayland-cursor" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71ce5fa868dd13d11a0d04c5e2e65726d0897be8de247c0c5a65886e283231ba" dependencies = [ "rustix", "wayland-client", "xcursor", ] [[package]] name = "wayland-protocols" version = "0.31.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" dependencies = [ "bitflags 2.4.2", "wayland-backend", "wayland-client", "wayland-scanner", ] [[package]] name = "wayland-protocols-plasma" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479" dependencies = [ "bitflags 2.4.2", "wayland-backend", "wayland-client", "wayland-protocols", "wayland-scanner", ] [[package]] name = "wayland-protocols-wlr" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" dependencies = [ "bitflags 2.4.2", "wayland-backend", "wayland-client", "wayland-protocols", "wayland-scanner", ] [[package]] name = "wayland-scanner" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" dependencies = [ "proc-macro2", "quick-xml", "quote", ] [[package]] name = "wayland-sys" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" dependencies = [ "dlib", "log", "once_cell", "pkg-config", ] [[package]] name = "web-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "web-time" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ "windows-targets 0.42.2", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-targets" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ "windows_aarch64_gnullvm 0.42.2", "windows_aarch64_msvc 0.42.2", "windows_i686_gnu 0.42.2", "windows_i686_msvc 0.42.2", "windows_x86_64_gnu 0.42.2", "windows_x86_64_gnullvm 0.42.2", "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winit" version = "0.29.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" dependencies = [ "ahash", "android-activity", "atomic-waker", "bitflags 2.4.2", "bytemuck", "calloop", "cfg_aliases", "core-foundation", "core-graphics", "cursor-icon", "icrate", "js-sys", "libc", "log", "memmap2", "ndk", "ndk-sys", "objc2", "once_cell", "orbclient", "percent-encoding", "raw-window-handle", "redox_syscall 0.3.5", "rustix", "sctk-adwaita", "serde", "smithay-client-toolkit", "smol_str", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", "wayland-backend", "wayland-client", "wayland-protocols", "wayland-protocols-plasma", "web-sys", "web-time", "windows-sys 0.48.0", "x11-dl", "x11rb", "xkbcommon-dl", ] [[package]] name = "winnow" version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] [[package]] name = "winnow" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" dependencies = [ "memchr", ] [[package]] name = "winreg" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" dependencies = [ "cfg-if", "windows-sys 0.48.0", ] [[package]] name = "wio" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" dependencies = [ "winapi", ] [[package]] name = "x11-clipboard" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98785a09322d7446e28a13203d2cae1059a0dd3dfb32cb06d0a225f023d8286" dependencies = [ "libc", "x11rb", ] [[package]] name = "x11-dl" version = "2.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" dependencies = [ "libc", "once_cell", "pkg-config", ] [[package]] name = "x11rb" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" dependencies = [ "as-raw-xcb-connection", "gethostname", "libc", "libloading", "once_cell", "rustix", "x11rb-protocol", ] [[package]] name = "x11rb-protocol" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" [[package]] name = "xcursor" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a0ccd7b4a5345edfcd0c3535718a4e9ff7798ffc536bb5b5a0e26ff84732911" [[package]] name = "xdg" version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213b7324336b53d2414b2db8537e56544d981803139155afa84f76eeebb7a546" [[package]] name = "xkbcommon-dl" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ "bitflags 2.4.2", "dlib", "log", "once_cell", "xkeysym", ] [[package]] name = "xkeysym" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "054a8e68b76250b253f671d1268cb7f1ae089ec35e195b2efb2a4e9a836d0621" [[package]] name = "xml-rs" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" [[package]] name = "zerocopy" version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", "syn", ] alacritty-0.13.2/Cargo.toml0000644000000061060000000000100111140ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.70.0" name = "alacritty" version = "0.13.2" authors = [ "Christian Duerr ", "Joe Wilm ", ] description = "A fast, cross-platform, OpenGL terminal emulator" homepage = "https://github.com/alacritty/alacritty" readme = "README.md" license = "Apache-2.0" [dependencies.ahash] version = "0.8.6" features = ["no-rng"] [dependencies.alacritty_config] version = "0.2.1" [dependencies.alacritty_config_derive] version = "0.2.3" [dependencies.alacritty_terminal] version = "0.23.0" [dependencies.bitflags] version = "2.2.1" [dependencies.clap] version = "4.2.7" features = [ "derive", "env", ] [dependencies.copypasta] version = "0.10.1" default-features = false [dependencies.crossfont] version = "0.7.0" features = ["force_system_fontconfig"] [dependencies.glutin] version = "0.31.1" features = [ "egl", "wgl", ] default-features = false [dependencies.home] version = "0.5.5" [dependencies.libc] version = "0.2" [dependencies.log] version = "0.4" features = [ "std", "serde", ] [dependencies.notify] version = "6.1.1" [dependencies.parking_lot] version = "0.12.0" [dependencies.raw-window-handle] version = "0.5" [dependencies.serde] version = "1" features = ["derive"] [dependencies.serde_json] version = "1" [dependencies.serde_yaml] version = "0.9.25" [dependencies.toml] version = "0.8.2" [dependencies.unicode-width] version = "0.1" [dependencies.winit] version = "0.29.15" features = [ "rwh_05", "serde", ] default-features = false [dev-dependencies.clap_complete] version = "4.2.3" [build-dependencies.gl_generator] version = "0.14.0" [features] default = [ "wayland", "x11", ] nightly = [] wayland = [ "copypasta/wayland", "glutin/wayland", "winit/wayland", "winit/wayland-dlopen", "winit/wayland-csd-adwaita-crossfont", ] x11 = [ "copypasta/x11", "winit/x11", "glutin/x11", "glutin/glx", "png", ] [target."cfg(not(target_os = \"macos\"))".dependencies.png] version = "0.17.5" optional = true default-features = false [target."cfg(not(windows))".dependencies.xdg] version = "2.5.0" [target."cfg(target_os = \"macos\")".dependencies.cocoa] version = "0.25.0" [target."cfg(target_os = \"macos\")".dependencies.objc] version = "0.2.2" [target."cfg(windows)".dependencies.dirs] version = "5.0.1" [target."cfg(windows)".dependencies.windows-sys] version = "0.48" features = [ "Win32_UI_WindowsAndMessaging", "Win32_System_Threading", "Win32_System_Console", "Win32_Foundation", ] [target."cfg(windows)".build-dependencies.embed-resource] version = "2.2.0" alacritty-0.13.2/Cargo.toml.orig000064400000000000000000000043431046102023000145760ustar 00000000000000[package] name = "alacritty" version = "0.13.2" authors = ["Christian Duerr ", "Joe Wilm "] license = "Apache-2.0" description = "A fast, cross-platform, OpenGL terminal emulator" readme = "README.md" homepage = "https://github.com/alacritty/alacritty" edition = "2021" rust-version = "1.70.0" [dependencies.alacritty_terminal] path = "../alacritty_terminal" version = "0.23.0" [dependencies.alacritty_config_derive] path = "../alacritty_config_derive" version = "0.2.3" [dependencies.alacritty_config] path = "../alacritty_config" version = "0.2.1" [dependencies] ahash = { version = "0.8.6", features = ["no-rng"] } bitflags = "2.2.1" clap = { version = "4.2.7", features = ["derive", "env"] } copypasta = { version = "0.10.1", default-features = false } crossfont = { version = "0.7.0", features = ["force_system_fontconfig"] } glutin = { version = "0.31.1", default-features = false, features = ["egl", "wgl"] } home = "0.5.5" libc = "0.2" log = { version = "0.4", features = ["std", "serde"] } notify = "6.1.1" parking_lot = "0.12.0" raw-window-handle = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" serde_yaml = "0.9.25" toml = "0.8.2" unicode-width = "0.1" winit = { version = "0.29.15", default-features = false, features = ["rwh_05", "serde"] } [build-dependencies] gl_generator = "0.14.0" [dev-dependencies] clap_complete = "4.2.3" [target.'cfg(not(windows))'.dependencies] xdg = "2.5.0" [target.'cfg(not(target_os = "macos"))'.dependencies] png = { version = "0.17.5", default-features = false, optional = true } [target.'cfg(target_os = "macos")'.dependencies] cocoa = "0.25.0" objc = "0.2.2" [target.'cfg(windows)'.dependencies] dirs = "5.0.1" windows-sys = { version = "0.48", features = [ "Win32_UI_WindowsAndMessaging", "Win32_System_Threading", "Win32_System_Console", "Win32_Foundation", ]} [target.'cfg(windows)'.build-dependencies] embed-resource = "2.2.0" [features] default = ["wayland", "x11"] x11 = [ "copypasta/x11", "winit/x11", "glutin/x11", "glutin/glx", "png", ] wayland = [ "copypasta/wayland", "glutin/wayland", "winit/wayland", "winit/wayland-dlopen", "winit/wayland-csd-adwaita-crossfont", ] nightly = [] alacritty-0.13.2/LICENSE-APACHE000064400000000000000000000251331046102023000136330ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2020 The Alacritty Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. alacritty-0.13.2/README.md000064400000000000000000000102671046102023000131700ustar 00000000000000

Alacritty Logo

Alacritty - A fast, cross-platform, OpenGL terminal emulator

Alacritty - A fast, cross-platform, OpenGL terminal emulator

## About Alacritty is a modern terminal emulator that comes with sensible defaults, but allows for extensive [configuration](#configuration). By integrating with other applications, rather than reimplementing their functionality, it manages to provide a flexible set of [features](./docs/features.md) with high performance. The supported platforms currently consist of BSD, Linux, macOS and Windows. The software is considered to be at a **beta** level of readiness; there are a few missing features and bugs to be fixed, but it is already used by many as a daily driver. Precompiled binaries are available from the [GitHub releases page](https://github.com/alacritty/alacritty/releases). Join [`#alacritty`] on libera.chat if you have questions or looking for a quick help. [`#alacritty`]: https://web.libera.chat/gamja/?channels=#alacritty ## Features You can find an overview over the features available in Alacritty [here](./docs/features.md). ## Further information - [Announcing Alacritty, a GPU-Accelerated Terminal Emulator](https://jwilm.io/blog/announcing-alacritty/) January 6, 2017 - [A talk about Alacritty at the Rust Meetup January 2017](https://www.youtube.com/watch?v=qHOdYO3WUTk) January 19, 2017 - [Alacritty Lands Scrollback, Publishes Benchmarks](https://jwilm.io/blog/alacritty-lands-scrollback/) September 17, 2018 ## Installation Alacritty can be installed by using various package managers on Linux, BSD, macOS and Windows. Prebuilt binaries for macOS and Windows can also be downloaded from the [GitHub releases page](https://github.com/alacritty/alacritty/releases). For everyone else, the detailed instructions to install Alacritty can be found [here](INSTALL.md). ### Requirements - At least OpenGL ES 2.0 - [Windows] ConPTY support (Windows 10 version 1809 or higher) ## Configuration You can find the documentation for Alacritty's configuration in `man 5 alacritty`, or by looking at [the website] if you do not have the manpages installed. [the website]: https://alacritty.org/config-alacritty.html Alacritty doesn't create the config file for you, but it looks for one in the following locations: 1. `$XDG_CONFIG_HOME/alacritty/alacritty.toml` 2. `$XDG_CONFIG_HOME/alacritty.toml` 3. `$HOME/.config/alacritty/alacritty.toml` 4. `$HOME/.alacritty.toml` ### Windows On Windows, the config file should be located at: `%APPDATA%\alacritty\alacritty.toml` ## Contributing A guideline about contributing to Alacritty can be found in the [`CONTRIBUTING.md`](CONTRIBUTING.md) file. ## FAQ **_Is it really the fastest terminal emulator?_** Benchmarking terminal emulators is complicated. Alacritty uses [vtebench](https://github.com/alacritty/vtebench) to quantify terminal emulator throughput and manages to consistently score better than the competition using it. If you have found an example where this is not the case, please report a bug. Other aspects like latency or framerate and frame consistency are more difficult to quantify. Some terminal emulators also intentionally slow down to save resources, which might be preferred by some users. If you have doubts about Alacritty's performance or usability, the best way to quantify terminal emulators is always to test them with **your** specific usecases. **_Why isn't feature X implemented?_** Alacritty has many great features, but not every feature from every other terminal. This could be for a number of reasons, but sometimes it's just not a good fit for Alacritty. This means you won't find things like tabs or splits (which are best left to a window manager or [terminal multiplexer][tmux]) nor niceties like a GUI config editor. [tmux]: https://github.com/tmux/tmux ## License Alacritty is released under the [Apache License, Version 2.0]. [Apache License, Version 2.0]: https://github.com/alacritty/alacritty/blob/master/LICENSE-APACHE alacritty-0.13.2/build.rs000064400000000000000000000021401046102023000133450ustar 00000000000000use std::env; use std::fs::File; use std::path::Path; use std::process::Command; use gl_generator::{Api, Fallbacks, GlobalGenerator, Profile, Registry}; fn main() { let mut version = String::from(env!("CARGO_PKG_VERSION")); if let Some(commit_hash) = commit_hash() { version = format!("{version} ({commit_hash})"); } println!("cargo:rustc-env=VERSION={version}"); let dest = env::var("OUT_DIR").unwrap(); let mut file = File::create(Path::new(&dest).join("gl_bindings.rs")).unwrap(); Registry::new(Api::Gl, (3, 3), Profile::Core, Fallbacks::All, [ "GL_ARB_blend_func_extended", "GL_KHR_debug", ]) .write_bindings(GlobalGenerator, &mut file) .unwrap(); #[cfg(windows)] embed_resource::compile("./windows/alacritty.rc", embed_resource::NONE); } fn commit_hash() -> Option { Command::new("git") .args(["rev-parse", "--short", "HEAD"]) .output() .ok() .filter(|output| output.status.success()) .and_then(|output| String::from_utf8(output.stdout).ok()) .map(|hash| hash.trim().into()) } alacritty-0.13.2/extra/alacritty.info000064400000000000000000000116461046102023000157070ustar 00000000000000alacritty|alacritty terminal emulator, use=alacritty+common, rs1=\Ec\E]104\007, ccc, colors#0x100, pairs#0x7FFF, initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%* %{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\, oc=\E]104\007, setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48; 5;%p1%d%;m, setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5 ;%p1%d%;m, setb@, setf@, alacritty-direct|alacritty with direct color indexing, use=alacritty+common, RGB, colors#0x1000000, pairs#0x7FFF, initc@, op=\E[39;49m, setab=\E[%?%p1%{8}%<%t4%p1%d%e48\:2\:\:%p1%{65536}%/%d\:%p1%{256} %/%{255}%&%d\:%p1%{255}%&%d%;m, setaf=\E[%?%p1%{8}%<%t3%p1%d%e38\:2\:\:%p1%{65536}%/%d\:%p1%{256} %/%{255}%&%d\:%p1%{255}%&%d%;m, setb@, setf@, alacritty+common|base fragment for alacritty, OTbs, am, bce, km, mir, msgr, xenl, AX, XT, colors#8, cols#80, it#8, lines#24, pairs#64, acsc=``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, bel=^G, bold=\E[1m, cbt=\E[Z, civis=\E[?25l, clear=\E[H\E[2J, cnorm=\E[?12l\E[?25h, cr=\r, csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H, cud=\E[%p1%dB, cud1=\n, cuf=\E[%p1%dC, cuf1=\E[C, cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A, cvvis=\E[?12;25h, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m, dl=\E[%p1%dM, dl1=\E[M, ech=\E[%p1%dX, ed=\E[J, el=\E[K, el1=\E[1K, flash=\E[?5h$<100/>\E[?5l, home=\E[H, hpa=\E[%i%p1%dG, ht=^I, hts=\EH, ich=\E[%p1%d@, il=\E[%p1%dL, il1=\E[L, ind=\n, invis=\E[8m, is2=\E[!p\E[?3;4l\E[4l\E>, kmous=\E[M, meml=\El, memu=\Em, op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM, rmacs=\E(B, rmam=\E[?7l, rmir=\E[4l, rmkx=\E[?1l\E>, rmm=\E[?1034l, rmso=\E[27m, rmul=\E[24m, rs1=\Ec, rs2=\E[!p\E[?3;4l\E[4l\E>, sc=\E7, setab=\E[4%p1%dm, setaf=\E[3%p1%dm, setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6} %=%t3%e%p1%d%;m, setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6} %=%t3%e%p1%d%;m, sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%; %?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m, sgr0=\E(B\E[m, smacs=\E(0, smam=\E[?7h, smir=\E[4h, smkx=\E[?1h\E=, smm=\E[?1034h, smso=\E[7m, smul=\E[4m, tbc=\E[3g, vpa=\E[%i%p1%dd, E3=\E[3J, kbs=^?, ritm=\E[23m, sitm=\E[3m, mc5i, mc0=\E[i, mc4=\E[4i, mc5=\E[5i, u6=\E[%i%d;%dR, u7=\E[6n, u8=\E[?%[;0123456789]c, u9=\E[c, rmcup=\E[?1049l\E[23;0;0t, smcup=\E[?1049h\E[22;0;0t, npc, indn=\E[%p1%dS, kb2=\EOE, kcbt=\E[Z, kent=\EOM, rin=\E[%p1%dT, rep=%p1%c\E[%p2%{1}%-%db, rmxx=\E[29m, smxx=\E[9m, kcub1=\EOD, kcud1=\EOB, kcuf1=\EOC, kcuu1=\EOA, kend=\EOF, khome=\EOH, kf1=\EOP, kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf13=\E[1;2P, kf14=\E[1;2Q, kf15=\E[1;2R, kf16=\E[1;2S, kf17=\E[15;2~, kf18=\E[17;2~, kf19=\E[18;2~, kf2=\EOQ, kf20=\E[19;2~, kf21=\E[20;2~, kf22=\E[21;2~, kf23=\E[23;2~, kf24=\E[24;2~, kf25=\E[1;5P, kf26=\E[1;5Q, kf27=\E[1;5R, kf28=\E[1;5S, kf29=\E[15;5~, kf3=\EOR, kf30=\E[17;5~, kf31=\E[18;5~, kf32=\E[19;5~, kf33=\E[20;5~, kf34=\E[21;5~, kf35=\E[23;5~, kf36=\E[24;5~, kf37=\E[1;6P, kf38=\E[1;6Q, kf39=\E[1;6R, kf4=\EOS, kf40=\E[1;6S, kf41=\E[15;6~, kf42=\E[17;6~, kf43=\E[18;6~, kf44=\E[19;6~, kf45=\E[20;6~, kf46=\E[21;6~, kf47=\E[23;6~, kf48=\E[24;6~, kf49=\E[1;3P, kf5=\E[15~, kf50=\E[1;3Q, kf51=\E[1;3R, kf52=\E[1;3S, kf53=\E[15;3~, kf54=\E[17;3~, kf55=\E[18;3~, kf56=\E[19;3~, kf57=\E[20;3~, kf58=\E[21;3~, kf59=\E[23;3~, kf6=\E[17~, kf60=\E[24;3~, kf61=\E[1;4P, kf62=\E[1;4Q, kf63=\E[1;4R, kf7=\E[18~, kf8=\E[19~, kf9=\E[20~, kLFT=\E[1;2D, kRIT=\E[1;2C, kind=\E[1;2B, kri=\E[1;2A, kDN=\E[1;2B, kDN3=\E[1;3B, kDN4=\E[1;4B, kDN5=\E[1;5B, kDN6=\E[1;6B, kDN7=\E[1;7B, kLFT3=\E[1;3D, kLFT4=\E[1;4D, kLFT5=\E[1;5D, kLFT6=\E[1;6D, kLFT7=\E[1;7D, kRIT3=\E[1;3C, kRIT4=\E[1;4C, kRIT5=\E[1;5C, kRIT6=\E[1;6C, kRIT7=\E[1;7C, kUP=\E[1;2A, kUP3=\E[1;3A, kUP4=\E[1;4A, kUP5=\E[1;5A, kUP6=\E[1;6A, kUP7=\E[1;7A, kDC=\E[3;2~, kEND=\E[1;2F, kHOM=\E[1;2H, kIC=\E[2;2~, kNXT=\E[6;2~, kPRV=\E[5;2~, kich1=\E[2~, knp=\E[6~, kpp=\E[5~, kDC3=\E[3;3~, kDC4=\E[3;4~, kDC5=\E[3;5~, kDC6=\E[3;6~, kDC7=\E[3;7~, kEND3=\E[1;3F, kEND4=\E[1;4F, kEND5=\E[1;5F, kEND6=\E[1;6F, kEND7=\E[1;7F, kHOM3=\E[1;3H, kHOM4=\E[1;4H, kHOM5=\E[1;5H, kHOM6=\E[1;6H, kHOM7=\E[1;7H, kIC3=\E[2;3~, kIC4=\E[2;4~, kIC5=\E[2;5~, kIC6=\E[2;6~, kIC7=\E[2;7~, kNXT3=\E[6;3~, kNXT4=\E[6;4~, kNXT5=\E[6;5~, kNXT6=\E[6;6~, kNXT7=\E[6;7~, kPRV3=\E[5;3~, kPRV4=\E[5;4~, kPRV5=\E[5;5~, kPRV6=\E[5;6~, kPRV7=\E[5;7~, kdch1=\E[3~, Cr=\E]112\007, Cs=\E]12;%p1%s\007, Ms=\E]52;%p1%s;%p2%s\007, Se=\E[0 q, Ss=\E[%p1%d q, hs, dsl=\E]2;\007, fsl=^G, tsl=\E]2;, Smulx=\E[4\:%p1%dm, Sync=\E[?2026%?%p1%{1}%-%tl%eh%;, XF, kxIN=\E[I, kxOUT=\E[O, BD=\E[?2004l, BE=\E[?2004h, PE=\E[201~, PS=\E[200~, alacritty-0.13.2/extra/completions/_alacritty000064400000000000000000000231071046102023000174430ustar 00000000000000#compdef alacritty autoload -U is-at-least _alacritty() { typeset -A opt_args typeset -a _arguments_options local ret=1 if is-at-least 5.2; then _arguments_options=(-s -S -C) else _arguments_options=(-s -C) fi local context curcontext="$curcontext" state line _arguments "${_arguments_options[@]}" \ '--embed=[X11 window ID to embed Alacritty within (decimal or hexadecimal with "0x" prefix)]:EMBED: ' \ '--config-file=[Specify alternative configuration file \[default\: \$XDG_CONFIG_HOME/alacritty/alacritty.toml\]]:CONFIG_FILE:_files' \ '--socket=[Path for IPC socket creation]:SOCKET:_files' \ '--working-directory=[Start the shell in the specified working directory]:WORKING_DIRECTORY:_files' \ '*-e+[Command and args to execute (must be last argument)]:COMMAND: ' \ '*--command=[Command and args to execute (must be last argument)]:COMMAND: ' \ '-T+[Defines the window title \[default\: Alacritty\]]:TITLE: ' \ '--title=[Defines the window title \[default\: Alacritty\]]:TITLE: ' \ '--class=[Defines window class/app_id on X11/Wayland \[default\: Alacritty\]]:general> | ,alacritty" \ && ret=0 case $state in (alacritty) words=($line[1] "${words[@]}") (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:alacritty-command-$line[1]:" case $line[1] in (msg) _arguments "${_arguments_options[@]}" \ '-s+[IPC socket connection path override]:SOCKET:_files' \ '--socket=[IPC socket connection path override]:SOCKET:_files' \ '-h[Print help]' \ '--help[Print help]' \ ":: :_alacritty__msg_commands" \ "*::: :->msg" \ && ret=0 case $state in (msg) words=($line[1] "${words[@]}") (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:alacritty-msg-command-$line[1]:" case $line[1] in (create-window) _arguments "${_arguments_options[@]}" \ '--working-directory=[Start the shell in the specified working directory]:WORKING_DIRECTORY:_files' \ '*-e+[Command and args to execute (must be last argument)]:COMMAND: ' \ '*--command=[Command and args to execute (must be last argument)]:COMMAND: ' \ '-T+[Defines the window title \[default\: Alacritty\]]:TITLE: ' \ '--title=[Defines the window title \[default\: Alacritty\]]:TITLE: ' \ '--class=[Defines window class/app_id on X11/Wayland \[default\: Alacritty\]]:general> | ,help" \ && ret=0 case $state in (help) words=($line[1] "${words[@]}") (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:alacritty-msg-help-command-$line[1]:" case $line[1] in (create-window) _arguments "${_arguments_options[@]}" \ && ret=0 ;; (config) _arguments "${_arguments_options[@]}" \ && ret=0 ;; (help) _arguments "${_arguments_options[@]}" \ && ret=0 ;; esac ;; esac ;; esac ;; esac ;; (migrate) _arguments "${_arguments_options[@]}" \ '-c+[Path to the configuration file]:CONFIG_FILE:_files' \ '--config-file=[Path to the configuration file]:CONFIG_FILE:_files' \ '-d[Only output TOML config to STDOUT]' \ '--dry-run[Only output TOML config to STDOUT]' \ '-i[Do not recurse over imports]' \ '--skip-imports[Do not recurse over imports]' \ '--skip-renames[Do not move renamed fields to their new location]' \ '-s[Do not output to STDOUT]' \ '--silent[Do not output to STDOUT]' \ '-h[Print help]' \ '--help[Print help]' \ && ret=0 ;; (help) _arguments "${_arguments_options[@]}" \ ":: :_alacritty__help_commands" \ "*::: :->help" \ && ret=0 case $state in (help) words=($line[1] "${words[@]}") (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:alacritty-help-command-$line[1]:" case $line[1] in (msg) _arguments "${_arguments_options[@]}" \ ":: :_alacritty__help__msg_commands" \ "*::: :->msg" \ && ret=0 case $state in (msg) words=($line[1] "${words[@]}") (( CURRENT += 1 )) curcontext="${curcontext%:*:*}:alacritty-help-msg-command-$line[1]:" case $line[1] in (create-window) _arguments "${_arguments_options[@]}" \ && ret=0 ;; (config) _arguments "${_arguments_options[@]}" \ && ret=0 ;; esac ;; esac ;; (migrate) _arguments "${_arguments_options[@]}" \ && ret=0 ;; (help) _arguments "${_arguments_options[@]}" \ && ret=0 ;; esac ;; esac ;; esac ;; esac } (( $+functions[_alacritty_commands] )) || _alacritty_commands() { local commands; commands=( 'msg:Send a message to the Alacritty socket' \ 'migrate:Migrate the configuration file' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'alacritty commands' commands "$@" } (( $+functions[_alacritty__help__msg__config_commands] )) || _alacritty__help__msg__config_commands() { local commands; commands=() _describe -t commands 'alacritty help msg config commands' commands "$@" } (( $+functions[_alacritty__msg__config_commands] )) || _alacritty__msg__config_commands() { local commands; commands=() _describe -t commands 'alacritty msg config commands' commands "$@" } (( $+functions[_alacritty__msg__help__config_commands] )) || _alacritty__msg__help__config_commands() { local commands; commands=() _describe -t commands 'alacritty msg help config commands' commands "$@" } (( $+functions[_alacritty__help__msg__create-window_commands] )) || _alacritty__help__msg__create-window_commands() { local commands; commands=() _describe -t commands 'alacritty help msg create-window commands' commands "$@" } (( $+functions[_alacritty__msg__create-window_commands] )) || _alacritty__msg__create-window_commands() { local commands; commands=() _describe -t commands 'alacritty msg create-window commands' commands "$@" } (( $+functions[_alacritty__msg__help__create-window_commands] )) || _alacritty__msg__help__create-window_commands() { local commands; commands=() _describe -t commands 'alacritty msg help create-window commands' commands "$@" } (( $+functions[_alacritty__help_commands] )) || _alacritty__help_commands() { local commands; commands=( 'msg:Send a message to the Alacritty socket' \ 'migrate:Migrate the configuration file' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'alacritty help commands' commands "$@" } (( $+functions[_alacritty__help__help_commands] )) || _alacritty__help__help_commands() { local commands; commands=() _describe -t commands 'alacritty help help commands' commands "$@" } (( $+functions[_alacritty__msg__help_commands] )) || _alacritty__msg__help_commands() { local commands; commands=( 'create-window:Create a new window in the same Alacritty process' \ 'config:Update the Alacritty configuration' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'alacritty msg help commands' commands "$@" } (( $+functions[_alacritty__msg__help__help_commands] )) || _alacritty__msg__help__help_commands() { local commands; commands=() _describe -t commands 'alacritty msg help help commands' commands "$@" } (( $+functions[_alacritty__help__migrate_commands] )) || _alacritty__help__migrate_commands() { local commands; commands=() _describe -t commands 'alacritty help migrate commands' commands "$@" } (( $+functions[_alacritty__migrate_commands] )) || _alacritty__migrate_commands() { local commands; commands=() _describe -t commands 'alacritty migrate commands' commands "$@" } (( $+functions[_alacritty__help__msg_commands] )) || _alacritty__help__msg_commands() { local commands; commands=( 'create-window:Create a new window in the same Alacritty process' \ 'config:Update the Alacritty configuration' \ ) _describe -t commands 'alacritty help msg commands' commands "$@" } (( $+functions[_alacritty__msg_commands] )) || _alacritty__msg_commands() { local commands; commands=( 'create-window:Create a new window in the same Alacritty process' \ 'config:Update the Alacritty configuration' \ 'help:Print this message or the help of the given subcommand(s)' \ ) _describe -t commands 'alacritty msg commands' commands "$@" } if [ "$funcstack[1]" = "_alacritty" ]; then _alacritty "$@" else compdef _alacritty alacritty fi alacritty-0.13.2/extra/completions/alacritty.bash000064400000000000000000000300761046102023000202230ustar 00000000000000_alacritty() { local i cur prev opts cmd COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" cmd="" opts="" for i in ${COMP_WORDS[@]} do case "${cmd},${i}" in ",$1") cmd="alacritty" ;; alacritty,help) cmd="alacritty__help" ;; alacritty,migrate) cmd="alacritty__migrate" ;; alacritty,msg) cmd="alacritty__msg" ;; alacritty__help,help) cmd="alacritty__help__help" ;; alacritty__help,migrate) cmd="alacritty__help__migrate" ;; alacritty__help,msg) cmd="alacritty__help__msg" ;; alacritty__help__msg,config) cmd="alacritty__help__msg__config" ;; alacritty__help__msg,create-window) cmd="alacritty__help__msg__create__window" ;; alacritty__msg,config) cmd="alacritty__msg__config" ;; alacritty__msg,create-window) cmd="alacritty__msg__create__window" ;; alacritty__msg,help) cmd="alacritty__msg__help" ;; alacritty__msg__help,config) cmd="alacritty__msg__help__config" ;; alacritty__msg__help,create-window) cmd="alacritty__msg__help__create__window" ;; alacritty__msg__help,help) cmd="alacritty__msg__help__help" ;; *) ;; esac done case "${cmd}" in alacritty) opts="-q -v -e -T -o -h -V --print-events --ref-test --embed --config-file --socket --working-directory --hold --command --title --class --option --help --version msg migrate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in --embed) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --config-file) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --socket) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --working-directory) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --command) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -e) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --title) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -T) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --class) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --option) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -o) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__help) opts="msg migrate help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__help__migrate) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__help__msg) opts="create-window config" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__help__msg__config) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__help__msg__create__window) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__migrate) opts="-c -d -i -s -h --config-file --dry-run --skip-imports --skip-renames --silent --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in --config-file) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -c) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__msg) opts="-s -h --socket --help create-window config help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in --socket) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -s) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__msg__config) opts="-w -r -h --window-id --reset --help ..." if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in --window-id) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -w) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__msg__create__window) opts="-e -T -o -h --working-directory --hold --command --title --class --option --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in --working-directory) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --command) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -e) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --title) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -T) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --class) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; --option) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; -o) COMPREPLY=($(compgen -f "${cur}")) return 0 ;; *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__msg__help) opts="create-window config help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__msg__help__config) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__msg__help__create__window) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; alacritty__msg__help__help) opts="" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 fi case "${prev}" in *) COMPREPLY=() ;; esac COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 ;; esac } complete -F _alacritty -o nosort -o bashdefault -o default alacritty alacritty-0.13.2/extra/completions/alacritty.fish000064400000000000000000000173331046102023000202400ustar 00000000000000complete -c alacritty -n "__fish_use_subcommand" -l embed -d 'X11 window ID to embed Alacritty within (decimal or hexadecimal with "0x" prefix)' -r complete -c alacritty -n "__fish_use_subcommand" -l config-file -d 'Specify alternative configuration file [default: $XDG_CONFIG_HOME/alacritty/alacritty.toml]' -r -F complete -c alacritty -n "__fish_use_subcommand" -l socket -d 'Path for IPC socket creation' -r -F complete -c alacritty -n "__fish_use_subcommand" -l working-directory -d 'Start the shell in the specified working directory' -r -F complete -c alacritty -n "__fish_use_subcommand" -s e -l command -d 'Command and args to execute (must be last argument)' -r complete -c alacritty -n "__fish_use_subcommand" -s T -l title -d 'Defines the window title [default: Alacritty]' -r complete -c alacritty -n "__fish_use_subcommand" -l class -d 'Defines window class/app_id on X11/Wayland [default: Alacritty]' -r complete -c alacritty -n "__fish_use_subcommand" -s o -l option -d 'Override configuration file options [example: \'cursor.style="Beam"\']' -r complete -c alacritty -n "__fish_use_subcommand" -l print-events -d 'Print all events to STDOUT' complete -c alacritty -n "__fish_use_subcommand" -l ref-test -d 'Generates ref test' complete -c alacritty -n "__fish_use_subcommand" -s q -d 'Reduces the level of verbosity (the min level is -qq)' complete -c alacritty -n "__fish_use_subcommand" -s v -d 'Increases the level of verbosity (the max level is -vvv)' complete -c alacritty -n "__fish_use_subcommand" -l hold -d 'Remain open after child process exit' complete -c alacritty -n "__fish_use_subcommand" -s h -l help -d 'Print help' complete -c alacritty -n "__fish_use_subcommand" -s V -l version -d 'Print version' complete -c alacritty -n "__fish_use_subcommand" -f -a "msg" -d 'Send a message to the Alacritty socket' complete -c alacritty -n "__fish_use_subcommand" -f -a "migrate" -d 'Migrate the configuration file' complete -c alacritty -n "__fish_use_subcommand" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c alacritty -n "__fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s s -l socket -d 'IPC socket connection path override' -r -F complete -c alacritty -n "__fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -s h -l help -d 'Print help' complete -c alacritty -n "__fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "create-window" -d 'Create a new window in the same Alacritty process' complete -c alacritty -n "__fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config" -d 'Update the Alacritty configuration' complete -c alacritty -n "__fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from create-window" -l working-directory -d 'Start the shell in the specified working directory' -r -F complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from create-window" -s e -l command -d 'Command and args to execute (must be last argument)' -r complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from create-window" -s T -l title -d 'Defines the window title [default: Alacritty]' -r complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from create-window" -l class -d 'Defines window class/app_id on X11/Wayland [default: Alacritty]' -r complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from create-window" -s o -l option -d 'Override configuration file options [example: \'cursor.style="Beam"\']' -r complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from create-window" -l hold -d 'Remain open after child process exit' complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from create-window" -s h -l help -d 'Print help' complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from config" -s w -l window-id -d 'Window ID for the new config' -r complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from config" -s r -l reset -d 'Clear all runtime configuration changes' complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from config" -s h -l help -d 'Print help (see more with \'--help\')' complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "create-window" -d 'Create a new window in the same Alacritty process' complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "config" -d 'Update the Alacritty configuration' complete -c alacritty -n "__fish_seen_subcommand_from msg; and __fish_seen_subcommand_from help; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c alacritty -n "__fish_seen_subcommand_from migrate" -s c -l config-file -d 'Path to the configuration file' -r -F complete -c alacritty -n "__fish_seen_subcommand_from migrate" -s d -l dry-run -d 'Only output TOML config to STDOUT' complete -c alacritty -n "__fish_seen_subcommand_from migrate" -s i -l skip-imports -d 'Do not recurse over imports' complete -c alacritty -n "__fish_seen_subcommand_from migrate" -l skip-renames -d 'Do not move renamed fields to their new location' complete -c alacritty -n "__fish_seen_subcommand_from migrate" -s s -l silent -d 'Do not output to STDOUT' complete -c alacritty -n "__fish_seen_subcommand_from migrate" -s h -l help -d 'Print help' complete -c alacritty -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from migrate; and not __fish_seen_subcommand_from help" -f -a "msg" -d 'Send a message to the Alacritty socket' complete -c alacritty -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from migrate; and not __fish_seen_subcommand_from help" -f -a "migrate" -d 'Migrate the configuration file' complete -c alacritty -n "__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from migrate; and not __fish_seen_subcommand_from help" -f -a "help" -d 'Print this message or the help of the given subcommand(s)' complete -c alacritty -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config" -f -a "create-window" -d 'Create a new window in the same Alacritty process' complete -c alacritty -n "__fish_seen_subcommand_from help; and __fish_seen_subcommand_from msg; and not __fish_seen_subcommand_from create-window; and not __fish_seen_subcommand_from config" -f -a "config" -d 'Update the Alacritty configuration' alacritty-0.13.2/extra/linux/Alacritty.desktop000064400000000000000000000005221046102023000175130ustar 00000000000000[Desktop Entry] Type=Application TryExec=alacritty Exec=alacritty Icon=Alacritty Terminal=false Categories=System;TerminalEmulator; Name=Alacritty GenericName=Terminal Comment=A fast, cross-platform, OpenGL terminal emulator StartupNotify=true StartupWMClass=Alacritty Actions=New; [Desktop Action New] Name=New Terminal Exec=alacritty alacritty-0.13.2/extra/linux/org.alacritty.Alacritty.appdata.xml000064400000000000000000000030031046102023000230310ustar 00000000000000 org.alacritty.Alacritty Alacritty APACHE-2.0 APACHE-2.0 A fast, cross-platform, OpenGL terminal emulator

Alacritty is a modern terminal emulator that comes with sensible defaults, but allows for extensive configuration. By integrating with other applications, rather than reimplementing their functionality, it manages to provide a flexible set of features with high performance.

https://user-images.githubusercontent.com/8886672/103264352-5ab0d500-49a2-11eb-8961-02f7da66c855.png Alacritty - A fast, cross-platform, OpenGL terminal emulator terminal emulator GPU https://github.com/alacritty/alacritty https://github.com/alacritty/alacritty/issues https://github.com/alacritty/alacritty/blob/master/CONTRIBUTING.md#contact Christian Duerr
alacritty-0.13.2/extra/logo/alacritty-simple.svg000064400000000000000000000273211046102023000177770ustar 00000000000000 image/svg+xmlalacritty-0.13.2/extra/logo/alacritty-term+scanlines.svg000064400000000000000000001016231046102023000214260ustar 00000000000000 image/svg+xmlalacritty-0.13.2/extra/logo/alacritty-term.svg000064400000000000000000000415461046102023000174620ustar 00000000000000 image/svg+xmlalacritty-0.13.2/extra/logo/compat/alacritty-simple.svg000064400000000000000000000265541046102023000212710ustar 00000000000000 image/svg+xml alacritty-0.13.2/extra/logo/compat/alacritty-term+scanlines.png000064400000000000000000002476701046102023000227130ustar 00000000000000PNG  IHDRx pHYsv5v5'sBIT|dtEXtSoftwarewww.inkscape.org<O5IDATx[,i[_d\TWwuUOԥ{4` ɲ% ,-#,ƒl0X%%$kLOKcW]USU}nZ<|_D~;r<{yveF|_p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p8p d6w_Y a0 AXrg|;9lGXMcXu??6p۱ovX3dН:MnGZt}מ&Nw+ZwLn- ^'7]gLem~ ~5_rߵstps?TUwzO.}ADm_~Dp8쯾=W?fg_p8yG}U) xn O~߸VYD"a5ӧO9993bgr8TUEUUϝ;w{.UU-{w'W|Gsu]rtt/p8AD{.~xxg}Çq8x ޽;|TDݷ~{fD/)c>cg !Zk {=7pl9T|CK =9|p8;3?,_Nn^ 'D7Çy|%Ar@`Y Wp8-y |wxppp//BȻ2f?vp8 ~CTcq8g}~[ ">#_%p8^0?яȥ`'O\p8?ӧܻw_W'8'? "+BUUzvv&=q8ƣG8;; {{{$,Ԃp/Q?8~/|Ux_oB8;;=Ǿ"pQ O>/p8=z#p8xp8n0 '''Kp8ǭr$}%Eh4p81F&p89p83sp8ۈ.l!?яO999/]8cPUw7xo}[ܻwom/M>S?ñ899?{o^{f+lc7~7CñolwG;caf{<|?,C]yB>|/OR53'Z-E/P?͘fܻw^{ ? [?'fl53~GO8;;#q ; vCq8)p=::Ç|f3z-olٓ'O_u~Wp3c~;99?O>qk \g?O?裏xb[B@U{;^(/<^>[!ɖ-ݮ}dO>{O<=UuŏcD3~|G7/1c![w6Ϻpr6~8==;eZߍ1`cVs,A" ݏmvǮk~3ۻI=| _W.K"Kn]s.=ӥq_͊[+m6@: V"'}לc]8<<\ S;d C@ȏ m ]r,R8&N@C/O oa~t_A[Ijr$Νd.K%̞{&{WĩApO`{[/qC EFηFȅWw7ʨPKލR-p 3[d@t8vFw[7L\!eغE !GFFPmį)Pb1F>@uǯZ/ЯkNkqzDj#bw[)V/$@M0-o٘[$9 V xɺF?X񲕯s|rDPot+?` '֞";n`׫yqBO~> RSmbKbRRu{]?;oeQ PI)gs`k:q46y̯r(]v-|d8-$G"%ҹ EڕNZvr9)#u^+wlOmC)` ؖZH9aصI;~ FaɁUA B(ABM A@<17]|V@k,߆0ؚ뀄E;Hө+:"/z#y*I0FO c2fbT)]I55,\ݯ";[_)~Asj& ߆3@A/ |Rf@BE5:GMk/d)ƞGTqZ-m%aK `[b ڨ:@̵SxH)g&;G ; aAPwl ڶ9kBR`Կck2obBODZ2S`qO wdhƾj YO`xs1YbW3xk$Se Epje‡6* ,@rjvB0 I!ʢ@ ':z6YضΫurHu)0x;7h4hkc.xjHiYhwbz$Bߩ^&Rpl 5Xy dDl327L ]#ñau S?[v=T<-_[dCQOeF4|Ej^}&,}zRB12" l+\f!% cþ)/J}xjL$O9I7C804[X+%б=џ_MZv[ʜU&E1"e5"sD_Hg0B`4~| bԪ|+Q*bd7 ) JBPHmw[r1X pPh=w%@֜-ղ$挀LA_z[ XA^!SgwYKT㮥FmШ&< 1]Y [?-pLJ1twxީr*cKlC~ d}IO~iYo/ݗ"+Ʒ q2Us1y?V=x UcjO-!eMy.-4 te蒖@y] ^Mw B TSS|$UB+{b[GvPN_dߺ{Wscu2#Q|*=LipH̄S&& I # @O$ Wt<+Cعe2s<_M6C81!Wi+A ߍ,[| :YVh,ߖ16 `3CQyjƩI258/NgmM;Opl q|[ PIRKjD]_( ,i6F.풿eYx=vr[zB@9 !]WCe"5ȠTAH9 [85 3_Pw4F,f,hf 6`Iٓ5G7f tn@$ ^srÒA+ Skأa4fRcȷҍ>2[C2y]Vo8]dѦqsHġ/b49,gR9@$MKN~bh(Mޗy##;g%flPM1L39!MR@;90ntJp7qT<y"dĺ8!׿UZj% 4XjICeVưRD6*4~S`#[?VA spl‰NP[ ~0 8?28n A0ݽΕ0T]|B#ĩe2Zl-k& (rbƼg䥛3}y)a}ĨGNSW{َ,9g&S~iZ./gXLʝ8WH+Uy3 PMq/jR(yT)L`e4(_[qms% JNW3NZhg*Kb ExAz2N.:v(u)zX񿇱'ʾ]xׂ1+DC[J^j*dq|v/j0VqD`I$: Yd_+=>[9`u|_*Gڟ?A0WxSJy+/$Cܶs GDe1,pbʄJ,nLYcA4':EBą6Nixïƍ?Y&HWD$;D),3Q$k|-(/"#vB]]m'Q\=];MC0 . S k(_Ҝ!aD$ 5;\ Xď58mAps2R_L3@@"wRerzC}΀,%FqeiBm2`3O ݠ_ IM@ILpd:7F݀D`*X ylpdb (p<۴kAlF]ʟRG?LĨDBvN0U+AI5t=zש_Ŋdg/5i O1I}%IJ$'@3`R@/΀ㆮ;@~Ȏ?۾??'AF&G}" im;_&Iu!7iٻb2Cb\O)4&9srv)ʄ`I/Ch)(6iovlw@xkF?rjndҎMR۟bD*1҄@)T.eSb^saQ#(٫7 jDY&^Bˆ/mUۻ[5iD빏v\!ou 5t*hQBPNq4(D=!}e&<Қ(j # R[86;#5up8*BډX6.YVҿU,ƘCix#MP&vnXY7p>P~ "˒ņp27anB &DIʀ1#ɀ: z.ݹ )S =uzZ[LE#C\;?m'HI \8fQy*p*` }O2,dH@' Uцp\mr`*㺎vL?UˊBH?L`O{<"$'JUĬ),6~ tWBk37d- 2pzFD{4ܑ `s$0)B*״6b-s[YZ8 pS,F':o?-81wĐ< QD54ybYjəkܞ%H™)6Tj5j 4τ&F `М 踎N;;3`/la4roc0 e?U5 'bT]2ɧlh2.0:hl$)>a9pSNj"٢1iI&@d@ǵ߲O$zPEcB@+uaMk'&_`LD$ R~H޵яl/Kwu}+-f4L i4 $b#wM E^XD':X-r!M:Tȣ:hsz> z?F*S10(_'f0LWZEvȈH.9c}`$r 8R´f185 afI\ H%L0ɀ+JAe{Z"TT+3VmB'*{hR#'~0Q51ޙw&)mђɮf WAZTKRg!pfp_Ѐ*50|3&$3 ÑB1 ,r8oBu3#IK?i_fY@`_;xs|}j"$ Rap .# <̊ay6)Y,DC B* tmj x8;Op\#P'd'@ PesPDyYWBd_41[w "A߫&CJ-"=p %%@e) D^KQMK-o¡ば,d p\uTs&~:꼵Ȏ-z;=4vA##r'L$8պ/DW0mPDDˎH!bL$^,& S$?&] M?g6qmxC2O[9`@ĈY h3Qf44<.6FA7eDk;g%k9x)(,P[Lsh EO@*x]`Mw6jD+:mkX7Gs&@K#PT!r5?"֤q K7 t]onϩ$ƜCw@U"f`N@Ły[ 踢 V5^`gFrl樳KSt2?hhR\F#ZEȉi Bu~[qxO4Ĕ*^m 6e1(%@gEdY$%"*jSձ#`Lt?GGufq?Uze|%{2PB}k8&/Rͷ5>3@ h, aQ\k&+!5jk8EHb%{R j:g3H] ٟT`%QYGJ0"] !W2y„*t.?gd\+yIOj3q |4 A`!K A(|/8Dڅn TS*俖u^ mO23 q;+ ޝ*ߚwE"]=&z7fes[X=Xw{z}d0"ИIh I L L4Lpf! ـV! xƳ"svu".kĨ,9c" 0Co,#RWקʃjoGڶ^@+q;Jb@lhopm=Kõi_[uP<*zע_XL|,΍ R0 -f`L h3yD`~<L۩Z:c?BhC-qWae`I]2 %;lbXS f򠊼1p*$@FeD "yڔep1ǖ9 /d~96>~ZŸb\o$P:PQH5̨ 75]S@.a [ u0 m-`߷DhʔUoj 3gA qksKp4M:3m$Yguc! EDRj*e*e EohqFKҺN*Õ)UXŚJ()OR75u#*rf0O&d9V8 ~q՛\JT<{~:V3iVo{, @帪yb ?ǙCPZ Y2gU._B5*GFْsm֒jyF8pw]x`zN@ h2 C`?+[S u6˳`.mrmL7S`%GT*B=Kp!W`S:b4f~ɨg#*]DnB@@=e@wDJL^`;B5c:n/I/I4WcIbߕW'sĸIp%62ܾoLsJ6C)g 8/1 "F83& KZm+`-[k"h`:Io|vo(Rm_H!#^+#q'D^oMw'Ɓb? /r 0-[YF gؗG2^Aòɹ)E'fZ8ҊS3K,9uh2s9/5X@sA`H TB'ѿQIž(a!s?_Dޚ(oM&0Kld_~[OY H )< z>N 7FS)J(PeBP%a ɷe (NtlpYM9ic%9&)F#YG/eFH"קʫNNˀW}Eb[2ZK2,aܻg.\F3 3@'!T96/@TACXHVH% o#.ˠ8٦BX(eK ÉB](QoQ&A^Lh C} a5GvRnH:uqq=.XG3v|X+$U-YgZEN搚ߍP-P-os.<(xk;W/?ƙ)Oci-4pc Y @Kl-Ȁʂ h0K^YMߊq6 b$6SqɖEfp|V'IjP,(&46|S\*XNcIJA7,mj/ 7z*|˲6褸dyZ77phʩ4P# jF%Mn,8.Wtf^ 9V zsǒ̺6A|ҿQW)H * |20IkRԻW5 [^r4pw@xQ!9n-{EҐK h5OJh-KCw1*'}Jr -i,|'1L 55TiDp$Dz+GdX?,{+ E] 2{d?W fzmv6A4f5LbaSqlJsm% a" ж p]pW|O|CEB@K' ! Io&,q?(/I͙)|kbT%M^|9z؇7JIFLf#TKdwo2۬ћpAYX4GnZOB:Y!9д@#d@8.s܅ƺ/APXjLJN7+UoH}3QER8r_R{eU޺Q/zl H5:N1s oW@1Q5ʉ(Q (PIHTCڀ je[+ڦums6̋ @ޅ_³# d$4?W+SDR`[OAp/P4 fOZ;0Tĩr~1HKQk>vA7B qJӆh,-FI H\tK'05W[~=(0u*;=?TkhUWI*`RTLɤH~M ըX6 o0K-~b1hLIx'$J^fYo~}QeK aa"Y D BbIf/J&8D114>Y$\-El2==֯34eQD5+:҇L~r&\رkR>5`8k0d9nЊՈ-tIHTo0hRթ3xJe]f"j ZlDt0fy*± Ӻh>^5Is5"e*M236UΉ}m(C>e~EB@΂tu]PQM~)ױֻViI({5 T싲{AxPߚwoN!ILWM+{m߈Qfl~+bfC4F$ ܙF^S^brF.{@pM{5\ S8Rc6da.<S g %G XZʷmr 踽&TؽTlq._:I/ f,s^g7LY7g+l=;Uog~hd`${Q-1gB,'jU1% * *iz6[#StJ#p&S,({SXT7˜!w,BւHw,1p=rkAcJbfR(X7R2 eݝ `}/л*8,!@7'eCR{uܯ"f"UB 5E.>Ek8@\kˑ bc vֺ0 K Hbū٫RI7F z~m`{d眒IJorTETZ$/}msGIr8se;9~sli r+ ꊘ!Xe`i"K$1ozf ܊Qe 5瞰в10I_4ͅ/afȳX(I*:C@L9$6Vg ,3;4Ґ cO"{L-d>BfQlK13 < paoU 6@/Nו$ IјaTWLHƆዘ#uUeA[8 _/l6LSd *Lh.1rj\iw{o`1)q31ѐ(Ngp7,&,p|9?9OFӪg78&׿Q,FT& &yF, I/mA]\VG2L`|! 1얞oRd[d [ĘI`O;+Z};(%b$"^ٶeԘ@  NU@Uj2tkؒĨD BeOU.hhlaX)0쮈faurt,<X,& #Suʺ *[tUٌ]BE5uۙf[ ß )/* هM`?\h#p!{h ,eM#Ąց'ajF78 2fXr* 43^S^*94MJbپ%@X9 )*|Sㄣ(ZL3]&-v1;2!Ah=_-!G)6p6_uE/a?wr2ޜ»;{ƃ ml凚 ${m/KȠTMCP)S0m*iT$pS1&I!9NSQ&0)fU$Ɋv+gT-MR`b&YhDCuH r`QБAUv]Bع޹i{69%/dtE2=զ!$~P*x_32SUi92G6%Dj[(© pƄ$]4de!db-OJLb@yBb'Mz5̛kgxn42+pF2,*Ƞ84h4 &!GC"w,Lr7tDZ'@Xx2rx684S3_%)jw'+^Ezyaў6c'z"5kّ]<3 t?7W xwO%>o?9 |><$fqD, Q `bh[Kє%\/I@qLOW YN8.\Nj bT̬RP tN Ԝ=-f,sJ/46X-4M:[]VC(s$  Crj95G!*O܋mfG^74`DDOkùəX#Ǎq1Wͽ9 l6Pѓ)1)DMʑk#< !/4.xEkr_@*Gud^לic1I(逡@sJu U" :떼ouW̳Z/W_th ZCet?JsS`ۙ$V8_h޻w9nOD YU}͒,{={v=-շ"dF AKKWH" "2sDcmz,ؓ .eeLTl:gF9]'m' N|+ur*%.{JsWabN\g&NWOj%*=pN _Q&g]U6WL 7v?9 <čl_OpNt47#é8egf;7QENNkNN_(v{ VE6'C[%e)ա!ZErK"7 uc`lh\)rEӤ\7w-hoGmfIw*%ҏN hN-_I`(˨e=n?ȦQ"8+M|8ϪʄK~F T7 Pk=eT6 壞@sؘ&^li-{V3|4^zՃ`m%XlS 9{^LY`O}Mxi{>%NvwQo0ː|<钌 7Ǭ]xDWNq'ڮgUR6l\Liz]bUP˩,@ !mt,r$)b(>>JCvoFl~(;TП$NR#T%=oD}TLRVr76 ϘR6dr Yy }yU [! W"™*ß|L%w%=΋dACVrecb(c>sLOOӤVEN# N9)_u&YU0Mcn7$1{?23XFM Rfc`Ui3uoa,9>a -/jL`.1_|l X󤃪NyMR6tbCf:> ѽG VF*#! u=PsVj|Drt^nYG=`m7Ru&Ф6e>],iQ@V}ԟfOxY K@ ym[XTg5ʓxU ?ܴ]`s%r:{gq*))C6!HEi32DrB @Ga N1W%;sƙ kjiyZ>H0.qwA۱L'*\P `JpLhLFF:|FP%`l$BEUq|6wd%ἲmD7FgЧlKe yYome~xONp<}>e)O}eGĨp8ȓ*Rʼndgvs!d7:a R$>*o{eƜޜބMtߎR"l鷅ȳy,T޴ų6ryvx}UUPd2Yn`7a2@}`ԝofύ̜X񤊜iF ĊPJuEÓH x_(}j{-f>@C5ٷMEyʸqJF nlw{JlouǸ}ް)fx] x(?eYߍvL+C/:F|/ 1dQK/ S0u!,sii1\czd,P~s1F{ E'Z bJol#KĦv{|$@KXߝ?̹RktK?zL^:@e&#e3i"i57@\f䚂) i1u-.u]J% l4%8 )mT"4Cu6b\sm=\u*ʧm$SnLkg<9oc֭rhMk?{}1[SnΏ=%?b|b]@WN|G$7}ܻ0>f1oܗi6`׽_co\&/@yF|L3Ώ&H2|`Eq5N[Dkuzg jaGdhC|'?TP05x'۞޹6<3J(xFU?%ELJ+R9>?D`_9cH)1 beL-΀Ku.qFkN&{?ܽI w2n({Џ΃+sldfnEqK}Wq*δ&RQPnJ;0F3[Q܄X"60YǙgub9 }mU*R?LT) \ RHA0۸ OUOzvŻcUs|" @Sg4ѿP@۠Sw/? _7ΪmG`s6&޿_اQ93?SlB*V^C@R [ K"0id$Bp?Ȁa` u P8BbY;OoVua0߮&*p,3ĀutuPנM$ȕIq`R0׎,L$h6w'7JU=oP0@zv4ρ_h@hTYcJ < gKەΌ|Rdk~~\^y FͽMu`d*_F\ϥoq (He߅(!+U UCTIZӋ!Z{V*Y9_qpf`t&&ă/.ܸ"$d@|Qwm0ߵevo|ZUGYJGSoB$"T(Yelʨ3nu;AÎGTwrK*sHq%@;݉k[ާX6%(_]I\pQޡ'q2" ͗ݧ GslSrw&Nk)虣6VOYՅm@ |f@M{z6T;S*3rx>S+Uc<Cm=Pif6L[>ȡDjw4ssN'ΗPq4?eJ1& f{LcGXծ&߁qMBNy WItfS|/!:n"!yNLagMr୓S/SցFE" }A0pc3JiB˓]q-)ٰ]م}_lp| iO/O.7<}g_'[[yN'jFNmFOuɳ`NɎ#_{#c.yO_%ᯭkFcmI&Eh-лF;O+}<0?qeB(П- ] S'E'dJ'h\]yIĘ*q\Juw4%Z4+)K0'1s]9yN8G^(Mf@2.cwhY~ݽA\':@']sm]9M=mUV&//( pR̘5Q%3:u1Zu6XuN*~fG*'7UyRJcdһ>rzuqLF Ɣ+'2sM;q>2 ]`'ۆ}hs/E.Xh55<6W|l:;x?:sgO,ael3v7&{oQ Iq)B`+NFL%QxYB c"?̊+8 M?93e4zc8SGN)Ƞ#dIَAթDv6Bqs "Nŀ㻮E /xl<5#q># فWSSk௜q\ߞ9_,?G'fzC9=ڬg7܎[]Z`#+R=On䠯(B ŏ%,NNSi3InX6d*S,FA&ѬmX1zLOc7@0em78'Y P(H3aɇSQ_X (*[}RBV%M1yDVwb2UG)gnc,1=n&9L||7]URAn/g>ͬۺ*h&1Jl6ޛinyZs"_cLʋ)*)o&N4!ghu#ԱLr0=sBGvb<>]*I\tyu I䩉̭,XO:ovcʞoB7d@z!XJ8+!nU>>%6ao8G^w}&:mr:sZS:hг+%oK2-(w|.x;t:`fpa9(, P(lE.D:U2ɝ[y gdm7 A xs#i6&'^qFb%P${F5e8c纗4BBMiiHh5lb4FNG< }J"f  ~Hd:7i11\wWƪ?nEmHf@'1㽼`8i1`N G׷&-{T"zE ьNH!q)FW2{]ϯu<ʛ [xM2zϐ{mwC`+Vv=Z&U3.߿#-|8ʬ-P '&581h<;=ã޶}9vrC&qCFDJǰ`vIfgqYV>&^)*?ϓiYgY0U23ᛥs;вwb\e&;$q.p-g^s5 & |bSH (B!T M͋/̟'۷?u=ndo*BL+ww ;0 ` $yĢV,2qNO\v3qI8sLϥkuKulalQy9Xe>oߟ9~n|pa7F3}̮I9΍À\YEI&Z<HAPvhBC!(jX_?Bͦ_jCfFJSNR$yN`$Q QG5+1j Ԛh aQUrVK嬲mEH8,O)UdtPl;`UcXpRS^iLQimʉֽ|F*bdi]TDt<E0%m]ʬH)C]x KAY碆ϖ+vq˸~H{s(̏hK*{e+ZpɻvI(nzpבL79nMQf9&Dm?Te0^ԉu-Uzs ;QU [- *r0bN}n\&;Gs/BK ՜2Ƭ5uMV_j{$8[qݭco{"Nݶ\G&dQR3%wى{M ^< B @Ϟo^tܗeqCϞG4 e0G 7JAP^ԉRoĀ{ݎ^_m* ǞǝdDCOM(NQ%3&XƦSO.%,1G?);04[ QD \E@A0$9 Kڳ5|'ɱwCdք%?@n_h ^wf֔ތ̏eokhʔP%#qJx:{W4<UJ\JO޶TK2kN7./ m20V^e6Vn$ϽDS h$i@C+,T*nMh)&Kf}]o}O)'%ǔt@*e2$9P;2g:8mgt6y#cJ\6j~c>'JCF 2c]w}j2MpSr|]U<+$4YSpg{ @x0+Y̻ gүoU~ O.}~o[2bЙӻ睢Cd7;$3>@=חy/Unҫ#C|6s`i8 4Q)xayyxeX /^I~9pӘ;ѭ$@5'&Lrxa2dg$t{Ȼ"V9-A|j<S^ZFT2G|oBv[ gy"h{I}?Nhn,?ϕ9]'!uJ*XH|.b?8V Y_UUUS`],+^z~;ًUҘ;}.\7_٬>Fb1{nXLy4,Lg#'9܆*? dr^MHu VCpB \sZ޿m[:>愠1f6@0pV0*rBBvVV Ej~x~qGL@nq~=|_(_NX.JGkS6)OA;m@w`t{ҷ4RgOCF(?-y_KuVqym|{ |tTy4p/!}ovl7wխtsx)r4̅(%@[CCE!RRf`ZF]E?.;͂YX, V|ٗOG7 :6̹z+}K *WWmKt]K۵.*4$)!RȀVOBZV xpΪ̇8HfF;Au ~N9X'0%&sFG+ʼnkl鎡$2$|vσp x=̋4i8@<-~gd }%PЄ Z8Y|2>_ 6a\ʕIUӒT= yg_~/?TU(wnjϜooi7]䕜0Xf|K~®cZC撹;WVZ`1|F(r7;'y4LIbъ7D5KIRp!?H%): 8bӣ; oCK`"J8h6ƹ&Bt?\9EL)xGl|gx?'/bM]XY!<܋w<T?RrJU?Mݰ:?|ղAD/ (傗ϟs~G !R@@"Z!;lVu,Dv24wzݜuϛYx-AKӃx`t|KIuV(sM<'6u$B)awH >'e8y c?}dܗao4V֠w0c K8 Đ*Ryzd} rw3W=?Ca[M>D?^o2uti٘N?Ce@ OPI*=&X.'6חX)CňxdXUV約y¢eOd0(H|½O 8PN*3UW./L[XНk̊o̵fN@=R".U>!AJbx|bVx>/sUv;^w6Pk7͹ڴ?o7lW.l6l뉱VRy-[-+; 'Jw!=[16#"\wJ Wna9mj_xtMG3`l6ʺs1NB%3Y?̧bS+an}J#8 }ݑ<%RʧIxXGb8ZI.p/🤙J"pF&hT;\p mO6);s"iMcJ$ V' GT $H1RI";RSb{=U`磗;t1%ח&@#yBiTjT@F+iƵtu+j7k0=icNsM*@ (ߣwnS0.|"xz$G'Cˁ2n-bkw,*1%W A#M-sm;OUH򅿷#久2aw"XQ|0tGD!hVU~+7#A`r, :;=Ͷ.81|E@LC`)&vG(5z-8{&Ew8u9+Q)!Xs^\ GUa\.=W89U}Ja<~*S(Xm+˥s1 w;~.qg ?^Ot:,3-׊!TTu4uK^x| [xeSgKމ3a#Wԋ3Œo߰^_Ӗ6@uH % .:u5bFU0Z"?kMܰ: 粇PkCx;Dpo<دȩ @GF a ?@` UZe!-RJlߟ;pZ2Ȟ/\+!}w{ eN`Xk8@ 9$ \xUUjb,X,,jœ'O⫯?zvA#o¡K/}`qz=&ڶ:bǞThSIrE'HN1j,22*l>3g<28Qߖ8&‹֩/~1l))1 Ώ3.'1KRw?I]st{h %*[ϪjWƓZj]8=1^59`Lg~0?}r|_o&6\ (A Ò/ eBj4nX6 %Ւ咋s|7}{+.T7gsk)mcDTЪB뚰P 1 ,F̲SnY\`*L**li|H ff2=:ɝ1Z NTAzPHT0A5 9et $mNדg!%c?A!h5W**r^5g<9ac9PSFY0<,Cpl9|ITZ/V[(H 7WꐓE,,x%9^ɓsM ٴ*նW^[,KFJ\+EaCa9=TH1(ٸ8ix+RHT-GQl5 {h097d|<9su >ABqي>=-PT D(Ou;Þd4B +"5SyvYh⼎\јɑOA~ĸg"}a+,j (t'{",np,uʁRUn8??SΚH}<{{8kj^ADѱujo*{ރsIe2x"$s96@w6qy1RzMǞ4t%Nv%㝈{,ɀx#FSZ{h$$G;3Nw]$ T$}kָyQ'w-)v'lgU)DXS=;Rjw||Kqutszsy\_]q=ח }}$KFL0OD^N$H8[ޮiw7^&YδpJǎ#ZeusUN6AD@0P =JvNbv=_8ޝZ3FWF!R~v@ ǃXR#?Xwzp8׏즧^v/ 长!&6f6`<=O;b1U 1eO#gxG*xY95úy=>puu&1Rg{N-ku괝up*/ (Si69s">91u <0:V-,gr*%.p WN@Sa p ?S[? S\ $XWؗ\B"0ib* PTe,d?w'2G\g{3$suR:ܷw2dk1kȖ.62EB@OЊPUujMStLgLwOąE3...@i),+<q|]j %l5CL̮ 쇰IƄJ#iZ'Fw;xsb0$9q4*,ݸ\%mOA o)EXt><BzwO-}һc@_jɻEEp΂Yy3jbXsCk=f7|nCVkZM[+syLo..ЇjX,j%MpZq_~/?lV{2nþWf\[o\z:vCt13bw`b e ppĨ%M4JBs^gl_:=ks1L;?9vʏmuʾ%)QuȲ8t Ob+HdbWDZG Vͩ[krAKwZ *gy7+S9^۞ިE "4* u}*մJHLS@BjMU_5M`lX.,+V_\/o>ɪ^ݷF,TT\/R./gTM5vͦmi7]f:`̭X T&@J+EBe0qUyR' X"&9Sq61 s#SBF>| z)W6)'}Q &:: >LĀ*6??{U N_Fj*;OUթ(,UY YpQ9/V 狕 пSULmv~_ m+@XaY*jx$ul{}Wr@q_Fd?l!Ċ2Ք˸HE%hu]QW5E/^gcn[,IrW)eLIޕ?G6k#֑+Tcʤ?QLjbdXl=d(*s]C<HS?ܥ /:N5Ꮋη^G׺rٱ\G8c潒E8F٤@o> ss0p& ȋ΄Zy {%]'6dF"`J%h D\9V4 b=IdRю|2LZbh8?Y2JR@:ްn ڎhq{tZHNkPY^m6yR)䖒Ocl]q(l٘&t͍#I}#MK*{fL.V2,fy@2IQ J憀ݖޏ]kY fE $RRDB }U?߼xBb@[{PlVpUϿv}GsG= Pr(XAT -F\!QE)AD ye,,ckeZU:m"iG׉<4Wd @jЫ)^ϽP@Ͽ(4O@JNw'},@wgXb0ws#ǁthhVHʥdnb[ۭK<`gl'=D6 }TPfܗ?w;>egZf[CEG1Khvwh鉩a}sÛ%ĚarBi;u 3c޼e}sww7lkEp;a\&؇"HkmlFeӅpk`$tNlGщT(30C?Oc/G6}Ÿ@;.V|"W&!Z)L_=O%A@Sq-: =h8{`vc|Й /-u?~ a?RL~} ]Zgji\(WŃ'OٕsrbhwmA@O|3QABTPKwE|"Fv?lږiX-Պ+^xɫW/y˦ Yk7 Ms||U= SI&`k1\$E__~_?9qTxexmّԆ5b #H!]EuI eٶ,K%|ko߿3_H6*cΎKU ˙޳~IZX߲nmlngoܓ@81aЊO,ER.³ՕuK{S^^7'FH,:xEhׁ7}dq(/^+*8XJAr^u|ȥ}x*or;w+2(\5x|`K}M^O BSG=5X#J#%DL;񏣀9GID$:*6iڶe.X,,W VW<oww׼\CmCC ;xO~l(MQ-bL'l7͎]c}G[ndd+ d@ 6U*4XVʟ/xj)*0Ϋ9|$>0Wx~F$mW(. H5YP-0NϷv!~z?FDk?r']?A"_952EVIn͕q:4h*{elfTޕ)gv@/%TЏ)$z!&blۦ],h Ŋg5|W'ȄL^DF36ΚB=}>_[&{2E@%ױ6Ay #㠄` PvfRHpJӻ*G_w'yh&F=F 15cg>ayaAuz{ d8dž;§}*oy?lpU|ZhŸJʋEE[X$ͺ&EG<Ȼ@&'J p\mq#>عں *fjZCjb q=@.\]=勗\]hRzp!l?CO3ftYH1ry˗\]=],I!6a\*@V_V Nx2^^]xZN1Ԍ̇#k1. @mŢpV=3X }0>}GϤ'U~}9W|Mִɥdڅaөw?Y9u21DEٚ=-3T8][ o{ۭ:f'o~V^v|OptլzzbjXV,ۄifِk4%"2)s8lؼ*Pi̲I,W+o M!VYK>kP;go:nxIŦ!?~b RE!r2<ȶɰ|ֶ⤓|8W~ۃϲ=ou <ApFe6mg^IOALS`#'~Y&E]>nҿ=Vj}w1oST|n8^16E~ =|1nsaSY U$1 H H)99){t cOmА\gZ 4ڑ jz3wr{fϕ @nle(&rbtmuD}-^2ھ/EǸO _rJ FE# w۞vv9Й6*lR93L<_3pL j .+˾C4B6Z-RuhSGkFn-MǶ4ЩU %x_TqoE)m : .yb1e~ϧ*Gz۬9ӗB7f=Kh`EqHN_זg%p0JqgP⮓=~>k=0Rs VPZՖV e2 y&_w~|j7᝗oؠL!l ZEU beRy8wJ*$jOpAږ Z=AA&. )4]6-傋+/^?z BCW rؑY`i7C\L+H$Ą:$j@j%`ԉULZ a 1)c |­ZcwNS@#&ǼR@(uDA&T.y, O#oL*|H{ DBM?#F R?:Z緍URRk_ ܚRv,]Oi??ixs%4%#t|4\ZDc$@*"FAmPJD$`!B@ǔHiZErm,+V3_Wj}J}Цhs<7tlR\q+\}3v͏??vC앁SrVs U0PP6g\6BɒiR^+#]z_ڟ?!#NORڑ5[fphon#}`-®8"Z1+|[z K9_5A*g@Nv8EX 9|}a\&Ƒٖ=l=7){ ROAj@ׁkh hh"•z0 qmbbjK>koϯY4QZU`AE` '=.fb3}g/)/ I7?6-ZviGs:`̱2JP QXMRTRA6 M#IZ>0VAC%{p->4N ! cPhoiB'>Д@BR-&Tedi KokOo#sQAż,+h"A*MXFX% ( h8=*> kOY9<~',DOB ͂3@i?&RZдKEKZ.V,W\>{ɫ//իϸ\bF)Qd A ItZβ̕i4Y\pZjZ+3ج  kBp@N10%U3?Ǚ^[;t|`TfA*ɩckmr֊deo40:LiN<~ >9 6X}P(n6~{)X(vqw6+YAYLITU/al{;?j'`S@ ]^]q%WWW4)>ax02i tl T0G!hR59cBJq >J3*~UhVe”'V `o#{a$Vy̛Fq}u[`OZn?lǺ99EWhI5`0XW`:)bu;Df!D/}wӟn䑀7k&AQw{08-Zqq wrm6V7/\'"Jչ#tTZ-sTo1Ęоg}G"'H=J99V`!cLal'VPs`TQlef5 pIJaVCG(}2^ R۝vGJ*LO]+O0y4~@u7{^:c'vE+Yr%&べW"1X>I=k|zRrWq#1`?D(5C `A>䤄%&*Q&:1~&"+egv?xzMDp[_kvv)N\-Mj""#$/w侥JL n)нEn2c(P5z(ju#j-K 1` =*h W')rVmHs |ZȀ#fMt;kzѩs ?`Tх>-iVT"ˤ\'J5i deieHYكM`r 4l}~79\Ub5T-Ds622&ES1*'Dj[Ҷ-rbuy7k^>d"MS@ [Ajj߼RD??bPԅzńe.ċ5%-85=vKH{΍c-z%@jB$>Nh lzij&bZW m1xkPN dX`A6H k% æJбP9X MIb?`j)*u?~!@`,>/oό?-6^=,̘.=;ZWCHv>0Å>sJA-?m?:2:>l3 vruų_ʟ VQHŁW4b wNfTpxY`=¶;ϑvElvsOtۡFPP7Qډ}!4JʪQVK t);h{ج 4HC `z{L x 'P45/FBsaUmWzc lçGH;u+c' b6C_UVѸhgՅ_/ۉOݎ(D=< /n#a 4L J`Z EHHhyHKղJb6cd41&cBӅr\#1]; FhY;gx5+ [o?ډ_WO'$$DL$5Y5q5_X]PKB&HcLCK` c? aT Z2ի{nv}GeԻ*AhY"Up]fzZɨ//2iA"qX阛߼mtJ##SnZ:?m6΁ KQcR9OF.탪Ot^+rTof̂+Ie 0ĩ@" R",.HiVHl(5x&`4CYC ǤV[[=0:gZ Eҿ߼dt9aqDāhA k*7!(dN,ZU+ jyhG#m5Vl@AE4Ѩ!MK=1L|qmq֮;INYV@EEnEɥ5s&e#m=d%XqY F<S CHHir0P꿯cX;^?w?ٸ }ߡDEJ6r8WXTj`j:_Ժ6JRâB2*2F.EX&QC9 >|HkAhE ]V eJ-V')Bu*Hpmp |Oп#>7 tOG&;n * ) ۮ&B/Sj66{H a]/{?nỵra]QvؕBXB@) &T 8\)a4K) ?H۲Jv0^" a¿TĹΌ?Zkpd߃'B@ş_ \gM6Y]wf}_ }vs!`U2fŀ q,B Ee]:%Pps)\#SkkݧI]Ư3v+l;a }`WpMZŀy.m~vV %wc?v/C+ PE7dX.,p3ߡmOM +p÷mWؖ!ۯR,TkB&!sBc4;JQ-)pD}э2AR>b:ĀE`{A:M_-wt7 }_o>'P:T0PA YWQjm0`qmgtp Xh8&/y{abLl2pS%uHHȟᵫ"@Cs11Jy◟52(kXxSu;n0Z3%¼m$Q@ݪ=dTʼdHDqb俛.pE6r2mBaz~6R X,)ZhZ@(S`XqA,_+h.qa* }&}06҉֡T D!yq"@)ǗBjQ4x^?b78Zjmg˨,S")/[?__.ˊc==; ؘڻp{BF%'f{} '~,-Rdq؏:'9([@,BBI|/! R$ 3V}/+.* $sR+A@]y6@Di_+}-Ay?wUlzJ BZ"ݽ߮whܣ9yK X6)AQz/2Ma.ٕqg!'ǩ)]5~ho:6YBä5%ce ba4\x@v;WR=>NpO?|ȴ?ÿ>z/Wo* R$i$Y !D@@FbBsI?u޿!6Kb +bIy/arٗ,.,aܯ"z@6zA5p3MhjSƲ~myUWV*kTŐ" [KdDB:GT"A:L!ZF̽)"|T$x*(1*1)))  baH 2pmɃ2dMQĀϋ!QٚC`#H'H >xU*WV^;W~铫|zCEP? *{K*6Y ?ngd\*_\^-NH Nr#je[F-V~O $@ BZ s³IW]AL;"$ qXM^8 @jk/{܉zAOIEK0Ԑ6>C!CRB ůITD X'-nD8(0 j} q::@ >N2; >?w=UO:7ʍ" nPcHplȪt9 @H(~}aIP) EA(Jm H5?R3oGL[lΩ/-e=iVH{hl}:L~-*v֘Q*(#C/6m'|{⺜T`;aU؉6@ˤ\"R?LP D4}/(3Ǚ [ }c>*t.]};(ч]V߈bѪF߀5kͶOQ-m]lM43QcYY5+<~$kuOύ7?ovmm6vY٪ЩyPB-Tv&`́ {\[%sf{G7X}0$lm jnce?Jg:!aiuֿ~{0`c[į cl]=YB "zrɹG@).,Ww@-0uFTi񒄆j>.RĨ@*JjkPm,(.iM'*Z20;\sNAׂYzÊEPj%`dsRgwJ'*hߝɹ?.JX}ׇl3xUɃP [7IGy91o,s~~Z-xkVӍB1c[ۍZ7+J?ɈAKCnRizbnxQ m7HogvMp_{mV?P_Aiy?A h; ?zMΠԠ {e^yC(݆wXߡCsuG<qD ԋUOMtAvlF]'t! Ngd">OY۱*ݸ=YgfSl{S6%Ͳ_FslB)M2Vy8?zkZ>;}j@{sp?٭o4i;L^tR g6jl{ō+ݦ%K5GWY]_AԦG{~״.MG&|]>%O#?5Hyq콓J=xuAh4+z z--:9CoM_;/DbӜ[ ~5kt؊!*"*Ix {W29d>`{f: ep/WWUc{qմ?K{NC'iChϰ ?nt?=$R6(׍r Q3ǤFJ#ڹ 1OҟbEa;ҿND#amP3?-[Mў>gn.]AD6ns!Sl{kcu2np+]W\XVb@D;u|P,O̯lz.IOA8p)@ E0vC `oiZSp1{_N䏮XHS;7?wo=mndPz쮀Z\P[5 %c4W4+%CRa!e᳕ԱÞѱ؂:Zi V8pPBr_(E -_"xFWmt;g2W?*8-NM7a֟*&ZKTUMB\~Կ=s & o7\bAQο}( ;w$hzB~BV$$T'R$6K798(2BR4Wp)/`f4 wAo5 Z^/ɁC_|mѷS~w P:V|0  ɕ J :lwFz'|eqke~;' @Up[~g4Nr1WgbC  FL} gp0پ%0 j Q0Ѱz:$ ]lOke4S1<ÑX_!lp ߮筲BW۪UG PP"R {$7HX:n-Vh WP~M=]܇%F@L|z3*X2g:!<8f Vw;?'t+NJ4f 6<d<]xZsc`:Gu^kBX_g+vl#>r\1L7NtvX;|Qy|{wvTi- jK==xמ3f}Aa3Mh,#\reZ6eT"ؓc~^Nf_?{{s +OrzP/FP}T3Bj3D[#`V}Ccԋ#1A#ZAUl6Si$ix0C`[\?&3;72j^hUU% gad"@:#N^GwaQ䃃j/2؋UM̶E!nl"UPb8kĆO} 4߿X0)Ze[#+M4:*_^*L˵qNcy{GԞH}Gʫ÷e:br *GJZ &\2(j` 1Al$-Y%rKvyPok:^g@{d?8)7=@Lb {bq~:mɷߣyv(4 X{ U9h:xd(*)mb)oGo)"H)TL.} l*h;`Octq|HV sKZO bj+~`m,YU$gɱjAz|u/)g{N}OMO~総,Y'߭#?vX,5sʂEOѿ( P +m b@$RY "^"3iyMjB@e_ 6"'`Z@6 0wCoШ FRX6j[ ;t}n!1a}"eheԊp ~ojK" Kc(FiX( Ww <1{NEfL.KNbW3d\)$]GrdMvY*DI5 c>C|遀-.(޻a1 HE ,JpWK%|}7iٴNOP OȚG8l9~6WH,I^@} F`Wd?^%6A"^ňԒ%Nq]"+my;b~u†Jk'2 + h6 0soTg?VG"#7 ټ_@TG?W ~ JJ+&L= :Q?U}% C Y`D@cD!ct mH&ReCVe+rH@D=Y6k 5$(wrC!r T'mʯP('』Ot;ߞl6u|G\A5c5ʋEl~bTˡONsٳFx=hES/ʈŝm obO)s* cޢ݆RTmeDy!{75| }7S*fI&`BsՌ[t{O8JUTP^ N6_}GE~E] 3~ &4R;օkTpns4~'HϬ0FyEm{8yנhЎ TQ_&}ZN<#2LB<^$ӳcUx0z?&g@>Cr4z3*!)ьJ)pUe6!9 9j6ywGy#,$EUzy|漮M*-$fGxFF&J-3=PNQtfŜki e;}/ئBct!7Y|O2Q٨G ~|SZD2IlO2dqVء?WHD؄ob%SM.4%|gl6븝;=Mvo[_s =.CXJ@b0#'xk&d'YKO>aaK=Wt}Wvⷓh@x.x^G㦿$1Ntҵ(&,@($1h jm![^]T͓=;'7֐  (cDJ@(._:mq1MBwo @3^^*~N M+'w'pbgD3`΍W@X#Ig2{o0]@U:!P A1g>'V_}qd܌:U'#:SŐY ߸z|HXFRj |skK#K'ڗsbhxNtBAqiS5'QrE/,f B@PR?ZXv( l@N344b Ȅ λ"Vo2Pswp%&62(>u?m LAٝ$ /[@E6u_*CB`HIǎJ+YJ0TF&wKiRi3J[UlSMCrǂճiSkdPM㮏蔐(&'#:xR<|G?M8O?N̤΃Q/-Ӓ6OZf|ʸ^d)gj+g: ϛfom_RWC;H*T<ßwnaQ$H}ԭCzĭ:V%-twGaWR,{RR{-m|)J|[ԇWSR# e vhwfUcS=vU'cO8V9YMV"앱ﺀ7ms?qFZ>Rgp|_{Th="u2cuȑEA&p3c4A@*Wѩ/QW,buPt@DU',u=?Ъ|}RxOD mb|wO}mHeM*5&ea)FSՃhKhŒN$e~]ϸ t=p 5ۼ e$);gxPp \|+-@m ՘& ̂ 7CoG޼ ҷЮjlIV"+4 : R(0 !aCx\E,Afs4~ksyF`bJ΂'("ŧg nTw/4'?|D*>5 Jx+CNrt"焾q^o1^WO,V5|ٹ>ͅ yIlzwvm$dǖpQHj&z ψ@9X+< D AM R(]0!_@lKP\ihO|yhK/~'u!`Ơ`;? ot;hl; w9 B#Yo(E` Xȭl Գ. ^:+43یN̏.f>qㄛGӯ;ߊ%+]ߣ h;E }N aWB?3NT9u~ 1#+sjq8J݊)dosh $6 vkc~TS=*,<=q&oly}jɀqͺ Pl @ ߁C|"-ĜĢw@`rG-j} r `#18nVV#C6Л@}n!?%H,WEIVUg|{vDv0Pïڠسbh[k-҄n`tfN^mvGlh-"rQ P ~&f}i`e y 2SMlsQ57Zlnbr䟻Lg3i@??n7;`;?+\$< p`?h$i:W4oW'樂 KP\X@EYv E~Ý Zr\taOSpV HKhH#L }  ]Лݯlvn#1x̫XKٵ@d$+Jbw;MYHyR1^0RDt)Fy`P\/ASwgO)yOL\.'Og|)b4oMS< +xQG!%ԩ^ OM@fIV[(kA7`1lUx˕ⲩ.lJ\ dڧ!O'-QIU(aM j8#٠?ف?gNJSCs*؊!t y PX k"\&0ba"8'G ] V1@0@PzD9R|T:ko~E)@s9-HpNc8/{ .q~K*LjQ&LlY=כ ɘR/.qww{Ʀh{>mTާ}x,!<_ygR~S &*LXG2Qq K_+p!hVwxzMc_~m+ZBU|m?tǀXP@&B"d -yy+:,~T1S ?,@q,fnVf t;#@8Ƴ1AP }C$+H!pW}]vN-4.@ڬLG~,*Dݘ߫Ɋ&g+֛8xl<9*u)Z@1 c08& b |LCl;A4?AKtZX[uuZ 2:j@#c;SLHaB9spt`Ңg3*f4۽=ϊAlX5B+kZ'P0p!lP' 5V(K^6.GdӷF)ϾzNV\z>q !v]ؽT@ҁrof uvP[nAy  _5bkmʑE^Vh$o*3 @Vc-(' wE ]cS=nc C+nA' ԁ4qd z4dMC=ʹ?=ә> 3 >zv 6'>ɡ  ǁ()*PT"j+χI7ARUW Lf FޓdgdVt逃MRQU /*D8R.!A# GaECxpyۍt-CY#:N';uVÄt8XC*] w<De0\S%aNSC9u fAC YtcRT4vv@]9'5ET?aUs'ŕ5 MY?d_F>n;θٝD2ʸww.aW>zW@\D'M# ^ A,!Ե qmn +d%s_Kfk:7O5V IrRD{rBX'cK/޵ێ.}o؜Er?~2na"1m*Ab:P0};ߋ#7@=K@n67{~ÐTFo7ߪ8yl@6ZR Ph0p2.F$" j{:UHd:Az1fS?Ul?\դz6@fplOJR@p:dbZ*/,9,LNٙ<x|?: vY6@ϊ o!r  wu@5kEPOc`,WW掹Zpy6h[#dXnK5C-]}&t({kb uY X_I/}/4=?cc`'E'QFrk5/E{O1Zqg8FO| onrĺmp% m瞁o}aC<68aϓ!*BlLPj@ʨ tW1"vsh7^j4pJI-򒃍9jAr>iq ,@J[h*{hv '!>8Il2 (Ƕ>+dX"[uÊUbM\ y) ҡ3A_\1+5on`E@0Pq)G=܈>!w1Yʗ{?ԗu)!S-j]/V^)㫌?R h:Tkj4t>0)px`4p1~E5E#!J'l?S;ܓ_4z‚P%3OxѺ[%(45k+¡@EZPi<3`: `",QD',#s+^u{p̂%$@aRE_0bESۓw98x_jgdp+ FBZrqǕp:8) zTZ؈U;z{djY #@`Y5KlD_.hqU?eTS5l6&@$Z)xGzᙢOtf =OVZ'm "Z D=GuKZT1 ^3P|ol艁Tʣɵ 'oN`Bx|O) H:HO'Hqik @,6_~Ǿ57IE:ZJ4(&r<轺d#htd_c02_7w}B+/ٵԧ7)8{>2:Df+77;Ŷh jx*xv=Sَ ݓ'>peRFtpJGZ۲+۟a,C"zbVۺX8q2Ui^ӎ&#I&Y2[1V5|kno1g|a俨,w,Zس-˳'ӧBlÎ*3 hS6_ͽso."[fIfZ-b t \x9 X#3TOpbGL q'OZU! \YOۿn ߏd  0yy<|>j2ˮ]85 l^z`gn4il[ hor{Qܵ=ak{ =3P22l\b/@g<#B8G Zݞ+L` h0s ,p&#M|$O?vJk5+a'|{Oi6o2+Iܔ"%. PQp @ ڂ-е@s0 ;* #9w:O^\D O6vH/,w=rHe d؜;{/hD]G?\.} '7Ofqˊ}veOB{ ZN`̧03 }ԩ40Ii׋U)hxU"` q-rRpјEdpF<-M_̦OgAd8.3)`:z)|^.Gb( [HM8wڒNCM`WmhL#uG`*OC (itIdSg=(+fzO PBٓEZn%8}k˂u#X8ۜ\&O %^:>&&UxXCTǣ0K\??4_(i9X0,b֑b+~܁FOߧO9MSPĢMG>6GKD',s I;Ͼh*"@%P Z 5?^|jVa 8*#k 0",yE ` Uh- },^X4y|-BV?>?p %xgww~,`(.W߽˕ra_{AOaIu%Pm'xuX%|wϸmv9c̞3G/7 g SEl8H \&Z^`k."j!⿾VqU@!xgo>T'0=vqp+ ֹֻAD@bPro\6EUR~ED8PṬ7+Y5_B|gꅍO EC'py0ľz@*3EB{ߙ/D u@%@[xjS 81  #1sXE떭B+.ar5d!C]s_;}oQž'V4 4֢4Bzaa%c|b@*"]ZS8J`K_V a\D/Wz%xt|5T}tY6.rABJ e+Up:1&L5HĦٿr4pCd{?8!.5(m!:N }m~mqJ9*Zp  @LDP"# N( _tt YS"!,*щ@)a\.i~5{R?w`ӗ8vEq:"׬6d^_vn"~~\˸2%[JA<"f!b b!xz^ظ LSN2}%&Oo˿5bw]č3{ a1^V sJ14iDU ů{CLn=o~ 'qH5 efk oK˜? o'RhP4 >?2I P#{ACHUֵ jda$YT qFSB@D) o׌e =<=p#IQz=tybƋE:Dfe/p :D(~L?kk  (Y_D jѬN7A* Q^@>fϬ=?N@p7V}vh˖pD,<;FK=<* 4((-s"ꉍ JҾB6xOBdfORuK"h/wn2(V 6 01pС10BK9 'A!ƒ}O^ñ=STR4țN 9AsD51Rb䔑3#gdChKʾ8ͧДO`irjǜW= :u5Yxs^ęSK.Mw*Z,rz "^ zCۍ^f9T%̠a \&" Cڽ%F;ֿH>` hY~7w/ ¿ :#L`R$Aё(6n;ݖzm 36mߛur>@{*W<?O|(O ^~ CpiobHU? *X}h[=d68ESkՙs̓~*6̈́G I7'U;Sz+ l`o%@<$,T=T%'k0H޾}c:ޕ:s/?{? v D#( gW2.hڛFc xĽsֆ'ٺh=s]RZz:<63U,X`E ,xu!Br ,VCr0g6:qXLpnA3 !)#iP,e3-8ʘf`ȱ4J55D0)ֿHoX"[x$B񟯁xua }rsIzv}D N N Y%N-$_ͻ|Tel!Ư!8Bh\:` ,.K+?A/_q(eo*&NZ=tHZp7 R M (  I%;z_G ivVނqb͸ +BZD狀MI*,1Nqq4o?l6-{MdiFFć|5_|{!6_`Ps!UEP,bu\,W}+b?8 _Tpj}J{&bjF,4?y-!&N=9*~ `@ k%4.Aq mX^+WW foGOt=X q+Ǻ{slDX]ٙ{Z K+ԋi-u." hFu,Wf ~Rv#ܟ{}K ܷJ7mg@]b h{1@;mH{Kgv׉ç7Z-Ootbu`Ev2i" l߆nL//z \aV'X]̡m?4؛ k4m|D vxi:e< $Jv(@+qLK X $ y VPD$(/h+U:\pT4%jg$Ad1"kk{ {Us8a \4Dž #If jj@^T(+E&M/yvI]+$1ϊ㓕,0tti/c47&"@.-KoW0hQbE*T Wk=?_G4iu<$vvp֎?"kK F_mP&\u_1սdrm/_\e&8r 3'O{hyYpxzO&j,$ z"rV@1"˄Mxx "c8ߧA9S5M.G-gpsN ԰r)x}qxg4gw8" HmQI9L /i~YT?hXIQ81eQ%рiQPUpEp3HN)}౟?mAD6άOf#xmʻ^>]"bl\M+n> $\=4c Q9G`}k5CڱaOz'=QaJ@d?ڭ{W$O MZб?SAvMxhX=7쬂~`DP@!.ł hhDg5fE8e YV`:ښ`Ci|ڦ^H缸 sJZpH!Y 23E-HAA:SfS̈`&%+&B#SQa J0On7;'&M6 ݺП c^eUu71I Rp Eh(0mCMo*">6Z xFQu`~ w?B=(w3PȤ_g5cXͥv@aE#JA,8*(蓠P3rM3/&#=>/ SwL7Au^R>׋bO) eF]` %BN#@\ XZ'ⷺ~E[A@!}: 5`?bv(IAYpz6=%GgfE䢤{^ڱY=n7[KgFFOrO 97B4J0O+mڅ㓭:LӠTp o z~iځUBO?ӐƼ$`w;ݷa?ie I.A]opUtH ){ݳɻ`PEPb]Kx^c4?Bh]K-aSܷm2F,l7wd!Kt0 U@-% YY'Z;vjړ@ C6 nw]wx힢 .TrzF<-o]&2qKqش}RtNݚ3W U yt7~LL?tNBO@΀UBJxԘe'$jr@on=зs_RW]E?Oߨ>x`feH{/gފN2ks0/~g11T83]1^չBUE/Җx-el`~=p=kޯZ0(ǹbG6%.o/UT\,2R͵⪱dٺ91bdr ԠF}眅p1s@@"PNB]y$W"ylчkԳ8r-B [и"YfcLFgZ"PJ[ wJ叱 Ru瞍0Pn nu&[0AAZ 4 C u=*X-Aw. rކ$LU8P*;n9}||U(?8l1M,bG@e#x}ˌ5kŪуTS*ΝFH_M7]&`K .W@GI Xl) oގ<PtG8B9Mq4 Ь +^B9T@ r"o͆m@;4:dpmw 0ihgXp&2 . 7/6nM [tӗC={ngSNu*]R+`f d 3#exYށ꾓I>vK}r`泻T?gs$XFaJ/ׄ~/Zc=u 97|dR#K-JG( eܦ b+0B&d2 Wo[Uo}c(PY5ty ] [@U9_ƹ4I׀?+Pi VgA  v?;G~}# XvlN Mh`˅ 6GjZriA7y;G=]}z%Ϫ4T6!(ɂyV4e a"X/N"HE1D}bb鹦$3-cEsDFzW(zT Z`@>(uV9} L0Q5!_C1&x9.zXsʲM٭&W$ePH i+JЏޫM /-{6x }VlR"c4>SZ`;splw`C?Bp cUgd HH 8yぃ{F":c}yO\`g.BB`kD mOxx8WOI$Sq*I7F`MYxiOsTzg-n̏[(Vc'0: PjR6zߥ'c_r~g̵1XKs)@I^ >:c4o<'܇z&|/^3^]d\ ZъB"JBY|WC9)LQh2 =lmE!EBMHXp`)|~}h?=0V'>?n}n l[ž7>D蓢K?Y|!ҩmd H4| |JPe(E`t#4G 'xT so?-n -8uԺ 7$d^?w`+P%7=HC.nTp^2.Ma;={޿G%,B2A9T"b+ڎ$ H&VLP )?@2$φp)~OJ6AAno",X'x+\xËh4\mv;N]R)4Ƽr_ 4DcAҤBroZ3`Ac6C/oM/ONEt+'_U@?wlon J{gȽe? S&Gc+80!`5cP,h袢 aH"\9G<N=uę!:9 S(`&m#}O'6&@n@5<:<s):rX ȩsB@Ef" ^,rT{M%2 nj}ksGׇNG;?mh:?J{xYԽauUD+ zR`h{@\Bݏ*}7Oc__DZ}U$Gp{d2*ANе%"\%$rxĽ8Z@>nw]܋hdrJ)AW~ O. Hՙ ]FS;8 9@$ 2)4 2X3ض#Gt>CupkzI2p3ۭŔϾd$-׏D2X.USZֳͥ \0Ω Bz@{3{hѬ\N'X~:Oŀ:7=) $bc N5a;3OfO׏(P%62k&n9陆vjD9,+NYǛ3-H0` E`$\4W}kWkC7{ZiFo6Rn9_'JشVbh0\cԯߙCEGlA:Bj@[@ ,a+YK rp3<@/ cL2?lgdoPE͘X\ޙrU:v16cD!(#`[~/B(I 0Io%R ~ <@ H ED [>59]U2X{WSgf}{߽{nY{X#6yBár= qҒֽ_d@kUx3rޮFY30A䛩W"O)5DoJM6 ;zqc cEg7ez\3,$LdPVGG.4Ǟd|i`Jq ȅx }AIJ{R PD5v=+=|DRw%V@082e +%fP "z>?o>@[3Y`ls2g{]k3[4ښg{}rsY31%!ehj1) RjqfNtpԮIghqۓKu60QvTτņeA&EEc'|GO^e X0>B?8u6w8)e&R&G[là"-  3p E (@F \M.;0\ B$ssjE A0].DSe!"q!RSr[A'[ R4Y`oDG{H@s'%ˤ:]}j2q=p`\g &1e'QF" @&8pB)e@Q B(]D! ڈLPrh?h G``=v]×<>pNT,iKS-_;wiAZ_ N e <LM?8l?ɴ.]=CZXT8nQ;6!Z ; g;t@^9T+p5ay^bb\D6 ?.5lQZ^lLvDBUǏAFCmP2pRd M ؅_P :@iw~ynW]xw8)V7LVf"X#96l^%M<^u.5`isN1KNEc`Cva-]h,|s7V糼IE=qp"s  [~Ycw!Xͨ_\4DwN*('`a}g/' X_!̏07Oi׊/l&l^!5)qY  [\:P#Kb#j|k`:K`Y%-fqDe45%&t~}kE>|0jhNJF x!7 UG[* :EnW/7NnYy1xKƬiePV@}=|yBֿZx$I@r :>|n|TN¦_SPssAh*d.|}kuKR41Zt PR`uNC(O|E:rGE>} |ii~`ƀXj4|)hFr/B; :cA7̭!@k_pLK>ILLD \2%fcp"۹rqX2b@9U/;`/!~Jb7 2^տ+q @(\޴Z|0!ᔰ?6vc3uXImy")%n$֋΁ѭd:?iH9tn%6&7CAhq$"@6(rdG3< ʱz(u]V<j}Nzpt8Y(@`A3 `إPdRE@DE }!M?F|-v@iɍ O>\ⳏ1c7Yח}]utPًȍc|0ǎ1пI w[&~4|0Z ɦoE!`E+K< wKoR5ɇ ȍ@ր\FW" *?t *`\V>aæ[0(va ]CW<0ai3eiZPKl=ƌ2x(ׄܿ Cў Weg&K@nGuP01ȂH 8|?%0Ccz,m~7#)30Ri,}⎁rLSLBr74APĐTG u9P CPVO$8P(?!e0]`xI)9.td(:Qtt?<[b97SI,еAVR60`=yL:`)7}ܝiu~h0-u*F'o @Lf4UȨsePV^D{.VW8 !LgQ2w2o fn釟 }lGULc O5IF9N ge䟇DIi?57o J !6TA&>BӸ,Ri#:cix;v?[ܒ]/ :αf^ Ѿ0hZ– %툱@//Q\ˇ]oe8)ehu 8'\H~6>nP9n}޻*tjCѣctd ) ̤@C(efkE$[:pbqgF@c0_5}ŵ93d$ _ jncgYıǞJd(&v93;oG7w@(`T[U258`\{56T]i֐2Μ*͋4;!#6͆BVNiNjų~~,}o ͱUcyB\5s׍[ԉ*l:aoZ;`t/ܞjo?V@U20dqȭAf|Dd|N$GdysH%/V^P)s>=>FQ9םlޣæ |(.*; =+-~&llΆlI-|O^{XωŀQQ Ӻ3\ʁ'2S;#ѻw0 @R O4OeMJl5MCIqȍIR a'&zp'88p9|ǛhΨx^{M,"CR=twñ+C~d7F[8?D!>–:],tgYQxBфi:=, H<ѻhpRh ISw@icC),i">A{8Ed}rQ;7 n^S{?mij[Eȉ߇ B ŜV?鴶@MT :a"gוKP'm!ko\ jRP۴}}@hM2!2 z%)*h1_ x0Vכ.&hĽ$M"|8/N1EgcBB cŀ?!//=/An?*H&1VscsӽS)۷I.ѡ4bױ׾5Bvګ>B`(`y1y|0H_36 B@p 50`cGNqK{<Lp(YTpch#Y.d+rߗC>F"!?v՟C>߫OPLJNA,(}@o Pz,e;lv\_ytAX4;Yކ)ND{#)<8eA("grؓ4] hՆԜIKZdHwA5݌`_1C!O1بtމ(4g=Jq֭Ȉ8x.*aC &$=%-duM,Tw{\;Q8d.$J =ǎ( 遒N@T|;ˎ=io3m»i "`(2 Y倵b/6WC 䔖W00&Y+B@@@1én4s7r=& RȉRin^y~'%nm4 `i:Js l {y>-ؕFuzfvd!>lBQ cɉ#=UĝqZ1Ja@j4]i@l0BKO㸮VӵJ?="d C US&-}`p2//6ob^}ߒ]H$xbo~Z'ΧܞI^yƾ)4pB9K}:ut'F=, /(.:s6߂yQ N(֓ )~H8pw/of.}M(~e|:v`_dUVz# ǟ@wi /c_>OJ` .bixj"p&c*7~oϥکքvk`HSM`K 8/1nkvRFB7'!FcP]8X O_"-( 9:vR6 ;cv*¼q}PtgFl82v%W e!%qꮚSɟ7ѢTm-Wxm 4@Ֆ !: SqK>l%GXQLK~vzF'hPP dkCBa2P#*6'"X ( (bB9JRwnrO:ff-6f)J7N#g,LodXqѩX), }˜bE2bsyNmo9#mh"ɤNCekk>*Lr#ˤj :~̎P͉?\o{jdž6;s*/v:f6=˅/ε*[ ?/n&f2 d\l8vA>x#<\jTcRq B{6T L K0[ ;8޵Aݴ%6۝ץ6uf }4@tp˦,z +_ǥ[z-ྒྷTH"6Kk8"[ G۱E{ {2 oK%۹5E9Q.-~^ƓTMaf#p95AQ1ND *B>E۳yflJnvg]vJwlW/3ۼ/?;i4 ְ'7 ߓTA.$`||r <>3I2h?H^ 8#pF{ߟٚ^XKml^th@){xx[I! P 9r-drp5 ˀsnkb=,EU̥:R8aVkλ;(%@E9u!%@ ?&~:@90OmT'ݘX7c,l뺢l)X 2D2Z>h #DSv| fg/gWs sNqN}6 i EB"\O-.L^Vdme0;/OG0#<ʇ"/*/LPsk`.$eK=36w+1 pX3@SgqtvA$Kka /~=yj /~ %?O GLdBOf ĺ%umoO2zeऱ?UkDw3WyCUf'ɡQ1&Gd8*ڿ+SҰkW ywNٮ@KUNl8f)}=Ȋ0A΁m P'& r؁;/׎AP=@tv˴\T@. #ת@2#ƶ')<{5*8-? pl?$C[P"q~&"l әBCdԂA .f&.0  uI/sB?ճzwP. EO )[`PW!K']/ŁJern09݁BC'@lzi-k c`l)e{$)lhwZ.L"d2ʆK3 d3=,SlN}w֭zPo(BU L ̀,G5.=0`F`r#wr??Uyrv:ku}Qf= ilH"`,1c:'2߄0$-?lyuկ,"R1 HN. dˈq%PaGøR xL; lT臒M?B@mOuq9=\(H&2 93@>f:/1ȰMߒOǢW +)=m*ʩ{8VL @WevvnIF3 '#M'7q#?כ|lmjz9nz6Z&[N.xW=NJeZ7s!L9ONKX6v @-K̝:ʶd+ "Ye[BF&(|ü pz\ #on6d9v/}tΜC's飙q#Di{߯nl K^Ӛ:YE's۴49D(s\: B@ʶ(韨$x.4WeT `w9fNr'c?v=|GG7E9uo:K.4E\v o (`nO0',+ C+)*%: j( zqRUx,? enʝ!9RhֿG}m} KZ'>^XYt~޽okdRz)\rt #]xT'^Y7E9>իg>SwXt fZ}k8b0MQo+'g (׿uX+̌t&?{=xݢ(ݝ>nr>>K_R{9|J 0~7jWOyTQ}|Fe>ok[ W_mD<ַ=}(ʽpκw>^7~E{{{x#_s^S 2~wӺp\BuWc⩧j}wFJFO_ y&|Iy^xfEQe7o~W^m}o2g?ZJ'2.C=|+udt:ůkīå킊(rr \O?4>a8={xwW浯?8/,EQe^~z]+7 W_h43<}((kl6OS;+V e<W^AvQEQ?p|կ~u|^'|' *EQes^uKW`{{{ȲLi(ʇNUUF+!{V2"Gtt7o;NQEQ.z'ɲL>EQe >,bCQEQkmi,PEQ!˲yC/(lo~BQEQ(~i?Ox₩CQEQloLYR((PUŐ/p8:EQEvvv^{2\_%QEQͧ(#N,{?ˢ(( 3'0pc^EQE\1~_QEQͥ):}+_%3mD(q_Igy1PEQea?M`⋿}N(A?~X@:9Wr)(F_t8?c f(֔?{nuaK/O}m(0tM^y_=g*(ʚ~~ON<EQEY~w=Ȟ,//x≷<^QEQ?я~oO{O>g((+~IߜY_| EQEQ>|,Y7\4s]fw^wEQEv聆{ϙ=PEQ]4*O*/ ?uO}QEQ{ qO~{w_3h?hXR+_IENDB`alacritty-0.13.2/extra/logo/compat/alacritty-term+scanlines.svg000064400000000000000000000752141046102023000227170ustar 00000000000000 image/svg+xml alacritty-0.13.2/extra/logo/compat/alacritty-term.png000064400000000000000000000070341046102023000207240ustar 00000000000000PNG  IHDR@@gAMA a cHRMz&u0`:pQ<bKGDC pHYs``kB IDATx\[PSWNIB\E^jZj[b/mgT2;>S_ڇZDZNEU(\ v4$ $|/ vY{^{@qqTj\@R *&C?Q팯\Z%ly3vO_(پy35چ|%П`PhԐH]}ty9n|]\ypy TA1|@x2k\ P*SI4&N[`_E=^P):x?( |{ԿNZh6o^ G[Y[Y[LF?񯶲s<)SfEa mQ005(jWXPiwpKeEE55m液vt[z{))fK㎜p88"h"T*J%yi|u:2߻뛕+#-pl:ΦcX]P,˲+L^cyX0d2t:#-~ r9jZmzzWllllll ((((((^rMMMMMM4qy#*p02 pͦRr%i73S& ~6rmfA0(/:Ri(+}{L?I8>|:B9_ee]B\jlmu8 ڵPV  DӀSU qJ%qFc{@( #QXHLZeopN"ȑA  v|rE&:/:ng4j4Ų# aF&Q.Qp@F#^JIFсI*+M#A="n#y?jՆ [+WVU{޻'ČpL }ӧGcO9kj׭jj**JKw:8~Lbۭ1lȮN)(-mxHKS*=@\[(̜7/7XzXЬ /_[Mk7%ȹz5;҈yaCNq6=!|lV*mܸeGtx_Y[_vf#89z*SAO3f(.J_]^(ݣظqŊ ),\`"-{vwXȝHL,b~ 5gG̲4 ([zV ==11Tªw矉 vgΌ'9 I$d{gF<|RuoQ\,ڵoYR_Χ?'=bkS/O>4LDGKf~s'PGQ :J݁_ge-Z_oϞx(blDX&+k"°mMl0w.q{{f q啕1+~4n'ǎz,~?^]*N{79Y6o]ݍ~͜RMdP3SM \QCCr9}}cq}!Ϝ1+O@w7ҡӧs={޽Du%!AX^_UUMDP31͛gQmmZ-qecJ[Odz ~ꔰ'(/?lr f9s6)?ǯV#߼)=xp!…~mo'ERv;Mww?ta6$[~6kߨ7.^L։[a7j̉\e=@"} ^:D(_.ܺEF>yNx(_Nw;:jJSR=5eŋCY髫kiy{!nд^Hӝgr=G/k)\b ^… _}!@IN& #&>&M`ŗΤ$b˅R%%y@qyFش7BE2'iiʕ@彽W>>>-y,q+˖s*y3tݼOFRx@}}EMkg߾t'K7L_ew;tZoodo#oǑ{ image/svg+xml alacritty-0.13.2/extra/man/alacritty-bindings.5.scd000064400000000000000000000172321046102023000202330ustar 00000000000000ALACRITTY-BINDINGS(5) # NAME Alacritty Bindings - Default configuration file bindings. # SYNOPSIS This page documents all key and mouse bindings for the default Alacritty configuration. See *alacritty*(5) for full configuration format documentation. # MOUSE BINDINGS [[ *mouse* :[ *mods* :[ *action* | _"Right"_ :[ : _"ExpandSelection"_ | _"Right"_ : _"Control"_ : _"ExpandSelection"_ | _"Middle"_ : _"~Vi"_ : _"PasteSelection"_ # KEY BINDINGS [[ *key* :[ *mods* :[ *mode* :[ *action* / *chars* | _"Paste"_ :[ :[ : _"Paste"_ | _"Copy"_ :[ :[ : _"Copy"_ | _"L"_ : _"Control"_ :[ : _"ClearLogNotice"_ | _"Paste"_ :[ : _"Vi|Search"_ : _"Paste"_ | _"L"_ : _"Control"_ : _"~Vi|~Search"_ : *chars*: _"\\u000c"_ | _"PageUp"_ : _"Shift"_ : _"~Alt"_ : _"ScrollPageUp"_ | _"PageDown"_ : _"Shift"_ : _"~Alt"_ : _"ScrollPageDown"_ | _"Home"_ : _"Shift"_ : _"~Alt"_ : _"ScrollToTop"_ | _"End"_ : _"Shift"_ : _"~Alt"_ : _"ScrollToBottom"_ ## Vi Mode [[ *key* :[ *mods* :[ *mode* :[ *action* | _"Space"_ : _"Shift|Control"_ : _"~Search"_ : _"ToggleViMode"_ | _"Space"_ : _"Shift|Control"_ : _"Vi|~Search"_ : _"ScrollToBottom"_ | _"Escape"_ :[ : _"Vi|~Search"_ : _"ClearSelection"_ | _"I"_ :[ : _"Vi|~Search"_ : _"ToggleViMode"_ | _"I"_ :[ : _"Vi|~Search"_ : _"ScrollToBottom"_ | _"C"_ : _"Control"_ : _"Vi|~Search"_ : _"ToggleViMode"_ | _"Y"_ : _"Control"_ : _"Vi|~Search"_ : _"ScrollLineUp"_ | _"E"_ : _"Control"_ : _"Vi|~Search"_ : _"ScrollLineDown"_ | _"G"_ :[ : _"Vi|~Search"_ : _"ScrollToTop"_ | _"G"_ : _"Shift"_ : _"Vi|~Search"_ : _"ScrollToBottom"_ | _"B"_ : _"Control"_ : _"Vi|~Search"_ : _"ScrollPageUp"_ | _"F"_ : _"Control"_ : _"Vi|~Search"_ : _"ScrollPageDown"_ | _"U"_ : _"Control"_ : _"Vi|~Search"_ : _"ScrollHalfPageUp"_ | _"D"_ : _"Control"_ : _"Vi|~Search"_ : _"ScrollHalfPageDown"_ | _"Y"_ :[ : _"Vi|~Search"_ : _"Copy"_ | _"Y"_ :[ : _"Vi|~Search"_ : _"ClearSelection"_ | _"Copy"_ :[ : _"Vi|~Search"_ : _"ClearSelection"_ | _"V"_ :[ : _"Vi|~Search"_ : _"ToggleNormalSelection"_ | _"V"_ : _"Shift"_ : _"Vi|~Search"_ : _"ToggleLineSelection"_ | _"V"_ : _"Control"_ : _"Vi|~Search"_ : _"ToggleBlockSelection"_ | _"V"_ : _"Alt"_ : _"Vi|~Search"_ : _"ToggleSemanticSelection"_ | _"Enter"_ :[ : _"Vi|~Search"_ : _"Open"_ | _"Z"_ :[ : _"Vi|~Search"_ : _"CenterAroundViCursor"_ | _"F"_ :[ : _"Vi|~Search"_ : _"InlineSearchForward"_ | _"F"_ : _"Shift"_ : _"Vi|~Search"_ : _"InlineSearchBackward"_ | _"T"_ :[ : _"Vi|~Search"_ : _"InlineSearchForwardShort"_ | _"T"_ : _"Shift"_ : _"Vi|~Search"_ : _"InlineSearchBackwardShort"_ | _";"_ :[ : _"Vi|~Search"_ : _"InlineSearchNext"_ | _","_ :[ : _"Vi|~Search"_ : _"InlineSearchPrevious"_ | _"K"_ :[ : _"Vi|~Search"_ : _"Up"_ | _"J"_ :[ : _"Vi|~Search"_ : _"Down"_ | _"H"_ :[ : _"Vi|~Search"_ : _"Left"_ | _"L"_ :[ : _"Vi|~Search"_ : _"Right"_ | _"ArrowUp"_ :[ : _"Vi|~Search"_ : _"Up"_ | _"ArrowDown"_ :[ : _"Vi|~Search"_ : _"Down"_ | _"ArrowLeft"_ :[ : _"Vi|~Search"_ : _"Left"_ | _"ArrowRight"_ :[ : _"Vi|~Search"_ : _"Right"_ | _"0"_ :[ : _"Vi|~Search"_ : _"First"_ | _"$"_ : _"Shift"_ : _"Vi|~Search"_ : _"Last"_ | _"Home"_ :[ : _"Vi|~Search"_ : _"First"_ | _"End"_ :[ : _"Vi|~Search"_ : _"Last"_ | _"^"_ : _"Shift"_ : _"Vi|~Search"_ : _"FirstOccupied"_ | _"H"_ : _"Shift"_ : _"Vi|~Search"_ : _"High"_ | _"M"_ : _"Shift"_ : _"Vi|~Search"_ : _"Middle"_ | _"L"_ : _"Shift"_ : _"Vi|~Search"_ : _"Low"_ | _"B"_ :[ : _"Vi|~Search"_ : _"SemanticLeft"_ | _"W"_ :[ : _"Vi|~Search"_ : _"SemanticRight"_ | _"E"_ :[ : _"Vi|~Search"_ : _"SemanticRightEnd"_ | _"B"_ : _"Shift"_ : _"Vi|~Search"_ : _"WordLeft"_ | _"W"_ : _"Shift"_ : _"Vi|~Search"_ : _"WordRight"_ | _"E"_ : _"Shift"_ : _"Vi|~Search"_ : _"WordRightEnd"_ | _"%"_ : _"Shift"_ : _"Vi|~Search"_ : _"Bracket"_ | _"/"_ :[ : _"Vi|~Search"_ : _"SearchForward"_ | _"?"_ : _"Shift"_ : _"Vi|~Search"_ : _"SearchBackward"_ | _"N"_ :[ : _"Vi|~Search"_ : _"SearchNext"_ | _"N"_ : _"Shift"_ : _"Vi|~Search"_ : _"SearchPrevious"_ ## Search Mode [[ *key* :[ *mods* :[ *mode* :[ *action* | _"Enter"_ :[ : _"Search|Vi"_ : _"SearchConfirm"_ | _"Escape"_ :[ : _"Search"_ : _"SearchCancel"_ | _"C"_ : _"Control"_ : _"Search"_ : _"SearchCancel"_ | _"U"_ : _"Control"_ : _"Search"_ : _"SearchClear"_ | _"W"_ : _"Control"_ : _"Search"_ : _"SearchDeleteWord"_ | _"P"_ : _"Control"_ : _"Search"_ : _"SearchHistoryPrevious"_ | _"N"_ : _"Control"_ : _"Search"_ : _"SearchHistoryNext"_ | _"ArrowUp"_ :[ : _"Search"_ : _"SearchHistoryPrevious"_ | _"ArrowDown"_ :[ : _"Search"_ : _"SearchHistoryNext"_ | _"Enter"_ :[ : _"Search|~Vi"_ : _"SearchFocusNext"_ ## Windows, Linux, and BSD only [[ *key* :[ *mods* :[ *mode* :[ *action* | _"V"_ : _"Control|Shift"_ : _"~Vi"_ : _"Paste"_ | _"V"_ : _"Control|Shift"_ : _"Vi|Search"_ : _"Paste"_ | _"C"_ : _"Control|Shift"_ :[ : _"Copy"_ | _"F"_ : _"Control|Shift"_ : _"~Search"_ : _"SearchForward"_ | _"B"_ : _"Control|Shift"_ : _"~Search"_ : _"SearchBackward"_ | _"C"_ : _"Control|Shift"_ : _"Vi|~Search"_ : _"ClearSelection"_ | _"Insert"_ : _"Shift"_ :[ : _"PasteSelection"_ | _"0"_ : _"Control"_ :[ : _"ResetFontSize"_ | _"="_ : _"Control"_ :[ : _"IncreaseFontSize"_ | _"+"_ : _"Control"_ :[ : _"IncreaseFontSize"_ | _"NumpadAdd"_ : _"Control"_ :[ : _"IncreaseFontSize"_ | _"-"_ : _"Control"_ :[ : _"DecreaseFontSize"_ | _"NumpadSubtract"_ : _"Control"_ :[ : _"DecreaseFontSize"_ ## Windows only [[ *key* :[ *mods* :[ *mode* :[ *action* | _"Enter"_ : _"Alt"_ :[ : _"ToggleFullscreen"_ ## macOS only [[ *key* :[ *mods* :[ *mode* :[ *action* / *chars* | _"K"_ : _"Command"_ : _"~Vi|~Search"_ : *chars*: _"\\u000c"_ | _"K"_ : _"Command"_ : _"~Vi|~Search"_ : _"ClearHistory"_ | _"0"_ : _"Command"_ :[ : _"ResetFontSize"_ | _"="_ : _"Command"_ :[ : _"IncreaseFontSize"_ | _"+"_ : _"Command"_ :[ : _"IncreaseFontSize"_ | _"NumpadAdd"_ : _"Command"_ :[ : _"IncreaseFontSize"_ | _"-"_ : _"Command"_ :[ : _"DecreaseFontSize"_ | _"NumpadSubtract"_ : _"Command"_ :[ : _"DecreaseFontSize"_ | _"V"_ : _"Command"_ : _"~Vi"_ : _"Paste"_ | _"V"_ : _"Command"_ : _"Vi|Search"_ : _"Paste"_ | _"C"_ : _"Command"_ :[ : _"Copy"_ | _"C"_ : _"Command"_ : _"Vi|~Search"_ : _"ClearSelection"_ | _"H"_ : _"Command"_ :[ : _"Hide"_ | _"H"_ : _"Command|Alt"_ :[ : _"HideOtherApplications"_ | _"M"_ : _"Command"_ :[ : _"Minimize"_ | _"Q"_ : _"Command"_ :[ : _"Quit"_ | _"W"_ : _"Command"_ :[ : _"Quit"_ | _"N"_ : _"Command"_ :[ : _"CreateNewWindow"_ | _"T"_ : _"Command"_ :[ : _"CreateNewTab"_ | _"F"_ : _"Command|Control"_ :[ : _"ToggleFullscreen"_ | _"F"_ : _"Command"_ : _"~Search"_ : _"SearchForward"_ | _"B"_ : _"Command"_ : _"~Search"_ : _"SearchBackward"_ | _"]"_ : _"Command|Shift"_ :[ : _"SelectNextTab"_ | _"["_ : _"Command|Shift"_ :[ : _"SelectPreviousTab"_ | _"Tab"_ : _"Command"_ :[ : _"SelectNextTab"_ | _"Tab"_ : _"Command|Shift"_ :[ : _"SelectPreviousTab"_ | _"1"_ : _"Command"_ :[ : _"SelectTab1"_ | _"2"_ : _"Command"_ :[ : _"SelectTab2"_ | _"3"_ : _"Command"_ :[ : _"SelectTab3"_ | _"4"_ : _"Command"_ :[ : _"SelectTab4"_ | _"5"_ : _"Command"_ :[ : _"SelectTab5"_ | _"6"_ : _"Command"_ :[ : _"SelectTab6"_ | _"7"_ : _"Command"_ :[ : _"SelectTab7"_ | _"8"_ : _"Command"_ :[ : _"SelectTab8"_ | _"9"_ : _"Command"_ :[ : _"SelectLastTab"_ # SEE ALSO *alacritty*(1), *alacritty-msg*(1), *alacritty*(5) # BUGS Found a bug? Please report it at _https://github.com/alacritty/alacritty/issues_. # MAINTAINERS - Christian Duerr - Kirill Chibisov alacritty-0.13.2/extra/man/alacritty-msg.1.scd000064400000000000000000000032301046102023000172110ustar 00000000000000ALACRITTY-MSG(1) # NAME alacritty-msg - Send messages to Alacritty. # SYNOPSIS This command communicates with running Alacritty instances through a socket, making it possible to control Alacritty without directly accessing it. # OPTIONS *-s, --socket* __ Path for IPC socket communication. # MESSAGES *create-window* Create a new window in the same Alacritty process. *FLAGS* *--hold* Remain open after child process exits. *OPTIONS* *--working-directory* __ Start the shell in the specified working directory. *-T, --title* __ Defines the window title. Default: _Alacritty_ *--class* _<GENERAL>_ | _<GENERAL>_,_<INSTANCE>_ Defines window class/app_id on X11/Wayland. Default: _Alacritty,Alacritty_ *-o, --option* _<OPTION>..._ Override configuration file options. Example: _alacritty msg create-window -o 'cursor.style="Beam"'_ *-e, --command* _<COMMAND>..._ Command and args to execute (must be last argument). *config* Update the Alacritty configuration. *ARGS* *<CONFIG_OPTIONS>...* Configuration file options. Example: _alacritty msg config 'cursor.style="Beam"'_ *FLAGS* *-r, --reset* Clear all runtime configuration changes. *OPTIONS* *-w, --window-id* _<WINDOW_ID>_ Window ID for the new config. Use _-1_ to apply this change to all windows. Default: _$ALACRITTY_WINDOW_ID_ # SEE ALSO *alacritty*(1), *alacritty*(5), *alacritty-bindings*(5) # BUGS Found a bug? Please report it at _https://github.com/alacritty/alacritty/issues_. # MAINTAINERS - Christian Duerr <contact@christianduerr.com> - Kirill Chibisov <contact@kchibisov.com> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/extra/man/alacritty.1.scd����������������������������������������������������������0000644�0000000�0000000�00000005224�10461020230�0016432�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ALACRITTY(1) # NAME Alacritty - A fast, cross-platform, OpenGL terminal emulator. # SYNOPSIS Alacritty is a modern terminal emulator that comes with sensible defaults, but allows for extensive configuration. By integrating with other applications, rather than reimplementing their functionality, it manages to provide a flexible set of features with high performance. # FLAGS *-h, --help* Prints help information. *--hold* Remain open after child process exits. *--print-events* Print all events to STDOUT. *-q* Reduces the level of verbosity (the min level is *-qq*). *--ref-test* Generates ref test *-v* Increases the level of verbosity (the max level is *-vvv*). *-V, --version* Prints version information. # OPTIONS *--class* _<GENERAL>_ | _<GENERAL>_,_<INSTANCE>_ Defines the window class hint on Linux. When only the general class is passed, instance will be set to the same value. On Wayland the general class sets the _app\_id_, while the instance class is ignored. Default: _Alacritty,Alacritty_ *-e, --command* _<COMMAND>..._ Command and args to execute (must be last argument). *--config-file* _<CONFIG_FILE>_ Specify alternative configuration file. Alacritty looks for the configuration file at the following paths: . _$XDG_CONFIG_HOME/alacritty/alacritty.toml_ . _$XDG_CONFIG_HOME/alacritty.toml_ . _$HOME/.config/alacritty/alacritty.toml_ . _$HOME/.alacritty.toml_ On Windows, the configuration file is located at _%APPDATA%\\alacritty\\alacritty.toml_. *--embed* _<PARENT>_ X11 window ID to embed Alacritty within (decimal or hexadecimal with _0x_ prefix). *-o, --option* _<OPTION>..._ Override configuration file options. Example: _alacritty -o 'cursor.style="Beam"'_ *--socket* _<SOCKET>_ Path for IPC socket creation. *-T, --title* _<TITLE>_ Defines the window title. Default: _Alacritty_ *--working-directory* _<WORKING_DIRECTORY>_ Start the shell in the specified working directory. # SUBCOMMANDS *msg* Send IPC socket messages (see *alacritty-msg*(1)). *migrate* Migrate the configuration file. *-c, --config-file* _<CONFIG_FILE>_ Path to the configuration file. *-d, --dry-run* Only output TOML config to STDOUT. *-i, --skip-imports* Do not recurse over imports. *--skip-renames* Do not move renamed fields to their new location. *-s, --silent* Do not output to STDOUT. *-h, --help* Print help information. # SEE ALSO *alacritty-msg*(1), *alacritty*(5), *alacritty-bindings*(5) # BUGS Found a bug? Please report it at _https://github.com/alacritty/alacritty/issues_. # MAINTAINERS - Christian Duerr <contact@christianduerr.com> - Kirill Chibisov <contact@kchibisov.com> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/extra/man/alacritty.5.scd����������������������������������������������������������0000644�0000000�0000000�00000066045�10461020230�0016446�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ALACRITTY(5) # NAME Alacritty - TOML configuration file format. # SYNTAX Alacritty's configuration file uses the TOML format. The format's specification can be found at _https://toml.io/en/v1.0.0_. # GENERAL This section documents the root level of the configuration file. *import* = [_"<string>"_,] Import additional configuration files. Imports are loaded in order, skipping all missing files, with the importing file being loaded last. If a field is already present in a previous import, it will be replaced. All imports must either be absolute paths starting with _/_, or paths relative to the user's home directory starting with _~/_. Example: import = [++ _"~/.config/alacritty/base16-dark.toml"_,++ _"~/.config/alacritty/keybindings.toml"_,++ ] *shell* = _"<string>"_ | { program = _"<string>"_, args = [_"<string>"_,] } You can set _shell.program_ to the path of your favorite shell, e.g. _/bin/zsh_. Entries in _shell.args_ are passed as arguments to the shell. Default: Linux/BSD/macOS: _$SHELL_ or the user's login shell, if _$SHELL_ is unset++ Windows: _"powershell"_ Example: *[shell]*++ program = _"/bin/zsh"_++ args = [_"-l"_] *working_directory* = _"<string>"_ | _"None"_ Directory the shell is started in. When this is unset, or _"None"_, the working directory of the parent process will be used. Default: _"None"_ *live_config_reload* = _true_ | _false_ Live config reload (changes require restart) Default: _true_ *ipc_socket* = _true_ | _false_ # _(unix only)_ Offer IPC using _alacritty msg_ Default: _true_ # ENV All key-value pairs in the *[env]* section will be added as environment variables for any process spawned by Alacritty, including its shell. Some entries may override variables set by alacritty itself. Example: *[env]*++ WINIT_X11_SCALE_FACTOR = _"1.0"_ # WINDOW This section documents the *[window]* table of the configuration file. *dimensions* = { columns = _<integer>_, lines = _<integer>_ } Window dimensions (changes require restart). Number of lines/columns (not pixels) in the terminal. Both lines and columns must be non-zero for this to take effect. The number of columns must be at least _2_, while using a value of _0_ for columns and lines will fall back to the window manager's recommended size Default: { columns = _0_, lines = _0_ } *position* = _"None"_ | { x = _<integer>_, y = _<integer>_ } Window startup position. Specified in number of pixels. If the position is _"None"_, the window manager will handle placement. Default: _"None"_ *padding* = { x = _<integer>_, y = _<integer>_ } Blank space added around the window in pixels. This padding is scaled by DPI and the specified value is always added at both opposing sides. Default: { x = _0_, y = _0_ } *dynamic_padding* = _true_ | _false_ Spread additional padding evenly around the terminal content. Default: _false_ *decorations* = _"Full"_ | _"None"_ | _"Transparent"_ | _"Buttonless"_ Window decorations. *Full* Borders and title bar. *None* Neither borders nor title bar. *Transparent* _(macOS only)_ Title bar, transparent background and title bar buttons. *Buttonless* _(macOS only)_ Title bar, transparent background and no title bar buttons. Default: _"Full"_ *opacity* = _<float>_ Background opacity as a floating point number from _0.0_ to _1.0_. The value _0.0_ is completely transparent and _1.0_ is opaque. Default: _1.0_ *blur* = _true_ | _false_ # _(works on macOS/KDE Wayland)_ Request compositor to blur content behind transparent windows. Default: _false_ *startup_mode* = _"Windowed"_ | _"Maximized"_ | _"Fullscreen"_ | _"SimpleFullscreen"_ Startup mode (changes require restart) *Windowed* Regular window. *Maximized* The window will be maximized on startup. *Fullscreen* The window will be fullscreened on startup. *SimpleFullscreen* _(macOS only)_ Same as _Fullscreen_, but you can stack windows on top. Default: _"Windowed"_ *title* = _"<string>"_ Window title. Default: _"Alacritty"_ *dynamic_title* = _true_ | _false_ Allow terminal applications to change Alacritty's window title. Default: _true_ *class* = { instance = _"<string>"_, general = _"<string>"_ } # _(Linux/BSD only)_ Window class. On Wayland, *general* is used as _app\_id_ and *instance* is ignored. Default: { instance = _"Alacritty"_, general = _"Alacritty"_ } *decorations_theme_variant* = _"Dark"_ | _"Light"_ | _"None"_ Override the variant of the System theme/GTK theme/Wayland client side decorations. Set this to _"None"_ to use the system's default theme variant. Default: _"None"_ *resize_increments* = _true_ | _false_ Prefer resizing window by discrete steps equal to cell dimensions. Default: _false_ *option_as_alt* = _"OnlyLeft"_ | _"OnlyRight"_ | _"Both"_ | _"None"_ # _(macos only)_ Make _Option_ key behave as _Alt_. Default: _"None"_ Example: *[window]*++ padding = { x = _3_, y = _3_ }++ dynamic_padding = _true_++ opacity = _0.9_ # SCROLLING This section documents the *[scrolling]* table of the configuration file. *history* = _<integer>_ Maximum number of lines in the scrollback buffer.++ Specifying _0_ will disable scrolling.++ Limited to _100000_. Default: _10000_ *multiplier* = _<integer>_ Number of line scrolled for every input scroll increment. Default: _3_ # FONT This section documents the *[font]* table of the configuration file. *normal* = { family = _"<string>"_, style = _"<string>"_ } Default: Linux/BSD: { family = _"monospace"_, style = _"Regular"_ }++ Windows: { family = _"Consolas"_, style = _"Regular"_ }++ macOS: { family = _"Menlo"_, style = _"Regular"_ } *bold* = { family = _"<string>"_, style = _"<string>"_ } If the family is not specified, it will fall back to the value specified for the normal font. Default: { style = _"Bold"_ } *italic* = { family = _"<string>"_, style = _"<string>"_ } If the family is not specified, it will fall back to the value specified for the normal font. Default: { style = _"Italic"_ } *bold_italic* = { family = _"<string>"_, style = _"<string>"_ } If the family is not specified, it will fall back to the value specified for the normal font. Default: { style = _"Bold Italic"_ } *size* = _<float>_ Font size in points. Default: _11.25_ *offset* = { x = _<integer>_, y = _<integer>_ } Offset is the extra space around each character. _y_ can be thought of as modifying the line spacing, and _x_ as modifying the letter spacing. Default: { x = _0_, y = _0_ } *glyph_offset* = { x = _<integer>_, y = _<integer>_ } Glyph offset determines the locations of the glyphs within their cells with the default being at the bottom. Increasing _x_ moves the glyph to the right, increasing _y_ moves the glyph upward. *builtin_box_drawing* = _true_ | _false_ When _true_, Alacritty will use a custom built-in font for box drawing characters (Unicode points _U+2500_ - _U+259F_), legacy computing symbols (_U+1FB00_ - _U+1FB3B_), and powerline symbols (_U+E0B0_ - _U+E0B3_). Default: _true_ # COLORS This section documents the *[colors]* table of the configuration file. Colors are specified using their hexadecimal values with a _#_ prefix: _#RRGGBB_. *primary* This section documents the *[colors.primary]* table of the configuration file. *foreground* = _"<string>"_ Default: _"#d8d8d8"_ *background* = _"<string>"_ Default: _"#181818"_ *dim_foreground* = _"<string>"_ If this is not set, the color is automatically calculated based on the foreground color. Default: _"#828482"_ *bright_foreground* = _"<string>"_ This color is only used when _draw\_bold\_text\_with\_bright\_colors_ is _true_. If this is not set, the normal foreground will be used. Default: _"None"_ *cursor* = { text = _"<string>"_, cursor = _"<string>"_ } Colors which should be used to draw the terminal cursor. Allowed values are hexadecimal colors like _#ff00ff_, or _CellForeground_/_CellBackground_, which references the affected cell. Default: { text = _"CellBackground"_, cursor = _"CellForeground"_ } *vi_mode_cursor* = { text = _"<string>"_, cursor = _"<string>"_ } Colors for the cursor when the vi mode is active. Allowed values are hexadecimal colors like _#ff00ff_, or _CellForeground_/_CellBackground_, which references the affected cell. Default: { text = _"CellBackground"_, cursor = _"CellForeground"_ } *search* This section documents the *[colors.search]* table of the configuration. Allowed values are hexadecimal colors like _#ff00ff_, or _CellForeground_/_CellBackground_, which references the affected cell. *matches* = { foreground = _"<string>"_, background = _"<string>"_ } Default: { foreground = _"#181818"_, background = _"#ac4242"_ } *focused_match* = { foreground = _"<string>"_, background = _"<string>"_ } Default: { foreground = _"#181818"_, background = _"#f4bf75"_ } *hints* This section documents the *[colors.hints]* table of the configuration. *start* = { foreground = _"<string>"_, background = _"<string>"_ } First character in the hint label. Allowed values are hexadecimal colors like _#ff00ff_, or _CellForeground_/_CellBackground_, which references the affected cell. Default: { foreground = _"#181818"_, background = _"#f4bf75"_ } *end* = { foreground = _"<string>"_, background = _"<string>"_ } All characters after the first one in the hint label. Allowed values are hexadecimal colors like _#ff00ff_, or _CellForeground_/_CellBackground_, which references the affected cell. Default: { foreground = _"#181818"_, background = _"#ac4242"_ } *line_indicator* = { foreground = _"<string>"_, background = _"<string>"_ } Color used for the indicator displaying the position in history during search and vi mode. Setting this to _"None"_ will use the opposing primary color. Default: { foreground = _"None"_, background = _"None"_ } *footer_bar* = { foreground = _"<string>"_, background = _"<string>"_ } Color used for the footer bar on the bottom, used by search regex input, hyperlink URI preview, etc. Default: { foreground = _"#181818"_, background = _"#d8d8d8"_ } *selection* = { text = _"<string>"_, background = _"<string>"_ } Colors used for drawing selections. Allowed values are hexadecimal colors like _#ff00ff_, or _CellForeground_/_CellBackground_, which references the affected cell. Default: { text = _"CellBackground"_, background = _"CellForeground"_ } *normal* This section documents the *[colors.normal]* table of the configuration. *black* = _"<string>"_ Default: _"#181818"_ *red* = _"<string>"_ Default: _"#ac4242"_ *green* = _"<string>"_ Default: _"#90a959"_ *yellow* = _"<string>"_ Default: _"#f4bf75"_ *blue* = _"<string>"_ Default: _"#6a9fb5"_ *magenta* = _"<string>"_ Default: _"#aa759f"_ *cyan* = _"<string>"_ Default: _"#75b5aa"_ *white* = _"<string>"_ Default: _"#d8d8d8"_ *bright* This section documents the *[colors.bright]* table of the configuration. *black* = _"<string>"_ Default: _"#6b6b6b"_ *red* = _"<string>"_ Default: _"#c55555"_ *green* = _"<string>"_ Default: _"#aac474"_ *yellow* = _"<string>"_ Default: _"#feca88"_ *blue* = _"<string>"_ Default: _"#82b8c8"_ *magenta* = _"<string>"_ Default: _"#c28cb8"_ *cyan* = _"<string>"_ Default: _"#93d3c3"_ *white* = _"<string>"_ Default: _"#f8f8f8"_ *dim* This section documents the *[colors.dim]* table of the configuration. If the dim colors are not set, they will be calculated automatically based on the _normal_ colors. *black* = _"<string>"_ Default: _"#0f0f0f"_ *red* = _"<string>"_ Default: _"#712b2b"_ *green* = _"<string>"_ Default: _"#5f6f3a"_ *yellow* = _"<string>"_ Default: _"#a17e4d"_ *blue* = _"<string>"_ Default: _"#456877"_ *magenta* = _"<string>"_ Default: _"#704d68"_ *cyan* = _"<string>"_ Default: _"#4d7770"_ *white* = _"<string>"_ Default: _"#8e8e8e"_ *indexed_colors* = [{ index = _<integer>_, color = _"<string>"_ },] The indexed colors include all colors from 16 to 256. When these are not set, they're filled with sensible defaults. Default: _[]_ *transparent_background_colors* = _true_ | _false_ Whether or not _window.opacity_ applies to all cell backgrounds, or only to the default background. When set to _true_ all cells will be transparent regardless of their background color. Default: _false_ *draw_bold_text_with_bright_colors* = _true_ | _false_ When _true_, bold text is drawn using the bright color variants. Default: _false_ # BELL This section documents the *[bell]* table of the configuration file. *animation* = _"Ease"_ | _"EaseOut"_ | _"EaseOutSine"_ | _"EaseOutQuad"_ | _"EaseOutCubic"_ \| _"EaseOutQuart"_ | _"EaseOutQuint"_ | _"EaseOutExpo"_ | _"EaseOutCirc"_ | _"Linear"_ Visual bell animation effect for flashing the screen when the visual bell is rung. Default: _"Linear"_ *duration* = _<integer>_ Duration of the visual bell flash in milliseconds. A `duration` of `0` will disable the visual bell animation. Default: _0_ *color* = _"<string>"_ Visual bell animation color. Default: _"#ffffff"_ *command* = _"<string>"_ | { program = _"<string>"_, args = [_"<string>"_,] } This program is executed whenever the bell is rung. When set to _"None"_, no command will be executed. Default: _"None"_ # SELECTION This section documents the *[selection]* table of the configuration file. *semantic_escape_chars* = _"<string>"_ This string contains all characters that are used as separators for "semantic words" in Alacritty. Default: _",│`|:\\"' ()[]{}<>\\t"_ *save_to_clipboard* = _true_ | _false_ When set to _true_, selected text will be copied to the primary clipboard. Default: _false_ # CURSOR This section documents the *[cursor]* table of the configuration file. *style* = { *<shape>*, *<blinking>* } *shape* = _"Block"_ | _"Underline"_ | _"Beam"_ Default: _"Block"_ *blinking* = _"Never"_ | _"Off"_ | _"On"_ | _"Always"_ *Never* Prevent the cursor from ever blinking *Off* Disable blinking by default *On* Enable blinking by default *Always* Force the cursor to always blink Default: _"Off"_ *vi_mode_style* = { *<shape>*, *<blinking>* } | _"None"_ If the vi mode cursor style is _"None"_ or not specified, it will fall back to the active value of the normal cursor. Default: _"None"_ *blink_interval* = _<integer>_ Cursor blinking interval in milliseconds. Default: _750_ *blink_timeout* = _<integer>_ Time after which cursor stops blinking, in seconds. Specifying _0_ will disable timeout for blinking. Default: _5_ *unfocused_hollow* = _true_ | _false_ When this is _true_, the cursor will be rendered as a hollow box when the window is not focused. Default: _true_ *thickness* = _<float>_ Thickness of the cursor relative to the cell width as floating point number from _0.0_ to _1.0_. Default: _0.15_ # TERMINAL This section documents the *[terminal]* table of the configuration file. *osc52* = _"Disabled"_ | _"OnlyCopy"_ | _"OnlyPaste"_ | _"CopyPaste"_ Controls the ability to write to the system clipboard with the _OSC 52_ escape sequence. While this escape sequence is useful to copy contents from the remote server, allowing any application to read from the clipboard can be easily abused while not providing significant benefits over explicitly pasting text. Default: _"OnlyCopy"_ # MOUSE This section documents the *[mouse]* table of the configuration file. *hide_when_typing* = _true_ | _false_ When this is _true_, the cursor is temporarily hidden when typing. Default: _false_ *bindings* = [{ *<mouse>*, *<mods>*, *<mode>*, *<command>* | *<chars>* | *<action>* },] See _keyboard.bindings_ for full documentation on _mods_, _mode_, _command_, _chars_, and _action_. When an application running within Alacritty captures the mouse, the `Shift` modifier can be used to suppress mouse reporting. If no action is found for the event, actions for the event without the `Shift` modifier are triggered instead. *mouse* = _"Middle"_ | _"Left"_ | _"Right"_ | _"Back"_ | _"Forward"_ | _<integer>_ Mouse button which needs to be pressed to trigger this binding. *action* = *<keyboard.bindings.action>* | _"ExpandSelection"_ *ExpandSelection* Expand the selection to the current mouse cursor location. Example: *[mouse]*++ bindings = [++ { mouse = _"Right"_, mods = _"Control"_, action = _"Paste"_ },++ ] # HINTS This section documents the *[hints]* table of the configuration file. Terminal hints can be used to find text or hyperlinks in the visible part of the terminal and pipe it to other applications. *alphabet* = _"<string>"_ Keys used for the hint labels. Default: _"jfkdls;ahgurieowpq"_ *enabled* = [{ *<regex>*, *<hyperlinks>*, *<post_processing>*, *<persist>*, *<action>*, *<command>* *<binding>*, *<mouse>* },] Array with all available hints. Each hint must have at least one of _regex_ or _hyperlinks_ and either an _action_ or a _command_. *regex* = _"<string>"_ Regex each line will be compared against. *hyperlinks* = _true_ | _false_ When this is _true_, all OSC 8 escape sequence hyperlinks will be included in the hints. *post_processing* = _true_ | _false_ When this is _true_, heuristics will be used to shorten the match if there are characters likely not to be part of the hint (e.g. a trailing _._). This is most useful for URIs and applies only to _regex_ matches. *persist* = _true_ | _false_ When this is _true_, hints remain persistent after selection. *action* = _"Copy"_ | _"Paste"_ | _"Select"_ | _"MoveViModeCursor"_ *Copy* Copy the hint's text to the clipboard. *Paste* Paste the hint's text to the terminal or search. *Select* Select the hint's text. *MoveViModeCursor* Move the vi mode cursor to the beginning of the hint. *command* = _"<string>"_ | { program = _"<string>"_, args = [_"<string>"_,] } Command which will be executed when the hint is clicked or selected with the _binding_. The hint's text is always attached as the last argument. *binding* = { key = _"<string>"_, mods = _"<string>"_, mode = _"<string>"_ } See _keyboard.bindings_ for documentation on available values. This controls which key binding is used to start the keyboard hint selection process. *mouse* = { mods = _"<string>"_, enabled = _true_ | _false_ } See _keyboard.bindings_ for documentation on available _mods_. The _enabled_ field controls if the hint should be underlined when hovering over the hint text with all _mods_ pressed. Default: *[[hints.enabled]]*++ command = _"xdg-open"_ # On Linux/BSD++ # command = _"open"_ # On macOS++ # command = { program = _"cmd"_, args = [ _"/c"_, _"start"_, _""_ ] } # On Windows++ hyperlinks = _true_++ post_processing = _true_++ persist = _false_++ mouse.enabled = _true_++ binding = { key = _"U"_, mods = _"Control|Shift"_ }++ regex = _"(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)[^\\u0000-\\u001F\\u007F-\\u009F<>\\"\\\\s{-}\\\\^⟨⟩`]+"_ # KEYBOARD This section documents the *[keyboard]* table of the configuration file. *bindings* = [{ *<key>*, *<mods>*, *<mode>*, *<command>* | *<chars>* | *<action>* },] To unset a default binding, you can use the action _"ReceiveChar"_ to remove it or _"None"_ to inhibit any action. Multiple keybindings can be triggered by a single key press and will be executed in the order they are defined in. *key* = _"<string>"_ The regular keys like _"A"_, _"0"_, and _"Я"_ can be mapped directly without any special syntax. Full list of named keys like _"F1"_ and the syntax for dead keys can be found here: _https://docs.rs/winit/latest/winit/keyboard/enum.NamedKey.html_++ _https://docs.rs/winit/latest/winit/keyboard/enum.Key.html#variant.Dead_ Numpad keys are prefixed by _Numpad_: _"NumpadEnter"_ | _"NumpadAdd"_ | _"NumpadComma"_ | _"NumpadDecimal"_ | _"NumpadDivide"_ | _"NumpadEquals"_ | _"NumpadSubtract"_ | _"NumpadMultiply"_ | _"Numpad[0-9]"_. The _key_ field also supports using scancodes, which are specified as a decimal number. *mods* = _"Command"_ | _"Control"_ | _"Option"_ | _"Super"_ | _"Shift"_ | _"Alt"_ Multiple modifiers can be combined using _|_, like this: _"Control | Shift"_. *mode* = _"AppCursor"_ | _"AppKeypad"_ | _"Search"_ | _"Alt"_ | _"Vi"_ This defines a terminal mode which must be active for this binding to have an effect. Prepending _~_ to a mode will require the mode to *not* = be active for the binding to take effect. Multiple modes can be combined using _|_, like this: _"~Vi|Search"_. *command* = _"<string>"_ | { program = _"<string>"_, args = [_"<string>"_,] } Fork and execute the specified command. *chars* = _"<string>"_ Writes the specified string to the terminal. *action* *ReceiveChar* Allow receiving char input. *None* No action. *Paste* Paste contents of system clipboard. *Copy* Store current selection into clipboard. *IncreaseFontSize* Increase font size. *DecreaseFontSize* Decrease font size. *ResetFontSize* Reset font size to the config value. *ScrollPageUp* Scroll exactly one page up. *ScrollPageDown* Scroll exactly one page down. *ScrollHalfPageUp* Scroll half a page up. *ScrollHalfPageDown* Scroll half a page down. *ScrollLineUp* Scroll one line up. *ScrollLineDown* Scroll one line down. *ScrollToTop* Scroll all the way to the top. *ScrollToBottom* Scroll all the way to the bottom. *ClearHistory* Clear the display buffer(s) to remove history. *Hide* Hide the Alacritty window. *Minimize* Minimize the Alacritty window. *Quit* Quit Alacritty. *ClearLogNotice* Clear warning and error notices. *SpawnNewInstance* Spawn a new instance of Alacritty. *CreateNewWindow* Create a new Alacritty window. *ToggleFullscreen* Toggle fullscreen. *ToggleMaximized* Toggle maximized. *ClearSelection* Clear active selection. *ToggleViMode* Toggle vi mode. *SearchForward* Start a forward buffer search. *SearchBackward* Start a backward buffer search. _Vi mode actions:_ *Up* Move up. *Down* Move down. *Left* Move left. *Right* Move right. *First* First column, or beginning of the line when already at the first column. *Last* Last column, or beginning of the line when already at the last column. *FirstOccupied* First non-empty cell in this terminal row, or first non-empty cell of the line when already at the first cell of the row. *High* Move to top of screen. *Middle* Move to center of screen. *Low* Move to bottom of screen. *SemanticLeft* Move to start of semantically separated word. *SemanticRight* Move to start of next semantically separated word. *SemanticLeftEnd* Move to end of previous semantically separated word. *SemanticRightEnd* Move to end of semantically separated word. *WordLeft* Move to start of whitespace separated word. *WordRight* Move to start of next whitespace separated word. *WordLeftEnd* Move to end of previous whitespace separated word. *WordRightEnd* Move to end of whitespace separated word. *Bracket* Move to opposing bracket. *ToggleNormalSelection* Toggle normal vi selection. *ToggleLineSelection* Toggle line vi selection. *ToggleBlockSelection* Toggle block vi selection. *ToggleSemanticSelection* Toggle semantic vi selection. *SearchNext* Jump to the beginning of the next match. *SearchPrevious* Jump to the beginning of the previous match. *SearchStart* Jump to the next start of a match to the left of the origin. *SearchEnd* Jump to the next end of a match to the right of the origin. *Open* Launch the URL below the vi mode cursor. *CenterAroundViCursor* Centers the screen around the vi mode cursor. *InlineSearchForward* Search forward within the current line. *InlineSearchBackward* Search backward within the current line. *InlineSearchForwardShort* Search forward within the current line, stopping just short of the character. *InlineSearchBackwardShort* Search backward within the current line, stopping just short of the character. *InlineSearchNext* Jump to the next inline search match. *InlineSearchPrevious* Jump to the previous inline search match. _Search actions:_ *SearchFocusNext* Move the focus to the next search match. *SearchFocusPrevious* Move the focus to the previous search match. *SearchConfirm* Confirm the active search. *SearchCancel* Cancel the active search. *SearchClear* Reset the search regex. *SearchDeleteWord* Delete the last word in the search regex. *SearchHistoryPrevious* Go to the previous regex in the search history. *SearchHistoryNext* Go to the next regex in the search history. _macOS exclusive:_ *ToggleSimpleFullscreen* Enter fullscreen without occupying another space. *HideOtherApplications* Hide all windows other than Alacritty. *CreateNewTab* Create new window in a tab. *SelectNextTab* Select next tab. *SelectPreviousTab* Select previous tab. *SelectTab1* Select the first tab. *SelectTab2* Select the second tab. *SelectTab3* Select the third tab. *SelectTab4* Select the fourth tab. *SelectTab5* Select the fifth tab. *SelectTab6* Select the sixth tab. *SelectTab7* Select the seventh tab. *SelectTab8* Select the eighth tab. *SelectTab9* Select the ninth tab. *SelectLastTab* Select the last tab. _Linux/BSD exclusive:_ *CopySelection* Copy from the selection buffer. *PasteSelection* Paste from the selection buffer. Default: See *alacritty-bindings*(5) Example: *[keyboard]*++ bindings = [++ { key = _"N"_, mods = _"Control|Shift"_, action = _"CreateNewWindow"_ },++ { key = _"L"_, mods = _"Control|Shift"_, chars = _"l"_ },++ ] # DEBUG This section documents the *[debug]* table of the configuration file. Debug options are meant to help troubleshoot issues with Alacritty. These can change or be removed entirely without warning, so their stability shouldn't be relied upon. *render_timer* = _true_ | _false_ Display the time it takes to draw each frame. Default: _false_ *persistent_logging* = _true_ | _false_ Keep the log file after quitting Alacritty. Default: _false_ *log_level* = _"Off"_ | _"Error"_ | _"Warn"_ | _"Info"_ | _"Debug"_ | _"Trace"_ Default: _"Warn"_ To add extra libraries to logging _ALACRITTY_EXTRA_LOG_TARGETS_ variable can be used. Example: _ALACRITTY_EXTRA_LOG_TARGETS="winit;vte" alacritty -vvv_ *renderer* = _"glsl3"_ | _"gles2"_ | _"gles2pure"_ | _"None"_ Force use of a specific renderer, _"None"_ will use the highest available one. Default: _"None"_ *print_events* = _true_ | _false_ Log all received window events. Default: _false_ *highlight_damage* = _true_ | _false_ Highlight window damage information. Default: _false_ *prefer_egl* = _true_ | _false_ Use EGL as display API if the current platform allows it. Note that transparency may not work with EGL on Linux/BSD. Default: _false_ # SEE ALSO *alacritty*(1), *alacritty-msg*(1), *alacritty-bindings*(5) # BUGS Found a bug? Please report it at _https://github.com/alacritty/alacritty/issues_. # MAINTAINERS - Christian Duerr <contact@christianduerr.com> - Kirill Chibisov <contact@kchibisov.com> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/extra/osx/Alacritty.app/Contents/Info.plist����������������������������������������0000644�0000000�0000000�00000004643�10461020230�0022126�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>en</string> <key>CFBundleExecutable</key> <string>alacritty</string> <key>CFBundleIdentifier</key> <string>org.alacritty</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundleName</key> <string>Alacritty</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> <string>0.13.2</string> <key>CFBundleSupportedPlatforms</key> <array> <string>MacOSX</string> </array> <key>CFBundleVersion</key> <string>1</string> <key>CFBundleIconFile</key> <string>alacritty.icns</string> <key>NSHighResolutionCapable</key> <true/> <key>NSMainNibFile</key> <string></string> <key>NSSupportsAutomaticGraphicsSwitching</key> <true/> <key>CFBundleDisplayName</key> <string>Alacritty</string> <key>NSRequiresAquaSystemAppearance</key> <string>NO</string> <key>NSAppleEventsUsageDescription</key> <string>An application in Alacritty would like to access AppleScript.</string> <key>NSCalendarsUsageDescription</key> <string>An application in Alacritty would like to access calendar data.</string> <key>NSCameraUsageDescription</key> <string>An application in Alacritty would like to access the camera.</string> <key>NSContactsUsageDescription</key> <string>An application in Alacritty wants to access your contacts.</string> <key>NSLocationAlwaysUsageDescription</key> <string>An application in Alacritty would like to access your location information, even in the background.</string> <key>NSLocationUsageDescription</key> <string>An application in Alacritty would like to access your location information.</string> <key>NSLocationWhenInUseUsageDescription</key> <string>An application in Alacritty would like to access your location information while active.</string> <key>NSMicrophoneUsageDescription</key> <string>An application in Alacritty would like to access your microphone.</string> <key>NSRemindersUsageDescription</key> <string>An application in Alacritty would like to access your reminders.</string> <key>NSSystemAdministrationUsageDescription</key> <string>An application in Alacritty requires elevated permissions.</string> </dict> </plist> ���������������������������������������������������������������������������������������������alacritty-0.13.2/extra/osx/Alacritty.app/Contents/Resources/alacritty.icns��������������������������0000644�0000000�0000000�00002424261�10461020230�0025006�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������icns� (ic12�� PNG  ��� IHDR���@���@���iq���sRGB��� IDATxmPqOwBH@$@'v4+tpәƝNN:iy3)vM;dکI<IN8h,d:ݽ{t-<{o}v>p- [CT0-r̦۟^a VDc͖c~"Y� ._/gyr"Oϒ,5Ok-O+ˈ H| ~1bQSeb6EiUpMP@a9Zc g&Y<ԗEZU<ECn8Q ){&DFOS@}DU}\dgInv44'4l^Z>nFN#5 Zp@]]ݸzL8?^5sN՚%T*h-LMMIHDbC,[Sl6pHwiaaA988k�ޮWbhhQW{4, @[[F' HVlv Y-x m2DiN{u@iӲix2z 7r$X_Ux$쵆z>1 $̤GRT�%aɝe!JXh~FcO#M)A+:Z\<jMCFX5E,y74"7pW p"xwGwv+.- % bT~}Hn.S Vvkr58XoόKH{`�14tbè϶i5p5pUΊ_8z`ќv4�"2O?hCp:X 12j,w{f.f-Vj/3 ޚ]N ~ ;VRqߍs4q2�tsnEI`&w9Ү�^[3tMs;=A D+%� `+Kwp)m; Cf=.t_/ggOhΞ{A=؅̀U5@O=;tu ^Fyfa�ϐSXMOO Z4Ti^vq|6Ja=$1~ ~(Z"``w3MztC CCPl (mpw[d,[vCc =�k!()ٷn9]컑M} Za#.x[>/Ҩ&"ϽȻX(8܌ʉ#r(P也`{?T/"0H;<##W~'dzO,w[{w= =IKjnMy7WC -Oyggv/olsyX_y P`Wѯf)%2|ć2 ؚόBVOu(f?i^н1$0omJ ~̮-A'4lz37xPG^$ " O4 `o 5/kr*/E[>R Z*X/<gRVTF~wr4N6T oR= o~kFO(!ga$1ٖ‡9kB|OOO14w&x#\{GC $X =#Z$#@M!n7FMoa7YtFrxA�Ak`�yI;w%^~ ZJZ+N;HDOB�. ΃轨yA. ~xNGREj]6) K%ǘx^F*>p˕j#[ < l`dž.QS8: gzQFf?@ #8[c|)_5 pt?N*r aK%b0uF{9Ke&\Q0�tnW~'/}Z8űwA/B##k1 `|g012;?4O{_RJ' UµM'Y�Cӂ_C` NcEEq⒂B(ʞũ6>f<k2d�QX `Ԩ�/VÇ7YhMl!3!tyPn<2.`a�`J,FnԢtjem3iA AwV�o峯^l8(*a5 `$V,n�QqeX!%D:%N҉tc7\wo>u _ʊ*Iu||X]%H4n"32Ԅ_LNNz5;?㙙ᏧWZ,4zĉ K'Y&o����IENDB`ic07��,PNG  ��� IHDR���������>a���sRGB���+IDATx}kdGީ[c=O͌[ !$XY6b ^/v,v86�Gڕvk!! =XiF b$f4g[UߗfuvuuTwuwPuo;9y'D::@:@WF#DBs7ɮ'jDmK|yYLY:,Ʋh#aRl;(\9J�G@/F%mqHϼմ:UڒxW| [3}ɻOc ] goYKjگ~!4`&Xn6{!Љ؇Pq:KZ[ź8>_ hWj:kFըTy%d U-z3jUĩ!~I+ջB jVӪ'_ղFs5ZRTC2ݡ{Tl6ߏM͡ ~*]7cP}2:,J3/[R&uf|WEDj9 lO7y>_4#YTd[gKi5ceFdyUg|%lYvT*ȥbzvD7nu{.+vkuVV�\['RũH0KXRQkDP70 PeWIg5qVHU|͇^E<yrR}$dY{Bך:_^(W:>~gtg�aXӱT*%H\:m H$"XLett8p"'N|rffOϜ9#m<NA ˾}dddSW^y [0돃ԕUIߞؿ;<<|r<-ouzN>M&p7!7廩Ztz3/6?~Ђ@JضJec;C u&!Xe||_w}CSO=%Pennn[V"3[�{jj!=zT>,&z1w{Gg2na.6$�cǎ){�)j61Q#\0 ,;uJ]QHd+oUΦnFWvC rBrxL‘)dc1܈|ix!ӄ e+XX)g]#!N. i @(#FWp�N�< %œ+൭WYܿ!M�$K=PL}}xȕ�uh3APLHT^D9$@ ݺ v�$�~$B̆32JAaԀ'EI8A�Q/:{;>M�Pz?�;Y+'RRMH䀹+9UB@l(pY ao]۟]!K K+yq,8@TJ �wpƇJt @G1 P wJ<P] I#n,%,dz71Zq�f8Kj+<qϞ)#rYS#.2!.UJ%0Xr�FZ!㒰 7G㡒CؖNS|t]L8./A6]mđ-�hm41me'lY3[Cgg`%[.zŭU9"v&h pjW5P²'pLؕ70`l|_AT%)HH޵68Af-^!_ ߞ#Z>ڿFL- I;n9[A' >8@`bM�Ў@~")t)#䌵pɴD4e0PJBR\Ez;L%9�7w, '"�\@! $�aA[.RPR\OoϦ9@3 rv"Y.fEǜO/-N ]JIJTu5إu\Q wMh7 n;o峃5!D7H+x]_\$qyI,yq,ֽUo&hn` u1m@9W=5!vb4%,F(9_Qa^b$[ŋWL f*; H`5Ěiz !M酨TR P;`.f`qd+*Hw?Fҧ�+f5Chk7:ć˰By]G-YLhSF1o$C{=H� |2N (7lM=t˨w|\^-İ"JtD`-7v1W?#VI*ˇ],TV_LɷZ ~sq�AdI@& LՀA}mJ hCX5q"DH(5%s0D CԲyk@;dT!ܫEף 2EtRJ0,8 LqUw\JvBf]XY]|\>č/�JhHЬ]i�+A<Ыu!* i[D܂ ]RRbs�l5ø8�@Oo?s;rqƟWl}eb@X\>0> CEȵ|b22˱f˚1<S=FGd q|Go"X_82͡/;9Ղk[j Mͤ l=\k?}}1W>9RZiWoOR._NZ᱋jcJ,,PV?|s[N;QIY>*v48fHH*' @^+3N#y ٲLcf(B(+-XƣEf]Yʌ|R^nUssC4[j~["B𧿨8LF3ӽbu'%" hܕl,gCeԋʉԡ D S)\:jXS.IO&[*VIc fka_>9rm</Sjwj0iqsX_\,{nR*,02dDP>B91N1ID0LU`ԯA8~ [1B^$dƁ?6~KڃrEq3htB~?j0 JW̶>b9OP h[ A 鲛4Mĝz7e *S S c)yE+ RT|G= c] & ~d~!jaNhT`^3X., U֩{IShh*7&R.`A[! BV {~NI%Hf ~!4,sL;0C~&2k.\ITʡ.ۯӬG/mM}B̤cP aRC AS l`V׫f+1?qu.bt@￞#); Dԭ!Np#)3I^wD>rEEx:Me-4QJ䉙+F35 �4Hg?T5@օ~<-"A�q~ SvDn甔rfa} "2F }5Iw0 !�t@9 �\%w&\yg^>s >L=eUgn #Q;+p]G*/.wϓ=g4>`gBGT7-plZ09�]h|9�g?e59XF;_ uneQ0゚6<y#8Nw 67AX9\͢BXzA|Ө5hLaP) @\}59�Y7Kfr�" 䚤-you5A/ .bRzs}d ?8*_NK!PنJo‘;\4f0\lQ?25},!rqRP� jM%jr i & %z *e]sQ9/J qCla]Y`+N$KE)C{*6xRUԴQ/4T9 d\Wl2lr2cPv�aW&C%9@r {>u2WS R :~8^%O[>{T)8eyC ZX,l[[ ̈ܵWWdDT\Lp6ڲ4mh}f5Ÿ0#Ee? D򲠡D ?qX!$f_죸&5)64vqҸnm -=1э؜6xNHa"aX=pnG -&7Lw�ps_k)͚>U>dfOb? 3P@UPDf;~!;wIsG@3%of-vTk* Nxr#4M(̚nW˷4u f6L*ς+{=AG noٷ1,_o}3rĢ |_�X a{dO_1g~šB`w8r$LL*p1P]Sѵ``�xe!~y,uF#}-<XgBrqY8o<sgQLӳSRK1R K:~8 ~T +{IJvu }.,H> f`-6Z $2(űVSi9ԋ`VR^?/$/+sa"qO޳O>%;@ ɬB8+{;{Z<Be|ȕ2l@u,S[?M`)+a.o08v5kmL8g!y[^aYNĩ#'8ST?vF17呇O.8V ) ًRHK@Bj-K(pjGt۪#jyn: ٸ@�-�zl|n$ ^)[>{9GPԼ<yxKzaccEolɧK~LPŠSnX^|oeb"0<z`zܑw+$4_++K7ph*�LH ؈`r�ֿnF���a=5]sٟzO/R췹?.c Cd)( 2RLx.= dM Z]!m8N `;\ "W&�SH{&]} {8iCJa{~w}pkGGvnx? aÇ)#S(@n{Oޓ32sqRb^H1pw+^^zb>"=餜a\@ 0D4Q`?ԯ[<ᷮa[ɜ!*o\eƩ!x {ar|Wnz$y`.$�(6R1;''qgWG,~xGW0d7_pr)XAQ'ꇆ l)Ŷo+ǽweh!D͠|}l_"]q01pJ Crׇ>!7w}p�f@d=.<{RJ0 R a7D aKn/JUe_d^㗻.ƱaV}:vp��[qˆf_u/17 db.@bƚqO.q*b܁]_4V r .@ (�r�a TNRKC{" (q㊼jڇZB0M4|E&ZN�b 'gݻ֦a@f?g†~@(6Ʈ zh ` K.�00 L '$P7xm];P UB5Ͻ=[]ئXCM5~5M-!�a X*xq>d@�*�94GHZ<YXR;%F Ѐ޾!ke?iO]o]vw簍Mx2'7$|OAG:YtIq$pˀ8ukDV?"U?_,@.F&5zQFܓ0-`vX_vKQ*;ʉݞ\a�(0Yp h0#YxMI97(]E'X+;T_SIWE Nt:BZRկ?Pgn+Ws"G,g̦7|=Y$ H#2 X!9�NxPN@H"8@ }p)Ϝ`HhOBsȖ0X_%. 3w~m ٽgq~B 6tcu)GĂ{4tr�',x,ث é)Fw .j K i$XȀLb֟CsRx !~υ%z;/>gc(hk�Wˤy\ Q 5`r�JC٣U_I.ʿ{oI?4W�Ug%ٗ\>+0I Id>c҃?.K NwR~v5$YB酇c IW ˡ 9EXޖ^OC!m'h nE`Tum|9@+e�۾aLluXr ?y\vʎ#NF]qNA{t%".(`ӋGś=Y]ppr�THx迁 \?r>@>mb:9�RKVq�"CIoa˿}oZajIOճҁ{GE}X^4p)!Ap)]'wv*p�  -p{<3ǥ|9ȭCx SJR[OaIŇJg96 "z*A'-%V�`ѳ!Y󎼮ƞuVϟEY\b;5UXE WKE UR 3*fR�\/4 ?@pL,ߗ1FL\Beh}}TaDb)DuvUvmo &@>=~q~G~6IA4DA^(<~#p y4M,7a ^0}{$D{-6`(�p  ǟ lyJ-0h%? _ACUƻJp'<ov)Q MzO,P#z jCXgN/Č-`Dž(Bb^=PN&q6�ژɠ@0%Hy{AB6"v~vO Y<z!&GwEd$>z]t-,[aX 0:0Wf�߂0!\ �dW��ŘDܹ.E84}ٯG xh)sI�W�d*Yp,+r<GOm!G}y}Jff\598RV �9cĻi &Lի!jzM'0p .�H( ʓ_UEUjE~' e� 䮷m1O8 |G0JྠO >#5aK N,\=Pb|VTDž#Ey33�y`'ti/&h`z@>u!HyAxQ?ĭK 阼r=[Ր0,,y,P +IgP pL?�RKس DDw`+4�nQ*!8p2R̴J@i4NeBl Mm`r^ҿeIQ n ݑ A|QeɁ9;>C~%cKկ6Iuzũ:dD8oH"g_RF P`]5)P~*G%qcӅwܕ/dCӈlrD8@` ͮlj X H=pv޼PSH@4qoU8cE,.z7S*:>�ϫYe[!mO$yo<y d�\*^ jLHA0 `yY LcZFf>2\`=NMsFBh߾DE8;ݰX*2~P�d"'/ÿO1t\B3(p J)C@̍:Hb%vE LA(gz$ߕ8T̏>$TՇQdpފ<x[ 4h0(�4"�r�@ze^53_6k5@n /_6W@rO20sp�r?}y;-#lP}0:b;ǦdF* .C_X~gBPl!#@e�"v}@5Q#hZ(x|2] po6GH�fOa-XSӃHhx=Qjxї+A !|z`� 64\�Փ ƥ%|TOOyX865q7| ksqÁu.㕔<qdCz_4Kg/Yrj( RP U&c_M ##p;Ψ3}gu� ːo*0 yPPwԫ*8VĘk&6M-YLXW0tðmTwpa!W"�&\ S]M`>/YRFe`A`$:;qNRb%i0E|6,HWTzqĻ8 TǪ#m8Ylj]L�l7jA kmKݬ܌_W0 zpVV. zB?Es `0 5XX�6wKiL ȹ#efijǵṋ +pA/Sv>+.0Ʃ6O0^*b6{-xM-k1s6`"zwW= Oc͟�:^7~ori%PȯOP%V/1XU#>Cèc 5ʽhLjMРj4XbdKpN! ϕ@1`M2 xcqGq 6B"0pyh*pb`q7�ѣyM(�>2G!/˜ɪRP[{̱RX/�#gǢ(TP5-vypMJLT ١FsWfOagk|@pA*l<K`!To$RT)�9V -Sv) %TJ_ܥIkU $lu&.`%�z[ !Q_!}ݘM`\Iy�B?�f=ܽc'K vNcńXx5a!!L |Zeu�fk�<MgLٷH!Fzo� A8&^yϤ�B^xCJǁ_݉Is/FA=W#K3&`u� tX+Q:OSkH>5!@zF$?,[%'OH$5/fCu[_m'x٪[7[0ٚw$xnzw??V[LCz9@ie � BJJϨxoG،yI%�qoeoZZ"SZ1,-TkKi-5A)Ӄ`k1] ^@w/ 8߱dAH-:r;ٍʹmN"Ck_ ە|Zy-8Zhjk1o5@�<=}3~2MdZ)_VhDh##P�4RRSo4�r)#6 m- qw8V 7B~y'%u*Um$ <od0aey>a /א�=*<۷O^y\xNh[tww-"wy|oH�!PJC듛oYIe333r\Gc Bf w/'Xؒ0 D~ �2}g200\8 zC9 dSSS@X뮻T*WW\zǕHꫯ>{;b }:ᲅ�f~yhh|/pU{6T"AH.eK2Go~{K-ׁ@t Ё@t Ё@t Ё@??qt����IENDB`ic13��TPNG  ��� IHDR���������\rf���sRGB���@�IDATxi%uo}ٷ`@b@RRlIHSMҔ>ȟ|/7آDٲCIH l}03=KOOwW׾}##_WjW5]UQ/"#cƍ7n: 2d A @ 2d A @ 2d A @ 2d A @ 2d A @ !r]qeh;7ae?@\anǼNvLIsy>ei!ݶ"Eyv~Sǂv͊msm12s/sD D�n 'oR\(M~2%a=ꗾ'k=C| [{ն8=8g¨)4p"]kސ/QS2%nǼ;>wH֦Լq~;7:ҧ9oO{|.Pȹ):~בDz,=TvH-'˗A uAk_jˍ/J ukN=g2dj)h`}\,05So'@@l/[ @,}  q~k,=n8_ P%%=q'Cܮu)#Dt"bpmKKqQ۬YqU(]N͛,/>%]Hom1o2(}tE)qy2Af#miq{A:7kϹrI:)#kC]qWT'B9t. >4%*ג&'Jl=ϬΞ!o{ۓ..O\8 ey'l=qUGc݇ =OZ^\"M { uagF&cqddXe+* 31$m=FCdUFu7u("]zҥdd86N> d!.)n2; zʰL~2ɸɛRU,7Yg2ܛgqI?}ԥ(ճ-o(?s q۟ +M.2ztrCddgWIE�J"q.iN}֡Бddŧ7>aIBPv]yϒPVL~25/zfia% ɰB|a a Y<>-oȐxfQid%}w/Cգz#?E}2mO\j!}C?5ȅI?iBe2-}zړDWd:n ½B|@ {z2,:,D>{>%ӆ^_i}5#e^?<~+n+\3{󩶥ۖ7*8ɺC8YW22&Ie6ܒ!5%k2>8o2}'Y_!}:m~ȾAxkZ?ݺr'g\nh8$ n4Z5׬,0.F\.r=Pm%�(>=׾؊*̞e A`W{uZS ~]VWW]TrF n \XtpnvvMNN ۼm^dgd^XXp/_j}c�n͝9Ò=ӿ7ɦw�fЌOUd,A 1ȈG ,~3t#&�oiiiCd~ Z n~~^ |M]2+ ]v?s2L\`}!0=�f_7/s2Lhojj{LJ3gkҳ^eHB�yk^<}W*ۄ|Y8@�w3ΝTlK.ne] A`pkkk{ ,]gq2"@@�ܿ5I,mdyXpd*E {@VS,Q ' b{^j֛ {[,r.-y! =~4w|AS~::կ~I s2,^xc߃@8�+| ^QVaqwu}uN4s� os=swg@Rf5v?7>`g2%x PH/�Bf/2>+OyzuÇ&Vpmyy us�W\6HQom`&fA xpGL#+`;�p ^z%O| dk7 @B%WMFe_. g 6~�!]pVۇ3g`!ШW q7]!p `}}=n\'!i!-6 `X~!A褿te6A|�Iy#B8GX.#pM(%xs�jT_6/mp ZQ %w* چx(7 Omꗸ?ʧ`2/A݁p�i|(W-_H]x`q<i!? _Kj >Qvn8Џ 1E\(fzCѬ??k9>vF2CpG҆#suJIH_a7PeD0Oqxu�D�҈@qd3!oNBdCj!<1PmU=s- D0xܽExd-F=5Jy=ޤ[^d""U{Iws7nVvwHkkzn$rL~=/v=*֘y&$ 0!V U3wt!00Яk_-`yD Y #j (ݳQUuC9Y/F3~84@�b I~K#[Q, :F-:(*%sU#JaUJ@, H_ZEJ{]k 5TasyA|ָg_h:w @X$8:sH2* BB]ZNj׺u&M7 w׺#n:}V%z i9N ny@֊Hfp}jMWW:r�ç͞ گ hqK¿A{,/N@X�'T*8 >?�?ҋ{ }Qp�`h{05_b hn;Rı| WAVp u?q#j ySۄlV3w]HwG(-/:9,vxu$rDy\N eY6Z˰c% @H"Sٳ=A ynOh` Ez9aL 4kXJ?\bigA7݇쾃J^rkmko'EV +[%W�umu r#�Bg:aw, ti/`'AiN~i`JBYig)S�90 DuU9@%ɽSvK)�@m͒^3ʹD+un NRIxq`PSEelein&C[֚@:P /9A@N^t 0 0j+H|uUw<>!DQ8>*d qmposDpY/ h;P+I .,?{̡�Q6K2w}"!.PҏV\e+X#߇' 2Cj(<Jw3JD"Q!.>i͚gY~' >τ`ZKWz+pguq%bv]eS^Cݳ~[،7 T(eb H׺tZŕ!Iֈmף}Vd Bpy"/ 18l<1|T"2{oUH> J<ⲳ bhM !00Я1bS_=^̲!~#1<[wh^,e@$r"m*z-l3rw*c4ߖ R\r9`Ϯ跔\85tVdbMtzcRT?f^17}%ѬRי�d[v/@84i*pλ<{şLv'R93u 5J 2X@7牲uhvۂm)Z}-<@� c!2%q{/ \cW- *  I6·en7frqB -l1"޲cz`mmp.\ �B"mb #\{J owqo{~1+\:sC@Wf Pd^?)H {$Dv{` ^UKj ?M ZT;(xgFa# F2{ Q*\%~kĿƵUX /p{釛RmtWE-�\\LjfX8w@5HfxoB$_ia-?d�HO!pٝM,BzL/Pw*To\l"( fc%J4dRiwG2N)HZ;CX?;)H2Fe$Tpu}i�a)0_ȻW^1vJB##" Q_'4ս9j\8�0?<ZLhLψ>lWq:{= ;a^2 Pȯ>k{0s#!ɬbcoޯT`vD"}p1rC qGn̷ZEWiՙ @&YߋI W2Πk~fVA/._?,R7!�W*?n[ P�kL{IvPXЯU~W�f ϱ%w;_̑ >~p޺(z]ܘr : '̀ A 3EڔMW!fX)KI=C43i-KK�Y {<Xww} ̀-_R| f8-hNj@T򵚱~+-9 pr�?7e*;7D,|` K<pN'*4=Б:B=r@&:`I-+&84 ҄)iɁ\WAIX/UIytRAb? f,4HрZU#dVT}bMW~eoğ+6ǘ9?3aI /Vz?!.'s$ᐑжu?) b,d�BL@_"S2=4=I@83iP'_,'i()>;_Ȼ"�1H,&@H%'_H%12JŽ!zt4ʷUi?}3 #T[  aY(e΄Ѯ~H *ܻ A'fB g!<kJ}VpKJk8rBԴKBխ>WyZ)G} mQ:<|0_0ܻ9�Ez$*p0cfp2݄@ ]Th[Ƕu֦cQVL鰶pաDuCtSD0f8ݠai�%YQpid淝~@[g`'UҜ'QyTkKgۤSk9%+]2)Ob}{eg;եn67(9~gVCF_M/ 4?s\Olύ+ɕ@1w=R]'|9?{++OmIDЄqI<\)| ZFl?%hèзf{7kLU�A@`EB2?ݚS`Zk/?-{D$aC@ Ǎ!KUZ{tQy ҜE8QV'ТN ]8mT@\) (s</g@|*3s!9~( 豠 Y}#`J@/rgNn]#0CXw²AȦ"48K""F릋@,BU&sLυJ"?." <}\"\�0? 0(߷3. ;-_W;V~fx;TJ.[@  iwRgD2כS~Sbr%26ܥY )`ړYUG� �FUD ƟeC?/6&k?@5o^?Y4|us­h šVgU8]oYQT|tϲ',8.: $ v:fđ2opUK�5$i$$GA5x#_ ~Qͼ\"( �2!x$½KAVC(Bc]嘮f`/[ BB 5.SzTx٭BJSajL!V" _&7ӫ HoKGGi\^ApZ(!ʋ3x2b3o||2 PЎU+bDqDN?ȳY]oH t L@U%s9@zۗY78;+\+̼~ӯc8F{C Gu)pGtexb/ўL3Ge)o֎}HSۺ-Oݽ\Z)GCA�٠ Ql!f8r�UoLꮯ цev >}WzᥧvDiq/ݙo*K38kZʛ?-Nedްufls̭!Xc @&ŕhSR_PPNofUA20 dV=iF?7,"3 f<9>d'[*,r) ! @89}|d T*׌P%NyUR:ωrɶ(]hKȣ>}p׮mG`^H1(X`�߮MY8kPd !>8ɥצWtw_^ކ2Dގ<< ii~m-vKn #'zJuEPO(@p6gk[֨@@LĉFս##Q@V Gi1 L.ͷ \~qZ5||rə3,e6FܗV|yei򭁈k?G_-[?a6C>?;=<_l÷MWFr̆ӮІ\@U`^z� 7U`CaLp$lUP}/`2p�hZ\xu >؈ F PoC66%d8 t宱ӁHK-V " }t'M ف9~f 1.gl?Өc jYv kuz=fWB^?L&]ac-F�$СYdKd= ?b`ظK�|[PX"<2 m�)Y,^40v%{m1LְK1T}X[}bP@d7sP= QdA!j@X[^(*_+z3/T܏-v*@PP %%jQP.d }wj}BI8i tAПEd@p�&~kAyfΧo JE �^0�T?J+'FX{uJS3k-J$:e@ƔA?Uq $*+j7ȨR(a#N{x֦_c4:,tsojM?iw@/.`q~rǶ9"!yz"ICIxlKY8޲C~PF2OD5).B5xH)'>f:= _CnV6cHZk[k*0QiX~)sHڍ%a1eNbHD|2["ڽ2-4$Cm#9$i6JGaO^wJS;UN#cW^FK,Sd9XA $(;Ao6*f#q7U0M7BQf SH[N {lncv `>:{/\u% )Ģ'.kAۓW"۰9Q9Fc0rd=([3.{Cٟaտ8u,$PH[YY4TUL.* JNڋ (Yj;/_¿~8�|5�p 08 9w~qոls?NjThN˵!w:,O}EYy?NOE[LfnPF$G@^D`P;]p3ZץNSR�:=^q_Si05NŨ¤ EfT�p4P[mh3) HCJ˴*{tGW6$'=U\6[nvFW0"B<On8*Av`@?V':q8x\T\~/x|>{ F8c{Ǿ!z&Pr%̋I~64yR:9#byt@ vs#U('h~VpfF\l1thX[z~B>daO{hpYBH ڐEYEw YjNϞ&Q4({r< <P w՘UeyGۀAFlXlݴ|dT4M%TkMmY}Z:J';`@,$_)cn! sK~G IBdx~ ڀߣh�@&mKS 'rmI !?c0|M"zeqG`̅(_3PC@8ʫ#slc%#pDu(wY]g�"ǎgڈ90R: U1N*fv lVlT,Us&3kpÍ>[56xY0p�"0WR,EƙJy_GU%\EtC6B hRAE xzs؝ז`P/~hO`2=0Qǁ"jO5 ""^*15fpD%u7U`?,7q+]sX~NAou B4Id/_JAbJ -wרd~ɵaWUvLeY2 :w3 @Yb$қvf΂|;5$v\/e3`J|uM"$aov@E IjRҰkL6B׊[vxX6w"m6!?JYTj#~ >Kq@ʓU߿f gp_V+A,hkBL~F/�0rսF1y4!ʋﭰ+ uwjYА"A.p%Tg6G_O|E(QR۩N0.>~LXpc[VzUKD_MЮ"O oQʩb݌Dm:coYtT,n:GPuLcɣBi^{_GrNEg-Wa&Ű-B!pTF.eԖ 4z)w(꓊rS{j{�Y ~Tے& 乄3+<*.�@@Z#n#Mz&<#\bK(H*-%#9p8yY(%>bN ^ϯcF62l+TyeB,3M 2}rn)Dn=aE1\:?}}�S BVV=UAv BF V5`,⯶YfX ||?݁Pt ipҀ6qQ]ss!WarZ[F9x*�%!!�݀1`<4Rp8S8P%>mW3h﬎bBaBn<omq2Y!I Aτ̎懛H *@!z!?vg|B2eھq] ´1)HAdj21mr0?I $rqn9$魡&֦p%|=Rn⸐n-bTE)R @;%7`r *IuiVs�99L1'@Hd�ՠ5|4ZoyDtM1=_3fG!$?!>uUi-T}MuHH AU/<># ٭pCFv*BRDl,?f!8"4vC$ 2˘ށlR*:Q,pk�kJb.|4 @blrP}z{*o}; L\~5y[#ࣟj$ CZi=>W7Џ@�hs|-�?hdMulkyw ɾ{˗܉Vɭ$n:}mE i{,XY>N i�'* ? ;ƣI Y߂e~UsObX@ ogQz㝐 RcYWl*X~q�ywi�,++|¬>cXSfV3Hqɶ&4JILq\s @\�֖�"TUgغmguz<V5.vV$aF(4έtDaq0_N}F .,^8fR�)zf@Ȉun*h?wVZ檕Uj`Ͽ]Gc 4yX;o}M׷ Ky S(7yY WDXxBpr NV]Y*fەxܨG68fGuML  OLnI> 3&)_b\F4lˏRA ?H?::Fب={{콷?w* Ԣ:h%^am%JPuΗCxn/3iol9e9xCN,=gg$Q{9GBFщ 7^$~]kt `'@ a`jtjDGN'%$UyZ~Bov/" ȋǼVqhȍqM%FsܗݯRN($ ХDXD=lIοG<Qcmm\ҷT?q f 9ɶk~0w=C�NU`.U50SKQ ֯-P~o J8nuDO3ra1'8�%6P(B�n"`Kf}ȣӂ?p5@y v~ [rlQԪN{V9k1=Qo 6\QuVJ;џkPEbTqoY9߹hXR4_ &Xb:5 ws?B3 _rɰgB3 76n 묍HkH[!wrӓ>/>lWD^ΟMoӕ%:[G%X L} kWhʔKOB8 3Ҏ˿ys][rr<ܴCN:sU~pkp 'V_8?1{jFZ[IГƮ'!~ь4gxGY|Ҩ *V{"gQeMn`_\aOLiwj;}j}?nuG%7jys !]<{̷yDWhH٬Y6j)0PX.u~8(a(&֪ҕ&@M-V$ dB-~CiVC�DhrBf D P�liA $�|C,5%ϰ y-{/{ȏs#'!R1y4䣵XH7=sGc# ?|nҝ^Q7BZQ^ڔrp$TjӨpx.XeY\䫿JdnMj"z]OUwbA@? tҬkPibj5|-\5�LTܟ / _i.Iu^͹ja[b"kM oVj7]es՝.; by_fU`%h!aH_5ޢp K< >vlzz מ`.i烙e_;6y+ђNV^yhz�6 Q> ?6]�Fdtot7XݷdiH3ji<u9Wcڕ"qgZ,| Ϲi�)4L1ȓsE^;'vRH%_zm#kT\Wdύ*M*+ލ 8O I l&j)}YcƗ*cP9/߿0? 0V5rI.Efwh}qgaxHW}fb|Lϸӧܙ3g܇>ys/7WmݓڵkniyŭҖUʮ 'oIȡ <ғ?75~e14?XR*`|[&va*xN@ LE2OgYIVe2�Qh ZڡH5s%#in/ -}.s!إgT%$ZK!FpO+s$!bX?<b\8 أ',`Sf [mP[.Whr`UO05ktLY@BDFl41STbeW 'yXnRm[)vge@VMJ=׳ I0_xNsm%@R<<S[Pq$W<X4~6WXfyUGB=E8gR>XwRa5ώJzRb׭<xfG%](n`]@!D wd)HzHw\iFAv#r�&8IV5G@ 10.�ͷ!o*# 2L}fXlhfg_BTx/]u zе͊™jfB@i감RErp}LpѮw>DQ;zpwT^qK,3p, І8  #'*D̵7XItO#Z{'8CF|FphI4Ʉ G-N/_v*W?XFFwӬOqܹtѝԓ(M\շZi_][\^rkHL1zc!D޺>5epS ]qW8*F7fM +\Dw#yf8]?-v8�{[akkb:0ERq?BX V77.|9 g=?!a"avAo_,AC#}@?׬o(=Oa+3ڛh8{9ysc?6�+" DgH," Hį=:>uyHD0 PBUg B[gGO bň )[q?> HcC7ּ:3eF6ɺ Z7~ugc&/QOIЏf:44 eh�P` AޣUY'DT.I�>ڈ-!$Y]guHʮՆV2@ZF*"m}pINA.ma|܄|m{`O`ਏnlc:]C�U`p�/Ku˰8_()jg䖎 XR_>IBi_C>%o[|g-r_e&* aB8<};&ŁrG*\@5uiAd"+ F6|o.Ke^* wJ|VmӋL,!렐>",k8,m︺#mXT(Mpܭkbc:3 e1?uN;~h%[rXQAk_q�%fD @_QG/ t:5>?4H2jqQ!q?=ܦ*B<B?AT rI`\ݝre?)~]{qq~~F{~(bځ: ! 3Nf8�^qs�iȯgA'i3o.9ϝpwO8z:MAgz C )ℛFBC0 .Yu}a GDŽ93?q;?(U�j&2acx)nI0ꕅݵEA!T`�6ӂ#뾮̮8pS9\bu`vD6"l:'@*p? ڋGlK%104[Jmf i?jTyu!XVFm/M7 o$?:i�rϨc?즆7ʐ*.GAN-2G|KvTiBbtVY�׳ ـH]V_T5E'rZֻ]݈X])d|;ކQlXM?FQX (!L`?|fz=}cɅS.A2U��@�IDAT_K/%zarm.�tLf OhP3 :�,FYVVSO>agztLHaȤʣX2@5,/͍mf*vkڒ#xu0U '^FP )ˈ[ԫ4!Uynm ,hkpuf\@t% Ö`J4i8w=]�Zɏ=z,"2! >]ΰUpge$HeH kJGu?ɟC H۪wE%Q]v'6it/WꕋPd4Nb.  )Ar8]FW0PB)Ohn|u,"0N"YGwa`U>wۀ1WlB$3$Mwf8KN6KEW]ltu>_?k6Xs9c~93>9fff9w̼E{gMH9o^a#Cƪ/5�KKW]iszY6M$$ R|i}νo. ^ա(ܧM!X(Oh&"{o7&KBklG |v7#j!1Ӭ teoyZ&":pb'�s}LŔ<wzWrZt_іRb7x`Ϣw `Ĭm c7X֟x`cT=bo :$2m}m7`M! NA)d5IF}\.y�lB>@K~+m'N^6,S?̎I #U2f20HnZڐk,vVVhpr3p1⁤nmO53|]u}f2xYV{6쭭g&?m ! G K|1�J f૎SB̯Ĺ[Ցn  ޴KmU51l:Y�UH#u)%iXbbyefew5K@<W+૷j=JQStd9ci8"Zj_J.4Ys^ F2R⁩x$جG@\fǕ͢2gVhfWCڔd`hĽ#`�.y}7FQ@I:( ˂u/"J ؀hr.�%Y2Ωx'T۶dڧ)n<RW^DBH!HRq<?Ho *3pWq#XWb ٗBx� �D�򶹞Q+[Fxqڝ匽 ^ho[ہۮsGV`?&YΞv>IW? MdF<\ _5:7gv<u+`rMLmd c!mBpCfpK#� Ɉ]; #%JSbhLFpv2&vTqqiVr�* 1_8|vĹ5w)Um@'ЅPA3DUϢQ(Ͷ*CQ0f .a.[~c8?Y^q3snrMX' � @D5.*'Bf{c/ =rԭ]?DW%4] $a*փsPƈ}v "$㰞ˑƒE nDXu+b0mjA<[jD@k;M_{Vg8AZ>00(WHH~,[E#if:>L;qzp}O=\[e]gkr[&r H�A0&rswylWʇу-ί= uٲ]8!Yr ]:c|<g!=0-2ՏIrvE;FLj}R}ș2Ϭ?CʞrΣs¸apzʈ+soJS8NV5pD�(Rji kb뿉?7^wz澝"@I-mȠR}r-?> jzt7GJΚ\n9/V>v\f~[ Y!bѫ�h |5WXwUQ�đm<z2ۂ[5` /T㞷IU,/I L\(/M4dꆻ56n) �~^K |:?0Liɤ_Aȏsx^F `'e׬2dnC\bv9ؠu@YL/.a+guULmmЖk[Ә9\C m@7 E�ɽˡh긮59@]^\@ b ":Tjw.aj�*E`=4fE tÀсcԹ(.# H[!2X2'p*eak40Tc}{iY$}s�J>.V5HEcvu*`ͣ`VW> >΀>Uo<FD g/45Lt#epP@?< #g)71;f>|y`~|`P;S?7MkL˄n}Э?8,/ mv<  %*YN`ݝ9ChL`lbQUag])*Y ڐ `-e&Y>.8Ը}8V8e]VLT?-HI4Z%sD�(& _U�pxz"~`QuF[Xw緱%"/[�:ڿ-bpLCPVq#`(`2Y: آf\q"]#�pެIru QWvqڠ.X&U`Oշ'P\ Wm&F녥2(_ҍޏa#%"xf9Xmĵd6.; H@?aG&ccQ�Ɂ4`_YU3-2{L< UXϳPqx|kɡ!N[U߾20lY/Xg�K&`m%'3$`3mPڊ+%ג_⤬CSsp�\a;Զg~n ur|mթ�+oSm-xP�*<ۤޒsߢf C߃))ҩqOU7c?s[k X;cet?oS�AUhe�O"׶.iL M?K{gkXT5 TͤBxKte[:FwW%Cle?͖aCiQS$.<@ p�k�r p0sR~Qi'^2E5F.j):yoWuC`KoEY0 }Nbn4�*9Vmi2V,Hyen3ܣg"5a%}M$Fq~ ܯ=sʽ6?,bOWkVDp4?F']q|O3ɿ+4ҾS tfIv\, >A�n! fk_8U8e8�>+`%XW~.rFi͵+P jf_aS Ns@HBܯ<d[q5 Ȅ83nL,\ؐf5vV+yS`UASP,%F(4΁9�5$]7Wtt+Ϭ?h{ $Z˺:˜Q㮏"κ (e1wV@T+|\4d/j?K�HԎk6(HBP gKħp6!Z+%.O�,=i=/ ϽEkh]ڱhV K/@M}}ss=0 P*.j5_osJ[b u#t^ }muu@wz0hiS^0iF?GqE�}ϔFp(y|/f ثbm'p((tU*H["퇨H{f}뢛Z%9�2DiG@a%Xe}`gԦn!v8V_Sok@p/6e3xE"qs<!H=;nJޱ�64a _';~` P^0U1LQtѸYɫ *_C6c_km7 ށ0UKXoL%aL3ߚA5Sy˿̓9K|ssn!ݓ֢28ж0io[kmOB2ax % }L4 K/֕cp9�RRd|AԄ ?`lP*[`I6}R˽gE@gi/.dOK^r/]~^SEh=,B%|w%Jwd9�QՑѣ4`DQ3֪ Zmwd=z>4JF*O^~Xhuugٙ*$}vꌀC ?<v4 =ot?knLek8([\7C:~+o ll.=ZiںeKz9vlC'<2Y ,Ƹaw߼b`$�`SNr -$4'P@igB '-d~_0 ]i\c:~Ԝ /B|Ò +e: y o3;eP= ocʝX"2~ R-s ΂$60f#.?>Sϸ}ӷa$_3("NM, [ ~t2>&5uE|Irkcٵ$FB@R`AU>vk㊟>_:~0 Q~x ύֹUtRjZuazpNנM4P48 tXdsN@}sl+aVa ƥ=aI-ȣ,6]eW[*mYI/WHl>?~EàmbH m_H׼å䶞3WZ-iCGu#jE惢y߷]QZƨORj-9ꑜBя&2>3StnB|\�\ Aޱ8>s@46TguD?Ue3\uZcb:@*FNAehlt'X~yִ 62lG#J"lެ3Pm=\>ԬUcGЎu`fsN�M2NO\2 ML3&~kPg,so&j:U`�5Zn .̡ׄ4e / ?t�ۤߕ`o7~&ncSuVfe`#A{pSdxPp8(ZX25`bUեHLf#puF=&ޯ2?`qf*Ȗ`c*BlkMaJ�!I<ˬ[.)d$Zk?yI� Aۄ�t1Ną;=_@^M}ي7M` 1/]n]`@BLFUv>Ige!?-u2p\bPC#Fp�ip:Vm hX~m #QPѺTaq1l�E(da4?yx!? '}igMI 0SVB!NY2$I3.7yθ 8<L 3A`PP 3B=KW*k5~"UCܬkn^s !"4xdH1H0-Cg\�0+7A~O:0%PP=A7q\5Kj}�Xy;5PUР# }=Ccoo-`� F7Uf"%!Z6zp5ŶT ~DoU)Gi-̃eWP\|ڒ |$ *@atQ`5 ˮ'%yp GJBVg{U>xɝ8҈(AJ+M[f|M"G7G WeSa6"* 3ʣg8[xy*?~kOiI,p}䶲i[+0 3.d'8qtp^K<~0iEx+U}$j<?"�qwY ºW!w.#c/iOfUbK5B$s)al._oK6~)Oρp8\R)>al#%tbrm+#m [닮vTXM6nz}ze3@c X|Š])|/D:_塛VPNUb旕gkR<3B5[? 7:YwT\Hu8Xҫ2�+`B4x}}32i22^hro8�/Dԗl{NWH, �JAf Šܫsnbl܊2@ۡ@v! =W is⏄~J폑_i}GKYBͭy?rY TNY9�+ A^%W]K.[ aApzvi 1@x:/cZ!,VۧgLH[7GkD7֘8_tH$\ZD4M[Vh6[|$�D'@ A9(_sT&? 0i`"`FAl_aȯ]�Su8HZKNk`]ZZ7A vlI`$<H;0y�}m2]W*?<Js="V-wK":w'TVZ]Gi@&& G1 ҺB?NIws޺( nQxKL3ʉ 76& %mHn4m`f)[ 4V }lMC08k:C7D`0{h"88%�G~ 7`1DG্4?+ KEgB@".@| !(; Sk{2_KS%$'g2(6܋MVjaBH;PtvTi(4A_Ӟ% ĚU4xbj`"uf"6 36@<\2>u8p>.~lb5)tSpdJ |]CAgCtSޖFa^dFч&;I�t`GaҖԩ[a�(/j8E:,Q` Dy/ qa9ABIFkG4BGn-WJ4> -b7D !vYBw~�Qb^$?7yMf:@mK V,ާ m1b EJm?'�Qqd 4HgDͼIp7R`ڒ^~5sGJ-O RzDd�4&_k/͹/kRpRm6N5jFB˴i λXv?,�-�^?<}Uw O?r9+ѪK [(M� H`򅬺Q.*AuhI%N/]o|6TaD<po4zGk*?{re&N2C5o$b|ѯ-@6-0"i|S\Ceď:A|A $ȬWI�B@~S1?L �m`;7^M^v-hI۽?7]�Vu\22 PṞ -5Ĺi -_}�ܫ:ߐPI 30 *&8 V5cؖf@.o 52QwG7 z }kϢtUR  k\YYB$?h扥ʕ(l۝ 2 ѝc(MY~']]C xm@�#jq. &Q`۪;�y{.W^r͍kHQE(&i" 8_{ b:4 '6b!ŠlCS ' A흐FϔΈ‰u~;xyZH7>#FF VI pnP00rCͼ/.WCBxPar0'EGJHp!y+ch@3?+ =m{HqL)B,9rƝe,j+?Ո@Dnp`PZ;Cq<o� SO[~m I@)$jLsz&)W}o@YlǯOݽiJZ|{!ExJ|QXEinjp.˻!�ebAJŽ;cRTf}FW�z͌=@H<Z,`s4`9U| T|I;U_RR]iHjFuN 8"�6?  c$EV,OL).@@2 0lUJx!2޿f|׮wa]A vv+%`\λP9ɤtD@óMqzd; iHȘ`S$i' ɧnKݖFƿ@?*]�^b0+A6D)|tqi$AG>P#5I LJ~vVw�A>ixE+ n^9Fd@_&]XbC]Hm h-wHvIui 2%ۅ;2f/P PU{K no%vR 5NO̟ww/&SP< kYRg6gcMp!Z% l "~9 ˴RaC(4VnoYYM£o.� \AޏCKJP7gOkF4NZ&X垁]׶ rsTݝCzdN�z?f𒻋-A+L`)R B0<R?ymצ"rO#q|^Z{?KM90П JU 2f)G24tg!+4<CP|k==iƖaAVsU$Xİ+n$ږ[zEb9 Vs- ƍ,ŋinEoRfqxo:ѬsڢD'Z{ <mH"m '=U.�Pwsىeh",EIZZhꀡUޭy^_s�;Wkz$xiL{߯S6sG*Hb.nm :<Ҥy98!:'o4f__Zij~i к\B@G^䚧�SfG!n[ tKѤSũӥ:%ugc+.$w WYt?8Xл]H6f@a Sz{e�7*p9֔Ȕo 0oI鄳Xgp6%_^t(( dWkec)%2?bUƴ\Z5I_amU`)K tÓ�>5tSYgMmU (8j|[5EQ5R`nMBxWC5`xxSM{{&)»XهC @LAKKj:xBiV FY[\iiiJ9t[K>AoP%?CBB!<=}6݊bk83c_S.3@X}X v"� qi9 Fq-N-D\DCK0@:#+ j}�pMO�ɘػjVJV"Dz1jlQ5#)a@~ Sû{ᮖs*rf h!ᤦmW<|UES㑐nU`J&B~MfY*Kg>ފ= ?b Ƅm|wmd'<gNK(K뙫ƨ"kb9g5`s Yi˯*.�` ʵ9؞syHHnlg /t6*_V;(Jd[K,90='�j|KZ(@ժ &E|FZZ,MݷTnaYj@3zb/_MO Vy_A(aH&SJT}Z9t+ m;SЖ [*_ ŋ;iɸ(lkQǃyZe2xQ$&X;IQ'̏F=l{G(Y�u/nF5?zg6D؇E #Sz,i# r3}O06B:s=݄pC#}[Ho:<SGKְC4f4v4XRH:2nU^q: vt4}e`P JSGѣ55[v]b"Vڠ c'܆T\^q9<3Iӭ lk6�9_^ķUp+<_h`̅2sݼ+_wBwAR꼜B$_s͕`W� D{ 9"8l %}`Bqi)}?z-"x\aMJ41C mBXUF0:d d$|7-*?[SB+Hu0/tt9p$ ev H =Խ<qr޽QKHq�aOLHzt T0a> 6Cø<|_˄w~qQ,bG$VSn$PZ}H>hk ycZ(З(@>(N+Eaزò,{.Is.)r{;?Μ3?Μ9s&Fk`v�m96~`4R+@0U<cl$vz5|qD'K5]&b_Pq _́xQN=f}HmRXPLER]}"9❸8zD6%Lя??s} {gZgCC5*DZFJ}%k|6PUee'eh�67P j:f'H(vVp`T${{IG'17~?ۍ'hj?k-@Q1swC)nA=~7~ZZ-8:\?bgxӚL1H D;w)mZ@YD^9e'JҺ9: нT{r2 -#Ċ( g<V�93Y_hRY�5R;WdbHbG 4Lq<P"$26E锧`Զ&:Hφ7e8t5'�cqC{9͛l̫!`Pب lUMlt>~yN0 x[wEfr Ǎ?om@ Wil. G[ӌs}o Twl+Cf߬}HQ=�څ&ҜwW Gr[`U`j-y+o~K: ?{O,] r1 Pݾw> 0\1%I%*~^W hiq2Z�C]]{0G^ݣ_w_aױ @lG *hguY]!B;Z;ogzUr*n0mc9d>e r�N^5="^j%fe`ż@J8Xpd3ޔa)ݚ'M$ <ws,|N\GTJ!:i'$td�6'*MKRыA*t˦�pXB$r⹿x@bXgyTa?=l#wA>ٻ/G �"@`  Ǟ 7}� k7/!t &1Ω?sND!]soHe݃jGOrEP޹9TJy0 RXwN?yxM\f(d![(Mm5(zdXq2#TJxreXVzE)ԇẽDZ<|:wv_5Xy3=ki-ˡ� $H)݁ D%xpK2#!�[z [m척b;ٯJɰ`, e(^%!eô8cQF }r8@'0,eD=A)xGf b#C_|98Qhu%T.)rWEL8\K䟕+}[ XvSR]{l4xdQ$,o1Ukغjٕ:^g>ihc^KRjAjGn̵JY.`sxk^[vy8]qcX7!Y1c,j7?G8CR[]gaoc _|&*4R0ϳjڽ0JaEL/SpuFyZϢH>-e3"*_k-n 9εO⯌`eV,##*1<=t&N k iPp6n0% #  *9~2Yc)T3l$Q @%?̠7 ='qf#׍[! xqwtz{~.yr?qpmt (ziTh)ϲ݂`(u,lǂX$-$҇VC^w,3P TWiݾiϺ㐉c <=4G?&Ur0d8�ҧ�!>48=pVN�8T GښF@ӔLrJCh%,8Ϟpt?S z' { a+SW@PeV u.٩EJ$nF'юC[X6 &9?z}$<=F{&3lĐ~[(Uz?1#o`-s_~+̱H3'9 C9 Qb 3?y�kޭNWA/&45ۅt�Mnvʢޡo,. f4rx3-VR==fI ^`u=)x[nWs�+�Zl뙵V*!e7HP;D`={F T;?e48�~sgHr*Ttj*PTA]ʾu1qK<Y+u R�s~_ĕڝ.ozϲ J©pG9W08JMޓA&蔄Ѯz^+5hfyVQNNޫ[LdJe�8&0TY*fW+(͎qU?'Nd_w JC"uJMu|O<P, s IFiMo *+ D鲒|^SgO nU>G(�Ȧ-IK}GrtyD|8z2!Fe1;)n4HSHq_C@2&j+&#*HdT8.tԱ:":Fi�u?9v *zs9m�KoȽb(ص (N5fBOE*F{~sySN#O+\Dh-Q+�Ŧҟy?5z2J7ޕJďD;$Z_uǸ­FیƽZgWR9*VH[VWK�zi8}k6ok@?I(\v_B3󠊡Jb/+K\Һ$9�@u,6r?LZB߹ӡ:q @lڀt8˺hl44nܷUIPb)i75.;BW+pF uUu@{Eו˴W8�,@o!;~ʲ>DDuSϭmt6rrGkQHa#~0dG̚-@OZq[$�ш_4@l,?w?t)හ2zR:#Y)VvD Y1CE)@$gS:}`]UR=4mE{粷 �e*N{K6("Tu46Z[AEU|DI*McE?*Uj*S`{|][v3eK_@8^0kiXZJO] .~,GUфU5*ݦv0'R?ɿ�+m˦:P$\3 *^[,XnrdeOaZ9!SGgCzw*T6Ydi{20iz<\W�cElPEmGڶ)8V`#+`Ҩ5OJFZҺ?ד.tt:,xu Y f_@?  O{$YӞ\V *Ɣ[!i[V)u6*d*>+2I$C!jkmcsID[5Y[ 0A A 7+A sd4_*Ӳ>K�Ӏ%zi*c]ݻ ZZ}FXhʓ=y`x^r4A0}P zְr0CSgXyپiBX3,H3J7<^Cwݻ}h˽e�R>U5ԟmDA[3Abr 0A >f&Bp|_@f#�hi@9Y# n9vI6t�6$j+;:NiL fZy*w'S;G�MFTVGi2^[BL:.% Y bE`w7BOK'Ϗ$-CYvV5o84 09w&qmt [9,n�W\ 5!ZcO1`DX馑nvQZmĶk >UL7w,n|4L.��IDATY}n Phޯ?iĨH :*HmoSp�0KO5|69: @O`~/rM~=eٺKrb`S�ڱ" \.3'PeKf}±ъP\sHUVV}ߴ@/oe6{&Mk HS4>,p jFj\PcݺuWLi�+e mE_۳E<gߐ?s}SFV{sgp.`[&`{eUc QS[t@e:W}Eg?Q>X1V�zexcHVM;z?L'I_۩= n@݀:t$&'!`/7e1F=l}5ChN3=js@=Hv2TP /4jNk\'GNaeDxǺMBy,;v$򻛛@ Rr�Y㷛w^o{Eo�Xh.:<3ڵk0oѨca׮]ԩS9oIH^|0<<{UH0 xWÑ#G:'E-8ۜSnѣG+bmNm5c /pYN`Jq$kp:-gĉM"?KGp0::ffXcN.a a`]رcGφ={!ױ믇&z2J+=ᩧ2d=8  1 ҥK̙3]iʩ1PY\CZe1OnX`k+Wwv}4tM$DWr  j},'ѻprDr   *sRY0p!Z"KHHXh[Ճ  [ hkLR% $ l é/TNeLH'OF{ =r`<+*a)a a`b6/?my)Tv[V\@V�m>==ӧ5)/^y[\ 7x' vÇK`iи  /h:4KR;8Vɟ00a:ofp�G8/( = 7<=a a�mSaO~ZAݒ(d B|$$\+  �sk1m,?eb& $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ld.d&����IENDB`ic08��TPNG  ��� IHDR���������\rf���sRGB���@�IDATxi%uo}ٷ`@b@RRlIHSMҔ>ȟ|/7آDٲCIH l}03=KOOwW׾}##_WjW5]UQ/"#cƍ7n: 2d A @ 2d A @ 2d A @ 2d A @ 2d A @ !r]qeh;7ae?@\anǼNvLIsy>ei!ݶ"Eyv~Sǂv͊msm12s/sD D�n 'oR\(M~2%a=ꗾ'k=C| [{ն8=8g¨)4p"]kސ/QS2%nǼ;>wH֦Լq~;7:ҧ9oO{|.Pȹ):~בDz,=TvH-'˗A uAk_jˍ/J ukN=g2dj)h`}\,05So'@@l/[ @,}  q~k,=n8_ P%%=q'Cܮu)#Dt"bpmKKqQ۬YqU(]N͛,/>%]Hom1o2(}tE)qy2Af#miq{A:7kϹrI:)#kC]qWT'B9t. >4%*ג&'Jl=ϬΞ!o{ۓ..O\8 ey'l=qUGc݇ =OZ^\"M { uagF&cqddXe+* 31$m=FCdUFu7u("]zҥdd86N> d!.)n2; zʰL~2ɸɛRU,7Yg2ܛgqI?}ԥ(ճ-o(?s q۟ +M.2ztrCddgWIE�J"q.iN}֡Бddŧ7>aIBPv]yϒPVL~25/zfia% ɰB|a a Y<>-oȐxfQid%}w/Cգz#?E}2mO\j!}C?5ȅI?iBe2-}zړDWd:n ½B|@ {z2,:,D>{>%ӆ^_i}5#e^?<~+n+\3{󩶥ۖ7*8ɺC8YW22&Ie6ܒ!5%k2>8o2}'Y_!}:m~ȾAxkZ?ݺr'g\nh8$ n4Z5׬,0.F\.r=Pm%�(>=׾؊*̞e A`W{uZS ~]VWW]TrF n \XtpnvvMNN ۼm^dgd^XXp/_j}c�n͝9Ò=ӿ7ɦw�fЌOUd,A 1ȈG ,~3t#&�oiiiCd~ Z n~~^ |M]2+ ]v?s2L\`}!0=�f_7/s2Lhojj{LJ3gkҳ^eHB�yk^<}W*ۄ|Y8@�w3ΝTlK.ne] A`pkkk{ ,]gq2"@@�ܿ5I,mdyXpd*E {@VS,Q ' b{^j֛ {[,r.-y! =~4w|AS~::կ~I s2,^xc߃@8�+| ^QVaqwu}uN4s� os=swg@Rf5v?7>`g2%x PH/�Bf/2>+OyzuÇ&Vpmyy us�W\6HQom`&fA xpGL#+`;�p ^z%O| dk7 @B%WMFe_. g 6~�!]pVۇ3g`!ШW q7]!p `}}=n\'!i!-6 `X~!A褿te6A|�Iy#B8GX.#pM(%xs�jT_6/mp ZQ %w* چx(7 Omꗸ?ʧ`2/A݁p�i|(W-_H]x`q<i!? _Kj >Qvn8Џ 1E\(fzCѬ??k9>vF2CpG҆#suJIH_a7PeD0Oqxu�D�҈@qd3!oNBdCj!<1PmU=s- D0xܽExd-F=5Jy=ޤ[^d""U{Iws7nVvwHkkzn$rL~=/v=*֘y&$ 0!V U3wt!00Яk_-`yD Y #j (ݳQUuC9Y/F3~84@�b I~K#[Q, :F-:(*%sU#JaUJ@, H_ZEJ{]k 5TasyA|ָg_h:w @X$8:sH2* BB]ZNj׺u&M7 w׺#n:}V%z i9N ny@֊Hfp}jMWW:r�ç͞ گ hqK¿A{,/N@X�'T*8 >?�?ҋ{ }Qp�`h{05_b hn;Rı| WAVp u?q#j ySۄlV3w]HwG(-/:9,vxu$rDy\N eY6Z˰c% @H"Sٳ=A ynOh` Ez9aL 4kXJ?\bigA7݇쾃J^rkmko'EV +[%W�umu r#�Bg:aw, ti/`'AiN~i`JBYig)S�90 DuU9@%ɽSvK)�@m͒^3ʹD+un NRIxq`PSEelein&C[֚@:P /9A@N^t 0 0j+H|uUw<>!DQ8>*d qmposDpY/ h;P+I .,?{̡�Q6K2w}"!.PҏV\e+X#߇' 2Cj(<Jw3JD"Q!.>i͚gY~' >τ`ZKWz+pguq%bv]eS^Cݳ~[،7 T(eb H׺tZŕ!Iֈmף}Vd Bpy"/ 18l<1|T"2{oUH> J<ⲳ bhM !00Я1bS_=^̲!~#1<[wh^,e@$r"m*z-l3rw*c4ߖ R\r9`Ϯ跔\85tVdbMtzcRT?f^17}%ѬRי�d[v/@84i*pλ<{şLv'R93u 5J 2X@7牲uhvۂm)Z}-<@� c!2%q{/ \cW- *  I6·en7frqB -l1"޲cz`mmp.\ �B"mb #\{J owqo{~1+\:sC@Wf Pd^?)H {$Dv{` ^UKj ?M ZT;(xgFa# F2{ Q*\%~kĿƵUX /p{釛RmtWE-�\\LjfX8w@5HfxoB$_ia-?d�HO!pٝM,BzL/Pw*To\l"( fc%J4dRiwG2N)HZ;CX?;)H2Fe$Tpu}i�a)0_ȻW^1vJB##" Q_'4ս9j\8�0?<ZLhLψ>lWq:{= ;a^2 Pȯ>k{0s#!ɬbcoޯT`vD"}p1rC qGn̷ZEWiՙ @&YߋI W2Πk~fVA/._?,R7!�W*?n[ P�kL{IvPXЯU~W�f ϱ%w;_̑ >~p޺(z]ܘr : '̀ A 3EڔMW!fX)KI=C43i-KK�Y {<Xww} ̀-_R| f8-hNj@T򵚱~+-9 pr�?7e*;7D,|` K<pN'*4=Б:B=r@&:`I-+&84 ҄)iɁ\WAIX/UIytRAb? f,4HрZU#dVT}bMW~eoğ+6ǘ9?3aI /Vz?!.'s$ᐑжu?) b,d�BL@_"S2=4=I@83iP'_,'i()>;_Ȼ"�1H,&@H%'_H%12JŽ!zt4ʷUi?}3 #T[  aY(e΄Ѯ~H *ܻ A'fB g!<kJ}VpKJk8rBԴKBխ>WyZ)G} mQ:<|0_0ܻ9�Ez$*p0cfp2݄@ ]Th[Ƕu֦cQVL鰶pաDuCtSD0f8ݠai�%YQpid淝~@[g`'UҜ'QyTkKgۤSk9%+]2)Ob}{eg;եn67(9~gVCF_M/ 4?s\Olύ+ɕ@1w=R]'|9?{++OmIDЄqI<\)| ZFl?%hèзf{7kLU�A@`EB2?ݚS`Zk/?-{D$aC@ Ǎ!KUZ{tQy ҜE8QV'ТN ]8mT@\) (s</g@|*3s!9~( 豠 Y}#`J@/rgNn]#0CXw²AȦ"48K""F릋@,BU&sLυJ"?." <}\"\�0? 0(߷3. ;-_W;V~fx;TJ.[@  iwRgD2כS~Sbr%26ܥY )`ړYUG� �FUD ƟeC?/6&k?@5o^?Y4|us­h šVgU8]oYQT|tϲ',8.: $ v:fđ2opUK�5$i$$GA5x#_ ~Qͼ\"( �2!x$½KAVC(Bc]嘮f`/[ BB 5.SzTx٭BJSajL!V" _&7ӫ HoKGGi\^ApZ(!ʋ3x2b3o||2 PЎU+bDqDN?ȳY]oH t L@U%s9@zۗY78;+\+̼~ӯc8F{C Gu)pGtexb/ўL3Ge)o֎}HSۺ-Oݽ\Z)GCA�٠ Ql!f8r�UoLꮯ цev >}WzᥧvDiq/ݙo*K38kZʛ?-Nedްufls̭!Xc @&ŕhSR_PPNofUA20 dV=iF?7,"3 f<9>d'[*,r) ! @89}|d T*׌P%NyUR:ωrɶ(]hKȣ>}p׮mG`^H1(X`�߮MY8kPd !>8ɥצWtw_^ކ2Dގ<< ii~m-vKn #'zJuEPO(@p6gk[֨@@LĉFս##Q@V Gi1 L.ͷ \~qZ5||rə3,e6FܗV|yei򭁈k?G_-[?a6C>?;=<_l÷MWFr̆ӮІ\@U`^z� 7U`CaLp$lUP}/`2p�hZ\xu >؈ F PoC66%d8 t宱ӁHK-V " }t'M ف9~f 1.gl?Өc jYv kuz=fWB^?L&]ac-F�$СYdKd= ?b`ظK�|[PX"<2 m�)Y,^40v%{m1LְK1T}X[}bP@d7sP= QdA!j@X[^(*_+z3/T܏-v*@PP %%jQP.d }wj}BI8i tAПEd@p�&~kAyfΧo JE �^0�T?J+'FX{uJS3k-J$:e@ƔA?Uq $*+j7ȨR(a#N{x֦_c4:,tsojM?iw@/.`q~rǶ9"!yz"ICIxlKY8޲C~PF2OD5).B5xH)'>f:= _CnV6cHZk[k*0QiX~)sHڍ%a1eNbHD|2["ڽ2-4$Cm#9$i6JGaO^wJS;UN#cW^FK,Sd9XA $(;Ao6*f#q7U0M7BQf SH[N {lncv `>:{/\u% )Ģ'.kAۓW"۰9Q9Fc0rd=([3.{Cٟaտ8u,$PH[YY4TUL.* JNڋ (Yj;/_¿~8�|5�p 08 9w~qոls?NjThN˵!w:,O}EYy?NOE[LfnPF$G@^D`P;]p3ZץNSR�:=^q_Si05NŨ¤ EfT�p4P[mh3) HCJ˴*{tGW6$'=U\6[nvFW0"B<On8*Av`@?V':q8x\T\~/x|>{ F8c{Ǿ!z&Pr%̋I~64yR:9#byt@ vs#U('h~VpfF\l1thX[z~B>daO{hpYBH ڐEYEw YjNϞ&Q4({r< <P w՘UeyGۀAFlXlݴ|dT4M%TkMmY}Z:J';`@,$_)cn! sK~G IBdx~ ڀߣh�@&mKS 'rmI !?c0|M"zeqG`̅(_3PC@8ʫ#slc%#pDu(wY]g�"ǎgڈ90R: U1N*fv lVlT,Us&3kpÍ>[56xY0p�"0WR,EƙJy_GU%\EtC6B hRAE xzs؝ז`P/~hO`2=0Qǁ"jO5 ""^*15fpD%u7U`?,7q+]sX~NAou B4Id/_JAbJ -wרd~ɵaWUvLeY2 :w3 @Yb$қvf΂|;5$v\/e3`J|uM"$aov@E IjRҰkL6B׊[vxX6w"m6!?JYTj#~ >Kq@ʓU߿f gp_V+A,hkBL~F/�0rսF1y4!ʋﭰ+ uwjYА"A.p%Tg6G_O|E(QR۩N0.>~LXpc[VzUKD_MЮ"O oQʩb݌Dm:coYtT,n:GPuLcɣBi^{_GrNEg-Wa&Ű-B!pTF.eԖ 4z)w(꓊rS{j{�Y ~Tے& 乄3+<*.�@@Z#n#Mz&<#\bK(H*-%#9p8yY(%>bN ^ϯcF62l+TyeB,3M 2}rn)Dn=aE1\:?}}�S BVV=UAv BF V5`,⯶YfX ||?݁Pt ipҀ6qQ]ss!WarZ[F9x*�%!!�݀1`<4Rp8S8P%>mW3h﬎bBaBn<omq2Y!I Aτ̎懛H *@!z!?vg|B2eھq] ´1)HAdj21mr0?I $rqn9$魡&֦p%|=Rn⸐n-bTE)R @;%7`r *IuiVs�99L1'@Hd�ՠ5|4ZoyDtM1=_3fG!$?!>uUi-T}MuHH AU/<># ٭pCFv*BRDl,?f!8"4vC$ 2˘ށlR*:Q,pk�kJb.|4 @blrP}z{*o}; L\~5y[#ࣟj$ CZi=>W7Џ@�hs|-�?hdMulkyw ɾ{˗܉Vɭ$n:}mE i{,XY>N i�'* ? ;ƣI Y߂e~UsObX@ ogQz㝐 RcYWl*X~q�ywi�,++|¬>cXSfV3Hqɶ&4JILq\s @\�֖�"TUgغmguz<V5.vV$aF(4έtDaq0_N}F .,^8fR�)zf@Ȉun*h?wVZ檕Uj`Ͽ]Gc 4yX;o}M׷ Ky S(7yY WDXxBpr NV]Y*fەxܨG68fGuML  OLnI> 3&)_b\F4lˏRA ?H?::Fب={{콷?w* Ԣ:h%^am%JPuΗCxn/3iol9e9xCN,=gg$Q{9GBFщ 7^$~]kt `'@ a`jtjDGN'%$UyZ~Bov/" ȋǼVqhȍqM%FsܗݯRN($ ХDXD=lIοG<Qcmm\ҷT?q f 9ɶk~0w=C�NU`.U50SKQ ֯-P~o J8nuDO3ra1'8�%6P(B�n"`Kf}ȣӂ?p5@y v~ [rlQԪN{V9k1=Qo 6\QuVJ;џkPEbTqoY9߹hXR4_ &Xb:5 ws?B3 _rɰgB3 76n 묍HkH[!wrӓ>/>lWD^ΟMoӕ%:[G%X L} kWhʔKOB8 3Ҏ˿ys][rr<ܴCN:sU~pkp 'V_8?1{jFZ[IГƮ'!~ь4gxGY|Ҩ *V{"gQeMn`_\aOLiwj;}j}?nuG%7jys !]<{̷yDWhH٬Y6j)0PX.u~8(a(&֪ҕ&@M-V$ dB-~CiVC�DhrBf D P�liA $�|C,5%ϰ y-{/{ȏs#'!R1y4䣵XH7=sGc# ?|nҝ^Q7BZQ^ڔrp$TjӨpx.XeY\䫿JdnMj"z]OUwbA@? tҬkPibj5|-\5�LTܟ / _i.Iu^͹ja[b"kM oVj7]es՝.; by_fU`%h!aH_5ޢp K< >vlzz מ`.i烙e_;6y+ђNV^yhz�6 Q> ?6]�Fdtot7XݷdiH3ji<u9Wcڕ"qgZ,| Ϲi�)4L1ȓsE^;'vRH%_zm#kT\Wdύ*M*+ލ 8O I l&j)}YcƗ*cP9/߿0? 0V5rI.Efwh}qgaxHW}fb|Lϸӧܙ3g܇>ys/7WmݓڵkniyŭҖUʮ 'oIȡ <ғ?75~e14?XR*`|[&va*xN@ LE2OgYIVe2�Qh ZڡH5s%#in/ -}.s!إgT%$ZK!FpO+s$!bX?<b\8 أ',`Sf [mP[.Whr`UO05ktLY@BDFl41STbeW 'yXnRm[)vge@VMJ=׳ I0_xNsm%@R<<S[Pq$W<X4~6WXfyUGB=E8gR>XwRa5ώJzRb׭<xfG%](n`]@!D wd)HzHw\iFAv#r�&8IV5G@ 10.�ͷ!o*# 2L}fXlhfg_BTx/]u zе͊™jfB@i감RErp}LpѮw>DQ;zpwT^qK,3p, І8  #'*D̵7XItO#Z{'8CF|FphI4Ʉ G-N/_v*W?XFFwӬOqܹtѝԓ(M\շZi_][\^rkHL1zc!D޺>5epS ]qW8*F7fM +\Dw#yf8]?-v8�{[akkb:0ERq?BX V77.|9 g=?!a"avAo_,AC#}@?׬o(=Oa+3ڛh8{9ysc?6�+" DgH," Hį=:>uyHD0 PBUg B[gGO bň )[q?> HcC7ּ:3eF6ɺ Z7~ugc&/QOIЏf:44 eh�P` AޣUY'DT.I�>ڈ-!$Y]guHʮՆV2@ZF*"m}pINA.ma|܄|m{`O`ਏnlc:]C�U`p�/Ku˰8_()jg䖎 XR_>IBi_C>%o[|g-r_e&* aB8<};&ŁrG*\@5uiAd"+ F6|o.Ke^* wJ|VmӋL,!렐>",k8,m︺#mXT(Mpܭkbc:3 e1?uN;~h%[rXQAk_q�%fD @_QG/ t:5>?4H2jqQ!q?=ܦ*B<B?AT rI`\ݝre?)~]{qq~~F{~(bځ: ! 3Nf8�^qs�iȯgA'i3o.9ϝpwO8z:MAgz C )ℛFBC0 .Yu}a GDŽ93?q;?(U�j&2acx)nI0ꕅݵEA!T`�6ӂ#뾮̮8pS9\bu`vD6"l:'@*p? ڋGlK%104[Jmf i?jTyu!XVFm/M7 o$?:i�rϨc?즆7ʐ*.GAN-2G|KvTiBbtVY�׳ ـH]V_T5E'rZֻ]݈X])d|;ކQlXM?FQX (!L`?|fz=}cɅS.A2U��@�IDAT_K/%zarm.�tLf OhP3 :�,FYVVSO>agztLHaȤʣX2@5,/͍mf*vkڒ#xu0U '^FP )ˈ[ԫ4!Uynm ,hkpuf\@t% Ö`J4i8w=]�Zɏ=z,"2! >]ΰUpge$HeH kJGu?ɟC H۪wE%Q]v'6it/WꕋPd4Nb.  )Ar8]FW0PB)Ohn|u,"0N"YGwa`U>wۀ1WlB$3$Mwf8KN6KEW]ltu>_?k6Xs9c~93>9fff9w̼E{gMH9o^a#Cƪ/5�KKW]iszY6M$$ R|i}νo. ^ա(ܧM!X(Oh&"{o7&KBklG |v7#j!1Ӭ teoyZ&":pb'�s}LŔ<wzWrZt_іRb7x`Ϣw `Ĭm c7X֟x`cT=bo :$2m}m7`M! NA)d5IF}\.y�lB>@K~+m'N^6,S?̎I #U2f20HnZڐk,vVVhpr3p1⁤nmO53|]u}f2xYV{6쭭g&?m ! G K|1�J f૎SB̯Ĺ[Ցn  ޴KmU51l:Y�UH#u)%iXbbyefew5K@<W+૷j=JQStd9ci8"Zj_J.4Ys^ F2R⁩x$جG@\fǕ͢2gVhfWCڔd`hĽ#`�.y}7FQ@I:( ˂u/"J ؀hr.�%Y2Ωx'T۶dڧ)n<RW^DBH!HRq<?Ho *3pWq#XWb ٗBx� �D�򶹞Q+[Fxqڝ匽 ^ho[ہۮsGV`?&YΞv>IW? MdF<\ _5:7gv<u+`rMLmd c!mBpCfpK#� Ɉ]; #%JSbhLFpv2&vTqqiVr�* 1_8|vĹ5w)Um@'ЅPA3DUϢQ(Ͷ*CQ0f .a.[~c8?Y^q3snrMX' � @D5.*'Bf{c/ =rԭ]?DW%4] $a*փsPƈ}v "$㰞ˑƒE nDXu+b0mjA<[jD@k;M_{Vg8AZ>00(WHH~,[E#if:>L;qzp}O=\[e]gkr[&r H�A0&rswylWʇу-ί= uٲ]8!Yr ]:c|<g!=0-2ՏIrvE;FLj}R}ș2Ϭ?CʞrΣs¸apzʈ+soJS8NV5pD�(Rji kb뿉?7^wz澝"@I-mȠR}r-?> jzt7GJΚ\n9/V>v\f~[ Y!bѫ�h |5WXwUQ�đm<z2ۂ[5` /T㞷IU,/I L\(/M4dꆻ56n) �~^K |:?0Liɤ_Aȏsx^F `'e׬2dnC\bv9ؠu@YL/.a+guULmmЖk[Ә9\C m@7 E�ɽˡh긮59@]^\@ b ":Tjw.aj�*E`=4fE tÀсcԹ(.# H[!2X2'p*eak40Tc}{iY$}s�J>.V5HEcvu*`ͣ`VW> >΀>Uo<FD g/45Lt#epP@?< #g)71;f>|y`~|`P;S?7MkL˄n}Э?8,/ mv<  %*YN`ݝ9ChL`lbQUag])*Y ڐ `-e&Y>.8Ը}8V8e]VLT?-HI4Z%sD�(& _U�pxz"~`QuF[Xw緱%"/[�:ڿ-bpLCPVq#`(`2Y: آf\q"]#�pެIru QWvqڠ.X&U`Oշ'P\ Wm&F녥2(_ҍޏa#%"xf9Xmĵd6.; H@?aG&ccQ�Ɂ4`_YU3-2{L< UXϳPqx|kɡ!N[U߾20lY/Xg�K&`m%'3$`3mPڊ+%ג_⤬CSsp�\a;Զg~n ur|mթ�+oSm-xP�*<ۤޒsߢf C߃))ҩqOU7c?s[k X;cet?oS�AUhe�O"׶.iL M?K{gkXT5 TͤBxKte[:FwW%Cle?͖aCiQS$.<@ p�k�r p0sR~Qi'^2E5F.j):yoWuC`KoEY0 }Nbn4�*9Vmi2V,Hyen3ܣg"5a%}M$Fq~ ܯ=sʽ6?,bOWkVDp4?F']q|O3ɿ+4ҾS tfIv\, >A�n! fk_8U8e8�>+`%XW~.rFi͵+P jf_aS Ns@HBܯ<d[q5 Ȅ83nL,\ؐf5vV+yS`UASP,%F(4΁9�5$]7Wtt+Ϭ?h{ $Z˺:˜Q㮏"κ (e1wV@T+|\4d/j?K�HԎk6(HBP gKħp6!Z+%.O�,=i=/ ϽEkh]ڱhV K/@M}}ss=0 P*.j5_osJ[b u#t^ }muu@wz0hiS^0iF?GqE�}ϔFp(y|/f ثbm'p((tU*H["퇨H{f}뢛Z%9�2DiG@a%Xe}`gԦn!v8V_Sok@p/6e3xE"qs<!H=;nJޱ�64a _';~` P^0U1LQtѸYɫ *_C6c_km7 ށ0UKXoL%aL3ߚA5Sy˿̓9K|ssn!ݓ֢28ж0io[kmOB2ax % }L4 K/֕cp9�RRd|AԄ ?`lP*[`I6}R˽gE@gi/.dOK^r/]~^SEh=,B%|w%Jwd9�QՑѣ4`DQ3֪ Zmwd=z>4JF*O^~Xhuugٙ*$}vꌀC ?<v4 =ot?knLek8([\7C:~+o ll.=ZiںeKz9vlC'<2Y ,Ƹaw߼b`$�`SNr -$4'P@igB '-d~_0 ]i\c:~Ԝ /B|Ò +e: y o3;eP= ocʝX"2~ R-s ΂$60f#.?>Sϸ}ӷa$_3("NM, [ ~t2>&5uE|Irkcٵ$FB@R`AU>vk㊟>_:~0 Q~x ύֹUtRjZuazpNנM4P48 tXdsN@}sl+aVa ƥ=aI-ȣ,6]eW[*mYI/WHl>?~EàmbH m_H׼å䶞3WZ-iCGu#jE惢y߷]QZƨORj-9ꑜBя&2>3StnB|\�\ Aޱ8>s@46TguD?Ue3\uZcb:@*FNAehlt'X~yִ 62lG#J"lެ3Pm=\>ԬUcGЎu`fsN�M2NO\2 ML3&~kPg,so&j:U`�5Zn .̡ׄ4e / ?t�ۤߕ`o7~&ncSuVfe`#A{pSdxPp8(ZX25`bUեHLf#puF=&ޯ2?`qf*Ȗ`c*BlkMaJ�!I<ˬ[.)d$Zk?yI� Aۄ�t1Ną;=_@^M}ي7M` 1/]n]`@BLFUv>Ige!?-u2p\bPC#Fp�ip:Vm hX~m #QPѺTaq1l�E(da4?yx!? '}igMI 0SVB!NY2$I3.7yθ 8<L 3A`PP 3B=KW*k5~"UCܬkn^s !"4xdH1H0-Cg\�0+7A~O:0%PP=A7q\5Kj}�Xy;5PUР# }=Ccoo-`� F7Uf"%!Z6zp5ŶT ~DoU)Gi-̃eWP\|ڒ |$ *@atQ`5 ˮ'%yp GJBVg{U>xɝ8҈(AJ+M[f|M"G7G WeSa6"* 3ʣg8[xy*?~kOiI,p}䶲i[+0 3.d'8qtp^K<~0iEx+U}$j<?"�qwY ºW!w.#c/iOfUbK5B$s)al._oK6~)Oρp8\R)>al#%tbrm+#m [닮vTXM6nz}ze3@c X|Š])|/D:_塛VPNUb旕gkR<3B5[? 7:YwT\Hu8Xҫ2�+`B4x}}32i22^hro8�/Dԗl{NWH, �JAf Šܫsnbl܊2@ۡ@v! =W is⏄~J폑_i}GKYBͭy?rY TNY9�+ A^%W]K.[ aApzvi 1@x:/cZ!,VۧgLH[7GkD7֘8_tH$\ZD4M[Vh6[|$�D'@ A9(_sT&? 0i`"`FAl_aȯ]�Su8HZKNk`]ZZ7A vlI`$<H;0y�}m2]W*?<Js="V-wK":w'TVZ]Gi@&& G1 ҺB?NIws޺( nQxKL3ʉ 76& %mHn4m`f)[ 4V }lMC08k:C7D`0{h"88%�G~ 7`1DG্4?+ KEgB@".@| !(; Sk{2_KS%$'g2(6܋MVjaBH;PtvTi(4A_Ӟ% ĚU4xbj`"uf"6 36@<\2>u8p>.~lb5)tSpdJ |]CAgCtSޖFa^dFч&;I�t`GaҖԩ[a�(/j8E:,Q` Dy/ qa9ABIFkG4BGn-WJ4> -b7D !vYBw~�Qb^$?7yMf:@mK V,ާ m1b EJm?'�Qqd 4HgDͼIp7R`ڒ^~5sGJ-O RzDd�4&_k/͹/kRpRm6N5jFB˴i λXv?,�-�^?<}Uw O?r9+ѪK [(M� H`򅬺Q.*AuhI%N/]o|6TaD<po4zGk*?{re&N2C5o$b|ѯ-@6-0"i|S\Ceď:A|A $ȬWI�B@~S1?L �m`;7^M^v-hI۽?7]�Vu\22 PṞ -5Ĺi -_}�ܫ:ߐPI 30 *&8 V5cؖf@.o 52QwG7 z }kϢtUR  k\YYB$?h扥ʕ(l۝ 2 ѝc(MY~']]C xm@�#jq. &Q`۪;�y{.W^r͍kHQE(&i" 8_{ b:4 '6b!ŠlCS ' A흐FϔΈ‰u~;xyZH7>#FF VI pnP00rCͼ/.WCBxPar0'EGJHp!y+ch@3?+ =m{HqL)B,9rƝe,j+?Ո@Dnp`PZ;Cq<o� SO[~m I@)$jLsz&)W}o@YlǯOݽiJZ|{!ExJ|QXEinjp.˻!�ebAJŽ;cRTf}FW�z͌=@H<Z,`s4`9U| T|I;U_RR]iHjFuN 8"�6?  c$EV,OL).@@2 0lUJx!2޿f|׮wa]A vv+%`\λP9ɤtD@óMqzd; iHȘ`S$i' ɧnKݖFƿ@?*]�^b0+A6D)|tqi$AG>P#5I LJ~vVw�A>ixE+ n^9Fd@_&]XbC]Hm h-wHvIui 2%ۅ;2f/P PU{K no%vR 5NO̟ww/&SP< kYRg6gcMp!Z% l "~9 ˴RaC(4VnoYYM£o.� \AޏCKJP7gOkF4NZ&X垁]׶ rsTݝCzdN�z?f𒻋-A+L`)R B0<R?ymצ"rO#q|^Z{?KM90П JU 2f)G24tg!+4<CP|k==iƖaAVsU$Xİ+n$ږ[zEb9 Vs- ƍ,ŋinEoRfqxo:ѬsڢD'Z{ <mH"m '=U.�Pwsىeh",EIZZhꀡUޭy^_s�;Wkz$xiL{߯S6sG*Hb.nm :<Ҥy98!:'o4f__Zij~i к\B@G^䚧�SfG!n[ tKѤSũӥ:%ugc+.$w WYt?8Xл]H6f@a Sz{e�7*p9֔Ȕo 0oI鄳Xgp6%_^t(( dWkec)%2?bUƴ\Z5I_amU`)K tÓ�>5tSYgMmU (8j|[5EQ5R`nMBxWC5`xxSM{{&)»XهC @LAKKj:xBiV FY[\iiiJ9t[K>AoP%?CBB!<=}6݊bk83c_S.3@X}X v"� qi9 Fq-N-D\DCK0@:#+ j}�pMO�ɘػjVJV"Dz1jlQ5#)a@~ Sû{ᮖs*rf h!ᤦmW<|UES㑐nU`J&B~MfY*Kg>ފ= ?b Ƅm|wmd'<gNK(K뙫ƨ"kb9g5`s Yi˯*.�` ʵ9؞syHHnlg /t6*_V;(Jd[K,90='�j|KZ(@ժ &E|FZZ,MݷTnaYj@3zb/_MO Vy_A(aH&SJT}Z9t+ m;SЖ [*_ ŋ;iɸ(lkQǃyZe2xQ$&X;IQ'̏F=l{G(Y�u/nF5?zg6D؇E #Sz,i# r3}O06B:s=݄pC#}[Ho:<SGKְC4f4v4XRH:2nU^q: vt4}e`P JSGѣ55[v]b"Vڠ c'܆T\^q9<3Iӭ lk6�9_^ķUp+<_h`̅2sݼ+_wBwAR꼜B$_s͕`W� D{ 9"8l %}`Bqi)}?z-"x\aMJ41C mBXUF0:d d$|7-*?[SB+Hu0/tt9p$ ev H =Խ<qr޽QKHq�aOLHzt T0a> 6Cø<|_˄w~qQ,bG$VSn$PZ}H>hk ycZ(З(@>(N+Eaزò,{.Is.)r{;?Μ3?Μ9s&Fk`v�m96~`4R+@0U<cl$vz5|qD'K5]&b_Pq _́xQN=f}HmRXPLER]}"9❸8zD6%Lя??s} {gZgCC5*DZFJ}%k|6PUee'eh�67P j:f'H(vVp`T${{IG'17~?ۍ'hj?k-@Q1swC)nA=~7~ZZ-8:\?bgxӚL1H D;w)mZ@YD^9e'JҺ9: нT{r2 -#Ċ( g<V�93Y_hRY�5R;WdbHbG 4Lq<P"$26E锧`Զ&:Hφ7e8t5'�cqC{9͛l̫!`Pب lUMlt>~yN0 x[wEfr Ǎ?om@ Wil. G[ӌs}o Twl+Cf߬}HQ=�څ&ҜwW Gr[`U`j-y+o~K: ?{O,] r1 Pݾw> 0\1%I%*~^W hiq2Z�C]]{0G^ݣ_w_aױ @lG *hguY]!B;Z;ogzUr*n0mc9d>e r�N^5="^j%fe`ż@J8Xpd3ޔa)ݚ'M$ <ws,|N\GTJ!:i'$td�6'*MKRыA*t˦�pXB$r⹿x@bXgyTa?=l#wA>ٻ/G �"@`  Ǟ 7}� k7/!t &1Ω?sND!]soHe݃jGOrEP޹9TJy0 RXwN?yxM\f(d![(Mm5(zdXq2#TJxreXVzE)ԇẽDZ<|:wv_5Xy3=ki-ˡ� $H)݁ D%xpK2#!�[z [m척b;ٯJɰ`, e(^%!eô8cQF }r8@'0,eD=A)xGf b#C_|98Qhu%T.)rWEL8\K䟕+}[ XvSR]{l4xdQ$,o1Ukغjٕ:^g>ihc^KRjAjGn̵JY.`sxk^[vy8]qcX7!Y1c,j7?G8CR[]gaoc _|&*4R0ϳjڽ0JaEL/SpuFyZϢH>-e3"*_k-n 9εO⯌`eV,##*1<=t&N k iPp6n0% #  *9~2Yc)T3l$Q @%?̠7 ='qf#׍[! xqwtz{~.yr?qpmt (ziTh)ϲ݂`(u,lǂX$-$҇VC^w,3P TWiݾiϺ㐉c <=4G?&Ur0d8�ҧ�!>48=pVN�8T GښF@ӔLrJCh%,8Ϟpt?S z' { a+SW@PeV u.٩EJ$nF'юC[X6 &9?z}$<=F{&3lĐ~[(Uz?1#o`-s_~+̱H3'9 C9 Qb 3?y�kޭNWA/&45ۅt�Mnvʢޡo,. f4rx3-VR==fI ^`u=)x[nWs�+�Zl뙵V*!e7HP;D`={F T;?e48�~sgHr*Ttj*PTA]ʾu1qK<Y+u R�s~_ĕڝ.ozϲ J©pG9W08JMޓA&蔄Ѯz^+5hfyVQNNޫ[LdJe�8&0TY*fW+(͎qU?'Nd_w JC"uJMu|O<P, s IFiMo *+ D鲒|^SgO nU>G(�Ȧ-IK}GrtyD|8z2!Fe1;)n4HSHq_C@2&j+&#*HdT8.tԱ:":Fi�u?9v *zs9m�KoȽb(ص (N5fBOE*F{~sySN#O+\Dh-Q+�Ŧҟy?5z2J7ޕJďD;$Z_uǸ­FیƽZgWR9*VH[VWK�zi8}k6ok@?I(\v_B3󠊡Jb/+K\Һ$9�@u,6r?LZB߹ӡ:q @lڀt8˺hl44nܷUIPb)i75.;BW+pF uUu@{Eו˴W8�,@o!;~ʲ>DDuSϭmt6rrGkQHa#~0dG̚-@OZq[$�ш_4@l,?w?t)හ2zR:#Y)VvD Y1CE)@$gS:}`]UR=4mE{粷 �e*N{K6("Tu46Z[AEU|DI*McE?*Uj*S`{|][v3eK_@8^0kiXZJO] .~,GUфU5*ݦv0'R?ɿ�+m˦:P$\3 *^[,XnrdeOaZ9!SGgCzw*T6Ydi{20iz<\W�cElPEmGڶ)8V`#+`Ҩ5OJFZҺ?ד.tt:,xu Y f_@?  O{$YӞ\V *Ɣ[!i[V)u6*d*>+2I$C!jkmcsID[5Y[ 0A A 7+A sd4_*Ӳ>K�Ӏ%zi*c]ݻ ZZ}FXhʓ=y`x^r4A0}P zְr0CSgXyپiBX3,H3J7<^Cwݻ}h˽e�R>U5ԟmDA[3Abr 0A >f&Bp|_@f#�hi@9Y# n9vI6t�6$j+;:NiL fZy*w'S;G�MFTVGi2^[BL:.% Y bE`w7BOK'Ϗ$-CYvV5o84 09w&qmt [9,n�W\ 5!ZcO1`DX馑nvQZmĶk >UL7w,n|4L.��IDATY}n Phޯ?iĨH :*HmoSp�0KO5|69: @O`~/rM~=eٺKrb`S�ڱ" \.3'PeKf}±ъP\sHUVV}ߴ@/oe6{&Mk HS4>,p jFj\PcݺuWLi�+e mE_۳E<gߐ?s}SFV{sgp.`[&`{eUc QS[t@e:W}Eg?Q>X1V�zexcHVM;z?L'I_۩= n@݀:t$&'!`/7e1F=l}5ChN3=js@=Hv2TP /4jNk\'GNaeDxǺMBy,;v$򻛛@ Rr�Y㷛w^o{Eo�Xh.:<3ڵk0oѨca׮]ԩS9oIH^|0<<{UH0 xWÑ#G:'E-8ۜSnѣG+bmNm5c /pYN`Jq$kp:-gĉM"?KGp0::ffXcN.a a`]رcGφ={!ױ믇&z2J+=ᩧ2d=8  1 ҥK̙3]iʩ1PY\CZe1OnX`k+Wwv}4tM$DWr  j},'ѻprDr   *sRY0p!Z"KHHXh[Ճ  [ hkLR% $ l é/TNeLH'OF{ =r`<+*a)a a`b6/?my)Tv[V\@V�m>==ӧ5)/^y[\ 7x' vÇK`iи  /h:4KR;8Vɟ00a:ofp�G8/( = 7<=a a�mSaO~ZAݒ(d B|$$\+  �sk1m,?eb& $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ ld.d&����IENDB`ic04��ARGBADA����ƒäC4Cfeھ;=|86픀S|ttstllFGkle@?e]>ijA]U7aa7UNN_OTO`�!3/8DKV^iq|E7E#$++$##,;;,##@EE@##,W==W,#|#Jd??dI#S|t##'mVVm&##tl##G78G##le##wy##ww##e]#:P#^^#P;#]U#8P'#>=#'P8#UNN_OTO`�����F8F+) )++++  ++##+|+@@+S|t++))++tl++"!++le++ ++ ++e]+#�++�#+]U +$*+ZY+*$+ UN! && !N_OTO`�ic14�ډPNG  ��� IHDR���������x���sRGB���@�IDATx[tٕu"ݪ}Ue.\]nLq Z43-$P<0 !@^ yôQiKW23"2䊓kgk{Y~&]"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"6V<la'æjoqbV bHkhc.Stt"X*E:,u hk :AG=yDqWg6~Df iqiM +}:+ƴDpesÃc~1!1]g8"=.5&Ez :RQ3klnEVnnUW^g]b^Bi|d7eunbxMiq?Ei=Vn8F4'o&2َ鶰)w hE[*Hrcΐ#yy-ѽļPg"M\b\O)7)u8nV9ԊRNQ&OKbH+>gMkh b8ҳvYqsh[S%*\;#KBpJaח(㻖y(M_1>c*=EM3M{,n8F4'o&2َpx,m >޸9ưeN_=E_%$)L)yJce:")X(%p}ƼH9ulNW}Z Mk[HOQS'3ư!gzcY:j6iK(QaY@nGy} ozV3hu^ qT l^9lW2m(`,ZbFg̋丱zNM\ܬ)rƎq&mtK $Ñ7͊3/G+:.1/TH)Sʍ{Jp2"-e G?3 Yr,Z!9ưoVܜyy=Zqy 7VϘoA&|i3Vw2 ƍ嘊D HD@M ~+] m�ƿ}UEWB4/4,HD`;l~}z{4DrG+/Wg"μD HmMS|J! �Vhοin^T.5T3D H[~wy"! Ng/BG"$@"|n4E�o5ET&HD HupsjFM39C1<Q4n@g'�t-u]XHSFw9\aO# }aQVtl K"NQSuz r7oVMKt71rcOǖFw\(K/57vohrc>mܼ:kEZG5ƈN1):"}b^Ez6%HϊSn Yq͙ףo )4zcxX=tLcs^^z-1Ye".i$3Vr^FS{9tFt-Q5pi 1lgu,alnħErcWGѭ{ͳ_lv<r+mw^<'2' L7؄ OZ<#T/t=CnG7CyYXSQ2-@ O~Z\wwvrVUK(i$8Vr^F}9tFGL+ӄ6iKXL54Ei\3L~ȟʵ-DCg1cN1,oĹ6�F LwՑ#*s:F<Db8Ydu%XϘA[VK(Y=DI{7 =orctGX\L?Ei2離17M"rA# "mtKԴ1icx=Cn{hܴrT~Ji4zzF}'KYAsf�@�Fu3_w]3W$8>\%&%=Byv;V( }BgguGCb] EI'Df3<\ #c1Xi4z\+3MOSiPYr!ΒGEȟ&.Y)evYyO[VKtpe]R_rnq>aݺ[bd|̫|\T;Ed~v,WTii94V%U@ڈ=+.!7Cn#M@褙|ɏճwRybHqcgYMyzN,@qYe q:A qmtKTE1 :jeA"y2F}2;=r-x�6A|Y~S+8GU50!&*w Cv󭙝k^2ll \wL{;uc |[5-1Aȟ#Ki4EgX|uNmq"3StXy$|w)y`IbHGi$b8薨YtÕm^FOUa;C[yaqR^Q.?$73ʕ|?_6} 9xR&h0]矧<c(^d _^!@.߼T: yty=Tby3jK(s˫4 4z\apgubEzB^pǰ"m–\b\r!c؊""ݕWˊ"n�4�hQ8D<v>ά ?"bϔg, &Kw#c8sFMzoVܴf}!u/4苲g)"׊D.?Src:>e^ޒFGL-+w?ʊn-Qc8ҳϒ qǰ qGܴo["u2Mn\ wclcI6�o�9&RgSۦ$3$3Eͫ?T6YKc8ҡxFvEtpS4A% t˚% +G]L/X=;qSr]thdCX8Wk~Hs,"=K_7.,9+HtX=c\*#c\H.{,M&H[pQ\5>#Mt7*uゎce<KnZ\wD,]Y׿$\�C=98!٩д$&6+rNGU{G<Ju6a3q(޲uB߱sEuTe 4}27VϮ\ OEL31oVb\-c+FwuDb\gʵDĸH[.ҳttα2M&m3EWH?=t3UeG::)ߘ.cp>Yvp ??n4s*w|ŦvӻqyR@.:/HD XWG>n}Pmg?ٷYXo}[z]_QᾸD HD Ӄ}ss^|35�o%JNSAΤ@"$5Aߒ^z>mOeeV-N8%@"$E5-�?;7od>֧?)3 O4<h=z6{{{g|D HDNsƍ֭[͝;w#qj+<}_P+]uy?Ќd"ND HS"Qwkܻwyꩧ>?�АW%7я$$@"4h<۷<H)׍Ol�|7d'%lfh~*p"$@"\ wm>OTAqFԶ13�wRz-LF"$@"p0"s5?<[=wxggtV!W??4<|+D HD d-Ei:WMLl�|{IJ~5:'WWDKD HVv|o>M5*ny5�4CH?05C]2$@"(oy/Ux I s{6D HF@yR~i0'�ꫯh$Şo~] '@"$ /| ;L<#`l@O$@"$�rNT࿎5iG�4\s_z(%$@")%#(a"HU�V?H$@"?[E-?Y^{A_fC~%@"$AChZ)k�uzOnt@"$C>5k߿ aia_3]"$@"\-z_S KD H@] 3:^_>}ZD HD"n_ЂϾ9uY"$@"`p6�Y�8L$@"$W�zu3]"$@"PIuf@"$@"p`_}KD HFnoD Hv_@WYD HD �l4%@"$@"pMKD HD >gMD H�D HD >?�Κ&@"$-:6ăc[orœX/+$5C`cc}vs֭gm>4zʣg�k|͕2 $@"p}Й:Vy:_ך{W<+ J~V-@wַ/)Z[' $@"0 ^| _hկ6[)�ZQۿt@"$"7>h~yJUe�I C]k ߿ϛ0G@eJ#vp╾r�=m0{n?::/R:f+-wW_}ݍQI'Wƕ^khi^~?`q//_VW) >azt"p#Xt teV>YD$F7_7nIν-28^>>>VR2ܟ.J`'BqOy0xi eM*;ݸ '늀0988KW$M0O�?]"pUdwޯxcÏ>x9]e豏XD"`aT`VD^k`4kI$k$v{j;n~,JTMuBF-X_Jo'twȤL"XC7 wWxx||rYyB mٽ1nOGv q`[w�i~zwfb^ \LzL"ƾeG93^as FHgFFS3~tmT-C ~ڭ W"1eN. 4>}߶1L `1p� {c`(7>lTQW�(E\z ъ0_+~aXˢUup̹Ox5C7_j*Ux[x \t![vу{oM-{ 7�h ~onyC /)w|ƷWsӏD\_,ve-\e14s9CM!ct"m:amI+�0Ց':u| DH.Wt}[݇SL]_mid11t5]: ϥͫKOP޼h6;Wy|x&S ҫbxQߌduS�f"I:8 n 8̨˼_j2z~z@6@gq|Q\ϙa.@ˍ~@~S<Pd1p^0X!"]"k|\5K> @WͧżA{~3ꊂg_4L�i-E_խrJ<Lxr@ >(hxE1Rr>jWD`U(7�|,^ʟ'nHb0fݰ6 DPh _ ?*[FHF)8J%=7V/W4`rCG4"`WT'o̼$@;u6[5�6~hRrk{^>r7@@PD=/sqe\Egߌvmߐhh�i }*[8yMVY[�'6�TT9#=7$x\n=G+~ix <{niQ>_| =7҄.b, M4 T z6�O@p aǕPz\%\6i{4s{<iKf�PIOGyzp;>ߍ+0 i(b\ga$TߡVj%Sm|d01` ͻKN\u*kĝ^n�.X080vѥ_M2>ޔے2F�m-vT6 ;/yCG]zGm_<o ah.<F<li¸6?qP^KFpm\nk@3|Q]Zʍ7Fz!ϖeՁ:!)c"/5.yF-s4|$& �zC %|3P`_u3hJÀqYK`*J΀�ik�*Z ͅhs!EMD-~16#( Z�2l a8rh} ӿSQO5(i5 o:K>5/rxbOxYuQf LCM}_1on5VCXq/A|!@HAJI*%DKVO.*ٯ8ޔH.j}hT$=~ ~+Ah�|J/7O?̏˟l!AEh}DA9v,=Ezg{浃ᆍPj²Ǣ:P^DgBDvR NOWct}gj@p6zo;#~nɯ ƀhr7ٞ:lDsۛj k## @FhQ(hQv֪<~ED8@~wոbp1t$Tac_8"fO]ad=o[9&JLnRi4#RQv&@Ӈ{&>Ĵ3е<}PpQSe#6V^C@PwR!wV'CPq`"pquzg d16=}LpP {[*7;shk%uEM|L:Pj>n>:65 ?_h;4 Pv4|Q/Dwi,86G>qGui/<7=ǵ8q^!@#M\$�͝S 14lhZ�#UL&l-'xxIy5 ~ ƾl , �PZh~= &҄%-U �۴nn�=Y�0aBѧJ|PDi�~_E4�nI-j:$/ veCy7 P[U}m`A=T&aR%�1ä F_.p ܙs"'A@7n$!eߟ{m-ǿtDհϨ% oޮ;ގ[R] gi k)W9Z&T]I+L okogd_ a$�ޞ ;gT}?~ 5X]�h A+~1V?V>=r[Oq7uP?!i^adIg֛ܬ* wwDC;Ǥ< /3:#6oKGVoi$68[_Wqys W+' d U,%ݥsMQ5:{u{~ a|1|>;9nʿxFF_Fg=)k]6'Y;,"Zumj7[J$RZPNj!B.^ZAJ0*/"`7ac)\?'*~e(òhe[hV{#bg ad_%L|hI4:y!N|<qaHQݙR2zRvLTm`i!J$s #�s{'5E8c 3\7& J_)Yh[P[zRO(<a\X<Wӗ9^ɯeg&W4w)}~iA0@éoC  Vb^3^ B`׬K.)O'kJH YiyX];nXa_zwZz1m% =qtm-??҃~B1d^x3CEg1LmKNI֡G#@(-puC5��U2= _*@捎|^F�c.\xoe4ok' E$8%#Fj*jgۇmAg#5P; Q]IK¹k;ҵƲ*aC40Q@$24=r0BX,#ݑG[qNWVz!MMn = 7ngy3/e0!417Zƿ,t@^KZoJhne?<C�Ćj, Œ�_h>"B3<n+�7ޛ.8ػ qe:>|?=~sS^؏e2t]Fj`owd`@�jJfO 0*(��RK@ 6>" vDB>]7vk�8`c#T%@5]2A2cC3O?bȸhڕ%S_ ~~yB b*VƵ"ev$1UK_Z,F^+c1175U##$˨L�S`Oe' g�N*'D<-.\poתrԙ$X7Zg2篰y/=}F�/##CvKam񞒢/� Ph0d̈"7෍c "Nyune V8 >:8 ~ `'�~O-i  NeT�.�(}F�۴nn%�> ,"`^,^l`Q5۪F8$bED6GֳF8刃HWW<hM1>x0ZfOq8Pgj@+c�kV^ sH:X-wXk#:8'MQhe u�40Om tȦ/J,+Q%*pp6AN)lՇ魎ׅ5�arK%\^DCx_-m&˨pHkҢ-U<'04n̘2D=(�yѝ!Y^ܯCnGͶ}p c$ч|ZaTT8Ӆj6K\B8Fm|LzС^g�_UwML>NWx�Pk: z9 PJ"ΗegsS� ,2$rC|XT"0fde;MQKO~X@� +AVt vQ*'<Cxr[+"zyW/32B>VĎ 氤=5�zCaîRe9 v8=,dJ >ƧK"pn>mnxWgMϪI$KC+ta|?<m_<r?fi! Pf4taWp5ʃWaezY0;&nHڰۡ@سcOW/; Vh-%煀E˃ 12 1T2p`0,fӪøGF?A@[ 8p_ؕѿӛnwG?|:6t6}m_#m^J_3E(e!]>N_V.�,Zf'JR>X�.|~/#E~m|(c_|m[~B+v[G?60R㼨GP6R;my(rumC2IgOohW%38y�W˙�4Jc :6L/.GP5�BA@jK;f>_6?*[j[Jp MuKe`BO4F]Gmj/e𲵼RXURڂ ?)߼�P�N䀠5vfS>lZ@XĈ �.6*d%"9 0I.yޝp kx¢LE�ۅǰSа~_2ZîQ�}5ĻOH˧Q1)Cww,\\>4Hⱞw` m,WVrY/bķ,zǣ2/NPøA`x%l3sK?8_V/Zõk� MD`*M5$4͗"zQgYȴm5 >rk6$^uTМYk9EBHAPD/Et oe42Z[FLOD10 o <jسxel�{Ux.|[\2Pt@"eC&Hf!Aq)!l}PY:eM aɀuz@|xaajE!!O*Iz%*biĨ`kuZ X+AS+0PnT͢L{ C(|dWt*"k�귲Љ6~UҳL�r\ܚò(eÒ4}Dͦ洟ܗ k0*/rDd%r6tDx#P^n|_](Lp`3 ֢H�b_[iqyI�;5Xvfw+dMk7p8~'w&D6 cS Q�q=Um]Hk�t7@\  44>zK{ Pvث�J^ P = ]]<D``=֤zt+yM)7�(01!6/<p?�n?7k^ L:c'9Mcr)@NRsĀbU'U$Fu H.pyO�ld?�e [7~F ]tbCK�O xyUJXtHf<ϊDO*!\{ #W|q`!5䗓ml�QH ׀HC.qƼX}T(+k-ʼnGYda<T0B|,gCГAa{.@ub^D^F9b;;#NΈ@4 cH٢3G}>o�>w:ޠ9m40VĦ8Q(ezXa<%?W"xA~kiŰzS/O2&zPL|?jp�F`Jv.tG']"Tt{?zTl�I+]"\D?=J዇ѧ?vҟiߧ)TtOK4 *bnj3_ug:N1XHWQs0n~#f-@c@!@E7S7@?fErK�i5�xj{.X"+~5SƜ}e@G}osW#�/o 'ݛ !T>FxumsX^~U?Q4{ȱ >P{%D@ķq%.]"Tt�!>'ney.SFҗߨOq CgQC4~>GL@L4UL,c`Ս P/װ09�(P|rc|xxv(œ P)`G6yyM.Uw+pᯃ'ID`I%"]Ǩ~s6x H!0zC5#F33݊y),!w8nugIdeݱ2zQ)ō1&Vi�?M.Bh- 1gDO} %#A(sDX"%gW/}`ъ9]"pVN8m˒C%\5x#5[h/𶖣62'DGy-Op<Dr|i8<R|[�t:02^!Chؾ\,^ʻ Wݟ%'!mO?IxWȐp wW ,κ#PMFk| cա7EcS PxӐ'6!m8bW #D^]_ +waY,hR6?4 {v&A7E w^?=,%D�4s{<iKf%�T4!Ƌ@hD3oCˢm7eW@=Ga w�4k铂y[FRd],izx"x} Swcijm"6qwiK" vZyЂF� =+>IFSIƍ>x`kˇ~o�yrڟ�`?�K'Ok?  LH7Ү٭K' ".Ψl_{ls�8)O_ Bŀ�pa^!XȮ{l S|.8#~4~ۯ^a?ƞ}ǂ?V_NAY%P0R3턭AKY2D=ȵp^ZNTJ-<iXJHZK q`5 PL<@AP*;:X#a[TuKDQ#tY8̃N"s!= LA�o� 0Oa}�cC74CF5d?q|igk%C?sѬ'dt&ŕΪcb.mCVEFwhْ!Cy@#�j0(l�s^zGZzl<n{7Ȭ�zYϴ�Ɔֆacz|k�F�?-En)~;ͽM5 $}1\Ͱ)1ѣ LDըlR)cS[/�zI~xԁ|מ芹߾JҚ1Oc'YY\|<qȔJ9!EN(-TDgJ?1Â)ػY~(!gxON>u^VGD^#u29.r-& >[[zLA@xC|7Lw"Yn%yyL\0'iudD@F� #@ȤwψK>jaGtz"ݮA\<Qiy8DJz^VwUL1D4ep>.Hk-ͻ#D@@+>-z(+GH);a4t5E`%�ޱKAkd10;!H'�a4mgړс@͈ckFkKa/eh5A�ܪZ8VgEc$EN!c_ 0l5,iC)+ "[ݹӝz@Iw':kJ4�{-:s}D,<e)`yˇб=aXC~xϮ?;*�uVu_ɴ@Ub<4iXv 8s5a`j1.� Xҗ@{y-NEPk"ePhE!E�u.X֦(!taVDz -b+_Mv5 m:W o |ޛc nGB:hF\n�L<Ȍҕ�xt01SbQ{PTqM)&M\PZdHC8 ܂E碧> 0 m�¶OL^NjiY� ߓϖAbLNhtw]"'YpӔXHxC6}|3`}7�}!A N9t w};OƦqkIO5 76nR[_h;GflJZư?[j |?l~l6G�hPbƕdUڪ% 7+K\>S @Br,| `fHF#}}vR }!4`60 D`]s]@O]tb`wp~O{g_~;27d-%wxe{<U0(t\dYa<,u~FnbKd +=D~�Іu;z_{jЊ 'WA +2]"0vG0Y3�d53`qn_@BU?��@�IDAT3?n?ۊ}Sql�M$wC"ɈiZ^`Ujۥ2X+6wg#聭P;@]{*G0?SQ1 d9%8%vg/v5p )CG�&Cs9ES#`?Q=yC4�0e� @c�JsK#8#Fj[tk(,Yw?H-$Yv[<PIUl ^8L=d7;�hhgto ߯фul̓HsG`ݥ7�F[݅n5-\LpCfK]}kQef[_9t?4YNrs12K2 [yrl{4[Ѭ0xbB 0rq>Xߢ�Yjl}KBoWCh�<vl . X[OЬBŷk84P5kNo2B:*xSPI<#?-nO N 'FՌ' '[C9P ́L�tX!H@94?)]"0/0΋5�Tr!`]̟E$W%�Fϰ|Y?n,a[{#1(koE澮| @L]km)::6A7�+Ա rF2v @��|�k(cm<(tiNewdo9p:vesa ¬ GG32�j�W_rg\ 'Os"_<.e'syz5QјG@ D_m_a}�e#M\D`6GOqYk�7c?/]0fddo4s+�oj{QldΡz/뗳VWQ W\4vd�(C.wV]1yuA5梌" V ~�?>#5vPs�$;hʢr0Pi 4d]Jbh%D`26Z7~ �%'#c14ge40H mC5i?s_rTǮ7j341UyQrTX\ߕ bo,F1.ܩ O<.8e<3Ki o^m5]]i1j1:@MP 965DOLA`5�́<:#;]"p2n*0d=k_Y[ח?V?)[{^5>ЫY �UI+]X"9g=?2_Zs "VxB_Uc<◱=4Y X�<O0 588*>HD8çЇJ^ 5�i.�̃$v2 k]i~6 A;Gd�PyQPoSbDIv ;d)--dWvѯ�u&e~Wvb1_>QxJOZ(~ނdZaxqg|o�lz ᲩF��m6}ͥrw?]"p"]"p=p�= h�;PƟ:y4p8`*C/dj`tp˄^SSUg,>^F'=*#u7U7>mOR�� 4=N>6>MhȾ;?پk))!#luL\n �Ouoy]nU'ֈXz0:<%QVBPܞMZ VrC>=-)/2�t+ 4.]fMGiOuJJՅ=oikiyUip΢]%d_B0,ڗm_z+5^y?jY~(aز.ѭ 1"J#нqcW2 �qRlԖIB)0 3o4{l+{?acB_ pyG>bPr(wb9rxdb"]/э0yw}Qǡ;IkIȟ0cOpWv=5 ̀ZQ<%v(-TG &HBD`:s;t�hO?f~GEҧ@mlMG:q #3}�Fù5<�+JBEA7yDu]YLEgO �=P-ob38WU�uMr; }N2.݁z{PԑE4CW>�su-s{|(1y bBxβÀ|TyF:FfW-r4$FuH]/ט(<⢜U2"9Ok"=#M릉.8Ҡ ]i) W@XWN�$$C5Ƞ=/'w:sS�qHd6/u)smSa}b?n~Vs/g�p϶ok:AP^/X r^.ꏴ{8wx/wϡ}{ xaF)ZaQ 36DXn$`OD@Ù" C^Ko�xA{F@D`n̗׿ cm_vjߺO~ri)'ʍQ-740�ej-0$"2GOsUUA|m屐wF)/$%MU"ѕW=HcΉa혏E!�&=װlF1 d٭1 Cϔ@P F ꔀ4p-t2K"jzzڭ9\X/#{v܆cļW\&V@_ �z?{fΰyJ>:3Pa!!IY7Q)A+s>ix<=^R]mCt,@E0q827ˏJdRRzC VqKs:_PJt BMHáF�0 @o哯EIDA@'�:=%2#-BOP>0yl4@OMu8 ևFͽ-H1A3@zUW܀x|ey̸G9Le�jR5 C@ ipEŤHC:]uQC$&V1d!L:;�ZkFe6p ~h;X]P ^'KuDQ tC`%�m9] $xp\iY6k�a4�520=PE>3d">l]'R<)|t Oef"� #<C+QH ۑ|psc,~ aT݊)E$!Q_"uy]\2|%|gwþFXYRtn4 ɀ HT4" J2hX%{ 96cR"P{:MIXᰟrG #?3�2-!<=yX e Yʘpa)y1TZdU^D*SĽ=h�C^3# @Mn1:j9$jtsQ%14DZf s]hwNn|B}w@ ]aJQC%>JS}J<YPt@_E9Nr|R~133^b@4,Lvï.aMƀ1,ޒ7˃RUy <E:CIeHR*BM}aؖ.ӌ4NA╹ PQIW5?(?!eEt v `![>=>~_k!<h! '㿧;cO9$q7�hOe@T"]"P6-3kER-Wv%F� PRGrIm뉀?)v޻|!o[ g�Oo9s|{:cpȈXc~/e~>\pZ8̜tE*Vn,"rs?*GbV- 1Gc^)C?:F@y2 `yװ<sp(ҍy0wJ4�$wyzcW Ɓ~Nӣ/1.� { Q:c EAY,t|`by{HrJᘖp<h�c Vµ uFGt Lmi<o 6%uy`1 xcCV}^1[Z;b�;;Gk|e g=~=_~m9Q7d$nJ>Oo5o9ȞYbk*iviǀ`;[9 Mg02s[(o 4<^ˮj70D]5TМʆ\ɾЧLK:V̱@9Aڣv>L0 RL�sA02�ƶ.īW]gto?zv\ENM},Y#3^><Veib0v; o*MxA;hHFqH0'kzgx}<۰Fl Ol* 6 mX4-(DTXVnDB^X#)}^3ewd9!pWl2HkC�Cm|^o.�ik�*Z ͉WsL8]aV_Oj|sЍmSp?>Oj579z3JcR w">ºXX$1GpYZsCP62rͨvY vBbV6R=j]+o|1++s|wZ^#znh7ͻF�ұ@5Z&>pM�+c]g?w ~k7phF>\3*� � ob|lcԼ4pǝdq{|['#,pU%yZyURDջUoM pʝ`Ep<9RYX*uySTX"]$ZZ2-nA&6ʝc:#58Qm+P_$ D?C~G澔T5* �Y@?{qX! ;FOw [<v17V෰CCP Q{,B v[QBݑMU0C)c߼=ش 2id�66zA+mj<\}elw.8JCuea}廓)Z|={A vK9؀d%X?n �[�p,|=hڈ =Ź[x/'xȑC5z >TOQ*I Є3²pK9m,B#)G93Mݍ}/PeSכ^UHHYbPC#Xrm\9/<BZe2xyM&w T�𣑾P[�P"}THh)3_EWy"-酜)x#�̃,2r069b~G=~-C1#>˾|}3ИѠy7l2[OI͛>ʜDy8ƨ عo_o>PÙ /&4d^7{ZQ&%Ed:<:%ꝖMB^&czw4l5hCڲZ`@ }7� O']"�ئy"n}g簅+у/){Go ЫŰ1P?%P 74DA4gF6`BpZ$n^:mekV [Tgk$Izo?Ыt(뚃R bii@wNiាAr* v80aco<@@4HnSh1z"t-yZ%֮*e|n-ۗos*z5['ne7@㰘nh  Mzo{9n zHL85z8/i`i[=n CQȨ::62B>A0ù,4|0 4*6i� 0GK`U<]' ͶQJXdHdckٺ]kUcOol߲W?/5_I, yt-?D@8Ev'+G6MO1o*]P}y?v�CnHO0�Ax|j{ UW|c^˹NġyM\t5I+N^ݭцRCƀJLtd(Lq~8yX@S'\7Bp9�;z̃NJv|_fC2^ދehwciЫ <=2#Y;͋$܌W̍?1:N;fJRcQEǑyƨa=/ _oMxȨ7հa1E~>-QMo5vhd9&u Zpj(ADL.w?(^?͇Ң-5 R7 v`!I€VqE%Uئusk7@[Pvw9.a_̣-~e$(? N{NΓ޷hSٓ;CvDq y.;dD|n\7e6|3L`9Cy@DO; P xD�4?ygrז@Á0-G  QSEgz/qV׊uW,9*<z>?jn6۲gӗ{p@� pϑG4Dkߠk5�,s\H橮�=x>ذhF͚�Fl|}QnkD�h E1(`qQ4tQi`WiJ}<8iװkGȐ6c!A]$Ǒ5/HМ״oimܴGx#yu#B5:e2S.cr(yY+_/#F7]FSkzF{bC��$= u~v~ rK"D`eҝfHt <y0\lu+́/z_<On!P^=̀Iz/ބ <-Lv&X| z#9MS /GXyjOU=]|oo۶�>V(mn`#"ah$i uqPΟKK2`A$>|}\E;蒠<ALW2Iidtq]E||,8"ƞŒǰo;j@[ 1KXލ'_j.Z:`l~uNuGV+ i: ՛r  ~ <#>EOpټnj꿧vоқřSZ 5d6gZ$kޞ=/Hyz0d(S2}bޚ`/P^ y뜋�E*ȱrs�.n+O3_G".2`5^}_lW_gb@ �Z^GPiNEBL"J8NpU&%8KvY:=k[(_U,hCTd.Tye2sFL~c7޼Q^Dc=,.ﲀ,ʗr}X~ߑg_gwH*T~!N FTP a}&}|@Z!#G@#ES~Ӌ 8 pϞ";el94�dۭ'7m 6/^{+G2pj�|_ݾ%C{pt-=uNè17W ~4>= z=mcO%9i2BA:|_s"{40T ?�O4�p"*6\i(mǹs4%k�p9<rg -pq̹Mއ9�;=k lCimNpGtLG|t1]Ϣc ch`�v5Mp>wy ƟrM1dɧ4h$F�['y-apNY@)>uB;ksٳ ;V#?𸫆ҷZ,)dAm0m¡@ !ER &@_ZU�,2MtZ=;.5+&F[G mm7tMO4O lW[j1'cKkMcCԩ-HBzW`f[sMy�Ɛ GzXFۊe<vH<|Qj!Emb=sY|Ӡ,^1|LO1oh~0C]m с2*P>𽣔q+^ r |==<]'xgVj5�t'`mZ4C-' _cnjhޓG͋7 և84 ~y+_Dd;=+_Osml674?dFTBЋVJQhTٔ*M̋'%Z\L: -f=/S4 }wwG]-*~}M�չ'v�>!@nvo>�HB%y-6)�A ȤY7Fk|>2(z^3o ,lp6F,jSC@ۏm6:$mPpmBߍ ̥8-Gl]تzMw{ˍe8nÐ5!`g !@#-g=eBOƑٖAP8mTGGDɮ1n:&ָ+,c)'<Le{7wwMaCo 7;S(8#g #/Hw[?-fNwKo�!P_lk q!lskd%%@B{@ 5zxxDcyr.G6/Ra<]AA؅FL.VaF66/�4lRg}h@2]Pv077'iay pҋ(&<IzԳWߍ|!TK!O WlJ`nihp2~K~ˀN8k'ɢV;@}C{|={2H�(/2&A@;Q6w7Os-b@ÈY/ϞbT)Y%/k\Ą!γN# U氵{ro>P%XFS)+94 5{bS!}6H1VL9Z&еCЍAzu$SV\}Mƹ,ߟѤ2|rְ2d0ԋǷ:T Ӆ2-#z `7bUl[#�>$,Yiy ܬ2flhSZaa׊ځ,؆> }YH xn>EU'f4.m1yq0 7Ѐh#6o?bKU}:.�GGC~LK^ tP(/yF-OmXOȐ]F+z!xtHɎkT#dr'?T'zzf:PjG0& i5N@^,خyv 7(VHeG_?E[WgѺh T)�3'>k~vpj~5u᙮)pgy|? ɺ~WGc?,_Fh##dml c$bNP1w[OhҖe-EMp|~Ӽ-;J`*b˹x=ғJ 2o=VCj['ŽFNT_,K_Oh_h*-Yszu(7<i5�(`\tWhGg?h1b<و�Ƌ?YV#f*{"_ڮIzE>=χtS~*MǏ|W>⍀b_XC }x0i{ R,:Mq{eç4u(c <ҍè8.;H!khLyrgAhٵJ}�F<L _5�Mps\Ϋd�31N8߰!*YUcKoK;¾!u[SZ%!qKsOf3,#o3vrU|v?&aw<#fww#mwfr 48۶BRFXA ?%,Ԣ8l^h 8O+rwy:aS6mKA mVFm^bbaxO( P]p<�cQ`dEeJ‘FFEqĵ`^ WB.ƾXdN3�6vt0y+=UC|(C4gJ#ήP8a1R2?E^?wg3-`z;>ᘯx]Ans򢥮,B|=ӡ:ZF!\HkyyX>[>?o~tj6֮c2Lϔ�˧P`=~9 ʻ'4rSG~QsWlLr[UkbeLfϱߍ}Rz5\!56_{ѼW)scXU4lj )ڦXNJ&d"0{jqػyEf%�TM,KNwZcQ.=zvR ד]^Pnp� Gq^=[/ۈ)˻( mK#(Խ9K c!!e2L<h1; )z˴5dMm@6cAe_ S[jH/XQv#>u'4.g.XH4\bjH=sD8x C5񕐭X|F-}-'֮`�f.�kfxh?3ۉum4@ô3ڦ$|KF3~R#u*IkjsŠ[\`-g]i㥫5.@~*3FFU<uRk~$#esR04d7$r!k3Nݱfb:Ըkuy~_Sӓd�M攆W>2Q[9..oߋҷyQni=-b^ygy ,"R\!-L^Ȍ~5ܫVq t*!pk�V ,j CӝfA]`$j_OrƇ<6s׌�C)I!t9:@.8@A:o{5O 42Q|1i-gK>GmCJX P b.ɇcSvSnЛ!<e`F $O* TUd\WŽg\Zy'\6LE}w8ʝ{ӺW3X mg|Tp(*&d貪YL)�M`9`V75I+#X8<eӣJZݍϹ�Om [eK Ķ�F":U4B =]A6O~'Kr)e1jQy!Wmj @eg;,gVdJU* %,ْku^//K/lY-[5ɜb~>qfDfdF."l�>d9�ۺGFu�taT<+ߔMэ6%t7pg X |&Čm184LˢmGwoϬl'( mW3Q-4Ȕ> YZY[tyQwe?#s v[�G\q::pansz=!we]C)6&@Mشs#�nrzڛ^YGߴ@o=kafCIyZ | Y'q C3O_?Z>;?vQ2rr@�revUD#Jr]o_C1xB^f1 ^Mw'B)όфAX8FGIOM=@1Iiho8 6+عQo`Ӡm{rÂ""m4e7�}t̵�v77_/ 8}4풿,h��TS�l~ƕ<0_]+}rg0C~? ~5ngcW#55ƍ2K \[*Ec! 7VY2"5ffFWXXL1`=>&D&H_ۡÂ+,yuv~ӼG"}Rl巹�p~))q0$|gqe+205{pBLqVqHuOMV*Yyw#@~v׿Y0ReNQ$7t'?{ 064Hk|3VGHT]_aE q*nمv,\Ƒ>xҟRm&ֻt�0LgnM(`اW tf갲qΌ1^w ȌN/aL2s^> Cg8.3t/i~}FA¼F߁| '@w){] ,µ+L{jvpg%jw۾W_ À* jBA;j@�+|ɞ? ?,yݲZP1[د@0|[@/:l6ۊc/{6ݬ lNH3zhW=?1,hp ChT L}+`Є]YאkWks&�86@? �ڍ5[=I;pn p1ݍ5zq8P+h!XݯU*,uDgDə~q:X5K/Zݒ,Pfk<џYЇd[Z!\- �6@h|Z/-.EͲe&m5uSh<m_%o9T ^[W?%ZF3&p=p*YR)ʕT ـ|/�vK@USZ{%:i<׆lO_7s�~HQu_uy5]L)�=bL^[E 6yn^c5?q8%n5ى8ra~c1֞2OӉJfW߈e*<CwպNk&5 :KBAc- :~ UDr?4n(BKK˴CT$`񰞠IЅ]OJ]}2o*-$yNFb̏0^Н ]  su@-_z] :7_K i{5IZT0 suܯ, \;YY 8etr@߲ʀlq뽔=Q/),t<<^BˆdF&gZ2;L xRӰzL ښFqB/| [[3 h:E,Wf,G �&I$̴&ݞԕH7m_ٗ@]bF$W%RE_nrֈ``F枿m)py~H]CϏs̗@'2+$2'tz? @2~,Gt˒B@rYP{:m+TxY&|#)$#l_&pd]5?zƃj8 fz&J>$n�; 4(j-VienÐҕoc̫I!NH? 3l˞4/D.AM9 ˸Iߦ/}91ж-MBģyˣ`Ăi.s3^4+��99y [^nq$#-G�^3FR@s+F]pHa^eֶO1omFc~X40v!D.� əiiT`@p2NO $LRy]aٗqGK{/Y-|T2NNHб:@˸_iu9)L`uS}ĨzZF�8 HJYzu&-oh,F f_ hfyx%,s:޷<뒦e_GbBeΞu-|`GZBpogwK$Sg6Dw [.?c}|ˤNx* +]vLs�>0]8.LJ@�ݷU �|:SH\I{%|Kvg[U { ۸-so~`a4UsaE36SO7OWqxgv:+ 26_z@TCi`W A/Hiޘ~\�8EGts~w|_$Ε�.S]x?+ss)0˭-EÔ=?q;;)umO{ }%k o<5]4^Vq.b3E,Lg5a2zMw2/?ڢȀtݏ1wݳw/= ??S?a2m`'~"=6xϠ=6pFnZ/Lz?I_P{u:v ~*Z>4_U,$ nV�-rW< 8i9T 8gv<y@S"H10„-Lnҥ ֌WX02m#-v`ѲJ#ˋӌl3+ |\0L,'կ�;>VOJ۳ZKA+Z_diP#͵җB#\*ڭ�,ess)pj[2K5}O|47}~xcaX8�.?0^g 2V)g^1LÝ?<nsLhM��@�IDATOSR4Lg{< #r Zc}a_isk , [i4W o:0JYC>-d)˟ӈ]fF!)9E258kF4f�z p; zUWd6_<Szt*q+eD9u!M(KmƟ~j}ʧ׹,܂|sZvF9Vf#)EFfI_h9 QHgӿ䳻˫+wy8t3>3QVd0gg&]V <nxhMc~SSQdm,ų�a1 G~Qi.#)"qΉd{]|{P5 #We4<Ui6vE � _ d*drD sWl#2ikۖ�:rv7]+"iW+!�\r$Q|rDW5G�`4l3Hd^sKy.ٿWu_Hڠ ¨poe;}}mHU9kXy-r*Cp :Dt-6* NA7g |4.dfc-r2xVem<+}ʼR dl?Q6vFAcCh325Aw Oi@: FȔÛox@/'p>6ɪ OIw;_4w ?%%t\3�\3z͋%Q~*ڝ]9�~YBPE?s89p{uИadPϠ <hP08q%~ϣbNq$?�O7aDe}0tI-yY?-@`j[ypZL a ))#,_!Dm;qk+/<q$OD[ӭqUp;HPmYE")yYM[?ڷA1Ocg X Suu<46&0<7& ]ϛ~P ym, `iآ�6WXzvsg:Nuy3Xg@k2 VQ{Z]1Hz?_,ǰJ'@gYJN>9 o{J#ӑAS>?Ts’ hulKeɩ9 ״Vާ&9 PYH#PF -Π_'ɴէꙪN[`bP0A55L_4-!7[-Uqcwnj)·�X#c5`濝  Fq56$$Ӝö[`|Ξp;b ZatCك]Ոe'¦˭}#JS_aJ$I>:{{y){:{nߔŸzr> `bǩUih ޝ(dm2z6վT*2<DpF#`<Xњ3 ^t+\$ LOG=N;1)RbVl=}m{aFH$M$V<!.a$I;pᚲo.(Ubp rQ`8۹hy+L8Mk3,a:N$�!mqpy]~Yd_nj-X 6 {ewY~4eˤ!_?Z`?vҼ)ɩ#W�h[ fRF3bZ"O3ns W72vp[i =A) on[_S[߳[Xk6ܰ~H->ʄEi(hvjf)*iWlχ]̧='麙~UůyI ׍V*莟 F _ \=^�_wQLgWX<+9g R#?>އfisSI巙 F5%,3 ?nMdS]"`\HNg !|h]}^q4-Yi"XS_#Mc#W y lvjvkv7 x}LWA"޶Y"Aw4c5Oe$D2~&o�`.}z෸W�vXgs>~g2a5OTUj{xjg x4LWfNdڍ|gsaՕjɵO;6jW6YW=�Q 45K  >+�Cfvֆ(a`*F6|4v׃M:WkieuX`Mqn%㡳H&a2a=p&̾/- � ʑpP HXi*M< 7\3{10陌y\yɻko a|>{`**Q� A\ʁ@嬨 Pս-;[6jLl*F16I4읳RcZߜ뎸NwZ <Si  Z=˲�>}>~Umۉgw>ԅ(h\m<@ zFݪbD"\ ̈技;K5fd71Y'5?j& إh#%ymh7a:Lށ4;\eGDċ\3M22EMW^XWp,>y:,,-�4P! b ,>NF=X2ä@򘰶.БHgq; dܼX[Z*ZnڰBMC.F<BJ Bg\q/},J#e5jC)څKPqqv,ǩ8"+vjWށVJrWثH` +'|Q@+ ʀ�lE}JonSZgnM\3�J/ep\DhuGư)i (a  Pr--_ jml͔q-6i3YJs^g^ ƴ4|h2bY>�lwnsLw;$<b/5迗Č%in +DxPXz[ u7'-OU0a2/sۡ.?N?bÔ/e"t{522LUnl+W6Nx6 %BeN?qN1u퐊v~Ҹ:c;d �bط�lKAlf87דu7v_n+q `пF � n cD�Mg,? 0P&c5@ãL =$7}]M {.C<~?>k~<2W٨3(&j%)Y[4љH 2|U?q%BY{V'ly> un7puEE2IC1V\t$6.%I3}ξgǖ3̦CGV9}ݠhۚe{캧'e;JJ�nb.jR sshvTU+1sPʢ'Tx&LJl|S~0 &0J_&ʒa2sv[|}pu%{\c]m*۵2G!@MD,0FL31  36e٧Жa2<GٮMtWd\vyZ'>B@c&|iфY q>Xq 1IVirir*|$/h߳Ug#.'&@l#d4I2''F9+�‘hxt#) (gcmwUf#W#fs1F cg"LG3Ɵe&3/cfG<g ar,+x4]@ `SC!QЕGG}M1!&RgfRBy6Aht?ʶpCD:+v($(�l>f?l7z  �|�DehBΡK}$h/NVi6M`+P{b <z\d>F_<Dxۧ 9M$lcVs Pyau >J[ӭ晿>W eDkyCLNjЍK&N>$Cr)lf3~czho+g{4lf/xV>g*+G?o}sޙX&_a%w;tHPL3ϗ\w(֒a7l`jdIaMm8˵ڐ6QxMeniO.6W,,s΂fOCh3|xxV�L5ܸӶqlvk#r�@F5L{nMў𦋘)`}D)ε[8B @էt/wxR?W7[!p~O +/q${ww?$BU�|0|ƚSۙ<qYLtVܙH~#N`@(·_z գ~f0NP+EA h@<ڪlh~xfv  o=R9VMa"<HGiL45b+JQPG͞u@箫F_J�f� ud�n$-Y~w1�uYdg0"3d/'YQ*}ȚW24wvx"+<o_U$.9dOE^1.�{26x>�0j S99;_▱pE �`u3BǮU�a Z[l[z`G\*hl79ӆh6ci^|益;m{c%d<7L`fڷw8`ga?^MKi75GwC B$5}üA`ss=(ߟXw̵�Q?7ׂ5~Hd]%^uaU,#P&~?}eoxgCAЙ /.NNO)g>5t|F׫u`G&[2Жs�2|>F+GZ\DP+�,S`IX[_o ^vvܳ̅63C_b^YeX*Ʀ`6M o}:[�p ~h~.X0mCm~|c_$ K>uNL,ރmvtآ6l ()((x `eUm /AssM(p-�hڎKd7r^6aG1҅e2vϿaa H2 foF\}8�qG %X\W36,lc;WŴ,q!?\Q(^2 d kd2nbޤl X@L^foe>Bv // /~?/Ãt8`SF/oAЉ1#0ˍ�AW,Y oL[. -Cepg=\k{i8ҧ$\ѭCFmKӦW:܊|/Sf.ؿZ=9JDVchOOm*4xS@a@bI" 뫤(ozg*_!W"K}6/y˥@Qc kr�ȶGqp$7?Wk*f {k+mN8Ԡ|0)ɸnLcvZTZד%|یq{\&N"ì}lg0xLrelM X[[x˷n(_7=V�vwwGp�#y-#`w.!!e-CcrO>h]<ME*yc<v8ؕ6 y4&fW o٧�*܆>:XzsδXWeXnknBBVg:)L6r\Yc:͜_ }/t@Є� y{6Ko4 (J,ER= =6Oˮ53UtI4!A]Ͳ_L<c1V6G!�f� *�n2L VxeX[]nܾ3|wox՗ a<Ǹ1mp -=FV)LgK?Ο!s$Z3)pSѴTXЏ1yvVޣ +o];*:S]/4}^\nhu͜ϙ #:kbRdgզ LXopL\^^aY+{l DD︙AX\ ZU0 kDҒ[]ጧpg^+=pxM=dqŢR�$}{[qsyyQ+ @.C/R߾ykBT*[�cm{0y$7^Զ]dKVf^ vq:[[KlH3Ǵ,0@tIWOrp`j/ԶmoG?qKĕ Z'\P-ۂ:a@H^)8*en]U T]Q+!�\dʞCHN EiL7u8?C\>S0?^ƽQտG DSG4-ߎƕl " !3ǧdC=oCEw䇁T>�=jG:X )t^Ot )[*vs[XV�X ~<<ka/Aߛ|ѯ@}y=@ An ؈9H"]SVJ ?*iS3 ۔fF\t R/ᚊ|'ҝxKY1+iFq>z|6�wYOor3tMPC]Àf#Lӭ晿ap~+�\1K.ϻ|Q)wy١;�x ]TDD�',l/<g(8It4�p?Q s`m\!t.WdB5 �v>h_lܸ5ƛ_WYOAw0<~poG㇬_&?œڠ �K;m8~6=�ll_o|{7sY~uȔS/'UiƂh D�?Z6�J`e+^�o�a wA sn4Z7]\3�WbRDc 2գ@Lߖ 6Kdlљ!e�f[ ӛLfKww&z<<Wn$3' p(|cYz3{P,oD?p]j(UyqabM|ڟ8rg`Gy"�߿xr"4lFFݾ3#v%z=+MGٮ�6?)8o6+@ vvG[k EG4Κ)Luk*ڳf…EPQmרF!6[[^MMmW�6dk$KJqjʞu'ppN192K"\cZY8Γ=' `s29YVk 䳿߮2}`Гc`#\:⎧=pnTMm;ʓD�FU̘W #S;kR(�HDY;m+�2{Oշy턿+F=桾7w~cN[J?6_ͰϊZa@Mve�l�s%xnÕW�װM;7@M/2<~pxxc Ve?Uп`Wۜ8+i w`x +H=3;֎:iWۖOVd+hkWl[H ` l(@97W)/^/*n W֚IySK"#v0gQpV2~{ K+�&Č=-gNDvF[͹i[p-�ZcoVy:sfsuxpuXX[F{~Qp>w=1FX?Wᷥxzedj1_[k'_}?wW(=CyK*R]#>agwkvxv>p :8#�A= �l_5S@˽};7߾'VzV]'``ENj m1.`#>ӈS[{V+YFyo~<%־n|+�@  AOpX0EsW&vg�21�դ@W;Pʸm5W">Ì&|NFqZNWoU*hսlcx24G,cZx4UH(<c!ci~̀1*Nf8 �.s�3eh)/_WX_߭;}gx̴uri`?bU. M�C4g-VBh[ vh&{#S(gbql_{CTy-s錧ފw*s*4 34N `DF?Ro*&-%ȱk@P6Lӭ晿M5=wYϊV�RQUy#&/L| MpE�-q H%!( �-)|u)faa*oY2XW }򕸀 :q(I8Y[F?LS3~g/'e¢ m4 {0kՕa?�wp !)0!?/:2w-~U l?Z [ĭ""+hYCgc-fJ݁YǨbݥhbig@IvBs)X`Kn"%%FfƤ8uPؕǘ_"Z{܂{=L|}JGC[j{[|r_vn"/텗f^Klqpaz b\~Y') ՛6t-NkMO3FЯpltx=B,?ZͲA?DR3A@QH��4! z=V8Vp׆֙bYbpvF~1 @gs e,Y\bZԡשp܃B9U00Zر wcb"zp?۠Cn'W)lS얏 Ӿ;] k("Mhuhog˿ۡoR*Hu׵|=G \uMڐ4ʁ2/0SdnH?K ë8>6Mx[X+Jr Wu{n!Ȍ7p}tG+q*;z TmUxrfffέɧ-yr^o;lr{YnYV2 @Cn lmL4Fy$OYNYeNش&oeDw!+?Bhqؾ`n2Q,8;#y5Mz rx:�~sD] 7J>v 3JOu(jzzy,CrX,^yWK>Vfl@:j[�^;v߰1Kɋpqfm&ȉ~{sF|ⴘś:t?et*Y W%_{�߆os`L?;p{�ɕCGMK-ewz*05C0||m{,CXiζx<7{E} }V@?HrP%@9eݧ̊s`>B_~npӯ BֶUVm5UiMSH{ttwcs+GC{;gK{ C5U替lC{͋/|!Dy\|nAWw=a/C�v1ZN{Ыbp{^ ~b@{Yx?~ơQ3s}(;aذR9O_Z9!“pzl> ˡzXת|9\ 5@~ @؄yڲ�9>7n6ɧC{z`4Ҟ1)gxV埀^!2ޣ|Lsv=HU_P2,Pw=qt < DxQE@y g �W‘.? 'nfvb<&3HgƭočCScֳih~ea;.? ~6+gj@=$͒9:C~@mpp/m" ܠfrݏL_Ǹ=xDQ`*`5I<됾a}c<�: 8-YnqW+,X=;HPwWbXנMG 0vNOLj7H)3uln( f>ׯU�=畍ב/w~eʣAٜ?g*_g7ϒw{ߡU֙fLb}f�{&x=_m*�ä ҿQC|QBס?y/9k9oG8&,4ƴPp[ß<|9 V/w]6ʁN)PzpXr6 ?ٿ7> aTQnЙ7S9qf31/ʞv W>>?^؎>�0(,*@nYa/Xϗ ?pb/0)ա@%�X29;6~= aF0  f퍅߼q6`8O4ko6A(GF2|zd6Hp�>u>aK0~- x/o8V<=R E:`؛ƍᥗ_~_?p\RݓpgY/|'|#`kL3agmh bѠ(,�r=*RC'7${w % A- ȖJgA&# { Dhz"ۼ@epmʛOYz !ߦ�U�w<Vn(*@F Ω\ ;ˤ^d\ 8:Hj_Wgǐ  LT�| ? ztOsm$s{OW9'GkrY *a_$n^s5aFͯ+aT-n޼1o}(yyXzi$ynd\ُ3Ɉ,cizE6/@wσ !6�{:KC=n#ՃyF\V\< Ы(m_.N+zY!PZ!HZ*i&Oi#>c鞛E*jw%Wԟ\ L[B$h'ӱ蒮)o we6e\GPh.;މt`zk\tOuk8Z6[8[\cy8Iq�> �?tj�;RD(�w@Am4-߲xX`o3|[X>Й6YxJB7ާpO8`eewh/OA{mv D u<mvhB4 >fwV @tu3F2mPuN�sTu+� Ӎ<30wn Ǭ8?G{%< >yT$ MAo30UO"_s A>2)9(Pcp Ôs�,23=khO{_F60~ pK.ƴc{&^#ۘ^#w٫:X> R?tg״< I/Gn`0hTƣU7o [+It"Ɉ=C{qvl[;)n"7W,Z(峌L0L:ҠcH]>0P+ ߫ڣ3m4xǑӞE804]/ۧjiWOb�8m;1\ߎ] 9;vg�7U/\9/J&?TߑQP8ƨ 1_NsaoH_y=I: 3 1 7ş(q^ϷH 7�xv.W�YzT x -̲4Q%"Bz"VzPX- .xu{*;4F/s k9&tXOu`ڍa ʚ;Eഫ�FSݪU? q&,ͤۛ{9;0ԴL Pj&,I9MoSxD$8Ah}_]5aҊßQd[KJӠP{<*u%�.'rc͋aHK3\Ÿ_>ĠL?̌#!cbN~PFF|k>5aq@Q<=]5mzoG 5~oEː``׳.}~ߖ؁{/s=/ߒ=DgY~6<˙pmiL(zÀ۴zF7ˑ G~F2Zv1{Bp"GTU5C?΃#0w<#zR,{Gw5Fk6�rF$Ī.Ѐ^yUJfS:zk/+>%h_l7A:D�A'jD<u5�U2(e}(WB�L 94p=}\L`[F(#ϲ&vb{%Ph{*ܓhOj0/qn9fhcܧF˟:57}xO;=p9v9AG?*2�syΰh߮Co`,&h3+e-czCf ?ɏB01K! @|`y�+ čݖ]f*f9/zEOU>K7pX3(/m~3|{�g Q T2z)TO`s@Vfk'�H` ^F[yq8f@M iy۬>>aHv+fNU@5LZ9%3ChxO;E#OU>x,;\ɷp-QV k6#8vMX�7[|[| BIY6I8Ac0E2=\=�{gGA <-x4,2& I~12izC-mWQ*,vg|j)|¦d  72x$*wkOT5ħpFsW@dq%�xf e'7/墉t C-�Lm<؄fvoF ෸{2 4,4]?啸"O奝xYJVG?yWvn|{ :;椿ek|_wU>�˯>z�n TAuT! =[ɩƤ;{?~';fA.o}>@)Aox& xJC�*7AJ@ۛßvD0>45-ae&yOTQ4v6/. A8M/+EZ(|"&Lfrt�W.bo_FlC@sV� Tf=s(P]~3tiN2"ߢ~*u|D7` ߿ݘ53>GD6\{.I4CgᨸPWW~yj;`#wY=b[H?q>Kbbxx �Zgٿp?`~w&Z;wow7^;SN"f*>g-o?\7ݿ5m [k29Uexs Gnh)�8B9w P DV>F}o؍˟bJO?N9oYL$݋LcғN>:_1yhvY:n{�?]D XWreăNG*RWUNWOyu3N�E׍_f@>l ?u;su&\]_)eGS:~^E{Y hJ|}+t�4_qβW=O$/lq'9@{lҟazLgLEEA�0?+�0U.!0_]]f%,�Qwn SeqפFc KxTqi%~O?lfi^e6APeGhͽq@yD!K[�߻p7@Q$N\8exC#1M.Oճw, >qI^U݅ < fĂ'`0<{)9lk.N\RY9.MDyx ǵ=\m.~BoJ@#g/kX˼ FOIpcy2=2#,G� 3{Z;Lc)W7q8zn̲.hsx�p {ɯ!xopmw^ Qڢ*mYt)cTӤNI`pmoN^h$O2A yZڳ8ؽ@.c[gi#-BiCjBCi)M] ׄ{f85׬130^ӈEᡯqi ^ qmFv6&<ٷHmQ[u| _pX{".vF ǞG)P(=fu Lγ׭<וV`մ9nҚqtLP $@LT$AÈfD-R5߂y��@�IDATf)Ǐ9wfuқ057н0™9o8F1RdU�{Y8V7^e9eC)n@ֱ@8ΩGclcxow?pXAx1fQP �R zmH##H;i"05N_KZ}m̦gP:ˌmK rMU|i;A]]}t4o;W_A;B=H%(00o~K<nM4͕@/!˴T}v4~}9qi|28g`Tr qe`q||5fDƲ662+xx@*ᚠ@oVe'htﲯ|�Qf݅1G0 ~BE#b#%>:5(Z:nl`SHxMm OO357U{4/5\,e`v�v#�8aY,0+6<5 07Q)zg˳&:"LqS6M`s_ϢodoS}Q})A&>^\DE!9hjDoHJxr9C")�7J)`jr=9/v||B _&s:7/vx6 dG<*|ѽ(=fNv80OwsV@aBSn1Q83i1MOoq3(5?skk@ &p=`܍XV߿%?�9 !�|ThgO ;Ccƭy~A:gUi+St: /4LF:4(-�oț�*s:_l7:؝݃-!%O>Eɍ�_fw�7e*yq:/f񜕮i $)Spr2`qD~V銑L?8#|n^M\ D.B<-3ӱ77_y) uw)ɉoefy^zr gӴʷn::3ۍ�fhcvruw]@QYf~.B@Y�fb?_C@^\V�ټJ/}Wڒ1O ʩgxd.F/~:lsiOfϧmh83}?UjM9+{Bn|tE�P3`KO$ǘD~fQEdvx�ϊt1'ҘB�WcSw7"r#"WJ�'k$㙛d5^vfcm+@_L3�{د W<޺0` 9RYў64irOmqTJH ]gKeWb,[`5�$$rp O`?ߊ EBp <λë*vhnɿtOY~Wn'Q ; *ahP�8 wT|%WIgX_YQ\!˴Sq*rUvjOqLgqΊ79Vq&߄8~ |1+�w!V�r(S� ]__% UY3�4`nR x*C~9ۓJuk V&Ko߾6 pO�FȄ_G3?J<1_g�b@w9w`Az/<ڒ",JNxdזٯg/^0p{c2ij$5K W0X?'_c%@h[l0�XfBn0}3u`*a =lJ.V} N9 >IFسlW0`j~= -II/b0�Wr{61V(<(p|1E@ @QvG櫥@.^.2f9;ks?R:6}^RP[p 0A@0¦v!H9PN`;f;FhEvU5gif~L2SK ഥaf0|²�Яe?ws;j̳|kί^?!U|2DXXL!29�):ra]V'V (ZDXYFCJWvE]4 ,O�Yvs3�|ȳ�0 aۏV;+Hث�h~ZI}tZ*D` 2if_' jQF:q8|$̍e(R }g�OȕWL@ N�D ( onI 7Z`Y^_Ĝtm_owllܥƿBJmngoxOY`Vp@ΰOݳ8_*rϯ _y:?dW;TpK%yRAK5w%b+4�.}VpKEX[ۈ Maw2B*ݙu3KV`2M[<a4h�u>'V;v'Y_ǧ6DdEC=VM1tc 4$-.7n=3$RR;8S I|xDFk,@񆃷-rg57D\'pn< B~kN.8$WE)yKy1͜&CWz-J�:�NA&99r !aߔ{$;鬩]1JYu?C˵$n㬿2f+�Eȶ� ~�nzK7(4 `E顓tʛ&MᖙM딥mY2ղ[3ٰѱ15 9n(]*޲?Ҽ*u]6( :${;ZOi a8Y7oUv@fpo椠gSxg�>=qD`-Ѿ8al+60\�qx˷ ^kb2[myLc`_@Gۈ@#<}ΉoXc텪yǏWOvʵ5 dVlxNu-fF2~36Fg5�k\u1f hlۏUtyFM +.a8DKb4>y2W~J[o22S>cSAEf u+X+JNF*(Lrb!'aV,cFDn+p `MWYHΉep6rރ߂_qq)fHXzR;<Qy6ʒJ&uE(0?9"P<D4zORUm;fvO�9yK/|&Z;s;=eOiP/a5НJ<f�;r܎2.>5_w\Pfʺځ{~Lg{_OdVg'anC:P:"C�nAx ݃9Zktn$ӁI33hmC\E$)Sn-��x-:DiW}T`ҠH9 �("NFAcw>1̃Xtipkc'T:D!ZAgJ|v.qvs\*/hMIEWxXr !#M҆�]li{"̭IC+u%g�>=+<sQ -«ZFFN;-*Q.K wDž U_-܉,ة[~+i7e6lOƫfxr m .jq4'_s߻9ȡBnzu<~�[�ۻ;Ý^և_mb9?G1(ë宰ܱyC\wݏە~[�{|_<DB@�ar8#[g.U[f^/$9(xJXPu6L ""V{袭(1 +M�mk6iOڧm<O &C{_D <s WB�Dy3s8@㘿VQ0s(]S%�i؏{�y?=L%p6q*h֓/<y9˒|Ϻ06]L ЮXɕ?B}==E-= zXQvɪ]SV4{ {Z{9!O?uh+7@0?C fz! N�uXԶݶFa~ծ $wKwooCm5[עʹNq.L8LpՔOIՙI?BIΒЯOm:VjHfsǗFdlԬj}iXD c#WC_\򤯷%]͡%imgk+`{ܯm?s<xgiu2S(&`'xU<*]g:>uO>e3;Z^BiO>ӯl)8�lymwWi_@f=֭8w%�{ccmqۿw߼8` ֋|Fa|J_�#vS hgpXn|6*SutMQ t 5-Ab~ j+�S޺}8b %h,o<Sۘa.c*4{T㖑?  9o*Ud?)�B�nQ57ϟ$B%:w<�\vI~ln?ZvpnbS/4~7_ar[d2Ml`f#tf2Md[wXֆOֆ59k>Xd+�w�``u߫o@ W鏶>L{}kwcssqp+Úwũu(̱kq4CSit\}jјƴxv{w'?(B+(iJɊ�[A�`G uB蓠_mqM$KᄐKCl>$>>#,hkp&̈EO - *"ʁO%aFQmmфj7Ksⶄs<)p3�~~0qG*e~\I0(PZc$m`=m1(G�g&{Q[7o Mgrs�<dcgw76띍{*<�NI,LNWy;i`^B6?9wlcܑ̈́W2~4 o<77^}sx?[| ׶m+M`-L =c_a2MU:*=ƥgϷt3 [f[a9ʀhuwan,pg Gk 0%22a~}L5n\OxgIaa'ٯJcYȊOt>pt0|J�~XP_tRn(JT~67*-g(`V\; ?FkVЗEew߱\  Y_gW-|bp@)`@r-fLSy <M0qGKA?4}۱5?eQn{RxMn} �YXFOkzkPQ�N;Ul +]20ݱ; gÎ(g۔_v?`O?O"0p/H^R(rIa+'}yZM0ˏiWѨX/P9#ZEV�8ֱ�ȑ@o[y BF+Vr;He[#3'n/ONjs\) vg�ygik{(6} A '_2-j;7XvAx7? F`9+"i' 1{F,3#C4 ǀiuH9ǀp Bj@ hR0XkoojC'()Sb~ZΦ$=M/?td>kXx' K,. 8X_-}o+09Z w'<C@Ҕ)u]ƲVk|[TE߸' '?q{o姏 ɜq"/A&t ]1W-2R+d2n:N_z�:/'Ex!eTϾ}~aF8G {i}neZUrU~dX\O`|63I+~E˝lz8 KY|̳4}j?&;ܹGǥFmߺ+JrfԶLVa�~7<>gL�Kb #0�t7V1v1pZWՔpntzÜܘ{ׇ)kz´A몟tZ )�&PXr=q9IrW_&n/ `rc,δ/Yi&g=:]yM'HyޢhFT΀ /[?|BlcV"J%-q73!>!:5?/ Rh1׊Bmӷ!!t9P|+;۴2f?3>=fw,/`?\ bHIq {RpӰrDa^"voi<0H�3\pv0vw[/}VSYhu҇]p5�Zq {`imX>1(=K!YXMV_Ig_n7 A.nSc`�yav3J8൸T !m_?~ 6i11tР%]ffփGiacz߀M1,p^yzX䰤�P4q#T2rUlܹa"  �n@D͗GWχ � Q?yp`ऍV0}jtV܏Sy7|�t2&YFF&#WjPO8 _CI- ֖m�a(iqk {v_ϲ\sey-94n-?e^lL<z$z|L")fR0ƕj+7_ 凟w�7Ə�~  2`R b9n1g5~_]pJ]:9&BDwFOZ Κ1ho1F�lG85Ty&"=?cg-pե@gҚV[! `u6 m۝/UMͼ3�2K"Q쌁sR`ln9pevV6##Clgg*:f`==ޱ Ib[Mڃ/$0e*lSx AzG.`{E/ o0Y6hΪ$G�΄8X W`]Dφ>pc2:aMS�J"ei!2my=GA�nWTyxkGMmԱis P!@$R �( B}0`J]`{NN'IJ(^cc&&fwc6vb";3EQĻ8y>YؤA[UYwVYW%rLl3j0a2}Vi6]ǻnwjcM#-`pJvmQ�Сۧݰ+0^s xuS_UgIcMJ4 H|4($Eng JZ_goL?Fmʁ*7mFӌ*7DrdzfFJ#F|nt~51 l-{T2S0�@VƜV�@{OG:�P.<\sblz ��k_F [?c[ ?F{4DW(`AL_$<_>ޛ~{*vm 0;n (h re% Re54z\iV[W#>7>EC~i'6Y~4k?,vZ$3eepm t_&㍱@ڎ!(t*26k[gW?fom\6s�OEs-|G{HT4mA=%[`@�8޻}8wo1% y ±8O{$L|:32OG36|T_nNwv='! AS,g3eOw?^C]٫* q-_߸=O?sՏߘno/OP|((VKV l0ۣDG7pm ag%x1f?"!\c|ɇ'Q$gJ1ApQa�]n !RI@(b)lD/6W'Ͷfhnyc?onԍJ).̀}SOnj+P=a-0�!QF}8h%l~bW?$ںl �6+MbP$F*k6ص lG}J-�/_ߛA “<FgZ 22vol{e4g`x1{gv.lC}'}aGNaej5?ﳎҟuZ6Yڂo]937?]�(:݌K6�θOF;nA=�Me:.#?LO+ ,rڇ;~A!"/g^7(G|$*5+0`4Yiq+4nqF~k7Y`{j5Ա`f _O;H~\zȸ;鸕Ώ;@?ۨ(+aBm <WMͼE�& ՗cDs_3{ ++:ζ!2%W \lNᆭqS.]gff5#3{9ckU 康:A9KvLL&wso_war%g%˕�ձfAVVy\`~6@ P^8^VRx fFSHthڶqџpLDWϼYa\O<`;MpZe+h[EJpc+$d1K:"m|�_[)Ȑp<aɜzÀ;b1m}#ѯIrd6"4|v0y~k| Jѡݳ~A�߬5ʶ pe^.ŚC/ķ˗>ɏ똡20`X*�Yn \c9G7r@$N`&D)~tx 艰NpbOy:_(ˎ@]f}:K,B]W�7`3\"MjA@",",D� qJXlNp ҿ?q ;Y 6M|Jی3m%lMH!BNx]w®CƱ-QOi诡v"L@h/ F!PR%NG8g`z+q}cW?6h>mtS_/f'tQ�NyWx<uvBywPn}pjov߽("!#*7_9 ]W/+� ސxBmGH P$`a9,-׵ g6Ѕ[_t=]8CKa+0MRHCtlNCD3�q>X^G|_w=�Q'f;y?_/^J9^R 6tఏ8۬pۀ۔̚l1 ^ ƂQTd,dpjڥ-u#6.VF�vMief e*Bpn,ߟHJMTLpJ5b Zfw(nSGYQDG.*'9Jk]Μg'$m]& G,.yl@ nGnXYHFfڕ3s=+0Ј}\/�gD95\#Ola MlD5I$װ*q/8B_ݯƾ8LJ53{хHut?<'*=$mX#YR?\w_N:#WW*مz*+^kcΌ eGKZGZ*Ca" w0Xq {ӗa:}: [W @ӏ�`>3J@ ;MZ[b�dXaجg,:θ LEO6M8GvP=p=0W9�A@> (s_S�3عnʸۧ{c #؝+94YY4g(2lvxe]Y^t,.2fY InxÀn}YR)eA$?m4m0(&/y@->T,b)سc̘ǡ̲H d}nh{pjK?jh'Ce_(FId7Lqy&@ɮ6D,Ol$FO�rs0ʀֽ)\L_΂@|3c_|V͜yv%kuTN->d>(x"/b|!q]ٷ&@CE'F0pYYmb S)ET5"12_S36G[td3rtm?[WVPtxLYkA1{oM9ĠъsO@N[0Ϋ ًgNP] �3c/BL�P+Z20[?."G ~e fk;p~%o!+i N`W.`/[BtaV&* d=�(&N=UY^zeoV׻g_F _n_a29p7#-m#w米:ǶDH#/@ ',�6S+YIl܉KuY~A}5n3)R̲.Kw*@LNp`2B&KY /aN*xRZޕyQ -#abi^ӿzkS\ ;v5We"4r +i1^z�K7o:d?)4>Mo�$ŹLFh[u-KsS ǯB`sVJ3Y|-�3x^�topk~{{ӛ|޿,\ (8C)]1 [665i3 s83wO{ Cxn s�؏|oM;v~{ p!:T |.�0 ߕ�mApx%n[<^#6ۨ[a:\&,:׶;9Q\0ae,*g袸X,�AQ?cqV@V͏>6�nhױu2Wл6e3�p%O+\@ aqObB qՖFOrٿ{`s 2R3.[QO,;̜:/Ӷ_@-p{#="�BxU6spmPӾ;w i]ٯzڴlp~Mwo"XD50,n)~Nwoa˕4|LxX�d&D�CR8ځamD2ZH}2<Xp*s)�rn&MG[Lݏ 1N[jL߃H{<!OoEW;yXqqZ΄ x3<D-Q92% 7,7�ǥ�uV3ԏqm <*+Y  N-8~_ i9;O~/�.Ҁ^ƀ'DF D›X*: qDT@k\ȤnCl߹y0XrAdѦ` X?ǰ<t?D�0l 0mLQ_Ζd+}j=~5L-;>W��㿂�qmZpo~ƭiwo|ںu!<㭹0s(v sF!�j�b(赛ka&*A9_ɮ+\GH[8P9�X'LJ!ôfe#|f(1 TRzt|di4 Ow72uF垀,3v:`L7Dn<w^`s# L;lL?GQҿ<O,@phE7BjÑa+kcUbm%PU 4K|$IWgA@7Y@n--v`fne[*AM0?1^dzL"|MO\ Ͱnf;(!K/սby/#M^T&<4B?Q4�DG#UeEU>}7+|L:YS#I->[ a,.&?3`dF;n�_Ɓ;e@*[" {^`ȶN+_|<0_YcdsͲ ‘ws>_%KT:|քeg/Y]P�G`'pݘ [\jWᯄxbG'7l�ǡ;upnw1.; vBZ7ʀlvYH%,r1pu[GU|*!xdB슀KX pٛ„E£;~4 pA2]D1m:X.OPʽl)V\=v5U!7McҏrS xa NnO?f`#W\jg%;^Äe mVܙ W(�'% Xt!p oő v@slG!BV,\Xx{o'[Gu?MG6pB1pԦ%+=j_bRGQi<pO0Af>O>@/M3*'2)gX%0�K<e 7<'-D3z;<p Ѯn|Fk&@p;MXރ=_|1+EN"5˯6! 5~ء:(I$$9n}Ro}76wY>ylF&ŐDb16]lÖOGh' 4ozy#A 0_[G�@\mO`(<{p][VM1@楸;; Vy}/ ĺ S]upA:kɣ Խw}$1mr�p ,2qpFkƀw6j2E{OL=tDv t�x]imw;=,M>fS9֔rkw m /߹ɍ�h+'[x{, pcπ}%~G$vg LL7vR`mA) Q*wnUى Xc+/b. 2/E{"~J4EdX$q{_ʥwg:PlIYR=3A-LPiHҦ_×p݆/ai4xW7`~oL?]>f6L߯OrE^sLL]ȚyGl#7{읫w9y{8daMӗl=Q@dr/}�2}p/[5~.8̟(�ԊͰ�tką{ҏBN\xxzp0A!Á;*BH|&#�rr#jqM� Hm>2 >O1vx@:SW\Xp~,>ŝ [Y–No6p{N6c,`ZsÀ0{.)b> h}lex50 ol楟(¼:tX;IT$vEh~.q]]m�~~ o(ZS, _3^ Y{ߡӝ'0.=\ AU_FRd^o"At0 [\p{zU@?3$>xX]#GXh_ڷom?Sm]i+sE`)$148t]�r0!�ssidx2N<NxuL8Z1;UhzVd6WOi.R :*"Kx݂tٱpAW90m*^QW+pѥf1yϯĀ@K\!�Խ0$F&umhu>?ƌ}s;"ahfG_ 3QK"=EӺAuL0N9(z= +z�ܣ``8ugrDlaa(e_{QǷZWٶ,2{i|4O\Hy<禮 2�q`f3gI! H7fVIx 6 ܡ1^(6A# XfdeqnӜ?-E<7y 35!0Tk-7�,Nr݈,| LzQ~wlVWB�Hv&ץ]$QܼM cl {}kg.;hEU޹ܟÏs� bMXDcYvktH`9NGX#yLĒ'/rr+VPϷ/c;.cpK(ц Vg%�n2xO��@�IDATg@?+\tX^tݟL?wde<s u/Mu--8XMs-=? -433}< e}��\!q;_kv.;{V@e6">i:S?jʀ`+}x;` �kvl-(Ǫ \*�~z___;}cq;y3汚 wynsȘN!9>ٞ} XUxuX`'*@wd[_Q8zx̅0@>~x$BK'�BTzG;<ޑAdA޲'=(ZMN"7:?ZSճApKEh07N:Ns߱eh!mG} {oN[5frJtxA\fu!`bLWWߥ\ֽ"k:n9Orڼyc@ h/#Bp\ = �sE�"v4a�I ^( #Rs 9 ~2BV ػ6+"ppimor>BA`}/pjA�,?/VhT`FW0W67aĿgȗ*$i48_]8<];/N|~u!'R!̱Wcg|j!�@< *Z NPHQ�aS%@p+0 ol楟8P|G}\9΋&P2Ś;k a\+DSj8sVA�F/ Ash7;(q-)M-Af"9%t2k<T"jZċ{Kw(7ӣ4!_]gƙeVg"*[i67:viߵ"B @tWVi&_A0IK xωw+&G[z).6~g28Wqz ʁSEɬܯ^eYV-QO?.tlob9 )J?z6}? T 񊊗(5щ+gpFpvFOQ:9fBt DVCuq�.l3|놝2s4_a)4SAwǵ"؇  .[O!e97^a͊H],ͅŲnlCy^yW>@ ] I }i)-dCS=+qo fXsozC v3u!niQ3!i$>̢u/'C %1ِ.gU3-0Qn<Gl@׍1K!S@)ν{mzRnbm", |OzQWioM͘h7m>*@rTXj8Aca`#nWIeއ7S7%6 =1+q|OTis y䝔JNwm=AE~?]VIa6S^LǕv1*;KhBm/a_bxfR @;']!Ht"`_g ৷ >ζCJEvZDfF9cQFQci/cLJ~`auK`r Œhkа Rkw_z+ewfG3~ e8f }7wc(Xδ 7䱙;t`f6ilC-sk_a$_E(xbٿʀsmo$vf,37QrG"!@€mdgےU pJI%PA'ѷ\TKԍn JiN=8ψol{L#ZtyG~5V`XW_p(WY&4ؕc nW滏K'�x0 o/^^6nGKC5}��r(ゲ:_}m}w"F_ f6|uvvXs94"^x3h!';*[Hr-Vf$¢,H]'~{8UIQ0}�XC_s~j ɛ_ Tp+ g{f+ ఉ7@<c^9|.<k?zpx>\*+G/?b{:|c�ׁ{lY*\gF^DMAJJQ`E<~Btb|bquexO3-t;bJW>mk(wf>g@[2 p",3'+s> P%yeb]3�~O|!W^j,AZYBJ 3;NU?a�/ClI8_E|oܳ"Yg$Rl٦1'ǜ@c 묖IjIKeEίjx6!0so ox p!_A �D 2lhñ%F3GǀLG @>LG\HU i| ]͈rg(W$’/#OG#�<rEP�ZB�[G8ֽPj.;fz3›+~K쇏 0H:>m:4)N. VچlLݵZg\#ƯZȯ� F#Dz/̞T "f^Ho8+P$^4s85<K��tsf uڙbCT!cB\sonz}1Y*g{9?>ga'̫~3{u K0Y<vF`lg}R 7Ɓ|a6z,`CRힹ/ #3]q{o> ~jj!eF{E@x �1-#N6p'J| 5GԀGZf$t.-/A"Pxԭ Uh_Ʈ9,Y0OaՏ2~ 2+(G:W�K1lԊUϺ3vGÖ[_f_Y[9"Wi_E:�wvJ1д,c$O/@t<$x:3ޘ|k&zip]<3QoةJ}v֧ 2V!Y׆p3RLLaÎ�`1}6K_ߊ_t5 r ]bļ&Fdj̟u8 o8v (xFͣ]a3ӧenD�w$KH, .uyn9v3>͌߫ cB(d[y1>îrT{&HV�_a?g4+�"."ڈ ǎv/@_|[tܽ}ʆʁ �c8B�3~cIZm%b)Re5l\GЕ9$̦t)bΖ,s,^onMsk*|$B22:cc:|^*p H3L^2;"~wPgcоHJݣڵBc ;05Rw %Z =#=q(Dh;?NG럚z -w__ڭ7X_'`G+riT[ :hx * hhđg�Np@�vaPx �|\k@zG>es@eձZx7^j,úX=%Gh|K\UUk|qU-[[i&tϦqc; OOQ;ip.q(4 8~A(<r'dN.8Svi8R4<޳gFޯRtLUiTI{>f,SPˤahnA$1K h no>~xfHK$ZKZQ4e`Cƙg.@4bC$a5H^k'/Vh;ru*+�sOf_M �(ںN�J�+kw*A S(k , D# ;쵯-)Fmj L8p0(A8Y 2cwf63|8v"z/>-mF' A[TVt!�@t@J�,&PxVI 7=ǂ--*')yu`[#i𧅙pZi&eg6ìlՁU2r Cw yܫÀvMt#Yϑ[rJ^}k= g,pvA@L@*Β)vI0R]0c{0dˏDS!V{w6sI9+ 3Yb& Nx#\V̆>Gh;@?asKeDAReFAbJOqE,Yx̾?nd60bG0]yġ`ZK:'@n~ԭrt,t2Iņwߓ2&W<$n!Rƌ\" G>rF?t8 :nf sG_ XfsvO|qTBT7V]gw6:M�<ڇ4>5z|bxqűI>[򶜥dSpί^jU]&|DBʷ޻?ݣMv5L,&怉},J%GaƱϹ1Apwb|G1K79V 4aY v C>Dm{ӻ2�2?e(J)x X[;𯸉Cx8d 3k|aÖk$|..KdZ U(f'I<\j\ =~_p5$9fvq,s%W USؤ~!x<L=pbĥ}|%m9N>xz=IԯwkdM= ߳J-~tO>Im8ȵq/ is؁-p,5ɷ�/P[ӺY~s0K~O/.N4x48c8~9h qPm۽{{*j*#N IZC Hv̆Àg1|951/ʛ q>}r& kU @*Aaut*I6P&XC4SGgG&qb|4#jV"edbMB?@xܸZ# i r/cYFp/ڞC{߷?j`OK!:q,Mv�y5= ~gF.=] 59kw?= wlC\ g5>pp_wxⷔl[+=8z|a\ꔇdjJ!'T63'*ۏ ;mBG۩6g] C}A@Mw.Ԉ8቟;AƜ^LGnD]pփr>g\k]eU(9+*>=yY㘈i{x^ "K*:̡VG|ӭ@J$ ?CHK%R]}P\ w gP!P3ф`cp mx*e&voOaR6I`$?]p9?J8V88ר;23ZgK`<ݔe|XnmxUAH04c'OW?ti�2p" GXz;!@-�VpEVO&Ƀ:PJ)q\U!>VA !JX?6>l:y�A|�Џ�-�*Xlo#R}4?6p9"8Y(BՎ'Hr@P7FK$ #4AXD#I3>'p3(hOOpn2P&w 6YpGk;+Y*UcYm!W/Pa.Α Eyg�.Z{Z^1:/ ~U,cCk�Q=H? M0=Z>Yc ZI{\oV12iN Ny꿘_-gI*�h1M%Q ? ԇ)-VM�nr(Nv�8Jey_H?2 Ӛ|8[60!E#Y݌ *(gc>�iX8OGlweu?' G˝5j�e4m.rT g�rOֺ ^ 4ybkyf9V`<a%:>RRk,cJp*v 8羟ۑwgQE] 8LID}%V�.Rq|ߕ9K;<)vfM`A@?IN@(7L1I!6Ovf/%qfm6{r_?X[DZ`a,)6?d^e LF C~B,]Wr;ie@u]d|6YidFO)=L3,m%濫~i'v #]xO nȷ]︮e hpv_"uZ5:@r"S*c/6M emƱ@Ƹ\aK*c{f߉Ϳit'0crpwA+KVsľmDjr|lGUW1#t鲙.�r%?. BM8 /? 䡜9@Ĩ0n1[*k+_޼%4miBq-fҦŖ�[2~4e/=ژ6 ]C\w_ۙmݕ\d̐Z ն)eEx&@fϧ j`u\cGV1+Y':9]V�FBq2�r+``mHg[<`--4n&_~`-lQ8s5�0?-u_K?KΞGJ2smZE<zs[l#8-ضPLV MMv^~&6+5-cS�1ݰqbH#li\-{p㟶 7mqk;ˢt1 >A scy(cc2'10yp~wo6ikR ve T9F 0iaY _fk<~k/7wvc<HĺybQeWE"XC@ә^g" p붬J79DL|-K61|@a`Dr~#KYF X~0'ql ڍD0}|;. a>(ZQzݞViimgj �aG(�Kj*(� R]ܶȌ;F6Sba.'g?p�(DBH Y"5u8d6�PP!+lxhJ֖|^Ljc;:�hOډ?Xg(`΄w[<?6GnMxWX۲0M0G5+m'?!FGFفoD4^޺x@G6}�?\\]`WVK^y 2g`g�H@/ /Ewՙ~T)r Ѡ E@Jg9D"1}fA`6jJ } CE??0Ev(4ĒC O"23΄qJ~Gy11͜(tjA| ٻ; >2=qvGi �!)ԥcl ޺"CM?+XQ MpOe@t6|ևlp.-.�a%y�sMGq {Pm3gއLđʁV _uo.P? S z+'-NJ#@D-sw Uc@bB 5nʔ+\sxbÂ7[uWK3̲rWK^y_9.^cXG+̫-d$q[6:K?m;~xVũ}YIc<�kPJ9!z-N<Q. lTZ}QD  inlh#WЬqrA]fEP~TB,G3�F@n=*js(WcnO1߸2R(i =Y>z26ŏ` ;Qj*bL`Ɲ}~*0Dͤr`G�ոU.L aDK?9.myt7W 800NXdڮx7< :;2 ܓx=(h|m|.01UҀ7V#Z%2zCWa_+[ƆScW4ìbp,Qzfխ+o~3023{msn3Fd7[Clg6V:~;n Qe^a@$].#IxFB*틼t`z6/L7CQ>+LҘyd[HG 0Z#˴;&r40Lڮk\Ni~n_iF5?>TWҧ6rK -_@ Be-H-8)?dW�)F <އGQ?F?W2Sᶎٟa`ya=}/c8~z`_�++rH-yRgTu.%YWQ�\H(B?(; ;D1}os;ƈ1~Rx1;4LJxwlpxlr)`4xwþ˾ 5yq6IZ̲fIC rx[Qp~Υ-, Z0_hDNkWJ(_;7ǽޖ~5kf /T!Ezu3NsFlL#a>@oXGA=O>XcaY =f �%`6Z*);?j2:F)Z˯HT+yV.8`CrU}:,ݚ7v8HܣoVf&4xb Į{A}G\'~5�%᧹!a &Ǎd .A�w: i9LVw<*Lcۄt %=`l;kݏ\E'z-M�ܧDw2|>=FaaN?ݽ*0Zw2`lSA;j,1d-ҝp+C! >~5M̏MoH"~{.y<aDo>SoxA`C Z |8 p aK0{ |-͛�1<牏̌8*П<�W!"R* U nm}8K  _a3㏶f. 7e<6_;q;~9ӷCl�۴KA|\]�'zf}O�l_L ʠNQ$iZ{M|  vQ�"<eDc/P^~Gc>LR4*:2KVi>[^ ^[~y3%((}ggQ˙G>ȴ FOD;.ww!s߃^yE@>m<}@e [g8r-0žE[1\c E WC(84 vZb uhlc wϽm2SOws0D2Hk.7~e<g6xQX,h&BώG Jz gv�OV y.j`[ V�`7Ost\J"'p{nnq3?LG62:)Y˹ %^z_>ICX ٯ:۶Y#Ǝ0�2v@@xHаZWp8G OaP*QB*OacV%VN˟~9i~;AX!c{|& n E7Y²ga[&;8+ޙ\9Gxd#yƪ+8u`!ڤ-'lZ/я|wm'ͷ�.Ҹ1ҿ+SX O@p 3#`,!}22Cx1=j"( HXO1L3wOw6]> `/;4=d_'eZzS ,P2#8yfsdİ>6vԟ V@Co ( +`-' x½yX-fT}Q M1Kx[Hv3{= Mɇ `[{~@^‡ۙM>l>LCV8x0Lu̳*2IvlfnBmn'sS`Aez9geDj[X`6'́'8`sy5t\lon:Z.Awq(׾= �d 6ANc R^l=U L/ek÷Q__& 5+'٢KM 6Woz#@M�;|%b�N'6~ -Z8O7'ܹ�qr3!2S P(PUvdut%.�E 2nK�P g�gBɕWW6Mo�?# {H}iTp
,6Pc}Lj+q@=\\%(9[i'pR mX޲`<?-!,8lV�jû _ ̃!� SQ}<mZ`o!8U{zɝi79˻1/qwYA``5x\u0L9lh[۟M?}/U(ؿ)q0 fŗ\3��Xcc %?"I\&عk__w6W 1n#\"Ш&SK YtA6=,LGkﶯMo*8C eX1$ a\#3,,\B)<[vXK GDU� G)ƴ:;H`׸o[ ]e2b^DuC�9@t tm?9Ok _`aq?!%*Gx)~LegPˇ#-���� .�A@LAfF7м؎} qW^އk0yupۛӍ+/: #cxЍ6l͎FgZKzߥF;f�N@Q`8;'opwGU~6ʁK l@a?vv;@ Uݯ^/b� l]d/D*+3c /x%~;9.sn{,+D|K.佻{;( AYp\˚A?'<{EX.#Ϧ)Q~ /.6UB6q:'QdVQ=Q܏9S~~? qX*"*�u�rU��YU='p.\1Oe$˒'#mmgu0r*Lx_֕-^#jPoyP}\2CC+qe/r U�Hd,&. 2J?ro%/N}t[D;5N�bp9*߱{-~x1Mpg* NyZ n5Ob'bW$A:q[F34F@y 亣ttYoqfqNM) D9q~w^(ʥ;BMn$ %a/SO�, k4zKϟJ�tO|_v3@?!"0U%Y?T|k1Ƒm Gb,jr;̾؆#ƍ2,z!^G㴸hNc[P[+ᄋ'-O?M] tjƑukXoqao2}q&P6k �H%.'eD\.?I~iCMIfj)4#`M0M2~Ħ钟[rG!(B`9xpuWT\'Yf0wAmHkۀ6Kwi|rq:ƩW)NH{.Ym w%ePX]ˋ1.oj~@^el@3}jIT!V=εǷjI&|yf3sp\J/xlNptDcSwKtzAK>|1}ggMܳiw-]쐰kSӱ?%4kK[Q!g <a*a/=Dٻ<0j\LY%poOk^t.}S�t瑉Tٹ% nvR>uGI[۶9Vv$ YA*:Op=FN3f;` 9*ÍA�=zpOqc/3lvI;tG4\fI;qMc+w.K726q.H#B+hGZ2Jxg�.C 3+3cwEM$�#u XKedjgQэ]Ck4}ԏSpcNOx:sllbjr͈VOugןoLЅ֜Www؆o ӖQ^'LA7 =:G5`qT Stǃn phph4ց˷Tz<YE0noxۇ/b֩ m.Bі@NGCp1�ns(J3�.[2B"K[g8g&T9b"YG 0X']x2N?~1B8 3!NSG'(ar_I8ᰝf.aSl@<CFr+4<L̠3}?0qy�&�,.'r�d$^�Ũyy{uKJԘ 0q_U|m ֘qfZ!7cLx˟F%B ,ot؟_|,Y/ E0jDŖIᣵN RyT67hwN g$Ԧ5|H<7}Î6r7a|+|Px+kH&~ oC@<̚WvxUjϧ(ܽvL~Ń-JPod%PZ^#Н,N0܁8�`fZ{;?{G@?m%�8&e'Ocs $a�|9fUtHC}p$wedt<^kӏo}�pfVC;n (gl ܎1ݳ2EeDӜ7q&z'i{[EX@cފ^�\Qmo[>;hwāzs~w^(ʥ;p$Z^:_"rl`.9y}%A&zr=Ob%<– vy< pu ~w]fF?.30,_\[ �9`Cu'v<7@ L7YǬ~)�V79=UwWIZO-co;n਴psŘ~j}p(±x$H|p4:z_ҖS,?ZvjP.VÍ n� 7'+ӻf!k1v0~\O ? ~:tm]t]~sog]N(ٗm_e_r`WЫK'�8 KQC0P֥_xQ Q }`&0Yߗ�U]BUo <bB񄷽Ltlk8m<cG#&.{}-DNBQs[E�`^qWI6+8?" 6 +ZYg%!e)}s`++|�G7]%bf)3kv8-Wj7?F#O#ݱw|pHQ_3l_smKa (FDэGYf,�f^cRx%Ra# 81<ݤܧ_,$?am \wAdWDׅLAA$+h6 gG~Zghx%,eMGae荙4%r& MA ?o1_w? y@ fsg~6B;mKOsKqyem\<l11SD]yLL@HYW4PB E �קOG?+V~ f,e]!F"qd�?;j`�Ke2P?FߟVߘ0OY�WJPVaCl[?GpJ:2FcKG \۟)ʱԛa0OMtk/;0ßcJYK4?M>S@�ClEP+R dBD^xN}/]0h)7wbCJ1MUiAc"#N̙A`~"T379<#t1t3K ԰R]#`7a^/\Fv30YDJc[Ӎ̆a[Yγ60!_ѫəv@'Ϡ*\7 dM=��&@UȱͲ Vp޼ izM~v9�L�p-OsuK��=Px@ ��@�IDATb`3RCA2 R<kKL-,!F!`ߙ֢�sD؉  �Aj��_ز_�= '7a_-~\${78!_sP0= ,|²I?"M<.X=�vh֦϶8B �Ǹ7y6j#a xҿ?lO_\]4%V�Wey.,}ܾ˾!lfg {QyJo_clBN7Yքyp_~7ֳs_'~-0G 38rDF#lDLJѣ>�'T%>H²JwrbvYap FOPx3F!.n,T2)(eێsL,:*jeAwtcʂMfe[@/[h@BKٌM; ^h` ţI-,\<ER,U3V93Г,;h=8bfì6Rڶ,KwI}E3mLp&,L.nnƈp#aF7%/yZ29c+`{i-MTM/uOM[²yQ^Wifގt@57!x݂ LM53TF}T#v{τxtc˃o]f \LӄB6ttO.GX~~&{5%r˘#^ʌmF6.EGc}Yf-,!ٷЏ92VOJnޥζ ,-�B.@yϠCQ; ~}~N+.wJ37*@N7&69/~+Aq|5fcqxDX`DF4]c1Xz,ٱ]V2 R[ ui$`c&R<<O u9Cmw "wWG*_ڒ: \6 e^VGX||YĆ0>kϘ%V~vV@ aܾf-!Fe=m6O@m(&l#I|p@|LnOD߹seL8OMl\q&l1aq&#̬ q8NVͬZ+=bVU~+ 滨E]0m!;Sľ&j ц6 spU;u|&ÈG+_RGB= 2#7`hG>ؠp;~}2I 3;p!Դ#,69UaR6yqD#QKx'Ƽ\6pc$LL!}g]2DtܔCMwy߿ɁYj@[V`$i_Cm JWQ30gDփ.�o'ybxtJCkRzkf)!Nb8* onMw`u IQ(p>ZНIqC[o;QG$` <ZޡMOuי|geX@}%"/){5 0ggf4񨨥y^Jp?�G\N=m?D٬Z]ι*&yͺ&C/=3U^s<lZ_#>4��}rr?Bvn;BZ 芤6˚~ wk0e.mz Oޑr+"Ieq(kح=ޛ[=I}&̟G:3$ΜI>8g <yww?WB yD (T-pיr]=sO |%V�.&gE oJ>َ[ʼ 0)6elǽLl/{`|5$IYEѭ3~''GN:w534B?~({1'=Ԅ;Y~49sU�jke!t @/n&xtEEا!5:׷s`ڠsv E:[\H0,}޶UXlflW Rz|ءQ+< a- gcHqd_|0|�lX_0~u# b"� Ec+�e+?V7>cewޕVvlose &M]} !ϩ2ҭifzMGla 9G;젵i;ǴL똮e.@ �y|~uZJ�Y 98K`}2MlD,v% ,g{M6u �uor,7p5xKF#A6z9kh6?f4^]b/˶nm} [dbbÓԆm#iÁ<ʟ P(Q1W7T /ڏF,YQDܖ8VC#|i|hGA7Qʃa|W`?;w-m# =%TA3v\%@Z/~̌K-2u0E#zT-O>z Ll~?)ߣQt_6b+R;"nwE[P{zGE3kM̜}3r5�F߽~8vM�yr uP g96EeIgkĚ !r3-\/,\Pw2 X ]}TFT,owwmi�̜$PJ W%|%{4uX߬ N0f&#c^b`U eɣ.;g&n8+lF[XGnFڞ!d&]q_V_3�k[ x5ڗjY}g.R�S3~k@7`?>{UziE B?0~Ott1Y͗OiNjťmL`v�5t\QqENnXW- %N8_tCFkhp8 u?�nl9@Czn9oށ !Q,MD8 JڞI<ٟaV�=wiw#>_<=y<w3�.M+}ߴ+(D`_'> @n;ꀝAXw:NfsĻ5f1IU&,8iNS4") R| ,?OB1í噘be?ܚ>{Nߝ',ڸ2;:Qv}Nj/Tϫ3�BWE^.񪳟{ϏDLZï+AB;W^ \~?~tɔ Q~& _<s !3fXqw6purz&l~!z3CȎh!&A;C< 4Yiv5g5Vy^藲ҸqQC�8ri%@*:2 �!lGeAo-"cd3̟. 7lgէ(�w{)�ݎWgc WW}Z+e{9q&DØqXjL6�q*6i/3~hw(Rɲ? s L9}gW͖<֊)D\m3Neطd,1l{: ?Z>mq+ <.(BhpD@a@!8Qxr(#ol5^fk5Jrό] }H|Bxq;;K�8ڼ$dJY_CBk0鍛 6]x !"8a>NFpIuݛÛUbUX,ED-ɦ- 2!+ J@ h {dozatZ%",˖TK-ݤX798q{3o{3Od~7"N"N+R{piIwnK:$h2`Lv`PӯB#(|ↀ+ ʰ=t0Zj߸!]f4R45.ze:fm2?ՌNXuf 1,`O=3׹~ͳ\1Ղ*Lȥ1xEOkXHG D�S<:6kdGmn 6E̔�l;?w뻋oH+Z/Et˛+SW3n]qgVxa�ذǻYl=@GaQ<Ri@B;D7l:,tTٌb4yF^{zӇ.X#Zת@s%k\:Ȟ_⋼fJ% 4!&cfRtug2j.Lt%ҫ €O],|?+ʕWNvn:^t(;meeou4GfencY$<’_~]7?ЏX %FLSvT+-&=�gzwxxe5νws bw4`Z+]ta b;~y쎿^ E\D \<A/[W_@PdBKO:Y2˭#=DG^l;†*ӭ ¡ 1 tχ5f5X!`)s[:lMuz$(H|!t1K)0t ZiYN}ղeɨnh$t΃ #οR!jg48A42Bmv̊j[R#o$o_,�֡<@Qf^ r''x3FU3} qțZu)QygbaF!@"$RD'tHe{wSRI |mIy] _d_1T޵=U6WF?qNM)%h2)lq^ë#0=% tfM\}HЇ岠`DeJyӲ $j?b ۓeN;涪7?Q>: IMw5~vF㼬Y7u9c*?_h|hn aa"]z!^/-wݐ5Vy^7eVٽ2Kd` ~$0̒V/9(NUt.6PeRw0@lXQp9P巻/LLLYqxUHv4 Z2FR4<ow^//]~eUB �G� n- FR=cˀQN8[2xhޕ0!KHUr/'@E2h�+{š>› qzug{ F٬*1Z89 ݊ƛzԆϮaP6-,MfEDRd~t Fw.�es8v-'M,ѩ݈3ƬiKφf[:tZb.4GC: zoy;'C%27l >)?XR �? ; ,ԄW(# ŵqW3 }q"nt#7V58@>z]�\q8,'F?JC23,47h=e:vD`SY+z|>7�vU�a � 3+\C2!'A=z -njS:5ݚwQsSB6uzתj|"(7�Ҹ\|T3Ȼ6tFw AZ:Xka@jO }@ ծ8+* Ҋ|@3t.Äy\~b�0K^Zg `~HtX)v6�^WF[,sAl^6'>-Eذ37vYV4{۲L̀!~HI~yp(b=T"SOWtrFrfvI皠nn^Fg+~Oy/z9$j DcX0�]]^Й㏇>% _ct K^p\]&h1 O$=1 PD @\.*,"=%!}߰{i[j(?}I2/:mf͌)0N̮R/[|`jUaSQ 7g@SCIKE;tU/ٗ�).9} _x' 43TŃ{_z$;o.&1J5Sj ,(>N<긢W%K8B}  Bqň� V"-3�Xӟ^cu%zQHI:FcW^=ZnZnJDξW+4x_@�0'+31�bLm1D%b ee�mV`톍֫Z ݪA67j&H9PC=U@:'`= jjfCR6L6 ϶x̕څAD5s0RȒBWH P\KݝHeOD'UDIgug1sC?&.9� jE 4,r _j&EU5.:Í+ {k�(<'OK @-W�qhr[�'Ȃ+ T2b� gDJoY^o*+y�#y Z(P'JUt($B+ :}zϝרN7` U�>�T@ p8зX`X K42FSR+|ǐ*Z Ti ?K~~{Eib�w_Qo; V՛ivCϯ~¿h訉t_q*E5U dkCmvN@xA4@п$E}Wluͣ =nb�0K!K|Ni԰<9!>2~7i (S ٧?hKCEÊ^n/u;HꯈI Eػb>Ahഘ殞ymB ltS#uXR|Y3{d\vL9ggA$`Y F4l3/_6@A$ŐATI)I3Bׯ"1l톧 Hl,qGH,C P=x[�AjIW-$!Oma ovUVdǬ4wZfjOݩwr'P҂Bm(h~"H`_!@ѫa8WJ| h{-ڧ- Rh�0T.kD]:ߟRf *fPb,8~ig<Tϯ\,Xqn�5O#Uߴ]':<]Ox2CȼY BJf(�sZᩝ ۖ 5HH#tHnaŸ ^y'^0{qrsWï1szC3Onjm yl^z]-ձ)4X]z̠D~H!CQ{/_dv|4Po`U]r!:9 J⢕6[}"w~<)aqTa.C- F`>2(J+?jGM͏~,AM\ x?;5oR17]~s3F$k"}kn:>>$n,S~o )1⧖¦@]3� gՍ6ʘBypoe)4#6A4fGCnk&s^--W'qR<܁xq1쑦tN(+ִ %i,_8Yw'N^`: ~&K2Y:' M d>CuW o_{]ӹ�hUHAaZcT/Y()s"G8e�c SR4!{iyS{ԅ^Pu2لڏ6[ȖۆzHgi\|wؑ+wNpG/"$ma��f}i Ҫd) -A8́zvQCZg[ݚV7UڧE1yeFϊe?q9Tw)Ei.V�f1hOJ5Vnu"Y,Ly$,g3�/?=XEIt8asMQ;v+ ^v޲cޟ=~Sq;A j'foh+|>ʂ`-:*ʔ�ɭ):yaNGH8zFzPM̫aZ>fF:[b }vRuOɲ/(b=U8$]iX6\= iW}pQ!h:#]Bp2p P./)(='Y҅)zrƆ,+kjNJ6.0#:ݛW_:LB8!96z{a+Se<qW5y"poJ0啧6mxZ& ZkS"PoA=sNN15Yg7ej=m^EB%bSK-oIP<C:NY﨑t7չtА UWqp#5t\ʊ &Ngct-m<B_ {m{ʰv?Z*{Ь)s?QX'CF=ΞVŀ|w^#U- d\0ԛaA',SMw,%KSf6Wh` T}.޺k7?dsl+.bmQ �s=[76� %5rnJ]-_isʓtgWg#$M{b?ts:vIx]("[*EI3ޢn`5д9g'K\=S^3%vZz[kV:` t+X +o~^EmԎS 7��%/ւA~ꧯcfVf蚍 DuG~dY-�8qfzWjJZ8aF{"DNcl[Sn,TvtiV%_bN.BJz02��PqF{qnɜFjg0{_MU7XoW9 �w]?*�EX+1RWcKԧ)p-+.bZ΍Na ]8�@9"6]+5m{#'\\D]h+8tU@_U;M9|{v?>%w·ez34Bqף/kUk@e T :WA�obdnwjoU@YkE[]co0r{S\τX)8r�RgYUDzGo2MCR=:$ڠ�!1b=󻢟�`W?\.Pp qF:8Cct*<0#^wH_CJt%+CO0pXjMBJ:'2| |Έ! U.'[pfU*T4 nw]":x-ц`FGSG]nK-[=/ό{>P+�8~wZA@PMtfCnܸw@m9Fm rV@EὯ*yJ"0SѮ6�1/goH*KI+ ;qR �xaT<p <,�5oaKʼ;#tw@,Psd9·ID3Bl):綻?l:�"!)`B@0߃ .(3 LX{uKxFYIDd e,g$$Rf'O$\ОRF{Nܑnٿ0J�@ 0:L]x2]Rѩ+0YQd0ښܺ-mI�>Okg�g%Y`Ze{zMk**wЌ[hk �fOtJ��Dl&Ea+Y{z {z E4{ܨ{P%XmN lsng5J9o#GvoKV<v ew˧oYHqT2$V'tJ'2r~'_Z^M4~4NDx3C뢣"gߓ 5YҮi/::a}{Twg�lȼ^;/>-�tE B8]XBw+0}Gm�P ?"ϏLesD?%y�/e@q\WZ1`d><jhl � {;@u@]>ʠ6~e9:|Tl@,*`pmOl~kwl#6Oc[ݿYmN*b8i0QQ7T#V~# .oܪ[|l+YttlS۴Asz<>Nq0'Pv2zi=$NΩd(^zYt2ߨ8<ЙU}Dϳ#v/07ʍS�~ԄɄsD4J%濼-Yi%=\CB8ɶiG`;TGfN&3 SlQ *PlGK&{b ꣁ�',A?h֏`ъh5@> AsԋH5+%C^j> G?u]NJ'0QF-pK>Y"Ws^єw8 lW=,áے5 XV;>Sq}"Up`kqf݁;` &OXD q塒 by)4ʝn]-IKGڛmĀݻ?ug#(_fDa^Şr"yya|<M9v# Ǝ�!e=Wi'Mr-Koj%c+ڠu0^y a`?A ]1|5ݗԡ| !BWxFb~ѣ+_ѝ!r|y{cҭ-#1D&Ol-(qș[oaf噅: ͺ̸h) A1 ):~#-p:);)S?(Ƀ1~)ױ娕K),Y42>ܢwPxA'\`~Mo1x@9b/a-,@#?xG5 rI h5h5J/ѺP Nf\YUa~?c@f({3q1.O [ō=^%dhh@ �|BY:9#^vÿ`kavCMiND!jWWHK:tX[_]L:YOkvIʞ#tBCo-qi%2ܐ1j{wYqY8W:B|-Po6�h \iX+)&dM@%JCJS<y%Z"vB37"8ZE(ߕ0(]4fx3dBͲ=` x ]t'R!9USJ^L 3z(O 7 ܢm_;!V/>>亶ᖵIFgop}2<t~[�yAZ҃04{:Hc=*_EWTIQav:5=Y۪@txyӋ(d<Xɯ=4Nt@.9U{%"�OpokJVa@U�j {wrP@KgԚ叴*[Z-͏kzp5{bf�BsFbXnlwu-W�Yʤ `_nWDc|h#/[WpU5 ƹdaM%v9Y pn;)m Er8zG\7ϺwO&xZe]fpC!%K-5?tR_[g1QQe8~q{Hř-Y�%Ȏ OAW* (aMg=z-Iy У37I+bt�xNn\IjIwO*:(h<Ԗ:7ݿdI)g0I 1XW̌kKB,X y@a <wձ`ShY7ab1hTs:+H+ |KowӯHgŠUfM`CWoPtJof7N+}rO+;z@Ѐ+QӚ_l>$WqGEOmG{ԫm]H/m׋@ a[wsGoZa>ĥS:~%hD(<b׋߶!ϠNܔ(j) ~ǦtRA;a=з÷LDe=69^Ȏfw㳋RGhXU(?Q>=>9z|V?fg 6N=9$AEWD': u wnk/[�k`a �fň~CA9 #$Jʷ_,1@g:3N|.X tnWBFg/!H Xz[f1{\;I? _ܠJ+ǣ|`5"9S˓<U@>}|v+U!nP }&V[nwP⁡8)-QϢjVo>(OO?ˆ>} !\wu9^l|FG1n+q`I:)*PSSP{5 ;L|�:ga zי= <O&ly}JZ͔l0rl5Lmn>%9q\Q Z`(◝i~~林I"5߾:Rla3b�h C`9>pn~>KYGO@3��̿ rM5#ך 8qJu۽yI#X3gV#}#?�*ŵQ̥6d4C\w\P>(;mJ:mE\w5{VR~:Nhy_ U6ڦu}Xr?E^ pvG4g`C2U\=jn ߁?ufvA{E@+.3 :/hoA� s:p>3$ɟ!ZhMU"y(jAeFŹA寅{VS)bHdd 4b :": <pٴx댶#Cs "W )SN0 "Lnn纝Bv�_&ѩ}'*]-c"fP?HTHzj2SO*pDz+�|"쬼q+ϞUܗFnze cK"{50Zі)UaZ5n1t*ƌ-g>vXъbvI[m8Uy(vP{W#+AM�`%d�,Rgw'3ۏHav2/BhpFK,7>%sF_F0 驍ٝ ( %:H"h>*$M 7[u` f6OwίH:!Y:%=t6>H,+ʼ'/? '#`VcY`@0~ �X__`Y�һSOu_v_w<�VP*=:(P\;ڨ83�ke]`@d?^�܂_0%7ڜ)?R >ՖXQ2(g@6 ׃<?:OK Ym:isv!!kZ_ I_Ask-wW,w[{06!>TJw3y .䭟4pj~w\ �f)@!1QnAg�6(Kљ[:3jD@s{ �$/>=ʶsx+VntAh0 TͨCE䁰{3@aW5dPS- 8TNɘ0IJ8ʥS3e:U�*&~{?9!@XDVRó{VY)6E>�ګ�3J�+L_yPw//0!î d~@\_}&Jm c`w\艹;b i5(86)$qDAM?g=WiBG"`{ s*J.zA6 @27D`@w,i0EEQi ,)";r  X`綺%~tUfF"oJT΂4봟=[DsGYݫR[!?u|gG{ TLx,Hq 9N~|+@!5hOU(ZW]7XW7I a_e/ΏLpfkwLN%aoILV3J- hrY/hPw^"vT',{\anm-CVjgmzvҚV 3I?Ӷѧ⿟/+Էva u�{5C>)#8V 9Qq@?>@:"x WѺi@48ܦVhv]@r4x;zq F\%hr.itIJcgԬ�:Rh2@9hT::\:xq{P@Y9S Z-Vn݁гz:?䚞CZdv}C �^?*ҜtC'O̗l;nZ08;uγ[U[PXBѦVg&~NT@e\>>Ȝ/v+;͍>&USjGo2ӞEoyʥQՕL[ jYw4LCj;3-1Kv+ 1FDFKFdsUd0"b5(8ހ8vCeWK7iA��5DIDATjQjiHdeR玲kYR9B �ˤb0S 0 LTh:gw5͋:g TՔVP1ĥ_K5@AFG FUtS~0,*ZY mgWaAbrƍL[K. f- E䇴cUQl"+91Ϭnuk s7F(Q,rqT_f!6*Φc^tEfwa�``(? e]-ׇ|�^7 i$#3{=$?7wkĩx s{5q� r;Sኯ}[)uOȬa]2H[�чH?L*1 |,b(Ysss�g$?+zx9|�%FϼJf]\ΏJ_p @Xh@00�`F[�0Hc'}L(R%6dG0qyVƕuɯݨ+펟וguSbV6ioEQ\aاN?: : a\7Tnm]Hܟ j\j(݃s } :S w`G&-BOa x/n\v8pbߟߑ}rtH$Qi -hv< s|XEqq`R7[W$gC `qe/{']a|O:_ tۊ6zLU2s0pAz0k _0`r۽Qg19AA3[?궯k�=ekZL"&gŜЏPkTȇi*Ƞ@]t}Z2Y.p 83J_y?PE<86-CرzkqCUz}}AwmmY R=1PJaEvnOJٖD�t0>�p%GSs/Khvұb-/O9�Hǫٿf4~4GחۚX2/K 4ԃ�T3O<@\ @ZodLtq5Dd=U.* wtpEϐ@؞h%;f_fTHa,?D4THTLþ5y1K/f8U.6#(zN4^!`N|x};U-$3EVT25gt 8bWm8ԥzw *7hmܖ@a߅~\ �f)ޒ9u<><^0A;eL+eyE}l{3 iht4HcZ8m:E <D|kH !"lrg75 (BFtPѺ"PKi/n#|g^�x?ЌY�y�Zc,� �?mguO^",~j%玑ƭnݿ솜+"�1Zgp`+p vȼ''Pe\ m\UbiRfW6EV I" 5nM,ZϊD/j ;jaj1fQ?8]Uԉnڦe�rA9ˠX^(S 7�n8=~޿t:/%3󜫲q>}?ʎ:VjEKkŢ\z{ ,:N-"F~ᦾ_}K}ԙ $\QӬ�h%wĈ?�"DBz �[�b0 �" ) 9\0�(ZZDS$ܮ*Zҹg ^0s� @F5CdjWȕBt|뮆Zn*Bݑv�F@�]:Lf0�XY鶖tp[+ RE@ԇ11ƞzn-~qbLgwnkɈ QmQV:DVmmO/:3�Ʋ" \دnhASDgP,t< ܩ'_ݐ#xE<MEWq]ro /i@ߢp rjwQ>vZK+0RGeq�N1r8bF֛\wE!ӑqcPEҡvq& P3m 4`[SK~G[C̝ngEgCq[wK+"&^W|Ƀl (AH]xBjEf `/9* 4m罯Ck:@)VD ; PpeT\-;-T}'Yr#wFӾ.?}u)rVnďv8?n3#�TfnyZ[Fml4?}K͆6ã䆏/<Zvf,@:*t{dGGO9x?y2|tj'@f:wpTwEK90bѾr/{[ҙr�I8#rGJQ #?f8]ͨ< V (䯈Ga�D\Ҩa5M jR !Vw \8"`JȾ^c3?w+uU~xxT}'A?t8<"NzC2~jn5IGKAaS/, GPOhzJjO=>n Aq1ӌ<Vۆ[MmHje;jXZYlBY>j&I%4N&QJJR -Ыe"I z*DT Ǝ?}8ÿ�KzNN{@{eP?J[N$њ@Iå 7&۰?8B!x>)C<WAFޱ^ ҵ=G,!!+ r':o 9�Z'=p<U0� wTՊe~ɾEnZ&Dr΁wr(eo?ŻLQΟӖymNi Ϭ+VsE,*VE"kR0{f=,emw+ϯB/f'T �lx\T>፝ɚ Uggjn]wW7w8&dt( 6GNN'h6h2iە 5�qvqQá74X9PT gt8Ń|f~HĬ1U ffڴ8c+:Ͻ}IAGp!� 6Qvr+7L4�ui|@# @!@@w281 x9FVjO dOrrRtW;c?Z~ti(mUaHoe =bST,av0-YUX>K;n܃sЫp]�ZlS�n]HvZ6^"YACͬ-NhkE۩L3vٙD1saȁ-u,.rv02�3A(bEY(;@yWK]Q+2(WI<Z:uWDqDc?4THC:iH'p[hE'`wf9(~}`פÀuHF@ۍ|9 @ :0MVn5+7�p�dƯJ� 2Z|ӣ*eaVhYVVqmzamE<VzJ7?]U*<8-2̪jE2}{0 wT6v中QzijSXNT[ࠥ/C3Z9oUf~b DBWwt0)Y-e(Kmrtd�i%")4a`'HՏg~zi1g;f'2w9+|C3iZh*+/GUT?uKV@ }+ n|m3X菆`0|uzIHûɪPzաXt*ͫnz/7:j%'7aPN`?5kC?c"x^_zpzb{�s+;^v/MjwZ3T!> ; {RpPڐ=OXec~,l/Ls50Aõ~+Nϟ @WiC_6]4z4d: 3}r0#o Sh8,o-UJSp^[}�*ȴ ingGD"+S ȏErQ<G= 81;?2!tnv"bc #Ӄ+$0|OUnF\"9/FޛnӋ</V*)b�KճO7qޓczE'Aˡi10c6�*�1s("r!XpOf?%zaU(R5^;J!N?8ʍ0,)È"IV;CPTeCW!U2fm@# Oi_e@S/u/gKP ȋȑ*C5 _Ώ,Z}@WupP{[q V!TZ3W*۩F歽BvM;.[u )fUkJ9h3걂F0jO&bf9f寴چii%|ySob( * W#�̺$2r!(HI=�<A�~:8@8w. 3EͺA\(:mFp5Oit8>sDAj'%i("U,1rL\KcUyfq `Y"jj,�a~8�1UI ^9�o*@ Z ']}xYӒ:s !'5p-;LH.*hB�_\_#VaCs{U\5"4 n]ZN�c@g, Wz% '/4Tymvk3D-8^YWCڝ*m^ M0w&DĮTpҢl]j !̜ZZ>rÏ~BwYWr0`t4;,v+Pܱ_0ăACс=rT5>o*:PVJ_ܱ;hĉZE_wR4 V&x(0b8fhh㶘V%%046[OA?qzCli5X\Q 4㡌ţ8L4BVNA3<+u@ U<0gE=I@xbz_Vj҆6պ2FPX"ăY%PfP 둯�&'ŏJm0n<* Xm4ܑzո F|Xa";;FQqso:xt,Nʃ,#S.( Z?&͏ëT^ilF?NB2C],@Y|�Ē=k|yP~/Dt-<aޫJVja%;,aSCb2fՄ /WǃڬWTEUZ]nevo'ѣXwX@ycGI{i-t,CcY}a8qF'v̕&ccXd? EQS,֑P1Ё#ډk4|rs# @ ZI‘5sЎN�A/R,3mŽj8; ϵ=N a#W0,JHbjw$?Q\Ӡ`4>w`hP~W/8F#^GC[lEIRZJtۥ Kiz3}5hn64t6+?om)"N5Z{jp㋥nӦڟ&�6kp KG\ �f EȰ{ mO5pw*=GtNF U9$RՏ.: tLØDFƩ�v#@x+a>nW(F{.0a/d~0fcrYW>ڟ5A4_Wn)ng/ "8(P0(`p�wu@_ӥv'Opa؅!+UWjq]*S]Z�g?S(P|%� fhrgf=c s>s,D\þz!TyY8A@>{\Ot( wP6;̶xA !k? Iĺؙ)Tka 9ak|% (taþz߷@ �1ף[oN'W- լ \z[[76� _"��h0� ҨzU챷m 3po$m~huՑV0ڪFtmTi�t\�R-lkV"zcY[5Ypcz 4aOOH/8q1J S3~P;"k` l$@A@\dƯwnvϼ\m=� н?>>WPYpV9Oؘi TWC\-t{m~9U[XzY?XrF+4o%,K!�ұ-0Qrrc Ʈ }O03>~#dù GNecs]'+/WDV<|`wvg5 螿=u? <g?4ȘcLy (.={j>ՉHkQ>92[=gGu` -s*!E7s1�K :*Pͮ2;'iw:~u�K)t|x3zQ;#= zD hg_Ӓd , }@ RTz*u34h "߷ 7 jWՀr;O `?*l}Z{Tm(LXjʕNـP>?܏>Z@A@qb*c7A@aߚQ3:Tk+=~I?4i5:)}؏Loj=tN!mb�]cw)�hp_3g3-�\I4Q,'Ftw ,I*S'�f"`y E5C}݊>:=u<9j+nqȏ,y oNcb6cf3F_ @g8OK(E!=F {D >A-5bk="rF@dcY={D~T6�` l^@Y^ W$3B~R`<kKʾSCI+;Ωߪ0SasUCLS'N}0c/n?n1r cc3Ʋ`j.�'~Dֿ[3Z[#5@=Ɂ^Á{:U+E3lfܾxO9A@�ܽRWsKߨ=zY{5أٯx24E4J.?2H> s6w.<�\^Z9BhPo0i@%}HO,;sP#쩽k;h㙁03L]sn`y^:g @Ԋ~n|)tymϾbWfe4n^B'=H0H>)d(|P\gvˬ$ߺ{Bw䞁cVكڤB]b0ZѹCxWgKa%Ns_L]w##@kDXmj� ݽ)?�{ P�>_-*(k8(̪\ͳz&*>)!ܵܖ!aKo zf3Y�@4L�iqO_ 4mk /˟">5#D| )Όm�=| g5( `B$-cCfUgO*8TN>X@�3:W5(`�s{p^vo"?$)ڒPW?ߌfq߿١�vVQc80j~wI{`TH6g&_V�<g "Y @0xB7z+2x v)Kz)`]#d%~fsR?faP|@;`@x$%U"p< *⑟$wWNJ$Ɉ`ox fHײ@,k :"~}t.щ=|n}[�E-s~k D0 �0\?98T'<=˒tfVKx�Y?�/koQu �  rAACAݹ@ >�4ܸ#قbġ[Mmㄙܵ?1�0*pRZ< ߅~χzESt8-D!(=ۭCn0aSupOkyڀO7‘ yYslP5?Œ C`D`!V'ߥ/{b޿Q%}/į`N 26_pZ T d J9F`�zn`Ϭ%![�`,;p޴:a\-Wmf @:am%F<E�8j 1b&;^D~JN np/lXͲIK! /Z<&2|Y><gĜ7�KO_G?FW7 %v׮i~|�Aq�{(_ό3?#�;-Yd�lmvw㳋q7F"0'�dI1ǀxo:m8:I�{`M{6C灡9;JOD $1s �ja KJG�oPr<`gϠ!:U�}1 u aSm1j6:m>ÌVNT@GY9*\ �fY ʩ3,{}TN@ Vb߳3Am ϾmI_tK?ǀ$`}=p:pLu0`s$'ZgJCxZC�X:u!AEE<y^֗wq~p&�r_> WOuX䯻s+fq߫:e~ rx�@uǜ?A`lͨ,\�̂@ڐ,U"p"�Kp�z[�5E-C…8簞7ܹVDL�yM Mn�`R%'.~0S?(HP3y# ۫t•2J@�,OӞYf1#PNݛap̸,3/CY`{^y t|@lhkMOВ,78$ !1{Sgt@iJ qfgٿf � `rG@O`Pv% sm,?+^;2t )MNy`5@N͌ȥダ^/ox r.�VntmY?<:0CvO0zR%'yӢȷ�flgsۤqGά x@zuVx쟝yt6ڗ:mZ҃n?c%͉FlԶRVs쉄~h˓u.ro;޽B�gAspGꟂ<[ ^^BD @{ >Qtg�fYZYV>J\3D#`>̼&7`N ٌF%b/叁@[p7''5}Lkg�f�+A@Dd#Lݛ?M �\a>`-ケF_K=hj.�Rȹs%K( (pEJD hC) <(4+.� ƏK+loD<JN$UϷ-{{Rns1�>G}{3tJN�}Lq{h"ыbjP 3AZD�<n\xW}{O%czLg'{͏P=nn~Kϩ !'+%�>MZ׾[VX ~vq$1x$TN qyzz�'iB~X#h4CxH=8@4|ȷ�ڞOOt.\9W70L\"0s6e0{m"$' im??ݻ}�떠4f²ލ @"8,o!4"iO__7#<V؇8*e˗/7otZ!H<nO/BҥK>*rO>/pbyyDA`{8;}ASO=oyA�ޛ8 /v! U"<1;ɾCIN6>6 X̓�!Oկ~ݮmbCZD,CFD`\k=;� yZW3wT+WtoFҲ6//v?|ov'j& @"$93<3Q^nٟYOO8ekkL B=sݯzd:C0vnw ?Ҟ$@"<)`\q~ꧺSNI??8&�ϷOL.HD x{wiّ.�#:ӧӞ$@", ^;>ӹܭ�BgΜ~!$(U"$@"(JdCo]σПph}n�AW Ha޾_~$@"prvo޼9@�[gϞ|�JD HNu}Ν{X<LXEP,\zuyLD HxP3s af*HD X<VWWw%xgksssu9ND HA@_b΃0@"$@"Xbf?s$@"$0z&HD H\>s,B:HD HfE@ PҊ=k$@"$�W�to}x1ND HYwS 51K$@"$x?'疧3�\+HD HD _�m/ @"$@"H <�=zD HD 8nlbW~WB SOD HcGG?c92SOD HE`W~ F}?{Hs"$@",<fL�@=}oI# @"$@"W8: 5m짂z"$@",:߿4[oo D HD F?}�x|AmIKD HE@?8� _5 Oe͕PLz"$@"0?k1z,s�@wy//+'U"$@" b^3֡g7=o FN=HD H$?Ӊ~3z| &|QCJ<@"$@"*I7ou/i&D HD#/?ђ3k4� F&[x D HD ?$Ќ9d 0//}U/Eu=_iiHD HG�RzEb}>@?"׵*U󔞳zR%@"$#zVϷ|&@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$Ry<[����IENDB`ic09�ډPNG  ��� IHDR���������x���sRGB���@�IDATx[tٕu"ݪ}Ue.\]nLq Z43-$P<0 !@^ yôQiKW23"2䊓kgk{Y~&]"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"6V<la'æjoqbV bHkhc.Stt"X*E:,u hk :AG=yDqWg6~Df iqiM +}:+ƴDpesÃc~1!1]g8"=.5&Ez :RQ3klnEVnnUW^g]b^Bi|d7eunbxMiq?Ei=Vn8F4'o&2َ鶰)w hE[*Hrcΐ#yy-ѽļPg"M\b\O)7)u8nV9ԊRNQ&OKbH+>gMkh b8ҳvYqsh[S%*\;#KBpJaח(㻖y(M_1>c*=EM3M{,n8F4'o&2َpx,m >޸9ưeN_=E_%$)L)yJce:")X(%p}ƼH9ulNW}Z Mk[HOQS'3ư!gzcY:j6iK(QaY@nGy} ozV3hu^ qT l^9lW2m(`,ZbFg̋丱zNM\ܬ)rƎq&mtK $Ñ7͊3/G+:.1/TH)Sʍ{Jp2"-e G?3 Yr,Z!9ưoVܜyy=Zqy 7VϘoA&|i3Vw2 ƍ嘊D HD@M ~+] m�ƿ}UEWB4/4,HD`;l~}z{4DrG+/Wg"μD HmMS|J! �Vhοin^T.5T3D H[~wy"! Ng/BG"$@"|n4E�o5ET&HD HupsjFM39C1<Q4n@g'�t-u]XHSFw9\aO# }aQVtl K"NQSuz r7oVMKt71rcOǖFw\(K/57vohrc>mܼ:kEZG5ƈN1):"}b^Ez6%HϊSn Yq͙ףo )4zcxX=tLcs^^z-1Ye".i$3Vr^FS{9tFt-Q5pi 1lgu,alnħErcWGѭ{ͳ_lv<r+mw^<'2' L7؄ OZ<#T/t=CnG7CyYXSQ2-@ O~Z\wwvrVUK(i$8Vr^F}9tFGL+ӄ6iKXL54Ei\3L~ȟʵ-DCg1cN1,oĹ6�F LwՑ#*s:F<Db8Ydu%XϘA[VK(Y=DI{7 =orctGX\L?Ei2離17M"rA# "mtKԴ1icx=Cn{hܴrT~Ji4zzF}'KYAsf�@�Fu3_w]3W$8>\%&%=Byv;V( }BgguGCb] EI'Df3<\ #c1Xi4z\+3MOSiPYr!ΒGEȟ&.Y)evYyO[VKtpe]R_rnq>aݺ[bd|̫|\T;Ed~v,WTii94V%U@ڈ=+.!7Cn#M@褙|ɏճwRybHqcgYMyzN,@qYe q:A qmtKTE1 :jeA"y2F}2;=r-x�6A|Y~S+8GU50!&*w Cv󭙝k^2ll \wL{;uc |[5-1Aȟ#Ki4EgX|uNmq"3StXy$|w)y`IbHGi$b8薨YtÕm^FOUa;C[yaqR^Q.?$73ʕ|?_6} 9xR&h0]矧<c(^d _^!@.߼T: yty=Tby3jK(s˫4 4z\apgubEzB^pǰ"m–\b\r!c؊""ݕWˊ"n�4�hQ8D<v>ά ?"bϔg, &Kw#c8sFMzoVܴf}!u/4苲g)"׊D.?Src:>e^ޒFGL-+w?ʊn-Qc8ҳϒ qǰ qGܴo["u2Mn\ wclcI6�o�9&RgSۦ$3$3Eͫ?T6YKc8ҡxFvEtpS4A% t˚% +G]L/X=;qSr]thdCX8Wk~Hs,"=K_7.,9+HtX=c\*#c\H.{,M&H[pQ\5>#Mt7*uゎce<KnZ\wD,]Y׿$\�C=98!٩д$&6+rNGU{G<Ju6a3q(޲uB߱sEuTe 4}27VϮ\ OEL31oVb\-c+FwuDb\gʵDĸH[.ҳttα2M&m3EWH?=t3UeG::)ߘ.cp>Yvp ??n4s*w|ŦvӻqyR@.:/HD XWG>n}Pmg?ٷYXo}[z]_QᾸD HD Ӄ}ss^|35�o%JNSAΤ@"$5Aߒ^z>mOeeV-N8%@"$E5-�?;7od>֧?)3 O4<h=z6{{{g|D HDNsƍ֭[͝;w#qj+<}_P+]uy?Ќd"ND HS"Qwkܻwyꩧ>?�АW%7я$$@"4h<۷<H)׍Ol�|7d'%lfh~*p"$@"\ wm>OTAqFԶ13�wRz-LF"$@"p0"s5?<[=wxggtV!W??4<|+D HD d-Ei:WMLl�|{IJ~5:'WWDKD HVv|o>M5*ny5�4CH?05C]2$@"(oy/Ux I s{6D HF@yR~i0'�ꫯh$Şo~] '@"$ /| ;L<#`l@O$@"$�rNT࿎5iG�4\s_z(%$@")%#(a"HU�V?H$@"?[E-?Y^{A_fC~%@"$AChZ)k�uzOnt@"$C>5k߿ aia_3]"$@"\-z_S KD H@] 3:^_>}ZD HD"n_ЂϾ9uY"$@"`p6�Y�8L$@"$W�zu3]"$@"PIuf@"$@"p`_}KD HFnoD Hv_@WYD HD �l4%@"$@"pMKD HD >gMD H�D HD >?�Κ&@"$-:6ăc[orœX/+$5C`cc}vs֭gm>4zʣg�k|͕2 $@"p}Й:Vy:_ך{W<+ J~V-@wַ/)Z[' $@"0 ^| _hկ6[)�ZQۿt@"$"7>h~yJUe�I C]k ߿ϛ0G@eJ#vp╾r�=m0{n?::/R:f+-wW_}ݍQI'Wƕ^khi^~?`q//_VW) >azt"p#Xt teV>YD$F7_7nIν-28^>>>VR2ܟ.J`'BqOy0xi eM*;ݸ '늀0988KW$M0O�?]"pUdwޯxcÏ>x9]e豏XD"`aT`VD^k`4kI$k$v{j;n~,JTMuBF-X_Jo'twȤL"XC7 wWxx||rYyB mٽ1nOGv q`[w�i~zwfb^ \LzL"ƾeG93^as FHgFFS3~tmT-C ~ڭ W"1eN. 4>}߶1L `1p� {c`(7>lTQW�(E\z ъ0_+~aXˢUup̹Ox5C7_j*Ux[x \t![vу{oM-{ 7�h ~onyC /)w|ƷWsӏD\_,ve-\e14s9CM!ct"m:amI+�0Ց':u| DH.Wt}[݇SL]_mid11t5]: ϥͫKOP޼h6;Wy|x&S ҫbxQߌduS�f"I:8 n 8̨˼_j2z~z@6@gq|Q\ϙa.@ˍ~@~S<Pd1p^0X!"]"k|\5K> @WͧżA{~3ꊂg_4L�i-E_խrJ<Lxr@ >(hxE1Rr>jWD`U(7�|,^ʟ'nHb0fݰ6 DPh _ ?*[FHF)8J%=7V/W4`rCG4"`WT'o̼$@;u6[5�6~hRrk{^>r7@@PD=/sqe\Egߌvmߐhh�i }*[8yMVY[�'6�TT9#=7$x\n=G+~ix <{niQ>_| =7҄.b, M4 T z6�O@p aǕPz\%\6i{4s{<iKf�PIOGyzp;>ߍ+0 i(b\ga$TߡVj%Sm|d01` ͻKN\u*kĝ^n�.X080vѥ_M2>ޔے2F�m-vT6 ;/yCG]zGm_<o ah.<F<li¸6?qP^KFpm\nk@3|Q]Zʍ7Fz!ϖeՁ:!)c"/5.yF-s4|$& �zC %|3P`_u3hJÀqYK`*J΀�ik�*Z ͅhs!EMD-~16#( Z�2l a8rh} ӿSQO5(i5 o:K>5/rxbOxYuQf LCM}_1on5VCXq/A|!@HAJI*%DKVO.*ٯ8ޔH.j}hT$=~ ~+Ah�|J/7O?̏˟l!AEh}DA9v,=Ezg{浃ᆍPj²Ǣ:P^DgBDvR NOWct}gj@p6zo;#~nɯ ƀhr7ٞ:lDsۛj k## @FhQ(hQv֪<~ED8@~wոbp1t$Tac_8"fO]ad=o[9&JLnRi4#RQv&@Ӈ{&>Ĵ3е<}PpQSe#6V^C@PwR!wV'CPq`"pquzg d16=}LpP {[*7;shk%uEM|L:Pj>n>:65 ?_h;4 Pv4|Q/Dwi,86G>qGui/<7=ǵ8q^!@#M\$�͝S 14lhZ�#UL&l-'xxIy5 ~ ƾl , �PZh~= &҄%-U �۴nn�=Y�0aBѧJ|PDi�~_E4�nI-j:$/ veCy7 P[U}m`A=T&aR%�1ä F_.p ܙs"'A@7n$!eߟ{m-ǿtDհϨ% oޮ;ގ[R] gi k)W9Z&T]I+L okogd_ a$�ޞ ;gT}?~ 5X]�h A+~1V?V>=r[Oq7uP?!i^adIg֛ܬ* wwDC;Ǥ< /3:#6oKGVoi$68[_Wqys W+' d U,%ݥsMQ5:{u{~ a|1|>;9nʿxFF_Fg=)k]6'Y;,"Zumj7[J$RZPNj!B.^ZAJ0*/"`7ac)\?'*~e(òhe[hV{#bg ad_%L|hI4:y!N|<qaHQݙR2zRvLTm`i!J$s #�s{'5E8c 3\7& J_)Yh[P[zRO(<a\X<Wӗ9^ɯeg&W4w)}~iA0@éoC  Vb^3^ B`׬K.)O'kJH YiyX];nXa_zwZz1m% =qtm-??҃~B1d^x3CEg1LmKNI֡G#@(-puC5��U2= _*@捎|^F�c.\xoe4ok' E$8%#Fj*jgۇmAg#5P; Q]IK¹k;ҵƲ*aC40Q@$24=r0BX,#ݑG[qNWVz!MMn = 7ngy3/e0!417Zƿ,t@^KZoJhne?<C�Ćj, Œ�_h>"B3<n+�7ޛ.8ػ qe:>|?=~sS^؏e2t]Fj`owd`@�jJfO 0*(��RK@ 6>" vDB>]7vk�8`c#T%@5]2A2cC3O?bȸhڕ%S_ ~~yB b*VƵ"ev$1UK_Z,F^+c1175U##$˨L�S`Oe' g�N*'D<-.\poתrԙ$X7Zg2篰y/=}F�/##CvKam񞒢/� Ph0d̈"7෍c "Nyune V8 >:8 ~ `'�~O-i  NeT�.�(}F�۴nn%�> ,"`^,^l`Q5۪F8$bED6GֳF8刃HWW<hM1>x0ZfOq8Pgj@+c�kV^ sH:X-wXk#:8'MQhe u�40Om tȦ/J,+Q%*pp6AN)lՇ魎ׅ5�arK%\^DCx_-m&˨pHkҢ-U<'04n̘2D=(�yѝ!Y^ܯCnGͶ}p c$ч|ZaTT8Ӆj6K\B8Fm|LzС^g�_UwML>NWx�Pk: z9 PJ"ΗegsS� ,2$rC|XT"0fde;MQKO~X@� +AVt vQ*'<Cxr[+"zyW/32B>VĎ 氤=5�zCaîRe9 v8=,dJ >ƧK"pn>mnxWgMϪI$KC+ta|?<m_<r?fi! Pf4taWp5ʃWaezY0;&nHڰۡ@سcOW/; Vh-%煀E˃ 12 1T2p`0,fӪøGF?A@[ 8p_ؕѿӛnwG?|:6t6}m_#m^J_3E(e!]>N_V.�,Zf'JR>X�.|~/#E~m|(c_|m[~B+v[G?60R㼨GP6R;my(rumC2IgOohW%38y�W˙�4Jc :6L/.GP5�BA@jK;f>_6?*[j[Jp MuKe`BO4F]Gmj/e𲵼RXURڂ ?)߼�P�N䀠5vfS>lZ@XĈ �.6*d%"9 0I.yޝp kx¢LE�ۅǰSа~_2ZîQ�}5ĻOH˧Q1)Cww,\\>4Hⱞw` m,WVrY/bķ,zǣ2/NPøA`x%l3sK?8_V/Zõk� MD`*M5$4͗"zQgYȴm5 >rk6$^uTМYk9EBHAPD/Et oe42Z[FLOD10 o <jسxel�{Ux.|[\2Pt@"eC&Hf!Aq)!l}PY:eM aɀuz@|xaajE!!O*Iz%*biĨ`kuZ X+AS+0PnT͢L{ C(|dWt*"k�귲Љ6~UҳL�r\ܚò(eÒ4}Dͦ洟ܗ k0*/rDd%r6tDx#P^n|_](Lp`3 ֢H�b_[iqyI�;5Xvfw+dMk7p8~'w&D6 cS Q�q=Um]Hk�t7@\  44>zK{ Pvث�J^ P = ]]<D``=֤zt+yM)7�(01!6/<p?�n?7k^ L:c'9Mcr)@NRsĀbU'U$Fu H.pyO�ld?�e [7~F ]tbCK�O xyUJXtHf<ϊDO*!\{ #W|q`!5䗓ml�QH ׀HC.qƼX}T(+k-ʼnGYda<T0B|,gCГAa{.@ub^D^F9b;;#NΈ@4 cH٢3G}>o�>w:ޠ9m40VĦ8Q(ezXa<%?W"xA~kiŰzS/O2&zPL|?jp�F`Jv.tG']"Tt{?zTl�I+]"\D?=J዇ѧ?vҟiߧ)TtOK4 *bnj3_ug:N1XHWQs0n~#f-@c@!@E7S7@?fErK�i5�xj{.X"+~5SƜ}e@G}osW#�/o 'ݛ !T>FxumsX^~U?Q4{ȱ >P{%D@ķq%.]"Tt�!>'ney.SFҗߨOq CgQC4~>GL@L4UL,c`Ս P/װ09�(P|rc|xxv(œ P)`G6yyM.Uw+pᯃ'ID`I%"]Ǩ~s6x H!0zC5#F33݊y),!w8nugIdeݱ2zQ)ō1&Vi�?M.Bh- 1gDO} %#A(sDX"%gW/}`ъ9]"pVN8m˒C%\5x#5[h/𶖣62'DGy-Op<Dr|i8<R|[�t:02^!Chؾ\,^ʻ Wݟ%'!mO?IxWȐp wW ,κ#PMFk| cա7EcS PxӐ'6!m8bW #D^]_ +waY,hR6?4 {v&A7E w^?=,%D�4s{<iKf%�T4!Ƌ@hD3oCˢm7eW@=Ga w�4k铂y[FRd],izx"x} Swcijm"6qwiK" vZyЂF� =+>IFSIƍ>x`kˇ~o�yrڟ�`?�K'Ok?  LH7Ү٭K' ".Ψl_{ls�8)O_ Bŀ�pa^!XȮ{l S|.8#~4~ۯ^a?ƞ}ǂ?V_NAY%P0R3턭AKY2D=ȵp^ZNTJ-<iXJHZK q`5 PL<@AP*;:X#a[TuKDQ#tY8̃N"s!= LA�o� 0Oa}�cC74CF5d?q|igk%C?sѬ'dt&ŕΪcb.mCVEFwhْ!Cy@#�j0(l�s^zGZzl<n{7Ȭ�zYϴ�Ɔֆacz|k�F�?-En)~;ͽM5 $}1\Ͱ)1ѣ LDըlR)cS[/�zI~xԁ|מ芹߾JҚ1Oc'YY\|<qȔJ9!EN(-TDgJ?1Â)ػY~(!gxON>u^VGD^#u29.r-& >[[zLA@xC|7Lw"Yn%yyL\0'iudD@F� #@ȤwψK>jaGtz"ݮA\<Qiy8DJz^VwUL1D4ep>.Hk-ͻ#D@@+>-z(+GH);a4t5E`%�ޱKAkd10;!H'�a4mgړс@͈ckFkKa/eh5A�ܪZ8VgEc$EN!c_ 0l5,iC)+ "[ݹӝz@Iw':kJ4�{-:s}D,<e)`yˇб=aXC~xϮ?;*�uVu_ɴ@Ub<4iXv 8s5a`j1.� Xҗ@{y-NEPk"ePhE!E�u.X֦(!taVDz -b+_Mv5 m:W o |ޛc nGB:hF\n�L<Ȍҕ�xt01SbQ{PTqM)&M\PZdHC8 ܂E碧> 0 m�¶OL^NjiY� ߓϖAbLNhtw]"'YpӔXHxC6}|3`}7�}!A N9t w};OƦqkIO5 76nR[_h;GflJZư?[j |?l~l6G�hPbƕdUڪ% 7+K\>S @Br,| `fHF#}}vR }!4`60 D`]s]@O]tb`wp~O{g_~;27d-%wxe{<U0(t\dYa<,u~FnbKd +=D~�Іu;z_{jЊ 'WA +2]"0vG0Y3�d53`qn_@BU?��@�IDAT3?n?ۊ}Sql�M$wC"ɈiZ^`Ujۥ2X+6wg#聭P;@]{*G0?SQ1 d9%8%vg/v5p )CG�&Cs9ES#`?Q=yC4�0e� @c�JsK#8#Fj[tk(,Yw?H-$Yv[<PIUl ^8L=d7;�hhgto ߯фul̓HsG`ݥ7�F[݅n5-\LpCfK]}kQef[_9t?4YNrs12K2 [yrl{4[Ѭ0xbB 0rq>Xߢ�Yjl}KBoWCh�<vl . X[OЬBŷk84P5kNo2B:*xSPI<#?-nO N 'FՌ' '[C9P ́L�tX!H@94?)]"0/0΋5�Tr!`]̟E$W%�Fϰ|Y?n,a[{#1(koE澮| @L]km)::6A7�+Ա rF2v @��|�k(cm<(tiNewdo9p:vesa ¬ GG32�j�W_rg\ 'Os"_<.e'syz5QјG@ D_m_a}�e#M\D`6GOqYk�7c?/]0fddo4s+�oj{QldΡz/뗳VWQ W\4vd�(C.wV]1yuA5梌" V ~�?>#5vPs�$;hʢr0Pi 4d]Jbh%D`26Z7~ �%'#c14ge40H mC5i?s_rTǮ7j341UyQrTX\ߕ bo,F1.ܩ O<.8e<3Ki o^m5]]i1j1:@MP 965DOLA`5�́<:#;]"p2n*0d=k_Y[ח?V?)[{^5>ЫY �UI+]X"9g=?2_Zs "VxB_Uc<◱=4Y X�<O0 588*>HD8çЇJ^ 5�i.�̃$v2 k]i~6 A;Gd�PyQPoSbDIv ;d)--dWvѯ�u&e~Wvb1_>QxJOZ(~ނdZaxqg|o�lz ᲩF��m6}ͥrw?]"p"]"p=p�= h�;PƟ:y4p8`*C/dj`tp˄^SSUg,>^F'=*#u7U7>mOR�� 4=N>6>MhȾ;?پk))!#luL\n �Ouoy]nU'ֈXz0:<%QVBPܞMZ VrC>=-)/2�t+ 4.]fMGiOuJJՅ=oikiyUip΢]%d_B0,ڗm_z+5^y?jY~(aز.ѭ 1"J#нqcW2 �qRlԖIB)0 3o4{l+{?acB_ pyG>bPr(wb9rxdb"]/э0yw}Qǡ;IkIȟ0cOpWv=5 ̀ZQ<%v(-TG &HBD`:s;t�hO?f~GEҧ@mlMG:q #3}�Fù5<�+JBEA7yDu]YLEgO �=P-ob38WU�uMr; }N2.݁z{PԑE4CW>�su-s{|(1y bBxβÀ|TyF:FfW-r4$FuH]/ט(<⢜U2"9Ok"=#M릉.8Ҡ ]i) W@XWN�$$C5Ƞ=/'w:sS�qHd6/u)smSa}b?n~Vs/g�p϶ok:AP^/X r^.ꏴ{8wx/wϡ}{ xaF)ZaQ 36DXn$`OD@Ù" C^Ko�xA{F@D`n̗׿ cm_vjߺO~ri)'ʍQ-740�ej-0$"2GOsUUA|m屐wF)/$%MU"ѕW=HcΉa혏E!�&=װlF1 d٭1 Cϔ@P F ꔀ4p-t2K"jzzڭ9\X/#{v܆cļW\&V@_ �z?{fΰyJ>:3Pa!!IY7Q)A+s>ix<=^R]mCt,@E0q827ˏJdRRzC VqKs:_PJt BMHáF�0 @o哯EIDA@'�:=%2#-BOP>0yl4@OMu8 ևFͽ-H1A3@zUW܀x|ey̸G9Le�jR5 C@ ipEŤHC:]uQC$&V1d!L:;�ZkFe6p ~h;X]P ^'KuDQ tC`%�m9] $xp\iY6k�a4�520=PE>3d">l]'R<)|t Oef"� #<C+QH ۑ|psc,~ aT݊)E$!Q_"uy]\2|%|gwþFXYRtn4 ɀ HT4" J2hX%{ 96cR"P{:MIXᰟrG #?3�2-!<=yX e Yʘpa)y1TZdU^D*SĽ=h�C^3# @Mn1:j9$jtsQ%14DZf s]hwNn|B}w@ ]aJQC%>JS}J<YPt@_E9Nr|R~133^b@4,Lvï.aMƀ1,ޒ7˃RUy <E:CIeHR*BM}aؖ.ӌ4NA╹ PQIW5?(?!eEt v `![>=>~_k!<h! '㿧;cO9$q7�hOe@T"]"P6-3kER-Wv%F� PRGrIm뉀?)v޻|!o[ g�Oo9s|{:cpȈXc~/e~>\pZ8̜tE*Vn,"rs?*GbV- 1Gc^)C?:F@y2 `yװ<sp(ҍy0wJ4�$wyzcW Ɓ~Nӣ/1.� { Q:c EAY,t|`by{HrJᘖp<h�c Vµ uFGt Lmi<o 6%uy`1 xcCV}^1[Z;b�;;Gk|e g=~=_~m9Q7d$nJ>Oo5o9ȞYbk*iviǀ`;[9 Mg02s[(o 4<^ˮj70D]5TМʆ\ɾЧLK:V̱@9Aڣv>L0 RL�sA02�ƶ.īW]gto?zv\ENM},Y#3^><Veib0v; o*MxA;hHFqH0'kzgx}<۰Fl Ol* 6 mX4-(DTXVnDB^X#)}^3ewd9!pWl2HkC�Cm|^o.�ik�*Z ͉WsL8]aV_Oj|sЍmSp?>Oj579z3JcR w">ºXX$1GpYZsCP62rͨvY vBbV6R=j]+o|1++s|wZ^#znh7ͻF�ұ@5Z&>pM�+c]g?w ~k7phF>\3*� � ob|lcԼ4pǝdq{|['#,pU%yZyURDջUoM pʝ`Ep<9RYX*uySTX"]$ZZ2-nA&6ʝc:#58Qm+P_$ D?C~G澔T5* �Y@?{qX! ;FOw [<v17V෰CCP Q{,B v[QBݑMU0C)c߼=ش 2id�66zA+mj<\}elw.8JCuea}廓)Z|={A vK9؀d%X?n �[�p,|=hڈ =Ź[x/'xȑC5z >TOQ*I Є3²pK9m,B#)G93Mݍ}/PeSכ^UHHYbPC#Xrm\9/<BZe2xyM&w T�𣑾P[�P"}THh)3_EWy"-酜)x#�̃,2r069b~G=~-C1#>˾|}3ИѠy7l2[OI͛>ʜDy8ƨ عo_o>PÙ /&4d^7{ZQ&%Ed:<:%ꝖMB^&czw4l5hCڲZ`@ }7� O']"�ئy"n}g簅+у/){Go ЫŰ1P?%P 74DA4gF6`BpZ$n^:mekV [Tgk$Izo?Ыt(뚃R bii@wNiាAr* v80aco<@@4HnSh1z"t-yZ%֮*e|n-ۗos*z5['ne7@㰘nh  Mzo{9n zHL85z8/i`i[=n CQȨ::62B>A0ù,4|0 4*6i� 0GK`U<]' ͶQJXdHdckٺ]kUcOol߲W?/5_I, yt-?D@8Ev'+G6MO1o*]P}y?v�CnHO0�Ax|j{ UW|c^˹NġyM\t5I+N^ݭцRCƀJLtd(Lq~8yX@S'\7Bp9�;z̃NJv|_fC2^ދehwciЫ <=2#Y;͋$܌W̍?1:N;fJRcQEǑyƨa=/ _oMxȨ7հa1E~>-QMo5vhd9&u Zpj(ADL.w?(^?͇Ң-5 R7 v`!I€VqE%Uئusk7@[Pvw9.a_̣-~e$(? N{NΓ޷hSٓ;CvDq y.;dD|n\7e6|3L`9Cy@DO; P xD�4?ygrז@Á0-G  QSEgz/qV׊uW,9*<z>?jn6۲gӗ{p@� pϑG4Dkߠk5�,s\H橮�=x>ذhF͚�Fl|}QnkD�h E1(`qQ4tQi`WiJ}<8iװkGȐ6c!A]$Ǒ5/HМ״oimܴGx#yu#B5:e2S.cr(yY+_/#F7]FSkzF{bC��$= u~v~ rK"D`eҝfHt <y0\lu+́/z_<On!P^=̀Iz/ބ <-Lv&X| z#9MS /GXyjOU=]|oo۶�>V(mn`#"ah$i uqPΟKK2`A$>|}\E;蒠<ALW2Iidtq]E||,8"ƞŒǰo;j@[ 1KXލ'_j.Z:`l~uNuGV+ i: ՛r  ~ <#>EOpټnj꿧vоқřSZ 5d6gZ$kޞ=/Hyz0d(S2}bޚ`/P^ y뜋�E*ȱrs�.n+O3_G".2`5^}_lW_gb@ �Z^GPiNEBL"J8NpU&%8KvY:=k[(_U,hCTd.Tye2sFL~c7޼Q^Dc=,.ﲀ,ʗr}X~ߑg_gwH*T~!N FTP a}&}|@Z!#G@#ES~Ӌ 8 pϞ";el94�dۭ'7m 6/^{+G2pj�|_ݾ%C{pt-=uNè17W ~4>= z=mcO%9i2BA:|_s"{40T ?�O4�p"*6\i(mǹs4%k�p9<rg -pq̹Mއ9�;=k lCimNpGtLG|t1]Ϣc ch`�v5Mp>wy ƟrM1dɧ4h$F�['y-apNY@)>uB;ksٳ ;V#?𸫆ҷZ,)dAm0m¡@ !ER &@_ZU�,2MtZ=;.5+&F[G mm7tMO4O lW[j1'cKkMcCԩ-HBzW`f[sMy�Ɛ GzXFۊe<vH<|Qj!Emb=sY|Ӡ,^1|LO1oh~0C]m с2*P>𽣔q+^ r |==<]'xgVj5�t'`mZ4C-' _cnjhޓG͋7 և84 ~y+_Dd;=+_Osml674?dFTBЋVJQhTٔ*M̋'%Z\L: -f=/S4 }wwG]-*~}M�չ'v�>!@nvo>�HB%y-6)�A ȤY7Fk|>2(z^3o ,lp6F,jSC@ۏm6:$mPpmBߍ ̥8-Gl]تzMw{ˍe8nÐ5!`g !@#-g=eBOƑٖAP8mTGGDɮ1n:&ָ+,c)'<Le{7wwMaCo 7;S(8#g #/Hw[?-fNwKo�!P_lk q!lskd%%@B{@ 5zxxDcyr.G6/Ra<]AA؅FL.VaF66/�4lRg}h@2]Pv077'iay pҋ(&<IzԳWߍ|!TK!O WlJ`nihp2~K~ˀN8k'ɢV;@}C{|={2H�(/2&A@;Q6w7Os-b@ÈY/ϞbT)Y%/k\Ą!γN# U氵{ro>P%XFS)+94 5{bS!}6H1VL9Z&еCЍAzu$SV\}Mƹ,ߟѤ2|rְ2d0ԋǷ:T Ӆ2-#z `7bUl[#�>$,Yiy ܬ2flhSZaa׊ځ,؆> }YH xn>EU'f4.m1yq0 7Ѐh#6o?bKU}:.�GGC~LK^ tP(/yF-OmXOȐ]F+z!xtHɎkT#dr'?T'zzf:PjG0& i5N@^,خyv 7(VHeG_?E[WgѺh T)�3'>k~vpj~5u᙮)pgy|? ɺ~WGc?,_Fh##dml c$bNP1w[OhҖe-EMp|~Ӽ-;J`*b˹x=ғJ 2o=VCj['ŽFNT_,K_Oh_h*-Yszu(7<i5�(`\tWhGg?h1b<و�Ƌ?YV#f*{"_ڮIzE>=χtS~*MǏ|W>⍀b_XC }x0i{ R,:Mq{eç4u(c <ҍè8.;H!khLyrgAhٵJ}�F<L _5�Mps\Ϋd�31N8߰!*YUcKoK;¾!u[SZ%!qKsOf3,#o3vrU|v?&aw<#fww#mwfr 48۶BRFXA ?%,Ԣ8l^h 8O+rwy:aS6mKA mVFm^bbaxO( P]p<�cQ`dEeJ‘FFEqĵ`^ WB.ƾXdN3�6vt0y+=UC|(C4gJ#ήP8a1R2?E^?wg3-`z;>ᘯx]Ans򢥮,B|=ӡ:ZF!\HkyyX>[>?o~tj6֮c2Lϔ�˧P`=~9 ʻ'4rSG~QsWlLr[UkbeLfϱߍ}Rz5\!56_{ѼW)scXU4lj )ڦXNJ&d"0{jqػyEf%�TM,KNwZcQ.=zvR ד]^Pnp� Gq^=[/ۈ)˻( mK#(Խ9K c!!e2L<h1; )z˴5dMm@6cAe_ S[jH/XQv#>u'4.g.XH4\bjH=sD8x C5񕐭X|F-}-'֮`�f.�kfxh?3ۉum4@ô3ڦ$|KF3~R#u*IkjsŠ[\`-g]i㥫5.@~*3FFU<uRk~$#esR04d7$r!k3Nݱfb:Ըkuy~_Sӓd�M攆W>2Q[9..oߋҷyQni=-b^ygy ,"R\!-L^Ȍ~5ܫVq t*!pk�V ,j CӝfA]`$j_OrƇ<6s׌�C)I!t9:@.8@A:o{5O 42Q|1i-gK>GmCJX P b.ɇcSvSnЛ!<e`F $O* TUd\WŽg\Zy'\6LE}w8ʝ{ӺW3X mg|Tp(*&d貪YL)�M`9`V75I+#X8<eӣJZݍϹ�Om [eK Ķ�F":U4B =]A6O~'Kr)e1jQy!Wmj @eg;,gVdJU* %,ْku^//K/lY-[5ɜb~>qfDfdF."l�>d9�ۺGFu�taT<+ߔMэ6%t7pg X |&Čm184LˢmGwoϬl'( mW3Q-4Ȕ> YZY[tyQwe?#s v[�G\q::pansz=!we]C)6&@Mشs#�nrzڛ^YGߴ@o=kafCIyZ | Y'q C3O_?Z>;?vQ2rr@�revUD#Jr]o_C1xB^f1 ^Mw'B)όфAX8FGIOM=@1Iiho8 6+عQo`Ӡm{rÂ""m4e7�}t̵�v77_/ 8}4풿,h��TS�l~ƕ<0_]+}rg0C~? ~5ngcW#55ƍ2K \[*Ec! 7VY2"5ffFWXXL1`=>&D&H_ۡÂ+,yuv~ӼG"}Rl巹�p~))q0$|gqe+205{pBLqVqHuOMV*Yyw#@~v׿Y0ReNQ$7t'?{ 064Hk|3VGHT]_aE q*nمv,\Ƒ>xҟRm&ֻt�0LgnM(`اW tf갲qΌ1^w ȌN/aL2s^> Cg8.3t/i~}FA¼F߁| '@w){] ,µ+L{jvpg%jw۾W_ À* jBA;j@�+|ɞ? ?,yݲZP1[د@0|[@/:l6ۊc/{6ݬ lNH3zhW=?1,hp ChT L}+`Є]YאkWks&�86@? �ڍ5[=I;pn p1ݍ5zq8P+h!XݯU*,uDgDə~q:X5K/Zݒ,Pfk<џYЇd[Z!\- �6@h|Z/-.EͲe&m5uSh<m_%o9T ^[W?%ZF3&p=p*YR)ʕT ـ|/�vK@USZ{%:i<׆lO_7s�~HQu_uy5]L)�=bL^[E 6yn^c5?q8%n5ى8ra~c1֞2OӉJfW߈e*<CwպNk&5 :KBAc- :~ UDr?4n(BKK˴CT$`񰞠IЅ]OJ]}2o*-$yNFb̏0^Н ]  su@-_z] :7_K i{5IZT0 suܯ, \;YY 8etr@߲ʀlq뽔=Q/),t<<^BˆdF&gZ2;L xRӰzL ښFqB/| [[3 h:E,Wf,G �&I$̴&ݞԕH7m_ٗ@]bF$W%RE_nrֈ``F枿m)py~H]CϏs̗@'2+$2'tz? @2~,Gt˒B@rYP{:m+TxY&|#)$#l_&pd]5?zƃj8 fz&J>$n�; 4(j-VienÐҕoc̫I!NH? 3l˞4/D.AM9 ˸Iߦ/}91ж-MBģyˣ`Ăi.s3^4+��99y [^nq$#-G�^3FR@s+F]pHa^eֶO1omFc~X40v!D.� əiiT`@p2NO $LRy]aٗqGK{/Y-|T2NNHб:@˸_iu9)L`uS}ĨzZF�8 HJYzu&-oh,F f_ hfyx%,s:޷<뒦e_GbBeΞu-|`GZBpogwK$Sg6Dw [.?c}|ˤNx* +]vLs�>0]8.LJ@�ݷU �|:SH\I{%|Kvg[U { ۸-so~`a4UsaE36SO7OWqxgv:+ 26_z@TCi`W A/Hiޘ~\�8EGts~w|_$Ε�.S]x?+ss)0˭-EÔ=?q;;)umO{ }%k o<5]4^Vq.b3E,Lg5a2zMw2/?ڢȀtݏ1wݳw/= ??S?a2m`'~"=6xϠ=6pFnZ/Lz?I_P{u:v ~*Z>4_U,$ nV�-rW< 8i9T 8gv<y@S"H10„-Lnҥ ֌WX02m#-v`ѲJ#ˋӌl3+ |\0L,'կ�;>VOJ۳ZKA+Z_diP#͵җB#\*ڭ�,ess)pj[2K5}O|47}~xcaX8�.?0^g 2V)g^1LÝ?<nsLhM��@�IDATOSR4Lg{< #r Zc}a_isk , [i4W o:0JYC>-d)˟ӈ]fF!)9E258kF4f�z p; zUWd6_<Szt*q+eD9u!M(KmƟ~j}ʧ׹,܂|sZvF9Vf#)EFfI_h9 QHgӿ䳻˫+wy8t3>3QVd0gg&]V <nxhMc~SSQdm,ų�a1 G~Qi.#)"qΉd{]|{P5 #We4<Ui6vE � _ d*drD sWl#2ikۖ�:rv7]+"iW+!�\r$Q|rDW5G�`4l3Hd^sKy.ٿWu_Hڠ ¨poe;}}mHU9kXy-r*Cp :Dt-6* NA7g |4.dfc-r2xVem<+}ʼR dl?Q6vFAcCh325Aw Oi@: FȔÛox@/'p>6ɪ OIw;_4w ?%%t\3�\3z͋%Q~*ڝ]9�~YBPE?s89p{uИadPϠ <hP08q%~ϣbNq$?�O7aDe}0tI-yY?-@`j[ypZL a ))#,_!Dm;qk+/<q$OD[ӭqUp;HPmYE")yYM[?ڷA1Ocg X Suu<46&0<7& ]ϛ~P ym, `iآ�6WXzvsg:Nuy3Xg@k2 VQ{Z]1Hz?_,ǰJ'@gYJN>9 o{J#ӑAS>?Ts’ hulKeɩ9 ״Vާ&9 PYH#PF -Π_'ɴէꙪN[`bP0A55L_4-!7[-Uqcwnj)·�X#c5`濝  Fq56$$Ӝö[`|Ξp;b ZatCك]Ոe'¦˭}#JS_aJ$I>:{{y){:{nߔŸzr> `bǩUih ޝ(dm2z6վT*2<DpF#`<Xњ3 ^t+\$ LOG=N;1)RbVl=}m{aFH$M$V<!.a$I;pᚲo.(Ubp rQ`8۹hy+L8Mk3,a:N$�!mqpy]~Yd_nj-X 6 {ewY~4eˤ!_?Z`?vҼ)ɩ#W�h[ fRF3bZ"O3ns W72vp[i =A) on[_S[߳[Xk6ܰ~H->ʄEi(hvjf)*iWlχ]̧='麙~UůyI ׍V*莟 F _ \=^�_wQLgWX<+9g R#?>އfisSI巙 F5%,3 ?nMdS]"`\HNg !|h]}^q4-Yi"XS_#Mc#W y lvjvkv7 x}LWA"޶Y"Aw4c5Oe$D2~&o�`.}z෸W�vXgs>~g2a5OTUj{xjg x4LWfNdڍ|gsaՕjɵO;6jW6YW=�Q 45K  >+�Cfvֆ(a`*F6|4v׃M:WkieuX`Mqn%㡳H&a2a=p&̾/- � ʑpP HXi*M< 7\3{10陌y\yɻko a|>{`**Q� A\ʁ@嬨 Pս-;[6jLl*F16I4읳RcZߜ뎸NwZ <Si  Z=˲�>}>~Umۉgw>ԅ(h\m<@ zFݪbD"\ ̈技;K5fd71Y'5?j& إh#%ymh7a:Lށ4;\eGDċ\3M22EMW^XWp,>y:,,-�4P! b ,>NF=X2ä@򘰶.БHgq; dܼX[Z*ZnڰBMC.F<BJ Bg\q/},J#e5jC)څKPqqv,ǩ8"+vjWށVJrWثH` +'|Q@+ ʀ�lE}JonSZgnM\3�J/ep\DhuGư)i (a  Pr--_ jml͔q-6i3YJs^g^ ƴ4|h2bY>�lwnsLw;$<b/5迗Č%in +DxPXz[ u7'-OU0a2/sۡ.?N?bÔ/e"t{522LUnl+W6Nx6 %BeN?qN1u퐊v~Ҹ:c;d �bط�lKAlf87דu7v_n+q `пF � n cD�Mg,? 0P&c5@ãL =$7}]M {.C<~?>k~<2W٨3(&j%)Y[4љH 2|U?q%BY{V'ly> un7puEE2IC1V\t$6.%I3}ξgǖ3̦CGV9}ݠhۚe{캧'e;JJ�nb.jR sshvTU+1sPʢ'Tx&LJl|S~0 &0J_&ʒa2sv[|}pu%{\c]m*۵2G!@MD,0FL31  36e٧Жa2<GٮMtWd\vyZ'>B@c&|iфY q>Xq 1IVirir*|$/h߳Ug#.'&@l#d4I2''F9+�‘hxt#) (gcmwUf#W#fs1F cg"LG3Ɵe&3/cfG<g ar,+x4]@ `SC!QЕGG}M1!&RgfRBy6Aht?ʶpCD:+v($(�l>f?l7z  �|�DehBΡK}$h/NVi6M`+P{b <z\d>F_<Dxۧ 9M$lcVs Pyau >J[ӭ晿>W eDkyCLNjЍK&N>$Cr)lf3~czho+g{4lf/xV>g*+G?o}sޙX&_a%w;tHPL3ϗ\w(֒a7l`jdIaMm8˵ڐ6QxMeniO.6W,,s΂fOCh3|xxV�L5ܸӶqlvk#r�@F5L{nMў𦋘)`}D)ε[8B @էt/wxR?W7[!p~O +/q${ww?$BU�|0|ƚSۙ<qYLtVܙH~#N`@(·_z գ~f0NP+EA h@<ڪlh~xfv  o=R9VMa"<HGiL45b+JQPG͞u@箫F_J�f� ud�n$-Y~w1�uYdg0"3d/'YQ*}ȚW24wvx"+<o_U$.9dOE^1.�{26x>�0j S99;_▱pE �`u3BǮU�a Z[l[z`G\*hl79ӆh6ci^|益;m{c%d<7L`fڷw8`ga?^MKi75GwC B$5}üA`ss=(ߟXw̵�Q?7ׂ5~Hd]%^uaU,#P&~?}eoxgCAЙ /.NNO)g>5t|F׫u`G&[2Жs�2|>F+GZ\DP+�,S`IX[_o ^vvܳ̅63C_b^YeX*Ʀ`6M o}:[�p ~h~.X0mCm~|c_$ K>uNL,ރmvtآ6l ()((x `eUm /AssM(p-�hڎKd7r^6aG1҅e2vϿaa H2 foF\}8�qG %X\W36,lc;WŴ,q!?\Q(^2 d kd2nbޤl X@L^foe>Bv // /~?/Ãt8`SF/oAЉ1#0ˍ�AW,Y oL[. -Cepg=\k{i8ҧ$\ѭCFmKӦW:܊|/Sf.ؿZ=9JDVchOOm*4xS@a@bI" 뫤(ozg*_!W"K}6/y˥@Qc kr�ȶGqp$7?Wk*f {k+mN8Ԡ|0)ɸnLcvZTZד%|یq{\&N"ì}lg0xLrelM X[[x˷n(_7=V�vwwGp�#y-#`w.!!e-CcrO>h]<ME*yc<v8ؕ6 y4&fW o٧�*܆>:XzsδXWeXnknBBVg:)L6r\Yc:͜_ }/t@Є� y{6Ko4 (J,ER= =6Oˮ53UtI4!A]Ͳ_L<c1V6G!�f� *�n2L VxeX[]nܾ3|wox՗ a<Ǹ1mp -=FV)LgK?Ο!s$Z3)pSѴTXЏ1yvVޣ +o];*:S]/4}^\nhu͜ϙ #:kbRdgզ LXopL\^^aY+{l DD︙AX\ ZU0 kDҒ[]ጧpg^+=pxM=dqŢR�$}{[qsyyQ+ @.C/R߾ykBT*[�cm{0y$7^Զ]dKVf^ vq:[[KlH3Ǵ,0@tIWOrp`j/ԶmoG?qKĕ Z'\P-ۂ:a@H^)8*en]U T]Q+!�\dʞCHN EiL7u8?C\>S0?^ƽQտG DSG4-ߎƕl " !3ǧdC=oCEw䇁T>�=jG:X )t^Ot )[*vs[XV�X ~<<ka/Aߛ|ѯ@}y=@ An ؈9H"]SVJ ?*iS3 ۔fF\t R/ᚊ|'ҝxKY1+iFq>z|6�wYOor3tMPC]Àf#Lӭ晿ap~+�\1K.ϻ|Q)wy١;�x ]TDD�',l/<g(8It4�p?Q s`m\!t.WdB5 �v>h_lܸ5ƛ_WYOAw0<~poG㇬_&?œڠ �K;m8~6=�ll_o|{7sY~uȔS/'UiƂh D�?Z6�J`e+^�o�a wA sn4Z7]\3�WbRDc 2գ@Lߖ 6Kdlљ!e�f[ ӛLfKww&z<<Wn$3' p(|cYz3{P,oD?p]j(UyqabM|ڟ8rg`Gy"�߿xr"4lFFݾ3#v%z=+MGٮ�6?)8o6+@ vvG[k EG4Κ)Luk*ڳf…EPQmרF!6[[^MMmW�6dk$KJqjʞu'ppN192K"\cZY8Γ=' `s29YVk 䳿߮2}`Гc`#\:⎧=pnTMm;ʓD�FU̘W #S;kR(�HDY;m+�2{Oշy턿+F=桾7w~cN[J?6_ͰϊZa@Mve�l�s%xnÕW�װM;7@M/2<~pxxc Ve?Uп`Wۜ8+i w`x +H=3;֎:iWۖOVd+hkWl[H ` l(@97W)/^/*n W֚IySK"#v0gQpV2~{ K+�&Č=-gNDvF[͹i[p-�ZcoVy:sfsuxpuXX[F{~Qp>w=1FX?Wᷥxzedj1_[k'_}?wW(=CyK*R]#>agwkvxv>p :8#�A= �l_5S@˽};7߾'VzV]'``ENj m1.`#>ӈS[{V+YFyo~<%־n|+�@  AOpX0EsW&vg�21�դ@W;Pʸm5W">Ì&|NFqZNWoU*hսlcx24G,cZx4UH(<c!ci~̀1*Nf8 �.s�3eh)/_WX_߭;}gx̴uri`?bU. M�C4g-VBh[ vh&{#S(gbql_{CTy-s錧ފw*s*4 34N `DF?Ro*&-%ȱk@P6Lӭ晿M5=wYϊV�RQUy#&/L| MpE�-q H%!( �-)|u)faa*oY2XW }򕸀 :q(I8Y[F?LS3~g/'e¢ m4 {0kՕa?�wp !)0!?/:2w-~U l?Z [ĭ""+hYCgc-fJ݁YǨbݥhbig@IvBs)X`Kn"%%FfƤ8uPؕǘ_"Z{܂{=L|}JGC[j{[|r_vn"/텗f^Klqpaz b\~Y') ՛6t-NkMO3FЯpltx=B,?ZͲA?DR3A@QH��4! z=V8Vp׆֙bYbpvF~1 @gs e,Y\bZԡשp܃B9U00Zر wcb"zp?۠Cn'W)lS얏 Ӿ;] k("Mhuhog˿ۡoR*Hu׵|=G \uMڐ4ʁ2/0SdnH?K ë8>6Mx[X+Jr Wu{n!Ȍ7p}tG+q*;z TmUxrfffέɧ-yr^o;lr{YnYV2 @Cn lmL4Fy$OYNYeNش&oeDw!+?Bhqؾ`n2Q,8;#y5Mz rx:�~sD] 7J>v 3JOu(jzzy,CrX,^yWK>Vfl@:j[�^;v߰1Kɋpqfm&ȉ~{sF|ⴘś:t?et*Y W%_{�߆os`L?;p{�ɕCGMK-ewz*05C0||m{,CXiζx<7{E} }V@?HrP%@9eݧ̊s`>B_~npӯ BֶUVm5UiMSH{ttwcs+GC{;gK{ C5U替lC{͋/|!Dy\|nAWw=a/C�v1ZN{Ыbp{^ ~b@{Yx?~ơQ3s}(;aذR9O_Z9!“pzl> ˡzXת|9\ 5@~ @؄yڲ�9>7n6ɧC{z`4Ҟ1)gxV埀^!2ޣ|Lsv=HU_P2,Pw=qt < DxQE@y g �W‘.? 'nfvb<&3HgƭočCScֳih~ea;.? ~6+gj@=$͒9:C~@mpp/m" ܠfrݏL_Ǹ=xDQ`*`5I<됾a}c<�: 8-YnqW+,X=;HPwWbXנMG 0vNOLj7H)3uln( f>ׯU�=畍ב/w~eʣAٜ?g*_g7ϒw{ߡU֙fLb}f�{&x=_m*�ä ҿQC|QBס?y/9k9oG8&,4ƴPp[ß<|9 V/w]6ʁN)PzpXr6 ?ٿ7> aTQnЙ7S9qf31/ʞv W>>?^؎>�0(,*@nYa/Xϗ ?pb/0)ա@%�X29;6~= aF0  f퍅߼q6`8O4ko6A(GF2|zd6Hp�>u>aK0~- x/o8V<=R E:`؛ƍᥗ_~_?p\RݓpgY/|'|#`kL3agmh bѠ(,�r=*RC'7${w % A- ȖJgA&# { Dhz"ۼ@epmʛOYz !ߦ�U�w<Vn(*@F Ω\ ;ˤ^d\ 8:Hj_Wgǐ  LT�| ? ztOsm$s{OW9'GkrY *a_$n^s5aFͯ+aT-n޼1o}(yyXzi$ynd\ُ3Ɉ,cizE6/@wσ !6�{:KC=n#ՃyF\V\< Ы(m_.N+zY!PZ!HZ*i&Oi#>c鞛E*jw%Wԟ\ L[B$h'ӱ蒮)o we6e\GPh.;މt`zk\tOuk8Z6[8[\cy8Iq�> �?tj�;RD(�w@Am4-߲xX`o3|[X>Й6YxJB7ާpO8`eewh/OA{mv D u<mvhB4 >fwV @tu3F2mPuN�sTu+� Ӎ<30wn Ǭ8?G{%< >yT$ MAo30UO"_s A>2)9(Pcp Ôs�,23=khO{_F60~ pK.ƴc{&^#ۘ^#w٫:X> R?tg״< I/Gn`0hTƣU7o [+It"Ɉ=C{qvl[;)n"7W,Z(峌L0L:ҠcH]>0P+ ߫ڣ3m4xǑӞE804]/ۧjiWOb�8m;1\ߎ] 9;vg�7U/\9/J&?TߑQP8ƨ 1_NsaoH_y=I: 3 1 7ş(q^ϷH 7�xv.W�YzT x -̲4Q%"Bz"VzPX- .xu{*;4F/s k9&tXOu`ڍa ʚ;Eഫ�FSݪU? q&,ͤۛ{9;0ԴL Pj&,I9MoSxD$8Ah}_]5aҊßQd[KJӠP{<*u%�.'rc͋aHK3\Ÿ_>ĠL?̌#!cbN~PFF|k>5aq@Q<=]5mzoG 5~oEː``׳.}~ߖ؁{/s=/ߒ=DgY~6<˙pmiL(zÀ۴zF7ˑ G~F2Zv1{Bp"GTU5C?΃#0w<#zR,{Gw5Fk6�rF$Ī.Ѐ^yUJfS:zk/+>%h_l7A:D�A'jD<u5�U2(e}(WB�L 94p=}\L`[F(#ϲ&vb{%Ph{*ܓhOj0/qn9fhcܧF˟:57}xO;=p9v9AG?*2�syΰh߮Co`,&h3+e-czCf ?ɏB01K! @|`y�+ čݖ]f*f9/zEOU>K7pX3(/m~3|{�g Q T2z)TO`s@Vfk'�H` ^F[yq8f@M iy۬>>aHv+fNU@5LZ9%3ChxO;E#OU>x,;\ɷp-QV k6#8vMX�7[|[| BIY6I8Ac0E2=\=�{gGA <-x4,2& I~12izC-mWQ*,vg|j)|¦d  72x$*wkOT5ħpFsW@dq%�xf e'7/墉t C-�Lm<؄fvoF ෸{2 4,4]?啸"O奝xYJVG?yWvn|{ :;椿ek|_wU>�˯>z�n TAuT! =[ɩƤ;{?~';fA.o}>@)Aox& xJC�*7AJ@ۛßvD0>45-ae&yOTQ4v6/. A8M/+EZ(|"&Lfrt�W.bo_FlC@sV� Tf=s(P]~3tiN2"ߢ~*u|D7` ߿ݘ53>GD6\{.I4CgᨸPWW~yj;`#wY=b[H?q>Kbbxx �Zgٿp?`~w&Z;wow7^;SN"f*>g-o?\7ݿ5m [k29Uexs Gnh)�8B9w P DV>F}o؍˟bJO?N9oYL$݋LcғN>:_1yhvY:n{�?]D XWreăNG*RWUNWOyu3N�E׍_f@>l ?u;su&\]_)eGS:~^E{Y hJ|}+t�4_qβW=O$/lq'9@{lҟazLgLEEA�0?+�0U.!0_]]f%,�Qwn SeqפFc KxTqi%~O?lfi^e6APeGhͽq@yD!K[�߻p7@Q$N\8exC#1M.Oճw, >qI^U݅ < fĂ'`0<{)9lk.N\RY9.MDyx ǵ=\m.~BoJ@#g/kX˼ FOIpcy2=2#,G� 3{Z;Lc)W7q8zn̲.hsx�p {ɯ!xopmw^ Qڢ*mYt)cTӤNI`pmoN^h$O2A yZڳ8ؽ@.c[gi#-BiCjBCi)M] ׄ{f85׬130^ӈEᡯqi ^ qmFv6&<ٷHmQ[u| _pX{".vF ǞG)P(=fu Lγ׭<וV`մ9nҚqtLP $@LT$AÈfD-R5߂y��@�IDATf)Ǐ9wfuқ057н0™9o8F1RdU�{Y8V7^e9eC)n@ֱ@8ΩGclcxow?pXAx1fQP �R zmH##H;i"05N_KZ}m̦gP:ˌmK rMU|i;A]]}t4o;W_A;B=H%(00o~K<nM4͕@/!˴T}v4~}9qi|28g`Tr qe`q||5fDƲ662+xx@*ᚠ@oVe'htﲯ|�Qf݅1G0 ~BE#b#%>:5(Z:nl`SHxMm OO357U{4/5\,e`v�v#�8aY,0+6<5 07Q)zg˳&:"LqS6M`s_ϢodoS}Q})A&>^\DE!9hjDoHJxr9C")�7J)`jr=9/v||B _&s:7/vx6 dG<*|ѽ(=fNv80OwsV@aBSn1Q83i1MOoq3(5?skk@ &p=`܍XV߿%?�9 !�|ThgO ;Ccƭy~A:gUi+St: /4LF:4(-�oț�*s:_l7:؝݃-!%O>Eɍ�_fw�7e*yq:/f񜕮i $)Spr2`qD~V銑L?8#|n^M\ D.B<-3ӱ77_y) uw)ɉoefy^zr gӴʷn::3ۍ�fhcvruw]@QYf~.B@Y�fb?_C@^\V�ټJ/}Wڒ1O ʩgxd.F/~:lsiOfϧmh83}?UjM9+{Bn|tE�P3`KO$ǘD~fQEdvx�ϊt1'ҘB�WcSw7"r#"WJ�'k$㙛d5^vfcm+@_L3�{د W<޺0` 9RYў64irOmqTJH ]gKeWb,[`5�$$rp O`?ߊ EBp <λë*vhnɿtOY~Wn'Q ; *ahP�8 wT|%WIgX_YQ\!˴Sq*rUvjOqLgqΊ79Vq&߄8~ |1+�w!V�r(S� ]__% UY3�4`nR x*C~9ۓJuk V&Ko߾6 pO�FȄ_G3?J<1_g�b@w9w`Az/<ڒ",JNxdזٯg/^0p{c2ij$5K W0X?'_c%@h[l0�XfBn0}3u`*a =lJ.V} N9 >IFسlW0`j~= -II/b0�Wr{61V(<(p|1E@ @QvG櫥@.^.2f9;ks?R:6}^RP[p 0A@0¦v!H9PN`;f;FhEvU5gif~L2SK ഥaf0|²�Яe?ws;j̳|kί^?!U|2DXXL!29�):ra]V'V (ZDXYFCJWvE]4 ,O�Yvs3�|ȳ�0 aۏV;+Hث�h~ZI}tZ*D` 2if_' jQF:q8|$̍e(R }g�OȕWL@ N�D ( onI 7Z`Y^_Ĝtm_owllܥƿBJmngoxOY`Vp@ΰOݳ8_*rϯ _y:?dW;TpK%yRAK5w%b+4�.}VpKEX[ۈ Maw2B*ݙu3KV`2M[<a4h�u>'V;v'Y_ǧ6DdEC=VM1tc 4$-.7n=3$RR;8S I|xDFk,@񆃷-rg57D\'pn< B~kN.8$WE)yKy1͜&CWz-J�:�NA&99r !aߔ{$;鬩]1JYu?C˵$n㬿2f+�Eȶ� ~�nzK7(4 `E顓tʛ&MᖙM딥mY2ղ[3ٰѱ15 9n(]*޲?Ҽ*u]6( :${;ZOi a8Y7oUv@fpo椠gSxg�>=qD`-Ѿ8al+60\�qx˷ ^kb2[myLc`_@Gۈ@#<}ΉoXc텪yǏWOvʵ5 dVlxNu-fF2~36Fg5�k\u1f hlۏUtyFM +.a8DKb4>y2W~J[o22S>cSAEf u+X+JNF*(Lrb!'aV,cFDn+p `MWYHΉep6rރ߂_qq)fHXzR;<Qy6ʒJ&uE(0?9"P<D4zORUm;fvO�9yK/|&Z;s;=eOiP/a5НJ<f�;r܎2.>5_w\Pfʺځ{~Lg{_OdVg'anC:P:"C�nAx ݃9Zktn$ӁI33hmC\E$)Sn-��x-:DiW}T`ҠH9 �("NFAcw>1̃Xtipkc'T:D!ZAgJ|v.qvs\*/hMIEWxXr !#M҆�]li{"̭IC+u%g�>=+<sQ -«ZFFN;-*Q.K wDž U_-܉,ة[~+i7e6lOƫfxr m .jq4'_s߻9ȡBnzu<~�[�ۻ;Ý^և_mb9?G1(ë宰ܱyC\wݏە~[�{|_<DB@�ar8#[g.U[f^/$9(xJXPu6L ""V{袭(1 +M�mk6iOڧm<O &C{_D <s WB�Dy3s8@㘿VQ0s(]S%�i؏{�y?=L%p6q*h֓/<y9˒|Ϻ06]L ЮXɕ?B}==E-= zXQvɪ]SV4{ {Z{9!O?uh+7@0?C fz! N�uXԶݶFa~ծ $wKwooCm5[עʹNq.L8LpՔOIՙI?BIΒЯOm:VjHfsǗFdlԬj}iXD c#WC_\򤯷%]͡%imgk+`{ܯm?s<xgiu2S(&`'xU<*]g:>uO>e3;Z^BiO>ӯl)8�lymwWi_@f=֭8w%�{ccmqۿw߼8` ֋|Fa|J_�#vS hgpXn|6*SutMQ t 5-Ab~ j+�S޺}8b %h,o<Sۘa.c*4{T㖑?  9o*Ud?)�B�nQ57ϟ$B%:w<�\vI~ln?ZvpnbS/4~7_ar[d2Ml`f#tf2Md[wXֆOֆ59k>Xd+�w�``u߫o@ W鏶>L{}kwcssqp+Úwũu(̱kq4CSit\}jјƴxv{w'?(B+(iJɊ�[A�`G uB蓠_mqM$KᄐKCl>$>>#,hkp&̈EO - *"ʁO%aFQmmфj7Ksⶄs<)p3�~~0qG*e~\I0(PZc$m`=m1(G�g&{Q[7o Mgrs�<dcgw76띍{*<�NI,LNWy;i`^B6?9wlcܑ̈́W2~4 o<77^}sx?[| ׶m+M`-L =c_a2MU:*=ƥgϷt3 [f[a9ʀhuwan,pg Gk 0%22a~}L5n\OxgIaa'ٯJcYȊOt>pt0|J�~XP_tRn(JT~67*-g(`V\; ?FkVЗEew߱\  Y_gW-|bp@)`@r-fLSy <M0qGKA?4}۱5?eQn{RxMn} �YXFOkzkPQ�N;Ul +]20ݱ; gÎ(g۔_v?`O?O"0p/H^R(rIa+'}yZM0ˏiWѨX/P9#ZEV�8ֱ�ȑ@o[y BF+Vr;He[#3'n/ONjs\) vg�ygik{(6} A '_2-j;7XvAx7? F`9+"i' 1{F,3#C4 ǀiuH9ǀp Bj@ hR0XkoojC'()Sb~ZΦ$=M/?td>kXx' K,. 8X_-}o+09Z w'<C@Ҕ)u]ƲVk|[TE߸' '?q{o姏 ɜq"/A&t ]1W-2R+d2n:N_z�:/'Ex!eTϾ}~aF8G {i}neZUrU~dX\O`|63I+~E˝lz8 KY|̳4}j?&;ܹGǥFmߺ+JrfԶLVa�~7<>gL�Kb #0�t7V1v1pZWՔpntzÜܘ{ׇ)kz´A몟tZ )�&PXr=q9IrW_&n/ `rc,δ/Yi&g=:]yM'HyޢhFT΀ /[?|BlcV"J%-q73!>!:5?/ Rh1׊Bmӷ!!t9P|+;۴2f?3>=fw,/`?\ bHIq {RpӰrDa^"voi<0H�3\pv0vw[/}VSYhu҇]p5�Zq {`imX>1(=K!YXMV_Ig_n7 A.nSc`�yav3J8൸T !m_?~ 6i11tР%]ffփGiacz߀M1,p^yzX䰤�P4q#T2rUlܹa"  �n@D͗GWχ � Q?yp`ऍV0}jtV܏Sy7|�t2&YFF&#WjPO8 _CI- ֖m�a(iqk {v_ϲ\sey-94n-?e^lL<z$z|L")fR0ƕj+7_ 凟w�7Ə�~  2`R b9n1g5~_]pJ]:9&BDwFOZ Κ1ho1F�lG85Ty&"=?cg-pե@gҚV[! `u6 m۝/UMͼ3�2K"Q쌁sR`ln9pevV6##Clgg*:f`==ޱ Ib[Mڃ/$0e*lSx AzG.`{E/ o0Y6hΪ$G�΄8X W`]Dφ>pc2:aMS�J"ei!2my=GA�nWTyxkGMmԱis P!@$R �( B}0`J]`{NN'IJ(^cc&&fwc6vb";3EQĻ8y>YؤA[UYwVYW%rLl3j0a2}Vi6]ǻnwjcM#-`pJvmQ�Сۧݰ+0^s xuS_UgIcMJ4 H|4($Eng JZ_goL?Fmʁ*7mFӌ*7DrdzfFJ#F|nt~51 l-{T2S0�@VƜV�@{OG:�P.<\sblz ��k_F [?c[ ?F{4DW(`AL_$<_>ޛ~{*vm 0;n (h re% Re54z\iV[W#>7>EC~i'6Y~4k?,vZ$3eepm t_&㍱@ڎ!(t*26k[gW?fom\6s�OEs-|G{HT4mA=%[`@�8޻}8wo1% y ±8O{$L|:32OG36|T_nNwv='! AS,g3eOw?^C]٫* q-_߸=O?sՏߘno/OP|((VKV l0ۣDG7pm ag%x1f?"!\c|ɇ'Q$gJ1ApQa�]n !RI@(b)lD/6W'Ͷfhnyc?onԍJ).̀}SOnj+P=a-0�!QF}8h%l~bW?$ںl �6+MbP$F*k6ص lG}J-�/_ߛA “<FgZ 22vol{e4g`x1{gv.lC}'}aGNaej5?ﳎҟuZ6Yڂo]937?]�(:݌K6�θOF;nA=�Me:.#?LO+ ,rڇ;~A!"/g^7(G|$*5+0`4Yiq+4nqF~k7Y`{j5Ա`f _O;H~\zȸ;鸕Ώ;@?ۨ(+aBm <WMͼE�& ՗cDs_3{ ++:ζ!2%W \lNᆭqS.]gff5#3{9ckU 康:A9KvLL&wso_war%g%˕�ձfAVVy\`~6@ P^8^VRx fFSHthڶqџpLDWϼYa\O<`;MpZe+h[EJpc+$d1K:"m|�_[)Ȑp<aɜzÀ;b1m}#ѯIrd6"4|v0y~k| Jѡݳ~A�߬5ʶ pe^.ŚC/ķ˗>ɏ똡20`X*�Yn \c9G7r@$N`&D)~tx 艰NpbOy:_(ˎ@]f}:K,B]W�7`3\"MjA@",",D� qJXlNp ҿ?q ;Y 6M|Jی3m%lMH!BNx]w®CƱ-QOi诡v"L@h/ F!PR%NG8g`z+q}cW?6h>mtS_/f'tQ�NyWx<uvBywPn}pjov߽("!#*7_9 ]W/+� ސxBmGH P$`a9,-׵ g6Ѕ[_t=]8CKa+0MRHCtlNCD3�q>X^G|_w=�Q'f;y?_/^J9^R 6tఏ8۬pۀ۔̚l1 ^ ƂQTd,dpjڥ-u#6.VF�vMief e*Bpn,ߟHJMTLpJ5b Zfw(nSGYQDG.*'9Jk]Μg'$m]& G,.yl@ nGnXYHFfڕ3s=+0Ј}\/�gD95\#Ola MlD5I$װ*q/8B_ݯƾ8LJ53{хHut?<'*=$mX#YR?\w_N:#WW*مz*+^kcΌ eGKZGZ*Ca" w0Xq {ӗa:}: [W @ӏ�`>3J@ ;MZ[b�dXaجg,:θ LEO6M8GvP=p=0W9�A@> (s_S�3عnʸۧ{c #؝+94YY4g(2lvxe]Y^t,.2fY InxÀn}YR)eA$?m4m0(&/y@->T,b)سc̘ǡ̲H d}nh{pjK?jh'Ce_(FId7Lqy&@ɮ6D,Ol$FO�rs0ʀֽ)\L_΂@|3c_|V͜yv%kuTN->d>(x"/b|!q]ٷ&@CE'F0pYYmb S)ET5"12_S36G[td3rtm?[WVPtxLYkA1{oM9ĠъsO@N[0Ϋ ًgNP] �3c/BL�P+Z20[?."G ~e fk;p~%o!+i N`W.`/[BtaV&* d=�(&N=UY^zeoV׻g_F _n_a29p7#-m#w米:ǶDH#/@ ',�6S+YIl܉KuY~A}5n3)R̲.Kw*@LNp`2B&KY /aN*xRZޕyQ -#abi^ӿzkS\ ;v5We"4r +i1^z�K7o:d?)4>Mo�$ŹLFh[u-KsS ǯB`sVJ3Y|-�3x^�topk~{{ӛ|޿,\ (8C)]1 [665i3 s83wO{ Cxn s�؏|oM;v~{ p!:T |.�0 ߕ�mApx%n[<^#6ۨ[a:\&,:׶;9Q\0ae,*g袸X,�AQ?cqV@V͏>6�nhױu2Wл6e3�p%O+\@ aqObB qՖFOrٿ{`s 2R3.[QO,;̜:/Ӷ_@-p{#="�BxU6spmPӾ;w i]ٯzڴlp~Mwo"XD50,n)~Nwoa˕4|LxX�d&D�CR8ځamD2ZH}2<Xp*s)�rn&MG[Lݏ 1N[jL߃H{<!OoEW;yXqqZ΄ x3<D-Q92% 7,7�ǥ�uV3ԏqm <*+Y  N-8~_ i9;O~/�.Ҁ^ƀ'DF D›X*: qDT@k\ȤnCl߹y0XrAdѦ` X?ǰ<t?D�0l 0mLQ_Ζd+}j=~5L-;>W��㿂�qmZpo~ƭiwo|ںu!<㭹0s(v sF!�j�b(赛ka&*A9_ɮ+\GH[8P9�X'LJ!ôfe#|f(1 TRzt|di4 Ow72uF垀,3v:`L7Dn<w^`s# L;lL?GQҿ<O,@phE7BjÑa+kcUbm%PU 4K|$IWgA@7Y@n--v`fne[*AM0?1^dzL"|MO\ Ͱnf;(!K/սby/#M^T&<4B?Q4�DG#UeEU>}7+|L:YS#I->[ a,.&?3`dF;n�_Ɓ;e@*[" {^`ȶN+_|<0_YcdsͲ ‘ws>_%KT:|քeg/Y]P�G`'pݘ [\jWᯄxbG'7l�ǡ;upnw1.; vBZ7ʀlvYH%,r1pu[GU|*!xdB슀KX pٛ„E£;~4 pA2]D1m:X.OPʽl)V\=v5U!7McҏrS xa NnO?f`#W\jg%;^Äe mVܙ W(�'% Xt!p oő v@slG!BV,\Xx{o'[Gu?MG6pB1pԦ%+=j_bRGQi<pO0Af>O>@/M3*'2)gX%0�K<e 7<'-D3z;<p Ѯn|Fk&@p;MXރ=_|1+EN"5˯6! 5~ء:(I$$9n}Ro}76wY>ylF&ŐDb16]lÖOGh' 4ozy#A 0_[G�@\mO`(<{p][VM1@楸;; Vy}/ ĺ S]upA:kɣ Խw}$1mr�p ,2qpFkƀw6j2E{OL=tDv t�x]imw;=,M>fS9֔rkw m /߹ɍ�h+'[x{, pcπ}%~G$vg LL7vR`mA) Q*wnUى Xc+/b. 2/E{"~J4EdX$q{_ʥwg:PlIYR=3A-LPiHҦ_×p݆/ai4xW7`~oL?]>f6L߯OrE^sLL]ȚyGl#7{읫w9y{8daMӗl=Q@dr/}�2}p/[5~.8̟(�ԊͰ�tką{ҏBN\xxzp0A!Á;*BH|&#�rr#jqM� Hm>2 >O1vx@:SW\Xp~,>ŝ [Y–No6p{N6c,`ZsÀ0{.)b> h}lex50 ol楟(¼:tX;IT$vEh~.q]]m�~~ o(ZS, _3^ Y{ߡӝ'0.=\ AU_FRd^o"At0 [\p{zU@?3$>xX]#GXh_ڷom?Sm]i+sE`)$148t]�r0!�ssidx2N<NxuL8Z1;UhzVd6WOi.R :*"Kx݂tٱpAW90m*^QW+pѥf1yϯĀ@K\!�Խ0$F&umhu>?ƌ}s;"ahfG_ 3QK"=EӺAuL0N9(z= +z�ܣ``8ugrDlaa(e_{QǷZWٶ,2{i|4O\Hy<禮 2�q`f3gI! H7fVIx 6 ܡ1^(6A# XfdeqnӜ?-E<7y 35!0Tk-7�,Nr݈,| LzQ~wlVWB�Hv&ץ]$QܼM cl {}kg.;hEU޹ܟÏs� bMXDcYvktH`9NGX#yLĒ'/rr+VPϷ/c;.cpK(ц Vg%�n2xO��@�IDATg@?+\tX^tݟL?wde<s u/Mu--8XMs-=? -433}< e}��\!q;_kv.;{V@e6">i:S?jʀ`+}x;` �kvl-(Ǫ \*�~z___;}cq;y3汚 wynsȘN!9>ٞ} XUxuX`'*@wd[_Q8zx̅0@>~x$BK'�BTzG;<ޑAdA޲'=(ZMN"7:?ZSճApKEh07N:Ns߱eh!mG} {oN[5frJtxA\fu!`bLWWߥ\ֽ"k:n9Orڼyc@ h/#Bp\ = �sE�"v4a�I ^( #Rs 9 ~2BV ػ6+"ppimor>BA`}/pjA�,?/VhT`FW0W67aĿgȗ*$i48_]8<];/N|~u!'R!̱Wcg|j!�@< *Z NPHQ�aS%@p+0 ol楟8P|G}\9΋&P2Ś;k a\+DSj8sVA�F/ Ash7;(q-)M-Af"9%t2k<T"jZċ{Kw(7ӣ4!_]gƙeVg"*[i67:viߵ"B @tWVi&_A0IK xωw+&G[z).6~g28Wqz ʁSEɬܯ^eYV-QO?.tlob9 )J?z6}? T 񊊗(5щ+gpFpvFOQ:9fBt DVCuq�.l3|놝2s4_a)4SAwǵ"؇  .[O!e97^a͊H],ͅŲnlCy^yW>@ ] I }i)-dCS=+qo fXsozC v3u!niQ3!i$>̢u/'C %1ِ.gU3-0Qn<Gl@׍1K!S@)ν{mzRnbm", |OzQWioM͘h7m>*@rTXj8Aca`#nWIeއ7S7%6 =1+q|OTis y䝔JNwm=AE~?]VIa6S^LǕv1*;KhBm/a_bxfR @;']!Ht"`_g ৷ >ζCJEvZDfF9cQFQci/cLJ~`auK`r Œhkа Rkw_z+ewfG3~ e8f }7wc(Xδ 7䱙;t`f6ilC-sk_a$_E(xbٿʀsmo$vf,37QrG"!@€mdgےU pJI%PA'ѷ\TKԍn JiN=8ψol{L#ZtyG~5V`XW_p(WY&4ؕc nW滏K'�x0 o/^^6nGKC5}��r(ゲ:_}m}w"F_ f6|uvvXs94"^x3h!';*[Hr-Vf$¢,H]'~{8UIQ0}�XC_s~j ɛ_ Tp+ g{f+ ఉ7@<c^9|.<k?zpx>\*+G/?b{:|c�ׁ{lY*\gF^DMAJJQ`E<~Btb|bquexO3-t;bJW>mk(wf>g@[2 p",3'+s> P%yeb]3�~O|!W^j,AZYBJ 3;NU?a�/ClI8_E|oܳ"Yg$Rl٦1'ǜ@c 묖IjIKeEίjx6!0so ox p!_A �D 2lhñ%F3GǀLG @>LG\HU i| ]͈rg(W$’/#OG#�<rEP�ZB�[G8ֽPj.;fz3›+~K쇏 0H:>m:4)N. VچlLݵZg\#ƯZȯ� F#Dz/̞T "f^Ho8+P$^4s85<K��tsf uڙbCT!cB\sonz}1Y*g{9?>ga'̫~3{u K0Y<vF`lg}R 7Ɓ|a6z,`CRힹ/ #3]q{o> ~jj!eF{E@x �1-#N6p'J| 5GԀGZf$t.-/A"Pxԭ Uh_Ʈ9,Y0OaՏ2~ 2+(G:W�K1lԊUϺ3vGÖ[_f_Y[9"Wi_E:�wvJ1д,c$O/@t<$x:3ޘ|k&zip]<3QoةJ}v֧ 2V!Y׆p3RLLaÎ�`1}6K_ߊ_t5 r ]bļ&Fdj̟u8 o8v (xFͣ]a3ӧenD�w$KH, .uyn9v3>͌߫ cB(d[y1>îrT{&HV�_a?g4+�"."ڈ ǎv/@_|[tܽ}ʆʁ �c8B�3~cIZm%b)Re5l\GЕ9$̦t)bΖ,s,^onMsk*|$B22:cc:|^*p H3L^2;"~wPgcоHJݣڵBc ;05Rw %Z =#=q(Dh;?NG럚z -w__ڭ7X_'`G+riT[ :hx * hhđg�Np@�vaPx �|\k@zG>es@eձZx7^j,úX=%Gh|K\UUk|qU-[[i&tϦqc; OOQ;ip.q(4 8~A(<r'dN.8Svi8R4<޳gFޯRtLUiTI{>f,SPˤahnA$1K h no>~xfHK$ZKZQ4e`Cƙg.@4bC$a5H^k'/Vh;ru*+�sOf_M �(ںN�J�+kw*A S(k , D# ;쵯-)Fmj L8p0(A8Y 2cwf63|8v"z/>-mF' A[TVt!�@t@J�,&PxVI 7=ǂ--*')yu`[#i𧅙pZi&eg6ìlՁU2r Cw yܫÀvMt#Yϑ[rJ^}k= g,pvA@L@*Β)vI0R]0c{0dˏDS!V{w6sI9+ 3Yb& Nx#\V̆>Gh;@?asKeDAReFAbJOqE,Yx̾?nd60bG0]yġ`ZK:'@n~ԭrt,t2Iņwߓ2&W<$n!Rƌ\" G>rF?t8 :nf sG_ XfsvO|qTBT7V]gw6:M�<ڇ4>5z|bxqűI>[򶜥dSpί^jU]&|DBʷ޻?ݣMv5L,&怉},J%GaƱϹ1Apwb|G1K79V 4aY v C>Dm{ӻ2�2?e(J)x X[;𯸉Cx8d 3k|aÖk$|..KdZ U(f'I<\j\ =~_p5$9fvq,s%W USؤ~!x<L=pbĥ}|%m9N>xz=IԯwkdM= ߳J-~tO>Im8ȵq/ is؁-p,5ɷ�/P[ӺY~s0K~O/.N4x48c8~9h qPm۽{{*j*#N IZC Hv̆Àg1|951/ʛ q>}r& kU @*Aaut*I6P&XC4SGgG&qb|4#jV"edbMB?@xܸZ# i r/cYFp/ڞC{߷?j`OK!:q,Mv�y5= ~gF.=] 59kw?= wlC\ g5>pp_wxⷔl[+=8z|a\ꔇdjJ!'T63'*ۏ ;mBG۩6g] C}A@Mw.Ԉ8቟;AƜ^LGnD]pփr>g\k]eU(9+*>=yY㘈i{x^ "K*:̡VG|ӭ@J$ ?CHK%R]}P\ w gP!P3ф`cp mx*e&voOaR6I`$?]p9?J8V88ר;23ZgK`<ݔe|XnmxUAH04c'OW?ti�2p" GXz;!@-�VpEVO&Ƀ:PJ)q\U!>VA !JX?6>l:y�A|�Џ�-�*Xlo#R}4?6p9"8Y(BՎ'Hr@P7FK$ #4AXD#I3>'p3(hOOpn2P&w 6YpGk;+Y*UcYm!W/Pa.Α Eyg�.Z{Z^1:/ ~U,cCk�Q=H? M0=Z>Yc ZI{\oV12iN Ny꿘_-gI*�h1M%Q ? ԇ)-VM�nr(Nv�8Jey_H?2 Ӛ|8[60!E#Y݌ *(gc>�iX8OGlweu?' G˝5j�e4m.rT g�rOֺ ^ 4ybkyf9V`<a%:>RRk,cJp*v 8羟ۑwgQE] 8LID}%V�.Rq|ߕ9K;<)vfM`A@?IN@(7L1I!6Ovf/%qfm6{r_?X[DZ`a,)6?d^e LF C~B,]Wr;ie@u]d|6YidFO)=L3,m%濫~i'v #]xO nȷ]︮e hpv_"uZ5:@r"S*c/6M emƱ@Ƹ\aK*c{f߉Ϳit'0crpwA+KVsľmDjr|lGUW1#t鲙.�r%?. BM8 /? 䡜9@Ĩ0n1[*k+_޼%4miBq-fҦŖ�[2~4e/=ژ6 ]C\w_ۙmݕ\d̐Z ն)eEx&@fϧ j`u\cGV1+Y':9]V�FBq2�r+``mHg[<`--4n&_~`-lQ8s5�0?-u_K?KΞGJ2smZE<zs[l#8-ضPLV MMv^~&6+5-cS�1ݰqbH#li\-{p㟶 7mqk;ˢt1 >A scy(cc2'10yp~wo6ikR ve T9F 0iaY _fk<~k/7wvc<HĺybQeWE"XC@ә^g" p붬J79DL|-K61|@a`Dr~#KYF X~0'ql ڍD0}|;. a>(ZQzݞViimgj �aG(�Kj*(� R]ܶȌ;F6Sba.'g?p�(DBH Y"5u8d6�PP!+lxhJ֖|^Ljc;:�hOډ?Xg(`΄w[<?6GnMxWX۲0M0G5+m'?!FGFفoD4^޺x@G6}�?\\]`WVK^y 2g`g�H@/ /Ewՙ~T)r Ѡ E@Jg9D"1}fA`6jJ } CE??0Ev(4ĒC O"23΄qJ~Gy11͜(tjA| ٻ; >2=qvGi �!)ԥcl ޺"CM?+XQ MpOe@t6|ևlp.-.�a%y�sMGq {Pm3gއLđʁV _uo.P? S z+'-NJ#@D-sw Uc@bB 5nʔ+\sxbÂ7[uWK3̲rWK^y_9.^cXG+̫-d$q[6:K?m;~xVũ}YIc<�kPJ9!z-N<Q. lTZ}QD  inlh#WЬqrA]fEP~TB,G3�F@n=*js(WcnO1߸2R(i =Y>z26ŏ` ;Qj*bL`Ɲ}~*0Dͤr`G�ոU.L aDK?9.myt7W 800NXdڮx7< :;2 ܓx=(h|m|.01UҀ7V#Z%2zCWa_+[ƆScW4ìbp,Qzfխ+o~3023{msn3Fd7[Clg6V:~;n Qe^a@$].#IxFB*틼t`z6/L7CQ>+LҘyd[HG 0Z#˴;&r40Lڮk\Ni~n_iF5?>TWҧ6rK -_@ Be-H-8)?dW�)F <އGQ?F?W2Sᶎٟa`ya=}/c8~z`_�++rH-yRgTu.%YWQ�\H(B?(; ;D1}os;ƈ1~Rx1;4LJxwlpxlr)`4xwþ˾ 5yq6IZ̲fIC rx[Qp~Υ-, Z0_hDNkWJ(_;7ǽޖ~5kf /T!Ezu3NsFlL#a>@oXGA=O>XcaY =f �%`6Z*);?j2:F)Z˯HT+yV.8`CrU}:,ݚ7v8HܣoVf&4xb Į{A}G\'~5�%᧹!a &Ǎd .A�w: i9LVw<*Lcۄt %=`l;kݏ\E'z-M�ܧDw2|>=FaaN?ݽ*0Zw2`lSA;j,1d-ҝp+C! >~5M̏MoH"~{.y<aDo>SoxA`C Z |8 p aK0{ |-͛�1<牏̌8*П<�W!"R* U nm}8K  _a3㏶f. 7e<6_;q;~9ӷCl�۴KA|\]�'zf}O�l_L ʠNQ$iZ{M|  vQ�"<eDc/P^~Gc>LR4*:2KVi>[^ ^[~y3%((}ggQ˙G>ȴ FOD;.ww!s߃^yE@>m<}@e [g8r-0žE[1\c E WC(84 vZb uhlc wϽm2SOws0D2Hk.7~e<g6xQX,h&BώG Jz gv�OV y.j`[ V�`7Ost\J"'p{nnq3?LG62:)Y˹ %^z_>ICX ٯ:۶Y#Ǝ0�2v@@xHаZWp8G OaP*QB*OacV%VN˟~9i~;AX!c{|& n E7Y²ga[&;8+ޙ\9Gxd#yƪ+8u`!ڤ-'lZ/я|wm'ͷ�.Ҹ1ҿ+SX O@p 3#`,!}22Cx1=j"( HXO1L3wOw6]> `/;4=d_'eZzS ,P2#8yfsdİ>6vԟ V@Co ( +`-' x½yX-fT}Q M1Kx[Hv3{= Mɇ `[{~@^‡ۙM>l>LCV8x0Lu̳*2IvlfnBmn'sS`Aez9geDj[X`6'́'8`sy5t\lon:Z.Awq(׾= �d 6ANc R^l=U L/ek÷Q__& 5+'٢KM 6Woz#@M�;|%b�N'6~ -Z8O7'ܹ�qr3!2S P(PUvdut%.�E 2nK�P g�gBɕWW6Mo�?# {H}iTp
,6Pc}Lj+q@=\\%(9[i'pR mX޲`<?-!,8lV�jû _ ̃!� SQ}<mZ`o!8U{zɝi79˻1/qwYA``5x\u0L9lh[۟M?}/U(ؿ)q0 fŗ\3��Xcc %?"I\&عk__w6W 1n#\"Ш&SK YtA6=,LGkﶯMo*8C eX1$ a\#3,,\B)<[vXK GDU� G)ƴ:;H`׸o[ ]e2b^DuC�9@t tm?9Ok _`aq?!%*Gx)~LegPˇ#-���� .�A@LAfF7м؎} qW^އk0yupۛӍ+/: #cxЍ6l͎FgZKzߥF;f�N@Q`8;'opwGU~6ʁK l@a?vv;@ Uݯ^/b� l]d/D*+3c /x%~;9.sn{,+D|K.佻{;( AYp\˚A?'<{EX.#Ϧ)Q~ /.6UB6q:'QdVQ=Q܏9S~~? qX*"*�u�rU��YU='p.\1Oe$˒'#mmgu0r*Lx_֕-^#jPoyP}\2CC+qe/r U�Hd,&. 2J?ro%/N}t[D;5N�bp9*߱{-~x1Mpg* NyZ n5Ob'bW$A:q[F34F@y 亣ttYoqfqNM) D9q~w^(ʥ;BMn$ %a/SO�, k4zKϟJ�tO|_v3@?!"0U%Y?T|k1Ƒm Gb,jr;̾؆#ƍ2,z!^G㴸hNc[P[+ᄋ'-O?M] tjƑukXoqao2}q&P6k �H%.'eD\.?I~iCMIfj)4#`M0M2~Ħ钟[rG!(B`9xpuWT\'Yf0wAmHkۀ6Kwi|rq:ƩW)NH{.Ym w%ePX]ˋ1.oj~@^el@3}jIT!V=εǷjI&|yf3sp\J/xlNptDcSwKtzAK>|1}ggMܳiw-]쐰kSӱ?%4kK[Q!g <a*a/=Dٻ<0j\LY%poOk^t.}S�t瑉Tٹ% nvR>uGI[۶9Vv$ YA*:Op=FN3f;` 9*ÍA�=zpOqc/3lvI;tG4\fI;qMc+w.K726q.H#B+hGZ2Jxg�.C 3+3cwEM$�#u XKedjgQэ]Ck4}ԏSpcNOx:sllbjr͈VOugןoLЅ֜Www؆o ӖQ^'LA7 =:G5`qT Stǃn phph4ց˷Tz<YE0noxۇ/b֩ m.Bі@NGCp1�ns(J3�.[2B"K[g8g&T9b"YG 0X']x2N?~1B8 3!NSG'(ar_I8ᰝf.aSl@<CFr+4<L̠3}?0qy�&�,.'r�d$^�Ũyy{uKJԘ 0q_U|m ֘qfZ!7cLx˟F%B ,ot؟_|,Y/ E0jDŖIᣵN RyT67hwN g$Ԧ5|H<7}Î6r7a|+|Px+kH&~ oC@<̚WvxUjϧ(ܽvL~Ń-JPod%PZ^#Н,N0܁8�`fZ{;?{G@?m%�8&e'Ocs $a�|9fUtHC}p$wedt<^kӏo}�pfVC;n (gl ܎1ݳ2EeDӜ7q&z'i{[EX@cފ^�\Qmo[>;hwāzs~w^(ʥ;p$Z^:_"rl`.9y}%A&zr=Ob%<– vy< pu ~w]fF?.30,_\[ �9`Cu'v<7@ L7YǬ~)�V79=UwWIZO-co;n਴psŘ~j}p(±x$H|p4:z_ҖS,?ZvjP.VÍ n� 7'+ӻf!k1v0~\O ? ~:tm]t]~sog]N(ٗm_e_r`WЫK'�8 KQC0P֥_xQ Q }`&0Yߗ�U]BUo <bB񄷽Ltlk8m<cG#&.{}-DNBQs[E�`^qWI6+8?" 6 +ZYg%!e)}s`++|�G7]%bf)3kv8-Wj7?F#O#ݱw|pHQ_3l_smKa (FDэGYf,�f^cRx%Ra# 81<ݤܧ_,$?am \wAdWDׅLAA$+h6 gG~Zghx%,eMGae荙4%r& MA ?o1_w? y@ fsg~6B;mKOsKqyem\<l11SD]yLL@HYW4PB E �קOG?+V~ f,e]!F"qd�?;j`�Ke2P?FߟVߘ0OY�WJPVaCl[?GpJ:2FcKG \۟)ʱԛa0OMtk/;0ßcJYK4?M>S@�ClEP+R dBD^xN}/]0h)7wbCJ1MUiAc"#N̙A`~"T379<#t1t3K ԰R]#`7a^/\Fv30YDJc[Ӎ̆a[Yγ60!_ѫəv@'Ϡ*\7 dM=��&@UȱͲ Vp޼ izM~v9�L�p-OsuK��=Px@ ��@�IDATb`3RCA2 R<kKL-,!F!`ߙ֢�sD؉  �Aj��_ز_�= '7a_-~\${78!_sP0= ,|²I?"M<.X=�vh֦϶8B �Ǹ7y6j#a xҿ?lO_\]4%V�Wey.,}ܾ˾!lfg {QyJo_clBN7Yքyp_~7ֳs_'~-0G 38rDF#lDLJѣ>�'T%>H²JwrbvYap FOPx3F!.n,T2)(eێsL,:*jeAwtcʂMfe[@/[h@BKٌM; ^h` ţI-,\<ER,U3V93Г,;h=8bfì6Rڶ,KwI}E3mLp&,L.nnƈp#aF7%/yZ29c+`{i-MTM/uOM[²yQ^Wifގt@57!x݂ LM53TF}T#v{τxtc˃o]f \LӄB6ttO.GX~~&{5%r˘#^ʌmF6.EGc}Yf-,!ٷЏ92VOJnޥζ ,-�B.@yϠCQ; ~}~N+.wJ37*@N7&69/~+Aq|5fcqxDX`DF4]c1Xz,ٱ]V2 R[ ui$`c&R<<O u9Cmw "wWG*_ڒ: \6 e^VGX||YĆ0>kϘ%V~vV@ aܾf-!Fe=m6O@m(&l#I|p@|LnOD߹seL8OMl\q&l1aq&#̬ q8NVͬZ+=bVU~+ 滨E]0m!;Sľ&j ц6 spU;u|&ÈG+_RGB= 2#7`hG>ؠp;~}2I 3;p!Դ#,69UaR6yqD#QKx'Ƽ\6pc$LL!}g]2DtܔCMwy߿ɁYj@[V`$i_Cm JWQ30gDփ.�o'ybxtJCkRzkf)!Nb8* onMw`u IQ(p>ZНIqC[o;QG$` <ZޡMOuי|geX@}%"/){5 0ggf4񨨥y^Jp?�G\N=m?D٬Z]ι*&yͺ&C/=3U^s<lZ_#>4��}rr?Bvn;BZ 芤6˚~ wk0e.mz Oޑr+"Ieq(kح=ޛ[=I}&̟G:3$ΜI>8g <yww?WB yD (T-pיr]=sO |%V�.&gE oJ>َ[ʼ 0)6elǽLl/{`|5$IYEѭ3~''GN:w534B?~({1'=Ԅ;Y~49sU�jke!t @/n&xtEEا!5:׷s`ڠsv E:[\H0,}޶UXlflW Rz|ءQ+< a- gcHqd_|0|�lX_0~u# b"� Ec+�e+?V7>cewޕVvlose &M]} !ϩ2ҭifzMGla 9G;젵i;ǴL똮e.@ �y|~uZJ�Y 98K`}2MlD,v% ,g{M6u �uor,7p5xKF#A6z9kh6?f4^]b/˶nm} [dbbÓԆm#iÁ<ʟ P(Q1W7T /ڏF,YQDܖ8VC#|i|hGA7Qʃa|W`?;w-m# =%TA3v\%@Z/~̌K-2u0E#zT-O>z Ll~?)ߣQt_6b+R;"nwE[P{zGE3kM̜}3r5�F߽~8vM�yr uP g96EeIgkĚ !r3-\/,\Pw2 X ]}TFT,owwmi�̜$PJ W%|%{4uX߬ N0f&#c^b`U eɣ.;g&n8+lF[XGnFڞ!d&]q_V_3�k[ x5ڗjY}g.R�S3~k@7`?>{UziE B?0~Ott1Y͗OiNjťmL`v�5t\QqENnXW- %N8_tCFkhp8 u?�nl9@Czn9oށ !Q,MD8 JڞI<ٟaV�=wiw#>_<=y<w3�.M+}ߴ+(D`_'> @n;ꀝAXw:NfsĻ5f1IU&,8iNS4") R| ,?OB1í噘be?ܚ>{Nߝ',ڸ2;:Qv}Nj/Tϫ3�BWE^.񪳟{ϏDLZï+AB;W^ \~?~tɔ Q~& _<s !3fXqw6purz&l~!z3CȎh!&A;C< 4Yiv5g5Vy^藲ҸqQC�8ri%@*:2 �!lGeAo-"cd3̟. 7lgէ(�w{)�ݎWgc WW}Z+e{9q&DØqXjL6�q*6i/3~hw(Rɲ? s L9}gW͖<֊)D\m3Neطd,1l{: ?Z>mq+ <.(BhpD@a@!8Qxr(#ol5^fk5Jrό] }H|Bxq;;K�8ڼ$dJY_CBk0鍛 6]x !"8a>NFpIuݛÛUbUX,ED-ɦ- 2!+ J@ h {dozatZ%",˖TK-ݤX798q{3o{3Od~7"N"N+R{piIwnK:$h2`Lv`PӯB#(|ↀ+ ʰ=t0Zj߸!]f4R45.ze:fm2?ՌNXuf 1,`O=3׹~ͳ\1Ղ*Lȥ1xEOkXHG D�S<:6kdGmn 6E̔�l;?w뻋oH+Z/Et˛+SW3n]qgVxa�ذǻYl=@GaQ<Ri@B;D7l:,tTٌb4yF^{zӇ.X#Zת@s%k\:Ȟ_⋼fJ% 4!&cfRtug2j.Lt%ҫ €O],|?+ʕWNvn:^t(;meeou4GfencY$<’_~]7?ЏX %FLSvT+-&=�gzwxxe5νws bw4`Z+]ta b;~y쎿^ E\D \<A/[W_@PdBKO:Y2˭#=DG^l;†*ӭ ¡ 1 tχ5f5X!`)s[:lMuz$(H|!t1K)0t ZiYN}ղeɨnh$t΃ #οR!jg48A42Bmv̊j[R#o$o_,�֡<@Qf^ r''x3FU3} qțZu)QygbaF!@"$RD'tHe{wSRI |mIy] _d_1T޵=U6WF?qNM)%h2)lq^ë#0=% tfM\}HЇ岠`DeJyӲ $j?b ۓeN;涪7?Q>: IMw5~vF㼬Y7u9c*?_h|hn aa"]z!^/-wݐ5Vy^7eVٽ2Kd` ~$0̒V/9(NUt.6PeRw0@lXQp9P巻/LLLYqxUHv4 Z2FR4<ow^//]~eUB �G� n- FR=cˀQN8[2xhޕ0!KHUr/'@E2h�+{š>› qzug{ F٬*1Z89 ݊ƛzԆϮaP6-,MfEDRd~t Fw.�es8v-'M,ѩ݈3ƬiKφf[:tZb.4GC: zoy;'C%27l >)?XR �? ; ,ԄW(# ŵqW3 }q"nt#7V58@>z]�\q8,'F?JC23,47h=e:vD`SY+z|>7�vU�a � 3+\C2!'A=z -njS:5ݚwQsSB6uzתj|"(7�Ҹ\|T3Ȼ6tFw AZ:Xka@jO }@ ծ8+* Ҋ|@3t.Äy\~b�0K^Zg `~HtX)v6�^WF[,sAl^6'>-Eذ37vYV4{۲L̀!~HI~yp(b=T"SOWtrFrfvI皠nn^Fg+~Oy/z9$j DcX0�]]^Й㏇>% _ct K^p\]&h1 O$=1 PD @\.*,"=%!}߰{i[j(?}I2/:mf͌)0N̮R/[|`jUaSQ 7g@SCIKE;tU/ٗ�).9} _x' 43TŃ{_z$;o.&1J5Sj ,(>N<긢W%K8B}  Bqň� V"-3�Xӟ^cu%zQHI:FcW^=ZnZnJDξW+4x_@�0'+31�bLm1D%b ee�mV`톍֫Z ݪA67j&H9PC=U@:'`= jjfCR6L6 ϶x̕څAD5s0RȒBWH P\KݝHeOD'UDIgug1sC?&.9� jE 4,r _j&EU5.:Í+ {k�(<'OK @-W�qhr[�'Ȃ+ T2b� gDJoY^o*+y�#y Z(P'JUt($B+ :}zϝרN7` U�>�T@ p8зX`X K42FSR+|ǐ*Z Ti ?K~~{Eib�w_Qo; V՛ivCϯ~¿h訉t_q*E5U dkCmvN@xA4@п$E}Wluͣ =nb�0K!K|Ni԰<9!>2~7i (S ٧?hKCEÊ^n/u;HꯈI Eػb>Ahഘ殞ymB ltS#uXR|Y3{d\vL9ggA$`Y F4l3/_6@A$ŐATI)I3Bׯ"1l톧 Hl,qGH,C P=x[�AjIW-$!Oma ovUVdǬ4wZfjOݩwr'P҂Bm(h~"H`_!@ѫa8WJ| h{-ڧ- Rh�0T.kD]:ߟRf *fPb,8~ig<Tϯ\,Xqn�5O#Uߴ]':<]Ox2CȼY BJf(�sZᩝ ۖ 5HH#tHnaŸ ^y'^0{qrsWï1szC3Onjm yl^z]-ձ)4X]z̠D~H!CQ{/_dv|4Po`U]r!:9 J⢕6[}"w~<)aqTa.C- F`>2(J+?jGM͏~,AM\ x?;5oR17]~s3F$k"}kn:>>$n,S~o )1⧖¦@]3� gՍ6ʘBypoe)4#6A4fGCnk&s^--W'qR<܁xq1쑦tN(+ִ %i,_8Yw'N^`: ~&K2Y:' M d>CuW o_{]ӹ�hUHAaZcT/Y()s"G8e�c SR4!{iyS{ԅ^Pu2لڏ6[ȖۆzHgi\|wؑ+wNpG/"$ma��f}i Ҫd) -A8́zvQCZg[ݚV7UڧE1yeFϊe?q9Tw)Ei.V�f1hOJ5Vnu"Y,Ly$,g3�/?=XEIt8asMQ;v+ ^v޲cޟ=~Sq;A j'foh+|>ʂ`-:*ʔ�ɭ):yaNGH8zFzPM̫aZ>fF:[b }vRuOɲ/(b=U8$]iX6\= iW}pQ!h:#]Bp2p P./)(='Y҅)zrƆ,+kjNJ6.0#:ݛW_:LB8!96z{a+Se<qW5y"poJ0啧6mxZ& ZkS"PoA=sNN15Yg7ej=m^EB%bSK-oIP<C:NY﨑t7չtА UWqp#5t\ʊ &Ngct-m<B_ {m{ʰv?Z*{Ь)s?QX'CF=ΞVŀ|w^#U- d\0ԛaA',SMw,%KSf6Wh` T}.޺k7?dsl+.bmQ �s=[76� %5rnJ]-_isʓtgWg#$M{b?ts:vIx]("[*EI3ޢn`5д9g'K\=S^3%vZz[kV:` t+X +o~^EmԎS 7��%/ւA~ꧯcfVf蚍 DuG~dY-�8qfzWjJZ8aF{"DNcl[Sn,TvtiV%_bN.BJz02��PqF{qnɜFjg0{_MU7XoW9 �w]?*�EX+1RWcKԧ)p-+.bZ΍Na ]8�@9"6]+5m{#'\\D]h+8tU@_U;M9|{v?>%w·ez34Bqף/kUk@e T :WA�obdnwjoU@YkE[]co0r{S\τX)8r�RgYUDzGo2MCR=:$ڠ�!1b=󻢟�`W?\.Pp qF:8Cct*<0#^wH_CJt%+CO0pXjMBJ:'2| |Έ! U.'[pfU*T4 nw]":x-ц`FGSG]nK-[=/ό{>P+�8~wZA@PMtfCnܸw@m9Fm rV@EὯ*yJ"0SѮ6�1/goH*KI+ ;qR �xaT<p <,�5oaKʼ;#tw@,Psd9·ID3Bl):綻?l:�"!)`B@0߃ .(3 LX{uKxFYIDd e,g$$Rf'O$\ОRF{Nܑnٿ0J�@ 0:L]x2]Rѩ+0YQd0ښܺ-mI�>Okg�g%Y`Ze{zMk**wЌ[hk �fOtJ��Dl&Ea+Y{z {z E4{ܨ{P%XmN lsng5J9o#GvoKV<v ew˧oYHqT2$V'tJ'2r~'_Z^M4~4NDx3C뢣"gߓ 5YҮi/::a}{Twg�lȼ^;/>-�tE B8]XBw+0}Gm�P ?"ϏLesD?%y�/e@q\WZ1`d><jhl � {;@u@]>ʠ6~e9:|Tl@,*`pmOl~kwl#6Oc[ݿYmN*b8i0QQ7T#V~# .oܪ[|l+YttlS۴Asz<>Nq0'Pv2zi=$NΩd(^zYt2ߨ8<ЙU}Dϳ#v/07ʍS�~ԄɄsD4J%濼-Yi%=\CB8ɶiG`;TGfN&3 SlQ *PlGK&{b ꣁ�',A?h֏`ъh5@> AsԋH5+%C^j> G?u]NJ'0QF-pK>Y"Ws^єw8 lW=,áے5 XV;>Sq}"Up`kqf݁;` &OXD q塒 by)4ʝn]-IKGڛmĀݻ?ug#(_fDa^Şr"yya|<M9v# Ǝ�!e=Wi'Mr-Koj%c+ڠu0^y a`?A ]1|5ݗԡ| !BWxFb~ѣ+_ѝ!r|y{cҭ-#1D&Ol-(qș[oaf噅: ͺ̸h) A1 ):~#-p:);)S?(Ƀ1~)ױ娕K),Y42>ܢwPxA'\`~Mo1x@9b/a-,@#?xG5 rI h5h5J/ѺP Nf\YUa~?c@f({3q1.O [ō=^%dhh@ �|BY:9#^vÿ`kavCMiND!jWWHK:tX[_]L:YOkvIʞ#tBCo-qi%2ܐ1j{wYqY8W:B|-Po6�h \iX+)&dM@%JCJS<y%Z"vB37"8ZE(ߕ0(]4fx3dBͲ=` x ]t'R!9USJ^L 3z(O 7 ܢm_;!V/>>亶ᖵIFgop}2<t~[�yAZ҃04{:Hc=*_EWTIQav:5=Y۪@txyӋ(d<Xɯ=4Nt@.9U{%"�OpokJVa@U�j {wrP@KgԚ叴*[Z-͏kzp5{bf�BsFbXnlwu-W�Yʤ `_nWDc|h#/[WpU5 ƹdaM%v9Y pn;)m Er8zG\7ϺwO&xZe]fpC!%K-5?tR_[g1QQe8~q{Hř-Y�%Ȏ OAW* (aMg=z-Iy У37I+bt�xNn\IjIwO*:(h<Ԗ:7ݿdI)g0I 1XW̌kKB,X y@a <wձ`ShY7ab1hTs:+H+ |KowӯHgŠUfM`CWoPtJof7N+}rO+;z@Ѐ+QӚ_l>$WqGEOmG{ԫm]H/m׋@ a[wsGoZa>ĥS:~%hD(<b׋߶!ϠNܔ(j) ~ǦtRA;a=з÷LDe=69^Ȏfw㳋RGhXU(?Q>=>9z|V?fg 6N=9$AEWD': u wnk/[�k`a �fň~CA9 #$Jʷ_,1@g:3N|.X tnWBFg/!H Xz[f1{\;I? _ܠJ+ǣ|`5"9S˓<U@>}|v+U!nP }&V[nwP⁡8)-QϢjVo>(OO?ˆ>} !\wu9^l|FG1n+q`I:)*PSSP{5 ;L|�:ga zי= <O&ly}JZ͔l0rl5Lmn>%9q\Q Z`(◝i~~林I"5߾:Rla3b�h C`9>pn~>KYGO@3��̿ rM5#ך 8qJu۽yI#X3gV#}#?�*ŵQ̥6d4C\w\P>(;mJ:mE\w5{VR~:Nhy_ U6ڦu}Xr?E^ pvG4g`C2U\=jn ߁?ufvA{E@+.3 :/hoA� s:p>3$ɟ!ZhMU"y(jAeFŹA寅{VS)bHdd 4b :": <pٴx댶#Cs "W )SN0 "Lnn纝Bv�_&ѩ}'*]-c"fP?HTHzj2SO*pDz+�|"쬼q+ϞUܗFnze cK"{50Zі)UaZ5n1t*ƌ-g>vXъbvI[m8Uy(vP{W#+AM�`%d�,Rgw'3ۏHav2/BhpFK,7>%sF_F0 驍ٝ ( %:H"h>*$M 7[u` f6OwίH:!Y:%=t6>H,+ʼ'/? '#`VcY`@0~ �X__`Y�һSOu_v_w<�VP*=:(P\;ڨ83�ke]`@d?^�܂_0%7ڜ)?R >ՖXQ2(g@6 ׃<?:OK Ym:isv!!kZ_ I_Ask-wW,w[{06!>TJw3y .䭟4pj~w\ �f)@!1QnAg�6(Kљ[:3jD@s{ �$/>=ʶsx+VntAh0 TͨCE䁰{3@aW5dPS- 8TNɘ0IJ8ʥS3e:U�*&~{?9!@XDVRó{VY)6E>�ګ�3J�+L_yPw//0!î d~@\_}&Jm c`w\艹;b i5(86)$qDAM?g=WiBG"`{ s*J.zA6 @27D`@w,i0EEQi ,)";r  X`綺%~tUfF"oJT΂4봟=[DsGYݫR[!?u|gG{ TLx,Hq 9N~|+@!5hOU(ZW]7XW7I a_e/ΏLpfkwLN%aoILV3J- hrY/hPw^"vT',{\anm-CVjgmzvҚV 3I?Ӷѧ⿟/+Էva u�{5C>)#8V 9Qq@?>@:"x WѺi@48ܦVhv]@r4x;zq F\%hr.itIJcgԬ�:Rh2@9hT::\:xq{P@Y9S Z-Vn݁гz:?䚞CZdv}C �^?*ҜtC'O̗l;nZ08;uγ[U[PXBѦVg&~NT@e\>>Ȝ/v+;͍>&USjGo2ӞEoyʥQՕL[ jYw4LCj;3-1Kv+ 1FDFKFdsUd0"b5(8ހ8vCeWK7iA��5DIDATjQjiHdeR玲kYR9B �ˤb0S 0 LTh:gw5͋:g TՔVP1ĥ_K5@AFG FUtS~0,*ZY mgWaAbrƍL[K. f- E䇴cUQl"+91Ϭnuk s7F(Q,rqT_f!6*Φc^tEfwa�``(? e]-ׇ|�^7 i$#3{=$?7wkĩx s{5q� r;Sኯ}[)uOȬa]2H[�чH?L*1 |,b(Ysss�g$?+zx9|�%FϼJf]\ΏJ_p @Xh@00�`F[�0Hc'}L(R%6dG0qyVƕuɯݨ+펟וguSbV6ioEQ\aاN?: : a\7Tnm]Hܟ j\j(݃s } :S w`G&-BOa x/n\v8pbߟߑ}rtH$Qi -hv< s|XEqq`R7[W$gC `qe/{']a|O:_ tۊ6zLU2s0pAz0k _0`r۽Qg19AA3[?궯k�=ekZL"&gŜЏPkTȇi*Ƞ@]t}Z2Y.p 83J_y?PE<86-CرzkqCUz}}AwmmY R=1PJaEvnOJٖD�t0>�p%GSs/Khvұb-/O9�Hǫٿf4~4GחۚX2/K 4ԃ�T3O<@\ @ZodLtq5Dd=U.* wtpEϐ@؞h%;f_fTHa,?D4THTLþ5y1K/f8U.6#(zN4^!`N|x};U-$3EVT25gt 8bWm8ԥzw *7hmܖ@a߅~\ �f)ޒ9u<><^0A;eL+eyE}l{3 iht4HcZ8m:E <D|kH !"lrg75 (BFtPѺ"PKi/n#|g^�x?ЌY�y�Zc,� �?mguO^",~j%玑ƭnݿ솜+"�1Zgp`+p vȼ''Pe\ m\UbiRfW6EV I" 5nM,ZϊD/j ;jaj1fQ?8]Uԉnڦe�rA9ˠX^(S 7�n8=~޿t:/%3󜫲q>}?ʎ:VjEKkŢ\z{ ,:N-"F~ᦾ_}K}ԙ $\QӬ�h%wĈ?�"DBz �[�b0 �" ) 9\0�(ZZDS$ܮ*Zҹg ^0s� @F5CdjWȕBt|뮆Zn*Bݑv�F@�]:Lf0�XY鶖tp[+ RE@ԇ11ƞzn-~qbLgwnkɈ QmQV:DVmmO/:3�Ʋ" \دnhASDgP,t< ܩ'_ݐ#xE<MEWq]ro /i@ߢp rjwQ>vZK+0RGeq�N1r8bF֛\wE!ӑqcPEҡvq& P3m 4`[SK~G[C̝ngEgCq[wK+"&^W|Ƀl (AH]xBjEf `/9* 4m罯Ck:@)VD ; PpeT\-;-T}'Yr#wFӾ.?}u)rVnďv8?n3#�TfnyZ[Fml4?}K͆6ã䆏/<Zvf,@:*t{dGGO9x?y2|tj'@f:wpTwEK90bѾr/{[ҙr�I8#rGJQ #?f8]ͨ< V (䯈Ga�D\Ҩa5M jR !Vw \8"`JȾ^c3?w+uU~xxT}'A?t8<"NzC2~jn5IGKAaS/, GPOhzJjO=>n Aq1ӌ<Vۆ[MmHje;jXZYlBY>j&I%4N&QJJR -Ыe"I z*DT Ǝ?}8ÿ�KzNN{@{eP?J[N$њ@Iå 7&۰?8B!x>)C<WAFޱ^ ҵ=G,!!+ r':o 9�Z'=p<U0� wTՊe~ɾEnZ&Dr΁wr(eo?ŻLQΟӖymNi Ϭ+VsE,*VE"kR0{f=,emw+ϯB/f'T �lx\T>፝ɚ Uggjn]wW7w8&dt( 6GNN'h6h2iە 5�qvqQá74X9PT gt8Ń|f~HĬ1U ffڴ8c+:Ͻ}IAGp!� 6Qvr+7L4�ui|@# @!@@w281 x9FVjO dOrrRtW;c?Z~ti(mUaHoe =bST,av0-YUX>K;n܃sЫp]�ZlS�n]HvZ6^"YACͬ-NhkE۩L3vٙD1saȁ-u,.rv02�3A(bEY(;@yWK]Q+2(WI<Z:uWDqDc?4THC:iH'p[hE'`wf9(~}`פÀuHF@ۍ|9 @ :0MVn5+7�p�dƯJ� 2Z|ӣ*eaVhYVVqmzamE<VzJ7?]U*<8-2̪jE2}{0 wT6v中QzijSXNT[ࠥ/C3Z9oUf~b DBWwt0)Y-e(Kmrtd�i%")4a`'HՏg~zi1g;f'2w9+|C3iZh*+/GUT?uKV@ }+ n|m3X菆`0|uzIHûɪPzաXt*ͫnz/7:j%'7aPN`?5kC?c"x^_zpzb{�s+;^v/MjwZ3T!> ; {RpPڐ=OXec~,l/Ls50Aõ~+Nϟ @WiC_6]4z4d: 3}r0#o Sh8,o-UJSp^[}�*ȴ ingGD"+S ȏErQ<G= 81;?2!tnv"bc #Ӄ+$0|OUnF\"9/FޛnӋ</V*)b�KճO7qޓczE'Aˡi10c6�*�1s("r!XpOf?%zaU(R5^;J!N?8ʍ0,)È"IV;CPTeCW!U2fm@# Oi_e@S/u/gKP ȋȑ*C5 _Ώ,Z}@WupP{[q V!TZ3W*۩F歽BvM;.[u )fUkJ9h3걂F0jO&bf9f寴چii%|ySob( * W#�̺$2r!(HI=�<A�~:8@8w. 3EͺA\(:mFp5Oit8>sDAj'%i("U,1rL\KcUyfq `Y"jj,�a~8�1UI ^9�o*@ Z ']}xYӒ:s !'5p-;LH.*hB�_\_#VaCs{U\5"4 n]ZN�c@g, Wz% '/4Tymvk3D-8^YWCڝ*m^ M0w&DĮTpҢl]j !̜ZZ>rÏ~BwYWr0`t4;,v+Pܱ_0ăACс=rT5>o*:PVJ_ܱ;hĉZE_wR4 V&x(0b8fhh㶘V%%046[OA?qzCli5X\Q 4㡌ţ8L4BVNA3<+u@ U<0gE=I@xbz_Vj҆6պ2FPX"ăY%PfP 둯�&'ŏJm0n<* Xm4ܑzո F|Xa";;FQqso:xt,Nʃ,#S.( Z?&͏ëT^ilF?NB2C],@Y|�Ē=k|yP~/Dt-<aޫJVja%;,aSCb2fՄ /WǃڬWTEUZ]nevo'ѣXwX@ycGI{i-t,CcY}a8qF'v̕&ccXd? EQS,֑P1Ё#ډk4|rs# @ ZI‘5sЎN�A/R,3mŽj8; ϵ=N a#W0,JHbjw$?Q\Ӡ`4>w`hP~W/8F#^GC[lEIRZJtۥ Kiz3}5hn64t6+?om)"N5Z{jp㋥nӦڟ&�6kp KG\ �f EȰ{ mO5pw*=GtNF U9$RՏ.: tLØDFƩ�v#@x+a>nW(F{.0a/d~0fcrYW>ڟ5A4_Wn)ng/ "8(P0(`p�wu@_ӥv'Opa؅!+UWjq]*S]Z�g?S(P|%� fhrgf=c s>s,D\þz!TyY8A@>{\Ot( wP6;̶xA !k? Iĺؙ)Tka 9ak|% (taþz߷@ �1ף[oN'W- լ \z[[76� _"��h0� ҨzU챷m 3po$m~huՑV0ڪFtmTi�t\�R-lkV"zcY[5Ypcz 4aOOH/8q1J S3~P;"k` l$@A@\dƯwnvϼ\m=� н?>>WPYpV9Oؘi TWC\-t{m~9U[XzY?XrF+4o%,K!�ұ-0Qrrc Ʈ }O03>~#dù GNecs]'+/WDV<|`wvg5 螿=u? <g?4ȘcLy (.={j>ՉHkQ>92[=gGu` -s*!E7s1�K :*Pͮ2;'iw:~u�K)t|x3zQ;#= zD hg_Ӓd , }@ RTz*u34h "߷ 7 jWՀr;O `?*l}Z{Tm(LXjʕNـP>?܏>Z@A@qb*c7A@aߚQ3:Tk+=~I?4i5:)}؏Loj=tN!mb�]cw)�hp_3g3-�\I4Q,'Ftw ,I*S'�f"`y E5C}݊>:=u<9j+nqȏ,y oNcb6cf3F_ @g8OK(E!=F {D >A-5bk="rF@dcY={D~T6�` l^@Y^ W$3B~R`<kKʾSCI+;Ωߪ0SasUCLS'N}0c/n?n1r cc3Ʋ`j.�'~Dֿ[3Z[#5@=Ɂ^Á{:U+E3lfܾxO9A@�ܽRWsKߨ=zY{5أٯx24E4J.?2H> s6w.<�\^Z9BhPo0i@%}HO,;sP#쩽k;h㙁03L]sn`y^:g @Ԋ~n|)tymϾbWfe4n^B'=H0H>)d(|P\gvˬ$ߺ{Bw䞁cVكڤB]b0ZѹCxWgKa%Ns_L]w##@kDXmj� ݽ)?�{ P�>_-*(k8(̪\ͳz&*>)!ܵܖ!aKo zf3Y�@4L�iqO_ 4mk /˟">5#D| )Όm�=| g5( `B$-cCfUgO*8TN>X@�3:W5(`�s{p^vo"?$)ڒPW?ߌfq߿١�vVQc80j~wI{`TH6g&_V�<g "Y @0xB7z+2x v)Kz)`]#d%~fsR?faP|@;`@x$%U"p< *⑟$wWNJ$Ɉ`ox fHײ@,k :"~}t.щ=|n}[�E-s~k D0 �0\?98T'<=˒tfVKx�Y?�/koQu �  rAACAݹ@ >�4ܸ#قbġ[Mmㄙܵ?1�0*pRZ< ߅~χzESt8-D!(=ۭCn0aSupOkyڀO7‘ yYslP5?Œ C`D`!V'ߥ/{b޿Q%}/į`N 26_pZ T d J9F`�zn`Ϭ%![�`,;p޴:a\-Wmf @:am%F<E�8j 1b&;^D~JN np/lXͲIK! /Z<&2|Y><gĜ7�KO_G?FW7 %v׮i~|�Aq�{(_ό3?#�;-Yd�lmvw㳋q7F"0'�dI1ǀxo:m8:I�{`M{6C灡9;JOD $1s �ja KJG�oPr<`gϠ!:U�}1 u aSm1j6:m>ÌVNT@GY9*\ �fY ʩ3,{}TN@ Vb߳3Am ϾmI_tK?ǀ$`}=p:pLu0`s$'ZgJCxZC�X:u!AEE<y^֗wq~p&�r_> WOuX䯻s+fq߫:e~ rx�@uǜ?A`lͨ,\�̂@ڐ,U"p"�Kp�z[�5E-C…8簞7ܹVDL�yM Mn�`R%'.~0S?(HP3y# ۫t•2J@�,OӞYf1#PNݛap̸,3/CY`{^y t|@lhkMOВ,78$ !1{Sgt@iJ qfgٿf � `rG@O`Pv% sm,?+^;2t )MNy`5@N͌ȥダ^/ox r.�VntmY?<:0CvO0zR%'yӢȷ�flgsۤqGά x@zuVx쟝yt6ڗ:mZ҃n?c%͉FlԶRVs쉄~h˓u.ro;޽B�gAspGꟂ<[ ^^BD @{ >Qtg�fYZYV>J\3D#`>̼&7`N ٌF%b/叁@[p7''5}Lkg�f�+A@Dd#Lݛ?M �\a>`-ケF_K=hj.�Rȹs%K( (pEJD hC) <(4+.� ƏK+loD<JN$UϷ-{{Rns1�>G}{3tJN�}Lq{h"ыbjP 3AZD�<n\xW}{O%czLg'{͏P=nn~Kϩ !'+%�>MZ׾[VX ~vq$1x$TN qyzz�'iB~X#h4CxH=8@4|ȷ�ڞOOt.\9W70L\"0s6e0{m"$' im??ݻ}�떠4f²ލ @"8,o!4"iO__7#<V؇8*e˗/7otZ!H<nO/BҥK>*rO>/pbyyDA`{8;}ASO=oyA�ޛ8 /v! U"<1;ɾCIN6>6 X̓�!Oկ~ݮmbCZD,CFD`\k=;� yZW3wT+WtoFҲ6//v?|ov'j& @"$93<3Q^nٟYOO8ekkL B=sݯzd:C0vnw ?Ҟ$@"<)`\q~ꧺSNI??8&�ϷOL.HD x{wiّ.�#:ӧӞ$@", ^;>ӹܭ�BgΜ~!$(U"$@"(JdCo]σПph}n�AW Ha޾_~$@"prvo޼9@�[gϞ|�JD HNu}Ν{X<LXEP,\zuyLD HxP3s af*HD X<VWWw%xgksssu9ND HA@_b΃0@"$@"Xbf?s$@"$0z&HD H\>s,B:HD HfE@ PҊ=k$@"$�W�to}x1ND HYwS 51K$@"$x?'疧3�\+HD HD _�m/ @"$@"H <�=zD HD 8nlbW~WB SOD HcGG?c92SOD HE`W~ F}?{Hs"$@",<fL�@=}oI# @"$@"W8: 5m짂z"$@",:߿4[oo D HD F?}�x|AmIKD HE@?8� _5 Oe͕PLz"$@"0?k1z,s�@wy//+'U"$@" b^3֡g7=o FN=HD H$?Ӊ~3z| &|QCJ<@"$@"*I7ou/i&D HD#/?ђ3k4� F&[x D HD ?$Ќ9d 0//}U/Eu=_iiHD HG�RzEb}>@?"׵*U󔞳zR%@"$#zVϷ|&@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$@"$Ry<[����IENDB`ic05��ARGB��ɛ���� �Ձ�ׁ؁ہ܁& '23��܁__6C@�8 ~~ de~~zz eNMdzzvv vvrr 8,$&*:rrnn JHnnkkG%&Hkkggi hggcciYXjłcc__= ?__[[ [[WW/ /WWSSSSPPPPLL<<LLOHO\OHNvKDKu��@'-36:@EIOSX\bekotz~�]X[_adhjnqtvz}'(#&''&##�%0�%##�.7�.##�<><$##/EEDDEE/##BLL=>LLB##�+S.-S�*## BZZO##NZZA#~~# %\aa:%%9aa]%#~~zz# <hhb%ts$ahh<#zzvv# ]ooI##Joo\#vvrr# 0vvu+>@,uvv1#rrnn# V}}^##^}}V#nnkk#'}9##:~'#kkgg#Jw##zy##vI#ggcc#yM##TS##Ny#cc__#9'##./##&9#__[[#le##el#[[WW#jrr2#gf#2rrj#WWSS#KK#SSPP #//# PPLL>>LLOHO\OHNvKDKu���F<;E()+++�%�%++��++**++++  ++�$""�$++  ++ +~~+ *--*+~~zz+ **+zzvv+ ++ +vvrr+ $&MP'$+rrnn+ +++nnkk+)!++!)+kkgg+ ++++ +ggcc+ ��++~++�� +cc__ +#��*++>?++*��#+ __[[ +��+ρ+��+ [[WW +&++&+ WWSS!+po+!SSPP"+AA+"PPLL>>LLOHO\OHNvKDKu�ic10�jPNG  ��� IHDR���������+���sRGB���@�IDATxk5u7y~#)dEɦDr ;MڮA~r@ I _b7hڍsA+l5kKPDJ(R|_|/ϭ{3{9̜^kp̙SD@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D@D`UV5&¿Z\zxzRWӃks`n˳.s;Cei!'GYeZXa4ʡMPI9ր@6 kKF 9 6ypḏ6y,SfQ41f敚,T_uzZ:O/}5t-�T,j7q|wNO(o+_nk= .'u'*:gymT}t}N[k5V8>z.=oҘWYkuxoZݶ 㼇 /ІYXFjEcM ;%1é}u1VVU`.'nJ{NGksr֥GUXXk$ĜӯOq` SOMSo5]f O??I(N?9 VuCNLI5)A{]>O}ꬢ#>}Fݦ[ZYIGG\jsrrvL٘9]N1V~UsSkXd-'nZݶ 㼇 /׆YXFjEcM ;%1é}u1VVU`.'nJ[]gα93qFgct9yX 4VMa+jq{B+W~x=NW[X?T|d?Yc@ KbC@s>yR S3sJN-@9]NŢnJp:\|;< ң_إ> (q DoNU{_ ԊƚvJ}t}dIIgNeY:t9yػ-8Vi^V輱u3:gt6fNw鯫@cYxɻiV>5|9&dG?}R8;[ȘE^Z7?ȓjڔqߜc%V2VvjYr.}u UGG\ɰlX.=o 57Fcؗ0$zujsh2 m%eV4԰S'OHr>s/*1oJB獭Xљ81scN]ְ[N__Hcm~NU۱l9>R<tt:[3hE^Z7?ȓjڔqߜc%V2VvjYr.}u UGG\ɰlX.=o 57Fcؗ0$zujsh2 m%eV4԰S'OHr>s/*1oJB獭Xљ81scN]ְ[N__Hcmy`kj7dg4NYRc]C.'vawfNj}xw_Sw?O+3߉׿x˓`'c5O~L-0W>Zh)/oD@D@D@D@D@D@$\񻎏OoS]KW[�wO'֒: ץv<7jmf �Gޓۼ5%W״E@D@D@D@F$^OacV.�`ӓ?3߳R\D@D@D@D@D@D`wT|&=o[�;'~Otd'G@_ظ]E@D@D@D@6LJx [7?<9!�>" " " " "0/?{]k)v[�ڇ?+}S+N$nzF/Y�/N'P/( ?-\sKY�x}][_4 m m^v�.4?[�x-;EX{_ќ-X�88Pl ,*" "7{w&5urX6foJzK3m!]3\Pg )cӯOا_'<Vi%ceULE\ ,S2V)*+UeO'~eD}ZMZuNкK~ţO|-jnj -'zhbn[#yIc0KHhaq?\~3ʪ ]-8Vi^V8pc죿59V99;gt&l̜.'_Wƪ5,wW7Xn[qt_oŝe#`ޅ?srzڞKZ]'!kNcX|`N\Fj|>Jkjwε?π lNiD/8V1Hcm(_<nXc�?YdI!,e]'ak ~){hAzsaVC\.8{�hzXxx"繦kVX2OYG[ݮMk;'uףuѯVx(tMsa >湷W4e|'O;.&_y5 ՀfBcDTCS$>>}8d~3dYEG}4/m݆_'~ϵܶzudh]֥Gc'57㖓S=nh1V‘wNkD-к1МDTԦ+񴒱S*fNw[pҼܵ>>Ś1~=Ʋ.=eݮ2VMAT_m0ιWO\D\um�Ov:4hEfĜz͵.ݬ<HL7kna`3ͷdϜ|FX\gsswF::V0H3v+$\shͨnh$[ݶ t i ~!ߘF/�%6f/׮\牰WygWpܬd1q !a{=6vD𙎧Swc4ﭜkTγҵh 0Qrܔt tfZkmEeSa@%ғŅ""}D-\_Nsuf3%H&GקO9+*7]}-4/+񗰳_KlѧդUe˜'֮rr:L9]N1V~UsSkXd-'o.q_1|mh /׆YXFkڎm4t9yE9b~}cXYuV@ro%ʂce>C ;9v.7ˌ?gt"ih@jnjVNJjZt?x#PoƱ 퍽`R|nw@qbc4:q 6[D^si:{qebH]ŘZ o <V+xzyخf̌5]Y}Ak 3vW`vQmUg2WW3t]Е,>.7v�t,jhv0]9<s |1˹9bj=uP<l29Y.<PO?2,<a]KWsx0cis⾴ {_ ]+>[tCLbk(pjZ# !'oZj 4ɤpg8;=-bF>Fhģ|!כ{f;K`8t-_5Ȱd�7uf0lg0ܥ[ެLa`L׀c}01�.''.]>fQ߇aW %DkPѧOu�ÚZ#[9yW|}u#UݥKLUcInC{Sg~�;~Aq}C N3-G-ᙇX P<ώ!R-9 pzF3&Ҫ^!uyXu:t7n+r<,+s鵰u u.gu0#'X]F, 6zه$[*Sq.�{.vqbtC;3:FF<a <<2A!eٺk baZ2p L3< uYkA[(טS)u6rW"ylεhThVGȑG<[WcU-xܔ\!Qã+.] rgHS UoIQ\;3ծkAe}9Z !sϬ v!L=2,2C|[fPkbhx :.g+sWhEװsŽAFk?~^0sX08gJ?3ggds<s5Fh׼˨/j#C�2.�WZ泘kxZмÂvAWät7xe9D6eΫe<JТy-a%͹0Cϗ8z3eTr9r#ͷO(<i^r76+~ڕn<s?19LVgye&nnm#Kۮ յŰl:V@:-in6w(.-c8gjء]ga^KniIZ^YqgZ:}&>d6m݇u v~-E],8f0]^vb.6u9eKgy-= .:Üuzt͐lsm3it тj05)Aǀ3ƾP$Ҧy596eΫ9'8<l^TY9ugN sݢyU3D ZM]eR]M<veͳmr`C`LM&=̚ϫ6ؘk8\&Wmos�|ǵq;0IU}I}ևv༚1-}boΥkʥ 8ZhÏ%tK`utIQL9IM4tHצRkŌrψRc^SۄثYUۘ)89&}.Pdvq_BKb-헅-w^.v?'_n1֚F#?d)>5fx ݦn�%tr/)~ y0ffWQCK !se2Qi݊]: uF[` a3/Qkct9(x=a �k{vʹ7!S>_Ͳڕy̎=^ZΡ[; әeb%Ll}Qb9yW#ݣOI]Ә=j-6v.]:QiY=0 P9GsTìYU`6#:|A@3b\`LsY0k510Pgv·lB hlp,kct0P%W }u}BF| 䌭K3lJQYiWDOej*Ab3?뒋oT~}k6taKD} 늿O#Z_Mlj֯ �;g*#*3WgB,d<Gs7dF|3ԕӡ_נ�H1*xuZ=#ķ &qX1h UXr|i-cyv(\gB,O8m|xCYS:)zعȳ@TsMO|a. 4W|]yȍ9Ol؇\Ny4po79bdz%y Cp:u cGvUK|-9b =<7Xg`q?` -3_1v?`zxn՘®#Ř%hD_.-Sz؁iϼOsx"Npqq3 QseՆX3oo\ t ]zXX\;ptrJr*8t0I Q871P'vOA+-y>Zla ƩG0€blA#F t8gmF31ܪv2aW0gz'!еI^AuN+1An<sqtu t#mqԚFpz.ƑbhuS@ŜhϚ47O~m=8}_o-.\*&W+׬wš as WĊfQNj>{۷O3>nٽ[g[h'8>>=Wwӣ[-fqWw?xٿ /m9|_}ONN "8^Ou~Qit'pO,LrWÀ]x3D&" " " " " "C"Fdm�pCGGG _^7PGD@D@D@D@D@D@%EO&_/΀7�p�sq$sȷs~~kY?+6m" " " " " " "> "~m]?p/`߷ kLX18O�&˜5%ᎀ.#�>O<е!&_w ,:>>.pw&" " " " " " 888(�?{luE{?EAGӂmE!S?ڦWvΝ֭[򤟋�D@D@D@D@D@D@D`_p|rqڵkťKq7�Q� "x]^4r^77oZҏ,B" " " " " " "4Νׯ<1cX\y<; �| =^U_??Q*" " " " " " Awp!ŀ_ȫG=]�-D" ޽{+b?/5ىl>; j_7f֟_|'8oYv-�|_^j# -7W_\6" " " " " " "xC=T 97W>3} �?w%K/m_ .<0 get�  W_~B)D@D@D@D@D@D@v#<R<cjpƟfuϴ�'':կ3fm" " " " " " " $_x{c A8"@�\A\B.H&H." " " " " " Nƍ?^? y,.�Q|o7c^g'I." " " " " " b�MǃæU�><V!|9B@;>}of,<ѷڬ_s$i>l|H6>^Z<]_ X(3y iwEkϟ{gEVD@D@D@D@D@D@ZܺuP<ŋ?x{h;�6/o߶_o##<ShpON:m�d2=xxK_Rq|_$&" " " " " " "0$'=m,|8k,8B?jT'%(J/" " " " " " 0X0oٮ⁀ܽEW4=>Vo0HS{w<t{`p_x߅ 8y8um" " " " " " " !g|C*.] xfӯ5�/°Cf+w*E@D@D@D@D@D@D`9/=ŁE�>\.ؕMD@D@D@D@D@D@D`5\R|.4ߏn*W%:qL׾VMSE@D@D@D@D@D@D@H9sooOG`Ao@߅_п67xxWR" " " " " " " +"/["ކ̚ �g1"E@D@D@D@D@D@D@VL{jQ. bcjM7O |K_*m" " " " " " " C:{8$mN-�A\)(対ߤ >j7L~^S(q%^J5$=sw;x4�V_v>Q0ur" " " " " " " CxӀ.! �ve-R)" " " " " " "foo.s=րo�o狛7oZqF}ȣ<9>>|vk@zOڼy [owL#/�pϹ_WUl4G-�<s!> y7tJ "owܱ-�K/T &" " " " " " "y�)�-?Pp@`nttdE�?HkV@azL_v.|7�m" " " " " " " O x/u޽{ŭ[6@qݻ$qg}�zW?&" " " " " " [B_/{b2<m@?%{WH m)> -"3O|?x MQS` �<h>o'�p56o8x�ݾ}{qh" " " " " " "bmoN֬D@D@D@D@D@D@D@;wj@l/,�\�w�.M$D@D@D@D@D@D@D@�sSD@D@D@D@D@D@D@ݻWLEBD@D@D@D@D@D@D` i^?h^��lD@D@D@D@D@D@Dx_8==-%pxxXLoմD@D@D@D@D@D@D `? 'ǚ�" " " " " " " t.eQD@D@D@D@D@D` <�ܻwxW7|x뭷۷o|"qA?8pHɤ8w\RܸqxGypFi@{֭[ų>[ 믿>W$wx{[<ŵkvK>_.g" " " " " " *_gG}G?Z<csJZ{W-XU" " " " " " W[>f@w//Ԍ8Y~~gy挞]D@D@D@D@D@Dz^{v@G_X`~ԧ~ t/Njzh@J?8׾V9yLD@D@D@D@D@$p7~7 j#98ϟ&" " " " " "1WfW�f0WR|ӟaW|7~xwwB~5 M-%ŋ˗/W^-x-:m>3L1L'KZ�>W^yžr-%׋Gy^ϟ ~w~wo +�=~m{2by-+NDD@~v9{V?[ED@ց�??nI1q~NJ+WeN77y4 ;s$" "ܯޛg_h`}"`NFcO<\?ǻ~JYbƾz`^$^}ʹfۿ׿u%x$#$3}mv<tͳ`4}X{/hz(`@˝;w~ t3<S|s+x6#LL|KV_\16PGD@D`yxeysy?:-�yX|/Bt" " kH MV@ 5e5c09YƋGe:-�$?wm<xk]f҉ _/ϚZjۻx�c߾gKi\u%o̵/}Iw4v� HJo5ofKUu%ݼ񹽗~hxž|]?Wk75DkZ?5λ)W[D@D`0'cnu�vz@}i soO'^\Aҕ#E9eٶzO +׹OS+( hn +Uusr=:`n;r71Z$Xy�"]<nʲeR'z"qyS+T΅Y[浝e'|_~[qsՐ@?�/| 9" " k@`ܯy~oLK c;MvGsͺX?4J۲<6môoV J|?A_z?pnׄ _~9y[ɬ_vBD@D`TLj }eK,-scKy]sycm}憱f[Y[z`0\l#o^o-�`|dߎ;d" " !l9덆MCL6{ʚvvshs7vO*ﴏNYK}_|1z�pܾ};{@DD@֓'}6Z#EJlڤ\;zn[}khMo~J ~F>~o ?(ڿ$cdn޼:c~Fn^\q5|yč彉ee^WMJX) &S?Ge, v_`hrԳO45ܖEˎ@^q[ao:/R|Y�oVq޾�'޽k?ܩJ΀m?=E�ۼu\D@D$4|T{K "6>jiS&{ ڮJ@5(-e�[J%ٻr�@nSe'UD@D@D- gZ�~zc=&KZ[�=m<,d؋Ii d" "IMfX٦vtPVn p]5ZU5yenĬYsJ jh{,]Lί }z飴ٱO.@B b?\ l*n[�8::ZVk�`8>>.xY7\�pV/" FJŦg^tBT]%{GUC2%.~޷,ݞlLƌn8ުb:YY)6V:N $U(Dݙ {xvit+Svu+c [nC֥kڪ-" "?83v\o]ܓIqw=�F47?p8&8SGAl>.amX򌟶)) ROK; (z™`SSM[iqv-N~<g2|cz3ν_ʒٟπj}ks rķWtnRD@D�Ol_`.CLr4}OH>;&@').g$<s,$zO%Y7fcBoݫeY4h]3e\{ZAb嘨Z m;6ӧApR,qR>^ԃ}^`.\�`}+�٣? 8ضȧ#!횞K]tFvxia8-=ex%( cO"JOE'A|lʩy|~ixs,7&D?v>mijv~�C_؇џ8 cPU}*j" " + 0h.R_/hXO! _L(u'd,,$VGFP/o0ۣlrmU2i4qbWD`ykʐ@'e^ru.[].;l�b r:?詳dh@C3F%NMhEJ6#\.K�쥗h C��VYVf\H*kOX>1G2JY2z,Eu>,2MX4UA߈j2ZnR}G2;$ fWR8Q.Xe(>| FqkNr0kwyG@f � A#3" " 6s7e!=4鞯Ҏ6ng'gqҖw�}$~CBrn&3M-vx\V+ mKw=xnFe 7 J-O2�.|^% n^mf7I-*[D@D@z+o=ںnZ�!Qe.2J," "P)Ěڐ1 # a%&-IiŽ"͙S( e)|ܬ +o,]Shc.m\@RL)bM3ػrdӒ}sQd=@n`h[us0(k{1drH[f-8t&+T<U#Z�0\D@D@#ͳf*c*H˼_Uzy 'j( v�KtR*f>e? BƼi2>t\)m螃GB~܃Ѩ,k ,-Ӆ0¿uSoWe5s-6YW]D@D�v떨I@ �cҍɉ?O�G> L\E@@۩2M_ \ڭ6H6& ʖpm͹Śu cy&kݮfYRdb4]+$GC2O)`' +dp@JXhzZ[YCo" " hu,8=J| ?#Øc9GD@֐@Hꁅ+z{R[#]Au<cꐱo\-O?f(gdI_1j,>Θ+*OM)*ڴiv*s.wuYfI=Js#/8џ٠R zY Uڮp��@�IDAT!DFr >t Sdž% !D@D`0ʝ%]e:5ʂJ1ٷÔA ?4ܖ3Ǚ&gI;nn^f[Jvd3kC1oKhX ɾ24�n\$жz?"-4j<s`ϗfLZ��]DDg";IIu�R=E@�|TiXKZZfXʿK'}? @b2jmabv,ӰB[ðl91+V[ݯAs 퐠|T ;fJn`pKetyt=wRI" " %[9s7+#Ȋ�Fm8F%r0ȑ˽,@XOp{n3g4J}vg ;Q..7!䟖.R ?lp\6!mMT9!#T(<ٶYQ_TmX> ~M ؘ>b4P/y�FFlxDޜ>J܋l(�{-mCm <ԅOEu<s2o3 Z uٳ ɟT_YÁ+U^ͦ'se&m)sW6\~0+ޏ{ \<x�LE�qгU2_節�OvX$,x>> >UlQi�HTITH]U)syד4y;탍J` \4`Ro�:L 3yls3ldx:l0>6nNeTHL}ce&"[o,Z7M9d'MLܹyݒ~͎w:a>8@&d6ԥ&Oa{rs}h]D@DN�gIm�f�gZyBB4Μf֙j,wP.lH1ic#ܽmg_o?v�W�Ʊ,>·<&^Zb~jl 0Yq'mgelXo=CƄ.j}cɽy'@WN�~X:O}v{/輌E `6LJ{U5.W)" NΚg]1�0:c\1K` 45pnBl,vH]粐>$]%U}y�pGy�9(qNƼMy/eY3&cj6tl6:\-DT(}e^1F6\ǯ�t-Y #@?hpD~\UO2w=Wls]ll:E@D`7 hMxMx@ICv?n+S}W셓%ź'vvuOܧ=C`s"awwn�,V_u�T8^pg1e83yPE=+BsKW qon Զq٬:ab�+�V><ls!8s =뼓\P167{=-Y&" "0@`uS s<h~Lt<3chW0k$v+>Q E[&v䟉-dy8$.#Ż4"^\�X¤'^z�Ƃ6҆в6m8\h.gsޛnp:m^gw'A;}E�&XWcy >菥X6C<L6s&F%7r2t@CX^E@6@x=<s S1[yK>?+P�P̮Cn٧mas!WI!;=x]�OHu2[�xb z]mDzDhg*etmmݪt36v(aL}z2q{#.�~a}/dz(Г}C?,r/U.0-:n(M1meVroH ēk*:C} a� =i4M,j!scɄY:Od,ml$~v?TARM__6^ŘYz ;5@X=ֺT}h^߄sK۔{tw+4Xg]6x.U Xh G[kAwH%*;8EQo&sA ?m�kʍj6X/Z�XhD@D`4S$o4[UVH /KJ[&&G:2[`]^wAL/5&{{GX8.ί'�y,+A<S&- 6Q]ֽQ8jq묤�/&ř=�#}ï |(1`ć}<Gi ]{n0a-ȹ -F~zQGiкm]Zzryk4y ,r36n[ 졀2AC=§�\ `!(/C~ I u�ژ&w>&+! m 7K2u->R1\lqPfp'6Eؔ= g:8-\C�=sh}U8"|0'xg%Ǣ%Gv 71 T}8D-�,c_62[O,BuQ^ff7 r %Rnߧ}"rs%J?NX�|֗Fm(&6b,=>Vv/m7ad:Sf>`K,dD~d=׶1l`_]wP_s MGX >G*@ #} ΤP6jC AX&2AwX1-�,an?",a` !" kL ZU&ye3@&eϩ(,ܒ.YZK؁^(6M7Oy$p1~71ݯC,ؗmh]ek iٌ6,ȃz=.sr`�a`sp}_r@:Lh', 6�s@j¨,m�%܂Y(o\j&eE8-�&O @b#ʿlϡ<?&h2d x�@޾O{1?`h_ ~cBߍ7@OpX8B�x}q,vxS4H+$[wGJԜ Je셊wϸ�J3>,Lp՞ɉpr�,p',nj>G?ȍ2^gb( A8rznvlZ-cU٢h894OcL?CqO`)^�Ƨ7A^ʶX6LMgp>e$/l }YA7!~Ln!?q޾|;kYp +#!PZ;RY1IRy<imsbbܶf'ڔK.�.Rw~�>G'؇G p&<bRdPg2 dJz( MD@D�H!ϋmr_|NMxErVT!ҡj6NWj|.Wi^wY ˒Sxe~?ZІm&qpzpGG* %б8zS]RTG)ƣ_8ċ{܇B}~؇+kq|ІF#& ?|RqIVrZ.pwÏ<j�FKWp�g:G'D@֟@J#$˼ߐ�WQro 'ȣk8>9�a<$ciw !¨qV5z,X:Xl/&ꚜur1\R='a>g&˺9%}?^Y�G1cP�~?| !]# \�@"q&*" ;KrQ~gQ,eZ�x;= �ӯ#S{$4J|LxU>P+LĸDyHx{)UJOl�#٧[(H 12y];e <0;~scMuܸl#?lo&mfJ? k8x}{�)ܯ\aE;Ї0&~~DanC0(cp!(/kֻy=D�c+" " sis bVEXz{v�>_sxGAϟd~8,|PaI[ԗ%;Eh:ECmf,Z5M"phJ4JgDâ?(cg+�E~c1|,a!{p_?nU=MXqic\ΒC|OQMD@D@K@ �#O?2u~:2G.X̠xuKx*z&|vv �<> g3G|^Bypx ]FU؉-� ["ɠ1lӣȒC*BiӄYMYܢ[o]sjs@#սCI^rБ[̐ 4Cl м 0-_츀N?c{$�.�wp<~SOE ^_zUap &" "=J�& >f?T!h�XLҭʘJfe֮\˒c_-6|]EX\E^q1"^! ca2RJYvvKw&Y Z%Vmt,AU9Pw&?p.Bn8h>"> E��؄�V€?+Gd(FR^gYM]ct8Fl΍6D@D`s[_{<3c-�Dm?1.6.0w9"PEU2u/KTxe>B9N� }y ]GP߳?_FA{u<$/,dzjC;lYۚAT.JSYiF˦ŒR_ڇ2o[ TrRo#s<@;؛w7>~@.)x/  UX>O&ӆt,L}s*KT.[s`!;�oD@ maG'N;Bܓ~<WnGpzx}p8`~q?w?!n@w x UKMN|DŮ6yt./ʘ/iŗP*|>xYLXwrNLc!ڴ�y?8>/; xlX;Yx3]S۴5*E@D`WL:aaA|T;Wv�4miݱv~JCҏ6x?|<~?</$y?wiU8~�w/w�[�}E͍%Dukb6Aec̗Lݢx-ʠ Vsͪ;cX)BhÂ[Tծ3!?b?s\#!)G:3gϒǏ/ : 댁w0ow@}g@|~�˴No.J|i?3UT_X'5ܙϯ3KQs%^s1AD=$L?v~v h_$1 �]CLI(rcnfn6 eV u҆ryRDQrj^I'uP&6vQOށe49'2%�Qr=qC1�`J/=CAǤ6�ll0g?;:X#8$9ئ?m" " "0&-�I} oOH KwQ_L*nG'ǯyͫw/Bvvݟx]Ƃ%琉o ̂biu!@ن̯ZsNV| 5X8ꢘթфk𖋑-1Ԟmc F5p�[T:Y?2/ޢϻENOɤw߁{;@x:#/4EdrF֡<VHA:lP[;z]D@D@& ˿@�r ۼd,_!J弲kmdldYІ<lQ &eLH /I?hp_!XQ B~mz}rβO/SdfĶykU0nק% ';A'_AE!v$CNVa? <{�PE^tG(nG;1 tvw J;6`ǍaƥmY<MD@D@D`lZ�`< AiD&:*v�R)K elPق� _PL$gڨ6QJf:ւ.B?䒥MNvy^>fTHBuTo2֎xbEqG�xqgm1�pLXWQ8W !J VG67vR" " "0-�$W¡_|m" " )KࢀgI&La Jf:Kh Y6m|:�k@_Bw3u] +=V6`L{-E?iϗmg~d='2\A+*M Zs.Tn'# zK& 1 =O8r,icq0_V?u>D@D@<5f{6˓�%" kD HU@fd%L>\1EOL؇ {lBcFg! C:YHЂp6쟜/J-ˤoN?p+\u'&vŶ%y3m>r=( 5Ą՛$S+6?n6tHb,:5[L6mfO~vtY]O=8 ,`ŀc_‰[ <n�aCmSQMsj$mUE@D` |23zTKD,l2l!"O}<%`k4ض'L;g9сojLfXl~ )(8]xf�t8!"�>,* ;.`<p> Z빒F/Q|s}*yz;ew15ԕ/qbC?A}oGY?>/;D=\l03C16YfY,\{V)" M 8tZ<}fQw�õ?꧸T_dh/U%`xdt afy>rf$-tΧCc;ؕfG";DN�.8piـit2ژa[<6U\ц[sb6Kb5ͮXCNɤj#[JQ�gtc>{@r )?.A1؆c #OxQFߡ FJH&o]RD@@#ooAE'O5xX|%?3!l9aMOBDŽ󧄋\L]u+n6Nx 6Y5;ݹf.]vS]s5_8pllr3�ކ=8~\�!tL<�O,GLâ�KpOIiGN}YeO tj`l ~zv{Ph&02:+2QuT+ʳL̊~ks,7$d}s74I$;r3QZ^7hcyYzvuw^Mo0neW>,'حӛ;&7isQ6xcĞWo=,߃Z@ ]G.�?>pX }/TΒH(7)@sd8ڧ~<OD@D` 0/kn<yԇ[C �Lޯ?7V0?ׅzs XT`«\�8߆O̟_ Ʉ#Zom(gEKj<led 6?\\!@'ű4m:G mg&\칋EĻx! ȫğI'�Hr> , GX$21>[2[AZTD@D`ϳu䟿jgmzG �qo1>l�@@4gqযuB=s�Y!"aƤ}(E'~[_ dv2$l.C>hJ Vm۶dNyoiKRd8sO?w2<0|fi?.am<p1!0b S}PcDiiWٷuc" "¹ۖPOxߝ9;;W2H\ݲ:d2r/"  vKe~jx=OD|Bv&>N8< $E:>T\E.E(ϣwتKVQQ yhԩ_̌(Gx\YcǾW"0i; n+f `rZh  ~mpSMD@%᏾z~Z�}C,>S?U_sIX9m˧JKԘ&Sgxʒ|8B%p@2-·_Fy , (д%|uYx w%oLu5tf빸)/犊'N4wz"цznLC? H[Y@�� xt< hÍ%?e\85r,}" "9+!ZY΄sq h`\}ovk!>S6bCﺴcL!J!dI~UgvP&H(-mB'_װ{ /mx<&F76^2X߽? tnٟ68[/o)+Jӆ_ a"ϟ{|K0B9>A|}/D}e� dO'<nqX2@sulP/g`rו UD@D` 0 Vq5 j=G�ǟwkUdD@D3v Hٶ+f~8ggBϫ _g2e$Wd u8 phӵq/.vǂ@V١lzUsn6_d˹5&rm`#KFWnO؂}4;߃mH.aA<uy"= ~w @ƻE!w0;  ��l3\Y)d,WhWrI]D@nE�徼HmT<'7%jm'LVB~=};OL(? 5~ϟW)gW{~˿% #wa= 9xF6X3/ܲm6x r%}@WLljR8ONU^)}uvF{Yycߣ>#m�e L=yL'�"�:�0#ʨbDǛsqw0mnfb\Fiب&" Ngpvv~Z�??@y8_D`?^t &Hrʐ?OV;Lʙs 9XR?d~_^~w\EhEm 'lo3"ՕݡER*5Vv& x\p"œo<fXO]VzҊpГ? db 1}bk{<Npla u(abg00*%@k;~`Js}PTi&TN'wmxs{uG[kUh޼]^e2J)~>+e��$?/y?WK�@&FEԯu V2?).}qӷYgiSMljK [(p(>5]|_2ԕE<գ޶#8=<ة|c &:?B |x e�c|3jIе) m" "S\i�{-IOHzTq4M]D@6�cUK99�&z̗w0:ZD*KdX 6Avw�d?[/e.�~?ȯ@6mn\HBB0^3lPuf;N9&1ƶ)-c:&3猹5ut='8Ȏas�qş_ ̜ Cvc x0y %"bQbgu-m, HX&" "(E#Z{-�ϾP$" "< x$qgklWd($wAҎ@ b=ڄ.�{KH_B^| qhτv憦m KԠb8ۨ@e'Tm"O-7/C+C-V' +f7Kt(gK)0ȟ2[Ɉ*i6\BG8V$ї?s}p}:е<>&CR^T�83@H_F'AEE)cR%*Cp3! 1{!i۷;x ~"*�x%pIfn1 ]9f\цz -GANU3t8&m%wŕ?ټQ{֠ 6gZ >~XXݍ3zI>"WFL p<vx nOG@fV*'<]y?+ٶBe >b8S&`rP�0.?MD@@3M�N.3hgx3Ybd[n-0yb?ڊ73tk_ ܞ;~5 �[{Bː 2電I-*Aɪ$&�9[ؿl&nT0.sNQYcAY[}G%h_&4H9�Dc<z𘱯w>})=8�7xy5;SYTz ť5Aw�ſ<:˱Ͻ%:rt-$ 2س|˓2Y?{ĝW[!,rØAH@–Fw*Wu)sԗzVt!JV-cܼQ)U;UqɤS$~[<%>YuKn1ci=19=-W 2^P0<Fvxւ)[,2H+UQ3v7j9�̺ gl)D@D`c 3Gj䧾8#}E-_2'D1y%X}[…:{͟[ wGP[pvEx }m帖AXqL -94o*SnN`QLmH}TQ;.0c,/0?r`g�'VgrzYRqo郜zʭ3p>ͺ)&" NobzgZ�ymc콇zݺ=;+k�Sv&RE %ade /#SY38U:fŇD•B?1?3R,3wOɩY8t"V�Խ@t eȠnt^Y4Sߠ7` ؖ@k쳥~F9$}=?!+I@p,OP@> GJU'_G׽-A T$Æ'^Aȷ4n /9V Q;mk�}A W�$o@I@[--PUW ;2c?rhBγvS3< GKq,VKDzCH8_q Qh0f9hsM٭lT/ɐC`٨g9HA;] I }?;Z{�QA�5;O=VHvVw.)A+^m@[w@91 >P̿{=�lnyPj7wԛ7+h X�jʑ7ZmȐp 'eYOg^4a>6V\/ߨVhi9sLLKú]rM~6^9iI<N OE<x�~ p/N?th,s � m_+0)BϿuj ?\~=Ͻ�Dž ~8 Y_7n@o Y`,.n%okldG4Kd *t~u_ PXvPTK0W2NZ+`e!W˾k:*l�^Hk٧\+s%{?l?J8v|�ğ>.5JW^ma}�0Xk0e|촭:�}ӣu^P[-[X`v]ptZ^S?3r 5;o$fqDtErJ ?87*H ^BDFmuR2|I)guO4:Zl<\4KNCA!S>l$Eyэd4$�}ş�̾s$2:uDa8*2I`hdV.ӲbE *@RS[-],8Hb봹:�#|p)uqխ-h lf5z*O.ph3ixP#g8d #SV7z'�}s*;mT(x'©CJ Ou32F,rTl|C\E_[Sw،PFlc cc1z"ر%>I f J+SV�+h<�"D �*D�%;f(PW?�;zw(me} /k^Zk[[2ud=K([ۼm8q^y%ű_cg5¡?=*^# Cv&7οxSѐ#QvZ5XPhckp?v.'S7~v$Xy #G^\4z'�"7hplN)km n>nuP*_^aS?><m>[[-('c^_�}4.38#Gng_N"T>4/=%/iSO)'e܎�^A*ۂMI&iݢd@\ךvl02UIۙ1Yvu_�yW_P^T1Nk©s�82@ʀI@*Ru =+� 1' p#h ~ xx C{:�CiDpcy��_wj /,;P8/c_h!Wg59xfsbe^ ;t1h_U�?#μ}EFɅö\$(njnZ+W϶(xl_ѐY֕Dɪ1Ov/?ྗ�Dt,Jp�ԉ}w�g |Ł Pqɡ��&!P< mK zXwk!x::�QSo�.ѱmm-,1^ Ϙ|b}8 -~�^/Xt�3_ܶ?yj#j�^9qca*->iSƄ9SrIXYkﴍq]iqL#Z8+)]KZ.;NCUgαJC�$�h�+M_HEp��~#і"'nqa۷uj 4 2v�Լ(Z7on讠-x ˅mh.GI򬿘˹ݳ bq h 8o%V0>3,KtU iMIE,(PB\P0>tD]7 VvdZ 20rEsOǧB k(8~hz6Ar<& Yw EJ!o1TD:k /1 ލg�<!tm@[`c DzsK'gN ;�pk gU}U�/9+�clv%<J2D)`ljGQz,&z2OalHe+ʤqf!1HA-Rzɗz8!.,+Ek \K6 �'eK޽2t@3% GE~ͱ tj mOZ�?i.h ^nGӳޡ Dl8=!kX4�%sΌ?Nsnx 8&w>'//b@짻}dcM6ID',e`p<k'߷u O,{ڧHæy׶]FtN^ ˼V9;:~'J?.q7>w D'ѧ<Vܨc,pŃVsέQ8䕊^xm@[-}]2Mo mҤlXp��@�IDAT: K7mr0@Oi{'@�K#X YsD>%Uag}iwn$hu)'l�R@d2W:uQE: (4Ktїo*cIhQ˶P;vvph m7-*ݺ|&6ݎhO[-p`"5hLrt84!c_уQG)%<# 1"̎_`V/KU}bAY&tyAF)ԅP㲙"ىT/v`Q*,PǠn 6lNpKY`ˤZ?^wpc ~,EZ/%WKiqy�/ѷILIQ9gf{-M7(Аh o翿'ُ�1傽YE/қY` s,}$'u8�cĿ '8kvrU:-,Qt<+x].ձc'U0N׵-H'׻8LDK =%CXЬ@N1KqSwV&A.4|T^c). E$E}�=RF�I =e!:UrV)}ѿ̳6ď JY䲡mW)\f mgMlc�Wez󊻂@[-bD τ vp83 -,l v5Ϛyȹ=nQhroܨ,fP_mviD&F7iJLZjf}nl� N6S+蟻,0}d �W঎d" NulEHQi@9YhrʅG8*͔Q'#KاzuO|QT^S[-xѱӖ�E7jz;U}z[[-x T8 'EÑac 5/G ДŌ>|]E#@U@/﷬)膆#_+�pZ |~$J|^hygH pvM !6 @){0}KZԾD,m~F\i:|,|3?usV�p)ǟvNz'T5  µh$¹:N97yMሒxP-h <c hLgߠi� zFF3S\չ,yc@[-"cx�줋ŧҼ@苗塐񑗨SUw! %}8kgEmh^85PLpȢŷ$B C@R l"XI*$W e4wX#e}P2QVU4ԱDg;*(kg _v. ^Jx8 8`:}.B�jT@H~dءZ�S[-x0{Q=ʽym�և nkt`{ܺh 8Lqi-'.qf&HyB^p8~D@4~xB&(mg_j�V\ ?U Qֿm~BoP:_س"\\B~<}h0qKt!aLv"-Nm@[Z@7 v& iy�6?PT=/ԛ+h khQcYۈ Y_Jv`$1#+�B/|$уcOā:._;u$k;A`f >}|./'JKuؘ/س<*@ߍ@3?ǡWV-g_EYN<:o[-x5=\[{�GG}5׭l շmhD[.ޖ e!H fO@";XSOL (q�R ]"r0h9x 숬 7:D8JU1n>uqg%cG_<pӫJ2y H--h X+�1`봭:� dDpJSsک-h 0 (&dqƮRÝi E{cgʰA糖X',?|,9f=5z!͟YFkhY\;Tl6/==>uXLzı:}G>UNt=C}B2^ulXᣛd8sNީ-h < h @cC߭%:YVg0Y7 mK]rه!^x9Eׇӆ#Np̃Kﯟ[ Om>SN�*T#NȐ]> e/rtշ_A'a5CU�BNs9?wu%a^YoH䪾Z�?V D;9 �m>D)Z;e:ma3;m{垪LoBmCYvA@],4p守fGircF?|b~  ;WU䧇Go-/C�VilNܝ_C6x/a&MNE,Go}*:lncF4i*$;URZ*�nqϥvDh'՛/_{�� PeK>�ergwrݴ(YIJh jV3=zm}:�̺q-?n%T|޺ -h ֗f~ 0I"?C^|s~pc~XN :)]w ];*<R̞J|$gx$`^Cf�$9"W=H÷-cBf!MH)jt!܍GqYIv*oݏ�aЏՐSs8<F}ظꛢ`e;8ȝ愬m<ɝma4NZ�7n. �eWm/Y`} \2JkgEq!AC\�`V?b|ӯ 09sJ>j�tP4o5PD"#E$yE}E$z5ٴeە9} eñx壆$</z!DiY|Y͡}sU|< J�V_w)+ q?: W(@v>*/9A$oFn c�Wߢ]�0rQw([߶@[-, L7;ۏ°Cg(�̖~`yAWpcF G)e#δ:s n ֎-KK|pfo Pp)T3xm}v۱de ؓ'鳼%bG_`fOk"V(0@w_&:H<G^rِhCt av(_ XxNXv@[--sno[�Vݩ-h � ¹&#i|g2fhG"a/3_Scz2~?OUQ唍B8Cԍc4'563{J=Ц2Y:).),6_%Q>3DR] K$KΗ�('^�19Yϱwby>@V6h(y9Y2&G0-URvuj m:�km0Unm--8^r,4l's(9f9w0@ΒiQep ?o/DϤrC9[m]8i8Vukwf i&.0eʕ)b"OX^r 8 HJpOL۔l4*Ŏa*c7gUʹ7?k�/V! D(0& YgȉGA$y)^h<iY@[-h L{kUw-xuza"˱pgn<p{pA8~3倬$Ni9͌ fJfY9`yRVDVYvhX`4 !c&~1`P_~SBUP~1%bο>@bIƹB{nsn3Ij)ѐ5=E$-`[--/#|Bu+{@[-1FHT @~ M9N<~'Ph>=A�`58< ?uiC9uPL�L$%'ژ!PX:?ٍ)Q+reIG푦?U:U҉0Td%}oVz |]#^ /.i`:Tx px@A~J)p~:m> ߷Pg=tAmm(/R69gV(/Q'<6GLC!<58K�:MHQצL-@xOpaQ0ɸ= Y¶jtu `l@Aएc\|WKZ&/>'qE'rv(_L:�we%\PxZ>3 8x;o  V6@?b-/؏PuWh E5NT6J̲"6u ?x@}̶i;F7y9ZLN{ FHǹ 8�@ٴ(m/Xl*C^Gs*:: 6H<A(�/+�cCv)7 ?: Z 8D#(0e"V!ISk?- 3/zm@[I-0[P'm_y�>ƾbsJE}ܭ-x *5:̄t Kda)ލ(̳*J8|=b$ |vR/rpƋӄNiq`"fW9U0X9 sQ6tMYM.fau($|BPv|vPyGw8Oy汩6A<5$fx)@ACbo[-x.\:mj�lj޸~MA<oVomZ�g qAn0~~9o9(h8.<xH{"r.g{BVS͕_)pyx拸KC]h\ݒMWG6@:5Eº, \>ѫkmZNR=J.gɯ^؀7|Q'̗{S9 _':mgeW' 8U.�v ͺ%^9ѫkomh wu9tY\27 3�5e'fn,MT](g9'^[?_ HP83d{%_: Vْ-*U})4GE3}G\?uO |Q~U�Re_S*>ApT@@,9t2D|7ȴ6�`DPvU*;o OoU6zv-�֟Y� -xYM6Ƒ�2p?fi#\?4C%ʋGY|.J�sm�er�ڔxh:QݚMv(e*WttAw\#+uL'p/(4=W%SYBq ?C� y_:t8�x4 g0qSoېy_~i@[-$PśN(g�ei�K7 11�ھmV m@ Q|\A)9f}xs O_*>yP,f  |;#XxNE,`\8Xc?[h+/56wlvXVj]lʕ9}ZWuTG$V>ӯM=}dYr. \+�;+[8o'e @7%6h ÅWVQ:=g_>^W>š:m;,0I]?}IO]$TƸ~phx~^ W_iC,䕌w٪pR [#T95ÒuS]g*CwH^2~>h^_�pO[R?-x͠,$Z6 *-h <# 0F1~yp[3nJ�EG s]7շmﰀ/{LN b>E@k&~frdx KUHOr'y/ ~/%N<3m\Z F-q2SKYѿ)3ii,Pړ?e۵xu[ ,{ 8b VěŗP,;U! X!f!X tPJQ�HF|#px�N@#mZ@cǨ -k�懘fwiswmwZ`.A@9qa'Aqs|C+߰~x֟G gXv*{"]q S2JG�N X+^m${:iwss TY3³A<->F31~oXXq);|^*8#+�ij% |�M<?9*~ ɃSs�8; S[-xfĀb3k՜�l}<GՍA=nomh o%v�jq,Q1]y ȹ fA�ӢgEeOyI_R'�T)Lv8.08 *k=??"{f=OM';ӀIs3As4OВߊqD<x/5� `1<>OK0< }(Wm$Pr՗űLk 4-/zm@[,q+[;�6:�1P �DK& m;Qśs R8gSxA. }ViqY�bIXL_Z5 #?T;dP7 )ɳS½-R<0X uAIsF#j[uLXÑV>jU.3K+?+ oGXN4|s��|0^ξ |E@ 5x+;P@ݴDprRH-xm@dq@�t7.__kl kr/o+ lܛ"{Ɵp)ǹ)DD{7?OeQ[GnIXa =yLy6eKh*8x;cCbAҌEKd3^Ad]^P)I>V^6?G~ xG%lW?|s>A;?^J�`ʂC# PCJO�ro0ҿm@[yYq[wҸ'TwI@[-m /ק<tI cr'pHqRXOn\?T34~fql �3 l?3)b?*s&W쿪r2&He\.sWbQؕo-}s>T+T`(e69pҟ F}VOu9+Qh5nN'\lhT˳Z 8TVśv 2'|L^m OkL ~6@�65o(~y}a~@[-j\I#!p?\p1ˏsJy8Иc�3B?^S/ �lj�VXdtINPRFFY؁�,Ӣ,9~S75i,0qUkԁɩ`􉤙< .f:YDGbVy?k@ج 8W?$/Q 翪HBP˧2yw�:,("1 #c�?m3@OzP:�(z>J]I[-XY`= noAh'EC`8j�f# ʀqR‘�F0w:'Eo;L։7s i?6%wiDXʠ/V<$Đp*z?Ǡpc!s&|8h3N9o)7yBNSުwr?h')?s5�.~>OIG-J @U6g�v$6 8E(S4y-?m@[-[[พ;6h HO)]"yrG4p_p^q1% R~, �;MyRNPWGpK&ոDpl\&نMrx*Pe,J,?G�cAȡ23c>(o#~+J*Xz'VQs#Ep~p@^~yvm:\Sj>p]3 5CNm@[Z|yw-h i�~+Q ƿi"7.ĎЙ&!'|+:A3ी@ PS%ڨw[YR +ߡKxKfDܺ,NO`<.uL{>fmtU|:VIyFѬ*h Ŕ"W4�ϤVM oݎ?jGA\aU@S%4)"0r m@?ǙNm@[X..<T /A`(B!o\�8^"#ptn4kM&BS%$ڀ /riE,"-9e~x'lT ,##P|dױEqO_d=HUNfcO V qo@oqtSNYh\(t'Sd 0g!pyi m�[x}͑޿Ԅ+x@[-@9=(} C8!ބ\c @/CB"?04xUfGt>]+<) -ܠps\נ%+JֻX2sDH<,p1<GB wl=Jb9p-�BXz_]XP~+KDA=^4 t>)' r Evl cƽ3k|�l}|e=i2mYlNpfHɋ4P9WqiFgSCso=G>v?AE&ZmTE-O-L*Y٤%kWO]7~!Scۡ}p�r ѫ h3&$z^Ts9Rx}# /B6i,9AJ hfFtE ڳ˝hrg_BS[-x2 d/O֊WQq�6>̾rWg`@[-XsDEǼ$y=\�ТDZPtd(O�7Ne̥їz Hvmw_h y;!DLUSOUU'@C rj߭cBUn͇>Y $�p)5>}.ͥn.:B+\xqx# s�x撅Ct8d!o[-9()#JǢ-;�quѯU�غ-x;_T.'DI� ��{6_a Wu^x%g@Fsk|@+8E'K{_h�mDmccN̛e .ْ+|[`}| HFj|̛i,2]«ŹP89g9 ~/# vKd8�4猐׎%� @[-`i>cЁڣ6�Vw?p⮤S[-xD GNL%P6'"rQQ<@R�r8?/C@/"< މA 4R]xH-r|eu> X`>cWZhE+~K)WK]'1sޘg@98(Ǭ8XDӎe=@>|mȠ@[-][jj{hcr(�mv߶@[i- ߀p`<]|A^.p'(a 'eNќPpV {-FS7q.4Ord+ /θ3˗ Z%[‘,0}0-^ڋ/dɋ7hgYa8|B0Kot.�BƬ>?Vξʡ3³'L[8b=hѾ2s#;m'g"T:vl kj�j{ܝ+5-x ]o I$f^\X,w)iJC89dg <$1pCNOgN}|c%%m_rF7rUSfW \%ѧ5wZ>P"Թ$ �`6gB% % oO@[-xd 0bj<A~u� V ~֢cw~gZu[Y [8B-|0?/ꓢ#8;@#D;MCG 3d5Nh=j<Jy0r 6eu,TAu/2@ӝeg7]Ňwm؅~auk=DMep̯էOiSi@`?! g_ `<%%^%K�p9Dr BɌhB"m'�6n2*m=TJO�6.rYRظ eyʻ@[[hͩße < =pm3}�\TL{U~IDYgx r3|[2tjrUxwzZ ul;sklo2hX g){+oD#Hg˹ �%O<<@�(8P~|o*ù <?0X*yߋy[-9U`勤MͯUk�>i(Mն@[-CX1)d{8c1 rc?}ǿ�rz؟59UwzGK? %'( V ITL@2Kr3\8yXM ^W2 t|"K?։r,p!]z,@3�F.VT0�::p4NL&pDފhv:mdz";i[ t�`[PnmZ`\S]d Ǖ_~{S 8¿NW+�T'wSD`1K}#,T;nB'lgNqHJQåH< u||JƋ6.ςbY†[ yRA[9'x�4�|V `~`J=Kհ -6(Nm@[ , 4@�DMKuŭ-xX_B ?a8Z9̸Dyy� 輸{4 N@8+0B*?RQpy<�džbX?8.d3ˑ?' (S| Jf$l֤4п>J<gI?X'}p' &YXW 0ė�hൂ|A)CT,ґCEa/w�.(2ˌ?<P2. $1?.2 mm-cm+z;�]`yEͭ=B]E[-gt`rrwnZWY#nj|pE}YB쿞Q+;z.$[Y^p#bKމWNf<~XUG oW{UIulAZ:KpM #3دXR#%8fEtLTJ<! 桉bB= Щ-h <zz\4\^ww}-XX5p- ‘?4ӗ57¬ r?T < U�ʱLeN_A*A6=aWsrvD6%ga}c?vt3px=*2խ/:L8 .p~E>l,Qaz$t8Js|g@BEIˠE)bCƋy[-x{�/ umX;z\~b?9sy!N@�WD N#"9A}F/&[9B'yT`,n*+!gv1C27/MtD*20T,:)[ 84xutrv'E#ō;(�OD6T?r:)NTT}L' 7T\/㥀|6G�o9 ;s]z@2 NݱItЗ90:m@[෷@�t<W)-'bm@[Z`|l\.4;pJE>L E# �Kx 38B/x+O ܉yӉ$8C$М(�2Q?ɟQȡ{&gyn }$[b[ǒcXILN1JEnzZ ΅ӛ#:7$t Ws`%'9Ij9 ;JkQO}n7m@ww�m% m;,P7kP)rĔNr']U4[3y`Xܖ3�L39 _֥ Q1{iUts.m%M8g_2'=3̴OX cjpfN>9`Oy-hNS©*q p E�9>[tx֚) d7XbIiTjaTJ"m fFN[[�[[Xw5}}&tmk@X(DGfo <$|8 Evz9mn+z=O/k8 e֞U!}` Re  $v'Wn: & )IaڃwsTήu 8%?k "М9� "84 dhLQI9tr�!j AKkZ^Hm@[` M*ii�l pZ[--%tg eeAD�rFrr!{u8388?+X8rk~^^}}E+3pɧȣRܘ%Y *O9]ԏɄ+L3Ğs^Jֶ{ gԎ3Ů�9dZ8e|X`a <͛K)ěE] 楀Tk˱Bː.ǧ$'�`Ґ EG@[-<1>|`nc�lcס^ių;Km#Z7yjʁᢋcg=^鷜pw9b yЩCN+i*wGN 0N=|b,{̷R upq"w.xA(p~1{u%dT?>?@sUTT`EDž > +7 TL,r/)'@v\w-Ga�NȈOHX>,EVL%g♎\mX BǟP*V� &Fe_y}}xƶ@[,`$q!8+QivƊF-Fax4 % THp�%|s擜#DJ46 % ~!~nnB:RbIy_y{/6{ilو!(<T$pϕ'"pn=~sڅr/!8g�A�i:"@ hI*C>֪Ud.mY?cЈ>V�c% U7b @[[`]6>ny<.ͧ�@8,A9A?T?^FpA+"�p#F�xBq ,ĠJk|gR5VG}BOOf1*6>tXtV~>s8vQ- \{'8p YV,WB]FQg8!(S pB-olm@[-K*߃Ûxxu++Bnq 7~sջx |Ì/ڡi I;�<P~N�5i�fz>x?�z.rMy]w/nN>Cjh_gh;J~]m>Esv_^ ~P־?p O>�莠@g}7xi$߶@[-0KTk}fF/Kgt8_oVh , CK\Di?cOG^g4[=#o&XH96]XLI6 q2E}}4?G}jmuƙD} Afts6dn<asjU;a<@*BMo|)+ F8@;m,1{ jPǡ*lX�HW0E-h VL˴` <rх9Enq'VLec5�8(*V[>S^�)M0(|Ҭ[ek}-Qt}GQiCоu@L[׷.ws.;$sEW" WzΆ@gi8L`5:E'GzS.^I])DL0rjB-h <1jDu+m�ܶɃSy Nܼ-7.#I]�vW?H��@�IDATxvTLϒp/X'Lq?r?䙼WY|<ڑ6<hM``YvWReW$_[+IL۱�zM{}�|)#'@�'��.F @8 '9S'e>ِ( B mvR}pis t�`s38qݼҮ-x~<&G@@ظ"DɒC+g@@8A q ?sDObUR%G)~'iG(Pg[8e/Zz~'W;[-irsǀj}}2޻ _~N} Dc �_�`�28 ܟ/ D.�8%F%<Zߩ-h <4�@4o]�صcDt#|^]cnjmRi QzEB5㏣@‰la%#�#?f%wN. 3*^S[IljCFlxKA9E 5!Om rOC4O4>9dW䬧]mH5eݦlIIg? >eV.44'+ 3]ؐT~<O}9|E9T_`%_i@`5�)<0s�~T�#Hm/Y;圅 EK֐)@[-+i_Qe@�5ϯ3jO ^Akh ^Ih8\sW@~:GKo6f?z&_�Z/~__Έtj <G_r(8[#rtrP+)p.X'%*A�V j�? KNt  TU�*P-`ZFE-h 'QWtoY�x?{-k wٝvj hҸ~�pOZhAgMC'#_s>¥ 8~8=/er+dq#�3:)ݔ}]޷]UNEDc27XIhX k*,m":!8|DJτwզoW2Rw�WhZs.|}`O&ڡN.U�ѧRѽ_ gP(թ-h lf|Jj^~)mnq9VߨI7-x) 8ޒQp8 `)1 j<4Me~ ~�1Op@Jי} �xэ_�;t91۱)H8'lznQ#cOMI8 m!D>#Wuyl4[ty%0PWdf=̣洭v&ՖXow7 R'Ǯ9;&ZB:8 >2g+[q0ˏXD`UB9Ry }8y) ]"ֿ"ة-h l l 8J}@[5Y[\9@c?r8q�? @ypO 4A{9g�e;¥* (8IfS ^;f52.iUGwo3ݼ ]'a-{HS!#x<Eca~"<ENfemGnw1vVQ(RV4Se 2}Γ^�IgѿvFaSlUr> J�A,z>8..bJ2 E`p Sg@[-xy�;f@[-p| R 3 \a1*�]P4,M Y|mGp@ʟiYfMߊN tS[`DZHy+()7ʳ,,ğ*e܆iIy gE;Q)[<fY?J]ցb\?2UyTN'eTȳ0mp̍Awv#RZ0_xXj88G<z+)ᱛz6(СJB~Sx6 m'0Y`m@[w@�~h : oǍǹ.L~;YG�y;8#,U�,gY̷r^xX?)(4PhƤi$D3YΉȠ@G9 ɲ)r!"LEz.3ٗSLLtRdg=)S٬CwVf15�Svơw߹-OQiոY`%S[Ux�Q B9ǣ7sΜe>򜊯oT󯢼\w~#^ }F+B"H4`DD{%:-Sm@[EX�q1:mWnpqc7/w0^q/ivB�X p=(rĹg%S=\{XJj92I?ȸ])trm;UZ_q *(\y5c0#Oz,}?U:Q9v!^h>.+2SVZsW|2 W#(%<!2+^IA8}n$@}~Cw#MtE2EPv?2=i@[-x�#7,U^&m'p,amË !^sY~?y ~yr2;Mf뵂Z,o kmW#u"ixK^U5^Gz<J|=^թZoz7ښ;C6I/Z<¯F[#`~L98̒֩zV憔\[˯E}/ oqt_^NMH]@:Q ݏpڥw,MEqrv ^ m@[?Y}:�".W,yZ-h Z`}n\r|!+GweLc\"7 <> 1̌<T^+q)Rn 32tP uWʥDGBJ!ffzUzя$J&mIH{ 8`ӼH[BgX mӚ]Ūu| (3el}EY8_|̊Iے,aȤŬsr:atܨWsN v#Cl:1|u洍I?$lĎF@b>W}-k-h | b]_7~Mϡh�6> \pfjo\io ~k JvԸr;E԰cX$d qUTN)Z+fG %̿.|kYG \i;Vy;�}N\ vyH)cQeXV;)y5#u7V;Kcֱh -]wn^]bqF:Ȭ>РvMBqٰqOZ`VL <V|yYg))�\\TCt\W ]ƥ+m� 0e!Q__HFɝH ޮHbmSx{qm][8o!~Dׅ�<йb=]-x5G;9*g)0tq *AR3,j&_p:Xϊ�(R|7?#�Ct/�Ke>76li[\:xw!3r3H\}_4Ym.ȗtsdYӪ :mr[:Mk %>Yn0ѷ.epu~Rsy:Ѿ_$z NZp%~â��<�[ dIʓY[-I Lcn<c/;Ᏽ_DM~ "3{�SCki ^RoݘrÎ8-|nq^38Vr,?gH?3_IuE݈QK"$|MvW>ߕJZxE_)0dt腗|ᕗ]{&s^mk?.Sz6A��Z B'*~޵S38w i/hS;$2Bn_ש-h Pi:mk~`[ż�[շ^\2oݞ/|νrx~rf0` j%;lٵfv"� )X5c~1!\' E,KQSffβEـ |nL6}& 3U( }ծ)3m賎..j5}_}%oGˊ !)ʘ,<w Wjh;O ^c8Kt8|w�.ɺΠѠm*$H�36h \1.}oY t�g-3ܣL.h v\< k\1arD\I�C΀[.T8% &AF])D@TN<A;E\s&UM:{.?Ү=}+ew|Wu6ܥ.]U]:>kޏ9mv#OZ>m<M'{auzRm'@S>i GaU;awj dq%m];,0ү/n0W_QemWe^p/ bt>->l9p.8P8!=:$;�T;&TK?R69I4zЍOɂaFrNЅ\`=?kc [Tc%cz#An~̲pJ5)B6K.uB:&\Klu6gRyW_ =@Eu߅,:�\EAʒ&VpNRsC瑀x5?s.]K9^Az\8H&6'uj ?f&̏k@�d%.}&B:]vj b#\+Tc )܊7]Bpp⽉ ?Dz# �@� SyGKУ�oIUAOVfj1[tp+ L-;]Y m�Φ\Ld!p8EYt@\74ՉL|H_v.yp Cu')er}fB}Y*&*Ci(r9 FEh^wޯM8mǢ]HXr< 0^g<z7?(,P ʛƾ9K^g~" zNCm@[` b;�n4Ywkm�Ъj.MQ_潶֗Ca\F)pq$p}Mb\<f qK �yxׅ/1w�r*D%-b+rߗJ>۷/3mio䤲CMOg1i ǠX\d`t ]~^j^Wvcm|KB '?i@@c+m�}mEx) ( p D R\o܊�2{PIk|H[-csЉ &=:�ܧLݚ�b3z}Eh V1iyԸdDɟ�ܲ{YrDYx_ɹH{K?oUoRc��\6Ǎp!d#J#2f!YpPL (mS-U'ag^ l)eq},*<KVFф8):e&@WN^6Qe)@ȺNd#ƩmJnO�5*<>"2?RιXp@� <цr@p-_ P2@ P.BFrihg.Zm@[{,3 v�ҺMV�rJqݭ-=-K#cK}{Ѯ q pݍ;�3=/B-?׳v5( 0*SɟMx/1/+��#Op ~ʑ0Z~픍(}(̉sy3G-Ya8+FV6,#wOyݕ&:j9E`(?,Wph l싈鷖X)\NZygKe%7x^K}F1}&!wu.֊F[}xOf ? 8с{:h8ҙ{)oݏȊ;;p%1�t?�x$#A%y[-^ 0#iM{ ܏Z@Y?7ٛnӻx4 òrJ>?t;S γi?N�ǂ x@8s=3}|O9>ʣx2 #Dæ!#[e&Q;&~J5\_EWܶ_븫\ݥ P(yd`ޥDtinӬw--u^x?Kw}3_Y2g[ω2DZ?Թp/=+=V3,=^x8 YZ,>!T0"!{MNq%f*A�N;JyeF<'h ~5T5^ɷ[k�[[X%-uYܶc?.um#Y`=Z׏s )ܰpsxF�1�g(LN %8H�A@:\ d3"JHFȢ!0J.@,|g)ЬmU܆Ѯ^Yi*7e\6XK;!hU�_x $fD۲^ӋYT`/īRQYB)z+ "="8/�_8 WzD(zv*XL+?%F�^g"=֕ dͧn2U.B$m65Nm@[,Ώj韰@�~h?_;ۮKV>�nq!/ɸy�Px8%Uf:|Y-�SmoU;9!,Pʫ,qAh.r燭(S$Ly>D>7qB 환$ı*9 ETRV ڿD^Yݘ٭ރj<= BI/=֍6ڰ4c}ioNI Z6Vm?3F%j[j3 []&iql,=";�'cw ށk;Btz�8Aj0`8nm3- /�%F@[-x)�@e>kng[-Znq*A3}on^8y:}Jز1�#1c9b#P_]S <<G],,^Д,R&ϩD&U�nf6jr什fV:LG A&Ų KR.<AfEp!>2.r%LL˘6Nj&(.Sc*$2pm%Khm`۸,:YrxlsCj{"dN#ANqE#P _=ZO'*2TG.L&UΕDXiM bmg`|�KSm[;S݁ 2Us{9 L{8r*v&ȩ:ȩ9ٌ> "I؁(WR&ҐER΂0UuVP΍Ʊ fMvlXbs^opo^ v9/#q`Mc]R)/ q/ާ},Sz;;z2ZgGXzңU(�=.V9 ]ks{g+�9P'brU:9�r<ne)2[V)U S*D*0Uy[-h <# t�1q!}꺎@[w�w9w 18`2vs܉;,c!2#& rHT6;ӶT9_ HVInە%U$bC D$ye ./DX!ːK/T4yse#;UMmidƀ| ?c:viϧ fb*<n֍+<妤3zÆ[k7+d-kY]=FIm[i}Vl0hA6iϷեhR#HHi[eZtKWDUJiR3.6~>azeP TAwvJ̠ˋ6)R6 "d)m~uV~ gq&ϗY a1(,SwЗjP^ ѡF!EL`IԐ?~`q*tt1o?#D'>|f@4EGQ.^O(Hܠ==>h{ }fϱV&�m>Ѹ zjS);.$�0ǰ.k: f+ ƄCFֹӴ'>6*cR48$,Su6|~etCt7ooM Q70\a>I}h ؝�zA_;42 e 4IWpp75MbH5yyeOz">sySz~J;FTE_XX_;CtK 7/r8n @ `iD~;WV%-Z�[f,E&LQTf^Orw0l1T(Si7جxt[2GoCZב@2oZҍa-O]+� <[s_SpäPunپ{Ͳ3r+3-mNun`36hsmóȒ͐k{7s0w{0пӀggk} GNջg*/ &)$ (_{OmHG^F#+_XX<gv'Mb쁋-gN]fSq\W].,,̧ /+#4=%l΍zyqw9,Csr?w_w[ j .h9{wq!!"ȁ/rT>Uk&yimL‘P2N酯L+܈ #$=R3m\:8Weg?lwC>h2vw: Ҍ=䄎 fzJ3Ь4PmJaf#645ɇ렐o Wj_| owNqo~3�͉u8Qґ1X+OMʗ@b8:#'%0}?ؙKg<Ey3Eky`yOoNȀb /z_N3[ௌ\ȽC&-Cx ] @LOtp4^7߿4vK\JnVE5"Nmv##o4 $/LCVV^H7 :%S羮.#} CbӐmhҠ ?M47߀Q�Љ W e=>SO4ѭdmkjp{Y0_\&J|OH#&Q(v{'1* j ڝԹ"ߠb\g=$O}L dRtL' zxB< tVO�)9s"uRX�<Gc@9dRf(Hj5.�׹C|Pw@oPu3#ytej  a"@׉d|ιs5+&.?:!@L�XG'،,Sʹת+׷/۞?Wotnz]<݀@3 }%&Wx] I�:+x&JȆ(vMh!ce:?b|>9z?Eנu7Ri͑ ^KD ]Q�7�p>< {>2 lޓ.c�^i4sJN;$RW|y`y`y`52sd/�8":I^:=<u0bYɰAW!EBͻ�u%0~i;8. Ugx&ҧOЏHGȦ/|Iuw owk7 =.sPWz8G:f'c8ȯOη:w󏼗B&Ly?b#Egzahd'=酓;G/y⿉oR /u0Ih_/UQ2@㔒SL%P^((~\@Uy' sp;P!v8|*2(Zvgi8v1D<MA›.ȇ6[/O#Whkcf z ( ڱ엻ſXb˪¾WXEd3ߛ~rs;hpAۻ5 + .Ǘ: #OQvN]�9QH8(RZ$!gy>(}97 c:|P@чP:–2'Dx_@ W�::3=u呋b/,|ȥp\N<tJ&}ɪ Cws3l޽[ܷY7lCBG`i~>N~:{?9/sCw׹>[ۡm�5}AB&ɢ]ߧTMS:FSy6-+zpk5܉7. vr߻;c'd_L vl(RL2@\g<I+ I6NL3y`M�1̌fV+Ǖ`ӃK6N^79+KskW&sVϻy</#п'7H7(o- ע{b2[P3>:=y?So Mkx$g np5A%9N\f)gRKsg/rߜe&=f=U4Ava8Bl'*mS4]a&\r2^ܱo_C$?- �wl_@ɀLq@Q'=Idn3)~M*c+_X=3I75 p8+~~9e)n:� "%/_sC]mA=h#pZ'sLmUW_~&�L�˻.;Hl?BKT`>Ei!eʵ̸3rrnsVkaiEyz44ԩ vXq&rwht;iV-/ $ߠO{A'�  )Nw{=?0 U<},>ezcTAh#7c?>MA~k{E- B=>Ua }�_c, ްC'jr@GQm%{~OF(tq(8#(k<<<0<)N~}"]9.t'U(>\kؔAߺ~}b<=bNQt%u&F &O�x �P.?wFK _"gC8ԙ} (Ij`I9JSi|Ώt!Sܮ H5x95F!<' ;_B8>�QrV4u&�8?xaG$t v? 842b-M%Qx|Uoc]t 'ӹ'~GlDg|‰�50n;!}H]�*�soG<1x4Nʬ<<<3rز"D9eL&\ZpjsWѱO]ҿ<<y`zhAAw~Q<A8DW`;ХsFues9%|#O\%\_NG�!h*Ca(9\a{�@# RfYi_,1&ha⵸2{А%K:ji R:={K՟�5y-_~@Nˑ AЗهLmlCgZg ]'G@KZ\^d| 8o;jFb_ &nW|x)QJg]-Llyߕ_Tȡ3pdQ7ϊB'Gmp A˞R.EKFJ6<tR S~ i.'=Krx:m76zmg8A?!ݭm~14 +�I�C#w'V{r`:!GV$N)=B* rɤtm1 ks'ad[+F Ir݉ ݁g|g<֘t @dsL {& Ϥ}+PGۚ:<E?,@larɚ0=`.p(Kc谣$FنAhСoC_<w}!thlrr4'Ny}_`u[WrgRemzkQ\9…bCl�U&n?<Wk<9=^ WZXX<C4ѳ0[ ű{!prkwdջ�_^/գ�LP �,x%rxPX̰476E\[�;l& GS]M9ݎGм![|B )#f0g}wo1nмk7MNe,<N#h1a:Pv*${V>*7_f:dS |sFj~s(RʐCrbM! n2{�D v+N' >I>fۖSx&(Rl6~;%[d/xy`y`y`yy`M�|9_~JgWd6``~ v9s_>K_4e> #/x k{ �} k.-0�bѾ8hҐ[m6uӸlW;7iG^a}VXYVJ۲eFpѭ%ݦ��Yo~j�<Mjb7R}eS+�,ϱ GQ74_0f p6x͟!&x4UXpX; o;m-D� z`tHs7F@ \b߫~upM!zHUY'wW1׾A\l-&K~5gzս<<{{GޣfMnDYun-; Ka J 휝�y A?)w4 Ax\ۇ"%ɴ :E&V.rι\f{W6)['vQN]ғDF霂sYqЪblÙ_ûwr)C^D+�w_ ^A.\j>\aɲOJF;T)0*q kiSA=ubб[6c0>ۻ`疅oƴw4rҶ�x!uvyM~M~>DStWf?@$y[}�Dqf+&Ge!_kx۫hU<<MxN�$)s umtF|pR g#ߵYe9|o�R2ZVTugtW/ɲYf JGys~86Ҷy/5s2I"~3ƒ7_v/O�^ |{;]rujusTb=HE|ܲjM�6Vh/7=MC"6F#t|}׽' l<m,o^T`BfFkf}#@~cPW Q9<ah::{I )k!pxD[XXrq ?_ՐkWNؤ/,|8 ٹt?1</o.߻v۩;wNB[%VW#y&�(x%ǹ˃<|F^ز $ N&Cu)9e7gnkT&{=hI AZy0vn0'@g$/up1jsmPRKY2zŁ,G[Wp >J;[H_Qp6�~#76WsYS4'LnC7reGT9imF7oloI:O jMN) F%3/8h;T;D6`К|ZtR5<<=zOt}M~&�Nf^t xoh c6��t}POgD}:`}>  e߾TL!{@?% 4l;u%V*0. .B!o- 'yK酝ve& #mvdj"o=ĢV< oiK1o >]sqn赚~W5rD;#w/ul/ͱҨN2Mmn,#sFީPyׅ$6K]ZT>#7]tpv7~3~&9~06f/a>FmѩxR̜[wdrN;r—m*-'S}&B~d\~^.|ն<x6b$gd| Y%qRXd=o{xqsw/s8gs:zybǛ^ (,mbk}0dŶSmrL^SW&w.eM-[X[xM{Jy7"C_vnɽ-U(7kBYKɯٹ!f!|7ƻRDi>N{D:k>;We[f.wjxvnF}v?O 10Xwo92isgO_0j'KLXzsr`L HxTK0j ǀ6�vhW<<,��@�IDATyG�'<7<߭w|ɩݾx btW?g>K=љkg wn{|xJrr65oGzc+ͻc;L\yJ;"_,\쪪6WVpː"gD)b e*;8d]>۸-h |+K}CX+:j�>/0+�M>!g.A&m 2P6JW>`3|aFjha#ͼ*Tɤ"~ft.P B7*ߵ {w�n𳀮7jE@5)P_(>bK'|CljªLLL;Fc9w.,|o-/p_^˕ ԻXXzkQqE+1[Od.<`8J`_F|',!h^!&bYɺ=)/n꼰7[O67<z?e[fZ|egn@v q%oR`:[oȕ7'~K:HʻK.<%i]^iT<ྌ.7?G)S=v ͗nj~ o}vo;�p'8®��P* �G?zL@0 �;ʁNאHQєvYws;ߍ`Cɝ퀋˲u+],,U=xx?ua䌙V8HMNPf S\8%SC,'nzJМDgĐ1lxQ{ʟuȄ6$y쥲v. 67oL{\%QE2o}Cz[J�<qs /xo!8[^/@J�CX}-bLg7 h⩃|+ڀ:OpM=Юan㓵n {u/}ba# Ҙs-~|5&tHO�n0/\[.y66ZiL)KOv ]X= 'QMOoܚ�8! R%r]N~y) >L60󿯅dJzY{4FsT#X*0Qe/y6x\BndPuVɦ\nÝ%b)e;1R}qк0fk#"FCY8Ade +;U r=rܻoe@YTw}%D2y 5U�N.tj"wTmi�6\ su2 +oxfFivmjc #?ce]\>Ǎk( E%(1:Ȁ#j+ oF|a,l~y`y{vsM�ruO\R<<@7h8-Cz79]gr[ ~7-Bny["2lLLJ5rt^ 6fBas' Խ_@-|EIl/"t45YD.ze&ʢDESjtG>YrWdReHX{d9qPBbdF>ÀN4XRrWJ0C<O*עJKNɫwf^_,U=d\]$pb |; 2Ld�(wo ΒW$A/s{!oؼ S4}\F^)22]Ty6Ͷ>Um.5Sl/s[: %ך;<G A:2�U: ٿGN EK}%+ްD4+S(s`<eěfS\oٙzNd{M͗>eպli}LJxCx͏™9GD1NaZ % f0~ $!r3-,|7 �>{|7. ]�'{}9L9:}*\X<Յs!dae+0tq6)g^�Emy[m4 lg͗9Ы PRmI\x35ڷfcַos5 qY~g}<bՋ|�A=G *nsSiܘ&}dDyMzC|;"ʿe!Gj@Sl[xi͟R:ߒ: ~JLkzg[2V9[8?bsGD.x >sM_;ҟc}t}~<b0M}N h~O6 |jIN޴/,|0 jl ?Y|l9.:(skzZ!8W28ˊ/ix{SM_wl\+xco_20S"+|2[B�wƵ.#- `?X- wa/7;F6G21l˅ )fPelDgu7<˱nyeU^?_ٿ%�y 5(3?1##A& 6rl-+ntalÃ|!v'mמm XJ%.6C]byDN`" / D> ZPT=Ǻ'|A>2aOD|KygsCH+*c+_X<Pg/qq 'Kg5`W׹/,5=Pmys@j+0+yxg"µdG[&7n/^Sƥ?%;�x�=өK| ڠ3?܁E3YLҐ.Eي:۞cȧڄm]CQ6fٍYb.H e_\r]}{AYEx::Q`o(}I"%▲�N<X[J#< X0tfz2WIyNgnry 6' ۡ2?ao$!|i4R m&`Q8:ꡬnN,9 }eٮvI# Spwr;dE]' X�'vpre<<wJ偿j8\ή @ 3PYs24)|I~I!O( ]`_#~ÜG|zSW׵304aS5H6�g}eRgƍ^6cC#6]FH%%m!_ ޭ0\DjyԌ;=1HmV7 Ө `&.-+I K$qu<$UN8G}d3v;ul I.&6ޭik-Àd $p! lWHgS~7|݁C<y~Ra}Ø pV'/g0ͣ�ЬOv<"LhiZ~y`y`y�x2N#'c•Nǣ3s[iy`yrxr +t)Ƀ| L�\ y�.믷&˨Doѻl>�fִ}>2hӀ+�O%EeKh6"umuv7` K-fZxp?ڡ_4Y)wrCQzOgt+{ -kMs" u~DŬS] 7/wd� ݲR :>dW%p)!m*n}f91t=هwBiѶ[L89@&bLg-=4k_#p,OkƤKd" mLQvclݙ*IuvIWZX=:5yM�|_OzHի偿r.p`�g0c,%wj 3@ wC\ 7!w;_޷z)c*+'X:ZC%+T@aVd:E*Sf2̳lMXp&}{tY3=^ks+6@\eu@ԭͤ+k}}9@mI`]em2,$cs)j7Ibo YҐ2O oлNsSoXϻvj}!j85oŚ? _[4T<>ey|,[~o9A\Av#oq/8#�e4"FmrmŬǝ <<<<=&�Wuߟz-os鎅A327@sSixÙ@;-j@=.*$x]=:W<P75eno-rԠA*|8neHwlW`6jA2{h_lmzܔoˤ&=:E -BG|Vr~V;/D_1tJ 2 S�OkK>ǖ;\SJTZ풧>"QIf1<S*;`IQV Fw d�]͘}(eLt>K= S[&cM@>;6W7yM2җ(_U o*r>WU̓U>m0ҞM1><<<<LX�8ҋJ_A>9D{jz )E4'+׃y#|+�7_; K3xML. E;6  (l|O-i=т1ЩdgնFMC ؐ} : 2t-0\�Ľ'�-5 *Sf`tr ,֖͂̀յmWM߱T{LY,"ąz[}#qf 4{C6jKFm==6Q*(yiȔCӼ8otOЅzg 7xG͹<wp>I~8PV=@2E}fn?[E_5%XF3_UTb  #09`dA \w +kᄁ+x; Y ({}mEj7V+ `6-&3d"f=^m"npח@n460;JGz<;\Y`m?ߝq Ow,Gc+xN_JYoԏnuJ�ϥߖA}#QI32o,`V2/HGg-OuKWw'\&4 @35/e$=]eSjD`۴K郐 -C"mЀj -#Bnᔗb'|r>8[7ɋ<LxTs�jr6uwK=$-Y3 D[zۄ<<<<p2p=Xgޓyw(~ҿ<Wރ�]TT=8!5\2X{={n7vUK$mW�2fI[ Lva.0D6`-Pzh3|0 ,=Cy&ldl&,₩Ys 0 1рCjZcDV;y@~dy"B瘼s|[&/B}6\ܑ;$_YJ7dɄCl{xȘZgPwCi =-4)B*,& s]eL J}oyYLkulzೌuY>Fv9/,(=J{oͪ:ì�k\?x 偿7\`f0e( z lΕd\u 7Co 7`th�r{~<'n Qwb4)Zӛ+TjTҠb{*[hOSu' NI.K!>͗A˲}=іXS`+7NԳ`#`PfYw:YF}@é2k KK]moǯ Sdi]zM@qH3mr\[Z c.&~=V3 t wRs-}嚃vqˋ(i{c }X- OByoEF.c%]hDh+_X<>ymڸ&�N\}ٿ\S纼K!y}, ݄k3@޷;r#W} ~91wo~8M]ɧl/Gu4F'䚠]!MI$HX5HM9T>kzJwaEO:|#bי/[KxWd>w~5Db?CB9s<O-3ps"ۏ?Eh9ɑ#YIV@= @ط̿Quf0] Ȏ|?eޔ<<D6;mW-ϛz[ ƀw[�w(7~|ϱa)+Hg!'zˋ'ٯҿЕ�ɥ:?i}MKPMIfmI|C ;B Y0~?k>*mpy|k3O.s*l OepzvFz LE[ Q۬�wS�O�pKgw],F~9&hklax=\v~1rVi7w`jU--Ǫ]l#}s5⫹™ka,'J GuBO�623Oj6+ [)$� ܉*sHrn>0 ӗJ*c*!KOQ_ڗ>wsCnyM'ss{G;DSn1 <;S〶U<Eqg}醱�L.]C1-𧼰DgB!0 9{JOx҂_(gn16y |y`y/7<:| \�'9^qIձOU_�!j�uAl_r*'7?+\}ff;> S^* rgm[i{[rm޹y_G9vwh[F]m6`3]Y~&qc#�%/ˣ�knoXp |Y� =ȭy1|ε/*+{&>_?4?xD12ꀟb^&lO6#')�6:__X=0\_֙G|M�ǹ36Szw=͸w ~\&_xh> 3H@Ou)R`{A>V'~='*bCҴEbd,*,?%k٦rϕiϧڶ^\]q!Pέ{&<n?~'byn^q�s0m6,�+YYxW8}#?<Frj�Wv5 vr9}>4윆$c?Ywٶ}}{|KmSfeo;</8q;�ۇ\QkPg"w`_}~+<E,KTv!aYrGxɉo�.r#ի/偯02Z@Z3Q)mĹ9q2pw@6 T"HHE`Gl;|)oO#]5d(Gs{[jڀS ˛ >o] Or?]~6k3gX,?7} 'YwrE풞8 t'(| 6瓒�}l/Y- ! _F pm6d'mhّ[lm&enJRm|8DA( ?_ (P5%|=∐"5$-,|,`>=C={ *3//ϸڱs~y`y<!qvrJH@Ԫs�rƠyV33ѿ4ODg?A2*8�݉jvITMSfh|lk̼�Υ. Ϝpf/Nu&P3w/8z2Kzofo �|&_0{"ɕ�7)q}^.O7;iKV`&ϛg>.'LfUMlw<exO?E/8Dt)@>HOu#ǻr�ROj9RH! S$UIX3'.Z6rM�\<9HRߺ?5,~l@Xr6�-G\UhL%w ,,xZzQ2d /Oh85u6900s:WPjəϲ3>E_MS x v&vmUmpd9]է&O�g}ߙgc 5G%ij.vUZi '#�=JЛ}~hO$?/ ^+I^!*/$O/p~D_@w15Sv{PUʣI! _z9j^#ܙ& OvWl[W˒oٙ(<@:+\2p}-G/<T9)d9Ѩ Вִ �)m$̮e-,|[zf Yj_5d`ʟgI}@~y%+u9ںj^X8]<AA,#/8K rXugw,>s_x^V'`{r5A` su2'2#K;Jm ZvNsBpT7cmV~з6AR7�Y`.NAVh _q^^TEfG/�n Љv >xuۧk,7W|k{s~KWwL0ʁwϺْ}`CSy\KkVw?evԾao7 l.nl l])7>yTd3GHx˹5�L2].U|�+ǐOW=2 Һ(Ȋ�qxPhW8 \Xv<o~4;Ϫy�xVw>V%p<<y \֠~l)6q-Z^{oQjp]58{ͺ޷DngjxVp$ w-<3ff2W]7i7M>وxSG$pԁ0v{=9A+W%H{@%}Ɖ�zٶ? XuoVm{@|~f<O5<?wIxuv5}JFZ{KA,yy3g|:6]Ѕ? 洯ws' o ģu}gKVSo$$}%'nkN* _�!~a&@�n |˘ٰqi$ˬ<<x +#W: ڪ/wږ?V k3͹ejitM�$K-'-w ΒsR@` ̻qwTw'A"@ܻsA[g(H�`B&id ~剠iʋ8\}TsӦ:VP8us#c<ho tUx 7 Aϱ=<3s/ X'2V;G4Y {DLU{oLec&#rc.P�>9I&,Lz4 ŵIp\DmoK3YJ5V 2{m8BmBEյNH7_Ca[\0Ahȱ} x@ԟ#s |'or2%''9餀96KC?re<Hm~6yߔ<rQ*pO5piY$ 툹oҵ'8 /`py\/787W3OW�'|g]X.?㋿T<uiY Ҁ +Xi7 !^AGZ#8e5U- F%-f|+VVTq52H`v{h`A]K$7d%}FgfMYeC=6#MnNq(<9I2| (sNUOZUݦQm}/Hb`IۄMn)y'ʵmڪ (mi6ؑ^A[\zA<}$ fseo=Vw~SIJJy{ɶW7iS2j$:;|+cM�pjPs®+wumow7oAH (נ[oo�=oI۠�ZWsN� -hچN $| ,[6h=Jw)[7|_ dF<>hٙ6doPm6@~OtDFyJ& &A~% =;ə`H#U0±D)N:';y4E9W-XǓT.mL5ryږ2COHudmrꛑW!w6lwPOfT\;}J"O6qWD7H{O''*xXiJT|1=W� ,*.JWR$*@] }Ak:ޫ_Aa@@/CVxȅ^#ʀ& J1M@GGq�,}G^wcY)Yu$LӄsCv]srdF(Zct1n�@.g46mže&O{[-M|ېcؤ6),۞ 'AVHM6WK)خ26qj6W8;{7^tqno2N(t9+nSgc ig>r袜txMc ˽d[B4h�RRm4}|xmړTIO?R 2ě8\ζo>akXRpw$uZEu�<7~T|(|e(da@x>Vqr?sט/!ٟE'bYJl._XXXx gpR<<<`(̈́(6)pڠ<0bf7;3 yw$S?i3|EO !zJS)o0pF}GF&S:[cUcTT}O, #VbI>~!kn9I3P/[ExM߂cuvTct8)aBzcy ;\i?Ǹwo/wNZ-.Smz$ ?X'T 5H*ݥvi4!zKO]fm'9s( #N(~O}:R.!`Wx̜ 2#/pプZ�^R 7>ꐽ�c e78k.|Sp0g %L'0 +l}C4'�`3mԖ/0rw_ȝ@\pɯ)crd[_ | Q\Xv$ܺ$ZL:=bSU20Rf营g13X7u1 X^ x+fk&|-2Nx'28DinxrU{B0t!r#G!pJtY#�Lh{_#`пDzlU̐f# BlVrv2S@]x o'i6󛡮-e-U3} 9n~2ԯMH,0M]{KKW59`U"%]-IHw �WZX<gBS/ַOc=jX؏SO>~%�qE3x5Ȯq+1wu~b%À7|_g0@  pwّ C4WpLePYT_o6tmMط <淼Cȍz;L g ;{oOD=+([zeם}ish�TDf3"XKwzG?i_A/~F5Qikw-NF$G~27L*F8[oȜޑl|܊Mطٰ?ji=mCI =L/<G\Rsm,yJ!ُT^ȓV81I_2&u)[k_r_xhV�j6FNy/c(;> c0xN4XW^%3Zwmыf9z�#w^}Ko9F7Su csS2cRxf}B)jruLپ6�6p߁r9&7fMK,➎B`TVs o 7<nl(� ��hN*~%ʪ`m+z6KIs�N<N3Hؙ(<|1x%'TFNN@E&t>iiI-*j#Rؼp:R;46~s#CX٦YY;=AQ&]b.%9oul#A*+^2]>^Kbx&?:a|#6cM�xʀz w:?YC{1vQ,xlla5n=-X] 5ɻqD2ҐK-9LM=mKgd� l6CE=Y66mmvn&mW3sXuMdNЈrg�7{y_P-wB}ko6\~lCzԮjaS-�o:$]}ͯQd wbW~CK4(v=䓆XM 1|tr\6T.msa.5Cg(tl\n=gdvmtQ}+~jDv䏆ȳ`#} v_O 6`M�sB8P2YW<:2kywy`z.M9S-rY;r l`%ݽAtp0vI%s ˃3N\<w^ˆ-e\NȚQ0W~-0Lj]-aCNݎffX&eS(#ԲG2l8+s&_9fu~1LP;"[knn 4ituArx)<aM #'|V<@u C(tK1 K�vU88|$m> &7FOBOo"y/&~oA@Ikks[A*gt'n;^7ldM2�iȭW=A<M:]|<YZ=.S?u:ۗ/ {]޶0rf&pΤ�ti]܍ FN 8pNuM~zΘ| @`ffpJ7H)>�}nzfxO2C4Sϥ##R3ܨG @'� MG5p["#� g<-?LT`sJؙ?jG|q۷z�sL5`9ڿn3-n$)$WlN$t}$ =K>'22n;: Mk>y~cO:<-#Y+? =57t^yDP9Uꏜ٤QƾQ' =�.M9&BZo9/e/5&�N~1$�׺p'aU<<p 8ާ`62gO_K7[vȸT]3Vrdga^UC'$hCTlI mfȎMoOk}|4jveMEhû@ x&mE!JO ȑnrW ޳Lc�?p o~8I n+zzy :7m27 m]+&"ätWT d�( �x{�ɉ;yW\R`J>ibG}kl`�;֞䐽Ȥ鴠Vɘ{(c%d]i(l-*i?pb-0 {5 P}Υ1; qJ"[; AǠKHABS <<z 硱O֯GrM�^jT�'/d'6c_X8(5e( 3=VCYePlA;`nΘ * $e'z,#nhgY(ޕ n*1xI4d�e`w"'+pWO ee V}@N.n_1 X):U$ٟxR*O1W rߌϟUXy E&)9С(wuIq!xOK=e>F/}#<Odbs\s.A<ca}:6HER=2+-,|cwx̞DoxM�TOr6,,| mAz~0g?yM+fCRyWUK}zcW+yoԚo{IdžX)L vG&~\{Lzg;gXYL x+r9zI2T^QwPsj ?R"*R'Z'J{HMocfRp ^ZF[jb6@HjDHe {R>3Տ#i  GxGG&r3>íCZS柫 ; sL$qpReryˁʝXĎ/~k_G��@�IDATjU3a_<4MZ3{zjϳSc[X!08&g7m{q771;C3.6h&<&� zɛ 6L�oLsU}K 3muS *{U7�E }{zܟq\t-FEl2`SKiR_ݥ馈])jxW >~Xwy~^Qz Pn~ؐ F$CMf˧o z $j7| YR\A @4t'-yX0&2)oOX?:1sS*9E\偯yYԗpNV,>^꽼1qƕʁJߖ2dñW;o?0#[yEܤדCHW%JZrQ h?;gt^ zogϧ*ym_s> F3 lw]s]dyɿks  j�vի 1XMe}l};ؒI=8'Gy%} ~/WtpjLJ_b6zeQv̴3wĦ[_ѧޑ;{qrK%}=@ rJ K*?Ā&Sf?(wWJW|AȊ*vD[~g`O}�vdP7+�2dGI^/Mp$~ F %H0aK3R}u+"BA֥wV9?#PN�\~*xk^8ָfle"=h&o>7DNYnq݁xH1l4t't5 QxzG+w Πz߹dNK:v59(w^!` [ʥeLLEw SlYho?/ *h[?a[*|PV @&o NnQ>Mr5 He>*)O6f tϬ]#|Y_Eo8N>%~ꪔt2n=*@7o`WR3^N�$gIKVo;%#]bg'lyOr C}|�8+1jѽO\R<<p*ÍwoM]Th�Q`|J<S3f`;_suxm7R.w(.+;PV`Y;As;9_BӻLG`&S`v/16ٮs0Wu-e[ :P>.\moȷzl.I2h.K?|<xr  W. Zm2.j.9 d6g�_aViGjtzE ._\xK?G:km4eKt4e#ZV[D@\HE[M2F=IC>&Vވ7ԅMOV;|S-㮌]( QK&dL* /*�&[ +dUcގ ipb;e_6+|M� yE炘Rҿ<E<0_ _:s-S jw=Ka9m 8qB wM剿[S@];r Z;4<#k1x#v1m|�۽?G4ͮau JiSB|Цr]f{c *raSwP?&9e &0:G֠R{�O!Jds lϱmށ"sn [fD@aeēuhKa#.N�R/S^8gbo$pzu;"ې"hO(,ԲU_[UrIɆ"d:=vƮaLkQ!mh2iYO�HϽ!:cPWx qo7IL\yWNh*^7mnoZiy`y[?rS [x1J'@]ꨤ;[NϸS30)8;'U45�JяjB%$s A}XgY5 ƝUe?ԁzT0s0Drqy=�D@N%oi*+}-SN`_Wc۸KeZWV4zWewKA 9,'0(2@c*!?2 H2W{U=VEorT4: m,liJmLz\㠍{K%|W^ Xv;f'd_ݞpL-ed UQپQflL׿ PBcqwLѝgAkx(�>�u ZGӑd9&<7427vQMIEI;k<<<<I O=xFK}ѩx:̠?z Ӝ7Cc]82 ze~ީc.w=�?pV sۆh( 6[-(bT s"+4(l_Lfzun#ɦ:дo7- TSA/˦o||= 6;ۤ,O# n�eM%?d##y3jӇI -,i6~x#WrNlm>_no?>n~NUSY%-b ̮2b Z纴1uvİQeG�iCjW[S|ùg[_ѡoAnduɭshO0> Mk +GLAc"ny`y`y`yy`M�6-=ݻ tG#jxFnnA?cp 9pΒ딭U�o}[.0eآ w%Snm23,>Q]W }œp l.V;y{:t' Q>*rzj;*6oƄ_A}N{YBKSl_}'{߶ WiËk:-նYr3un3=Li-0>ײ[2کˋpOեM:xB݀9H݈S]&M"i%>\ET9F]q] pKa'-=o>{G|b[Г mÞ2�a$*wL_c >Y:G 8p7 o h;2500w@Nf\ Е͝{`lײ.͟t"7" Nh l~ñm6&Mz6b}}҂ oخC~6u_BvR`'6' ĭgH+ޡ U&G/a-(0˷ql۬' -5>65?{oǍlQJHky[7iι@eXld&bC @f"KY`fp˘ON>~YLI3&ɻofm &63O˘ROY<Z#*D[=\o.020_]4GƏ}ϩ<9B�*3|iη~^k$2Yi>Wl\l_=I5hIZ'ct5r@GHywȑK]KG�+kY /*;WCcKME䡿`@WxmF7oQxҗZS.S_�AKÞiFQh%[Gw;FH9 k?;ƺ6[=\?Vmv<�; \3 CNBN|GY@=8uS2>|np, /n/eŎwhN k�Ve٪1e>(vZ& %/x$-+vtd7v'N͉ZF҆AY.2G,6K#>ks~s|JgCaƃu /e6b8,4aC9} mll<cݎ};R O׷s5{Z[1Z'ao *]1[-�:9ř.S-R^orǴ Spu:b!_@,IdBr$Z킝b~$4Ue,b:CZ&#]N?Oo򟠽žwl7w?f�huzQ@c ѼKo&!CScF8wku HꄡԾ@v7e2Q)~% BB)};I@]13I.hjSZ,C#%N%kU;Aш0I4=A@ rr ZhrlynOL9�tR]116:#ped&5&cI'v:+�v\͖{`{=u0;Wp&N}7_'aKDx{8r~=~K~N_sm],m2}tdGȳ3/y#o<*"u� mƒv.}S%rDL.4نKEV ,0ƒQE c/R> y\g 凉/ˣ H/O<bv<y}T  Ir{sw>;q0x̽lb]"cUZ?&6ߐ;w~} y5:vnR KN?/2 [.<:$uى,$4iʮS + $pW~$e4^~$zrP>hc %?g_{>�7+1c2b:" h G-C_&I5L4{6==N9oΟ{}z!7ZA}䠍l<i=r3q�)95`RGjl,7#|[k4LQ!L7�6qi檊̓/njZa}{@5uLOaiʝewZJ;!qß@/?ٿ;- -|U}72RQF3p27u0%<H3fy-0k+w#wʸoRDB~\_O.0.}M%{/yꁧsOG =hx K_ nZ7~%ٵ\-og-n٦uNcp˟;h.F {{߰v68'X5v3_T0)97)temx{`{+!=R;,fs$W&�Uj_{<pzִU+/_-#`7yɽ3ꇳ;BA`$$ CA8T !`|B[J\'ޱpAYg6V,ZDR:NC?Vc:Xi }cJ&q;@VA5wI/"'7_ҋѴNHuDM 0U W]ZF)#+ǟZz,9.{a15� `$wx X% {" 0vJ Jߛ`m6v"l3HSߨ4&A0;oG#PGOCn[> -V o].wp߯p!{1uMҼl[a0P+8qt(}>=Ux?Ls@?=M �g`p >MPU^DnK7hNr(uW~Cf~SA4ɼk7Lw]\ybɾՕ2�QbPrȧ4Ep+9iթae޶˴7]564?3ۿ|c]UG&A}ipd 'A!l` �g?)gҾ|cA4ǟtGQرxfl[_894 H I%)>N+Ty6ʩô)tIUgԹupSS;gjcƧ7|űw'��=O�d`p z)�Ǟmψ H7r})_:##Oa^�8s7z^�8/bf� ` zgTyq PZGjP S7=Zߒ߰y'':x:1 #);+yk״V5-%OqjwDv͠'�L�] xkKAQ&x=p Рbݡ/9fd` /XC =ui_$�B w)?O?~ S,4ILˬzZǠC-KyǗ7/|TԑOm1_r7,N1vL&0prvX@4/ƆRUf!op{`{k@.6Zص�dOfKVkpbAu'uT}a:N/vI!p[ '0JY>U$B;9՜TfiH RL!gܲ-g4eV;V4yM-#rbwO�VO$'1(M?#À +/ >YgILZ }4{l!Fa- A fgѰi|" '`iG惠*ER|MeZU)reW]|jxyl[m9@1Ӄ#ncsa4>w%N2 is X�_(IVt*;$ACD~{`{>=)E<2JN'oXUI3.xu8Z t08l.L!wP |Z:I+ZgB_&$'c\iվ' B+<׷^I#3�`$挊i�MWIAljE_ʳS`\yT[tP{;u[>  ht]*!O]Y1w|XAݕ6T l,ڔC 1 [/Vau,k<57/9D;KfiXcXxOYT __BB 3թPLJ]~D`n&ƭƅt]ʭZ2C"Oݪ7vk qT9D}MyխI<+*y�FN2Vqc96:ܱ:yXs*aC =w*YIv9NȞ:V5aǾ5| o�ߋUWC7c{`{+@M:+s4f?W<y$C4_2~,M|$2W  lߢ5K̜�;?Ia@jb>)Q72[j6?l^e:@:lXV/ 6>6}Mdy t}Kz?@7@r! e h�Xz 5hGj F hc}FIQSy\z/Zs5-va½_!KWlؾx~.OV@&UPql9bTkP4{{>VQ/IX K7н[|5+Q^9/y *l'3~=X0pQ~q6Ad@c<.^풧f lP&큯sy+n7v:/^0uݸ\r19ݺ>G)צn^,AQ &`o0B@  )%~ {ggl�tpu ̀I>2^r%ALtя%eN+k~L觺W<pK e(>KS[=_[Ljܐ< (3^ _p:+%W& L[N\�kؙHJ!-k@<dž55=A?4sy)2bJiEk7.�ȢW^&6dRc<bOo4Y9i {c5a&i5vo83XF\ +/]#~; 룖qK}`P墀 <X4t8eDēN(l"ηJjc(�_*t^0}Jq:o[gy8dtY1 V*0HDwW_4:Xi{7;Iо[C`nj3rkپHM;!% <Vp 7n~2>USSqݣMp-enť`..х?[+4\ҳW,��N>'a. |oyT͡& ` 9IGzfF�lǺtqsqXc,$Ǵ4o/j]glSqw!뉖+^_={Eo߳b=T iYְtv^2T:-_}J붍zR]F^5m$mRYfJRq}3u�871:X ]޲Of!�%.O:>gQ yǎc*ϭOY6i]Y#2읶HSaʽ�pnsR>FgV=ȥ(fL�qw;W+0*$ :OF+n@�?.?<۔E7]k'6|SwI=mx4LvUUC_Q}+z$ X3?F7ľ;JVE72Nh F/j#j#Jt*yz$|]ShT 7yƌ qHՎeM0e5a^cYۇ�|YvbXE."q.|G/^]և/ɫe馤]K|(`$ G:򟤏9ğ$[M G1T�~1ݏMMiD,lؑ qeG|ug X/Yk/2.V-Hk1'^ߣÀ�O;_(iVCE, S~'==<X9'j^�8{13hN^n`{`{7zLI9|Nl%Ag� !rrKJh'|;ӯ}D&n>7~NO(gj[favd3&?mE:I;M [bCxeSOڂV:v6$ t9s)>ttͷ\l@=E/%9" #1<?zg`W�D�|[Q '#鎵j ART2Bk/$u+@{rqKY plWh&Czm9˱V-X .r՟y fH=YwM0 c#Ei]NyTڿ)U+Nǘ]_Shȵ-4S;bͣ!wt_No9ӎq<裬 p KflcBu3)KYkyw"tC_<t ?Sx:ehOl~W HzxZF^x-'YjT|\ߋ΋]$𩀗)|6;.+�~_wZ۝g'Rd u0^&>EO.CJ붖S9tI)+N]L7"~c.ܠŀ$<.F-<Ny 56PNQHa(,ql: rPaiZ] I0hxڷ f ğr[M@}2:'+b\,H3!/}E:#zm.o#I[VM?bN-2Qr 7na1v#aIU1O>cװ5;ml=/Յ{`x{`ӻ[Sx(m|LQS<3Xpa9slٙtz`i�v!]=G|+$_PD^�5S_дa҂[h=�SML2vNUlN%v×v5J5o[ :(Xzdf{D�k |@ygFLV YG%hRV~' d;)t,R(v9 d-&%be>ՠo;Aw]#�T;Z1E %b,kjfUQ$ϻjAZv֟'D 9!wy\0}^A݆o70^Qw\v(sRɨ6cV՚Ib@eK*?w*zc;+y4;JXʓ\}]=4'MH>'`Eg`N> C@ Au@?6dz!%ܾ}ol.$0B_%:Ox;eDLB 8MSF/O3Ұm%Q?V?NX82"KC n qEIDZZg�14U$Y�;C+؊>ܤ89j$e`iCceҜC( [,Sx`mϱ#mG}[VcSyAg_I6z_'EU~vYa)$vܪ$FlyE{6;i)ssAϜ_p:9_u#B=Q19zxHiȨ+@'`5寙'�[==+<ɚzVI5xQ;yGYiM'GIO\R+uL6.f}Mszi*mӤM2Fg ͌7<ɉx4.U61'MBXy MV!LY7}7;7Fo*]mpK~�BB@dhчh u`lZI#&p`N�%F6ˮ%'o);` fb\L(Y`�]x7 0`t|P[ ҇\C,�K8;p"]F}ca @L4"7ɸHB]CߑGlnSVsM=9_uXMFw8_(0=ҭY. #k?ZH. H&Xm_)[Pn{`{`{`{{gB3ճnl||cN0 h<'sMpJ4BVx 9 %<'h^r#d1h)?AC(`]8r5ŶAjwҔBx /T9GԎ#° Z߁/v4\;?|Y&˘,'햝?Ϥf@ [V`|= �2)'{.XtpcXMjl�ARq_()*os~a7l7,@pb= :YCjui0!Ƞ},Q(8y$40FSCL #flW˭QVG>\޳�@tF:/7KMSe*i pYl!mEKqSd ,|7==yc睯?E{ a% TxB$2DSmg$C|DNE(9QeWrlA>l%)CD=jqy foO |)CCFvQ("!o6@>DWUnС@ڞTAi7% Z$^Iѹ67/~"߷.<{3hkuK#rг(�.﨩vq1 @F`[5L8DJ5R:)[\L:>ۛ?̒LQڼCLN*pҸ'ų+6s?X!.] @H,o2\I!p%wZ~Yn)3ig~muvj*=So%.xy.zOg{c'7sǭc>8x:_aYAZA�~eH_r{==@u1,Z�w\>xU/Rtno^r#'c1t^҉@ ؜[K $<Ύ$|a]X !JF;~$yڙ6> 4Blx MQPZgOisB.f&vZ 'r7Ϟl\-}Wp! GbA 4 r(ʦ#rY6Ad?#9Eb8'ceIVvt{^{Qʱ1ǃcހ"<{~?'=SA,Dwt"�l줩ikUEvS~wjbDa@Sthb$E;:wDJqV|ay^/x1}Vܱ혟c)t=Rc<l�m 2E~؟lơ['w4Z^�8sB|^UoeO~z:vby@A`P&/<EƝ pQJ{ڼ/ !.-g>u~oXL[~ ٷA>ڜW#&BH66lnP5X?GZneZhɝO̅ke:hJ@T:K7xK7?]'`"E!c ёR3 \ @A7h)c�@AR {-SN[ANyZ�!?gX#;.us_g|g3Xywe|_plv'xd>cdҵi%jGvXC׆4<o)3-6W}x[ w 7s\aۇn/¿eb.fe!�Y @4Ǿcޱ0]8]y.Kn?h𤋆pVảȿL_�OBg!@1*䝑:IFn5]<4Iǫ@H#7I_LH#\sNr&N? iP #A~" /9\'3xbAz'd cGL5r9M5>u 9X7uhW-]n)3e y8[*hX䆼osrEֻy�Wސs<?'r�n(zAE?n ֲaiIE`>C곐95 68_a {Ac  2Y :|Q/Qv VB (ɯL |d1x3qƚK_d@+2x,֠E]Դ&յScPd-3pZ]|JnɱN's!Γ [{h8Bʌy<C8c̵K/n@4큯9U,V?tf-{:M{n7j=\yw^{։aE)[k)j'3~Oy5ة ;sQٽwD>7h?e{k�>VkdPIK RtQf#r=#A=Ƨ$78*ga{']�(pC_{x4!TTP01Ǫ0gOKw@)2EZ#Kfkc~a_sq�*O ^$0_/︾grB�߲]c;zGue}XhxLs籺0lcOmS"G^-5c-O)�<W �\;9e]RGvy jƿcԉH>2ʯzM91}é}5q/;�_gos5*wݜhJ enb~4xZp \|t֢z} y%@ *?_J,j+wQI“7D"f!-R[@jsfU acOZ˓nZʮ2.~� _�?D57yپ(cr 4 B�@I? EC$~>eN2k]CAY:W֩[ 8pڕEҳP~,]! HD4&s$i~ITS*; < ZNG OzNg Z$w:]UsE˘o 49ٗ�{KK?c<{XӒpʇiRnq❶Vxu 9sVڵ�8ȹfѹܼn|zeTyMjJN.!LPiT< | ~Қ7hWc4% 2 )@)Ȝ͋,&SzȭSTaEr=#ȵq%6! nV QdLT0�ǻ~W f�3I9 O3wCʫ\2`91r}$dGir5KmFpTG<g׭}ګ?&R\J"ecљ?QlN ChQMH/Ŀxǹ=�<N kgWf|ވܒZ$]KpO.eQ�P E/0*;,6:LRW*kWL+D ᓛrE큯Xg΢�p.u,[}\ԙN_h.$! A+t'@߉ fPs.#~z snxn~ξ%G,ɕKڳa$k|kdV))8�՟38_ ٱ^HQ&JIsj&uwr`K&C|+] G*B v5MThO, _9 L/z9 (; }y_߿@u-xӋs)��@�IDATjkd~QbIs<@< `�ӳ�}cqc>G#k/}rİpx.0Xd4a_Ņؘi FKuַCgw`{W{`#f7'e9!(ω\~4s;qA@+{,[n"Å,�$8*ÜkvwRfK=z([Rc~F↹zd'EO{vM�s[/ Qw+焷AP`Y当`!?G?[js!�4) qTGFDr*:2%Ͷ%إAhy <rl `<ǁ<6iW{<+o؟Tz؈ڃ8&T!d芌Sc4yΕQP폱?ecP+ hzOB\r|\s, =# Pǐ à!삘MQM6#5 7mrdq 1O]+ � a}Vob Y�p2 |8?PUP#ri +lՠ G^qȿ$`q+`tgGl,S� )=H+ 9LiG"atCwZѠ6٣ bs~@ A߱�pC�3*~Pw?/(c@<?y4# "O#<mk2Ifh'$ CI86&eh^pP_x`x[.�&o/=6XI�y%y44]8˞,nRe2S.#5ܔ5HKo9ƴa{0 \�p1c �Su\K8 h;ƒZVw !ʨt6y8Va_ν�0:\?0f"ݻkSqzĮJH[AqI$e}|%] ~zHd ǻ.�lBMɓl!PZF:$ީ|T2凎 9fjY iqGȰh;Urlxv{k+zt2.@埸)N'M�!2ŀn(P2R&*B0HA.!]wS�Y sGƽ ,{?O\r 7߻QQxȠ2<< <8唛H袓 `}DʼnӣGP]yE >fo#]7*[/ KoY ^-:%8.ǯb�ʊ8+3:> 11먻.8X_k#A:Ck>Z p6===0q>)4sW,�xйk~NLx);됍\_Y%F.BM? pI;LM�O]z�ҟ9h~�03={SݞK7Zvs NFjqg,qcn&̍г>W^SWv(m>Co1Żlv%:ޥLdkpw՞ _= hP@Ỽ0tZzm; = jM~BߒA j6vk<>y.Yf~#.4K\pߠ1sL^>|Z5Dž fYӤ>fz\bGI<-e:q'ʹ-ؽT<y 7 6CEL-y=Ai5窗329*|9Oʸ7x r/8,9hS$<PO+ElKW]큯9~ ym �_osq@==xM=NL`9/n^A 1cW dBlNs3Hs~?w> ԩiDvd&Ӟ 1ieZh.|L?siɋ1Dm`aG"I(_5mOy$M<cxKT{=mJFÒCtxuQ60w+b084DD U@Y[USi[j 8>Ǒ2+ %J7XV>,B~bs"j7kHZBܝp9F!Ʒ˱!o9zSpӢKDIwK}mgg?x>cZ|'<R/LҔݐ_4A<Oo$x DFpƄx{r1dt wmll=�D^D_>DQZ&#'GˣlE�"OxW_8� >NxnI= Ї X2"nk 'h%.8f=c┶֚6* v-WmTi5VX$w R|Dɯoӟw 9 1rUO؆)]N TI>*{?J0S4$w4e`Zx O�ʁUZSK}{͏6}|_cI.<,hZYT `Sf*g-\Qgw?jF6\ydu7gh9eZr>T_i�al7w<sR(']? zscȚs�0r!?"ԙQ:wzWun_N?<%>p2 'p]Lso)?eI�jI�q. )?>2#p'=٥9!GYSl.r`rQ= SxMöҠCAe 8r-2Tw V8-~�9e�|w Zd1ϣ(6sG˰tNXH~RP!2+�EV% 0j{؏;\d9->շ5Q5]8fu_�<e@ct�YFibãY5*[캻]c<FiPj3 BN~R@܏zMtn^)'SO5˹NE ?b A^A,H(o}n^83`3^H{wǾ;}===<,&] ;t1[ÔS�cI'$@u2o09v2}/{?E_{Lք8.<8Gٴiȅ:_^ )[]v]if"af[mI*o)|z[4�_6- ]/'" נưtko6g ^+Fycҡut?':2 3ɐ̶H`+_ lGVg�]xcp~.7,K~7dir`T l0ށg_Ɛ%k{DOˈK$IWm<3&>$h)M3 ^F2 b.Cb?x_q&9g�*55υ.n*Tj/0q\Ɠ-RXh3jVs Ii{`{`{큽�Eθ}v%'GSq 'A{&}`Ì|}K�^|A30)�xڦJ') <O!�RJ^C9tE;P&U I~smK 8B!m-#I؟I]$;(lx-[队�su~�=;Ն�<Xcwo. r06`lLB솔16K2 9Ekh 96e 49mϠvBSF "{E 3 *[S\,PɨJZXIC]ajSڮEՄ.Fr)mE浔Qh35BTZ߀c45i<͏e^p�x+5b4|ڷ)7ZcC# nJNpt᝶~gm T�d?-k\mLUnL>9639 81@]L5i⁳zdg¹ɧN&_?w-rqrN6'uza.RKFa$UvcP`/-esN苟Nϛ'%[GsW|g@oٯnhHPSdd�ɱpO$ex#R4 qѰ"K=5zhFƨwm=&i9v�\ ,Ek1'tr �qcg+h>;{ 1uX)^Ԃ vIM("븳b <CbK<y<hè3ך+QY#{O НBr8\AK84Ss)B;x]aV?ziBlKՔ /N}Bm3swiZ|/�^eXZM_]ֿ==k<2SŞ,uH\Cj?Iʌ e}ЌI/܁g r ȭG;|2Py N{ZA'v'A&mȞNx] wZ[-{qmXzƦ&|ZVr4B># ]`GxzG<w]mJ- 8&  zXd\[#dzW2b|,oşh5 df׼Y@Yy!TM IO|q}!Чթn(S=H;i\\>iHTjucS 3.YܤؗqA,Љ~ҟyp3Pn=ɳC0 �j% yuZ&|{`{Ky`ސY/e_�pwL"W1@?s[zĞ#f qWL3U$wk@Ǚ= M^Vj0"1R!ʢ '|oKgBFzsWVsN hYw#MPP3}ݝ$ukRri=i6һv}M$_+Ȫk DK՟A 8_"odqA>H&8>|z`x`�:%APZ^Q:N㺅mA' QHy crO s!Z  ;xg̵{Rwr5ٖ|ŅMk1zn6yJx_uL1羕9)ȨP5ot!^c�e;s8n;7ᖾ̫2DFc'c\(1:zɯ?PYBy%M3lӾ7!3I\ p6==pVC2'N`X<|/�\q;S!Fvֿ=5!< fL@89!+3uxD׻ޕk#`ŀ Kko ͲͺüSI&4H]UeNbsaT`xmW> J {عr$)p':'��$3۵Ar7hI2a~D.pBh*I_xew5DLWᮣ*Xm:"rн,ALs@.r|8I�>p[.ʼa{ ?QCtڤi̒Z`sHbۮ4*]w[5Xtm{ZD"?є2T>1} 2,|/:x<d1:fer� yl1: /@N oljqz>{ yӫp._]z HIkף宦46߬OFZspf3pnN0W- *b"(liCĕȤOphRfՓdAFBڮsӶ|^N&t0i:"<b"(<dž_#o@/~|ߠ`G](0tQgjUMͬ 4tKH9ty(kV;NE?7X%Zu(k̝~C^mbJ)ޖ ƻAc/# ~};Y�\�xͼc](cTXfpvdd&/[(~Ww=bzOZ&-YYX)'Ztͅ [7;.5Ln~9DqLpLj(Ptu"s{\6.7i\8 ֤n. nl~voDݧ)uR_ftZ~ԑcRcbYZ#u�eĀ-N~ ?ȹ᎐;7.4FjJ!MҬ /sв?-\aeΜz')m-{&@`9Fu|�ͿaG 8םJq% ``h]Y f _G䯩FJyZcem9J/�O%3VÅ<�`Y?~(>S@#v r !Bkh,zM}-i:;4v].$XlWIvϝRņQTxmjyE~)u\dx\x|w=;^OɌb7xq<9ǒp,ֽҤþM[e@<gs#qT�x'\`�5@;ɜz`=2=/P=\BH8kZYu/B(ɤ@F9mٰxO夭iUB,׺'DJӴߒ.v5}io˧? EꎏQ:oa�4"@~Z_4 `Ȩav|CcC<KSȃac4sd*P%H-y=HedSuIU}ԃͯ\ls4"@EY vNrA ?S!&\lp7saA׾If>ǩϐǮQھ#:cF=f*fY駴'G<�.x2}r5FAaD."IѸ"hQ<0<'GNN+2Pwꁚ-!G%Wr>i5\xr`eu_ hқw4/g̼c L97.mNa>/& `NtV~&y4B+Dݐ%xH'V}jMζIf�lsH| :ooS˹_BayOQ: uu pS]fӫ8DZgAcqcEӦ4Ը,^۸J+xUG9ح*cG΅6L,x1xC?k|¾f@lmxZ-@N;pJB#u(<ߚتkAz㳡8Cim`E<'Nkex<at +lV KY!gg| h&4%H l.T@ [(8878$0{d,wϝOQQ^�8{91:eҳ׽+ג4'ag^M"z44sL+]+hr~@d|,= P |#�Wzc瘍ZWOL;5yͻLQۼ>QzgxENMKۻnWz`P>6k5͸a˫]�X02' w/X??wgrhh8s3y9J*_W43rlP9 aRV(e FvCJt Ԗt-LYf>,w�k�elk3_ j%_rp]r BC}6 $1eweDj yIYMeU 8ဧ\wѕn[h}G퓹x G[pi]AXe[N"o5e\{L\3_q0]Ѹ=~ 2{y^N^ (s}C<68NaMͼCrRi{`{w@=(9;r/�\p ŧ.C|8ԅfCR\et|*Neȫ LyY闦,^',�?{#G~DO\E 2aE0N)ar+,SDG*߰u-%'}7υΑr#oV?JbT ],}|/,^ݾn&KG@ƟnACŽfxأ"@jt#�<jA0  1§*|[QiA0utqj=t%Hz7GC#ckK~D\q̼I�zw84{iG*G1VJثв l=f (D:Aq=kgϢ_L<Wh@k�x%K  �~@_Hc\PPx'}^/"@A9V n~*d9=9N: s8g}[ry=$.5==<0+gp <J p'RfO.�\1Q$o=g? \| S%r0P К1h_G[لD| >] ú)m笣6.<ˀxРO_s.EE^9"\@ @)Ņuχ ]`;gmJݔ@l!ea!.gjm%x<OE̐1C^Q;aiD\~x0'S.yLڌ�L+hW~}lI9ެ:ّ4[POt[`4t,#@L8HRj*6L[I)Zyx&lsrÏWm7[oܿwE6`yccÏ9zG?BNjR0Fs'h.[oMV5{=m ^cw:I+ݪRhO; +2sz*kP 1 H ^:P�JMrGyל xosI?,�|w1/RN$Ms2aw9Š.z:-jW s;LNK?̆O*{]KI֕A,2xGCyo1.@'p�\Eδ Z 3xSAZ* 1/ܽ!!r;w HiJV: M<6ebLHFM׹>nYfy68Kv1UǗOqg�+{cKKB�tq1jN2xvٔ|,KN:R>SC#c]ufk餴{O|4",T5c@G. &k #x@ k\l`@ػ�OS>Uqr.䳨/OZ=Y:s%C[Nr$z]jkU�^y}L:%;w[ËHH 2 ባV{q~Jpv$8Sz,)K(}G ` �@NpM.i⧹rҩmn~:w{~_Yt* }߁qK_$gԀ PB .@)B�ܑBAΚcy \7$WW$DY Ň@_ovt1:0ŴB2 G}4�13)q<g/l48Xh{ ›2b:MO__Iڰ¶sk]+.ܲ¿!+s>1'4 1g!Ýnjs;\KAmbWU6d0x07}PT8(=w:^{g/ _ j--d5޹3( Zu7w0/7w}d_5|�~W%O�\>q0$�6͢+,|S籇>!jTڒ }Kqkz!')A*g9'9:  >|;7=†1"#߼SEeHP*N "妃mmy#TӮEGͮI,\㫤X`ƿbFs - r<_%c8AH~5onn?ܥ,w;*zN{PgQP]~5Lnv,2os>R;K@);ZTm]uE|l0g{;Я9|NgU\Dk1r#~XPv#+!ѱ#\\T V. l{`{Kz $G;en|ee 큿N5'd6x 0E8$9pF"Me_2زYxW˽K�0�V4hF|rBsly<@78g�ڶzMGm/R[xCv�i劚eplx\s;}廘`h:4Q2X68c!+45r!E,_ =+%RA]XPwD$mie2wz0Zh'CcAvxeV)'x/}D_R G}>@6DzG),$0H#_;*`yv=$>o@/ih׈խfVE!tB䩣 izo.9r�y|c'dSxc5. ~FO)S5*q02-U�(>B!H'h~{`{`{O�@':A]?A&ll|N:L; tj&ş-y˱9)VOLE]}xyk^\E�?T8 p@]Z�ȜDB"&`љ$r!W]VS# w~TBv/M-f& ZFAY1;fw(7(}!W?KV:,:*`)5A "p)j+ 12 7-rU~d!*RO-HT+bS%* HB*#?fہ(S> oy7=:n$Qت3m? DG}ݦ9.ݩ^8ۄrC^Ԥ#OR^nvWmt7dlC+BCQENcU29s޷to8^oWЯp˅cj^ ,B>χGv^Uqh*'AE?v|xw"tY$-EsrOUv_8� h'3I| {kG홀#;&3u h:`Ss8(mbDlcPaҠ[@ߠ-7�5cPYuJokwa$g1~1&|= !W$L$@fX(kp@xCJCB8!wlءH?3B~pJS;I-ּ |W\|Y[hՂiA rRf�ʐkYeg ?ԫ �eEIQ�< 5F^,XyJ=Px% u4ZN_:ϳY,Pmu-֑jC5>IDl*/ѝJ~vzޚVrsVt"]DCc)$5&)iaCǙ Ky">\ }ӈ5ц aߙ]4RCԴtUwvi .C~4}Œ!:UI;ȟycOu~̟4CػylY|.ky 0l}Yb>^2Ս&\*>P܎FlJ<D MjǾ8vi;EUd} uWpl=yOH zWg(>zŭo| b,-<N-cHeLvcęՎ*pb4C { >!:K X=p\\pDsHǀ;%8Y:Zj7SD?r2R[(:-\'H{===^�]&% ~W=`IG \$89DqJLiA#LAL5sqϙ9[!>2~mMJa4r;1]XZ$jƴyOu{ 8gAhSʄL¦+ H[|%_&w7?[3||ܠ-?,G.XGS . Ł;t4!lұ(IHFquԹp YQh.TঝVrQ!7凑}85קdd7oQn@ #s)b% ߖE$Ϗl MW]rb:L97 HnĹx]Uq"3!$֙F]O +GLaCTrcɍ{6ρFΉЅ ,zT,;FV6@y\Lbxt i<TjнxR(|R[٧=�>ϓ+ɫNgHc! 'NCή:D@Z&1Gw--軨IN>1;zwy/]?k7v|[m=%'L4LtEMg`~vGNOMj}#Oۛ~ϯ#gE,�|@vПWgy]�3:a3Fi`䱧<! )˸42U2|Iin(Ɂ >Ƹ4Uf)Qz"f}G/Zn뒧o?޻¾o Ce yMܰđdk4; SUfmrA[#Ӵam[q;HϺ|Jג~3�-j3SD/8X Wݬc3}Zх[Z 30̺ɲP�t. nl< tqOӏ( �qSs4i <UU[�8<;%3r10H;D?ygK)AJf>|ɗ[&AHsInzOWV)>+8TL:¦;/ @>yGTA'k:> a  R0@79`63<`{*`{Ef ]|rօuϻJL}x!ԘoYp)7 =aGA}%cN>3ȯcoe+ͥ nSa[wl?rW]fBt|4  kl#5?D)囖v$u(s'c-nql]ݱ 91W 8b[<q ǠG59ȥKXHĔYVvM'gy`xd\ﳔŸ^�>;~@&St+9\b^ʗ;Gg*Ѝ0_No;W.pk9w__]3U}C~AKSWԀ<aR|B>\^_wDa7? +ybn7ijћ'T!QapC�F@k0hS"&q8mZ⭖ofʶv?IeɽTP$ $3 )&?ц/zLbSKZkmo[տSM0E )|IQӺ2r'(3)>t*͌A1ǎkbWc82tPW)E_cd{O+yz?rڑq/ƚw⚁7n׉Ըo?N6�kl9k]Ve$V x> ;8W#4]+W2yz!c[M %ZêUϢytiTpηa)Q0,,@cC$Ҳ@UۗI3W͊N�w d73N*�WYL< 3jҎ'Ԓn!ɉk_Zì|g  {.V;v{\UI:8!M5D N PjA66PA>�k _W[v-&{>yCl'-T^ʨZgȽXST>g[&rC(@%j)'[yiF 8=N�ǛD瀻e$ybݐf<pHmwC^Ҧ8�΀q96ǭSAEg0 c)%5"Dtx6%}5ޝ+:9g?ƜݲaC�#O2?sYjC7kj5rN٣kߺGC~׌�6(_5PjaÉ~Vf(&W*k<00,\"; 0W]Ҁ* ^2A!G2?t@'R~9p}6rS./[6֐Ur#� 3~W!mc }ri8lo44?ƔҘwClh@z}IGgöCC>م^eC5`Hُ{>l/++ NKE_SHe 8#[(jNJδ ($;nCҸ[ /'cjp�A莛9U3${,Re2:H5=3—dwvz^.16tw8hgHԱ+f��@�IDAT\92?Pƽc2m + nG攗f V <7dBZf�x~ukT9+dsjY]3r*h,*AFtA �YM:lx)ctzad 252r^2}<DL[U7PE7v;EvOunut% \fL*t=W uja=ۯ-)-vciːz0X\ܨ D9t"44a߰ZDcFLn|TGI)_wp9>>ٜ[|I%˿XHe(!o˕Lq50E [e�1 n t߂Y<DaG6dЉQ;50ڒ�ސ-F<"C#Y@2@.qӋO%l's3?S6痾've^u^tw�at؎2NglGH"ZIP%_ ͚\5j40FPrG`G!O/ܷzzV~V <2)dȼrL 4> e&1˒X?[y&bi1Q W|,1?fJ?vyR= @(,L/~-khW={጗'?y(k&PޤW5\#EҀ!#nt.z|ehr_P*aG {Tts~rs~~gu\_o޿y{lQ�m)60)XC`L>P'IQt\<1�y.cIwYs{{soNH{xy\�>qsGu/a+XXg&¦@I~.K]>O߭׼!Vg=喱ƆQ9 a/D4s~9tvc7Ƙ4/hk'7e9&[5&`,؂_êU?AaOZ�xdžYD:oj_+i O"Ƈi\cb I =uȿ:|ygu,�%|kB D5=5n,y-g|F^'щ4f~š˭ƞH-i& W״rN@524:,�1pv-8Q:nop%g[cq#]Ppc"$MiC !.9'tի͛77_ޜBijW?csz,`bswss�b#FR:+ȚysĿ 4J1-.KsLjy﫟ϘC @[| NSP>QS"NѾx,3x=g<ӚgY9ݲ uCO{|� 68Ac늴rw>~Sc| ]5=ǩ7~ j&룢1*Au~W x 6=ו5:�>arY5j4017ǝB`4, 1(ʢFNUrd*cS^SP-/Lp_:r7*#'mm :1a>vf\Þ(V\,WdD;N)5Y#o9־"n� 2.�,Y׸yN4FI "puDo,!^$)@i炙-/_n~oN39݇np\=}y{M`ИgW$k: #{/kA*,".|~.[Zo~it&T]c F1cX�%78^2&O:MQ uAC_|رA</1ǍeГiS}|rSgwwhG7qiI$ tƠoA21mu.�7 v�nӘK~�Ǣ8w qc;B^=tJ7tkX5j5/X�ϫ_0{<_glej`@&ѿ%Ҏ8 ^11F0 6>4-G,*so~=l~0}qr ei6ɶHm_&[̃$TMwa <qf+\p7c}gTC~0W{|O_#ZSh[=m9w؄0qbA?b _(el)._PcCS}�8񯌕l 77p|nsr37|Ny P^bc�(_ ʁAj| &ގCJsjL$vL:k[1O| {mI#{8Y^~MJt8՟-ș6(Nz& r r\<GLvP9 %)ٔ'<�agX78q�蘻d|^+cOr Qxf:{4;r i0h?/9+[w2j`k߼xb+Y�mJ3}ۑ9u[`MX5CNj 9 8i'56 c �Net`L8t}WPF!F 0:\w#[p̥bR1+d%Qy+d >rh4JçR 'Z&_%S:߱0>Ӷ�:~ƛ ϙ`*]FƂ45F>8b`t >V"Lɻg-N5:R͖t7zh t HL\{!=8qR1)͓/ҿ){j%[߾e_o�m+2矹߻ $vo:j̻?} >#Myq�$> P ڡ͖e^1>;7E7mSv��`\H@4Ž.& .43~N7QxTki12՘.@C~&҇ J@:e(m2A*Eow>x_ c8:)Џ#X5چ:RhM i@aW/Mj`i[ _6kD5 xB db~ag1u]Atrdf̀_FAVAh zWEZ}Y<g1F?]' u!I>1Q>.#t~F٠#q gM uL�leocahy9/6i o'ۋ]awX0 l;Ev1)BB J+(QK~ZU9rPSJt1a~d򖀿j0q`^o~yv믿n~v�s8-ސ͇ܲ_7Q=,kسtv{eᦣ`O';`^SjEW*+ae4٦Ja�t% *ylw9,tt3@㟝Ğa]H3qmsdD\|hSp';W,i#DDŽ+ d3?2DKf1or!:^tÒM�KiqM![Uu¥aRȗpCeFu1)n(k4fW x 4̾e9 4Ժg4SYgZǪvS5 ' ]k 3�jkDj#@21D629�}?T I1ɉҡ@g-2n5I?,g R@Vg3xz@6iQbxt} pL-7|ZW]<7>RU#va(  --uCw植G.(@4l[%xk'-Mnָ`$B : ޑެJv %GA[y`kxs{o o6o߼s޿y�9&FۻfYDŽǨ.g0٢WʛqovʿO Ĥci-F(=<6 7:[3w}<S̚ǃUURO(mNA·M~FP�$S "D` 7jf8q}~Fk{(68< bw!%}H1iGyp`e 8qUKZVճJ$K=Ġ÷bԪU5:�hpр8gi%@/vB8y^NP" ]hr14=C=<ۘS A<F0---.)mPWF;Fv3]W+L*I\EڰhEX 1!2T?kW6v98#t=شuV¼&#+rF]+O o81d^0O:8�9_'+N �\/Y??;ٜG{V_:%w6/mɣr%\m@؆2`ae'@2iAZJa}%m90uť0IM1չ NKh0*GQ%-y.+{¼[a% ݱ}; tڈ ;E\TZn.;{ux{{SA˴S#4r7 oROߑ=唾uF󄶺amlIad=e~Zvr ƹD7~fdle\5j`�:_k\5j4d6d~\N 5ɤig9\¥erʕ?�>Pی b`#4~> W2DyMCM�s}5JOi, 1n((K/�\P�rq�kЄF2 KZ~E֓ 1y̗iQ[xΑq[x8<ϕx �n?9ڜ?9#P'yK8 =%�r7.^ꯈʗW+yD@ɺ^{PW)IxF(ԙ�thѨ1W䶻uh.XsxArikʟ�u5)"uu"Am`]tcG=m&[&XF)KOSTb>C;`xm g w cVQ1a/S$K\e @ƺ#iHְj`K laҀB5_ 'vNeg<.tFjCO\$4LiWl]�cg*\:+vLƀ�g�$N:e> #�. 6)2x{oz`˽M <o9*/n9j10zNe+X~5 dC'8Mƕ~�1-x�iG90uPW v~Nt7כ{,:�a{gkkPy،tߌwR(C25Ғ6Eޜ:Uyq숃A\䀊vQUq@l;6}Ds`S]#]RUGJ&}OSrF ̢iR_�Jlֻgti\c)s\^~]�3<3m]%ͫtg?/@$͸L|\JqPe:ƫV <Ykxn 0OabvfbNzvrﳠe @2u蟼0(\;c@ lg:a%ZAzo<e|4X_Che4[E afҺG>cԤZ 3=dn3�-t<#/ {Waʼnc>0cM^g2: <.N�qZ[icpb@L+؂\ƊDU? *٣|*#ub0y1@pN�89:guߞH}`Nxc%x'ۇ5KY HV nm2izX "_ J{}vր˸Jd1S1Du=Ljhۙ'g-ڃV"6ydjPя7 o] ,^[Ӧ*3bXan\w~t>JgӘuM}wwߩ;4R$9r)b�4)+tFa63n V a`?q-y |^Oߏɯ}z֥shpc2zD>rƦIp_4Z5 +ckAg>ic4++Cvvq֡cik@֑J 0%ƍQ^]`7|G]*g[tK!\ޕ12m`4 t(j7h6<lci:F6?vfw�@�wKkʿpչypq^gty@!#JDW?<OX#7 ~WPc�G6\m9b >{s'K{eYy+%ڇ_O�u,9N|H'~{IoƋ|'E?q elT`C1MHxN�tƭN~ds΀QoQ/M�IC #Io(b¦ddM@J,l݈IPJFz [&Jb1[wߝq8YSGmo-qcwSŴ4|h/#FkB/4SvMX5p.uw}.kgnqC0 ;3_5論9Ec9s9o _AHWPc5)1A!L>ۉo0D< W]18OFG2yMN(Y\xrM'q7;ɣe尲E>W/Y X3Zſ&a =mxE`x@E.�SF?1e;b+_>"=t1OY$KE41WZ=xƔgoyS OƓ娃 FV+\^߂# ;ٲqXQξM|#;oߣ/qy5 �.q?9'#@DJ.\i1ealƒ</ }FbǭƼƞ_F%2YmFu"?J9>KIdUX`+.#Q4ȏhC|ls zƪ #<(CCt=ev/n)xCx(5FʴS54xK݂9rlڼX58tcĒ/oA rkX5j4qė]c_?:S~IY*m'Ѐ?򞞍3#:'ᙌͧQ.#8+Lc<$pM '��CW0.k a7iW-:l O:АaרggY紕EGjmfTʊ a6UNiԉ4}_X\:n4z)5$WF#&0zUFLO>/;혮J]=8܏j8|^<2ZܒX\~ؼ?Cy>s%܀zкK`)/7*P^ڼPß4{VNcKG�78"  j6juűܤ]߼=%]}5'i\o: i^!�s>w~`S(Hpyfd0\|'�=Rn &X'uiH>ʭ>34I$MͫiW0pI_@8\vps�YW ݧsk\'<"#S`νo~f Vҧd5Z5j;4ӟU}_!�ɺ>-NH~ގܷ_5<j:2#, $er,tf!O!'MB<8+je gv_㟩%N 02J~@W<А؝x2-~-W5>n}?•oh[p;<asz):F1-o[Vү cD1'{, ODk@cCá[C{2v?$0[ZyC:!F8D�&:>ygN}%hf=eo5֯c_]^n>|x5Qzq5Ņ@_#~,f'�aS f�u��Ca�0JFUڸRXջ� *�8s\xjL{ݐikaL|ͥ?΁Cx.xY ^s$At L\6˹܂#1n}z:*ޕnj9B#`Z;McšcE8/c�Wcg;V{'ozSnc"+iDzCO@b尧UH A|n!,cЀ}~ڃA\ע�n㤇VB&<EyV6 ȺU'㦅7.028^M^|  _$_*'?N:�b0;*#3E�WC"o�H=[_k{pG e >)5Pen]c ,b01'Fixʣ 6x Z(~�~ R>OSf[?}n OG^'WzsR~uaUί 8p.;C?F?Q�c3˶i$'xUZ0EyOw}gְW�0y@`v`Cq<@q{`Uka&mա m0oǟ{seX+as^҅%WN+,ܰWu:6GA_U9y$;p8?ej0IFh\C<X5j5&ax_i oP_:v=2V ga;tXa 6 `5u4fq<ƾgF ľ,+X< "xY" nle' Ń&w;3]aM0i(peK�x?bX m-a/bHp}蟝&!BC$ V!In||~ W_ʁ@d~Zh(8w']e &M "3p5,e,sjrP)X|eq !L>SH!غf:;EHm^Eg'V |ÃSM{ $^q`|&~t,94}ӱ4M4sJ»7c27^ܜ޼`|k-a!J4mO\^_yf+!H>Uf[ !|:3$/~ pMX5=ppJ^ul}"�6}}3ytofX5j� qW ?&v  W4rN;|c4X" u/>bVqiWHYH/acڹL�; \<Sݺs0w#sa;> gOCj^g; j~Qhїt�[\J)h^ gm yrٗ1@ n`K!> Z4΁>[}WnθO?Vwٖ6|Uo's\2 !3KJ uHQEiH42F i'wٰ!5Bf@brVdtYW}>:{tNl$L1J|2 `J|DoK+ܬ&Fݨ?:ԹVǥ;<ܽ"<8Hg;} rYVt2_qmNҩ5eb V |5%Zh`u��ۜ9)ƬtFYѫV <)cbfcN4w+¤.[{9dO?d\krW@W8i}g q,�R~ ? m%Ro<9}7eح}ܸf<7|n ״05oA\}V5ih"h1-Fs2"ͷXA ag G1e:c{b{G˳ׯ7o߾ټ}z9N#^ǚVf1o8Pz7WySb-`?Wf17F;q&T9@Pynh7qk[c|Anq㎭OTq{=:B]GҨpbZ2l)NZe + >ejdiڐ.L&y>K7ٖ_ @k*o/Qs1-^{@=Oű�V�z3C];H;D+I 7 `MX5=0N=a'ju�<{Kä-^h~A?'^Zh $4cʱ5f=t5ϴWMgg�0~cb@8(AZ{cڱCϱ_q[|Tqxu(+L:9oZxä|7̟ 34g4)-\,n[Y3Úce~[/0"8=5-sEߐUW5tY)tS'Bh(�!ao!LlqQg5fuwc>y�YN2Epm7^o�Sv�;>wĝ_W/87lsptكGx s&� SNG�h |@aZ}E{#6ڤAa5nQܫcƾcc'\ٗ^OF� YBa v7f;ÛSǻuokNQa.۱0ÜtZc?pbap{#m%W[ƶN :(X5vMm: ¶΁w tOoy) X5``o:ZiM:�[u_YY/kX5j4r ;q� 5 - c1kbl 1"i!FV x.>{/7m6o0"t�+�:-B73pilRScΛ~r|cW.'sl5.�]?x]Iƃ./L4 LAȰ6ۖOH {5 F?4bW~eP4ljw~gq��Y� kHCv<888::bCo+y<��_?Nr�0!8ϲ �0D|�j4s 1eeu4w.C ;GGuq;4U-u|QP~)xD4o5ݪwcY5t-wA8p:�p�3p8<<w,]�q�]PC_Cx!X9@`<n V |+%T_W| PڷKJ3ݷZiW U5;f:_SĚ@6F1mJ0;4k(_F}1)W,'ivb;G˜:AuJ?eôAL&+RwY3KxB0n,KG—Է',uW�rgaRx3ە?i*c`࿏8�HjxCC+BC=M?֥ehˉ1>[d$I41Ii{su_ky}Vp�#}Q~rr9{yΊ/momF Wglnht4+VO_^lxt` bxwՂ7׋@G@} p_@;9{npsQ3xi4YMS˕68q1]m5qc<_ w3ώq�?9�M4.[u;Q0! lAA+2[͠N?KO!NaM7I2)#M KhkڛVߒN�w :=%#  COCpgVҊl0zF>?U_N}J8XI}MQ՘dU4>р%SLZ'_Rh#.B a ^g2I~Ǭ\0<gCr| s',5Dt0B$e}ݠp#^heig o?v4`  3/4p ΤA%Դ!bKI}V�aFy4:t '@[7�0AU c#kJ_;�Ja#S#FoZG�1C?p+g~u뗛3?*#f8 pt|?(-+w>ӯ~>Z6w�!/-bA# 4�{^+:E*]{R`*Fr�=FwBCc1ɸ4(ii!oV 'wq?I*a%O:&O2;[͓Av> oe" g|¤ =? N5=�njܑF̝;^[c6SO0ktVƩ83@@mް @dX5jG4C0vj2T5+5LV k`:)y4CLj~IcC:`"+pp(bHZ#KA_%|?RI*YMtJe$[C*`,[.uEԽF]̯ad|7Ó93]PP`I|־0Ws~Ke40�!Ɍ?=fQ60 s 1.WIig0g?�Wkkb)3N?9/q�pN��7^m^r& v=}t??<Ԡ0?}5oీz#G}h|q V+yӊH>Xڀ\$ ih4m^[X9h۔ DEN�}@_@zpBULe-l!ga gAsRful5P=/2ȜDr}�ka((c>%o6.JT}jk�cz%4XG @i7T:IMۄlEnT>DkX5j`Vh&ְj`wi3u~Uơ3&<!N�@] 68w14-|ߝ�8 pN#PEi>9 DR1c � Sd^ lS@>�߮WNnY ߞ"`ݰ&]%AyyڂȽW U44R]An9a֯ e"$0t{ h]yk-s!H?+];�j?h \6=WSY|�#~򟞝m9s�ʫ�rNSC+r9>ҷOR~>lNy;g�\g{żUP?`qR0S nIӺQ�%P:p˭%m3 |<8CVqK`7}% e#J53B5=IwoZNR:M0o8uy THhY_t~,4iZz6NH.ArQ 9xn)8c{rt:qB#<Y͇KţDSΡ{˂=rY"HF#ƫV W�WjUUgV ξ-9y ȉ Pę;#2⠭Y�>KG"@WpZ[G=1X'{h\�F&фiz:/UpbLO\"k5]m G5-|Hc^ ~d\X b#�v�WAa̰|.ُ ~s.Cv&<!|( #fg�w9m9 �s �wp�:CYw[[GC"w@f�Ė΅s:./>p�|qy؈|pEG&t* E8fHgS Zm^UC cw,ڬPiq8ϋA7Lw}g%f%I4TۚaY( Ac⧐{&oggzz">[а%'q7rȻdt޷ `V{{?ҾzKg@g;A�431}2yE%}Ek_Aټ$#M]?V X5𯬁0ZgYL_WV j`̻|"L;KՌ,4qP| A8w8. r?C _ (75wiʼn Xk:W�ghX6pǨxǺM/J U<kQX8L(sAy%]V ].e>*`b]lNcvB-8?m: y4Q4�y} @=C�Y?3?п#`TVȁhX}Y򒧼ús|C[ 2{e:| /`%m{[z,X.ʴua)G.qpC}a'xq{dO(Sg6I$}T(}`m7J0!vSn.? 1-eGzV$[M;.<hC*?x=oy؅Xռ..zm6K.��@�IDATWr e>aTih)Zt^sj;!7_6:�~Fg3*ZX53*&g~oQ"LUff 5fƾI!4�SCs�k+l+/04_OQ28< ]&܁ [ϸ@i 9DKsՅ;޷!h¼p^ܠ 4@N}5*"vI] Y`q8=G/X^՗1"­Ium8{? Ӡ[0[�NO09UW5X#<me<G-"2OKɯtSֱddD%4{+K\ѵ Hp%g,~OIS!4 "-6#L6*%d 4tYN⩛xl4<sSu!aLߣմG,e'C:g~g][߻ΑCiD2c~w[N8TT:.ԊƵF*!Y @-5j`U 2Y7??Up0ri 0N&5Rh�y1v3;1%L'{X^/\-4%j\%+, `r-I {b\{bi)GGMKfi(A,/'�keEn6?85O�HڿUaux+Ź#sȪ0pV͹m 2_^@?2tƏTgX3\׀k G0XsP F|xE*gCS Cڬ>n𒧼uXuZ2ԐN2y}ې{HC{4|̇Ϙ_% H3bp7,t,Clok'><1>a޲FA<f/Qδ1|xg Qw0Q_tuP?yRNA%4�4Ȃ~ぬ#22 Xwa2ȫT4}39nQ-c1W{ѣ,Wf>{_³j,X .!u]h%ԉ){sRWЀ֏UEc}K5:�]gV_6[V <Ѐ�TD0'54(EeUztի43їIyp5G{5L2kA]C>w$XG~3 +�t\&S! ,tYd|l #Nr'鐏2!kډ.L&Qg{B;N? _�}״Ɲ��7wq7ĵ[=dIٺh5Io�<8EӚz*}=&-N :0|1X1-k*;N뿾\rUulqK }�S!S~5hl?m x {#(5S9'e\AT P:ܕ#xa\m 3C';7Q&Z: MO4,#sc8Ecᖗ۴!|+d嶖zJSo;#|л5KAvt{]8)_;AV`GǑcΘvv'&]ӎ]Jcx۳v !#W Q:V^*5^5j3=>C\q>SF8@~DƯƿVW <V5i!@'t)8eqqx}f40wfaጯN49'|:]ꧼaDI90%P\.<'c RhJ.'M z4HytIgaS^8I.Z!`lﰖ~fWXA7}21+m}ehoӈd.IC 9V$VeݰF0}#[Nq#rkpsB=`㫏Ol_;Ͽ5}\W6ޱN}w>>7݊Roq�pIus{} np�wq"ǀ΁q[QgpL^G�u|ԑNTz@0Ν$VP̫q7JD=:P|~K[P9WoSaw+.i>qyH<VlP$e|X!H#+9-Ұַl&~E4Vil*#StIW㩸,LPkz~sE]Of <-;5{l>cK/..J#m"޻H\@dǪUk 1'{h~[ӿ/us uH?J,aN/5j`<B0D=9l!1 $4mD>YYfChYnپH9bZyIRVy"qE 4nlD%t1 |]t` |ŴNgO% |Lͼa pHu0]7FO ?ϟG�N9@Þ)�P1g|Ps@@@*RMђt q =acU?y8*@tK>[51?r퓿װp|{| #"dTM3 KfŰbs=u~\&+.^ xM|s{p })pG@Ů!u=pt&hXP`hxp̢Ōyr w7u|{1C G΍l^ar(}mKb6ҳ.g7<K Dpo=fGvp{uX.sU }gκ S/#| ̽4M8IB3ae�=Hm7ݩ}zFO5^N =udçv Tv�XNt%fXʆ&_UF537_iK-f;+߸14LܒN2M)*0j U1@hQcƉXIh� pr�XaVnqu SGguy鯑_9]K~IT#F`yL_,qY5-•9` 8Fin1/@g� %MJCJUPqsWܞot Gy }vF?>=F=lo:Qa{~~C3l1oU;wM`d}\pg'�5@ݮ @#܁~ _g^F*ZLڻv5Ƨtp�D>Fw�*4GE#:�ru&<Woi)h0]p H39B߈|.bc}xl@?`;rqj ~Pd:yd =tR03`Ȑ.hZLnmZDV j/=W}ZSON39˯+8?Ԥ/Wr\5'5ʼ:I�O't"ǔL/&3!Ik Y1ưvEs|f\Cb &Jx>p9T3?m�?c�b\k.K_=/\#vfhc($X \~; w|h(5NP<$?Kg�}gvtG]w[/.qxOu_^q�Fw<'31FyſVu臶V<uYūyUƣ= ,?ҫFK8&n3d^^p:zܺ*t,9H?evH9w`\R F9VTϖ37sH^q�Rc粯n �^Kfh$:B*1knE0& gh&,?Sk]HW1@t>%trQ543_G. ?s7Ƃ W u&h8~VB5 _2Kա~̠[hr .,lӥvik( ta=G٦sRqr*+� tV~f_F@_'1NC�"8}H%(Pf/)Dd\YKTI�`Df<SN ƾ'#MV5yK>I8ܯFuXWn21dw! Y MܸKhr&ۖ18(�Ҫrl)q^ vC x9m#y2WxIB'=!GzdOڏK>42CgwbTn|vf+OB20OIo]-<h{Mֱw:q`!*:Aܰ~l\\H)'ԥ�I@:SH,1_HZ?W G!?*H /J|P-;Jj/N;z�b{s8Q`&NCVI;eV ]9Y_b>6`\ěD2L?noKCh/ ]tԉ -GuYƮWi$8LzMYyW}KӸp/k3D"O܆2o~?ã|˗g'#ǩ)Ɩf:u@/m`ٱz,+I߱5x$ ҋ)s1Bɻ%S%2LP b״t| jw@Рn wZ- #N< 4?)>_? ǯG\7d5_g?#w{]}KNǶcб%,!hSN} =lw�Ų6Nn~Ɖ_êU~Πcqk\X�ϥم/ ?NZƏł^V |V#P"dk(.s 1o|mA^L>pzv_ߖ}pp1@V?V=3_C]jVرrtdμ3]ޙqszS{*1L_sbs1/iCax88S@ǀ[cW 0m8 R%?hY,Y8kpƹ<ОtHz#_�y?� c˗6o^szC|9?;�: j�x!r<�xSs.x iS{ƕ�@@ <�LG`1֐΁?[F|@ ;U5Q7`P?;@c>>)cK)_yya ߪ._G~[Mwm=LTzjG~61^3Q#=8Nhy:fsq�ݪvɃumx �u.rH+l@7y)3,Ђ5Z5j`W d #fW;O_�Oth'y>鄤ǯ]5W@O B;7?\HόLCKza^N-ƀ~ux+4�P;[-9� *]T ckCΓDQᱯ&qwLvMgw^d{ ^c}?v? 3v~fmWYQ;lG[!m9I׫gӳ }z_OuVʩ:c4Z?W4O6g7o_ͯ޼~jsXcN.}pq9{N7:q9n9F 4J@�9 �@@XX! t`F^N��jjF?-Ṉ_-G wxbK:?}!~N'8ΏwcB#1-Gk@|47vnzqMOзetijz4;}9@nX@q=yhK\`ʹq+AeO{O^V x%k،dSjWX_IOOyљkzןjiPp&n ~;o?F� 'Yy|O ;t�hxp1 # +o6a xũ~Y "5{w K0m٤ X_$"[#LY{i6M3M9kZI!n,�SC?|w{UeԮ,Jcb544 ō1Es3R!H i8�558nl#0H?+Gcܼyͯkv�•O 02o#Iqpns}3@ C�wPǀo0Gqsg�mwR6�6zywmMm/N5kϕǹA� ! Gqm^qƗDh;OtlXZa-"TM(sFs֓|'o xШ9q<%l`pv3k^{W|/Ө|68b1~ =] Ew�,$4s #"j j`'@w>!n9gm ϩ_0g!ݹҕw 8n=d͸XItd�vߎJz�p/{14{o|;WOȟcףu�`�9R&-u76 дf~- &]VavXL^ʈbQ\yI@9ynF/LL[C~d~}>G{>f6ы"0\ed?q˛SΊbI_UY(/k teqg6Wv![INWo:�n^<ۜC{@/u*lƛV/zsrz9dWN k` ps}v د7�~ ~{�yC�G?걡”~W+ئl9$wYN@^ ({z�: ?(�McXvuQ2N\( /2]((| dB#tBcb3ZxIo<"93ɴ?Q>(z/rp??%qH+Rjpb!dKg -<5"j wWv' Q8'_l# *DI~X5jS ,C+)5:�6^T=;Q~&ߪk ,E̸'gK̇| ~0_۠]_bjM H.� {woWl}}tυLcNᐆ| �b?:6FB:&Hh8dPO9 1*XpsyM N[_Yh(Eg4/^ejJ )3Dpɿ|Iy@XI!2>Xk}W5Ϫ>[]<!s s'ny}j-c}�78'=?Ax `d4}fa\V ~W ׹xHۊs6X1UGNCN%q̠5lm{K>8]qj'{VNyKxa^ Irg9p.�yٷT#?QO>h! >3'<\Y&P)s,4B7k5FM9څƛ@UB{@?;=Dv+L!CDM'O}i<o*Ww)doއlə)9(h)IOveu�6v_X5N 7pbN=S7!ij'fcNF9#2?_'�?ߐi6�Gtf`dH?2 ^'/=ZL5| 3I M[9 %ɇR55ohq֝c h>b 42.;FHKh|Ji:H`L]>5u`՟Ny+>s`kȓg<-�xN|~v$8�Ȋ =kfslf5WT63/^G=TVi?x<@ކ(lWloUPuOߖӨ76` `5P~UqCD1}tEON+^u֬L | {,19&BͰQ؃�B2`4mB;V[/䒮|_}$x,i)Zt/L=D .42Dl@vI0>>i!kX�?CKk^T&V |N<p1-IWBCҼF9jBy7oڹlvU�bwg|O+@Yi043if�HǾ\ a3h$y0޲&JT8ɹ0Nel.?r(fŸ|tib =Qwɼ@56u� CAS5tz�.c '#`�w l�bw�Nc>w_!gy_ DQ5Oᡗ԰9x99ٜrg6>n//77Dz;59p|G6`8 oKZbztYB)lв D7@A:%%Ԁ3ҿ=K=K#N7E#)n�ޢ6:j7[f.zǨt~ܹ_}3$L7eA nT:qx !<!;3Nĸ?@m9SB!)9# ]44ieqG<WS:z҇H#6o[5j`V?QkիV |J9 ,9I☖9Yɦe-8;q @W'}ɷU~<e"yGt�o3CAb-XMO!pj< !O:e+pȶ#JMX<{iF-<\+vYg~VB�|׳|ŗ~W�9~H1?.{8cWL g62 B#vN� 1�΀s�x7�?Q+dX :2}?\V.Ҽ)>>ۜ;*_pP5?G[==�h4m=,3Jel|p٦J|mq!.7ᎦKNP7}wۇ8@_+wxM᡼%S>kǸq' 5y}#-/"d>!4̀ 9#g{$̈) cn[e37@Tr$E Rldd]c-lsn{h7W| XWE4#SeHrX.˘ 3-t[k`.5N�]ZbcT�jN\+WäXMSjfrP^5Pʥ (TC(~`5f'^jiK׮qU0e{#7ΰaDv{u9 ܊n~;oi=�Lߓ?p]2_P@翤akB(#[#H{Aa߅ y>oJ&^8<i!<4{f+L\r_V}] y ^ jes!وAQY6GDyv2lyקLL�,ly {,>Ѻ-+}ؚ vLOdB5SlR/ps6�8M?"9?]&}3@5<gֳE G\퉔QSǙKyE ]h㚷4EI%ܧ(X 4#�4Ui% �|wL+c6 z|3@L-øWFamh)ǩ4ːnf0\Gv؄pXZk |X'�F_1<GN1%iE #7jw+,}w4LG`}y{% -ux` =Jgd[7EFnc][%eX>iAkcP/~"ߖi8qkE'[pͨ}#5~?]]]MJ{\`q| Xc+;Hł78r50>8uA +pZ]^aqV߉_UV܀A{;X9Qsiά̎dR| {�b 8"b9 DrD$uX-b\jC/]W<,Sef6,q~618gt+.%}"'�,~eb1"! [ڸ.ި%ɉOxw_'ͼ"_%p3mlts85_=12v�Lqvs5H?s3䙕L|�B?J)<?Wz_k`k`<ke|X'�B%~Bkk Cj`o7hE*afĕ5̃DT8@y <.) gC&ќ]-*eϐ\){,H6):p5F.SREA}Ӵ?XB-rY u"/&19@^;Ѻ$A0&6K*پ}CC_|;Vh9 -mjz7@^ �L`S^J6AtVW�- `; pDzbeYf#TOi`q4?s?AwOy`DQv9\ӷ@#_QNjϙd*?q1=sS@�ld[՟xkݐ�h 7.F:,=@.?| Ķx?>~R?OOǽg/Io޳3'ݜ&4$Wm_D_X5j | t@X4ˠy3\#13&i8n}ntt̑UNlli#+dz?N1Fnv5PV !yGb=:_Z@U{tRJ UeZ$jѹe9jroyן]rWVJu;L0v LMg !o6Tth-W\ĕNDqI-T} W`wGl K$>mƵPg 83@6Ȉ!ĽB]> .]Ue[B'b8¿OAW%7+>\EȧL>f{w;;VܙtR7qf=义N^<<y _ϙ�-e,N`<�h/I CȗntN8` nN ȃ|<q\^I|0d!C5 th^HU}j+ I@3-DV|�~xOn['oSU$Mc"�^0مfF)#gJ_`\ ͖vp8yWhtq"L XOj@3>^`ַ @"Fխ5�x@OП�?_+_U'W@9_/ׯ-5n} ̏B+*17~7NC} _5uU]F--zTP.;�ug ; >hauA[=30%[˨KD qEl~ cރeO' nI,m4I|xA/o"`?L�AmteXe?J=<2 `�*t*zrwmTؗz|d0'L,h=>^ Z| ^ '?g)w|^o>l>yf{bPn;pi[U Gw9ۼp 2ݕܷL\h;!.k= !F=!]:ԛy Z# xZF՘P(u~J\';reN7a'g~$>{:=5a=d�\N0ZK9*&ҍ~Xt]6&Mg%ܰH_ Xvĥ<Fķ{>3 %Ah+ƀѾɜOC?| *D%9^`p5.d lvlKq+>b?J`5ReY(V :+#vQfƯG+b׃?|]Ƿ1# &JYoul'B(mceվ}Q4576xǎoq-S#и`*kC` k+ Mcx Pn.[GI4u;s9Ik4;AOC4kſVU:H( ]`sEaZy@X(d'τ�ng[^�w$#+Ol̻ldBtw.qn?>C�+Ϯ$TkRq&7Wn0ÇՇLX0�z]{OY| {I&czn�\:8um:C#O)8}GeA{,,�ǀ;'9g2Ϗ6d X3a&0Y1~ЅԍbV /64a7#E^dH&h BM`!) xĖ1I@kY.9"a Og2~#,SNs0o鎣- b8~ 6jj Gf|uJN�x=c|8]1Ņ__xj`R&ը@ B & J<fQ�<1-08t9RK�%-j5>ynnD^ܜÇf_|~ ǿ3 g8"btCT}_E/(g ?禎.m>x~X ^xdďNߵ �q]�P?8 uW'rqe#&i' YҜ21psz9??\?nfgC.gYę湴+9 :ݲ �+ٝ�[&�\w�Z]U6@Ϊ?m&ex&6~vLZZ^CR[JX2FzANy' 𣚩W{[apN,m ?d'�Љ�\0nEy^r1;UDω&p_ nxmf>E4pǵO7`gf}\g#@vm'[>cLk~G͖]cRn)|y߅[vOwX!_ Wr%()(7rA^ Pc%χ3j oTc i;S>QPb`J�'uv g^v"Bg oDt2ld}mײu>Eol bnpUϧ�@[rQ*� xQmVI_Co jMyU 4JAߞA<|Xyĕ̯ɇ$N@l`=z%saRv9ƿy3 7^qwao]z 52{_{w�ٳʿN Sg4M)U|A뼞B>DޗA/I L& Pδ4u&|#p s&$l&ԾHџsI*:Me2 g}7YAܻNn,9xҠo1cI V>??(Q|ӴP"K:00�,U$-$m2xc\սl �/[;={W1+j5u.p+#èJjt%4UU}U>=ǘ˅B﻽IڑW]Ƿߏ~M87]&o|d2~ΫM!m5~Ϋ{$yB_+tוVQW+o!:Jct``osȖ.HD!6@c>ǰaKx\~..6œ r"iڷ<3l$;|Sj"3v` 2s8lW"xbӧ51 ;QBT:=L0oAkhIWҖ#r*z8B#gwvqN'&7UDG6.Aex~7^Ӊ|fZowF7"]CxggM/ô5Gϗh9㹟t9v8@>K5ƘM2Jby�@#&%z_k;*6F erNiv~5 /~{ xw@qy TOFx�p |[a 4Hp~1*pI�-8'øC\qa9<3~/y}!aw^)#Ȗ0eHJӄ6d�ݔ_Dr@kVh0=Pc8ڧ8 bSDMD&a k>۷̹ ydf ~k { җ|%+3/C<?�|۷wm~xnW3+iJ)gk״f9<ϥm*-_P3Kx+c�CAZo#T�& <()⏼_&(r:%`t3SȌ3N>m;W~|!e2beLp\6yT"xw`3N'!]u$3Np6%FDNg|U@*k/Q#\ 9saCv P6qL?<bǐcx2H#tbbOZ&3&5^J:Ff WZ<di7cAb5N�r"[��@�IDATlgƲW>!T+ /t@ PQ ṱ*zīTKS\iQT֍eXy)F;pK4|뇳O?:� F3QzPHFltRl^ͷ}4;yt3sfgNoHҭnN9֋O?s8'}f؏ں^ӎdN>w~b6y#?U?;"3c2{_&4򥛌} 3cwU~W/._cO?n~o�[R2�]?SNg>L35k�O]Wo>lΘ8<`;X-/JW|#f}c>'3!`�䗳u(]P)-pՎN ֐1`|0Lㅓqwc99sc6XB.Ix񢤩n3`=gnkto/fy߸΄#}hx; heұx3졠093sٚ<5~08l n`*gL8_ Wrه5אjbiWTEV1ؤwSy뇕VC|?gc_?Z ttjCxg%__[+۵^{Z-D_ʼJzs[WJ e\^=[J+3OOp)B$h% ͭ˒[\ܓy3tYo\x})0Ê;E7h͸47!\$oi#Vi-GqcWHn z'� �pN.4L*M' \POZ醯1]Zguߕ{ }/ ~'�A_\^b<?׿~�^19@Zb~ge-a_sk Wp9cG)?swOjƯEG{v+ԙc7�|! �<pO�(Bzi1ֈW̸q?XgjID' /]0x]bv);2o6qfv3}W3h!lڦk>_ˏ@|d`]'g|uѳ>=v\'Uy /<w-l8|+Ї:.䓀p&bdqNަ/v4l=[s=u[k໬ W3@gxZL6{n"yAp0o-R{F3w=sT*|ĕ,8ýoxYYSi/ÿ :t[]o^O `$PoB{h f%6xpڢ['!)2=bĐT@tTw\*Tw٨4 ewkmoYx?sc(Nc<|~x3 w*q\7WF(#- [q9a\ _[~FƊ�loU3 WlU~\y�/# 'R qrT>Gy kb576_Q &:7ǔk&no, a|{{َ'! n#t'#(+8ر"{;2X޶AddaN�hIPqҐydNxJv&R*txJ:tMHmw,_�)\fW/w?lpg.BQ&ܴ#Npv#ye!cƋ[W\grFLzp(c0ʄ�q #X�;z' :e'd0uP.W'\#b5]�E=}Wڅ]'�^!/k =G }͈;�ȓ7GCO8�}/ "rg~/6Yz5q_+$qnYblZ}jX A/HS$/,,D5 H<PUD]X&=6_^biUݺǸO1^ 8,4:^sUށB%^0IyX9 ;r 4DJpޕ}  ?ƺ 'dF {ϙp v�f]�?yrsɧ�{DR)7:d)_1M%}'N`w5 141/ku->mz;S;0wƒI�0##v�x{&ȥ_ ȒRӖVA:݇=#iV|=c!q11(cI8䇉$y̮�_ xȫ�c h Z#xE%rGAsgF@8;6 ?s[2)ai@ /nx<wv̟uxI.�,�G'tN7Ek<)" (a'Y֊u S~u@,Xk`< k|X'�hu>ό~%[k |O50?=Ad`t�# ߖU`QQU=b; ;V~d%lWI(Ŷ59\%8Q*;8*a0t<u eה}~{320Y"cOu|$]25x-6+n/;pѦ*bRܡEozb`o\ +� L�8X_VǪ[@<'nGؓ=ϓ_om?T;&jKN�K]_yIàM2?eKƿ6ooϹXLnHYb褋 U7=L,^L Ġ:GFW|1�-;ju>i+OqDUoVIŠ49BpgYվ< z G?i-OE)<ytz{{!=w9;#]{Mc8d &l$- 4y(c a.Yտ8}.䄢"<ÉCe2ot8z7ڳ`BXk`TרhVw^{O^`bqQ1jhH*}a (^*E1sEu" ϸ|k7( pA\M2Lk5IqCë %:iPZg&D|a2?7e0O̲7δ{KUUCn+�+ 4q%a(G@txF9m1RM(? `;4s { O?}_+�1}/'yV}|yڃ^o^jKvQ17~QS?U<AdPy޾nl677ۛ9=LG24ڀ|n)¾cXcǧ]v5g? ?4CngIكi<* zqKOr8,oedrD/N d'KY>7Vp{jkyڟK3 H'3\.>yqK/67L29]r<qPtJz2~l^oI'3X]! N&\k`^ ٕZk |ZoSunDGt`ÍCk.xl2]Y[~ko؃�_c`FIޓLʢSZ% 0L 6E"vQwl|Ri-QQ(/= ϰuzIv۵L3MQ)hNʩT޲-.xF .2�P荏pFO> ,t`E�5oL\aE䳀#Yha"EK "0Grs3txD#?Ӥ >fD\d ''wAʂexezɹ�FvӞXuSuW)XSHl_`վvr z]y0yj#]}^*d{`#y:xӯ`+>+[Yr;!?CH߇-"·'FNԣ5kv!x�MB(qI�GQ|{e1Q%#',_[!ihZ78KXo+O:@BdplXq-N{+͙ _w66COd2}36C*y'ʦ+tZk 55j`�w^Q&vVfq xJpυ΂0 ?߅rx΋u@Cck- kA20K6V;^?NbL~h+6d x=3qKt e2SNkq2rE`ыa mmAckB\B3s~4ܝ(p<&ex'*i[_KVNK;|;eM8?�uh[kgY<\*w'9Py w~M`fcdI:xμYQ,DW2\2Y+w:P֭;",;׃S'zfu 9A]4yLP(LkB'RW7G;x;! }ʕlb⩶;!2_.xM_}E"'�<ЉQah^jg9ts8pY.t�uMSm??3'L ´p >jd~o:m/s;1 po@!~h_zo3Qsa /5*4텧65Z_ �v}9[k`(%;HRUόRZ\дþ@BbAP<4BN�^7S(2)9 &̐сoƦ)vC#i\Hfe7Ƨ;.) ޓ \s4y%;m^6:?ptWMԎ-FN`{]N  h{.i\ٶ*叼|z"\JQ'FvHIc0@x_S'ι.8$CED)9LMT'#Z/b? Gj߄s^(42rK'+e|˔QFztˑN2 KuV.G{WB+s>m,bD t0 dqz@fL<\6ss!4LNyG_QK*E!)z gΦ =%4 D3<l~҅Wrk|?XWK|1e,#OGSTz&X5'iV3NKpR.< p߱v6i4m>KB |p3�#l$:n 5@?_ϰ~�8ӵ"q _]kF '@#UG+J.])UCViK41a͠Kx0b3(?P1>j|\�9M|E5!ߤdM8maЍ]@& I:Mt>ćDLa4sP/|=5/`ݚ/ǥ|al^ }}a7۹g G:n!<Aԣ/aOeiYVs20RaqNC߳*곆ͮ@y2>*aF"ј:R_7'&1ᔿ'd!zz>m gbd _ u[NOLD8u/q]{@Hrm x�'D #3c8@z} JGǑɅE4Ҥ"u+!^|#'B;IPlަk75weܣ k4-Q Q[s~6w-uqOE7vww*x5?J&Y-2Aٸ"M|AS,+ =xĭڂ켰{wv2kk{^j|{)nտMC y[7a̓~%o:V5.�'*O_hEٌ{�tсFX|f>NN?pO�;n0ado,{rܜFax"|8[lcX4eW�x$ƾ±;/q;!C|Iph' ;A �ߔMeߴIQa9~99LV'̉ >wO'5#~p^oy 3AehT`i~ZN<qeyN}Zfq~1gP:1o]Bԓ'~)t&j?eΩȥoB(%at5y0`u$ʱ~ K8F~m$};a lFuz 7ί4'Gܧx2w/l 0&zM $q6xI0sg<DA^'X3% I;<8y%ItZ~ C$loi  **"dy/~_ gA/uTTEԨ'(`T015iTT=?[6MG8<z*=K|[&�B?@YF>$q6tDB A #>ߟ1"I|"P7*nFVI?7[}}U}]&�:�9< �*PWW2GWVT6 AN{׮nfYΛkh\|Y܉' c6F'Y-NPwk>w:VǥRn/ʀ >jY$ǿwWה*q{kYL�oo p\| &tƑ僷>�\ xiԱ#5 hMcx Ţ!8\*QO8:�sij9;X/L\eh9Oω%P,8�W#aUQR.>#l^MOr wenI\B^nhoi~eGі{v6[; ǎ;h}U׋7j'Q)5~ɸ9O7x"?+mQ`ʫtID7ZXfhynY&%['�^!]pFuhj_=j1}�U(xQA8=e+} #:gG�tjg؉FQϠc%lwOgLᅻn41j}{D'N`vtgzD̸o#a amY[omyA?EFZA*{se`Z-=+veu Z9}J|ԠJ+]:(t Bar \ϱO~9I Oj괧?`FɿG^61|rŻ-S>xˡ7WOO90ϭN8<~/mҮ<ӎ35[,[7~sLrlnnn 3pFp|'4)O;Zz +u[2qN9|0ϼN�こIQEZcrh #?{R%X۷hX`R0Ñ,73oElsbL<%g5,FBa]Ijfe3~n'�wņfAdԀn WM呻m"%F'h� Tt`æw'0֧1?H8'SL�Ɓ3]?#tAKWo� 5b#˨^Xk௬I{Is`C|!$&Ԙ~TMnU+}}2C�4PƏ�ກم0i=nl5^-s⹼9L/aE7t“K2n*ؾ(AQʹ-ZJ:>R ϴΉW_+vf[ SD&}û$@΅srՊ?tc&4�Wy?qL <=xib>ʍ�P#ʾ3ObN.b-0n!Q̰ 07g…/ek\onn6WWnS7L�`0N^wb^#??oƾ_?2wr+;%H^-=1AN{ 0>' aW8qr�p�13 |]�H] 0k�%GYmlBs({gQ993 CT96 ;>q�qd" s8!pϘ*5 aoq <8CFs/ecKVp%`EUCRM`%Zk |5#/mvo޷Z\z)'9He!}_ X5E~XOrB$tiHCe[g]3;剑'(�veO M%^>l.ًNBg "G\I^}o4k)Ŋ<`qfS)fE�$v?~f{^)�*ܳ8r7NsC %\BO A' 4š?9Gf՞&H#!x_JQx6xNſe%cx{w g:tkFͤ#wsi?( .e֛QFW p/+�\N__pp `^jhW@ТtΫ>P*�qM&o �a92�mwȝ8 k{N�@3hOx s]7Í{6b6i;m 7luy?ㄭ44#pKgQH4bn! }_!ʙ�$+~Y)3H;8yN-d3/\":t6jj ݟM *:0㥾5Gp^WWXYk O¬,C>3E[(۟ԁQH#hy]Ȍy_J~=(U�;~*r=R/Uۮ*վh wx?Jj\a|kGۆȨaW#)=VIB'+Eogo�q5d<x'I�w (q5:ZT02![ @{`HAodd8,8*j�!oQ.u?'J[W~ }/@^Ec2I&E'2Q‰3Li/z)e�kD?r �>WXQ{''oe?Ԯb*34s]%n w ћQgDk |5`sG~h(zu[0=+k y 1Z eՂ33~\Kn,�`ŹR*)~;ϟؚ\|<|IbCY'kE֔n2e4gAcLis!bwf|=w xL'~)Ki^I ] gQ&Ϯ[mD>bo~ԁ&ILb-x)ͫJ*Mq#e_s?w«'l?e|sqq|y7o//6 pjZ.Q|%xUv1~hND5ypea']L�Q& DM뗦GYaI9pjwi]|w3'lItBxC\fմ%̿ =Ҿ@TB[ѴLHO<2hv5<O#$S 8֘^~}ag:^,y_p0HiCl݈`qwRxط$3 Qn-W ؞Hf(Q+HRd 41k"}ᛯ_u\E_~T75`RFυ Aҍ^=&�[qm �rQ[wg\\[-ס%\mWfbpG|pF9u] C*mz;UϸN 3&o+1' 4<Of eo: vB/cw2sIw T-N+ƿ�~aûw'3EoJgϾ:B 7Adv3 C#awbg=-{/y/S^ _BU�& ?ױ";%-YƱCIÑӻ�ޖoj_IEǖn1 T+?9�߱űH S^�Gt\0Ƽ>{8a&J5}&~̯ilwoAw:CY^/Qܖ<t3~DŽJ}+f5|9c.1;x53H@cp\ ,pv6pɘ2t,RL^]UA݃ϕRϭOoYa[meFɊİok)8Rcg`"h:Qc'LJz95tWߝ=l~$g :xw`rEETvA43i6lY?Hmyer= 7-sC9W)w׽;o?[jKS&_2௾IZ�W]sĸa/?n ~W5lO�=sWYӏxsv־"?-RڷJF Ns7C3ݜav`>4Ƙ.6^_b":9ۜe-�$IOu| +&Gc+~ .e[&W)(:nX G9f'Q{4k|w=sΘ8gy&= ǭO9tRϤua' ,d@[^׌n(^CF0-8aqI�ȧ�eN$d2�~9 <OE<C"$?>>}R 1 5xp)2BNw}~].5@L:\u(_f8ws \DG G9GRm ~hYN?[Gn%Eʷ?_xm6?*E9EFN8\J[PM3N64mG;ٗ?;|s0h kWݮPP· lӥu�']㟴(0E+ҁ7.0n*eA)E|-NHC=2]ra|C͏?_?y�ğa,dRo7թ(^Mpfkqƙ %)W| -73^8e슸lr �ho{xOe�w~6?titw` @:5 ;pQ!փh~ ~H WFėE dr׍2&\qK2Җ2 مÈhݟ!ӨC?P$«i\\voou~[&gnkoMg�:1Pu&cTMd՟t|dtz/]`UIv8 /+7S�_A gsIFoUխ5@ ᣔ:hՍ- �G0oйq$_O x[xhTa[)~+k>R_.u7O&ԗGK^DPCUv@(v{z +u?;l"Id` 4mce8q~jG'=ҿLcY(O c.'n_|F|dve[ �r*_\Lni>tx,:Iú+5\1FxNq0jm^ºf@ӄh0Cy9RG'X]/]rԡ0 pWX?'|o{z+� `c>t/XŘyh=,Twskqf8aIv&X8F=yNw�C-в.ޜ%uiE;D+0j9bJkQxq' %o ;EnÃD`4D/zX굉M'=_aпars`Nn=LwW|ߓ)N݊A^ pґL'!k+H3WfOt )(eX@4k |5e<A"�/]EQtX_KWG!H5x򨎋J@<3*Y\**nEa235Ҏ�MJ?+p?^<n~<Ċ܏nr2�/ؐ)Jq 5pIXV$_".'ޝZ^9~P!5ߖpPxίzU;rQqQ2}mwdʷ+yG_yOA(T:I)#w�_?F謹;43|ʪ;WyyÏ�?G&r�`ouV_qh2B;tm&v-35摰n~OAs�1x0m-+ p;`]1 `%6Nq@`&yMD +LiOH qz~=qsHW8D0]dTh&Θpgc}:zRɼRtt*[슝gXG;ݒFN;tI_e+"0i"vZ84-K2 IaqPkiGZ'V6}KQц,#+|g\"*^R$߹J#~uk |555JN�Pc2/S+׿E =ECޅWY9dBYwwqոl5�ʹ+r^giN]c'`2&6x3MmGg55 #B/|G5gp._%Hn 8m<h]s+ʵ*oB<p+R2ΥB 7tɬryy&5+BKoiD? $�aa'|p:�S9{Ƕ^x�NW!"w"b X9,b%>2Zh~ʿbo?O=+7 x͡\wwro<axi�?}V۟0Wýh!H<:J1p0="Դagj{#:ɒ򹺫H~^Ծ%2yE#2ǕKCU>„rv6%ԅ7} LX8) Y{ݔsэkK2K⑺q@g80eA_w`Nfen/#XSe#a;.]^deI�g9`>^pg"4xƃ^'f K/o�*m8 *Y5WA__�*2Q~l]R1˧3+*ε#�?ijB-y=`q7r=�v{wr/ݚdt)8 ?Ig4K`с=D.LSVrY6H&M�ҙDI+~ć�XwnXauMWT݌Ce Wlh%1E-xt_vh{ӯ�Nc=4nS7L豈Y3pg %E^_AKoٽED b8, �(yt{tsN:0tp3x&<4imA=_x8ޫ-e.__o.x-/loVtUk^?<yYSO94/4ZmZB:5'lŒ+=Qqb$g|*I57 nwp*x&8=XDQ8Ã,Q!6yizwtM,άkyK _*cę\VGj=.#.yߌ;͉k6o!öhCK״a3APmD،GڔGyh,yCā[Zk 5B5N�PŮlj@eq:\51(:Z4E"5au*?5�WP5cF+z3&*@ [E13q'B(% +$ [*ޒO8e! j[&A7D;ppg`M zAõqENe9<D@-q$l/#7^1, }d^H'N9�痼.׼ w=2xDkHj%j%ih۰l~bud\*Վ_= i ^&PoS\%LY)eR usw{I| �zk&_R(! &8VDC!!>c lٮx'$,tC,_MT pCd/;uClQU'vR r?s:#S&&<Nfw&Ǐ#!` iFXגl�U� .i7<;!;~4~H9M1Lv|4L,=QI*"VFԎU'ZXk:*mMZITrPeT~THWp @.(Y01pfJ �<g� \1?Sk`SB&r8TDLN%>MxKi3!σʖ<FFzggU#q:FVn #~O@Dq}Ȗֽ핓-+L%cTv3Ʋ x:Eƽ|ŗJ\ANc^z.�;<; YǹS]\}h +*e躷-NTxoq`4C73eyO i:3SR~i}P։uvQzk'R$sGr&;:(c;Bh<e٦8?R"+X:/=V#O<5`ƒ޾@a_o!+3|*#/"m])[ѥIG,��@�IDATu"n"|A:sxd?hL;ycio 6\.cwt7Ωl<ӤaiA?2ѤZʹq)k'$xkuk 5K-D%j+ϵd SeVюC S!Mx FDI|]~ :(t{UBgZ3v{ϾɢUV av !FHÈ)mf&-ª08"$s(4*׺N(]p":kNzϡo}v'�ƳzJ;\KNI߱]u$ |l-l|„|<sAk/J9ȌZnd0Lå5h=4I�=+ <Z1I 㺝J 'h7G'Y pNRoS| $1�LWڅOw:Ln#!z*hP)__7ۆ(qup雴g�?q<p7QRAmט{Pԣc21̔z9dNC {Ƥ Srh&aWɶi}D$ "ތI XM;lH˯Wn.$W~W<Hm>ˉ& ɨΌaB?Jkg +92$i<pe'Q&7p?Vo\ *�_h~+Հjң |R P+mE[1{w"PPČ˻B*e$ [6 tŀPx$}*7VomaYFTNn@@'ȫ=و뼁ӵX{Ri JV#aH%Sq{ +pn\8-F-T�TɀZaQ^W� 'T3zbH`: =֝T}f:ГF;O_M}KO,"DSH@s- oߒWP5~ 247Z,)ϺU8If'f l,O6)9j>ucL0@& <3yyxl73sxCS퐶nwO4ЧEh>!mlBOtBy/+璐փJ+NNZ1 p*t4*BgQ8נ4/~a]W;"35>JbD]gb(c#pIe[7L 8Pxm!A?%Lt>`I>n Zk | 5OPN n Q_t_X*5^źh}RMh^4�]lAvLfa.h:Qy*FD<γ&JG^ zQ+H$s>i0t#z v74M߸/waxd; #o-4I k`m,X7\n^|bA|uC<; 'qG]Lv&MX44:�kܳ>Ki$2@#~6QŨߓN_V-s=sB ;N wo^Yak1و)ٌIY2 jgPfdb?O^YG7`~@Վj߃+�7|x<<}& =;&G}USuOv8:E& TCN!>ICx'HA_p8a�8Ni'K:ca;=2;$~T^%W@Rn"` Gdd>L'S{:oͲMLKd0u[= 9mea7w10WN"K'8`/'tzRGn<ty,!ƍnB숧tf5@nJ7S_A &Yyxq̎R᰽ ,z5(XfI`+�'FQp#BeH$sf|"�<%C;r-8VWVPи…;Ar]c ar oPye;+Kv txm˞4g7+t}98L ґE֧rhGWX7{k<Mc_<F?D.g֔|\L;MMҪ D"ae^p".>KLt92,5047k;?([څ_oon6wכst�@!8d^onG%9qc6>A7bu&k4ŵ: -x�>P?LPGwL {C'9DO__^K#; ɾ6iG6rb΀N=!L{÷ zOkgQ'�ݘs  -C<2d[k �R:Tv:n癨gj~wK-Gd?m5ŊQ 1At!&n ⑰^? >t9]w~v-zLcN!X�c=,]:NҔ  lu͊.yELƬnp A{aо; n8'z7Kv~o0xQ.E?t;pT�'l\jP( Պt(fq+p-�w]ʷtnT8rOUF%YH;PvwI+i&?5ͧ ?x/J]ƺUxư  yPb_e��X7/h[;ߕ(*|7(; `=O 1WӪDρ[U� '"NH;ψ1{짮Jsx+҆ ${W5N�S05d0= P&�>S}wd&GskJQr2hx"sԧ)bl&C [͇+=;6Lܲ+ [&IxU ;4ꮍGs 38L0I)%lu$s u s;F9~q$_!ğҥΉsB@� LϷBzgk�ԥ=ʛIH:Kـ "B6~!jΌq816hoLIߴƍ53:?-[{'gnh[%'"ILn/Gc<9 ߲3 pky'N'M~v^ok k@~f-:탺LOԯgfWE2#EӨ}}U|]S1u^\ќ1QUV VA8.-* q($Ή\Q~PW ci Pm:ދݠ]{'�f庌R\Kq@K eQ";z:0dNa<i9wx;r*�t8w<2Ip� ~hNN7'N `@e6:9C<[w꿧+I87׍<H:$-Cӑs/Nж?'m8qM0Grf ˭W pA㟋]0 峀 �D&�\wB N�Vܼ߿N! 7=D1 f^Nz_:&vacQL�.x$HLD: @wۿw`w�\xƸDYvvV@W J�G 0WwļTv8N0=ıh7&==ƮUT==NVWI<G.`$!艦W| ce׎x{h%`�xeL\ZL Lf( [b_F0ay.i̠F'@�'wIܼ3&J Fqm~v4\Z>§L; hu?%#!a6~'l\;_iW[(�:/[#ZڳVjB>Y#_:GWA0(c_\%8z $�0>gT)$ &z܈ݓ(OžڲNYܶc; @ ;I:cp#_Gu|f":r'(B]Eyu6.L;L0nbԻҿ>򞿆;$m]?~>;Cv@ey#IbF#'ԓaW&!+|OV#-EL_zݡw&EYۇ]1t�}xip˕C:itw,q3ߎO-.FE~~.o�zȱtilq \3X w<qܰ{6<pi8u`>D+?2!<cgFѵxK�/^#GGpjE=MGOU 5x/uTph'z3T-r%<2vtvLU 2 ҆'s Nb-]k@KK@JG.w}4.U0i;M>ƌJrC xwƽRzi!v)W =% @E:'2eBzViسK�pʎ|?{w"2*Igadn&mJJv&fx\'" V<wRbQuC]Y_\֝uOGFU}뼐7 tOeqhǁ<2TB?ڥI0q_>dC`s>6r$(f&'}eR 3A+ hl[S+rন)՗{e(r/ပwFw` }ܑߖӨ7y)NFĥUEe?@}HR vq+U>X݋i~$_<7~ sZ;!Ւӧwݺt> ۟՚\EI١S,lUmK W,E~w盳:mI#Qyu)CƏΖV8Ѱce 8/W5VGa&J;P+0l[ ʏ޹0qjVGpg[{gleIѮ$DQb9 ËH݂(- G �4^>;;=؜]^n.l޼}yuuq<?ۜwUQG!B+.ʜ:T3!~b1ax딶"QxFRFGU'n=xVz]XL Ǯʲ#3>Ƒ{y'Еv$G`Vu1pk=c(2jG D웴L4j3&=}6OѯǥyhbyNeU%m/-HTEץ܁tn$-lK>%qc?Na'gAN%�'r@Ag5�_߃!Zw�  j[uxp0Rph< @S B1A8q3.=h5q"]p|gOw8N-w2  4ІET a,n:xJ3Ƌkhŭ[0,H;srM>qtt[.:9c>-ڃ[ouhc׶KS!6<JZ@q.rjPg߭u1J'ywNsΡgU\,ipH";h<A60M4f&ID �[5sprvrpGvNpVB0&+  D¼t [s�uQjQ:id~ʖ~lgvF!J::?<ͅ�xE 48E&|4g<Ak^\-<Ա ;Cʹ̖{?9ϓqrC[Җ/gIuڵ__$1gfv6?O9PS7 ,JbcGV[w?p=):@CilepjG ka=zW(jr?$,ȳ}Kec:%^:9ds ]A9'<;1\ I|(,Ng>=�:vp| I "T)xTյe%,K|/ B<iM <9|Za3uR W-Lɞ|C`<M9-D1fgO8]]ُn8@;3ZvR]&7= �njM N6 p{-:qOnSw XwN|sq6~om\Aw�#vUz!QUxsi%0uT<#j&C&qgf7\1M;Cetbç?7;&NӇ�w|�-/t�:Ud� L�0 .a QJM뢻+c]qٝGE(駐I6^�*gd|J$)gLX2 pI'3II^ꀩWP eBx.t-&̖F:^!,wlˠ+d~4.a/-W8!ilS~ (_$Ӥݱ _}NI >sP9 0�ߪ�Cӣ|ibuGۛdZqHA_k෺Wユ| Wxx $Q\֚Zd? w`t<g4q m3^�w<[;Ο6c`�dګw2#O ([Kf6tqC*m~rZJto"iipN۸˭@o9.3/Z ޴>:  ;Dd<|r-XhdRVd1r4TB}p8r՟ڜ<pk?N=<Z-:2 pvw�N9՟ӳ%YϿ/7߽ݼ`I[|4FG,Z&7/6l U>N2M7nh<ZƼ|N+c[ zs+`ݞnNv8(�#x]ۇ + ;_H[n�\uR1X zU5pfGCאtF{^WIs~+')2�֕A C,yr 2͟i TaY-3C`=lȷBxt8W\l|`> XGRqAe;~~ h!l]yzEB3 o [/=:f6k^LO9:Xc"`5N?P 1~ VՈ3>+hvVn �t_�2 |7p TIVH OxL@2Sx7 <hn曡vZ]|ӿ}44Mš(p`u yl􋮴z]}?zzv30&h]5ϠXL*v Xp& (Q//>g:~gI�.W4;zj?_0 .^mxeޜ\Ұi7n*!m92ў4/Y 7B#n2G HʻS^8]VJe{t;Y�8NoYb؟�3{|Mtiv?b/8++#.zQ3,Ű<VSUC^&gI|ÜܲY"~dZhNP^W=nΓR7՜&zH0gyaWŝ"M4˞ 3?VoD6. {f9? s /6mY&Q4$mD@v+g VҖҝqk^k"{͒\ X`EBן~>qo|�y2"xHw3 ug4"oaow`A3DL;BXшӏ<>XW w/`4c"-9]t 2`09&tQtO0 xi$4 &le݋g)R"\aK/{%';&8͡YJ?=8eC~7 +s8 ֐tξ+_6ӯ>JǕ(< 13M�+ :lϪNO9z$�� 3�޲ }nl6wďqӠK3(ۘpW+'` = Ҭ׈DBFWZ6pH~+qA`ܶZkkԧqC$rs>[}wIOG:8eL.Yh^={9F4A2$SBHSu\hOFѬeR/eN0@ Om#; YaFqNI' X v] W&Q6ZЬ֡4#Ա .LoQxlvJw zVi\4:P kˆ=DP#}외 MnKhDHTI\d k 5ϫuϨjFef 0 KR ~ p ag,t̕E]9A8zj'@MHd�¾&d+̉ϡs!)ԫCcN޼d3xMi9y}mHzwC -iDLpRf;xw{]nVoO[4k%ő%lw,Rc9Pn6Vx5~]WpYklw~wp S;�\J朝gnw%{غkԻ:sb7BhOpdb#431T/\NtHf;ҍF&knM7fR8TTǻLO׷kk߱hϹAx°O[xEmL\' _ pu62Q' ܪaaЭeMˀ ҘNHC:9 elZ6Yu}.Ť$R-FZ -݉$;h$#K|U^*1 P~ Φ06͗t|nQT>mO]ߗ[xNXGXJIZzⴧ1Hn%, ^Z]Ȑ?} L2 \Zk 5@sXS5_d<;*0\ Ue%: |y�Zz┩�~F�.q�΁nw~$K^ہ+Ut*OIgZ1S:肁7oS9Qw{J!iZ&xnD^,+h8vpAZ\Kwg)vor94xV 'rtrsP %HD^M6A:Dk\4tЙb€cv�rs>;]{ͨoʼnaM^dy#<?7 R@luWǖk[74!2Fɋ=?1_Q d�SwL|l7G76?eBwmnAG-%Py DR@âl~DrC͏m3q!WLyP=z':LmgL0Ky� Oe0}AF\^ڌPz݇B`I <gL.~ON߲ y"å,3>-/4<֭zyH} e8=c2]*:Nnw^!/rCF;>WTV% CJ ]4{[bZk 5E5N�|Q5Bk 5` 8Plpbh1u%;Ox*'QB#}$t' ]�f7gbSdzdU@y #c$xI0&%!m٫Skd}tC[;tmMLe|uz\I~4O X_zqc*P 0Dlb`+*4 hkqTJ+vhs藣<; kN8 pv QUGiM~%Ώdq!&? eZϡ㑅a|cS׃&~6\vf'qg)敊#u2Y 9T7.NČ VؐAV0U#aVk-jY-M^ i}`>Au\ʦ\o'v}q {ix|<X ge.,u[΢*h ?2[R͢1ɡ sH<Bk1ռY/|"IlzCXrMK7=_wo _o)v[(} =֕`D�FKWٷ|b\7??*!u5Z/I~2Bs^| k ,7Äi:*=/̸'D: J6]yCmr +�|]�2AVf3%gX~t1a40o,媌4E~';%=5 rSAtzu9:l)@p˵튨nY=00fVɁt KgOu#rC: А3>p*(+xPz9.z&;S|B;:^: ae*:4qi2v)Ӽ%a6lK4ymɿ#󶧮V"7w:YM5$PwC^N} �pRt&;{FI**=m&ү~+ZpT2:VdL>V<hWmX;tGmx`M%|>nE7hHLCAhzCPL^o#3i#8io ֡oXuGKhzut4_ū6/mo/<e'V?imC^ev*OGq?I 敏׻?{=EQY j0>0ohkw+pM]Ԁ]bS$A\K6CdBGH*o#N'k[f06"3|AeTOY+g4X|дD. ,ю~i0{LҢs"FoӑX|fzʛc3@AzS[@|v떑۞u9-P1�O5 �ABG{W[JI<7G4unKݘ'TZ~n;_ursd[ɡv)/xW=?T's2==r6r9TE9 E Kzuk)ІlX(y towy,t; ap>gjpɋ ƿSݲJ9!$#? tL(mq]{\4w@-3I1&, ?qϮ.tl -tگPU-֨0y,߉' -d30 @GAFm4oG t^ gGf9y2ٷd %okP3!4fT.wdZmm{V9 4� C-і P6iݑװWa2"ۿraON�vC!lۙk+@q4l`!3DM > :P�H<ڒw'3~/q::a`<0f-3_lt<ӏ<{/43 rEf|QR9-27Nfh79\ut<9?eP+?o6$xqzr;�j'�ic(9'@;Qhl&Z&uץW Ǎא04ƛq L! J)6 ܃@9z#˾У:VYf,t[ϫKU]έp2_ux:sm["KZ3"Ϡ\fh6.̳1K Mk!g|;~Nx&:|. ҟIʫ61qHƏN \'O= Y2lCd!Ǩ^tSO@=uR'|9LnP|L+&#Mz_pm 4|YKU ZqaC̦ 3(6ǹ{w-i[9Ky6l^xI)7G2$ر, w";j"~LsYd Ozx0dRI]`ZCHYjc:͕?IO+f�㎌})JxA%eǪwnɒVw.gktó ]x5FQ+l'[߷ycR蟪X H (VJF|wH 輆usI7ʚ靯3_)@=u@0:T 4ip~zct8KN;ΰ#;�t0:�4MZ;/LslzMeTؔqz7gkShYuU/`SWsYte7#sH#Jv9*/SM^-ϭ-0X /r I8-;4 5]T4TTy NOS'<N+�7ן6w7:n7w\,\N�쁉L8A�'p"@X ouM%ՍUUe=i;Y =87tC܋+Nf=q{(~O_6OF>h&`iKP} ғf c97ɷYn ϒ<rOZy"' Ɍ4Jȳѿiy 5=k�<;\#E&Ayi6nJs|.<PT8tC׋)\t, Z?R h>HH�jOnR5!1n!K>C.#tгuVv̠8y�|Gsu\3'FmI1 { GphѡB2|<qy~o0m49t>M˝i&:Ė7t~l3OZ;Os�dk' {Юt:(AsmwP -<|z5YnVV!ސbqW=M]m>#O x#[vL>e%ݦ^6P'ʫUjↅ>3œn$ ,t-$^$~(F.ͷ ӆh7w5ևO7_?P\2!ps}�,|I88=s1eI�85xbYP�%kK7DaMM#*AsɶD&y4-u=7H=~Ko|5e. &?|K?cQluP۴ҽfZa|d:^%pPyFfrĩp tɈ7: D'lW>2d 47w[1>iL)};2Qq5vng6mᡏ* +MhcB#5#@\M}y(\ n;zZapXc}l9*Ï1脑Ȁ'NJw*+rb~{)( _qYY{b]�;\7 �5˖k- K~iӉwwts>:L<f94vf W.'�柷Рah@~2`y:0.>$ES-&W7`'k�:qߜĬړ; u2IKpr8Z9gpT?yr> nyR:+Qu<q.Ž'ΏKK\mR}60tJ dċgF}ËH�6po?~|Ӈe쬸-_g_ǟ^ڏ �]1@a(YA$h߮2΄ �ZQv=Aj?T'��9'n|-I{}ncƆ�.j$փ*É&.ݠ,5yuᜇ%z~.Ysx=~.蝮䤿$4B2L$}q/l?ijf2& Z8X>L>׈[ZL2*"o555Cրf~jPCŏ:Wһ;|0tOꅯ557# 鰇9;@W;(y�X98De |N r\gP˃Yőv0MܳX�۬BG\#߲lAA/ eݿ_qltYtۿe:u<He | -ݳ84)0μ=`3L)38{ 鷏lfOL:-[wlYPS> =4LPl9 ys d+4”oX`#E~֣aň[M?"e'pDfˤ۳ڲv;&nUۛk~sU pWs=t <?Vm$z Ŀ֓�FT66T^-+ %cKB̦M2PgIK_*ɫJ@?M꤀50x7l3&�^jޥ NPz.55�ni _<:fI� ξDo\H^5iYVEՒ|N@i !0GT CµHV#{Z]ݞezZ�܀뇎[Zk}[84a7)82҆ ,@/3<Jw־/l@d2g0AW &3OU\xJrKglKqy5aΫipX<|g%: �:U[+j:y5H.N@:\heσQ2۰ӀL�aǍ-Xt%_t= ͍.G}L֦On:LZ%G&:4M(H`KPY$WnxH -c'k5X@=/י:N][\ZVU{T/NIyaL I]k/&wGo5jiާ,r_@&5(gsi͏i٦)#%ٖw>iZr;x��@�IDATg2d67 e 3j(i:ml{A k#*eL}<6]$Z`5Rڭ}!Ϗ>>kx8c>do0f$r_Ykk`ui{Ii*^n=;A[0;x9,�׻nu-ngUwdϙ<:'^ekH#ݜ Ef gt*L\1LGCE Ioay_^: \'2 ;o㆖7?rYVXldbBL<u=`ѓ LCM‘?q%Uz.@XC<Հ|Octdw99;rmNw|>tĀQ*3v~H%` Yg|HRYg<&E#pg'87(!Վ ;=; ࠑѶyG4WS8o%BLiqs΢f LdPaH2|݃;Ɓ eB l %Ti?r~fL5ȜN~M\^]^Ch^(\VC/&@ǡyvObuq-9d4XH6zh򡙿yO'1A/L?Z+\k໯ti9_v)LAt'4M{k?UN j`O . ,ql u a]yrx|^ζYGglɾVn�]fCμaLz)n^n?,w΢ing;'?8/@fy ܉=m ?ʞw$Æ 8O[6q]/\ Ix x([4y }N~@nu:ߢw?]SlǤ�$w ڧ؁ZƕSA$YBg~[ML9fjو{Um}m/@ r}9>=q2l;1޿[E!;5ğ\vKQT\EHP˪C#dC9mK_fFWޭԬ>|,N`rʙUf4fԾ3}ΒFhӋ7=sZ~gJЗr;xg4su^ [^شKt6ph絥ۂZS}ʔ8};<4!cN'G 4N~8x"?V2_wͿkxX'�^dׂN^^ZZ߶0_\;([=Yxӷ8 ́-Gޕ8k`1KBx/S' �2/ җ&Ѻqs<?8׼Oh+vp!{|qlj&eUA^G\+&_8{).Kҝ�[-@sD|'tsջL�&�@�ྪvZ:@{ۭC2rIB0IVy*lW4P\- &_e: v|O}h_1p΋1,O -Rv>$�5)ɣP_W ^+BN@AK' h9,-QzXwб+'DI�yi ގ�?:ϗMo6Wo߮b >33ܿ6֍vZ6=q mř&t>qz>'y ڰ}Teo[Dc]>S@~P?hxŽ5�;�J*�tΠ| "557x~996]x:m{bq׀aq}Wt팎_�u>.X_7ĉٗ}@+:~TQ+)d<XIE9CcVi;CSТx3^`Cx4u($7/YMrCAAs`GGw8:c,�3%.:V`=u@[Ddv;fV֭OJóĀYчCd@3 @Vq{`'nl?ܜa_/wmflsr5(fZPGEj[U&?#4z/l^lд!Dֿ=xχ88HۧM,� O.luOg xͫr ˴}0î^�w?PiT#' 2Q�NNggK*C}/ p]ٯNr+ΦLp}UK7qN@m!AeBV~ t eLѥ+Zegpo8%@7nHB+su|@>Uo.oa6a`w{9'|~ϛS: t>N86vh[t=#,8{Ҽ {#=BZi _{뎭wZ+/{^rkk |] ޒIŒ02w"2N8�~kǿN 88>ettﳿgP /Ϙ l$/WMs|L<ZN~K$aC5,eU~ f,8ψDZ<#72-<KG{#)^5sV;iyO&G9L 5y|,S<}e |?]8R֥ u3/h _qV_+n?v�c+1K};Sw�bs~6oznN�lY_wuDUΠ:UU`\2nO\ ? Ͳ>:.vuچсֲfN|peU++(礐 ^)'Gl_l9: :�g:+6\�J!ӧ-4Wn|'{zG9,(n(W}EcG'o=D maw{\opz=_ -' ~;C^.51!y3UW{ ~BRG'Ϊ喛4CL5t vD/էe}v<U_CW5-,]4uT<QLXE" C+\k໯5n �[=į]k߰Y:.ز t�ش0uJ X( `Q6_!-?2:M9S8S NO >b,=ɃYϜxCyℐz@ω&b]LvmnCul7Al{r_Y?w'=F# >!C#�oO h?DMz#�,2&|J(g8C,�tL�0 �՟#۹߭Ɩ?m.._6o�zslsNaڤscqȩSL?<.ٳ[+4 7h.meCxЄt#y7YN'Kr~<f]lWps*;m (K zQ~D' p02.j|1}`Gm#ȭecT{lW1L~2ĕEƸi[G!Ev$qC֔6i4NP~.;aƒC鯊aֿs.w# GbzD+a9nbwΉNC*`S;&&A5c';>iiG9WWR-y8r`\Z?P h<S^%Cj㮑3U"_:xxukN=QV}?Go[W:k2 d!<dxJRh$#A);5o|3~PmFqâI2g~r@JZu^\8Ox5nȓVWq3a?b.np;:\:ULӿŎ]w.ϙ8+i&-gh$ iYUOmU'p PϏw%mg<4+D腟4nKǁ-]Qi^8hډ\H/q@i]t|7#i_'9' +77l;lo:A'8y&^N:cq HU 3IH7dqBlYz*=Ы|2 ̈́1Ik>ܰ05upOZͨ3_tBn.6U-TbOFbB6?IO@>&LlrpwO'+}n̾P/>M-7=.uLCggy.vl_a''J+>1LF5ZX'� dZ搿<ZXD,r04x~Ef'�W/qq<WRlp:H^NR+_\猾. pj<)^@Ve$e _ OH`%]#/df%W8Zf=J*<X-4k Ma81n8l@FmvԻY<<2wk(g<ẅ7s#<M7O*5e"�y� ]9UN <3A�s&6 �v痼d�ONϲ[55˝GRlD5[,**<ّ8iq g\FG4ð͐5nݛ6(>r:a˄qp.2GL 2N*?[q_+'<'--7돛[Vu7L_h_iǎhOnHESQ<aA(  ]9!WMe ̅6}~7Ll|"~u*/yܫo߶ȀiAad#(0W㿭)HLu{!hPq C|, e *Ԏ{Z-Gva[~0_55̿eڵqAS' 4h rcޏ;RJym84 �MP/:^q]Z8՚9ݏ^/n�@(DBFa\ԡO<.]%-qk2Sݼ+/C<+],?%x['CPk)y*v&KQ Ҝ SgdCd;BV2+7#lke@{^n8Ws2仒\19-G~p3X(4ĔH7nP2N\ٲKI6L{>N1y*9q&12'_niEhg8+ NCgP~=dNWdtmiH)Et(*ͦ47o<6USwbP~c]ȶ�I�gO~mPpy S?ѣ]۱Jl Q:6n9qB8r+uO䰹s̳DwD}8 櫊$]Bt<\oia}//MȒ3Mi~ɴJC?'43t�<-iJDFCΒ4?n*˿I_qb"'h]:gftwμ|D@c3wy,)V͡BnKHi7|5W<_]k`/mL/9 a022qO%Z 7i 8@~ń�;ɳUIf& My 'i `B|DGVOxT|S玶etK72~HAW~ CXX7Ygśt1QpdWmPܞ;r)l'PgԸF9 qtwv+LlOs zyK@ MromE=3&zT:mgzi ߋj{ YiFhcXڂ$ Mqi/9ʍK~YY.:7ey�ėriwdcW�vLxlvk&|?JC@-lg5RqB.ʭaUL%r$k =M#M/1Τ|ϳ 3u~qJZ<)Dk\K,Ѕ?##a$J~~+yy?VkIY? 6ra;`&yV R]{(4wq2 kkF^v-aҼFo{gҨZ-4s<NHZk 5P5D^a?2 3]n Dk^k S0!x&~]rp�`t|Ff;WQk sdCdaܠ@] -bL{2NU淳Hwh(=igB 7b�>@_:e�5'n!bm~�򮰙oNDr.4GZ)!h,)5D&bzX2țbC.ɮr3=yW$'г�OLD(a^ иˆ{(d3Cs.=4x_'9I#ݴ rH(˄қg q\X5vmZ0 j_!ϯ(ٶ@xe/*n﫾}68qh [v sCۚ(θ/7 Bp'eU<oR>4QjJY|a"B^m#φnw<O׬*L \c~ϒ�lH?tFh7݈t@_ =yMĿ %8CeѡcsIx5MoBI m +$|'R5gM %&hq1ir+H̠OH/0(٨W0h-SZk 5X'�C0b^pBmF `qn9+%˒'�zF&5 MT^9x8Qķh=1rT-/H69b%M¾3ɸ9~ϔ`/ ga %: <ذiUv8,w}Mz{h;>ŕ�Ky;¸+q8/$~ P*=XhkG9zɖAuyFO 91qda?1Zmb\Bwn77ć < j0@F\|fu E)S/M\ڠ0ig@Ϊ2vDhaUTS i3T ǿ(semx;&iB-{\=9HN򆪓6m< 0r Zl`UP#4WhYMZθe(oCus'Ĺmd$kP9L)h|%JqMb͏-"?Hח(0`o( jMhᗆN{O}ʧP¿QߟI(˶3�j=q{isB8RM܏φG&q_ؑb km ^kWtz~^5@bvgX 9>Xx,A\tj?0hU1<Еa6rY4tsa[e>$y7 ۙ"I3tboYbI:y >ؒΩ.K^d+pOlL{ B9~^)V=wgǛ\3�N�\㰹 ƹ։3#DZ'2}UAuqm8E^#RڝqIgh$4m|"7< pC2zMvx_ q0{j4ߓm RGMt )@ʒnh8Lr/Yr!!6xmI7drb*]u2Phpg.?s,PCKgrx! akB7&] OO! L܁6'{|dk"�rs FQq} 91`ۥa#}rєI6$v##Cl-LZi|uɉ#sixCrO6h! LG22>,uVz7NSm1UGC': Xڵ5ڏ=F[#`Y!H?-ӥGQʗ$σʄJތD9ys T-Rw\Kg#4e�x& ®7rkk ]H=?Ǒv>8p�eV?`W9v ]Qqnx714l3=%!z̄“Ć/EQ̷}~s}_ͷ\,ɠ6S{Qy#m3e9hu{G)/Y~bBiv0n�gd R넀</u,R<U9 ^-P]7kU"&}~f.�D<x$=vɞ|Asӛ?Gpk>rqG@^VCS]'"T]#n'РLj�!I^ Gh^ hC(@t%< lNY" M@ңr #"w\ -mqwsu㳀 wO88kN�2)`:qElC&3̖d 6!׾LNϝ#҅ў҉y|C{�ל;fy:Nxz'zY(ga y۾"%!`Zzϐ%7qaNW0l|![W gnd:YkNhk&nu9C jӾO{vBm^ǿ>ysA(4'4XW0ф ^j ƃ:@ש~*/�"Wd)`5*V仨C'B 0d3}b�$r:+qP,҈; ~t5LYd;=׬}cU^ $ o(Q|uq\褟/'CKrzi '=lQ] yv�391Fvk#�=e<@qeh<'+f2^.UCijEj=x?`(#C8{w8,LxJMN<mBl&�:OWG{N?e Y[{KU @*z 6)“4¾x3cv>yNH(ԗ!ϸmUt428#rKbOmӯ 8 宓[<k¨O x�xw.vʟM:�ƣdN~&2UKpAR-0;!8Nh / #p'@>~^'gk0+3'AIk9 s#2qI/!9N)K^1IE}{l(Ɉ6w~ <ן0k̉ץm_}mk �U6?~jUquTVB:EW v Yk໬z[;{ NuYW^'�^YqXXԊ U_ K@y:`GcJrɸ&r@qACR9= O#9+OD2fϡX  �U0}v,<sT-Bemo-2Cg]32;ۊ}߹8~3pEN"6rfNԇ >r_yIZ hl~eWo{n1 x*%�U;8'� $;$�cc!.Ѻmw@E R}'s}'Vv۬v쒲ء6ڗ>cM{  |nqEFF8~ -<I1Cf"6Bi,>WÖPy }9]P3#Llep;^q I#;�x�_>+7yN'. m7[E  Cl˺Ҧ)WO).e�\ڎ;/* �nv�l*im:4-tf AzG;}XUR\dֺ}V=l6yJy](0$PwB)?}!O6O�"PmǼJ&i@iqUqϖQr}FWlxhv=ߗzmڬ�ܢv+WW<8 & 1sqe!KUƥg!wyhz-[aqo�)0#v峁l3� QU M fK84n\oY@o!w!:8L;#ɫ~r_ �|_ɜRh:}5 j/: \V+bzԀ6B)clЂ9^0(xl3q=c[: N*J oVxkVo8j[K< u.A=- g0A~na4rYwun*xpGu'?rCжvE9o|! e5IC^ߺ՚Wnqh{3]J �{ )H'ch`ضrm66Q^{7i m;s69dtyM�9'VP|6fMFO0�HDT�i3 Maug|S,!v~3:z(C&A*|knxr)eM^wϤ-2DzG{ërbui?c7lD|ੈ~&=Yk?Zc-kΫzSvW. uM}U5whUXH5BC0n$FnDܖc<L\q8PaˀYȕm:ct&nMB8JOK ]L nVi*tY7شݠ/ oi:t I{t&qpx)g�=ߕ03%�W?�^N:<*v7Td*V#3n&WDsrJ6ߍ̅.�OgD�Fn]9٠]׹a{?W|YiڞJ$Ӆx/O@:Lh^F9 KTXVk:Rxk''άi@7Ƹyxos$L:2K9^XtoH0.! (L|l!%h:ugY4y`gN 9 Eb:Ex[y<Q-e cPo(fb>8pȄ64LӔ743Ls^et|r>b..sX ԥd+k+Ew$6* 2ږBb7$saw)튮5]@G߄ γ]w�rŖSw4U߽į\k_XC!GcrzvV2Ġgqzj茗lf4+¢w=mޜr8K~;DQR9>y_ܣo% |4wn5O ~m,tЦ_iثm휊oYO0wpl܎>ҵiwg?}cK&"Hvx?Ƴ_[�/ߝmO/6 fǻ;�w?17QUT^&F;Gu|O4(c0%487vÏI3":膦|Džf_#|~tz%ؠI2::<<qF4)\ڑ7~C=c:c?HI~[m?,m3niss3ء@4i JsCQQZ&E4i`f2ռYaDTw`søyI3(9GK35lZUuhcP[X&f;+6&p+?BhZЉ.-"&hB[\LD'|E,wq%~J$DְQZ>!6 }_: !;Ħ0:W/v-`?Zcp0Ï%jڴCxjI x9DL@wuA$C ;zްl$r!'ȓnp|߼ ?|v63 su[0z Ɍ<Wy7! cVh>pƖyO+n�1ν X8Y~Q2Ԇxܰ48"EZ$p۳ A^Vp]'΁~wʉqO/nN:ڜmNwo.Cyq:V=Q%2T12PYBjƗKWy fvM XmV4w,+=?^URK$;G!Ϫ8HE#׏9҆a'x'O99�W��*\0Z<4[ < BkT,F:< |۹lP3<DC&p?~Fn􉗙sW=mY"Looyvhzǿrji}ƭ+ѐr2*?vqWvi-_FN}�hW0syFtuF|>q$`%4E>͟8+0ʚ/jk06oTǡ?!]Z_TK7k;RVc#`ظ(z0+ϡꕎql?�;�ʉgΎ6?1lIzݭ5ئT򄇡u?9DƠM-lCKE?YV|d~ٴN* M-+9YJ0t:t;pxڵ_7e[&#g[f"`p3'Jvj�IisGF>W&}s=<N?ܜ^\p/3p�_v N6jL |V?ZWuE#}W'ya|e64·AZƑL{Hq˄-I+m-q?[NzuxN�x c<vLN78 #�LVq�(�c2�L"8y�8`n4ZN�ܒඖTγEBvRKǿ޶6ϖbw3 d9 GҀ2!J,#?}8oO\L|lUW7`B6 ȡoh5B7f|T RfYH7nnf:.2�Ӟ[FJ_zCv�_ e" keŀЎG:U�iGx,9i )JC,K!Բb]k?[˿kguo/}�-{ƘFv��?RZ_X{8: o30g]}2]hF Oub:Goܭt\/8 )](*"FHd 2RiCrqJ{H\^ [|}?3w {<>Mg+x9�4#Nx2(z&$- l5$ykk`;Y!(Di >'rIw9Na*~W՟b'�83&�6o\is. OƖʼn8q䤫cqǞ4¯[scLony<E_h a4#&㧡I L'ygK? g@coU~:A7l ()@\ߒ]�g\8 <s@'&jI?Enp6+sDZTV ,]G;ߍ rvv)FIIk'34 &uNND_w�6.< ҼYf"r 4m~ek^J=)/7h\;3~\ǟ6:! ,`!>R[_'c5yZi]�@'>x+)}]ZE <b}ZyV^/^te̯XZN hK: ƱUi8r<*3;-G^_li%r?VoqboO{cv�8*:"COɛ).[CG0dÇDK#jE 3(_:'κ"gN7+2YFizU~'8~:o[;c,6?~ #Vwe8p_.*ΈeEOW?zj?rC;vɀ8BV*N\?qF[g? /lv9fsY�g �')fiy._p>::>3q-@3W) ƛĥ2U/cwt8Em(_Iť%ގ<Ȏ_WPQ&q!�Y �Ng<98''VO0hg_'R9k|%i�qQ! `B w 0�?Ng?B#8!mR+~RT^qr(:ȔMU>V_.�粘zej96snhC~:}Ét*}|04>{`եF3,u`~ZxWt =˕z%mq~D{ld�: IQm: 0E4L9Q_3*0W>;S`mQNg=[V55b7)N�zbűa}|  2:`G؃v'tA%[^<n~:5�/ r�3TҶTe`T:f3hCg!kRҏy:4;s:E !'Aſկ4yCMIӥ}5V9v`[q@5V1l |qA#CIH'#|.̘ xp&+Y;w7@IZ;l8󷛓wc-�-0QЫ{dzUZŦφ;o?鐱7M?ahfͫgMJdREƹ _ mV��@�IDAT?samvٝ$t@!93T�MXUo@GC$3yOH2:;2>쌛V`v/9˗]t؊ zCw἟⼟qgOs `YġYfܥ�Jp)4R:f(u ҰP (412&(Pr9,ׁG9.'\Әӧ3> P kfg[qVzm3+t38U-voWb{, )舩 =3s>-Káe,d O5͉1GZ*}deFOeZ]r4YV"vZk-z ktlcV8;Ype7db:p4t/9s#:Snh$ �nou{϶?q|ѕyL-/> +5 x:O2'/r M q>3o#etD堍䁍/I+H|tfSwͤ;jx4c5rgT7&B+X[P / F)u K_�j'vp��Er{^Yww,�\};nEv LX/ׁEQ8skq`@] 'v*c[2HrxqCDԸvozPzfP^x} 4X!iԡCM_% Om'1Haf|wR^x w3&M8'2}S9)3Gej+qalUlJYKS5hTA݋:htI|i "aŚ\{%悁qiTs*GTZI`Ih$N)!A-&J>ZVμf9B$Wi %:]aȷ<d5ںNk`?`Y^ f댉^6<�ԓ&O`'5UgxQ /,`kZOo? 8k zm/t[-),Л '4?4'mgG$ @϶hޭ˰H�_�[B޻,�Իj wF n);"\<mQ ;$s3#3A;MfLo@fAU]pN4SxL+oFJç(I뉭Ή./ �neVޝiy_'sY'i fP<C mƵ.aVx 4B"X Lv @q$}�+q|#;o|6EzLqɐρw/݃br#).$9U 9W~QqUD+=%ճy@lMۤ81tp(G}zh h&A>3 Om iVm脱c4y }XQ<uknEp6P`3^,$؊ꄕ2b%(&epPIÁ뒿⛂MqߗW:r:5Tl.4CpSC,=nqimA4!Vcw$eAVFҍ|L-'qd y!oDn]a+=4#-;:s狺WvWo$c d瀌_%:IK%\ikoݾJœ-=l[G&[L2tF # ^ 89f'.�0+r{w.yYtd'v#Go&F3j&F3Y:̤(}̥F Fcfѵ|0<M=z(8˃1@ C^I�0?x^j.eU tBGw S($. ` Nu d r8(JaD!q1+�')Gر`=g-qm#Qrw;ypv0;ghỀ@ZO=@NFZ/&0` kJq8+c#zBa0eMP:Aͯ 361Rod>RmT -71?]y _�}G/x%;x, { PEʉtEЪqk$VkT@ϴ ҁr}A)=Zeq^{78^o.|E뢧`<a"ES^h܄L˅ >LMo=u>G${Z4LhH/yOQ:Gq[7߮w:\9x>*1Ap]Dh y߼LC{ғہ e{.olm?_Zm-Z Őtѳiz )2,& &NW#HL&= .rꂇ|y֚8 ur̀N:Dh^IG</ ܐ1h^37+=d=ala_թI Q@Nc~ t:|�ٚ| gw�{AT;7W.}ϥ 9,&8]ikQE[Xe@t G8WGxdG#w.4 ݒZ~sΟwJE9Q [1xsM-wda:z sQtS6Qnְ@dO*7Iv4ʛ4mdlË:d�aXw[ub+xdG޵O{[#L9,YuH<_T3vlv n+g{-ږ #mP9Z>×$X4Mz -9AYϖȒFNyegH$Ht,/̝|rP)H'Dl.Lf!, {Q .Xv؏͙rDBGf8K#N}yg($ ʎIkHlZ`[�kPu4|0~eZ״˿Xhi DPB9;L�I Tϙ0ʋQI32A:eu8iz s0Y5Ic򄩒Otτ4IYthli)X2eiؑ!Cgd846~[Y gn^x7D}ϾY-áGMHix*[d;rXqX <$I!?; RaeMï9sHD8 p `ࢄ3<]{qixg&1zJsk?||f/l ̿?>j?-q4| OQFЃӈH$8U$vY6dZ} R7?i夷|; XN=�NY_8_KBqэ}l;:x 8}I[ib)[vf#ZVj蚀<-C:Iѓ>A/<UܽW6Rb}TJȜh?a4W\=� 2?~/#vQ"HY^h@+D):Nu ?C|U/w=C:�S!<FEw Ѵ}07S:qK qY˞22/BIOiZ+ⵃ[)=ixuś­H 8&�fN>$ߚp8WdsФL u8qќr/tfoX@duHyB10BRw7$Uժ;I1'aVYR JQvݴ- äm nk_tU߶YCq -0kWt1q';*5&=wsQ vzGgؑ{ޱA<xXWb)"{qtF !uzry?sRK?٥KtY#!!;~:҄lH3GI6xV]|S4tCǕT-AKs(s転u|u.�F�PpזFKVgq'}ɾLɹkGj+clE8cPIeDh$d8C[Ȇ`dX Zc})*Biv! %%*)H:QY<_ 77iG\{1I?Z΄I Y 1$p=xJ9c;seFYd9d:.NŅ4 ;i?8im U<MhtcFy XKyZrVΆn1F8!4[Z_5-u l �oŒNzqhyo8j7H3Ita\GӖ2eb|1Q'ԻϤ45z-@M>!Ϊw8=k?Ig£dLT'iVYKd/ �TӤaFvaDZIF$eXʡdM7+ŋ L>So~d9_?f.|g�t8IWruࡧ2!USlE:WQ�2,,kۧTf(niglZHh˝Ecquy5Q|GVı 7hwĵWqOYɍ^ 4SZnXI'ci^@WqHӌF`95  ]Ytvti刃~4(@D9Rw\-B=x@ .{߻ @>{= ? @|nT[Z§LRy iT#`'ceeO%EHvOwLtWU#@ܱ5"R wm|w@0CՆ:0MkKBt>Yi&&J`&k2LrJM3*<ah>f78Ul?D37P93&tWI)S]'.+rzyv7')'xF pYbFy<73 爼7Fp۽Gv_ʋ#o"`F—gqqV\:xSf17',}}`ꢀZ$':A.tYF 9*f'yN3t+?w}f>JFٻ^/䧼I\Jv(\`N]4K伳zD,�v"?~t/0&4`&$Z2ub+$V:2N~hr1:z8hd cqVV~_uD1Y{ ύ<><~B7k|awc~ku}1?.�^�"zHo:m[<Fy[85HdT9~M;b{mq&hWV~AX[~|7 =:Eqz G#g:sx. kxwv�> '��\q  /r1@g싮!0  VmtկA9}w,DJˢ4߳`zG#9|\sTqw{gΕ/P#:f@O4I},k& H0vtM]p:mҩ 3Cbl/=Q.eYk R_V=$<'Dy-@])77[ýp}% �Yމ{d!!F..^meJxjlDr ra +n[�x>džn-}foZ~aDSPK<B'S;ƝO ƜG5qxN`^/^ΘX"[7c] w ׎*S؂).>׀]uyѻ #P]&n?c-3Бoqœr` q'XEV:c"Z⍧Ӭ{��d1 wA%w .qs{ǩ,9prr|}":K\Ӟ}_|N}䛦 5SQkTɸip6/rЅ 5>AƩ8 +ŠW?LpaqG<-|hS9GǩiGpuw= d1( �caJ0 9Q< ƭiB9jŶ?V nS^T-VmSq0OB �\~vN9$B}'T_V 5$Д+ޚi/śްڢH=_KSy>nX�ȣSعr/k�{m>ͲP+�ZLq@Ms-R,Q!j"nb xqA;߼)}| Jd"S-l-[xbE&wD2aDۓV ' |Z; ] P^g ×n�{,St|9�LX"K02M>igr1UW㭫q?k|ͻcq|?.N01]w0|YǟL\ pC+;SNJ3i �)t)h<^VzZR:9g�Mc{6cQ+7\x9~uOǹP@Ə, >8rKy�# З^}9dOcw$}ը ׎}-�֢��\U52&M'qe9< W\K!mHَ}Z՟AȍtWN> t|e£Y(0vۻ$ԅ5\wcv�(5ww'@p!�b,xF@icІKV?l/fHlNs]eSjtB$;a�,�Xќ޹3'4˗0wJTuUlΣXZFuwys4Mk}5=qf@O3d�[^V/cό:`VCzwSx?,rx kCx7/DmwU�877ͦ߹{Fڵ&5!\38<9(sc&ZoRV'% L^Ӗ7CSmln#'"6U6t_Kk괫tl:VXwXQĮґ;S# �: Ƶw_Ý*1Qv!i'rt %2#32v3i#v4Y'N ݱئP7:NI�ףb FQ&NΛ Y::lY Vwˑ+63@ӽqX Rο8i-h ?5ei 0@E8W{48002:2B8.MPieC@ ‘A<چ*]!*S~-qS�:O�YpSKqk˿'wW ?#4D[Px �fU,tlۢوm~9�/C_/!;p,i7Tf;Mk]Rޝ*,+oMF1 զ=I;ً�/Ê="\$QMKLkJM_bޞ Xm_ Z^十!k峵1o61ɘL1N3j"HuT$qN}Wr|V.J. @rPHʠQ@ЄwKʿKzV~ _u^tvzmj<J#3wpCzl;)A+:ҟcYE6CC|N?eiYcX+w|;~v3pv젗׍<g1lPԗlzG4zS]Nݻ YdI)L`,"_Z*)FMc\# LO;@63"zRd$6nMHP0\9x|G藑wXOSVS^ 8_ (GBnf'X"X,DjC%IW$o;NQSHͬX#TApSS yi̊bgǖ+V9<w7x:|C+r 2Zc}Ɵ9Yt! h뎈<]9 U|O٫mME(91 yʊ\%IM9F.F ;= F!<y~tMv~ [Zk& A)''5j~O&}oTJe . ЉJ{o wJt~ɫ6pLxC ϥ/aK.F_k_u4}J[eXA 22ᖳAlnLGar\:̷2?e-S3q;[Qy 7Lgh$d 3 ~)8}74I0/�8nɻv;|;B:k6YL{leӨ$=%vqK<qmXגI }|~\@^c^WZD^`rS62M/}#l@Wy^ۨbwhwQw;ڌ:Cf;)GjƂrߝB"tc�w:|A/x�zH] ^<}[* l| 5ꬁO/^!C;2ƴ / qxBy`iS āG4295sG':mNjzwUG5ݚIgk]ۨ7 .ABߥr:NKv @r@Nkϔb3iUh~^ɯFBh[tkn Ffo?I0;RZ,ڟ|[�x.И58Zl XZ`փ4邑1QXH'Q+Xrj hq BqMP*TLL}F�M׿] �%Q^MD5&^o%y555`Xsx~ YmP1CLPoiSqՑb /sUM)TLX9aM6F24baF e k<uk<|sx_xVwO/Y�xۿ~wkw/ӫ4v^gQvYv} %J"=SԒ7ε #7Mh-GyXˣ ;.q:"!xIt :r:,u3q e+6#_Mw)^Щ hޱP尽3*{_|t< |d7/<ّdT*`G[K7{ҍX~ Vc'|_%LE t䏝^P8J%Xx)w3?γ_QUFd,fNJ>$/%.s𹲴q~rhH}KpB_T9goXr+@_XW/U\+OȊcb1K `Nq+n-Wf [ |Qz(_)o3m]cv!?fo؛`e4n:)x;}щΐ=!=qʥg €�NROn=�/>[_1q}I0rk2es[58H4k9Ѭsd#4R |*G6pQ34qA̍lnɺf!I s_ rlӭz)''r we͡:tK;EQ99M/UZ!h54~=f�q}tvw8?`xݝ~߻Sv pƶq�#zm[ݻYrBQ4.>IziGh1R-y9\W8j>?lzXAIo۶ /Fi;:&/ ]l_Ѧ NE'yΟ�=̛%O>ˁO]<~}xxA#3<3_Ȣb@{Å+xQ7;ҘҒŻ"�q'Wm7N2:~X'UKf.Xy+~�q|Ǘ�zEK\|Uck[^J)_h5kGq˾Fi;N:ȿ ER �]YFrV%y[Lj SWEܲ_`|E傗ܜx"�5 .j8‘> ru8D;ȊkaĉRV 4ʶyYeDYiWm\U32�޸1㚌 3n7sɑ^�p"! 'N"u3qEJI9|z�rW;SǻQw}NW Y~'_N9"wָui})aNV_H{m4N2BPMt PUO 5wS`̄NGs GN#<c{duuʄmx@?F㮁殀D % (|uГ ? 8yxSu�gݼ?[߱; g38 �S5|6.#r:NlЩ(=#4-^c?Ȣ4O]v\KA[eשH '< LQ_{#":zd}yECCK4GEx-g9 (xqkA8fCE� w�_ ~5@ <,,G#o_XG,\�Zvj8|IeиxE�Phڄ �=Aw@wOi �pɘU#Wǝi "݀B9xV`zq=ރxh (eyꍺ&-d3Oq 2_ҽI=ltr<j Il}Xa>ÿ.bk gV3cu2ָ5pGǟB;E^ `v 44Z"hy;�~#<g n-Z�[,slve orn0nӽOL0b5p&r2 EI&ԉj:y.�阔D)z w)~LTI O. 9s)NAt<E[wC7kvN~1vȆWE|J%^Fy.tKG<ԓGp?W�'Gg?wO'G#8@;i.8I /`*|qnN<s.�#_ w?d`{�O9|~_[q�#@[|ګ^67-qŚ::sq!y4kAXȪ4.04XهA']~ vC�tqڡG&2|3[ cہ_ H#7i]H8_,)-} $fF=[.l\hM\5s`J'9]FRi.z+F1(IdQ hY+{C;|@Kb,愍9a[$&L /#uS7iQgUOP;*:d{= ;@##muTaŪK.3KŜx-d<QS=.ڷ 1 kq9$49q+nꢇ >[Z૶مUKMdvV&b%ߺ 2j[Z+4tܱIs d&Q'VL9:,ْ*!'N8bMlM/Y+wn]C7aD' 3 ↈyjB#\S.By:[h-dŒSAU2oH8#ݡ8uL qH?qI_&HK�04n9q,A:TTHd*-,Cܭ~zHbbmllx�v,쮾�KֿŨTS4i'3q6(B~<@yi'qZ_/EkG44Q/B|?p48iA,VqNvz~yKSR|œ9FS{�Ks {mmzgb+r=7K�n~ـ]v^ P^GHV8BndqlC m^ڞ 5W= n,*a$ }Ț%MM#@Ru6ɤ2ʽZ^hfm;ʶ~X<2C|dt(}#+KWqc�Y6\{ 8 +5+�^gH9M*UX<PQљ<۞'1l p̈-Qs2Z`i°IAwP@ԝ(q'ޡl<~IR=?d{N'߱N?w|iϩI@N`,p 5Y)NnHS3*&Huc#Ά2&Zɟ4G8Xi-a&0q$-UnR Qsn͜P�ayҸ2\ՒBtNaCβY;,уrOdxw*O&^ɲ?<HX . `wN�w1 4{~ĴH>,]:<M^%[c3m7bqc6F@SUN=f`Wg/F64M3p A[1&0U-Os?Z<,NbC8W2(-kNɄ]N3H''vJe~<g'/?;@z;/XJęh?*un=H>%:a1!`# nGS qV +]"Ƽ6r,:8ҏ$旐\ zc I?-LAP,Ai%0T]]2tTYUfSqQj V˒B;w9>r\@ww}k$'eڠD 0�9\Pm*0@ċTם-l-~ l �99H bxWIJ MNfp'WZp ;.Yq?LG9�O*iYIX9IZEОc 0+ v2t>wX35I&n&Fc(D~dc891Ce /fK 49sBهMᩳN:?y 0Ӕmduɪ:w Suus΀=; ȧ�},=bHߺ9u4-Li.0}m/-YM-KJ5 %+fz־ܔUB7y86M| iAh4q4lвʐiTthCPҎծKRlsu!时iu6F;F;Ҡ8k8wgW,�o;#A_U9U;~\dCu#4g=aZ[{z~䢽+i-J1x<E AzE`2�uD֖L tDefCٝhϨz"]0gf9Gi$M1@ o{ .Ye`8ÞNN=Ql:(cL`h9ڵx$e 2_FZߢ6n�oN <מxO欤yZ̉ēāNB++MEНP~*+_6 &=𮿻P:яnTV0#pN5 1g)VWpdWwDs;AS+2YKl#.-'ҟtR >V/R_/`-Y͝&W/XyCD鷁'.EijB"35vㅀlp( l8܆{boer:c:p~B y :nf~λ޶܆*^G.x3k!CUQhexCH `0}3JXeQ&Еo[IS7ִuv mXM%~ҍ[ʓV~z'6VO_Ր.6fB\Ege#@EZq$44�lcoB4Mx yC[Q ُ.�Ш~ku/jMvP"$]ƭ<(=�ƏEעsMGYnDd7M8L0h)̊Z7E<A'r1ؗ>EweanoGBGEIbg]..?W &--�|e`ul_Q_Cǝ($�Ly°ϚNs[pDO`/:7T^I K<" 8̩2 1cyu y(YN3*xw4%}ѥ>3$C {cAJTX):'©W;oi7?ws[Q4[4U-#׎N^qR-gd˾yRNvsv nO!jP 7$N5mPJ3s6;47 jnD ym褒t(Jd8vr(9_MPxRN`ܩ=J9Ƀ鴕U'ac$܁b$,͙3n_ٔqBmk|FڮzY>Rퟕ~ʹC)ǔ۷S{v^J $hG0s(xstb#RqUzKt1d$^3=`Ii$ȥa;8ydF2GX}3^36Gݽ˼*[QHf5BHт•65ɨšw,gֲ&r8eZ% ~.lB"=ijZ՛c6ޠ47F_+H_0+YDo1[a[� P?c45 oY|-0G#0  �!ֵ陼Bsܳh*E ^VgNlG)S p}Bj̤Ikt)yF@A^!15NtA5eZT2 '¢ kf~N}=wࡼvGx!dBir��@�IDAT_s<~#I�~^Uɺ+GY9z)4rYtevr޸Qk0@ٜb-)biR:^tDA?SJ{<+OxV9Nor{ϧZ3Ik#!7G{MYb /[Iv9Vnymxe7 2.Fd P]zCD9  ]f499~~x5|ڂ4C 9Q]d;r@Fx-" V6W|GhLm-g_ iv7gf =j,3I8:>5mBD٧S�Hzoo}-ŞF6aU\[x$/)x }!%+:DiGEkV,gt ]I2)DvL!Fk]肕NOo$o;(mE&be# =%of%W 2E[ E 6 joɦsmm`mQ<d݆ѷhM/㪖ɢD2::͝OXNB<_*&3Kd d+t⹃e ގӒ3UަI-3kOf[{nZ/V"4@v| 8A'ch:%Y#Mh:[?x�X]�ȣ'<P_n^oѭӧ##tiEī|Z EfZCE> ^a=o[p7/;ڟCnqЮx-i*o? -y((0wt`> Hp_ӁK_G߸A(`M8i4}$]hHm/N=o߶㟻wle9|)ZlhW+ؔwɎ#CbCdޔKYQw?ۏ8>?|E,;(0e .zMvnqc7wUme$$ܫV9NeoZ>.MJUZF~>? (1 iA̚*7tZYxQعD IbƇX�ː6/Vw]77ǾG!4waf7`S-|`@4nyx s.oB 7~mޮ-zQT_o7y[�xcЦDm8M7crLBfN $Hpb! 8 ɬAYU�9S'"8N|Ϲ-EOx ?; jz(Z**m z�%(N8<r" |)ʲ -#[�,>]�7Bu#�qbug?F]H6c)oCJy{qTl|{xknco39~ĮB7Slϧ rtB ʣ'8yp~_fr~SNCG;:Q:.ty] ( / 71t;_y;u'8g¯Jsq̅�,.N?$o/ͨ0p}QxX倈#4?Ҽw7[ Aq|m'ދ:Thjҥ !�Rw(=ϻOv?/Y `Qe5LJ=;@yNxURhm/o?8Zwq_|J;B8YȄݝ/{OO6}:bnÀ?#3dic"pe0 = >U(cB[I#d~TttkP=K5Ƀh%:$h7tGvZ ;w~U` { ` }yiwASZxh|-,鶰4;/3۶�[ ( o߶u=OULODM8Ы &@&۩Y/Αw4y_4b/8>2y7�~;*)YC\59 uYWh _z\";rtu^7]x|'?3tw=ĥ]~4'Dij/&t:6n[f;6y:Quv'je�N񗈕Ĉ5cU|;|[Xra'8'w%]?OGrG4ri בgN_qpvBWIh,4�YH|wt%3 $Z&4 atKL8 ~%fG.)`l'i؄ ҖJΏcy=ͅ[}3Qp�t=>#;vw׌U?�� D.�ēq-\��נ�ՈBL @-}\}VЕΉӲ5υ8w8޺t+c\M=-G>T~yŗ5#4eްBrǡi-#˾v5i ?+h/)44qe,8Āk醡wvI�8\O]ב?$'\#36Dǵ=6 ~�`[Z-Z�?7m3y[(Dd"֡u-Zf+S =OG<03@ن\Du4wMI3t@<ș>S&8N?0qֹCV`&JIoj[Wy.~QoXt:K~㪛fU:Z¦u9Itr3?IQ7'n?N|&4NOHx'y&/N`#!%o)6U#6Z&dr{?6u}wow~prNT|Z^Gɴvur7)N}uxq҈vJD֓ŁW@7O [4i6e KVsGx=vCMN:qLdtΒ#q*i<!nJ<TR)qp<�; m:zq~277mj5*DYAP6ҨR\B<J/ ?Ԩ=Q#;Ҧ v[v܀~wY"p=e̖MvթI>RzyȰ*/>Gw;4δ]au4pLv!f|}:~_KWY@ZNYI+:\3д{k/Ҽ&<�o:gaK|;o--e??T=o}xܴ}N@$83'E?o-0~Ԝd<{#CI(;N/ 1lK[ul'NJ9NlH:?2M<H˄ntCv>YtU<C]?~B~1i[ZJ6!-Duk4'&?|?/Q;N5ur' Ļ:c6>'X (#yh 9ޕ ڈȸ:q]*B̮}+;�;u<ˤ.KUa׾4mO;:aBWj�?DUquz+4+v+.r`u~SF<F<A`$?B/ң_Gb[(S ~ 6- 8Xv;Be1ˑ+ɂBx;k}Umri>+Ss� [y%S�m|i糗ꃾKyRr o=' +X[Xތv(-H:wК6E^#�W24CN418P<:Ga`7lY!=HƶXX64x]pރb+N4y 4b$^6)K^OEN|Ќt\a-Л^>hUn-[`[�xEoNFd7noWjZOˤr4 s8?OKN{ueYARM̉+@aՋ@Gmސ ɏlZ9 Dl:0|:Nbܠc^o|yRI;yߗ�pMŵ픉' zYwt錠K  hC8k Ԝf8|u`IBU �G+_ ]#++薧?ׁqp|_gBwuw-2kuQ/PE"V4a ; <stx�ȵNȳ̽P0Fr( Jqll M#:,<q~ d_ȃ׾ӯME�s1CJ 8j' �)<,о6K|c;S|SV.=4YfvB+x GPLR'B"sT?Ny9Uq~K>_kk+kӿ$.n]@1*iivj't;JvCO0pHtQ<zrER"2NnެXHrہX4H u~l7` dF(;Ą2͑If8q'2;b3dHTϤwl5xo'\d%/ʗ2+2K{$i*哳29R_6ӡ\a[}Y^Hwj1 E ,dReDFC((2)꜊ Kt\^w /.OyBd)3/ܝ?2etVx)*!G&;:pmh᣹wj瀠si) '1y4/9 GG֡Ѿ?ڏ @b_#/hID̷ǹ1S+O O:;@"kDF`#B6!<OI8֏iϝ$&r+zR_ lKXIKWx8 ZFAZ?k74PشvT!zUP:hOIfP>}oe5ohNϚ+iK'rtD(ifh2P}c?\3<g \EqlPWF0ר8U\U1ʣLBK7bykWj.U9h+<DY�fnox9kj/tqjq yz۲qXBw1&]wEiAL.ϝp˧~QUudbEߌL4X~m^SoKfaje29?#m%K:k:jl|]0<g)*rɡ$]59Eps[qE4r HnQȔ\ǝ (\Ywf(>@=p}!N};q1@=ߝ=ìrc3ҽÊ=eхڷw]+Vqj41 ZWže"'M&FO|ќI+gڜq5w+_3S"]&>-䎀@{h�rXyxהf?,ܸG +$<P-o5$6\o'$>FcKyw l Hj/[i-TDJMLc$2e#ŋgi3dckr@}s\z q=ǥAb] `#X3$-Yf|]Tg x>Gʏ槌vC^r0)>uggtOH܏hI^x]5&W5�%=|"I3z[zux$ Ϲ豅l[xОp:9Ȥ oj'C68`: ur) fi)qhƤD%9N&8[W_<//|.YX>AeKY<Vuܗҷk_xk]kuM�Cqi|G5gctçpRo/o@d<Oy$3/ɦp{|#{nLJ-ueF\X=<`XkQ,8;,/aY4com..5w88Www;~r.� vuR9-sa+_NdL @z_u̠,Gx5)0'aRx!v MU}XPܣ\@8(@W �r(H !Ԯ\i옖6p6ԑ'ꀷ^*[|ޑ\SBc�~%G\0y߅ Kh.�X*Hvx@ChĻ?xťtۗݯS8(�Gq؅ڍUc �.^=/Yz1;ؙc그c`[iV|~V叹;}s5MhxZV4|^n�aaↅ'y! h9 O8j.aօs f)\нNŽNwOA'.m [ J `p!ο#^--�E>ďdFݲm|<[UZxq&'1J R'Cz&@N* -ֹ1DF;MN23s']򮿎=s'A!>@&;lN԰Cx8a?LG$"#>C Q}R,̗dgptx;M:tοN^pp,"P"oZ, S2SFD#R1):$%J,ehZxYЉrA3^�8> �wq|"��X,8^).EsqwZ׊D|Ёqh葧~uz 2yGfRV(-q˖ C<xqN<.2o0qxa 2NEs r<:=ewOڧlG??~p i\y�Kg#㡍 �)Xq_ZE�Qh%"XAPGw#-D#e+^礏0R, ]߻Wc?_Y`z9 ˻j8DFu#ʘN(h$L{տ7r;i_+JQ[Hǻr^7~`<K~]�`O-;Q|׃ ? ,܅5~pu|*8R (eSXitt[ R htg_I�=B ;1m͹%P x&1;ϝwRBi$Ȥ+YM'~Q�xWuExljE�朔iLG \)0I^u Ik<G^Nࢣ6ʑ|eU&ꆜϊ5O:D~^ ==I);NpN,8 v$M"1 P a>;NN.NU-N.ƑI)+6 bH%Aں߻~~@<p._ @w)X�X|?r)mx!ent.{`{I2spN}qVr5%8}؅]p:z(;:yk'-.JI:N;u>#�Mj2 ڗx6~p3F�>A?SYhr b@݅~j2rU?^AZ�`H̾2'D%RaW xmw^-G!1u g%3Am݋;66LtALRJW.5if[$,>miSg-[t>\n\r�]] :rWE1n5«#ԄXf9wuAJ҈A@ ^+Z?� idˈ[B2'(<yLbNFxd%EsϬ"w "Z-%~qstd=raw<τS΋y90_!BԁPѤҳ}}NgBQ𺒖EO5H\Dyw|~O9.!-dyABO:H1`M:%2P]GbuàLE~FD6%Gkҁ[ddh+x:k'οuV[ɪs_s_ D./D$_me! Z,d(kb#ߑ\;I_Um.ߴm-A~ nٌ sjB' T3͟`j'BivC'�.8k=N/3"_m萴3"mƌ\8LġFoH=YK`2rgSy 5u>wOoq׼y<T&$h 6 eӋ";H_㯅:MvNQb.U 3?W6x-os˜E ˅%˪l.H1+ޅ6EyRC$up &Q鐵Nɣi#B3y|QifjFBUO(j؈=C?7Cф,6<c.xʿׄ;ldXA.F4yuu s /"+k÷x´7 oa_S5޺ʎ1֙nXdҿe%(]%g * rN*p<w33Mu}{|enwXq=L<uxJdu7c]0hSu+rB_:~ƑqbXؤ͋&{jr5p<x'ZoyQ9jdcNJ‡6K#5 5ʨ5NS"QOL3q021ł8!!JZ.�Yu{w1dG/!O%FYʱeN[vJ?AtXff5hQJ oXXLyua}auK ǡ&P[Ir #P IHAiQg95規opa.걽i! @QHw�P xA޹O q3E&5o(7~8'ۡVhU׸x/`Sn (<Z#u5eqGX.5(ʬ+D A*HDz0DovANܯ.(m2v>]>#7"*lZNF$D/Ԍ w\?-{vϐif|k\ud4Y-0y d]>uK*sf,}TkR7dkWmn _֋U/Wz?9MhӀ3>h'ׄI<<ę0<4f v �*wv߱�#%�?LtLdN by21CiAwU%VX'\D|WO]O1N&ϸ' *@+`N(<%92cawþ[m&JzPqv:#[9TfJO\BʐP9I!g=67Ħ%"+ Q1yUFeJVc/4/zc#χWm1u{ڴ w2sV1\4NCEd|8<5͝AK;/#:dr 􉛕r@q ,OgB#Z\[$v&($n&u{I4$ֱ##mJ'fڠ1:}/�O-:c [-峃\ F\̕SE}>괞B `~Z-;AңC.#5~;n8<TV&1C!K0H3t)3l"Ў JTiMOm`-d~mVѤ'CwYVXM;Il/ t,бkβ_6o $QK u .�Yj^U^#Iimߧn-[1_1DȕXC�G|97U cs[}goS*T<T(qe@ȗ'\MDCe)WW9 ԃ>{ݙ[|\ڿqng`k7`54&>/z[yC^(dY#pœ'R@Js7ݢ)kA9 RH3L"1j' ~ʨyC =T$ųǟg}+7 +tnMsj3iꔮ^6pܞ%ozUr ?b}ʪ+{:rV-v'ə=mK6l˯N(& (AXO)K"Lވjqgˡ=!|adz ]4< [~妼IsGVr?:ꨒW?& +ᡅ(N&>t}fخòԳcl͹IE#`Jt'K^-K[ig1ڔ1'ȃ 'pbdK r:mZ*or|ؠEV~p':Έ=TI6}3ZPU7d< r C3u#t|ܳ+.Xl7\!{122lj$LsATTD "jaCS>=3%0t7�qk0׀W dq�ӁF 8x�\A 5=,i#~s[8`JqLfZW?]V<ƅ7yCZMo1.8Ou AX]–nVA[5b7\.�Xit:8-OHK2'n6�5b!w%AyjKx/QFAɁ>+2ûljL�<P`L6rVyRqmn&4"42-M驂*O)]|g,X|hIBEdx}+`>,�I‡:/Be>N_G>4⸕Y^yNۂcv\ŃO ,ߟ�|KOfwyDPmŸok /J=:1 9coe؈P9*ibT< ̽ "8g <UQ`\I7l?%ZTFNq▰UqSWÏ#?~Qex . _ُ+4Ȏ.:WgU<U4Z\ AkYW ɳ]s>K}^Qy"Cgd$Ė4L'yI6f8 Ll|ҹv^%O�u8֞L S{y0ʰzW\�@ψS9�1|h8(6c9!*z9(thNb?m!| 茫P |#bCܚF8'|GKM~FGG]ƗEU_δ�ӥ_7T ~bA&.Fq1ސ2A{lA6TGsýd8#:qErUwW T[0#F-Fog~:8ܜ`51vN/aK9ȎW'B'! gX7o> 0I0#,er!4UAFg'!t m#lZS1 o>L%�j7ouhA\ 'N66[[ g2N�Oa_gN1;QO{g` ]p!A~$�XW*Kl#MIދ39A-Ҏ4QA /-J +MCO$hX@״ sY$k%j?Y*!/-ULSƊXkt<&+[uTKubSub\.$?Rѡ2Olj& TZ&NR~E cXYvx/%O�tA??jeTiozJ{ <|.~:g怕L̸m+f@FiL;$�f?;#^N 7IA3*M8|Iϟ%8qͿ4. r&;)ۈgSӟoXxuʳ˴F\#1ARY �߰2pK-#P 1'4/\r5UOQ62H%}/^-ndۙJ%P֖eX9A~K*od/䅾QF~Z9�_p?xvA 5|U\>@`֑=ui$#C{XZ@M7HEYUdRCrP#`ha [Rl\֛n?6l}]mp&H&cfvm?_Y_iD<(�y+3~x> ^#?9ou׳0DN�Q�hމrN8`~^-@qG�tA5)B.I: K�~:u@za} b Tb#˯R\y҆b]W=e JC\ܩҟ ?E*j`2<~p-?E);dYY$8-&nz 140B*g2)*ITgN/bL Lk|.7}uhXYH=Ofy_ ÒtL8X?{ |m ~;N?.?}Gm cC e]cH\\yk�OJCp x,c0 Ӗ%ۦ5<?SA b` !HRNJ 5\*v*g 7=&1dtF`͇<8Q:h 3gk@Wp1O¿x-DOOx>ёp65PBΕmFhvwx} n󥙉Mi%0Y iӺ []F7|=<ˠs>on� 5�{1Lf%w ^CJ1=_Ky X1D@ lSƾ|@F^$2,>a˅7pqիy<R0e1 oM :ȶM;1`.`Qm7=/k&n `7oA5 @B`&i; 4N(ۓefN |9ٟR/?mZ_ kY |.6gai_N(#'i`5AaYf\#ۘmoo5&m[#> &Oi| ^wJH?M Dn�[/+Ho'24r&R+_Zwԁ3'Yg*& {wր˽sd鋻~WP ^u5uCo퇏uU`K[JCg-vz#K}p�A9w)rg=0mb?:ՠMBR p;$h[+My;`q9sN/غŊ| v=v~k:FIҬ ^p ܟ2D~?;xt[}ʂ? ۭ4Oga!�ԁe.d*k LLWk0YZ64;VzZ@&8HUr0]"a=nnv7a&h܏rоY?PX?U Ν`T{7g/~;bW�|=iOvrLC{AC<+5гRzh� c_W'bC?/|ʬ@y6|C6 {c_gԑ;h } 1qSd^D@m"iYQ֓NÊWO. Swyz{x49?lu5@sS.跭0x �dwån EHZFp٦&7|)@Xznv' µ=چq=' wLѸ؎w?筟ns2lU>P`qIOr_$LN*ʮbڞ_S/noݥ w W:}vi&}% Q7c~MӰ'}&DUZϰnj`D`w//,E ͏lSڽcw?lh<eg~lqH2/,6̀0|8>>4nJ?#g[$RUDooX[ZTdwϾTv VW Kӭ9~v2TI?RodH#‚82|w?vo,JðcPXIke6F sJ��Sc/GBI|`X7~և}d+(̕0V+wλ,˓&�Z �a.'4 Y?g�=5Corv+ϙ� miSD7E7ik ,OkR 8 ߁$sQL�^dZjVq"9x-B:i.l3 Suuaq֯CV4$xy#,;| !B x1J8U '=M#.qu5xIpC|aLh5�3et,%=@h� f(1aHU׷'<tC]NяomG4\Cf&౽6nmL8AwBFC r@}4K:N*+~*:g|qU > SNu>ÿ { 7oLv3D�jo;+}6k3 zfsf ~-g|WTo|-Fhó{ |y <-n/xb �O,g@bPQ3Nv+%%n?ˠQA@G"1r5NC_25 ʠwr[y1`mS&. {h[NM+I.dS~9ۭҴ0B2^Q"&pG&wp&>ur0Dpof{$ ׯ>o1nw@x43tX|:1EFatJH.\kvWWvh]��@�IDATnVϵf 0k2@&5��'4$o^]\r �Wݦ1ReB Fl1JyeC7>9{ (|&�6٦mu CpI[ SgR'\>1cXht[!NGC'၆0Q+43Ɖt!oE?9h3 p_�[&s\مfoU,[HIT\e[b7`T1`UWa}I gpyp0ozɡt[ 0n.߹.LW~~Γm(qI{1M8iQH.is#v%nil^ !MN?<LF+&`obOvXY[UߨtG7$[h١&}TQF;?ƺ\M oL&,~| dlg1->_8j]{ |u |^>7gp\3l p't J.9G(F n/�dW�mDgde<\T_ ~ K1>麡S2WO'XzOYߤP\DD/p9,Ozgc5QP[ s٠*d@zPMl\EqL&l<EqHzeV`O7L~`ָsWx�[h~.R� )?qI2e\i3j<iRe#8Fhlհs"Y~�3,2~,Ig^tѯ:&0HE?Be%B\~V+cz8Pz\–Z WݹJ;�3p3gٛF^FHI�= s+]T'Xa0A tU#04@O&o G+¶)\đDmFp|sK<wىV.9�zv G+!JAYtCMT})^ܧx/wִV_a qĭ45uD^?0B57Pi+tH7+ôV5<p 'Si%%`ǢKCf#-}"|k{^Jef԰'ibp k J l{mUJ!7+L\{IN+'?%DTu�Lq @Rh/Jlu"nN A8H~*@gOdmt̟?J@A׍J É"-cp柟MX\v2EA*W?"1,%\ĉ2[8^ .pGb<Pվ1#e",0<s8?:PF! naz->:}'MI&h,[lo{[+o:@p)VAR)a~o͉Y$LveXZ?y02˹+ځABkLEgXh2_W]bI0y]aG'OȲR2 z(OZš*#6˛4:)mUqls}Bs{ij*46oAh 3 #Ez5zM z4mj`uW8#[\M\m^+a^}:EEɟOy~6xz.tze<!U 9;:@LxL_"OIDh0wAɪ Q>ql. nA^_Z6"8_}'�Ⱦ,V {o_V;%qH\.~A Z\,f>R�$e s Om+\)Q_ _#ȁVj/䞑gaZG7/q1#09;#c*sNÖ9UgD}Kb $"i ׳ؔqu^'s?MPNX;?46X o<Ϊ{ -8gp@�ϯ8ͯ�%gK: MOZ)qг\+I2Ƙo&9[cx5�I85_Ѧ,9S W 1g=g@.̚$0~W}WjE|}F巭ߦN/M#fv@`W8I�^@!$)!s9S`Ud! Vx&UDU*^E)`cy`-: ڟmE~ڢ,}9<ՇK="tdW\22|`1?rr%~mM3ºзa\SFU;_8|]O^Q#y @N\|QK~1uH(]HF)gf&KH8?v@K[Kvj#+}-u^H_)42P0[~a!]'`yty0؇B.00�ѧ2XF^s'GKڵWLOGi߸^ѳHLT,s02qX~/l$b&&pӧ$CԪy JtUM"md &JW[dNq-׼7jEQ(W`_lYAa;F_$.tN\!b@x5?dQf$FץCp~xB-d8� X=O`8gbic_>a}0/�пgW\/_'>D�M뾱{d|uo ^oqCs07`t4r`:**xp֣u_F}KXa /'q|6y�N(m?pM0`v{_7#e�oߗz `_|6-2H(S[$jxx(F-<fpU 4m/}4H&큟>vx|Iq9~s�k�+J.?*#W/Х5+$bh 2C/VcmÏtR nk<#E_yNӖĚx^ ]} };;6gG<8us>׻l6g57(-jX,:n/+nOeXt'%@>v{CO,|72k |k7Ɓ?cpH!F>eK?x(+(jҿ;DˢӣbºMVZQ{o䮲&\{<8|h[_b̧.9[Fݑ~0?c20xX Nhvc!Gt �4LYd�DsU<C+6c<h9?diq.*WS N\M�|ȺWX4.^5* r5)|,ā,kUOc,Oǚ/Sxؒ qg'+PSaaMo\?ê7=8ۀ2{tqBhI MT#xYDldǀhVj = +9u CÀr{~ @(cBr2@ P7&'O.ͤ@pxGN|o @8x{0DN�TvW8'mm?5~Il}>wΊ?}K&W'IDktܲB0)I#P~Ke~,/WMmkoyͱ?l}kK7~fdoоɹ# 9%L𩶗էp`B`*%E%@;ٙRSJx|lf+i h@1lg"\ A7<kШq_Cy4Duա D@W_jb`L<0p)Ҭ&1v&Z2ٌ @dܬd!\̯8Bϸ6} 6q;JP=>V?* 4>oq_RӳdH/8T+a_?g�a"�y7O#ߕ$ Om.c˲i g$BZ>Qx_N �\J@t̨qm|\cѯO8�3pAiٿWg$˿]0 p. _ NG3M_c̣ڄv�kş'9)C!pN6)0[$ѫӵLXpa c�1 #0Ƈ8 2>$�&O\'L#ۘjҹmN8}hq9C<ɒ2пC;Jփ>D{ϳ�K˄<C8^L\Aw8n7� OSnr`hUoLH_v}d�x ~۟[ڧׄ@Vi\WKg?_z}D!ӍI@;^rƆ;;c|& ENЏOuucධڗY7va'OEgrk"g_yOүD@s_3{{\9⮓|ҭ>ݲS35UUͿ3CF<|)%<<OC 4~?qIYQ%&%x}.}g1ai .h|wƠa³RQ./0=\?z8o}Uѹ=Un qڅm&Їw|xdMxIs§i5݁WXZ>=V:|�asD@YݺK~VURiJwHr نf`n˪6W: OlL Դy'a2_XE;!?zci_pF~KY-׫3`V9�.U*ηIP(1P{Jb*e?mkmO/4JdxY<)A}ଃ _/ kk@<#ɉy?ƻ3"`^^::ٖ)wz]|-ap1HgȡԱ =<M@OfSV]x*e[T*0Z.�f>E|O+ ))Y�.2:ՕaN СG y`x,Y;IkbW>zd瀟d'׫L!E%Nz%K_N՗OrUrTy,eJѦPs7K1~v ~DS^Nf>eLb8ؔ 4y); ~*lid?SGRkJTG=@[ t ePQA' Yc"]à<jQ _JW?`3 _+FկF_H|Cw\pu11(Sg2-˰N"&~"K8m_8g8R 43HzTF2g;7�0i/ѡI7:_]9!9ʗ ln&QDFa/h�̧zO3 ?6~ eX6 eB(`Oo:}|!.f sBpjUq4>?~ۨFcFܺ:kO~(�YDILo,+g i ϰvJMCʋlgzwUwS)um$XYg{�1,^1a-Ejb&9aytoAՕa#@&%x(̽, t0o9Wet' hd9%Bie+ ]\ l|ŝ"M'~E>&7R Z@ti&|$d'*Sdbq4w\r[tpŌ` v PM?6wO␙{7N VO@w{ |{ I}]K'~x wTKOn�A2l ^aǧ1�88,Zop_CcA V^r}ϻle+j:]H;rI#n 8pid*'(Q"nWI[ZmLdMQZ+C5E~K3v=zл8"; t_Z5| * ؄,ï`%5-otMKtH%G`u0/C൪aҸ)f*y ZU>1i0L' .B7;\q6=?SL̫+T+RIK/"kȏIIS$ \{T~Vگ0RN" 'Gb,H +˻ɖ?lH)\ _~EYf˜W^RuYM9CG({K( ՠNBK�6<ұ%i*CLpL$#`M\-B)6wAx #!+1l2zʴIVb)~*ΖfkGb*$[LcU."UFhWJA&*0G_tgn Z8X??{5&nh#p&ŕQV}%! o#[SW={4w{ %QG=Z׸ 8(ln/xpRd cXp #D[;a �/َ c'V<Jw 5~Zh ˌk/ 6\D!#HOYO'Npx֟8u|�4 k ``$=q ċsзw\wηE ``>Wmo&ts@yₒ{U⢂CgfJc2L}ǠHFp1J=8S~Z-q8DSͼ*1#ufJ�*3sy_^\ۺ0l=X4yA|p ܡ˿ʱMsj1EwTKT}A_\E xˡz&pO~y4ztȄx-%{W̭H@N,L 'MRԝ%<aFm~ӏ4ZT*N~AH[0HQ9)˔,k;;o161{,ʏ5R9_=dA0(6@#Y+~ҏ (r&X~]ѴY/0] l7 A!nZ- N>m y)|31g0JC;&خ8Oђv^'�>Pcͮ^r3j8<Kϵ<ȷ�<!_8} { )}x!Ql# ӘR $DV1۸AYV20'=e7Y 2}xd4!([n`P[L|F(o;*;q�Ӡ5]oj+E9� ~[c7QXU8 ]ZvGgh<$CX C]{_a߀ zDt| FڃVHY#lRDb\ 0'?lɷ|o ";ԦR]U4/jmA&* liBٶxT_S5eY^C fFWX&'\+0d;*>Yv_326a>bkJ Ʃ�<PO|::0wo:4IP2!6#-nS Ռ&\`ODE8Qam`¤_E <AzB- S]~M+,#W&)K7WM+J`XsI M* "NC4 'цe`lpmekܤ4L^LhK@QyR~:l^^1CA|^3 pM\]yGomv!<ٹ-c P_,'~Q0)M𪺻h%pjߝh^�WIO'g(ynO6x8$f\##q6~o22@4.<@ʕ3/�pU@l˯@$AՒ���Qd\2}N^G|yO3t$$A0.-Uef4;�|͉^o8 ʕ<Ov\kH G3LV?+-_C}Gfzq TmVT@ND )p,,40\0=R/cV�и|ax|}sZn)tV(;x4Ϳe$O$=LJO*&YI"�lI�X $WO<5@^I Lqs|靇⯼˗ɂ7^#0[lt b1fN/3SϨÜ2_(I&c؛+sW3'AM>t- 'K^8\JAm+>x'|!!ؼd/ y7x;ژ}7on=~ަg6<%FQ� lr=Df61d� jes]}QM1-p:8D[i!| 53#g(t Bش |Ț ŸX 9i jKJF].auD$%C}IyrL@a"H}=%#a\9Rc=+A `tĉtDn$B՞`SGNo)j O\`䌌5e:BV&n"<o#,[.VUp7X[_|"_-7 o=%Sυl1bࡘFYl"h*bl"҄^S?,H{W|<E@2kDd2O5`*|SF]eu_6&25EW2kϓw7L]_?+ie1z-Aа G@+ʘG&Ƙi/] tgƝvhiΝ +Te7gZO^͓xHH;pN8fCxPo@ɥEֈCYs=g=�>&ܱѓ�N8Ypk^$U!IRH)?JLQ)ȫ@UpqxCQ``sCENoY˂ N!WYؾ;^ЀAx SPξEwxl@%iG<\$ bA-= 7SG  i'~bњ?g^?볘HpJGa/Ijcq#$?PC/_Љo~}4p^-i{lQ}};'E3ngw8) cিr)$~_*�E*H(M9= ,^ˁl& l@߳6D"fK)# ugVo ds6YyHn oڭ"xЄ6 }$?-> >]色7\@~Dx(-?ۚ ~5`=ie0?'4((_#N�**[ϊ,4lc5,[^4 2q=�[x�+ P~7aZ16\YwΎJ '/�DCi|N]{=d 8ЀwKubp*U8Q!+6hԻ/#tc)=7l໽& E%3hذZq9D1s�M&vfIEf"* [>yFIzklug1ϳN0!p�>�NZ d�g:_5)PoL /<ϡY_n;WdR/rlգHNUmYɢ+emcg]^6:'~]_H/sϬ",L9q[`M4,~9 jSݝVu6ᗇIg47EΩ::ʤ};p+|ާ90qLy|ٗ>`ˁ\(^ 4.gw{ <h}ˍE޹ǕIe O(qȓ-[Ƃ5g@؁zVexۣ)9+<FRV!{07B8H`Bjaa1[qyk/x*U$#2Ok~4cY68^3pvOV~R_$Ì 2bP4o7d&1쀱U,mO.f! +4xH3KB$dFGk?à#~!SX~6x~/by 1ͅ*"G9NY7LƷhXɲR bdq|>I'>7Y f�0 a:> ͳㄴbmw`ǘ!#ڋE Nc߸۝}|G;5&`߻o_= ݿƿq7s `]c쨱] .4%LNsLrd�@ӿ\]§>6@zv[o^~H ;%޶jɚ`̝�HvH >'p{ }oކܼ{Y υc/:Jqmav)(G I}([u:{>EiYkҔ}p  f~>|QNeR /Vؾ<{2;䷾~ Lخl' @ vK%6E`K (_ͱ۾5#>| )vzC8T႗u7d XQ:8]}Cx =KV 2nW7cSX6g:BN%NcGL߈oA[R�~IP kSRzxy-vo �xp>:u� ;6N k`8AH]`$۠Pk`w7U|#Vy*A8 i11SqN`]ȟ <<9oXݧ+͞ y�9hUW:�ߪ!Yc(Hub7< R~M, ~q0E'p:17y7Ai1 nGe8ئ/Քa<d$<ʲ- NcdBV;"_cI_85�_p\>3ia 2F\tDOީ'%yJ8*i`բO\Ƽ貃4X s!mz }3)Ra'x;zsBW7bWSkun#Ni+y%>]8,�u^ٔ8(# pdv-ƃyz8k]ѩkrw[^s'_tީ ^{t{!ޏQ1MpҏF$_2\lGK ?M{hA}' %@s2d»XSĘo?}f N@0Qk;@t.HqAwU Oz]se7 c0xQuKC [0~6ҨrP\L&� ].?�᥺Np�A$ʣ `VV f75<b0#u-jcejL?thD�g~ri߹�?�|P+˓y勼`\u=Cs} upx>s$SFO94ps\0?THֽLIM8F?i3+^15(f@ٙ$A^ED&~v#hk{+go ?�pJk"Y¾d*\j|z|+< ҟSJ 7x6}݋3,\O[ ljo6qℇJs]8d-[viL^"z}U�8Yl:[OӼLX^S%es\]�ym^zWw*;/m{SǪ En *9�'r+.xB hCY< 1w+}rCӦ̠EG$S0@+KV azv6 U#ee5F4GМ Ȥ�t ¬ݱm |vQtԥ+[uCVI: _2C^P%jϠ-+?~ekN ]g�H}gO5 A`7ٱl"­bwpiw>6�2U^zSCĨN{'{H7]�N`gB;�c yDbhu2 r �, >_j+@Mx vV+ x&�:Ϝֽ|\ T /R8~`i'!mK5a.�o;gmu?S^W6I,)s>˧8/WW�|-_gU0g3WNOcWN_' X8� oHw�k ]mI>>~`WM*]-;f@#?gdABU߳ g6PDӝ_<?{Ը)Jˊ0[Qko?'~D5a_َ`JC޾}<�~厦n݂sN<+4Lv_o/#]=(tɁM9i֩ )zegrS6> wa �wŤCtBQXH]W /r[Qomu5X^0},cGzU�`^7xM&>NN yl@f@^>E$TvU b'C4k.�Vkh]^:0p (i M [ U BW<q0/;Ȱ:O G 7O]c Z9@1bvZƯ˵SF! N$i; *";=27*ɇ$S0&rWy&34ʄ� 5089u)Nh ,>J}.ZpH[,d%&Ref=U_pjG+n <8vP~}%RhKI 1)ѧ̯ Oo['eF�\m_)4BP%9pR NZYSʸdT>uC?OX]J<_&Q$|eKNo Nxh );UXǓ˲I}nv b=UԯO(Uą+Po Pxl#;?'6i> 8Icz{ ,%q4@ydx 9U?Cx$C\ *-m/1^r|8fwA}4KN'ȧN=9'G=6pR/< V~{ ׬p#Ta4id! gqƌ8&΁!Mz=e$O_YKvP@1VRӥ%dN;ÿ_s =#jЂΪnxI0Q\F}mruZa!sf<vM<]pbtDN͑Y V㣠Lw)'\) @;nO99y ʧihg+ΈQr$ ?r1&/ ;�Z4^epAOB}c۱$x(Oo6O~?O.5izsMJ{,jg|: _<7ٝ<[x4+}VVE㤼g `rn_F-895}, bNZQ=VQHUf0$d ,~2N'�3[K 3;b >8 ->?I/<x }aQv{> p[%gϿy]?aPI<S/}>Gl 13B[H8;I>/}d6<#1qVh+qx4ܲ9KVSyqV~ 10ߑF W2Bgzƚ嵽7le?NQ\ GImgjCIc!{"W��f֪s끀u@07�Us{x~v[YlIV8EjvB Se9p#{<!zG$D/j%\v,eQL>ۑqK|,Tێ8#SQvO<c%[`r'cD_5@~o Zz-pPHbS*g+q8qA=?a[ʎۀCpEgzù*δ PӶ }tFW\% W/yΆv\")p+Mx\[%M݊N-nG9#t$Pm@Mq eCkٹ:??g2~ʸ.x&<@˾?/+}|h{Mb|\x2}Vt}E~#?FYVOH~l �?|Ncv`SQ?<=ikok7p25@o|z�?&% N>f_<?s(_~rݵD-h5�9V>돢0 }32i8{3>wx_a{9!`^Orvu ;�+McR.A3�s]Uq Х&Ozi:a._lnlH-u鱄451co�D`&�0]tvog/zv�ί9��@�IDATMZȩ⧼)ЗSª/aRC??x57^ <CZV 'A`«KnlQ[chd?`}pYlt1ah¶T7'-N5yH$y~<[#+{6}nC�^9_e]"v`ʙU"~P`'^w7Lo mҫmT](1繀_t;4yJv&s[)iv'ǭ4q7xDm8p?Ey| |__lW͗kmM\zVү{>/F "N�nniNqɁoů\ ^Kew/Z>+zmO쏚- 3벮A4v7K`{H60aN')^xgGHW+ @N8{A/0_W~w쟿3�8 7 u;FlϴF6-8i{ipmiLtAp�%A tqSVÕ�V6xɁ=hon"-e<E]e8<) 4rPRؖC.pik.�.>?_x·~ϕI7K<~r@c\L*iip'2!t› p!& ̕0Ds'<c oX:G\H4 %pcc,$LÍ!/0<yfR=]�2ƅKNmט砿ԓݳyρgT�=!L<CL>N+\g�kI /]|2J+~&X %N6i1wyWkW}?Pt �;]`Ld1ob?7nŗ|l?%(T6�UnWp5/,OIc{x?9g3'2%38~"τ|>=S޿!d�Ryg>{gmJ~RkUO`Ƀǯ/< v}/~r.v#K&r5?H=v8mm}"Dwt0Ǡ@;&G�9sٿkF/1?.�'@toNu'\&ܨbo>bx,[b!m"oo񕻥&hB<,#T/˳9fײƋr�QuA杕aXJv?աi"`|$9{&\2Z'oz+Cj 8e >";WF[ix}F5k|Zṗ-˰>:<pVO]�n�n[ϮN$ŋ02"ہL( p7 =}:q5[x17y{">ɽaǥ޺vJ~ k%<ͨCpOq|/+| dN�8$xp R'?< Kp|4qL]�'(0'@M qʴrXO$=tYq@hOq0,+Uïz)^Lvc_]zUXxV9P>x*s:K_/5�ބab瀓�/3`{{ҵjS^҇7⍨fc;bgWo-WADŽn*-LFl9AoL%eõ`;qAM|gpeb }�q.1.1vb\v{{a&[ћaqy� A5\@ )^OisQtMGE=9=ߏ(?̭k`2b%&seu`%jrk; BcFq,d?<sV~?̊_qa_7ƈ*m(qap45tc 0~ǫHEZp_ F%O1k( >^x&/#/tk|e*UgT1v1pg<e܁mtcj.:o{TVm*f>5̴Dş O_p'[X;78 k�6!� �_> kjNy|;vR�Kg^�S8 `咭1WXFH@fr?Ƒa *q!%z d75Ahcd>� NT,__[7p+}?hhX84m4bpᨃdQ#Wc۶eLzM)nw[6Zm=uk @EqJ]fZy sD!-}bd@a6xJj֔/1HT(Hx, SAW]궰}!ŶƕB4iD <6lg4>_@SfYMM??|/F_ ,k'8|aм<ttP#z|x/ƜQ6wnhTukyA߉Z^m[p]!֩.4q UM_Q;%P͉4_=OÃO ߡ:+מ$~ؚN ߰>O ek2Po^;6Ygq=<W3?_O_ PQ`G XViAn')Xq 4Sn[ކop(=""mvn`A+YOm); `N8ƚBm0 "(8YHMVnr8޳EzKaZ&` Ds^C8&XGnOxi]DPtM.s_p0!y2 BI=PPq%1gKtE 3Ɖk�>D_8]{*6@\΍ToX.mGʨ (a{<' ㇕{J(~7^ �)_`x܃S;E0fS<玒E3(L㶭xi$24xd8a>~Ih@y萂K*#x$RI r7޸-"яKүÒJJhwI"CfӢXoYiS$I%~}^duJK$u,nؒLAH'KjZH�ayG<Â'{!_}= 4!@_ڲuI(J)3o&V2إfa`'~w{ %)} ;%Z4<=璔Z1ۼjY rF생pv) 3) _r_0=+: 8~ޜDGB�Ш(od!:(lrV|ĥG4p[R6*tBC$4 M}9 TTUD;s'�+e0qD-_,x "q/|@7h7k:2ayx78YJ0unJL4Xg:9F. H#l 6 M4 u {*7Y7!GqefP'T=_yz|:NGI;8MT.P:II?:U!1l L1>e"{j #Q/;<ú~##$Qu2.ɕ !Am7 {tCD𶉕!*oSQPGM]3ji[O$f&x.[c\AϹqQ�OX:o851 n7TE'<G%Gry[fFx w4rhmE|{yV5敖[w1I<G7$;.{ҩԯ%iɈqt^{ />T{{ <Z 0}`x.f@44} +|^/Dl}Y?EI[.fy[JRt,#%/AK/tyV;A:3"ɫax"7 L)sHS|X5f2r1| 2$LKX/ۆʩ:J 2$(>1)TwN(*q^l V;Oتy\L)rWFh୓zV{']l1o$8;P65ކ?'a! ޔat}+>|4𕁡^㓧2G&^+˞:ɀ%ΐC~  WR1�NəR՛e#R5(82~aɽuF\QUٴ/(}J}g Gɷ[z)gқԊKoz9okVwrQqI?bMn"I5m)Vgk*g~97;4N?u;JS Ǖɐ+"@ޮ:2ƗUK[jvSJj\ ~>d}P̈́yPϠ //$Ϋ @v�}-�^ H +#w"~mT2h^&rV`A<> os|g:k?^-~e�2,[ ͛ǔ&kY1Τ˷y;3O1߰cm].MmPz锕d>qAɼJZX&,U8*?[K<Ce7!dJبUxYa 9q>?ϝ[ԩM:ž=mݫg9uޅ];M6'`}aw4MK_ПOWQJ#rQ]iÇd?GidvnXfme*?+qqCY̩NrU& va| |"/G]Q7 =վOdš,x*u[7SOtL-&i7ݾS J%v6-SJK7ͧ'}ّk bP-$EX˳YyzAX<\2NY3{Ws>cr5EZ6ϖ\Mϵq׾¸5'%^Q[/{$)fóy BwЧsQ[5,-^Șd)OV+ | ;,0mxz0!;ҫ ŝ?D &ð<s2 e3 œaO.Bxw=ͻ3?+�2P;�s" ri ۄ5;G7LE ~_ &-<_+4t jD B(,i##X v±0<x;7or 'sP>6eԋ: mKRM=) PI&ؒ {tW z|e]שg"J? c7nKJvےHJ;XM,@ Y qW` _khKWqpYh|`i’`='~-?u_0m^ 'e%_HH._ ֢tk8 .O4`)9&0xŜb c5TT59co' qR:&7N;^X+sy3'Mulv [FKdCeWn0e<B8-o*%ש$8t4P[Y@kz׵Pc7m_ԥBIȑ^׿XeRfX1eӇV)jT_N � 2}>>CMY8>U28 ;FgeDczTS"&vyV2<KgbI~_d:gd2\OF4MI0nIԼfnAS %?SxYuE=СXV& |dFDA7vޞ4:Iߜq�s/=7iO>�T '=4[dlD <4 aB /97hT(;iU5\%Yoy]&)4%�"^g84՜I#o <qbl2U(u.`nTh:k5IG?A7JQkTX-,sʝzHcW/@ԧwE�x/V"]#WtdocKч p>g`~xuvbL~%�_`q ?B@ b70u`4ͨBq>nۺ2 %h$JB)*l#"& he\[Mhq2꯼|q)C(kFܕIt$Q/h1( uxX<!&[)2t$7˺-) I`QA[|WRh�\ee Zm3MSx+:O5~ t{q|)5~2aʝ-p \s jpv&8Dz'_%*O]4x3srp诉:rw<to&=) 7^TL6`c�|Xh}NLճ%[܇haHJ㡤+1hGktma*7m'4^=9._ttɂCN*cav0}B0<vsDP:^ҟܵQ.XdӘ#Vq&<f^6u\״j̧v.0ʭ,wݟ;%w͚uN-װ4ڹ&>g@:.kaq:NF 3OSڪ2v9}Br`й>3[3E.t~C>Ґ^9fw츸ÿf={7?ݾvi__?itW[ mS֤iũs"Eڀɜ \hdEV Ozq>'vY5 OZ .V1"%rx]V5(>I>SM)(gy%-אwdx&yE~6°v#!=^0+�`u:>e~d{ j`T:-9nhw_\st\&Kƫ.7$cCYm/4r:k`uz;tOS%w NN'sy/}}5y�;bw\dL�";5TQD.AG{hD kFn\M^];{celء$g#YIfA6-Hz&dB nF?}ɕf5y۴^#$ed7o>?%~lbv Џ�z S~͇]OuÏS&L J'I<`: WO-mI$1e"zpV^m7ߥb<[keᝳpį3,>H<癧|R27驔s?Nw~C^Jgx8t&E:Ig54$iO3]r*38 ʹ[t:(HIױ}=묏mdo9#7>8td˂�(şz۾X N<Iqwl?s=;{/vKWەЎ>★Mr#ӌvд!o(5R6x:4hū3ph] ͐%t,BoM0><O:+疓G斛Iq".P`鿓kS;U2)k,!h-J3?� 1eY [8r#<ߓUaD7 h7܆2~vC+�ooh`#X9FІt..qy{䞐<Z # 1=S L d:݆sN �QNF'<N rߣ"fgQHVD_`˄-Skb'|yˆa'yY�' :GSF &.!'>n#| ݟtb5�sr]ܰwyv|VXƆe N&MN&NۀCs. ?wm|}]�bA{~$991]D."<_NqN�CvU=|OږXzx6 / ,JINWU3{X�i; #ϻ>w1Ϟ�ȷ�X`5|3v�\<&8Z$L w/|Di;U܏ȪOL^’ lw/8O!`Vz.^ӡϐI9&C>CΆ|<,,Œ;z Od�uu9| OmlBo)1G;zccΘ,߂X"=`J%- :+oQCG\? hso`+vF'.<?;hTV@ g1�]lY)X}{ߞM�^(oCs v+;id'儥& Ci>wlמn'~,ח*m|gX[ӕ"5D8h�\-\g&\R1:WJ/%CGΧH T'IߠctS =Z �jG �ܚC02Xng`pR7H؁7|R8Sw3)bMbk8Oe&9>|~SK+V@ oFu$ ra젦Ë<4IˌX_uEH|[OG-tu h: <A+#Uo�ܱpƻA|3CobXM*'? *>IsW2'"윭cĈ>RŽ" p_NTA.r&Y`ng7@>sEp@#;p8~~~"Kѧ\1�ιh]_/Z p@-GVWz SjǾh+>Aw-jKg;QIz:p{lϓ+i,Wli_`Kqi̸Sj&HCDt{3V$imoe 鼼,pI\81DM_'nb܏/9^BK rCly�g> mS Y&4nG/L{Ҍ9dLaP㆛ߝ|ܪhZ(~WjAǍy5e^Y,tqq8A!6�c+b-�_R)[O �TK�N4kdBѣx@B : MSS&GQ\^=n=穎w<vD|a1$`P|ɲwx(GKaI#nx`+:Cz7LƐs3)Ou0k�uIEG N q U\3IyCC^?Mcv&`L0S/�x /!p=\,>י^@bXx-{`E[9n�> "A/�hA.I. ~sjxĚM዇Aq&Ri=)U+O6SҞiRnqgW(_#&Đ祐48?g,�?׿pXO㱠$mԱV:\N'j~UfW_ڃXC,)}D@ҷsX2 ivT>> ΰ\ЄBn1;+Vgt}_[QgL mvD#65 xsou| xk!.-dC{9ߝoi8&86x k3_Ƌum*6/'v5\NmqXeOw^۠~K�9['scYj _3,:?[,-D{$WD{Uʡ8SȬҘ~Mk"|5h~4|=O=k8ѯ#Z:q.E&>iDI9P9iooO�~wo3Iָ85p;JWmIК&2v 6aCxYevڀq:^S3r10k�>)L\h!<ߺ W2JEg@W9,6@eVvcCEDS9cp]Myt,<I:l4&NY\/Tݼvޡ&Ǥ[/a0,ߐ|8`['88x*.>mSf#8v%HopB{ qiʶXU&Ze%r͋賱)V1sSr|||=ɟ|11N~ڑ&lЌؼ+)IV]ߦkҩ"CUb^Rhfo`{? 2fWi'4ףTKN|S$Rzj5AG%i˦$dzgj LW;}Z�xJN_mE3ϝ?:k{݄v6Ft�w4+g Ҙ /pp)Od)6Nc)gyُxGgG ppd'61k2|8gYcn i.m&:n||?]ξ![zyojGB5땩0aECоƜvȟ>᝔sHNL݅.p.b[^y_xp/.M~ A^+X Cl6ZOZB]% -i*pu:*󴷓|A'dR)'%Ht@;ȁ>+@dNgաP=9ꅎ=`.SaC+ Т64*� �߉M%(HT< &4>F|/(gNCUCOS*t]�N5 =ĩW9M1K&rQ@~jnl D^!L8}/=k'ѱMGF}#+Ͱ[Kﺰhu pC{.8 ZHwט^@7_O ,䵨zJ!GUWŧߤw/C+�uLGf3gՕ;ݩ_?ztG0567k"&DvdI#r 6W|׿iM�/r�?;cAҧ!}赁c 2LTMћɆfMR9WoY!x ɒEۜJ|҇o|!m8*lM8_]O&L䠩oUgflE Oc3+r[&p+]͚JEX_s҆ް)Y}K.»g/~`%oc�X MrbJ=)*װW|`M`  =)9<X*r 8 H䘵o_3 4f.nR~Նp4UF;?7֞ϓ~O]hf�;5s>jr�Js`xshY uB"'_e&ix'㟩CVLCo~� i{}صؑ1hk@e.3n8ϢK3@=Wu6cD>Z )q>Nuv񇢱c0�ycOTd C[uVpod[.{ ׬u mW ?c/XsX>e 5ŽO/Ex`KbJ~]NŽ6iJ*g/^s;}V_jk+chFtitOa?} H S>6k`<5LsLGTIcI@'gߧ1]&8KaS~Iӡ),XVît?qI<Z#lr xҌr",_tfzΣ!W86847>ផcw؅<!vԄΉ|/8w8eq%ࡢ&wmW+%j?K 20 q_L0?V=fL:z/}~`今&ߧ. �q,<jxCk<&i8C7ȵt۱$=ҘҞ`M%uTD\Vba,�HC"z�,4 oy˻YxI8wx5N&� 9LnX/UIyˢ@h  F^0. "FN|f @<|kw<?;Y0&A9vpmŁ?`s {ZlZa੶_c9+ÓF&N(P~? KG~1kh|v2�7,q|;8?+N:~5H} 1<\yLZ  fnxԸR ,O_"TN/OR'%:p~|O /81Q 3b TdBs*]' z-8 ZMOlu/�=~ony~Y<>qҀ8#s  OhҠ=]&)F嘲dѴI]-֒kN;kf[ذ88]vWٵɽI)?wfgXC;_eФzELǜ"5G>uN{ h[W@WD8h:L_~wOx�'.�<ef ǧ:k�xJ�8 xZSfk"~k}AZx6Byb2sZ3T9Kq }X{Xf߱x䉠Qyߊs ]6>U['@?_"x}a#@Iʣ[O֗hd' 5Ԫ;\w*ʽfaSz dm(A-D=?!??3^t@^#_O7|mt/X<)6PϹ7r?XPR>}m^j ^c9Jwlkd&a)ݞ@[8i)ejZh^s:gfzE),p8,  �>w1Y<�]Xpq ' }4tlD'w><SYci1kFyr/y968'c/CčqNtD-?pb'qL|G4_�zawgo̻_ It[`wC4+45;kdk{ٵ9WLlkfM8Oo2Eg~) Or|ߙW^&jHw</uw?qB7ήce %M},s[ ,Ső;nr.*fuqk5K mv�?O?wg(Yjv]�vieuk9𢫊h�P:2Aay? $ِF('^<.}dpvMz�bg'<`?Fi5o]`R8*I‡n_o޽}O,rgN<D.9mj<hs2dEqߋlkRFx )ld="NV8#mM:8JWqcЬBxY0ؐ1 YVe1nϢ%;^ֱ`1MU1'˃-)(UoR+Bc+dU M_bl#ocvչwen 5*Cbr!ay;'vagMls5OVƎ\ p/;cH N{b�ݛ͝3?e-6۲Mn1t; -X|=ae}'tד'h8 9v@ܼ`9yZ<arrGUͩHf-ZPtB HF%kƣD(,Շ (}!m²#7U{'qw6l =8xg+ *\@!kS&/'mS_&6;'XM),g6,Q!l&V#YfWx9}Gqdf֬ßX*L:[;}.RXxJq$^u]O6},XG!M̄gE iB釓N[^iԕ^ 0ter%JrЭrɧa%<fW?u:M)έ{)Kv ;+/~ ^1ضq}' i{lzCTP x_�O#>O)zCNק›*7X,pή{\X?UlmP xL~N] =)6S1.ڲK72u-yu6m\zg?ưP|W|5fvب,g�қE huQ^&ʑtm/ HW@Wư;*{w?E �>E-`#3S*.٫q`cnęe0ͤ )́3 *'N߃A?_IOl'ξOkΫ� EA `<=zbCxhKB&b`#h[!y;C(kkp*Ym<pӏIߺԋl&O:ɋ2UrK }~-˴lxybk;ۛiԅ�rЍ+'ŲHGl&E$SN<•lAc'6`YnD%PJuV^P&t@Fg^2qLhmVtPaibдuX%ZX4I)o(uլf:ġ'ICISiҧֱG YNb[F}l��@�IDATjL YI)<O}:z0q9Aȥl5yZ|![^nKCh)φKaYZ22Er�nZubU(=yF~ h'D7W\p~ꮳMGKN$Cӌ ݦ٧V@W+iw1壋#Bk?RQxуƶ{Ym8Ȩsԅi@n!o!Bzkvzzo:\lc݅M's e' װtmJE�.&f NsisԱWUjG:P�J]{N-.�x8 LmXP@I^I:K(j[fXyx~6džM X�=r u-w˾tB2N[,z)Oub5q}ޠP=G0J;leʧ*3S$ڽda:XX<ZxNKyn=\STA*nstqfq5 mP֤8fl_}ě!]Y2&M´iWbeyLC |=l'"D\mMzpޓ.vE<dE�BvP5ԭ#\E2| DKm`F l%N#3*B}2EW¶yL]B VmS<aۍI{ou = 0Oe.b[| _4LZi ] X[+Xk.8{`dߺN5s#o xx@Fd/ƌ󯀯XZUcY90*_ۅ`lg~}S e%himNQT5pZ�U~/]5*TjvM&@6s}Tw:P@9Ї?.Ԅ =Nʚ*G ˈ[29!|Ǩ<Lx'?'qMGe2Ox`!Jײ3A .'iLӀ;@;L;fO79TY'h:e3Q[ζ>Ԟ7<4҆ L<!pRY5y#o;1Ƶ )ocAj2: ZUtV9mT>RO֝8^f(K Cɗ @ W@'U^aY4}W_ڐW х uJ[aV;P]bsY:5o;a7[KN|z#O53+~6M<`%Xj6>"74[HM(tjy*'M*S4ł>NӦ.8riS^ycq4 71Mޣ_v{�g1r3Lhvƥ_$i+D0 FBF-}v{$&e+A%-37Ăan> ˟�/6KzWgt?s4Gq՛=<,Zj᏶W.6�0auЂTx8-�PN{~RW,L̐S -"xE )�b ϱCr3&~gF{Tò721}~N0&8ϖHXx"ESdqOhuj%C`�Mt{ǙDvEADG+2R_7?D9�q}~_x|ǚXyzvNaI<`(`o Nښ2-AQ ҪV+ -4cCɫNKlK1м_?5o?;{{Z}w�i Ŝ+NJ{`㚅uؠfo$U"j'͸Fl!*$40 6T׼٩Tg*iS]吉MOJ (ԥxG}k�LIcl#M<%'hڝ?K_zfWzrM06M v~U9߸v{X1$w\q^̽_ٹ~&$:Fill+[$m$oCHdMGBӦQǡ{:66 -E =e: £P& c3_X/9AeY#quJl#oICY2ɁX UrF|BO5k`V&F \]ǧ~zFk�~) g6=q v}{tw?o^hF| .:K ]r\0ϓd7 fE89m MX@d*&yH�8_ [C:ѴA; &_<lp#9D|3?wg>�~?~y] m yfDS-H/ R'X_|m''A90 !q#C+:kDzeȆƉI,mY@ :O:wD볻_Xa'5UklF<u~� K.V!ŀn;넛,X{p3!OFP D) c~&\9 _l!p [oK~z~.�h]^pw/f;;;N:>d(݅ &V� <i} &ܱ6{{D=(_i3WIJz}p# >::P}5 r:hռ/=U3D)x&ݔՔ2 \fē~Oga= }} ޓrCXj|ЂlR~==$9˕q�G3OeQN s7)}vB#+ԹG!`D;Dlpyu*ޤ;e|9v�|֩6wϐ) M`2@B[2C{V<5B>UМfK^;N èm;@Ҝ;p<a<[Bq2k`mN6,KB/#C:G^ޠ=UiekU&D*TCVe ;"'k4yn̪_ mwp͡W(@{{{!P6Icgeml?eFܦLz7! SInNmJU\pT`o޴N?x ݭNׅh +\605%NX' K.fZ1'`h[9h`pԤKoԑPt뤃[O<$Ǜfa.wM`p� xsE^%pa@8tw1T\!P74hZc{U?ix- tM'ю%o>fs! M tVA,3#�[�Q'NV Wu@k%3QRMxS`s@f½ɣ36~xC(o+6a⡓ccmKd"_qYAdž, ;N ^" ]ךi}XNRݏw_/Sc{nN,[cg}u50@&fsWIv+szʯ:4:#:2LL}/b P;ۋ̑Z3 n206寙eMTD&hlD;6LMZ~ș`?:y M4L>@=Fmo 9׉O?X;m5mS巛IkB�<w Z)'uS�@ҪHdv =69=\>Єuގ( 9?T_?jq;2|:~pⲜ8 z??{upŪ)mcL7 ^:qڠyYX9Q0W^=S:F)H,w.9Y^V!SNoMaaۀ;,pf!wz @ { 3@K>kq- qlXM-Z7}!Vt۾2d?1=1éj.c|Y^cOc|5Rq*Hz^J?EhNaPpi'ܓ>1toҴ=dhē~OY>0:w%LF87dG/9!Ko{{K|̱C#c 7 3fC(k9eC.5D �_آYj c^Y2frZ�xwsѻBN=`Or` g+_M6j&Z`93; c Γ;i @N.tn1I^2;vTIhƛe&3N] cؿ+9Ҙ{lش;<:NO^1/k'n8̪|v&f:NjpPɘ|TD ېҔIc".Q҇&h|$tt�j8W<Rg4)+4Dfo˟S^H8.�) &ѷOy�->]v�._|U\3˶YTʼn{A�XFF򶎖+CiAd p ~$C5O_i QZti 0νOgg�?+_ǥ�lv ~'0-&܌9;xYV<>j>{tNjf8N.p;ӾGs o αkƜk<T\&^OӴ! y x#$aOÓ|?`c{}H5r NlW/"+O5 ㏋oe$r}:Y`ԋ�x]h{2Hn\@>Z S'xpZ�x*GS58ֿ=43oN #I[C㤌7z/X_U|'oy|1){9_bH~+g>s_ΈV+sl^S֠Hrgy;J+c,;$X O =ˌ1rSU<IGNTd&?19W�b ǥ'LHS3!:ٚA7qyZ8plة7Op0_P+t.t-|dy,hy �hswnwqí.\�Yȯ:8{ �ȸPOi2'c8D\`a 6{kECq7okC"Nّ_ Wي-:zBX;�7�|+�wp~k]'stq3lyM# �)5 !Rzd|yME. eѸu|xwq;L܅�N}uykY879( 6Gv�5,ncZ6@^vMLk OoaxZA&o[&-DMr)IS.j)ts܉ ƘW\N~Eir?@73{]YKH/3Lsb? r:5۱ѱܧGc'6Cfd{Z[s ̙ aPHEppMZ==0JneqHs)Lt} aox:| L⪼k K{((s~v9y{tE>4ҏޤFN=vdN~+&Ŀ&o͓yDqIL]N5Ӿ]I&erѡGe4V悚" ͋/L<\~'"8pʷ'Z"x>xAӝ�8w.;? xW\L@j^b]n\Vl˼S,̸ y6VU0>~!uoCkr`ؿ -LSZ؄wo]_gpο\God,8*]/ߎZZL-_֛0p 8x탶K}ë1!{f|M 1K0pC|8ohxp\1W f3chd.jFȈO=Oؽ} o(r)56p#BǏ^v><�8§3ָxnø]qve{]jգLex+wL|:}5M( {OJwZ�vGhܼ9erS-ƵDGBgr6~#0}o7app5=ݚL9H3JC?ⓚ,dL*2;Qc.|PӚI3&?Ik=UR4cTL_<!"]e�ZȳnH1'Pl&˿p. lǤMLҢ 0V(o1;9?1m%^I&,(rU H0,Яܽ#Ql^6Bw{V{=Xii,c^v1-бt6U8hq4+/ӪTJSy{2*-QGSBWIrRΐtdka8+LYGt(Ȉ oBҴWӾDHg8Pܸ�ӟ�<I/^IC8ye7@$ d)2J3N(<ղӚWW5V+v7e᷀l{wlD<̓ 9HR4{ pBch1B߃߰ fmgU6 =IƇL-hnpe=R똺d'^e|H<y;>ч7W^6r:KfYqwBm>1`07jKsJ ;˪SC]r%]6Iot = $ǭ>oSis[g.O|.0 Ѹr3Y'ɛ-LMNڔMS\സEb`&w23ZѐU^ᡮ<“uuRִNPKo,aQh"B{,1d7^`p;ym퓕OTR$ӲwD^vL. 41$oSKeEcVwYsCL٭Yֳ{"Zު4_ɇvm&'L:oR֟ %~MOX3RGćtff<Њ,kFl%_}?JW4wюd}2gL 9U2PY0nec Jx(_u\}Msu%"o7^ G*J}{;?^moǴMڈw|wZ ?� G:TiAũC1g6Fflr9r/9�ny|zUjtVe -8%^c< �)_.%ehnTbhp|:^ܯ|Gnr~-�߻=!'_::7]]#k/=_g-g'0W& ɯ'+}RN]˧g/d+?^{~{~Ow xA\a r@sOÓ~d???ͦ}Hm{6x+O|SkS'.xԃ|ʣlDtдn'LR&kҔ!x  J&k=rR|S~ ~+c5YϣO"OY-1x}`^ `^�tgyO|; <+2Yi5�*䢞&Cӈ4EDBG[:M[K"-Hl=M8"jѪt%&dW%n(i<`>'ϟ >k4w5b!0Fb/e@/ԭ )x'` j<5dB:OQuIځNAxfq_틎'x#,w�,Ib_lq;4ތ͹US"G<I;|LTwk?ѩCyCow;%}Ό8;9;r+s3S>.K| 齄|Å7$588xarzw " '>o xI-/a u`gvû`ž2,50f8x&~ 'MIx63;X$l&`N,gbS't?>vO; A:4[bd,2mG ?GtMYMP<sW Rׄp]n D9xy:C{- 0iN9Fy  F4Ă@]4pubN:{FA ^3\\V+Nl~%q8> �:gOgΞLdz�<?HԟYQG% plF%!4Jh i<Th1 \R)D9җ?#�+Q>u2nEv;>ȖAW]H[_GXJv`Z*U!H/ e ހ% . !"DU5>_ j)ơs.{F<s?Ϲ,~d.BpA�. &Mij&S|{cO>6嵬kc{N ͮp�|3޸\zrvɵ E^A,4ϫh. .-/=&޿͈T-&1?OQAq7W{\yMf!5@Gv r׭Qs=)5`4~k&琇3xCIt>|&NnۏOgvKȓgE�vdG5"a"Lf?'2CgNL*|#+IZ[Gk;{Wox5�7&c.�8.<ΤL 8 p(1i|Lja`@uDM&Nhv!_5|)bd I|w|/0\tܳq#uӀkp|?w?0>|1߼l=&,ا\(Vif1Wآ{Nف?t@k22n&%N\T=N V'aB@!`<ns7_s |.q>�OCwA3/4hqM{!PGZA[#pЊgI|qӧn!Oސ/ *Z~Ɵ}OZ:OOj@9ͪ,08e"* i"Q|2+z80ia nt-݀cے1:vx6 G>Ƥ6bXȥlk|a O\v/ig.i_�7\3;� (E�XW iCq~U2HnT|\WǷt._lGwoyrd9ߓ/WyB< {ߌ)lMœ1b .N_/X%~ M'o'+�_f2d!`и*BPAI+4?jM|}C fE^#S]~W83z͖g?ٿduS ;[CѩwfCńgev(c0Dlg@Mq2C Xx_IǮ _>1NDg�[Dm!S;/q]�_wa N,3.6߽_ E�2[b >%JAԙXq[ M_(�4FccٻڴvDh(ѶM~j>s ]d$H,?yCŀw&yl_p_ ʸfx;s \BJ:8 DzU SXM &JBOS)p_ܶݘ8TW^5YlV E�Ǡ$xxy񖅀'g/wWFOl:Ti{I}U3zLvҏ]!x0/i omk.y~` Zt7ړK}=MG߅jc�W:<w!Å�9ǘBiGG�#Z/ =ﰐ_MN �N<{}s<5}2}b&8Ez^2t'UgEzK,e8Ο'0ϸ%O?dmsj +܄<0[:08GUTM9iV-}9'Ӧ^;9 !lc~zB+(gĺ{1�ejĽX9HhB /2rCwk +5;Шȸ/E{Qpxq :S~8ɿtO; .}̆b t`P6E�bXmnfL-]\rhȯ-Քּ ԉLlgSx%LMSJ^B88%'M%E[dyqf.g98kS*@hME3 `E2w5Q8Xٌ]:z&twrE'? 4! ]2a;D7EɥCg&wRxIч2(zt|L\8MK*jZdL'[E EԼ+\ZJXU�_%3hĤaq9;,r6 ȳl&0[Y�ݗ[)d4#TAIWX޻2"en}-Bu9Ϥ(dˁ@CLt2Y`i%~%Wl;?~_,׋l9s>Ƅ ڡ9ǁL|C'q]%uORNMf䏞wEcc_OO-=쪏+iD#ӺJ?Wv~| oK4x t1D=s-08PL6}I]:HyaXV W[_qͣEH{h Y `a trLw_uŀ;v <M\ jaZ]4BDB6q)=MY6enjn<174[[>O!h:lyV>e.d1c4§M{0=TJ\ rD|rMui T}kS"⪏N#?2204MWmF'.xo\-�v5$мGfҨcF(֦aM#78&NdŌ9y=F?26)dwW$lham4Ӌzp1w\W7\7\'S\2QԺ6 ]xcE FIhuu.jk2]`z r 5q'S�>G.92:k*aA.N2j㪓(qphN}ʂ"6Jbdk1KpYe?L&3WA{a�LdHkebu\G0$>|#1T=͎wF^nð.ktiES@5L~2 OsDY8rT(E+yT?ؒbQYrW><a*Bt*u0uVnMG_8M_:`NG;t+w}䞠SE!Ff4Dq�a[>:!L]*u8:LcA'A\,>DT˝t֍ ч$zJrL,)I�$zF Qi/ qwO%ec{<? (/ m5$؏z{ݍ -ca 3.vN?H6==Hh. JS?t6Tz8>Y֏R/ JB0a^#/bn+}c{oTSqƊS/{́8JPԑ0\]J[p˰o|х&HNN5j�Tc3*9iCwRQA>^,ӢwEyv]יE�lg@Y6)G 72lE{�Ovtd"Ȟzb1<#zҼi44e-֔CVn FntLLוzęaP Z1-/cq e\ZG`mrط N\7H99:53Uj<i}w6 yɸ42r mJ[JK})H:/6QA<Apb'E (рYLZK}DկK~`uC|K !9?~xCv֭uoOFcw.nx#S7,4EcЌL 6oepyb`Hoӭuv;~G�~9]nڒ=bWS*a]BhʄӴbxMO<w“vol>e"OA}Q3r~!)�^ � dna{fA:x=2A &=1"Y {NQs,ZOS jSiSI_z<PE%9jLy`,{:<]|s�8. qƿ-`砼ŽCDrrĭG{KsO#Շ>rI#nqmU>i_ugB։=L_Ť>�}K'e'ϪQ_&�ae <1V֣Noe250 ++K8uTn:OiYSkD{~X2G.l�^d5ʲK#$.9L O$lcy a(}`Q`*8ErƵ `]=ISޕe ,9FF]Q' o �|8ud1z7Cf, H ]`b |"$[Q ,|v<mj5rR&aj�|wE�v8]"�te`{ky?HhȰV Cۀka7SU${Hޑ*ud[[<ElҡIbtIk0 s<]&j7d2aݺk=Clxɦm`[pS pJj;7S�62 VpP+t' 'G|3x3A8В4-fU?gU-s$Iنe0xL_6!r LF`o,mKC~z5Xs%$0IOa6Z߃]�>Wp]-Ypl($;)Y'vk%vto*X{t~UVe(Y]=VKjUQ*lX]<8KRDgfƫ,unq/s+Xg@@5w#亖(_d9A!鄵dpy{ǼvFK?cBώ@ó^)kHD}|s}ԍu/]+�c?XEa9QG z-0XkmTmָEYbi+4:<Nhz'AѼל3x)Ci]I܋SԼzO/\r^ _t6=k$?MWI$&o{MYŇhZ[d>A6m;tI*#!�h^ ] ĻS9 \9oU$oos3Iݚ`Ɲo]$SXL &ᐕE<  h!z:|w5]1u}Y{ >Ah{m੎k/ʴ?m{'9R#|F%tsȪ fqO2_<yJ?:4u-N f~Z"j|cON]g ~pgOT-B?*,4T<py2|_Oٿ3'W<OCL<-ɶY&Vo6wL]DxAY@-q}CCwα[ 񁍓ퟬj6J㉾Ou-|U';JO� 9t짯hgW|0~.\SiNɍS6$!r6ߊ*:܋JN,d9GN-%D <eyϬ|xB|5�ꗯ g% |-�{Ӄ] Zぃw_K´Mjt^K$f1@ĮqycݯDFu7o:`ӫ[+B~ӟt\2cQ A fcHV0ae#IZz�F]ƻ s mYyNSUѭ]8`-N~ &=lCCf|\γ5=4XlHNij #r򊡊Gv"ioiNt.VWȯDn͜QNIBʸ&Do q1CJ? 9Q&[yNy'\yO#7`q2~syDWUaԦ nwQٴfb\:O^fcWcӳmZ7uliE+Mg_8Փx(5_bvƬ|b: <Zf�jIZ^!@n�,0'Fq]M4}|cBar@ m fE'LpУ ܊t]oݷ#@;xb['Щ9|sw?Ko_%z_O5{x(LRi9;= u߰-"uTW?'JrF0|X S_::W?:;}C, 𓀼>q pW*�6b@An =48Vi`K{SSS} PVKƶG^+#OW{o3f+MR3 B8`Oq<cR"_N${/ y*W��@�IDATF}^GF?&.1]N#;t=]f>FѴ[WnDc-,6Vel!W ^^%�Ԏ* QO ,|ۯը5|KpZ�q>U1ѹu4I3N'UvL$sd%I"!X{eO?%O$09L&a>ak5 [c{Y톔}"雞zO,v:d%>y,wmչ.OF]?*&苂UҢLm_'=>؟y_�gwgz͖XhXqcI P- Z|LƀIj=ksք >U&=2;)*VF^gc?1ŁO>OاU$SzwzBuh/<{�go p ]Lh͎Ќ][rczL}Do ZQ,cK)pf^tz3>Ξ$~5�vLP?Sv d�uϪ?4QRl[xqXW;BzYC4xrh!wp1sm|s n%_bεx-.5];+58IڷKnpAiD{5Xu zs=Vk b,eR8E4:Yݕ[{IP3Vĕ_3";Nu 0z8LIU/b :f8潳״sw|-;ծiM�ǣkbsЖMIc<pC\ٶ%lwxݶ,ɖP HQdZ6!q 9cac+g4oCK 7� Ff<J:@ tN<|(ՋRuZ�x종OGgg}=)0ـstee0s1ȲwP$?|zJa=w@d_3ϊ<t)]1L9ٿer6;^ >ҙFVj5ᐶSܡps$B)v�U-�?r'7.L} ]|0)jp5VhՀ*+[ ll]#rn�#cF1И "A�\ X?n{~J=$�Tz|ڏô[.-S/]v=~syn}Oà )d2�(",&jL̲oFH3Ln{/Y�p࣋L2{&bJN> @i; g<a_N,јĚf{ T4Y_^xfW~iF?cY_N3'ʒw%sN/\ePC^}j:k+}"/1k53Қ�<DzC}ʭJ+d(Zi $/y--ӵ(] �O&MQ(`( ]8~b_  AQpz|)@>矲79 /;`d�B ǩ弘�˼쿚&bҳC ˶.36J2VQC, ;Bѽ;tp;hoo{rhQ=eIޙ#D;8灷eM3ݛCl,m?Zhz3-4a_Y-֐Az濼_6{ '3ne c ubXQ9p`ie(#-AmKems`Ne(!D:%tFV;8;9I�+f}s_nי ,lx^`?N A +kfM,�t!p<uH᭢ook$ CWڳQVqz`9WrܟNIeJ[C `ِ)%%Yh5MrDiNaUH?e' 4??+?0`i�lE�?M|JYљ0C6+CUZnC~#thq/CVq~BVM⥓Eg_5>±Qiy xi-<ޓ'pMWjOly2 U? }S=}8>ux@򍄋ńzL"|)@^gɛ\ FX�=wjRjɃ/SղOZUtiāX)%' 1@I ܅q_yw|{-Oeo\ aнaj[`ieFy`mAUWk㦵d;<.^$<+QݍNw +JuT= yŎze. ;+^].~¢+݃*qwDH9"Wk^m8o>v XQ1 (fToLy*i.ץp@s1W�|N}- h\�` m`_p�7Ļ͘3m]G+9Ji-+o+G3UJ `ٌd|bE(+�\�s˱KkL}}Л.�>@p?켦ϽM]hRq=B/ 0{0{ UX}Th<\v;T<O+�}* 4-_cc^Y3`[k^\0 #X@U',gWE'y(ʵ?cqn$qxi>k!>B+xdt~  6o9#>>iWMc4áI$ܞzh'e@K:gcE9\Ϝ_\}:kwSv j'cr,�-Eh DzNhXdo_`'s]V&2x@ߥ)졜x1�k2D j_LqkkqOVI _?-&ec `d4m+1RÈV#-%eb@:7tg7֯@ -ZƢ@&LWz7Ƞ3>wE"_^VUФkQo] >x >a>j=*RU;B`d:*==�_ߙ&0gr)�fؓG |a +[k.l>C~7~`@`yeGqftT9=iF5[5l҇Ee$6 ; ՠ)ͳ{2fOU[ W1X9:Nf{;2H ӟ_Fd) :y 96L"5iO%84=v!w_~ �)7/?J_u .R >3 AZlRO!U>M2�v/;(;(R ;'v5Hr5UB#$&\Ē+~o8NG* *3# }(=PNoګ߶mV _m/l[X ,qVߔm:vE <sIϲaaϼ/Pn&1>;u:"q7I" CF;KF#H+%o򊚙<Q@N $/��QFؼ;�NmQnHt&5^ԊY٣, x  ?ʣaӂr1(njOi6ыS/hϬ8IV/:Ac}e,z?D4nQCyaK8=hhL@JJ2;bHDD%4ô_gn^GIU)>~S�Yl9^PTc6fHהWW;m>d[^hӴ?m{ xĄqLQjV}ICz5|с!u?X'|Uo:w }kF L2X\xa9MAnS7[S�, e=N�|}ott~ N֣Tz> `WO0H=c1`w*]�$iK_'K\{.8`v{?*ە~ϾVa #R4Av`0}=^iϡ;{2ݢH4$�?X;wtǍ<'.VSL1Lɫ\>O!QGU2fc/dy =\@3"F'4ʴ͊)<;NXQ{wB e?�mQ!/9?m^(ABl15J6e&FV[)9X <A0mh:(Mse/�8g6_tDlI;O�(-. $#лpƊࢁfioA.�;8d+ hҶ`[4Ma?uV ~Oξ \ L&vAuUƅ+_XU} ա##Xdt]FxG'nQuD߱04u 6e)#Im .y+�6o8E\p0g�{5sNpx*8/�4^_S<fNzglx.L{%|)nHZՇ*~2Ϛg~z)]3ޟ?_ SR�V<yln>(9 +5s�\HݰJU{/N䟷)vO37lԓ'as=& G21ZHq%Yv+ BlןOuWj _::<+yq٫孻\=WLpd2 (Ѕ�N9B"\�(=8˽�SjWkdP/#F+q[|+ObhM'37#ܛ 3f Nո(OB;MzsJɤÛYy�}sNU?Zp/ &r!63u:6>fb <"3�o@r^~Y"n7C(q },` l$ ċX,DľgʅnH~Ig\ .J;'Ko"�n炿L_ѡbEW \[? ;3mPob[Md[I, m$Lr.Nq"@э:yxSթB#iKRwT)xÚrι^m? kY@<Eo�\$8bWu<}&nKdA} mKd^l P2-Z\E==#N �`9x hhͪ|9<;)0ګ8ጤhf;tH4\PjG4;DH ;+S^t 7?cvPUW Zg%x [Ec;l]xCN<fiOًOZ9nz‹^ {C[:�[;N?0Rf᮰P|O �j@u;'9 Ά3lSG2qdLq:rߖIlG<I1Hd<J +,T쟼+]l}] �ҷڗ1x䟉X; ?�ԁr.Ҡ5 `Com/;;Z!&$XLUNq#N.lB '�ep{ap)+-'i_uG@“8Ð/#B^XYvg268i]WMTZ-Oлϲ_2WT+�l�[& p%KbNŅofOw1ED%J+Ҁ?V#,zd~4\ wnQjPڟB2ϥ3.gYk.{Я־B>?9~qg?.0e\n~)P]@Oz2ϙ jҸL/{6Mh<#fI8xx&1GS2矋�s!uO+' &G� dN%򏌴âyoF:DjuW?WXY6k<%ąqOn?- 7 | E�*c&~QUdU |F v44J](1 *!IXqiߔ!#)& n:XIp*<[A3~ώ6 w= Y-;Ǿbeo, I5�3z ?73 ;%apvVd?5 YL/C sG/ȟo-IYiɾ%xPG{aR&EN`doS' x"i>{i?|ίθ-H[<j?nwmwI"%`j#= pu_�z3 nJi,Y'Լv2?G~mw؇i+)e?m~J60$�uо҅6�.tѡ,�wu7s<)`[XI[E8UvЬoIAFwX'󍤀FbF�yg swERN'=bPj7D.)Uee�?vIIccc_3ߘO�tA;$V19Xl:r8 ȆUgիJejC޷ݴ0yDt7gdƧjHс%Eс}sFwu |rm'{dnvTGYZ=$Jܥ,m#1VD!lBIso xN<cOƹ)ܯ`ק,].e}9ۦՀ, 0V 1dLYA4hl{0F�iv2{";S^৞6[ Zz{ؖ#~L8WEE= s�_yv` 02rD^*Jp Ml3wofg>ڕӎ!Հ4vq zrZDN]sfUInYl+=;yFƅɇfkh>I-߲ C'9/ӿF_zU5QeHg {65"+C�j 9c 3O 3_YtqWجj~ ΂9|L2 *_gZw<Oo*.TȜ�@~T9ɼ~cxtfuAN4e�/Hy ss~y.(svQ.e�j�2,4IuXVaA+Ѓm{ִ91B `d #3v(XǏ tD[w?SM*Ш<Ng1L/L$<ANÙ@%xyMcDpǠik ;@j(!ȓ/3Qnk gN-p9Nl/ X q6[9~4ng:4{ /&<StS\8Ώ.'. x߅3 E.8kH:0Pw;*8{;jpgci:2`w';ɋ)kwȊROؐO=`Gî0:w^s2-蠪߰-{1 FՙbNi@Z4/]=V4 |1\#dAGv4kc#7'c_oԱ~@.]%�ӏ~.?rB�0PCNeXî<7-O=a/.g틋K iRx}R0/Ct;cC s(P,8ftY0@E+wJXxI�ϋ:ByBM vvtk~wqpn%O[&КXLô; uJְŏJ&-C,'<%A@!sG&@G:/6�ہL'ʇL(NRpVN�1F+$Od؁G r۴M;#U-C=T0 @][q].Oa¶NmC/OTU!:zf倽V҆_֛*b/rꍠ@tc,iLI d*[VDɻ]n<y20 L|MJaCbma:?Iڲ͋rql=],IpDFȴ`؆NogMb ҄A5<:Վ 뮣QTFߑq7E݊Q7~'<K*O:\# gD.l)nv;a@#_Y|M^}`A*3d|FX<x̮>y-n�QM뀭(&aN8h>)d �d})0j_i"}5PCƕm}8 @o俎Wj;(r1 _�v&| <)@G#^~m`,`!^Mƣq/Y{:5Ac鬖N f ˢ:apπ!�g ~9qn&N2;lxA [ˡ;}&; N `(ar3Ej`/4f-ƑyɈe}Hwb697~9/̤ɯށwg\twϏ!5?tQoMën^G2xD( 3e@Ǔ&c(q* nue%NC.ɑg#�nb}o|?ܲ{=�kF3fUZ'-1ğPBÇc3el%p eeW_Y/8ܥfm{?5g[i=@yLk6E&IeMCH0|RZ.!.%<dt"\d!jO!.>sqMiHw_5Co81㊺' c7.-rNMc'/]țL('!`4apd(/ (|28Mr{]N)@:'l�v$;}m <!v"}]w+}_;\�/;yl'8xVF1㬻Vx#/ږAE EaHtf(c9 05f$Z;:[[$�Br=^sa7'3ޞ|vWԓ16S n ͟%)a 3̓$Qvk:n4xÈWb+TVMC�;zؕIhLUI NFe9ogw0v| v7~Ѧpt=0ډBe3NʅaDrV %V ;z{V:m q>k�⟴1:]"AṴ#9yWJ %#�,iKh)RVųڠ䉋 αE(C(yܶ-R7,]i,N .>R t�ؾJk\[CT 70dQfX{nHİ[rܷ :x@/�%^ϯ pdr�@90 E8cl_Q_mjT9>1 ,n@I7Qu (Oat9I;*s:0r6.|/?v ]\|)4蕒 qUG1xi`ܤ5r`S=HEJ /\+V.y{iNFq97DK_'xgv�= oZ^`޷1#' H[gۏ x,'0-Of{ l[v[Q&񟝱`T�9/ntO9 2(OF L%i1Mf ꈖE+HN9t͟`bc.97oΙ_klowz^s'^H,*Uׂ˖\H1qʂ,`W+쒢<M)=�ۜfp�\!Y,`Q#(Y$�mbע@.}؇fX"-@y{FDwq.R(l?SGtKF1UD;0$KPú%2yn/:uKf}_.x?Crx>1TSlЭzj>Ya\◞40Qf1Wn"C~ͷ^{J-y/vl⿀cc?Y*-,1s:Zf!iR*&( f'@-@d/gWU8yYR`wS^bvl)XCb:E^ntU^3cBﮊt;d/v@۴9;d1B3x4 F@Y ZҔ4M1 z!܌h_x`%ގ !0BS>^tx9Aw+\o7~:EJ�POƽy|7Af ؼ$rltѡFO vWzxӿi{$6SF*(] F`[ i@Οq|g 2g~"0l?3)qk `R'(4*J āv).0*Q±vi;+y߉-qe}濅I|\$4 y=[?.(IμVєn23& (=f�&ߤm,}(vrM NЭv]"G'uxw2#"nr-E0K9w`w1kyXEGM AOz =!Sa/Ucxگ%({;$/:\ OƇv{a%s8F#(Ɖ|#uS򋜞/y$u?aꇑWVtJRV+0#_@H �;7ӀbFUbS`폀8 G@ۓΙ  gYi~:ɠ;(g?=9Z-{lprRBP2zpb{Q};ԑGR2G~Ub++ʣd;${"x $<㒆ݩwD72_6vB{2yx\I ɿ't-2.u=Xޕ!Ȍɜf/`:?c5Ͱ?I%1 jؠ:nf͙; Mp q5�` 0S#tgNhf1mGW�흊Σ X!vQVEg-}u7xZ1-GGoӣ Y-ZJ+'.�\3g1S[>X �5w߉Az0@%4@ <Üم�cӨ ` !X#;ٹlrEJf_iw>2@+xT\{l۵\>.Y >~L4ͺiv\x/gd _Rdqm�EZ8!>-k蟶1կ [!Uh{Bp":ɘ[F;x�Fyn>r @N[((~/_[MUf/#ta@"Z#ؚWM:/0f%Hn �9,^d_7R !8)`htu0?:F�:8F@;b8X#fn$tddqbYGG7| n*�0ӋB3XYMyN%ܼӸ:vL!muTW)IxzYmwkfbGpdS-s_8=p�ymi|dD^}Pɫ�J74j?eQJD Y$b Ǵ|'fb6E˻)hNҵ:1w"vjG2cyI./,  ", S.sLr@y_y'#m`|BCrҴU(1%c Xk7F!B೨q{�M%W{|5En?ilI3;i%}^Z; JH7nw<5TXHY,Sf_%-v^9O]7Sj/;4'|E*joYՆ ЇٮuLle'K#Ӎ,yEH.R-+X#ϡt@t 6W"^?8_D̾M_iNj]j6ysm[hҴUf?׋a鿴<zS�'>Mi.<eM`M?_y ҉ϲs1Ճ+xs's蟝箝ތtiĠcg*Ϝ]=XAR9v!w0鿁=G(_.{q;3C/@3 =E?Cs'$\5 rtimWTv."?1/#z >ON]=2eL##tɝ1O^"<FuT% O{D�'o ɧ ΢ Sy,�mLvϻy=p^ p0gn4^@;g.N8Nr7hN#,[>C5]Vzw? �0pë� `Z(I a"@eoMo  lg1y3RD諲H)�2gϒذtr_;g?Bw Wkn9;^,�x`pd ఱbF|x+Mխx>4)[C}Oğuyzgvkq|,EJeߍ>,~b&MC~m)=ͬfA1FPN1ҷZ�NYS�ɫr@.�`ElɃϙiyr@?c'j3&x pxL⤟4$wQp?0p!�7JPtI5GfpD^ZP!]fO7jmϛV.~^)i|4|߼u{s+=i0[t'^o9 $O"|BۜI>S9(\BɁ ܈0%c5kEd⒏7twvCxT:o%G\$}p׿̈V%~/s!@W?@ԔvR͝yk41?`qjEd]3y;gI�.%gw9w#%_^HXO;a _x^B/oVUޒ�)#S}*W l>�ǹ:5"�죤b'E0ky [/QhYaI*keKN\`MƁGnUF3kB3Ǭ骯*iGhzdw6mP~ 'KU:79 @ߖp,,bh_gէۤ}Y-rW>ٷN?Mm1 Siºѯ>/5g9׀r}*Ϝϣ{W hQF|:wwg@Ā^@|'~Ҵ}ΛSf?AqD6Jo090rUzUQ`1#d1xBM߲][XӯAjnU^ف; .�ʠW:;$%jron"~p.T6tۏK{2J֡i[I2wċ=>G:k),Hk�4~?Tx=NĮI N � {1)Av(y^n0<jC?n:1WEQ6{b}N�x G]U� vLX?zߴR$5V&r^a+1a#fqR+BSBX[ȉ*2-4? <�:Tɳ@iNgf8m#+&~>>3ײʅ2CRj"VҞ`Zۊ<<u:W~ݮK #'y] }Nޝ;'PGϝ~iY]{2߱mY 4d fcHϞmHݛ߃lB:KT?[iiRn]5C&)?eд!,!q�LO0`)}Q.A!-ۖ‹h\L{>7x`Mpx |(+nZ0M7suΆ 6c7dHdnW oi'7M�d=d9:>=M4I7F1+4tVy">mWH\yr4ma v]n8o pv 3 u"g<D6}7qƈjAvӼ؏=Ľfy .mp#]-N~6IUŐh!MNu igHz/2dŷ fsmn[j뒯eB j[wx-ryQ%q[øc?-?% ^ $ev [ d4A(cԝ>tkot!OL'Z,8pI;`Rsb<ֽӨ(8?󀐐7 :e}w'I^v18٧!>cTIN[ϭg(G=>w >fTcկo{t`.n:sQIӹB#e zKlAl~ȟ^=lIo]QWS~`%2*WWq*Ynq_Mž'uЁw8t@n!~H GUcg^ȴ3rs8戸=`Hh.,vn2[F\<И>PWYd�Z{Bq%cQ7<q#y_y/w\�Zag\'�/_oWy �wj &,>l 9C=e *LҀuZfN ]|VG`![!3O'u@L+ $[܉n4*Y 0$svi 䫓 0!7{I/ͰjAy\iNfȮEh"_ P=&$߄Ϙd EnPM<z1n��@�IDATִN߲կ?%1H^ECqG;j1=*= G%&yA>C;n<"MlhPN?p=UŇGxEۊTqR>n @&m;R  "M<o 9KWz^Or 摞 !iS9[A9BMp:T/Cv5rAxg&|oxo2${DNy eFv=g9M| oa-}+ӡipy{ؾQGoE>'-!XXG�A[2$9Pv bl2*–F7/lGB|7'b߹tDJ"}d:ԔbvSq*۱�:r΂�_R^6Wτ_ OW?S_7qK d~aI0S [gbv*h)6x|~ό3=yم4N.@dՌB,g-u-"�]dx &6'�c[vvܒDfj5MvZ[ҡїY%.t~ %}E~`~+lOSF6{ ouYp#opWh{im<BO5?Oy55x%+o,zNYx-PW\g6Y>™pr…s+\Yxz~)@`)|էWsge8[43zn?O?[ TP^~*֤�ȁP ~30D߁R#~'ĝ{ŀGvAzaߏ 8`B;u Wik{* aOp#| ƟEx?tvf8}A䚜vLa"dGL,@I >pa2(ѯ'd'+鎊 =ƍNpC`EDQuܑeFk=F :Ш<I[+QDFNvaH}}辗oc3�Y�`v3߼isXt@-;vBV6uf|:rtfD# 6_ct o w:}V*.os�m҆[@7'2:mP�s2;0 XȥN$@  }7 *gMAcL)>0 �i4f\q>'}�^]m7]<ͅДcfIvK.kxVv `>C}T=lVaKa<v<la07Wzi>cOf �ʤ/xo@M/,XuDZЦ($kM]7P�^#Q)2/!CӐ03C"~uL=:~Jw/"+-"t2("dsψ# ��9Qv@8r"Ak&~07~xh'�Sca a<$GOكx㴕"-;隕Vlo:l5Oz<4®xL\Rා߳�pF3!|_1zp`[M[?O kk<5|2/MAD蒣� $H2!S�cJM׻{É<3I�'֙ 9QK>wJ�l~p�onÀ!| \ kq8c5K/̌Dp5 `Lv-e@:|. "� T,ag ǰ |r"fX5$ m>h6S[I\ ˤ>{~i7w=_'�s?>"\p<G~Zvm;KGLbj:r޲-8pyRo {z <= O[Zæ6SW=�h&uW>\ڜO,=ۼ�d{.xds`/b_HĿ[z.NTN JOR<o ̳9;Ebsu2/%,mPT�hL24 @5sw@rw'>zǏNO~䈤9X蟝#5%3rO]ԔvJvÿmoMԃn\[/pְ5Z迃v<nqe'gNj9KrE�#*熦xtDZ8?lES;;iV^2ɏѦ�ĩ4K`|J$V=FA< lcLXyeۮW�j?nuf! ;Nd?=0 �<€nsz@2w ʥ hЍnGߺ-f7]OzݹwRo}pbo/qa?w'869 zE1u0t85cɰ!vzɔEP,e fV`yV1d,KҦR p^sw`w'?Ewf�^ěW.B3L hLӱw4Y\ j-zFS;ZOb{)C6(}FK]ŧw4C( k gG9jAwK&{޺' q8 Bm܌j7ҕ_-HYJ cRY+@QNϜϜ.'R`4AfYL5C ۨD@N lu0 5IsK 
qjk0�,�G6ȑH:dC z-g [�6k4-$fG Gj_c&yAz@8zZ]O{0͉G%1ϼ}$Wーq|<�ա;­ LLYq >2y-�A4/! }/OKdSp�$'|*cEތđsRlex^k,̯|4RD(.m"h;*W=$#GP&h9ڿapςF0,@wY`emytq[X@ߞ2&0CFʒ`$GAޭvR$LdMvAX'АvpRe7 drN0i_m[k1]xA0,n+x}@nfŁ2C!^Rۄ򄳮ǿ!6aj;qgÃUJ+8IaEy"[hNM'ݪ}pNOz<&4 r- MC1e6dPl[ L|)`^̗KH${'T 334J fd-�S r2ӓ?~F2�\I�vE �]H?�#?/FԑWؽ"xڄ%f2dݶt"nj:xC]gLo: ɡ?yAh4kkҷ{Ni#6wX39'm[2,R}'D -&Bπ)&Z DNa N3e&oDVXx IͿ!O^; ϭѫ[ݕ^/ua.#_-uO iT5 FW)Q#rq*L=?|Kn ÷nZ#,7}" HL #ʸfhzdlWZ[⮢1膹+X,h<$o핑t'j>pW%@x w Xaj2mK;y<N^;Tu){YnI; @A\W]Q& Z;K:DèƟGl Oݐ1}]r|&^ |%਷榧ߪe(&A?tcpw�iDN<=L gpO)F TKC|U+؞R)eץY[$hێSwvt:<x$,@{ڸxd;pۑ] pѠ>a6M[Ln=4YXMz>wEw3 #GoIJ^ gl?3;'!@^r�\ߝmn9Pu?wFbϑpB._F8aG|e0&])`t8L=ނѶ Kap % L+[(pvgx82{?W;.)U8-3"WLB, VѰi\\vE O|:O7:TZ^z鉀*iyq6 DO ?%:Ƴ| -_Ŷ",զY]4Sr:N޶ԪqrOw5iKo خ0{oAKDIMxqS=X#?` ' v§-YڣGP=q{3hkyܪCVjGhCc VzEuE Qc h9툧ajLcӯ0c,I%G%1"#hDAEQN=Ns_6 Bp)SflUF'RĻ[mՀq;{.s _x=>t=50#\:]/_qL [ hl!ozÍT(o1mՊ&o)T k7z@\5 1dcHz_3研ˏy'=fF)O|ϐǪm`MrZha#WҸ!yU(ji#\OíV tw&)D?/s\le줙�TP=#H QWxaUBhqK 8/pL3 (*YƛW��Ҽ/q"�ʏL#KnN�W촰plgISM?L4|8B>m܌,KTWAeb�N[vֶ-fw+ +,;Ox:4}بi@Z #b#Mh1"թXGn6c Sj*2[] x;7%*+qLqr .dC.�8G]AΣlqfSE c?etۓ9)v)pZ�إ3CXӝQ:MtTvVoJ5P׎Nt�uImM_ҳz:mg/1鎵 %* (kFC@oيf*GUzaH ~e�/\`w:-ZNie㯭|68H�VA*WwQ�񼾍 }۱~.</ _~ p�HhB8; dT t0ɂ5XbBf a̝qlr[>=SE�'7\ę"mLPB>+㴈V:p#߸U& GnΈ0nѯd 9%ᤑ#6Ft,TBHͫ=+'"�ITԶDH42N ;~l(j3v^JB@IQbKطL2r1/p I,UТYeAHZ\ 0p-?c%{y GDDG,Ҥh:3 sM=8qLq _-r[Ax.݂jBf@K9*|ʎ;-ta+-E<=_h XJNS�)&i⾀'/R T/5:| 7䰃 ";trG$uxƨ돸MKnw4*G'nB q>wZt$ `ˣ!QH,innԖo!o7_l[q7dtRv=pŀ+g {lDj| p究4ړ.M洊vz.)`9ܤ8ܙ:+w[$d]0ϿR "~wc'"q.>e<ܼcF2@UׅE6>wfG^IV;6ʩ_VpA<<<sGGwC_jx`! ?<O vY$0\&}̅�yʌ#�kL\0J:lxPp"'ܶM!kôG ?2W=ۆ-;< .bK|I] ouhZa&4)3d[v˰+){F]UΒHhk|?xhuN=I1 W2%7~\uSxԘ�HzTTsmU0U`ǖ9H8=y~ʭ/?N4dvS#T?m~Qt;au"vR,/vHo@茇NoŅu |OAP:T(;# @fnmF7IP@ p@ {u&9*߂Bs9-eb{v?`nnE;z7_]Bm7lv/~>|-s狀PAy ^>us6<)7z�� Ӽ@̙x5 X7ИarzORIOiQfToܫ LQ&;aAʭ\wή9<c& _0�+� ,Q'. ;N}D#&꤯zM'Ke3n$� |kڞn?qfaF�q@}xAO%f&9n\Lx9ه)`Y iie']^,4o)u. 8Sd+`'6=f:A5Ju";?tt %?mG+d'SjڬpIk~ssǭkz˭<'[&YR%_ȢoB;Bqs4.�8q,ĺc(I6{꯸\N', ҫX#)6fЪ6~zy&=c̳iY7mL 3gTߍPd`g$2HU anr�ێ]%A[A%3ʍ?m={vEޱ mV6rMo7━fc_7Mo@04xInUiett9HgvͿٰ[2g#\LɫLq5鯝n;=)rfqa@2’1t?Y)`A kN`hҳm  6HdZ^~�*�K?x3w.vGWj5<4{t3{<D:Px2Bd8~hPBT  1޾eݿ79 �};t �LD Ήt?dF�n`MijS d8c)`tqh<v:BhC)iܸaKv+\Fx4~~|Ac_;yWuMv>hc޴}״r8iWXkG3Em<qK5ain�Xw15|>'>p<B:7D\-b@nECqAB@e g=�&U@򇂘2U i|uԳ䱝]Z/S,ct%du'U<jЄ=]܄�&|a9aɹ"`wA+rE/>nR~Gxy1@3 ?.~L(]㑛{_!\##fEZT8ղ~Ikko9ٿ9/~v?&~Y}Sn_gWDY9ū0dv4)#tFħ x <m<+=~ΏkLb2;y�[=YOmgdߣxO՟%@ mlj/Jm-yo 0WTl_`8&œbTDZI9 aN"4?B}93g'0rߥ4M  rs?<ah&7O~?N"»pko*|/>�&iHGMM@X j@>hq+-?8Z¤J׀;Xqx<7r=VMOe!Ǽ|q1{kY/u? ? eGXjzS S U<a} +-NyKVIH d2/M20pU& a3Agts _|qГ?t0*dokv_qqs]̉no_Uz{v@ߡU:⫚C ^c8 LمbJvdOp#<Ȏ4u9q7\րGx |�#ۀw$x;?kI ^u<me"@-�;٩bq18� ׉ ;9PݹͤY΃�d�%l"3G|HmGHt6gʱ|:? ͯL1_ � ,p$_wr@ {&Fd1VLj>`[y}MMv*SSj<=RX %yd:@\%ʐ)t_JNS-Ղ4:~8|xEuY.{5'}6#ه|OK#w\i|˯毶[ߙ܍s_շ|P qqo )qW6H#BNĵJS,@,y�YH\S~3g\"թALg `:yqYm{-7lݹ@@p ;J@c/0t1u \-q#9o<Dquh'9y? ޯ#Uhʮ ;p��Љ?_nw)1vd6[,#,?_i'A`fRN'S`X l:ќh z3qG4Zx@`(ciLI Y pQn>^v{ˤYz_kzxړ4am\ 伶f|w��kY'9!׶tFJQӇ?' 2cA0cwOhүСϾ.42NP qoF;h){Nӈκz o �xE{Ólю`Y[%^S{\+W_n; /<a63f[&]vLc %/}XY-�O?n?itg?8@:khW?hx$p gOh>VI<_E L_Ye=LwӫWsAz<B_o90dTTHұڱ@߲Jax40vr `t[Zrkbm'(=IWP)uC`܅o pl�F^CNwvf8Qjy<٦Ӽ={tp'~ Qc~y w 6߲95;9'S+F!楓~ G]pU{%AiױǢ&$;?&C)P<GJގ2>�/;Nf?2<~?r$Lt@ۉYxccr /zTa&Vp+GZ]p쟧U�O5xߟL] } �uJ�`~z< QF/[ށ 5Si?i,IZ3th\e_d˄1b<.lk:~N= 0nU{ȧ}JXFf`Y+MküOJN|%@FGyy[ԪNě}_gȷ<t`ES\ܧp̠MB_r-3DOWK>C0-y/J3g 4iuVd)p,[�.B6T sg<DozQsryGkj_ c[o@I_Fp?;JÖSC8Ѵɬ0:숟hQ`Y s3dƫ9h@3Q4LA0snO_΍7ScB7%'dl 4JF19D*o0!^܀ orkS&q"A5B y--"c]aHd[LA mY $,;.Pg1+P?<ϋl1=Y)q4`V\?MN)p<F^34) cEe@lK('^Š>,zDĒa9=;5d(X)ޫ:m3dPbfCdϟ >ܡЊOC4cLyM5-ڝ,+'{Bq՛+izE0tHKp)J��pyNvA\FR y֙[ i hl:ut|$^̶fBt%Q`%3NQ>sr{7X_z԰<^|}yKG0st@?Y Ϟi"~r3O. ͭsH{* ^ui?mp1=M;ttU3ݭpP;aG9xι 59wϜ!<Sn�N e{J wl'NtZ$c:S `_ F߶;ʀ _. p.u�{?;W?no $ Y&N]d4x w3,ο k!3n?g³b6NcZX;fG\s !z@u< MiO/7ͪӆg@6d=o۾14pU}}sö+tEb!ht۲:jû=uOɷVn:3]OTC _pz_qg8otsGMpQ.܍<F=YP/:ӏZ)9Dm ?FF_M#3GyO/.Y(5/wi3A ^lNMϳ'`݁ZqZwЂ;3BvAgһlQ8cp]o4v7\`3x PgE% Ej4r`^u-?r PPj顽4ɿyQOsI˫!a�ƍK6^vd:^'LtPx ;"#2\d? u8u<^XH8?}gE;d$% >ν_4�v_Θ5כ7o~ޜ[XH6#'A]?pvC%mj ˿墿wEoJÙ�c1WW,NJ�j`8*,uo@+&?fX) ./��d<{G+;w':ϴ_A }.{8%�Q{U58]osyz&-|"{Hɿg ? NI8\wJ5{ڄ}:G~&ܯGć~o,(2 ,?߸8 /}}.lB�}\}(F�Jۏt}e^!(\SG>ne)@op҃ͱ�IHnz O�d@؃ӱ[R B G2 5qpR2&g 3?m z2p<aY܁3r?^,0�2Qj /`Ny?amJ$\ߣ;.̋Zmp;M{DFLiosnBrn{GF+OʀNda eTRV_rҸ=GZX G%�2AwU'}a't?D, �ͳs]}wzԟA%A,8| Ff 羳#I7o?d�\rC늙2.d^>Ï 3=&;e_R`U=~tbO񰏬_`H,xSOU3'?~rR+9ȷI+ҡnh|?r뛞5.O5v8q/8[=RX'�FC^ؔ="cq!s.+wuO>B'jm]_X/cx-rx_A eE 8% C8�8,7.פ'}Vր n2籭r*-o;wnj<=Gb0o�ݍYưtJIm\}tD/wi/FqIG !b.`}h#8"4`\=g#L+�0- `" ?G( d\�p"?z$duM:9e^~VxxӠGa7r %QkSJ)l+I?Zi9VZO&84>on8)>gT�gLhÔT\G<e3щ)N֝re|Iw'ԙ*@^ �v :x2+p�N0&D>…�\b.vx#R`}ŃsK0Y7CLOdHtKmh4p_>�.{<?(Q'0?gOYxoo8 P&wV&WasqO"f -s|Iyyhr8pפSŽ�Gr?q\Oge2K9E/]�ω�Ea}:8k�9UGD.><Њ?ztI*׾ �4)GЩgtN6LrKp#d'{E�et2@z4;&N_qW�<@JDB".()B0+n&8qvܶa5j  $DZ] A[넮3cn#F@=R7C35!< "7H#qgNfX Qyy<d0:LSo;pRo=YYVY[2?'�Xf_�:o-+z@~ `{*옞Q8VF Hd/B&}nyn,M:]U֋l$_k}^Dڎgϫ,2q d p蛬eJ0C(}^2.ԗ?Ȕ O�OkiZIo|-O [tԩix >A[ly~3Aw+GD;i>#>ˆQH-F?͟b$(g�0c¾aq 4Bs7f.}.Fo\wa:“o\�t㮈&~|g.Fo RlK `|N5ę} $k:&Y@~hA|~.;psG�U󧌗E�#kם.`#}O 7B鄨Ny:XoZ d%Ů +Awtzdµ{脅r[(8Le ]Do #g�!x=sV-NyZ7gwl tW~U{f3'*3q_�6^TxLZ:}Nb<Ub E^F@_Pu")IlN.2&R0�[y>n1O)kNy<;ZH'ϒgyIJyZcI_qD)dnfm ļhZf_"P.y'\.{&Ŷo)3*@h',( ~ ! m̖d<xi0{=.QдeDG6#v\ض*ᄙ8'_ _fŎ,3/8~ԏ�؇kjyY[4lor6]FdDt2wc+8|h-=\;Fo0xˠŎod ϱ;8t(@g8-}qĿ^@n0A'}j.` k6 8zu�C?Q~ tcSCe|  M6je)^nNx|w_q|ٙ^G@8\NoځPF(A5f3GzIsyC aͥWis3BTJ3dLZ SG8'/X`dFO[4q 9i�(cN9o$䙣msZLTG4Tb i'e/u�d'ˊTeI-ޕӷ'#+ji[Vom# a~RS7Rnى\qV*=qF}ڛ$([2;.YF2]Jyby f2:yƬkNeE�2oQGt'0Yf޴z \i2Oִܗ}fO})uw lTe J?M <Akz }Wљ�/~؟�}JЋ tq]u VN KX7, J4l 0G\=q|Od"4HrG#~90z2b5|Yz,Qw=hȅa*Հոsidкg�)`:��@�IDAT[>UnU0 S-xϥ0uX@{Lob[vi}&O]1xUR8Ƹ'K^n¿\?a}</AW}oة N/!oseΧHh#k)\g4*SU,%>CR&=mŜp,﮼fgm1 w.7aFVVі?q&Ï3 a?S]G~`T)] )2Fv2[KI _st͋x1͏cw_k2ek"x×7q%O.? ?)gIcϒs0N3 ȭΫ#.|NkM*=ESαvs`o=qO _7or*钷 &Z ! . /tх_U~(_sF,YpH Oh.ts3K{}#W! [[hW#wShSʈe3(oA O%UJ 2$.y}h w s jJtRhj|t- >"77?AE\LY yP+b{kIԍ:u"JSْ4n<jb7{ v{mu|{pw-fՎRl[+#i:,]H[}s-S̽EO,\G�qm&񾆦?"[>\LpmV5- {@ʑ^H,ec@Y<ƅ�!%Feh޴#ME<[ M7^[xHB  �#W9";)pgO=HJᭁ6 0gdZ_4R&c O4 ]1\v9hǩKqʋ΄rueDrQPOK|@ ieδv4&0~ni003gPPȯ�<O�A,ôr ?k|˝ڝf0+uJ�ذ\i^$M sH/|0sd9hx W"mZU[R JqIw䝯{ǵYx/zw�kp�L/R)Mk4/JM.NV|/�`s*| '1 <4LLT- c'Eȅ p>pS4 2<{$EV)÷dBQ~jv% Oa6ڝ؊vAy<z-JW #9k輓@PWmNu.lf<?S@']҅|58 )aguŗ&~K[l� 1 .qwF �@&g%2)띴{t}Gc{]ɇ:0YY >GxFX:;;!f;D7w>#~{Gl2bjdMNO|. MG-pݥxL:n ͖K 6 #�ukPRz VBEGZ68tnO|\?_p9sW̏c-�T_<_'^;[YЧvhf%z<%SD(xS6y"+GJTA"7lݟ<*|G?1{շ�dҟE,.:lshh7O42ښPE:'~~﫫G,,\. \qz xO9ꀫgsݷ@o|I5C˜M*z<ߕpJzUtw-(C%K'�y#~`ÓAO_\|5箿{Lau6_sLh(a7MLxyI >AS&h\|s#Ҏ�LySYxK�[< .c~:1F8bs?{9穯Tqق/i#3cp:젇V~Uw~?Kcs2 ZSLiN}?a!O.t`Pk7 8y]ytb4 f|>O7FG+A [7^:{DE�;Zˠ�"Sw6Lu ,ct|af E.{(wyy@$IIL]׏1AxJ dp�Õ/SS(O'9 okۦ:8N !?ߛ]`ڋ6a3e0)Iofڟ3'n+NYvX'ڠ89~7 bp!R"eW) X{;?/?Y `AE7J' N9B@&=: rg2ٕ4t/JJhp",'R2r,Eh69oN31z6)(:gрXIJ8'6YQ's2i;x4)M q{a.hK#+!;;v߸~.Kّ'c{ i/ŽaU?+?M+3Y,oV_i牼47v| ㄦOg F g.ڙ|XbKFt,�<pqjiH7[#8۩;xp9n~XkG17;*%ܠ42_0B<~ǤϾcF^|o;N~΀g \CGLX萛Uv =&ރϰ:\G2ݥ_}sg:iy#xgs4g�63տ_Bg?/(|CF;p1\-/|5t㒧.4Xи%_> a}o/5[r7;M0ٝs׼֓<NΊ̈́_S19$n9m ,e† \X |J5zϕyKQNMA<93VTw_ o3t-�'uNj�5 0 3YVx =Ԏ, ۇV&γ3ep3RjL VߺS%iB??gUd_sV!0wQw_0Gv7ԯsbcvЎ_T@^h,.MZ^2NN3_n.v^'�˼ys7T7,Yx^gĒL7M}g ׫U5y!gxQJR/d_)csщ �~h#weLǘ 6bu%NА5z6AN2pcEj{ _3)x͎Kzğ̰חOZoCp@.>6kEֳNyU;xkovz >Lk7A}.x";Qx>_ P`%Ϯ4vp=x 셮EA !+uИ H3ٯ'23uq ;b4 oi>=^!@w՟ }"g#E3m{1Ghޣ49'Nsԟ qy�}Zv3^-�䔓}G}IFŽY M;D֜ &NŘPd`9O):AW.E0_FyN'.:xNحR^%N{j5~|kٹ7L3ķ-5S' lEy|]Җw/ ~"2>9F.;gU"UZ֠vB)>7:6<O3zް#Z0j Wiu>M˃hF oo!z)$(_.[s=ӯ~M�ܥWy)0֨;@88 XqEOӯ ng0\ǟͭZA�d9 �LX1 S�_<k/,j:ygG?^^Ghffv*| 3΀WdJUx2ב&3N>qTK;}HAɳf)/6�HsLo=Ӝ&]nd}m '�ae3 q1lᙂTB <%g'[G*lLO^�~ fay?LܻI�8 ~N�X_K\3Y7io+~s LʗgBf !WG$]=ӅnĿ\L:@_B@~kE�'oKN ?ˁ82;|%_(G /xN>&s\q }mGZiWe1?(Z+C:|LcM,j}Sχb; cpL%CO n;xeRu`;.ds!a9 w1ᯣL._A@α~4>[wGӡ>Ήs|^ 2/.: F^0P� J@,ɓ R|v+$< X%. 4%8f]*"UN�u mJ>e t%O�eP :uI� AXcߏ>-d')Gw}+�c&ޏ8ۜE?FfJ/*e1[�y?:(\`Evg?;ɻo]Pi$+q~iP 5&^)`L ۄM V-w"ͺE; o 9I7[u�`_Hlg Y(KN<uAw<@NQ_/2¿6nCSw1Ksqsb$1cw̏.S;:u>yO?$d|hRqN\iIOŬiaSX�x=מmuN>/ɆpV_AF)(8eb3Y0j\1JcFG|-~&Y"r|xDp[,đ] 梩 ac ւ#?w8FdŏHV[{Ru6كFcydfRR/XϮ-.\&TE&6; a) \@H.):u$ܭz dڭMkqE�Dn#eӝq;vclghYhNch&w7tq*la2{vˮkm� ڜ<0~}�ɾ'C'ަǒTm)z|z5@z;v)R[<ۙG\ "50/H,:jC]H>r; mt >,O5N\W.c[7T`\kwYV>>/p[>ĵcy㺯K<ܢ@cGu"M^ iJ^;gT}&F#KgԵW%~\RS X g/�ٝc')h9k4KgS &n_=/nvdM ˔<;x />DOǼ۳[~gWD. *W5Xb#z xZ.Y;_\�eG#;7݆0Oc <DVSq΄3<*^ W^3* nxAD^<cL3@rU@tx2vf"ϋa_ZIj߉u[G~ O\s@S|<q}X:v/(Ik_I̯e8l4A"$IS1`7=CGASA^h$)#и)'mXx<E7r<Vm|Bɫq2^ru FS~6)E_Γf/:rkDd[b8ϗ.^)")h\$\=2vJKYxQBvD㚰-2 Hs_mmǫ7t=h1޶͚y-%.x`pq[N;/]gOӮd2Y>.w },�<xQ!Nfw&.iiwJ((=9y9w [.V}z~ww~,�dqm&Ux`ew c??6A_,N0>/>b2c49 x X E3(V"5!|S[7bi+f, ,pO$ ($I n6. >,�8 3[Ƿ I4]>@:u=`+Y|)KVΔ@8;o~ b ɿZ(Ƃ_�&=|SV*GY(OAQ{Ɣm^\;ϔ)<KnтHsGS=`fQ@9'u9/}k&؏j) ~D:FX\W@;n)ȏ{Yc]\ESq,'k$(. ؏s6.$O{O:‡.Õtӏw䋦�y#g:/Na7V5`!:ܗN4/[3`E<ezLOyϠ\O|{{_{W{6IFO,iuTڌ73ꓹwmEm38L-Tʗ|\bb򔯰?y1 �pyB FWuo3:B~b4^`fvsdqВU r>N΄xl4-C4"B,QG~ ^i&9 ܸ?IN@F͙?Q4׷`|@N=9H @ED0@HuiuF*qC{N}&!5:: A@ BCGs13WV�5zBVR-83+d2R^L8ӝZ&͵�.Qer~LOe?4q_W-<F1|' �gSo;쾁+04MH*{ wi/q}ذxЊMGΗׯ}[J!xOz .,ط_ZNQ *ehEۄuuB޲;逿L $'iK/c_"V=l Pi,[Inkwڛ_�`P3u& C20w?W߮߿^7�;x X?uw"vXW2TrV+"4 w?:F~\{yvܲxi B##&N0 ؿd;\7T<8!| /ʳ9Ҝ9@Ag ى u&E oDq{|[!F~Z,ߝe2@[8lrt|''閹)\?LB�,<`]PNʒpGDS#q 9ћ7s>Nҳς@~`r &�'�?NO OҖ g  ܂XS`J36 ` y|a~R9K%g Jdf/>A]�x/<u\z.<'ٍҢ]iz "q}G_EJs8/.ش=l�8xI$dA%R>�~~)�::,]U<@L�Q}nF$;ZYXׯsxyoˤ@&pM=d خ C&׽1 �5I4j7^e'{z�AhGw}o6T8`NXmΉЈMG:rė@`OzGgВ:Drήw`۟3IظѥJk',/Q<zk'hLH08yDF<zN]TN+G-<04,E($7mU &׃ dG*q +',/ <B߲F7g*X3ǿ~=7I�v= xWOi45eeJhTy>J=)g]‹@)L^3G='){x[Y<S]�K,`:| C—)OmɈZʮi;E(çYy ,jn3�6,@_rȜՋ״(^io]={ǫ�谩tKpHqDJ]n,.|b6hK m/7L߈y;ٟ0q++&o=OhkOE a]Y 0BI4Y<0�|,z.3|Xa%" <æ�8%Ksfa?ߛɊ* %93F�ED|8&�Ow&貣&ovRuS_Ԑ#2v@1@Y:LqC)[D_37o7Y?y;Ҳ o@I]ȷL2Ogbd9@Aѭ+=V]g|%)eA@ B=5�}|78,Ε|j2DYJT&r{ɏl(\ຉϩ¸PGg� f Es{ P S-9ѡ)(ۥ[qäMps\,X~t{g ތҩnF'atƞؤm}CEۙ=n &.eI?@"BYIaJD<r aeЧ,Q}p 7Z62.SNx W\"6ND$Ý(ҝnĤa`Klf$a^3W੢'Ne|MՏ ψx E�_}/s�̬Mk0m|_3eccŠTܡ'kH Kke9zifByjj5Praˊa/Y�ND: @KfP⎲K߳(lj<K/ ?vX+~ LFǎ G}Fkh'6stF>[rYXwۀA^Txcd-v(_r=_�o81"E]l8u kreϐ(͋QmYLi�4Ye]D ly67 $#zWYC8趜.]G,� ۔ѽtZ K3 X|w#0:&1|'c|<>d md @I;cw\=` LO> |Ռ[dj}X,pYKG9v# _IKΒֿ a,"p&ej637ōpW>-)-ЛuF;(]{ X#LZ]QW uYu8q  y6A\z,wZ+L?\ L>ܗEM?4<zH?O~'k{rl>6M(ԯ,b7UDIQ ]5'ˆT;ne2[ ;Xfˎ)p(A0?zG�8 J0!}_03WO.x3I7Ej.c \+Pµ>�7 6/�>K X)c+ Oj%å@rm+1[ cx^& ˔Ɋ"*ja[*'WyoʅM_*x*7 $]9c+Jj�ZSe ` T|h@M١#0pEç̺dXÄ|iOV;\Xzan[6ݶw< ]E(%Sʟ B÷FXꚰ'ˎxKٰ[e!՟J<} 9ҷ'Wς[O5^~8m^D!; S {;I":~h  k>HcýC56x#FS1 4`r6PQB]F[ճ?WK;<&d֠v|l\: =Γ *H?_\ �n~coĜh|\';inwpy@r 0'cXm*:`S/=]F y9bZp' cr\c㐛kv@ ;�/ۀf-|-!ؼ~U27+HC3otWZmp|~IyRH�B>S\WU<[U=<D\Z, 2-9Bm[>G'8iB;&F7Gm$hl#"'5-Kۅۗ_Jy4GA1ԩ* 9c<}F<6$xƗuq]ghYq5z#nuH#SX�8O;RRt<khG8sih1~ןyG&|ߜCEl؁&|NjxMo|e6?C.04tvh'_/ ߣnrVx  B`dNسτX�?==w|Oa '�g'ŏ=9kyИ5GUMγQxs|Os+efZ%ݲRJMt;~K&t/wmT[\i#i&ݷo_h{>Yk҇Uظۑ=6 ?Ɔ[hY@BԴgՈ^ #cDŽNvS'} K.@z`VoBQP}g 7QK FG83G'N@뭓}g6VՍOfc/=czW}\KPu[�,x?1h2- I^UDkhgp2'8B;MFxQxSN7~aH#>6M#׭PDa}.O ց{:8ݖ^ѻ�Js~Y?8γO9@qpb@'MSo`UCj@وH k6O�~$$"pn2ӀESkTȠ#YHVH@C_fOyyƦ'z;'u_ݨ�_AjN~٢<"ywUR>)`tqMT6-yGo,~ Oav&Ly IM Rmws(E:F_\w=KO`cwoܯ _e1�ژc p yT|aEQ`4(w O"S^/vfaD,HM!".$qW^֍w(~qsN _ z25W>4](04Bɇ>rMYO챰TKl Qq rH߫F@E?ϥ:r!1洝}&pt.DBmljK+oMEMG~,�|,|(~ y: |&;'2p7J'.<vFs٨#KXbއ#?e Hq7lF5=:bӛZ2&3<[tڞ4\m <qLCjp8< ^?; F^08 FeO^|Z3P0$.\�>.@,0r )0 <y�^iO2 8  |qȥEB_7o^\ݾ3gl7,;W+~2c9QwrdտY�7ǘ[5,F\u�/+\(? 5eOmbk,Tl񤋕k%Pq�;<*R e[K&>^N~~5Y (*?a 郩[H}ys]o�K'#3x!� ?-Xٗ>Xc~ژ* `_FrAm\~UEw^pM̻tOy%<gG~d 1}.c#7J|5pil_2>q +^}7~, eM~,�<tb{S M,@“a )� SFCZ.�|WD[.ǹ70I8Ю"byin)$Jy[I< cǪ"|xM6xk<ʎ={ ~ʋ|y2ؿGL;R6GU92[caXB ?qB)@${*Ve JgKq~GˑMŦDQ(oٕHr~Nhk|'໓-eKx'-P6I-Ɵ5 \m kO0?ſ~ĆY��x|~m -Iϭ>oO"Ll<-}LC T?N}>~j(N)mgO*]}9Cz?6Issj >bJ gؒSyT< {fҍ@a]_,@'LiLO~5.|X.n?{N0q T}/#ҽӯƏ, [5r, Q"4퀾L P&W=H<r30<6nooe0Cǥ@TA3i"w޸ʫ|*Y(558Nݨ;Yz #U8& 4U#nhGGk_>^f#QJC,™_-TA.c'\Z5PA 8d@`;g.at"]~&9,_:'=*f~@}һJ-�y l楲uyL呙| HCP?G�96Ğ#̞[af,Kgw{<4˾%xƹF[%IT?+b\g�K&o9>о�9f;[_|&ke첧1d*Kp_" FEmJy&Ik>l'EM}yR?>䟒_x>s/(o}8'<:ScdفŞxXW:K�-<Uߴ(Yn,>shG>4>tZ$)"G"O6Lڡ񡗰6n~@")`^eȜΎǵ|M'X(mc\A*M_dd,�MPT|uF^CwIX&Mw7W݋ͨ ~18+*@_EFM hlzI جB^NZ{^;ƯY~GeGjć68S'BFa2w9orʖ'_FЀ&|sg)pVQ*;nPkjޗ_ �Tvhݯ=05�xc?N<gioYeG��ћS�P$ط .Sf ׼qlG a^EHK1ND?tj ֦,�8?FYtu Yd?RۗI.J{L-*kt }o:ETvN�!'E�v?F0X7a[-MY�QSIȃ߫'ܣY5T}s 7L=U/} ug'>yշN)y2`*Wl-&|. bw^q }g|/+˽|.wj> UzM -X84M)}Ùj.W954{ma9@h8� grty.€B@f 0<^\xһ r?0OC~A8#!ՑusOLUs� <x 2<nWF8)1Guͨq @_�W2HT~Һ֒o!@g_FV2w.ܧ| �k/gpOdLP~z FS1^mm9_q]�)�W?%"AM SVNkGF=᦭ $<5hwzI)]cL8}ȜvT7z%|{jN0 u uU_*X\x|es P?K@茱!o45Qp~UϖK? xӪA,Sg W}/WvtƞJѩI_?mkk Z @#'ZvJr*#}3' �5xp8~eJ 撈B=G+f'm9h�q۳`f'%<el`&4nM2صBpM g/B-7,;.ej@P$@FdkPyp+f4Z,0խ˚uƑ1mU~|$lFH)uspedW*iBY.lf"O PSȘqи8}-N=#F4c8P "UvwO8w)[sW]|sIׯ|+NY̢70aϳ<ON 3./j|]tmč5VNU<,v\N Jq|[ pڧzRVBVxh \E'쉵%E~x`K <7_[ *h!kTU鿥oMhZu_+8TPp)pF>/)~ިOs��@�IDAT+O9Xϕl:Y\!2u{HwXNQ#R,ǠztI}t>P:xSN&L?ׇ]bdh}[$ET3N#4)^ɠtT<fOX`tU0:'nu&z$ cܼy#27&/ʰ雱]k)"ߊRUڳha0QYŖr9[tq4|ˬ8a9œ {*6x:H!MMtpEo 3K.G08pA1`�{VW<>TEy^}ka_!,į� Tr)OKw/xyHѿH>/'(ʍl|niro/ =av}%2/Yj\D98/h~pOQmr)@'S!t*Xӛ�H-5lwM<, .=W `BcPbv-,؞m rMo%l\*/y \RSdS]XfZlIyA^�y3!y07T �2ݣ V$2h(v0)ۄF V3bĊ.&-Zu�w2*co[8a˯ ×o}a_ m?^<yr�? ?)͕4'k|~|�%p1R~02'iB`@"H<me~7ᅎSi R0`%4yzܿHޕ)V~B|>.WD}GVF`_=/b#;rM=])0fY҇5$ZavvTkƦ*ϭ,. 8/7Tk<wG %3W&0&I|C*rrDh>SgroH_7c젎2G6fI|tϢW3π04`iK(V|YHF%&l3 ¨ō]mSPC_B/iCIq~hHS[lxM +,e5턔=32nh:E9�l tnMi0 4 PkSqy_a~O6+3aȢ>|nZy0|&x?O懫߮n-xF_/>%wˑ#_&uZr)?f1o8�oۯ':ujkt! 糴[.`8S ll +yZ6X~#) ?M5S^H/'˳L%p7ob) $]I-+}Nvƺ72iEA<&ٞ-I_ u50 B,y%ty.#ng9-|HN?KWX�x\ �(<N_Ny(J2`2@SE Vn">(gª&<ҽOᕌr% `OSx/ObȎ 6O~dZN/}%x>c|�5j4F b2H!28A^Gđ)c7/7a?,ȩY eafYHDLO*:cZ~><_e/~"ŀg3o&֞p@,Һ) 3^s>mgrˤ= ,?d'gr�aۍq)�+5h�\(H*(V\C<!R 5dH><=-cqU tkgߌ~6!XdI+צ ;kk*_z_ITqØN޿Ƹ_Yr3EѡKӁ4n<-ބi[)@&[*/�@&j?m& jդ@:ʤ#.i@&<U,z"d/ K<%{ Gtl(DqxeK?(rXʚsF_ L㖶z~gi+PuqcB7-; C+' =HﰡA x܌4Ӌx-qRILFm\(8,H+N;d>}fiy @8= �{߉wqu]@_(Bt {@nQ(ˆS ^n8Gq {lUVʁx]P@^CGLIT m8R<ږh}])I ,<?>myJ2}D=-P^$@<}#ŀF+ޖViƽ\3ч@fYճGؘjPa_a_|Mp\ wsR^ZOkchGE�j :ئ;ׯ[nZ۔XTv)@t|O>"z*-gM_jlڡ>C} V]gb/B "3ptVGJG"]ߡʔٿ2?Pt]8u ))Ef!&k+ w / c W mţ (KS?E ݻaqz6)`f]~`2 p؃;N+�K . Op�Y5ny%ui'8=D: Ү`r1~|78 N%㦬H �RrzoT`C[v_+le_-[M%m¨[B=וe+0ot.mWVBW᪜$\n+r(Qx:QX e,bKi븃\UqK؍ /I"C448Sez)ʵLP"K -Z\!*Uۼ&#FU:n_s fcK{H#eHߙ+{Нzi+1W_c`{1{]=`& {B :iKAOr"EX%/9ie-8Cʎtpv KSt0œ# _O@XҞH x!LLҶ]| xe*-^XZ.~<&8 -^y>]'q֎*kJ՝`袻z ,jg-׏ZZ0xjԹ ^N'2z |I7N}q09b-"d^Bv!`)d[_LJxkSN�D=U*CG̍!'7~aqiܞ.Ai҇.y#zƁtpmzTC(—!G \�p AJ?A ط.^ `oF,0 0UH; w%]'^QЁ"ag<)eXD|/N~iNCS�8Aa2G' W dZV^_IAt[>;)\ZW#>L& n+KxRA]p-;s<<1ʞaؚ<?RY$pʟ& )9^<Z&+zJҳk�%.c`3]gO65W2EZLb7p׭BQez`ѲoT4eEU OM84$ }l{K <n>ot Vb57pHV&lbO ͦ-sKpҼot ^��K t3cԐxd;YzJ+Ԟh�2( M1Q?I x#k% V �M,0V:N4Mh` :͇pi"quA_a3!ka㖔p=œ^i~Fh#x_Y K|\ƭY%tt<t>NՙĢ@ Q/.No;,={~hgIq*}*6BU-}"q2nqk][Tnpl6GGɄ�3/1QέkW\<?L )U>SlG~n:AXzAe&WhXʄU@v0VNUZJF&'"m Tm}eӠ7tp'}l@u`JD^h[ /w�pg#>Lk0jcװ!C0;0/;SG_,b1h@,#=PIf-U%J]|ZwsƻA2IV"8x-:\/50-\�g0mxvKeqѐ])�!וEq$Ε�''x?-{ =ˌ:Q3a=w!~Ǒgږؤ ^Wѣ0#3"e! d()pj9}V#Op)SZP Vx~}//Ş̪(9Ѽ* wy/KS~&$O8O<MTӟOgX]S"V x wG )po  �&ͧd}J}HՏ, 5Hw&s:iJzt } 3ٹN|BkY뫋B5cB&FWNR@ğ]w2Nj%GpB`Nx n%0L7-٢&ѣe< s�_s . ~-SLsDކ`KN~<<P&~Mگ�W߼^ޏ�& ?Lc9uqQ&zw]`ho)|/gl傁:-nQ&Y`sFDB*=xp7sڄrX2,Nz]bOU+C+\�AFxW.НUpL: LqԤi[?؁>� 7�LLLO[dFfhdh4q͝#{ 38/~|}&-:�>CU5=?)`v(He`@4W F)* #|-'#7*>ԅ/`8h[.W ?XxӐqAKHt#Sm+/8_%xV X u?t H.&X]3/Oqp~,t'li &i,,U:;oxߟ|ד/: #D)彰',00WKtz|�XlevN@ }5EӁ+3@씖lHe.mM|nN/%pe콲۵+- 8 ^:Z02_뢫 0w|L|&d\z/?O"[n]DHTeXqPd(HIO%~̉r@_[ JafƞcvbNz8J{VW8Ŀ| s>3P'Z<"a; Mّ9a (x0܄ sBx_ n{3kS^hC4`qH3tJ5dĉJJ%R2tSp}94k"2*,} �\3g~a3)tR| ;a.~*0E3ØꍰLh;N_Xx �WYȉNߋ�.fdAWS|P8礀">{,�k< C,)`vS$UN S,xnKpD\.#7"j;XKߑ_g_Mo%rjmȌo0604J(}p )ކDV5N.w_.Vp*3i~MyJ4??'x4{s b4ӔG{SYJ,Dn-/Ur=l=oEۙړx~?sHw�3"n#aniڴIͅlt 80P4r빋о XfˣCTxsMwn9>}Ɖ|>oҙX?br]) [\� >_@[4w <g7>z?n_\]7+?W~k�G'Ϩ>+ �e6O&ܰFDvK>".r }L?�p22SE[Yis+fH&ȨfxgvvdG 3;}mg4�/ O*vTDV6ԽϚ@ |!}b(e4qM ~8HV!>_FCώ2,\l{GdK"(wՆ e1ys|-ߞ'Y� VG C;Eԇ j_5 1Qx2m*ɿ4x|&01v<'J.~�Bc`7L ^ϑ'r" ap/d&.'ˣ]o8τ?\�k׾`<C&Nⵃgw'?k! PC{zna`bp'p}v#O ]pM^,.a?g5_ yW[­]>,V zF~\TO1vGN''}u)@A˿}#YSt,�|ltw$M"g7pRұN}$ BpFf?_,t}(UR~m+j7C `.:"AH<'EN@*V.= Ģ5YD}&BgNxN9ɗ傀 ½(q[&WO9k�} aJ`tA>vvo_?~խ �/C3L~v!|'w/KȲP&!_/+qe;+C;?b X0ԖT; @;Aţ,NKU]2eG?oSZxY@t]c?;_x'y{ݕgוm~^X�x,aπ'cSSE`:١g=Nm L>>`n |֣_tUKf'np#4> '&[NLc!PM ԔePPI<sYG&4D6?g^7Za2Fk'N}G? \. 7yG~ ;_s�G_m_c`ۚF$>;X9| \p0MJD*‡"Uj?%)_Q#UMR|'llipl' \.f9g朙9mϬo{~چ VH6ٓU•!_H_w<m=%uD6(’hk-E*G<i{MΔ{=r5= ,+-knnlW%#'/rp�,pAyHzD SOgrPM}QүB:E&&Nzym]Rg4v*q6]:K$h^n֜ɹe׬PE5tUhխ*5ZΉ V:¸W.U7 wmNh'Wzo SV yo%pU^n D#n=\ '#���kcf~e7S˜9wm]+?BS"|EV/BU$P)f3"**s%olHJE(S fX^^HWM.V3K[j|㩶Sϳx5ƒc iMtTWi'M{UGq6"9]^�Xϗ.|V{q.7Ks"P浨n,1WkieyujY9qXBkIQr?5"t">Ie_;f$9vƤ)1UD+A@”7ZΘe@׼ O@r~D@ƿ7S~weөq[i?~[�WbcAwW_^Z]rv*lߓ<T_bB9+j߆zu~NH?vjX/͉+vu9NȬa'j?]kPF*ҭ0+3.zcɱXʞi e*6p`֑7\VHJE5#&}qI75hS4ɬ ,\$7\έg/p�w]k"śf]TŽ*ܿEc4]**_窨3eSFuţA1UV˔&j]Q:U:j"ʴ!YPNW09ye� ȷѝ!H?G7+�7^͒{#iZNX,!7 lɉ Łd~ϱ_]%6_� G�ic�^PW�\M_句5;h" V@ec$ x.S&'NgJuZ?4#_*U^2j^a֟8׺^}dPm[!ҿ#(|<c4>T)�XwP'YJʟEwE`X"0A4oXBd%4-o^c^z\df:_\]/xJX.D\X;/Yzwk@ 4p�xx2qL #Y#n^!KFXqwsq?J{@ewgd䟕mnxnxN�}w`֙lpۨ`pBtgKeiBa'g@rdPY)CG }#�NDr"+Z'O.AFOsƤ6(Ucq ɋLbb 8/#d9uJ0u^[cW=GwJ@X8ɏ lJsjm oTȘKٽ½p9#u,rgqE# EK#H7g4A):KQ'ʯC}@*ƾlc paWe o]ʱN�So_w;V}nX-{;\g̿6q  <CpW8f�HF~d0g A�Ѯ�N>_N8?TqH pY5U'2&#~>VW2-V9/NFhYq RB`ӵάqmRG z^|\N-Ggֱ>}?a8ғ3].Ō,]X>jJfd:qVNzz9!}(CM]RjJZq)Sl3NSo!t&ɐψzb83W~3zø@tz,,�? ?o@Z0#nǏ0�j@i%;F u;�bl_i[j/w}v l�9 7@-C΋(Pi;9`]38��(m<9֖@>;G%GV)7aFmXcjxxrr(=|jy&˕? uwL•!!~Eؾ72gŪv4nGKث:.TəL#iXG^lfC=LA KV*S^I[QPf:{n[/]&�vfD9t;@֏V(p/;`pnh@} cw|'|V*/'C<B>R!3f[7ˑi@% о�\|9a跮 } P{3Ba̬[msq%p̮65ыLGr}s(GVIqObS+ۨ??b$V~*]_~�8+ǽVG.M e,&1R囜&&khƷL'YZ9OzJrc!_'@xO H}~dr685.[w/ ,V1��}Ծ.܆%ђ΋a<o/ƸSs)6N9x(qA>ufASeǤ>̷Ty? mVBH*[%/ɦِ1p$I4p3')w)u%w_==&~=F0R^)R+ks=9tB9O".OdmlhFޘp]i)hC>OFw^vm+9'Qv (߹QW+Ց)dAj6,<{ݟo "ru1QSm)doDqQ(@oZ-iEU p`8�2z7)�D V3&S&߫PntO~ck>Ԙ"^Z a+n菀$LH[0x_q۠ s=WiC.6ӳhx׺�q_;#׫ʓ?3[0;�FmKKܡFMk>r0$A2rf( z I^Vh+d_1^r{[<)5 �d8�&sA COXBbj_)$0쌬=ER' &;՘n\J36!^a}'imoT*лp7]wDqtk 3P}kwk�w\cp\AYrB'VQl|Fz4yUF@쨧N?5s6IEg @�">P(C� �g>"h>Q 45Ȥv|PiB`/*)#>|'XL)9b!:vWh[:6>҈2t@sWuW9XW Q4|Sƾ^m^kuIyc@;6@G>B%4Lq7^w/eA &!ź2KU,ι}\w�0r&n?{s:5,y64QǢǙvDEW@Iqh3xa{ s3e KI},+d[^2J2og >R7ϙ�Qm[Q_Bx2]Unny)9Q`8ԶW QXA <)\UwmN,ŚHB`Osl<<*:d{9d5S#\9bç's /.fq#,qarx1`<4 Ca ŌX*9/e۰2Øw^y>/ؐ!휖@q}N6u>Ю[k�z `k}S�20-!H*߮\3r|\A]~^H>j�`O"@c? |}~^-ٔ_P=uT(tUά"\O>h/[ݗF߬�XO ^dN@ABQ 2^sI'9tAmOp;+pJ`ZbՁ737YNs{K~7t7'�6@W}wc>Sp+L{̘uJ\]^t)Ox&_� UΊ(`*�:-8C�8&նuq_8hⱓ^̡ӱ<߆6-W|iwGrݩ~P�Qv�#AMDӝʳrp3z @h_�/n uג ܿ�ÍAJ׽�1?ƕ"{㭨� M5}8=p,��ID'.NN셞T@ ؐב(6i}�;y.R^8�S� x/W U�v(%6=xG顟?{^udӿ7@Kx9 Aƽ��j!+v:XGGXK} eC}ȋQ1@�X]αwB;\q�ߞu.~⎉|谐�ֈ@a9^P�e >+c@Ft2mH;w𷁭#oOyFegpJGLTs 7ZA_q?0il쮿49JҋĴ”7TWB/@�XeNtb>X-0p�SfBN;� zWd:TC͵TW&=DȗJ^= 'A/cޛ3{i6,unD rN?RV+~sj/T<.}zmE(N.j� f<)hP'5 pjk;8>9L!�]LxIB/=U�^~I ȏ�aеq�o,дPw63z@ T֝ȇzSAe^z`J 4#gէr#Il8#S\R8#J~#' @�OOsW8>� ti ))^qp4�@ W-!%r|vuߛ\06dѳmp�7c�itK@w n o6^e`ߛ3,ayyq;B&y8Z'E'#/G/2B@�Xm<�gHc%JwO@gfO:@`*|ђdzZ >�;_{2@#_rϪzM:J�?};;7np9I߾B^W^7J� yF_lS@o_Kǯ%=2`Gzұ G Q?#@�K ̓Q`2aݗr^B?� �5'.bmkvd*o w�~lGW:ɲ�㮾pFwvr ޠ殓`m:NioF^U;*Wi5ߒC`[W2nq7�AeN�w6og0/+`(WAM;ayD J! �pa݆Ld?OzS% �%"`C0:mc?PvȷwxٿBv�$yeo!0gn �=`gi;l+n8vkK7_];Ռ:(o#zG|_*k^N%I�@$#=v�8`t"#h& �@x&aʅLb[a,nc^zY6CcW�'-t}Z|wCuhS?0#z?i~nw7^Qʠ"{^Ke_eTBaߟ++;Ҙs@�:ccp?L\588m@�8.| #>:6s\@XɨEk=.ZCٱ^~0e>FC?*c_mG=�|^>Zq>4w6E p_վǣF F}ͶXbL͹� �s@��A: !)X 3߲W 謟qy6eN;~uU7IeKvƆzȤ:~@e8@lKUҝ|7dCtLgq+WCYMp@�� 8�J!�@de0-2aT’1]w^rd=u?^ӷ#C^37d[_ƼeYg gt'}omFJ=mߚ>ߡFrI8t)e[q@����\*ua �u Ϲݰ#鹡WS+(;B.T,^FOGiɠvl+m_:Tf`-= 0^p2/y;m[Q&R!c%Y%,rB@�XO<\Q�8a}\r� i3 fYU/?7oC>dc־n;6ᬼXvN�!02;%鿴e5+�;9v9McŀW `~qJojsKҵqA|SN � \ycNnn9_(Ӝ �֞@\{#^-|!^e  ȸP�ǫ�]vO7݈>qK깮r}ޤ�:32u m_y\~3%#'i^ D%#g@1׮O#[�w9jFJ! �x4S :<ygAmB�Я^{Tκl>}$N5A�I;8�/wd#;Fuþd~5!�@)缔m+φ;n:phoί  a]+q,]4)z=I7HVʋ9e<IzrxB@�X#W^gyŷtw8�kwI'<Ow �@TB0ح納~!K:J@˲m[OryM{hE }O=Q È]0p� .<�J@lӝWT �dxB1 JsbJ ( �#05lu1 %cn{ةA#%?6u ǔβ:mq^</ H+(R2?GyN;|ъ�_|^x.�z`M�e;> cZ��)IDAT6|.yi[C7E4*"s#TP !�@`q9_ymƸ\CH�E/=_ -a� �c#-2'}yD}Kڡ2GN9u1X}F΀V�tZ5Nɇ ^E_U-f_ow.wƌ,;<9G$92\$"m#� �"笘4WEr4Xh48�c5PJwJhR= �,lַ:<oaYJ"]^"'Q6)7 m࿦O�00{H&?VěȎkفdYT۟_d~D%p[ey&iD\$� n_xV>0^Yn\�Xoe 'D/B@�Xacy2_[WPK$"~$*KȝPWS6˒d~]yYǮt(ZIf۪S΁22%܏0HPhX2>j$%� �#P8dD8�YHZG@& �,",*+Yxc@. 6 <ZZ9mի��Q(o Nv^!pJ[V CiaoANAG"/aQR8ȉB�ǰ&ƛ tguinݚ} ѝV: �lQ?{gSC SvG%/G<0Y'绒c`pJ~~}g:@ݙs7us7椳u۸n&}/L0ڭFϦ1凎>,SO;!@�Js伞(mM}4<�S >|ݗ}Al}4Y� l Ǔ$ ^jȗ宾ӡ닛bIJ''t4 @5㧻�`c|cSS@:08�~@}_R~F3 s 6}v$" rX򥼒=LB@�X3<aJ�8��ҧw^n.dݪ� �#/6y6rC/]s5m'dgCՍPrY9KJ?lV @w.pWXYWqɹ`dyƿ~?}Ȏn<:pk=LQ#JM�@�kK΀2- ``8�#Bl#\,6C�X2ݥ撦FI  3,Kvp^ٔiuCf=FF*d6 t] �%u�%/vUѸӠ8zѐDsP �֞@bZ�q�*'I� ϑ.ўtn^ uZJU5"Ip,nPVr[z͟~|ոlІ~=ʡyU3 R]YSyR#Aol @�� *dA�:VnmcU{ Ng Ur2#W􌿖P<uc`[G4i=%ӷ;W7빟YyY'wd漬ZR @�� 0O8�I �@�{(FnƷ\*(u2a焋.'+ۑQ-~[v]vBǺס9gU^R Ė' b#K@�b �x+X@�'@XGn#ZC٥sHy); Z5eٺ类]Nk3  ^9ӊ_d;уuf{,L& �@`xOy')~w!e$J2~2}(*�cYɓ:ģy6޳+pnxMwOSUG6*pJxP{t;n3TLz1<B\.d|(:9zN2%� 0n͡�&&3G�& �,+0|ε޵}P_�3;RI'9$1 4z%gږ>^{N�t;W @ r:Y1KT>,+YխyY/WA�@�'} '`шu4wRrcc=�C�W4 6�ˢk[qU\ ^~7z*;5}ҎgSz,`K+i%W �~@:ٯ2/Yy"+[o294! �-2ey^V獵 _ 3\N-Y� �!T{S:Xc!vd{)o߆7lɗ ʘϚ|7_%<x\n$pᔪY52E�֓4KSY}pl=$BEMghTNx~q6r~g⥎b;! 2pCSƩЊ7ο*; 9,Dr{xQ 򪛕jV3r��֗@b&sXG`�؉N7N� >3mVk[5獜�$ ;5_rl K%i<O+�6y rӓd/5Y5Nh&A=3U$@�BOYq�d‹z-X8�}S? �U$PpO,+<FFKˇF}e ¢Y1QI0xf&TrQUUtKD �lbl8EwpA:xbei �C [n'yA B0rHd#;[J+ \i{'J*uHfY"uβ,P4WۛXw+lTo#' @�O-v�p � 粿t5K]duX{>P= �,I7)b(9b$:JVA#ݪSRY^xK$q(][ JSQWK#� p2y-L1idxFy:K?OHɜ�hN @� ].AV WFuO *D3Ӛj hU*T'%[M� ph>Ău�ΓgtohpC7Itso~(B�X+ff,1nc*J�~�.\gTxC%>jPdEu�ԼZD �@` ČX1q�,+�N8˴7M� d D9JF mu ~;&OO˒~wDgVKZO�Nц}Np>^9-Kz P� �5"\44M!A+B#ٸ#S3V͜U 5Im!kT�֟@;t7yrr'H$9wܜ~1q&9.tj � ꦉdE6+=5΀&sh<7քJrkeeC0jy,,1!@�'@3whCp]]޻W)Oy9>sb� �#灉AO&{$#)(Jf9cjJD<C;8NPݣKdB�"#s<m9tg0ۦF<0=, �'<L"tEg `#E^2%*!Ֆ$7ejƌyьZWz|A��Go_ekV)?w9%1 �@øj a]lvi~k-(Y+5XSD۶K-WD KK둂� �wq]tٙ~9{t/]\@�al[^$#}wlW;DJc:Q&� �̓$[6$oB]�+666)M9�3T!�=2+dL÷guW~^p:*R QZ"pU)KG/P� �&N5S:r �IF7ؽ/{ M]W@U@�X_Ŵx")_g&;MS: �<if4 _nUpͷKp�G??}x@,5*v@!B�.zz*e)vמK*NkdK0$r@�8 z׿~mu9F�B9t&X`p{{vY@E=!� �ۡ<3nzMwš7#i@�84] m^7ablk,ҥKb>~ꧺ??݅>Ut �@�"3{ɥG%X!A@�XMݦ}ͷ#^o\)N̻KH � p(=9T ,\:KȜ!�@`@vv̲YG9�/^=#?#: �@{e`#9OSM@�8/~ıֳuyb: z;xN}/v/_� 6{�'^L3j-إ25c&@�<x__Zm=ބ�4'#y{;5 @�ؠ`TO/NXxh��N6__۴c7̺q�_'o7!� 8věCEK}m8VԌ1-� �Eoy[fV7e�?~駟 Ĥe/{ٚ �V@1d6RJ8d@�뮻__h{6m=D�@s&<cMjwϖ|WH �@�$Zlue[ C�;Ν;7s(?�rJ#[|#K_ݙH �@�F5Kz;SʷE9@�| xU?ζ٬իݣ>:K�h~r+_J#[^NV@ @�X RtN@��vɟCPgl_׽Uv]O}Y]ϸg,~̙cv'� �@��__~W~s|ҥKݟɟ`@�!/^ؽ%/Nzc 9POv[  �@�� �\7WUݯw{bÿTdv:?->ْgy{7]-o{ӛԉe~7>m>q@�� �@�8W>=yϞ5Mx&p |~~h_ϖ~;M~>uv&p@�� �@�n oxC76^gGydN~+Ugg9 {8v_җo~ݷX7 s@�� �@�8I(7vEk^/|ᾗy￟}0M@cR/xAw}uOXbd� �@��tO=qwe5{<>>Ov&q@�� �@�rvZbgHDw…}h@�� �@�GAop|([6p�'+$>w7Y5@�� �@�Xo}[a}_TkW/'Ғ|3׾ݹsPU@�� �@�8,?gg׿u6V? D0bկ~5Vw}wwԩU6 �@�� �vj'0x;ɻέ+^WuwuWw*'@�� �@�';>h^ݯS~8�Xɍxg_;n|� �@�� ?ހ'ov~gggњI=�fOH馛n->^%p̙3G.M@�� �@` xf|g l q�,_GO<� �@�� pЄ� �@�� �,=&+q@�� �@�lotvS؛� �@�� �% kz +; :@�� �@�Lr�l3Ȅ� �@�� �@` M�]Qy@�� �@��"K^ZC�� �@�� C�� �@�� __K|@�� �@��VիW=�C� �@�� �E@{�|u/E!�@�� �@�X]7n喯=� �@�� �@`۷z+w}_Ǧ)#� �@�� �@`5 O|�>>!�@�� �@�X3{<8�We8� �@�� �m'G$ �@�� �@` lnn~cC==ſ⃢� �@�� �B#�~p\ �@�� �@�+NSeN"$� �@�� �@`-2x `IK_]҄� �@�� �,'?Ym0 ne!�@�� �@�XIu}­`U @�� �@�9uأc~ � �@�� �@ ߪE�9? !�@�� �@�X9M�K}9P҄� �@�� � ?v NKvy IC�� �@�� |d֤^M\ ŁV|Qk&B@�� �@�Rz6n �+nll|L� �@�� �%Vv�1{yg$� �@�� �@` <cZ�}\V9 �@�� �@�KAοՓS2{챧YzA�� �@�� p|?|SY=ϝ; zV%A�� �@�� p<d?s6=�/_06g( @�� �@�[}<)U<GУ�[J!�@�� �@�8^2~z R=,iB@�� �@��2~{05Jw`kk # @�� �@�OwW�))zq @�� �@�hsګ1V�{oS"#� �@�� �@`Ak~~^^ p]N~!�@�� �@�I@ꡇZS2K9.)zߔC�� �@�� 0'2M_(j'�+ � �@�� 0_Asj�pr|^N�?.}]� �@�� �@ l2ay]_񰝢< �@�� �@�%y 9�ܓ5ތgT�@�� �@�8-?yUz~ϝ9s+z̳@�� �@�XUz᭭7?裏^Ҿ�>su2� �@�� �5$%7G@sz$G%Q?4 �@�� �@�7}z3U2W�k~.x{Yh{m!�@�� �@�+@`S}B}] zK>oo!�@�� �@�'gwvv?: f G{>8 �@�� �@`h{Q7>C ^G5Pځ� �@�� �3?{ˑQ�oy9~Mo\G� �@�� p6\#5ێE /h!pW @�� �@�X=hgn_4K�h:Uo3_J6}~# @�� �@�XV_VM)~lw'ZFX?; x�UD @�� �@�X76(|ڵk<ȕ3ws-~+#9ەܺ �@�� �,-gԳ #9W?W^#<ryiG@ �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�� �@�[2Kߒ6����IENDB`ic11��PNG  ��� IHDR��� ��� ���szz���sRGB���iIDATX WMlEl:^GIiKI8HT!" EiEVmR*!\zPAEhʥEJڔ i$ubǎ{c:2gpIO3~y.1DUC}1P5q�P}Ҙu*؎[g "5s:Vu(G1;|qu; ZّBV [YB_heS}Hb~Ч H$:m&֑ihnnI d`&tݥr9–$mjo ^.K_@0;׵v+ya{n훘KB95Wؗqy&;E?qU0+8O)hA:eV=I2ıdM'`z2 k1y&[4M6ZuPs2mږ;Ϳ@oZ#r.!w|t~hm6ֺ2hhT 0l@.80p7MBdq,7 o ])ɶ7ZnYDd{ |\NpYtdbQm6^jYh̓ >; >Toom0zVvpe@ާw?ڊv;ٽZ`3P*g^Ro ޷G" Ի6ݛPQn"*8n Hxn4u ʼn6H$HuA[B8D+Tt%ŜS40-!e#K F-X/3TnoF鷯˜ p_c\Mxy 2;E|Cr_5`I<6q9^}+KdyS7`O^ל랷 ~4I| E#%}rR~9v׈Vh/o޹ʴzyN-ƗQ׮#7WՎc}rZḵ2xl.\5k_WNMOsѲ <\q:XsLF%~j D7g(����IENDB`info�� bplist00X$versionX$objectsY$archiverT$top�U$null WNS.keysZNS.objectsV$class TnameTiconZ$classnameX$classes\NSDictionaryXNSObject_NSKeyedArchiverTroot#-27=CJR]dfhjlnsx}���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/extra/promo/alacritty-readme.png���������������������������������������������������0000644�0000000�0000000�00000401634�10461020230�0020127�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������PNG  ��� IHDR����w���ª S���zTXtRaw profile type exif��xmPA!>V9M>(nD@$3:8KjR!&͉R I0Q|x0# Z3?>7gEHp_ }K(DSȦ8 y z'u#W޾y0 � 6bpk b{:> Y/0!?��iCCPICC profile��x}=H@ߦE* ":EEkP! :\MGbYWWAquqRtK -b㸇;@hVf$�ML*)b+B@9*3˘4|=|,?ǀZ0m MOeeY%>'0ď\W<~\rYQ3'.VMx8j: 9U[j_.+\5 "QA6Xy?%r)䪀c5h]?UI 8c@.j8N3pw&0IzŎm⺣){0dȦJAZB7-п} KJ�x}ݷk.ro(�� xiTXtXML:com.adobe.xmp�����<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> <x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0-Exiv2"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:Description rdf:about="" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:GIMP="http://www.gimp.org/xmp/" xmlns:tiff="http://ns.adobe.com/tiff/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmpMM:DocumentID="gimp:docid:gimp:97bfc33b-83c3-4a5c-81c7-4756b93bc385" xmpMM:InstanceID="xmp.iid:ac82669f-fb87-4296-bd1a-e81e471a65b6" xmpMM:OriginalDocumentID="xmp.did:f3d9776b-2535-4341-a7a6-307a5fd9e9b7" dc:Format="image/png" GIMP:API="2.0" GIMP:Platform="Linux" GIMP:TimeStamp="1684461828385275" GIMP:Version="2.10.34" tiff:Orientation="1" xmp:CreatorTool="GIMP 2.10" xmp:MetadataDate="2023:05:19T05:03:48+03:00" xmp:ModifyDate="2023:05:19T05:03:48+03:00"> <xmpMM:History> <rdf:Seq> <rdf:li stEvt:action="saved" stEvt:changed="/" stEvt:instanceID="xmp.iid:5ab5477e-2940-4f29-b723-d5a9cc63ecd9" stEvt:softwareAgent="Gimp 2.10 (Linux)" stEvt:when="2023-05-19T05:03:48+03:00"/> </rdf:Seq> </xmpMM:History> </rdf:Description> </rdf:RDF> </x:xmpmeta> <?xpacket end="w"?>wt���bKGD������ pHYs�� �� ����tIME0CA�� �IDATxGwWoDz(DRQJT=3gNr72=W!Eʔ(: OA"}0H  sS3㚸7. "C %Ź/XL5""""""""" J""""""""bJ""""""""bJ""""""""bJ""""""""b%NF<_|gajbuR YZI^=n 9}zOwmd~5kR?GTƘ\Ǿ}}\Ҝo:9zg㿝ᆯދU͟om]NKw7m UNl'  ,3EkO, v޶|yf5|&E|n;L2Tj|N C:/} nXܫm[H43i_NEI.75. kXl4طOV\g"""""!& <Ub^s-3BkV8rI @=TD['-{DŽ2�3#ݱ XcDS.'R%o}=D췔SRYAaz#C&�/c4M&|ǝ_S!ʂ&D{N\Ro:9f-8+݄ QGShŵAvQĊp㛻̤-0\ut1ѿe3PjeEy`r$ݑ`ȋaexq:?OxE#'9|L,(|vώ,{@yk+uNB!#_կ/#k9J<{po_sJuLDDDDx9R~qLtQZMAfGIr ̦n <}2 &Kmfr Kc v `%%6"Q-]]`Y?]5/v{p+Y;ǽx:NT™O07zfKAS~"95A_O7;?18͹j\a~ ᡼m T8,ɥ&ybyl@|N˥Vo5+I6q &xy0D(h%La5S-' {qZfy!'ؘ@iʟޣv s9EˉJ>'գ8#R㩵?M&b _;Wx3~y^? #L1<TʰG!Jl MoJ;vF[`6nn ) p|C3%:ԙ`X)3-;? Xr3{1fۉ=,Ff]7-Uɋ!<`XY txf=dĉBPc.2NOoc c` p-LwW2xi^o7~uR_ ["FN_B_j> 3Q`%'^OДl/d; ^^ ^?q ʼno;F=^k9Q"M9}/c +,0ba9kXaǓ\ ib3̲<333fHZŠe}zh fz+/;7,5W6*;6F[ةtj:T\czC,Z=\t7;}GDDDDDm9P L+ɳ c'๨U`&w_V=0b EǠ48'3m 2MGhKUUcz^:J23+xV&}cƅz\59L>oΓdpQs\ipd9fE]n</JeyKP7V37DtG`yOf0LЄB4vԃwi^hpRyw|UƉ8?[嗝Yk.\0M3_ ޼ N||7n"1q ~by0´va Ś41ROrp=DSS%3;e6 `<qx0)ߟP^]c$Ins=w/e7uGaZ+X)fDDDDD7PrW{4,wLl Nz|8JbLyC 0ͼw 7L$Q3?!7mXdq7paIzB{edm!; E  q+@�kL `)^KYb$LsIy7$6[m$'h-3H?銅+"`vP JY*Ljl ̱0>\WE0 [[8y1Sl_K O1s, V`Ћ2κ.#&ٙ!g|0(;Q(4Xn?,om߾St=փ7eX=f|cm[x4Ninm,b^nmvfBǃqX盝#"""""/U`m;^5vbKAb`VؽS^A Q]cyv f6nxb˒`h)q_[m٧``ZINAs33YN(`B!A|yL|I:O"tC[`y91lݒ8{YU,L <;$VФ@46X|=}VŅ#+mvM^߃trU[{uoٍ]O A˩xI{vW Ǿjd*fEPt[[/xy1H'Wso;-rV"Nfȯ<y#z\dݏx`'Tzj\[-( =mj~V OJ3<Bn +K<M($60"Zbs{"_0 q8n!X8jw \Ft"B,KrtIķO(mITmSg(h΍ai?i?^Mh oHĶ6 `-OYgπ\XQwS/T|'GIZuA5 tT8 14ً 6XDg!;E׃( /kx[ȡ}$T^-fȯ9v2gjdra-3Bg_>J[px` rM&h9řMOsvIoF,�+Rlu3-7fPЀ>f CAX$ r{}YZM6%C :;+p;Vg/>"Hhd|(EVo#mT:,R9b뛛;W1=>d_sPsmՃ�d^ WY %f-ubݣ~tM{s9AX+T0XZ$x<8!sq`-0t;wϾSlEQ`x"Gn1#@yčaЍc`x-盝cx*8y,^DX;cyTA߿^C|kĖ2Cw_V"mhX:X1ޓpo]Q4TW;ᦺA~qjcn\A^+Ա'ʑ$ `R K|:].A|,R89 8ʯ_^KnOsk@~YDUlY:%)થ9o~ꟿ/nӇϻ46Y[OW._艘t=xqKU4,쵥rѱe @c#ϿAJ>Ѩ$E5=W>Tzެ[6[mQD=0!_{iXYfֳ5 rjkkK*[^nbxX8`ip g~WW"""""I/Z%Ĺ- 0!<]|x7Y4ù~ Jz.]g{e~Ė\%>TEg4J<alult}USnhLE6kO3R! 9765ˊHX&P�smL`%F<gq7gMcB2i 7pa7I@r²H/JR6 m4x!tgML `xM^_fH->5caFSRXvZd|dw9qSc/cqfU召&zrz9_[r9},WI=O#Z <`|sZbbdԞ_vY8:,R/,27;/*QeYiuqR?0;8ȋva%zi] r ɽfrwwi@>$""""rLJ8WUe;Heuȓ9po l-b{cb;aRKG0hڌ )='ULUK3AW G3 S,=e їkbLĖ?؜֖8B/?_0%?=LU0@ȟajGe{e[RVYMczWU\3-DK[ N+ `z Ƚy$n5* (8^v-VOe8B!9?bl;Deu8||3 #6wKѧ3}vc R,䦆xa-ma"<#y4:JΞeEæͲGIA66ón޸@MRGyY_>M|zF6%i|+?XKL ?:<)$""""FWWƵt,Sح@?=Gr]>*VDv.I0_W=l[&5J;%ZDDDDDdp8Bnj\ydk%jOq `vү6!O+$"""""fhO.a"7Fv_Pzة}y6w:#Jd+6Pr:DW"beXg}F~k$`xBV&N<dqJ""""""""$""""""""آآآآT<^n}W_ T8Xt %WG`M7Ho.*^'V6xmyۮ幚Z߸>:5#t5'؃ݓ>9`P2T⃋=zW?NfpbD2*{poO3`l?A\F|:57Yf``&{""""""""J\Me|4ʼnZ\;TmN7L3@O8__GgkKX@}nAa.^(<y;飩YW-ݵ(LbAH ZB)8ƒG&Lm13(InaZƤ'so  bDhhp'ܬ<??!y$ Hg/~H=`8Z8X8%oV�ջfx8^L&r93H+zv?M|DL_G#3 #)m9P L+ɳ +r7ù?#箥(EmO5K}ZbEDDDDDDDJH(=}; _ YytO>>C!'H'M>H?p""""""""<G誠Kt;Xy~N6ۙ& ZN_Hgyg'j0ơ14u12d(VDDDDDDDĎ %gKS"3}~' IYeC:\Wm=5.K\:XR; %G 9S&;? f=t16^)Xinyt5 I&Gam%9sɛ˜=%o 2f ŻL-046,(2̋ ~D""""""""JFs[`Cx 0ʻZ#,o?:N1(3+tMCX@~zz+ڹzb?LFJ\%J+"""""""rHoOyU5͋A*@˅iñL[VwYn XKoXp r+,>{A,: cRKG0ŊCK(YA/EŦF/6<[L? 4-ad^008KbEDDDDDDD*xnzqYzϓׯ(VDDDDDDDp]]]يX,ׄ %E %E %ũ*xOW5$""""""""($""""""""($""""""""($""""""""hSs՞˭x \۔~,翾"a7)˽?!i[ޟ?sc,{Rq~ׅ#h7>r>S%>q<ԝ^oq<Cz8]m+~]߅ǡlo[?bzB{}*=Xӷ1pM[Ca+di C<vQj.6zIM~_zΑ]:dIRqcxs>hp0]^}BLr*Nr+PU_iBC<!S1. kX,ڈ=e{"g@>?>!~qb1Շq; *k ̳tu~ڸs踵؎%ok޶~&"""U S|pZO`. pbD2*{poS$wa2 s/efG[Qhsc�xxmr7 Tw:H{RYAazn:eA q=Jf'8mYBe!L b#j8c` Xq8q L>~FS}ACi"ΡcnoC[*ƾ;e{J\Me|4ʼnZ\;TmN7L3@O8__GgkK'<'8n#>R<wgG9UKww-.+W"n[[tL`7u 0 GY;\V (A'&b'OQ{1]u¬NtLWYx_?>O/9d>_Mm6}w,y[3)Gx|Iw;_xd}$0lzr'so  bD~˿rSw&?VIf?$0-Al1굴5ayD#5^|^`e `E ᡼m T8,ɥ&yby믝N2ieX^<~x+zڵ s9EˉJ>'գ8Ώʗ;[IϬgA㩵N&Y{<Ku?<]/YN~Gwh픭Lk{7Ft:3`n?l t ]U9gG, mxh9Ewka/B4~NciY\x>`hȲk _eeka�� �IDAT'ě71[;&G:N xp#X�GI[>6&"Z)Fo;o]J}y6w:#bV6qm7;}iocL-lEe+zNP) ꯧ֛靟\g50?g6[o?[Xb_:{{٫ckU$RL _ƨ=4;?o~/Lwmg~OIUo#b``lk?‹@=-`ň a8mg1}c>l(IDXvW5rron-bxixw\h`$Q~ʪ9]YE K38k:X}u)ˉ:{%\dv&ax(*c%'0Naa VP7&XL* K ctXʢ 7X_O5dbhn4- r@ΰ]daIMU'zާw?=vFK8[(dX@y/'3 1=KhWPe}Ep7:v{MkeIde}+u WgYV#Ņs'Y 㦤~ |xtOY ựԲ瘝!\U׊{ec3!CV&N|=Kdxojc;ネvu^acLN[([c`ȏ/"0a~H(2xidytc~뷈~Vb^:K=~טj@DDD~ 7M8Qi%yta믆zϵ ͋wxB)N\P*_+Ql1gn u;ODc'bs5|'rR�UݼHOs Gs32N,4nR\pኄ?O$'>Ml%".7~zCa`~&Md06F4nO0`B,F֮z<,3<83ŗ`e }w</7`RUƘ^\ITR/]k6G)ib�75g?J{JgNlǰ_{ߍMOs<^nZô4W2Jي^݈X�Z޹x*gb殣2S-Ɩ Au 0B):#G�oW<gJ#^;;msm6N_5LSmVXm `%uV<+ܾ1DBi%[{]FV:K=~V̘j@DDDPrW{4,woI5�3zO*f&H'M>H?p]ĶZf~: W*E�׋AzmYZ_OA&RrbI,bZ|El>#_3s,0S]> >e,`cr._.W', V`Ћ2κ.#&ٙ!߸^6O(۰<ht2,-.c5D0&sьm1X|-6gj&0D\oX~X,3ۃ<kۍ-`۵ElKٍ㝝YRbbg؊ 4H>͏C,ͧHe- Hyw2FƲX;q*&d2>xCվoZ^g x @Pt6=w ٫-S"jgP"M܆Ez~oLb9_±ok�ׯN<K=~V䘺k-&\|xr+oݩ-gէ90X ?}D /am%-F|0:6E +<>/z37ƷږI:IVڢ ʰ5qdş18nfpЀtc傚m{uψ؍-)' `-N%  b`[mj+׃Ej%VtƓ~b1){Lآa)=cm_. tz:+vuF@x/߰쟢 .~FK6‹'<z|Զ;zSz1CX$≭@svηmc{CfS*۫-Q"jbc$/V"2 L($E>ȱoky&]̴w{~1u"""K(9#t^*{|+^L"M0u?r~˥!j{q_rMXK[T:"H[p~Ҿz8` ɵ'#T\rO.#O:g!`9E $40זXE$3 W^:\p >}& oEfQV`M3C U6ʒHl_bZ;Pxj7 mήٌ-`۵x &j]ǖmbg(�~"ղgXmLVNuPz*o}ݙXfZٌm4 1,&ާ<9mEn<EIj PXɐwrϕpwg&_:}{f?3@DDD~[ %G 9S&;? Ϳ~]^d~~e$K88™:dV"o&#mT:,R9bk? ~L׮kOۊ'* :;+p;Vg</>"HlzJ�d^ WY %f-b|b JsRqV|u`ݵIxpݣlfh[+  PX~+5Js&^} �k[15Z|c717"ưb/g(:Ǥb_z˟۶CXF;7]Ke{\:SG[__ ^7ʼrvn^)2K1덎vmlg|nv ;dgLo>c_j(d<AX+,8pog{)~m֙3;c O'OV\ً(DDD& r<*H9{K~qo /zӟon=fP/ -}td2{ZK{s#7r?%^�ųݚAӷvӟ"M p_!vi>I+OZh4"ԟuBW._l`Շ}ŋ[2f1 4,5\زoIvdvRes z \bSz\!B^qhaYɛrZc(g-ve,0*8y2cB+v*=؏s /dHg,0˩%[^nbxXGPhIaXBrS&=V PHVMAݸ鎿6�U5spSC 8zxovfV3`GM�&Ƹ:^?E*'W±okYgvR}:팩&0]ʅrÏyɫrhx@η4p`wF Xޤ&vN1(3+tMCgͼ\%> TE& m4x!tgM׵ p{񚼾J >5caFSRX+19?h3•ISWDk9ZߩOcG~\F;<^Z 6zt5.d+ډ/Lwa7E@r²Hlo\*E2p<@~?J!+58eZ3G!W" 9k}9 ^[bbdԞ_vY8:,R/,2}9}߸),21D[o9>+A$pc<7L|ǏnyӴ z#eb,4GZjb+~a?.3Ot 1"Y{lkx>>>YOω[dG<^;ہNvcgLݧ=Fي scfcm\1I(\[V(طݫj"n9K=oSm]l RwIDDmJ(S^U͖' A OvOنc}GoY[KH';l}L;{iFv_VbI!ZjpZ)ƧRː-�ۀ+[AQڀce>Op5S gG.^_-÷6CO[=eVCC ?ezsUΙmᥬj={nj;c)^ݟ#ݾ[ `$757dl`pĖ$3涰Vg륱‡`f6ZB"ma"<#y4:Jaa>w^[(/˧O268\j˾AEǮ?)l,+k c]vUu_ \O7u+, &_ 渙z37)t6P.ÓO|LD79vya1u =Fي-rօ^W_lf;[{%2Jկi%lv 6'st FĔL9 FWWj,S�?O_\6.z?LC)UCz>MC_ yՉ!_Ux U)oxnzqYzϓׯ(V=}Bţ7$r`}G]]ŘI"""""oNU?>X96'xbU0#;ϣ'T3rT0m  O)"""""ȁݼ{ WU2,ώ3>#1NUTWwi3# I"""""P9(1n˘Ar_5!"""""L{(-J(-J(-J(-J(-J(-NUAijVч|�KÏ9HP2|u^|Jm|cvrZik"ube,<ax`gFY}?^mglV Ԯ?I )U;Ą\ֻn45z+X$f*k"-Ɠ[3–܊B"{TUko 3=LbEDDDDDDDޡ%zp!hv::ʝXn|sfp2&$?a:&5몥ݏT""""""""%ph x0vX#3$ fk2Oq@0c[&^{pp""""""""qxKެS0wΏpW ~/LrS]M4=+Gs1uD02S ̐=XRykf8Qi%ytWDF?qwCM*U`&w_VXy;Jjz?|FEb,v+$!ĻXKɧܚLڡNz|8JbEDDDDDDDJ<G誠Kt;Xy ݝbszJ396;<\"ϓ^,y\T:᧹aj`VX;3:/}DO=q+SsX5x<^\a~'W VDDDDDDDԎ %G 9S&;? fD}=u^ͯ{< rCI&aFkGvX[bEDDDDDDDL(A߿^C|kyx҇|tzZJ's J~>: 2S}ZbEDDDDDDDm/h.>HϬNA4ù~ Jz.]g{e"PXap'E XG0LmRH20(1w=5K?a*VDDDDDDDJ?UD6ωry/5oY-odN1`5Qd-37{l$T-3;>Δ`&坽4`y#_+Q92XTlj:2jsq>  e Β=Xd ބnj\ydk%9\FWWF"FϟlT)"""""""7[3DDDDDDDD%DDDDDDDD%DDDDDDDD$""""""""{J""""""""oJ(-J(-J(-t:9`|G9RԽ|Q/1&dEYYep,$/^ȖS*WyDgd~̬|/™<O'oyq8}r[f.O{ӧWtY4N֮~o׏5[g㿝ᆯދU͟om]NKw7m UNl'  ,꫚w?BG0Njx#2#t5'؃a G Gݝ4FM e_1pzj ] XVgsQu桪ӄ*~yB2w I7>E3W(ϰcG_޷8>BLr*Nr+֯ޖ<ɍ+|6Eb)y_4~;5R塯 tO߯X(]̪wZJ1v߸=S#PGGwMut<gx}8Z׈""oCL(xNjڥRݗ[%.&0eT6PYn1sL7q$ ͽtdA.ɤHWQ|*Nt17]*+|^l*=DYЄBh3V#c;+(L2[APYXeg&pD,n0|3>t%ϖޒ`„`e,,&c B$;k}_fv&z-kM/36$zUU஥?T7+`~vĶǛ!=(3T 8KyeeԶ'⇿G׏[u("ҖFi^&\2>Dk-r'V|e&m'-7qε0 <;zy\twⲢ<|0[ZG~9+0|M\4tJ !'XQ+BpYI;<<x^lVx|K1{B> +wdmXv{[#"`@~?<%z@ǩP#U*�or}+={L/g 0 عlۛ8qn$q8q]ۏeǩ877r|;ײر,iWZ.wl Qu s`@b@PGe{}뀍3-|8193|Jok?ḉ4:!6zҏ ,Hނy{×VnW+?DeU"VQ ĄRAn{kGUsBb(fn\potCundɝ6<܆G^c W%d|{M)UٍJ͐;Kܾ͢=\,[WP]ꤩL Ґl5urŸ�� �IDATd)4ŝOݗI6:RGcǬ'.Nsʊ\מ!ZNάqMp//r7݂e0袭ˆ<=#^lYh FөW9R;_Ù2t6 Wv;vνxh?y󚄫/(_y_276{߯U<)-\0 s:u>^},q~:)"3C\h"B_\-nݤz-֭Tnkdwzp]4Wyי,Fd(x>ϳ#TcܻzW` nf�%bMVP2AB[]h,)y,Ǎ+yz`<&,Vo=Y@ZgDM3Ԩ(3q7ƁVRr[7" ~RIu 4ӪFφ*A1W=Xu 7y>OY=O6Z 6o3-Wy^dm avXF\AMoo"V[^ُ<C9\WNb3ȻU:SEgS ;f=Adq۷=&Ula$5Rкՙ@ J1&{ndbtEsܚ{;H$"+7ϣOrb_)1IO}ۃ"8ª[&c%g1w ~?jsn$HS9N4$Q5ȒōRȾ>os\YuO*8" O=e~,n2Nhfi]) ϳ~K[$q 9h<4GlH8jpɉSEˡ2\3\n#u+ MӁȾ:@%>Y'<v/w#]`f:$0jX+( ql?KTte7237-OP IK -cO:$H [䵅$ 197o=.n8i>v S2L,ZCgD`7VHH8< Ḏlx)`]2a\xt6YxTԇ P,1n; NpŭIEVA[2'7h7=tL!PYK҉ߔf:#}y W9pvzXQ C*$u)%rJ{uv7L2]c>o֋͎7o{h?~͇9`w"VrY=&M]AJ 5g륱CmQlHv<]ELNp_z濆7u33@ &bQǞ2d=ؽ5KseݱS5g.vVPEEcMn|~De7iɩB.NNq /r͂!q-6W9VέޙF RCpUi4@򶲿YA[0� tz?7gg2{<9=lދ3+FdZMc \ G\qN{\H Є'I$<ո$@ueȺʽ{GAubc׸0/z_bם \v0 hxE <HS )Fg b|{ i0y}9ʠC,眹Oq{^LVxv3?fn%€Ɋ c}p _glDP<x&У pA^9݌mi+kedyVd&3mC<%#@8YN݅@W lKQaz'dœv4KMOdFs} wS\?nmK0jj=$ٍ!ADTQf17]#>o֋nMCA@O.jv=ó{|+0 F)juk/=jbrlg7]H)@0)4:W`#]@Y#u33@ &k{:BC'<tSSE=5EOUH7ƽW;qwW$e_;{{ n"!n`MZpH.W3w/~+]/ޚjMCNҭn,6 =Kw;K Eq!3;]B N!#ԑ,|~7h~ׇ[ idv񸩩v_Q@h~·�L¦(X%m"u>dL fxyVC:ʌ/rm@3 hN,6[-[i I'1Kt,G3*Z}:3b% y%Az k E]:%##d28WbbIv#d:K7 8?trMdSz옉3p-YK7^Nd3c֣ el_^ws;۸_jQXT5Gt$g#N;̽Ww z腷Hf]QH:MjA ,7K?^7 |WUSI< 6I'<0wPL[ɕ y%`pN)p+u8X ߂ 1X]O=I޹6w"[ט i>4kkj3zc~{LJNvk'%eJT&W<$RCݙ; E7V<2}/}V*8@={La5u2#wڨ 힤p -'^)f~b{f[hN%xO6 J*:1B%|<R2W%lv:XVެ~ cf9S@'lhU}-V :x,Vv<YX ڬkP,EPKNϪ+vV%F%b-opnĒMmRu.n YQ(N]n[u2瘞MTg">ͭGqCy7ﻭ'76>9j(P̊[!M)kmҬGy#> ok#nO;2:6^박HVʆ\cT5\b{(-كe tuޞ .k,+\g@L(=t>ڟ<IWBb:}lFB#8:y @ swx}5pzXߖK8-U]tUZH/v}wKMKUv>ҍ'f7CT8u u3˝3*"UCI4݄mI^ܴP2wԵ_0$Cf@~otv4QW#Ewt(*ntRX*\U]@�Erkl ?h]A$_mK]ڎA]TiE,٤dX+WЛNO^:3f% y%Q c>] \J9*MoHmcI!v3dm3K b%!$ G2RRئ}]*"NPPEۅdɝ;I/F|ވooFJv<% .ODqнH$b'z~{kӖC1mQ`oe }L  1yh9~V�2OWMt}kAA6~De $ml$\!ozHrB!_d^l4g 6O3#/m ~),o�z= yd;Gxr5-Zz;/nIi)>"WQv͔Wa5lޕV%�-YY8k\*{y2eW:֌qe%'e>+'eRTJ5rIӃ: By[ SqcB'IIY{D*ɦ5eB,ߤ+}ZЖl0K6m'~TLفjpc q4CGtƣd_xHB.ޖ}6$=A0XQ{Љ�vCjbw$5lX,> 5Hw Ʌ~le`nVVtfS@Ɩ-"ڢ\٘Xz|[_[dFMv36-p 3r)I/s^k,Q]B]J]-5X%bDp6+EJTP^QSSg89|"s_ wVqb:He+r9p]ۖ%ܸLP#Pؽz/uNfI'ݦd_Pl7Z\ݎ [!N\Feb<. I,#7�jeg%/VQszfoV؂}wFi5xSxBOU={Lnji?~=6Dɶ"&9i8}5^:َϴu޼܊*-̈MJ"d_+/Y¨K& bdd&;1{Rdvqd&dG >@ν&YLU1l-E.^%Bꣲrʮ}e$EȊ-$mP)vޡG\ }P?d֋6⃑݃b@rPYˮpKoKi[ myBBrtgTJ.lIJkŴEAW\.ari<v%_/Uk3Ft ..ٮ\~ U&ੳ h^{:_8\DB#%Y򾕜̫mnsS/עqdfB;Pk5]+R-m;4y-vb ,N_# tql+}G-EFi9TEաxM%0*M: D6O֗B)/@K0R$h:hW*R)]ZsU.fY2Ik؋tN<'9Mpdr"VPiՆUf<Mنz\ާvS.-3M3:[Y pSvehjJ|*-'_|!PF2GԼ#wi ;¤n<.+ezө"ꖋ'5x`n7,omfgիWuf&K$ yɁsJY{у!ºOd2<\Ux =4k*2ln;"N$'9s4B-\jvFnnv*s,ٺ~^[n66x1 Zҩr)(Dꇌzlo._-LxUb&' YO0E%-c${*{$m )@5wo=Plv|f|}j._/Yk6}1P` 7&yge W2r/ؽ{zakz+onxUswxM7>V2%ԁwy;EWK-^=At.ZªP^Q3Ga6%NuZGHW'M4KGƹq].gKv/iu핊dW]kȜl zދͮj?r'$`d;]|Yd PщOYz~Qd[^AŪ@ak?۝] ȘQ#}^8&GQsh^]]^v7UpSC 04zsu[%%)J'P4ؙEY{EmMkHB}^ʾ=`VV,P/(Mo}WzqlB4Y\Xd,ٴvB,厮 E >6nyֲu_5 T#9,4pc^k^w ![/vm`+l |8:T;L$Cӌ ޤ{;~:VC.bobKXbV/#T}aJ0&\و?X(op_CY>@]GGGG#CЈQ:[8a* >|]F6FT8ao^G,T ~^LW8be9?X}Xo[7!@}NEMC`k74Z GttC'tnQGW7 /%Pո 7W >q,T0$kه@iVܱ;\X @ 1yHJE@e ,nB^CI <fQ1/w @E)(V =*-nB^Ӈ;Hu;b;@ MM |Sد@غ@ .PJ@ @ Mr @ @ FL( @ @  !&@ @ J@ @ C %@ @ !BRϟjśomEmvUⱛ%#yי[U7oIN-#5>%v7x~ӝ*lGȫl0}k\ v~^xMxU@Qv%;/olP^.N}Ql@  J'QnC. PinZxfdQzSSb3rrV:wڕ)|m.D9O>&fX'Ty: g*aFv^,TC;rcۑx<$}P()tWW+UU�">Jy2~fRK;67y@ o_ƈ-ɱ]T3?&Oeo=%Fvy)o袼Ǖo˝2j2M SFU"ܵvDb#(` Fւ& 1&5M 1ډq{HC*"o!YAS ]>xd4B!bcKv\\~)ߙdvPx&@ ClۄlgNƣ3 zBU7\xqdM'jڛt/%:\:IR$7^H03hKwWaуܺywոR}L\> =:D0ȃUΏYP;DUĄl;Ӌb=DҨjT@vq%;-of;A^3@Sm<n @ (& 쓱p׺C}QR#iji,jp,bCC{Oe2zlG1e7jf#]t6PcDg}aR-kdws;&-Rh;n?U<)-\0 s:u>^9(rhȷ@w|#k0\ˋMH򕣍z5t`иg? !}4G3ir,f&Pn< zp]4WyC]n#c֓DMDdeBԈ~a6IT1ɿo<[!:9BYK=ƽqp{�_f&YB;3b;k٤3׹MWP@ꤩL +mh!bvxYN> ŖQWNbͳuu3袭ˆ<=#^L"bN̐ol7CYPk*v!4Vxca+FPZg zz>V`[HVμ| m;3f70[ ZTaP@  T^^+O<^ʋgSgYkHjvaLpnfb(miU*!nO-S ёܘqѣ͸SxX@;uG*<6U"WFe} N푧9UqU%YP|TW"M05ttTČ["D(a୨2?DdyÊR愥( Ɏ" 3&,05:C씆�� �IDATgM0;Fnp$7-'DbI+490y)nNĈ,Uu$\U [u3 O>=`Ӝ[צRjV21ώ0ՊЯ=qn1leTWaa@^=&rۅ9pR|z̐Eۑʤ"I Y TlX| ,ƌ_m@g:dgb "Ѻ9h<,[qDA")N:K.`a ŒDžۙ4Fˆ%Nn OUX8<<eUxbwY*iS;=`\h ͌2Ff GZ09jynSy b @.6-/[|Lui+C֣ݛ_)@c IW{,TuuQiXu_+QMf9BOq%)L9ᥦi.7R|bRslдi4@r+%ГA߹`x2|Ӌcrz/Hb ubc׸0/WQkխJ&R`sASCE,cDg-c\{:&9i9+WA򶲿YA[0� tz?7gg ׈rm �+tBcc9s|Irq@2yKyt3\sei [mglgM~φ6iD^Sܼ0Cm`yHxzUU_ߪ,"\L Lr{2U َ$&wh8'۽X\.$X0`gFbNc#vf7n~ #) T 2o3<LJ `dw6`‡BUN.Bi<4wb#@C_FbH @ (cBZާ ]gfɖ]%Ż n)}FD=H `p9J1[)jrsoM5NI'4tj|nf'P`t݅`q!^C6Hw@qA7Or,˻\nw U&)SHjT ng:i+}i>=,LB"bn>I(EDž,˹_#zXncŁ RM/nucYmldFqI^`nA*fQuN Hz{lS/ֱI#L$z+tůrw;#3pHaIwFU-a($ӋtXRG8X!Nd=^ފYH, ~lΌb}~(~7%ێ]QH: P*>$Y^ݖ_Kw)j$zێDsu>t?gL-V@ [&,et=$~KWxw%XUMJ332ZN ׆OJ0Əl4ǁ'X_}g3J+eCZ$tXnɭd^# -VݓaېЉ-L%7wfPt+Cb͉!:u0̀ZKIFtyIFga1wSj>='}T)8V#_#zȖEƿEou׉u&9rv^=e?K-[lSoBw06i/VqK-25piD5t&(+l= NjIra'FͽΌĒF̈oQK UaGF']"mhյ_Q4,N\n$YN\^#1`^R~@ |wL(}?yuy'u쪲@jc?hTuUi!Mݍ/@-Ui2f-+x=٧#Yy,$O_IlZPp%%c4kEؑj|PeHgQ<Vd̔wTW)M<2J&>?nKp!5ܠ6:$gB'd ZD%KU1p)(&У*jj{lS۹&31u헷 ɻln0aiT5R|*Dg ElKϗa9?4j;wLgGu>]jk)mM'na3;3Kv3#Y7BbI#(l&DZ2d_L#E8n-j^YYG[t?s-Ak$)[~@ <J&-OJr`%\TuFm}82=ƏlAX$ I":x+k̨J&' +9)Y8F4 Nd7[-*='k߫p+ĵv;q3=<*.>6\<Az^Ew~\͑N6W^2_Cz`J;ْ{%:Q5LJʘ]*AjXL˥MmAt8=,oˠS\ٙy әྶ0)JX 7d;Gxr5-ZzG}S;3Kv3#YoVbXR,%E*ԣ¿N,:G;{h ]nw%{vW$޻,mlf_VF}}&$Č@ ;S*7PB?e~+Bî2d=$mXٴ6Db_+QYN$5HX|;u3ϟ˷l d?UUvy3e$ mSa Ԣ%H2p(n,N,ye@Zsg~K',wSo*j1|љYXyzn\&Kl/Y C]t C5=RLzS.{rV\hCᜌ(Љj"RY!)D։#5CtX xd;>CFGdgQb(Hg9ttg|SR:Dzare3#u5pŗy#�h1sA:Hv;xeS;3Kv3#Yo؋5`;݃b@rPYˮpKOFO0Nň1ST[B":T0&-Jg8~ O<uv1R`}ۦ\\~ U&ੳ h^{:pމFJ.ɳt}+9yK_t}4ze1l{jvWbI/=^C/pgp<</XŽqbR,^r-0rg~#L"kQF0ZαWvZDveԵV%\־s%{MH6< pt 5N·|t7u_[`f>EC/RFs(I#KX:2 {&OR5qh Ƒ] DM-3Ð~A_ddpCUTzWT" NݤIǔ(9wٰQ2BJigFl'\%8ܯP 7=XdGg[QLUku+ALAɘbߙdOE}RCM0#1uCuK5q :BKhf'&82C4ΌĒ̈o׷5K KgxZ%frqې3Lnz,UŁќCC\vnW&J pk$)[~8S&N1q,N G=ɉ?P/OMyH+/{^҉b|WnI'<zmaQ߾FDn25١.Zj) s#30{>W#ww{TÑN 1l,e3wv7AxUjV 5vHvI)x+XKÆ'PhX#gF>49p:ML\ZEfLge]k!9΍}"v8LO_xW5_Cz ]T]u<|4qu MdP#*jeEvf.A]S";3b;_+%̏9ˋU"hMyzЫ'DS:eV , vQshPqYlC.bobKXbV/#hfnAz/Ck7xʝZhp^z?EٙX؀͢fZ _CPw r`;4c7Z m+P P!f\I茴E^%1&Rk$\Hꋌ S{|ѐL`#WB! tpT|ƻlW'*̙VW49zx V_<L=iB+w[L< [^:mLr'iη1@&'<LFun*-iow3l84TkGң,,||J  ݽGN /RgvHLm$_@ 1 < &>,+TRقiD/ LeyZ8vw@H nDR(`.>)9G_(1_@ "&M:j**]# 11͞zl'Rc^L&J(mSPaDf0p!MW A}CI vf_# )Lc@ `gء$;]@ G\-@ @ 0P@ @ BL( @ @  !&@ @ Jx<.UHv7{CUB`, @ xmR˩uf$t_ )2V}g~LщoWops|Tp+ﳴ޻R"H"xu|Dv$mZ~w~?ld~7"h§_$-?_ 5]>�K'&Y)TٓNCahm԰'/O- [b[l:[/$r vr^PWa2]P@ (}<G5{O܆>u]&VAݻi ౛ѓQGgLMݗIKgc%^=f~b[ƶ75tG24CahDѝ$'fY!aYi$L]8lfs�}R;eO LSQwQ鴠yP\e|#Ǫ(3Et_-54#8du5a253~kVj>7?Z3wGsb՜"_xy56:Xۣ\owT\cauO(vleF,]L{s4 ^K_VQ8`$oR;ڱcos?|,k'c7kR[]¹Z+&]c~1\rZ n [c'tbSg[fFOE .]^(qr'9;Rzb売 evοyJ$7 >d];?ߙ%>2mr}<U_d򽷩5uٝd[kyʥ3r.-Zro8w5xa)gE~ՌXRؙC_?mj@=ʛEG9K n -o ?o ]ɔ|ߝ%ſD WǞr?}/f?ٚ*?y=aEľGk;1f+<I7/#g6cᝥ&tBcq5 = 1o]Ķlqex9=~@ 6mBT3wтQ\e=hA.uDm5^FYOkS\}"a ,?wO3-=MlWFh$$&YD!? g>].ɤ~'m>Ӻ#{3~~;:X{_>O?_Ɵ6'ѹw}7Gn_} )$XuP#9xFR[|O~ydϼx\Lqwv9Qg(5U0tQml5vOwtCmz~65&<&d~33۷gPl6cI' d@ mPJ/ rO>]>s EI͏0vZ{v#왎4<T$%KbC@ OWN)3:gՕ;˶!_^k{/wf?'y:i}4nEgXxo7?>MNŊa}t0ә/«[0w~r+yQP|˿K�r{YrvW-궰</jOmUtёm/WvPY3O|3Q"H{>?~?替s8I9F60AK'ك4h n_~?x2WWf_W,{Wm|i:keM6#[Hv�˙cS'=?+w ?}-Xğ+7ClT~O{hH_o R3?35$?R~-_bAq92̽wFɄ&&|EN_q><?a*+TK]g0&9OG>ߞ^15K̍p/>eU?8TAD:g b4NJi>XSgA*"]=~c({%lx>WWFPzdǹ$ۨⓦs^[u\P= t" 25U$?? W1#HjdCSIԜ{?\=^.o狀O|E7S?IZ}y<Qǚ7zI֣|L]\-l ?̯;m/26/)46~K|+2}Oş[6~S<תϼ)k n+Pǹ*^j7|1(elv3!.kW]d@ >7=d 7_M sNQ#L ~< SK'; VP_eC,,$J^TtۓO0Ё$sO?9w(I^o!67PD8ħ4GEfd<w6FRN'9Sɿ 573:D&ƈ*�'?שqKy d4cmaN_Ɔd2Z%"=L036OzLI 03�z̿av:k˦q&t“={bG..x$Hp[ç= xo'<_񠋺 ׏uVs^GWpMF1zpJ?GB+$=ح?}$mDpsRb ϕ絲 ~( y{HyG_T=]W_hpRySa%lVSf8z$ d1c_K$~SVM.s$o0AO168śCO2r{7'yw8†WY/o~}J; LJn9S|o �� �IDAT>>xTI>ѩim*~ 󏟭ټD<I;_}4?KzDػɡ^ts߹zG}_z<YfG_[㿯di>Va&J:S\h;|$#oGIgLH@Mge͍x?XGi1 k_Y=T~%k'pd2}\;#2U{ə6R;woݷ`P�9.ݜb ; wF ɴ~F |Oo o/0yL 0=w5FI&;>jϽ[%U*ܻz'@IL !/R oB@ $! ! )mU޵Ej˽*^ْ-fȣ̙3s9sfv m@p̼&%aEVm?4P@x,KuTbCeG894*ݵxX}?F2[W8q Gqoqmd%[8Pb tI7bR#5gKtHRor>3-Z.2(-[4ucm?`z"&@FTT\DꗟdvV02zX!㞟%jjSTr-6L*u,j?5mcW55) .ӌ+}leX |QOCM(}OMC*> _mWg_ ᱵb])?x+gAžyڍ+o-l~_ySjx.q/Xf{u<m79cW,b(6s)Ku(Uop7h r$y-Q!FLSp Bc빾f*,7v HFV}9.r(^x ЙW{Qw/j)v& hsǓᯛfMk:26_ѻ5<<#{VYyu+z|`40']}cX/��rW ~97k⣪̓'.Lk9R$/D4# TP;nIE?\8j.IY-0c˼X|vrH."t2g`,\ԙkxlnw`kXg@t2(!__MA>jbcooX׾ѝc99ёNrJ:8y/|64{C7v]㑯DHBH(z\*ht99c(Yu*IaZ|*9Tc;lK74 Gy*{s>7>t=sъhz]nکG/e=/GjVy.Mඌ’<R@Ch�WA$\p(>)8DQoq/*503UW~ֳr5 (T"-Vdl_cot5p(/ffTÑܡ4zeBI*[i<@X (]ڑ8w�EOېo"rb(ij@JI |SRYY'c@1CA37m*6w/w[MBV&f/,^yp+?P;سi?I:458{` {~c>s:qIqJG > ffFrH .\ƑSJ.GU9ǎjv \Q]| "X&&l,$1K*e;wEo:NrZ8R_G~5[m9xo_FgBωںiU >` QzchY6qk6Jn_w;wv)aH4a )wW6cPuIyh$S ZiS\皠` *%5&ێm8Eiǃ-&:}oR~Tusw~g -{C]VKZTQ2ֳՑ'9:8t0-1Q9tKudaveгSmQ.~Q;gUv<8�x{eo.arDlkbYj 1Xg9n@ !,ZHV<vnԄx 9V lGɤf/P졺v\yQjuQjơ!k9̄Vە0u5 oMt~O:rBsgctC\MR 1< A5A A!l\=n\=`Ie϶c|G}u >o7ONqx综#*aQWީ䴢JnL\;c1pE5􊞧^^{J$_O(T]ĵ _SOrs_v(w)=M*c]&UE1s\79`zv8hJ q6 -e/yɹJJn8N3g*sMMDlV":~]#KtlkDa G%:%u!_?z|S(ݰ^½iTG-մ㕯V[C{~\aP[OӔ IHLdAɄJ^ʪs%n%slF-;u26� ,3B06J@ʎQ"!:$ hlGdOp(.̅tpu0$em=Y+XGnV$5Z>3!=,{Z-Jw+F<>ɔ5*d홠zC `6~L]e". C[L]a)AMiFeu]uܷFut2fe9XyQ>7cfcE,L%!5|~!_vuTLUJsH\ kq|Xy/JHWi gtvPy_=#':Fw\Ǖq*9b~7t ־ORw|0^+K,~t* O;gX ;G9l[k.S,XC|$_n:e' 2qQܳ,_Fg@ʎed Y#^+D@ %ZȮe|~C,f4(t46|ik7̈́lFO zeBf"#/7..ԫx<8O|Sf'l#Jud_JŠY%|eiѡtvߥ2dfaT#MGظ{ݨȘ!C6 =%` - К,K w<"#=7~o1z=|m-jIy,|ێ&Z$!!} @xO ѣ ]ӰeX rr{oݓ$4}GޣDPD4_kLczd0(^_7G}lkB2hNB)+x7{˦uG;w> /ɭ~KIcw7OF@H|]n*b2附=72nvyj,- gtgwFkچ}ם` [|T;vf{d]:lNRl)QJc 2%ƨ!ġ&VH`ԅ$< G8'p&7,I>Gj~53+nnK%̬C¡$sTĎ3(eb=ozQ%6-M >'5 $@q9 XRf2*>UMt&*8j2ˈ LKא>)s` &Y*?]`95/qԍO6pټ0-)KIZGKԐeW-$+=v`ub; \~B$Zp$33x;&SK~7S7j蓵vTI5z_q7}nH=L*(aX$ڪSfdrmfVcTSVA9cC*qA6{,l×nsmmA$"ÃFXɜFpu~.湑x;"9o^^4;Τ\ƓmQuc 'cSœY9jc.!7W"6*>=>Og(n]VR\1|^~GTt⣵j%/1X Y<4Mk8uGgkRx:; fȕUN2k0*6nޱAԂ<40tUi]IOa ǏRhHMA䡼s25?%Y'5dOKq$=vZwv xFm!ꮀs @p&%)$YS1I $³X, ]4m IәW g2r4eOi**=5%TeD2)"bsC15iXy ~,#x޷X\ͩ!86PGyDW{NL"Ɗ/sU>S` ΔXl-H :ݔ|*aE.L"(F{,Kg),J] _Ĭbct$aT(H'l(xױg[�ʪ-k K+-=ȦdV9S6z]_ Y;r<**O"%\ں$UpZ7 %:p=JxSUxfg/Tَ?rjxr5@HhOć#1/pcwŖy ^v"%1)1 SG Gm3$M2Abn\}xJk{E3)Ty67{{kq_nBcRzǖaTmxZI{`|u(9: URH$Iy;Y<TWS;6:N[<a5,&=66i&*D""-B{:N˜xXi*&foe˸j ]c}pO% <4y>GiMPh\W{fE<u^׍!:"5l$O-͟eQiܽ7N".'o(c{Z.$%\JkxtGI=w'D̛ߒݨ02´HVd7 -z,,j<W>mk#WfXo\nB#QzlD ;pb"4J9y𩯼z&pYNl +ykxl H n\l^GPFޟ8}QaP:Zkq9\ C M0QMDD�gvf A14$JS"mqL&-Ί9̈馣j쟏5ggF8OI.>bdSuYj$gmР|{Z&MJ]|>M~3d"&j0faă49>lOcH~ɳNΌtSc$N[@YFrU|Ls.;+ _xrww<e/side:9qUv#/?qϗV2%C[~6 {5xD3= YR5#CFCd$H8wL.%N9X=/xԞ6_φʛGOvݍvQ<AxttnEFZ8jwul&lO!y;_`zc?Vu/ "1ق,7B205'\]|!ɇ}_lm7ǙQÏn\AN#$9kt̘,'{سךϕI㥾o<Vы;Muͬ=oⵟEx;y~48?JVa]o|U{xOkűd'v9ؽϾ^UJx~vSs'Ő"T뇉9Nd$W6úvxNypLk8tGvvI9F,3 jf!j}oqKq4=؏UGxqE g U\F._ុ9Qę|wQHy [,"OQ?֧ͧ{zf2/' ] b:y'cW`5_+z냁=CרVGYSN%@ 3nF1Rs_gׁs\[<DWy wlǕ Ug!b4>1.^֯6:wB2w- Bv<[ҋ[kxuGY0OZ~ V<ȭP׼XΆnֳtCV:zill[:i- b9qPطY<I;;~VbAxQ 낵<A`kt44wpX8NlXx9T%I2 eL,3S" dD @0@0My,Z=L:h |]uؾ^Rp2]6^& | Tw ZID$(h/bD%UK[/6 Y"JX'"58<bo. QKogSc4$CbѸ;,ʿ#"l9D%@ MVFUDt@ '%YC gU8@ >5 @ E8@ @ !J@ @ %@ @ A@@ @  Bt1Y8 -[TNO9qAwQ{Lh,b[Эzg~zOass+mGٸ*(@ @;X,KV)wwT2'ud"n:k(+*=$撑ŨAuV_AqQ%m]F2ltQ eGAc'+70B2J Ji򝡲cv5V(2$$`=XC{>3Egs3 p&-^ @ OС$afނb}G(Ίɋ1ŪEvcp"CDtywS56 ceLСzzwv!X4Hk۷= NBffY*;2rhKM%R/sa0Kr&c' 5ɠ89kT k(Mg&{>3o;�XiwEJ @ |8g%5K&cQlTUKA7Rb2ע:ٱ0ͽ*!.XX2B.DtqdFPvr $Wqt1LNQ|h@ʎ\ 񓳉ԫ8*vP.1w"R;BKh)8..F>zo~Lzq8&@ >]3c}SI@sQQҍ+kJ5̌O dBPt(j+=^ԸTQh*jAJ!9`̧̦Z:PV69�ܭ9LGɀ55i DXh=&)m3x_$6g~El`;8f_4] 7l5PG4.]BC1�� �IDATmGRȎ H ŀ"Wŗ1'Cw9beƚed[{w;UL6]\'ݔm{';ʑ2I29i8f|։.i!O@-%8_OU,Lc+̖"[_TϘu'�MIՆ}ȧVOiIN]@ '\h,:JO[%6tD`#*wiO%IBd$ztN S3M59KeGׇnH&bB<:k)+ud$~,I\ӆ# 05BWq/f[*g}Z:qьY':pn3fvwRE9wQ8imц6Yf ^<^ � }d4a6;hinF NS BּiD]w!L )?zo`}v] !fL~BL)d%~gR�&Z Æ-o^\f\e'F@ g7)( +M]m{iNjKR:iUAc"%-׃W199D: 9>]�ʞ etbY K)e48Ou8j"bBrsp~*^@O,d&99>P(޵b4ͻ x;ݧɂIzp?^%;vS29+(7(+�#P=xXB$@QQU VdAmmgUUwu gl '9N٢zl10p5DFZ:7B c:m}5a KDef`(JJ ހd6ArG6Y0ɠ 4ط&˱N'v\f!5%Rvbt] @ oȟV꣘hIA*Con(X<ŗ\ƪWҕ̊3 g4dJrtWQPfC9Keǂ h薱$NUYqHDh\,BgY>t܁ AjĄŤՅ9H&cq8IftJo1(8l>#\( }J&bCwEE!Hk#;Nr l[1*lAuvEɚ;z7cNC)sߜd qa(Z�%0ybȧ3ޖ$t`);1.@ 7>J:+9>r�v|Dw2"1[̨@.%uvv@ $7 EŌ[�epkc 1LDL,lgk~[#PL\7:]\MgF%aPq:CV&$T??Qa9$ AFdTz{OZEQP5ĒdS_$#TS4QA*:98N탽 Hz\̋|!1V=V=& %%ԻS8evV0bL2 6cmT7C8^Jo@{);q.@ C.̅tfب>#D‹/[WB]FBCN_gGE*~Zl,^1vP78mQO1 s[./oIf=w1 HZY3g9t)5./X,9BJ##16 :~CahQ=8}a6|:*vBL!H(RM[CI/t OfgU'-fsPߵ ȲdPp %1Zޯ@]@ ¡tnXHiz<[m ↸L3L?[2̩MEA9?@ٱ 5- <>G=M)D0y�tITσ4l{�hñJpFJ&,& $GR{]2UEAj %T-YDݰ^E͘ګ::dfJ47 BcU#1-DNJ#VY`ٕnePlG+A$K+V=-5p @ @p>22w13:JٳbȝDZ S-US*n,xn_7D;)SU1(60vlFKKJb`Q,Yٓ0 Ah%OWæI0"M}A59极,HADDž{a5R0)LFu9ol%2z; *NU/0pҙ0%Ts`:3f> D!1V6*H̜䪥뭁;NU9  .M~׭NL?K4&˨F t] &}RϜE˙lK@ @9E(I!̚IIo ŢeI(/ɐ4YH(xr.#ǯ.OQvtJ%2g!BV8ŵǒ39F}-c8ijfŗnƧ7j2 J &Q;.o&}f 13/ ]n fW{«JgԗUwNUF%9ukx f,AZ$oG+p (%V:I^ʚX.M0YuR\L8l T0 0Bq] F3ed"$@2='ԹKSUU8xr0_4M�&@bccQ 1cG{~ &JCիBH /\N[EWpm_xNҧ4YNz=M͑""(;>]7<l@%_@ @8`#қ2><U' 4Stch$CϻUz}/3,,f) ϜBrtUS>]�b,(ٵOdR㬘ìH>ΖUPZkK6o9X h% g7q2IG Wvh\LL 碳bmָ_rԴ2cF&A<f)pxKʭU߀cn:wЈ(4m(OLeD>sPk6`0&zo� +: hP]T{l߿6J1H'IoVbo Sc  #׋"*Z:c-;N]W;.'.7co5!@ 󀔕5B"g>╳V8nG 9 LKY{l/Ʋ@@ @ \bX,=9<V@w({3W@ @7.{>f,f Tv0B@ �D@0m0cKn^ad @ J§9@ @ x9@ @ F8@ @ !J@ @ %@ @ A@@ @  CI @ cdObetIFWͲb|^ |שHt'K_摽eX}?Fu{e} RGƍwл)fZz3$̗]|P3TxpON#}/:3nJJжAn~;p\ng^*s\d+\3z~U?= &io>>\͉oaXRØׇe+}w-YBXWDK+3:Eδ6JckS5s5__"<Ӈavס|`?f6~]#tjx˙ͶsCRZO  {x?͆{^٘Az eʂdEPxwG%'1/Y#O)4 ׉HCZ|$AZTOM9Vx.PT7-&(РЖgDP.$ɉp( >4Rt04 LF dß] /ŵXn}#^W+Nl Ή%.HFmgò>-d2]iL;du=/б-O&3lZχƁ<pA#2™#|Q+}>Q~֜"s 2h!w:a}x &`nGij(^րz1&te*C19nds!Bي!2y r1bxNZa~ELՄNR~SNeZnlNdS(QS=Twi6d9rM� SlQI=}qx#bsDiSn$.%|p(AH$$"A0Ip5dMfc2>>[mU6Tdzi9h$ fƟr7T�XW\̎Ā,1ᬽ0܆y^!$~;Ofӎz^ދ3q6 ix *Q./_Ϣ|a+ƭ%r WJռcS?sH?g~K"+sJk.KLƢبpnhe %)t1M,2ZGѥĽ#;=ss%а"$!yOpRӭd LD#`d-f-Iu&J}ܾ笷hBVqhOZh�w҄Є%ģ˸6+/dXӝȊ5-P0qsHCEMfgpYBב] $Oކ&>_'kudM5s" ;޳ass*_9s(:/1q\?l&mf=580C^SA?|+BHXz:NV'dsi$9`=Cl9XX.SHV^+7βWxxwi@y49_Bl;u{p!޿|&UڗS/9$_x-:ԡ|wݼ=ϲ.>iL_ڻESc1tU[/J4LK\liA(]-q o:;+_fOn'7v~~#lc7 dN6qK˸Vv9DjpbËʞq.N;sь`Lmू*rp=OE !ZcjPQwy)H81GlCS,m"im5uoy\S`ᮟ]\CW@>&||^{r.ǹ![i:?,IJ^W!|Ä Waf74`רcskg_{}#+O0B�t'PmS"˄͇x] HCA"5[Tڧ_ߺ3L.d&RWk&Fұ2nj6Si(L\ZZ\ V37`m.aMZ He:?Mz{R ƥ^؄w}\vTz>-z, <Ď6SrߏȎ> B9W6y+'wr!C9]g´b q7W)<|Hl&tL&=jO;)65M'ŏIJҧfcP{Z<cާ8dXu٤>9N e\h #ԺűA#2%=d]Ͳ@'~cg}?a:S!"{ʸC W=1mZ|́DZYf c<V5L^}p?y]Ĕ.'1%}oRdFX/'P}q^yS]4D%̌7;R~4 xm:e$zhXy]ܚKCK{3)}%_]s3CN]ϱrJivrJ)m,SwJI,,ɄcX#C*j7uyW<B{mtߨ5yw?].87ɼ{KmG5?&:t|%d;VF L_~2J_a64?̚V+5lļ%31- Q -8kR<q*h*Ǽ<T'-rb:=|\у%}1:i|~}mpb_%>fh v XC$65c odwe1(iƊ-*q 2l>z=odW~ *^ٕox(vӎ=K͉4 ؏Tm`+jRUA&-w RX0!}R_{{d1WYWc/cqaIsr"E$AY8C'd$C顄)kV\XNu67QֿZߟ5:dfMlAd"$Vq8ڐn$?]`/Gתxe<Τr4mTF.Z΋dz&R3zz6BmULeH$INbvlVc]5E4R׎o]Wlմ\^ӥꦻwˋhmvϐФ^kĭ NZȴ۾LlYL]{?bذT{)sEj_ds",g] D9~.:*i)/[Xr$4ݳAiqBw�+4y&2xq #t�}GHS[D[BP>ȡ!LH(]v7v9k{&&:]5Cwnc,&M4ss(ӇLWׁ݇eZ_3M|Yq/铦3+!Y0)Mee=cek./H'# |o%1qcr.ԣ(dһ9)ى|WJw7y^>Wz*)4.G(qiÉЀj_>Ȼvƽc=O5HWkg{ $n |s"X7Q]|5G|wT (;z/8Xt 7Ծ=ɮ6 \3;)]+h` o<͞v\ l>| u[?_ .�9KrЪmǀ?i"_yh7~`A9h_ˮOWgrS32Qg[ NـBLJݮfIĆ{Arh'͙ǦO&4`m N> wr~M Bx{ w�v<^q?8+N\p^~}{;O D6T&HfLObąs#HY`5e՗GQ :37~{ MUO&m, Wi,as Pn HUVy _e&7v HFV}9.r(^xO%sFGBR8!+c:96dqe?v 5Ҽw?w3pC =歗妝 _zrf=*G K٠~}Y4[cQ29x)8R˷;vieDpl\ĸ�� �IDAT::lm p9 Cƌ,@TDպ[X~BCu,Uj?5ʫ^Pe1ud uj8'4?-jl t#!)J6T@72(-[it(!1+w& SyWk,0'L j{ٕU979GVP'p`gl<|8|1cÌ !n[%b+T9tC|RIuϭzcj׮Z{}N}CJC"6h.fJ궓cydRIz.^&wNBOޠBjOR5WoA(T 1Nrl ZL+*e,*X\C\c<|~ض]Hǐv4CAz A4hXeQ^ӭ5 w^)Cɳ.eaFH+c9E4Tb3M7U q Zm!fUDiB׵sK)v䐛mBm-4gpjf?{W^'(*+ *e%X~i9y'O(]WKxۜ.i"(ão3mHwy}t n^x~Da] ޙcGÁMS=`A`J&/ߵ*;Grz '_<_S*-fNwb#'I+J׍qpRo'C~z/wpt ܄>B\Q)+r=n/; =|g뉁NmIds~jS(p =˳n5£h4v}*q {J+|70^W9:zP^Eb윾]̢z 9El99T**c0^SbVEDTR <^R_G}/86]gGo鲎,'U6]|۽<D22 f~ A|.A#`bwVtfp#LDV'ochZG&ε)*ܼϱ]Wy%S' q{|?ıdKʱ(70^DLWqax Ο$*Tk>z{ŕ4'/JZNO%0!=7բbW@$0:% ݪ.ntM=>q9-[Ne g^>&E(3vq}ѤWZkG BJΓ<958ͮ6C]V-k:8ҸNtpZJ8E(;ﭷH,HRUN搛WLna_ %yeBd38xPh*[mi`YPs3EfS%aaS�=]}i_"/"Rڦ&!:s|pf؈ܻ٦3fIFMZk֓כs0w=" 8YR'ņܡ1<_mx.4g@/$E>A^ (.wtu0e36i!;u /yhgKxӪ3vWC7ua�w?w/2.,&lkF3c.6%j^5RvNy6EL඘Ao^$L~E)_?gb?]1J|9A'0P*0U]IV xf4%FQFn K8>KdcbЮb>Յ?ͽrCۚ##{fы؋vV7.!   &%}WOg6|4DLu2|8M@ALS3"l]<NƻW86^jacE 5Mױo' K3a}ID55b͢bC`1Ӗ̣&`X0VћF,?á"_#>J<'>*3SO�3(ؕ$O֩}b"@<"jiů<LA]9~Ξo"s怜Fgs_.@+~;F7 {˿m{V m\ݖ}ƉSqbGSIA"HH}gU>N}VktzOwpVV;"hU:PM;.8m| YM[κr%f4n&ï3."<'ތcH2?nJtǿ7;b$l3nQ\2`kcr5}=$ @dٿ厷PJpod#%9d0NuNFf /6脮azro#n1b"IT$Q4ʲS„X*϶3ɋ"_AJ%Bo^%h:ԙm}:(X329M[Kބx"茶~u懤bjRAʹ'$ozwu\J7|aN4EGv͙*ܮۖu{\&&D"o3m|o/̹G`AλV>˗q&9ǎpBxYKތxVn7f,^ $ܡz @gP@E&чu +k<Uwc)7R>tNc'o&!}T{.<5;Уq†.+9nqp+KًrԫuOr GiHߔg<;-W.q7v]Mɔ3ҦB~gof1x .{m n}ذ'b\<ߟ+:ipTV 1QZQIFяFD4+ylw ^~P1gRQ6>~tt<uܗ8BMfLfK§6twv⬶^5z ǃ\Ը=@rTWBbK#ɍ!1vsDl&kj*c}7Fv k%͖K lROmN* *:$N`| j eM* (:qu;Xbj &#+T`s\lTn0?vq&Z=F4,VZ*l&]l&Oo=3]tGfGƴ<ux݂l5G鲶 ==7f/NOn-@F`ņ_'~omW\$𯽗:#250xʲG#S {f&62[Zot<PS<^:'[%o=nk !}J(#A4Y�ks&A(j%7c6�a͓AvNGV{~]zϼzXOr_/rGJtڦ[\Lc݇K*:mcӗ%){:Yh-QtFd>&'=U]Ng'Ghզxy98_L'^TRx̺{Du}u웹 ͞YV,>ӕb> ޓLY=Nn~m|% }w=<A~C&m._Sj_s2iuWVb%?]UCeb`%'6eU=t`QcjG%eowyWk'bzNbgaXq#OccC}7H(<6 ǖYo!1OnDI6޺+mc=c[R04kǦ|vmƢhDFf/2OΖu0<$$+x<DkJ*U.὚͖ʳj;W9wTV@z)dճ24tF_fJؘ]Á'(N/ "\ou4!O21Fug൙ý\o-w 6NwʲDBch@e^Z;﨡ol#b5-$i$QTIx:•Ϋ':hnK/ӛd˴ެQ-z(50Y&Aٰ{{8NpBc3<_WMo/ֶQ5TdYЇ517#O|\˯my?Ȫȃ)tιV׎p7v^x- kT\y؎Z)k%Fӯ7.1|7xgp4Kǿ7uIp8]hTdY!|<s o3[0(AtՋ>kNjk4M=M}Iw^ST|MټCo+D sF"eup*ReAzK|z O]A˳b {t T||ko J:SaϢ&Ä6?psru_ dRa_?2rvQtDfA&f0fr&Tk_1?z&gRRt\㳯߼3$U r%V]{g u>Tj ~0R{Os+Cbl wwxe*`_8Wq籣X-MgWB aeg?\3ǪspBxA(ƐFb0GKAƒ+  AL;Q01gA94u=j^]{?/} "gw) 4tb+mi/G~AvmĶ5CY%*sPQ'6QQJK7/75>-lǞo?.ƛD|bY_`2&ASσtm9VmQ.521^Q$k:7b}9U"3w@Z!Á9'җ;tb|~BϪ kCvytLo#g=L8 t9;޵LeX c/ڷUJ{5IVnsSV79yn A}NTQB)śc=4_mke1 sfe& z'%tu TT on9 lyCU唢vŗ89_t7<UYFeA :3 m-}hm"@G'!}=fmPe+us-[Ʀe@@vjtI>&l*$ę}i>:ǚ~"8Z@?^xoWyuHKof7|]&~qh+U֣Lz|nMac'x|=胯rRtE5=~<@Ö2TEcۃ ˚8i]*ټn %NO &"Ff/'_Ň#-yW[c� 2zz{l8HPǠ%Ŧ6]"u{^Jm%,zux?ez/3ovٺ$U)OttXa|/|yF߹_]@}uJ(|ֲwQ&7P,cMs<#̣* }2șm|[W]hFN~?SY`G/i>q븰fg+t-A<7~yB֕e8ħm2w?'YS@r8/5Bn bU>=o;e{d!oZ7 ye-1vI??l Q]o#:0){KozF&‡1v_iL0l`޸C @#4OBB7wYsȬ\G\[wSU�Ĉ-Tıs>VUYDdȻ@FA1zh30:w{oyJ2ѣqG~CѧX "_{3ƚ2ɭ%b^X22uI .>qk0'kzg|6>>ybօ^[^'tQ:d&6=F<?*YJc9l=:܊NqSf\ImV͉0xpm'giUL"+R__?k>O$#VrϭMxevVo[}#]}K[sW yMD"u<6݇nsgv>IVOQv-]|q|sV N>}="Wu8x=TO뽹dq½9-[)#rA!ToUntYOҷU7ğ|-K!4s(rJd-^jL \ I& 6½Ǿ/r9 ݏS仧oo:G;ݻς|Zs҂*"AAA݌^兀CHrR;AAAoV5ٝ$(sPJ   pK2IH3PAAAA ! %AAAAPAAAA ! %AAAAPAAAA ! %AAAA{vRcC8dzۈ,(c>So<ZÆAAAA*&lصTHMI-4 (s$+ۍEH$AAAAϪ%L8tp=^m0EUXnS6w}sKC)s\茤T    |V-ku{5:(*HUUJ,v1@    BJޑ7=LK�yIbA N +    ̚~Z%NT=NZ@Mm1^9&   pWY %tx,F,aWJ}<f$$   p0E;OL'U={˪esMG}    ]@7sz1T2rAAAA k2dɮaCuN9%h:]AAAAX=7͖K 7:),ĪLNL    V-پՃM%}3W�$i+acv , 8x&se-zAAAAz;LNrȜ{&' $9Ħx( Ԕ̀xn6SWAAAAX6J}}lvDVzzzD    7x_q    F    `I(        `I(        `I(        `I(        `@`Taʑ#VA%v?6f=3]L/[[_iaܳoPI`vR8'\Ⅳ7ԆURUsCu8F{II Uw.&"a,mP]7l"݌lDkj޷$e$8 PRlܳ9=BW>1x9L\\v3zl.ݠ-'2TIw~@�� �IDAT.79AdTs\FUl0PRB.&ogׂb+Wo2haQU09v|UlCx8wcB5w7q.!)r֚3y΃d|xSWt}k�CqHƱYń-w4P`Jnhqa^$+ۍEH$ydc=>X�ՕANY9{5~P\`l=`dh� 6ovoDE7=L_KlVpQ=dUL7\yu�Pՙhنt|U^7 :6bSх k%A#!)r֚S.nTmWpe,!:^/{WiV-dj)*rѾK^"OvB=MZj}= :#)%~}};!7RNs^?ب:Vvآ]<فrJ:=8ֳtIř zpl5:=-ajCzXZ<;Kׅ kMMd6(L2, �} =3k`)!aJ._W^Ӻ~QP ۊr;'v0km%nTI$d26Rɶ4Oh+Tuu+-vZ-`[PeVl(`NnksM*-97L4c^VOl(w6>N5:cPldUc}u ^;f= 7p/VAhHփTٔe qGh*6+ױ#en Wu$ h@U6:NS{ mz `Ra3eqCq~GRm #eo}iц/QQYaw'[7)o4L q"QڮquH3R%[֐;۷!.oZSOy^6Œ\)H{.kO?Dv5PUv}[ \uH4hS"rvz]MWi OEfFlP|Y1{cRm׍4ڙ1ߗDRҺHS;.<[])ӅB<db a/õuyX|ͼb鴇50K|'Yj& ơ$۠8j86N$3NQb[f'D˱pafn}[0Oo)oBj𜜜?H$i 2P\Vdcydb!8 nZh!FyZj Ć[i\ՌCJv덌WlX k(Z-)" qb& [ԇ/jeL 2q&'㘝vW;[VŊ' IE!ed<@0$ckhr<b`XDM#3YqgeSPRyE>B,m(X\`c'1K`pىݬi?Sh(kHOl J 0 u064#PP[Qpc8. uŜ6!3YdPP2lMQ]O{)v`zGhj҅FfQⰪă1<6SeŊ͜`*=~r3`늃ݏ&9 72B]t05T(kG[n[5<D^/N:R?9wq嗑mq-E>j-7#qx3;%< jV<䗖w ,yurwARgtƾ)3/ dt6m\;LnFJ&jP̊"#9pd650K|ǀO5dFɪ,'ۢ1'd+TgN73SwԛAMW| aVRJy-l/q1jjɎ6ft'wr|tF6xڠc1=S?MphH�6>ή;^餡N 'bGۥ3BkhDѮF_Վ '_Q*d=CפX(k\fqyxT^*h>_6зh?ϭgT#C\9ya]ǖ 7JNV=9\4> WLD3qe08>8m56DxM1JᎷKeEF`ʭe] }-lTAf?H5 �q`tg;}+ iq'_k֭ ϹNԦvTf] 5Q|z|OO�* L1L7(3C5Է\}W#(y-%>jM7~ݐ=Y ]ϖrJd7y"0gPTAu#rP3snWΌ>}3"3HWRosx)](.n蓴9Ee+OxUTU18^ 4wT#6i(뚏 N'n (^ꋱCқQMW|RfM'5bW'vlZظ: \nwpάcc&[<Be N< 6mu<z zI&IEKg?8E]M;[7ə!`|v'R of$^yHo$WN=P36ȥWO4TQTSoL/>+ߑ15n,6+r|6m`xʶC~:^.6Z/< ehp ʉfnBFaEvU�=D魹ہB'8D:_. ʈ'„c:Af뤏l; mPVԛ/_ǃEщ4>C?G#EUSط߉\pdZ?qƆIy-[~ݠ=$?k'[/21㌶_j 9GY[7&=fzM֍tٙ1go,y6:.xf'׈Ѕɍǥ@b1 k Ư(v* i4K|\ÈMCLn; A̅do4X^H:$7&_ hI2J {PU4n[iط,sF?'jT]k(kprxu"\ n}9I,݆N8^f?9Ś#?TlzhDn)uvPa5 tbY)9hLK$ w.(SӫX^ *Y]n Kw:cs*Xm:^.6QF!ՂN$zѹf3}#F䠺*XCJ?ۋ�}]\o{9&]oz[l>^AA?o;*:5"3MoKɛ~?վo)451ޒ!%I=4^IQfFl݈nR3h li] iA|w׈Ѕ0?;t5 K-?м/ }4 ۅ(T+N`TE1 t7J(5x[FFN6V|EL!Bt"N@κyZV@CtF#eNZdžW/[w`ļ%+a,UChƢ$bh GfnKrxSYdf[ۋpmBaֱ71[nkuLx ,UhPx*A=x2l{/k㵣QHJe P 7#بkN𢿊ue[@nq19'^T$Ym){@2ݷȼ'cfœ̌7-g?W?*ޅ}3xKүY׻Lu#rPlx<E̊go,$egFJߒ] nSI8Y]n/.�Jg_O ˃<}+>1S ٤8d̯Lꅸn%f H"d~߄$dɮA|9jkێM^w`sU^;̄t["HdR^i(3bg�7/n<nm37?ԹgZƢrW6*c.'6/OemΫZIDFn-sO٬ 8*iҷ|g',VAqۻ.l "s=(N3(z/<O -z*gokLl rPf}V&ٞ넇[yc7T;95ws!՛i=҈?y_2Л){@3ĉQ\d-Gf)hߖ3؂9&[2q3{HJXm #ۖ|qӲ1"3CnLV+9P@1S銅Ѿ%%3~'-mHy0NPm8Y](8=nLLĕ3 zJ}Mmyߊw 5ɔP~]O١۝φ8 yk5ŋPzK~WeSZ94DOQ`ieb4[.57yK=3ϞN* *: sOl+n\-Mf(Dxnʦ+_Yܸ z<0K/tH%V1-NfE' dN{z DpzX]R۬dBɥ.PZof2kM%&9w$�=B(MiӬͣaQCm k̮$ \B{EHT5trیr35Y*z1m6TR('2X Yu))Q? )a>$~Vbΐ<qJg|fbdݎ=Ke kDoʦ*v/(d!SڷQfL!MS7!M>jM7Cqx3=7dR\䚞*X2ku ?HCjXfl݀f"7=^JJl [^bKW-[ }KFft6:vxXp 7(%ՅBE# ƞN:ax:a VzcȧI#q( (rӴpwR"ߗ o*UT>m[ٱ!v%¬%UPl (Y{ ׸28e䉁fJؘ]Á'(N/ "\orl K(h>HÜcrBcIsJם/6R6ig(I džRrsrvjϼE y[?'c=^ņס�n*whAm8L\Wn!YpNL7PdZKcTODP],Z6%zxjW-?DUTGr AZ-bA*t RmoZ? gI'ܧ]fq)*n/S Wf_RUhhzce#>@벢jt]̬Mch4NY3@sx@UW yXS>X6!i1`NEf%ϣB3;zX]h^zK!uwRkmlP!(69mzFb)H{5'g y}3x37؃!A2LՖ<vZ!xN,J 4M![7"!MDY̓aFxu֯銅|ߌ "=mH5䚹;Ƿ]t.yrde:>B>/]c>5y4Rz _f5.bXr %7R{83)- VSNNΟG$+G6UvᴛQ�drrى6=sJ33bt8a۸| :xKN%uE.v'.kX'{i x^~UJ=l-1~w 0F:QvrXQ@`wp( O٢% %VܼӒ_;ߵ:m@1c[y2#d";Ërb t2sz�>w ݁U 3z #w>OV^˅1G2`-ɶpLi#X/AÉe7yg.u\җuV-Kxڻ.Љ1pp{].ϝJ 7Ěaê!7N4'#eYͶuE/U-vw+ֈG!fvpx8 y,FI-h^#zK!uOW^XǺ"'Ѿ7xoA.30pe%FkI ^+><w&&ƛi ~ۍ20bw8qy<8-/|]Į} ̸n\6%@WNq_XhLo-yʷ! )rFoN"[c8I]Tn,'SJ'91Wp]0M70]'q|}iڤ8_VQm!McRKdPRz3l7B/.>2.,-@~|> PRRBOOϚl} :HYAOm{C56/c-w)++k۟` ?XKHlO[Dp`-fc{)\ ›ɳPذ|K+t $b/؎O26vɲ:R͜Al]]=1 6lѾ4I2IH#f(}ggW Ô} S{Ղ˛FZ Bz'8.(bB,"'%eEpJaF$$1B򲦒DF<죯:u-x}HYAH<x _"uAt!kw撩G |->M"g-ߡ$    r    2PAAAA ! %AAAAPAAAA ! %AAAAPA2›Y>ùBAX�۽ZHYAx3a jt6ET3J6<ޙ7O~V}P7k#(SgqY+z\G˂hO^v 8"|K iM % ȯn-#E'<dm"~UWɣF.mګ;4ݴO^E[uǒ?YO5Ey/g_pC?_kwKInL\4 <P| J6|.GK X(d㞝6" ثl<ZÆ ӟEQ:[T(:ñsM`ʮeso|o-FQh:|~Yl>|^?Ȥ}hMMY5YzzN]d<q(E۰ izPMTotkDMzwݽ YO)?[ {xKk=,GkwDf}4tBޫ_OW\رXHYAxU:]{(Csq8C0ocIVH)]bx�}_ݚn B{f"_.U|ts=r1~>ɛ sl1>CK~rъ�� �IDATzb[NNr_NNŮS?'d1\:;Q?A;w?_=~+y;xn|ׂk4n&'?BpqczӏpB_VYAx3j %S\W5LQU۔]x_RyF:#)^3;w|H3}[W8v^E3G!7_[|e^Ts0`C.f[M5*~Rd&Bp'rkM>M0첂f]%c-\bFuUjAY u.&(+$(˫(rZѣct^W:oo/{jU.KhrFQu<R@ tZՏn*>;Ż |#IzNyw(/~_O_FS ҧ N9p.Ko%xkv~avgaqy~4?طLRO2n~?{۩gE5_KcyzF =^nS¡+zс!> Wodʪl?f];iMsr>o=ɟ^Og8շM>@W!~20(s<v9yۗ,zk-?E*. ͯҏNqbY}? ^NţOSi^ =4xI^1}# zVGt}X?;<^wfVK,Krwb'$$! $!/{!K@B @H!$tqM%ٲzڮ]mydKlkdɱy`3gN͙3{wG+,'֦}%tw LbMuwr3oBW&^|^(( S|1|\xq6"=T^Ëzw&5g~ONR"?䅯.{r0 O[=c.30z?6|n?>zmv;\xu}5x_#㨉oN֕?ˊFg:zce_?K~٥f&a3a<J}x;`fXn[%x7@Y:9ae4uypXzWSA}dfe1pXvq<U7ka݋0W?ǛO}l7pL[[^8yg" !h>w>O I¥ 4`Zz H+ bS{!ъюəJޔ3+fF6+0"#P_w?sgEQusjs7f=ZAOV| T4Fȹ|{F? Us+3ȌRrGh73S&Ӌi}7Z TsOpPއ:i))ulU(Bn6G+vz"~OPFB#TU$sV_=~*9GAB17_f3l\|hc`xV?~zSQx<=7sGY8N#1c1?4H4x\J Qy8m!*g+h VODZ_ކ^ԸtJn" >B"9peg0has|vN ( Jn&>?=F]՘h^/kNqGjScQ}O#_-3kSD/<-Ml˘isw?OU'o~ܷ)s)v5o~n2[ `2yH!B:U-#UQIKéǓq`pb}XP9ka&/X ZȂm``MK)4CUljǎ| 8jc, ?5NvkjCK#qmOIecO3P**#8RkXRM@b3 , >k?(kLHCdc[x�Y)WϢXNA=v]`oA.boЭH1 aKw�ƘG>6i,Ȏ8ECڄBJ#kJңPak2yA,;{\`Eo`_SKӹ0m;_ [7;fD;،(} r~.Y "(\|W&Dj7WlQ=?{O?rwoF}wѿҢڏk <[L`9Dj_[_:4f~W^7|_87'~ LI\rٽܚ6k ر ̋Vк77Wp 9뮾VcO GشlL7/}MWΞj"]�$OcIF0`~ t-Ds)Xj-T35NUO7(5U?ث){9E̊~1W'XNWlȯeڕ$Ԯ`VL MJfbJq*5OZsnz/b}eS@;]*N-Ӗ35ˎֶMO<MOs29w>HɌb Pzn) D:y"`Wٙ1Jf흿:ߨ=6PȉAc7~_3osEhqײ~Yۥ9~;/Z $?Z�e,˰U?ϗ: \'xp\8_jɾRV,I(A9x8Tg2r0oZ=I 5֬SӘb�x/Y- œc)_>`p\>CKTs.aڼ4iFG'P,9-"eA>u٭8{;Xf0PR+ȓ4頸I!d h,3Z6)|XȻḀpQC+#T/2ĹeZ Ǖ3]Ծ-"DZ6; ėnOTJ#W./<!tOu{-Jj)t#i`SPPĄ31K$Z0sHOŮh4Wo?TF`}'.s&&2 V5jyf6ӣH/K8t,Fͻ/k0+.޷t"ԼOt [^ٌO325r>I檍NH++I%jpqcFf FUǿg$=z4Tܞxy?kպ&^QO14* "-4V)* K,r<߼~H;jQqŝ*8f}`ާJ]*,,o*Z|5 BݖtL2ZT hNo Ƴ;,|mѡ?=;װu N6S9WaݾCO b"53 Il3S<5:p[kd�U!!.T&d'cBkoHiZLڹ . .Yց;4nKgX}Y رճku.*YX5C&j]AtOҳO^K(\ρ_KzuX;9}>x߽t/ͻUlX񖙎o/P#՛L_m5W&קpByJXtS:ӓQ�5'Djxܦ‘ztnUO{͌^+-9:15.y5*HZ1ɎdL_~Q4dQ VO_{|upl@W,(h Ow_r0?F+XmnQ졤&O=ꤎ?0"6u` +MQBc$nrQ0-g/tqd X-r\~@d9"Zo+>tr/Sp:1gBu8CBsևY|b=[*[#~Zߘ[|68PL_q.DBb.7,7ד~nMm>mY�5vg7u~?ె9\n˿y tR{_VS5_ Qu$$M.!#=Xl:D,d9}97\:7}̬,x&mp.XlNU'K=;Qw`Z�P 0'ᚷyft՝lbx`Ku0[,wLeǮqqo98LObk[ '/nwɇQD{mgh+uB1[^iF !NM,$&ރI#iŘ'ý4O\!,9J05'. tu3G15%{(4⬕{!?2 Z| ̈́":3O]k_@Ɨ~ޓ]ux}'zkV# -Pgʾ+-W5~3c),p {Nzϗ!ٸ7u;>#|K()&e s%/>dvm)<5k3wc9=xF*e56־PujJC⋙aw'>A;mrl-c΍2;s=Oz=JH?Ѓ.a 5pԞ,o4A"#iYg䐟 Qác9k&B#i8:H8?x쩄bjRAO�v QqG\wӅCt,msxZ N?? ۿ@`A }P 3Uz$HH?uZv\`$?!L+6/kC܃H被IsC`XF>هm#3^V3IsxQhe0߾Oc_A5c2PЈKiNf裖C|L"4Zkil/ ySPh6uXtb@n ?@F**vShS=i6w[̍/s3u'<~n CTG8{Zj7Xbtvj=<NoF;ZLι #kY]YJJp񼃤;;WjW,8j2ۇSYC>r:s̜^ Nշ 6j#?8+Cqbu8FK職Bk}ǙfFh(Q̼~-m9h(/G!rhčɒ4"}mI+}l M9$:5̜hHZqb=W&Br̎.6r?Ϗ.Y8^jC#:m7Oh~At]vCj*WڲËp**n\HHWɾF}ݑuWM;ǟˏ2' .0Vyy<\N7Rr01xLI,.(ƑwuڽQH^HPAXq\g$`qs4zS6ǟ"d$9!H8(Q؜g%ʁh٩5):p]S ә9;>K^]b;O2!詯%+"խ\Mn\{̑Dx"HDqXяI$@ IY}H:l¸^>t"zz?W=@P\ŝ5O~6YVc1ZΎtń'3WΎ<gVyTQȞ3m6g6z5'{~صsG_~.N9t׿˞Yc'qYhNgi4U\s.!1zL!ʛpȸ꺑w|}qFJS/!+aεx6fEe2ko$kI%{l,χ )| fCϺYӝWfSHc OO-N";:y;Qi;kf%:98P.l (q,$ k¶Pg:3=y\< 7e7A3GTI+Nj>2̛^_+l_[mܔT¿ݔGSgGiNj5啣p襪Hj*/zĮ"V}gN|/Ks$_U̬psZq#kx_'J:օ\u?|j>U^YD:H;;kW?D N'NSG_\E{-=0rxKsߜkS:B$.).Lltu2аwL|4u0RIJy|h%N_&8f)ڮ>1 hntG Ǟg w,Y@%e|b"9)^i2Xj!6gBJ4θ*qK(uN' ײ3ЉpGxquUhydn4tBe/齁/ی2:LwtE?ŷ" ?n.e{aۦFyPά|' ~+X+FT[5k0+g 2os;3 w\j06FͼS٩|}^?wܦ:-잓[䷒ Y<,)Y̆ӢiSM*xws[] Z(W_]Mhn>W 2:ѳ<\nxU < B$/#5T'>qd3ٿ,Rá]KH`M#Q[VsC;`4t- B u|[m¤c/qcBe+9X7YWpWkBI岠wm|[3q&d 庯peQ[п >POokG@QFuaf2|eޖ.O&nݻ͵VY%sM$t>OفR,$4>B]S#mĦ XACvpdp->7:0<6}" qa8{+LQ%$HBPNILm>ֺ([mtpl(g{Gn~i$81_o`F\|ɹdǖjͬz ޿ڀ R,4֯繷䭎Og+jT<$璟K;_^?|Is(**fzZ:ij_?ya2 IooxmؖM<Ҷ:|$r-T|'S0"*3UTDQxqaQi#p>o|~A9:d(Jb|*qtqlUl}g%ey\vkl$b#3i^yX�Ŗ@`]Oi52?]!ֆvh>cIk'6BR0)D%[HBTb6u\OcAߓ0  WȦqsB.q\k6m<ru;lZu2[H1<f3(Y3̎;Le-{%؛mTLZO.c4<Ђߒ@ ^W{^ [|0iɷ6uߥ-*w3*>?}y/j Ùc홑vr~=xbN"g`J\ڭ+xk_w{o] Ӝu_+�� �IDAT~{{lBC -5u}3[N#ka =0Y?OwzV Nq FO_ngk)پ~~ѩ8~g-{2d+Jń=w|}qFJ[7G)oµ?vMW gzQtpd 6NfN{ӷy*C((:a#RތN6zN1C_8pJxx 5Ħx$5V RPPpNzeDHOOA %p/_^Bz^yt+!}|dMSCqqT'E6<u3\ȯ\<xm2 uܳ $Sχ߾\B?]uF}pXvM㡿ԳU hra:v.9Iq'/io)o(?Pd+ΆN*dL�o.4V>}f)!Nh'kNgNQ ܺD%xPHHs!B 5g|,-E?쩉<-XAHug[xҀR8)dY!2:x!Ν<{F qRKrC=z6l<|t_R\$n -s i8}9Hs!Bj vkDyC>+O'VK, FСz ,lh{@T}q B"%q\83tl敿<K| Xxrȏ7:]=jk Ҟ B-݌kk)!4srPi߾/WEPB!%$!B|` CIB!xB&%AzzB!B!LJB!B! ( !B!BC$$B!B! npZ"W%(RB(v'.qaB!0,E 6Jd}cvf;uigsC [{xV>)4SQ Ӊ5S9wN?b>Xz7/tqWRs竹$Fgn~J+rlVC$_6[w]γϴq w|al׹Tׂ0Ҟ)HދP{x:i#B!G 3ͧ ކ޲U\e\WtS;Wp$W(Nvlm<B\P7yoޜƒhhnכ}Fѵ"S)]]t}d9|7:Ν lU0d\1tBX6fǓbj;0Y&u}=ҕ}|\VVhB!4<3l ,X4d:8Fc"ĢhD"'P�-H0I\,Q|ryKujJk>6i"M?'VzG ?@"3®zuM\6Q;0Y&u} X{L~xΠ5-!%!B9k%g˖NíuS}8@jn2 6e]_v3e2=IȖL߳& BTnWojkG & L4t@ k=yiM y|˃g5$!rq7^[ S!Z@)YIi�Y$&U Rj_u@h%eV1YQh\ =+ndʬBn84)8=cζ_=NOS}fz6>̻/F,ycsf]28JH5o>ÁOǔAtم\V6:+Q۴vw 3 L矠`pۿ|؞Bkg8!^N)VV !q^ǭ+_ \ze"nv [FYelf8U"Z*ZFeD\~M2@k{_`ݾ~0(Xz_^#CG!_Ń׭O-+k9>3S]\y,I>3RVciW?fc,_ݙ2~n#RcgR&V,i)\zS63rTmb]W:ykFҎb//37 b6^0פ Ί*@Lڳ; 9.qvr( . 6-mVB!&ށqzXN.8Nak{5yQdUZ(k̶wmhEdPr3l1jt@ǿY)WϢXNA=v]ȭReaa5{hFrF C{5E a0vkjCK#qmOIecO3V뮡RABTzN[Jz&֞A-5&9nڦSMRu_U6V?ÙaM3CVuҐGVV2WJK?3-/bA秵.$s~.ܬ|x/{[^e͟G[o")-v64#f'K+\3z?mu~x'Y r,tQa.5tkty [BǮ(y0 ] :;VPQgP&8r0qԝ.c6{p[ Ny'i]?i=Lȣi>t:O,#i CGm+=(q4bMq{Xۤ ;n*Q.>4A HgyJke!B (ss(IBCj{#FK3Kr$1}AP3vל_2m9Shmk440's烔(pquW L#T/2ĹeZ Ǖ3]Ծ-+Y`#Oԧ&XTE|*Ṽp(*6Zzuw73u 此yM3::X_ưuRg'ʛ궑@3pI[{*Gξ " VS7�=)ϕy8ʠ(I%\]_0ٙy\7Q}wXAΏCǵ3/a ]7bQ}JE \t/{ ~ } Y?^=͎桭~U!h{ WMO䢥N^_Լ@ nFkxݙ2;zn>(Ωik7^ɪgcgQҙ4_Ge$i^:={O78_%MT{=m%5֊JCQk!{B!ąK=skC!B g/Kg8b% I3Kȍ`s)j`rAFjvE.TYX U%DebV'^uJ]" )=3j%Tw.u/ͻUlXyPN¢vu=P5ﮠzz:zU-*v}MLE+3|8 T^_?n � pt`RNh˚90#tC;Bt^!.ӅU9ޡkg߆vBLsۓcyh^?,Y7pnqc\03\ŅrC,}yWILΑ ۽mw9(й�o!eW<ۙ DVuzuM<+!B\JMR;04G'3c"3;Ue^t8\')]CCP) `"斫NLsƻi-轻֓2 {0@X2x\#yP0Y-F(0rϯp9Ð@X#,*vx߾x {ʯZ-&l?8Jn,XUefGu?Li\ @~[ȃםEs :- t\s399|by?ۛ V9qǞvGhe>gPvUm^^W!|~dS'&rg~TbpXS#[¤ LDs 4i 7N ĜdPbK3s0hғg;z9; 9N5!-TK?ϕ"$l7ȤJǂN7$c!B8'JO)5j;:"4LrPo'OU;%Z& ,J˚q_B!@oǓy؄@5c2Pq6LM3G4bf^綌JIQsUPhpc$Ci,v3 fMG[h]9],Nlf_˙O"Ak `QG mS<?EHy@<T ݃%E|Qj7nqP޽[k)RU,ftmKQh p,|wB;ԝI^H[R^u H`sNzܱ}ds$MH{#'mˆCCrO !uNț6s H E"3'&88y>5Wzk6K-~X\|,ޔǿ̢S_KHWp_E[G#^yS.)&='{>vfMw:y5OP%ų1+-#yi#\BbSȺf,\FkGA!@洜"A"Ē4|tj`ssPЅIhf¶T"0t�Y';ئ03xR&cStz'D upt:| LLI<e|6#Cb!5Z;?7)<Xsu|�`yrs`mf'f2?UkI^z6>z'+$=Fٜ>|=`t848h=!d/B Y)YbuaS@+`%h贗m`_9rCq4�J͔WvLpĹIZH Y L*{9Y¢L܎L<̡F&sM$t>OفR,$4>B]S}M'䍡֎iP5U[F*[9̺:_[JL:.k#ۚO|JjD$붇pt*{MUػbg3dquv*_ϷZC#rcQ<|m Z<F)kٴk<;(b/>wZ4J_m԰N_[&?Er %c_) uN }NRN΃n `5l:ey)8ښhh<fԠk;l%Hw$N㝁zeSu<q<61;IpݭlX3OOaĩ8D+feQf)GqPc?xꃑssB a n| cd]~'gwz(JNoyhn aKryHڱd*7,uNS�3y.⮫_oG\氟6uҦ2YpB!.PO޶#rwFeXDEGm'zM^�GZSDE9q(ݶSOV6wn|>yS Λ;)3m:“;{i;~.{W+1҃r_ G'gѲLL;kt넚P .&))#h(3?-P_ظ9gj!1.o)oy�n!*. gs}oijSAlj:$vЁ֑p?Z滘ü0eM:=жvŊ;ށ'ц%ng ?SCݰbf`Pm3˜̢9"-l-ZG7u>+$;1 uUf#76dL# }l�GU63 $Foʎz=xU+.dJf>[3u㍎&9-$vmG -HNf+n$;Pƽt%k̔ސJzUb(@n9r0r\#uH}0[N* g9PGF\PN[׍Գ�ā8arEǗc.\~Q (BQq߹,t5Ħ55<Z>y6&8ތ[wwWB!plc󌂂1+3ihh~`(}7OOycEyBΕȃ&[Y=+]1^Es]7:NgmϞ\S#~e_>K=[e%!B\@n?˾B\�|Mm|K<4x%$8*d  f#~#i6mefvƖ;{j"'DKi'%$B @�k6JA!Q4wW62>;n_/#iυv?g(<pU!%(C!0 ( !wf,YA"=oӞv3B}zj!&JOPB!>'%$!B\Jq!B.$!B@JB!B! ( !B!BC$$B!B! B!B!0DJB!B! ( !B!BCgT)\4xz^[WEqiSq]II];Wp��5p(${X&{;tB!B!,l ,X4d@daE[+8(ȉ}wF\d!B!BtJ& -[pd,'Il˺fʢe$*;UݕlYW_# !B!BLPtVRZbo<@uɹcEE¥Zog:$h$B!B9{@MN.8NakҫTq$SX@TB}tRU{&Y!B!b"Y3P[RUՈw}g*yc?5#)YB!B!&9PBBh gb r*ذf/mjvlfo\Y-.!3y&28ʞKB!B!b|Rv(hSWê2/:کR05RVEtU"$S06k-B!B1!#:f7B%&ރu':JwdWy au}>:lv,\h!B!BrNPxrOqPsCq"-A ňԨxcmZ:GӪ6p|N!B!bœ+4[yf0{NIБEfN VEMp(#Kh,iͱMIƌFyM!B!bJJt%ssp*X]P XrI&:e rCq4�J͔Wv06,f$~LN7Ns=%!B!Bs^y3EH5QV'N BzFGZe6ܱ1Pϡe ToYCxLq{i|AZrB!B!&RPPp4:zD&@zz: _!B!B|`V8B!B!PB!B!H@I!B!B"%!B!BaB!B!!P7!B!B"%!B!BaB!B!!PB!B!H@I\�LDJP,�RN>\&*e!B!b"'lZ]] MLQ|"-�� �IDAT\2D | |x><MxF7ޣR%\7MqfzǏZP>N}$OSs竹$FgnȅX% c!W-lM%zr}>b{S!}F2^ZoLC!B!d:%őE)uU'Sq]IIOi\ÁQ]|gﰱO&ϏuVXX;h蟘j(-[]&&vM¬56O8߼9%Z¯7HkEj~S V 恏.~R7)^F xvm:`'~Ln')=i,3Zk-Oo%M)2fⶩ0;S+ѱݛCi7KWrs[Yţ5TB!brgNgo&-lW]22a"ĢhD"0).P~H0s &D]jSI] <CI(><%:5|}+  &hvlҪm(h6TE!:֊ z:w-�D-.;^ﭢ)KXZuӃTk"su9ͣ}F[kh䇗 ^ë !B1iS<3XtnRs$mi/뚆)h`Wa stJ\ﮢGcd]gʄ^4Qr{oqH!$! Rvy B$vbq/e2}Iے-ɲcOsOW)M7I%bxo@'ҟL]Rh(\Xw/_>N0)= %92;#%Fr=ʑmFTbsP C^ Y Ʉ褲Į+t|No|3,k\x‡OB! (8ܨb:FyՅeQr=D:}o;sR5|Ӥf/Dq{M7[5Ɂsʶ(OXQ5?0EVx}9 5" j ӹ{()+SdTR :C>`3Wϳa<{ H5@%O_KЁD [z (fl)ۄQ\vȳIU,]M^=x/{h%OkX8\}w2|Nniip$1ۿyF?T.;Fw= ?#ۃ$/9-od;?#A΃3Mڦ9pQ4vn,;/ivfJwTIeϓKM__NOv-^K0s,^e)<SyG]Ӫ߹n2^~X`anLJWI~F'Moaߞ>֗*Nǫf6Uz ~xGhB! (G9v(=ʟ(I,.|{i�jQVу88eBٹEQ82jJn*g6Ժqx *n ] Z tOG#Vo?"5آ̈noGGɄݮy#F#.F'k>몍\'+)8i\-atF08\UK,;qN&΃a4QfT'9^a%U=QY̾ƽ9|זzTT\.rv?hb zmSj&*f9Q -E5Lw!K6"Vh} 9NʗWS6ŖohM�m'tJR_KpGc 9xi)(6;e 7J]L>F7 -4� hOo׫CwkH&mYαm�Js\6a(B!PsBQIs!uqgyXH}}F@UjDV',qExA Y'�=c� (fg!.PXl l>/(JYtFՙ{(ehUPHq}1̶\Rds]AP@$ p-x} G, YnaR.\ %%h 2UUFNINu0Xlnc,>2@ V|o?IsPegvUMOC7&&޷v㏞%Br?9Lۊ| nW1V߳Evr= vm#x86kMMU>죣׏Ec% - 8X@%/h',|2niar; X'$9`bFVgs/˽:> j,>23PSIjqՅy׭ͬ9&027l7$F`LqymA'vе=!y,!B1H&$Re5|ɐ_F-=I ݴ "<x*E0d6=Ρ0]c0奸(McHSR))mly"VL@xf_:VrۨM*VX4D|l N[~,d嚱!!=JSYxӣS.0HTWp9NYf~n-%|{ J9vpoGFB1HLWdBYf^n弶m ʬk7Tjru'&Oo?kO�RQNNr,#}h*u|^q'v&C<g?,wZ4/�<jBh '(Dwt?A$B!T]3mx-=Z2: j<u4Զgz?wޘUXRRZ퇆ķK cPU TWՑR=4B) 0 &&ct 䄳FT0#'%",E(zȄĂMMFj4((ܲ{og\mRҟ]ډ<yzG"Ib:LK_ta =8h;'هOsS0+_"748J0 Òy\fU9R?+1:>ѧm ]}uz3J<ӁcA.YF3xӧLF6OhϣCroB!bck$A2nV  _{3}㥃5ۍ+w\]d�ӫAJ 3G6Ƨ)K8S1|QR'V $ćB r'~ 6J,+Ru|VCiHw<RabIPgNR@k]}4T,|3W1OB!Lʀ)"ɡVzc-Bӳbсm,2% N}l&02sI':fui&+w6pH֙@KEԉ߇?NVe(c1={*&6]: RUƦvNeڍdNRmF, H1=/׵MfpfSY"tF]-f+ʦ0MUJ㉩F'3 }G/z~k=Ӯkk6g1Rl }fbqDTC= ,6y+ARnB!BLUfɣv<S0?jF{:º&#ʚb̊Nh؇} f04g^ 8 ˼N޺Qjr,fLF8o5͕eUPl 0OR-fE63q=Z d[Q5P[ K2wlo{Y/Wܺc+gHn2 &92 yKJt$0i\ҵ%eQy KKqIp].E$Oަ{m"�,u<COۂhzǸ7 XIEg,X0:.VI3>Mty!9JgTf-g^'HfCJJޘ#{ !B1UWl`* (,, (zl,GCg K>D9\EȲ C㩡kޓn/cUE:m CgУ?학J,|2`;]F~⻼s }l8j>Og 9SA 7H1*ăzx*Բ}1|it1J7JTQbч" g,7ne\6xe9(1w6D}d y'J$tNȎ `#n庪2|zcNr]*P;w;Ʈ\6Uǐ$/KEŽfL&_ NI;tI;z?<>=\Jq}6E?#3#eᙕK p7^7qiU~ J8vNHiu\2׮w*Q�#/7jt<umgSr|w1 jE9H!)db:i~)*W >L㑙 +VsRdwy毘M[F+f\$B!P`Ǔ?�$7 HdD7axȜԖvC2iW6vQ_QHۅ0Ɖt%tU|6d)2!p0kuMB22 쐬G<T?`Utv^NO{3-(14 2%i(|>MU,]M^ %Hl`Gʫo-"mX֕ /:Q_acd|X2Ȯ' ;Q_[ڦ4m*ܷ([_ꢤ֎g6צ:3hQ:[bgo+QƜvSĉw*ڔKQbKS[BrMNc!)GI64b;ǹ>l 3Wv;uv=">fC~3|1ha XXMkk;!cQjZq)IrKB!bߺ~ (--S *UϽ.dS!twoFZ/SLWs<h.~Rg()T.凫mQz5&빯,=B!r(!^|W/ʡ/$!^fjn ,wi;Fb_`r3Ԭ@a/$$B!ĔI@I(tIA2Rk뵹xui PٶɧW.>rc�B! ( !, x:o&Fl$ؾ J!B1e'{( !U3NB!b 2PR8B%$B!%B!B! ( !B!B)B!B! ( !B!B)hFf<EBCXK\g6B!1~qX,&%2\.@Z~V"65N#TM% 5?qH]+4|E%ʓbr̢=都&$zs ~m |$M yׇYRjxy%Q cb8GD?sMo^Q΂5]a"5:>5U([Xs9&)B! 2+SkA}w4snZ[L0}JoN"NyUy`y 8YhsFbFV,3;AaAI=6Et](>80ѵTzTk뀮s&~{ fkKV_lu-_:ȁ-(keQ!"C&-}R^ԊAO#]o Cv<ey,cV~ӴGϿLv:5ч gPƿw7y0N*`}[y%qY,\ͲEnr (}'zX'D%*}O5C'_L7Wda6ypyg@c Wqx@+ѷ˸_]|7.p۪liqT !B1 d,yYj.VuWia8;aqbR4Rߙx $F>ScWuxBzHUNz2BkbU`Ұ Wlλ6ơzO=`ܦh#>j5-D8k,XQZ"cf(Ϧ V/OޒEP7I[bEMP~ 4N7k߷eYAX\}H<wVN7q^%t%Qx.*bHjH޶'K:!HX^"*\NʊLh  t4eź_†Jz,J_{CՔvgaR+GN~h{|:TFo[yw7L%B!/k@ɐ3 |R\]iC|UW4Bm/-v�3uӿh+N꯻ -NWf'M(Ύ&13XP%]/Xd ׁBEC1w*ĺ{q!ɑ:Ʉ(I$'Y1'/֍ek7Eg0r3w4IУz.B!zIA@dX\}Hko?"_5 <Lݽ7v|Cue,0uwN`e;rے\Vqp {^?Cp==oٮe~+* h}]<`=Ky~keqAEtu1ۛ9zoY{OqiB!xJ))7Xf^@auިfQr=D:}o;_ \T.Z{Rm^S͖3st6vrJQ^ .j~-D]a0s 16HMkrADOf))+SdTR :C>`FWϳa<{ %q PIWR$t "ět& pSl9Q8'BgmNnb -QȾ~ ;]fz?ɶx1o.†8ȟ;̱7+ed<9YH~lihw~sݧL7D -m4 \'Ў3nȧإ?dO7}e(,a~;>e]dB sX|ܙ&'T'o`">'2yW`àGyi]}R {*&ȁM6cUtbi([Nh1kMSĬ y4*sAẂUyv:]aXT5i\<qٷea#KLذ[8ǩB!=JϱCJd5N*WgqhKlF# \NŤ^"k$ZXPZt ΠBsGe%7X3Kfj8m<iT.-g{Nc騂yd_D#8LkFm"L.Uhi5\uFX_�m'tJR_KpGc >l"VaZs-:?i$)-^Z| Nierz|(GY2;hǺ �� �IDAT'kY⡢WO%_B;K !ݝKuC6=}D\3?|og Ke:mbM ?dM#YN+*905/{c\37ghz{ RN,rDZ$ILpVщW59lk=�ۻ5VTY\VIسulP~?!B (] YRjG$ͅini<*(zAY6!-' |,: Eo D1; pB*gh@`+yAQ]WbUsH!{flw )Nw/ٖ[J<lu;8$B)o3+@'6aZIdFY#RMCtdD=,+XUeDYbcѻ!sNpI~s5sԭo_{u}r 2,|_GQ@0]˹u ,6pPkgᜠoɯ-ƹ]`6x8 vV|x97xccߛH57kd<)ǎe0~ u|u8/vw@53ds]ݡF?H ;|bt2ߦ7jxX>*yG 3l=__Π^C#@݅~u>޳|]P%Pl '$RoZl3* \1'$R!B (]Ձd"p旑_FU ^x'LZ6ds S)s(=Ρ0zy)-\il)B)@Ii)BsPR(Z1Z:u 3lޞZ!t& &Z,̅ tOAa~5n\Ne :9=%‘ٴw/Nc<;H x|fq:TY=#89r #o;0OȯNDGŤ"4Mv i H-yvrTb<E:ݧxv<6.}_`Ͼ_奞g0[# xciC>9f C0ZiI^>Qzv;uW4qPǛ ӛr= L煌o\oU k[h Eyg%,Zf?YEOܼhD 3~[*B!9ѶG҃yV1SGCm+[),Ƣom'(PP׈tȔb�ШJe $5B) 0 wX&3ǓFT0c'˥ZGK[]@"<[Vr-|I)z[BL4!Db۶BްƏe}<7Hn<Gt7:uRuLe uTgM'bSE)=u&с1ÄfȶY/pYH[7 ܼ/}>6mUI%ib ] }h,:+@BmݼS;w-O,/fѺbVq?Zws2peڅjPHpo kVx ?igM&mhϣC<B!@@)cxC2nVAB${h ˑ8:M}-|"xR8T{,qݔpWaZ߻'>b pk= F: -/ғiR5TVq尰<\<&Zh&=aw9\;ca~0*z%GɎ(J8&d5BÀNOO5߇vooϏQܹL-q!5| ޹[q.N{ܺΧ�ZC^:~:u*9&Ttz<V!B2dʩFr3!-BWQVAQ'JWT*h铋 ad撦O2:bL*gW0> m8N3=靡ᑞDm8 Ct3=kxo񌽇TQ].JQPZx| `v-nv)v*XF2'ʨ6#H"{>/YP#ǂ.PR{Fg,`bSxgtm=cKTՀMI_wxM4 p4*FF',k]FYTa %לRWHHJE9s.®<uY&Cɉ.ZnY36 )Q!ENlڙB!ڧ^,yΙGz FWWaVt">'?)YW1Z{ӌ/8f04g^ 8 ~hܼ&/2jw78'a[Yxsewr6&h*'T YM2s5y* Q4} ubB2fG\1Rr2> |讜iErm+oo)'ϔp8p,߸',\Ev65w$KoJc!B f(,>*>{9%X[=cí8-.T]gK%.lӾYLPtx *C ]<=fr|yW XK57<ffcC'ӧ~MABR3Ptu&CJ`)v➱'ʬB6 ~!B!^ %QU8PYXP<X8җq&o)sjY?bwe5@SC]ͮ­G:i뗿^p`c5)g4Qtv6=o76T~,y3'1N<;g+O-3-PA[Sne\6xe9(1˾s,^މD޾ިa5=7'rc94/ן�|j2gfC)El ͆C<1ϏicWK.KxgscuxaGPыζJbn[3GPb6omsf\Х~ظjbYq5ˊ3Z%M !{? ZCcSy=hiF_9r>VfgNҁ8q_,? e@y١Nf2(qwa>=ƞ\6Tp׹} ;CINŷ|n.[]̽Km_3/B!&`Ǔ/f'N E%# s|sD̥4W4=Ny;ȭ,ǩLI^0jm7? Yv*z*AG3sv"a7n /SSTVUU|ͷvz9}S!ZOXĈ68L8yH}obl](}Gzd ; -NF~vd@#s 1rɢʆ3xCϴtF7[)ͦАd]?OxsK-w_qr諸-x t_3+vَExXڹV\JGZ[gNQEђ<?8 K EC~ܬ0�z8Cc{)o/</4}̺3ů-aҀ�O͕,"ŠsOr8oׇ n'nC�hWW$em^q9]ƆK}ΚXOvQ&ص_闞r !BqS~R"3N)@Vq>NЩv޽eiW1.a "bG̉ 76pB;v${:wO6\}e>?IJ>t?Ω\^W0ģ<\kMlt*i_!B3\3{8+Y*E9ue |" (c\J[0ft5IABkٻeZ;j r )}Hе@X?ٷo}}JB!JP):\+[TPDB!ΞJq!f od, !B1.t %!QŔԈKQ!B!BJBq ~!B!.HJB!B!bJ$$B!B!DJB!B!bJ$$B!B!DJB!B!bJ$$B!B!xP1rs-/fb礱l%D4ma虗 NJfgvEn=dcGO1եB!B!f ()Xfb\ PD-2L(/xrT*Vʖ]r+J*o8Ȧz9Vo=`J*Z!B!b\!gh9i݇ѝf56h^bۙ9MR+{ٿN50pF]c["JB!B!3RSnTvͼɽQ͢zztev™,V, >zCZ8f,V# %!B!Br6֣;D/99\%VؾјuTW .CEs>e=ZB!B!Aƫ9s,) Bj47wOd$Jtsp7KKqA%U94M99,r !B!B$ΝL$H 8˨kX5K: %QT̪a@p�2?I!B!bf]3mx @(dުUP)qs׭gnp'0Ϣ)[wYJB!B!3E6 p*#b)K}aۺOq XWw\B!B!5᪌r;o.(k*W4=63OLWfeB!B!ĥ*J%9hXXOe$)*¬D|t"0*2GVR`Qt g!B!BsPR,YZSŜESϚh #})�RM4yKS˺%Q,b=4"=I'HK]*|(ݝN~RRB!B!3mm';sNInHhXܦ s|sD̥4W4=N{(cDm'0w9de[a4mݯI- !B!B ~,:Df@ii)RB!B!xp\c/ !B!B)B!B! ( !B!B)B!B! ( !B!B)1f[߲~|Y?/RBqy=CN7I L!B$3B!B!ĔB\.4h*B!'3B!B!ĔH@I!B!BL,y6R<N <ȿh!5_dncWBWe 񡙹K^5w|Ͼw3rڑbe}7%nBQt|O}|%*J,儯|;opykB!BLe{{>s\}I0 <w| /oSllz۹m<=.C~~]jzr TfYP.K,"+ȳW/Hrn>xc$ u/)x^N8@�Ɯ;PB!7{ L8{$9xC%٥8Hg\]_*ocC܃e= fƨTY�7sj)RCIf4G_I;ljkQu/O~`_|fҊ=_|6}Ͼ KPB!?ZX~\Sȼ|)}/?tr22/2׿7Rl-^Vl^} =d[4lp;gK>LE/#+? L2c>y0-B(B!B!QydE6LkYJJay~ ۧ,~1wF<~óYbITE>(¦hn{|%zxyp6-$SL,_ʒr f0]}Gxq7Cg8?/hT9lx/� >7־FO.nZ>l Z#/ȯ~ö8C3{tU/?Vq7[.2׊Ծ_{ z Q7|t)'>x1_áѥ:y7ľ -lFrQM_kwqn!P;%ot%3r9j)?:>/TN)5^G3U'>ߢwN_~EfWE_cMJUrou)ϱzh HNV*-$hV~ԍ&\!B!ŀBզSf0)sU\]?7՘+ &p'ćV{_Vz&9T+Q4=j!Ws,I?}>/Tmg_8]hbĝ]J)p ==` D7S:w}KQf ds~%VO/龳DX潝OߐGK UF~&3o<Ik _*cC zcQ+V|tRiK{r*ZI!**ƩFin9Gj<ȁ!Qʜ<IK=+4?ȱ4:?s9-ͩ~ \q,\j!n68}Mtu/T^^|+‘2[\|xIH_=,ǢLAxv0/^,][X{M#?<\&k!yL lW$B!BPR]ܲ΃Mx`9pY߯@s ym'M{xt@JT/rf=S40p*:HR ZpINtPsX몊9p l{8-^)o5)1sytwE\2gN(8|XG9w}YHקKv_ի[X7Rˎ_4ܥ(8UסB$Z912JӀaWnsn5统;}:JdW6h[1/t:w_BN2*Ev ׉yɧ.߱2x|ǼMwn+y-xOBg\Ky~ }.kZG?q韰ϧu޿zxysx%k"T!B!^)ûAUERT^#I0ᘙ O󭯽26P ~?/g;?ptG^v!Ec/M6āSDtlw tTw5 js(<<o;3g"ғ<ݑ^v/MEE#@I]5vEcc zyuE8@릹-f9مt4$SBCGEim M'tp{GgxᅓW%ѾIN25{ڶ=KcesO%(Ǿ>M0ʃ]jyo䉧 �� �IDATtx.!B!g(qahqBWfuޱ5=س-/Q{_M<O۸m|+leOKi P)w|y2#/,0wqUgǿwH3޻,K,r/`c0N*, a7M,dT6=B~{eXh꽿?T,ɒ%GyxGg{t^{NM 㾇뤵#Rθvzakh(LynWϰk$WɌ �ՕuVB\bgГԔx|{*iMZz%-QkDA=9qPM}|ާ'_g~bd=fʲ1׍2]Tc:Lk|87y56T$B!/> C^>:,&k?ϐx3YdcSjX\T@㊯Xak3Z+Ó){Zh1 zN堹9e7p̟NE\KWs7A6vr i$9x[n$-?J]e ~P8SREmי`M'Q$8efǙ:LޒLNBk(yvJB!B\@FnbGyx1*grߪ859uܰ8ML! `Џިcm)'4^Ҧӳ=FE N"EQm{_n} a//]^W~? 6{$:aU@-TSIM Ib}-Ff9Z23+i^߈Ȉs> Ϗ)Xm6 CkP|J߾*o>^qzΈ٤GQ`} T2:"`+<V5it5B!x9c"UϽ?#G{h*uWmt?(*憏'JOd8QEJd ߵXCOa_b4PP0"l>x5ٌW9LF|{9g8C�lf9P<L^޶rUv*:c'P P^Gӑzb͔kcSB4UT10IT؛kS'ynj 5/TZh:2V_|G[fL>a&VS*D,+ӌ}k.C8U^7Xʵ#d_.eqU"('<S%xL0DC)<W3o4}v6\}E1$ai`[L!B!A?EȎ7rj,%r>ALn]F Ǟ;ϟXC9Uۉ!!h3tٗFYBG>UI:z<_8&"UGC({"!g<[Ն xcWu4;Q$EZVyjXzmo#Ăw!m,o {*׮Wym!W̻?|5U(QidF Բuk;([\7S՝I6o㩍CfTUqYBA5MXGiJu6B2^6uӯ;+Edz*6TR&} @ym^Oa6v`J"Ѧ#Pl̜79O̽n>էEdC= /_*^sCY w}?:~N,ᎂVP[׉.>#j<xCxuW~r V?vw6tB!BHBiű ŒH^q1CoOcNq!<ݯpݪbf傧'ݦ32[ttc<WINhpóXXLVtqF{;'Rd AMUݣZ\id-vcԣYs-]GNA2ֳO1N>Pɳ&]Ɔdp-<ijl<TW5.K�*uuj1TRNZ'=ob͜D2xxm?Jaa&:y"1n]; 4wx>"'[YX VAG>†d͞i_y J\ɚKXAg +HύFu5sM/ϱKTªО\2?yw߱E('#e#!B!J~~<6¾oEy>v\.R.}ݷy?yQ/ܜ7ƣp={?9Cf]h3O? ?s*#B!AB f≷*&TIHBGB6s(*.e],�;EhۅV_);~)B!xILgeoo8;fgǰ7g8s5߻9+_wqo<o|4BI!B<6 ymf1u<Kyf)^V32e#R/WPr5 � -Ci؂8&<ML(& !B! %I( Iy4u?RV $&BJB!BL-I(BJ3ײ9 ,:*e!e$$B!?ϰ锈L4%B!B!xp8_ˢB!B!",PB!B!aB!B!$B!B!DX$$B!B!b8X| qf}^Lڲu,ϰ[MBrR㉲=t6pI{BB!B!S<&,]^Hob6wS 5<4"5Ђ;lQ$d%>1oڣIK !B!BLP98nNUzII87S +^~t&cJ>yTW%۷ɫN(IN 7#HJI!B!bj5B);ﰿ΍:wH..!3 8X}[tF4\4{F!ՕM4hLB!B!S=yi*= .abo1%S{4#^h :zdB!B!Ԙ0H|4>@m(¥YV]db ̎`H+ !B!BLP28w!9o:^HHO'=%˨9"cT,Qf 6$$B!B1= 3R Eđx4& S߮ЍJB!B!4 %ѩtYtͭ,3B:b;U}GxQOB!B!J30餽w$Gt kB*`4}G1ʪ*!) !B!BLP.*Ye]cO%�M^ vr1*.B!B!S%L.ƦbcV@g T4ڏohK(OPޑLQl.NۋìG6PVمLPB!B!:o>+g`BNMr_P'[[XHnjhN;AGIB!B!SI̸8NHKK^!B!B 1N!B!B!! %!B!BI( !B!BHBI!B!BEJB!B!",PB!B!aB!B!$B!B!DX$$B!B!" %!B!B@ eLZĕ`>oҥNM .vu7.å]'Ij| qX zNCk7Qydn,iUo`U}^oܲ\MY\rAm?OB!BPR]83Z>^y Ye&m:gX ggrg#');Π=i.6Һޭ9-f;*r  ŗ|%衫x}֑ħ&`5 -x[0h80mzjiA}D 6A^I& !B!G!o49 I{cs|[F&&\1<Yso.%0Ee;͈yq3(:Qvt8..Wx23mnoyj^+H5Ģ6W|]:;Q6.]gi -Sfnmt_enGB!%EtS^Rr0N-CMqp$I¨usH3);ņݮICU#v.OP*D4O3ݡ%DDa7Ӎ +v+dB!bh< uVpLS1I9Ix2#[):NGdE= bnT|.\6]4j^g3Dˈb&&9i;,�jNg, ̢ygc3iVvN\Mt)fr )N!aj1N6 NtI,p 96W9;C-m9={OʲV1Q�P}W͏;J|klGY;i_JKE6.Wk/%49K7,&j!Aba)q8G2W_<&ƣ^{ƃanӁ=vw8D$B!ҹҼ4$L-bJ"ux91Ȣ8/Dii )*{ϵ9)2gi<nzDeR* Ö910+D҂X9ˎ^#>š@]$3 1,]Ǫ@ȍs2 ()eYV$:5_ x m Σ.Q.ankkgk -z-w]x<餵%¬qGKmx ߅ӧ0Tv즾t`_Ga$x5zel0x0m:?!l8 ]F8$zц=.Uјlp{HnB!BHB<2&2wa6h<|P"K(=X}5sMRa!FcGY0ʞ5näh\.ƛ/`~ ̡vr+�H^U9(hAY˱Բkj=*`$ .Izz GZQ}|f6N*]!;fsuv;qOb>~3#Q||wA@ܼ\EJzzBលޗ tsb6Nv�3+bixJsg_Emw9X ǷzHkx^=(yz1f5f..` Ck`h{/5yF7JXtpxx8LScx(́/L$\ΥdfqE^B!BJ/ɑ8w!9o<^NG!I(M]lfZSn)*;aGAr3VJI&BpVk`N֖NԜf3@~7]p:=hDN79 :JEESX!3V{`LS :VX`1)T㧫--^ˆE+v4.WL~HM,fv.}N' O;fE#ruhfvU5۞fh ЪGA띚8LwՕG0rV@TʏP [{K'Y6f)B!ҴW*8r JAVqъ㌿[e'fv36pXQ4?a&# >wu#E$ڱCӏM>kq C_Ije㸠9^Z?sSm(h8C`QzόbaS@yVCÒ@wie' Okd"Q_WCx?vZ@x+8LS՗ Ænh1Wqk-5B!#:5S2EÆ(b )L4:њ lx`7Il8l:zp +KX8{c p5bTB.:TM5:1{`1k'znFlv3ؑ.80[ Z Y;[4?.op쾄a�khLcav֮ Gn�oԵ[X]i*xDvk_$:4pnunB!BHB|t;|V΂#:r/tE38+*V0na n0L h>|C)Fpr:fώŨvPe+ ,z6mޡ9v(ոL ~^ƨDb.Z]YR>7}07,aw7+:#=v:K4gQML�#Cl.vf]u:Y*6nӹ<[X}i*xw;cI۷r7ѾKzz,V_ B!T%w| :ה/m6"ɋR7ϺQ6A}p'5!)BM ẙѡyh_b#RZWOA1?t3_44 ;1R�H9wHw MjJ$5zPQ0FtRNJı.5shfQЂm- \Θգ`0*^; $9Ɯ56~4ߐ@Hm\9BMX`ӷ&(CaŠhzzsSCZ^<-j`%=Nmt*}hI wjJ @=+d!B!$4ΰ'2)PbY&81}_3%S8'cGkwpʆS{[9rY:mL _wӭj'էȝCƲ l8"MTJi_ Xu jDX~=>tv~jϐ/j'A2"]uqnT !t =.&5AITE9HYt%9łQ y�':LtCf imB:FNrq FդhS{_YbCp4/ 7ՀBV%`F_ȥkfLz5Sz z _)8LoP6v-{fE&1e54g%-uQ]BnII%6E_OD^ۨ?#e!"Bk<,B!$ơ &>0l%؀S:sɴBO*-7u0j[Ð*e˜db|+:^Jeېhû0go᧩be|-"2Ez^%#JD}pTMpogKTDi~<՜(?Ay$`qKz\Q,mƾ^@~f 043jgfE{yOe4bQC^*8v"q 7#5xeS8m<4TʁH3bI[Cm:Z8qv +4m<#S8$:IP@7 `!҈w8𹚨>IYe #oZ %c5RQdB!(%??y)iii+5T3(b#V2v5ޭH@!B!ާǐѠH.C1DɣԎ[eJjA<tvJ2I!B!.Pz3yBPLH##i{=%B!bF:C BLBd\2 1} %M%uXUƑZI& !B!ED �� �IDATJB p?K$B!b'k( !B!BHBI!B!BEJB!B!",PB!B!aB!B!$BLOs2^Xgƍ $B!b$x/c<c`뫴e>^S| xk ") 1҈NQz|'GHއ my{~VU)m c*,+3ӈ1Pp?ʷ`U'N> @?Cti3|/B~ xcs//p݇s6Ȩ1FEkҸ>A]u㜑7pQJ?VH+Jӫ"ЕyZmB!BLPR]83Z>^y Ye&m:gX c!{rqX h]-VpAǼldŒ|iC*jW5GwD]<sa%%$FV gPZzbѼ-T6 9Vl%ƨG˜CCt<ΊRz3Kp~͛SY -N3 %lu"{_askM|\0XXb!UZJB!b�,]^HEĘS 5<4"f%kk@ zt".hm):=| @!//1]Nm>v t;s $9ŷq4۶6`Ѳ]7C 4u`v/|k?0h cw^H#5|m3n.ke")a\aңl뙡 ^\ʼn ~x֧Sj^B!bꍞPR Ʊ.NIQɦ6'cX}j7*$a)[/uS?b:!)6ŧ.嗳(59QT풿Њ)2Fv34 y[6=�?zֶh~_WKԦBnS56s߻%�}6 3:^|A趲\JR#~=CZ?V>RO'V:xnBB!S>:>cl`撬L>022K$%Q# m#e:, ԘIIL$CY];eմ#jumi䇋\sӚ[QݍO?[S,(߽m`"rOɌ(۹<,{[Sm ]Hs{+GPUg+9yn>oD`W^s%*>upEq2j0ƒ_^FϤb~-whouZG1&dU!jDuPӰl3)TͻK3sH0;m8[8ב|wy.ys7̝KUU=/Ng- ysqe [CIIf} ޷v8`^ ײ(1ғg�hk3)FV fͭJ cne'ʒI7[\aFmN*oԊY'{NH#]ozzCJn8Fw1YȊI vǼjypyUoN:}g$Ωq`~;Zlzwpq%r׿aE1fBn?=[U1p!nao~:KcYcEy&B!śPJO֡ɤ-K pp?ITzo0)Ɋ�_7@{P[",(h>t.yß4O+U'ѧbUʼ%{y/-l=} L$駹ڨ M|8Fue#lJ fq?foh?9bewV8#X8g=wL'v-s<Ǿv=ҙ;;q _eCUω7o;i FCD rƘvE0=)\3\`B 8iDHެkMJ䑍rxSOmh`KaV&'Og |" *cf_k ^z=midѱ$tkk(yimDEyފ\AVD*hvj!R >=/us}hqMr+js.;FΤ_an׉]l: o&nV{~{ju20GAF›fo~ũ>d;hΎb=jtQw(=Nm9Tb\.-HaN&vߙP?^MI_IJ9pws<V~<], evQQœKƂlL&4sŻ*K"(Ib:פB!J1Vqdt#aLdl"x�D fc4Qz8*4bi:u'/rm|(P͋|K?gG t/KWqMP)!4+R+~s-rm|(Ps|bw ,nqluH}պWm* VsMyǡLtXGw40d>5 lG jʏ+ax>@W*QĺDwn|>spx{NL`Iu&<jOdG[Q\{kqW/i>: Rٷ~HT0jxqȫ.W~[2޲n44<u]rUpKB7v= mtaOo_cXH{'^ i\3iViL{8e'ts 3-hmht`Le_e~" gRz5`x= t}<ٷE䖤Pv µG)iE'Fh %dBqf'%)aP<Y5?~?}1ۜ(1C|p}1֏٫YnD=4|w@{W/]U$ߛT{�5DJ 3M5)B!..#j"4E1dRZF.$'MG8P z 餧`M ] �I/#R?K;qzg¡LoԩToz]uUʟKFi@}U;;ʞb;qkzgcV_޷9|-*zR2RiD_RFFEzӋ8r6y ]$ĥ`Q4NLP ;}TeVmXzl zBĈDP_"@m`u*: 8 h4WlvVh`5[8pN-li M4khԎܪCϰWc%�B4V߇"+CiX(_CSAgaQ@^ X꣬6s ng}Nv#&= r>SQ;[ i(1y̎Ǣo{ W/L nySzM !B͈CL3 _: Eđx4&x1•+ȏ۰I d6``]Q#&sߠU:-&Tz|=,*nmȃnXf#2(?t8xnڐ:xz<t܈k0m5T<pPR0}[t>ﰲ@/^ zam `0Z7 ٞ'/uLS){F@FCP4jO .c!9kofI~.hƪq{ x{GT �f }5dpe1![OKSVW~$É= $vӼxpZ UEϟ.k9~β3ŤG|uӟkR!B\ %C�){ LgtDbӁbJf5hh<hfXEa!:[u"*J;l`u cG2;yk(߻ONxns,cݟ"ݡzp7i(4b"!frb,[YsEo </εX|UD㪽hjXWuw_Go#ׯaaAɳ/}c>#3ֈfg@B!S?8(kif#FAzAf餽w,8#Gj.y&mضnymJC� G],}9)[9=_$4XV9Xçʹꈴ BĈs ӳF0ԗT paJXɍIv|E`Y2hŢAm1V}-F X;k3L[ln#_8eV_5�t K$Iuüv6S0/OhGwjtpGcΊ&BG\TFTj[q<\T+s,0_L+Dl`QQA}ӜC�y%^sǝV:y834|!0B!3? wo7WURtO.w!m~Q)6\BIP vl?NG@6`{$cue:2%(}weҒ3q׼x}b'&\U QWVA'Y8)k+n``t}eqeYlq96%D.~~46td]q͚ǵWΙ4TZj:2{'|_,khlK{#^M!9{%Es'"?+*mxfP_hwvD!)kfHeyN8{ٹl:/ߔŇI=SP0>Ҏ^9-54+HИBy$RV@ Mid87B}e$F) ?! KITFv:ݝБVHcz/ur?6~zJߘD**uuGM}G![G6Rƾhظ1$Uw9k2V !Bu xF3IFjO?tNT"3Y(ɎY%&k2Ph?-O+2ggaz *A]+ ۉ(t':ee9ῄ'F!Z7[g<~d5}l1ǗbM-XOX?wzp[g<}|Vt ?yr5j'kBm~7 }'|:{l)URgcDkcϗ3ݓt)W__t=F_I�߷xxpn}Z!&~ʪ2 u:㮗-lju+49]#Hzzy`[x7VOX'oMc =$s}FŶ\J1|B</5� O"j9).֨xn4F?HkHs. ;IWwpkCz=;ЀW9Y3YY_8Pb3p hν喝*ӻ&g}f%n=iA2,/}yd'e=Et6`LHBsu8j&d}V _[[{<#Κ]ǒk[k"!&-G5Ʋr fu2XGz6&co/t̙`GMO}GùEnY%. fG T;e\VI᫋uG'It ) !B}/K9&�G@BBQtb@BB2Dœ0xl&YejeJb|,(05?ef eP~zWyhBT<}?}0-d /`ͰOnI3;pYI˛E¡7_)v-ykOI<h_ZZ$yA^<&t ,`ƞ#)4#X7|'JhII!Z颲 |c77=ēǩHK!.*ןfgӼ!r(xr^K i nz-mxѤ 4=͟{ ԷZNY�->-鳉) &z~џoA<fliDAہ>}`ųxa mmsw͎wLУPq !G׎?{[y䷯r"xy6?YCyd#TL1T;4Uo^3[*| o!IcGm5"�[wݣuѺ/}?lO}("rc~|xwY# fkbIر'[ƿ&_*M B!"V~~oNS"2Ҩ@vK/~mʇy>V{O|gIdySI,)T]8}bo)Oݳ8pd[aE~U;s*oc,$B!p86H8..vGDŽRRHzV :4N7kbcQ%fzbѡrYl,l̲VKĒ\9uP885<a`hhKJH'%$B! ?|>Dd 8\.׌(>AiO3GYV+3{6-�V^ʞ3˾=kp˿5*w:f/-aŬ(Xqz*57,mq 5 .zR;'-"شgw6 {<bkcS?vR{u%Ka7[9ᗟB!b|f-䑷i0y+ dgng';__8uIU6㦛/4Ԡ-{y,;KY5�rVV!M"׿|Mb6v_bʆw" W!Bț$.„Ҁ;RS1xAg _RV^ecPE&' !BI(IB),̊㡬GJY)+eETV!BI(IBI!B!b M($B!B!"PB!B!aB!B!$3d`NW+)XlܸAIb!B!8w E8L˿p W4;玡JxΜESPl@Q4|ƿ?Q~UW<=^r%03?`^F;'~-Ԏr,᚛S^{,kgI=Γ~va�%2>En_S@bWOv>t?UoMSTH+Jӫ"ЕyZIoB!BLyO()d._B~yW#xҖcyo0Kj]8T+y+-=ΊRz3Ke}% h=Wvhq98W`5h>]%gpL,߼9r_t:P^,!;Jټ6$/mHEw|TUϝɤ'Fz:^c,꺫뺮mmֵmڻ"^B!{珄H 3 }^^'w~w˹eqm \TeVYl40nj -(m٠n5'^TQIDDDDD<4>=:)Ng@fn}^?! NKGL-KYfzc )QR<aYrVD�� �IDAT~DQ|!1>86/bS;&?NadI,ZPIoa_ +SJo"#1}b 3biu}[Bޣ W1<?<}91=[<Pt2{`?+=gM>#EDDDD}'d ͘= vHlmAh Ǐ:ro L X u" Yk)^,9X{ݱ*D.׿ˢZ$fzA}~!,jXŕ߿r?3W't%-&e;:/l^YKUձNgm^{"scOH ~=2ߕS'"""""npNg.6n,D&G᧼F?g]1n]<l4iflj@ڷ>EHgǜ/it+j$}K\bֺ| W|ΖLj#X&M'_1k(ݾm簷A"w`B ֳؙY}XއZIͯ a{(Yǿң֮ oa<Z;7 {lZҬbۤHL` WMe;Ws,ҮvpD~8ަjf u. k6*(&ɜy\:? *ض[Ƨ.j9ic*+g[4~ <Ň ۮcfP'O_xO6V4űC \ҏ\Ti7"W% ʧqה0v| 7]ľQTgykt^0[ܛ ڕ{YФPuUKƘܒCCa}I.(aQeC1m?ٗDcúV8l4i1a,t;z$b֗RKh/$[<^|!Y'#n`Xepʨ/CK"t?ަ W <s =Am?ٕm]20ۍ@;5o,p4C-쭴`Fzn=(\OaXO"\/=O])V\5ETVc %|4RXdzI18W G) d}N%ûuethVϣ2-prC_̚}d+2)7o`"KWjl)\q}_̚"+ uћΜ62 v3dצ5l:=⦇|(7Qk &"7 nLnMcAJf װ qޥGqA#;iU<'I{+NE.&eGܞ~dž19YЋ.(օ> ?BI ز.5Ŵ[J{QaW'W7L_}Hȯt-nWIA@O\'W|.&x'u<1hU4ex\[4ݮGs,(t+C.]~uMF<!,+Ĥa',!O7+%gZx*$g�,WpgJDYȯ1&>0)loz$­8b_Q�XI ݗids?M1:U_~ϤFߦRQ8K뎲: Mkame w%ٕ-0 .3 ,sO"=<rWOyeejj{Yo\9O>ILYn60 ͂mL璧伱|/.L*�K 3{{1ٿʖNҕͬY׀[xJ^;1I],8?<xn~cIFW7ѝPw*8NQ=NA>EDDDDCfDA>IU @"∋ ݎi%0"~#06u lI庹T6M9ydon680\7Fn" \C9=̹_z %^{``ߵ,$wc.B@xD;:zs[M> mnZ trΝ1I�bdbb/$8`ؾ`ϚkY5Uǭ0[[MM!"sLV5e>YoY̻߳)+q=ˋ/SeZMNPDZ=eMup6j!2>"s׬n;vVڲwuܿJ^"W|\I"""""rP\ћ@h(`LjL9mJgfV$+ Ç=$~2Ba� u8Lyc=tܺ{h926x<uƇum!p.uMyȃz/^$!] 3j&fmn1ÅYZN+b\ܽG$sa #Q} _o \TW5_^SSؼ/}VU6QUI ~>>4{<e]m!?ڦ~l<։;>fCMuMm�V?K*YOBiajB9&@ Q |MO0.`|F),o*гDZfcM7lGenvKhDIY@ C|@yK '01F]W`7qv| |ײ"gx3:|[Ha®Lե6Y| pD$Rpdt2jeO}2�{CӞ2kkk lw"JHAذ:ӭx;V~7g/?f lnoʃg u_gG˨q6?1'-j6Vt bDD  !a""{o&RI+ޘ߆L ŷtn<'/x8,g ŧ\cgkع82|cg  CMCQmNDDDDDNp%,?`Z|ֳ7ŧiZe'>) oä=\;vLAXn HdPpE86cUiGy'tEUn6vBPD?W .19=c`qX›ʰFpQ_\}0�W]%cILzpv5YÜ 8->Lڙ.F㡴'b{iv3mn,vlo*9ٶj 1Sx3vT:)Nre!qt5Id 4nq�~>. 'Ϡ”3{7E0rKYXJ3[7]ĭcb˴D. Ui^DDDDD:i+J"�;TFDžI֥lgNv'gL? _+mWI;lnA#>W39ԮUy}wO1s_* 0B ¬XͶYMr-)GRxF֛jlt8Foّݟ> 9/,*KP lVXaxOXh|4sqpL<w6М'NIR1;h{{Vlz_ܵڱ=g%즼ʊT,Tc|:JJO%TX OH_l_[ ]wUatTd`]DNɯ&"3-Gt ]P}>:Γ!#kdBqf|^>l } ebbܷ|nD͟r.qV =f;߹W5aɗwSmO q8Kp$,9;RZ,FOӟOIDDDDD_N+Y ""NX�;""߮2.^y[ ܉�KXp9{;Q~d'??;= ;x #mo=ɚ%(!06JW5ozֿvJp鯱riqYl{qV/YOy%[9K_y*y۶{x9=jIXr“)rsT|qf|A+ AmZF>%WWx2!P_/;J .ʚ;tǷw]/PvÓxr|]}ofBjmAoxa,pyҸ}I:*MFc/gxE}''d);*KM!B6~(?Ҵo$0`�m%80`@;fe:>[Mwbmd|(rjcJNlz5RGL}^AFjjEEE2bccU"ރKa_Ol. {]ʰ1u+]N~S|նSn^Ptw@]2Զ<1>kU3dS+7}n4kC?,mmʘS'a6Q9!']"00i9i%8G5t12gE^%[bRوKƂIUE!D-E|ڵ%mfPS1IDDDDD\EړFבCP:ńc8 )ؚ{`OrK9kPǢyGc?y ơAX9,]ٞOfu9o,tcX3IWj=@DDDDDQAIڗl*Vt6P_9CSRLڗ/=3 0q9(\w^ udo_/hai9l*=ڟP_åI"""""4CɢtHKLDDDDD*([TP$""""""""nQAIDDDDDDDDܢE%q~A/>ÇYYP̟!v$RΏ+3wĂOxEo(?ӟq~PźG/VDDDDDDDDwnyf>tV6W7 ?]vj+""""""""9i+ظ͂oن&o PuuVDDDDDDDD<uny3(ز�KD~;/iPdžu9ԙVDDDDDDDD<qfBIPOvv KK$8""""""""r\:hAF>IU @"∋𴭈YPMZr 4q]&5fB9&@ Q |W"""""""":`A^]Jqq-V9ఀi+""""""""Cw`g51frp JF@%hFH*#¤xR6uGDDDDDDDD:BOHx;@=Cc9PFAll,JbEw$""""""""nQAIDDDDDDDDܢE%qKV([TPx>jitI|sfsvh�Yd2hy ލc/`lU/"""""""gYCƶ,Ӻb+B%b{2ԳLJg?^݀s)ԯx^\Jqk۹rMJ_wt~Xwzub?“'SCM4t\\ǿP֔xiDVov~\gyp3)xxvz2N4tڵOV>=O. :u//ǧXXn߿D폏򿯬;0htS /}dnXȗ~zu{֔Qmyne TY+$qH1:sH0"k)Sd[1~\^<I?cr&Ƚ+/W}LraSA 0I9%j`W_t1gE\/gRf}2fk@.s9_ 9;Xװr _~ 2E\gol_~<핞t;1ڻ%l˭Afّ7Ҙ4*Em=h[2y˺`#sg..tu)IŻb>ONI]y)Zī, 'K;a׍r }gtǮ,p*_`7W\^|Ke!]3?v-~}X#1bzK廟`^QG-^J+<-c8mϙd76@55tM&� f¿>婾%dg%;5?!;<[z;jyh ǑdLIŕ=+M3GA?)fư5 2JWxEAlOmbw})@ڄ l xO>yeR23wcn_ӓŇsHzGpVTvMˎZ*SS|p~c xuaŸqޤ$~ er:ȨfqE ^ۺ_}N'٥ >3 !SMsfR]]l2>8(\2o,<0r!tŕ==&+LE2ևqy\>n܋'w%InV> R74äf_GǯiWZNFQXjVҟ`~?q!P)J=Ȩ57\zɆr/0=E~rћo\U{ٽv}4 n&$R;߬d7A$.>!)Qt<͒zڍ+zkum]ʹGgZ`8p[;mu?ypr?;z }4[_N1qP ,g^z҇3.dDwU3dgn}Fa?s.-wxj s5d݇njqP3sW^0n!YkΛV{NJgq͂ź[DDDN?^A\tHmA>Ć3iH8w>E^xUnQc+<,]FdtV<((6Fs oAA)[=Rw~[3^ɀ3O~Wܹ7wŜ=7>gbf~ ;*sfeA/{_ZB`2*9_E֒l?,{T|~XF]ƈ෣gmpm;dA0i"/dԤ4>ܼŊ[];6QYtܕ|k{�7N(qB@AzQ]=_zKJ$s zRLwkKb=r3G Wѳo,2+ EشIXRO57L"jQgjqYCl(`Đv\NMxT(ڽ_sr>1񞦕m>ڟ@lI_Ew@t9c"}}l<V~O/kQOj#6lv37­xDl:sYSL}BîKaIq+n\M lKK1\s7w<RǺ[uDDDDOHƟ-&7:/%o仹IhՀJ<YLCI^0jqfk>yqg;$.A.oe��IDAT)%^cgг2/ituOrff-)[o~a!!X�` ;$FA5.N6&m?9;v؂Zu2!XB+gw74OMO<`¥Uf +?/͙}x&w7"z0MfbsCfK1'cgnعs\AӸ W<0;)y__<\#˃pܔI=XڝܷŔGCp3GX{]sLs+xr[ K_';Y^8iqC).ɐL}-H&0v\ 6%66a •3֚` a̭Op~o0Y½x$s¹CyK㢉 @ӽ1>>}쵝|&Xc8ǹ & ew/t'm79,L9#?k vQ䲩)X]{I_ᆍ@o$?Z8ս\ r^gm lLo8t0wwr p5vx8VU̞ԙ1ď>~sd]ycƟ9@Q[۬XǾj:b]'m;zAO?.xD&byi 2+Xڃ<z~;m0C/-οŸW>c]'CϤvG֦^fqUwOp (bժ8 Jm?I.rat cpTZ^ub|r|ޯݤ// 2$ϳsvN`ߜVmoKx άqJrIDDzw eb],zu-gűm: & @CĎ讀Xܜ/U}zr8Ƙs%u՘ÞZ)"""˭4~� <ɫ؇+r#B]yO6{c]y5%߳n,L ")@cg|\ۧ,jkpZ3#8v&?_6U7uSKfgs˯+< Nvgpl?COs@$=Y:<kہ J`Zi:grX% n>1x] v1_ TV?:BUyGq]ZwƒZ0ɥa9 f+3}˫ێPOƎ>ul9yO'q`",󐁄v6šG b8:!-]s໱qn?.E.`_nWe7dV=F<cR}m]bT]m&6oqڑ$I[;'4՘TWi&JkL>U{ï;q;ttի<ZS.j\nR1k9OڃʅOsB� i̸V:_3{ Ұ}^Kh.ۑɲ9-ߤ&{)va`\1LHZG >Y;co;7UwwY|mFWl% />\=LYrۛpmʽΣabOj?Q=Xpt3ksqqPGop FW8q73~h'[ü%dV?s7i}< ]3j7<bs֦x;iuOƘ jxhuxwxhO%r2}JO2~'3zSm{n.^t lq24jZ8Mj2); gN+\G_fmg#�#@Ӭd;OeOrP/?gvyXP?.3nbj{TɌIeoY~^]˯FL"kW]ORjSiaEKHWRlDj-DP([/}~E4^9r;&~p :=utfK2b9v1hظU-on:riPx+Z[fX,.?,`ƕ'ss^G~_1ޟ}Lz^fȨ`ٖ9A&""""]M|w0C#~h֗ߏř-nQCx[2'^]eel ב5M;KJ(Rz| 8roK!OYe\o}<S¨۹Yk.p644իoCAP_JXs'wb8x:+qE%Dv\2rb".Y;oXo1+)9Ֆbͷ3Ys7~ɂaڛֳkf\JAX󪮠z'qSR37`|9ԚFMOS0sDzvv[po0@N^Et\^tsі0fB/b3w{?8ר/e C;yƃhS'cL >i;xqۉ7,\9HtQó/ŝ.b7:S+zsvO q)& 5|_X:m^5x|ƴ3z*CB&/7y]߿[ގ5?Lzɥ\}nX#51 EIvV"#? Bj6~fO>ɝ<oV]?7N$ڸ4O kY7w1{ǜKy}ɢ)3a<d2+O .w2kz=?ӯeo>2$g&J1/uV1pz)eVvۇ:z{lJNJ~qk|;qy_+OLg|>o $3xB{uhQt6hY98&1]5噯Uэg^JrW+ffWX$vϸ$/\PjK0IdW`t!!*=e^߽/܉čI؝ p kaoN~鷓R1Q 99J xBHR gE{ h\?"+RPK^1;]X/Au\4&bpf|u Wmח}:ő%�Kf};>?9_?;qy!da #Tv0}qѯBxmNAs칓{1x*(DеwoYaH�;?}%}<dMҤ̊ռ#\2 RHY[̮|,ӱ.OnsB7=I><'n o\ a\Xz$0)`u[ǵ዇tLޓؤD\U{ٺh0;<^T9[鯖hz>J;ɜ<ӽW aR7ں im3aߔo D[잿=Gywx'Ȼ|Ƥu#{$ԕn6{3wxOԘ)[{H}Ƿv״;uDDDDd2)dsyjb4N[C{rk<pONn;]3Yߨb֋n)%dY|VǚwţPr%LޛIP˗1OY-OӸnr |;oV VRSSO|a#綫͚ſ= 5 7=`¼<=va'<7 5/ˏXd ( v#.TΚr<4Bv)>5gޏ"<+.4}Dw'!d㫿ez"rN350q<#m~6c'.C9sT2]vP>^𥛛rIw9q}}n5k*Zt6APb%}~{0"Iykzρ=;߮ؕh9e>%Sٿ7ؘX5rºZR!sULp=/+LIYa&ey̠<s|?^n;WW_8nyk:a/,l`نn?}^o5ݵZ#""""""s9 J""""""""r|,JJʈ!88BIDDDDDDDDܢE%q J""""""""DDDDDDDD-*([TP$""""""""nQAIDDDDDDDDܢE%q J""""""""DDDDDDDD-*([TP$""""""""nQAIDDDDDDDDܢE%q J""""""""DDDDDDDD-*([TP$""""""""n:9*P$""""""""nņ;6����IENDB`����������������������������������������������������������������������������������������������������alacritty-0.13.2/res/gles2/text.f.glsl��������������������������������������������������������������0000644�0000000�0000000�00000002370�10461020230�0015605�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������varying mediump vec2 TexCoords; varying mediump vec3 fg; varying highp float colored; varying mediump vec4 bg; uniform highp int renderingPass; uniform sampler2D mask; #define COLORED 1 mediump float max_rgb(mediump vec3 mask) { return max(max(mask.r, mask.g), mask.b); } void render_text() { mediump vec4 mask = texture2D(mask, TexCoords); mediump float m_rgb = max_rgb(mask.rgb); if (renderingPass == 1) { gl_FragColor = vec4(mask.rgb, m_rgb); } else if (renderingPass == 2) { gl_FragColor = bg * (vec4(m_rgb) - vec4(mask.rgb, m_rgb)); } else { gl_FragColor = vec4(fg, 1.) * vec4(mask.rgb, m_rgb); } } // Render colored bitmaps. void render_bitmap() { if (renderingPass == 2) { discard; } mediump vec4 mask = texture2D(mask, TexCoords); if (renderingPass == 1) { gl_FragColor = mask.aaaa; } else { gl_FragColor = mask; } } void main() { // Handle background pass drawing before anything else. if (renderingPass == 0) { if (bg.a == 0.0) { discard; } gl_FragColor = vec4(bg.rgb * bg.a, bg.a); return; } if (int(colored) == COLORED) { render_bitmap(); } else { render_text(); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/res/gles2/text.v.glsl��������������������������������������������������������������0000644�0000000�0000000�00000002227�10461020230�0015626�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Cell coords. attribute vec2 cellCoords; // Glyph coords. attribute vec2 glyphCoords; // uv mapping. attribute vec2 uv; // Text foreground rgb packed together with cell flags. textColor.a // are the bitflags; consult RenderingGlyphFlags in renderer/mod.rs // for the possible values. attribute vec4 textColor; // Background color. attribute vec4 backgroundColor; varying vec2 TexCoords; varying vec3 fg; varying float colored; varying vec4 bg; uniform highp int renderingPass; uniform vec4 projection; void main() { vec2 projectionOffset = projection.xy; vec2 projectionScale = projection.zw; vec2 position; if (renderingPass == 0) { TexCoords = vec2(0, 0); position = cellCoords; } else { TexCoords = uv; position = glyphCoords; } fg = vec3(float(textColor.r), float(textColor.g), float(textColor.b)) / 255.; colored = float(textColor.a); bg = vec4(float(backgroundColor.r), float(backgroundColor.g), float(backgroundColor.b), float(backgroundColor.a)) / 255.; vec2 finalPosition = projectionOffset + position * projectionScale; gl_Position = vec4(finalPosition, 0., 1.); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/res/glsl3/text.f.glsl��������������������������������������������������������������0000644�0000000�0000000�00000003357�10461020230�0015623�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#if defined(GLES2_RENDERER) // Require extension for dual source blending to work on GLES2. #extension GL_EXT_blend_func_extended: require #define int_t highp int #define float_t highp float #define vec3_t mediump vec3 #define texture texture2D varying mediump vec2 TexCoords; varying mediump vec3 fg; varying highp float colored; varying mediump vec4 bg; #define FRAG_COLOR gl_FragColor #define ALPHA_MASK gl_SecondaryFragColorEXT #else #define int_t int #define float_t float #define vec3_t vec3 in vec2 TexCoords; flat in vec4 fg; flat in vec4 bg; layout(location = 0, index = 0) out vec4 color; layout(location = 0, index = 1) out vec4 alphaMask; #define FRAG_COLOR color #define ALPHA_MASK alphaMask #endif #define COLORED 1 uniform int_t renderingPass; uniform sampler2D mask; void main() { if (renderingPass == 0) { if (bg.a == 0.0) { discard; } ALPHA_MASK = vec4(1.0); // Premultiply background color by alpha. FRAG_COLOR = vec4(bg.rgb * bg.a, bg.a); return; } #if !defined(GLES2_RENDERER) float_t colored = fg.a; #endif // The wide char information is already stripped, so it's safe to check for equality here. if (int(colored) == COLORED) { // Color glyphs, like emojis. FRAG_COLOR = texture(mask, TexCoords); ALPHA_MASK = vec4(FRAG_COLOR.a); // Revert alpha premultiplication. if (FRAG_COLOR.a != 0.0) { FRAG_COLOR.rgb = vec3(FRAG_COLOR.rgb / FRAG_COLOR.a); } FRAG_COLOR = vec4(FRAG_COLOR.rgb, 1.0); } else { // Regular text glyphs. vec3_t textColor = texture(mask, TexCoords).rgb; ALPHA_MASK = vec4(textColor, textColor.r); FRAG_COLOR = vec4(fg.rgb, 1.0); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/res/glsl3/text.v.glsl��������������������������������������������������������������0000644�0000000�0000000�00000004237�10461020230�0015641�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������// Cell properties. layout(location = 0) in vec2 gridCoords; // Glyph properties. layout(location = 1) in vec4 glyph; // uv mapping. layout(location = 2) in vec4 uv; // Text foreground rgb packed together with cell flags. textColor.a // are the bitflags; consult RenderingGlyphFlags in renderer/mod.rs // for the possible values. layout(location = 3) in vec4 textColor; // Background color. layout(location = 4) in vec4 backgroundColor; out vec2 TexCoords; flat out vec4 fg; flat out vec4 bg; // Terminal properties uniform vec2 cellDim; uniform vec4 projection; uniform int renderingPass; #define WIDE_CHAR 2 void main() { vec2 projectionOffset = projection.xy; vec2 projectionScale = projection.zw; // Compute vertex corner position vec2 position; position.x = (gl_VertexID == 0 || gl_VertexID == 1) ? 1. : 0.; position.y = (gl_VertexID == 0 || gl_VertexID == 3) ? 0. : 1.; // Position of cell from top-left vec2 cellPosition = cellDim * gridCoords; fg = vec4(textColor.rgb / 255.0, textColor.a); bg = backgroundColor / 255.0; float occupiedCells = 1; if ((int(fg.a) >= WIDE_CHAR)) { // Update wide char x dimension so it'll cover the following spacer. occupiedCells = 2; // Since we don't perform bitwise operations due to limitations of // the GLES2 renderer,we subtract wide char bits keeping only colored. fg.a = round(fg.a - WIDE_CHAR); } if (renderingPass == 0) { vec2 backgroundDim = cellDim; backgroundDim.x *= occupiedCells; vec2 finalPosition = cellPosition + backgroundDim * position; gl_Position = vec4(projectionOffset + projectionScale * finalPosition, 0.0, 1.0); TexCoords = vec2(0, 0); } else { vec2 glyphSize = glyph.zw; vec2 glyphOffset = glyph.xy; glyphOffset.y = cellDim.y - glyphOffset.y; vec2 finalPosition = cellPosition + glyphSize * position + glyphOffset; gl_Position = vec4(projectionOffset + projectionScale * finalPosition, 0.0, 1.0); vec2 uvOffset = uv.xy; vec2 uvSize = uv.zw; TexCoords = uvOffset + position * uvSize; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/res/rect.f.glsl��������������������������������������������������������������������0000644�0000000�0000000�00000010436�10461020230�0014544�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#if defined(GLES2_RENDERER) #define float_t mediump float #define color_t mediump vec4 #define FRAG_COLOR gl_FragColor varying color_t color; #else #define float_t float #define color_t vec4 out vec4 FragColor; #define FRAG_COLOR FragColor flat in color_t color; #endif uniform float_t cellWidth; uniform float_t cellHeight; uniform float_t paddingY; uniform float_t paddingX; uniform float_t underlinePosition; uniform float_t underlineThickness; uniform float_t undercurlPosition; #define PI 3.1415926538 #if defined(DRAW_UNDERCURL) color_t draw_undercurl(float_t x, float_t y) { // We use `undercurlPosition` as an amplitude, since it's half of the descent // value. // // The `x` represents the left bound of pixel we should add `1/2` to it, so // we compute the undercurl position for the center of the pixel. float_t undercurl = undercurlPosition / 2. * cos((x + 0.5) * 2. * PI / cellWidth) + undercurlPosition - 1.; float_t undercurlTop = undercurl + max((underlineThickness - 1.), 0.) / 2.; float_t undercurlBottom = undercurl - max((underlineThickness - 1.), 0.) / 2.; // The distance to the curve boundary is always positive when it should // be used for AA. When both `y - undercurlTop` and `undercurlBottom - y` // expressions are negative, it means that the point is inside the curve // and we should just use alpha 1. To do so, we max one value with 0 // so it'll use the alpha 1 in the end. float_t dst = max(y - undercurlTop, max(undercurlBottom - y, 0.)); // Doing proper SDF is complicated for this shader, so just make AA // stronger by 1/x^2, which renders preserving underline thickness and // being bold enough. float_t alpha = 1. - dst * dst; // The result is an alpha mask on a rect, which leaves only curve opaque. return vec4(color.rgb, alpha); } #endif #if defined(DRAW_DOTTED) // When the dot size increases we can use AA to make spacing look even and the // dots rounded. color_t draw_dotted_aliased(float_t x, float_t y) { float_t dotNumber = floor(x / underlineThickness); float_t radius = underlineThickness / 2.; float_t centerY = underlinePosition - 1.; float_t leftCenter = (dotNumber - mod(dotNumber, 2.)) * underlineThickness + radius; float_t rightCenter = leftCenter + 2. * underlineThickness; float_t distanceLeft = sqrt(pow(x - leftCenter, 2.) + pow(y - centerY, 2.)); float_t distanceRight = sqrt(pow(x - rightCenter, 2.) + pow(y - centerY, 2.)); float_t alpha = max(1. - (min(distanceLeft, distanceRight) - radius), 0.); return vec4(color.rgb, alpha); } /// Draw dotted line when dot is just a single pixel. color_t draw_dotted(float_t x, float_t y) { float_t cellEven = 0.; // Since the size of the dot and its gap combined is 2px we should ensure that // spacing will be even. If the cellWidth is even it'll work since we start // with dot and end with gap. However if cellWidth is odd, the cell will start // and end with a dot, creating a dash. To resolve this issue, we invert the // pattern every two cells. if (int(mod(cellWidth, 2.)) != 0) { cellEven = mod((gl_FragCoord.x - paddingX) / cellWidth, 2.); } // Since we use the entire descent area for dotted underlines, we limit its // height to a single pixel so we don't draw bars instead of dots. float_t alpha = 1. - abs(floor(underlinePosition) - y); if (int(mod(x, 2.)) != int(cellEven)) { alpha = 0.; } return vec4(color.rgb, alpha); } #endif #if defined(DRAW_DASHED) color_t draw_dashed(float_t x) { // Since dashes of adjacent cells connect with each other our dash length is // half of the desired total length. float_t halfDashLen = floor(cellWidth / 4. + 0.5); float_t alpha = 1.; // Check if `x` coordinate is where we should draw gap. if (x > halfDashLen - 1. && x < cellWidth - halfDashLen) { alpha = 0.; } return vec4(color.rgb, alpha); } #endif void main() { float_t x = floor(mod(gl_FragCoord.x - paddingX, cellWidth)); float_t y = floor(mod(gl_FragCoord.y - paddingY, cellHeight)); #if defined(DRAW_UNDERCURL) FRAG_COLOR = draw_undercurl(x, y); #elif defined(DRAW_DOTTED) if (underlineThickness < 2.) { FRAG_COLOR = draw_dotted(x, y); } else { FRAG_COLOR = draw_dotted_aliased(x, y); } #elif defined(DRAW_DASHED) FRAG_COLOR = draw_dashed(x); #else FRAG_COLOR = color; #endif } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/res/rect.v.glsl��������������������������������������������������������������������0000644�0000000�0000000�00000000451�10461020230�0014560�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#if defined(GLES2_RENDERER) attribute vec2 aPos; attribute vec4 aColor; varying mediump vec4 color; #else layout (location = 0) in vec2 aPos; layout (location = 1) in vec4 aColor; flat out vec4 color; #endif void main() { color = aColor; gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/cli.rs�������������������������������������������������������������������������0000644�0000000�0000000�00000041564�10461020230�0013621�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::cmp::max; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::path::PathBuf; use std::rc::Rc; use alacritty_config::SerdeReplace; use clap::{ArgAction, Args, Parser, Subcommand, ValueHint}; use log::{error, LevelFilter}; use serde::{Deserialize, Serialize}; use toml::Value; use alacritty_terminal::tty::Options as PtyOptions; use crate::config::ui_config::Program; use crate::config::window::{Class, Identity}; use crate::config::UiConfig; use crate::logging::LOG_TARGET_IPC_CONFIG; /// CLI options for the main Alacritty executable. #[derive(Parser, Default, Debug)] #[clap(author, about, version = env!("VERSION"))] pub struct Options { /// Print all events to STDOUT. #[clap(long)] pub print_events: bool, /// Generates ref test. #[clap(long)] pub ref_test: bool, /// X11 window ID to embed Alacritty within (decimal or hexadecimal with "0x" prefix). #[clap(long)] pub embed: Option<String>, /// Specify alternative configuration file [default: /// $XDG_CONFIG_HOME/alacritty/alacritty.toml]. #[cfg(not(any(target_os = "macos", windows)))] #[clap(long, value_hint = ValueHint::FilePath)] pub config_file: Option<PathBuf>, /// Specify alternative configuration file [default: %APPDATA%\alacritty\alacritty.toml]. #[cfg(windows)] #[clap(long, value_hint = ValueHint::FilePath)] pub config_file: Option<PathBuf>, /// Specify alternative configuration file [default: $HOME/.config/alacritty/alacritty.toml]. #[cfg(target_os = "macos")] #[clap(long, value_hint = ValueHint::FilePath)] pub config_file: Option<PathBuf>, /// Path for IPC socket creation. #[cfg(unix)] #[clap(long, value_hint = ValueHint::FilePath)] pub socket: Option<PathBuf>, /// Reduces the level of verbosity (the min level is -qq). #[clap(short, conflicts_with("verbose"), action = ArgAction::Count)] quiet: u8, /// Increases the level of verbosity (the max level is -vvv). #[clap(short, conflicts_with("quiet"), action = ArgAction::Count)] verbose: u8, /// CLI options for config overrides. #[clap(skip)] pub config_options: ParsedOptions, /// Options which can be passed via IPC. #[clap(flatten)] pub window_options: WindowOptions, /// Subcommand passed to the CLI. #[clap(subcommand)] pub subcommands: Option<Subcommands>, } impl Options { pub fn new() -> Self { let mut options = Self::parse(); // Parse CLI config overrides. options.config_options = options.window_options.config_overrides(); options } /// Override configuration file with options from the CLI. pub fn override_config(&mut self, config: &mut UiConfig) { #[cfg(unix)] { config.ipc_socket |= self.socket.is_some(); } config.window.dynamic_title &= self.window_options.window_identity.title.is_none(); config.window.embed = self.embed.as_ref().and_then(|embed| parse_hex_or_decimal(embed)); config.debug.print_events |= self.print_events; config.debug.log_level = max(config.debug.log_level, self.log_level()); config.debug.ref_test |= self.ref_test; if config.debug.print_events { config.debug.log_level = max(config.debug.log_level, LevelFilter::Info); } // Replace CLI options. self.config_options.override_config(config); } /// Logging filter level. pub fn log_level(&self) -> LevelFilter { match (self.quiet, self.verbose) { // Force at least `Info` level for `--print-events`. (_, 0) if self.print_events => LevelFilter::Info, // Default. (0, 0) => LevelFilter::Warn, // Verbose. (_, 1) => LevelFilter::Info, (_, 2) => LevelFilter::Debug, (0, _) => LevelFilter::Trace, // Quiet. (1, _) => LevelFilter::Error, (..) => LevelFilter::Off, } } } /// Parse the class CLI parameter. fn parse_class(input: &str) -> Result<Class, String> { let (general, instance) = match input.split_once(',') { // Warn the user if they've passed too many values. Some((_, instance)) if instance.contains(',') => { return Err(String::from("Too many parameters")) }, Some((general, instance)) => (general, instance), None => (input, input), }; Ok(Class::new(general, instance)) } /// Convert to hex if possible, else decimal fn parse_hex_or_decimal(input: &str) -> Option<u32> { input .strip_prefix("0x") .and_then(|value| u32::from_str_radix(value, 16).ok()) .or_else(|| input.parse().ok()) } /// Terminal specific cli options which can be passed to new windows via IPC. #[derive(Serialize, Deserialize, Args, Default, Debug, Clone, PartialEq, Eq)] pub struct TerminalOptions { /// Start the shell in the specified working directory. #[clap(long, value_hint = ValueHint::FilePath)] pub working_directory: Option<PathBuf>, /// Remain open after child process exit. #[clap(long)] pub hold: bool, /// Command and args to execute (must be last argument). #[clap(short = 'e', long, allow_hyphen_values = true, num_args = 1..)] command: Vec<String>, } impl TerminalOptions { /// Shell override passed through the CLI. pub fn command(&self) -> Option<Program> { let (program, args) = self.command.split_first()?; Some(Program::WithArgs { program: program.clone(), args: args.to_vec() }) } /// Override the [`PtyOptions`]'s fields with the [`TerminalOptions`]. pub fn override_pty_config(&self, pty_config: &mut PtyOptions) { if let Some(working_directory) = &self.working_directory { if working_directory.is_dir() { pty_config.working_directory = Some(working_directory.to_owned()); } else { error!("Invalid working directory: {:?}", working_directory); } } if let Some(command) = self.command() { pty_config.shell = Some(command.into()); } pty_config.hold |= self.hold; } } impl From<TerminalOptions> for PtyOptions { fn from(mut options: TerminalOptions) -> Self { PtyOptions { working_directory: options.working_directory.take(), shell: options.command().map(Into::into), hold: options.hold, env: HashMap::new(), } } } /// Window specific cli options which can be passed to new windows via IPC. #[derive(Serialize, Deserialize, Args, Default, Debug, Clone, PartialEq, Eq)] pub struct WindowIdentity { /// Defines the window title [default: Alacritty]. #[clap(short = 'T', short_alias('t'), long)] pub title: Option<String>, /// Defines window class/app_id on X11/Wayland [default: Alacritty]. #[clap(long, value_name = "general> | <general>,<instance", value_parser = parse_class)] pub class: Option<Class>, } impl WindowIdentity { /// Override the [`WindowIdentity`]'s fields with the [`WindowOptions`]. pub fn override_identity_config(&self, identity: &mut Identity) { if let Some(title) = &self.title { identity.title = title.clone(); } if let Some(class) = &self.class { identity.class = class.clone(); } } } /// Available CLI subcommands. #[derive(Subcommand, Debug)] pub enum Subcommands { #[cfg(unix)] Msg(MessageOptions), Migrate(MigrateOptions), } /// Send a message to the Alacritty socket. #[cfg(unix)] #[derive(Args, Debug)] pub struct MessageOptions { /// IPC socket connection path override. #[clap(short, long, value_hint = ValueHint::FilePath)] pub socket: Option<PathBuf>, /// Message which should be sent. #[clap(subcommand)] pub message: SocketMessage, } /// Available socket messages. #[cfg(unix)] #[derive(Subcommand, Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub enum SocketMessage { /// Create a new window in the same Alacritty process. CreateWindow(WindowOptions), /// Update the Alacritty configuration. Config(IpcConfig), } /// Migrate the configuration file. #[derive(Args, Clone, Debug)] pub struct MigrateOptions { /// Path to the configuration file. #[clap(short, long, value_hint = ValueHint::FilePath)] pub config_file: Option<PathBuf>, /// Only output TOML config to STDOUT. #[clap(short, long)] pub dry_run: bool, /// Do not recurse over imports. #[clap(short = 'i', long)] pub skip_imports: bool, /// Do not move renamed fields to their new location. #[clap(long)] pub skip_renames: bool, #[clap(short, long)] /// Do not output to STDOUT. pub silent: bool, } /// Subset of options that we pass to 'create-window' IPC subcommand. #[derive(Serialize, Deserialize, Args, Default, Clone, Debug, PartialEq, Eq)] pub struct WindowOptions { /// Terminal options which can be passed via IPC. #[clap(flatten)] pub terminal_options: TerminalOptions, #[clap(flatten)] /// Window options which could be passed via IPC. pub window_identity: WindowIdentity, #[clap(skip)] #[cfg(target_os = "macos")] /// The window tabbing identifier to use when building a window. pub window_tabbing_id: Option<String>, /// Override configuration file options [example: 'cursor.style="Beam"']. #[clap(short = 'o', long, num_args = 1..)] option: Vec<String>, } impl WindowOptions { /// Get the parsed set of CLI config overrides. pub fn config_overrides(&self) -> ParsedOptions { ParsedOptions::from_options(&self.option) } } /// Parameters to the `config` IPC subcommand. #[cfg(unix)] #[derive(Args, Serialize, Deserialize, Default, Debug, Clone, PartialEq, Eq)] pub struct IpcConfig { /// Configuration file options [example: 'cursor.style="Beam"']. #[clap(required = true, value_name = "CONFIG_OPTIONS")] pub options: Vec<String>, /// Window ID for the new config. /// /// Use `-1` to apply this change to all windows. #[clap(short, long, allow_hyphen_values = true, env = "ALACRITTY_WINDOW_ID")] pub window_id: Option<i128>, /// Clear all runtime configuration changes. #[clap(short, long, conflicts_with = "options")] pub reset: bool, } /// Parsed CLI config overrides. #[derive(Debug, Default)] pub struct ParsedOptions { config_options: Vec<(String, Value)>, } impl ParsedOptions { /// Parse CLI config overrides. pub fn from_options(options: &[String]) -> Self { let mut config_options = Vec::new(); for option in options { let parsed = match toml::from_str(option) { Ok(parsed) => parsed, Err(err) => { eprintln!("Ignoring invalid CLI option '{option}': {err}"); continue; }, }; config_options.push((option.clone(), parsed)); } Self { config_options } } /// Apply CLI config overrides, removing broken ones. pub fn override_config(&mut self, config: &mut UiConfig) { let mut i = 0; while i < self.config_options.len() { let (option, parsed) = &self.config_options[i]; match config.replace(parsed.clone()) { Err(err) => { error!( target: LOG_TARGET_IPC_CONFIG, "Unable to override option '{}': {}", option, err ); self.config_options.swap_remove(i); }, Ok(_) => i += 1, } } } /// Apply CLI config overrides to a CoW config. pub fn override_config_rc(&mut self, config: Rc<UiConfig>) -> Rc<UiConfig> { // Skip clone without write requirement. if self.config_options.is_empty() { return config; } // Override cloned config. let mut config = (*config).clone(); self.override_config(&mut config); Rc::new(config) } } impl Deref for ParsedOptions { type Target = Vec<(String, Value)>; fn deref(&self) -> &Self::Target { &self.config_options } } impl DerefMut for ParsedOptions { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.config_options } } #[cfg(test)] mod tests { use super::*; #[cfg(target_os = "linux")] use std::fs::File; #[cfg(target_os = "linux")] use std::io::Read; #[cfg(target_os = "linux")] use clap::CommandFactory; #[cfg(target_os = "linux")] use clap_complete::Shell; use toml::Table; #[test] fn dynamic_title_ignoring_options_by_default() { let mut config = UiConfig::default(); let old_dynamic_title = config.window.dynamic_title; Options::default().override_config(&mut config); assert_eq!(old_dynamic_title, config.window.dynamic_title); } #[test] fn dynamic_title_overridden_by_options() { let mut config = UiConfig::default(); let title = Some(String::from("foo")); let window_identity = WindowIdentity { title, ..WindowIdentity::default() }; let new_window_options = WindowOptions { window_identity, ..WindowOptions::default() }; let mut options = Options { window_options: new_window_options, ..Options::default() }; options.override_config(&mut config); assert!(!config.window.dynamic_title); } #[test] fn dynamic_title_not_overridden_by_config() { let mut config = UiConfig::default(); config.window.identity.title = "foo".to_owned(); Options::default().override_config(&mut config); assert!(config.window.dynamic_title); } #[test] fn valid_option_as_value() { // Test with a single field. let value: Value = toml::from_str("field=true").unwrap(); let mut table = Table::new(); table.insert(String::from("field"), Value::Boolean(true)); assert_eq!(value, Value::Table(table)); // Test with nested fields let value: Value = toml::from_str("parent.field=true").unwrap(); let mut parent_table = Table::new(); parent_table.insert(String::from("field"), Value::Boolean(true)); let mut table = Table::new(); table.insert(String::from("parent"), Value::Table(parent_table)); assert_eq!(value, Value::Table(table)); } #[test] fn invalid_option_as_value() { let value = toml::from_str::<Value>("}"); assert!(value.is_err()); } #[test] fn float_option_as_value() { let value: Value = toml::from_str("float=3.4").unwrap(); let mut expected = Table::new(); expected.insert(String::from("float"), Value::Float(3.4)); assert_eq!(value, Value::Table(expected)); } #[test] fn parse_instance_class() { let class = parse_class("one").unwrap(); assert_eq!(class.general, "one"); assert_eq!(class.instance, "one"); } #[test] fn parse_general_class() { let class = parse_class("one,two").unwrap(); assert_eq!(class.general, "one"); assert_eq!(class.instance, "two"); } #[test] fn parse_invalid_class() { let class = parse_class("one,two,three"); assert!(class.is_err()); } #[test] fn valid_decimal() { let value = parse_hex_or_decimal("10485773"); assert_eq!(value, Some(10485773)); } #[test] fn valid_hex_to_decimal() { let value = parse_hex_or_decimal("0xa0000d"); assert_eq!(value, Some(10485773)); } #[test] fn invalid_hex_to_decimal() { let value = parse_hex_or_decimal("0xa0xx0d"); assert_eq!(value, None); } #[cfg(target_os = "linux")] #[test] fn completions() { let mut clap = Options::command(); for (shell, file) in &[ (Shell::Bash, "alacritty.bash"), (Shell::Fish, "alacritty.fish"), (Shell::Zsh, "_alacritty"), ] { let mut generated = Vec::new(); clap_complete::generate(*shell, &mut clap, "alacritty", &mut generated); let generated = String::from_utf8_lossy(&generated); let mut completion = String::new(); let mut file = File::open(format!("../extra/completions/{}", file)).unwrap(); file.read_to_string(&mut completion).unwrap(); assert_eq!(generated, completion); } // NOTE: Use this to generate new completions. // // let mut file = File::create("../extra/completions/alacritty.bash").unwrap(); // clap_complete::generate(Shell::Bash, &mut clap, "alacritty", &mut file); // let mut file = File::create("../extra/completions/alacritty.fish").unwrap(); // clap_complete::generate(Shell::Fish, &mut clap, "alacritty", &mut file); // let mut file = File::create("../extra/completions/_alacritty").unwrap(); // clap_complete::generate(Shell::Zsh, &mut clap, "alacritty", &mut file); } } ��������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/clipboard.rs�������������������������������������������������������������������0000644�0000000�0000000�00000006075�10461020230�0015007�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use log::{debug, warn}; use raw_window_handle::RawDisplayHandle; use alacritty_terminal::term::ClipboardType; #[cfg(any(test, not(any(feature = "x11", target_os = "macos", windows))))] use copypasta::nop_clipboard::NopClipboardContext; #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] use copypasta::wayland_clipboard; #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] use copypasta::x11_clipboard::{Primary as X11SelectionClipboard, X11ClipboardContext}; #[cfg(any(feature = "x11", target_os = "macos", windows))] use copypasta::ClipboardContext; use copypasta::ClipboardProvider; pub struct Clipboard { clipboard: Box<dyn ClipboardProvider>, selection: Option<Box<dyn ClipboardProvider>>, } impl Clipboard { pub unsafe fn new(display: RawDisplayHandle) -> Self { match display { #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] RawDisplayHandle::Wayland(display) => { let (selection, clipboard) = wayland_clipboard::create_clipboards_from_external(display.display); Self { clipboard: Box::new(clipboard), selection: Some(Box::new(selection)) } }, _ => Self::default(), } } /// Used for tests and to handle missing clipboard provider when built without the `x11` /// feature. #[cfg(any(test, not(any(feature = "x11", target_os = "macos", windows))))] pub fn new_nop() -> Self { Self { clipboard: Box::new(NopClipboardContext::new().unwrap()), selection: None } } } impl Default for Clipboard { fn default() -> Self { #[cfg(any(target_os = "macos", windows))] return Self { clipboard: Box::new(ClipboardContext::new().unwrap()), selection: None }; #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] return Self { clipboard: Box::new(ClipboardContext::new().unwrap()), selection: Some(Box::new(X11ClipboardContext::<X11SelectionClipboard>::new().unwrap())), }; #[cfg(not(any(feature = "x11", target_os = "macos", windows)))] return Self::new_nop(); } } impl Clipboard { pub fn store(&mut self, ty: ClipboardType, text: impl Into<String>) { let clipboard = match (ty, &mut self.selection) { (ClipboardType::Selection, Some(provider)) => provider, (ClipboardType::Selection, None) => return, _ => &mut self.clipboard, }; clipboard.set_contents(text.into()).unwrap_or_else(|err| { warn!("Unable to store text in clipboard: {}", err); }); } pub fn load(&mut self, ty: ClipboardType) -> String { let clipboard = match (ty, &mut self.selection) { (ClipboardType::Selection, Some(provider)) => provider, _ => &mut self.clipboard, }; match clipboard.get_contents() { Err(err) => { debug!("Unable to load text from clipboard: {}", err); String::new() }, Ok(text) => text, } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/bell.rs�����������������������������������������������������������������0000644�0000000�0000000�00000002741�10461020230�0015227�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::time::Duration; use alacritty_config_derive::ConfigDeserialize; use crate::config::ui_config::Program; use crate::display::color::Rgb; #[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)] pub struct BellConfig { /// Visual bell animation function. pub animation: BellAnimation, /// Command to run on bell. pub command: Option<Program>, /// Visual bell flash color. pub color: Rgb, /// Visual bell duration in milliseconds. duration: u16, } impl Default for BellConfig { fn default() -> Self { Self { color: Rgb::new(255, 255, 255), animation: Default::default(), command: Default::default(), duration: Default::default(), } } } impl BellConfig { pub fn duration(&self) -> Duration { Duration::from_millis(self.duration as u64) } } /// `VisualBellAnimations` are modeled after a subset of CSS transitions and Robert /// Penner's Easing Functions. #[derive(ConfigDeserialize, Default, Clone, Copy, Debug, PartialEq, Eq)] pub enum BellAnimation { // CSS animation. Ease, // CSS animation. EaseOut, // Penner animation. EaseOutSine, // Penner animation. EaseOutQuad, // Penner animation. EaseOutCubic, // Penner animation. EaseOutQuart, // Penner animation. EaseOutQuint, // Penner animation. EaseOutExpo, // Penner animation. EaseOutCirc, // Penner animation. #[default] Linear, } �������������������������������alacritty-0.13.2/src/config/bindings.rs�������������������������������������������������������������0000644�0000000�0000000�00000165532�10461020230�0016116�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#![allow(clippy::enum_glob_use)] use std::fmt::{self, Debug, Display}; use bitflags::bitflags; use serde::de::{self, Error as SerdeError, MapAccess, Unexpected, Visitor}; use serde::{Deserialize, Deserializer}; use toml::Value as SerdeValue; use winit::event::MouseButton; use winit::keyboard::{ Key, KeyCode, KeyLocation as WinitKeyLocation, ModifiersState, NamedKey, PhysicalKey, }; use winit::platform::scancode::PhysicalKeyExtScancode; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use alacritty_terminal::term::TermMode; use alacritty_terminal::vi_mode::ViMotion; use crate::config::ui_config::{Hint, Program, StringVisitor}; /// Describes a state and action to take in that state. /// /// This is the shared component of `MouseBinding` and `KeyBinding`. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Binding<T> { /// Modifier keys required to activate binding. pub mods: ModifiersState, /// String to send to PTY if mods and mode match. pub action: Action, /// Binding mode required to activate binding. pub mode: BindingMode, /// Excluded binding modes where the binding won't be activated. pub notmode: BindingMode, /// This property is used as part of the trigger detection code. /// /// For example, this might be a key like "G", or a mouse button. pub trigger: T, } /// Bindings that are triggered by a keyboard key. pub type KeyBinding = Binding<BindingKey>; /// Bindings that are triggered by a mouse button. pub type MouseBinding = Binding<MouseButton>; impl<T: Eq> Binding<T> { #[inline] pub fn is_triggered_by(&self, mode: BindingMode, mods: ModifiersState, input: &T) -> bool { // Check input first since bindings are stored in one big list. This is // the most likely item to fail so prioritizing it here allows more // checks to be short circuited. self.trigger == *input && self.mods == mods && mode.contains(self.mode) && !mode.intersects(self.notmode) } #[inline] pub fn triggers_match(&self, binding: &Binding<T>) -> bool { // Check the binding's key and modifiers. if self.trigger != binding.trigger || self.mods != binding.mods { return false; } let selfmode = if self.mode.is_empty() { BindingMode::all() } else { self.mode }; let bindingmode = if binding.mode.is_empty() { BindingMode::all() } else { binding.mode }; if !selfmode.intersects(bindingmode) { return false; } // The bindings are never active at the same time when the required modes of one binding // are part of the forbidden bindings of the other. if self.mode.intersects(binding.notmode) || binding.mode.intersects(self.notmode) { return false; } true } } #[derive(ConfigDeserialize, Debug, Clone, PartialEq, Eq)] pub enum Action { /// Write an escape sequence. #[config(skip)] Esc(String), /// Run given command. #[config(skip)] Command(Program), /// Regex keyboard hints. #[config(skip)] Hint(Hint), /// Move vi mode cursor. #[config(skip)] ViMotion(ViMotion), /// Perform vi mode action. #[config(skip)] Vi(ViAction), /// Perform search mode action. #[config(skip)] Search(SearchAction), /// Perform mouse binding exclusive action. #[config(skip)] Mouse(MouseAction), /// Paste contents of system clipboard. Paste, /// Store current selection into clipboard. Copy, /// Store current selection into selection buffer. CopySelection, /// Paste contents of selection buffer. PasteSelection, /// Increase font size. IncreaseFontSize, /// Decrease font size. DecreaseFontSize, /// Reset font size to the config value. ResetFontSize, /// Scroll exactly one page up. ScrollPageUp, /// Scroll exactly one page down. ScrollPageDown, /// Scroll half a page up. ScrollHalfPageUp, /// Scroll half a page down. ScrollHalfPageDown, /// Scroll one line up. ScrollLineUp, /// Scroll one line down. ScrollLineDown, /// Scroll all the way to the top. ScrollToTop, /// Scroll all the way to the bottom. ScrollToBottom, /// Clear the display buffer(s) to remove history. ClearHistory, /// Hide the Alacritty window. Hide, /// Hide all windows other than Alacritty on macOS. HideOtherApplications, /// Minimize the Alacritty window. Minimize, /// Quit Alacritty. Quit, /// Clear warning and error notices. ClearLogNotice, /// Spawn a new instance of Alacritty. SpawnNewInstance, /// Select next tab. SelectNextTab, /// Select previous tab. SelectPreviousTab, /// Select the first tab. SelectTab1, /// Select the second tab. SelectTab2, /// Select the third tab. SelectTab3, /// Select the fourth tab. SelectTab4, /// Select the fifth tab. SelectTab5, /// Select the sixth tab. SelectTab6, /// Select the seventh tab. SelectTab7, /// Select the eighth tab. SelectTab8, /// Select the ninth tab. SelectTab9, /// Select the last tab. SelectLastTab, /// Create a new Alacritty window. CreateNewWindow, /// Create new window in a tab. CreateNewTab, /// Toggle fullscreen. ToggleFullscreen, /// Toggle maximized. ToggleMaximized, /// Toggle simple fullscreen on macOS. ToggleSimpleFullscreen, /// Clear active selection. ClearSelection, /// Toggle vi mode. ToggleViMode, /// Allow receiving char input. ReceiveChar, /// Start a forward buffer search. SearchForward, /// Start a backward buffer search. SearchBackward, /// No action. None, } impl From<&'static str> for Action { fn from(s: &'static str) -> Action { Action::Esc(s.into()) } } impl From<ViAction> for Action { fn from(action: ViAction) -> Self { Self::Vi(action) } } impl From<ViMotion> for Action { fn from(motion: ViMotion) -> Self { Self::ViMotion(motion) } } impl From<SearchAction> for Action { fn from(action: SearchAction) -> Self { Self::Search(action) } } impl From<MouseAction> for Action { fn from(action: MouseAction) -> Self { Self::Mouse(action) } } /// Display trait used for error logging. impl Display for Action { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Action::ViMotion(motion) => motion.fmt(f), Action::Vi(action) => action.fmt(f), Action::Mouse(action) => action.fmt(f), _ => write!(f, "{:?}", self), } } } /// Vi mode specific actions. #[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)] pub enum ViAction { /// Toggle normal vi selection. ToggleNormalSelection, /// Toggle line vi selection. ToggleLineSelection, /// Toggle block vi selection. ToggleBlockSelection, /// Toggle semantic vi selection. ToggleSemanticSelection, /// Jump to the beginning of the next match. SearchNext, /// Jump to the beginning of the previous match. SearchPrevious, /// Jump to the next start of a match to the left of the origin. SearchStart, /// Jump to the next end of a match to the right of the origin. SearchEnd, /// Launch the URL below the vi mode cursor. Open, /// Centers the screen around the vi mode cursor. CenterAroundViCursor, /// Search forward within the current line. InlineSearchForward, /// Search backward within the current line. InlineSearchBackward, /// Search forward within the current line, stopping just short of the character. InlineSearchForwardShort, /// Search backward within the current line, stopping just short of the character. InlineSearchBackwardShort, /// Jump to the next inline search match. InlineSearchNext, /// Jump to the previous inline search match. InlineSearchPrevious, } /// Search mode specific actions. #[allow(clippy::enum_variant_names)] #[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)] pub enum SearchAction { /// Move the focus to the next search match. SearchFocusNext, /// Move the focus to the previous search match. SearchFocusPrevious, /// Confirm the active search. SearchConfirm, /// Cancel the active search. SearchCancel, /// Reset the search regex. SearchClear, /// Delete the last word in the search regex. SearchDeleteWord, /// Go to the previous regex in the search history. SearchHistoryPrevious, /// Go to the next regex in the search history. SearchHistoryNext, } /// Mouse binding specific actions. #[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)] pub enum MouseAction { /// Expand the selection to the current mouse cursor position. ExpandSelection, } macro_rules! bindings { ( $ty:ident; $( $key:tt$(::$button:ident)? $(=>$location:expr)? $(,$mods:expr)* $(,+$mode:expr)* $(,~$notmode:expr)* ;$action:expr );* $(;)* ) => {{ let mut v = Vec::new(); $( let mut _mods = ModifiersState::empty(); $(_mods = $mods;)* let mut _mode = BindingMode::empty(); $(_mode.insert($mode);)* let mut _notmode = BindingMode::empty(); $(_notmode.insert($notmode);)* v.push($ty { trigger: trigger!($ty, $key$(::$button)?, $($location)?), mods: _mods, mode: _mode, notmode: _notmode, action: $action.into(), }); )* v }}; } macro_rules! trigger { (KeyBinding, $key:literal, $location:expr) => {{ BindingKey::Keycode { key: Key::Character($key.into()), location: $location } }}; (KeyBinding, $key:literal,) => {{ BindingKey::Keycode { key: Key::Character($key.into()), location: KeyLocation::Any } }}; (KeyBinding, $key:ident, $location:expr) => {{ BindingKey::Keycode { key: Key::Named(NamedKey::$key), location: $location } }}; (KeyBinding, $key:ident,) => {{ BindingKey::Keycode { key: Key::Named(NamedKey::$key), location: KeyLocation::Any } }}; (MouseBinding, $base:ident::$button:ident,) => {{ $base::$button }}; } pub fn default_mouse_bindings() -> Vec<MouseBinding> { bindings!( MouseBinding; MouseButton::Right; MouseAction::ExpandSelection; MouseButton::Right, ModifiersState::CONTROL; MouseAction::ExpandSelection; MouseButton::Middle, ~BindingMode::VI; Action::PasteSelection; ) } // NOTE: key sequences which are not present here, like F5-F20, PageUp/PageDown codes are // built on the fly in input/keyboard.rs. pub fn default_key_bindings() -> Vec<KeyBinding> { let mut bindings = bindings!( KeyBinding; Copy; Action::Copy; Copy, +BindingMode::VI; Action::ClearSelection; Paste, ~BindingMode::VI; Action::Paste; Paste, +BindingMode::VI, +BindingMode::SEARCH; Action::Paste; "l", ModifiersState::CONTROL; Action::ClearLogNotice; "l", ModifiersState::CONTROL; Action::ReceiveChar; Home, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollToTop; End, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollToBottom; PageUp, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollPageUp; PageDown, ModifiersState::SHIFT, ~BindingMode::ALT_SCREEN; Action::ScrollPageDown; // App cursor mode. Home, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOH".into()); End, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOF".into()); ArrowUp, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOA".into()); ArrowDown, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOB".into()); ArrowRight, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOC".into()); ArrowLeft, +BindingMode::APP_CURSOR, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1bOD".into()); // Legacy keys handling which can't be automatically encoded. F1, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC, ~BindingMode::DISAMBIGUATE_ESC_CODES; Action::Esc("\x1bOP".into()); F2, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC, ~BindingMode::DISAMBIGUATE_ESC_CODES; Action::Esc("\x1bOQ".into()); F3, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC, ~BindingMode::DISAMBIGUATE_ESC_CODES; Action::Esc("\x1bOR".into()); F4, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC, ~BindingMode::DISAMBIGUATE_ESC_CODES; Action::Esc("\x1bOS".into()); Tab, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC; Action::Esc("\x1b[Z".into()); Tab, ModifiersState::SHIFT | ModifiersState::ALT, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC; Action::Esc("\x1b\x1b[Z".into()); Backspace, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC; Action::Esc("\x7f".into()); Backspace, ModifiersState::ALT, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC; Action::Esc("\x1b\x7f".into()); Backspace, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC; Action::Esc("\x7f".into()); Enter => KeyLocation::Numpad, ~BindingMode::VI, ~BindingMode::SEARCH, ~BindingMode::REPORT_ALL_KEYS_AS_ESC, ~BindingMode::DISAMBIGUATE_ESC_CODES; Action::Esc("\n".into()); // Vi mode. Space, ModifiersState::SHIFT | ModifiersState::CONTROL, ~BindingMode::SEARCH; Action::ToggleViMode; Space, ModifiersState::SHIFT | ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollToBottom; Escape, +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection; "i", +BindingMode::VI, ~BindingMode::SEARCH; Action::ToggleViMode; "i", +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollToBottom; "c", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ToggleViMode; "y", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollLineUp; "e", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollLineDown; "g", +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollToTop; "g", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollToBottom; "b", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollPageUp; "f", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollPageDown; "u", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollHalfPageUp; "d", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; Action::ScrollHalfPageDown; "y", +BindingMode::VI, ~BindingMode::SEARCH; Action::Copy; "y", +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection; "/", +BindingMode::VI, ~BindingMode::SEARCH; Action::SearchForward; "?", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; Action::SearchBackward; "v", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::ToggleNormalSelection; "v", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::ToggleLineSelection; "v", ModifiersState::CONTROL, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::ToggleBlockSelection; "v", ModifiersState::ALT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::ToggleSemanticSelection; "n", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::SearchNext; "n", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::SearchPrevious; Enter, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::Open; "z", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::CenterAroundViCursor; "f", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchForward; "f", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchBackward; "t", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchForwardShort; "t", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchBackwardShort; ";", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchNext; ",", +BindingMode::VI, ~BindingMode::SEARCH; ViAction::InlineSearchPrevious; "k", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Up; "j", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Down; "h", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Left; "l", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Right; ArrowUp, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Up; ArrowDown, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Down; ArrowLeft, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Left; ArrowRight, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Right; "0", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::First; "$", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Last; Home, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::First; End, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Last; "^", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::FirstOccupied; "h", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::High; "m", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Middle; "l", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Low; "b", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::SemanticLeft; "w", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::SemanticRight; "e", +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::SemanticRightEnd; "b", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::WordLeft; "w", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::WordRight; "e", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::WordRightEnd; "%", ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; ViMotion::Bracket; Enter, +BindingMode::VI, +BindingMode::SEARCH; SearchAction::SearchConfirm; // Plain search. Escape, +BindingMode::SEARCH; SearchAction::SearchCancel; "c", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchCancel; "u", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchClear; "w", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchDeleteWord; "p", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchHistoryPrevious; "n", ModifiersState::CONTROL, +BindingMode::SEARCH; SearchAction::SearchHistoryNext; ArrowUp, +BindingMode::SEARCH; SearchAction::SearchHistoryPrevious; ArrowDown, +BindingMode::SEARCH; SearchAction::SearchHistoryNext; Enter, +BindingMode::SEARCH, ~BindingMode::VI; SearchAction::SearchFocusNext; Enter, ModifiersState::SHIFT, +BindingMode::SEARCH, ~BindingMode::VI; SearchAction::SearchFocusPrevious; ); bindings.extend(platform_key_bindings()); bindings } #[cfg(not(any(target_os = "macos", test)))] fn common_keybindings() -> Vec<KeyBinding> { bindings!( KeyBinding; "v", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::VI; Action::Paste; "v", ModifiersState::CONTROL | ModifiersState::SHIFT, +BindingMode::VI, +BindingMode::SEARCH; Action::Paste; "f", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::SEARCH; Action::SearchForward; "b", ModifiersState::CONTROL | ModifiersState::SHIFT, ~BindingMode::SEARCH; Action::SearchBackward; Insert, ModifiersState::SHIFT, ~BindingMode::VI; Action::PasteSelection; "c", ModifiersState::CONTROL | ModifiersState::SHIFT; Action::Copy; "c", ModifiersState::CONTROL | ModifiersState::SHIFT, +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection; "0", ModifiersState::CONTROL; Action::ResetFontSize; "=", ModifiersState::CONTROL; Action::IncreaseFontSize; "+", ModifiersState::CONTROL; Action::IncreaseFontSize; "-", ModifiersState::CONTROL; Action::DecreaseFontSize; "+" => KeyLocation::Numpad, ModifiersState::CONTROL; Action::IncreaseFontSize; "-" => KeyLocation::Numpad, ModifiersState::CONTROL; Action::DecreaseFontSize; ) } #[cfg(not(any(target_os = "macos", target_os = "windows", test)))] pub fn platform_key_bindings() -> Vec<KeyBinding> { common_keybindings() } #[cfg(all(target_os = "windows", not(test)))] pub fn platform_key_bindings() -> Vec<KeyBinding> { let mut bindings = bindings!( KeyBinding; Enter, ModifiersState::ALT; Action::ToggleFullscreen; ); bindings.extend(common_keybindings()); bindings } #[cfg(all(target_os = "macos", not(test)))] pub fn platform_key_bindings() -> Vec<KeyBinding> { bindings!( KeyBinding; Insert, ModifiersState::SHIFT, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x1b[2;2~".into()); // Tabbing api. "t", ModifiersState::SUPER; Action::CreateNewTab; "]", ModifiersState::SUPER | ModifiersState::SHIFT; Action::SelectNextTab; "[", ModifiersState::SUPER | ModifiersState::SHIFT; Action::SelectPreviousTab; Tab, ModifiersState::SUPER; Action::SelectNextTab; Tab, ModifiersState::SUPER | ModifiersState::SHIFT; Action::SelectPreviousTab; "1", ModifiersState::SUPER; Action::SelectTab1; "2", ModifiersState::SUPER; Action::SelectTab2; "3", ModifiersState::SUPER; Action::SelectTab3; "4", ModifiersState::SUPER; Action::SelectTab4; "5", ModifiersState::SUPER; Action::SelectTab5; "6", ModifiersState::SUPER; Action::SelectTab6; "7", ModifiersState::SUPER; Action::SelectTab7; "8", ModifiersState::SUPER; Action::SelectTab8; "9", ModifiersState::SUPER; Action::SelectLastTab; "0", ModifiersState::SUPER; Action::ResetFontSize; "=", ModifiersState::SUPER; Action::IncreaseFontSize; "+", ModifiersState::SUPER; Action::IncreaseFontSize; "-", ModifiersState::SUPER; Action::DecreaseFontSize; "k", ModifiersState::SUPER, ~BindingMode::VI, ~BindingMode::SEARCH; Action::Esc("\x0c".into()); "k", ModifiersState::SUPER, ~BindingMode::VI, ~BindingMode::SEARCH; Action::ClearHistory; "v", ModifiersState::SUPER, ~BindingMode::VI; Action::Paste; "v", ModifiersState::SUPER, +BindingMode::VI, +BindingMode::SEARCH; Action::Paste; "n", ModifiersState::SUPER; Action::CreateNewWindow; "f", ModifiersState::CONTROL | ModifiersState::SUPER; Action::ToggleFullscreen; "c", ModifiersState::SUPER; Action::Copy; "c", ModifiersState::SUPER, +BindingMode::VI, ~BindingMode::SEARCH; Action::ClearSelection; "h", ModifiersState::SUPER; Action::Hide; "h", ModifiersState::SUPER | ModifiersState::ALT; Action::HideOtherApplications; "m", ModifiersState::SUPER; Action::Minimize; "q", ModifiersState::SUPER; Action::Quit; "w", ModifiersState::SUPER; Action::Quit; "f", ModifiersState::SUPER, ~BindingMode::SEARCH; Action::SearchForward; "b", ModifiersState::SUPER, ~BindingMode::SEARCH; Action::SearchBackward; "+" => KeyLocation::Numpad, ModifiersState::SUPER; Action::IncreaseFontSize; "-" => KeyLocation::Numpad, ModifiersState::SUPER; Action::DecreaseFontSize; ) } // Don't return any bindings for tests since they are commented-out by default. #[cfg(test)] pub fn platform_key_bindings() -> Vec<KeyBinding> { vec![] } #[derive(Clone, Debug, PartialEq, Eq)] pub enum BindingKey { Scancode(PhysicalKey), Keycode { key: Key, location: KeyLocation }, } /// Key location for matching bindings. #[derive(Debug, Clone, Copy, Eq)] pub enum KeyLocation { /// The key is in its standard position. Standard, /// The key is on the numeric pad. Numpad, /// The key could be anywhere on the keyboard. Any, } impl From<WinitKeyLocation> for KeyLocation { fn from(value: WinitKeyLocation) -> Self { match value { WinitKeyLocation::Standard => KeyLocation::Standard, WinitKeyLocation::Left => KeyLocation::Any, WinitKeyLocation::Right => KeyLocation::Any, WinitKeyLocation::Numpad => KeyLocation::Numpad, } } } impl PartialEq for KeyLocation { fn eq(&self, other: &Self) -> bool { matches!( (self, other), (_, KeyLocation::Any) | (KeyLocation::Any, _) | (KeyLocation::Standard, KeyLocation::Standard) | (KeyLocation::Numpad, KeyLocation::Numpad) ) } } impl<'a> Deserialize<'a> for BindingKey { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'a>, { let value = SerdeValue::deserialize(deserializer)?; match u32::deserialize(value.clone()) { Ok(scancode) => Ok(BindingKey::Scancode(PhysicalKey::from_scancode(scancode))), Err(_) => { let keycode = String::deserialize(value.clone()).map_err(D::Error::custom)?; let (key, location) = if keycode.chars().count() == 1 { (Key::Character(keycode.to_lowercase().into()), KeyLocation::Any) } else { // Translate legacy winit codes into their modern counterparts. match keycode.as_str() { "Back" => (Key::Named(NamedKey::Backspace), KeyLocation::Any), "Up" => (Key::Named(NamedKey::ArrowUp), KeyLocation::Any), "Down" => (Key::Named(NamedKey::ArrowDown), KeyLocation::Any), "Left" => (Key::Named(NamedKey::ArrowLeft), KeyLocation::Any), "Right" => (Key::Named(NamedKey::ArrowRight), KeyLocation::Any), "At" => (Key::Character("@".into()), KeyLocation::Any), "Colon" => (Key::Character(":".into()), KeyLocation::Any), "Period" => (Key::Character(".".into()), KeyLocation::Any), "LBracket" => (Key::Character("[".into()), KeyLocation::Any), "RBracket" => (Key::Character("]".into()), KeyLocation::Any), "Semicolon" => (Key::Character(";".into()), KeyLocation::Any), "Backslash" => (Key::Character("\\".into()), KeyLocation::Any), // The keys which has alternative on numeric pad. "Enter" => (Key::Named(NamedKey::Enter), KeyLocation::Standard), "Return" => (Key::Named(NamedKey::Enter), KeyLocation::Standard), "Plus" => (Key::Character("+".into()), KeyLocation::Standard), "Comma" => (Key::Character(",".into()), KeyLocation::Standard), "Slash" => (Key::Character("/".into()), KeyLocation::Standard), "Equals" => (Key::Character("=".into()), KeyLocation::Standard), "Minus" => (Key::Character("-".into()), KeyLocation::Standard), "Asterisk" => (Key::Character("*".into()), KeyLocation::Standard), "Key1" => (Key::Character("1".into()), KeyLocation::Standard), "Key2" => (Key::Character("2".into()), KeyLocation::Standard), "Key3" => (Key::Character("3".into()), KeyLocation::Standard), "Key4" => (Key::Character("4".into()), KeyLocation::Standard), "Key5" => (Key::Character("5".into()), KeyLocation::Standard), "Key6" => (Key::Character("6".into()), KeyLocation::Standard), "Key7" => (Key::Character("7".into()), KeyLocation::Standard), "Key8" => (Key::Character("8".into()), KeyLocation::Standard), "Key9" => (Key::Character("9".into()), KeyLocation::Standard), "Key0" => (Key::Character("0".into()), KeyLocation::Standard), // Special case numpad. "NumpadEnter" => (Key::Named(NamedKey::Enter), KeyLocation::Numpad), "NumpadAdd" => (Key::Character("+".into()), KeyLocation::Numpad), "NumpadComma" => (Key::Character(",".into()), KeyLocation::Numpad), "NumpadDecimal" => (Key::Character(".".into()), KeyLocation::Numpad), "NumpadDivide" => (Key::Character("/".into()), KeyLocation::Numpad), "NumpadEquals" => (Key::Character("=".into()), KeyLocation::Numpad), "NumpadSubtract" => (Key::Character("-".into()), KeyLocation::Numpad), "NumpadMultiply" => (Key::Character("*".into()), KeyLocation::Numpad), "Numpad1" => (Key::Character("1".into()), KeyLocation::Numpad), "Numpad2" => (Key::Character("2".into()), KeyLocation::Numpad), "Numpad3" => (Key::Character("3".into()), KeyLocation::Numpad), "Numpad4" => (Key::Character("4".into()), KeyLocation::Numpad), "Numpad5" => (Key::Character("5".into()), KeyLocation::Numpad), "Numpad6" => (Key::Character("6".into()), KeyLocation::Numpad), "Numpad7" => (Key::Character("7".into()), KeyLocation::Numpad), "Numpad8" => (Key::Character("8".into()), KeyLocation::Numpad), "Numpad9" => (Key::Character("9".into()), KeyLocation::Numpad), "Numpad0" => (Key::Character("0".into()), KeyLocation::Numpad), _ if keycode.starts_with("Dead") => { (Key::deserialize(value).map_err(D::Error::custom)?, KeyLocation::Any) }, _ => ( Key::Named(NamedKey::deserialize(value).map_err(D::Error::custom)?), KeyLocation::Any, ), } }; Ok(BindingKey::Keycode { key, location }) }, } } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct ModeWrapper { pub mode: BindingMode, pub not_mode: BindingMode, } bitflags! { /// Modes available for key bindings. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct BindingMode: u8 { const APP_CURSOR = 0b0000_0001; const APP_KEYPAD = 0b0000_0010; const ALT_SCREEN = 0b0000_0100; const VI = 0b0000_1000; const SEARCH = 0b0001_0000; const DISAMBIGUATE_ESC_CODES = 0b0010_0000; const REPORT_ALL_KEYS_AS_ESC = 0b0100_0000; } } impl BindingMode { pub fn new(mode: &TermMode, search: bool) -> BindingMode { let mut binding_mode = BindingMode::empty(); binding_mode.set(BindingMode::APP_CURSOR, mode.contains(TermMode::APP_CURSOR)); binding_mode.set(BindingMode::APP_KEYPAD, mode.contains(TermMode::APP_KEYPAD)); binding_mode.set(BindingMode::ALT_SCREEN, mode.contains(TermMode::ALT_SCREEN)); binding_mode.set(BindingMode::VI, mode.contains(TermMode::VI)); binding_mode.set(BindingMode::SEARCH, search); binding_mode.set( BindingMode::DISAMBIGUATE_ESC_CODES, mode.contains(TermMode::DISAMBIGUATE_ESC_CODES), ); binding_mode.set( BindingMode::REPORT_ALL_KEYS_AS_ESC, mode.contains(TermMode::REPORT_ALL_KEYS_AS_ESC), ); binding_mode } } impl Default for ModeWrapper { fn default() -> Self { Self { mode: BindingMode::empty(), not_mode: BindingMode::empty() } } } impl<'a> Deserialize<'a> for ModeWrapper { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'a>, { struct ModeVisitor; impl<'a> Visitor<'a> for ModeVisitor { type Value = ModeWrapper; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str( "a combination of AppCursor | AppKeypad | Alt | Vi, possibly with negation (~)", ) } fn visit_str<E>(self, value: &str) -> Result<ModeWrapper, E> where E: de::Error, { let mut res = ModeWrapper { mode: BindingMode::empty(), not_mode: BindingMode::empty() }; for modifier in value.split('|') { match modifier.trim().to_lowercase().as_str() { "appcursor" => res.mode |= BindingMode::APP_CURSOR, "~appcursor" => res.not_mode |= BindingMode::APP_CURSOR, "appkeypad" => res.mode |= BindingMode::APP_KEYPAD, "~appkeypad" => res.not_mode |= BindingMode::APP_KEYPAD, "alt" => res.mode |= BindingMode::ALT_SCREEN, "~alt" => res.not_mode |= BindingMode::ALT_SCREEN, "vi" => res.mode |= BindingMode::VI, "~vi" => res.not_mode |= BindingMode::VI, "search" => res.mode |= BindingMode::SEARCH, "~search" => res.not_mode |= BindingMode::SEARCH, _ => return Err(E::invalid_value(Unexpected::Str(modifier), &self)), } } Ok(res) } } deserializer.deserialize_str(ModeVisitor) } } struct MouseButtonWrapper(MouseButton); impl MouseButtonWrapper { fn into_inner(self) -> MouseButton { self.0 } } impl<'a> Deserialize<'a> for MouseButtonWrapper { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'a>, { struct MouseButtonVisitor; impl<'a> Visitor<'a> for MouseButtonVisitor { type Value = MouseButtonWrapper; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Left, Right, Middle, Back, Forward, or a number from 0 to 65536") } fn visit_i64<E>(self, value: i64) -> Result<MouseButtonWrapper, E> where E: de::Error, { match value { 0..=65536 => Ok(MouseButtonWrapper(MouseButton::Other(value as u16))), _ => Err(E::invalid_value(Unexpected::Signed(value), &self)), } } fn visit_u64<E>(self, value: u64) -> Result<MouseButtonWrapper, E> where E: de::Error, { match value { 0..=65536 => Ok(MouseButtonWrapper(MouseButton::Other(value as u16))), _ => Err(E::invalid_value(Unexpected::Unsigned(value), &self)), } } fn visit_str<E>(self, value: &str) -> Result<MouseButtonWrapper, E> where E: de::Error, { match value { "Left" => Ok(MouseButtonWrapper(MouseButton::Left)), "Right" => Ok(MouseButtonWrapper(MouseButton::Right)), "Middle" => Ok(MouseButtonWrapper(MouseButton::Middle)), "Back" => Ok(MouseButtonWrapper(MouseButton::Back)), "Forward" => Ok(MouseButtonWrapper(MouseButton::Forward)), _ => Err(E::invalid_value(Unexpected::Str(value), &self)), } } } deserializer.deserialize_any(MouseButtonVisitor) } } /// Bindings are deserialized into a `RawBinding` before being parsed as a /// `KeyBinding` or `MouseBinding`. #[derive(PartialEq, Eq)] struct RawBinding { key: Option<BindingKey>, mouse: Option<MouseButton>, mods: ModifiersState, mode: BindingMode, notmode: BindingMode, action: Action, } impl RawBinding { fn into_mouse_binding(self) -> Result<MouseBinding, Box<Self>> { if let Some(mouse) = self.mouse { Ok(Binding { trigger: mouse, mods: self.mods, action: self.action, mode: self.mode, notmode: self.notmode, }) } else { Err(Box::new(self)) } } fn into_key_binding(self) -> Result<KeyBinding, Box<Self>> { if let Some(key) = self.key { Ok(KeyBinding { trigger: key, mods: self.mods, action: self.action, mode: self.mode, notmode: self.notmode, }) } else { Err(Box::new(self)) } } } impl<'a> Deserialize<'a> for RawBinding { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'a>, { const FIELDS: &[&str] = &["key", "mods", "mode", "action", "chars", "mouse", "command"]; enum Field { Key, Mods, Mode, Action, Chars, Mouse, Command, } impl<'a> Deserialize<'a> for Field { fn deserialize<D>(deserializer: D) -> Result<Field, D::Error> where D: Deserializer<'a>, { struct FieldVisitor; impl<'a> Visitor<'a> for FieldVisitor { type Value = Field; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("binding fields") } fn visit_str<E>(self, value: &str) -> Result<Field, E> where E: de::Error, { match value.to_ascii_lowercase().as_str() { "key" => Ok(Field::Key), "mods" => Ok(Field::Mods), "mode" => Ok(Field::Mode), "action" => Ok(Field::Action), "chars" => Ok(Field::Chars), "mouse" => Ok(Field::Mouse), "command" => Ok(Field::Command), _ => Err(E::unknown_field(value, FIELDS)), } } } deserializer.deserialize_str(FieldVisitor) } } struct RawBindingVisitor; impl<'a> Visitor<'a> for RawBindingVisitor { type Value = RawBinding; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("binding specification") } fn visit_map<V>(self, mut map: V) -> Result<RawBinding, V::Error> where V: MapAccess<'a>, { let mut mods: Option<ModifiersState> = None; let mut key: Option<BindingKey> = None; let mut chars: Option<String> = None; let mut action: Option<Action> = None; let mut mode: Option<BindingMode> = None; let mut not_mode: Option<BindingMode> = None; let mut mouse: Option<MouseButton> = None; let mut command: Option<Program> = None; use de::Error; while let Some(struct_key) = map.next_key::<Field>()? { match struct_key { Field::Key => { if key.is_some() { return Err(<V::Error as Error>::duplicate_field("key")); } let value = map.next_value::<SerdeValue>()?; match value.as_integer() { Some(scancode) => match u32::try_from(scancode) { Ok(scancode) => { key = Some(BindingKey::Scancode(KeyCode::from_scancode( scancode, ))) }, Err(_) => { return Err(<V::Error as Error>::custom(format!( "Invalid key binding, scancode is too big: {}", scancode ))); }, }, None => { key = Some( BindingKey::deserialize(value).map_err(V::Error::custom)?, ) }, } }, Field::Mods => { if mods.is_some() { return Err(<V::Error as Error>::duplicate_field("mods")); } mods = Some(map.next_value::<ModsWrapper>()?.into_inner()); }, Field::Mode => { if mode.is_some() { return Err(<V::Error as Error>::duplicate_field("mode")); } let mode_deserializer = map.next_value::<ModeWrapper>()?; mode = Some(mode_deserializer.mode); not_mode = Some(mode_deserializer.not_mode); }, Field::Action => { if action.is_some() { return Err(<V::Error as Error>::duplicate_field("action")); } let value = map.next_value::<SerdeValue>()?; action = if let Ok(vi_action) = ViAction::deserialize(value.clone()) { Some(vi_action.into()) } else if let Ok(vi_motion) = SerdeViMotion::deserialize(value.clone()) { Some(vi_motion.0.into()) } else if let Ok(search_action) = SearchAction::deserialize(value.clone()) { Some(search_action.into()) } else if let Ok(mouse_action) = MouseAction::deserialize(value.clone()) { Some(mouse_action.into()) } else { match Action::deserialize(value.clone()).map_err(V::Error::custom) { Ok(action) => Some(action), Err(err) => { let value = match value { SerdeValue::String(string) => string, _ => return Err(err), }; return Err(V::Error::custom(format!( "unknown keyboard action `{}`", value ))); }, } }; }, Field::Chars => { if chars.is_some() { return Err(<V::Error as Error>::duplicate_field("chars")); } chars = Some(map.next_value()?); }, Field::Mouse => { if mouse.is_some() { return Err(<V::Error as Error>::duplicate_field("mouse")); } mouse = Some(map.next_value::<MouseButtonWrapper>()?.into_inner()); }, Field::Command => { if command.is_some() { return Err(<V::Error as Error>::duplicate_field("command")); } command = Some(map.next_value::<Program>()?); }, } } let mode = mode.unwrap_or_else(BindingMode::empty); let not_mode = not_mode.unwrap_or_else(BindingMode::empty); let mods = mods.unwrap_or_default(); let action = match (action, chars, command) { (Some(action @ Action::ViMotion(_)), None, None) | (Some(action @ Action::Vi(_)), None, None) => action, (Some(action @ Action::Search(_)), None, None) => action, (Some(action @ Action::Mouse(_)), None, None) => { if mouse.is_none() { return Err(V::Error::custom(format!( "action `{}` is only available for mouse bindings", action, ))); } action }, (Some(action), None, None) => action, (None, Some(chars), None) => Action::Esc(chars), (None, None, Some(cmd)) => Action::Command(cmd), _ => { return Err(V::Error::custom( "must specify exactly one of chars, action or command", )); }, }; if mouse.is_none() && key.is_none() { return Err(V::Error::custom("bindings require mouse button or key")); } Ok(RawBinding { mode, notmode: not_mode, action, key, mouse, mods }) } } deserializer.deserialize_struct("RawBinding", FIELDS, RawBindingVisitor) } } impl<'a> Deserialize<'a> for MouseBinding { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'a>, { let raw = RawBinding::deserialize(deserializer)?; raw.into_mouse_binding() .map_err(|_| D::Error::custom("expected mouse binding, got key binding")) } } impl<'a> Deserialize<'a> for KeyBinding { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'a>, { let raw = RawBinding::deserialize(deserializer)?; raw.into_key_binding() .map_err(|_| D::Error::custom("expected key binding, got mouse binding")) } } #[derive(SerdeReplace, Debug, Copy, Clone, Eq, PartialEq)] pub struct SerdeViMotion(ViMotion); impl<'de> Deserialize<'de> for SerdeViMotion { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let value = deserializer.deserialize_str(StringVisitor)?; ViMotion::deserialize(SerdeValue::String(value)) .map(SerdeViMotion) .map_err(de::Error::custom) } } /// Newtype for implementing deserialize on winit Mods. /// /// Our deserialize impl wouldn't be covered by a derive(Deserialize); see the /// impl below. #[derive(SerdeReplace, Debug, Copy, Clone, Hash, Default, Eq, PartialEq)] pub struct ModsWrapper(pub ModifiersState); impl ModsWrapper { pub fn into_inner(self) -> ModifiersState { self.0 } } impl<'a> de::Deserialize<'a> for ModsWrapper { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: de::Deserializer<'a>, { struct ModsVisitor; impl<'a> Visitor<'a> for ModsVisitor { type Value = ModsWrapper; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("None or a subset of Shift|Control|Super|Command|Alt|Option") } fn visit_str<E>(self, value: &str) -> Result<ModsWrapper, E> where E: de::Error, { let mut res = ModifiersState::empty(); for modifier in value.split('|') { match modifier.trim().to_lowercase().as_str() { "command" | "super" => res.insert(ModifiersState::SUPER), "shift" => res.insert(ModifiersState::SHIFT), "alt" | "option" => res.insert(ModifiersState::ALT), "control" => res.insert(ModifiersState::CONTROL), "none" => (), _ => return Err(E::invalid_value(Unexpected::Str(modifier), &self)), } } Ok(ModsWrapper(res)) } } deserializer.deserialize_str(ModsVisitor) } } #[cfg(test)] mod tests { use super::*; use winit::keyboard::ModifiersState; type MockBinding = Binding<usize>; impl Default for MockBinding { fn default() -> Self { Self { mods: Default::default(), action: Action::None, mode: BindingMode::empty(), notmode: BindingMode::empty(), trigger: Default::default(), } } } #[test] fn binding_matches_itself() { let binding = MockBinding::default(); let identical_binding = MockBinding::default(); assert!(binding.triggers_match(&identical_binding)); assert!(identical_binding.triggers_match(&binding)); } #[test] fn binding_matches_different_action() { let binding = MockBinding::default(); let different_action = MockBinding { action: Action::ClearHistory, ..MockBinding::default() }; assert!(binding.triggers_match(&different_action)); assert!(different_action.triggers_match(&binding)); } #[test] fn mods_binding_requires_strict_match() { let superset_mods = MockBinding { mods: ModifiersState::all(), ..MockBinding::default() }; let subset_mods = MockBinding { mods: ModifiersState::ALT, ..MockBinding::default() }; assert!(!superset_mods.triggers_match(&subset_mods)); assert!(!subset_mods.triggers_match(&superset_mods)); } #[test] fn binding_matches_identical_mode() { let b1 = MockBinding { mode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; let b2 = MockBinding { mode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; assert!(b1.triggers_match(&b2)); assert!(b2.triggers_match(&b1)); } #[test] fn binding_without_mode_matches_any_mode() { let b1 = MockBinding::default(); let b2 = MockBinding { mode: BindingMode::APP_KEYPAD, notmode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; assert!(b1.triggers_match(&b2)); } #[test] fn binding_with_mode_matches_empty_mode() { let b1 = MockBinding { mode: BindingMode::APP_KEYPAD, notmode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; let b2 = MockBinding::default(); assert!(b1.triggers_match(&b2)); assert!(b2.triggers_match(&b1)); } #[test] fn binding_matches_modes() { let b1 = MockBinding { mode: BindingMode::ALT_SCREEN | BindingMode::APP_KEYPAD, ..MockBinding::default() }; let b2 = MockBinding { mode: BindingMode::APP_KEYPAD, ..MockBinding::default() }; assert!(b1.triggers_match(&b2)); assert!(b2.triggers_match(&b1)); } #[test] fn binding_matches_partial_intersection() { let b1 = MockBinding { mode: BindingMode::ALT_SCREEN | BindingMode::APP_KEYPAD, ..MockBinding::default() }; let b2 = MockBinding { mode: BindingMode::APP_KEYPAD | BindingMode::APP_CURSOR, ..MockBinding::default() }; assert!(b1.triggers_match(&b2)); assert!(b2.triggers_match(&b1)); } #[test] fn binding_mismatches_notmode() { let b1 = MockBinding { mode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; let b2 = MockBinding { notmode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; assert!(!b1.triggers_match(&b2)); assert!(!b2.triggers_match(&b1)); } #[test] fn binding_mismatches_unrelated() { let b1 = MockBinding { mode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; let b2 = MockBinding { mode: BindingMode::APP_KEYPAD, ..MockBinding::default() }; assert!(!b1.triggers_match(&b2)); assert!(!b2.triggers_match(&b1)); } #[test] fn binding_matches_notmodes() { let subset_notmodes = MockBinding { notmode: BindingMode::VI | BindingMode::APP_CURSOR, ..MockBinding::default() }; let superset_notmodes = MockBinding { notmode: BindingMode::APP_CURSOR, ..MockBinding::default() }; assert!(subset_notmodes.triggers_match(&superset_notmodes)); assert!(superset_notmodes.triggers_match(&subset_notmodes)); } #[test] fn binding_matches_mode_notmode() { let b1 = MockBinding { mode: BindingMode::VI, notmode: BindingMode::APP_CURSOR, ..MockBinding::default() }; let b2 = MockBinding { notmode: BindingMode::APP_CURSOR, ..MockBinding::default() }; assert!(b1.triggers_match(&b2)); assert!(b2.triggers_match(&b1)); } #[test] fn binding_trigger_input() { let binding = MockBinding { trigger: 13, ..MockBinding::default() }; let mods = binding.mods; let mode = binding.mode; assert!(binding.is_triggered_by(mode, mods, &13)); assert!(!binding.is_triggered_by(mode, mods, &32)); } #[test] fn binding_trigger_mods() { let binding = MockBinding { mods: ModifiersState::ALT | ModifiersState::SUPER, ..MockBinding::default() }; let superset_mods = ModifiersState::all(); let subset_mods = ModifiersState::empty(); let t = binding.trigger; let mode = binding.mode; assert!(binding.is_triggered_by(mode, binding.mods, &t)); assert!(!binding.is_triggered_by(mode, superset_mods, &t)); assert!(!binding.is_triggered_by(mode, subset_mods, &t)); } #[test] fn binding_trigger_modes() { let binding = MockBinding { mode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; let t = binding.trigger; let mods = binding.mods; assert!(!binding.is_triggered_by(BindingMode::VI, mods, &t)); assert!(binding.is_triggered_by(BindingMode::ALT_SCREEN, mods, &t)); assert!(binding.is_triggered_by(BindingMode::ALT_SCREEN | BindingMode::VI, mods, &t)); } #[test] fn binding_trigger_notmodes() { let binding = MockBinding { notmode: BindingMode::ALT_SCREEN, ..MockBinding::default() }; let t = binding.trigger; let mods = binding.mods; assert!(binding.is_triggered_by(BindingMode::VI, mods, &t)); assert!(!binding.is_triggered_by(BindingMode::ALT_SCREEN, mods, &t)); assert!(!binding.is_triggered_by(BindingMode::ALT_SCREEN | BindingMode::VI, mods, &t)); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/color.rs����������������������������������������������������������������0000644�0000000�0000000�00000016400�10461020230�0015424�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use serde::de::Error as SerdeError; use serde::{Deserialize, Deserializer}; use alacritty_config_derive::ConfigDeserialize; use crate::display::color::{CellRgb, Rgb}; #[derive(ConfigDeserialize, Clone, Debug, Default, PartialEq, Eq)] pub struct Colors { pub primary: PrimaryColors, pub cursor: InvertedCellColors, pub vi_mode_cursor: InvertedCellColors, pub selection: InvertedCellColors, pub normal: NormalColors, pub bright: BrightColors, pub dim: Option<DimColors>, pub indexed_colors: Vec<IndexedColor>, pub search: SearchColors, pub line_indicator: LineIndicatorColors, pub hints: HintColors, pub transparent_background_colors: bool, pub draw_bold_text_with_bright_colors: bool, footer_bar: BarColors, } impl Colors { pub fn footer_bar_foreground(&self) -> Rgb { self.footer_bar.foreground.unwrap_or(self.primary.background) } pub fn footer_bar_background(&self) -> Rgb { self.footer_bar.background.unwrap_or(self.primary.foreground) } } #[derive(ConfigDeserialize, Copy, Clone, Default, Debug, PartialEq, Eq)] pub struct LineIndicatorColors { pub foreground: Option<Rgb>, pub background: Option<Rgb>, } #[derive(ConfigDeserialize, Default, Copy, Clone, Debug, PartialEq, Eq)] pub struct HintColors { pub start: HintStartColors, pub end: HintEndColors, } #[derive(ConfigDeserialize, Copy, Clone, Debug, PartialEq, Eq)] pub struct HintStartColors { pub foreground: CellRgb, pub background: CellRgb, } impl Default for HintStartColors { fn default() -> Self { Self { foreground: CellRgb::Rgb(Rgb::new(0x18, 0x18, 0x18)), background: CellRgb::Rgb(Rgb::new(0xf4, 0xbf, 0x75)), } } } #[derive(ConfigDeserialize, Copy, Clone, Debug, PartialEq, Eq)] pub struct HintEndColors { pub foreground: CellRgb, pub background: CellRgb, } impl Default for HintEndColors { fn default() -> Self { Self { foreground: CellRgb::Rgb(Rgb::new(0x18, 0x18, 0x18)), background: CellRgb::Rgb(Rgb::new(0xac, 0x42, 0x42)), } } } #[derive(Deserialize, Copy, Clone, Default, Debug, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct IndexedColor { pub color: Rgb, index: ColorIndex, } impl IndexedColor { #[inline] pub fn index(&self) -> u8 { self.index.0 } } #[derive(Copy, Clone, Default, Debug, PartialEq, Eq)] struct ColorIndex(u8); impl<'de> Deserialize<'de> for ColorIndex { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let index = u8::deserialize(deserializer)?; if index < 16 { Err(SerdeError::custom( "Config error: indexed_color's index is {}, but a value bigger than 15 was \ expected; ignoring setting", )) } else { Ok(Self(index)) } } } #[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)] pub struct InvertedCellColors { #[config(alias = "text")] pub foreground: CellRgb, #[config(alias = "cursor")] pub background: CellRgb, } impl Default for InvertedCellColors { fn default() -> Self { Self { foreground: CellRgb::CellBackground, background: CellRgb::CellForeground } } } #[derive(ConfigDeserialize, Debug, Copy, Clone, Default, PartialEq, Eq)] pub struct SearchColors { pub focused_match: FocusedMatchColors, pub matches: MatchColors, } #[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)] pub struct FocusedMatchColors { pub foreground: CellRgb, pub background: CellRgb, } impl Default for FocusedMatchColors { fn default() -> Self { Self { background: CellRgb::Rgb(Rgb::new(0xf4, 0xbf, 0x75)), foreground: CellRgb::Rgb(Rgb::new(0x18, 0x18, 0x18)), } } } #[derive(ConfigDeserialize, Debug, Copy, Clone, PartialEq, Eq)] pub struct MatchColors { pub foreground: CellRgb, pub background: CellRgb, } impl Default for MatchColors { fn default() -> Self { Self { background: CellRgb::Rgb(Rgb::new(0xac, 0x42, 0x42)), foreground: CellRgb::Rgb(Rgb::new(0x18, 0x18, 0x18)), } } } #[derive(ConfigDeserialize, Debug, Copy, Clone, Default, PartialEq, Eq)] pub struct BarColors { foreground: Option<Rgb>, background: Option<Rgb>, } #[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)] pub struct PrimaryColors { pub foreground: Rgb, pub background: Rgb, pub bright_foreground: Option<Rgb>, pub dim_foreground: Option<Rgb>, } impl Default for PrimaryColors { fn default() -> Self { PrimaryColors { background: Rgb::new(0x18, 0x18, 0x18), foreground: Rgb::new(0xd8, 0xd8, 0xd8), bright_foreground: Default::default(), dim_foreground: Default::default(), } } } #[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)] pub struct NormalColors { pub black: Rgb, pub red: Rgb, pub green: Rgb, pub yellow: Rgb, pub blue: Rgb, pub magenta: Rgb, pub cyan: Rgb, pub white: Rgb, } impl Default for NormalColors { fn default() -> Self { NormalColors { black: Rgb::new(0x18, 0x18, 0x18), red: Rgb::new(0xac, 0x42, 0x42), green: Rgb::new(0x90, 0xa9, 0x59), yellow: Rgb::new(0xf4, 0xbf, 0x75), blue: Rgb::new(0x6a, 0x9f, 0xb5), magenta: Rgb::new(0xaa, 0x75, 0x9f), cyan: Rgb::new(0x75, 0xb5, 0xaa), white: Rgb::new(0xd8, 0xd8, 0xd8), } } } #[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)] pub struct BrightColors { pub black: Rgb, pub red: Rgb, pub green: Rgb, pub yellow: Rgb, pub blue: Rgb, pub magenta: Rgb, pub cyan: Rgb, pub white: Rgb, } impl Default for BrightColors { fn default() -> Self { // Generated with oklab by multiplying brightness by 1.12 and then adjusting numbers // to make them look "nicer". Yellow color was generated the same way, however the first // srgb representable color was picked. BrightColors { black: Rgb::new(0x6b, 0x6b, 0x6b), red: Rgb::new(0xc5, 0x55, 0x55), green: Rgb::new(0xaa, 0xc4, 0x74), yellow: Rgb::new(0xfe, 0xca, 0x88), blue: Rgb::new(0x82, 0xb8, 0xc8), magenta: Rgb::new(0xc2, 0x8c, 0xb8), cyan: Rgb::new(0x93, 0xd3, 0xc3), white: Rgb::new(0xf8, 0xf8, 0xf8), } } } #[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)] pub struct DimColors { pub black: Rgb, pub red: Rgb, pub green: Rgb, pub yellow: Rgb, pub blue: Rgb, pub magenta: Rgb, pub cyan: Rgb, pub white: Rgb, } impl Default for DimColors { fn default() -> Self { // Generated with builtin alacritty's color dimming function. DimColors { black: Rgb::new(0x0f, 0x0f, 0x0f), red: Rgb::new(0x71, 0x2b, 0x2b), green: Rgb::new(0x5f, 0x6f, 0x3a), yellow: Rgb::new(0xa1, 0x7e, 0x4d), blue: Rgb::new(0x45, 0x68, 0x77), magenta: Rgb::new(0x70, 0x4d, 0x68), cyan: Rgb::new(0x4d, 0x77, 0x70), white: Rgb::new(0x8e, 0x8e, 0x8e), } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/cursor.rs���������������������������������������������������������������0000644�0000000�0000000�00000007733�10461020230�0015634�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::cmp; use std::time::Duration; use serde::Deserialize; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use alacritty_terminal::vte::ansi::{CursorShape as VteCursorShape, CursorStyle as VteCursorStyle}; use crate::config::ui_config::Percentage; /// The minimum blink interval value in milliseconds. const MIN_BLINK_INTERVAL: u64 = 10; /// The minimum number of blinks before pausing. const MIN_BLINK_CYCLES_BEFORE_PAUSE: u64 = 1; #[derive(ConfigDeserialize, Copy, Clone, Debug, PartialEq)] pub struct Cursor { pub style: ConfigCursorStyle, pub vi_mode_style: Option<ConfigCursorStyle>, pub unfocused_hollow: bool, thickness: Percentage, blink_interval: u64, blink_timeout: u8, } impl Default for Cursor { fn default() -> Self { Self { thickness: Percentage::new(0.15), unfocused_hollow: true, blink_interval: 750, blink_timeout: 5, style: Default::default(), vi_mode_style: Default::default(), } } } impl Cursor { #[inline] pub fn thickness(self) -> f32 { self.thickness.as_f32() } #[inline] pub fn style(self) -> VteCursorStyle { self.style.into() } #[inline] pub fn vi_mode_style(self) -> Option<VteCursorStyle> { self.vi_mode_style.map(Into::into) } #[inline] pub fn blink_interval(self) -> u64 { cmp::max(self.blink_interval, MIN_BLINK_INTERVAL) } #[inline] pub fn blink_timeout(self) -> Duration { if self.blink_timeout == 0 { Duration::ZERO } else { cmp::max( // Show/hide is what we consider a cycle, so multiply by `2`. Duration::from_millis(self.blink_interval * 2 * MIN_BLINK_CYCLES_BEFORE_PAUSE), Duration::from_secs(self.blink_timeout as u64), ) } } } #[derive(SerdeReplace, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] #[serde(untagged, deny_unknown_fields)] pub enum ConfigCursorStyle { Shape(CursorShape), WithBlinking { #[serde(default)] shape: CursorShape, #[serde(default)] blinking: CursorBlinking, }, } impl Default for ConfigCursorStyle { fn default() -> Self { Self::Shape(CursorShape::default()) } } impl ConfigCursorStyle { /// Check if blinking is force enabled/disabled. pub fn blinking_override(&self) -> Option<bool> { match self { Self::Shape(_) => None, Self::WithBlinking { blinking, .. } => blinking.blinking_override(), } } } impl From<ConfigCursorStyle> for VteCursorStyle { fn from(config_style: ConfigCursorStyle) -> Self { match config_style { ConfigCursorStyle::Shape(shape) => Self { shape: shape.into(), blinking: false }, ConfigCursorStyle::WithBlinking { shape, blinking } => { Self { shape: shape.into(), blinking: blinking.into() } }, } } } #[derive(ConfigDeserialize, Default, Debug, Copy, Clone, PartialEq, Eq)] pub enum CursorBlinking { Never, #[default] Off, On, Always, } impl CursorBlinking { fn blinking_override(&self) -> Option<bool> { match self { Self::Never => Some(false), Self::Off | Self::On => None, Self::Always => Some(true), } } } impl From<CursorBlinking> for bool { fn from(blinking: CursorBlinking) -> bool { blinking == CursorBlinking::On || blinking == CursorBlinking::Always } } #[derive(ConfigDeserialize, Debug, Default, Eq, PartialEq, Copy, Clone, Hash)] pub enum CursorShape { #[default] Block, Underline, Beam, } impl From<CursorShape> for VteCursorShape { fn from(value: CursorShape) -> Self { match value { CursorShape::Block => VteCursorShape::Block, CursorShape::Underline => VteCursorShape::Underline, CursorShape::Beam => VteCursorShape::Beam, } } } �������������������������������������alacritty-0.13.2/src/config/debug.rs����������������������������������������������������������������0000644�0000000�0000000�00000002770�10461020230�0015401�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use log::LevelFilter; use alacritty_config_derive::ConfigDeserialize; /// Debugging options. #[derive(ConfigDeserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct Debug { pub log_level: LevelFilter, pub print_events: bool, /// Keep the log file after quitting. pub persistent_logging: bool, /// Should show render timer. pub render_timer: bool, /// Highlight damage information produced by alacritty. pub highlight_damage: bool, /// The renderer alacritty should be using. pub renderer: Option<RendererPreference>, /// Use EGL as display API if the current platform allows it. pub prefer_egl: bool, /// Record ref test. #[config(skip)] pub ref_test: bool, } impl Default for Debug { fn default() -> Self { Self { log_level: LevelFilter::Warn, print_events: Default::default(), persistent_logging: Default::default(), render_timer: Default::default(), highlight_damage: Default::default(), ref_test: Default::default(), renderer: Default::default(), prefer_egl: Default::default(), } } } /// The renderer configuration options. #[derive(ConfigDeserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum RendererPreference { /// OpenGL 3.3 renderer. Glsl3, /// GLES 2 renderer, with optional extensions like dual source blending. Gles2, /// Pure GLES 2 renderer. Gles2Pure, } ��������alacritty-0.13.2/src/config/font.rs�����������������������������������������������������������������0000644�0000000�0000000�00000010544�10461020230�0015257�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::fmt; use crossfont::Size as FontSize; use serde::de::{self, Visitor}; use serde::{Deserialize, Deserializer}; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use crate::config::ui_config::Delta; /// Font config. /// /// Defaults are provided at the level of this struct per platform, but not per /// field in this struct. It might be nice in the future to have defaults for /// each value independently. Alternatively, maybe erroring when the user /// doesn't provide complete config is Ok. #[derive(ConfigDeserialize, Debug, Clone, PartialEq, Eq)] pub struct Font { /// Extra spacing per character. pub offset: Delta<i8>, /// Glyph offset within character cell. pub glyph_offset: Delta<i8>, #[config(removed = "set the AppleFontSmoothing user default instead")] pub use_thin_strokes: bool, /// Normal font face. normal: FontDescription, /// Bold font face. bold: SecondaryFontDescription, /// Italic font face. italic: SecondaryFontDescription, /// Bold italic font face. bold_italic: SecondaryFontDescription, /// Font size in points. size: Size, /// Whether to use the built-in font for box drawing characters. pub builtin_box_drawing: bool, } impl Font { /// Get a font clone with a size modification. pub fn with_size(self, size: FontSize) -> Font { Font { size: Size(size), ..self } } #[inline] pub fn size(&self) -> FontSize { self.size.0 } /// Get normal font description. pub fn normal(&self) -> &FontDescription { &self.normal } /// Get bold font description. pub fn bold(&self) -> FontDescription { self.bold.desc(&self.normal) } /// Get italic font description. pub fn italic(&self) -> FontDescription { self.italic.desc(&self.normal) } /// Get bold italic font description. pub fn bold_italic(&self) -> FontDescription { self.bold_italic.desc(&self.normal) } } impl Default for Font { fn default() -> Font { Self { builtin_box_drawing: true, glyph_offset: Default::default(), use_thin_strokes: Default::default(), bold_italic: Default::default(), italic: Default::default(), offset: Default::default(), normal: Default::default(), bold: Default::default(), size: Default::default(), } } } /// Description of the normal font. #[derive(ConfigDeserialize, Debug, Clone, PartialEq, Eq)] pub struct FontDescription { pub family: String, pub style: Option<String>, } impl Default for FontDescription { fn default() -> FontDescription { FontDescription { #[cfg(not(any(target_os = "macos", windows)))] family: "monospace".into(), #[cfg(target_os = "macos")] family: "Menlo".into(), #[cfg(windows)] family: "Consolas".into(), style: None, } } } /// Description of the italic and bold font. #[derive(ConfigDeserialize, Debug, Default, Clone, PartialEq, Eq)] pub struct SecondaryFontDescription { family: Option<String>, style: Option<String>, } impl SecondaryFontDescription { pub fn desc(&self, fallback: &FontDescription) -> FontDescription { FontDescription { family: self.family.clone().unwrap_or_else(|| fallback.family.clone()), style: self.style.clone(), } } } #[derive(SerdeReplace, Debug, Clone, PartialEq, Eq)] struct Size(FontSize); impl Default for Size { fn default() -> Self { Self(FontSize::new(11.25)) } } impl<'de> Deserialize<'de> for Size { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { struct NumVisitor; impl<'v> Visitor<'v> for NumVisitor { type Value = Size; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("f64 or i64") } fn visit_f64<E: de::Error>(self, value: f64) -> Result<Self::Value, E> { Ok(Size(FontSize::new(value as f32))) } fn visit_i64<E: de::Error>(self, value: i64) -> Result<Self::Value, E> { Ok(Size(FontSize::new(value as f32))) } } deserializer.deserialize_any(NumVisitor) } } ������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/mod.rs������������������������������������������������������������������0000644�0000000�0000000�00000031323�10461020230�0015066�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::fmt::{self, Display, Formatter}; use std::path::{Path, PathBuf}; use std::result::Result as StdResult; use std::{env, fs, io}; use log::{debug, error, info, warn}; use serde::Deserialize; use serde_yaml::Error as YamlError; use toml::de::Error as TomlError; use toml::ser::Error as TomlSeError; use toml::{Table, Value}; pub mod bell; pub mod color; pub mod cursor; pub mod debug; pub mod font; pub mod monitor; pub mod scrolling; pub mod selection; pub mod serde_utils; pub mod terminal; pub mod ui_config; pub mod window; mod bindings; mod mouse; use crate::cli::Options; #[cfg(test)] pub use crate::config::bindings::Binding; pub use crate::config::bindings::{ Action, BindingKey, BindingMode, MouseAction, SearchAction, ViAction, }; pub use crate::config::ui_config::UiConfig; use crate::logging::LOG_TARGET_CONFIG; /// Maximum number of depth for the configuration file imports. pub const IMPORT_RECURSION_LIMIT: usize = 5; /// Result from config loading. pub type Result<T> = std::result::Result<T, Error>; /// Errors occurring during config loading. #[derive(Debug)] pub enum Error { /// Config file not found. NotFound, /// Couldn't read $HOME environment variable. ReadingEnvHome(env::VarError), /// io error reading file. Io(io::Error), /// Invalid toml. Toml(TomlError), /// Failed toml serialization. TomlSe(TomlSeError), /// Invalid yaml. Yaml(YamlError), } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Error::NotFound => None, Error::ReadingEnvHome(err) => err.source(), Error::Io(err) => err.source(), Error::Toml(err) => err.source(), Error::TomlSe(err) => err.source(), Error::Yaml(err) => err.source(), } } } impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Error::NotFound => write!(f, "Unable to locate config file"), Error::ReadingEnvHome(err) => { write!(f, "Unable to read $HOME environment variable: {}", err) }, Error::Io(err) => write!(f, "Error reading config file: {}", err), Error::Toml(err) => write!(f, "Config error: {}", err), Error::TomlSe(err) => write!(f, "Yaml conversion error: {}", err), Error::Yaml(err) => write!(f, "Config error: {}", err), } } } impl From<env::VarError> for Error { fn from(val: env::VarError) -> Self { Error::ReadingEnvHome(val) } } impl From<io::Error> for Error { fn from(val: io::Error) -> Self { if val.kind() == io::ErrorKind::NotFound { Error::NotFound } else { Error::Io(val) } } } impl From<TomlError> for Error { fn from(val: TomlError) -> Self { Error::Toml(val) } } impl From<TomlSeError> for Error { fn from(val: TomlSeError) -> Self { Error::TomlSe(val) } } impl From<YamlError> for Error { fn from(val: YamlError) -> Self { Error::Yaml(val) } } /// Load the configuration file. pub fn load(options: &mut Options) -> UiConfig { let config_path = options .config_file .clone() .or_else(|| installed_config("toml")) .or_else(|| installed_config("yml")); // Load the config using the following fallback behavior: // - Config path + CLI overrides // - CLI overrides // - Default let mut config = config_path .as_ref() .and_then(|config_path| load_from(config_path).ok()) .unwrap_or_else(|| { let mut config = UiConfig::default(); match config_path { Some(config_path) => config.config_paths.push(config_path), None => info!(target: LOG_TARGET_CONFIG, "No config file found; using default"), } config }); after_loading(&mut config, options); config } /// Attempt to reload the configuration file. pub fn reload(config_path: &Path, options: &mut Options) -> Result<UiConfig> { debug!("Reloading configuration file: {:?}", config_path); // Load config, propagating errors. let mut config = load_from(config_path)?; after_loading(&mut config, options); Ok(config) } /// Modifications after the `UiConfig` object is created. fn after_loading(config: &mut UiConfig, options: &mut Options) { // Override config with CLI options. options.override_config(config); // Create key bindings for regex hints. config.generate_hint_bindings(); } /// Load configuration file and log errors. fn load_from(path: &Path) -> Result<UiConfig> { match read_config(path) { Ok(config) => Ok(config), Err(err) => { error!(target: LOG_TARGET_CONFIG, "Unable to load config {:?}: {}", path, err); Err(err) }, } } /// Deserialize configuration file from path. fn read_config(path: &Path) -> Result<UiConfig> { let mut config_paths = Vec::new(); let config_value = parse_config(path, &mut config_paths, IMPORT_RECURSION_LIMIT)?; // Deserialize to concrete type. let mut config = UiConfig::deserialize(config_value)?; config.config_paths = config_paths; Ok(config) } /// Deserialize all configuration files as generic Value. fn parse_config( path: &Path, config_paths: &mut Vec<PathBuf>, recursion_limit: usize, ) -> Result<Value> { config_paths.push(path.to_owned()); // Deserialize the configuration file. let config = deserialize_config(path, false)?; // Merge config with imports. let imports = load_imports(&config, config_paths, recursion_limit); Ok(serde_utils::merge(imports, config)) } /// Deserialize a configuration file. pub fn deserialize_config(path: &Path, warn_pruned: bool) -> Result<Value> { let mut contents = fs::read_to_string(path)?; // Remove UTF-8 BOM. if contents.starts_with('\u{FEFF}') { contents = contents.split_off(3); } // Convert YAML to TOML as a transitionary fallback mechanism. let extension = path.extension().unwrap_or_default(); if (extension == "yaml" || extension == "yml") && !contents.trim().is_empty() { warn!( "YAML config {path:?} is deprecated, please migrate to TOML using `alacritty migrate`" ); let mut value: serde_yaml::Value = serde_yaml::from_str(&contents)?; prune_yaml_nulls(&mut value, warn_pruned); contents = toml::to_string(&value)?; } // Load configuration file as Value. let config: Value = toml::from_str(&contents)?; Ok(config) } /// Load all referenced configuration files. fn load_imports(config: &Value, config_paths: &mut Vec<PathBuf>, recursion_limit: usize) -> Value { // Get paths for all imports. let import_paths = match imports(config, recursion_limit) { Ok(import_paths) => import_paths, Err(err) => { error!(target: LOG_TARGET_CONFIG, "{err}"); return Value::Table(Table::new()); }, }; // Parse configs for all imports recursively. let mut merged = Value::Table(Table::new()); for import_path in import_paths { let path = match import_path { Ok(path) => path, Err(err) => { error!(target: LOG_TARGET_CONFIG, "{err}"); continue; }, }; if !path.exists() { info!(target: LOG_TARGET_CONFIG, "Config import not found:\n {:?}", path.display()); continue; } match parse_config(&path, config_paths, recursion_limit - 1) { Ok(config) => merged = serde_utils::merge(merged, config), Err(err) => { error!(target: LOG_TARGET_CONFIG, "Unable to import config {:?}: {}", path, err) }, } } merged } // TODO: Merge back with `load_imports` once `alacritty migrate` is dropped. // /// Get all import paths for a configuration. pub fn imports( config: &Value, recursion_limit: usize, ) -> StdResult<Vec<StdResult<PathBuf, String>>, String> { let imports = match config.get("import") { Some(Value::Array(imports)) => imports, Some(_) => return Err("Invalid import type: expected a sequence".into()), None => return Ok(Vec::new()), }; // Limit recursion to prevent infinite loops. if !imports.is_empty() && recursion_limit == 0 { return Err("Exceeded maximum configuration import depth".into()); } let mut import_paths = Vec::new(); for import in imports { let mut path = match import { Value::String(path) => PathBuf::from(path), _ => { import_paths.push(Err("Invalid import element type: expected path string".into())); continue; }, }; // Resolve paths relative to user's home directory. if let (Ok(stripped), Some(home_dir)) = (path.strip_prefix("~/"), home::home_dir()) { path = home_dir.join(stripped); } import_paths.push(Ok(path)); } Ok(import_paths) } /// Prune the nulls from the YAML to ensure TOML compatibility. fn prune_yaml_nulls(value: &mut serde_yaml::Value, warn_pruned: bool) { fn walk(value: &mut serde_yaml::Value, warn_pruned: bool) -> bool { match value { serde_yaml::Value::Sequence(sequence) => { sequence.retain_mut(|value| !walk(value, warn_pruned)); sequence.is_empty() }, serde_yaml::Value::Mapping(mapping) => { mapping.retain(|key, value| { let retain = !walk(value, warn_pruned); if let Some(key_name) = key.as_str().filter(|_| !retain && warn_pruned) { eprintln!("Removing null key \"{key_name}\" from the end config"); } retain }); mapping.is_empty() }, serde_yaml::Value::Null => true, _ => false, } } if walk(value, warn_pruned) { // When the value itself is null return the mapping. *value = serde_yaml::Value::Mapping(Default::default()); } } /// Get the location of the first found default config file paths /// according to the following order: /// /// 1. $XDG_CONFIG_HOME/alacritty/alacritty.toml /// 2. $XDG_CONFIG_HOME/alacritty.toml /// 3. $HOME/.config/alacritty/alacritty.toml /// 4. $HOME/.alacritty.toml #[cfg(not(windows))] pub fn installed_config(suffix: &str) -> Option<PathBuf> { let file_name = format!("alacritty.{suffix}"); // Try using XDG location by default. xdg::BaseDirectories::with_prefix("alacritty") .ok() .and_then(|xdg| xdg.find_config_file(&file_name)) .or_else(|| { xdg::BaseDirectories::new() .ok() .and_then(|fallback| fallback.find_config_file(&file_name)) }) .or_else(|| { if let Ok(home) = env::var("HOME") { // Fallback path: $HOME/.config/alacritty/alacritty.toml. let fallback = PathBuf::from(&home).join(".config/alacritty").join(&file_name); if fallback.exists() { return Some(fallback); } // Fallback path: $HOME/.alacritty.toml. let hidden_name = format!(".{file_name}"); let fallback = PathBuf::from(&home).join(hidden_name); if fallback.exists() { return Some(fallback); } } None }) } #[cfg(windows)] pub fn installed_config(suffix: &str) -> Option<PathBuf> { let file_name = format!("alacritty.{suffix}"); dirs::config_dir().map(|path| path.join("alacritty").join(file_name)).filter(|new| new.exists()) } #[cfg(test)] mod tests { use super::*; #[test] fn empty_config() { toml::from_str::<UiConfig>("").unwrap(); } fn yaml_to_toml(contents: &str) -> String { let mut value: serde_yaml::Value = serde_yaml::from_str(contents).unwrap(); prune_yaml_nulls(&mut value, false); toml::to_string(&value).unwrap() } #[test] fn yaml_with_nulls() { let contents = r#" window: blinking: Always cursor: not_blinking: Always some_array: - { window: } - { window: "Hello" } "#; let toml = yaml_to_toml(contents); assert_eq!( toml.trim(), r#"[window] blinking = "Always" not_blinking = "Always" [[window.some_array]] window = "Hello""# ); } #[test] fn empty_yaml_to_toml() { let contents = r#" "#; let toml = yaml_to_toml(contents); assert!(toml.is_empty()); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/monitor.rs��������������������������������������������������������������0000644�0000000�0000000�00000011030�10461020230�0015767�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::path::PathBuf; use std::sync::mpsc::{self, RecvTimeoutError}; use std::time::{Duration, Instant}; use log::{debug, error}; use notify::{Config, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; use winit::event_loop::EventLoopProxy; use alacritty_terminal::thread; use crate::event::{Event, EventType}; const DEBOUNCE_DELAY: Duration = Duration::from_millis(10); /// The fallback for `RecommendedWatcher` polling. const FALLBACK_POLLING_TIMEOUT: Duration = Duration::from_secs(1); pub fn watch(mut paths: Vec<PathBuf>, event_proxy: EventLoopProxy<Event>) { // Don't monitor config if there is no path to watch. if paths.is_empty() { return; } // Exclude char devices like `/dev/null`, sockets, and so on, by checking that file type is a // regular file. paths.retain(|path| { // Call `metadata` to resolve symbolic links. path.metadata().map_or(false, |metadata| metadata.file_type().is_file()) }); // Canonicalize paths, keeping the base paths for symlinks. for i in 0..paths.len() { if let Ok(canonical_path) = paths[i].canonicalize() { match paths[i].symlink_metadata() { Ok(metadata) if metadata.file_type().is_symlink() => paths.push(canonical_path), _ => paths[i] = canonical_path, } } } // The Duration argument is a debouncing period. let (tx, rx) = mpsc::channel(); let mut watcher = match RecommendedWatcher::new( tx, Config::default().with_poll_interval(FALLBACK_POLLING_TIMEOUT), ) { Ok(watcher) => watcher, Err(err) => { error!("Unable to watch config file: {}", err); return; }, }; thread::spawn_named("config watcher", move || { // Get all unique parent directories. let mut parents = paths .iter() .map(|path| { let mut path = path.clone(); path.pop(); path }) .collect::<Vec<PathBuf>>(); parents.sort_unstable(); parents.dedup(); // Watch all configuration file directories. for parent in &parents { if let Err(err) = watcher.watch(parent, RecursiveMode::NonRecursive) { debug!("Unable to watch config directory {:?}: {}", parent, err); } } // The current debouncing time. let mut debouncing_deadline: Option<Instant> = None; // The events accumulated during the debounce period. let mut received_events = Vec::new(); loop { // We use `recv_timeout` to debounce the events coming from the watcher and reduce // the amount of config reloads. let event = match debouncing_deadline.as_ref() { Some(debouncing_deadline) => { rx.recv_timeout(debouncing_deadline.saturating_duration_since(Instant::now())) }, None => { let event = rx.recv().map_err(Into::into); // Set the debouncing deadline after receiving the event. debouncing_deadline = Some(Instant::now() + DEBOUNCE_DELAY); event }, }; match event { Ok(Ok(event)) => match event.kind { EventKind::Any | EventKind::Create(_) | EventKind::Modify(_) | EventKind::Other => { received_events.push(event); }, _ => (), }, Err(RecvTimeoutError::Timeout) => { // Go back to polling the events. debouncing_deadline = None; if received_events .drain(..) .flat_map(|event| event.paths.into_iter()) .any(|path| paths.contains(&path)) { // Always reload the primary configuration file. let event = Event::new(EventType::ConfigReload(paths[0].clone()), None); let _ = event_proxy.send_event(event); } }, Ok(Err(err)) => { debug!("Config watcher errors: {:?}", err); }, Err(err) => { debug!("Config watcher channel dropped unexpectedly: {}", err); break; }, }; } }); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/mouse.rs����������������������������������������������������������������0000644�0000000�0000000�00000001455�10461020230�0015442�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use serde::{Deserialize, Deserializer}; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use crate::config::bindings::{self, MouseBinding}; use crate::config::ui_config; #[derive(ConfigDeserialize, Default, Clone, Debug, PartialEq, Eq)] pub struct Mouse { pub hide_when_typing: bool, pub bindings: MouseBindings, } #[derive(SerdeReplace, Clone, Debug, PartialEq, Eq)] pub struct MouseBindings(pub Vec<MouseBinding>); impl Default for MouseBindings { fn default() -> Self { Self(bindings::default_mouse_bindings()) } } impl<'de> Deserialize<'de> for MouseBindings { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { Ok(Self(ui_config::deserialize_bindings(deserializer, Self::default().0)?)) } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/scrolling.rs������������������������������������������������������������0000644�0000000�0000000�00000002400�10461020230�0016275�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use serde::de::Error as SerdeError; use serde::{Deserialize, Deserializer}; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; /// Maximum scrollback amount configurable. pub const MAX_SCROLLBACK_LINES: u32 = 100_000; /// Struct for scrolling related settings. #[derive(ConfigDeserialize, Copy, Clone, Debug, PartialEq, Eq)] pub struct Scrolling { pub multiplier: u8, history: ScrollingHistory, } impl Default for Scrolling { fn default() -> Self { Self { multiplier: 3, history: Default::default() } } } impl Scrolling { pub fn history(self) -> u32 { self.history.0 } } #[derive(SerdeReplace, Copy, Clone, Debug, PartialEq, Eq)] struct ScrollingHistory(u32); impl Default for ScrollingHistory { fn default() -> Self { Self(10_000) } } impl<'de> Deserialize<'de> for ScrollingHistory { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let lines = u32::deserialize(deserializer)?; if lines > MAX_SCROLLBACK_LINES { Err(SerdeError::custom(format!( "exceeded maximum scrolling history ({lines}/{MAX_SCROLLBACK_LINES})" ))) } else { Ok(Self(lines)) } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/selection.rs������������������������������������������������������������0000644�0000000�0000000�00000000723�10461020230�0016274�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use alacritty_config_derive::ConfigDeserialize; use alacritty_terminal::term::SEMANTIC_ESCAPE_CHARS; #[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)] pub struct Selection { pub semantic_escape_chars: String, pub save_to_clipboard: bool, } impl Default for Selection { fn default() -> Self { Self { semantic_escape_chars: SEMANTIC_ESCAPE_CHARS.to_owned(), save_to_clipboard: Default::default(), } } } ���������������������������������������������alacritty-0.13.2/src/config/serde_utils.rs����������������������������������������������������������0000644�0000000�0000000�00000006061�10461020230�0016632�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Serde helpers. use toml::{Table, Value}; /// Merge two serde structures. /// /// This will take all values from `replacement` and use `base` whenever a value isn't present in /// `replacement`. pub fn merge(base: Value, replacement: Value) -> Value { match (base, replacement) { (Value::Array(mut base), Value::Array(mut replacement)) => { base.append(&mut replacement); Value::Array(base) }, (Value::Table(base), Value::Table(replacement)) => { Value::Table(merge_tables(base, replacement)) }, (_, value) => value, } } /// Merge two key/value tables. fn merge_tables(mut base: Table, replacement: Table) -> Table { for (key, value) in replacement { let value = match base.remove(&key) { Some(base_value) => merge(base_value, value), None => value, }; base.insert(key, value); } base } #[cfg(test)] mod tests { use super::*; #[test] fn merge_primitive() { let base = Value::Table(Table::new()); let replacement = Value::Boolean(true); assert_eq!(merge(base, replacement.clone()), replacement); let base = Value::Boolean(false); let replacement = Value::Boolean(true); assert_eq!(merge(base, replacement.clone()), replacement); let base = Value::Integer(0.into()); let replacement = Value::Integer(1.into()); assert_eq!(merge(base, replacement.clone()), replacement); let base = Value::String(String::new()); let replacement = Value::String(String::from("test")); assert_eq!(merge(base, replacement.clone()), replacement); let base = Value::Table(Table::new()); let replacement = Value::Table(Table::new()); assert_eq!(merge(base.clone(), replacement), base); } #[test] fn merge_sequence() { let base = Value::Array(vec![Value::Table(Table::new())]); let replacement = Value::Array(vec![Value::Boolean(true)]); let expected = Value::Array(vec![Value::Table(Table::new()), Value::Boolean(true)]); assert_eq!(merge(base, replacement), expected); } #[test] fn merge_tables() { let mut base_table = Table::new(); base_table.insert(String::from("a"), Value::Boolean(true)); base_table.insert(String::from("b"), Value::Boolean(false)); let base = Value::Table(base_table); let mut replacement_table = Table::new(); replacement_table.insert(String::from("a"), Value::Boolean(true)); replacement_table.insert(String::from("c"), Value::Boolean(false)); let replacement = Value::Table(replacement_table); let merged = merge(base, replacement); let mut expected_table = Table::new(); expected_table.insert(String::from("b"), Value::Boolean(false)); expected_table.insert(String::from("a"), Value::Boolean(true)); expected_table.insert(String::from("c"), Value::Boolean(false)); let expected = Value::Table(expected_table); assert_eq!(merged, expected); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/terminal.rs�������������������������������������������������������������0000644�0000000�0000000�00000001413�10461020230�0016117�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use serde::{de, Deserialize, Deserializer}; use toml::Value; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use alacritty_terminal::term::Osc52; use crate::config::ui_config::StringVisitor; #[derive(ConfigDeserialize, Default, Copy, Clone, Debug, PartialEq)] pub struct Terminal { /// OSC52 support mode. pub osc52: SerdeOsc52, } #[derive(SerdeReplace, Default, Copy, Clone, Debug, PartialEq)] pub struct SerdeOsc52(pub Osc52); impl<'de> Deserialize<'de> for SerdeOsc52 { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let value = deserializer.deserialize_str(StringVisitor)?; Osc52::deserialize(Value::String(value)).map(SerdeOsc52).map_err(de::Error::custom) } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/ui_config.rs������������������������������������������������������������0000644�0000000�0000000�00000053341�10461020230�0016255�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::cell::RefCell; use std::collections::HashMap; use std::error::Error; use std::fmt::{self, Formatter}; use std::path::PathBuf; use std::rc::Rc; use alacritty_config::SerdeReplace; use alacritty_terminal::term::Config as TermConfig; use alacritty_terminal::tty::{Options as PtyOptions, Shell}; use log::{error, warn}; use serde::de::{Error as SerdeError, MapAccess, Visitor}; use serde::{Deserialize, Deserializer}; use unicode_width::UnicodeWidthChar; use winit::keyboard::{Key, ModifiersState}; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use alacritty_terminal::term::search::RegexSearch; use crate::config::bell::BellConfig; use crate::config::bindings::{ self, Action, Binding, BindingKey, KeyBinding, KeyLocation, ModeWrapper, ModsWrapper, MouseBinding, }; use crate::config::color::Colors; use crate::config::cursor::Cursor; use crate::config::debug::Debug; use crate::config::font::Font; use crate::config::mouse::{Mouse, MouseBindings}; use crate::config::scrolling::Scrolling; use crate::config::selection::Selection; use crate::config::terminal::Terminal; use crate::config::window::WindowConfig; use crate::config::LOG_TARGET_CONFIG; /// Regex used for the default URL hint. #[rustfmt::skip] const URL_REGEX: &str = "(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)\ [^\u{0000}-\u{001F}\u{007F}-\u{009F}<>\"\\s{-}\\^⟨⟩`]+"; #[derive(ConfigDeserialize, Clone, Debug, PartialEq)] pub struct UiConfig { /// Extra environment variables. pub env: HashMap<String, String>, /// How much scrolling history to keep. pub scrolling: Scrolling, /// Cursor configuration. pub cursor: Cursor, /// Selection configuration. pub selection: Selection, /// Font configuration. pub font: Font, /// Window configuration. pub window: WindowConfig, /// Mouse configuration. pub mouse: Mouse, /// Debug options. pub debug: Debug, /// Send escape sequences using the alt key. #[config(removed = "It's now always set to 'true'. If you're on macOS use \ 'window.option_as_alt' to alter behavior of Option")] pub alt_send_esc: Option<bool>, /// Live config reload. pub live_config_reload: bool, /// Bell configuration. pub bell: BellConfig, /// RGB values for colors. pub colors: Colors, /// Path where config was loaded from. #[config(skip)] pub config_paths: Vec<PathBuf>, /// Regex hints for interacting with terminal content. pub hints: Hints, /// Offer IPC through a unix socket. #[cfg(unix)] pub ipc_socket: bool, /// Config for the alacritty_terminal itself. pub terminal: Terminal, /// Path to a shell program to run on startup. pub shell: Option<Program>, /// Shell startup directory. pub working_directory: Option<PathBuf>, /// Keyboard configuration. keyboard: Keyboard, /// Should draw bold text with brighter colors instead of bold font. #[config(deprecated = "use colors.draw_bold_text_with_bright_colors instead")] draw_bold_text_with_bright_colors: bool, /// Keybindings. #[config(deprecated = "use keyboard.bindings instead")] key_bindings: Option<KeyBindings>, /// Bindings for the mouse. #[config(deprecated = "use mouse.bindings instead")] mouse_bindings: Option<MouseBindings>, /// Configuration file imports. /// /// This is never read since the field is directly accessed through the config's /// [`toml::Value`], but still present to prevent unused field warnings. import: Vec<String>, } impl Default for UiConfig { fn default() -> Self { Self { live_config_reload: true, #[cfg(unix)] ipc_socket: true, draw_bold_text_with_bright_colors: Default::default(), working_directory: Default::default(), mouse_bindings: Default::default(), config_paths: Default::default(), key_bindings: Default::default(), alt_send_esc: Default::default(), scrolling: Default::default(), selection: Default::default(), keyboard: Default::default(), terminal: Default::default(), import: Default::default(), cursor: Default::default(), window: Default::default(), colors: Default::default(), shell: Default::default(), mouse: Default::default(), debug: Default::default(), hints: Default::default(), font: Default::default(), bell: Default::default(), env: Default::default(), } } } impl UiConfig { /// Derive [`TermConfig`] from the config. pub fn term_options(&self) -> TermConfig { TermConfig { semantic_escape_chars: self.selection.semantic_escape_chars.clone(), scrolling_history: self.scrolling.history() as usize, vi_mode_cursor_style: self.cursor.vi_mode_style(), default_cursor_style: self.cursor.style(), osc52: self.terminal.osc52.0, kitty_keyboard: true, } } /// Derive [`PtyOptions`] from the config. pub fn pty_config(&self) -> PtyOptions { let shell = self.shell.clone().map(Into::into); PtyOptions { shell, working_directory: self.working_directory.clone(), hold: false, env: HashMap::new(), } } /// Generate key bindings for all keyboard hints. pub fn generate_hint_bindings(&mut self) { // Check which key bindings is most likely to be the user's configuration. // // Both will be non-empty due to the presence of the default keybindings. let key_bindings = if let Some(key_bindings) = self.key_bindings.as_mut() { &mut key_bindings.0 } else { &mut self.keyboard.bindings.0 }; for hint in &self.hints.enabled { let binding = match &hint.binding { Some(binding) => binding, None => continue, }; let binding = KeyBinding { trigger: binding.key.clone(), mods: binding.mods.0, mode: binding.mode.mode, notmode: binding.mode.not_mode, action: Action::Hint(hint.clone()), }; key_bindings.push(binding); } } #[inline] pub fn window_opacity(&self) -> f32 { self.window.opacity.as_f32() } #[inline] pub fn key_bindings(&self) -> &[KeyBinding] { if let Some(key_bindings) = self.key_bindings.as_ref() { &key_bindings.0 } else { &self.keyboard.bindings.0 } } #[inline] pub fn mouse_bindings(&self) -> &[MouseBinding] { if let Some(mouse_bindings) = self.mouse_bindings.as_ref() { &mouse_bindings.0 } else { &self.mouse.bindings.0 } } #[inline] pub fn draw_bold_text_with_bright_colors(&self) -> bool { self.colors.draw_bold_text_with_bright_colors || self.draw_bold_text_with_bright_colors } } /// Keyboard configuration. #[derive(ConfigDeserialize, Default, Clone, Debug, PartialEq)] struct Keyboard { /// Keybindings. bindings: KeyBindings, } #[derive(SerdeReplace, Clone, Debug, PartialEq, Eq)] struct KeyBindings(Vec<KeyBinding>); impl Default for KeyBindings { fn default() -> Self { Self(bindings::default_key_bindings()) } } impl<'de> Deserialize<'de> for KeyBindings { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { Ok(Self(deserialize_bindings(deserializer, Self::default().0)?)) } } pub fn deserialize_bindings<'a, D, T>( deserializer: D, mut default: Vec<Binding<T>>, ) -> Result<Vec<Binding<T>>, D::Error> where D: Deserializer<'a>, T: Clone + Eq, Binding<T>: Deserialize<'a>, { let values = Vec::<toml::Value>::deserialize(deserializer)?; // Skip all invalid values. let mut bindings = Vec::with_capacity(values.len()); for value in values { match Binding::<T>::deserialize(value) { Ok(binding) => bindings.push(binding), Err(err) => { error!(target: LOG_TARGET_CONFIG, "Config error: {}; ignoring binding", err); }, } } // Remove matching default bindings. for binding in bindings.iter() { default.retain(|b| !b.triggers_match(binding)); } bindings.extend(default); Ok(bindings) } /// A delta for a point in a 2 dimensional plane. #[derive(ConfigDeserialize, Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct Delta<T: Default> { /// Horizontal change. pub x: T, /// Vertical change. pub y: T, } /// Regex terminal hints. #[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)] pub struct Hints { /// Characters for the hint labels. alphabet: HintsAlphabet, /// All configured terminal hints. pub enabled: Vec<Hint>, } impl Default for Hints { fn default() -> Self { // Add URL hint by default when no other hint is present. let pattern = LazyRegexVariant::Pattern(String::from(URL_REGEX)); let regex = LazyRegex(Rc::new(RefCell::new(pattern))); let content = HintContent::new(Some(regex), true); #[cfg(not(any(target_os = "macos", windows)))] let action = HintAction::Command(Program::Just(String::from("xdg-open"))); #[cfg(target_os = "macos")] let action = HintAction::Command(Program::Just(String::from("open"))); #[cfg(windows)] let action = HintAction::Command(Program::WithArgs { program: String::from("cmd"), args: vec!["/c".to_string(), "start".to_string(), "".to_string()], }); Self { enabled: vec![Hint { content, action, persist: false, post_processing: true, mouse: Some(HintMouse { enabled: true, mods: Default::default() }), binding: Some(HintBinding { key: BindingKey::Keycode { key: Key::Character("u".into()), location: KeyLocation::Standard, }, mods: ModsWrapper(ModifiersState::SHIFT | ModifiersState::CONTROL), mode: Default::default(), }), }], alphabet: Default::default(), } } } impl Hints { /// Characters for the hint labels. pub fn alphabet(&self) -> &str { &self.alphabet.0 } } #[derive(SerdeReplace, Clone, Debug, PartialEq, Eq)] struct HintsAlphabet(String); impl Default for HintsAlphabet { fn default() -> Self { Self(String::from("jfkdls;ahgurieowpq")) } } impl<'de> Deserialize<'de> for HintsAlphabet { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let value = String::deserialize(deserializer)?; let mut character_count = 0; for character in value.chars() { if character.width() != Some(1) { return Err(D::Error::custom("characters must be of width 1")); } character_count += 1; } if character_count < 2 { return Err(D::Error::custom("must include at last 2 characters")); } Ok(Self(value)) } } /// Built-in actions for hint mode. #[derive(ConfigDeserialize, Clone, Debug, PartialEq, Eq)] pub enum HintInternalAction { /// Copy the text to the clipboard. Copy, /// Write the text to the PTY/search. Paste, /// Select the text matching the hint. Select, /// Move the vi mode cursor to the beginning of the hint. MoveViModeCursor, } /// Actions for hint bindings. #[derive(Deserialize, Clone, Debug, PartialEq, Eq)] pub enum HintAction { /// Built-in hint action. #[serde(rename = "action")] Action(HintInternalAction), /// Command the text will be piped to. #[serde(rename = "command")] Command(Program), } /// Hint configuration. #[derive(Deserialize, Clone, Debug, PartialEq, Eq)] pub struct Hint { /// Regex for finding matches. #[serde(flatten)] pub content: HintContent, /// Action executed when this hint is triggered. #[serde(flatten)] pub action: HintAction, /// Hint text post processing. #[serde(default)] pub post_processing: bool, /// Persist hints after selection. #[serde(default)] pub persist: bool, /// Hint mouse highlighting. pub mouse: Option<HintMouse>, /// Binding required to search for this hint. binding: Option<HintBinding>, } #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct HintContent { /// Regex for finding matches. pub regex: Option<LazyRegex>, /// Escape sequence hyperlinks. pub hyperlinks: bool, } impl HintContent { pub fn new(regex: Option<LazyRegex>, hyperlinks: bool) -> Self { Self { regex, hyperlinks } } } impl<'de> Deserialize<'de> for HintContent { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { struct HintContentVisitor; impl<'a> Visitor<'a> for HintContentVisitor { type Value = HintContent; fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("a mapping") } fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error> where M: MapAccess<'a>, { let mut content = Self::Value::default(); while let Some((key, value)) = map.next_entry::<String, toml::Value>()? { match key.as_str() { "regex" => match Option::<LazyRegex>::deserialize(value) { Ok(regex) => content.regex = regex, Err(err) => { error!( target: LOG_TARGET_CONFIG, "Config error: hint's regex: {}", err ); }, }, "hyperlinks" => match bool::deserialize(value) { Ok(hyperlink) => content.hyperlinks = hyperlink, Err(err) => { error!( target: LOG_TARGET_CONFIG, "Config error: hint's hyperlinks: {}", err ); }, }, "command" | "action" => (), key => warn!(target: LOG_TARGET_CONFIG, "Unrecognized hint field: {key}"), } } // Require at least one of hyperlinks or regex trigger hint matches. if content.regex.is_none() && !content.hyperlinks { return Err(M::Error::custom( "Config error: At least on of the hint's regex or hint's hyperlinks must \ be set", )); } Ok(content) } } deserializer.deserialize_any(HintContentVisitor) } } /// Binding for triggering a keyboard hint. #[derive(Deserialize, Clone, Debug, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct HintBinding { pub key: BindingKey, #[serde(default)] pub mods: ModsWrapper, #[serde(default)] pub mode: ModeWrapper, } /// Hint mouse highlighting. #[derive(ConfigDeserialize, Default, Copy, Clone, Debug, PartialEq, Eq)] pub struct HintMouse { /// Hint mouse highlighting availability. pub enabled: bool, /// Required mouse modifiers for hint highlighting. pub mods: ModsWrapper, } /// Lazy regex with interior mutability. #[derive(Clone, Debug, PartialEq, Eq)] pub struct LazyRegex(Rc<RefCell<LazyRegexVariant>>); impl LazyRegex { /// Execute a function with the compiled regex DFAs as parameter. pub fn with_compiled<T, F>(&self, f: F) -> Option<T> where F: FnMut(&mut RegexSearch) -> T, { self.0.borrow_mut().compiled().map(f) } } impl<'de> Deserialize<'de> for LazyRegex { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { let regex = LazyRegexVariant::Pattern(String::deserialize(deserializer)?); Ok(Self(Rc::new(RefCell::new(regex)))) } } /// Regex which is compiled on demand, to avoid expensive computations at startup. #[derive(Clone, Debug)] pub enum LazyRegexVariant { Compiled(Box<RegexSearch>), Pattern(String), Uncompilable, } impl LazyRegexVariant { /// Get a reference to the compiled regex. /// /// If the regex is not already compiled, this will compile the DFAs and store them for future /// access. fn compiled(&mut self) -> Option<&mut RegexSearch> { // Check if the regex has already been compiled. let regex = match self { Self::Compiled(regex_search) => return Some(regex_search), Self::Uncompilable => return None, Self::Pattern(regex) => regex, }; // Compile the regex. let regex_search = match RegexSearch::new(regex) { Ok(regex_search) => regex_search, Err(err) => { error!("could not compile hint regex: {err}"); *self = Self::Uncompilable; return None; }, }; *self = Self::Compiled(Box::new(regex_search)); // Return a reference to the compiled DFAs. match self { Self::Compiled(dfas) => Some(dfas), _ => unreachable!(), } } } impl PartialEq for LazyRegexVariant { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Pattern(regex), Self::Pattern(other_regex)) => regex == other_regex, _ => false, } } } impl Eq for LazyRegexVariant {} /// Wrapper around f32 that represents a percentage value between 0.0 and 1.0. #[derive(SerdeReplace, Deserialize, Clone, Copy, Debug, PartialEq)] pub struct Percentage(f32); impl Default for Percentage { fn default() -> Self { Percentage(1.0) } } impl Percentage { pub fn new(value: f32) -> Self { Percentage(value.clamp(0., 1.)) } pub fn as_f32(self) -> f32 { self.0 } } #[derive(Deserialize, Debug, Clone, PartialEq, Eq)] #[serde(untagged, deny_unknown_fields)] pub enum Program { Just(String), WithArgs { program: String, #[serde(default)] args: Vec<String>, }, } impl Program { pub fn program(&self) -> &str { match self { Program::Just(program) => program, Program::WithArgs { program, .. } => program, } } pub fn args(&self) -> &[String] { match self { Program::Just(_) => &[], Program::WithArgs { args, .. } => args, } } } impl From<Program> for Shell { fn from(value: Program) -> Self { match value { Program::Just(program) => Shell::new(program, Vec::new()), Program::WithArgs { program, args } => Shell::new(program, args), } } } impl SerdeReplace for Program { fn replace(&mut self, value: toml::Value) -> Result<(), Box<dyn Error>> { *self = Self::deserialize(value)?; Ok(()) } } pub(crate) struct StringVisitor; impl<'de> serde::de::Visitor<'de> for StringVisitor { type Value = String; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("a string") } fn visit_str<E>(self, s: &str) -> Result<Self::Value, E> where E: serde::de::Error, { Ok(s.to_lowercase()) } } #[cfg(test)] mod tests { use super::*; use alacritty_terminal::term::test::mock_term; use crate::display::hint::visible_regex_match_iter; #[test] fn positive_url_parsing_regex_test() { for regular_url in [ "ipfs:s0mEhAsh", "ipns:an0TherHash1234", "magnet:?xt=urn:btih:L0UDHA5H12", "mailto:example@example.org", "gemini://gemini.example.org/", "gopher://gopher.example.org", "https://www.example.org", "http://example.org", "news:some.news.portal", "file:///C:/Windows/", "file:/home/user/whatever", "git://github.com/user/repo.git", "ssh:git@github.com:user/repo.git", "ftp://ftp.example.org", ] { let term = mock_term(regular_url); let mut regex = RegexSearch::new(URL_REGEX).unwrap(); let matches = visible_regex_match_iter(&term, &mut regex).collect::<Vec<_>>(); assert_eq!( matches.len(), 1, "Should have exactly one match url {regular_url}, but instead got: {matches:?}" ) } } #[test] fn negative_url_parsing_regex_test() { for url_like in [ "http::trace::on_request::log_parameters", "http//www.example.org", "/user:example.org", "mailto: example@example.org", "http://<script>alert('xss')</script>", "mailto:", ] { let term = mock_term(url_like); let mut regex = RegexSearch::new(URL_REGEX).unwrap(); let matches = visible_regex_match_iter(&term, &mut regex).collect::<Vec<_>>(); assert!( matches.is_empty(), "Should not match url in string {url_like}, but instead got: {matches:?}" ) } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/config/window.rs���������������������������������������������������������������0000644�0000000�0000000�00000021243�10461020230�0015616�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::fmt::{self, Formatter}; use log::{error, warn}; use serde::de::{self, MapAccess, Visitor}; use serde::{Deserialize, Deserializer, Serialize}; #[cfg(target_os = "macos")] use winit::platform::macos::OptionAsAlt as WinitOptionAsAlt; use winit::window::{Fullscreen, Theme as WinitTheme}; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use crate::config::ui_config::{Delta, Percentage}; use crate::config::LOG_TARGET_CONFIG; /// Default Alacritty name, used for window title and class. pub const DEFAULT_NAME: &str = "Alacritty"; #[derive(ConfigDeserialize, Debug, Clone, PartialEq)] pub struct WindowConfig { /// Initial position. pub position: Option<Delta<i32>>, /// Draw the window with title bar / borders. pub decorations: Decorations, /// Startup mode. pub startup_mode: StartupMode, /// XEmbed parent. #[config(skip)] pub embed: Option<u32>, /// Spread out additional padding evenly. pub dynamic_padding: bool, /// Use dynamic title. pub dynamic_title: bool, /// Information to identify a particular window. #[config(flatten)] pub identity: Identity, /// Background opacity from 0.0 to 1.0. pub opacity: Percentage, /// Request blur behind the window. pub blur: bool, /// Controls which `Option` key should be treated as `Alt`. option_as_alt: OptionAsAlt, /// Resize increments. pub resize_increments: bool, /// Pixel padding. padding: Delta<u16>, /// Initial dimensions. dimensions: Dimensions, /// System decorations theme variant. decorations_theme_variant: Option<Theme>, } impl Default for WindowConfig { fn default() -> Self { Self { dynamic_title: true, blur: Default::default(), embed: Default::default(), padding: Default::default(), opacity: Default::default(), position: Default::default(), identity: Default::default(), dimensions: Default::default(), decorations: Default::default(), startup_mode: Default::default(), dynamic_padding: Default::default(), resize_increments: Default::default(), decorations_theme_variant: Default::default(), option_as_alt: Default::default(), } } } impl WindowConfig { #[inline] pub fn dimensions(&self) -> Option<Dimensions> { let (lines, columns) = (self.dimensions.lines, self.dimensions.columns); let (lines_is_non_zero, columns_is_non_zero) = (lines != 0, columns != 0); if lines_is_non_zero && columns_is_non_zero { // Return dimensions if both `lines` and `columns` are non-zero. Some(self.dimensions) } else if lines_is_non_zero || columns_is_non_zero { // Warn if either `columns` or `lines` is non-zero. let (zero_key, non_zero_key, non_zero_value) = if lines_is_non_zero { ("columns", "lines", lines) } else { ("lines", "columns", columns) }; warn!( target: LOG_TARGET_CONFIG, "Both `lines` and `columns` must be non-zero for `window.dimensions` to take \ effect. Configured value of `{}` is 0 while that of `{}` is {}", zero_key, non_zero_key, non_zero_value, ); None } else { None } } #[inline] pub fn padding(&self, scale_factor: f32) -> (f32, f32) { let padding_x = (f32::from(self.padding.x) * scale_factor).floor(); let padding_y = (f32::from(self.padding.y) * scale_factor).floor(); (padding_x, padding_y) } #[inline] pub fn fullscreen(&self) -> Option<Fullscreen> { if self.startup_mode == StartupMode::Fullscreen { Some(Fullscreen::Borderless(None)) } else { None } } #[inline] pub fn maximized(&self) -> bool { self.startup_mode == StartupMode::Maximized } #[cfg(target_os = "macos")] pub fn option_as_alt(&self) -> WinitOptionAsAlt { match self.option_as_alt { OptionAsAlt::OnlyLeft => WinitOptionAsAlt::OnlyLeft, OptionAsAlt::OnlyRight => WinitOptionAsAlt::OnlyRight, OptionAsAlt::Both => WinitOptionAsAlt::Both, OptionAsAlt::None => WinitOptionAsAlt::None, } } pub fn theme(&self) -> Option<WinitTheme> { self.decorations_theme_variant.map(WinitTheme::from) } } #[derive(ConfigDeserialize, Debug, Clone, PartialEq, Eq)] pub struct Identity { /// Window title. pub title: String, /// Window class. pub class: Class, } impl Default for Identity { fn default() -> Self { Self { title: DEFAULT_NAME.into(), class: Default::default() } } } #[derive(ConfigDeserialize, Default, Debug, Copy, Clone, PartialEq, Eq)] pub enum StartupMode { #[default] Windowed, Maximized, Fullscreen, SimpleFullscreen, } #[derive(ConfigDeserialize, Default, Debug, Copy, Clone, PartialEq, Eq)] pub enum Decorations { #[default] Full, Transparent, Buttonless, None, } /// Window Dimensions. /// /// Newtype to avoid passing values incorrectly. #[derive(ConfigDeserialize, Default, Debug, Copy, Clone, PartialEq, Eq)] pub struct Dimensions { /// Window width in character columns. pub columns: usize, /// Window Height in character lines. pub lines: usize, } /// Window class hint. #[derive(SerdeReplace, Serialize, Debug, Clone, PartialEq, Eq)] pub struct Class { pub general: String, pub instance: String, } impl Class { pub fn new(general: impl ToString, instance: impl ToString) -> Self { Self { general: general.to_string(), instance: instance.to_string() } } } impl Default for Class { fn default() -> Self { Self::new(DEFAULT_NAME, DEFAULT_NAME) } } impl<'de> Deserialize<'de> for Class { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { struct ClassVisitor; impl<'a> Visitor<'a> for ClassVisitor { type Value = Class; fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("a mapping") } fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: de::Error, { Ok(Self::Value { instance: value.into(), ..Self::Value::default() }) } fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error> where M: MapAccess<'a>, { let mut class = Self::Value::default(); while let Some((key, value)) = map.next_entry::<String, toml::Value>()? { match key.as_str() { "instance" => match String::deserialize(value) { Ok(instance) => class.instance = instance, Err(err) => { error!( target: LOG_TARGET_CONFIG, "Config error: class.instance: {}", err ); }, }, "general" => match String::deserialize(value) { Ok(general) => class.general = general, Err(err) => { error!( target: LOG_TARGET_CONFIG, "Config error: class.instance: {}", err ); }, }, key => warn!(target: LOG_TARGET_CONFIG, "Unrecognized class field: {key}"), } } Ok(class) } } deserializer.deserialize_any(ClassVisitor) } } #[derive(ConfigDeserialize, Default, Debug, Clone, Copy, PartialEq, Eq)] pub enum OptionAsAlt { /// The left `Option` key is treated as `Alt`. OnlyLeft, /// The right `Option` key is treated as `Alt`. OnlyRight, /// Both `Option` keys are treated as `Alt`. Both, /// No special handling is applied for `Option` key. #[default] None, } /// System decorations theme variant. #[derive(ConfigDeserialize, Debug, Clone, Copy, PartialEq, Eq)] pub enum Theme { Light, Dark, } impl From<Theme> for WinitTheme { fn from(theme: Theme) -> Self { match theme { Theme::Light => WinitTheme::Light, Theme::Dark => WinitTheme::Dark, } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/daemon.rs����������������������������������������������������������������������0000644�0000000�0000000�00000005450�10461020230�0014307�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::ffi::OsStr; #[cfg(not(any(target_os = "macos", windows)))] use std::fs; use std::io; #[cfg(windows)] use std::os::windows::process::CommandExt; use std::process::{Command, Stdio}; #[rustfmt::skip] #[cfg(not(windows))] use { std::error::Error, std::os::unix::process::CommandExt, std::os::unix::io::RawFd, std::path::PathBuf, }; #[cfg(not(windows))] use libc::pid_t; #[cfg(windows)] use windows_sys::Win32::System::Threading::{CREATE_NEW_PROCESS_GROUP, CREATE_NO_WINDOW}; #[cfg(target_os = "macos")] use crate::macos; /// Start a new process in the background. #[cfg(windows)] pub fn spawn_daemon<I, S>(program: &str, args: I) -> io::Result<()> where I: IntoIterator<Item = S> + Copy, S: AsRef<OsStr>, { // Setting all the I/O handles to null and setting the // CREATE_NEW_PROCESS_GROUP and CREATE_NO_WINDOW has the effect // that console applications will run without opening a new // console window. Command::new(program) .args(args) .stdin(Stdio::null()) .stdout(Stdio::null()) .stderr(Stdio::null()) .creation_flags(CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW) .spawn() .map(|_| ()) } /// Start a new process in the background. #[cfg(not(windows))] pub fn spawn_daemon<I, S>( program: &str, args: I, master_fd: RawFd, shell_pid: u32, ) -> io::Result<()> where I: IntoIterator<Item = S> + Copy, S: AsRef<OsStr>, { let mut command = Command::new(program); command.args(args).stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null()); if let Ok(cwd) = foreground_process_path(master_fd, shell_pid) { command.current_dir(cwd); } unsafe { command .pre_exec(|| { match libc::fork() { -1 => return Err(io::Error::last_os_error()), 0 => (), _ => libc::_exit(0), } if libc::setsid() == -1 { return Err(io::Error::last_os_error()); } Ok(()) }) .spawn()? .wait() .map(|_| ()) } } /// Get working directory of controlling process. #[cfg(not(windows))] pub fn foreground_process_path( master_fd: RawFd, shell_pid: u32, ) -> Result<PathBuf, Box<dyn Error>> { let mut pid = unsafe { libc::tcgetpgrp(master_fd) }; if pid < 0 { pid = shell_pid as pid_t; } #[cfg(not(any(target_os = "macos", target_os = "freebsd")))] let link_path = format!("/proc/{}/cwd", pid); #[cfg(target_os = "freebsd")] let link_path = format!("/compat/linux/proc/{}/cwd", pid); #[cfg(not(target_os = "macos"))] let cwd = fs::read_link(link_path)?; #[cfg(target_os = "macos")] let cwd = macos::proc::cwd(pid)?; Ok(cwd) } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/bell.rs����������������������������������������������������������������0000644�0000000�0000000�00000011307�10461020230�0015425�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::time::{Duration, Instant}; use crate::config::bell::{BellAnimation, BellConfig}; pub struct VisualBell { /// Visual bell animation. animation: BellAnimation, /// Visual bell duration. duration: Duration, /// The last time the visual bell rang, if at all. start_time: Option<Instant>, } impl VisualBell { /// Ring the visual bell, and return its intensity. pub fn ring(&mut self) -> f64 { let now = Instant::now(); self.start_time = Some(now); self.intensity_at_instant(now) } /// Get the currently intensity of the visual bell. The bell's intensity /// ramps down from 1.0 to 0.0 at a rate determined by the bell's duration. pub fn intensity(&self) -> f64 { self.intensity_at_instant(Instant::now()) } /// Check whether or not the visual bell has completed "ringing". pub fn completed(&mut self) -> bool { match self.start_time { Some(earlier) => { if Instant::now().duration_since(earlier) >= self.duration { self.start_time = None; } false }, None => true, } } /// Get the intensity of the visual bell at a particular instant. The bell's /// intensity ramps down from 1.0 to 0.0 at a rate determined by the bell's /// duration. pub fn intensity_at_instant(&self, instant: Instant) -> f64 { // If `duration` is zero, then the VisualBell is disabled; therefore, // its `intensity` is zero. if self.duration == Duration::from_secs(0) { return 0.0; } match self.start_time { // Similarly, if `start_time` is `None`, then the VisualBell has not // been "rung"; therefore, its `intensity` is zero. None => 0.0, Some(earlier) => { // Finally, if the `instant` at which we wish to compute the // VisualBell's `intensity` occurred before the VisualBell was // "rung", then its `intensity` is also zero. if instant < earlier { return 0.0; } let elapsed = instant.duration_since(earlier); let elapsed_f = elapsed.as_secs() as f64 + f64::from(elapsed.subsec_nanos()) / 1e9f64; let duration_f = self.duration.as_secs() as f64 + f64::from(self.duration.subsec_nanos()) / 1e9f64; // Otherwise, we compute a value `time` from 0.0 to 1.0 // inclusive that represents the ratio of `elapsed` time to the // `duration` of the VisualBell. let time = (elapsed_f / duration_f).min(1.0); // We use this to compute the inverse `intensity` of the // VisualBell. When `time` is 0.0, `inverse_intensity` is 0.0, // and when `time` is 1.0, `inverse_intensity` is 1.0. let inverse_intensity = match self.animation { BellAnimation::Ease | BellAnimation::EaseOut => { cubic_bezier(0.25, 0.1, 0.25, 1.0, time) }, BellAnimation::EaseOutSine => cubic_bezier(0.39, 0.575, 0.565, 1.0, time), BellAnimation::EaseOutQuad => cubic_bezier(0.25, 0.46, 0.45, 0.94, time), BellAnimation::EaseOutCubic => cubic_bezier(0.215, 0.61, 0.355, 1.0, time), BellAnimation::EaseOutQuart => cubic_bezier(0.165, 0.84, 0.44, 1.0, time), BellAnimation::EaseOutQuint => cubic_bezier(0.23, 1.0, 0.32, 1.0, time), BellAnimation::EaseOutExpo => cubic_bezier(0.19, 1.0, 0.22, 1.0, time), BellAnimation::EaseOutCirc => cubic_bezier(0.075, 0.82, 0.165, 1.0, time), BellAnimation::Linear => time, }; // Since we want the `intensity` of the VisualBell to decay over // `time`, we subtract the `inverse_intensity` from 1.0. 1.0 - inverse_intensity }, } } pub fn update_config(&mut self, bell_config: &BellConfig) { self.animation = bell_config.animation; self.duration = bell_config.duration(); } } impl From<&BellConfig> for VisualBell { fn from(bell_config: &BellConfig) -> VisualBell { VisualBell { animation: bell_config.animation, duration: bell_config.duration(), start_time: None, } } } fn cubic_bezier(p0: f64, p1: f64, p2: f64, p3: f64, x: f64) -> f64 { (1.0 - x).powi(3) * p0 + 3.0 * (1.0 - x).powi(2) * x * p1 + 3.0 * (1.0 - x) * x.powi(2) * p2 + x.powi(3) * p3 } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/color.rs���������������������������������������������������������������0000644�0000000�0000000�00000025303�10461020230�0015626�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::fmt::{self, Display, Formatter}; use std::ops::{Add, Deref, Index, IndexMut, Mul}; use std::str::FromStr; use log::trace; use serde::de::{Error as SerdeError, Visitor}; use serde::{Deserialize, Deserializer}; use alacritty_config_derive::SerdeReplace; use alacritty_terminal::term::color::COUNT; use alacritty_terminal::vte::ansi::{NamedColor, Rgb as VteRgb}; use crate::config::color::Colors; /// Factor for automatic computation of dim colors. pub const DIM_FACTOR: f32 = 0.66; #[derive(Copy, Clone)] pub struct List([Rgb; COUNT]); impl<'a> From<&'a Colors> for List { fn from(colors: &Colors) -> List { // Type inference fails without this annotation. let mut list = List([Rgb::default(); COUNT]); list.fill_named(colors); list.fill_cube(colors); list.fill_gray_ramp(colors); list } } impl List { pub fn fill_named(&mut self, colors: &Colors) { // Normals. self[NamedColor::Black] = colors.normal.black; self[NamedColor::Red] = colors.normal.red; self[NamedColor::Green] = colors.normal.green; self[NamedColor::Yellow] = colors.normal.yellow; self[NamedColor::Blue] = colors.normal.blue; self[NamedColor::Magenta] = colors.normal.magenta; self[NamedColor::Cyan] = colors.normal.cyan; self[NamedColor::White] = colors.normal.white; // Brights. self[NamedColor::BrightBlack] = colors.bright.black; self[NamedColor::BrightRed] = colors.bright.red; self[NamedColor::BrightGreen] = colors.bright.green; self[NamedColor::BrightYellow] = colors.bright.yellow; self[NamedColor::BrightBlue] = colors.bright.blue; self[NamedColor::BrightMagenta] = colors.bright.magenta; self[NamedColor::BrightCyan] = colors.bright.cyan; self[NamedColor::BrightWhite] = colors.bright.white; self[NamedColor::BrightForeground] = colors.primary.bright_foreground.unwrap_or(colors.primary.foreground); // Foreground and background. self[NamedColor::Foreground] = colors.primary.foreground; self[NamedColor::Background] = colors.primary.background; // Dims. self[NamedColor::DimForeground] = colors.primary.dim_foreground.unwrap_or(colors.primary.foreground * DIM_FACTOR); match colors.dim { Some(ref dim) => { trace!("Using config-provided dim colors"); self[NamedColor::DimBlack] = dim.black; self[NamedColor::DimRed] = dim.red; self[NamedColor::DimGreen] = dim.green; self[NamedColor::DimYellow] = dim.yellow; self[NamedColor::DimBlue] = dim.blue; self[NamedColor::DimMagenta] = dim.magenta; self[NamedColor::DimCyan] = dim.cyan; self[NamedColor::DimWhite] = dim.white; }, None => { trace!("Deriving dim colors from normal colors"); self[NamedColor::DimBlack] = colors.normal.black * DIM_FACTOR; self[NamedColor::DimRed] = colors.normal.red * DIM_FACTOR; self[NamedColor::DimGreen] = colors.normal.green * DIM_FACTOR; self[NamedColor::DimYellow] = colors.normal.yellow * DIM_FACTOR; self[NamedColor::DimBlue] = colors.normal.blue * DIM_FACTOR; self[NamedColor::DimMagenta] = colors.normal.magenta * DIM_FACTOR; self[NamedColor::DimCyan] = colors.normal.cyan * DIM_FACTOR; self[NamedColor::DimWhite] = colors.normal.white * DIM_FACTOR; }, } } pub fn fill_cube(&mut self, colors: &Colors) { let mut index: usize = 16; // Build colors. for r in 0..6 { for g in 0..6 { for b in 0..6 { // Override colors 16..232 with the config (if present). if let Some(indexed_color) = colors.indexed_colors.iter().find(|ic| ic.index() == index as u8) { self[index] = indexed_color.color; } else { self[index] = Rgb::new( if r == 0 { 0 } else { r * 40 + 55 }, if g == 0 { 0 } else { g * 40 + 55 }, if b == 0 { 0 } else { b * 40 + 55 }, ); } index += 1; } } } debug_assert!(index == 232); } pub fn fill_gray_ramp(&mut self, colors: &Colors) { let mut index: usize = 232; for i in 0..24 { // Index of the color is number of named colors + number of cube colors + i. let color_index = 16 + 216 + i; // Override colors 232..256 with the config (if present). if let Some(indexed_color) = colors.indexed_colors.iter().find(|ic| ic.index() == color_index) { self[index] = indexed_color.color; index += 1; continue; } let value = i * 10 + 8; self[index] = Rgb::new(value, value, value); index += 1; } debug_assert!(index == 256); } } impl Index<usize> for List { type Output = Rgb; #[inline] fn index(&self, idx: usize) -> &Self::Output { &self.0[idx] } } impl IndexMut<usize> for List { #[inline] fn index_mut(&mut self, idx: usize) -> &mut Self::Output { &mut self.0[idx] } } impl Index<NamedColor> for List { type Output = Rgb; #[inline] fn index(&self, idx: NamedColor) -> &Self::Output { &self.0[idx as usize] } } impl IndexMut<NamedColor> for List { #[inline] fn index_mut(&mut self, idx: NamedColor) -> &mut Self::Output { &mut self.0[idx as usize] } } #[derive(SerdeReplace, Debug, Eq, PartialEq, Copy, Clone, Default)] pub struct Rgb(pub VteRgb); impl Rgb { #[inline] pub const fn new(r: u8, g: u8, b: u8) -> Self { Self(VteRgb { r, g, b }) } #[inline] pub fn as_tuple(self) -> (u8, u8, u8) { (self.0.r, self.0.g, self.0.b) } } impl From<VteRgb> for Rgb { fn from(value: VteRgb) -> Self { Self(value) } } impl Deref for Rgb { type Target = VteRgb; fn deref(&self) -> &Self::Target { &self.0 } } impl Mul<f32> for Rgb { type Output = Rgb; fn mul(self, rhs: f32) -> Self::Output { Rgb(self.0 * rhs) } } impl Add<Rgb> for Rgb { type Output = Rgb; fn add(self, rhs: Rgb) -> Self::Output { Rgb(self.0 + rhs.0) } } /// Deserialize an Rgb from a hex string. /// /// This is *not* the deserialize impl for Rgb since we want a symmetric /// serialize/deserialize impl for ref tests. impl<'de> Deserialize<'de> for Rgb { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { struct RgbVisitor; // Used for deserializing reftests. #[derive(Deserialize)] struct RgbDerivedDeser { r: u8, g: u8, b: u8, } impl<'a> Visitor<'a> for RgbVisitor { type Value = Rgb; fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str("hex color like #ff00ff") } fn visit_str<E>(self, value: &str) -> Result<Rgb, E> where E: serde::de::Error, { Rgb::from_str(value).map_err(|_| { E::custom(format!( "failed to parse rgb color {value}; expected hex color like #ff00ff" )) }) } } // Return an error if the syntax is incorrect. let value = toml::Value::deserialize(deserializer)?; // Attempt to deserialize from struct form. if let Ok(RgbDerivedDeser { r, g, b }) = RgbDerivedDeser::deserialize(value.clone()) { return Ok(Rgb::new(r, g, b)); } // Deserialize from hex notation (either 0xff00ff or #ff00ff). value.deserialize_str(RgbVisitor).map_err(D::Error::custom) } } impl Display for Rgb { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "#{:02x}{:02x}{:02x}", self.r, self.g, self.b) } } impl FromStr for Rgb { type Err = (); fn from_str(s: &str) -> Result<Rgb, ()> { let chars = if s.starts_with("0x") && s.len() == 8 { &s[2..] } else if s.starts_with('#') && s.len() == 7 { &s[1..] } else { return Err(()); }; match u32::from_str_radix(chars, 16) { Ok(mut color) => { let b = (color & 0xff) as u8; color >>= 8; let g = (color & 0xff) as u8; color >>= 8; let r = color as u8; Ok(Rgb::new(r, g, b)) }, Err(_) => Err(()), } } } /// RGB color optionally referencing the cell's foreground or background. #[derive(SerdeReplace, Copy, Clone, Debug, PartialEq, Eq)] pub enum CellRgb { CellForeground, CellBackground, Rgb(Rgb), } impl CellRgb { pub fn color(self, foreground: Rgb, background: Rgb) -> Rgb { match self { Self::CellForeground => foreground, Self::CellBackground => background, Self::Rgb(rgb) => rgb, } } } impl Default for CellRgb { fn default() -> Self { Self::Rgb(Rgb::default()) } } impl<'de> Deserialize<'de> for CellRgb { fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>, { const EXPECTING: &str = "CellForeground, CellBackground, or hex color like #ff00ff"; struct CellRgbVisitor; impl<'a> Visitor<'a> for CellRgbVisitor { type Value = CellRgb; fn expecting(&self, f: &mut Formatter<'_>) -> fmt::Result { f.write_str(EXPECTING) } fn visit_str<E>(self, value: &str) -> Result<CellRgb, E> where E: serde::de::Error, { // Attempt to deserialize as enum constants. match value { "CellForeground" => return Ok(CellRgb::CellForeground), "CellBackground" => return Ok(CellRgb::CellBackground), _ => (), } Rgb::from_str(value).map(CellRgb::Rgb).map_err(|_| { E::custom(format!("failed to parse color {value}; expected {EXPECTING}")) }) } } deserializer.deserialize_str(CellRgbVisitor).map_err(D::Error::custom) } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/content.rs�������������������������������������������������������������0000644�0000000�0000000�00000045007�10461020230�0016165�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::borrow::Cow; use std::ops::Deref; use std::{cmp, mem}; use alacritty_terminal::event::EventListener; use alacritty_terminal::grid::{Dimensions, Indexed}; use alacritty_terminal::index::{Column, Line, Point}; use alacritty_terminal::selection::SelectionRange; use alacritty_terminal::term::cell::{Cell, Flags, Hyperlink}; use alacritty_terminal::term::search::{Match, RegexSearch}; use alacritty_terminal::term::{self, RenderableContent as TerminalContent, Term, TermMode}; use alacritty_terminal::vte::ansi::{Color, CursorShape, NamedColor}; use crate::config::UiConfig; use crate::display::color::{CellRgb, List, Rgb, DIM_FACTOR}; use crate::display::hint::{self, HintState}; use crate::display::{Display, SizeInfo}; use crate::event::SearchState; /// Minimum contrast between a fixed cursor color and the cell's background. pub const MIN_CURSOR_CONTRAST: f64 = 1.5; /// Renderable terminal content. /// /// This provides the terminal cursor and an iterator over all non-empty cells. pub struct RenderableContent<'a> { terminal_content: TerminalContent<'a>, cursor: RenderableCursor, cursor_shape: CursorShape, cursor_point: Point<usize>, search: Option<HintMatches<'a>>, hint: Option<Hint<'a>>, config: &'a UiConfig, colors: &'a List, focused_match: Option<&'a Match>, size: &'a SizeInfo, } impl<'a> RenderableContent<'a> { pub fn new<T: EventListener>( config: &'a UiConfig, display: &'a mut Display, term: &'a Term<T>, search_state: &'a mut SearchState, ) -> Self { let search = search_state.dfas().map(|dfas| HintMatches::visible_regex_matches(term, dfas)); let focused_match = search_state.focused_match(); let terminal_content = term.renderable_content(); // Find terminal cursor shape. let cursor_shape = if terminal_content.cursor.shape == CursorShape::Hidden || display.cursor_hidden || search_state.regex().is_some() || display.ime.preedit().is_some() { CursorShape::Hidden } else if !term.is_focused && config.cursor.unfocused_hollow { CursorShape::HollowBlock } else { terminal_content.cursor.shape }; // Convert terminal cursor point to viewport position. let cursor_point = terminal_content.cursor.point; let display_offset = terminal_content.display_offset; let cursor_point = term::point_to_viewport(display_offset, cursor_point).unwrap(); let hint = if display.hint_state.active() { display.hint_state.update_matches(term); Some(Hint::from(&display.hint_state)) } else { None }; Self { colors: &display.colors, size: &display.size_info, cursor: RenderableCursor::new_hidden(), terminal_content, focused_match, cursor_shape, cursor_point, search, config, hint, } } /// Viewport offset. pub fn display_offset(&self) -> usize { self.terminal_content.display_offset } /// Get the terminal cursor. pub fn cursor(mut self) -> RenderableCursor { // Assure this function is only called after the iterator has been drained. debug_assert!(self.next().is_none()); self.cursor } /// Get the RGB value for a color index. pub fn color(&self, color: usize) -> Rgb { self.terminal_content.colors[color].map(Rgb).unwrap_or(self.colors[color]) } pub fn selection_range(&self) -> Option<SelectionRange> { self.terminal_content.selection } /// Assemble the information required to render the terminal cursor. fn renderable_cursor(&mut self, cell: &RenderableCell) -> RenderableCursor { // Cursor colors. let color = if self.terminal_content.mode.contains(TermMode::VI) { self.config.colors.vi_mode_cursor } else { self.config.colors.cursor }; let cursor_color = self.terminal_content.colors[NamedColor::Cursor] .map_or(color.background, |c| CellRgb::Rgb(Rgb(c))); let text_color = color.foreground; let insufficient_contrast = (!matches!(cursor_color, CellRgb::Rgb(_)) || !matches!(text_color, CellRgb::Rgb(_))) && cell.fg.contrast(*cell.bg) < MIN_CURSOR_CONTRAST; // Convert from cell colors to RGB. let mut text_color = text_color.color(cell.fg, cell.bg); let mut cursor_color = cursor_color.color(cell.fg, cell.bg); // Invert cursor color with insufficient contrast to prevent invisible cursors. if insufficient_contrast { cursor_color = self.config.colors.primary.foreground; text_color = self.config.colors.primary.background; } RenderableCursor { is_wide: cell.flags.contains(Flags::WIDE_CHAR), shape: self.cursor_shape, point: self.cursor_point, cursor_color, text_color, } } } impl<'a> Iterator for RenderableContent<'a> { type Item = RenderableCell; /// Gets the next renderable cell. /// /// Skips empty (background) cells and applies any flags to the cell state /// (eg. invert fg and bg colors). #[inline] fn next(&mut self) -> Option<Self::Item> { loop { let cell = self.terminal_content.display_iter.next()?; let mut cell = RenderableCell::new(self, cell); if self.cursor_point == cell.point { // Store the cursor which should be rendered. self.cursor = self.renderable_cursor(&cell); if self.cursor.shape == CursorShape::Block { cell.fg = self.cursor.text_color; cell.bg = self.cursor.cursor_color; // Since we draw Block cursor by drawing cell below it with a proper color, // we must adjust alpha to make it visible. cell.bg_alpha = 1.; } return Some(cell); } else if !cell.is_empty() && !cell.flags.contains(Flags::WIDE_CHAR_SPACER) { // Skip empty cells and wide char spacers. return Some(cell); } } } } /// Cell ready for rendering. #[derive(Clone, Debug)] pub struct RenderableCell { pub character: char, pub point: Point<usize>, pub fg: Rgb, pub bg: Rgb, pub bg_alpha: f32, pub underline: Rgb, pub flags: Flags, pub extra: Option<Box<RenderableCellExtra>>, } /// Extra storage with rarely present fields for [`RenderableCell`], to reduce the cell size we /// pass around. #[derive(Clone, Debug)] pub struct RenderableCellExtra { pub zerowidth: Option<Vec<char>>, pub hyperlink: Option<Hyperlink>, } impl RenderableCell { fn new(content: &mut RenderableContent<'_>, cell: Indexed<&Cell>) -> Self { // Lookup RGB values. let mut fg = Self::compute_fg_rgb(content, cell.fg, cell.flags); let mut bg = Self::compute_bg_rgb(content, cell.bg); let mut bg_alpha = if cell.flags.contains(Flags::INVERSE) { mem::swap(&mut fg, &mut bg); 1.0 } else { Self::compute_bg_alpha(content.config, cell.bg) }; let is_selected = content.terminal_content.selection.map_or(false, |selection| { selection.contains_cell( &cell, content.terminal_content.cursor.point, content.cursor_shape, ) }); let display_offset = content.terminal_content.display_offset; let viewport_start = Point::new(Line(-(display_offset as i32)), Column(0)); let colors = &content.config.colors; let mut character = cell.c; let mut flags = cell.flags; let num_cols = content.size.columns(); if let Some((c, is_first)) = content .hint .as_mut() .and_then(|hint| hint.advance(viewport_start, num_cols, cell.point)) { if is_first { let (config_fg, config_bg) = (colors.hints.start.foreground, colors.hints.start.background); Self::compute_cell_rgb(&mut fg, &mut bg, &mut bg_alpha, config_fg, config_bg); } else if c.is_some() { let (config_fg, config_bg) = (colors.hints.end.foreground, colors.hints.end.background); Self::compute_cell_rgb(&mut fg, &mut bg, &mut bg_alpha, config_fg, config_bg); } else { flags.insert(Flags::UNDERLINE); } character = c.unwrap_or(character); } else if is_selected { let config_fg = colors.selection.foreground; let config_bg = colors.selection.background; Self::compute_cell_rgb(&mut fg, &mut bg, &mut bg_alpha, config_fg, config_bg); if fg == bg && !cell.flags.contains(Flags::HIDDEN) { // Reveal inversed text when fg/bg is the same. fg = content.color(NamedColor::Background as usize); bg = content.color(NamedColor::Foreground as usize); bg_alpha = 1.0; } } else if content.search.as_mut().map_or(false, |search| search.advance(cell.point)) { let focused = content.focused_match.map_or(false, |fm| fm.contains(&cell.point)); let (config_fg, config_bg) = if focused { (colors.search.focused_match.foreground, colors.search.focused_match.background) } else { (colors.search.matches.foreground, colors.search.matches.background) }; Self::compute_cell_rgb(&mut fg, &mut bg, &mut bg_alpha, config_fg, config_bg); } // Apply transparency to all renderable cells if `transparent_background_colors` is set if bg_alpha > 0. && content.config.colors.transparent_background_colors { bg_alpha = content.config.window_opacity(); } // Convert cell point to viewport position. let cell_point = cell.point; let point = term::point_to_viewport(display_offset, cell_point).unwrap(); let underline = cell .underline_color() .map_or(fg, |underline| Self::compute_fg_rgb(content, underline, flags)); let zerowidth = cell.zerowidth(); let hyperlink = cell.hyperlink(); let extra = (zerowidth.is_some() || hyperlink.is_some()).then(|| { Box::new(RenderableCellExtra { zerowidth: zerowidth.map(|zerowidth| zerowidth.to_vec()), hyperlink, }) }); RenderableCell { flags, character, bg_alpha, point, fg, bg, underline, extra } } /// Check if cell contains any renderable content. fn is_empty(&self) -> bool { self.bg_alpha == 0. && self.character == ' ' && self.extra.is_none() && !self.flags.intersects(Flags::ALL_UNDERLINES | Flags::STRIKEOUT) } /// Apply [`CellRgb`] colors to the cell's colors. fn compute_cell_rgb( cell_fg: &mut Rgb, cell_bg: &mut Rgb, bg_alpha: &mut f32, fg: CellRgb, bg: CellRgb, ) { let old_fg = mem::replace(cell_fg, fg.color(*cell_fg, *cell_bg)); *cell_bg = bg.color(old_fg, *cell_bg); if bg != CellRgb::CellBackground { *bg_alpha = 1.0; } } /// Get the RGB color from a cell's foreground color. fn compute_fg_rgb(content: &RenderableContent<'_>, fg: Color, flags: Flags) -> Rgb { let config = &content.config; match fg { Color::Spec(rgb) => match flags & Flags::DIM { Flags::DIM => { let rgb: Rgb = rgb.into(); rgb * DIM_FACTOR }, _ => rgb.into(), }, Color::Named(ansi) => { match (config.draw_bold_text_with_bright_colors(), flags & Flags::DIM_BOLD) { // If no bright foreground is set, treat it like the BOLD flag doesn't exist. (_, Flags::DIM_BOLD) if ansi == NamedColor::Foreground && config.colors.primary.bright_foreground.is_none() => { content.color(NamedColor::DimForeground as usize) }, // Draw bold text in bright colors *and* contains bold flag. (true, Flags::BOLD) => content.color(ansi.to_bright() as usize), // Cell is marked as dim and not bold. (_, Flags::DIM) | (false, Flags::DIM_BOLD) => { content.color(ansi.to_dim() as usize) }, // None of the above, keep original color.. _ => content.color(ansi as usize), } }, Color::Indexed(idx) => { let idx = match ( config.draw_bold_text_with_bright_colors(), flags & Flags::DIM_BOLD, idx, ) { (true, Flags::BOLD, 0..=7) => idx as usize + 8, (false, Flags::DIM, 8..=15) => idx as usize - 8, (false, Flags::DIM, 0..=7) => NamedColor::DimBlack as usize + idx as usize, _ => idx as usize, }; content.color(idx) }, } } /// Get the RGB color from a cell's background color. #[inline] fn compute_bg_rgb(content: &RenderableContent<'_>, bg: Color) -> Rgb { match bg { Color::Spec(rgb) => rgb.into(), Color::Named(ansi) => content.color(ansi as usize), Color::Indexed(idx) => content.color(idx as usize), } } /// Compute background alpha based on cell's original color. /// /// Since an RGB color matching the background should not be transparent, this is computed /// using the named input color, rather than checking the RGB of the background after its color /// is computed. #[inline] fn compute_bg_alpha(config: &UiConfig, bg: Color) -> f32 { if bg == Color::Named(NamedColor::Background) { 0. } else if config.colors.transparent_background_colors { config.window_opacity() } else { 1. } } } /// Cursor storing all information relevant for rendering. #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub struct RenderableCursor { shape: CursorShape, cursor_color: Rgb, text_color: Rgb, is_wide: bool, point: Point<usize>, } impl RenderableCursor { fn new_hidden() -> Self { let shape = CursorShape::Hidden; let cursor_color = Rgb::default(); let text_color = Rgb::default(); let is_wide = false; let point = Point::default(); Self { shape, cursor_color, text_color, is_wide, point } } } impl RenderableCursor { pub fn new(point: Point<usize>, shape: CursorShape, cursor_color: Rgb, is_wide: bool) -> Self { Self { shape, cursor_color, text_color: cursor_color, is_wide, point } } pub fn color(&self) -> Rgb { self.cursor_color } pub fn shape(&self) -> CursorShape { self.shape } pub fn is_wide(&self) -> bool { self.is_wide } pub fn point(&self) -> Point<usize> { self.point } } /// Regex hints for keyboard shortcuts. struct Hint<'a> { /// Hint matches and position. matches: HintMatches<'a>, /// Last match checked against current cell position. labels: &'a Vec<Vec<char>>, } impl<'a> Hint<'a> { /// Advance the hint iterator. /// /// If the point is within a hint, the keyboard shortcut character that should be displayed at /// this position will be returned. /// /// The tuple's [`bool`] will be `true` when the character is the first for this hint. /// /// The tuple's [`Option<char>`] will be [`None`] when the point is part of the match, but not /// part of the hint label. fn advance( &mut self, viewport_start: Point, num_cols: usize, point: Point, ) -> Option<(Option<char>, bool)> { // Check if we're within a match at all. if !self.matches.advance(point) { return None; } // Match starting position on this line; linebreaks interrupt the hint labels. let start = self .matches .get(self.matches.index) .map(|bounds| cmp::max(*bounds.start(), viewport_start))?; // Position within the hint label. let line_delta = point.line.0 - start.line.0; let col_delta = point.column.0 as i32 - start.column.0 as i32; let label_position = usize::try_from(line_delta * num_cols as i32 + col_delta).unwrap_or(0); let is_first = label_position == 0; // Hint label character. let hint_char = self.labels[self.matches.index] .get(label_position) .copied() .map(|c| (Some(c), is_first)) .unwrap_or((None, false)); Some(hint_char) } } impl<'a> From<&'a HintState> for Hint<'a> { fn from(hint_state: &'a HintState) -> Self { let matches = HintMatches::new(hint_state.matches()); Self { labels: hint_state.labels(), matches } } } /// Visible hint match tracking. #[derive(Default)] struct HintMatches<'a> { /// All visible matches. matches: Cow<'a, [Match]>, /// Index of the last match checked. index: usize, } impl<'a> HintMatches<'a> { /// Create new renderable matches iterator.. fn new(matches: impl Into<Cow<'a, [Match]>>) -> Self { Self { matches: matches.into(), index: 0 } } /// Create from regex matches on term visible part. fn visible_regex_matches<T>(term: &Term<T>, dfas: &mut RegexSearch) -> Self { let matches = hint::visible_regex_match_iter(term, dfas).collect::<Vec<_>>(); Self::new(matches) } /// Advance the regex tracker to the next point. /// /// This will return `true` if the point passed is part of a regex match. fn advance(&mut self, point: Point) -> bool { while let Some(bounds) = self.get(self.index) { if bounds.start() > &point { break; } else if bounds.end() < &point { self.index += 1; } else { return true; } } false } } impl<'a> Deref for HintMatches<'a> { type Target = [Match]; fn deref(&self) -> &Self::Target { self.matches.deref() } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/cursor.rs��������������������������������������������������������������0000644�0000000�0000000�00000006054�10461020230�0016027�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Convert a cursor into an iterator of rects. use alacritty_terminal::vte::ansi::CursorShape; use crate::display::color::Rgb; use crate::display::content::RenderableCursor; use crate::display::SizeInfo; use crate::renderer::rects::RenderRect; /// Trait for conversion into the iterator. pub trait IntoRects { /// Consume the cursor for an iterator of rects. fn rects(self, size_info: &SizeInfo, thickness: f32) -> CursorRects; } impl IntoRects for RenderableCursor { fn rects(self, size_info: &SizeInfo, thickness: f32) -> CursorRects { let point = self.point(); let x = point.column.0 as f32 * size_info.cell_width() + size_info.padding_x(); let y = point.line as f32 * size_info.cell_height() + size_info.padding_y(); let mut width = size_info.cell_width(); let height = size_info.cell_height(); let thickness = (thickness * width).round().max(1.); if self.is_wide() { width *= 2.; } match self.shape() { CursorShape::Beam => beam(x, y, height, thickness, self.color()), CursorShape::Underline => underline(x, y, width, height, thickness, self.color()), CursorShape::HollowBlock => hollow(x, y, width, height, thickness, self.color()), _ => CursorRects::default(), } } } /// Cursor rect iterator. #[derive(Default)] pub struct CursorRects { rects: [Option<RenderRect>; 4], index: usize, } impl From<RenderRect> for CursorRects { fn from(rect: RenderRect) -> Self { Self { rects: [Some(rect), None, None, None], index: 0 } } } impl Iterator for CursorRects { type Item = RenderRect; fn next(&mut self) -> Option<Self::Item> { let rect = self.rects.get_mut(self.index)?; self.index += 1; rect.take() } } /// Create an iterator yielding a single beam rect. fn beam(x: f32, y: f32, height: f32, thickness: f32, color: Rgb) -> CursorRects { RenderRect::new(x, y, thickness, height, color, 1.).into() } /// Create an iterator yielding a single underline rect. fn underline(x: f32, y: f32, width: f32, height: f32, thickness: f32, color: Rgb) -> CursorRects { let y = y + height - thickness; RenderRect::new(x, y, width, thickness, color, 1.).into() } /// Create an iterator yielding a rect for each side of the hollow block cursor. fn hollow(x: f32, y: f32, width: f32, height: f32, thickness: f32, color: Rgb) -> CursorRects { let top_line = RenderRect::new(x, y, width, thickness, color, 1.); let vertical_y = y + thickness; let vertical_height = height - 2. * thickness; let left_line = RenderRect::new(x, vertical_y, thickness, vertical_height, color, 1.); let bottom_y = y + height - thickness; let bottom_line = RenderRect::new(x, bottom_y, width, thickness, color, 1.); let right_x = x + width - thickness; let right_line = RenderRect::new(right_x, vertical_y, thickness, vertical_height, color, 1.); CursorRects { rects: [Some(top_line), Some(bottom_line), Some(left_line), Some(right_line)], index: 0, } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/damage.rs��������������������������������������������������������������0000644�0000000�0000000�00000026307�10461020230�0015733�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::iter::Peekable; use std::{cmp, mem}; use glutin::surface::Rect; use alacritty_terminal::index::Point; use alacritty_terminal::selection::SelectionRange; use alacritty_terminal::term::{LineDamageBounds, TermDamageIterator}; use crate::display::SizeInfo; /// State of the damage tracking for the [`Display`]. /// /// [`Display`]: crate::display::Display #[derive(Debug)] pub struct DamageTracker { /// Position of the previously drawn Vi cursor. pub old_vi_cursor: Option<Point<usize>>, /// The location of the old selection. pub old_selection: Option<SelectionRange>, /// Highlight damage submitted for the compositor. pub debug: bool, /// The damage for the frames. frames: [FrameDamage; 2], screen_lines: usize, columns: usize, } impl DamageTracker { pub fn new(screen_lines: usize, columns: usize) -> Self { let mut tracker = Self { columns, screen_lines, debug: false, old_vi_cursor: None, old_selection: None, frames: Default::default(), }; tracker.resize(screen_lines, columns); tracker } #[inline] #[must_use] pub fn frame(&mut self) -> &mut FrameDamage { &mut self.frames[0] } #[inline] #[must_use] pub fn next_frame(&mut self) -> &mut FrameDamage { &mut self.frames[1] } /// Advance to the next frame resetting the state for the active frame. #[inline] pub fn swap_damage(&mut self) { let screen_lines = self.screen_lines; let columns = self.columns; self.frame().reset(screen_lines, columns); self.frames.swap(0, 1); } /// Resize the damage information in the tracker. pub fn resize(&mut self, screen_lines: usize, columns: usize) { self.screen_lines = screen_lines; self.columns = columns; for frame in &mut self.frames { frame.reset(screen_lines, columns); } self.frame().full = true; } /// Damage vi cursor inside the viewport. pub fn damage_vi_cursor(&mut self, mut vi_cursor: Option<Point<usize>>) { mem::swap(&mut self.old_vi_cursor, &mut vi_cursor); if self.frame().full { return; } if let Some(vi_cursor) = self.old_vi_cursor { self.frame().damage_point(vi_cursor); } if let Some(vi_cursor) = vi_cursor { self.frame().damage_point(vi_cursor); } } /// Get shaped frame damage for the active frame. pub fn shape_frame_damage(&self, size_info: SizeInfo<u32>) -> Vec<Rect> { if self.frames[0].full { vec![Rect::new(0, 0, size_info.width() as i32, size_info.height() as i32)] } else { let lines_damage = RenderDamageIterator::new( TermDamageIterator::new(&self.frames[0].lines, 0), &size_info, ); lines_damage.chain(self.frames[0].rects.iter().copied()).collect() } } /// Add the current frame's selection damage. pub fn damage_selection( &mut self, mut selection: Option<SelectionRange>, display_offset: usize, ) { mem::swap(&mut self.old_selection, &mut selection); if self.frame().full || selection == self.old_selection { return; } for selection in self.old_selection.into_iter().chain(selection) { let display_offset = display_offset as i32; let last_visible_line = self.screen_lines as i32 - 1; let columns = self.columns; // Ignore invisible selection. if selection.end.line.0 + display_offset < 0 || selection.start.line.0.abs() < display_offset - last_visible_line { continue; }; let start = cmp::max(selection.start.line.0 + display_offset, 0) as usize; let end = (selection.end.line.0 + display_offset).clamp(0, last_visible_line) as usize; for line in start..=end { self.frame().lines[line].expand(0, columns - 1); } } } } /// Damage state for the rendering frame. #[derive(Debug, Default)] pub struct FrameDamage { /// The entire frame needs to be redrawn. full: bool, /// Terminal lines damaged in the given frame. lines: Vec<LineDamageBounds>, /// Rectangular regions damage in the given frame. rects: Vec<Rect>, } impl FrameDamage { /// Damage line for the given frame. #[inline] pub fn damage_line(&mut self, damage: LineDamageBounds) { self.lines[damage.line].expand(damage.left, damage.right); } #[inline] pub fn damage_point(&mut self, point: Point<usize>) { self.lines[point.line].expand(point.column.0, point.column.0); } /// Mark the frame as fully damaged. #[inline] pub fn mark_fully_damaged(&mut self) { self.full = true; } /// Add viewport rectangle to damage. /// /// This allows covering elements outside of the terminal viewport, like message bar. #[inline] pub fn add_viewport_rect( &mut self, size_info: &SizeInfo, x: i32, y: i32, width: i32, height: i32, ) { let y = viewport_y_to_damage_y(size_info, y, height); self.rects.push(Rect { x, y, width, height }); } fn reset(&mut self, num_lines: usize, num_cols: usize) { self.full = false; self.rects.clear(); self.lines.clear(); self.lines.reserve(num_lines); for line in 0..num_lines { self.lines.push(LineDamageBounds::undamaged(line, num_cols)); } } } /// Convert viewport `y` coordinate to [`Rect`] damage coordinate. pub fn viewport_y_to_damage_y(size_info: &SizeInfo, y: i32, height: i32) -> i32 { size_info.height() as i32 - y - height } /// Convert viewport `y` coordinate to [`Rect`] damage coordinate. pub fn damage_y_to_viewport_y(size_info: &SizeInfo, rect: &Rect) -> i32 { size_info.height() as i32 - rect.y - rect.height } /// Iterator which converts `alacritty_terminal` damage information into renderer damaged rects. struct RenderDamageIterator<'a> { damaged_lines: Peekable<TermDamageIterator<'a>>, size_info: &'a SizeInfo<u32>, } impl<'a> RenderDamageIterator<'a> { pub fn new(damaged_lines: TermDamageIterator<'a>, size_info: &'a SizeInfo<u32>) -> Self { Self { damaged_lines: damaged_lines.peekable(), size_info } } #[inline] fn rect_for_line(&self, line_damage: LineDamageBounds) -> Rect { let size_info = &self.size_info; let y_top = size_info.height() - size_info.padding_y(); let x = size_info.padding_x() + line_damage.left as u32 * size_info.cell_width(); let y = y_top - (line_damage.line + 1) as u32 * size_info.cell_height(); let width = (line_damage.right - line_damage.left + 1) as u32 * size_info.cell_width(); Rect::new(x as i32, y as i32, width as i32, size_info.cell_height() as i32) } // Make sure to damage near cells to include wide chars. #[inline] fn overdamage(size_info: &SizeInfo<u32>, mut rect: Rect) -> Rect { rect.x = (rect.x - size_info.cell_width() as i32).max(0); rect.width = cmp::min( size_info.width() as i32 - rect.x, rect.width + 2 * size_info.cell_width() as i32, ); rect.y = (rect.y - size_info.cell_height() as i32 / 2).max(0); rect.height = cmp::min( size_info.height() as i32 - rect.y, rect.height + size_info.cell_height() as i32, ); rect } } impl<'a> Iterator for RenderDamageIterator<'a> { type Item = Rect; fn next(&mut self) -> Option<Rect> { let line = self.damaged_lines.next()?; let size_info = &self.size_info; let mut total_damage_rect = Self::overdamage(size_info, self.rect_for_line(line)); // Merge rectangles which overlap with each other. while let Some(line) = self.damaged_lines.peek().copied() { let next_rect = Self::overdamage(size_info, self.rect_for_line(line)); if !rects_overlap(total_damage_rect, next_rect) { break; } total_damage_rect = merge_rects(total_damage_rect, next_rect); let _ = self.damaged_lines.next(); } Some(total_damage_rect) } } /// Check if two given [`glutin::surface::Rect`] overlap. fn rects_overlap(lhs: Rect, rhs: Rect) -> bool { !( // `lhs` is left of `rhs`. lhs.x + lhs.width < rhs.x // `lhs` is right of `rhs`. || rhs.x + rhs.width < lhs.x // `lhs` is below `rhs`. || lhs.y + lhs.height < rhs.y // `lhs` is above `rhs`. || rhs.y + rhs.height < lhs.y ) } /// Merge two [`glutin::surface::Rect`] by producing the smallest rectangle that contains both. #[inline] fn merge_rects(lhs: Rect, rhs: Rect) -> Rect { let left_x = cmp::min(lhs.x, rhs.x); let right_x = cmp::max(lhs.x + lhs.width, rhs.x + rhs.width); let y_top = cmp::max(lhs.y + lhs.height, rhs.y + rhs.height); let y_bottom = cmp::min(lhs.y, rhs.y); Rect::new(left_x, y_bottom, right_x - left_x, y_top - y_bottom) } #[cfg(test)] mod tests { use super::*; #[test] fn damage_rect_math() { let rect_side = 10; let cell_size = 4; let bound = 100; let size_info: SizeInfo<u32> = SizeInfo::new( bound as f32, bound as f32, cell_size as f32, cell_size as f32, 2., 2., true, ) .into(); // Test min clamping. let rect = Rect::new(0, 0, rect_side, rect_side); let rect = RenderDamageIterator::overdamage(&size_info, rect); assert_eq!(Rect::new(0, 0, rect_side + 2 * cell_size, 10 + cell_size), rect); // Test max clamping. let rect = Rect::new(bound, bound, rect_side, rect_side); let rect = RenderDamageIterator::overdamage(&size_info, rect); assert_eq!( Rect::new(bound - cell_size, bound - cell_size / 2, cell_size, cell_size / 2), rect ); // Test no clamping. let rect = Rect::new(bound / 2, bound / 2, rect_side, rect_side); let rect = RenderDamageIterator::overdamage(&size_info, rect); assert_eq!( Rect::new( bound / 2 - cell_size, bound / 2 - cell_size / 2, rect_side + 2 * cell_size, rect_side + cell_size ), rect ); } #[test] fn add_viewport_damage() { let mut frame_damage = FrameDamage::default(); let viewport_height = 100.; let x = 0; let y = 40; let height = 5; let width = 10; let size_info = SizeInfo::new(viewport_height, viewport_height, 5., 5., 0., 0., true); frame_damage.add_viewport_rect(&size_info, x, y, width, height); assert_eq!(frame_damage.rects[0], Rect { x, y: viewport_height as i32 - y - height, width, height }); assert_eq!(frame_damage.rects[0].y, viewport_y_to_damage_y(&size_info, y, height)); assert_eq!(damage_y_to_viewport_y(&size_info, &frame_damage.rects[0]), y); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/hint.rs����������������������������������������������������������������0000644�0000000�0000000�00000054120�10461020230�0015451�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::cmp::Reverse; use std::collections::HashSet; use std::iter; use ahash::RandomState; use winit::keyboard::ModifiersState; use alacritty_terminal::grid::{BidirectionalIterator, Dimensions}; use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point}; use alacritty_terminal::term::cell::Hyperlink; use alacritty_terminal::term::search::{Match, RegexIter, RegexSearch}; use alacritty_terminal::term::{Term, TermMode}; use crate::config::ui_config::{Hint, HintAction}; use crate::config::UiConfig; /// Maximum number of linewraps followed outside of the viewport during search highlighting. pub const MAX_SEARCH_LINES: usize = 100; /// Percentage of characters in the hints alphabet used for the last character. const HINT_SPLIT_PERCENTAGE: f32 = 0.5; /// Keyboard regex hint state. pub struct HintState { /// Hint currently in use. hint: Option<Hint>, /// Alphabet for hint labels. alphabet: String, /// Visible matches. matches: Vec<Match>, /// Key label for each visible match. labels: Vec<Vec<char>>, /// Keys pressed for hint selection. keys: Vec<char>, } impl HintState { /// Initialize an inactive hint state. pub fn new<S: Into<String>>(alphabet: S) -> Self { Self { alphabet: alphabet.into(), hint: Default::default(), matches: Default::default(), labels: Default::default(), keys: Default::default(), } } /// Check if a hint selection is in progress. pub fn active(&self) -> bool { self.hint.is_some() } /// Start the hint selection process. pub fn start(&mut self, hint: Hint) { self.hint = Some(hint); } /// Cancel the hint highlighting process. fn stop(&mut self) { self.matches.clear(); self.labels.clear(); self.keys.clear(); self.hint = None; } /// Update the visible hint matches and key labels. pub fn update_matches<T>(&mut self, term: &Term<T>) { let hint = match self.hint.as_mut() { Some(hint) => hint, None => return, }; // Clear current matches. self.matches.clear(); // Add escape sequence hyperlinks. if hint.content.hyperlinks { self.matches.extend(visible_unique_hyperlinks_iter(term)); } // Add visible regex matches. if let Some(regex) = hint.content.regex.as_ref() { regex.with_compiled(|regex| { let matches = visible_regex_match_iter(term, regex); // Apply post-processing and search for sub-matches if necessary. if hint.post_processing { let mut matches = matches.collect::<Vec<_>>(); self.matches.extend(matches.drain(..).flat_map(|rm| { HintPostProcessor::new(term, regex, rm).collect::<Vec<_>>() })); } else { self.matches.extend(matches); } }); } // Cancel highlight with no visible matches. if self.matches.is_empty() { self.stop(); return; } // Sort and dedup ranges. Currently overlapped but not exactly same ranges are kept. self.matches.sort_by_key(|bounds| (*bounds.start(), Reverse(*bounds.end()))); self.matches.dedup_by_key(|bounds| *bounds.start()); let mut generator = HintLabels::new(&self.alphabet, HINT_SPLIT_PERCENTAGE); let match_count = self.matches.len(); let keys_len = self.keys.len(); // Get the label for each match. self.labels.resize(match_count, Vec::new()); for i in (0..match_count).rev() { let mut label = generator.next(); if label.len() >= keys_len && label[..keys_len] == self.keys[..] { self.labels[i] = label.split_off(keys_len); } else { self.labels[i] = Vec::new(); } } } /// Handle keyboard input during hint selection. pub fn keyboard_input<T>(&mut self, term: &Term<T>, c: char) -> Option<HintMatch> { match c { // Use backspace to remove the last character pressed. '\x08' | '\x1f' => { self.keys.pop(); }, // Cancel hint highlighting on ESC/Ctrl+c. '\x1b' | '\x03' => self.stop(), _ => (), } // Update the visible matches. self.update_matches(term); let hint = self.hint.as_ref()?; // Find the last label starting with the input character. let mut labels = self.labels.iter().enumerate().rev(); let (index, label) = labels.find(|(_, label)| !label.is_empty() && label[0] == c)?; // Check if the selected label is fully matched. if label.len() == 1 { let bounds = self.matches[index].clone(); let action = hint.action.clone(); // Exit hint mode unless it requires explicit dismissal. if hint.persist { self.keys.clear(); } else { self.stop(); } // Hyperlinks take precedence over regex matches. let hyperlink = term.grid()[*bounds.start()].hyperlink(); Some(HintMatch { action, bounds, hyperlink }) } else { // Store character to preserve the selection. self.keys.push(c); None } } /// Hint key labels. pub fn labels(&self) -> &Vec<Vec<char>> { &self.labels } /// Visible hint regex matches. pub fn matches(&self) -> &[Match] { &self.matches } /// Update the alphabet used for hint labels. pub fn update_alphabet(&mut self, alphabet: &str) { if self.alphabet != alphabet { self.alphabet = alphabet.to_owned(); self.keys.clear(); } } } /// Hint match which was selected by the user. #[derive(PartialEq, Eq, Debug, Clone)] pub struct HintMatch { /// Action for handling the text. action: HintAction, /// Terminal range matching the hint. bounds: Match, hyperlink: Option<Hyperlink>, } impl HintMatch { #[inline] pub fn should_highlight(&self, point: Point, pointed_hyperlink: Option<&Hyperlink>) -> bool { self.hyperlink.as_ref() == pointed_hyperlink && (self.hyperlink.is_some() || self.bounds.contains(&point)) } #[inline] pub fn action(&self) -> &HintAction { &self.action } #[inline] pub fn bounds(&self) -> &Match { &self.bounds } pub fn hyperlink(&self) -> Option<&Hyperlink> { self.hyperlink.as_ref() } } /// Generator for creating new hint labels. struct HintLabels { /// Full character set available. alphabet: Vec<char>, /// Alphabet indices for the next label. indices: Vec<usize>, /// Point separating the alphabet's head and tail characters. /// /// To make identification of the tail character easy, part of the alphabet cannot be used for /// any other position. /// /// All characters in the alphabet before this index will be used for the last character, while /// the rest will be used for everything else. split_point: usize, } impl HintLabels { /// Create a new label generator. /// /// The `split_ratio` should be a number between 0.0 and 1.0 representing the percentage of /// elements in the alphabet which are reserved for the tail of the hint label. fn new(alphabet: impl Into<String>, split_ratio: f32) -> Self { let alphabet: Vec<char> = alphabet.into().chars().collect(); let split_point = ((alphabet.len() - 1) as f32 * split_ratio.min(1.)) as usize; Self { indices: vec![0], split_point, alphabet } } /// Get the characters for the next label. fn next(&mut self) -> Vec<char> { let characters = self.indices.iter().rev().map(|index| self.alphabet[*index]).collect(); self.increment(); characters } /// Increment the character sequence. fn increment(&mut self) { // Increment the last character; if it's not at the split point we're done. let tail = &mut self.indices[0]; if *tail < self.split_point { *tail += 1; return; } *tail = 0; // Increment all other characters in reverse order. let alphabet_len = self.alphabet.len(); for index in self.indices.iter_mut().skip(1) { if *index + 1 == alphabet_len { // Reset character and move to the next if it's already at the limit. *index = self.split_point + 1; } else { // If the character can be incremented, we're done. *index += 1; return; } } // Extend the sequence with another character when nothing could be incremented. self.indices.push(self.split_point + 1); } } /// Iterate over all visible regex matches. pub fn visible_regex_match_iter<'a, T>( term: &'a Term<T>, regex: &'a mut RegexSearch, ) -> impl Iterator<Item = Match> + 'a { let viewport_start = Line(-(term.grid().display_offset() as i32)); let viewport_end = viewport_start + term.bottommost_line(); let mut start = term.line_search_left(Point::new(viewport_start, Column(0))); let mut end = term.line_search_right(Point::new(viewport_end, Column(0))); start.line = start.line.max(viewport_start - MAX_SEARCH_LINES); end.line = end.line.min(viewport_end + MAX_SEARCH_LINES); RegexIter::new(start, end, Direction::Right, term, regex) .skip_while(move |rm| rm.end().line < viewport_start) .take_while(move |rm| rm.start().line <= viewport_end) } /// Iterate over all visible hyperlinks, yanking only unique ones. pub fn visible_unique_hyperlinks_iter<T>(term: &Term<T>) -> impl Iterator<Item = Match> + '_ { let mut display_iter = term.grid().display_iter().peekable(); // Avoid creating hints for the same hyperlinks, but from a different places. let mut unique_hyperlinks = HashSet::<Hyperlink, RandomState>::default(); iter::from_fn(move || { // Find the start of the next unique hyperlink. let (cell, hyperlink) = display_iter.find_map(|cell| { let hyperlink = cell.hyperlink()?; (!unique_hyperlinks.contains(&hyperlink)).then(|| { unique_hyperlinks.insert(hyperlink.clone()); (cell, hyperlink) }) })?; let start = cell.point; let mut end = start; // Find the end bound of just found unique hyperlink. while let Some(next_cell) = display_iter.peek() { // Cell at display iter doesn't match, yield the hyperlink and start over with // `find_map`. if next_cell.hyperlink().as_ref() != Some(&hyperlink) { break; } // Advance to the next cell. end = next_cell.point; let _ = display_iter.next(); } Some(start..=end) }) } /// Retrieve the match, if the specified point is inside the content matching the regex. fn regex_match_at<T>( term: &Term<T>, point: Point, regex: &mut RegexSearch, post_processing: bool, ) -> Option<Match> { let regex_match = visible_regex_match_iter(term, regex).find(|rm| rm.contains(&point))?; // Apply post-processing and search for sub-matches if necessary. if post_processing { HintPostProcessor::new(term, regex, regex_match).find(|rm| rm.contains(&point)) } else { Some(regex_match) } } /// Check if there is a hint highlighted at the specified point. pub fn highlighted_at<T>( term: &Term<T>, config: &UiConfig, point: Point, mouse_mods: ModifiersState, ) -> Option<HintMatch> { let mouse_mode = term.mode().intersects(TermMode::MOUSE_MODE); config.hints.enabled.iter().find_map(|hint| { // Check if all required modifiers are pressed. let highlight = hint.mouse.map_or(false, |mouse| { mouse.enabled && mouse_mods.contains(mouse.mods.0) && (!mouse_mode || mouse_mods.contains(ModifiersState::SHIFT)) }); if !highlight { return None; } if let Some((hyperlink, bounds)) = hint.content.hyperlinks.then(|| hyperlink_at(term, point)).flatten() { return Some(HintMatch { bounds, action: hint.action.clone(), hyperlink: Some(hyperlink), }); } let bounds = hint.content.regex.as_ref().and_then(|regex| { regex.with_compiled(|regex| regex_match_at(term, point, regex, hint.post_processing)) }); if let Some(bounds) = bounds.flatten() { return Some(HintMatch { bounds, action: hint.action.clone(), hyperlink: None }); } None }) } /// Retrieve the hyperlink with its range, if there is one at the specified point. /// /// This will only return contiguous cells, even if another hyperlink with the same ID exists. fn hyperlink_at<T>(term: &Term<T>, point: Point) -> Option<(Hyperlink, Match)> { let hyperlink = term.grid()[point].hyperlink()?; let grid = term.grid(); let mut match_end = point; for cell in grid.iter_from(point) { if cell.hyperlink().map_or(false, |link| link == hyperlink) { match_end = cell.point; } else { break; } } let mut match_start = point; let mut iter = grid.iter_from(point); while let Some(cell) = iter.prev() { if cell.hyperlink().map_or(false, |link| link == hyperlink) { match_start = cell.point; } else { break; } } Some((hyperlink, match_start..=match_end)) } /// Iterator over all post-processed matches inside an existing hint match. struct HintPostProcessor<'a, T> { /// Regex search DFAs. regex: &'a mut RegexSearch, /// Terminal reference. term: &'a Term<T>, /// Next hint match in the iterator. next_match: Option<Match>, /// Start point for the next search. start: Point, /// End point for the hint match iterator. end: Point, } impl<'a, T> HintPostProcessor<'a, T> { /// Create a new iterator for an unprocessed match. fn new(term: &'a Term<T>, regex: &'a mut RegexSearch, regex_match: Match) -> Self { let mut post_processor = Self { next_match: None, start: *regex_match.start(), end: *regex_match.end(), term, regex, }; // Post-process the first hint match. post_processor.next_processed_match(regex_match); post_processor } /// Apply some hint post processing heuristics. /// /// This will check the end of the hint and make it shorter if certain characters are determined /// to be unlikely to be intentionally part of the hint. /// /// This is most useful for identifying URLs appropriately. fn hint_post_processing(&self, regex_match: &Match) -> Option<Match> { let mut iter = self.term.grid().iter_from(*regex_match.start()); let mut c = iter.cell().c; // Truncate uneven number of brackets. let end = *regex_match.end(); let mut open_parents = 0; let mut open_brackets = 0; loop { match c { '(' => open_parents += 1, '[' => open_brackets += 1, ')' => { if open_parents == 0 { iter.prev(); break; } else { open_parents -= 1; } }, ']' => { if open_brackets == 0 { iter.prev(); break; } else { open_brackets -= 1; } }, _ => (), } if iter.point() == end { break; } match iter.next() { Some(indexed) => c = indexed.cell.c, None => break, } } // Truncate trailing characters which are likely to be delimiters. let start = *regex_match.start(); while iter.point() != start { if !matches!(c, '.' | ',' | ':' | ';' | '?' | '!' | '(' | '[' | '\'') { break; } match iter.prev() { Some(indexed) => c = indexed.cell.c, None => break, } } if start > iter.point() { None } else { Some(start..=iter.point()) } } /// Loop over submatches until a non-empty post-processed match is found. fn next_processed_match(&mut self, mut regex_match: Match) { self.next_match = loop { if let Some(next_match) = self.hint_post_processing(®ex_match) { self.start = next_match.end().add(self.term, Boundary::Grid, 1); break Some(next_match); } self.start = regex_match.start().add(self.term, Boundary::Grid, 1); if self.start > self.end { return; } match self.term.regex_search_right(self.regex, self.start, self.end) { Some(rm) => regex_match = rm, None => return, } }; } } impl<'a, T> Iterator for HintPostProcessor<'a, T> { type Item = Match; fn next(&mut self) -> Option<Self::Item> { let next_match = self.next_match.take()?; if self.start <= self.end { if let Some(rm) = self.term.regex_search_right(self.regex, self.start, self.end) { self.next_processed_match(rm); } } Some(next_match) } } #[cfg(test)] mod tests { use alacritty_terminal::index::{Column, Line}; use alacritty_terminal::term::test::mock_term; use alacritty_terminal::vte::ansi::Handler; use super::*; #[test] fn hint_label_generation() { let mut generator = HintLabels::new("0123", 0.5); assert_eq!(generator.next(), vec!['0']); assert_eq!(generator.next(), vec!['1']); assert_eq!(generator.next(), vec!['2', '0']); assert_eq!(generator.next(), vec!['2', '1']); assert_eq!(generator.next(), vec!['3', '0']); assert_eq!(generator.next(), vec!['3', '1']); assert_eq!(generator.next(), vec!['2', '2', '0']); assert_eq!(generator.next(), vec!['2', '2', '1']); assert_eq!(generator.next(), vec!['2', '3', '0']); assert_eq!(generator.next(), vec!['2', '3', '1']); assert_eq!(generator.next(), vec!['3', '2', '0']); assert_eq!(generator.next(), vec!['3', '2', '1']); assert_eq!(generator.next(), vec!['3', '3', '0']); assert_eq!(generator.next(), vec!['3', '3', '1']); assert_eq!(generator.next(), vec!['2', '2', '2', '0']); assert_eq!(generator.next(), vec!['2', '2', '2', '1']); assert_eq!(generator.next(), vec!['2', '2', '3', '0']); assert_eq!(generator.next(), vec!['2', '2', '3', '1']); assert_eq!(generator.next(), vec!['2', '3', '2', '0']); assert_eq!(generator.next(), vec!['2', '3', '2', '1']); assert_eq!(generator.next(), vec!['2', '3', '3', '0']); assert_eq!(generator.next(), vec!['2', '3', '3', '1']); assert_eq!(generator.next(), vec!['3', '2', '2', '0']); assert_eq!(generator.next(), vec!['3', '2', '2', '1']); assert_eq!(generator.next(), vec!['3', '2', '3', '0']); assert_eq!(generator.next(), vec!['3', '2', '3', '1']); assert_eq!(generator.next(), vec!['3', '3', '2', '0']); assert_eq!(generator.next(), vec!['3', '3', '2', '1']); assert_eq!(generator.next(), vec!['3', '3', '3', '0']); assert_eq!(generator.next(), vec!['3', '3', '3', '1']); } #[test] fn closed_bracket_does_not_result_in_infinite_iterator() { let term = mock_term(" ) "); let mut search = RegexSearch::new("[^/ ]").unwrap(); let count = HintPostProcessor::new( &term, &mut search, Point::new(Line(0), Column(1))..=Point::new(Line(0), Column(1)), ) .take(1) .count(); assert_eq!(count, 0); } #[test] fn collect_unique_hyperlinks() { let mut term = mock_term("000\r\n111"); term.goto(0, 0); let hyperlink_foo = Hyperlink::new(Some("1"), String::from("foo")); let hyperlink_bar = Hyperlink::new(Some("2"), String::from("bar")); // Create 2 hyperlinks on the first line. term.set_hyperlink(Some(hyperlink_foo.clone().into())); term.input('b'); term.input('a'); term.set_hyperlink(Some(hyperlink_bar.clone().into())); term.input('r'); term.set_hyperlink(Some(hyperlink_foo.clone().into())); term.goto(1, 0); // Ditto for the second line. term.set_hyperlink(Some(hyperlink_foo.into())); term.input('b'); term.input('a'); term.set_hyperlink(Some(hyperlink_bar.into())); term.input('r'); term.set_hyperlink(None); let mut unique_hyperlinks = visible_unique_hyperlinks_iter(&term); assert_eq!( Some(Match::new(Point::new(Line(0), Column(0)), Point::new(Line(0), Column(1)))), unique_hyperlinks.next() ); assert_eq!( Some(Match::new(Point::new(Line(0), Column(2)), Point::new(Line(0), Column(2)))), unique_hyperlinks.next() ); assert_eq!(None, unique_hyperlinks.next()); } #[test] fn visible_regex_match_covers_entire_viewport() { let content = "I'm a match!\r\n".repeat(4096); // The Term returned from this call will have a viewport starting at 0 and ending at 4096. // That's good enough for this test, since it only cares about visible content. let term = mock_term(&content); let mut regex = RegexSearch::new("match!").unwrap(); // The iterator should match everything in the viewport. assert_eq!(visible_regex_match_iter(&term, &mut regex).count(), 4096); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/meter.rs���������������������������������������������������������������0000644�0000000�0000000�00000004160�10461020230�0015622�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Rendering time meter. //! //! Used to track rendering times and provide moving averages. //! //! # Examples //! //! ```rust //! // create a meter //! let mut meter = alacritty_terminal::meter::Meter::new(); //! //! // Sample something. //! { //! let _sampler = meter.sampler(); //! } //! //! // Get the moving average. The meter tracks a fixed number of samples, and //! // the average won't mean much until it's filled up at least once. //! println!("Average time: {}", meter.average()); //! ``` use std::time::{Duration, Instant}; const NUM_SAMPLES: usize = 10; /// The meter. #[derive(Default)] pub struct Meter { /// Track last 60 timestamps. times: [f64; NUM_SAMPLES], /// Average sample time in microseconds. avg: f64, /// Index of next time to update. index: usize, } /// Sampler. /// /// Samplers record how long they are "alive" for and update the meter on drop.. pub struct Sampler<'a> { /// Reference to meter that created the sampler. meter: &'a mut Meter, /// When the sampler was created. created_at: Instant, } impl<'a> Sampler<'a> { fn new(meter: &'a mut Meter) -> Sampler<'a> { Sampler { meter, created_at: Instant::now() } } #[inline] fn alive_duration(&self) -> Duration { self.created_at.elapsed() } } impl<'a> Drop for Sampler<'a> { fn drop(&mut self) { self.meter.add_sample(self.alive_duration()); } } impl Meter { /// Get a sampler. pub fn sampler(&mut self) -> Sampler<'_> { Sampler::new(self) } /// Get the current average sample duration in microseconds. pub fn average(&self) -> f64 { self.avg } /// Add a sample. /// /// Used by Sampler::drop. fn add_sample(&mut self, sample: Duration) { let mut usec = 0f64; usec += f64::from(sample.subsec_nanos()) / 1e3; usec += (sample.as_secs() as f64) * 1e6; let prev = self.times[self.index]; self.times[self.index] = usec; self.avg -= prev / NUM_SAMPLES as f64; self.avg += usec / NUM_SAMPLES as f64; self.index = (self.index + 1) % NUM_SAMPLES; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/mod.rs�����������������������������������������������������������������0000644�0000000�0000000�00000152072�10461020230�0015273�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! The display subsystem including window management, font rasterization, and //! GPU drawing. use std::cmp; use std::fmt::{self, Formatter}; use std::mem::{self, ManuallyDrop}; use std::num::NonZeroU32; use std::ops::{Deref, DerefMut}; use std::time::{Duration, Instant}; use glutin::context::{NotCurrentContext, PossiblyCurrentContext}; use glutin::prelude::*; use glutin::surface::{Surface, SwapInterval, WindowSurface}; use log::{debug, info}; use parking_lot::MutexGuard; use raw_window_handle::RawWindowHandle; use serde::{Deserialize, Serialize}; use winit::dpi::PhysicalSize; use winit::keyboard::ModifiersState; use winit::window::CursorIcon; use crossfont::{Rasterize, Rasterizer, Size as FontSize}; use unicode_width::UnicodeWidthChar; use alacritty_terminal::event::{EventListener, OnResize, WindowSize}; use alacritty_terminal::grid::Dimensions as TermDimensions; use alacritty_terminal::index::{Column, Direction, Line, Point}; use alacritty_terminal::selection::Selection; use alacritty_terminal::term::cell::Flags; use alacritty_terminal::term::{ self, point_to_viewport, LineDamageBounds, Term, TermDamage, TermMode, MIN_COLUMNS, MIN_SCREEN_LINES, }; use alacritty_terminal::vte::ansi::{CursorShape, NamedColor}; use crate::config::font::Font; use crate::config::window::Dimensions; #[cfg(not(windows))] use crate::config::window::StartupMode; use crate::config::UiConfig; use crate::display::bell::VisualBell; use crate::display::color::{List, Rgb}; use crate::display::content::{RenderableContent, RenderableCursor}; use crate::display::cursor::IntoRects; use crate::display::damage::{damage_y_to_viewport_y, DamageTracker}; use crate::display::hint::{HintMatch, HintState}; use crate::display::meter::Meter; use crate::display::window::Window; use crate::event::{Event, EventType, Mouse, SearchState}; use crate::message_bar::{MessageBuffer, MessageType}; use crate::renderer::rects::{RenderLine, RenderLines, RenderRect}; use crate::renderer::{self, GlyphCache, Renderer}; use crate::scheduler::{Scheduler, TimerId, Topic}; use crate::string::{ShortenDirection, StrShortener}; pub mod color; pub mod content; pub mod cursor; pub mod hint; pub mod window; mod bell; mod damage; mod meter; /// Label for the forward terminal search bar. const FORWARD_SEARCH_LABEL: &str = "Search: "; /// Label for the backward terminal search bar. const BACKWARD_SEARCH_LABEL: &str = "Backward Search: "; /// The character used to shorten the visible text like uri preview or search regex. const SHORTENER: char = '…'; /// Color which is used to highlight damaged rects when debugging. const DAMAGE_RECT_COLOR: Rgb = Rgb::new(255, 0, 255); #[derive(Debug)] pub enum Error { /// Error with window management. Window(window::Error), /// Error dealing with fonts. Font(crossfont::Error), /// Error in renderer. Render(renderer::Error), /// Error during context operations. Context(glutin::error::Error), } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Error::Window(err) => err.source(), Error::Font(err) => err.source(), Error::Render(err) => err.source(), Error::Context(err) => err.source(), } } } impl fmt::Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Error::Window(err) => err.fmt(f), Error::Font(err) => err.fmt(f), Error::Render(err) => err.fmt(f), Error::Context(err) => err.fmt(f), } } } impl From<window::Error> for Error { fn from(val: window::Error) -> Self { Error::Window(val) } } impl From<crossfont::Error> for Error { fn from(val: crossfont::Error) -> Self { Error::Font(val) } } impl From<renderer::Error> for Error { fn from(val: renderer::Error) -> Self { Error::Render(val) } } impl From<glutin::error::Error> for Error { fn from(val: glutin::error::Error) -> Self { Error::Context(val) } } /// Terminal size info. #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq)] pub struct SizeInfo<T = f32> { /// Terminal window width. width: T, /// Terminal window height. height: T, /// Width of individual cell. cell_width: T, /// Height of individual cell. cell_height: T, /// Horizontal window padding. padding_x: T, /// Vertical window padding. padding_y: T, /// Number of lines in the viewport. screen_lines: usize, /// Number of columns in the viewport. columns: usize, } impl From<SizeInfo<f32>> for SizeInfo<u32> { fn from(size_info: SizeInfo<f32>) -> Self { Self { width: size_info.width as u32, height: size_info.height as u32, cell_width: size_info.cell_width as u32, cell_height: size_info.cell_height as u32, padding_x: size_info.padding_x as u32, padding_y: size_info.padding_y as u32, screen_lines: size_info.screen_lines, columns: size_info.screen_lines, } } } impl From<SizeInfo<f32>> for WindowSize { fn from(size_info: SizeInfo<f32>) -> Self { Self { num_cols: size_info.columns() as u16, num_lines: size_info.screen_lines() as u16, cell_width: size_info.cell_width() as u16, cell_height: size_info.cell_height() as u16, } } } impl<T: Clone + Copy> SizeInfo<T> { #[inline] pub fn width(&self) -> T { self.width } #[inline] pub fn height(&self) -> T { self.height } #[inline] pub fn cell_width(&self) -> T { self.cell_width } #[inline] pub fn cell_height(&self) -> T { self.cell_height } #[inline] pub fn padding_x(&self) -> T { self.padding_x } #[inline] pub fn padding_y(&self) -> T { self.padding_y } } impl SizeInfo<f32> { #[allow(clippy::too_many_arguments)] pub fn new( width: f32, height: f32, cell_width: f32, cell_height: f32, mut padding_x: f32, mut padding_y: f32, dynamic_padding: bool, ) -> SizeInfo { if dynamic_padding { padding_x = Self::dynamic_padding(padding_x.floor(), width, cell_width); padding_y = Self::dynamic_padding(padding_y.floor(), height, cell_height); } let lines = (height - 2. * padding_y) / cell_height; let screen_lines = cmp::max(lines as usize, MIN_SCREEN_LINES); let columns = (width - 2. * padding_x) / cell_width; let columns = cmp::max(columns as usize, MIN_COLUMNS); SizeInfo { width, height, cell_width, cell_height, padding_x: padding_x.floor(), padding_y: padding_y.floor(), screen_lines, columns, } } #[inline] pub fn reserve_lines(&mut self, count: usize) { self.screen_lines = cmp::max(self.screen_lines.saturating_sub(count), MIN_SCREEN_LINES); } /// Check if coordinates are inside the terminal grid. /// /// The padding, message bar or search are not counted as part of the grid. #[inline] pub fn contains_point(&self, x: usize, y: usize) -> bool { x <= (self.padding_x + self.columns as f32 * self.cell_width) as usize && x > self.padding_x as usize && y <= (self.padding_y + self.screen_lines as f32 * self.cell_height) as usize && y > self.padding_y as usize } /// Calculate padding to spread it evenly around the terminal content. #[inline] fn dynamic_padding(padding: f32, dimension: f32, cell_dimension: f32) -> f32 { padding + ((dimension - 2. * padding) % cell_dimension) / 2. } } impl TermDimensions for SizeInfo { #[inline] fn columns(&self) -> usize { self.columns } #[inline] fn screen_lines(&self) -> usize { self.screen_lines } #[inline] fn total_lines(&self) -> usize { self.screen_lines() } } #[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct DisplayUpdate { pub dirty: bool, dimensions: Option<PhysicalSize<u32>>, cursor_dirty: bool, font: Option<Font>, } impl DisplayUpdate { pub fn dimensions(&self) -> Option<PhysicalSize<u32>> { self.dimensions } pub fn font(&self) -> Option<&Font> { self.font.as_ref() } pub fn cursor_dirty(&self) -> bool { self.cursor_dirty } pub fn set_dimensions(&mut self, dimensions: PhysicalSize<u32>) { self.dimensions = Some(dimensions); self.dirty = true; } pub fn set_font(&mut self, font: Font) { self.font = Some(font); self.dirty = true; } pub fn set_cursor_dirty(&mut self) { self.cursor_dirty = true; self.dirty = true; } } /// The display wraps a window, font rasterizer, and GPU renderer. pub struct Display { pub window: Window, pub size_info: SizeInfo, /// Hint highlighted by the mouse. pub highlighted_hint: Option<HintMatch>, /// Hint highlighted by the vi mode cursor. pub vi_highlighted_hint: Option<HintMatch>, pub raw_window_handle: RawWindowHandle, /// UI cursor visibility for blinking. pub cursor_hidden: bool, pub visual_bell: VisualBell, /// Mapped RGB values for each terminal color. pub colors: List, /// State of the keyboard hints. pub hint_state: HintState, /// Unprocessed display updates. pub pending_update: DisplayUpdate, /// The renderer update that takes place only once before the actual rendering. pub pending_renderer_update: Option<RendererUpdate>, /// The ime on the given display. pub ime: Ime, /// The state of the timer for frame scheduling. pub frame_timer: FrameTimer, /// Damage tracker for the given display. pub damage_tracker: DamageTracker, /// Font size used by the window. pub font_size: FontSize, // Mouse point position when highlighting hints. hint_mouse_point: Option<Point>, renderer: ManuallyDrop<Renderer>, surface: ManuallyDrop<Surface<WindowSurface>>, context: ManuallyDrop<Replaceable<PossiblyCurrentContext>>, glyph_cache: GlyphCache, meter: Meter, } impl Display { pub fn new( window: Window, gl_context: NotCurrentContext, config: &UiConfig, _tabbed: bool, ) -> Result<Display, Error> { let raw_window_handle = window.raw_window_handle(); let scale_factor = window.scale_factor as f32; let rasterizer = Rasterizer::new()?; let font_size = config.font.size().scale(scale_factor); debug!("Loading \"{}\" font", &config.font.normal().family); let font = config.font.clone().with_size(font_size); let mut glyph_cache = GlyphCache::new(rasterizer, &font)?; let metrics = glyph_cache.font_metrics(); let (cell_width, cell_height) = compute_cell_size(config, &metrics); // Resize the window to account for the user configured size. if let Some(dimensions) = config.window.dimensions() { let size = window_size(config, dimensions, cell_width, cell_height, scale_factor); window.request_inner_size(size); } // Create the GL surface to draw into. let surface = renderer::platform::create_gl_surface( &gl_context, window.inner_size(), window.raw_window_handle(), )?; // Make the context current. let context = gl_context.make_current(&surface)?; // Create renderer. let mut renderer = Renderer::new(&context, config.debug.renderer)?; // Load font common glyphs to accelerate rendering. debug!("Filling glyph cache with common glyphs"); renderer.with_loader(|mut api| { glyph_cache.reset_glyph_cache(&mut api); }); let padding = config.window.padding(window.scale_factor as f32); let viewport_size = window.inner_size(); // Create new size with at least one column and row. let size_info = SizeInfo::new( viewport_size.width as f32, viewport_size.height as f32, cell_width, cell_height, padding.0, padding.1, config.window.dynamic_padding && config.window.dimensions().is_none(), ); info!("Cell size: {} x {}", cell_width, cell_height); info!("Padding: {} x {}", size_info.padding_x(), size_info.padding_y()); info!("Width: {}, Height: {}", size_info.width(), size_info.height()); // Update OpenGL projection. renderer.resize(&size_info); // Clear screen. let background_color = config.colors.primary.background; renderer.clear(background_color, config.window_opacity()); // Disable shadows for transparent windows on macOS. #[cfg(target_os = "macos")] window.set_has_shadow(config.window_opacity() >= 1.0); let is_wayland = matches!(raw_window_handle, RawWindowHandle::Wayland(_)); // On Wayland we can safely ignore this call, since the window isn't visible until you // actually draw something into it and commit those changes. if !is_wayland { surface.swap_buffers(&context).expect("failed to swap buffers."); renderer.finish(); } // Set resize increments for the newly created window. if config.window.resize_increments { window.set_resize_increments(PhysicalSize::new(cell_width, cell_height)); } window.set_visible(true); #[allow(clippy::single_match)] #[cfg(not(windows))] if !_tabbed { match config.window.startup_mode { #[cfg(target_os = "macos")] StartupMode::SimpleFullscreen => window.set_simple_fullscreen(true), StartupMode::Maximized if !is_wayland => window.set_maximized(true), _ => (), } } let hint_state = HintState::new(config.hints.alphabet()); let mut damage_tracker = DamageTracker::new(size_info.screen_lines(), size_info.columns()); damage_tracker.debug = config.debug.highlight_damage; // Disable vsync. if let Err(err) = surface.set_swap_interval(&context, SwapInterval::DontWait) { info!("Failed to disable vsync: {}", err); } Ok(Self { context: ManuallyDrop::new(Replaceable::new(context)), visual_bell: VisualBell::from(&config.bell), renderer: ManuallyDrop::new(renderer), surface: ManuallyDrop::new(surface), colors: List::from(&config.colors), frame_timer: FrameTimer::new(), raw_window_handle, damage_tracker, glyph_cache, hint_state, size_info, font_size, window, pending_renderer_update: Default::default(), vi_highlighted_hint: Default::default(), highlighted_hint: Default::default(), hint_mouse_point: Default::default(), pending_update: Default::default(), cursor_hidden: Default::default(), meter: Default::default(), ime: Default::default(), }) } #[inline] pub fn gl_context(&self) -> &PossiblyCurrentContext { self.context.get() } pub fn make_not_current(&mut self) { if self.context.get().is_current() { self.context.replace_with(|context| { context .make_not_current() .expect("failed to disable context") .treat_as_possibly_current() }); } } pub fn make_current(&self) { if !self.context.get().is_current() { self.context.make_current(&self.surface).expect("failed to make context current") } } fn swap_buffers(&self) { #[allow(clippy::single_match)] let res = match (self.surface.deref(), &self.context.get()) { #[cfg(not(any(target_os = "macos", windows)))] (Surface::Egl(surface), PossiblyCurrentContext::Egl(context)) if matches!(self.raw_window_handle, RawWindowHandle::Wayland(_)) && !self.damage_tracker.debug => { let damage = self.damage_tracker.shape_frame_damage(self.size_info.into()); surface.swap_buffers_with_damage(context, &damage) }, (surface, context) => surface.swap_buffers(context), }; if let Err(err) = res { debug!("error calling swap_buffers: {}", err); } } /// Update font size and cell dimensions. /// /// This will return a tuple of the cell width and height. fn update_font_size( glyph_cache: &mut GlyphCache, config: &UiConfig, font: &Font, ) -> (f32, f32) { let _ = glyph_cache.update_font_size(font); // Compute new cell sizes. compute_cell_size(config, &glyph_cache.font_metrics()) } /// Reset glyph cache. fn reset_glyph_cache(&mut self) { let cache = &mut self.glyph_cache; self.renderer.with_loader(|mut api| { cache.reset_glyph_cache(&mut api); }); } // XXX: this function must not call to any `OpenGL` related tasks. Renderer updates are // performed in [`Self::process_renderer_update`] right before drawing. // /// Process update events. pub fn handle_update<T>( &mut self, terminal: &mut Term<T>, pty_resize_handle: &mut dyn OnResize, message_buffer: &MessageBuffer, search_state: &mut SearchState, config: &UiConfig, ) where T: EventListener, { let pending_update = mem::take(&mut self.pending_update); let (mut cell_width, mut cell_height) = (self.size_info.cell_width(), self.size_info.cell_height()); if pending_update.font().is_some() || pending_update.cursor_dirty() { let renderer_update = self.pending_renderer_update.get_or_insert(Default::default()); renderer_update.clear_font_cache = true } // Update font size and cell dimensions. if let Some(font) = pending_update.font() { let cell_dimensions = Self::update_font_size(&mut self.glyph_cache, config, font); cell_width = cell_dimensions.0; cell_height = cell_dimensions.1; info!("Cell size: {} x {}", cell_width, cell_height); // Mark entire terminal as damaged since glyph size could change without cell size // changes. self.damage_tracker.frame().mark_fully_damaged(); } let (mut width, mut height) = (self.size_info.width(), self.size_info.height()); if let Some(dimensions) = pending_update.dimensions() { width = dimensions.width as f32; height = dimensions.height as f32; } let padding = config.window.padding(self.window.scale_factor as f32); let mut new_size = SizeInfo::new( width, height, cell_width, cell_height, padding.0, padding.1, config.window.dynamic_padding, ); // Update number of column/lines in the viewport. let search_active = search_state.history_index.is_some(); let message_bar_lines = message_buffer.message().map_or(0, |m| m.text(&new_size).len()); let search_lines = usize::from(search_active); new_size.reserve_lines(message_bar_lines + search_lines); // Update resize increments. if config.window.resize_increments { self.window.set_resize_increments(PhysicalSize::new(cell_width, cell_height)); } // Resize when terminal when its dimensions have changed. if self.size_info.screen_lines() != new_size.screen_lines || self.size_info.columns() != new_size.columns() { // Resize PTY. pty_resize_handle.on_resize(new_size.into()); // Resize terminal. terminal.resize(new_size); // Resize damage tracking. self.damage_tracker.resize(new_size.screen_lines(), new_size.columns()); } // Check if dimensions have changed. if new_size != self.size_info { // Queue renderer update. let renderer_update = self.pending_renderer_update.get_or_insert(Default::default()); renderer_update.resize = true; // Clear focused search match. search_state.clear_focused_match(); } self.size_info = new_size; } // NOTE: Renderer updates are split off, since platforms like Wayland require resize and other // OpenGL operations to be performed right before rendering. Otherwise they could lock the // back buffer and render with the previous state. This also solves flickering during resizes. // /// Update the state of the renderer. pub fn process_renderer_update(&mut self) { let renderer_update = match self.pending_renderer_update.take() { Some(renderer_update) => renderer_update, _ => return, }; // Resize renderer. if renderer_update.resize { let width = NonZeroU32::new(self.size_info.width() as u32).unwrap(); let height = NonZeroU32::new(self.size_info.height() as u32).unwrap(); self.surface.resize(&self.context, width, height); } // Ensure we're modifying the correct OpenGL context. self.make_current(); if renderer_update.clear_font_cache { self.reset_glyph_cache(); } self.renderer.resize(&self.size_info); info!("Padding: {} x {}", self.size_info.padding_x(), self.size_info.padding_y()); info!("Width: {}, Height: {}", self.size_info.width(), self.size_info.height()); } /// Draw the screen. /// /// A reference to Term whose state is being drawn must be provided. /// /// This call may block if vsync is enabled. pub fn draw<T: EventListener>( &mut self, mut terminal: MutexGuard<'_, Term<T>>, scheduler: &mut Scheduler, message_buffer: &MessageBuffer, config: &UiConfig, search_state: &mut SearchState, ) { // Collect renderable content before the terminal is dropped. let mut content = RenderableContent::new(config, self, &terminal, search_state); let mut grid_cells = Vec::new(); for cell in &mut content { grid_cells.push(cell); } let selection_range = content.selection_range(); let foreground_color = content.color(NamedColor::Foreground as usize); let background_color = content.color(NamedColor::Background as usize); let display_offset = content.display_offset(); let cursor = content.cursor(); let cursor_point = terminal.grid().cursor.point; let total_lines = terminal.grid().total_lines(); let metrics = self.glyph_cache.font_metrics(); let size_info = self.size_info; let vi_mode = terminal.mode().contains(TermMode::VI); let vi_cursor_point = if vi_mode { Some(terminal.vi_mode_cursor.point) } else { None }; // Add damage from the terminal. if self.collect_damage() { match terminal.damage() { TermDamage::Full => self.damage_tracker.frame().mark_fully_damaged(), TermDamage::Partial(damaged_lines) => { for damage in damaged_lines { self.damage_tracker.frame().damage_line(damage); } }, } terminal.reset_damage(); } // Drop terminal as early as possible to free lock. drop(terminal); // Add damage from alacritty's UI elements overlapping terminal. if self.collect_damage() { let requires_full_damage = self.visual_bell.intensity() != 0. || self.hint_state.active() || search_state.regex().is_some(); if requires_full_damage { self.damage_tracker.frame().mark_fully_damaged(); self.damage_tracker.next_frame().mark_fully_damaged(); } let vi_cursor_viewport_point = vi_cursor_point.and_then(|cursor| point_to_viewport(display_offset, cursor)); self.damage_tracker.damage_vi_cursor(vi_cursor_viewport_point); self.damage_tracker.damage_selection(selection_range, display_offset); } // Make sure this window's OpenGL context is active. self.make_current(); self.renderer.clear(background_color, config.window_opacity()); let mut lines = RenderLines::new(); // Optimize loop hint comparator. let has_highlighted_hint = self.highlighted_hint.is_some() || self.vi_highlighted_hint.is_some(); // Draw grid. { let _sampler = self.meter.sampler(); // Ensure macOS hasn't reset our viewport. #[cfg(target_os = "macos")] self.renderer.set_viewport(&size_info); let glyph_cache = &mut self.glyph_cache; let highlighted_hint = &self.highlighted_hint; let vi_highlighted_hint = &self.vi_highlighted_hint; let damage_tracker = &mut self.damage_tracker; self.renderer.draw_cells( &size_info, glyph_cache, grid_cells.into_iter().map(|mut cell| { // Underline hints hovered by mouse or vi mode cursor. let point = term::viewport_to_point(display_offset, cell.point); if has_highlighted_hint { let hyperlink = cell.extra.as_ref().and_then(|extra| extra.hyperlink.as_ref()); if highlighted_hint .as_ref() .map_or(false, |hint| hint.should_highlight(point, hyperlink)) || vi_highlighted_hint .as_ref() .map_or(false, |hint| hint.should_highlight(point, hyperlink)) { cell.flags.insert(Flags::UNDERLINE); // Damage hints for the current and next frames. damage_tracker.frame().damage_point(cell.point); damage_tracker.next_frame().damage_point(cell.point); } } // Update underline/strikeout. lines.update(&cell); cell }), ); } let mut rects = lines.rects(&metrics, &size_info); if let Some(vi_cursor_point) = vi_cursor_point { // Indicate vi mode by showing the cursor's position in the top right corner. let line = (-vi_cursor_point.line.0 + size_info.bottommost_line().0) as usize; let obstructed_column = Some(vi_cursor_point) .filter(|point| point.line == -(display_offset as i32)) .map(|point| point.column); self.draw_line_indicator(config, total_lines, obstructed_column, line); } else if search_state.regex().is_some() { // Show current display offset in vi-less search to indicate match position. self.draw_line_indicator(config, total_lines, None, display_offset); }; // Draw cursor. rects.extend(cursor.rects(&size_info, config.cursor.thickness())); // Push visual bell after url/underline/strikeout rects. let visual_bell_intensity = self.visual_bell.intensity(); if visual_bell_intensity != 0. { let visual_bell_rect = RenderRect::new( 0., 0., size_info.width(), size_info.height(), config.bell.color, visual_bell_intensity as f32, ); rects.push(visual_bell_rect); } // Handle IME positioning and search bar rendering. let ime_position = match search_state.regex() { Some(regex) => { let search_label = match search_state.direction() { Direction::Right => FORWARD_SEARCH_LABEL, Direction::Left => BACKWARD_SEARCH_LABEL, }; let search_text = Self::format_search(regex, search_label, size_info.columns()); // Render the search bar. self.draw_search(config, &search_text); // Draw search bar cursor. let line = size_info.screen_lines(); let column = Column(search_text.chars().count() - 1); // Add cursor to search bar if IME is not active. if self.ime.preedit().is_none() { let fg = config.colors.footer_bar_foreground(); let shape = CursorShape::Underline; let cursor = RenderableCursor::new(Point::new(line, column), shape, fg, false); rects.extend(cursor.rects(&size_info, config.cursor.thickness())); } Some(Point::new(line, column)) }, None => { let num_lines = self.size_info.screen_lines(); term::point_to_viewport(display_offset, cursor_point) .filter(|point| point.line < num_lines) }, }; // Handle IME. if self.ime.is_enabled() { if let Some(point) = ime_position { let (fg, bg) = if search_state.regex().is_some() { (config.colors.footer_bar_foreground(), config.colors.footer_bar_background()) } else { (foreground_color, background_color) }; self.draw_ime_preview(point, fg, bg, &mut rects, config); } } if let Some(message) = message_buffer.message() { let search_offset = usize::from(search_state.regex().is_some()); let text = message.text(&size_info); // Create a new rectangle for the background. let start_line = size_info.screen_lines() + search_offset; let y = size_info.cell_height().mul_add(start_line as f32, size_info.padding_y()); let bg = match message.ty() { MessageType::Error => config.colors.normal.red, MessageType::Warning => config.colors.normal.yellow, }; let x = 0; let width = size_info.width() as i32; let height = (size_info.height() - y) as i32; let message_bar_rect = RenderRect::new(x as f32, y, width as f32, height as f32, bg, 1.); // Push message_bar in the end, so it'll be above all other content. rects.push(message_bar_rect); // Always damage message bar, since it could have messages of the same size in it. self.damage_tracker.frame().add_viewport_rect(&size_info, x, y as i32, width, height); // Draw rectangles. self.renderer.draw_rects(&size_info, &metrics, rects); // Relay messages to the user. let glyph_cache = &mut self.glyph_cache; let fg = config.colors.primary.background; for (i, message_text) in text.iter().enumerate() { let point = Point::new(start_line + i, Column(0)); self.renderer.draw_string( point, fg, bg, message_text.chars(), &size_info, glyph_cache, ); } } else { // Draw rectangles. self.renderer.draw_rects(&size_info, &metrics, rects); } self.draw_render_timer(config); // Draw hyperlink uri preview. if has_highlighted_hint { let cursor_point = vi_cursor_point.or(Some(cursor_point)); self.draw_hyperlink_preview(config, cursor_point, display_offset); } // Notify winit that we're about to present. self.window.pre_present_notify(); // Highlight damage for debugging. if self.damage_tracker.debug { let damage = self.damage_tracker.shape_frame_damage(self.size_info.into()); let mut rects = Vec::with_capacity(damage.len()); self.highlight_damage(&mut rects); self.renderer.draw_rects(&self.size_info, &metrics, rects); } // Clearing debug highlights from the previous frame requires full redraw. self.swap_buffers(); if matches!(self.raw_window_handle, RawWindowHandle::Xcb(_) | RawWindowHandle::Xlib(_)) { // On X11 `swap_buffers` does not block for vsync. However the next OpenGl command // will block to synchronize (this is `glClear` in Alacritty), which causes a // permanent one frame delay. self.renderer.finish(); } // XXX: Request the new frame after swapping buffers, so the // time to finish OpenGL operations is accounted for in the timeout. if !matches!(self.raw_window_handle, RawWindowHandle::Wayland(_)) { self.request_frame(scheduler); } self.damage_tracker.swap_damage(); } /// Update to a new configuration. pub fn update_config(&mut self, config: &UiConfig) { self.damage_tracker.debug = config.debug.highlight_damage; self.visual_bell.update_config(&config.bell); self.colors = List::from(&config.colors); } /// Update the mouse/vi mode cursor hint highlighting. /// /// This will return whether the highlighted hints changed. pub fn update_highlighted_hints<T>( &mut self, term: &Term<T>, config: &UiConfig, mouse: &Mouse, modifiers: ModifiersState, ) -> bool { // Update vi mode cursor hint. let vi_highlighted_hint = if term.mode().contains(TermMode::VI) { let mods = ModifiersState::all(); let point = term.vi_mode_cursor.point; hint::highlighted_at(term, config, point, mods) } else { None }; let mut dirty = vi_highlighted_hint != self.vi_highlighted_hint; self.vi_highlighted_hint = vi_highlighted_hint; // Abort if mouse highlighting conditions are not met. if !mouse.inside_text_area || !term.selection.as_ref().map_or(true, Selection::is_empty) { dirty |= self.highlighted_hint.is_some(); self.highlighted_hint = None; return dirty; } // Find highlighted hint at mouse position. let point = mouse.point(&self.size_info, term.grid().display_offset()); let highlighted_hint = hint::highlighted_at(term, config, point, modifiers); // Update cursor shape. if highlighted_hint.is_some() { // If mouse changed the line, we should update the hyperlink preview, since the // highlighted hint could be disrupted by the old preview. dirty = self.hint_mouse_point.map_or(false, |p| p.line != point.line); self.hint_mouse_point = Some(point); self.window.set_mouse_cursor(CursorIcon::Pointer); } else if self.highlighted_hint.is_some() { self.hint_mouse_point = None; if term.mode().intersects(TermMode::MOUSE_MODE) && !term.mode().contains(TermMode::VI) { self.window.set_mouse_cursor(CursorIcon::Default); } else { self.window.set_mouse_cursor(CursorIcon::Text); } } dirty |= self.highlighted_hint != highlighted_hint; self.highlighted_hint = highlighted_hint; dirty } #[inline(never)] fn draw_ime_preview( &mut self, point: Point<usize>, fg: Rgb, bg: Rgb, rects: &mut Vec<RenderRect>, config: &UiConfig, ) { let preedit = match self.ime.preedit() { Some(preedit) => preedit, None => { // In case we don't have preedit, just set the popup point. self.window.update_ime_position(point, &self.size_info); return; }, }; let num_cols = self.size_info.columns(); // Get the visible preedit. let visible_text: String = match (preedit.cursor_byte_offset, preedit.cursor_end_offset) { (Some(byte_offset), Some(end_offset)) if end_offset > num_cols => StrShortener::new( &preedit.text[byte_offset..], num_cols, ShortenDirection::Right, Some(SHORTENER), ), _ => { StrShortener::new(&preedit.text, num_cols, ShortenDirection::Left, Some(SHORTENER)) }, } .collect(); let visible_len = visible_text.chars().count(); let end = cmp::min(point.column.0 + visible_len, num_cols); let start = end.saturating_sub(visible_len); let start = Point::new(point.line, Column(start)); let end = Point::new(point.line, Column(end - 1)); let glyph_cache = &mut self.glyph_cache; let metrics = glyph_cache.font_metrics(); self.renderer.draw_string( start, fg, bg, visible_text.chars(), &self.size_info, glyph_cache, ); // Damage preedit inside the terminal viewport. if self.collect_damage() && point.line < self.size_info.screen_lines() { let damage = LineDamageBounds::new(start.line, 0, num_cols); self.damage_tracker.frame().damage_line(damage); self.damage_tracker.next_frame().damage_line(damage); } // Add underline for preedit text. let underline = RenderLine { start, end, color: fg }; rects.extend(underline.rects(Flags::UNDERLINE, &metrics, &self.size_info)); let ime_popup_point = match preedit.cursor_end_offset { Some(cursor_end_offset) if cursor_end_offset != 0 => { let is_wide = preedit.text[preedit.cursor_byte_offset.unwrap_or_default()..] .chars() .next() .map(|ch| ch.width() == Some(2)) .unwrap_or_default(); let cursor_column = Column( (end.column.0 as isize - cursor_end_offset as isize + 1).max(0) as usize, ); let cursor_point = Point::new(point.line, cursor_column); let cursor = RenderableCursor::new(cursor_point, CursorShape::HollowBlock, fg, is_wide); rects.extend(cursor.rects(&self.size_info, config.cursor.thickness())); cursor_point }, _ => end, }; self.window.update_ime_position(ime_popup_point, &self.size_info); } /// Format search regex to account for the cursor and fullwidth characters. fn format_search(search_regex: &str, search_label: &str, max_width: usize) -> String { let label_len = search_label.len(); // Skip `search_regex` formatting if only label is visible. if label_len > max_width { return search_label[..max_width].to_owned(); } // The search string consists of `search_label` + `search_regex` + `cursor`. let mut bar_text = String::from(search_label); bar_text.extend(StrShortener::new( search_regex, max_width.wrapping_sub(label_len + 1), ShortenDirection::Left, Some(SHORTENER), )); // Add place for cursor. bar_text.push(' '); bar_text } /// Draw preview for the currently highlighted `Hyperlink`. #[inline(never)] fn draw_hyperlink_preview( &mut self, config: &UiConfig, cursor_point: Option<Point>, display_offset: usize, ) { let num_cols = self.size_info.columns(); let uris: Vec<_> = self .highlighted_hint .iter() .chain(&self.vi_highlighted_hint) .filter_map(|hint| hint.hyperlink().map(|hyperlink| hyperlink.uri())) .map(|uri| StrShortener::new(uri, num_cols, ShortenDirection::Right, Some(SHORTENER))) .collect(); if uris.is_empty() { return; } // The maximum amount of protected lines including the ones we'll show preview on. let max_protected_lines = uris.len() * 2; // Lines we shouldn't show preview on, because it'll obscure the highlighted hint. let mut protected_lines = Vec::with_capacity(max_protected_lines); if self.size_info.screen_lines() > max_protected_lines { // Prefer to show preview even when it'll likely obscure the highlighted hint, when // there's no place left for it. protected_lines.push(self.hint_mouse_point.map(|point| point.line)); protected_lines.push(cursor_point.map(|point| point.line)); } // Find the line in viewport we can draw preview on without obscuring protected lines. let viewport_bottom = self.size_info.bottommost_line() - Line(display_offset as i32); let viewport_top = viewport_bottom - (self.size_info.screen_lines() - 1); let uri_lines = (viewport_top.0..=viewport_bottom.0) .rev() .map(|line| Some(Line(line))) .filter_map(|line| { if protected_lines.contains(&line) { None } else { protected_lines.push(line); line } }) .take(uris.len()) .flat_map(|line| term::point_to_viewport(display_offset, Point::new(line, Column(0)))); let fg = config.colors.footer_bar_foreground(); let bg = config.colors.footer_bar_background(); for (uri, point) in uris.into_iter().zip(uri_lines) { // Damage the uri preview. if self.collect_damage() { let damage = LineDamageBounds::new(point.line, point.column.0, num_cols); self.damage_tracker.frame().damage_line(damage); // Damage the uri preview for the next frame as well. self.damage_tracker.next_frame().damage_line(damage); } self.renderer.draw_string(point, fg, bg, uri, &self.size_info, &mut self.glyph_cache); } } /// Draw current search regex. #[inline(never)] fn draw_search(&mut self, config: &UiConfig, text: &str) { // Assure text length is at least num_cols. let num_cols = self.size_info.columns(); let text = format!("{:<1$}", text, num_cols); let point = Point::new(self.size_info.screen_lines(), Column(0)); let fg = config.colors.footer_bar_foreground(); let bg = config.colors.footer_bar_background(); self.renderer.draw_string( point, fg, bg, text.chars(), &self.size_info, &mut self.glyph_cache, ); } /// Draw render timer. #[inline(never)] fn draw_render_timer(&mut self, config: &UiConfig) { if !config.debug.render_timer { return; } let timing = format!("{:.3} usec", self.meter.average()); let point = Point::new(self.size_info.screen_lines().saturating_sub(2), Column(0)); let fg = config.colors.primary.background; let bg = config.colors.normal.red; if self.collect_damage() { let damage = LineDamageBounds::new(point.line, point.column.0, timing.len()); self.damage_tracker.frame().damage_line(damage); // Damage the render timer for the next frame. self.damage_tracker.next_frame().damage_line(damage); } let glyph_cache = &mut self.glyph_cache; self.renderer.draw_string(point, fg, bg, timing.chars(), &self.size_info, glyph_cache); } /// Draw an indicator for the position of a line in history. #[inline(never)] fn draw_line_indicator( &mut self, config: &UiConfig, total_lines: usize, obstructed_column: Option<Column>, line: usize, ) { let columns = self.size_info.columns(); let text = format!("[{}/{}]", line, total_lines - 1); let column = Column(self.size_info.columns().saturating_sub(text.len())); let point = Point::new(0, column); if self.collect_damage() { let damage = LineDamageBounds::new(point.line, point.column.0, columns - 1); self.damage_tracker.frame().damage_line(damage); // Damage it on the next frame in case it goes away. self.damage_tracker.next_frame().damage_line(damage); } let colors = &config.colors; let fg = colors.line_indicator.foreground.unwrap_or(colors.primary.background); let bg = colors.line_indicator.background.unwrap_or(colors.primary.foreground); // Do not render anything if it would obscure the vi mode cursor. if obstructed_column.map_or(true, |obstructed_column| obstructed_column < column) { let glyph_cache = &mut self.glyph_cache; self.renderer.draw_string(point, fg, bg, text.chars(), &self.size_info, glyph_cache); } } /// Returns `true` if damage information should be collected, `false` otherwise. #[inline] fn collect_damage(&self) -> bool { matches!(self.raw_window_handle, RawWindowHandle::Wayland(_)) || self.damage_tracker.debug } /// Highlight damaged rects. /// /// This function is for debug purposes only. fn highlight_damage(&self, render_rects: &mut Vec<RenderRect>) { for damage_rect in &self.damage_tracker.shape_frame_damage(self.size_info.into()) { let x = damage_rect.x as f32; let height = damage_rect.height as f32; let width = damage_rect.width as f32; let y = damage_y_to_viewport_y(&self.size_info, damage_rect) as f32; let render_rect = RenderRect::new(x, y, width, height, DAMAGE_RECT_COLOR, 0.5); render_rects.push(render_rect); } } /// Request a new frame for a window on Wayland. fn request_frame(&mut self, scheduler: &mut Scheduler) { // Mark that we've used a frame. self.window.has_frame = false; // Get the display vblank interval. let monitor_vblank_interval = 1_000_000. / self .window .current_monitor() .and_then(|monitor| monitor.refresh_rate_millihertz()) .unwrap_or(60_000) as f64; // Now convert it to micro seconds. let monitor_vblank_interval = Duration::from_micros((1000. * monitor_vblank_interval) as u64); let swap_timeout = self.frame_timer.compute_timeout(monitor_vblank_interval); let window_id = self.window.id(); let timer_id = TimerId::new(Topic::Frame, window_id); let event = Event::new(EventType::Frame, window_id); scheduler.schedule(event, swap_timeout, false, timer_id); } } impl Drop for Display { fn drop(&mut self) { // Switch OpenGL context before dropping, otherwise objects (like programs) from other // contexts might be deleted when dropping renderer. self.make_current(); unsafe { ManuallyDrop::drop(&mut self.renderer); ManuallyDrop::drop(&mut self.context); ManuallyDrop::drop(&mut self.surface); } } } /// Input method state. #[derive(Debug, Default)] pub struct Ime { /// Whether the IME is enabled. enabled: bool, /// Current IME preedit. preedit: Option<Preedit>, } impl Ime { #[inline] pub fn set_enabled(&mut self, is_enabled: bool) { if is_enabled { self.enabled = is_enabled } else { // Clear state when disabling IME. *self = Default::default(); } } #[inline] pub fn is_enabled(&self) -> bool { self.enabled } #[inline] pub fn set_preedit(&mut self, preedit: Option<Preedit>) { self.preedit = preedit; } #[inline] pub fn preedit(&self) -> Option<&Preedit> { self.preedit.as_ref() } } #[derive(Debug, Default, PartialEq, Eq)] pub struct Preedit { /// The preedit text. text: String, /// Byte offset for cursor start into the preedit text. /// /// `None` means that the cursor is invisible. cursor_byte_offset: Option<usize>, /// The cursor offset from the end of the preedit in char width. cursor_end_offset: Option<usize>, } impl Preedit { pub fn new(text: String, cursor_byte_offset: Option<usize>) -> Self { let cursor_end_offset = if let Some(byte_offset) = cursor_byte_offset { // Convert byte offset into char offset. let cursor_end_offset = text[byte_offset..].chars().fold(0, |acc, ch| acc + ch.width().unwrap_or(1)); Some(cursor_end_offset) } else { None }; Self { text, cursor_byte_offset, cursor_end_offset } } } /// Pending renderer updates. /// /// All renderer updates are cached to be applied just before rendering, to avoid platform-specific /// rendering issues. #[derive(Debug, Default, Copy, Clone)] pub struct RendererUpdate { /// Should resize the window. resize: bool, /// Clear font caches. clear_font_cache: bool, } /// Struct for safe in-place replacement. /// /// This struct allows easily replacing struct fields that provide `self -> Self` methods in-place, /// without having to deal with constantly unwrapping the underlying [`Option`]. struct Replaceable<T>(Option<T>); impl<T> Replaceable<T> { pub fn new(inner: T) -> Self { Self(Some(inner)) } /// Replace the contents of the container. pub fn replace_with<F: FnMut(T) -> T>(&mut self, f: F) { self.0 = self.0.take().map(f); } /// Get immutable access to the wrapped value. pub fn get(&self) -> &T { self.0.as_ref().unwrap() } /// Get mutable access to the wrapped value. pub fn get_mut(&mut self) -> &mut T { self.0.as_mut().unwrap() } } impl<T> Deref for Replaceable<T> { type Target = T; fn deref(&self) -> &Self::Target { self.get() } } impl<T> DerefMut for Replaceable<T> { fn deref_mut(&mut self) -> &mut Self::Target { self.get_mut() } } /// The frame timer state. pub struct FrameTimer { /// Base timestamp used to compute sync points. base: Instant, /// The last timestamp we synced to. last_synced_timestamp: Instant, /// The refresh rate we've used to compute sync timestamps. refresh_interval: Duration, } impl FrameTimer { pub fn new() -> Self { let now = Instant::now(); Self { base: now, last_synced_timestamp: now, refresh_interval: Duration::ZERO } } /// Compute the delay that we should use to achieve the target frame /// rate. pub fn compute_timeout(&mut self, refresh_interval: Duration) -> Duration { let now = Instant::now(); // Handle refresh rate change. if self.refresh_interval != refresh_interval { self.base = now; self.last_synced_timestamp = now; self.refresh_interval = refresh_interval; return refresh_interval; } let next_frame = self.last_synced_timestamp + self.refresh_interval; if next_frame < now { // Redraw immediately if we haven't drawn in over `refresh_interval` microseconds. let elapsed_micros = (now - self.base).as_micros() as u64; let refresh_micros = self.refresh_interval.as_micros() as u64; self.last_synced_timestamp = now - Duration::from_micros(elapsed_micros % refresh_micros); Duration::ZERO } else { // Redraw on the next `refresh_interval` clock tick. self.last_synced_timestamp = next_frame; next_frame - now } } } /// Calculate the cell dimensions based on font metrics. /// /// This will return a tuple of the cell width and height. #[inline] fn compute_cell_size(config: &UiConfig, metrics: &crossfont::Metrics) -> (f32, f32) { let offset_x = f64::from(config.font.offset.x); let offset_y = f64::from(config.font.offset.y); ( (metrics.average_advance + offset_x).floor().max(1.) as f32, (metrics.line_height + offset_y).floor().max(1.) as f32, ) } /// Calculate the size of the window given padding, terminal dimensions and cell size. fn window_size( config: &UiConfig, dimensions: Dimensions, cell_width: f32, cell_height: f32, scale_factor: f32, ) -> PhysicalSize<u32> { let padding = config.window.padding(scale_factor); let grid_width = cell_width * dimensions.columns.max(MIN_COLUMNS) as f32; let grid_height = cell_height * dimensions.lines.max(MIN_SCREEN_LINES) as f32; let width = (padding.0).mul_add(2., grid_width).floor(); let height = (padding.1).mul_add(2., grid_height).floor(); PhysicalSize::new(width as u32, height as u32) } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/display/window.rs��������������������������������������������������������������0000644�0000000�0000000�00000036663�10461020230�0016032�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#[cfg(not(any(target_os = "macos", windows)))] use winit::platform::startup_notify::{ self, EventLoopExtStartupNotify, WindowBuilderExtStartupNotify, }; #[cfg(all(not(feature = "x11"), not(any(target_os = "macos", windows))))] use winit::platform::wayland::WindowBuilderExtWayland; #[rustfmt::skip] #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] use { std::io::Cursor, winit::platform::x11::{WindowBuilderExtX11, EventLoopWindowTargetExtX11}, glutin::platform::x11::X11VisualInfo, winit::window::Icon, png::Decoder, }; use std::fmt::{self, Display, Formatter}; #[cfg(target_os = "macos")] use { cocoa::appkit::NSColorSpace, cocoa::base::{id, nil, NO, YES}, objc::{msg_send, sel, sel_impl}, winit::platform::macos::{OptionAsAlt, WindowBuilderExtMacOS, WindowExtMacOS}, }; use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; use winit::dpi::{PhysicalPosition, PhysicalSize}; use winit::event_loop::EventLoopWindowTarget; use winit::monitor::MonitorHandle; #[cfg(windows)] use winit::platform::windows::IconExtWindows; use winit::window::{ CursorIcon, Fullscreen, ImePurpose, Theme, UserAttentionType, Window as WinitWindow, WindowBuilder, WindowId, }; use alacritty_terminal::index::Point; use crate::config::window::{Decorations, Identity, WindowConfig}; use crate::config::UiConfig; use crate::display::SizeInfo; /// Window icon for `_NET_WM_ICON` property. #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] static WINDOW_ICON: &[u8] = include_bytes!("../../extra/logo/compat/alacritty-term.png"); /// This should match the definition of IDI_ICON from `alacritty.rc`. #[cfg(windows)] const IDI_ICON: u16 = 0x101; /// Window errors. #[derive(Debug)] pub enum Error { /// Error creating the window. WindowCreation(winit::error::OsError), /// Error dealing with fonts. Font(crossfont::Error), } /// Result of fallible operations concerning a Window. type Result<T> = std::result::Result<T, Error>; impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Error::WindowCreation(err) => err.source(), Error::Font(err) => err.source(), } } } impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Error::WindowCreation(err) => write!(f, "Error creating GL context; {}", err), Error::Font(err) => err.fmt(f), } } } impl From<winit::error::OsError> for Error { fn from(val: winit::error::OsError) -> Self { Error::WindowCreation(val) } } impl From<crossfont::Error> for Error { fn from(val: crossfont::Error) -> Self { Error::Font(val) } } /// A window which can be used for displaying the terminal. /// /// Wraps the underlying windowing library to provide a stable API in Alacritty. pub struct Window { /// Flag tracking that we have a frame we can draw. pub has_frame: bool, /// Cached scale factor for quickly scaling pixel sizes. pub scale_factor: f64, /// Flag indicating whether redraw was requested. pub requested_redraw: bool, window: WinitWindow, /// Current window title. title: String, is_x11: bool, current_mouse_cursor: CursorIcon, mouse_visible: bool, } impl Window { /// Create a new window. /// /// This creates a window and fully initializes a window. pub fn new<E>( event_loop: &EventLoopWindowTarget<E>, config: &UiConfig, identity: &Identity, #[rustfmt::skip] #[cfg(target_os = "macos")] tabbing_id: &Option<String>, #[rustfmt::skip] #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] x11_visual: Option<X11VisualInfo>, ) -> Result<Window> { let identity = identity.clone(); let mut window_builder = Window::get_platform_window( &identity, &config.window, #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] x11_visual, #[cfg(target_os = "macos")] tabbing_id, ); if let Some(position) = config.window.position { window_builder = window_builder .with_position(PhysicalPosition::<i32>::from((position.x, position.y))); } #[cfg(not(any(target_os = "macos", windows)))] if let Some(token) = event_loop.read_token_from_env() { log::debug!("Activating window with token: {token:?}"); window_builder = window_builder.with_activation_token(token); // Remove the token from the env. startup_notify::reset_activation_token_env(); } // On X11, embed the window inside another if the parent ID has been set. #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] if let Some(parent_window_id) = event_loop.is_x11().then_some(config.window.embed).flatten() { window_builder = window_builder.with_embed_parent_window(parent_window_id); } let window = window_builder .with_title(&identity.title) .with_theme(config.window.theme()) .with_visible(false) .with_transparent(true) .with_blur(config.window.blur) .with_maximized(config.window.maximized()) .with_fullscreen(config.window.fullscreen()) .build(event_loop)?; // Text cursor. let current_mouse_cursor = CursorIcon::Text; window.set_cursor_icon(current_mouse_cursor); // Enable IME. window.set_ime_allowed(true); window.set_ime_purpose(ImePurpose::Terminal); // Set initial transparency hint. window.set_transparent(config.window_opacity() < 1.); #[cfg(target_os = "macos")] use_srgb_color_space(&window); let scale_factor = window.scale_factor(); log::info!("Window scale factor: {}", scale_factor); let is_x11 = matches!(window.raw_window_handle(), RawWindowHandle::Xlib(_)); Ok(Self { requested_redraw: false, title: identity.title, current_mouse_cursor, mouse_visible: true, has_frame: true, scale_factor, window, is_x11, }) } #[inline] pub fn raw_window_handle(&self) -> RawWindowHandle { self.window.raw_window_handle() } #[inline] pub fn request_inner_size(&self, size: PhysicalSize<u32>) { let _ = self.window.request_inner_size(size); } #[inline] pub fn inner_size(&self) -> PhysicalSize<u32> { self.window.inner_size() } #[inline] pub fn set_visible(&self, visibility: bool) { self.window.set_visible(visibility); } /// Set the window title. #[inline] pub fn set_title(&mut self, title: String) { self.title = title; self.window.set_title(&self.title); } /// Get the window title. #[inline] pub fn title(&self) -> &str { &self.title } #[inline] pub fn request_redraw(&mut self) { if !self.requested_redraw { self.requested_redraw = true; self.window.request_redraw(); } } #[inline] pub fn set_mouse_cursor(&mut self, cursor: CursorIcon) { if cursor != self.current_mouse_cursor { self.current_mouse_cursor = cursor; self.window.set_cursor_icon(cursor); } } /// Set mouse cursor visible. pub fn set_mouse_visible(&mut self, visible: bool) { if visible != self.mouse_visible { self.mouse_visible = visible; self.window.set_cursor_visible(visible); } } #[cfg(not(any(target_os = "macos", windows)))] pub fn get_platform_window( identity: &Identity, window_config: &WindowConfig, #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] x11_visual: Option< X11VisualInfo, >, ) -> WindowBuilder { #[cfg(feature = "x11")] let icon = { let mut decoder = Decoder::new(Cursor::new(WINDOW_ICON)); decoder.set_transformations(png::Transformations::normalize_to_color8()); let mut reader = decoder.read_info().expect("invalid embedded icon"); let mut buf = vec![0; reader.output_buffer_size()]; let _ = reader.next_frame(&mut buf); Icon::from_rgba(buf, reader.info().width, reader.info().height) .expect("invalid embedded icon format") }; let builder = WindowBuilder::new() .with_name(&identity.class.general, &identity.class.instance) .with_decorations(window_config.decorations != Decorations::None); #[cfg(feature = "x11")] let builder = builder.with_window_icon(Some(icon)); #[cfg(feature = "x11")] let builder = match x11_visual { Some(visual) => builder.with_x11_visual(visual.visual_id() as u32), None => builder, }; builder } #[cfg(windows)] pub fn get_platform_window(_: &Identity, window_config: &WindowConfig) -> WindowBuilder { let icon = winit::window::Icon::from_resource(IDI_ICON, None); WindowBuilder::new() .with_decorations(window_config.decorations != Decorations::None) .with_window_icon(icon.ok()) } #[cfg(target_os = "macos")] pub fn get_platform_window( _: &Identity, window_config: &WindowConfig, tabbing_id: &Option<String>, ) -> WindowBuilder { let mut window = WindowBuilder::new().with_option_as_alt(window_config.option_as_alt()); if let Some(tabbing_id) = tabbing_id { window = window.with_tabbing_identifier(tabbing_id); } match window_config.decorations { Decorations::Full => window, Decorations::Transparent => window .with_title_hidden(true) .with_titlebar_transparent(true) .with_fullsize_content_view(true), Decorations::Buttonless => window .with_title_hidden(true) .with_titlebar_buttons_hidden(true) .with_titlebar_transparent(true) .with_fullsize_content_view(true), Decorations::None => window.with_titlebar_hidden(true), } } pub fn set_urgent(&self, is_urgent: bool) { let attention = if is_urgent { Some(UserAttentionType::Critical) } else { None }; self.window.request_user_attention(attention); } pub fn id(&self) -> WindowId { self.window.id() } pub fn set_transparent(&self, transparent: bool) { self.window.set_transparent(transparent); } pub fn set_blur(&self, blur: bool) { self.window.set_blur(blur); } pub fn set_maximized(&self, maximized: bool) { self.window.set_maximized(maximized); } pub fn set_minimized(&self, minimized: bool) { self.window.set_minimized(minimized); } pub fn set_resize_increments(&self, increments: PhysicalSize<f32>) { self.window.set_resize_increments(Some(increments)); } /// Toggle the window's fullscreen state. pub fn toggle_fullscreen(&self) { self.set_fullscreen(self.window.fullscreen().is_none()); } /// Toggle the window's maximized state. pub fn toggle_maximized(&self) { self.set_maximized(!self.window.is_maximized()); } /// Inform windowing system about presenting to the window. /// /// Should be called right before presenting to the window with e.g. `eglSwapBuffers`. pub fn pre_present_notify(&self) { self.window.pre_present_notify(); } pub fn set_theme(&self, theme: Option<Theme>) { self.window.set_theme(theme); } #[cfg(target_os = "macos")] pub fn toggle_simple_fullscreen(&self) { self.set_simple_fullscreen(!self.window.simple_fullscreen()); } #[cfg(target_os = "macos")] pub fn set_option_as_alt(&self, option_as_alt: OptionAsAlt) { self.window.set_option_as_alt(option_as_alt); } pub fn set_fullscreen(&self, fullscreen: bool) { if fullscreen { self.window.set_fullscreen(Some(Fullscreen::Borderless(None))); } else { self.window.set_fullscreen(None); } } pub fn current_monitor(&self) -> Option<MonitorHandle> { self.window.current_monitor() } #[cfg(target_os = "macos")] pub fn set_simple_fullscreen(&self, simple_fullscreen: bool) { self.window.set_simple_fullscreen(simple_fullscreen); } pub fn set_ime_allowed(&self, allowed: bool) { // Skip runtime IME manipulation on X11 since it breaks some IMEs. if !self.is_x11 { self.window.set_ime_allowed(allowed); } } /// Adjust the IME editor position according to the new location of the cursor. pub fn update_ime_position(&self, point: Point<usize>, size: &SizeInfo) { // NOTE: X11 doesn't support cursor area, so we need to offset manually to not obscure // the text. let offset = if self.is_x11 { 1 } else { 0 }; let nspot_x = f64::from(size.padding_x() + point.column.0 as f32 * size.cell_width()); let nspot_y = f64::from(size.padding_y() + (point.line + offset) as f32 * size.cell_height()); // NOTE: some compositors don't like excluding too much and try to render popup at the // bottom right corner of the provided area, so exclude just the full-width char to not // obscure the cursor and not render popup at the end of the window. let width = size.cell_width() as f64 * 2.; let height = size.cell_height as f64; self.window.set_ime_cursor_area( PhysicalPosition::new(nspot_x, nspot_y), PhysicalSize::new(width, height), ); } /// Disable macOS window shadows. /// /// This prevents rendering artifacts from showing up when the window is transparent. #[cfg(target_os = "macos")] pub fn set_has_shadow(&self, has_shadows: bool) { let raw_window = match self.raw_window_handle() { RawWindowHandle::AppKit(handle) => handle.ns_window as id, _ => return, }; let value = if has_shadows { YES } else { NO }; unsafe { let _: id = msg_send![raw_window, setHasShadow: value]; } } /// Select tab at the given `index`. #[cfg(target_os = "macos")] pub fn select_tab_at_index(&self, index: usize) { self.window.select_tab_at_index(index); } /// Select the last tab. #[cfg(target_os = "macos")] pub fn select_last_tab(&self) { self.window.select_tab_at_index(self.window.num_tabs() - 1); } /// Select next tab. #[cfg(target_os = "macos")] pub fn select_next_tab(&self) { self.window.select_next_tab(); } /// Select previous tab. #[cfg(target_os = "macos")] pub fn select_previous_tab(&self) { self.window.select_previous_tab(); } #[cfg(target_os = "macos")] pub fn tabbing_id(&self) -> String { self.window.tabbing_identifier() } } #[cfg(target_os = "macos")] fn use_srgb_color_space(window: &WinitWindow) { let raw_window = match window.raw_window_handle() { RawWindowHandle::AppKit(handle) => handle.ns_window as id, _ => return, }; unsafe { let _: () = msg_send![raw_window, setColorSpace: NSColorSpace::sRGBColorSpace(nil)]; } } �����������������������������������������������������������������������������alacritty-0.13.2/src/event.rs�����������������������������������������������������������������������0000644�0000000�0000000�00000211663�10461020230�0014172�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Process window events. use std::borrow::Cow; use std::cmp::min; use std::collections::{HashMap, HashSet, VecDeque}; use std::error::Error; use std::ffi::OsStr; use std::fmt::Debug; #[cfg(not(windows))] use std::os::unix::io::RawFd; use std::path::PathBuf; use std::rc::Rc; use std::time::{Duration, Instant}; use std::{env, f32, mem}; use ahash::RandomState; use crossfont::Size as FontSize; use glutin::display::{Display as GlutinDisplay, GetGlDisplay}; use log::{debug, error, info, warn}; use raw_window_handle::HasRawDisplayHandle; use winit::event::{ ElementState, Event as WinitEvent, Ime, Modifiers, MouseButton, StartCause, Touch as TouchEvent, WindowEvent, }; use winit::event_loop::{ ControlFlow, DeviceEvents, EventLoop, EventLoopProxy, EventLoopWindowTarget, }; use winit::window::WindowId; use alacritty_terminal::event::{Event as TerminalEvent, EventListener, Notify}; use alacritty_terminal::event_loop::Notifier; use alacritty_terminal::grid::{BidirectionalIterator, Dimensions, Scroll}; use alacritty_terminal::index::{Boundary, Column, Direction, Line, Point, Side}; use alacritty_terminal::selection::{Selection, SelectionType}; use alacritty_terminal::term::search::{Match, RegexSearch}; use alacritty_terminal::term::{self, ClipboardType, Term, TermMode}; #[cfg(unix)] use crate::cli::{IpcConfig, ParsedOptions}; use crate::cli::{Options as CliOptions, WindowOptions}; use crate::clipboard::Clipboard; use crate::config::ui_config::{HintAction, HintInternalAction}; use crate::config::{self, UiConfig}; #[cfg(not(windows))] use crate::daemon::foreground_process_path; use crate::daemon::spawn_daemon; use crate::display::color::Rgb; use crate::display::hint::HintMatch; use crate::display::window::Window; use crate::display::{Display, Preedit, SizeInfo}; use crate::input::{self, ActionContext as _, FONT_SIZE_STEP}; use crate::logging::LOG_TARGET_CONFIG; use crate::message_bar::{Message, MessageBuffer}; use crate::scheduler::{Scheduler, TimerId, Topic}; use crate::window_context::WindowContext; /// Duration after the last user input until an unlimited search is performed. pub const TYPING_SEARCH_DELAY: Duration = Duration::from_millis(500); /// Maximum number of lines for the blocking search while still typing the search regex. const MAX_SEARCH_WHILE_TYPING: Option<usize> = Some(1000); /// Maximum number of search terms stored in the history. const MAX_SEARCH_HISTORY_SIZE: usize = 255; /// Touch zoom speed. const TOUCH_ZOOM_FACTOR: f32 = 0.01; /// Alacritty events. #[derive(Debug, Clone)] pub struct Event { /// Limit event to a specific window. window_id: Option<WindowId>, /// Event payload. payload: EventType, } impl Event { pub fn new<I: Into<Option<WindowId>>>(payload: EventType, window_id: I) -> Self { Self { window_id: window_id.into(), payload } } } impl From<Event> for WinitEvent<Event> { fn from(event: Event) -> Self { WinitEvent::UserEvent(event) } } /// Alacritty events. #[derive(Debug, Clone)] pub enum EventType { Terminal(TerminalEvent), ConfigReload(PathBuf), Message(Message), Scroll(Scroll), CreateWindow(WindowOptions), #[cfg(unix)] IpcConfig(IpcConfig), BlinkCursor, BlinkCursorTimeout, SearchNext, Frame, } impl From<TerminalEvent> for EventType { fn from(event: TerminalEvent) -> Self { Self::Terminal(event) } } /// Regex search state. pub struct SearchState { /// Search direction. pub direction: Direction, /// Current position in the search history. pub history_index: Option<usize>, /// Change in display offset since the beginning of the search. display_offset_delta: i32, /// Search origin in viewport coordinates relative to original display offset. origin: Point, /// Focused match during active search. focused_match: Option<Match>, /// Search regex and history. /// /// During an active search, the first element is the user's current input. /// /// While going through history, the [`SearchState::history_index`] will point to the element /// in history which is currently being previewed. history: VecDeque<String>, /// Compiled search automatons. dfas: Option<RegexSearch>, } impl SearchState { /// Search regex text if a search is active. pub fn regex(&self) -> Option<&String> { self.history_index.and_then(|index| self.history.get(index)) } /// Direction of the search from the search origin. pub fn direction(&self) -> Direction { self.direction } /// Focused match during vi-less search. pub fn focused_match(&self) -> Option<&Match> { self.focused_match.as_ref() } /// Clear the focused match. pub fn clear_focused_match(&mut self) { self.focused_match = None; } /// Active search dfas. pub fn dfas(&mut self) -> Option<&mut RegexSearch> { self.dfas.as_mut() } /// Search regex text if a search is active. fn regex_mut(&mut self) -> Option<&mut String> { self.history_index.and_then(move |index| self.history.get_mut(index)) } } impl Default for SearchState { fn default() -> Self { Self { direction: Direction::Right, display_offset_delta: Default::default(), focused_match: Default::default(), history_index: Default::default(), history: Default::default(), origin: Default::default(), dfas: Default::default(), } } } /// Vi inline search state. pub struct InlineSearchState { /// Whether inline search is currently waiting for search character input. pub char_pending: bool, pub character: Option<char>, direction: Direction, stop_short: bool, } impl Default for InlineSearchState { fn default() -> Self { Self { direction: Direction::Right, char_pending: Default::default(), stop_short: Default::default(), character: Default::default(), } } } pub struct ActionContext<'a, N, T> { pub notifier: &'a mut N, pub terminal: &'a mut Term<T>, pub clipboard: &'a mut Clipboard, pub mouse: &'a mut Mouse, pub touch: &'a mut TouchPurpose, pub modifiers: &'a mut Modifiers, pub display: &'a mut Display, pub message_buffer: &'a mut MessageBuffer, pub config: &'a UiConfig, pub cursor_blink_timed_out: &'a mut bool, pub event_loop: &'a EventLoopWindowTarget<Event>, pub event_proxy: &'a EventLoopProxy<Event>, pub scheduler: &'a mut Scheduler, pub search_state: &'a mut SearchState, pub inline_search_state: &'a mut InlineSearchState, pub dirty: &'a mut bool, pub occluded: &'a mut bool, pub preserve_title: bool, #[cfg(not(windows))] pub master_fd: RawFd, #[cfg(not(windows))] pub shell_pid: u32, } impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionContext<'a, N, T> { #[inline] fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&self, val: B) { self.notifier.notify(val); } /// Request a redraw. #[inline] fn mark_dirty(&mut self) { *self.dirty = true; } #[inline] fn size_info(&self) -> SizeInfo { self.display.size_info } fn scroll(&mut self, scroll: Scroll) { let old_offset = self.terminal.grid().display_offset() as i32; let old_vi_cursor = self.terminal.vi_mode_cursor; self.terminal.scroll_display(scroll); let lines_changed = old_offset - self.terminal.grid().display_offset() as i32; // Keep track of manual display offset changes during search. if self.search_active() { self.search_state.display_offset_delta += lines_changed; } let vi_mode = self.terminal.mode().contains(TermMode::VI); // Update selection. if vi_mode && self.terminal.selection.as_ref().map_or(false, |s| !s.is_empty()) { self.update_selection(self.terminal.vi_mode_cursor.point, Side::Right); } else if self.mouse.left_button_state == ElementState::Pressed || self.mouse.right_button_state == ElementState::Pressed { let display_offset = self.terminal.grid().display_offset(); let point = self.mouse.point(&self.size_info(), display_offset); self.update_selection(point, self.mouse.cell_side); } // Scrolling inside Vi mode moves the cursor, so start typing. if vi_mode { self.on_typing_start(); } // Update dirty if actually scrolled or moved Vi cursor in Vi mode. *self.dirty |= lines_changed != 0 || (vi_mode && old_vi_cursor != self.terminal.vi_mode_cursor); } // Copy text selection. fn copy_selection(&mut self, ty: ClipboardType) { let text = match self.terminal.selection_to_string().filter(|s| !s.is_empty()) { Some(text) => text, None => return, }; if ty == ClipboardType::Selection && self.config.selection.save_to_clipboard { self.clipboard.store(ClipboardType::Clipboard, text.clone()); } self.clipboard.store(ty, text); } fn selection_is_empty(&self) -> bool { self.terminal.selection.as_ref().map_or(true, Selection::is_empty) } fn clear_selection(&mut self) { // Clear the selection on the terminal. let selection = self.terminal.selection.take(); // Mark the terminal as dirty when selection wasn't empty. *self.dirty |= selection.map_or(false, |s| !s.is_empty()); } fn update_selection(&mut self, mut point: Point, side: Side) { let mut selection = match self.terminal.selection.take() { Some(selection) => selection, None => return, }; // Treat motion over message bar like motion over the last line. point.line = min(point.line, self.terminal.bottommost_line()); // Update selection. selection.update(point, side); // Move vi cursor and expand selection. if self.terminal.mode().contains(TermMode::VI) && !self.search_active() { self.terminal.vi_mode_cursor.point = point; selection.include_all(); } self.terminal.selection = Some(selection); *self.dirty = true; } fn start_selection(&mut self, ty: SelectionType, point: Point, side: Side) { self.terminal.selection = Some(Selection::new(ty, point, side)); *self.dirty = true; self.copy_selection(ClipboardType::Selection); } fn toggle_selection(&mut self, ty: SelectionType, point: Point, side: Side) { match &mut self.terminal.selection { Some(selection) if selection.ty == ty && !selection.is_empty() => { self.clear_selection(); }, Some(selection) if !selection.is_empty() => { selection.ty = ty; *self.dirty = true; self.copy_selection(ClipboardType::Selection); }, _ => self.start_selection(ty, point, side), } } #[inline] fn mouse_mode(&self) -> bool { self.terminal.mode().intersects(TermMode::MOUSE_MODE) && !self.terminal.mode().contains(TermMode::VI) } #[inline] fn mouse_mut(&mut self) -> &mut Mouse { self.mouse } #[inline] fn mouse(&self) -> &Mouse { self.mouse } #[inline] fn touch_purpose(&mut self) -> &mut TouchPurpose { self.touch } #[inline] fn modifiers(&mut self) -> &mut Modifiers { self.modifiers } #[inline] fn window(&mut self) -> &mut Window { &mut self.display.window } #[inline] fn display(&mut self) -> &mut Display { self.display } #[inline] fn terminal(&self) -> &Term<T> { self.terminal } #[inline] fn terminal_mut(&mut self) -> &mut Term<T> { self.terminal } fn spawn_new_instance(&mut self) { let mut env_args = env::args(); let alacritty = env_args.next().unwrap(); let mut args: Vec<String> = Vec::new(); // Reuse the arguments passed to Alacritty for the new instance. #[allow(clippy::while_let_on_iterator)] while let Some(arg) = env_args.next() { // New instances shouldn't inherit command. if arg == "-e" || arg == "--command" { break; } // On unix, the working directory of the foreground shell is used by `start_daemon`. #[cfg(not(windows))] if arg == "--working-directory" { let _ = env_args.next(); continue; } args.push(arg); } self.spawn_daemon(&alacritty, &args); } #[cfg(not(windows))] fn create_new_window(&mut self, #[cfg(target_os = "macos")] tabbing_id: Option<String>) { let mut options = WindowOptions::default(); if let Ok(working_directory) = foreground_process_path(self.master_fd, self.shell_pid) { options.terminal_options.working_directory = Some(working_directory); } #[cfg(target_os = "macos")] { options.window_tabbing_id = tabbing_id; } let _ = self.event_proxy.send_event(Event::new(EventType::CreateWindow(options), None)); } #[cfg(windows)] fn create_new_window(&mut self) { let _ = self .event_proxy .send_event(Event::new(EventType::CreateWindow(WindowOptions::default()), None)); } fn spawn_daemon<I, S>(&self, program: &str, args: I) where I: IntoIterator<Item = S> + Debug + Copy, S: AsRef<OsStr>, { #[cfg(not(windows))] let result = spawn_daemon(program, args, self.master_fd, self.shell_pid); #[cfg(windows)] let result = spawn_daemon(program, args); match result { Ok(_) => debug!("Launched {} with args {:?}", program, args), Err(_) => warn!("Unable to launch {} with args {:?}", program, args), } } fn change_font_size(&mut self, delta: f32) { // Round to pick integral px steps, since fonts look better on them. let new_size = self.display.font_size.as_px().round() + delta; self.display.font_size = FontSize::from_px(new_size); let font = self.config.font.clone().with_size(self.display.font_size); self.display.pending_update.set_font(font); } fn reset_font_size(&mut self) { let scale_factor = self.display.window.scale_factor as f32; self.display.font_size = self.config.font.size().scale(scale_factor); self.display .pending_update .set_font(self.config.font.clone().with_size(self.display.font_size)); } #[inline] fn pop_message(&mut self) { if !self.message_buffer.is_empty() { self.display.pending_update.dirty = true; self.message_buffer.pop(); } } #[inline] fn start_search(&mut self, direction: Direction) { // Only create new history entry if the previous regex wasn't empty. if self.search_state.history.front().map_or(true, |regex| !regex.is_empty()) { self.search_state.history.push_front(String::new()); self.search_state.history.truncate(MAX_SEARCH_HISTORY_SIZE); } self.search_state.history_index = Some(0); self.search_state.direction = direction; self.search_state.focused_match = None; // Store original search position as origin and reset location. if self.terminal.mode().contains(TermMode::VI) { self.search_state.origin = self.terminal.vi_mode_cursor.point; self.search_state.display_offset_delta = 0; // Adjust origin for content moving upward on search start. if self.terminal.grid().cursor.point.line + 1 == self.terminal.screen_lines() { self.search_state.origin.line -= 1; } } else { let viewport_top = Line(-(self.terminal.grid().display_offset() as i32)) - 1; let viewport_bottom = viewport_top + self.terminal.bottommost_line(); let last_column = self.terminal.last_column(); self.search_state.origin = match direction { Direction::Right => Point::new(viewport_top, Column(0)), Direction::Left => Point::new(viewport_bottom, last_column), }; } // Enable IME so we can input into the search bar with it if we were in Vi mode. self.window().set_ime_allowed(true); self.display.damage_tracker.frame().mark_fully_damaged(); self.display.pending_update.dirty = true; } #[inline] fn confirm_search(&mut self) { // Just cancel search when not in vi mode. if !self.terminal.mode().contains(TermMode::VI) { self.cancel_search(); return; } // Force unlimited search if the previous one was interrupted. let timer_id = TimerId::new(Topic::DelayedSearch, self.display.window.id()); if self.scheduler.scheduled(timer_id) { self.goto_match(None); } self.exit_search(); } #[inline] fn cancel_search(&mut self) { if self.terminal.mode().contains(TermMode::VI) { // Recover pre-search state in vi mode. self.search_reset_state(); } else if let Some(focused_match) = &self.search_state.focused_match { // Create a selection for the focused match. let start = *focused_match.start(); let end = *focused_match.end(); self.start_selection(SelectionType::Simple, start, Side::Left); self.update_selection(end, Side::Right); self.copy_selection(ClipboardType::Selection); } self.search_state.dfas = None; self.exit_search(); } #[inline] fn search_input(&mut self, c: char) { match self.search_state.history_index { Some(0) => (), // When currently in history, replace active regex with history on change. Some(index) => { self.search_state.history[0] = self.search_state.history[index].clone(); self.search_state.history_index = Some(0); }, None => return, } let regex = &mut self.search_state.history[0]; match c { // Handle backspace/ctrl+h. '\x08' | '\x7f' => { let _ = regex.pop(); }, // Add ascii and unicode text. ' '..='~' | '\u{a0}'..='\u{10ffff}' => regex.push(c), // Ignore non-printable characters. _ => return, } if !self.terminal.mode().contains(TermMode::VI) { // Clear selection so we do not obstruct any matches. self.terminal.selection = None; } self.update_search(); } #[inline] fn search_pop_word(&mut self) { if let Some(regex) = self.search_state.regex_mut() { *regex = regex.trim_end().to_owned(); regex.truncate(regex.rfind(' ').map_or(0, |i| i + 1)); self.update_search(); } } /// Go to the previous regex in the search history. #[inline] fn search_history_previous(&mut self) { let index = match &mut self.search_state.history_index { None => return, Some(index) if *index + 1 >= self.search_state.history.len() => return, Some(index) => index, }; *index += 1; self.update_search(); } /// Go to the previous regex in the search history. #[inline] fn search_history_next(&mut self) { let index = match &mut self.search_state.history_index { Some(0) | None => return, Some(index) => index, }; *index -= 1; self.update_search(); } #[inline] fn advance_search_origin(&mut self, direction: Direction) { // Use focused match as new search origin if available. if let Some(focused_match) = &self.search_state.focused_match { let new_origin = match direction { Direction::Right => focused_match.end().add(self.terminal, Boundary::None, 1), Direction::Left => focused_match.start().sub(self.terminal, Boundary::None, 1), }; self.terminal.scroll_to_point(new_origin); self.search_state.display_offset_delta = 0; self.search_state.origin = new_origin; } // Search for the next match using the supplied direction. let search_direction = mem::replace(&mut self.search_state.direction, direction); self.goto_match(None); self.search_state.direction = search_direction; // If we found a match, we set the search origin right in front of it to make sure that // after modifications to the regex the search is started without moving the focused match // around. let focused_match = match &self.search_state.focused_match { Some(focused_match) => focused_match, None => return, }; // Set new origin to the left/right of the match, depending on search direction. let new_origin = match self.search_state.direction { Direction::Right => *focused_match.start(), Direction::Left => *focused_match.end(), }; // Store the search origin with display offset by checking how far we need to scroll to it. let old_display_offset = self.terminal.grid().display_offset() as i32; self.terminal.scroll_to_point(new_origin); let new_display_offset = self.terminal.grid().display_offset() as i32; self.search_state.display_offset_delta = new_display_offset - old_display_offset; // Store origin and scroll back to the match. self.terminal.scroll_display(Scroll::Delta(-self.search_state.display_offset_delta)); self.search_state.origin = new_origin; } /// Find the next search match. fn search_next(&mut self, origin: Point, direction: Direction, side: Side) -> Option<Match> { self.search_state .dfas .as_mut() .and_then(|dfas| self.terminal.search_next(dfas, origin, direction, side, None)) } #[inline] fn search_direction(&self) -> Direction { self.search_state.direction } #[inline] fn search_active(&self) -> bool { self.search_state.history_index.is_some() } /// Handle keyboard typing start. /// /// This will temporarily disable some features like terminal cursor blinking or the mouse /// cursor. /// /// All features are re-enabled again automatically. #[inline] fn on_typing_start(&mut self) { // Disable cursor blinking. let timer_id = TimerId::new(Topic::BlinkCursor, self.display.window.id()); if self.scheduler.unschedule(timer_id).is_some() { self.schedule_blinking(); // Mark the cursor as visible and queue redraw if the cursor was hidden. if mem::take(&mut self.display.cursor_hidden) { *self.dirty = true; } } else if *self.cursor_blink_timed_out { self.update_cursor_blinking(); } // Hide mouse cursor. if self.config.mouse.hide_when_typing { self.display.window.set_mouse_visible(false); } } /// Process a new character for keyboard hints. fn hint_input(&mut self, c: char) { if let Some(hint) = self.display.hint_state.keyboard_input(self.terminal, c) { self.mouse.block_hint_launcher = false; self.trigger_hint(&hint); } *self.dirty = true; } /// Trigger a hint action. fn trigger_hint(&mut self, hint: &HintMatch) { if self.mouse.block_hint_launcher { return; } let hint_bounds = hint.bounds(); let text = match hint.hyperlink() { Some(hyperlink) => hyperlink.uri().to_owned(), None => self.terminal.bounds_to_string(*hint_bounds.start(), *hint_bounds.end()), }; match &hint.action() { // Launch an external program. HintAction::Command(command) => { let mut args = command.args().to_vec(); args.push(text); self.spawn_daemon(command.program(), &args); }, // Copy the text to the clipboard. HintAction::Action(HintInternalAction::Copy) => { self.clipboard.store(ClipboardType::Clipboard, text); }, // Write the text to the PTY/search. HintAction::Action(HintInternalAction::Paste) => self.paste(&text, true), // Select the text. HintAction::Action(HintInternalAction::Select) => { self.start_selection(SelectionType::Simple, *hint_bounds.start(), Side::Left); self.update_selection(*hint_bounds.end(), Side::Right); self.copy_selection(ClipboardType::Selection); }, // Move the vi mode cursor. HintAction::Action(HintInternalAction::MoveViModeCursor) => { // Enter vi mode if we're not in it already. if !self.terminal.mode().contains(TermMode::VI) { self.terminal.toggle_vi_mode(); } self.terminal.vi_goto_point(*hint_bounds.start()); self.mark_dirty(); }, } } /// Expand the selection to the current mouse cursor position. #[inline] fn expand_selection(&mut self) { let selection_type = match self.mouse().click_state { ClickState::Click => { if self.modifiers().state().control_key() { SelectionType::Block } else { SelectionType::Simple } }, ClickState::DoubleClick => SelectionType::Semantic, ClickState::TripleClick => SelectionType::Lines, ClickState::None => return, }; // Load mouse point, treating message bar and padding as the closest cell. let display_offset = self.terminal().grid().display_offset(); let point = self.mouse().point(&self.size_info(), display_offset); let cell_side = self.mouse().cell_side; let selection = match &mut self.terminal_mut().selection { Some(selection) => selection, None => return, }; selection.ty = selection_type; self.update_selection(point, cell_side); // Move vi mode cursor to mouse click position. if self.terminal().mode().contains(TermMode::VI) && !self.search_active() { self.terminal_mut().vi_mode_cursor.point = point; } } /// Handle beginning of terminal text input. fn on_terminal_input_start(&mut self) { self.on_typing_start(); self.clear_selection(); if self.terminal().grid().display_offset() != 0 { self.scroll(Scroll::Bottom); } } /// Paste a text into the terminal. fn paste(&mut self, text: &str, bracketed: bool) { if self.search_active() { for c in text.chars() { self.search_input(c); } } else if bracketed && self.terminal().mode().contains(TermMode::BRACKETED_PASTE) { self.on_terminal_input_start(); self.write_to_pty(&b"\x1b[200~"[..]); // Write filtered escape sequences. // // We remove `\x1b` to ensure it's impossible for the pasted text to write the bracketed // paste end escape `\x1b[201~` and `\x03` since some shells incorrectly terminate // bracketed paste when they receive it. let filtered = text.replace(['\x1b', '\x03'], ""); self.write_to_pty(filtered.into_bytes()); self.write_to_pty(&b"\x1b[201~"[..]); } else { self.on_terminal_input_start(); let payload = if bracketed { // In non-bracketed (ie: normal) mode, terminal applications cannot distinguish // pasted data from keystrokes. // // In theory, we should construct the keystrokes needed to produce the data we are // pasting... since that's neither practical nor sensible (and probably an // impossible task to solve in a general way), we'll just replace line breaks // (windows and unix style) with a single carriage return (\r, which is what the // Enter key produces). text.replace("\r\n", "\r").replace('\n', "\r").into_bytes() } else { // When we explicitly disable bracketed paste don't manipulate with the input, // so we pass user input as is. text.to_owned().into_bytes() }; self.write_to_pty(payload); } } /// Toggle the vi mode status. #[inline] fn toggle_vi_mode(&mut self) { let was_in_vi_mode = self.terminal.mode().contains(TermMode::VI); if was_in_vi_mode { // If we had search running when leaving Vi mode we should mark terminal fully damaged // to cleanup highlighted results. if self.search_state.dfas.take().is_some() { self.display.damage_tracker.frame().mark_fully_damaged(); } } else { self.clear_selection(); } if self.search_active() { self.cancel_search(); } // We don't want IME in Vi mode. self.window().set_ime_allowed(was_in_vi_mode); self.terminal.toggle_vi_mode(); *self.dirty = true; } /// Get vi inline search state. fn inline_search_state(&mut self) -> &mut InlineSearchState { self.inline_search_state } /// Start vi mode inline search. fn start_inline_search(&mut self, direction: Direction, stop_short: bool) { self.inline_search_state.stop_short = stop_short; self.inline_search_state.direction = direction; self.inline_search_state.char_pending = true; } /// Jump to the next matching character in the line. fn inline_search_next(&mut self) { let direction = self.inline_search_state.direction; self.inline_search(direction); } /// Jump to the next matching character in the line. fn inline_search_previous(&mut self) { let direction = self.inline_search_state.direction.opposite(); self.inline_search(direction); } fn message(&self) -> Option<&Message> { self.message_buffer.message() } fn config(&self) -> &UiConfig { self.config } #[cfg(target_os = "macos")] fn event_loop(&self) -> &EventLoopWindowTarget<Event> { self.event_loop } fn clipboard_mut(&mut self) -> &mut Clipboard { self.clipboard } fn scheduler_mut(&mut self) -> &mut Scheduler { self.scheduler } } impl<'a, N: Notify + 'a, T: EventListener> ActionContext<'a, N, T> { fn update_search(&mut self) { let regex = match self.search_state.regex() { Some(regex) => regex, None => return, }; // Hide cursor while typing into the search bar. if self.config.mouse.hide_when_typing { self.display.window.set_mouse_visible(false); } if regex.is_empty() { // Stop search if there's nothing to search for. self.search_reset_state(); self.search_state.dfas = None; } else { // Create search dfas for the new regex string. self.search_state.dfas = RegexSearch::new(regex).ok(); // Update search highlighting. self.goto_match(MAX_SEARCH_WHILE_TYPING); } *self.dirty = true; } /// Reset terminal to the state before search was started. fn search_reset_state(&mut self) { // Unschedule pending timers. let timer_id = TimerId::new(Topic::DelayedSearch, self.display.window.id()); self.scheduler.unschedule(timer_id); // Clear focused match. self.search_state.focused_match = None; // The viewport reset logic is only needed for vi mode, since without it our origin is // always at the current display offset instead of at the vi cursor position which we need // to recover to. if !self.terminal.mode().contains(TermMode::VI) { return; } // Reset display offset and cursor position. self.terminal.vi_mode_cursor.point = self.search_state.origin; self.terminal.scroll_display(Scroll::Delta(self.search_state.display_offset_delta)); self.search_state.display_offset_delta = 0; *self.dirty = true; } /// Jump to the first regex match from the search origin. fn goto_match(&mut self, mut limit: Option<usize>) { let dfas = match &mut self.search_state.dfas { Some(dfas) => dfas, None => return, }; // Limit search only when enough lines are available to run into the limit. limit = limit.filter(|&limit| limit <= self.terminal.total_lines()); // Jump to the next match. let direction = self.search_state.direction; let clamped_origin = self.search_state.origin.grid_clamp(self.terminal, Boundary::Grid); match self.terminal.search_next(dfas, clamped_origin, direction, Side::Left, limit) { Some(regex_match) => { let old_offset = self.terminal.grid().display_offset() as i32; if self.terminal.mode().contains(TermMode::VI) { // Move vi cursor to the start of the match. self.terminal.vi_goto_point(*regex_match.start()); } else { // Select the match when vi mode is not active. self.terminal.scroll_to_point(*regex_match.start()); } // Update the focused match. self.search_state.focused_match = Some(regex_match); // Store number of lines the viewport had to be moved. let display_offset = self.terminal.grid().display_offset(); self.search_state.display_offset_delta += old_offset - display_offset as i32; // Since we found a result, we require no delayed re-search. let timer_id = TimerId::new(Topic::DelayedSearch, self.display.window.id()); self.scheduler.unschedule(timer_id); }, // Reset viewport only when we know there is no match, to prevent unnecessary jumping. None if limit.is_none() => self.search_reset_state(), None => { // Schedule delayed search if we ran into our search limit. let timer_id = TimerId::new(Topic::DelayedSearch, self.display.window.id()); if !self.scheduler.scheduled(timer_id) { let event = Event::new(EventType::SearchNext, self.display.window.id()); self.scheduler.schedule(event, TYPING_SEARCH_DELAY, false, timer_id); } // Clear focused match. self.search_state.focused_match = None; }, } *self.dirty = true; } /// Cleanup the search state. fn exit_search(&mut self) { let vi_mode = self.terminal.mode().contains(TermMode::VI); self.window().set_ime_allowed(!vi_mode); self.display.damage_tracker.frame().mark_fully_damaged(); self.display.pending_update.dirty = true; self.search_state.history_index = None; // Clear focused match. self.search_state.focused_match = None; } /// Update the cursor blinking state. fn update_cursor_blinking(&mut self) { // Get config cursor style. let mut cursor_style = self.config.cursor.style; let vi_mode = self.terminal.mode().contains(TermMode::VI); if vi_mode { cursor_style = self.config.cursor.vi_mode_style.unwrap_or(cursor_style); } // Check terminal cursor style. let terminal_blinking = self.terminal.cursor_style().blinking; let mut blinking = cursor_style.blinking_override().unwrap_or(terminal_blinking); blinking &= (vi_mode || self.terminal().mode().contains(TermMode::SHOW_CURSOR)) && self.display().ime.preedit().is_none(); // Update cursor blinking state. let window_id = self.display.window.id(); self.scheduler.unschedule(TimerId::new(Topic::BlinkCursor, window_id)); self.scheduler.unschedule(TimerId::new(Topic::BlinkTimeout, window_id)); // Reset blinkinig timeout. *self.cursor_blink_timed_out = false; if blinking && self.terminal.is_focused { self.schedule_blinking(); self.schedule_blinking_timeout(); } else { self.display.cursor_hidden = false; *self.dirty = true; } } fn schedule_blinking(&mut self) { let window_id = self.display.window.id(); let timer_id = TimerId::new(Topic::BlinkCursor, window_id); let event = Event::new(EventType::BlinkCursor, window_id); let blinking_interval = Duration::from_millis(self.config.cursor.blink_interval()); self.scheduler.schedule(event, blinking_interval, true, timer_id); } fn schedule_blinking_timeout(&mut self) { let blinking_timeout = self.config.cursor.blink_timeout(); if blinking_timeout == Duration::ZERO { return; } let window_id = self.display.window.id(); let event = Event::new(EventType::BlinkCursorTimeout, window_id); let timer_id = TimerId::new(Topic::BlinkTimeout, window_id); self.scheduler.schedule(event, blinking_timeout, false, timer_id); } /// Perform vi mode inline search in the specified direction. fn inline_search(&mut self, direction: Direction) { let c = match self.inline_search_state.character { Some(c) => c, None => return, }; let mut buf = [0; 4]; let search_character = c.encode_utf8(&mut buf); // Find next match in this line. let vi_point = self.terminal.vi_mode_cursor.point; let point = match direction { Direction::Right => self.terminal.inline_search_right(vi_point, search_character), Direction::Left => self.terminal.inline_search_left(vi_point, search_character), }; // Jump to point if there's a match. if let Ok(mut point) = point { if self.inline_search_state.stop_short { let grid = self.terminal.grid(); point = match direction { Direction::Right => { grid.iter_from(point).prev().map_or(point, |cell| cell.point) }, Direction::Left => { grid.iter_from(point).next().map_or(point, |cell| cell.point) }, }; } self.terminal.vi_goto_point(point); self.mark_dirty(); } } } /// Identified purpose of the touch input. #[derive(Debug)] pub enum TouchPurpose { None, Select(TouchEvent), Scroll(TouchEvent), Zoom(TouchZoom), Tap(TouchEvent), Invalid(HashSet<u64, RandomState>), } impl Default for TouchPurpose { fn default() -> Self { Self::None } } /// Touch zooming state. #[derive(Debug)] pub struct TouchZoom { slots: (TouchEvent, TouchEvent), fractions: f32, } impl TouchZoom { pub fn new(slots: (TouchEvent, TouchEvent)) -> Self { Self { slots, fractions: Default::default() } } /// Get slot distance change since last update. pub fn font_delta(&mut self, slot: TouchEvent) -> f32 { let old_distance = self.distance(); // Update touch slots. if slot.id == self.slots.0.id { self.slots.0 = slot; } else { self.slots.1 = slot; } // Calculate font change in `FONT_SIZE_STEP` increments. let delta = (self.distance() - old_distance) * TOUCH_ZOOM_FACTOR + self.fractions; let font_delta = (delta.abs() / FONT_SIZE_STEP).floor() * FONT_SIZE_STEP * delta.signum(); self.fractions = delta - font_delta; font_delta } /// Get active touch slots. pub fn slots(&self) -> HashSet<u64, RandomState> { let mut set = HashSet::default(); set.insert(self.slots.0.id); set.insert(self.slots.1.id); set } /// Calculate distance between slots. fn distance(&self) -> f32 { let delta_x = self.slots.0.location.x - self.slots.1.location.x; let delta_y = self.slots.0.location.y - self.slots.1.location.y; delta_x.hypot(delta_y) as f32 } } /// State of the mouse. #[derive(Debug)] pub struct Mouse { pub left_button_state: ElementState, pub middle_button_state: ElementState, pub right_button_state: ElementState, pub last_click_timestamp: Instant, pub last_click_button: MouseButton, pub click_state: ClickState, pub accumulated_scroll: AccumulatedScroll, pub cell_side: Side, pub lines_scrolled: f32, pub block_hint_launcher: bool, pub hint_highlight_dirty: bool, pub inside_text_area: bool, pub x: usize, pub y: usize, } impl Default for Mouse { fn default() -> Mouse { Mouse { last_click_timestamp: Instant::now(), last_click_button: MouseButton::Left, left_button_state: ElementState::Released, middle_button_state: ElementState::Released, right_button_state: ElementState::Released, click_state: ClickState::None, cell_side: Side::Left, hint_highlight_dirty: Default::default(), block_hint_launcher: Default::default(), inside_text_area: Default::default(), lines_scrolled: Default::default(), accumulated_scroll: Default::default(), x: Default::default(), y: Default::default(), } } } impl Mouse { /// Convert mouse pixel coordinates to viewport point. /// /// If the coordinates are outside of the terminal grid, like positions inside the padding, the /// coordinates will be clamped to the closest grid coordinates. #[inline] pub fn point(&self, size: &SizeInfo, display_offset: usize) -> Point { let col = self.x.saturating_sub(size.padding_x() as usize) / (size.cell_width() as usize); let col = min(Column(col), size.last_column()); let line = self.y.saturating_sub(size.padding_y() as usize) / (size.cell_height() as usize); let line = min(line, size.bottommost_line().0 as usize); term::viewport_to_point(display_offset, Point::new(line, col)) } } #[derive(Debug, Eq, PartialEq)] pub enum ClickState { None, Click, DoubleClick, TripleClick, } /// The amount of scroll accumulated from the pointer events. #[derive(Default, Debug)] pub struct AccumulatedScroll { /// Scroll we should perform along `x` axis. pub x: f64, /// Scroll we should perform along `y` axis. pub y: f64, } impl input::Processor<EventProxy, ActionContext<'_, Notifier, EventProxy>> { /// Handle events from winit. pub fn handle_event(&mut self, event: WinitEvent<Event>) { match event { WinitEvent::UserEvent(Event { payload, .. }) => match payload { EventType::SearchNext => self.ctx.goto_match(None), EventType::Scroll(scroll) => self.ctx.scroll(scroll), EventType::BlinkCursor => { // Only change state when timeout isn't reached, since we could get // BlinkCursor and BlinkCursorTimeout events at the same time. if !*self.ctx.cursor_blink_timed_out { self.ctx.display.cursor_hidden ^= true; *self.ctx.dirty = true; } }, EventType::BlinkCursorTimeout => { // Disable blinking after timeout reached. let timer_id = TimerId::new(Topic::BlinkCursor, self.ctx.display.window.id()); self.ctx.scheduler.unschedule(timer_id); *self.ctx.cursor_blink_timed_out = true; self.ctx.display.cursor_hidden = false; *self.ctx.dirty = true; }, // Add message only if it's not already queued. EventType::Message(message) if !self.ctx.message_buffer.is_queued(&message) => { self.ctx.message_buffer.push(message); self.ctx.display.pending_update.dirty = true; }, EventType::Terminal(event) => match event { TerminalEvent::Title(title) => { if !self.ctx.preserve_title && self.ctx.config.window.dynamic_title { self.ctx.window().set_title(title); } }, TerminalEvent::ResetTitle => { let window_config = &self.ctx.config.window; if window_config.dynamic_title { self.ctx.display.window.set_title(window_config.identity.title.clone()); } }, TerminalEvent::Bell => { // Set window urgency hint when window is not focused. let focused = self.ctx.terminal.is_focused; if !focused && self.ctx.terminal.mode().contains(TermMode::URGENCY_HINTS) { self.ctx.window().set_urgent(true); } // Ring visual bell. self.ctx.display.visual_bell.ring(); // Execute bell command. if let Some(bell_command) = &self.ctx.config.bell.command { self.ctx.spawn_daemon(bell_command.program(), bell_command.args()); } }, TerminalEvent::ClipboardStore(clipboard_type, content) => { if self.ctx.terminal.is_focused { self.ctx.clipboard.store(clipboard_type, content); } }, TerminalEvent::ClipboardLoad(clipboard_type, format) => { if self.ctx.terminal.is_focused { let text = format(self.ctx.clipboard.load(clipboard_type).as_str()); self.ctx.write_to_pty(text.into_bytes()); } }, TerminalEvent::ColorRequest(index, format) => { let color = self.ctx.terminal().colors()[index] .map(Rgb) .unwrap_or(self.ctx.display.colors[index]); self.ctx.write_to_pty(format(color.0).into_bytes()); }, TerminalEvent::TextAreaSizeRequest(format) => { let text = format(self.ctx.size_info().into()); self.ctx.write_to_pty(text.into_bytes()); }, TerminalEvent::PtyWrite(text) => self.ctx.write_to_pty(text.into_bytes()), TerminalEvent::MouseCursorDirty => self.reset_mouse_cursor(), TerminalEvent::CursorBlinkingChange => self.ctx.update_cursor_blinking(), TerminalEvent::Exit | TerminalEvent::ChildExit(_) | TerminalEvent::Wakeup => (), }, #[cfg(unix)] EventType::IpcConfig(_) => (), EventType::Message(_) | EventType::ConfigReload(_) | EventType::CreateWindow(_) | EventType::Frame => (), }, WinitEvent::WindowEvent { event, .. } => { match event { WindowEvent::CloseRequested => self.ctx.terminal.exit(), WindowEvent::ScaleFactorChanged { scale_factor, .. } => { let old_scale_factor = mem::replace(&mut self.ctx.window().scale_factor, scale_factor); let display_update_pending = &mut self.ctx.display.pending_update; // Rescale font size for the new factor. let font_scale = scale_factor as f32 / old_scale_factor as f32; self.ctx.display.font_size = self.ctx.display.font_size.scale(font_scale); let font = self.ctx.config.font.clone(); display_update_pending.set_font(font.with_size(self.ctx.display.font_size)); }, WindowEvent::Resized(size) => { // Ignore resize events to zero in any dimension, to avoid issues with Winit // and the ConPTY. A 0x0 resize will also occur when the window is minimized // on Windows. if size.width == 0 || size.height == 0 { return; } self.ctx.display.pending_update.set_dimensions(size); }, WindowEvent::KeyboardInput { event, is_synthetic: false, .. } => { self.key_input(event); }, WindowEvent::ModifiersChanged(modifiers) => self.modifiers_input(modifiers), WindowEvent::MouseInput { state, button, .. } => { self.ctx.window().set_mouse_visible(true); self.mouse_input(state, button); }, WindowEvent::CursorMoved { position, .. } => { self.ctx.window().set_mouse_visible(true); self.mouse_moved(position); }, WindowEvent::MouseWheel { delta, phase, .. } => { self.ctx.window().set_mouse_visible(true); self.mouse_wheel_input(delta, phase); }, WindowEvent::Touch(touch) => self.touch(touch), WindowEvent::Focused(is_focused) => { self.ctx.terminal.is_focused = is_focused; // When the unfocused hollow is used we must redraw on focus change. if self.ctx.config.cursor.unfocused_hollow { *self.ctx.dirty = true; } // Reset the urgency hint when gaining focus. if is_focused { self.ctx.window().set_urgent(false); } self.ctx.update_cursor_blinking(); self.on_focus_change(is_focused); }, WindowEvent::Occluded(occluded) => { *self.ctx.occluded = occluded; }, WindowEvent::DroppedFile(path) => { let path: String = path.to_string_lossy().into(); self.ctx.paste(&(path + " "), true); }, WindowEvent::CursorLeft { .. } => { self.ctx.mouse.inside_text_area = false; if self.ctx.display().highlighted_hint.is_some() { *self.ctx.dirty = true; } }, WindowEvent::Ime(ime) => match ime { Ime::Commit(text) => { *self.ctx.dirty = true; // Don't use bracketed paste for single char input. self.ctx.paste(&text, text.chars().count() > 1); self.ctx.update_cursor_blinking(); }, Ime::Preedit(text, cursor_offset) => { let preedit = if text.is_empty() { None } else { Some(Preedit::new(text, cursor_offset.map(|offset| offset.0))) }; if self.ctx.display.ime.preedit() != preedit.as_ref() { self.ctx.display.ime.set_preedit(preedit); self.ctx.update_cursor_blinking(); *self.ctx.dirty = true; } }, Ime::Enabled => { self.ctx.display.ime.set_enabled(true); *self.ctx.dirty = true; }, Ime::Disabled => { self.ctx.display.ime.set_enabled(false); *self.ctx.dirty = true; }, }, WindowEvent::KeyboardInput { is_synthetic: true, .. } | WindowEvent::ActivationTokenDone { .. } | WindowEvent::TouchpadPressure { .. } | WindowEvent::TouchpadMagnify { .. } | WindowEvent::TouchpadRotate { .. } | WindowEvent::SmartMagnify { .. } | WindowEvent::CursorEntered { .. } | WindowEvent::AxisMotion { .. } | WindowEvent::HoveredFileCancelled | WindowEvent::Destroyed | WindowEvent::ThemeChanged(_) | WindowEvent::HoveredFile(_) | WindowEvent::RedrawRequested | WindowEvent::Moved(_) => (), } }, WinitEvent::Suspended { .. } | WinitEvent::NewEvents { .. } | WinitEvent::DeviceEvent { .. } | WinitEvent::LoopExiting | WinitEvent::Resumed | WinitEvent::MemoryWarning | WinitEvent::AboutToWait => (), } } } /// The event processor. /// /// Stores some state from received events and dispatches actions when they are /// triggered. pub struct Processor { windows: HashMap<WindowId, WindowContext, RandomState>, gl_display: Option<GlutinDisplay>, #[cfg(unix)] global_ipc_options: ParsedOptions, cli_options: CliOptions, config: Rc<UiConfig>, } impl Processor { /// Create a new event processor. /// /// Takes a writer which is expected to be hooked up to the write end of a PTY. pub fn new( config: UiConfig, cli_options: CliOptions, _event_loop: &EventLoop<Event>, ) -> Processor { Processor { cli_options, gl_display: None, config: Rc::new(config), windows: Default::default(), #[cfg(unix)] global_ipc_options: Default::default(), } } /// Create initial window and load GL platform. /// /// This will initialize the OpenGL Api and pick a config that /// will be used for the rest of the windows. pub fn create_initial_window( &mut self, event_loop: &EventLoopWindowTarget<Event>, proxy: EventLoopProxy<Event>, options: WindowOptions, ) -> Result<(), Box<dyn Error>> { let window_context = WindowContext::initial(event_loop, proxy, self.config.clone(), options)?; self.gl_display = Some(window_context.display.gl_context().display()); self.windows.insert(window_context.id(), window_context); Ok(()) } /// Create a new terminal window. pub fn create_window( &mut self, event_loop: &EventLoopWindowTarget<Event>, proxy: EventLoopProxy<Event>, options: WindowOptions, ) -> Result<(), Box<dyn Error>> { let window = self.windows.iter().next().as_ref().unwrap().1; // Overide config with CLI/IPC options. let mut config_overrides = options.config_overrides(); #[cfg(unix)] config_overrides.extend_from_slice(&self.global_ipc_options); let mut config = self.config.clone(); config = config_overrides.override_config_rc(config); #[allow(unused_mut)] let mut window_context = window.additional(event_loop, proxy, config, options, config_overrides)?; self.windows.insert(window_context.id(), window_context); Ok(()) } /// Run the event loop. /// /// The result is exit code generate from the loop. pub fn run( &mut self, event_loop: EventLoop<Event>, initial_window_options: WindowOptions, ) -> Result<(), Box<dyn Error>> { let proxy = event_loop.create_proxy(); let mut scheduler = Scheduler::new(proxy.clone()); let mut initial_window_options = Some(initial_window_options); // Disable all device events, since we don't care about them. event_loop.listen_device_events(DeviceEvents::Never); let mut initial_window_error = Ok(()); let initial_window_error_loop = &mut initial_window_error; // SAFETY: Since this takes a pointer to the winit event loop, it MUST be dropped first, // which is done by `move` into event loop. let mut clipboard = unsafe { Clipboard::new(event_loop.raw_display_handle()) }; let result = event_loop.run(move |event, event_loop| { if self.config.debug.print_events { info!("winit event: {:?}", event); } // Ignore all events we do not care about. if Self::skip_event(&event) { return; } match event { // The event loop just got initialized. Create a window. WinitEvent::Resumed => { // Creating window inside event loop is required for platforms like macOS to // properly initialize state, like tab management. Otherwise the first // window won't handle tabs. let initial_window_options = match initial_window_options.take() { Some(initial_window_options) => initial_window_options, None => return, }; if let Err(err) = self.create_initial_window( event_loop, proxy.clone(), initial_window_options, ) { *initial_window_error_loop = Err(err); event_loop.exit(); return; } info!("Initialisation complete"); }, WinitEvent::LoopExiting => { match self.gl_display.take() { #[cfg(not(target_os = "macos"))] Some(glutin::display::Display::Egl(display)) => { // Ensure that all the windows are dropped, so the destructors for // Renderer and contexts ran. self.windows.clear(); // SAFETY: the display is being destroyed after destroying all the // windows, thus no attempt to access the EGL state will be made. unsafe { display.terminate(); } }, _ => (), } }, // NOTE: This event bypasses batching to minimize input latency. WinitEvent::UserEvent(Event { window_id: Some(window_id), payload: EventType::Terminal(TerminalEvent::Wakeup), }) => { if let Some(window_context) = self.windows.get_mut(&window_id) { window_context.dirty = true; if window_context.display.window.has_frame { window_context.display.window.request_redraw(); } } }, // NOTE: This event bypasses batching to minimize input latency. WinitEvent::UserEvent(Event { window_id: Some(window_id), payload: EventType::Frame, }) => { if let Some(window_context) = self.windows.get_mut(&window_id) { window_context.display.window.has_frame = true; if window_context.dirty { window_context.display.window.request_redraw(); } } }, // Check for shutdown. WinitEvent::UserEvent(Event { window_id: Some(window_id), payload: EventType::Terminal(TerminalEvent::Exit), }) => { // Remove the closed terminal. let window_context = match self.windows.remove(&window_id) { Some(window_context) => window_context, None => return, }; // Unschedule pending events. scheduler.unschedule_window(window_context.id()); // Shutdown if no more terminals are open. if self.windows.is_empty() { // Write ref tests of last window to disk. if self.config.debug.ref_test { window_context.write_ref_test_results(); } event_loop.exit(); } }, WinitEvent::WindowEvent { window_id, event: WindowEvent::RedrawRequested } => { let window_context = match self.windows.get_mut(&window_id) { Some(window_context) => window_context, None => return, }; window_context.handle_event( event_loop, &proxy, &mut clipboard, &mut scheduler, event, ); window_context.draw(&mut scheduler); }, // Process all pending events. WinitEvent::AboutToWait => { // Dispatch event to all windows. for window_context in self.windows.values_mut() { window_context.handle_event( event_loop, &proxy, &mut clipboard, &mut scheduler, WinitEvent::AboutToWait, ); } // Update the scheduler after event processing to ensure // the event loop deadline is as accurate as possible. let control_flow = match scheduler.update() { Some(instant) => ControlFlow::WaitUntil(instant), None => ControlFlow::Wait, }; event_loop.set_control_flow(control_flow); }, // Process config update. WinitEvent::UserEvent(Event { payload: EventType::ConfigReload(path), .. }) => { // Clear config logs from message bar for all terminals. for window_context in self.windows.values_mut() { if !window_context.message_buffer.is_empty() { window_context.message_buffer.remove_target(LOG_TARGET_CONFIG); window_context.display.pending_update.dirty = true; } } // Load config and update each terminal. if let Ok(config) = config::reload(&path, &mut self.cli_options) { self.config = Rc::new(config); for window_context in self.windows.values_mut() { window_context.update_config(self.config.clone()); } } }, // Process IPC config update. #[cfg(unix)] WinitEvent::UserEvent(Event { payload: EventType::IpcConfig(ipc_config), window_id, }) => { // Try and parse options as toml. let mut options = ParsedOptions::from_options(&ipc_config.options); // Override IPC config for each window with matching ID. for (_, window_context) in self .windows .iter_mut() .filter(|(id, _)| window_id.is_none() || window_id == Some(**id)) { if ipc_config.reset { window_context.reset_window_config(self.config.clone()); } else { window_context.add_window_config(self.config.clone(), &options); } } // Persist global options for future windows. if window_id.is_none() { if ipc_config.reset { self.global_ipc_options.clear(); } else { self.global_ipc_options.append(&mut options); } } }, // Create a new terminal window. WinitEvent::UserEvent(Event { payload: EventType::CreateWindow(options), .. }) => { // XXX Ensure that no context is current when creating a new window, // otherwise it may lock the backing buffer of the // surface of current context when asking // e.g. EGL on Wayland to create a new context. for window_context in self.windows.values_mut() { window_context.display.make_not_current(); } if let Err(err) = self.create_window(event_loop, proxy.clone(), options) { error!("Could not open window: {:?}", err); } }, // Process events affecting all windows. WinitEvent::UserEvent(event @ Event { window_id: None, .. }) => { for window_context in self.windows.values_mut() { window_context.handle_event( event_loop, &proxy, &mut clipboard, &mut scheduler, event.clone().into(), ); } }, // Process window-specific events. WinitEvent::WindowEvent { window_id, .. } | WinitEvent::UserEvent(Event { window_id: Some(window_id), .. }) => { if let Some(window_context) = self.windows.get_mut(&window_id) { window_context.handle_event( event_loop, &proxy, &mut clipboard, &mut scheduler, event, ); } }, _ => (), } }); if initial_window_error.is_err() { initial_window_error } else { result.map_err(Into::into) } } /// Check if an event is irrelevant and can be skipped. fn skip_event(event: &WinitEvent<Event>) -> bool { match event { WinitEvent::NewEvents(StartCause::Init) => false, WinitEvent::WindowEvent { event, .. } => matches!( event, WindowEvent::KeyboardInput { is_synthetic: true, .. } | WindowEvent::TouchpadPressure { .. } | WindowEvent::CursorEntered { .. } | WindowEvent::AxisMotion { .. } | WindowEvent::HoveredFileCancelled | WindowEvent::Destroyed | WindowEvent::HoveredFile(_) | WindowEvent::Moved(_) ), WinitEvent::Suspended { .. } | WinitEvent::NewEvents { .. } => true, _ => false, } } } #[derive(Debug, Clone)] pub struct EventProxy { proxy: EventLoopProxy<Event>, window_id: WindowId, } impl EventProxy { pub fn new(proxy: EventLoopProxy<Event>, window_id: WindowId) -> Self { Self { proxy, window_id } } /// Send an event to the event loop. pub fn send_event(&self, event: EventType) { let _ = self.proxy.send_event(Event::new(event, self.window_id)); } } impl EventListener for EventProxy { fn send_event(&self, event: TerminalEvent) { let _ = self.proxy.send_event(Event::new(event.into(), self.window_id)); } } �����������������������������������������������������������������������������alacritty-0.13.2/src/input/keyboard.rs��������������������������������������������������������������0000644�0000000�0000000�00000065455�10461020230�0016016�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::borrow::Cow; use std::mem; use winit::event::{ElementState, KeyEvent}; #[cfg(target_os = "macos")] use winit::keyboard::ModifiersKeyState; use winit::keyboard::{Key, KeyLocation, ModifiersState, NamedKey}; #[cfg(target_os = "macos")] use winit::platform::macos::OptionAsAlt; use alacritty_terminal::event::EventListener; use alacritty_terminal::term::TermMode; use winit::platform::modifier_supplement::KeyEventExtModifierSupplement; use crate::config::{Action, BindingKey, BindingMode}; use crate::event::TYPING_SEARCH_DELAY; use crate::input::{ActionContext, Execute, Processor}; use crate::scheduler::{TimerId, Topic}; impl<T: EventListener, A: ActionContext<T>> Processor<T, A> { /// Process key input. pub fn key_input(&mut self, key: KeyEvent) { // IME input will be applied on commit and shouldn't trigger key bindings. if self.ctx.display().ime.preedit().is_some() { return; } let mode = *self.ctx.terminal().mode(); let mods = self.ctx.modifiers().state(); if key.state == ElementState::Released { self.key_release(key, mode, mods); return; } let text = key.text_with_all_modifiers().unwrap_or_default(); // All key bindings are disabled while a hint is being selected. if self.ctx.display().hint_state.active() { for character in text.chars() { self.ctx.hint_input(character); } return; } // First key after inline search is captured. let inline_state = self.ctx.inline_search_state(); if mem::take(&mut inline_state.char_pending) { if let Some(c) = text.chars().next() { inline_state.character = Some(c); // Immediately move to the captured character. self.ctx.inline_search_next(); } // Ignore all other characters in `text`. return; } // Reset search delay when the user is still typing. self.reset_search_delay(); // Key bindings suppress the character input. if self.process_key_bindings(&key) { return; } if self.ctx.search_active() { for character in text.chars() { self.ctx.search_input(character); } return; } // Vi mode on its own doesn't have any input, the search input was done before. if mode.contains(TermMode::VI) { return; } // Mask `Alt` modifier from input when we won't send esc. let mods = if self.alt_send_esc(&key, text) { mods } else { mods & !ModifiersState::ALT }; let build_key_sequence = Self::should_build_sequence(&key, text, mode, mods); let bytes = if build_key_sequence { build_sequence(key, mods, mode) } else { let mut bytes = Vec::with_capacity(text.len() + 1); if mods.alt_key() { bytes.push(b'\x1b'); } bytes.extend_from_slice(text.as_bytes()); bytes }; // Write only if we have something to write. if !bytes.is_empty() { self.ctx.on_terminal_input_start(); self.ctx.write_to_pty(bytes); } } fn alt_send_esc(&mut self, key: &KeyEvent, text: &str) -> bool { #[cfg(not(target_os = "macos"))] let alt_send_esc = self.ctx.modifiers().state().alt_key(); #[cfg(target_os = "macos")] let alt_send_esc = { let option_as_alt = self.ctx.config().window.option_as_alt(); self.ctx.modifiers().state().alt_key() && (option_as_alt == OptionAsAlt::Both || (option_as_alt == OptionAsAlt::OnlyLeft && self.ctx.modifiers().lalt_state() == ModifiersKeyState::Pressed) || (option_as_alt == OptionAsAlt::OnlyRight && self.ctx.modifiers().ralt_state() == ModifiersKeyState::Pressed)) }; match key.logical_key { Key::Named(named) => { if named.to_text().is_some() { alt_send_esc } else { // Treat `Alt` as modifier for named keys without text, like ArrowUp. self.ctx.modifiers().state().alt_key() } }, _ => text.len() == 1 && alt_send_esc, } } /// Check whether we should try to build escape sequence for the [`KeyEvent`]. fn should_build_sequence( key: &KeyEvent, text: &str, mode: TermMode, mods: ModifiersState, ) -> bool { if mode.contains(TermMode::REPORT_ALL_KEYS_AS_ESC) { return true; } let disambiguate = mode.contains(TermMode::DISAMBIGUATE_ESC_CODES) && (key.logical_key == Key::Named(NamedKey::Escape) || (!mods.is_empty() && mods != ModifiersState::SHIFT) || key.location == KeyLocation::Numpad); match key.logical_key { _ if disambiguate => true, // Exclude all the named keys unless they have textual representation. Key::Named(named) => named.to_text().is_none(), _ => text.is_empty(), } } /// Attempt to find a binding and execute its action. /// /// The provided mode, mods, and key must match what is allowed by a binding /// for its action to be executed. fn process_key_bindings(&mut self, key: &KeyEvent) -> bool { let mode = BindingMode::new(self.ctx.terminal().mode(), self.ctx.search_active()); let mods = self.ctx.modifiers().state(); // Don't suppress char if no bindings were triggered. let mut suppress_chars = None; // We don't want the key without modifier, because it means something else most of // the time. However what we want is to manually lowercase the character to account // for both small and capital letters on regular characters at the same time. let logical_key = if let Key::Character(ch) = key.logical_key.as_ref() { // Match `Alt` bindings without `Alt` being applied, otherwise they use the // composed chars, which are not intuitive to bind. // // On Windows, the `Ctrl + Alt` mangles `logical_key` to unidentified values, thus // preventing them from being used in bindings // // For more see https://github.com/rust-windowing/winit/issues/2945. if (cfg!(target_os = "macos") || (cfg!(windows) && mods.control_key())) && mods.alt_key() { key.key_without_modifiers() } else { Key::Character(ch.to_lowercase().into()) } } else { key.logical_key.clone() }; for i in 0..self.ctx.config().key_bindings().len() { let binding = &self.ctx.config().key_bindings()[i]; let key = match (&binding.trigger, &logical_key) { (BindingKey::Scancode(_), _) => BindingKey::Scancode(key.physical_key), (_, code) => { BindingKey::Keycode { key: code.clone(), location: key.location.into() } }, }; if binding.is_triggered_by(mode, mods, &key) { // Pass through the key if any of the bindings has the `ReceiveChar` action. *suppress_chars.get_or_insert(true) &= binding.action != Action::ReceiveChar; // Binding was triggered; run the action. binding.action.clone().execute(&mut self.ctx); } } suppress_chars.unwrap_or(false) } /// Handle key release. fn key_release(&mut self, key: KeyEvent, mode: TermMode, mods: ModifiersState) { if !mode.contains(TermMode::REPORT_EVENT_TYPES) || mode.contains(TermMode::VI) || self.ctx.search_active() || self.ctx.display().hint_state.active() { return; } // Mask `Alt` modifier from input when we won't send esc. let text = key.text_with_all_modifiers().unwrap_or_default(); let mods = if self.alt_send_esc(&key, text) { mods } else { mods & !ModifiersState::ALT }; let bytes: Cow<'static, [u8]> = match key.logical_key.as_ref() { // NOTE: Echo the key back on release to follow kitty/foot behavior. When // KEYBOARD_REPORT_ALL_KEYS_AS_ESC is used, we build proper escapes for // the keys below. _ if mode.contains(TermMode::REPORT_ALL_KEYS_AS_ESC) => { build_sequence(key, mods, mode).into() }, // Winit uses different keys for `Backspace` so we expliictly specify the // values, instead of using what was passed to us from it. Key::Named(NamedKey::Tab) => [b'\t'].as_slice().into(), Key::Named(NamedKey::Enter) => [b'\r'].as_slice().into(), Key::Named(NamedKey::Backspace) => [b'\x7f'].as_slice().into(), Key::Named(NamedKey::Escape) => [b'\x1b'].as_slice().into(), _ => build_sequence(key, mods, mode).into(), }; self.ctx.write_to_pty(bytes); } /// Reset search delay. fn reset_search_delay(&mut self) { if self.ctx.search_active() { let timer_id = TimerId::new(Topic::DelayedSearch, self.ctx.window().id()); let scheduler = self.ctx.scheduler_mut(); if let Some(timer) = scheduler.unschedule(timer_id) { scheduler.schedule(timer.event, TYPING_SEARCH_DELAY, false, timer.id); } } } } /// Build a key's keyboard escape sequence based on the given `key`, `mods`, and `mode`. /// /// The key sequences for `APP_KEYPAD` and alike are handled inside the bindings. #[inline(never)] fn build_sequence(key: KeyEvent, mods: ModifiersState, mode: TermMode) -> Vec<u8> { let mut modifiers = mods.into(); let kitty_seq = mode.intersects( TermMode::REPORT_ALL_KEYS_AS_ESC | TermMode::DISAMBIGUATE_ESC_CODES | TermMode::REPORT_EVENT_TYPES, ); let kitty_encode_all = mode.contains(TermMode::REPORT_ALL_KEYS_AS_ESC); // The default parameter is 1, so we can omit it. let kitty_event_type = mode.contains(TermMode::REPORT_EVENT_TYPES) && (key.repeat || key.state == ElementState::Released); let context = SequenceBuilder { mode, modifiers, kitty_seq, kitty_encode_all, kitty_event_type }; let associated_text = key.text_with_all_modifiers().filter(|text| { mode.contains(TermMode::REPORT_ASSOCIATED_TEXT) && key.state != ElementState::Released && !text.is_empty() && !is_control_character(text) }); let sequence_base = context .try_build_numpad(&key) .or_else(|| context.try_build_named_kitty(&key)) .or_else(|| context.try_build_named_normal(&key)) .or_else(|| context.try_build_control_char_or_mod(&key, &mut modifiers)) .or_else(|| context.try_build_textual(&key, associated_text)); let (payload, terminator) = match sequence_base { Some(SequenceBase { payload, terminator }) => (payload, terminator), _ => return Vec::new(), }; let mut payload = format!("\x1b[{}", payload); // Add modifiers information. if kitty_event_type || !modifiers.is_empty() || associated_text.is_some() { payload.push_str(&format!(";{}", modifiers.encode_esc_sequence())); } // Push event type. if kitty_event_type { payload.push(':'); let event_type = match key.state { _ if key.repeat => '2', ElementState::Pressed => '1', ElementState::Released => '3', }; payload.push(event_type); } if let Some(text) = associated_text { let mut codepoints = text.chars().map(u32::from); if let Some(codepoint) = codepoints.next() { payload.push_str(&format!(";{codepoint}")); } for codepoint in codepoints { payload.push_str(&format!(":{codepoint}")); } } payload.push(terminator.encode_esc_sequence()); payload.into_bytes() } /// Helper to build escape sequence payloads from [`KeyEvent`]. pub struct SequenceBuilder { mode: TermMode, /// The emitted sequence should follow the kitty keyboard protocol. kitty_seq: bool, /// Encode all the keys according to the protocol. kitty_encode_all: bool, /// Report event types. kitty_event_type: bool, modifiers: SequenceModifiers, } impl SequenceBuilder { /// Try building sequence from the event's emitting text. fn try_build_textual( &self, key: &KeyEvent, associated_text: Option<&str>, ) -> Option<SequenceBase> { let character = match key.logical_key.as_ref() { Key::Character(character) if self.kitty_seq => character, _ => return None, }; if character.chars().count() == 1 { let character = character.chars().next().unwrap(); let base_character = character.to_lowercase().next().unwrap(); let alternate_key_code = u32::from(character); let mut unicode_key_code = u32::from(base_character); // Try to get the base for keys which change based on modifier, like `1` for `!`. match key.key_without_modifiers().as_ref() { Key::Character(unmodded) if alternate_key_code == unicode_key_code => { unicode_key_code = u32::from(unmodded.chars().next().unwrap_or(base_character)); }, _ => (), } // NOTE: Base layouts are ignored, since winit doesn't expose this information // yet. let payload = if self.mode.contains(TermMode::REPORT_ALTERNATE_KEYS) && alternate_key_code != unicode_key_code { format!("{unicode_key_code}:{alternate_key_code}") } else { alternate_key_code.to_string() }; Some(SequenceBase::new(payload.into(), SequenceTerminator::Kitty)) } else if self.kitty_encode_all && associated_text.is_some() { // Fallback when need to report text, but we don't have any key associated with this // text. Some(SequenceBase::new("0".into(), SequenceTerminator::Kitty)) } else { None } } /// Try building from numpad key. /// /// `None` is returned when the key is neither known nor numpad. fn try_build_numpad(&self, key: &KeyEvent) -> Option<SequenceBase> { if !self.kitty_seq || key.location != KeyLocation::Numpad { return None; } let base = match key.logical_key.as_ref() { Key::Character("0") => "57399", Key::Character("1") => "57400", Key::Character("2") => "57401", Key::Character("3") => "57402", Key::Character("4") => "57403", Key::Character("5") => "57404", Key::Character("6") => "57405", Key::Character("7") => "57406", Key::Character("8") => "57407", Key::Character("9") => "57408", Key::Character(".") => "57409", Key::Character("/") => "57410", Key::Character("*") => "57411", Key::Character("-") => "57412", Key::Character("+") => "57413", Key::Character("=") => "57415", Key::Named(named) => match named { NamedKey::Enter => "57414", NamedKey::ArrowLeft => "57417", NamedKey::ArrowRight => "57418", NamedKey::ArrowUp => "57419", NamedKey::ArrowDown => "57420", NamedKey::PageUp => "57421", NamedKey::PageDown => "57422", NamedKey::Home => "57423", NamedKey::End => "57424", NamedKey::Insert => "57425", NamedKey::Delete => "57426", _ => return None, }, _ => return None, }; Some(SequenceBase::new(base.into(), SequenceTerminator::Kitty)) } /// Try building from [`NamedKey`] using the kitty keyboard protocol encoding /// for functional keys. fn try_build_named_kitty(&self, key: &KeyEvent) -> Option<SequenceBase> { let named = match key.logical_key { Key::Named(named) if self.kitty_seq => named, _ => return None, }; let (base, terminator) = match named { // F3 in kitty protocol diverges from alacritty's terminfo. NamedKey::F3 => ("13", SequenceTerminator::Normal('~')), NamedKey::F13 => ("57376", SequenceTerminator::Kitty), NamedKey::F14 => ("57377", SequenceTerminator::Kitty), NamedKey::F15 => ("57378", SequenceTerminator::Kitty), NamedKey::F16 => ("57379", SequenceTerminator::Kitty), NamedKey::F17 => ("57380", SequenceTerminator::Kitty), NamedKey::F18 => ("57381", SequenceTerminator::Kitty), NamedKey::F19 => ("57382", SequenceTerminator::Kitty), NamedKey::F20 => ("57383", SequenceTerminator::Kitty), NamedKey::F21 => ("57384", SequenceTerminator::Kitty), NamedKey::F22 => ("57385", SequenceTerminator::Kitty), NamedKey::F23 => ("57386", SequenceTerminator::Kitty), NamedKey::F24 => ("57387", SequenceTerminator::Kitty), NamedKey::F25 => ("57388", SequenceTerminator::Kitty), NamedKey::F26 => ("57389", SequenceTerminator::Kitty), NamedKey::F27 => ("57390", SequenceTerminator::Kitty), NamedKey::F28 => ("57391", SequenceTerminator::Kitty), NamedKey::F29 => ("57392", SequenceTerminator::Kitty), NamedKey::F30 => ("57393", SequenceTerminator::Kitty), NamedKey::F31 => ("57394", SequenceTerminator::Kitty), NamedKey::F32 => ("57395", SequenceTerminator::Kitty), NamedKey::F33 => ("57396", SequenceTerminator::Kitty), NamedKey::F34 => ("57397", SequenceTerminator::Kitty), NamedKey::F35 => ("57398", SequenceTerminator::Kitty), NamedKey::ScrollLock => ("57359", SequenceTerminator::Kitty), NamedKey::PrintScreen => ("57361", SequenceTerminator::Kitty), NamedKey::Pause => ("57362", SequenceTerminator::Kitty), NamedKey::ContextMenu => ("57363", SequenceTerminator::Kitty), NamedKey::MediaPlay => ("57428", SequenceTerminator::Kitty), NamedKey::MediaPause => ("57429", SequenceTerminator::Kitty), NamedKey::MediaPlayPause => ("57430", SequenceTerminator::Kitty), NamedKey::MediaStop => ("57432", SequenceTerminator::Kitty), NamedKey::MediaFastForward => ("57433", SequenceTerminator::Kitty), NamedKey::MediaRewind => ("57434", SequenceTerminator::Kitty), NamedKey::MediaTrackNext => ("57435", SequenceTerminator::Kitty), NamedKey::MediaTrackPrevious => ("57436", SequenceTerminator::Kitty), NamedKey::MediaRecord => ("57437", SequenceTerminator::Kitty), NamedKey::AudioVolumeDown => ("57438", SequenceTerminator::Kitty), NamedKey::AudioVolumeUp => ("57439", SequenceTerminator::Kitty), NamedKey::AudioVolumeMute => ("57440", SequenceTerminator::Kitty), _ => return None, }; Some(SequenceBase::new(base.into(), terminator)) } /// Try building from [`NamedKey`]. fn try_build_named_normal(&self, key: &KeyEvent) -> Option<SequenceBase> { let named = match key.logical_key { Key::Named(named) => named, _ => return None, }; // The default parameter is 1, so we can omit it. let one_based = if self.modifiers.is_empty() && !self.kitty_event_type { "" } else { "1" }; let (base, terminator) = match named { NamedKey::PageUp => ("5", SequenceTerminator::Normal('~')), NamedKey::PageDown => ("6", SequenceTerminator::Normal('~')), NamedKey::Insert => ("2", SequenceTerminator::Normal('~')), NamedKey::Delete => ("3", SequenceTerminator::Normal('~')), NamedKey::Home => (one_based, SequenceTerminator::Normal('H')), NamedKey::End => (one_based, SequenceTerminator::Normal('F')), NamedKey::ArrowLeft => (one_based, SequenceTerminator::Normal('D')), NamedKey::ArrowRight => (one_based, SequenceTerminator::Normal('C')), NamedKey::ArrowUp => (one_based, SequenceTerminator::Normal('A')), NamedKey::ArrowDown => (one_based, SequenceTerminator::Normal('B')), NamedKey::F1 => (one_based, SequenceTerminator::Normal('P')), NamedKey::F2 => (one_based, SequenceTerminator::Normal('Q')), NamedKey::F3 => (one_based, SequenceTerminator::Normal('R')), NamedKey::F4 => (one_based, SequenceTerminator::Normal('S')), NamedKey::F5 => ("15", SequenceTerminator::Normal('~')), NamedKey::F6 => ("17", SequenceTerminator::Normal('~')), NamedKey::F7 => ("18", SequenceTerminator::Normal('~')), NamedKey::F8 => ("19", SequenceTerminator::Normal('~')), NamedKey::F9 => ("20", SequenceTerminator::Normal('~')), NamedKey::F10 => ("21", SequenceTerminator::Normal('~')), NamedKey::F11 => ("23", SequenceTerminator::Normal('~')), NamedKey::F12 => ("24", SequenceTerminator::Normal('~')), NamedKey::F13 => ("25", SequenceTerminator::Normal('~')), NamedKey::F14 => ("26", SequenceTerminator::Normal('~')), NamedKey::F15 => ("28", SequenceTerminator::Normal('~')), NamedKey::F16 => ("29", SequenceTerminator::Normal('~')), NamedKey::F17 => ("31", SequenceTerminator::Normal('~')), NamedKey::F18 => ("32", SequenceTerminator::Normal('~')), NamedKey::F19 => ("33", SequenceTerminator::Normal('~')), NamedKey::F20 => ("34", SequenceTerminator::Normal('~')), _ => return None, }; Some(SequenceBase::new(base.into(), terminator)) } /// Try building escape from control characters (e.g. Enter) and modifiers. fn try_build_control_char_or_mod( &self, key: &KeyEvent, mods: &mut SequenceModifiers, ) -> Option<SequenceBase> { if !self.kitty_encode_all && !self.kitty_seq { return None; } let named = match key.logical_key { Key::Named(named) => named, _ => return None, }; let base = match named { NamedKey::Tab => "9", NamedKey::Enter => "13", NamedKey::Escape => "27", NamedKey::Space => "32", NamedKey::Backspace => "127", _ => "", }; // Fail when the key is not a named control character and the active mode prohibits us // from encoding modifier keys. if !self.kitty_encode_all && base.is_empty() { return None; } let base = match (named, key.location) { (NamedKey::Shift, KeyLocation::Left) => "57441", (NamedKey::Control, KeyLocation::Left) => "57442", (NamedKey::Alt, KeyLocation::Left) => "57443", (NamedKey::Super, KeyLocation::Left) => "57444", (NamedKey::Hyper, KeyLocation::Left) => "57445", (NamedKey::Meta, KeyLocation::Left) => "57446", (NamedKey::Shift, _) => "57447", (NamedKey::Control, _) => "57448", (NamedKey::Alt, _) => "57449", (NamedKey::Super, _) => "57450", (NamedKey::Hyper, _) => "57451", (NamedKey::Meta, _) => "57452", (NamedKey::CapsLock, _) => "57358", (NamedKey::NumLock, _) => "57360", _ => base, }; // NOTE: Kitty's protocol mandates that the modifier state is applied before // key press, however winit sends them after the key press, so for modifiers // itself apply the state based on keysyms and not the _actual_ modifiers // state, which is how kitty is doing so and what is suggested in such case. let press = key.state.is_pressed(); match named { NamedKey::Shift => mods.set(SequenceModifiers::SHIFT, press), NamedKey::Control => mods.set(SequenceModifiers::CONTROL, press), NamedKey::Alt => mods.set(SequenceModifiers::ALT, press), NamedKey::Super => mods.set(SequenceModifiers::SUPER, press), _ => (), } if base.is_empty() { None } else { Some(SequenceBase::new(base.into(), SequenceTerminator::Kitty)) } } } pub struct SequenceBase { /// The base of the payload, which is the `number` and optionally an alt base from the kitty /// spec. payload: Cow<'static, str>, terminator: SequenceTerminator, } impl SequenceBase { fn new(payload: Cow<'static, str>, terminator: SequenceTerminator) -> Self { Self { payload, terminator } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SequenceTerminator { /// The normal key esc sequence terminator defined by xterm/dec. Normal(char), /// The terminator is for kitty escape sequence. Kitty, } impl SequenceTerminator { fn encode_esc_sequence(self) -> char { match self { SequenceTerminator::Normal(char) => char, SequenceTerminator::Kitty => 'u', } } } bitflags::bitflags! { /// The modifiers encoding for escape sequence. #[derive(Debug, Clone, Copy, PartialEq, Eq)] struct SequenceModifiers : u8 { const SHIFT = 0b0000_0001; const ALT = 0b0000_0010; const CONTROL = 0b0000_0100; const SUPER = 0b0000_1000; // NOTE: Kitty protocol defines additional modifiers to what is present here, like // Capslock, but it's not a modifier as per winit. } } impl SequenceModifiers { /// Get the value which should be passed to escape sequence. pub fn encode_esc_sequence(self) -> u8 { self.bits() + 1 } } impl From<ModifiersState> for SequenceModifiers { fn from(mods: ModifiersState) -> Self { let mut modifiers = Self::empty(); modifiers.set(Self::SHIFT, mods.shift_key()); modifiers.set(Self::ALT, mods.alt_key()); modifiers.set(Self::CONTROL, mods.control_key()); modifiers.set(Self::SUPER, mods.super_key()); modifiers } } /// Check whether the `text` is `0x7f`, `C0` or `C1` control code. fn is_control_character(text: &str) -> bool { // 0x7f (DEL) is included here since it has a dedicated control code (`^?`) which generally // does not match the reported text (`^H`), despite not technically being part of C0 or C1. let codepoint = text.bytes().next().unwrap(); text.len() == 1 && (codepoint < 0x20 || (0x7f..=0x9f).contains(&codepoint)) } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/input/mod.rs�������������������������������������������������������������������0000644�0000000�0000000�00000163643�10461020230�0014773�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Handle input from winit. //! //! Certain key combinations should send some escape sequence back to the PTY. //! In order to figure that out, state about which modifier keys are pressed //! needs to be tracked. Additionally, we need a bit of a state machine to //! determine what to do when a non-modifier key is pressed. use std::borrow::Cow; use std::cmp::{max, min, Ordering}; use std::collections::HashSet; use std::ffi::OsStr; use std::fmt::Debug; use std::marker::PhantomData; use std::mem; use std::time::{Duration, Instant}; use log::debug; use winit::dpi::PhysicalPosition; use winit::event::{ ElementState, Modifiers, MouseButton, MouseScrollDelta, Touch as TouchEvent, TouchPhase, }; #[cfg(target_os = "macos")] use winit::event_loop::EventLoopWindowTarget; use winit::keyboard::ModifiersState; #[cfg(target_os = "macos")] use winit::platform::macos::EventLoopWindowTargetExtMacOS; use winit::window::CursorIcon; use alacritty_terminal::event::EventListener; use alacritty_terminal::grid::{Dimensions, Scroll}; use alacritty_terminal::index::{Boundary, Column, Direction, Point, Side}; use alacritty_terminal::selection::SelectionType; use alacritty_terminal::term::search::Match; use alacritty_terminal::term::{ClipboardType, Term, TermMode}; use alacritty_terminal::vi_mode::ViMotion; use alacritty_terminal::vte::ansi::{ClearMode, Handler}; use crate::clipboard::Clipboard; use crate::config::{Action, BindingMode, MouseAction, SearchAction, UiConfig, ViAction}; use crate::display::hint::HintMatch; use crate::display::window::Window; use crate::display::{Display, SizeInfo}; use crate::event::{ ClickState, Event, EventType, InlineSearchState, Mouse, TouchPurpose, TouchZoom, }; use crate::message_bar::{self, Message}; use crate::scheduler::{Scheduler, TimerId, Topic}; pub mod keyboard; /// Font size change interval in px. pub const FONT_SIZE_STEP: f32 = 1.; /// Interval for mouse scrolling during selection outside of the boundaries. const SELECTION_SCROLLING_INTERVAL: Duration = Duration::from_millis(15); /// Minimum number of pixels at the bottom/top where selection scrolling is performed. const MIN_SELECTION_SCROLLING_HEIGHT: f64 = 5.; /// Number of pixels for increasing the selection scrolling speed factor by one. const SELECTION_SCROLLING_STEP: f64 = 20.; /// Distance before a touch input is considered a drag. const MAX_TAP_DISTANCE: f64 = 20.; /// Threshold used for double_click/triple_click. const CLICK_THRESHOLD: Duration = Duration::from_millis(400); /// Processes input from winit. /// /// An escape sequence may be emitted in case specific keys or key combinations /// are activated. pub struct Processor<T: EventListener, A: ActionContext<T>> { pub ctx: A, _phantom: PhantomData<T>, } pub trait ActionContext<T: EventListener> { fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&self, _data: B) {} fn mark_dirty(&mut self) {} fn size_info(&self) -> SizeInfo; fn copy_selection(&mut self, _ty: ClipboardType) {} fn start_selection(&mut self, _ty: SelectionType, _point: Point, _side: Side) {} fn toggle_selection(&mut self, _ty: SelectionType, _point: Point, _side: Side) {} fn update_selection(&mut self, _point: Point, _side: Side) {} fn clear_selection(&mut self) {} fn selection_is_empty(&self) -> bool; fn mouse_mut(&mut self) -> &mut Mouse; fn mouse(&self) -> &Mouse; fn touch_purpose(&mut self) -> &mut TouchPurpose; fn modifiers(&mut self) -> &mut Modifiers; fn scroll(&mut self, _scroll: Scroll) {} fn window(&mut self) -> &mut Window; fn display(&mut self) -> &mut Display; fn terminal(&self) -> &Term<T>; fn terminal_mut(&mut self) -> &mut Term<T>; fn spawn_new_instance(&mut self) {} #[cfg(target_os = "macos")] fn create_new_window(&mut self, _tabbing_id: Option<String>) {} #[cfg(not(target_os = "macos"))] fn create_new_window(&mut self) {} fn change_font_size(&mut self, _delta: f32) {} fn reset_font_size(&mut self) {} fn pop_message(&mut self) {} fn message(&self) -> Option<&Message>; fn config(&self) -> &UiConfig; #[cfg(target_os = "macos")] fn event_loop(&self) -> &EventLoopWindowTarget<Event>; fn mouse_mode(&self) -> bool; fn clipboard_mut(&mut self) -> &mut Clipboard; fn scheduler_mut(&mut self) -> &mut Scheduler; fn start_search(&mut self, _direction: Direction) {} fn confirm_search(&mut self) {} fn cancel_search(&mut self) {} fn search_input(&mut self, _c: char) {} fn search_pop_word(&mut self) {} fn search_history_previous(&mut self) {} fn search_history_next(&mut self) {} fn search_next(&mut self, origin: Point, direction: Direction, side: Side) -> Option<Match>; fn advance_search_origin(&mut self, _direction: Direction) {} fn search_direction(&self) -> Direction; fn search_active(&self) -> bool; fn on_typing_start(&mut self) {} fn toggle_vi_mode(&mut self) {} fn inline_search_state(&mut self) -> &mut InlineSearchState; fn start_inline_search(&mut self, _direction: Direction, _stop_short: bool) {} fn inline_search_next(&mut self) {} fn inline_search_previous(&mut self) {} fn hint_input(&mut self, _character: char) {} fn trigger_hint(&mut self, _hint: &HintMatch) {} fn expand_selection(&mut self) {} fn on_terminal_input_start(&mut self) {} fn paste(&mut self, _text: &str, _bracketed: bool) {} fn spawn_daemon<I, S>(&self, _program: &str, _args: I) where I: IntoIterator<Item = S> + Debug + Copy, S: AsRef<OsStr>, { } } impl Action { fn toggle_selection<T, A>(ctx: &mut A, ty: SelectionType) where A: ActionContext<T>, T: EventListener, { ctx.toggle_selection(ty, ctx.terminal().vi_mode_cursor.point, Side::Left); // Make sure initial selection is not empty. if let Some(selection) = &mut ctx.terminal_mut().selection { selection.include_all(); } } } trait Execute<T: EventListener> { fn execute<A: ActionContext<T>>(&self, ctx: &mut A); } impl<T: EventListener> Execute<T> for Action { #[inline] fn execute<A: ActionContext<T>>(&self, ctx: &mut A) { match self { Action::Esc(s) => ctx.paste(s, false), Action::Command(program) => ctx.spawn_daemon(program.program(), program.args()), Action::Hint(hint) => { ctx.display().hint_state.start(hint.clone()); ctx.mark_dirty(); }, Action::ToggleViMode => { ctx.on_typing_start(); ctx.toggle_vi_mode() }, action @ (Action::ViMotion(_) | Action::Vi(_)) if !ctx.terminal().mode().contains(TermMode::VI) => { debug!("Ignoring {action:?}: Vi mode inactive"); }, Action::ViMotion(motion) => { ctx.on_typing_start(); ctx.terminal_mut().vi_motion(*motion); ctx.mark_dirty(); }, Action::Vi(ViAction::ToggleNormalSelection) => { Self::toggle_selection(ctx, SelectionType::Simple); }, Action::Vi(ViAction::ToggleLineSelection) => { Self::toggle_selection(ctx, SelectionType::Lines); }, Action::Vi(ViAction::ToggleBlockSelection) => { Self::toggle_selection(ctx, SelectionType::Block); }, Action::Vi(ViAction::ToggleSemanticSelection) => { Self::toggle_selection(ctx, SelectionType::Semantic); }, Action::Vi(ViAction::Open) => { let hint = ctx.display().vi_highlighted_hint.take(); if let Some(hint) = &hint { ctx.mouse_mut().block_hint_launcher = false; ctx.trigger_hint(hint); } ctx.display().vi_highlighted_hint = hint; }, Action::Vi(ViAction::SearchNext) => { ctx.on_typing_start(); let terminal = ctx.terminal(); let direction = ctx.search_direction(); let vi_point = terminal.vi_mode_cursor.point; let origin = match direction { Direction::Right => vi_point.add(terminal, Boundary::None, 1), Direction::Left => vi_point.sub(terminal, Boundary::None, 1), }; if let Some(regex_match) = ctx.search_next(origin, direction, Side::Left) { ctx.terminal_mut().vi_goto_point(*regex_match.start()); ctx.mark_dirty(); } }, Action::Vi(ViAction::SearchPrevious) => { ctx.on_typing_start(); let terminal = ctx.terminal(); let direction = ctx.search_direction().opposite(); let vi_point = terminal.vi_mode_cursor.point; let origin = match direction { Direction::Right => vi_point.add(terminal, Boundary::None, 1), Direction::Left => vi_point.sub(terminal, Boundary::None, 1), }; if let Some(regex_match) = ctx.search_next(origin, direction, Side::Left) { ctx.terminal_mut().vi_goto_point(*regex_match.start()); ctx.mark_dirty(); } }, Action::Vi(ViAction::SearchStart) => { let terminal = ctx.terminal(); let origin = terminal.vi_mode_cursor.point.sub(terminal, Boundary::None, 1); if let Some(regex_match) = ctx.search_next(origin, Direction::Left, Side::Left) { ctx.terminal_mut().vi_goto_point(*regex_match.start()); ctx.mark_dirty(); } }, Action::Vi(ViAction::SearchEnd) => { let terminal = ctx.terminal(); let origin = terminal.vi_mode_cursor.point.add(terminal, Boundary::None, 1); if let Some(regex_match) = ctx.search_next(origin, Direction::Right, Side::Right) { ctx.terminal_mut().vi_goto_point(*regex_match.end()); ctx.mark_dirty(); } }, Action::Vi(ViAction::CenterAroundViCursor) => { let term = ctx.terminal(); let display_offset = term.grid().display_offset() as i32; let target = -display_offset + term.screen_lines() as i32 / 2 - 1; let line = term.vi_mode_cursor.point.line; let scroll_lines = target - line.0; ctx.scroll(Scroll::Delta(scroll_lines)); }, Action::Vi(ViAction::InlineSearchForward) => { ctx.start_inline_search(Direction::Right, false) }, Action::Vi(ViAction::InlineSearchBackward) => { ctx.start_inline_search(Direction::Left, false) }, Action::Vi(ViAction::InlineSearchForwardShort) => { ctx.start_inline_search(Direction::Right, true) }, Action::Vi(ViAction::InlineSearchBackwardShort) => { ctx.start_inline_search(Direction::Left, true) }, Action::Vi(ViAction::InlineSearchNext) => ctx.inline_search_next(), Action::Vi(ViAction::InlineSearchPrevious) => ctx.inline_search_previous(), action @ Action::Search(_) if !ctx.search_active() => { debug!("Ignoring {action:?}: Search mode inactive"); }, Action::Search(SearchAction::SearchFocusNext) => { ctx.advance_search_origin(ctx.search_direction()); }, Action::Search(SearchAction::SearchFocusPrevious) => { let direction = ctx.search_direction().opposite(); ctx.advance_search_origin(direction); }, Action::Search(SearchAction::SearchConfirm) => ctx.confirm_search(), Action::Search(SearchAction::SearchCancel) => ctx.cancel_search(), Action::Search(SearchAction::SearchClear) => { let direction = ctx.search_direction(); ctx.cancel_search(); ctx.start_search(direction); }, Action::Search(SearchAction::SearchDeleteWord) => ctx.search_pop_word(), Action::Search(SearchAction::SearchHistoryPrevious) => ctx.search_history_previous(), Action::Search(SearchAction::SearchHistoryNext) => ctx.search_history_next(), Action::Mouse(MouseAction::ExpandSelection) => ctx.expand_selection(), Action::SearchForward => ctx.start_search(Direction::Right), Action::SearchBackward => ctx.start_search(Direction::Left), Action::Copy => ctx.copy_selection(ClipboardType::Clipboard), #[cfg(not(any(target_os = "macos", windows)))] Action::CopySelection => ctx.copy_selection(ClipboardType::Selection), Action::ClearSelection => ctx.clear_selection(), Action::Paste => { let text = ctx.clipboard_mut().load(ClipboardType::Clipboard); ctx.paste(&text, true); }, Action::PasteSelection => { let text = ctx.clipboard_mut().load(ClipboardType::Selection); ctx.paste(&text, true); }, Action::ToggleFullscreen => ctx.window().toggle_fullscreen(), Action::ToggleMaximized => ctx.window().toggle_maximized(), #[cfg(target_os = "macos")] Action::ToggleSimpleFullscreen => ctx.window().toggle_simple_fullscreen(), #[cfg(target_os = "macos")] Action::Hide => ctx.event_loop().hide_application(), #[cfg(target_os = "macos")] Action::HideOtherApplications => ctx.event_loop().hide_other_applications(), #[cfg(not(target_os = "macos"))] Action::Hide => ctx.window().set_visible(false), Action::Minimize => ctx.window().set_minimized(true), Action::Quit => ctx.terminal_mut().exit(), Action::IncreaseFontSize => ctx.change_font_size(FONT_SIZE_STEP), Action::DecreaseFontSize => ctx.change_font_size(-FONT_SIZE_STEP), Action::ResetFontSize => ctx.reset_font_size(), Action::ScrollPageUp | Action::ScrollPageDown | Action::ScrollHalfPageUp | Action::ScrollHalfPageDown => { // Move vi mode cursor. let term = ctx.terminal_mut(); let (scroll, amount) = match self { Action::ScrollPageUp => (Scroll::PageUp, term.screen_lines() as i32), Action::ScrollPageDown => (Scroll::PageDown, -(term.screen_lines() as i32)), Action::ScrollHalfPageUp => { let amount = term.screen_lines() as i32 / 2; (Scroll::Delta(amount), amount) }, Action::ScrollHalfPageDown => { let amount = -(term.screen_lines() as i32 / 2); (Scroll::Delta(amount), amount) }, _ => unreachable!(), }; let old_vi_cursor = term.vi_mode_cursor; term.vi_mode_cursor = term.vi_mode_cursor.scroll(term, amount); if old_vi_cursor != term.vi_mode_cursor { ctx.mark_dirty(); } ctx.scroll(scroll); }, Action::ScrollLineUp => ctx.scroll(Scroll::Delta(1)), Action::ScrollLineDown => ctx.scroll(Scroll::Delta(-1)), Action::ScrollToTop => { ctx.scroll(Scroll::Top); // Move vi mode cursor. let topmost_line = ctx.terminal().topmost_line(); ctx.terminal_mut().vi_mode_cursor.point.line = topmost_line; ctx.terminal_mut().vi_motion(ViMotion::FirstOccupied); ctx.mark_dirty(); }, Action::ScrollToBottom => { ctx.scroll(Scroll::Bottom); // Move vi mode cursor. let term = ctx.terminal_mut(); term.vi_mode_cursor.point.line = term.bottommost_line(); // Move to beginning twice, to always jump across linewraps. term.vi_motion(ViMotion::FirstOccupied); term.vi_motion(ViMotion::FirstOccupied); ctx.mark_dirty(); }, Action::ClearHistory => ctx.terminal_mut().clear_screen(ClearMode::Saved), Action::ClearLogNotice => ctx.pop_message(), #[cfg(not(target_os = "macos"))] Action::CreateNewWindow => ctx.create_new_window(), Action::SpawnNewInstance => ctx.spawn_new_instance(), #[cfg(target_os = "macos")] Action::CreateNewWindow => ctx.create_new_window(None), #[cfg(target_os = "macos")] Action::CreateNewTab => { let tabbing_id = Some(ctx.window().tabbing_id()); ctx.create_new_window(tabbing_id); }, #[cfg(target_os = "macos")] Action::SelectNextTab => ctx.window().select_next_tab(), #[cfg(target_os = "macos")] Action::SelectPreviousTab => ctx.window().select_previous_tab(), #[cfg(target_os = "macos")] Action::SelectTab1 => ctx.window().select_tab_at_index(0), #[cfg(target_os = "macos")] Action::SelectTab2 => ctx.window().select_tab_at_index(1), #[cfg(target_os = "macos")] Action::SelectTab3 => ctx.window().select_tab_at_index(2), #[cfg(target_os = "macos")] Action::SelectTab4 => ctx.window().select_tab_at_index(3), #[cfg(target_os = "macos")] Action::SelectTab5 => ctx.window().select_tab_at_index(4), #[cfg(target_os = "macos")] Action::SelectTab6 => ctx.window().select_tab_at_index(5), #[cfg(target_os = "macos")] Action::SelectTab7 => ctx.window().select_tab_at_index(6), #[cfg(target_os = "macos")] Action::SelectTab8 => ctx.window().select_tab_at_index(7), #[cfg(target_os = "macos")] Action::SelectTab9 => ctx.window().select_tab_at_index(8), #[cfg(target_os = "macos")] Action::SelectLastTab => ctx.window().select_last_tab(), _ => (), } } } impl<T: EventListener, A: ActionContext<T>> Processor<T, A> { pub fn new(ctx: A) -> Self { Self { ctx, _phantom: Default::default() } } #[inline] pub fn mouse_moved(&mut self, position: PhysicalPosition<f64>) { let size_info = self.ctx.size_info(); let (x, y) = position.into(); let lmb_pressed = self.ctx.mouse().left_button_state == ElementState::Pressed; let rmb_pressed = self.ctx.mouse().right_button_state == ElementState::Pressed; if !self.ctx.selection_is_empty() && (lmb_pressed || rmb_pressed) { self.update_selection_scrolling(y); } let display_offset = self.ctx.terminal().grid().display_offset(); let old_point = self.ctx.mouse().point(&size_info, display_offset); let x = x.clamp(0, size_info.width() as i32 - 1) as usize; let y = y.clamp(0, size_info.height() as i32 - 1) as usize; self.ctx.mouse_mut().x = x; self.ctx.mouse_mut().y = y; let inside_text_area = size_info.contains_point(x, y); let cell_side = self.cell_side(x); let point = self.ctx.mouse().point(&size_info, display_offset); let cell_changed = old_point != point; // If the mouse hasn't changed cells, do nothing. if !cell_changed && self.ctx.mouse().cell_side == cell_side && self.ctx.mouse().inside_text_area == inside_text_area { return; } self.ctx.mouse_mut().inside_text_area = inside_text_area; self.ctx.mouse_mut().cell_side = cell_side; // Update mouse state and check for URL change. let mouse_state = self.cursor_state(); self.ctx.window().set_mouse_cursor(mouse_state); // Prompt hint highlight update. self.ctx.mouse_mut().hint_highlight_dirty = true; // Don't launch URLs if mouse has moved. self.ctx.mouse_mut().block_hint_launcher = true; if (lmb_pressed || rmb_pressed) && (self.ctx.modifiers().state().shift_key() || !self.ctx.mouse_mode()) { self.ctx.update_selection(point, cell_side); } else if cell_changed && self.ctx.terminal().mode().intersects(TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG) { if lmb_pressed { self.mouse_report(32, ElementState::Pressed); } else if self.ctx.mouse().middle_button_state == ElementState::Pressed { self.mouse_report(33, ElementState::Pressed); } else if self.ctx.mouse().right_button_state == ElementState::Pressed { self.mouse_report(34, ElementState::Pressed); } else if self.ctx.terminal().mode().contains(TermMode::MOUSE_MOTION) { self.mouse_report(35, ElementState::Pressed); } } } /// Check which side of a cell an X coordinate lies on. fn cell_side(&self, x: usize) -> Side { let size_info = self.ctx.size_info(); let cell_x = x.saturating_sub(size_info.padding_x() as usize) % size_info.cell_width() as usize; let half_cell_width = (size_info.cell_width() / 2.0) as usize; let additional_padding = (size_info.width() - size_info.padding_x() * 2.) % size_info.cell_width(); let end_of_grid = size_info.width() - size_info.padding_x() - additional_padding; if cell_x > half_cell_width // Edge case when mouse leaves the window. || x as f32 >= end_of_grid { Side::Right } else { Side::Left } } fn mouse_report(&mut self, button: u8, state: ElementState) { let display_offset = self.ctx.terminal().grid().display_offset(); let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset); // Assure the mouse point is not in the scrollback. if point.line < 0 { return; } // Calculate modifiers value. let mut mods = 0; let modifiers = self.ctx.modifiers().state(); if modifiers.shift_key() { mods += 4; } if modifiers.alt_key() { mods += 8; } if modifiers.control_key() { mods += 16; } // Report mouse events. if self.ctx.terminal().mode().contains(TermMode::SGR_MOUSE) { self.sgr_mouse_report(point, button + mods, state); } else if let ElementState::Released = state { self.normal_mouse_report(point, 3 + mods); } else { self.normal_mouse_report(point, button + mods); } } fn normal_mouse_report(&mut self, point: Point, button: u8) { let Point { line, column } = point; let utf8 = self.ctx.terminal().mode().contains(TermMode::UTF8_MOUSE); let max_point = if utf8 { 2015 } else { 223 }; if line >= max_point || column >= max_point { return; } let mut msg = vec![b'\x1b', b'[', b'M', 32 + button]; let mouse_pos_encode = |pos: usize| -> Vec<u8> { let pos = 32 + 1 + pos; let first = 0xC0 + pos / 64; let second = 0x80 + (pos & 63); vec![first as u8, second as u8] }; if utf8 && column >= Column(95) { msg.append(&mut mouse_pos_encode(column.0)); } else { msg.push(32 + 1 + column.0 as u8); } if utf8 && line >= 95 { msg.append(&mut mouse_pos_encode(line.0 as usize)); } else { msg.push(32 + 1 + line.0 as u8); } self.ctx.write_to_pty(msg); } fn sgr_mouse_report(&mut self, point: Point, button: u8, state: ElementState) { let c = match state { ElementState::Pressed => 'M', ElementState::Released => 'm', }; let msg = format!("\x1b[<{};{};{}{}", button, point.column + 1, point.line + 1, c); self.ctx.write_to_pty(msg.into_bytes()); } fn on_mouse_press(&mut self, button: MouseButton) { // Handle mouse mode. if !self.ctx.modifiers().state().shift_key() && self.ctx.mouse_mode() { self.ctx.mouse_mut().click_state = ClickState::None; let code = match button { MouseButton::Left => 0, MouseButton::Middle => 1, MouseButton::Right => 2, // Can't properly report more than three buttons.. MouseButton::Back | MouseButton::Forward | MouseButton::Other(_) => return, }; self.mouse_report(code, ElementState::Pressed); } else { // Calculate time since the last click to handle double/triple clicks. let now = Instant::now(); let elapsed = now - self.ctx.mouse().last_click_timestamp; self.ctx.mouse_mut().last_click_timestamp = now; // Update multi-click state. self.ctx.mouse_mut().click_state = match self.ctx.mouse().click_state { // Reset click state if button has changed. _ if button != self.ctx.mouse().last_click_button => { self.ctx.mouse_mut().last_click_button = button; ClickState::Click }, ClickState::Click if elapsed < CLICK_THRESHOLD => ClickState::DoubleClick, ClickState::DoubleClick if elapsed < CLICK_THRESHOLD => ClickState::TripleClick, _ => ClickState::Click, }; // Load mouse point, treating message bar and padding as the closest cell. let display_offset = self.ctx.terminal().grid().display_offset(); let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset); if let MouseButton::Left = button { self.on_left_click(point) } } } /// Handle left click selection and vi mode cursor movement. fn on_left_click(&mut self, point: Point) { let side = self.ctx.mouse().cell_side; match self.ctx.mouse().click_state { ClickState::Click => { // Don't launch URLs if this click cleared the selection. self.ctx.mouse_mut().block_hint_launcher = !self.ctx.selection_is_empty(); self.ctx.clear_selection(); // Start new empty selection. if self.ctx.modifiers().state().control_key() { self.ctx.start_selection(SelectionType::Block, point, side); } else { self.ctx.start_selection(SelectionType::Simple, point, side); } }, ClickState::DoubleClick => { self.ctx.mouse_mut().block_hint_launcher = true; self.ctx.start_selection(SelectionType::Semantic, point, side); }, ClickState::TripleClick => { self.ctx.mouse_mut().block_hint_launcher = true; self.ctx.start_selection(SelectionType::Lines, point, side); }, ClickState::None => (), }; // Move vi mode cursor to mouse click position. if self.ctx.terminal().mode().contains(TermMode::VI) && !self.ctx.search_active() { self.ctx.terminal_mut().vi_mode_cursor.point = point; self.ctx.mark_dirty(); } } fn on_mouse_release(&mut self, button: MouseButton) { if !self.ctx.modifiers().state().shift_key() && self.ctx.mouse_mode() { let code = match button { MouseButton::Left => 0, MouseButton::Middle => 1, MouseButton::Right => 2, // Can't properly report more than three buttons. MouseButton::Back | MouseButton::Forward | MouseButton::Other(_) => return, }; self.mouse_report(code, ElementState::Released); return; } // Trigger hints highlighted by the mouse. let hint = self.ctx.display().highlighted_hint.take(); if let Some(hint) = hint.as_ref().filter(|_| button == MouseButton::Left) { self.ctx.trigger_hint(hint); } self.ctx.display().highlighted_hint = hint; let timer_id = TimerId::new(Topic::SelectionScrolling, self.ctx.window().id()); self.ctx.scheduler_mut().unschedule(timer_id); if let MouseButton::Left | MouseButton::Right = button { // Copy selection on release, to prevent flooding the display server. self.ctx.copy_selection(ClipboardType::Selection); } } pub fn mouse_wheel_input(&mut self, delta: MouseScrollDelta, phase: TouchPhase) { let multiplier = self.ctx.config().scrolling.multiplier; match delta { MouseScrollDelta::LineDelta(columns, lines) => { let new_scroll_px_x = columns * self.ctx.size_info().cell_width(); let new_scroll_px_y = lines * self.ctx.size_info().cell_height(); self.scroll_terminal( new_scroll_px_x as f64, new_scroll_px_y as f64, multiplier as f64, ); }, MouseScrollDelta::PixelDelta(mut lpos) => { match phase { TouchPhase::Started => { // Reset offset to zero. self.ctx.mouse_mut().accumulated_scroll = Default::default(); }, TouchPhase::Moved => { // When the angle between (x, 0) and (x, y) is lower than ~25 degrees // (cosine is larger that 0.9) we consider this scrolling as horizontal. if lpos.x.abs() / lpos.x.hypot(lpos.y) > 0.9 { lpos.y = 0.; } else { lpos.x = 0.; } self.scroll_terminal(lpos.x, lpos.y, multiplier as f64); }, _ => (), } }, } } fn scroll_terminal(&mut self, new_scroll_x_px: f64, new_scroll_y_px: f64, multiplier: f64) { const MOUSE_WHEEL_UP: u8 = 64; const MOUSE_WHEEL_DOWN: u8 = 65; const MOUSE_WHEEL_LEFT: u8 = 66; const MOUSE_WHEEL_RIGHT: u8 = 67; let width = f64::from(self.ctx.size_info().cell_width()); let height = f64::from(self.ctx.size_info().cell_height()); if self.ctx.mouse_mode() { self.ctx.mouse_mut().accumulated_scroll.x += new_scroll_x_px; self.ctx.mouse_mut().accumulated_scroll.y += new_scroll_y_px; let code = if new_scroll_y_px > 0. { MOUSE_WHEEL_UP } else { MOUSE_WHEEL_DOWN }; let lines = (self.ctx.mouse().accumulated_scroll.y / height).abs() as i32; for _ in 0..lines { self.mouse_report(code, ElementState::Pressed); } let code = if new_scroll_x_px > 0. { MOUSE_WHEEL_LEFT } else { MOUSE_WHEEL_RIGHT }; let columns = (self.ctx.mouse().accumulated_scroll.x / width).abs() as i32; for _ in 0..columns { self.mouse_report(code, ElementState::Pressed); } } else if self .ctx .terminal() .mode() .contains(TermMode::ALT_SCREEN | TermMode::ALTERNATE_SCROLL) && !self.ctx.modifiers().state().shift_key() { self.ctx.mouse_mut().accumulated_scroll.x += new_scroll_x_px * multiplier; self.ctx.mouse_mut().accumulated_scroll.y += new_scroll_y_px * multiplier; // The chars here are the same as for the respective arrow keys. let line_cmd = if new_scroll_y_px > 0. { b'A' } else { b'B' }; let column_cmd = if new_scroll_x_px > 0. { b'D' } else { b'C' }; let lines = (self.ctx.mouse().accumulated_scroll.y / height).abs() as usize; let columns = (self.ctx.mouse().accumulated_scroll.x / width).abs() as usize; let mut content = Vec::with_capacity(3 * (lines + columns)); for _ in 0..lines { content.push(0x1b); content.push(b'O'); content.push(line_cmd); } for _ in 0..columns { content.push(0x1b); content.push(b'O'); content.push(column_cmd); } self.ctx.write_to_pty(content); } else { self.ctx.mouse_mut().accumulated_scroll.y += new_scroll_y_px * multiplier; let lines = (self.ctx.mouse().accumulated_scroll.y / height) as i32; if lines != 0 { self.ctx.scroll(Scroll::Delta(lines)); } } self.ctx.mouse_mut().accumulated_scroll.x %= width; self.ctx.mouse_mut().accumulated_scroll.y %= height; } pub fn on_focus_change(&mut self, is_focused: bool) { if self.ctx.terminal().mode().contains(TermMode::FOCUS_IN_OUT) { let chr = if is_focused { "I" } else { "O" }; let msg = format!("\x1b[{}", chr); self.ctx.write_to_pty(msg.into_bytes()); } } /// Handle touch input. pub fn touch(&mut self, touch: TouchEvent) { match touch.phase { TouchPhase::Started => self.on_touch_start(touch), TouchPhase::Moved => self.on_touch_motion(touch), TouchPhase::Ended | TouchPhase::Cancelled => self.on_touch_end(touch), } } /// Handle beginning of touch input. pub fn on_touch_start(&mut self, touch: TouchEvent) { let touch_purpose = self.ctx.touch_purpose(); *touch_purpose = match mem::take(touch_purpose) { TouchPurpose::None => TouchPurpose::Tap(touch), TouchPurpose::Tap(start) => TouchPurpose::Zoom(TouchZoom::new((start, touch))), TouchPurpose::Zoom(zoom) => TouchPurpose::Invalid(zoom.slots()), TouchPurpose::Scroll(event) | TouchPurpose::Select(event) => { let mut set = HashSet::default(); set.insert(event.id); TouchPurpose::Invalid(set) }, TouchPurpose::Invalid(mut slots) => { slots.insert(touch.id); TouchPurpose::Invalid(slots) }, }; } /// Handle touch input movement. pub fn on_touch_motion(&mut self, touch: TouchEvent) { let touch_purpose = self.ctx.touch_purpose(); match touch_purpose { TouchPurpose::None => (), // Handle transition from tap to scroll/select. TouchPurpose::Tap(start) => { let delta_x = touch.location.x - start.location.x; let delta_y = touch.location.y - start.location.y; if delta_x.abs() > MAX_TAP_DISTANCE { // Update gesture state. let start_location = start.location; *touch_purpose = TouchPurpose::Select(*start); // Start simulated mouse input. self.mouse_moved(start_location); self.mouse_input(ElementState::Pressed, MouseButton::Left); // Apply motion since touch start. self.on_touch_motion(touch); } else if delta_y.abs() > MAX_TAP_DISTANCE { // Update gesture state. *touch_purpose = TouchPurpose::Scroll(*start); // Apply motion since touch start. self.on_touch_motion(touch); } }, TouchPurpose::Zoom(zoom) => { let font_delta = zoom.font_delta(touch); self.ctx.change_font_size(font_delta); }, TouchPurpose::Scroll(last_touch) => { // Calculate delta and update last touch position. let delta_y = touch.location.y - last_touch.location.y; *touch_purpose = TouchPurpose::Scroll(touch); // Use a fixed scroll factor for touchscreens, to accurately track finger motion. self.scroll_terminal(0., delta_y, 1.0); }, TouchPurpose::Select(_) => self.mouse_moved(touch.location), TouchPurpose::Invalid(_) => (), } } /// Handle end of touch input. pub fn on_touch_end(&mut self, touch: TouchEvent) { // Finalize the touch motion up to the release point. self.on_touch_motion(touch); let touch_purpose = self.ctx.touch_purpose(); match touch_purpose { // Simulate LMB clicks. TouchPurpose::Tap(start) => { let start_location = start.location; *touch_purpose = Default::default(); self.mouse_moved(start_location); self.mouse_input(ElementState::Pressed, MouseButton::Left); self.mouse_input(ElementState::Released, MouseButton::Left); }, // Invalidate zoom once a finger was released. TouchPurpose::Zoom(zoom) => { let mut slots = zoom.slots(); slots.remove(&touch.id); *touch_purpose = TouchPurpose::Invalid(slots); }, // Reset touch state once all slots were released. TouchPurpose::Invalid(slots) => { slots.remove(&touch.id); if slots.is_empty() { *touch_purpose = Default::default(); } }, // Release simulated LMB. TouchPurpose::Select(_) => { *touch_purpose = Default::default(); self.mouse_input(ElementState::Released, MouseButton::Left); }, // Reset touch state on scroll finish. TouchPurpose::Scroll(_) => *touch_purpose = Default::default(), TouchPurpose::None => (), } } /// Reset mouse cursor based on modifier and terminal state. #[inline] pub fn reset_mouse_cursor(&mut self) { let mouse_state = self.cursor_state(); self.ctx.window().set_mouse_cursor(mouse_state); } /// Modifier state change. pub fn modifiers_input(&mut self, modifiers: Modifiers) { *self.ctx.modifiers() = modifiers; // Prompt hint highlight update. self.ctx.mouse_mut().hint_highlight_dirty = true; // Update mouse state and check for URL change. let mouse_state = self.cursor_state(); self.ctx.window().set_mouse_cursor(mouse_state); } pub fn mouse_input(&mut self, state: ElementState, button: MouseButton) { match button { MouseButton::Left => self.ctx.mouse_mut().left_button_state = state, MouseButton::Middle => self.ctx.mouse_mut().middle_button_state = state, MouseButton::Right => self.ctx.mouse_mut().right_button_state = state, _ => (), } // Skip normal mouse events if the message bar has been clicked. if self.message_bar_cursor_state() == Some(CursorIcon::Pointer) && state == ElementState::Pressed { let size = self.ctx.size_info(); let current_lines = self.ctx.message().map_or(0, |m| m.text(&size).len()); self.ctx.clear_selection(); self.ctx.pop_message(); // Reset cursor when message bar height changed or all messages are gone. let new_lines = self.ctx.message().map_or(0, |m| m.text(&size).len()); let new_icon = match current_lines.cmp(&new_lines) { Ordering::Less => CursorIcon::Default, Ordering::Equal => CursorIcon::Pointer, Ordering::Greater => { if self.ctx.mouse_mode() { CursorIcon::Default } else { CursorIcon::Text } }, }; self.ctx.window().set_mouse_cursor(new_icon); } else { match state { ElementState::Pressed => { // Process mouse press before bindings to update the `click_state`. self.on_mouse_press(button); self.process_mouse_bindings(button); }, ElementState::Released => self.on_mouse_release(button), } } } /// Attempt to find a binding and execute its action. /// /// The provided mode, mods, and key must match what is allowed by a binding /// for its action to be executed. fn process_mouse_bindings(&mut self, button: MouseButton) { let mode = BindingMode::new(self.ctx.terminal().mode(), self.ctx.search_active()); let mouse_mode = self.ctx.mouse_mode(); let mods = self.ctx.modifiers().state(); let mouse_bindings = self.ctx.config().mouse_bindings().to_owned(); // If mouse mode is active, also look for bindings without shift. let mut check_fallback = mouse_mode && mods.contains(ModifiersState::SHIFT); for binding in &mouse_bindings { // Don't trigger normal bindings in mouse mode unless Shift is pressed. if binding.is_triggered_by(mode, mods, &button) && (check_fallback || !mouse_mode) { binding.action.execute(&mut self.ctx); check_fallback = false; } } if check_fallback { let fallback_mods = mods & !ModifiersState::SHIFT; for binding in &mouse_bindings { if binding.is_triggered_by(mode, fallback_mods, &button) { binding.action.execute(&mut self.ctx); } } } } /// Check mouse icon state in relation to the message bar. fn message_bar_cursor_state(&self) -> Option<CursorIcon> { // Since search is above the message bar, the button is offset by search's height. let search_height = usize::from(self.ctx.search_active()); // Calculate Y position of the end of the last terminal line. let size = self.ctx.size_info(); let terminal_end = size.padding_y() as usize + size.cell_height() as usize * (size.screen_lines() + search_height); let mouse = self.ctx.mouse(); let display_offset = self.ctx.terminal().grid().display_offset(); let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset); if self.ctx.message().is_none() || (mouse.y <= terminal_end) { None } else if mouse.y <= terminal_end + size.cell_height() as usize && point.column + message_bar::CLOSE_BUTTON_TEXT.len() >= size.columns() { Some(CursorIcon::Pointer) } else { Some(CursorIcon::Default) } } /// Icon state of the cursor. fn cursor_state(&mut self) -> CursorIcon { let display_offset = self.ctx.terminal().grid().display_offset(); let point = self.ctx.mouse().point(&self.ctx.size_info(), display_offset); let hyperlink = self.ctx.terminal().grid()[point].hyperlink(); // Function to check if mouse is on top of a hint. let hint_highlighted = |hint: &HintMatch| hint.should_highlight(point, hyperlink.as_ref()); if let Some(mouse_state) = self.message_bar_cursor_state() { mouse_state } else if self.ctx.display().highlighted_hint.as_ref().map_or(false, hint_highlighted) { CursorIcon::Pointer } else if !self.ctx.modifiers().state().shift_key() && self.ctx.mouse_mode() { CursorIcon::Default } else { CursorIcon::Text } } /// Handle automatic scrolling when selecting above/below the window. fn update_selection_scrolling(&mut self, mouse_y: i32) { let scale_factor = self.ctx.window().scale_factor; let size = self.ctx.size_info(); let window_id = self.ctx.window().id(); let scheduler = self.ctx.scheduler_mut(); // Scale constants by DPI. let min_height = (MIN_SELECTION_SCROLLING_HEIGHT * scale_factor) as i32; let step = (SELECTION_SCROLLING_STEP * scale_factor) as i32; // Compute the height of the scrolling areas. let end_top = max(min_height, size.padding_y() as i32); let text_area_bottom = size.padding_y() + size.screen_lines() as f32 * size.cell_height(); let start_bottom = min(size.height() as i32 - min_height, text_area_bottom as i32); // Get distance from closest window boundary. let delta = if mouse_y < end_top { end_top - mouse_y + step } else if mouse_y >= start_bottom { start_bottom - mouse_y - step } else { scheduler.unschedule(TimerId::new(Topic::SelectionScrolling, window_id)); return; }; // Scale number of lines scrolled based on distance to boundary. let event = Event::new(EventType::Scroll(Scroll::Delta(delta / step)), Some(window_id)); // Schedule event. let timer_id = TimerId::new(Topic::SelectionScrolling, window_id); scheduler.unschedule(timer_id); scheduler.schedule(event, SELECTION_SCROLLING_INTERVAL, true, timer_id); } } #[cfg(test)] mod tests { use super::*; use winit::event::{DeviceId, Event as WinitEvent, WindowEvent}; use winit::keyboard::Key; use winit::window::WindowId; use alacritty_terminal::event::Event as TerminalEvent; use crate::config::Binding; use crate::message_bar::MessageBuffer; const KEY: Key<&'static str> = Key::Character("0"); struct MockEventProxy; impl EventListener for MockEventProxy {} struct ActionContext<'a, T> { pub terminal: &'a mut Term<T>, pub size_info: &'a SizeInfo, pub mouse: &'a mut Mouse, pub clipboard: &'a mut Clipboard, pub message_buffer: &'a mut MessageBuffer, pub modifiers: Modifiers, config: &'a UiConfig, inline_search_state: &'a mut InlineSearchState, } impl<'a, T: EventListener> super::ActionContext<T> for ActionContext<'a, T> { fn search_next( &mut self, _origin: Point, _direction: Direction, _side: Side, ) -> Option<Match> { None } fn search_direction(&self) -> Direction { Direction::Right } fn inline_search_state(&mut self) -> &mut InlineSearchState { self.inline_search_state } fn search_active(&self) -> bool { false } fn terminal(&self) -> &Term<T> { self.terminal } fn terminal_mut(&mut self) -> &mut Term<T> { self.terminal } fn size_info(&self) -> SizeInfo { *self.size_info } fn selection_is_empty(&self) -> bool { true } fn scroll(&mut self, scroll: Scroll) { self.terminal.scroll_display(scroll); } fn mouse_mode(&self) -> bool { false } #[inline] fn mouse_mut(&mut self) -> &mut Mouse { self.mouse } #[inline] fn mouse(&self) -> &Mouse { self.mouse } #[inline] fn touch_purpose(&mut self) -> &mut TouchPurpose { unimplemented!(); } fn modifiers(&mut self) -> &mut Modifiers { &mut self.modifiers } fn window(&mut self) -> &mut Window { unimplemented!(); } fn display(&mut self) -> &mut Display { unimplemented!(); } fn pop_message(&mut self) { self.message_buffer.pop(); } fn message(&self) -> Option<&Message> { self.message_buffer.message() } fn config(&self) -> &UiConfig { self.config } fn clipboard_mut(&mut self) -> &mut Clipboard { self.clipboard } #[cfg(target_os = "macos")] fn event_loop(&self) -> &EventLoopWindowTarget<Event> { unimplemented!(); } fn scheduler_mut(&mut self) -> &mut Scheduler { unimplemented!(); } } macro_rules! test_clickstate { { name: $name:ident, initial_state: $initial_state:expr, initial_button: $initial_button:expr, input: $input:expr, end_state: $end_state:expr, input_delay: $input_delay:expr, } => { #[test] fn $name() { let mut clipboard = Clipboard::new_nop(); let cfg = UiConfig::default(); let size = SizeInfo::new( 21.0, 51.0, 3.0, 3.0, 0., 0., false, ); let mut terminal = Term::new(cfg.term_options(), &size, MockEventProxy); let mut mouse = Mouse { click_state: $initial_state, last_click_button: $initial_button, last_click_timestamp: Instant::now() - $input_delay, ..Mouse::default() }; let mut inline_search_state = InlineSearchState::default(); let mut message_buffer = MessageBuffer::default(); let context = ActionContext { terminal: &mut terminal, mouse: &mut mouse, size_info: &size, clipboard: &mut clipboard, modifiers: Default::default(), message_buffer: &mut message_buffer, inline_search_state: &mut inline_search_state, config: &cfg, }; let mut processor = Processor::new(context); let event: WinitEvent::<TerminalEvent> = $input; if let WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state, button, .. }, .. } = event { processor.mouse_input(state, button); }; assert_eq!(processor.ctx.mouse.click_state, $end_state); } } } macro_rules! test_process_binding { { name: $name:ident, binding: $binding:expr, triggers: $triggers:expr, mode: $mode:expr, mods: $mods:expr, } => { #[test] fn $name() { if $triggers { assert!($binding.is_triggered_by($mode, $mods, &KEY)); } else { assert!(!$binding.is_triggered_by($mode, $mods, &KEY)); } } } } test_clickstate! { name: single_click, initial_state: ClickState::None, initial_button: MouseButton::Other(0), input: WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, device_id: unsafe { DeviceId::dummy() }, }, window_id: unsafe { WindowId::dummy() }, }, end_state: ClickState::Click, input_delay: Duration::ZERO, } test_clickstate! { name: single_right_click, initial_state: ClickState::None, initial_button: MouseButton::Other(0), input: WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Right, device_id: unsafe { DeviceId::dummy() }, }, window_id: unsafe { WindowId::dummy() }, }, end_state: ClickState::Click, input_delay: Duration::ZERO, } test_clickstate! { name: single_middle_click, initial_state: ClickState::None, initial_button: MouseButton::Other(0), input: WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Middle, device_id: unsafe { DeviceId::dummy() }, }, window_id: unsafe { WindowId::dummy() }, }, end_state: ClickState::Click, input_delay: Duration::ZERO, } test_clickstate! { name: double_click, initial_state: ClickState::Click, initial_button: MouseButton::Left, input: WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, device_id: unsafe { DeviceId::dummy() }, }, window_id: unsafe { WindowId::dummy() }, }, end_state: ClickState::DoubleClick, input_delay: Duration::ZERO, } test_clickstate! { name: double_click_failed, initial_state: ClickState::Click, initial_button: MouseButton::Left, input: WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, device_id: unsafe { DeviceId::dummy() }, }, window_id: unsafe { WindowId::dummy() }, }, end_state: ClickState::Click, input_delay: CLICK_THRESHOLD, } test_clickstate! { name: triple_click, initial_state: ClickState::DoubleClick, initial_button: MouseButton::Left, input: WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, device_id: unsafe { DeviceId::dummy() }, }, window_id: unsafe { WindowId::dummy() }, }, end_state: ClickState::TripleClick, input_delay: Duration::ZERO, } test_clickstate! { name: triple_click_failed, initial_state: ClickState::DoubleClick, initial_button: MouseButton::Left, input: WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Left, device_id: unsafe { DeviceId::dummy() }, }, window_id: unsafe { WindowId::dummy() }, }, end_state: ClickState::Click, input_delay: CLICK_THRESHOLD, } test_clickstate! { name: multi_click_separate_buttons, initial_state: ClickState::DoubleClick, initial_button: MouseButton::Left, input: WinitEvent::WindowEvent { event: WindowEvent::MouseInput { state: ElementState::Pressed, button: MouseButton::Right, device_id: unsafe { DeviceId::dummy() }, }, window_id: unsafe { WindowId::dummy() }, }, end_state: ClickState::Click, input_delay: Duration::ZERO, } test_process_binding! { name: process_binding_nomode_shiftmod_require_shift, binding: Binding { trigger: KEY, mods: ModifiersState::SHIFT, action: Action::from("\x1b[1;2D"), mode: BindingMode::empty(), notmode: BindingMode::empty() }, triggers: true, mode: BindingMode::empty(), mods: ModifiersState::SHIFT, } test_process_binding! { name: process_binding_nomode_nomod_require_shift, binding: Binding { trigger: KEY, mods: ModifiersState::SHIFT, action: Action::from("\x1b[1;2D"), mode: BindingMode::empty(), notmode: BindingMode::empty() }, triggers: false, mode: BindingMode::empty(), mods: ModifiersState::empty(), } test_process_binding! { name: process_binding_nomode_controlmod, binding: Binding { trigger: KEY, mods: ModifiersState::CONTROL, action: Action::from("\x1b[1;5D"), mode: BindingMode::empty(), notmode: BindingMode::empty() }, triggers: true, mode: BindingMode::empty(), mods: ModifiersState::CONTROL, } test_process_binding! { name: process_binding_nomode_nomod_require_not_appcursor, binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1b[D"), mode: BindingMode::empty(), notmode: BindingMode::APP_CURSOR }, triggers: true, mode: BindingMode::empty(), mods: ModifiersState::empty(), } test_process_binding! { name: process_binding_appcursormode_nomod_require_appcursor, binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: BindingMode::APP_CURSOR, notmode: BindingMode::empty() }, triggers: true, mode: BindingMode::APP_CURSOR, mods: ModifiersState::empty(), } test_process_binding! { name: process_binding_nomode_nomod_require_appcursor, binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: BindingMode::APP_CURSOR, notmode: BindingMode::empty() }, triggers: false, mode: BindingMode::empty(), mods: ModifiersState::empty(), } test_process_binding! { name: process_binding_appcursormode_appkeypadmode_nomod_require_appcursor, binding: Binding { trigger: KEY, mods: ModifiersState::empty(), action: Action::from("\x1bOD"), mode: BindingMode::APP_CURSOR, notmode: BindingMode::empty() }, triggers: true, mode: BindingMode::APP_CURSOR | BindingMode::APP_KEYPAD, mods: ModifiersState::empty(), } test_process_binding! { name: process_binding_fail_with_extra_mods, binding: Binding { trigger: KEY, mods: ModifiersState::SUPER, action: Action::from("arst"), mode: BindingMode::empty(), notmode: BindingMode::empty() }, triggers: false, mode: BindingMode::empty(), mods: ModifiersState::ALT | ModifiersState::SUPER, } } ���������������������������������������������������������������������������������������������alacritty-0.13.2/src/ipc.rs�������������������������������������������������������������������������0000644�0000000�0000000�00000013177�10461020230�0013624�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Alacritty socket IPC. use std::ffi::OsStr; use std::io::{BufRead, BufReader, Error as IoError, ErrorKind, Result as IoResult, Write}; use std::os::unix::net::{UnixListener, UnixStream}; use std::path::PathBuf; use std::{env, fs, process}; use log::warn; use winit::event_loop::EventLoopProxy; use winit::window::WindowId; use alacritty_terminal::thread; use crate::cli::{Options, SocketMessage}; use crate::event::{Event, EventType}; /// Environment variable name for the IPC socket path. const ALACRITTY_SOCKET_ENV: &str = "ALACRITTY_SOCKET"; /// Create an IPC socket. pub fn spawn_ipc_socket(options: &Options, event_proxy: EventLoopProxy<Event>) -> Option<PathBuf> { // Create the IPC socket and export its path as env variable if necessary. let socket_path = options.socket.clone().unwrap_or_else(|| { let mut path = socket_dir(); path.push(format!("{}-{}.sock", socket_prefix(), process::id())); path }); env::set_var(ALACRITTY_SOCKET_ENV, socket_path.as_os_str()); let listener = match UnixListener::bind(&socket_path) { Ok(listener) => listener, Err(err) => { warn!("Unable to create socket: {:?}", err); return None; }, }; // Spawn a thread to listen on the IPC socket. thread::spawn_named("socket listener", move || { let mut data = String::new(); for stream in listener.incoming().filter_map(Result::ok) { data.clear(); let mut stream = BufReader::new(stream); match stream.read_line(&mut data) { Ok(0) | Err(_) => continue, Ok(_) => (), }; // Read pending events on socket. let message: SocketMessage = match serde_json::from_str(&data) { Ok(message) => message, Err(err) => { warn!("Failed to convert data from socket: {}", err); continue; }, }; // Handle IPC events. match message { SocketMessage::CreateWindow(options) => { let event = Event::new(EventType::CreateWindow(options), None); let _ = event_proxy.send_event(event); }, SocketMessage::Config(ipc_config) => { let window_id = ipc_config .window_id .and_then(|id| u64::try_from(id).ok()) .map(WindowId::from); let event = Event::new(EventType::IpcConfig(ipc_config), window_id); let _ = event_proxy.send_event(event); }, } } }); Some(socket_path) } /// Send a message to the active Alacritty socket. pub fn send_message(socket: Option<PathBuf>, message: SocketMessage) -> IoResult<()> { let mut socket = find_socket(socket)?; let message = serde_json::to_string(&message)?; socket.write_all(message[..].as_bytes())?; let _ = socket.flush(); Ok(()) } /// Directory for the IPC socket file. #[cfg(not(target_os = "macos"))] fn socket_dir() -> PathBuf { xdg::BaseDirectories::with_prefix("alacritty") .ok() .and_then(|xdg| xdg.get_runtime_directory().map(ToOwned::to_owned).ok()) .and_then(|path| fs::create_dir_all(&path).map(|_| path).ok()) .unwrap_or_else(env::temp_dir) } /// Directory for the IPC socket file. #[cfg(target_os = "macos")] fn socket_dir() -> PathBuf { env::temp_dir() } /// Find the IPC socket path. fn find_socket(socket_path: Option<PathBuf>) -> IoResult<UnixStream> { // Handle --socket CLI override. if let Some(socket_path) = socket_path { // Ensure we inform the user about an invalid path. return UnixStream::connect(&socket_path).map_err(|err| { let message = format!("invalid socket path {:?}", socket_path); IoError::new(err.kind(), message) }); } // Handle environment variable. if let Ok(path) = env::var(ALACRITTY_SOCKET_ENV) { let socket_path = PathBuf::from(path); if let Ok(socket) = UnixStream::connect(socket_path) { return Ok(socket); } } // Search for sockets files. for entry in fs::read_dir(socket_dir())?.filter_map(|entry| entry.ok()) { let path = entry.path(); // Skip files that aren't Alacritty sockets. let socket_prefix = socket_prefix(); if path .file_name() .and_then(OsStr::to_str) .filter(|file| file.starts_with(&socket_prefix) && file.ends_with(".sock")) .is_none() { continue; } // Attempt to connect to the socket. match UnixStream::connect(&path) { Ok(socket) => return Ok(socket), // Delete orphan sockets. Err(error) if error.kind() == ErrorKind::ConnectionRefused => { let _ = fs::remove_file(&path); }, // Ignore other errors like permission issues. Err(_) => (), } } Err(IoError::new(ErrorKind::NotFound, "no socket found")) } /// File prefix matching all available sockets. /// /// This prefix will include display server information to allow for environments with multiple /// display servers running for the same user. #[cfg(not(target_os = "macos"))] fn socket_prefix() -> String { let display = env::var("WAYLAND_DISPLAY").or_else(|_| env::var("DISPLAY")).unwrap_or_default(); format!("Alacritty-{}", display.replace('/', "-")) } /// File prefix matching all available sockets. #[cfg(target_os = "macos")] fn socket_prefix() -> String { String::from("Alacritty") } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/logging.rs���������������������������������������������������������������������0000644�0000000�0000000�00000017516�10461020230�0014500�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Logging for Alacritty. //! //! The main executable is supposed to call `initialize()` exactly once during //! startup. All logging messages are written to stdout, given that their //! log-level is sufficient for the level configured in `cli::Options`. use std::fs::{File, OpenOptions}; use std::io::{self, LineWriter, Stdout, Write}; use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, OnceLock}; use std::time::Instant; use std::{env, process}; use log::{Level, LevelFilter}; use winit::event_loop::EventLoopProxy; use crate::cli::Options; use crate::event::{Event, EventType}; use crate::message_bar::{Message, MessageType}; /// Logging target for IPC config error messages. pub const LOG_TARGET_IPC_CONFIG: &str = "alacritty_log_window_config"; /// Name for the environment variable containing the log file's path. const ALACRITTY_LOG_ENV: &str = "ALACRITTY_LOG"; /// Logging target for config error messages. pub const LOG_TARGET_CONFIG: &str = "alacritty_config_derive"; /// Name for the environment variable containing extra logging targets. /// /// The targets are semicolon separated. const ALACRITTY_EXTRA_LOG_TARGETS_ENV: &str = "ALACRITTY_EXTRA_LOG_TARGETS"; /// User configurable extra log targets to include. fn extra_log_targets() -> &'static [String] { static EXTRA_LOG_TARGETS: OnceLock<Vec<String>> = OnceLock::new(); EXTRA_LOG_TARGETS.get_or_init(|| { env::var(ALACRITTY_EXTRA_LOG_TARGETS_ENV) .map_or(Vec::new(), |targets| targets.split(';').map(ToString::to_string).collect()) }) } /// List of targets which will be logged by Alacritty. const ALLOWED_TARGETS: &[&str] = &[ LOG_TARGET_IPC_CONFIG, LOG_TARGET_CONFIG, "alacritty_config_derive", "alacritty_terminal", "alacritty", "crossfont", ]; /// Initialize the logger to its defaults. pub fn initialize( options: &Options, event_proxy: EventLoopProxy<Event>, ) -> Result<Option<PathBuf>, log::SetLoggerError> { log::set_max_level(options.log_level()); let logger = Logger::new(event_proxy); let path = logger.file_path(); log::set_boxed_logger(Box::new(logger))?; Ok(path) } pub struct Logger { logfile: Mutex<OnDemandLogFile>, stdout: Mutex<LineWriter<Stdout>>, event_proxy: Mutex<EventLoopProxy<Event>>, start: Instant, } impl Logger { fn new(event_proxy: EventLoopProxy<Event>) -> Self { let logfile = Mutex::new(OnDemandLogFile::new()); let stdout = Mutex::new(LineWriter::new(io::stdout())); Logger { logfile, stdout, event_proxy: Mutex::new(event_proxy), start: Instant::now() } } fn file_path(&self) -> Option<PathBuf> { if let Ok(logfile) = self.logfile.lock() { Some(logfile.path().clone()) } else { None } } /// Log a record to the message bar. fn message_bar_log(&self, record: &log::Record<'_>, logfile_path: &str) { let message_type = match record.level() { Level::Error => MessageType::Error, Level::Warn => MessageType::Warning, _ => return, }; let event_proxy = match self.event_proxy.lock() { Ok(event_proxy) => event_proxy, Err(_) => return, }; #[cfg(not(windows))] let env_var = format!("${}", ALACRITTY_LOG_ENV); #[cfg(windows)] let env_var = format!("%{}%", ALACRITTY_LOG_ENV); let message = format!( "[{}] See log at {} ({}):\n{}", record.level(), logfile_path, env_var, record.args(), ); let mut message = Message::new(message, message_type); message.set_target(record.target().to_owned()); let _ = event_proxy.send_event(Event::new(EventType::Message(message), None)); } } impl log::Log for Logger { fn enabled(&self, metadata: &log::Metadata<'_>) -> bool { metadata.level() <= log::max_level() } fn log(&self, record: &log::Record<'_>) { // Get target crate. let index = record.target().find(':').unwrap_or_else(|| record.target().len()); let target = &record.target()[..index]; // Only log our own crates, except when logging at Level::Trace. if !self.enabled(record.metadata()) || !is_allowed_target(record.level(), target) { return; } // Create log message for the given `record` and `target`. let message = create_log_message(record, target, self.start); if let Ok(mut logfile) = self.logfile.lock() { // Write to logfile. let _ = logfile.write_all(message.as_ref()); // Log relevant entries to message bar. self.message_bar_log(record, &logfile.path.to_string_lossy()); } // Write to stdout. if let Ok(mut stdout) = self.stdout.lock() { let _ = stdout.write_all(message.as_ref()); } } fn flush(&self) {} } fn create_log_message(record: &log::Record<'_>, target: &str, start: Instant) -> String { let runtime = start.elapsed(); let secs = runtime.as_secs(); let nanos = runtime.subsec_nanos(); let mut message = format!("[{}.{:0>9}s] [{:<5}] [{}] ", secs, nanos, record.level(), target); // Alignment for the lines after the first new line character in the payload. We don't deal // with fullwidth/unicode chars here, so just `message.len()` is sufficient. let alignment = message.len(); // Push lines with added extra padding on the next line, which is trimmed later. let lines = record.args().to_string(); for line in lines.split('\n') { let line = format!("{}\n{:width$}", line, "", width = alignment); message.push_str(&line); } // Drop extra trailing alignment. message.truncate(message.len() - alignment); message } /// Check if log messages from a crate should be logged. fn is_allowed_target(level: Level, target: &str) -> bool { match (level, log::max_level()) { (Level::Error, LevelFilter::Trace) | (Level::Warn, LevelFilter::Trace) => true, _ => ALLOWED_TARGETS.contains(&target) || extra_log_targets().iter().any(|t| t == target), } } struct OnDemandLogFile { file: Option<LineWriter<File>>, created: Arc<AtomicBool>, path: PathBuf, } impl OnDemandLogFile { fn new() -> Self { let mut path = env::temp_dir(); path.push(format!("Alacritty-{}.log", process::id())); // Set log path as an environment variable. env::set_var(ALACRITTY_LOG_ENV, path.as_os_str()); OnDemandLogFile { path, file: None, created: Arc::new(AtomicBool::new(false)) } } fn file(&mut self) -> Result<&mut LineWriter<File>, io::Error> { // Allow to recreate the file if it has been deleted at runtime. if self.file.is_some() && !self.path.as_path().exists() { self.file = None; } // Create the file if it doesn't exist yet. if self.file.is_none() { let file = OpenOptions::new().append(true).create_new(true).open(&self.path); match file { Ok(file) => { self.file = Some(io::LineWriter::new(file)); self.created.store(true, Ordering::Relaxed); let _ = writeln!(io::stdout(), "Created log file at \"{}\"", self.path.display()); }, Err(e) => { let _ = writeln!(io::stdout(), "Unable to create log file: {}", e); return Err(e); }, } } Ok(self.file.as_mut().unwrap()) } fn path(&self) -> &PathBuf { &self.path } } impl Write for OnDemandLogFile { fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> { self.file()?.write(buf) } fn flush(&mut self) -> Result<(), io::Error> { self.file()?.flush() } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/macos/locale.rs����������������������������������������������������������������0000644�0000000�0000000�00000007572�10461020230�0015414�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#![allow(clippy::let_unit_value)] use std::ffi::{CStr, CString}; use std::os::raw::c_char; use std::{env, slice, str}; use libc::{setlocale, LC_ALL, LC_CTYPE}; use log::debug; use objc::runtime::{Class, Object}; use objc::{msg_send, sel, sel_impl}; const FALLBACK_LOCALE: &str = "UTF-8"; pub fn set_locale_environment() { let env_locale_c = CString::new("").unwrap(); let env_locale_ptr = unsafe { setlocale(LC_ALL, env_locale_c.as_ptr()) }; if !env_locale_ptr.is_null() { let env_locale = unsafe { CStr::from_ptr(env_locale_ptr).to_string_lossy() }; // Assume `C` locale means unchanged, since it is the default anyways. if env_locale != "C" { debug!("Using environment locale: {}", env_locale); return; } } let system_locale = system_locale(); // Set locale to system locale. let system_locale_c = CString::new(system_locale.clone()).expect("nul byte in system locale"); let lc_all = unsafe { setlocale(LC_ALL, system_locale_c.as_ptr()) }; // Check if system locale was valid or not. if lc_all.is_null() { // Use fallback locale. debug!("Using fallback locale: {}", FALLBACK_LOCALE); let fallback_locale_c = CString::new(FALLBACK_LOCALE).unwrap(); unsafe { setlocale(LC_CTYPE, fallback_locale_c.as_ptr()) }; env::set_var("LC_CTYPE", FALLBACK_LOCALE); } else { // Use system locale. debug!("Using system locale: {}", system_locale); env::set_var("LC_ALL", system_locale); } } /// Determine system locale based on language and country code. fn system_locale() -> String { unsafe { let locale_class = Class::get("NSLocale").unwrap(); let locale: *const Object = msg_send![locale_class, currentLocale]; let _: () = msg_send![locale_class, release]; // `localeIdentifier` returns extra metadata with the locale (including currency and // collator) on newer versions of macOS. This is not a valid locale, so we use // `languageCode` and `countryCode`, if they're available (macOS 10.12+): // // https://developer.apple.com/documentation/foundation/nslocale/1416263-localeidentifier?language=objc // https://developer.apple.com/documentation/foundation/nslocale/1643060-countrycode?language=objc // https://developer.apple.com/documentation/foundation/nslocale/1643026-languagecode?language=objc let is_language_code_supported: bool = msg_send![locale, respondsToSelector: sel!(languageCode)]; let is_country_code_supported: bool = msg_send![locale, respondsToSelector: sel!(countryCode)]; let locale_id = if is_language_code_supported && is_country_code_supported { let language_code: *const Object = msg_send![locale, languageCode]; let language_code_str = nsstring_as_str(language_code).to_owned(); let _: () = msg_send![language_code, release]; let country_code: *const Object = msg_send![locale, countryCode]; let country_code_str = nsstring_as_str(country_code).to_owned(); let _: () = msg_send![country_code, release]; format!("{}_{}.UTF-8", &language_code_str, &country_code_str) } else { let identifier: *const Object = msg_send![locale, localeIdentifier]; let identifier_str = nsstring_as_str(identifier).to_owned(); let _: () = msg_send![identifier, release]; identifier_str + ".UTF-8" }; let _: () = msg_send![locale, release]; locale_id } } const UTF8_ENCODING: usize = 4; unsafe fn nsstring_as_str<'a>(nsstring: *const Object) -> &'a str { let cstr: *const c_char = msg_send![nsstring, UTF8String]; let len: usize = msg_send![nsstring, lengthOfBytesUsingEncoding: UTF8_ENCODING]; str::from_utf8(slice::from_raw_parts(cstr as *const u8, len)).unwrap() } ��������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/macos/mod.rs�������������������������������������������������������������������0000644�0000000�0000000�00000000036�10461020230�0014720�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������pub mod locale; pub mod proc; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/macos/proc.rs������������������������������������������������������������������0000644�0000000�0000000�00000010017�10461020230�0015104�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::ffi::{CStr, CString, IntoStringError}; use std::fmt::{self, Display, Formatter}; use std::io; use std::mem::{self, MaybeUninit}; use std::os::raw::{c_int, c_void}; use std::path::PathBuf; /// Error during working directory retrieval. #[derive(Debug)] pub enum Error { Io(io::Error), /// Error converting into utf8 string. IntoString(IntoStringError), /// Expected return size didn't match libproc's. InvalidSize, } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Error::InvalidSize => None, Error::Io(err) => err.source(), Error::IntoString(err) => err.source(), } } } impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Error::InvalidSize => write!(f, "Invalid proc_pidinfo return size"), Error::Io(err) => write!(f, "Error getting current working directory: {}", err), Error::IntoString(err) => { write!(f, "Error when parsing current working directory: {}", err) }, } } } impl From<io::Error> for Error { fn from(val: io::Error) -> Self { Error::Io(val) } } impl From<IntoStringError> for Error { fn from(val: IntoStringError) -> Self { Error::IntoString(val) } } pub fn cwd(pid: c_int) -> Result<PathBuf, Error> { let mut info = MaybeUninit::<sys::proc_vnodepathinfo>::uninit(); let info_ptr = info.as_mut_ptr() as *mut c_void; let size = mem::size_of::<sys::proc_vnodepathinfo>() as c_int; let c_str = unsafe { let pidinfo_size = sys::proc_pidinfo(pid, sys::PROC_PIDVNODEPATHINFO, 0, info_ptr, size); match pidinfo_size { c if c < 0 => return Err(io::Error::last_os_error().into()), s if s != size => return Err(Error::InvalidSize), _ => CStr::from_ptr(info.assume_init().pvi_cdir.vip_path.as_ptr()), } }; Ok(CString::from(c_str).into_string().map(PathBuf::from)?) } /// Bindings for libproc. #[allow(non_camel_case_types)] mod sys { use std::os::raw::{c_char, c_int, c_longlong, c_void}; pub const PROC_PIDVNODEPATHINFO: c_int = 9; type gid_t = c_int; type off_t = c_longlong; type uid_t = c_int; type fsid_t = fsid; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct fsid { pub val: [i32; 2usize], } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct vinfo_stat { pub vst_dev: u32, pub vst_mode: u16, pub vst_nlink: u16, pub vst_ino: u64, pub vst_uid: uid_t, pub vst_gid: gid_t, pub vst_atime: i64, pub vst_atimensec: i64, pub vst_mtime: i64, pub vst_mtimensec: i64, pub vst_ctime: i64, pub vst_ctimensec: i64, pub vst_birthtime: i64, pub vst_birthtimensec: i64, pub vst_size: off_t, pub vst_blocks: i64, pub vst_blksize: i32, pub vst_flags: u32, pub vst_gen: u32, pub vst_rdev: u32, pub vst_qspare: [i64; 2usize], } #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct vnode_info { pub vi_stat: vinfo_stat, pub vi_type: c_int, pub vi_pad: c_int, pub vi_fsid: fsid_t, } #[repr(C)] #[derive(Copy, Clone)] pub struct vnode_info_path { pub vip_vi: vnode_info, pub vip_path: [c_char; 1024usize], } #[repr(C)] #[derive(Copy, Clone)] pub struct proc_vnodepathinfo { pub pvi_cdir: vnode_info_path, pub pvi_rdir: vnode_info_path, } extern "C" { pub fn proc_pidinfo( pid: c_int, flavor: c_int, arg: u64, buffer: *mut c_void, buffersize: c_int, ) -> c_int; } } #[cfg(test)] mod tests { use super::*; use std::{env, process}; #[test] fn cwd_matches_current_dir() { assert_eq!(cwd(process::id() as i32).ok(), env::current_dir().ok()); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/main.rs������������������������������������������������������������������������0000644�0000000�0000000�00000016001�10461020230�0013762�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Alacritty - The GPU Enhanced Terminal. #![warn(rust_2018_idioms, future_incompatible)] #![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)] #![cfg_attr(clippy, deny(warnings))] // With the default subsystem, 'console', windows creates an additional console // window for the program. // This is silently ignored on non-windows systems. // See https://msdn.microsoft.com/en-us/library/4cc7ya5b.aspx for more details. #![windows_subsystem = "windows"] #[cfg(not(any(feature = "x11", feature = "wayland", target_os = "macos", windows)))] compile_error!(r#"at least one of the "x11"/"wayland" features must be enabled"#); use std::error::Error; use std::fmt::Write as _; use std::io::{self, Write}; use std::path::PathBuf; use std::{env, fs}; use log::info; #[cfg(windows)] use windows_sys::Win32::System::Console::{AttachConsole, FreeConsole, ATTACH_PARENT_PROCESS}; use winit::event_loop::EventLoopBuilder as WinitEventLoopBuilder; #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] use winit::platform::x11::EventLoopWindowTargetExtX11; use alacritty_terminal::tty; mod cli; mod clipboard; mod config; mod daemon; mod display; mod event; mod input; #[cfg(unix)] mod ipc; mod logging; #[cfg(target_os = "macos")] mod macos; mod message_bar; mod migrate; #[cfg(windows)] mod panic; mod renderer; mod scheduler; mod string; mod window_context; mod gl { #![allow(clippy::all)] include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs")); } #[cfg(unix)] use crate::cli::MessageOptions; use crate::cli::{Options, Subcommands}; use crate::config::{monitor, UiConfig}; use crate::event::{Event, Processor}; #[cfg(target_os = "macos")] use crate::macos::locale; fn main() -> Result<(), Box<dyn Error>> { #[cfg(windows)] panic::attach_handler(); // When linked with the windows subsystem windows won't automatically attach // to the console of the parent process, so we do it explicitly. This fails // silently if the parent has no console. #[cfg(windows)] unsafe { AttachConsole(ATTACH_PARENT_PROCESS); } // Load command line options. let options = Options::new(); match options.subcommands { #[cfg(unix)] Some(Subcommands::Msg(options)) => msg(options)?, Some(Subcommands::Migrate(options)) => migrate::migrate(options), None => alacritty(options)?, } Ok(()) } /// `msg` subcommand entrypoint. #[cfg(unix)] fn msg(options: MessageOptions) -> Result<(), Box<dyn Error>> { ipc::send_message(options.socket, options.message).map_err(|err| err.into()) } /// Temporary files stored for Alacritty. /// /// This stores temporary files to automate their destruction through its `Drop` implementation. struct TemporaryFiles { #[cfg(unix)] socket_path: Option<PathBuf>, log_file: Option<PathBuf>, } impl Drop for TemporaryFiles { fn drop(&mut self) { // Clean up the IPC socket file. #[cfg(unix)] if let Some(socket_path) = &self.socket_path { let _ = fs::remove_file(socket_path); } // Clean up logfile. if let Some(log_file) = &self.log_file { if fs::remove_file(log_file).is_ok() { let _ = writeln!(io::stdout(), "Deleted log file at \"{}\"", log_file.display()); } } } } /// Run main Alacritty entrypoint. /// /// Creates a window, the terminal state, PTY, I/O event loop, input processor, /// config change monitor, and runs the main display loop. fn alacritty(mut options: Options) -> Result<(), Box<dyn Error>> { // Setup winit event loop. let window_event_loop = WinitEventLoopBuilder::<Event>::with_user_event().build()?; // Initialize the logger as soon as possible as to capture output from other subsystems. let log_file = logging::initialize(&options, window_event_loop.create_proxy()) .expect("Unable to initialize logger"); info!("Welcome to Alacritty"); info!("Version {}", env!("VERSION")); #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] info!("Running on {}", if window_event_loop.is_x11() { "X11" } else { "Wayland" }); #[cfg(not(any(feature = "x11", target_os = "macos", windows)))] info!("Running on Wayland"); // Load configuration file. let config = config::load(&mut options); log_config_path(&config); // Update the log level from config. log::set_max_level(config.debug.log_level); // Set tty environment variables. tty::setup_env(); // Set env vars from config. for (key, value) in config.env.iter() { env::set_var(key, value); } // Switch to home directory. #[cfg(target_os = "macos")] env::set_current_dir(home::home_dir().unwrap()).unwrap(); // Set macOS locale. #[cfg(target_os = "macos")] locale::set_locale_environment(); // Create a config monitor when config was loaded from path. // // The monitor watches the config file for changes and reloads it. Pending // config changes are processed in the main loop. if config.live_config_reload { monitor::watch(config.config_paths.clone(), window_event_loop.create_proxy()); } // Create the IPC socket listener. #[cfg(unix)] let socket_path = if config.ipc_socket { ipc::spawn_ipc_socket(&options, window_event_loop.create_proxy()) } else { None }; // Setup automatic RAII cleanup for our files. let log_cleanup = log_file.filter(|_| !config.debug.persistent_logging); let _files = TemporaryFiles { #[cfg(unix)] socket_path, log_file: log_cleanup, }; // Event processor. let window_options = options.window_options.clone(); let mut processor = Processor::new(config, options, &window_event_loop); // Start event loop and block until shutdown. let result = processor.run(window_event_loop, window_options); // This explicit drop is needed for Windows, ConPTY backend. Otherwise a deadlock can occur. // The cause: // - Drop for ConPTY will deadlock if the conout pipe has already been dropped // - ConPTY is dropped when the last of processor and window context are dropped, because both // of them own an Arc<ConPTY> // // The fix is to ensure that processor is dropped first. That way, when window context (i.e. // PTY) is dropped, it can ensure ConPTY is dropped before the conout pipe in the PTY drop // order. // // FIXME: Change PTY API to enforce the correct drop order with the typesystem. drop(processor); // FIXME patch notify library to have a shutdown method. // config_reloader.join().ok(); // Without explicitly detaching the console cmd won't redraw it's prompt. #[cfg(windows)] unsafe { FreeConsole(); } info!("Goodbye"); result } fn log_config_path(config: &UiConfig) { if config.config_paths.is_empty() { return; } let mut msg = String::from("Configuration files loaded from:"); for path in &config.config_paths { let _ = write!(msg, "\n {:?}", path.display()); } info!("{}", msg); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/message_bar.rs�����������������������������������������������������������������0000644�0000000�0000000�00000030666�10461020230�0015323�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::collections::VecDeque; use unicode_width::UnicodeWidthChar; use alacritty_terminal::grid::Dimensions; use crate::display::SizeInfo; pub const CLOSE_BUTTON_TEXT: &str = "[X]"; const CLOSE_BUTTON_PADDING: usize = 1; const MIN_FREE_LINES: usize = 3; const TRUNCATED_MESSAGE: &str = "[MESSAGE TRUNCATED]"; /// Message for display in the MessageBuffer. #[derive(Debug, Eq, PartialEq, Clone)] pub struct Message { text: String, ty: MessageType, target: Option<String>, } /// Purpose of the message. #[derive(Debug, Eq, PartialEq, Clone, Copy)] pub enum MessageType { /// A message represents an error. Error, /// A message represents a warning. Warning, } impl Message { /// Create a new message. pub fn new(text: String, ty: MessageType) -> Message { Message { text, ty, target: None } } /// Formatted message text lines. pub fn text(&self, size_info: &SizeInfo) -> Vec<String> { let num_cols = size_info.columns(); let total_lines = (size_info.height() - 2. * size_info.padding_y()) / size_info.cell_height(); let max_lines = (total_lines as usize).saturating_sub(MIN_FREE_LINES); let button_len = CLOSE_BUTTON_TEXT.chars().count(); // Split line to fit the screen. let mut lines = Vec::new(); let mut line = String::new(); let mut line_len = 0; for c in self.text.trim().chars() { if c == '\n' || line_len == num_cols // Keep space in first line for button. || (lines.is_empty() && num_cols >= button_len && line_len == num_cols.saturating_sub(button_len + CLOSE_BUTTON_PADDING)) { let is_whitespace = c.is_whitespace(); // Attempt to wrap on word boundaries. let mut new_line = String::new(); if let Some(index) = line.rfind(char::is_whitespace).filter(|_| !is_whitespace) { let split = line.split_off(index + 1); line.pop(); new_line = split; } lines.push(Self::pad_text(line, num_cols)); line = new_line; line_len = line.chars().count(); // Do not append whitespace at EOL. if is_whitespace { continue; } } line.push(c); // Reserve extra column for fullwidth characters. let width = c.width().unwrap_or(0); if width == 2 { line.push(' '); } line_len += width } lines.push(Self::pad_text(line, num_cols)); // Truncate output if it's too long. if lines.len() > max_lines { lines.truncate(max_lines); if TRUNCATED_MESSAGE.len() <= num_cols { if let Some(line) = lines.iter_mut().last() { *line = Self::pad_text(TRUNCATED_MESSAGE.into(), num_cols); } } } // Append close button to first line. if button_len <= num_cols { if let Some(line) = lines.get_mut(0) { line.truncate(num_cols - button_len); line.push_str(CLOSE_BUTTON_TEXT); } } lines } /// Message type. #[inline] pub fn ty(&self) -> MessageType { self.ty } /// Message target. #[inline] pub fn target(&self) -> Option<&String> { self.target.as_ref() } /// Update the message target. #[inline] pub fn set_target(&mut self, target: String) { self.target = Some(target); } /// Right-pad text to fit a specific number of columns. #[inline] fn pad_text(mut text: String, num_cols: usize) -> String { let padding_len = num_cols.saturating_sub(text.chars().count()); text.extend(vec![' '; padding_len]); text } } /// Storage for message bar. #[derive(Debug, Default)] pub struct MessageBuffer { messages: VecDeque<Message>, } impl MessageBuffer { /// Check if there are any messages queued. #[inline] pub fn is_empty(&self) -> bool { self.messages.is_empty() } /// Current message. #[inline] pub fn message(&self) -> Option<&Message> { self.messages.front() } /// Remove the currently visible message. #[inline] pub fn pop(&mut self) { // Remove the message itself. let msg = self.messages.pop_front(); // Remove all duplicates. if let Some(msg) = msg { self.messages = self.messages.drain(..).filter(|m| m != &msg).collect(); } } /// Remove all messages with a specific target. #[inline] pub fn remove_target(&mut self, target: &str) { self.messages = self .messages .drain(..) .filter(|m| m.target().map(String::as_str) != Some(target)) .collect(); } /// Add a new message to the queue. #[inline] pub fn push(&mut self, message: Message) { self.messages.push_back(message); } /// Check whether the message is already queued in the message bar. #[inline] pub fn is_queued(&self, message: &Message) -> bool { self.messages.contains(message) } } #[cfg(test)] mod tests { use super::*; use crate::display::SizeInfo; #[test] fn appends_close_button() { let input = "a"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(7., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![String::from("a [X]")]); } #[test] fn multiline_close_button_first_line() { let input = "fo\nbar"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(6., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![String::from("fo [X]"), String::from("bar ")]); } #[test] fn splits_on_newline() { let input = "a\nb"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(6., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines.len(), 2); } #[test] fn splits_on_length() { let input = "foobar1"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(6., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines.len(), 2); } #[test] fn empty_with_shortterm() { let input = "foobar"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(6., 0., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines.len(), 0); } #[test] fn truncates_long_messages() { let input = "hahahahahahahahahahaha truncate this because it's too long for the term"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(22., (MIN_FREE_LINES + 2) as f32, 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![ String::from("hahahahahahahahaha [X]"), String::from("[MESSAGE TRUNCATED] ") ]); } #[test] fn hide_button_when_too_narrow() { let input = "ha"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(2., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![String::from("ha")]); } #[test] fn hide_truncated_when_too_narrow() { let input = "hahahahahahahahaha"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(2., (MIN_FREE_LINES + 2) as f32, 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![String::from("ha"), String::from("ha")]); } #[test] fn add_newline_for_button() { let input = "test"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(5., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![String::from("t [X]"), String::from("est ")]); } #[test] fn remove_target() { let mut message_buffer = MessageBuffer::default(); for i in 0..10 { let mut msg = Message::new(i.to_string(), MessageType::Error); if i % 2 == 0 && i < 5 { msg.set_target("target".into()); } message_buffer.push(msg); } message_buffer.remove_target("target"); // Count number of messages. let mut num_messages = 0; while message_buffer.message().is_some() { num_messages += 1; message_buffer.pop(); } assert_eq!(num_messages, 7); } #[test] fn pop() { let mut message_buffer = MessageBuffer::default(); let one = Message::new(String::from("one"), MessageType::Error); message_buffer.push(one.clone()); let two = Message::new(String::from("two"), MessageType::Warning); message_buffer.push(two.clone()); assert_eq!(message_buffer.message(), Some(&one)); message_buffer.pop(); assert_eq!(message_buffer.message(), Some(&two)); } #[test] fn wrap_on_words() { let input = "a\nbc defg"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(5., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![ String::from("a [X]"), String::from("bc "), String::from("defg ") ]); } #[test] fn wrap_with_unicode() { let input = "ab\nc 👩d fgh"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(7., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![ String::from("ab [X]"), String::from("c 👩 d "), String::from("fgh ") ]); } #[test] fn strip_whitespace_at_linebreak() { let input = "\n0 1 2 3"; let mut message_buffer = MessageBuffer::default(); message_buffer.push(Message::new(input.into(), MessageType::Error)); let size = SizeInfo::new(3., 10., 1., 1., 0., 0., false); let lines = message_buffer.message().unwrap().text(&size); assert_eq!(lines, vec![String::from("[X]"), String::from("0 1"), String::from("2 3"),]); } #[test] fn remove_duplicates() { let mut message_buffer = MessageBuffer::default(); for _ in 0..10 { let msg = Message::new(String::from("test"), MessageType::Error); message_buffer.push(msg); } message_buffer.push(Message::new(String::from("other"), MessageType::Error)); message_buffer.push(Message::new(String::from("test"), MessageType::Warning)); let _ = message_buffer.message(); message_buffer.pop(); // Count number of messages. let mut num_messages = 0; while message_buffer.message().is_some() { num_messages += 1; message_buffer.pop(); } assert_eq!(num_messages, 2); } } ��������������������������������������������������������������������������alacritty-0.13.2/src/migrate.rs���������������������������������������������������������������������0000644�0000000�0000000�00000017620�10461020230�0014476�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Configuration file migration. use std::fs; use std::path::Path; use toml::map::Entry; use toml::{Table, Value}; use crate::cli::MigrateOptions; use crate::config; /// Handle migration. pub fn migrate(options: MigrateOptions) { // Find configuration file path. let config_path = options .config_file .clone() .or_else(|| config::installed_config("toml")) .or_else(|| config::installed_config("yml")); // Abort if system has no installed configuration. let config_path = match config_path { Some(config_path) => config_path, None => { eprintln!("No configuration file found"); std::process::exit(1); }, }; // If we're doing a wet run, perform a dry run first for safety. if !options.dry_run { #[allow(clippy::redundant_clone)] let mut options = options.clone(); options.silent = true; options.dry_run = true; if let Err(err) = migrate_config(&options, &config_path, config::IMPORT_RECURSION_LIMIT) { eprintln!("Configuration file migration failed:"); eprintln!(" {config_path:?}: {err}"); std::process::exit(1); } } // Migrate the root config. match migrate_config(&options, &config_path, config::IMPORT_RECURSION_LIMIT) { Ok(new_path) => { if !options.silent { println!("Successfully migrated {config_path:?} to {new_path:?}"); } }, Err(err) => { eprintln!("Configuration file migration failed:"); eprintln!(" {config_path:?}: {err}"); std::process::exit(1); }, } } /// Migrate a specific configuration file. fn migrate_config( options: &MigrateOptions, path: &Path, recursion_limit: usize, ) -> Result<String, String> { // Ensure configuration file has an extension. let path_str = path.to_string_lossy(); let (prefix, suffix) = match path_str.rsplit_once('.') { Some((prefix, suffix)) => (prefix, suffix), None => return Err("missing file extension".to_string()), }; // Abort if config is already toml. if suffix == "toml" { return Err("already in TOML format".to_string()); } // Try to parse the configuration file. let mut config = match config::deserialize_config(path, !options.dry_run) { Ok(config) => config, Err(err) => return Err(format!("parsing error: {err}")), }; // Migrate config imports. if !options.skip_imports { migrate_imports(options, &mut config, recursion_limit)?; } // Migrate deprecated field names to their new location. if !options.skip_renames { migrate_renames(&mut config)?; } // Convert to TOML format. let toml = toml::to_string(&config).map_err(|err| format!("conversion error: {err}"))?; let new_path = format!("{prefix}.toml"); if options.dry_run && !options.silent { // Output new content to STDOUT. println!( "\nv-----Start TOML for {path:?}-----v\n\n{toml}\n^-----End TOML for {path:?}-----^\n" ); } else if !options.dry_run { // Write the new toml configuration. fs::write(&new_path, toml).map_err(|err| format!("filesystem error: {err}"))?; } Ok(new_path) } /// Migrate the imports of a config. fn migrate_imports( options: &MigrateOptions, config: &mut Value, recursion_limit: usize, ) -> Result<(), String> { let imports = match config::imports(config, recursion_limit) { Ok(imports) => imports, Err(err) => return Err(format!("import error: {err}")), }; // Migrate the individual imports. let mut new_imports = Vec::new(); for import in imports { let import = match import { Ok(import) => import, Err(err) => return Err(format!("import error: {err}")), }; // Keep yaml import if path does not exist. if !import.exists() { if options.dry_run { eprintln!("Keeping yaml config for nonexistent import: {import:?}"); } new_imports.push(Value::String(import.to_string_lossy().into())); continue; } let new_path = migrate_config(options, &import, recursion_limit - 1)?; // Print new import path. if options.dry_run { println!("Successfully migrated import {import:?} to {new_path:?}"); } new_imports.push(Value::String(new_path)); } // Update the imports field. if let Some(import) = config.get_mut("import") { *import = Value::Array(new_imports); } Ok(()) } /// Migrate deprecated fields. fn migrate_renames(config: &mut Value) -> Result<(), String> { let config_table = match config.as_table_mut() { Some(config_table) => config_table, None => return Ok(()), }; // draw_bold_text_with_bright_colors -> colors.draw_bold_text_with_bright_colors move_value(config_table, &["draw_bold_text_with_bright_colors"], &[ "colors", "draw_bold_text_with_bright_colors", ])?; // key_bindings -> keyboard.bindings move_value(config_table, &["key_bindings"], &["keyboard", "bindings"])?; // mouse_bindings -> mouse.bindings move_value(config_table, &["mouse_bindings"], &["mouse", "bindings"])?; Ok(()) } /// Move a toml value from one map to another. fn move_value(config_table: &mut Table, origin: &[&str], target: &[&str]) -> Result<(), String> { if let Some(value) = remove_node(config_table, origin)? { if !insert_node_if_empty(config_table, target, value)? { return Err(format!( "conflict: both `{}` and `{}` are set", origin.join("."), target.join(".") )); } } Ok(()) } /// Remove a node from a tree of tables. fn remove_node(table: &mut Table, path: &[&str]) -> Result<Option<Value>, String> { if path.len() == 1 { Ok(table.remove(path[0])) } else { let next_table_value = match table.get_mut(path[0]) { Some(next_table_value) => next_table_value, None => return Ok(None), }; let next_table = match next_table_value.as_table_mut() { Some(next_table) => next_table, None => return Err(format!("invalid `{}` table", path[0])), }; remove_node(next_table, &path[1..]) } } /// Try to insert a node into a tree of tables. /// /// Returns `false` if the node already exists. fn insert_node_if_empty(table: &mut Table, path: &[&str], node: Value) -> Result<bool, String> { if path.len() == 1 { match table.entry(path[0]) { Entry::Vacant(vacant_entry) => { vacant_entry.insert(node); Ok(true) }, Entry::Occupied(_) => Ok(false), } } else { let next_table_value = table.entry(path[0]).or_insert_with(|| Value::Table(Table::new())); let next_table = match next_table_value.as_table_mut() { Some(next_table) => next_table, None => return Err(format!("invalid `{}` table", path[0])), }; insert_node_if_empty(next_table, &path[1..], node) } } #[cfg(test)] mod tests { use super::*; #[test] fn move_values() { let input = r#" root_value = 3 [table] table_value = 5 [preexisting] not_moved = 9 "#; let mut value: Value = toml::from_str(input).unwrap(); let table = value.as_table_mut().unwrap(); move_value(table, &["root_value"], &["new_table", "root_value"]).unwrap(); move_value(table, &["table", "table_value"], &["preexisting", "subtable", "new_name"]) .unwrap(); let output = toml::to_string(table).unwrap(); assert_eq!( output, "[new_table]\nroot_value = 3\n\n[preexisting]\nnot_moved = \ 9\n\n[preexisting.subtable]\nnew_name = 5\n\n[table]\n" ); } } ����������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/panic.rs�����������������������������������������������������������������������0000644�0000000�0000000�00000001504�10461020230�0014132�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::io::Write; use std::{io, panic}; use windows_sys::Win32::UI::WindowsAndMessaging::{ MessageBoxW, MB_ICONERROR, MB_OK, MB_SETFOREGROUND, MB_TASKMODAL, }; use alacritty_terminal::tty::windows::win32_string; // Install a panic handler that renders the panic in a classical Windows error // dialog box as well as writes the panic to STDERR. pub fn attach_handler() { panic::set_hook(Box::new(|panic_info| { let _ = writeln!(io::stderr(), "{}", panic_info); let msg = format!("{}\n\nPress Ctrl-C to Copy", panic_info); unsafe { MessageBoxW( 0isize, win32_string(&msg).as_ptr(), win32_string("Alacritty: Runtime Error").as_ptr(), MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_TASKMODAL, ); } })); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/mod.rs����������������������������������������������������������������0000644�0000000�0000000�00000027072�10461020230�0015435�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::borrow::Cow; use std::collections::HashSet; use std::ffi::{CStr, CString}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::OnceLock; use std::{fmt, ptr}; use ahash::RandomState; use crossfont::Metrics; use glutin::context::{ContextApi, GlContext, PossiblyCurrentContext}; use glutin::display::{GetGlDisplay, GlDisplay}; use log::{debug, error, info, warn, LevelFilter}; use unicode_width::UnicodeWidthChar; use alacritty_terminal::index::Point; use alacritty_terminal::term::cell::Flags; use crate::config::debug::RendererPreference; use crate::display::color::Rgb; use crate::display::content::RenderableCell; use crate::display::SizeInfo; use crate::gl; use crate::renderer::rects::{RectRenderer, RenderRect}; use crate::renderer::shader::ShaderError; pub mod platform; pub mod rects; mod shader; mod text; pub use text::{GlyphCache, LoaderApi}; use shader::ShaderVersion; use text::{Gles2Renderer, Glsl3Renderer, TextRenderer}; macro_rules! cstr { ($s:literal) => { // This can be optimized into an no-op with pre-allocated NUL-terminated bytes. unsafe { std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr().cast()) } }; } pub(crate) use cstr; /// Whether the OpenGL functions have been loaded. pub static GL_FUNS_LOADED: AtomicBool = AtomicBool::new(false); #[derive(Debug)] pub enum Error { /// Shader error. Shader(ShaderError), /// Other error. Other(String), } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Error::Shader(err) => err.source(), Error::Other(_) => None, } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::Shader(err) => { write!(f, "There was an error initializing the shaders: {}", err) }, Error::Other(err) => { write!(f, "{}", err) }, } } } impl From<ShaderError> for Error { fn from(val: ShaderError) -> Self { Error::Shader(val) } } impl From<String> for Error { fn from(val: String) -> Self { Error::Other(val) } } #[derive(Debug)] enum TextRendererProvider { Gles2(Gles2Renderer), Glsl3(Glsl3Renderer), } #[derive(Debug)] pub struct Renderer { text_renderer: TextRendererProvider, rect_renderer: RectRenderer, } /// Wrapper around gl::GetString with error checking and reporting. fn gl_get_string( string_id: gl::types::GLenum, description: &str, ) -> Result<Cow<'static, str>, Error> { unsafe { let string_ptr = gl::GetString(string_id); match gl::GetError() { gl::NO_ERROR if !string_ptr.is_null() => { Ok(CStr::from_ptr(string_ptr as *const _).to_string_lossy()) }, gl::INVALID_ENUM => { Err(format!("OpenGL error requesting {}: invalid enum", description).into()) }, error_id => Err(format!("OpenGL error {} requesting {}", error_id, description).into()), } } } impl Renderer { /// Create a new renderer. /// /// This will automatically pick between the GLES2 and GLSL3 renderer based on the GPU's /// supported OpenGL version. pub fn new( context: &PossiblyCurrentContext, renderer_preference: Option<RendererPreference>, ) -> Result<Self, Error> { // We need to load OpenGL functions once per instance, but only after we make our context // current due to WGL limitations. if !GL_FUNS_LOADED.swap(true, Ordering::Relaxed) { let gl_display = context.display(); gl::load_with(|symbol| { let symbol = CString::new(symbol).unwrap(); gl_display.get_proc_address(symbol.as_c_str()).cast() }); } let shader_version = gl_get_string(gl::SHADING_LANGUAGE_VERSION, "shader version")?; let gl_version = gl_get_string(gl::VERSION, "OpenGL version")?; let renderer = gl_get_string(gl::RENDERER, "renderer version")?; info!("Running on {renderer}"); info!("OpenGL version {gl_version}, shader_version {shader_version}"); let is_gles_context = matches!(context.context_api(), ContextApi::Gles(_)); // Use the config option to enforce a particular renderer configuration. let (use_glsl3, allow_dsb) = match renderer_preference { Some(RendererPreference::Glsl3) => (true, true), Some(RendererPreference::Gles2) => (false, true), Some(RendererPreference::Gles2Pure) => (false, false), None => (shader_version.as_ref() >= "3.3" && !is_gles_context, true), }; let (text_renderer, rect_renderer) = if use_glsl3 { let text_renderer = TextRendererProvider::Glsl3(Glsl3Renderer::new()?); let rect_renderer = RectRenderer::new(ShaderVersion::Glsl3)?; (text_renderer, rect_renderer) } else { let text_renderer = TextRendererProvider::Gles2(Gles2Renderer::new(allow_dsb, is_gles_context)?); let rect_renderer = RectRenderer::new(ShaderVersion::Gles2)?; (text_renderer, rect_renderer) }; // Enable debug logging for OpenGL as well. if log::max_level() >= LevelFilter::Debug && GlExtensions::contains("GL_KHR_debug") { debug!("Enabled debug logging for OpenGL"); unsafe { gl::Enable(gl::DEBUG_OUTPUT); gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS); gl::DebugMessageCallback(Some(gl_debug_log), ptr::null_mut()); } } Ok(Self { text_renderer, rect_renderer }) } pub fn draw_cells<I: Iterator<Item = RenderableCell>>( &mut self, size_info: &SizeInfo, glyph_cache: &mut GlyphCache, cells: I, ) { match &mut self.text_renderer { TextRendererProvider::Gles2(renderer) => { renderer.draw_cells(size_info, glyph_cache, cells) }, TextRendererProvider::Glsl3(renderer) => { renderer.draw_cells(size_info, glyph_cache, cells) }, } } /// Draw a string in a variable location. Used for printing the render timer, warnings and /// errors. pub fn draw_string( &mut self, point: Point<usize>, fg: Rgb, bg: Rgb, string_chars: impl Iterator<Item = char>, size_info: &SizeInfo, glyph_cache: &mut GlyphCache, ) { let mut skip_next = false; let cells = string_chars.enumerate().filter_map(|(i, character)| { if skip_next { skip_next = false; return None; } let mut flags = Flags::empty(); if character.width() == Some(2) { flags.insert(Flags::WIDE_CHAR); // Wide character is always followed by a spacer, so skip it. skip_next = true; } Some(RenderableCell { point: Point::new(point.line, point.column + i), character, extra: None, flags: Flags::empty(), bg_alpha: 1.0, fg, bg, underline: fg, }) }); self.draw_cells(size_info, glyph_cache, cells); } pub fn with_loader<F, T>(&mut self, func: F) -> T where F: FnOnce(LoaderApi<'_>) -> T, { match &mut self.text_renderer { TextRendererProvider::Gles2(renderer) => renderer.with_loader(func), TextRendererProvider::Glsl3(renderer) => renderer.with_loader(func), } } /// Draw all rectangles simultaneously to prevent excessive program swaps. pub fn draw_rects(&mut self, size_info: &SizeInfo, metrics: &Metrics, rects: Vec<RenderRect>) { if rects.is_empty() { return; } // Prepare rect rendering state. unsafe { // Remove padding from viewport. gl::Viewport(0, 0, size_info.width() as i32, size_info.height() as i32); gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::SRC_ALPHA, gl::ONE); } self.rect_renderer.draw(size_info, metrics, rects); // Activate regular state again. unsafe { // Reset blending strategy. gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR); // Restore viewport with padding. self.set_viewport(size_info); } } /// Fill the window with `color` and `alpha`. pub fn clear(&self, color: Rgb, alpha: f32) { unsafe { gl::ClearColor( (f32::from(color.r) / 255.0).min(1.0) * alpha, (f32::from(color.g) / 255.0).min(1.0) * alpha, (f32::from(color.b) / 255.0).min(1.0) * alpha, alpha, ); gl::Clear(gl::COLOR_BUFFER_BIT); } } pub fn finish(&self) { unsafe { gl::Finish(); } } /// Set the viewport for cell rendering. #[inline] pub fn set_viewport(&self, size: &SizeInfo) { unsafe { gl::Viewport( size.padding_x() as i32, size.padding_y() as i32, size.width() as i32 - 2 * size.padding_x() as i32, size.height() as i32 - 2 * size.padding_y() as i32, ); } } /// Resize the renderer. pub fn resize(&self, size_info: &SizeInfo) { self.set_viewport(size_info); match &self.text_renderer { TextRendererProvider::Gles2(renderer) => renderer.resize(size_info), TextRendererProvider::Glsl3(renderer) => renderer.resize(size_info), } } } struct GlExtensions; impl GlExtensions { /// Check if the given `extension` is supported. /// /// This function will lazily load OpenGL extensions. fn contains(extension: &str) -> bool { static OPENGL_EXTENSIONS: OnceLock<HashSet<&'static str, RandomState>> = OnceLock::new(); OPENGL_EXTENSIONS.get_or_init(Self::load_extensions).contains(extension) } /// Load available OpenGL extensions. fn load_extensions() -> HashSet<&'static str, RandomState> { unsafe { let extensions = gl::GetString(gl::EXTENSIONS); if extensions.is_null() { let mut extensions_number = 0; gl::GetIntegerv(gl::NUM_EXTENSIONS, &mut extensions_number); (0..extensions_number as gl::types::GLuint) .flat_map(|i| { let extension = CStr::from_ptr(gl::GetStringi(gl::EXTENSIONS, i) as *mut _); extension.to_str() }) .collect() } else { match CStr::from_ptr(extensions as *mut _).to_str() { Ok(ext) => ext.split_whitespace().collect(), Err(_) => Default::default(), } } } } } extern "system" fn gl_debug_log( _: gl::types::GLenum, kind: gl::types::GLenum, _: gl::types::GLuint, _: gl::types::GLenum, _: gl::types::GLsizei, msg: *const gl::types::GLchar, _: *mut std::os::raw::c_void, ) { let msg = unsafe { CStr::from_ptr(msg).to_string_lossy() }; match kind { gl::DEBUG_TYPE_ERROR | gl::DEBUG_TYPE_UNDEFINED_BEHAVIOR => { error!("[gl_render] {}", msg) }, gl::DEBUG_TYPE_DEPRECATED_BEHAVIOR => warn!("[gl_render] {}", msg), _ => debug!("[gl_render] {}", msg), } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/platform.rs�����������������������������������������������������������0000644�0000000�0000000�00000012547�10461020230�0016503�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! The graphics platform that is used by the renderer. use std::num::NonZeroU32; use glutin::config::{ColorBufferType, Config, ConfigTemplateBuilder, GetGlConfig}; use glutin::context::{ ContextApi, ContextAttributesBuilder, GlProfile, NotCurrentContext, Version, }; use glutin::display::{Display, DisplayApiPreference, GetGlDisplay}; use glutin::error::Result as GlutinResult; use glutin::prelude::*; use glutin::surface::{Surface, SurfaceAttributesBuilder, WindowSurface}; use log::{debug, LevelFilter}; use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; use winit::dpi::PhysicalSize; #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] use winit::platform::x11; /// Create the GL display. pub fn create_gl_display( raw_display_handle: RawDisplayHandle, _raw_window_handle: Option<RawWindowHandle>, _prefer_egl: bool, ) -> GlutinResult<Display> { #[cfg(target_os = "macos")] let preference = DisplayApiPreference::Cgl; #[cfg(windows)] let preference = if _prefer_egl { DisplayApiPreference::EglThenWgl(Some(_raw_window_handle.unwrap())) } else { DisplayApiPreference::WglThenEgl(Some(_raw_window_handle.unwrap())) }; #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] let preference = if _prefer_egl { DisplayApiPreference::EglThenGlx(Box::new(x11::register_xlib_error_hook)) } else { DisplayApiPreference::GlxThenEgl(Box::new(x11::register_xlib_error_hook)) }; #[cfg(all(not(feature = "x11"), not(any(target_os = "macos", windows))))] let preference = DisplayApiPreference::Egl; let display = unsafe { Display::new(raw_display_handle, preference)? }; log::info!("Using {}", { display.version_string() }); Ok(display) } pub fn pick_gl_config( gl_display: &Display, raw_window_handle: Option<RawWindowHandle>, ) -> Result<Config, String> { let mut default_config = ConfigTemplateBuilder::new() .with_depth_size(0) .with_stencil_size(0) .with_transparency(true); if let Some(raw_window_handle) = raw_window_handle { default_config = default_config.compatible_with_native_window(raw_window_handle); } let config_10bit = default_config .clone() .with_buffer_type(ColorBufferType::Rgb { r_size: 10, g_size: 10, b_size: 10 }) .with_alpha_size(2); let configs = [ default_config.clone(), config_10bit.clone(), default_config.with_transparency(false), config_10bit.with_transparency(false), ]; for config in configs { let gl_config = unsafe { gl_display.find_configs(config.build()).ok().and_then(|mut configs| configs.next()) }; if let Some(gl_config) = gl_config { debug!( r#"Picked GL Config: buffer_type: {:?} alpha_size: {} num_samples: {} hardware_accelerated: {:?} supports_transparency: {:?} config_api: {:?} srgb_capable: {}"#, gl_config.color_buffer_type(), gl_config.alpha_size(), gl_config.num_samples(), gl_config.hardware_accelerated(), gl_config.supports_transparency(), gl_config.api(), gl_config.srgb_capable(), ); return Ok(gl_config); } } Err(String::from("failed to find suitable GL configuration.")) } pub fn create_gl_context( gl_display: &Display, gl_config: &Config, raw_window_handle: Option<RawWindowHandle>, ) -> GlutinResult<NotCurrentContext> { let debug = log::max_level() >= LevelFilter::Debug; let mut profiles = [ ContextAttributesBuilder::new() .with_debug(debug) .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 3)))) .build(raw_window_handle), // Try gles before OpenGL 2.1 as it tends to be more stable. ContextAttributesBuilder::new() .with_debug(debug) .with_context_api(ContextApi::Gles(Some(Version::new(2, 0)))) .build(raw_window_handle), ContextAttributesBuilder::new() .with_debug(debug) .with_profile(GlProfile::Compatibility) .with_context_api(ContextApi::OpenGl(Some(Version::new(2, 1)))) .build(raw_window_handle), ] .into_iter(); // Try the optimal config first. let mut picked_context = unsafe { gl_display.create_context(gl_config, &profiles.next().unwrap()) }; // Try the fallback ones. while let (Err(_), Some(profile)) = (picked_context.as_ref(), profiles.next()) { picked_context = unsafe { gl_display.create_context(gl_config, &profile) }; } picked_context } pub fn create_gl_surface( gl_context: &NotCurrentContext, size: PhysicalSize<u32>, raw_window_handle: RawWindowHandle, ) -> GlutinResult<Surface<WindowSurface>> { // Get the display and the config used to create that context. let gl_display = gl_context.display(); let gl_config = gl_context.config(); let surface_attributes = SurfaceAttributesBuilder::<WindowSurface>::new().with_srgb(Some(false)).build( raw_window_handle, NonZeroU32::new(size.width).unwrap(), NonZeroU32::new(size.height).unwrap(), ); // Create the GL surface to draw into. unsafe { gl_display.create_window_surface(&gl_config, &surface_attributes) } } ���������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/rects.rs��������������������������������������������������������������0000644�0000000�0000000�00000040400�10461020230�0015764�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::collections::HashMap; use std::mem; use ahash::RandomState; use crossfont::Metrics; use log::info; use alacritty_terminal::grid::Dimensions; use alacritty_terminal::index::{Column, Point}; use alacritty_terminal::term::cell::Flags; use crate::display::color::Rgb; use crate::display::content::RenderableCell; use crate::display::SizeInfo; use crate::gl; use crate::gl::types::*; use crate::renderer::shader::{ShaderError, ShaderProgram, ShaderVersion}; use crate::renderer::{self, cstr}; #[derive(Debug, Copy, Clone)] pub struct RenderRect { pub x: f32, pub y: f32, pub width: f32, pub height: f32, pub color: Rgb, pub alpha: f32, pub kind: RectKind, } impl RenderRect { pub fn new(x: f32, y: f32, width: f32, height: f32, color: Rgb, alpha: f32) -> Self { RenderRect { kind: RectKind::Normal, x, y, width, height, color, alpha } } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct RenderLine { pub start: Point<usize>, pub end: Point<usize>, pub color: Rgb, } // NOTE: These flags must be in sync with their usage in the rect.*.glsl shaders. #[repr(u8)] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum RectKind { Normal = 0, Undercurl = 1, DottedUnderline = 2, DashedUnderline = 3, NumKinds = 4, } impl RenderLine { pub fn rects(&self, flag: Flags, metrics: &Metrics, size: &SizeInfo) -> Vec<RenderRect> { let mut rects = Vec::new(); let mut start = self.start; while start.line < self.end.line { let end = Point::new(start.line, size.last_column()); Self::push_rects(&mut rects, metrics, size, flag, start, end, self.color); start = Point::new(start.line + 1, Column(0)); } Self::push_rects(&mut rects, metrics, size, flag, start, self.end, self.color); rects } /// Push all rects required to draw the cell's line. fn push_rects( rects: &mut Vec<RenderRect>, metrics: &Metrics, size: &SizeInfo, flag: Flags, start: Point<usize>, end: Point<usize>, color: Rgb, ) { let (position, thickness, ty) = match flag { Flags::DOUBLE_UNDERLINE => { // Position underlines so each one has 50% of descent available. let top_pos = 0.25 * metrics.descent; let bottom_pos = 0.75 * metrics.descent; rects.push(Self::create_rect( size, metrics.descent, start, end, top_pos, metrics.underline_thickness, color, )); (bottom_pos, metrics.underline_thickness, RectKind::Normal) }, // Make undercurl occupy the entire descent area. Flags::UNDERCURL => (metrics.descent, metrics.descent.abs(), RectKind::Undercurl), Flags::UNDERLINE => { (metrics.underline_position, metrics.underline_thickness, RectKind::Normal) }, // Make dotted occupy the entire descent area. Flags::DOTTED_UNDERLINE => { (metrics.descent, metrics.descent.abs(), RectKind::DottedUnderline) }, Flags::DASHED_UNDERLINE => { (metrics.underline_position, metrics.underline_thickness, RectKind::DashedUnderline) }, Flags::STRIKEOUT => { (metrics.strikeout_position, metrics.strikeout_thickness, RectKind::Normal) }, _ => unimplemented!("Invalid flag for cell line drawing specified"), }; let mut rect = Self::create_rect(size, metrics.descent, start, end, position, thickness, color); rect.kind = ty; rects.push(rect); } /// Create a line's rect at a position relative to the baseline. fn create_rect( size: &SizeInfo, descent: f32, start: Point<usize>, end: Point<usize>, position: f32, mut thickness: f32, color: Rgb, ) -> RenderRect { let start_x = start.column.0 as f32 * size.cell_width(); let end_x = (end.column.0 + 1) as f32 * size.cell_width(); let width = end_x - start_x; // Make sure lines are always visible. thickness = thickness.max(1.); let line_bottom = (start.line as f32 + 1.) * size.cell_height(); let baseline = line_bottom + descent; let mut y = (baseline - position - thickness / 2.).round(); let max_y = line_bottom - thickness; if y > max_y { y = max_y; } RenderRect::new( start_x + size.padding_x(), y + size.padding_y(), width, thickness, color, 1., ) } } /// Lines for underline and strikeout. #[derive(Default)] pub struct RenderLines { inner: HashMap<Flags, Vec<RenderLine>, RandomState>, } impl RenderLines { #[inline] pub fn new() -> Self { Self::default() } #[inline] pub fn rects(&self, metrics: &Metrics, size: &SizeInfo) -> Vec<RenderRect> { self.inner .iter() .flat_map(|(flag, lines)| { lines.iter().flat_map(move |line| line.rects(*flag, metrics, size)) }) .collect() } /// Update the stored lines with the next cell info. #[inline] pub fn update(&mut self, cell: &RenderableCell) { self.update_flag(cell, Flags::UNDERLINE); self.update_flag(cell, Flags::DOUBLE_UNDERLINE); self.update_flag(cell, Flags::STRIKEOUT); self.update_flag(cell, Flags::UNDERCURL); self.update_flag(cell, Flags::DOTTED_UNDERLINE); self.update_flag(cell, Flags::DASHED_UNDERLINE); } /// Update the lines for a specific flag. fn update_flag(&mut self, cell: &RenderableCell, flag: Flags) { if !cell.flags.contains(flag) { return; } // The underline color escape does not apply to strikeout. let color = if flag.contains(Flags::STRIKEOUT) { cell.fg } else { cell.underline }; // Include wide char spacer if the current cell is a wide char. let mut end = cell.point; if cell.flags.contains(Flags::WIDE_CHAR) { end.column += 1; } // Check if there's an active line. if let Some(line) = self.inner.get_mut(&flag).and_then(|lines| lines.last_mut()) { if color == line.color && cell.point.column == line.end.column + 1 && cell.point.line == line.end.line { // Update the length of the line. line.end = end; return; } } // Start new line if there currently is none. let line = RenderLine { start: cell.point, end, color }; match self.inner.get_mut(&flag) { Some(lines) => lines.push(line), None => { self.inner.insert(flag, vec![line]); }, } } } /// Shader sources for rect rendering program. static RECT_SHADER_F: &str = include_str!("../../res/rect.f.glsl"); static RECT_SHADER_V: &str = include_str!("../../res/rect.v.glsl"); #[repr(C)] #[derive(Debug, Clone, Copy)] struct Vertex { // Normalized screen coordinates. x: f32, y: f32, // Color. r: u8, g: u8, b: u8, a: u8, } #[derive(Debug)] pub struct RectRenderer { // GL buffer objects. vao: GLuint, vbo: GLuint, programs: [RectShaderProgram; 4], vertices: [Vec<Vertex>; 4], } impl RectRenderer { pub fn new(shader_version: ShaderVersion) -> Result<Self, renderer::Error> { let mut vao: GLuint = 0; let mut vbo: GLuint = 0; let rect_program = RectShaderProgram::new(shader_version, RectKind::Normal)?; let undercurl_program = RectShaderProgram::new(shader_version, RectKind::Undercurl)?; // This shader has way more ALU operations than other rect shaders, so use a fallback // to underline just for it when we can't compile it. let dotted_program = match RectShaderProgram::new(shader_version, RectKind::DottedUnderline) { Ok(dotted_program) => dotted_program, Err(err) => { info!("Error compiling dotted shader: {err}\n falling back to underline"); RectShaderProgram::new(shader_version, RectKind::Normal)? }, }; let dashed_program = RectShaderProgram::new(shader_version, RectKind::DashedUnderline)?; unsafe { // Allocate buffers. gl::GenVertexArrays(1, &mut vao); gl::GenBuffers(1, &mut vbo); gl::BindVertexArray(vao); // VBO binding is not part of VAO itself, but VBO binding is stored in attributes. gl::BindBuffer(gl::ARRAY_BUFFER, vbo); let mut attribute_offset = 0; // Position. gl::VertexAttribPointer( 0, 2, gl::FLOAT, gl::FALSE, mem::size_of::<Vertex>() as i32, attribute_offset as *const _, ); gl::EnableVertexAttribArray(0); attribute_offset += mem::size_of::<f32>() * 2; // Color. gl::VertexAttribPointer( 1, 4, gl::UNSIGNED_BYTE, gl::TRUE, mem::size_of::<Vertex>() as i32, attribute_offset as *const _, ); gl::EnableVertexAttribArray(1); // Reset buffer bindings. gl::BindVertexArray(0); gl::BindBuffer(gl::ARRAY_BUFFER, 0); } let programs = [rect_program, undercurl_program, dotted_program, dashed_program]; Ok(Self { vao, vbo, programs, vertices: Default::default() }) } pub fn draw(&mut self, size_info: &SizeInfo, metrics: &Metrics, rects: Vec<RenderRect>) { unsafe { // Bind VAO to enable vertex attribute slots. gl::BindVertexArray(self.vao); // Bind VBO only once for buffer data upload only. gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo); } let half_width = size_info.width() / 2.; let half_height = size_info.height() / 2.; // Build rect vertices vector. self.vertices.iter_mut().for_each(|vertices| vertices.clear()); for rect in &rects { Self::add_rect(&mut self.vertices[rect.kind as usize], half_width, half_height, rect); } unsafe { // We iterate in reverse order to draw plain rects at the end, since we want visual // bell or damage rects be above the lines. for rect_kind in (RectKind::Normal as u8..RectKind::NumKinds as u8).rev() { let vertices = &mut self.vertices[rect_kind as usize]; if vertices.is_empty() { continue; } let program = &self.programs[rect_kind as usize]; gl::UseProgram(program.id()); program.update_uniforms(size_info, metrics); // Upload accumulated undercurl vertices. gl::BufferData( gl::ARRAY_BUFFER, (vertices.len() * mem::size_of::<Vertex>()) as isize, vertices.as_ptr() as *const _, gl::STREAM_DRAW, ); // Draw all vertices as list of triangles. gl::DrawArrays(gl::TRIANGLES, 0, vertices.len() as i32); } // Disable program. gl::UseProgram(0); // Reset buffer bindings to nothing. gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindVertexArray(0); } } fn add_rect(vertices: &mut Vec<Vertex>, half_width: f32, half_height: f32, rect: &RenderRect) { // Calculate rectangle vertices positions in normalized device coordinates. // NDC range from -1 to +1, with Y pointing up. let x = rect.x / half_width - 1.0; let y = -rect.y / half_height + 1.0; let width = rect.width / half_width; let height = rect.height / half_height; let (r, g, b) = rect.color.as_tuple(); let a = (rect.alpha * 255.) as u8; // Make quad vertices. let quad = [ Vertex { x, y, r, g, b, a }, Vertex { x, y: y - height, r, g, b, a }, Vertex { x: x + width, y, r, g, b, a }, Vertex { x: x + width, y: y - height, r, g, b, a }, ]; // Append the vertices to form two triangles. vertices.push(quad[0]); vertices.push(quad[1]); vertices.push(quad[2]); vertices.push(quad[2]); vertices.push(quad[3]); vertices.push(quad[1]); } } impl Drop for RectRenderer { fn drop(&mut self) { unsafe { gl::DeleteBuffers(1, &self.vbo); gl::DeleteVertexArrays(1, &self.vao); } } } /// Rectangle drawing program. #[derive(Debug)] pub struct RectShaderProgram { /// Shader program. program: ShaderProgram, /// Cell width. u_cell_width: Option<GLint>, /// Cell height. u_cell_height: Option<GLint>, /// Terminal padding. u_padding_x: Option<GLint>, /// A padding from the bottom of the screen to viewport. u_padding_y: Option<GLint>, /// Underline position. u_underline_position: Option<GLint>, /// Underline thickness. u_underline_thickness: Option<GLint>, /// Undercurl position. u_undercurl_position: Option<GLint>, } impl RectShaderProgram { pub fn new(shader_version: ShaderVersion, kind: RectKind) -> Result<Self, ShaderError> { // XXX: This must be in-sync with fragment shader defines. let header = match kind { RectKind::Undercurl => Some("#define DRAW_UNDERCURL\n"), RectKind::DottedUnderline => Some("#define DRAW_DOTTED\n"), RectKind::DashedUnderline => Some("#define DRAW_DASHED\n"), _ => None, }; let program = ShaderProgram::new(shader_version, header, RECT_SHADER_V, RECT_SHADER_F)?; Ok(Self { u_cell_width: program.get_uniform_location(cstr!("cellWidth")).ok(), u_cell_height: program.get_uniform_location(cstr!("cellHeight")).ok(), u_padding_x: program.get_uniform_location(cstr!("paddingX")).ok(), u_padding_y: program.get_uniform_location(cstr!("paddingY")).ok(), u_underline_position: program.get_uniform_location(cstr!("underlinePosition")).ok(), u_underline_thickness: program.get_uniform_location(cstr!("underlineThickness")).ok(), u_undercurl_position: program.get_uniform_location(cstr!("undercurlPosition")).ok(), program, }) } fn id(&self) -> GLuint { self.program.id() } pub fn update_uniforms(&self, size_info: &SizeInfo, metrics: &Metrics) { let position = (0.5 * metrics.descent).abs(); let underline_position = metrics.descent.abs() - metrics.underline_position.abs(); let viewport_height = size_info.height() - size_info.padding_y(); let padding_y = viewport_height - (viewport_height / size_info.cell_height()).floor() * size_info.cell_height(); unsafe { if let Some(u_cell_width) = self.u_cell_width { gl::Uniform1f(u_cell_width, size_info.cell_width()); } if let Some(u_cell_height) = self.u_cell_height { gl::Uniform1f(u_cell_height, size_info.cell_height()); } if let Some(u_padding_y) = self.u_padding_y { gl::Uniform1f(u_padding_y, padding_y); } if let Some(u_padding_x) = self.u_padding_x { gl::Uniform1f(u_padding_x, size_info.padding_x()); } if let Some(u_underline_position) = self.u_underline_position { gl::Uniform1f(u_underline_position, underline_position); } if let Some(u_underline_thickness) = self.u_underline_thickness { gl::Uniform1f(u_underline_thickness, metrics.underline_thickness); } if let Some(u_undercurl_position) = self.u_undercurl_position { gl::Uniform1f(u_undercurl_position, position); } } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/shader.rs�������������������������������������������������������������0000644�0000000�0000000�00000013143�10461020230�0016116�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::ffi::CStr; use std::fmt; use crate::gl; use crate::gl::types::*; /// A wrapper for a shader program id, with automatic lifetime management. #[derive(Debug)] pub struct ShaderProgram(GLuint); #[derive(Copy, Clone, Debug)] pub enum ShaderVersion { /// OpenGL 3.3 core shaders. Glsl3, /// OpenGL ES 2.0 shaders. Gles2, } impl ShaderVersion { // Header to which we concatenate the entire shader. The newlines are required. fn shader_header(&self) -> &'static str { match self { Self::Glsl3 => "#version 330 core\n", Self::Gles2 => "#version 100\n#define GLES2_RENDERER\n", } } } impl ShaderProgram { pub fn new( shader_version: ShaderVersion, shader_header: Option<&str>, vertex_shader: &'static str, fragment_shader: &'static str, ) -> Result<Self, ShaderError> { let vertex_shader = Shader::new(shader_version, shader_header, gl::VERTEX_SHADER, vertex_shader)?; let fragment_shader = Shader::new(shader_version, shader_header, gl::FRAGMENT_SHADER, fragment_shader)?; let program = unsafe { Self(gl::CreateProgram()) }; let mut success: GLint = 0; unsafe { gl::AttachShader(program.id(), vertex_shader.id()); gl::AttachShader(program.id(), fragment_shader.id()); gl::LinkProgram(program.id()); gl::GetProgramiv(program.id(), gl::LINK_STATUS, &mut success); } if success != i32::from(gl::TRUE) { return Err(ShaderError::Link(get_program_info_log(program.id()))); } Ok(program) } /// Get uniform location by name. Panic if failed. pub fn get_uniform_location(&self, name: &'static CStr) -> Result<GLint, ShaderError> { // This call doesn't require `UseProgram`. let ret = unsafe { gl::GetUniformLocation(self.id(), name.as_ptr()) }; if ret == -1 { return Err(ShaderError::Uniform(name)); } Ok(ret) } /// Get the shader program id. pub fn id(&self) -> GLuint { self.0 } } impl Drop for ShaderProgram { fn drop(&mut self) { unsafe { gl::DeleteProgram(self.0) } } } /// A wrapper for a shader id, with automatic lifetime management. #[derive(Debug)] struct Shader(GLuint); impl Shader { fn new( shader_version: ShaderVersion, shader_header: Option<&str>, kind: GLenum, source: &'static str, ) -> Result<Self, ShaderError> { let version_header = shader_version.shader_header(); let mut sources = Vec::<*const GLchar>::with_capacity(3); let mut lengths = Vec::<GLint>::with_capacity(3); sources.push(version_header.as_ptr().cast()); lengths.push(version_header.len() as GLint); if let Some(shader_header) = shader_header { sources.push(shader_header.as_ptr().cast()); lengths.push(shader_header.len() as GLint); } sources.push(source.as_ptr().cast()); lengths.push(source.len() as GLint); let shader = unsafe { Self(gl::CreateShader(kind)) }; let mut success: GLint = 0; unsafe { gl::ShaderSource( shader.id(), lengths.len() as GLint, sources.as_ptr().cast(), lengths.as_ptr(), ); gl::CompileShader(shader.id()); gl::GetShaderiv(shader.id(), gl::COMPILE_STATUS, &mut success); } if success == GLint::from(gl::TRUE) { Ok(shader) } else { Err(ShaderError::Compile(get_shader_info_log(shader.id()))) } } fn id(&self) -> GLuint { self.0 } } impl Drop for Shader { fn drop(&mut self) { unsafe { gl::DeleteShader(self.0) } } } fn get_program_info_log(program: GLuint) -> String { // Get expected log length. let mut max_length: GLint = 0; unsafe { gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut max_length); } // Read the info log. let mut actual_length: GLint = 0; let mut buf: Vec<u8> = Vec::with_capacity(max_length as usize); unsafe { gl::GetProgramInfoLog(program, max_length, &mut actual_length, buf.as_mut_ptr() as *mut _); } // Build a string. unsafe { buf.set_len(actual_length as usize); } String::from_utf8_lossy(&buf).to_string() } fn get_shader_info_log(shader: GLuint) -> String { // Get expected log length. let mut max_length: GLint = 0; unsafe { gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut max_length); } // Read the info log. let mut actual_length: GLint = 0; let mut buf: Vec<u8> = Vec::with_capacity(max_length as usize); unsafe { gl::GetShaderInfoLog(shader, max_length, &mut actual_length, buf.as_mut_ptr() as *mut _); } // Build a string. unsafe { buf.set_len(actual_length as usize); } String::from_utf8_lossy(&buf).to_string() } #[derive(Debug)] pub enum ShaderError { /// Error compiling shader. Compile(String), /// Error linking shader. Link(String), /// Error getting uniform location. Uniform(&'static CStr), } impl std::error::Error for ShaderError {} impl fmt::Display for ShaderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::Compile(reason) => write!(f, "Failed compiling shader: {}", reason), Self::Link(reason) => write!(f, "Failed linking shader: {}", reason), Self::Uniform(name) => write!(f, "Failed to get uniform location of {:?}", name), } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/text/atlas.rs���������������������������������������������������������0000644�0000000�0000000�00000023226�10461020230�0016743�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::borrow::Cow; use std::ptr; use crossfont::{BitmapBuffer, RasterizedGlyph}; use crate::gl; use crate::gl::types::*; use super::Glyph; /// Size of the Atlas. pub const ATLAS_SIZE: i32 = 1024; /// Manages a single texture atlas. /// /// The strategy for filling an atlas looks roughly like this: /// /// ```text /// (width, height) /// ┌─────┬─────┬─────┬─────┬─────┐ /// │ 10 │ │ │ │ │ <- Empty spaces; can be filled while /// │ │ │ │ │ │ glyph_height < height - row_baseline /// ├─────┼─────┼─────┼─────┼─────┤ /// │ 5 │ 6 │ 7 │ 8 │ 9 │ /// │ │ │ │ │ │ /// ├─────┼─────┼─────┼─────┴─────┤ <- Row height is tallest glyph in row; this is /// │ 1 │ 2 │ 3 │ 4 │ used as the baseline for the following row. /// │ │ │ │ │ <- Row considered full when next glyph doesn't /// └─────┴─────┴─────┴───────────┘ fit in the row. /// (0, 0) x-> /// ``` #[derive(Debug)] pub struct Atlas { /// Texture id for this atlas. id: GLuint, /// Width of atlas. width: i32, /// Height of atlas. height: i32, /// Left-most free pixel in a row. /// /// This is called the extent because it is the upper bound of used pixels /// in a row. row_extent: i32, /// Baseline for glyphs in the current row. row_baseline: i32, /// Tallest glyph in current row. /// /// This is used as the advance when end of row is reached. row_tallest: i32, /// Gles context. /// /// This affects the texture loading. is_gles_context: bool, } /// Error that can happen when inserting a texture to the Atlas. pub enum AtlasInsertError { /// Texture atlas is full. Full, /// The glyph cannot fit within a single texture. GlyphTooLarge, } impl Atlas { pub fn new(size: i32, is_gles_context: bool) -> Self { let mut id: GLuint = 0; unsafe { gl::PixelStorei(gl::UNPACK_ALIGNMENT, 1); gl::GenTextures(1, &mut id); gl::BindTexture(gl::TEXTURE_2D, id); // Use RGBA texture for both normal and emoji glyphs, since it has no performance // impact. gl::TexImage2D( gl::TEXTURE_2D, 0, gl::RGBA as i32, size, size, 0, gl::RGBA, gl::UNSIGNED_BYTE, ptr::null(), ); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::LINEAR as i32); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as i32); gl::BindTexture(gl::TEXTURE_2D, 0); } Self { id, width: size, height: size, row_extent: 0, row_baseline: 0, row_tallest: 0, is_gles_context, } } pub fn clear(&mut self) { self.row_extent = 0; self.row_baseline = 0; self.row_tallest = 0; } /// Insert a RasterizedGlyph into the texture atlas. pub fn insert( &mut self, glyph: &RasterizedGlyph, active_tex: &mut u32, ) -> Result<Glyph, AtlasInsertError> { if glyph.width > self.width || glyph.height > self.height { return Err(AtlasInsertError::GlyphTooLarge); } // If there's not enough room in current row, go onto next one. if !self.room_in_row(glyph) { self.advance_row()?; } // If there's still not room, there's nothing that can be done here.. if !self.room_in_row(glyph) { return Err(AtlasInsertError::Full); } // There appears to be room; load the glyph. Ok(self.insert_inner(glyph, active_tex)) } /// Insert the glyph without checking for room. /// /// Internal function for use once atlas has been checked for space. GL /// errors could still occur at this point if we were checking for them; /// hence, the Result. fn insert_inner(&mut self, glyph: &RasterizedGlyph, active_tex: &mut u32) -> Glyph { let offset_y = self.row_baseline; let offset_x = self.row_extent; let height = glyph.height; let width = glyph.width; let multicolor; unsafe { gl::BindTexture(gl::TEXTURE_2D, self.id); // Load data into OpenGL. let (format, buffer) = match &glyph.buffer { BitmapBuffer::Rgb(buffer) => { multicolor = false; // Gles context doesn't allow uploading RGB data into RGBA texture, so need // explicit copy. if self.is_gles_context { let mut new_buffer = Vec::with_capacity(buffer.len() / 3 * 4); for rgb in buffer.chunks_exact(3) { new_buffer.push(rgb[0]); new_buffer.push(rgb[1]); new_buffer.push(rgb[2]); new_buffer.push(u8::MAX); } (gl::RGBA, Cow::Owned(new_buffer)) } else { (gl::RGB, Cow::Borrowed(buffer)) } }, BitmapBuffer::Rgba(buffer) => { multicolor = true; (gl::RGBA, Cow::Borrowed(buffer)) }, }; gl::TexSubImage2D( gl::TEXTURE_2D, 0, offset_x, offset_y, width, height, format, gl::UNSIGNED_BYTE, buffer.as_ptr() as *const _, ); gl::BindTexture(gl::TEXTURE_2D, 0); *active_tex = 0; } // Update Atlas state. self.row_extent = offset_x + width; if height > self.row_tallest { self.row_tallest = height; } // Generate UV coordinates. let uv_bot = offset_y as f32 / self.height as f32; let uv_left = offset_x as f32 / self.width as f32; let uv_height = height as f32 / self.height as f32; let uv_width = width as f32 / self.width as f32; Glyph { tex_id: self.id, multicolor, top: glyph.top as i16, left: glyph.left as i16, width: width as i16, height: height as i16, uv_bot, uv_left, uv_width, uv_height, } } /// Check if there's room in the current row for given glyph. pub fn room_in_row(&self, raw: &RasterizedGlyph) -> bool { let next_extent = self.row_extent + raw.width; let enough_width = next_extent <= self.width; let enough_height = raw.height < (self.height - self.row_baseline); enough_width && enough_height } /// Mark current row as finished and prepare to insert into the next row. pub fn advance_row(&mut self) -> Result<(), AtlasInsertError> { let advance_to = self.row_baseline + self.row_tallest; if self.height - advance_to <= 0 { return Err(AtlasInsertError::Full); } self.row_baseline = advance_to; self.row_extent = 0; self.row_tallest = 0; Ok(()) } /// Load a glyph into a texture atlas. /// /// If the current atlas is full, a new one will be created. #[inline] pub fn load_glyph( active_tex: &mut GLuint, atlas: &mut Vec<Atlas>, current_atlas: &mut usize, rasterized: &RasterizedGlyph, ) -> Glyph { // At least one atlas is guaranteed to be in the `self.atlas` list; thus // the unwrap. match atlas[*current_atlas].insert(rasterized, active_tex) { Ok(glyph) => glyph, Err(AtlasInsertError::Full) => { // Get the context type before adding a new Atlas. let is_gles_context = atlas[*current_atlas].is_gles_context; // Advance the current Atlas index. *current_atlas += 1; if *current_atlas == atlas.len() { let new = Atlas::new(ATLAS_SIZE, is_gles_context); *active_tex = 0; // Atlas::new binds a texture. Ugh this is sloppy. atlas.push(new); } Atlas::load_glyph(active_tex, atlas, current_atlas, rasterized) }, Err(AtlasInsertError::GlyphTooLarge) => Glyph { tex_id: atlas[*current_atlas].id, multicolor: false, top: 0, left: 0, width: 0, height: 0, uv_bot: 0., uv_left: 0., uv_width: 0., uv_height: 0., }, } } #[inline] pub fn clear_atlas(atlas: &mut [Atlas], current_atlas: &mut usize) { for atlas in atlas.iter_mut() { atlas.clear(); } *current_atlas = 0; } } impl Drop for Atlas { fn drop(&mut self) { unsafe { gl::DeleteTextures(1, &self.id); } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/text/builtin_font.rs��������������������������������������������������0000644�0000000�0000000�00000133207�10461020230�0020334�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Hand-rolled drawing of unicode characters that need to fully cover their character area. use std::{cmp, mem, ops}; use crossfont::{BitmapBuffer, Metrics, RasterizedGlyph}; use crate::config::ui_config::Delta; // Colors which are used for filling shade variants. const COLOR_FILL_ALPHA_STEP_1: Pixel = Pixel { _r: 192, _g: 192, _b: 192 }; const COLOR_FILL_ALPHA_STEP_2: Pixel = Pixel { _r: 128, _g: 128, _b: 128 }; const COLOR_FILL_ALPHA_STEP_3: Pixel = Pixel { _r: 64, _g: 64, _b: 64 }; /// Default color used for filling. const COLOR_FILL: Pixel = Pixel { _r: 255, _g: 255, _b: 255 }; const POWERLINE_TRIANGLE_LTR: char = '\u{e0b0}'; const POWERLINE_ARROW_LTR: char = '\u{e0b1}'; const POWERLINE_TRIANGLE_RTL: char = '\u{e0b2}'; const POWERLINE_ARROW_RTL: char = '\u{e0b3}'; /// Returns the rasterized glyph if the character is part of the built-in font. pub fn builtin_glyph( character: char, metrics: &Metrics, offset: &Delta<i8>, glyph_offset: &Delta<i8>, ) -> Option<RasterizedGlyph> { let mut glyph = match character { // Box drawing characters and block elements. '\u{2500}'..='\u{259f}' | '\u{1fb00}'..='\u{1fb3b}' => { box_drawing(character, metrics, offset) }, // Powerline symbols: '','','','' POWERLINE_TRIANGLE_LTR..=POWERLINE_ARROW_RTL => { powerline_drawing(character, metrics, offset)? }, _ => return None, }; // Since we want to ignore `glyph_offset` for the built-in font, subtract it to compensate its // addition when loading glyphs in the renderer. glyph.left -= glyph_offset.x as i32; glyph.top -= glyph_offset.y as i32; Some(glyph) } fn box_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> RasterizedGlyph { // Ensure that width and height is at least one. let height = (metrics.line_height as i32 + offset.y as i32).max(1) as usize; let width = (metrics.average_advance as i32 + offset.x as i32).max(1) as usize; let stroke_size = calculate_stroke_size(width); let heavy_stroke_size = stroke_size * 2; // Certain symbols require larger canvas than the cell itself, since for proper contiguous // lines they require drawing on neighbour cells. So treat them specially early on and handle // 'normal' characters later. let mut canvas = match character { // Diagonals: '╱', '╲', '╳'. '\u{2571}'..='\u{2573}' => { // Last coordinates. let x_end = width as f32; let mut y_end = height as f32; let top = height as i32 + metrics.descent as i32 + stroke_size as i32; let height = height + 2 * stroke_size; let mut canvas = Canvas::new(width, height + 2 * stroke_size); // The offset that we should take into account when drawing, since we've enlarged // buffer vertically by twice of that amount. let y_offset = stroke_size as f32; y_end += y_offset; let k = y_end / x_end; let f_x = |x: f32, h: f32| -> f32 { -1. * k * x + h + y_offset }; let g_x = |x: f32, h: f32| -> f32 { k * x + h + y_offset }; let from_x = 0.; let to_x = x_end + 1.; for stroke_size in 0..2 * stroke_size { let stroke_size = stroke_size as f32 / 2.; if character == '\u{2571}' || character == '\u{2573}' { let h = y_end - stroke_size; let from_y = f_x(from_x, h); let to_y = f_x(to_x, h); canvas.draw_line(from_x, from_y, to_x, to_y); } if character == '\u{2572}' || character == '\u{2573}' { let from_y = g_x(from_x, stroke_size); let to_y = g_x(to_x, stroke_size); canvas.draw_line(from_x, from_y, to_x, to_y); } } let buffer = BitmapBuffer::Rgb(canvas.into_raw()); return RasterizedGlyph { character, top, left: 0, height: height as i32, width: width as i32, buffer, advance: (width as i32, height as i32), }; }, _ => Canvas::new(width, height), }; match character { // Horizontal dashes: '┄', '┅', '┈', '┉', '╌', '╍'. '\u{2504}' | '\u{2505}' | '\u{2508}' | '\u{2509}' | '\u{254c}' | '\u{254d}' => { let (num_gaps, stroke_size) = match character { '\u{2504}' => (2, stroke_size), '\u{2505}' => (2, heavy_stroke_size), '\u{2508}' => (3, stroke_size), '\u{2509}' => (3, heavy_stroke_size), '\u{254c}' => (1, stroke_size), '\u{254d}' => (1, heavy_stroke_size), _ => unreachable!(), }; let dash_gap_len = cmp::max(width / 8, 1); let dash_len = cmp::max(width.saturating_sub(dash_gap_len * num_gaps) / (num_gaps + 1), 1); let y = canvas.y_center(); for gap in 0..=num_gaps { let x = cmp::min(gap * (dash_len + dash_gap_len), width); canvas.draw_h_line(x as f32, y, dash_len as f32, stroke_size); } }, // Vertical dashes: '┆', '┇', '┊', '┋', '╎', '╏'. '\u{2506}' | '\u{2507}' | '\u{250a}' | '\u{250b}' | '\u{254e}' | '\u{254f}' => { let (num_gaps, stroke_size) = match character { '\u{2506}' => (2, stroke_size), '\u{2507}' => (2, heavy_stroke_size), '\u{250a}' => (3, stroke_size), '\u{250b}' => (3, heavy_stroke_size), '\u{254e}' => (1, stroke_size), '\u{254f}' => (1, heavy_stroke_size), _ => unreachable!(), }; let dash_gap_len = cmp::max(height / 8, 1); let dash_len = cmp::max(height.saturating_sub(dash_gap_len * num_gaps) / (num_gaps + 1), 1); let x = canvas.x_center(); for gap in 0..=num_gaps { let y = cmp::min(gap * (dash_len + dash_gap_len), height); canvas.draw_v_line(x, y as f32, dash_len as f32, stroke_size); } }, // Horizontal lines: '─', '━', '╴', '╶', '╸', '╺'. // Vertical lines: '│', '┃', '╵', '╷', '╹', '╻'. // Light and heavy line box components: // '┌','┍','┎','┏','┐','┑','┒','┓','└','┕','┖','┗','┘','┙','┚','┛',├','┝','┞','┟','┠','┡', // '┢','┣','┤','┥','┦','┧','┨','┩','┪','┫','┬','┭','┮','┯','┰','┱','┲','┳','┴','┵','┶','┷', // '┸','┹','┺','┻','┼','┽','┾','┿','╀','╁','╂','╃','╄','╅','╆','╇','╈','╉','╊','╋'. // Mixed light and heavy lines: '╼', '╽', '╾', '╿'. '\u{2500}'..='\u{2503}' | '\u{250c}'..='\u{254b}' | '\u{2574}'..='\u{257f}' => { // Left horizontal line. let stroke_size_h1 = match character { '\u{2500}' | '\u{2510}' | '\u{2512}' | '\u{2518}' | '\u{251a}' | '\u{2524}' | '\u{2526}' | '\u{2527}' | '\u{2528}' | '\u{252c}' | '\u{252e}' | '\u{2530}' | '\u{2532}' | '\u{2534}' | '\u{2536}' | '\u{2538}' | '\u{253a}' | '\u{253c}' | '\u{253e}' | '\u{2540}' | '\u{2541}' | '\u{2542}' | '\u{2544}' | '\u{2546}' | '\u{254a}' | '\u{2574}' | '\u{257c}' => stroke_size, '\u{2501}' | '\u{2511}' | '\u{2513}' | '\u{2519}' | '\u{251b}' | '\u{2525}' | '\u{2529}' | '\u{252a}' | '\u{252b}' | '\u{252d}' | '\u{252f}' | '\u{2531}' | '\u{2533}' | '\u{2535}' | '\u{2537}' | '\u{2539}' | '\u{253b}' | '\u{253d}' | '\u{253f}' | '\u{2543}' | '\u{2545}' | '\u{2547}' | '\u{2548}' | '\u{2549}' | '\u{254b}' | '\u{2578}' | '\u{257e}' => heavy_stroke_size, _ => 0, }; // Right horizontal line. let stroke_size_h2 = match character { '\u{2500}' | '\u{250c}' | '\u{250e}' | '\u{2514}' | '\u{2516}' | '\u{251c}' | '\u{251e}' | '\u{251f}' | '\u{2520}' | '\u{252c}' | '\u{252d}' | '\u{2530}' | '\u{2531}' | '\u{2534}' | '\u{2535}' | '\u{2538}' | '\u{2539}' | '\u{253c}' | '\u{253d}' | '\u{2540}' | '\u{2541}' | '\u{2542}' | '\u{2543}' | '\u{2545}' | '\u{2549}' | '\u{2576}' | '\u{257e}' => stroke_size, '\u{2501}' | '\u{250d}' | '\u{250f}' | '\u{2515}' | '\u{2517}' | '\u{251d}' | '\u{2521}' | '\u{2522}' | '\u{2523}' | '\u{252e}' | '\u{252f}' | '\u{2532}' | '\u{2533}' | '\u{2536}' | '\u{2537}' | '\u{253a}' | '\u{253b}' | '\u{253e}' | '\u{253f}' | '\u{2544}' | '\u{2546}' | '\u{2547}' | '\u{2548}' | '\u{254a}' | '\u{254b}' | '\u{257a}' | '\u{257c}' => heavy_stroke_size, _ => 0, }; // Top vertical line. let stroke_size_v1 = match character { '\u{2502}' | '\u{2514}' | '\u{2515}' | '\u{2518}' | '\u{2519}' | '\u{251c}' | '\u{251d}' | '\u{251f}' | '\u{2522}' | '\u{2524}' | '\u{2525}' | '\u{2527}' | '\u{252a}' | '\u{2534}' | '\u{2535}' | '\u{2536}' | '\u{2537}' | '\u{253c}' | '\u{253d}' | '\u{253e}' | '\u{253f}' | '\u{2541}' | '\u{2545}' | '\u{2546}' | '\u{2548}' | '\u{2575}' | '\u{257d}' => stroke_size, '\u{2503}' | '\u{2516}' | '\u{2517}' | '\u{251a}' | '\u{251b}' | '\u{251e}' | '\u{2520}' | '\u{2521}' | '\u{2523}' | '\u{2526}' | '\u{2528}' | '\u{2529}' | '\u{252b}' | '\u{2538}' | '\u{2539}' | '\u{253a}' | '\u{253b}' | '\u{2540}' | '\u{2542}' | '\u{2543}' | '\u{2544}' | '\u{2547}' | '\u{2549}' | '\u{254a}' | '\u{254b}' | '\u{2579}' | '\u{257f}' => heavy_stroke_size, _ => 0, }; // Bottom vertical line. let stroke_size_v2 = match character { '\u{2502}' | '\u{250c}' | '\u{250d}' | '\u{2510}' | '\u{2511}' | '\u{251c}' | '\u{251d}' | '\u{251e}' | '\u{2521}' | '\u{2524}' | '\u{2525}' | '\u{2526}' | '\u{2529}' | '\u{252c}' | '\u{252d}' | '\u{252e}' | '\u{252f}' | '\u{253c}' | '\u{253d}' | '\u{253e}' | '\u{253f}' | '\u{2540}' | '\u{2543}' | '\u{2544}' | '\u{2547}' | '\u{2577}' | '\u{257f}' => stroke_size, '\u{2503}' | '\u{250e}' | '\u{250f}' | '\u{2512}' | '\u{2513}' | '\u{251f}' | '\u{2520}' | '\u{2522}' | '\u{2523}' | '\u{2527}' | '\u{2528}' | '\u{252a}' | '\u{252b}' | '\u{2530}' | '\u{2531}' | '\u{2532}' | '\u{2533}' | '\u{2541}' | '\u{2542}' | '\u{2545}' | '\u{2546}' | '\u{2548}' | '\u{2549}' | '\u{254a}' | '\u{254b}' | '\u{257b}' | '\u{257d}' => heavy_stroke_size, _ => 0, }; let x_v = canvas.x_center(); let y_h = canvas.y_center(); let v_line_bounds_top = canvas.v_line_bounds(x_v, stroke_size_v1); let v_line_bounds_bot = canvas.v_line_bounds(x_v, stroke_size_v2); let h_line_bounds_left = canvas.h_line_bounds(y_h, stroke_size_h1); let h_line_bounds_right = canvas.h_line_bounds(y_h, stroke_size_h2); let size_h1 = cmp::max(v_line_bounds_top.1 as i32, v_line_bounds_bot.1 as i32) as f32; let x_h = cmp::min(v_line_bounds_top.0 as i32, v_line_bounds_bot.0 as i32) as f32; let size_h2 = width as f32 - x_h; let size_v1 = cmp::max(h_line_bounds_left.1 as i32, h_line_bounds_right.1 as i32) as f32; let y_v = cmp::min(h_line_bounds_left.0 as i32, h_line_bounds_right.0 as i32) as f32; let size_v2 = height as f32 - y_v; // Left horizontal line. canvas.draw_h_line(0., y_h, size_h1, stroke_size_h1); // Right horizontal line. canvas.draw_h_line(x_h, y_h, size_h2, stroke_size_h2); // Top vertical line. canvas.draw_v_line(x_v, 0., size_v1, stroke_size_v1); // Bottom vertical line. canvas.draw_v_line(x_v, y_v, size_v2, stroke_size_v2); }, // Light and double line box components: // '═','║','╒','╓','╔','╕','╖','╗','╘','╙','╚','╛','╜','╝','╞','╟','╠','╡','╢','╣','╤','╥', // '╦','╧','╨','╩','╪','╫','╬'. '\u{2550}'..='\u{256c}' => { let v_lines = match character { '\u{2552}' | '\u{2555}' | '\u{2558}' | '\u{255b}' | '\u{255e}' | '\u{2561}' | '\u{2564}' | '\u{2567}' | '\u{256a}' => (canvas.x_center(), canvas.x_center()), _ => { let v_line_bounds = canvas.v_line_bounds(canvas.x_center(), stroke_size); let left_line = cmp::max(v_line_bounds.0 as i32 - 1, 0) as f32; let right_line = cmp::min(v_line_bounds.1 as i32 + 1, width as i32) as f32; (left_line, right_line) }, }; let h_lines = match character { '\u{2553}' | '\u{2556}' | '\u{2559}' | '\u{255c}' | '\u{255f}' | '\u{2562}' | '\u{2565}' | '\u{2568}' | '\u{256b}' => (canvas.y_center(), canvas.y_center()), _ => { let h_line_bounds = canvas.h_line_bounds(canvas.y_center(), stroke_size); let top_line = cmp::max(h_line_bounds.0 as i32 - 1, 0) as f32; let bottom_line = cmp::min(h_line_bounds.1 as i32 + 1, height as i32) as f32; (top_line, bottom_line) }, }; // Get bounds for each double line we could have. let v_left_bounds = canvas.v_line_bounds(v_lines.0, stroke_size); let v_right_bounds = canvas.v_line_bounds(v_lines.1, stroke_size); let h_top_bounds = canvas.h_line_bounds(h_lines.0, stroke_size); let h_bot_bounds = canvas.h_line_bounds(h_lines.1, stroke_size); let height = height as f32; let width = width as f32; // Left horizontal part. let (top_left_size, bot_left_size) = match character { '\u{2550}' | '\u{256b}' => (canvas.x_center(), canvas.x_center()), '\u{2555}'..='\u{2557}' => (v_right_bounds.1, v_left_bounds.1), '\u{255b}'..='\u{255d}' => (v_left_bounds.1, v_right_bounds.1), '\u{2561}'..='\u{2563}' | '\u{256a}' | '\u{256c}' => { (v_left_bounds.1, v_left_bounds.1) }, '\u{2564}'..='\u{2568}' => (canvas.x_center(), v_left_bounds.1), '\u{2569}'..='\u{2569}' => (v_left_bounds.1, canvas.x_center()), _ => (0., 0.), }; // Right horizontal part. let (top_right_x, bot_right_x, right_size) = match character { '\u{2550}' | '\u{2565}' | '\u{256b}' => { (canvas.x_center(), canvas.x_center(), width) }, '\u{2552}'..='\u{2554}' | '\u{2568}' => (v_left_bounds.0, v_right_bounds.0, width), '\u{2558}'..='\u{255a}' => (v_right_bounds.0, v_left_bounds.0, width), '\u{255e}'..='\u{2560}' | '\u{256a}' | '\u{256c}' => { (v_right_bounds.0, v_right_bounds.0, width) }, '\u{2564}' | '\u{2566}' => (canvas.x_center(), v_right_bounds.0, width), '\u{2567}' | '\u{2569}' => (v_right_bounds.0, canvas.x_center(), width), _ => (0., 0., 0.), }; // Top vertical part. let (left_top_size, right_top_size) = match character { '\u{2551}' | '\u{256a}' => (canvas.y_center(), canvas.y_center()), '\u{2558}'..='\u{255c}' | '\u{2568}' => (h_bot_bounds.1, h_top_bounds.1), '\u{255d}' => (h_top_bounds.1, h_bot_bounds.1), '\u{255e}'..='\u{2560}' => (canvas.y_center(), h_top_bounds.1), '\u{2561}'..='\u{2563}' => (h_top_bounds.1, canvas.y_center()), '\u{2567}' | '\u{2569}' | '\u{256b}' | '\u{256c}' => { (h_top_bounds.1, h_top_bounds.1) }, _ => (0., 0.), }; // Bottom vertical part. let (left_bot_y, right_bot_y, bottom_size) = match character { '\u{2551}' | '\u{256a}' => (canvas.y_center(), canvas.y_center(), height), '\u{2552}'..='\u{2554}' => (h_top_bounds.0, h_bot_bounds.0, height), '\u{2555}'..='\u{2557}' => (h_bot_bounds.0, h_top_bounds.0, height), '\u{255e}'..='\u{2560}' => (canvas.y_center(), h_bot_bounds.0, height), '\u{2561}'..='\u{2563}' => (h_bot_bounds.0, canvas.y_center(), height), '\u{2564}'..='\u{2566}' | '\u{256b}' | '\u{256c}' => { (h_bot_bounds.0, h_bot_bounds.0, height) }, _ => (0., 0., 0.), }; // Left horizontal line. canvas.draw_h_line(0., h_lines.0, top_left_size, stroke_size); canvas.draw_h_line(0., h_lines.1, bot_left_size, stroke_size); // Right horizontal line. canvas.draw_h_line(top_right_x, h_lines.0, right_size, stroke_size); canvas.draw_h_line(bot_right_x, h_lines.1, right_size, stroke_size); // Top vertical line. canvas.draw_v_line(v_lines.0, 0., left_top_size, stroke_size); canvas.draw_v_line(v_lines.1, 0., right_top_size, stroke_size); // Bottom vertical line. canvas.draw_v_line(v_lines.0, left_bot_y, bottom_size, stroke_size); canvas.draw_v_line(v_lines.1, right_bot_y, bottom_size, stroke_size); }, // Arcs: '╭', '╮', '╯', '╰'. '\u{256d}' | '\u{256e}' | '\u{256f}' | '\u{2570}' => { canvas.draw_ellipse_arc(stroke_size); // Mirror `X` axis. if character == '\u{256d}' || character == '\u{2570}' { let center = canvas.x_center() as usize; let extra_offset = usize::from(stroke_size % 2 != width % 2); let buffer = canvas.buffer_mut(); for y in 1..height { let left = (y - 1) * width; let right = y * width - 1; if extra_offset != 0 { buffer[right] = buffer[left]; } for offset in 0..center { buffer.swap(left + offset, right - offset - extra_offset); } } } // Mirror `Y` axis. if character == '\u{256d}' || character == '\u{256e}' { let center = canvas.y_center() as usize; let extra_offset = usize::from(stroke_size % 2 != height % 2); let buffer = canvas.buffer_mut(); if extra_offset != 0 { let bottom_row = (height - 1) * width; for index in 0..width { buffer[bottom_row + index] = buffer[index]; } } for offset in 1..=center { let top_row = (offset - 1) * width; let bottom_row = (height - offset - extra_offset) * width; for index in 0..width { buffer.swap(top_row + index, bottom_row + index); } } } }, // Parts of full block: '▀', '▁', '▂', '▃', '▄', '▅', '▆', '▇', '▔', '▉', '▊', '▋', '▌', // '▍', '▎', '▏', '▐', '▕'. '\u{2580}'..='\u{2587}' | '\u{2589}'..='\u{2590}' | '\u{2594}' | '\u{2595}' => { let width = width as f32; let height = height as f32; let mut rect_width = match character { '\u{2589}' => width * 7. / 8., '\u{258a}' => width * 6. / 8., '\u{258b}' => width * 5. / 8., '\u{258c}' => width * 4. / 8., '\u{258d}' => width * 3. / 8., '\u{258e}' => width * 2. / 8., '\u{258f}' => width * 1. / 8., '\u{2590}' => width * 4. / 8., '\u{2595}' => width * 1. / 8., _ => width, }; let (mut rect_height, mut y) = match character { '\u{2580}' => (height * 4. / 8., height * 8. / 8.), '\u{2581}' => (height * 1. / 8., height * 1. / 8.), '\u{2582}' => (height * 2. / 8., height * 2. / 8.), '\u{2583}' => (height * 3. / 8., height * 3. / 8.), '\u{2584}' => (height * 4. / 8., height * 4. / 8.), '\u{2585}' => (height * 5. / 8., height * 5. / 8.), '\u{2586}' => (height * 6. / 8., height * 6. / 8.), '\u{2587}' => (height * 7. / 8., height * 7. / 8.), '\u{2594}' => (height * 1. / 8., height * 8. / 8.), _ => (height, height), }; // Fix `y` coordinates. y = (height - y).round(); // Ensure that resulted glyph will be visible and also round sizes instead of straight // flooring them. rect_width = rect_width.round().max(1.); rect_height = rect_height.round().max(1.); let x = match character { '\u{2590}' => canvas.x_center(), '\u{2595}' => width - rect_width, _ => 0., }; canvas.draw_rect(x, y, rect_width, rect_height, COLOR_FILL); }, // Shades: '░', '▒', '▓', '█'. '\u{2588}' | '\u{2591}' | '\u{2592}' | '\u{2593}' => { let color = match character { '\u{2588}' => COLOR_FILL, '\u{2591}' => COLOR_FILL_ALPHA_STEP_3, '\u{2592}' => COLOR_FILL_ALPHA_STEP_2, '\u{2593}' => COLOR_FILL_ALPHA_STEP_1, _ => unreachable!(), }; canvas.fill(color); }, // Quadrants: '▖', '▗', '▘', '▙', '▚', '▛', '▜', '▝', '▞', '▟'. '\u{2596}'..='\u{259F}' => { let x_center = canvas.x_center().round().max(1.); let y_center = canvas.y_center().round().max(1.); let (w_second, h_second) = match character { '\u{2598}' | '\u{2599}' | '\u{259a}' | '\u{259b}' | '\u{259c}' => { (x_center, y_center) }, _ => (0., 0.), }; let (w_first, h_first) = match character { '\u{259b}' | '\u{259c}' | '\u{259d}' | '\u{259e}' | '\u{259f}' => { (x_center, y_center) }, _ => (0., 0.), }; let (w_third, h_third) = match character { '\u{2596}' | '\u{2599}' | '\u{259b}' | '\u{259e}' | '\u{259f}' => { (x_center, y_center) }, _ => (0., 0.), }; let (w_fourth, h_fourth) = match character { '\u{2597}' | '\u{2599}' | '\u{259a}' | '\u{259c}' | '\u{259f}' => { (x_center, y_center) }, _ => (0., 0.), }; // Second quadrant. canvas.draw_rect(0., 0., w_second, h_second, COLOR_FILL); // First quadrant. canvas.draw_rect(x_center, 0., w_first, h_first, COLOR_FILL); // Third quadrant. canvas.draw_rect(0., y_center, w_third, h_third, COLOR_FILL); // Fourth quadrant. canvas.draw_rect(x_center, y_center, w_fourth, h_fourth, COLOR_FILL); }, // Sextants: '🬀', '🬁', '🬂', '🬃', '🬄', '🬅', '🬆', '🬇', '🬈', '🬉', '🬊', '🬋', '🬌', '🬍', '🬎', // '🬏', '🬐', '🬑', '🬒', '🬓', '🬔', '🬕', '🬖', '🬗', '🬘', '🬙', '🬚', '🬛', '🬜', '🬝', '🬞', '🬟', // '🬠', '🬡', '🬢', '🬣', '🬤', '🬥', '🬦', '🬧', '🬨', '🬩', '🬪', '🬫', '🬬', '🬭', '🬮', '🬯', '🬰', // '🬱', '🬲', '🬳', '🬴', '🬵', '🬶', '🬷', '🬸', '🬹', '🬺', '🬻'. '\u{1fb00}'..='\u{1fb3b}' => { let x_center = canvas.x_center().round().max(1.); let y_third = (height as f32 / 3.).round().max(1.); let y_last_third = height as f32 - 2. * y_third; let (w_top_left, h_top_left) = match character { '\u{1fb00}' | '\u{1fb02}' | '\u{1fb04}' | '\u{1fb06}' | '\u{1fb08}' | '\u{1fb0a}' | '\u{1fb0c}' | '\u{1fb0e}' | '\u{1fb10}' | '\u{1fb12}' | '\u{1fb15}' | '\u{1fb17}' | '\u{1fb19}' | '\u{1fb1b}' | '\u{1fb1d}' | '\u{1fb1f}' | '\u{1fb21}' | '\u{1fb23}' | '\u{1fb25}' | '\u{1fb27}' | '\u{1fb28}' | '\u{1fb2a}' | '\u{1fb2c}' | '\u{1fb2e}' | '\u{1fb30}' | '\u{1fb32}' | '\u{1fb34}' | '\u{1fb36}' | '\u{1fb38}' | '\u{1fb3a}' => { (x_center, y_third) }, _ => (0., 0.), }; let (w_top_right, h_top_right) = match character { '\u{1fb01}' | '\u{1fb02}' | '\u{1fb05}' | '\u{1fb06}' | '\u{1fb09}' | '\u{1fb0a}' | '\u{1fb0d}' | '\u{1fb0e}' | '\u{1fb11}' | '\u{1fb12}' | '\u{1fb14}' | '\u{1fb15}' | '\u{1fb18}' | '\u{1fb19}' | '\u{1fb1c}' | '\u{1fb1d}' | '\u{1fb20}' | '\u{1fb21}' | '\u{1fb24}' | '\u{1fb25}' | '\u{1fb28}' | '\u{1fb2b}' | '\u{1fb2c}' | '\u{1fb2f}' | '\u{1fb30}' | '\u{1fb33}' | '\u{1fb34}' | '\u{1fb37}' | '\u{1fb38}' | '\u{1fb3b}' => { (x_center, y_third) }, _ => (0., 0.), }; let (w_mid_left, h_mid_left) = match character { '\u{1fb03}' | '\u{1fb04}' | '\u{1fb05}' | '\u{1fb06}' | '\u{1fb0b}' | '\u{1fb0c}' | '\u{1fb0d}' | '\u{1fb0e}' | '\u{1fb13}' | '\u{1fb14}' | '\u{1fb15}' | '\u{1fb1a}' | '\u{1fb1b}' | '\u{1fb1c}' | '\u{1fb1d}' | '\u{1fb22}' | '\u{1fb23}' | '\u{1fb24}' | '\u{1fb25}' | '\u{1fb29}' | '\u{1fb2a}' | '\u{1fb2b}' | '\u{1fb2c}' | '\u{1fb31}' | '\u{1fb32}' | '\u{1fb33}' | '\u{1fb34}' | '\u{1fb39}' | '\u{1fb3a}' | '\u{1fb3b}' => { (x_center, y_third) }, _ => (0., 0.), }; let (w_mid_right, h_mid_right) = match character { '\u{1fb07}' | '\u{1fb08}' | '\u{1fb09}' | '\u{1fb0a}' | '\u{1fb0b}' | '\u{1fb0c}' | '\u{1fb0d}' | '\u{1fb0e}' | '\u{1fb16}' | '\u{1fb17}' | '\u{1fb18}' | '\u{1fb19}' | '\u{1fb1a}' | '\u{1fb1b}' | '\u{1fb1c}' | '\u{1fb1d}' | '\u{1fb26}' | '\u{1fb27}' | '\u{1fb28}' | '\u{1fb29}' | '\u{1fb2a}' | '\u{1fb2b}' | '\u{1fb2c}' | '\u{1fb35}' | '\u{1fb36}' | '\u{1fb37}' | '\u{1fb38}' | '\u{1fb39}' | '\u{1fb3a}' | '\u{1fb3b}' => { (x_center, y_third) }, _ => (0., 0.), }; let (w_bottom_left, h_bottom_left) = match character { '\u{1fb0f}' | '\u{1fb10}' | '\u{1fb11}' | '\u{1fb12}' | '\u{1fb13}' | '\u{1fb14}' | '\u{1fb15}' | '\u{1fb16}' | '\u{1fb17}' | '\u{1fb18}' | '\u{1fb19}' | '\u{1fb1a}' | '\u{1fb1b}' | '\u{1fb1c}' | '\u{1fb1d}' | '\u{1fb2d}' | '\u{1fb2e}' | '\u{1fb2f}' | '\u{1fb30}' | '\u{1fb31}' | '\u{1fb32}' | '\u{1fb33}' | '\u{1fb34}' | '\u{1fb35}' | '\u{1fb36}' | '\u{1fb37}' | '\u{1fb38}' | '\u{1fb39}' | '\u{1fb3a}' | '\u{1fb3b}' => { (x_center, y_last_third) }, _ => (0., 0.), }; let (w_bottom_right, h_bottom_right) = match character { '\u{1fb1e}' | '\u{1fb1f}' | '\u{1fb20}' | '\u{1fb21}' | '\u{1fb22}' | '\u{1fb23}' | '\u{1fb24}' | '\u{1fb25}' | '\u{1fb26}' | '\u{1fb27}' | '\u{1fb28}' | '\u{1fb29}' | '\u{1fb2a}' | '\u{1fb2b}' | '\u{1fb2c}' | '\u{1fb2d}' | '\u{1fb2e}' | '\u{1fb2f}' | '\u{1fb30}' | '\u{1fb31}' | '\u{1fb32}' | '\u{1fb33}' | '\u{1fb34}' | '\u{1fb35}' | '\u{1fb36}' | '\u{1fb37}' | '\u{1fb38}' | '\u{1fb39}' | '\u{1fb3a}' | '\u{1fb3b}' => { (x_center, y_last_third) }, _ => (0., 0.), }; canvas.draw_rect(0., 0., w_top_left, h_top_left, COLOR_FILL); canvas.draw_rect(x_center, 0., w_top_right, h_top_right, COLOR_FILL); canvas.draw_rect(0., y_third, w_mid_left, h_mid_left, COLOR_FILL); canvas.draw_rect(x_center, y_third, w_mid_right, h_mid_right, COLOR_FILL); canvas.draw_rect(0., y_third * 2., w_bottom_left, h_bottom_left, COLOR_FILL); canvas.draw_rect(x_center, y_third * 2., w_bottom_right, h_bottom_right, COLOR_FILL); }, _ => unreachable!(), } let top = height as i32 + metrics.descent as i32; let buffer = BitmapBuffer::Rgb(canvas.into_raw()); RasterizedGlyph { character, top, left: 0, height: height as i32, width: width as i32, buffer, advance: (width as i32, height as i32), } } fn powerline_drawing( character: char, metrics: &Metrics, offset: &Delta<i8>, ) -> Option<RasterizedGlyph> { let height = (metrics.line_height as i32 + offset.y as i32) as usize; let width = (metrics.average_advance as i32 + offset.x as i32) as usize; let extra_thickness = calculate_stroke_size(width) as i32 - 1; let mut canvas = Canvas::new(width, height); let slope = 1; let top_y = 1; let bottom_y = height as i32 - top_y - 1; // Start with offset `1` and draw until the intersection of the f(x) = slope * x + 1 and // g(x) = H - slope * x - 1 lines. The intersection happens when f(x) = g(x), which is at // x = (H - 2) / (2 * slope). let x_intersection = (height as i32 + 1) / 2 - 1; // Don't use built-in font if we'd cut the tip too much, for example when the font is really // narrow. if x_intersection - width as i32 > 1 { return None; } let top_line = (0..x_intersection).map(|x| line_equation(slope, x, top_y)); let bottom_line = (0..x_intersection).map(|x| line_equation(-slope, x, bottom_y)); // Inner lines to make arrows thicker. let mut top_inner_line = (0..x_intersection - extra_thickness) .map(|x| line_equation(slope, x, top_y + extra_thickness)); let mut bottom_inner_line = (0..x_intersection - extra_thickness) .map(|x| line_equation(-slope, x, bottom_y - extra_thickness)); // NOTE: top_line and bottom_line have the same amount of iterations. for (p1, p2) in top_line.zip(bottom_line) { if character == POWERLINE_TRIANGLE_LTR || character == POWERLINE_TRIANGLE_RTL { canvas.draw_rect(0., p1.1, p1.0 + 1., 1., COLOR_FILL); canvas.draw_rect(0., p2.1, p2.0 + 1., 1., COLOR_FILL); } else if character == POWERLINE_ARROW_LTR || character == POWERLINE_ARROW_RTL { let p3 = top_inner_line.next().unwrap_or(p2); let p4 = bottom_inner_line.next().unwrap_or(p1); // If we can't fit the entire arrow in the cell, we cut off the tip of the arrow by // drawing a rectangle between the two lines. if p1.0 as usize + 1 == width { canvas.draw_rect(p1.0, p1.1, 1., p2.1 - p1.1 + 1., COLOR_FILL); break; } else { canvas.draw_rect(p1.0, p1.1, 1., p3.1 - p1.1 + 1., COLOR_FILL); canvas.draw_rect(p4.0, p4.1, 1., p2.1 - p4.1 + 1., COLOR_FILL); } } } if character == POWERLINE_TRIANGLE_RTL || character == POWERLINE_ARROW_RTL { canvas.flip_horizontal(); } let top = height as i32 + metrics.descent as i32; let buffer = BitmapBuffer::Rgb(canvas.into_raw()); Some(RasterizedGlyph { character, top, left: 0, height: height as i32, width: width as i32, buffer, advance: (width as i32, height as i32), }) } #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] struct Pixel { _r: u8, _g: u8, _b: u8, } impl Pixel { fn gray(color: u8) -> Self { Self { _r: color, _g: color, _b: color } } } impl ops::Add for Pixel { type Output = Pixel; fn add(self, rhs: Pixel) -> Self::Output { let _r = self._r.saturating_add(rhs._r); let _g = self._g.saturating_add(rhs._g); let _b = self._b.saturating_add(rhs._b); Pixel { _r, _g, _b } } } impl ops::Div<u8> for Pixel { type Output = Pixel; fn div(self, rhs: u8) -> Self::Output { let _r = self._r / rhs; let _g = self._g / rhs; let _b = self._b / rhs; Pixel { _r, _g, _b } } } /// Canvas which is used for simple line drawing operations. /// /// The coordinate system is the following: /// /// 0 x /// --------------→ /// | /// | /// | /// | /// | /// | /// y↓ struct Canvas { /// Canvas width. width: usize, /// Canvas height. height: usize, /// Canvas buffer we draw on. buffer: Vec<Pixel>, } impl Canvas { /// Builds new `Canvas` for line drawing with the given `width` and `height` with default color. fn new(width: usize, height: usize) -> Self { let buffer = vec![Pixel::default(); width * height]; Self { width, height, buffer } } /// Vertical center of the `Canvas`. fn y_center(&self) -> f32 { self.height as f32 / 2. } /// Horizontal center of the `Canvas`. fn x_center(&self) -> f32 { self.width as f32 / 2. } /// Canvas underlying buffer for direct manipulation fn buffer_mut(&mut self) -> &mut [Pixel] { &mut self.buffer } /// Gives bounds for horizontal straight line on `y` with `stroke_size`. fn h_line_bounds(&self, y: f32, stroke_size: usize) -> (f32, f32) { let start_y = cmp::max((y - stroke_size as f32 / 2.) as i32, 0) as f32; let end_y = cmp::min((y + stroke_size as f32 / 2.) as i32, self.height as i32) as f32; (start_y, end_y) } /// Gives bounds for vertical straight line on `y` with `stroke_size`. fn v_line_bounds(&self, x: f32, stroke_size: usize) -> (f32, f32) { let start_x = cmp::max((x - stroke_size as f32 / 2.) as i32, 0) as f32; let end_x = cmp::min((x + stroke_size as f32 / 2.) as i32, self.width as i32) as f32; (start_x, end_x) } /// Flip horizontally. fn flip_horizontal(&mut self) { for row in 0..self.height { for col in 0..self.width / 2 { let index = row * self.width; self.buffer.swap(index + col, index + self.width - col - 1) } } } /// Draws a horizontal straight line from (`x`, `y`) of `size` with the given `stroke_size`. fn draw_h_line(&mut self, x: f32, y: f32, size: f32, stroke_size: usize) { let (start_y, end_y) = self.h_line_bounds(y, stroke_size); self.draw_rect(x, start_y, size, end_y - start_y, COLOR_FILL); } /// Draws a vertical straight line from (`x`, `y`) of `size` with the given `stroke_size`. fn draw_v_line(&mut self, x: f32, y: f32, size: f32, stroke_size: usize) { let (start_x, end_x) = self.v_line_bounds(x, stroke_size); self.draw_rect(start_x, y, end_x - start_x, size, COLOR_FILL); } /// Draws a rect from the (`x`, `y`) of the given `width` and `height` using `color`. fn draw_rect(&mut self, x: f32, y: f32, width: f32, height: f32, color: Pixel) { let start_x = x as usize; let end_x = cmp::min((x + width) as usize, self.width); let start_y = y as usize; let end_y = cmp::min((y + height) as usize, self.height); for y in start_y..end_y { let y = y * self.width; self.buffer[start_x + y..end_x + y].fill(color); } } /// Put pixel into buffer with the given color if the color is brighter than the one buffer /// already has in place. #[inline] fn put_pixel(&mut self, x: f32, y: f32, color: Pixel) { if x < 0. || y < 0. || x > self.width as f32 - 1. || y > self.height as f32 - 1. { return; } let index = x as usize + y as usize * self.width; if color._r > self.buffer[index]._r { self.buffer[index] = color; } } /// Xiaolin Wu's line drawing from (`from_x`, `from_y`) to (`to_x`, `to_y`). fn draw_line(&mut self, mut from_x: f32, mut from_y: f32, mut to_x: f32, mut to_y: f32) { let steep = (to_y - from_y).abs() > (to_x - from_x).abs(); if steep { mem::swap(&mut from_x, &mut from_y); mem::swap(&mut to_x, &mut to_y); } if from_x > to_x { mem::swap(&mut from_x, &mut to_x); mem::swap(&mut from_y, &mut to_y); } let delta_x = to_x - from_x; let delta_y = to_y - from_y; let gradient = if delta_x.abs() <= f32::EPSILON { 1. } else { delta_y / delta_x }; let x_end = f32::round(from_x); let y_end = from_y + gradient * (x_end - from_x); let x_gap = 1. - (from_x + 0.5).fract(); let xpxl1 = x_end; let ypxl1 = y_end.trunc(); let color_1 = Pixel::gray(((1. - y_end.fract()) * x_gap * COLOR_FILL._r as f32) as u8); let color_2 = Pixel::gray((y_end.fract() * x_gap * COLOR_FILL._r as f32) as u8); if steep { self.put_pixel(ypxl1, xpxl1, color_1); self.put_pixel(ypxl1 + 1., xpxl1, color_2); } else { self.put_pixel(xpxl1, ypxl1, color_1); self.put_pixel(xpxl1 + 1., ypxl1, color_2); } let mut intery = y_end + gradient; let x_end = f32::round(to_x); let y_end = to_y + gradient * (x_end - to_x); let x_gap = (to_x + 0.5).fract(); let xpxl2 = x_end; let ypxl2 = y_end.trunc(); let color_1 = Pixel::gray(((1. - y_end.fract()) * x_gap * COLOR_FILL._r as f32) as u8); let color_2 = Pixel::gray((y_end.fract() * x_gap * COLOR_FILL._r as f32) as u8); if steep { self.put_pixel(ypxl2, xpxl2, color_1); self.put_pixel(ypxl2 + 1., xpxl2, color_2); } else { self.put_pixel(xpxl2, ypxl2, color_1); self.put_pixel(xpxl2, ypxl2 + 1., color_2); } if steep { for x in xpxl1 as i32 + 1..xpxl2 as i32 { let color_1 = Pixel::gray(((1. - intery.fract()) * COLOR_FILL._r as f32) as u8); let color_2 = Pixel::gray((intery.fract() * COLOR_FILL._r as f32) as u8); self.put_pixel(intery.trunc(), x as f32, color_1); self.put_pixel(intery.trunc() + 1., x as f32, color_2); intery += gradient; } } else { for x in xpxl1 as i32 + 1..xpxl2 as i32 { let color_1 = Pixel::gray(((1. - intery.fract()) * COLOR_FILL._r as f32) as u8); let color_2 = Pixel::gray((intery.fract() * COLOR_FILL._r as f32) as u8); self.put_pixel(x as f32, intery.trunc(), color_1); self.put_pixel(x as f32, intery.trunc() + 1., color_2); intery += gradient; } } } /// Draws a part of an ellipse centered in `(0., 0.)` with `self.x_center()` and `self.y_center` /// vertex and co-vertex respectively using a given `stroke` in the bottom-right quadrant of the /// `Canvas` coordinate system. fn draw_ellipse_arc(&mut self, stroke_size: usize) { fn colors_with_error(error: f32, max_transparency: f32) -> (Pixel, Pixel) { let transparency = error * max_transparency; let alpha_1 = 1. - transparency; let alpha_2 = 1. - (max_transparency - transparency); let color_1 = Pixel::gray((COLOR_FILL._r as f32 * alpha_1) as u8); let color_2 = Pixel::gray((COLOR_FILL._r as f32 * alpha_2) as u8); (color_1, color_2) } let h_line_bounds = self.h_line_bounds(self.y_center(), stroke_size); let v_line_bounds = self.v_line_bounds(self.x_center(), stroke_size); let h_line_bounds = (h_line_bounds.0 as usize, h_line_bounds.1 as usize); let v_line_bounds = (v_line_bounds.0 as usize, v_line_bounds.1 as usize); let max_transparency = 0.5; for (radius_y, radius_x) in (h_line_bounds.0..h_line_bounds.1).zip(v_line_bounds.0..v_line_bounds.1) { let radius_x = radius_x as f32; let radius_y = radius_y as f32; let radius_x2 = radius_x * radius_x; let radius_y2 = radius_y * radius_y; let quarter = f32::round(radius_x2 / f32::sqrt(radius_x2 + radius_y2)) as usize; for x in 0..=quarter { let x = x as f32; let y = radius_y * f32::sqrt(1. - x * x / radius_x2); let error = y.fract(); let (color_1, color_2) = colors_with_error(error, max_transparency); let x = x.clamp(0., radius_x); let y_next = (y + 1.).clamp(0., h_line_bounds.1 as f32 - 1.); let y = y.clamp(0., h_line_bounds.1 as f32 - 1.); self.put_pixel(x, y, color_1); self.put_pixel(x, y_next, color_2); } let quarter = f32::round(radius_y2 / f32::sqrt(radius_x2 + radius_y2)) as usize; for y in 0..=quarter { let y = y as f32; let x = radius_x * f32::sqrt(1. - y * y / radius_y2); let error = x - x.fract(); let (color_1, color_2) = colors_with_error(error, max_transparency); let x_next = (x + 1.).clamp(0., v_line_bounds.1 as f32 - 1.); let x = x.clamp(0., v_line_bounds.1 as f32 - 1.); let y = y.clamp(0., radius_y); self.put_pixel(x, y, color_1); self.put_pixel(x_next, y, color_2); } } // Ensure the part closer to edges is properly filled. self.draw_h_line(0., self.y_center(), stroke_size as f32, stroke_size); self.draw_v_line(self.x_center(), 0., stroke_size as f32, stroke_size); // Fill the resulted arc, since it could have gaps in-between. for y in 0..self.height { let row = y * self.width; let left = match self.buffer[row..row + self.width].iter().position(|p| p._r != 0) { Some(left) => row + left, _ => continue, }; let right = match self.buffer[row..row + self.width].iter().rposition(|p| p._r != 0) { Some(right) => row + right, _ => continue, }; for index in left + 1..right { self.buffer[index] = self.buffer[index] + self.buffer[index - 1] / 2 + self.buffer[index + 1] / 2; } } } /// Fills the `Canvas` with the given `Color`. fn fill(&mut self, color: Pixel) { self.buffer.fill(color); } /// Consumes `Canvas` and returns its underlying storage as raw byte vector. fn into_raw(self) -> Vec<u8> { // SAFETY This is safe since we use `repr(packed)` on `Pixel` struct for underlying storage // of the `Canvas` buffer which consists of three u8 values. unsafe { let capacity = self.buffer.capacity() * mem::size_of::<Pixel>(); let len = self.buffer.len() * mem::size_of::<Pixel>(); let buf = self.buffer.as_ptr() as *mut u8; mem::forget(self.buffer); Vec::from_raw_parts(buf, len, capacity) } } } /// Compute line width. fn calculate_stroke_size(cell_width: usize) -> usize { // Use one eight of the cell width, since this is used as a step size for block elements. cmp::max((cell_width as f32 / 8.).round() as usize, 1) } /// `f(x) = slope * x + offset` equation. fn line_equation(slope: i32, x: i32, offset: i32) -> (f32, f32) { (x as f32, (slope * x + offset) as f32) } #[cfg(test)] mod tests { use super::*; use crossfont::Metrics; // Dummy metrics values to test builtin glyphs coverage. const METRICS: Metrics = Metrics { average_advance: 6., line_height: 16., descent: 4., underline_position: 2., underline_thickness: 2., strikeout_position: 2., strikeout_thickness: 2., }; #[test] fn builtin_line_drawing_glyphs_coverage() { let offset = Default::default(); let glyph_offset = Default::default(); // Test coverage of box drawing characters. for character in ('\u{2500}'..='\u{259f}').chain('\u{1fb00}'..='\u{1fb3b}') { assert!(builtin_glyph(character, &METRICS, &offset, &glyph_offset).is_some()); } for character in ('\u{2450}'..'\u{2500}').chain('\u{25a0}'..'\u{2600}') { assert!(builtin_glyph(character, &METRICS, &offset, &glyph_offset).is_none()); } } #[test] fn builtin_powerline_glyphs_coverage() { let offset = Default::default(); let glyph_offset = Default::default(); // Test coverage of box drawing characters. for character in '\u{e0b0}'..='\u{e0b3}' { assert!(builtin_glyph(character, &METRICS, &offset, &glyph_offset).is_some()); } for character in ('\u{e0a0}'..'\u{e0b0}').chain('\u{e0b4}'..'\u{e0c0}') { assert!(builtin_glyph(character, &METRICS, &offset, &glyph_offset).is_none()); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/text/gles2.rs���������������������������������������������������������0000644�0000000�0000000�00000034345�10461020230�0016657�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::mem::size_of; use std::ptr; use crossfont::RasterizedGlyph; use log::info; use alacritty_terminal::term::cell::Flags; use crate::display::content::RenderableCell; use crate::display::SizeInfo; use crate::gl; use crate::gl::types::*; use crate::renderer::shader::{ShaderProgram, ShaderVersion}; use crate::renderer::{cstr, Error, GlExtensions}; use super::atlas::{Atlas, ATLAS_SIZE}; use super::{ glsl3, Glyph, LoadGlyph, LoaderApi, RenderingGlyphFlags, RenderingPass, TextRenderApi, TextRenderBatch, TextRenderer, TextShader, }; // Shader source. static TEXT_SHADER_F: &str = include_str!("../../../res/gles2/text.f.glsl"); static TEXT_SHADER_V: &str = include_str!("../../../res/gles2/text.v.glsl"); #[derive(Debug)] pub struct Gles2Renderer { program: TextShaderProgram, vao: GLuint, vbo: GLuint, ebo: GLuint, atlas: Vec<Atlas>, batch: Batch, current_atlas: usize, active_tex: GLuint, dual_source_blending: bool, } impl Gles2Renderer { pub fn new(allow_dsb: bool, is_gles_context: bool) -> Result<Self, Error> { info!("Using OpenGL ES 2.0 renderer"); let dual_source_blending = allow_dsb && (GlExtensions::contains("GL_EXT_blend_func_extended") || GlExtensions::contains("GL_ARB_blend_func_extended")); if is_gles_context { info!("Running on OpenGL ES context"); } if dual_source_blending { info!("Using dual source blending"); } let program = TextShaderProgram::new(ShaderVersion::Gles2, dual_source_blending)?; let mut vao: GLuint = 0; let mut vbo: GLuint = 0; let mut ebo: GLuint = 0; let mut vertex_indices = Vec::with_capacity(BATCH_MAX / 4 * 6); for index in 0..(BATCH_MAX / 4) as u16 { let index = index * 4; vertex_indices.push(index); vertex_indices.push(index + 1); vertex_indices.push(index + 3); vertex_indices.push(index + 1); vertex_indices.push(index + 2); vertex_indices.push(index + 3); } unsafe { gl::Enable(gl::BLEND); gl::DepthMask(gl::FALSE); gl::GenVertexArrays(1, &mut vao); gl::GenBuffers(1, &mut ebo); gl::GenBuffers(1, &mut vbo); gl::BindVertexArray(vao); // Elements buffer. gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo); gl::BufferData( gl::ELEMENT_ARRAY_BUFFER, (vertex_indices.capacity() * size_of::<u16>()) as isize, vertex_indices.as_ptr() as *const _, gl::STATIC_DRAW, ); // Vertex buffer. gl::BindBuffer(gl::ARRAY_BUFFER, vbo); gl::BufferData( gl::ARRAY_BUFFER, (BATCH_MAX * size_of::<TextVertex>()) as isize, ptr::null(), gl::STREAM_DRAW, ); let mut index = 0; let mut size = 0; macro_rules! add_attr { ($count:expr, $gl_type:expr, $type:ty) => { gl::VertexAttribPointer( index, $count, $gl_type, gl::FALSE, size_of::<TextVertex>() as i32, size as *const _, ); gl::EnableVertexAttribArray(index); #[allow(unused_assignments)] { size += $count * size_of::<$type>(); index += 1; } }; } // Cell coords. add_attr!(2, gl::SHORT, i16); // Glyph coords. add_attr!(2, gl::SHORT, i16); // UV. add_attr!(2, gl::FLOAT, u32); // Color and bitmap color. // // These are packed together because of an OpenGL driver issue on macOS, which caused a // `vec3(u8)` text color and a `u8` for glyph color to cause performance regressions. add_attr!(4, gl::UNSIGNED_BYTE, u8); // Background color. add_attr!(4, gl::UNSIGNED_BYTE, u8); // Cleanup. gl::BindVertexArray(0); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0); gl::BindBuffer(gl::ARRAY_BUFFER, 0); } Ok(Self { program, vao, vbo, ebo, atlas: vec![Atlas::new(ATLAS_SIZE, is_gles_context)], batch: Batch::new(), current_atlas: 0, active_tex: 0, dual_source_blending, }) } } impl Drop for Gles2Renderer { fn drop(&mut self) { unsafe { gl::DeleteBuffers(1, &self.vbo); gl::DeleteBuffers(1, &self.ebo); gl::DeleteVertexArrays(1, &self.vao); } } } impl<'a> TextRenderer<'a> for Gles2Renderer { type RenderApi = RenderApi<'a>; type RenderBatch = Batch; type Shader = TextShaderProgram; fn program(&self) -> &Self::Shader { &self.program } fn with_api<'b: 'a, F, T>(&'b mut self, _: &'b SizeInfo, func: F) -> T where F: FnOnce(Self::RenderApi) -> T, { unsafe { gl::UseProgram(self.program.id()); gl::BindVertexArray(self.vao); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo); gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo); gl::ActiveTexture(gl::TEXTURE0); } let res = func(RenderApi { active_tex: &mut self.active_tex, batch: &mut self.batch, atlas: &mut self.atlas, current_atlas: &mut self.current_atlas, program: &mut self.program, dual_source_blending: self.dual_source_blending, }); unsafe { gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0); gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindVertexArray(0); gl::UseProgram(0); } res } fn loader_api(&mut self) -> LoaderApi<'_> { LoaderApi { active_tex: &mut self.active_tex, atlas: &mut self.atlas, current_atlas: &mut self.current_atlas, } } } /// Maximum items to be drawn in a batch. /// /// We use the closest number to `u16::MAX` dividable by 4 (amount of vertices we push for a glyph), /// since it's the maximum possible index in `glDrawElements` in GLES2. const BATCH_MAX: usize = (u16::MAX - u16::MAX % 4) as usize; #[derive(Debug)] pub struct Batch { tex: GLuint, vertices: Vec<TextVertex>, } impl Batch { fn new() -> Self { Self { tex: 0, vertices: Vec::with_capacity(BATCH_MAX) } } #[inline] fn len(&self) -> usize { self.vertices.len() } #[inline] fn capacity(&self) -> usize { BATCH_MAX } #[inline] fn size(&self) -> usize { self.len() * size_of::<TextVertex>() } #[inline] fn clear(&mut self) { self.vertices.clear(); } } impl TextRenderBatch for Batch { #[inline] fn tex(&self) -> GLuint { self.tex } #[inline] fn full(&self) -> bool { self.capacity() == self.len() } #[inline] fn is_empty(&self) -> bool { self.len() == 0 } fn add_item(&mut self, cell: &RenderableCell, glyph: &Glyph, size_info: &SizeInfo) { if self.is_empty() { self.tex = glyph.tex_id; } // Calculate the cell position. let x = cell.point.column.0 as i16 * size_info.cell_width() as i16; let y = cell.point.line as i16 * size_info.cell_height() as i16; // Calculate the glyph position. let glyph_x = cell.point.column.0 as i16 * size_info.cell_width() as i16 + glyph.left; let glyph_y = (cell.point.line + 1) as i16 * size_info.cell_height() as i16 - glyph.top; let colored = if glyph.multicolor { RenderingGlyphFlags::COLORED } else { RenderingGlyphFlags::empty() }; let is_wide = if cell.flags.contains(Flags::WIDE_CHAR) { 2 } else { 1 }; let mut vertex = TextVertex { x, y: y + size_info.cell_height() as i16, glyph_x, glyph_y: glyph_y + glyph.height, u: glyph.uv_left, v: glyph.uv_bot + glyph.uv_height, r: cell.fg.r, g: cell.fg.g, b: cell.fg.b, colored, bg_r: cell.bg.r, bg_g: cell.bg.g, bg_b: cell.bg.b, bg_a: (cell.bg_alpha * 255.0) as u8, }; self.vertices.push(vertex); vertex.y = y; vertex.glyph_y = glyph_y; vertex.u = glyph.uv_left; vertex.v = glyph.uv_bot; self.vertices.push(vertex); vertex.x = x + is_wide * size_info.cell_width() as i16; vertex.glyph_x = glyph_x + glyph.width; vertex.u = glyph.uv_left + glyph.uv_width; vertex.v = glyph.uv_bot; self.vertices.push(vertex); vertex.x = x + is_wide * size_info.cell_width() as i16; vertex.y = y + size_info.cell_height() as i16; vertex.glyph_x = glyph_x + glyph.width; vertex.glyph_y = glyph_y + glyph.height; vertex.u = glyph.uv_left + glyph.uv_width; vertex.v = glyph.uv_bot + glyph.uv_height; self.vertices.push(vertex); } } #[derive(Debug)] pub struct RenderApi<'a> { active_tex: &'a mut GLuint, batch: &'a mut Batch, atlas: &'a mut Vec<Atlas>, current_atlas: &'a mut usize, program: &'a mut TextShaderProgram, dual_source_blending: bool, } impl<'a> Drop for RenderApi<'a> { fn drop(&mut self) { if !self.batch.is_empty() { self.render_batch(); } } } impl<'a> LoadGlyph for RenderApi<'a> { fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph { Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized) } fn clear(&mut self) { Atlas::clear_atlas(self.atlas, self.current_atlas) } } impl<'a> TextRenderApi<Batch> for RenderApi<'a> { fn batch(&mut self) -> &mut Batch { self.batch } fn render_batch(&mut self) { unsafe { gl::BufferSubData( gl::ARRAY_BUFFER, 0, self.batch.size() as isize, self.batch.vertices.as_ptr() as *const _, ); } if *self.active_tex != self.batch.tex() { unsafe { gl::BindTexture(gl::TEXTURE_2D, self.batch.tex()); } *self.active_tex = self.batch.tex(); } unsafe { let num_indices = (self.batch.len() / 4 * 6) as i32; // The rendering is inspired by // https://github.com/servo/webrender/blob/master/webrender/doc/text-rendering.md. // Draw background. self.program.set_rendering_pass(RenderingPass::Background); gl::BlendFunc(gl::ONE, gl::ZERO); gl::DrawElements(gl::TRIANGLES, num_indices, gl::UNSIGNED_SHORT, ptr::null()); self.program.set_rendering_pass(RenderingPass::SubpixelPass1); if self.dual_source_blending { // Text rendering pass. gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR); } else { // First text rendering pass. gl::BlendFuncSeparate(gl::ZERO, gl::ONE_MINUS_SRC_COLOR, gl::ZERO, gl::ONE); gl::DrawElements(gl::TRIANGLES, num_indices, gl::UNSIGNED_SHORT, ptr::null()); // Second text rendering pass. self.program.set_rendering_pass(RenderingPass::SubpixelPass2); gl::BlendFuncSeparate(gl::ONE_MINUS_DST_ALPHA, gl::ONE, gl::ZERO, gl::ONE); gl::DrawElements(gl::TRIANGLES, num_indices, gl::UNSIGNED_SHORT, ptr::null()); // Third text rendering pass. self.program.set_rendering_pass(RenderingPass::SubpixelPass3); gl::BlendFuncSeparate(gl::ONE, gl::ONE, gl::ONE, gl::ONE_MINUS_SRC_ALPHA); } gl::DrawElements(gl::TRIANGLES, num_indices, gl::UNSIGNED_SHORT, ptr::null()); } self.batch.clear(); } } #[repr(C)] #[derive(Debug, Copy, Clone)] struct TextVertex { // Cell coordinates. x: i16, y: i16, // Glyph coordinates. glyph_x: i16, glyph_y: i16, // Offsets into Atlas. u: f32, v: f32, // Color. r: u8, g: u8, b: u8, // Whether the glyph is colored. colored: RenderingGlyphFlags, // Background color. bg_r: u8, bg_g: u8, bg_b: u8, bg_a: u8, } #[derive(Debug)] pub struct TextShaderProgram { /// Shader program. program: ShaderProgram, /// Projection scale and offset uniform. u_projection: GLint, /// Rendering pass. /// /// For dual source blending, there are 2 passes; one for background, another for text, /// similar to the GLSL3 renderer. /// /// If GL_EXT_blend_func_extended is not available, the rendering is split into 4 passes. /// One is used for the background and the rest to perform subpixel text rendering according to /// <https://github.com/servo/webrender/blob/master/webrender/doc/text-rendering.md>. /// /// Rendering is split into three passes. u_rendering_pass: GLint, } impl TextShaderProgram { pub fn new(shader_version: ShaderVersion, dual_source_blending: bool) -> Result<Self, Error> { let fragment_shader = if dual_source_blending { &glsl3::TEXT_SHADER_F } else { &TEXT_SHADER_F }; let program = ShaderProgram::new(shader_version, None, TEXT_SHADER_V, fragment_shader)?; Ok(Self { u_projection: program.get_uniform_location(cstr!("projection"))?, u_rendering_pass: program.get_uniform_location(cstr!("renderingPass"))?, program, }) } fn set_rendering_pass(&self, rendering_pass: RenderingPass) { unsafe { gl::Uniform1i(self.u_rendering_pass, rendering_pass as i32) } } } impl TextShader for TextShaderProgram { fn id(&self) -> GLuint { self.program.id() } fn projection_uniform(&self) -> GLint { self.u_projection } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/text/glsl3.rs���������������������������������������������������������0000644�0000000�0000000�00000027574�10461020230�0016675�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::mem::size_of; use std::ptr; use crossfont::RasterizedGlyph; use log::info; use alacritty_terminal::term::cell::Flags; use crate::display::content::RenderableCell; use crate::display::SizeInfo; use crate::gl; use crate::gl::types::*; use crate::renderer::shader::{ShaderProgram, ShaderVersion}; use crate::renderer::{cstr, Error}; use super::atlas::{Atlas, ATLAS_SIZE}; use super::{ Glyph, LoadGlyph, LoaderApi, RenderingGlyphFlags, RenderingPass, TextRenderApi, TextRenderBatch, TextRenderer, TextShader, }; // Shader source. pub static TEXT_SHADER_F: &str = include_str!("../../../res/glsl3/text.f.glsl"); static TEXT_SHADER_V: &str = include_str!("../../../res/glsl3/text.v.glsl"); /// Maximum items to be drawn in a batch. const BATCH_MAX: usize = 0x1_0000; #[derive(Debug)] pub struct Glsl3Renderer { program: TextShaderProgram, vao: GLuint, ebo: GLuint, vbo_instance: GLuint, atlas: Vec<Atlas>, current_atlas: usize, active_tex: GLuint, batch: Batch, } impl Glsl3Renderer { pub fn new() -> Result<Self, Error> { info!("Using OpenGL 3.3 renderer"); let program = TextShaderProgram::new(ShaderVersion::Glsl3)?; let mut vao: GLuint = 0; let mut ebo: GLuint = 0; let mut vbo_instance: GLuint = 0; unsafe { gl::Enable(gl::BLEND); gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR); // Disable depth mask, as the renderer never uses depth tests. gl::DepthMask(gl::FALSE); gl::GenVertexArrays(1, &mut vao); gl::GenBuffers(1, &mut ebo); gl::GenBuffers(1, &mut vbo_instance); gl::BindVertexArray(vao); // --------------------- // Set up element buffer // --------------------- let indices: [u32; 6] = [0, 1, 3, 1, 2, 3]; gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, ebo); gl::BufferData( gl::ELEMENT_ARRAY_BUFFER, (6 * size_of::<u32>()) as isize, indices.as_ptr() as *const _, gl::STATIC_DRAW, ); // ---------------------------- // Setup vertex instance buffer // ---------------------------- gl::BindBuffer(gl::ARRAY_BUFFER, vbo_instance); gl::BufferData( gl::ARRAY_BUFFER, (BATCH_MAX * size_of::<InstanceData>()) as isize, ptr::null(), gl::STREAM_DRAW, ); let mut index = 0; let mut size = 0; macro_rules! add_attr { ($count:expr, $gl_type:expr, $type:ty) => { gl::VertexAttribPointer( index, $count, $gl_type, gl::FALSE, size_of::<InstanceData>() as i32, size as *const _, ); gl::EnableVertexAttribArray(index); gl::VertexAttribDivisor(index, 1); #[allow(unused_assignments)] { size += $count * size_of::<$type>(); index += 1; } }; } // Coords. add_attr!(2, gl::UNSIGNED_SHORT, u16); // Glyph offset and size. add_attr!(4, gl::SHORT, i16); // UV offset. add_attr!(4, gl::FLOAT, f32); // Color and cell flags. // // These are packed together because of an OpenGL driver issue on macOS, which caused a // `vec3(u8)` text color and a `u8` cell flags to increase the rendering time by a // huge margin. add_attr!(4, gl::UNSIGNED_BYTE, u8); // Background color. add_attr!(4, gl::UNSIGNED_BYTE, u8); // Cleanup. gl::BindVertexArray(0); gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0); } Ok(Self { program, vao, ebo, vbo_instance, atlas: vec![Atlas::new(ATLAS_SIZE, false)], current_atlas: 0, active_tex: 0, batch: Batch::new(), }) } } impl<'a> TextRenderer<'a> for Glsl3Renderer { type RenderApi = RenderApi<'a>; type RenderBatch = Batch; type Shader = TextShaderProgram; fn with_api<'b: 'a, F, T>(&'b mut self, size_info: &'b SizeInfo, func: F) -> T where F: FnOnce(Self::RenderApi) -> T, { unsafe { gl::UseProgram(self.program.id()); self.program.set_term_uniforms(size_info); gl::BindVertexArray(self.vao); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo); gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo_instance); gl::ActiveTexture(gl::TEXTURE0); } let res = func(RenderApi { active_tex: &mut self.active_tex, batch: &mut self.batch, atlas: &mut self.atlas, current_atlas: &mut self.current_atlas, program: &mut self.program, }); unsafe { gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, 0); gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindVertexArray(0); gl::UseProgram(0); } res } fn program(&self) -> &Self::Shader { &self.program } fn loader_api(&mut self) -> LoaderApi<'_> { LoaderApi { active_tex: &mut self.active_tex, atlas: &mut self.atlas, current_atlas: &mut self.current_atlas, } } } impl Drop for Glsl3Renderer { fn drop(&mut self) { unsafe { gl::DeleteBuffers(1, &self.vbo_instance); gl::DeleteBuffers(1, &self.ebo); gl::DeleteVertexArrays(1, &self.vao); } } } #[derive(Debug)] pub struct RenderApi<'a> { active_tex: &'a mut GLuint, batch: &'a mut Batch, atlas: &'a mut Vec<Atlas>, current_atlas: &'a mut usize, program: &'a mut TextShaderProgram, } impl<'a> TextRenderApi<Batch> for RenderApi<'a> { fn batch(&mut self) -> &mut Batch { self.batch } fn render_batch(&mut self) { unsafe { gl::BufferSubData( gl::ARRAY_BUFFER, 0, self.batch.size() as isize, self.batch.instances.as_ptr() as *const _, ); } // Bind texture if necessary. if *self.active_tex != self.batch.tex() { unsafe { gl::BindTexture(gl::TEXTURE_2D, self.batch.tex()); } *self.active_tex = self.batch.tex(); } unsafe { self.program.set_rendering_pass(RenderingPass::Background); gl::DrawElementsInstanced( gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null(), self.batch.len() as GLsizei, ); self.program.set_rendering_pass(RenderingPass::SubpixelPass1); gl::DrawElementsInstanced( gl::TRIANGLES, 6, gl::UNSIGNED_INT, ptr::null(), self.batch.len() as GLsizei, ); } self.batch.clear(); } } impl<'a> LoadGlyph for RenderApi<'a> { fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph { Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized) } fn clear(&mut self) { Atlas::clear_atlas(self.atlas, self.current_atlas) } } impl<'a> Drop for RenderApi<'a> { fn drop(&mut self) { if !self.batch.is_empty() { self.render_batch(); } } } #[derive(Debug)] #[repr(C)] struct InstanceData { // Coords. col: u16, row: u16, // Glyph offset. left: i16, top: i16, // Glyph size. width: i16, height: i16, // UV offset. uv_left: f32, uv_bot: f32, // uv scale. uv_width: f32, uv_height: f32, // Color. r: u8, g: u8, b: u8, // Cell flags like multicolor or fullwidth character. cell_flags: RenderingGlyphFlags, // Background color. bg_r: u8, bg_g: u8, bg_b: u8, bg_a: u8, } #[derive(Debug, Default)] pub struct Batch { tex: GLuint, instances: Vec<InstanceData>, } impl TextRenderBatch for Batch { #[inline] fn tex(&self) -> GLuint { self.tex } #[inline] fn full(&self) -> bool { self.capacity() == self.len() } #[inline] fn is_empty(&self) -> bool { self.len() == 0 } fn add_item(&mut self, cell: &RenderableCell, glyph: &Glyph, _: &SizeInfo) { if self.is_empty() { self.tex = glyph.tex_id; } let mut cell_flags = RenderingGlyphFlags::empty(); cell_flags.set(RenderingGlyphFlags::COLORED, glyph.multicolor); cell_flags.set(RenderingGlyphFlags::WIDE_CHAR, cell.flags.contains(Flags::WIDE_CHAR)); self.instances.push(InstanceData { col: cell.point.column.0 as u16, row: cell.point.line as u16, top: glyph.top, left: glyph.left, width: glyph.width, height: glyph.height, uv_bot: glyph.uv_bot, uv_left: glyph.uv_left, uv_width: glyph.uv_width, uv_height: glyph.uv_height, r: cell.fg.r, g: cell.fg.g, b: cell.fg.b, cell_flags, bg_r: cell.bg.r, bg_g: cell.bg.g, bg_b: cell.bg.b, bg_a: (cell.bg_alpha * 255.0) as u8, }); } } impl Batch { #[inline] pub fn new() -> Self { Self { tex: 0, instances: Vec::with_capacity(BATCH_MAX) } } #[inline] pub fn len(&self) -> usize { self.instances.len() } #[inline] pub fn capacity(&self) -> usize { BATCH_MAX } #[inline] pub fn size(&self) -> usize { self.len() * size_of::<InstanceData>() } pub fn clear(&mut self) { self.tex = 0; self.instances.clear(); } } /// Text drawing program. /// /// Uniforms are prefixed with "u", and vertex attributes are prefixed with "a". #[derive(Debug)] pub struct TextShaderProgram { /// Shader program. program: ShaderProgram, /// Projection scale and offset uniform. u_projection: GLint, /// Cell dimensions (pixels). u_cell_dim: GLint, /// Background pass flag. /// /// Rendering is split into two passes; one for backgrounds, and one for text. u_rendering_pass: GLint, } impl TextShaderProgram { pub fn new(shader_version: ShaderVersion) -> Result<TextShaderProgram, Error> { let program = ShaderProgram::new(shader_version, None, TEXT_SHADER_V, TEXT_SHADER_F)?; Ok(Self { u_projection: program.get_uniform_location(cstr!("projection"))?, u_cell_dim: program.get_uniform_location(cstr!("cellDim"))?, u_rendering_pass: program.get_uniform_location(cstr!("renderingPass"))?, program, }) } fn set_term_uniforms(&self, props: &SizeInfo) { unsafe { gl::Uniform2f(self.u_cell_dim, props.cell_width(), props.cell_height()); } } fn set_rendering_pass(&self, rendering_pass: RenderingPass) { let value = match rendering_pass { RenderingPass::Background | RenderingPass::SubpixelPass1 => rendering_pass as i32, _ => unreachable!("provided pass is not supported in GLSL3 renderer"), }; unsafe { gl::Uniform1i(self.u_rendering_pass, value); } } } impl TextShader for TextShaderProgram { fn id(&self) -> GLuint { self.program.id() } fn projection_uniform(&self) -> GLint { self.u_projection } } ������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/text/glyph_cache.rs���������������������������������������������������0000644�0000000�0000000�00000024137�10461020230�0020107�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::collections::HashMap; use ahash::RandomState; use crossfont::{ Error as RasterizerError, FontDesc, FontKey, GlyphKey, Metrics, Rasterize, RasterizedGlyph, Rasterizer, Size, Slant, Style, Weight, }; use log::{error, info}; use unicode_width::UnicodeWidthChar; use crate::config::font::{Font, FontDescription}; use crate::config::ui_config::Delta; use crate::gl::types::*; use super::builtin_font; /// `LoadGlyph` allows for copying a rasterized glyph into graphics memory. pub trait LoadGlyph { /// Load the rasterized glyph into GPU memory. fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph; /// Clear any state accumulated from previous loaded glyphs. /// /// This can, for instance, be used to reset the texture Atlas. fn clear(&mut self); } #[derive(Copy, Clone, Debug)] pub struct Glyph { pub tex_id: GLuint, pub multicolor: bool, pub top: i16, pub left: i16, pub width: i16, pub height: i16, pub uv_bot: f32, pub uv_left: f32, pub uv_width: f32, pub uv_height: f32, } /// Naïve glyph cache. /// /// Currently only keyed by `char`, and thus not possible to hold different /// representations of the same code point. pub struct GlyphCache { /// Cache of buffered glyphs. cache: HashMap<GlyphKey, Glyph, RandomState>, /// Rasterizer for loading new glyphs. rasterizer: Rasterizer, /// Regular font. pub font_key: FontKey, /// Bold font. pub bold_key: FontKey, /// Italic font. pub italic_key: FontKey, /// Bold italic font. pub bold_italic_key: FontKey, /// Font size. pub font_size: crossfont::Size, /// Font offset. font_offset: Delta<i8>, /// Glyph offset. glyph_offset: Delta<i8>, /// Font metrics. metrics: Metrics, /// Whether to use the built-in font for box drawing characters. builtin_box_drawing: bool, } impl GlyphCache { pub fn new(mut rasterizer: Rasterizer, font: &Font) -> Result<GlyphCache, crossfont::Error> { let (regular, bold, italic, bold_italic) = Self::compute_font_keys(font, &mut rasterizer)?; // Need to load at least one glyph for the face before calling metrics. // The glyph requested here ('m' at the time of writing) has no special // meaning. rasterizer.get_glyph(GlyphKey { font_key: regular, character: 'm', size: font.size() })?; let metrics = rasterizer.metrics(regular, font.size())?; Ok(Self { cache: Default::default(), rasterizer, font_size: font.size(), font_key: regular, bold_key: bold, italic_key: italic, bold_italic_key: bold_italic, font_offset: font.offset, glyph_offset: font.glyph_offset, metrics, builtin_box_drawing: font.builtin_box_drawing, }) } fn load_glyphs_for_font<L: LoadGlyph>(&mut self, font: FontKey, loader: &mut L) { let size = self.font_size; // Cache all ascii characters. for i in 32u8..=126u8 { self.get(GlyphKey { font_key: font, character: i as char, size }, loader, true); } } /// Computes font keys for (Regular, Bold, Italic, Bold Italic). fn compute_font_keys( font: &Font, rasterizer: &mut Rasterizer, ) -> Result<(FontKey, FontKey, FontKey, FontKey), crossfont::Error> { let size = font.size(); // Load regular font. let regular_desc = Self::make_desc(font.normal(), Slant::Normal, Weight::Normal); let regular = Self::load_regular_font(rasterizer, ®ular_desc, size)?; // Helper to load a description if it is not the `regular_desc`. let mut load_or_regular = |desc: FontDesc| { if desc == regular_desc { regular } else { rasterizer.load_font(&desc, size).unwrap_or(regular) } }; // Load bold font. let bold_desc = Self::make_desc(&font.bold(), Slant::Normal, Weight::Bold); let bold = load_or_regular(bold_desc); // Load italic font. let italic_desc = Self::make_desc(&font.italic(), Slant::Italic, Weight::Normal); let italic = load_or_regular(italic_desc); // Load bold italic font. let bold_italic_desc = Self::make_desc(&font.bold_italic(), Slant::Italic, Weight::Bold); let bold_italic = load_or_regular(bold_italic_desc); Ok((regular, bold, italic, bold_italic)) } fn load_regular_font( rasterizer: &mut Rasterizer, description: &FontDesc, size: Size, ) -> Result<FontKey, crossfont::Error> { match rasterizer.load_font(description, size) { Ok(font) => Ok(font), Err(err) => { error!("{}", err); let fallback_desc = Self::make_desc(Font::default().normal(), Slant::Normal, Weight::Normal); rasterizer.load_font(&fallback_desc, size) }, } } fn make_desc(desc: &FontDescription, slant: Slant, weight: Weight) -> FontDesc { let style = if let Some(ref spec) = desc.style { Style::Specific(spec.to_owned()) } else { Style::Description { slant, weight } }; FontDesc::new(desc.family.clone(), style) } /// Get a glyph from the font. /// /// If the glyph has never been loaded before, it will be rasterized and inserted into the /// cache. /// /// # Errors /// /// This will fail when the glyph could not be rasterized. Usually this is due to the glyph /// not being present in any font. pub fn get<L: ?Sized>( &mut self, glyph_key: GlyphKey, loader: &mut L, show_missing: bool, ) -> Glyph where L: LoadGlyph, { // Try to load glyph from cache. if let Some(glyph) = self.cache.get(&glyph_key) { return *glyph; }; // Rasterize the glyph using the built-in font for special characters or the user's font // for everything else. let rasterized = self .builtin_box_drawing .then(|| { builtin_font::builtin_glyph( glyph_key.character, &self.metrics, &self.font_offset, &self.glyph_offset, ) }) .flatten() .map_or_else(|| self.rasterizer.get_glyph(glyph_key), Ok); let glyph = match rasterized { Ok(rasterized) => self.load_glyph(loader, rasterized), // Load fallback glyph. Err(RasterizerError::MissingGlyph(rasterized)) if show_missing => { // Use `\0` as "missing" glyph to cache it only once. let missing_key = GlyphKey { character: '\0', ..glyph_key }; if let Some(glyph) = self.cache.get(&missing_key) { *glyph } else { // If no missing glyph was loaded yet, insert it as `\0`. let glyph = self.load_glyph(loader, rasterized); self.cache.insert(missing_key, glyph); glyph } }, Err(_) => self.load_glyph(loader, Default::default()), }; // Cache rasterized glyph. *self.cache.entry(glyph_key).or_insert(glyph) } /// Load glyph into the atlas. /// /// This will apply all transforms defined for the glyph cache to the rasterized glyph before pub fn load_glyph<L: ?Sized>(&self, loader: &mut L, mut glyph: RasterizedGlyph) -> Glyph where L: LoadGlyph, { glyph.left += i32::from(self.glyph_offset.x); glyph.top += i32::from(self.glyph_offset.y); glyph.top -= self.metrics.descent as i32; // The metrics of zero-width characters are based on rendering // the character after the current cell, with the anchor at the // right side of the preceding character. Since we render the // zero-width characters inside the preceding character, the // anchor has been moved to the right by one cell. if glyph.character.width() == Some(0) { glyph.left += self.metrics.average_advance as i32; } // Add glyph to cache. loader.load_glyph(&glyph) } /// Reset currently cached data in both GL and the registry to default state. pub fn reset_glyph_cache<L: LoadGlyph>(&mut self, loader: &mut L) { loader.clear(); self.cache = Default::default(); self.load_common_glyphs(loader); } /// Update the inner font size. /// /// NOTE: To reload the renderers's fonts [`Self::reset_glyph_cache`] should be called /// afterwards. pub fn update_font_size(&mut self, font: &Font) -> Result<(), crossfont::Error> { // Update dpi scaling. self.font_offset = font.offset; self.glyph_offset = font.glyph_offset; // Recompute font keys. let (regular, bold, italic, bold_italic) = Self::compute_font_keys(font, &mut self.rasterizer)?; self.rasterizer.get_glyph(GlyphKey { font_key: regular, character: 'm', size: font.size(), })?; let metrics = self.rasterizer.metrics(regular, font.size())?; info!("Font size changed to {:?} px", font.size().as_px()); self.font_size = font.size(); self.font_key = regular; self.bold_key = bold; self.italic_key = italic; self.bold_italic_key = bold_italic; self.metrics = metrics; self.builtin_box_drawing = font.builtin_box_drawing; Ok(()) } pub fn font_metrics(&self) -> crossfont::Metrics { self.metrics } /// Prefetch glyphs that are almost guaranteed to be loaded anyways. pub fn load_common_glyphs<L: LoadGlyph>(&mut self, loader: &mut L) { self.load_glyphs_for_font(self.font_key, loader); self.load_glyphs_for_font(self.bold_key, loader); self.load_glyphs_for_font(self.italic_key, loader); self.load_glyphs_for_font(self.bold_italic_key, loader); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/renderer/text/mod.rs�����������������������������������������������������������0000644�0000000�0000000�00000014252�10461020230�0016415�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use bitflags::bitflags; use crossfont::{GlyphKey, RasterizedGlyph}; use alacritty_terminal::term::cell::Flags; use crate::display::content::RenderableCell; use crate::display::SizeInfo; use crate::gl; use crate::gl::types::*; mod atlas; mod builtin_font; mod gles2; mod glsl3; pub mod glyph_cache; use atlas::Atlas; pub use gles2::Gles2Renderer; pub use glsl3::Glsl3Renderer; pub use glyph_cache::GlyphCache; use glyph_cache::{Glyph, LoadGlyph}; // NOTE: These flags must be in sync with their usage in the text.*.glsl shaders. bitflags! { #[repr(C)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] struct RenderingGlyphFlags: u8 { const COLORED = 0b0000_0001; const WIDE_CHAR = 0b0000_0010; } } /// Rendering passes, for both GLES2 and GLSL3 renderer. #[repr(u8)] enum RenderingPass { /// Rendering pass used to render background color in text shaders. Background = 0, /// The first pass to render text with both GLES2 and GLSL3 renderers. SubpixelPass1 = 1, /// The second pass to render text with GLES2 renderer. SubpixelPass2 = 2, /// The third pass to render text with GLES2 renderer. SubpixelPass3 = 3, } pub trait TextRenderer<'a> { type Shader: TextShader; type RenderBatch: TextRenderBatch; type RenderApi: TextRenderApi<Self::RenderBatch>; /// Get loader API for the renderer. fn loader_api(&mut self) -> LoaderApi<'_>; /// Draw cells. fn draw_cells<'b: 'a, I: Iterator<Item = RenderableCell>>( &'b mut self, size_info: &'b SizeInfo, glyph_cache: &'a mut GlyphCache, cells: I, ) { self.with_api(size_info, |mut api| { for cell in cells { api.draw_cell(cell, glyph_cache, size_info); } }) } fn with_api<'b: 'a, F, T>(&'b mut self, size_info: &'b SizeInfo, func: F) -> T where F: FnOnce(Self::RenderApi) -> T; fn program(&self) -> &Self::Shader; /// Resize the text rendering. fn resize(&self, size: &SizeInfo) { unsafe { let program = self.program(); gl::UseProgram(program.id()); update_projection(program.projection_uniform(), size); gl::UseProgram(0); } } /// Invoke renderer with the loader. fn with_loader<F: FnOnce(LoaderApi<'_>) -> T, T>(&mut self, func: F) -> T { unsafe { gl::ActiveTexture(gl::TEXTURE0); } func(self.loader_api()) } } pub trait TextRenderBatch { /// Check if `Batch` is empty. fn is_empty(&self) -> bool; /// Check whether the `Batch` is full. fn full(&self) -> bool; /// Get texture `Batch` is using. fn tex(&self) -> GLuint; /// Add item to the batch. fn add_item(&mut self, cell: &RenderableCell, glyph: &Glyph, size_info: &SizeInfo); } pub trait TextRenderApi<T: TextRenderBatch>: LoadGlyph { /// Get `Batch` the api is using. fn batch(&mut self) -> &mut T; /// Render the underlying data. fn render_batch(&mut self); /// Add item to the rendering queue. #[inline] fn add_render_item(&mut self, cell: &RenderableCell, glyph: &Glyph, size_info: &SizeInfo) { // Flush batch if tex changing. if !self.batch().is_empty() && self.batch().tex() != glyph.tex_id { self.render_batch(); } self.batch().add_item(cell, glyph, size_info); // Render batch and clear if it's full. if self.batch().full() { self.render_batch(); } } /// Draw cell. fn draw_cell( &mut self, mut cell: RenderableCell, glyph_cache: &mut GlyphCache, size_info: &SizeInfo, ) { // Get font key for cell. let font_key = match cell.flags & Flags::BOLD_ITALIC { Flags::BOLD_ITALIC => glyph_cache.bold_italic_key, Flags::ITALIC => glyph_cache.italic_key, Flags::BOLD => glyph_cache.bold_key, _ => glyph_cache.font_key, }; // Ignore hidden cells and render tabs as spaces to prevent font issues. let hidden = cell.flags.contains(Flags::HIDDEN); if cell.character == '\t' || hidden { cell.character = ' '; } let mut glyph_key = GlyphKey { font_key, size: glyph_cache.font_size, character: cell.character }; // Add cell to batch. let glyph = glyph_cache.get(glyph_key, self, true); self.add_render_item(&cell, &glyph, size_info); // Render visible zero-width characters. if let Some(zerowidth) = cell.extra.as_mut().and_then(|extra| extra.zerowidth.take().filter(|_| !hidden)) { for character in zerowidth { glyph_key.character = character; let glyph = glyph_cache.get(glyph_key, self, false); self.add_render_item(&cell, &glyph, size_info); } } } } pub trait TextShader { fn id(&self) -> GLuint; /// Id of the projection uniform. fn projection_uniform(&self) -> GLint; } #[derive(Debug)] pub struct LoaderApi<'a> { active_tex: &'a mut GLuint, atlas: &'a mut Vec<Atlas>, current_atlas: &'a mut usize, } impl<'a> LoadGlyph for LoaderApi<'a> { fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph { Atlas::load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized) } fn clear(&mut self) { Atlas::clear_atlas(self.atlas, self.current_atlas) } } fn update_projection(u_projection: GLint, size: &SizeInfo) { let width = size.width(); let height = size.height(); let padding_x = size.padding_x(); let padding_y = size.padding_y(); // Bounds check. if (width as u32) < (2 * padding_x as u32) || (height as u32) < (2 * padding_y as u32) { return; } // Compute scale and offset factors, from pixel to ndc space. Y is inverted. // [0, width - 2 * padding_x] to [-1, 1] // [height - 2 * padding_y, 0] to [-1, 1] let scale_x = 2. / (width - 2. * padding_x); let scale_y = -2. / (height - 2. * padding_y); let offset_x = -1.; let offset_y = 1.; unsafe { gl::Uniform4f(u_projection, offset_x, offset_y, scale_x, scale_y); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/scheduler.rs�������������������������������������������������������������������0000644�0000000�0000000�00000006241�10461020230�0015021�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Scheduler for emitting events at a specific time in the future. use std::collections::VecDeque; use std::time::{Duration, Instant}; use winit::event_loop::EventLoopProxy; use winit::window::WindowId; use crate::event::Event; /// ID uniquely identifying a timer. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct TimerId { topic: Topic, window_id: WindowId, } impl TimerId { pub fn new(topic: Topic, window_id: WindowId) -> Self { Self { topic, window_id } } } /// Available timer topics. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Topic { SelectionScrolling, DelayedSearch, BlinkCursor, BlinkTimeout, Frame, } /// Event scheduled to be emitted at a specific time. pub struct Timer { pub deadline: Instant, pub event: Event, pub id: TimerId, interval: Option<Duration>, } /// Scheduler tracking all pending timers. pub struct Scheduler { timers: VecDeque<Timer>, event_proxy: EventLoopProxy<Event>, } impl Scheduler { pub fn new(event_proxy: EventLoopProxy<Event>) -> Self { Self { timers: VecDeque::new(), event_proxy } } /// Process all pending timers. /// /// If there are still timers pending after all ready events have been processed, the closest /// pending deadline will be returned. pub fn update(&mut self) -> Option<Instant> { let now = Instant::now(); while !self.timers.is_empty() && self.timers[0].deadline <= now { if let Some(timer) = self.timers.pop_front() { // Automatically repeat the event. if let Some(interval) = timer.interval { self.schedule(timer.event.clone(), interval, true, timer.id); } let _ = self.event_proxy.send_event(timer.event); } } self.timers.front().map(|timer| timer.deadline) } /// Schedule a new event. pub fn schedule(&mut self, event: Event, interval: Duration, repeat: bool, timer_id: TimerId) { let deadline = Instant::now() + interval; // Get insert position in the schedule. let index = self .timers .iter() .position(|timer| timer.deadline > deadline) .unwrap_or(self.timers.len()); // Set the automatic event repeat rate. let interval = if repeat { Some(interval) } else { None }; self.timers.insert(index, Timer { interval, deadline, event, id: timer_id }); } /// Cancel a scheduled event. pub fn unschedule(&mut self, id: TimerId) -> Option<Timer> { let index = self.timers.iter().position(|timer| timer.id == id)?; self.timers.remove(index) } /// Check if a timer is already scheduled. pub fn scheduled(&mut self, id: TimerId) -> bool { self.timers.iter().any(|timer| timer.id == id) } /// Remove all timers scheduled for a window. /// /// This must be called when a window is removed to ensure that timers on intervals do not /// stick around forever and cause a memory leak. pub fn unschedule_window(&mut self, window_id: WindowId) { self.timers.retain(|timer| timer.id.window_id != window_id); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/string.rs����������������������������������������������������������������������0000644�0000000�0000000�00000022457�10461020230�0014360�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������use std::cmp::Ordering; use std::iter::Skip; use std::str::Chars; use unicode_width::UnicodeWidthChar; /// The action performed by [`StrShortener`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TextAction { /// Yield a spacer. Spacer, /// Terminate state reached. Terminate, /// Yield a shortener. Shortener, /// Yield a character. Char, } /// The direction which we should shorten. #[derive(Clone, Copy, PartialEq, Eq)] pub enum ShortenDirection { /// Shorten to the start of the string. Left, /// Shorten to the end of the string. Right, } /// Iterator that yield shortened version of the text. pub struct StrShortener<'a> { chars: Skip<Chars<'a>>, accumulated_len: usize, max_width: usize, direction: ShortenDirection, shortener: Option<char>, text_action: TextAction, } impl<'a> StrShortener<'a> { pub fn new( text: &'a str, max_width: usize, direction: ShortenDirection, mut shortener: Option<char>, ) -> Self { if text.is_empty() { // If we don't have any text don't produce a shortener for it. let _ = shortener.take(); } if direction == ShortenDirection::Right { return Self { chars: text.chars().skip(0), accumulated_len: 0, text_action: TextAction::Char, max_width, direction, shortener, }; } let mut offset = 0; let mut current_len = 0; let mut iter = text.chars().rev().enumerate(); while let Some((idx, ch)) = iter.next() { let ch_width = ch.width().unwrap_or(1); current_len += ch_width; match current_len.cmp(&max_width) { // We can only be here if we've faced wide character or we've already // handled equality situation. Anyway, break. Ordering::Greater => break, Ordering::Equal => { if shortener.is_some() && iter.clone().next().is_some() { // We have one more character after, shortener will accumulate for // the `current_len`. break; } else { // The match is exact, consume shortener. let _ = shortener.take(); } }, Ordering::Less => (), } offset = idx + 1; } // Consume the iterator to count the number of characters in it. let num_chars = iter.last().map_or(offset, |(idx, _)| idx + 1); let skip_chars = num_chars - offset; let text_action = if current_len < max_width || shortener.is_none() { TextAction::Char } else { TextAction::Shortener }; let chars = text.chars().skip(skip_chars); Self { chars, accumulated_len: 0, text_action, max_width, direction, shortener } } } impl<'a> Iterator for StrShortener<'a> { type Item = char; fn next(&mut self) -> Option<Self::Item> { match self.text_action { TextAction::Spacer => { self.text_action = TextAction::Char; Some(' ') }, TextAction::Terminate => { // We've reached the termination state. None }, TextAction::Shortener => { // When we shorten from the left we yield the shortener first and process the rest. self.text_action = if self.direction == ShortenDirection::Left { TextAction::Char } else { TextAction::Terminate }; // Consume the shortener to avoid yielding it later when shortening left. self.shortener.take() }, TextAction::Char => { let ch = self.chars.next()?; let ch_width = ch.width().unwrap_or(1); // Advance width. self.accumulated_len += ch_width; if self.accumulated_len > self.max_width { self.text_action = TextAction::Terminate; return self.shortener; } else if self.accumulated_len == self.max_width && self.shortener.is_some() { // Check if we have a next char. let has_next = self.chars.clone().next().is_some(); // We should terminate after that. self.text_action = TextAction::Terminate; return has_next.then(|| self.shortener.unwrap()).or(Some(ch)); } // Add a spacer for wide character. if ch_width == 2 { self.text_action = TextAction::Spacer; } Some(ch) }, } } } #[cfg(test)] mod tests { use super::*; #[test] fn into_shortened_with_shortener() { let s = "Hello"; let len = s.chars().count(); assert_eq!( "", StrShortener::new("", 1, ShortenDirection::Left, Some('.')).collect::<String>() ); assert_eq!( ".", StrShortener::new(s, 1, ShortenDirection::Right, Some('.')).collect::<String>() ); assert_eq!( ".", StrShortener::new(s, 1, ShortenDirection::Left, Some('.')).collect::<String>() ); assert_eq!( "H.", StrShortener::new(s, 2, ShortenDirection::Right, Some('.')).collect::<String>() ); assert_eq!( ".o", StrShortener::new(s, 2, ShortenDirection::Left, Some('.')).collect::<String>() ); assert_eq!( s, &StrShortener::new(s, len * 2, ShortenDirection::Right, Some('.')).collect::<String>() ); assert_eq!( s, &StrShortener::new(s, len * 2, ShortenDirection::Left, Some('.')).collect::<String>() ); let s = "ちはP"; let len = 2 + 2 + 1; assert_eq!( ".", &StrShortener::new(s, 1, ShortenDirection::Right, Some('.')).collect::<String>() ); assert_eq!( &".", &StrShortener::new(s, 1, ShortenDirection::Left, Some('.')).collect::<String>() ); assert_eq!( ".", &StrShortener::new(s, 2, ShortenDirection::Right, Some('.')).collect::<String>() ); assert_eq!( ".P", &StrShortener::new(s, 2, ShortenDirection::Left, Some('.')).collect::<String>() ); assert_eq!( "ち .", &StrShortener::new(s, 3, ShortenDirection::Right, Some('.')).collect::<String>() ); assert_eq!( ".P", &StrShortener::new(s, 3, ShortenDirection::Left, Some('.')).collect::<String>() ); assert_eq!( "ち は P", &StrShortener::new(s, len * 2, ShortenDirection::Left, Some('.')).collect::<String>() ); assert_eq!( "ち は P", &StrShortener::new(s, len * 2, ShortenDirection::Right, Some('.')).collect::<String>() ); } #[test] fn into_shortened_without_shortener() { let s = "Hello"; assert_eq!("", StrShortener::new("", 1, ShortenDirection::Left, None).collect::<String>()); assert_eq!( "H", &StrShortener::new(s, 1, ShortenDirection::Right, None).collect::<String>() ); assert_eq!("o", &StrShortener::new(s, 1, ShortenDirection::Left, None).collect::<String>()); assert_eq!( "He", &StrShortener::new(s, 2, ShortenDirection::Right, None).collect::<String>() ); assert_eq!( "lo", &StrShortener::new(s, 2, ShortenDirection::Left, None).collect::<String>() ); assert_eq!( &s, &StrShortener::new(s, s.len(), ShortenDirection::Right, None).collect::<String>() ); assert_eq!( &s, &StrShortener::new(s, s.len(), ShortenDirection::Left, None).collect::<String>() ); let s = "こJんにちはP"; let len = 2 + 1 + 2 + 2 + 2 + 2 + 1; assert_eq!("", &StrShortener::new(s, 1, ShortenDirection::Right, None).collect::<String>()); assert_eq!("P", &StrShortener::new(s, 1, ShortenDirection::Left, None).collect::<String>()); assert_eq!( "こ ", &StrShortener::new(s, 2, ShortenDirection::Right, None).collect::<String>() ); assert_eq!("P", &StrShortener::new(s, 2, ShortenDirection::Left, None).collect::<String>()); assert_eq!( "こ J", &StrShortener::new(s, 3, ShortenDirection::Right, None).collect::<String>() ); assert_eq!( "は P", &StrShortener::new(s, 3, ShortenDirection::Left, None).collect::<String>() ); assert_eq!( "こ Jん に ち は P", &StrShortener::new(s, len, ShortenDirection::Left, None).collect::<String>() ); assert_eq!( "こ Jん に ち は P", &StrShortener::new(s, len, ShortenDirection::Right, None).collect::<String>() ); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/src/window_context.rs��������������������������������������������������������������0000644�0000000�0000000�00000047756�10461020230�0016136�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//! Terminal window context. use std::error::Error; use std::fs::File; use std::io::Write; use std::mem; #[cfg(not(windows))] use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; use std::sync::Arc; use glutin::config::GetGlConfig; use glutin::display::GetGlDisplay; #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] use glutin::platform::x11::X11GlConfigExt; use log::info; use raw_window_handle::HasRawDisplayHandle; use serde_json as json; use winit::event::{Event as WinitEvent, Modifiers, WindowEvent}; use winit::event_loop::{EventLoopProxy, EventLoopWindowTarget}; use winit::window::WindowId; use alacritty_terminal::event::Event as TerminalEvent; use alacritty_terminal::event_loop::{EventLoop as PtyEventLoop, Msg, Notifier}; use alacritty_terminal::grid::{Dimensions, Scroll}; use alacritty_terminal::index::Direction; use alacritty_terminal::sync::FairMutex; use alacritty_terminal::term::test::TermSize; use alacritty_terminal::term::{Term, TermMode}; use alacritty_terminal::tty; use crate::cli::{ParsedOptions, WindowOptions}; use crate::clipboard::Clipboard; use crate::config::UiConfig; use crate::display::window::Window; use crate::display::Display; use crate::event::{ ActionContext, Event, EventProxy, InlineSearchState, Mouse, SearchState, TouchPurpose, }; #[cfg(unix)] use crate::logging::LOG_TARGET_IPC_CONFIG; use crate::message_bar::MessageBuffer; use crate::scheduler::Scheduler; use crate::{input, renderer}; /// Event context for one individual Alacritty window. pub struct WindowContext { pub message_buffer: MessageBuffer, pub display: Display, pub dirty: bool, event_queue: Vec<WinitEvent<Event>>, terminal: Arc<FairMutex<Term<EventProxy>>>, cursor_blink_timed_out: bool, modifiers: Modifiers, inline_search_state: InlineSearchState, search_state: SearchState, notifier: Notifier, mouse: Mouse, touch: TouchPurpose, occluded: bool, preserve_title: bool, #[cfg(not(windows))] master_fd: RawFd, #[cfg(not(windows))] shell_pid: u32, window_config: ParsedOptions, config: Rc<UiConfig>, } impl WindowContext { /// Create initial window context that does bootstrapping the graphics API we're going to use. pub fn initial( event_loop: &EventLoopWindowTarget<Event>, proxy: EventLoopProxy<Event>, config: Rc<UiConfig>, options: WindowOptions, ) -> Result<Self, Box<dyn Error>> { let raw_display_handle = event_loop.raw_display_handle(); let mut identity = config.window.identity.clone(); options.window_identity.override_identity_config(&mut identity); // Windows has different order of GL platform initialization compared to any other platform; // it requires the window first. #[cfg(windows)] let window = Window::new(event_loop, &config, &identity)?; #[cfg(windows)] let raw_window_handle = Some(window.raw_window_handle()); #[cfg(not(windows))] let raw_window_handle = None; let gl_display = renderer::platform::create_gl_display( raw_display_handle, raw_window_handle, config.debug.prefer_egl, )?; let gl_config = renderer::platform::pick_gl_config(&gl_display, raw_window_handle)?; #[cfg(not(windows))] let window = Window::new( event_loop, &config, &identity, #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] gl_config.x11_visual(), #[cfg(target_os = "macos")] &options.window_tabbing_id, )?; // Create context. let gl_context = renderer::platform::create_gl_context(&gl_display, &gl_config, raw_window_handle)?; let display = Display::new(window, gl_context, &config, false)?; Self::new(display, config, options, proxy) } /// Create additional context with the graphics platform other windows are using. pub fn additional( &self, event_loop: &EventLoopWindowTarget<Event>, proxy: EventLoopProxy<Event>, config: Rc<UiConfig>, options: WindowOptions, config_overrides: ParsedOptions, ) -> Result<Self, Box<dyn Error>> { // Get any window and take its GL config and display to build a new context. let (gl_display, gl_config) = { let gl_context = self.display.gl_context(); (gl_context.display(), gl_context.config()) }; let mut identity = config.window.identity.clone(); options.window_identity.override_identity_config(&mut identity); let window = Window::new( event_loop, &config, &identity, #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] gl_config.x11_visual(), #[cfg(target_os = "macos")] &options.window_tabbing_id, )?; // Create context. let raw_window_handle = window.raw_window_handle(); let gl_context = renderer::platform::create_gl_context( &gl_display, &gl_config, Some(raw_window_handle), )?; // Check if new window will be opened as a tab. #[cfg(target_os = "macos")] let tabbed = options.window_tabbing_id.is_some(); #[cfg(not(target_os = "macos"))] let tabbed = false; let display = Display::new(window, gl_context, &config, tabbed)?; let mut window_context = Self::new(display, config, options, proxy)?; // Set the config overrides at startup. // // These are already applied to `config`, so no update is necessary. window_context.window_config = config_overrides; Ok(window_context) } /// Create a new terminal window context. fn new( display: Display, config: Rc<UiConfig>, options: WindowOptions, proxy: EventLoopProxy<Event>, ) -> Result<Self, Box<dyn Error>> { let mut pty_config = config.pty_config(); options.terminal_options.override_pty_config(&mut pty_config); let preserve_title = options.window_identity.title.is_some(); info!( "PTY dimensions: {:?} x {:?}", display.size_info.screen_lines(), display.size_info.columns() ); let event_proxy = EventProxy::new(proxy, display.window.id()); // Create the terminal. // // This object contains all of the state about what's being displayed. It's // wrapped in a clonable mutex since both the I/O loop and display need to // access it. let terminal = Term::new(config.term_options(), &display.size_info, event_proxy.clone()); let terminal = Arc::new(FairMutex::new(terminal)); // Create the PTY. // // The PTY forks a process to run the shell on the slave side of the // pseudoterminal. A file descriptor for the master side is retained for // reading/writing to the shell. let pty = tty::new(&pty_config, display.size_info.into(), display.window.id().into())?; #[cfg(not(windows))] let master_fd = pty.file().as_raw_fd(); #[cfg(not(windows))] let shell_pid = pty.child().id(); // Create the pseudoterminal I/O loop. // // PTY I/O is ran on another thread as to not occupy cycles used by the // renderer and input processing. Note that access to the terminal state is // synchronized since the I/O loop updates the state, and the display // consumes it periodically. let event_loop = PtyEventLoop::new( Arc::clone(&terminal), event_proxy.clone(), pty, pty_config.hold, config.debug.ref_test, )?; // The event loop channel allows write requests from the event processor // to be sent to the pty loop and ultimately written to the pty. let loop_tx = event_loop.channel(); // Kick off the I/O thread. let _io_thread = event_loop.spawn(); // Start cursor blinking, in case `Focused` isn't sent on startup. if config.cursor.style().blinking { event_proxy.send_event(TerminalEvent::CursorBlinkingChange.into()); } // Create context for the Alacritty window. Ok(WindowContext { preserve_title, terminal, display, #[cfg(not(windows))] master_fd, #[cfg(not(windows))] shell_pid, config, notifier: Notifier(loop_tx), cursor_blink_timed_out: Default::default(), inline_search_state: Default::default(), message_buffer: Default::default(), window_config: Default::default(), search_state: Default::default(), event_queue: Default::default(), modifiers: Default::default(), occluded: Default::default(), mouse: Default::default(), touch: Default::default(), dirty: Default::default(), }) } /// Update the terminal window to the latest config. pub fn update_config(&mut self, new_config: Rc<UiConfig>) { let old_config = mem::replace(&mut self.config, new_config); // Apply ipc config if there are overrides. self.config = self.window_config.override_config_rc(self.config.clone()); self.display.update_config(&self.config); self.terminal.lock().set_options(self.config.term_options()); // Reload cursor if its thickness has changed. if (old_config.cursor.thickness() - self.config.cursor.thickness()).abs() > f32::EPSILON { self.display.pending_update.set_cursor_dirty(); } if old_config.font != self.config.font { let scale_factor = self.display.window.scale_factor as f32; // Do not update font size if it has been changed at runtime. if self.display.font_size == old_config.font.size().scale(scale_factor) { self.display.font_size = self.config.font.size().scale(scale_factor); } let font = self.config.font.clone().with_size(self.display.font_size); self.display.pending_update.set_font(font); } // Always reload the theme to account for auto-theme switching. self.display.window.set_theme(self.config.window.theme()); // Update display if either padding options or resize increments were changed. let window_config = &old_config.window; if window_config.padding(1.) != self.config.window.padding(1.) || window_config.dynamic_padding != self.config.window.dynamic_padding || window_config.resize_increments != self.config.window.resize_increments { self.display.pending_update.dirty = true; } // Update title on config reload according to the following table. // // │cli │ dynamic_title │ current_title == old_config ││ set_title │ // │ Y │ _ │ _ ││ N │ // │ N │ Y │ Y ││ Y │ // │ N │ Y │ N ││ N │ // │ N │ N │ _ ││ Y │ if !self.preserve_title && (!self.config.window.dynamic_title || self.display.window.title() == old_config.window.identity.title) { self.display.window.set_title(self.config.window.identity.title.clone()); } let opaque = self.config.window_opacity() >= 1.; // Disable shadows for transparent windows on macOS. #[cfg(target_os = "macos")] self.display.window.set_has_shadow(opaque); #[cfg(target_os = "macos")] self.display.window.set_option_as_alt(self.config.window.option_as_alt()); // Change opacity and blur state. self.display.window.set_transparent(!opaque); self.display.window.set_blur(self.config.window.blur); // Update hint keys. self.display.hint_state.update_alphabet(self.config.hints.alphabet()); // Update cursor blinking. let event = Event::new(TerminalEvent::CursorBlinkingChange.into(), None); self.event_queue.push(event.into()); self.dirty = true; } /// Clear the window config overrides. #[cfg(unix)] pub fn reset_window_config(&mut self, config: Rc<UiConfig>) { // Clear previous window errors. self.message_buffer.remove_target(LOG_TARGET_IPC_CONFIG); self.window_config.clear(); // Reload current config to pull new IPC config. self.update_config(config); } /// Add new window config overrides. #[cfg(unix)] pub fn add_window_config(&mut self, config: Rc<UiConfig>, options: &ParsedOptions) { // Clear previous window errors. self.message_buffer.remove_target(LOG_TARGET_IPC_CONFIG); self.window_config.extend_from_slice(options); // Reload current config to pull new IPC config. self.update_config(config); } /// Draw the window. pub fn draw(&mut self, scheduler: &mut Scheduler) { self.display.window.requested_redraw = false; if self.occluded { return; } self.dirty = false; // Force the display to process any pending display update. self.display.process_renderer_update(); // Request immediate re-draw if visual bell animation is not finished yet. if !self.display.visual_bell.completed() { // We can get an OS redraw which bypasses alacritty's frame throttling, thus // marking the window as dirty when we don't have frame yet. if self.display.window.has_frame { self.display.window.request_redraw(); } else { self.dirty = true; } } // Redraw the window. let terminal = self.terminal.lock(); self.display.draw( terminal, scheduler, &self.message_buffer, &self.config, &mut self.search_state, ); } /// Process events for this terminal window. pub fn handle_event( &mut self, event_loop: &EventLoopWindowTarget<Event>, event_proxy: &EventLoopProxy<Event>, clipboard: &mut Clipboard, scheduler: &mut Scheduler, event: WinitEvent<Event>, ) { match event { WinitEvent::AboutToWait | WinitEvent::WindowEvent { event: WindowEvent::RedrawRequested, .. } => { // Skip further event handling with no staged updates. if self.event_queue.is_empty() { return; } // Continue to process all pending events. }, event => { self.event_queue.push(event); return; }, } let mut terminal = self.terminal.lock(); let old_is_searching = self.search_state.history_index.is_some(); let context = ActionContext { cursor_blink_timed_out: &mut self.cursor_blink_timed_out, message_buffer: &mut self.message_buffer, inline_search_state: &mut self.inline_search_state, search_state: &mut self.search_state, modifiers: &mut self.modifiers, notifier: &mut self.notifier, display: &mut self.display, mouse: &mut self.mouse, touch: &mut self.touch, dirty: &mut self.dirty, occluded: &mut self.occluded, terminal: &mut terminal, #[cfg(not(windows))] master_fd: self.master_fd, #[cfg(not(windows))] shell_pid: self.shell_pid, preserve_title: self.preserve_title, config: &self.config, event_proxy, event_loop, clipboard, scheduler, }; let mut processor = input::Processor::new(context); for event in self.event_queue.drain(..) { processor.handle_event(event); } // Process DisplayUpdate events. if self.display.pending_update.dirty { Self::submit_display_update( &mut terminal, &mut self.display, &mut self.notifier, &self.message_buffer, &mut self.search_state, old_is_searching, &self.config, ); self.dirty = true; } if self.dirty || self.mouse.hint_highlight_dirty { self.dirty |= self.display.update_highlighted_hints( &terminal, &self.config, &self.mouse, self.modifiers.state(), ); self.mouse.hint_highlight_dirty = false; } // Don't call `request_redraw` when event is `RedrawRequested` since the `dirty` flag // represents the current frame, but redraw is for the next frame. if self.dirty && self.display.window.has_frame && !self.occluded && !matches!(event, WinitEvent::WindowEvent { event: WindowEvent::RedrawRequested, .. }) { self.display.window.request_redraw(); } } /// ID of this terminal context. pub fn id(&self) -> WindowId { self.display.window.id() } /// Write the ref test results to the disk. pub fn write_ref_test_results(&self) { // Dump grid state. let mut grid = self.terminal.lock().grid().clone(); grid.initialize_all(); grid.truncate(); let serialized_grid = json::to_string(&grid).expect("serialize grid"); let size_info = &self.display.size_info; let size = TermSize::new(size_info.columns(), size_info.screen_lines()); let serialized_size = json::to_string(&size).expect("serialize size"); let serialized_config = format!("{{\"history_size\":{}}}", grid.history_size()); File::create("./grid.json") .and_then(|mut f| f.write_all(serialized_grid.as_bytes())) .expect("write grid.json"); File::create("./size.json") .and_then(|mut f| f.write_all(serialized_size.as_bytes())) .expect("write size.json"); File::create("./config.json") .and_then(|mut f| f.write_all(serialized_config.as_bytes())) .expect("write config.json"); } /// Submit the pending changes to the `Display`. fn submit_display_update( terminal: &mut Term<EventProxy>, display: &mut Display, notifier: &mut Notifier, message_buffer: &MessageBuffer, search_state: &mut SearchState, old_is_searching: bool, config: &UiConfig, ) { // Compute cursor positions before resize. let num_lines = terminal.screen_lines(); let cursor_at_bottom = terminal.grid().cursor.point.line + 1 == num_lines; let origin_at_bottom = if terminal.mode().contains(TermMode::VI) { terminal.vi_mode_cursor.point.line == num_lines - 1 } else { search_state.direction == Direction::Left }; display.handle_update(terminal, notifier, message_buffer, search_state, config); let new_is_searching = search_state.history_index.is_some(); if !old_is_searching && new_is_searching { // Scroll on search start to make sure origin is visible with minimal viewport motion. let display_offset = terminal.grid().display_offset(); if display_offset == 0 && cursor_at_bottom && !origin_at_bottom { terminal.scroll_display(Scroll::Delta(1)); } else if display_offset != 0 && origin_at_bottom { terminal.scroll_display(Scroll::Delta(-1)); } } } } impl Drop for WindowContext { fn drop(&mut self) { // Shutdown the terminal's PTY. let _ = self.notifier.0.send(Msg::Shutdown); } } ������������������alacritty-0.13.2/windows/alacritty.ico��������������������������������������������������������������0000644�0000000�0000000�00001156302�10461020230�0016075�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000��������������������������������������������������������������������������������������������������������������������������������������������������������������������������� ������ �TL�������� �(R�L����� �(�"�``��� ���J�@@��� �(B��;�00��� �%��~�((��� �h��£� ��� ���*���� � ������ �h��Z�PNG  ��� IHDR���������\rf��LIDATxi$Gv&=ȣ@Ѝqg}�31J&Ff+jiɸd\rү]h&Q!.WҴI#gp 0p1U}TuuUy?ȈLH+3," ϟܝ~ $X ] , F�$XH@+ H`#a� `$ A$H1`;0(rx`#~!I`8?5waQB/},R}z$7aެh6@ MPwZ�-vh HZaN*D'O�$`jҎ''^Mϝ< 1dKIG`׃v.6*u&brmvLJt,/ ؝$y[ ;])e2[wV*e޳.jԱ]bt?_S7{�(!�M;Ω'�i'Ќ nҮ[501pyh2z7O^Fs8'Q[XeP#%F&^AjB2�Kp>؀$RG`"ɮrIg) ps1 &Zu2 ϶O;ϓaU&,u >nʜET*ΌN:SSB�A*G}IEm7ћ5q^YVU_0 rlIܐDM,-QdenaÒY2 %h+deӲfd0n4$7g?x??x3dG8WqK0 7_K4yl~&.;r׿mX`l&aH%ʵä| H{q:lu!g8io]ռ~qaޯ7䙬<zmjX`޸m^)\Z_Z߽IдM֠G&-'["V~�3FSo4_~#/"bI��kmT]nreH٦qЈ"Ó 8V܌T@@ZM\h]N92s)87{u#ar]aawg6I�T&P[E2") kٿN+clOy._m:`?ۆS{*PF棈3o؇۔Cj(V [},7,.tpo9(&9LiQ[柮1"3"!20:9kfG�F:jw=A}^h;c (wY\@^=hFNԱ<:SϛFHG rzUf�F33ΖoזM]'Er*@DĞd^(ddVnWMV-01oTI#P#i+9 wb3fv=Խ}~OARhľ"ˡY~U-of?X7z1DlMDﴛ�&\M)q{uQ SALeO)awYSNvSN>iF}ym SUP”h>I]}^OHG7*_Q3>^RW H 0@DDf�͚z$ֳ7nsE*t*|P9>lv=[)CK4q.WPGy+N3phQ㩷Jsj{f,{[뾋B;aP0\"@䰁 ZC�Jꮵ@lm؇hގsL~ 2 N_T' n2>;5 :ܷkQxw*}tSFcPyɧ}:*B[߰ c$h4 ̜pO|6;NlMWbFM2 `$kt SiU6I-S3H:Q</SfoZ'EvFs~(vi/8B>鴞| >euAU%Oz_UOF\ TiF˴<tI?a�:NVν]F’0XQ֚~/|te�>\|9<S89u`&̽uN<*�0(cڞ9PHEl;RFV'HѾ==h?Fd; )G@Gm"OjFbOy*M:`K%hԆjvsLYgtD|2oٮxR =ȏ9 >;Q_�Yyպ2Y S\`�0[x[ o87B.O[~Wɏ~ovcOV\8lVh\fV ЬCdPrI+/0i] \}hh&χ./# 0'y{q[̐ 1uY>g?/q};KL<ow<O{{ƍN3;ɒMR2$`{|؛$X ИP !Z\!UN7%0u/w'addy H3X{c0l4(J(Vl6!egu|#=+F_"juµcSFQ>Wt流#އï9ZhmbA#5m[pGJAd:ꮼ[x4@}]җm2{ߦ^B,FG0::t: lzz_O~JxV??GSZwS>yzIVN%#ꈥ^_1^^v@h' zA ]Vܰz1j[hWFC(߆uQD Wblk׬u l4 ?F6nNO={h4^{]/>(Λ.(NW/tr|~ 91VϨu zw޿>nɱ}FRF}SnTO2�4 EEN'lUgM܀z~8GqܥKl6ۅFxYYK8uD0A4,5�m{2ⶭQUmҥ1Mܲ6ni6}޿M}锱}xlSSSΟ?$H!֭[f͚*ř <Ǧ>GRO:W+ >WLݻf޲O?n!S(J=$H={>aV>wRN ARɩ[7߲9y} ,M03nܸ9"j+sL,oM{.}/׆w -FK/t~k/]P[tuSfgg1;[ˬ- |(*~aֿ?N2n8j<>MYeP(lّQ0(:{n`qQDAQI(4QCz_fFV6kժa/%JިeG`Amud^3n~?(&_ �@Z5eYZ6g .,/:$?."LZ�3*7h4h4:̮EN(D(cYGϲRƦ/!J!JEEM{/۹~�BgϞ\Tmڛgq'? fI b".[{G֞8W}A"FJ2P-);a,ϭcsXP_0�Xg%|Ka "z%ovBϾ# TO Fj@ߋ3@aڸiعc'*h347p"~|sfF2Kj6-XRh]"9NR2s'3Wkb'lF$߁*mbpԗD`#l ̆O=(~N5?`w#"_Hw0rO0 f'&&ӧΘnT3AabbJecUܤFZ� � rX�g's{6owVrzӇIz,S[/L_6߹%T~ `_ h߉AP*x>G7nKwy'Mzֽ9%" j5|'(|5:y$yB_RŎJ37okb�O>Udb"(2 DׯcrrSSSꫯ'H "*N87099k׮])0Iܹs݃�Hg@ѥEABp/ ҂UhYΞ;\>)lٲ/ُQP,Q(:u#k6"F3Tf BZAQOP@XDVǶR'hW[a rH%i˲PTqѷND,-Ē ACe d#l AP_ fuV;"л=s0gGo@#jߘ�HՅ@+UPҴrI Gr't�HЗ`N$Ii?2asz۫s քrMwK$Tãr__x(c$SFa}V2G#sf 8E؀&cX@YHf!p`�sTWa aHJ, (}4YKCQ~Q׎(A/x@&zCS $!#F$[ ph-<a8j=@5zs�.QǣF1c_P1.IG2vڼ#h0 X8h^4-X&%|ie}/ |-@XC W # '0E %AM�@ٵ4AYmf@/U<h&B띚޹)H"#=tNm'V;CM OOh~ `$3P Ooܵ;jހ ;.m۬a6+I wGRD�Rb�A|oBSai+6T�H�ޑ?^4\dY3qCeCu9X+,J>aP@<#KV$8vo hk(`~ AxȬ`o9.If D8O ̀`~%cHzA@8)"( XԷ#P2$Fʐ ~!T{>kfyB\ OS JZ�ۼV{tI;HL+:yyӻt�, Nsiϔ@A~gե' O~o9LywAP~HsJ<5}ބ:S^Pנ7U#d|"__?Q߹[rE$d wm="J~A#Q$emEe9Gԥjz/5<aͬtko'$j>+* V*+"�P5Cq@H `aPO$~A~Fע  `sb~' \F  n7J?6!'R@H=~1wT+< i ݀"cCdlw!BKQy=|) U c 'EdKE }*{W=5l_īNUyӍJ90' ?Sm~UJ9¢, 1ipI/|<Q>?\H:1'[V(;0fKW/-|{"6$9Cr0'!Ax4[ƮTcO.IteQ$L`p`؇n rɟ&cE~m6GU9. + qCbXd ܞ!ב߈Y^/uIe=K:6<` 8<\*OW3@v{�V auh)<1@[H�&u**4ۗwDoma@_ִgl$;�EA  e[} υ9[(i-8t3C-+LeVB9+ `WLJd00xƟAJBA;'0!ql}ynP10XLQ`M ѱF#w9pCD ;2UU%b37ˣx<Tk9T J*L [ oosT1D< 0-`o(.4ҸH+ sL&`ah1q t@3�t�DTώ:ʸA%bLKsh2 «<-D6eq 0 O00;2uv ޝǥwi�ޯ1Vx:lOv\哳(:N"L ?0QCX@ M>�jLx8%Y*+<uyD BO Ʊ\1bs8}@$ŽóOW㜫i`e5!xAWFe-Vz}72{gqg ɷTE`)" zA#cGU[뤷%+aitɦ׋cCy6'% 0(y uO,$[R <3Vrw~@?kCR#7Kcy8K�!^�όpK CA]_ 䧆'@o`&<5VveS�zݵӆx43 �gkU*{0և ؞8~2� G<{; G?|~^АN 0#ov1MOJ� 3e`?r$G76w2~eͺ^b|<;09$Y=(�`00q4_@ޔ� 2G6�,/̣5 L@ޔ8�3Q~n",�$-Ε5_fvq$pw e 10O%]O=`}o `PYI`&<+bߤ# &Bך&%pa\7sO0@$m:'q0@x`�9"L;zl@(:(TGF ?C,M߿9 $OA S`/ (ccH� C2,bPoGpqwN2x8^ 4)h->02ó2, DI7~4t>燆$2CA/(9D v0Ղ >=^jyb|XƯC^b4Kv9+tm30�.Lx:_–LRG8WWnPG(Z^Σrlx1  " &@M GWۢn Q"U=3Қ"[іAhx L8^/k @۵)h7H&;ZcUXs{D}}&QgJ=L;9~Ɔ]U3ZIso)N`[]Ęauw^GU5Pj70xm: #_x.3 cQDB7@C2'K`uv{ͽ b=3+L~hyәQ2ѯj�U%lC&< qW` <-ن~?9oPKWr(YI0Jtui%[2 <xFDstuo->( d a|T 7SDz:' Ʉ*s`+S9hixye6X 9Z}cg`rL۵V�q NFJ0+`t= NW3ѾL~ bxzg3OMY8H3?� Q uDd`P O<t6;K B3?Z??�ޘ )QL'V#Q";oPWÄ.2 8qs<og?@tޮ4x\oxFnN;d൩7 r~IkjMn4ܪ:"A¦jXt=@7x#kg: 9/4IG<B0~63/K _3͑2P51~+it 8n&Q Hgc{4ߏRHL??j~Ż_q<yʖ 燚x8ʖpwh^6xu<qw@>QAw8wଢ଼$ ҂qViGC=IiDK -$>) еImξmH# H'Iԫ#P"!9T-? \qj&^F<ӟeI<}x`Y \ˡ$-( K5\KY .e.֕#sj?oKLo~ B:1MϩIP)5~Qw:8 Z`�+5.Tسk'|Q<أسk..TSxcrl[;LƑEN'˄fS+!x{=�ߏ\OJ# q:9lO|ZSu#~40 Ǫx ,VE@FZHPpJz|Q:ev;|Za5ާA/JٖIԭ$ h)q|cilE9(�lHvjc'O>"`^GՊ x߭ؿ6<Ѓ�P^cV#9TOwʰ2v$*=@K$+bcBUS'Y!wfG0I eRfc%a|Vlm }?]ơ&Kkl9p"�֤-P? hQfqM =k$T$xn╫9XQL( 1l(bM ( К -Ͽiu iy},v8sXfW ] ǟ?1Qb>_ sU<:Q&V!#Z!AAxm+X[~Iشq#< cL*i(0f!SMdep\$� 3Zcks0<1GAfx {vN'%{<c`,&:Ǎ$CR <g��7>یѻ;7L|^<zCS^<~cMm �S)>ġy|pЕd�k3T[=U)<f{0N=1�K{&Y$XBܼc| PVY `LxxMs>ly b|^SWx~SKp(^<ziz 'Gy!Y%m(sCKIm^SND@ 6]8~~[cОz98۶nO= [2SO`-�0U3b krO^Qn. k$EaX5=>CU 2+c@Lq駱u˖N-[p{b?2K!J3<][c5X"T�8uCA]'2޼6x?f89 -0 1>> Ζx |B0h& jb,ih9ѽs hi\+`d0\lӟ{/åc2%P=[d+r0;3(-t9uٕg`V Xd#*5WӏB0޽1OnVi<s2'.vۀP:T:뙂{S: FCO=Z= MT[~�tbZ`� n) kʾ;y|U |!rSVmݱw?(MMG-b+M.)&A%�0iAh֔8~2W5>k ѽ (+jxxkuZhme!7?hH<J 4, vx Bk# KS <} WuDXV:�Rĺrܗn|{ܣH%]z5ު?fFnZa4hH$u0pCȯ^]U^A"W 2 Š3gQj0(.ί2&;?Gsxѝ {F>AJ _ꏥĞa=7;=o_a�u ذc/xS�o\e$tD8pR# N ݼ>L'ޯF֗7_ğ8V㫣8S2@:;۟<JP:#&;]-54,R&n١Xu.fWF[#Q [oOVd_[rZiӀ!C-d*z.А>j [ߏ6p:+ܴ#5ԛ-ߏ;oK+V]LxB3q7}d ;KDF(,&~:wXZC0~95HachZh�RzIfǎ.M aqV g xU2Wa-g@+� qtKk.?s]/ϣԌ^}=wcXDQ4L@}#7 ^4ֹq= ҔRR0W "$A7d2581[WF 1c]chv4,e.02Pl9̢ m؁w=<�+#8gU'͡[ظ” R AxlciKw"/.g�߻Y*źF{%L AIӰ*"(,H"Κ1OK $u<ae(5&ˁ#:m6[ ͥZ�tmqvb/f~7v@]s,R~e:ehJFw܍wd&f} DG# pC rŬXpJ%n_UC+ݞ*pA\ə?2L<8;U&/L;o0P =σ�'g2Ĩ{}/IWpxuy(TE31n+`ukÜ_�QiKk!}h:b2oJwIo)uo{m@̍Cҹ< x1Y G2P(?Ād`pu_ƇCz|0= oF⮹H�ގ!`a1x|3۞/ 1>>'綔ibvG':0Ol*aW<y%ᥳyL`oM#Oz� tMHFcY@aॳyԙ挎2ڡ/( c-sr ,dˣئ? >47ChU)@UUR`1z_i�q20z9&,Ŷ2mw9�9rdkfYw>>0Q6c+`fи(fUI_S%,f&VUe˹M~S].sopYܹf+ �,_ EZ포GW%{SS\5ڹ1OFsíYS_2EO?#Y8·!-H�s,<C9y OMCn/:@e)!cH64RǒZkkN ۞]˙s_S$�o͂$$CC�īA51ҭ 4~�"I s[K< .,џAx2vk~\@a3-_m�u<ӱ)TU)SV媭@B�P/n)<J( ؙ[2p,70єv6ֲy^-wu7Հyq\~&gJrT& g[x0>>o`L%ad g@d]koli}h){|/%qC$kpG >ܒDyƅsBڰ;8CcM ouN ԉAc; w3G\B� y_bBUxV=ĒCL_#=T]ũt0>g�,۱|'$[F8Q\=J?8嘧tQy>�brO,�Aπl\.QL%ZĖ !')εᩭ%p΁hJ\5꙱?J" Q\&>Z Xoht�*O8AO g򸮮?E M3 �c20Ύ@@DJd�c) /* e(}h..gFL) a\5:{- T%`{܁ko;17,;0Fo_M*-h)®R30:� j~9�$^_}m域h �G'̛-*i+MNQ4W`u;^ŶϾ^.�$: ^HիM̡? @?+ ɦ 8~yzM?s/y /G8lk[#^֡=t qPeSg3髖[J@~ٷ@ƻ6 vyi~w1 ?d²Q-V7y|O:`9L$[8Եo!B~SܗO0]WSVh5&%#_ b�x}qLzn+a[ny*\ -0l/c)�̤MZ^ysUS)8Vm 0T/c_ 0<733E$ϗhJ�u<L^% /"a~Rȥ-g9ݬ3cPHg6a{4; ԽZ$ݝ![+hv_8 8;8􏺲t>yMqlOWI뺴\Tp0{6 sgɪWN !`Lqv2_O@uK0`Lqk-Qf o`  M{"* LX.0~yB�?8/&s"Zy][;uog.g ͒><<Z 1>Flҡ]y^=G0& p|OX>߯c1 lRG,AC4=lc/a}T+mq^;O81J0ξ7p_E!yTcBu$E2Pik|8&�%lח20.P Z`&<ֲ0һϿYhlr42Ւv%H�;Ep @Lv:Alk˰y3;;^fKw6ڟEwfTu� p|ozl7{Q][`xDSO "M9S/l[0oz;2ϽϧQ5\kѯ||f({YIIo,8 ʷM=гoWtIӃ6ekP@.)@uQU)u(0ξ{^Ʃ1\ICnKkM\s/8qn,ieN "̴S[gʮ >qCqz f\$Z:["/{ί @g1}/Tw 8;gƺia'm.+­5Kj"x9W Ҝ/ȷdֻA45�% k:=ƅAs*nT=${A8y/.ӫ=JZ0Ͼ4v[5gXʪ?Fwi[1>6w.7 {b�xvwqI++rK00pbGˇ~&_QiĈZ;GmW Vu @rD ĕmwX |<f- }ępֶKm(KRTm?/ {0C�_g�¸ΎA.' ϶.q�k2W!#B5 :�H06-Me` ATXj?RU۾gZ+_0Y1sYoyZn=ýw]bUF>'&+^9߇wX�cY-]e`XqǃKv)U"QRB[1DyR+3h!_"ϫOpa&սq(/Ę1wsUmI)�\�S-*Nyzg 0/!n^w߁ tos4K |n }I�K 6ѷ?"/Cs畍Y>DO.̋kA) /:Y#٧}jR9n/8}6Lxp,7ȳ,hۯd�]G;].a\w0.jND'aJmA^]xun[0?Œ�xq ۡ}U_QϳOl1>N>@ܼ�qԂJUPxyT䦹t`^�F?1?}ӥO �Ѓ'_G_ d`ךUnsE.|y=ӟDt90<`\T^PANn hu|<Sؽfex8?w-REl7Sb?7+ZyL:XM bxY еA&^2~w~&vF?SkMۻt^);`VY8Oj;=4q6�.Rx4@qנJD_~[jW~(F5K$[gI(,Ae`܋`Lxp[wl� G'Gqj*p?@3VQiE�2ѹ3 2pY<蕁AW'G/tQ;Rai9x_P\p&/hXñ5?øiG"|<fjbN�0f4~Sw>ty س'wlٯ0/ WK>5i?@Ư. ý) �xrO {. eߺ4x@~ůŎؔ#m], O$ _ok'߮bw>ͣf!4 �$M&V\BوO\f ?ż#3f±(芸Wײx"1@*\q6X'@L(^] �hrj'&A3g�fZ@i{XoO|a ɄwTpǦ*$oZq qm3�g&{_0QL->@ +_WO]!M|9 Chwpv;6Uů Rܫ~VD)p"w`$:Cֈm(B ͥK\{sGq`�˂q׋r>JiȰߙyrJz!,A68i1( 2$GH|t1Vu{/]p_TAL`xUwÉ@_ d8[ny`&(gIKm98˱_鷯d^̋׊&~o=CۧolCZU`\5JOZE*hJ¿:O׆'{<v(�w5h$LW}-_-z;_jE/8mfEq7FDɗj|:Yl96,P 3a8%qkPN C{Q~r &W+D7/J]1*OAܼLKzMZ !ls)čz H� QՊƵ _Gl D,!~XVg,k':K P o! G &Oj?3U-'=.9ԋ;rɐ 2H@& Wa �xbf&' BƃW&Ѐ4;1u9PX�9̉`Ej@\#�к` _ � (a\kuzmHK:H��D7΁Eb\"/10lZ t`)@kXJא KQX7;a�K DZb4`H�K JA:�"'v W}cɬ�L VN~{+ g ~otfg@W@$?,V,1y>C-Ϟ̀Zs`$;rrF2$H00Q$y3lf=Ϗw煽j2$H3G�>@w;\S^tMŽ;1>>i'!(g%H VR֎cΝ(W*uǚxGyfFXĞݻ#^kW/4 QNHX.Xm}Gi&|GR~Rt)tի, 7pMcw&,µk׺[r>7w?V;WUa۶mؿ?,QV ,3n::u _u5.(AǏ13rqlڴ f.\S0== )mqQ->ˌZ\(R68~jhm"(/3<J=^yw� U{nlݺibbbo6bߦӸ\.`۶mf/Aˁ;,+a%(>Q潝4A^1,IN=jϟB0?:v@34M[6l @s^~ԽcDzh5A0H:k>RJJ%\rׯ_G bpCu "B&&&˄(:8 ʣӝ8t[ϰvG8;j^,fGe�a Gs9 @Dl BŒ<7suAG@QQtlZc{gX}_Qm/kMQG/Qg*DT|i`%&H`ɀ/,3fu+ A C) $Xdfʠ7M> `B(ANgSƏ߽SD7 ] _c�agaw.t$H0 &3ۃ3O�r $ĂfJgGomV4Md &&3`>DV>RʈǛhedܛ[v$ffABM:#Ӗ7,A4~&q&?�r &]\3j<곢?>lH jOvt*7KqMUj3? cԑ=u'ujod3S5K`ݳ>: o:UXjy)l W?o mk߻{fs`wQeP=YhQ޳:aio?=7UnX£;0^xnܺ1S7꘭浹wJٓ`>�pdSPu9-"@* ~)e9� f0 !`˚̟_9`ݿ+}ïP.W ڳ1rm �Rv#2Y0@Ği|߭_-V>Z8g$KsMH0OЅI"M4rOgSu0 ٷ3?W gkx`F_?9}?zd%SO0c/PGI1II`<{ f6$%X �,jK}L�IN~dΫ9v~c>Tm݄2V VJW]=ÕZch bP LbNMj\RH`4%&Մ)1>:TU~ydxL8oI^ � ۿĆr*cQk1(=O,M0/f%H@&G~@ V A0 V0 F�$XH@+ H`#a� `$ A$H0 V0 F�$XH@+?bo=4����IENDB`(��������� ������@��d���d����������\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�[r�@GO�CJS�FIK�CDE�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DCB�BCD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DCB�DDC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DCB�BCD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DCB�DDC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCB�DDC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�@BD�HKO�RW_�QW`�[r�\t�\t�\t�\t�\t�\t�\t�\t�Vez�;& �DEE�BB@�Pv�EGI CDECCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCBBCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCBCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCBBCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCBCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDBBBDCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCC@BCHJN �AA@�CEF�A;4�Ubu�\t�\t�\t�\t�\t�HKM�HKO�@><�DFFDEEQDEEDDCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCBCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCBCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDBDEDFHSDFG@A@�KOR�JMQ�\t�\t�\t�JLM�IIJ�LT[EFHJCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDDCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDDDCDDCEGKOYaKMO�KMP�\t�FJO�HIK�QRSFFFuDDDDDDDDEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEDDDDDDDDEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEFFvTZaJKL�HJK�DHM�;GSEFFvEEEDDDEEDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDEEEDDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDEDDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDEEDDDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDDDEEEEEEFGGuQXaIKM�CCA�FGGIEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEGHHIEED�IIJGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFHHHHIJ[FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFHIJ[GHIGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGHHIIIHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHIJJJHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFGGGGGGGGGGGGGGGFFFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHJJJIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRRR```eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee```RRRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJIIIMMMssssssMMMIIIJJJJJJJJJIIIJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJLLL{{{___EEEBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBEEE___{{{LLLJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKJJJbbbqqr������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������qrqbbbJJJKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK������������KKKKKKKKKKKKKKKKKKLLLKKKKKKKKKKKKKKKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMJJI������  ������IJJMMMLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMOOO+++������,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$������+++OOOMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMPPP&&&������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������&&&OOOMMMMMMMMMMMMMMMMMMMMMMMMMMMNNNMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNPPP&&&������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"9+9+*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������&&&PPPNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOQQQ&&%������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!eEdE(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������&&&QQQOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOQQQ&&%������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!^^(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������%%%QQQOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPRRR%%%������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#-$u u -$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������%%%RRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQQQQQQQQQQQQQQQQQQQQQQQQQQQPPPRRR%%%������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*":,؈ ׇ :,*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������%%%SSSPPPQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQSSS%%%������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"Q9Q9)"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������%%%SSSQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRTTT%%%������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!qLqL(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������%%%TTTRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRSSSRRRSSSRRRRRRSSSRRRRRRRRRTTT%%%������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"c b )"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������%%$TTTRRRRRRSSSRRRRRRRRRSSSRRRSSRSRRRRRSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSUUU$$$������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#/&x x /&+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������$%$UUUSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTVVV~~~$$$������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"?/݋܊?/*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������$$$VVVTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTUUUTTTUUUTTTUUUTTTUUUTTTTTTUUUTTTVVV~~~$$$������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!Z>Z?(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������$$$~~~VVVTTTUUUTTTUUUTTTUUUUUUUUUTTTTTTUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUWWW~~~$$$������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!~S}S(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������###~~~WWWUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVWWW}~}$$#������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#j j *#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������###~~~WWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVXXX}}}###������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#5)́ ˀ 5)*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������#$#}}}XXXVVVVVVVVVVVVWWWVVVVVVVVVVVVVVVVVVWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWXXX}}}###������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"'.(nxxxwxxxxxxxxxxxxyOb+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"L6K6)"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"Obyxwxxwwwxxxwwxwwxm'.(+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������###}}}YYYWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXYYY}}}###������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*' }����������������� (,$+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!mJmJ(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"(,$ ����������������� }*'+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������###}}}YYYXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXZZZ}}}###������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!Ob����������������L^,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"b b )"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!L^����������������Nb,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������###}}}ZZZXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYZZZ|||###������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"'.(�����������������y*&+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#1'{ z 1&+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*&y�����������������'.(+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������###|||ZZZYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ[[[|||"""������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"b�����������������">E,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"F3F3)"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!">E�����������������c+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������"""|||[[[ZZZZZZZZZZZZZZZZZZZZZZZZZZZYYYZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ\\\|||"""������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#:?�����������������h+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!jHiG(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#h�����������������#:?+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������"""|||\\\ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\\\|||"""������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%v�����������������%21+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"c c )"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"&21�����������������u*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������"""|||\\\[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[\\\[[[[[[\\\[[[[[[\\\\\\\\\\\\[[[]]]{{{"""������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!K_�����������������Wu,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#3(~ ~ 3(*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!Wu�����������������K_,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������"""{{{]]][[[[[[[[[[[[[[[[[[\\\[[[[[[[[[[[[\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\^^^{{{"""������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"(-& ����������������� )*"+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"O8O8)"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+")+" ����������������� (-&+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������"""{{{]]]\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]^^^{{{"""������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"^�����������������HY,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!|R{R(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!HY�����������������^+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������!!!{{{^^^]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]^^^]]]]]]]]]]]]^^^___{{{!!!������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#9=�����������������r*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$p p ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%q�����������������#8=+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������!!!{{{___]]]^^^]]]]]]]]]]]]^^^]]]]]]^^^]]]^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^___zzz!!!������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%p�����������������#:A,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"?/ۊ ۊ ?/*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"#:A�����������������p*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������!!!zzz___^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^_________________________________```zzz!!!������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!H\�����������������a+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!gFgF(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"b�����������������H\,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������!!!zzz```__________________________________________________________________aaazzz!!!������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"(+% �����������������&0.+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"f   f *"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"&0.����������������� (+%+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������!!!zzzaaa_________________________________`````````````````````````````````aaayyy!!!������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"Z������������������Rp,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"8+Ѓ   σ 8**#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!Rp������������������Z,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ yyyaaa`````````````````````````````````aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbyyy ������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$6;����������������� y)) +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(![?  #"  [?(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)) y�����������������$6;+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ yyybbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbyyy ������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$k�����������������DV,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"^#),,)$^(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!CV�����������������k+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ yyybbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccxxx ������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!EY�����������������j*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#4(~  $-3562-$ } 4(*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%j�����������������EY,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ xxxcccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcccbbbbbbccccccbbbcccccccccccccccdddxxx ������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"(*# z�����������������#8>+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"T;"-6<??<6-"T;)"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#7>����������������� z(+$+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ xxxdddcccccccccbbbcccbbbccccccccccccccccccccccccccccccccccccccccccccccccdddxxx ������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"V}������������������[+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!Y +6?EHHE?6+ Y(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"[������������������V}+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ xxxdddcccccccccccccccccccccccccccccccccdddddddddddddddddddddddddddddddddeeexxx ������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$48���~'.,+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#1'z %3?HORROH?3%z 1'+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"'.+~��$49+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ xxxeeedddddddddddddddddddddddddddddddddddddddddddddeeeddddddddddddddddddeeewww������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$f�Ll,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"N8 -<HRX[[XRH<- N7)"+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!Ml�f+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������wwweeedddddddddeeeeeeddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeefffwww������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!BV� q)(+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!U$5EQ[beeb[QE6$T(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#)( q�BW,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������wwwfffeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeefffffffffffffffffffffffffffffffffgggwww������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#()" t� ?Q,"+#+#+#+#+#+#+#+#+#+#+#+#+#/&v ,>MZdknokdZM>,v /%+#+#+#+#+#+#+#+#+#+#+#+#+#," ?R� u(*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������wwwgggfffffffffffffffffffffffffffffffffffffffffffffffffffgggffffffffffffgggwww������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"Ry�c+$+#+#+#+#+#+#+#+#+#+#+#+#)"J5 4FVcntxxtmcVF4 J5)"+#+#+#+#+#+#+#+#+#+#+#+#+$c�Rz,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������wwwhhhfffgggffffffffffffffffffffffffgggggggggggggggggggggggggggggggggggghhhvvv������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"%37$5;+"+#+#+#+#+#+#+#+#+#+#+#(!{R'<N_lw~΁΁~wl_N<'{R(!+#+#+#+#+#+#+#+#+#+#+#+"$5;~%37+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������vvvhhhggggggggggggggggggggggggggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiivvv������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$a�U,"+#+#+#+#+#+#+#+#+#+#+#.%s /CVgu΀чҋҋЇ΀ugWD/s .%+#+#+#+#+#+#+#+#+#+#+#+"U�a+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������vvviiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiivvv������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"@S� u',)+"+#+#+#+#+#+#+#+#+#)"G4 6K_p~щԑ֔֕ԑщ~p_K6 G4)"+#+#+#+#+#+#+#+#+#+"',) u ?T,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������vvviiihhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiijjjuuu������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#))! o�Hg,"+#+#+#+#+#+#+#+#+#(!wO%=SgxЇՒؚؚٞٞՒЇxgS=&wO(!+#+#+#+#+#+#+#+#+#,"Gg� o))!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������uuujjjiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkuuu������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"Nw� j)'+#+#+#+#+#+#+#+#+#-$q ,DZn΀Ԑ؛ܣݧݨܣ؛Ԑ΀oZD,p -$+#+#+#+#+#+#+#+#+#*' i�Nw,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������uuukkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkuuu������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"%15y ;N,"+#+#+#+#+#+#+#+#-$q 3Kbvщטܤ߭߭ܥטщvbK3q -$+#+#+#+#+#+#+#+#," <Nx%15+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������uuukkkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkllluuu������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$\��\+$+#+#+#+#+#+#+#+#(!lI 9Ri~ԑڡ߭߭ڡԑ~iR9 lI(!+#+#+#+#+#+#+#+#+$\��]+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������uuulllkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkllllllkkklllkkkkkklllkkkkkkkkkllllllttt������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#," =Q~x$28+"+#+#+#+#+#+#+#*"9+υ$@XpІיުުיІpY?%υ9+*"+#+#+#+#+#+#+#+"%28w~ <Q,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������tttllllllkkklllkkkkkklllkkkkkkkkkkkkllllllllllllllllllllllllllllllllllllmmmttt������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)( i�O+"+#+#+#+#+#+#+#+#(!]*E_wӍۡۡӍw_E*](!+#+#+#+#+#+#+#+#+"O� j)( +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������tttmmmlllllllllllllllllllllllllllllllllmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmttt������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"Jt n'+'+"+#+#+#+#+#+#+#)"J7.Lf~֕ީީ֕~fL.J7)"+#+#+#+#+#+#+#+"'+' mKs,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������tttnnnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmnnnmmmnnnmmmnnnnnnmmmnnnnnnnnnnnnttt������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"%03s}Cc,"+#+#+#+#+#+#+#+#,$y,RlЅٜٜЅlRx,,$+#+#+#+#+#+#+#+#,"Cc}s%03+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������tttnnnnnnmmmmmmmmmnnnmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnooosss������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#X�~~~~~~~~~~~~~~~~�b*&+#+#+#+#+#+#+#+#(!aI!TrҌۣܣҋrUaI!(!+#+#+#+#+#+#+#+#*&b�}}~}}}}}}~}}~}~}�X+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������sssooonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnoooooooooooooooooooooooooooooooooooosss������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#," :Nx}|||||||||||||||}w!9J,"+#+#+#+#+#+#+#*#4*ŗLyՒޫުՒyƗL4**#+#+#+#+#+#+#+#,"!8Jw}|||}||||||||||||x :O,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������sssooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooopppsss������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)' e�}{|{{{{|{{{{{{{{{�|V+#+#+#+#+#+#+#+#+#(!~c6}יט}~c6(!+#+#+#+#+#+#+#+#+#V�}{{{{|{{{{{{{{{{{�| d)'+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ssspppoooooooooooooooooooooooopppoooooopppppppppppppppppppppppppppppppppqqqrrr������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"Gqzzzzzzzzzzzzzzzzz{o%/5+"+#+#+#+#+#+#+#)"C6 ޵u۠۟޵tC6 )"+#+#+#+#+#+#+#+"%05o{zzzzzzzzzzzzzzzzzGq,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������sssqqqpppppppppppppppppppppppppppppppppqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrr������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"&.1mzyyyyyyyyyyyyyyyyyJz+"+#+#+#+#+#+#+#+#*"XޥަX*"+#+#+#+#+#+#+#+#+"Jzyyyyyyyyyyyxyyxyyym&.1+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������rrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrrrrr������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#T�yxwxxxxxxxxxxxxxx�y f()%+#+#+#+#+#+#+#+#(!YJ1ѡѡYJ1(!+#+#+#+#+#+#+#+#()% f�yxxxxxwxxxxxxxwxx�yT+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������rrrrrrqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"!8Lrwwwwvwwwwvwwwwwwwu?_,"+#+#+#+#+#+#+#+#1(1(+#+#+#+#+#+#+#+#,"?^uwwwvvwvvvwwvvvwwwr!8L,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrsssssssssrrrsssssssssrrrrrrssssssqqq������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)' _�wuuuuuuuuvuuuuuuu�w[*%+#+#+#+#+#+#+#+#( sfOtfO( +#+#+#+#+#+#+#+#*%[�wuuvuuuvuuuuuuuuu�v _)&+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������qqqssssssssssssssssssssssssrrrsssssssssssssssssssssssssssssssssssssssssstttqqq������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"Dmttttttuttttttttttto"5F,"+#+#+#+#+#+#+#*"=4$ɴɴ=4#*"+#+#+#+#+#+#+#,""5FnutttttttttttttttttDm,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������qqqtttsssssssssssssssssssssssssssssstttttttttttttttttttttttttttttttttttttttqqq������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"&-/htssssssssssssssss�tP+#+#+#+#+#+#+#+#+#)!zz)!+#+#+#+#+#+#+#+#+#P�tssssssssssssssssth&-/+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������qqqtttttttttttttttttttttttttttttttttttttttttttttttttttttttttuuutttttttttuuuqqq������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#O�srrrrrrrrrrrrrrrrsg%.2+"+#+#+#+#+#+#+#)!PH:PH;)!+#+#+#+#+#+#+#+"%.2gsrrrrrrrrrrrrrrrr�sO+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������qqquuutttttttttttttttttttttuuutttttttttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuppp������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"!5JlqqqqqqqqqqqqqqqqqpEv,"+#+#+#+#+#+#+#+#.&.&+#+#+#+#+#+#+#+#,"Dvqqqqqqqqpqqqqqqpqql!6J,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������pppuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvppp������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)& Z�qppppppopppppppoo�q _((#+#+#+#+#+#+#+#+#( icWjcW( +#+#+#+#+#+#+#+#((# ^�pppppppppppppopop�q Z)&+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������pppvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvwwwvvvvvvwwwvvvwwwvvvwwwppp������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"@jnoooooooononnnnnnol;[,"+#+#+#+#+#+#+#*"80"80"*"+#+#+#+#+#+#+#,";[lnnnnnnnonnnnonnnnn@k,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������pppwwwvvvvvvvvvwwwvvvvvvvvvwwwvvvvvvwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwooo������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"&+-bnmmmmmmmmmmmmmmmm�nU*%+#+#+#+#+#+#+#+#( ww( +#+#+#+#+#+#+#+#*%T�nmmmmmmmmmmmmmmmmnb&,-+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������pppwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxooo������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#L�mllllllllllllllllmf"2C,"+#+#+#+#+#+#+#)!IA4HA4)!+#+#+#+#+#+#+#,""2Cflllllllllllllllll�mK+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������oooxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyooo������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"!4GglkkkkkkkkkkkkkkkklJ+#+#+#+#+#+#+#+#+#,$,$+#+#+#+#+#+#+#+#+#Jlkkkkkkkkkkkkkkkkkf!3G,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������oooyyyxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyooo������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*% U�kjjjjjjjjjjjjjjjjj_&,0+"+#+#+#+#+#+#+#( _YM_YM( +#+#+#+#+#+#+#+"&,/_kjjjjjjjjjjjjjjjj�k U*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������oooyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzooo������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"=hhiiiihiiiiihiiiiiih@q,"+#+#+#+#+#+#+#*"3,3,*"+#+#+#+#+#+#+#,"@qhiiiiiihiihiiiiiiih=h,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ooozzzzzzzzzzzzzzzzzzzzzyyyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzznnn������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#&*,\hhghghghhhhhhhhhh�h W)'!+#+#+#+#+#+#+#+#( |vl|wl( +#+#+#+#+#+#+#+#)'! W�hgggggggghhgghhhgh\'*,+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������nnnzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{nnn������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#Ggffffffffffffffffgd7W,"+#+#+#+#+#+#+#*!B:-B:-*!+#+#+#+#+#+#+#,"7WdfffffffffffffffffgG+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������nnn{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{|||{{{|||{{{{{{||||||{{{|||{{{||||||nnn������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,""2E`eeeeeeeeeeeeeeeee�fN*$+#+#+#+#+#+#+#+#*"*"+#+#+#+#+#+#+#+#*$N�feeeeeeeeeeeeeeeee`"1E,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������nnn|||{{{||||||{{{||||||{{{{{{|||{{{|||||||||||||||||||||||||||||||||||||||mmm������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%P�eddddddddddddddddd^#0@+"+#+#+#+#+#+#+#)!JC6JC6)!+#+#+#+#+#+#+#+"#0?^ddddddddddddddddd�eP*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������mmm||||||||||||||||||||||||||||||||||||}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}mmm������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,":ebccccccccccccccccccD+#+#+#+#+#+#+#+#+#*"*"+#+#+#+#+#+#+#+#+#Eccccccccccccccccccb:e,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������mmm}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}~~~}}}}}}}}}mmm������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#')*WbbbbbbbbbbbabbbbbbX&*-+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#&*-XbbbbbbbbbbbbbbbbbbV')*+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������mmm~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~mmm������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#Caaaaa`aaaa`aaa`aaa`<m,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,";m`````````````````aaC+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������mmm~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~lll������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,""0B[`________________�` P)& +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)& P�`________________`[#0B,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������llllll������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%K�_^^^^^^^^^^^^^^^^^\3S,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#," 4R\^^^^^^^^^^^^^^^^^�_K*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������llllll������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"7b\]]]]]]]]]]]]]]]]]�^G*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$G�^]]]]]]]]]]]]]]]]]\7b,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������llllll������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#')) Q\\\\\\\\\\\\\\\\\\V#-<+"+#+#+#+#+#+#+#+#+#+#+#+#+"#-<V\\\\\\\\\[\\\\\\\\ R'))+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������lllkkk������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#@[[[[[[[[[[[[[[[[[[[@+#+#+#+#+#+#+#+#+#+#+#+#+#+#?[[[[[[[Z[[[[[[[[[[[?+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������kkkkkk������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#.@UZZZZZZZZZZZYZZZZYZQ')++#+#+#+#+#+#+#+#+#+#+#+#')+PZZYZYYYYYZYYYYYYYZU#.A,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������kkkkkk������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$G�YXXXXXXYYXXYXXXXXXX7i,"+#+#+#+#+#+#+#+#+#+#,"7iXYXXXXXXXXXYXXYXXX�YG*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������kkkjjj������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"5_VWWWWWWWWWWWWWWWWW�X I)%+#+#+#+#+#+#+#+#+#+#)% H�XWWWWWWWWWWWWWWWWWV5_,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������kkkjjj������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#'(' LWVVVVVVVVVVVVVVVVVT 0O,"+#+#+#+#+#+#+#+#," 1OTVVVVVVVVVVVVVVVVVV L'('+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������jjjjjj������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#<UUUUUUUUUUUUUUUUUU�UB+$+#+#+#+#+#+#+#+#+$A�UUUUUUUUUUUUUUUUUUU<+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������jjjjjj������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#,>OTTTTTTTTTTTSTTTTTTO$+9+"+#+#+#+#+#+#+#$+9NTTTTTTSTTTTTTTTSTTO#->+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������iiiiii������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$C�SRSSSSSSSSSSSSSSSSS:+#+#+#+#+#+#+#+#:SSSSSSSSSSSSSSSSRR�SB*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������iiiiii������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"2\PRQQQQQQQQQQQQQQQQR I''(+#+#+#+#+#+#''( HQRQQQQQQQQQQQQQQQQP2],"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������iiiiii������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#('& GQPPPPPPPPPPPPPPPPPO3e,"+#+#+#+#,"3ePPPPPPPPPPPPPPPPPPQ G('&+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������iiiiii������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#8OOOOOOOOOOOOOOOOOOP B)%+#+#+#+#)% BPOOOOOOOOOOOOOOOOOO8+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������iiihhh������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+##+<JNNNNNNNNNNNNNNNNNNK .K,"+#+#," .KLNNNNNNNNNNNNNNNNNNI#+<+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������hhhhhh������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$>MMMMLMMMMMMMMMMMMMM;+#+#+#+#;MMMMLMMMMMLLMLMMMMM>*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������hhhhhh������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"0ZJLLLLKLLLLLKKKLLLKLG%*6+#+#%*6GLLLLLKKLLLKLLLLLKLJ0Z,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������hhhggg������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(&$ CKKJJJJJJJJJJJKJJJJK6{+#,#5{JJJJJJJJKJJJJJJJKJK B(&%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������gggggg������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#5}JIIIIIIIIIIIIIIIIII A(&%(&% BJIIIIIIIIIIIIIIIIII5}+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������gggggg������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$*:DHHHHHHHHHHHHHHHHHHG/]/]GHHHHHHHHHHHHHHHHHHD$)9+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������gggggg������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$:GGGGGGGGGGGGGGGGGGG = =GGGGGGGGGGGGGGGGGGG:+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������gggggg������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#.WDFFFFFFFFFFFFFFFFFFEEFFFFFFFFFFFFFFFFFFD-W,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ffffff������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(%# =EEDDEEDEEEDEDDEDDEDEDEEEEDEEEEDDDEDDEE =(%#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ffffff������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#2yDDCDDCDCCCCCCCCCCCCCCCCCCCCCCCCCCDCCCC3z,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������ffffff������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#%(8?BBBBBBBBBBCBBBBBBBBBBBBBBBBBBBBBBBBC>%(8+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������fffeee������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������eeeeee������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#,U?@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@?,T,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������eeeeee������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(%" 8?????????????????????????????????? 8(%"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������dddddd������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#/v=>>>>==>>=>=>=>=>>>>>=>>>>>>==>>>=/w+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������dddddd������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#%'69<<<<=<<<<<<<<=<<<<<<<<<<<<<<<<<<9%'6+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������dddddd������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#2<;<;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������dddddd������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#*R9::::::::::::::::::::::::::::::9 *R,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������dddccc������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)$! 3999999999999999999999999999999 4)%!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������cccccc������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#,t888888888888888888888888888887,t,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������cccccc������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#%&4477767677777777777777777777774%&4+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������cccccc������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#.6556555665566656565555665555.+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������cccccc������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,# (O3444444444444444444444444443 (O,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������bbbbbb������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)$ /33333333333333333333333333 /)$ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������bbbbbb������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#*p22222222222222222222222221*p,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������bbbbbb������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#%%2/111111111111111111111110.&%2+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������aaaaaa������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*/0000000000/00//00/0//0/*+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������aaaaaa������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,# &M.////..../....../...../. 'M,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������aaaaaa������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)$ +-----------,---------- +)$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������aaa```������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#'n,,,,,,,,,,,,,,,,,,,,,,'n,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������``````������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#&%1+,,,,,,,,,,,,,,,,,,,,+&%0+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������``````������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#),,,,,,,,,,,,,,,,,,,,(+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������``````������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#!&H+++++++++++++,++++++!&I,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������```___������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#&%/%%3%%2%%2%%2&%2%%2%%2&%2%%2%%2%%2%%2&%2%%3%%2%%2%%3&%2&%.*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������______������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������______������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������___aaa������ +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+# ������aaahhh%&%������                                                                                                                                                             ������%%%hhh|||???������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������???||{ZZZ:;;:::ZZZYYYCCC898111/00000/00000000/00000/00000/00000/00/00000000/00000/0000000/000/0000//00000000000/00/00000/00000/00000000000000000000/0000//00000/00000/00000/00/00000000/00000/00000000000/00/00000/00000/00000000/00000000000/00/00000/00000/00000000/0/00000/000/00000/00000000000/00/00000/00000/00000000000000000000/0000/000/0000/000/0000//00000000000/00/00000/00000/00000000000000000000/0000//00000000000/00/00000/00000/00000000/00000000000/00/00000/00000/00000000/0/000/00000////00/00011888CCCYYY|||gggbbbbbbbbbbbbbbbaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaabbbbbbbbbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbaaaaaabbbbbbbbaaaaaaaaaabbbggg|||ɩقՃ/᫬.4Liڄڄ��۾ݾ���+,�����%ݩ٩%��v�\t�lw��� \ڹۺ[ ��q|�\t�\t�\t�]v���� .Дg{mnnnnnnnnnnnnnnnnnnnnnnnnonnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnmmnnnmmmmmmmmnnnnmmmnmmmmnmmmmmmmmmmmmmnnnmmmmmmmmmnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmnnmnnnfؓ/ ���]v�\t�\t�\t�\t�\t�\t�ep~���Yp��!_�$�$�$�$�$�$�%�%�%�&�'�(�(�)�)�*�+�,�,�-�.�/�/�0�1�1�2�3�3�4�5�6�6�7�8�8�9�:�:�;�<�=�=�>�>�?�@�A�A�B�B�C�D�E�E�F�G�H�H�I�I�J�K�L�L�M�N�O�O�P�P�Q�R�R�S�T�T�U�V�W�W�X�Y�Y�Z�Z�[�\�]�^�^�_�_�`�a�b�b�c�d�d�e�f�f�g�h�i�i�j�k�k�l�l�m�n�o�o�p�q�r�s�s�s�t�u�v�v�w�x�x�y�z�z�{�|�}�}�~��������������������������������������_T���gv�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�'�(Y&&&''()**+,,-./001223445677899:;<<=>>?@AABCDDEFFGHHIJKKLMNNOPPQRSSTUUVWWXYZZ[\\]^__`abbcddefgghijjkllmnnopqqrssttuvwxyyz{{|}}~���������������������������������������� X�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�-�.8(''()++,--./0012334556789::;<<=>??@ABBCDDEFGGHIJKKLMNNOPQQRSSTUVVWXYZZ[\]]^_``abccdeefghiijkllmnoopqqrsstuvwxxyz{{|}~~����������������������������������������� 7�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�0� 2+***+,-../0122344567899:;<==>??@ABBCDEFGGHIJJKLMNNOPQRRSTUUVWXXYZ[\]]^_``abccdefgghijkklmmnopqrrstuuvwxyzz{|}}~����������������������������������������� �\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�����%�/O,,,,--//0112345577899:;<<=>?@AABCCEEFGGHIJKLLMNNPPQRSSTUVVWXYZZ\\]^__`abccddffghijjklmmnoppqrsstuvwxxzz{||}~�����������������������������������������N����\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�Bc�9�"H.o,,,,-./0122345567899:;<==>?@@ABCCDEFGHHIJKKLMNNPPQRSSTUVVWXYZ[[\]^^_`aabcdeffghijjklmmnopqqrstuuvwxxyz{||}~���������������������������������������o �Ts�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t� 3� 2�$K/I.,,.//0122344567889:;<==>?@@ABCDDEFGGHIJJKLMNOPPQRRSTUVVWXYZ[[\]^^_`abccdeffghiijklmnnopqqrsttuvwxxyz{||}~�������������������������J"{��\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�8�8��'� ; .+1A3G4G4G4G5G6G6G7G7G8G9G9G:G:G;G;G<G=G>G?G@F@GAGBGCGDGEGEGEGFGGGGGHGIGJGKGKGKGLGNGNGOGPGQGQGRGSGSGUFUGUGVGWGXGYGZGZG[G[G\G]G]G^G_G`G`GaGbGcGcGeGfGfGfGhGiGiGiGkGlGnGnGnGpGqGqGqGrGsGtGuGuGvGwGxGxGyGzG{G|G}G~GGGGGGGGGGGGGGGGGGGGGGGG�G�G�G�G�G�G�G�G�G�G�G�G�G�G�G�G�G�G�G�G�GG G F F G GG F GF G GG F F FA, ����\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�To���7�-�-�/�0�0�0�1�2�2�3�4�4�6�6�6�7�8�8�:�;�;�=�>�>�?�?�@�B�C�C�C�D�E�E�F�H�H�I�J�J�K�L�M�N�O�P�P�Q�R�R�T�T�U�V�W�W�Y�Z�Z�[�[�\�]�^�_�_�`�a�b�c�d�d�f�f�g�g�h�i�j�j�k�l�n�n�n�o�p�q�r�r�s�t�u�u�v�w�x�y�z�z�{�|�}�}�~�~��������������������������������������������������������������������������������������Y}�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���������� ���������d���d����������\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\u�KOU�ILQ�DEF�CDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDC�BCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDC�BCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�BBC�EGI�JNT�EIN�\u�\t�\t�\t�HMR�GKO�CDE�$��DEFCDDDDDDDDDDDDDDDDDDDDDDDDDCBCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDBCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCBCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDBCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDDCCBDDDDDDDDDDDDDDDDDDDDDDDDDDDBCCEGH/���CCC�EIN�EJP�\t�IIJ�HHI�Vu�DEE6DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDDCDEDDE7C\wGIK�IKM�HHI�LLLEEErDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEEFsLOSIJK�HZk�EFFqEEEEEDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFqu|�GGH=FFFFFFFFFEEEEEEEEEEEEEEEEEEEEEFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFEEEEEEEEEEEEEEEEEEEEEFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFEEEEEEEEEEEEEEEEEEFFFFFFEEEEEEEEEFEEEEEEEEEEEEEEEEEEEEEEEFFFEEEEEEEEEEEEEEEEEEEEEFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFEEEEEEEEEEEEEEEEEEFFFEEEEEEFFFEEEEEEEEEFFFFFFEEEEEEEEEEEEEEEEEEEEEFFFEEEEEEFFFGGG=GGHGGGFFFFFFGGGFFFGGGGGGFFFGGGFFFFFFFFFFFFGGGFFFGGGGGGGGGFFFGGGGGGGGGFFFFFFFFFGGGGGGGGGGGGFFFFFFGGGGGGGGGGGGFFFFFFFFFFFFGGGGGGFFFGGGFFFGGGGGGFFFFFFGGGFFFFFFGGGFFFGGGFFFFFFGGGGGGFFFFFFFFFGGGFFFGGGGGGGGGFFFFFFGGGGGGFFFFFFFFFFFFFFFGGGGGGFFFFFFGGGGGGGGGGGGFFFFFFFFFFFFGGGGGGFFFGGGFFFGGGGGGGGGFFFGGGFFFFFFFFFFFFGGGFFFFFFGGGFFFFFFGGGFFFGGGFFFFFFFFFFFFGGGGGGGGGGGGGGGGGGFFFFFFGGGFFFFFFGGGGGHHHHGGGHHHHHHHHHGGGHHHGGGHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGHHHGGGHHHGGGGGGGGGHHHGGGHHHIIIHHHHHHHHHHHHHHHHHHHHHHHHGGGIIIMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMIIIGGGHHHHHHHHHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIaaaaaaIIIIIIIIIIIIIIIIIIIIIIIIIIIJJJJJJJJJJJJJJJJJJJJJIIIaaaccc777111222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222111777cccaaaIIIJJJJJJJJJJJJJJJJJJJJJKKKKKKKKKKKKKKKKKKKKKLLLJJJ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������JJKLLLKKKKKKKKKKKKKKKKKKKKKLLLLLLLLLLLLLLLLLLLLLQQQrrr� "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" �rssRRQLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMTTTddd$,$,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#+#+#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,$$dddTTTMMMMMMMMMMMMMMMMMMMMMNNNNNNNNNNNNNNNNNNNNNTTTccc$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"<-<-*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$cccTTTNNNNNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOUUUccc$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!hGhG(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$cccUUUOOOOOOOOOOOOOOOOOOOOOPPPPPPPPPPPPPPPPPPPPPVVVbcb$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!` ` (!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$cccVVVPPPPPPPPPPPPPPPPPPPPPQQQQQQQQQQQQQQQQQQQQQWWWbbb$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#.%w w .%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$bbbWWWQQQQQQQQQQQQQQQQQQQQQRRRRRRRRRRRRRRRRRRRRRXXXbbb$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"<-ډډ ;-*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$bbbXXXRRRRRRRRRRRRRRRRRRRRRSSSSSSSSSSSSSSSSSSSSSYYYbbb$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#("T;T;("+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$bbbYYYSSSSSSSSSSSSSSSSSSSSSTTTTTTTTTTTTTTTTTTTTTYYYaaa$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#'!vOvO(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$abaZZZTTTTTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUUUUZZZaaa$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"f f )"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+##aaaZZZUUUUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVVVVV[[[aaa$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!,!,!,!,!,!,!,!,!,!,!,!+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#1'| | 1'+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+",!,!,!,!,!,!,!,!,!,!,!,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+##aaa[[[VVVVVVVVVVVVVVVVVVVVVWWWWWWWWWWWWWWWWWWWWW\\\aaa$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)*!Wo_|^{^{^{^{^{^{^{^{^|^{$:<+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"E2E2)"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$9<^{^|^{^{^{^{^{^{^{^|_|Wo)*!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$aa`\\\WWWWWWWWWWWWWWWWWWWWWXXXXXXXXXXXXXXXXXXXXX]]]```$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*' �����������t+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!dDdD(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$t����������� *'+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$```]]]XXXXXXXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYY^^^```$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!Rg����������$9;+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!\\(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$9;����������Rg,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$```^^^YYYYYYYYYYYYYYYYYYYYYZZZZZZZZZZZZZZZZZZZZZ______$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"'/+�����������b+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#/%w v /%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"b�����������'/++"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$______ZZZZZZZZZZZZZZZZZZZZZ[[[[[[[[[[[[[[[[[[[[[______$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"e�����������'/*+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"B1B1*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"'/)�����������e+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$___```[[[[[[[[[[[[[[[[[[[[[\\\\\\\\\\\\\\\\\\[[[```___$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!"=C����������Qi,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!gFgF(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!Pi����������"=C,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$___```\\\\\\\\\\\\\\\\\\\\\]]]]]]]]]]]]]]]]]]\\\aaa___$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*&w����������� {)(+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"c c )"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)( {�����������w*&+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$___aaa\\\]]]]]]]]]]]]]]]]]]^^^^^^^^^^^^^^^^^^]]]bbb^^^$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!Md���������� BN,!+#+#+#+#+#+#+#+#+#+#+#+#+#*#5)ʀ ʀ 5)*#+#+#+#+#+#+#+#+#+#+#+#+#+#,! AN����������Md,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$^^^bbb^^^^^^^^^^^^^^^^^^^^^_______________^^^^^^ccc^^^$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"'.)�����������j+$+#+#+#+#+#+#+#+#+#+#+#+#+#)"S;S;)"+#+#+#+#+#+#+#+#+#+#+#+#+#+$j�����������'.)+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$^^^ccc^^^^^^^^^___^^^___^^^___```______``````___ddd^^^$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"_�����������$58+"+#+#+#+#+#+#+#+#+#+#+#+#(!X  W(!+#+#+#+#+#+#+#+#+#+#+#+#+"$58�����������_+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$^^^ddd___```___```___```___````````````aaa``````eee]]]$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"#:A�����������Y+"+#+#+#+#+#+#+#+#+#+#+#+#0&w  w 0&+#+#+#+#+#+#+#+#+#+#+#+#+"Y�����������#:A,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$]]]eee``````aaaaaaaaa```aaaaaaaaaaaaaaaaaaaaaaaaeee]]]$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*&o�����������~','+"+#+#+#+#+#+#+#+#+#+#)"J5 '..' J5)"+#+#+#+#+#+#+#+#+#+#+"','~�����������o*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$]]]fffaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbfff]]]$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!Ia����������Jd,!+#+#+#+#+#+#+#+#+#+#(!zQ(5<<5(zQ(!+#+#+#+#+#+#+#+#+#+#,!Jd����������Ia,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$]]]fffbbbbbbbbbbbbbbbbbbbbbcccccccccccccccccccccggg\\\$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"','|����������� p*'+#+#+#+#+#+#+#+#+#+#-$r "6CJJC6" r -$+#+#+#+#+#+#+#+#+#+#*' p�����������|','+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$\\\gggcccccccccccccccccccccdddddddddddddddddddddhhh\\\$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"Y�!=J,"+#+#+#+#+#+#+#+#)"E2 /CQXXQC/ E2)"+#+#+#+#+#+#+#+#,"!=J�Y+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$\\\hhhdddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeeiii\\\$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#7?�a+#+#+#+#+#+#+#+#+#(!sM !;P_gg_P<! sM(!+#+#+#+#+#+#+#+#+#a�#7?+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$\\\iiieeeeeeeeeeeeeeeeeeeeefffffffffffffffffffffjjj[[[$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%h�%25+"+#+#+#+#+#+#+#,$o -H^muum^H-o ,$+#+#+#+#+#+#+#+"%25�h*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$[[[jjjfffffffffffffffffffffgggggggggggggggggggggkkk[[[$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!E^R|,"+#+#+#+#+#+#*"B0ތ 9Tk{σσ{kU9ތ B0*"+#+#+#+#+#+#+"R|E^,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$[[[kkkggggggggggggggggggggghhhhhhhhhhhhhhhhhhhhhkkk[[[#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"(+& t�� s(*%+"+#+#+#+#+#(!oJ "DaxщԑԑщxaD# nJ(!+#+#+#+#+#+"(*% s�� t(+&+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$[[[kkkhhhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiiilllZZZ#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"SD_,"+#+#+#+#+#,#m -OmЅ֖ڟڟ֖ЅmO- m ,#+#+#+#+#+#,"D_T+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$ZZZllliiiiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjjjjmmmZZZ$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$4=|�f*&+#+#+#+#+#2'| 7ZyՒܤܤՒyZ7| 2'+#+#+#+#+#*&f�|$4<+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$ZZZmmmjjjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkkknnnZZZ$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$a�}"8G,"+#+#+#+#)"[AeЅڟڟЅeA[)"+#+#+#+#,""8G}�a*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$ZZZnnnkkkkkkkkkkkkkkkkkkkkkllllllllllllllllllllloooYYY$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"A[�X+#+#+#+#+#)"J5#JoԐ߬߬ԐpJ#J6)"+#+#+#+#+#X�A[,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$YYYooolllllllllllllllllllllmmmmmmmmmmmmmmmmmmmmmpppYYY$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(*% l�s%/2+"+#+#+#+#,#w'TzٜٜzTw',#+#+#+#+#+"%/2s� l(*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$YYYpppmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnnnnqqqYYY$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"N~~~~~~~~~~~~Kw,"+#+#+#+#(!bI!ZЄݧݧЄZbI (!+#+#+#+#,"Kw~~~~~~~~~~~~N+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$YYYqqqnnnnnnnnnnnnnnnnnnnnnoooooooooooooooooooooqqqYYY$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$2:s}|||||||||�} h()#+#+#+#+#*#4*ƚTՎՎƚT4**#+#+#+#+#()# h�}|||||||||}s$2:+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$YYYqqqoooooooooooooooooooooppppppppppppppppppppprrrXXX$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$[�|{{z{zz{zz{x>[,"+#+#+#+#(!f=ՕՕf=(!+#+#+#+#,"?[x{zzzzzzzzz�|[*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$XXXrrrpppppppppppppppppppppqqqqqqqqqqqqqqqqqqqqqsssXXX$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"=Xvyyyyyyyxyy�z\*%+#+#+#+#)"C7"߿߿C7")"+#+#+#+#*%\�zxyyyyyxyxyv=X,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$XXXsssqqqqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrrrtttXXX$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#()# e�xwwwwwwwwwwq"4C,"+#+#+#+#*"jj*"+#+#+#+#,""4Cqwwwwwwwwww�x d()#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$XXXtttrrrrrrrrrrrrrrrrrrrrrsssssssssssssssssssssuuuWWW$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"I|vuuuuuuuuuuvP+#+#+#+#+#(!YM:YM:(!+#+#+#+#+#PvuuuuuuuuuuuI|+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+##WWWuuussssssssssssssssssssstttttttttttttttttttttvvvWWW$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$08ktststsssssth&-/+"+#+#+#+#1(1(+#+#+#+#+"&-/htssssssssstk$08+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+##WWWvvvttttttttttttttttttttttttuuuuuuuuuuuuuuuuuuwwwWWW$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$T�srrrrrrrrrrqDr,"+#+#+#+#( tmatma( +#+#+#+#,"Drqrrrrrrrrrr�sT+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$WWWwwwuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvwwwVVV$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"9Umpppppppppp�q ])(!+#+#+#+#*"=5'=5'*"+#+#+#+#)'! ]�qppppppppppm9U,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$VVVxxxvvvvvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwwwwwwxxxVVV$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#((" ]�onnnnnnnnnnl9W,"+#+#+#+#)!)!+#+#+#+#,"9Wlnnnnnnnnnn�o ](("+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$VVVxxxwwwwwwwwwwwwwwwwwwwwwxxxxxxwwwxxxxxxwwwwwwyyyVVV$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"Dymllllllllll�nS*$+#+#+#+#)!PI<PI<)!+#+#+#+#*$R�mllllllllllmDy,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$VVVyyyxxxxxxwwwxxxxxxxxxwwwxxxyyyxxxxxxyyyxxxyyyzzzUUU$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"%.6ckkkkkkkkkkke#1@+"+#+#+#+#.&.&+#+#+#+#+"#1@ekkkkkkkkkkkc%.6+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$UUUzzzxxxyyyxxxxxxxxxxxxyyyyyyzzzyyyzzzyyyyyyyyy{{{UUU$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$N�jiiiiiiiiiijH+#+#+#+#+#( icXicX( +#+#+#+#+#Hjiiiiiiiiii�jN+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$UUU{{{zzzyyyzzzzzzyyyzzzzzzzzzzzzzzzzzzzzzzzzzzz|||UUU$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"6Seggggggggggh\&+-+#+#+#+#*"80"80"*"+#+#+#+#&+-\hgggggggggge6S,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$UUU|||zzzzzzzzzzzzzzzzzzzzz{{{{{{{{{{{{{{{{{{{{{}}}UUU$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)'! V�feeeeeeeeefe>m,"+#+#+#+#( xx( +#+#+#+#,"=meeeeeeeeeee�f V)'!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$TTT}}}{{{{{{{{{{{{{{{{{{{{{|||||||||||||||||||||~~~TTT$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"?uddddddddddd�e S)&+#+#+#+#*";3%;3%*"+#+#+#+#)& S�dddddddddddd?v,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$TTT}}}|||||||||||||||||||||}}}}}}}}}}}}}}}}}}}}}~~~TTT$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"%,4Zcbbbbbbbbbb_5S,"+#+#+#+#*"*"+#+#+#+#,"5S_bbbbbbbbbbbZ%,4+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$TTT~~~}}}}}}}}}}}}}}}}}}}}}~~~~~~~~~~~~~~~~~~~~~SSS$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#H�a``````````�aJ+$+#+#+#+#+#+#+#+#+#+#+$I�a``````````�aH+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$TTT~~~~~~~~~~~~~~~~~~~~~SSS$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#," 3P\_^^^^^^^^^_Y#.<+"+#+#+#+#+#+#+#+#+"$.<Y_^^^^^^^^^_\ 3P,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$SSSSSS$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)& N�]]]]]]]]]]]]@+#+#+#+#+#+#+#+#+#+#@]]]\]]\]]\]�] N)& +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$SSSSSS$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,";r[[[[[[[[[[[\R')*+#+#+#+#+#+#+#+#')*Q\[[[[[[[[[[[;r,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$SSSRRR$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#%*2RZYYYYYYYYYYY8i,"+#+#+#+#+#+#,"8iYYYYYYYYYYYYR%*3+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$RRRRRR$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#B�XWWWXWWWWWW�X I)%+#+#+#+#+#+#)% I�XWWWWWWXWWW�XB+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$RRRRRR$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#," 0MSVVVVVVVVVVVS 1O,"+#+#+#+#," 1OSVVVVVVVVVVVS 0M,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$RRRQQQ$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)% G�UTTTTTTTTTT�UA+#+#+#+#+#+#A�UTTTTTTTTTT�U G)%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$QQQQQQ$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"7oRRRRRRRRRRRSM$+9+#+#+#+#$+9MSRRRRRRRRRRR7o,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$QQQQQQ$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#&)0JQQQQPQPQPQPQ9+#+#+#+#9QQPPPPPQPPPQJ&)0+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$QQQPPP$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#<OOOOOOOOOOOO G''(+#+#''( GOOOOOOOOOOOO<+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$QQQPPP$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"!.KKMMMMMMMMMMML2d,","2dLMMMMMMMMMMMK!.K,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$PPPPPP$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)% @LKKKKKKKKKKL@*$*$ @LKKKKKKKKKKL @)%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$PPPPPP$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"3lIIIJJIIJJIIJG!,H!,HGJIIJIIIIIIII3l,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$OOOOOO$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#&(/CHHHHHHHHHHHH99HHHHHHHHHHHHC&(.+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$OOOOOO$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#7GFFFFFFFFFFFDDFFFFFFFFFFFF7+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$OOOOOO$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#!+HBDDDDDDDDDDDDDDDDDDDDDDDDB!+H,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$NNNNNN$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$:CCCCBBBCCCCBBBBBCCBBBCBC:*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$NNNNNN$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#/i@AAAAAAAAAAAAAAAAAAAAAA@/i,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$NNNMMM$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#&&-;??????????????????????;&&-+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$MMMMMM$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#2=====================>2+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+##MMMMMM$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#")F:<<<;<<<<<;;<;<;;;<;<:")F,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+##MMMMMM$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$3::::::::::::::::::::3*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$MMMLLL$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#+f88888888888888888888+f,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$LLLLLL$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#'%+ 3766666666666666666 3'%++#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$LLLLLL#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#-555554455545455555,+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$LLLLLK#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#"'C233333333333333332"'D,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$KKKKKK$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$-1111111111111111,*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$KKKKKK$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#(c////////////////(c,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$KKKJJJ$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#'$* ,...--------.-. ,'$*+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$JJJJJJ$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(,,,,,,,,,,,,,,(+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$JJJJJJ$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#"%A+,,,,,,,,,,,,+"%A,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$JJJJJJ#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#(*)*)**))*)**(*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$JJJIII#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$IIIJJJ$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$$JJJTTT�                                                                                                          �TTTrrr''(������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������'''rrr_``566$$$!!!!!!!"!!!!!""!""!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!""!!!!!!!"!!!!!!!!"!!!!!!!!!!!!!!!!!!"!""!!!!!!!!!!!!!!!!!!"""!!!!!!!"!!!!!!!!"!!!!"""!!!!!!!"!!!!!!!!"!!!!!!!!!!!!!!!!!""!!!!!!!"!!!!!!!!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!""!!!!!!!"!!!!!!!!"!!!!!!!!!!!!!!!!!""!!!!!!!"!!!!!!!!"!!!!"""!!!!!!!"!!!!!!!!"!!!!!!!!"!!!!!!!$$$565___wwwvvvvvvvvvuuuvvvvvvvvvvvvvvvvvvvvvvvuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuvvvvvvvvvvvvvvvvvvvvvuuuvvvvvvvvvvvvvvvvvvvvvuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvuuuvvvvvvvvvvvvvvvvvvvvvuuuvvvvvuuuuuuuvww㦦ʡɠ;檪;����oo�����qq���� '�6܎ӻۏ6������\t����+H�*JP<<====>?@@BCCEFFGHIJKLMMNOPQRSTUVVWXYZ[\]^__`abcdefghhijklmnoopqrstuvwxyzz{|}~)P2����\t�\t�\t�\t��-�&=%�%�&�'�(�)�+�,�-�.�/�0�1�2�3�4�6�7�89�:�;�<�=�>�?�@�B�C�D�E�F�G�H�I�J�K�L�N�O�P�Q�R�S�T�U�V�W�X�Y�[�\�]�^�_�`�a�b�c�e�f�g�h�i�j�k�l�m�n�o�p�r�s�t�u�v�w�x�y�{�{�|�~�~��������������������������������< ��\u�\t�\t�\t�\t�\t�\t�-�.*)*+-./012456789;<=>?@ACDEFGHJKLMNOQRSTUVWYZ[\]^`abcdeghijklmopqrstuwxyz{}~����������������������������\t�\t�\t�\t�\t�\t�\t�\t�9��!�-e,,,./01245678:;<=>?ABCDEGHIJKLNOPQRTUVWXZ[\]^_abcdeghijklnopqrsuvwxz{|}~���������������������������e���\t�\t�\t�\t�\t�\t�\t�\t�?� 2�8.b-,./013456789;<=>@ABCDEGHIJKLNOPQRTUVWXZ[\]^_abcdeghijklnopqrtuvwxz{|}~���������������c � �\t�\t�\t�\t�\t�\t�\t�\t�\t� 3� 3�� �0/1282838485868788898:8;8<8>8?8@8A8C8D8E8E8F8H8I8J8K8L8M8N8P8Q8R8S8T8U8V8X8Y8Z8[8\8]8^8_8`8b8c8d8e8f8h8i8j8k8m8n8o8q8q8r8t8u8v8w8x8y8{8|8}88888888888888888�8�8�8�8�8�8�8�8�8�8�8�8�8888888888881 ��� �\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�"H�L�0�.�0�1�2�3�4�5�6�7�8�9�:�;�=�>�?�@�B�C�D�E�F�G�H�J�J�K�M�N�P�Q�Q�S�T�U�V�W�Y�Z�[�\�]�^�_�a�b�c�d�f�g�h�i�j�k�m�n�o�p�q�r�t�u�v�w�x�z�{�|�}�~�������������������������������������������������������� �&�&�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���`������� ���������d���d����������\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�Xl�=>?�DFH�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�CDD�CDE�EHJ�;6-�Ym�\t�FGI�FGG�CCD�EFHDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDCDDCDDDGLCCB�EGH�EGI�DEF�GIJDDEODDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEOFILEFF�EGIEEExDDDDDDDDDDDDEEEEEEEEEEEEEEEDDDDDDDDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDEEEEEEEEEDDDEEEDDDEEEEEEEEEEEEDDDEEEEEEEEEEEEEEEEEEEDDDDDDDEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEDEEEEEEEEEDDDEEEDDDEEEEEEEEEEEEDDDEEEEEEEEEEEEEEEEDDEEDDDDDDDEEEDDDEEEEEEEEEEEDDDDDDDEFFyJKMFFGYEEFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFYGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGHHIHHHHHHHHHHHHHHHHHHGGGHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHGGGHHHHHHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIIMMMmmm~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}~~~mmmMMMIIIIIIIIIIIIIIIIIIKKKKKKKKKJJJKKKJJJqqqkkk222))))**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)**)))222kkkqqqJJJJJJKKKJJJKKKJJJLLLLLLLLLLLLLLLQQQjjj                                                                                jjjRQQLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMUUUNNN��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���NNNUUUMMMMMMMMMMMMMMMNNNNNNNNNNNNNNNVVVLLL��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*">.>.*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���LLLVVVNNNNNNNNNNNNNNNPPPPPPPPPPPPOOOWWWKLK��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!jHjH(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���LLLWWWOOOPPPPPPPPPPPPQQQQQQQQQQQQQQQXXXKKK��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!a a (!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���KKKXXXQQQQQQQQQQQQQQQRRRRRRRRRRRRRRRYYYKKK��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#.%x x .%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���KKKYYYRRRRRRRRRRRRRRRTTTSSSSSSSSSSSSZZZKKK��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*"=-܊܊=-*"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���KKKZZZSSSSSSSSSTTTTTSUUUUUUUUUUUUUUU\\\JJJ��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!V<V<(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���JJJ\\\UUUUUUUUUUUUUUUVVVVVVVVVVVVVVV]]]JJJ��� ,$+#+#+#+#+#+#+#+#+#+#+$))))))))))))))))))+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#'!zQyQ'!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$))))))))))))))))))+$+#+#+#+#+#+#+#+#+#+#,$ ���JJJ]]]VVVVVVVVVVVVVVVWWWWWWWWWWWWWWW^^^JJJ��� ,$+#+#+#+#+#+#+#+#+#+"(+"v L[,!+#+#+#+#+#+#+#+#+#+#+#+#+#*"i i *"+#+#+#+#+#+#+#+#+#+#+#+#+#,!L[ u(+"+#+#+#+#+#+#+#+#+#+#,$ ���JJJ^^^WWWWWWWWWWWWWWWYYYYYYYYYYYYXXX___JJJ��� ,$+#+#+#+#+#+#+#+#+#+#+#k�������� ~*'+#+#+#+#+#+#+#+#+#+#+#+#*#5)ˀ ˀ 5)*#+#+#+#+#+#+#+#+#+#+#+#+#*' ~��������k+#+#+#+#+#+#+#+#+#+#+#,$ ���JJJ___XXXYYYYYYYYYYYYZZZZZZZZZZZZZZZ```III��� ,$+#+#+#+#+#+#+#+#+#+#,!"?G�������!AK,!+#+#+#+#+#+#+#+#+#+#+#)"M7M7)"+#+#+#+#+#+#+#+#+#+#+#,!!AK�������!?G,!+#+#+#+#+#+#+#+#+#+#,$ ���III```ZZZZZZZZZZZZZZZ[[[[[[[[[[[[[[[aaaIII��� ,$+#+#+#+#+#+#+#+#+#+#+#*' {��������k+#+#+#+#+#+#+#+#+#+#+#+#(!uOvO(!+#+#+#+#+#+#+#+#+#+#+#+#k�������� {*'+#+#+#+#+#+#+#+#+#+#+#,$ ���IIIaaa[[[[[[[[[[[[[[[\\\\\\\\\\\\\\\bbbIII��� ,$+#+#+#+#+#+#+#+#+#+#+#,!Ph��������%55+"+#+#+#+#+#+#+#+#+#+#+#l l +#+#+#+#+#+#+#+#+#+#+#+"%55��������Ph,!+#+#+#+#+#+#+#+#+#+#+#,$ ���IIIbbb\\\\\\\\\\\\\\\^^^^^^^^^^^^^^^cccIII��� ,$+#+#+#+#+#+#+#+#+#+#+#+"'/+��������Z|,"+#+#+#+#+#+#+#+#+#*";-և և ;,*"+#+#+#+#+#+#+#+#+#,"Z|��������'/++"+#+#+#+#+#+#+#+#+#+#+#,$ ���IIIccc^^^^^^^^^^^^^^^_______________dddHHH��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+"b�������� (,%+"+#+#+#+#+#+#+#+#(!`B `B(!+#+#+#+#+#+#+#+#+"(,% ��������a+"+#+#+#+#+#+#+#+#+#+#+#+#,$ ���HHHddd_______________```````````````eeeHHH��� ,$+#+#+#+#+#+#+#+#+#+#+#+#,""<D�������I`,!+#+#+#+#+#+#+#+#)"a a )"+#+#+#+#+#+#+#+#,!I`�������"<D,"+#+#+#+#+#+#+#+#+#+#+#+#,$ ���HHHeee```````````````bbbbbbbbbbbbaaagggHHH��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#*& q��������p*&+#+#+#+#+#+#+#*#5)ˀ $//$ˀ 5)*#+#+#+#+#+#+#+#*&p�������� q*&+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���HHHgggaaabbbbbbbbbbbbccccccccccccccchhhGGG��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#,!Ke�������!<G,"+#+#+#+#+#+#(!W= 6BB6 W=(!+#+#+#+#+#+#,"!<G�������Je,!+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���GGGhhhcccccccccccccccdddddddddddddddiiiGGG��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+"'-*}��`+#+#+#+#+#+#+#(!\0HUUH0[(!+#+#+#+#+#+#+#`��}'-*+"+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���GGGiiidddddddddddddddeeeeeeeeeeeeeeejjjGGG��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"Z%12+"+#+#+#+#*#3'} A[hh[A} 3'*#+#+#+#+#+"%12Z+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���GGGjjjeeeeeeeeeeeeeeegggggggggggggggkkkGGG��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"#8BPx,"+#+#+#+#)"R: -Rm{{mR- R:)"+#+#+#+#,"Px#8B,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���GGGkkkggggggggggggggghhhhhhhhhhhhhhhlllFFF��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%h�� r(*#+#+#+#+#(!X<cӎӎc=X(!+#+#+#+#(*# r��h*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���FFFlllhhhhhhhhhhhhhhhiiiiiiiiiiiiiiimmmFFF��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,!EbB\,"+#+#+#1&z KsԑڠڠԑsKz 1&+#+#+#,"B\Eb,!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���FFFmmmiiiiiiiiiiiiiiikkkkkkkkkkkkjjjnnnFFF��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"',( r�d*%+#+#+#0&x (ZσۣۢσZ(x 0&+#+#+#*%d� r',(+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���FFFnnnjjjkkkkkkkkkkkkllllllllllllllloooEEF��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"S{"7C,"+#+#(!uP5hՓՓh5uP(!+#+#,""7CzS+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���FFFooolllllllllllllllmmmmmmmmmmmmmmmpppEEE��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#5?xU+#+#+#*">/ל=uۣۣuל=>/*"+#+#+#Ux#5?+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���EEEpppmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnqqqEEE��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*%_�~}}}}}}~p&.0+"+#+#)!q7ςςq8)!+#+#+"&.0p~}}}}}}�~_*%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���EEEqqqnnnnnnnnnnnnnnnpppppppppppppppsssEEE��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"@_y{{{{{{{zHs,"+#+#)!QA%ąąQA%)!+#+#,"Hrz{{{{{{{y@_,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���EEEssspppppppppppppppqqqqqqqqqqqqqqqtttDDD��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(*' hyxxxxxx�z d)(!+#+#+#.%qq.%+#+#+#)(! d�yxxxxxxy h(*&+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���DDDtttqqqqqqqqqqqqqqqrrrrrrrrrrrrrrruuuDDD��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"Lwvvvvvvvs<W,"+#+#( k]Fk]F( +#+#,"<WsvvvvvvvwL+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���DDDuuurrrrrrrrrrrrrrrtttttttttttttttvvvDDD��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#2=mttttttt�uW*$+#+#*"80 ǹǹ80 *"+#+#*$W�utttttttm#2=+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���DDDvvvtttttttttttttttuuuuuuuuuuuuuuuwwwDDD��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$V�sqqqqqqrk#2@+"+#+#( ww( +#+#+"#2@krqqqqqq�sV*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���DDDwwwuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvxxxCCC��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,";\mooooooopK+#+#+#)!IB5JB5)!+#+#+#Kpooooooom;\,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���CCCxxxvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwyyyCCC��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#()% ^�nmmmmmmma&+-+"+#+#,$,$+#+#+"&+-ammmmmmm�n ^()%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���CCCyyywwwwwwwwwwwwwwwyyyyyyyyyyyyyyyzzzCCC��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"Fkjjjjjjjj@n,"+#+#( a[Oa[O( +#+#,"?njjjjjjjjkE+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���CCCzzzyyyyyyyyyyyyyyyzzzzzzzzzzzzzzz{{{BBC��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$/;aihhhhhh�i V)&+#+#*"4,ſſ4,*"+#+#)& V�ihhhhhhha$/;+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���BBB{{{zzzzzzzzzzzzzzz{{{{{{{{{{{{{{{|||BBB��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$N�gfffffffc6S,"+#+#( {vl{vl( +#+#,"6Scfffffff�gN*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���BBB|||{{{{{{{{{{{{{{{|||}}}}}}|||}}}~~~BBB��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"7Ybdcccccc�dK*$+#+#*"5-5-*"+#+#*$L�dcccccccb7Y,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���BBB~~~}}}|||}}}}}}}}}~~~~~~~~~~~~~~~BBB��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#('$ T�baaaaaab[#.<+"+#+#*"*"+#+#+"#.<[aaaaaaa�b T('$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���BBB~~~~~~~~~~~~~~~AAA��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"?|_________A+#+#+#+#+#+#+#+#A_________?|,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���AAAAAA��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"$-9W]\\\\\\]R')*+#+#+#+#+#+#')*R]\\\\\\]W$-9+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���AAAAAA��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+$F�[ZZZZZZZZ8i,"+#+#+#+#,"8iZZZZZZZZ�[F+$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���AAAAAA��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"3VVXXXXXXX�Y I)%+#+#+#+#)% I�YXXXXXXXV3V,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���AAA@@@��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(&" J�VUUUUUUVS 0O,"+#+#," 0OSUUUUUUU�V J(&"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���@@@@@@��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"9ySSSSSSSS�T@+#+#+#+#@�TSSSSSSSS9y,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���@@@@@@��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$*7LQQQQQQQQL$+9+#+#$+9LQQQQQQQQL$*7+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���@@@@@@��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#>ONNNNNNNO8+#+#8ONNNNNNNO>+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���@@@???��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"/SKLLLLLLLM D(''(&' DMLLLLLLLK/S,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���??????��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)%! AJJJJJJJJI1a1aIJJJJJJJJ A)%!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���??????��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#3vHGGGGGGGH > >HGGHGGGGG3u,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���???>>>��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#%(5AEEEEEEEEEEEEEEEEEEA%(5+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���>>>>>>��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#6CCCCCCCCCCCCCCCCCC6+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���>>>>>>��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,# +Q?AA@@@@AAAAA@A@@A? +P,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���>>>>>>��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)% 8>>>>>>>>>>>>>>>? 8)% +#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���>>>===��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#.r<<<<<<<<<<<<<<<<.r,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���======��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#%&37:9:::::9:9:9::7%&3+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���======��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#/87777777777777/+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���======��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,# (N45555555555554 (N,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���<<<<<<��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)$ /332233322333 /)$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���<<<<<<��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#)o000000000000)o,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���<<<<<<��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#%%1,.....-....-&%1+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���<<<;;;��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#),,,,,,,,,,)+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���;;;;;;��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#!&I++++++++++!%I,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���;;;;;;��� ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#&%-&%0&%0&%0&%0&%0&%0&%0&%0'%-*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ ���;;;<<<��� *")!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!)!*" ���<<<SSS                                                                              SSS@@@@@@®®;ବ;�NٻN���&yޗy&������+ѥ++,-/0134578:;<>?@BCEFGIJKMNOQRTUVWYZ\]_`abdeghiklmoprstvwyz{|~����\t�\t�,��%�)|()+-.0135689;<>?ABDEGHJKMNPQSUVXY[\^_abdeghjlmoprsuvxy{|~����������������������z�� �\t�\t�\t�\t�1N�-�. ,,-/023578:;=>@BCEFHIKMNPQSUVXY[\^`acdfgiklnoqstvwy{|~�������������������� �C|�\t�\t�\t�\t�\t��!��*�/-t.0134578:<=?@BDEGHJKMNPRSUVXZ[\^`acdfgiklnpqstvwy{|~�����������t���\t�\t�\t�\t�\t�\t�;[��#�-��*�� ������� �� ��������!��"��"�*�/�3��2��5��>�=�A�A�H��H��O�Q�R�S�Z�\�a�d�f�i��k��h�m�j�m�d�j��i��p�v�p�u�y�}�y�t�t�r�r��t��������������������������������������������������9�\t�\t�\t�\t�\t�\t�\t�\t�Nj�$M� N��K��K��K�I�L��L��L��M��N�O�P�Q�R��Q��R��R�S� U��T��U��U��V��V�X�X��X��Y��Z��Z��[��[��\��]��]��^� c��c��g��i��o��p�r� p��p��v��v��u��u��|�����������������������������������������������,�3��+�+�)�-�1��L~�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���@������� ������@���d���d����������\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�JPW�EFG�DDE�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CCC�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CDC�DDD�DDD�DDD�DDD�CDD�CDF�DGK�JPY�EFF�DCB�DDEDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDCDDDDDDDDDDDDCDDCDEEDB�FFG�FFGDDEfDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEfFHIFFFuEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFuGGGGGGGGGGGGFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFGGGGGGGGGGGGIIIIIIIIIHHHSSSggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggSSSHHHIIIIIIIIIKKKKKKKKKNNNddd322%$#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%%#%$#322dddNNNKKKKKKKKKMMMMMMLLLUUU999 """""""""""""""""""""""""""""""""""""""""""""""""""" 999UUULLLMMMMMMOOOOOONNNVVV122,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#@/@/*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$222VVVNNNOOOOOOQQQQQQPPPWWW222+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!lIlI(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#222WWWPPPQQQQQQRRRSSSRRRYYY222+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#("c c (!+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#222YYYRRRRRRSSRTTTTTTTTT[[[122+#+#+#+#+#+#+#+#,!,!,!,!,!,!+"+#+#+#+#+#+#+#+#+#/%y y /%+#+#+#+#+#+#+#+#+#+",!,!,!,!,!,!+#+#+#+#+#+#+#+#122[[[TTTTTTTTTVVVVVVVVV\\\112+#+#+#+#+#+#+#*'!AI FR FQ FQ FQ EO(,#+"+#+#+#+#+#+#+#*"?/ߌߌ?/*"+#+#+#+#+#+#+#+"(,# EO FQ FQ FQ FR!AI*'+#+#+#+#+#+#+#112\\\VVVVVVVVVXXXXXXXXX^^^111+#+#+#+#+#+#+#*( }[w,!+#+#+#+#+#+#+#(!\@\?(!+#+#+#+#+#+#+#,![w })(+#+#+#+#+#+#+#111^^^XXXXXXXXXZZZZZZZZZ___111+#+#+#+#+#+#+#,!Tm����� (+#+"+#+#+#+#+#+#(!XX(!+#+#+#+#+#+#+"(+# �����Tm,!+#+#+#+#+#+#+#111___ZZZZZZZZZ\\\\\\\\\aaa111+#+#+#+#+#+#+#+"&1.����J],!+#+#+#+#+#+#.%u u .%+#+#+#+#+#+#,!J]����&1.+"+#+#+#+#+#+#+#111aaa\\\\\\\\\^^^^^^^^^ccc111+#+#+#+#+#+#+#+#+#e�����s*&+#+#+#+#+#)"D1D1)"+#+#+#+#+#*&s�����e+#+#+#+#+#+#+#+#+#111ccc^^^^^^^^^`````````ddd011+#+#+#+#+#+#+#+#,!!=H����";D,"+#+#+#+#(!nJ  nJ(!+#+#+#+#,"";D����!=H,!+#+#+#+#+#+#+#+#011ddd`````````bbbbbbbbbfff001+#+#+#+#+#+#+#+#+#*' s�����`+#+#+#+#+#+#k 11k +#+#+#+#+#+#`����� s*'+#+#+#+#+#+#+#+#+#001fffbbbbbbbbbdddddddddggg000+#+#+#+#+#+#+#+#+#,!Li��&00+"+#+#*"=.ً1MM2ً=-*"+#+#+"&00�Li,!+#+#+#+#+#+#+#+#+#000gggdddddddddfffffffffiii000+#+#+#+#+#+#+#+#+#+"'.,|Ot,"+#+#(!gFLjjLfF(!+#+#,"Os|'.,+"+#+#+#+#+#+#+#+#+#000iiifffffffffhhhhhhhhhkkk000+#+#+#+#+#+#+#+#+#+#+"Z�� q))!+#+#*"h.fІІf.h*"+#+#))! q��Z+"+#+#+#+#+#+#+#+#+#+#000jjjhhhhhhhhhjjjjjjiiilll000+#+#+#+#+#+#+#+#+#+#,""8E@X,"*#5)΅BۡۡB΅5)*#,"@X"9E,"+#+#+#+#+#+#+#+#+#+#000llliiijjjjjjllllllkkknnn/00+#+#+#+#+#+#+#+#+#+#+#*&e��a*%+#-$sWטטWs-$+#*%a��e*&+#+#+#+#+#+#+#+#+#+#+#/00nnnkkkllllllmmmmmmmmmooo//0+#+#+#+#+#+#+#+#+#+#+#,"Df~w#5@,"(!bIiibI(!,"#5@w~Df,"+#+#+#+#+#+#+#+#+#+#+#//0ooommmmmmmmmoooooooooqqq///+#+#+#+#+#+#+#+#+#+#+#+"',*l|{{{|Q+"*"4*ǣjǣj4**"+"Q|{{{|l',*+"+#+#+#+#+#+#+#+#+#+#+#//0qqqoooooooooqqqqqqqqqsss///+#+#+#+#+#+#+#+#+#+#+#+#+"Pyxxxyj&,-+"( nPnP( +"&,-jyxxxyP+"+#+#+#+#+#+#+#+#+#+#+#+#///sssqqqqqqqqqsssssssssttt///+#+#+#+#+#+#+#+#+#+#+#+#,""4CnuttttCn,")"C:)C:))","Cnttttun"4C,"+#+#+#+#+#+#+#+#+#+#+#+#///tttsssssssssuuuuuuuuuvvv///+#+#+#+#+#+#+#+#+#+#+#+#+#*%X�rqqq�r ])'+#*"*"+#)' ]�rqqq�rX*%+#+#+#+#+#+#+#+#+#+#+#+#+#///vvvuuuuuuuuuwwwwwwwwwwww.//+#+#+#+#+#+#+#+#+#+#+#+#+#,"=blmmmmj8S,"( YREYRE( ,"8Sjmmmml=b,"+#+#+#+#+#+#+#+#+#+#+#+#+#.//wwwwwwwwwwwwyyyyyyyyyyyy../+#+#+#+#+#+#+#+#+#+#+#+#+#+#'*) ]kjjj�kP*$+"1)1)+"*$P�kjjjj]'*)+#+#+#+#+#+#+#+#+#+#+#+#+#+#../yyyyyyyyyyyy{{{{{{{{{{{{../+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"Fgfffg`#/<+"( pj_pj_( +"#/<`gfffgF+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#...{{{{{{{{{{{{}}}}}}}}}|||...+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#0@^cccccC+#+#1)1)+#+#Cccccc^#0@+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#...|||}}}}}}}}}~~~...+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$L�`___`U')*+#+#+#+#')*U`___�`L*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#...~~~...+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"6_[\\\\[9i,"+#+#,"9i[\\\\[6_,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#...-..+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#'(' NYXXX�Y J)%+#+#)% J�YXXXY N'('+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#...--.+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#<UUUUUS 0O,"," 0OSUUUUU<+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#--.--.+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+"#,>NRQQQ�R?+#+#?�RQQQRM#,>+"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#--.---+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*$@ONNNNI$*7$*7INNNNN?*$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#------+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,"0\JJJJJK6~6~KJJJJJ0\,"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#------+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#(&% @GGGGGBBGGGGG @(&%+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#------+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#3DCCCCDDCCCCD3+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#---,--+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$(;=@@@@@@@@@@=$(;+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,,-,,-+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#4=<<<<<<<<=4*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,,-,,,+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#*Y8999999998*Y,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,,,,,,+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#($$ 265555556 2($$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,,,,,,+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*{22222222*{+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,,,,,,+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#$%9-......-$%9+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,,,+,,+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#*#),,,,,,)*#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+,,+++,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,#%%6'c'b'b'b'c'c%%6,#,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$+++001          001eeeeee/µ/�xl~i|i|i}i~iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiihhhhhhhhhhilx��[r���&�'�)�,�.�0�2�5�7�9�;�>�@�B�E�G�I�K�N�P�R�T�W�Y�[�]�`�b�d�g�i�k�m�o�r�t�v�y�{�}�������������������]��\t�/� 1,p,.1358:=?ADFHKMORTWY[^`begilnqsuxz|������������p�\t�\t� 2�.� 5.0+2+4*6*9+;+>*@*B*D+F+I+K+M+P+R*T*W+Y+[+^+`+b+e+g+i+l+n*q*s+u+x+z+}++**+++++�+�+�+�+�+�+*****+ � �\t�\t�\t� 5�0�.�0�2�4�6�8�;�=�@�B�D�F�I�K�M�P�R�T�W�Y�[�^�`�b�e�g�i�l�n�q�s�u�x�z�}������������������������������ �\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���0���`���� ������$���d���d����������\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�EFG�DDE�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CDE�DFH�EEE�DDEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDDCDEEEE�EEE2DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEEF2FFGFFFFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFFFFFFIIIIIIHHHUUU]]][\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\[\\]]]UUUHHHIIIIIIKKKKKKPPPNNN(&#'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"'%"(&#NNNPPPKKKKKKNNNMMMSSS))( ( ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' -#-#' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' (  ))(SSSMMMNNNPPPPPPUUU)(' ,$+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#)"V<V<)"+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#,$ )('UUUPPPPPPSSSSSSWWW)(' ,#+#+#+#+#+#+"+"+"+"+#+#+#+#+#+#+#(!WW(!+#+#+#+#+#+#+#+"+"+"+"+#+#+#+#+#,# )('WWWSSSSSSUUUUUUYYY)(' ,#+#+#+#+#))'.'(.&(.&(-%*%+#+#+#+#+#+#+#p p +#+#+#+#+#+#+#*%(-%(.&(.&'.'))+#+#+#+#,# )('YYYUUUUUUXXXXXX[[\((' ,#+#+#+#,!JXHV,!+#+#+#+#*#7*Ӆ Ӆ 7**#+#+#+#+#,!HVJX,!+#+#+#,# (('[[\XXXXXX[[[ZZZ^^^((' ,#+#+#+#+"&31���v*%+#+#+#+#)"R:R:)"+#+#+#+#*%v���&31+"+#+#+#,# (('^^^ZZZ[[[]]]]]]```((' ,#+#+#+#+#+#g���";B,"+#+#+#(!~S~S(!+#+#+#,"";B���g+#+#+#+#+#,# (('```]]]]]]``````bbb((' ,#+#+#+#+#,!!?J���a+"+#+#+#-$s s -$+#+#+#+"a���!>J,!+#+#+#+#,# (('bbb``````bbbbbbddd((' ,#+#+#+#+#+#)' s���&0/+"+#)"D211D2)"+#+"&0/��� s)'+#+#+#+#+#,# (('dddbbbbbbeeeeeefff((' ,#+#+#+#+#+#,!LkOr,!+#(!rM)WW)rM(!+#,!OrLk,!+#+#+#+#+#,# (('fffeeeeeegggggghhh((' ,#+#+#+#+#+#+"&.-z� p)) +#,$qF||Fq,$+#)) p�z&.-+"+#+#+#+#+#,# (('hhhggggggjjjjjjjjj((' ,#+#+#+#+#+#+#+#Y�?V+!6)ЊfۡۡfЊ6)+!?V�Y+#+#+#+#+#+#+#,# (('jjjjjjjjjllllllllm((' ,#+#+#+#+#+#+#,""8G{�_*$+"r)ффr)+"*$_�{"8G,"+#+#+#+#+#+#,# (('llmllllllooooooooo((' ,#+#+#+#+#+#+#+#*& b�}||t#4>) YF&ϚϚYF&) #4>t||�} b*&+#+#+#+#+#+#+#,# (('ooooooooorrrrrrqqq((' ,#+#+#+#+#+#+#+#,"BhvwwxN+"1(1(+"NxwwvBh,"+#+#+#+#+#+#+#,# (('qqqrrrrrrttttttsss('' ,#+#+#+#+#+#+#+#+"'++fssse'+,(um`un`('+,esrsf'+++"+#+#+#+#+#+#+#,# (''sssttttttwwwwwwuuu('' ,#+#+#+#+#+#+#+#+#+#Konnm@l*!>6(>6(*!@lmnnoK+#+#+#+#+#+#+#+#+#,# (''uuuwwwwwwyyyyyywww('' ,#+#+#+#+#+#+#+#+#,""2Ddji�j W)&)!)!)& W�jiid"2D,"+#+#+#+#+#+#+#+#,# (''wwwyyyyyy||||||yyy('' ,#+#+#+#+#+#+#+#+#+#*%Q�feeb5Q*!D=0D=0* 5Qbed�eQ*%+#+#+#+#+#+#+#+#+#,# (''yyy||||||~~~{{{('& ,#+#+#+#+#+#+#+#+#+#,"9d_``�aI+$*"*"+$I�a``_9d,"+#+#+#+#+#+#+#+#+#,# ('&{{{~~~}}~('& ,#+#+#+#+#+#+#+#+#+#+#'))R\[\V$-;+"+"$-;V\[\R'))+#+#+#+#+#+#+#+#+#+#,# ('&}}~('& ,#+#+#+#+#+#+#+#+#+#+#+#>WWWW=+#+#=WWWW>+#+#+#+#+#+#+#+#+#+#+#,# ('&''& ,#+#+#+#+#+#+#+#+#+#+#,""-AORRRJ''(''(JRRRN"-A,"+#+#+#+#+#+#+#+#+#+#,# ''&''& ,#+#+#+#+#+#+#+#+#+#+#+#*$@NMMM2c2cMMMN@*$+#+#+#+#+#+#+#+#+#+#+#,# ''&''& ,#+#+#+#+#+#+#+#+#+#+#+#,"0`HIII ? ?IIIH0`,"+#+#+#+#+#+#+#+#+#+#+#,# ''&''& ,#+#+#+#+#+#+#+#+#+#+#+#+#'&( >DDDDDDDD >'&(+#+#+#+#+#+#+#+#+#+#+#+#,# ''&''& ,#+#+#+#+#+#+#+#+#+#+#+#+#+#2@??????@2+#+#+#+#+#+#+#+#+#+#+#+#+#,#''&''&,#+#+#+#+#+#+#+#+#+#+#+#+#+##(?9;;;;;;9#(?+#+#+#+#+#+#+#+#+#+#+#+#+#,#''&''&,#+#+#+#+#+#+#+#+#+#+#+#+#+#*#06666660*#+#+#+#+#+#+#+#+#+#+#+#+#+#,#''&''&,#+#+#+#+#+#+#+#+#+#+#+#+#+#,#(]111111(],#+#+#+#+#+#+#+#+#+#+#+#+#+#,#''&''&,#+#+#+#+#+#+#+#+#+#+#+#+#+#+#($& +---- +($&+#+#+#+#+#+#+#+#+#+#+#+#+#+#,#''&'&% ,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$&W((((&W,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$,$ &&%00/                                  00/{{{PPPMMNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNMMMOPP{{{#ėė#�>] 7ܼ58:=@CEHKNPSVY[^adgilortwz}@ ����C��*G,/258;>BEH�K�N�Q�U�X�[�^�a�d�h�k�n�q�t�w�{�~����������������G���!E�0��(�13 5 8 : > A D G J M P S V Y \ _ b e i l o r u x |       � � � � �     �� �#�\t�&J�.�0�3�5�8�:�>�A�D�G�J�M�P�S�V�Y�\�_�b�e�h�l�o�r�u�x�|�����������������������(�\t�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(���(���P���� ���������d���d����������\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�\t�DEE�DDD�EDD�DDD�DDD�DDD�DDD�DDD�EDD�DDD�DDD�EED�EEE�DDD�DDD�DDD�DDD�EDD�DDD�EEE�DDD�DDD�DDD�EDD�DDD�DDD�EED�EEE�DDD�DDD�DDD�DDD�EDD�EDD�EEE�DDD�DDD�EED�DDD�DEE�DDEDDD`DDD~DDD}DDD~DDD~DDD}DDD}DDD}DDD}DDD}DDD}DDD~DDD}DDD}DDD}DDD}DDD}DDD}DDD~DDD~DDD}DDD}DDD}DDD}DDD}DDD}DDD~DDD}DDD}DDD}DDD}DDD}DDD}DDD~DDD~DDD}DDD~DDD`DEEFFFEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFHHHHHHMMMWWWVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVWWWMMMHHHHHHKKKLLLRRR/-+)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!)&!/-+RRRLLLKKKNNNPPPDDE *!)!)!)!)!)!)!)!)!)!)!)!)!)!(!6)6)(!)!)!)!)!)!)!)!)!)!)!)!)!)!*! DDEPPPNNNRRRSSSEEF+#+#+#+#+#+#+#+#+#+#+#+#+#+#(!bCbC(!+#+#+#+#+#+#+#+#+#+#+#+#+#+#EEFSSSRRRUUUVVVFGG+#+#+#+#+$*'*&*'*%+#+#+#+#+#(!^ ^ (!+#+#+#+#+#*%*'*&*'+$+#+#+#+#FGGVVVUUUXXXYYYHHH+#+#+#+"%54z g*&+#+#+#+#-$v v -$+#+#+#+#*&f z%54+"+#+#+#HHHYYYXXX[[[\\\III+#+#+#+#)) ��"<B,"+#+#*"?/ތދ?/*"+#+#,""<B�� ))+#+#+#+#III\\\[[[^^^___JJJ+#+#+#+#,!Sn���c+"+#+#(!dDdD(!+#+#+"c���Rn,!+#+#+#+#JJJ___^^^aaacccKKK+#+#+#+#+"&1/��&0.+"+#)"dd)"+#+"&0.��&0/+"+#+#+#+#KKKcccaaadddfffLLL+#+#+#+#+#+#`�Oq,!*#7*ωGGω7**#,!Oq�`+#+#+#+#+#+#LLLfffdddgggiiiMMN+#+#+#+#+#,"!;I� p)( (!]@0tt0]@(!)( p�!;I,"+#+#+#+#+#MMNiiigggjjjlllNOO,#+#+#+#+#+#*' i�?U(yROڟڟOyR(?U� i*'+#+#+#+#+#,#NOOllljjjmmmoooPPP ,#+#+#+#+#+#,"Fj~�])#K8llK8)#]�~Fj,"+#+#+#+#+#,# PPPooommmppprrrQQQ ,#+#+#+#+#+#+"&--lzzr#3>,"nn,"#3>rzzl&--+"+#+#+#+#+#,# QQQrrrpppsssuuuRRR ,#+#+#+#+#+#+#+#O�utuL(bYIbYI(Lut�uO+#+#+#+#+#+#+#,# RRRuuusssvvvxxxSSS ,#+#+#+#+#+#+#,""4Fjoob&*+5,ƿƿ5,&**booj"4F,"+#+#+#+#+#+#,# SSSxxxvvvzzz|||TTT ,#+#+#+#+#+#+#+#*% T�jih>k)}xm}xm)>khi�j T*%+#+#+#+#+#+#+#,# TTT|||zzz}}}UUV ,#+#+#+#+#+#+#+#,";fcc�d R(%6.6.(% R�dcb;f,"+#+#+#+#+#+#+#,# UUV}}}VWW ,#+#+#+#+#+#+#+#+#')+T^^[ 3P+"+" 3P[^^T')++#+#+#+#+#+#+#+#,# VWWXXX ,#+#+#+#+#+#+#+#+#+#@YX�YD+#+#D�YXY?+#+#+#+#+#+#+#+#+#,# XXXYYY ,#+#+#+#+#+#+#+#+#,""-COSSN$*8$*8NSSO"-C,"+#+#+#+#+#+#+#+#,# YYYZZZ ,#+#+#+#+#+#+#+#+#+#*$@MMM77MMM@*$+#+#+#+#+#+#+#+#+#,# ZZZ[[[ ,#+#+#+#+#+#+#+#+#+#,"0cGGHCCGGG0c,"+#+#+#+#+#+#+#+#+#,# [[[\\\ ,#+#+#+#+#+#+#+#+#+#+#'&) =BBBBBB <'&)+#+#+#+#+#+#+#+#+#+#,# \\\]]^ ,#+#+#+#+#+#+#+#+#+#+#+#0<<<<<<0+#+#+#+#+#+#+#+#+#+#+#,# ]]^___ ,#+#+#+#+#+#+#+#+#+#+#+##'@576675#'@+#+#+#+#+#+#+#+#+#+#+#,# ___``` ,#+#+#+#+#+#+#+#+#+#+#+#*#-1111-*#+#+#+#+#+#+#+#+#+#+#+#,# ```aaa ,$+#+#+#+#+#+#+#+#+#+#+#,#'\,,,,'\,#+#+#+#+#+#+#+#+#+#+#+#,$ aaaccc$############"2552"############$ccc;:921/22022022032032022022032022032032022032/31.31-31-32.32/22032032032022022032032022032032022021/;:9Ȋnm~mmmmmmmlllllllllllllllllllllllllln̊Vm��),047;?B�F�J�N�Q�U�Y�\�`�d�g�k�o�s�v�z�~�������������U�<���Q�.0:3:7:;:?:B:F:J:M:Q:U:Y:]:`:d:h:l:p:s:w:{::::::�:�:�:�:::::�8f��<�/�-�/�3�6�:�>�B�E�I�M�Q�T�X�\�`�d�g�k�o�s�v�z�~�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������(��� ���@���� ���������d���d����������DDE�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�DDD�CDE�ABCDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCDD@BCEEEEEEDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDEEEEEEHHHHHHPPPQQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQPQQQQQPPPHHHHHHLLLOOO:97*&+' +' +' +' +' +' +' +' +' +' +' +( +( +' +' +' +' +' +' +' +' +' +' +' *&:97OOOLLLOOOQQQ&$ '*"*"*"*"*"*"*"*"*"*")!@/@/)!*"*"*"*"*"*"*"*"*"*"'&$ QQQOOOSSSTTT'%!( +#+#+#+#+#+"+#+#+#+#(!oKoK(!+#+#+#+#+"+#+#+#+#+#( '%!TTTSSSWWWWWX'%!( +#+#)(brn$78+"+#+#)"e e )"+#+#+"$78nrb)(+#+#( '%!WWXWWW[[[Z[['%!( +#+#+#m��e+"+#+#2'  2'+#+#+"e��m+#+#+#( '%!Z[[[[[___^^^(%!( +#+#,!!@L�&0.+")"N7 N7)"+"&0.�!@L,!+#+#( (%!^^^___cccaaa(&"( +#+#+#)' t�Op,!(!~U11~U(!,!Op� t)'+#+#+#( (&"aaacccgggddd(&"( +#+#+#,!Lm� p)( /%}ee}/%)( p�Lm,!+#+#+#( (&"dddgggkkkggh(&"( +#+#+#+"&..v�>T7(Д5ڛڛД57(>T�v&..+"+#+#+#( (&"gghkkkooojkk(&"( +#+#+#+#+#U�~�~\)"wFwF)"\�~�~U+#+#+#+#+#( (&"jkkooosssnnn(&"( +#+#+#+#,"!7Hqwn!0;RF1RF1!0;nwq!6H,"+#+#+#+#( (&"nnnsssvvvqqq(&"( +#+#+#+#+#*& Z�ppI.&.&Ip�p Y*&+#+#+#+#+#( (&"qqqvvvzzzttt)&"( +#+#+#+#+#,">ihi\$'(e^Qe^Q$'(\ig>i,"+#+#+#+#+#( )&"tttzzz~~~wwx)'"( +#+#+#+#+#+#&*,Xb`:i.%.%:i`bW&*,+#+#+#+#+#+#( )'"wwx~~~{{{)'#( +#+#+#+#+#+#+#A�[�[ K)%)% K�[�[A+#+#+#+#+#+#+#( )'#{{{~~~)'#( +#+#+#+#+#+#,"".EPSQ /L /LQSP".E,"+#+#+#+#+#+#( )'#~~~)'#( +#+#+#+#+#+#+#*$@MM<<MM@*$+#+#+#+#+#+#+#( )'#)'#( +#+#+#+#+#+#+#,"0eEEDDEE0e,"+#+#+#+#+#+#+#( )'#)'#( +#+#+#+#+#+#+#+#'&* :>>>> :'&*+#+#+#+#+#+#+#+#( )'#)'#( +#+#+#+#+#+#+#+#+#.7777.+#+#+#+#+#+#+#+#+#( )'#*'#( +#+#+#+#+#+#+#+#,#"&B/00/"&B,#+#+#+#+#+#+#+#+#( *'#)&"'*"*"*"*"*"*"*"*"*")"'~(('~)"*"*"*"*"*"*"*"*"*"')&">=;# %"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"%"# >=;TjҚ:V:Y:]:`:c:f:i9l9p9s9v9y9|999999999988888SݙLg��%�(�-�2�7�<�@�E�J�O�T�X�]�b�g�l�q�u�z�����������%K�+�+�+�/�4�9�>�C�G�L�Q�V�[�_�d�i�m�r�w�{�����������������������������������������������������������������������������������������������������������������������������������������������������(������0���� ������ ���d���d����������EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEE�EEEHDDD{DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD}DDD{EEEHGGGJJJLLLKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKLLLJJJGGGMMMEDD,( -( -( -( -( -( -( -( -( /* /* -( -( -( -( -( -( -( -( ,( EDDMMMSSS>=<$+#*"+!+ +!*"*"(!L6L6(!*"*"+!+ +!*"+#$>=<SSSXXXA@?%+#+#IWaJY+#+#(!|R|R(!+#+#JYaIW+#+#%A@?XXX^^^CBA%+#,!Ws�&0-+"+#o o +#+"&0-�Ws,!+#%CBA^^^cccEDC$+#+"&10�Po*!=.ۑۑ=.*!Po�&10+"+#$EDCccchhhGFE$+#+#+#_� q&&gHOOgH&& q�_+#+#+#$GFEhhhmmmIIG$+#+#,"!:K~;RxTӐӐxT;R~!:K,"+#+#$IIGmmmrrrKKJ$+#+#+#)& b�|XD8#ҹҹD8#X�| b)&+#+#+#$KKJrrrxxxNML$+#+#+#,"Blpi#0;#0;ipBl,"+#+#+#$NMLxxx}}}PON$+#+#+#+"&+.]�hCOG9OG9C�h]&+.+"+#+#+#$PON}}}RQP$+#+#+#+#+#D�_S'(('((S�_D+#+#+#+#+#$RQPTSR$+#+#+#+#,"!/GRT5e5eTQ!/G,"+#+#+#+#$TSRVVT#+#+#+#+#+#*$ @�L A A�L @*$+#+#+#+#+##VVTXXW#+#+#+#+#+#,#/gABBA/g,#+#+#+#+#+##XXW[ZY#+#+#+#+#+#+#'&,5995'&,+#+#+#+#+#+##[ZY]\[#,$+#+#+#+#+#,#*00*,#+#+#+#+#+#,$#]\[ccb$$$$$$$ )!Q!Q )$$$$$$$ccbwwuvusvusvusvusvusvusvusvurwupwupvurvusvusvusvusvusvtsvtswvt]tAߜ@FKQV[aflqv|]�� �'�-�4�;�B�H�O�V�]�d�k�r�y�������� �������������������������������������������������������������������������������������������������(������ ���� ���������d���d����������CCCCCC#DDD"DDD"DDD"DDD"DDD"DDD"DDD"DDD"DDD"DDD"DDD"DDD"CCC#CCCHHHHHHGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGHHHHHHLLL3/).)/(/'/).)5-5-.)/)/'/(.)3/)LLLQQQ,'*!$54K\(+"( Y=Y=( (+"K\$54*!,'QQQWWW-(+! BMRn) ^^) Rn BM+!-(WWW^^^.) +")( t s1,ǎ2ǎ21, s t)(+".) ^^^ddd.*!*","Ip|*CRЬtЬt*BR|Ip,"*".*!dddjjj/*!*"+"&-/iRvvRi&-/+"*"/*!jjjqqq0+"*"+#+#I^6@L6@L^I+#+#*"0+"qqqwww1,#*"+#,"!0IT;;T!0I,"+#*"1,#www~~~1,$*"+#+#)% ?DD ?)%+#+#*"1,$~~~2-$*"+#+#,#-i;;-i,#+#+#*"2-$0,#&'''#!) ( (#!)'''&0,#jid^[U_\U_\U_\U_[U][]][]_[U_[U_[U_ZU^ZTjgcrpppppppppppor� 0R9XBXKXUX^XgXqXzXXXXXQ�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/windows/alacritty.manifest���������������������������������������������������������0000644�0000000�0000000�00000000633�10461020230�0017123�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version='1.0' encoding='UTF-8' standalone='yes'?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" > <asmv3:application> <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings"> <dpiAwareness>PerMonitorV2, unaware</dpiAwareness> </asmv3:windowsSettings> </asmv3:application> </assembly> �����������������������������������������������������������������������������������������������������alacritty-0.13.2/windows/alacritty.rc���������������������������������������������������������������0000644�0000000�0000000�00000000223�10461020230�0015714�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#define IDI_ICON 0x101 IDI_ICON ICON "alacritty.ico" #define RT_MANIFEST 24 #define APP_MANIFEST 1 APP_MANIFEST RT_MANIFEST alacritty.manifest �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/windows/wix/alacritty.wxs����������������������������������������������������������0000644�0000000�0000000�00000006125�10461020230�0016747�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:ui="http://wixtoolset.org/schemas/v4/wxs/ui"> <Package Name="Alacritty" UpgradeCode="87c21c74-dbd5-4584-89d5-46d9cd0c40a7" Language="1033" Codepage="1252" Version="0.13.2" Manufacturer="Alacritty" InstallerVersion="200"> <MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of [ProductName] is already installed." /> <Icon Id="AlacrittyIco" SourceFile=".\alacritty\windows\alacritty.ico" /> <WixVariable Id="WixUILicenseRtf" Value=".\alacritty\windows\wix\license.rtf" /> <Property Id="ARPPRODUCTICON" Value="AlacrittyIco" /> <MediaTemplate EmbedCab="yes" /> <ui:WixUI Id="WixUI_Minimal" /> <Feature Id="ProductFeature" Title="ConsoleApp" Level="1"> <ComponentRef Id="AlacrittyExe" /> <ComponentRef Id="AlacrittyShortcut" /> <ComponentRef Id="ModifyPathEnv" /> <ComponentRef Id="ContextMenu" /> </Feature> <!-- Application binaries --> <DirectoryRef Id="AlacrittyProgramFiles"> <Component Id="AlacrittyExe"> <File Id="AlacrittyExeFile" Source=".\target\release\alacritty.exe" Name="alacritty.exe" KeyPath="yes" /> </Component> </DirectoryRef> <DirectoryRef Id="AlacrittyProgramMenu"> <!-- Application shortcut --> <Component Id="AlacrittyShortcut" Guid="aa36e61a-23cd-4383-b744-2f78e912f0dc"> <Shortcut Id="AlacrittyShortcutFile" Name="Alacritty" Description="A cross-platform, GPU-accelerated terminal emulator" Target="[AlacrittyProgramFiles]alacritty.exe" /> <RemoveFolder Id="AlacrittyProgramMenu" On="uninstall" /> <RegistryValue Root="HKCU" Key="Software\Microsoft\Alacritty" Name="installed" Type="integer" Value="1" KeyPath="yes" /> </Component> </DirectoryRef> <DirectoryRef Id="AlacrittyProgramFiles"> <!-- Add to PATH --> <Component Id="ModifyPathEnv" Guid="edf0b679-9eb6-46f7-a5d1-5160f30acb34" KeyPath="yes"> <Environment Id="PathEnv" Value="[AlacrittyProgramFiles]" Name="PATH" Permanent="no" Part="first" Action="set" System="yes" /> </Component> </DirectoryRef> <StandardDirectory Id="ProgramFiles64Folder"> <Directory Id="AlacrittyProgramFiles" Name="Alacritty" /> </StandardDirectory> <StandardDirectory Id="ProgramMenuFolder"> <Directory Id="AlacrittyProgramMenu" Name="Alacritty" /> </StandardDirectory> <!-- Add context menu --> <Component Id="ContextMenu" Guid="449f9121-f7b9-41fe-82da-52349ea8ff91" Directory="TARGETDIR"> <RegistryKey Root="HKCU" Key="Software\Classes\Directory\Background\shell\Open Alacritty here\command"> <RegistryValue Type="string" Value="[AlacrittyProgramFiles]alacritty.exe" KeyPath="yes" /> </RegistryKey> <RegistryKey Root="HKCU" Key="Software\Classes\Directory\Background\shell\Open Alacritty here"> <RegistryValue Type="string" Name="Icon" Value="[AlacrittyProgramFiles]alacritty.exe" /> </RegistryKey> </Component> </Package> </Wix> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������alacritty-0.13.2/windows/wix/license.rtf������������������������������������������������������������0000644�0000000�0000000�00000025225�10461020230�0016351�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{} {\*\generator Riched20 10.0.17763}\viewkind4\uc1 \pard\sa200\sl276\slmult1\qc\f0\fs22\lang9 Apache License\par Version 2.0, January 2004\par {{\field{\*\fldinst{HYPERLINK http://www.apache.org/licenses/ }}{\fldrslt{http://www.apache.org/licenses/\ul0\cf0}}}}\f0\fs22\par \pard\sa200\sl276\slmult1\par TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\par \par 1. Definitions.\par "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.\par "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.\par "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.\par "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.\par "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.\par "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.\par "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).\par "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.\par "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."\par "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.\par 2. Grant of Copyright License.\par Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.\par 3. Grant of Patent License.\par Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.\par 4. Redistribution.\par You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:\par (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and\par (b) You must cause any modified files to carry prominent notices stating that You changed the files; and\par (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and\par (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.\par You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.\par 5. Submission of Contributions.\par Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.\par 6. Trademarks.\par This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.\par 7. Disclaimer of Warranty.\par Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.\par 8. Limitation of Liability.\par In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.\par 9. Accepting Warranty or Additional Liability.\par While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.\par END OF TERMS AND CONDITIONS\par \par APPENDIX: How to apply the Apache License to your work.\par \par To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.\par Copyright 2016 Joe Wilm, The Alacritty Project Contributors\par Licensed under the Apache License, Version 2.0 (the "License");you may not use this file except in compliance with the License.You may obtain a copy of the License at\par \par \tab {{\field{\*\fldinst{HYPERLINK http://www.apache.org/licenses/LICENSE-2.0 }}{\fldrslt{http://www.apache.org/licenses/LICENSE-2.0\ul0\cf0}}}}\f0\fs22\par \par Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions andlimitations under the License.\par } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������