Repository: umnik1/yaamp Branch: main Commit: a8d71ea458f7 Files: 348 Total size: 4.2 MB Directory structure: gitextract_3komkc99/ ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── bundled/ │ └── skins/ │ ├── .gitignore │ ├── Green-Dimension-V2.wsz │ ├── MacOSXAqua1-5.wsz │ ├── Skinner_Atlas.wsz │ ├── TopazAmp1-2.wsz │ ├── Vizor1-01.wsz │ ├── XMMS-Turquoise.wsz │ ├── ZaxonRemake1-0.wsz │ ├── base-2.91/ │ │ ├── CLOSE.CUR │ │ ├── EQSLID.CUR │ │ ├── EQTITLE.CUR │ │ ├── NORMAL.CUR │ │ ├── PLEDIT.TXT │ │ ├── PNORMAL.CUR │ │ ├── POSBAR.CUR │ │ ├── PSIZE.CUR │ │ ├── PVSCROLL.CUR │ │ ├── REGION.TXT │ │ ├── Skining Updates.txt │ │ ├── TITLEBAR.CUR │ │ ├── VISCOLOR.TXT │ │ └── VOLBAL.CUR │ └── base-2.91.wsz ├── dist/ │ └── .gitignore ├── main.js ├── package.json ├── res/ │ ├── icon.hqx │ ├── icon.icns │ ├── icons/ │ │ └── icon.icns │ └── license.txt ├── src/ │ ├── __tests__/ │ │ └── basic.spec.ts │ ├── global.d.ts │ ├── index.css │ ├── index.html │ ├── node/ │ │ ├── api-server.js │ │ ├── preload.js │ │ ├── protocol.js │ │ ├── thumbar.js │ │ ├── thumbnail.js │ │ ├── transparency.js │ │ ├── updates.js │ │ └── utilities.js │ ├── renderer.ts │ └── webamp/ │ ├── webamp.bundle.d.ts │ └── webamp.bundle.js ├── tsconfig.json ├── tslint.json └── webamp/ ├── .editorconfig ├── .gitattributes ├── .gitignore ├── LICENSE.txt ├── README.md ├── YAAMP_FONT/ │ └── font.psd ├── netlify.toml ├── package.json └── packages/ ├── ani-cursor/ │ ├── .gitignore │ ├── README.md │ ├── babel.config.js │ ├── package.json │ ├── src/ │ │ ├── __tests__/ │ │ │ ├── __snapshots__/ │ │ │ │ └── parser.test.ts.snap │ │ │ ├── fixtures/ │ │ │ │ ├── Green Dimension v2/ │ │ │ │ │ └── eqslid.cur │ │ │ │ ├── Super_Mario_Amp_2/ │ │ │ │ │ ├── close.cur │ │ │ │ │ └── eqslid.cur │ │ │ │ └── piano.ani │ │ │ └── parser.test.ts │ │ ├── index.ts │ │ └── parser.ts │ └── tsconfig.json └── webamp/ ├── .babelrc ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierignore ├── CHANGELOG.md ├── assets/ │ └── skins/ │ ├── base-2.91/ │ │ ├── CLOSE.CUR │ │ ├── EQSLID.CUR │ │ ├── EQTITLE.CUR │ │ ├── NORMAL.CUR │ │ ├── PLEDIT.TXT │ │ ├── PNORMAL.CUR │ │ ├── POSBAR.CUR │ │ ├── PSIZE.CUR │ │ ├── PTBAR.CUR │ │ ├── PVSCROLL.CUR │ │ ├── REGION.TXT │ │ ├── Skining Updates.txt │ │ ├── TITLEBAR.CUR │ │ ├── VISCOLOR.TXT │ │ └── VOLBAL.CUR │ └── base-2.91.wsz ├── config/ │ ├── jest.integration.js │ ├── jest.unit.js │ └── webpack.library.js ├── css/ │ ├── base-skin.css │ ├── context-menu.css │ ├── equalizer-window.css │ ├── gen-window.css │ ├── main-window.css │ ├── milkdrop-window.css │ ├── mini-time.css │ ├── playlist-window.css │ └── webamp.css ├── demo/ │ ├── config/ │ │ ├── webpack.common.js │ │ ├── webpack.dev.js │ │ └── webpack.prod.js │ ├── css/ │ │ └── page.css │ ├── index.html │ ├── js/ │ │ ├── DemoDesktop.tsx │ │ ├── DesktopIcon.tsx │ │ ├── DesktopLinkIcon.tsx │ │ ├── IconImage.tsx │ │ ├── MilkIcon.tsx │ │ ├── Mp3Icon.tsx │ │ ├── SkinIcon.tsx │ │ ├── SuspenseImage.tsx │ │ ├── WebampIcon.tsx │ │ ├── avaliableSkins.ts │ │ ├── butterchurnOptions.ts │ │ ├── config.ts │ │ ├── delete-service-worker.js │ │ ├── dropboxFilePicker.ts │ │ ├── eventLogger.ts │ │ ├── index.js │ │ ├── logger.ts │ │ ├── mediaSession.ts │ │ └── screenshotInitialState.ts │ ├── readme.md │ └── skins/ │ ├── .gitignore │ ├── AmigaPPC-dark.wsz │ ├── Green-Dimension-V2.wsz │ ├── Internet-Archive.wsz │ ├── MacOSXAqua1-5.wsz │ ├── My_Funny_Valentine.wsz │ ├── Skinner_Atlas.wsz │ ├── Sonic_Attitude.wsz │ ├── TopazAmp1-2.wsz │ ├── Vizor1-01.wsz │ ├── XMMS-Turquoise.wsz │ └── ZaxonRemake1-0.wsz ├── docs/ │ ├── architecture.md │ ├── music-credits.md │ ├── press.md │ └── usage.md ├── index.d.ts ├── jest-puppeteer.config.js ├── js/ │ ├── Disposable.ts │ ├── __mocks__/ │ │ ├── fileMock.js │ │ ├── mediaMock.js │ │ ├── storeMock.js │ │ └── styleMock.js │ ├── __snapshots__/ │ │ ├── regionParser.test.js.snap │ │ └── serialization.test.ts.snap │ ├── __tests__/ │ │ ├── .eslintrc │ │ ├── baseline.integration-test.js │ │ └── fixtures/ │ │ ├── CENTRA_VISCOLOR.TXT │ │ ├── PLEDIT.TXT │ │ ├── PLEDIT_TOPAZ.TXT │ │ ├── PLEDIT_WITH_EQUALS.TXT │ │ ├── PLEDIT_WITH_QUOTES.TXT │ │ ├── VISCOLOR.TXT │ │ ├── region.txt │ │ ├── region1.txt │ │ ├── region_empty_sections.txt │ │ ├── region_eva.txt │ │ ├── region_ituned.txt │ │ ├── region_leading_comma.txt │ │ ├── region_satellite.txt │ │ ├── serializedState/ │ │ │ └── v1/ │ │ │ ├── balance.json │ │ │ ├── double-mode.json │ │ │ ├── equalizer-auto.json │ │ │ ├── equalizer-band.json │ │ │ ├── equalizer-on.json │ │ │ ├── equalizer-preamp.json │ │ │ ├── focused-window.json │ │ │ ├── llama-mode.json │ │ │ ├── main-window-position.json │ │ │ ├── repeat.json │ │ │ ├── shuffle.json │ │ │ ├── volume.json │ │ │ ├── window-hidden.json │ │ │ ├── window-open.json │ │ │ ├── window-positions-are-relative.json │ │ │ ├── window-shade.json │ │ │ └── window-size.json │ │ ├── viscolor_green_dimension.txt │ │ └── viscolor_valgaav.txt │ ├── actionCreators/ │ │ ├── equalizer.ts │ │ ├── files.ts │ │ ├── index.test.js │ │ ├── index.ts │ │ ├── media.ts │ │ ├── milkdrop.ts │ │ ├── playlist.ts │ │ └── windows.ts │ ├── actionTypes.ts │ ├── baseSkin.json │ ├── components/ │ │ ├── App.tsx │ │ ├── Balance.tsx │ │ ├── Character.test.js │ │ ├── Character.tsx │ │ ├── CharacterString.tsx │ │ ├── ClickedDiv.tsx │ │ ├── ClipPaths.tsx │ │ ├── ContextMenu.tsx │ │ ├── ContextMenuTarget.tsx │ │ ├── ContextMenuWrapper.tsx │ │ ├── Css.tsx │ │ ├── DropTarget.tsx │ │ ├── EqualizerWindow/ │ │ │ ├── Band.test.js │ │ │ ├── Band.tsx │ │ │ ├── EqAuto.tsx │ │ │ ├── EqGraph.tsx │ │ │ ├── EqOn.tsx │ │ │ ├── EqTitleButtons.tsx │ │ │ ├── EqualizerShade.tsx │ │ │ ├── PresetsContextMenu.tsx │ │ │ ├── index.tsx │ │ │ └── spline.js │ │ ├── FocusTarget.tsx │ │ ├── Fullscreen.tsx │ │ ├── GenWindow/ │ │ │ └── index.tsx │ │ ├── MainWindow/ │ │ │ ├── ActionButtons.tsx │ │ │ ├── Close.tsx │ │ │ ├── ClutterBar.tsx │ │ │ ├── Eject.tsx │ │ │ ├── EqToggleButton.tsx │ │ │ ├── Kbps.tsx │ │ │ ├── Khz.tsx │ │ │ ├── MainBalance.test.js │ │ │ ├── MainBalance.tsx │ │ │ ├── MainContextMenu.tsx │ │ │ ├── MainVolume.tsx │ │ │ ├── Marquee.test.js │ │ │ ├── Marquee.tsx │ │ │ ├── Minimize.tsx │ │ │ ├── MonoStereo.tsx │ │ │ ├── PlaylistToggleButton.tsx │ │ │ ├── Position.tsx │ │ │ ├── Repeat.tsx │ │ │ ├── Shade.tsx │ │ │ ├── Shuffle.tsx │ │ │ ├── Time.tsx │ │ │ └── index.tsx │ │ ├── MilkdropWindow/ │ │ │ ├── Background.tsx │ │ │ ├── Desktop.tsx │ │ │ ├── MilkdropContextMenu.tsx │ │ │ ├── PresetOverlay.tsx │ │ │ ├── Visualizer.tsx │ │ │ ├── __tests__/ │ │ │ │ └── PresetOverlay.test.js │ │ │ └── index.tsx │ │ ├── MiniTime.tsx │ │ ├── OptionsContextMenu.tsx │ │ ├── PlaybackContextMenu.tsx │ │ ├── PlaylistWindow/ │ │ │ ├── AddMenu.tsx │ │ │ ├── ListMenu.tsx │ │ │ ├── MiscMenu.tsx │ │ │ ├── MiscOptionsContextMenu.tsx │ │ │ ├── PlaylistActionArea.tsx │ │ │ ├── PlaylistMenu.tsx │ │ │ ├── PlaylistMenuEntry.tsx │ │ │ ├── PlaylistResizeTarget.tsx │ │ │ ├── PlaylistScrollBar.tsx │ │ │ ├── PlaylistShade.test.js │ │ │ ├── PlaylistShade.tsx │ │ │ ├── RemoveMenu.tsx │ │ │ ├── RunningTimeDisplay.tsx │ │ │ ├── SelectionMenu.tsx │ │ │ ├── SortContextMenu.tsx │ │ │ ├── TrackCell.tsx │ │ │ ├── TrackList.tsx │ │ │ ├── TrackTitle.tsx │ │ │ ├── __snapshots__/ │ │ │ │ └── PlaylistShade.test.js.snap │ │ │ └── index.tsx │ │ ├── ResizeTarget.tsx │ │ ├── Skin.tsx │ │ ├── SkinsContextMenu.tsx │ │ ├── VerticalSlider.tsx │ │ ├── Visualizer.tsx │ │ ├── Volume.tsx │ │ ├── WindowManager.tsx │ │ ├── useBarVisualizer.ts │ │ └── useOscilloscopeVisualizer.ts │ ├── constants.ts │ ├── emitter.test.js │ ├── emitter.ts │ ├── fileUtils.ts │ ├── hooks.ts │ ├── hotkeys.ts │ ├── loadQueue.js │ ├── marqueeUtils.test.ts │ ├── marqueeUtils.tsx │ ├── media/ │ │ ├── StereoBalanceNode.js │ │ ├── elementSource.ts │ │ └── index.ts │ ├── mediaMiddleware.ts │ ├── playlistHtml.tsx │ ├── reducers/ │ │ ├── display.ts │ │ ├── equalizer.ts │ │ ├── index.ts │ │ ├── media.ts │ │ ├── milkdrop.test.js │ │ ├── milkdrop.ts │ │ ├── network.ts │ │ ├── playlist.test.js │ │ ├── playlist.ts │ │ ├── settings.ts │ │ ├── tracks.test.ts │ │ ├── tracks.ts │ │ ├── userInput.test.js │ │ ├── userInput.ts │ │ └── windows.ts │ ├── regionParser.test.js │ ├── regionParser.ts │ ├── resizeUtils.test.ts │ ├── resizeUtils.ts │ ├── selectors.test.ts │ ├── selectors.ts │ ├── serialization.test.ts │ ├── serializedStates/ │ │ └── v1Types.ts │ ├── skinParser.js │ ├── skinParserUtils.ts │ ├── skinSelectors.ts │ ├── skinSprites.test.js │ ├── skinSprites.ts │ ├── snapUtils.test.ts │ ├── snapUtils.ts │ ├── spinParserUtils.test.ts │ ├── store.ts │ ├── trackUtils.ts │ ├── types.ts │ ├── utils.test.ts │ ├── utils.ts │ ├── webamp.js │ ├── webampLazy.tsx │ └── winamp-eqf.d.ts ├── package.json ├── presets/ │ ├── builtin.json │ └── winamp.q1 ├── scripts/ │ ├── compileSkin.js │ ├── parsePresetFiles.js │ ├── postcss-optimize-data-uri-pngs.js │ └── postcss-optimize-data-uri-pngs.test.js ├── static.d.ts └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ node_modules .cache .parcel-cache skin.json token.json artifacts ================================================ FILE: .travis.yml ================================================ matrix: include: - os: osx osx_image: xcode9.2 language: node_js node_js: '10' env: - ELECTRON_CACHE=$HOME/.cache/electron - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder - os: linux dist: xenial language: node_js node_js: '10' env: - ELECTRON_CACHE=$HOME/.cache/electron - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder cache: directories: - ~/.npm - ~/.cache - node_modules - "$HOME/.cache/electron" - "$HOME/.cache/electron-builder" override: - yarn install --frozen-lockfile before_install: - | if [ "$TRAVIS_OS_NAME" == "osx" ]; then mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v2.3.1/git-lfs-$([ "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-2.3.1.tar.gz | tar -xz -C /tmp/git-lfs --strip-components 1 export PATH="/tmp/git-lfs:$PATH" fi before_script: - git lfs pull # For Electron e2e UI testing # See https://github.com/electron/spectron#on-travis-ci - | if [ "$TRAVIS_OS_NAME" == "linux" ]; then export DISPLAY=:99.0 sh -e /etc/init.d/xvfb start sleep 3 # give xvfb some time to start fi script: - yarn build - | if [ "$TRAVIS_OS_NAME" == "linux" ]; then docker run --rm \ $(env | \ grep -Eo '^[^\s=]*(DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|_TOKEN|_KEY|AWS_|STRIP|BUILD_)[^\s=]*' | \ sed '/^$/d;s/^/-e /' | \ paste -sd ' ' \ ) \ -v ${PWD}:/project \ -v ~/.cache/electron:/root/.cache/electron \ -v ~/.cache/electron-builder:/root/.cache/electron-builder \ electronuserland/builder:wine \ /bin/bash -c "yarn --link-duplicates --pure-lockfile && yarn dist --linux --win" else yarn test && yarn dist fi before_cache: - rm -rf $HOME/.cache/electron-builder/wine ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2025 Maksim Chingin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ![](https://github.com/umnik1/yaamp/assets/2902730/70de0d28-d871-4a45-8416-0f0a09cbb198) # Yaamp Исходники проекта по интеграции Яндекс.Музыки и *Winamp (Webamp)* ## Описание **Yaamp** — это десктопный музыкальный плеер, который объединяет классический интерфейс Winamp с возможностями Яндекс.Музыки. Приложение построено на базе Electron и использует Webamp для воссоздания аутентичного опыта использования легендарного Winamp с современной интеграцией потокового сервиса. Yaamp позволяет наслаждаться музыкой из каталога Яндекс.Музыки через знакомый интерфейс Winamp, сохраняя все его характерные особенности: скины, эквалайзер, визуализацию и ностальгический вид. ## Особенности ### Основной функционал - **Интеграция с Яндекс.Музыкой** — полный доступ к каталогу музыки через официальный API - **Классический интерфейс Winamp** — точная копия оригинального плеера через Webamp - **Поддержка скинов** — использование оригинальных скинов Winamp (.wsz файлы) - **Эквалайзер** — 10-полосный графический эквалайзер с сохранением настроек - **Визуализация Milkdrop** — поддержка визуализации музыки - **Плейлист** — полнофункциональный плейлист с возможностью управления треками ### Управление воспроизведением - **Моя волна** — запуск персонализированной радиостанции - **Любимые треки** — быстрый доступ к избранным композициям - **Поиск** — поиск артистов и альбомов с возможностью воспроизведения - **Управление треками** — переключение, пауза, воспроизведение через интерфейс или горячие клавиши ### HTTP API - **Веб-интерфейс** — управление плеером через браузер - **REST API** — программное управление плеером через HTTP запросы - **Удаленное управление** — контроль воспроизведения с любого устройства в локальной сети - **Поиск и воспроизведение** — поиск артистов/альбомов и запуск через API ### Интеграции - **Discord Rich Presence** — отображение текущего трека в статусе Discord - **Горячие клавиши** — поддержка стандартных горячих клавиш Winamp - **Touch Bar (macOS)** — управление воспроизведением через Touch Bar на MacBook ### Технические особенности - **Кроссплатформенность** — поддержка Windows, macOS и Linux - **Автоматические обновления** — встроенная система обновлений через electron-updater - **Сохранение настроек** — автоматическое сохранение позиций окон, скинов и эквалайзера - **Прозрачность окон** — поддержка прозрачности для аутентичного вида Winamp - **IPC коммуникация** — взаимодействие между Electron и Webamp через IPC --- ### **Установка** 1. `yarn install` и `yarn install` в папке **webamp** 2. Поправить в **package.json** - "copy" и "deploy-webamp" на тот, на какой системе вы сейчас работаете, на данный момент настроенно на Windows **Добавление функционала и работа с Webamp** 1. Используйте `yarn deploy-webamp` для сборки Webamp --- **Based on:** [Webamp](https://github.com/captbaritone/webamp "Webamp"), [yandex-music-api](https://github.com/MarshalX/yandex-music-api "yandex-music-api"), [yandex-music-open-api](https://github.com/acherkashin/yandex-music-open-api "yandex-music-open-api") *While the Winamp name, interface and logo are surely property of Nullsoft.* --- # Yaamp API HTTP API для управления плеером Yaamp. ## Включение API API можно включить двумя способами: 1. **Через файл настроек** (`settings.json` в папке userData): ```json { "api": { "enabled": true, "port": 8080 } } ``` 2. **Через IPC** (из renderer процесса): ```javascript ipcRenderer.invoke('setApiSettings', { enabled: true, port: 8080 }); ``` После изменения настроек API сервер автоматически перезапустится. ## Веб-интерфейс На корневой странице API (`http://127.0.0.1:{port}/`) доступен веб-интерфейс для управления плеером. **Особенности:** - Кнопки управления: Предыдущий трек, Воспроизведение/Пауза, Следующий трек - Слайдер управления громкостью (0-100%) - Кнопки для запуска "Моя волна" и "Любимые треки" - Поиск треков с возможностью воспроизведения найденных артистов и альбомов - Отображение статуса API и последнего действия - Поддержка клавиатурных сокращений: - `Пробел` - Воспроизведение/Пауза - `←` - Предыдущий трек - `→` - Следующий трек Просто откройте в браузере: `http://127.0.0.1:8080/` ## Endpoints Все endpoints доступны по адресу `http://127.0.0.1:{port}` (по умолчанию `http://127.0.0.1:8080`). ### GET /next Переключить на следующий трек. **Пример:** ```bash curl http://127.0.0.1:8080/next ``` **Ответ:** ```json { "success": true, "message": "Next track" } ``` ### GET /prev Переключить на предыдущий трек. **Пример:** ```bash curl http://127.0.0.1:8080/prev ``` **Ответ:** ```json { "success": true, "message": "Previous track" } ``` ### GET /playpause Переключить воспроизведение/паузу. **Пример:** ```bash curl http://127.0.0.1:8080/playpause ``` **Ответ:** ```json { "success": true, "message": "Play/Pause toggled" } ``` ### GET /play Воспроизвести трек. **Пример:** ```bash curl http://127.0.0.1:8080/play ``` **Ответ:** ```json { "success": true, "message": "Play" } ``` ### GET /pause Поставить на паузу. **Пример:** ```bash curl http://127.0.0.1:8080/pause ``` **Ответ:** ```json { "success": true, "message": "Pause" } ``` ### GET /volume?value=50 Установить громкость плеера (0-100). **Пример:** ```bash curl http://127.0.0.1:8080/volume?value=75 ``` **Ответ:** ```json { "success": true, "message": "Volume set to 75%", "volume": 75 } ``` ### GET /mywave Запустить "Моя волна". **Пример:** ```bash curl http://127.0.0.1:8080/mywave ``` **Ответ:** ```json { "success": true, "message": "Моя волна запущена" } ``` ### GET /myloved Загрузить "Любимые треки". **Пример:** ```bash curl http://127.0.0.1:8080/myloved ``` **Ответ:** ```json { "success": true, "message": "Любимые треки загружены" } ``` ### GET /search?query=... Поиск артистов и альбомов. **Параметры:** - `query` или `q` (обязательный) - поисковый запрос **Пример:** ```bash curl "http://127.0.0.1:8080/search?query=король" ``` **Ответ:** ```json { "success": true, "results": [ { "type": "artist", "id": "12345", "name": "Король и Шут" } ] } ``` **Примечание:** Результаты поиска могут содержать артистов (`type: "artist"`) или альбомы (`type: "album"`). Используйте ID из результатов с эндпоинтами `/setArtist` или `/setAlbum` для воспроизведения. ### GET /setArtist?id=... Загрузить популярные треки артиста по ID и начать воспроизведение. **Параметры:** - `id` или `artistId` (обязательный) - ID артиста из результатов поиска **Пример:** ```bash curl "http://127.0.0.1:8080/setArtist?id=12345" ``` **Ответ:** ```json { "success": true, "message": "Артист загружен" } ``` **Примечание:** ID артиста можно получить из результатов поиска (`/search`). ### GET /setAlbum?id=... Загрузить треки альбома по ID и начать воспроизведение. **Параметры:** - `id` или `albumId` (обязательный) - ID альбома из результатов поиска **Пример:** ```bash curl "http://127.0.0.1:8080/setAlbum?id=67890" ``` **Ответ:** ```json { "success": true, "message": "Альбом загружен" } ``` **Примечание:** ID альбома можно получить из результатов поиска (`/search`). ### GET /status Проверить статус API сервера. **Пример:** ```bash curl http://127.0.0.1:8080/status ``` **Ответ:** ```json { "success": true, "message": "API server is running", "endpoints": ["/next", "/prev", "/play", "/pause", "/playpause", "/volume?value=50", "/mywave", "/myloved", "/search?query=...", "/setArtist?id=...", "/setAlbum?id=...", "/status"] } ``` ## Безопасность API сервер доступен только на `127.0.0.1` (localhost), что означает, что он доступен только с локальной машины. Это обеспечивает базовую безопасность. ================================================ FILE: bundled/skins/.gitignore ================================================ base-2.91.zip Skinner_Atlas/ ================================================ FILE: bundled/skins/base-2.91/PLEDIT.TXT ================================================ [Text] Normal=#00FF00 Current=#FFFFFF NormalBG=#000000 SelectedBG=#0000C6 Font=Arial ================================================ FILE: bundled/skins/base-2.91/REGION.TXT ================================================ ; I stole this from the Complex skin, cause hey I thought it was cool :) ; (and cause I'm too lazy to document it myself. :) ; The original author is Adam Kennedy ; ; Hope you don't mind Adam :) ; ; ; -Justin ; ; ; P.S. you can use the section names [WindowShade] and [Equalizer] ; for obvious purposes =) ; ; ; REGION.TXT STRUCTURE FOR DEFINING SKIN MASKS ; ;The region information comes without any supporting documentation ;so I thought I might as well make some. ; ;The region.txt in WinAmp 1.92 allows us to some interesting things with transparencies ;But how does it work? ; ;Well, basically, it lets you define a set of polygons. Anything inside a polygon is drawn. Anything not in a polygon is not drawn. Simple heh? ;For how to define it have a look below at the first block. Un-comment it now. Don't worry about commenting the actual one lower down, if WinAmp finds multiple definitions, it only does the first and ignores the rest ; ;How to make a mask ;1. Type [Normal]. Real simple that one. (My guess is it is just for forward compatibility) ;2. Just type the NumPoints= and leave the number blank, we'll fill it in later ;3. OK, now for the fun part. ; The co-ordinates you should type in are the OUTSIDE pixel co-ordinates in x,y format. ; Start at the top lefthand corner and work your way CLOCKWISE around you polygon. ; Now WinAmp ONLY accepts the PointList as one line of comma seperated variables. ; You can use spaces, but DONT GO ONTO A NEW LINE. Clear? Good. :) ; One last thing, don't type the first position again at the end, WinAmp joins them. ; Putting a space between each pair is simply common sense, right? ;4. Once your done, count the number of co-ords, and fill in that number for NumPoints. ; ;Oh, as a side note, the x variables go from 0 to 275, and the y from 0 to 116. ;So if you look at the first example you can see I've gone across the second top line, gone down a bit, ducked in one pixel, gone down to the bottom, and across and back up the other side, putting another ledge on the other side. ;This does the outside border, and chops some bits out on the top and edges ;[Normal] ;NumPoints=8 ;Do this LAST! ;PointList=0,1, 275,1, 275,14, 274,14, 274,115, 1,115, 1,14, 0,14 ;Cool heh? Very subtle effect. Now lets try a more complex one, with multiple polygons ;For your first hard(ish) mask, I suggest defining each element as a seperate mask. ;It makes them a bit easier to think about. ;First, lets define an area that JUST does the titlebar. ;[Normal] ;NumPoints=4 ;PointList=0,1, 275,1, 275,14, 0,14 ;Simple as can be :) ;Go ahead, uncomment it and have a look. Just remember to recomment everything above it ;Doing your areas one at a time does speed the process up a bit ;Now lets define JUST the area sort of inside the outer ring ;[Normal] ;NumPoints = 4 ;PointList = 3,15, 272,15, 272,113, 3,113 ;Right, so say we want a mask that has, the titlebar AND the main area. ;We just add them together ; [Normal] ; NumPoints = 4, 4 ;Make sure to get the order right(although it doesnt matter here =P ) ; PointList = 0,1, 275,1, 275,14, 0,14, 3,15, 272,15, 272,113, 3,113 ;Dont forget to add that extra comma after the first set. ; Having that bigger gap that lets you "keep it in your head" easier, it's a good idea ;OK, now lets try something tricky. We are going to make a mask for just one green line around the outside of the skin ;This introduces the other "big thing" with masks. Have a look at the first three co-ordinates below. You can see the first two moves we make are to go one to the side and then go down to the bottom. Looking at the last co-ordinate you can see we will come back up at the end, making a line two wide, right? ;WRONG!! Here comes the big important phrase. ;IF YOU ARNT FOLLOWING THE OUTSIDE EDGE, YOUR CO-ORDINATES MARK TRANSPARENT SPACE LIMITS ;That's right. Because I don't make a square, because I have to turn "inside" the box, I am only marking space, and what I end up with is a mask with one green line. ;WARNING: Leave your skins dialog open when you do this one. :) ;[Normal] ;NumPoints = 8 ;PointList = 1,14, 2,14, 2,114, 273,114, 273,14, 274,14, 274,115, 1,115 ;OK, as the final touch lets add lets the border we just made to the other two. ;You should be able to work this out on your own ;[Normal] ;NumPoints = 4, 4, 8 ;PointList = 0,1, 275,1, 275,14, 0,14, 3,15, 272,15, 272,113, 3,113, 1,14, 2,14, 2,114, 273,114, 273,14, 274,14, 274,115, 1,115 ;hmm... that still looks a bit tacky down the bottom right ;So I'm going to modify it a bit ;See if you can work out what I've had to alter just by looking at the display of it ;[Normal] ;NumPoints = 4, 4, 8 ;PointList = 0,1, 275,1, 275,14, 0,14, 3,15, 272,15, 272,80, 3,80, 1,14, 2,14, 2,81, 273,81, 273,14, 274,14, 274,115, 1,115 ; Justin's whacked trans skin :) in one, big lame messy line ; [Normal] ; NumPoints=20,4,4,4,8,4,4,6,6,4,4,4,4 ; PointList=0,0,19,0,19,11,114,11,114,0,156,0,156,11,243,11,243,0,275,0,275,13,266,13,266,22,264,22,264,13,111,13,111,22,109,22,109,13,0,13, 109,22,266,22,266,36,109,36, 16,88,130,88,130,105,16,105, 136,89,157,89,157,104,136,104, 22,13,22,62,102,62,102,13,100,13,100,24,24,24,24,13, 0,0,275,0,275,3,0,3, 16,72,264,72,264,81,16,81, 0,13,0,78,16,78,16,75,4,75,4,13, 275,13,275,78,264,78,264,75,272,75,272,13, 14,78,16,78,16,105,14,105, 130,81,132,81,132,105,130,105, 146,81,146,89,148,89,148,81, 130,96,136,96,136,98,130,98 ;THE END ; ;Post-Script ;The other good thing about doing your mask in bits and pieces like this is that can make multiple versions so you can change as your whims change ================================================ FILE: bundled/skins/base-2.91/Skining Updates.txt ================================================ Coppied from winamp/wa_dlg.h from the Winamp 2.9 ML SDK. 1) gen.bmp has a generic window frame for plugins to use. its format is similar to the minibrowser's. In addition gen.bmp includes a font for the titlebar, in both highlight and no-highlight modes. The font is variable width, and it uses the first color before the letter A as the delimiter. The no-highlight form of letter must be the same width as the highlight form. 2) genex.bmp has button and scrollbar images, as well as some individual pixels that describe the colors for the dialog. The button and scrollbar images should be self explanatory (note that the buttons have 4 pixel sized edges that are not stretched, and the center is stretched), and the scrollbars do something similar. The colors start at (48,0) and run every other pixel. The meaning of each pixel is: x=48: item background (background to edits, listviews etc) x=50: item foreground (text color of edit/listview, etc) x=52: window background (used to set the bg color for the dialog) x=54: button text color x=56: window text color x=58: color of dividers and sunken borders x=60: selection color for listviews/playlists/etc x=62: listview header background color x=64: listview header text color x=66: listview header frame top color x=68: listview header frame middle color x=70: listview header frame bottom color x=72: listview header empty color x=74: scrollbar foreground color x=76: scrollbar background color x=78: inverse scrollbar foreground color x=80: inverse scrollbar background color x=82: scrollbar dead area color ================================================ FILE: bundled/skins/base-2.91/VISCOLOR.TXT ================================================ 0,0,0, // color 0 = black 24,33,41, // color 1 = grey for dots 239,49,16, // color 2 = top of spec 206,41,16, // 3 214,90,0, // 4 214,102,0, // 5 214,115,0, // 6 198,123,8, // 7 222,165,24, // 8 214,181,33, // 9 189,222,41, // 10 148,222,33, // 11 41,206,16, // 12 50,190,16, // 13 57,181,16, // 14 49,156,8, // 15 41,148,0, // 16 24,132,8, // 17 = bottom of spec 255,255,255, // 18 = osc 1 214,214,222, // 19 = osc 2 (slightly dimmer) 181,189,189, // 20 = osc 3 160,170,175, // 21 = osc 4 148,156,165, // 22 = osc 4 150, 150, 150, // 23 = analyzer peak dots ================================================ FILE: dist/.gitignore ================================================ * !.gitignore ================================================ FILE: main.js ================================================ // TODO: Нужно сделать рефакторинг всего кода, но мне лень с: const path = require('path'); const url = require('url'); const { ipcMain, webContents, session, remote, screen, TouchBar, nativeImage } = require('electron'); const { TouchBarLabel, TouchBarButton, TouchBarSpacer } = TouchBar; const crypto = require("crypto"); const DiscordRPC = require('discord-rpc'); const checkForUpdatesAndNotify = require('./src/node/updates.js') const interceptStreamProtocol = require('./src/node/protocol.js') const { createApiServer, stopApiServer } = require('./src/node/api-server.js') const electron = require('electron') const fs = require('fs') const {readFile} = require('fs/promises'); const app = electron.app const BrowserWindow = electron.BrowserWindow const { YandexMusicClient } = require('yandex-music-client/YandexMusicClient') const { getTrackUrl } = require('yandex-music-client/trackUrl') // раскомментировать для отображения дебаг панели //require('electron-debug')({ showDevTools:true, devToolsMode: 'undocked' }) const tokenPath = app.getPath("userData") + '/token.json'; const skinPath = app.getPath("userData") + '/skin.json'; const eqPath = app.getPath("userData") + '/eq.json'; const settingsPath = app.getPath("userData") + '/settings.json'; const URL_WITH_ACCESS_TOKEN_REGEX = 'https:\\/\\/music\\.yandex\\.(?:ru|com|by|kz|ua)\\/#access_token=([^&]*)'; let nowPlaying = 0; let nowPlaylist = []; let yaAuthToken = ''; let skinData = ''; let eqData = ''; let settingsData = { windows: { mainWindow: { x: 0, y: 12, visible: true, }, playlistWindow: { x: 0, y: 244, size: [0, 0], visible: true, }, equalizerWindow: { x: 0, y: 128, visible: true, }, milkdropWindow: { x: 275, y: 12, size: [7,8], visible: true, } }, zoom: 1, api: { enabled: false, port: 8080 } }; let resetSettings = settingsData; let currentBounds; // Discord const sessionId = crypto.randomBytes(20).toString('hex'); const clientId = '1161295534770892860'; DiscordRPC.register(clientId); const rpc = new DiscordRPC.Client({ transport: 'ipc' }); rpc.login({ clientId }).catch(console.error); // Mac Touchbar let prev = new TouchBarButton({ backgroundColor: '#000000', icon: nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAASCAYAAACw50UTAAAAAXNSR0IArs4c6QAAASZJREFUOE9jXLv12H8GKoPr9+8zzJ8wmYERZLiTlyXVjN+37TjD0nVrGS4dOIow/Nz56xRb8OH5BwaQq48dO8Zw69S5ATK8t2cq3CfFJdkYvoLJI8uBXH7u/DmG89euM9w6eRa3y0Gaff38GCLC3RjQgwyXHIrh+IIFlwEwcZBX0C2myHBkgwkZfvv0eeKDBd1gQobjTS3owWJkqMmwYuUulIjFFywkuRxkKroFVDUc3QKqG45sAdmGg4IABrAVDTB5ZDnkpIgS5qAChxoAlkPhhoMMBRU43z+8p4b54Ox/5/QFBsaWKUv/g2z78f0HVQyGGXL7zAUGRnl5w/+MDIwIgxkhbCZGBob/DFAZRkYGRqg4SA4k+h8k9h9UzzAyMCDLwdQCpQBA03BAzydq3wAAAABJRU5ErkJggg=='), iconPosition: 'overlay', click: () => { mainWindow.webContents.send('prevTrack'); } }) let play = new TouchBarButton({ backgroundColor: '#000000', icon: nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAASCAYAAACw50UTAAAAAXNSR0IArs4c6QAAAQ9JREFUOE/FlbESwUAQhnfzLswo6YxOoTBDyzsoeQQlHaWSjoKhVJ4uoRGqoFFKR3dmw0oGiRM345rM3F2+/78/uxccToUEzcN2HBh0e4AEzxez2vDz2QL6oyFshOXDTcv+WcA9ukCuhRBwWG3+BG+3ut5J6o2a8onIuWmZYK1t2C0jnBO8VC7DZDxWFgnCI2NhONtWEfna+XMmUSKxnauIaINXKwVPL1jCQfh+tQ0vxefM2fk7KK/Fdh4FfQ9XcK4C/RqeSadeMv3UTaGZ04WjY3CHPj4oQenCObsnHXyv/Q9ULc1OX5La5XzRAmaI5zyZyEkABDTQhyMC8i8Eb/PIT+B9/n7j/q6ktfs0SgOutQw52vzOQLoAAAAASUVORK5CYII='), iconPosition: 'overlay', click: () => { mainWindow.webContents.send('playPause'); } }) let next = new TouchBarButton({ backgroundColor: '#000000', icon: nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAASCAYAAACw50UTAAAAAXNSR0IArs4c6QAAAPtJREFUOE9jXLv12H8GKoPr9+8zaCoqMjCCDHfysqSa8fu2HWdYum4tQ3RQMMLwc+evU2zBh+cfGECuPnbsGENydPQAGd7bMxXsk+KSbAwfweTQ5UEuP3f+HMP5a9fxuxxkgK+fH8PmTZswLIDJRYS7MSAHJ8mGg1yHbgFVDUe3gOqGI1tAE8NhYUx1w5Ejj6qGo6cKqhmObjAo7Ck23MhQE5x5sBULMDl0eZzpHFTgUANg5FCQoaAC5/uH99QwH5z93917z8DYMmXpf5BtP77/oIrBMEP2rVvKwGhmFgquLBgZmRj+///PwMjIiNUSRgbs4gw41F+4sJ0BABVaXHLFWpERAAAAAElFTkSuQmCC'), iconPosition: 'overlay', click: () => { mainWindow.webContents.send('nextTrack'); } }) let trackinfo = new TouchBarButton({ backgroundColor: '#000000', textColor: '#01E804', label: '', click: () => { mainWindow.webContents.send('nextTrack'); } }) const touchBar = new TouchBar({ items: [ prev, play, next, new TouchBarSpacer({ size: 'small' }), trackinfo ] }) // Keep a global reference of the window object, if you don't, the window will // be closed automatically when the JavaScript object is garbage collected. let mainWindow; function createWindow() { electron.protocol.interceptStreamProtocol( 'file', interceptStreamProtocol(), (error) => { if (error) { console.error('Failed to register protocol') } }, ) app.commandLine.appendSwitch("disable-features", "OutOfBlinkCors"); // For Linux: Remove "resizable" // Create the browser window. getSettingsFromFile().then( () => { mainWindow = new BrowserWindow({ width: 800, height: 600, transparent: true, useContentSize: false, frame: false, hasShadow: false, show: false, resizable: false, fullscreenable: false, icon: path.join(__dirname, 'res/icon.png'), webPreferences: { nodeIntegration: true, contextIsolation: false, enableRemoteModule: true, webSecurity: false, preload: path.join(__dirname, 'src/node/preload.js'), } }) // and load the index.html of the app. mainWindow.loadURL(url.format({ pathname: './dist/index.html', protocol: 'file:', slashes: true })) mainWindow.setTouchBar(touchBar) // and show window once it's ready (to prevent flashing) mainWindow.once('ready-to-show', () => { mainWindow.webContents.setZoomFactor(settingsData.zoom ? settingsData.zoom : 1) mainWindow.show() checkForUpdatesAndNotify() if (settingsData.api && settingsData.api.enabled) { const port = settingsData.api.port || 8080; createApiServer(port, mainWindow); } }) mainWindow.on('closed', function () { stopApiServer(); mainWindow = null }) }); } function createLogin() { electron.protocol.interceptStreamProtocol( 'file', interceptStreamProtocol(), (error) => { if (error) { console.error('Failed to register protocol') } }, ) app.commandLine.appendSwitch("disable-features", "OutOfBlinkCors"); // Create the browser window. mainWindow = new BrowserWindow({ width: 350, height: 450, frame: false, hasShadow: false, resizable: false, icon: path.join(__dirname, 'res/icon.png'), webPreferences: { preload: path.join(__dirname, 'src/node/preload.js'), } }) // and load the index.html of the app. mainWindow.loadURL('http://yaamp.ru/login.html') mainWindow.on('closed', function () { // Dereference the window object mainWindow = null }) } const getTokenFromFile = async()=>{ try { const result = await readFile(tokenPath,'binary') yaAuthToken = result; } catch (error) { fs.writeFile(tokenPath, '', (error) => {}); } } const getSkinFromFile = async()=>{ try { const result = await readFile(skinPath,'binary') skinData = result; } catch (error) { fs.writeFile(skinPath, '', (error) => {}); } } const getEQFromFile = async()=>{ try { const result = await readFile(eqPath,'binary') eqData = result; } catch (error) { fs.writeFile(eqPath, '', (error) => {}); } } const getSettingsFromFile = async()=>{ try { const result = await readFile(settingsPath, 'binary') const parsed = JSON.parse(result); settingsData = { ...settingsData, ...parsed, api: { enabled: parsed.api?.enabled !== undefined ? parsed.api.enabled : false, port: parsed.api?.port || 8080 } }; } catch (error) { fs.writeFile(settingsPath, JSON.stringify(settingsData), (error) => {}); } } // This method will be called when Electron has finished // initialization and is ready to create browser windows. // Some APIs can only be used after this event occurs. // Linux has transparency disabled and window creation delayed // due to issues with transparency of Chromium on Linux. // See https://bugs.chromium.org/p/chromium/issues/detail?id=854601#c7 if (process.platform === 'linux') { app.disableHardwareAcceleration() app.on('ready', () => { getTokenFromFile().then( () => { if (yaAuthToken) { setTimeout(createWindow, 100) } else { setTimeout(createLogin, 100) } }) }) } else { app.on('ready', () => { getTokenFromFile().then( () => { if (yaAuthToken) { createWindow() } else { createLogin() } }) }) } if (yaAuthToken) { app.on('web-contents-created', (event, contents) => { // Prevent all navigation for security reasons // See https://github.com/electron/electron/blob/master/docs/tutorial/security.md#13-disable-or-limit-navigation contents.on('will-navigate', (event, navigationUrl) => { event.preventDefault() }) // Prevent new window creation for security reasons // and open the URLs in the default browser instead // See https://github.com/electron/electron/blob/master/docs/tutorial/security.md#14-disable-or-limit-creation-of-new-windows contents.on('new-window', (event, navigationUrl) => { const parsedUrl = url.parse(navigationUrl) if (parsedUrl.protocol === 'file:' || parsedUrl.protocol === 'chrome-devtools:') { return } event.preventDefault() electron.shell.openExternal(navigationUrl) }) }) } else { app.on('web-contents-created', (event, contents) => { contents.on('will-navigate', (event, navigationUrl) => { const match = navigationUrl.match(URL_WITH_ACCESS_TOKEN_REGEX); if (match) { fs.writeFile(tokenPath, match[1], (error) => { if (!error) { app.relaunch(); app.quit(); } }); } }) })} // Quit when all windows are closed. app.on('window-all-closed', function () { // Stop API server when all windows are closed stopApiServer(); // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', function () { // On OS X it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (mainWindow === null) { createWindow() } else if (settingsData.api && settingsData.api.enabled && mainWindow && !mainWindow.isDestroyed()) { // Restart API server if it was enabled const port = settingsData.api.port || 8080; createApiServer(port, mainWindow); } }) let accountData = {}; getTokenFromFile().then( () => { const client = new YandexMusicClient({ BASE: "https://api.music.yandex.net:443", HEADERS: { 'Authorization': `OAuth ${yaAuthToken}`, // specify 'en' to receive data in English 'Accept-Language': 'ru' }, }); client.account.getAccountStatus().then(async ({result}) => { accountData.uid = result.account.uid; accountData.login = result.account.login; accountData.fullName = result.account.fullName; accountData.secondName = result.account.secondName; accountData.firstName = result.account.firstName; accountData.displayName = result.account.displayName; }); // Получаем любимые треки ipcMain.handle('getLikedTracks', async (event) => { nowPlaylist = []; let likeTrackIDs = []; const data = await client.tracks.getLikedTracksIds(client, accountData.uid).then((data) => { data.result.library.tracks.forEach((element) => { likeTrackIDs.push(element.id); }); return data; }) const tracks = await client.tracks.getTracks({"track-ids": likeTrackIDs}).then((data) => { return data; }) return tracks; }) // Получаем URL трека по ID ipcMain.handle('getTrackByID', async (event, trackid) => { if (!trackid.includes('blob')) { nowPlaying = trackid; const data = await getTrackUrl(client, trackid).then((data) => { return data; }) await client.tracks.playAudio({"track-id": trackid, "from": 'web-main-rup-radio-main', "timestamp": new Date().toISOString(), 'uid': accountData.uid, 'play-id': sessionId}).then((data) => { return data; }) // Discord Integration // Check on uploaded track if (!/^.*-.*-.*-.*-.*$/.test(trackid)) { await client.tracks.getTracks({"track-ids": [trackid]}).then((data) => { const element = data.result[0]; const startTimestamp = new Date(); let artist = []; element.artists.forEach((a) => { artist.push(a.name); }); const presObj = { details: `${element.title}`, state: `${artist.join(', ')}`, largeImageKey: 'https://' + element.coverUri.replace("%%", "200x200"), largeImageText: `${artist.join(', ')} - ${element.title}`, smallImageKey: 'https://yaamp.ru/icon.png', smallImageText: 'Yaamp.ru', buttons: [ { label: 'Listen to this track', url: `https://music.yandex.ru/track/${element.id}`, }, ], }; rpc.setActivity(presObj); return data; }) } return data; } else { return trackid; } }) // Получаем список плейлистов пользователя ipcMain.handle('getUserPlaylists', async (event) => { let userPlaylists = []; await client.playlists.getPlayLists(client, accountData.uid).then((data) => { data.result.forEach((element) => { userPlaylists.push({ title: element.title, uid: element.uid, kind: element.kind }); }); return userPlaylists; }); return userPlaylists; }) // Задаём плейлист ipcMain.handle('setPlaylist', async (event, data) => { let tracks = []; let tracksList = []; await client.playlists.getPlaylistById(data.uid, data.kind).then(async (data) => { nowPlaylist = { uid: data.result.uid, kind: data.result.kind, title: data.result.title }; let tracks = []; data.result.tracks.forEach((element) => { tracks.push(element.id); }); await client.tracks.getTracks({"track-ids": tracks}).then((data) => { mainWindow.webContents.send('setTracks', data.result); }) }); return true; }) // Получаем список исполнителей пользователя ipcMain.handle('getUserArtists', async (event) => { let userArtists = []; await client.artists.getArtists(client, accountData.uid).then((data) => { data.result.forEach((element) => { userArtists.push({ title: element.name, id: element.id }); }); return userArtists; }); return userArtists; }) // Задаём испольнителя ipcMain.handle('setArtist', async (event, data) => { let tracks = []; await client.artists.getPopularTracks(data.id).then(async (data) => { tracks = data.result.tracks; tracks = await client.tracks.getTracks({"track-ids": tracks}).then((data) => { mainWindow.webContents.send('setTracks', data.result); return data; }) return tracks; }); return true; }) // Получаем список альбомов пользователя ipcMain.handle('getUserAlbums', async (event) => { let userAlbumsIds = []; let userAlbums = []; await client.albums.getAlbums(client, accountData.uid).then((data) => { data.result.forEach((element) => { userAlbumsIds.push(element.id); }); }); await client.albums.getAlbumsByIds({"album-ids": userAlbumsIds}).then((data) => { data.result.forEach((element) => { if (element.type !== 'podcast') { userAlbums.push({ title: element.artists[0].name + ' - ' +element.title, id: element.id }); } }); }); return userAlbums; }) // Задаём альбом ipcMain.handle('setAlbum', async (event, data) => { nowPlaylist = []; let tracks = []; await client.albums.getAlbumsWithTracks(data.id).then(async (data) => { data.result.volumes[0].forEach((element) => { tracks.push(element.id); }); tracks = await client.tracks.getTracks({"track-ids": tracks}).then((data) => { mainWindow.webContents.send('setTracks', data.result); return data; }) return tracks; }); return true; }) // Получаем список станций ipcMain.handle('getRotor', async (event) => { let stations = []; let userAlbums = []; await client.rotor.getStationsList('ru').then((data) => { data.result.forEach((element) => { stations.push({ title: element.station.name, id: element.station.id.type + ':' + element.station.id.tag }); }); }); return stations; }) // Задаём станцию ipcMain.handle('setRotor', async (event, data) => { nowPlaylist = []; let rotorTracks = []; let lastTrackID = null; mainWindow.webContents.send('setLoader'); await client.rotor.sendStationFeedback(data.id, {type: 'radioStarted', "from": 'web-main-rup-radio-main', "timestamp": new Date().toISOString()}, null).then((data) => { // console.log(data); }) for (let i = 0; i < 15; i++) { if (i !== 0) { lastTrackID = rotorTracks[rotorTracks.length - 1].id; } await client.rotor.getStationTracks(data.id, true, lastTrackID).then((data) => { data.result.sequence.forEach((element) => { rotorTracks.push(element.track); }); }); } mainWindow.webContents.send('setTracks', rotorTracks); mainWindow.webContents.send('hideLoader'); return true; }) // Моя волна ipcMain.handle('setMywave', async (event) => { nowPlaylist = []; let myWave = []; let lastTrackID = null; await client.rotor.sendStationFeedback('user:onyourwave', {type: 'radioStarted', "from": 'web-main-rup-radio-main', "timestamp": new Date().toISOString()}, null).then((data) => { // console.log(data); }) mainWindow.webContents.send('setLoader'); for (let i = 0; i < 25; i++) { if (i !== 0) { lastTrackID = myWave[myWave.length - 1].id; } await client.rotor.getStationTracks('user:onyourwave', true, lastTrackID).then((data) => { data.result.sequence.forEach((element) => { myWave.push(element.track); }); }); } mainWindow.webContents.send('setTracks', myWave); mainWindow.webContents.send('hideLoader'); return true; }) // Любимые треки ipcMain.handle('setMyloved', async (event) => { nowPlaylist = []; let likeTrackIDs = []; const data = await client.tracks.getLikedTracksIds(client, accountData.uid).then((data) => { data.result.library.tracks.forEach((element) => { likeTrackIDs.push(element.id); }); return data; }) const tracks = await client.tracks.getTracks({"track-ids": likeTrackIDs}).then((data) => { mainWindow.webContents.send('setTracks', data.result); }) }) // Поиск ipcMain.handle('search', async (event, data) => { let best = []; await client.search.getSearchSuggest(data.searchText).then(async (data) => { if (data.result.best) { if (data.result.best.type === 'artist') { best = [{type: data.result.best.type, id: data.result.best.result.id, name: data.result.best.result.name }]; } if (data.result.best.type === 'album') { best = [{type: data.result.best.type, id: data.result.best.result.id, name: data.result.best.result.title }]; } } return best; }); return best; }) // Лендинг блоки ipcMain.handle('lendings', async (event, data) => { let lendings = []; const ALL_LANDING_BLOCKS = [ "personalplaylists", ]; const allBlocks = ALL_LANDING_BLOCKS.join(","); lendings = await client.landing.getLandingBlocks(allBlocks).then((data) => { lendings = data.result.blocks; return data.result.blocks[0].entities; }) return lendings; }) // Открытие ссылок ipcMain.handle('openLink', async (event, data) => { require('electron').shell.openExternal(data.link) return true; }) // Играет сейчас ipcMain.handle('openPlayNow', async (event, data) => { require('electron').shell.openExternal(`https://music.yandex.ru/track/${nowPlaying}`) return true; }) // Сохранения скина ipcMain.handle('setSkin', async (event, data) => { fs.writeFile(skinPath, data.link, (error) => {}); return true; }) // Удаление скина при ошибке ipcMain.handle('deleteSkin', async (event, data) => { fs.writeFile(skinPath, '', (error) => {}); return true; }) // Получение скина ipcMain.handle('getSkin', async (event, data) => { skinData = await getSkinFromFile().then( () => { return skinData; }); return skinData; }) // Поставить лайк ipcMain.handle('setLike', async (event, data) => { await client.tracks.likeTracks(client, {"track-ids": nowPlaying}).then((data) => { mainWindow.webContents.send('showMessage', 'Трек добавлен в "Мне нравится"'); }) }) // Поставить дизлайк ipcMain.handle('setDislike', async (event, data) => { await client.tracks.dislikeTracks(accountData.uid, {"track-ids": nowPlaying}).then((data) => { mainWindow.webContents.send('showMessage', 'Дизлайк поставлен'); }) }) // Выход из профиля ipcMain.handle('logout', async (event) => { fs.writeFile(tokenPath, '', (error) => {}); await session.defaultSession.clearStorageData(); app.relaunch(); app.quit(); }) // Текущий плейлист ipcMain.handle('nowPlaylist', async (event, data) => { return nowPlaylist; }) // Рекомендации по плейлисту ipcMain.handle('setPlaylistRecomendation', async (event, data) => { let tracks = []; mainWindow.webContents.send('setLoader'); for (let i = 0; i < 25; i++) { await client.playlists.getRecommendations(data.uid, data.kind).then(async (data) => { data.result.tracks.forEach((element) => { tracks.push(element.id); }); }); } await client.tracks.getTracks({"track-ids": tracks}).then((data) => { mainWindow.webContents.send('setTracks', data.result); mainWindow.webContents.send('hideLoader'); }) }) let locked = false; // Разблокировка окна для перетаскивания окон ipcMain.handle('movingWindowStarted', async (event, data) => { if (!locked) { const { width, height } = mainWindow.getBounds(); const newWidth = width + 500; const newHeight = height + 500; mainWindow.webContents.send('unlockWindow'); mainWindow.setBounds({ width: newWidth, height: newHeight }) locked = true; } }) // Блокировка окна для перетаскивания окон ipcMain.handle('movingWindowEnded', async (event, data) => { if (data) { const windows = data.windows; windows.forEach(window => { if (window.key == 'main') { settingsData.windows.mainWindow.x = window.x; settingsData.windows.mainWindow.y = window.y; } else if (window.key == 'playlist') { settingsData.windows.playlistWindow.x = window.x; settingsData.windows.playlistWindow.y = window.y; } else if (window.key == 'equalizer') { settingsData.windows.equalizerWindow.x = window.x; settingsData.windows.equalizerWindow.y = window.y; } else if (window.key == 'milkdrop') { settingsData.windows.milkdropWindow.x = window.x; settingsData.windows.milkdropWindow.y = window.y; } }); fs.writeFile(settingsPath, JSON.stringify(settingsData), (error) => { if (error) { console.error('Error writing to settings file:', error); } else { mainWindow.webContents.send('lockWindow'); } }); } locked = false; }) // Блокировка окна для перетаскивания окон без сохраения ipcMain.handle('movingWindowEndedWithoutSave', async (event) => { mainWindow.webContents.send('lockWindowWithoutSave'); setTimeout(() => { mainWindow.center(); }, 100) }) // Увеличение окна ipcMain.handle('setRatio', async (event, data) => { settingsData.zoom = data.value; fs.writeFile(settingsPath, JSON.stringify(settingsData), (error) => {}); setTimeout(() => { app.relaunch(); app.quit(); }, 3000) }) // Получение настроек ipcMain.handle('getSettings', async (event) => { if (!settingsData.windows.milkdropWindow) { settingsData.windows.milkdropWindow = { x: 275, y: 12, size: [7,8], visible: true, }; } if (!settingsData.api) { settingsData.api = { enabled: false, port: 8080 }; } return JSON.stringify(settingsData); }) // Настройки API ipcMain.handle('setApiSettings', async (event, data) => { if (!settingsData.api) { settingsData.api = { enabled: false, port: 8080 }; } const wasEnabled = settingsData.api.enabled; const oldPort = settingsData.api.port; if (data.enabled !== undefined) { settingsData.api.enabled = data.enabled; } if (data.port !== undefined) { settingsData.api.port = parseInt(data.port) || 8080; } fs.writeFile(settingsPath, JSON.stringify(settingsData), (error) => { if (error) { console.error('Error writing to settings file:', error); } }); if (mainWindow && !mainWindow.isDestroyed()) { stopApiServer(); if (settingsData.api.enabled) { const port = settingsData.api.port || 8080; createApiServer(port, mainWindow); } else if (wasEnabled) { mainWindow.webContents.send('showMessage', 'API сервер остановлен'); } } return true; }) // Задать размер ipcMain.handle('setSize', async (event, data) => { if (data.id == 'playlist-resize-target') { settingsData.windows.playlistWindow.size = data.size; } else if (data.id == 'gen-resize-target') { settingsData.windows.milkdropWindow.size = data.size; } fs.writeFile(settingsPath, JSON.stringify(settingsData), (error) => { console.log(error); }); }) // Сохранение EQ ipcMain.handle('setEQ', async (event, data) => { fs.writeFile(eqPath, data.link, (error) => {}); console.log(data.link); mainWindow.webContents.send('showMessage', 'EQ сохранён'); return true; }) // Получение EQ ipcMain.handle('getEq', async (event, data) => { eqData = await getEQFromFile().then( () => { return eqData; }); return eqData; }) // Сбросить настройки ipcMain.handle('resetSettings', async (event, data) => { fs.writeFile(settingsPath, JSON.stringify(resetSettings), (error) => { console.log(error); }); setTimeout(() => { app.relaunch(); app.quit(); }, 3000) }) // Milkdrop fullscreen ipcMain.handle('toggle-milkdrop-fullscreen', async (event, status) => { if (status) { currentBounds = mainWindow.getBounds(); mainWindow.maximize(); mainWindow.webContents.send('setFullscreen', status); } else { mainWindow.webContents.send('setFullscreen', status); mainWindow.restore(); mainWindow.setBounds(currentBounds); } }) ipcMain.handle('isPlay', async (event, data) => { if (data) { play.icon = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAASCAYAAACw50UTAAAAAXNSR0IArs4c6QAAAQ9JREFUOE/FlbESwUAQhnfzLswo6YxOoTBDyzsoeQQlHaWSjoKhVJ4uoRGqoFFKR3dmw0oGiRM345rM3F2+/78/uxccToUEzcN2HBh0e4AEzxez2vDz2QL6oyFshOXDTcv+WcA9ukCuhRBwWG3+BG+3ut5J6o2a8onIuWmZYK1t2C0jnBO8VC7DZDxWFgnCI2NhONtWEfna+XMmUSKxnauIaINXKwVPL1jCQfh+tQ0vxefM2fk7KK/Fdh4FfQ9XcK4C/RqeSadeMv3UTaGZ04WjY3CHPj4oQenCObsnHXyv/Q9ULc1OX5La5XzRAmaI5zyZyEkABDTQhyMC8i8Eb/PIT+B9/n7j/q6ktfs0SgOutQw52vzOQLoAAAAASUVORK5CYII='); } else { play.icon = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAASCAYAAACw50UTAAAAAXNSR0IArs4c6QAAAPZJREFUOE9jXLv12H8GKoPr9+8zrJmzjIERZLiTlyXVjN+37TjD0nVrGe6duYkw/Nz56xRb8OH5BwaQq48dO8bw/PqjATC8t2cqii+KS7LhfHxyIJefO3+O4fy16wzPrj7E7nKQAb5+fmADI8LdGJCDDJ8csuE4g2VkGz4a5vBkSr/UcgNHDjUy1ETJRMjpHJ8cTpeDChxqAFgOfX79MSSHggwFFTjfP7ynhvng7A/OoS1Tlv4H2fbj+w+qGAwz5AXI5To6rv8ZGBgZGBkZEYYzMjIwwqoQEJuRkeH///9gGgRh4D8jAwMjiGBgYGBkQoiD1IC0AwDEdnVTCfcsTgAAAABJRU5ErkJggg=='); } }) ipcMain.handle('nowPlaying', async (event, data) => { trackinfo.label = data; }) // Управление громкостью ipcMain.handle('setVolume', async (event, volume) => { if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('setVolume', volume); } return true; }) // Получение текущей громкости (можно расширить позже) ipcMain.handle('getVolume', async (event) => { // По умолчанию возвращаем 50, можно сохранять в настройках return 50; }) }) ================================================ FILE: package.json ================================================ { "name": "yaamp", "version": "0.0.6", "description": "Winamp + Yandex Music", "main": "main.js", "targets": { "main": false }, "scripts": { "copy": "xcopy bundled dist /e /Y && xcopy res dist /e /Y", "clean": "rmdir /s /q node_modules && del /f yarn.lock && yarn cache clean && yarn install", "build": "yarn run copy && yarn build:src", "build:src": "npx parcel build --public-url ./ ./src/index.html", "watch": "npx parcel watch --public-url ./ --hmr-hostname 127.0.0.1 --hmr-port 54439 ./src/index.html", "test": "jest", "electron": "./node_modules/.bin/electron .", "start": "yarn run build && electron .", "pack:win": "electron-builder build -w --x64", "pack:linux": "electron-builder build -l --x64", "pack:mac": "electron-builder build -m --x64", "pack": "yarn run pack:win && yarn run pack:linux && yarn run pack:mac", "dist": "yarn run build && build --x64", "deploy-webamp": "cd webamp && yarn deploy && copy packages\\webamp\\built\\webamp.bundle.js ..\\src\\webamp\\" }, "homepage": "https://yaamp.ru", "repository": "https://github.com/umnik1/yaamp", "author": "Maksim Chingin ", "license": "MIT", "dependencies": { "axios": "^1.5.1", "bufferutil": "^4.0.8", "discord-rpc": "^4.0.1", "electron-is-dev": "^1.0.1", "electron-log": "^3.0.1", "electron-updater": "^4.0.6", "encoding": "^0.1.13", "form-data": "^4.0.0", "html-to-text": "^4.0.0", "left-clicky": "0.1.1", "mime-types": "^2.1.22", "parcel": "^2.9.3", "utf-8-validate": "^6.0.3", "yandex-music-client": "github:umnik1/yandex-music-client" }, "devDependencies": { "@types/jest": "^24.0.11", "@types/node": "^10.14.1", "@types/webdriverio": "^4.13.3", "electron": "^13.0.0", "electron-builder": "^24.0", "electron-debug": "^3.2.0", "eslint": "^5.15.2", "jest": "^24.5.0", "parcel-bundler": "^1.12.2", "spectron": "^13.0.0", "ts-jest": "^24.0.0", "tslint": "^5.14.0", "typescript": "^3.2.4" }, "browserslist": [ "Chrome 69" ], "build": { "appId": "me.umnikone.yaamp", "productName": "Yaamp", "copyright": "Copyright © 2023 Maksim Chingin", "files": [ "!.*${/*}", "!src/*.*", "!artifacts${/*}", "!docs${/*}", "!bundled${/*}" ], "directories": { "buildResources": "res", "output": "artifacts" }, "mac": { "category": "public.app-category.music", "target": "pkg" }, "win": { "target": "nsis-web" }, "linux": { "target": [ "AppImage", "deb" ], "category": "AudioVideo" }, "publish": { "provider": "github", "owner": "umnik1", "token": "" } }, "jest": { "transform": { "^.+\\.tsx?$": "ts-jest" }, "testRegex": "(/__tests__/.*(\\.|/)spec)\\.tsx?$", "moduleFileExtensions": [ "ts", "tsx", "js", "jsx", "json", "node" ] }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } ================================================ FILE: res/icon.hqx ================================================ (This file must be converted with BinHex 4.0) :%$N`-$3h1$"M0Q3cBc3a0@B%9%9B9(4dH(3%!!!!!Y!!!dYGL+9)EhFJG'mJGA0 P)(4SDA-JD@0[EMS+#P0dCA!J-6SJ3fp`H5"dD'8JD@0[EL"dEb"dD'8JBfaTF'* [BA*N#Q%T)%0XD@0V)'pZ)(4SDA-JCQPXC5"QFQpY)(4SC5"'D@jNCA)+BLNJ3fK [Eh0P)#G(CA3J5@jQEbFJCR*[E5"dD'8J*dCTE'8R)'ePER8Z#Q-T)%PZ)(4SC5" TEQC[)(GTEQ4[Gb"dD'&d)("[F(-JGA!X)'0XD@0V)'pZ)(4SC5"TBfpZ#Q3T)%0 SEfpcC5!R3fp`H5FJCR*[E5"dD'8J*d9NDA3R)'ePER8Z#Q8T)%0XEh0P)(4SC5" TEQC[)(GTEQ4[G`S+8h4PF#!b1L"3BA0dC5"dD'8JD@0[EL"dEb"dD'8JC'9cDA* PC#"TG'9Y#Q%T)%G[)(4[)(4SC5"TG'9Y)'PZ)(4SC5"'D@jNCA)JG'KKG#"jEh8 JGf&ZG#"K)'0eFh4[E5"TBfpZ#Q)T)%0XD@0V)(4SC5"TG'9Y)#KQD@aP,#"QEfa NCA)X)'4TFfXX)'9dBbNJ#Q)T)%0SEfpcC5!R4f9d)%PZCQmR)'CbEfdJG'KP)#G 'D@aP*b"YC@je,JTM+5"*EL"dD'8JD@jQEb"hD@jNEhFJG'KKG#"`Eh"c)(9`,#" ME'PMDb"[EL"dD'8JD@0[EJTN+5"$D'p[Ff8J*e"KFh4P*b"QFQpY)(4SC5!R4@4 TG#FJE@9ZG5i+C5NJ3fa[Ff8JG'KP)'PZCQmJGfPZC'ph#JT6G'9`)$-k)!T&EQT [H5"jEh9b)'jPGfaj)'0eFh4[E@PkC@3JD@0[EL%+#NC[FL"YEh*P)(4SEh*[G@G S)'4TFQ9MG'P[ER-X)(0PC5""F("XC5Gc)(GPBR0TG'8JBA3k#QKdG(!k,bphGhF ZBA"`E'8ZBfpY,h0eF("[FR3[E@&M-6!a,f0eFh4[E@PkC5mf,`V6V!!!!3!!!dX V!!0++`!!!$)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!dSRD@0ZF`!$5LGTFc-b!!!#p3d!!!%!!!J)!`-+'ASL"i!!(!% !!!X+!`m0!`$r0cIrr`%!!!d0"")B'3S!DYHAJ3"r$`m&&L!E!b5Jr2"Grrm!%3m &'bJ6$A(Zrrpb!!!(%"%&)LJ03-Rrq[q4!!N,#48'*"mKP2[rqIrG&4)1!JB)+LP Bh[rlqrrlrlN,&`d###`Sd2rirIrkqIqi"4N3!L!-'hpcVIrfrrQQB88A!3!U@aT )G[,prmXc!Me5(h-b!3!)!%lZrr"Y!J!"J!!3!J$rreMXrCmF!!-#!!8!!!D!!!@ Cf@J!!31&!!ErkcJfr`!$L!!%"bKk&3'"!!!"J3!0!!!%!!!R-a-60#PU'JD!!"` &!!!`-Jj46JXCrb`Vk[m&!!!d04&9Fh0-!&HSJ)%!IcJk%ParGea0L-R+6rrr!$X l%f+2Ge*X`Gr4A!!!!MBl%QfDD&UKh0E9K$-C6bT#&(D9A)(2hFhAXc9`5`dU')+ 5BkrBdYr9cY#@8A41$aH+J+hTbpVA`F$JNdTk83jY)f#%E*VAX-c9LAbC@!dT5ji XBA1m`0bU+33q9LH,33!!#!!l`Gr,@J%!!B!!%!d!rrp'cpQ$&`!#!J!&!!F%J!! +Jl99!!%#!!!"!!#!!J[r`5iXr`!$!!!"!!#!!S!!$3BJDa%!!3%!!!-#!J!!$3! !"3!!+cF8&$JI,3F#J!!F"3!!0$82@&8-+6N3$NkY"3!!0cN5A(Yj9`8I15f"!"S l240LKRp[4$9(44k'R!!q2a4RPSCE0%"A54q!!&mi2K0`TAP#1%a@8MP#&eFX4"4 lT9Sf4P*-8$icI&%1,KQ(Qcdp89Y`8%T*0Pap9"!AMiB`88TM9Mdq65Y8JeF3Fb4 P9$p(8Lp#6$jhS9i1,8ZC*h092MP23!d+398SM81!!!3428a-)B-!#!i!NR)E6%m a#)%!!`8!"`5!!"``3Km!!!%!!!%!!!-#!R"(%4#6!!)!!!%!!!-#!S!!$3)+,J8 !!3%!!!-#!J!!FcKYD`!!!3J!!!!!!!3!P*3!"!)!"`!!!!!!!!-!I[rrI`!!BUB !!!!!!!3!JIrlr2q,U2rB!3!!!!3!JIrkr[lmr[crV!!"!!-!JIrkr[rrr[VrjK- !!33!JIrkr[rqrrrqr[pq!!-!I[rkr[rqrrrrrrlprhi!P2rlr[rqrrrrrrlrr[[ rP*6rqrlrr[rrrrrqrrllrj3!I[rpr[rrrrrqrrlkrhi!!`#!rrlqrrrqrrlkri) !"!%!#p[rqIlrrrlkri%!!`!"!+Arr2lmr[lkri%!!`!!!!$@rkZ-rrclri)!!`! !!!!!T'B!!(rrrhm!!`!!!!!!!!F!!J3!PC8!"!!!!!!!D@`c-J!!#Gq(!)!"J`# !!B%!!`cr!2q)!!)"!3+!!!%&"B!!"!%"!!!'M!!#!3%#J!!$"4-5"))!!!b-!)! #J!!3"KB8%K)%!!!(*[m!0B!&&"H&!)!#J!!4"aJA&4-6%J3"!!!,GrhB#LY&K!# !!S!!%JFE'4F@&4-6&J8!4XrrrqBGjrq$!!)#!J1!!"-)(K`D'4F9'4B!'CcqrI2 r[38PIB)!!J)#!i!!%3NJ(K`E'4SH#J&Rl2rkpIrK)i3!J!1!!"%+)b%I(K`K'!! `a2rpqrRqqN5%!)!$J!!4#L8N)5!L)`F-L[Vrqrhlq[pKJ!!'#!%"!!-$")!!%`X S*L-M+4J!6Ylrr2cqr2RrM3!*J!#!!3%$")!!&3`V+58U*`3IVIrpqrlrrI[rY3% 8%J5!!!)"!35!!"F-,5SU-"8'F2(rqrcrr[lmrmN,%aB5%J5!!!!"J!!C$6!Y-LF $1F[rr2cqrrlrr[crRaX*&"36%J5#!!N1-c!a%a18rIrlJ2d#r[lrJ2i)rIpM!4S 6%a)%J!!V%$Bb0491j2rjq2Vkr2cqrrlrr[hfrj)!("86%K)&!!!30c-h$EcrpI[ lrIq"rJhrrI[pq2qV!"`@&436"B!!'`mf1`fQrr[rr[rqr[rrrIVlrI[prhd%(KF @&J@#!"N12K+'lEbiPG6rrIlkqIhmr2r"*`!,%KJC"S!!!!@!!"F4+3JC3!dqp[r mq2[pr2rdF%HLPQJm)3D!!!)""!@!!"F5Tq+A6IMrq[Vpr2hrVam!0'+"V-`a!!# !!3)$"!Z!!!8j'#EXrrL!r!Ari%m!!31"!!S#!J!!#!%"!!-&"S!!%5,TrrRpqrr lM!`!!`)!!3-%!i!!!J-"!B3!#b2CrrVmr2r'-!!#!iB!!JS0$i3!#a2(rrRmrqj S!3!$!BB!J!'#!!aZ'!1drrIrrTiB!!-#K`#!!B-!#[E#(HErrp"'!!%$L!#!!B3 !#6iS#YIrH!X!!!1)!)!"K3!)&a-&JM8!eMd'L!#!!B`!!JS"!BF!J!'-!!3&!!! #!S8!J!')!!0H!!!-J3!#!3%#J`#!!BF!K`!#"`F*J`!##!B'J3!$#Im!riJ!!JF (#B!!!4mIJ!!%#!J!!!@-!!))#!U!!!-FDQFEJ!!##J!,M!!##!J+J!!3(QjTCQB E!!!%*Im!,'3&%K1&!!))#!Z!!!FJFfjTCfGQ'S!!"JKNaEJ**6U%!!)*#3Z!!") KGh0ZE@TQCQiF!$Q`d,r''YArJ`!##3N,J!!6)RaiFR&[DR"[150php+LiU%#&fH #!!)*#3b!!"%NJAehGR*bHeJF8-2PckVA`4b%!!)+#Jb!!"%PKS&mHRCrG$!XR1, 9dVM1f$L%!!)+#Jf!!"%QLiD!IB#'84jVe0l-eXE)j8f!!!B0#3B!#JS0J!!6*j! !Li5$MR3T2l6MdXl@dmIQEadPJ!!%#!B'#`f!!"8TP)q(N!#15#@(hYR0dG,@c1@ 8&'YQ'i!!!JJ'$S!!&bUCNSqFEL4AbH,3d0,4dXrCT"9UE'CR'i!!!!L!!"NVRTH HN!!m-D(Ldmh2cp,4dFrDJb)cC'KRCKZ#!!iYSjfICL4bfH$6epRKjp+!d3R6fG4 *4(0QCfBEJ!!p-kUITP-jZ0h)`m'rbZhHcp(9dm@pi(JjGfPRCQFH!!!cV+'X3Tl Mamc,cXlQfmc8em5ea-hKMc0kDfPTDKq!!"XZU,02K1MEhq,9iY[2fFQYXmh4hGp D-haXEQiGJJ!C,,KJBlk9PhUri0(6VD,$dp6KR5-PD'jbFak!!!!2J!!A0S3N1em C2GE@`jqadY2HcPa(ZY#VMRSIJ!!##3X2J!!9-G[hS8VKeE'SbY6AhBmD!$4HHDM 41i!!"!N(#`X5J!!1-43LdmQV[Y66i,T!!!!#J3!+!3)!!!i("`!,$a#!!"FJcX+ ecp2EeA)+!!)"!!%$"!-"!!!*"`H%!!XJYmE&dYAJSLF!!3+$!!8"!!!0$a#%!!X 3Sp2-dq,(9!%!!J'$!!)"!!#!"))!$&S2!CEJbpcEJ"3!!J+%!!8"!!!&"!5$!!V DY4[$eZ5X13!"!S8!"3%!!!8%")3!#68H"lhCBJN!!!5&!!8"!!!&"!5&!!S5%!4 V,!#`0`-!!S-!"3)!!!8%")`!"3N!"`!!!S%!!J)!!)!&M!!-"!!!"`B!!!)!!!) !!)!&L!!$9`!!#i%!#`8&"J!!!J)!!!B&"BF!K`!##!J+J`!##3F(J3!$!l8!NiJ !!JJ)#S!!!5)LJ!!%#3N!!!+-!!))#!U!!!-IFh%GJ!!#$!!%M!!##3N,J!!&)AG aEh!HJ!!(%Im!%#)#"`H&!!)*#3Z!!!FLHhGbF("[(B!!"J)Q38!%$a@%!!)*#3b !!")MJ(YfGA0ZEhBI!"9$4cT+#8eMJ`!##3S-J!!6*)5!HRThFhGh54NX8NmT8cX !##@#!!)+#Jb!!"%QLB4rIRTjJQ8N'N959$*-4`U%!!)+#Jf!!"%RMSQ$JRk'IMm 80&4,9d*(845%!!)+#Jf!!"%SNSk)KBH0B"`L690(@&0$9KQ!!!B,#3F!#`X1J!! 6+CH5LiU8Ic3@2P40599M49BN+bD!!!3*"`F,$S!!&5ZFPSk@P9FA,&*35de,Ade 8-4YdEaf!!!)*"`k!!!NXS*Q@SAXT'dK9J%d+6%j06cS8GA4ZF"k!!!!*J!!0,D@ HSjP*&$955NG'4df!6!K3-"8iE(&[Eak#!!iZUU5PFamN89K@AQ0cI%k!6!P16dN 98RTZF(!HJ!!p0E#QV&S23eG36Ne+8SjR5%a36N%p8LP)IR&`Eh%K!!!eXkHa5M4 95%K(4d4hB%0388!b3%Y8-$q"Fh*aFb'!!"X`VVKD+eK58e0,G'0'988U-8P18P- C2)4dGhFIJJ!C,VeY'N!X05TKC%P2+L!r8%j6-3B`F(CkHb'!!!!2J!!A1)SL1@) K+'*03"i[6Np36#"*`p5aPB-LJ!!##3`2J!!9-YrhU$4N5M!Q4P&18$3*!$4FH+I 42)!!"!S($!`6J!!,,aF3@d!V1P"1883AK!!+!3)!!!i)#!!-%!f!!"F5@$Nd5P" 265S$!!%!!!%$"!-#!!!*#!L%!!J856Y$6dj41`k'!!8"!!!0$a'%!!S)28C,6P* *(`!!!B3!"3%!!!8%"))!#5%'!$G35e"3,`H(!!8"!!!&"!5$!!T33JT(6P-r&3! !!B8!"3%!!!8%")3!#4-,!N92)`-!!!1&!!8#!!!&"!5&!!S'"3%R%!"!'`!!!S- !!J)!!)!&M!!&!`!)!!!#J3!&!J!!"J8&M!!2!3!!#!F!!!)!!!)!!!B&"BJ!!b! !!!5"!!X'"JF!!!)#!!!'"3@(!'`iE@X!!!3)!!!!!!!!!!!!!!!!!!3!PTB!"!! !!!!!!!%$!!!!!!!!!!!!!!!!!!!!!!!$!)$rri!!!`!!!!!$!!-1!!!!!!!!!!! !!!!!!!!!!`#$rr[lri-!!`!#!`!4XiB!!`!!!!!!!!!!!!!!!!-!J[rkr[lkri- !"!!!BZErQ3!$!!!!!!!!!!!!!!!$!),rq[lrrrlkri3!,X$rq[qZ!!)!!!!!!!! !!!!!!`##rrVqrrlqrrlprEM[rr[lrm3!!3!!!!!!!!!!!!-!J[rkr[rqrrrqrrl mrrhmrr[rZ3!"!!!!!!!!!!!$!),rq[lrr[rrrrrqrrllr[rprqBK!!%!!!!!!!! !!`##rrVqrrlrrrrrrrrrrrlqr[rc3!!#!!!!!!!!!!-!J[rkr[rqrrrrrrrrrrr rrrllrki!"3!!!!!!!!!$!),rq[lrr[rrrrrrrrrrrrrrrrlpri8!!`!!!!!!!`# #rrVqrrlrrrrrrrrrrrrrrrrrr[lmri-!!`!!!!-!J[rkr[rqrrrrrrrrrrrrrrr rrrrqrrlkri-!!`!%!)2rq[lrr[rrrrrrrrrrrrrrrrrrrrrqrrlkri-!!`#!rrV qrrlrrrrrrrrrrrrrrrrrrrrrrrrqrrlkri!!P[rlr[rqrrrrrrrrrrrrrrrrrrr rrrrrrrrqrrllrjD9rr[qrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[[rPJ"rrrV qrrlrrrrrrrrrrrrrrrrrrrrrrrrqrrlkri!!"!##rrVqrrlrrrrrrrrrrrrrrrr rrrrrr[rqq[q$!!3!!`##rrVqrrlrrrrrrrrrrrrrrrrrrrlrr[VrJJ!$!!!!!`# #rrcqr[rrrrrrrrrrrrrrrrrqrrlkri3!!`!!!!!!!`#'rrhqrrrrrrrrrrrrrrr rr[rqq[q%!!-!!!!!!!!!"3#@rr[qrrrrrrrrrrrrrrlrr[VrK!!$!!!!!!!!!!% !)YIrrIlqrrrrrrrrrrrqrrlkri3!!`!!!!!!!!!"!"I@rrcrr[cqrrlrrrrrr[r qq[q%!!-!!!!!!!!!!!%!Yrrkrrcprrcqrrlrrrlrr[VrK!!$!!!!!!!!!!!!!3$ "rr[lrr'lrIhqrrlqrrlkri3!!`!!!!!!!!!!!!!$!+RrqIr&-J#&rrVqrrrqq[q %!!-!!!!!!!!!!!!!!!-!N[rTD!%!"!#%rrVqr[VrK!!$!!!!!!!!!!!!!!!!!`" pZ48!!`)!!`#%rr[lri8!!`!!!!!!!!!!!!!!!!!!!!d%!!-!!!!!!`#"rrq"!!- !!!!!!!!!!!!!!!!!!!!!!!)"!!!!!!!!!`#AQ!!$!!!!!!!!!!!!!!!!!'PS-c) !!"1"M`#!!S-!!J)"!D!!J!+&!!)#!3'H!!J#!J-!!!%!#`Z"!!)#!3'F!!S#!J- !!!%!$"-5#S%!!J)"!B!!!`)!!!+6!!J#!J-!!!%!$4@!%J!+J3!"!J'"!!-5!"J 6N3!1!J)$!!!"!!iA&"36%K)+JJ!(!RL)!J"4q%L3!!!3!J)%!!!"!!mC&K88&"- 5%JU#!!B+!#'irrpDM`!G!`-%!!!"!"!E&aF@&438%a)5#J!$@J!&HIRrp2p`MJ! H!`-%!!!"!"%G'4NB&aB9&"36%4-1!3!pe[rjpI[rLid!(`-$"!!!!3!5(aXD'KN B&aB9&"-A%3!8RIrqq[Apq[pYM!!K!`-&!!!"!"-J("`E'KSC'"F@'"J&!'$Vrr[ mpr[lrkF!")S!)!-$"3!!!3!8)KiH(4`E'KSB'"d2!#V!rrhlr[Mlr2r0#B!!!!+ (!#!$!`8!!!%!&53J)"mH(4`E'KiD!!L&qIrlrIrjqrhrkKq,!#!%"!8!!!%!&bB L)5!J(aiF(L%-!%MFrrcmr[rlq[lpr6f!!!%A!BB!*`3%"J!!!J!B+#-M)L%J(am N'3!CU2rqqrlrrrckrr[rCJ!)!J%#!3'%!#)%"!B!!!)!'5SP*53M)L%N)`F!D[$ rqrcrr[rpqrrkri`!$)%!!J)"!B)!*!3%"J!!!J!D+bFQ*L8M*#N9!$(*rrclr[r qrrhlrr[rX`!2&!U"!!)#!3'!!#B%"!F!!!)!'bdS+#FQ*5SM!3Z2r2rlrIrqr[r qrIlmrp82#4B4%JU"!#`#!3%!"38(!!!#!"`[+LST*bSX$`"4i[rmr2rqr[rqrrl qrIra,!)C%a-5%JU"!"J#!3%&"`!!!J!G-5`X+LS`)!!IX[rpqrlrJ2i"rrq"rJV r43!9'"88%a)5#S%!&J)""`!!!J!H-bdY,$!Y#!&dp2rlr2rqK2m1r[lrqD&'"!8 6&4-6%K)+J3!'!J!!!J!I0B![#c3D!$R4rrcmrrrqri(q!IrqJ2q!rJVrf#)''43 8%a)5#S)!+`%!)$Fa-$!U"!qDrrlkr2hmqrVlqrcqrrlqrrlqrrljprp-!"X9&"3 6%K)+J!!$!J!M1)!b#$-!6HRrqIMkqS$j"[[prIlrr[q!rL(rrI[mqrpK!"d@&43 8%a)5#`!!!J!N16-c-MB!U2rhr[rqJ2m%r[rqr[q"rK,rrIVlr[rkrhF!(KF@&43 8%K-,J!!+!J!L16-c13#-rrZ!rJEpr2lrrIhrJ2i6rrlkqIhrrrhhrj)!(KJA&K8 8&3b#!#N#!#)j-MX"G[rhr2lrr[lrr[lrr[lrr[[hqrrrr[[mrp3c!"`C'"F@&`f "!"))!!!#!#)j1`CJrr[qrrR[dHlrJ2jrrrchqIlrrrhlrrCf!`FH(4XC&aN1!!% !!!)&#!!!!J!K2a-RHP8k)5-!4[Mrr[rqq2EmrrrqqrhrVa-!#`m,$aBB'`m!!3! !!`)&"3J!!!)!*5N!!!3VA33dm[rprr[fqIlrr[cmrqCA!T(ph,5&8LJI%!!"!!! $!J)!"38)!!!S!`!SLF6drfFLl[rpr[MirIrrrI[rr*%2!"YEETM'l[lrE!!(!!! $!J+!!"`&"3J!!!J!Tp@&-KAIrrcmpr[rrrllr2r+0!!#!i)!#3)P8`X#!!!2!J+ #!#!&"4)!!!3!!3!4e2rlq[Rqrrrmqrr`E3)!!`%!!!-$"!+!!!8"!!!$!J+%!"F '"J`!!!J!$XVrq2RmrrrqqrlrUKX!!`+'!!-""`!!J"H'!"3)"3!!!3@krrElr[r qr2crh8S!!31,!)!$LJ!3"3#XrrEprrrpqrrjK`S!!`',!!)#!3'(!")(!3!*!*[ rq2lrr[[prm%X!!)$M!!#!J%"LJ!2#!#*rrVrrrclrqYM!!!$!B`!!J)"!B`!$'I rq[lqqrlrRa8!!`+0!!)#!3'0!!U,rrVmr2rB2J!"!ii!!J)"!Bi!#A$rprrjH`8 !2311!!)#!3'2!!CDrrqk)J!+J!!!!B`!!J)"!C!!!!G)qe-!!P!a!S!!!!'+!)! #N3!$&"N!%)%!"!)#!!!"L!#!!T-!!`)!!!+!!)!#!J!!!B-!!J%!!)!#R!!&!J) $!!!"J3!#!3!!J!+H!!S#!J-!!!%!!!%!!)!#S!#!!S-!J!+2!)m!#`S+$J!!"!3 !!!d*#D!!$3S+$`!!!`)#!`!!$JN*RJ!2#JS3!!!&!%*#!!3!!!i*#C`!%3X,$`! !"3""E'Sq!!3!!!d*#B!!!`%!!!'6!"),#a!!!!8!3h"NBfXq!!3!!!i,J3!$$J! 6$j%!'`X,%3!!"3"&G'KSCQ0V2J!%!!!%!@0[!3"#`cq3!!!5$!`4!!!&!%ChDfY TD'CMDci!")!!"JJ!'Tc*hNb2!"d-$")!!!B!5(TZEQeVD@KQBfXp!!CC!!4JfXZ Xk&b1!"i-$"-!!!B!5RjaFA"ZE@YTD'CKEd-!!$+ak-ZEcq*hM3!I$3d5!!!'!%b "G(4cFA"ZE@YSD("B%Jq"hYV5P-24j9Z-!#%0$4-!!!B!6S9hGhCdFh&`EQYbELi !5mAKcYQKYY6JM3!$LJ!J$3d8!!!'!&#)HRYjGhCdFfpbH9!%(ClLeX[FX,,@fki 'J!!!!BF!)!d0%`!!"J"5LheqI(YjH(9cI@dI!@[9hFl1flq`eYE(')X!)!i1&3! !"J"8Mi#"IhjmHRGpId-!0VILdFr3f-fbeY(A-S!!!4!'KJ!R$Ji9!!!(!&D5Ji5 #JApmIBGQ%!k+hpM1dG$8f,I8cpp9!!S!!!m*#B3!+3i2&3!!"`"BPSD(KS5"IiL !-J"8bq$2d0,4dYr"dFlLG!-h!3-!!!d*#B)!+`m2&J!!"`"DQBQ+LBH$KijC!b1 Qip61dG,5d0r1cXrIQ3"-FMd!"!!!$JN*J!"c$`mA!!!(!&bFM)f-LBL6I#!$FpR FcY(5dG,4eGA1d0Uf#$a`B@Xq!!3!!!i*#3!2$aB!!!F!AU#2NBk,Nj*)!$fqiY( 2dY(4dY,4dY(4eXmJ+h*PCQ0V2J!%!!!0#3N3&`!!"`"JSj+8N!#5RA%2%T,Keml 4JG)#dG(5J0&ZdcN!AR0VCfCMDci!"!!!$JNB!!!)!'+QPT@6Rj%e!&c4hmr3dG$ 2cml4dY(4dY(5cB8l!KYIE'GQBfXq!!3!!!i!!!F!C+UCQCfLB3)SVH,5cG,8eYR EhH28dG,5dG,4dZ2DVaBrG'KSCQ0V2J!%J!!A"J"QVCbFRSJM"RhHhG,AfGRBepV MrZA3J0*rdG(9dm,!j6i[GfPTD'CMDci!!`!'!'k[Rk#IRa8i`p['`X'mYl'[ZX6 Uimh5dY(3e0E%YmA2i8XNH@YVD@KQBfT#!!-'!'qaS+'JT455j-R2d0$4dp6@dql RcY,4d0,BbDffcp61i&iEHQeYDfPSC'a$!!-!"J"TXU#JUb"[iFmLdY,4d0$4cHM QcG,3dGM2V+6&eY,3bqYq%(T[EQeVCh""!!1!!(m)!'QbRUmY@q$,cp(6eG[3jHI 1dY$AeE'AY0A9d-l6il%M'AK`F'jVG%-!"3!!'3!!#!"TX+mm6rAHhpM0aUR@kFl 4dpLkNCr0f0(2cYr5AJ!TFRGcF@jh43!&!!!2%4N!!!J!CVp3&9p!+aXK!%VLcp$ BcTU-[GR6d-l@i*%0#'a9H'jZFR"k4`!&!!!2#K!4'!!!#!"aK4dU1ek'$c2Ldp, CYibRe0E3cp(K[dJ&NIreeVHAHRp*!!8!!!m+#J!3%4N!!!N!EYhcr[pR)Yl9eFk IQ-ICdFr1h0Gf$3!E@fZ5[qImri!!#3!!%3S+J!!F%"%C!!!,!*r-Ic!@c0V8ZCL eep63cY6KTLX!!3+#!!N$*P%+"3!!'!X,JJ!J%"%H!!!(!!%!%F,KbDHRcYM4cmr Ib9N"!!)"!!!$!`3#J!!&!`!!$3X,K!!A%4%A!!!+!!kjiVLQ`0M6d-lBhBX@!!) #KJ!'!JJ!!"XC'BB!!3N(J!!2"DVEVEE5eY$1dZ'h23!"!SJ!"3)!!!J'"iS!%!- !QG1abYI5cmlGdfi)!!)"L!!&!J!!"J8&K`!5"J%!"`#%dVl8e0$1eH#I*!!#!SN !"3)!!!F&"BS!$JF!F0R+eG(2cq(&8!!!!SS!"3)!!!F'"S`!$&6Ncp,3cYRHJK% !!J++!!8#!!!("JD0!!Thiml1dZ5c-`!"!SX!"3)!!!F'"Si!#9cMbpl9C!3!03@ ,!!8#!!!)"JD2!!C*k1#C(!!)J!!!!iN!"3)!!!F'"T!!!!XrdN3!!83T!J)!!!1 (!!8#!!!)"`H4!!-3&!!0J3!%#!N!!!1&!!8$!!!)"`H6!!-#!!!"J!!&#!J*!!! $J`!&!`!!#!F(R!!&#!J+!!!$J3!&!`!!#3F(RJ!0#!J*!!!$!!!$!!!)"`HJ!!X )#!N!!!-#!!!)"`H2!)m!#`X,$`!!"!3!!!i+#U!!$3X,%!!!"!)#!`!!$`S+RJ! 2#`X4!!!&!%K)!!8!!!m+#T`!%3X-%3!!"3"'GR4%!!8!!!i+#TS!%J`-%J!!"3" )HQeVG83!"3!!$`Z"!!-&!!B&N3!E$!`6!!!'!%TpF("[Dh9%!!8!!!8!*#F!!"P #&T!!!")0$4)!!!B!6)"cFh*aEfYe4!!%J!!'!`!)2%&,(Bm!(3d0%`!!"J"1JhC fGA4bF@pVG8-!"5i!!5*54c"A)Bi!(Jd0&!!!"J"3KhPjH(CeG(*aEfPj4`!!%N" 96b",8bZ0!"m0$4-!!!B!8BTmI(YkH(CeG("aH&mH"5p469NF28p6)B`!)3i1&!! !"J"6MAprIRelHAKfFhTd1!!B590)AL`a89%c!!'+!#!1$K8!!!B!9C!!JS+"Ihj pHhGkJ&J1"MT86dCH2be66d!#L`!J$Ji8!!!(!&H8KB@%JS'!IAZ%FbN!*9"46%K D8Le568N*L`!J$Jm@!!!(!&QAKiL(KS5#Ii@&5`82494-6%T8BM&36%m6J!!"!`H '!#F2$aB!!!F!@jU+LiU)Ki1&MQ`E!6*66dY05djZ1da-8L!!"`!!%!S+K!!T$`m @!!!(!&fGMBk0M)Q'N!#&2!!E6&*,6%e05R4+5%e6+JSj!3-!!!i+#S)!+`m2&`! !"`"ISC!!NC!!MSU2P'%0#$j868Y06%e(E9j&69%j!&&l3J!&!!!2#JU!!%B3%"F !!!F!BD56P*13!)qDJ5X!+9&35da06%e,9'&(68p%!%*iDR9%!!8!!!m+#J!3%"F !!!F!BkH@Q*@5QTG4!a*(8da-68b!66"-88a-6Nd*-hTZEfYe4!!&!!!1#JS3'!! !#!"NUTQDPjQLGaS"09415de06Nj06%a0J%`K6K8&C(adF'pVG83!"3!!$`SC!!! )!'DZR*bDTC8q!"p28i"-58T)4dC-68a-68a05c)@!b"PGA"[Dh9%!!8!!!m!!!J !D,'IS+5SD!`*2e**4dP-89KICR455de06%e-69423!0)I("aEfYe4!!&J!!A"J" UY++MT)dX!#e@9PGHC@Y[FhH"YAK*J%er6%a36N!r9"-mIh*bF@pVG83!!`!'!(1 fTDDPT"S26&406%T&2cFb16Z&G%*068a,6e&!0%&-9"FaJ(0dFR&[Dh4)!!3(!(1 iTULQU4id9%P+58P+5de35BPm4%j05de64#Xc5Np,8aiRJA9eG(*`EA9)!!3!"J" YZDDQX#XN9%b"64j-684rHd016%a65LNM39&06%TA,"b!GhCeG("k4J!%J!"r#!" YZD5d14Y65Na-68j44APl4%e,88mZ&M&38%a,694#"Kk!HAKfFhe)!!8!!"S!!!J !EEDd5"KG8e445dXiERa&6%j60K!H5&*-5dY58#!!-RKrHhTfJ%S!"3!!%")D!!! )!'V'@!!I%3F#$`!hH%C-8NNC$$P66NY,6P-c!"*XA(phGhYiJd`!"3!!%!X4%KN !!!J!GSNL0dGSM43QH%G18c--*8p45dY-8NJE#jErppLmRB+)6J!'!!!3#`X!%4% D!!!*!((KmrlrD4Ge59&*(4G#9%a,5e"1+`8!'9PVNVrRr2q#!!N!!"),#i!!("% 5'J!!#`#Hbhda$fK18$BA-P*25dY08Md2!!!"JJ!*!bC4#J8!!"N,#i)!'4%5(`! !#!!"!!eL8dBP*8P56%Y-8NSJ!!!"J!!$!`-%!S!!"3-!!!i-$)3!&")5'!!!#3! 0AP3f*6a66NY,6e%c#)N!"J))!!!F'4U'!"3*#3%!!!C86Ldc69&,5de53aB!!!' )!!8#!!!)"`H,!!i$5%B`49&05dY465J$!!'*!!8#!!!("JD(!!m#!!!"!$P%28p 25dY18MS0M!!&!J!!"`B'LJ!1!J!X5NK36%Y-8NJG!!!"LJ!&!J!!"`B'M!!*(e* -68a,6e%["Sd!"3)!!!F'"Sd!"bY65dY08d%5MJ!&!J!!#!B'MJ!*)P0+88iN!3! A")X!"3)!!!J("im!"KY98MJ+!!1!!!!$L3!&!`!!#!F(N!!!#aG0'3!!'Jm!!`! !!iF!"3-!!!J("j%!!`B(!!@"!!3)#J!!!i8!"3-!!!J("jS!"3J)#3!!!i-!"3- !!!J("j`!"3J)#J!!!i%!"3-!!!N("ji!$3J)#J!!!`!!!`!!#3F(S!!,#!J*!!! $!`!!#3F(M`"S1'eV!!!*#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!Q*J!!`!!!!! !!!!!!!!!!!!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`##rrq#!!-!!!! !!!!!!!!!!!-"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)Arqr[rK3!$!!! !!!!!!!!"!`!5%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!K2rkr[lkri8!!`! !!!!!!!-"!%MS5!!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#%rrVqrrrqq[q&!!- !!!!#!J!EU[hr@3!$!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)6rq[lrr[lrr[VrK3! $!J-!!Qh`rr6rF!!%!!!!!!!!!!!!!!!!!!!!!!!!!!-!K2rkr[rqrrrqrrlkri8 !!J!db[rlq[VrKJ!%!!!!!!!!!!!!!!!!!!!!!!!!!`#%rrVqrrlrrrrrr[rqq[q #"j2mr[RqrrVrR!!$!!!!!!!!!!!!!!!!!!!!!!!$!)6rq[lrr[rrrrrrrrlrr[h jk[rkqrrqr[crXJ!#!!!!!!!!!!!!!!!!!!!!!!-!K2rkr[rqrrrrrrrrrrrqrrl mr[VqrrlqrrVr[!!"!!!!!!!!!!!!!!!!!!!!!`#%rrVqrrlrrrrrrrrrrrrrr[r qrIrqr[lrrI[f1!!#!!!!!!!!!!!!!!!!!!!$!)6rq[lrr[rrrrrrrrrrrrrrrrr rr[lrr[lqq2pF!!)!!!!!!!!!!!!!!!!!!!-!K2rkr[rqrrrrrrrrrrrrrrrrrrr rrrrrr[rjri-!"!!!!!!!!!!!!!!!!!!!!`#%rrVqrrlrrrrrrrrrrrrrrrrrrrr rrrrrr[crR`!$!!!!!!!!!!!!!!!!!!!$!)6rq[lrr[rrrrrrrrrrrrrrrrrrrrr rrrrrr[crK!!%!!!!!!!!!!!!!!!!!!-!K2rkr[rqrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrlpri8!!`!!!!!!!!!!!!!!!`#%rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrr rrrrrr[rqqrq&!!-!!!!!!!!!!!!$!)6rq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrlrr[VrK3!$!!!!!!!!!!-!K2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrqrrlkri8!!`!!!!!!!`#%rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrr[rqq[q&!!-!!!!$!)6rq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrlrr[VrK3!$!!-!KIrkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrqrrlkri8!!`##rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrr[rqq[q#!*Mrqrlrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrlrr[[rQ*Irqrlrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrlrr[[rQ!#"rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrr[rqq[q#!!-!K2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrqrrlkri8!!`!$!)2rq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrlrr[VrK!!$!!!!!`#$rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrr[rqq[q%!!-!!!!!!!-!Jrrkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrqrrlkri3!!`!!!!!!!!!$!)2rq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrlrr[VrK3!$!!!!!!!!!!!!!`#'rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrr rrrrrr[rqq[q)!!-!!!!!!!!!!!!!!!-!K[rpr[rrrrrrrrrrrrrrrrrrrrrrrrr rrrrqrrlkriB!!`!!!!!!!!!!!!!!!!!$!(hrrIlrrrrrrrrrrrrrrrrrrrrrrrr rrrlrr[VrKJ!$!!!!!!!!!!!!!!!!!!!&!&ArrIlqrrrrrrrrrrrrrrrrrrrrrrr rr[rqq[q'!!-!!!!!!!!!!!!!!!!!!!3!62cmr[lrrrrrrrrrrrrrrrrrrrrrrrr qrrlkriB!!`!!!!!!!!!!!!!!!!!!!J!qp[[mr[lqr[lrrrrrrrrrrrrrrrrrrrl rr[VrKJ!$!!!!!!!!!!!!!!!!!!!#!$(Zr2[rr[lqrrhqrrlrrrrrrrrrrrrrr[r qq[q'!!-!!!!!!!!!!!!!!!!!!!!#!,Vrq2rqr[lqq[lmr[rqrrrrrrrrrrrqrrl kriB!!`!!!!!!!!!!!!!!!!!!!!!#!+crr2lqrrckrqhkrIlrr[rrrrrrrrlrr[V rKJ!$!!!!!!!!!!!!!!!!!!!!!!!$!*Arq[rqqIlqR!Z$rrVqrrlrrrrrr[rqq[q '!!-!!!!!!!!!!!!!!!!!!!!!!!!%!(hrq[Vkrp%m!!)!K[rkr[rqrrrqrrlkriB !!`!!!!!!!!!!!!!!!!!!!!!!!!!$!'Arp2rcGJ3!!`)$!)Erq[lrr[lrr[VrKJ! $!!!!!!!!!!!!!!!!!!!!!!!!!!!$!%crrV)K!!)#!!!!!`#'rrVqrrrqq[q'!!- !!!!!!!!!!!!!!!!!!!!!!!!!!!!#!$[T83!"!`!!!!!!!!-!K[rkr[lkriB!!`! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!i8!!-#!!!!!!!!!!!$!)Irqr[rK`!$!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"!`!!!!!!!!!!!!!!!`#$rrq%!!-!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"!!!!!!!!!!!!!!!!!!-!QTS!!`!!!!! !!!!!!!!!!!!!!!!!!!!!!'Pd-c)!!'#4!!!!!,F!J!-&!!!"!3!!J!2`!)!$"`! !!3!!!3!!J!2Z!)!$!J!!!B%!!J%!!)!$l!#!"!)!!!'$!!)"!!#!!qS!J!3#!!! "K3!#!3!!J!2S!!8%"!8!!!'"!!%*#B%!!J%!!)!$jJ!&"!3&!!!#J3!$#4)5#B% !!J%!!)!$j!!&"!3&!!!#J3!-4%")*J3!#!3!!J!2L!!8%"!8!!!+"!!F+%a% 5%4!5#B%!!J%!!)!$i!#!"3)!!!+"!!N+&")5%4)4%")*J3!#!3!!J!2H!)!&!J! !!S%!#`S9%a)6%K%5%4!5#B%!!J%!!)!$P`!"!J(!!!8&"3B!!!+"!!d,&4-8%a) 6%K%5%4!5#B%!!J%!!)!$P!!"!3,"!!8&"3B!!!+"!!m,&K38%a36%K-5%4)4%") *J3!#!3!!J!15!!B$!3"F-J!"[!!&"38'!!!#J3!4#aF8&"88%a36%K-5%4)4%") *J3!#!3!!J!12!!J#!J!GV[p5!!1l!!8&"3B!!!+"!!%-&i!9$K39&"-8%a)6%K% 5%4!5#B%!!J%!!)!$M!!+!3-!!R2er2pZ!!1k!!8&"3B!!!+"!!--'"B@J"81&"8 8%a36%K-5%4)4%")*J3!#!3!!J!1+!!X$!J!idIripIq'!!5j!!8&"3B!!!+"!!% -'B%@J"81&"88%a36%K-5%4)4%")*J3!#!3!!J!1(!!d#!`!2QIrrprMmrjX!!lJ !"38&"J!!!S%!!3dCJ4F"&KD!&3i8&436&"-5%a)4%K%3%JQ"!!8"!!!$!`'&!!i $!!"CkIrmqIEqqrqh!!+h!!8&"3F!!!+"!!30'KJA')!A!4B@J"81&"88%a36%K- 5%4)4%")*J3!%!3!!!`'$!"!#!J!N[2rpr2her2rmrmJ!!EB!"38&"`!!!S%!!`i E'"Q!')!A!4B@J"81&"88%a36%K-5%4)4%")*J3!!!B3!%!%$!!9qq2rlrIleq2r qrIrFY`!&"38(!!!#J3!&$KXC'4JCJ"L!&`%@&S!9$K39&"-8%a)6%K%5%4!5#B% !!J%!!i!!&!-"!%$Crrcmr[lhpIlrr[hrlJm!!E-!"38&"`!!!S%!"`iF'KND'4J CJ"L!&`%@&S!9$K39&"-8%a)6%K%5%4!5#B%!'3%!!!)$!"@Mrrllr[rrqI2lrrl rr[ri'!!"XJ#!"`)!!!+"!!N2(4SE'KND'4JCJ"L!&`%@&S!9$K39&"-8%a)6%K% 5%4!5#B%!'!%$!!"Ml[rlr2rqrrVcq2rqr[rqr[mZ!!+a!)!(!J!!!S%!#`mG'aX D'aSC'KNB'B!BJ"F"&KD!&5S8&436&"-5%a)4%K%3%`J!!!-#!#[&rrclr[rqrr[ dpIhrr[rrr[cr3`!#X!!&"`F)!!!$J3!0$amF'a`E'KXD'4SC'"Q!')!A!4B@J"8 T&"88%a36%K-5%4)5#`)"!`!*J[Rrqrhrr[lrr2Adq[rqrrrqrrVr8J!$V`!&"`F )!!!$J3!2%"mF(4`E("XD'aSC'KNB'B!BJ"F"&KD!&438&436&"-5%a-2"3!#!3" 'fIrmr2q!rJ6rrIEcpi$q"[rqrrcrd!Z`!!8("`J!!!1"!"%3)"dG("dF'a`E'KX D'4SC'"Q!')!A!4B@J"8Q&"88%a-8%`S!!3)!'UErr[[qrrlrr[rqpr2frIrqrrl rrIrV)3!"VJ!&"`F)!!!$J3!6%#%G(4iG("dF'a`E'KXD'4SC'"Q!')!A!4B@J"@ !&#%9$`-!!`!"DHlrqrcrr[lrr[rqqI6frIrqrrlrr[hp3J!$VJ!&"`F*!!!$J3! "%5'!(S!G$4`G("XF'aSE'KND'4JCJ"L!&`%@&S!9%"B6"`!#!J!ba[rmqrlrr[r rJ2i'q[6erIrqri$q"2[rD3!%VJ!&"`F*!!!$J3!'%5)I(KmH(S!G$4`G("XF'aS E'KND'4JCJ"L!&a!@&4B@$3%!!`!0M[VrqrhrrS$r%Ilqrr[dpIcrr[rqr[rkrj- !!ki!"3F(#3!!!i%!!4)MJKm"(Kk!(3dF(4`E("XD'aSC'KNB'B!B%4F@&aJ5"3! $!3"3i2rmr2rqrS$rJ2i1r2Adr2rqrrrqrr[rZ3!"VJ!&"`F*!!!$J3!"%L1"))! I!4iHJ"dI("dF'a`E'KXD'4SC'"NB&aFC&JX!!3)!),$rrI[qrrk"ri$q$rhfp2c rr[rrr[rmrpX4!!'Y!!8("`N!!!1"!!35*#%J)B!JJ"m"(Kk!(4dF(4`E("XD'aS C'KNB'"NC%3-!!`!%Fr2rqrcrr[k"ri(q$[Idqrrqrrrqrrhrmb`!!Ud!"3F(#3! !!i%!!4-PJ#%")#'!))!I!4iHJ"d)("dF'a`E'KXDJ"N1'KB)!!)#!$V1rrclr[r qJ[q"rJljp2[rr[rrr[rqr2p3!!1Y!!8)#!N!!!1"!!J6*5)L)5)K)#'!))!I!4i HJ"d&("dF'a`EJ"S1'aS1!3%$!"'Br[llrIrqJrq"rJlkp2Vrr[lrrrlrq[pi!!5 Y!!8)#!N!!!1"!!S6*L-L)b)K)L%J)B!JJ"m"(Kk!(48F(4`E("SE(48&!!-!!&V QrrcmrrlqK2q!rJllp2Vrr[lrrrlrq[qH!!1Y!!8)#!S!!!1"!!`8*b-N)b)M)L% L)5!KJ##!(`%H(S!G%K`G("XG'JX!!3)!*VRrrI[qrrk&ra$qrrlmpIRrr[lrrrl rqrr!"Di!"3J)#J!!!i%!$K3R*#3M*#-L)b)K)L%J)B!JJ"m8(KiG(KdF(4d5!`! $!!Gqp[rlrIrqK[m9r[rqrIEirrlqrrrqrrcrhKN!!3!"!i!"TJ!&#!J+!!!$J3! 3&#JN*#8N)b3M)L-L)5)K)#'!))!I%KiH(4dI'3J!!J%!3YErr2[qrrk'raIqrrl pprMrr[lrrrlrrIrf0J!$!!!"!!#!!k3!"3J)#J!!!i%!!48SJ#80*#8N)b3M)L- L)5)K)#'!)")I(aiH(ai3!3%$!"HLrrllrIrqKrm+r[rqrIMhrrlqrrq!rJ6mreX !")%!!J%!!)!$SJ!J+!!!$J3!8&5NQ*L8Q*53P*#-N)b)M)L%L)5!KJ#!3(am K&`8!!`!!C1[rqrcrr[k(r`AqrrlqqIH!rS$r#2lrq[q#!!3!")%!!J%!!)!$S!! N,!!!$J3!R&5SQ*LFQ*5BP*#8N)b3M)L-L)5)K)#%J(b)G$!!#!J!Z`[rmqrl rrSMr#2lrr[lkprlrrS$r#[lrq[qT!!)!"K)*J3!#!3!!J!1H!!8*#3X!!!1"!!% @+S!RJ#BH*5BP*#8N)b3M)L-L)5)K)#)L&!)!!`!,L2RrqrhrrSRrJIi%qrIqrrk !r`cqrr[rc!X!!!34%4)*J3!#!3!!J!1F!!8*#3X!!!5"!!B@+bJR+#FRJ#BF*5B P*#8N)b3M)L-L)5)N'`J!!J%!60hrr2crrrk+r`Iqrrlmq2hrrS$r$[lrrIrS*!! #!4!5%4!5#B%!!J%!!)!$QJ!N,!!!%J3!"&Lb#+!%R*i!Q'58Q*53P*#-N)b) L*#%3!!%$!"fVrrllr[rqLrm(r[rqr2Rprrk!ra$qrrlpqd-!!`!1%a%5%4!5#B% !!J%!!)!$Q!!N,!!!%J3!"&bf"+B!S!5FRJ#BA*5BP*#8N)b-N*4N&!!-!!fr `rr[mrrlqM2m'r[rpq[hrrS(r%IlqqrpT!!3!$"35%K%5%4!5#B%!!J%!!)!$PJ! N,!!!%J3!%&biU+5U!+B!S!5FRJ#B#*5BPJ#31*L%-!!)#!$E+rrclr[rqMIm 'r[rqq[crrS(r%rlrq[q4!!3!#486%K-5%4)4%")*J3!#!3!!J!18!!8+#J`!!!5 "!!%A,S!U!5NUJ#Q!+!%R*i!Q%58P*#BQ&3)!!`!2NrcrqrhrrSrr"Ilrr2crrS( r&Ilrqrqh!3%!"K86&"-5%a)4%K%3%JQ"!!)"!!#!!j)!"3S+$!!!")%!#"J[+bX U+bST+S!TJ#J8*bFQ*L8Q+"i)!!)!!&EMrrcmrrlqMrm&r[rprIrqJImAr[rmrpF 6!!%$&"88%a36%K-5%4)4%")*J3!#!3!!J!13!!!&#JS-!!!%J3!+'$!V+b`V+LX U+5U!+43S+#FS*LBT*4%!!3)!)lArrI[qrrk3!2m&r[rqrIrqJImCr[rprr!Z!!) "%aB8&436&"-5%a)4%K%3%JQ"!!)"!!#!!ii!"3S+$!!!")%!!4J`J#`(+b`V+LX U+5U!+4)S*bFT+4S%!!-!"RRerr[prrlqNIm&r[rqr[rqJ2mEr[rqr2p4!!-!%"F 9&439&"-8%a)6%K%5%4!5#B%!!J%!!)!$M!!&#JS-!!!%J3!K'6%Y,5`Y,#XX+bS V+LNU+5NS+#SM$!!#!J!rd[rmqrlrrTEr!2k$r`Mqr2pi!!3!$aQ"&3i8&436&"- 5%a)4%K%3%JQ"!!)"!!#!!iS!"3S+$!!!")%!$KNb,5dZ,5`Y,#XX+bSV+S!T$LX T&J%!!`!8RIrqqrhrrTIr!IlqJ[mGr[crP3!'!3!,%aFA&K89&"88%a36%K-5%4) 4%")*J3!#!3!!J!1)!!8,#Jd!!!5"!!%D-S!Z'bdZ,5`Y,#XX+bSV+5SX)!F!!`! !B1Rrr2crr[kIralqrrG!!!%!!J%!"Jm9&aB9&"88%a36%K-5%4)4%")*J3!#!3! !J!1'!!8,#Jd!!!5"!!-D-bm[J#iB,5iY,#dX+b`V+LdS%3!"!J!V[[rpqrlrrU, r"IlqrmYV&S!!&3)!!JN5&K88&436&"-5%a)4%K%3%JQ"!!)"!!#!!i3!"3X+$3! !")%!"4Sd,bm`,i!Z&5dZ,5`Y,#XY,4X%!!-!#B6irr[prrk-ri2qM[m"r[q!rJ6 rm+0"")%!%J3@&488&436&"-5%a)4%K%3%JQ"!!)"!!#!!i)!"3X+$3!!"B%!!4X dJ$#!,i!Z%bdZ,5`Y,b8-!!)"!%MDrrcmr[rqKrq%rT6r)2lrr[clr[lreANE!!! $&4B9&439&"-8%a)6%K%5%4!5#B%!!J%!!)!$J!!&#`S0!!!&J3!%'c8a-$'!-!% [,i!Z%#dY,b`@!3%$!"URrrllr[rqJ[q%rS2rJIi$rIlrrSrr$IlqrrhlrIhrd33 !!K8@J"81&"88%a36%K-5%4)4%")*J3!#!3!!J!-'!!X+$3!!"B%!!4XfJM'!-"% [,biZ,c!L"`!$!!&Ul[rlr2q&rS,rK2k"r36mrIlrrT!!ri$q#[rlp2[Z%J!"&"F @J"81&"88%a36%K-5%4)4%")*J3!#!3!!J!-%$!i!!!@"!!8E0M)b-6+!-B!`$bm Z-LX3!!)#!$2(rrclr[q#rJ$rKrk"rB$m"IhmrIlrrSrrJ2i0rrhiqIhrp4i!!4) A&KD!&3i8&436&"-5%a)4%K%3%JQ"!!J"!!!$!`i!!!@"!!FF0c)b-c)a-S!a%6! [-6%F!`!$!!f1qrrlrIrqrS$r!IlrJIi2rIhmqrckqIVhprRiq[hmrB$qM[q!rJh rr[RhrIrqrImh!!%4')!@J"81&"88%a36%K-5%4)4%")*J3!'!3!!!`!!"B%!!4` iJ$-P-M-b-6)a-6!a+3X!!3%!8Z$rr2crr[rqr[hmr2Vjq[Ifpr6epI1!p!IhqIc qrrhmrB$qM[m(r[lrr[Vfqrq!rJVmrd8!!3mC&KF@&S!9$K39&"-8%a)6%K%5%4! 5#B%!!!'!!!!&J3!J($Jd0$-d-c)c-M%b-6!d(!!#!"q[rrhiqI[iprMep[EdJ2@ "pS$h#[Mkr2lrr[rqrIcpJ2k0ri$q%2rlp[MqrrlqrrllreN!!3dCJ"F"&KD!&3i 8&436&"-5%a)4%K%3%JQ"!!)"!!@"!"NI163d063c0$-b-c)a-M%c)3!!,I$rq2R mqi(mJ2f#rSIrJ2i#rIcpJ2k-ri$q"rrmp[ImrrlqJ2m(r[VrH3!##aQ"&`%@&S! 9$K39&"-8%a)6%K%5%4!5#B%!!3%&J3!9(cNe063e0$-d-c)c-M%a0#8"!$VrqS$ qLrq(rJ2rrIcpJ2k,ri$q"IrpprAkri$qJ[m)q[q(!!)*'KFBJ"F"&KD!&3d8&43 6&"-5%a)4%K%5#B%!!J%!"B%!&4dj068d063c0$-b-c)a-bN"!"lerrf6rJErr[l rrIcpJ2k+ri$q#2rqq26ir[rqrS6r"[[rS!!""aU!')!A!4B@J"8,&"88%a36%K- 5%4-*J3!!!B!!!!@"!"3G168e0$8d-c3c-M-b-bd$!",[rrf8r`IqrrlmrIlrrSR rJ2i'rrlkp2Emri$qKIm'qrqp!!%&'B%BJ"F"&KD!&3N8&436&"-5%K-*J3!'!3! !$`!!"B%!%adj068d063c0$-b-M-["3!(hIrpNrm(r[rqr2hqrrk*r`[qr[rqqrA dq[lrr[k(r`ImrmF!!!3C'B%BJ"F"&KD!&3F8&436&"-8#S%!#!%!!!--$`!!"B% !%Kdj068d063c0$-b-c))!!$(rrb5r`IqrrlmrIlrrSMrJ2i)rrcfmrIprrlqKrm ,r[rprq!*!!)B'KJCJ"L!&`%@&S!9"439&"-9#S%!#J)!!!3$$!`2!!!&J3!4(6N e063e0$-d-c)d$!!!ZrrlNIm(r[rqr2hqrrk(ri$q"[rmpr2eqrq!rSEr$[lqrrc lrq!,!!)@'KNB'B!BJ"F"&KD!&3-8&"8,J3!-!J!!"!-$!!`-$`!!"B%!%"dj068 d063c0$-e$`!!R[rlN!$r"rlrr[cpr[rqK[q!rJRrrIMdp2RqrrlqKrm3r[rqqrl rUa`!!3!9'aNC'"Q!')!A"KB@&488&JZ"!!8#!!!&!`1!!!8-$!m!!!@"!!mG168 e0$8d-c-f&!!!KrrkM2q"rJErr[cpr[rqKIq!rJIrr[RdmrEmri$qK[m6r[rrr2c rh8X!!3!!"4JE'4SC'"Q!')!A""B@&4F,J3!&!J!!"33%JJ!&$!`2!!!&J3!2(6N e063e0$-h'!!!GrrkrS$rJ[i2rIhmqr[kqr[prrlprIlrrS6rJ2i+rrlkpI2dq[l rr[k(raAqrrhlrrQ)#`!$!!%2'aXD'KND'4JCJ"J&&aF@&KF-J3!&!J!!"33%K!! &$!`2!!!&J3!A(6Ne063e-cFG!!"BrrVmqr[kq[[mr[rqJ[m)r[rpqrhpr[rqK2m -r[lrr[[fp26hrIrqrSIr'2lrr[[prm)Z!!)#!!NC(4`E'KXD'4SC'"Q!'!-A&KJ -J3!&!J!!"33%KJ!&$!`2!!!&J3!0(6Ne063d0b%!!%Arr2k"ra(qrrlflYV'ZCZ 'Gdj5krrprrk%r`Mqr[rmp[6dpIZ"rSEr)2lqrrclrqYN!!!$!!-8(KdE'a`E'KX D'4SC'"NB&aFC$)%!"3)!!!8%")J!"3`-$`!!"B%!&Kdj068d0bB!!$,dfmHlRSK h@%Bd(4)&JJ!&",2rr2rqJrm%r[lrr[L!p!6irIrqrSIr)2lrr[[qrk%A!!B%!Jm H)"`F(4`E("XD'aSC'KNB'4JC$B%!"3)!!!8%")S!"3`-$`!!"B%!#Kdj063h+J! !!a%'L!!*!3)&"!1drrcrrS2r#Ilqrrcfp26fqrq!rSEr)IlrrrcmrpP#!!-#!!! ,'4XH)#!I(KdF("XD'aSC'KNB'Jf"!!8#!!!&"!5-!!8-$!m!!!@"!!8G168f,J+ %!"!"!3)$!J!!"3!"!J#KrrVrrS,r"2lqrrljJ23%qIlrr[k'rb,qr[rpqrrjL3X !"!!@IS*J3b`D%!d3&4XH(aiF'aXD'4NE$B%!"3)!!!B&"Bi!"3`-$`!!"B%!'ad j0M%$!!!$"3S1%a36%4-D-%d2!!-!Q2rkrrk#r`Rqr[rmp[6dprcrJ2k'rb,qrrl lrIr$,`!"!!"AjIrprrcXdDq)B6dK%3`2&K`H(4SE$S%!"3)!!!B&"C!!!!8-$!m !!!@"!"NG1M3Q+#ib-5dS+$00FT[%mem!"3#*rrVqrS(r$2lqrrljp22eq[lrr[k 'rb2qr[rmr2rUC!!!"!!jbrrpr[hkqrlrr[lrqZ#kM&`c'!X,'`k"!!8#!!!'"3@ 5!!8-$!m!!!@"!"8G16Fe,#Ja6RQUerIrr2pf!!B!HIrkJ2k!r`[qr[rmp[2dq2l rr[k(rb2qrrhlrrf@%J!#!`!+G+HacHMkrrlrr[rpq[crr[lrpFqFEK5"!!8#!!! '"3@8!!8-$!m!!!@"!#)G16jVSYEirrlrr2MrIJ!(!'Mrqrlrr[rrr[lrr[VdmrE mri$qK[m+r[rqqrcrc6N!!31&!"X-*%*QMVEEprrqr[rpqIhmrjB!!3!""!!!"J8 &PJ!X$!`2!!!&!!!#!&Imrrlrr2Vqr[crN!!!"`"5rrcqrrlrrrlqrrhhmrAkr[r qrSEr#rlqrrclrr*b!`!$!B)!!J-$!S3!&!3H4A5ReIMrr2q)!!%!!KF!!"B&"CJ !(3`-$`B,$J-!!3#2rrcqr[rZ[S9(!`8!3IIqrIrqri(q"rVdp2MprrlqKrm+r[r qqrlrVKi!!J+)!!%"!B!$!!+#!!i#)%f8I3!#!!)B!!!K"3@D!!m-$#N!!"S#!!% !L[r&K885J!!4"3!dl[rprrlrr[lrrIIcp[crJ2k'r`Vqr[rmr2rI6`!"!j%!!`% $"!1#!!J#!!!6!!![)KqF!!S-$#N!!"S#!!!''i%!#!%$"J!Sjrrmri(q#2rkp26 kr[rqrSIr#[lrrI[rqS`-!!-#P`!!!B!$"`!!!3!0)#m`RJ!9063q!!!,!!!#!!% %!`%!!J!Fh2rmri$q"[rppr2hrIq!rSEr#[lrr[[mrm8a!!)$RJ!&!3!0)#m`S!! )0M3P$3!#!!!"J3!'!J!5crrlri$q"Irkp2Alri$qK[m,r[lrr2[rl@J!!!-"RJ! &!3!!"33&SJ!&06)N#J!#JJ!4!3!,`rrlrrlqrrlhp2RqrrlqKrm+r[rqqrlrT4N !!J+I!!8"!!!%!`1N!!8&"3B!!!+!!!i"!31errVrr[lrqr6frIq!rSEr#[lrr[c mrpK'!!%$S!!&!3!!"!-$TJ!8"38(!!!#!!!#!+6rq[rqrrlhp2VrJ2k(r`Vqrrh lrrH"#!!$!D!!"3%!!!3$!ki!$J-!PIrkr[lrqrAhr[rqrSIr#[lrr[[prl`T!!) $S3!&!3!!"!-$VJ!,"!#'rrVqrrlhpIcrJ2k'r`[qr[rmr2rSAJ!!!`'K!!8"!!! %!`1Z!!d%!(VrqrlrqrAjr[rqrSIr#[lrrI[qrTX6!!-#SJ!&!3!!"!-$VJ!-"!" Trr[qr[IfrIrqrSIr#[lrr[[mrp%p!!%$S`!&!3!!"!-$VJ!*"!"CrrcqqrEkri$ qK[m,r[lrrI[rp(F&!!-"S`!&!3!!"!-$VJ!,"!"*rIlmqIRqrrlqKrm+r[rqqrh rXb%!!J+N!!)"!!#!"+i!#!-!1[Irq[Rpri$qK[m+r[lrr2criP3!!!1P!!)"!!# !"+i!#J-!,Zrrq2[qrrlqKrm+r[rpqrrmN3i!!`+P!!)"!!#!"+i!#3)!)HErq2l rr[k(r`Vqrrllr2r*0!!#!kB!!J%!!)!%VJ!'!J!@frrkri$qK[m,r[lrr2[rm'd #!!-"TJ!#!3!!J!5Z!!J"!!h0rr[rr[k(r`Vqrrllr[qU(!!#!UF!!J%!!)!%X!! &"VlrqrrqKrm+r[lrr2[rh%S!!31S!!)"!!#!"+m!"J-!82rkrrk(r`VqrrhlrrZ (#J!$!DJ!!J%!!)!%X!!&!J"$rrcqK[m+r[rqqrcrb5i!!J1T!!)"!!#!",%!"3) !,[rqrS6r#rlqrrclrr"S!!!$!DN!!J)!!)!%XJ!&!3!Bq2rqJrm0r[rqqrlrU"F !!J)!!!+R!!8#!!!&"!5c!!8"!!lYrrf"r`Vqrrrmr2rF4!!"!i!!!J3!!U8!"3) !!!8%",F!!Y[rrB$r$IlrrI[rqB-(!!-"!!!#J3!!!U-!"3)!!!8%",B!%!%!b2r mrrlrr[[prm!R!!)#J`!%!JB!!!+K!!8#!!!&"!5h!!i#!,Erqrlrr2[rkei!!!1 &!!8#"3B!!!+I!!8#!!!&"!5i!!d$!*[rqrhlr[qH%3!$!SF!"38&"J!!!Td!"3) !!!8%",N!#`3!KIrhr2r91`!#!iS!"38&"J!!!TX!"3)!!!8%",S!#J-!E[rmpRJ %!!-"M!!&"38'!!!#Q3!&!J!!"33%Z`!)!`"4rl3J!!)#M`!&"38'!!!#P`!&!J! !"33%[!!'!3!cB!!!!j)!"38&"J!!!T8!"3)!!!8%"-%!!3)"P!!&"38'!!!#N`! &!J!!"33%`!!"!31A!!8&"3B!!!+4!!8#!!!&"!6H!!8&"3B!!!+2!!8#!!!'"!6 J!!8&"3B!!!+0!!8#!!!'"!6L!!8&"3B!!!+,!!8#!!!'"3AN!!8&"3B!!!+*!!8 #!!!'"3AQ!!8&"3B!!!+(!!8#!!!'"3AS!!8&"3B!!!+&!!8#!!!'"3AU!!8&"3B !!!+$!!8#!!!'"3AX!!8&"3B!!!+"!!8#!!!'"3AZ!!d&"3B!!!)!!!)!!!B&"I! !#`8&"J!!!J)!!!B&"EF!Y`!,&43C!!!)#!!!'"38m!!0&48C!!!*!!!*!!!B&"6 Z!!89&4N!!!Q"!!8*!!!B&"6X!!89&4S!!!Q$!!8*!!!B&"6U!!8@&KS!!!Q&!!8 *!!!B&"6S!"8@&KS!!!N!!!%!1$N!!3!!#3!!'"38jJ!A&KBE!!!+!!!"!$CTD68 !!3!!#3!!'"38j!!C&aFE!!!+!!!"!$CVBQ&T03!"!!!*!!!B&"6L!"XA&a`!!!S !!!%!0faMC'0KD68!!3!!#3!!'"38i!!G&aFF!!!+!!!"!$GYC'9NC'0KD68!!3! !#3!!'"38hJ!I&aFF!!!+!3!"!$K[C@CQC@4NBf&T03!"!!!*!!!B&"5A!!!#`3! ,'"FF!!!+!3!"!$P`J'F5CQCPC'4MB@Ne!!%!!!N!!"J8&*3!!3%#`3!,'"FF!!! +!3!"!$PaJ'J8CfGQCQ9NC'0KD68!!3!!#3!!'"38NJ!'!J!!5#F!!E`!#aJA(3! !#J%!!3!kFi"T&QKSCfGQCQ9NC'0KD68!!3!!#3!!'"38M`!)!J)!'SVC53!#Z`! ,'4JG!!!+!3!"!$YdJ@SAD@KSCfGQCQ9NC'0KD68!!3!!#3!!'"38M!!+!3)!!Pl 3ZpTF!!1k!#NC'4d!!!S"!!%!1h9VE'YVDQTTD'KRCfCQC@4NBf&T03!"!!!*!!! B&"5+!!X#!3!ZUqLZYZ9Z!!1j!#XC'4i!!!X"!!%!2(CXE@eXDfYUDQPSD'GRCQC PC'4MB@Ne!!%!!!N!!"J8&)F!$3%#!!apeq+cSpAGJ!!#Z!!Y'4NH!!!,!3!"!$e iE@jZE@eXDfYUDQPSD'GRCQCPC'4MB@Ne!!%!!!N!!"J8$)8!$J)!!%M#hYA&MY$ 3hCB!!VF!#aNC(`!!#`%!!3!pHB"[(fjZE@eXDfYUDQPSD'GRCQCPC'4MB@Ne!!% !!!N!!"F(J`!3!J)!(CVIeFr@KlRAcYZP!!'f!!XC'4m!!!X"!!%!2RU!F#"[Efj ZE@eXDfYUDQPSD'GRCQCPC'4MB@Ne!!%!!!N!!!1"!"!"!J!%CY,GcXrHNTRCd0$ BYEF!#aNC(`!!#`%!!3!qHi&a)("`EfjZE@eXDfYUDQPSD'GRCQCPC'4MB@Ne!!% !!!N!%i!!%J)"!$@ciG,2cZ#PIXr6dG(9a!be!#XD'Km!!!X"!!%!2hebFh*bFA& `F'pZEQeYE'YVDQTTD'KRCfCQC@4NBf&T0B!!'J%)!!!"!J!4KG[CcY,1hlTbYpI 3dY(6c43!!E)!,4SD(`!!#`%!!3"!IR0dG(0bFR&aF("[EQjYE@aVDfTUD@KSCfG QCQ9NC'0KD65"!!m"!J!!8FIIcmr5cYh,G*R@JY%$eLB!!E%!5aSD)!!!#`%!!3" !Ih4eGA4dFh*bFA&`F'pZEQeYE'YVDQTTD'KRCfCQC@4NBQ"`-3!"!J)!)k,JeFl 4dXrBfB#!bG64dY,4cpXh!!+`!!XE'L!!!!`"!!%!3B#!GMeeGA4dFh*bFA&`F'p ZEQeYE'YVDQTTD'KRCfCQC@0RD%!1!!-!"fV8h-l3dY,3e150G+rAd0,4dG,0idB !!Um!#aXE)3!!$!%!!3"#JS"h-hCfGA9dG(0bFR&aF("[EQjYE@aVDfTUD@KSCfG PCQaA(3!"!3!kXq(5cp,4dY(3kTeaP01"d365cYZ[#,!!64XE)3!!$!%!!3"#JhK jH(KhGhCeGA4dFh*bFA&`F'pZEQeYE'YVDQTTD@GQE'Be"!!#!"L-fpR1dG,4dY, 0lDjaLmV8dG,4dY$@aaX!!Di!64XE)3!!$!%!!3"$K(PkHRPiH(GhGR9eG(4cFR* aFA"`EfjZE@eXDfYUDQGUEdi5!!)!!PV*hmr2dY(5dG,-km&bKmM9d0,4dY(4ecB !!Ui!44`F)J!!$!%!!3"%KATlHhTjHAKiGhGfGA9dG(0bFR&aF("[EQjYE@aVDQP aBLJ!!!)!,+EJe-l4dY(5dG2-jp4fK-A@d0+!d362heF!!ki!64`F)J!!$!%!!3" %KhYmI(YlHRPjH(KhGhCeGA4dFh*bFA&`F'pZEQeXDR"[3JN!!J!-H0EEcY$5dG, 5dG20iH4pIm,@d0,4dG,0iAS!!ki!64`F)J!!$!%!!3"&L(apIAamHhYkHAPiH(G hGR9eG(4cFR*aFA"[EfjXER9D'`!"!3"'[H(4cp,4dG,5dG,1f[#*HVrAd0,4dG, 1hT`!!Di!#adF)`!!$3%!!3"'LB&q*hemI(YlHRPjH(KhGhCeGA4dFh*bFA&`Efe eE$3#!!)!(C6Heml4dY'!dK24dY$8q*Pe[0I3dY(4dXrCZ3d!!Dd!0adF)`!!$3% !!3"'LRq!IhpqIRemI(YlHRPjH(KhGhCeGA4dFh*bF@pcGNm3!!)!"@,1hXr3dY( 4J0)6dG,4d2UXFVRAd0,4dG,3e-iM!!+Y!$BG(#-!!!d"!!%!4ib!JB'!IhpqIRe mI(YlHRPjH(KhGhCeGA4dFh&aH@BQ!!%"!$1YiG21dY,4JG)6dG,5cIM"F,ABd0, 5dG,4d0Y"!!1Y!$8G(5-!!!d"!!%!5)f"JS+"JB"rIhjqIAamHhYkHAPiH(GhGR9 eG(*iG8)(!!)!%B$CfXl4dY'#dK24dY,-mp9bVpM3dG,4dG,1i@3!!kd!04dG)`! !$3%!!3")MS+$Ji+#JB'!IhpqIRemI(YlHRPjH(KhGhCcGReF'3!#!!"1`Z$3cp, 4dB25%Y(5c1cRHDRBd0(5dG(5cZ#%!!+Y!!XG(53!!!d"!!%!5Bq!K#@$Ji+#JB' !IhpqIRemI(YlHRPjH(KfGAea-`%!!J!MR0r@cY(5dB65%G(5cHAdK+,Cd0(5dG( 5cYkK!i!!!!1U!!XG(53!!!d"!!%!5C'"K51%Ji1#JS'"J(prIRjpI(alHhTkHAC lI9!1!!)!#'[4hFl3dY'&dKR4dXlHrC1DfG(4dY(4dXrB["3!!3%,%`J+#kB!-am H*3!!$3%!!3"+NSD(KSD&KB5$Ji+#JB'!IhpqIRemI(YlH(U#D53!!3%!1V6KdXr 5dY'&dK[4dXrBrkD8f0(4dY(4dY$6dLi!!`!!#3!!&a38T!!b(aiP!!!0!3!"!%Z 6KiL)KiD'KB@%Ji1#JS'"J(prIRjpI(YjJAY""3!#!"D)fpR1dG,4KY)6dG,3e2q jN!$AdY(5dG,5dFrG6J!%J3!!!'"38SJ!b(aiP!!!0!3!#!%Z9L)Q*L)L(KSD &KB5$Ji+#JB'!IhpqIAYrK&iA!!)!!9E(hmr2dY(4KY)@dG,4dIl0Mp66dG,4dY( 5cZ&`!!-!'J+!!!8*!!!B&"5J!$%I(bB!!!i"!!)!6*D*LSU*LBL)KiD'KB@%Ji1 #JS'"J(ppIBCe-3!!!J!TSq$9cY(5dBI5)G(5dFrjhj,3e0(5dG,4dXhJNJ!$!#0 V03!"!!!*!!!B&"5H!$!I(bB!!!i"!!)!6CH+LiZ+LSQ*L)L(KSD&KB5$Ji+#JB" qK)43#`!#!!YdeGc1d0,4Lp)Jcr,ZQX[9d0,4dY(5cYZ`#`!!&Q0MD68!!3!!#3! !'"38R!!,(amQ!!!1!3!#!%fBJB`JLiU+LBQ)L)H'KS@&K)1$JS##LQ`K!!%"!%+ kiG(2dY(4LG)NdG,1krQQaYE3dY(5dG,2eXFI!!!,@fGLB@Ne!!%!!!N!!"J8&*S !,amI*J!!$J%!!J"1QBf1MBf-M)Z+LSQ*L)L(KSD&KB5#JBU!3!3!!J!ENGhAcY( 5dBV5*Y(5cpVqYF(Ad0,4dY(5dG,A1`!$!P"VBf4MB@Ne!!%!!!N!!"J8&*J!,b! J*`!!$J%!!J"2Qik2Mik0MBb-LiU+LBQ)L)H'KS@#KiaI&!!#!!4Ic0l2d0,4dBh 5*FrfbElAd0,4dY,4dFrI@`!%!%&ZBf9NC'0KD68!!3!!#3!!'"38PJ!Z)#!R!!! 1!3!#!%qFMj!!N!#2Mik0MBb-LiU+LBQ)KiH&KBpj,`!"!J!`UZ(8cY,5dBc5+G( 5cZAD[YI3dY(5dY(5cH&p!!3!-@jPCQ9PC'4MB@Ne!!%!!!N!!"J8&*3!,5!J*`! !$J%!!J"3RC!!NC'3!*!!Miq1MBf-M)Z+LSQ*Ki@0LNm*!!)!$hhBfml4dY'2dLR 3eZ$%e0(5dG,5dG,1hTi#!J!LE@KRCfCQC@4NBf&T03!"!!!*!!!B&"55!#dK)5J !!!i"!!)!8*k4NT+4NC!!N!#2Mik0MBb-LiZ+KiU5EKm!!J!!5m$Jd-r5dG'3!0) &dGR0dY,4J0)KdG,2fEN5!!!6CfYSD'GRCQCPC'4MB@Ne!!%!!!N!!"J8&*!!!!` K)5J!!!i"!!)!8D#5J*-FNT+4N!#3!)q2MSf0M)b+LC1&23)!!J!KQGr@cY(5dC( 5"G(5dY(5dB$5)p(5d061+3!"#&eZD'PSD'GRCQCPC'4MB@Ne!!%!!!N!!"J8&)i !+b%K+!!!$J%!!J"5SC59P*56Nj+5NC!!N!#2Mik0M)U3!*0I%3!#!!CSd0h1d0, 4NY)&dG,4dG,4J0)PdG,4d0Y(!!-!6h*TDQTTD'KRCfCQC@4NBf&T03!"!!!*!!! B&"5-!#XK)5N!!!m"!!)!8U+9PTD9P*56Nj+5NC!!N!#2Mib0Ph`X!!%"!$LaiG, 1dY,4P0)$dG,5dB,5#G(3ifJ!!`"(H@Q"DKGTD'KRCfCQC@4NBf&T03!"!!!*!!! B&"5+!#SL)5N!!!m"!!)!8k5@PjH@PT@8P*16NT+4N!#2MCD3!%d(!!)!&)AEfFl 4dY'AdJ(4dB,5*p(3fRm!"3%#0PYaFfeTD@TTD'KRCfCQC@4NBf&T03!"!!!*!!! B&"5)!#SL)5N!!!m"!!)!9+@AQ*LAPjD@PC58Nj15NBk6QQmF!!)!!&6&i0$2dY( 4Rp)$dG201S!!)3%!!Kj)Ch0ZDQTTD'KRCfCQC@4NBf&T03!"!!!*!!!B&"5'!#N L)5N!!!m"!!)!9+DBQCQBQ*HAPTD9P*56NC'EL6X!!!)!*k$JeFl4dY'LdJA4dYD UA"5#!"d,-&YXDQTTD'KRCfCQC@4NBf&T03!"!!!*!!!B&"5%!!`M)LS!!!m"!!) !9DHCJ*SBQCQBPjH@PT@8NCQCAJi!!J!*FG6FcY$5dC,5!0'0dJr4dY(4fZ$*LMN %!!!"!"KZJ'SAD@KSCfGQCQ9NC'0KD68!!3!!#3!!'"38JJ!S)b)U!!!2!3!#!&@ TQjbEQjUDQCQBPjH@Nj@IILN!!3%!3,MKdFr5dY'0dJI4dG$2cY(5dBh5$p(5dFr 1e0rDXQNC!!!3DQb!DKGTD'KRCfCQC@4NBf&T03!"!!!*!!!B&"5!!#FM)LS!!!m "!!)!9UUFRCfFQjZDQTQBQ*D9Rj9,"3!#!"Q1hGM1dG,4LG)-dG$2cXl2dYADhqV Id*!!dP(4dG,3cY2Ah,!'!!PQEQYVDQTTD'KRCfCQC@4NBf&T03!"!!!*!!!B&"3 !)b-U!!!2!3!#!&HVRCkHRCfFQjZDQTQ@Qk&['!!#!!0FbYr2d0,4K0)#dG$2J-i 0cp,@h12UmIImr[rbdp'2dJl4dY(3eG6%[-[)%3!%B(#!DcaUDQPSD'GRCQCPC'4 MB@Ne!!%!!!N!!"J8&#-V!!!2!3!#!&HXRTqIRTkGRCbEQjQCT)dh!!!#!#kSi06 1JG)5dG$2cFh-cY(9fq2Umr[rr[lrri$q"Ir`d0$5dBc510(5dG$6em@b[p(9c"d !!&PbE'aVDfTUD@KSCfGQCQ9NC'0KD68!!3!!#3!!'"3V!!!3!3!#!&LZRi#J%Tq HRTfGR*UJRed-!!)!$AR@fXf!cKh0cY$8fGrRlrEprrlrr[caj0R+`m6&e[[rmG( 4dY',dR$4dY(3dYM,V+r-eG(3ebm!!&&dE'eXDfYUDQPSD'GRCQCPC'4MB@Ne!!% !!!N!!"J!!"!"!!)!@DqJSU'KS+#IRTkGR+#'*3!"!3")[Z,6dpMFi16Tl1cZkZ2 GdF@kUk#9LS+!KC1QZ-63p2radG(5dBV5,p(5dY(4f0'XRlr@dp(4cp`q!!")G@a YE@aVDfTUD@KSCfGQCQ9NC'0KD68!!3!!#B!!!4!"J!!M@E#LSk1LSD'JS*qHRTZ RA!!%!"k9h0E,bmc'`EfcUk1BNSb)J)85KSU0NCHU[mrAfGE9p2radG(5dBV5,0( 5dG$@eV18VG,@d0(5dFrH6`!!2RGYEQeYE'YVDQTTD'KRCfCQC@4NBf&T0B%!-!N !$`%!!3"JXD+NT+1MSU'KS+#IRTbQE!!!+FcBaF6%`,fmZlbq`-2(bXh2dG28eGD !e`cBeY24d0$`rr,4dG,4LG)[dG,4d0AB[C'CapM4dG,4dY(1i@8!!$9iE@jZE@e XDfYUDQPSD'GRCQCPC'4MB@NjJ3!)#!m"!!%!B,'MJ+36Sk1LSD'JS*qGTRJ!!$2 DcY26e0@#eJ69eG66di$5JY%-d0$4dG,2lIrbdY(5dBM5$p(5dG$6f-@9L,EBe0$ 4dY'!dKl1i(8!!#YhEQpZEQeYE'YVDQTTD'KRCfCQC@4NBQNjJ3!$#!!3!B!!!PU bSi#N$U1MSU'KS+#HT)-#!"l0djA4#G,5cqVrmp,4dY'(dJr4dY(3dYM-RRkId0I 3dG,4JY)'cpk*!!!KGS"[%fjZE@eXDfYUDQPSD'GRCQCPBfXfJ3!!#B!!"a!"!!) !@V+MJ+31Sk1LSD'JRk12#!!5ap64NY)+dG,5cZIrmp,3dY''dK$4dY(3dGI3UAk +`GR5d0,5dB25"XrGR3!!'A5!F#4[EQjYE@aVDfTUD@KSCfGQC'`h!!%!!!N!!#i !!"!"!!)!@V+MJ+30Sk1LSD'ISCJ3!!Lkep#8dJI1j2rddp$5dBA5%0(5dY(4eY1 bJhZXeGA3dG,4KG)(cpUS!!!4F(+!F#4[EQjYE@aVDfTUD@KSCf9Z1!!"!!!*!!! C*5i!!"!"!!)!@V+MJ+3-Sk1LSD#KRKS!!+VDd*(5#G(5cZ(rp023dY'%dK(4dG, 4d0E9ZSYdPXRBdG(5dG'%dM,4dY$8[!N!#@acFA&`F'pZEQeYE'YVDQTTD'G[1!! "!!!*!!!CP,J!!%!%!!J"DXU1!T!ZMSk+KS+8P!!#FhFq3!0)*dG,1h[redp$ 5dB65%0(5dG$8eVq8G)1heY63dG,4K0),dG(5d-lL[JX!"@CeJ(%QF("[EQjYE@a VDfTTD(!j!!%!!!S!!"N9&3!P*5i!!"!"!!)!@V+MJ+3+Sk1LS+Na!!#*hXq2dJR 4dXrEr[E6d0,4Jp)3dG,4d02AaCajGk(1ep(4dY'&dLI4dY(1f0f3!"S!!J"FH(& bFA&`F'pZEQeYE'YVDA%k!!%!!!S!!"S9&B!!$#8P,J!!%!%!!J"DXU1!T!QMSU# V3!!!GZ$1M0+!d3M5cpMppp63dY'#dK(4dY(3dYI+ShpcMElAdp$4dY'%dJl4dG, 2dH'k3J!"!3!ADAD!FKCaFA"`EfjZE@eXDR-k!!%!!!S!!"S9&B)!$#8P,J!!%!% !!J"DXU1!T!QMS+j1!!"NiFl4J0+$d3$3J-m,cXl2dG$@qrI8d0,4JG)4dG,5d0, AcUQ%G(kTdGE3dG,4KG)SdG,3cYc9G!X!!`!'3AGhFh4cFR*aFA"`EfjZE@Yd1`! "!!!+!!!E&KD%!!`P*5i!!"!"!!)!@V+MJ+3(SDjF!!"3hFf!caA1cXr2dG29epV Ghq(Ji0I4qIM8d0,4JG)4dG,4d0E5X)PhH*6%f0,3dY,4K0)TdG,4cYAJSbN!!J% !*@TrGR9eG(4cFR*aFA"[EfjXG6`!!3!"#J!!'aB@KJ!Z*58Z!!!3!3!#!&UbSk5 NSDeU!!!rhpADhGrJiGlFemh'YkLDKR0P4NRUr063dY'!dK(4dY,3dpHjMAThK,( 8eG$4dY'%dLV4dG,3cpr(9J%!!J!28hplGACfGA9dG(0bFR&aF'pYGM`!!3!"#J! !'aB@L!!J*58Z!!!3!3!#!&UbSk5LV(J!!#h,Z+QFL(CN6ciZ(K%'JJ!'",Rrdp$ 5dB$5%0(5dG$@cTpmHAbEbYI4dG,4KG)UdG,4cYMEL"B!"!!$1AH"H(GiGhGfGA9 dG(0bFR&`EhJp!!%!!3S!!"`@&iS!P,J!!%!%!!J"DXU1MUi3!!!34"iN!(3% %!`1hrp23dY(5dY(5dY$5elZ*HAQ*Z0E8d0(5dB65+p(5dXr4iEBk!!)#!"9GJ(T jHhYkH(GhGR9eG(4cFR&`H6d!!3!"#J!!("FAM!!2*58Z!!!3!3!#!&UbSUQ3!!D +!"i(%!!"!J#Qrp,3dY(5dY(5dG$@d+*pH(kLcYI3dG,4KG)VdG,3cYc8FJS!"!! 9L,@MLi"hFR"bG(GjHAGfGA4dFh&k2J!"!!%+!!!F&aH1!$NP*5i!!"!"!!)!@V' QQ3X!!3F3'bFd38eABh#$R5`!"!#Brp22dY(5dG(5d0,A[SahHT,!ep,3dY,4K0) XdG,4cYEJSLJ!!3!!9qArrIrmmH$-Y*f*HA"ZF(0fGhCbHcm!!3!"#J!!("FAN!! !0L8P,J!!%!%!!J"DXk&fHiL6R*kKSUHc`Y(Nrf%!"J#)rp62dY(5dG,4d0E4TAe fKDr6eG$4dY'%dLh4dG,2dH$$9!%!!`!jbrrprrllr2hrr[lrqZR5YCQ#FQYUI%! !!3!"#`!!(4FANJ!d*58Z!!!3!3!#!&UbV+bQSD+V[0$Qp[lprh-!"`"jrpA2dY( 5dG,3dYI"MR9mRXVAdG$5dG'%dLh4dY(1fpGk$`!#!J!+G+HacHMkrrlrr[rqqrc qrrlrppkpUd-!!3!"#`!!(4FAP!!a*58Z!!!3!3!#!&U[SVE2jrRrr[lmq[pr!!J !D2r@cY,4dY,4d0A5UAaeMlhAdp$4dY'%dJV4dY(1e1'T,J!"!S8!'``N3QD1YY[ hrrlqrrllr2hrN3!#!!)-!!!G&aH@!#iP*5i!!"!"!!-!FIrpr[rmr2rqr2q3!!! (!&(rfFl6dG,5dG(A`j!!Fi'YdYE3dG,4K0),dG(5d-rIbed$!!)"JJ!#!`-#K!! 8""j&G+I9q2rmriN!!J!#'3!!+"JCQ!!X*58Z!!!9!`!#!)hrr2lqrqkqK8F$"3" !q0[0dp(5dG$9e+alGj[)ep,3dY,4K0)+dG,4cYMGMaN!!J+)!!%"!B!$!!+#!!i #)%f8I3!#!!)D!!!['"QD!!mP*6S!!"d#!!)!L[r&K885J!!@"3!cm0r-dp(5dG( AaT&bLVV@e0$4dY'%dJV4dG,2dH'j33!!!T%!!`%$"!1#!!J#!!!9!!!i+bQF!!S P*$S!!"`#!!!''i%!&`%$"J!RkH,,dp(4d069VRYlUG(@d0(5dBA5#Y(5d-lFe() +!!)"P`!!!B!$"`!!"3!)*c-eRJ!91MP%!!!2!!!#!!%%!`%!!J!EhHA,di$4#pM )NA5@aYI5d0,5dB65#Y(5dFl9i+)S!!%#RJ!&"3!**c3eS!!)1cNZ"3!)!!!"J3! 8!J!4d1M+dp(3e0D`Hi1heY63dG,4K0),dG(5cp$Jae8!!!)"RJ!&"3!!$``0SJ! &1MJZ!J!)JJ!6!3!+a1c+dp(4f-U5H+22ep(4dY'&dJV4dY(1fGZ'&3!#!Tm!"38 !!!i,#k3!"4%4&!!!#)!!%`%"!lAZbG23e0HaIBl$f0,3dG,4K0)+dG,5cY,KXcN !!3+J!!8&!!!1$!bQ!"N4%4J!!!B!!!)!Sqr+dY$Bbj1!X0A9d0(5dBA5#Y(5d-l Gd@N(!!)"S!!&"3!!$J`-UJ!!!B!!%3)!P2$+dG2BXB'DcGM4dG,4dB65#Y(5dFl @hjSL!!)#S3!&"3!!$J`-VJ!3!`#%m-V4f-Z9LVhBdp$4dY'%dJV4dG,2d1$"63! !!U)!"38!!!i-$+i!$`3!Gqr+e0HbLDM8eY$4dY'&dJV4dY(1fYPr%!!#!D)!"3B !!!i-$+i!$`3!CZh-f-ZDPmICdG$5dY'%dJV4dY,1dq'X-J!"!U-!"3B!!!i-$+i !$J3!9ZM3eV58Y0I8d0(5dB65#p(4dY$2hXeK"!!#!D-!"3B!!!i-$+i!$3-!4H6 @bD1QcpM3dG,4KG)+dG,4cYIHNaX!!J+N!!8'!!!2$!bZ!!d$!$EJeEHM`GM5d0, 5dB65#Y(4dXr4iEa&!!!#T3!&"J!!$``-VJ!-!J!UfFkVYG2@d0(5dBA5#Y(5d-l FeRB-!!)"T3!&"J!!$``-VJ!,!J!Ic-@[bYI4dG,4KG)+dG,4cY6JT5X!!3+Q!!8 '!!!2$!bZ!!X"!"@ka,l9e0$4dY'%dJ[4dG,3cpr*@3)!!J'Q!!8'!!!2$!b`!!J ,UFl,eG(4dY'&dJV4dY(1f0b,&`!#!UF!"3B!!"!-$,!!"35FfFr6dBI5#Y(4dXr 4iEBp!!%#U!!&"J!!%!`0V`!)!J"%j-l4dG,4KG)+dG,3cY[9EJJ!!J'S!!8'!!! 3$Jk`!!8#!$IDcp''dJV4dY(1e1#P*J!"!UN!"3B!!"!1$V%!"3%!*YA4dB65#p( 4dY$2hmP9!!!#!DN!"3B!!"!1$V)!"3%!&-h6dB25$Y(5dFlBhBN6!!)#!!!(!DB !"3B!!"!1$V8!!`c$eG'"dJV4dY,2dZ'f1!!"!S!!!Jd!#+8!"3F!!"%1$VF!!VA Bd)$5%Y(5d-lFdfX'!!)"!!!#!!-!!!LM!!8(!!!4$Jkf!"!"!+AEcp,4dY(1eH# H)!!#!S-!"!J8!!!)S3!&"`!!%3i1Y`!1!J#@hFr4dXr3i-9-!!!#K3!&#"%8!!! )R`!&"`!!%3i2Z!!0!J"rhmr4cYRDJ3i!!J'(!!84%43!!!LG!!8(!!!4$Jqj!!X $!'lKbp,KX$%!!3++!!84%43!!!LE!!8(!!!4$Jqk!!S$!&[GfY"L!`!#!B`!"4% 4&!!!#*N!"3F!!"%1$lX!#!)!4qZ6'J!#!Sm!"4%4&!!!#*F!"3F!!"%1$l`!"J% !+Nm!!!+5!!84%43!!!L9!!8(!!!5$Jr"!!%#!C3!"4%4&!!!#*-!"3F!!")2$m% !!!+A!!84%43!!!L4!!8(!!!5$`rH!!84%43!!!L2!!8(!!!5$`rJ!!84%43!!!L 0!!8(!!!5$`rL!!84%43!!!L,!!8(!!!5$`rN!!84%43!!!L*!!8(!!!5$`rQ!!8 4%43!!!L(!!8(!!!5$`rS!!84%43!!!L&!!8(!!!6%"$U!!84%43!!!L$!!8(!!! 6%"$X!!83%"3!!!L"!!8(!!!6$a$Z!!d4%43!!!J!!!F!!"-3%2!!#a%4&!!!"`F !!"-3%,F!Y`!,&aFE!!!*#3!!'K89m!!0&aFE!!!+!!!+!!!D&4AZ!!8A&a`!!!U "!!8+!!!D&4EX!!BB&a`!!!S"JJ!&#J!!'K89kJ!+'"FF!!!+!3!!!3'!!!8+!!! D&4AS!"8B&ad!!!S"!!%!26i!!3!!#J!!'K89jJ!A'"FG!!!+!3!"!$TcFMS!!3! !#J!!'K89j!!C'4NG!!!+!3!"!$YdDfTc1J!"!!!+!!!D&4AL!!XC'4d!!!S"!!% !2(D!E!aUFcS!!3!!#J!!'K89i!!,'4NH!!!,!3!"!$ahJ@d0E'Tc1J!"!!!+!!! D&4AH!!XC'4i!!!X"!!%!2AL"EJpYE@aUFcS!!3!!#J!!'K89h!!K'4NI!!!,!3! "!$ejEh"[EfjZE@eXDR-k!!%!!!S!!"S9&GS!)aNC(`!!#`%!!3!qHh"aFA"[Efj ZE@eXDR-k!!%!!!S!!"S9&C)!"!%!!"N0[J!P'4NI!!!,!3!"!$pmFA*bFA&`Efp ZEQeYE'Tc1J!"!!!+!!!D&4@5!!-*-8JE[3!R'KSI!!!,!3!"!$ppFR0cFR*aFA" [EfjZE@eXDR-k!!%!!!S!!"S9&Bd!#3%!!5&20NdL!!'k!!XD'Km!!!X"!!%!3(k !G"TcFh*bFA&`EfpZEQeYE'Tc1J!"!!!+!!!D&4@0!!J42&Sb0eBR!!'j!!XD'L! !!!X"!!%!3(q!G4adG(0cFR*aFA"[EfjZE@eXDR-k!!%!!!S!!"S9&BS!#J3Z69F m)P&3,`!"Z!!,'aSJ!!!-!3!"!%'!JABGGA4dFh0bFR&aF'p[EQjYE@aUFcS!!3! !#J!!'K8-K3!-!3!!'NG38%m35Ne30lN!#aXE)3!!$!%!!3"#JS&h(RCfGA4dFh0 bFR&aF'p[EQjYE@aUFcS!!3!!#J!!'3L'!!X+1&*15Pi309*,8$bi!#mE'b%!!!` "!!%!3S0iHAKiGhGfGR9dG(0cFR*aFA"[EfjZE@eXDR-k!!%!!!S!!!5#!!m"!!% P69&-5'BI'90,6%p#Y`!`'aXK!!!-!3!"!%1%HATkHAKiGhGfGR9dG(0cFR*aFA" [EfjZE@eXDR-k!!%!!!S!&)-!$a0"8Ne04QFe!NT16%a14`5e!$!F(#)!!!`"!!% !4)9kHhYkHRPiH(GhGRCeG(4cFh*bFA&`EfpZEQeYE'Tc1J!"!!%*JJ!4"M"36dY 14Q4-!$945de-68X(Y!!Y("`L!!!-!3!"!%5(HhamHhYkHRPiH(GhGRCeG(4cFh* bFA&`EfpZEQeYE'Tc1B8!#ae*8Na-6NGHB3!C8B*-!8i1X`!a("`L!!!-!3!"!%@ )I(epI(alHhTkHAKiGhGfGR9dG(0cFR*aFA"[EfjZE@eVDASf!!'!!"301e*15da 15&Ca#!*%6da068a-8"5b!%SF(#)!!!d"!!%!4BPpIRjpIAamHhYkHRPiH(GhGRC eG(4cFh*bFA&`EfpZE@Y`F8B3!!%!!LG08%Y-68e+6hdC!#e55de-6%e,8aQa!!X G(#-!!!d"!!%!4SU"IapqIAemI(YlHRTjH(KhGhCfGA4dFh0bFR&`F'pYERCH(i% !$K9"8Na,68a06%L$,!!86S&-"%e,8%!$X!!,(4`M!!!0!3!"!%H,JB!lIhpqIAe mI(YlHRTjH(KhGhCfGA4dFh0bFR&`ER9[1J3!!3!,0P"25da06%e14)0$!!a'6Na 06%e-6NN*X!"0(4`M!!!0!3!"!%H0JB+"JB#!IhpqIAemI(YlHRTjH(KhGhCfGA4 dFh0bF(0i9"-!!3!#*%Y46%a06%e-6N*p@`!*3e",68a06%a2%`!"VJ!Y(4dM!!! 0!3!"!%L1JS1$JS'"J)"rIhjpIAamHhYkHRPiH(GhGRCeG(4bFRTU+i%!%a0!8Ne ,6%e-68a23R4c!!C"88Y0J%`%5e)I!!'Z!%dG(5-!!!d"!!%!5Bq$K)5$Ji+"JB# !IhpqIAemI(YlHRTjH(KhGhCfGA*jH%F+!!%!"Lp28%Y-68a068a24'Q)"3-q88Y 06%a05e)Y!!'Z!#`G(53!!!d"!!%!5C!!K)@&K)5$Ji+"JB#!IhpqIAemI(YlHRT jH(KhGh4fIQ%GJ3!'(8G56%a06)"0%%a14PfA&3!l88Y06%a05e%jX!!h(4dN!!! 0!3!"!%U4KBD'KB@%K)1$JS'"J)"rIhjpIAamHhYkHRPiGhCqG$J$!!%!$6P56NY -68b!64&-6NP5RbS!19*,68a-68Y24!@[!$BI(L8!!!d"!!%!5T1'KiH'KS@&K)5 $Ji+"JB#!IhpqIAemI(YlHRPhHhp9%3!"!!-R69&,6%e-J8d46%e,5k&$!$C55de -6%e-68X0V`!-(aiP!!!0!3!#!%Z8Ki#)'SH'KS@&K)5$Ji+"JB#!IhpqIAemI(Y jHS*Y+B%!"aC#8Ne,68e-J8d66%e04CaH!$*55de06%e-6&!B!!'Y!!XI(L8!!!i "!!)!6*@"L5@)L)H'KS@&K)5$Ji+"JB#!IhpqIAemHS&q4JJ!!3!)-P"25da06)* 0%da06N15HJ!Z8dY-68e-68Y5*!!"V3!d(amQ!!!1!3!#!%b@LSZ+LSQ*L)L(KSD &KB5%Ji1#JB'!J(prIRYqK@-E!!%!!#"*8Na-68b%64*-6d+&N`!R8dY-68e-68Y 5-!!"V3!d(amQ!!!1!3!#!%fALib-LiU+LBQ)L)H'KS@&K)5$Ji+"JB#!IRf'H6B "!!%!$ca56NY-68b%64&-6d0hTJdJ8dY-68a-68Y41`'!!!!$UJ!c(amQ!!!1!3! #!%fCM)f0M)b,LSU*LBL)KiD'KB@%K)1$JS'!IS5'93m!!3!%+dj35da06)90'8a 24@Qb)"K86%a06%a06%p&"`!!!3X8#3X-TJ!R(amQ!!!1!3!#!%kDMBk1MBf-M)Z +LSQ*L)L(KSD&KB5%Ji1!JBT`*i%!"aP%8Na-68a-K8dE6%j(AEJk%90-6%e-68e -68i6!!)!!!S!!"N9&D3!-L!J*`!!$J%!!J"2Qik2Mik1MBf-M)Z+LSQ*L)L(KSD &KB5$JBQ$438!!3!+0P&25da06)C0$%a1595f93Y568a06%f!6!04)!!#J3!&#J! !'K89SJ!a)#!R!!!1!3!#!%qFMj!!N!#2Mik1MBf-M)Z+LSQ*L)L(KSD&JSH0C"J !!3!")dY46%a06)G0&Na15df[FJT26Na06%e-68Y5,!!"!4`$J!!&#J!!'K89S!! -)#!R!!!1!3!#!&#GN!#!N5'3!)q2MSk0MBb-LiU+LBQ)L)H&KBjp0!!!!3!52e* 05de06)G0)8a06%LMM3p,6da06%e-68Y41!!#!#Ce1J!"!!!+!!!D&4@H!!`K)#F !!!i"!!)!8*q4J*)JNC'3!)q2MSk0MBb-LiU+LBQ)KBb-93`!!3!',Np35da06)Y 0)%D@T"Y&8%Y06%e-68Y33`B!!"KXE()k!!%!!!S!!"S9&C`!,b%K+!!!$J%!!J" 4S*18Nj15NT'4N!#2Mik1MBf-M)Z+LSH*NR-M!!%!!"a(8Na-68b+654-6N@&Y#d r8NY06%e-68a15`i!!!aMF'YUFcS!!3!!#J!!'K89QJ![)5%S!!!1!3!#!&+KP*@ 9P*16NT+4NC!!Miq1MSf0M)b+L*+)3`3!!3!-19&15da06)T0#Na15'#j4$P65de -J%dB6%a3'3!"!PCdDfeXDR-k!!%!!!S!!"S9&CJ!,L%K+!!!$`%!!J"5ST@@PT@ 9P*16NT+4NC!!Miq1MSf-LSq8C"8!!3!#*da45da06)j0*8DIC$965de-68e-68Y 5*3!#!%GhE'jYE@aUFcS!!3!!#J!!'K89PJ!Z)L%T!!!2!3!#!&1NPTHAPTD9PC5 6Nj+5NC'3!)q2MSb0Pi!a!!!"!"9#8Ne,68e-M%dT6%j%Fh`h8Na06%e06%e,8M) !!J!eH'j[EQjYE@aUFcS!!3!!#J!!'K89P!!Y)L%T!!!2!3!#!&1PPjLBPjH@PT@ 9P*16NT+4NC!!Mib9NP-+!!%!"c*36dY-68b265P,8ha#6Na06%e06%e,86d#!3! NGR"`EfpZEQeYE'Tc1J!"!!!+!!!D&4@5!#`L)5N!!!m"!!)!9+DBQCQBQ*HAPTD 9PC56Nj+5NBk5QR3J!!%!!"p*8Na-68b4639+C9"+68b!65&-68a24`N!!"9[Fh" aF'p[EQjYE@aUFcS!!3!!#J!!'K89N!!!$#)L+3!!$`%!!J"9TjQ!QKbCQ*LAPjD @PC@8Nj14N!#DM%%#!!%!$ca56NY-68b4639-8&0+68b!650-68a064)!!!PPGh& bFA&`EfpZEQeYE'Tc1J!"!!!+!!!D&4@1!!`M)LS!!!m"!!)!9DLDJ*XEQTUCQ*L APjD@PC@8NCHDC")!!3!%+Nj35da06*00"%a06%e-JNdM6%a4(J!"!&9lFA0bFR& aF'p[EQjYE@aUFcS!!3!!#J!!'K89M!!I)b)U!!!2!3!#!&DUQjfFR*ZEQTUCQ*L APjD@Nj5IJLk"!!FB4&*-6%e06*90!Na06)*0*8a-8bS!!3"-JR&bFh0bFR&aF'p [EQjYE@aUFcS!!3!!#J!!'K89LJ!@)b)U!!!2!3!#!&DVRCkHRCbFQjZDQTQ!Q"# @P*fA83F!!3!*09&25da06*C0!%b%63e-6&!b!!)!!MTLHRaeFB"b&R&aF'p[EQj YE@aUFcS!!3!!#J!!'K89L!!T*#-V!!!2!3!#!&HXRTqIRTkGR*bEQjUDQCL9QU& d(3!"!!%M5e&-6%e-S%d$6%e0'S)!"3)J6A"mGi"b&R&aF'p[EQjYE@aUFcS!!3! !#J!!'K89KJ!T*#-V!!!2!3!#!&LYRk#JRjqHRTfFR*ZEQTLBSj!!2J!!!3!52P* 05de06+*0"8a-6d%P#B)!!``dBR@!FKCaFA"[EfjZE@eXDR-k!!%!!!S!!"S9&B3 !+#3M,!!!%!%!!J"BVU#KSD#JRjqHRTfFR*ZBS+&M$`!"!!8Z6e",6%e-Mdd$6Nj 06)p0+%a-6e*,04J$!!!"!"ThFh0bFR&aF'p[EQjYE@aUFcS!!3!!#J!!'K89JJ! R*#3X!!!3!3!#!&Q`SD+LSD'JS*qIRTkGQTbRK#X!!3!!'dC56%a06)T0J8i(6%Y )4d4,68b065T-68a-5de48%-U$!!!%A*eFh0bFR&aF'p[EQjYE@aUFcS!!3!!#J! !'K89J!!-*53X!!!3!3!#!&UaSS#M&k+KSD#JRjqGQkDF6`8!!3!-1&&15da06)4 0J8i068Y*4dC'5%e8B'Z$DdQ463a-68a,6Ne14!-!#@jfJ(-QFR*aFA"[EfjZE@e XDR-k!!%!!!S!!"S9&3!P*#`!!"!"!!)!@V+MJ+38Sk1LSD'JS*bLU(3D!!%!!LC -88Y-JNf!6K406%T)4N9&58pBCA1$Nk#UX,fB8%b266G-68a,6dj!28K+#!!%ChK dG(0cFR*aFA"[EfjZE@eXDR-k!!%!!!S!!"S9&53X!!!3!3!#!&ZcT)#P%k5NSk1 LSU#IUj-k!!!"!"9"8Ne-J%iF68a+4d9$3dC-9@*aJT1NXE[#`EkiXl#iN!"*5Ne -M%d36%e-5dj436%q68j0$J!!AhU!G&YcFh*bFA&`EfpZEQeYE'Tc1J!"!!!+!!! D&5d!!"!"!!)!@l5PTkHQTD@NT+1MSDHQB3`!!3!(-9"258P(484&58pCCR@&PD5 [YVLcVk#2IfTH@e0RUVL55dY06)Y0F%a06%Y08dBU,NK36%a2%J!!9hadGA4dFh0 bFR&aF'p[EQjYE@aUFcS!!3!!#J!!'J!!%!%!!J"FYUHSU+HRTU@PT+5LTS`Q!!% !!"j(88e299eQF(b'M*15Li9eC99!-#%4"J%%$b!b1dUBZj0,5dj-LNd[6%e06%a 56#SI29&16%e-84S!!%eqG(CeG(4cFh*bFA&`EfpZEQeYE'Tc1J!"!!!+J!!q%3% !!3"FYkLTUDLSTkHQTD@NSDjI!!3!$cj899CBA9TA9%Jp-L-B$`F#!3!#"JS1&#B l5P*989#C[j4-5dj-LNdX6%e-5e&3-"3V6P"-6%e-5e)K!!"$J(9fGR9dG(0cFR* aFA"[EfjZE@eXDR-kJ3![#J!3!3!"!'1hUDUUUDQSU+HRTU@PSUea!!!689"*4d9 !1cJe0$Bi2%&%4dT06P"4J9)-8e&06%Y*NEk86%Y16)P0,da06%Y28MN4'%466%a 06%e05e)Q!!!jJ(9hGRCeG(4cFh*bFA&`EfpZEQeYE'Tb2S%!+3N3!3!"!'1iUDZ VUUQTU+LRTkDPSkap!!!98%T068j28&&58P&48%p16S"0Jd`,5da068L+[jC05dj -L%d26%e-5dj6348*-e*25da06)"0(NY5,`!!,S"fGhGfGR9dG(0cFR*aFA"[Efj ZE@aUFck"!"S*!"%"!!%!AEQTUkZUUDQSU+HRTU5VL3%!%%k@6!P068D$[jG15Nj -Kdd26%e-5de54ad!(NY55da06)*0(8a40J!!)hphH(GhGRCeG(4cFh*bFA&`Efp ZE@ae1i!!!3%+J!!C%3%!!J"GZDQVUkUTUDLSTkHPUC8)!!P+68b563T-68j&I,k C6NT16)C0%%a06%Y-8NXR!!Xp8de,68e-Jdd'6&!l!!!DI)"i0AGhGRCeG(4cFh* bFA&`EfjYGM`!!3!"#J!!-!!!%3%!!J"GZDQVUkUTUDLSTkDSRK!!"8G16*00#%j &GEfD6dT16)90%%a068a-88i["3!T8&",6%e-K8dr6%p"!J!5H(TjH(KhGhCfGA4 dFh0bFR&aF'jh2!!"!!%+!!!E*c!!!"%"!!)!AEQTUkZUUDQSU+HRT4X!!d026*& 0#8a14@klR%p+6Nb&63p-68a,8&!f$!!949*-6%e-K8e"6%e-68F&!!TdI(PjH(K hGhCfGA4dFh0bFR&[H$d!!3!"#J!!("FR*c!!!"%"!!)!AEQTUkZUUDQSTkDX*J! !1e"-N!"0#8a14QHjRNp+6Nb%64"-68a,6e%m%`!'-e&25da06)903Na06%Y55!8 !"@eqHATjH(KhGhCfGA4dFh0bF(Nq!!%!!3S!!"`A&`!R*c!!!"%"!!)!AEQTUkZ UUDQSTV!c!!!h88b263P-6NCKYU"35Nj-Jdd36%e-5dj534S!!"p*8Na-68b&65G -68a,6P%i$!!#!'+"HATkHAKiGhGfGR9dG(0aHci!!3!"#J!!("FAJ!!C*bF`!!! 4!3!#!&fjUDZVUUQTTV*#!!!`88Z163P-6NGEXU*458j-JNd46%e-5de545%$!!d k8Nj,6%e-K8dR6%e-6&*((!!!!3!CFAjlHhTkHAKiGhGfGR9dFR`r!!%!!3S!!"` A&i)!'#FR-!!!%3%!!J"GZDQVUkUTTV43!!!R8NZ#6BC-J%X)6NP@VU4458j-J8d 46%e05de555F&!!)R6&&,6%e-K8dS6%e-5e"2,JB!!3!'4Aq!I(alHhTkHAKiGhG fGA4p3!!"!!%,!!!G&aH%!"FR*c!!!"%"!!)!AEQTUkZUTl9I!!!N8NZ!6)",J%` 268j28&&58P408+QR8NP16)&0%8a06%Y465d*!!!63&*05de06)40+8a068Y08Mm 5!!%!!#KaL(jpIAamHhYkHRPiH(GfG(j!!!%!!3X!!"dA&iB!,LFR-!!!%3%!!J" GZDQVUkLdEJ!!'P*06e"489*589"158C#1MFZ+"iIRkT558j-J%d46%e05dj40Jd !!!BZ6e",6%e-K8dT6%e-5e&,)`%!!3!3@BH$IAjqIAemI(YlHRTjH(GfId%!!3! "#`!!(4FAL!!K*bF`!!!4!3!#!&fjUDZTXhd!!"004N-l0c!Q)aS6%!J%!B%!"J+ 'V9**6Nb!63C-68a,88SHJ!!''N956%a06)90+Na06%Y186B+!!-!!carLAprJ(p rIRepI(alHhTkHAH"33!"!!%,!!!H'"Q+!"8R*c!!!"%"!!)!AEQTUE+*!!!$#38 $L3!F!3%!JV*65%j-68e-68e,69)i#J!!#6946NY-68b&65T-68a-8NBC!!%"!"G NLB+"Ji1#J(prIRepI(alHhTiJN)!!3!"#`!!(KJCM!!2*bF`!!!4!3!#!&fjU,# 9"SS!(JF3!!!"!(Hc9%K16%e06%e-5e&,)!!!!5&+88a-68b&65Y-68a,6e!a"J! $!"@*ZDQ4KhpkHATpIi'"J(jpI(alHB0#!!%!!3X!!"mB'Bi!15FR-!!!%3%!!J" GZ+bI#`!""a!E+$C%8&aSGBLL,J!$!'bd98K16%e06%e,69)k$!!!%6a568Y068b %63G-68a,69*#&)%!)&IPrrhrr2(LcVLMMi&iGRKmIRpqHS4$!!%!!3X!!"mC'C! !!$BR*c!!!"%"!!)!AEQRHS#0QD+PU+UZZFI9j[pK!!3!BE4@4dj-68a06%Y36#- "!!BY6P",6%e-K%dY6%a06%a45LB#!!%!1F[rrIrqqrcprrlqrrVUe,QILATdFi9 %!!%!!3X!!"mC'C)!0#FR-!!!%3%!!J"GZE+cVDLSX-$5jrEqrIpc!!8!9V4B4dj -68a06%e523i!!"a'8Na-68a-K%dY6%e-5e"2,!B!!!%!#R5RXFhSq[rqrrlrr[[ mr[rqrrIJ`,"(!!)!!3`!!"mC'C3!-5FR-!!!%3%!!J"HYULkdHMjrrlqr2VrI`! '!%Ub@NC16%e06%Y365B"!!ij88j,6%e-K%d+6%e-5de52K%!!!'&!"X-*%*QMVE Eprrqr[rqqrcprj%!!J!#$3!!(aNCPJ!Z*bF`!!!4!3!$!(,rrIlqr2crr[crN!! !"J!hVPe'6da068a-8Mm3!!3U69&,6%e-K8d*6%e-6&&+)J%!!B-!!J-$!S3!&!3 H4A5ReIMrr2q*!!)!!KN!!#ND'TJ!,#FR-!!!&J-!!J#0rrhqr[rZ[S9("!3!+kK J48p-68a,6dmT!3!C4&*05de06)40"da06%Y2863*L`!"!3'!!`!#JJ!1!L"0P(d !!J!#'J!!-"SDQJ!2*bFm!!!G!`!#!)VraB9&%S!!&J3!)U0M4%p-68a-8N)4!!X h88p,6%e-K%d+6%e05da53aF!!!'4!!-"!`3$JJ!)!J!!&3!!1#XUR!!+*bBl!!! G!J!!"KZ"!"F"!`8!'CeQ4%p-6%Y28#X"!5C-88a-68b&63P-68a,8%iU!`!"Q!! !!B!$"`!!"3!)+$3eRJ!91cT&!!!3!!!#!!%%!`%!!3!5P'P$6i"-#e*%%J!93P* 05de06)40"da06%Y18MX1S3!&"3!)+$3eS!!)1cS["3!)!!!"J3!8!3!-Lfa$6da ,6e%X!!Bc8%p,6%e-K8d*6%e-6&**(`!!!Cm!"3B!!"!0$D)!"6Si,J)!#))!%`% !"S*Z3dp-6&*&%J!K5e&-6%e-K8d(6%e-5dp3-3HL!!8'!!!1$!bN!!85%48!!!L #!"%#Gh"#6dY18Li!$Mp568Y-68b%63T-68e,69*"&3!!!D!!"3B!!!m-$+B!'4) 5'3!!"`!!!3"XFN015e0'%J%Z8&",6%e-K8d*6%e-5e&-*J)!!D%!"3B!!!m-$+S !!!'!!"%"!'&c3de18Li#'NK56%a06%b%63G-68a,6P%i$+3!"3B!!!m-$+X!%`% !!!)!9A0$690'&3Xj8dj,6%e-K8d*6%e-6&*((!!!!D)!"3B!!!m-$+i!$`)!6A0 $8&)[#LC288Y-68b&63G-68a,8%mZ"U8!"3B!!!m-$+i!$`)!3R*%9%BC&d066%Y 068b%63T-68e,69)r%J!!!D-!"3B!!"!-$+i!$J)!0Qj)8M%8-P*25da06)90#8a 06%Y45b-"!!'N!!8'!!!3$!bZ!!d#!#YV68BK*%T55da06)90"da06%Y2868+T`! &"J!!%!i1VJ!0!3!KD8`e)6e668Y068b%63T-6%e-6&*&'3!!!D8!"3B!!"!1$Ui !$!%!'@9&+M*18%Y-68b&63G-68a,8%iV"+J!"3B!!"!1$Ui!#`%!%eXm,d956%a 06)90"da06%Y18M`3U3!&"J!!%!i1X!!*$%ik2%p25da06)90#8a06%a555!!!!' R!!8'!!!3$Jk`!!J&380)8%a-68b&63G-68a,6e!c#+S!"3F!!"%1$V!!"3%k6%a 16)G0#Na-68a-8N)@!!!"U!!&"`!!%3i1X3!"'91!6!&06)90#8a06%Y36LJ$!!' T!!8(!!!4$Jkb!!-88%a-KNd(6%e-5de52!kX!!8(!!!4$Jqc!!-16Na-K8d*6%e -6&&*(`!!!DS!"3F!!"%1$l3!!`G,68b$63G-68a,6e%b"i)!!3F"TJ!&"`!!%3i 2Y3!$"%G16)&0#Na068Y08N)8!!!"J!!#$3!)T3!&"`!!%3i2Y`!#3Np-J%d*6%e -5e"0*`)!!B!!"3%!!`!!#+-!"3F!!"%1$lJ!#ca36%e-68a,6P)k#iB!"!J9!!! )S3!&"`!!%Ji2Z3!-0e&-6%e-6&*)(!!!!B8!"3N4&3!!#*m!"3F!!")2$lJ!#J% !,P&,6%Y28#m&LJ!&%K%9!!!)R3!&"`!!%Jm2Z3!)!3!S8NT08N!4M3!&%K%9!!! )Q`!&"`!!%Jm2ZJ!*!3!K89"-*!%!!Bd!"4)4&3!!#*N!"3F!!")2$lX!"3%!'PB f#C)!"4)4&3!!#*F!"3F!!")2$li!"!mG!!!"NJ!&%K%9!!!)P3!&"`!!%Jm2fJ! &%K%9!!!)N`!&"`!!%Jm2h!!&%K%9!!!)N3!&"`!!%`m3hJ!&%K%9!!!)M`!&"`! !%a!3i!!&%K%9!!!)M3!&"`!!%a!3iJ!&%K%9!!!)L`!&"`!!%a!3j!!&%K%9!!! )L3!&"`!!%a!3jJ!&%K%9!!!)K`!&#!!!%a!3k!!&%K%9!!!)K3!&#!!!%a!3kJ! &%K%9!!!)J`!&#!!!%a!3l!!&%4%9!!!)J3!&#!!!&"!3lJ!0%K%9!!!)!!!)!!! 8%"(`!!X5%48!!!J(!!!8%"'h!(3iE@X!!%!)!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!S+%!!`! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)Vrri`!!`!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!`#0rr[lrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[lkrii !!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrrrlkrii!!`!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!`#-rrVqrrlqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!)#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrqrrl krii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrqrrlkrii!!`!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!#!J!QKJF!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!`#-rrVqrrlrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!"!`!$ErIS#`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrr qrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`)!1-crrr!B!!%!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!J-!%*AmrrVqr5S!!J!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`# -rrVqrrlrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!- !!&MNrrcmr[hr1`!#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrr rrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!)#!#@hrrhpqr2hrIp2!!-!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!! !!!!!!!!!!!!!!!%$!!ClpIrmrIEdqZrmrfB!!`!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrV qrrlrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!$!3"!e2r prIRbqIrpp[[rI!!%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrr rrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!#!J!@RrrqrIcdpIlrr[rfqIq4!!-!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`! !!!!!!!!"!`!!BZVrr2hhmr[rr[lqrqrjrkN!!`!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrl rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!`)!,F(rrIhkmrI qr[lqrrlrqI[r[J!#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrqrrlkrii!!`!!!3-!#SIirrhppI6prrlqrrlrr[reprr2!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii !!`-"!%VFrrcpqI,jrrlqrrrrrrrqrr2hrq%*!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!"bUrrlpr22fr[rqr[r qrrrrrrlrr2Vrm"3!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrqrrlkriTMmIrmrIIcqrrqr[rqrrrrrrrrr[rim[rk*J!"!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!$!)crq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrl mr[rqrIVbq2rqr[lrrrrrrrrrrrrqrrRerrmi!!)!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlmqrlfp2hrr[lrr[rrrrr rrrrrrrlrr[MmrdS!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrrlqr[cqr[lrrrrrrrrrrrrrrrrqr[rmlrhrB!!$!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! $!)crq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrr[lqrrlrrrrrrrrrrrrrr[rqrrEjq[pe!!3!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlqrrrrrrrrrrrrrrr rrrlrr[rip[hriKm!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrq[6qr[Jm!!)!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)c rq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrqrrccrI[rB!!%!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr qr[lqmrclriF!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqrr6jqrqZ!!)!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[l rr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrlrr[rfprhrd!i!!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrl rq2AprqSQ!!)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrr[cr[hm4`!$!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrr[r rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrr[rpm[hlrf`!"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrR lr2q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqr[crZ`-!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrr[rprqiE!!)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl priX!!J!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!-!M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlprii!!`!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr qrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!- !M2rkr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2r kr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[r qrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii !!`!!!!!!!!!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!! !!!!!!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!!!!!!!!!-!M2rkr[rqrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrl krii!!`!!!!!!!!!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!! !!`#-rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!!!!!!-!M2rkr[rqrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr qrrlkrii!!`!!!!!!!!!$!)crq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!!!!`# -rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrqrrlkrii!!`!!!!-!M2rkr[rqrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrqrrlkrii!!`!$!)hrq[lrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrim!!`#+rrV qrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkriX!S2rlr[rqrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrqrrllrk'Hrr[qrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[[rS!#)rrV qrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkriS!!`#,rrVqrrlrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrr[rqq[q0!!-!!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[VrM!!$!!!!!`# +rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrqrrlkri`!!`!!!!!!!`#+rrVqrrlrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rr[rqq[q-!!-!!!!!!!!!!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[VrM!!$!!!!!!!!!!! !!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrqrrlkri`!!`!!!!!!!!!!!!!!!`#+rrVqrrlrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[r qq[q-!!-!!!!!!!!!!!!!!!!!!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[VrM!!$!!!!!!!!!!!!!!! !!!!!!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrqrrlkri`!!`!!!!!!!!!!!!!!!!!!!!!!!`#+rrVqrrlrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q -!!-!!!!!!!!!!!!!!!!!!!!!!!!!!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[VrM!!$!!!!!!!!!!!!!!!!!!! !!!!!!!!!!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrqrrlkri`!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#+rrVqrrl rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q-!!- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[VrM!!$!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!`#+rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrqrrlkri`!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#+rr[ qrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q0!!-!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#+rrVqrrlrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[VrPJ!$!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!`#2rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrqrrlkrjB!!J!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`# @rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q@!!-"!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!J#9rrVqrrlrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrlrr[VrN`!$!3!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!"!`#6rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr qrrlkrj-!!`%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!`#4rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#4rr[qr[rrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrlrr[VrN`!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!`#5rrcqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrl krj-!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!"!#2rrcqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%"!DVrr2rqrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrlrr[VrN`!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!J#Qrrcpr[rqrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrj- !!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!-!P[rlr22qrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$!)Erq[hdr2rqrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrlrr[VrN`!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!"!"frr[qpIcrr[lqrrlrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrj-!!`! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3 !Crrmr[2krrlprIlrr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!&Irr2ldqIrqr2hqrrlrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrlrr[VrN`!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!"!")q[hqp[Rrr2cqrrlqrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrj-!!`!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!1[2 rrIEjr[[prrlqrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"!#lVrrhhpIclr[rqr[rrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrlrr[VrN`!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!3!LiIrpq2(lrIrqr[rrrrrrrrrrrrrrrrlqrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrj-!!`!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!'rrq[R Yr2rqr[lrrrrrrrrrrrrqrrlqr[rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-!9Irpl[[rr[lrrrrrrrrrrrrrr[r qr[rmr[rqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrl rr[VrN`!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!J!rrrhir[rrr[rrrrrrrrrrr[rqr[rpp2Eqqrcqrrlrrrrrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrj-!!`!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#!#cqrrA jrrlrrrrrrrrrrrrqr[lrq2,krIhrr[cqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!'2,rm[Mrr[rrrrrrrrlrr[lrr22 frIcrqhU2rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[V rN`!$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!,jIrkr2rqrrrrrrlrr[lrr[Ecr2hprm!X!!#4rrVqrrlrrrr rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrj-!!`!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$4rrE crrlrrrrrrrlqrrVbq2hmrqPK!!!$!`#4rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#!,lrp[Arr[rqrrlqrrhdpIhpr[q H&3!#!J!!!`#4rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[VrN`! $!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!-!TrrkqIrqrrlqr[lhm[Vpr2r63!!"!`!!!!!!!`#4rrVqrrl rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrj-!!`!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#0rrM [rrlqr[rlmrIpr2reHJB!!`%!!!!!!!!!!`#4rrVqrrlrrrrrrrrrrrrrrrrrrrr rrrrrrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!(IrqIErr[rqpI2mrIhrYL3!!J) !!!!!!!!!!!!!!`#4rrVqrrlrrrrrrrrrrrrrrrrrrrrrrrrrrrlrr[VrN`!$!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!-!A[rmp[hrqI,jrIcrieF!!!-!!!!!!!!!!!!!!!!!!`#4rrV qrrlrrrrrrrrrrrrrrrrrrrrrrrrqrrlkrj-!!`!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`"'rrh [q[6erIcrr*-3!!-#!!!!!!!!!!!!!!!!!!!!!`#4rrVqrrlrrrrrrrrrrrrrrrr rrrrrr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#!$2rrrIbqrhprmSf!!)$!!!!!!! !!!!!!!!!!!!!!!!!!`#4rrVqrrlrrrrrrrrrrrrrrrrrrrlrr[VrN`!$!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!%!(rErrIhmrr&[!`!$!3!!!!!!!!!!!!!!!!!!!!!!!!!!!`# 4rrVqrrlrrrrrrrrrrrrrrrrqrrlkrj-!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3!1k[r kr[qV(3!#!J!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#4rrVqrrlrrrrrrrrrrrr rr[rqq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!29rrrG6!!"!`!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!`#4rrVqrrlrrrrrrrrrrrlrr[VrN`!$!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!"!-ArK3X!!`)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!`#4rrVqrrlrrrrrrrrqrrlkrj-!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%!H$` !!J-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#4rrVqrrlrrrrrr[r qq[q6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-"!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!`#4rrVqrrlrrrlrr[VrN`!$!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!)#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!`#4rrVqrrlqrrlkrj-!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#5rrVqrrrqq[q 6!!-!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#4rrVqr[VrN`!$!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!`#5rr[lrj-!!`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!`#2rrq3!!! $!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!3-!TUF!!`%!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"TBc! i!!$JN!!!!!!-DP!J)!d+K`S!!!!8CR4jF'T`-L!!!!!!DR!b)!!!!%pUF$*S!!! !&QPSC()!!!%!!!!"!!!%"`F!!!!!!!pMEfab!3!!!!!!%!!!!#*MC'9Q!!3!!!! !!!%!!`!"!!!!!3!!!!)!!J!!!!-!!!!!DR!bBrp2re%!-J!!!!!"!!!!!3!!!!! !!!!!!!!!!3!!!!%!!!!!!!!!!!!!"!F"!3F"!3F"!3F"!IpN!#-!!80bC@&dEh) k)%TKFe"PFL"@CA*cD@pZ)$%Z16!`,M(r8J!-!!!!!3!&"!3!!IpF!"0!3%K)8%K )8%K)8%K)8%K)82pG!"3"3%")5&")5&")5&")5&")5&$rA3!8!N"!5%K35%K35%K 35%K35%K3red!&!0!3%K)8%K)8%K)8%K)8%K)82q3!!!+!!!!!0p2!!(rNpq#1"& 2!k[0YL+j4lrG*MZVIi-T!Nc"r5#0qMa"f4aLY5`0d'EXSl'+aki0,lBk$dC)MA2 5J&jrH"fTJZPc@MNNc&arVMe-0Gdehi)`%8m$eCj[L38@#$KBrP5+c,+j54EFeY1 1DJiQI@DVcR)F#AhaLNr%pE*4#HNIbQ['Aem8(0GTK)9S"!r@+p'2'jS,1d"42pq #%"&2!p8)mVlQ!aF#[(&)+La2-"+Zka)S4)3p`Ah@4KFaCj1cDlrP2Kk-0ZDP'aM ch"V2NJ-Hq+()BeKBka)5CZ2ZAGq#D"'(KC6DfC@dDef955LIq49AUAjVm"5)4XV fEN0$hLQqP*pDm$NljU6#"G-4T1[m@Z8+RMlfF5!2ZhEdeEZIYhe9+'f'%lAS[PV 9-#Brcm$QIJHcmd)`5EpX*,AL0&iTh2403!1#9$pk+MHpY"*j)*YKhNmf)EmLm+l f,&rfAhY!'YB6B'l,*j4hIjj04aFN!Bb-Vc*e!rH+,8r3#C@Q`D0`!V##IU"`"CQ *9S3j@d1e&q6Ui#Kk-d9'G'&9rhr8SE,41lm%3D@UF3jb[R+,Uk-fN@+(hcjc X9f&b8,8)Vi+*AJr2l49MdI9EKaiIq[%065Fmh*0pGa8331j'*#Ra1[j9!fV3Q,, 0%-(1cm$kIJJ4q#+!-%P6CYlYV3l[D4CJI33*GM+(MUm'*UDXDM9aiYVk#%(@+14 "L(TY@bV&9FaMdVFK4hF2`cKehRI"$2!!d,mIXJESJBlE8pAQMQp*+ejbebrhUG! V*Ya*"U'fCN)b(PA@160YrK+L`pV)6a$8%lIVV5`j+G)a#Z@("#Tp&q,2!NbbQdi $H+k#"V0*ThTXf*9d5-ULXH6(`b!kd6F)SF1MmH32j"6B95hUKRXTm('pmm-SGk$ j5h+Da4PR)4+0[c+FNMSrapTh2`1ir"!!'Fd%[S[K3lHX'*%b1H`l#FlZ-JK['q0 %Hh(PBEKRJ(66dXlF$kb&d1%H&!+58*(GEPQB`@8-c`KUmQYBV*Zc)"JCPZZ!r+X @PCmXRBBNDMPR2&%r("D5D*L!c)T(ci5e!BjSa1Drh,CJ#-e3!d,1j-fMCGDFI!+ 'HY,`hU#IVcDVlYhb0r'V[C44E-8M8*Vc#8JB)4U8Ej4FAVrV(Hl2c%[&[%KREA( 'N@&QDNhGZI'i0#Q0&mA2`3Cq"p(i))!KVNH$e!Lrb-[6KjhPl$44[pmNHVbqpGC a#%Je*I5Z)+a4i1Mh`+L"Ur4TPM8b'0`"[UB18A&Z@!b1Xd*#+f#B2`%9bkMK9,D HeDZAC6m[,4*)1$3+4%FZArepB*e-"-C8'AjTCp`hT!m'd5)#Z0Cc,X6"mdm'M"h qX'UYkTNr,*cG+4kCcHP9',iXYTk9S$,"GfD)+8SJU9B%4%-ahLKp`43*jR5Ba5K 48r%(pNci5ENE0EV50l%eY,Z,0+5G%`62`UHr1YCqGML29MmNrQ0rcDYb336p,1K (qTcp-N,C+0"H5#G)`&kNG6`rYq#8RqRY`f6"i5"bm(6,E)CJqhbIh6i"iC-D(Q6 Zk*FQiNlTmpq+LmYirbC0D*4IkpFC'`HfPLSkP%3b,KQqBHl`['kBa[6%F$+K[[R JL8b&pAKVmrl%CX@L5Y-e+m-Pf-4562bf&1&&FI&(J)RZ[Fa,8Y&Ke0!Jirc6EEA -&AcTX#(e!jH`X+mld2[FAD-8"`HMZVpjA@CE@hNPaP1,$V@93j*q-2kpN!"Vi-' (ckYkN5PHmcE)PIZ'[(9*qF6K`3ehJ[,mJ+(c[Nf)T@mTF6k)U-ZV9hD0LXGHm+H 0cUb`"riN1IpQiLFr#aci$@)eQM'ZVcILDM4EGLVQd"lM%Th4hBCKrXE2e*EFXNZ K`9c`AlRBAJHD0riJhX6,MV9"3TNcKINFKKY),ec9m`YpK(c'-b1NT&@91J1$Mr[ eSX6I9cLhfmilQiI)(p#VG11TTrQ`34)'k`RPjQ9F-BXTRS5$"RCrFRe[DN[9VF8 M11TPIR[3U-0(MbfXcPEr@RYC+TM"3%PBVc39"DEr((0RM@`H0mcJYblKZXYH6M- (H-mX*ZmVTlZN*`9(JKd$GL9m&5e151,ACY$()VXfPcRr$P@#%"'1GL!,f46INHP Q+IL2HG6JT'8iNbXi""(AGl6*mQa$[a!EQG%@r9J1"ae&dq#P@1RQBFf%0rKaQ+@ ((92(Zmr#Z*q&K6mlC)j#VVh)UHa[*FX@*RlL$b4MBXFdl*UN4mBF3N4hN!"Xb8D b#qRKB&ce&2ZYGDJp6h%BX-ZiqfLk%'-h#&a*Z&VVfHNk"c&Fc2H08GSHd3(CD&k `4[K6MEEbCAFJiZ#b64##`Ze('*!!@iMIp1Rj%UA,ApU#ZSZq9%K$lTp3L0pBc0# &9`Cq0C6Xd6Q#XI[GRdE#f"8"p0LP!1m4Z&E#e)4)Nc&#E#jCPXB8mQ!3RBFcpp# 1$Z&S-birIhmN(ie"dNKh30'YDFH$GJ&4K'MUAV#A*jZC#cMrGX5jc"6aeNhSei2 UG&NZHM`IibSRQJMQk[$#pe4r5@kX`MmbkP&,1"ed'!C-M!&GUA-iH'TPNhVU*Le "Be95(#S',NBhSQ9Nh8e,jE$5JbDT4h$F8L)H"`UAePQEKZ,G06DMLSB!d(QBpjq fLD9FhLkF5ccD4U)-GHc34j[Aa-I1$6L3!(3@U6'9AU6#Y@fjV4iE3jbHQRarRVR &lSbiLDL5Y3*E1AE64jCQed3(%39kYDf2i3pP,mHG0U2'0m+$8efKlRKh)HIN2bQ f(iDq8@b*AGbP2G$AKRBNVAZ6`2+%fpeNAZNEN!$cUL4@ST6E*DB+E-29X4E(B+` d!YB-R&erDkYaRTf85Al%VR8NMVLP1!%ZE*KGqE!$-BjMkRHC5%b"$56V[D,r,8* cqYieh,+crE#M,U5J5T+C0(9P@(JqMf[E[8hIPE(BB`DJN!$HKiJf[mac0BP4ATF +UpA,5BD@J1b(k3SmX"4kdNLAC-IkhA$YY(e-9ap3PZR*54c@Kmr#Ujq&C4q&R)j )&"T&-!G5-0-X"NeIK!(cASf0Hh[D41A0I`l2bhC4h*Rl*,jRPR5!6J@pUN3N*'a 8MH61djMNL*&',Kj[$f-E-S`V2l)rK9aHTXYZqYP'jV)[kQUC&XaQ!r6!JVA4F5d -[ArZK@b$@MBSLqhC5qd@%Vd`PHL+h@c56iZN#T!!ShXpkpVrJ0LMq,2@Pjj+rY[ *-T0lM%!A-F01UTCFM8MHqZfjdeZl-Mk1P$pr4%[(i3-JiGT0%#Crc)dITCm*P5D -21hYR#iY3)[D@HjJ62BZRf4pZ'EA8Ymcf'iiK"dHiQPZFGpC+cEr1`1pra)V8B$ pZE-[ASc8TQSUmrDAe8+Kf`9k%H6Y2jeCXheEdG[R''cT&2M1peA1ILk!(FApU"& b[),HprF!(4UZVSC2[d$!JkTIq0HVqImjerS%mB-9*-,XTLNZMNF%eHGAcVXD12* j2iQVYjmNVQdY+Z`hE#k3!&Hhkf'aaFjUI3,cVT6JHY%[U5kK'(d#pF*33XSd+p& JJm(NFG"`,H%rkQDj*&lH`(!BAh[Hkal+`X*f(Dr(Vq*[4-I-b0,cXRiek#[+[Di %&YZrd8mB@U+(r93293V-TX[0HKdfVZ#fhqHYN!#I8fQ+VCCfX"53!+K8jJSPbP, kr(e3eGrKjaCCjPMk+"kYALi93DF&11kN!95a(klk@)k+l%k09%ij1U1keB8pqh) [V)8j9G`0'+mUjQ'%*&TQ'He*lcaZ(20lQ%X[D6r2`TLIK68IK8)l1$,1*TKa#rS @183FiHl)Mf4J)H-"Ci4YFGp$bIb$DACSdh2*9Z(bUj*rNJ5K3Bm`cQ[H"HFF4BV m%Q-fFPrNMPe"20m'X$KmZV@U9dI%jTGdSSNq(a3+9!Ahjpm9*iYCrEYBR0"Z'6b 1UI4cXiafi$I4H1MQ2hX+QQl4HLriaPMMG0lfS9Ci'JIkTb'[hD&3-H62mkbELc[ MMM'Z0ISfM`B++*94VAeiL9389LEc'`1P$19&Br*[68UZ(heJDDNZ(V(mrP$$R'X G%[Pb`XRXNcTpkqY5)2dm"1EMQV8[*)d3D5&BVE@`IUkrC#)l%f5RYZJEfPDk@`( &k(TfY$RSreX+!F[R99$UYQN!q0M,QM!0bh+JJ1,S$*,dA0J0C+de5,JR%M3$lKc -jB-)"eRPNbT-PF-A1QL3!+2UH+&djE"'[6G)f$5`f`V'+%4T,PU0([SHNRkY2AQ R(m6A2!S9EC!!l42S82X#-'lUE`*jB'9JjVHj8&aMm[8#ScHq6irD9J`kJ)A6*2- *X%&83`M&j-rC+%j9B+Pk+j5Vk'3Uh+H'acL,0[VbShU-IV&aA%$iIC-K$I1kFKB ",arIXXjjN9S+%&K)HLkqcR"8G*@TqD'f6V-rcm0`jq'l-IK[q+JAf)N!,(5M56e -M+3X'MKehP6A("#Im'Ar$T&"cCRQ%)ANX(b1l0q85h('mfNr!D&IVG4&N!#IUF[ Xa1r#d0f`9A+SebFkpm!E"!!L+Kl#0'D9,eR'hm6bHU@Tkh%kQL-N3c1`LMTArTq BASc`#jEXe!4X$3j"`A,c[VIJ$iBEe$bjD`5"D@lMGP8"aj5B1li)V&5bqfp6L5i KUq%&#RqBr8F9q+kU2VYiJJ60BHFlG0,J6qXC)@PPV*V$32VAN4"pFA8$PkQ(,4j 0`NfUTD3+Sf5Pq&'J3IYFbi82'(h3QJe[4)I2m3kpajRUd)eYNFR0XdiY%$(J#5& Hb,(HX4cTIa[U(+ilV,&e4fH(i`KaB,#4Td6iCF4e)R6L)r0#PN6ZqX8hH'Di'j+ $Rbp216X8MB#p,8Zib!Q4l14CI3jkhY$fa%h1%HqG@mM#+,82XRNE!1e`YfK%r6$ G!iibbCeS`aGd!jXKqe2[QrVciC[lT8L1+LrpIBkH!2%*d0hJ0K-mClB5aqEY2B9 @30*,T-a*P!lEl*U@[mEarU`@Y#h61#Xr!)eE(NqeIbQ(0mTKq,pU*fl24F!Kj0J m9X8HQN1j,!5MS-2$jrQ0rS&'f,Rphdlc&`cC"NlVhel[kT@jkq[2!4[r6(ieH)d HXAl86[pp,!E$@6-41)+"5bUFQ[5a!R1$NAd9p'M+f0r5qRMiZQ8X$HpBMD18U)D f0BP8CkLT1m+RE)ilNr9dYLhRU4DTX&@qIJMr-R%AhQ&N!@0#kBrYc(qrMZKk)pp MSDdi)qfBkJ)UGGb@TGFN[pQRFZ#Qp5hAbK#1Xdr&JpY19Jd-r",&MGTlJXJ1Eb9 NbJe4$Jm%L2'9[K`*L(28kr$8#Fi0q(JUXRVBh,YNPXB)9"ar$ApKFCTS8pEcc@% kM-VFP",5B0T9X*[C#p$pZ3+'IPmCke'lB)5jSb-,EPjqbcZ3!,U`MLXK&`$21TS Lkk*q,-Z"RcPaH8MpbYJI8"dhBCI-N!#Ylq'Md[baRli1b8`e*Gib-`X#[jFk1NH #1K+02S4I@q)pMpQiq6cISl*JhMP@qpl)eNdE!QZ(6Pdq%9rB)N'[r9-lM9U)b9T YrQe)`FCAGMT4bSf-C1L2!&K-XUG8eB$IDic@%%Q#dhE)cP'2eAliBX(-3Ke+YdG &M)[Z8lb&P,qLZK5`epFdaiC1NA-aU(G$iH@RVDR)[EMQJj2"IDYAd209QM5a`c$ 9cZ'TIi8@pVi83P&P18&SZ2p5FMebU@,+*CULm)'d&9BRa-,I4cHZ9dEZUc8kR5C 8%#-BF63K9B96a%m0FcQ$bRP),klSpCc1J1li2)mLGmfFKlX!')id8hf'fiMaC3h @PPR3#8!CV5aT4r#i*X8FR,+Ah!"cU,[5c4MYGaN%QBq&6+a[qj2CSp(epUF#HNH bZCVc5HM2D)I4MIXSr`S62hJKhrb"dNNrV+p&MU#M6Ijf,01h!MB(CK(UI2l5,5K ,AE9Gf,+#HrG4Bj4)kZr"'i03AerFi3[0df`S,bMM2C9F`i,VV)NMl-XVd`SjN!$ 4$EK9$I%$26((IQ*UY-ZL[d3fJ29@5H`R30b!J5'1pRKh,!S0qpIk%6NYfpEcM+Z qADZVY95$br`13U[Z+)eJ&eQ-JbBTNE@K6cDj3leQrA$0%A,GXPliNj&FAKLdb+d YhUEm)c!j9apA1'KDF5IeISAj9FF$P(Jl5HL0ChS@6h6q,d8B3T'Vqk#aAAE4AZr I9qNm0FFl6Y'$cNc9FZ(mhBD,`NcMd8NS!,@*)q(h`%5VLLK1-lbPEIBDlk@BNLY 2YLi("Ba#Nk%)lJC9h)H9dN#Bh$ID`"$'4ICm0JcUGVD0eR9S@,`+C1Dr&m"l[Ub "F8HfU$0j53T#SB5Cd%9UUP0pANBZ+b2`DbcUjB%fZ-GkUD3Icm1K#IKdAaq(5`# S+2X`jZLX+VJhF*2e8cH+P88BraKKB0HMAH@!"-XRk8I)Ph3kB9F6RKc*JlELXm` mE2TNBMX@0r5"[pPfX6S)eXqlhmed*b53!!'cAEGFE[)!q3-"d+MDPEP8efm`bc' 1i4k*-dVB)Cl#erCC2!RPT5i-X'#*aG(GYf0*YLiLAbGc,E8H!0Nb3)kU'&i*6H[ CAJK**LjAjVjbN!$EPLIJ+h(Mej08k3AGm`4[#XiqL4#JN@@A*1NQ2b0fRCc46PE a"13,j`SeZqC'VheIhMYY!(Fia[[8)q)@+@bMT5d9fCSUZH!C2SKR(UB(rY0D(C9 Z3-flG*6(kX#9NG!r02e%A5M*-5pd824Pd"a05+'X26MlQ!YL)jVE8q!)GrCpG3r Kmaeki1Z"#`X,(@$h94[$P81SP9S,F-pS*"iaYZDb8"2FNJ14DrJ,TN8k$E9fJ[c (SJ+(#D0N3(1dMhU-Q41VmVpfZp[5NRHAQHX5CfYP3@b8B&h#B5DGPF#6hC0(VF, +0!INf-b*DHqYk((FYYGi9e'4i[9hGP6FHSQCd-DHjcUL8+Uf)dFk[D"IrRidhfK J-A0mFJ"1(RZY#Z$0THQ$#NHB"CN2kVY)T@&mZ,h#ra8j,[S9*RI"[V$`Hm2*`jP @6hN+k'G&P3F+CCCi@6F0DPDj"0JiYQi,5#GpYT&`GH5[)TYT5E$`KLT[lBeCP!" lPk$$pG[l!bU$FZ8PH4*iKa1b69j,&3(T5cFF#280RpNHC-QYC0rkKp[GX#p6KVj dJc9JMCd(CAPLL,`19%*`db+V8ML`qTd-@YkI@01J19+KZ62$AFihj#38lMiM,Ed I[%hEcYVUhTBGPq`V8(A'@d0R9S+DAQ,11iX8`B#(6&fk`f%[R%X"LFj9KLfG3K, J'UE`mqL!"9cSmQM8'GF,+I`Il[PmcX38[4)-$QB$F%4)LC6-iHeJFE9G)1J5"QL %+'3V)&Fc*k!9-Xfq,9R&BIII'r[Dd*J$K#6L&"[i+iq@[XBq6mJ!aV8!LRD8jmE p5@9ahVFbEm1acYi8Z(r)U9j!$4pij,edI&j*XT!!QIfP0)@fqbF+B5S1QQ(39(k rQY(XKJT&XdIQ+(l&faS)'q3-iEZaDI3CXdGD*%#f",rKhN5,VM0M,0EDm&$X*fc lSZkJfU!1,p5!1BI!ZCJUQ`Mi[BdKNE@HKU8Hl-I,NABhGhLq(0iYllR,aZ&$H2B e1ZKNNEJ8TR[4-6pr9A+E4f$)9j!!5S6c`KEPJdlkG`-ifP!G)hrANEii-XiTaSd 60GQS(XH)DM$&k6cEr1h9`1e0c0f@RU&NK[XApmTJLYZZ![a)19*JJ*HBC$G+Ga+ SUUM[-X4jX-QT65U,l!kM9Sm"LFQ(K5D+XTb,*m&%Bk8Z4IZrTIR5miRMa`+GT[% k@JMp,%VQ!@($UT%-L5k)X2[[-IF!eq[HU+!VaVadrGI-$i8GbZ90`c%,pGbjmIa #VrXINal,jS'S4M$`q0[$'Xi%L-)8f$pqqAfUcrSVb5R5G@l++J*V5@cTcfAlDGX P!b(ZaaZN1MYe-RY'CH"*YqB&9(eBlX1[U[*6[hr(Xi$dh6M&)XKhBeDLhEDR!*K "hIK,1KLmU#kNaHP0pA34a2BjlAE03bMQ#3mPI0%*3`U"2U!REDRbr8[-QNr"4pY $8eji1l'TCE$k"3@`["[*B$brelc$%#`YmKM#ed*V629rJ3lG'PLF6VedLZ0C$cp )CKQeH*pPTkXMKamN+$X'&'DS',5!SRCU)[J*U[Be"0UCRPZdc*f+d4&%Lj1AVLH X&hAql)q&3XmRr8,C*K)%NVSF-mb-cAqC*e`1E,23HM&*F'*9($YbYJ[j*daPG"a dXJKLmQH28TBJ([NAhQXfFB3qrP&jRcQcV(EB2*lT)+(+CG6bcSb0k,&'EG$F)A8 P28VPNjr!@9#(Q02lFf2-4Ke2[qKNN!"`k!b1Ue@,Y0(KjAkNElINcr!Vi$$AI5` 6f-h*,,l)cMfFE6-"*)[Z%S&A+bFdl5@,hYUfUCJ)KHE1Q2+NL*fl1eca998N$Z% UXm2LfqaM,0`rbk3GX%fD&HB-c%Zj9lc@r2D2&&-ci9cIa3M16EHk!PiLS5Z`r8' CHpJ4,Y[TEhp6kCMXYdL%p5!k5MkHdciN+60r(Gl&"T1C!e@DKf,T&DCD`Ubl(96 ,jT!!X$e[5#9Z,5U#GdB*a(kdm6(UKYCEeL@LG#`hhmN%6iLe45JN1"2)rNeNj4H pG(E'3abh3h(1fk+Acm0mCq(3K(iG'i$@[p&G#HCJaMDGH4$D#$J(FY+iK0C!Z9k R[+SLepRaqMJk-1c&UA%P@EKJ'NCb@rZK2Kr8299-8R(&JGFPKcM"p5l-&43,kMN q'GYK0"N)iH-5Il,"-Q!UafDNABTNdM91k##q'm*)!FePGD(Q3K8fXJ!%McF5mAY $pbLJVa%q$EHUr2b5I3pm#LSpHE&5+bEF5C4Bip"bdh,LqAHH+bEHMQ4)QZcLIBT PU9fd6bNKK5T$1A3DZM@9MlJF,"RIBX&J,j8Qi"+"mIZT9i2)()DT'L,C[V[*H$) LRcZ59!2aSVjpBMIQ2CL2@Kb[rLBE"ilcTMfh6-fp4(pkTp4YbJ&6bSF!ip'AaJ1 +*N!"*0)PJ0UachKCF32!h*!!G9D%K62[AqBdi90`%aMQM4LYYX-q+8k(2RElJ6( c!25d5&6pe`m-Bj'9r$-k[MR,fS9DKRC84k1aLF,AfGld6*rfX2+pV%mE1YpNCp6 fH)iBl#T-i4qNBUr2m06HTJf5SjBpm!Ql9NhT*bNQ$@LQ"Y3DQ1'je[TSKDqr%dl #,VS-qTTqr1(p(368DMVkE+kBa#Kr&TqV3+Z#6l,+,q1LHa$)E%*5dPr83l+lHIB S3cbNk42N%2f*CXeA%eKA",Sr*AX&RmTQqYbGebXFjUqHKH3lG2p(5Zr'FG)'02S !rFKG[ilkkkhV5j!!-YF4@U)"DlphFY8*4ZPMQTh,dmI0'XGr("ZP@0!0@5#ld81 [EMAlhph'6T(aabIZcqI&AKZj&rH--U6)83Z3!&iFbXaRViDC-,icaF$c"(R`e@I *(2CHc$cjL+Ti[6,-e)9-6"k%F(#aE"Ajk$8(ZVXX+`BU,N3-'@1d#plj&Aqc,D5 'mcb,b--49m-EmB+'H`Dh%PI4h)JN@LdM,X&R1X8FP2,&Vf8PqN1D3DdI8Tq2VIZ -d,QZJ[2$iPXiSe5b3U#[EK"FMkhJ+fEd$M-h`TR"YbmleDKAZd4,GCfebmPQ,[4 P@mL"+pJ'ei"0,%-!l*Rj9r()ACIqiGHLCqA93AdefKBM4U(*4ENBrIq#MVT-Md0 CClBT*USekClZ8lq%Rh$#l*3jd3cTEYKf5[IhFR$U@YDFr1@9',#%#YSccBj'EM4 D"p-8U%8U'j@[8-DMQRk*j0flR&F4%HS15b6XaP5$4iEDUi-IF"N[9#(Ire`0Re@ r5Pl@Xm)8A"%)rc@U"kCS24B@@M6fI-rl$k0c*iKla$B"PZ5A,AUjCPh2f%0eFJS $Jm)4IK8a,P-Ic"H`dI*icQ#EkVZjjh'`%5''J3LAHeRhTfh-$19-Q%CJ(5d8eL6 QC@`h8*)e`5Hf3imk)2k6IH0%phUU+*kd,qQDALDfJq%!DjGMECf&G1AqCk@a"b6 ")+l'"-h'#Xkb9,-L)Cfb'IHiGS1`6(S@,BRBZqF&,hFi!Pp#km%F5Q(-PMG@Vj( GESP)ii$mFQB4H#rib9G9SVTLpLLBF[hMQhlTMdGK3q$0L1cDm,e4$CSj(!E)YQ& hG*@l`5#[KmMKP@iF34jS#`T-"Z%iX4(EN!$*EkTq@bAJ2@IB&"Z1,+TdR2)6D!M Xj)5J+YLq%CLfaT)V[$[d-dH&&rP%I#FBIrBH@l)`P&aZEdmkU21JE(pcU6ID,`( F2Ll@d2pa$r"mYX,('FK[!H)dTU`#`F`H+%rFAX$2YDAK'0Q#!&kK0P)5(1RSLf4 Q4*!!%dSa%00@Tf0!@Sm2!-&j+apmE-Pi'(e5&,'MK6&kjNmk9p"A`$AbN@mEJjY dip+J"Zr)JmL*bAqJqJSE@*)%XE)H`&dBh$#L!Hkp'I8$IS(#L6DVHejaJhMHcRE r0G'X[(bj0R0p+KV"VLBq@'$eDr(bhfJ[h%$MlN%JJbEb'lP@(IL,"lj(-`EVAXP LB@$8DkrIKIjC5)QQM5")Q'AldkM)%XXVJ$@d5Q0BD@ULZVY`k[U2R,c`#(UKm"G "ibe-$NPa@jTQ!M!ZIdilVhj9C%cXD#Z(!Kq2HP90,*5IIN'FLI#Q0S$`Ai8MBSk D9!$ZNT!!Fkf,DR#A'C%FIRE+D9AF`S8l-paMmJXZ$L[1fFI-)bFf!bpIa$Er!pd e!PLqP9*fL(P%'J5p-r6Xr"1%Rf`*Y"+!55"DFlYF*E(ZZ@1UEFr$6bIKTT(iDG" N6&1-FG6dI"-Lc%hD1!NJJrCm9RNQ8@r+E6"R`+,kIRmrf"C8QUGal'G`)`DHaH` G65cN4M#EHDhh3Pl2Cap4!ha8k+KJCIa28,-lpEHXCZ)@3HNYS-(rC"1JKNUHj"r dNV#'HfT344``(6+%Qc!#+G&a$P"XS25%0I',)K%4%!1N9Lr(I`f'0RfDFi`[q*@ @UYmHH*mi"p8iS8j'R8!((FLambR&jqUjH(,9h94%bahX6(2L[JYBBIDAf+'icS+ #B-LUAQZ'm9b6B,iIlE"b)+fM'Y9I-M,5V8@aqD1KmNK#,X3VjGS[-H)TMq@560h Vd*pVe*I'h"N5jXG,DQGIV"&A'haP@N`idFY`h"lCGqeTeJ63T2U9UeSJVD(N+C& [KY[hYRIMDaejrMI(DckG1$ah-BqLrD0-T@9rK!D9"G'"j3Ti5U#A$0Xe3%PR!lV )LaAC8!"dKQrc"QVRcpMjq"e!qZ'6%l%#GD*UTU$$R2EL@0j%&#)ITDSlEcK8DY, K`R'Gi40!B0KZXjY*"hp#mYdrebE8j9CX!EFDKG0VM`"I#&rRS$&3Qbb#iM4%02m BSQ'51[NL6f%lm0i"6d[4qh+86brHIM*bZX2-bi9p[AY*AUQe$GGE@KaLaSLQ'GM TYV1-Ab68)m`rYJ331XeQ8Nr*U3q"MPh5e4j4e*6'pldX(jm2@-&'J0YjFTcQDNj D%0paYRJmY)4dpbCre0p025q$KEZlSf9[$-6kfL&3ApKch1@)pV(20M!@djZp'Xp 9+9+NpR9%XQiAld0YX3NiLiRhfZ4fS[HU&CXNPJNE-#G1)E"SBlPFCPh3IAE@&E" 5PdD,PiPCcIBT%2UB%[pDUlE-cpRe!LR`!Y`jZCqJV-mK09Di!L#F1rR+`QcBciM H11hPkcdISmcVcHeXj%jZEdG3VdSHK5K*'+6`[B0UTrER"K4GU&Gar8c9[4Xq!$G S@DRk$8`HPX-pdb@k3K#ri5$Frh!Gm0N8hFKIiB(&E+9#RSHHqPDSS'PD4-AH+IU 6Y*5aY*b-21l"@jaE$D(CV[*R8##@eHVb&4*!)@2XHSL["KrHjTm+Vj'#k)"KcEZ &`iIiDrVbj)Y16DA+8Y%F*,efN!"Fc+Dk&Tk+H0#B1Y`0GT!!B%[D"Kd0YC(9,,B VDV8,@jDr1qGmVjDqYJP(`"kfhqN(-R3!KPj"rGTN[c5*hh*4,8Z3!,Yh*N0BA@U -MG*1,(KT[bCUrJh+c08"@Yc@jXFe(2JXbZN'hFr$d2jq(T!!dr2e%YUlQ(ZMS+Z AC[[P4+A3'0&C3KC*2`LL1Uk"IZ$0RAEDfJ5@rI,JrYk@eQV(6IHYVb!CkNDJ!(r 1'1J0+Me'!L-!M-2VSRJqS2'&A&#Pk0BjKB9qBdANJLpf#@3&PPX9+dXjUU[SmCS e043j+[`2NE"C$q0-!TiBp'#BAK9PeVlIm55L3IJ'MX4I!@b3!%PY"C33r"eGfC@ ',#YP$`HH'f8hDqR&&!dMkFD0Z1`3"p65Mq'&q$K6!U(KCNG9RPj3&8KY,dpY1a$ IFmAaKKifJrm-c$NQjd$M*hqM$(4-Hp0,,,G'-D`Nf[kJ@TGq2bf82US'p%,r&B$ IVUJ6c@pX%addi6$##8CH,1YI[%2'LS+Z@X#cKpBSJ4lA1pVJ0bVkc6HVSY(RX&+ ,IQ1Z2[QV)1N#fA)R[K+Db%G5`NX2UMhC"dj',FUc@4G02aQ(*"!SC84[$RqdbSM #"DKZ,TEr2A!FIH0ML*F#M%efjeHkdcGRA$0cm9YJh4SHFrX-AN8k9pX%#BCB'DK dXR-(bb+XG'6q&eCb(9,j-aV,$fbXbVZI+Kef)FGajaJd@baZJc-Ek6(X!kH`[BU `ZMKQ1'DmjG3Sm&!VHR*LFlDAc96@34bIfTk)IH+8iV#($!FEP'1QHZqHiE)IjM0 q2lEeaAbchV(UN4RklkPrTYpKXrcEPGL5ZSZqMbL6VX3-Za[@!`5a0#*B,0A)HL1 KMNE"d()aU3RM#HGTqe84(&CQL'lqCbD`[E9#ekmY69GdZILM%Y()d'*4h1-rm3( NTDZKXMLJkV+q[B`1kjM$Ap-M04lcc9A)IRjG,YE%(R)H@Fhr$8*G8%TG@M$L$HB P2*NaLbP!NfP%[m"R)Q"MpSEhF#D6q+(CceJ[&I02$P%T-[AdI"Iha,H-p151F+I D%B#),jkq!3[#jd*5bE2k+F0ZZQ&$6eEL*-,G5,0%jY2MDbJ$PY3-P,d*cAk)JV! Qe9Y"crml-J'Yri*aAA26,9PIS$IT[%"NaM3m4L55&H`ePkaIdffU(Up#&e(Sbbl R""YeM,hh"dacB)q@*)S"4,q'a(Z`HIIDSF`d&%P25Ym&5SS[+&9,Uqk+d5VB6I# +)P@Y11a`i!PMl16TR0cLD[$R%ep2)K65bXm6NSbpXjcP@!D'MXKA6jRp!C,-rS! EdA$@e40CP@[r&`Y`6D%Gj(Z3!)h&9!@mT1[a9B!aJIpq3ZFr(!j&B&cGaLahTc$ !pU2Q9[f+k&)c0UM#,Ucbl`&r6A&(MTa9!rZVXC)Bq"`+fl,EG8$$QKYG*2p*X[C *BVIe1Xm"rh6%h%B33a1KYkd`1jE5qS&UccbP4#%Ye8cH09TJqB14Hh6)4NFB9q! '+,mFLR`EPI`!KKqNeNB8"a+'KdP8`$pR6jmNhY(X6`"VaNifl-aBTrD"VQI'+JB aLSVLiL5IX5Q@4`f'RrKEYM@mmEh6(P)9VmQ5hLr[ijRp[DI9DqR-(CS65Xdp3AB 0HM&e1Bki@+p%R-MdKcq%mdfjpq21PCK3qVldD-@SJf,0jTFi"#k2@@VRF`Y&b6Y &Abd1G4i)92%eAh+NPcb[9L&,#UFjQEDVCc$'raTA)ZZ0RcpqTkEF"'imAi-Z+a3 `#MM%F&$*j`#T3d#H85k+MN))MHZ12Eq,#QlbGFMK$GQ,*"%p#K9E[aJAfG*k)$P "6+l9"2m+P1((k,hpipcSd8SH3[S1Fhj#LD+dB)&0cNaY4A6RE,R`)0jbh3V#cZa Y1D%CS&fLDUYe!f6khJY4k@jc[#",B4'BD+Yp2eb-9bC`i&hr9cEbq)RNPdLK0`Y +-cPb+,2i%2*&)+!!QDa9fVIT-0MSh&CiNlT(*pY626)eki3qfqlDF0fHfML)pN& MGh!PX1bm'29jBM,L#a1Y&hppJ2C4+R*hd6eD9G$42dZ2@GTN2XD4N!"k*IG$DTq IG$`&G(9hAbc!dFlLY4Mf#N4r6QH-cTH+0L(1"MA2l#hP"TY44K-DHR-*j&bXKY4 bU2bA9e(XQ-Nl&6c"cp$j'ic+T%f0NY0rMUE6ZMEL6Q83B$j2``"kbhZ*JaQB("i U+61QZSM9XN'KiEI@I&&DeR&5*K[hN!!3i#qpKGNE'kiJU0m(6p[dB$%+DBP&Jm' $U1Eaif4[ZA(#d-9$p%c*+Q#Z"Zm*mm0eN!#`!L6kRQ(jLR#D`,a635c)6-$MU,B 1Y(I-)X`'S,A+&5cbmE+XdG,,d0MjJb2V9I$+JEJS59lJZ')2Em3X[5(eBNbZQHN @hYT80YRF8#1eri&5eIh6me#MfkCT[P)kJBj-EihE&a&Z)Di[kaKG"kCEBAdqP$4 @-aY"NNeF)PA@JYUR#3haa(p@fIMKD96f-'m!CaKQ[P&S)R0GlC!!JR99id&*Q[, 1q18hU&ZL#-@200Sj2aH5pQrCP[@eBd*p21b@c*I%Td[AkT%J9,J8lPeM-K0Cj(m U`X`e6k@P@PMPEPh'eF#`h$iSK#T1`bi-SQJ(S9mGXJ9PK1V@jYG'BihahH['l0a CeVqC40llC-r''k,1(1(DiCd3`$$Y'L*BdpKQS#9'hb*HfU3rdlD6e$NppGU!Ap* `FK)''(frcHV2E`'$r#fJJYhH9X-C*V0fP)@dYLC%c6q"Y"h*a`'#QAa5"p+Y53J ed%IF#bj5ql0rIMHj8b!1V3ZfK+R+Tp&2j`k)pG3Yl%%D3!"%ai,%JblCI5#[ M`(rEda9S)4"fi$A-AI2&bL[m((%dF&IGX0(X8&9XU'8@akMr*j&E2Lar'!Smr)X C)dMKH#1k%5L)K!Ufm[T5Zae*CbKk`lV*Bjd!JXc4YlAfpLAS(e)'DAUKfTHTY-M @!Gpf9I[-,md`EkFVS&)4XAVBZp-SkDErILBDJ##&i2E-jPl*%S3qUjNVAhi,!Fc C`VPe*`Dq%C!!H3KP&ha+JEpQ#6A,&8BRj+FaH02SFP"Y(,rQJ#@hYLPb66"[%"8 lX*&KEDVQbQl+#0,I'cbi,&aI5J4b,kdQ*iQ$k[ffpRd[d@!B2r4TEmABTkY4rYM M0T3"eQ&XL3lfl'6M$jB6b#1bD8Gc#-lb6Y-Ghb@5PGGkI#UpCS'03iLlRMI#Yl6 *[B0rLE4+FA0SN!!M9VV0@h@erMA$Uq"&qKI#FRHqbJLa$j+h3V6D&%k0YQ#JAQG I&HB"dMZaQ@CTaCdG)fk-iH*#'ql6Bim,HcdqJN-c43l*qP8h*+@`H!Gj2[+9V4e V!apBQ2Xl@aQXq4qHCfML,p3rTHSdfd"BC96G!GrN,L4&+dlY[4Hb(qAhNFH#!&e K&IRVMFC%#-`aQkqT%9hj%lm`0lS,pj'5D0$ZR)Xi6B1EY+U1#r$%MBXZhHR*Bid bm[HS42+%+SI`29BLjFA-9m2Cef-5!iq`1am+RM%a)*r$[lTm6-H4&0Cd!hC[!h% 9)#qX+$PhZmk#U#AIcP*MNd*`Cq$MK08p03,d!(mRRhK60PDi4P16EIfL[p5JI6` &X2D*YH8iQ,YejQ`8!hNlU3,!0e$$$`bTdAerS+ZqIlEr&r@Nl%"'pd,A@)i,+FD jXUNEBG9eI(A4ab@RMIRB*(4lRjq*M#XEiPK8i+qpjHJbM-%!K#(#f`HAEdYG(kT GNRh!@@mkN`["!UAlbfi$GPml9P)B6C268FIU#HDFGp$34bdS,Vb5UP*)'I#2N!# h6'#LD-+c1)`)TpSN9#N6`hM9TPk`%PRP2GM#e#Pc0D#hKDET8-4@C*!!5$ajFUa e#0EXH@#rCJ'dmIN[pRUCZU2jIR6S(HN5X*IXrG'RZm1l$f(k"J%EKRrQF*CU1,P !fqX"k6J`h4KIN!"8ZE0+0TEf$@X+)r*[!NHQAk@Z"@L-)(N#XfDj'+BH4hHmb@1 Jc4)Rd"C4fF2@Q))XlAQU,V1[!VR(keCr,ICPBdNG%)QK'U@LD))qfM24Y4%ME(+ ZrZ%pBSI,mmCl1Zk8fi-AC&D0bGbpekh8PXHrr%K0BM+c#`)4!Em`a#MjUT!!CPJ 'DCV+lmFR`hATK[Y9F"J2ZPb)BK0qM`D(8iRj*RDfH@2ZBi+dpN*eG(9,"kj#Q,L 1-VRSKhIRFr#IiVfG1f9Ge$Y"fHAlR%!qe43MSAQP$[ED[NHF2l!LRNP-4ZqHm&E 1"04'+pR")R$dmHc'@0"8JfZ!ddF-V5!,mJEACMTNLGI4KT1FS#A*DYZ2+Ja`C+k LbZF&i9!5@14'r56E),Nk+U3h1+PZpYM4BQfqD-F%qlRM!9(eKe38F(+L6H$l$HC K8LSU25a6pVZ8Ul$p$+33pV**B0L,!$39Z-4E3&R@VKZQD!1$S@4p$-lhUm2Aqb0 E)U`5h)Bfq'&1L2C8I+lC+Di`ZXqCB&YNU,&A`b3Bi&@@TM`5`ammd49kj20!apX m3-)*J(hm(k4S5D91XNf5iNA2TqH+F@*08'*F2NAK8lr[-r2JLclY4K00LU`A2qX hj&0#91[cXjEA"#Y!e+J5P((`MfJcdV4qrHfc0,*Z,hF"1(5iT)$mY5&GlmJMhAh 3rb(`N!"D!EAL[9Urc!5mYEab`8KAYKT$M4D8i@5PK+CL*%d4cTPXTmpNEbP5%mr 6R(i9c5CG8(CKIpa'(-X`Xred6UNI'%T+aMC[!'KqrJR@1KZj'M`8FjaPdF'CAFU c)m+q)FJ9QkG0[Z#qQqZ@c2L6-RP)a"A@Y,SGTk#5ecCGfdl&25d#XYpa-f6C*kL pj5PKJqhE&lJ#ciT5`Jh5cj4*Ip0N3PIUAh1JF9AM%DMkZA$A*2!'Drj9QM&Tcm2 8iRiHY&2cpK6`hq[Ke(&#IFZ6DYb-VQ50,NG"(GFMb1+q+)2E&,&10%ClpUNZ"$Y f&bdPqALMNFC8UjGeS8B5la'"cYS)C4&4Cek02(U+X0$hU0fX(J5`*Q2ia2b&JYa c6Xf#e)X2h639"(U5Z'fL*`2HMG,Sf,a!9L4H5cQQC[a`T%T-l+[XXR&9I*Hh2c9 c8MF&Q,6f1k(Pp,mTY[NKHB,Va#&icJ"YRf$-`PjBhiX%pIDhV&RXCX6'5bf'h&6 NYlB$a3eaib$LTm(GY*@qPh3jPdNZr`UFmq)M6Z0BUi-,0MG-PMhETR3&`Ibk`%` L)p-$KqcP#lrEU89Bk6eRA$G3PMZ'CJcJRc,$'S@+IfBU63pGjVA%DKE"JVGZF#8 hIChYdlSb9Am[VZjT)eij!NUU5BlmErHfPk@U@GE5RTJh[!R[Bj(ldCSQUYXm!6& 8*pbirercm1N)rRSKhRHJ-SaUTYcE`H#i5Hi3rYMlM"ep@"3PqEJYdTFN$ALAJLi rB-UeBa'-EdBB5X1U0cSFqiirTH5N*RX-qSMpdU4h69@)3"ld3ZZ,!L6JHD1YqSR K9ANG5MR2+VD'Xffi!C!!'3A1fkRZ96`(BKkd,RVbir,D*"3IK2Y3qL4,RFcJP6p HJ8MJR-M$LM("DlP[NMc)VRJrULJeGkV!NrZTa!Y6RKbcDr#M-Qf$Yqf2PMQXa9B rDlAJUr(QJNh)Chdm((LbTj!!a@emLfZq68hK`i,a2(bF2,PjeqV@&d1arbD[T`m XDp38Y4clQMM$J%"#(Q94%#rpfi(%R8k%K"AB)YF5jq'3!*X&[$efj4&*4L#HN!# kl!Gr3mMLdmd2H`GkQaF%P2[DLH3@8Y`VU0[8(qMGa3rUjN99I1e9*4YPlh,UVr" 'GddP2*STpM*ffarei-lpN!!fppP!(db12#*Pbad09fpjA4H8Iba@NcEh3ZrMcC3 X"6!jDH[PZj@dZbIL3QJIGJGBHXMNIC)+e(J3l9E96VmC3EN!TG!S%eD,*PRG98b kD0E%NpV!pY9`)MPCEr8Phe6HCCTZT%j#JG341a`"6Ld$@p,%5l8S(J`Jaib+QpL [01q`T'LBE"kU,a$m)&mN@fl[ZZrBr'+d-FC8kmU4ELe5Kd5TXa2BBhIV-*V9KIS cf2GbXd)&Z1,G##H"pTGd)PJDHU(KjmHK9SE%ba0Y%c&$Ma"@paT1323p*5'hRj1 2NZ16(PbT3!(%f#AakM8#q#fZdjam#j2I3C+8pZ+0S@Q`-+#Q("m5B9&Q+pLccbb GF`083dbqHHLX$@2d'5A%Smk"L%EK&@[@AIiNV6'eq@Ba'iHkAIpZF!rH-EMekZ- #V8MA2BL$3#G,lq'%i4TmIYGFKFYLC-4YVpaU[L1Q!fHcYhZ$K#c$5KCkQC`AM"5 *Br"Dlk[1N!#D&Yl91mcp"l$5"EcM60m[bLbe+RE,,SaB9PkBVQZ#-ZV&2P3*rNZ rD8)#RiqXVfdq2c@Sh)ld,Ve3FRVAT`TfKN3&)Fh44h`*8fRJVJl3IlPrY[23)5f Gjli%)AGSPh,#HB+8,9%-j"VS*VP,Bi6id,24,bTkmQ(pGhGrh2ZE1JJQE62`8Up [QF,+*cL0!@LJ4&ISE"A)NP`F+F6&*a)&Ki0T&XN%,JFLTCI2bRcZZ6iLDTPpfq% KTULcqRa5VcG0@6%,UaM%pQB!qAJEiVC[2A+G,@!plV`#h3-[kpP2c-HqGBr6D4* �S-KPBkXMDZT9T*IkAjpb43D``q@"HT9CUdbP5E!TF&QSpE3LdD*8ZC'FE[pGp m'0Fe2bjrlViXVh556KPSk"l2pbm'bF,$Dp$B@m0-f-aqVUDrr6BIl9I3e8P8llU `,-RGT@r`E(ZEaP4L35jLfRM"@X5R&k&4*-bXi2A""EHTc9Y4+M)5`8djp@GJh@h 'F8K$ilZeY5r"ZiBK23Rkk+@[4aIZ9h3$1aLSERDZ2)R#`fK#MG8p-J2hj1Na61X LV%fU0TY3S)FR9NL,j8VR2ULdU$P0d'Uh@&8rAD6lV[al``,mK'[-@6U6,C%PmJ- iMcZ93C3h0K'haHk2bb(0V$2RX6I`LJ0X(1DiQ0NN9)hSVUmMe`!KX5QA8IkI(dS I%6k[QljHQ'!f[U,HrRq%PG9[@V$$j"*q"L1RGN"%e1#6M8ah!4ULk(m&p,GE[d$ 'ea[iC[m$pU!b!fB!-l!dUH+DZra[M+(&rc'-,MQShR&`)0X!c+6[l9kdN!")j8N RFDZB&S@p8MU#T'f6!F'`)KL5BBFe8ALZDZ0Da[cl$45&5+AYFkm9ppDP0AQqqkd BBcMDq!lG)a2LM3PGc(U,*@-KihSA(UKdbD%qdT)*HK1J5`J0H@SZmmhi)KMK4ip T,)k*Ghp'E$NRidMI*$r3'G,3#Hk'iNej!Tall1YSh)KR1SB03!HMcT35k9Jmc+Q @!@M,Y)+r9$)$#LAFZKY,D#F9X%fY!!p1-*YNAS(6q#F2lLALN3ifBmr1"YEHU-j 1r5@4,&,0VZXpGl3ci2'HQmX8'b@DP-"`'q6"2lLMbL-*[ETH[(['L1(@"1Z,9b# D,rh+i'GhRr"$A@lT-d$IH3J`UaE-&ihSTP@!&3A`!Uj4Q59QaP4@iR3*JG2)6fX [`!bqHCPqN5G#P@PTcMhCPE862-1GM)%Hh)M%@),r)ePXmfZKpQBaUb1*iq9I#JK $&L3meS6&KGl[qf329K-L'jGJqPX@QAh++kEI!IcTik!1hr+Kb,KAd3Dr4R#BicT LNdq")pKDc$dZ%ZYY!C2h-RlZ%2hG3#TkiP4P6Gj-5V[BLhpCk#,$"8R$DZF* h8cHB"DI8RcPIpjfU0&Bh)!k8(5P#Qpq"Ci`@N4EaUcAiLLGNb+X0Y53R"KV+lMi @XS8#K9XNMVKYY@$*p9QaK2l`cmh0RYG@482r@GcS@[[HadV1QVEZm0$4eGHa0k@ ZI!12#NSi3)k8$6+"Q6CfP1VaYXRffU+c9(R4fD"`ND%adX)!q))QJ+p&a0aDHj% JU5f5KILCd,i3'V+a15JpmPk0Z$`)[YeM@+YGA6M*rc$N5J&Tf8lZe[J%q1U'dL$ qURj#mCfk8dqQ)Mr0VSYJ3SQM!ABbaY6j3N'*a2Dpc3*j&"AJL6biPE"1cc9qS"K V#B4iG'8H'[0UfBdK2J(`30NV0%!'[CD3!,GP9k'pCa*3p!J4a[M85$kb,$e4d'D T1T88UMA-rBi6A+FV0fN+C-%V9+JVEP04hHq4#QlMb,03A@%!+0`!Im@Nfa"A'"4 @mfd6[j8SGR"J1X6%M&cRqJI'j3fle(R&Y(GCBQ@@HdmNk[lG$T)Dmh)hkfU2*hj j`b0"9`NVYFd2l88b$9V&5,RNKjebQ,P3rJH[)P)@dK$5UdHbbC+%k9#P5ZY!U%I F1HaNdiU2"B9E550je)(l4SZ!SD&@@5h,Tm4D$06jLQc2cZ1aHhTf$D&DK!!Ce[Z C3JqpH*rl%DX"f&4$E8hDcS9$j%a'pSQB6Ie)$qa'@&hVjje"6!"cGJCCPe),X!r ,B1c"Gc8&6ZJ,%$ep`YCBG'`0HFm`TTV&F2X%"ahRI(dYC,fZh)a'MP1X)Hr(5eU 5ih'e(a)k(m`V62#V4JhV6p52l"Y#m1`R!6K9!bL6AjS(Um$kVHmKIdpSar0,U3h 4!C-Tj[@DeFSVfK`b[aH"S51cZRejT*-*fb8F%Mch@[f4G15(5cp5-@Bij'#'S&U EaA"89$@*h9C2Ir4TEmABTkY4rYMM0T3"eQ&XL4XY4Lq",b38B"S!B+I@X$DD3U9 VqKKXi#k(drU2pL`'eqiNH)5i2Z[CeBH0)"F1-01`[,mGErJdEckbfheBC-e[%j1 $Xe52`-AZQ$CTQibde"4b3#PRQkVT05[GD9eh,DMCepp&mF-`-TeDK@6),h3he#% ATlX$8J,3B-jH4&#ZZhA9"8-(,fm3NSFMJrdm1T'MFZhpQfdq%QDcf$JVj)AcdPX 1q0BJB#58dhr@$Vcm@PZH%!d-H4C[TaUF8"(l`2l0Fb)l6$#3!#@KSfY2M$$KGXU bcq3-`GY4#jB!CHMI3rZHMkiHQi)j!*UYKVI%Iq-jXYGG"%cAHDLU-V#YY&cY'Z@ 08[*CD8XPNN-XmmA"kmN8e5p3',,`3*8(,@*B80GqQYVdNm'V-LV-J4`#iQ8)Xq( RhFlfPkl&*X[05FhUR"HeZN+24E)EC3[@A*C#`l61h"FSKXB(#4iii0qf(C@2m,8 rEVDZhBdI`2h#iPr!I+fm*MNHaFY2i%*4&UiBQ,fIm(a)q6%E2MqjL6)15j`%)9i @-55AF!3D"V`ZeLKIeG+iKdj'["@P4)P`d@&DI+d0mD46rAC&(4Q`ipMS5j6Q&V# cH!BX[2(h(c8Ia85Q0e&aqT%b1j1M1X[I0)LVD)q&'emj8J+KJ+9ZUK6JDe1UK8e f-k$M#ZKjiERr+fBr1*-8lZ5c2'Ni!JJhbf6%0a+[#Cd"!fYb%6+QTDV8VBX3mdD %E$%Q[U$r6+ZdlU0bV8Y[U+r&[TXTpY#$dEjc`#4acE0jK'lim5j+P,P$a-EMJ6L ekb+[#D)6E!1bUK`CIBa-jLA*XL$fLrk-5VhT%0V48$FAZIZiDU%l')S5q+lN86b 1B(),35D3!$T,66[jN!$#dqGNU@2`Hd9raC,FK,*RKe2@!I+K%6XD9B2XkkRh@p+ KN`@'$(,dYe5$#j@Y1kX9T`,ZNXr[0B5[+NDFfeVh"UfK$chiKJ,br4Apd9SVT@% ,K3l3K3FrFFDpj48GCjB*eE'EK'lmbC-e-qrfIBqL%3R!k6bJBrHQDhqVjKM+dR1 5qC4mVXDFj*R5$5dp2QHZ$9qY[!m6Q%6E5r'NlM`&BQD$3S0Pr-XL(9!U9'6"rU6 E5hT8ZCK(A6iUC9$pBccK+`reLrdm1QK![mSP,L18PP@I5qHSblUUBpaQXS4`H9P qrch16D&`YZBF'UDm)Gq8ij'Z1"q$,k[iHTmfB,hqK*0YZJf+3-P`0!6ALNja48& 2TH80PH('(lejS-3+Ipj5,TejMM@+A[pc`qM"cM)dZcAlCQlFie&d,UPBDJh`jSj BYd@1@'8XG,62RZ"[h(VD)bmL5a9GqPJMSUSDSfI#5[h3ed@GR5BJiFk4V46GT+S Ma`NB`l@[ICJ%Y8hUJ4-U1-S@(@%mSS)T#aQIX%6''Y3[$V9"k[Bd$mHK2&ZXD'a K-%A2"5!kaa82aeMq@&2jhdkjD1aU$BVpPkLbFY3Jl(md,Gj"UQ3f5V9R,arP`"m RdZ9eFbch&c&B6UD'-G@C-qi(mEf)hmr&5VF1%I*KC@4)pDS0eN0RmkG@'A(kpjC L-GkDRNqAiqeZhq6XR4iTJh(J!9mFRNPDD*h)h41,'@I@fSBHZ2"FeM&ZFd(jdf* fCPSZ0X,b$`bmK*C)0rpZLa2qlHdpeZlAG5d+q,f%K&NKq5b'1!6%)`5L56-Ij8- "rIlPE9Gb(,`dHU%(GH11",Z3!28,,UYd!,+%G!2dk@6kXeK2N!"4)CL(`m%`&a8 $l6ZF2XHMIcE$ab`p[pDSQ1SG+$$d!TQ,*RBjQp(Zak9[qCQ#RV*[-k)Qj#MB9AE bpP$TBjV"!42Q0Z&2He[%cFNUER',a[&lEa+e`mS(3FGfffZ3!0U"heBeh1UEL1k L4TqJe*,rEIpN3&K@iLkQ%aAR[Y)5,UXb@f#GQ%eEHblYMcK`8[cLMMTrcRid)dB @@I`Q8@GUh`+#L!2aRX#PPMaBdSI'@lBjVc#*M-)k5V#L%KD!eQITX5S(9(h8EdD +i[R@qPZX14bXQUehB2"L`&mHUX1"G*&rc)B6YmiD-lJ6Tbe[ap[U$6m29@RjqZJ !fKTI'bbrr[(c2[Fc!LbLe5X*j@,4mI-``REH1PCi'[pNfSbp$ekTc)2jMZXaVaD dH,"-D(GfAeHBFfA*`4j9AREbpkDY!(jCRZ`rjQ[VZRZH[bXNXTEj$piaiKl4#SA Y-Z853+QC#Bq%T+"-[Z`2aq49MI[2Lc6+SSQ!G*fb&QHED`XjAZKf$$D5"S)dLN6 !q5ej1,-2qZI-MYAX&45@Zj!!54("N!#a"h6)%#DdCDbZkL+a8@IF'H$#8*'&b2i 8i1b5(@-*+SqEbY!A8pIU2J&+'4"1dYpV#$,drN#BZHhPFV#@`QG'0,&pmmE'RqJ 0,`$YqPJR[Zl,p5H*#$lkGfdIXM8hhR1a[krM[Q@F(NhRBdIZM"bb(b94!IkJQ[M T3$QJBk#6)IjaXqr2p)AAc23!mXqlb`b)&DkY+aEeq`q88U,"2S!TmN2LN!#JIhB B8X2LH*!!fj60G-51%#1mPPUT@MIYMQN"6C!!GI$TKdFU"!h`MS09GE&(YV3p`03 "r*-9"`Y``+'AFN59dT!!TDYRIedTp-3UhZmAScRYc+,T4dj*e*MQ8+r(T*'8L$N YCd+@9ST-(0U+5#RZ2G5U0L%cIEYD!3VKQ@Qr9+@jJc[f#cf9(PIaR()Ne82$BIF m0185US`GH$3lp[l[DQXLN3YdXUqcqT1B60fX[2TSH%C9324+cPE`N!#GYj!!)Zb 22qKIlTQZ5Tp%Q3AN8(RdeaD6,eraBJ8Vl-EI"iX)k-4FLe&GU+-#cC*AVq[cXcf $A[$`AK+8LYdUd4qXTfkDh+$B)G#S6HSMpFVN%ME+*%Pl+-'L@V)IMZPZ@UKZ3l8 !p5k2a'4`Sr*N96U9R)Q,(P1hG'MZ+a8[Vf-f#*iJ)C`$rD9mF$4qAHF8JH$f(e! *9A1UFC4cV!3Cfqk"`JdAbee*@-N143kAIJ"Z"6i+!(M,+f20@Lh[P'e%2pG5QL6 BM[Q9@SrE"d!hLMJel&B(mE%(2"CkXIZ&-MK8MPJbjVFj*1HQ!aU+"9[55@9ALFK N8qFj2[e`VXLYLTVhM3P2l[QIVJN3SMNK$"!S*)jbP&"jClD*9cD$,1I-'Rm(-T) VeZ#NbX"SB-!"6@GPUp,fad1e5'ce6ZM-4@3"DFHj&ErQNL)LGhmdk(&kJFQeFc` GKG`5bf@5KG(lT+0N2Ij8e9-U&heN%@Db9ah6YQ$9JEXCRBj9p8&N@LE&XCHAbq* i5i4jDM`f`8#"Hd2Y(RB-d$r3p+K9+ESjp9XdE*B+dV9bNQTqfeR5%a+D!JGc+aq Me-U3!2)J0N3YY4CA"ZE'9kdmK!B@1aTH08H*)BIFYeEdDPKdcYjNJ$DIcZPp,$Y H@Yj+"5`FCj8&0a,YPa$RdM"RliIeDiBMCepc9a+(ZCb0,BQm*"A%8!SVS2ASUTU DIFS%6)U!j)3Bh,bBDj2PJk"9l')Gq5lTM)IQX'-k8l4lP`4i*5j`UU[q#lTF6)Z 8ac)hHkQr&aJ,9'ja*%&Ydl!a+GJ*)YG8a(+lhaSlmppa0$Sp%$%#C*&`E6fR(Dl f0PYaXKaYTrLZ&SLZA3j8@Z$N)rY%I+YK1q+ELYR6PP[ppJDBR)h)QPj!FBfEl5D E(k0@BS(KbH`H"Lf4M,AN3`eCA&l&ET(FAR'@Pm0V(c0D3`C9T'Q+UfP(a,)`#Ii lV!If&#SHYjqPCFCBek5,@@YNZTd*iqP92p$R106kEd(VlTDS@XUl%Q9!1S-!#Gr `DqMfh"pDB!lcY5)3CZ-!$5kBF'FUhpjPl,VmcH`*G!aZ*Upp,f9X-HqKUMcT1', a65B[FQ&bXI+N(@-CPCT1D0Fl6iSDX&i3M3mjJ@4p'D%DJET-3IF%+E)r1r9`frE 09BD,-[+(3"TfkGF*e,4hEAj%H48'TP@V-[5eNK")E$EmCi`0Ehf!5E)F)d$!)15 lFk`"C06fU-SfeVFUAfjp3a88bBb8F)KP4k6(#"E+$&&TdBXiL9pAlJ4QhFUbqNm &[D60k,FpB3c"K[T5lGCr`&QX&IAI@d8'JA)BF6JrZ-Xcm80[[38dA!,1mP$cd[4 +1Lk4[2--E,a6CMJE2fPhF5I!k&k&I!3%K4,819dVMa[iG!J3kJLppR1f!k0cY"a dm"am,E[6,&`l(9+2VC!!@@%Jf3V#`X"9Q$I&SI51)1[-jpPGL,BdS+'85+8E44P r[pE8$GRkN@mJ)3L%)VY"Je8R81N6&MD#L2#2NY8KYkiq*,5""K#T!Le`Hi#2RBK h##,a(!"*SE[rA1pEZ'Re%b9bKckk1hiFIrKFlJcAZ6hhDrfJ0c9k@&XSA*k![QD 4L1!dY@1A-c!,qC8bap&N,FaB6I,`Ld"JNp,'[FYTD293TLb[KJR1IeePEU0!-6A ($f!,382SpY0T*a%'+%fKB#T+E4QfU09rN!#S"&BX`A[Y&Zqpef,jB6P#NrGDaYN B)U3)#l4[A'8U&4%,P6)8jEIUk4+FX(dZl4rC'9Ub@dULK6eakUAJj[B&)QG51JA !'&L5qq2!P+X&f%k-ZU1PJpqSGfVQG0qPd*%9MR3Gef1,ml[lEp2!NUk@"hLle[E 4C[09paXr!Y$4j18jIjHakB4YSG`1#PM51(DQ--RL!$"165Xjq1+S-[lXQidpq#c ND"JEm#)2,(Y6+fP9#5Tmd9d(iTk4$#4C$A0CDM0f9#X"iUS9HeH"pQKN%ISE$ZG !bPRe5mQ8[RmU-UC))$*PZT'(9fVFf1U0X+ZCXV"F1VbrT"BcD`0l@!K#0iV@pYH #lL&d#G9V526qRHp%,d84XkV#0i#Fi*jYBeeE(F)r""eJDR`E2QYDj0KUPVda)%A 0,6!qARdrd+#Q+4!h)Af%[I2P@IaLFL(4"G'"%L)N(@[U%'k%8&X#F`iFdFf9RKe $'56BC`R)412M02$%Y-49E(mrCRaeGi%C,!U632fjlXN9k1hQ0$l(99VA%1XeE9Z +AjQFL"ID5q"@Gk9Kq'YpBU%M&0%Br6cSd"cPTMiDfJe'q3iH[F#'5(F@CA#9+Lr S(kX4A$YHE([Z@LJ*R8km$62&jlrQr8!cdM*[8-S'DS+UMY2,`kYY"8"a(KBrhc3 F@(c1,fXAm2b2c,AA*TU4b$FrkA9d5Qp),P6I5IMeMI*p+khjmfk8#q&f2,#mIY3 H-69Z@D4FrFN*m98[q[+R6-Sf53NeY[Hi+Tl*J41+HGG1d[a#VVicJP9Q+@QPEbC YE(hj)2`Bq#G@jTC94S"6Y4iUa1q0Tbb,$-YHb!j'Q)4`l6J[Ve-Si6AhDBP11GN fbA8)f"3[Hb$%QiF$Hl'Leq*qAG*6)k8ce3#q3lN2@XDMkF,+PCL",i*RE1#4QHG L58`YG+qZbT3H8QJ`MKZl[+Pi+pf[c4Yq[deVbDl!-Ac0QY#!p+'NXR0ai*P@+(l $flYe3f2BRj[6djN"dFN@SI1PKJN8J1CmAcP4QR$'SC,$6bf*U#e@3G6[Z6TMM2A !L-K(3IM+SA$&1G3Sm-YQXbdaP*@T(eeNU0"-aVCrq-cd0Re8HNE9%eKBG!V%9i& HD!1"r",2q6!!LKrZ1-BD)R(pbL63FRrdD@r&f+HV8IlBicD8!GCKE)N@Id4*2&) a5J+BFY0cjHk2X#I$4kYS,ZHL-e&qi#2lN!$D!MNqRP"lNK3J*8+j%iliVpL(N!" ASK%IK`QJJm-,)DD@2m*@i8DK%4kaY@dGBCY`-UqP#$QjfarG6Ncr,['r*2aGXcA 960K%B+c3GXF)V6&IrZ5ifHkSA`!l*e%8&pR`RrpM6T!!'I+I#X%ZCC6M6e%p41- L''S2ejl,kFIY2Kli%EG@$L2M,48qFP*bU*!!LM5Y&Um9)G6ik`fX98LAdTa+-lE UMZG*VLId@KIci1lf"j+82l24reCj'#,3#ZPBV-#ISZArGB13!"J,+a9*q6LFER@ FTLV'mVE#AG4LL)+c8Jr,$f2q`TjQE8Kp"bkBSeDMQ-+KYFcieDehAjI,S39G-X$ "'bE&%HbddRb-$+eCDTlj#(HD*UqAkC46YVdTE5FUU0@,%&r66-Y-m(q%EkG`!j! !qH,%IT&djhm(LDMcD"8!elep6"I2kqlE2j'pmG5'D*c#0lI&%VT"`Pk`#R)*BK8 V9)ALR4VLB0-j2eMp,I`ZS9G9H8CD"pAA6ZAa4PRV`eA(YMQlU&dZaLa&r(E'95E KQQ(54HGECV6#IYCJ8RBAA1#)ejKqH0%T3GZdKDqp&JE#pCrmmX3M$2lq5)C&rQ- )2kjqYX42FB&MJE3DZjKV0T&rE!*Ef(*-C$9N!5rScBpEb$U)`Y"6f2!2P*U3!!e *T2B%fPTNll,(dKkq9$GZ9'8d9iZ!`DBMM&0'!@FQTi[LSNN3jRcd*+pFrXIbU,) #H)$RV1hLaHjQGmJeUi0PNBf"JX6((8ZpfYicX!iCEpNVp)SrG&3XTBa$ZEiQr$M KBE2A2)"IR9(#bIPLD9&')Qe&1IEGUG%aT3Jl)Q(dF*cUIdR0fT%ieP+L)Cc9jX8 X0hq#'1-K)cfIf+PP8J36A4mP4)SPM)S2NY!Sjml0!"i9k0QkUT'29q'#Z42(S(X *RZ+keTiH9H++VmJp**K&SK&5f)4Lim(I"LHCc`L,dS1S9f3a,29FmDqN,RVX3)F N1G[&U4A(6,Q%S-3)r`GEaRl2B-IcLaDM5dU9H2P'Nh+hUFmDmm'A[jZ++b6QD[# VS)XjY#K%qj'Y$m$r$@N((IVJMS35h36f3)!B9QlbAQ3*Be'r6kDK+"+pk#9Se#+ iQd9Yl[)b)hqpeH)#k)#cl8"+*KTbVZ*ZmTV,8`K[[l)59&F,fLXA0Jm(R(!Z2M$ Fk24L"RUKLi1iUAlD$X#c)P(MrElj6H6YqTMZk`P9D@H,LkiIm,)")rdhZ`p8"&e pCeERq)9,3c01*TlDG5USa!M()j2SSJp+X",6"*)$LG$j22NN1L&-5k"EUG!Aq(a D'eTY*fQilNjk,@62iQjVaSZLLS$6lMKBd-A6pr#c)$Bk!3rXZ!+!5H-6B#UcL+B m+P-)j3-BHAPMllldDq8q"J"Al!TFXT2U&idjHmY,P(5BA-RR-H*LH0UK55r"hJU hLMY4@ICkH6X(pFU1Xm(9XHH%!daF3&Re+IHqr*`Y4(+3!'LTNpcT9+DNe'-#qbY 1QdS@L[m6TB#Fi9Uiaid@HcKZmlLV!KjKEY)XDD63lM!VTCN3aP%q&Km%@d$9MD- lrH`M,C[&VD!e9T*2@ETZ*hKGF'Ua`fJ)8lS04"Aa'p6B8Nb)GJ)AREPQ9h,ID4I BFNjNCGPfjR"BImr(Ud`9jk&BV%blUNc$+@25SLNp`kIV,%[9l4LVri-4L%d03+I TUCZ%N!!PANpDiTiPUJbIfdfBP*l#h&$DjS[*,eI9I0)i89A9VHI3&3e&dHN2cCD ZB)3N1HN62hmX-X)5KlZ23Y2,pA*Dq`2(V$+)$UD@h!#)kHHrrTq"ZBjc2PiU`Bc 'VVK!(NNii"m,G-Cm8l3XVeRe$HI9AlETX9BJ6YN8cAp6A``lr1A'&P$I"%0dkDP 5FKV!H&S+[ReE8Lfp!I+iC2bmr*CRc,[+dIDT$pJBrhr2`kFjq(5l2ck93-S*&k` hiki1A`ZD0$kXYJ$1!eedXHJD*%1%BNr8jVGTNp2$fM&R!"0QkL@F,BV14`3!Mj3 `r1D)l4)QhaZcmLX%1fcerJrN@P3XRPf%ZSiBCqM$1U8Z2V3J*Zc3lc&[Bj!!I3a G5D(qK*(appr62)a[MqcerHIM,5Fi0T640@m@,l(JpJ)2UcbGKSUkAL)qAAVXQ`l j`iCCGM'9Llm&pN)hYMNJ&H#,hf!ZNKM3UFRA,N[(Hh,"Gpdd6E1)IpB2H!+HreD A'@!0G$ccj-05CPFQ3h5APJ3Tk8YTeJ20c-S[TNX&`Zem#`N"bZcf-cK&)ebhrL# P-C+&DRF$35RXbG8)MF3"+eZ0EG1$RD3XLP)D'U5+@U"69eG(2'"V9c6!1'Cherm EQ0RBqkamR**XjQB$N!"J@*QL[84M0"Dl2@K-Qd5kVUkqD*D'K+AH(eM@289k%*c +9B`$&5U@X,pj+dPAaFGKe[RceJi2-`lB'@fS-$X0!J1dqK-1c"cSZ@T'PUldh5b jb"I"k#pdYA$Ri$hqk(e16@FSUF[+R9j!Mc@6NZc"(6BLqfr)SA6Uj)Ff"jhd+8A C*arcpDHHSJ`bDhm%Va"ZCLE$dk-CQi3U'fBfaE%C$d#HN@h@4La!,L0CCaNeLVV mR*HGm1F6U6YCr#p*%Y'#f`,VSjBAZCYDLLNjMVM-""4J@6GFf2#BH4MqG[YFl@, *PKPN*d"QYfZJNJ29jH*K3k@iL'!`2iKVSb$p6CM3Vf4&8`*b%pUX"1PMJel*&+a M3-`LcNKc%E3X!+ji6kj9GfHkVec!N@F`i'Cj&31TC[(9-0@l$%f0LPBCL3)"@,+ Ab4VR*Em&3Vek,5Y[1LQANcf0"JJlLB%aYbQ`-H4PX`BG#UF+l$f[8VCqC89KkSc -JYSflNi,[eVi4JYGE%$K[2[r#@[ZAa9iPDT4PT0%Y$aDl&I@IiKb'm"IE@X5fJm 5qKmTSIF2L)G&Qd'N%HMe6SQK5X$i0qJ(8DC%&`Ga2,2+i@Xi@8d$m-!2J20bp!Z 6Fk8D6jQ0Ck,`kPcXcU+qXNd1Cid,G"5Q316)PTBq01F3X5&+JdY4h%(Rk!B&MUV HrNqp3HEFNK9KAU0RiUaYIpVpDESpQB5iT"+*#*%G9BMM"m9*Sc48V)VPkjVNh*r '90QZG)mrVVX4354i+V3r)5bjp64dJ!%JdPd"FcEEpmIqJ`83aPM53+8P#qB!MKZ I*4Uh5Q-Z&VCZjLjGp!")R$FA(r1H'rAA!`p1pbAC%)aBmKHe8k#e9d3eK@h`8'S [22CjPj@P4&NDqHR`)K6Qr$&A"2mRP$*JJT4b%JQhbR`D!i-"59BR8r8+FQ++U5Q -R9hUhbc@p&qI,L$!2XGTQq+9jFQRHBa8C+aCk0RjIajHM%2&1d"-bP*ECAHZ12K MiT,JU)2"a5E%CV`HElAf,ika+FIEe1da&PX([dh)&-id6`K`R2SFS+"9cBKIDIN Em#rBE$jY93FUBSIqZ"13!*1rfU"YBr(QX!qT0`h#BA8rP!Qc$hpE#T%4diISh@a ER#H2-&G)9mV1NPE4kQ+S[9d[SaqF4*emc&aK+3SU39C1F'VVRPSAHMcI2108"$M `MVLPDF,Xp"SSZYAI2@dM5%c9Zaaf5`mi,efBBf44q(8ZH[jik4Y[T(A$`GaMQD3 pTVmFSf6BK3@+AXJk*I)J-'BYd89#%Qp(a-,pFm9UIaJHKFQJYL0+ZA6XpL32(#h bp26!!93@V6[dK)cG8Z"rUamSdMBY8lhd&E4P0G!p,G8GPK'Z-r85G3KDiCj4i&) 13ZHdPqUC61f$66[lX%P"rh-T#c&%56qfDVj0%*MD'AFr6JRGcC@9[E%'l39V&RR kp61@hf`B(,*"A4$-[2V+6Q0AZeJ2*diIZe%jd959T+1M(mRjqFUAGlM"1c59Dka Fbd2YaH&Ei6KaHrK(*LCR(S31*CE#"[Qh%Q[XKNU@%+alFC!!!pd9AEMDKhTMP,h ,T6pdEr4@iMk8P325I2f,5VfDU[e@@d9%9f"'`HbkC1@1&[mqPZFaKdfklL[E0'" @iU1+PDR@SU&,)FPF5j)ME+FTeDQ*rCk4(!b6!lG'1JQ#Tae+$+A(I1Ua89H[Pc* %MMH[9((1a[cTTRD,!36kUG06jRT&'am5DT19$Q*je9,4dZ"Z-1"kDK$DRUclX$T q!ChPiTF`2D8XZdaGYMC4FP*LSfTk(+-k+pbh)2aF1`Md*Ka5c%c4mDmpNBp%VF1 18"qC3r,AGR9fk,,A'l9KAE'+0S!F#[DkR!12d4chDAXm"qfX[BP@GLQBaPCP$3J N,U(HC[bM%$PVcMIM1KmLCcL6Y1B&)3#5Vm1j$[XE4')*aLHZTVLrja1lmVel&(9 hJeJ#aJ6%"QqS`-&(a&(@rb2f*!cD56CL4N6Gj(h)qj%D*S1`3mQ$5KBBc*!!dQ" qV2p"VY2NqVTf[Ykjrd1ZfqhSIbqhVG[Yl",lHc(q(6INqhYjRfpV2mqc6qI8#2K VlGb3!'3FTh(J$`MZ#EX'Bf16Aj%,ecrfkeG$+jXccP1GC[[C8@!#2`!l)&P")D2 RQR**D"j(KhFIFJYXC*HDara-hcj'b&)S9iBCZCR4fk""%j-PC)IfL'cCP84HaV, kSJq@$iJJG)hEd!dZX$#)Ra[-2U$D+k'jKT45Fr38TaLc'UPP(3MI1XS6!qaDGTV QhL6hU1"fJMSq9!JJrc)`,M$QCM4Um1bf+63Tl0*cJKek9dYXr1Q)5b1f%[i8!G# %VjQj"e8'ZHKLj*!!fcff*HXXYV[FTBACblGN(J+0`4!%aN-U`QDd4'jLT24@rCa Z'bK@HKSTqe8LNq"G8`0'ZSPTBl$YMBYdaa4T,FVYTRGTG06b[M&(`@STr(1ZNF$ Zmrm*-BF#)fkc+S@NNaYdmAG$$$iaY#2Xb')D+1qf3#c!Hc(YM@bXDdHeX,IS-KJ XSh+YKSKh2a!r8S`rH%!@pB2(3l*6GpDhHClFi6i)rIEf5@mh3[T`-N-4p14rlk! a9()U2Gb8MKm&lUU0JIS9U!C3pDM,V6JTk%YKFRm&G)d9Z%QB#HPc4Hip&A5c8FY `fc0)&Y!HV(B![4X[[MaUFT(qB,1h%P2m'aG!,aKqp8G*M"3(q1ICe44DKN58$-c aC*Pl*QCGjcQ-"b`eAAM1aRCDlRIH[ZUMNp8,)`fSfEahqALN+ZrEl$U[(KN)I64 Xi5GD19QFKr4m4l0eS1DrY5G$f$Yj*4CJCP1&mFK3Z'JQ!h`&[G0aYLLB(K9e%`a f)!`kJfVNdm&BmDj6[QRlRrbVk#&J1j!!)pNAQSqb6X'BeiF*Y3cF%)`i-VdlQ,) #Yp3bK3C%+Z)V2XpCEV+`9fV*-(4"kC!!bp[2q+S'Lj[ZVIQJ3rG9%b'ASh%*0d@ pqU#GF31U5jR65(pGYNeF#J1A$'J4Y`9[%ZR0AD5D)a"4eaq"kde2B9#@835J'iN 3#!BBi02eDBJ`dRJAZJ)CLUcECKf4"HP6JDY"1CKj4ck4br`Q&2ihIqmc@X*N5b& D)*[TlK5q8U5%U$[8(J&ELX*"jklZHY$l962%4KlAkl`&#RI*Cp"Q$+ZUhKIkKii QmMc2R`1#iYl+qc`jAVBH-eRU41aFZ98Fi+bSXL1cA&9r2Q3aLX!2dHi6Zr@4G!5 "$!0KET0'e@Rh6%R'-Sral$XK-Lee'HNC[Lll82XY@`qK,`l296A#e-AJ9*MmE'G [rarS#XeYq4K1YkL(65jaE8jKM$D%8U$AU!b6@6)$U,rAm(SEi"ZBr`h[a[mjq+" !R3@f34RDL$*Q1Z)eXEV5`@YM%S%PSPi,i@#Hp0dJUSErGm1aYUd&j'IbK4KV*+M d6$m#(M06%jkCUQhh[#M8NIeP"Jif4aZ2r$BfPfk#LAF!2Y!699-5CXS#R)IC63b BK[)IbM6Y,MXS,&*!JZI9'Q3biPf3!%dhHJ+JkKRH[l(!('0bm[TFPPT`LiaL+36 VKah4+#Z)q1V9GVqPBCQc-$@8bXiT2#C%6Aq,Kj*h-mIKSbX%+')VD1*TSA%QG)S $',1!846*DpAbDB%DR0qKKM)E(Mem+*qJ,,Sic%PG+LT$r30akY6U1!cPSNH$`VY $MHkXJ`2J#ieP)Qj)h0"L#qXF$rQiRSAbL'VChi&3q6iM6J02IjVqcDNbP8pc6"m GBlZS)*!!"25+GG&RAU+84N&A&R&cP$Uki3bE,!JmTiQ($FE(9@4@!S2(dS`BS!! H%eEImeHjXp'Uq+l)Q2mm,DZLlPFYF5c3656b'N0(#L3l-q!DPe'9JkNk!H2ZG!q GIN0KqkpadIH5*"APl(R(5keBZ0J`m-&IPE3cHCI%8S1ck3,Q5+G`["kS'f(B+@Z 2E-3-*`)9DqQ@$6P6cR28i#CpI4%XINVAK3de`S)pd'+PH'f1DU8$1p!d8$EMp14 jpR"[Cj-iP(Ef*H2b6KHh2`$*$BC43Y*j$Q3BIjE#Q3'MNj!!Z!D&#"`e[9j1GUS $i3PE`6pM+UbCN!"*[kCY1ZABXM9-p1T`,eNHjUV6BklfY%X90e)PElhPUpV(B'Z AfK69DZX0-lmPjYGFK6)D6c$+9($GFjMbki1VX+"i)')+9VAqU&HYS,C&hXY1T00 H5YC(LLDc2APj$MLdDqm$Mfe9B6qC1[*C[*p)C@SKDT(dX1KYk&8#NCYKl)jY-m` I!+8!G9ah#3%4e%@aV'V(%rQqE$D4"[e"HRlD2rf,4N'8#eLXBlcRRCjNdm8lqL! ifMQ'YhY'L+DN'b5GNjIp9[fCHkk4V8,dN6p%N!#0$ebcYr#Pk)Y-PMf$qe&pDD+ fjDB[jc'%IP'Q5-ReIl93$TbM9hlE!E"i-Z,f,N'3!#5RrT!!d4p['F`Tl2668-F 5-L$UPh,`2ZMl-%aF)T2DJY0*ich2JF%4CBdm"P'"cdhZ0kSTQADI`E-0q+NF&%L ii39bdY*5P9A$mHa2d[pC5'm"Zc)KQ`TC[$b[9'fGf[$IYiplZiZCjNS-%(mpE5r -&9lD(j@`UPDZB3qU[IRJrh@%Qq*(bP*99Up![EJMM,+MA9[K,BZV3Mhlc&BL,lF *p'8Tq@Nejik+0+iE#rIbTp6qp#XCf&LVNf!'Pj4B)k2(&a(0%+6GL%#&XIhZ$qL JY"9UfHf3!2,)-(BL"Z&k1fklK0jT#dSmVNc!@hj(-Sd192dYc@mZjiaVDXV[rfM 1ck$QTI`*V-$SUrY55U,h!a9VM2TIPmbeq'P8&J%lpV`SdGE'Vfr@d9d#QCfAJ&M bATD9[Nb)"2!PTN#c&-l#`!A0[*rk,d9G[C&@XjaiR`$[lj&@34L)p@MKJ9!'06) ST%jRK3`BC[05*MXHD65+20PfiRq+(XrCp,ZP!l58aJ8FHB`@Df4`RY[L&2,6[Jj j"YTi5+E@"Y+mj,&Pld')2XNpm-33BT%V2LI-DkA8Yr2Xchj(+T&,8k2mmMl(6l# `8SG6C!b1ae0N$)l(8f3-MXG6C!b1ae0N$)qGhi,1(8E'I,ZilC@Nj5%cjK9D6m" b@HHrrdF,@pS45GTD3FB+LU$d&rU"p$f0k',2`ZJ4[-ZjKRaGIfJH,Dp*jIEV$AU 8h'Fqj26N4)MKV66T99S32-X@ihX&H4Uf6$`T+Q*3dM4bp29FIfi$KlGS8TI1U5j C)flpQhm9&[[EcLdkG@,-,%bZB+0XRedp+4(r-ZaS[J15l2(a(#j(X@#9iZ&UZC! !"8Ph0e4il2Ndk*`NE*bNBbMY$SZ[N[i-`l2#[5TY'#CY5jYah&*kNlXMKQemS6$ K%&3$SKaKdXlJZ$GmGZMXN`JHdZGdJUBb)Q3EUA6A8q-9%[jB(cbTPqT9hj+AMC2 S[6KDTmH+H4&Q#A)Dlcp@5ZIPJ[,N*V8[I&91,TG)GiP)mKR0V*DeZ!m[iEp63SA '92U+2)eRf3+HZC%qPZARRc,li4LCPYq%Yjq%TLIUlX&hFY1Mlp5H`9UqlqMq0[P iPb#B"18K4dc@%b4pL,V8hj2-%B9I&KkpbeDXEe1p8Ma%LHi)3Ekbhm#rRkj32pN KJ9dXp1$`Z8`+0aYSU3*d-`FHClrdSNHK&'Kd93)peRD3!+8+bI0bH$J9NGDYJm- meGNrJ0S`#N+H#S)*Z$MS18q[RmpJ5m%)E#m"IH@)Ja-p4RrDi@pZ&kKXa%l@Nkb q[JP)!5A@*d0iEFRqm6NU!*RGkBb![BC[KQ"S[Nicq,@8D8jBe#*"8d'Z0mk*F-5 5miGB4("@K+[[MYYR%-5hcFTVAk#2)UdF[LJN02R[h&dR&40Gk1b-"N5RS%AJUdF j+'3LAlrM4+ZSEL!c9PE&2i6cN!!#SiL*E[[ZHR36C'"bN!$'q"aPIG'4!%S@2KF &pNb1UFQjdr&JIM*3T0eR-jY*FR([K%[Qp"EKG&YcZ6Jl[38iG&UQVmH@rE!V6q* $&Z4+M32LaJSS0pr$h(6[AfZSMHZL'3kDr15YcaX4!dTK03&f!IefmCZ"B#UjR!9 BlQpr$FIh@l+-pL['BA%pH*KAZMYG[FlkN!!p@U+@&hm6j-KDh5*e6Y9!Jqrl0G5 Kjibc[dL![F6kdj639ac$,ZYGpb[YXF)rpmEh2Ekp6ML"KFZYFGb(c6IGUk$Q42[ mjH&cErMfq+fSIc#rNLQbQ8,kl(CDEl"KNVIDe)C8j&CRI09pk0H0GQ$!5#jF$Qh UVqcaD@*a['%Xj+UaXqHJLp*r#N,"L[%2bk2'kP*iQNf6S&Jb@Mkl[2iDdCZEIRL D"Mb-kj+V1[h59CS3Tm"lBQ,R*'qR#erS@pV$m&ZKIc@cekF45+2l[F0jA[A$$'B EJl'EJF)McRIER+13!#fmeqI*5E8LFCfldMd$'IY#j`pLMACCN!$GQ[-qa[M!*-! 2r9bMh(jI,UYN,[`GJ5r%PJRa3UBBQ8SkZE6i1-[ZMZKLf[IS%p`kfKHGTEcYB89 Nf+IBAm'RJCIFr-!&+f5A-#lpP4aMeF$K,5ZphB21hS!-AF26ejN0TCF%DfM#-B` RVhh5`K31laYIaM0V,T(#kD1Ue(Gm84pf0(0E#@BHXf4QK`J,Qr)DQJGE")!45)$ rGKb0dVaH(q(Hj$Fpm)XDk4Jj"cQ4mh)0L!6I8K6"k91"Aq6@'le+cB3qCDdBiJq Bd2D`r[9"`l5#(H'ID((03mBEY)'ZaE+!l@fE5m3H0#q0"KXFbD5p"NYYbGihRfD K0UaBNK2*mH(SEST'I"bR4aBFN6c1E!-Uhp#0jX-8I9b%pcARd)fjcYVEZ`A0NYl ZlVm[aMjH[1XqmUK$86EqrZ-3"J5QQG,aD)Dl!HP8G*pY9&FT0RRE3'e!l"C4$VH eJ)HYNVPDG@T%3%%A(ZhSl`+AC+1f,b$d"6A0-)ZYfR*Er8HpGNU,((DCA&qbmm4 !S,S,'2ZDS3NSf#YC3rM$p%1dIQJF@U$*S(pJSd$3e2+F$DFkZX3SNqRehX4R,,K )4hjQ'"[k)M36rFV'F%4SP,fb*jFZkYqmT*(+b(5VC[MLZrRpBejF*IQSP"45E)N [pb*MfX66fqQhG)kbPQVi`i!4dj'mrfP$MAdi(TL#VcFldd6J6Rl'U`B%X2F534q i!UR#QUhHjGXBK%X6bjSUkF(d51rXNS+U"B,PPhEjBh`K*C9)B6D`ej!!hXEGD[" e,BcHeB0!90DDlahMGaQ9%$6988)P*mX3DRpF[#*"&jc$Ei9,KCPK)U&!L1U50@l DZIe3!ZMjSHR%YUABXp9Q*X@2r)bP6N$VARiQ%r61EemfVerV[,@Y2A"9*FlKh8, 4Ak(-,$qAC@JCED"dDMl04T`)NDP*11[C*D)f3aSl#Ck1I`bf`h+LHSi&8r5"PHC kpUq1HF,YP5fMkkT)F4d'f[cUENJF!d9H#YcU%)+'E5ml5m0bK"GEHc!X`PkdMBN Z)E-1mcqMVrV#SNfLl(BpTR3&!K,0F[+"l6BrD,C,%N8e(Z``,F",P69iPQX`SPH +YAG+83I5,V1m'EY)[&m%YeQAUiNAa4!*BmV`bXIXScdKZF#RbcFF#PE,TJ-j3T@ 9&3@M-8kdmf1GSrKFP3F-M,%UDLj6[b2Rk(QTAFPH5K&d)jQ['+KJ3XLll82Cb+[ M5VKDTG8AHL5Td)4rdkaGQeibAFEPCJP"j#$)T"KJV,3N'B[Be$25mFTk&V%)f3( -L(`q,8Nl+IJ*,HU$pRR3fhi0QLkqGqX4rPQE4!')MMSZ!h$1qc(%Xp1RjE4mi@D +i*[UShp0[3"9LZ4A[44hmd44ip8J2c'IIX1-[EGJH&5rd8P,Z0MAVc5ir(*aalp &KHT@T#fa49hH*-q`HaX6EJqBjf#qddZ-lrN&kjkK%pAIFKhX,LfHVlILV-+!PZb 2CSRk4deVN`N#+MAdq8!,lQ"[@FS0#lpF(d24MU38A2[M+ac+Y4UE4QTNNVC8Tq" Lb9p#'1VpQcS0jIZFHI)PPk,YSaPM"Q2UbL9mQ3j4aP&64Ge21pVF[&"HECHQjpF KTCY)cB"jCp(NYS4j'+qQm6RSj)"#ac2eI0N@EF0Hr2Zmq)(r8,-l!#CE6e8qR8a N8JZKq)NL(T0KeK(61!0LBHSIh`J+j%6,2@ZIQA#D([P#GB0e"a1KBH`Y'90Mr)h N#T[PM1&IImMkdbdR&`Kd14Qq5FrL8lET,Fr`0[V9G0B$kUAk0r'e4&9)p&ae&0R M&f)05QQ*p3KI(rpb)HXQ2@,RMQb#XUY5m4m-D`JN9XH,)q804#)-BbFp0m12bH# $0bc*i2D9J!jPGZ0d)-kX)`,*-rb*1jZQQBiLY0G5eEX#!TI'@F$5#0mp2LPfk#X 1%qcL16M-@!i`la9,lV@T-eRq"dp(E1(UfLjkI)+kh@r-`l5FebVZ`DJ&k1fSER2 hc5S5&GfGJpI0"'Ml3l55dFP6@Rr*kCP9$9ckUpc)B1Z[`3!(3HHG3HZP'i#D"jD JpJU2BY+G,`%Ld@S'JN[a"J$@90m)p5ml*&C3HkH5h0DKbcAbUE)(SI(@jC86+T& 6P+Ef+h(`I)`iNF&1TAbN'QaNZXSr4Td5MSqIRACe'8A3,fE$dmii2$eqh$I$QU4 $rRAYAKB&VT1kb@F"mlPS-,+eb)Er22G(S(`-*9VZ4#Lh)4ak*`U(fa%VbI8UYNC Me&2!VUBmp$'R1CBBS!HNREX3+-fkch'1ANI2bc1N&N%2ljTfN!#h*cABY0#a)32 4iXGC!'6lh%mFVT&Eh`ri89H6#NLU9Jpf@)c-kc+[qf,bFGdLG6i`E%-"XQpKEki rHh(UFa&*3K[H!iNr5c'I2,IV[$m91V#kdFE6k*hf@'J[-i!BU8RJ(rSG`f$+)Nf J`XrB-9(FhIfPL0J0)E!-MMNN`#X[,K1dFXp@d3SqVqZAdTdiV'GZ1*h@XS8%La$ R'bUIE-fR$c0J4H2,BQbmhE0&KDErEiikR-qHT,*JIbj18+e0BXkpH+ilUE(k,82 @a#m""2FD0HLjr'&PR0HR+iIZ,`B(LN8@Hm-bE+Dc$"2r,Z*!5`$AVX(%`c#RKhB RV3!`hEq"I)(`4D31c%5%UPrY$Q,"jjhk&*N3b%b)5AD,EmlbrhN$,YGk[pbX4'P 9,ABqq5mC-0IQSLQB"r)&T,[(4-XQ'c(E)qXLY,,CX`6JhK0&'$m6qm4maY+`&9D 9c[Jf2A[RdaXIZ8`TTZ@'!#r6el1i*L'aJ[QLR6iF#HR)dB&YfhqCME4rEXm4*90 '5@8CIa1Z6ji68#d"2Mfmp2+cd'`ZP39a,PJmfR2R'f[0,HhaFIHCGm-RImkZEpB fJaI9@h!lp"`D%m!mP8(bU[0E6rm!`2B'!(DCk6&N5'kAp2XH6Bh()[hLkId%raX 58#Bha*Iq,Ul19-P3)pL9Q$Z`qKiCj5[9BYFqpDe6SaEEr3r5h,irA5"3#+HCCP# Gp-kZ$P@$P@(e2NfB)fc-#BQBpKr&jRZ$@ie1r"6!j!r1l@22P2DAmF,i%GALChF NmJR!6L,$YF%,%+!jAMhIiZ%8Th#ZV-'McfMbR+IkFA%[DFIFL8YV8r!9qrB**Yp UEV+ap[8kbjV(6Ml%Ir4lR'"93#Umkl[`UVd@8MJ+PhBeej)`ZJK-6R`2NL2+laY f@dG3%EF6f'M*B02TR6FrHK%!083*9"M'&Nk81pM[`BU[6XlFB66Xl$#h9)m9!I8 -8S31J6[ePpN$$IfK+PK&TlPkhQdl#LCIc&"k,@5NMV,f[&M*D6H,SlVbG#Be6iA 805@,AC!!f%P-B-hXmHfJU8&lIb81%f`!U'MjeNfSBUT2qe[f[Hq(plL3!-%i1H# ZCdrHQd*GH3ZD+0Hj$[hHf6dU@R'Yq,j+L$m$3FdL29+&4EellP8e#K)#HkC@phl Ja4[d2l%KFE`8rBrEUb18HVAd#P9aA-)PR8$)LF3&mQK4C[08DBYSfUb$Fa&cm6[ XPYhZ"lHlcJ-DrHi05b#VJreSH!'NVJ%%VmebMIA0IU0ce[m*CYM%M)S,VVJVDe! Di9!",6l-*VV@hqU3!!hG8GKDGZYHU)U440K!PX3J5arEb3cF#DmG-IGjf8MKlh& Z461c5B6IU%l-ic&Tqa4E9QZ"Fa,(2S(EM*qala&BLjl'ec$Q@-T'[eM8l2(VJZj 403!a*PkDYk#Q!cLVqf1lY)C-C(5H`1k$MS+SC,(%60!Nqhr#3[h5L@XLG+i2$k2 '#f)1U#cYAL#3!+B0a1+cJFZ+XL&64%`63Y1D&-Vk!j!!4,dT$HhAF"dA@I`UbTZ S-#D`Q8I"lK@K-GHXSCi$QCX@KX&3SPJ+-rRCKGQcl8j9jIb4a6fq29V"#02r4N1 LAENQ4Q6'P&Za*+rHUf3bHVSj)Lr`411D*0eN@8m60f@i#2"pHfK'`3DAl!PG*p2 KBP#`$q9[eEU9S!AE[6#$$&-UH98[)$Yie$GjR%N9&5TIH(%L(G9pdF&jlGjp4+( `S%Niple+j9LjC"S)0%2&GVr`[kKe)NZQaD1&bhi&3CE)"%1"UICYD&F13hH'Q() CGLPjqPDcDLBkS+R8mkS&+8#l$jDrBdXL8+pYM-EZpj4K4kfc%A8X9H0&EBE$bbB +fKHT0YK%%"E%Naj)FF9jm-dL0)-j4"hfG-Ch4&"k*$9(qZ%-lS(E9eLaUpp[4i, @h8LLRqa(R0Jj2XDSDfS(i2'[hP!jKZ85N!"d0C,pA1N6aVc[2RGM[djK)kq,kMS 0%i-EGlQ5b5QhKikd+C[UhEX3DkL6rKKrkiAUl5!68Ip-F-Yr!bZ+%p(a$lrKi1r JB04d'"Hj0j4ma04KL1J-,jA0e1655[9h4BL%VUCNebpKHNfB#k[C@dlZSQYmT1, %kK"5)Ck3!+IZiNKr$jb,q&X8#E3YT8@*`%H*eMUB%HdC"qMUm6qr*52fY&8*aD# 5&[T44T`S#rK1*K"b&E0U9Z-NX@i@qUHXZl$R13N+4GYm4DklaYJ6JY`"AYpA+TE qH#U+Z(6JTJM4f@V1V6r(V1hk!R,XNI4ESFqZc4fY9#lAP5cUU3*Ha-pclD*hF$p ,VB'Gce'aR!bCLSB#MF%iESpUcU,9`dmNl)-FrD)K#piBY@Dq53#9`C(!cfBVDRP aXAdmNAD`K03RU&AHDlfS@5L,SP!iK""q4aZAK,F!mLl60(iFRelDDb@He6DZb4b TpcGQB[c+T'*T&(REj5*p)#Vb"l,r--!BPXU)4U+&9d`pKf&KFZcX'&`SHcR`%@h HFl&$T@d4-!*YM[hEF*!!81kqC%fkfa%CpKU2S@e+0JBj*jG1Nl-1ap!N2arr2'e Q[LecmI1&C%TT,9qk%@#%a8mX1'bG0i2HR(IVlDK%P6R(VkpH#jK%pCp*d9abA01 !%F@ldm&M[FcLa!Q"AE&,b-K96+[+A[0Qf4MFkqmI[FTrAKJ89VL2[GMkZ*ek5*H `bRBfb$+%YZr0YX28ZmP(b`)N,T03jm-cXa$Xd8D8mPQ3!)([c9V#-hLk(8D9*XM V+Fp-&CRJbN+qGVNSl)Eq3)5YKQJ0k5lQUkK-6Pm"'HKH91`EK0aLVSlI(`LHqM` 2Q%CY8c$ia5ZEAT&-1!5S3p[C5h9Q"CX2j%Yf@8d!FPDiE#qTU0,jJ+J8FITSeVZ i`42)4R1Sk#)Sa@C[,Qf+e@@hHPG9qrd20!64b(&*4fiC`SGV$mf@X"kK46l%[Kr PjbQbQ%q&M4ahZKN6LZVTAZbT81pc4l8%K3pTLXV2)MFb'jq)qLjP-ff)Pcihl0d XMC`AN!$(R%,K4E%F1ifP9lC1D)LT2P[F!"'c@DIX41!lE5JR6k'+)jmrFqdA*$B @IKM@JT()*Al3l@@+kj`i`b!P3G*GZVBD*l''QDaN&RLNc34`G!-dCKPpLYR4$a% qABImmEqTL#Hc&HDd(Zhl4k1!Fh[!#e#$l16R,2Zia4c)L2R(cTl@2NrT!"b#V-l pR+r+P`Sl@Xj6I96)kkmEH+ji,!k'KCBC-QBfUZ)%!4r9FP"0bp*bU%(j6baU`E@ -Z%4@rA0hqPa&-ap!ArGK(@5$L*Ur"9i9TSFePHS,KVFrY1lNhKq!M8I#$VKkNG+ 5VSaNI"AL3eM5hhVA9Y*L+9YY9''Fk[pciK2KHNE8fqH++U%0#Rd`2mG2dL1aDPm !(+SXPQ&dH[6r0'l1c@40S&SceZL4'1GCp`UXj5XVb)GMh2Xq"6drDF)9SjP4X3c &$1bjp@$NQAH3!&S3&N"p%&[DMl'hU&3RT+S1Fe1ZeReCV,f)b,lai1IU#Y"B[ZI 8Bi`&)kJ#F6'dl1NE%ZhD)J+$@iCNr&M9BY#$CZ5c*8Ya,,d#R%rH%FejpjVcirS Bk2piPa5Na8H0,,')HVlM'GpU$#1p[5(`2dIf2`6+Q@Zc$kh#JGFHpjdP5aTC6HK Y*iil,kH88X)Ye!c''2"rMIVHJRV,6[[KUpp'e862I3FD,)q#U+LhB,6NjMF@#4Y *XLXVL1Z0,9KYCpD4Lb3VAcV-CrX+bjk")p,Be`8j*!KX5YHIrK)B'2hTIZ158aZ "8G+PP'3Ac)*+PIXeH`cRDH-UkCFI02@S!X'M4'6GmM*0Tmc&(KR2R&R'a9PN-L+ JDfF"P,XI4qASL"e+cIjRPB$4*FbjlUm$%hAchep2NQIid8L[p#5i21$bTC&dr48 j(Laq2lV("JZ0lZJ8#a!ekVH50#Q+Q"r#l%+X#0A3$GHD2B%91Ld'%'L0"Ta$2bV jA%kjV#Pm$*lq+1B)CQcY08&K8ZPf%)'Zh!mjiNkUYrbk$%[[5JJ0Ze,Eer"03jG Y!pbdf+fKa4LFQq99E*bC+SJIqU"q`@mXjT%$A3Ui@Ik)[rAH,0RPKk3Lf[mPH%d [hIS+qmQBPCl+!UqAQ,ZkblAcAFYHEYQIc8d+e[F#M9C2%!iG!UA`Mk#%Ba$LZqe #9A3M!IG(M&CHXNiBTGGFGfVpjME010@m@G3@*YXdGlcaf"V("+feP4MAA$aC*II Q`%ic-m("'LX0QU'arCV'L(Sj((k2@mJkjpm`r!AG(@QIe%q`6K#VceCrZkR8RqC pRcE62mZ`VcD"#VA"&fB,,@qldZ#4)Aa[8pBJ))8ceHR'Gl`dDSlccd@!k"cl(0r A9ldbClplkM$HME`R`G"PBkqmTBaejSba'NjAkH2l25iX5GHpD85(LJl4h9GV58B '1+!M4bj3E'C0'9`+"a[mJkZj@Lbd[qiAj-'64Qqdc2L"Kf)8*pMSX*k5[cU,Qk6 +2$UQ5m@fPNHKldL"(E)BiGaG)e)hTJ%c"Q[m+KPED2XQq3Al9K6K(81SG3kKeH" 0$lI'qSUB#%V+b9,bEA!9I83JJ(!(dJSqQC!!JUH#1JE`baLlFDj*Dah5CVkC*@) )Xl8dJ`Tq9afJ0m"&-l6M*@0PTP(A9SGV2%-#8U1I#e,&eJU#R4"eU+@l+Ki&8@, 1+0#0p'146K(hGVPfrd++2M2`1&hC1qbIHVU&TG1TR++($K#D%kR*Cb-R%C!!2$e i,JJBqKdm4CLZL8%XS16ar+J1dR5ld'G86TdBJeBlfcDAP33l[JjKLE%AHF1+rY2 Gf1ZEbaQf)4L)Kq5jGfbcX3AkCSZ6DhPA6BQl@m6amlC%c'd5cQ!eVK8dpl3S+"+ jYYZ!jY,q2K$jC2TXp4qT"Y#+HK0LYddq!q+3!&jJJ0-i6*V`m$QlHB,[r55bN`B NVd6Ar`1MHJhpcfr4DK[arP,UT+Ej80XkKcF,*2(eY0-aGm)a9DKqql8m6EKMSHQ 4krppTf4eTTJ$RXMc-80Ib84M0lb4ZdFc,jTCLBCC&69M-!r4S`N,2U$9&l$5)DR S+*Q&010dIq9R$(G&`p(a,p1jT44"`B[CqNAE5-%UX"S)bdqm32+N)Zqa$18IMa$ EhJaMSph3-SGC1[,QQ%)LDIm2j2Ul8VlHpRq(FKIEe0CIEhir`llIiGmAm1ZR*p[ IYIKk2AmqmhqIA3$iD-Z4r0fHFF%r@b*0%X"b-Ef8`4QZTb4`BC!!FN4,1NBIc6G p`dQ(I&9PBXDHHEX18pZ2(0+lkZYFZmTbrLMLR&&G)X0%rMG#h!@h4Ie8fpd'$8@ '5FQSBSFbqF@!ae-pbKKH**!!FXS-TYi(c&rdV,qiK1!0kHq!m+pG2aJVDD1$VQ! '$lR,%DZS[adPTA2`*4l9epbKLRF[#X"q1ScM*r!)1h0YFKDp$VhY3Y"1IlK6[Bp [8K*,IQh1bReMbBiKR[X`,FXKYlpY@d1`$2I5#ar&SYF"CJ9&hQ%[k5c8aTkEQ!% lNeIC6pR9V'i!Gq'V84QU-U+jPXC@A,b0jcZ6DGK,QdNB1C3m3qarefR`[Y4h-c! C`9ULLPY,P*5(T'ddSCa-jAQ6%*QU`""!PPK+'[Z+Q'%d,Qh*BRSi!pX,cT%qj%I $QHJKGm%4,p6K#99`,8S&$!99A!#l)H6MF24L4m4j$q('VS!#-8fb6c"P)9ea*LC BKS1)VaD@Yc(pAANqLl306i`R@*[*Ph+h50f3!$%!Vi9Jfa2B@I)eECQemfD',Nk hV683)UTJZb!eSXl6p(VSC3ELLIp@C2%PAaM3p%6#BVeZFMD1Y%QD0B8Z`NlUZX' ,JCU8YU$dH6a`SQQ6l)PFR3PGE"LBXY['C1b9GIXHGk80&2LbX+q3!"0+K"M`DaV b"Ub1)`l1&k[0jh,i(jS,1[pPb-)0p4TD[X3YV$N,b1L!90L@`AE)B8ZRY')&A*U 2l'1ilEYG-Lh$&Q33ciJIAMQ2fFq9UR$E2D5'(@Gem,X9UqXER4+RJj)dm"Jaa[B N[BB3c[C0F`4)!%)ph%4P8+!&GhJq&&UQc+1-GP'k5)"SRU4-`hAG+V$3c&N2#Cc *hhm[qieH$6meI#MCiF,qL-'#RFC3PLlFJm3@VebU+bN64Sa,@,9FRV&KT)II3f@ !BK&1*0fQ9djRl45"jPYXml)6X"HQZ8dlXVHCa#V56`$4D24Z5K'+CBJq`Qb')[Z 25r!rdja'@6erHY'4j6eDJk5S+F@XmiD)cjVh`pG&3Z,@H4RFXN*FNkQ'5SX,@&# lPh2X*pGCjf26Tf-*[M6"NJ1e!kpCE,K-6X&iNL8V2eAAM%*bB-N[mUV#"Fahe[c Ifq)V2XpCEXMp6-B5'@(aD(m(YB3YK4a[0RYYk$PG!VC1ZJiVKraI"c-#Sd1@h-R p6L!har1m,bSEDXH`A+m,0UMk)Bj)QiGN`l`i3@0IQ%UKKMCCA#NSC6G4kaq&cq$ -85#PEm+!pE8$DGj`'q(%!F43MDFEFEKlU,*k&TQpZ[d5#6bJ0ADNlaLR9IU@T0- XNVU$`LLBTZ9e*[AQqHM@#iLPF91hrCD,9YE8JAXVlfPG[0UVAjFj`fB9ZHASf'r ibm9j+5Aq-D[%94S*!U#VcI3[KdL9'IJ8k,##GjjcD(VdBf9NZDBX"J2S%peh*@% 3HX@iFp6Y)CH+SrfEdk+#,!0MMD+LV,1*JK@S1c@3!,QLbFVB)!J@id&dqhZKqXC '`ph'cZdTmbHiZP'f2QYm,0)4J!04"pqCVjB6P6[mi[iNcc632k(dAcE*hM&3KfA %-AXMNNN*2AP)1h)(LKbB8@1aDAdmp[@Bica-ll##MX@qJ+[r8(@Ci8"q1'PcLl+ IX`Uc+bP,*8BcTR(VZqHZ+P2S#dCjCYcC'%`Y6NL"mmNf0CDF-b&qZ!d4lcH3!2j bVdjI2ff5+HR-@-d5q1lbDF(QYL#pLHRlI#*UlkLpqdBJ1'0(Ja')Y'GT*N0V&65 %r$d5#YL)TCl@'K5Xp0hU!9ZM$*8IL8Fh,&Bl0rCVF-ZiJ62L8p(TBY`TGrKTV([ V!(2'@aQ&daJ#3XVq$lPANXKYhTY3P!+%pZqFle!BAQqkFmI'AD'"CYk"ep*j'&A f!5B9GL,aRdaR+PZ-ALjm'RS35RcA(V[YID%bH$UI10HeGa,3lP&qf)YH#JVHhLM ZhbdH&1#XRp3D`Er'#H1@N!$ICrG6Z5q05m3p*af&M&$E$p#'"%52Q243CZ8Z#*8 85JKcb*!![S*ZqmaPSAD+[[&[QkpkhE)%3T!!cRP3LClI63Vh8QjGr$il0JMRa'E K`J0JF*C"AP2+J&NIQIM6)A*'JCL&1E,LVrHE*Yh$ZZ),0DmL&%QMMEi-qJ2bePV 2ALFqH9UmB&"AU'`D!RqqAS4JJ5Nff+Vj"0SJ!P`QpPp6`LB36GFD#TRL0YCCdS+ L#E%hiklBI(+I3dZ,`$EcmUU%k[p(`56Q`qVe&iUYHjL"4KU$Il1em5IbpSiYMJq mqMiq9V(,%&9CVXp"4f@[mQ!)eRje`aZV)`l$l-m#&CPjc*@VR8k*Fkh30fZ+ZCl ZC&Ah!P'rKlFS0ED&+8)EVa2aeck,lcZNh"me+-Ci&`M60m3RV@hmQ[%3TZH664p Hiemah*,NBbrSX$d31Il%ieqD#Hp$Y*G,e&03NhZc,qN#jNMdjCa+'@NU#XdCbN+ 9llTliY$A!Th98r45@bm`hN1a#EJ069Q'0ZfDKi$0BHZr$[3c'M-`Y)96S(B1L(6 6KhepQS#3!#DV'B6RLK(M,IB&B$ijQ$QV@m#`dl@QaAe%,RJUb6dBU+BCFCJj5q9 H`4eCd%JC'rbK*++BUBVPpE#r4m2H@B-m59BmA+"F+kLXb1qa&5RCra!!Fq(3CQa )cdY#kD0lbaMq+GrU#mm&I98mq,hccFP$ih&5Y%D)'k%d8Ti4*riX")Vl6rDr`RC Z)DlB'IU4!e[E%LjrpSj!6*m%@DApp+S+k&i&kP$lZS#+r*5eTDMp46*'F2Bec28 *kAjj59V)j(HJQi0Qq!YQKR989bb4@R#2Sl1VHQ[ZYjci!,93H0XMJLq#h%iKkDP 1Id9cPcK4qJmC40VAQ6j&1%p#iZcIl!dV6rI,lFrfqBjcIV0N"LmA(C!!d-84SUl `TLjlV!"(Vkk!S6+dipE`EZ3RqHZemI-Sm9a)K#j(FN+$q%km!QeNAleFc*Y4`ri )BcXicd3J"KE83!FAVAdi0q#iHeNkI81#YXqPL![EbK+Vr,p`bHE&$ib3!)0af6Q %Jkcfj5aI-"`jf9S"0*D,A%fAkr6,iGBV9+)GGachD#!R%aNdNB$6IB5U0!',-j! ![Ch!i6+Nf)f8T'2(6I*SMRU68+iHi5*$B*YT,HEA`NacpY[`DFk`AG`(bl4L@mN hi3(VFEGIK45-Pa2!i5kqiH#$5$*mTXEV'Q2X0hhXcM-62KKiaSRB$$%i2)i+cL2 AP$rfdG9RUl`qZL+DfJ8(j)2SY&FEIK"U5*F0U$VFJ5j92IMd!S[$$lbjBd"LBYJ R086''AbrFN&[AN'DJqY"iUh9F98e1$%-6`VKh6#jr@543-iiXm+P9LqqmXVNh-I !TH,R$6-$F*%ebYJcAfhXb1f0h##94,lqr5D1@B%N4bp#-$Ga0@6aGFb@[-NB%fA hX3&6GGf-er5fYb,8N!"a'DB,CEqrlqR5Q,p-M3e1GZHeEAqdF6Cie0S&e!8'J'2 1MPb+`!Tb(`[f-jA4YR,%V(-!SH(hfaD*-8eG$V`-pb,3BY*hTQX5e'K!h"@C6"Y jU#JF*j6Me)YjPJq3!(kSJ'r%-AU[M`pRR@0*8qe1+#B&3MFGVR2imc,BQ$Qi4jT &L***Zj+%VcNDV-k1T%rafXl0U$cT+H"1q"1@Y$!ADp(&hThEIiSa(5KiV%NKdY9 K(f5@@lQD'd9c#-dA1$j3Qm!'%9H,D8kpp')!!jc66qVI6()U,Gqf3'i+G[e6%Rb J8$A'D,DNlS#rqQL*mJBHH`"G3TMB0cG,LRpKmkmU#U[r$DIpKB5+#UK&6mMa&&Y 0B"AL"E&-`6e$)Y)hp0KG-HT@i*RcBjM%@S%'"`EUjGpNEdC9MX%"Z&DYq+fh8!J -[@$V8!C+23B-%G4QGZS%!E+XHq5Z!DeDAlbSf`)&A"[*b-5Mf@r4Y)Z8@V)&SMd (YkPD$IprmUYITd[1(6@hLa(rHU296j-+ZfKV%Hb%dk'IT6ZR415EDMUFE*9bR!2 aFp"MhSeU)L&DVNiAAZ!jbiLlpc@`4BRNk"BBBVVaXjbA9HF"qB(0AN9Z-@6`TJ& J#4iP9&K[BK,-J$IHKGq!5X9FDd-ijmN0-bU#JdNCCrS,U9UQc*5G#8Df03SqVjP G6$AB'K60#!j,U$H86DfFHRUSF9FlK,B46Rj&P(R+e5G!3DRaqc0VRJeJUh'*Q3E Ycrp0jrT"Dc5E69'cYGSMlbHK8VcK51NdIe"&L!ra!`k$[cNJ!#1d4-k0G3FK[YN CpN"jMXXZV-'McfN-i#!NG!FKafRS+69d'CHAN!$3j%lb2'NYh1lf#eSBRJ+L`qc !(+('f2AG"3UQZY!FHXNX-A,Bm8P#l(KT2fqB9,mcm+1*`'BSikihKD%3efFbbmI P*e-cpqc`8lh4%mMeDG@bR`I`!E!hp*dRQmfYeHpXYamb)ciJD9'2`$-Y+U$2JB[ C3Jjch(UcG'Rj[G8!Er)hN!!)!XFN+UNfAP*FMDFe1Me31%TESGS%*jSq+f!Z#R4 RaDS'mRG6RScH`fR&NS16i8p1+PY"SNeL-`1[lV1l5!Xrmh*i1"@4eUemU"iNcY1 CJP(5BS`r&5Ge8H%ZM9U"R*4f45Eb"V*djRYZ6E(UleS3BC%Pi1[eT02lmZk!ZPh 6E[@qKpmY,PP-Ikr'GKrb"pbJC6Fd'V'deL[h,*@)Sm8"KS2&Kl"[l45A`,8XLD& 8NpEqb9UJ[ISj,FT#DXdcJ9b+@BdQGfT5)F#PVHZTlcCMTf-QQ,@3!!hU$EaQ"RU c)BeN@!I0,1#(HjA1q'@XS4b3!"Caq$C$)p4AHKM4*j+`q6dBUXKDUMi+C(JA4Kk ,5E0MQ3qhC)kB$T-A$4V,d'2h$8K5r`fd8jYLKmpi0%0G"j*6a3C`eNca)3YD1U4 IcSb'p$2%fAa*i633aLXZ805rh$+6$4F[8bPjVrdZVJ&4A*%[rVYPEhHZLcc((ri JJcjDb5i)@BU(f)!@Sdcf0[AMD3hXqIT*)9&G6DX58L1P3"ad@8ZP#QI)!d4LbBK R*3c%!h2bjNm$+I(TZ4JjRh!'HD(e9UZlHE(cX`U"qSNB1+jaDf,5mG"NC$c)lNr C2aJiVe#aP1m!9jLmT@0f*Y2`a5fLZifj'5d5IlpZ1qIVqDET3pIa&l[f[ZKNLA0 "4jD4MGFK+Y$YrTK0842JL*BD*Pe%Vcl``beZ20'h#)MCIG[&i&#K0QQZ%h#l+U- qKkd,l3`23*XdZ6D$1Jcb%[9A"p#V(1H+A8amNLcka*kd5X8*3QK#bGV2'FYYY*B @*[XLN!#le'NBJZpDCaFha(RrIF*R5D8USU%eZK5aPe*lbSTATC3e2AklRC9BHRk m3KCVbTmG45rbAEQ#bfHj"LAKjj,fRX@%%@5A`&SB$be5mNBmR#f-lV[2JmMV"52 ak"hfr@kjERPJ,I%6*[NZ6KCbC,(rGK0ZXfBApHj3T&NiVD!AVP[69%UlBlE2"BR 3j@FqLFSDTHP,L'a$1"'SJ9$"Hp(fqU'MKZrK5dDhRB$H08F5-5a$pR$G0c6UF*[ @IDUiYZqlm6RAS+HL$@1(H#B-K4"D23"',46CQBqR)$#T4i[c$*q'#,$be4Q',c2 [2%rCbF"TjRkNjjMe*+Bf#PHf89D`&'SLV9#mhmAB9!3JCBh4Kd#aACf!Hk85c#U cfjTJ"cQS'8)G&BI00)b*,-r%5b)aNrl*S3T6P'8)M9b&UB+p!$&#H#kY*L6iCEk fQUbN&I0%A'Mk$i14j)-f#QCKjd'#Ei69CKqJZ[pq0EUXjH8,`cci$YChb92Q1ah [18HJm,l3Hb#V6Gm+KhT*IdJBL%2fe9Lpp`kC+lpVH4mq+1QJe*qkXE`q$a'q2dK 3"6dV-ZRk3&ZX9kkHQXZ@&"r90%hm)2"rkS(L0$iNhjfQA+TI8r-$Ee3fUq*4JP$ E@kaKM#AXHHBq5YKLNVk!)f`[R4ImS@8k@9Vq&Z@Lha*9H+XL0r4iA31K2((N"JR Zr6bY)!EkZ5D"m@5+0AM4YZJSTX!cY%[kZHEmD"951`SLpiLYULV!4fXYFXET%-' a,S'Ufq+lja-C'-[ic-V+T"B(pL+rhr!,i$hl@J4@42M[FCi((Sh[fI2fNIBDP4f MZ'@KP%"$eNlaBeV',@UQN9SC"Nb4(je*'@p#K0C0r&S%j(1RdGKUD#Y6`'$fQ5Y "pSjNDjhe#U#dXi[B`dpLG-jQCT%ak(b`jNdpZM,9Z1HCHNVNkMZ9VS5HpBbD5VL MKk*S8UrXU@6$XAd-2B+U5J0"1cL,qTiDG'Y#d[Dk&`RA[k@(U-C9$GmUP(%&UAj `AXa""6f@`RdXeQ-IAqc2)dIp814%)9!p)08eJKe"Aa92KhV!L"!8ErID6qRJGFQ mbV*!)SM"LP"4Ekjk%HijSFN`!jZV2Tm&@5VBjaC@9qJ-V!'hMS%iiK(DiR'FTAD HR1[32CMH)9*kjCfEFQ('mFNRYLqSX!DdYeRr2Ca,fEhDQ"kcAAi)V"Y'KI@+MT! !`F%`R4+@09-MHVh[[6R!)6l$Lh9'Pr'k5HAMch"KL3m8aEjEBHc**4S&LGRBbDQ M3+!`0E(rDGBHP!Y*X00`cF[Dk"16Vm[r&"*F84ifiH$M6%+h`"dGqD`ee$I1i2( pE'$(Da3-jM8"0G%GR2$MQqJ+`f+-Qmb2aMd5[q5d1@fR(B,ck03V[*cZbC20aj6 JU+QN#jT66Ae#Le&Sl-4D3iC'YeZh'Kj)m0j35bm,h!U+Z()!3N#F63-%lc&04R` YQ!"`AUrFeTXppH92E#*%mMEb@d`LBrC,b,fe!jVDEEbTcZ$C3,CMPEq%%@ZfX`5 8pShc*&perf0$62HkdQMKYc)!458qfZaZh)5)&m)K[d(!KhUGhULVEM*JcNi`hPC kP%j'42mJTD(VQDE@8A6"Ak1(X%Ak-ALGe2J,5Lj$(+IlPq@jk[*aCcm$)m,T&4` ,PY-haR%+f3c+HQ(h`P-$JZ3`Ek)NFR'J1FY%`[+Ia0$B-,Sac4J&0N$!#!MVHB$ @)KR*5reLe-!-MlBUG85GfF%RG`k"'01"MM@%J&F6Xi+b43#*8ZlN1+1G3S%pXpP @B00BQpFBq0'Z%PKN%+9(L0%p9hX*qU#Z@l(rGXa48`Y9j"1G#qc-'@P`qB2PJ3[ Y1@fcNkehr'p5@KS*QB)a1QbX(5M-J[RP+H2C`EKi1DV,dQB(ei@4MrfrcfU%5#f L(RK)lEq,iX+iaF[d8h2CD*!!BiPjNmr4CBd3,h%PEBCV6%Srk6V%mZ-A*`,8dqh IQILCVmm3EDp+T%%)Q``$qU-YQ8*5Y3f`dRe&6Dki%'(h"pVA*CrhR,3)cABFPYS J$+32lk%hTU1#r$$H,AB$4rEMC'aT`*m92bD[KRIijdP9!00(AfAE[Ia8EGRqf1c I3&C&SRZ@qa[TP+ZIbCITQ9H(hhq-EM4`QR(eRcdL@UkGdQ-%#8j'lramPQDjbAJ '0LP#MjA)R0R`V5$-#,H!%M+1)F!$BSLKPcc,!28hmM@#3Jk`d8T-U`VF*YcepCb FrTGB'+Uke2V[UG5HXH23QCm9Y9BIdb%8pbTmGcR+k4Y2A4H,YI#$'I#LLhQFBd- 5UE5Ra*XV&`rDKHQ[(R*lTpXPIjN(Yh2Tc'QXX4m%l5+Q'-Q+$frThp@91eT`T2* 4-q!q,Q(YU#ESc'Y+j2!D+Bmh#'p-j$%Zh!pS1LR5KbcC$4,Ebe@Y!)Ib'%'+6'I 6eKfXXmJUjA8R+k$`+q5QdFJ`2CBDY$3[M!$CLUrqM*)*4#RajhA[IjAjFJi!0Cj k()M'mDHZl$I%U&,*(hb*G%f$R"PqkSi3k5V2dVC6cYlpM(1Q[-b3!2DrhD6pHme %!l(GNpbaQKT9!86e$1X1ickCl`8$N!"&dq)4RqTFCC!!KDTLU!Ec8l1N-$%d#pm [IqP"$9TUM%8iQFMl%`(*fB3Yd4Ll#pVVdq#ha1aj4Hi+6%DjrXK@4'M!MFTrRSU +pQqIFYp1r5BRfh'UjrV1)VB6MEBq0AE@N`eG(&1[h"Lr&b`+hJe*XC-YRp4B)D- *!mlSITA*deqM1lQ&K&%8IQ8p@k[bKb9GM1l[-pB`pJYj%-r-D1pif+6DS56jecD Xh*ji@882))0rce63@NK6@B'&G95DlbRlabBGUYE6hm%iMc,UPH&,Hl0#GLB3Pj9 ZAR!Q3Ip5hCJYIGbDdSV#U(*6!&r&2Y$Y5b+,@hC#HEFVKLJ9HlR`4P,DHRTjp@C Dr"&BBPJN'I9SNra&emG,kelD&V%(ae+l46jjcLUE"3dq2)U"59cX3iI``$-dXf! IbSFqb90D1f+a&Kp%ZmB2h2KVER!CM0DU!XF*EYIPdF2jGMC86PcjE&4m&q-J"0[ H)c("Q'VjZ[h*[+qFSpQCMME59ih-9+RD')LNKBkKNVfZ9a55ZYX["[-JH),2$al "mM*L)+rYam)"@mYPi18kFmp%[c4*H[YRKV%YAhNBQUpbQF,TrVGLNe!e,)#AE@% "XjMZI'AVeY(1VmpMMb#8F@j03%"EA+4-Celb"Ra'UENZQ,6%'F8!)0-"h"@q0`! T@30[)%bZ4pBaX2j55C`TamAhZUKj)r$32rK49j-+5+YFk-KYqDX""Q#MB-1hUXC e!@LlT4XhSZV3&HMe*rcIh,%h4-*LR'5+fa9lEqV*Ifi4'hhjmf0#jFidkH+hMXJ !YHVE%l-'6KJG#V*ldMa)-+,Cr3A&ackqVBMbT#581X#qjl"i$J@!k2ESki[J@,r TP#FJZGa0fP*qCT!![RPbKe$3G#a%#A!3a-Q%4PcrHL0QcQ00rCJSJ$*M`*NS-ch *SCPq%"QAjcdVi-VfMC!!NT`MkR8MI2GcL3dp1F6B*qUeX(Ei"@U5-'9[(%Lf`@! Z,TpZ"Uk"-cpeTH$0NKb"(FLIA("+d+E&-AA'UpZS3(3$!JJV58J)S+!#C!AqdqL lN!"VhCac%6Y$h)ZkG9hE1jei+lM9(0ql9`bU33Ar@,2Y$Q-A%$8qFkk1jMJVp@, kBpR[PKpQS!B6KFkEdTG+(KfF8R31jK-DEG1qF[R$Jd*6eYk4%!l5kkeV*-K4MFG Mbp96Q8N2M%m,GA#+0A68lU!HCYrCXSDBLMaY!"JZ#&i6cqMJ5+`k0T[06I2lq", EG+lq*SQTNE'&4YD`kp,JAP(BF%E8fiL4bSDBJ!EBY'5SX32ZRrYZ[`SlAj'%1GU ,Xe*RJj3dbGINr2UE[hRq4&R23!##bXP'''(2,qfp(UJ,bRq'+LJ5'a*m*)S+93p *r0bhml+M1IGKS[JH-NJ[ZcNFekAAFc@iLr&D5TrYcCG*I#[X6bTM(*eYCL-pi)) GRkFGDIA*S8XF[bEVl*[+"Q*9*XSCJpi#[YkUh[afX9*lU+%GGCH1CE)`fG#&rbh &I-Q4pM*[@G#k2(Yqj4h,6Sqr8RX6f*iC0#b9-1cCh85j(iM+I6`GrM@MQMSEQUp X5@TcYS3QD-[q*[mVhm+9k+TjYeq[`20Ja,[E-i#EQ-f@cQ!YKEPV)q-B--+Z(A9 ##q!8fP,,-N,+VF#3!+Q#Z*FX!m3fFDi#Zf!D+8HZ2#41NhdlH"&NLdHZZPHY3VR VXeD(F2prp*()6+8#e0%K&(r&!hlCVkP5@f+C"cQf36Q,+F[00Ti-C$jkHJ[ZC)) #j$[-DVrfcQHQGA-(ZYZ'QQ+HXR8bZ)NQE*BL4hYk`1S'EJh(diKTfASb(6`ekP8 I'Q8PbKXIlGDiEE5PB[,AHXYZ+Z`YR3VbCGCrM*pHPGehM&kcQ@Gr!f12))""Lfh A&Q*&BR3$4)R`LN,59'M'#TLkD(6N&P"0@L2+(1[*j"Q4,U8LlSk@-V6N8RfUck* M1P)4C'%%iY2HF@+eVB&BHc1U&qC$j1KZ&[adEl-dQCmp35r0@0VBA@MaDT`j$'K CS(Reqie#-Yp@0@+HXQVL[@M9c&5DJ(U@h(Xq-(pe)#"be9CQlr(X2[8hHm2-4pj j[JQDKabKE6L-%hY*0CX,XX,,[@[ih&Bl[BD!b@SafPiDp*!!"rRKHd1[@+UA'Q` TZXHrD"'j[3LSE,ZjlBV6-iT%&ld(qA)Tr6cYV8SqEBZer81-0Pk9$LCPKY'+%U% mV0C95prI4R1reHU-f&Z`ZQU-DXJ%XFTjMZZ()TEJm0XCdUb!HJ89Ef%XG8A[R+G (Rj2Dm1l,(fT`e!AI*V`U@Yb$IEde0%b4@-PmiLkjB5*,cU*JcENNXcGA!CU1818 lRAXLi1D)Q8(,fF'K6Z'-6T%&(,Sid31!X8rfiCbRZDd9(M#6[$X5NaEND,Jq-Xq ZQS"N4JJ(0`r$8&`l'-`l`52H!e`La+cPj8DDHIZ$N!$CC40f2&j!AGQ[cQaUqDp 5AeV)Y!24-'G`B4h&$-Ap9N%M&-8f1EmHP&f,RmTLFV+Q2RaZ54E"P9J+&Y63C5I bP[I%(h&&AA%'1KP2#H0&kDh6!JmLINd!%G"B`jblcSk4Y6aCT-**YBp`K(aRV)9 +Fp&Rqc8U@T`"AI2#C6#D0hf+mPQGYjAdC@T+dd(K$8'VbQH25aVCB!-LH28Pm4f c85)4ih68ib$r*4$95U[(2,YV``HbX`C(2mFKjRXc[2pS6+PS(94eJ'BF$&La+Y0 6cZ`H-`)6+0d3bJYeEjilXLcfVI(`5hXbl$K*,B8IiaQ-Jmm9+DVlkTb9!P(MXl, %963H0@Id9"LmMF3XkeSS5R'b3i)6djCR&fflc14B3G9UXbem'K9#TUBP5#949m" 1ZXJh$"*8MLX8Y#X5SN$N3[+-6)Y2*)`[QKGcU83P8hll$cQ'c[2UGhbqVB&"S+c Bh,fQ&8lATB9M5Y#S+Vl@!Bpi'TRSq2eIAjScD2((eNp*U`-pA2%Phf,J3*PLKCX a(Y$[I-0M"hpT*fRCK,qQ,*Qc-haEacP1Sd)8flQ3!!FM@p+Z-JTQ*&H%DJkP99* Z![L-M*3H49di8+AGYZLGm`+qlcZ-)MGZQmUNT'8X2qik'dml'dTEpVdm$[)FLKe $4VG'0"`k#qFD4006ZL@1k&Pk&[X1XQeqfPF,'ch"*"4JY&V@VQDf2Gqh@A`[Ifa 9@QhcrHY"aI&fR2(kbZ,0X8-[)C!!DreVDkXr(8al`m%FKA'$XN#kj6S`Kd!PEm2 C+@ErID5*'m9@HiEZNa%MT'NJR$N$CPJUR&kamMNl%Mi$'jF@2l9S"845#9E&i@! %AD"QNCVBl#b&J)[0*K6*Y)PEL,`E16rT9qEC34pBiE[C`#U*Bh[$CL21B$)FhP$ eQ'mL(QA)Gepj6`@1JJe%!6*,9aJLpHN!*NPEM0[#b2hlGBLfZIHiG)-Kic65r&V Hf@2Lqi,P'K$)rE2SDA6r-phm*bkS%q*"BGr(@SV$cSj)qf0GpR'KZNXEhMdB8)C [CGp8I#0PZDbU6)I4#(V6NE)9l56Y1`*3lN3F'X0`VLU@3+4V'iHY`P2"6(a8akc a+dEC0JAm0k4cNU*L!DcKl4H!!RGYN!"HL6T`&Y-G+*V@fi*EM['c,hN1med6j8q -@,[Sj#fl1@5Z(10F8qJ!bXi(*Nre-$f-Y%ZeacJehdm&if'i20&c0!2!"V)lbhH 58jK@C$E!2A1k%"-@EQdlJ#qaBR(k2Qp1)*(ak&RXXrY'1[%SqJRiQ#)mi#RQ%qX aYTpqSAijPM6SMk&JcZeYSMTFm0VbD!L,l4*bpfA'hAP1+QjDl'ckGIF#LV[DL+5 11!j*8mAp2hiV6eH1K',,,qaG'N'jM-H(deC&YCL3!$[6GNiALPqp#8Y"$Tc01f[ ac-4M+!Ah,ZjdZC1Y`ZF42FH!L!ID%6$ZH%!dqXSQm'iBP4,PC9J'd9)dhID!ARH r[6cDPhCGc)'M)"hDffLFMFK8BIZfe$E@f2Da8b4'iCSj54ZP,qE[%S*BC%#56J( Uh#eJS6DH5f(bZT@f4e`!amI1h(3*YMIDM8-MpA8hf1rJ#2eQTPq@XVBIJ`P[ELT K-p[cU+VHTAVVd5eQ9Hp-6mbCY(c2$PC+DG'qX(@p[6TMjCG%b$XP(F)88KUpj@M )r9kZJ"*Q03kYM'ZI+6`lNRLNJmfG-`K4dX-@&55[bSB[-d3p&8Yb[kcN(Jj&`9U r)`N*L-fRY3(EA261hp,H2Mj`YVp)@ZD0MqrC8i-M11pdLFF%Tb&MG8Z@3,F$SDp 80KY#2Lfp[fk%S*)Z#-Dc)TKd+fI#Q$iIRE`'[AY%jHbe[hJA1B3""2k@4SqQeQ% d3PqLa4A#13K))`a+%EMc!V-fJIQ5qijhlqR5hXQ%%Pd%9)A0Hb+JdFFEEQJXCi8 Zea8K@bKdiP,%8FP+HGe0f$fMfNIh[Td,-,1#%,9B-f0$K8*Gpa8bm)SmV!kY$S, &K9NV*(paL(-m5p5m&6*S%MA5"f-&)i*e'MbIL42#Y'91YF1rhTkr#9d9D#b3!$d AZE8P0hr6"VND*@0cB#b6cEA0T'Zk)afZZ2+SC-3LU`NYM&8P'Najl9Vad4%C-3L @5PejVi&(fm593p,'4qN!)H!(h0Jj*,(YlLGqV3HR+QF,%1D1F,RV-L'&'T@hM41 GYdrb$LmC[3H$@TlT@e(S5G3PG1K,"(&92bLJVeN1',F4k"Brlq2(qIYkQ&TCZFH 2M`&hAGQadLbZ58#$Q(ec3YM0RbdmAqp*Y+E"3d``4G*-KKI*S&f&Y6+pCfb)J-L m'8,0)fm1P(NEG+Ai,PG'F3F-6Zm23NT0[aP8,5r"AiIVCFRB$Z%IX)Rc*NjLHD& R+lCLA6H"0a[kS'LrM$dFMRK2R68ZPa'ZIXC!9k$NT"R-)LMPT5m#l1RMHVi5ZiH &pcYl&k%("p9hY"U2+ahk`P+c@+F![YKRmG19QE'R,iE(hbPX)b8fNT)2dAPTZMm +A5flGbScUB1ZQENhlq`[[$8l!Q8)$h&bf66C-eApIDV+DYET5!!3''$-qcHdTMA D$+IG1)b5A0*"IPm4Bc#C@2pca6'T+PFbb8b,6f8AK@m2!pNQ`M6Ea$44G4e0kp[ +p&CeE4IES6SUTa1@k-Za,kR9eILe@c[%$A`&RTB((+MXK16CiRY4FBUI2CST`Yf *K2j&d1Y)HXYKLXJPeDUT"E5YbGImM&"SEhL-lerMBe9#E0N3aN-DL@5$,Y&ChF( Hm(F,F$GbkUjJNXI+JTkfVK[iAM%A6E"Em38k-19HRZI4mBZRRGANHG)QUf)+d[P &4Yf6Vi20GpLI'ChB6bTCc,PT&r*#ERm8TTAK0Z+"4+$N06GpMdePTZ'djQZFfR' aTq!J'6ii*1hU4jhRH(XRbiY-+r(-i2KhZ)5A`@2l*LR4F'Slbp%m8rma6(&[Y,M KpUM394f'-F8*EMY6NHl3[p"-X2'$F+c-2G0IleZMYK30IYQarI-(2ZhB6Tr9ZQ9 SiCBIGpKG+Ef&6BbRcr`PX*B)Ea'IQ5465bDRE)a$STYXa3qF16d9qpr,fd*Qil& kV18!h$X,pmkQcVVITaR0h,Z$62dUrPjNh4qRj0MfQeI$Q,GPLQ8JNX(#pZ'F!a" K*Jb4Sm`X(U'eK4+VLDXdV@P(N!#-KKmrhHeJU#H!01*HeNCBY1+ACe9IS*e6BGa 6MSAUl)qQHaUrBf*Y)2"RMREi4@frml5[icpc8m,ml`e6GXE2ZBm5h43Z9#4i[ZN aY,)*X95(*9LjmarUf-CYIQMr92[Y'E2J2EhN!'(1HPEREBac6$dBGcLM,Am35Pk PM%9BbI%BiLhC([[q1SPmNDcR!f5%pmi6UpLLH'3j4E8CYC9djV,H#b9-Ljr'UAX lqBcC3D9!qPNeCLj18'cL5'[((IKdkN`iAE&rjRfI0Y-rbl#[0S%+YF%ACJXYEl[ 5i*%KI'p6e+jcdHMCQMHrQ+N0Y#MF&D'@'@'@*q'2@j3h6HV9*CG&+ReMFaP$rhJ *ZSeRrcr3"NFM46@j[TEfBqj+`HY8H'dS+*Td*FjCiPD8a3p&TFM#qGYMk(9F*-T $!`NM`LlF`k#rPCFGC2hQQN)"Hh(qFf$p@-M!jFrFip2%j!@Kd`'"qY'ZqIB3T'm YRVa6$(-U&pqTl2FaaBe1S9!&&G1I&hp@(C2rHN3Pm-jM8A-8cdDJ&Ti4)ILCTi, rJ)X"LJ@8RE*KI,N3"N2r"Cl3aQqV$eXL2'Z,[i-,,GCi`+UHb8A0F'%l$l6(E@b [44&efL6C#-"L9I[l6baf*$*Q0d-m-T9!&#[r6-0'HqHFaELq&"+QAr+F83iXVV" &DUkdc629BVi,&0JkhMP%U`[2T8-P#eU[&Ub8m!eqkZNKM!Sl9'(6RXReAh$BYK9 hM@52QS%j*iP&[j,U"KH054TqZQdfUS`,qjqb[k3B3,lVS@E*m[3N*8+qAqqPem1 DV$TI9NeaL(I"R'Y#F4B6lCHkBR,LD#"F$Rl,$lb+$0*0mecKEJbfaDC2`#ZhRF@ NbEZ!3#QZ!Xce&HfZb8#Xj@T,E#-dJ%I9[hR3X(kIKLd9YQ-rdi[f2(T(C@'Ke8q `BE[c1N`5i!-+S6T$jcj4T51bjX-5)SKDd3Jc2fCC5JK9T'11FYire#Lf+03qKJK 6jIR"kB9f8qTcZD3`HD!!02d!ZY3kFSKi,k-C(PM$2$d`&5#,DbVPL1K8Je(4biC RbPJcG#EQRCMf[e*E!J&*I"cZbp5"bbQMKl&&8@LJQU*Mp*X08(C%2l$9adeAPKm L%!I)6hRqa"Yj##J%M$$2HfH[VZXD[,#AVU!Rf"SKY2pc()640E9aLdTIFeE8Q9h P0!9Np4Iir!,*&58`!!PNfQ`89N%MB&)#j0N(mdrYhMPj-9li[pE([9LeTKRp4F8 aTGIIj2Ul@ElHkRq(E[IEe$CIEheI`l`IiGfhm1Xc)qV[E[`p"hqIG0r2Ur$iD-Z 4r0fHF%d`lKlTY@hiG2Qf-BEFk'Kih(VN&,XJTcE@6k"j8'@9MMA56j8Hjj3e!D, ZR1jj6B1$YSi1eFclkJ`%K'-'3$261J0`[Ff[L1FD&'dK4#Sj#'CcH#![2"rRf-c %c8Q`dXG2ZV@K9aG#h(qd[LYHq2&V[*[a"*5RLU+QfZM![8JVM0b@eIE8lPD`1'8 BFP&l1'1+k'E8)50r20bYTS4[#EpZJ`Xk!D%*Gk9)VAP91h[EIJ*TIRr)Zcm(5TV Qq"LU9L'eZG%LY`'IYaq,4#1-B1Thr"XmYU,A(-cj!G,KjcZ8qcK`HkE(TZ4JjRh !'HD(e-'CpdJ,0e+jFLfYUM+I+H@!i&rcmD,IPJd`UC!!4l&3C1jF%Q,TU*@F(RP ,*UX1H`L+**R%[@f5mZj#Hq*[kX-aa@JlV$f"p-kqfQ@'HJKGm"P1bTPNI2!GY"[ +V86XH[mFpQV1q9[*m`V@j"SU-je$J!r2bb,plLSJKX`8VpX+U5TReb0ZI"'CE`R Xr[i+T&rEM+5"0JTVNJHDE393ahkqk9J")22+AjZaqfiKc+@B+qT)d"JPVPb%-f* 1![!lZ3)U!1KGK#X2'D(#QCm0,RM+044)MG'8Fr)fR*r52dR3i[Yq)5CZi-b&a)A -lc,pU`'TIG"D)e0m!$G"p%k@B)G,LSdrq!XH)A(rA2QGYAX#dNe0eTRU&kPiIiS 5IpSclkq'`kI5HfpfLUf&"kbaaAAPBAE#[,p`,-N@2-8CK9%V+SI$TS"Hf-aBFPU iSB,3&eX*cAmGQ#2993)5VP,`3m`De-hf*i(Gljbi0`8NdV1p6#T+HcNkeMBTCh, -!lpiVmK!5aFqE!`dlD@&m"$`2QiYS4h0-I*6Cr38QVIc0KKSFUq!hk+2[5Y58Ef MK*Sf%K2i1FTj6T%62Tkbi+[V@DG!0RAqCiK5!F)h)(SE2NE#Y[F2QpdrQ$@k*iU VDM$"4%!NFqU8a6KSGmD[kC6`k5!V%4CQ,QMbA[(%"aS#pUV*1Qr1rC!!VJkca(E U4Be5*$rqYYfbFbm,2*5!Q`l(Ba$5&8l"QKjeq'e$bC`d-`f8)DqPB'H`CXa",b- &28$pppNUqLNZ5ASR1cQV18NH&dVpKUS(,%m@HBR&qXcCID6dFd,IkHiP&5"0Y[i P9#r#lX+)fVr"AVV3C0'bUDJGUkEAhr-e!*J0YZXf9Z[()1P`,i,$YEpiAV8UZ[F *RSAZ4Fi2$dr`9VZPpe!N%m`(h1VU(F%,'V,60E219NFEP2h*+-FXeG0Zl'hfhdX LpPJHALY,DjQqTaj0Ll+-#DdCP-5Jcm$f645j2r*IBj9!!96+0FAKaN0*(P)6bVd dj6%'HmT3[jLIm@NhSkkdV1RFA!#Z[&ZG1-AMmN5EN!$P'lEPIp2HD&T--kP''-b E*EPHja$eCJ8#42@,0pH9RYlS43F%3VCJrBJipDS@CU"2e84aqp4N9mFT5+T&f%9 c*BYAX"irVN@-X&PLX2(l%+rXF""Ke*VF,iYcd%Z)bLC[!CTRZ8[r#G$lXrcfIVF (6BdK,,PfMBk"Hp'1e`Q(mYRJac)p,2N#JC)Z1U3*-3J$R5hRNA`X,)8r@ImNCcM cK4ElcPqAeJ$Z#d9F-0T&pY%8[B5Qr2++HTZi6Y58RbG0M%6ZQ#[ZHE'2"kk6Hf- &Q#6+-b5Tf'clC$5em&G#3PL((eR[-(SF&J6UrY*`f0c+)TeF5lNETpcQH4b@TRr DCF#SBD(BP!#824r@UqNG#fMLJYfdDQa0G`h+`QK2(c`&X'IZHDPqedZ4fIbeU8T PGqE9VMam85C(iEkep&B$E%Ihq9GV2$!EqjBe(elA,-`E)+hrHH0#mbqLDSCk5pl S#HPViI$Q3M-6-98dl'#MlJ1V"1Fi)e5XJ+@@lU0ic%(&Y,0-Rj&*!B)#45YIYr# $I1L&"DBq&ZmlAeN02`FH"GJVTVEe3q-[8ScBqKmrUV2-PAq0MB2aViNM8F#l@FJ qimK4SC4Bj-RP%+14h0rb'aBkp41H$N&h62l%qd4N$UH@%a-9GiQ!6B!q,B[,rR- aGPDP!VjBp6"Bi'Q3!(HRE-d@riKXH5PEJ,rV&KRVP9IIIiAMG9A*Jq)$-rC6rCf BLL[hF+5RLVP0d+U5XpS4UVXdI#2iS6!Nkb1JB$6kIjaTYNC*mF-pbNpPIDi66&E 2d*81"X1(,NGN-EKTd#'$,P+r"Nd)HAKJ3r8FlNqkqh2)e%Ki-0@m*ahXG[Um!SL 55DL5dCq[Qq3bekj@lUEh3a`Q#MXjRkSmK91-h61@&)`L[XfQkY46"X"jID[iS4l BpI%U!3[I(1cBURmZLD#APKPV*91M(j!!T*82JHVK9I4!-&,[q4[J2&rJl25!D)# 5!`!ePl6JDf)F4V$9&J&B'elPIqN#jX1Q+1qk8E#1(rD8+U@qCTkL"Y#+EZUF*&[ 1ec&DHjC`PQ22ma+6hmfcCEB1id%ZL&QB#3UY6LV+PdpJ[Fh+qqrKG[03*-FJd+P Jf1E[r8Sm&8Z'irXmNUURmhX,90HXa#HR'kfA5``Icckh&AGLYhe"0QY4LRQ1b"+ )1VX85HX#VrjmpG93p(KGT$JTcSIH`N(UkGlCfrZ``R34)b2eM-kH"LR8a)ak[jb f40c8m@ccM%k+2qc%80rdZ(9`6i+hjZk3!$!F!+"R9CUhf3,"Mhr1S0Sj6Teaj9h F3X[iBb)N,5AApbT$#05[krlP4h1'DkM'8f6r)ZUX'90T9`FE'c$fCh)kV%L8cX$ eFRKkcf@i8XbD*G&eQBjZD$4&FGUYJRKHi*R22YrKS1-R0![p"c6e+TQ[!FPpIVr 1NSmTC`F$Tkpr5S`0NB88@6,mR++h5VT1*h*YPeJpr6qiepJDG(E*d-YeJ(ERp%K pd-mQjUh@K1*-&&'+b-X([$!K`@$,B(THNL839D)2%5"0Q)RZh3D!JpGVSGfCDeq 60RdMRTUIC'hN"dXU-Bba88rH4'1cT4f+"C!!%Y%3LE+hHa52FYMPHSM4`j9&a2K j4LA*S*Z-)hN(M8Mj"Zei,b$$,kkdZ)d1BKGNFkmAAh84JcN6H!)FHe&!P1kC21J Ik`5D$MKS&Y'LL"e$Al,UY)@p2F9D9rA6@E*CXQZ$3J6d[b+QJmIr@Jm&Ef9"Ifp Rm9hIHKJAQ'8$YRDBKp"ZiKYre#+[C91r+(XG2Rfj1C)@mBRD@VXCC#!,ZN%#S3c FY@L8i0l3BjK+a"TiXpG69%fVaBT1qTpjT4kG)ML-3K*RdV&3B-*FViFp8aKhB5P AE6e)86Sp%lbhNeDf(+JK$a*DY"!*D$1+'0fT3da+23qBd#01i9510i2CbGqI#rX J-Y6'Q%mhRS`6T*)PcDb-R)!8KNN&daUIa5*($9jeNl910'Tp[j3FFS&DLGrd%$k 1Q(dF5)cKXUhkQV3D`JS@C4eQY1dS9SR)CE2C!c&"mlHfE)984AUUGKlJQ2'5FbA m,bqLH$AURS,'S#!&+4!lV-,#DeB*T-Y+mPEd6Jqk9XJlV+K26NBiBJFMcEKr(I$ ,&M6Z01lR*Sk%+rmCeCF@42PqBB&([4$@0XeHEHFPMRk8'$MM!9$$aA##0Q6QN54 *pM`[aCYQK#ElP`@4de+EGYQQ1aXD)I-Vhc%H0b@e+8p0K-1Z4,@r"PM2[ESU9"6 @$b35XR1ALMSLm8Ar,a2[!)$*VC!!8Z!G6Z#UDS(I&kSi+0GR$q[E!4heFeR$f1& `+(M(kN+9c'V1fIPBTiDmUJQeLpcch"4b+-ML1LHl$D3iC2Eff1RE1K0h1p'X@dD YKIpMXc4#Mp51[`rr)l2alJJ"E'95DjM5!RZTfL*4k6mkYD5PpR[HIrpUI%4dXiV m!r@hPQeX4%d8[QGVCSfiUlN1L[bFLeS@M!k%fYBAaUqJSrXpkhZ`p`%AYLMY302 DZ&*TF5bTh$5GlAY*M)&rU(A5AifSFR(aN@!$AX,aN!#rXpL0fFh1R,!%Hc%+qF& `-Mc8i6A((cjR0ZL$,Z(MbLL9&K8dqTb!2jSCYRTbpb&C9##rf'C$QYmQ5r8iL#A TQ8h8'Va$d*BlKQI6hI$8KKl0F3UH'*j#H[5-R+Sf54'HBKpf09Kk5CP3CC%04!b T[bA$Ab-ZBfV$L%eFTpqRcU8I#+UT4RZ,!Y&j60ce-@2*`iMbeHHdMbeN+JIZF3i jDC!!)1G!D`FR&3r$2"1S6i5CL(qf99GY0MjZAmjceh2KFU,THFpMDV)b,DV#UcY XP5H9Ell*hd'c)k5!1dD(K4ZbdhIE!286XRaR+0jb`"a1CNHdN!",lM)CF*qHEbp JUdRQ`SPMJ5lXPNEZ@U-+fp'$4,fN%3eM)BmjDG(hkNpLH"1d%VdMH+`+mMSqGlR 'mDAH-4-8b(lLeA4Kc522cq2BCe,)f)mrc*T,BdUf&B%Naf$RIcAP&A$'XA[meme Pf5jGC3FflQm`#Y[`*fhpCCFlB-#!QIJL!fF+EGHK,8h%Ge2r3$d1!q6qF!ZkphU K(PD2(q!q'bFFdUCJ2b,0q8XhE0151QIm#VF$&!`3`Yc,JUFM460JQMC,EeH%+ES %BR+KY5VcVL(V0dY&V%k2eFVcPP9!cA[L@EDS0GLbJl0Z9PL8*&dl!i",LCQ)GHb !b6Kec([RmM+B5j!!kkr@ASq3!*`a9*BZGZJ,rN1X)'!SHBrR+"D&kq15`#caj"M C04EfZY(L!pdY+1VX4`hDi&cmA#Albf8IeVHmj"4arS*UBCjk83fk9(&`b"9CVBi `H$$cG28k5Gi`I5A0jc(6aC1BZbFJUc("HEAPk8dFl5JhP#hGBYjDABEXJrV4pmG m,B4YmX1PhVTS!28[bMR4+PF@GSk$'B`m@SBhVULZ[pVHY9k3!+DiiE[9%8TfqpE Vh0JDK"Xpc!,SPQZFQ9!hpKCcA'br$[`d'T+GKP3LhZ$+UE(TZ4JjRh!'HD(eFH` Qk3&P$@HNc"ba4XQbHfN$e#6PLK9SAJ+b+#NjBRlDE#+qjV!ke3UcMLLL8bD+l@i e!k-b[L)6CZkRQSrKBf8Taqj+IajQc,4#`H(ImDjEFC!!e4%q#)R[bJ1'`JB3Up1 U%A`Ze1*@B6X#a5LlbmlP*E&H`1e1RD0@&QS%M28LTj'DY0+(T4bi6XXDrL,#1&S 31Hd)Dj15bA9Vdp`)j1!R8RZG"630mSGQXj)K5'cLS&CT%U-mT,XJh9m1+J9b4i5 `E3[R3"Hm9(plr3NGfiG5('%!rJblmp8fHHZ@G%"Ipa+INSJ@5YjP[VYr0M+Y828 T%Yq+ZQCTp@ZLm-G#5-R`8q9++AU1G!h50811%P4-X)DTXh$+bq2QZ%-IY"FJRL# 94a+ea`%Cp%!EbM3p$b"`[`-I-ZpD)@56L'0CVUHFSjXLBKfSr4J-F-Q2)9J%e*r $j4MP[e1h8D304a@(CCVH!V6%dT3#kP"HX*cV[9'ZrU"dcmVdeEi5G6b9XGH3!%p F029MBV1ALXRUA83)l'bF'P&PDS8Eap[a2E*[N6@%3P2RqY`MP"qPD@@6q$8e&JK ak-5XCZFIUe[%c$CJ8!&MY0V5E%r14J`RN@U+1hj'X9PVd"-0jD$C[8j1TL6Id)F IKGQPMd0X-E@+iN5bbTkF6@1h,r2U44#RV2&K8AF`$biRlpBpeL0lE!`BA9Mb488 UpC3Y)Sl0U[c@40'ADU%j2r5P+1M$UR6l*qhk'6!'URei5UETRG4eBU+3!#rTJhP kKFXlaU9ZHq$J%U+,K-dfX%IG!Q%l9F'-H0L6lm+m2PHlc-KjcIT)BI&G1f()M2! bBm+[Q(e1-0)0,jCdaj!!bSBXTCL9j*rc!fq)GFYamBINc@(#5"fH(3UKeZ(DppN @+@RK%iT&cV2CCrC#YpeGiNFXS45Rf%,)djQhN!$Q@*Ai-MY'hUkVJSL$8URPE-E ifK!pZV`qjH4KJFHrhHYMJ"Q+pJl%j3aPFLZ3!*@VV6b8221Kh4-drC@UL'0NKFC KTPLLrJJrS*2PFb'Ic)h`Kcr60,BdaX[@NL(VELD[lGFiqj0D*c-i%BmlM!9**85 I3,HCl'MrC(e`(YC#PBP4Gjj4'i&4NGH3!(+Z#b2(P[e*,JTr)q+IQRASr8d&Shh r3`Gc%Z'(%1R*bHAFN[($&Q)3FAd)dkZ`Yb8G+'A-%1dMMLL*qhk2EA88d8bUh2b $B%&KcS,k%S'GA`Mp-R%#2dm9QN03phl%bNbQXp*DAl-+k8Yq$HEmDdr6VY!91rA !q2L3!29R9U3k(SGHP(iE+UHGVFY)M8X+Tc"jC@9R0hP#Hj!!hKNBbkdXQ4Mr9YL k%)MMqcYbDr%`44GJ+VpeKU8DQ*fCGZb&hM#%2!X5K"f*-MZl*R5%Sk&QKUm3+[N lV'`[NI*(9*3e)IB3'`K$bC@!-AlGcH#XU9E6**E""RCjiB0'D$&dLJpFI1r(k4! mN!#3!$`)P(N2%!Jq0jS#cd8"r6N"h)*JJQfQ55@*j9$#iijl5GpR,l(5Ppk8+iQ NEcfpX#D[VQL#KAS(&FBA,4kYMh1i4KA*8M6eCUAq#`KdK'kF4IFhi-FjC,)LiFj 4mmFq8imPQqa'K6eYS,c`j,aG5S2FlGY&CfA,V,mYjTPCeim0d@+GS-0e1pcZlj! !i@S82irQeai4GZF#I6#jKqF06AdLXVPh")+(*TIAP08l9&#ja)[Z65)4Ik$h%4! !FUG5k3EqIH`Y5dlD&b@"G-Qq,&e1jCUJQ02-m0@CH`[8X6m0+DqLJKMV+AXERac N`!R1l+fm#1mY`iT6APV'!E-hSU#V2iMQc8(c-G)(dZfFfH$Q+NUUa#C9qf0d64p "QbV-mCc6r2K4VNVN&V4%Va%2,XN5aF'Z'jV5RPNQ*CG$E5BX2aeME''B46ZBGSP $CK0,VYNrJG2V5)IZKI!m9p6F')rH((kM&a##0FUe%IGfdX4qNlMNeDKUBA8hLBR G+ISe4QU2a@UDMR@hDC%-0UJp8T4IY96GB)VdMc#@2(QA)FB8rZS@H+%DqfmG+e, Q&e+TJS@L)0+5!Tmq`&SI%Fj0k9IL)NlmF)$PAhS''!q05VlI[@YmBQr8fP&Lq-G P`9ca$l2YGZN2))2jSImS31TAV"i&"[ldq0hL+e%VGkIT1X6c#,CMRbK,mRe("HQ 6iM!4*cRcF%[GS*-If,MiiiNfcT9C81#GcHq@"[8b04bE`)`fPbbb+aN!h(a5)GB d2STd4m"haSkb*HA498'EIU0XVBcQBL2CUCTfHN-X"Im(e0Z#-1X4$bd'(iGr!Nk K48Mh!q)2Dr)Xi#$F"!I[AQ"INCG5Hd(%FYDC`6CBhjccr(%(4fEF(GKieK*3Nf( Q0G[L`GM)6H9!Ei&8IrUq*DHbb+,aB`GcCMmYHH,hl2%J&$#TRV3KB[&Y$ID)jT@ ,NaC634R82RpNd0C+eiR,5dDA`#T-L)`TPXrdXp5"p#Q*2kEdQ*hX2`DikRBpIlr fVFefZDhK*TKYXG)KB6l0e#qa1MZG!&a$6'pH@C%#U&$aK0UjVLf+Cp"rA)D2(!U 8mA+H)Ufb&18aSTaq`U%-BRbT%S`'6pEeNB&m*Mre+jVRTBpJ,IPVNA18@j6kd$m +0P'M!'Gd3"'rf4@J6Lr'*(qqe9!XG"8B&%@(94F-,Ti2e9-$*#-I9``T9JjLCCN "AmXaCfXA+34B)l&YMTcC(KEhZ3Y"`+IB5&K$@TTRj%**PYjaQH0"m@1jb@KRhlV r0eK"1q[ZcpaQq3HRAS)$[reZ6T!!R)Z9#L$lI6hi3)pB$G,"p(&Vi1CE1pK9Bcl 8C,A8q5(e2jLC)#$,Ue5JcfT6VICd64jT18LbqQ$!M3jR9,%$2S+jXqCi5e6r(T1 5-lcFi1G8()mk4JZf*jeT49cj9)95SqV$ZS193I(DK%hVZX2-I(20+!IKA`lmMKh dk$'&J%f[2SbIjrlC0a@B9Z38Z9ebTdcNi(5!ElCha[CJ)IRmTLZ(""Yc$#+!EK' -KL'3!2pIrB18Zpd$3@Y4dkq'rL+&Z1d1Hm3+dP#F516UQ!EU[+X!6LAcXi%0#e% "!ipF[iF%C!`m3!')dXN)EI%DUd`KkD%YEM5lH(EU#"Z6%[0%G[dQmQ43+c#!aT- i)TQE'1'l2R*BCbq3!%'#fMDHf[p&eY(%keQdG6PTpS*PmPhdY(SkP-aEV#Ne@#) &Fb-#rbPrE3ZVZE1j86TF9IhDKVla!#+PhpiJi3JCe,prrLTHEbDdE`"0qD"bh@e 622!`fYh0D4'%'(N[bR,l405lVVL6(1%r#0TNVm2pGj`ppQhV#X%'4)rU'eAq)pU B[,hq`BAaYkc1#aicJeB!VNr$cSZ3!-l8lYMrBmVVprjrFa&$lfUGD@$QdNhLq28 +'-j9TfjbC"@)"EN5CL,*l%2-ZkHUk9JpH`ri89HN6,%H!`8)p1cV(9KU09JBD`E aEKDc5D`-2-0[+DiF&6E&#AHcaZp`feJ*Za[E8843-''EIQSLrFQEdA6HIKif9RT q8fH,BHF#G(B(m`)+B+ThYcBR"+ieUl8D)f8B,(j&R0K3d3Zdrf05eN0!K`Ej+5V #pVehXqTZMTp6'j00$r5ArKJUM(XLE-!3*Xb%LQ,)5+[C5E%(lQ"F6C!!F$%VrCY qZhBq%e'YHEd[K5`Jh)h-[aH*9i%'pRpE*TSfmDE-`Cl0!XbbqC8e5!&aZLPFr3a rB2*@P0[5lHJmeXZIq%kZJJ-FrIV*-Z4Y[qIXd"A4@fLF4Cmk5$354hl)1UqMa-[ %+rp8SdqpLGQ3!(K0U*,P%*5V9eR)m*FER$KEXT6PBdkpp01rF6R@X'"JCk*$d3E TXfPiNXTP`6,2[eLPc1)$4*hb-JA)J@-BJ#Dj0NLhm)BaJ-$a$[3024MZjUpaT%b )UJQ5rNlJ@J$5qmY0&X2VCr#@)r3hilD%0VE)TSCBfiMd6l++P#VFYRr88j!!"DT D&lbj1*!!,e4JjQY+R&Hj*`Pb6JAh)'XN,6i'd`B'#c&+HTNH2QpjPhfBI'(2SFZ 50ILCFG,5lIKlaiDCIi$IR"5KjKUGrbZUa!'B'Ui#(IG2IacZfC1MZaUhb4&VE%0 P9Qbm3FGE,LEX&YRR)H4R#R#55HcE6P[cRhl$A0*V3j@1JPZSL!(!JEXNe83rQ+L P4280G34M-Cr9#edCL58-p)KML6pZi1iK5i!+Tr2L6)K,"-`-m&1,&T'4lZNF,[E ,FI-L-q)%h5VmN!$GP![r9drX@MPj@+8@-&`TXG&DFi[m!@S4Jf[)9jm[Zi0rEMr QV-L58r-dq8bFU6VFAh#MpIMNFDdj)GdK3VN#CT9!dYXEQ%$3C`AkRX(ci%K8Tj& PBa,"91L1N@V#0Bhp3Q1%4q$qXY'"a,6EhXfjU&l+`!$Q$&S`@6Fc9RiJdI5$*Z) HFLIT*H#Fd@AL69TM2$SJBKmriIma('NP"+a6f[l"R!DPUZ-k0Rhl'Q+(%Z-Ae6p A%6Y#lM@84DC`P*e1q3lTaXd,K9TUcLf'KIL-lh2Umi''hqfd5CM1D!Lj$$*,d(L -lc5@rL(TRpTr5PeT4eCXQKmB9[Zq"M8,XH$a'1-TpdqPSFHKcZi6jpi6E@bGKCY cZ"M#Y8T2GUC18NQjRaE6+4ES&aZ*,BV6bI[QZ,NX4h$iICr[qiQbXcM[UkMl1N9 4aQr!8lrp4b8bG&QL+DQmQ3Ej'qYYq""L-JD#Pq#[P+lFKH25I@@59#*6U[`2i@A KNN&4A("rP@hkah&EK%4qBJ$f#f[[T+KB1@2D8h8R#k[&4l,18l-E32Ff$58A4D5 -ZA1BR24Df&Bfd`%p*k*MfIbFH1r'+Q@+J5BH`4B@JTahHXa9(k(kUe#c0,G+Z`K V-MTP0,rq6BTRX)$kASb&PFP,0Q1erY&Fd'p!2!!R$+kG'pd6$VrU2&4,@+q89de $Q@``'YM9bIdmQN4RV4S0d0mD-PdZ,13&a5)T6hkrXBZ+-a@8LjYk,X!!ekLFj#I cV-)em+ViUcPeQITb(Cm00k(,q8+'IUA3fM1Sh%SEqIcANcZh1N-mhAq+dP)ES&G *"f*`cV@eK"b1Xb!TPY-VQcd-SkkTeTh*if(a5i#1H1(c8CFd(GQLPD6AMB6N,kP MeA[i9SaMVa[*2-qa5Lbj!d4MVFE'5KSZLdLSRKlAb1+%D!16$Z!#El$N%AM1ASH ,,fem261jb$1hRr#K,fA8Ve4f-KZeM5kDLIN1+Tj2H-aj'bEj!j'eU$-r2)8dq4D 0NHKrfLc-2PS5FE[`)iTQrc&%d1rp!$b#'Yr[VXbP8L4*m##b!&TmKD$fR'3!Xqc 0V*D#3DG!'1cpDKlqJ#`$(6RbCh3RliS&+KHAYq(fd4aI3kUB'cCJPCR(&GNa0(' hd[`LVK,RR0B5(1qHjVCJ(8-f0#6!V3aVZbQ6[eJ$+Xmr(+!2`a545e@[K"$!A%5 9aZClYT9b@#9Kfe-h"i!@me24L%befKd$,hKck9`B3pXK)qKC*A$fhT1!3E9G-,Q NQpqf-X)Hal`KB,8ehk'#JEQFBq9BRUE)5@%1bMMR`SKQh3D-,`JE#5keK"1bQ"0 SPHfZGchNAmfl2)SDJ'kX',qGTJ(A!c1AN34!51R"-+"Ia"!`lTDd-c,@AF,4eT@ T%+)ISUF6iMV4b[a`Li*C"1cJU+Eh',m"IibA0-4ZS(kHbE+&U3S8lrlH&a`e&EG %L'%M(iN,m`+qli,TISqC9@1eDYVM5lb&+jaGcR@TB@Q'(Qk(*$-d50Td*IJV`c# b@+Zm[Nb#mHRjZmS-qJ9&P#iBk0%Aah-LliYC&rY*4mcfaY"@lX0b6a5k@1DL#&J XrYjDXB%QKaE[[fc&1lCINA6`I`TD[G`5E@8N[4SmTS5ES9,NJ4fUJF9QL,XIGbV YZ@qCGkC*5M)AZH(JL#b*cmYF*&*d,KVkZUUq+jN,UpR,*NCaEMPL6-M'%)jfVJ1 4HL"6i`C2VJEHImQ)Aih,9GEpf$`U(rUUQU[i4%!ILJ340"cTZ&91RaL%[0HTHmY NA+&feJKXCl[IF,D6Z!k1@CZmDUm"11[0CUA15H8XfZk-591d9YbJ,MJm5F0``UK ip+krVjPD6FaFe,h1IAX'IiN!`JR@6$&dDhrl0&b3!,(9e%,cXhV(AmI4,C%qqL3 JV"qhD(a%AZ#!e""@2339Me$#G`*83cD0,K'`d+&Xhe2h,fkNP)DeGB3Cl)f9K&X XXVk(qe$'MR)X-hE!-+lS,)9Q5kj59JQ@lc01-3Gr'6NjAB*-U,Sir`$Ql91-rTB UASYV@!lcQPHH#lc3M2%fb&kkkU5+3+bPMaNKh8iHf6*SFNqfDFN83L295V5eGQ* BSZNhe$(d@TJ`k&Ql+qba$NZSSbXLC,R)PhVhhp+ZETJ*m$1S02CU!Zk4M)Ar0Q8 U[R4!LJAZ$1*5A#FLNHb$PdKJZETl4T`fJKEPA0[FViD2V8ATZQ`U3"UJEGTYmL* ECVe#[++-94CFR@1qb5Hrp2@"da@`X3)15'e%2JLAfriRiKf0GH6r,eMr"+$$bA, GCAe$)"01KZ55XerJJBqma`U43RJma8Mr6XHY6(dac5#5hrp4qjjCU'VdK[VN%G9 [bB0,e@alUMQm!'`MeGqrAAp3#%[e%DB1)5&)ZS@!["hE!Eb(*TlJFl9f1GBZ[`L B8@jHF'BlY3FF,#$rDf6d',PKA,[YEJD%`d[J0d"PBB8,ZCba0P$5NbANRaER(2% N`'ESRjENR-)1p4m0''ZJmFr@fpL1`+C*fY#rUBcLKQZGB"Gj52YjN49kl4SUi"& 4Ylpa&4!DXfp@CeRY0'j[F"G[M-%RCmJ#8Qp"M@"1KbKAH0i"32cc0kNp%J)Bha- ,aTmFH8#0km3Ej'G+ZYbEApdV4R`%28,L#P`K9"J9jh"R6#6J3,p!BL9MDCfkJY3 N368@+AGR&3G9D%,XUT-Z6+Q1B(l`lP%G-"PbP#mKT4#(&KBVj*Z0L,2!V9QiFpj +De&dP9hI-XKX31M`DCFdEbTI,5JbpeDbF0Bb2S!k8QUQTMq'$I$fkBJ%jMZI6Gc d$N+I"IQBZ*iIZHHF10PUpmA"c!d9D4FlHJ)6-"[%DMRILd,XiGi*(K@IHKE5*@* V!Lm-(qN!)H!(jCCl(#K6p1JjBT2GiKJHk$2'D-di"@U8ejbPX&QC*mh6,5Vq15e jpp5P%'#ehQ39rQAY5)6c5k-!f(*6DT["Mc%mq9S#GA5E'8*`YdJD[0*)S'!0[q` ,k&i(e`42U4$6bLES21aD4e05TR#2KPhT-VM'Q(!8`KJ`4RV",EpTSrG-'6j-e5( [B`@!B$h4%'M!!D%%5T!!h[aY3B&FD5$1#Q3f(FEbfqaX2fZT$eUJcrRfYY3l0DK `C6U2,UUc+AYe"$,+rdCTk`rkqH(M,a5d9L4,A(2&'q*%JbfP&IaIV2Ij`I'SrKa ZZ$fAkL([dR1apNHZpLq[DANY0#IMhpJ+bCZKeX3#eb*1XM)ZJX`arC9bpMGV8ND PE-0Ve5j3Skd#"",eZB$0V'5d`53l&amh0+&r%Cr,'*qHkkr)pI,Y'fUfj(&9eKG UTJ+B[Ta*X&!%-"'DUDD%JR)Gh1-44LSir+I#),!dMqD"(pceLY[--&T!ahc6S%h Y6*LI%*!!GhpV4Rpi0G+BCG8UKfZL8&&qjP@GGlMaja($*Y'&XAia#Bdr"$A3l3P #2@Fkq2JkTQ`hjmUa,,QcEl!pZ0AVhV(5CHE0pK54#L0RY,K55S1%!c$r@3!YKU[ p5&$X2-eN(q"0df@,l[J3EH1N"dJ)br9#HeV@U!S+a3L5+Cjb)K5*i5q2Y(Um6)) CKTJ(flbZ6VH"rMVDrEGa@EG,@+20DbX!KAIHJjRXlJ6hVQf#0E!94(QQV&!5jl[ 2ql@8(1fFpHR4Ij2MhZZCd%6eQ#hlV*e1r+BfVd906pQMGIZbbbZQj9`UZS)N564 0NahK,qTY@2IfpFG0+q2k1FkN8Y'#"bBahp5kiAh*qp(Y$,%U4Nq[r'YI$,q1hDQ FBb[*2)RV1aqKcXL[QPZ!cGjj"mBbpAGQ5k-hL)jZ-(J[B(mlj`jpU*(ZGK!-`jh 2er$!#D[C,6(JU'db2d[9)R0[2mR1Q"6'baq3!,*HaD&$4fPQ2#KZ2AD3!)638cE -!iriU8!9dTRF&V!H[(-$45Rd4"[N8(P[[Cd4Rq8-jTJE29Jq&D1fUXre2q0!XYZ TL08IG!UGr0@qdm3*EJcN'S@V[)c`PI26aLGmjim2q#9k51*ZAia'N8Uf1pmTUkm K!"iMF!Hh@,c@LRUj,RPX0r2iL3ImBiLB2J(I9q*H#Db[25Qhb*KNHp%2UiJFe+b pU(J%I9l2[+aZX-8X%Q[e68Ybph1l'3,rIF6DP"5VjRfI0Y-rbl#[0S%+YF%ACJX YEl[5i*%KI'p6e+jcdHMCQMHrQ+N0Y#MF&D'@'@'@*q'2F+F$T6GK3-QZUIb)U6r k$cY9-Ke9!%5($Gd#TTY"l(HfKSc&6K+3!2b%ec#i#[T"[fMQ`BLf),r&ZicFkeI 22GfpUQdZhi3DedYi,T3k@hUKqm48&@-@p`05%%#M`hcM-Z1$CI$X'&9hq#06VIp Z0Amf!`@Rcc8+-dUFJc$Y,b28@NarYe8)BD2AD8"1T6"JE4kYF)q@r&'G8SZ&(NH Ki!JrUkI8N3%+lT56c+ArF1qT%((hXHr!d("e8T!!cG6l3G-2GC!!LA*ML9%q9@b Rfd[$$*T(+!4Ib-+GlE5cLM4VB9QiGLdqD@AY#15`JM9Pq4Iq*m)2Yi5+JPb%Hkb `D!+#b[`&+c0PJ9laarKc&aIE"ZJb*8EUlj1X5JX-@()@$QSUfrL89,4K3,PRi(p Qh6@#$+l4+93m+Y[5HBVqGd3m52@Q9j8LHF6EhDMV2E$10CP0D*4kKlFEK5Ch&Ic QCG%ATV`$iQH!5P@@)R+6%%+mH@h1[I,5&c-%YIce+XLLVlC$aH0&#pH4+RD9DFb 6B(@Z"I&r33X(mLpp$'H#8iS3mVD+*66Z`30`[[,SB$TFhfCC,,ZFBehep6M-a5Q )RhY-50,r-E[*UZ3h$@h"FLI$bCHUQqcq`DBJQXCC#0"aE)5)+kmYMeppZr`)efD ZLj0$3pUk+X!FTdGJ1jSKU5ba5@VUM#!5-i8#&dNGM(-)!6)PfA&8"#TRj9B)Li` Gi2'#!64!2$&kcFZRqU)E"HeH`V#iJEq%&NjEM$&U#-dBQ3BA[e6GRD-e-NE3)Z& k*p"K-0LK+'%!@0[Ii6"U@ee$f44,,p1@*Q+`R)VM4V%Imm5,dHaK$m`M[!&'i1Q SEJ26pkeN8C8rTc#PZ$ibIq2ff&qhDrmhDlpY8CIECPpZbAm0UllE!aIE6YpZbGp Zfrm&FUf(J0PK#m`R44X$hLHbZ@5V#4N3$LX[43Ld`+r($Y`!$$Pm2A`pK3%-$28 ,'GA,@2'r-RhcKkE#-5U$AJe"V`DJei03Dm'S0H$8'["U$AJe"V`DJei03Dm'S"k ME@EHQrpkDA-&cbUPrcUG6UG6UG6UG6UG6ceN#3@#T,PQPBTELh&Z,F@iYaELh&Z ,F@imPTZ-*MP,qHL)GNAjGP$d@2GK,l2Ih[6HQp0[KMED@DQlfpfpfpfpfpfpfpf pfpfpfpfG%MJpZr!q+3(TT-0R`l6mNaqe`aJbdKG*,jj'pje4,)FY'`DXAd6*5)X 4II*@85IA,kl6`8aEBcPSNS41J2Q-`FUCKm%%GjTq)3kmr$I&dX6Rje'9I0E-H&H ZlYKbI038$2mp0pVU,EVf65CIH0!YPX`)[T19lU3qm1YKLREZ$kf3!#2YM+"k8(` Ibc@!@kX[3%jS`BJZ51ADNqdkSALp"BE%3iY!!!!!*p3S))$AB!9MINmNP9jUZAR G""Pd$FX(ePTalNX2DV9p92G3qlDd(a'%JhrP4UhbXkcV1Sj",#j5(QAZ%mkaNlU Bd'8l-"rF"c9Cb(T4lMh(Z2M4RGK-p58JX6j6+Ri6NH[Pm0YM@%"j%k+D!$L#*4N )#YA25Y%%mhXG8L`qd-@!6U@c(`0)`m-c,P#UE$m&ZcMNhLGS52H6B%+bZb"%&Fh LKFR8+Ya$)*C4aH2*30fF#SAh3Bap''H%VReJ,5"mU`LqTQmXp*jH5S[S5iC`J51 @%@prbJb$QK%H"kLad[dNBp4'LR$8B"2haAEC#HfE4Zde%c1#Y+FDB2&EB8BVf#e JYB,B!-2YlD(I)d@Z5ieHZ"Zf%Nr94YhGjd"i!P68@j6L%Ip`eLVV2hLcj-M-US% C+k5caQ%9qLkhfiGrhCfHEB80qHLBQIpUc```IX1['`9@)1ha`)FB8Tj$mb'4Z6( Ue['"-92jNK)PpRd+c$*i+S)raaq`i%BL!Bcl&jf,G1'mh,#L-&BBMV&"mYM6!ZT 8FS%G`j6@e'Ur(c1)@9De*Y60r3#+$fYEi5eDA4A2m8k-6@cEAaiq(MAl%9pc9LI FIqCa[4LEP!(2aZaKQB#Tij4TUfX-3ERl@8mS8!@"C*HP"E(Vi4S9a)c05A(!(hM IMiGGPN`aR'b5Ir#AG,cSe,@Y[j38PQp1rS'[2`)mXbh8a*-R*'DpXN'de5%Ddl` jcE2&4ZZi+S'Z0!bPK*fK'rdpq2"2JV@1eV8-6H-#pEk[L9VIIP*5Jjik,*TFVEX -M3J)lkZcL3rimJ(b5jHPe4TN(mLQ8d!Y65H5#TZR+3N3'Cb@-aUFH&lh$c[5+%b E)90N+QaD&Zkf1#1$pf2p(Pk%[bp4h!8%4q*5pMqkY24[CChr0if0'6[hrP-m[k8 !BVLDUkeFDZTKb@16ifS$1SA0F*,%TEbP0(fbhC+ZeJfMkC!!b'L'ZR)3&#JXRd9 ZBUU2SECLdiScPA'6FVd!jZ5)%2pr[G([c!JVUUUUUUUUUPT$bC!!`@YmaeeaTp2 &`F5%-I0lKT0)'k8YmCH&4qGfA99999998VacSVXRS9-CR5XXQ-RrBZ`KH3`i4a) jYEM5PPjE$2p-jR-jR20A1(+bNmFcLG$6hf!bPhplq&"%B)'BdMQk)#D#(GN-C2j JL@J#-&@ASS4DB&IMKfi!"Kbq(b4$l128,&%6EYBmEmbII1(TX)a+S0H$8'["U$A Je"V`DJei03Dm'S0H$8'["U$AJe"V`DL!f36'eXH2p22(P@LP`+EqG6UG6UG6UG6 UG6P')qV8R1&X@FaELh&Z,F@iYaELh&Z,F@e3,@d&N!#T2&'9bUEXdI'BG4Q6$#m $-a!lm8d84H+cc-cc-cc-cc29M5IdA1p[G[G[G[G[G[G[G[G[G[G[G[GP@mGLh'A C&cK-MF(GM([leEG+lMrIl*ZMk8ck@lK"RJCArR)iE)iE)hpqeL0He2L8N3%$-l$ %FfVB8fC&QEMU89*qFkNjF(8lRCbZHLp,b&@#k2pR#FQ&5)CIm-#2"*16&[f0U3j *Fm+qXp)EG&$e)QT8hrSlap9ihLLF'1HiXbGXel@hL3d#[S*c)[52B,+a)85BP+! !!!""HYb65lHF-k,44)Lpb9L*r5@GP`dHNDEkBNc3pME4HZB6h!EGa!'!-!AfkM- h(iZ2c'X6@S1"IIBm$V2PIildr"1&1&1&1%CjkcPr("q"6&eriq%P&pCF&i1$"02 f!NGA-51f-iTH&ipqE8DpPVrHmN+FA[0rq['JQ([cG29QII3pYjZ4N8%[rIp+!V% LF,eXN9,5`5cNp8"66Zl`Q[Ga(hSYQfKDqi'6qa'qJA,H5)&D*Y%Y@!mNKB*G))N eTqJfM,TLrhj%lXeLCP5Ye2SlY2@FP#93mj1m0"D-A[F*+f+5Di54*CBLr`(4c92 JS$9T%A4pb2Z4q,&,IrLC%#VMlI(5FY5`AqJ)3-6'%I"5@GbADQ!bGba*[KXH!Q3 h[8,r+KriVH,YF+ZPX"F1)-f&Gi[MX`(l0TfKFEKZ8V"%Dfp0*83Xb$iMI[TcN3U EV%K!0&*$k@m241DpqU$iiN3HD1Jp9V8!dY6a3*VpNL$EmXApCSlm&E22Tq65pBj +cMa`5&PA`)!!!q39"rcP$$G%CCX2#&,GiKI%kEdq%96,()d(jikk,PJ3lp1[,d! D'D8I[QTZB'SY,NHPXLU&PNRHPicAjP4aZl5kFFB`2*eDk8%c[iF,)EU$2Uj8X"( !p%MRU+$ArdhAjTrad"R4$%'`5r,[pU`,+'Hqp#)8(S+,qRPhL4ciT[)1RCb2JC! !,SDRhlEZmd+,,X-R2*ff[A'E"f`iTC[Dl)QDJ8AKp03EQH4k96f-A2Nd+3j%afC 8M36hC+2CiUX[e93lADX22kcP5"3*(m-2m[DND"MH9!lHI0HF-#1C)4Re@ZR%L"R cSf(p42X%q`8(fU#e*ZP5(F&52c[Jh3rK+1'&5&G2(h4A6XeGj#8+IB36pq(bqbf P4%fY6HX,p`frq&!Z2HG`F1[#r2Tfpd0FHVb'q2VLEJ-p-9eFfCPDNU&A@*N0VCa GH[R%NVHFBHVcL[KHF6CXDB+j(P5L20ZFrfX%Mi$&G99999999@+aK"hci#A8R8h ,L)AHc))1EKdkcJj&q@*a*NS`p(RhjG9999999EH6Rl,2YT%M84H"J'!B"J'!F"p cl"VF@hA[@0h2q*d&@mV4ldXUh(`EmCc$2-mcc20!fhZ)VB+54'(F-0K9SAc10-@ 431%,i"caN!#PbkPCbS!"6T)f0MDmSLhUaFGaRq1(EJ!'(,iH[Kkq(ViH`S#'&[( $iDRB`&E4'pR!m++pU)Dc4[@pCjqRrhpchde@d`K)Thp3)A2XZUUUUUUUUUUe`&' LX%PUXe#AHbe[Q$SURhYH1#0D'+iF#)F#)F#)F#)F#)F#)F#'Hked(UphJMiX[hr R[SCd2eQ!pAC`ipF%4%4%4%4%4%4%,Y2@P4&lrh,"S2pR[e2A(X&A)hGC%r56j#+ &jm+&%4cb35)bJ2FF9'fT3B33(YY$1GRh*X*TeRA-aNp)8V61Y0iHEHDh-r,i&E" 4DX!QlhQ0dNNl6+6UGe9k)VkP!K2rIqrKLR6[IfcSq9'bE5Ap`PPd+0*B*'#H(9T $h,@kjk8`0C'd1N&R9mQ`-cAZS!qq33RJrIf+@-D#QNEAR+-PI9CV"k&#ZK"FCpY (a3UYJN-iN8f#XmU(HU3)Gc95IQ5rI6(ZfaYBa2K(ZZGmDf#[*+KbQS%kTj+AETE TETES)-XYEZDBEaANdQHjI#Z%FEP--K3dr)+@ET`eejlZ+kZ6ca8G'cLep!h(K6[ 05#6`Rrpqm&l-YNK!*BRlI'HdDG*Ml6f9)PHVCY-e#H%UN!!@2Z&k1&1Y"dF!5@Z )!NDBcM&Ir4+fCCHGQ2RT&5,)Bf@EeN-[rf+kIqAH[r2$k)(I8&6,mY&,mm2#Pmp #Q)RI6N0FUSq%*,XVB2lY96Y(H@afq1XC-a*ZjV6Dcj3`LP&RTI&K%BGl5qN6D@M KVNP4@&fFjF%bJp#&S&Mfb'!i,4V9+TTDMfAMVC!!ed*T1V0d*h9h@9JVLbC)QCK 59'[YPAfSFD3J&+6,JiFI"$ET`a-G4`rXERR(#SC%I"$V,T3"H!&p5IpP38'#&AX KV$J+bN!EM8cpQIR#5iMIiEr@pdV2K-B9r*2bhV+LC'`Je5edlk"EYUZ'0i1UN!" iiBe9%$Hcmim9c)-5c!p[mI0ILMT8'feX4B1M"dK*kh0bk5hjXc16ZXN&4V+&EK` ,GabC-BH0FIm2q9cdlIG)KVC%''mDII[ejb2im#a`l[p1K8l*8XXk@'hQa'!5)GC T%iSM8Ll8p#iN"q!cHELr&#J!FS3MYMe4TbY$0kq'ld[3DeZ0LmJ+mqG`B*!!RUd -jC+2FIm0CU6[)D4KJSF(c%2EXUK-$30KJQ!E5iY8p`XIRkc@4YmQ2D[',H[aNRL CMIPmc$-'1PF51UUHe(IpZL13!2[cmU--0BCqMC8,8Gcbc$pi)L-M(ah,F+R@#Sb 1#1)SBf'K*Q,"3p4P'L#SeJ0kU6kf0EbJ"Ie02%5H6BI%L`SB@epe[K('4F9GlGB #ffQ@pDYEq&!YPRmpr%UIT89H(L!61id93dcN#"Z![)5#BS*LJQ+#BbJP,i0pM1m )!8!IpeL8)U%[rZlc(CEj53PTD@QMDF0BLe9AN`+%K,rqpb1%I4ef*3X-YME#EXa rIQV4IblGQlMqVUUIZUkcK)9Ap9[Si#Tf9)4k'+X249M9N5,8r"'C3,B"S*D3!'d N*!PXU2pZ$'FhLXVK+"hP3m$ikG06&`0-@8ABdS9VM9K8Xe$q6431%,i"cacacam "rpPTBc!j!!'DL3!!!!aU8#!J$3U(#J!!!"4QG(P`DR!b)!!!!!"UF$)J!!!!6fT `-QJ!!!!@D@KNFJ!!!J!!!!)!!!3("`!!!!!!$f0[E()"!!!!!!!3!!!!)Q0NC@B !"!!!!!!!!3!$!!%!!!!"!!!!!J!#!!!!!`!!!!"UF$*Mrdrr83!b!!!!!!)!!!! #!!!!!!!!!!!!!!!#!!!!!J!!!!!!!!!!!!!%"`%""`%""`%""`%"rf3!)`!"3h* PBA4[FMSJ5Q&c8'9b)&CPFR0TEfiJ-5ij-$!Z-Ip5!!`!!!!"!!8%"!!"re`!%d" !5%K35%K35%K35%K35%K3red!&!&!3%K)8%K)8%K)8%K)8%K)82pG!"3#3%")5&" )5&")5&")5&")5&$rA3!8!d"!5%K35%K35%K35%K35%K3rj!!!!S!!!!"Q8J!!Iq 6hiA-%9"4f$$4TMPE!)3-6p,6%X&BiG`8ErYT*R1#P@iqS%d43ZX&9[Rm9,6iq$` ljLr5)@$CE+*frY($0bZ88MN*FaF3#pEF#iQ,1[C%TFVT)#&T'*A`A#bH"XpA%Ej #5`XSI*88khBCmP'm(PA`e!,U#&KiFfdB#"JZIeZ4*p%SXfN0m##6M9MGEX$&P6f S)6U4e4Ti@jji13l6ZUpbYbI`E$"lbNfl@IhGidfT%-mr*4#hfcP9IUGD(%-J-b@ )D2i)4UN'hipJ[X)4GmL(l6`9D%-H#f%$9F@LcM`$eCCLX)0PlTqrIKI!48%U q@K(aVU4f-AbP8d[0$X)30VrQ-'If9+%EK,lR+2mb#@4keZF-4"frHq%YrJH`%iU D219D(q)C&8[ZbBNV[MD"GX12R,1+99DYi'M)j8e(K&KLPP,3qj5US@D#A6Jj@"% d4(l%Ah%R`[@XiPH2U$Rmk6N%l@mpM[1P2Kh[6CibSfC6m&d3ClIJM8988H)9IDd Ih1PLaH9*c*T"QS+18+Rf$CM$+@RhcXEfi-AqR0q6PV5l$pLke1haN9-$hd`R*c' #4jdiB3eh`'[c,2DQ2i-X`9E)R"+PFGY$4dL-G)rh8b9[beP0VRphDGHDV)X[aRU ,B5Z8hpq&i"&35VjD%I'ZT(BaI+965md3T(mV9%NDQl4cTN-b&kL5qqK0PajNcK@ k,`81j6+9LbM6Gm&eH+T&UjQ3!",FM%I`,j+D999!HANP)DZ#U-BMUM"ML%)F!'e `%fE1Mf`5ELqp+,F(,!r$9Bhr+S@BkP!qi#EbkBI@T)b@b1G-5q#BE9mHC*A8(j( 5"c#fQ%pP*EdJIAL9YN2(l6PCem9Q"S849b)p05Lk5hf*!Q2p&0J8l4X2dH#Fa,V ,ElP!FL308iM&`BAie%NeQjNK+@Ylrd+l-4VaQ+E8fC!!ad!K64%I(Ncq@e+Drb8 +`fC4b-LH4ZGlhiA+%9!p`lilk1JaEr(b+5'd*VH+'TLfmB4hke`m4f*4l$#qm5l ah4ajH6-K)FdZ6eD#QqE"ZmF1"aZb'D&'JA*ePUmJj3!N%dpSd0jQ)--drX`#C9T 33%F5mLc,h6ZEQ0PP$JL(`6'3!'%B+dVREPfTZ8I&`6ICV9SmNqcD!@fmeEJ@X@q pQH+X-ES8ljJ"18ej-3I3`H6+$JV('&,GK49M#e*93cdpKp%k+N-reeTMpLX%-4[ eDBHDG)9*J5#r"i+S(hP-$2P&+Hb!jUbAH1i)9-)M5QecXY"@Um-c)8&Y`#q+)q" b3Rr2`TUr1TCqGD#(Ee,C6r8G,cJV`Ee6Bi[!eSQ'2+PNj1S@HSjC5N%q#ZKkb9- $$QhSPqP@a+I8Jl9REC-F$b@ADJLGXXcVPr-#!QE6(irLH0hhP$NV8%JNlYpj#MJ UP%f6[($fa189K9%!'3lUEcNh3+`J@Cq"ZSJ9b8pF@6m[ZN"c&5MmAE$Z69T5Q-) -Cl1Vej%&Y1Rc1f5c"Z)eh*D#h13(Pl#`VdF1rf-*r(152qF2cX&r(R)e@'a(c54 '[m'aVVAZY+-qf%[KGI2b`"qCP8I`f-GjX$elfp&c)p5m"YJC-ZaVMjGQ#DPTG4R `U)0af-BdZ)J&3TU+f6NeNaB"Q5rZBiP!'P-P#X%(rP5+J-2V3mhbdDeJA1DdrMh (AH,CI2)p5pD"RUki8F+#c)IrETXA#B1pk"RN5B!e1QKAic'+Q2S!%A1RGZbI`VN Y!6h!hN-#iJ`'!SEIST'H%3j8"4!RC#kace'mcdjYlUD`[5!V--qc3MkmR$mih2e `XXJlH(B+aThJNCZcM9i2eX&A2%S+UZ#AGGd"Sfj0Rr"%4Ac%+XJr9Z"!cN#rcf2 l4f`!-amYHpTbphb-k0)&C"G-qj8lbQTVT@#XbRS,UVVKEmABRI,*)!q0d"3Fj5E %Nh#pPcNf[2XUiSq+iQML-DBp0YGPaZl64$31E-Brcm+V[cV1IRBSKfp)DL'$c9D rLNEkIGHSCVQ@d5B3jXDE!i!bh@P*BAV(Z@aP@#VHpR*V(@X'i2&24XZiS9Ipm@K "qpZ0ZcNd5hfmFM8CCEfd5P&2%rp6UKmAEQ82Y#[SKL!aTZl2ZSZR!#bDF2*epBS EYIfJN[pZ+j*F0rL1(kaiMQc'CE9r9kPi34kl-mI38C`E'0NQcEFCeBcb+p6-ah& *hALT2hlR,,-Ld,CkL)[eI$DRPl#`Vc'Gq%2!"U9'+NKQ#IC%T(Im4G&pFpZdp+q IpM$,"UNB(fHFUiHJqAIp5ae2BL*dTeJ-qfI3"b")'9eDq(3V*hcDp(TfZqS8NBj k+f8k!UkFcVf4Vhdh#)Rm30j0N!![UIpm,-+A,M&G+lLmNAT#[Q4K&e@2m1X%eL@ I[1q9j)ki$LT'd'YA3$1F[JF,6LiPc$5V1&20BB3(Y%6Ip@MaT'h4peP0[,mI`A) NPl`)*!"rGZhF!`2QfedjMQHHhNE83N,5VRQU`Gi4@!phaT`d9mapcV@K+l3-H`l 2iC5)44'E9eNlk#l@p+`%+pVF6UbYBJaKdl*bE9IMqY+EE(fU+-Rh4rCe`e!(0C` JU($$Xb`2p-)4("[&U%VNc94AL[h3kTq8J2L'1*cDX[f*FQE`BHc!"aj,RABHHf4 G)Hr-1IC9e39QPh!&aL"8SE*5kb)b'`@R0IUi%3KIGE@EUeQbP!fj2XDHIS@J0Rj iEBCf@UC5[d"hrhr2`TqIK9%IK@U15"3$RfBSKX'5N!#j6d`c"Zh!AcfR*9NFl[S )Ej8cmaa"[JfbC))UF3qbcaAFA'LLCQ$B)XRSSC-C3MU+UUDrSHB,QXj"BQ8418* dD@,d$+83[&4I28)ED9B$rQ4MJ`AdShF2D8LZFA`fdccJSbdRHrDrB%$FlG)pGZS l&F!Kh+)$G11+'3C(@4NDA6)3$*GfD&##AQmUTZ@4e*2[$!AhId4,aq%$)A4r6kE #UK*4-8KIFf!JF0GcNPGRjrVEDPcLL68DNBGm45!5CNB9IFp2R`ZA(0e9,NUk,1A lJZbelPQr6TpXlFUNaHKRm54Pl'eb[35i6HU,HH6b%(HVU"FTTYE8p(d2(#CLprG X2Y4U(4M&hl[iMG80'GRAC+@L%qQe4DI1S!Y"m8&3+#F4F6968EKkKXUCX+M4KdU m4MB&'&L@[3[ZjIprE$lFV%K@("mKUHD&EH5(plb9M92,DAMThqiZeYK1HTG1BE% 2,64,0aB4[B!PD5hQpM9b'jLKkrCl45!f2HU1mZ3`XJ8I'cRHM8VLd94')K6%*3G ji,0jh,p3N!"%k@UABLmh$pD+iU#Ff9R`kF8MN[Z&ed"[8qVp1c%[f[,VK,%AP1G GU`fX*`!UUY)-VpRhlB2MEpKGQ(VKpr*Pl&%)SpG34@i2LXrl4E+kfJ8Q@S$$1aY 2H&r2`T@IK6-IK6Bf-eh"eR5Z%C(@ElX(T3D'``rG4I2Km&Y!kFV6`eK#&MC52!0 #12T,,2%JLh%MX[fj09T!["r6`DAL+GM-hFLYFGR&l$,RIFhXAJ@f[KaaI,*L!k& U!jCrN4BRbHR#%&m'a$4*6#fcd'8$E9H98rKi*&Ha*cjPbU`Q1*h1J+TK`6eT+YI [ZQS,)04MEh2M-m)!J56LEc[MMJpU@SchX"riVrPaBXBU8&Q6#6Zc#&dp3qY#d2- MMa'rkH@cm*L+4cC0+i#elm1JqhdBiY+`XR2H!ADJ9Q3Y@I#Nj&jbACMmKIU)6PK "0F!,h&@Ip9Pb,di-,0h[IArkkRLchdc@Yc0r'V@ahaE(00Mh6a0A3&Vpr$1PEBl S"MlZ2IcDd)aSEJUrcqr@DZrb,S#Ki*fQ(dba@pCX-8XmZVliHAE`,fBIB`Hl9Hd Zm@6Bc(FE%0q)MYA%e&Jp5pf(9r1HCCYp3c+kXHNHS(UaP1XKZMIDF,fcCV$A8D8 &eTUTBEA@H9E!&ATTe$PXL5JJ(@FHep"cSiTj8[3LGS(0kGKHd!kkDI*SUJ1R!Nj T%C@"UVb"Y%SFlQDQeUJ8I'1#8)KHd#F(TKYli*8S+qLb[16Pcm0N*q'dNIKZi+J ATM(bCU',A5kF2DGf[-f2)%eDN!!aaBB1+[$pNB#N0J3&bF506QAhDID96UljqD" "SJ,Ypr"6jEIpiHJ19hrb,4E&iREPq',hLD&SR+M#,6J-e*ci0ZIV456R&Cp2$F@ LFH"1b2'"&*@SS9'VT-Md-I@pH4%cHDIDT$FCpET2T$2@dIa[,4*"bITPfVc[ECL I`D'Vc`DaPJ@eUF0c'a41QI0DNaHFB#+RD(iJKrpUUZbC,M2dFjjmjZ@pPE%L!*) b-irmKip@)LiaVB$R5NGRJ@c0)'UXSl4!&`phFUK#df`SF%E(01`))ZT6l#mlZ5A i--X0X&rK+Nr@'iXNVq&%#-pX(bR1JP`@8T,pZHep5T6eRh1TVmk@lq6&F,RedqE 5Vr+QJRmJdN$&hFVG32+0j41c[McN-9SNj$H04DG6KlUAl6,mm1MV+9GLbMN,ilL aQ04!bGqVN!#cm"[(EYP%dR52pU5jLmC&63L63YmdIiU5`rcaCVe+91i!c2KQ'b& XVrSEE"kX!![PaJ`cNE0N"k$$bDA-afQSQEp@Mdi(X1%%HNA!598XX23XiDNj*96 %R)RRd"SmV[P[XD9ke+1"rIDD*X*""eB2h[4[6CNeb@+*lMqhlJGXf(-i!,Ccjl% i,f3GI$X"IcTa*aQ2P!1$%Jm!(cUI1lIlQ[il#lP'6Yh!T$&cd9$+98$`NKM&J4i 5X0J(Xk*ARB+XmS9jrHB90Y#dQP$(LpSPEFMiHVeMa5C5r,JEbi@3!0KFMk5%q%" @##Dd2AD8L9*A0"--l$LKYe5"i,#PPD3kqmQD3!K$f`l)LH6Vc%r%LSq(j1Si3i8 iEGZKIG"Vl4Nc@r!d%'3UL)U,mT+[l(939#8eQ#6A'8V,d-DMSBkDKk@&#BHq-5Y 2DBcpqLAPTY3--48$J@MKe'*#[ql2a1Z!!SSX4Y@SRi9f%qlG6eX4+rZ+iYmka1C 53XjI'bIJ1Pb0qZAR-XM@*U#R*clp03TPP$F%8SX8,KH#H#qJ#$KG[@(d*#Y,UcJ p!UH@$+`8MP2DPpVUaFGhA#V(ZiPbSl`%rFfN)TS%q4*5d3D-Tq*!DG!&a9V8CGj 5dT("2Hq&&[Dq&K%40M3b,Imd8F0!LJICb$qeqa`LQ$P94%b9mlk6AaJJFI*9*%T Y4M`L$(#Y8eFUb)K@J69+#QEFJ"d@35)lUJ3S*!eUP*52b&Se$&(2Vda3Y8qdNLr qbIIUh)1CmI*STe0[VZHHMZ21YTFD*HbLUE)8'2ibIMQ)#Ij,IiKrafRZQDhj31k H0`Ii!50mDB,3lM++J-PURABbNXTJR"P6-,[kbKXDSIU,6)2p"VASpk5#FAISJCh 5"QTNi+ZXdN)PT6`2b$85FTMN)512aR["MpGBIELr(UC@B-4e&jG&6Jb)J#NRDj, @jG85U!KLH!h1ArJYA,VF*m3"S``+F#KN-fFF0[`$%#Hrh3YYK`I4LhM0Dk"X[!r [ShQ$D9[6#j6RTNHL(8p55MY)V#h`b4dTpLN0rI)+GQU53K0B$VM(5@hJ3jRh6jd [D'cS%j6U[FKHC[&e2"&#KE2hd-m6bH+l@$V+Q8r[bY9SVKR6)X,0KZQ1lN0fT32 %KjQq,aVck[adRi+l$Ff#A$'CDc31*LH!SXA0[M8"!I0L6q9&,hd+'VU6!XlDA`, m#(8a%Z$BF"ZQbJfGYPDdreYPaicL4YB!#QP[cK[cPBN0JY3QZpm"M)`fAMladRJ 1$mr$HLIK[r2ck,#S+2X`jYmM9)6&0+@fXXZ8K*3@X8PfaEfPHCBG%bIA1eb*NL+ %m"G#m62a5KY$2E%d`HF60LCX02U,Z('#G4JPeT%'%59lA"U@"*),Kf5lal5R'Ve h%-RQlZha6N3jZhbP!`PZ@2cAr`R0hMBXb9ll2if3!*NPaS6L2FME6rK"C4)(aE) +IdV)iq*Nq56i$bc@Q90#FMj,aq$!f`A85K@'KPJa2NDJ4(H1Q%R3dUNG@(*+TM- P$%b%,$@[[*-D!"[YUqN[,I"Z+fl'rbrm94qmP4eUD8ka"4EJ16&cqQkJ"'1%8k6 bd6FqfElCb-j0eaAdPM&`YlqJ8G`aq)`pA%C8JV4D@DbXClXX@mP(53C-3ZcVAJe *0BU$D'+2$rP#QQKEqKjMAUbM)L2j`$H!C"@I&YXZ++k(93[pLi8f'-T(&H4UFZ` `#*150)hC(#XrQUercr`r-URd'chGkLj$I!UBIR)8&)F1dcQ&"Gl8N`R-j2(hEeR E*2P+GI`bL%Jj@T6RY+p(&"BPP3TTUihcFRc6N!!F'[&Df*Y4BVB+hRM&'l%e'3p Rp'5+BiEl9+A'4U-eBTlG&GK!dpI)rfFb9Vp!*H)UijN+PH+3!0$Yp2Xji#(ISM% '#aSkb[&"e#SVJPMC9PM&-2&ki+8,2k$$bDA+RUCaC%cTP#%&qKfG9pEF*[ejG%% XQYbTj&)rV"MAdK(,-ZL9Q*RH&,-ehdX@Sd8F4SS2S@Lb@Jrk-[#LM1N[XUfkDk! QRG,%#Krp)PA5ljc+a*SLYPa0r[fq*r6KJ"*kFXZTc8lQ01ASmjhD3CE0i)Q9q+` CCaCHfh4$r&ihJ,*jU"1DijRA`$0hPCDD%dCIGck3!-RqD4B0kK@cb%5$aURr9I' k0b@DQ4V!#ZP*a'+aj4IhNbe5'P2r"EVZMM&XX*`lbYf"V,*(MCLUdX8@ITrCYBE 5l4ji6V(cc(1LI(K8I00jjCC9e6b,Z9XX3k5I&Q3Xj-EF$(Z3!%"c1(NMRqFbTSh ZID+IY-4UN6kk,!bR(![MG&ie6,q!r99HDU(PNZ9miDXR[E-J@)53!-P5QjP0h%I pQ!#H[Z[$!ddE(pVJ6U-@[qjZ@hJ*m`@P"3[Ge1)J+pM5%le`6jKD+VX@rBkSmBY `Fd5-ZfG*(#YMha-Cbb3R*EE!NUrZ@,lp4UAj%e`#J#e+0EA2HiKDPbF6@qPjcFr 1BM1B%Z`rcM6TPLQQ,A["%hY%RESA4aeNj#LiGA2S@f'i@E%dbJ+mRd3NqSXXX@f RM3c6[@dY5$j(8C,ldjRLjhXdhUKeK3AdiK`0dG&rkFX@YYY#b0B*Yaj5ibLB#-B 4cQRjB`0bChrA2JSZiV[0l-`&5XI1jDHM9+md`@[53q)Mq`mV30UM#q8!QbNHRPq TNXcUNb"@*NRFQCFBhh"TkijU2@!aPY)1XL8IPVb,&2i4$(&+#9DFXhS$4#*hEac hK5*d"%"hDd`32(&C+2F(DB4Vcp)#b8![N!#Va0Z85e+$ZB@+P,jTU"j&bXY`cGK @!h#$3J*cEIdZMfTI%GcSA$bJ"Z,dJammR[&!rc`T"2P5`dr6j'i!N!"Z`"GEQCM LQ4Rb+&iCE+`N0b)R-bUIU3f6-IYl#(@2Kk!YN8fQ*P2i2GcN*i(K""9qj5NaGlY PKHKdh1-*Qk`pr$$r(6+Ub4'$rGH"jcIpcPFhZ@A50k2bYV&0E"d`6C5,XeVR)B" +6l[+fk39M*2B$#Lm$BFkSNcDTbrDh30fRTIH[8I@1p`CCDYP13`k$LX@2dBj&!G j,epqM2LN))[9@2hZbA)YS2IM1T(J2(RDX@Ij1CP@YQRR[IP2)ERQT,@2$"9TZ"Q H$3r4erSej#-)*I"hDUrFMQFJC)VaKVDfVC(1ZSC&XXPdcPMUh+`LHC5Zk5XjmGX $'1!IflJV0QK-fLrZ1M(iX"6H*6Ik*3YGf5iGRUPREKe15L#8H+JbVcd$PP-e4!N $Fq'GR(lQTJ"ArAq#cFCCk@)28"0kAfF*V&*D"IKk#F9-Dj+rm1ap!Bp390$Hb3) Z&3i+LrG(VF5FaF!1m4PAZ`ek!H!M5dRAKDZkVq'M1LiRr+4SZJr2`h@RiEecmqK XeVr4A62qlS[phc+&2eepaeq[40PDIMTBq%fPP))ZelGeaHNdR+ppTRY0HqT)PI) qd2j"0M2,%3J1dT@DKcV@![6A1qJbI-mXLPYXK5hmjAAhjZ+6dFD-j9dMRR1XhZ- YSPe#4''A[1TR+jVF(!(RV$("fA(m2Q`%iefU`hUlUXlK[jR$'&VqZaHLq3aCZP) 4)e6)3"Phk*YK!IDNiE02SPR,c#SEhM81iP,FMBY*kGX$%N!"*V#d-(YBEkG)(KE rG4AN@2%%rC+YA,%3kZLXq,NfJdXlYR2,rQHhNLCLAXH)mGP54U!L'PeI9*&&K8L Y1&kbZ0Y5eEhi`p#iDH&iJ1#,KHEqme&,)#DjDp!N95"b'jhCkeRL@IZ+QU90MLc %E-8)`)j0LkJXQiRFq+`-5MN6Z8Ykad#"SeXj*,ZUX@DI-rahMM-2Q@f6lAIpCd% 3*e-Nl*02Q@#2TijEaL`T!8pe+5p%XM6H!,'K11'Y$V'41,'rfFJJ#0CR515%%AG *TNiMpZ9p`8d$e3QeS*`QPm[18$VV5EaR6F$!BmZq%T50&2H)IB#MbdCNYBGj4@b &G*P1'SBe3TAlRZiEZ$[!&2C9imkePXe0AFL4TmH8SNQ-B$%*dEr'FG)'02S!rFK G[ilkkkhV5ieRQ'#l@V3VC((5&bL1drETL)NUl!NZ#lZZBRcXJ1,YM#bK+"3(fpG ZVKl#4Nb@%,1&`r*@DS($,J,,rEFiGV22iHp1eFBa,lqa2p!V$#`%8+(p#JTLUm@ Ll%GZkl%CapR2[2p+IbJ+mPhILG'%me)@B)9e"jCqKbkj@G-SP+Ca4$(fLePIF%6 KKjY#5@TrAJQH)Q(&4558M2cca*S`4ZA`I'rKY5rG+GfQe#JS-M0Jh$V*9LA5Y8N 5"'GC"PTjPiHA"I3hp%mM(,N3T9hK8)iI8ZR`YHI@d1D[Z14bUEC3m4j-8$e!#Db CdbI"8RpM3(%dEY&+e+lhCY,)DjL)mA-rR@9Jl51UJl28B-N)[c[bI[j(Trj%(9' ,4Uba`Z62NK)Y0MX3!hNR!9f8*JfRU#N,G4-lbT!![`%(IELZ%@@6N!#GE5%fRZ+ !%S8CPSeDcZE&r&cG((AZSljA+9E50Yj2RLRTe+CpEmj$+ND1%dcJNh'+`)RqaBa D*8YTl)KTk8'(p!PV-C8)bBC[BSH,(mGEM-hmfadH,Neb'[-bJGQU[%IZ0S4M%KA %Dq1Ial2D4Dh-U[[5BdJH5-i'UcX0L1+LP40*0RI$4jbPqZ'UC9%APEUX5Ba),hB 9RB65`AR`+!NVG!NaiR(j4dcB+%Q!bqE4Z#kPcEkRX85`0MG@&Yl"SehhZcY0UN, J,"V0ePB8Fj2RV6Y9iaSlKD6630L9"rpEfHD(b$NXYI*KJd@pIIl+"*ilFT!!f1! RNcra[6#K6ZX"ae%SeY++l9&M)N&$9kp1Sh(*3PNZGAdj"qP@q6FGqhR6bjYQ'28 XGKKbL$MJq#qR+e9CGTQUpT`Nb3dp)9l53CN2i20'"m,R,l+SFA9SQHj`+-a5Li@ @*34,DcCTf@ZpU8#2KblNKYSCZ)hMpFZBC-F!DBI[a%MLie8)3Zar*59ck(pDQ&C cdC+h(044$i%hQZm1%klJ[ci@L#3m4JjVlcU&cRA40P[8&bA!Jjbh!6`+dkL'('` J#2c+S!lKY0"[V43H&[c$aGKY$&`Q9QLa2bq[d80%8cVNR+EQe,YGPfbB%'c#%aB Hh#RbdSPfZqi%U`2m8`+a#4i4pVd5rA3+IT2D9`D)Hmb#("+M&JdSaQ"&IX3F8`D ),(PG4[$pJFhfL`p'M6VH4mUJqfB@dEN-(P-jkaD8NR"k%5Xa@kZDUNr0''SViaR i@MCV[ApkcZh5"eV99Pl*fTf+Pfa,Nif+-'P+)hIa-f4e(CEA$Zd@8"dEjKCpH)- -Z*jr1Q(C4q4XUTqZ'9dpjF#)Z(RZBU'kRhKMMS@!Li6%rf$pEYp6D5@CaJ5[(h% (T6iJ'MaD@ki9TGYYENi9cm04*q'QdIKU+'40*%f"KGQDpT'1lG0fHS4YIh"0*Q@ )),QbZ`k3!%%h@[pY*MU$%XBYbjpPm-aR68+e-!!k-ZC%(Yap)hJPKeJ@mVF##1k M9eCSZbrGX4`eLi69Y+5iDZCmjp-&4&Gp"TM*+q11@bAJI!98Z6X@65F1j+M4ELV YH1T&aa[kZ%*A"fqFGDpTN!#0PRR5-5"#A&+E2-(8%kL$!*2DI,#S(aH%i$4RlL& %)%1`r"Ir&*K$lGm%LT!!i,[+dmD`0d([P0@4lZ$`kKlp$6[ki!1L,VBF`S3JS)9 1)N[L1iiY3(`*)2F0A!'EbGf!@IdV#HZr2V-0D'E&+9d8qdX+Xq%bC4L1iJ1rU5% TCrLYmmSpXipq&Ge#i`a@GcHp+D1P9SRf2k@$&(pKFrIJ(X(U4e"V#99hjaQCF-m r[a-3KBS3i6lUJEZ555eE2f6YjLMXkSG'cka3ArUa@0qP&a)3-H8SkLP@caCp%EU Dl"ND,8!'8Bd)UEFY9&R%(D[RdG"iI,L%&*K1ZPG9YUKjMGr5leDL`!ZHJ@Kq"3f FIM`,0e,Z(,XJkLeN4L-+YpdQS-1BK&l%Di8JPmR@lh,L8FQjla#[&$mcC$[Sh(M H!D%2cTGSj$e1cTGGmE!FD"@IpQ4*hfmh29$3NmJJe%b9pEdiBZf1-3cJc"rL$AM Zej3YN5[1[(`GSF1`FlQVre-T9Y`RN!#6-$IIGVK3Vjcdid(N0UEUa&U)6*6B*1j [$%4l`'r63q#d8BPU%#0lTY(L0bp'r6SZZq[Jraj#--FVEM*(R1EYN!"A-B(($f1 P)JXLiE,c+Y$M"IjMV@+8)1ZD6I6L6h,TG9mqX%'kHUhATC'T@,HNKe+A4SZAL9R 1KJeD+`@SZY4`3)$0RLiA0KT'rQ$fCRk0&3lXBC[jli2"6S+[,JS2FUKVYKUp2A( Fj2E-NVNYX9X!R#BB'GX%KeQadDrVZlC4aY%C19$!)`8bIX)0d%Km[)"bPZ+C9Q5 RZ@dKLbjXBq03LYq@Aq-(h!0e[RFiIIm!Ac'RmUU1(B8[Gecd%Ke2A-S,''L+*mB `(36K&Ch+ba*ThcCDB9RU8Scp[3`(Y@f3!&GBQ(Q$05D(TlKPlkplJJm6Y#a*b0T m*2mVJC4YT1G5KGZ9iH00(@ZArKd5C6BQM3+#R(-6m[p6V((,$QX'J-6`-5pFI3k AAJq%P3Q#"R)`E)%Af#CPY5+MBL)2)Sj'jXpJrZrJZqSe)`NMb1V3D`4r+Y3lfK4 SHDJirbI104N6-3eG"lqhR5UpFJ&S)F1JMU-d84R4cm1lUIKhmcmr4Q$*d0amPk$ q&J'Bl"36hDZAab&5$*VcKPHK2Q1+"35Nm&Qah(Ce9%H%UpHY-Z!DaA'U3$E")1' GLe$I)8q0"$d0"lS@pf,pjPGSfTCU--H"kbX,r9Je(BZk6jL4j8qBdffKZHP(pL0 FS%`cDceh8[,)eY-1[@B4,@00,9L%bqTJT-M,Tk*Nm08$9I2'DHfJ*qlP9a-i)8D $`U,2fE4P,9UN&qiR*GfM-aY*)Jj*CIYQhBXVeDPmamlbD8I)JDSS35mHFb,C#r+ (5!aPrR#[b*l1IR@KM&BG39Pf!%0ppe'X#q8d5hTRpaP1A9p[3,2$#M3D+D0l3Je CQM-#F0BU@$`FmG!5*6&SfK''2QU'T*E8B8m(med!R8GYF#MfD$+EaBU$2F&I5Sp B"hfqKT,B[RK,8)ZLRP$CCrSd#m0SMScMF0VjL[@F0[T%KqL2@`*YM[LP)[p@p(c %Tkj4a,ARbl1#I9lqBV,,0[bZ@2jp#6lPrb@i&HJjebBmR+[Rl9&MZ)mC4UYH)pl RlYH`@X%FeESG3Tce&kBb`PrF@#4lirV8)9!GVChU`VMkSUdYf9!Y#VpiH#Kl4T9 cAUKEEmJplmb!1,E4fr+r5#MF`#I+3+a9JdD)1*`di*L5U,S,[AU)BKMYi!2-l*Z R"EYDU@Y5#2#l9d4@JYFYM`mQdplq(edd3'3IkH&8P(9MU%eJ,H9d4%&-`b8(IC1 #(6EM+mb!*b3%pP5EZ&0mUSKZ-P2MjFbA,Y'DYMA@-RA2R1Q%GFIPS+9bS6F9TT@ FaASH43I)SiD`9X1$db!KCL,$&SfYM`RQV9YTZJQTjATLRdLpRK8TrQ#*lZ6fqXk ecGr6rhqeB2&CN4%eA9FiBi$A6MSFJfqLeJZD@*(5#,rPDhL5aN5D"JR"r`M[p-m 1h&Cq2*S-iNfNc`$+VX"BXEC'fBrP#R,XAdShkL)SFhakEi,J5E+B@[SQHYK6SC( K8@cqZE*aVee[f6X4!l$2(HXmGe%Qk$P&J$NaXI`-RMieT3SJ*DacHF@q&H-[LKH )2FTr#`SP&4VJ)cj-U1`0i+kCD5G'YLq03XL5pJl*j31Qq56)BYmLYAP3+2J%d%Z $[+)4$(CE6@TIc,@T&%%h18+E&8)Ie"&`9)MeAp5T#0BCDNKHd#"LJ@"Zic,YERX VQRR(S8m9PIkj"[#E0"LDJRG'KJZ!1&jLB$+E%FfQfJcQ'&jY2Q$!'6Y8PX%Vp#K V+RL6C"Ib"d`m1l5abc6aPQc"P)Ud3QcXhJTZ"Uj8bSS6(!(C#($+5ae`-8&YDF$ Ji$HTjb0edCrmVr&8$hS)kI`"0DrID9&0j"@V@d)X$NR,H8+#5qFbX161pe[k!ZV &HRpkJbc4G1X9B-h@P(98ZH%UeVASrMdBEE6hA'V,q'-&i!4h$mYNSN#AdQl"8-B XAP!lXrQ%qM4ZSaJI',KY1!SBb@NjG'lMJ'2Y*)400@DUq@+l&MHShN992bT,1rR 25L#b41if6PX#Z!BNX2c#rDpHK[!KIAYV$rpjH42@q%NC1U3NpGEI(rJ+Lp'i2&l MGG$-X(,K(09fei-mBZS#5qDDA8!a9Xh2I-!E6GCcS9'Ri*F6ER3PXL*X`Z9+N@N Q2iiI`"dd"00FhJAT#*6VTN8)5!D!C3RjQIF!P$qiZ)QHp'FEdeTDkKAff(3k9aS 9Y6AVLLVC*@$mr[1#()"pCAJeHe8bj$@F&dG[TKR(d9h-I)h[0%JcE!6&&rKLl#1 I1p&p3#f#Sc3l'E3`lVd1[jb$efm'!1rP,*c,2*p+098YYjAQ`NcYXMehC,if$e# E&Ra6CM#Hi-9-eb[h%[b8Shpq3%1HLB&NU![%QDPlPX4GViC4hlb*bl2QMaR@0b5 %iDjM)k,V'#A"pJYHk*J)2mqI5EJXcbmkDd@G,[KA6)cj3ZhGmI,QDmr0$L%@5Gq G6'TP9kEH3J4#9`Y%D$a)1IE[Bj13!%*(U9HYMYc9$8Ddh524EV-rS-)N["A`)cp dJq12#!AYB2d8,%8,92MVYUpeQE5D%DKN0+CNiT!!9Z%dGT(6HY4$R5q'00)"c!Q `2la!lEh'j`#5AK6Xr`1AJAPRZ,#VGCT&)C)A5J9AZZEE5Pf)8%KPr!GT,Dc5ZFD h,@F+'+kJ,B1J&T8b1c*MYLVQ0FYURBj#N!$6P#lSQ4(VE#-)qqZ-deh,cjP)E`& "6lIGMK"rqBj#JJd2'BM1iemX#NV5lhCkTX&S0d+rb8SFCmN(V0JI!XbAQ92&"J+ r4'N0X!ecG2mLj#4'S"jVSHJMRM6ZR'd#FSm[*&YE'5F02j5f1Klll$CC)p6-A9$ aL#Dk,'D*(A4LZF'%5kqpaM@2i'1!3VX#Nii$XB+EB+f*UPf@2Yc8Bpbj#NA(`dl kI'e-i'Dakdja'JfH"bZa4jbM#ii2IXb4Ib&H@Y**8`CL)l!h9RM['c8Pla8(#ZN QrZ$XL9hYmP$N[mSbU6$4IHQ6'19LPrLj!3,YYe!X`cibk*GS0D'cbYQMGi@eaI$ ApL-#ZXkeV5%eH6bFJQL+%`V!&S&mi#(Q@d5f48G8**H1KBI5d*M9`"@3!&B(&j( MqJ!e*Bd,bMeRM[GqSD2M*Ci5R9UD`(ZJN!#dV$Z5(N,D$Ei@%LakSS$iflLJZHi 9&r+U)1M)F%P[dbZMlU$Pr*V2NH(6eq4JL5CX8GCp3cbl*Ek8HkH'`U6U"#c[mf6 f3@BIcI`63kNNr6'iA62+9@P0SBGa0jm0Dh20X`XR#A#rp5-A[b`rhXEl9EB@Qrh aGpU%2#bfN!#0D%NM`GI!6(2LPQ5#f)0,XZb"FBS6EP@T@!lPX*6@dbpFFQNMbpB %$SSr1#ra@6l&fjb4U`94%Sr$##RBT8liaEM,+'iPCA5cfZqJ"P#T8VQ*H)Ueh4e 4kkN,hr)l+(,R6,T6D`F90dHCT"MjjKrP-NdJIcTC5,9cJUpS2@eP2!CjXAbGm4Q (0pM'TS%r8L08jDL@r)5VJ@bl#'+KXAA1eaKId*)Mfl(##&'p"q`[l9fk1+3VrHA bFSfT&H&fl,f99,H5Xrcf&Xjl5(8VTa4hj&))a[!Udlp$A'9D0DTe`lbZNb(TA-r d364@@LG0'JBKXl3[Rhqf'!9md-RHmBU84ffQEFM[0+"r12lNjj6ck1@NG8+5&f2 k6m,52hHcU#[I)fV81H8bl$UH3c#1SB5!1mAr#8I(Cd2"'**pX!3$6P+Z)+U!r@Q 4&TJ*B%P#9`1mje'Pc`Eihj0'Uk'iEq9`F4'AR4E[LpZ5`%VjhJl&*2JYTAM*FLj 6'Hbf5PJ5c39@C&j(K,9$C%UG0)M)$!NVE0AcFiN"-FGN-*STGj!!@cIrILp8dmm PZ+Ji3NL6k5`Jic`cii0P-'qjV%pL33"[FB)E%aAc*-b,!m'Dh,*4'PTB3'k#-'a E)!Gl$M89ZqY3YI,%,D&icFqRiYYUHCl[K$1M2J(Ap,,5ZH*`@re[4Lrak0#bPB) iq+!'pA+UM1Tp%q8&hBTD+*4Hjc9`)ZXAJ&MEN[,+if`HI(6`#DVff9q[i3TQB(' S,N"*Tfk8Bf(fa'eSB+LL(epe&D+l6ISC,&`r(N'm6bQ3!!aYd#RlNFpD18Z'49! k"f,&c'aq*Qe8m8hE@'RD%&1!mGH6l`J@BTK0Y"PkUKjFaE!-BKldGlP'XpcNkZI e)1-XNSA)Bb-rR2[4DFS[%5QhbJXYpHUX$45[@bmQEMkZBN(hP5LS-PHU-&Ql1PH (*c`0E)AU@R5YkK5ECiV*!P2a&IMTARDk56M(,"UrqThXGZdYl5r8eIRJGU`4HM( e,cB'RiM5(p1iXMfA@[2DLmm[5&cqLK'9j92%Yq+U)2J*)C!!K6idJh!kR)2lYqJ apc5Iqf$qIqCFb51M3IYcYa,%@@q[S-l1S-%PCf%lDlTQ(k,Sa"e%"VJYG03QFD' j-Z-*)Bf'k0pX@U2l$!ddAGba6LVb$K9M"k9S,9#5U`2YNTD!$91AV0q#&Cq-Y*S 4p,DQh(KMM6r-8(VM"jjKU$+Y3V"Z-a,+'q2[4@+%kY2eBK6CF1fTb4`+FT!![DQ jS*6)FPfj"&HhJFI+pd0&i1@-BDJZA5V@LMMhMm)Sj9QfMBl5%jPKBQ-$*0lCC9+ R1TG-eiPGCZk8k`TeU#BF2"5*KMKQ`8+*3F4f'mr$ddTq(UEcmr9mfX!#Ve3ei6a *FZ6ZU)j[%5GU3jEX3S%e*5)DVY2RM)GHKji8Mp@0[&0#Ze6XGrG-f#)qpNFZ0D` [-YeLl3"jdY`9UKi(J14B9IhPNAHE'9NjqC&e&[A-b2kKQ8*+p-&`3m1+#cX&"Ud D`rHYQ1AH@Y%T)T-hX*ZhQ)d9&aBCD!iZ$&J6#6%k(Hh53JUS20,','`A%)1`Fi@ T3a[P*@+@kdZ!-f&Zj[L-ZYTfPLG#TXh&QJ3m)9G1m#q,5CXRd!eGc`DbjK@VG4h r%m+V"eqiq*iecYH49#q@PE2fRBMB'$i'S4(e#%RU-$DLaBF[jF!S,3-Q%STqflb M9FCZX[RF)85-4j3Yb2&X`e[`,aD6b54jkPM80k2b383Xj)#ilQNLTea&9TE$"&Y efP5b3(r@N!"[@JRcaDSNRCNQc")8'0IEEdNRI!0M9I,'-`$hH9RCp(()"1PXXcr aRPlU!hKdlYC&Z4qQi[i6aQVpi'58)+e["X1Q*0,hlaQeF&0,FT,F&e*CkcM4e@$ hJe(&+$Q)TkeS32p"4%X`5&jhN[8iAK)'L5!VSNmh@(LEcM(NHFPbr,11&AUAh[e JD&XDTT(N[QC#a#m99m$k8ALCC4-'!L!+`GZ@LUfFmPfBYAX2i6Kc,[E2N5LCRSZ %86TR1Z&(hMGB(&J-RHN3jXq1'aC[hY4%46kf"YURq3IJp8p#QaL%ljcDc&j5Ik[ 5#MMHS5[UHUmG3cQY*i$Veip4(U4KUc%'U%r8#MLkUjL50@N2'[Pe4C@@Ulhf5J[ mBp[5NE*Bj(b!b5L"%m4+B&*0)kP"IIHU4(CfceaYSL&(FVFG&5#()98CI+-`#Jd V@eVmA1%CI%VF4'F330DG8pAUQFi409IN`!#I15G3PrQc3jDeT0XNUff!Fb0RAFX &"3bG!C+3!0&&25"#)CY`KRA1fq4,!$X#DCC#FJiK!icA@'N8MNe'Er'pPM2Sa5C hT@Za1SlD)qj$FAZM5Q2e%#02$h1QKDIMJ3@@VHX*'mFb@$k+h#[Gar1HGUJ+82j X3JMKG$ldH3P(MG`)QG1#RDFC`P9@BlUFDSi)-AjJ[P(lhHQJiTq*lQT,PLAFlX0 Ijd6'2++diK+(,&El@UDbFm%5Y%hePHQ(#lM5ld$X-9Qc,5U2MfTD8K[6bq`YP(S 6a!+GQ#AmrHjc%@bGPH"kI#(T!qfkBFa6EaeAEA48&dlLhrpMX$!")%)mIH(IX5( SK0*jQ'#S"I2JDhj'+[T2SccD$)E6&lYI9qiKLRUG4GQaq,1+`T4#r`fC(A1r4@! PpNL$B0Maa`3P5*34i`m,)GN8GCV9VlR0)K*"P1+)KbNS%"KEbYCrCH@cTACbXID pQ02MaBNN&3h+hkm(d,jYKBS-UaB8,G8lHce[#cCR2JhNVlDMCVr%f$%B[Z2lD)` $Y6k%JbI*Nh0`S*@hcSZ%PZUbY-bejP8MhM+P3Uj'$(MY[dECTAE3'rd1YA&@K2j @E-)F"!$mk(*a9CB,8`T"8lIdaTH#'H'Q&k--m5l#he8TKCL&XdKlSDrQbLI9ZZh `q"r+hkiP)[R(l65V(*6*V@UP%lKM1cjPD*&0mJLld6CeKY8ZPFe219eEEUjYB!f Z`[!"8"![RM!VmlNFeh(-8&Y*cm9mAj-[BK3Af9%+X(5@I$#b5DSQG)CmlX)@GbH jL6"$Prm"jmkAX$ABGHjQRZ9[6QNKPhb`q5mkeT4l`1TZ+%MC&S--JE&D9ZjZE`R k%XVFQD,5eIEMK)rXdlJJ"jTChqaC#k+#Uc@2AN3b`-`TlDd$ArdFQUJVDd2G9Yd mk'YFZjr$`UMVHL"DTi0e+1jF'8-,DcX1hA-'aSHBSTi28d)KUK'i8ec6ie6H+Q* YNJeQ3UK4rX!UY3[Q-$@G9ThGX`'`K8"4PL8-JlbjImTqUBA6Mp2AKY+pUd,MSr' AMi%p$f6QTD,pjL9aJ9q([,5c42((19A$9XfkCZ#"U[*'bfK&9[C2LC0+3Z,P-ek ,-9K4,Mc"kLQ"92d!Bb[KENX`Vc)GZTLJ#hY&3K9&Z13SEA-,a)U6$d5DC9R&XVQ Ti)&mkh1Im2S@[+p2li'XG%mEeXPVl*YcU&f4VSMGR)P8CbB&AMAj2Zf+Epq*6(b CdLm!IkU8DR-5-*pB"84EL[L*B!DTm4`rlbb4M-mfMrZ`656,pqR++MXi#riF(He brd-@J&3SNXl*me,c`$-i'hdE5TQPYc[#YV[T#2E"5NLD8Rd-%,qRiQpFrZK6VMX @iPBI!S&iDqr@HqlGM(`(i[,LUSYQ'Mj@&fNMh1U%'+6h4EI$d91Q6%,RGZHcKca Uj)%$CE0I[QPDL@mdQ6Rr"Dp1rhSXiQ!2!#D8[4c`NX8T3JL3!-XX["&K`[)V-KP FHeCD[SmkLfcHIc-5pN9&)qCjQh,$r5K!YShQcYm$,9B88GJd[dX#QB81klP"9*V SNJ+li$k+NiceA1Z8m4"S-+@NGAU81+!dAh#EJ8"Ub0(r9ElM+!C"U8+-h5T8a[5 *JU-i`RIEDCYJJ*MN$GBTIk+D-MZ,P8U'FT@2$+`ICmY&"bJ(h0LUU0GaKAfb&,m $i"L(4VL'FY&3jHc3R![2XBEKC3Nq1MpiPGRP1X2"YZZK%MSqJaH#-2R2&N8ZD+( j,UZ`GR-Tp0F,2"+XR'cm2UmJR(eli8"@(ZK#Rc0il'(d0(qh-I**hFIAPkI4bG5 2Z5MrF!H'lf8F2N)Qp,[4JaK(fJTDLMb&EZVmFD!CAPEMTJ`EH@fBL`$l@+`(+50 6kQ'QH+Yp1Y-ZZ+4l'0JIE2NJ2'2-I,TJr&I'dKfh"Ilh($1)9)bIQbfL!@rac+c Y83QI5!T+RX0SSPLUrAA`X6pX0!5QRq,l(aFSTaBT2f-N02U+A#HeM)mABE5(#Q1 h%h&01L0[%Q"Ke)-UDiGjBGlaZ$SU'r2NE,3qZ6mA5TVSP!8JkP6ZXI[$Z[YKfPR "%R8J!0,qNRfpLT5mH)H98HU%UZ"JmM0LmE(B)K$XN9PmJj`XEfdM1TSIbR04-@! QXihV(bXFQF`69)$d0KfY'5%VCGVBf3"1f0DUAb`[9-c+[@Z%cijrrKTBaUr0BbT &f"M5$f&S+(k@2TAT[iEXra1r9J@LEbhhdR0IEC`EEqH!1-fKeH9Ych+&`#dT!1a *SKj$N!#ZDN%cXVa18b283qKX&RU(GPKaf'(3&`)TS0R#[hDMap-QEGiC#"XjeJ0 ddFhh$#)[!FE4BI[9ehMR4P[pY"G(!NrA-K4k["8k$Q(X"1MES`c*ELh@5fIDDPN !fF`)$di)YU9LIQGMq@[fm%,p5#YG8%DrC$KIU*E558J(Zk8R1GL89Q!6T)E4`YD FT6chaj!!BD3)FfdH66)`efD)3$#@9YIdcXbGSC--Pl289DV'UY`q"j@XZ&D0(+8 2e&lZ(!qYj5FLeb*6FELC`"a+908rmUSJk+I89lkEaYbR8VqQSMVLL[K'Z34,2J3 D0I"-f8!lKBP'Cj9bCD(EP[-*HEl8"aJ-"J+!,rpHA'RaeMRa$9!,jV%Q$,`KJ)$ 2%iI'+$06q!Gq)rMRhJa-B$"-+r2F608kNI6R-pbjhj*meB"E@d!`B[AC4fY8RX4 #iaZU1UQY)jALCB0,#3T0ieDKVEN(lJ@Eeh"*&)@3!#SCZBE'`9Z6K83F2G0U[@` LC3BJCVe(LNFi&TlJ!0+U%k"6X9+Q-kI3e$G1fAPqVB(Ii0T@'k1""*!!JQjJ6@[ 5TpV*1L`dU!kpm-f,PN(bK5"U%YUIT1kSaPN1ZU(ALKYVdG+LTM`9`ef[MfRR($E mTY@6bMN`0!Za50Zbi-LpfZ[HS8phG5mMS(M1h-%[RLPK,RThhdFME$GF%JRTVC@ T`Xe*"+AXjI4iRRUKG6L5Ycl@(A*')@hkNf*58-B2lJ43dB[9rC!!X%*NBif[Ck# k,cJXPTAFk!QQpi)Eq8[jXK8@H[jqLLk*$TLkH%hj9r*-66Cp3J8ffNmB1'VF4D4 "ca0PRfD22,CH-bfKM0rEB2SC2a(*Uqh30j!!rA*d!Fj"1KhlklaR)"Lc'EilJA` q3J%Q$hmNE`4VFlar#ICXC,8[5$)SjEUj(`a)lX4#mqSaJpKAk8K-ZI"8(HG[MZ% pdH5kSfChG"XFRreF`5@&fa,'#GS'Ujb9JVM9q@"T3B,[(3b6*1rqKA9'XQTGELP 8)X-L!0P&Fk38@$!JrHTZZb$&CZSUD0i!PXFh80(QL4R+B-U,rh-FAhmDTpmpMcl pEQfj#X0V3mB3lDqMNkd+Z&Pk9A+-8jN)lb*EpjS)5Te*I-AF-Kp0KM(+f)mb4dX ap159eBZ0-PecVF65c@IBD25r024"`h223EIV(Dhb1cH$4-FlK[PKk-hp-N'VJAk QRS62Z89+d+0eh#I111#+K4+hC6K%QHQSLSE8K4#1TKJ#Zf-R(5c%iVjq&KpQ+%& b"V`[fmb3!'Lhj[C0ALPf"JrF[EbG%LiMUBE!c3)ld3FcAVUM$j`G2@24,#TJZXj NqjrAZ##qp+H[50CK9qJpAIPq*VBH8BQHQT%h[QML8a9Y&EUUdU36J@0emS'j$3T !LC!!LhK#ibfUkC,5C4MeL4Q2U8VGr+8!`2)AdqBDF4,mD"NR*R%9U99,V!-'J#f D0J[idQ$lLP1&)GRR9p'+UmiS2#Ke135BVpYQ)R@CZbh0PL1iVac!0mPmJF(`9a' 0#qkY0Zpr53'XlE,"FH(a`rTYT&`[8b3d#IM2cl!!1%'M"*F'Qh9&mjkpP+U8,p8 @!Z9'jNQflQcr6d[Z(8(VaqAG@hSa+l*M@6A'jRMD3L1Z#A+@Ka[J1B8aKMBD4I% GfX0ciACppIh6B82$qHE56l)4$U%2`+%eEm@#'K')Aj*E`eP&4b5PX0f&F"QX[MZ 8r3ELJ,"YZ#P560-EBE-USR9ARF-Q8E-RJPe+Er3fFpAeK3l8f6E8%Gk%VCL"ajl bT3LE2mZQcm3lrcA59i%2Jk%Xaf)U8LV8HMMprhSpiN!RmR2MQ2mm%cV6E!l*h)# *Q5N9ceLAa(Ek$Hm5,Bleq3AS[`*kc#P&raJDP`GiNMNC)9hkqr6a6f5fp`"",F" +8c)%RQDdmfMZ('K0lQ@DkhhQG"Xm@(p6UL"'le3faJNRX!F&lfT[-VGYS'*U-SR jG!JCLHBZ3HB,kA"#rMHaHQjG*H,Pb*m#$eqiE))j6(2A5'(*%aUQ"1AqE)+,IQE Z*SZV@KX%i0!f'KD5NDcZdHKCq1pPrJIl-#@VEYLIN!$SMp4e"#p,p4DY)('K8I! 6QK!khV'bFAYkE*3YpQie*%#![eB`r2mGf"GcrMRI$#2DD9Rj'1QpAmIEk5dr$dr *qIU3!!$D,,lV#kEZ%lPcTk-P-CGJZ5pP%ckeUa9A5Lf[Kc`MqVC8hZ(8XL$&N!" AkPd@9,E*FL[qFh*k%!Q-PU!2+c(fkMCDl&cdN!"@0&NU41)d"1la+FGJmG#"l2e p'5['!#d4#lIUb6jcYP"9m#p)HZd-q-@USE*4H#[B#)JQ09%VjUmX(q0PLdJN-M# 9mP8heC9j(M$LRhQKrPNLTdrR4M4aB%5Rl50eFhIlAFK4F$EaIQaBAX%mX#Jdr5I N*QDXS$GPdcbNDBd`2r@V,5HdeRhd(le%JHeXNBC2NkrMlhCJ)%JU34RYjE%j(P" #lSdD+`F#3L5[AJE*61JBHk**I0+b#ql9BiLS@+B%SeRMA$1aG,`!DCfTjk&58aX F@mIDJR%ShEH+Cd5[pqJT'JVHi2c2!-*YrKb$ap%l'LbETcQhDKPh2HeZX4B@DkQ KaB"qS$kJ*a,plhYjBK!Q,qpI3lH)YbKEY2hpMZ(*E!QUd[Y-je3Hqa"B@qXFpp@ r"Lm!P,'[h&10#1+T6VI[&3AlZj6KhKeBi`T[34X0#G!r,m9qre-L3+r4Vh$$QJk 0%@b)Zd@8***"H5`01iI8[*ELb8"8rbGeMT1+`aI*I(bS,CG@c'aX`clG3hRFMZK LC%hTk,KFq5Fqf%)Z2bX!Vp#M)L*f[RQR0p)ij&dEMr@`0U$e(bD,-35DZENhb[' G@4qGi&ZCTV[G@X9(*'k4(,XU%!h90iGNVhMN)T,Pk0fi2VGJQjTkEAE,8Qac2LI C*Cl(ec!4q&Z`d(R3`MGAUECiFFC*FT@"1NAAqhhm)1c%APf)X@Gll+q#lFYbFC% (IN,&*'iEGij[%f#*0'eY)bAeZL`2$fAD[3$CS1Qe$f-"ak23(31(jTQjTrF0A1X (,&CdGaZ44S0(pL#!0@5Mm$jVH'1hf-AmqP-LK+8i00@H$MHCPHK1%(HY65[4I8* %93mAmb10SrjldqQh)((lk)hd(Fdb@-*@)m"S)lcc`jb`U+&KPDcNI+I2L6Z9Y5! b)J%BQPa6V#(*[KV15#KJMm)IK%`H+IYCh2@`&G2Q,jc88kQq`k28rDHpJXp[SMq LZ)l&@`&0GbQ!39A*r4h%3i8S[J*rkU'XU%3KZ3M2G4dAecpD8E5V0mG"5#'9E'2 D9YUXME0Sk#d9e*QA-jiHEdLm3,J3XaN&cYHEScbqE!-6Q`kFcQ%bI4&NjrH'*S[ EPlX&*0#lejQ0Qh0"YB)(k`mPPamEph9iEcV&+i'eaqQ5`9DI5MfV1*FdRaJ1FlD (8Y(1Q9EX%f2f,0+3!"[%r"+1j2C2dc%'#H"N#h0GM'@IM5Y2Y6NllR*'1*!!iG* Y2*Gk-DAE5kLfiUTh`B1T-@9)S3*-NNaTqZ6ZH"3AedaK`2j1%FGdPRmpE$"mmNH +)*29E462Ai,I+Fi$m-QYNB+&5jIQ'id2Kc8*,Nb+#+Q-805h%S1p40K$XaC+NFR keb5J1LdNXQ+r25#&,'#(d`qY`@dN,$lQCSl4HHrhN!$lT6JdJ8$m4!$e1KRDR,d Fl-&dr5*V9q3LPPF*)93CQBL+BZVJeTMQmj-fbSBbRlr`F(68ip4A4T@)H'i66Nh QMKY0b`a0Cphe2[Pj6@4aJQPMT6SkR*!!l)+5M6&,ClXdFj(LSjP2Q5qHeBRBqI- (Mrd%PLU*'-C4@l`P,jHEqIAcJF3,AUp&+@me'rf[6fAQUR53!2S6Cqepa&dip9r 4*d*ZLZhk$1!BF6f98"&@5`j@jk26F[[TlB0*JHHBk*!!NK"8(EjA5ra0jlPckGQ !mI81Q($iN!!qhH,bM%#6VjGIY&Z3!'#baM1imI``X*HD%@#jP4L,dElG%eZ[Tfj Qj14R1e2LXeQcK5!4,E491FVbGJcM%m(SdpYLa&e8I0CYc`jcE+NEje+bZQEJU(! %[@A0JQIjL[i,%X#!Q,1)SfN3VeP,b"KcJ!)EjbZ#cS@Ck8Ec-J$cYih8DhE)Vi4 T49`2q!%T!rbcc!&dVXcp2$REEUa#2MGP1BYiJ3R%$A(r&`SJ8C6bEMSI!Hr6am8 h8!Eh%,Z6#*SJMQjI%NAf9NE@b%ffm0X-E@3G`@866a6#Ph'SATd#1r9@5RK'J-L 8l0r0#D!5`AC!Gq$S@1iGk2G%PfLT`S40"M0heC()i`piV8N[L#Uc#T8KLH"m`)l +&8m`@mj2LZ62erb+I(a+FFDfAB84"IP5m85F40%4reqZR(H0`LdB&#q4NKk#H(G @INVIVZp3Lq[ZpXjK-lLGZ*SF@fkDHMr&)Vc1H9EbMmR8XGJ,VfLH66!2r(T"HGE 6Zld41LPh1K`0rYABJ[*VhHPQ1)emk4BNF4PKBabXpL&9%$MBVl&-j$DaqliaLd( 0M"['GpaHmrB2V[`6jD`'+FmkDb[Apl'cKFKV'jXBbQS6FVDHXmb4'a+&ih2hJe" F)D"`hmYb")SQ#P,,Y6+kRk0!a&&hNk!2CImKkBd5jRBMaJJ-JIlrF9j(+UFk2D3 [kk*j92"`p4a`+Af0iS2@J0l[&qKFED"48Xcm,IB)`*8PHq5rrN0#CpbVf(A5mq" 2i$h12`q@*ihMj"daXj!!kR`*Y6fLZiKZh8EK#33KJ('P+!@MEJd!c$8Zm)aeBhd IN!#YYjIDZ5MH6+"Ipp-`@IV6VjUU!)PjiR`"`30Xd10cS)mRE)`98UDQShL[RY, H(i,K$VCNl!lR$58$BijQC"INd[L29R@BD'MD81k1,li5p`PI[e['[+$hDUa#&T* jIU2@RTfB+Jr+R``TJqMrDHVrAVkccKqTbVX,reA9BDL(*![ei(qjE4i,5QIkdke #2bDZ#`C2f)%XDhAFR,'jQI"M"+d#(CEHrY6m)TKqfD9!Xi)B&81@12cGT4GSG#P BJY3m2J4PN!#q*ZE['l+cHUIVP+#3!+M+p3k9TLJAp6))SDe00@h$iU-Vflad)U) A-""i*5EL9)@lQ&!04r69'ZaICj`54*%#2F9,kiJhe-[ceVfJa-KVp,Je#55X4U& afK49KN)@NF[l8Ik2!G*J2#A-V-hIj$80hMU(-9TdE20ZD8fII*LEJ!-FDqb"#ce N5#86[Pl*hlAXP'kXP+"#a9LJ$(LZmcBQ!'QjJCjj%KZ@hIUp*!P3pb1iYKa$jq- A"(EF&8e@C3QXF6h*'Q0[%3a[''kp5fFAVA4f)1F!+5A"Sh3H@c&lUZ@kP(haaU` A)k`fRXP8*RH!659lhFqJ`fh&YZkFl14eEPP[B8jkMq%GF),fILS63RF[46B3LNk Q6[!q%b[b"@F"6,CXAm&eacB-mrirmUSV$NLY,aerQ!UZ)kd,)Nibh$iC`IeqZ'A @DY'aFm+Ni[mXV@+Mr9@"$Mr2Dhp'JE80R,aN3CIb0[Uapkei,NZcK--+'GJN*S& 3i+q#Gflf85C83Afc!qq-%C!!@AQN-8@$P[+C32S3RqchZkbd,)!*5"TC@k[JYPN lE,B%5UXTqX35D'AN!VQ-i&Z8q6@e@EP1&5C#2$-9CkV"KXZ!IfIM4Nb"pZ"dF@A &TI"TTe8P$KR!ZV5BTj&*5XSbQT!!iY6Aa[JUdJaKQ6E@1D()AKH*`DFl`&hf&Kr 4U#j@eTVa`SBlk4[('e$1`k1!i(QLH&'D,p*8RR%iFQ5Q"mNp[Jlr4U%[8-(91mb H`-Yd*XaIeTlcm*(U1PV@+AU3!$j6BS1A0*UUXIcZC3Q&U#9-F41qV5I49qRLbXe CjhAE`ibXickFchFPIEXE%UGk!ZZ)kV$Y%H0D5mDc#85!1T1)'TqlUpY)l14YiaK I%hI0L&ATELX@5,1Y*TXafKc%')j$"3a%P6YGX@8,1r8PmM*APZkeBEP#R,6CQ9U J2UcPQ)YEff+GKpeieS166UeQ[1hIi!f"X2HC(+96Ya!`d-XNrJBabA1@`aiTHM2 SJ3*4E22L`hQ&E#krUAqd%JHa#*Ni5UQLY&3e84JjBMm)Q9dA&kb'hL)eJ@9'LBB D(3DZL(#a'5Y5+%Pjd3VE"4U#Fh%,[lRjH'a%R%Y"lpNB!39pabCf#A1%f$%qSUa jD#d`CGTc#Ec`"rK2&(LfB)I!mSI''e9'ZSBEe,9`0jkGVe521LlEC$,QMJj11S% )lTNj+h!p&kLEl"Z$'Sf0C4qC'AP5N!!U1PF+TD"c#rh+DRH1m@KlJ'&**SC!B-h MGEEIi%X5ed!GA#(N)0%")Sf5Pdf"QdL"((h+CX)Jc5HYaHPZpBE!BMV%f04hdC2 'F'&5)p$LqNNBT9RJcCR3M4H%P%V2$ki-9`cP%`hRNRZSS5TRh!b[c[6rH04DQH0 !!64lBIh[4P`8LM2"!TbB`aS&`4bB`km1C"!'9-A'p5ZE%GCh94`b9hm31bhqA$H UK!0lDG`j0imaM&H)J'S,`h&9Ne-DKVRq9*L$Gjk)*CJJip!rS"DC5eF+ZVlUcdN $G#Nd,62i$qL+B*kX1k@jT&[S"ZGDH1Ir4@BRkmdcMfpD6X56@Z4a`Zf,1-0NHYk B1%P8G'A-6"&JXAhA&2"bh#(4N69Fmb,XUX'Fr6li3H3BNH963bLiQq`i-L$RrIA m`-NA)bJ1kJMbGG@2UK#RbchYKX9D0ZEJ-Z&@X[!$-aYi9-25"*G%DTYX'eKm"MQ !ZV3S86e#,M3b%B$@INk9flKLc,!hHVIKYpQNY55KfP,Kk@*rNMEZijL"#p&,CqL U6C!!0RLQJcqPli)4GP"VR(40VQBDeM2PfPh8i'"&c5Xj))E8J!5L2$*q*hjEG6( c!(U9TlXIS0G1pGcjFmaj"-*rjiqQh-LN#$cqSc$#`'%YqJAM2f&I2P!""eEdD() dSMqQd&2demrk34+&bR63kjGQ*'TVZ8jUV#TdQa2@UL--Br*-%"SP#HhH)NpqHP) R6"Lk#BTIipKA0XAQAf[AT%c[ibTE9eDbq9kI4ERlp&-r&REarb@@`+Pp0MN6b#J #R[CI`[Z*h`(k1T6AkATZLTVJ6LV31%T+dkP[@HeRcSL'bBXXX[jZ#*ZMe@c`61, VB!r`4Q-1,EiC8h`-4*6bf-EiLPPceDZeeSRQNmlF0HYV#&2p96d[j,f,cm1TDIK dm4q(6d#-8SiF,&4K&)HkeH5"d[p#HAarV5!aZ+EE[j!!pV&(NHpf&G3'cqCmL63 l)YK+HjH8P-#4@PYM-C!!F$MJRiYkhVelR0j"G!L(PpH#R(3a2l-%I96*ibA3k'( `mGDLj!Gqp#K3f[%YPmJS(hFJ2TT)TTA`3L8h!2LBfi[bTf&M#Sfi"6TJ64bAcYh MKZke9mP*3!M#"m[2L)K@P8#`H)*a*%CY""IX0NEpY2bF$5blN!!pCmQL3KBplNB [5X'3!2$VPrJ!Cmh0dV)X[(cG1k)$%i3p0@"&MFXh$hHLXdm5Z-$*@Rr9AkCep"@ ["Dl)6LaTUP'i)&T*X2524&b$`e'%V@YmFZp'PqYT(31CSrG45Sq**p!NFNGkZ`* N0qh"rYF-PSiM055TNd*2R69e$KZ190-iL'1&BA3YVN+4YT@(6'M+V1RpGJKl)[P aP"2d(,PT[!JN4Y2q!p6mKk`#U4@Dq&lrCe$Jai3dl[pCQ1R(`bK,9-Q`,c!CXDp jDlZk&cPpFb@CE[SEEc3#,eFF,(1rMFLfbbDL$94i"4DZ9(Z`@)Y0CM[`YG`e%$H )8-Lk9+E-ZKkLQ(r%k)jXDrYbYKL'DP29Y4@bR1`dN5PU#[*bCkM[HfXrh$acD4, M`Uchf!K'qp9!'U&@0X#c2m2SYD*)*f1p34DAEbrlf)4HXcU%f0Z$@M6!eHEbUMS )+a+$-f32l`%k[Y!0IX$Yajr,D"(p,S[P+qYP*R)@3j%'HR6aZ0GcDX5#(,UJdTb ,8Sdb%1[k@Q5Vi)P**ib!%VA*DP[2Q*!!9X#%rGSD%$!)Qem*TFDJmE31FQ*[,1X N25K0Z16+lRB)"(U#+PNPD[eHANI'#le@5[X%U,@E)d8I#226dic3&1XaXLBEa)P IM(eeMm4k%)B3Q$6$9N2-&2NBf,c35U`"cmbcSB0%TPBF1S0)d,`mpr#*k8(369m r-$DNMpVbBbPi-TjAhZh-VpX5)DV0fYmLMf!0PfMAP[3F62H(E",m8N9Bfr`JU!j Mjl"d9k[Vm'BKFak[qQ!Nb@ZhJ0rK`I"j9AGIPZI#NEqNUT@e&-(jDX)h[2%f(9- dIMP5kc[5GN6#6M9feLH,GrPckkrQj3)%q9`!)!i6[j!!ATQ!kdql(2L9,kB4!S[ 3,6fKa22@&hra6FB%N!"*e$AqFNR&,pNh*)8lcIji&6FN#fpL4Dc#eLf,9aLN+%9 'F$bRF'CiSHV,mXlP6FN!*-6A)J"Z*0-dNMpJQPNUG!m)hF#c&Tk1[3ZX'P3Q1U' fRQMYSSfQCdJZd!+M(*Qh0qEe'ahUiUl%VX%MMhVl&9*S,SC5Y&[(BR6h5bPr*a% 9,Q%LEN9radZ,K5N#k$i6b+@CS@'dV&m,&19eQTE@"Z`r*c0XRNqd2Glj2FCQr[[ IA`Er#`0k$fQRkc+cXK@C#Sfd`))f8UIdqf&+L#QTrb[CA"aIDEe"bB9qR(&kZP+ HZ5A@p,@GSYZ2[8di@qi-+lE%a@blXU[@H@)p)Ff*fe$H"V*Jj%-H49`0YN[eE4& $`IhkphLeJZdXB+YF"Df'#!TiN!#,%S*Th5cRaNkLRR4E81G5EcBM#jc$)aIa%@Z 2H-r'(25[&[UK4F5L-6CTFjNPA'%e+hMi4lNYjN5#mTEU-(R2pj-)`UF3#3H1C9- Q&'YZJF`i-*ihjfiK"aTMY$Ud$h`2,L*YP"2R[VG#-!)SNQ*NhQbFGMiHK#JqYeK SMX[E3'FB&)I`NTZ)EmV!!5%IrQ'9II`XDMA&"UaR1TH2db1hK-#8q-m6bRA(+eJ `1TZ`f-)@jf%GUVj@8lQVNCI$G"!)KDAb#V*`SJ-*'m-$Ql&@pa2+YF&Y#5#[DNE a+"5$HG3+h'lVTC!!K3lhcQA`ir3JNm-Z2+aH6karKP5EjCj'qCL!IJI8*SJb[Ya &$cp9Ni"iIJ(KEKU1Qk`'!+AMiCmj0#E$e%5P*S9EqdXE-FhC&P)62dB*rGCP@hc Biah,`3c,EB2)*DbX2PBE%8Yd,2D*%@Fm)rke@DlN(dfMh@!bU*e0LNN#@3B5kNU [H%MS`#E[d-[2Kh3iYpCjD(91+H&6M@6*UH-NFJ5UUkAT3F&#A)P*pQ'PP8A"D[M 9l$IJl#VIqCk2iH$5LeQ([(!dJ'J[8V,@bAHe+YK+%lU"*Ed,HDVTA!j3NQ@p'5r 5J%C4hA`r%RTDLFYm'52+PKCbGNM!Vl&!L`V"c6%,dl3q!T12j5FGJ)2mXP9E1ej [9JSRG'!QcN`K,jh1U+eRUYq+mG60p[%2"L8YmNr[`qdL21AB$GNq@R+YHKQC"X& Xe+eACrpelZ&IQK-RC,cr(06ec3k%CP%[rGQIKBH&MDJ9"`emhM,+MG4SI6iKmI) RNZ5acj20%(M0'eC&"q-9'%@EFe'GYUI"0ihb(c&[)PPi`+@i1p"@2K8cHd6a&1J %Z$E*0hH,VX[+8)kkF!(N[4dC&,#mcj@"8l6PpBXbdFL&CY`+Z9K+J9)[Eb8IA!4 )DbaF+f6M*i4$)8QIj@"KbrhUjfZ4R9!"&06P$N,cG''AUQ*K$E3Z)V"@$TKf$-( $ECX#b3!c@BNB1DMe``RlZ0%6(FT#aZ6kYjIiG3Am1V[q'b1I`k22iG2[m1Y6q'h 12iG*(m1Xrh$VErKZ-20h'(AC-kQml#0rX8dDEE1fK1JfR0B[Nh-qjETT@KTpqp4 9VbkBD`$pGJ*rGRJYrKrb4+"E(p5)4c9[f[6k'3Tl3YC%qGEA(@#@e1396iFrr-j 9hrAfA0CTJ$rh6e++VGiQMp22MmB5RNRRAMIb4pJ&,"jTTc*3iRR014JLR3+kp42 RTFSD%Q+p'KP$)k#&LD[2m'dY0eh1cRp+qLM4Hd[M@L[e2Sb-9qYPNJXa9Am6a-A '8C4P%EKcMaj)1qm!dCqV6qY,jC+(ACXJ"'G8TCXc[p&52VI+M"E&ipJ"DUe9 em16(c-D8Y!maTDAe[hV-Hm9jkHPYGV(lFVd5GNlkXlf,fL84NGI%%IfhBkUdabM QM&c3Y*SLr`Fqdd"$MQ@lA&PDaXK-H@J$Jl8PIERm+ZZ6U@ZG#9Xaa[Z&0CS63m' A&ilPEQ2Pp+dmC(dI`m0AIFSi9Hq4kMbTeRj8#)j1R4dB%E+3!0HL#@f0`!AaS'0 MEEjCa0q3!"83p6"I+-k`,cRXb!3"6'qr`'pLL1Hr,91d'A'GLqmJiqI$4)V[K*V aMecZrHYif2&,9kU-U,G#je2*qCIUi%*hacM`'pl'-I`[Cp$dHD-fdU!![#["XE$ $cDRBEPPH,)D*2V,faP('c[LdSjrL1E2PUPH*eQ`kK)HVFQ#YXJEp@bkB8YTXc3k p+ep2M[i0AaG#93[QMAV9DLhi5XY6Z6X60V#bG(UZ#rHa9'pSIbc$FA@[ki"QKrD 61+5V3m@6QM%#YZ[,HcNr@YVFHmSRCPBBZh6AI2m9F0XJp!i[+5*C2-'23VIbd!D bD#i3*Nr(Yd3LBAS&TfJTJqhqT*L$6!qBEB5PcVk3!2[I3ib#ci4hL305CbZCjib j'53)IrBHfJ-lcm@2GqMifqN'3"rE1j(r8(-B,m9!imXNf+$)fb-,)rLrNX*453V 00@ArBCZ-[r)%1I,XMS-UY42@P&PHX)Q*cdNK-RaIS04-6IcF1b+c6DlKY+k'GB9 iFbf@eAQ+%9lj0qL&f!qYJ0R"bcfT`5FR`,a!LK6(P,5%eSbI&DfeXpaLp*ANcVJ b4K3XU`r1$'U+&hK4pp,$I4PH[2aCLQY6h9H+drEN!rUL66jVSYMa5maX#l-!p#b VqP!`lX!Kj,`-f!R24+mqQU$AU'ZP#'I6Q+(MhFYlTi*'31%&ZX!Y)kFmJ(H4jj` (9ZiT$JDf0PE@IJH)j(9T(EF(@1`@%[82GMFZam8-T$!IYP+T`Ai-XM9Yi-l!a)% mlCG*imM%DSeEdHRX9r&I&Jc#`3!UaEMD',Cr(9XMKSVL0*!!`Re'AD,h$)pM(Xc Lqi[A264GIDY,@YarM!h(-rLcNP4`15j$ldd`U"FDIpSrV5,8lD4$fC%JG%G%LmF B!KMJ'KP&3@$'GUHF441K[Z3K@bcSLdATi,THfEha4kQe2rmM#rTFRR)`Kq`rkFf 0Shkc',Y`kJYIA,XJ%$%L@Sl0*2N$Ha`@4d9hXk!hS5Pq5UEN,!h&hi0P9"Z'Eh@ VlA84G0eVZ"JKB*40p)6[%aVQkT!!,",SccN1FN&+'@A5YXAK'Elb%MfQ$()E4Xr Nm4H&60HPi&Md[GR!c@@)%C&)Jqj!5KJFGr*BZT@6Y*6U4M9EJc(U"G'C!CIAaHd 0M-$`5Eb$YKbD'6CUST!!Qh(TR13!Aae&(fc!"K*bAl`iZ)2@me&hqI['Z4bIXTU 1)+XF6CFE'lV+e0G9C4-2CLESd5#c!cST*9[b8+,B!N1*RAlGG*@SmVQ"Eh8`(8c 2('D$`pDC'c8!JJSd4da1f+PH-2CR$B-0+ih*H`9Z),Gi[e(@%UYXPBj)pBFjr14 'E8PUee#K,qF(8BGq+5Dkkl`Fq'K-H'd56!lV`B&F'8H3!2NRlpMVXi"h$("*1U" "VJX4RNTf6!eM')'DT!m#DaMB11+mreE9#ICQ&P0e*Xlk2A1#2+I`eHkATLKSh2k "p4H+8cKk-q#!bj85UE-`hC90PGf*r$brMI6b9p%C5eV9ffbME92Dk+@fpT&PV-P HYVXX"jI9jidTY+,BpBaB+HSjIIi6G`$22cN!X0pEhZ(mLq025"hNMVJ`EpS5pG' q2'pdHRjK#dH0@dQP4UTV&eTcfJVLr5K9NRjY$AfGpfl3UQGT3DaEFE59q0@jX#+ c[f,,X$iB(5r)&@`VqVlX'P[SLBr@!8CG,ak'"-Ke*4fkNBrU"5Ap'@P8cqQ%jHI h8Xdjj-[!!BXP&5[V%k3*9UG-9kkMlmpBi)h[H0bHZEL&"2A+kpdE`c"N-(TMSH$ +K--Bj[cL,emm)1NpIh2jfKfMLRYF1iY-#'P%T8Taph,ke"4,3NVbACIKqLSQqM) H$@lc3AG'cc3`Z,pf4K3G"e&003j5Ue%X02M6dKUmDCClP))ePd`IdUG#PT)Q**q V902I-rS3lGbh$0B2F@8fGILQHS[rIm11YC4lk0@Rlf2&&F(&ZC423Y$ZVYA1''N @jiU(ZV%KI0hRQ'AK%Zd#Ae5dPZ%#0)pcmKA%+3FP$dqXAI$Y+IKA(P59(,Njd$l "SBb@r"!dcKdH"YR4YQR$3Ql`85"eF32diCRC!m&3+J`VP8p88A'KP4T0hd!!`X4 %8K9Rf52ZMr[UY88IQ"Q6bheEG)+ACpR9$@"pBUh6ZA!04`iKQcVYQEjbX(1i3TN $LL#(0K3iD@3Q4Jqrm589![GebHKSLL#piIhR!TN5SXCReA$D"bQ`CaS"Q+RcBMj El5b5j"!$bLe5,DdNfbH8Gl(`ALMB'(mVSVae!bmLrPbcKirUDFA9HS"T1fG043* )6q62(aGb#kCaJ#U8J)(GLD$85eYd,TJ$1'rR36ZTJE28)[(f2+GYY9DGd+"D[lZ 4,"kf9XF020aHNq5a&,GB+rf5DbfCrL*a"E*,QLLjXbdqCYGX4ahA*kiZ32'(24X rIJc1NG!8P[#`JG`88Ch0mPr5QFMK5PLd,JX&be2k5q)0hKkqcHGrp(XC&&eZD#) +"IZQbd0Q)%VQ2AK8)`kIB*Q*JDbqY`0JDV"BPa89N!#Vmp942[KhXaA9YY*a$#f ,r%IPG(m43TLGJ-8hb[leRiDShb&ES+$TSCXZ(RCSSh5H(@pHrI!8MIZEUD"JNHT j#1hj&4!)f!i5+Ka(cX0TqGPFLqPJFJE-h9i,jfA5`1DdcN5$f#-ZJaj+rJahPrk VFjJ-`#T3iSH!jJVIZ"(UJ58TRriErZUd'I#jV[(%-QRFQeml,9`H3+4JRbLMD5b f+frZR,59@Mc$+9F)5#EB6lR*Am9F6lFe52Ah0bLG,R)#K+RiY$@Dqd0CVlQ&4C( [#BEe5F@P5`pqN!!lQ2@j`CTDMk#)dqHVb+T59!MQ0-Cklj!!*r0HJrHf'15)SeD JVp)#UI+KJ-K+!p3jqd4@ef3,KI@3!!UlRZh+%6'[$phUiI6&S-&*Z(*F%P![BG# 0Y&r(8AHd9C5efM!`UbF(ihTZGlL'dPpl&a-SUJ2YL-*[96qVYcVmQ,3""),NFXb f"ld@NI@!INp*XY(IF-jrcr$M8rUqcaXV5iVG3"ZM4AF+YaHF("D%-4f1Za`D4P# bCR9Lbp[2YrV#fD(dqY!Mdf'%FB0"el[Ue9fii&e)!3pT$hT8M@VkQHhNlf*6@+m 4V(J'VC4*V$ke2A2F8JK&@MKI$Mjm*%jBV-58H#h,XfPk9c81SAa$&'1cUl3XR#D UaHMq2$l,[fK+b8haqFG,8HF40p1)61d&*B1kh6301XJZIAc@0)0MiGlN6Ip@KpV YparJ6T2ZUV6q`-N4a$+X5V),RQ3C49D@5N6#L0eV1B26`8*d(5,kAh'Bj[hr%#c 2SB@JVS22QaV3Q8baMRP&6-1Md"Lf5D`QiCHYb(qmE+5HUDNq,38k"G8*@H$R!DN a%pf3!,4Ca)CdXUp%NG40iJ4ffe0ASdU$41&cBK%iBY[(+(36ES4E,,$,8Pm4G#P I$kQX[8FBk)AKQEJeZYpY#Ee%RUA#V2!iYe6+p8IJ6rUd$E""XPfk4,-'C#cjQI[ AfeYBF+4F8M2'rUV[)L!l593(`6qkSh2i9iS+9UbF[G[ZE(QSPQDl8me8aeTrKDJ A*%JRM[69E%K2U*PJbf#if0Jje992Xp+Qlq4DIUjiFN3+p3eZXA%FFe!AQU0*aG2 +UjbQQ[DTj[),&ZKE,3NYe#@rNdRV35J"@,G,q1MDbe8LLjr%,,9j`q3D+LV&q)P Nc9j#$rdU3DpaP"c-Ca@DpGE$MMPKRLa(-S8(9NFh8I1i#N8bj`L4+i`MPC@49G+ X[rlY8i6(-b*%HdXd`XYCV&CqX*%DD21r%epL(mG"#"mTjaJ@R6GaU%JX$0G*`0h F'#$@#Ym'VhFSY)p-A64Mm5HhKX35&[cF6K("HfVpR8K8@YG2T#HAN3ED9D*ja#Q ai83-2FbMk-+Xc!G%'6@e%LRa![SP00(J2K418UTmJTk(Ul!5d6[92aHNdA(%FdQ A9SAb&K,C*BJ,*3$+FVVX9D1c$kV4EjP5ckR2+(`FHl'aYP)ND+Cc5dhaiNjU9[Y LNVN)jLB3Ki80S9HVGUF+8GeAfFq"qVpjN!"IA(ZLNGQ)hLQfpMi(38ZSHf&2N@( 8bJ6+",Brdr%LYkTIHCAP!pGS80#b@URThrF!,F@68hU,6)dH&jrchDfL-%@82HZ ZYfIIpSY6qYbUmqZ6N4UdAp&("EZIYjI9Lf`P"cBX`1*h99,)qSq4Q&,#-#Fe3"9 %fN5)10%PUC&6h[V[Tl0%-p-XQMMK(0,Mc&*4%USCdTah#Y)2Uk2P9QHhLK28KHR r2Z5e318kl+iq!pY@6)3VXMRf0TIqLlSGL[Z*q'#cKBeJMVE1-%@LFL)(BM%DRb( `ZFX5hU9ZUqe,&S"8KkkK*`hc5Z!JQ1m'&EZNAU&R3QdNH$p0Q"QlYlBX$p"lhYF q80)UC$k"RY1(rh1&2`bH+k'`B04'lb3YklFEaV*$R2[Dc8Z2IKZN9d9!S3aJBaZ [TbX`R&bBE%U'"G2c%&XM5[elIq,qme&cIla$bamkc+445Y8G0hl(5K`Gk5h)TUI bFP9KF)!%#aC8k*%Er-KC"CC)G$f%HkN,D32VHe05$m#&f1-UG#e8FkeFbY9-5hi k#38@+FJGQRQql(45JJd42@E)90$&[#FM$qQ$%IUNLEfpc,eGhCIj6,H8eic"`Dk X9B9dLS`RAQij0`HbL"PVeq`&(QPL"e"h*H)E3kAdE,5!f-&YMk-AfY$C1*e46QG mSf@%*5)0BR"kZLD3!2!Sj3!`9lIKbh[1d+28IAA1J$8ec*6-L`"11US[MJl*)UE ,@B0VZ`0deFG1,JaE4HUdfYmlRY)8MJ*LVmG3e44N@k3NkN)@P8[0%dImm,9e9J% Y5)6C52FhRkV#a"N$k!I@1bj9,K#KCY*A6)0ec&AQDSeVU61(i8&"&MZ88IX$))Y %IiVppiG8rbC4e,%CX%H(J8F&X,hV*aF+pFFDpDCZ8mAA&D696MDr)cMU-8F6UdH G0hcPkA(VR[VL66VJHBFAX)"6914[eSYjXbH,`%4f2ImdV)b`rKhC$&65BS'i53r QRT)I#9P4lre5rhr$FbHQ&pZ&bUS"SM+96C50M%,2f92e995+M`Mii(#GKk9-968 -RYT#i63#*J'k4+H9U0)d8JPl$I@SA6J@RLVKQQLPk4GdmTp0e[Q*9CMfaF%XDLF 2pe$14H1BNa[%m6[i#Y,lLqE11&5T'6RC'N*-(*1!T0FNRHP-FXaNfRcBd"%#-bR !A"LhpicBaCaa#J3Fhl8S,Z@C9hIB4#EiN!#Nq21BjQH@mpe')i3NZK90Q&i)*G0 lDYq*Qc*"'VTY)JcRUC4p!bb3!*MUj%RMfb10HYK'Nd)Mbej'c$,HHYm'aTCQIre CkkmCCQIZaX[NH-*i*eC$2QBBV4pK0Ae9qVU(*Vj2lG6AG95TX*!!PMcDD0"Z(4J "j`3JZqdF!4SHH98,G0,r8*R#Q$`NQJM9S%NE4E0rIMjkr-VZ0)94VX4#CQjZ,j* Y8+aaLAUR!*I%cSIPqQjiRDZPiV9*%3B)NXN95Q!B0DVc9l5&F!"%""C@EAp1*hX #90)$XM4QKQP&K`H"8601e,#%k5he-Zi@$f(Lc0k2`pQ')CpEJbZm[IV,QF*L23S b9lkh9hmCUQC9UYIkraMAflPf1"*q#iAcFRJlL!l,E`ZBPk&hF[AYSdYXV&6M%hb %YGd,4jq,iIiq0L9N+""p$RffBFcC[04eXcq)-)hHK-rQhN-H&QXBlEPV2D39KSU YU#KVTfGJ00dSZ'3H3kBUST)cp!l,"KZ0PIRH#$MqUFphSCHq,F%JhHiG!FDirDK LXCGH'LUAFi42AB8MeX0)-CYm6r4S,ArG@3(!)d)q%QEXJUK,AbQ0E!J0hqlF%(k 55d#TiV@,IM%(A8#564#f@FU8"j!!f)NI91!PEeB85CD&'9r%G@%-6AcM@9ImB6[ ,&ZYH1+"3DQGEJkZINDSSYm6Z,UBbb'mfCS&hhB6&8F5'6rhl)PI3+Leqej6mbjK 4JQEY%ScC&9#[KkCd1B$81GR[Fb)ZPRUEX6JqN3'PbL4hflN5edkfTa)Vm6`2(8J ICC!!Z@QK69`ce'LRM*ARAB%S"'"rUYfq!3r*HRHCEqi"ibSm,)LYRq,+`+S1@mG 9A**Fc0RC*-C`%,!32!1$cc0apJ$+-XIVCH,-ZqXd#4SF`D"AXZ)XR##G3-8-6+c +VEpcRLUKQ2@TA[(j8l#UrR`$6D`-r"b6C[R,$3eA+[h9DqGA5H5k1PpMP0Pq2Mj lCi6-#Mp0HNlbc@Ek`6#bh"A"&2,"NS)0FlJ)F*q-6UGMP'!bqF-AA+@'4+MUV'5 D4CkN"HdY#U-5r95hH+!$mri$8p$i45B24S"826)e$qlVQ`55!A)3Ye9CSm%[`HD Z2AqMR#"%rMUbBiE8JRA3XAjCc,p$*LAZlbkd9Zi8L@1IiJ9f8**!Li5aaZE3&R, `L[a&58l)BL)Be,Q'k-(,4MbqR-$V5kN&$phDVkFL&S6J-KqGmflh@NULL3C$Ipi bp@MAEUB[IE*Tc*0!AiLRA[mc69NdT-,m8jNJMi`P[qL)McKH1B`8`LR*!k6N&ZR h"#k6cF5RHcUlT&$ek!)A(X"09Y`M`RB31``T[2e@bhS8'Pb',)D6`p%*59DAp4a @Z"qqYS[KL`[I#mP)DRGZr,[K!4)p(cHfp$YfN!#he!cc#Lmlp!5,4#dI'q3c)hY j#aEMEf1KfAPC5%3!pp%APN#Fri&iPQqV@ZQYIpJ%4BepNqJbF`VmHpSrJ!UEXJc LQ#B4FV@H%)5&[I@B'NAkb0,*fm@1ca['#PRkhT95*(HUrPbADI9YrFb+paD5ZVd 'YGqN2RDqZXp%l&m,8,IaQX#%(YE1IQ1CG[R%EEMiIN+4aUi+I(e+E)4P[)[4`D3 PL0&IQ+&,'9frr`TZS-ACLe5pPZ!+3e"CeqcpJj!!XH%bqBZ4`AGE-!L8(iiVR5R L@qZ)38"VAj+dk&KIjRRh5Va*RqlA0"GmQIR#rfNQfZl%R[6Y44I4459K6ap4,&0 TMFV0B$,M0%8lJ%m[i88McD%`92KM"ea0(q5Vk1f$LHPKpKqV(eCHl+KU#4R`[bL -6"41#86Hh$KbqiGF4,3@Lb2Vi,-38KpBJ)1jq[4JV'ei2fbLR[NpT'YBV+Ak6V* @E8,(615[RqX)CElC1JaMemZV%kiT5P1*4M#l10Ipbm2T9Xfa8E*Vh+e4DMPiIm' 3!1MV@Dm$ka,V,4e3&C%+qX$A1Jc2GK2NMb"QL4bS+,%8B$IF&C!!Fl%hG8A5a)X SCQeS"(lq*TRJeqlTZ&U-cLlJ+8lK!9"fVA5+JSqN4&CI&9VH892l&"`kD&-XaKS (CrQ6D[4j9,cJp$NXZI$p"lSIc2b1j)q%Gj-3hCmlSb8CM1INf(EGA`IU4Rp@+M8 +BKTh5mZ``5NP!0(EK9Udl0Vc(2%T,AYGfka$3EPBBZV4Fr+lf$*I-qKYbJ&1pT- `QX$JCL`[jc9aAREr8-qm5!1ULV9Bc#RHS`R&-Pl,D-$A-$*6&I8)[b6a,U9N*rU l59F@6#ENKV@ZU"X-GhQJY3l+!&0B6rAQq8HKXEQpNFBjk&4'8I)r6CqhKER3i9C Qb1$)bL%T"(jKhb6j!48`c)5LE#1G(jcc`3*[NC2FDY!T+FYH1LZ3!!'JBQj`%Gj SpYe"@%jL(%&I&UM1TfM*A"MiAdkk[)ZC!pTP-N'K'[#3!&KY4K,,YQA0X416Q45 +1U83%"J6A9CAVT`d*"#@b+I4$Rri8BB,('4cZG4e4cPbIC02-4YlY9(qjfJ@BRb ZU60GcBpF!`4fHp'(SLa+pMk605I!Uj0,YPN!,M'Le3C%aqbJ+PJ2faX6+abkpfc 25"!BSE"S[i'[XSEQZl`XZX,c"D"GHJNTKi`KqqdN@Jb)6VIf!EY--HBRmp"+Jij +((f-T"2FmT+CkQbA*dT5Nd5@rJm,@l('ddBhj+-SpG[q(8qYYe5Pq!md&TE@Q!q CDIe#Z&4'`e(q0B2jBK'jEp!GBmZVZ6KT[AF!"J9K2SH8jF`!JELXId)Fr5hLLiD !X(fRFVQd+GKC2RAY5&c-!-`8fJ,Br9)H#D@l@PdZ21S[2EQ*#jSm(-MheiTC0'[ 5KR$acQE,bfcR1Ea3"S,4jC0VXk1+)JES[JqR1`C4!(AXT9bFTJ*h"G(mHS2e#f% Q&+%jCAB&#"r3,f)PcJhIGMSPh4mIG[&K'X(pDNGeMHK6r)ePN3@9aYJrRGhVZ1` 9Qj3`"D(!`m,T-MjcP(BeK[q$Q2*BMh3!m1#SV+i1(aR)RRZNa6G9Im%i#b1fe)N rbIV1-,fTH@fE$Q39BG-PPKa0reEjq`jS@-f$C4)#PBZ1e1Z$UJNNHrM[MfHRLeK +*m,K%#T@m!(0K5KT4l&jdTTHmr)!8N05aYCQ[Q9il@I2Q!CjVpB-DZ8,9AXVFcA 6TTY1HMR8U2l0Ae2E9AZ6CiEVD63Ym,'F#hAIh3`9llM4M-#YV'lQNj!!0S`YS0% $pX&#IKXh*Jh$HJId@d+QFT-PE)-fPM`9A1X)08EfUM&*!*R!!k0NTU'd%KRe&*m KGfMhC6SYbMd1))@9R`l$"9JTiI1c&9lY@PAAU'NcrC&)iAAjlF8@0Y11hMJ+kKA llVc`Cr&$AIaLPhG)p&Pd`bjH0H)*C6q*X5pRXa%#F3q3!,SYGXc,'1Vhl`9T`8U hl4Z(DXDr$HS-[M4T4%(PYTJ*lr-ap*1YcTb"P2B@cHcA3`C)hb`lQ*G%XB[CX`F )Pf*hL,6)l6!Ib"50qI53!-N4rN*!ZP*l5I!ICr$*#iH-5T!!%#4c11KEb$+Q`Up $qG)GAUA6qkV%"A(3[8Z*Q[k#3%a3Nc%KG`GU8@9APC'[LLkp)VJ9R'1qYHpTmc& MC"j8Y6!C)(S$6lkhb-km#%`!$Aj0fJ[5#CZBL"'E19D-(R'Z%VE#b0Z3!&jlFUY @(bKUN!")-F"EA&+Nhfap5b@'K#(aNH&+22NH5-2NqVV*rKh0AfpXAm1L(,lHdEq (FIpKh"r`k0FI`l)[iGirm1hlq(5!mqfql()!b3`[f,1LNALGS%Td,+D9rh!'RhI 5l2"@jHHS8Je$ZkRF+AN'92Qd4D-3UKE'VCh5cERfMep!3#G"N!$)XD6Sk%ESV4R RH&&aU#CcMF!5Z#jSF-#e$NM-A3Gq35,62bCp1LCb#V*p3C%E3*M+DqRk!QF2rfR U`cj#(Pm-PLUSMq6SI)0B`ZNaHj8pm*2QdGIN5HGbEa-)fJ-E6khAImf'#Rkq3pZ RCb*ja'1qTq!@18H8X4&*3G%5FhlPGjf[LaC#GD6U28)UTi2%92B@Kf1RXJZ0"h$ dUX@1b-0+3&M8,JTk3j8cUp`-TY6&6jmHR6i3X%ZU`PZMh0aUe(NHa9,@19&eAaK 8NF*U[@Mlc)ahIAL)qZ[q+,!3-k)kq(3!1HdipD152$BSDYN)2&[iY9,CYQ3X"j* EN9d`5EmbpJ&ZFi&a9R")`ZC19qjp4H$!N!#@Ej!!2DqD"1*jJpmp+$E+#bM(#f` mi8JS@J3b1SR&3fR14,-6MkGq!ZVlM['r`91&SU(le`,pU0QbT2@lSJT,$)H9F-` ,l2NT-*@d-+hPELL#6KXNlD5C`R-Yd3EqD%TJS'SH'G-2!JEX119UfBHN-C()"f) mJ`BB#YhSDd,EcC5a%[A5qTKH5G4T35icYLTh'UA8e&"(I&UTJrUI#LZB8+N($1# ST!P9l`*Z*jpRSShRXd2mKC+@dpl9#h[[ahh`6%HUc[HmK2P-TS0-6D23Uq4p*&k Rl)$-!TepY4@-bGXVE"U0fqV!UhB2f$qNIX,!2-Y`6FPp8UN+q14B#S%$93Jcrd# 51a$C'FH6d2Bf,9DX#-,06jNkR`F*jLDP0[NAI#+%,QC8Pij,X%C!L,9UhYd@NFm hqcd#9+cC-Jd[3#c4UCEIB(8MSADYq)CTG*8eXM`K@RZX1bb%VS4iEK0[S(qUk"H $10GfKIPK"!Y6"rYa#+iK4D2L1FcpF)!9Nef3!$h*bE%3Ek89aN@f`rUNJ,$8I,V DCQUJaB-I$8aQRS+YeQ@LSANKdGP`YNFkm-B`d&T&l-V0Ch1Q,XcI3A'Xc$3%Z+` X&683+DQ@%p!ZP4S-Z-P4NeB+b"X!6a5RBi++dLY3UaEGP$h1,l0Gm(5"k4fK9L3 GUL4dQ@fif-0RIem$R1f(qSjIVZdPj[JA[r2C5a$khIPJj6DU8N@UR34&HMe`-T8 VH)EGlK"1QHI$q1#3!(N-Zm'LB%q41UH2PkE4Shai[jXC(I4)Fdf(2+%T&STf!a0 cH&[H[9#%e#aT,eILpCI9mBTK!P,CMN*h[K1%PSp#&SL!)9BE+-Mlc5"C+!aKQBf QDb+Q#hK#TV2m(-md+aM1SCM*@4`+*kP30H2X0Rf)A&Y,S*q6b@HGjU5Nf$',a5d 1EP)TRcHk%'ZKU$4i(HV*m)i'BF#6&P(2*%c,m,Y'kZVamlJB-!m(F9R-pkU%ErY G"Q*k(8Fe@@JL#2J-REp(S4peRe08cVS+1*[mpYRQ+d4S*bGrR-(cE!qILm2M(`+ RB8&eZX2@@NSh4)UK!e3C!CQ*3fN[*+#+@Rb0dlb25mkHB-2LXhf,U+K*'r[AiUl d&6Rr0k%dK(h3K@%L+Mh,AS[&h&BA'N`)2P$[$R0c8QZd'I*XSVe0l1!i@Zf,rH" Z+(DqleHN!R&h6VkG60Y(dS4bhUrd!Xe!pCf&lQJd@eU6NHVGk!Q88@*jQ+@(&A% 8++aMKG&Lpjj!`P"b)kPpB9eS[dZjHA5cXH&+`Iap(b`i[C(&C`9qRFKG@F%Z'-C 21#[c1hLrY@c*p8`j9@AAdrS6%2X[62629E)m1hhHRP!6G-d0b05kq()-lCIqbAh ET0i2+RAFTF!if2jE%AcT(a6P,rB'5,rd+LMI&`+S3X"C*lA6rYZ8k6XrTJUHpMZ f$V`E2k`IkX[4*`S2[I`IcbhfFpJ6ZEG&Ri'j0`6U!i[Aq&4Y1SD""*2CL%pJ&** E2TcbI0C)qGBbHKUlJJ`+Cch(241Aai41J2mAF10&2AmShMQE3GPrdbRXeB&XXi! %I+C6G$1JJk,AZ@bAfY"J(4CQLTY#k6!!rd2)(NXl(IU4MY!T9aZ%-+F19rh#V'1 0h-"(NYmVCHRF9Gdq,Baf3X'Q6jiNlACJP9F)$T31ri$a5e-@fYZh3%J%#R&`@+m mYMEPh%"f0&6U%*N5SbH1qhf!-CKkAdaVS`8PrhmXL&pYScRf*E(lKT8K,jrH*pb ISePjAR#cU'qR3kBdB2I!'JV"3,P@),3qUEMQRppN0$UN!Y%H!YSTJj1h#Zi!rfY 2h-D)a`GhikmFMTc6#RP#IBa8b-1AGjFD,9cl@fYqY0pPXrL[X1&0)19eGUYK[qf -pJBeZLZla5)T[TK&-13bKM(+TJbpYr$&eRahCHLN@%U5mAJ-(XB[JC&Tab3AB@- ED""(3,%ZCMaB%e&L3V%(Dd4R@%Zp*!XE[1HDK%[GFP1S'4em,&XkjY[fh31'fVj e+E!RGFcfL3m"YabB0Vmd6+c26VK2QfH$bT!!pG'd0M0K2VACJK#%*bULm5lN6&& jfADj)jq[,H*UVdY@+F6f3GZiE+6Id3BT61*A$p3M)qGPfH@a-fIlq3U2Cq,)qfl X[fpQ*Sb-6GYE@,VQq!pq$I1m+G5q"VS[jYGC+S@5@aLVQARQPS&3f,F8BSA&I2L $8+0lJGM1F-mL58G[Dp`IRhYfddBGDm)"`&12aa&kURlMf6iQ$0H552aiRc8ppJ& Hr&rI9q*&Y63j)k2cq0M,3eXG'#j5Lr`9jcNFdS!K4k@ja4+cf092I-3h2*HXdj[ DHX1BIlR,Ul!`-lJcpmR''6Lclj@mHc(KMM28DkHHS+if8YJ*-cb%A1[('0p,D19 -0%kVM&5!Q()NC0b#&p!A61Jq[bCIDCcH@MpDpj+fBX!H,QE"J5A4SKXB@d,AkUc @cRNhp$'SZr[2bJDM"#6XqrRLEEDjLSVh(''QDdZk@IlUcYpiY#lEFJP2qhc`C4K VRDLClUK8fe`PC0'@3EadYYER6@rld[*1UKaAp%5SCPV5*b,lZ-0ckXSdpDkUi,U )QPr`!"j4ra1P)E2!e5%f4r0(1cI,"&rrIemMS$,P1IR'UGBiVeXf#Vi!,859QT6 6Ed#6',i[N`pJPff+`I*N6*V*&E3,D5Td!c`IT*-KmFHR!P!21(PINR,hiV"S2rZ DE4(@fqTCXQmG!F!+!D"f6`DjAMBXR6Mk!c*dbVrMN!#r-ZU(plbQD+1p'&EHF!2 &UdQ8'HNMb`V`6G)J64rcLrm`D+Prk*6B%L@I`B'Fj!'VA*`3@a*2V9%c$kP*hh' CiVVVrbIN`)IA%Yf)LqdDdTAVMk*0f+e'6B-)0&I%(`-r`ikeP([SeDI[6QU#T'k 2jc,lY#eQA`h[HdCC*5j)r`E2NHq9MF#Hj3%Zppm&40(0CR`RDF5b@I6XN!$@XbY G0[f6eIJREeNXbMQlNVpd+2Ye1DT+ZHGZ4XMRkm0FGYX66%i"VMQNCkh(#b@bh$N R(ZIf+Y@Fr,edL#T8P@f,5'RT1U-j30d4LbpEV,ZQpDN(XkMKpP@NbmBflAS,+Ia QQJCHqI'&jaa(qkVUSFB#@iV2ZPAG@*N6F+!LcG8#)PrAMQK%q'6!X)VlhCil(E0 6#3-C3$S"lSfd@+ZejqY+F'[kMCA68d%@66A-qKrT+qD9Z5Hd#`1BA-Xjib9I(l8 Z6TaI45dbX6U%3m+NUj'0RCiq-hi'CXIflMh`[r%A%kF)@1l!9CC@'TS&QqUl-m2 [N!#2Mb("Km5a!9)ZdJN@F#faVe`(&dmdH!Z"lN1jZ&Vl`rZpR#@qDRZ56lj0[,r IGLB'Y9q198pD'DGT6(,$iA2*&5K$XBMrJ-mVe++Sb@5`FG$8F%5VFlmL1X+UcXY JQYjLD%)GGRSbaNb)1"HCmpFh-K5FN!$)6VlV)@*IC-rlC[0BphE,39L(J%U"YPI dm-6[E1I4eYRT!fep$3b`ca(p9QBikDTE1,4-DYT3%Y4+i""b0pmeXdU3!,VIFj[ VYU),"H#bV)*dEF1KSa0%qf0KY-p%HFD5X8'"UU8*RQi5*U#!8(h)Q4kl+HL'6j& #88YLQIprmfHU6QcM`rCRIeG'PVTV%jUVChFc2kq"ZQ(&LhbEM2j#9`kkc'*2mD5 "1i'Q+T84qNqaBZZ2b1`1FTiL,(cj1Ur-Tqekh6Iq%iNNM#-j@"QXJjd+e2IT[`' "1(!3EplF0632`d[NVCiPMTVABTQGcBSX5@Ph*"jL2,`F)[$%kG29GZMZAdJLqj! ![J#k9G*0FlGYV8-m*Z!kRRRIB"c4FqkLTA"&0q!!jUFh"iMS!J'4963qRJNS0i@ dTSAlLk0-5a@8fB&#B`ZBm49e("CA3mSJUViH"8c`MpX-YS6fi-)TKQ#Ja5chC%# IPfjk&*4A944KcH"&M[9#r1i%@NL)5)HcCA3*mbS+A!-%9bEK(*8dSY1jjBad*4+ *EriQCepLfUMe(aDTd9K"eBk$RaIhrQT,aUBU24)DR!c4crKBm,'Xe[#iI0'0!*! !C(%jQS35*'"mH6[lGhjS,#iI@8AI4ZK5k#34r!,NrDE4GfLef4bPT4iNZ%,b+EE E"(Mqll$pP!%(`E`bD,CZc`kG36J4XP9ikLQeSBp5*6!jL28RdJm8[e394qXr&1h FN!$"D#8SD#a@*Fq$"#kGM3&iPcF'aQ1-5B+r1qZ6j[[+p-3SNA#i&5ZA!dDP%(h 9fh-j88JLU+-0R,4i#YTL*fQRU6iaR%a9bC*DRI%41UY0cA3P9m["RBY1$dT#HK6 R%c(bR!me*iBZ0*lJ"4h%r-QJ)+KPjAX8-GGBiPkF(p"ALR*QCBLEUqX"kbE9NkT ,cIq!3ka#r"9p)IY*PBINBB$$R,53!((aQ![VUkAd&aUqE@I48F6+4[V[PPHhddC 5XS2j4-VUIU2YV*L&r'l,*%aRS)G'39Z9QbSNk5+(N!!C*3SNR%%'U,XL1X9r`jD k2@lQ4@,!R"d**6A0ZN$5rfH9M4FiB)bJYU[kX6k8i3CCNjb'IDC!k(1@fQY-QZS 'Ml(A--h-QMH#hCDGcJppQKpL$@HUf,d5Hc-T3LpIV!(H,EIHLpDXpRQ2"-Y!CUk lm(Z`8c@qPp@MAN+NLmqpD)*[5[HDMaj+kST9Mid6SLi"JirjAN2TkeleG9(ebfJ k,JUElGHdl,2PlKki&kT8X5EQI&PKB*l#H5q'Y-5((r'hq#Cff5$$l64Xh2pih(X qlfQYJ#`!i)5(l+C,GA0@5-1K8-qqJ#VALH%`(4d+,58Je-hT`F`TQ)5D3VYT3+S %[JF"V(9EKj'0jhim!DQ+hU(+IQrKDZXcBQ#cdXqYH-,!ch@hh"9651N8P$c1qTc "XM-)2C4cFMI*jfIj+kMB@+lE0hPNpXPcZ#F,k+k,B%j[##d,4G*p3NqU)jC6Z&H 5#dE#!A0JQY2$4D(D`"cUC83pMG)KFRR9e4c6P!+Y)+j)6[cSHf'eKbF6Y(,5Jb+ d(5lNR%'[9HpqpbI5,*jd+TZ#[ia@%ArCkrddQX9deXRFVpGIhqmPeCBk5CU)B*' )Te$%q1h1l10T!dRZL#4AqjZiq,X#,lR,6-SL5Crr'@k"%3+mNqNHA-TF#%4c4h! f[aSR@0)ES0rMbAb`T[YX6&k-6@5['6Y4N!"PYFqKRXk2J[,H*4Ddrhhc,JAc%a% 3rblYUYGV6Y'phA,TBeQMR(a5XBKfblpKY-LXhHCddH*ScJk'jX*SM%TXV`(92p$ CP)BNmd&iM'9U-ZXI%%!D2B%KF0&SpFBa&H2e[m)RiEH"SVZLHG#[bJD@A9KFihb #E-3++!a+DC[,"&[Hf4[Z4Y6ib654J#B,6b'0immPDD`3dNE4BVrGp,2J4qTd6C! !Xq,EGhU-rR`0Z9&qVh%ip1Rp4031KNVAjbYRLFhG@2&Q-NQkG!*!r33`GIX#9cI Z@Z4dj0iZD+L6i`QbRRE)AT!!dejQV*R2N!"l0hCGXq(P1*fYbGC9iP2a4[k+m%L e(JbYSe@ECRk4E%0,9&qm9E')Z8TXbSiRX[%q*#h%LJ8e545jRQ+BiS-H+Drq0'L ,#QF+*L6hF,j4Xc8j8%XI`RaAb"rhYCM4MfKM5Q,'T@,aZCZ6-m8l&`[(rc-C)!) G*rZ[AhfrZ0J"H5,bMA*b1&e(HJQ`MJ[,R)rlLTYqieRNA5#f#ANJJX%*@*dV)UY 3SlbHNJX`,KP[dp(9b%HJ1FB+!R2lFad0iMAr&TX@%lqXMXTK4iF[jPh$1N80Rj! !-Q'#q4pJjpb@(q0emlGQ#rmr2hG2jX"-'hkE[HRl0RBp$UM!mjZjR2Q2q`8p*iE -eqA5$9qkD'B`p#pB[R%4iCpfBH#qbfjbd5#JV81Ljrlp!T!!m1Q$PEiQe1)!QL3 ""GRd0ampmJKb2pMA4ffIc4G0NNYikLDjQ6QPkD&SH"JL0Nr@iHrBa6"D(QEBVQ( N3I$pQC,3aQHQZe5V!L1#VaBVQA8mCUrq1-V!@3-0$im&QYDS*AZ+V(cK-kSFVb% )#%`aqjTJ&4%c!A@qr+pM",ZmH3J)kdaG9''-VjeUEYafS0fAQZ0d"R+RV(l-d[- h1+3RcqZ0`CAiE!Gr-2E36KX3IY2pRV-QFC*'lHAmSC,!%[P6T(3U2"6G6!+0Nl2 pNQ-4+XE@mSVIUZfE'+lRZX-r3K%JA01mm!m&%2'+T9fV%A8KHjcI1iVLVkJPk1% V98#&FFFNQ$&T9#(H&22peRY8XYrMM&"C`451#X!+2r9M4CB-hESLl4Fel)#2AGe IrZRbKk)L*@cb(JBDkaJaXC,l3%jLPFYD1r[dpD$,6%69+8*m%``NJId1JmrGPd[ cb#-e0#`P8`cE4,`a3B9&9qe5@#PjAX[M'l[kh,bb9-V8,aBe3UYH@MiS'Y+04Y* 'i$rJ8&)KeQ)MC1M1GGDXe,-c)Y`1VpGp8&a*-U"mfKlP6-ESXY%T6p1NaXE1-+6 $0U(DdN@%DpR4'QmINpFhcQRLr)5AaRc%GAY!,#IeVTU*EQY6kpNYfN!DKMf3!2a ,Q4V-6qhPT0#G%[Rr)0CLXbKRfT4'1B$ll5$E*"5d@(LkN!#3!%N0ch%BV3)R-(S CT(qQc#eqT5`CYH+CT0&`pKp0M*SVA9i!ipNk`%CNJ`H(Ii5Y,5*aaDSBFI2GabM `ep@-h[F0b6U1FGpqLX+[8+lid85FDDTa0+SU253-3fjS8aUQ0IID!a-Uj"fLGp, ARI+c"&8EI*rUDPp0p39cB8*F-rCdk!!TTk56q,B@kUbAk0&20P9UZA9p9[b&rL% Ck2!EfXI0&F@$#rl#aVLk,U1GcQ-H%h0"fBGdbiH#!e*a4hA`*RSJ![08!b,U(8) #JipG*AF(@TG+pQFpH-5UR44rqSF818c#-dX8#Y!Mp"GT$`S!Hf+krFkqM1!+%ic P+60cBf3EB+I+$+3''HBP%GThHXR0(NkT[+rcRrX+hfdFi0Zfd*hl&"!9-C0FqBR %+cY&-lk'UJK@GVkakP9#K@H`EY(jC9Y4CV@kdk!C2NL(plA4!blZ"L`M5dq&UD# *H4MXJBL#X#NM&dPB@T62'b"C#k0-!#"4mkkVPIA1kC!!UX(BFZ3am!l@)IXJri@ H4(fPX*%`L,JbFLi,#ZqiR4(!k0C2`0!!GHjhj+hJk-cfUq($dJMA"RFJdf&`D%1 MiI2Pk-MFF(%J03lC"[@lMb8Rq%-VRXbHLa!6%ff"9!PGHLP%*Q`UiA!1HTfq[MP 8JF53!-M!U5PAUE2-cbTL[QV#TR+5j'01hhFN@qUfPGm-`hChAdEa(QS*cpHlC"6 5[&*MDjdFLhKcYD4fCK%JJ@q!V"CTd1E!V4AJTGl+DZUrI[EHdX%b@L!ae&MQB39 j&G40aP@(pF6(cLjjeG!f8Q1549e26(1r8(8pp5miV$"4d"bBD(Z1S$bc-`U!RaX 9K0*9U+q@6H3irh%m"E$D"e#eYj14#56Pf+Q$N!$UJ89&0Zf)iM[V2$c2(&-IJPA i(8lq+(C"2qecU4,,NSVBb2,&(i9$#HNqY5+8iDe1,dk$rHl2d##INfaeCJD5Mqb jm%26Ej3BH#%#D+5r"l5*)bP5Shmi"S,TC&ZLGb)3Tm*F8!XJKdSam[2)Y3e@[Mf cA"Z,Mdc'rcd*(Ih@Gfl6*Kje`$VGbcJReI'K@YNT#[(b9PNkX%TN14U`pM*F2*K LI4JDPN0haqFf-Ic@(Ib9ZcfTQ0,Y-a&iHC!!-eI38!f[GkR9j0&RE9Y2bbiLX49 F-q`cGQjI2Am0EfVUcDGebr1KA0[,)VZ&V%"ZG5q`''M-lY4ApU-fTK9aqX!SZ+D @)qT2Bq!`4$j+)h4E8q0jG@YjEe,0AASlad"Di*XYc,*phA6dD!"3d3N"P'e@9KH k'"5Q3r3d,(-5rZ4N%L[8+jCBEM4rq"#cl11,("UX!!S6-0Z0f+fCYXcECQfc0YQ DhUk09kDMRRMrDpcPp4f"GCTI8#JcVIY@I5dfk&%`"6[ERGjN)r)NA44Q'UXj@*% Ck2FB0fT0)"l#L,8TKbAF5bf*VQZ'&EF$"a+HjRSr%!`(ZpA&Q*PbPKNF3rS0eh' -NNrM2q8UM"+HX[26DiX$2#"(`fQCc)3+eE#JME$kLMbX8P"UBKYP"'cj1c4Y@J3 4Ppff!%"4j1qhKpikTrNb'jaL)G%@R"41a9(028DLi2p$2%i&"AEHh+#G@DN*DA[ 1fER&frZ+LM@lKC!!Aj*ADIm3T3$pN!#iYMDq1"K$LFFXj-Lj(4p@)%#j$H,J[CY )VrP%[c66GN+LcHRKEX#%AiIBa2#mqkF@hh!B#3J+,ZGUMQI3bKY"YYbETHHPde@ *6"NY*1,kS!-Cai`XBpITAh*#c&aXe0+5f"[IkV"0Al5MU#i-bb%dbHk!C@9H`,B LQUAXE5!A(XQf6S#Sq5pHlV)0Y[K,8DR*Lj8a!YHhjGY(eI$XcM2`Ff(G%@-fikC mSlVSBfL`!YZE,Xpjd!6p%pRB0&&TbJPldahhE2'55V[(l-,590FdRUIM4Kr@JQY *6$L"bjZ!X*Q+lm9DV6HhQ`d2GZcr%*9++f`$Q@PCH22'ViZi621-N!"c"9l1r!# 2MBVSkRGl"!UBmCX,4(@GTTQd@iaDdjZcHQ$)J9'JL1,PAj)3!GU@(mc&YZ$@'Pk #%b)4ZKL1[f%f3NBG!'K3%N"E"3E163-[f#A+!0#ZAQKd9+,&mcD448(0L9Ti+)P YXcmYcjBR"QVbM6GT0m8pbPIRaV-LEVUbRQf*IU06Zfm*Ql4SQ!$G*Uf*+m-D'R9 LSC2D`1I!1pFR66Qha)&ipU4Jp'EHqKek5J'L&mp(JI4%RU+)LkK'RpXUmY%!@-k Si!hqQXP5qR%iNVMB(#`X05XfrA8SVQD1R!1L2P2-8G#LG+31)6`lVd*ISiEP"fX C)UerjAT@!Zr3R`Hqjc4kBZiH$U04MG)Zd0ZNb&l0JRVeX%e3Fr2L[['[lhlkZ3` aV0lKK`G4cVRqMZ)E%*[bm$q*Q3&1K939R5e%Aj63@edfKEY"YMpQ8BBT,(j3BTe I`2(+Dc(3)iT6NkkaB6LfbQ,PFL#V"98D`'+UrEb+P1Yc0R@[A4j15dI#'[k`e[' -K5j4!I3LdC2Ce8f-Xr9jlUD$-j`#"If@4e+%I,Zc9hrUC)L5J3dM9h+dqkD)+56 JI96rJ1JidE1A2J59Aj3l50EGidS3YJM69SKe3aUcd[a!JeAPMJ%2a8[8lrpYbC2 mdY,#jjVT*JqeKRG#Yf$b!)jRK"KV'6FIrUh!'(4NXkKU"!N2fVBD'Pij$bb(G`S -hrmBG9$`e(CF&9IB%Y)8)SRk[@SR'NHLGa33X51lk08Xj*e"VB[8+[+Qhm#j89C m2qLHchD,4)0VR48h###Mc)Qdm,J*C!aAAqf4XAJhqMYS3h5Pd5G2qi+(&l)A[)( 4*aVR4K$R+@LPEk2ce[BYK$lb1c$BT$(,"8Jk'6[5TCIYjH"lq[khYYhb3Q42XFc CkI"Mpq-+&X"C,l`rrC[("&3-YY`,qLYpFkj@,a(,k!f(E4cTRaa[aaDeDk23($Z [(BM8cP20$CB1LpkI*qb!AMPP3,kc,eFfM2ZDZ3LJ@Sa59RJE8p%U("j+I5lSd'" iZF*UU*0[KV(L[(cTYKaIC[5CBQ+!aqdrD#kcAiGZ8I`3c#1"&C[F*q&Q,C3S+XN fM-SLJE*H,*H#'dHYlhlKrJ'5#HAib-)e2-)R4*`lG,6TNEMTJ,T@6VHMjpF$Q!8 R1Z8f8!9d*K#f4e["[M@@K1%l&XJ'3"HUbRqFaiMqUF+ZiNLl+S!YC220%r24ZJr q'L"5%e3V#EY&a8#GX+(&4UUIVE[q@(pk)9b'Bbrb&"-IT#3[-e@YK2GB6cQld'' !QXHpE+PHR%IHXl39-%KP&QpCRES6r+UBQ@`%TV%@U3G[r*hE"reD`JcJaV$G+d, Y)qlSq5*Na'q2PUjdkZ`"i#VX5mM0FUJfCLP`[$Mm,jp1DCNqBZX$85bD$FX%l#p Q"B5-Ecj5iS2M(KUl0iIPU4q+F53)Ea4#6-BbleF)'GdXF&@a,hG8qH'03b9cN!" *cCAXU&LAQe9B+3Vll,I56mK1YDE2reGa6@LFNQPe1Te[HJ32S)$0+(36p(V!NV+ &0*PRECDeYrJq)bE%k8e%jM+VmD"NeB5d@X5+GTQc#P[VhK'%Uld*,BXj+,TZ`"5 hfK4-`5Bh([XR9C08DDFSU@,1$+k3!%aQbfd+6V#95hq@jqk"leSI#RCq5LpE-X` bf#K8K+F%%(3,IdSeZSI6r4%SIpKfh9m(kNCr9LSe#Q)DGd`2[Q23c1i0"d"m([0 %4VYP(LA$*ZP+JpU&[4Z(M`Lmf""pl,l5IFqlDc)&aIbUd#5eCc`L5!FQ%BX[r1" &9hV*LK@KLM)jrHF$DQ6,EAKJp8'h6)AdXbfE*rh8Z'a4j(V)1AG[*-i03aiPTXH 'UaQ(N9LEl!GhZDk@KK(IC2-NEe@lcGX(+Sr3lj!!T(@Xj)#XQpQdXUIA"5S'NS" EZ,T,R)D%6RF'!(22Q#e1TDAJ94P)P+$pKRbNeD#41b-3%4hF5m#`9h`03-pf@GG 264MQQrRc45p"&VKZphPJq#p[0bjB$(mb&%@42C2SMRhEpJpb,)bk9r@Vmc82JJ" 8amRebrS425CkbYZ8ecMiEYcNTS`UGM!QU'CV8M9RS*d-UL)J&J!G%NP1Rh[%h(U 89R3%l3Lh6(QHXN6iJBd#&jr33d(+(B'RNA0)C[d,Tk%&b-Ur@UI6PSJhpr!-2Q9 3+4B@K[pm$aBDNGZ5Ar`lb-GC*B8Lbf8A&k,Z05*Pk+rLek)XGI"bR%KIN[Me%Vr Rl[2Ye5Ch24'b'60q*Die'@)L$IBSR%)3Mbl8H$rEX91&VZ`5[AZeNlVBRY4%+ae !P$#"STc'3qV(T,R'i"CjDdZR2dc91+98TBeSR0-eIlF3jE(8M0"rkiqFejrf$JU *d4UB(jQrk'k@DP`CP3$F#Dd99CIEQ(pCa[(904i%p6ZR6-BTVE'[L3d@DMCYG+b ULRMDG#)%*L&bc2m*khh8$cqQM'bM8,i-hUl[fk$"iR+rmHaFA8mqb"VPIFpD(QV JH[BJh[QpII"Z#$`efpr6Hib$VJ+YYdj)TX!YecSNRDT[jZ8!)8riS*AfM23KZIE $JaIVlp2'P`RSm`MY1r,0a0A!BE9EZMcTE'-jkr8CSTemGk8qQEC0$a$QBI+!T`f "kNNN@L9UL6cm[B5[`,9FJLV%QUkQh9Q)`'d9A1FC5aS#Y%,$hHejHJ#jmU+ITVf i8Hl+f`KEkX*&5kD+T,fhTiZ*@BbhURC,PVViG&KHKjAC%K%+D[mUY(1#RM-cfX1 McH2NZ@rVk6J@SaQ!(8DB8U(Ph*jFqQ,"jd-D@QEGHr1Hb!$'LMldVj8b3IRABPD d#8'rC$dZVXDGm6a!UNL#4AKJPC9JJ,BaT'eT%mmF0H-jd9E+8iA%Q*3j#'2hVQ( HFcrJa)Y[&FqQ,H5lf5I$2BZYce(LHe`80KFdqYrLLM9bS#D#fbD&56$MCGKSL#A f1fAT*XU1XkFdD#eH[)A%4l`ZjZ!q@B!"CS%Z&k!mp6rP@YSZEIK#Im4c&`[Ci"j 24XCpZdJIR$IK4jF!ZKq(%Rb8"k,(deReM"kpB(6kZhL0+`TU!f3XHBeA4`-N#*A ,pB%B'*!!HA+#ir#i)CTcBpd2M-mp"5jFl+,0T8@6fZe@ZEiHhNPp[(Qr(*4D`fl N+2mZNl*kX(ic8$$EPTH$0Sr5ClNF[P%TfQ[ccHJS-XXKqC02a5G%bqj%@KTRTlD Xljl8C*'IFeUM$Pd"!&-"H'3#bCV(NY6iTG3+d2p5l1NaaGVi"a1N![NL,6X(X6J m'H8d0+@S6DGhf(C8F"mGF2+Umhb*a9L1LAY,l`I0r'Ecq,N[51CjZ!'ih*c3'-f (UK(JNc""YjJX9f"G-kPB,VbK3BSj@Vc$q!KiYTfV-l6l3q(-l&$8h%GH)pe,HSA c!afrhR-laMMU4K5rPMVNC#qC1!EqXU0q-PC1c-dBB,1`42maXcXe0,BMi)VFrcc 6#EKLbaIhPlN6UUUUUE'HeNEHC&3pS*,B!D"(fkHS#Bd@hrcm3adf9`-BV8FR"Ic F9P,!KVMH9h@MApl5'HUdE1Qc"m"rLB`aQjXp%fVPIMP3rcj)a[JFBKS[YEY!"NU H(Z%rTJZUVmTk2kVkBIL#HG"&DMUI050H4a`Uh%+-mc4XGImL"dPMM3Lf-BKbkr4 ajT`ri[UkYrfpYAlHd$pZrZI`l0VlHfEq(DCr$S9ar$XPrKh8r`GTrf(4%2,EqV# i5BY@fdJ5Dr`YF%1)LhMpkI[XDaYMTMKNRSXihS,4q!,4H@kN1%51G,(BI5h3[rm ''fqPMR1QVcViLS#aQSli[MZ63fc@DHLlRb`2arG-`cf,[dejCc`ebmqFqq99j8J d[2l6l25Aj!B#5HJC6,EapCmJT0P'9EVXTTIU"cMSc6-j%SRPkUVN+(EK&5-Nf8F cdF*RJVeG(*D3!,e4Tccke83JEI'AGe1iI9G#l''!5[lTma%YK&0V+2`1QipFD$2 P+UFTJr#i#LReF$0i@K-a$J@$8"10Ql0r[BM`f*5PCZ2DqSp'RM)IdS1V)j@!'ZG `c&qJ#k&X*#pUbJ$p$e)YbD1EC!hZJhehIq`8&$UJ4q)*dMcq+88I,%i#e4G39Td rkPV,)DM3`c&i*AaP!HI8FM0di2Y"2hTapD)*q0rBqrR+8dh%fMp'kf9mjr$(Q(J Z8C!!NqLB8kIYSP3lHkb6*D-([N4A5'"ZSC-VJe&qX%46YEkr$%"B181N#,eCc(R p9+`3mVe(kJQQ!5K!dcPimrf!d*kRfj+hGJhr61ai6%Z!E&M))d,j4`'c5%+&`Ca @d#R%e#FYli@**kNa0)M@0JkE`PBTY#e*a$eP4TieBjD9IY@C"4p'+eeJZ2mc3N5 L1"GZCh&J'DmDKf($&a+(rE5PB#%l@hqP0)mY'$`[`9YDJ$p0J@1$V(%8A#NpXDJ pXJ!AAaUFTSf8Zr&461Zj"5hD*P15I9AdR"XN2p%fLCdFc%kE8*8K6`+QFF85THd Xe0*2U`6kDH[Kj""8mEEIKB4L39@F&-Y$d'Q5J12I5h629HHJ6$8S8QDE!k#YB"$ @#2`D9KI+e!9N0)PTefb&ZLY3#DCkhKNQ3khV%BH-Mi[(APN+@i--iHB*9(%-SN+ DLFil$#6[IpZkT6+F%$rm8b,H5QrQ(b9HDqP!03p$1QX,[X2N9*h5VlSQV"1@)HZ U@(iP@hEXpM-4AH2C%+d)0Sjh40[@k%9c&5KPU55"Jrfl%3*eJHD"p9Ld(U8(&*0 (hG!C-b29b3[hF[MMm8'2MDTYr!3+()TK20,Yk3cF-PCdcff3!0R$Tf[V$qKh*P@ Yc109(BEb5#dNA6&Z+)6LL[54((lF!"V(kB&Yi#ZK4m&LdZ33443,j@KJj66K%fK pP@dYFiT-`92GX3[ZRPCf@Kh)ULrIF)eaL[#XqImk"06%#q3pU5NqiT1%m!eT-Gd 56Eb8JkX["'ca$ZKLkaAT##qF`[)D,XQ024C(0XE(4'LJYf`Uh%X(!b((q&cbGp4 hbf'5RkZIMdDh@$51B2&%*V9(AF8*Abp%Z$8fNC&pmB3+5N-4[q'8U&M2C)4"'jk V'*2$!'CaqEid1HKk+3cYHpb@deT+"M36rGA8%hE(rA6V,F2--bUq3cZS2D*pA5L 3!+JL34&Y0'86'I%D&m8D(9PMJ3`%GUk8dNempH+0Ak4GNkQN"-G4TL*QmfJ5K(J i5#28!21JB9KkM-DjEj%Me'5l62%GKhF,hL6DDMrLK(ZS)Qhe$fHN)AKhd%!eH2f D$(Rr2,+ED#apZaP)hlreFVk2NHcXqHIV9j*qUXherh-m8DKq53q@J6Nhi45)0Tm a'P)AR*!!!1qSGakSfh*+a+ZTYRll[%c@d[J3@+Pc#1Pfi--X+JJqqJ*TeU45*qZ -S!!2h3-c%'UR&3jENDZ%m[3dN!!'Y([m*U9#,&08&UN9i3+,Bq$2D`JKG2$d$Ep M"1m+P-k#"N&LY813!+6ZYqShHVrSY5#@q&!Y-C`AREMlF3jk`iZ,6kRIM)2&!*5 !N!#Y&56r02ZqpE3)jJBRL@JDUCZl)2-!+BmSi32dA856dC*j-Q-KKUIjQdm1G&d @V$A3Y)1"QE!$rVN-lQ3q@apd,Z9%dIAh%69QPNZN+ZjX98,T91&MN5jM0dHQ,), #i)Q0cPXVSG%bVf9&i`GN`CmeKb[p$lB[X-$rH5`CdPUR4P2EmZTm0Abr@L[`R)` klY--mef+XBbjJ4"&P-RhZRi$42(39&2Tba@Y-fD'FEJSG`&ae,bpK)bS9qETj@d HG'b&P@D%JU@'Fi$MIDh,")P+BB'r'46P*q#2lCU)#,`cjrpr,)KIJlCK1TY4#M6 kIq#$V+b`E2-GRA`hKmR[H$JTMbYC,FHiK3R[AR,Tik)Zm@L[iCa1aC(Tm"[DeE3 T,1V,Naaf@h-@b,e$FLJ!B,(MUV4fhXUNB!jjkY6QD"@%Ch#NKNLGcR-`UZ(04pA hk`rE*a&V%A8I6)``+D#qYdVNl3UJpmT96R5aLUr&2P2I`HI9VSi-pBG@XBjdmXA #2q@[d[5be`0"9DC36%2@rQ"kQ'2iDIA9B2iVdhU83T!!(8HUSG-YUC!!Br8Af(E +Vrp184HIY6@XQMU&Np-*A)SHi6Z&#AiCka#AFe)9!#5kqmGTJ%4ELY3#4#6)H2F fh5V5-BMfKI@jB#ekIKDSN9G3m$XRQUa*m)Sm"HT)dmUiJFTU(IHI1HT[Za3N4fc 8VR#hC[eGV60CX5mEk*a%cb(%DH`X1L5KPh-09bTfjeJGE5*MT*QG9`Rr-f'ZYVe (Ak@Eabqp2h2pJM&$0+pelpk![Z'I"9eq1TXSQjD6r*@'(M(Tp))NR8U#48G*AQI Tr0@+Af)m'bhlIKNLJI%2$NhJTV58+%(N9"*$T3@F%!)d5%`B[JA&'SP5Vp!b9&` Q46@KYqEMqqIiFAaE&ZELd(G+Lm02jRlXTIhaIJ`pP9mP,Tp"JJlh)8mQcNP[k@' C,Kea(561UlPi,242SM@V["HR!ja@Q"qL"-jBDc0f+(F&,hHZlCe*p'"IFpJTll* *S2K2L*VHH*E,M-iRA1G#XpH6)Ya1V6Reh6*YKEL1KMIe3,ppp!2#J),%T'$NYSU fL[aUJPP3P85K4[U@m2FJHd#UXj,+,YV6ZcRRId0c&&5NI&)R'l5DTAXL"+jGPYZ GJSpYeD6@kGLHJPSJi)9+,'dN9bE%)QNq+kB%LH"f10d&P0D3!$bR9QPKa@8+*JY jU'jkElf`caBd5d8M!5lS[1F90*!!S2cbcBUef&Fmf3Y*Akkm0Sa2L`#JifVa2M- ek'DC-HN1-Q1G1Zrj8p1#&mJL[PCS"0$SF&F!9cQIf&%T8i61&R48l-QjhU(S5TJ rcINJ**fe,(JrVjdGJ$RQ!KiUq0M'1p[1YFFq@[p6'C45*(r9(bBYlrmE!8ddk[" Q"cpL8V"'DSI%CJcEiPhd9h'2PKRVqRi39AQjc"kd&4C2'Dl3STI8jqU4lH"k6Ea %f*!!DTl9h&581A&JUMC(Sjm1V"65$Cm1m!('Zff(BQ3eS[0@'MQQVk9*H**(!6C ""D#")edZ15emZEk0%e'@VfMC0c5,CBAIic[cTp$dc!fqBA$Pce*J!3m582Nmf!b Jrch)L0iU506GhfB@h0P4FXR4TH6%QQ$`9ZaY'2$G+2J@ii6[Vk6)PHbYFhdThMU 3!1m&YYRBdXNdiZlVh(eqq'(,Zd2AN!$([f-B)Ujj$CbDcIQLKbe1DdUmfM4*q-0 &p-4i$bQqT4mFZ-hE6&Uc%Npi+N5-QXFh'5%QZ`fcmJVi"9(JH(!C1T3Y+l"Z5ki jp2,9D@58VI4HQ@N(RB$8*Z8ciZY4P`2FUIQ[,G`GVl1EIcC0M@J,k50J3j92TrD 8%%YBKGpQ(0qrj2@VB%rSRA6Y#hX1H2*M4e"5`drU5#V&NEI5A`(,'b)d9%NJ#fC J"k[G5$mabHSBkZFeQl%"'!8GIG9cq0XH"+Z`"CZ*PAP!h#E1P1(f6Y&NKrdmib) "KTbRE(6X@`899dFl+bMCd'ZDc$5PcGe54"RbR4ZR,[Kk&$L1GZN'GF,Xq'$BI`3 r5NBRYVep+kmPr(BYc+bkd&[J"MZT6HrF&)faDp8jITmhZ'Xa2Y9(hrKk(V0cbUA Eq9M*[G&M$5$+8!`-&)ljZaq*GD4DKE4&)T1DMqd4Dkap'1hBb1X[IXi8!Ie,5G4 !PM6hX3J[9N6LS-SZZRIVj-0H,-i6,'K4h6qYK(k3!)[jQd&im3VF`*R8Hr++4Y$ dR$3hj%j#p@C5m6)-h+e-HDPrZh!VlHiT+@2pmD368DaLVZiQMqbNJhAF6#p[l4k #heLm0qj)-5p(@Pb'ZCc+U8[f9SeQrfT#FD*h'-X#kd36(9dkG"l9B,#(VdT1a-G '$)SMMF(&$qL'd6%Y"1M%i2Z,BcKTC&,dD'd@B1`&0@+6X0f-&XEFMSP&iSZiNPD SXLqehJa!T8IIHeCkhG*N4J2cfHAG999Dd(r2Tr)Y9BCLbRSRqD'5hRD*hJ2ZGAL hBH+3!02ENYhjheY($15C'D4,dLVQ3Ni,XQ0mL3Y`$!1Y+XaKAr`bZdUkD3)aJVC lkd032Rqap%G)2`Qk5`dX92BFpm+,pf!6T'q#++--8I3k%,p#F,JmDEJLXPhClLm B&$T*lVrH'JEQ4Vb#11(a-"#PMV6V+@FQ`54DaK(J+Jl,FSGq%4eUqe$3E15`P!P %Y&-,YU44GcS9V*KQIflJDll#&4NCJS'1*UT+TAl2CVeP+[VDE$&`(B0BHM2f&V* 4mrL)Ap3JFKF)I2Jq#91P-U*CN[X0bZF,1K#'SNH!-k#+8%L1PM&%X&KI`Jp#-Cp &H*RaZVm0`Q+9pd'E-!68MJqTdU[!$dYDT4SD@NJD`$D1*Dm)6Ye'[+1*)Pmp@qe GE+*3)'64d0E"p-dU[1(DLR8D!UNa-L,jAP*d+KIh(*8XNpTi*U)*)NNl&EaDKA- UUANRfkZY[2H'1RpV&`0jbEPY,,A$2JpSH@Ge-'l`kHUH43AQ@@&SijVaZYVC`"r hTG1LkCRa%!%3C*VPe4K1b3B'B&p&PdGj54Ih5j!!QeKXQ8mjVcNJQ@6F`4ap2R- `q*1eb@$Vl45GV%%r4'f+D14m%jh)C%`4%,5DDiaQ)hDrP$$8Jcjq#CZC4HNZG9D 1R(1d&5Q55[l*S'jp0KVL4f#+b(Q+2J+lGNFkM2UL&Y2T*&UJ0e*)k8-p`I,IYBc hCr#6UQ0("Jl"[!'L#mVQGCli%N8#DV-MLD23aVM'm&T(GG@hrUTr5!lQUDVLT9K Qj40L%)Q'Hdmi&NUj+QMN8G9CaR6q(F1I86"$j!mP#&*R(ei"Fp2NLD*@iLrb0T! !eMCL,!iQi6KP$d#cFeQ5@,r$@UhVr1XrIL''6[l!%A2"bHB00MBKMc(-+'QLI"T 'UZr[ZGC&XLLCa-be[0dBT!je5*VdB*+)0Lpdda2C6M!P@Qr'kiiCE,2C'%Ff4Zl 5,lBpY`m9*N`PPAMH$9V,MXd(V5N)*AFrTA'a,$aj['['akQ$C(qINDkfKDaE&hC cSbi8c$c$KA"b,JrK'Yq"babfUPT8P#`TeIKb"VDh&D(4JUeBLH!Xb8[XjhX8V'Q %YUNQAZG'q63RVb8"Qi)Hqp+Y3L`l4&H`hlQZ,j0)UKT@69A09#2dKj*HJ&GKrAm 3U'B4UX(&4-2QK&Y#8r@Y!@R&B+%3jdQ2RcPJ+fkDCDZ"HM%H-%`%P`C9pKLXS6, Z3qah5@2%44SLl+Ka&H(95aDQ&-+9P)e[0H*pRX5Tj2Cfmre*XhRpjMPiq-D3!%Z 6(j`+-3B"dqr,35C*EP+Mjkhd)#VCEAJ)'0ErBS1+Qekrf2R6Ajb3!1qJS-MrCS4 **338X@X@`)CN-3+HaDQq0I(j2,3hbcY1m3mPULaf2ETQhpJ0Vk@R1jlG5UEl)00 IU'qdHT[Z%+'[0!c`%0`rE@64fm+@,@L2cqqXBT(*rDbl6Br1A40IM4[4582*Zd8 3Miqi2SXlbP!a3DXKU@5e*dKdjaGEU&%e9V*63f[LlNA'b5LAmf,phF-)ccXKqEf +QUSmBSC6$8h3*V!YAb[ST$q)G*MDRX5UNAr@3-P(&F"mBKGK-`b+m1[[NEj-cKb 4N3*iF8e!$rjREFhbJKPFKZa,'fLV#'1KHmlDRi+MQ-Br-@lCfc!V5jX4NV&`A1S pFr+c"KJEY3,dND"b@Qb4a-,SL,iKb@&1`))(D'9d1M0,-,*!JZbcUJ!lVd8b,ma eK8J(a8F+KiPNLe&L8kQ6S&i55$*8fUG62,9d8Q!X"0+DJ$4D6pMXCc`9e@a$0ZM 0qI)q&fQ"A$A`NkbN2a-hUJX2A`JAr8I0aaT-rB1Qk@XB8ZZ5MVJ5a#$(h+Q!p$j "fApqiAfF61f8eq@N`bm8KMQ!)Y,RSVN`3r3kc+c0Uj!!RQVM1$kkQ#GGkR6e-1c J'YqHqN8+0#Nd#c)jaH0d%CGD+%2A8*R6Dhl[Y-C,ib%0fD)`CNE8C"rS6%"1kCq Erd!VeJ6cPS&k1m)M#8U#dB,fZ'ei0pb)hl0cB6I@mb'jbrVJV(*35BE&T9hhmFU rKR@)eR,4K$GC2F+'3P(b)36#eH%H#`#`qjXk26Pa@$CKmJdQ,aTS#E)*J#(1NY0 T!3$MUCV4%Z5l-108+@L%Zm6%BQd#ldhTq6#r-U4q3#'If62l`9hJFPq%k-RBNmj GZR[#P6SL+91*56-FDIMGDd5SUfF)`IdATN3RT+jZAACF-B2%`Hq$,@cH4R$#R"l *ahFA(,X3[2"C8mRGS2mep8S8G2'$"r8r!5+@AJKPlM[h8Ai1eH1YhYd1!JM3bp1 D*LV$TKNPNm#bL#RjC4KC)h2iahS%qeSB!PpMkZiD2L29l*U"BrhV*J1p-V`$,GT Cr"5)*p$-pb0NUf90N9jV`AA5GN2BHhC2H-Y(r6Pb0L8d+F(N#Q**R)Ja-cBB&B` fX22+*YLHc0&6L3plmJAN*0"'4PZ+AJ2fB95*!9#'fQHd*(!59FC@Sq5Pj[&`KD- NJefPd&YK!pF0L$j@TbBCY9NXa#3!e@-)QY5@q)h5TdSN&%N,NP3iklE)BJDcLHS '!50cYRQ(#U+!$Z9-FQrHV!4eNU2e3Y-5U+Dp-4(PPXR@3+!ahSMcI-K$e'QH0,H k2$QM6565BYd,q&)jG5KUkf%++`f'N!#Y+ai[$9kmV0&i*k,U!F-%9f+aGP@dcE3 @KE0VQm0jkKHZI6J3L`3RZ9,Z!X4k$l*Y[Q1Q1k+&SARF@icU,aq4aD!Ld,#r6Yj B(1kVX)3AMKbBEp3EbM%14pF)J+)AaBYIED&!)Yi+,N5h8#Hqcr-@pT!!`!2PeLG 9-Z4"(NQ-Ur+fY9S)&dI!arc[qH)lde#Q#+QUT0E#%kkZ-b&CM6Sf&Y3[iG5lpej RZ[Ir3qdf(eCC)XlHE5GF[433E,r5(m""ZrQ&[EY##d#!@'!*jTPp2m'f(TUIY+# 4@3IL6C@P!GL+N!"0[m,(jK"&iUS!`[,IGN`8#U"+h'h18QHqeF'T*aIii1M-pU[ K`p))e`Ch)00KF'K%1h!HqjFkHSG0mPY2QRJ3RU-kIm,"G[1LCJe9NTGQV*M+#@5 hD+9URQdB%@5r51%AeCm&9&k(E%VdL!SaF'@(Kii)&NimCKE#kqf(5CURPKDAL@C F*1REC+pk,)FPhQS0K"R(*--Lm+G)iAFZ%J$U"GfI6Lpc@I&DMJl(%LNGD3--3Ak 6BF#A1S06,lN!DCEYITU4e8mb#FXUM$ba)X'FXcd-e'r%N5Firbd9hKPrNS)F0E$ 3+[`1Je3`Lk(p-#53!&Y*MmMk(@MF`TFEj`fm5VPkd,IT1C-QFUj-BA,64TA0BrV Lp%[p'&,l&1ic,r"Z8)GPP''G'F@G+4f-Bj8R`36ma8Ldr*lG0[ULHH2QPedd"1K 6fmDji"YE(4h,ZNNcp8kJ$rfZDII@+KmS+j0VN!$!Dr!m(GBjl9YT@&Ti&R2E1B( J'D`K2b44q$f#m&i,`)qFlUpjM%rR3F3EEL,CF6C#D3m(GIITIRcfhfm`#&I%GBq "!AD2rT-RQ)3R'-1@e9k,2bYAS'V!+C@SLPFeL[b8@BCdfYXMqKRYFPc8&QTVMqC M#ah@f$RYcGf3!*j58f&4-6mA83VmmiLr8f0RcaXc%%ST"1QBSq@jL4(L+a4R$%E 0*`aP2e"Nm)RBf"0iAL6QUAM48emKGF'B,!Vb(G[HJBlP!L'U39qZX8lTT2h@N`6 aT8,h)hr&f+H`3h[U%D-4jYSTjq2iZ35P9eDc'k*lSQLfAZI2)$M8h9Hh2@bDDD3 THmBLGrK!eMdL3A`Q4ZY33&+'CLe0'YDjIhk+([S"a#ikk'C6cdea,Gp*(1-XVN* 6HBVlRkCrF($Gp!(bX!eL1rXJ2'KDMFZ3!2T6SVQYC!Ic4*Tr2kUdIIcSCHF)2@P NCS(KS'934fr2+CT5KhkT2VlYN!!3F0M3X1L`[",Kd"31QH&XN!!m5C-eDRX!mXT Zm9qaL-6fc+Y4NqCc1GUhTk)&3,)j@G(c2MCb+UHdG9$VV)R0"L+l)X)HpY'qI@V 1F[3fLa#CLj!!Ya-d+*GPSCbC5#BZh9(5(i*2#Qm@VMTUJ+mG-J*k[a5YfIQU3Lb $jF21phZTiZ)AYN)Y6i4Cpd0Gf,bJ12eTL@pci9+V2B$F@dD$fAURPRL[(1FH9kf CpqD$#jFS6C!!plCYaANUeS)&k+3l@J%qd#$SMVB-XI*rX4dafp3[RQHM[,3Yhq* -26J3ceINZ#KUqE"9$ETVMfRCaM#A1&aU!r-(dImkUL(Kq[#*MR@Y@'M93Q'bh,- 9A90XBfF'@6b5dPJLI%pE%Xe6pEF2P92lmA@p6*dlLJmM9&RilJq2CRAXE#'$K#a F)ND#l'4h4a(iAp5qiI8[&3A0S&8a"lDK1p3m$`FacD0E9eG3D`EmQU`@jpm5B*D &iG!4r-%"4X#R+*8+9L%8bJ4C*!6N-"kKi-#XX"[pZHH*YUDEN[[SXTb50*Y,VJL 4$`BU1HUSX&V&RKV$['BNL"Vk!a6@`*m%FXqh2`&TqcGqT2p$JbFK&P[N2j8pi)2 $'iq&GkF0-CQrQ"rPdmpdYN`RGHi#hl@JJ@M'Bj-5V+3G`cV850HM[a52,#rA$rH *5RCqXU+##[*fAaP'3UUH0C&CAffl"i(1*[pIS$)FX&T9j,G2iidfHbUJ-E+cKb( ,T+&&P#`H0G&9,f3jr*2+jLHe3KG9C"SfRPK2T8@#"Ud*+li("elNEM@VEPG4pea l+)Z93LFRm[k5Fr0R0KZ%'5f&U@*kZ0&B,$aT$)QM)l3DDN[h'a48KkeMdArQ$(2 bCiZ%0b$l!USTZK58)em3CdlY*!i2Ff&l&2"$&INh`ai8*Ap&#!+2VPYNQ3qV,V) ,hNUkD-G@%-qS,3b(qGBr!EH2KePJA,pkZN#6V[Gq%K&1Xf'i%&lY8aKij9fM-"X 0pKJ0ZeZZ"D*X"JHr,Y"[+*Y&D51h-k50V%02lj9HjPqSG`rN1,m"a6GV6`BL%V1 G4lU0KU@XLp88UEY+i&CmE"Q3!)"dQ@,,E'2eRbpml+0r(@Zj(6ZK@qr"2ma*hkJ mB1i"aPc-E"m(0@pK[V"JhRmpAeCb9)c+Gh!j$TQ,0ZE##3Pk`j9rN!#CF8H6&X6 "&h#IAk4DUpcK*JBpYG-9`*SUGM6@lC*Tl*2)!R6mG-TP+@2QX&B9)5MB(!MpSCQ EZDANePH85P$NU2a99c($[l+m!l@f%[8HeAX)EST+ch39Y0I$i88X[TKF#Qk4F49 AIRc'H[Zhlr*55&9rBC(cN!#iBY%A(984Nk"0pLjQTa1Y%-&3YeX2HVlT2H,C9iq #%[CN93I9VP*m'cC#(J@YTYkBCZdH1hIK%jeKBf[%)HJZB)X'N`Ec*3Ur4JdjA$f re)hIP8i@N@aT[Sq*H3Y%ERP"0-UhbMZeR5de+QQb6"5I)33EAqU4J8)bBRRj"$j KfUP@3F+iZaP&FLA6CF%HShBH%JX+SHVE,BPTC4C6&,$j86Mr&+EZjkEjf*FS2"8 e)Bl)&ZS4!25!-8i1VJZQhCL1AHZXE8#c#fYmX'`X6FD1BMZEjS(,H@12!N%pRb9 Bh*-ViQ4rebBjiM4ara0J,iYiU[@2)plA#GQ42C2#Fq,hF-"&!jh1B)5bdkX+,"$ FBFB+@5S+q++hJjVK``pE`k(Kb"ERE!l!E1+IcP[G1TdFfBATMbUPUji(pEm@piN hXRSGFd9Maf(r$2[,@2"hbBd)(j@YF#,CVTdYReU+&fJ'f6@DfPjKB6ELDde,@[# C'5l[5mQ,Lm)T@E(Ua,I-mpV*N!$F4qmIBq8q5$bTkdApb%!KFeb[pFT&Fb((fSR B6+JTRK4dkmk"p56kH+LTN!$ah0VV[UD!f&T%2AAX#S1(TeiAYLZNYi1KFQf*`dC 6VdajrdINRUbXi(AiAjpRi-ki&[G"J#&%hZ)HE@i0,3TDDqkL%c(T8cP,f1ZR$e0 EL26qZ0mNdr111kCdHjP3+"m)-LcA[FCV!j5Cdr0S4c+Icp$[D[AC)KYNF0imc"q !bKR$&5%PF33&'90UR9NiH%[@F48GVqLaSjrKhbaX%CY,'paf*"pMq#QGj2YaLZr a'lVf!$FR+0#p+Y1#Z!IYN3JDAP!lK$IDJNab$-!fH[IHlp4I0Z[#c-l@YH#*4@R IcRX56kM0d9F-&'Np1'Pj6&SU1Iaj,@*[(+&8Y,-9lqY4M"YUFLj`D!)ZV4A"fq" f#k$9HCD!%51S'F2104rmd`3r1!VjBPjh3+EjifFpejiDcZeidR3FD$(63AE!GDe 1$G3&Jm06XZUhUeimVKiVUY+cc5bUk%+1"%XYXIJb@l0YZ&!ilmC`I0mE,hKKm-U $'EREicAHP@Bdc[MkFjTE'``deSY5L+CSjlrAalNPik#c`)R6Uj%M2r4'&U6SEPe T8i-L3-LhjY3(,Kec$jem0@1EDKEhqDIM&i)Cdd&F"b&mQ2c%2p`'DRm9i-*l&A2 'jlj8,cl[Ci'ijUTMM4JV((dX$3K[p!+#c9V[H3D99jJ5l3I"Y+h6#09LM'Jr3E& (@S[bRQ!jBJDY2d+cmCVYGmYqJepM83'MQ@qUpJC[KCP`(Zq)Ur[Ba-kaB8Y'F)& X@6(+k`$5i$h-Rl)'mBFIVG3@Fca5++,N3VQP*-@JI!$(abZ%E(L96IQbpfPmNq& NP*0BHRXZSV'RYVG2GAc00Z4iaNJL)Ki-bBrp4#GEqp6E#'4DhJKN!iX"kMpKb5, PRPS3%D"YXKLcec#q22k*($5Fld`,*JJE$@e##D9iR8Y1SSe4mdBRBB)Z42eKVhc [6CGY*daMHAB,Pl*1B)YbCmVRMM`DF0RH*GbA%6b$K#+@#,PP1CUNGr%@,fj5%UI +j!Z,0Vj"@5&Tm&%RiI"ZXpE)D9P%6)U!PUPm)E&#JZ@bINqrc%Zm$iPI'ljb!aE jj)HCpTP&F#-E8[2pANNNNGKB1$Rf-$A6ekf0@I+@bSj!A@r&9ijlFRr95@V@UN) 2[06$%*pLLDk`hK(B5)IJ@icBYYMPe()N38q!mZG!6!(QfShpK9Ll(rG1Sb5+m$( Uad9CiMY[A"3aZrEZd8'+8rh'6rQ3!(H8PIPj@hVH2pmBV!JlS&"Gp@M`5C(L6k5 SLb(8%N2T`kdi9ll$YGU`V)Ua8"JVh"C5J55C0KE+2r0jNRCmmmB`NdG0EmFErL$ #KcVF@j*aTeklIq$%Lfm9ckBYj,[C*m-pM6eVKXPFYTj,Ndb-'K*`XD4-LeHEZ"@ 9Af-YNe'@i@cG"Z1&Ur1FR,L5N!!H)ImGj!pl0k&S5RiCX$F`&U@4VG-bL`,"Ia` @a2PLHp**j#`'leHP-p*,LbHE@fDakR'M@YEVVqd4SDND"VhhK292%[`aAPMr-pV %YS81AH'@P@rjK6+lEpq[il""JT4H&CM4)*Ir9'dYKHSB$i9"b[4%X%Q)I*@AaR` 6`I`@3@TqemZQV[#aPM%KVND`KiEHULZF"$+B(B,&IMq+$#$"Xm,RjY9@YFLLaa1 (*KrGl,KL1i!HTp0Y)H)#84H!*B*c1!0K3R,(U(Ah$Zq96kP9dkD@FB2FQ)ZijLD &*9j6,JVMiMKe15e6S)k$lQVXAkrVITQDRDX9+*I`3qjeYZ1iZd9RN!$b58CHh'A Ii#9hX9c-[f1Eb2,aG#QG@fqGlA66'[!Lq4%K1r9f2SkN"dJLJp,YP@+YKd6VJM9 ArHiT#dDI'J0e&$,AZY*S+8Abq-k+`3Im!rYaqhHSKdaD92jCQE`5L85MRD+A")L 3!+!aSb[9*rGGL1V'bD5ab*84YBN4Hl8Y[Y5mLN!K6ERD@P6@+k-)aQKrFki+`$N rCLX2R1@Im21F*fmZH,CkBiUV#)(N"edA@p+Yd$&beLqlq9,6c@iV604!RVBl,`4 P(Cbp9qh#6k+21DpT6Q[0AZI!q#T-)QJ*NYQ@baCJJqAfe[pKZMr$G'qfd-Re9Tr $DVq'iYpYRirK5Rm0XIiEMr`V32K3,'N5Q$Je$mlmSaVq)mD(94Q4J[b#iNM#I3# JRd!S*p!+#I3#JRd!S*p!+#I3#JRd!XDlNcfF,$rrA1E3`'!`'!`'!`'!`'!`'!` 5EY%Yp)6mBcDIpYUfVDYUfVDYUfVDZ4b*-pek[r5q#`Y%"p5rrh@k!RjY0Aqc6$a )hE@4lH#b*"bQ!DhN-GU5r345k9)[5`mH8TR!V'BaELh&Z,F@iYaELh&Z,ELm-C! !H*[lRaa`FJa-rhrBVbC$Tbd@cKc)dAVM`B058'dAjq#!j'abX"S8&cR3rU["VbM F!BQCp@#r3C(aX`)K1"'f2kKk*f-Db*f"MacN#VU`1,lr*!SqF("@)Q4LXI%GYle m3)!2h!pa)DfB-`Y(iMf[+RpBG1peh1+BNX2MhLTQmSd&apdCHG$2$2SeAq"GfAM CB,G2-K%SD$4"3d!!!!!&"$C"iGbkrFbdDSS+#'pq'ja',F#!mlVPN3IK'L`[18& j32dLFeJfP8q%'KpP2cPb!XY2L9')YVr+RSF@(@2f-&+b3+Gl[Gk%CTa(2i%!KGR C'J5$Q,lp$Y(j6-rM'XD[Q!"NM*K+'mQ(19QIe#D[TU'q`iD($Qm(3F92Dm"Q"CQ m'a!l1TZN8Z*CVjdj%R+TmVY$9Gj'mKIT-aeTb$1CHK'Ma$Hfe1l*@6$Ueaiq4#X @-9N##bK@YeK2E-p5d-MlJ4(b"iXB$ZU+-[ph+Z[),LLCGVJdj8G##Zmc5Te[+8N 5#Y)Lk2Z4pb2Ypcm(T)Zi5EG1%9EX,`H@-dQ%kXP,,B""&3m)KbrXkZ4haEZ2(-a &e)3@8EV%!TY35Xr1[CE6mGq-9!S,imlk1)fb+d1pqIGjm%q`6l"2X%q`9(rcaQG `LL3MPXJd9QR-NVC14S,6&ZUkbG2!X8kLBr*l1X+M-l$%P(aNjcZQDahUq43h*AJ cKB!(jP,d&Urb["+(i@B%E&5(FS9bAJ+RhH4!Arl@CD,c)bCJ*VV6ECR0ZM`691E )#0Md2qL88(dRalKlp!RD3TXQf3E4ra+IeCIf[%LSJ5!!&%"%(Cl32-5")0kfdS! 1CRjpq2QD[)43HfEik2ReGXA+Y&&PqTXM9Schk!3*--q"qKPeeiEYVXhTbZN')r% `6"i2(Sd3@fJjR&CVbVI9UPJZ!E-FTaVc$X!IK&K3+q!IimJ3$bG6-T4$(5QGAl5 )[6'GL4P[+f*eD0c'c&Ll"I$`2'G+9VB),p6a,RDP42$f)q#,$2`k2[0KhL6ePRp 1rJVB-'ah#%*Sl-#C3EYb26kN@JS-JFj`2*G!+UBZMhI6c&h[MG&'9iGh1dY2R8f &qqG6B82YBrP*BUQmb-52C*Vq2SR9-ak*YEXeLPkj'I4m+C%J+a#%I1R*2DC4QK0 'LlCPj5+X48$iTL,Y23mjY`C*rTXem88SZSrID4MqBdNLNQ!N`,,pLEE,b6*p`6) 2JZ%VACLk48$!4*9f3ZZc0Sj6#q6F09NKa0R"3TqUIlU5(@4Kr@FB5)*X&&-jA'2 2[@22NiJ`!GPjEVDSl4Freehr8$dkf[eaq6h5NFGq6FFHX*Lqc*f6XR9GfZ+3!#Y m)BkE35TEVGEVGEVGEVB!$2VSf&CkXGVh[0EL[RrrI#T[#ehGCf8dB*&Rq*RM8DM 8DM8K'NqKe0qYqDK)2YIDqepVlATM--5JkNkNY!)THMqiYaELh&Z,F@iYe+#8I6l AhV%[HN&m8,835$qc+Yrkfa51ajK&jS[JE)RHXm4aKlN(U3HT"kN(U3HT"kP*LDT Q5J'6r,5eJ%JfXE1lk+,Mj[f#(Ic'K2S1J6k$S%qJk"2S1J6k$S%qJk"2S1J6k$S (92'M`5IrCcQM`Sh$!`-$!`-$!`-$!`-ME2$i3J5YSjXC[DpVf[DpVf[DpVf[B3* @kIppa%J84YEH@pMMrh0bqm%fY5b%B"bBHJQBXMfm&N5$P-!e[)Bl8PqJLPdU4Ic *S4+p+a5h&Z,F@iYaELh&Z,F@iYQ'I&(ZYK["Z1lG#LmY#pEC81*MLJc*dGdj,Uh ih085SY3i#f[Rb#Z`%m!XmE*C0+f6Kp[$lcj%k!k051`R"8"RNUiR#"ci(r'$2dl e[,PF!#Q(TJL9qY@%bL8XLj*fQ0@l&5p%`dh26em230FF&!,8AYp4I@VH@)IJA$P bAaIZpdrT[Q3SjiMqZ!CFhlV`!!!!"'9((IK@dq8AUIA9'BTRGLH0ZaCbP`JcFjK YdfMlTC!!reMGjAPH9jVPJb[Di"QUeGZKV,+ljNq-`*dQS%i8i8i8i8B9mCVd23# jEB8Q"+&2H20&b!eNdkiLBc9Ii-L$j4+)$-re6NTU0XrP$E$SeU62X8V2G&lFFK5 $NGU3!!J!h'13!+C[90SXkmiXMQ5j,V3FMi9e@m9&AUL$bKTrNi0**h@D2fB4prJ F24Nc[`fq*aYl%XUD*ed!'Z[E%9`hXm*d%cdKV,LEGG%A4pb2Z4pb2Z8IiPNbqci djp,C&Al2Hm)%B&Rk8fSe2S['8L(XAT!!fAiV9!N1pa5IQ@,chXGPN!"f"iD,e6$ 6'@`1f%R'1"+JFf@L8"AFGZ'YVr"2X%q`6l"2X&EQ*1*rp#hI$qcYeCIhCDYVNhF Lk[&-GpRa9GL654(CRT[R%8j4)H()G1fk3"5PpK+S4l)$Id4M4pi[NF4i9E6$@49 4,P8YS2`lXS)+!,P4XaN,XdQA#j9AlLZ+IUP)3fZ"F14K*d8VI98C"jNVa$lB)YE VfYJ9l)iSjSBC+Jd8-VImTV6)@4b%X*J`T5J,erd2`r-K)SPBX6LIA15(1PD6NT- ipcN0cY9#FClCf5C&YV(NH&S5ch@p8eBeBeCHhRX+#mPQ)188iV&`f04h8,2$ekm 6THCRqSNKC4,l2KrXBpRG#HAeG2eJL&02JcX1M[6@1#C4-SQ84q8RK395#pXf''i TXMDL%6$r2kXbF-%5f$'JND#(hj[%C!BG@eqQ4!%)&035d[Pr5"QJdm$QYdX$'NJ 4,apMSe-ke"bElRGK20Jh4)kU6)N,-0@"+p*-PMB5c404b)D6eRlF+$dYl+AZ(&` c0!85lH0#3p,kaHh!QC'+"D`pp-Gr'aM3a9XTX0aNTqMjp93ehI(6ME[NU[&B9kZ fY-[YH%p)Lk2`H2FR%@HZ!"G(!53qah"'55YjQU#mGF-b&Q[1ZjIk2VaQ6DR3TES !V(UTLYKiURqh,J+-8mf-QCaDHla!4Ed-!A@b'Y`IZ$J&Njrbp0)*%i8#eNEYhlL eKQQLa$acZcrM1U+e!Pf[eIUqhc2q)iG5,iqCc1Cc1Cc1Cc1Cc1C-U`m#f[Vh0MT 'Y3A,IrprqLPPGrjkM3URNar,Y9UY9UY9PkY#U$1%-U6JCEAdMT(51NG)jG)@C'2 8R8RI&2A`rZ,F@iYaELh&Z,ELmD686T(6fD,,5e"*%PTM!,qZ4rELF`!f-k@0Z2Q $XqIC6Qh2LN1+3iT$LN1+3iT$LA+jURr9"jbrHXl99Q'1l-1(VhQ`'(,iH[Kkq(V iH[Kkq(ViJ-rf[qT8%Nr!qRfa"FQU*T+K)F#FR5e"4e-CY5mre+r!$!#+8P+Z"r+ cb#fSRh2XZUUUUUUUUUUUTBie"bilpqrI[hlpqrI[FT!!Jj!!SqF@,-i525Y'3'F f+@4P!%55%fSEFq[r,Cem@"J!!!!0EICTrAkraf4b#(B3D$,!Z2!E2YihqA`M,JJ bH!0em1H-cEM3"%2$*+3hG4e-pJDVReS$A)e#2-(QS&'`,VLlGe[#rNLi#KBMJ66 GNFKq2L"`MqkUk''PZfhb9JVE[1@ER!rm[@9XL#9L3DMlpE!N&!!!!!"eF3E'prI K23MZPh0m8&l3KS-)!hT"!qAbldK2H(h-!@,i`2,3dqSLITaPeD[TNd51J**"eR8 %#2IjLBj"ek28F)iUPEE)8S2Lf8!)9Lq%JiMSVe&(SA*E6E@"8D"6bqe&1E$jlKG eaRM5SBq+pE@'&KfY@`PAK048NT!!P2Am852YBAq9e5l-ADdL"AFPh[BED2a3(q1 jrDHZH@FI`$iX%#l+EqYpL-JZNS0Z5555554M$+))("8[%jch([jhcZP&6cTcVD1 !#EE0jlM[b4N[+cN"5Fi`rc[J"8DX@dZ"h&[f8b-dP1,6`f,CN!##Jfj*****)"b +0Nf4UFVk$SkB*l$IkI88Y'Fi5H9I,0(`@+T+XMiRl3"eR)HKA`fPm93GK-((ENh 'b3XU"KN5fZDi+UL*Sf6KpUC,r5CMbfj*******&rk40UEDpT5`2%JJe$CJ5'b$# 6prRkqiPhl25ZXJBkq1BD'$5J$EDM-aBXPXE05iB,f%A29EpQka-LJ'c6hIf0mjY BQIQAeaa#a(Yi,2LBFTd&bT4!MC!!#NL@BDM8a$frQ1Y`@pL0IUbldYj$J"'LcDP DPp@3!1i*'6!"f[fN2T+pkdAZ3',"Vf@m*YQm%R&TDQkZfc!h2cah,Z'iT)8Y3XB DHXIdf-K*N30X3$0,djj@P6pF(605raSePp'B6Pc0pS20%[Dm-'3'DX1*aSUlMdG (e`@Vb%jdM2B#PBkh!I`8`*Yjd4R*D-'b[B4$*qHhrAChD)Ah#P@5rB%13KTcVKi $UV`eL'I(l`Npk+ppGa4,PdYe(ac2!ZU2QFe+V%#YXT-M!4K%3klfA3q3!0[Nf2X HH9H#F%a[HM&EX(pQ,GRMCl+EilGi+Z8Yrcllb&LM5lG,GVSlR9)kq,`8X#@E*8R bIKq6UN5pYd6"5ZD8mAAkL1$4&,hIR95D!jP!KKLBqU'aZKfK,mBdT+@P1%TqfBr qVIN&Di9Vhm@4N!!EZ[Be%Y9'12`EAc5XYE&A*Na-`1QkNHMd'kDPCR)jS'ZdiF` rHQcJHBU,j#IVUQT8ajbrHXl99Q'1l-1(VhQ`'(,iH[Kkq(ViH[Kkq(ViIMj`E-R HZpaG[a*U%cH04U04X,LiZ9qQJirrIiCE1`[$bTcS!+r(0"%iXEXJe50!rid5MA2 T%BN!08+GreZX!0KN-KN-KN-KP`)[Y5@EpD-0TMTjmcLcfpfpfpfpfpfpfHZA"%` lLfD-81'chHhZhZhZhZhZhZhZd3'@Q'AdDPBQVfQYM*LL#dPT,5@NY*D5dPT4mS1 L3q(ZMReDBr`[$pZZpp@fPpZippYappZi0pZiRr$C@qh6Rq&Y6kUDJq(@)(3q8(3 iI$h4hfk3!0pYXIYf%rEd8r`h&Re94r`fYrKd)Im'fepZR9pYJAfe&"m1U3%I&(b ")q6GAIEUhr#hIfkdrYh"rKZEr#m2q'cAm0fpqhBApZNhm+h[YUf2NSciQ4&rfTY e%,m$U!4AITVr"Di)Zc"CDhhHP`5*#pijhMRH1KGaH"p9[i*Zrh)&6VYb*mlqfZR mka4YjCR`E(5%J("a@kr#LA'BChP3eLl`!L,)MNAZj)NBHrYhCEbl9!e*$(c3231 [iP`5FX!GHq('DCqhN`23MbE*i5pk*i*5+5`0ZQe@rR,$fK14eT3-l&9pR4'B`(q 9-L9!1C39m@ciH#E09MME&bm&1aGT(GFL@6&da1!E44k13Im4q`2Lhh5%KkIlBI# S43e[LD*p9V&&VX0*3l&`d06EMdk*l)B'`-5F`Xm)Bi!iIfE5[r0bjV8Ti`cT5b" 3DF4@pm#DkpQPG!G`-dcQ0)-`5hjAm4FBP12@Jd`Pp&JrheMSR9BGj201TFE'm$l acKa%ZaZ4b@Hh,1RLZJMD#a(cBr9N41[caC!!8SaS(NTXXCG&rhaCL2h$`5S%9EI U-pbFqX$d`+M@eqN(55q-[LHS80l4#eKcAeVR5T5[Ab#U`i`8A&%ZJmNI5ib3!1T Eb0*()3DbbD(f$+8beLTU(bFh`k&HLiSV#EYTm'fkCXUURT4+brelh18aBci5E[6 AC3M09)V"X',rIA4VM%fSbh(YNRE%fSMh4)4fM%rPDTXEYU"'mf4bQZ1Cf`VKYrb qM[F0@Ycb,JCqde8*@G%%N!"iR58rq&,&$rV&fTC15"29Y8Yl@&)p3)Mr@X2IHcX QUMa5Ib[2cJ9rl95(-%5Y1CiR$8hAm&#P)fqNH5PBMRk-MUAlNA5,#hMh0#(j&QE H6"4BpKZCSI'p-ji,Sp!pi*V"FbP'344hFX3K-k+p6@qm*fRH!1H8H#XV65M$cBP GmiqXmL$V5eKlmB`M!e!JX1b8kFl+`hK,PP'S'8KGXmX0KiU+ShXU5%S"pqY+Alc GEL1Y'@IH')i1Ue(NNJD"(43"D53Vic2NJ2(&0CPPQUEdBi85rclYCi"(`e'%Ihq Nl3lDBH0(V@b8V$)J(LGDfe*pFU16KFFTIa8M8ked[FFa2jYA[q&GPb1cBc,jNQ` IQIUY[FP6BJPrq)MX0VAr)qB[(4Si*4QGLq$EhL,,C43)%Ma&m2(aA44N@MY5d&L @"--(a)XlG!3Q*9FBLJkN5J)YjbQ4SLS"iEj4k1Hhr%CKMh@&MdqMQlPh(E*Y(UC E4602[5i1L(rI9HGqXDR-1l3(PfdIFLJdiPkN304ZL3-,XM66c3$!5TYNTD8V1@" Nh0Na!kmrp884Nm@BdD*I&Se'(@$1MALQ!99M9LFbA',rC"K0%V"29kGG5#cj+*Q M"p#46($38ijMEY,HlEd3rSVC4c%jDi8eTeKP!2"!EL2(`2p([p(#rH9RR80@,cH Ed%HBMJ2LFreMqppLC)[THikla8m6E4#[jZXKTV![F265S`h2F&RlhM()G!iR[`T ml%G'Q)''EI1qh`Z,eBbI!cJpE@Z0+UVJHK326ri3R"A%81BaZG6QG,Q'[!J[Er* "IMRATJ"m4FHk4CLBXl6C@0*p`8p#fhppiQ1NPAUV@LrHJiblZk1P%ImShaFA$#4 RjeLf0`HCI["#e(kdk60,K5C0R-@&%2QKD8+l#NK0ZV4BD@f(jU9lfT+c)f@Z$X[ I9e!6Kj&f6P8lG,`mC2aBZXaGl*dCaSFhbeeBSrRp#"!c+H`Y`hk,XCDfri!(M,8 jJGklaXc59hNE&Rim00[RBBq'V9)$G@00YD!P$'pNLTPd3T'-(Mk$ehr&DKAJ0if C5jhdk@K8&9YmRke!*rG,hZQ6#KTQIXKDTCJK&`A"Pk6!JAZlbqAJqjF@8UM,6mV M*p`6Tf"$5XReiiB'NL*T2IYf`,db5j4Ba0T,B4k8[XiQkIpY9eM)P#r+,TC+U(l 2"f5-@[k**am0&%SI4T*ZjKZCiRHFCNB8FHQcp4p2@'lXTBqp*P@K#4fdAF298f2 -1p-DYGrVK-$a(GkqLT`X(``I%pP5eG0&[EZpC@dG@IFFRLL!I%c'cA"`6`S@Q&R &fL-d!23)E$@h5Bp,Q*ZrAaR)pNHTrMphd["mEh6QH&`JCcLHL"%lTrlTiRjLh'V hX0(c4rA[M,p0&c,%AD9diEec1(r4C*!!DD'Il`Y,AGj[k!cAXrkNB'iBMp$$()# 0qr3NImVRKk!,DL$"#6aT4#)$B6"kpTjdcpmE$mN'K$fIeh9QCE1FT2LNc!C6PbQ q[UrUX4IZNeBY9%4b#8m,E$&B-)%qKV1Q(I�FCE*h'Cp,1VG*U6D"1S,*I*JCE T$DRkj5@QL$8M!8j4fVBM,I"!Fb)2p,$bpf+H%FVcfk&'1biYh6#Fk(*GVYRGq6S mrRB,fCrKY)Slm4*m4r2Tahl,Yr5M)C!!-EkZ4N8)hIXPFqFm0RN@L96ME-fX%2N LDeR8UfLEC6bDb&2SfTX%hcaXEeHbpdYQQ&elQL@#r!%&i-BVQ$CqDT%a**NZZZ5 @(93N3kC)Q@Ll"$hJ[@M!UCPe,08VrKaa+5BKI`5,m&QFeFj98XZk,0CQAj(dEpM r4XKU5rF)cK4F&hRE3!32I9([B`r95XaKPDm(cN2pQ2jQPh'Pk'+5+C!!hLYJl)( +qpkJ+F@B(1Gl4AEdPZMS)T,Y,4S+i(eCAkFUHjr1LCCeFhBj!%acRF2-*[T%)!f 63VU#%LbdXZPl#i2ZETR4BI&d0T-ph*El0*0[)X5-qqp'Cr6P"S4mLrehTZV1S4Y e&D6Bh@J(bh,N8G*([TVf0#h1*`AjUbTrM6c&,kir4b4iaUP2X('!c9q1!A+U!k- '21H$@bCMP%[`ZA@ZSF'UL'V[lCNVhRdVY((X`3-%lDeqpU+r5'%Yeip4rR'-%4[ Q!aYMh63q&RHTj-KXdPiBSi*VVBdEASc"09!JJEM0XP)S$6kP"KdBNMq'J4eMM2@ `0jd[IM`1)I[Gp5,DY*hl&6$5X,(jqKeI9Ldl3*l+[aCqLCR6dRaR`FDG666[BZB I22p&-I(FFA@`afG$Ne*bqkfeUZSSc6-I!X8(-f!F9&pbic1GA(fe-T5XkYP6ATA G!c0H+Jr@l5pp-c$!-AaR,BqHPCkU',&q@#9a$l8h`&*2[,rUH**QHPdB"*a1`j4 K@@Y*fJqBG+IbFN5jHV[Qp)TKX99qrb+cXPb0HRQ[4J2#b4$K(&Zd61-0bcbIp$- 8""GAQH`C$AS&FJV23KiC6BDQ1ZP$2!52"T@*k$8IPIp9L&M3Xm5fM$X&0el$j@* HpNjiU0JD*DN!k2VXZ+RQJ1A"I0H@5DErAmVLLkMlS520+Y'$a!Ui0,-`(52U8IZ +J*Mq6%AXBRGM-aE#NSef+3I!dZ"USG3FVq+Lm$VaNT2bUkXEq`cINhH-jS"$*EV UiCRZFcS*N3i0LYpB1%#%$5FkcIdT1p*KmT1$cKcdjKHLYQVA5A9')kVfCUN5p+c ZLcC1dc*Q&C*+iSXTN5)I0S`,aA5c)bmAlXC$U"*T"ENErIX0ZhL*k2iP'UT5Tj! !,LbEDqFJdk'pa(F%"TKZ8S#!8ZA-kNSiHKk0SC(kqqDplqLce%(i1'MERlFI"Ec F&+8*5""DjEECYKl(*,*1(P8cTqImH@MNC6G2r`"I0rbV2rGQPP@cI%f(MAVmRHN qcmb')`16XN8NK2"XYYrA-k66rd'"k[clS+3ZA1,d,VK(MKrYApH[mRSl5X@SPT* "qee'k(NB+"I12(C#H8pQSNI3[S!b5"SPLfVU[![Td)DUfe8dESFMe`6k!RSU(il #')P[*9(ckd4#q&rCUM#Vd,TTZ2VGMJfAK4h&p%d*1S)$KI129lD66MA5Y#1ljVC 6P85&[(Q-EfPVqi@3!&,RLI$!(+aU'[[KRm2HdX!@#9L`1SX(,KAVr+(!c9jS-VU P%FT,)Q8iPf(54PK)DeTY6VFSK-hbK,!lR%SlklqG@TqK'jJlm`jU+(TQ#jJmilT 9XF*D,096(R2ATVQYSETHpi)UZ%+%Gc,RC40kl[#UAJ(5VG"p6iY"13[qrXSqb!* eDhqP)k&"$!1,+B5hh'+,D4LG)%9466HUY$*X`IBIhq,ANJIE-&AerPZNUGTi8B1 i9GU4Gqb,*L6a0[4lT*FCFSh(lF)C'@-mSJ4l(pT*89db5!Ur6m(K-9UUJAPFUm4 *8&0q`lKaC'BQr'r8$)&ibHA$V8+,6TT%UiaC!(a+%%I&9,[r+Mhc,JQL0iUFBPN kE&MG`$MGI2Ii"E`f&#PcQUklJDM!!FbI(-dMX!Gf5#jTdPJjNpG)3YaU@N,d13c R0"RDFcF(N!#[h3eebU((b*SBYAkqAccYBKiZK"+d"V81VESpND%c(!j(K6N'm*4 BBr%a'fB33F!Y)Ll3IeK2G"p!VpGLp5"#1fLq@j3SlQ[6pFFAPED0#%ZaaXRE[iU k,Z3Y8E%QjqZ+`)LGm)V2VK'%j")EYk6'V-fBh0hS-Tm!1@54Zj`G1Q%8Y4+j@CD pb,i`Ree[@L0(la04'0(RG+QVCD$+peN"i4E105ZLmIi9)#"NHb2,H!i9,SdHK16 RhiacT4KiX#faSfHSB%d(UP%!Y3q3!)fj1ckh-2hZUBcarI3iY+fC&AAh@rL'MfF IE3hQ`mGH$,M2qV$Y0h-lq,+h@%Dp84mmfaXMHFIVUXLZ&HQTljh!JR!a$(DUiUA C!HRZreC`,F)drBP+Z+mYZ(#2)c)AV&rS69KPGm-mBMRm60YZ%D2IGf'lrZBDN[T 1lDT2j'`eC(iEh"Mk',5X,NPM3PF3C0R5[Rdi*dN@5MVEKPR"8N%@JXrbf!BGq#S "kXKY8HG$`RhZ+9NmbTUih33HkGdk-340)NfNTjI&mr+ApK@NDN6i1KQ9p@m4!2B DA@`P@Tbf@61ZTUCDBTjT*%RErediJ64')CJRJ+3Se(E3qDX#HX'42Y#hi"*D@lM H0qk09-G5S6`@K6PL%33J'j+KH#l3%48lJiT-fGeQ#`C@@NTFlE)G(VjLQ0hli6M 61*`hrC*c-Z$BrIFb%$GRRZ6HP--8EkI!iC3H82)LHFN+FF9RB6a'JmIC(`+AV*3 b(RUlLCk)9bLRjeDj+-820)X8pS-8FiXBaQT'NmE9@fp[MLKDHiZldi`d8!-IDpA 9b#!KJ+DhB#c%6Z%N,F"R3fA8FQ'q*5fiZi%2KRp5YlDTr`X@)`V1jB14!6,!!)X m+2dIedFj`JTV@+9``qJBq+ZBUeHpU2+UcGYL!FhNG45l#V6Ha2B0m6EGe"'e-dH FbZBl,eJMjGrQ)HbJZ+jT1)EVFXN8[*ljZFk#9$"k!+BIdMS&Q+Er#jiD8bh*eQ8 (dPqBb%90cQBcIac60R43rQA)Q)BG"LXK5-G-r`GBiVH8qHGAd`pf)D-)6LQ3!%a [JD"CERre'PIe6XL4k4r[GNY4-#KTL%ZpdCQVCaNTK+pfUm#c%llL[0YJ%UrX4FR NfkSlS+bQYJ%ikSSAlR2beMYJ[1"VTZMPram4N!#3!+kE1`-S6FPG95DrA*-aU@A l3`'UT"0Um5AcI"p5,lPeS`V&pFGc!LP1%FbCk$F&&lPi-BbMhirCGp3Ci6H"`'j 9QVkCjZM$Dd4'J[ej`Kcj*9$`95aDSBNLIII"89IXI3DREZ9kYcZI#TTIr)DT4T! !R"d8CQ%4K65Qp90I#PTZHU(*i)I+P0T[Are9efhldEK#[[R,pHHj1bY0cNE(+G( QAVbqm)'p(#M[Hi-heNmNI&ic6Vh`BUpm5kE6e"qKUDLhDI&mk(ekm0lJ9hB'#0@ IjRcr*""5lBR8N!$,0`95dZ@,V!TPlF!!`jK#qTU!M4K$iAhk8l@riM--Hk`XHRd Fl+efpReU9NP'd*!!VebH#K,TSq'AKG8h8p(b04IkHr%"1E$pT4'papSr%MLjq*N 2fT[6M4L*#lP[(PA#pqGF"@@hiiGZ!!BF[Kkq(ViFMUU8h89Jaa%+"U%FD$C6VCU id5eDlFec[p&19VPp3$!Y#$Zc,VEE3(q*#6ir2[1m*94`QHH$ep5kV"6*#G3!h9i a3&k9k1V[&$HpG%Ji'EF[S6"9md[9D8ENj#jQkV'NT41QA)Q)$GZ4k9fc!81C2#G b*0E`8Ar#+[NeRmb9%GX6cZ(IpQHCVU5BbN-V6F1E'LiTh[Q-GfYfUlEk6TPT3U0 *10B42L4HZ#MFcc'(kTr!9,5X&'5+PNpII[h01%k#`$M)T0GN-&5`Ir0Yj[k#"9T EXKkaaZ[Sre4p[G#PAja6&L$+NYGP"X6,Xd8G#5VZhQ*3BX0ql2laY2b3!,TEK6M TYq[@TKV0f6@C5I)YX*NASaq*D!*@M9ICNH4I[B1JH0KSrc$jAHrN0qm[9[S+Z8K eT1@N2be$QV,BK,aL@068F9FYrb129JK2GLbrUR5*BQNJ#E8m8!1[3d"aidq[&hp 66,+8R*GjVTX)Gd19fLf#&jf5ff3TI+3hQXmG4SkNb'j03BT1e`E0"kG%qZE%UZq U9$fe8#Rj+j8VNSPjVPMmE'61R-YRpj!!5RVq9k&S)Hb`'aI8EmqNclDi%)kJYj8 dTT9MRpN1AjhY*-%,2E0eARS-lDqKI%IC5Kj4Q0UjNd3bThfU4,DdY)hFAqdH6#m -*qF-3i(S2KTmE'`"RUadX,20aYK5[E$0&b#"3Q-$@,B9P5)2hf$FQr@F-Yrf9qc peR!BNJ&N02-d3&(UcXLRrK[&Q6$I[pl0E!qSBK',V-JHYV3Z%T[VNL634Y)db24 pCZcK"G*h2Al4GbYLdi*Kd)P,aJ4r@6GRq-0a#iYCDLT#UcbSlR#"M8h3T-'k&D# LQ(5`V!C&`98Q8fc4cHK%j$4NLPRLJa)#Z+,p003hU&qF65MQU)K*0jPmlq3eS&) hR0STq[Sl,[-R)0c'eDaI1GlU(rIj@3eQi,"S)GG[VC!!H#!$qTd0RHYLRBdfpaJ ikYHi,H9AVXjb(Y,C#1fS5-82R4T4H+jllPfI1&5"EbhIiTrJfI2Af$i$NQr4U1, !U#Uqra%8'"T-4BcXTI"G4m8YJZfNVV,!!e6ihlkTCGX"HhX+AI$EJeTGif*-U`X d@j%ESXG+dD[FG0N(Dr6Y+4cKQpm23d(A"Ue@ke'&q-C%&AIU4UrpIM5,B9$KEi@ ,$q[0JE',&GFC4Zj8+UGhRY,-pHXU`*2@Q9HpS22,IT!!(M!M)B%C$$DMrL8[[45 P'$2-`JL,)pCe59crC[0acI&2rbeKU[m3b9cY2f-jr`mk)eFQblGc#9JHIi6k+L[ (RU+#FJJX![d!8MERdH'-,()apP&i*aYfL%rRSS"C-2m(V(GZhdq-Ykeq3f(YpJD Y*Yc[)14b@mc[NHC!4%'1Jbl)$r9X-eE2-lqk+*3-r@!VZcJN-aZNpr)3Gr)Q&Aj G`TQ5fM%I3"`5@"&Dbi(PZJ-AUKKeN!#$(2IMJ4R4M#a`R@!`LiI)QAi4Fbl3FY8 H#CA$F*Q%'QQB86#93jU6Jd93diDDZl(+R(8G-bca*A!#bU4D*ZPQq+S`DL-e[m+ [26+CIcdN-,a&a9M$U!1*ac!QQFJ[19M9G+`Mk$aENH%&'l[dSH#B""c625$)G#1 `XcpNXI))[4(LH``"JJU6e(YYk"4CaHJ&%@*K0d$YlPcdR'Gj8M#USBSNK2990@C C@0TU1388ePDM0EKmMKqA!fL2)daESYVU[c2*UUbCD"3V#q8iq*I"kTiZbfCAMpk ac06-G9(j`hXN8-CF**9P%H9%VlEh,4JQQI-2`#kL+QdIZPB!m4q`ZK+,b)X$-1J LEG%lI-+UITk4d@H#)XU*bJQTX,HdrF$0VGTBf@d$63[F8fCTfkqRiJMp5)iY%JT e%VKjZ*cNSV&D'NjIkr,S2V+,KP*+p)(jL6NNRJR-UViX#j&9H%Uj3D-,j%Y[QrX ZXYb-[S"lrY&*EJ,q1kH`ZrM!I$)L+E[NhKSU$kdjL05Y2VrXpqc@qN,C-,e)lH- KIhaEPTkZC[Zh$FGca#K2TJimKpK&rC@YlmPHD0&aT[PmD5ljdZT"lLmX&MC1"+A A)TFcNSP0jr12Y8$h0rCSG,")bY)FZQ,NrH&UMCej+!!F5iJL,cS,kX[56,rCS$[ %6l&&ll8r'cV-a#j-BHXjAA%)e&HpifQH8N(dA6qE40bAHE*Vrf*dc($-+-4AU0[ T8qZ[p@bbV-"qei(3dAB,J4*f[R+4iBSfK,6%'mQ2h'4hV8&EcKTrQq#RKY'6,PP L#f5,G!b(G'9%#L,hPE@5BIRfND2aS(RQSS4l5K$PIje5U8ddQ5Faie,iQ8J$[!h r!h"Qe+!(R(6L)c#m5A0qpA&XEQh,Pri`UB(IM2I0TPc8BkRVBcXS*3GDN!$NVLb 5*r*HjC[CNf-a&#F'Ym[I(!eNMSeF(RkTr)Mb*j!!*rS-eh1618Cjqa@TKJcA09V iM)+Ji4-QVp#qX2N+A5Cq3HB`CTc0bUi(+SFRLAE$`jTUf(HK)Fd'jSK`C%1FHhp *pCBj!cfej%)cJTQHedXhUa3C%rF#NBGI+k$d0Fm@ZJCAVNh41!$ep!98Ld&HG[H "@h'--0@G0,2+be,CIaYrX)FGLdXbDI08L+-b#EQNJ&,8@HPc#!@3!,0E4ieFj0L E#LM*CD6#M)`1E`Ufh[+LZ60f'"E1Edacp+q!Ji-[@@NS%)3EF1)p#aPl%1,4m8* q(X,'k,RG*4*#@Lq[[iX@pUmB!cLSC#4NA#m-48&k2'McZ8Q+DP#K#Y$-8+,B60d ar&#`(VlKNEqVLJ'iI(hFCMV8&M$V,kB'J"![3a([-*aDQCRCdj*@pCN`hp3Xi5* PcI*BhTJe#jrbDEJ40KPSd6NcR3R9"#Zcq#`dGjm84i9Pj-J9dU&5$Ufh9'#T)&Y fF$@F!1E0jFlSVAe"-,`('%$HmjM2N!!KI*!!3TQ[(mKFXkrEG-,qi6E#0Grmkkd 8322aShMUmb0,+#6KDc55AQJaNrU!,YS!['e3KU&BZKMHUAK9@$l2b382SB)46eP !hpSPITrV1X5H5rcPVbE1Dera6+qj0NCNS5VP%9Cf9A8XiRMc5)V5dFANmY4Th,K RSRQ+pBd"J"KM)0ZFI9`,BhY+5hqH8hZAIr05Ip'UPZI(eA$+EEeV[-IDpYc,h0" KHEmb64QT8iUJDE["$b"ZTND[2LR&A`-!R%(DD54+NFdN3ri*`,X1p2UJeR!mF,a N-9@K#(jjkIpf0&cA#0qra$"qfQ%XBYUZ5bK48T[&A!LX!J#XIp"f`9U!'j-,PkE RfcEj08H@p4S5fEI5GQ&GL`-lJN0C,l(r%DM9lD0N-dbmf!!jiFEF5*3#jJ&!8,T HCK!92M18a%a"rbPf3DRh9-E)N!"Jjr"lX&!ll6kmpF&h4VGEh5Jr8-&GB+`F'[h VeCj&'"*"(R82b'4klZBEC5"RmfZTL%ZDl#Zaf-dfT[",G05ciTA[2,i,i91YE(F 3G0549GeRCh[K4X1&H3PkF,rr-L!!4LSBpm)3DjBMH!TmD-hKMKLZ@0qfeD2J@+# +`5MCUI'miZK,N!#biX8d(GJJERF4C65iP@f([LMLi12L'P(iSYEM-CM!0(KdI!N Pp!GA`1I-d94@(d)#p-cQS,`MMFllllDPa!N(c@B3JKbX3U[#42,aEL@q5-S["Zi KGZpRaFe!SX'h6FTqSE9,ZI-RSfBk$iU9`%!@pb+XY!Y[2I-3+%"Z"6q%KkHrm[L 0G@Zb5l1k)Z'GY(N$dJ@(X%ZJaMpM1&emlrhhNU91f+G4'aVBJ)5#0X#,EV@KcV, "&EBT9c-!2C)rYMf*LB52&Q+*m(3EK8$K0*TQ5D#Ma1ad)S)FHdb*LXhRZq`G`e# N9e+06Phl*r)LbKT6pRePd0%rFZFrk%TelA-KULACpMB#iGZ-D'`D4b*-Ta-,9jp +-Q`$1*UCB06ca"Tcr,$8Pf,b(a*DPf4&Jq@UIlMpq)4`Zfm*SUaR1)QAprhF&,D jXeYMUNRB2,U"iS@9$LCUZ51YZZ#abNDRm&8f,BX'%B(8R-S+CRJGKX&B4mRAj*F Sk0k#33bMBbZN!I)6&6K"m%6jm$5US"TNbA5`&`d58@C1GD%`$Ap+"NeRS0pSaca B6-im"Y38lEDH,5lTii4`F`"B3Q&EkABM+dE,Z$$cLPaQ35Ef1DUc80'i1,5M$3p UP-2%0'*d5!b*4J'e@PiC5+,S)5+,%0SeK8fP(3m%'D&0U01EV3d`QIP$LB!TS9F 5llCRVN!eHH'S[IM42cqVrPR5(3TT8lDX65@+EqV2JSR`3,fBf!16L,(i0)jbmYQ iJ%1d[r(TjHVKmZlc6C+E*B`GcbPaQ(UI[Z)'hCU,q*+mcG(Q0@RejH@0ffECLV) #$h6J6-d%*G)'G0cdS8JUZC98jd6-*j-2@G'dEV,220TqfcHA*IQ"V6Def3EqH*X X*j2fj*K1aT!!YJiL3P3$JPh`Bkke4l"f0"XJS+k#JEK#kYP3ZjXYX1j)eDfk5#P !0H*NR,YRZBFpG6A8q)p@r(Y3E$HX+bk+"Cj!D8[hBYAlITPT%1cd0iClJR+M'(P BMC3GVp"2PIRhkBZ6U,@b&VMhYY*3kTeH(VqqD1KK4T,Ga)V2RZjeQjEkNAVDakV L%'fFQS#Jddlk%[BhR8)@LpIJ0,QSm5jpI!!fiRDS5f6[[#&hNCVaTPc'F$&UB+K `I`!i2"2T!X6MCB,m9NQQYh)q$aEi#U1e-"-a"*e18q1*)lB6EVp2ii+A3a`L,ra RTq6GYXiN+-PbRZpiUQR,Dh[ER0%AFJXS6&aYTR!bHAUUr`e-Qa)*d1X5KeH$biL b!1KURIkI'k0Z5ZJ'b(Ahj0FqASHHa[Q06qRT[BI*Ri#-TjTpQYrlSHA10Ap+YjL 98-E2-(C"8,@LG8r`$I642$Xm8YNaP8j*lKPL#YQ9GN`QX*d1e'D@4%$+JePF"I# 1C+&mE0j#KFhX-[aG6H+H"$#2k6*'HLC$1`dA$Ti8mVKT['4!6d)IZJ"Cf[He'Q[ r#@-[SZPl'ihjQMN3bD)jbZjdlpMlMXrr!mf0V5Mq6CiX'B9'Q$iI9"6')93rIKB CL$R@)@q9KF"N1rl4r!QNpT,JA8f@R0Y$-1EeEZ3CM43*6Jb1TNlfea3XM6d-Eq2 -@ql(''A(A+aMSQ&IfdNIF95U20"PKIPH3SZ"N!"#aacN!'+2KBG6ZlLNc-H'-#I MK$aeUi$Y"+f"@4&kdjI42,P%%j!!SkVqQT5!h[X,-VE$*#IU$IK[@aMFj3dY&Bq FQ&p`hFm,$N#fS6+*l8qXP88Bi-pJS4LCcR(+dZ%,GQEh4q0r6,UrlpDF1Y'DS`Y dMGVPE1RDL,XD``S-8pc$jC(,!,59!,!+CAbqkPYSY@1bhmDUPS!UZSXHGAXYU*d (Vam'&9VMEB+XI3,3c$AXQ9TNL)6'e&VlCMY`(aGR#"4p6XCK(Br03&rQPMMTRA5 SKdd1T1)aB!4baAbX8Qe[V[B+%"EYZHH'mPS+QbD"IQCR4+4fJ4pq*24F!iX+a%P Vi9p&6I#k#-C!h$J(RM#(R4T+6CXB8eK$*-9qEpm'El8EB%ii1S%rN3a&XhXCF(" JP`,A[pIL"hea--lS8l0VG@V'@LX96@GG2(cYYPX4&CFNQ'++`Q@Rq`G!B1VkZTL 22-[+4p%AKm"`E)0cUi$8D5$UFK59X03SpHi5bjDp#3jU2JR+h$iqPL,pNrNZafj k(mUU`0Gd'qqqKCb6@$,Ykq&Ddjc!lRaUkjecZc0GFKTU[q'@-K%H#KG5E9K4,CP L#FS)4%0bT$Z2jRfI0Y-rbl#[0S%+YF%ACJXYEl[5i*%KHmG*%I@Adfr&N!!R)e% c,&2Te%IA@4',aBH(QZ@6&AcThG66bpYG2jeLMEbc2N%M"aA!hrS!!B,AYbFAca) iYrLC$aIFra%"H9T3dRk8QmiS%j93q"YKC**hmkY"@d!jEN)G5K'9(BkP#4N29+X E8dZrA)YPI96KS&&YdZ3YpM,PfQm0LNR0(ErrIRMDqpS!!!'!cUDmL,Z9p3"5`Jq e[12)4F@)[4rr3HfKBRaZHB&ElXH2N`fdE%MGF+,XP$QSl([+*eY5##"8"dU(aQ" dE0EPL3&[2HGK!T*F"jN#4Ur4'e@aK2[2'3dHffbebR`FLYf`#UMS64%H@#dYRf1 &I,U-B!JUa)ZC02aa1EI9)I5f1[9X+f)!VTm'6KNlm&-!I-p!Rdm-"&C#q*(rE`r cH"S93r#1lr9AQjB0G%e6@lf,L-pK('P)jYlSM*!!JS4P3,'5RQ$hDeY[NjUI&c, &)LMQ,VAk2$2EbXBI2b`"-KZA)S(d8#(JpG#!a8C0'al$'GaLVA!$j'8ZfKqEIQJ BVS,U&jiCa5ckPialRGX5')kTKdB1'HdBSSaY1($$9raHFl245&j!RVCRlqhF5Fr k&2M@jbFlbfe!KqQGhrJ#BPF`&[pMGG-8`pEm%IG$`ESF#F39"8(A8#eGKG@FKH! pcf!j-*8c&86kIl"&QF5NRLVCi%ke1$rIQcEYZe(9DHITPr"LG6$h+S'8JfY6'@F 3U@FTCSRKAS,EQirG*)'XP#16ND2Zi$ZL&M+AFZ'PpB$2MM&0`Cr!4XE+PAQm8#p KAiESc8-ZP0c,`k[VeH[C$4(Ib$lE@U!1FNBh5QjdZNb%8JBfV[5e)aF2-b[$A-6 &hp6k4!aNPbh"R'rf,Cr1Ir@YAVUfadcHPM[J"9m3HhJTcF"PL!YJ!(TNd%bk3(6 e9'Uk8%PHiijFqQK%m6YEj(VP9TKBJPp0FSa-`cp``i#5ipP("CXeZUbU@5JV")+ 55E'pDc[heZ(2d'ECP"@IpbGRYZ*8c#Y"84CJFhc[er#YPK)@cFNDPN`!AI6%ED+ HC1QDGfh!bX'mS%&(%l2"[F4d[d1J234J9S%A349%X*5`-)AL,#pqeqfe,C0iK+j BC8RN*!#r0jkHhckD#!mYQKlAaVeqS-%V!I"`MXi%BGb-e,M,&*C**rJ$TA$&d2m 8%c&T)BVbh3%#lR1p+k2"0'Vh5%VU%'ZlF@R,bd4'crC3X9KemQ3MH4#$N!"%P-S -1+icMk$IceS6C4+LkU,UQ%N3!)qDB3SMiR[E@eVR(rpD@(a#2CAThh+ERq"9'Yc dRc,[[p)2(M%"jP$%I'$3l3,-Y!U@3rDd[kbl`b8TE#D@J9@5aAb0MIhL"`4rThK )SN$L"jmRkCe,@1QpS8e4`EV&&S%C)J'QRCPhM-%GQZLdSX-5%PB9C`GT1Jl+X+P 9L5I02$!aVp3IB12c$Rqk8%CcT4bihZYh$[Yc%dK0q*lp@F*hkB%ia8m1m3dYfD0 lJf"NS93"k#Y3G&26[&0k*N2L`l2#Q)JGG$CXBAh5$pKK+U`VQZ$DJi5[HjN,hZA fQmQApI4Vf646D6e5)1BRLY[M3S'ih"FZ0`DP0YLYd*'"iqf)fIcYj4(UB9MYR38 IJhi(akJHT%'V,kS(faAGhXJ2iedl&!A9TI2!CF6,kZaNDNQpap@c,kND`IUfHM9 lhYpK[AQrV`(K(KGR5'jiZ9X&)d#M`"r0cMXbejId+)H!m*pHqXG9b2l'EPLP&D5 2+$3LCbqZ8C-leFGU+0e$8!'AkDF*b2,MCM-$X'+c83I!ce55AbTVGC*X["q&00$ BU)U,Tfl%i&&YMTM8Gm3f[AkKD`e9)6Y+K`"'+-F(1S[$XQpp@Ril(Z$*943I!D$ mD(+h5NNm%MIja8j%0Bq90%AH5k#9&amP!A&e-8diA+6q2DSp9jF#2#XKDL9r1$A TaPE,-rD6i[HbL@EXNEGDp%+LJXbl&k`HiFSR0H'(fNaQJ#L"k5rT")C5dehX3U, p)Y`16#Fr-liPI14")RMGK5PA([8-cCQXkJAqHaRZDd@JEp'3!2%d@%lrHS3PXhK d$NE1'CK5`E*0,@b`[M#)(VS"M3cj%(%LrT!!)h83db84h0ER#*qSr#944beUIpj kMQbj!%Sj!50aK,b`f5`G85ldhaG2UB)H,D6ADb@jI4EdK46C@PApda*2%V`IQZ' 5kbVjaqE9-Jc24VA(LGi`hr&NMH`-'fYH-D9"3AT4T&53!'EPilrMNA5%pl@'fmd SRrf8biXm*@"X$0#%5'"09L`I23dqlf&Kh&rhSF3ZMS$Ah0TbTjmJc2#DQGB+HGm EA-F`,2VZJmC'c60h92FNl[H%P49h[)@pSIEGNM(Z+MfN6P%Z$FEG-5"[kq+03J# kN[IRJ"FL1Fh$K#)S'"`1!JQUDa!XLXZEV`EUml#jqZ0q8Zh*!IiX$1U!VlAT%5B Ha+!f%hYkcZ8#jSPrpEqV`MC8EA'@j*X`MDQ3!1,V2'aSP1!QR$3'1k6%'V2*(jL i!f-%PL[,#BbkcA`ZrcDq*8"ZTV60MXbN439Qh-1NMEX-PQXr8[+&&Zjj0YI0@h3 HP['[Q$rG@k92bE`!4Hip)%!IE+5p`Fm`@abrI9YG)Z,pHh+f0m%[)i#8Te,8)0F 08D+V[AVT24eRG(fqI+0K88A'fZCA9kl(qhj8ULGSY,b-1fC+cQ)KMC4YX2J1U0U RN!"GE20$+TLQ"UAp5'T5hDA[Mr"+bT5X&0UVLG36EAP-Sd(FFb[TD6mKkqRQk"` l+Cp0DQ#H-TkTCMl!2F`(Adp%SUHIUH!8&HT"`a-Fh9EG&LB9-JHZbPSqPqq[#(K )l!9!la``S3VTp)Q',D5(0R,jZ+II3Xe15Z",i8l$b5C8Z0[@H`cR!ML3!$DZ'L6 %H*J`FB#rbC0J`)5L8CTJ@8,Y'X3#2r'+DV,)9Da&ZEbp[K%iDJUGXK*4[M'V@8E !M8ShRc'0@2#U2#U2#UFmVTN+(AjYi)JThUMPm*%)+@HI,4),H&[8SkDDX96J&!` 6"GETR"*i`%j4RQ(%9ajGZA4LJKQqq)'d4,E0me$b8GT,92h'!`k1FU(*CVdLpr% !'h[iakDCMaJ3p0-ai`)HQQBmB%26X5P`$'lZKi[LY+X5%k@rEpZ6EJKL'*c2Y85 ci2-QppQ5P9BKEBUekCfI!U$8FS$#RrIe%13UKij)'rFZ16"Z4+QPES[p-!##B)A jf4JfU*[F2Nd`3ljNED%R`l%'&4ji%LVFX6DdJJ8aKRh'l5U2*ilPYV!FS[@qcrF mlD9Z)NC6j)59ZF,N2Qhkj5VlQZQSP6XMZG"8fPpJ&dHASCcC8rkAjD3V1eCJ2Jk D$p-pU3XI8)a)-M)fKLMBC5*MYjP$hcSRSd"h3h10[SRkqkkhG#NcPM`*'V@bmRF 6iHADV5HFlJ%i6IL0+Vd65rX63NS0dQD@BPL)bfHj)$3%PMa4FR-*@RmrRXNi+Z6 5940I[FQ*CdPK&PYX@aJMiKli%UZUK1`[mG#C+i+ET`LjNFKDc6a@K*elKZbjN!" 12@Q9RAm-@,RRc[Hp@-pM#-cQLKjHX5ipLCdMJ0Fcdrm5"$qNcdhTVVm+!#!f@(h 0%GFeFH@-@0kj&ilk8(2KNPFILX!%*6kqGcN#Pef,@mVpR2'm4&d@2UY&SV9qG-9 ,U10AcPa&,1(aCUdL6RpI*&9fdPR,MVfJF4,ij+X%ZJ[%%,HS[SJf$DKpL5Khek$ "2qQ#CcLq**M&'$![Xh*pe%bE*3lj!Dj!Q8Q@LRrM,eT+c%kT#56i54(LLqba8XM `*cS3)[YZfLlMM`9M6L@UB0U9re0hNF%XL*Kq"@CI0k))!$mK5R3`iGKcN[0)5b` lPYdQ)lSKf38-5rm4,cbf-233&D"!3c+c,``"K1LU)LRLZ-+h+5NI+Sl!k-f2'NP @R4!rU6rYLNHMb@Qj)"(D$2X'0i8eQlkbm%lG[XHjD314EiRQ*pI'[`"[`K2d+4[ #$%c*D,kV@$h#@TS)[hX@RcY33&e83Y,i'h4I*UF,MFqHS(r94+UrRR&9qQiiQqT TJ)1(K-U&6KH(lc'YN!#m(!`PCFFCd4eMLFqXNYIHc5eF"rlFa)I,F6PJ)ZCAB*i *53`Z4F,5lT,A*$pP(hjmam)1#X#U#jDV2mr!0Xl,8PFX"j-(3D"Zd#Dkj8TVkRb I'l$i$RBbAccK6Z$aG8"kFC4jaJEkI!If@*)HH@(eM$P0f8'fEpj[cbEHh(TQ`,m BTTSP,he-#-KH&(H&Iha!Hcm,J'hf-TJc"@jN94Kb9EFHeMVEr*`22%Q2q9XHBh" !a4r9f0"+-Y$A%&%(mVMjAY6#!MH%$r"I0'5afaMdqHf%H@f@l`(X*IpZCXUEh2b [TVS(aq54RrcPj%3&,+Vm&l(#!cR1ik$$Vbq9ji2-19R"a-%"rc92F2XYD$,)kMq +9eDrN!!Hah5DLPS1'V(6SU%3P&M5`eM1ISr!lmM4-6D8'Q5%E#0l-)rTDBEH4f1 V-$1-c"RLB6@N&l+'*5j3)EjKUi10N!#GSjfAmA$c`ijHR!*X[Ibl#I"1Xb2S`PJ 0)hBmmX6!bpqr6j11ed8"`"V*%+FK8XMI68AGV#PlClbfJae59k-R)m9Pd4KjN!! 'b8C!V&"**KbCbl!5aITP&bG0iYhVi''03BR*H!T02hBc3RIKD%@UIY3FKbh+Rm! NeJV'fZjbiRS'jc'%A0CL+,)%pC!!+Y$LY`[imFJC,9r#&1HDHa5Z`U@j1dDlI`2 C'6[6ADm"RIaDhXCa!9aGHbCcKkimPe4FUJa,c1I$cm+1AQ-42HELNG+Q,V$6*G2 55)5mQ-YDL1FLPpC"ffJE8C`U5J6e$Y4Di!`QI$f&S!`GNi+HPiHp+4GPAe4,H&G )($ePU,8ImBAja5)0e81)LP+"Gq,"9H$Cl39QriE"+LB"P[#qQa4fTCbqH'pSX*! !1F!&cparT6d1+akd*UR(G$QLJQ`mI)hqfGAGd@%b`&BGbi5Yf)&AHSiaNCk!-+* Jd)0[apYq9,dcd2)Z$+mkLD+e3[9NjE'PMDX%dm)`43F%m+"XT9lcJ1[Pj"b$0j[ rFQk4eleK9hbNFlEC$h["R*k+$I@0[8)`#*Qkm1Cc!H9Qk"3mf65,4b%P"9GKiqS K,Rm0j*&3e6K(G@l2ClkJiVH95&)iKjjN9YX%MRf&X1Fd#mDD4G+#6JI3BBqT`3F M'CRi-ZNf1GpFJH1lUiKRXkXq@ZDLYiK5RHPU*%*HBRj)afp`*+d&p!I5$6#f(hX UjGlST6caJ,*,S'*fh*fDL8jb&F$#@9lbkNJQbM1$rY5-),'bL"Z`MqZ1@bMTE4Q j@r!!r-VhkF(@cBI'bcRHATpiE*D#bXP+dXKCL6'KCBEf%cU"C+TM2C'AP5lRN!" ahhl2Xqfaf*!!cVDe,)Yh#!9eCTd1#UKH#C!!rb9pPP!0N!!AN!$&#$)a"cp$"'+ 04(FThb`NB1b&LLU`Y&l%L0FlP$MaSRYhGI!Sq#kM4Kc&@f0pdPrAb$SAR5PC3NS 8Z'd*e'kYj&JhMX$')"I3-U&j8%58Al@F""$82*56-)Rb`T-!ZHI1QHK0+U-iV+6 bJYiR0beLXdQL@'CIf)"TaVQ&RVl6K'SF1c@c+JhaLcmRI9$J'iRNRdUfdP2TE$Y XBMH)J41i8%F@P%3BqNYIjhNV908Ncdp200Y*[N`X*0+$raLrHYLDrRab'c0*Q`k -PqdTSeDBkH'M-$8+Q9Gb9@!'`1jN635QIH9fYDM9MYm&mSCIrhrcdQ$0E+kjYVh lA!Y8(i,-aA`M3-PGFM@S-qmlbZ6Q@a@5LJ50aSRr+)T(-451BLNFa&)jLDdeHMr rIq2cB$#3!*IrHQ0a"r+2N!!XqIUjVkY`[fkCrYhBRcqQlp[6Aqh9l[Yk(llHUMI YhDrEY*r#kjp9F4mPLKm)R+2N#6jqV@rEZrpEShqhIMp[BEqhTc[Ue+llGr[iGIp rKd"Afl2AffTIEA%I2DB2K%iVkJ@qV86IYhUrESjqhFhp[6lqhTQrEV4r`h'rKeM lpZj2lGGri@KIE9ep5f$iQ4&XIkTpH[hJKR(pIPM8AQNT3`LhdfA$I+4%d*l-`"P GdPfkh&)`!"c9`B$i)ULm%He0$e5lIcI[lDkIcV&'hPQI)(51NF9J@j!!6c"fMF2 T!PY)R5PfH[4Gp`Mpp1XVL2dQ&2M6DNaMG&q@)K*M"6If,mc6&qk`UfGT3A%M+Tr lK")a[VAeJ0-TPaEMY0542CmLQMAe9*qjaG`R3!)SP)me&jA'F[QAP1PS4#l+-0k BNM8PA,F,p*bl0c2SI`1b,$GQ-#ifeC%3*8LkU$B6MTaALbU%i(G`"hF53epU`YI &AL!@ad*K-K#q5JDY@PBU)Zq!Q*6N#*R(IQ%P(TCZ#$l6@%AZY23I+Dp[bVmA,9` XZDGU4mh685Ghi61CcK)X,c`3RFGakh81)b2AJDQX)$)%89Ul305YqeRL#!9Y(8# XdZLX"T!!PdLb'fFK[P6YIISibD-)dqC4Ni&JFS`TiGjrp)G&`ei+IFiHFmMNY4V MVTqVDREJ9J461QMQ,(83d5-JfrQ*EKS'q%a6-k'!elC*,''PRq)#[kbGQGUd1U3 CcIp1UCZXKGY64m-T8)`LPhX[m@X5ZJ,1kF6(EA6P@I[Elh0e3K)LPE&9dPM,0[8 XVCh)X!'F9J%e1&[%a%5FNJm+e9H1G""2@GXKSqa(6j-2Q5ll3X!5!mddF(ff1bC C!f`N8P41[+eA@&l`X&cRJ6d2m@Y,8YFmai!!$#3M%q0QQbU[QfGQ%f(q[G6h!%X Uk+#"(UqqZa3#m#E##l+Tad6T&QGXM,-0H9qIJXh8plQFN!$Rhc1k(JA`SJFYHdG b'9!je1&+9$)MjA$X+pIh@GP+HAqDJ-ZU4KFdZa*cj33c8UC8MYqRac+"IaIr6b9 Dl#ERVe'i1S6UQ*8b(DMc+jSGjLZk-Qem+pY`,+JdIp4b)L49@[iSHQ4-C+[k!0d jPSVA5VF$J1J1Mre%[*E3J)8P@YmQ0VAJT$H*8LdMkZZ5TJL$QA'b)8Hk`GJZ5Aq 4Yrj(0N9J+SJT2[F5$Sr4mR+2S8P)ZhV#&C8MQpC6f"484UFahd5K0ZRZd)kafM` L`HTU81e6FI%YR5FXY6dfrbT"8[EDl!k*d'Y4HXjRRif9,*+lD5l1KCI!b9rMd`l PQ'*pMc[DVQm*d#*124a$-+VUdmdFm&A-(-Mej"-$8H$%-#9)p0)mJfDQGFb&I3D a%'2RaIQjcIUa()NBr25#Z*,C&,!pUB)1(hpHJR"A,l8BSQF4%m&,Nqi#2F63VQ$ Berda3#B3@a8DX'63GAMmHf$SE@iibIGL$93S96++jeC1M,jCq6kK9k@Q%kSkXFf *d,jTL%"rT$0fKXe[iC@'AC'9*'biXIALhR8f1a3R'K!$)ami-8!6T&CMMdE$pa) B%,pT0j'a1c2F(i43NarTC&i1@G)QX(26K,N0aHRrB$D[,3H9PB%D*r-b!+LllRV -VQ@8qNGNU!$hYE0M4N!C*Lb5aK48a6riL1cqDQZX"rT!+bTmZlmhFZ6,b)SY)m4 $T-h9E%k,F(R)"5Y+,XeD'Dp4pKFAD9*mBEr-e9)1KhR2k!mkUQB(Vr5-[FB#UF4 qPANFm8S#)[lUf&pZ'4*F$KR'FJTHXQCmT0T,dXeFD*DX%@rHM,,Z(hi,Kpq#iII JZ(hi,LaIVHXPDB#UH!M(Aer+([T9RjBE@LXKh1Cqm9X`HYFH2NpEGI0mipQG2*+ YdX`f@VV`lh-3f#&pAR,`'iR-SVAd&LfjfKKhH$LGUM3jM*SE"THi,!Jf!`phMSV `b&Z(e2G1SBSE2A9kHp-l3ISRUd4aLLcTGd-mMNDA56qc4Z4DdYA[[V$&b+fmR-* )%"T%hrYSHeh,YaTp44QN14NVb$CHMSmDpRd11NLrjb9)@5U[%TGC2R5(*!M6V'2 kA#E&c9bDp6a+pJA[XdU(X'm9Q!@dMcK5CdZ,BUklTGqkMp1SkeAIU%l5`3d)8@R ZcAF$bUdPIqKpj$1G4,MaiRVa6UYdBNXcF3eUH&,$L4,3m@[HVSZ%jV#9GAjRDje 58,"9Xb&"8X9SdQdTN6*YG!fYG&#('k(qCS*XRhS6SA!G5bIXS-bIXk0F[+IF9)q Ia$pF[BQ1ViDEml9FbVarieeQ&)A@El9KF5Xrl6QYm,)SPmrUeYU'XQ'rFLRN$@" NMNU%9l21qcAGd0,I@rFYGmaQ`fT)5'"F,*HG'URT6[mp1-'Y849H'Yk`SLBdN!$ &(k#d8RZl*PGPfjK$"DBJ`QYINKqEheJ5a4pq!l9%p%ZkXpXL5@KKiYfcQ(P1TH! aKdCT(92f`)jmRKVa'rEd3-FqQHh6Re@dArIY,hUUp*Tl4h2r+ddA-Fik#"TbRlh TUHh`Bk`eKYUP[Z4iK41Y%f`ipb6YXG2BEX,@mjU[J62FQ3[[AeTdJ"hfDfEZ6#q 0c'Z@PLBE)lCjb(a0TT4V@VY%dae#SN,L4i1bQF1E,fCZTRXC`58L0GY@&U`6#P# 9*m'l9S4m3dX00Ba@ZC4f-R996)J3*`0'rI0ThhhC*q-Y)IDULFSZ$)@IYND[01N K9UjBd6FM0m+TLlF2DXc,H%HlqaG1)NpLa`'GV@M8F1mRqe2d+,Vc5mp[DBjp)`) Lp9"#!l*P1PZicc$2DrG8k#25LcZSr`"qpMAd'!XaZ,@jU0fHH#'[UPkB5i-TE40 r,KhNf3B'P$!h$4%FN!$[3JTb-AATF`mJCf&'NmRGEIJCjRELZQAMP(@Zji0Q(Vr 3eb24QQFcCr)-Q29+GZmkK983RFe3&dFE[$5J5q88-fF0QM9di4,G&e!bU3IYMr5 A'Zm+-2ci&XhlmJQieX3f"cX4fTR4"%GBDIC&8+'C(MCc@J%6'+NfjV(e"l*Eh2% "'HbHT3l&Dj6+fcfBqLS$XZI)D-`*@fBr`pGcM(8`D"6M%LDI3V3P(Jr5d")6PMD N6RQ(!mUq2ANTdrp08q$dpr49&[la%RLe[6(`8VepXLPM$r@V*DBBL`qa8hZZdX9 2pYkN,'hMPppE0UU3!*S)cUU#RqckrGJ8+aH$a8!dpK5H0JbR8V9F83ZVB+VTcV[ ##RUq2Z!dY*NmjIPh0S1$c4QTE8XbQ@epFjIQrCS*K3%aiLLc+BfpQjF6`)BQ"0A S4KHK5LiBr1'Q*4reJdN'Y@LiDG#4B*,cCDHI8E1Mpk4KVK#Rh@+!MV3[ARe`(#+ &3h("*pS$SF3+hArJpAJ[fL'@j,b0b@1ZUr9Q4GZHQprXl!c6Ej!!Ck)2E,XAKY8 D+iIAe8h!Rf[ZU3kRVaY"+fEP"@#HkIAPKXfZ%HFI%'!J@'N%p'LaHp[PZ5e)(C4 Y0*UAl24pHYlQL6&190'6d$L+M!YJPBIJI4`dleDRNFVCKkQU[b[4bkR-!Y-ShZ! %FZTcEfl9FTc%2"LJCIpXlf#hAPN&l'j2PbMT5lAF!kcX#d*-C-+&HkFfQZl1)@N pID(CC9i2A!'%UmM+)H5&-1'r5T*MFl2f#+&IfS3c@TU,TJ+JF9rGL$ei5AAI02( 8F+jS"6l3kZ1f*+5Fh(VE&P9Pifa(4l`Ce`J11C(bbLNe",Tc,p`rIT!!,4XRBqa 3@)9Y(@Y14%i[0h"#4Vf)a1GfVk&%c$EBJeXQXpp"eJ3,M3e)+AA6$IEJ2EZIhk2 qI(J3"qJ[8%@9#5a$`-XU%a*elrUmBr2*I9U1BFkLEU0qL39[LP6*939MYl'ZCcd L)rD&4BkAE(6KD"*Z0rbLE3JG++k#6d(eHfH9qM(Zk*!!"R["YlZ&SL9$$B$GP9F dBSfEEKmH`ZiKNPFQ69e((DX0*'&DaQE8&-($c!+$ahU!hL%f(T9T"m-D2r9)'!$ dj!,cmfTc&q5"#&Skmp)N3AQ$X$E8j55eJ2[GjR-PFIKU+cKH!b@42piYd2m%1VF Dh,15,IT5bD3$J"@"6N2kq*LREQIDCMm%Ccll-)EJZA5#i24cMTA*F1(&[XQ6bce -(B*e1pT2pSk6BP,'JjD*(3FXEMa!B388@iiRi(M@6d9*!JYE0+UXpGNh$qRVH3h %HRVH3h%HRVH3!0L,r24ZX)q)1dZ$AU+IakF$A2E%!((i@fhCbq6BLBk@H%KlpfB -N!#BY0&6D"k"efqB&qD+`Qa*-4H$Y+H6YZMjN3qDlK@1VR0Vp$chl+-#R+XI0E, EMh+$8j&lF)i2"",(T-NIf)hEb[1H9d%XZNK,)&a0J9`Jd6"lIJ3K""UrTVl5IZY A0[F"r3GSbHfHJH'kb4f(HKZkma(Pf0[D24%ZIHp*Q!5YSi`Fm2iJQ8M2dXj-V'c Vf&V%6X,%ppmVSa1SL%a58('9RpP'NANa8[DQjqCrL8aVFPX85Em3%#VZMa9S')' Nq`hUX4RM!MGiI*LNBAC+M%"P4S!p2TdH`5JjXiV3@E@@pUSdSV[&5k3EhTpbh,` k`j!!4EHC923"c$VbEMA28hHCBJL-Hc2GK,db6D#*p$X'9%#'81Ai)c+Jj,#cKIH `T116hQ+&&+VZq'6ihXb%K$r3Y,XT&m"kq%P3CdAPDhD&i0MUX+3#4pKHdPX4!PH qhEA*bB)C!6Neb@M4V-P[85hhKY0L"!KR62"20'UQHHbAhQ((j30P1C2PCqP(r)Y !%kka)9H'mqhS$R6aKjSVa,'+rQlQm+48f%e6L0M%#YLr'bB3&J6*''BTl4ejeR& CI!MA"*XYfiffqEP#9PJT@-ICb$Q[Z4k)TYA5kIl!3UXKDL)qN8+JRYaKdeChADB ejV"FqJ8J,3F"rR@r`D@T%)CGLKeSe"qD15*cm*AY`KF$h1!9hTYj$0F*TRrhD"[ qr[0$0Q)5aQ'pc9Z(E(M*DTLR,Bhr*I),R9qe!P&Up1FFJD*m+aUb)@@`NE0e"k@ [,lkqc0(T(4l"5Lej,iPq`JYKh#Vr*%9[4FKP9cQM3TmHS%@UPRSleDQ+RGMa@A[ Ne8rFeT@lj0-!8Ke8[2S@%qBbaVkUJV9%3#mfGLEfpU%KXJ2*5NY3f84h["B6Rqe bYXf5RrRBjSP,iNlH#6U!1&IhAV0N+(*495Zr+j)d%(dKFdk*#Y9qBUbdrMKP*XD m&DppE%ki$&e,(SN+QL6q$K,6,jkSD8fJM%BfIV3T+@E4D!@-D$aM@Cl"FhZj+@5 GLEAB#qr1lcYQK`STJfb)QXU-Q508P",FAS"Z)#K,QUX+h2ZUaUNP04bh$I+RE6k h)FDI&[X%EEfPpXVRLcI1Z2BFCAHPED,dfZ-5p4"FX%-4hDpECVSdeRIA")HY[6* )!(*JN9XYR@5`HQBfHD[JDD@DD+Vf+i3[K8,JrMa-NAKAAlhJDQYVp$&ZH1bY4HJ #FX02P6eK`[)956pT5%kbc+Pmb-[ebPJHBIjIH5`6IN`,164JQALL``YV)R$$`i" I1c#ReJaZN@2[Ba*HE44)UjDBIa@-pFdm91EK@!rArJe"EbDPV$XRlbUprIA+aG& h"aN0r2X9FbX$&e-NG*'&KiI@p*N98d!AJdHEk9Bkd$3`'PMTZLP4$e5qJ5SGqh6 Sdbp5SHqQm&T2EK1I30,&r`Ej$Bq%@r(m5#VQ5)Ja6Vf8%24,ENYB"S5Kd(L6X#5 pkJP$d*`H)SId5A+fj(F@!BhABMZRqY`FcjT@G`aaMK[6(!!5NLe$"TbaU"m0ae) Id#TNR4@r6DjR+!6YSk1SA!r@JER)(#iZ'c%Z))SG)QClq-h`EfE%a2BK(fDN'fU XR%Lc@r&@-hC*[km0Jj'a-U5h62kBH8)%aY3cJKNJ96k&Z9R&%$a`a5E8SkShPKK 8T*bqG"HC&V3CMZ[b(%N2'`CHYEh--TS`+!M#l`$r%)$63`1jE'crCJ0H-NC!3cZ J4B$"PJc-0(@ece1)Z)`@NBdS31fe[ZQpTDM`9!FMP2mRBC(21'25pd1(HQj"G6V $G62[m3KrUMK$`(cVA`AeLPQ*JGHMqRqTfYhYYN(k2Kkc4f8Ki3X8m4$RKUr8U8[ H9Ge$`r6Ek3+H0UPflimd`p5G#qHhCYI8XHhfLeXL!lCmD@`R9Hh"!+c[`mbhA14 YNL,IhKC5Lh+9DH&GR9HImcml#2KYTY)B)fK%!KaP(8[rK,H5AD`#Va4#d80bMD6 GiaRm8HCf#D0RdE*C+KBA'1P@e"6Ffc%(NL!G)0V&3FGHqX`Mp1l`e-Ge$!#"fV+ Z@'I'i8B"fEHAY+3lIXdi1hPrBC'V1ehCSRZU0"!96c1XMk[m2r+C`(M6@4pq!A+ 4j@R61l`%CA+821*$FCC6RLj!25e,r9aM!+3H0(XlRNiK[edkk"j83piN9kC0F[# -CCQDqSL3!0TNHL#rF5LR+1SJmPAFhd)R8mK6*8#Vi89L8kj(9V$3eT%idAjP*"* +PS"ERdeD4mITqf)rE2a8&R3AJm`fJYVm#T&%#J+58KQDV6cdF9B0*m"C&'FIrV6 %`Jm!$VN'Sl"efIG%JAiXrbQEEfZIVd`P*ldjU1pB"F&',1Mb5FEM`MGiCL%EG,l e3rHhP3IZfiQDq#Uk,`RcG4*rJ)T%Y`em0"iPc%LVGD1!+Mjk&B!I!2)mfLdaY4A FIr+ApIbZ'!2Abi[(N!#SS4lq`9E(&*Dq'UHN*XN$kI&P6L5LJ%cA@%fLlGX`8J! 0fmUm4H(5#IEVPHUlMmfJrXc25VFl,5G`HT5+AfE!FG1-j@eV(`lF8b+A!%1-BIX T`(-c4HABSBPE%!SEMbKJ'"BJp)(!h)1(Y#9V!d)k#[SCHq+3!-lH)dU9SiplI"c PP%0Br`4Zl0*BEhD[mN*DP&%EGcNNh'YDA4AM5e(aYdh+L+GX9cVZ(i5p'*SN8l( !LqQR$De*+c$DqChdRlaHGKDRR`+HG'6(D8b#M`c1Rm9['hXH)"eEma0PMJkHi[Q 1'-0R3"8H@fMK1"imha42qK0r*@!4d2T*fCS+9L*0GZ1[)bKZ6Rbf`f6AMYch$-c N6bhFq5b(DFiGY8JbFlhlVi!D[e4SV,)Iq@i6G)5b'b)Yi`Q*K#[[#EK0G(!3SME Mh2if-8ThmG#lm#*%J@j-BBA'lj1jFZ$GHQ+%j2Cde3E8fPKC0*Y20F#85Lpj@eH (`H1D%Pfc+1Qqr86UC&[XaNF5`,G!6"C8b6&hdiFbX3K(hiP%Jb86ma-PKYhbUU! qZ6@aPY,-k96r4"QeYI-[GBY1PYfI9@00[jAD@12M*T8#p3#"-YRd5P45Hhe[4l' %hfc"m8J5r6LiH,$a+Gh%-b4c$r'PGaZBXKA@mJEDlFH#@VBR*Y-`RaQcE(!TMQI A`RUTlmLFrHA#N!$$fl[30Z8GjqEM-"%#k@,&%NHK"T'p`ke21Sk[6EeV'+dlXS, HG@Q"C(+YJSJDDTrh9$LNlS!Y&93h%d%lUHYe1lj'p9Eld3T,U5fDTQJp#pjV(48 T1TU6&jT3d%XTh9ZJliA$K5eN3cq[ielhQ83l[0%qX'bKa6q2fD"LI)2aUKr$c3[ K5'E`E4Er'p0PF(eaTSqa$0EG4%Y)C$LfRHp2YlIZ0%i$CqX9BSc`j5Q!'0)fU8S 33HPdkPNPdB"bR+Z+jiIpqSHC,6@k$XXhT3N%q%D%PXTVNFYDe6q+q3$K"l35FFc `JqX6A20%c`hi"$&#+c+p&$UBU4jhp-#[bIU'1eNVpRbi-1QFCHF9`,G(+F9pe60 YmEXecMrMa)G)&,pkF(QaNBLG(cZ3!"&6",4LJ+Tre3HF[hV1e9CKMZc$KkpjX"K bq(ViH[Kkq(ViH[Kkq(iqiNdA+p66+mFmR-!D&,6rAfi!rXY"'@XYCDbF+fPf%"K &6#*RRm$Ta0K',X9TPXYhm4SAAb2%Xj'k,T0Z,I$&%MLjmrLC%@fUIp8(R,pkcY9 @BBlX`iH[HE!BF[Kkq(ViH[Kkq(ViH[Kq2Z*0&b[8db[(2*c!'K5drepZ!2l,34P V,@@XR$(i2S+DBh$*SJ&ZP1JEcM'IL(1V%5-TZKJhZV"HG3r(1r##md'pqG9Q&jJ EcmiAkMPqM3CLjMTrqY94j"1CeTX"2BSG)FaHTa4SPIR[hU+YU8pl"`ILkE1)!*e PF*frAaFSffp*B3[1NT!!3(TH*&L5BU-dPkb!,,1M'CG&,`"H+TJ4IM@DPT%p)rM A5F@[S-U6iZ1lN!!+3,-2XE!8(`iSLYV)d+`fSQPT!r`!28ddV8!aBAF6%eFUqb& i,9*EcF#K9&KI4#"R`#0J+HT%R[A&dZbbC#4D,Ca#piGKPhGhMV6CZL1cAjp3$%E MD9XeqFr16K8#,&h8kD['hD)aEGC-([V3Tk@a)L@Pp+m558P0h2*p[,@J)DD1ZH8 HRXrcEHQ'XYCfUNI4F&&r[fTVBbeN4860T"HpDklU1[A4D(H%1HEQUpmJ)d%10L' [6Yl8V3l#B(T5e)fkH*b"[Y8[,fpb9SIkhXNYM&-"FqHD5fB)@@q9Kj')HliTi"a F*9IaF3NSq-bH`Ck*+eiMY(3TqDjBk,mi)2pP6eE,DY-*[CEIMHqEV,Ji-V`S9Ci $6,ef2k6PBcAD8%'NlNaQ3T0D0*cRECTKGfhHT*PFbQYLUVq[3FR[[&H(&Xr$EEl l,-DUN!$iiH#BIFY@k@M[j#4k+if-rfa#el0l&%k1f,kaQQ&P4[J-i["DU3i)m1q $@KcbRcMHUIV1cGK떴X0'qJ4@$-A1dZ+eh"q2c5T%++a(Q[)j3hS++25q@Q M4PhDS1A45FUaZMRl8AHF(f)rE+fFA(L'MYj9BcP6dVFCbIpRK9l10MTrMK`G2qU JF*p[d22GZ0R&pZFF'TT`Pe$A2[p[@B`5LPqi@GIX`qZC)#%Tla8C6)U-JJ31,*, !q-EF*ri`)QH#ZI5AVJAK+2leM%"f3L66kBT'[hmY'eJl4MD66mCK"Y1QK'p`V'a F%VmaSBDfJDUH#jfci&F0r$MQXfjdNKX`XL0VBbAEl99KfH[U(-c+cJC-QNd'el8 k#ArY(N`[ApcI6lKDN!!rX6@F8M*$M0iNfr[DL`iP5Pk$0%A8a"kBUYPFl)P%DaJ I+90b@3SXRhdibhPScQ-k2-eeDDf*laQ*IFm*HrQp06U3!*qeSXL,,m[KMCIG@K8 dRZ68YCa8R##5Xi[++#0,YEB-"R#4iSS"+pHheH5,UVC"5++T4P3Z-QIU`k(@F8- VcJi5@c"#"Eqdck2HHT0$BSf2L[NRe%Ll*A%H*h$&LlPfYH-9IK,QjBphQd62Iph [AclqC3!56dPcT`I#f+8!9BCd[D%1BQ[1Sm[JJDdpLTh2A5eXPR89R`K5kEb(*[% FT#16aC(`mKbr"jHmeh**DQj-9AmXAmDH*YLpDj99!eBB5[TaU0E9G*RJaJ0J0mr hq9N0USChCJ#6FGi6LJ!BkrL+L+Qp+cNEGZmhq3"92Jp'*9r`S22Up*EN6b*)FBS EX6A"-aa8K2Bb8'Djl&#PA%*m9QkG`*R9j)FdZkhkc`HEQ"q%HlG(`0mC4EiqSd" Z"C!!46-!h'k!-e-KGd5flj`F4lP55iaUp+Cd1`Z#PLi@LSajNUAhBSI(IT9,q15 #qK*[!`,)84`mRLbHpBmr0"pTidkY-EITj#&im&EjC"hYqDZELPl$jT`+fkk9R)P G#,23@LI0*C@YMp8i0c@*4`i)0fElJ(%#I'1lkmhRrdTGbm&LCBh4M#l+a`TTYLD Bb4D%3d0RTSYk*UFcT[be8BVS*3Xp)aNcr4'*Y#JA)rL'N4h"fNPLpaEG#'TP91Z *'k!`!Q2rBL,f,[jI"V9XV-FCi1c(Mi(dQC!!j`0b!%iEQ@p-N!!j"ICq,YQ''Ii iYXp+FdmDj2h1$-HLCqcQ)pP9'MYF)r'p$TM*a&)#qq$abXmQ%Li0B%aqFeVcV5H jT'0$ap1f*1bXm+"H-Z('-DIKl[e9q5@a(GY)pbm*iI4GBe'Z)QpD[UHj"A,BHGh a&&1)d2KB9N+j49BZ@4F%"k3qkYic"&(S2SFPbJTdYcJr8S$8mc$))T0X+J*HN!" HV5Tcr%kDZ+@4&X*KpN-@hC!!qrY0'ehe`"DH2q1"c"RIYU2VY%$pDI'+,'46QF* !0aXM#k%Z95B[9jI`(L`pd2$r+bpQCP5+ESH"&['NiJaiXjSIM4T#5&0-X55(QlF A1i)!H`Dcq[PDjX6EYa&Ldj[UMj2SSReq,+EXYm,*bp8&R`2&Ja3F6"NUGkT5[Eq pLE$&qAGBrM%36bja-Z*'`4qA-e(i%%&*,ThR[cP#%L82)HNc1r1m"k!VRFFPaf# (6@3F"#-k,i5F-*qZCc3ReV+-c$hLc1VV'JL!f(c%0460TfH86[!!F,iU,bjE%G2 5k$c4-$-(FlR[[qC#4Y3C[q,42I2Te)VD,16d&NdK!MHKJMFEjS[5@)(&Gd0-ljT 4p8Tp#LZJl9fTjP14QRFIb*Q+kmd-f,#'b0+LEaZhUkVXmMUDT+R-6R&'hG[1K*b 1Ge-ldi'cBfq`PA1"ZBk[!`5ZEa-U1`UYUl-96Pd2b5q'@(9RXill9MAiIP3K-jN rd-'YpDXq8XRp+)-ckplAB-bk2fTk9ac+,SUKeL'Y2+$f,1-T3jflKPPD0JLTarZ 5B)1G44maf2#5[+6N6f8YJ2#@eLBYheQ8*GBA-5TR'mBP!9&5SM59Yl6Chmpq4r' mmhX)K#2GH`5N[Q!5%klG#6HRC@rQ![pcbd%6DiPJk5PImq*J(%#`ke10-e5XF"A N$e%BNdiA-![V'$[F$61cS2f*h3!ij%%GI2-R3`+`mFKKJQLjXPCQf&9SfmJCFjE 5Rj!!RrkmM(`0m`rf*FJ1d&$%93MMB6"pRK$e"f&)3X6pXpBHN3JRB)jqY2%G[FU 1Xr8-T81GCj6e@d1LACCl2@S8&IP(e@jZ[VeN@+ZTab#r'FQZjbh%Gk#$Z9[[N8P KIHiRTN2TXbj68,rkj'q*($&Z3f,E(idHAI@i@br"8'Q4AYFXR3rPEpd%VF[*,N3 )BEYRD[B!0e0@dXeA56MR&hIcZ41N8'RrA0jP@IhJl*,8p*8m6VrK$S@!K[+eiLT Ih'lP!Q-pi1PU8U(Dr1Yj0C[2H9`0ZFH1fbB&i#Am&Kd*0K!#A(mal1S2CeNGK5E 1f05)LE8FTV1+"0#PA02f4H9b"b4U$QLkRVk2IFc`R6ac3h1e3Q3%QrCiJemCHK* h`)30HT85%Cqlj-4%C6#Z0HPf*`f3!(h'B`rCd(5Abr+J3Q(cXUZAeD3&EQ-,%0) XM96'hScFi96mlb*F"XCfb(8Hb%8XN!!cNM8G2E[4jfG''`Xl11k2e9V-r9P(m1R VCe4Y8%@G,1[Ze3mGN[@KZMJh%U+Np$rVB*1S)eKI[9d&p&&+9pS[SQ$4FJV$q@B mZ%-!pIB150G8PGNq#$IGAN$jd912H%a-jmPJffcTc&&6SA98i&mUPZa)Cf@KHc8 2kmkEme4T8TCfFa,BqJ-JUU@LE4Q-GM"%1IpHL'rjXRGAj!''kIm+apXf8Kf5if! -3majNL`FK(+#%VTZA#Ka(&Tmc#)BebcFNfU60pik3pS3MmDPpclSra5afC[haH[ B@4hR&V`FPN&RhV0M!XJ96jcN"kqSR*CiGI"6TS8(,`+q0Mi-4hrB['APNV$f!4f F[,Jj`D#e2qI#`3JFL01HQ$lLcD$'NK+Zq&QNfF$!c0J#fF"9h%J[Uh"hpFb'6[& IrS),0VDaCFc@B"cNe[8HSVaASFEm$Za$N!!fN!!h0"jLkKlCIVekF&b0!0*8LK$ T-jjCLq6dk)m$1aFj3@MUm*'iZ&Mr@856'A&#F1GhqIfrjGK6L&56M9R,L$+26`N 2kT!![bAQ3G5Di,Im%k[S0q4-Qb`Z-"L!"FA4YcCpiQDMTSG&1e$Nd,qRV9#MXU6 'Nd8N&V6SGA`Bl@A%2e+C#I@2Dd%a$`BL*q64CERmAXTpk1VJN!"IPdV3UbM,G3f b$3"r5'*RS3[3DE`QAdY%)[H&DB)h5`c#2`$QjjR@c"HdUKIXMpb`TYU5f5-&ZV) '+KraNl`a%`KL)%Gr!&8l@(iiVGJ12lVJf5UHmQUdaHBN*&JFUh2@$8kBVPGE14@ r!l(eUjiijK6,E"RQF%,hR3F"NZ`S+QTNGV'GGUY,FGA+C1`TMac35H!XCkLUBDV 0"`4Z0U0XZlTiMm#$H8-qAGE4AkXbp#*`c!T[+3$NMPj5#GikMc1%%mFBmp,FjLB UG2mPkrCpKp6TLEplbiLM&G8[$@2`3A+9*RZj8(HSR)j5#&Ep4F50Xe[JElKU)+j mQqr*6),PU`YbiFPbrX%d$X%e$9b+0X+X!Ge`'09)fVARKr3@26#0UL4l-02[c#& Z4(1M-+riQT1GfVKDZFY$2Brfc&eTV)4k&`Z)e2TbJlLXATaEB5D"p6595bjZkbR @Dqc9J)QMhXI*5YU,)M@VL-[@Ti15X'T@R6QRGjU+TUcBQb-r&23ciI'$2Bb2[-" $8ebS'd*-AQ4KLmcQY&MP&KKI`6(S@Zp3Rb,ET6RX(V6LKGK!kBIr1&PBEV!friV clDi'@m*KZ%bCr8hl9*a`Z3B)&aPbGPc'dB)PeK3`Tb,ALN0k'Yil-HVa(K4dJT% YH#"HL[5p0P$,H9`#1'9(LI@")KdH6iG(J!#I9DZ$NLXBDH@8`SKa2k'PI%Ih$9D L&f(EG%()pX"qTm`JS2JP9-Ua'+CGq[j8)@RYR[)!!!!"U(jf'Tkc--&i6f3Q,GG fR#b%8DY1jf"(#*J`hcc8NrmHYp,K@AQ21,*C9"YmB(j%SbA-l,%4'"B!FEUBj$, ["TeEmRrAKQKYQ&X[9f[j2h`4H5#(3cZiCCrYZ)M8[rEGqfBMqRJ-Z1E+",k5*I4 b(ZIJkP9$fTjMql(M&MCC9`4DpQD@G$(X"h&E%2e@fjV&KLG30HD!lIV6UI9$-A& dEhXbD9D+lGiXD[I[jP2G+`mT@S[lrbH)'9j@"*6*GRla6hQpJ3&iB03&a0jQ`U# NK!e(X4F49'%G%LI6-9MGR$8,YrN)12,dQ'c90Ufr(BFCePdqEE9VTh!d(DfIC*E (NkDEZC(G!86laXkK!#@Cj*E5T'dQfl-h3eKrkCA8HKm2["pN(jqVfdA6rR!iYp1 N*i*!)@"5+E1`P&Z(RB3DJ#KbIE1E`(1j-A!eeU"2km)HL(Dp'4@,Ech[UF2j%I2 @pBQIa#iC3d+b1dVSm#e)d&Fb3M5iaJ&TVi&I"BRHN!!2hiJA$LhGMQ`[Q-@FmeI Tpb$Mq6+I"`8l[Za#mD49$MN*+M@j-Y)UZ2LdVR)TQP9Y4Pm&6KBmP$FH9C8@`TM 5'R#P'&&8lrLX(I8@8dh-01lVH)#0rcaH9bhmT)cERVY%i1TlMb!QqpHaTKMr4[Z 5QqUA302"J2E2P$qca2RF36P(Xd*6EMkG8JGX!DDB8rTD`fQRB6-Kk9-TCZk1laG pdfMMM6V%[EEE56YE!*)E1,ll'C@X#*1&+'HMp[19H1AdqD-KpcYP'3AiGBlhDcH JKM65IV-a24aJPi)433BPlT!!4#81VGblrETF'FkTaVqB3JeXrb$AXG9,pNMhdJ( '-@XBiG3aQDV%G$MZ"KpAkEC1L@qBa6caeRB)cm@5+S!h[)LhYb)Y[)3dQN&EEV8 lVS23mcSiCZ[6#4"cJapXHbTUB,$'U,MA8F96,jLZ,H8LJKFF6C-X@NcdrLRhEe[ fqfqQf"+Bb'2GM%"q3c&`[iqA#-1SN!!akBJYrf#)-+1Cd5mAa(Qp&K&$1mke*PX *q&&RfZ8iL($N3UhN*ELl+hJE0q5[RVD9p"+ra9Kaqe[%f"B"+e[ijYYS@SXEG@f -#mfj4H0K#SMl&Pk9"*TNSpaZ85Lji1LMGRHF2BjK8[+lXUe!lX2rB[X"dAkN'Zd NiR-2"UYJHQ2Jp0TQdI#P1Vi64V0ZbQ5"SDVA8LeqGVYe1$03)J*fLbVcQ,$hLmc DPjQ,k!RK"6'H%+MF9jI[XRE!4eSUNCX2pU95Mr-HFY+r1NU3!-ZqFHE1&GH1keL PX@,TN6'KAd"G[#KP2RR'H)BXE&q$%IK4*8KqpjC[bLDU8dfX49l(E4B1DQD-l6a &SM@H`CQ-bMGAFDb1QBGX(U*'VS!YKDBY,5P*'%QBmHRPkZ(bl[00h+*$Kb2@r&* )(NdTBcFELk(2d)a9"!RfJ)KUG*dR`cSCVA3`C03T2-%%X!Zcdrj(MjrZdpqbjI4 #5Pjda@jK25MFENi[F5pB,NSQ$4*YIcq1L5VHqZPJGd)j-*08+Hrcj1IV6Jlb(MM -$[(TBiHQM9p[)NhC@d-jiGe)MUimI84rM81Lb9-QHjS(CZ+3!#mj'5QDHp,#!S! V0pJplPKcAF"QikFM3Y4Nkc2c")0#HJXTSTi4PX%JpfhD,`)2l8N@@QS[E1NBbGa l,@N9XZDJjGMKTX5Q`r51)`[lH$0hd[h%)e++@5JN"GGa)0"A!R(0Camki)8Nb`# HPmLNLdUZ!r$0XKmGfbh$ERTIVqcrD-2pafj`0[Rb4+4d@pIk95@d`%PX%8%A&V0 m[$cbU1rX5cp0`0d#84*)Hj,i"5`C1%X)ChU9TkZ'aThJreHk"SMQR(0(G(&e,e) R2!3YER5J6N+LZjHFrfSak4f56)NHKcl@E,a(LL0$KZrXI((qe(XkLD94GQmp4aj RS[)+R[U+6GHJc)QISm6`SUe*VAFmJC',H'ArB1+(Sh&-ef[+XYfP8X3HVCF8fbe e`#L5!aq+U-[+pR%S*h-)L&`N@#,,`%[)#a(d1k1V-dfdHPNqcRRLFUaAL#XJK"* peAfm[UB'%T6HUI(DhN2(`Xc`%T%T'U!0*1,c%#YDNGa6U(S@r*bEjHGGKXaMaSX Tbc8T'p1-(V+*+pRI&[JkLdTS8Xaeq[CKK)HeGC6dLh(ecjQYDe!k8*'ZXM4[UPi i'QTT9LiI`Ubd0Q)NipV2idlV8cp9h*'L9X&PM,L`i6%baX2SpIaSQJRJ&G`2Gp1 jqBKhI-*6b[KLm!p+LH[CT1IN3k*6i,Y@![PTm#I$l*q(5)cIr,m@I2pr2ShGdpJ )dP'$IK-l5KS8ba5emlM(Z!r[R'SfUPVE#NZj0F"d"@D%49)J"P13!("E+4$lK`l d)+9'THHF,(Q2@Vi9Me`#SAHVe$QBpYj[CA8AS+*$Ma9d()CJ!Zr4UES&Fbq)0I, bHFqfaAdKX)@"86FVZJ#V6LLR1ri1'jUrd1mQ+r`HLrA+4rSe*Xhq8Zd1##`Yk+6 --UiEmU$e#Hd*(Z"Q2EHJB!L1+kV"lci'5Dr*mA!,XqBeiZ"R%D*mbH%k)EA*M'm l(U['D9LpE@0&2Cbb`YNh3j!!`YcU5-D8Q3mM@@*F6hN2TPH'`EYpBfICVE1kp0a !"qr@R$V@HGZKI6HqD,-ehlK3+AM@*4Q&MRGr0Qp`&V&[#CiL@XdaVr+VIPhRTZ+ hS&qX)TUYqXRXamk2A*p$@"cZ)0HJc&b+Vmm-k0k)V62!#eq,'U9mdKRY5V0J6T) lDpfRl[(k!@qDL3Z4qA@Md2IG,2HEcVmF`IPpd#0YiKIcjM3mrHYq*,ZrPm[8UPD @KKpI1a)bbjA'$KfLF*DQTh4b[2`NrGc0mTDK-SK4KIp"p[S8+h`S2H*Nl0I+0)" ZMmp6m-[ldk@X30KrZ3-'0(UC13ajN3b%,ZNY)$[8B@2,!a'L&HEr'98cL@*2e!e qAXQ(Z%QfljcDE,KjIhhQe8[H!p1LpeZqmqqT0a3UH-T,ZL%54CiM-@"IG%&UK!G 8C2#U1,,UL5HeC%L9iRAK00QGS&L!Em@MSh6%Ej4SGemfHYB5mTEXEpJq%V`6HrV ePQ&)C@R[lMKIVaL,%#kMb0Rl"8Ed4FdhFb"8TEJQ`h#hFH9YKXJ@*I,'-c[I,I5 4QVP448V49UieF4B*JrK33HAr121,e3jim`iGNCipR4PaeGE)Dh"qi1!@6Rr,ddJ N6RqPTfYr($&YT`i'K5drllF!If@JM,@@XYCDb*,AmJ!!-)eA9r(m2KMEHVQU4Qc hj0EpYSphmNI0I#3PJM5k"SjNf5mfRa)iZI2iQ4&p[kP@c9`BQ!#C8)'%M6&"D5B &alEiGphNGBhDmZ!J-l`pi5M0C0Q0crBb(M(5!'UI(6Kb3ar[Q(*&4k#)FN-IljK b48HJL(*$(qqBHc,)J@Je5'mcrhrq,E31NVB'Z1b-BQ1lHbK43dkR[NkLf)bXCIc 2qCrc2qCrc2pCcXr8P(c(USI'B&q&q(4r%d`KIKIKFNaGRpFEe-0beVKa%1[Jk(1 iRj*3JLi!15GB`lrKH$JC[2Ter+Nq8e"&5aL8k!YUd&$m#`$`3$"8R6r&!Pm51J[ 8j+i+!NZGJ(%,8IB)[0`2SIpHIGfl-m9epi"jBIA01*-[#@S%-GhX5!i6)mpR`+U h+eUVM-[#AUN1j3(hKL-L4)b@*XX)rh2kl%$1IBaJ8ADd'DCTPkP2bFQ*eZHr1Uc YI&!+Hhc2C@Ykc#CkP,*Sp)rrIr0i'MHMb[,BV%h-!&%8$KYer3[pp518R+#cp`d MB'fcm6-MB,Prr5(9LapR4dGr[QqV[e[)`4aQAD*cD,AQG)E$j[i(S`BD@ATjG2b )Vrpq4$@lDUc"2kCF*LMqhp9ZZpQAj5`DihZGKM85ASXDM''(SmLNE(TZf$Y1ULq Fbej53fI8E8E8lc)T$*F49Z5hSJ+*a-VE$C,V3@hC0,+(51G*[6DU-Rqq)m,TQ0- Spa'EE#MaJiEZ)$iGq(m,m&Sl%qp1)0UX0caLBfFRFb-YkVhh##B3cee!GhDI8f" L5,Xc[!T&NQ99r,!K$`&q4c4"Lj-8)KY5M!'%G8)KHJ0QX[4L@Sa,8BPU-5e'*Df 6[`1QT4dl,-c*kBVMq46GhMVM6f9'-+8Z'E5IX'r1,%HXPRqJ+N@GlR+[I*!!f'- mhk[pG5T[Hb4pl5fNk@Y(5lck@aLj0ZHqSF3f-r)$[Q"da"U3!&9Fk1!'Bd*)HF4 %A#Ek!CB#24Hpj&kjkaZlmc9CU"+"L0Fc[(cb'i38B@BeP0C6@8eP0C6@8eP0C6@ 8eP0CBEKZ*p5rXreGNG)D8ilIbQ&5Mj5Z'kj,RkEX@@2TBp*aifmB$ec+SGq,HQV Z18++h"-S+Y-leQk)K(k@Sq&hSTZ22b4F[P(H`Ul@)qcja$mJVj)2ha[&DaBKZNa IhZ+MS6XAEm%Dh*rT+@$A-SK5`+f`[1EVhXYVAJUj#cNABXlh1lU[a#@J)(b+dYR *lHq6[pF@h)&IP-`e"0S[kT1-'lfk*U+Mq1ALZd)+fJ4QBEX-(65GTN8-2Y0klYH Y9cRFIXMLfD%M6LD!lD(iT*b"hY,!)kHj,L#""iQY9iAcZY#,Lc`%9)1VmmZAXQl A@i@4q%E%!S!D[DaZ4`04&rMBP+[F'mZ0fr5b#[+#hJ,4b1C4%h5Y$'ik5S[Sm&f L55Zl4C,"K'(UHADSd1LA)8YK89HSAk9"$+eIhRa*9cl#hpLA#'1Zm#)$22[q*p3 U""PEM$DScA'8-2Yi4XGPEi,r2,l,9CjbQjc%p4(!cA35Kq&CpDD$,K"pNeBcZ0f fqpQLL1Aql%X46,BNE3aP*8G3%SU$Yr!P1")Ea+bicK$b1a1DMKd&LFc0)!G&"4r EJ4fjkaf"(ERV(B'hC-8[e5`cPeQ"RDDDf"$GN!#!R$QI@kR2bjAQ8LlN(rprrhm "KE`8N!!-G9hH(IAEU8R0bG34F-K)S!'%K,M'4d4&B1jrpRL@Q3YqXP-k-Ch(9pG %`lIAiJQ959UeT3"UNQ&dFa$U'D'6JG@+0"3*)!B4#FCj+$"0@c![BAiAiB-C#fB mYQ3CmZIep#5DT!"`ZMDLifSqVIpE1d3c5f!Td-HH@&L"1-fIHf3laJa02h'Z-%U l#e3i6K&++-hAb(IU6qRb[dd5XLcC22aNr'CK`dd`+3mm"Eh168)"&X2S$8EkDSN 0`c8A$cacPb#'28V2YR3E(4e"LI,VNhM)iAN%9LGV"0)AS15',lC[QJ[3ccmeikf l"BJL%Ip[X92Vki,hUKTGm`Z+KIMM-S2bp`Y`1q!bH%)(YXqLkYHKSUJcXTUGE3% R[[+bXE"QJ5V'bfl6j`(*i!mMje,jSF,IK(C@QMML28da"(%0rc+!%C!!j*EdTZi hJEbIdrY#r3!IpRrMA8Cep@JPMSQ*6Q@ambE,"5&5dc&p14r!r"GZ32#4Sr9"e-8 6J)M80r@dm'FEHV%@6Pm-VMpDbkTG(X39'[`q2-)Jm&pcRQ["l0j8eI--Vl&2(jp ff3f8c1)%4bZpMdCG3#cYa-$*i+k!HiIr@&r$Gk06Fq6+Q!5J"p0#k[P`Gkc+h,k JS3P61,EY2r4H*#`"E",rC#XD9TrIB4@jXBFkQUP$LFCJM6hJcPqc'SCVmbDD6I` aB$f2e$L2I9S*2MKd(`$dMZQ)G8`$9P9kV[0EIB)J-IHJarGm-m#4VPL%b3Mr&$) L)Lp-I'1JBI3kD%"-$eD!AXB-PT+YN!$L`arZ-EfrU2)&5rp$BCb2H1F*TZ2erdF 6QRHS2&U+D3$S(cm)rSZTN@[Gd%B1cApkhrcbN3qpG*BdK+[3Z+qhh1F0['54eX` HH"pXZ&em2!Q&@0cIEhrE-AUTiNZp[!K$+1T6R`RXcb[45GVb-$Y4#%-#6)K2a$[ drdDU)R)$,KDda%)Ri2BT5Ejr*0V-f1#V@UR&*fK-Je8aLXM9@XE"K11j2pHhGcj Z+EIkiPk)lHlXSd@GDJ@!!Jb,pclAJG@dQFdThDbZ0&'VGZ2$`M$5IY@#`-9T%BQ +-A-N'VKrd8BG9UVBSPNeUeN#N!!,-abT1NF#pZS,erAmqJeMQPlqAdj@PBi`6DE aI4U")M24XUD"ZS8P"(YC[dFK(L2+0RdCV6cJP%)!8M2@P4Ap,BRkJ+%)YTSbDPH +cbX@KTJlcRl6hfaDDGIJ6b`"cV3-ZR[r6%'RBT&lm5rpT&&XEMi3PeDc9%6k*-N 'ciVT[cMc99p'*Q0h1Fcc!(55Q*eI1YL%rYeURb)4,EZ5"'-IqPB2@1HfhURPZ%[ D#db+j(e$L[UCAE8`'c*!!Er`Je*$1+&HR1M#"B5rXAk4NjiX*@33i2!`FS#UZq[ hCrG@,ET&m184maV9P(Sc0ZqDa4@,6I%lNIfDVlD&iP`9*IeZL*@QH1I`22ffQMC EfM9A52-EcXB14GN,d@r8Lc`m6("YNXZFD+Ki"5M03(9jDm,9bQSZTKGl65$M9mL qYP6`4+lUR+(0d'ik(HLiSh0lYdjh"GFM&GfPR,3ZY2*MmBC(N!#5S-3H-'P6Te) mc$ZQ!Z9L!Z[j6!&PP'&CUem"F[4Qqee1dFIebTT2NDKdCSQBL4U`CIUG"SHVf4[ M$!0jKH#(&kX1Y"G@#B-10RPVA+lqcf`Q3J(FjPRREYdY69[I65AQ%C(CNE)6a2F T9hm6N!#ehbGY%B91&-lX$@YkFNrU'II'SZ")L9c8T5N5!MMd[2BkRq&Y251h+PS 90)X-[QBSGMiEb"qMl`2YXZAU[-)pb4NlmFN!rT9q)lURc-fb2ImB,GaNUhd"pqa Z"[ab+pa(5Q!@&Q*8YjDl,rSQ2k8S0aa*8ar15L93"`3L'D&+UeArDP+JEFk"2rJ IZF!3(kQLeN`F#Hk4dCKrY,b,kp0*HfcfiG)25$"$pjCmJH-C*$r*b(qBRIbpck% [h2LPKG("m4CUNP0VI&Ea%cKGJ)'Am@0E6VcS8RAehJ06BdM6ha'Xm8ac"#Rc0VN AR[PjXFH#h4Ujd(AJR6`MaGcXbZd1k!*@!!6dHPRFCfSCr3-qENEh-D9K$RDhAU5 )j%M(QHC6Yidd4IAD3&RacPII3XGebIR(Q5Z#c&AK6[GE8p9LPG(h"'hEMKDf10P eMf*9+d#R5dleNHM%DSG)G*@h#9IC3had-Tjl4i14Z6JR$U#b3kr)T5eYbHcXNQ3 p+64"2Ij3L*TDm#8*(@HFR+d$9BbAa5bre+p,-Hf06cli'1+'l,eA#G4rr9TFkl- 0P9[lQN0@fS@YAJB(p#aLKl+J+)UIiQ8MaNAijm&+T83(A+2eXNGFT$4QQbXNGFS r@b4eppR!34&2RRYT,B,'9d$8$C&,)m4iJN[90lf52[D@dR5eSkBeGjFrG,P4TGE Q,N*cbUjU4#@e8HhIc94"'jfc85$+ep[lraXZE2Pf(#eQD@"0ST+6!#!C8ZNMrST !b)T'K1U5Cq4"JdAafbq*%'#bp-8h'r5hpaGU6!Xi[6Fe3h@69R0C6@8eP0C6@8e P0C6@B&R"CLX#QXTV+DbV[#mShN2NmSQR8Z5jjh!45FN+#Y4l!,qC"kP6prV[3R* VR0TE*d)hYUbhcb@Hf#ULPB2+fG52IfXSG13mGU`[))HdQXPeL,RJK1m22d8KUcd M)JU4j-,KF,KF0'$Ie@"e%Si(X9e4-krVDUhk'pUfeHMedqjed3JS!5PR)ZB3YCk mihTZ1N53!1SQFJKR35Pi353+qM-N-BYfhKcmA+CG2hFVljJ$&X[l-`'KAS3HYRI $M6a0B230Yh[f4l)8!Ik,)iLi&fXjDd&V&[md!GSF'6(IhYmqLe@c+6p(R,'Rb"R R8hp2dScIp'cAJ')RAS#b[Rd@G02&(Q2+Zc+N%UI$k8eZm6Y+#UEP[Y%ckN5LiV4 ,B"Dqi+JR)IpVV2JC)mQTeP!d3jD@)q$AjAVj8G`SdD1MA@hb3GNYB+@*Mp"0"&' GH5NKXM8*pqm%X6$UJa&Jm#,65N)Fc`Tc2NAe!4rd)M1EKF8hS++fj`!-bAU!X0M ,pC&k[EhX-[kFc48H&,GB9pa$`MieFEJe[J+&VK[JaMhr'dX8+YB-DY5$q`B[mha Z@HLI9[ARMH+Yjhd5%R%62dZPpkS&`+3Lr&b,R+#,ADHaj'lr(hLc"q`MHqlp2UN c-`mf1aTqf[2T*`[)dk6Q%4(cRJ"G"qLq'RHfGdp6YlPMmC`,FdE+"iS%450JL#f FJU0`PX2Rc(@RjqLaq1k#FJj,h&XF,@'qpVkR*3bD,RAK02U4+ij&3ZKhA)BJCd, !lV%UCrRJK[@eIN)f,EQ26d1LEp[C%$)5&"TGc1PV#Rr0I&cZjdEmQYqXh3"RCj- 542C2L#k4QNeiQ"FSS80dQ6eTF53kUj*bY1'0Z&R,d$c!cmmPY40)-3911'$CaE$ pcNcZaJf%JEfMh4E1M'r1paY6%+)hV9$*'$fDh`r4i6iGU(LEmpTX,U[U$r4YY%5 'ZLHI@#18A&`0G$--l`5((U02dCEP3@(3lScajZ4`%Q-h$3jcP"#q[j33B1Z"-$N CiR$UiCZmd%K[T3+9hkUmSe9(*d8,-ICrK!N%4hbBa`LERIf3!'MHD'(EPi%[E%k B8&'VPNYL%@")+H-U@kJXlF1cdRm&8[UPUA"SN!!'mlTM+`&c%cDJEP!VTK$pK9l J[l(FRmVNU-@FL)0qc"c*6CPVN8$iQT++5DiH-aT!BIhQHfRJd+D2*B,KF'"H$HN GLQ%PL)P&QJaBC8UkVhTp5V+3!"R4&*-&18"j!X"XMl$A6qYT6iq`C,'8MTe01)( 00CF8mF6R)RA3!,dD4JU[UC*il65II"a&XUee&ImV'c15"f81'a3!U%Le)a$mV9F qQfPk")rG4ljpLp--&2SIYX(@BD0r"Y2e,Ahc6QNBRH'@pIMlfX)clYY$fbbVM9@ TB%D&"69ed`M%T1U-a$j"p[iK'2Y4Gd8%!(SDC1`U,BLr&pUH*"%!R4&Yb+M2Qcb 01V&ZDXGhQ)l+QbK,,8Dfq@XR9MH(R%+rJUlbi5C"'66K5$$dSU30&#,TC*U,TQA )m8"!R4,((pA*iRJVKZZ,f)!S5A4!Bki)dS'-N3I(*9EEkQ%X4efk-@B&MiA@DcC eGV'+kXKF,[9a3KrFr+qT9*5D[B$kP!![8Tf"JTG*M*rrFMJ9rR0rK'dm-mMff08 M05FPqSqmNHXTR1iV*3bCXP22X0"+(P2RRXV1RV2r,"J2UEi,`rm%'cX!3FL'X6@ 83qq[+DibkakdFTE"9Tk@jBBkVjcEFZ#[reSNNrI,Q(6ElF6p+6HL*KFEreCf@eN )bM@LecfQ0VHQdHlTQImU[L89bQeFccHIKlk`e1&R9kTB3aPY40c#6PDFP9,ciFK QQRPcEBc(+Ql%@ERLU+pDhh)hQ%qrTDD1`I6p-$!XJ4m2iJcSabYdrH$'bH#lp"[ CZUcC%dr*Kf@fiP)Nj[l`-Hj-@%FG@cYCYDUQ85kU&TD48TKGa(NV,J1Sb#IU!P% ZNrlD$BNj,[Zb2rJcYE)'qX8+CXe*iLN,Am3[M4@ICX#(i4J6c9A,dR$9ccaj0Pr 0a"KU`@!YTRT!MC`Z3pr$@P&HJ*!!6)b+p`@h&9e#HIM+'IV[0KGkcMNiM@l8P!3 6APN$%5eUfa!-08@'k0ZKaqe9kGX#H%dVMd)5-facR"`dBmhR+JYl1Er!@-jM9RX $he3!)IA%I1b&l(98HVFA"!N$9fI!##S-4&,"$[V5Z2cF#5q[hr''!-QLbK&1rX" KBpi6B0))GHc(`,0`q+DIXih"'K(-A0kNl%"Z'@68Hkq6@h)[5CHd'Pc%,qR!U8e R#`@(lkSdL2pq'#l&d#22b5!brH!)lj!!LfiKYc+)8EFGV9#i5JMAZ[58XHjB63r mL62f[Zmca[p!TdYp'3(5SK@I+0#pKL,A(UdZ+K'99E)&Qm8NdNpBI'M1@V+-[l8 9Bm)bE"@1aEYUD%*8P0S*qU0$db%-*SJG-83SUUT(+ZZD#%JIIP!P&98bj$D!%m* h("bjqUa@Re10UGVFB#a2HRZC3DpqMmQEI'Fi551TYUFZ8bA!-He"fC8SRVX`KFc )UX*,DFK*dH(pZ3EcQ4+G58L1Yh4`2$XmZ1%Q83,Dd3UU*B8UR+,)@D'60H,LRT5 [db"FU*K#B2U`B,'rTPRJr-0pNQpV2f`B83ibKr3h)E4[9dJ5GArAFUARFJ,V[Mp eeL!bI([KmY(1A(U9A5Tc,Dri8SCqcQclh`cFqeqGQ[#T+!G(CTL0J8Z(J+TLM"@ "8+`h%hi&V`Tc&2d8R)LP`%j4#GmP[,Tf``lP$0U-)6BSkNchieH%b*E9Nl&)Y!` (hA1Jri5j)5"X5NU#"-V0kN0*R-$HZVr(AV@2(@l%#i)0d*03*59Dq'k[fqdrA*p H`Hd&6-@b&ZM68i*I'UE9RX'Y&bYG%km9dRd-UcHH62h@p"pa2NZZHUE[0S)Q$1I U)H5b)ERKB(XB8!mZRHB+PBf4-@Nj+Ma*9AG'3TAX"'FZReqrl5-QIUiQ"X!2MX$ ')"I3-U&j8%58f5hhaH&'m-1IVrCI#cdFH9,8Tk50EHPJq'1SSh$0mGL3!*NjmBG PaJ2R,4BpTR$`b'Qai535[hBq@rf+IZ`N,&*RjI*hP'-)BrGXfa2eGMU&`D3cmR@ -DCR0rZ9jR[JJiAerpBK0H9k"mcJe[*ZFlm"l%,EAK,(9a-a9qAUqL5AK#2LV+aJ #l4&`)r9rmIC61iehCS(2YI[3f'XZh54p`L5lRrK3,(Yr(Z,dE-0p64&pC[$-&,# K+',a*fLrJ1A$'$c8XKiXb(Lc)H,-KiXb(Lfp4QBrrhrpp*J(C*BU%["6m%3P*5S 0Q1F*ph-AQb#GIXC'%!)-*G8%NT9qpS$aMj!!*2RkXGp@h(lG(2fl[cjr5[pEdUA eDTrlHJfqVUVlkYV[fl3rYXZ2NdY(b@D(`LF`q3*(cpAFr9Z9qV3Aq'qPp[B0qVT )r9UE[flirYkkIq'kPpZc&p9Che9"(cfU$i4H+qS&[UeAhlGh[fk$rYh+[UkJ[fp +9p@Xhr$G+qhV"hlGT2fl!Afee2UU@qT8!2LC%#DUIAVpi)CarAjBe&jT+8-)Yp0 P`hbN40#Hc-!CAG*GZYa5-!!FeF'!q#+S["(Y63p8ZhmhlqfZRmka4YjCRb"dMT( &B&Z3!%m`GSh$k3*E5*dTGRVdAIF)rI6V+iMp*K6idfT-Bh4IPL)5B`8hpLr-daI ZX+YRD8&a)3+6rfP",V@!(Zq[ZY+++Zc0-L"B!YSJYf$5*RRh!NZi!ap)Xb9-!#F 2I68U'UjN,B5Xj9l$#l+-0kBNM8PA,F,p*bl0c2dZ00EbRN&m)aZE([&P8*`1lJ$ Zi!l`CffDeU1&6Ar6fK$rK`K`1V&K(FL@6U$#6Epb"-2Sr`HYZi#NeF5F[qMP0## TZi`,EU-,ZKCc'q%3JB$,r8$UB"NHcMFZmD+04ViS,Nfd*$DiR5m3MKq+45+B#jK Qk@B3A"!+J6EkcK"S'IGR$C6%T%TN)kF89hG6N!$JepFeG-`0"rprp8L0!Uf8$3J UUCUr4-,ZC`@m5,PTc"LAQbrUT!A!UQ)q8CERp9HeT'IJZD#hA,D$XSXS6fUArfY PX-pNCNL`[F$$kpT2S0"GB48$r40dl(K!Xj&Z5%CF+4M6!CCBi8GdH1LlMMrc[&J !b53mJJ"rXqPT2rRC!ZcSfUd$lGUA03*mT2pPJ!jjP#@UcAdF5M`a1Y5mlVT*pfJ biH"F3Qq4ipGr)b-@3Mc!U&QRRQ`((`Jm36X[-HS*3HQjLI*p#Zh*NP$D''f)8I0 KdEZ)jNfZ`MIe2K@f-Xkc"E`@[kc"E`@[kc"E`@[kc"E`@[kc"EU5I4+I+aJ[8H[ UJfGd[*L6,%Z"Y$bBa5G",5YYBi#C!!NiM[ER6X$%),fhpLNe+ICIp(cVhkZaQ`# *1&S9bb99cN$5-Q*V$CbYYUmDE@IEQ,e(H!6Y$,Ud"iM25bPp*Lpb0`&%pMEBjD# iir#MU9[DHTX`'eHcq0b%*lp(!*d9946i4@d%aQ*DGe2i++a&!Y)H&`VFHQ8#mI5 lk1KLX[0KImkr`58eGd'E5)-qb$abP@"B)$mDFf*iad1MNMIN%)Ze-V1@E`pMAAr bJ4JVJ%H0&*1l+1N*6B$k'K1[6j!!3PCP'pL)&,VSiPFK4#eH#C24YY,ke6hF,"S #bTj#`JJ51CHcH,PGKca$N!"$VENXVH''EQ`@BL`IT'3ebTINk3[m9YkK2,Z0mrM 8A3r!D+!NUGa$H,CMUi9NGUb(PUq2Vieq*Q(A*KIdc!F93,M(2A)l%*hh`Qd[4'% )9MBRTGi,f'f#$*H86Y,j&#"CAL[p1%Z[3b*%PAXV(D5LP5X'2VaFJIXMI$A`-@! A@DQjP4LBTqG"A`8&KEA1Qk(dUmNA1bH&*&MQ#@fjhl2lj+URA8V0JfhNa(QaK-k 94km&Q`@Y'$+fCm!045)&f2Zk@!,J2YEhYk+kZ,'TCDAr09ALEPS%'L1A&5frq)# PARkDJ3[9@C0553U,ZcVY`bpYAUk#3"h"hJZ,Pk[eKIK*J0%NmIm)S`MPGX,20Zj f3XmflRC#ccEZGMpS299k6K'I0!ULK60"J)BeN!$YV`!e1B&+r$QS!)AHNE)"D(2 p6Hp!&V$YS$S4@IQaXUcUrac-45EIYZ6HmcNh[-j2,Cb'Y-(-q#ek+0&S"SbNkjl Bl2LCM!UiEaB"`GVeEk!'j2AcI0mhcI12CGVVE3Q'bH+h9B8f"0TQ&PaDN@6!3LA )ADUd`X`jSM`Qq)6D6B(,SYN[jQl1am&)rhdRq1'kZ8NCL%[rGqhPXaU3!'Z+aU8 Cd4e-,5**cb%650NR8rpabPQY8p"EHDQQ81ZFIJAUh$#,e'YjEYES&Xb!1@5p+i+ ZaiY@j1GRebc3'@5U[%Tb)[)(Qe0JDibTZC*dTIJmf!NP',RcjSU`$`6m#j%Zrd, B&YP2+jETKG!lqDS9[#C2FNJ[`,CNbGc"q(80UImRkRY($9B*P%Ff!ll4aNl09F6 A@h%A4-@'BEB%!G2f#0,+'6RUK5L4$p4J(m,@3EAq"UU1"PB!&qT5V--N-8D(FpE hBiNY60**34'kJ#R%fPcj&K@rZ(eK5cM0@aVB0$4"!699kR005+N!Ef!3!!0ZAqC la@e'QkKmXQMVUhPh'*%V3!QV!Cl53,638lcYGGaJpY[rAAfiLP&G46F-&f+"!Fa a#M*RQL3@3+eBcXhlMQR`4+M)4+B-9e&GUf9m6Yl2,hXiq+`qkpIl('[0Y+JHGq! jcS0q@)j#l+bpSdq+8YSZbH+1b'jGK+pG+$46LYfRebL6'#YhX%#11E1(6NAY)VD e6(Bb@mMUMIH$PLSIc'e5V8*1@'L*S3VNkHbmk)"3,RqbpfVDN`kG)'MLNTP2p1d 0afAm05&RfI*jUE2@kdE2d80`[8cDrfHER3RM!LK'hF#M(@cTR3T4kC-)r!,cMD" +PQGLU&PT"Tr2Gi2eckKU@8&AHbfD'*jUfrGjBjaSZQF3SkR(P,S8JC!!D1)$m@A dA03qf'5Lp+!EH-&0'(LYEpUpBabAGL",HIX8j2$,`@)k#(bh$$++ZrVi1b[CL@@ 6Ad'M(kpMQ4A-)Fa6!PBR1GU!N!"`)3VU+1Q)Y)98ED9'6KTjeVdjcq$R9NYlX%C S@`hUeDpVNLfkmhR#1$RB*04H"9J*`XCDQGU`H"$Q998N!kY@cdFTUm"82A-*(J1 kipYC$VPH#rCFD!Li5iL[LTQQUkLaM!8V$`YRmQiHJX$p&CE`PlC,lTB1cC!!Z*L jdb-k,bM$b2$QqYGL*!DY98j2TNacG(6L&,'r5[p5Z#FS[JXbTI3aYf))qVU)k!i 8I+$IimZmD%k2edi`bYSPK,8Cm4)G8K$93`bTmXQGPC1&0BKe$PH&JLcP@0'YQH9 (Qhm6Apm*Ycr@0K#Lf#PRLT4045)NL6Q[m*!!dZp86,&Zm"HdSmJ)K'U3!1-M4AV )J0lRa&6Ul!@pMrCdi88P4@!FP%9[@+ZUXkQjd!*I@ljC6SV*l@M!j@hbE2cc-&D PJ1%4MEB&[lr4Maa!0Hm'$`plrE3aqLhCR#!ad&e)#ZF#"V5)iaFR*K,ZV8jihk0 A-m-iFm1XV*HD6ZQZp&c3$dr[%mC8c$TpZH,1bL,G5LlR@G*4k,fIE1Y%UJqNe9H G!(X0(MU#X5Acb#hf1X(c4T!!"L,$lk#(Cd`BmJ+$TARe&i#Y!BaC5CH2h%Gi-D- TVUm'h)1LcQqLH8R*k&C`SqY02bdVVJB8i#k-DfUrXKG,+TR!96QY39M6T&!1$$S lKf'V1a`iFP)8%l'U'kM2*+p3DFJ3jM4BjK1X$Pi#B[d1qMrYk%mVU`fe4SB[*)E @e!E&#mpa-ik23N[%i!VqS1N9'aAU0XKe#r22'b)pmV(%FJ1RaeE(X`[TmB!-'b* rQ49YqN['9VSKAI6bl0MTM!"lLX5mFef2QK&ifH8Y9!DXjcFe0`$ASkKk[1IIJ!l !c%$EHpLF+[4XPQe&#BLa@!,#Q*aKRmk6NMHrYPEScc9)'ENEGJA+2[Q#VQ9YGPe X!l3)fXr&)#6LC3p0V-JABmHad5F2fMk,CMqeXc!+d9@R,VR$)L2mfFekf+Xi(Y+ PL*c&,0k-f33l(lb2%R1JZ1[XLk"ZAhE9!NDa$DX9&i4!E5TL'PR9cemP&e`GiS* kHmZ@TUmEZKadKBblEmRX(Acf9Tm&r8Y8Fc8QGb`HT0e+*aLUf'J)EAf,03*jrhr dT86,B*j3I"$kfH2hkC1A4FeJ`G9c-)-SKCD58GfQJIG%YH!N3cH(L0l6D9+E*dC J%4$LVHBeX&(IkdQ8R&r+eF(2EFXlUVmSLaNr3[J&&YB(0!FL4AdJ3@V,aiF#+UH 6lc*5BGQT0c0N986CN!$PrUHFaD-Gh,l`,1J2!B")2l3aBY`R!)Ge[PH#TZAD1Q$ "D`VG&Q+80X`(biZm%1)+K'U2A5E*"`&N,!@Ueb)M08PZQRVHN5P)hTGUZaAUE)1 )`B6BJfhbml13!)RhLCV#40d,mYTbp6l-H1#S*qRp3-"TMQVadk`V@&T$#!Q#[De -i25CkVGEpD$&C69p$m(T-T'LaempdCITNk"U$q%4RQm&aFp5K!YRSB!QF6T6Zlf 2-Ip3`cr0MG*m6P4A,%UL&J'(283$+q@bDGCFJGC3AeKZSr$`J#i)fpMkf1RYE-J 8,SHXIjJ(RiZJ%X@"0D+8P@TX1MpGD0VbYPE`iGM-hbVRK@)c$BBm@@q@FhSG&aN d"2H-2a'm)hSB0T8"5'GCF1R@9ZcXMdb"FbB0R)89bZXf+G#KfkXF*iC9L#eSKb) "&i)VQZJHkI2*Lh-CKjrLJl`"Amp#U5!PbYq!eYEG#4&CG4jjp$B$bjkr63-a[JD TZZX'SXr(pVRRc[`"5d1B82EJHkPrP!Zc0U-GaF!A9feeV8-3%f1%iR#bQ$a$qmc ,Y,*GhZ[F$6e[ch*#aR)bq(iEkPT+!X9MSpY[K1D#&l4fIq,hMVBM%(9%DLmGGXp rLiB#rSjXMQT,F2cRJj-2"Phbj*(hm0!6kGIFF"3S4,#Qf)'M`@J!30e[CmZ)+E! kl2AMG&EBA!iTEZq1B8ATkRfc9raNdJI,pGX$mPlPiDhM#ZhrIcL++,XR68CSMKa Chfi+'*+ilX+QBEJm0m#)4eYr%P#pJJ"cUV8k6I1'N5`&HifEEL'&+B(!0UrD"Rl Dm"d%rXK!j0cSMKT(rNmH5rC)!411,PSahIjkeG#&4+%@HmDe(*5dh&SPS%E*M,C I,)M&R#l-q%j)VFK!)0$i2Yq@plI#(R5a+TYq-L,ip(6`[!bGmm51mB[a0Xk6mYa YSjS82"EbBGHIDaEN3U1f2d!-iQDIh5XlFC(HGLc%IA$Uc@f+MKKm0d@JPj42XND A,HPS3qQcA6jX*BZ&6rfpqb1',4,5,qIeS'%qa(IiZ8aHfU["(j!!k-0*&ILr%NS -U&L3!&$ilSRe[$F)bI($1jBK@RjVbjRfaIZ1V+Rif(rV5(k8j%dII!DUV'UZj[% *4hk%)6!DZcc(ad#IXe1bV1NLF@*8Kr8F&IG$(@YJQQfNmXLK,YN'$*3UR&Ar5-G B4ZM[cU'd'YAqmJX9mq(hG%RPPYpqU*`K6TQPcFHeViTa+CL,*q1ZN!$iRQ,p)+N bXY+h8'jR,TcDUap%iE["@#S!"#GdP-Xe'Zkr(%&QND!`hfNliLA@3RpF6q#A!kT NSipie+R@Y)YZHNH('Z#Kb@6"+[RVBXLL4-#+,!2J!K*-4,p*)3$K9qmB`Cd!hM' [b,Ai-+rLUh$*1FRjreX0hQ-B-4*'QA0hA"'Ikr8c*8YlL$J[N!#d-53j0Jec-9@ dZQbKjT!!U0eTZh9H*2SjpqG6l@H+TYfI)[Ml5"H3!0c,l'3H-RYG(-mpp&N6VrM E4@250!Z`FZEf1c,fYJCi4R6SXl)-3E4$dU2h3"P8im4j,88EY3N[M%Xef"S*Aek Ai!2aQ3+5N!$kA`P+4i4(Jp'pF4-j%Z-Lh"S2Ncq'd+j@(YQfTkFH3aFJr+qc6`Q 9"(R3!C%EfL5cfV*"C9AZ"&2`HC'k8[e0*m%jVH+kZIpMjYG%$Z-l[6`%(T1B62( iYS0V+AT'BfX)EZ`(MqcE*)F`)*I%I@9jiec'[q`VVqU+j(a6@f3qk+&-6l,qd(k E12p['rHF'DECHB00eVKU2S80Lj9'I@#KA&IS1J`dRG)bj6Y*$2CK)3Hfe1-D"R` bC5!!6Bk5U'"%8Z!lr'!KG%e"q#Q,e65M+8IkVAmG2,R3hj4e`EKEH[Gr1&X9@jK jBl,e''G,cP'0-,TFDM(d6m[bCkYabF$)5'rM3h5Cf@)0efFJf",,T69aJh3Z$36 b'rDLf(a$EFI+!`U5bKU8H+"QZ&"LD0X["X@P!P6(Hb-ULYE"H$J4*X&%!#,SibD P1K9bT+j6AJFZ+cLr)*XaYLRlfC6`d`1M&fX#6Kh#"RaKI)*a9TTVQ8Ujkhb#LVK %p@i"`G25HYB!'!M,ENi,H-iqJPc`p'L3!+ma*m-Mhl2!)R[Xl0C[(pQP[XH!%D) i&RcH)%p2R"38b#i+Be,*A`H)8mbe(fU2N!"G@+!BYk#pb!HUNUp-E3cpDU+V5+, V3d(YVVKNcA-&bfC+KGj"Vf,p3d*&f+pENd`5EYiG0r+[i"DX%3*a2b5Ak5G%Ql& UYL8cl,LSB855B09(mPhJBVeArhZN@E)"#LV1GA'FMV(MT1SjJ*JVcc$1mK+1V#J F2c!!jYUJ(6U''KHGa(iF%`c!86UTA1j#La)P605%"pHjP-5YqiST!*!!5-[G1q+ A8!P2CX)"4p@bl*dA80Rj8#h%S4%Xer)*)jDkTZ&hXp)I[TRmBKKXF#')4VH`EfT Z8`)2XAi8$Ta*&&eM3(*jK9i@1b(bPrAmVK,ZfUYY5@+c3ffkC+YEFK'1Tk[BqEE j2b4,a[)hXX'VV*aZFYMjC0NHK5L"9$(E*6S1ID)ma9CfAU+YkhepZ!2eIGNjJlf Ij`M`4!hC[P+)HX*C-dMe*N5+8pHf)X-dBP%%55FF*'(LN!"CrbqAl-)`-Cd&BqU VEL#N1k83#hp1I-"p-'L[0[9IP(NapMacRk%d('AMi%rqZ`feRlSEHaH(8a!CAS% YqhFMEr@iQ@cEQH6@[ZMq2iqJ)kUa5ajFjHh"lNCLeUb*e[FbUVYCZ'3JlT5%Jd& P[*N%NMRabPjIjlD+YZeS`q'-Yj@AU(T)DH!JArI(YjMRA,LP5XU5(1k'IQXX'R1 R)!j5Q8fqr0c'9'QK5cI-cL(THLT(-D[Si-X3kJqFfMrIXL&$Z'XVDP!a''B,bpK ZIP8SkKTT('e50TA"dH+K6NKRDhFGYc%q3p4"PaSN4e2r1KLQkV&Lj5Tf%M`0TqY qe(1UB3cXpqf--+!4E%lFi@($J%QPef3,XQk2A1EX+qP6$IMci1UP2ZSLJZY85Tq [2"Y"-KLrSFL!kr+b'*RepLDh,(PUQI)TlCaR9h8D)3G&Fq4#@&H(V0P1+fe1TH2 !Rcq@"@V#`YJ$hrpa,H'E[E1Ur4r5aA1#U"!4#i2RLX-U1[)MaJ4Er6r*[rZq1m5 @F8ZmNH,h@a&9'5*&`LcPGAEYlD6(plhQCXdq[8[YR(jVfdJ(5ENaBhM`HqaTK[) -fP6!$CV[M`*ErNq5M%JEikB,qCj%PhX18LrSL,FBP'@5l5,r6E$TMQ8BEf"YrGj BJRED4kY#K#(pb#b$P8ldF6q1`hD+SEqEG"jYIErfd1jceahJ&9`3K-HT)GmVE$j *D2c-&$XMq4Z$PEb0T,-c3'Z!mN4)Le41-0m((CcB[FP5Z4bU1#NYI1rG`,GCN`0 A0[[@Qe4+[)GP2(89-@STM1'HA8LE+(icPDclZ19HjQpK1kpDNR&CH*Di&1JhIA5 A2d!+LG2K[0pmZ-QCa(%T1)pCc1a55(HUIp8(R,pkcY9@BBlX`iH[HE!BF[Kkq(V iH[Kkq(ViH[Kq2Z*0&b[8db[(2*c!'K5drepZ!2l,34PV,@@XR#96aN!`MqNl9T2 i,4LF)chAGG($CApLC*ZbY[4T#jQh&[KLG"&$1%m51,Rcq*N4EDTre3HF[hV1e9C KMZc$KkpjX"Kbq(ViH[Kkq(ViH[Kkq(iqiNdA+p66+mFmR-!D&,6rAfi!rXY"'@X YCDbF-IJqJUdD2$0kYU"A2e`5pGXL9cUC*S#paiGY"I@!UaLrZ9LNVUrEr5K&*8d 'hq9G`2CXUAAl2-I$f8RAYr+mC1%6c"5Q+r,K0BAlEQKRQI6QHQS*I%3A!$&e!bG "hFJm84RB#HBZcE31YPeeK)BI[K#NfMHB-DiK%T(DX0$hV(k@,Pk#,#rA#f`ZXZR M!J[QpiRf*qr`(p-*-JHVTTf[Km!L@R6Q"3bRD1*HmlSCid8kdX6p%h5ELT[m5ZA i1Y6Aj+me-khJbS*X2Bqejl&UrZB[TDZ6AZVb)d60lcXcQG9*qAC"J1jA+rL9m4c 1Cc1Cjl2Xm!&+m%j9YaD$AFhR3`E3E0#B4*eqUTC@*TPpi6$Q5IAVN9*VME0'ME" 3622-P'LZH[6ARYKCl@ZDRB68)KY8NiMjQa0rqkFH"H)EieZ1KaRYFVq-VV*#NN+ S%"&-[Nk#*$JGG2l3-23UE#BS*QIr$63@fLc`GlZhCmc,$Xf%UNU0@[cq@aJj,&K ,!m$pM#4p(r[0QXDCXG,X"ABrNfa@Zq1Kl+I2DmZU@ia+9H@"ceT'qH8m4RfK85f lEhLJGpM`6kdhrTrCe#0&Y+k!kTYarSV92a,+DI)pr&V6i$H53#(b$Tj+3Zh"T1J '9%[2Bba+0X6[bRM4qZl+6`Y')MHQa`(mRh$KbALAfCGXAZcT1F43H4q`S3R)FRr fb+UKUT`mf92A%j[A2VhdlIVRelkG[ed!-CpDPJ1#FL@FhN%*)D&ddHhh"jJ+VRL k6ZfXa8'b0)ZE0-T8are@'d'!,(lY93@#RHQ"%9jR)k5qYU(#k0F09kGqTrI&0PM CBf@0PMCBfCQ-3#CJqT9*@#@1'S#YHciJ!'[4Q@[H!1k0JVh8#5A#ThfGchfdGKc `%MBjbUIF,R[!dl+*dIm@jiEh!PpHfKZARGGmDMR'FGX)Ta!GR`e&"93AX1A4DNB GQN43abT-`&[aQBP!01(ha)@A*#XHQ-Ujf9HZhqdHJHA!BI2iSA1$HDL+j"E2*#" 5)TEBN!"[)lTBeR#*2*e#bDIEebH3!)TQk0Pf#&FAGj+A*aDV$Ad56Ck5Ba#-T)a NZX8Ja3MXkA"hPG`rFUiY3bh`@N-%VEc[,i32UbU"`r4l1#H`,,E$5DA3NkQk"qG !qPa3)&AmYceRfH@[6DBr)&)&UHF"I2*DjHc'GFcNEe8GmT(4&D0MQ&KYeRDGP*0 UeFQSTfb[R3Cp@,c3B!RZ9-*3450'N4@MDZjFlV$HL13)F)a[SHV)NCcVXpk(QAY U)i`cq,'mLD+[3E-#i[2"3KTY[X9e@Jp((YEkQ`mXqF3apA1A#U[[kE`dNpaj#k3 GVZiVq*,49S$(%JRMHa6fP-m5ZmYmUMp9'R[LI9hH,p-6G1UZKTm[fCX8KNaqi&H 02&E8LqH-(@cC'&l-c-3Rb16p,jpJSBCcKN0Xp#Jl+PQjkG89DE@9$U3c1fV5K5f el!Nk9MAN#6T@0H3*26"eir9J#0@C%c2`&"I8RL86f5&h04)eTP4Ef+H@SpF+U@* Gj1G0JMc3ETPa9"V%&%CVd!Xc`$%jh0KNmh6@e,PA-ENk0rYpN!"AZIlLMfcN!Q) ii#EC1fdm+fkqEj[QfI0LNB%MSK[a"Pk8frU[+D&Lf0FY6P"KjY5R1T`V(BfJ$X* rc6QYMAkYk(Jm"[[h`p$%$rprV(0cZQRN"XNBRQ(qq+hM'c%0H6SX!pfY*ak+[!, $aAJp6%NHBh4TVe#G+cmI,JDHHG[HQ0UQ@#5i'bhLfNEmGSM&q$"Zd!JI'fqHP1Z 5QiiFbJBU*bqjGL*LkphK&5-k&8Kc6lrGB(ajm'l0i"jJMGDDVYX[+CG2B0pQR#6 2SXi8cZpA$BGkMXV(b6'4MhL+VSTQ9*f%i"DIG4lI"b6Q'iF9*HP(J6EN02%8cjC HfM+8Ch&-rcMCGk5EbK8-[H#Xpf0%@hNE($6X*Cr2#b[NJIaq$L$9Z%XSqP--ARp 3GB%@`be,Bd33Fllk%0024f(6X"Q"paJrq"C[CM4QP+li+6m`Rlj#p*ad2KJ'4ZA 5L"$-M1-TQ+&HF4aIU@F0,RKqc#Pi86bj@hl*-VDE)&mSd2l#dZCVFa'Rdp#S(RI H1bU'dbCM&CAfIdXa&lV&$X!Gie[IeVIKVk@!qc0Kmj'IlX[0N`+))KZ+k`U#b#` %K4H#3ZR[LFAh5l,J'R5!ek@pP#MSlDlXPQQ'TVG)i,alCiVc+1XLB$*mbI&dXk[ %R"lC!J@TG6BY9'**,GhcQM0e)-hGL&6B0B2#@r&UKAbK$G%Gql-2qRG,-drBT9P Db1fcY@hT"L-$!P5"GHd1P9%J*&GRHkV9%J[9`eq0VSGGhJ'kTfi86jd,,Yr+,K' ql[$r4I`ER,0,a2BRNGGaFp(C,E$1CE'@14MLlhS[e,hJeJMPEE"8mdFP,"'LA#T 8bLGVhqJ&hQJ8$mh[8"fp&d1@eh!@GZGh!lY(*N+eG5rrAU*RED1(X,rIH#'d(-l eT%c6YPVFmF)Vh@I96Yr$`h%f![!j!ed9lA-AUJSP#mGa$`2,cY6)$c"[X*VcEAq -f$G6Fr%q16!dJ486D"@VmGX2CMXHJ*dVC&mReG[C5l%N(U!H[e-)1MFd[1$dc3' 2+"'-8j2[XrkV9i+khDS1%(`X#qCT&1A*`f(YF5"FQ(6qpS0GQk,HGP88YCEDiRG U&-`[UR[PfSYS0%SMI4FZKHa``4eE%fj'!qY-r)8!&RPLI84jP"!*#fN#UJ`!Q&0 2*MYheME)J5MIMl&qF(MGm9E&&'RVQ$Hq#VZ[T2a'i-eJ[j+!`i8QHpI'**E`%j8 +`LGe$$BqMJkB8`hID%#23fQ#b(d@2IYhYl))R0MD36m#a)e-a3'&DZ2(VBQ!HYL HSSdrFf0dS"c"(P8cc@iIP$1p"`1-S@VGjlj*NUc5$!5br)clkk)i8RPD%P,6T&D -+UHEYG6&)hMD8aDHl4%-Y'0j-iVffeZN9f18i6J"NZDe9%X#VS1P$DXrAmLm['# "E[-GBI`Cc6)Uma2+N5cp,q&S#cI!SrfXm15f&ear-Yr4A2EK!ZTh5Ue"FiL6E** p3)&)Q$'SRjTFC8IA*J"!U4Z3!)Q)MAj![`(`f1'L,fYPL6HKMJ8MUL8-*qJ`eS- `A(Bq&3R+%lqCqY0(TC@HZQ!XjV`r)TlFi[+6%M$kFIT(+&jiI4p!qFe&k!NL"fr H,`XLX83[(P1dXi31-!0HA%6j,h4Kr'IjNQhb9kN)`[jZ+3Lcf-pIP(k',Zkeh`r SPKqp+jdQV#jM,MjjcPYL-G3qi05C2C`p-TR3NL6VM,pNZ`hNA1a(Ba@BEmrKB`9 FR'R`3XcEXK&Blj!!NGBQaKh3p)pBB5"-iJf@kmp60@)K3&e1$X!pVXYlS(MVi$C BKZb*R31'HQ*MAr%$me"DA8X"TV04KrjcSi$PQ&"A,NBfecVe@%A!`eH6J)1"r`8 C"GBdI1rBm$M4CRYQ)Z"G)d+AfMj&(V9pe#LUXS"r#)mY(1N2bVESle#'0$UL#R4 JlS11[`%US"",P-@EYK3+dAiK$Tmr9p"Gb%NAd+DhV@)I30)V9(!b(6M0D#Nqdeh 3NL[X90mY&BLa2k-bcAIlr2@+@!"Xh+5T(#c51KZ!r#%Id*md5&RjPfpCmeMrG0' hV$Cdb@&H[DX9T)Ac)#[NFbP%R8k'i[6D2NX4iLZDq94(P`%H9K6r05G+2JQI3`b $EYpB[K20TFSlh35cYqYEDE2G-U9l,9dkbmAh2DQSJKmimh`b#CA2A00Rl32b0"m 4BZ%IZ83MeJVmHMB!,E)-0$9i(RiE8BahS4K4CKF#2aS&c[IZCi6@[q33UA*a4XY djCIf8l8bFDCG[`8mQ8j!#BZ0%@h@Q3b%QeG#@T)G%JC)I1DDE+ECV-CZQH8@6L* )-((%6kK-'#DXI&3hBP+&&N"3-*b8@b*AiA2ZQTi-KN5N[DdGEYb!)'A16&1+i2* pcBajf@PHE#1HYQ1eFf`aJi*D`&m9XJk@IqcSp$()*+q4Sp$Y%qL0!IQCE,G[iYL 0@83TcS24l'Dj&0e3L"+j4(IbNfC`mp8)B-iHE+9R+FhVRXi+h)e+Se3KbPH*Zb+ "KU2,+N9"e*ai*emE'B"UJ(dMD%4J+Nf)PUP1fJS%JL5AMIe4rLUT8"R6$A$NH+- lb!BH+FjhacGfFfjm'pE29jPR)3(AQll28-b6bU3VE$,2i5UaX0"#SQe2U5#Ti%E 66b6bGf0CXcTP"2+pd0a65cIKiB"[3MJUjEkJ"'eM95`r'S4G[r$VT0%[qcH!BGj JVI8#bHZFrR8(2J8N,)4*Ga38k*!!MdK2XNdUJXR`f96I[r*j0![9mT!!Zq"kfd, ,c,[#c0)h)dTi0'Mr3TQCZ1)G4Fp2pV&4Erm8f20@p'idL1,E(FS-&XTiPS0jNV' pTfPC[$2GNhqphdB'eY+&1380J5mPj5AqlP`dE,&Za#fH1m0)ri3+L-'J[X#RimF &aeVJ03CH9mA-$KYh-G%!@@b@(e2aMm-MZYUlH8e2(`emi3m6iDqFIX0XGKbqCN$ "F([bTYATNNKU"a0Ta0'`Pd@VKpqMQ9"Uc*T@HX,!jcGT#C(3H#lQb*!!H9,8F'c Q[bT#PET-J0`9#d5Mq*XjZ%hVl,a#!TRj[3[k1qR(%K&JmE9K*1F-e9ar[lMM0@+ C'+8HSBG)KIFTaGr8q#jTkBaJA)aJA-4LA)aJA)aJ-fL+*'dqZT8"IHa6UeB,3'" +`89CrV0+jk@Ci2*,22-METTJ'Xe2aS#q1NHimIq'fmK6%@'MQkq@khG@LU-LRk, acL0,rYl"fMCcpP[%I2Np-1EjM)@,$6!p1$kEVY9Zr`rmk11S@pbjEk!)%iaV-'b @hSi!bIDG@rKjA92'TJh83,!M(LT+Y[!4NKhI1hl)KSf@HXp(2C&MGe!"8L*mPC* XE3bK'p0N94N2kC@GTCP&Xi[0KfqTIRkZ5Y'S%I!YUhj&3cT%9m1F2S(+&FMIiqq #&R8XXikd6jG*#[8#hISSiPEQIGH$+G-c@eD,4!JZl90`0iD3!0-f$hd$ALTlFdF GEj-66e9aEC!!GPP+,!fDVi9XQk9DQ924L9U@HJKrRDlpGQDU'PP(Tab-8@2UrfB #`K3DIFQ$J+5fY(5$UK3UaiX+Rbc0fFIA859!ViZF#JjP-6(2%NUIafe(@*UZ+'[ bJL@"UHLZh)qqEVNT@M(N*D[m%T*e9alkLf*J30p[-"BjTH)9iPQ&U0(cm!#hVpL k`mER3LHBqYZ)$8rL`@V*jfSl(5%fN!$Sl[c!19Z@DG3Mhbf9@RG1$+VFNYkVFM+ DPe1jXH"pLk3aL390l8ha&#V(9fSe+82%mU!EmrKlEM31#Z&%qXr*2!&@)!2b[$h 30$J-e%[Cm'[`#Y0#4rPjDb$F,dhhNUFdpRr66dRdcPVpPrbHHApfkRGDX$"+D9F V*HkV0JbMrF(-J#,Rd[+c%DPH3II#,K-lZPj3'IpNYZ9*EF@*!9JCQG4F2IE`)&8 8QU4$p2Fq9IP[d,0kGpk88(kpc)eN)A`YR2S#Cd!p4%)33'jX[rY039H9Ghh[c%b r-q!$h,KLQ"YcK%aP0Srp(Yjk4Y*r#+paK2eIIYRfj03d(p6('NDfSGlVe!M9ZK* 5KTEJc1"3FJ5bM$@0"8J[R%eaGr'+JHD!a6@pIchF6AGC(FJaq1Ib$,KjJ!E'XV% eKIh!68ISi6LVLLB-&J+p2eqKTELdLm+DT4-cS59!R"5J8KcpGN#J1XF4%QU(50i cqJ[Nlc)SB0RPU08Y&[TY9@5ZUY`@"p3(+k!d$L2XjjX##AC1"@p*#+28Y)PY*jH k2JYN@EX)h#[NSR84X,k19palf$k9f6Q!kKYVEM+!3c$++6Tm-&9j0G(d9J&PmHP *!mF6phEkCVQDi,Kmp@0*QMa@YD+Ee8$cS9&UjRI'dfM$GIhDAr(TjHVKm[Hp+K[ qcNCN)-RK)0mKF+qiKHp5,C*Flm!X!alD@EZG+)#U31J3kl(VRGMiKV-R[GdY3(i DH`3L&RQ(G3$[(aY1F'0I3*@AVD6XPZ+[%0cP'dV-',+E50aX3eZ!5'a4aaTk6D9 G'(f!A*!!5Dr9fQF5r`8d3pkpq"eGV`V-HUiF&)2DQK8mqRG`ArQdZEPUl24'-aZ YjXNJ,`8eN!$Y9mYSl4kRQTdSpP*P9'Y'VeViF-U$5LF4I1)A`TV-&E@N!Q'!F*, 0qU[0TD`kRhZ(H!+X0%)X'I@S6R(j@6l`hDj`bR&fTZ85(M*GmD+!p2%D!"*N5f& U9Sq@@pTcmUF6RJ@DI1aEAXEQlB$MF#Q2V0E1l4i++8*R-PmEleGN0h,6##GbSRK ,(q"Y!m[b('!kR0cc'#M0YCfBSN)0mKaT@CNE32pRm8Z$C0h)dHTB)GCK#pGJ2mJ Yblm0SHPX+qLmij2r%Eqm4H1$(f0*$D8Z+4f(MM3"'Je,A!T-b5MB#l()&Ib,V4R )!3'j6bNQ6UKPUGQmA"HpVE$qjem1A'c+U%&T(Tcqb59%!#$BTP9rVIc*E"V6NL3 ,la9BVFk*i%D4GHTefm`RdSCjCa%e83PJIj5rm"+4+AdA0Ka0#+TaTANFFiRaJCS 61Uq'+Faf%Y3lm!#!K'rYT&4fhJqbr"Q1!lk4c@pX,5&U'If8+S$B2GfdRlH0J)5 &I2I%ic21RcqA'Y5(@m8lJPrU%+TPPX&!`fJFf$@#DGP!Xq[Y0##Dr#1#j[ABlp3 m4mq'*kG%N!!D5T*k44Nb-6cBh*X&5qM"`Fi[jGPN#dbd8,1$jeR5L$e1"KijR6k V$RMrHi'@&k!43!5#1eV,Z@*C,*B-%-TIULA,9N3-A80%AN-jK$'F*b8k89jZa!l jj&C#Ra*T)mJ[6[#haCT4h"3Yr&Q2I%*&T)8&XA2YNTPkJIS,d9ME3Z9qrA"9Cd# l$N,Ti6jBb"J@ZimlANPMpP1-TVMekd-`Xl[2dU#'GURZ[d@!"CNcJdR&5Ej#d[- f-JZ(XjaR8-"FeQZC(&I*V#Nr2aA#4pj'C66b8VacIiCJUFH1PM-@2A!kZ*YmYH* Z4L1&5cI"i,PGcM&bmSi&-``-a1+mKAcGjDCfZ1PLk)JQ(pkL-$m[P'9+Hh!+TMl (Q![Y&jl+4iRaZQ["$JH4h1ZD6HIf8lNTBf'*YVBc&-,$SlkE,044!Aeb[VX#+j2 XZrJXpl!Dil&ApBY2YhNd"1k#H2V6314,Aa"i6G9S,"pZI(`I9&`L@h2,j&-1@pj Um2&q!`)T11QB90*q-dSh6haIE(61ZFFe-CV,M'PNp'FN,UV[pCMk3L'-L84Zh)d UqiX*lN5MlQ((K&Q#S4-KCJA[Ppd0ImijiYcS9NDJph!bb6EX`"GCN46a*C-h"Ke 6BR'iSDEa-aG(C(M'H6`EUQi52SaTGlVFSImE4m8)TfA9j+l8Xb4VH(%Hd%"#j"' mmGY9P!$+ch)m@@04-4d*NLmV+l%JY8H,9Z)Fm)$Ip(qrC[VX,6JECqrY2m2J,aP ,e4HPL&D3!$kZ#Xkb+Y-dGK,r($4f0j`),)q5lrRa!iU@M*VTMqKUlR%5k6kVFGk R45i@Q[5V3Kri8%(PrcMcLp81H2-1(C'H2CdCFGA@b'Y`IZ$J&Njrbp0)*%jrTDG VIa`aEDF1"S8Y2qqh!(pPS)bePV,@@XL5A0S"K(p+3IYIFf*N+dRU*5D*C%RbJqe @UZcST#8Af'3%EFfaaFe9acCR%MLjrhriQ4'!2kP@c9`BQ!#C8)'%M6&"D5B&alE iGphNGBhDmZ!J-l`pi5M0C0Q0crBb(M(5!'UI(6Kb3ar[Q(*&4k#)FN-IljKb48H JL(*$(qqBHc,)J@Je5'mcrhrp#Dk#3dBp9$ic![`[`Z5BlYBK8Fr#IAXdjD%!PGj GLQfAl@%4HU,aJkeK5DRlkD4makSb8%4CM'!&q&q&q&q&q&b6*D0ZD0D!mh+)C6@ fi!bBfa,+EC!!"9XMR'QB+K04B5JZUFNRFce8X)LUC1kMNq`dC&hdjQZjY*M1-*9 S`a8IUH&pi3LmQ9-L$Hd3&3@bCbXEXE8+(DreSN5S39`S6YLmVi$)r`%PNTq'QJX (,@llT0A`CG9qEfKqNkSXdN#kLla'm`biUp(J-rj3-"GM91-6j[!bJhZM,bCV4Qa U58K#ZC!!NIBHR,m'-f+eN!#kkd#8BimjKc8,C*8[d6AD,)8rrhrhr%r@,rDJr0V 6kcB4j@rY4&U*-mZ"kN9Z1kNp9k[F#2JkC"3paiE@1XB+Bd3iBI)-(''Y8+G9,AS rf0Qa%rRidm*"A1AUXB$-X&bJKkd[f1(DmHcAZcf&lbe@X(@Mb#B2M&20J*8`5+f ZS+bhhS,F#-bihikQpSr2&e1c-VdK8M6hPFL*"Y$q&1d896fMPELkka-i&Gqr(Qa N`pdqYlk6C%-M4rfU-SSV#1G!Jj[(k@2DU'ChV&cR0C[b8a99p3FDi[T8"J`qb'2 RN!#m@P!YZ8L59'GHpaLGYXEqmi!V!&T1C+2pVd0Jc`lQC-$U6!UR66B1@p&m99d '6BC3*lJKbVrU9,%Ih*4%@d*6K'ecXrA*ah'YlG2Q(&d0d!1GNmI)$XMTNp"5Kb( `elU''[3Sq3Qa%a*EeB+eJV@#YB+eJV@#UJXPRkM!IAhDcUJ6)eXRXbHh(&Y#`R* ap(GRG1@6FIA9@k&#m,A`5cfe%#LZ,mNL8pV`KCCcTBCcTBCcTBCcTBCcTBCcTB9 H+)Bc5cr6I95P)(293PDCed9l!C4,FXHTidQ(1jHNk#%[DlV69[FHr*Mh-*f(rFN U2&1l09%(%#SZqYFR3i1#@b%20lG#8HL(R+'V*EP'&BUYY3KR5qdrZ-rFh-PTUrM 2NRa5'VGkemh,9I+FTPMr6mak+YDkDN"pp[F&1'@)A,XHI[VjkR*Rh@N,DH4Qp5# `e!kC*NXkMaI0kJ2c@EM'!m#QB$8E0`h4`8&RH#8l"V%AGTrcG@#A[628FDVVU8V %J$9bbTDjY'V1ia-GV&-FU3"!6V-#q#@)U(3i@h66Zkq#A$`CbCTTV20(3bJ)F`4 `*GR"Fkca-QBFZFTP!SciNdRPlSM!CG#4%XU9biNb2PXp),a[q&T0AC4da+rXem( 6V6`j08m1ie4)$G2FV40d@#U6mEGqUSb,#frdm6Q`M0d3J5Q8V&+@-5dq8M(U%mh (p,f4U$4CB,Ykc8GrmGb!cA35Kq'QTIBXhm,DA,(rI91SpA%Gm"FRRV$bJbr[2$$ q"4#GbKeA$XA'c3kHVqKU%1&HJfdS!#T#6N%NR4kQS&HQS&HQP&#ZKFaFj0$+k%` 2N9fh63l3,[ZZ)XN)IFC4m[d2EGDfArprr9!$@C-`$Z-6Z2"L+FI8d),J)K+5hpd 9VTRj*I'&2k5Nd3Ck'`3ePVBDST@TbIMZQCF9[jJ6F('68jC%LiF#k#KppY6E,iH Ra)%Rk`303`dU(aQ"IKIKJh6[EMfeNUNTR2llFhKh9J%rmT!!pRV[Vm"XN64T+Er qpmJ3,JJD,E(aYTkCa3dUNR##4+dqc+'Rlr#QAB6*-R[!AMGCdk*UFZ[2BF-%QM' 8FYL`j`6P2SjmVZ(HTji0m%+LJfR[,1NN+CD1JA5#Xbm%Vc1[A"4L$+I@q%UMdpQ Qi%*!@ldFCL@P(q"I([TV(Kc@%NL(6eAeHY@Q%)UDUPh0",DMmmNIV6qiNZTq0Jf TM6BJC8R)plEHZ'Ja@i554q,Xm6M(6[XL4ck-S+lQM+R%[0GkTPrl@ihZ6[(K'DM !C"qBC'G#lBKIIVL[U(B*NBVM-Y"GX+V2A!9jI'RGmdhNl&j-jJIp,Z!CAbT-RTj eT%8@ArmV@N,`4clIRFM422p2L9&-rSlqk'9XC8aRA!L-I([`4pA)"`qVZkdQdGi AM[mjA4dPB3Gj#r[-p`BU0PX@CN$3!`CiCrq#")6qTkrSpJK3Z!X5p(Kd$RIEKRc *SrA8p15cGHY&Mk"S4P*5c2#5mHfkA4%,H*cY&qH4*iVKibbHqF1U`Icd0l#(F(H i,[B*&kl3Pa0L!00X%`(H3DZ"+a9"H@8XL)r@"8FGMBY5X2Y$8)*S8h4(Nf@Vahq TNHe'TH"58S`%UcYjBF'j41YN)eJR"MmV0hECa@"'D4[fYVDbNH!f2VDk*a3L%@T ($pmUqAl9lF[dAV3k-Aq@)m3[V&q5QH5QR2K6RFq&YE'RHdFm-EV5d5IPGINHhhZ XXp$aP"c8q&&!k[5M[+!eH+bVA@Qh@bbG4RFXqm6%YQj4G`-8"a+&d*chX6cmi3L 8eB[Z64TQP*-J*aRU[r2(VZlN(Kp1D%Va#Bi%RB3LNk%E,*!!+BJ(Z#bK@4kP55[ plE1#([*&2h@M8hMQA6-iS4-P0fXq1L5`jiVe[CcIaClSPj3!E6+'hM)Ta(Hf$&" h1SjBkMkiA9Q2EZ@[mS%-6Rb[r5S"Pi0,0(!@T3EE3r)3DC6'CXra!DCTH12cET& T))ET"TA(aM@cpX5mZ,5Lp9a1c8f13UZSZ8Dm,@AAY!3&1q8US`MY&1VFhRGZI-N 8lhGV&Qm&$f@$eD+U88rEhA-[b!(JaMVfP8qDhQ&XeSV!'k01Qk,)jk$MjA,LkYl e6BE1C5!"P#&Yd'EL3R,59ef@elPZ0!Bb4R+3!+lX5!*(jiq&-FfG92ER1q#,hq$ N4CDNiV[`UX9(IGHJAmLjT1h0Bh3'Z&)qN!!r9SX8BVL@`*+K&dS&eLJ85J!rU*R *UCr2"5kS1q[3plq&&EVZIA4KXIUm@jLmI8b-,qmbLdjHJ#VjI[%X1kZ&1(e3jKN JdJ(j*ab'cC!!N!#1e!-X2)"JkYFlJer08R#UI*NGGX8fp!ZeH&6q$b#&3!b%6X# (6fp+b,be25AIf0X&bN*$6F2V9*LQeFE2m2RJ'T!!6e`48Q*%-F6Ta`8DcN&K'-" Z(,i&NlDQ$Db)VJa4[X5K&Mb-X$cJ2$+IV#pqD&b629cm-cFh#+*8@Y($MkPSHi( 43*%5KFHX1"YCEG!qXPSAk+)aS)eT1D"N5T@(r$Gj$cfDlba1JBI"jQG'%r@HRPq Q+pjDU4r%+I*cG"9lRVSTdk63R'JhZ0Pm2fU#KTfY-f+IT1Hk(RQb"'r(Fd6r2UT )(,29fH6@AMEZI1UaV8MMA#%8m1DT3jCVccQihFpUSAKmkdkr$`*`eH2MVN(fC3m b"`CJ*DXT`&S`HYpmTKHqcaM85),Xm(m'KhDKfK,XS,59iLTHb8HiLJ+!aqDAeI# e"XpmVHQ,JL0aDMSL!fa5pPPYj!,M9`ac0YUMD)T4ST2VUP#@ikJ3miC&dNK1lkD p)J(+AArep&)0[MjEH[mH1Y!iIHN+bbHQh+QKMf!QGl3GqCa0`d"a,bLD*YCEXK` ,c#hl2X+e-q8Kb06182pK!`+4ph&l`0ZY&MIbKmTZjai,jf%N9d-361&QS@#X'eM kEE&Y3,-dG#f53SJPm0`!*5h*Ua!d%I9-Y1&HE13HE[pr3XGebKmd2p4if!hK4h2 MP)"GZqiEf%N46!l(&8S9J5!N"(""aiBB1+VcTiGqKSX(RqeL40Q(5EUV,Ef1&'Q $0Jh&ed)&c#e+Uk)6(LDLR)G"$fHKY853!$,-RJ`@)lIjm9*RXprc&0k)#kp5*4l X46l3H0D$aV3H0D3f#I`dIaAaH0$Mka0@4JmQY0KG26GhPch*MfAlcY&0a-aCGEB G(L&UpV'BNQSHaTVT!JPrqAGpllj'UN*%-"rV)EI9H1G99frf29-#aleA'eJV@#Y B+1hB0B#YB+5lTDhV#')PipU-K5Sf-0Ph0Vqi&U0dU&+[IBfhpi"XQcL*Z8lk1&a G23@RqlR0FAd!1Jkj81m80(A5kX4d$SQ-*%[SaGMRAN41k*!!2IMR`cR5`cR5`cR 5`cR5`bHVZ58HLjGD@'@[E+iIiciG8T`8[@"6)$DjNi1HKYbqJQr[jS5JQ$0#QHb QK)MbcqfMcIprp$(NMkp`b`G@ZIDIDIDIDIDIDIDIE21da-e+lD2`CQUFAYVhNSj lG$54DIN!@+eQTA44"eZ&rd#!Aj'J-,"TK!BN**ejEY+8fEfX1N%[MkrIG$6dMR@ 4f[FEdL@9hb9DE@q(+i&%F+9bd(BTeR!k-2QY`&f`E6hUhCpEF&%bGHir2%IGbZh r-D296H&jVjCp,GhI!mL%L%JP9c@eZf#(Er*fQfDTlm(BTa!'`9kJQa`jB23METh P8Xfk,&21JJ2E1+DU3Uf'0EKAF*Id0A13!)-!bh&@!h4CaH%IQ!'#AM%Xa'hQ#lJ @N!#Y[kFIYSk%m"KZkLS`4cVpIQ0C'@kZrh#1!i[cQmfGqGLYlDQ#`M%piZ%9hEI 13qheQQa0`(Rb)3Q&K$$A%5G-"jmL%&%*NRHl2&VJLLq"qjF)fSa0bFNKHG*EK!5 "(ah`SQG$24(@@Bp5eJL"Bb*VLK)#Zel4)D,!i%YH8p&H*N'PYhe3M3"2Bk`I#G4 AIR&`(,cG+JZ0%h'"@jTKjZDB94Bc#hY-mh5a`hF!hCV`ha2l`,l"3Kh4[lT3a"D f*q6lEehaNGmCDIiGMZd5F8"2bqYYqY,KqMHN(Rlq#CID025dXClj-k(P'E!6m$P 'bTj&+b0IIpPJ()eYf[26TV1lG*GFHIHRJ[1c2(2@4+!D[YpRr3@U0[`SBfa[e*N N)L$-+j+I*FKd9+T8kDIFdFr`%ES"#M-`iY5lJLl0)k9kHNBF31[[@G$a(RQ+PZ5 BHN(%+PR%%J"#T'i#pIj63DR5Lb%[bUXdCqXCPE4*9"GDc)jH'q2"dE$q#CF5Y4F -VY(hbiX$Af2Ti5!j%hpJ3c8SfR0MYhDB)*DK6E5ae4kNhpk)M''mfD@@1GP0Qm# 8J6eFd`N$ZbTBS9($V#5hY(V&GE`UI'K`2pV08cMhS)"cdB!E8B61iYpC'jhFP[3 KXQeBm!Yi),(9!02k"$Q[e$Lr)NDFTA,4"fGp4j5FH)C-mfaZYU'C)$E%lQ6GZZc LQkV6(6D%LLKHMfVa&k2,d(VikV#"i[KY8Fa(FN3**BTRk0+V15'(DiH,SjpHF3l qDB'$,`QQ5Y!rrZLIS'0NTPJ40@1APl&#MUGb[ia@'4(r+#C(B,,I[$lJl'GFSS" `+-*edjLQRi[JIYE8q`XU,4bdMR[Ibjh@r-j#q%Z0Sjqr+G@q()l2f$5$"ELVc'U (-1T,qS-CQKG'm"3IP*CKASeGe%9!e,3pGKa,r5F-TNljmUaJRq(iRipB'rbP"+5 10lhTK[%l&5DEI8@MiX3k"5)lbClQ`m-EXTDdB$fFP'6h26qYZlBa"a(k%F(3Z`" c!,l-lCek6M2*Kkbi%+IYI2LiIffSdRUGNVe+S[('"K*"f9`r1qp`J4G(c0F-!Jq kUj`8E*M4G@C5)8mR4D)fiKbCSi"CP-F!"`,5)eT+B-BQ&4+k$l+$IbHTeVa2PS- JYa9HTcPYTeCGQ56K+I'(RqdBV[mXC21MA[JS01ldUiYUTbl@mGG0"$T2TZX5ECe ,(ArI[%r$)C!!mr$ldCPCr6&P#dXP+,)B+a-i4[ZkIqlqhRL1+(qXYdlJ(fCCKFa eUMVAPGj19H5pmTEY+6HVG'&0#0VG"'3p0YXqcS`f&4)H''DIV0SFdlMR(YCT)Ll h1('S8bkmDPC"cPBQ6fXC5%i*pEIHm9dmdkG)Zm@+dk-bqp+MbBYF`E&l+d!5'mD -XU`m0)Q"B!*'ZFa$AcZqqEl(mSaPTVM"Tl6QldRG1Z5),58K',UZ,5TT+JH[S,6 8!q,m$1d%%QYLqIkj69e[Q4iZeTjGj,3eC)&6cUdX$YTJeI(G8kqE!NckT!k(2cL 2M!5XS1qqm4I54AD!qj,I+JAJaXK49a+F)LK[@0,+b+9D$Fa&BmfArK,1p&l6[Ia Scd9e9F)+-L#m[N"1DT'Y5iG+Pmm,cG9M4'hLSqC,[BJ@rh`Q1kGAcpH50BC)-rG ZP62@**U![LV2Jp%6CSid5MVDqj)SZ1REH+Z@Z9!pd#m,+&!Dk[TX(N9b$")!&jJ JD*r23j,(QEJq9"Z8!0'0EZ&BZ8cI$jCa)m@-604-%&KRBXb%cbSeRCZ6K,&&RLB Rjm1Q4Z6"-PHUCi&`4,,*,FTlYr''!-QLbK&1rX"KBpi6B0))GHc(`,0`q+DIXih "'K(-A0kNl%"Z'@68Hkq6@h)[5CHd'Pc%,qR!U8eR#`@(lkSdL2pm[@DU2YlI"M1 2A8[caM-$'PSF#mDN,-G+X85af'-6)NPbD%6*C3M*R$bmIrjGSDL'!arRc4f1(KN @SI'N,H8N*a3&#c1X!r'l&c[jcNTSeUM@SAjDVScRY4M!("c%4`c-I`#2R'-"D,[ b'Q8BKeYQ!%T@)6X,f(5$GkZL1N,Xj+%G584FAVG)'MI&qMV,S$a'GE!5HiN$Tpe hZ#(kaQD(0(3@GeQRS6(jpjLReblpH9'Pr%V%$&%2$F#0P$BBVH!XHY(MVR$LIir a@Bp#4[Y0SlL3!&'fNrSHS,JF*5(ZG26A16-Fe[E!-8G$IqhAi5,B5bA8h!412QD 1A3lVGM)$rc'DEflG#6PAp9kY%2!mU%RZT@p$Y,k1djI0Ni'1'P(ZMd&ZD6&5Fr5 BmSbY*4Y5ab!efK-N&%2Eap"RQAqGT$EhaIJS0`BJd6D2q0IdQ9iNl'j)eXFBYNP Smd616eSh`SKr6eB(!`KVV#)K8l*6ED+)Gh5,55Mj3r[$lbXFDbe`8eN*DY!UM0p @DBrIGVhR!dUGeM#,C1qVXq43+lS9qY`&[9*P9dNFICUPqYF*BF6pQ`1-m8p2m4Q l[B#1JY`qfjJYR`84UYHR#2K@qd3Rq!Dk)fh1H4QmZVm&Bm',fk@3!*rZ)arPVZV kT+C`ElBVk9riLc6eMDTVNrQ,dUiCY@Y#($RVRmLD`LrN"GAlEDepM0Al&0UE8fh a5q2RiKf3!&!R+Ge-S@SGXB@Lq1j(8a+P0idfC'%%!kldG4%H@"A@D&!ch5*Z%(c i+BbilHfBbpX8(Ipda%3YE9(fH-1UPLHE"j+emUBrHqq6QrmB[VR1'e*p$RAbY6( `IrUT!2%CB[CJK8'ZJS9jT-)r*3I@'R0mEENNNNNNNNNNNNNNDrK3,(Yr(Z,dE-0 p64&pC[$-&,#K+',a*fLrJ1A$'$c8XKiXb(Lc)H,-KiXb(Lfp4QBrrhrp+$LZ#J` N*IaH")B@S5B5#JLaD`*%JpbD!N5%Z%-UMr+qS&rDXGpYdAfk[Ae+4r#`YqffQMj !RlAApZbpp9jhe20p30b[U"EkP2IY[,pZN!$qeA2ffhr`ZYNq3*qTX[Ye&rKH[kR hp30arJ#r`+pqfd2fk1I`+cpYArm&HZI8#I`FElG6Ii@Pr#M3q*N4IlqX5T8C4,) -*A*m&jra(M3kU-b-&q3A%NB6k!8%qJ&"2S"36k!8%qJ&"2S"36k!8%qJ&"2S"3G &IfGPArpd6ElEV["Ad#!0D`Li3,NARkG999999999995cp$rZM1T-c+3UpqPckk0 0f2lf*K`p*Za$,N"Er4aNhN,EqYMr()0kcCE`Di9eEG0@@6Ppkqq[4D*ZBj!!82f U#dc2JFDCZ0`NQ*-5!@A`TL3p[ZL-@[3@!R%kX%D%!!!!!!!!#X',#62Z"*0KP3( #-[pI`Ur$)MJl1kKi$MNrGH&m51dMA6kXB!&#a0J@c,+&VN),r00#')T3&!8"3SH B'E,VAKSS5aJ13GRE*2Z6bQ%JT$L(+!GY2'Dq&+Jc)RY6V!#%jB3TU-%NGD9PZFS D4NkULiQebd3HHprUj9bPMq5V@J5f,2U05CrP@F,80$Z!5(!B,b+j3$hQ'LMpR(L +8%#bTJ[b8-GRbBH+(e'ENRrccch%%4X2G5MiIqV[J%NCd*e"cUNqTXFPf1)iiL# &GN,b6K(&G[66MK'(PMB#NF9re'N#b*KV6#Dk@6'Y$A[4eJKDZ9'GJGZY'JpjI#S N!dVr+*5-%!TdT[56Y21)ZViNkV#V[@#a`BMDc[50ed$A@-)pV+#U42+hq,eL))P @Tib0-1U[-Hb9UeRL#%X`P[8BhRi[2iMr5mrMi4Y%2e0ZQLf+0b')fBcbVR"KD8k @jHCZkNDI(CPpEDC5!ThH9fQJTR``%41QCj)iZ6b#5bf)3EYJcVqMmS(J5,0YK*B NQ+6Q%%GKT46$@0[DbfN!2"V3)8h%M@E*I"&ETfG&F@F8"FGeY-(+-(FP#qRYpEX -6+%H!fY"Ekim1XY6rF-k5EYP'hY*dr#pQ'ZjSJAl%XMVYC)*+#G8"DP9bAb8&L* dqQU-0!%RpI8kDm9P5pDU-EGP'0ZbM'hC4MEXSaYf8Bfl+-EGP'0ZbM'r(-E%IIp p6kcr4MU[)b3L-MPeqS%,RfA9999999999@ViQ4!mNXZcQ-Pk2h1N05lr&,Xdc'l )+YS&4eH&ZD6iB0)8dX8#E9*2T'6$[6rTYB&)2+KdV2kN5aFpAZFPp!aX1*!!1`L SN60@rdr!md)f-JeM@0BeM0Il6N6CddB*!!!!!!!!!!!!!!%A(HV)&5,EaAc,8CU mkRkN4IprhI+#H!lr-VH'(U5%!%6KLd"6XY(FJ-!T5eL5diHjC-!iiR&KIU4P5+H Q59!je)B9YQqIR6ka28I6FkE4Cp,XVJ8d3d3d3cIc"4jMY,B`kbM!'U%CQb'44([ pp$@N#lBh&(41Vk@l-EXaZc'f)+[PJ5Z!rfr&r!G`FPZD*J#HDN[TLV!4)Kr`104 6N6-Z65C(kMV+BBiBU+[9b"P,T`d!!!!!!!!!!!&B"H6p9fh!,!i35'*[+@5!jc[ kYJ1NCjiNm(Jm(Jm(Jm(J2H+`9SK0"iBmE8$P4dYKRjQ#Q#lbN!"c4QQ-Lj!!Prf h(kr+pX3%5mL`MK8Cd4HC0-5ImZqNeGrRUq*1`[hcUE#rI1TX,pmkQ`[hcUE+D*+ `Rm8CJr8dA%L[q*N4IUeF@ZTI*1jNPJQTLiqHk![ldPSGfU(QHMapQV30+eS(`mA 4U#,UV2M0EPU+4f#L@jDLNGJSPZ@Sb5brqqm$1C4KFlTQFL85P(dqGVFKp*4MD5Q ,8e4kF0Z)Z(4B'"JC6!i5*i(J40$@Cf8(IN#jY@3aqQq!YC8@q1A4eD5M#d(9%Yq p8VQC4#E'NS`k8%#lk(#h$-M@h[f'k3$&C2B#DGiVD!D2-,LaCh"i0F3kGYIc6K[ *(D4jjl-L)X(M1)LS6!#9K)Mc2Ue6,BbB-eMaCb"i0'81++k6m!I$KAk14Yd56Fa c&VL1MkH4KD8q2)Yf$l!!,4IIE1!cLVlE,6'lHhZ&l"0d99Kq$5a"4m(f62hAmK$ kIIF@i)V,BUpkDL"QJTP$QTQp!,YKDB#[G(+l"ZRRi8fPMDj-2Z&hRbMBCqcK@3I 6mCeamr"*%Z,@+AHqem1%(TZQM$'PFk6$3bHGqEV0"#3T##(CVZY$qmm2c519bb4 )20JM['lQVC6$95-9Ihj"eZRH5-I[@23B%XkDqPI$1Y8(iAG+b5e[9)c"%3X[Xp` hk!F%#Fm`FVrpXKide8LXEFr5r9'ESCRLjfm*f9AH2Bd5eG4RbZL1+kZAj0!%V&p R@mqLAq,Pm!b%NY*U&80B#9dEX!C!M919ZMh0c))e1'9B@4(lDUcc!c*"j@fCUd& 'b"hYG2MpVf`[k%N1+ZIVYRF1*'MGqC8UU8&dF,#Tk)4$GK,)#NdJ0l+`%HFlQ!l I"(DU'DLmICpNAK,,AU%P(2D5i$Mf$qT",Q2M[(U*RVf,l6D+XbU'[3,E4Q@0JE! f"X$Af*!!a%*Gre@(#)B"!!!!!!!!aH`h[M5#UeLS4H96kpj+DF3I4PifrC3'8@L @QiT5FGUD*kMK(#1%F)ikrC`bfr!,iJ,(jq!%2[-5areYZS*$U(CZS1(,9)XGXi" j$JPZeY1Td4ik9@fffffffhp*K*'hEHAZR"i'G%k)bP'hCfLb8pD5p`Pq8P2kA$6 kEPcRLp2r@h(q[NEY(kTlbN'6r,5eJ%JfXE1lk+,Mj[f#(Ic'K2S1J6k$S%qJk"2 S1J6k$S%qJk"2S1J6k$S%qJkMj,rrGYLSh$!`-$!`-$!`-$!`,B,'LESj'9TP(3J f$B0Jf$B0Jf$B0Je`q'4Z'"JB'"JB'"JB'"JB'8`2rY!erhrP3em51,RmrhriQ4& r[kP9bI``4q1rP`jBcpk#I+d+&UYq3A%NB6k!8%qJ&"2S"36k!8%qJ&"2S"36k!8 %qJ&"e6R%bY[2rea*jFFC['2C1TRJef@"pcl,UUUUUUUUUUTCmM-A0p($6-V9!bS @X8P'0G#qpf*19Dm"mjckDHE##TkR[ZaCfJKe5r2hmQ!%ZpEakl"!%J0AH9cNYN" qK$B4eq[Kl#[B,cIVb5dGLJUUIc334XXb2Q*3&'cRSmQIReAE@2XY402B883!!!! !!!6Cd!&VrA@j!GbdJ24d'Ra3BY53!%VfTVHiT0GaT`T`T`T`TY4-keDfP"HLUR9 hPYcRGY91DCTQQEB3NT+c'#Md-%q`A%3Z4`Y"j*******(J"hlpdkHkRHej!!!F6 T4Q$UeSSKQ!I+@4()&'(A+pK,jcFV6EVbifVH6`RKX#G-#'0#)i2S2q%V61)pR0L (CbidaX22iTlLp,e66B&5#bESfSS3"lf2X+C4hrV9N5e0Lm+VdbNr(P5,XjqRMEm *bGI)B!P,YP+9h(k*"+,*8QXb9LI`[mhVZM1&4r*Qh10AHmZNc-Iefjli@*DqVf- qq"UF6Lp*b0b#N@@*l-3Hf&2G@GI`UeD(MC!!8MkjhbVEZEIGXjRrDi3fDDfdf6d IYPacm4iF43X-3H52hjeeV8XSPDIR6X@Nb,`)YrV2T5MZBhlK5fAd`92L)FfM&V& J2jJJJm"J@PLpe)i6R+HmPC[q8,dp`)Mi8AeG[%R*dAqAf4C*hFA`EHAiTEFdb@5 $!TACTPZjASP05D6VDA[*5&Mi@LmhifXm!a8[-B)iVqeE1,q8VTfXAC(Iq&#I%r@ mNaGi6[`"X"5H"@bp,R[#ZNPIhATHSC!!VA"[5p3b&Di0kAU'3VA"[5p3b&Di0kr rAHm-rhrrIrfV5aE$L`e`*h0FP4,NARkG99999999999@XmrY$M$Dj,p`!XSk"Dp V#-9brSieVEJ1C')9Ci9Ci9Ci08[&4TB*B`a38k&$FJ+(*%[iFJ!'%K,FrHlU!44 1VN$r(Z&hkN[&+qh``PJQjl[GDc3Qkf8!FN!!!!!!!!!!!!!#UrNcdUEh&&ThX@G kF@9F!M*TQij)*`T`T`T`T`T`T`T`T`T`MU@r[PT*I`iM1$GV60+jHF'%+rFPbA* AbG&MU`EU'XDGb555555555555555555555C#1#B0ZN[qiV)HrGXQ$fZ"Y$mJc(X *I1EPDFkFkFkFkFkFkIIA-ePU2P[Zd4-IcLe8"8,#dI'JQM9mC"FXjmX4mV,iUVD UCZVDTBkIepVMU9flrSiVTBflFmV+V2MbYfJlDZ)r3,P6$Z(*k9!&QXIbR8G4e3j M4`e*5-KR5LP8!!!!!!!!!"SSEjVMbTNeP9+Lj5c$5FlY+rEq!,q&Yqb`*S4k#Ip R'-$bEGflYhEZhJZM4`9p5R1M(`28FFUF`4S!3HqL85fcqhj2`H&6[CeINm%b@1G [p6ke!XY[l`J!6-"-"rNHbNSH5l,p$L@M62kLIB*pJRf#IB*pJRf#IB$PpK0l96S Yi$U*$MBfNXriQ4&qURZp#p"BLG2TUM$3"*rAe1Q[&C8[@UM'hC4MEXSaYf8Bfl+ -EGP'0ZbM'hC4MEXSaYf8D6l*4rpl3,J``d3UViFL8Sr4,Yh!k`IVY%5U4Zi-M-! "-9pYUUUUid(S$%KVhL2ScI92r2Yb2EI[mNCBd(2!0bqqcGa$Cf2&V9#,c(rf*kD -)'1UVE%0(UK5FLZPjfJEMq0TZ5V@4LXhMjL0`IijJHb1UAHQXah['a&Z8qJ&p&L pje0dreJV0G!C'ki$BM-,[1N2P3Q`,U-SHd+Bd5fBq-9Mi@)@r)A-4-@NCLjfI%) b4TGM,qq`DCFDHRXB&D[Ml1$3TpF(8mZc'Bc(+pFHiQQ%bINJS8[TQ$l`GDd5AI# d02pkkb)@-@%(ddNqbRZ*(CkI58-3*AC4#5m[r`@0$+Elre(3S'h@$Xk`&fJ3E3" %2QP9+!d-e58#4MAhTl2(U9!4iLFSq@lQ`%%E60Er&i[J5PEcD-T[q#$A5@'L3rl IIp@L59K#Za6k2@FJ,r(%(S+fI+&T&IpCSmY)rYIlCdHG'MUcNMqL3%XDXH25"mG -UU&#jXr*'$Q'GlJ#ErLC%-Ql,M0"C*80XH,DdRQ[mDh9P**ZF@+R1%"Zc[$N2L5 6MdZ(qZQ9#I3*rhqmGai(HUK[,Cc-Z41T[X'dlr#ZH%C0A0AT+kRmf8YKV&*i@XD 2mqr0ZYmqDBKCZm*j*Ye1G#23G"b!2Z$0dHFGiP2r0!'!!!!!!!&5cRdd$'!5aJ% N8(U9llN8lHS*JhRKr(69U"QfKY$D'd0RC#b*#5B3M1,IUiY"S'833jJA4q,15*N Q6hCdbJBZ8!+261YKNaQqja&0Z5555553!$b,59irVZr#NG581r+4CN!1-fha0h$ KBG!kfa`KfSE!MS`BdSdM&#pCckTlbN'6r,5eJ%JfXE1lk+,Mj[f#(Ic'K2S1J6k $S%qJk"2S1J6k$S%qJk"2S1J6k$S%dRe'e)!rrh2!D0``-$!`-$!`-$!`-$%U%$6 fAm*[eAVLL+)SLL+)SLL+)SLJS)fU0999999999999999@hNk2m2PErpr[3f+ib` I%MLjr2prq*N4@EqT@FU!!8k50MBf[+)YkXA(FCrMKfi!"Kbq(ViH[Kkq(X+"AIk i@rmDY[bI&0+&9((0IINHiMEcqXDk$kAPRrZ58(rR#+%Ed+MN*-SbQLc6JQjbrVH paVi('H)PIR"R3KaUEB'k23l9kMjl"B)QrTV%`VIid#a-[hJqPrmDT&QF$Jj8DZ1 AAHYH%FdFq`IQ3qc9SI05[jiY!%Y+!!!!!!!%d1KZhA5JE391m8XQJ+@p0-0-KYZ ,k@VEa1*`Zic8I0qaT2Q)BYDF1"!'52P1K2N+J0Z5555555554mPS@IZfXZbFDlH $1jCbC,90X5GlBJIi43BZeKJG%cDKEq%'aQe(TdC-dE`BLS0DeBZjQ+IrCDqC"'c mLNCrT(m4cf-8GSC&8`H,p2jfXe1h4`HQpH$I+b2jKNf4',G2IN,SdX+#+9[hiBl M*lBX`jXU8RYT#fR-A*!!*!jPSUf4Gb!dAJD!GcZap66XB0YdJkMCS38T,aa($(P pIaK8$PTcU%mIA+!)e2mV9G,(S,,QV0GYT-N!G9Ij'fpmCeJRkrU"PVfDR#rm0'l [4#+K1JJ4pbKE)%#UGjP*3IeMU3j-8rYE#$ch"4d'e3[1TE![%NBa6lfelBY!Q[I Eej`B91ehe$*cAaBk5'b%Zj1)f5"`KmC0$a#08TMHC8kSQq1$6UY"+epM"kSjmPE ARCR6P1VAGqlQG`[Q%4qQ3M6II+PCbS!"6T)f0MDmSLhUaFGaRq1(EJ!'(,iH[Kk q(ViH`S&GrVKEqqM(-Ep'q$TNkQA'rQ-9LpFAYH5`PK0(mQbkN@H6pe[rB(i(Ml4 8J9AE'm*V5cK,jIj6,%A`01H#QTr&kmAK(&l+P@4(iUbF[CEqE10`A,#RG8$SE[e rr[DXT2EGpN%a+J!!!!!!!!!!!!&X3`fVhY%LmF,m*2PQr&`MK(#1%F)i4`MK(#1 %F*8[0TERPrQHb8%mELP+$ENNNNNNNNNNNNNNNNNNNNK`'filf%Ir0("6b&mCm`R rB*D)2[X'K1$IN!!+DTXj"'-+cN&39"DCBQfQE$9)ei%P#b8lIeqEf@IN88UmicX BhrfPU8,P)*!!d(C3HXPC%H+fMi9C-C[mapXh6jrE3q,lVQ0&i!!1!3J!Akp$IhV VKT0Ul%4ZRp!T`T`T`T`T`T`CaBM1A1%K@[DB*m[,JmjV4NTPZPZPZPZPZPZPZ!a 32H9Z,M9Zbj2+,rVj(JPT#"Eiq3m`eKY,Pq@"A#&6hE9'!`$aDIY5'N)rN!!rq*N 4@+eF(j!!iFEN"i0pb3bcF&8Y,PLka9d88BK&[lRHVR1Be&RI+pq+G@3A`9I-#SB r$L#-NIRMS!B4qeXUPIH8m@2SrHa(G!jaZ+q6)(kLXR,55L89%8L-VHDGR)P%SU) SfA4qRCb*4++L+-VErTfFL85LRjCVhXX(NqZa)-bV,Rjlc31Qr-E!#Laj8`L)d,a )b3@Vi8#,Ap%@3JBL92Jjc[6R44$J5RaqGI$Clib$KPi(4[-,8GN!U4XmV@1EjfT ''%TNhpZll8eNFPV@`UAEF(XQ-BJ3V2Y,LE`+6@9D1QK#el@-%hP$UFQU+rD-4p1 F*!D%L,(+UJ#GArhK1*kcd#&TK1KdjMd5kD)SaYMU(@RRSF"GXH09Y&qFrf&Bl$c cGmrbCT[!Z1K%0A%Nqhb8f'Ymk$Yee!ZFAF6ZFHf+fl)0"TX3Sk2LAZk([39'fl" 6`jkhm1)MU9fH4E3(14+rMf0ce6PeKFAie)pi,A+QbS%0r*6Qir"db%`"kE+fjYP D3D$dQ6-90UI8Pb@[%ANbLEqKbK$AD2X)FDpYj5GY4!rN#T!!bhmcD3*RP6DBd)U qZ3`$@QY$NjHE2'T441LD)hrT%h)pAEq%99D&%kcU+SULK3c18ZmXIYf+$kNCrM% 8Z465E)hr4fP0*J0SFUT-dd[QP6L3!*2DbGIbVX6%"TG,9iBY!CFGlDK`1V+"0"8 qVTbLCH00PHNF,k@D#[Di0G0J6(TJeeG`kcb[+-%ZGl[mcVZ8dM9j&$ip'kpScEH cTXl$lYPIa3`*G4"YT+@SaB)i!2prpB*irYk$8`jX2J$&B+c*&eB52fFI'fj**** *R-Zb-%AcqaSS"R5B[iR6#J+lIlUq'ji,U6b5555555D'8U52UQT8ajbrHXl99Q' 1l-1(VhQ`'(,iH[Kkq(ViH[Kkq(ViJ-rr6*K`jrJI6lBJZ69%dP3N1"16TDJSkT- krYbc(*Nl[1GTXSkCR)P%SP%SP%SP%SP%SP&3TT+5L85L85L85L85L85L85LS1E+ 5L85L85L85L85L85L85LS*355L85L85L85L85L85L85LRrpN!!!%!!!0,+`!$5LX !!!!b!!!!!!!!!!!!(!!b!!"TBfjc!!!!#Vqjrrm!!!!!!!!!!*mk: ================================================ FILE: res/license.txt ================================================ MIT License Copyright (c) 2018 Jakub Ďuraš Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: src/__tests__/basic.spec.ts ================================================ import path from 'path' import { Application } from 'spectron' const baseDir = path.join(__dirname, '../..') const electronBinary = path.join( baseDir, 'node_modules', '.bin', process.platform === 'win32' ? 'electron.cmd' : 'electron' ) describe('Basic functionality', () => { jest.setTimeout(30 * 1000) const app = new Application({ path: electronBinary, args: [baseDir], requireName: 'spectronRequire', env: { ELECTRON_IS_DEV: 0, NODE_ENV: 'test', }, }) beforeEach(() => app.start()) afterEach(() => { if (app && app.isRunning()) { return app.stop() } }) it('Is showing an initial window', async () => { const electronWindowCount = await app.client.getWindowCount() expect(electronWindowCount).toBe(1) const mainExists = await app.client.waitForExist( '#webamp #main-window', 5000, ) expect(mainExists).toBeTruthy() }) it('Allows minimizing of the window', async () => { const isMinimized = await app.browserWindow.isMinimized() expect(isMinimized).toEqual(false) const wasMinimized = await new Promise(async (resolve) => { const eventTimeout = setTimeout(() => { clearInterval(checkInterval) resolve(false) }, 10000) // We don't use minimize event becasue it doesn't get triggered const checkInterval = setInterval(async () => { if (await app.browserWindow.isMinimized()) { clearTimeout(eventTimeout) clearInterval(checkInterval) resolve(true) } }, 500) app.client.leftClick('#webamp #minimize') }) expect(wasMinimized).toEqual(true) }) // TODO: Skipped till I figure out why it doesn't work it.skip('Allows closing of the window', async () => { const wasClosed = await new Promise((resolve) => { const eventTimeout = setTimeout(() => { clearInterval(checkInterval) resolve(false) }, 10000) // We don't use minimize event becasue it doesn't get triggered const checkInterval = setInterval(async () => { if ((await app.client.getWindowCount()) === 0) { clearTimeout(eventTimeout) clearInterval(checkInterval) resolve(true) } }, 500) app.client.leftClick('#webamp #close') }) expect(wasClosed).toEqual(true) }) }) ================================================ FILE: src/global.d.ts ================================================ import { Track } from './webamp/webamp.bundle' declare global { interface Window { minimizeElectronWindow: () => void closeElectronWindow: () => void webampRendered: () => void centerWindowsInView: () => void webampOnTrackDidChange: (track: Track) => void webampPlay: () => void webampPause: () => void webampNext: () => void webampPrevious: () => void } } ================================================ FILE: src/index.css ================================================ /** * RESET */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font-size: 100%; font: inherit; vertical-align: baseline; } html, body { overflow: hidden; /* width: 100vw; height: 100vh; */ } #app { /* width: 100vw; height: 100vh; */ } .spinner { width: 26px; height: 26px; border-radius: 50%; border: 3px solid #0f0; animation: spinner-bulqg1 .8s linear infinite alternate,spinner-oaa3wk 1.6s linear infinite; position: absolute; left: calc(50% - 26px); top: calc(50% - 26px); } @keyframes spinner-bulqg1 { 0% { clip-path: polygon(50% 50%, 0 0, 50% 0%, 50% 0%, 50% 0%, 50% 0%, 50% 0%); } 12.5% { clip-path: polygon(50% 50%, 0 0, 50% 0%, 100% 0%, 100% 0%, 100% 0%, 100% 0%); } 25% { clip-path: polygon(50% 50%, 0 0, 50% 0%, 100% 0%, 100% 100%, 100% 100%, 100% 100%); } 50% { clip-path: polygon(50% 50%, 0 0, 50% 0%, 100% 0%, 100% 100%, 50% 100%, 0% 100%); } 62.5% { clip-path: polygon(50% 50%, 100% 0, 100% 0%, 100% 0%, 100% 100%, 50% 100%, 0% 100%); } 75% { clip-path: polygon(50% 50%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 50% 100%, 0% 100%); } 100% { clip-path: polygon(50% 50%, 50% 100%, 50% 100%, 50% 100%, 50% 100%, 50% 100%, 0% 100%); } } @keyframes spinner-oaa3wk { 0% { transform: scaleY(1) rotate(0deg); } 49.99% { transform: scaleY(1) rotate(135deg); } 50% { transform: scaleY(-1) rotate(0deg); } 100% { transform: scaleY(-1) rotate(-135deg); } } .message { position: absolute; width: 93%; top: calc(50% - 26px); text-align-last: center; background: black; padding: 9px; font-size: 15px; } ================================================ FILE: src/index.html ================================================ Webamp
================================================ FILE: src/node/api-server.js ================================================ const http = require('http'); const url = require('url'); let apiServer = null; let mainWindow = null; function getHtmlInterface() { return ` Yaamp - Управление плеером
Yaamp Remote Control [ - ]

YAAMP

Статус: Проверка...
Действие: -
`; } function createApiServer(port, window) { if (apiServer) { apiServer.close(); } mainWindow = window; apiServer = http.createServer((req, res) => { // Enable CORS res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); if (req.method === 'OPTIONS') { res.writeHead(200); res.end(); return; } const parsedUrl = url.parse(req.url, true); const pathname = parsedUrl.pathname; const method = req.method; // Serve HTML interface on root path if (pathname === '/' && method === 'GET') { res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(getHtmlInterface()); return; } // Handle API endpoints if (pathname === '/next' && method === 'GET') { if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('nextTrack'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Next track' })); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/prev' && method === 'GET') { if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('prevTrack'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Previous track' })); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/play' && method === 'GET') { if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('playPause'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Play' })); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/pause' && method === 'GET') { if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('playPause'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Pause' })); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/playpause' && method === 'GET') { if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('playPause'); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Play/Pause' })); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/volume' && method === 'GET') { const volume = parseInt(parsedUrl.query.value) || 50; if (volume < 0 || volume > 100) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Volume must be between 0 and 100' })); return; } if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('setVolume', volume); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: `Volume set to ${volume}%`, volume: volume })); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/mywave' && method === 'GET') { if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.executeJavaScript('window.require("electron").ipcRenderer.invoke("setMywave")').catch(() => {}); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Моя волна запущена' })); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/myloved' && method === 'GET') { if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.executeJavaScript('window.require("electron").ipcRenderer.invoke("setMyloved")').catch(() => {}); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Любимые треки загружены' })); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/search' && method === 'GET') { const query = parsedUrl.query.query || parsedUrl.query.q || ''; if (!query) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Query parameter is required. Use ?query=... or ?q=...' })); return; } if (mainWindow && !mainWindow.isDestroyed()) { const decodedQuery = decodeURIComponent(query); mainWindow.webContents.executeJavaScript(`window.require("electron").ipcRenderer.invoke("search", {searchText: "${decodedQuery.replace(/"/g, '\\"')}"})`) .then((result) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, results: result || [] })); }) .catch((error) => { console.error('Search error:', error); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: error.message || 'Search failed', results: [] })); }); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available', results: [] })); } } else if (pathname === '/setArtist' && method === 'GET') { const artistId = parsedUrl.query.id || parsedUrl.query.artistId || ''; if (!artistId) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Artist ID parameter is required. Use ?id=... or ?artistId=...' })); return; } if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.executeJavaScript(`window.require("electron").ipcRenderer.invoke("setArtist", {id: "${artistId.replace(/"/g, '\\"')}"})`) .then((result) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Артист загружен' })); }) .catch((error) => { console.error('Set artist error:', error); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: error.message || 'Failed to load artist' })); }); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/setAlbum' && method === 'GET') { const albumId = parsedUrl.query.id || parsedUrl.query.albumId || ''; if (!albumId) { res.writeHead(400, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Album ID parameter is required. Use ?id=... or ?albumId=...' })); return; } if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.executeJavaScript(`window.require("electron").ipcRenderer.invoke("setAlbum", {id: "${albumId.replace(/"/g, '\\"')}"})`) .then((result) => { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'Альбом загружен' })); }) .catch((error) => { console.error('Set album error:', error); res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: error.message || 'Failed to load album' })); }); } else { res.writeHead(500, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Window not available' })); } } else if (pathname === '/status' && method === 'GET') { res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: true, message: 'API server is running', endpoints: ['/next', '/prev', '/play', '/pause', '/playpause', '/volume?value=50', '/mywave', '/myloved', '/search?query=...', '/setArtist?id=...', '/setAlbum?id=...', '/status'] })); } else { res.writeHead(404, { 'Content-Type': 'application/json' }); res.end(JSON.stringify({ success: false, error: 'Not found' })); } }); apiServer.listen(port, '127.0.0.1', () => { console.log(`API server is running on http://127.0.0.1:${port}`); if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('showMessage', `API сервер запущен на порту ${port}`); } }); apiServer.on('error', (err) => { if (err.code === 'EADDRINUSE') { console.error(`Port ${port} is already in use. Please choose a different port.`); if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('showMessage', `Порт ${port} уже занят. Выберите другой порт.`); } } else { console.error('API server error:', err); if (mainWindow && !mainWindow.isDestroyed()) { mainWindow.webContents.send('showMessage', `Ошибка API сервера: ${err.message}`); } } }); return apiServer; } function stopApiServer() { if (apiServer) { apiServer.close(); apiServer = null; console.log('API server stopped'); } } module.exports = { createApiServer, stopApiServer }; ================================================ FILE: src/node/preload.js ================================================ const { remote } = require('electron') const { ipcRenderer } = window.require('electron'); // const handleTransparency = require('./transparency.js') const handleThumbnail = require('./thumbnail.js') const handleThumbar = require('./thumbar.js') let windowLock = true; let zoom = 1; let fullscreen = false; // We want to completely disable the eval() for security reasons // ESLint will warn about any use of eval(), even this one // eslint-disable-next-line window.eval = global.eval = function () { throw new Error(`Sorry, this app does not support window.eval().`) } // Add require for e2e spectron tests if (process.env.NODE_ENV === 'test') { window.spectronRequire = require } /** * Electron API wrappers passed to the renderer * * Only implementation of the selected APIs is available * to greatly reduce the attack surface * See https://github.com/electron/electron/blob/master/docs/tutorial/security.md#2-disable-nodejs-integration-for-remote-content */ window.minimizeElectronWindow = function () { return remote.getCurrentWindow().minimize() } window.closeElectronWindow = function () { return remote.getCurrentWindow().close() } window.webampRendered = function () { // handleTransparency() handleThumbnail() var ms = navigator.mediaSession; ms.setActionHandler('nexttrack', window.webampNext); ms.setActionHandler('previoustrack', window.webampPrevious); handleThumbar( 'stopped', window.webampPlay, window.webampPause, window.webampPrevious, window.webampNext, ) ipcRenderer.invoke('getSettings').then((rs) => { const settingsData = JSON.parse(rs); zoom = settingsData.zoom; }) } window.webampOnTrackDidChange = function(track) { let state if (!track) { state = 'paused' } else if (track) { state = 'playing' } var ms = navigator.mediaSession; ms.setActionHandler('nexttrack', window.webampNext); ms.setActionHandler('previoustrack', window.webampPrevious); handleThumbar( state, window.webampPlay, window.webampPause, window.webampPrevious, window.webampNext, ) } function getTranslateXY(element) { const style = window.getComputedStyle(element) const matrix = new DOMMatrixReadOnly(style.transform) return { translateX: matrix.m41, translateY: matrix.m42 } } ipcRenderer.on('unlockWindow', (event, store) => { windowLock = false; document.getElementById('title-bar').style.webkitAppRegion = 'no-drag'; setTimeout(() => { // window.centerWindowsInView(); }, 100) }); ipcRenderer.on('lockWindow', (event, store) => { windowLock = true; document.getElementById('title-bar').style.webkitAppRegion = 'drag'; }); ipcRenderer.on('lockWindowWithoutSave', (event, store) => { windowLock = true; window.centerWindowsInView(); document.getElementById('title-bar').style.webkitAppRegion = 'drag'; }); ipcRenderer.on('setFullscreen', (event, status) => { fullscreen = status; }); setInterval(() => { if (windowLock) { zoom = zoom ? zoom : 1; const windows = []; // Helper function to collect window data const addWindowData = (containerId, windowId) => { const containerEl = document.getElementById(containerId); const windowEl = document.getElementById(windowId); if (containerEl && windowEl) { const rect = windowEl.getBoundingClientRect(); const translate = getTranslateXY(containerEl); windows.push({ x: translate.translateX, y: translate.translateY, width: rect.width, height: rect.height }); } }; // Collect data for all windows addWindowData('main', 'main-window'); addWindowData('playlist', 'playlist-window'); addWindowData('equalizer', 'equalizer-window'); addWindowData('milkdrop', 'gen-window'); if (windows.length === 0) return; // Calculate min and max extents let minX = Math.min(...windows.map(win => win.x)); let maxRight = Math.max(...windows.map(win => win.x + win.width)); let minY = Math.min(...windows.map(win => win.y)); let maxBottom = Math.max(...windows.map(win => win.y + win.height)); let totalWidth = maxRight - minX; let totalHeight = maxBottom - minY; // Add additional padding if needed (e.g., 12px for height as in original code) totalHeight += 12; // Check for context menu const contextMenu = document.getElementById('webamp-context-menu'); if (contextMenu) { totalWidth += contextMenu.scrollWidth; const menuDiv = contextMenu.querySelector('div'); if (menuDiv) totalHeight += menuDiv.scrollHeight; } // Apply zoom if (zoom) { totalWidth = Math.round(totalWidth * zoom); totalHeight = Math.round(totalHeight * zoom); } if (totalWidth && totalHeight && !fullscreen) { remote.getCurrentWindow().setBounds({ width: totalWidth, height: totalHeight }); } } }, 100); // Adjust interval as needed ================================================ FILE: src/node/protocol.js ================================================ const fs = require('fs') const path = require('path') const mime = require('mime-types') const isDev = require('electron-is-dev') function interceptStreamProtocol() { // Content security policy const cspSrc = [ "default-src 'none'", "script-src 'self'", "style-src 'self' 'unsafe-inline' data:", "img-src 'self' data:", "font-src 'self' data:", "media-src 'self' blob:", "object-src 'self' blob:" ] if (isDev) { cspSrc.push("connect-src 'self' ws://127.0.0.1:54439") } else { cspSrc.push("connect-src 'self'") } return function (request, callback) { const url = request.url.substr(8) const filePath = path.normalize(`${__dirname}/../../${url}`) const contentType = mime.contentType(path.extname(request.url)) callback({ statusCode: fs.existsSync(filePath) ? 200 : 404, headers: { 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'private, max-age=0', 'Content-Type': contentType, // 'Content-Security-Policy': cspSrc.join(';'), 'Date': (new Date).toUTCString(), 'Server': 'Electron', 'X-Frame-Options': 'DENY', 'X-XSS-Protection': '1; mode=block', }, data: fs.createReadStream(filePath) }) } } module.exports = interceptStreamProtocol ================================================ FILE: src/node/thumbar.js ================================================ const path = require('path') const { remote, nativeImage } = require('electron') function handleThumbar(state = 'stopped', onPlay, onPause, onPrevious, onNext) { // Only supported on Windows if (process.platform !== 'win32') { return } const mainWindow = remote.getCurrentWindow() mainWindow.setThumbarButtons([ { icon: nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAgAElEQVR4Xu3d289dd53f8ffy2HGcBMckxmAMgYDBEDBDQmCcwa1mQiCBEEiAJCThkIPJ+Xw+x3ESonaqVv0DmIqbajStqt70otWgXoyqthdVK1VtL1pppGlHakdqpRm1Uu8+1Y+uMI+NHe/n2ae11ve9pMi52Hut3++11m8/bz/ee+0ONwUUUEABBRQoJ9CVm7ETVkABBRRQQAEMAC8CBRRQQAEFCgoYAAVPulNWQAEFFFDAAPAaUEABBRRQoKCAAVDwpDtlBRRQQAEFDACvAQUUUEABBQoKGAAFT7pTVkABBRRQwADwGlBAAQUUUKCggAFQ8KQ7ZQUUUEABBQwArwEFFFBAAQUKChgABU+6U1ZAAQUUUMAA8BpQQAEFFFCgoIABUPCkO2UFFFBAAQUMAK8BBRRQQAEFCgoYAAVPulNWQAEFFFDAAPAaUEABBRRQoKCAAVDwpDtlBRRQQAEFDACvAQUUUEABBQoKGAAFT7pTVkABBRRQwADwGlBAAQUUUKCggAFQ8KQ7ZQUUUEABBQwArwEFFFBAAQUKChgABU+6U1ZAAQUUUMAA8BpQQAEFFFCgoIABUPCkO2UFFFBAAQUMAK8BBRRQQAEFCgoYAAVPulNWQAEFFFDAAPAaUEABBRRQoKCAAVDwpDtlBRRQQAEFDACvAQUUUEABBQoKGAAFT7pTVkABBRRQwADwGlBAAQUUUKCggAFQ8KQ7ZQUUUEABBQwArwEFFFBAAQUKChgABU+6U1ZAAQUUUMAA8BpQQAEFFFCgoIABUPCkO2UFFFBAAQUMAK8BBRRQQAEFCgoYAAVPulNWQAEFFFDAAPAaUEABBRRQoKCAAVDwpDtlBRRQQAEFDACvAQUUUEABBQoKGAAFT7pTVkABBRRQwADwGlBAAQUUUKCggAFQ8KQ7ZQUUUEABBQwArwEFFFBAAQUKChgABU+6U1ZAAQUUUMAA8BpQQAEFFFCgoIABUPCkO2UFFFBAAQUMAK8BBRRQQAEFCgoYAAVPulNWQAEFFFDAAPAaUEABBRRQoKCAAVDwpDtlBRRQQAEFDACvAQUUUEABBQoKGAAFT7pTVkABBRRQwADwGlBAAQUUUKCggAFQ8KQ7ZQUUUEABBQwArwEFFFBAAQUKChgABU+6U1ZAAQUUUMAA8BpQQAEFFFCgoIABUPCkO2UFFFBAAQUMAK8BBRRQQAEFCgoYAAVPulNWQAEFFFDAAPAaUEABBRRQoKCAAVDwpDtlBRRQQAEFDACvAQUUUEABBQoKGAAznvQkvwMcBY4AlwIfBPYAfwL8V+DfAf8C+Kdd1/3FjLv1YQoooIACMwgk2QV8Bfga8A3g4/3T/hL4c+DPgH8J/FHXdb+YYZflH2IAvMslkOQC4CXgHuB9m7ha/hA40XXdf9jEc3yoAgoooMApAkm+BRwDvgqcOyNQ+0vYm13X/a0ZH1/yYQbAGU57kquAPwAumePKeLLrur8zx/N9qgIKKFBSIMn17Yc48Pk5AP60/QWu67o/mmMfk32qAXCaU5vkbuBnCzrrf7/rujsWtC93o4ACCkxaIMl1wHHgtxY40Ze7rntrgfubxK4MgF//ddP3gH+w4LNrBCwY1N0poMC0BPr3Wb3Rv9dqGZO7teu69s+zbr2AAbDhUkjyAeA/A+3f/he93dJ13aLDYtFjdH8KKKDASgWStDdWt1/1tzf4LXP778DBruv+zzIPMqZ9GwAnB8Br/a+elnEO/1XXde19BW4KKKBAeYEkV/Y/+K9dIcZzXdf9zRUeb9CHMgBODoB/D3x2iWfsw13X/bcl7t9dK6CAAoMWSHJF/4P/62sY6B93XffX13DcQR7SADg5ANrnSd+zxDP1za7r/skS9++uFVBAgUEKJDkMtH/j//YaB/g/u67bu8bjD+rQBsDJAZAln51jXdct6tMFSx6qu1dAAQXmF0hyWbsvCvAdYO0/c7quW/sY5lddzB6EMAAWcyW5FwUUUODk19ND/XuqbgG2DQXHAPirM2EAGABDWZeOQwEFJiCQ5CDQ3lB9+5B+8L9DawAYAKddZkn8J4AJvAA5BQUUWL1AknbX1HYDnx8C21c/gtmOaAAYAAbAbGvFRymggALvKpDkAPAqcBewY+hcBoABYAAMfZU6PgUUGLRAkv3Ay/0X9Zwz6MFuGJwBYAAYAGNZrY5TAQUGJZBkH/AicN8mvp1vMHMwAAwAA2Awy9GBKKDAGASStM/PPw88COwaw5hPN0YDwAAwAMa6eh23AgqsVCDJRcAzwCPA+Ss9+BIOZgAYAAbAEhaWu1RAgekIJNkDPAk8vuQ7pK4UzQAwAAyAlS45D6aAAmMRSLK7/6H/BNAiYFKbAWAAGACTWtJORgEF5hVIch7wGPA00H7tP8nNADAADIBJLm0npYACmxVI0t7Q9zDwLDD5L8oxAAwAA2CzrxI+XgEFJiWQZCfwQP/O/vdPanLvMhkDwAAwAKqsduepgAInCSRpN+35Sf9Z/g9W4zEADAADoNqqd74KFBdI0m7TezfwEvDhqhwGgAFgAFRd/c5bgWICSdoX8/wIeAX4aLHp/9p0DQADwACo/irg/BWYuECS3wDu6L+o5+MTn+7M0zMADAADYObl4gMVUGBMAkk64PvAa8ChMY19FWM1AAwAA2AVK81jKKDAygT6H/zfBY4Dn1nZgUd2IAPAADAARrZoHa4CCpxZIMmNwOvA53R6dwEDwAAwAHyVUECB0QskuR44AVwx+smsaAIGgAFgAKxosXkYBRRYvECSa/sf/F9a/N6nvUcDwAAwAKa9xp2dApMUSHJ1/4P/y5Oc4AomZQAYAAbAChaah1BAgcUIJDkKvA20P93mEDAADAADYI4F5FMVUGA1AkmOAG8A16zmiNM/igFgABgA01/nzlCB0QokuRz4KXDdaCcx0IEbAAaAATDQxemwFKgskOQw8BZwQ2WHZc7dADAADIBlrjD3rYACmxJIcln/q/6bgHYnP7clCRgABoABsKTF5W4VUGB2gSTtVr3tc/w3+4N/drd5HmkAGAAGwDwryOcqoMBcAkkO9rfsvQ3YNtfOfPKmBAwAA8AA2NSS8cEKKLAIgSSX9l/S8wOgfVuf24oFDAADwABY8aLzcApUFkhyCfAKcCewvbLFuuduABgABsC6V6HHV6CAQJIDwEvAPcA5BaY8+CkaAAaAATD4ZeoAFRivQJJ9wMvAvcDO8c5keiM3AAwAA2B669oZKbB2gSR7gReAB4Bdax+QA/g1AQPAADAAfGFQQIGFCSS5CHgOeAg4f2E7dkcLFzAADAADYOHLyh0qUE8gyR7gaeBR4D31BMY3YwPAADAAxrduHbECgxFIsht4ov/vwsEMzIGcVcAAMAAMgLMuEx+ggAKnCiS5AHgMeAp4r0LjEzAADAADYHzr1hErsDaBJOcBDwPPAhevbSAeeG4BA8AAMADmXkbuQIHpCyRp7+Rv7+hvb/BrH+1zG7mAAWAAGAAjX8QOX4FlCiRpN+25r/9I3/5lHst9r1bAADAADIDVrjmPpsAoBJLsAI4BLwIfGsWgHeSmBAwAA8AA2NSS8cEKTFsgSbs/f7tPf7t730emPdvaszMADAADoPZrgLNX4JcCSdo38rVv5nsV+Jgs0xcwAAwAA2D669wZKnBGgSTbgNv6H/yflKqOgAFgABgAdda7M1XgVwJJOuBm4DjwaWnqCRgABoABUG/dO+PCAv0P/pv6H/yHC1OUn7oBYAAYAOVfBgSoIpDkBuB14PIqc3aeZxYwAAwAA8BXCAUmLpDkOuAE8MWJT9XpbULAADAADIBNLBgfqsCYBJJc0//gv2pM43asqxEwAAwAA2A1a82jKLAygSRHgbeB9qebAqcVMAAMAAPAFwcFJiKQ5AjwFnD1RKbkNJYoYAAYAAbAEheYu1ZgFQJJrgTeBK5dxfE8xjQEDAADwACYxlp2FgUFkrR3878BXF9w+k55TgEDwAAwAOZcRD5dgVULJGmf32/v6r9x1cf2eNMRMAAMAANgOuvZmUxcIMmh/lf93wXanfzcFNiygAFgABgAW14+PlGB1QgkOdj/jf9WoN27302BuQUMAAPAAJh7GbkDBZYjkOTS/pa9dwDt2/rcFFiYgAFgABgAC1tO7kiBxQgkuQR4DfgRsH0xe3UvCpwsYAAYAAaArwoKDEQgyQHgFeBuYMdAhuUwJipgABgABsBEF7fTGo9Akv3AS8AxYOd4Ru5IxyxgABgABsCYV7BjH7VAkn3AC8D9wLmjnoyDH52AAWAAGACjW7YOeOwCSfYCzwIPAeeNfT6Of5wCBoABYACMc+066hEKJNnT/+B/BLhghFNwyBMSMAAMAANgQgvaqQxTIMlu4CngcaD9v5sCaxcwAAwAA2Dty9ABTFUgSftb/hPAk0D727+bAoMRMAAMAANgMMvRgUxFIEn7d/1HgWeAi6YyL+cxLQEDwAAwAKa1pp3NGgWS7AIeBJ4D3rfGoXhoBc4qYAAYAAbAWZeJD1Dg3QWStM/ut4/yPQ98QC8FxiBgABgABsAYVqpjHKRAknP6m/e8CLS7+LkpMBoBA8AAMABGs1wd6FAEkrTb9N7V372v3bffTYHRCRgABoABMLpl64DXJZCkfSNf+4Kedr/+9k19bgqMVsAAMAAMgNEuXwe+KoEk24Db+2/oO7iq43ocBZYpYAAYAAbAMleY+x61QJIOuLX/wf+pUU/GwStwioABYAAYAL4sKHCKQP+D/zvAceCzAikwRQEDwAAwAKa4sp3TlgWSfBt4HfjNLe/EJyowAgEDwAAwAEawUB3i8gWSfAM4AXxh+UfzCAqsX8AAMAAMgPWvQ0ewRoEkX+1/8B9Z4zA8tAIrFzAADAADYOXLzgMOQSDJ7/Y/+I8OYTyOQYFVCxgABoABsOpV5/HWKpCk/U3/9wB/8K/1THjwdQsYAAaAAbDuVejxVyKQ5Ergp0D7lb+bAuUFDAADwAAo/zIwbYAklwNvAu1Nfm4KKNALGAAGgAHgy8EkBZIc7n/wf2uSE3RSCswpYAAYAAbAnIvIpw9LIMll/Zv72o182p383BRQ4DQCBoABYAD40jAJgSSH+hv43OIP/kmcUiexZAEDwAAwAJa8yNz9cgWStC/nea3/sp72pT1uCigwg4ABYAAYADMsFB8yPIEk7et429fytq/nbV/T66aAApsQMAAMAANgEwvGh65fIMmB/m/8dwI71j8iR6DAOAUMAAPAABjn2i036iT7gZeBY8A55QCcsAILFjAADAADYMGLyt0tViDJPuAl4F7g3MXu3b0pUFfAADAADIC663/QM0+yF3geeBDYNejBOjgFRihgABgABsAIF+6Uh5zkIuAZ4BHg/CnP1bkpsE4BA8AAMADWuQI99q8EkuwBngIeA94jjQIKLFfAADAADIDlrjH3fhaBJLuBx4EngQsFU0CB1QgYAAaAAbCateZRThFIcgHwaP+3/vZrfzcFFFihgAFgABgAK1xwHgqStDf0PQw8C7Q3+rkpoMAaBAwAA8AAWMPCq3jIJDv7d/Q/B7y/ooFzVmBIAgaAAWAADGlFTnAsSdpNe9pn+F8APjjBKTolBUYpYAAYAAbAKJfu8AedpN2m9+7+Jj4fHv6IHaECtQQMAAPAAKi15pc+2yTbgR/3t+396NIP6AEUUGBLAgaAAWAAbGnp+KRTBZK0b+S7A3gV+LhCCigwbAEDwAAwAIa9Rgc/uiTbgO/339D3ycEP2AEqoMAvBQwAA8AA8MVgSwJJOuB7wHHgsi3txCcpoMDaBAwAA8AAWNvyG++Bk9wIvA58bryzcOQK1BYwAAwAA6D2a8CmZp/km/0P/is29UQfrIACgxMwAAwAA2Bwy3J4A0pyLXAC+NLwRueIFFBgKwIGgAFgAGxl5RR5TpKv9D/4f7vIlJ2mAmUEDAADwAAos9xnn2iSo8DbQPvTTQEFJihgABgABsAEF/ZWp5TkCPAm0P7m76aAAhMWMAAMAANgwgt81qkluRJ4A7hu1uf4OAUUGLeAAWAAGADjXsNzjT7JYeCnQHt3v5sCChQSMAAMAAOg0IJ/Z6pJ2o172q/62+f52w193BRQoJiAAWAAGACFFn2SQ/27+m/2B3+hE+9UFTiNgAFgABgABV4akhzsb+DT7tnf7t3vpoACxQUMAAPAAJjwi0CSS/sv6fkB0L6tz00BBRT4pYABYAAYABN8MUhySf+1vD8Gtk9wik5JAQXmFDAADAADYM5FNKSnJzkAvAzcA+wY0tgciwIKDEvAADAADIBhrcktjSbJfuAF4F5g55Z24pMUUKCUgAFgABgAI17ySfYCLwL3A7tGPBWHroACKxYwAAwAA2DFi24Rh0tyEfAc8DBw3iL26T4UUKCWgAFgABgAI1rzSfYAzwCPAheMaOgOVQEFBiZgABgABsDAFuXphpNkN/Ak8ATQ/t9NAQUUmEvAADAADIC5ltByn5yk/S3/MeAp4L3LPZp7V0CBSgIGgAFgAAxwxSdp/67/SP/r/osHOESHpIACIxcwAAwAA2BAizhJeyf/A/0b/PYNaGgORQEFJiZgABgABsAAFnWS9tn9+4DngfaZfjcFFFBgqQIGgAFgACx1ib37zpO0u/UdA14C2l383BRQQIGVCBgABoABsJKldvJBkrT789/Z37b3I2sYgodUQIHiAgaAAWAArPBFIEn7Rr4fAq8AH1vhoT2UAgoocJKAAWAAGAAreFFIsg24rf9q3k+s4JAeQgEFFHhXAQPAADAAlvgikaQDbul/8H96iYdy1woooMCmBAwAA8AA2NSSme3B/Q/+m4DjwOHZnuWjFFBAgdUJGAAGgAGw4PWW5AbgBPD5Be/a3SmggAILEzAADAADYEHLKcnX+x/8Vy5ol+5GAQUUWJqAAWAAGABzLq8k1/Q/+K+ac1c+XQEFFFiZgAFgABgAW1xuSY4CbwPtTzcFFFBgVAIGgAFgAGxyySY5ArwFXL3Jp/pwBRRQYDACBoABYADMuByTtH/bbz/4vzbjU3yYAgooMFgBA8AAMADOsjyTXA68AVw/2JXswBRQQIFNChgABoABcIZFk6R9fr/94P/2JteVD1dAAQUGL2AAGAAGwCkCSS4DXge+C7Q7+bkpoIACkxMwAAwAA6AXSHKw/zjfrUC7d7+bAgooMFkBA8AAKB8ASS7t/8Z/O9C+rc9NAQUUmLyAAWAAlA2AJJf0X9LzI2D75Fe7E1RAAQU2CBgABkC5AEhyAHgVuAvY4SuCAgooUFHAADAAygRAkv3AS8BPgHMqLnjnrIACCrwjYAAYAJMPgCT7gBeA+4FzXf4KKKCAAmAAGACTDYAke4HngAeB81zwCiiggAIbfuh1nR9z7jmE2LAykmTJC+VY13U/W8YxklwEPA08AlywjGO4TwUUUGDsAv4GwN8ATOY3AEl29z/4HwPa/7spoIACCpxBwAAwAEYfAEna3/KfAJ4E9rjaFVBAAQXOLmAAGACjDYAk7d/129/226/726/93RRQQAEFZhQwAAyA0QVAkl3AQ8CzwPtmvNZ9mAIKKKDABgEDwAAYTQAk2dl/lK99pO/9rmQFFFBAga0LGAAGwOADIEm7aU+7ec+LwAe3frn7TAUUUECBdwQMAANgsAGQpN2mt92u92Xgwy5bBRRQQIHFCRgABsDgAiBJ+2Ke9gU97Qd/+6Y+NwUUUECBBQsYAAbAYAIgyTbgjv6Leg4u+Fp3dwoooIACGwQMAANg7QGQpN2F8VbgOHDIFaqAAgoosHwBA8AAWFsAAL8PfLf/wf+Z5V/uHkEBBRRQ4B0BA8AAWFcA/By4AjjsclRAAQUUWL2AAWAArCsAVn+1e0QFFFBAgV8JGAAGgAHgC4ICCihQUMAAMAAMgIIL3ykroIACBoABYAD4OqCAAgoUFDAADAADoODCd8oKKKCAAWAAGAC+DiiggAIFBQwAA8AAKLjwnbICCihgABgABoCvAwoooEBBAQPAADAACi58p6yAAgoYAAaAAeDrgAIKKFBQwAAwAAyAggvfKSuggAIGgAFgAPg6oIACChQUMAAMAAOg4MJ3ygoooIABYAAYAL4OKKCAAgUFDAADwAAouPCdsgIKKGAAGAAGgK8DCiigQEEBA8AAMAAKLnynrIACChgABoAB4OuAAgooUFDAADAADICCC98pK6CAAgaAAWAA+DqggAIKFBQwAAwAA6DgwnfKCiiggAFgABgAvg4ooIACBQUMAAPAACi48J2yAgooYAAYAAaArwMKKKBAQQEDwAAwAAoufKesgAIKGAAGgAHg64ACCihQUMAAMAAMgIIL3ykroIACBoABYAD4OqCAAgoUFDAADAADoODCd8oKKKCAAWAAGAC+DiiggAIFBQwAA8AAKLjwnbICCihgABgABoCvAwoooEBBAQPAADAACi58p6yAAgoYAAaAAeDrgAIKKFBQwAAwANYVAD8HvgB8tuC6c8oKKKDA2gUMAANgXQFwD/D3gO8Axw2Btb8WOAAFFCgmYAAYAOsKgGNd1/2sHTxJB9zSh8Cniq1Bp6uAAgqsRcAAMADWHgDvDCDJNuB24FXgE2tZER5UAQUUKCJgABgAgwmADSHwG8CPgFeAS4usRaepgAIKrFTAADAABhcAG0JgO3AX8DJwyUpXhgdTQAEFJi5gABgAgw2ADSFwDnAMeBE4MPE16fQUUECBlQgYAAbA4ANgQwjsBO4DXgA+sJIV4kEUUECBiQoYAAbAaAJgQwjsAh4EngPeN9G16bQUUECBpQoYAAbA6AJgQwicBzwKPA1cvNSV4s4VUECBiQkYAAbAaANgQwhcADwOPAXsmdgadToKKKDAUgQMAANg9AGwIQR29xHQYqD9v5sCCiigwBkEDAADYDIBsCEE2m8BngUeAdpvB9wUUEABBU4RMAAMgMkFwIYQ2NuHwENAe7+AmwIKKKBAL2AAGACTDYANIbCv/+jg/cC5rn4FFFBAATAADIDJB8CGENjf30zoJ0C7p4CbAgooUFbAADAAygTAhhBodxNs3zNwN7Cj7Op34gooUFrAADAAygXAhhBo3y/wWv/FQ+17B9wUUECBMgIGgAFQNgA2hED7xsHjwB1A+yZCNwUUUGDyAgaAAVA+ADaEwEHgBHArsG3yq98JKqBAaQEDwAAwAE4RSHIIeAP4HtCVfoVw8gooMFkBA8AAMADOsLyTHO5/I3DjZF8BnJgCCpQVMAAMAAPgLMs/yeX9bwSuL/tK4cQVUGByAgaAAWAAzLisk1wJvAlcO+NTfJgCCigwWAEDwAAwADa5PJMcAd4Crt7kU324AgooMBgBA8AAMAC2uByTHAXeBtqfbgoooMCoBAwAA8AAmHPJJrmmf7PgVXPuyqcroIACKxMwAAwAA2BByy3JdX0IfHFBu3Q3CiigwNIEDAADwABY8PJKcgPwOtA+PeCmgAIKDFLAADAADIAlLM0k7QZCN/W3GG73E3BTQAEFBiVgABgABsASl2QfAjf3IfDpJR7KXSuggAKbEjAADAADYFNLZmsPTtK+W+A24FXgk1vbi89SQAEFFidgABgABsDi1tNZ95SkfdvgD/oQ+NhZn+ADFFBAgSUJGAAGgAGwpMX1brtNsh24E3gZ+MgahuAhFVCguIABYAAYAGt8EUiyAzgGvAh8aI1D8dAKKFBMwAAwAAyAASz6JOcA9wEvAPsHMCSHoIACExcwAAwAA2BAizzJLuAB4Dlg34CG5lAUUGBiAgaAAWAADHBRJzkPeBh4Frh4gEN0SAooMHIBA8AAMAAGvIiTXAA8BjwFvHfAQ3VoCigwMgEDwAAwAEawaJPsBp4EHgcuHMGQHaICCgxcwAAwAAyAgS/SjcNLsgd4uv+tQPvtgJsCCiiwJQEDwAAwALa0dNb7pCQX9W8UfAg4f72j8egKKDBGAQPAADAAxrhy+zEn2dt/dLB9cqB9gsBNAQUUmEnAADAADICZlsqwH5SkfWSw3VXwXmDnsEfr6BRQYAgCBoABYAAMYSUuaAxJDvQhcDfQbi7kpoACCpxWwAAwAAyACb44JLkEeKX/voH2vQNuCiigwEkCBoABYABM+EUhyaXAa/03ELZvInRTQAEFfilgABgABkCBF4MkB4HjwG3AtgJTdooKKHAWAQPAADAACr1MJDkEnABubn8BKDR1p6qAAqcIGAAGgAFQ8GUhyWXAm8CNhkDBC8ApK+A/AZx0Dfi3oQ0cSbLkFXKs67qfLfkY7v4sAkkOA28BN4ilgAK1BPwNgL8B8DcAtdb8mc73lcAbwHVyKKBADQEDwAAwAGqs9ZlmmeRIHwLXzPQEH6SAAqMVMAAMAANgtMt3eQNPchR4G2h/uimgwAQFDAADwACY4MJe1JSSXN1/auDLi9qn+1FAgWEIGAAGgAEwjLU46FEkubYPgS8NeqAOTgEFZhYwAAwAA2Dm5eIDk3wTeB24Qg0FFBi3gAFgABgA417Daxl9knb/gBYCn1vLADyoAgrMLWAAGAAGwNzLqOYOkrR7Z3yvv8Vwu7GQmwIKjEjAADAADIARLdghDjVJ+26BW/svHWq3GnZTQIERCBgABoABMIKFOoYhJmnfNngH8Crw8TGM2TEqUFnAADAADIDKrwBLmHuS7cCPgZeBjy7hEO5SAQUWIGAAGAAGwAIWkrv4dYEkO4C7gZeAD2ukgALDEjAADAADYFhrcnKjSXIOcC/wAvDByU3QCSkwUgEDwAAwAEa6eMc27CQ7gQeA54H3j238jleBqQkYAAaAATC1VT3w+STZBTwMPAvsHfhwHZ4CkxUwAAwAA2Cyy3vYE0tyHvA48BRw0bBH6+gUmJ6AAWAAGADTW9ejmlGS3X0IPAlcOKrBO1gFRixgABgABsCIF/CUhp5kT//bgMeA90xpbs5FgSEKGAAGgAEwxJVZeExJ2j8HPAM8ApxfmMKpK7BUAQPAADAAlrrE3PlWBZK0N6nZiacAAA9ASURBVAi2Tww8CLQ3DropoMACBQwAA8AAWOCCcleLF0iyr7+ZULuXwLmLP4J7VKCmgAFgABgANdf+6GadZH9/e+FjQLu5kJsCCswhYAAYAAbAHAvIp65eIMmB/psH7wTa7YbdFFBgCwIGgAFgAGxh4fiU9QskuRR4BfgR0L6J0E0BBTYhYAAYAAbAJhaMDx2eQJKD/W8Ebge2DW+EjkiBYQoYAAaAATDMtemoNimQ5BDwOnAL0G3y6T5cgXICBoABYACUW/bTnnCSy4ATwHcMgWmfa2c3n4ABYAAYAPOtIZ89UIEkh4E3gW8NdIgOS4G1ChgABoABsNYl6MGXLZDk8j4EvrHsY7l/BcYkYAAYAAbAmFasY92yQJIrgZ8CX93yTnyiAhMSMAAMAANgQgvaqZxdIMkR4PeAo2d/tI9QYLoCBoABYABMd307s3cRSPK7/ZsFDQGvlJICBoABYACUXPpO+h2BJF/rQ+C3VFGgkoABYAAYAJVWvHM9o0CS9ibB9vHBL8ikQAUBA8AAMAAqrHTnOLNAkm/3NxT6zZmf5AMVGKGAAWAAGAAjXLgOebkCSdqdBNuNhNqdBT+z3KO5dwXWI2AAGAAGwHrWnkcdgUAfArf23zXwqREM2SEqMLOAAWAAGAAzLxcfWFUgSfuSoTuAV4H25UNuCoxewAAwAAyA0S9jJ7AqgSTta4fb1w+3ryFuX0fspsBoBQwAA8AAGO3ydeDrEkiyA7gLeAm4ZF3j8LgKzCNgABgABsA8K8jnlhZIcg5wDHgROFAaw8mPTsAAMAAMgNEtWwc8NIEkO4H7geeBDwxtfI5HgdMJGAAGgAHga4MCCxJIsgt4CHgWeN+CdutuFFiKgAFgABgAS1la7rSyQJLzgEeBZ4CLKls49+EKGAAGgAEw3PXpyEYukOQC4AngSWDPyKfj8CcmYAAYAAbAxBa10xmeQJLdwFPA40D7fzcF1i5gABgABsDal6EDqCKQpP1zwNPAI0D77YCbAmsTMAAMAANgbcvPA1cVSLIXeA54EGjvF3BTYOUCBoABYACsfNl5QAX+v0CSfcAL/UcIz9VFgVUKGAAGgAGwyhXnsRQ4jUCS/f1dBX8CtJsLuSmwdAEDwAAwAJa+zDyAArMJJGl3E2zfM3A30G437KbA0gQMAAPAAFja8nLHCmxNIEn7foHX+i8e2r61vfgsBd5dwAAwAAwAXyUUGKhAkvaNg68DtwPtmwjdFFiYgAFgABgAC1tO7kiB5QgkOQicAG4Fti3nKO61moABYAAYANVWvfMdrUCSy/rfCHwX6EY7EQc+CAEDwAAwAAaxFB2EArMLJDnc/0bgxtmf5SMVOFnAADAADABfFRQYqUCSy4E3gOtHOgWHvUYBA8AAMADWuAA9tAKLEEhyJfAW8LVF7M991BAwAAwAA6DGWneWBQSSHOlD4OoC03WKcwoYAAaAATDnIvLpCgxNIMlR4G2g/emmwGkFDAADwADwxUGBiQokuaZ/s+BVE52i05pDwAAwAAyAORaQT1VgDAJJvt5/fPCLYxivY1yNgAFgABgAq1lrHkWBtQskuaH/jcDn1z4YB7B2AQPAADAA1r4MHYACqxNI0m4gdBNwHGj3E3ArKmAAGAAGQNHF77RrC/QhcEv/pUOfrq1Rc/YGgAFgANRc+85agV8KJGnfLXBbHwKfkKWOgAFgABgAdda7M1XgjAJJ2rcN/hB4BfiYVNMXMAAMAANg+uvcGSows0CS7cCdwMvAR2Z+og8cnYABYAAYAKNbtg5YgeULJNkBHANeAg4s/4geYdUCBoABYACsetV5PAVGJJBkJ3Af8Dywf0RDd6hnETAADAADwJcJBRQ4q0CSXcADwHPAvrM+wQcMXsAAMAAMgMEvUweowHAEkpwHPAI8A1w8nJE5ks0KGAAGgAGw2VXj4xVQoH188ALgMeAp4L2SjE/AADAADIDxrVtHrMBgBJLsBp4EngDa/7uNRMAAMAAMgJEsVoepwJAFkuzp/1ngUaD9dsBt4AIGgAFgAAx8kTo8BcYkkOSi/o2CDwPt/QJuAxUwAAwAA2Cgi9NhKTBmgSR7gReB+4H2CQK3gQkYAAaAATCwRelwFJiSQJJ274AXgHuBdk8Bt4EIGAAGgAEwkMXoMBSYskCSdjfBdnvhe4B2l0G3NQsYAAaAAbDmRejhFagkkOQS4FXgx0D73gG3NQkYAAaAAbCmxedhFagskOTS/iuIfwC0byJ0W7GAAWAAGAArXnQeTgEF/kogyUHgdeD7wDZtVidgABgABsDq1ptHUkCBMwgkOQScAG4GOqGWL2AAGAAGwPLXmUdQQIEZBZJcBrwJ3GgIzIi2xYcZAAaAAbDFxePTFFBgeQJJLu9/I/DN5R2l9p4NAAPAAKj9GuDsFRi0QJIrgTeA6wY90BEOzgAwAAyAES5ch6xANYEkR/p/GvhKtbkva74GgAFgACxrdblfBRRYuECSo8DbQPvTbQ4BA8AAMADmWEA+VQEF1iOQpP0moH1q4LfXM4LxH9UAMAAMgPGvY2egQFmBJNf2IfClsghbnLgBYAAYAFtcPD5NAQWGI5CkfVqg3VDoiuGMatgjMQAMAANg2GvU0SmgwCYEktwEHAc+t4mnlXyoAWAAGAAll76TVmC6AknanQS/14dAu7GQ22kEDAADwADwpUEBBSYpkKR9t0D7joHXgE9OcpJzTMoAMAAMgDkWkE9VQIHhCyRp3zZ4R/81xB8f/ohXM0IDwAAwAFaz1jyKAgqsWSDJduDHwCvAR9Y8nLUf3gAwAAyAtS9DB6CAAqsUSLIDuAd4CfjQKo89pGMZAAaAATCkFelYFFBgZQJJzgHuBV4E9q/swAM5kAFgABgAA1mMDkMBBdYjkGQn8CDwHPD+9Yxi9Uc1AAwAA2D1684jKqDAAAWS7AIeBp4F9g5wiAsdkgFgABgAC11S7kwBBcYukOQC4FHgaeC9Y5/PmcZvABgABsBUV7fzUkCBuQSS7Aae6P+7cK6dDfDJBoABYAAMcGE6JAUUGI5Akj3AU8BjwHuGM7L5RmIAGAAGwHxryGcroEARgSQX9e8PaO8TOH/s0zYADAADYOyr2PEroMBKBZK0Nwg+339yoL1xcJSbAWAAGACjXLoOWgEF1i2QZF9/M6H7gPZRwlFtBoABYACMask6WAUUGJpAknYToXZ74XZ3wXZzoVFsBoABYACMYqk6SAUUGLpAkkuAl4G7gPa9A4PeDAADwAAY9BJ1cAooMDaBJJf23zz4Q6B9E+EgNwPAADAABrk0HZQCCoxdIMlB4DhwG7BtaPMxAAwAA2Boq9LxKKDApASSHAJeB24BuqFMzgAwAAyAoaxGx6GAApMWSHIZ8AZw0xBCwAAwAM4UAP9ryffAvqnrun886dXu5BRQQIHTCCQ5DLwJfGuNQP+767rJ3NVwXsfB/Fpm3oks4vlJ/jXwpUXs6wz7uKzruv+0xP27awUUUGDQAkm+0P9G4OtrGOi/6bruyjUcd5CHNAA2nJYk7esw/8aSztR/7LruM0vat7tVQAEFRiWQpP0gbr8RuHaFA3+t67oTKzzeoA9lAJwcAO1Wl38CtK/FXPR2Z9d1P1/0Tt2fAgooMGaBJEf73wj8zpLn8T+AT3Zd95dLPs5odm8AnHKqkrQ3qvyjBZ/Bf9h13c0L3qe7U0ABBSYjkOTq/jcCVy1pUrd2XfeHS9r3KHdrAJzmtCVpd7T6/QWd0T9od8jquu7/Lmh/7kYBBRSYrECSr/Uh8MUFTvLFruveXuD+JrErA+AMpzFJq9D2w7vd5nKr21Nd1/3trT7Z5ymggAJVBZJc34fA5+cw+C/AvV3X/fM59jHZpxoA73Jqk7SPi7Qvu7gbuHgTV0H7NdNx3/G/CTEfqoACCpz+N7Lf7u8suJkQaB/pPtF13d8V9cwCBsCMV0eSrwDtzSrtY4Ltntftm7D29G8a/FPg3wJ/DPyi67q/mHG3PkwBBRRQYAaBJH8NuBH4MtBuLvTO5/nbm/r+HPgzoH2U+591XfeLGXZZ/iEGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgoYABXPunNWQAEFFCgvYACUvwQEUEABBRSoKGAAVDzrzlkBBRRQoLyAAVD+EhBAAQUUUKCigAFQ8aw7ZwUUUECB8gIGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgoYABXPunNWQAEFFCgvYACUvwQEUEABBRSoKGAAVDzrzlkBBRRQoLyAAVD+EhBAAQUUUKCigAFQ8aw7ZwUUUECB8gIGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgoYABXPunNWQAEFFCgvYACUvwQEUEABBRSoKGAAVDzrzlkBBRRQoLyAAVD+EhBAAQUUUKCigAFQ8aw7ZwUUUECB8gIGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgoYABXPunNWQAEFFCgvYACUvwQEUEABBRSoKGAAVDzrzlkBBRRQoLyAAVD+EhBAAQUUUKCigAFQ8aw7ZwUUUECB8gIGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgoYABXPunNWQAEFFCgvYACUvwQEUEABBRSoKGAAVDzrzlkBBRRQoLyAAVD+EhBAAQUUUKCigAFQ8aw7ZwUUUECB8gIGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgoYABXPunNWQAEFFCgvYACUvwQEUEABBRSoKGAAVDzrzlkBBRRQoLyAAVD+EhBAAQUUUKCigAFQ8aw7ZwUUUECB8gIGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgoYABXPunNWQAEFFCgvYACUvwQEUEABBRSoKGAAVDzrzlkBBRRQoLyAAVD+EhBAAQUUUKCigAFQ8aw7ZwUUUECB8gIGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgoYABXPunNWQAEFFCgvYACUvwQEUEABBRSoKGAAVDzrzlkBBRRQoLyAAVD+EhBAAQUUUKCigAFQ8aw7ZwUUUECB8gIGQPlLQAAFFFBAgYoCBkDFs+6cFVBAAQXKCxgA5S8BARRQQAEFKgr8P7CYv7UWbhAzAAAAAElFTkSuQmCC'), click: onPrevious, tooltip: 'Previous', flag: [(state === 'stopped' ? 'disabled' : 'enabled')], }, { icon: nativeImage.createFromDataURL(`${(state === 'playing' ? 'data:image/png;base64,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BgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQEAAeAMECBAgQGCggAAYeOmOTIAAAQIEBIA3QIAAAQIEBgoIgIGX7sgECBAgQOD/AXSg9tP0gtASAAAAAElFTkSuQmCC' : 'data:image/png;base64,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' )}`), click: state === 'playing' ? onPause : onPlay, tooltip: 'Play', flag: [(state === 'stopped' ? 'disabled' : 'enabled')], }, { icon: nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIACAYAAAD0eNT6AAAgAElEQVR4Xu3dSdBsZ33f8d9/kU3siiuVKsdJOWN5m8oic7LLWHElmyycbJyNnUqycqUSKiU0XdA8ogkJgRBikIwYZbCZByeRbRnLCCNbIBAIC4RACCEJIaEBdepBfc29usN7+u3TT3ef8+kqSip0+jznfJ7/ve/3vrff7ooHAQIECBAgMDuBmt0du2ECBAgQIEAgAsAQECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQIECAAIEZCgiAGW66WyZAgAABAgLADBAgQIAAgRkKCIAZbrpbJkCAAAECAsAMECBAgACBGQoIgBluulsmQIAAAQICwAwQ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7iY29M4kr66q/7eJkzsnAQIEpiCwWCzad0d/ceR7+cWqan/d6rEUEAAnGYXFYnF5kv854pS0P+m3v+P/1IjndCoCBAhMUmCxWPx0kncl+bcj3eB/qqr2Y9UexwgIgFOMw2Kx+PdJ3pjk59aYmD9cvqr/Q2ucw1MJECAwS4HFYnEkyblr3Hx7D5Vf8gLrkwsKgNNM1mKx+PNJfi3J/17xdQHtpwnaG/h8cI3B9VQCBAjMXmCxWPyD9mLpFf9KoH1AWvuU1Eurqn1iqsdJBATAwLFYLBb/Ism/SfKPkvzVJD+b5C8sn95eVPKlJP83yfur6vcGntZhBAgQIDBAYLFYtN9z2+/B/3j549o/n+RvJGm//7YPRmt/2v9Mkju9zmoAqJ8CGIbkKAIECBAgMDUB3wGY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiagACY2o66HwIECBAgMEBAAAxAcggBAgQIEJiawP8Hl2gF4sUAPwkAAAAASUVORK5CYII='), click: onNext, tooltip: 'Next', flag: [(state === 'stopped' ? 'disabled' : 'enabled')], }, ]) } module.exports = handleThumbar ================================================ FILE: src/node/thumbnail.js ================================================ const { remote } = require('electron') const { debounce } = require('./utilities') function handleThumbnail() { // Currently only supported on Windows // TODO: Add support for other platforms? if (process.platform !== 'win32') { return } const mainWindow = remote.getCurrentWindow() const mainWebampWindow = document.querySelector('#main-window') const setClip = () => { const boundingRect = mainWebampWindow.getBoundingClientRect() mainWindow.setThumbnailClip({ x: boundingRect.x, y: boundingRect.y, width: boundingRect.width, height: boundingRect.height, }) } const observer = new MutationObserver(debounce(setClip)) observer.observe( mainWebampWindow.parentElement, { attributes: true } ) setClip() } module.exports = handleThumbnail ================================================ FILE: src/node/transparency.js ================================================ const { remote } = require('electron') function handleTransparency() { const mainWindow = remote.getCurrentWindow() // Mac OS already handles it around the UI (windows and context menu) well. // TODO: Check if forward: true still doesn't work reliably // if the webamp windows is not in the foreground (no events triggered). // TODO: Check if skin transparency can be implemented without performance hit. // Windows // Ignoring mouse events around the UI (windows and context menu). // Works by using mousein and mouseout and forwarding when ignoring. if (process.platform === 'win32' || process.platform !== 'darwin') { mainWindow.setIgnoreMouseEvents(true, { forward: true }) let ignored = true const mouseenterHandler = () => { if (ignored) { mainWindow.setIgnoreMouseEvents(false) ignored = false } } const mouseleaveHandler = (e) => { if (!e.toElement || !e.toElement.offsetParent || e.toElement.offsetParent.id === 'webamp' ) { mainWindow.setIgnoreMouseEvents(true, { forward: true }) ignored = true } // We want to schedule events again for context menu. // Context menu can "stick out" of windows. if (e.toElement.classList.contains('context-menu')) { e.toElement.addEventListener('mouseenter', mouseenterHandler) e.toElement.addEventListener('mouseleave', mouseleaveHandler) e.toElement.addEventListener('click', () => { // Removing context menu means we have to trigger leave too // mainWindow.setIgnoreMouseEvents(true, { forward: true }) // ignored = true }) } } const rebindMouseEvents = () => { const webampWindows = document.querySelectorAll('#webamp .window') for (webampWindow of webampWindows) { webampWindow.removeEventListener('mouseenter', mouseenterHandler) webampWindow.removeEventListener('mouseleave', mouseleaveHandler) webampWindow.addEventListener('mouseenter', mouseenterHandler) webampWindow.addEventListener('mouseleave', mouseleaveHandler) } } const observer = new MutationObserver(() => { rebindMouseEvents() }) observer.observe( document.querySelector('#main-window').parentElement.parentElement, { childList: true } ) rebindMouseEvents() } // Linux // Ignoring mouse events around the UI (windows and context menu). // We'll track and save position of webamp windows and context menu // and poll mouse to see if it is within the saved bounds. // TODO: Check if we can use forward: true on this platform too. if (process.platform === 'linux') { /** * @type {[id: string]: {minX: number, maxX: number, minY: number, maxY: number} } */ const elementPositions = {} let ignored = false let interval const setupWatchingElements = () => { const watchWindowAttributes = (webampWindowWrapper) => { // Removed from the DOM if (webampWindowWrapper.parentElement === null) { delete elementPositions[webampWindowWrapper.children[0].id] return } const recalculateElementPositions = (windowWrapper) => { const recalcWindow = windowWrapper.children[0] const boundingRect = recalcWindow.getBoundingClientRect() elementPositions[recalcWindow.id] = { minX: boundingRect.x, minY: boundingRect.y, maxX: boundingRect.x + boundingRect.width, maxY: boundingRect.y + boundingRect.height, } } const observer = new MutationObserver( (mutationsList) => recalculateElementPositions( mutationsList[0].target ) ) observer.observe( webampWindowWrapper, { attributes: true } ) recalculateElementPositions(webampWindowWrapper) } const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { const changedNodes = mutation.addedNodes.length > 0 ? mutation.addedNodes : mutation.removedNodes for (const changedNode of changedNodes) { watchWindowAttributes(changedNode) } } }) observer.observe( document.querySelector('#main-window').parentElement.parentElement, { childList: true } ) for (const webampWindow of document.querySelectorAll('#webamp .window')) { watchWindowAttributes(webampWindow.parentElement) } // Context menu is watched just by observing adding and removing of the node. // When added, whole body is position of the contet menu. const contextMenuObserver = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.addedNodes.length > 0 && mutation.addedNodes[0].id === 'webamp-context-menu' ) { elementPositions['webamp-context-menu'] = { minX: 0, minY: 0, maxX: 9999, maxY: 9999, } } if (mutation.removedNodes.length > 0 && mutation.removedNodes[0].id === 'webamp-context-menu' ) { delete elementPositions['webamp-context-menu'] } } }) contextMenuObserver.observe( document.querySelector('body'), { childList: true } ) } const enableTransparencyChecking = () => { clearInterval(interval) interval = setInterval(() => { const cursorPoint = remote.screen.getCursorScreenPoint() const windowBounds = mainWindow.getBounds() const cursorWithinBounds = (cursorPoint.x >= windowBounds.x && cursorPoint.x <= (windowBounds.x + windowBounds.width) ) && (cursorPoint.y >= windowBounds.y && cursorPoint.y <= (windowBounds.y + windowBounds.height) ) if (!cursorWithinBounds) { return } const positionInWindow = { x: cursorPoint.x - windowBounds.x, y: cursorPoint.y - windowBounds.y, } for (const elementId of Object.keys(elementPositions)) { const elementPosition = elementPositions[elementId] const withinX = (positionInWindow.x > elementPosition.minX) && (positionInWindow.x < elementPosition.maxX) if (!withinX) { continue } const withinY = (positionInWindow.y > elementPosition.minY) && (positionInWindow.y < elementPosition.maxY) const within = withinX && withinY if (within) { if (ignored) { mainWindow.setIgnoreMouseEvents(false) ignored = false } return } } if (!ignored) { mainWindow.setIgnoreMouseEvents(true) ignored = true } }, 200) } const disableTransparencyChecking = () => { clearInterval(interval) } mainWindow.on('restore', () => { enableTransparencyChecking() }) mainWindow.on('minimize', () => { disableTransparencyChecking() }) mainWindow.on('closed', () => { disableTransparencyChecking() }) setupWatchingElements() enableTransparencyChecking() setInterval(() => { setupWatchingElements() }, 100) } } module.exports = handleTransparency ================================================ FILE: src/node/updates.js ================================================ const { autoUpdater } = require('electron-updater') const log = require('electron-log') const electron = require('electron') const isDev = require('electron-is-dev') const htmlToText = require('html-to-text') function checkForUpdatesAndNotify() { if (isDev) { console.warn('Updates are not checked in dev mode') return } autoUpdater.autoDownload = false autoUpdater.autoInstallOnAppQuit = false autoUpdater.fullChangelog = true autoUpdater.logger = log autoUpdater.on('update-available', (info) => { log.info('Got info about update available', info) electron.dialog.showMessageBox({ type: 'none', buttons: ['Открыть', 'Отмена'], title: 'Доступна новая версия', message: [ `Доступна новая версия: ${info.version}.`, ` Хотите её скачать?`, ].join(''), detail: htmlToText.fromString( info.releaseNotes.reduce((acc, n) => acc + n.version + '
' + n.note, ''), { singleNewLineParagraphs: true } ), noLink: true, }, (choice) => { if (choice === 0) { electron.shell.openExternal('https://yaamp.ru') } }) }) autoUpdater.on('error', (err) => { log.error('Update check failed', err) }) autoUpdater.checkForUpdates() } module.exports = checkForUpdatesAndNotify ================================================ FILE: src/node/utilities.js ================================================ function debounce(fn, time = 100) { let timeout return () => { const ctx = this, args = arguments clearTimeout(timeout) timeout = setTimeout(() => fn.apply(ctx, args), time) } } module.exports = { debounce } ================================================ FILE: src/renderer.ts ================================================ // Temporary switch to custom webamp build // import Webamp from 'webamp' import Webamp from './webamp/webamp.bundle.js' const { ipcRenderer } = window.require('electron'); const DEFAULT_DOCUMENT_TITLE = document.title let trackList: { metaData: { artist: string; title: any; }; url: string; duration: number; }[] = []; const webamp = new Webamp({ initialTracks: trackList, // initialSkin: { // url: './skins/base-2.91.wsz' // }, availableSkins: [ { url: './skins/base-2.91.wsz', name: 'Base v2.91' }, { url: './skins/Green-Dimension-V2.wsz', name: 'Green Dimension V2' }, { url: './skins/MacOSXAqua1-5.wsz', name: 'Mac OSX v1.5 (Aqua)' }, { url: './skins/Skinner_Atlas.wsz', name: 'Skinner Atlas' }, { url: './skins/TopazAmp1-2.wsz', name: 'TopazAmp v1.2' }, { url: './skins/Vizor1-01.wsz', name: 'Vizor v1.01' }, { url: './skins/XMMS-Turquoise.wsz', name: 'XMMS Turquoise' }, { url: './skins/ZaxonRemake1-0.wsz', name: 'Zaxon Remake v1.0' }, ], enableHotkeys: true, }) const unsubscribeOnMinimize = webamp.onMinimize(() => { window.minimizeElectronWindow() }) const unsubscribeOnClose = webamp.onClose(() => { window.closeElectronWindow() unsubscribeOnMinimize() unsubscribeOnClose() }) webamp.onTrackDidChange((track: any) => { window.webampOnTrackDidChange(track) if (track && 'metaData' in track && track.metaData.title && track.metaData.artist) { document.title = `${track.metaData.title} - ${track.metaData.artist}` } else if (track && 'defaultName' in track) { document.title = track.defaultName } else { document.title = DEFAULT_DOCUMENT_TITLE } ipcRenderer.invoke('nowPlaying', document.title); }) // Render after the skin has loaded. webamp.renderWhenReady(document.getElementById('app')).then( () => window.webampRendered() ) // Expose some webamp API on the window for the main process window.webampPlay = function () { // @ts-ignore webamp.play() } window.webampPlay = function () { // @ts-ignore webamp.play() } window.webampPause = function () { // @ts-ignore webamp.pause() } window.webampNext = function () { // @ts-ignore webamp.nextTrack() } window.webampPrevious = function () { // @ts-ignore webamp.previousTrack() } window.centerWindowsInView = function () { // @ts-ignore webamp.centerWindowsInView() } window.webampSetVolume = function (volume: number) { // @ts-ignore if (webamp.store) { // @ts-ignore webamp.store.dispatch({ type: 'SET_VOLUME', volume: Math.max(0, Math.min(100, volume)) }); } } window.webampPlayFirstTrack = function () { // @ts-ignore if (webamp.store) { // @ts-ignore const state = webamp.store.getState(); // @ts-ignore const trackOrder = state.playlist.trackOrder; if (trackOrder && trackOrder.length > 0) { // @ts-ignore const firstTrackId = trackOrder[0]; // @ts-ignore webamp.store.dispatch({ type: 'PLAY_TRACK', id: firstTrackId }); } } } ipcRenderer.invoke('getSkin').then((rs: any) => { if (rs) { webamp.setSkinFromClient(rs); } }) ipcRenderer.invoke('getEq').then((rs: any) => { if (rs) { webamp.setEqFromClient(rs); } }) ipcRenderer.invoke('getLikedTracks').then((rs: any) => { rs.result.forEach((element: any) => { let artist: any[] = []; if (element) { element.artists.forEach((a: any) => { artist.push(a.name); }); if (element.durationMs) { webamp.appendTracks([{ metaData: {artist: artist.join(', '), title: element.title}, url: element.id, duration: Math.floor(element.durationMs / 1000) }]); } } }); webamp.appendTracks(trackList); }) ipcRenderer.on("setTracks", (event:any, data: any) => { webamp.setTracksToPlay([]); let tracksIds: string[] = []; data.forEach((element: any) => { let artist: any[] = []; if (element) { element.artists.forEach((a: any) => { artist.push(a.name); }); if (element.durationMs) { if (!tracksIds.includes(element.id)) { webamp.appendTracks([{ metaData: {artist: artist.join(', '), title: element.title}, url: element.id, duration: Math.floor(element.durationMs / 1000) }]); tracksIds.push(element.id); } } } }); }); // Display loader ipcRenderer.on("setLoader", (event:any) => { const el = document.createElement('div'); el.classList.add('spinner'); const box = document.getElementById('playlist-window'); box.appendChild(el); }); ipcRenderer.on("hideLoader", (event:any) => { document.querySelector(".spinner").remove(); }); // Show message ipcRenderer.on("showMessage", (event:any, data: any) => { const el = document.createElement('div'); el.classList.add('message'); el.innerHTML = data; const box = document.getElementById('playlist-window'); box.appendChild(el); setTimeout(() => document.querySelector(".message").remove(), 1000); }); ipcRenderer.on("playPause", (event:any) => { // @ts-ignore const status = webamp.getMediaStatus(); // @ts-ignore if (status === "PLAYING") { // @ts-ignore webamp.pause(); ipcRenderer.invoke('isPlay', 0); } else if (status === "PAUSED") { // @ts-ignore webamp.play(); ipcRenderer.invoke('isPlay', 1); } else if (status === "STOPPED") { // @ts-ignore const state = webamp.store.getState(); // @ts-ignore const trackOrder = state.playlist.trackOrder; // @ts-ignore const currentTrack = state.playlist.currentTrack; // Если есть текущий трек, просто запускаем его if (currentTrack !== null && currentTrack !== undefined) { // @ts-ignore webamp.play(); ipcRenderer.invoke('isPlay', 1); } // Если нет текущего трека, но есть треки в плейлисте, запускаем первый else if (trackOrder && trackOrder.length > 0) { // @ts-ignore const firstTrackId = trackOrder[0]; // @ts-ignore webamp.store.dispatch({ type: 'PLAY_TRACK', id: firstTrackId }); ipcRenderer.invoke('isPlay', 1); } // Если плейлист пуст, ничего не делаем } }); setInterval(() => { // @ts-ignore if (webamp.getMediaStatus() === "PLAYING") { ipcRenderer.invoke('isPlay', 0); } else { ipcRenderer.invoke('isPlay', 1); } }, 2000); ipcRenderer.on("prevTrack", (event:any) => { // @ts-ignore webamp.previousTrack(); }); ipcRenderer.on("nextTrack", (event:any) => { // @ts-ignore webamp.nextTrack(); }) ipcRenderer.on("setVolume", (event:any, volume: number) => { window.webampSetVolume(volume); }); ================================================ FILE: src/webamp/webamp.bundle.d.ts ================================================ interface TrackInfo { /** * Name to be used until ID3 tags can be resolved. * * If the track has a `url`, and this property is not given, * the filename will be used instead. * * Example: `'My Song'` */ defaultName?: string; /** * Data to be used _instead_ of trying to fetch ID3 tags. * * Example: `{ artist: 'Jordan Eldredge', title: "Jordan's Song" }` */ metaData?: { artist: string, title: string, }, /** * Duration (in seconds) to be used instead of fetching enough of the file to measure its length. * * Example: 95 */ duration?: number; } interface URLTrack extends TrackInfo { /** * Source URL of the track * * Note: This URL must be served the with correct CORs headers. * * Example: `'https://example.com/song.mp3'` */ url: string | URL; } interface BlobTrack extends TrackInfo { /** * Blob source of the track */ blob: Blob; } /** * Many methods on the webamp instance deal with track. * * Either `url` or `blob` must be specified */ type Track = URLTrack | BlobTrack; interface Options { /** * An object representing the initial skin to use. * * If omitted, the default skin, included in the bundle, will be used. * Note: This URL must be served the with correct CORs headers. * * Example: `{ url: './path/to/skin.wsz' }` */ initialSkin?: { url: string, }; /** * An array of `Track`s to prepopulate the playlist with. */ initialTracks?: Track[]; /** * An array of objects representing available skins. * * These will appear in the "Options" menu under "Skins". * Note: These URLs must be served with the correct CORs headers. * * Example: `[ { url: "./green.wsz", name: "Green Dimension V2" } ]` */ availableSkins?: { url: string, name: string }[]; /** * Should global hotkeys be enabled? * * Default: `false` */ enableHotkeys?: boolean; /** * An array of additional file pickers. * * These will appear in the "Options" menu under "Play". * * In the offical version, this option is used to provide a "Dropbox" file picker. */ filePickers?: [{ /** * The name that will appear in the context menu. * * Example: `"My File Picker..."` */ contextMenuName: string, /** * A function which returns a Promise that resolves to an array of `Track`s * * Example: `() => Promise.resolve([{ url: './rick_roll.mp3' }])` */ filePicker: () => Promise, /** * Indicates if this options should be made available when the user is offline. */ requiresNetwork: boolean, }]; } export default class Webamp { constructor(options: Options); /** * Returns a true if the current browser supports the features that Webamp depends upon. * * It is recommended to check this before you attempt to instantiate an instance of Winamp. */ public static browserIsSupported(): boolean; /** * Add an array of `Track`s to the end of the playlist. */ public appendTracks(tracks: Track[]): void; /** * Replace the playlist with an array of `Track`s and begin playing the first track. */ public setTracksToPlay(tracks: Track[]): void; public setSkinFromClient(data: string): void; public setEqFromClient(data: string): void; /** * Webamp will wait until it has fetched the skin and fully parsed it and then render itself. * * Webamp is rendered into a new DOM node at the end of the tag with the id `#webamp`. * * If a domNode is passed, Webamp will place itself in the center of that DOM node. * * @returns A promise is returned which will resolve after the render is complete. */ public renderWhenReady(domNode: HTMLElement): Promise; /** * A callback which will be called when a new track starts loading. * * This can happen on startup when the first track starts buffering, or when a subsequent track starts playing. * The callback will be called with an object `({url: 'https://example.com/track.mp3'})` containing the URL of the track. * Note: If the user drags in a track, the URL may be an ObjectURL. * * @returns An "unsubscribe" function. Useful if at some point in the future you want to stop listening to these events. */ public onTrackDidChange(callback: (track: Track) => any): () => void; /** * A callback which will be called when Webamp is closed. * * @returns An "unsubscribe" function. Useful if at some point in the future you want to stop listening to these events. */ public onClose(callback: () => any): () => void; /** * A callback which will be called when Webamp is minimized. * * @returns An "unsubscribe" function. Useful if at some point in the future you want to stop listening to these events. */ public onMinimize(callback: () => any): () => void; } ================================================ FILE: src/webamp/webamp.bundle.js ================================================ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["Webamp"] = factory(); else root["Webamp"] = factory(); })(self, () => { return /******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ 1894: /***/ (function(__unused_webpack_module, exports, __webpack_require__) { "use strict"; var __read = this && this.__read || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = this && this.__spreadArray || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.convertAniBinaryToCSS = void 0; var parser_1 = __webpack_require__(7478); var JIFFIES_PER_MS = 1000 / 60; // Generate CSS for an animated cursor. // // This function returns CSS containing a set of keyframes with embedded Data // URIs as well as a CSS rule to the given selector. function convertAniBinaryToCSS(selector, aniBinary) { var ani = readAni(aniBinary); var animationName = "ani-cursor-".concat(uniqueId()); var keyframes = ani.frames.map(function (_a) { var url = _a.url, percents = _a.percents; var percent = percents.map(function (num) { return "".concat(num, "%"); }).join(", "); return "".concat(percent, " { cursor: url(").concat(url, "), auto; }"); }); // CSS properties with a animation type of "discrete", like `cursor`, actually // switch half-way _between_ each keyframe percentage. Luckily this half-way // measurement is applied _after_ the easing function is applied. So, we can // force the frames to appear at exactly the % that we specify by using // `timing-function` of `step-end`. // // https://drafts.csswg.org/web-animations-1/#discrete var timingFunction = "step-end"; // Winamp (re)starts the animation cycle when your mouse enters an element. By // default this approach would cause the animation to run continuously, even // when the cursor is not visible. To match Winamp's behavior we add a // `:hover` pseudo selector so that the animation only runs when the cursor is // visible. var pseudoSelector = ":hover"; // prettier-ignore return "\n @keyframes ".concat(animationName, " {\n ").concat(keyframes.join("\n"), "\n }\n ").concat(selector).concat(pseudoSelector, " {\n animation: ").concat(animationName, " ").concat(ani.duration, "ms ").concat(timingFunction, " infinite;\n }\n "); } exports.convertAniBinaryToCSS = convertAniBinaryToCSS; function readAni(contents) { var _a; var ani = (0, parser_1.parseAni)(contents); var rate = (_a = ani.rate) !== null && _a !== void 0 ? _a : ani.images.map(function () { return ani.metadata.iDispRate; }); var duration = sum(rate); var frames = ani.images.map(function (image) { return { url: curUrlFromByteArray(image), percents: [] }; }); var elapsed = 0; rate.forEach(function (r, i) { var frameIdx = ani.seq ? ani.seq[i] : i; frames[frameIdx].percents.push(elapsed / duration * 100); elapsed += r; }); return { duration: duration * JIFFIES_PER_MS, frames: frames }; } /* Utility Functions */ var i = 0; var uniqueId = function () { return i++; }; function base64FromDataArray(dataArray) { return window.btoa(String.fromCharCode.apply(String, __spreadArray([], __read(dataArray), false))); } function curUrlFromByteArray(arr) { var base64 = base64FromDataArray(arr); return "data:image/x-win-bitmap;base64,".concat(base64); } function sum(values) { return values.reduce(function (total, value) { return total + value; }, 0); } /***/ }), /***/ 7478: /***/ ((__unused_webpack_module, exports, __webpack_require__) => { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); exports.parseAni = void 0; var riff_file_1 = __webpack_require__(1343); var byte_data_1 = __webpack_require__(2394); var DWORD = { bits: 32, be: false, signed: false, fp: false }; function parseAni(arr) { var riff = new riff_file_1.RIFFFile(); riff.setSignature(arr); var signature = riff.signature; if (signature.format !== "ACON") { throw new Error("Expected format. Expected \"ACON\", got \"".concat(signature.format, "\"")); } // Helper function to get a chunk by chunkId and transform it if it's non-null. function mapChunk(chunkId, mapper) { var chunk = riff.findChunk(chunkId); return chunk == null ? null : mapper(chunk); } var metadata = mapChunk("anih", function (c) { var words = (0, byte_data_1.unpackArray)(arr, DWORD, c.chunkData.start, c.chunkData.end); return { cbSize: words[0], nFrames: words[1], nSteps: words[2], iWidth: words[3], iHeight: words[4], iBitCount: words[5], nPlanes: words[6], iDispRate: words[7], bfAttributes: words[8] }; }); if (metadata == null) { throw new Error("Did not find anih"); } var rate = mapChunk("rate", function (c) { return (0, byte_data_1.unpackArray)(arr, DWORD, c.chunkData.start, c.chunkData.end); }); // chunkIds are always four chars, hence the trailing space. var seq = mapChunk("seq ", function (c) { return (0, byte_data_1.unpackArray)(arr, DWORD, c.chunkData.start, c.chunkData.end); }); var lists = riff.findChunk("LIST", true); var imageChunk = lists === null || lists === void 0 ? void 0 : lists.find(function (c) { return c.format === "fram"; }); if (imageChunk == null) { throw new Error("Did not find fram LIST"); } var images = imageChunk.subChunks.slice(0, metadata.nFrames).map(function (c) { if (c.chunkId !== "icon") { throw new Error("Unexpected chunk type in fram: ".concat(c.chunkId)); } return arr.slice(c.chunkData.start, c.chunkData.end); }); var title = null; var artist = null; var infoChunk = lists === null || lists === void 0 ? void 0 : lists.find(function (c) { return c.format === "INFO"; }); if (infoChunk != null) { infoChunk.subChunks.forEach(function (c) { switch (c.chunkId) { case "INAM": title = (0, byte_data_1.unpackString)(arr, c.chunkData.start, c.chunkData.end); break; case "IART": artist = (0, byte_data_1.unpackString)(arr, c.chunkData.start, c.chunkData.end); break; default: // Unexpected subchunk } }); } return { images: images, rate: rate, seq: seq, metadata: metadata, artist: artist, title: title }; } exports.parseAni = parseAni; /***/ }), /***/ 4615: /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { "use strict"; // EXPORTS __webpack_require__.d(__webpack_exports__, { "default": () => (/* binding */ webampLazy) }); // EXTERNAL MODULE: ../../node_modules/@babel/runtime/helpers/esm/defineProperty.js + 3 modules var defineProperty = __webpack_require__(2601); // EXTERNAL MODULE: ../../node_modules/react/index.js var react = __webpack_require__(2784); // EXTERNAL MODULE: ../../node_modules/react-dom/index.js var react_dom = __webpack_require__(8316); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/components/Context.js var Context_ReactReduxContext = /*#__PURE__*/react.createContext(null); if (false) {} /* harmony default export */ const Context = ((/* unused pure expression or super */ null && (Context_ReactReduxContext))); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/utils/batch.js // Default to a dummy "batch" implementation that just runs the callback function defaultNoopBatch(callback) { callback(); } var batch = defaultNoopBatch; // Allow injecting another batching function later var setBatch = function setBatch(newBatch) { return batch = newBatch; }; // Supply a getter just to skip dealing with ESM bindings var getBatch = function getBatch() { return batch; }; ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/utils/Subscription.js // encapsulates the subscription logic for connecting a component to the redux store, as // well as nesting subscriptions of descendant components, so that we can ensure the // ancestor components re-render before descendants function createListenerCollection() { var batch = getBatch(); var first = null; var last = null; return { clear: function clear() { first = null; last = null; }, notify: function notify() { batch(function () { var listener = first; while (listener) { listener.callback(); listener = listener.next; } }); }, get: function get() { var listeners = []; var listener = first; while (listener) { listeners.push(listener); listener = listener.next; } return listeners; }, subscribe: function subscribe(callback) { var isSubscribed = true; var listener = last = { callback: callback, next: null, prev: last }; if (listener.prev) { listener.prev.next = listener; } else { first = listener; } return function unsubscribe() { if (!isSubscribed || first === null) return; isSubscribed = false; if (listener.next) { listener.next.prev = listener.prev; } else { last = listener.prev; } if (listener.prev) { listener.prev.next = listener.next; } else { first = listener.next; } }; } }; } var nullListeners = { notify: function notify() {}, get: function get() { return []; } }; function Subscription_createSubscription(store, parentSub) { var unsubscribe; var listeners = nullListeners; function addNestedSub(listener) { trySubscribe(); return listeners.subscribe(listener); } function notifyNestedSubs() { listeners.notify(); } function handleChangeWrapper() { if (subscription.onStateChange) { subscription.onStateChange(); } } function isSubscribed() { return Boolean(unsubscribe); } function trySubscribe() { if (!unsubscribe) { unsubscribe = parentSub ? parentSub.addNestedSub(handleChangeWrapper) : store.subscribe(handleChangeWrapper); listeners = createListenerCollection(); } } function tryUnsubscribe() { if (unsubscribe) { unsubscribe(); unsubscribe = undefined; listeners.clear(); listeners = nullListeners; } } var subscription = { addNestedSub: addNestedSub, notifyNestedSubs: notifyNestedSubs, handleChangeWrapper: handleChangeWrapper, isSubscribed: isSubscribed, trySubscribe: trySubscribe, tryUnsubscribe: tryUnsubscribe, getListeners: function getListeners() { return listeners; } }; return subscription; } ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/utils/useIsomorphicLayoutEffect.js // React currently throws a warning when using useLayoutEffect on the server. // To get around it, we can conditionally useEffect on the server (no-op) and // useLayoutEffect in the browser. We need useLayoutEffect to ensure the store // subscription callback always has the selector from the latest render commit // available, otherwise a store update may happen between render and the effect, // which may cause missed updates; we also must ensure the store subscription // is created synchronously, otherwise a store update may occur before the // subscription is created and an inconsistent state may be observed var useIsomorphicLayoutEffect_useIsomorphicLayoutEffect = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined' ? react.useLayoutEffect : react.useEffect; ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/components/Provider.js function Provider(_ref) { var store = _ref.store, context = _ref.context, children = _ref.children; var contextValue = (0,react.useMemo)(function () { var subscription = Subscription_createSubscription(store); return { store: store, subscription: subscription }; }, [store]); var previousState = (0,react.useMemo)(function () { return store.getState(); }, [store]); useIsomorphicLayoutEffect_useIsomorphicLayoutEffect(function () { var subscription = contextValue.subscription; subscription.onStateChange = subscription.notifyNestedSubs; subscription.trySubscribe(); if (previousState !== store.getState()) { subscription.notifyNestedSubs(); } return function () { subscription.tryUnsubscribe(); subscription.onStateChange = null; }; }, [contextValue, previousState]); var Context = context || Context_ReactReduxContext; return /*#__PURE__*/react.createElement(Context.Provider, { value: contextValue }, children); } if (false) {} /* harmony default export */ const components_Provider = (Provider); // EXTERNAL MODULE: ../../node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js var hoist_non_react_statics_cjs = __webpack_require__(3463); // EXTERNAL MODULE: ../../node_modules/react-redux/node_modules/react-is/index.js var react_is = __webpack_require__(3920); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/components/connectAdvanced.js var _excluded = (/* unused pure expression or super */ null && (["getDisplayName", "methodName", "renderCountProp", "shouldHandleStateChanges", "storeKey", "withRef", "forwardRef", "context"])), _excluded2 = (/* unused pure expression or super */ null && (["reactReduxForwardedRef"])); // Define some constant arrays just to avoid re-creating these var EMPTY_ARRAY = (/* unused pure expression or super */ null && ([])); var NO_SUBSCRIPTION_ARRAY = (/* unused pure expression or super */ null && ([null, null])); var stringifyComponent = function stringifyComponent(Comp) { try { return JSON.stringify(Comp); } catch (err) { return String(Comp); } }; function storeStateUpdatesReducer(state, action) { var updateCount = state[1]; return [action.payload, updateCount + 1]; } function useIsomorphicLayoutEffectWithArgs(effectFunc, effectArgs, dependencies) { useIsomorphicLayoutEffect(function () { return effectFunc.apply(void 0, effectArgs); }, dependencies); } function captureWrapperProps(lastWrapperProps, lastChildProps, renderIsScheduled, wrapperProps, actualChildProps, childPropsFromStoreUpdate, notifyNestedSubs) { // We want to capture the wrapper props and child props we used for later comparisons lastWrapperProps.current = wrapperProps; lastChildProps.current = actualChildProps; renderIsScheduled.current = false; // If the render was from a store update, clear out that reference and cascade the subscriber update if (childPropsFromStoreUpdate.current) { childPropsFromStoreUpdate.current = null; notifyNestedSubs(); } } function subscribeUpdates(shouldHandleStateChanges, store, subscription, childPropsSelector, lastWrapperProps, lastChildProps, renderIsScheduled, childPropsFromStoreUpdate, notifyNestedSubs, forceComponentUpdateDispatch) { // If we're not subscribed to the store, nothing to do here if (!shouldHandleStateChanges) return; // Capture values for checking if and when this component unmounts var didUnsubscribe = false; var lastThrownError = null; // We'll run this callback every time a store subscription update propagates to this component var checkForUpdates = function checkForUpdates() { if (didUnsubscribe) { // Don't run stale listeners. // Redux doesn't guarantee unsubscriptions happen until next dispatch. return; } var latestStoreState = store.getState(); var newChildProps, error; try { // Actually run the selector with the most recent store state and wrapper props // to determine what the child props should be newChildProps = childPropsSelector(latestStoreState, lastWrapperProps.current); } catch (e) { error = e; lastThrownError = e; } if (!error) { lastThrownError = null; } // If the child props haven't changed, nothing to do here - cascade the subscription update if (newChildProps === lastChildProps.current) { if (!renderIsScheduled.current) { notifyNestedSubs(); } } else { // Save references to the new child props. Note that we track the "child props from store update" // as a ref instead of a useState/useReducer because we need a way to determine if that value has // been processed. If this went into useState/useReducer, we couldn't clear out the value without // forcing another re-render, which we don't want. lastChildProps.current = newChildProps; childPropsFromStoreUpdate.current = newChildProps; renderIsScheduled.current = true; // If the child props _did_ change (or we caught an error), this wrapper component needs to re-render forceComponentUpdateDispatch({ type: 'STORE_UPDATED', payload: { error: error } }); } }; // Actually subscribe to the nearest connected ancestor (or store) subscription.onStateChange = checkForUpdates; subscription.trySubscribe(); // Pull data from the store after first render in case the store has // changed since we began. checkForUpdates(); var unsubscribeWrapper = function unsubscribeWrapper() { didUnsubscribe = true; subscription.tryUnsubscribe(); subscription.onStateChange = null; if (lastThrownError) { // It's possible that we caught an error due to a bad mapState function, but the // parent re-rendered without this component and we're about to unmount. // This shouldn't happen as long as we do top-down subscriptions correctly, but // if we ever do those wrong, this throw will surface the error in our tests. // In that case, throw the error from here so it doesn't get lost. throw lastThrownError; } }; return unsubscribeWrapper; } var initStateUpdates = function initStateUpdates() { return [null, 0]; }; function connectAdvanced_connectAdvanced( /* selectorFactory is a func that is responsible for returning the selector function used to compute new props from state, props, and dispatch. For example: export default connectAdvanced((dispatch, options) => (state, props) => ({ thing: state.things[props.thingId], saveThing: fields => dispatch(actionCreators.saveThing(props.thingId, fields)), }))(YourComponent) Access to dispatch is provided to the factory so selectorFactories can bind actionCreators outside of their selector as an optimization. Options passed to connectAdvanced are passed to the selectorFactory, along with displayName and WrappedComponent, as the second argument. Note that selectorFactory is responsible for all caching/memoization of inbound and outbound props. Do not use connectAdvanced directly without memoizing results between calls to your selector, otherwise the Connect component will re-render on every state or props change. */ selectorFactory, // options object: _ref) { if (_ref === void 0) { _ref = {}; } var _ref2 = _ref, _ref2$getDisplayName = _ref2.getDisplayName, getDisplayName = _ref2$getDisplayName === void 0 ? function (name) { return "ConnectAdvanced(" + name + ")"; } : _ref2$getDisplayName, _ref2$methodName = _ref2.methodName, methodName = _ref2$methodName === void 0 ? 'connectAdvanced' : _ref2$methodName, _ref2$renderCountProp = _ref2.renderCountProp, renderCountProp = _ref2$renderCountProp === void 0 ? undefined : _ref2$renderCountProp, _ref2$shouldHandleSta = _ref2.shouldHandleStateChanges, shouldHandleStateChanges = _ref2$shouldHandleSta === void 0 ? true : _ref2$shouldHandleSta, _ref2$storeKey = _ref2.storeKey, storeKey = _ref2$storeKey === void 0 ? 'store' : _ref2$storeKey, _ref2$withRef = _ref2.withRef, withRef = _ref2$withRef === void 0 ? false : _ref2$withRef, _ref2$forwardRef = _ref2.forwardRef, forwardRef = _ref2$forwardRef === void 0 ? false : _ref2$forwardRef, _ref2$context = _ref2.context, context = _ref2$context === void 0 ? ReactReduxContext : _ref2$context, connectOptions = _objectWithoutPropertiesLoose(_ref2, _excluded); if (false) { var customStoreWarningMessage; } var Context = context; return function wrapWithConnect(WrappedComponent) { if (false) {} var wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; var displayName = getDisplayName(wrappedComponentName); var selectorFactoryOptions = _extends({}, connectOptions, { getDisplayName: getDisplayName, methodName: methodName, renderCountProp: renderCountProp, shouldHandleStateChanges: shouldHandleStateChanges, storeKey: storeKey, displayName: displayName, wrappedComponentName: wrappedComponentName, WrappedComponent: WrappedComponent }); var pure = connectOptions.pure; function createChildSelector(store) { return selectorFactory(store.dispatch, selectorFactoryOptions); } // If we aren't running in "pure" mode, we don't want to memoize values. // To avoid conditionally calling hooks, we fall back to a tiny wrapper // that just executes the given callback immediately. var usePureOnlyMemo = pure ? useMemo : function (callback) { return callback(); }; function ConnectFunction(props) { var _useMemo = useMemo(function () { // Distinguish between actual "data" props that were passed to the wrapper component, // and values needed to control behavior (forwarded refs, alternate context instances). // To maintain the wrapperProps object reference, memoize this destructuring. var reactReduxForwardedRef = props.reactReduxForwardedRef, wrapperProps = _objectWithoutPropertiesLoose(props, _excluded2); return [props.context, reactReduxForwardedRef, wrapperProps]; }, [props]), propsContext = _useMemo[0], reactReduxForwardedRef = _useMemo[1], wrapperProps = _useMemo[2]; var ContextToUse = useMemo(function () { // Users may optionally pass in a custom context instance to use instead of our ReactReduxContext. // Memoize the check that determines which context instance we should use. return propsContext && propsContext.Consumer && isContextConsumer( /*#__PURE__*/React.createElement(propsContext.Consumer, null)) ? propsContext : Context; }, [propsContext, Context]); // Retrieve the store and ancestor subscription via context, if available var contextValue = useContext(ContextToUse); // The store _must_ exist as either a prop or in context. // We'll check to see if it _looks_ like a Redux store first. // This allows us to pass through a `store` prop that is just a plain value. var didStoreComeFromProps = Boolean(props.store) && Boolean(props.store.getState) && Boolean(props.store.dispatch); var didStoreComeFromContext = Boolean(contextValue) && Boolean(contextValue.store); if (false) {} // Based on the previous check, one of these must be true var store = didStoreComeFromProps ? props.store : contextValue.store; var childPropsSelector = useMemo(function () { // The child props selector needs the store reference as an input. // Re-create this selector whenever the store changes. return createChildSelector(store); }, [store]); var _useMemo2 = useMemo(function () { if (!shouldHandleStateChanges) return NO_SUBSCRIPTION_ARRAY; // This Subscription's source should match where store came from: props vs. context. A component // connected to the store via props shouldn't use subscription from context, or vice versa. // This Subscription's source should match where store came from: props vs. context. A component // connected to the store via props shouldn't use subscription from context, or vice versa. var subscription = createSubscription(store, didStoreComeFromProps ? null : contextValue.subscription); // `notifyNestedSubs` is duplicated to handle the case where the component is unmounted in // the middle of the notification loop, where `subscription` will then be null. This can // probably be avoided if Subscription's listeners logic is changed to not call listeners // that have been unsubscribed in the middle of the notification loop. // `notifyNestedSubs` is duplicated to handle the case where the component is unmounted in // the middle of the notification loop, where `subscription` will then be null. This can // probably be avoided if Subscription's listeners logic is changed to not call listeners // that have been unsubscribed in the middle of the notification loop. var notifyNestedSubs = subscription.notifyNestedSubs.bind(subscription); return [subscription, notifyNestedSubs]; }, [store, didStoreComeFromProps, contextValue]), subscription = _useMemo2[0], notifyNestedSubs = _useMemo2[1]; // Determine what {store, subscription} value should be put into nested context, if necessary, // and memoize that value to avoid unnecessary context updates. var overriddenContextValue = useMemo(function () { if (didStoreComeFromProps) { // This component is directly subscribed to a store from props. // We don't want descendants reading from this store - pass down whatever // the existing context value is from the nearest connected ancestor. return contextValue; } // Otherwise, put this component's subscription instance into context, so that // connected descendants won't update until after this component is done return _extends({}, contextValue, { subscription: subscription }); }, [didStoreComeFromProps, contextValue, subscription]); // We need to force this wrapper component to re-render whenever a Redux store update // causes a change to the calculated child component props (or we caught an error in mapState) var _useReducer = useReducer(storeStateUpdatesReducer, EMPTY_ARRAY, initStateUpdates), _useReducer$ = _useReducer[0], previousStateUpdateResult = _useReducer$[0], forceComponentUpdateDispatch = _useReducer[1]; // Propagate any mapState/mapDispatch errors upwards if (previousStateUpdateResult && previousStateUpdateResult.error) { throw previousStateUpdateResult.error; } // Set up refs to coordinate values between the subscription effect and the render logic var lastChildProps = useRef(); var lastWrapperProps = useRef(wrapperProps); var childPropsFromStoreUpdate = useRef(); var renderIsScheduled = useRef(false); var actualChildProps = usePureOnlyMemo(function () { // Tricky logic here: // - This render may have been triggered by a Redux store update that produced new child props // - However, we may have gotten new wrapper props after that // If we have new child props, and the same wrapper props, we know we should use the new child props as-is. // But, if we have new wrapper props, those might change the child props, so we have to recalculate things. // So, we'll use the child props from store update only if the wrapper props are the same as last time. if (childPropsFromStoreUpdate.current && wrapperProps === lastWrapperProps.current) { return childPropsFromStoreUpdate.current; } // TODO We're reading the store directly in render() here. Bad idea? // This will likely cause Bad Things (TM) to happen in Concurrent Mode. // Note that we do this because on renders _not_ caused by store updates, we need the latest store state // to determine what the child props should be. return childPropsSelector(store.getState(), wrapperProps); }, [store, previousStateUpdateResult, wrapperProps]); // We need this to execute synchronously every time we re-render. However, React warns // about useLayoutEffect in SSR, so we try to detect environment and fall back to // just useEffect instead to avoid the warning, since neither will run anyway. useIsomorphicLayoutEffectWithArgs(captureWrapperProps, [lastWrapperProps, lastChildProps, renderIsScheduled, wrapperProps, actualChildProps, childPropsFromStoreUpdate, notifyNestedSubs]); // Our re-subscribe logic only runs when the store/subscription setup changes useIsomorphicLayoutEffectWithArgs(subscribeUpdates, [shouldHandleStateChanges, store, subscription, childPropsSelector, lastWrapperProps, lastChildProps, renderIsScheduled, childPropsFromStoreUpdate, notifyNestedSubs, forceComponentUpdateDispatch], [store, subscription, childPropsSelector]); // Now that all that's done, we can finally try to actually render the child component. // We memoize the elements for the rendered child component as an optimization. var renderedWrappedComponent = useMemo(function () { return /*#__PURE__*/React.createElement(WrappedComponent, _extends({}, actualChildProps, { ref: reactReduxForwardedRef })); }, [reactReduxForwardedRef, WrappedComponent, actualChildProps]); // If React sees the exact same element reference as last time, it bails out of re-rendering // that child, same as if it was wrapped in React.memo() or returned false from shouldComponentUpdate. var renderedChild = useMemo(function () { if (shouldHandleStateChanges) { // If this component is subscribed to store updates, we need to pass its own // subscription instance down to our descendants. That means rendering the same // Context instance, and putting a different value into the context. return /*#__PURE__*/React.createElement(ContextToUse.Provider, { value: overriddenContextValue }, renderedWrappedComponent); } return renderedWrappedComponent; }, [ContextToUse, renderedWrappedComponent, overriddenContextValue]); return renderedChild; } // If we're in "pure" mode, ensure our wrapper component only re-renders when incoming props have changed. var Connect = pure ? React.memo(ConnectFunction) : ConnectFunction; Connect.WrappedComponent = WrappedComponent; Connect.displayName = ConnectFunction.displayName = displayName; if (forwardRef) { var forwarded = React.forwardRef(function forwardConnectRef(props, ref) { return /*#__PURE__*/React.createElement(Connect, _extends({}, props, { reactReduxForwardedRef: ref })); }); forwarded.displayName = displayName; forwarded.WrappedComponent = WrappedComponent; return hoistStatics(forwarded, WrappedComponent); } return hoistStatics(Connect, WrappedComponent); }; } ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/utils/bindActionCreators.js function bindActionCreators(actionCreators, dispatch) { var boundActionCreators = {}; var _loop = function _loop(key) { var actionCreator = actionCreators[key]; if (typeof actionCreator === 'function') { boundActionCreators[key] = function () { return dispatch(actionCreator.apply(void 0, arguments)); }; } }; for (var key in actionCreators) { _loop(key); } return boundActionCreators; } ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/connect/wrapMapToProps.js function wrapMapToPropsConstant(getConstant) { return function initConstantSelector(dispatch, options) { var constant = getConstant(dispatch, options); function constantSelector() { return constant; } constantSelector.dependsOnOwnProps = false; return constantSelector; }; } // dependsOnOwnProps is used by createMapToPropsProxy to determine whether to pass props as args // to the mapToProps function being wrapped. It is also used by makePurePropsSelector to determine // whether mapToProps needs to be invoked when props have changed. // // A length of one signals that mapToProps does not depend on props from the parent component. // A length of zero is assumed to mean mapToProps is getting args via arguments or ...args and // therefore not reporting its length accurately.. function getDependsOnOwnProps(mapToProps) { return mapToProps.dependsOnOwnProps !== null && mapToProps.dependsOnOwnProps !== undefined ? Boolean(mapToProps.dependsOnOwnProps) : mapToProps.length !== 1; } // Used by whenMapStateToPropsIsFunction and whenMapDispatchToPropsIsFunction, // this function wraps mapToProps in a proxy function which does several things: // // * Detects whether the mapToProps function being called depends on props, which // is used by selectorFactory to decide if it should reinvoke on props changes. // // * On first call, handles mapToProps if returns another function, and treats that // new function as the true mapToProps for subsequent calls. // // * On first call, verifies the first result is a plain object, in order to warn // the developer that their mapToProps function is not returning a valid result. // function wrapMapToPropsFunc(mapToProps, methodName) { return function initProxySelector(dispatch, _ref) { var displayName = _ref.displayName; var proxy = function mapToPropsProxy(stateOrDispatch, ownProps) { return proxy.dependsOnOwnProps ? proxy.mapToProps(stateOrDispatch, ownProps) : proxy.mapToProps(stateOrDispatch); }; // allow detectFactoryAndVerify to get ownProps proxy.dependsOnOwnProps = true; proxy.mapToProps = function detectFactoryAndVerify(stateOrDispatch, ownProps) { proxy.mapToProps = mapToProps; proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps); var props = proxy(stateOrDispatch, ownProps); if (typeof props === 'function') { proxy.mapToProps = props; proxy.dependsOnOwnProps = getDependsOnOwnProps(props); props = proxy(stateOrDispatch, ownProps); } if (false) {} return props; }; return proxy; }; } ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/connect/mapDispatchToProps.js function whenMapDispatchToPropsIsFunction(mapDispatchToProps) { return typeof mapDispatchToProps === 'function' ? wrapMapToPropsFunc(mapDispatchToProps, 'mapDispatchToProps') : undefined; } function whenMapDispatchToPropsIsMissing(mapDispatchToProps) { return !mapDispatchToProps ? wrapMapToPropsConstant(function (dispatch) { return { dispatch: dispatch }; }) : undefined; } function whenMapDispatchToPropsIsObject(mapDispatchToProps) { return mapDispatchToProps && typeof mapDispatchToProps === 'object' ? wrapMapToPropsConstant(function (dispatch) { return bindActionCreators(mapDispatchToProps, dispatch); }) : undefined; } /* harmony default export */ const mapDispatchToProps = ([whenMapDispatchToPropsIsFunction, whenMapDispatchToPropsIsMissing, whenMapDispatchToPropsIsObject]); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/connect/mapStateToProps.js function whenMapStateToPropsIsFunction(mapStateToProps) { return typeof mapStateToProps === 'function' ? wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps') : undefined; } function whenMapStateToPropsIsMissing(mapStateToProps) { return !mapStateToProps ? wrapMapToPropsConstant(function () { return {}; }) : undefined; } /* harmony default export */ const mapStateToProps = ([whenMapStateToPropsIsFunction, whenMapStateToPropsIsMissing]); ;// CONCATENATED MODULE: ../../node_modules/@babel/runtime/helpers/esm/extends.js function extends_extends() { extends_extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return extends_extends.apply(this, arguments); } ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/connect/mergeProps.js function defaultMergeProps(stateProps, dispatchProps, ownProps) { return extends_extends({}, ownProps, stateProps, dispatchProps); } function wrapMergePropsFunc(mergeProps) { return function initMergePropsProxy(dispatch, _ref) { var displayName = _ref.displayName, pure = _ref.pure, areMergedPropsEqual = _ref.areMergedPropsEqual; var hasRunOnce = false; var mergedProps; return function mergePropsProxy(stateProps, dispatchProps, ownProps) { var nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps); if (hasRunOnce) { if (!pure || !areMergedPropsEqual(nextMergedProps, mergedProps)) mergedProps = nextMergedProps; } else { hasRunOnce = true; mergedProps = nextMergedProps; if (false) {} } return mergedProps; }; }; } function whenMergePropsIsFunction(mergeProps) { return typeof mergeProps === 'function' ? wrapMergePropsFunc(mergeProps) : undefined; } function whenMergePropsIsOmitted(mergeProps) { return !mergeProps ? function () { return defaultMergeProps; } : undefined; } /* harmony default export */ const mergeProps = ([whenMergePropsIsFunction, whenMergePropsIsOmitted]); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/connect/connect.js var connect_excluded = (/* unused pure expression or super */ null && (["pure", "areStatesEqual", "areOwnPropsEqual", "areStatePropsEqual", "areMergedPropsEqual"])); /* connect is a facade over connectAdvanced. It turns its args into a compatible selectorFactory, which has the signature: (dispatch, options) => (nextState, nextOwnProps) => nextFinalProps connect passes its args to connectAdvanced as options, which will in turn pass them to selectorFactory each time a Connect component instance is instantiated or hot reloaded. selectorFactory returns a final props selector from its mapStateToProps, mapStateToPropsFactories, mapDispatchToProps, mapDispatchToPropsFactories, mergeProps, mergePropsFactories, and pure args. The resulting final props selector is called by the Connect component instance whenever it receives new props or store state. */ function match(arg, factories, name) { for (var i = factories.length - 1; i >= 0; i--) { var result = factories[i](arg); if (result) return result; } return function (dispatch, options) { throw new Error("Invalid value of type " + typeof arg + " for " + name + " argument when connecting component " + options.wrappedComponentName + "."); }; } function strictEqual(a, b) { return a === b; } // createConnect with default args builds the 'official' connect behavior. Calling it with // different options opens up some testing and extensibility scenarios function createConnect(_temp) { var _ref = _temp === void 0 ? {} : _temp, _ref$connectHOC = _ref.connectHOC, connectHOC = _ref$connectHOC === void 0 ? connectAdvanced : _ref$connectHOC, _ref$mapStateToPropsF = _ref.mapStateToPropsFactories, mapStateToPropsFactories = _ref$mapStateToPropsF === void 0 ? defaultMapStateToPropsFactories : _ref$mapStateToPropsF, _ref$mapDispatchToPro = _ref.mapDispatchToPropsFactories, mapDispatchToPropsFactories = _ref$mapDispatchToPro === void 0 ? defaultMapDispatchToPropsFactories : _ref$mapDispatchToPro, _ref$mergePropsFactor = _ref.mergePropsFactories, mergePropsFactories = _ref$mergePropsFactor === void 0 ? defaultMergePropsFactories : _ref$mergePropsFactor, _ref$selectorFactory = _ref.selectorFactory, selectorFactory = _ref$selectorFactory === void 0 ? defaultSelectorFactory : _ref$selectorFactory; return function connect(mapStateToProps, mapDispatchToProps, mergeProps, _ref2) { if (_ref2 === void 0) { _ref2 = {}; } var _ref3 = _ref2, _ref3$pure = _ref3.pure, pure = _ref3$pure === void 0 ? true : _ref3$pure, _ref3$areStatesEqual = _ref3.areStatesEqual, areStatesEqual = _ref3$areStatesEqual === void 0 ? strictEqual : _ref3$areStatesEqual, _ref3$areOwnPropsEqua = _ref3.areOwnPropsEqual, areOwnPropsEqual = _ref3$areOwnPropsEqua === void 0 ? shallowEqual : _ref3$areOwnPropsEqua, _ref3$areStatePropsEq = _ref3.areStatePropsEqual, areStatePropsEqual = _ref3$areStatePropsEq === void 0 ? shallowEqual : _ref3$areStatePropsEq, _ref3$areMergedPropsE = _ref3.areMergedPropsEqual, areMergedPropsEqual = _ref3$areMergedPropsE === void 0 ? shallowEqual : _ref3$areMergedPropsE, extraOptions = _objectWithoutPropertiesLoose(_ref3, connect_excluded); var initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps'); var initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps'); var initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps'); return connectHOC(selectorFactory, _extends({ // used in error messages methodName: 'connect', // used to compute Connect's displayName from the wrapped component's displayName. getDisplayName: function getDisplayName(name) { return "Connect(" + name + ")"; }, // if mapStateToProps is falsy, the Connect component doesn't subscribe to store state changes shouldHandleStateChanges: Boolean(mapStateToProps), // passed through to selectorFactory initMapStateToProps: initMapStateToProps, initMapDispatchToProps: initMapDispatchToProps, initMergeProps: initMergeProps, pure: pure, areStatesEqual: areStatesEqual, areOwnPropsEqual: areOwnPropsEqual, areStatePropsEqual: areStatePropsEqual, areMergedPropsEqual: areMergedPropsEqual }, extraOptions)); }; } /* harmony default export */ const connect = (/*#__PURE__*/(/* unused pure expression or super */ null && (createConnect()))); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/hooks/useReduxContext.js /** * A hook to access the value of the `ReactReduxContext`. This is a low-level * hook that you should usually not need to call directly. * * @returns {any} the value of the `ReactReduxContext` * * @example * * import React from 'react' * import { useReduxContext } from 'react-redux' * * export const CounterComponent = ({ value }) => { * const { store } = useReduxContext() * return
{store.getState()}
* } */ function useReduxContext_useReduxContext() { var contextValue = (0,react.useContext)(Context_ReactReduxContext); if (false) {} return contextValue; } ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/hooks/useStore.js /** * Hook factory, which creates a `useStore` hook bound to a given context. * * @param {React.Context} [context=ReactReduxContext] Context passed to your ``. * @returns {Function} A `useStore` hook bound to the specified context. */ function createStoreHook(context) { if (context === void 0) { context = Context_ReactReduxContext; } var useReduxContext = context === Context_ReactReduxContext ? useReduxContext_useReduxContext : function () { return (0,react.useContext)(context); }; return function useStore() { var _useReduxContext = useReduxContext(), store = _useReduxContext.store; return store; }; } /** * A hook to access the redux store. * * @returns {any} the redux store * * @example * * import React from 'react' * import { useStore } from 'react-redux' * * export const ExampleComponent = () => { * const store = useStore() * return
{store.getState()}
* } */ var useStore_useStore = /*#__PURE__*/createStoreHook(); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/hooks/useDispatch.js /** * Hook factory, which creates a `useDispatch` hook bound to a given context. * * @param {React.Context} [context=ReactReduxContext] Context passed to your ``. * @returns {Function} A `useDispatch` hook bound to the specified context. */ function createDispatchHook(context) { if (context === void 0) { context = Context_ReactReduxContext; } var useStore = context === Context_ReactReduxContext ? useStore_useStore : createStoreHook(context); return function useDispatch() { var store = useStore(); return store.dispatch; }; } /** * A hook to access the redux `dispatch` function. * * @returns {any|function} redux store's `dispatch` function * * @example * * import React, { useCallback } from 'react' * import { useDispatch } from 'react-redux' * * export const CounterComponent = ({ value }) => { * const dispatch = useDispatch() * const increaseCounter = useCallback(() => dispatch({ type: 'increase-counter' }), []) * return ( *
* {value} * *
* ) * } */ var useDispatch = /*#__PURE__*/createDispatchHook(); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/hooks/useSelector.js var refEquality = function refEquality(a, b) { return a === b; }; function useSelectorWithStoreAndSubscription(selector, equalityFn, store, contextSub) { var _useReducer = (0,react.useReducer)(function (s) { return s + 1; }, 0), forceRender = _useReducer[1]; var subscription = (0,react.useMemo)(function () { return Subscription_createSubscription(store, contextSub); }, [store, contextSub]); var latestSubscriptionCallbackError = (0,react.useRef)(); var latestSelector = (0,react.useRef)(); var latestStoreState = (0,react.useRef)(); var latestSelectedState = (0,react.useRef)(); var storeState = store.getState(); var selectedState; try { if (selector !== latestSelector.current || storeState !== latestStoreState.current || latestSubscriptionCallbackError.current) { var newSelectedState = selector(storeState); // ensure latest selected state is reused so that a custom equality function can result in identical references if (latestSelectedState.current === undefined || !equalityFn(newSelectedState, latestSelectedState.current)) { selectedState = newSelectedState; } else { selectedState = latestSelectedState.current; } } else { selectedState = latestSelectedState.current; } } catch (err) { if (latestSubscriptionCallbackError.current) { err.message += "\nThe error may be correlated with this previous error:\n" + latestSubscriptionCallbackError.current.stack + "\n\n"; } throw err; } useIsomorphicLayoutEffect_useIsomorphicLayoutEffect(function () { latestSelector.current = selector; latestStoreState.current = storeState; latestSelectedState.current = selectedState; latestSubscriptionCallbackError.current = undefined; }); useIsomorphicLayoutEffect_useIsomorphicLayoutEffect(function () { function checkForUpdates() { try { var newStoreState = store.getState(); // Avoid calling selector multiple times if the store's state has not changed if (newStoreState === latestStoreState.current) { return; } var _newSelectedState = latestSelector.current(newStoreState); if (equalityFn(_newSelectedState, latestSelectedState.current)) { return; } latestSelectedState.current = _newSelectedState; latestStoreState.current = newStoreState; } catch (err) { // we ignore all errors here, since when the component // is re-rendered, the selectors are called again, and // will throw again, if neither props nor store state // changed latestSubscriptionCallbackError.current = err; } forceRender(); } subscription.onStateChange = checkForUpdates; subscription.trySubscribe(); checkForUpdates(); return function () { return subscription.tryUnsubscribe(); }; }, [store, subscription]); return selectedState; } /** * Hook factory, which creates a `useSelector` hook bound to a given context. * * @param {React.Context} [context=ReactReduxContext] Context passed to your ``. * @returns {Function} A `useSelector` hook bound to the specified context. */ function createSelectorHook(context) { if (context === void 0) { context = Context_ReactReduxContext; } var useReduxContext = context === Context_ReactReduxContext ? useReduxContext_useReduxContext : function () { return (0,react.useContext)(context); }; return function useSelector(selector, equalityFn) { if (equalityFn === void 0) { equalityFn = refEquality; } if (false) {} var _useReduxContext = useReduxContext(), store = _useReduxContext.store, contextSub = _useReduxContext.subscription; var selectedState = useSelectorWithStoreAndSubscription(selector, equalityFn, store, contextSub); (0,react.useDebugValue)(selectedState); return selectedState; }; } /** * A hook to access the redux store's state. This hook takes a selector function * as an argument. The selector is called with the store state. * * This hook takes an optional equality comparison function as the second parameter * that allows you to customize the way the selected state is compared to determine * whether the component needs to be re-rendered. * * @param {Function} selector the selector function * @param {Function=} equalityFn the function that will be used to determine equality * * @returns {any} the selected state * * @example * * import React from 'react' * import { useSelector } from 'react-redux' * * export const CounterComponent = () => { * const counter = useSelector(state => state.counter) * return
{counter}
* } */ var useSelector = /*#__PURE__*/createSelectorHook(); ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/exports.js ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/utils/reactBatchedUpdates.js /* eslint-disable import/no-unresolved */ ;// CONCATENATED MODULE: ../../node_modules/react-redux/es/index.js // Enable batched updates in our subscriptions for use // with standard React renderers (ReactDOM, React Native) setBatch(react_dom.unstable_batchedUpdates); // EXTERNAL MODULE: ../../node_modules/redux/es/redux.js + 1 modules var redux = __webpack_require__(4081); ;// CONCATENATED MODULE: ../../node_modules/redux-thunk/es/index.js /** A function that accepts a potential "extra argument" value to be injected later, * and returns an instance of the thunk middleware that uses that value */ function createThunkMiddleware(extraArgument) { // Standard Redux middleware definition pattern: // See: https://redux.js.org/tutorials/fundamentals/part-4-store#writing-custom-middleware var middleware = function middleware(_ref) { var dispatch = _ref.dispatch, getState = _ref.getState; return function (next) { return function (action) { // The thunk middleware looks for any functions that were passed to `store.dispatch`. // If this "action" is really a function, call it and return the result. if (typeof action === 'function') { // Inject the store's `dispatch` and `getState` methods, as well as any "extra arg" return action(dispatch, getState, extraArgument); } // Otherwise, pass the action down the middleware chain as usual return next(action); }; }; }; return middleware; } var thunk = createThunkMiddleware(); // Attach the factory function so users can create a customized version // with whatever "extra arg" they want to inject into their thunks thunk.withExtraArgument = createThunkMiddleware; /* harmony default export */ const es = (thunk); // EXTERNAL MODULE: ../../node_modules/redux-devtools-extension/index.js var redux_devtools_extension = __webpack_require__(8267); ;// CONCATENATED MODULE: ./js/actionTypes.ts const ADD_TRACK_FROM_URL = "ADD_TRACK_FROM_URL"; const CLOSE_WINAMP = "CLOSE_WINAMP"; const OPEN_WINAMP = "OPEN_WINAMP"; const MINIMIZE_WINAMP = "MINIMIZE_WINAMP"; const IS_PLAYING = "IS_PLAYING"; const IS_STOPPED = "IS_STOPPED"; const PAUSE = "PAUSE"; const PLAY = "PLAY"; const SEEK_TO_PERCENT_COMPLETE = "SEEK_TO_PERCENT_COMPLETE"; const SET_BALANCE = "SET_BALANCE"; const SET_BAND_VALUE = "SET_BAND_VALUE"; const SET_FOCUS = "SET_FOCUS"; const SET_BAND_FOCUS = "SET_BAND_FOCUS"; const SET_FOCUSED_WINDOW = "SET_FOCUSED_WINDOW"; const SET_MEDIA = "SET_MEDIA"; const SET_SCRUB_POSITION = "SET_SCRUB_POSITION"; const SET_SKIN_DATA = "SET_SKIN_DATA"; const SET_VOLUME = "SET_VOLUME"; const START_WORKING = "START_WORKING"; const STEP_MARQUEE = "STEP_MARQUEE"; const STOP = "STOP"; const STOP_WORKING = "STOP_WORKING"; const TOGGLE_DOUBLESIZE_MODE = "TOGGLE_DOUBLESIZE_MODE"; const SET_EQ_AUTO = "SET_EQ_AUTO"; const SET_EQ_ON = "SET_EQ_ON"; const SET_EQ_OFF = "SET_EQ_OFF"; const actionTypes_TOGGLE_LLAMA_MODE = "TOGGLE_LLAMA_MODE"; const TOGGLE_REPEAT = "TOGGLE_REPEAT"; const TOGGLE_SHUFFLE = "TOGGLE_SHUFFLE"; const TOGGLE_TIME_MODE = "TOGGLE_TIME_MODE"; const TOGGLE_VISUALIZER_STYLE = "TOGGLE_VISUALIZER_STYLE"; const UNSET_FOCUS = "UNSET_FOCUS"; const UPDATE_TIME_ELAPSED = "UPDATE_TIME_ELAPSED"; const SET_USER_MESSAGE = "SET_USER_MESSAGE"; const UNSET_USER_MESSAGE = "UNSET_USER_MESSAGE"; const SET_PLAYLIST_SCROLL_POSITION = "SET_PLAYLIST_SCROLL_POSITION"; const CLICKED_TRACK = "CLICKED_TRACK"; const CTRL_CLICKED_TRACK = "CTRL_CLICKED_TRACK"; const SHIFT_CLICKED_TRACK = "SHIFT_CLICKED_TRACK"; const SELECT_ALL = "SELECT_ALL"; const SELECT_ZERO = "SELECT_ZERO"; const INVERT_SELECTION = "INVERT_SELECTION"; const REMOVE_ALL_TRACKS = "REMOVE_ALL_TRACKS"; const CROP_TRACKS = "CROP_TRACKS"; const FILE_INFO = "FILE_INFO"; const REMOVE_TRACKS = "REMOVE_TRACKS"; const SET_AVAILABLE_SKINS = "SET_AVAILABLE_SKINS"; const REVERSE_LIST = "REVERSE_LIST"; const RANDOMIZE_LIST = "RANDOMIZE_LIST"; const SET_TRACK_ORDER = "SET_TRACK_ORDER"; const PLAY_TRACK = "PLAY_TRACK"; const BUFFER_TRACK = "BUFFER_TRACK"; const DRAG_SELECTED = "DRAG_SELECTED"; const SET_MEDIA_TAGS = "SET_MEDIA_TAGS"; const SET_MEDIA_DURATION = "SET_MEDIA_DURATION"; const TOGGLE_WINDOW = "TOGGLE_WINDOW"; const CLOSE_WINDOW = "CLOSE_WINDOW"; const MEDIA_TAG_REQUEST_INITIALIZED = "MEDIA_TAG_REQUEST_INITIALIZED"; const MEDIA_TAG_REQUEST_FAILED = "MEDIA_TAG_REQUEST_FAILED"; const NETWORK_CONNECTED = "NETWORK_CONNECTED"; const NETWORK_DISCONNECTED = "NETWORK_DISCONNECTED"; const UPDATE_WINDOW_POSITIONS = "UPDATE_WINDOW_POSITIONS"; const WINDOW_SIZE_CHANGED = "WINDOW_SIZE_CHANGED"; const TOGGLE_WINDOW_SHADE_MODE = "TOGGLE_WINDOW_SHADE_MODE"; const LOADED = "LOADED"; const SET_Z_INDEX = "SET_Z_INDEX"; const DISABLE_MARQUEE = "DISABLE_MARQUEE"; const SET_DUMMY_VIZ_DATA = "SET_DUMMY_VIZ_DATA"; const SET_WINDOW_VISIBILITY = "SET_WINDOW_VISIBILITY"; const LOADING = "LOADING"; const CLOSE_REQUESTED = "CLOSE_REQUESTED"; const LOAD_SERIALIZED_STATE = "LOAD_SERIALIZED_STATE"; const RESET_WINDOW_SIZES = "RESET_WINDOW_SIZES"; const BROWSER_WINDOW_SIZE_CHANGED = "BROWSER_WINDOW_SIZE_CHANGED"; const LOAD_DEFAULT_SKIN = "LOAD_DEFAULT_SKIN"; const ENABLE_MILKDROP = "ENABLE_MILKDROP"; const SET_MILKDROP_DESKTOP = "SET_MILKDROP_DESKTOP"; const SET_VISUALIZER_STYLE = "SET_VISUALIZER_STYLE"; const GOT_BUTTERCHURN_PRESETS = "GOT_BUTTERCHURN_PRESETS"; const GOT_BUTTERCHURN = "GOT_BUTTERCHURN"; const RESOLVE_PRESET_AT_INDEX = "RESOLVE_PRESET_AT_INDEX"; const SELECT_PRESET_AT_INDEX = "SELECT_PRESET_AT_INDEX"; const TOGGLE_PRESET_OVERLAY = "TOGGLE_PRESET_OVERLAY"; const PRESET_REQUESTED = "PRESET_REQUESTED"; const TOGGLE_RANDOMIZE_PRESETS = "TOGGLE_RANDOMIZE_PRESETS"; const TOGGLE_PRESET_CYCLING = "TOGGLE_PRESET_CYCLING"; const SCHEDULE_MILKDROP_MESSAGE = "SCHEDULE_MILKDROP_MESSAGE"; const SET_MILKDROP_FULLSCREEN = "SET_MILKDROP_FULLSCREEN"; const SET_MILKDROP_LOCK = "SET_MILKDROP_LOCK"; ;// CONCATENATED MODULE: ./js/baseSkin.json const baseSkin_namespaceObject = JSON.parse('{"images":{"EQ_PREAMP_LINE":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAAABCAYAAADpXEERAAAAE0lEQVQoU2Pcdfruf4ZRMKRDAAD1lwNjTqcaUQAAAABJRU5ErkJggg==","EQ_GRAPH_LINE_COLORS":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAATCAYAAABRC2cZAAAAR0lEQVQYV2O4rCT9n+F9kOJ/hvfViv8ZHkzSQCE2afxneH/HEJm49Nr0PwOYWPLIAkp0PjL4z1B41uQ/Q9QGnf8MWrPEIAQANWYwvnlToNIAAAAASUVORK5CYII="},"colors":["rgb(0,0,0)","rgb(24,33,41)","rgb(239,49,16)","rgb(206,41,16)","rgb(214,90,0)","rgb(214,102,0)","rgb(214,115,0)","rgb(198,123,8)","rgb(222,165,24)","rgb(214,181,33)","rgb(189,222,41)","rgb(148,222,33)","rgb(41,206,16)","rgb(50,190,16)","rgb(57,181,16)","rgb(49,156,8)","rgb(41,148,0)","rgb(24,132,8)","rgb(255,255,255)","rgb(214,214,222)","rgb(181,189,189)","rgb(160,170,175)","rgb(148,156,165)","rgb(150,150,150)"],"playlistStyle":{"normal":"#00FF00","current":"#FFFFFF","normalbg":"#000000","selectedbg":"#0000FF","font":"Arial"}}'); ;// CONCATENATED MODULE: ./js/constants.ts const BANDS = [60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000]; const WINDOWS = { MAIN: "main", PLAYLIST: "playlist", EQUALIZER: "equalizer", MILKDROP: "milkdrop" }; const LOAD_STYLE = { BUFFER: "BUFFER", PLAY: "PLAY", NONE: "NONE" }; // TODO: Make this an enum? const MEDIA_TAG_REQUEST_STATUS = { INITIALIZED: "INITIALIZED", FAILED: "FAILED", COMPLETE: "COMPLETE", NOT_REQUESTED: "NOT_REQUESTED" }; const UTF8_ELLIPSIS = "\u2026"; const CHARACTER_WIDTH = 5; const WINDOW_RESIZE_SEGMENT_WIDTH = 25; const WINDOW_RESIZE_SEGMENT_HEIGHT = 29; const WINDOW_HEIGHT = 116; const WINDOW_WIDTH = 275; const TRACK_HEIGHT = 13; const LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split(""); const DEFAULT_SKIN = baseSkin_namespaceObject; const VISUALIZERS = { OSCILLOSCOPE: "OSCILLOSCOPE", BAR: "BAR", NONE: "NONE", MILKDROP: "MILKDROP" }; const VISUALIZER_ORDER = [VISUALIZERS.BAR, VISUALIZERS.OSCILLOSCOPE, // TODO: Verify the order VISUALIZERS.NONE]; const TIME_MODE = { ELAPSED: "ELAPSED", REMAINING: "REMAINING" }; // TODO: Convert to enum once we are fully Typescript const MEDIA_STATUS = { PLAYING: "PLAYING", STOPPED: "STOPPED", PAUSED: "PAUSED" }; ;// CONCATENATED MODULE: ./js/utils.ts function imgFromUrl(url) { return new Promise((resolve, reject) => { const img = new Image(); img.onload = () => { resolve(img); }; img.onerror = reject; img.src = url; }); } const getTimeObj = time => { if (time == null) { // If we clean up `` we don't need to do this any more. return { minutesFirstDigit: " ", minutesSecondDigit: " ", secondsFirstDigit: " ", secondsSecondDigit: " " }; } const minutes = Math.floor(time / 60); const seconds = time % 60; const digits = time == null ? [" ", " ", " ", " "] : [String(Math.floor(minutes / 10)), String(Math.floor(minutes % 10)), String(Math.floor(seconds / 10)), String(Math.floor(seconds % 10))]; const [minutesFirstDigit, minutesSecondDigit, secondsFirstDigit, secondsSecondDigit] = digits; return { minutesFirstDigit, minutesSecondDigit, secondsFirstDigit, secondsSecondDigit }; }; const getTimeStr = (time, truncate = true) => { if (time == null) { return ""; } const { minutesFirstDigit, minutesSecondDigit, secondsFirstDigit, secondsSecondDigit } = getTimeObj(time); return [truncate && minutesFirstDigit === "0" ? "" : minutesFirstDigit, minutesSecondDigit, ":", secondsFirstDigit, secondsSecondDigit].join(""); }; const parseViscolors = text => { const entries = text.split("\n"); const regex = /^\s*(\d+)\s*,?\s*(\d+)\s*,?\s*(\d+)/; const colors = [...DEFAULT_SKIN.colors]; entries.map(line => regex.exec(line)).filter(Boolean).map(matches => matches.slice(1, 4).join(",")).map((rgb, i) => { colors[i] = `rgb(${rgb})`; }); return colors; }; const SECTION_REGEX = /^\s*\[(.+?)\]\s*$/; const PROPERTY_REGEX = /^\s*([^;][^=]*)\s*=\s*(.*)\s*$/; const parseIni = text => { let section, match; return text.split(/[\r\n]+/g).reduce((data, line) => { if ((match = line.match(PROPERTY_REGEX)) && section != null) { const key = match[1].trim().toLowerCase(); const value = match[2] // Ignore anything after a second `=` // TODO: What if this is inside quotes or escaped? .replace(/\=.*$/g, "").trim() // Strip quotes // TODO: What about escaped quotes? // TODO: What about unbalanced quotes? .replace(/(^")|("$)|(^')|('$)/g, ""); data[section][key] = value; } else if (match = line.match(SECTION_REGEX)) { section = match[1].trim().toLowerCase(); data[section] = {}; } return data; }, {}); }; const clamp = (value, min, max) => Math.min(Math.max(value, min), max); const sum = values => values.reduce((total, value) => total + value, 0); const base64FromDataArray = dataArray => { return window.btoa(String.fromCharCode(...dataArray)); }; const base64FromArrayBuffer = arrayBuffer => { return base64FromDataArray(new Uint8Array(arrayBuffer)); }; // https://stackoverflow.com/a/15832662/1263117 function downloadURI(uri, name) { const link = document.createElement("a"); link.download = name; link.href = uri; window.document.body.appendChild(link); link.click(); window.document.body.removeChild(link); } const toPercent = (min, max, value) => (value - min) / (max - min); const percentToRange = (percent, min, max) => min + Math.round(percent * (max - min)); const percentToIndex = (percent, length) => percentToRange(percent, 0, length - 1); const rebound = (oldMin, oldMax, newMin, newMax) => oldValue => percentToRange(toPercent(oldMin, oldMax, oldValue), newMin, newMax); const normalizeEqBand = rebound(1, 64, 0, 2400); const denormalizeEqBand = rebound(0, 2400, 1, 64); const normalizedToDb = value => { return value / 2400 * 24 - 12; }; const dbToNormalized = db => { return Math.round((db + 12) / 24 * 2400); }; // Merge a `source` object to a `target` recursively // TODO: The typing here is a bit of a disaster. function merge(target, source) { const s = source; const t = target; // Iterate through `source` properties and if an `Object` set property to merge of `target` and `source` properties for (const key of Object.keys(s)) { if (s[key] instanceof Object) Object.assign(s[key], merge(t[key], s[key])); } // Join `target` and modified `source` Object.assign(target || {}, source); return target; } // Maps a value in a range (defined my min/max) to a value in an array (options). function segment(min, max, value, newValues) { const ratio = toPercent(min, max, value); /* | 0 | 1 | 2 | 0 1 2 3 */ return newValues[percentToIndex(ratio, newValues.length)]; } // https://bost.ocks.org/mike/shuffle/ // Shuffle an array in O(n) function shuffle(array) { const sorted = [...array]; let m = sorted.length; // While there remain elements to shuffle… while (m) { // Pick a remaining element… const i = Math.floor(Math.random() * m--); // And swap it with the current element. const val = sorted[m]; sorted[m] = sorted[i]; sorted[i] = val; } return sorted; } function sort(array, iteratee) { return [...array].sort((a, b) => { const aKey = iteratee(a); const bKey = iteratee(b); if (aKey < bKey) { return -1; } else if (aKey > bKey) { return 1; } return 0; }); } function moveSelected(arr, isSelected, offset) { const newArr = new Array(arr.length); let next = 0; for (let i = 0; i < newArr.length; i++) { const from = i - offset; // Is a value supposed to move here? if (from >= 0 && from < arr.length && isSelected(from)) { newArr[i] = arr[from]; } else { while (next < arr.length && isSelected(next)) { next++; } newArr[i] = arr[next]; next++; } } return newArr; } function spliceIn(original, start, newValues) { const newArr = [...original]; newArr.splice(start, 0, ...newValues); return newArr; } function replaceAtIndex(arr, index, newValue) { return [...arr.slice(0, index), newValue, ...arr.slice(index + 1)]; } function debounce(func, delay) { let timeout; let callbackArgs = []; return function (context, ...args) { callbackArgs = args; if (timeout != null) { clearTimeout(timeout); } timeout = window.setTimeout(() => { func.apply(context, callbackArgs); }, delay); }; } // Trailing edge only throttle function throttle(func, delay) { let timeout = null; let callbackArgs = []; return function (context, ...args) { callbackArgs = args; if (!timeout) { timeout = window.setTimeout(() => { func.apply(context, callbackArgs); timeout = null; }, delay); } }; } let counter = 0; function uniqueId() { return counter++; } function objectForEach(obj, cb) { Object.keys(obj).forEach(key => cb(obj[key], key)); } function objectMap(obj, cb) { const modified = {}; Object.keys(obj).forEach(key => modified[key] = cb(obj[key], key)); return modified; } function objectFilter(obj, predicate) { // TODO: Could return the original reference if no values change return Object.keys(obj).reduce((newObj, key) => { if (predicate(obj[key], key)) { newObj[key] = obj[key]; } return newObj; }, {}); } const calculateBoundingBox = windows => { if (windows.length === 0) { return null; } const windowSizes = windows.map(w => ({ left: w.x, top: w.y, bottom: w.y + w.height, right: w.x + w.width })); return windowSizes.reduce((b, w) => ({ left: Math.min(b.left, w.left), top: Math.min(b.top, w.top), bottom: Math.max(b.bottom, w.bottom), right: Math.max(b.right, w.right) })); }; function findLastIndex(arr, cb) { for (let i = arr.length - 1; i >= 0; i--) { if (cb(arr[i])) { return i; } } return -1; } function getWindowSize() { // Aparently this is crazy across browsers. return { width: Math.max(document.body.scrollWidth, document.documentElement.scrollWidth, document.body.offsetWidth, document.documentElement.offsetWidth, document.body.clientWidth, document.documentElement.clientWidth), height: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight) }; } function getScreenSize() { return { width: window.screen.width, height: window.screen.height }; } function weakMapMemoize(func) { const cache = new WeakMap(); return value => { if (!cache.has(value)) { cache.set(value, func(value)); } return cache.get(value); }; } ;// CONCATENATED MODULE: ./js/reducers/playlist.ts function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const defaultPlaylistState = { trackOrder: [], currentTrack: null, lastSelectedIndex: null, selectedTracks: new Set() }; function toggleSetMembership(set, value) { if (set.has(value)) { set.delete(value); } else { set.add(value); } } const playlist = (state = defaultPlaylistState, action) => { switch (action.type) { case CLICKED_TRACK: return _objectSpread(_objectSpread({}, state), {}, { selectedTracks: new Set([state.trackOrder[action.index]]), lastSelectedIndex: action.index }); case CTRL_CLICKED_TRACK: { const id = state.trackOrder[action.index]; const newSelectedTracks = new Set(state.selectedTracks); toggleSetMembership(newSelectedTracks, id); return _objectSpread(_objectSpread({}, state), {}, { selectedTracks: newSelectedTracks, // Using this as the lastClickedIndex is kinda funny, since you // may have just _un_selected the track. However, this is what // Winamp 2 does, so we'll copy it. lastSelectedIndex: action.index }); } case SHIFT_CLICKED_TRACK: if (state.lastSelectedIndex == null) { return state; } const clickedIndex = action.index; const start = Math.min(clickedIndex, state.lastSelectedIndex); const end = Math.max(clickedIndex, state.lastSelectedIndex); const selectedTracks = new Set(state.trackOrder.slice(start, end + 1)); return _objectSpread(_objectSpread({}, state), {}, { selectedTracks }); case SELECT_ALL: return _objectSpread(_objectSpread({}, state), {}, { selectedTracks: new Set(state.trackOrder) }); case SELECT_ZERO: return _objectSpread(_objectSpread({}, state), {}, { selectedTracks: new Set() }); case INVERT_SELECTION: return _objectSpread(_objectSpread({}, state), {}, { selectedTracks: new Set(state.trackOrder.filter(id => !state.selectedTracks.has(id))) }); case REMOVE_ALL_TRACKS: // TODO: Consider disposing of ObjectUrls return _objectSpread(_objectSpread({}, state), {}, { trackOrder: [], currentTrack: null, selectedTracks: new Set(), lastSelectedIndex: null }); case REMOVE_TRACKS: // TODO: Consider disposing of ObjectUrls const actionIds = new Set(action.ids.map(Number)); const { currentTrack } = state; return _objectSpread(_objectSpread({}, state), {}, { trackOrder: state.trackOrder.filter(trackId => !actionIds.has(trackId)), currentTrack: actionIds.has(Number(currentTrack)) ? null : currentTrack, selectedTracks: new Set(Array.from(state.selectedTracks).filter(id => actionIds.has(id))), // TODO: This could probably be made to work, but we clear it just to be safe. lastSelectedIndex: null }); case REVERSE_LIST: return _objectSpread(_objectSpread({}, state), {}, { trackOrder: [...state.trackOrder].reverse(), // TODO: This could probably be made to work, but we clear it just to be safe. lastSelectedIndex: null }); case RANDOMIZE_LIST: return _objectSpread(_objectSpread({}, state), {}, { trackOrder: shuffle(state.trackOrder) }); case SET_TRACK_ORDER: const { trackOrder } = action; return _objectSpread(_objectSpread({}, state), {}, { trackOrder }); case ADD_TRACK_FROM_URL: const atIndex = action.atIndex == null ? state.trackOrder.length : action.atIndex; return _objectSpread(_objectSpread({}, state), {}, { trackOrder: [...state.trackOrder.slice(0, atIndex), Number(action.id), ...state.trackOrder.slice(atIndex)], // TODO: This could probably be made to work, but we clear it just to be safe. lastSelectedIndex: null }); case PLAY_TRACK: case BUFFER_TRACK: return _objectSpread(_objectSpread({}, state), {}, { currentTrack: action.id }); case DRAG_SELECTED: return _objectSpread(_objectSpread({}, state), {}, { trackOrder: moveSelected(state.trackOrder, i => state.selectedTracks.has(state.trackOrder[i]), action.offset), // TODO: This could probably be made to work, but we clear it just to be safe. lastSelectedIndex: null }); default: return state; } }; /* harmony default export */ const reducers_playlist = (playlist); ;// CONCATENATED MODULE: ../../node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js function objectWithoutPropertiesLoose_objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } ;// CONCATENATED MODULE: ../../node_modules/@babel/runtime/helpers/esm/objectWithoutProperties.js function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = objectWithoutPropertiesLoose_objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } ;// CONCATENATED MODULE: ./js/reducers/windows.ts const windows_excluded = ["hidden"]; function windows_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function windows_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? windows_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : windows_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const defaultWindowsState = { focused: WINDOWS.MAIN, positionsAreRelative: true, genWindows: { // TODO: Remove static capabilities and derive them from ids/generic [WINDOWS.MAIN]: { title: "Main Window", size: [0, 0], open: true, shade: false, canResize: false, canShade: true, canDouble: true, hotkey: "Alt+W", position: { x: 0, y: 0 } }, [WINDOWS.EQUALIZER]: { title: "Equalizer", size: [0, 0], open: true, shade: false, canResize: false, canShade: true, canDouble: true, hotkey: "Alt+G", position: { x: 0, y: 0 } }, [WINDOWS.PLAYLIST]: { title: "Playlist Editor", size: [0, 0], open: true, shade: false, canResize: true, canShade: true, canDouble: false, hotkey: "Alt+E", position: { x: 0, y: 0 } }, [WINDOWS.MILKDROP]: { title: "Milkdrop", size: [0, 0], open: true, shade: false, canResize: true, canShade: false, canDouble: false, position: { x: 0, y: 0 } } }, browserWindowSize: { width: 0, height: 0 }, windowOrder: [WINDOWS.PLAYLIST, WINDOWS.EQUALIZER, WINDOWS.MILKDROP, WINDOWS.MAIN] }; const windows = (state = defaultWindowsState, action) => { switch (action.type) { case ENABLE_MILKDROP: return windows_objectSpread(windows_objectSpread({}, state), {}, { genWindows: windows_objectSpread(windows_objectSpread({}, state.genWindows), {}, { [WINDOWS.MILKDROP]: windows_objectSpread(windows_objectSpread({}, state.genWindows[WINDOWS.MILKDROP]), {}, { open: action.open }) }) }); case SET_FOCUSED_WINDOW: let windowOrder = state.windowOrder; if (action.window != null) { windowOrder = [...state.windowOrder.filter(windowId => windowId !== action.window), action.window]; } return windows_objectSpread(windows_objectSpread({}, state), {}, { focused: action.window, windowOrder }); case TOGGLE_WINDOW_SHADE_MODE: const { canShade } = state.genWindows[action.windowId]; if (!canShade) { throw new Error(`Tried to shade/unshade a window that cannot be shaded: ${action.windowId}`); } return windows_objectSpread(windows_objectSpread({}, state), {}, { genWindows: windows_objectSpread(windows_objectSpread({}, state.genWindows), {}, { [action.windowId]: windows_objectSpread(windows_objectSpread({}, state.genWindows[action.windowId]), {}, { shade: !state.genWindows[action.windowId].shade }) }) }); case TOGGLE_WINDOW: const windowState = state.genWindows[action.windowId]; return windows_objectSpread(windows_objectSpread({}, state), {}, { genWindows: windows_objectSpread(windows_objectSpread({}, state.genWindows), {}, { [action.windowId]: windows_objectSpread(windows_objectSpread({}, windowState), {}, { open: !windowState.open }) }) }); case CLOSE_WINDOW: return windows_objectSpread(windows_objectSpread({}, state), {}, { genWindows: windows_objectSpread(windows_objectSpread({}, state.genWindows), {}, { [action.windowId]: windows_objectSpread(windows_objectSpread({}, state.genWindows[action.windowId]), {}, { open: false }) }) }); case WINDOW_SIZE_CHANGED: const { canResize } = state.genWindows[action.windowId]; if (!canResize) { throw new Error(`Tried to resize a window that cannot be resized: ${action.windowId}`); } return windows_objectSpread(windows_objectSpread({}, state), {}, { genWindows: windows_objectSpread(windows_objectSpread({}, state.genWindows), {}, { [action.windowId]: windows_objectSpread(windows_objectSpread({}, state.genWindows[action.windowId]), {}, { size: action.size }) }) }); case UPDATE_WINDOW_POSITIONS: return windows_objectSpread(windows_objectSpread({}, state), {}, { positionsAreRelative: action.absolute === true ? false : state.positionsAreRelative, genWindows: objectMap(state.genWindows, (w, windowId) => { const newPosition = action.positions[windowId]; if (newPosition == null) { return w; } return windows_objectSpread(windows_objectSpread({}, w), {}, { position: newPosition }); }) }); case RESET_WINDOW_SIZES: return windows_objectSpread(windows_objectSpread({}, state), {}, { genWindows: objectMap(state.genWindows, w => windows_objectSpread(windows_objectSpread({}, w), {}, { // Not sure why TypeScript can't figure this out for itself. size: [0, 0] })) }); case LOAD_SERIALIZED_STATE: { const { genWindows, focused, positionsAreRelative } = action.serializedState.windows; return windows_objectSpread(windows_objectSpread({}, state), {}, { positionsAreRelative, genWindows: objectMap(state.genWindows, (w, windowId) => { const serializedW = genWindows[windowId]; if (serializedW == null) { return w; } // Pull out `hidden` since it's been removed from our state. const { hidden } = serializedW, rest = _objectWithoutProperties(serializedW, windows_excluded); return windows_objectSpread(windows_objectSpread({}, w), rest); }), focused }); } case BROWSER_WINDOW_SIZE_CHANGED: return windows_objectSpread(windows_objectSpread({}, state), {}, { browserWindowSize: { height: action.height, width: action.width } }); default: return state; } }; function getSerializedState(state) { return { positionsAreRelative: state.positionsAreRelative, genWindows: objectMap(state.genWindows, w => { return { size: w.size, open: w.open, hidden: false, // Not used any more shade: w.shade || false, position: w.position }; }), focused: state.focused }; } /* harmony default export */ const reducers_windows = (windows); ;// CONCATENATED MODULE: ./js/reducers/media.ts function media_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function media_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? media_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : media_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const defaultState = { timeMode: TIME_MODE.ELAPSED, timeElapsed: 0, // The winamp ini file declares the default volume as "200". // The UI seems to show a default volume near 78, which would // math with the default value being 200 out of 255. volume: Math.round(200 / 255 * 100), balance: 0, shuffle: false, repeat: false, // TODO: Enforce possible values status: MEDIA_STATUS.STOPPED }; const media = (state = defaultState, action) => { switch (action.type) { // TODO: Make these constants case PLAY: case IS_PLAYING: return media_objectSpread(media_objectSpread({}, state), {}, { status: MEDIA_STATUS.PLAYING }); case PAUSE: return media_objectSpread(media_objectSpread({}, state), {}, { status: MEDIA_STATUS.PAUSED }); case STOP: case IS_STOPPED: return media_objectSpread(media_objectSpread({}, state), {}, { status: MEDIA_STATUS.STOPPED }); case TOGGLE_TIME_MODE: const newMode = state.timeMode === TIME_MODE.REMAINING ? TIME_MODE.ELAPSED : TIME_MODE.REMAINING; return media_objectSpread(media_objectSpread({}, state), {}, { timeMode: newMode }); case UPDATE_TIME_ELAPSED: return media_objectSpread(media_objectSpread({}, state), {}, { timeElapsed: action.elapsed }); case SET_MEDIA: return media_objectSpread({}, state); case SET_VOLUME: return media_objectSpread(media_objectSpread({}, state), {}, { volume: action.volume }); case SET_BALANCE: return media_objectSpread(media_objectSpread({}, state), {}, { balance: action.balance }); case TOGGLE_REPEAT: return media_objectSpread(media_objectSpread({}, state), {}, { repeat: !state.repeat }); case TOGGLE_SHUFFLE: return media_objectSpread(media_objectSpread({}, state), {}, { shuffle: !state.shuffle }); case LOAD_SERIALIZED_STATE: return media_objectSpread(media_objectSpread({}, state), action.serializedState.media); default: return state; } }; function media_getSerializedState(state) { const { volume, balance, shuffle, repeat } = state; return { volume, balance, shuffle, repeat }; } /* harmony default export */ const reducers_media = (media); // EXTERNAL MODULE: ../../node_modules/reselect/lib/index.js var lib = __webpack_require__(4949); ;// CONCATENATED MODULE: ./js/reducers/display.ts const display_excluded = ["skinCursors"]; function display_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function display_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? display_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : display_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const defaultSkinGenExColors = { itemBackground: "rgb(0,0,0)", itemForeground: "rgb(0,255,0)", windowBackground: "rgb(56,55,87)", buttonText: "rgb(57,57,66)", windowText: "rgb(255,255,255)", divider: "rgb(117,116,139)", playlistSelection: "rgb(0,0,198)", listHeaderBackground: "rgb(72,72,120)", listHeaderText: "rgb(255,255,255)", listHeaderFrameTopAndLeft: "rgb(108,108,180)", listHeaderFrameBottomAndRight: "rgb(36,36,60)", listHeaderFramePressed: "rgb(18,18,30)", listHeaderDeadArea: "rgb(36,36,60)", scrollbarOne: "rgb(36,36,60)", scrollbarTwo: "rgb(36,36,60)", pressedScrollbarOne: "rgb(121,130,150)", pressedScrollbarTwo: "rgb(78,88,110)", scrollbarDeadArea: "rgb(36,36,60)", listTextHighlighted: "rgb(0,198,255)", listTextHighlightedBackground: "rgb(0,198,255)", listTextSelected: "rgb(0,198,255)", listTextSelectedBackground: "rgb(0,198,255)" }; const defaultDisplayState = { doubled: false, marqueeStep: 0, disableMarquee: false, loading: true, llama: false, closed: false, working: false, skinImages: DEFAULT_SKIN.images, skinColors: DEFAULT_SKIN.colors, skinCursors: null, skinPlaylistStyle: null, skinRegion: {}, visualizerStyle: 0, // Index into VISUALIZER_ORDER dummyVizData: null, playlistScrollPosition: 0, skinGenLetterWidths: null, // TODO: Get the default value for this? skinGenExColors: defaultSkinGenExColors, additionalVisualizers: [], zIndex: 0 }; const display = (state = defaultDisplayState, action) => { switch (action.type) { case LOAD_DEFAULT_SKIN: { const { skinImages, skinColors, skinCursors, skinPlaylistStyle, skinRegion, skinGenLetterWidths, skinGenExColors } = defaultDisplayState; return display_objectSpread(display_objectSpread({}, state), {}, { skinImages, skinColors, skinCursors, skinPlaylistStyle, skinRegion, skinGenLetterWidths, skinGenExColors }); } case TOGGLE_DOUBLESIZE_MODE: return display_objectSpread(display_objectSpread({}, state), {}, { doubled: !state.doubled }); case actionTypes_TOGGLE_LLAMA_MODE: return display_objectSpread(display_objectSpread({}, state), {}, { llama: !state.llama }); case STEP_MARQUEE: return state.disableMarquee ? state : display_objectSpread(display_objectSpread({}, state), {}, { marqueeStep: state.marqueeStep + 1 }); case DISABLE_MARQUEE: return display_objectSpread(display_objectSpread({}, state), {}, { disableMarquee: true }); case STOP_WORKING: return display_objectSpread(display_objectSpread({}, state), {}, { working: false }); case START_WORKING: return display_objectSpread(display_objectSpread({}, state), {}, { working: true }); case CLOSE_WINAMP: return display_objectSpread(display_objectSpread({}, state), {}, { closed: true }); case OPEN_WINAMP: return display_objectSpread(display_objectSpread({}, state), {}, { closed: false }); case LOADING: return display_objectSpread(display_objectSpread({}, state), {}, { loading: true }); case LOADED: return display_objectSpread(display_objectSpread({}, state), {}, { loading: false }); case SET_SKIN_DATA: const { data } = action; return display_objectSpread(display_objectSpread({}, state), {}, { loading: false, skinImages: data.skinImages, skinColors: data.skinColors, skinPlaylistStyle: data.skinPlaylistStyle, skinCursors: data.skinCursors, skinRegion: data.skinRegion, skinGenLetterWidths: data.skinGenLetterWidths, skinGenExColors: data.skinGenExColors || defaultSkinGenExColors }); case TOGGLE_VISUALIZER_STYLE: return display_objectSpread(display_objectSpread({}, state), {}, { visualizerStyle: (state.visualizerStyle + 1) % VISUALIZER_ORDER.length }); case SET_PLAYLIST_SCROLL_POSITION: return display_objectSpread(display_objectSpread({}, state), {}, { playlistScrollPosition: action.position }); case SET_Z_INDEX: return display_objectSpread(display_objectSpread({}, state), {}, { zIndex: action.zIndex }); case SET_DUMMY_VIZ_DATA: return display_objectSpread(display_objectSpread({}, state), {}, { dummyVizData: action.data }); case LOAD_SERIALIZED_STATE: { const _action$serializedSta = action.serializedState.display, { skinCursors } = _action$serializedSta, rest = _objectWithoutProperties(_action$serializedSta, display_excluded); const upgrade = url => ({ type: "cur", url }); const newSkinCursors = skinCursors == null ? null : objectMap(skinCursors, upgrade); return display_objectSpread(display_objectSpread({}, state), {}, { skinCursors: newSkinCursors }, rest); } default: return state; } }; /* harmony default export */ const reducers_display = (display); const display_getSerializedState = state => { // My kingdom for a type-safe `_.pick`. const { visualizerStyle, doubled, llama, marqueeStep, skinImages, skinCursors, skinRegion, skinGenLetterWidths, skinColors, skinPlaylistStyle } = state; let newCursors = null; if (skinCursors != null) { // @ts-ignore Typescript does not like that we can have `undefined` as // values here. Since this is going to get serialized to JSON (which will // drop undefined) it's fine. // This code is geting removed soon anyway. newCursors = objectMap(skinCursors, cursor => { return cursor.type === "cur" ? cursor.url : undefined; }); } return { visualizerStyle, doubled, llama, marqueeStep, skinImages, skinCursors: newCursors, skinRegion, skinGenLetterWidths, skinColors, skinPlaylistStyle }; }; const getVisualizerStyle = (0,lib/* createSelector */.P1)(state => state.visualizerStyle, visualizationStyle => { return VISUALIZER_ORDER[visualizationStyle]; }); ;// CONCATENATED MODULE: ./js/reducers/userInput.ts function userInput_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function userInput_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? userInput_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : userInput_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const defaultUserInput = { focus: null, bandFocused: null, scrubPosition: 0, userMessage: null }; const userInput = (state = defaultUserInput, action) => { switch (action.type) { case SET_FOCUS: return userInput_objectSpread(userInput_objectSpread({}, state), {}, { focus: action.input, bandFocused: null }); case SET_BAND_FOCUS: return userInput_objectSpread(userInput_objectSpread({}, state), {}, { focus: action.input, bandFocused: action.bandFocused }); case UNSET_FOCUS: return userInput_objectSpread(userInput_objectSpread({}, state), {}, { focus: null, bandFocused: null }); case SET_SCRUB_POSITION: return userInput_objectSpread(userInput_objectSpread({}, state), {}, { scrubPosition: action.position }); case SET_USER_MESSAGE: return userInput_objectSpread(userInput_objectSpread({}, state), {}, { userMessage: action.message }); case UNSET_USER_MESSAGE: return userInput_objectSpread(userInput_objectSpread({}, state), {}, { userMessage: null }); default: return state; } }; /* harmony default export */ const reducers_userInput = (userInput); ;// CONCATENATED MODULE: ./js/reducers/equalizer.ts function equalizer_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function equalizer_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? equalizer_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : equalizer_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const equalizer_defaultState = { on: true, auto: false, sliders: { preamp: 1200, 60: 1200, 170: 1200, 310: 1200, 600: 1200, 1000: 1200, 3000: 1200, 6000: 1200, 12000: 1200, 14000: 1200, 16000: 1200 } }; function migrateSliderValues(sliders) { const migrated = equalizer_objectSpread({}, sliders); const needsMigration = Object.values(sliders).some(val => val > 0 && val <= 100 && val !== 0); if (needsMigration) { Object.keys(migrated).forEach(key => { const value = migrated[key]; if (value >= 0 && value <= 100) { migrated[key] = Math.round(value / 100 * 2400); } }); } return migrated; } const equalizer = (state = equalizer_defaultState, action) => { switch (action.type) { case SET_BAND_VALUE: const newSliders = equalizer_objectSpread(equalizer_objectSpread({}, state.sliders), {}, { [action.band]: action.value }); return equalizer_objectSpread(equalizer_objectSpread({}, state), {}, { sliders: newSliders }); case SET_EQ_ON: return equalizer_objectSpread(equalizer_objectSpread({}, state), {}, { on: true }); case SET_EQ_OFF: return equalizer_objectSpread(equalizer_objectSpread({}, state), {}, { on: false }); case SET_EQ_AUTO: return equalizer_objectSpread(equalizer_objectSpread({}, state), {}, { auto: action.value }); case LOAD_SERIALIZED_STATE: if (action.serializedState.equalizer) { const loadedState = action.serializedState.equalizer; return equalizer_objectSpread(equalizer_objectSpread({}, loadedState), {}, { sliders: migrateSliderValues(loadedState.sliders) }); } return state; default: return state; } }; function equalizer_getSerializedState(state) { return state; } /* harmony default export */ const reducers_equalizer = (equalizer); ;// CONCATENATED MODULE: ./js/reducers/network.ts function network_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function network_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? network_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : network_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const network = (state = { connected: true }, action) => { switch (action.type) { case NETWORK_CONNECTED: return network_objectSpread(network_objectSpread({}, state), {}, { connected: true }); case NETWORK_DISCONNECTED: return network_objectSpread(network_objectSpread({}, state), {}, { connected: false }); default: return state; } }; /* harmony default export */ const reducers_network = (network); ;// CONCATENATED MODULE: ./js/reducers/settings.ts function settings_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function settings_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? settings_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : settings_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const defaultSettingsState = { availableSkins: [] }; const settings = (state = defaultSettingsState, action) => { switch (action.type) { case SET_AVAILABLE_SKINS: return settings_objectSpread(settings_objectSpread({}, state), {}, { availableSkins: action.skins }); default: return state; } }; /* harmony default export */ const reducers_settings = (settings); // EXTERNAL MODULE: ../../node_modules/invariant/browser.js var browser = __webpack_require__(7677); var browser_default = /*#__PURE__*/__webpack_require__.n(browser); ;// CONCATENATED MODULE: ./js/fileUtils.ts // Import music-metadata type definitions function genMediaTags(file, musicMetadata) { browser_default()(file != null, "Attempted to get the tags of media file without passing a file"); const options = { duration: true, skipPostHeaders: true // avoid unnecessary data to be read }; if (typeof file === "string") { return musicMetadata.fetchFromUrl(file, options); } // Assume Blob return musicMetadata.parseBlob(file, options); } function genMediaDuration(url) { browser_default()(typeof url === "string", "Attempted to get the duration of media file without passing a url"); return new Promise((resolve, reject) => { // TODO: Does this actually stop downloading the file once it's // got the duration? const audio = document.createElement("audio"); audio.crossOrigin = "anonymous"; const durationChange = () => { resolve(audio.duration); audio.removeEventListener("durationchange", durationChange); audio.src = ""; // TODO: Not sure if this really gets cleaned up. }; audio.addEventListener("durationchange", durationChange); audio.addEventListener("error", e => { reject(e); }); audio.src = url; }); } async function genArrayBufferFromFileReference(fileReference) { browser_default()(fileReference != null, "Attempt to get an ArrayBuffer without assigning a fileReference"); return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { resolve(reader.result); }; reader.onerror = reject; reader.readAsArrayBuffer(fileReference); }); } async function genStringFromFileReference(fileReference) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onload = () => { resolve(reader.result); }; reader.onerror = reject; reader.readAsText(fileReference); }); } async function promptForFileReferences({ accept, directory = false } = { accept: null, directory: false }) { return new Promise(resolve => { // Does this represent a memory leak somehow? // Can this fail? Do we ever reject? const fileInput = document.createElement("input"); if (accept) fileInput.setAttribute("accept", accept); fileInput.type = "file"; fileInput.multiple = true; // @ts-ignore Non-standard fileInput.webkitdirectory = directory; // @ts-ignore Non-standard fileInput.directory = directory; // @ts-ignore Non-standard fileInput.mozdirectory = directory; // Not entirely sure why this is needed, since the input // was just created, but somehow this helps prevent change // events from getting swallowed. // https://stackoverflow.com/a/12102992/1263117 // @ts-ignore Technically you can't set this to null, it has to be a string. // But I don't feel like retesting it, so I'll leave it as null fileInput.value = null; fileInput.addEventListener("change", e => { const files = e.target.files; resolve(files); }); fileInput.click(); }); } function urlIsBlobUrl(url) { return /^blob:/.test(url); } function curUrlFromByteArray(arr) { const base64 = base64FromDataArray(arr); return `data:image/x-win-bitmap;base64,${base64}`; } // This is not perfect, but... meh: https://stackoverflow.com/a/36756650/1263117 function filenameFromUrl(url) { if (urlIsBlobUrl(url)) { return null; } const lastSegment = url.split("/").pop(); if (lastSegment == null) { return null; } return lastSegment.split("#")[0].split("?")[0]; } ;// CONCATENATED MODULE: ./js/trackUtils.ts const trackName = weakMapMemoize(track => { const { artist, title, defaultName, url } = track; if (artist && title) { return `${artist} - ${title}`; } else if (title) { return title; } else if (defaultName) { return defaultName; } else if (url) { const filename = filenameFromUrl(url); if (filename) { return filename; } } return "???"; }); const trackFilename = weakMapMemoize(track => { if (track.url) { const urlFilename = filenameFromUrl(track.url); if (urlFilename != null) { return urlFilename; } } if (track.defaultName) { return track.defaultName; } return "???"; }); ;// CONCATENATED MODULE: ./js/reducers/tracks.ts function tracks_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function tracks_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? tracks_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : tracks_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const tracks_defaultPlaylistState = {}; const tracks = (state = tracks_defaultPlaylistState, action) => { var _action$duration; switch (action.type) { case ADD_TRACK_FROM_URL: return tracks_objectSpread(tracks_objectSpread({}, state), {}, { [action.id]: { id: action.id, defaultName: action.defaultName || null, duration: (_action$duration = action.duration) !== null && _action$duration !== void 0 ? _action$duration : null, url: action.url, mediaTagsRequestStatus: MEDIA_TAG_REQUEST_STATUS.INITIALIZED } }); case SET_MEDIA: { const newTrack = tracks_objectSpread(tracks_objectSpread({}, state[action.id]), {}, { duration: action.length }); return tracks_objectSpread(tracks_objectSpread({}, state), {}, { [action.id]: newTrack }); } case MEDIA_TAG_REQUEST_INITIALIZED: return tracks_objectSpread(tracks_objectSpread({}, state), {}, { [action.id]: tracks_objectSpread(tracks_objectSpread({}, state[action.id]), {}, { mediaTagsRequestStatus: MEDIA_TAG_REQUEST_STATUS.INITIALIZED }) }); case MEDIA_TAG_REQUEST_FAILED: return tracks_objectSpread(tracks_objectSpread({}, state), {}, { [action.id]: tracks_objectSpread(tracks_objectSpread({}, state[action.id]), {}, { mediaTagsRequestStatus: MEDIA_TAG_REQUEST_STATUS.FAILED }) }); case SET_MEDIA_DURATION: { return tracks_objectSpread(tracks_objectSpread({}, state), {}, { [action.id]: tracks_objectSpread(tracks_objectSpread({}, state[action.id]), {}, { duration: action.duration }) }); } case SET_MEDIA_TAGS: const track = state[action.id]; const { sampleRate, bitrate, numberOfChannels, title, artist, album, albumArtUrl } = action; const { kbps, khz, channels } = track; return tracks_objectSpread(tracks_objectSpread({}, state), {}, { [action.id]: tracks_objectSpread(tracks_objectSpread({}, track), {}, { mediaTagsRequestStatus: MEDIA_TAG_REQUEST_STATUS.COMPLETE, title, artist, album, albumArtUrl, kbps: bitrate != null ? String(Math.round(bitrate / 1000)) : kbps, khz: sampleRate != null ? String(Math.round(sampleRate / 1000)) : khz, channels: numberOfChannels != null ? numberOfChannels : channels }) }); default: return state; } }; /* harmony default export */ const reducers_tracks = (tracks); const getTrackDisplayName = (state, id = null) => { if (id == null) { return null; } const track = state[id]; if (track == null) { return null; } return trackName(track); }; ;// CONCATENATED MODULE: ./js/types.ts // Avoid warnings from Webpack: https://github.com/webpack/webpack/issues/7378 // TODO: Use a type to ensure these keys mirror the CURSORS constant in // skinParser.js // TODO: Type these keys. // TODO: type these keys // TODO: Fill these out once we actually use them. // This is what we actually pass to butterchurn // A URL that points to a Butterchurn preset let TransitionType = /*#__PURE__*/function (TransitionType) { TransitionType[TransitionType["IMMEDIATE"] = 0] = "IMMEDIATE"; TransitionType[TransitionType["DEFAULT"] = 1] = "DEFAULT"; TransitionType[TransitionType["USER_PRESET"] = 2] = "USER_PRESET"; return TransitionType; }({}); /** * Many methods on the webamp instance deal with track. * * Either `url` or `blob` must be specified */ /** * Type definition of the music-metadata module. * Ref: https://github.com/Borewit/music-metadata/blob/master/src/index.ts */ const SELECT_PRESET = "SELECT_PRESET"; const NEXT_PRESET = "NEXT_PRESET"; ;// CONCATENATED MODULE: ./js/reducers/milkdrop.ts function milkdrop_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function milkdrop_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? milkdrop_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : milkdrop_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const defaultMilkdropState = { display: "WINDOW", overlay: false, lock: false, presetHistory: [], presets: [], currentPresetIndex: null, butterchurn: null, transitionType: TransitionType.DEFAULT, randomize: true, cycling: true, message: null }; const milkdrop = (state = defaultMilkdropState, action) => { switch (action.type) { case SET_MILKDROP_DESKTOP: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { display: action.enabled ? "DESKTOP" : "WINDOW" }); case SET_MILKDROP_FULLSCREEN: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { display: action.enabled ? "FULLSCREEN" : "WINDOW" }); case SET_MILKDROP_LOCK: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { lock: action.enabled }); case GOT_BUTTERCHURN: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { butterchurn: action.butterchurn }); case GOT_BUTTERCHURN_PRESETS: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { presets: state.presets.concat(action.presets) }); case PRESET_REQUESTED: if (action.addToHistory) { return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { presetHistory: [...state.presetHistory, action.index] }); } return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { presetHistory: state.presetHistory.slice(0, -1) }); case RESOLVE_PRESET_AT_INDEX: const preset = state.presets[action.index]; return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { presets: replaceAtIndex(state.presets, action.index, { type: "RESOLVED", name: preset.name, preset: action.json }) }); case SELECT_PRESET_AT_INDEX: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { currentPresetIndex: action.index, transitionType: action.transitionType }); case TOGGLE_PRESET_OVERLAY: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { overlay: !state.overlay }); case TOGGLE_RANDOMIZE_PRESETS: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { randomize: !state.randomize }); case TOGGLE_PRESET_CYCLING: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { cycling: !state.cycling }); case SCHEDULE_MILKDROP_MESSAGE: return milkdrop_objectSpread(milkdrop_objectSpread({}, state), {}, { message: { text: action.message, time: Date.now() } }); default: return state; } }; /* harmony default export */ const reducers_milkdrop = (milkdrop); ;// CONCATENATED MODULE: ./js/reducers/index.ts const reducer = (0,redux/* combineReducers */.UY)({ userInput: reducers_userInput, windows: reducers_windows, display: reducers_display, settings: reducers_settings, equalizer: reducers_equalizer, playlist: reducers_playlist, media: reducers_media, network: reducers_network, tracks: reducers_tracks, milkdrop: reducers_milkdrop }); /* harmony default export */ const reducers = (reducer); // EXTERNAL MODULE: ../../node_modules/react/jsx-runtime.js var jsx_runtime = __webpack_require__(2322); ;// CONCATENATED MODULE: ./js/playlistHtml.tsx function playlistHtml_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function playlistHtml_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? playlistHtml_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : playlistHtml_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const getAsDataURI = text => `data:text/html;base64,${window.btoa(text)}`; // Replaces deprecated "noshade" attribute const noshadeStyle = { height: "2px", borderWidth: 0, color: "gray", backgroundColor: "gray" }; // We use all kinds of non-standard attributes and tags. So we create these fake // components to trick Typescript. const Body = props => { // @ts-ignore return /*#__PURE__*/(0,jsx_runtime.jsx)("body", playlistHtml_objectSpread({}, props)); }; const Font = props => { // @ts-ignore return /*#__PURE__*/(0,jsx_runtime.jsx)("font", playlistHtml_objectSpread({}, props)); }; const Hr = props => { // @ts-ignore return /*#__PURE__*/(0,jsx_runtime.jsx)("hr", playlistHtml_objectSpread({}, props)); }; const Div = props => { // @ts-ignore return /*#__PURE__*/(0,jsx_runtime.jsx)("div", playlistHtml_objectSpread({}, props)); }; const Table = props => { // @ts-ignore return /*#__PURE__*/(0,jsx_runtime.jsx)("table", playlistHtml_objectSpread({}, props)); }; // TODO: Move tag out to the string creation step in order // to avoid the warning. const Playlist = props => /*#__PURE__*/(0,jsx_runtime.jsxs)("html", { children: [/*#__PURE__*/(0,jsx_runtime.jsxs)("head", { children: [/*#__PURE__*/(0,jsx_runtime.jsx)("link", { rel: "stylesheet", href: "null" }), /*#__PURE__*/(0,jsx_runtime.jsx)("style", { type: "text/css", children: ` body { background: #000040; } .para1 { margin-top: -42px; margin-left: 145px; margin-right: 10px; font-family: "font2, Arial"; font-size: 30px; line-height: 35px; text-align: left; color: #E1E1E1; } .para2 { margin-top: 15px; margin-left: 15px; margin-right: 50px; font-family: "font1, Arial Black"; font-size: 50px; line-height: 40px; text-align: left; color: #004080; } ` }), /*#__PURE__*/(0,jsx_runtime.jsx)("title", { children: "Winamp Generated PlayList" })] }), /*#__PURE__*/(0,jsx_runtime.jsxs)(Body, { bgcolor: "#000080", topmargin: "0", leftmargin: "0", text: "#FFFFFF", children: [/*#__PURE__*/(0,jsx_runtime.jsxs)(Div, { align: "center", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Div, { className: "para2", align: "center", children: /*#__PURE__*/(0,jsx_runtime.jsx)("p", { children: "WINAMP" }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(Div, { className: "para1", align: "center", children: /*#__PURE__*/(0,jsx_runtime.jsx)("p", { children: "playlist" }) })] }), /*#__PURE__*/(0,jsx_runtime.jsx)(Hr, { align: "left", width: "90%", size: "1", color: "#FFBF00", style: noshadeStyle }), /*#__PURE__*/(0,jsx_runtime.jsx)(Div, { align: "right", children: /*#__PURE__*/(0,jsx_runtime.jsx)(Table, { border: "0", cellSpacing: "0", cellPadding: "0", width: "98%", children: /*#__PURE__*/(0,jsx_runtime.jsx)("tbody", { children: /*#__PURE__*/(0,jsx_runtime.jsx)("tr", { children: /*#__PURE__*/(0,jsx_runtime.jsxs)("td", { children: [/*#__PURE__*/(0,jsx_runtime.jsx)("small", { children: /*#__PURE__*/(0,jsx_runtime.jsxs)("small", { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Font, { face: "Arial", color: "#FFBF00", children: props.numberOfTracks }), /*#__PURE__*/(0,jsx_runtime.jsx)(Font, { color: "#409FFF", face: "Arial", children: " track in playlist, average track length: " }), /*#__PURE__*/(0,jsx_runtime.jsx)(Font, { face: "Arial", color: "#FFBF00", children: props.averageTrackLength })] }) }), /*#__PURE__*/(0,jsx_runtime.jsx)("br", {}), /*#__PURE__*/(0,jsx_runtime.jsx)("small", { children: /*#__PURE__*/(0,jsx_runtime.jsxs)("small", { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Font, { color: "#409FFF", face: "Arial", children: "Playlist length: " }), /*#__PURE__*/(0,jsx_runtime.jsx)(Font, { face: "Arial", color: "#FFBF00", children: props.playlistLengthMinutes }), /*#__PURE__*/(0,jsx_runtime.jsx)(Font, { color: "#409FFF", face: "Arial", children: " minutes " }), /*#__PURE__*/(0,jsx_runtime.jsx)(Font, { face: "Arial", color: "#FFBF00", children: props.playlistLengthSeconds }), /*#__PURE__*/(0,jsx_runtime.jsx)(Font, { color: "#409FFF", face: "Arial", children: " second " }), /*#__PURE__*/(0,jsx_runtime.jsx)("br", {}), /*#__PURE__*/(0,jsx_runtime.jsxs)(Font, { color: "#409FFF", face: "Arial", children: ["Right-click ", /*#__PURE__*/(0,jsx_runtime.jsx)("a", { href: "./", children: "here" }), " to save this HTML file."] })] }) })] }) }) }) }) }), /*#__PURE__*/(0,jsx_runtime.jsxs)("blockquote", { children: [/*#__PURE__*/(0,jsx_runtime.jsx)("p", { children: /*#__PURE__*/(0,jsx_runtime.jsx)(Font, { color: "#FFBF00", face: "Arial", children: /*#__PURE__*/(0,jsx_runtime.jsx)("big", { children: "Playlist files:" }) }) }), /*#__PURE__*/(0,jsx_runtime.jsx)("ul", { children: /*#__PURE__*/(0,jsx_runtime.jsx)(Font, { face: "Arial", color: "#FFFFFF", children: /*#__PURE__*/(0,jsx_runtime.jsx)("small", { children: props.tracks.map(track => /*#__PURE__*/(0,jsx_runtime.jsxs)("span", { children: [track, /*#__PURE__*/(0,jsx_runtime.jsx)("br", {})] }, track)) }) }) })] }), /*#__PURE__*/(0,jsx_runtime.jsx)(Hr, { align: "left", width: "90%", size: "1", color: "#FFBF00", style: noshadeStyle })] })] }); const createPlaylistHTML = props => { const node = document.createElement("div"); (0,react_dom.render)( /*#__PURE__*/(0,jsx_runtime.jsx)(Playlist, playlistHtml_objectSpread({}, props)), node); return node.innerHTML; }; const createPlaylistURL = props => getAsDataURI(createPlaylistHTML(props)); ;// CONCATENATED MODULE: ./js/marqueeUtils.tsx const getBalanceText = balance => { if (balance === 0) { return "Balance: Center"; } const direction = balance > 0 ? "Right" : "Left"; return `Balance: ${Math.abs(balance)}% ${direction}`; }; const getVolumeText = volume => `Volume: ${volume}%`; const getPositionText = (duration, seekToPercent) => { const newElapsedStr = getTimeStr(duration * seekToPercent / 100, false); const durationStr = getTimeStr(duration, false); return `Seek to: ${newElapsedStr}/${durationStr} (${seekToPercent}%)`; }; const getDoubleSizeModeText = enabled => `${enabled ? "Disable" : "Enable"} doublesize mode`; const formatHz = hz => hz < 1000 ? `${hz}HZ` : `${hz / 1000}KHZ`; // Format a number as a string, ensuring it has a + or - sign const ensureSign = num => num > 0 ? `+${num}` : num.toString(); // Round to 1 and exactly 1 decimal point const roundToTenths = num => (Math.round(num * 10) / 10).toFixed(1); const getEqText = (band, level) => { const db = roundToTenths((level - 50) / 50 * 12); const label = band === "preamp" ? "Preamp" : formatHz(band); return `EQ: ${label} ${ensureSign(db)} DB`; }; ;// CONCATENATED MODULE: ./js/resizeUtils.ts function getPositionDiff(graph, sizeDiff) { const newGraph = {}; const positionDiff = {}; for (const key of Object.keys(graph)) { newGraph[key] = { above: [], left: [] }; positionDiff[key] = { x: 0, y: 0 }; } // Construct an inverted graph for (const [key, neighbors] of Object.entries(graph)) { const { below, right } = neighbors; if (right != null) { newGraph[right].left.push(key); } if (below != null) { newGraph[below].above.push(key); } } function walkRight(key) { const node = newGraph[key]; const nodeSizeDiff = sizeDiff[key]; node.left.forEach(left => { positionDiff[left].x += nodeSizeDiff.width + positionDiff[key].x; walkRight(left); }); } function walkDown(key) { const node = newGraph[key]; const nodeSizeDiff = sizeDiff[key]; node.above.forEach(above => { positionDiff[above].y += nodeSizeDiff.height + positionDiff[key].y; walkDown(above); }); } // Find disconnected nodes, and walk for (const [key, neighbors] of Object.entries(graph)) { if (neighbors.below == null) { walkDown(key); } if (neighbors.right == null) { walkRight(key); } } return positionDiff; } function generateGraph(windows) { const bottoms = {}; const rights = {}; for (const w of windows) { const bottom = w.y + w.height; if (bottoms[bottom]) { bottoms[bottom].push(w); } else { bottoms[bottom] = [w]; } const right = w.x + w.width; if (rights[right]) { rights[right].push(w); } else { rights[right] = [w]; } } const graph = {}; for (const w of windows) { const edges = {}; const top = w.y; const left = w.x; const tops = bottoms[top]; const lefts = rights[left]; if (tops) { for (const below of tops) { const isToTheLeft = below.x + below.width < w.x; const isToTheRight = below.x > w.x + w.width; const overlapsInX = !(isToTheLeft || isToTheRight); if (overlapsInX) { edges.below = below.key; break; } } } if (lefts) { for (const right of lefts) { const isAbove = right.y + right.height < w.y; const isBelow = right.y > w.y + w.height; const overlapsInY = !(isAbove || isBelow); if (overlapsInY) { edges.right = right.key; break; } } } graph[w.key] = edges; } return graph; } // EXTERNAL MODULE: ../../node_modules/butterchurn-presets/lib/butterchurnPresets.min.js var butterchurnPresets_min = __webpack_require__(6278); var butterchurnPresets_min_default = /*#__PURE__*/__webpack_require__.n(butterchurnPresets_min); ;// CONCATENATED MODULE: ./js/selectors.ts function selectors_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function selectors_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? selectors_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : selectors_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // @ts-ignore const getSliders = state => state.equalizer.sliders; const getEqfData = (0,lib/* createSelector */.P1)(getSliders, sliders => { const preset = { name: "Entry1", preamp: denormalizeEqBand(sliders.preamp) }; BANDS.forEach(band => { preset[`hz${band}`] = denormalizeEqBand(sliders[band]); }); const eqfData = { presets: [preset], type: "Winamp EQ library file v1.1" }; return eqfData; }); const getTracks = state => state.tracks; const getTrackUrl = state => { return id => { var _state$tracks$id; return (_state$tracks$id = state.tracks[id]) === null || _state$tracks$id === void 0 ? void 0 : _state$tracks$id.url; }; }; const getTrackOrder = state => state.playlist.trackOrder; const getTrackCount = (0,lib/* createSelector */.P1)(getTrackOrder, trackOrder => trackOrder.length); const getOrderedTracks = (0,lib/* createSelector */.P1)(getTracks, getTrackOrder, (tracks, trackOrder) => trackOrder.filter(id => tracks[id])); const getUserTracks = (0,lib/* createSelector */.P1)(getTracks, getTrackOrder, (tracks, trackOrder) => trackOrder.map(id => { const track = tracks[id]; return { url: track.url, metaData: { artist: track.artist || "", title: track.title || "", album: track.album, albumArtUrl: track.albumArtUrl || "" } }; })); const getOrderedTrackObjects = (0,lib/* createSelector */.P1)(getTracks, getOrderedTracks, (tracks, trackOrder) => trackOrder.map(id => tracks[id])); const getSelectedTrackIds = state => { return state.playlist.selectedTracks; }; const getSelectedTrackObjects = (0,lib/* createSelector */.P1)(getOrderedTrackObjects, getSelectedTrackIds, (tracks, selectedIds) => tracks.filter(track => selectedIds.has(track.id))); // If a duration is `null`, it counts as zero, which seems fine enough. const runningTimeFromTracks = tracks => tracks.reduce((time, track) => time + Number(track.duration), 0); const getTotalRunningTime = (0,lib/* createSelector */.P1)(getOrderedTrackObjects, runningTimeFromTracks); const getSelectedRunningTime = (0,lib/* createSelector */.P1)(getSelectedTrackObjects, runningTimeFromTracks); // Note: We should append "+" to these values if some of the tracks are of unknown time. const getRunningTimeMessage = (0,lib/* createSelector */.P1)(getTotalRunningTime, getSelectedRunningTime, (totalRunningTime, selectedRunningTime) => `${getTimeStr(selectedRunningTime)}/${getTimeStr(totalRunningTime)}`); // TODO: use slectors to get memoization const getCurrentTrackIndex = state => { const { playlist } = state; if (playlist.currentTrack == null) { return -1; } return playlist.trackOrder.indexOf(playlist.currentTrack); }; const getCurrentTrackNumber = (0,lib/* createSelector */.P1)(getCurrentTrackIndex, currentTrackIndex => currentTrackIndex + 1); const getCurrentTrackId = state => state.playlist.currentTrack; // TODO: Sigh... Technically, we should detect if we are looping only repeat if we are. // I think this would require pre-computing the "random" order of a playlist. const getRandomTrackId = state => { const { playlist: { trackOrder, currentTrack } } = state; if (trackOrder.length === 0) { return null; } let nextId; do { nextId = trackOrder[Math.floor(trackOrder.length * Math.random())]; } while (nextId === currentTrack && trackOrder.length > 1); return nextId; }; const getNextTrackId = (state, n = 1) => { const { playlist: { trackOrder }, media: { repeat, shuffle } } = state; if (shuffle) { return getRandomTrackId(state); } const trackCount = getTrackCount(state); if (trackCount === 0) { return null; } const currentIndex = getCurrentTrackIndex(state); let nextIndex = currentIndex + n; if (repeat) { nextIndex = nextIndex % trackCount; if (nextIndex < 0) { // Handle wrapping around backwards nextIndex += trackCount; } return trackOrder[nextIndex]; } if (currentIndex === trackCount - 1 && n > 0) { return null; } else if (currentIndex === 0 && n < 0) { return null; } nextIndex = clamp(nextIndex, 0, trackCount - 1); return trackOrder[nextIndex]; }; const getGenWindows = state => { return state.windows.genWindows; }; const selectors_getWindowOpen = (0,lib/* createSelector */.P1)(getGenWindows, genWindows => { return windowId => genWindows[windowId].open; }); const selectors_getWindowHidden = (0,lib/* createSelector */.P1)(getGenWindows, genWindows => { return windowId => genWindows[windowId].hidden; }); const selectors_getWindowShade = (0,lib/* createSelector */.P1)(getGenWindows, genWindows => { return windowId => genWindows[windowId].shade; }); const selectors_getWindowSize = (0,lib/* createSelector */.P1)(getGenWindows, genWindows => { return windowId => genWindows[windowId].size; }); const getWindowPositions = (0,lib/* createSelector */.P1)(getGenWindows, windows => objectMap(windows, w => w.position)); const BASE_WINDOW_HEIGHT = 58; const getNumberOfVisibleTracks = (0,lib/* createSelector */.P1)(selectors_getWindowSize, getWindowSize_ => { const playlistSize = getWindowSize_("playlist"); return Math.floor((BASE_WINDOW_HEIGHT + WINDOW_RESIZE_SEGMENT_HEIGHT * playlistSize[1]) / TRACK_HEIGHT); }); const getOverflowTrackCount = (0,lib/* createSelector */.P1)(getTrackCount, getNumberOfVisibleTracks, (trackCount, numberOfVisibleTracks) => Math.max(0, trackCount - numberOfVisibleTracks)); const _getPlaylistScrollPosition = state => state.display.playlistScrollPosition; const getPlaylistScrollPosition = (0,lib/* createSelector */.P1)(getOverflowTrackCount, _getPlaylistScrollPosition, (overflowTrackCount, playlistScrollPosition) => { if (overflowTrackCount === 0) { return 0; } return Math.round(Math.round(overflowTrackCount * playlistScrollPosition / 100) / overflowTrackCount * 100); }); const getScrollOffset = (0,lib/* createSelector */.P1)(_getPlaylistScrollPosition, getTrackCount, getNumberOfVisibleTracks, (playlistScrollPosition, trackCount, numberOfVisibleTracks) => { const overflow = Math.max(0, trackCount - numberOfVisibleTracks); return percentToIndex(playlistScrollPosition / 100, overflow + 1); }); const getVisibleTrackIds = (0,lib/* createSelector */.P1)(getScrollOffset, getTrackOrder, getNumberOfVisibleTracks, (offset, trackOrder, numberOfVisibleTracks) => trackOrder.slice(offset, offset + numberOfVisibleTracks)); function getAllTracksAreVisible(state) { return getVisibleTrackIds(state).length === state.playlist.trackOrder.length; } const getTrackIsVisibleFunction = (0,lib/* createSelector */.P1)(getVisibleTrackIds, visibleTrackIds => { return id => visibleTrackIds.includes(id); }); const getVisibleTracks = (0,lib/* createSelector */.P1)(getVisibleTrackIds, getTracks, (visibleTrackIds, tracks) => visibleTrackIds.map(id => tracks[id])); const getPlaylist = state => state.playlist; const getDuration = state => { const { playlist, tracks } = state; if (playlist.currentTrack == null) { return null; } const currentTrack = tracks[playlist.currentTrack]; return currentTrack && currentTrack.duration; }; const selectors_getTrackDisplayName = (0,lib/* createSelector */.P1)(getTracks, tracks => { return (0,lib/* defaultMemoize */.PW)(trackId => getTrackDisplayName(tracks, trackId)); }); const getCurrentTrackDisplayName = (0,lib/* createSelector */.P1)(getCurrentTrackId, selectors_getTrackDisplayName, (id, getName) => { return getName(id); }); const getMediaStatus = state => { return state.media.status; }; const getMediaIsPlaying = state => state.media.status === MEDIA_STATUS.PLAYING; const getCurrentTrack = (0,lib/* createSelector */.P1)(getCurrentTrackId, getTracks, (trackId, tracks) => { return trackId == null ? null : tracks[trackId]; }); const getCurrentlyPlayingTrackIdIfLoaded = (0,lib/* createSelector */.P1)(getMediaIsPlaying, getCurrentTrack, (mediaIsPlaying, currentTrack) => { if (!mediaIsPlaying || !currentTrack || currentTrack.mediaTagsRequestStatus === MEDIA_TAG_REQUEST_STATUS.INITIALIZED) { return null; } return currentTrack.id; }); const getCurrentTrackInfo = (0,lib/* createSelector */.P1)(getCurrentTrack, track => { if (track == null) { return null; } return { url: track.url, metaData: { title: track.title || null, artist: track.artist || null, album: track.album || null, albumArtUrl: track.albumArtUrl || null } }; }); const getMinimalMediaText = (0,lib/* createSelector */.P1)(getCurrentTrackNumber, getCurrentTrackDisplayName, (trackNumber, name) => name == null ? null : `${trackNumber}. ${name}`); const getMediaText = (0,lib/* createSelector */.P1)(getMinimalMediaText, getDuration, (minimalMediaText, duration) => minimalMediaText == null ? null : `${minimalMediaText} (${getTimeStr(duration)})`); const getNumberOfTracks = state => getTrackOrder(state).length; const getPlaylistDuration = (0,lib/* createSelector */.P1)(getTracks, tracks => Object.values(tracks).reduce((total, track) => total + (track.duration || 0), 0)); const getPlaylistURL = (0,lib/* createSelector */.P1)(getNumberOfTracks, getPlaylistDuration, getTrackOrder, getTracks, selectors_getTrackDisplayName, (numberOfTracks, playlistDuration, trackOrder, tracks, getDisplayName) => createPlaylistURL({ numberOfTracks, averageTrackLength: getTimeStr(playlistDuration / numberOfTracks), // TODO: Handle hours playlistLengthMinutes: Math.floor(playlistDuration / 60), playlistLengthSeconds: Math.floor(playlistDuration % 60), tracks: trackOrder.map((id, i) => `${i + 1}. ${getDisplayName(id)} (${getTimeStr(tracks[id].duration)})`) })); const selectors_WINDOW_HEIGHT = 116; const SHADE_WINDOW_HEIGHT = 14; function getWPixelSize(w, doubled) { const [width, height] = w.size; let doubledMultiplier = doubled && w.canDouble ? 2 : 1; if (w.title == "Playlist Editor") { doubledMultiplier = 1; } const pix = { height: selectors_WINDOW_HEIGHT + height * WINDOW_RESIZE_SEGMENT_HEIGHT, width: WINDOW_WIDTH + width * WINDOW_RESIZE_SEGMENT_WIDTH }; return { height: (w.shade ? SHADE_WINDOW_HEIGHT : pix.height) * doubledMultiplier, width: pix.width * doubledMultiplier }; } function getFocusedWindow(state) { return state.windows.focused; } function getWindowPosition(state) { return windowId => state.windows.genWindows[windowId].position; } function getPositionsAreRelative(state) { return state.windows.positionsAreRelative; } function getDoubled(state) { return state.display.doubled; } function getLlamaMode(state) { return state.display.llama; } function getZIndex(state) { return state.display.zIndex; } // TODO: This is poorly memoized. It invalidates when a window moves. const getWindowSizes = (0,lib/* createSelector */.P1)(getGenWindows, getDoubled, (windows, doubled) => { return objectMap(windows, w => getWPixelSize(w, doubled)); }); const selectors_getWindowPixelSize = (0,lib/* createSelector */.P1)(getWindowSizes, sizes => { return windowId => sizes[windowId]; }); const getWindowOrder = state => state.windows.windowOrder; const getNormalizedWindowOrder = (0,lib/* createSelector */.P1)(getWindowOrder, getGenWindows, (windowOrder, genWindows) => { return [WINDOWS.MAIN, ...windowOrder.filter(windowId => windowId !== WINDOWS.MAIN && genWindows[windowId] != null)]; }); // TODO: Now that both size and position are stored on genWindows this seems a bit silly. const getWindowsInfo = (0,lib/* createSelector */.P1)(getWindowSizes, getWindowPositions, getNormalizedWindowOrder, (sizes, positions, windowOrder) => { return windowOrder.map(key => selectors_objectSpread(selectors_objectSpread({ key }, sizes[key]), positions[key])); }); const getWindowGraph = (0,lib/* createSelector */.P1)(getWindowsInfo, generateGraph); const defaultPlaylistStyle = { normal: "#00FF00", current: "#FFFFFF", normalbg: "#000000", selectedbg: "#0000C6", font: "Arial" }; function getSkinColors(state) { return state.display.skinColors; } const getSkinPlaylistStyle = state => { return state.display.skinPlaylistStyle || defaultPlaylistStyle; }; const selectors_getVisualizerStyle = state => { const milkdrop = state.windows.genWindows[WINDOWS.MILKDROP]; if (milkdrop != null && milkdrop.open) { return VISUALIZERS.MILKDROP; } return getVisualizerStyle(state.display); }; const getVolume = state => state.media.volume; const getBalance = state => state.media.balance; const getShuffle = state => state.media.shuffle; const getRepeat = state => state.media.repeat; const getChannels = (0,lib/* createSelector */.P1)(getCurrentTrack, track => { return track != null ? track.channels || null : null; }); const getTimeElapsed = state => { return state.media.timeElapsed; }; function getSerlializedState(state) { return { version: 1, media: media_getSerializedState(state.media), equalizer: equalizer_getSerializedState(state.equalizer), display: display_getSerializedState(state.display), windows: getSerializedState(state.windows) }; } function getEqualizerEnabled(state) { return state.equalizer.on; } function getEqualizerAuto(state) { return state.equalizer.auto; } function getBrowserWindowSize(state) { return state.windows.browserWindowSize; } const getOpenWindows = (0,lib/* createSelector */.P1)(getGenWindows, genWindows => objectFilter(genWindows, w => w.open)); const getStackedLayoutPositions = (0,lib/* createSelector */.P1)(getOpenWindows, getDoubled, (openWindows, doubled) => { let offset = 0; return objectMap(openWindows, w => { const position = { x: 0, y: offset }; offset += getWPixelSize(w, doubled).height; return position; }); }); const getUserInputFocus = state => { return state.userInput.focus; }; const getUserInputScrubPosition = state => { return state.userInput.scrubPosition; }; // TODO: Make this a reselect selector const getMarqueeText = state => { const defaultText = "Winamp 2.91"; if (state.userInput.userMessage != null) { return state.userInput.userMessage; } switch (getUserInputFocus(state)) { case "balance": return getBalanceText(state.media.balance); case "volume": return getVolumeText(state.media.volume); case "position": const duration = getDuration(state); if (duration == null) { // This probably can't ever happen. return defaultText; } return getPositionText(duration, getUserInputScrubPosition(state)); case "double": return getDoubleSizeModeText(state.display.doubled); case "eq": const band = state.userInput.bandFocused; if (band == null) { // This probably can't ever happen. return defaultText; } return getEqText(band, state.equalizer.sliders[band]); default: break; } if (state.playlist.currentTrack != null) { const mediaText = getMediaText(state); if (mediaText == null) { // This probably can't ever happen. return defaultText; } return mediaText; } return defaultText; }; const getKbps = (0,lib/* createSelector */.P1)(getCurrentTrack, track => { return track != null ? track.kbps || null : null; }); const getKhz = (0,lib/* createSelector */.P1)(getCurrentTrack, track => { return track != null ? track.khz || null : null; }); function getDebugData(state) { return selectors_objectSpread(selectors_objectSpread({}, state), {}, { display: selectors_objectSpread(selectors_objectSpread({}, state.display), {}, { skinGenLetterWidths: "[[REDACTED]]", skinImages: "[[REDACTED]]", skinCursors: "[[REDACTED]]", skinRegion: "[[REDACTED]]" }) }); } function getMilkdropMessage(state) { return state.milkdrop.message; } function getMilkdropWindowEnabled(state) { return state.milkdrop.display === "WINDOW"; } function getMilkdropDesktopEnabled(state) { return state.milkdrop.display === "DESKTOP"; } function getMilkdropFullscreenEnabled(state) { return state.milkdrop.display === "FULLSCREEN"; } function getMilkdropLockEnabled(state) { return state.milkdrop.lock; } function getPresets(state) { return butterchurnPresets.getPresets(); } function getButterchurn(state) { return state.milkdrop.butterchurn; } function getPresetTransitionType(state) { return state.milkdrop.transitionType; } function getCurrentPresetIndex(state) { return state.milkdrop.currentPresetIndex; } function getCurrentPreset(state) { const index = getCurrentPresetIndex(state); if (index == null) { return null; } const preset = butterchurnPresets_min_default().getPresets()[index]; if (preset == null) { return null; } return preset; } function getPresetNames(state) { return state.milkdrop.presets.map(preset => preset.name); } function getPresetOverlayOpen(state) { return state.milkdrop.overlay; } function getPresetsAreCycling(state) { return state.milkdrop.cycling; } function getRandomizePresets(state) { return state.milkdrop.randomize; } function getClosed(state) { return state.display.closed; } function getSkinImages(state) { return state.display.skinImages; } function getSkinCursors(state) { return state.display.skinCursors; } function getSkinRegion(state) { return state.display.skinRegion; } function getSkinLetterWidths(state) { return state.display.skinGenLetterWidths; } function getPreampLineUrl(state) { return state.display.skinImages.EQ_PREAMP_LINE; } function getLineColorsUrl(state) { return state.display.skinImages.EQ_GRAPH_LINE_COLORS; } const getPreampLineImage = (0,lib/* createSelector */.P1)(getPreampLineUrl, async url => { if (url == null) { return null; } return imgFromUrl(url); }); const getLineColorsImage = (0,lib/* createSelector */.P1)(getLineColorsUrl, async url => { if (url == null) { return null; } return imgFromUrl(url); }); function getDummyVizData(state) { return state.display.dummyVizData; } function getMarqueeStep(state) { return state.display.marqueeStep; } function getNetworkConnected(state) { return state.network.connected; } function getTimeMode(state) { return state.media.timeMode; } function getLoading(state) { return state.display.loading; } function getWorking(state) { return state.display.working; } function getAvaliableSkins(state) { return state.settings.availableSkins; } ;// CONCATENATED MODULE: ./js/snapUtils.ts function snapUtils_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function snapUtils_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? snapUtils_ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : snapUtils_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const SNAP_DISTANCE = 15; const snapUtils_top = box => box.y; const bottom = box => box.y + box.height; const left = box => box.x; const right = box => box.x + box.width; const near = (a, b) => Math.abs(a - b) < SNAP_DISTANCE; // http://stackoverflow.com/a/3269471/1263117 const overlapX = (a, b) => left(a) <= right(b) + SNAP_DISTANCE && left(b) <= right(a) + SNAP_DISTANCE; const overlapY = (a, b) => snapUtils_top(a) <= bottom(b) + SNAP_DISTANCE && snapUtils_top(b) <= bottom(a) + SNAP_DISTANCE; // Give a new position for `boxA` that snaps it to `boxB` if neede. const snap = (boxA, boxB) => { let x, y; // TODO: Refactor/simplify this code if (overlapY(boxA, boxB)) { if (near(left(boxA), right(boxB))) { x = right(boxB); } else if (near(right(boxA), left(boxB))) { x = left(boxB) - boxA.width; } else if (near(left(boxA), left(boxB))) { x = left(boxB); } else if (near(right(boxA), right(boxB))) { x = right(boxB) - boxA.width; } } if (overlapX(boxA, boxB)) { if (near(snapUtils_top(boxA), bottom(boxB))) { y = bottom(boxB); } else if (near(bottom(boxA), snapUtils_top(boxB))) { y = snapUtils_top(boxB) - boxA.height; } else if (near(snapUtils_top(boxA), snapUtils_top(boxB))) { y = snapUtils_top(boxB); } else if (near(bottom(boxA), bottom(boxB))) { y = bottom(boxB) - boxA.height; } } return { x, y }; }; const snapDiff = (a, b) => { const newPos = snap(a, b); return { x: newPos.x === undefined ? 0 : newPos.x - a.x, y: newPos.y === undefined ? 0 : newPos.y - a.y }; }; // TODO: Use the first x and y combo const snapDiffManyToMany = (as, bs) => { let x = 0; let y = 0; for (const a of as) { for (const b of bs) { const diff = snapDiff(a, b); x = x || diff.x; y = y || diff.y; if (x !== undefined && x > 0 && y !== undefined && y > 0) { break; } } } return { x, y }; }; const snapToMany = (boxA, otherBoxes) => { let x; let y; otherBoxes.forEach(boxB => { const newPos = snap(boxA, boxB); x = newPos.x || x; y = newPos.y || y; }); return { x, y }; }; const snapWithin = (boxA, boundingBox) => { let x, y; if (boxA.x - SNAP_DISTANCE < 0) { x = 0; } else if (boxA.x + boxA.width + SNAP_DISTANCE > boundingBox.width) { x = boundingBox.width - boxA.width; } if (boxA.y - SNAP_DISTANCE < 0) { y = 0; } else if (boxA.y + boxA.height + SNAP_DISTANCE > boundingBox.height) { y = boundingBox.height - boxA.height; } return { x, y }; }; const snapWithinDiff = (a, b) => { const newPos = snapWithin(a, b); return { x: newPos.x === undefined ? 0 : newPos.x - a.x, y: newPos.y === undefined ? 0 : newPos.y - a.y }; }; const applySnap = (original, ...snaps) => snaps.reduce((previous, snapped) => snapUtils_objectSpread(snapUtils_objectSpread({}, previous), {}, { x: typeof snapped.x !== "undefined" ? snapped.x : previous.x, y: typeof snapped.y !== "undefined" ? snapped.y : previous.y }), original); const snapUtils_boundingBox = nodes => { const boxes = nodes.slice(); const firstNode = boxes.pop(); if (firstNode == null) { throw new Error("boundingBox must be called with at least one node"); } const bounding = { top: snapUtils_top(firstNode), right: right(firstNode), bottom: bottom(firstNode), left: left(firstNode) }; boxes.forEach(node => { bounding.top = Math.min(bounding.top, snapUtils_top(node)); bounding.right = Math.max(bounding.right, right(node)); bounding.bottom = Math.max(bounding.bottom, bottom(node)); bounding.left = Math.min(bounding.left, left(node)); }); return { x: bounding.left, y: bounding.top, width: bounding.right - bounding.left, height: bounding.bottom - bounding.top }; }; function traceConnection(areConnected) { return (candidates, node) => { const connected = new Set(); const checkNode = n => { for (const candidate of candidates) { if (!connected.has(candidate) && areConnected(candidate, n)) { connected.add(candidate); checkNode(candidate); } } }; checkNode(node); return connected; }; } const applyDiff = (a, b) => ({ x: a.x + b.x, y: a.y + b.y }); // TODO: This should not const applyMultipleDiffs = (initial, ...diffs) => { const metaDiff = diffs.reduce((m, diff) => ({ // Use the smallest non-zero diff for each axis. // TODO: Min should be the absolute value x: m.x === 0 || diff.x === 0 ? m.x + diff.x : Math.min(m.x, diff.x), y: m.y === 0 || diff.y === 0 ? m.y + diff.y : Math.min(m.y, diff.y) })); return applyDiff(initial, metaDiff); }; ;// CONCATENATED MODULE: ./js/actionCreators/windows.ts function actionCreators_windows_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function actionCreators_windows_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? actionCreators_windows_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : actionCreators_windows_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // Dispatch an action and, if needed rearrange the windows to preserve // the existing edge relationship. // // Works by checking the edges before the action is dispatched. Then, // after disatching, calculating what position change would be required // to restore those relationships. function withWindowGraphIntegrity(action) { return (dispatch, getState) => { const state = getState(); const graph = getWindowGraph(state); const originalSizes = getWindowSizes(state); dispatch(action); const newSizes = getWindowSizes(getState()); const sizeDiff = {}; for (const window of Object.keys(newSizes)) { const original = originalSizes[window]; const current = newSizes[window]; sizeDiff[window] = { height: current.height - original.height, width: current.width - original.width }; } const positionDiff = getPositionDiff(graph, sizeDiff); const windowPositions = getWindowPositions(state); const newPositions = objectMap(windowPositions, (position, key) => applyDiff(position, positionDiff[key])); dispatch(windows_updateWindowPositions(newPositions)); }; } function windows_toggleDoubleSizeMode() { return withWindowGraphIntegrity({ type: TOGGLE_DOUBLESIZE_MODE }); } function toggleLlamaMode() { return { type: TOGGLE_LLAMA_MODE }; } function windows_toggleEqualizerShadeMode() { return withWindowGraphIntegrity({ type: TOGGLE_WINDOW_SHADE_MODE, windowId: "equalizer" }); } function windows_toggleMainWindowShadeMode() { return withWindowGraphIntegrity({ type: TOGGLE_WINDOW_SHADE_MODE, windowId: "main" }); } function togglePlaylistShadeMode() { return withWindowGraphIntegrity({ type: TOGGLE_WINDOW_SHADE_MODE, windowId: "playlist" }); } function windows_closeWindow(windowId) { return { type: CLOSE_WINDOW, windowId }; } function hideWindow(windowId) { return { type: SET_WINDOW_VISIBILITY, windowId, hidden: true }; } function showWindow(windowId) { return { type: SET_WINDOW_VISIBILITY, windowId, hidden: false }; } function windows_setFocusedWindow(window) { return { type: SET_FOCUSED_WINDOW, window }; } function windows_setWindowSize(windowId, size) { return { type: WINDOW_SIZE_CHANGED, windowId, size }; } function windows_toggleWindow(windowId) { return { type: TOGGLE_WINDOW, windowId }; } function windows_updateWindowPositions(positions, absolute) { return { type: UPDATE_WINDOW_POSITIONS, positions, absolute }; } function centerWindowsInContainer(container) { return (dispatch, getState) => { if (!getPositionsAreRelative(getState())) { return; } const { left, top } = container.getBoundingClientRect(); const { scrollWidth: width, scrollHeight: height } = container; dispatch(centerWindows({ left, top, width, height })); }; } function windows_centerWindowsInView() { return centerWindows({ left: window.scrollX, top: window.scrollY, width: window.innerWidth, height: window.innerHeight }); } function centerWindows(box) { return (dispatch, getState) => { const state = getState(); const windowsInfo = getWindowsInfo(state); const getOpen = selectors_getWindowOpen(state); const { top, left, width, height } = box; const offsetLeft = left + window.scrollX; const offsetTop = top + window.scrollY; // A layout has been suplied. We will compute the bounding box and // center the given layout. const bounding = calculateBoundingBox(windowsInfo.filter(w => getOpen(w.key))); if (bounding == null) { // There are no windows to center return; } const boxHeight = bounding.bottom - bounding.top; const boxWidth = bounding.right - bounding.left; const move = { x: Math.ceil(offsetLeft - bounding.left + (width - boxWidth) / 2), y: Math.ceil(offsetTop - bounding.top + (height - boxHeight) / 2) }; const newPositions = windowsInfo.reduce((pos, w) => actionCreators_windows_objectSpread(actionCreators_windows_objectSpread({}, pos), {}, { [w.key]: { x: move.x + w.x, y: move.y + w.y } }), {}); dispatch(windows_updateWindowPositions(newPositions, true)); }; } function windows_browserWindowSizeChanged(size) { return dispatch => { dispatch(actionCreators_windows_objectSpread({ type: BROWSER_WINDOW_SIZE_CHANGED }, size)); dispatch(ensureWindowsAreOnScreen()); }; } function resetWindowSizes() { return { type: RESET_WINDOW_SIZES }; } function stackWindows() { return (dispatch, getState) => { dispatch(windows_updateWindowPositions(getStackedLayoutPositions(getState()))); }; } function ensureWindowsAreOnScreen() { return (dispatch, getState) => { const state = getState(); const windowsInfo = getWindowsInfo(state); const getOpen = selectors_getWindowOpen(state); const { height, width } = getWindowSize(); const bounding = calculateBoundingBox(windowsInfo.filter(w => getOpen(w.key))); if (bounding == null) { // There are no windows visible, so there's no work to do. return; } const positions = getWindowPositions(state); // Are we good? if (bounding.left >= 0 && bounding.top >= 0 && bounding.right <= width && bounding.bottom <= height) { // My work here is done. return; } const boundingHeight = bounding.bottom - bounding.top; const boundingWidth = bounding.right - bounding.left; // Could we simply shift all the windows by a constant offset? if (boundingWidth <= width && boundingHeight <= height) { let moveY = 0; let moveX = 0; if (bounding.top <= 0) { moveY = bounding.top; } else if (bounding.bottom > height) { moveY = bounding.bottom - height; } if (bounding.left <= 0) { moveX = bounding.left; } else if (bounding.right > width) { moveX = bounding.right - width; } const newPositions = objectMap(positions, position => ({ x: position.x - moveX, y: position.y - moveY })); dispatch(windows_updateWindowPositions(newPositions)); return; } // TODO: Try moving the individual groups to try to fit them in // I give up. Just reset everything. dispatch(resetWindowSizes()); dispatch(stackWindows()); dispatch(windows_centerWindowsInView()); }; } ;// CONCATENATED MODULE: ./js/actionCreators/media.ts function playTrack(id) { return (dispatch, getState) => { const state = getState(); const isStopped = getMediaStatus(state) === MEDIA_STATUS.STOPPED; if (isStopped) { dispatch({ type: BUFFER_TRACK, id }); } else { dispatch({ type: PLAY_TRACK, id }); } }; } function media_playTrackNow(id) { return { type: PLAY_TRACK, id }; } function media_play() { return (dispatch, getState) => { const state = getState(); if (state.media.status === MEDIA_STATUS.STOPPED && state.playlist.currentTrack == null && state.playlist.trackOrder.length === 0) { dispatch(files_openMediaFileDialog()); } else { dispatch({ type: PLAY }); } }; } function media_pause() { return (dispatch, getState) => { const { status } = getState().media; if (status === MEDIA_STATUS.PLAYING) { dispatch({ type: PAUSE }); } else { dispatch({ type: PLAY }); } }; } function media_stop() { return { type: STOP }; } function media_nextN(n) { return (dispatch, getState) => { const nextTrackId = getNextTrackId(getState(), n); if (nextTrackId == null) { dispatch({ type: IS_STOPPED }); return; } dispatch(playTrack(nextTrackId)); }; } function media_next() { return media_nextN(1); } function media_previous() { return media_nextN(-1); } function seekToTime(seconds) { return function (dispatch, getState) { const state = getState(); const duration = getDuration(state); if (duration == null) { return; } dispatch({ type: SEEK_TO_PERCENT_COMPLETE, percent: seconds / duration * 100 }); }; } function media_seekForward(seconds) { return function (dispatch, getState) { const timeElapsed = getTimeElapsed(getState()); dispatch(seekToTime(timeElapsed + seconds)); }; } function media_seekBackward(seconds) { return media_seekForward(-seconds); } function media_setVolume(volume) { return { type: SET_VOLUME, volume: clamp(volume, 0, 100) }; } function adjustVolume(volumeDiff) { return (dispatch, getState) => { const currentVolume = getState().media.volume; return dispatch(media_setVolume(currentVolume + volumeDiff)); }; } function media_scrollVolume(e) { e.preventDefault(); return (dispatch, getState) => { const currentVolume = getState().media.volume; // Using pixels as percentage difference here is a bit arbirary, but... oh well. return dispatch(media_setVolume(currentVolume + e.deltaY)); }; } function media_setBalance(balance) { balance = clamp(balance, -100, 100); // The balance clips to the center if (Math.abs(balance) < 25) { balance = 0; } return { type: SET_BALANCE, balance }; } function media_toggleRepeat() { return { type: TOGGLE_REPEAT }; } function media_toggleShuffle() { return { type: TOGGLE_SHUFFLE }; } function media_toggleTimeMode() { return { type: TOGGLE_TIME_MODE }; } ;// CONCATENATED MODULE: ./js/actionCreators/equalizer.ts const BAND_SNAP_DISTANCE = 50; // 5 in old scale (0-100), now 50 in new scale (0-2400) to maintain same snap distance in dB const BAND_MID_POINT_VALUE = 1200; // 50 in old scale (0-100), now 1200 in new scale (0-2400) function _snapBandValue(value) { if (value < BAND_MID_POINT_VALUE + BAND_SNAP_DISTANCE && value > BAND_MID_POINT_VALUE - BAND_SNAP_DISTANCE) { return BAND_MID_POINT_VALUE; } // Round to nearest 0.1 dB step (value divisible by 1) return Math.round(value); } function setEqBand(band, value) { return { type: SET_BAND_VALUE, band, value: _snapBandValue(value) }; } function _setEqTo(value) { return dispatch => { Object.values(BANDS).forEach(band => { dispatch({ type: SET_BAND_VALUE, value, band: band }); }); }; } function equalizer_setEqToMax() { return _setEqTo(2400); } function equalizer_setEqToMid() { return _setEqTo(1200); } function equalizer_setEqToMin() { return _setEqTo(0); } function setPreamp(value) { return { type: SET_BAND_VALUE, band: "preamp", value: _snapBandValue(value) }; } function equalizer_toggleEq() { return (dispatch, getState) => { if (getState().equalizer.on) { dispatch({ type: SET_EQ_OFF }); } else { dispatch({ type: SET_EQ_ON }); } }; } function toggleEqAuto() { return dispatch => { // We don't actually support this feature yet so don't let the user ever turn it on. // dispatch({ type: SET_EQ_AUTO, value: !getState().equalizer.auto }); dispatch({ type: SET_EQ_AUTO, value: false }); }; } // EXTERNAL MODULE: ../../node_modules/winamp-eqf/index.js var winamp_eqf = __webpack_require__(2105); ;// CONCATENATED MODULE: ./js/skinSprites.ts /* TODO: There are too many " " and "_" characters */ const FONT_LOOKUP = { a: [0, 0], b: [0, 1], c: [0, 2], d: [0, 3], e: [0, 4], f: [0, 5], g: [0, 6], h: [0, 7], i: [0, 8], j: [0, 9], k: [0, 10], l: [0, 11], m: [0, 12], n: [0, 13], o: [0, 14], p: [0, 15], q: [0, 16], r: [0, 17], s: [0, 18], t: [0, 19], u: [0, 20], v: [0, 21], w: [0, 22], x: [0, 23], y: [0, 24], z: [0, 25], '"': [0, 26], "@": [0, 27], " ": [0, 30], "0": [1, 0], "1": [1, 1], "2": [1, 2], "3": [1, 3], "4": [1, 4], "5": [1, 5], "6": [1, 6], "7": [1, 7], "8": [1, 8], "9": [1, 9], [UTF8_ELLIPSIS]: [1, 10], ".": [1, 11], ":": [1, 12], "(": [1, 13], ")": [1, 14], "-": [1, 15], "'": [1, 16], "!": [1, 17], _: [1, 18], "+": [1, 19], "\\": [1, 20], "/": [1, 21], "[": [1, 22], "]": [1, 23], "^": [1, 24], "&": [1, 25], "%": [1, 26], ",": [1, 27], "=": [1, 28], $: [1, 29], "#": [1, 30], Å: [2, 0], Ö: [2, 1], Ä: [2, 2], "?": [2, 3], "*": [2, 4], "<": [1, 22], ">": [1, 23], "{": [1, 22], "}": [1, 23] }; const imageConstFromChar = char => `CHARACTER_${char.charCodeAt(0)}`; const CHAR_X = 5; const CHAR_Y = 6; const characterSprites = []; for (const key in FONT_LOOKUP) { if (FONT_LOOKUP.hasOwnProperty(key)) { const position = FONT_LOOKUP[key]; characterSprites.push({ name: imageConstFromChar(key), y: position[0] * CHAR_Y, x: position[1] * CHAR_X, width: CHAR_X, height: CHAR_Y }); } } const sprites = { BALANCE: [{ name: "MAIN_BALANCE_BACKGROUND", x: 9, y: 0, width: 38, height: 420 }, { name: "MAIN_BALANCE_THUMB", x: 15, y: 422, width: 14, height: 11 }, { name: "MAIN_BALANCE_THUMB_ACTIVE", x: 0, y: 422, width: 14, height: 11 }], CBUTTONS: [{ name: "MAIN_PREVIOUS_BUTTON", x: 0, y: 0, width: 23, height: 18 }, { name: "MAIN_PREVIOUS_BUTTON_ACTIVE", x: 0, y: 18, width: 23, height: 18 }, { name: "MAIN_PLAY_BUTTON", x: 23, y: 0, width: 23, height: 18 }, { name: "MAIN_PLAY_BUTTON_ACTIVE", x: 23, y: 18, width: 23, height: 18 }, { name: "MAIN_PAUSE_BUTTON", x: 46, y: 0, width: 23, height: 18 }, { name: "MAIN_PAUSE_BUTTON_ACTIVE", x: 46, y: 18, width: 23, height: 18 }, { name: "MAIN_STOP_BUTTON", x: 69, y: 0, width: 23, height: 18 }, { name: "MAIN_STOP_BUTTON_ACTIVE", x: 69, y: 18, width: 23, height: 18 }, { name: "MAIN_NEXT_BUTTON", x: 92, y: 0, width: 23, height: 18 }, { name: "MAIN_NEXT_BUTTON_ACTIVE", x: 92, y: 18, width: 22, height: 18 }, { name: "MAIN_EJECT_BUTTON", x: 114, y: 0, width: 22, height: 16 }, { name: "MAIN_EJECT_BUTTON_ACTIVE", x: 114, y: 16, width: 22, height: 16 }], MAIN: [{ name: "MAIN_WINDOW_BACKGROUND", x: 0, y: 0, width: 275, height: 116 }], MONOSTER: [{ name: "MAIN_STEREO", x: 0, y: 12, width: 29, height: 12 }, { name: "MAIN_STEREO_SELECTED", x: 0, y: 0, width: 29, height: 12 }, { name: "MAIN_MONO", x: 29, y: 12, width: 27, height: 12 }, { name: "MAIN_MONO_SELECTED", x: 29, y: 0, width: 27, height: 12 }], NUMBERS: [{ name: "NO_MINUS_SIGN", x: 9, y: 6, width: 5, height: 1 }, { name: "MINUS_SIGN", x: 20, y: 6, width: 5, height: 1 }, { name: "DIGIT_0", x: 0, y: 0, width: 9, height: 13 }, { name: "DIGIT_1", x: 9, y: 0, width: 9, height: 13 }, { name: "DIGIT_2", x: 18, y: 0, width: 9, height: 13 }, { name: "DIGIT_3", x: 27, y: 0, width: 9, height: 13 }, { name: "DIGIT_4", x: 36, y: 0, width: 9, height: 13 }, { name: "DIGIT_5", x: 45, y: 0, width: 9, height: 13 }, { name: "DIGIT_6", x: 54, y: 0, width: 9, height: 13 }, { name: "DIGIT_7", x: 63, y: 0, width: 9, height: 13 }, { name: "DIGIT_8", x: 72, y: 0, width: 9, height: 13 }, { name: "DIGIT_9", x: 81, y: 0, width: 9, height: 13 }], NUMS_EX: [{ name: "NO_MINUS_SIGN_EX", x: 90, y: 0, width: 9, height: 13 }, { name: "MINUS_SIGN_EX", x: 99, y: 0, width: 9, height: 13 }, { name: "DIGIT_0_EX", x: 0, y: 0, width: 9, height: 13 }, { name: "DIGIT_1_EX", x: 9, y: 0, width: 9, height: 13 }, { name: "DIGIT_2_EX", x: 18, y: 0, width: 9, height: 13 }, { name: "DIGIT_3_EX", x: 27, y: 0, width: 9, height: 13 }, { name: "DIGIT_4_EX", x: 36, y: 0, width: 9, height: 13 }, { name: "DIGIT_5_EX", x: 45, y: 0, width: 9, height: 13 }, { name: "DIGIT_6_EX", x: 54, y: 0, width: 9, height: 13 }, { name: "DIGIT_7_EX", x: 63, y: 0, width: 9, height: 13 }, { name: "DIGIT_8_EX", x: 72, y: 0, width: 9, height: 13 }, { name: "DIGIT_9_EX", x: 81, y: 0, width: 9, height: 13 }], PLAYPAUS: [{ name: "MAIN_PLAYING_INDICATOR", x: 0, y: 0, width: 9, height: 9 }, { name: "MAIN_PAUSED_INDICATOR", x: 9, y: 0, width: 9, height: 9 }, { name: "MAIN_STOPPED_INDICATOR", x: 18, y: 0, width: 9, height: 9 }, { name: "MAIN_NOT_WORKING_INDICATOR", x: 36, y: 0, width: 9, height: 9 }, { name: "MAIN_WORKING_INDICATOR", x: 39, y: 0, width: 9, height: 9 }], PLEDIT: [{ name: "PLAYLIST_TOP_TILE", x: 127, y: 21, width: 25, height: 20 }, { name: "PLAYLIST_TOP_LEFT_CORNER", x: 0, y: 21, width: 25, height: 20 }, { name: "PLAYLIST_TITLE_BAR", x: 26, y: 21, width: 100, height: 20 }, { name: "PLAYLIST_TOP_RIGHT_CORNER", x: 153, y: 21, width: 25, height: 20 }, { name: "PLAYLIST_TOP_TILE_SELECTED", x: 127, y: 0, width: 25, height: 20 }, { name: "PLAYLIST_TOP_LEFT_SELECTED", x: 0, y: 0, width: 25, height: 20 }, { name: "PLAYLIST_TITLE_BAR_SELECTED", x: 26, y: 0, width: 100, height: 20 }, { name: "PLAYLIST_TOP_RIGHT_CORNER_SELECTED", x: 153, y: 0, width: 25, height: 20 }, { name: "PLAYLIST_LEFT_TILE", x: 0, y: 42, width: 12, height: 29 }, { name: "PLAYLIST_RIGHT_TILE", x: 31, y: 42, width: 20, height: 29 }, { name: "PLAYLIST_BOTTOM_TILE", x: 179, y: 0, width: 25, height: 38 }, { name: "PLAYLIST_BOTTOM_LEFT_CORNER", x: 0, y: 72, width: 125, height: 38 }, { name: "PLAYLIST_BOTTOM_RIGHT_CORNER", x: 126, y: 72, width: 150, height: 38 }, { name: "PLAYLIST_VISUALIZER_BACKGROUND", x: 205, y: 0, width: 75, height: 38 }, { name: "PLAYLIST_SHADE_BACKGROUND", x: 72, y: 57, width: 25, height: 14 }, { name: "PLAYLIST_SHADE_BACKGROUND_LEFT", x: 72, y: 42, width: 25, height: 14 }, { name: "PLAYLIST_SHADE_BACKGROUND_RIGHT", x: 99, y: 57, width: 50, height: 14 }, { name: "PLAYLIST_SHADE_BACKGROUND_RIGHT_SELECTED", x: 99, y: 42, width: 50, height: 14 }, { name: "PLAYLIST_SCROLL_HANDLE_SELECTED", x: 61, y: 53, width: 8, height: 18 }, { name: "PLAYLIST_SCROLL_HANDLE", x: 52, y: 53, width: 8, height: 18 }, { name: "PLAYLIST_ADD_URL", x: 0, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_ADD_URL_SELECTED", x: 23, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_ADD_DIR", x: 0, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_ADD_DIR_SELECTED", x: 23, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_ADD_FILE", x: 0, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_ADD_FILE_SELECTED", x: 23, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_REMOVE_ALL", x: 54, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_REMOVE_ALL_SELECTED", x: 77, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_CROP", x: 54, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_CROP_SELECTED", x: 77, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_REMOVE_SELECTED", x: 54, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_REMOVE_SELECTED_SELECTED", x: 77, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_REMOVE_MISC", x: 54, y: 168, width: 22, height: 18 }, { name: "PLAYLIST_REMOVE_MISC_SELECTED", x: 77, y: 168, width: 22, height: 18 }, { name: "PLAYLIST_INVERT_SELECTION", x: 104, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_INVERT_SELECTION_SELECTED", x: 127, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_SELECT_ZERO", x: 104, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_SELECT_ZERO_SELECTED", x: 127, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_SELECT_ALL", x: 104, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_SELECT_ALL_SELECTED", x: 127, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_SORT_LIST", x: 154, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_SORT_LIST_SELECTED", x: 177, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_FILE_INFO", x: 154, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_FILE_INFO_SELECTED", x: 177, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_MISC_OPTIONS", x: 154, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_MISC_OPTIONS_SELECTED", x: 177, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_NEW_LIST", x: 204, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_NEW_LIST_SELECTED", x: 227, y: 111, width: 22, height: 18 }, { name: "PLAYLIST_SAVE_LIST", x: 204, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_SAVE_LIST_SELECTED", x: 227, y: 130, width: 22, height: 18 }, { name: "PLAYLIST_LOAD_LIST", x: 204, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_LOAD_LIST_SELECTED", x: 227, y: 149, width: 22, height: 18 }, { name: "PLAYLIST_ADD_MENU_BAR", x: 48, y: 111, width: 3, height: 54 }, { name: "PLAYLIST_REMOVE_MENU_BAR", x: 100, y: 111, width: 3, height: 72 }, { name: "PLAYLIST_SELECT_MENU_BAR", x: 150, y: 111, width: 3, height: 54 }, { name: "PLAYLIST_MISC_MENU_BAR", x: 200, y: 111, width: 3, height: 54 }, { name: "PLAYLIST_LIST_BAR", x: 250, y: 111, width: 3, height: 54 }, { name: "PLAYLIST_CLOSE_SELECTED", x: 52, y: 42, width: 9, height: 9 }, { name: "PLAYLIST_COLLAPSE_SELECTED", x: 62, y: 42, width: 9, height: 9 }, { name: "PLAYLIST_EXPAND_SELECTED", x: 150, y: 42, width: 9, height: 9 }], EQ_EX: [{ name: "EQ_SHADE_BACKGROUND_SELECTED", x: 0, y: 0, width: 275, height: 14 }, { name: "EQ_SHADE_BACKGROUND", x: 0, y: 15, width: 275, height: 14 }, { name: "EQ_SHADE_VOLUME_SLIDER_LEFT", x: 1, y: 30, width: 3, height: 7 }, { name: "EQ_SHADE_VOLUME_SLIDER_CENTER", x: 4, y: 30, width: 3, height: 7 }, { name: "EQ_SHADE_VOLUME_SLIDER_RIGHT", x: 7, y: 30, width: 3, height: 7 }, { name: "EQ_SHADE_BALANCE_SLIDER_LEFT", x: 11, y: 30, width: 3, height: 7 }, { name: "EQ_SHADE_BALANCE_SLIDER_CENTER", x: 14, y: 30, width: 3, height: 7 }, { name: "EQ_SHADE_BALANCE_SLIDER_RIGHT", x: 17, y: 30, width: 3, height: 7 }, { name: "EQ_MAXIMIZE_BUTTON_ACTIVE", x: 1, y: 38, width: 9, height: 9 }, { name: "EQ_MINIMIZE_BUTTON_ACTIVE", x: 1, y: 47, width: 9, height: 9 }, { name: "EQ_SHADE_CLOSE_BUTTON", x: 11, y: 38, width: 9, height: 9 }, { name: "EQ_SHADE_CLOSE_BUTTON_ACTIVE", x: 11, y: 47, width: 9, height: 9 }], EQMAIN: [{ name: "EQ_WINDOW_BACKGROUND", x: 0, y: 0, width: 275, height: 116 }, { name: "EQ_TITLE_BAR", x: 0, y: 149, width: 275, height: 14 }, { name: "EQ_TITLE_BAR_SELECTED", x: 0, y: 134, width: 275, height: 14 }, { name: "EQ_SLIDER_BACKGROUND", x: 13, y: 164, width: 209, height: 129 }, { name: "EQ_SLIDER_THUMB", x: 0, y: 164, width: 11, height: 11 }, { name: "EQ_SLIDER_THUMB_SELECTED", x: 0, y: 176, width: 11, height: 11 }, { name: "EQ_CLOSE_BUTTON", x: 0, y: 116, width: 9, height: 9 }, { name: "EQ_CLOSE_BUTTON_ACTIVE", x: 0, y: 125, width: 9, height: 9 }, // This is technically not a sprite, it's just part of the background. // However, we extract it to use it as a fallback for // `EQ_MAXIMIZE_BUTTON_ACTIVE`. Without this, skins that don't implement // `eq_ex.bmp` would show the default skin's `EQ_MAXIMIZE_BUTTON_ACTIVE` // instead of showing no sprite aka, just showing through to this portion of // the title bar image. { name: "EQ_MAXIMIZE_BUTTON_ACTIVE_FALLBACK", x: 254, y: 152, width: 9, height: 9 }, { name: "EQ_ON_BUTTON", x: 10, y: 119, width: 26, height: 12 }, { name: "EQ_ON_BUTTON_DEPRESSED", x: 128, y: 119, width: 26, height: 12 }, { name: "EQ_ON_BUTTON_SELECTED", x: 69, y: 119, width: 26, height: 12 }, { name: "EQ_ON_BUTTON_SELECTED_DEPRESSED", x: 187, y: 119, width: 26, height: 12 }, { name: "EQ_AUTO_BUTTON", x: 36, y: 119, width: 32, height: 12 }, { name: "EQ_AUTO_BUTTON_DEPRESSED", x: 154, y: 119, width: 32, height: 12 }, { name: "EQ_AUTO_BUTTON_SELECTED", x: 95, y: 119, width: 32, height: 12 }, { name: "EQ_AUTO_BUTTON_SELECTED_DEPRESSED", x: 213, y: 119, width: 32, height: 12 }, { name: "EQ_GRAPH_BACKGROUND", x: 0, y: 294, width: 113, height: 19 }, { name: "EQ_GRAPH_LINE_COLORS", x: 115, y: 294, width: 1, height: 19 }, { name: "EQ_PRESETS_BUTTON", x: 224, y: 164, width: 44, height: 12 }, { name: "EQ_PRESETS_BUTTON_SELECTED", x: 224, y: 176, width: 44, height: 12 }, { name: "EQ_PREAMP_LINE", x: 0, y: 314, width: 113, height: 1 }], POSBAR: [{ name: "MAIN_POSITION_SLIDER_BACKGROUND", x: 0, y: 0, width: 248, height: 10 }, { name: "MAIN_POSITION_SLIDER_THUMB", x: 248, y: 0, width: 29, height: 10 }, { name: "MAIN_POSITION_SLIDER_THUMB_SELECTED", x: 278, y: 0, width: 29, height: 10 }], SHUFREP: [{ name: "MAIN_SHUFFLE_BUTTON", x: 28, y: 0, width: 47, height: 15 }, { name: "MAIN_SHUFFLE_BUTTON_DEPRESSED", x: 28, y: 15, width: 47, height: 15 }, { name: "MAIN_SHUFFLE_BUTTON_SELECTED", x: 28, y: 30, width: 47, height: 15 }, { name: "MAIN_SHUFFLE_BUTTON_SELECTED_DEPRESSED", x: 28, y: 45, width: 47, height: 15 }, { name: "MAIN_REPEAT_BUTTON", x: 0, y: 0, width: 28, height: 15 }, { name: "MAIN_REPEAT_BUTTON_DEPRESSED", x: 0, y: 15, width: 28, height: 15 }, { name: "MAIN_REPEAT_BUTTON_SELECTED", x: 0, y: 30, width: 28, height: 15 }, { name: "MAIN_REPEAT_BUTTON_SELECTED_DEPRESSED", x: 0, y: 45, width: 28, height: 15 }, { name: "MAIN_EQ_BUTTON", x: 0, y: 61, width: 23, height: 12 }, { name: "MAIN_EQ_BUTTON_SELECTED", x: 0, y: 73, width: 23, height: 12 }, { name: "MAIN_EQ_BUTTON_DEPRESSED", x: 46, y: 61, width: 23, height: 12 }, { name: "MAIN_EQ_BUTTON_DEPRESSED_SELECTED", x: 46, y: 73, width: 23, height: 12 }, { name: "MAIN_PLAYLIST_BUTTON", x: 23, y: 61, width: 23, height: 12 }, { name: "MAIN_PLAYLIST_BUTTON_SELECTED", x: 23, y: 73, width: 23, height: 12 }, { name: "MAIN_PLAYLIST_BUTTON_DEPRESSED", x: 69, y: 61, width: 23, height: 12 }, { name: "MAIN_PLAYLIST_BUTTON_DEPRESSED_SELECTED", x: 69, y: 73, width: 23, height: 12 }], TEXT: characterSprites, TITLEBAR: [{ name: "MAIN_TITLE_BAR", x: 27, y: 15, width: 275, height: 14 }, { name: "MAIN_TITLE_BAR_SELECTED", x: 27, y: 0, width: 275, height: 14 }, { name: "MAIN_EASTER_EGG_TITLE_BAR", x: 27, y: 72, width: 275, height: 14 }, { name: "MAIN_EASTER_EGG_TITLE_BAR_SELECTED", x: 27, y: 57, width: 275, height: 14 }, { name: "MAIN_OPTIONS_BUTTON", x: 0, y: 0, width: 9, height: 9 }, { name: "MAIN_OPTIONS_BUTTON_DEPRESSED", x: 0, y: 9, width: 9, height: 9 }, { name: "MAIN_MINIMIZE_BUTTON", x: 9, y: 0, width: 9, height: 9 }, { name: "MAIN_MINIMIZE_BUTTON_DEPRESSED", x: 9, y: 9, width: 9, height: 9 }, { name: "MAIN_SHADE_BUTTON", x: 0, y: 18, width: 9, height: 9 }, { name: "MAIN_SHADE_BUTTON_DEPRESSED", x: 9, y: 18, width: 9, height: 9 }, { name: "MAIN_CLOSE_BUTTON", x: 18, y: 0, width: 9, height: 9 }, { name: "MAIN_CLOSE_BUTTON_DEPRESSED", x: 18, y: 9, width: 9, height: 9 }, { name: "MAIN_CLUTTER_BAR_BACKGROUND", x: 304, y: 0, width: 8, height: 43 }, { name: "MAIN_CLUTTER_BAR_BACKGROUND_DISABLED", x: 312, y: 0, width: 8, height: 43 }, { name: "MAIN_CLUTTER_BAR_BUTTON_O_SELECTED", x: 304, y: 47, width: 8, height: 8 }, { name: "MAIN_CLUTTER_BAR_BUTTON_A_SELECTED", x: 312, y: 55, width: 8, height: 7 }, { name: "MAIN_CLUTTER_BAR_BUTTON_I_SELECTED", x: 320, y: 62, width: 8, height: 7 }, { name: "MAIN_CLUTTER_BAR_BUTTON_D_SELECTED", x: 328, y: 69, width: 8, height: 8 }, { name: "MAIN_CLUTTER_BAR_BUTTON_V_SELECTED", x: 336, y: 77, width: 8, height: 7 }, { name: "MAIN_SHADE_BACKGROUND", x: 27, y: 42, width: 275, height: 14 }, { name: "MAIN_SHADE_BACKGROUND_SELECTED", x: 27, y: 29, width: 275, height: 14 }, { name: "MAIN_SHADE_BUTTON_SELECTED", x: 0, y: 27, width: 9, height: 9 }, { name: "MAIN_SHADE_BUTTON_SELECTED_DEPRESSED", x: 9, y: 27, width: 9, height: 9 }, { name: "MAIN_SHADE_POSITION_BACKGROUND", x: 0, y: 36, width: 17, height: 7 }, { name: "MAIN_SHADE_POSITION_THUMB", x: 20, y: 36, width: 3, height: 7 }, { name: "MAIN_SHADE_POSITION_THUMB_LEFT", x: 17, y: 36, width: 3, height: 7 }, { name: "MAIN_SHADE_POSITION_THUMB_RIGHT", x: 23, y: 36, width: 3, height: 7 }], VOLUME: [{ name: "MAIN_VOLUME_BACKGROUND", x: 0, y: 0, width: 68, height: 420 }, { name: "MAIN_VOLUME_THUMB", x: 15, y: 422, width: 14, height: 11 }, { name: "MAIN_VOLUME_THUMB_SELECTED", x: 0, y: 422, width: 14, height: 11 }], GEN: [{ name: "GEN_TOP_LEFT_SELECTED", x: 0, y: 0, width: 25, height: 20 }, { name: "GEN_TOP_LEFT_END_SELECTED", x: 26, y: 0, width: 25, height: 20 }, { name: "GEN_TOP_CENTER_FILL_SELECTED", x: 52, y: 0, width: 25, height: 20 }, { name: "GEN_TOP_RIGHT_END_SELECTED", x: 78, y: 0, width: 25, height: 20 }, { name: "GEN_TOP_LEFT_RIGHT_FILL_SELECTED", x: 104, y: 0, width: 25, height: 20 }, { name: "GEN_TOP_RIGHT_SELECTED", x: 130, y: 0, width: 25, height: 20 }, { name: "GEN_TOP_LEFT", x: 0, y: 21, width: 25, height: 20 }, { name: "GEN_TOP_LEFT_END", x: 26, y: 21, width: 25, height: 20 }, { name: "GEN_TOP_CENTER_FILL", x: 52, y: 21, width: 25, height: 20 }, { name: "GEN_TOP_RIGHT_END", x: 78, y: 21, width: 25, height: 20 }, { name: "GEN_TOP_LEFT_RIGHT_FILL", x: 104, y: 21, width: 25, height: 20 }, { name: "GEN_TOP_RIGHT", x: 130, y: 21, width: 25, height: 20 }, { name: "GEN_BOTTOM_LEFT", x: 0, y: 42, width: 125, height: 14 }, { name: "GEN_BOTTOM_RIGHT", x: 0, y: 57, width: 125, height: 14 }, { name: "GEN_BOTTOM_FILL", x: 127, y: 72, width: 25, height: 14 }, { name: "GEN_MIDDLE_LEFT", x: 127, y: 42, width: 11, height: 29 }, { name: "GEN_MIDDLE_LEFT_BOTTOM", x: 158, y: 42, width: 11, height: 24 }, { name: "GEN_MIDDLE_RIGHT", x: 139, y: 42, width: 8, height: 29 }, { name: "GEN_MIDDLE_RIGHT_BOTTOM", x: 170, y: 42, width: 8, height: 24 }, { name: "GEN_CLOSE_SELECTED", x: 148, y: 42, width: 9, height: 9 }] /* We don't currently support the Media Library, so there are disabled GENEX: [ { name: "GENEX_BUTTON_BACKGROUND_LEFT_UNPRESSED", x: 0, y: 0, height: 15, width: 4, }, { name: "GENEX_BUTTON_BACKGROUND_CENTER_UNPRESSED", x: 4, y: 0, height: 15, width: 39, }, { name: "GENEX_BUTTON_BACKGROUND_RIGHT_UNPRESSED", x: 43, y: 0, height: 15, width: 4, }, { name: "GENEX_BUTTON_BACKGROUND_PRESSED", x: 0, y: 1, height: 15, width: 47, }, { name: "GENEX_SCROLL_UP_UNPRESSED", x: 0, y: 31, height: 14, width: 14 }, { name: "GENEX_SCROLL_DOWN_UNPRESSED", x: 14, y: 31, height: 14, width: 14, }, { name: "GENEX_SCROLL_UP_PRESSED", x: 28, y: 31, height: 14, width: 14 }, { name: "GENEX_SCROLL_DOWN_PRESSED", x: 42, y: 31, height: 14, width: 14 }, { name: "GENEX_SCROLL_LEFT_UNPRESSED", x: 0, y: 45, height: 14, width: 14 }, { name: "GENEX_SCROLL_RIGHT_UNPRESSED", x: 14, y: 45, height: 14, width: 14, }, { name: "GENEX_SCROLL_LEFT_PRESSED", x: 28, y: 45, height: 14, width: 14 }, { name: "GENEX_SCROLL_RIGHT_PRESSED", x: 42, y: 45, height: 14, width: 14 }, { name: "GENEX_VERTICAL_SCROLL_HANDLE_UNPRESSED", x: 56, y: 31, height: 28, width: 14, }, { name: "GENEX_VERTICAL_SCROLL_HANDLE_PRESSED", x: 70, y: 31, height: 28, width: 14, }, { name: "GENEX_HORIZONTAL_SCROLL_HANDLE_UNPRESSED", x: 84, y: 31, height: 14, width: 28, }, { name: "GENEX_HORIZONTAL_SCROLL_HANDLE_PRESSED", x: 84, y: 45, height: 14, width: 28, }, ], */ }; /* harmony default export */ const skinSprites = (sprites); ;// CONCATENATED MODULE: ./js/regionParser.ts function pointPairs(arr) { const pairedValues = []; for (let i = 0; i < arr.length; i += 2) { pairedValues.push(`${arr[i]},${arr[i + 1]}`); } return pairedValues; } function regionParser(regionStr) { const iniData = parseIni(regionStr); const data = {}; Object.keys(iniData).forEach(section => { const { numpoints, pointlist } = iniData[section]; if (!numpoints || !pointlist) { return; } const pointCounts = numpoints.split(/\s*,\s*/).filter(val => val !== ""); const points = pointPairs( // points can be separated by spaces, or by commas pointlist.split(/\s*[, ]\s*/).filter(val => val !== "")); let pointIndex = 0; const polygons = pointCounts.map(numStr => { const num = Number(numStr); if (num < 3) { // What use is a polygon with less than three sides? pointIndex += num; return null; } const polygon = points.slice(pointIndex, pointIndex + num).join(" "); if (!polygon.length) { // It's possible that the skin author specified more polygons than provided points. return null; } pointIndex += num; return polygon; }); const validPolygons = polygons.filter(polygon => polygon != null); if (validPolygons.length) { data[section] = validPolygons; } }); return data; } ;// CONCATENATED MODULE: ./js/skinParserUtils.ts function skinParserUtils_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function skinParserUtils_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? skinParserUtils_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : skinParserUtils_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const getFileExtension = fileName => { const matches = /\.([a-z]{3,4})$/i.exec(fileName); return matches ? matches[1].toLowerCase() : null; }; function getFilenameRegex(base, ext) { return new RegExp(`^(.*/)?${base}.(${ext})$`, "i"); } async function getFileFromZip(zip, fileName, ext, mode) { const files = zip.file(getFilenameRegex(fileName, ext)); if (!files.length) { return null; } // Windows file system is case insensitve, but zip files are not. // This means that it's possible for a zip to contain both `main.bmp` _and_ // `main.BMP` but in Winamp only one will be materialized onto disk when // decompressing. I suspect that in this case later files in the archive // overwrite earlier ones. To mimic that behavior we use the last matching // file. // // This works because `JSZip.file` filters the files by iterating the // underlying `files` object under the hood: // https://github.com/Stuk/jszip/blob/25d401e104926fef8528d670ecfe53f14e77a297/lib/object.js#L182 // Since JavaScript objects are iterable in the order that the keys were // added this _should_ mean that by taking the last file here we will get // the last file that JSZip extracted. const lastFile = files[files.length - 1]; try { const contents = await lastFile.async(mode); return { contents, name: lastFile.name }; } catch (e) { console.warn(`Failed to extract "${fileName}.${ext}" from the skin archive.`); return null; } } function fallbackGetImgFromBlob(blob) { return imgFromUrl(URL.createObjectURL(blob)); } async function getImgFromBlob(blob) { try { // Use this faster native browser API if available. // NOTE: In some browsers `window.createImageBitmap` may not exist so this will throw. return await window.createImageBitmap(blob); } catch (e) { try { return await fallbackGetImgFromBlob(blob); } catch (ee) { // Like Winamp we will silently fail on images that don't parse. return null; } } } function getSpriteUrisFromImg(img, sprites) { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); if (context == null) { throw new Error("Failed to get canvas context"); } const images = {}; sprites.forEach(sprite => { canvas.height = sprite.height; canvas.width = sprite.width; context.drawImage(img, -sprite.x, -sprite.y); const image = canvas.toDataURL(); images[sprite.name] = image; }); return images; } async function getImgFromFilename(zip, fileName) { // Winamp only supports .bmp images, but WACUP set a precidence of supporting // .png as well to reduce size. Since we care about size as well, we follow // suit. Our default skin uses .png to save 14kb. const file = await getFileFromZip(zip, fileName, "(png|bmp)", "blob"); if (!file) { return null; } const mimeType = `image/${getFileExtension(file.name) || "*"}`; // The spec for createImageBitmap() says the browser should try to sniff the // mime type, but it looks like Firefox does not. So we specify it here // explicitly. const typedBlob = new Blob([file.contents], { type: mimeType }); return getImgFromBlob(typedBlob); } async function getSpriteUrisFromFilename(zip, fileName) { const img = await getImgFromFilename(zip, fileName); if (img == null) { return {}; } return getSpriteUrisFromImg(img, skinSprites[fileName]); } // https://docs.microsoft.com/en-us/windows/win32/xaudio2/resource-interchange-file-format--riff- const RIFF_MAGIC = "RIFF".split("").map(c => c.charCodeAt(0)); function arrayStartsWith(arr, matcher) { return matcher.every((item, i) => arr[i] === item); } async function getCursorFromFilename(zip, fileName) { const file = await getFileFromZip(zip, fileName, "CUR", "uint8array"); if (file == null) { return null; } const contents = file.contents; if (arrayStartsWith(contents, RIFF_MAGIC)) { try { return { type: "ani", aniData: contents }; } catch (e) { console.error(e); return null; } } return { type: "cur", url: curUrlFromByteArray(contents) }; } async function getPlaylistStyle(zip) { const files = zip.file(getFilenameRegex("PLEDIT", "txt")); const file = files[0]; if (file == null) { return DEFAULT_SKIN.playlistStyle; } const ini = await file.async("text"); if (ini == null) { return DEFAULT_SKIN.playlistStyle; } const data = ini && parseIni(ini).text; if (!data) { // Corrupt or missing PLEDIT.txt file. return DEFAULT_SKIN.playlistStyle; } // Winamp seems to permit colors that contain too many characters. // For compatibility with existing skins, we normalize them here. ["normal", "current", "normalbg", "selectedbg", "mbFG", "mbBG"].forEach(colorKey => { let color = data[colorKey]; if (!color) { return; } if (color[0] !== "#") { color = `#${color}`; } data[colorKey] = color.slice(0, 7); }); return skinParserUtils_objectSpread(skinParserUtils_objectSpread({}, DEFAULT_SKIN.playlistStyle), data); } async function getGenExColors(zip) { const img = await getImgFromFilename(zip, "GENEX"); if (img == null) { return null; } const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); if (context == null) { return null; } canvas.width = img.width; canvas.height = img.height; context.drawImage(img, 0, 0); const getColorAt = x => `rgb(${context.getImageData(x, 0, 1, 1) // Discard the alpha channel .data.slice(0, 3).join(",")})`; // Ideally we would just have a map from key to the x value and map over // that with getColorAt, but I don't know a great way to make that type // safe. So, we'll just do this for now, where we explicitly call getColorAt // for each key. return { // (1) x=48: item background (background to edits, listviews, etc.) itemBackground: getColorAt(48), // (2) x=50: item foreground (text colour of edits, listviews, etc.) itemForeground: getColorAt(50), // (3) x=52: window background (used to set the bg color for the dialog) windowBackground: getColorAt(52), // (4) x=54: button text colour buttonText: getColorAt(54), // (5) x=56: window text colour windowText: getColorAt(56), // (6) x=58: colour of dividers and sunken borders divider: getColorAt(58), // (7) x=60: selection colour for entries inside playlists (nothing else yet) playlistSelection: getColorAt(60), // (8) x=62: listview header background colour listHeaderBackground: getColorAt(62), // (9) x=64: listview header text colour listHeaderText: getColorAt(64), // (10) x=66: listview header frame top and left colour listHeaderFrameTopAndLeft: getColorAt(66), // (11) x=68: listview header frame bottom and right colour listHeaderFrameBottomAndRight: getColorAt(68), // (12) x=70: listview header frame colour, when pressed listHeaderFramePressed: getColorAt(70), // (13) x=72: listview header dead area colour listHeaderDeadArea: getColorAt(72), // (14) x=74: scrollbar colour #1 scrollbarOne: getColorAt(74), // (15) x=76: scrollbar colour #2 scrollbarTwo: getColorAt(76), // (16) x=78: pressed scrollbar colour #1 pressedScrollbarOne: getColorAt(78), // (17) x=80: pressed scrollbar colour #2 pressedScrollbarTwo: getColorAt(80), // (18) x=82: scrollbar dead area colour scrollbarDeadArea: getColorAt(82), // (19) x=84 List view text colour highlighted listTextHighlighted: getColorAt(84), // (20) x=86 List view background colour highlighted listTextHighlightedBackground: getColorAt(86), // (21) x=88 List view text colour selected listTextSelected: getColorAt(88), // (22) x=90 List view background colour selected listTextSelectedBackground: getColorAt(90) }; } ;// CONCATENATED MODULE: ./js/skinParser.js function skinParser_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function skinParser_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? skinParser_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : skinParser_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const shallowMerge = objs => objs.reduce((prev, img) => Object.assign(prev, img), {}); const CURSORS = ["CLOSE", "EQCLOSE", "EQNORMAL", "EQSLID", "EQTITLE", "MAINMENU", "MMENU", "MIN", "NORMAL", "PCLOSE", "PNORMAL", "POSBAR", "PSIZE", "PTBAR", "PVSCROLL", "PWINBUT", "PWSNORM", "PWSSIZE", "SONGNAME", "TITLEBAR", "VOLBAL", "WINBUT", "WSNORMAL", "WSPOSBAR" /* * > There are usually 4 more cursors in the skins: volbar.cur, wsclose.cur, * > wswinbut.cur, wsmin.cur, but they are never used, at least in the last * > versions of winamp, so there's no need of including them. The cursors * > shown when the mouse is over the app-buttons are the same in normal and * > winshade mode, except for the main menu button. You can make animated * > cursors, but you have to name them with the extension .cur (animated * > cursors are usually .ani files). * * -- Skinners Atlas * * "VOLBAR", * "WSCLOSE", * "WSWINBUT", * "WSMIN", * */]; async function genVizColors(zip) { const viscolor = await getFileFromZip(zip, "VISCOLOR", "txt", "text"); return viscolor ? parseViscolors(viscolor.contents) : DEFAULT_SKIN.colors; } async function genImages(zip) { const imageObjs = await Promise.all(Object.keys(skinSprites).map(fileName => getSpriteUrisFromFilename(zip, fileName))); // Merge all the objects into a single object. Tests assert that sprite keys are unique. return shallowMerge(imageObjs); } async function genCursors(zip) { const cursorObjs = await Promise.all(CURSORS.map(async cursorName => ({ [cursorName]: await getCursorFromFilename(zip, cursorName) }))); return shallowMerge(cursorObjs); } async function genRegion(zip) { const region = await getFileFromZip(zip, "REGION", "txt", "text"); return region ? regionParser(region.contents) : {}; } async function genGenTextSprites(zip) { const img = await getImgFromFilename(zip, "GEN"); if (img == null) { return null; } const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); canvas.width = img.width; canvas.height = img.height; context.drawImage(img, 0, 0); const getLetters = (y, prefix) => { const getColorAt = x => context.getImageData(x, y, 1, 1).data.join(","); let x = 1; const backgroundColor = getColorAt(0); const height = 7; return LETTERS.map(letter => { let nextBackground = x; while (getColorAt(nextBackground) !== backgroundColor && nextBackground < canvas.width) { nextBackground++; } const width = nextBackground - x; const name = `${prefix}_${letter}`; const sprite = { x, y, height, width, name }; x = nextBackground + 1; return sprite; }); }; const letterWidths = {}; const sprites = [...getLetters(88, "GEN_TEXT_SELECTED"), ...getLetters(96, "GEN_TEXT")]; sprites.forEach(sprite => { letterWidths[sprite.name] = sprite.width; }); return [letterWidths, getSpriteUrisFromImg(img, sprites)]; } // A promise that, given an array buffer returns a skin style object async function skinParser(zipFileBuffer, JSZip) { const zip = await JSZip.loadAsync(zipFileBuffer); const [colors, playlistStyle, images, cursors, region, genTextSprites, genExColors] = await Promise.all([genVizColors(zip), getPlaylistStyle(zip), genImages(zip), genCursors(zip), genRegion(zip), genGenTextSprites(zip), getGenExColors(zip)]); const [genLetterWidths, genTextImages] = genTextSprites || [null, {}]; return { colors, playlistStyle, images: skinParser_objectSpread(skinParser_objectSpread({}, images), genTextImages), genLetterWidths, cursors, region, genExColors }; } /* harmony default export */ const js_skinParser = (skinParser); // EXTERNAL MODULE: ../../node_modules/tinyqueue/index.js var tinyqueue = __webpack_require__(1195); var tinyqueue_default = /*#__PURE__*/__webpack_require__.n(tinyqueue); ;// CONCATENATED MODULE: ./js/loadQueue.js // Push promises onto a queue with a priority. // Run a given number of jobs in parallel // Useful for prioritizing network requests class LoadQueue { constructor({ threads }) { // TODO: Consider not running items with zero priority // Priority is a function so that items can change their priority between // when their priority is evaluated. // For example, we might add a track to the playlist and then scroll to/away // from it before it gets processed. this._queue = new (tinyqueue_default())([], (a, b) => a.priority() - b.priority()); this._availableThreads = threads; } push(task, priority) { const t = { task, priority }; this._queue.push(t); // Wait until the next event loop to pick a task to run. This way, we can // enqueue multiple items in an event loop, and be sure they will be run in // priority order. setTimeout(() => { this._run(); }, 0); return () => { // TODO: Could return a boolean representing if the task has already been // kicked off. this._queue = this._queue.filter(t1 => t1 !== t); }; } _run() { while (this._availableThreads > 0) { if (this._queue.length === 0) { return; } this._availableThreads--; const t = this._queue.pop(); const promise = t.task(); browser_default()(typeof promise.then === "function", `LoadQueue only supports loading Promises. Got ${promise}`); promise.then(() => { this._availableThreads++; this._run(); }); } } } ;// CONCATENATED MODULE: ./js/actionCreators/playlist.ts function cropPlaylist() { return (dispatch, getState) => { const state = getState(); if (getSelectedTrackObjects(state).length === 0) { return; } const selectedTrackIds = getSelectedTrackIds(state); const { playlist: { trackOrder } } = state; dispatch({ type: REMOVE_TRACKS, // @ts-ignore The keys are numbers, but TypeScript does not trust us. // https://github.com/Microsoft/TypeScript/pull/12253#issuecomment-263132208 ids: trackOrder.filter(id => !selectedTrackIds.has(id)) }); }; } function removeSelectedTracks() { return (dispatch, getState) => { dispatch({ type: REMOVE_TRACKS, // @ts-ignore The keys are numbers, but TypeScript does not trust us. // https://github.com/Microsoft/TypeScript/pull/12253#issuecomment-263132208 ids: Array.from(getSelectedTrackIds(getState())) }); }; } function playlist_removeAllTracks() { return dispatch => { // It's a bit funky that we need to do both of these. dispatch({ type: STOP }); dispatch({ type: REMOVE_ALL_TRACKS }); }; } function playlist_reverseList() { return { type: REVERSE_LIST }; } function playlist_randomizeList() { return { type: RANDOMIZE_LIST }; } function playlist_sortListByTitle() { return (dispatch, getState) => { const state = getState(); const tracks = getTracks(state); const trackOrder = sort(getTrackOrder(state), i => `${tracks[i].title}`.toLowerCase()); return dispatch({ type: SET_TRACK_ORDER, trackOrder }); }; } function playlist_setPlaylistScrollPosition(position) { return { type: SET_PLAYLIST_SCROLL_POSITION, position }; } function scrollNTracks(n) { return (dispatch, getState) => { const state = getState(); const overflow = getOverflowTrackCount(state); const currentOffset = getScrollOffset(state); const position = overflow ? clamp((currentOffset + n) / overflow, 0, 1) : 0; return dispatch({ type: SET_PLAYLIST_SCROLL_POSITION, position: position * 100 }); }; } function playlist_scrollPlaylistByDelta(e) { e.preventDefault(); return (dispatch, getState) => { const state = getState(); if (getOverflowTrackCount(state)) { e.stopPropagation(); } const totalPixelHeight = state.playlist.trackOrder.length * TRACK_HEIGHT; const percentDelta = e.deltaY / totalPixelHeight * 100; dispatch({ type: SET_PLAYLIST_SCROLL_POSITION, position: clamp(state.display.playlistScrollPosition + percentDelta, 0, 100) }); }; } function playlist_scrollUpFourTracks() { return scrollNTracks(-4); } function playlist_scrollDownFourTracks() { return scrollNTracks(4); } function playlist_dragSelected(offset) { return (dispatch, getState) => { const state = getState(); const tracks = getTracks(state); const trackOrder = getTrackOrder(state); const selectedIds = getSelectedTrackIds(state); const firstSelected = trackOrder.findIndex(trackId => tracks[trackId] && selectedIds.has(trackId)); if (firstSelected === -1) { return; } const lastSelected = findLastIndex(trackOrder, trackId => tracks[trackId] && selectedIds.has(trackId)); if (lastSelected === -1) { throw new Error("We found a first selected, but not a last selected."); } // Ensure we don't try to drag off either end. const min = -firstSelected; const max = trackOrder.length - 1 - lastSelected; const normalizedOffset = clamp(offset, min, max); if (normalizedOffset !== 0) { dispatch({ type: DRAG_SELECTED, offset: normalizedOffset }); } }; } function invertSelection() { return { type: INVERT_SELECTION }; } function playlist_selectZero() { return { type: SELECT_ZERO }; } function selectAll() { return { type: SELECT_ALL }; } ;// CONCATENATED MODULE: ./js/actionCreators/files.ts const { ipcRenderer } = window.require('electron'); // Lower is better const DURATION_VISIBLE_PRIORITY = 5; const META_DATA_VISIBLE_PRIORITY = 10; const DURATION_PRIORITY = 15; const META_DATA_PRIORITY = 20; const loadQueue = new LoadQueue({ threads: 4 }); function addTracksFromReferences(fileReferences, loadStyle, atIndex) { const tracks = Array.from(fileReferences).map(file => ({ blob: file, defaultName: file.name })); return files_loadMediaFiles(tracks, loadStyle, atIndex); } const SKIN_FILENAME_MATCHER = new RegExp("(wsz|zip)$", "i"); const EQF_FILENAME_MATCHER = new RegExp("eqf$", "i"); function loadFilesFromReferences(fileReferences, loadStyle = LOAD_STYLE.PLAY, atIndex = undefined) { return dispatch => { if (fileReferences.length < 1) { return; } else if (fileReferences.length === 1) { const fileReference = fileReferences[0]; if (SKIN_FILENAME_MATCHER.test(fileReference.name)) { dispatch(setSkinFromBlob(fileReference)); return; } else if (EQF_FILENAME_MATCHER.test(fileReference.name)) { dispatch(setEqFromFileReference(fileReference)); return; } } dispatch(addTracksFromReferences(fileReferences, loadStyle, atIndex)); }; } function setSkinFromBlob(blob) { return async (dispatch, getState, { requireJSZip }) => { if (!requireJSZip) { alert("Yaamp has not been configured to support custom skins."); return; } dispatch({ type: LOADING }); let JSZip; try { JSZip = await requireJSZip(); } catch (e) { console.error(e); dispatch({ type: LOADED }); alert("Failed to load the skin parser."); return; } try { const skinData = await js_skinParser(blob, JSZip); ipcRenderer.invoke("setSkin", { link: JSON.stringify(skinData) }).then(() => {}); dispatch({ type: SET_SKIN_DATA, data: { skinImages: skinData.images, skinColors: skinData.colors, skinPlaylistStyle: skinData.playlistStyle, skinCursors: skinData.cursors, skinRegion: skinData.region, skinGenLetterWidths: skinData.genLetterWidths, skinGenExColors: skinData.genExColors } }); } catch (e) { console.error(e); dispatch({ type: LOADED }); alert(`Failed to parse skin`); } }; } function setSkinFromClient(data) { return async (dispatch, getState, { requireJSZip }) => { if (!requireJSZip) { alert("Yaamp has not been configured to support custom skins."); return; } dispatch({ type: LOADING }); let JSZip; try { JSZip = await requireJSZip(); } catch (e) { console.error(e); dispatch({ type: LOADED }); alert("Failed to load the skin parser."); return; } try { const skinData = JSON.parse(data); dispatch({ type: SET_SKIN_DATA, data: { skinImages: skinData.images, skinColors: skinData.colors, skinPlaylistStyle: skinData.playlistStyle, skinCursors: skinData.cursors, skinRegion: skinData.region, skinGenLetterWidths: skinData.genLetterWidths, skinGenExColors: skinData.genExColors } }); } catch (e) { console.error(e); dispatch({ type: LOADED }); alert(`Failed to parse skin`); ipcRenderer.invoke("deleteSkin").then(() => {}); } }; } function setSkinFromUrl(url) { return async dispatch => { dispatch({ type: LOADING }); try { const response = await fetch(url); if (!response.ok) { throw new Error(response.statusText); } dispatch(setSkinFromBlob(response.blob())); } catch (e) { console.error(e); dispatch({ type: LOADED }); alert(`Failed to download skin from ${url}`); } }; } // This function is private, since Winamp consumers can provide means for // opening files via other methods. Only use the file type specific // versions below, since they can defer to the user-defined behavior. function _openFileDialog(accept, expectedType) { return async dispatch => { var _fileReferences$; const fileReferences = await promptForFileReferences({ accept }); dispatch({ type: "OPENED_FILES", expectedType, count: fileReferences.length, firstFileName: (_fileReferences$ = fileReferences[0]) === null || _fileReferences$ === void 0 ? void 0 : _fileReferences$.name }); dispatch(loadFilesFromReferences(fileReferences)); }; } function files_openEqfFileDialog() { return _openFileDialog(".eqf", "EQ"); } function files_openMediaFileDialog() { return _openFileDialog(".mp3", "MEDIA"); } function files_openSkinFileDialog() { return _openFileDialog(".zip, .wsz", "SKIN"); } function fetchMediaDuration(url, id) { return (dispatch, getState) => { loadQueue.push(async () => { try { const duration = await genMediaDuration(url); dispatch({ type: SET_MEDIA_DURATION, duration, id }); } catch (e) { // TODO: Should we update the state to indicate that we don't know the length? } }, () => { const trackIsVisible = getTrackIsVisibleFunction(getState()); return trackIsVisible(id) ? DURATION_VISIBLE_PRIORITY : DURATION_PRIORITY; }); }; } function files_loadMedia(e, loadStyle = LOAD_STYLE.NONE, atIndex = 0) { const { files } = e.dataTransfer; return async (dispatch, getState, { handleTrackDropEvent }) => { if (handleTrackDropEvent) { const tracks = await handleTrackDropEvent(e); if (tracks != null) { dispatch(files_loadMediaFiles(tracks, loadStyle, atIndex)); return; } } dispatch(loadFilesFromReferences(files, loadStyle, atIndex)); }; } function files_loadMediaFiles(tracks, loadStyle = LOAD_STYLE.NONE, atIndex = 0) { return dispatch => { if (loadStyle === LOAD_STYLE.PLAY) { // I'm the worst. It just so happens that in every case that we autoPlay, // we should also clear all tracks. dispatch(playlist_removeAllTracks()); } tracks.forEach((track, i) => { const priority = i === 0 ? loadStyle : LOAD_STYLE.NONE; dispatch(loadMediaFile(track, priority, atIndex + i)); }); }; } function loadMediaFile(track, priority = LOAD_STYLE.NONE, atIndex = 0) { return dispatch => { const id = uniqueId(); const { defaultName, metaData, duration } = track; let canonicalUrl; if ("url" in track) { canonicalUrl = track.url.toString(); } else if ("blob" in track) { canonicalUrl = URL.createObjectURL(track.blob); } else { throw new Error("Expected track to have either a blob or a url"); } dispatch({ type: ADD_TRACK_FROM_URL, url: canonicalUrl, duration: track.duration, defaultName, id, atIndex }); switch (priority) { case LOAD_STYLE.BUFFER: dispatch({ type: BUFFER_TRACK, id }); break; case LOAD_STYLE.PLAY: dispatch({ type: PLAY_TRACK, id }); break; case LOAD_STYLE.NONE: default: // If we're not going to load this right away, // we should set duration on our own if (duration != null) { dispatch({ type: SET_MEDIA_DURATION, duration, id }); } else { dispatch(fetchMediaDuration(canonicalUrl, id)); } } if (metaData != null) { const { artist, title, album } = metaData; dispatch({ type: SET_MEDIA_TAGS, artist, title, album, // For now, we lie about these next three things. // TODO: Ideally we would leave these as null and force a media data // fetch when the user starts playing. sampleRate: 44000, bitrate: 320000, numberOfChannels: 2, id }); } else if ("blob" in track) { // Blobs can be loaded quickly dispatch(fetchMediaTags(track.blob, id)); } else { dispatch(queueFetchingMediaTags(id)); } }; } function queueFetchingMediaTags(id) { return (dispatch, getState) => { const track = getTracks(getState())[id]; loadQueue.push(() => dispatch(fetchMediaTags(track.url, id)), () => { const trackIsVisible = getTrackIsVisibleFunction(getState()); return trackIsVisible(id) ? META_DATA_VISIBLE_PRIORITY : META_DATA_PRIORITY; }); }; } function fetchMediaTags(file, id) { return async (dispatch, getState, { requireMusicMetadata }) => { dispatch({ type: MEDIA_TAG_REQUEST_INITIALIZED, id }); try { const metadata = await genMediaTags(file, await requireMusicMetadata()); // There's more data here, but we don't have a use for it yet: const { artist, title, album, picture } = metadata.common; const { numberOfChannels, bitrate, sampleRate } = metadata.format; let albumArtUrl = null; if (picture && picture.length >= 1) { const byteArray = new Uint8Array(picture[0].data); const blob = new Blob([byteArray], { type: picture[0].format }); albumArtUrl = URL.createObjectURL(blob); } dispatch({ type: SET_MEDIA_TAGS, artist: artist ? artist : "", title: title ? title : "", album, albumArtUrl, numberOfChannels, bitrate, sampleRate, id }); } catch (e) { dispatch({ type: MEDIA_TAG_REQUEST_FAILED, id }); } }; } function setEqFromFileReference(fileReference) { return async dispatch => { const arrayBuffer = await genArrayBufferFromFileReference(fileReference); const eqf = (0,winamp_eqf.parser)(arrayBuffer); const preset = eqf.presets[0]; dispatch(files_setEqFromObject(preset)); }; } function setEqFromClient(data) { return async dispatch => { const eqf = JSON.parse(data); const preset = eqf.presets[0]; dispatch(files_setEqFromObject(preset)); }; } function files_setEqFromObject(preset) { return dispatch => { dispatch(setPreamp(normalizeEqBand(preset.preamp))); BANDS.forEach(band => { // @ts-ignore band and EqfPreset align dispatch(setEqBand(band, normalizeEqBand(preset[`hz${band}`]))); }); }; } function files_downloadPreset() { return (dispatch, getState) => { const state = getState(); const data = getEqfData(state); console.log(data); const arrayBuffer = (0,winamp_eqf.creator)(data); // const base64 = Utils.base64FromArrayBuffer(arrayBuffer); // const dataURI = `data:application/zip;base64,${base64}`; ipcRenderer.invoke("setEQ", { link: JSON.stringify(data) }).then(() => {}); // Utils.downloadURI(dataURI, "entry.eqf"); }; } function files_downloadHtmlPlaylist() { return (dispatch, getState) => { const uri = getPlaylistURL(getState()); downloadURI(uri, "Winamp Playlist.html"); }; } let el = document.createElement("input"); el.type = "file"; // @ts-ingore const DIR_SUPPORT = // @ts-ignore typeof el.webkitdirectory !== "undefined" || // @ts-ignore typeof el.mozdirectory !== "undefined" || // @ts-ignore typeof el.directory !== "undefined"; // Release our reference el = null; function files_addFilesAtIndex(nextIndex) { return async dispatch => { const fileReferences = await promptForFileReferences(); dispatch(addTracksFromReferences(fileReferences, LOAD_STYLE.NONE, nextIndex)); }; } function files_addDirAtIndex(nextIndex) { return async dispatch => { if (!DIR_SUPPORT) { alert("Not supported in your browser"); return; } const fileReferences = await promptForFileReferences({ directory: true }); dispatch(addTracksFromReferences(fileReferences, LOAD_STYLE.NONE, nextIndex)); }; } function files_addFilesFromUrl(atIndex = 0) { return async (dispatch, getState, { handleAddUrlEvent }) => { if (handleAddUrlEvent) { const tracks = await handleAddUrlEvent(); if (tracks != null) { dispatch(files_loadMediaFiles(tracks, LOAD_STYLE.NONE, atIndex)); return; } } else { alert("Not supported in Yaamp"); } }; } function files_addFilesFromList() { return async (dispatch, getState, { handleLoadListEvent }) => { if (handleLoadListEvent) { const tracks = await handleLoadListEvent(); if (tracks != null) { dispatch(playlist_removeAllTracks()); dispatch(files_loadMediaFiles(tracks, LOAD_STYLE.NONE, 0)); return; } } else { alert("Not supported in Yaamp"); } }; } function files_saveFilesToList() { return (dispatch, getState, { handleSaveListEvent }) => { if (handleSaveListEvent) { handleSaveListEvent(getUserTracks(getState())); } else { alert("Not supported in Yaamp"); } }; } function files_droppedFiles(e, windowId) { return dispatch => { var _e$dataTransfer$files; return dispatch({ type: "DROPPED_FILES", count: e.dataTransfer.files.length, firstFileName: (_e$dataTransfer$files = e.dataTransfer.files[0]) === null || _e$dataTransfer$files === void 0 ? void 0 : _e$dataTransfer$files.name, windowId }); }; } ;// CONCATENATED MODULE: ./js/actionCreators/milkdrop.ts // @ts-ignore function normalizePresetTypes(preset) { const { name } = preset; if ("butterchurnPresetObject" in preset) { return { type: "RESOLVED", name, preset: preset.butterchurnPresetObject }; } else if ("getButterchrunPresetObject" in preset) { return { type: "UNRESOLVED", name, getPreset: preset.getButterchrunPresetObject }; } else if ("butterchurnPresetUrl" in preset) { return { type: "UNRESOLVED", name, getPreset: async () => { const resp = await fetch(preset.butterchurnPresetUrl); return resp.json(); } }; } throw new Error("Invalid preset object"); } function initializePresets(presetOptions) { return async dispatch => { const { getPresets, importButterchurn } = presetOptions; importButterchurn().then(butterchurn => { dispatch({ type: GOT_BUTTERCHURN, butterchurn: butterchurn.default }); }); const presets = await getPresets(); const normalizePresets = presets.map(normalizePresetTypes); dispatch(loadPresets(normalizePresets)); }; } function loadPresets(presets) { return (dispatch, getState) => { const state = getState(); const presetsLength = state.milkdrop.presets.length; dispatch({ type: GOT_BUTTERCHURN_PRESETS, presets }); if (presetsLength === 0 && getRandomizePresets(state)) { dispatch(selectRandomPreset()); } else { dispatch(milkdrop_requestPresetAtIndex(presetsLength, TransitionType.IMMEDIATE, true)); } }; } function milkdrop_appendPresetFileList(fileList) { return async (dispatch, getState, { convertPreset }) => { const presets = butterchurnPresets_min_default().getPresets(); dispatch(loadPresets(presets)); }; } function milkdrop_selectNextPreset(transitionType = TransitionType.DEFAULT) { return (dispatch, getState) => { const state = getState(); if (getRandomizePresets(state)) { return dispatch(selectRandomPreset(transitionType)); } const currentPresetIndex = getCurrentPresetIndex(state); if (currentPresetIndex == null) { return; } const nextPresetIndex = currentPresetIndex + 1; dispatch(milkdrop_requestPresetAtIndex(nextPresetIndex, transitionType, true)); }; } function milkdrop_selectPreset(presetKey, transitionType = TransitionType.DEFAULT) { return (dispatch, getState) => { dispatch({ type: SELECT_PRESET_AT_INDEX, index: presetKey, transitionType }); const state = getState(); const currentPresetIndex = getCurrentPresetIndex(state); console.log(currentPresetIndex); }; } function milkdrop_selectPreviousPreset(transitionType = TransitionType.DEFAULT) { return (dispatch, getState) => { const state = getState(); const { presetHistory } = state.milkdrop; if (presetHistory.length < 1) { return; } // Awkward. We do -2 becuase the the last track is the current track. const lastPresetIndex = presetHistory[presetHistory.length - 2]; dispatch(milkdrop_requestPresetAtIndex(lastPresetIndex, transitionType, false)); }; } function selectRandomPreset(transitionType = TransitionType.DEFAULT) { return (dispatch, getState) => { const state = getState(); // TODO: Make this a selector. const randomIndex = Math.floor(Math.random() * state.milkdrop.presets.length); dispatch(milkdrop_requestPresetAtIndex(randomIndex, transitionType, true)); }; } // TODO: Technically there's a race here. If you request two presets in a row, the // first one may resolve before the second. function milkdrop_requestPresetAtIndex(index, transitionType, addToHistory) { return async (dispatch, getState) => { const state = getState(); const preset = state.milkdrop.presets[index]; if (preset == null) { // Index might be out of range. return; } dispatch({ type: PRESET_REQUESTED, index, addToHistory }); switch (preset.type) { case "RESOLVED": dispatch({ type: SELECT_PRESET_AT_INDEX, index, transitionType }); return; case "UNRESOLVED": const json = await preset.getPreset(); // TODO: Ensure that this works correctly even if requests resolve out of order dispatch({ type: RESOLVE_PRESET_AT_INDEX, index, json }); dispatch({ type: SELECT_PRESET_AT_INDEX, index, transitionType }); return; } }; } function milkdrop_handlePresetDrop(e) { return milkdrop_appendPresetFileList(e.dataTransfer.files); } function toggleRandomizePresets() { return { type: TOGGLE_RANDOMIZE_PRESETS }; } function togglePresetCycling() { return { type: TOGGLE_PRESET_CYCLING }; } function milkdrop_scheduleMilkdropMessage(message) { return { type: SCHEDULE_MILKDROP_MESSAGE, message }; } ;// CONCATENATED MODULE: ./js/actionCreators/index.ts const { ipcRenderer: actionCreators_ipcRenderer } = window.require('electron'); function actionCreators_close() { return dispatch => { // TODO: This could probably be improved by adding a "PREVENT_CLOSE" action // or something, but this works okay for now. let defaultPrevented = false; const cancel = () => { defaultPrevented = true; }; dispatch({ type: CLOSE_REQUESTED, cancel }); if (!defaultPrevented) { dispatch({ type: STOP }); dispatch({ type: CLOSE_WINAMP }); } }; } function actionCreators_open() { return { type: OPEN_WINAMP }; } function actionCreators_toggleVisualizerStyle() { return { type: TOGGLE_VISUALIZER_STYLE }; } function actionCreators_minimize() { return { type: MINIMIZE_WINAMP }; } function actionCreators_setFocus(input) { return { type: SET_FOCUS, input }; } function actionCreators_unsetFocus() { return { type: UNSET_FOCUS }; } function actionCreators_focusBand(band) { return { type: SET_BAND_FOCUS, input: "eq", bandFocused: band }; } function loadSerializedState( // In the future this type should be the union of all versioned types. serializedState) { return dispatch => { dispatch({ type: LOAD_SERIALIZED_STATE, serializedState }); dispatch(ensureWindowsAreOnScreen()); }; } function actionCreators_loadDefaultSkin() { return { type: LOAD_DEFAULT_SKIN }; } function toggleMilkdropDesktop() { return (dispatch, getState) => { if (getMilkdropDesktopEnabled(getState())) { dispatch(showWindow(WINDOWS.MILKDROP)); dispatch({ type: SET_MILKDROP_DESKTOP, enabled: false }); } else { dispatch(hideWindow(WINDOWS.MILKDROP)); dispatch({ type: SET_MILKDROP_DESKTOP, enabled: true }); } }; } function setMilkdropFullscreen(enabled) { return (dispatch, getState) => { dispatch({ type: SET_MILKDROP_FULLSCREEN, enabled }); actionCreators_ipcRenderer.invoke('toggle-milkdrop-fullscreen', enabled); }; } function toggleMilkdropFullscreen() { return (dispatch, getState) => { const currentState = getMilkdropFullscreenEnabled(getState()); dispatch(setMilkdropFullscreen(!currentState)); }; } function setMilkdropLock(enabled) { return (dispatch, getState) => { dispatch({ type: SET_MILKDROP_LOCK, enabled }); }; } function toggleMilkdropLock() { return (dispatch, getState) => { const currentState = getMilkdropLockEnabled(getState()); dispatch(setMilkdropLock(!currentState)); }; } function actionCreators_togglePresetOverlay() { return (dispatch, getState) => { if (getPresetOverlayOpen(getState())) { dispatch(windows_setFocusedWindow(WINDOWS.MILKDROP)); } dispatch({ type: TOGGLE_PRESET_OVERLAY }); }; } function actionCreators_stepMarquee() { return { type: STEP_MARQUEE }; } ;// CONCATENATED MODULE: ./js/mediaMiddleware.ts /* harmony default export */ const mediaMiddleware = (media => store => { const { media: { volume, balance }, equalizer: { sliders } } = store.getState(); // Ensure the default state is the canonical value. media.setVolume(volume); media.setBalance(balance); media.setPreamp(sliders.preamp); // TODO: Ensure other values like bands are in sync media.on("timeupdate", () => { store.dispatch({ type: UPDATE_TIME_ELAPSED, elapsed: media.timeElapsed() }); }); media.on("ended", () => { store.dispatch(media_next()); }); media.on("playing", () => { store.dispatch({ type: IS_PLAYING }); }); media.on("waiting", () => { store.dispatch({ type: START_WORKING }); }); media.on("stopWaiting", () => { store.dispatch({ type: STOP_WORKING }); }); media.on("fileLoaded", () => { const id = getCurrentTrackId(store.getState()); if (id == null) { // Attempted to set the metadata for a track that was already removed. // Really, the media should have been stopped when the track was removed. return; } store.dispatch({ id, type: SET_MEDIA, kbps: "320", khz: "44", channels: 2, length: media.duration() }); }); return next => action => { const returnValue = next(action); const state = store.getState(); switch (action.type) { case PLAY: media.play(); break; case PAUSE: media.pause(); break; case STOP: media.stop(); break; case SET_VOLUME: media.setVolume(getVolume(state)); break; case SET_BALANCE: media.setBalance(getBalance(state)); break; case SEEK_TO_PERCENT_COMPLETE: media.seekToPercentComplete(action.percent); break; case PLAY_TRACK: { const url = getTrackUrl(store.getState())(action.id); if (url != null) { media.loadFromUrl(url, true); } break; } case BUFFER_TRACK: { const url = getTrackUrl(store.getState())(action.id); if (url != null) { media.loadFromUrl(url, false); } break; } case SET_BAND_VALUE: if (action.band === "preamp") { media.setPreamp(action.value); } else { media.setEqBand(action.band, action.value); } break; case SET_EQ_OFF: media.disableEq(); break; case SET_EQ_ON: media.enableEq(); break; case LOAD_SERIALIZED_STATE: { // Set ALL THE THINGS! if (getEqualizerEnabled(state)) { media.enableEq(); } else { media.disableEq(); } media.setVolume(getVolume(state)); media.setBalance(getBalance(state)); objectForEach(state.equalizer.sliders, (value, slider) => { if (slider === "preamp") { media.setPreamp(value); } else { // @ts-ignore I don't know how to teach TypeScript about objects // that use Slider as keys media.setEqBand(slider, value); } }); break; } } return returnValue; }; }); ;// CONCATENATED MODULE: ./js/store.ts // TODO: Move to demo const compose = (0,redux_devtools_extension/* composeWithDevTools */.Uo)({ actionsBlacklist: [UPDATE_TIME_ELAPSED, STEP_MARQUEE] }); /* harmony default export */ function store(media, actionEmitter, customMiddlewares = [], stateOverrides, extras) { let initialState; if (stateOverrides) { initialState = merge(reducers(undefined, { type: "@@init" }), stateOverrides); } const emitterMiddleware = () => next => action => { actionEmitter.trigger(action.type, action); return next(action); }; const enhancer = compose((0,redux/* applyMiddleware */.md)(...[es.withExtraArgument(extras), mediaMiddleware(media), emitterMiddleware, ...customMiddlewares].filter(Boolean))); // The Redux types are a bit confused, and don't realize that passing an // undefined initialState is allowed. const store = initialState ? (0,redux/* createStore */.MT)(reducers, initialState, enhancer) : (0,redux/* createStore */.MT)(reducers, enhancer); return store; } ;// CONCATENATED MODULE: ../../node_modules/fscreen/dist/fscreen.esm.js var key = { fullscreenEnabled: 0, fullscreenElement: 1, requestFullscreen: 2, exitFullscreen: 3, fullscreenchange: 4, fullscreenerror: 5, fullscreen: 6 }; var webkit = [ 'webkitFullscreenEnabled', 'webkitFullscreenElement', 'webkitRequestFullscreen', 'webkitExitFullscreen', 'webkitfullscreenchange', 'webkitfullscreenerror', '-webkit-full-screen', ]; var moz = [ 'mozFullScreenEnabled', 'mozFullScreenElement', 'mozRequestFullScreen', 'mozCancelFullScreen', 'mozfullscreenchange', 'mozfullscreenerror', '-moz-full-screen', ]; var ms = [ 'msFullscreenEnabled', 'msFullscreenElement', 'msRequestFullscreen', 'msExitFullscreen', 'MSFullscreenChange', 'MSFullscreenError', '-ms-fullscreen', ]; // so it doesn't throw if no window or document var fscreen_esm_document = typeof window !== 'undefined' && typeof window.document !== 'undefined' ? window.document : {}; var vendor = (('fullscreenEnabled' in fscreen_esm_document && Object.keys(key)) || (webkit[0] in fscreen_esm_document && webkit) || (moz[0] in fscreen_esm_document && moz) || (ms[0] in fscreen_esm_document && ms) || []); var fscreen = { requestFullscreen: function (element) { return element[vendor[key.requestFullscreen]](); }, requestFullscreenFunction: function (element) { return element[vendor[key.requestFullscreen]]; }, get exitFullscreen() { return fscreen_esm_document[vendor[key.exitFullscreen]].bind(fscreen_esm_document); }, get fullscreenPseudoClass() { return ":" + vendor[key.fullscreen]; }, addEventListener: function (type, handler, options) { return fscreen_esm_document.addEventListener(vendor[key[type]], handler, options); }, removeEventListener: function (type, handler, options) { return fscreen_esm_document.removeEventListener(vendor[key[type]], handler, options); }, get fullscreenEnabled() { return Boolean(fscreen_esm_document[vendor[key.fullscreenEnabled]]); }, set fullscreenEnabled(val) { }, get fullscreenElement() { return fscreen_esm_document[vendor[key.fullscreenElement]]; }, set fullscreenElement(val) { }, get onfullscreenchange() { return fscreen_esm_document[("on" + vendor[key.fullscreenchange]).toLowerCase()]; }, set onfullscreenchange(handler) { return fscreen_esm_document[("on" + vendor[key.fullscreenchange]).toLowerCase()] = handler; }, get onfullscreenerror() { return fscreen_esm_document[("on" + vendor[key.fullscreenerror]).toLowerCase()]; }, set onfullscreenerror(handler) { return fscreen_esm_document[("on" + vendor[key.fullscreenerror]).toLowerCase()] = handler; }, }; /* harmony default export */ const fscreen_esm = (fscreen); //# sourceMappingURL=fscreen.esm.js.map ;// CONCATENATED MODULE: ./js/components/Fullscreen.tsx // Adapted from https://github.com/snakesilk/react-fullscreen function leaveFullScreen() { if (fscreen_esm.fullscreenEnabled) { fscreen_esm.exitFullscreen(); } } function enterFullScreen(node) { if (fscreen_esm.fullscreenEnabled) { fscreen_esm.requestFullscreen(node); } } function FullScreen(props) { const { onChange, enabled } = props; const ref = (0,react.useRef)(null); (0,react.useEffect)(() => { function detectFullScreen() { if (onChange) { onChange(fscreen_esm.fullscreenElement === ref.current); } } fscreen_esm.addEventListener("fullscreenchange", detectFullScreen); return () => { fscreen_esm.removeEventListener("fullscreenchange", detectFullScreen); }; }, [onChange]); // This must run in response to a click event, so we'll use useLayoutEffect just in case. (0,react.useLayoutEffect)(() => { const isEnabled = fscreen_esm.fullscreenElement === ref.current; if (isEnabled && !enabled) { leaveFullScreen(); } else if (!isEnabled && enabled && ref.current != null) { enterFullScreen(ref.current); } }, [enabled]); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { ref: ref, style: props.enabled ? { height: "100%", width: "100%" } : undefined, children: props.children }); } /* harmony default export */ const Fullscreen = (FullScreen); ;// CONCATENATED MODULE: ./js/hooks.ts function useUnmountedRef() { const unmountedRef = (0,react.useRef)(false); (0,react.useEffect)(() => { return () => { unmountedRef.current = true; }; }, []); return unmountedRef; } function usePromiseValueOrNull(propValue) { const [value, setValue] = (0,react.useState)(null); (0,react.useEffect)(() => { let disposed = false; propValue.then(resolvedValue => { if (disposed) { return; } setValue(resolvedValue); }); return () => { disposed = true; }; }, [propValue]); return value; } function useScreenSize() { const [size] = (0,react.useState)(getScreenSize()); // TODO: We could subscribe to screen size changes. return size; } function useWindowSize() { const [size, setSize] = (0,react.useState)(getWindowSize()); const handler = (0,react.useCallback)(throttle(() => { setSize(getWindowSize()); }, 100), []); (0,react.useEffect)(() => { window.addEventListener("resize", handler); return () => { window.removeEventListener("resize", handler); }; }, [handler]); return size; } const cursorPositionRef = { current: { pageX: 0, pageY: 0 } }; window.document.addEventListener("mousemove", ({ pageX, pageY }) => { cursorPositionRef.current = { pageX, pageY }; }); // We use a single global event listener because there is no way to get the // mouse position aside from an event. Ideally we could create/clean up the // event listener in the hook, but in the case where we want to check the cursor // position on mount, that we wouldn't have had time to capture an event. function useCursorPositionRef() { return cursorPositionRef; } // CSS hover state is not respected if the cursor is already over the node when // it is added to the DOM. This hook allows your component to know its hover // state on mount without waiting for the mouse to move. // https://stackoverflow.com/a/13259049/1263117 function useIsHovered() { const cursorRef = useCursorPositionRef(); const [hover, setHover] = (0,react.useState)(false); const [node, setNode] = (0,react.useState)(null); (0,react.useLayoutEffect)(() => { if (node == null) { setHover(false); return; } const domRect = node.getBoundingClientRect(); const { pageX, pageY } = cursorRef.current; setHover(pageX >= domRect.left && pageX <= domRect.right && pageY >= domRect.top && pageY <= domRect.bottom); const enter = () => setHover(true); const leave = () => setHover(false); node.addEventListener("mouseenter", enter); node.addEventListener("mouseleave", leave); return () => { node.removeEventListener("mouseenter", enter); node.removeEventListener("mouseleave", leave); }; }, [node, cursorRef]); return { ref: setNode, hover }; } function useOnClickAway(ref, callback) { (0,react.useEffect)(() => { if (ref == null || callback == null) { return; } const handleClickOut = ee => { const clickOutTarget = ee.target; if (!(clickOutTarget instanceof Element)) { // TypeScript doesn't realize this will always be true return; } if (ref.contains(clickOutTarget)) { return; } // If the click is _not_ inside the menu. callback(); window.document.removeEventListener("click", handleClickOut, { capture: true }); }; window.document.addEventListener("click", handleClickOut, { capture: true }); return () => { window.document.removeEventListener("click", handleClickOut, { capture: true }); }; }, [ref, callback]); } // TODO: Return useSelector directly and apply the type without wrapping function useTypedSelector(selector) { return useSelector(selector); } function useActionCreator(actionCreator) { const dispatch = useDispatch(); return (0,react.useCallback)((...args) => dispatch(actionCreator(...args)), [dispatch, actionCreator]); } function useTypedDispatch() { return useDispatch(); } // EXTERNAL MODULE: ../../node_modules/classnames/index.js var classnames = __webpack_require__(2779); var classnames_default = /*#__PURE__*/__webpack_require__.n(classnames); // EXTERNAL MODULE: ./css/gen-window.css var gen_window = __webpack_require__(6237); ;// CONCATENATED MODULE: ./js/components/ResizeTarget.tsx const ResizeTarget_excluded = ["currentSize", "setWindowSize", "widthOnly"]; function ResizeTarget_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function ResizeTarget_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ResizeTarget_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ResizeTarget_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const { ipcRenderer: ResizeTarget_ipcRenderer } = window.require('electron'); function ResizeTarget(props) { const { currentSize, setWindowSize, widthOnly } = props, passThroughProps = _objectWithoutProperties(props, ResizeTarget_excluded); const [mouseDown, setMouseDown] = (0,react.useState)(false); const [mouseStart, setMouseStart] = (0,react.useState)(null); let currentNewSize = [0, 0]; (0,react.useEffect)(() => { if (mouseDown === false || mouseStart == null) { return; } const [width, height] = currentSize; const handleMove = ee => { const x = ee.clientX - mouseStart.x; const y = ee.clientY - mouseStart.y; const newWidth = Math.max(0, width + Math.round(x / WINDOW_RESIZE_SEGMENT_WIDTH)); const newHeight = widthOnly ? width : Math.max(0, height + Math.round(y / WINDOW_RESIZE_SEGMENT_HEIGHT)); const newSize = [newWidth, newHeight]; currentNewSize = newSize; ResizeTarget_ipcRenderer.invoke("movingWindowStarted").then(() => {}); props.setWindowSize(newSize); }; window.addEventListener("mousemove", handleMove); const handleMouseUp = () => { setMouseDown(false); ResizeTarget_ipcRenderer.invoke('setSize', { size: currentNewSize, id: props.id }).then(rs => { ResizeTarget_ipcRenderer.invoke("movingWindowEnded"); }); }; window.addEventListener("mouseup", handleMouseUp); return () => { window.removeEventListener("mousemove", handleMove); window.removeEventListener("mouseup", handleMouseUp); }; // We pruposefully close over the props from when the mouse went down // eslint-disable-next-line react-hooks/exhaustive-deps }, [mouseStart, mouseDown]); const handleMouseDown = e => { // Prevent dragging from highlighting text. e.preventDefault(); setMouseStart({ x: e.clientX, y: e.clientY }); setMouseDown(true); }; return /*#__PURE__*/(0,jsx_runtime.jsx)("div", ResizeTarget_objectSpread({ onMouseDown: handleMouseDown }, passThroughProps)); } /* harmony default export */ const components_ResizeTarget = (/*#__PURE__*/(0,react.memo)(ResizeTarget)); ;// CONCATENATED MODULE: ./js/components/FocusTarget.tsx function FocusTarget({ onKeyDown, windowId, children }) { const focusedWindowId = useTypedSelector(getFocusedWindow); const setFocus = useActionCreator(windows_setFocusedWindow); const focusHandler = (0,react.useCallback)(() => { if (windowId !== focusedWindowId) { setFocus(windowId); } }, [windowId, focusedWindowId, setFocus]); const [ref, setRef] = (0,react.useState)(null); (0,react.useEffect)(() => { if (ref == null || onKeyDown == null) { return; } ref.addEventListener("keydown", onKeyDown); return () => ref.removeEventListener("keydown", onKeyDown); }, [onKeyDown, windowId, focusedWindowId, ref]); // It's possible for a child component to gain focus and then become // unmounted. In that case, the browser will return focus to the ``. // In the following hook, use a `MutationObserver` to watch for that behavior // and refocus the containing FocusTarget when it happens. // // I tried a number of other approaches using `focus/blur/focusin/focusout` on // various DOM nodes, and was unable to find a solution which would trigger in // this senario in Firefox. Therefore we use this `MutationObserver` approach. (0,react.useEffect)(() => { // Only create the `MutationObserver` within the currently focused target. if (ref == null || windowId !== focusedWindowId) { return; } const observer = new MutationObserver(mutations => { // In the common case we won't have focused the body, so we can do this // inexpensive check first to avoid calling the more expensive `O(n)` // check of the individual mutations. if (document.activeElement !== document.body) { return; } if (mutations.some(mutation => mutation.removedNodes.length > 0)) { ref.focus(); } }); observer.observe(ref, { subtree: true, attributes: false, childList: true }); return () => observer.disconnect(); }, [windowId, focusedWindowId, ref]); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { ref: setRef, onMouseDown: focusHandler, onFocus: focusHandler, tabIndex: -1, style: { height: "100%", width: "100%" }, children: children }); } /* harmony default export */ const components_FocusTarget = (FocusTarget); ;// CONCATENATED MODULE: ./js/components/GenWindow/index.tsx const Text = ({ children }) => { const letters = children.split(""); return /*#__PURE__*/(0,jsx_runtime.jsx)(react.Fragment, { children: letters.map((letter, i) => /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: `draggable gen-text-letter gen-text-${letter === " " ? "space" : letter.toLowerCase()}` }, i)) }); }; const CHROME_WIDTH = 19; const CHROME_HEIGHT = 34; // Named export for testing const GenWindow = ({ children, title, windowId, onKeyDown }) => { const setWindowSize = useActionCreator(windows_setWindowSize); const closeWindow = useActionCreator(windows_closeWindow); const getWindowPixelSize = useTypedSelector(selectors_getWindowPixelSize); const focusedWindow = useTypedSelector(getFocusedWindow); const getWindowSize = useTypedSelector(selectors_getWindowSize); const windowSize = getWindowSize(windowId); const selected = focusedWindow === windowId; const { width, height } = getWindowPixelSize(windowId); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_FocusTarget, { windowId: windowId, onKeyDown: onKeyDown, children: /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { id: "gen-window", className: classnames_default()("gen-window", "window", { selected }), style: { width, height }, children: [/*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "gen-top draggable", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-top-left draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-top-left-fill draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-top-left-end draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-top-title draggable", children: /*#__PURE__*/(0,jsx_runtime.jsx)(Text, { children: title }) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-top-right-end draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-top-right-fill draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-top-right draggable", children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-close selected", onClick: () => closeWindow(windowId) }) })] }), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "gen-middle", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-middle-left draggable", children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-middle-left-bottom draggable" }) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-middle-center", children: children({ width: width - CHROME_WIDTH, height: height - CHROME_HEIGHT }) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-middle-right draggable", children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-middle-right-bottom draggable" }) })] }), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "gen-bottom draggable", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-bottom-left draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "gen-bottom-right draggable", children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_ResizeTarget, { currentSize: windowSize, setWindowSize: size => setWindowSize(windowId, size), id: "gen-resize-target" }) })] })] }) }); }; /* harmony default export */ const components_GenWindow = (GenWindow); // EXTERNAL MODULE: ../../node_modules/lodash/lodash.js var lodash = __webpack_require__(6635); var lodash_default = /*#__PURE__*/__webpack_require__.n(lodash); // EXTERNAL MODULE: ../../node_modules/butterchurn/lib/butterchurn.js var butterchurn = __webpack_require__(6900); var butterchurn_default = /*#__PURE__*/__webpack_require__.n(butterchurn); ;// CONCATENATED MODULE: ./js/components/MilkdropWindow/Visualizer.tsx // webamp/packages/webamp/js/components/MilkdropWindow/Visualizer.tsx // @ts-ignore // @ts-ignore const TRANSITION_TYPE_DURATIONS = { [TransitionType.DEFAULT]: 2.7, [TransitionType.IMMEDIATE]: 0, [TransitionType.USER_PRESET]: 5.7 }; function Visualizer({ analyser, width, height }) { const visualizerStyle = useTypedSelector(selectors_getVisualizerStyle); const playing = useTypedSelector(getMediaIsPlaying); const trackTitle = useTypedSelector(getCurrentTrackDisplayName); const currentPreset = useTypedSelector(getCurrentPreset); const lock = useTypedSelector(getMilkdropLockEnabled); const transitionType = useTypedSelector(getPresetTransitionType); const message = useTypedSelector(getMilkdropMessage); const selectPreset = useActionCreator(milkdrop_selectPreset); const isEnabledVisualizer = visualizerStyle === VISUALIZERS.MILKDROP; const canvasRef = (0,react.useRef)(null); const [visualizer, setVisualizer] = (0,react.useState)(null); const lastShownMessage = (0,react.useRef)(null); const presets = butterchurnPresets_min_default().getPresets(); const presetKeys = lodash_default().keys(presets); (0,react.useEffect)(() => { if (canvasRef.current == null || (butterchurn_default()) == null) { console.error("Canvas or Butterchurn is not initialized!"); return; } if (visualizer != null) { // Note: The visualizer does not offer anyway to clean itself up. So, we // don't offer any way to recreate it. So, if you swap out the analyser // node, or the canvas, that change won't be respected. return; } const _visualizer = butterchurn_default().createVisualizer(analyser.context, canvasRef.current, { width, height, meshWidth: 32, meshHeight: 24, pixelRatio: window.devicePixelRatio || 1 }); _visualizer.connectAudio(analyser); if (!lock) { const randomPresetKey = presetKeys[Math.floor(Math.random() * presetKeys.length)]; const preset = presets[randomPresetKey]; _visualizer.loadPreset(preset, 0.3); setVisualizer(_visualizer); selectPreset(randomPresetKey); } else { _visualizer.loadPreset(currentPreset, 0.3); setVisualizer(_visualizer); } }, [(butterchurn_default()), analyser, height, width, visualizer]); // Ensure render size stays up to date (0,react.useEffect)(() => { if (visualizer == null) { return; } visualizer.setRendererSize(width, height); }, [visualizer, width, height]); // Load presets when they change const hasLoadedPreset = (0,react.useRef)(false); (0,react.useEffect)(() => { if (visualizer == null || currentPreset == null) { return; } if (hasLoadedPreset.current) { visualizer.loadPreset(currentPreset, TRANSITION_TYPE_DURATIONS[transitionType]); } else { visualizer.loadPreset(currentPreset, TRANSITION_TYPE_DURATIONS[TransitionType.IMMEDIATE]); hasLoadedPreset.current = true; } // We don't want to trigger the transition if the transition type changes. // eslint-disable-next-line react-hooks/exhaustive-deps }, [visualizer, currentPreset]); // Handle title animations and change preset (0,react.useEffect)(() => { if (visualizer == null || !trackTitle) { return; } if (!lock) { const randomPresetKey = presetKeys[Math.floor(Math.random() * presetKeys.length)]; const preset = presets[randomPresetKey]; selectPreset(randomPresetKey); visualizer.loadPreset(preset, 0.3); } else { visualizer.loadPreset(currentPreset, 0.3); setVisualizer(visualizer); } visualizer.launchSongTitleAnim(trackTitle); }, [visualizer, trackTitle]); (0,react.useEffect)(() => { if (visualizer == null || message == null) { return; } if (lastShownMessage.current == null || message.time > lastShownMessage.current) { lastShownMessage.current = Date.now(); const randomPresetKey = presetKeys[Math.floor(Math.random() * presetKeys.length)]; const preset = presets[randomPresetKey]; visualizer.loadPreset(preset, 0.3); visualizer.launchSongTitleAnim(message.text); } }, [visualizer, message]); const shouldAnimate = playing && isEnabledVisualizer; // Kick off the animation loop (0,react.useEffect)(() => { if (!shouldAnimate || visualizer == null) { return; } let animationFrameRequest = null; const loop = () => { visualizer.render(); animationFrameRequest = window.requestAnimationFrame(loop); }; loop(); return () => { if (animationFrameRequest != null) { window.cancelAnimationFrame(animationFrameRequest); } }; }, [visualizer, shouldAnimate]); return /*#__PURE__*/(0,jsx_runtime.jsx)("canvas", { height: height, width: width, style: { height: "100%", width: "100%", display: isEnabledVisualizer ? "block" : "none" }, ref: canvasRef }); } /* harmony default export */ const MilkdropWindow_Visualizer = (Visualizer); ;// CONCATENATED MODULE: ./js/components/MilkdropWindow/Background.tsx const Background = props => { const { innerRef } = props; return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { ref: innerRef, className: "draggable", style: { // This color will be used until Butterchurn is loaded backgroundColor: "#000", position: "absolute", top: 0, bottom: 0, left: 0, right: 0, height: "100%", width: "100%" }, tabIndex: 0, children: props.children }); }; /* harmony default export */ const MilkdropWindow_Background = (Background); ;// CONCATENATED MODULE: ./js/components/MilkdropWindow/PresetOverlay.tsx function PresetOverlay_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function PresetOverlay_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? PresetOverlay_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : PresetOverlay_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const ENTRY_HEIGHT = 14; const HEIGHT_PADDING = 15; const WIDTH_PADDING = 20; const LOADING_STYLE = { position: "absolute", top: 0, left: 0, color: "white", background: "rgba(0.33, 0.33, 0.33, 0.33)" }; const OUTER_WRAPPER_STYLE = { position: "absolute", top: 0, left: 0, padding: "15px 10px 0 10px" }; const INNER_WRAPPER_STYLE = { display: "inline-block", whiteSpace: "nowrap", overflow: "hidden", background: "rgba(0, 0, 0, 0.815)", fontSize: "12px" }; function presetIndexFromListIndex(listIndex) { return listIndex - 1; } function listIndexFromPresetIndex(listIndex) { return listIndex + 1; } function PresetOverlay({ height, width }) { const presetKeys = useTypedSelector(getPresetNames); const currentPresetIndex = useTypedSelector(getCurrentPresetIndex); const requestPresetAtIndex = useActionCreator(milkdrop_requestPresetAtIndex); const togglePresetOverlay = useActionCreator(actionCreators_togglePresetOverlay); const appendPresetFileList = useActionCreator(milkdrop_appendPresetFileList); const unmountedRef = useUnmountedRef(); const [selectedListIndex, setSelectedListIndex] = (0,react.useState)(() => { if (currentPresetIndex != null) { return listIndexFromPresetIndex(currentPresetIndex); } return 0; }); // Number of presets, plus one for the "Load Local Directory" option, minus // one to convert a length to an index. const maxListIndex = presetKeys.length; // - 1 + 1; const renderList = (0,react.useCallback)(() => { const maxVisibleRows = Math.floor((height - HEIGHT_PADDING) / ENTRY_HEIGHT); const rowsToShow = Math.floor(maxVisibleRows * 0.75); // Only fill 3/4 of the screen. const [startIndex, endIndex] = getRangeCenteredOnIndex(maxListIndex + 1, // Add one to convert an index to a length rowsToShow, selectedListIndex); const presetElms = []; for (let i = startIndex; i <= endIndex; i++) { const presetIndex = presetIndexFromListIndex(i); const isSelected = i === selectedListIndex; const isCurrent = presetIndex === currentPresetIndex; let color; if (isSelected) { color = isCurrent ? "#FFCC22" : "#FF5050"; } else { color = isCurrent ? "#CCFF03" : "#CCCCCC"; } presetElms.push( /*#__PURE__*/(0,jsx_runtime.jsx)("li", { style: { color, lineHeight: `${ENTRY_HEIGHT}px` }, children: i === 0 ? "Load Local Directory" : presetKeys[presetIndex] }, i)); } return presetElms; }, [currentPresetIndex, height, maxListIndex, presetKeys, selectedListIndex]); const loadLocalDir = (0,react.useCallback)(async () => { const fileReferences = await promptForFileReferences({ directory: true }); if (unmountedRef.current) { return; } appendPresetFileList(fileReferences); }, [appendPresetFileList, unmountedRef]); const handleFocusedKeyboardInput = (0,react.useCallback)(e => { switch (e.keyCode) { case 38: // up arrow setSelectedListIndex(value => Math.max(value - 1, 0)); e.stopPropagation(); break; case 40: // down arrow setSelectedListIndex(value => Math.min(value + 1, maxListIndex)); e.stopPropagation(); break; case 13: // enter if (selectedListIndex === 0) { loadLocalDir(); } else { requestPresetAtIndex(presetIndexFromListIndex(selectedListIndex), TransitionType.DEFAULT, true); } e.stopPropagation(); break; case 27: // escape togglePresetOverlay(); e.stopPropagation(); break; } }, [loadLocalDir, maxListIndex, requestPresetAtIndex, selectedListIndex, togglePresetOverlay]); const handleNode = (0,react.useCallback)(node => { if (node != null && document.activeElement !== node) { node.focus(); } }, []); if (presetKeys == null) { return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { style: LOADING_STYLE, children: /*#__PURE__*/(0,jsx_runtime.jsx)("span", { children: "Loading presets" }) }); } return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { ref: handleNode, tabIndex: -1, style: OUTER_WRAPPER_STYLE, onKeyDown: handleFocusedKeyboardInput, children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { style: PresetOverlay_objectSpread(PresetOverlay_objectSpread({}, INNER_WRAPPER_STYLE), {}, { width: width - 20 - WIDTH_PADDING, maxHeight: height - HEIGHT_PADDING }), children: /*#__PURE__*/(0,jsx_runtime.jsx)("ul", { style: { listStyleType: "none", padding: 0, margin: 0 }, children: renderList() }) }) }); } // Find a tuple `[startIndex, endIndex]` representing start/end indexes into an // array of length `length`, that descripe a range of size up to `rangeSize` // where a best effort is made to center `indexToCenter`. function getRangeCenteredOnIndex(length, maxRangeSize, indexToCenter) { const rangeSize = Math.min(length, maxRangeSize); const halfRangeSize = Math.floor(rangeSize / 2); const idealStartIndex = indexToCenter - halfRangeSize; const startIndex = clamp(idealStartIndex, 0, length - rangeSize); const endIndex = startIndex + rangeSize - 1; return [startIndex, endIndex]; } /* harmony default export */ const MilkdropWindow_PresetOverlay = (PresetOverlay); ;// CONCATENATED MODULE: ./js/components/DropTarget.tsx const DropTarget_excluded = ["handleDrop", "windowId"]; function DropTarget_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function DropTarget_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? DropTarget_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : DropTarget_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function supress(e) { e.stopPropagation(); e.preventDefault(); e.dataTransfer.dropEffect = "link"; e.dataTransfer.effectAllowed = "link"; } const DropTarget = props => { const { // eslint-disable-next-line no-shadow, no-unused-vars handleDrop, windowId } = props, passThroughProps = _objectWithoutProperties(props, DropTarget_excluded); const droppedFiles = useActionCreator(files_droppedFiles); const onDrop = (0,react.useCallback)(e => { supress(e); droppedFiles(e, windowId); // TODO: We could probably move this coordinate logic into the playlist. // I think that's the only place it gets used. const { currentTarget } = e; if (!(currentTarget instanceof Element)) { return; } const { left: x, top: y } = currentTarget.getBoundingClientRect(); handleDrop(e, { x, y }); }, [handleDrop, droppedFiles, windowId]); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", DropTarget_objectSpread(DropTarget_objectSpread({}, passThroughProps), {}, { onDragStart: supress, onDragEnter: supress, onDragOver: supress, onDrop: onDrop })); }; /* harmony default export */ const components_DropTarget = (DropTarget); // EXTERNAL MODULE: ./css/context-menu.css var context_menu = __webpack_require__(3234); ;// CONCATENATED MODULE: ./js/components/ContextMenu.tsx const ContextMenu_excluded = ["label", "checked", "className"]; function ContextMenu_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function ContextMenu_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ContextMenu_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ContextMenu_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const Portal = props => { const node = (0,react.useMemo)(() => { const div = document.createElement("div"); div.id = "webamp-context-menu"; div.style.position = "absolute"; div.style.top = "0"; div.style.left = "0"; div.style.zIndex = String(props.zIndex + 1); return div; }, [props.zIndex]); (0,react.useEffect)(() => { document.body.appendChild(node); return () => { document.body.removeChild(node); }; }, [node]); const style = { top: props.top, left: props.left, position: "absolute" }; return /*#__PURE__*/(0,react_dom.createPortal)( /*#__PURE__*/(0,jsx_runtime.jsx)("div", { style: style, children: props.children }), node); }; const ContextMenu_Hr = () => /*#__PURE__*/(0,jsx_runtime.jsx)("li", { className: "hr", children: /*#__PURE__*/(0,jsx_runtime.jsx)("hr", {}) }); const Parent = ({ children, label }) => /*#__PURE__*/(0,jsx_runtime.jsxs)("li", { className: "parent", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("ul", { children: children }), label] }); const LinkNode = props => /*#__PURE__*/_jsx("li", { children: /*#__PURE__*/_jsx("a", ContextMenu_objectSpread(ContextMenu_objectSpread({}, props), {}, { children: props.label })) }); const Node = props => { const { label, checked, className = "" } = props, passThroughProps = _objectWithoutProperties(props, ContextMenu_excluded); return /*#__PURE__*/(0,jsx_runtime.jsx)("li", ContextMenu_objectSpread(ContextMenu_objectSpread({ className: classnames_default()(className, { checked }) }, passThroughProps), {}, { children: label })); }; function ContextMenu({ children, offsetTop, offsetLeft, top, bottom, selected }) { const zIndex = useTypedSelector(getZIndex); if (!selected) { return null; } return /*#__PURE__*/(0,jsx_runtime.jsx)(Portal, { top: offsetTop, left: offsetLeft, zIndex: zIndex, children: /*#__PURE__*/(0,jsx_runtime.jsx)("ul", { className: classnames_default()("context-menu", { top, bottom }), children: children }) }); } ;// CONCATENATED MODULE: ./js/components/ContextMenuWrapper.tsx const ContextMenuWrapper_excluded = ["children", "renderContents"]; function ContextMenuWrapper_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function ContextMenuWrapper_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ContextMenuWrapper_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ContextMenuWrapper_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // Trigger a context menu at the user's cursor position when the user right // clicks within this component. // For a component that triggers relative to a given component when the user // left-clicks see ``. // TODO: Consider using nested contexts to ensure we don't ever have multiple // non-nested context menus open at a time. function ContextMenuWraper(_ref) { var _openPosition$y, _openPosition$x; let { children, renderContents } = _ref, passThroughProps = _objectWithoutProperties(_ref, ContextMenuWrapper_excluded); const [openPosition, setOpenPosition] = (0,react.useState)(null); const closeMenu = (0,react.useCallback)(() => { setOpenPosition(null); }, []); const handleGlobalClick = (0,react.useCallback)(e => { if (e.button !== 2) { if (e.target instanceof Element && e.target.id !== "notClose") { closeMenu(); } } }, [closeMenu]); const handleRightClick = (0,react.useCallback)(e => { const { pageX, pageY } = e; // TODO: We could do an initial render to see if the menu fits here // and do a second render if it does not. setOpenPosition({ x: pageX, y: pageY }); e.preventDefault(); e.stopPropagation(); }, []); // Add click-away listeners when window is open (0,react.useEffect)(() => { if (openPosition == null) { return; } document.addEventListener("click", handleGlobalClick); document.body.addEventListener("contextmenu", closeMenu); return () => { document.removeEventListener("click", handleGlobalClick); document.body.removeEventListener("contextmenu", closeMenu); }; }, [openPosition, closeMenu, handleGlobalClick]); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", ContextMenuWrapper_objectSpread(ContextMenuWrapper_objectSpread({ onContextMenu: handleRightClick, style: { width: "100%", height: "100%" } }, passThroughProps), {}, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu, { selected: openPosition != null, offsetTop: (_openPosition$y = openPosition === null || openPosition === void 0 ? void 0 : openPosition.y) !== null && _openPosition$y !== void 0 ? _openPosition$y : 0, offsetLeft: (_openPosition$x = openPosition === null || openPosition === void 0 ? void 0 : openPosition.x) !== null && _openPosition$x !== void 0 ? _openPosition$x : 0, children: renderContents() }), children] })); } ;// CONCATENATED MODULE: ./js/components/MilkdropWindow/MilkdropContextMenu.tsx // @ts-ignore const MilkdropContextMenu = props => { const desktop = useTypedSelector(getMilkdropDesktopEnabled); const currentPreset = useTypedSelector(getCurrentPreset); const currentLock = useTypedSelector(getMilkdropLockEnabled); const closeWindow = useActionCreator(windows_closeWindow); const toggleDesktop = useActionCreator(toggleMilkdropDesktop); const toggleFullscreen = useActionCreator(toggleMilkdropFullscreen); const toggleLock = useActionCreator(toggleMilkdropLock); const selectNextPreset = useActionCreator(milkdrop_selectNextPreset); const selectPreset = useActionCreator(milkdrop_selectPreset); const presets = butterchurnPresets_min_default().getPresets(); const presetKeys = lodash_default().keys(presets); return /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenuWraper, { renderContents: () => { return /*#__PURE__*/(0,jsx_runtime.jsxs)(jsx_runtime.Fragment, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: toggleFullscreen, label: "Fullscreen", hotkey: "Alt+Enter" }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: toggleLock, label: "Lock preset", checked: currentLock }), /*#__PURE__*/(0,jsx_runtime.jsx)(Parent, { label: "Select preset", children: presetKeys.map(presetKey => { return /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: () => selectPreset(presetKey), label: presetKey, checked: presetKey == currentPreset }); }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: () => closeWindow(WINDOWS.MILKDROP), label: "Quit" })] }); }, children: props.children }); }; /* harmony default export */ const MilkdropWindow_MilkdropContextMenu = (MilkdropContextMenu); ;// CONCATENATED MODULE: ./js/components/MilkdropWindow/Desktop.tsx const Desktop = /*#__PURE__*/react.memo(({ children }) => { const [desktopNode] = react.useState(() => document.createElement("div")); react.useEffect(() => { desktopNode.classList.add("webamp-desktop"); document.body.appendChild(desktopNode); return () => { document.body.removeChild(desktopNode); }; }, [desktopNode]); return /*#__PURE__*/react_dom.createPortal(children, desktopNode); }); /* harmony default export */ const MilkdropWindow_Desktop = (Desktop); ;// CONCATENATED MODULE: ./js/components/MilkdropWindow/index.tsx function MilkdropWindow_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function MilkdropWindow_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? MilkdropWindow_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : MilkdropWindow_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const MILLISECONDS_BETWEEN_PRESET_TRANSITIONS = 15000; function useKeyHandler() { const trackTitle = useTypedSelector(getCurrentTrackDisplayName); const selectNextPreset = useActionCreator(milkdrop_selectNextPreset); const selectPreviousPreset = useActionCreator(milkdrop_selectPreviousPreset); const toggleRandomize = useActionCreator(toggleRandomizePresets); const togglePresetOverlay = useActionCreator(actionCreators_togglePresetOverlay); const scheduleMilkdropMessage = useActionCreator(milkdrop_scheduleMilkdropMessage); const toggleCycling = useActionCreator(togglePresetCycling); // Handle keyboard events return (0,react.useCallback)(e => { switch (e.keyCode) { case 32: // spacebar selectNextPreset(); break; case 8: // backspace selectPreviousPreset(TransitionType.IMMEDIATE); break; case 72: // H selectNextPreset(TransitionType.IMMEDIATE); break; case 82: // R toggleRandomize(); break; case 76: // L togglePresetOverlay(); e.stopPropagation(); break; case 84: // T if (trackTitle != null) { scheduleMilkdropMessage(trackTitle); } e.stopPropagation(); break; case 145: // scroll lock case 125: // F14 (scroll lock for OS X) toggleCycling(); break; } }, [scheduleMilkdropMessage, selectNextPreset, selectPreviousPreset, toggleCycling, togglePresetOverlay, toggleRandomize, trackTitle]); } function Milkdrop({ analyser }) { const desktop = useTypedSelector(getMilkdropDesktopEnabled); const fullscreen = useTypedSelector(getMilkdropFullscreenEnabled); const overlay = useTypedSelector(getPresetOverlayOpen); const presetsAreCycling = useTypedSelector(getPresetsAreCycling); const currentPresetIndex = useTypedSelector(getCurrentPresetIndex); const mediaIsPlaying = useTypedSelector(getMediaIsPlaying); const toggleFullscreen = useActionCreator(toggleMilkdropFullscreen); const selectNextPreset = useActionCreator(milkdrop_selectNextPreset); const handlePresetDrop = useActionCreator(milkdrop_handlePresetDrop); const setFullscreen = useActionCreator(setMilkdropFullscreen); const handleKeyDown = useKeyHandler(); // Cycle presets (0,react.useEffect)(() => { if (!presetsAreCycling || !mediaIsPlaying) { return; } const intervalId = setInterval(selectNextPreset, MILLISECONDS_BETWEEN_PRESET_TRANSITIONS); return () => clearInterval(intervalId); }, [presetsAreCycling, currentPresetIndex, mediaIsPlaying, selectNextPreset]); const screenSize = useScreenSize(); const windowSize = useWindowSize(); if (desktop) { return /*#__PURE__*/(0,jsx_runtime.jsx)(MilkdropWindow_Desktop, { children: /*#__PURE__*/(0,jsx_runtime.jsx)(MilkdropWindow_MilkdropContextMenu, { children: /*#__PURE__*/(0,jsx_runtime.jsx)(MilkdropWindow_Visualizer, MilkdropWindow_objectSpread(MilkdropWindow_objectSpread({}, windowSize), {}, { analyser: analyser })) }) }); } return /*#__PURE__*/(0,jsx_runtime.jsx)(components_GenWindow, { title: "Milkdrop", windowId: WINDOWS.MILKDROP, onKeyDown: handleKeyDown, children: genWindowSize => { const size = fullscreen ? screenSize : genWindowSize; return /*#__PURE__*/(0,jsx_runtime.jsx)(MilkdropWindow_MilkdropContextMenu, { children: /*#__PURE__*/(0,jsx_runtime.jsx)(MilkdropWindow_Background, { children: /*#__PURE__*/(0,jsx_runtime.jsxs)(components_DropTarget, { windowId: WINDOWS.MILKDROP, handleDrop: handlePresetDrop, children: [overlay && /*#__PURE__*/(0,jsx_runtime.jsx)(MilkdropWindow_PresetOverlay, MilkdropWindow_objectSpread({}, size)), /*#__PURE__*/(0,jsx_runtime.jsx)(Fullscreen, { enabled: fullscreen, onChange: setFullscreen, children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { onDoubleClick: toggleFullscreen, children: /*#__PURE__*/(0,jsx_runtime.jsx)(MilkdropWindow_Visualizer, MilkdropWindow_objectSpread(MilkdropWindow_objectSpread({}, size), {}, { analyser: analyser })) }) })] }) }) }); } }); } /* harmony default export */ const MilkdropWindow = (Milkdrop); ;// CONCATENATED MODULE: ./js/components/PlaybackContextMenu.tsx const PlaybackContextMenu = () => { const previous = useActionCreator(media_previous); const play = useActionCreator(media_play); const pause = useActionCreator(media_pause); const stop = useActionCreator(media_stop); const next = useActionCreator(media_next); const seekForward = useActionCreator(media_seekForward); const seekBackward = useActionCreator(media_seekBackward); const nextN = useActionCreator(media_nextN); return /*#__PURE__*/(0,jsx_runtime.jsxs)(react.Fragment, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Previous", hotkey: "Z", onClick: previous }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Play", hotkey: "X", onClick: play }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Pause", hotkey: "C", onClick: pause }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Stop", hotkey: "V", onClick: stop }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Next", hotkey: "B", onClick: next }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Back 5 seconds", hotkey: "Left", onClick: () => seekBackward(5) }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Fwd 5 seconds", hotkey: "Right", onClick: () => seekForward(5) }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "10 tracks back", hotkey: "Num. 1", onClick: () => nextN(-10) }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "10 tracks fwd", hotkey: "Num. 3", onClick: () => nextN(10) })] }); }; /* harmony default export */ const components_PlaybackContextMenu = (PlaybackContextMenu); ;// CONCATENATED MODULE: ./js/components/OptionsContextMenu.tsx const { ipcRenderer: OptionsContextMenu_ipcRenderer } = window.require('electron'); const OptionsContextMenu = () => { const toggleTimeMode = useActionCreator(media_toggleTimeMode); const toggleDoubleSizeMode = useActionCreator(windows_toggleDoubleSizeMode); const toggleRepeat = useActionCreator(media_toggleRepeat); const toggleShuffle = useActionCreator(media_toggleShuffle); const doubled = useTypedSelector(getDoubled); const timeMode = useTypedSelector(getTimeMode); const repeat = useTypedSelector(getRepeat); const shuffle = useTypedSelector(getShuffle); return /*#__PURE__*/(0,jsx_runtime.jsxs)(jsx_runtime.Fragment, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438", onClick: async () => { OptionsContextMenu_ipcRenderer.invoke("resetSettings").then(() => {}); } }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Time elapsed", hotkey: "(Ctrl+T toggles)", onClick: toggleTimeMode, checked: timeMode === TIME_MODE.ELAPSED }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Time remaining", hotkey: "(Ctrl+T toggles)", onClick: toggleTimeMode, checked: timeMode === TIME_MODE.REMAINING }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Double Size", hotkey: "Ctrl+D", onClick: toggleDoubleSizeMode, checked: doubled }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Repeat", hotkey: "R", onClick: toggleRepeat, checked: repeat }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Shuffle", hotkey: "S", onClick: toggleShuffle, checked: shuffle })] }); }; /* harmony default export */ const components_OptionsContextMenu = (OptionsContextMenu); ;// CONCATENATED MODULE: ./js/components/SkinsContextMenu.tsx const SkinContextMenu = () => { const loadDefaultSkin = useActionCreator(actionCreators_loadDefaultSkin); const openSkinFileDialog = useActionCreator(files_openSkinFileDialog); const setSkin = useActionCreator(setSkinFromUrl); const availableSkins = useTypedSelector(getAvaliableSkins); return /*#__PURE__*/(0,jsx_runtime.jsxs)(Parent, { label: "Skins", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: openSkinFileDialog, label: "Load Skin..." }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: loadDefaultSkin, label: "" }), availableSkins.map(skin => /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: () => setSkin(skin.url), label: skin.name }, skin.url))] }); }; /* harmony default export */ const SkinsContextMenu = (SkinContextMenu); ;// CONCATENATED MODULE: ./js/components/MainWindow/MainContextMenu.tsx const { ipcRenderer: MainContextMenu_ipcRenderer } = window.require('electron'); const MainContextMenu = /*#__PURE__*/(0,react.memo)(({ filePickers }) => { var _userSettings$api2, _userSettings$api3; const networkConnected = useTypedSelector(getNetworkConnected); const genWindows = useTypedSelector(getGenWindows); const close = useActionCreator(actionCreators_close); const openMediaFileDialog = useActionCreator(files_openMediaFileDialog); const loadMediaFiles = useActionCreator(files_loadMediaFiles); const toggleWindow = useActionCreator(windows_toggleWindow); const menuOpened = useActionCreator(() => ({ type: "MAIN_CONTEXT_MENU_OPENED" })); const [playlists, setPlaylists] = (0,react.useState)([]); const [artists, setArtists] = (0,react.useState)([]); const [albums, setAlbums] = (0,react.useState)([]); const [rotors, setRotors] = (0,react.useState)([]); const [playlistgetted, setPlaylistgetted] = (0,react.useState)(false); const [searchResult, setsearchResult] = (0,react.useState)([]); const [lendings, setLendings] = (0,react.useState)([]); const [data, setData] = (0,react.useState)([]); const [userSettings, setUserSettings] = (0,react.useState)([]); const [apiPort, setApiPort] = (0,react.useState)('8080'); const handleChange = event => { MainContextMenu_ipcRenderer.invoke("search", { searchText: event.target.value }).then(rs => { setsearchResult(rs); }); }; const handleApiPortChange = event => { const port = event.target.value.toString(); setApiPort(port); }; const handleApiPortSave = async () => { const port = parseInt(apiPort) || 8080; await MainContextMenu_ipcRenderer.invoke("setApiSettings", { port: port }); MainContextMenu_ipcRenderer.invoke('getSettings').then(rs => { setUserSettings(JSON.parse(rs)); }); }; const handleApiToggle = async () => { var _userSettings$api; const newEnabled = !((_userSettings$api = userSettings.api) !== null && _userSettings$api !== void 0 && _userSettings$api.enabled || false); await MainContextMenu_ipcRenderer.invoke("setApiSettings", { enabled: newEnabled }); MainContextMenu_ipcRenderer.invoke('getSettings').then(rs => { setUserSettings(JSON.parse(rs)); }); }; (0,react.useEffect)(() => { if (!playlistgetted) { setPlaylistgetted(true); MainContextMenu_ipcRenderer.invoke("nowPlaylist").then(data => { setData(data); }); MainContextMenu_ipcRenderer.invoke('getUserPlaylists').then(rs => { setPlaylists(rs); }); MainContextMenu_ipcRenderer.invoke('getUserArtists').then(rs => { setArtists(rs); }); MainContextMenu_ipcRenderer.invoke('getUserAlbums').then(rs => { setAlbums(rs); }); MainContextMenu_ipcRenderer.invoke('getRotor').then(rs => { setRotors(rs); }); MainContextMenu_ipcRenderer.invoke('lendings').then(rs => { setLendings(rs); }); MainContextMenu_ipcRenderer.invoke('getSettings').then(rs => { var _settings$api; const settings = JSON.parse(rs); setUserSettings(settings); if ((_settings$api = settings.api) !== null && _settings$api !== void 0 && _settings$api.port) { setApiPort(settings.api.port.toString()); } }); } menuOpened(); }, [menuOpened]); return /*#__PURE__*/(0,jsx_runtime.jsxs)(react.Fragment, { children: [data.uid ? /*#__PURE__*/(0,jsx_runtime.jsxs)(jsx_runtime.Fragment, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("openLink", { link: "https://yaamp.ru/" }).then(() => {}); }, label: data.title }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setPlaylistRecomendation", { uid: data.uid, kind: data.kind }).then(() => {}); }, label: "\u0420\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0430\u0446\u0438\u0438 \u043F\u043E \u043F\u043B\u0435\u0439\u043B\u0438\u0441\u0442\u0443" })] }) : /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("openLink", { link: "https://yaamp.ru/" }).then(() => {}); }, label: "Yaamp" }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setMywave").then(() => {}); }, label: "\u041C\u043E\u044F \u0432\u043E\u043B\u043D\u0430" }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setMyloved").then(() => {}); }, label: "\u041B\u044E\u0431\u0438\u043C\u044B\u0435 \u0442\u0440\u0435\u043A\u0438" }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Parent, { label: "\u041D\u0430\u0447\u0430\u043B\u044C\u043D\u044B\u0435 \u043F\u043B\u0435\u0439\u043B\u0438\u0441\u0442\u044B", children: lendings.map(result => { return /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setPlaylist", { uid: result.data.data.uid, kind: result.data.data.kind }).then(() => {}); }, label: result.data.data.title }); }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsxs)(Parent, { label: "\u041F\u043E\u0438\u0441\u043A...", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("li", { className: "input", id: "notClose", children: /*#__PURE__*/(0,jsx_runtime.jsx)("input", { className: "searchField", type: "text", id: "notClose", placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442...", onChange: handleChange }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), searchResult.map(result => { return /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { if (result.type == 'artist') { MainContextMenu_ipcRenderer.invoke("setArtist", { id: result.id }).then(() => {}); } if (result.type == 'album') { MainContextMenu_ipcRenderer.invoke("setAlbum", { id: result.id }).then(() => {}); } }, label: result.name }); })] }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Parent, { label: "\u041F\u043B\u0435\u0439\u043B\u0438\u0441\u0442\u044B", children: playlists.map(playlist => { return /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setPlaylist", { uid: playlist.uid, kind: playlist.kind }).then(() => {}); }, label: playlist.title }); }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(Parent, { label: "\u0418\u0441\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u0438", children: artists.map(artist => { return /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setArtist", { id: artist.id }).then(() => {}); }, label: artist.title }); }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(Parent, { label: "\u0410\u043B\u044C\u0431\u043E\u043C\u044B", children: albums.map(album => { return /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setAlbum", { id: album.id }).then(() => {}); }, label: album.title }); }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(Parent, { label: "\u0421\u0442\u0430\u043D\u0446\u0438\u0438", children: rotors.map(rotor => { return /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setRotor", { id: rotor.id }).then(() => {}); }, label: rotor.title }); }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("openPlayNow").then(() => {}); }, label: "\u0421\u0435\u0439\u0447\u0430\u0441 \u0438\u0433\u0440\u0430\u0435\u0442..." }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setLike").then(() => {}); }, label: "\u041B\u0430\u0439\u043A" }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setDislike").then(() => {}); }, label: "\u0414\u0438\u0437\u043B\u0430\u0439\u043A" }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), Object.keys(genWindows).map(i => /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: genWindows[i].title, checked: genWindows[i].open, onClick: () => toggleWindow(i), hotkey: genWindows[i].hotkey }, i)), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(SkinsContextMenu, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsxs)(Parent, { label: "\u0423\u0432\u0435\u043B\u0438\u0447\u0435\u043D\u0438\u0435", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setRatio", { value: 1 }).then(() => {}); }, label: "x1", checked: userSettings.zoom === 1 }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setRatio", { value: 1.2 }).then(() => {}); }, label: "x1.2", checked: userSettings.zoom === 1.2 }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setRatio", { value: 1.4 }).then(() => {}); }, label: "x1.4", checked: userSettings.zoom === 1.4 }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setRatio", { value: 1.6 }).then(() => {}); }, label: "x1.6", checked: userSettings.zoom === 1.6 }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("setRatio", { value: 1.8 }).then(() => {}); }, label: "x1.8", checked: userSettings.zoom === 1.8 })] }), /*#__PURE__*/(0,jsx_runtime.jsx)(Parent, { label: "Options", children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_OptionsContextMenu, {}) }), /*#__PURE__*/(0,jsx_runtime.jsx)(Parent, { label: "Playback", children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_PlaybackContextMenu, {}) }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsxs)(Parent, { label: "API", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: handleApiToggle, label: (_userSettings$api2 = userSettings.api) !== null && _userSettings$api2 !== void 0 && _userSettings$api2.enabled ? "Выключить API" : "Включить API", checked: ((_userSettings$api3 = userSettings.api) === null || _userSettings$api3 === void 0 ? void 0 : _userSettings$api3.enabled) || false }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)("li", { className: "input", id: "notClose", children: /*#__PURE__*/(0,jsx_runtime.jsx)("input", { className: "searchField", type: "number", id: "notClose", placeholder: "\u041F\u043E\u0440\u0442 (8080)", value: apiPort, onChange: handleApiPortChange, onBlur: handleApiPortSave, min: "1024", max: "65535" }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: handleApiPortSave, label: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u043F\u043E\u0440\u0442" })] }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("openLink", { link: "https://yaamp.ru/donate.php" }).then(() => {}); }, label: "\u041F\u043E\u0434\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u043F\u0440\u043E\u0435\u043A\u0442" }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: async () => { MainContextMenu_ipcRenderer.invoke("logout").then(() => {}); }, label: "\u0412\u044B\u0439\u0442\u0438 \u0438\u0437 \u0430\u043A\u043A\u0430\u0443\u043D\u0442\u0430" }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: close, label: "Exit" })] }); }); /* harmony default export */ const MainWindow_MainContextMenu = (MainContextMenu); ;// CONCATENATED MODULE: ./js/components/WindowManager.tsx function WindowManager_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function WindowManager_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? WindowManager_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : WindowManager_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const { ipcRenderer: WindowManager_ipcRenderer } = window.require('electron'); const abuts = (a, b) => { // TODO: This is kinda a hack. They should really be touching, not just within snapping distance. // Also, overlapping should not count. const wouldMoveTo = snap(a, b); return wouldMoveTo.x !== undefined || wouldMoveTo.y !== undefined; }; let posOnStart = false; function useHandleMouseDown(propsWindows) { const windowsInfo = useTypedSelector(getWindowsInfo); const getOpen = useTypedSelector(selectors_getWindowOpen); const getWindowHidden = useTypedSelector(selectors_getWindowHidden); const browserWindowSize = useTypedSelector(getBrowserWindowSize); const updateWindowPositions = useActionCreator(windows_updateWindowPositions); const [draggingState, setDraggingState] = (0,react.useState)(null); // When the mouse is down, attach a listener to track mouse move events. (0,react.useEffect)(() => { if (draggingState == null) { return; } const { boundingBox, moving, stationary, mouseStart } = draggingState; const handleMouseMove = ee => { const proposedDiff = { x: ee.clientX - mouseStart.x, y: ee.clientY - mouseStart.y }; const proposedWindows = moving.map(node => WindowManager_objectSpread(WindowManager_objectSpread({}, node), applyDiff(node, proposedDiff))); const proposedBox = WindowManager_objectSpread(WindowManager_objectSpread({}, boundingBox), applyDiff(boundingBox, proposedDiff)); const snapDiff = snapDiffManyToMany(proposedWindows, stationary); const withinDiff = snapWithinDiff(proposedBox, browserWindowSize); const finalDiff = applyMultipleDiffs(proposedDiff, snapDiff, withinDiff); const windowPositionDiff = {}; moving.forEach(w => { windowPositionDiff[w.key] = applyDiff(w, finalDiff); }); // Log the updated positions of the windows being moved WindowManager_ipcRenderer.invoke("movingWindowStarted", { windows: windowsInfo }).then(() => {}); updateWindowPositions(windowPositionDiff, false); }; function handleMouseUp() { setDraggingState(null); // Log that window movement has ended WindowManager_ipcRenderer.invoke("movingWindowEnded", { windows: windowsInfo }).then(() => {}); } window.addEventListener("mouseup", handleMouseUp); window.addEventListener("mousemove", handleMouseMove); return () => { window.removeEventListener("mousemove", handleMouseMove); window.removeEventListener("mouseup", handleMouseUp); }; }, [browserWindowSize, draggingState, updateWindowPositions]); // Mouse down handler return (0,react.useCallback)((key, e) => { if (!e.target.classList.contains("draggable")) { return; } if (getWindowHidden(key)) { // The user may be clicking on full screen Milkdrop. return; } const windows = windowsInfo.filter(w => propsWindows[w.key] != null && !getWindowHidden(w.key)); const targetNode = windows.find(node => node.key === key); if (targetNode == null) { throw new Error(`Tried to move a node that does not exist: ${key}`); } let movingSet = new Set([targetNode]); // Only the main window brings other windows along. if (key === "main") { const findAllConnected = traceConnection(abuts); movingSet = findAllConnected(windows, targetNode); } const stationary = windows.filter(w => !movingSet.has(w)); const moving = Array.from(movingSet); const mouseStart = { x: e.clientX, y: e.clientY }; const boundingBox = snapUtils_boundingBox(moving); setDraggingState({ boundingBox, moving, stationary, mouseStart }); }, [getWindowHidden, propsWindows, windowsInfo]); } function WindowManager({ windows: propsWindows }) { const windowsInfo = useTypedSelector(getWindowsInfo); const setFocusedWindow = useActionCreator(windows_setFocusedWindow); const handleMouseDown = useHandleMouseDown(propsWindows); const updateWindowPositions = useActionCreator(windows_updateWindowPositions); const centerWindowsInView = useActionCreator(windows_centerWindowsInView); const setWindowSize = useActionCreator(windows_setWindowSize); const toggleWindow = useActionCreator(windows_toggleWindow); const windows = windowsInfo.filter(w => propsWindows[w.key]); if (!posOnStart) { if (document.getElementById('playlist-window')) { WindowManager_ipcRenderer.invoke('getSettings').then(rs => { const settingsData = JSON.parse(rs); console.log(settingsData); if (settingsData.windows) { WindowManager_ipcRenderer.invoke('movingWindowStarted').then(() => { let obj = windows.find((o, i) => { if (o.key === 'main') { windows[i].x = settingsData.windows.mainWindow.x; windows[i].y = settingsData.windows.mainWindow.y; } if (o.key === 'playlist') { windows[i].x = settingsData.windows.playlistWindow.x; windows[i].y = settingsData.windows.playlistWindow.y; setWindowSize(o.key, settingsData.windows.playlistWindow.size); } if (o.key === 'equalizer') { windows[i].x = settingsData.windows.equalizerWindow.x; windows[i].y = settingsData.windows.equalizerWindow.y; } if (o.key === 'milkdrop') { windows[i].x = settingsData.windows.milkdropWindow.x; windows[i].y = settingsData.windows.milkdropWindow.y; setWindowSize(o.key, settingsData.windows.milkdropWindow.size); } }); const newPositions = windowsInfo.reduce((pos, w) => WindowManager_objectSpread(WindowManager_objectSpread({}, pos), {}, { [w.key]: { x: w.x, y: w.y } }), {}); updateWindowPositions(newPositions, false); centerWindowsInView(); if (!settingsData.windows.playlistWindow.visible) { toggleWindow('playlist'); } if (!settingsData.windows.equalizerWindow.visible) { toggleWindow('equalizer'); } WindowManager_ipcRenderer.invoke('movingWindowEndedWithoutSave').then(() => {}); posOnStart = true; }); } }); } } const onBlur = (0,react.useCallback)( // I give up on trying to type things with `relatedTarget`. e => { const { currentTarget, relatedTarget } = e; if (currentTarget === relatedTarget || currentTarget.contains(relatedTarget)) { return; } setFocusedWindow(null); }, [setFocusedWindow]); return /*#__PURE__*/(0,jsx_runtime.jsx)(jsx_runtime.Fragment, { children: windows.map(w => /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: w.key, onBlur: onBlur, onMouseDown: e => { handleMouseDown(w.key, e); }, style: { position: "absolute", top: 0, left: 0, transform: `translate(${w.x}px, ${w.y}px)` }, children: propsWindows[w.key] }, w.key)) }); } // EXTERNAL MODULE: ../../node_modules/lodash/deburr.js var deburr = __webpack_require__(7329); var deburr_default = /*#__PURE__*/__webpack_require__.n(deburr); ;// CONCATENATED MODULE: ./js/components/Character.tsx const Character_excluded = ["children", "className"]; function Character_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function Character_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? Character_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : Character_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } const characterClassName = char => `character-${deburr_default()(char.toString()).toLowerCase().charCodeAt(0)}`; const Character = /*#__PURE__*/react.memo(_ref => { let { children: char, className } = _ref, passThrough = _objectWithoutProperties(_ref, Character_excluded); return /*#__PURE__*/(0,jsx_runtime.jsx)("span", Character_objectSpread(Character_objectSpread({}, passThrough), {}, { className: `${className || ""} character ${characterClassName(char)}`, children: char })); }); /* harmony default export */ const components_Character = (Character); // EXTERNAL MODULE: ./css/mini-time.css var mini_time = __webpack_require__(3362); ;// CONCATENATED MODULE: ./js/components/MiniTime.tsx // Sigh. When the display is blinking (say when it's paused) we need to // alternate between the actual character and the space character. Not // Possible to do that in pure CSS with the background being dynamically generated. // All "space" characters is also how Winamp renders no content. const MiniTime_Background = () => /*#__PURE__*/(0,jsx_runtime.jsx)(react.Fragment, { children: [1, 7, 12, 20, 25].map((left, i) => /*#__PURE__*/(0,jsx_runtime.jsx)(components_Character, { style: { left }, className: "background-character", children: " " }, i)) }); const MiniTime = () => { const status = useTypedSelector(getMediaStatus); const duration = useTypedSelector(getDuration); const timeElapsed = useTypedSelector(getTimeElapsed); const timeMode = useTypedSelector(getTimeMode); const toggle = useActionCreator(media_toggleTimeMode); let seconds = null; // TODO: Clean this up: If stopped, just render the background, rather than // rendering spaces twice. if (status !== MEDIA_STATUS.STOPPED && duration != null) { seconds = timeMode === TIME_MODE.ELAPSED ? timeElapsed : duration - timeElapsed; } const timeObj = getTimeObj(seconds); const showMinus = timeMode === TIME_MODE.REMAINING && status !== MEDIA_STATUS.STOPPED; return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { onClick: toggle, className: classnames_default()("mini-time", "countdown", { blinking: status === MEDIA_STATUS.PAUSED }), children: [/*#__PURE__*/(0,jsx_runtime.jsx)(MiniTime_Background, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(components_Character, { style: { left: 1 }, children: showMinus ? "-" : " " }), /*#__PURE__*/(0,jsx_runtime.jsx)(components_Character, { style: { left: 7 }, children: timeObj.minutesFirstDigit }), /*#__PURE__*/(0,jsx_runtime.jsx)(components_Character, { style: { left: 12 }, children: timeObj.minutesSecondDigit }), /*#__PURE__*/(0,jsx_runtime.jsx)(components_Character, { style: { left: 20 }, children: timeObj.secondsFirstDigit }), /*#__PURE__*/(0,jsx_runtime.jsx)(components_Character, { style: { left: 25 }, children: timeObj.secondsSecondDigit })] }); }; /* harmony default export */ const components_MiniTime = (MiniTime); ;// CONCATENATED MODULE: ./js/components/ClickedDiv.tsx function ClickedDiv_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function ClickedDiv_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ClickedDiv_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ClickedDiv_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // Winamp has a strange behavior for the buttons at the top of the main window. // It shows through to the main background sprite until the first time that it's // clicked, and then it shows the dedicated undepressed sprite thereafter. // This component is an abstraction that tracks if a div has ever been clicked. // Look in `skinSelectors` for CSS selectors that look like `#some-id.clicked` // for examples of this functionality in use. function ClickedDiv(props) { const [clicked, setClicked] = (0,react.useState)(false); function handleMouseDown(e) { setClicked(true); if (props.onMouseDown) { props.onMouseDown(e); } } return /*#__PURE__*/(0,jsx_runtime.jsx)("div", ClickedDiv_objectSpread(ClickedDiv_objectSpread({}, props), {}, { className: classnames_default()(props.className, { clicked }), onMouseDown: handleMouseDown })); } /* harmony default export */ const components_ClickedDiv = (ClickedDiv); ;// CONCATENATED MODULE: ./js/components/ContextMenuTarget.tsx const ContextMenuTarget_excluded = ["renderMenu", "children", "top", "bottom"]; function ContextMenuTarget_ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function ContextMenuTarget_objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ContextMenuTarget_ownKeys(Object(t), !0).forEach(function (r) { (0,defineProperty/* default */.Z)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ContextMenuTarget_ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function getNodeOffset(node) { if (node == null) { return { top: 0, left: 0 }; } const rect = node.getBoundingClientRect(); const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; const scrollTop = window.pageYOffset || document.documentElement.scrollTop; return { top: rect.top + scrollTop, left: rect.left + scrollLeft }; } // Trigger a context menu relative to the child element when the user // left-clicks on the child. // // For a component that triggers relative to the user's cursor on right-click // see ``. function ContextMenuTarget(props) { const handleNode = (0,react.useRef)(null); const [selected, setSelected] = (0,react.useState)(false); (0,react.useEffect)(() => { if (!selected) { return; } function handleGlobalClick(e) { if (selected && // Typescript does not believe that these click events are always fired on DOM nodes. e.target instanceof Element && selected && // Not sure how, but it's possible for this to get called when handleNode is null/undefined. // https://sentry.io/share/issue/2066cd79f21e4f279791319f4d2ea35d/ handleNode.current && !handleNode.current.contains(e.target)) { setSelected(false); } } document.addEventListener("click", handleGlobalClick); return () => { document.removeEventListener("click", handleGlobalClick); }; }, [selected]); const offset = (0,react.useMemo)(() => { return selected ? getNodeOffset(handleNode.current) : // Kinda awkward. This is a nonsense return value since we only use //this value when we are selected. { top: 0, left: 0 }; }, [selected]); const { renderMenu, children, top, bottom } = props, passThroughProps = _objectWithoutProperties(props, ContextMenuTarget_excluded); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", ContextMenuTarget_objectSpread(ContextMenuTarget_objectSpread({}, passThroughProps), {}, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "handle", style: { width: "100%", height: "100%" }, ref: handleNode, onClick: () => setSelected(!selected), children: children }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu, { selected: selected, offsetTop: offset.top, offsetLeft: offset.left, top: top, bottom: bottom, children: renderMenu() })] })); } /* harmony default export */ const components_ContextMenuTarget = (ContextMenuTarget); ;// CONCATENATED MODULE: ./js/components/useOscilloscopeVisualizer.ts const PIXEL_DENSITY = 2; // Return the average value in a slice of dataArray function sliceAverage(dataArray, sliceWidth, sliceNumber) { const start = sliceWidth * sliceNumber; const end = start + sliceWidth; let sum = 0; for (let i = start; i < end; i++) { sum += dataArray[i]; } return sum / sliceWidth; } function usePaintOscilloscopeFrame({ analyser, height, width, renderWidth }) { const colors = useTypedSelector(getSkinColors); const bufferLength = analyser.fftSize; const dataArray = (0,react.useMemo)(() => { return new Uint8Array(bufferLength); }, [bufferLength]); return (0,react.useCallback)(canvasCtx => { analyser.getByteTimeDomainData(dataArray); canvasCtx.lineWidth = PIXEL_DENSITY; // Just use one of the viscolors for now canvasCtx.strokeStyle = colors[18]; // Since dataArray has more values than we have pixels to display, we // have to average several dataArray values per pixel. We call these // groups slices. // // We use the 2x scale here since we only want to plot values for // "real" pixels. const sliceWidth = Math.floor(bufferLength / width) * PIXEL_DENSITY; const h = height; canvasCtx.beginPath(); // Iterate over the width of the canvas in "real" pixels. for (let j = 0; j <= renderWidth; j++) { const amplitude = sliceAverage(dataArray, sliceWidth, j); const percentAmplitude = amplitude / 255; // dataArray gives us bytes const y = (1 - percentAmplitude) * h; // flip y const x = j * PIXEL_DENSITY; // Canvas coordinates are in the middle of the pixel by default. // When we want to draw pixel perfect lines, we will need to // account for that here if (x === 0) { canvasCtx.moveTo(x, y); } else { canvasCtx.lineTo(x, y); } } canvasCtx.stroke(); }, [analyser, bufferLength, colors, dataArray, height, renderWidth, width]); } ;// CONCATENATED MODULE: ./js/components/useBarVisualizer.ts const useBarVisualizer_PIXEL_DENSITY = 2; const BAR_WIDTH = 3 * useBarVisualizer_PIXEL_DENSITY; const GRADIENT_COLOR_COUNT = 16; const PEAK_COLOR_INDEX = 23; const BAR_PEAK_DROP_RATE = 0.01; const NUM_BARS = 20; function octaveBucketsForBufferLength(bufferLength) { const octaveBuckets = new Array(NUM_BARS).fill(0); const minHz = 200; const maxHz = 22050; const octaveStep = Math.pow(maxHz / minHz, 1 / NUM_BARS); octaveBuckets[0] = 0; octaveBuckets[1] = minHz; for (let i = 2; i < NUM_BARS - 1; i++) { octaveBuckets[i] = octaveBuckets[i - 1] * octaveStep; } octaveBuckets[NUM_BARS - 1] = maxHz; for (let i = 0; i < NUM_BARS; i++) { const octaveIdx = Math.floor(octaveBuckets[i] / maxHz * bufferLength); octaveBuckets[i] = octaveIdx; } return octaveBuckets; } function preRenderBar(height, colors, renderHeight) { /** * The order of the colours is commented in the file: the fist two colours * define the background and dots (check it to see what are the dots), the * next 16 colours are the analyzer's colours from top to bottom, the next * 5 colours are the oscilloscope's ones, from center to top/bottom, the * last colour is for the analyzer's peak markers. */ // Off-screen canvas for pre-rendering a single bar gradient const barCanvas = document.createElement("canvas"); barCanvas.width = BAR_WIDTH; barCanvas.height = height; const offset = 2; // The first two colors are for the background; const gradientColors = colors.slice(offset, offset + GRADIENT_COLOR_COUNT); const barCanvasCtx = barCanvas.getContext("2d"); if (barCanvasCtx == null) { throw new Error("Could not construct canvas context"); } const multiplier = GRADIENT_COLOR_COUNT / renderHeight; // In shade mode, the five colors are, from top to bottom: // 214, 102, 0 -- 3 // 222, 165, 24 -- 6 // 148, 222, 33 -- 9 // 57, 181, 16 -- 12 // 24, 132, 8 -- 15 // TODO: This could probably be improved by iterating backwards for (let i = 0; i < renderHeight; i++) { const colorIndex = GRADIENT_COLOR_COUNT - 1 - Math.floor(i * multiplier); barCanvasCtx.fillStyle = gradientColors[colorIndex]; const y = height - i * useBarVisualizer_PIXEL_DENSITY; barCanvasCtx.fillRect(0, y, BAR_WIDTH, useBarVisualizer_PIXEL_DENSITY); } return barCanvas; } function usePaintBar({ renderHeight, height }) { const colors = useTypedSelector(getSkinColors); const getWindowShade = useTypedSelector(selectors_getWindowShade); const windowShade = getWindowShade("main"); const barCanvas = (0,react.useMemo)(() => { return preRenderBar(height, colors, renderHeight); }, [colors, height, renderHeight]); return (0,react.useCallback)((ctx, x, barHeight, peakHeight) => { barHeight = Math.ceil(barHeight) * useBarVisualizer_PIXEL_DENSITY; peakHeight = Math.ceil(peakHeight) * useBarVisualizer_PIXEL_DENSITY; if (barHeight > 0 || peakHeight > 0) { const y = height - barHeight; // Draw the gradient const b = BAR_WIDTH; if (height > 0) { ctx.drawImage(barCanvas, 0, y, b, height, x, y, b, height); } // Draw the gray peak line if (!windowShade) { const peakY = height - peakHeight; ctx.fillStyle = colors[PEAK_COLOR_INDEX]; ctx.fillRect(x, peakY, b, useBarVisualizer_PIXEL_DENSITY); } } }, [barCanvas, colors, height, windowShade]); } function usePaintBarFrame({ renderHeight, height, analyser }) { const [barPeaks] = (0,react.useState)(() => new Array(NUM_BARS).fill(0)); const [barPeakFrames] = (0,react.useState)(() => new Array(NUM_BARS).fill(0)); const bufferLength = analyser.frequencyBinCount; const octaveBuckets = (0,react.useMemo)(() => { return octaveBucketsForBufferLength(bufferLength); }, [bufferLength]); const dataArray = (0,react.useMemo)(() => { return new Uint8Array(bufferLength); }, [bufferLength]); const paintBar = usePaintBar({ height, renderHeight }); return (0,react.useCallback)(canvasCtx => { analyser.getByteFrequencyData(dataArray); const heightMultiplier = renderHeight / 256; const xOffset = BAR_WIDTH + useBarVisualizer_PIXEL_DENSITY; // Bar width, plus a pixel of spacing to the right. for (let j = 0; j < NUM_BARS - 1; j++) { const start = octaveBuckets[j]; const end = octaveBuckets[j + 1]; let amplitude = 0; for (let k = start; k < end; k++) { amplitude += dataArray[k]; } amplitude /= end - start; // The drop rate should probably be normalized to the rendering FPS, for now assume 60 FPS let barPeak = barPeaks[j] - BAR_PEAK_DROP_RATE * Math.pow(barPeakFrames[j], 2); if (barPeak < amplitude) { barPeak = amplitude; barPeakFrames[j] = 0; } else { barPeakFrames[j] += 1; } barPeaks[j] = barPeak; paintBar(canvasCtx, j * xOffset, amplitude * heightMultiplier, barPeak * heightMultiplier); } }, [analyser, barPeakFrames, barPeaks, dataArray, octaveBuckets, paintBar, renderHeight]); } ;// CONCATENATED MODULE: ./js/components/Visualizer.tsx const Visualizer_PIXEL_DENSITY = 2; // Pre-render the background grid function preRenderBg(width, height, bgColor, fgColor, windowShade) { // Off-screen canvas for pre-rendering the background const bgCanvas = document.createElement("canvas"); bgCanvas.width = width; bgCanvas.height = height; const distance = 2 * Visualizer_PIXEL_DENSITY; const bgCanvasCtx = bgCanvas.getContext("2d"); if (bgCanvasCtx == null) { throw new Error("Could not construct canvas context"); } bgCanvasCtx.fillStyle = bgColor; bgCanvasCtx.fillRect(0, 0, width, height); if (!windowShade) { bgCanvasCtx.fillStyle = fgColor; for (let x = 0; x < width; x += distance) { for (let y = Visualizer_PIXEL_DENSITY; y < height; y += distance) { bgCanvasCtx.fillRect(x, y, Visualizer_PIXEL_DENSITY, Visualizer_PIXEL_DENSITY); } } } return bgCanvas; } function Visualizer_Visualizer({ analyser }) { (0,react.useLayoutEffect)(() => { analyser.fftSize = 2048; }, [analyser.fftSize]); const colors = useTypedSelector(getSkinColors); const style = useTypedSelector(selectors_getVisualizerStyle); const status = useTypedSelector(getMediaStatus); const getWindowShade = useTypedSelector(selectors_getWindowShade); const dummyVizData = useTypedSelector(getDummyVizData); const toggleVisualizerStyle = useActionCreator(actionCreators_toggleVisualizerStyle); const windowShade = getWindowShade("main"); const renderWidth = windowShade ? 38 : 76; const renderHeight = windowShade ? 5 : 16; const width = renderWidth * Visualizer_PIXEL_DENSITY; const height = renderHeight * Visualizer_PIXEL_DENSITY; const bgCanvas = (0,react.useMemo)(() => { return preRenderBg(width, height, colors[0], colors[1], Boolean(windowShade)); }, [colors, height, width, windowShade]); const paintOscilloscopeFrame = usePaintOscilloscopeFrame({ analyser, height, width, renderWidth }); const paintBarFrame = usePaintBarFrame({ analyser, height, renderHeight }); const paintBar = usePaintBar({ height, renderHeight }); const paintFrame = (0,react.useCallback)(canvasCtx => { if (status !== MEDIA_STATUS.PLAYING) { return; } if (dummyVizData) { canvasCtx.drawImage(bgCanvas, 0, 0); Object.entries(dummyVizData).forEach(([i, value]) => { paintBar(canvasCtx, Number(i), value, -1); }); return; } switch (style) { case VISUALIZERS.OSCILLOSCOPE: canvasCtx.drawImage(bgCanvas, 0, 0); paintOscilloscopeFrame(canvasCtx); break; case VISUALIZERS.BAR: canvasCtx.drawImage(bgCanvas, 0, 0); paintBarFrame(canvasCtx); break; default: canvasCtx.clearRect(0, 0, width, height); } }, [bgCanvas, dummyVizData, height, paintBar, paintBarFrame, paintOscilloscopeFrame, status, style, width]); const [canvas, setCanvas] = (0,react.useState)(null); (0,react.useLayoutEffect)(() => { if (canvas == null) { return; } const canvasCtx = canvas.getContext("2d"); if (canvasCtx == null) { return; } canvasCtx.imageSmoothingEnabled = false; let animationRequest = null; // Kick off the animation loop const loop = () => { paintFrame(canvasCtx); animationRequest = window.requestAnimationFrame(loop); }; loop(); return () => { if (animationRequest != null) { window.cancelAnimationFrame(animationRequest); } }; }, [canvas, paintFrame]); return /*#__PURE__*/(0,jsx_runtime.jsx)("canvas", { id: "visualizer", ref: setCanvas, style: { width: renderWidth, height: renderHeight }, width: width, height: height, onClick: toggleVisualizerStyle }); } /* harmony default export */ const components_Visualizer = (Visualizer_Visualizer); ;// CONCATENATED MODULE: ./js/components/MainWindow/ActionButtons.tsx const ActionButtons = /*#__PURE__*/(0,react.memo)(() => { const previous = useActionCreator(media_previous); const play = useActionCreator(media_play); const pause = useActionCreator(media_pause); const next = useActionCreator(media_next); const stop = useActionCreator(media_stop); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "actions", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "previous", onClick: previous, title: "Previous Track" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "play", onClick: play, title: "Play" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "pause", onClick: pause, title: "Pause" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "stop", onClick: stop, title: "Stop" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "next", onClick: next, title: "Next Track" })] }); }); /* harmony default export */ const MainWindow_ActionButtons = (ActionButtons); ;// CONCATENATED MODULE: ./js/components/Balance.tsx function Balance({ style, className, id }) { const balance = useTypedSelector(getBalance); const setBalance = useActionCreator(media_setBalance); const setFocus = useActionCreator(actionCreators_setFocus); const unsetFocus = useActionCreator(actionCreators_unsetFocus); return /*#__PURE__*/(0,jsx_runtime.jsx)("input", { id: id, className: className, type: "range", min: "-100", max: "100", step: "1", value: balance, style: style, onChange: e => setBalance(Number(e.target.value)), onMouseDown: () => setFocus("balance"), onMouseUp: unsetFocus, title: "Balance" }); } ;// CONCATENATED MODULE: ./js/components/MainWindow/MainBalance.tsx const offsetFromBalance = balance => { const percent = Math.abs(balance) / 100; const sprite = Math.floor(percent * 27); const offset = sprite * 15; return offset; }; const MainBalance = /*#__PURE__*/(0,react.memo)(() => { const balance = useTypedSelector(getBalance); return /*#__PURE__*/(0,jsx_runtime.jsx)(Balance, { id: "balance", style: { backgroundPosition: `0 -${offsetFromBalance(balance)}px` } }); }); /* harmony default export */ const MainWindow_MainBalance = (MainBalance); ;// CONCATENATED MODULE: ./js/components/MainWindow/Close.tsx const Close = /*#__PURE__*/(0,react.memo)(() => { const close = useActionCreator(actionCreators_close); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_ClickedDiv, { id: "close", onClick: close, title: "Close" }); }); /* harmony default export */ const MainWindow_Close = (Close); ;// CONCATENATED MODULE: ./js/components/MainWindow/ClutterBar.tsx const { ipcRenderer: ClutterBar_ipcRenderer } = window.require('electron'); function setFocusDouble() { return actionCreators_setFocus("double"); } function mouseUp() { return dispatch => { dispatch(windows_toggleDoubleSizeMode()); dispatch(actionCreators_unsetFocus()); }; } const ClutterBar = /*#__PURE__*/(0,react.memo)(() => { const handleMouseDown = useActionCreator(setFocusDouble); const handleMouseUp = useActionCreator(mouseUp); const doubled = useTypedSelector(getDoubled); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { id: "clutter-bar", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(components_ContextMenuTarget, { bottom: true, renderMenu: () => /*#__PURE__*/(0,jsx_runtime.jsx)(components_OptionsContextMenu, {}), children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "button-o" }) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "button-a", title: "Лайк", onMouseUp: async () => { ClutterBar_ipcRenderer.invoke("setLike").then(() => {}); } }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "button-i", title: "Моя волна", onMouseUp: async () => { ClutterBar_ipcRenderer.invoke("setMywave").then(() => {}); } }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { title: "Toggle Doublesize Mode", id: "button-d", className: classnames_default()({ selected: doubled }), onMouseUp: handleMouseUp, onMouseDown: handleMouseDown }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "button-v" })] }); }); /* harmony default export */ const MainWindow_ClutterBar = (ClutterBar); ;// CONCATENATED MODULE: ./js/components/MainWindow/Eject.tsx const Eject = /*#__PURE__*/(0,react.memo)(() => { const openMediaFileDialog = useActionCreator(files_openMediaFileDialog); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "eject", onClick: openMediaFileDialog, title: "Open File(s)" }); }); /* harmony default export */ const MainWindow_Eject = (Eject); ;// CONCATENATED MODULE: ./js/components/MainWindow/EqToggleButton.tsx function toggleEqualizer() { return windows_toggleWindow("equalizer"); } const EqToggleButton = /*#__PURE__*/(0,react.memo)(() => { const handleClick = useActionCreator(toggleEqualizer); const windowOpen = useTypedSelector(selectors_getWindowOpen)("equalizer"); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "equalizer-button", className: classnames_default()({ selected: windowOpen }), onClick: handleClick, title: "Toggle Graphical Equalizer" }); }); /* harmony default export */ const MainWindow_EqToggleButton = (EqToggleButton); ;// CONCATENATED MODULE: ./js/components/MainWindow/PlaylistToggleButton.tsx function togglePlaylist() { return windows_toggleWindow("playlist"); } const PlaylistToggleButton = /*#__PURE__*/(0,react.memo)(() => { const selected = useTypedSelector(selectors_getWindowOpen)("playlist"); const handleClick = useActionCreator(togglePlaylist); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-button", className: classnames_default()({ selected }), onClick: handleClick, title: "Toggle Playlist Editor" }); }); /* harmony default export */ const MainWindow_PlaylistToggleButton = (PlaylistToggleButton); ;// CONCATENATED MODULE: ./js/components/CharacterString.tsx const CharacterString = /*#__PURE__*/(0,react.memo)(props => { const text = `${props.children}` || ""; const chars = text.split(""); return /*#__PURE__*/(0,jsx_runtime.jsx)(react.Fragment, { children: chars.map((character, index) => /*#__PURE__*/(0,jsx_runtime.jsx)(components_Character, { children: character }, index + character)) }); }); /* harmony default export */ const components_CharacterString = (CharacterString); ;// CONCATENATED MODULE: ./js/components/MainWindow/Kbps.tsx const Kbps = /*#__PURE__*/(0,react.memo)(() => { const kbps = useTypedSelector(getKbps); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "kbps", children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_CharacterString, { children: kbps || "" }) }); }); /* harmony default export */ const MainWindow_Kbps = (Kbps); ;// CONCATENATED MODULE: ./js/components/MainWindow/Khz.tsx const Khz = /*#__PURE__*/(0,react.memo)(() => { const khz = useTypedSelector(getKhz); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "khz", children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_CharacterString, { children: khz || "" }) }); }); /* harmony default export */ const MainWindow_Khz = (Khz); ;// CONCATENATED MODULE: ./js/components/MainWindow/Marquee.tsx // Single line text display that can animate and hold multiple registers // Knows how to display various modes like tracking, volume, balance, etc. const SEPARATOR = " *** "; const CHAR_WIDTH = 5; const MARQUEE_MAX_LENGTH = 31; // Always positive modulus const mod = (n, m) => (n % m + m) % m; const isLong = text => text.length >= MARQUEE_MAX_LENGTH; // Given text and step, how many pixels should it be shifted? const stepOffset = (text, step, pixels) => { if (!isLong(text)) { return 0; } const stepOffsetWidth = step * CHAR_WIDTH; // Steps move one char at a time const offset = stepOffsetWidth + pixels; const stringLength = (text.length + SEPARATOR.length) * CHAR_WIDTH; return mod(offset, stringLength); }; // Format an int as pixels const pixelUnits = pixels => `${pixels}px`; // If text is wider than the marquee, it needs to loop const loopText = text => isLong(text) ? `${text}${SEPARATOR}${text}` : text.padEnd(MARQUEE_MAX_LENGTH, " "); // Call `step` every second, except when dragging. Resume stepping 1 second after dragging ceases. function useStepper({ step, dragging }) { const [stepping, setStepping] = react.useState(true); react.useEffect(() => { if (stepping === false) { return; } const stepHandle = setInterval(step, 220); return () => clearInterval(stepHandle); }, [step, stepping]); react.useEffect(() => { if (dragging) { setStepping(false); return; } const steppingTimeout = window.setTimeout(() => { setStepping(true); }, 1000); return () => { window.clearTimeout(steppingTimeout); }; }, [dragging]); } // When user calls `handleMouseDown`, and moves the mouse, `dragOffset` will update as they drag. function useDragX() { const [mouseDownX, setMouseDownX] = react.useState(null); const [dragOffset, setDragOffset] = react.useState(0); react.useEffect(() => { if (mouseDownX == null) { return; } const xStart = mouseDownX; const handleMouseMove = ee => { const diff = ee.clientX - xStart; setDragOffset(-diff); }; // TODO: Use `once` or something instead of this flag nonsense let cleanedUp = false; const handleMouseUp = () => { if (cleanedUp) { return; } document.removeEventListener("mousemove", handleMouseMove); document.removeEventListener("mouseUp", handleMouseUp); setMouseDownX(null); cleanedUp = true; }; document.addEventListener("mousemove", handleMouseMove); document.addEventListener("mouseup", handleMouseUp); return handleMouseUp; }, [mouseDownX]); const handleMouseDown = react.useCallback(e => { setMouseDownX(e.clientX); }, []); return { handleMouseDown, dragOffset, dragging: mouseDownX != null }; } const Marquee = /*#__PURE__*/react.memo(() => { const text = useTypedSelector(getMarqueeText); const doubled = useTypedSelector(getDoubled); const marqueeStep = useTypedSelector(getMarqueeStep); const stepMarquee = useActionCreator(actionCreators_stepMarquee); const { handleMouseDown, dragOffset, dragging } = useDragX(); const offset = stepOffset(text, marqueeStep, dragOffset); const offsetPixels = pixelUnits(-offset); useStepper({ step: stepMarquee, dragging }); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "marquee", className: "text", onMouseDown: handleMouseDown, title: "Song Title", children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { style: { whiteSpace: "nowrap", willChange: "transform", transform: `translateX(${offsetPixels})` } // Force the DOM node to be recreated when the doubled size changes. // This works around a Chrome browser bug where the `will-change: transform;` // on this node seems to cause a change to the `image-rendering: // pixelated;` which we inherit from `#webamp` not to be respected. , children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_CharacterString, { children: loopText(text) }) }, doubled ? "doubled" : "not-doubled") }); }); /* harmony default export */ const MainWindow_Marquee = (Marquee); ;// CONCATENATED MODULE: ./js/components/MainWindow/MonoStereo.tsx const MonoStereo = /*#__PURE__*/(0,react.memo)(() => { const channels = useTypedSelector(getChannels); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "mono-stereo", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "stereo", className: classnames_default()({ selected: channels === 2 }) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "mono", className: classnames_default()({ selected: channels === 1 }) })] }); }); /* harmony default export */ const MainWindow_MonoStereo = (MonoStereo); ;// CONCATENATED MODULE: ./js/components/MainWindow/Position.tsx function usePosition() { const duration = useTypedSelector(getDuration); const timeElapsed = useTypedSelector(getTimeElapsed); const position = duration ? Math.floor(timeElapsed) / duration * 100 : 0; const scrubPosition = useTypedSelector(getUserInputScrubPosition); const userInputFocus = useTypedSelector(getUserInputFocus); const displayedPosition = userInputFocus === "position" ? scrubPosition : position; return [position, displayedPosition]; } const Position = /*#__PURE__*/(0,react.memo)(() => { const [position, displayedPosition] = usePosition(); const dispatch = useTypedDispatch(); const seekToPercentComplete = (0,react.useCallback)(e => { dispatch({ type: SEEK_TO_PERCENT_COMPLETE, percent: Number(e.target.value) }); dispatch({ type: UNSET_FOCUS }); }, [dispatch]); const setPosition = (0,react.useCallback)(e => { dispatch({ type: SET_FOCUS, input: "position" }); dispatch({ type: SET_SCRUB_POSITION, position: Number(e.target.value) }); }, [dispatch]); // In shade mode, the position slider shows up differently depending on if // it's near the start, middle or end of its progress let className = ""; if (position <= 33) { className = "left"; } else if (position >= 66) { className = "right"; } return /*#__PURE__*/(0,jsx_runtime.jsx)("input", { id: "position", className: className, type: "range", min: "0", max: "100", step: "1", value: displayedPosition, onInput: setPosition, onChange: () => {} /* React complains without this, can probably rename onInput to onChange */, onMouseUp: seekToPercentComplete, onMouseDown: setPosition, title: "Seeking Bar" }); }); /* harmony default export */ const MainWindow_Position = (Position); ;// CONCATENATED MODULE: ./js/components/MainWindow/Repeat.tsx const Repeat = /*#__PURE__*/(0,react.memo)(() => { const repeat = useTypedSelector(getRepeat); const handleClick = useActionCreator(media_toggleRepeat); return /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenuWraper, { renderContents: () => /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { checked: repeat, label: "Repeat", onClick: handleClick, hotkey: "(R)" }), children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "repeat", className: classnames_default()({ selected: repeat }), onClick: handleClick, title: "Toggle Repeat" }) }); }); /* harmony default export */ const MainWindow_Repeat = (Repeat); ;// CONCATENATED MODULE: ./js/components/MainWindow/Shade.tsx const Shade = /*#__PURE__*/(0,react.memo)(() => { const handleClick = useActionCreator(windows_toggleMainWindowShadeMode); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_ClickedDiv, { id: "shade", onMouseDown: handleClick, onDoubleClick: e => e.stopPropagation(), title: "Toggle Windowshade Mode" }); }); /* harmony default export */ const MainWindow_Shade = (Shade); ;// CONCATENATED MODULE: ./js/components/MainWindow/Minimize.tsx const Minimize = /*#__PURE__*/(0,react.memo)(() => { const minimize = useActionCreator(actionCreators_minimize); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_ClickedDiv, { id: "minimize", title: "Minimize", onClick: minimize }); }); /* harmony default export */ const MainWindow_Minimize = (Minimize); ;// CONCATENATED MODULE: ./js/components/MainWindow/Shuffle.tsx const Shuffle = /*#__PURE__*/(0,react.memo)(() => { const shuffle = useTypedSelector(getShuffle); const handleClick = useActionCreator(media_toggleShuffle); return /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenuWraper, { renderContents: () => /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { checked: shuffle, label: "Shuffle", onClick: handleClick, hotkey: "(S)" }), children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "shuffle", className: classnames_default()({ selected: shuffle }), onClick: handleClick, title: "Toggle Shuffle" }) }); }); /* harmony default export */ const MainWindow_Shuffle = (Shuffle); ;// CONCATENATED MODULE: ./js/components/MainWindow/Time.tsx const Time = /*#__PURE__*/(0,react.memo)(() => { const toggleTimeMode = useActionCreator(media_toggleTimeMode); const timeElapsed = useTypedSelector(getTimeElapsed); const duration = useTypedSelector(getDuration) || 0; const timeMode = useTypedSelector(getTimeMode); const seconds = timeMode === TIME_MODE.ELAPSED ? timeElapsed : duration - timeElapsed; const timeObj = getTimeObj(seconds); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { id: "time", onClick: toggleTimeMode, className: "countdown", children: [timeMode === TIME_MODE.REMAINING && /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "minus-sign" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "minute-first-digit", className: `digit digit-${timeObj.minutesFirstDigit}` }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "minute-second-digit", className: `digit digit-${timeObj.minutesSecondDigit}` }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "second-first-digit", className: `digit digit-${timeObj.secondsFirstDigit}` }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "second-second-digit", className: `digit digit-${timeObj.secondsSecondDigit}` })] }); }); /* harmony default export */ const MainWindow_Time = (Time); ;// CONCATENATED MODULE: ./js/components/Volume.tsx function Volume({ id, style, className }) { const volume = useTypedSelector(getVolume); const setFocus = useActionCreator(actionCreators_setFocus); const unsetFocus = useActionCreator(actionCreators_unsetFocus); const setVolume = useActionCreator(media_setVolume); return /*#__PURE__*/(0,jsx_runtime.jsx)("input", { id: id, type: "range", min: "0", max: "100", step: "1", value: volume, style: style, className: className, onChange: e => setVolume(Number(e.target.value)), onMouseDown: () => setFocus("volume"), onMouseUp: unsetFocus, title: "Volume Bar" }); } ;// CONCATENATED MODULE: ./js/components/MainWindow/MainVolume.tsx const MainVolume = /*#__PURE__*/(0,react.memo)(() => { const volume = useTypedSelector(getVolume); const percent = volume / 100; const sprite = Math.round(percent * 28); const offset = (sprite - 1) * 15; const style = { backgroundPosition: `0 -${offset}px` }; return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "volume", style: style, children: /*#__PURE__*/(0,jsx_runtime.jsx)(Volume, {}) }); }); /* harmony default export */ const MainWindow_MainVolume = (MainVolume); // EXTERNAL MODULE: ./css/main-window.css var main_window = __webpack_require__(6289); ;// CONCATENATED MODULE: ./js/components/MainWindow/index.tsx const { ipcRenderer: MainWindow_ipcRenderer } = window.require('electron'); function loadMediaAndPlay(e) { return files_loadMedia(e, LOAD_STYLE.PLAY); } const MainWindow = /*#__PURE__*/react.memo(({ analyser, filePickers }) => { const mainShade = useTypedSelector(selectors_getWindowShade)("main"); const status = useTypedSelector(getMediaStatus); const focused = useTypedSelector(getFocusedWindow); const loading = useTypedSelector(getLoading); const doubled = useTypedSelector(getDoubled); const llama = useTypedSelector(getLlamaMode); const working = useTypedSelector(getWorking); const className = classnames_default()({ window: true, play: status === MEDIA_STATUS.PLAYING, stop: status === MEDIA_STATUS.STOPPED, pause: status === MEDIA_STATUS.PAUSED, selected: focused === WINDOWS.MAIN, shade: mainShade, draggable: true, loading, doubled, llama }); const toggleMainWindowShadeMode = useActionCreator(windows_toggleMainWindowShadeMode); const scrollVolume = useActionCreator(media_scrollVolume); const loadMedia = useActionCreator(loadMediaAndPlay); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_DropTarget, { id: "main-window", windowId: WINDOWS.MAIN, className: className, handleDrop: loadMedia, children: /*#__PURE__*/(0,jsx_runtime.jsxs)(components_FocusTarget, { windowId: WINDOWS.MAIN, children: [/*#__PURE__*/(0,jsx_runtime.jsxs)("div", { id: "title-bar", className: "selected draggable", onDoubleClick: toggleMainWindowShadeMode, children: [/*#__PURE__*/(0,jsx_runtime.jsx)(components_ContextMenuTarget, { id: "option-context", bottom: true, renderMenu: () => /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_MainContextMenu, { filePickers: filePickers }), children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_ClickedDiv, { id: "option", title: "Winamp Menu" }) }), mainShade && /*#__PURE__*/(0,jsx_runtime.jsx)(components_MiniTime, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Minimize, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Shade, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Close, {})] }), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "status", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_ClutterBar, {}), !working && /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "play-pause" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "work-indicator", className: classnames_default()({ selected: working }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Time, {})] }), /*#__PURE__*/(0,jsx_runtime.jsx)(components_Visualizer // @ts-ignore Visualizer is not typed yet , { analyser: analyser }), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "media-info", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Marquee, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Kbps, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Khz, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_MonoStereo, {})] }), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_MainVolume, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_MainBalance, {}), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "windows", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_EqToggleButton, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_PlaylistToggleButton, {})] }), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Position, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_ActionButtons, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Eject, {}), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "shuffle-repeat", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Shuffle, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_Repeat, {})] }), /*#__PURE__*/(0,jsx_runtime.jsx)("a", { id: "about", href: "#", title: "Yaamp", onClick: async () => { MainWindow_ipcRenderer.invoke("openLink", { link: "https://yaamp.ru/" }).then(() => {}); } })] }) }); }); /* harmony default export */ const components_MainWindow = (MainWindow); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/PlaylistResizeTarget.tsx function PlaylistResizeTarget({ widthOnly }) { const windowSize = useTypedSelector(selectors_getWindowSize); const setWindowSize = useActionCreator(windows_setWindowSize); const currentSize = windowSize("playlist"); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_ResizeTarget, { currentSize: currentSize, id: "playlist-resize-target", setWindowSize: size => { setWindowSize("playlist", size); }, widthOnly: widthOnly }); } /* harmony default export */ const PlaylistWindow_PlaylistResizeTarget = (PlaylistResizeTarget); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/PlaylistShade.tsx function PlaylistShade() { const focused = useTypedSelector(getFocusedWindow); const getWindowSize = useTypedSelector(selectors_getWindowSize); const playlistSize = getWindowSize("playlist"); const duration = useTypedSelector(getDuration); const name = useTypedSelector(getMinimalMediaText); const closeWindow = useActionCreator(windows_closeWindow); const toggleShade = useActionCreator(togglePlaylistShadeMode); const focusWindow = useActionCreator(windows_setFocusedWindow); const addedWidth = playlistSize[0] * WINDOW_RESIZE_SEGMENT_WIDTH; const trimmedName = (0,react.useMemo)(() => { if (name == null) { return "[No file]"; } const MIN_NAME_WIDTH = 205; const nameLength = (MIN_NAME_WIDTH + addedWidth) / CHARACTER_WIDTH; return name.length > nameLength ? name.slice(0, nameLength - 1) + UTF8_ELLIPSIS : name; }, [addedWidth, name]); const time = (0,react.useMemo)(() => { return name == null ? "" : getTimeStr(duration); }, [duration, name]); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-window-shade", className: classnames_default()("window", "draggable", { selected: focused === WINDOWS.PLAYLIST }), style: { width: `${WINDOW_WIDTH + addedWidth}px` }, onMouseDown: () => focusWindow("playlist"), onDoubleClick: toggleShade, children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "left", children: /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "right draggable", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-shade-track-title", children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_CharacterString, { children: trimmedName }) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-shade-time", children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_CharacterString, { children: time }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_PlaylistResizeTarget, { widthOnly: true }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-shade-button", onClick: toggleShade }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-close-button", onClick: () => closeWindow("playlist") })] }) }) }); } /* harmony default export */ const PlaylistWindow_PlaylistShade = (PlaylistShade); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/PlaylistMenuEntry.tsx // We implement hover ourselves, because we hate ourselves and https://stackoverflow.com/a/13259049/1263117 function PlaylistMenuEntry({ children }) { const { ref, hover } = useIsHovered(); return /*#__PURE__*/(0,jsx_runtime.jsx)("li", { ref: ref, className: classnames_default()({ hover }), children: children }); } /* harmony default export */ const PlaylistWindow_PlaylistMenuEntry = (/*#__PURE__*/(0,react.memo)(PlaylistMenuEntry)); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/PlaylistMenu.tsx function PlaylistMenu(props) { const [selected, setSelected] = (0,react.useState)(false); const [ref, setRef] = (0,react.useState)(null); const callback = (0,react.useCallback)(() => { // If we've clicked on a Context Menu spawed inside this menu, it will // register as an external click. However, hiding the menu will remove // the Context Menu from the DOM. Therefore, we wait until the next // event loop to actually hide ourselves. setTimeout(() => { // Close the menu setSelected(false); }, 0); }, []); useOnClickAway(ref, selected ? callback : null); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { id: props.id, className: classnames_default()("playlist-menu", { selected }), ref: setRef, onClick: () => setSelected(selected_ => !selected_), children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "bar" }), selected && /*#__PURE__*/(0,jsx_runtime.jsx)("ul", { children: react.Children.map(props.children, (child, i) => /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_PlaylistMenuEntry, { children: child }, i)) })] }); } /* harmony default export */ const PlaylistWindow_PlaylistMenu = (/*#__PURE__*/(0,react.memo)(PlaylistMenu)); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/AddMenu.tsx const AddMenu = () => { const nextIndex = useTypedSelector(getTrackCount); const addDirAtIndex = useActionCreator(files_addDirAtIndex); const addFilesAtIndex = useActionCreator(files_addFilesAtIndex); const addFilesFromUrl = useActionCreator(files_addFilesFromUrl); return /*#__PURE__*/(0,jsx_runtime.jsxs)(PlaylistWindow_PlaylistMenu, { id: "playlist-add-menu", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "add-url", onClick: () => addFilesFromUrl(nextIndex) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "add-dir", onClick: () => addDirAtIndex(nextIndex) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "add-file", onClick: () => addFilesAtIndex(nextIndex) })] }); }; /* harmony default export */ const PlaylistWindow_AddMenu = (AddMenu); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/RemoveMenu.tsx /* eslint-disable no-alert */ const RemoveMenu = () => { const removeSelected = useActionCreator(removeSelectedTracks); const removeAll = useActionCreator(playlist_removeAllTracks); const crop = useActionCreator(cropPlaylist); return /*#__PURE__*/(0,jsx_runtime.jsxs)(PlaylistWindow_PlaylistMenu, { id: "playlist-remove-menu", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "remove-misc", onClick: () => alert("Not supported in Yaamp") }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "remove-all", onClick: removeAll }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "crop", onClick: crop }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "remove-selected", onClick: removeSelected })] }); }; /* harmony default export */ const PlaylistWindow_RemoveMenu = (RemoveMenu); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/SelectionMenu.tsx function SelectionMenu() { const invert = useActionCreator(invertSelection); const zero = useActionCreator(playlist_selectZero); const all = useActionCreator(selectAll); return /*#__PURE__*/(0,jsx_runtime.jsxs)(PlaylistWindow_PlaylistMenu, { id: "playlist-selection-menu", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "invert-selection", onClick: invert }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "select-zero", onClick: zero }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "select-all", onClick: all })] }); } ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/SortContextMenu.tsx /* eslint-disable no-alert */ /* TODO: This should really be kitty-corner to the upper right hand corner of the MiscMenu */ function SortContextMenu() { const reverseList = useActionCreator(playlist_reverseList); const randomizeList = useActionCreator(playlist_randomizeList); const sortListByTitle = useActionCreator(playlist_sortListByTitle); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_ContextMenuTarget, { style: { width: "100%", height: "100%" }, top: true, renderMenu: () => /*#__PURE__*/(0,jsx_runtime.jsxs)(jsx_runtime.Fragment, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Sort list by title", onClick: sortListByTitle }), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Reverse list", onClick: reverseList }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { label: "Randomize list", onClick: randomizeList })] }), children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", {}) }); } ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/MiscOptionsContextMenu.tsx const MiscOptionsContextMenu = () => { const downloadHtmlPlaylist = useActionCreator(files_downloadHtmlPlaylist); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_ContextMenuTarget, { top: true, renderMenu: () => /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: downloadHtmlPlaylist, label: "Generate HTML playlist" }), children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", {}) }); }; /* harmony default export */ const PlaylistWindow_MiscOptionsContextMenu = (MiscOptionsContextMenu); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/MiscMenu.tsx const MiscMenu = () => /*#__PURE__*/(0,jsx_runtime.jsxs)(PlaylistWindow_PlaylistMenu, { id: "playlist-misc-menu", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "sort-list", onClick: e => e.stopPropagation(), children: /*#__PURE__*/(0,jsx_runtime.jsx)(SortContextMenu, {}) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "file-info", onClick: () => alert("Not supported in Yaamp") }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "misc-options", onClick: e => e.stopPropagation(), children: /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_MiscOptionsContextMenu, {}) })] }); /* harmony default export */ const PlaylistWindow_MiscMenu = (MiscMenu); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/ListMenu.tsx /* eslint-disable no-alert */ function ListMenu() { const removeAllTracks = useActionCreator(playlist_removeAllTracks); const addFilesFromList = useActionCreator(files_addFilesFromList); const saveFilesToList = useActionCreator(files_saveFilesToList); return /*#__PURE__*/(0,jsx_runtime.jsxs)(PlaylistWindow_PlaylistMenu, { id: "playlist-list-menu", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "new-list", onClick: removeAllTracks }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "save-list", onClick: saveFilesToList }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "load-list", onClick: addFilesFromList })] }); } ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/RunningTimeDisplay.tsx // While all the browsers I care about support String.prototype.padEnd, // Not all node versions do, and I want tests to pass in Jest... // Sigh. function rightPad(str, len, fillChar) { while (str.length < len) { str += fillChar; } return str; } const RunningTimeDisplay = () => { const runningTimeMessage = useTypedSelector(getRunningTimeMessage); const text = (0,react.useMemo)(() => rightPad(runningTimeMessage, 18, " "), [runningTimeMessage]); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-running-time-display draggable", children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_CharacterString, { children: text }) }) }); }; /* harmony default export */ const PlaylistWindow_RunningTimeDisplay = (RunningTimeDisplay); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/PlaylistActionArea.tsx const PlaylistWindow = () => { const play = useActionCreator(media_play); const pause = useActionCreator(media_pause); const stop = useActionCreator(media_stop); const openMediaFileDialog = useActionCreator(files_openMediaFileDialog); const next = useActionCreator(media_next); const previous = useActionCreator(media_previous); return /*#__PURE__*/(0,jsx_runtime.jsxs)(react.Fragment, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_RunningTimeDisplay, {}), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "playlist-action-buttons", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-previous-button", onClick: previous }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-play-button", onClick: play }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-pause-button", onClick: pause }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-stop-button", onClick: stop }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-next-button", onClick: next }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-eject-button", onClick: openMediaFileDialog })] }), /*#__PURE__*/(0,jsx_runtime.jsx)(components_MiniTime, {})] }); }; /* harmony default export */ const PlaylistActionArea = (PlaylistWindow); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/TrackCell.tsx function TrackCell({ children, handleMoveClick, index, id }) { const skinPlaylistStyle = useTypedSelector(getSkinPlaylistStyle); const selectedTrackIds = useTypedSelector(getSelectedTrackIds); const currentTrackId = useTypedSelector(getCurrentTrackId); const selected = selectedTrackIds.has(id); const current = currentTrackId === id; const dispatch = useTypedDispatch(); const playTrackNow = useActionCreator(media_playTrackNow); const onMouseDown = (0,react.useCallback)(e => { if (e.shiftKey) { e.preventDefault(); dispatch({ type: SHIFT_CLICKED_TRACK, index }); return; } else if (e.metaKey || e.ctrlKey) { e.preventDefault(); dispatch({ type: CTRL_CLICKED_TRACK, index }); return; } if (!selected) { dispatch({ type: CLICKED_TRACK, index }); } handleMoveClick(e); }, [dispatch, handleMoveClick, index, selected]); const style = { backgroundColor: selected ? skinPlaylistStyle.selectedbg : undefined, color: current ? skinPlaylistStyle.current : undefined }; return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: classnames_default()("track-cell", { selected, current }), style: style, onClick: e => e.stopPropagation(), onMouseDown: onMouseDown, onContextMenu: e => e.preventDefault(), onDoubleClick: () => playTrackNow(id), children: children }); } /* harmony default export */ const PlaylistWindow_TrackCell = (TrackCell); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/TrackTitle.tsx const TrackTitle = ({ id, paddedTrackNumber }) => { const title = useTypedSelector(selectors_getTrackDisplayName)(id); return /*#__PURE__*/(0,jsx_runtime.jsxs)("span", { children: [paddedTrackNumber, ". ", title] }); }; /* harmony default export */ const PlaylistWindow_TrackTitle = (TrackTitle); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/TrackList.tsx function getNumberLength(number) { return number.toString().length; } function TrackList() { const offset = useTypedSelector(getScrollOffset); const trackIds = useTypedSelector(getVisibleTrackIds); const tracks = useTypedSelector(getTracks); const numberOfTracks = useTypedSelector(getNumberOfTracks); const selectZero = useActionCreator(playlist_selectZero); const dragSelected = useActionCreator(playlist_dragSelected); const scrollPlaylistByDelta = useActionCreator(playlist_scrollPlaylistByDelta); const [node, setNode] = (0,react.useState)(null); const [moving, setMoving] = (0,react.useState)(false); const [mouseStartY, setMouseStartY] = (0,react.useState)(null); const _handleMoveClick = e => { setMoving(true); setMouseStartY(e.clientY); }; (0,react.useEffect)(() => { if (node == null || mouseStartY == null || moving === false) { return; } const { top, bottom, left, right } = node.getBoundingClientRect(); let lastDiff = 0; const handleMouseMove = ee => { const { clientY: y, clientX: x } = ee; if (y < top || y > bottom || x < left || x > right) { // Mouse is outside the track list return; } const proposedDiff = Math.floor((y - mouseStartY) / TRACK_HEIGHT); if (proposedDiff !== lastDiff) { const diffDiff = proposedDiff - lastDiff; dragSelected(diffDiff); lastDiff = proposedDiff; } }; const handleMouseUp = () => setMoving(false); window.addEventListener("mouseup", handleMouseUp); window.addEventListener("mousemove", handleMouseMove); return () => { window.removeEventListener("mousemove", handleMouseMove); window.removeEventListener("mouseup", handleMouseUp); }; // I'm not 100% sure how well this would work if it rebound mid drag, so // we'll just pretend it's okay that we have stale values in there. // eslint-disable-next-line react-hooks/exhaustive-deps }, [moving]); function _renderTracks(format) { return trackIds.map((id, i) => /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_TrackCell, { id: id, index: offset + i, handleMoveClick: _handleMoveClick, children: format(id, i) }, id)); } const maxTrackNumberLength = getNumberLength(numberOfTracks); const paddedTrackNumForIndex = i => (i + 1 + offset).toString().padStart(maxTrackNumberLength, "\u00A0"); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { ref: setNode, className: "playlist-tracks", style: { height: "100%" }, onClick: selectZero, onWheel: scrollPlaylistByDelta, children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-track-titles", children: _renderTracks((id, i) => /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_TrackTitle, { id: id, paddedTrackNumber: paddedTrackNumForIndex(i) })) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-track-durations", children: _renderTracks(id => getTimeStr(tracks[id].duration)) })] }); } /* harmony default export */ const PlaylistWindow_TrackList = (TrackList); ;// CONCATENATED MODULE: ./js/components/VerticalSlider.tsx // `` can be rotated to become a vertical slider using // CSS, but that makes it impossible to style the handle in a pixel perfect // manner. Instead we reimplement it in React. function VerticalSlider({ value, height, width, handle, handleHeight, onBeforeChange, onChange, onAfterChange, disabled }) { const ref = (0,react.useRef)(null); const handleRef = (0,react.useRef)(null); function handleMouseDown(e) { const sliderNode = ref.current; const handleNode = handleRef.current; if (sliderNode == null || handleNode == null) { // I don't think this could ever happen in practice return null; } const sliderRect = sliderNode.getBoundingClientRect(); const handleRect = handleNode.getBoundingClientRect(); const { top: sliderTop, height: sliderHeight } = sliderRect; const { top: handleTop, height: realHandleHeight } = handleRect; // If the user clicks on the handle we want them to continue to hold onto // that point of te handle. If they click outside of the handle (in the // slider itself) we want to center the handle at that point and have them // move the handle from the center. const handleOffset = handleNode.contains(e.target) ? e.clientY - handleTop : realHandleHeight / 2; const baseOffset = sliderTop + handleOffset; // Measure the actual rect height rather than use the `height` prop, becuase // we might be in double-size mode. const spanSize = sliderHeight - realHandleHeight; function moveToCursor(event) { // Ensure dragging does not cause elements/text to be selected. // https://stackoverflow.com/a/19164149/1263117 event.preventDefault(); const startOffset = event.clientY - baseOffset; onChange(clamp(startOffset / spanSize, 0, 1)); } function handleMouseUp() { if (onAfterChange != null) { onAfterChange(); } document.removeEventListener("mousemove", moveToCursor); document.removeEventListener("mouseup", handleMouseUp); } document.addEventListener("mousemove", moveToCursor); document.addEventListener("mouseup", handleMouseUp); if (onBeforeChange != null) { onBeforeChange(); } // Move the slider to where they've started. moveToCursor(e.nativeEvent); } const offset = Math.floor((height - handleHeight) * value); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { style: { height, width }, onMouseDown: disabled ? undefined : handleMouseDown, ref: ref, children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { style: { transform: `translateY(${offset}px)` }, ref: handleRef, children: handle }) }); } ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/PlaylistScrollBar.tsx const HANDLE_HEIGHT = 18; const Handle = () => /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-scrollbar-handle", style: { height: HANDLE_HEIGHT } }); function PlaylistScrollBar() { const getWindowPixelSize = useTypedSelector(selectors_getWindowPixelSize); const playlistHeight = getWindowPixelSize(WINDOWS.PLAYLIST).height; const playlistScrollPosition = useTypedSelector(getPlaylistScrollPosition); const allTracksAreVisible = useTypedSelector(getAllTracksAreVisible); const setPlaylistScrollPosition = useActionCreator(playlist_setPlaylistScrollPosition); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-scrollbar", style: { marginLeft: 5 }, children: /*#__PURE__*/(0,jsx_runtime.jsx)(VerticalSlider, { height: playlistHeight - 58, handleHeight: HANDLE_HEIGHT, width: 8, value: playlistScrollPosition / 100, onChange: val => setPlaylistScrollPosition(val * 100), handle: /*#__PURE__*/(0,jsx_runtime.jsx)(Handle, {}), disabled: allTracksAreVisible }) }); } // EXTERNAL MODULE: ./css/playlist-window.css var playlist_window = __webpack_require__(383); ;// CONCATENATED MODULE: ./js/components/PlaylistWindow/index.tsx function _maxTrackIndex(state) { return state.playlist.trackOrder.length - 1; } function PlaylistWindow_PlaylistWindow({ analyser }) { const offset = useTypedSelector(getScrollOffset); const getWindowSize = useTypedSelector(selectors_getWindowSize); const selectedWindow = useTypedSelector(getFocusedWindow); const getWindowShade = useTypedSelector(selectors_getWindowShade); const getWindowOpen = useTypedSelector(selectors_getWindowOpen); const maxTrackIndex = useTypedSelector(_maxTrackIndex); const skinPlaylistStyle = useTypedSelector(getSkinPlaylistStyle); const getWindowPixelSize = useTypedSelector(selectors_getWindowPixelSize); const selected = selectedWindow === WINDOWS.PLAYLIST; const playlistShade = Boolean(getWindowShade(WINDOWS.PLAYLIST)); const playlistSize = getWindowSize(WINDOWS.PLAYLIST); const playlistWindowPixelSize = getWindowPixelSize(WINDOWS.PLAYLIST); const doubled = useTypedSelector(getDoubled); const close = useActionCreator(windows_closeWindow); const toggleShade = useActionCreator(togglePlaylistShadeMode); const scrollUpFourTracks = useActionCreator(playlist_scrollUpFourTracks); const scrollDownFourTracks = useActionCreator(playlist_scrollDownFourTracks); const scrollVolume = useActionCreator(media_scrollVolume); const loadMedia = useActionCreator(files_loadMedia); const showVisualizer = playlistSize[0] > 2; const activateVisualizer = !getWindowOpen(WINDOWS.MAIN); const handleDrop = (0,react.useCallback)((e, targetCoords) => { const top = e.clientY - targetCoords.y; const atIndex = clamp(offset + Math.round((top - 23) / TRACK_HEIGHT), 0, maxTrackIndex + 1); loadMedia(e, LOAD_STYLE.NONE, atIndex); }, [loadMedia, maxTrackIndex, offset]); if (playlistShade) { return /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_PlaylistShade, {}); } const style = { color: skinPlaylistStyle.normal, backgroundColor: skinPlaylistStyle.normalbg, fontFamily: `${skinPlaylistStyle.font}, Arial, sans-serif`, height: `${playlistWindowPixelSize.height}px`, width: `${playlistWindowPixelSize.width}px` }; const classes = classnames_default()("window", "draggable", { selected, doubled }); const showSpacers = playlistSize[0] % 2 === 0; return /*#__PURE__*/(0,jsx_runtime.jsx)(components_FocusTarget, { windowId: WINDOWS.PLAYLIST, children: /*#__PURE__*/(0,jsx_runtime.jsxs)(components_DropTarget, { id: "playlist-window", windowId: WINDOWS.PLAYLIST, className: classes, style: style, handleDrop: handleDrop, children: [/*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "playlist-top draggable", onDoubleClick: toggleShade, children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-top-left draggable" }), showSpacers && /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-top-left-spacer draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-top-left-fill draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-top-title draggable" }), showSpacers && /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-top-right-spacer draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-top-right-fill draggable" }), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "playlist-top-right draggable", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-shade-button", onClick: toggleShade }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-close-button", onClick: () => close(WINDOWS.PLAYLIST) })] })] }), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "playlist-middle draggable", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-middle-left draggable" }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-middle-center", children: /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_TrackList, {}) }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-middle-right draggable", children: /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistScrollBar, {}) })] }), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "playlist-bottom draggable", children: [/*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "playlist-bottom-left draggable", children: [/*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_AddMenu, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_RemoveMenu, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(SelectionMenu, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_MiscMenu, {})] }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-bottom-center draggable" }), /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "playlist-bottom-right draggable", children: [showVisualizer && /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "playlist-visualizer", children: activateVisualizer && /*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "visualizer-wrapper", children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_Visualizer // @ts-ignore Visualizer is not yet typed , { analyser: analyser }) }) }), /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistActionArea, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ListMenu, {}), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-scroll-up-button", onClick: scrollUpFourTracks }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "playlist-scroll-down-button", onClick: scrollDownFourTracks }), /*#__PURE__*/(0,jsx_runtime.jsx)(PlaylistWindow_PlaylistResizeTarget, {})] })] })] }) }); } /* harmony default export */ const components_PlaylistWindow = (PlaylistWindow_PlaylistWindow); ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/Band.tsx const MAX_VALUE = 2400; // New range for 0.1 dB precision // Given a value between 0-2400, return the sprite number (0-27) const spriteNumber = value => { const percent = value / MAX_VALUE; return Math.round(percent * 27); }; // Given a sprite number, return the x,y const spriteOffsets = number => { const x = number % 14; const y = Math.floor(number / 14); return { x, y }; }; const Band_Handle = () => { const style = { width: 11, height: 11, marginLeft: 1 }; return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { style: style, className: "slider-handle" }); }; function Band({ id, onChange, band }) { const sliders = useTypedSelector(getSliders); const value = sliders[band]; const backgroundPosition = (0,react.useMemo)(() => { const { x, y } = spriteOffsets(spriteNumber(value)); const xOffset = x * 15; // Each sprite is 15px wide const yOffset = y * 65; // Each sprite is 15px tall return `-${xOffset}px -${yOffset}px`; }, [value]); const focusBand = useActionCreator(actionCreators_focusBand); const usetFocus = useActionCreator(actionCreators_unsetFocus); // Round to nearest 0.1 dB step (24 dB / 2400 = 0.01 dB per unit, but we want 0.1 dB steps) // Each 0.1 dB step = 10 units in our 0-2400 range const roundToStep = val => { return Math.round(val / 10) * 10; }; // Note: The band background is actually one pixel taller (63) than the slider // it contains (62). return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: id, className: "band", style: { backgroundPosition, height: 63 }, children: /*#__PURE__*/(0,jsx_runtime.jsx)(VerticalSlider, { height: 62, width: 14, handleHeight: 11, value: 1 - value / MAX_VALUE, onBeforeChange: () => focusBand(band), onChange: val => { const newValue = (1 - val) * MAX_VALUE; onChange(roundToStep(newValue)); }, onAfterChange: usetFocus, handle: /*#__PURE__*/(0,jsx_runtime.jsx)(Band_Handle, {}) }) }); } ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/EqOn.tsx const EqOn = () => { const toggleEq = useActionCreator(equalizer_toggleEq); const on = useTypedSelector(getEqualizerEnabled); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "on", className: classnames_default()({ selected: on }), onClick: toggleEq }); }; /* harmony default export */ const EqualizerWindow_EqOn = (EqOn); ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/EqAuto.tsx const EqAuto = /*#__PURE__*/(0,react.memo)(() => { const selected = useTypedSelector(state => state.equalizer.auto); const toggleAuto = useActionCreator(toggleEqAuto); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "auto", className: classnames_default()({ selected }), onClick: toggleAuto }); }); /* harmony default export */ const EqualizerWindow_EqAuto = (EqAuto); ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/spline.js // Adapted from https://github.com/morganherlocker/cubic-spline function spline(xs, ys) { const ks = getNaturalKs(xs, ys); const maxX = xs[xs.length - 1]; const allYs = []; let i = 1; for (let x = 0; x <= maxX; x++) { while (xs[i] < x) i++; const t = (x - xs[i - 1]) / (xs[i] - xs[i - 1]); const a = ks[i - 1] * (xs[i] - xs[i - 1]) - (ys[i] - ys[i - 1]); const b = -ks[i] * (xs[i] - xs[i - 1]) + (ys[i] - ys[i - 1]); const q = (1 - t) * ys[i - 1] + t * ys[i] + t * (1 - t) * (a * (1 - t) + b * t); allYs.push(q); } return allYs; } function getNaturalKs(xs, ys) { const ks = xs.map(() => 0); const n = xs.length - 1; const matrix = zerosMatrix(n + 1, n + 2); for (let i = 1; i < n; i++ // rows ) { matrix[i][i - 1] = 1 / (xs[i] - xs[i - 1]); matrix[i][i] = 2 * (1 / (xs[i] - xs[i - 1]) + 1 / (xs[i + 1] - xs[i])); matrix[i][i + 1] = 1 / (xs[i + 1] - xs[i]); matrix[i][n + 1] = 3 * ((ys[i] - ys[i - 1]) / ((xs[i] - xs[i - 1]) * (xs[i] - xs[i - 1])) + (ys[i + 1] - ys[i]) / ((xs[i + 1] - xs[i]) * (xs[i + 1] - xs[i]))); } matrix[0][0] = 2 / (xs[1] - xs[0]); matrix[0][1] = 1 / (xs[1] - xs[0]); matrix[0][n + 1] = 3 * (ys[1] - ys[0]) / ((xs[1] - xs[0]) * (xs[1] - xs[0])); matrix[n][n - 1] = 1 / (xs[n] - xs[n - 1]); matrix[n][n] = 2 / (xs[n] - xs[n - 1]); matrix[n][n + 1] = 3 * (ys[n] - ys[n - 1]) / ((xs[n] - xs[n - 1]) * (xs[n] - xs[n - 1])); return solve(matrix, ks); } function solve(matrix, ks) { const m = matrix.length; // column for (let k = 0; k < m; k++) { // pivot for column let iMax = 0; let vali = Number.NEGATIVE_INFINITY; for (let i = k; i < m; i++) if (matrix[i][k] > vali) { iMax = i; vali = matrix[i][k]; } swapRows(matrix, k, iMax); // for all rows below pivot for (let i = k + 1; i < m; i++) { for (let j = k + 1; j < m + 1; j++) matrix[i][j] = matrix[i][j] - matrix[k][j] * (matrix[i][k] / matrix[k][k]); matrix[i][k] = 0; } } // rows = columns for (let i = m - 1; i >= 0; i--) { const v = matrix[i][m] / matrix[i][i]; ks[i] = v; // rows for (let j = i - 1; j >= 0; j--) { matrix[j][m] -= matrix[j][i] * v; matrix[j][i] = 0; } } return ks; } function zerosMatrix(rows, columns) { const matrix = []; for (let i = 0; i < rows; i++) { matrix.push([]); for (let j = 0; j < columns; j++) { matrix[i].push(0); } } return matrix; } function swapRows(m, k, l) { const p = m[k]; m[k] = m[l]; m[l] = p; } ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/EqGraph.tsx const GRAPH_HEIGHT = 19; const GRAPH_WIDTH = 113; function EqGraph() { const sliders = useTypedSelector(getSliders); const preampLineImagePromise = useTypedSelector(getPreampLineImage); const preampLineImage = usePromiseValueOrNull(preampLineImagePromise); const [canvasNode, setCanvasNode] = (0,react.useState)(null); const canvasCtx = (0,react.useMemo)(() => { var _canvasNode$getContex; return (_canvasNode$getContex = canvasNode === null || canvasNode === void 0 ? void 0 : canvasNode.getContext("2d")) !== null && _canvasNode$getContex !== void 0 ? _canvasNode$getContex : null; }, [canvasNode]); const colorPattern = useColorPattern(canvasCtx); (0,react.useLayoutEffect)(() => { if (canvasCtx == null || canvasNode == null || preampLineImage == null || colorPattern == null) { return; } const width = Number(canvasNode.width); const height = Number(canvasNode.height); canvasCtx.clearRect(0, 0, width, height); drawEqLine({ colorPattern, sliders, canvasCtx, preampLineImage }); }, [canvasCtx, canvasNode, colorPattern, preampLineImage, sliders]); return /*#__PURE__*/(0,jsx_runtime.jsx)("canvas", { id: "eqGraph", ref: setCanvasNode, width: GRAPH_WIDTH, height: GRAPH_HEIGHT }); } function useColorPattern(canvasCtx) { const lineColorsImagePromise = useTypedSelector(getLineColorsImage); const lineColorsImage = usePromiseValueOrNull(lineColorsImagePromise); return (0,react.useMemo)(() => { if (canvasCtx == null || lineColorsImage == null) { return null; } return canvasCtx.createPattern(lineColorsImage, "repeat-x"); }, [canvasCtx, lineColorsImage]); } function drawEqLine({ colorPattern, sliders, canvasCtx, preampLineImage }) { const preampValue = percentToRange(sliders.preamp / 100, 0, GRAPH_HEIGHT - 1); canvasCtx.drawImage(preampLineImage, 0, preampValue, preampLineImage.width, preampLineImage.height); const amplitudes = BANDS.map(band => sliders[band]); canvasCtx.fillStyle = colorPattern; const paddingLeft = 2; // TODO: This should be 1.5 const min = 0; const max = GRAPH_HEIGHT - 1; const xs = []; const ys = []; amplitudes.forEach((value, i) => { const percent = (100 - value) / 100; // Each band is 12 pixels widex xs.push(i * 12); ys.push(percentToRange(percent, min, max)); }); const allYs = spline(xs, ys); const maxX = xs[xs.length - 1]; let lastY = ys[0]; for (let x = 0; x <= maxX; x++) { const y = clamp(Math.round(allYs[x]), 0, GRAPH_HEIGHT - 1); const yTop = Math.min(y, lastY); const height = 1 + Math.abs(lastY - y); canvasCtx.fillRect(paddingLeft + x, yTop, 1, height); lastY = y; } } /* harmony default export */ const EqualizerWindow_EqGraph = (EqGraph); ;// CONCATENATED MODULE: ./presets/builtin.json const builtin_namespaceObject = JSON.parse('{"u":[{"name":"Classical","hz60":33,"hz170":33,"hz310":33,"hz600":33,"hz1000":33,"hz3000":33,"hz6000":20,"hz12000":20,"hz14000":20,"hz16000":16,"preamp":33},{"name":"Club","hz60":33,"hz170":33,"hz310":38,"hz600":42,"hz1000":42,"hz3000":42,"hz6000":38,"hz12000":33,"hz14000":33,"hz16000":33,"preamp":33},{"name":"Dance","hz60":48,"hz170":44,"hz310":36,"hz600":32,"hz1000":32,"hz3000":22,"hz6000":20,"hz12000":20,"hz14000":32,"hz16000":32,"preamp":33},{"name":"Laptop speakers/headphones","hz60":40,"hz170":50,"hz310":41,"hz600":26,"hz1000":28,"hz3000":35,"hz6000":40,"hz12000":48,"hz14000":53,"hz16000":56,"preamp":33},{"name":"Large hall","hz60":49,"hz170":49,"hz310":42,"hz600":42,"hz1000":33,"hz3000":24,"hz6000":24,"hz12000":24,"hz14000":33,"hz16000":33,"preamp":33},{"name":"Party","hz60":44,"hz170":44,"hz310":33,"hz600":33,"hz1000":33,"hz3000":33,"hz6000":33,"hz12000":33,"hz14000":44,"hz16000":44,"preamp":33},{"name":"Pop","hz60":29,"hz170":40,"hz310":44,"hz600":45,"hz1000":41,"hz3000":30,"hz6000":28,"hz12000":28,"hz14000":29,"hz16000":29,"preamp":33},{"name":"Reggae","hz60":33,"hz170":33,"hz310":31,"hz600":22,"hz1000":33,"hz3000":43,"hz6000":43,"hz12000":33,"hz14000":33,"hz16000":33,"preamp":33},{"name":"Rock","hz60":45,"hz170":40,"hz310":23,"hz600":19,"hz1000":26,"hz3000":39,"hz6000":47,"hz12000":50,"hz14000":50,"hz16000":50,"preamp":33},{"name":"Soft","hz60":40,"hz170":35,"hz310":30,"hz600":28,"hz1000":30,"hz3000":39,"hz6000":46,"hz12000":48,"hz14000":50,"hz16000":52,"preamp":33},{"name":"Ska","hz60":28,"hz170":24,"hz310":25,"hz600":31,"hz1000":39,"hz3000":42,"hz6000":47,"hz12000":48,"hz14000":50,"hz16000":48,"preamp":33},{"name":"Full Bass","hz60":48,"hz170":48,"hz310":48,"hz600":42,"hz1000":35,"hz3000":25,"hz6000":18,"hz12000":15,"hz14000":14,"hz16000":14,"preamp":33},{"name":"Soft Rock","hz60":39,"hz170":39,"hz310":36,"hz600":31,"hz1000":25,"hz3000":23,"hz6000":26,"hz12000":31,"hz14000":37,"hz16000":47,"preamp":33},{"name":"Full Treble","hz60":16,"hz170":16,"hz310":16,"hz600":25,"hz1000":37,"hz3000":50,"hz6000":58,"hz12000":58,"hz14000":58,"hz16000":60,"preamp":33},{"name":"Full Bass & Treble","hz60":44,"hz170":42,"hz310":33,"hz600":20,"hz1000":24,"hz3000":35,"hz6000":46,"hz12000":50,"hz14000":52,"hz16000":52,"preamp":33},{"name":"Live","hz60":24,"hz170":33,"hz310":39,"hz600":41,"hz1000":42,"hz3000":42,"hz6000":39,"hz12000":37,"hz14000":37,"hz16000":36,"preamp":33},{"name":"Techno","hz60":45,"hz170":42,"hz310":33,"hz600":23,"hz1000":24,"hz3000":33,"hz6000":45,"hz12000":48,"hz14000":48,"hz16000":47,"preamp":33}]}'); ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/PresetsContextMenu.tsx const PresetsContextMenu = () => { const openEqfFileDialog = useActionCreator(files_openEqfFileDialog); const downloadPreset = useActionCreator(files_downloadPreset); const setEqFromObject = useActionCreator(files_setEqFromObject); return /*#__PURE__*/(0,jsx_runtime.jsx)(components_ContextMenuTarget, { top: true, id: "presets-context", renderMenu: () => /*#__PURE__*/(0,jsx_runtime.jsxs)(jsx_runtime.Fragment, { children: [/*#__PURE__*/(0,jsx_runtime.jsxs)(Parent, { label: "Load", children: [builtin_namespaceObject.u.map(preset => /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: () => setEqFromObject(preset), label: preset.name }, preset.name)), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenu_Hr, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: openEqfFileDialog, label: "From Eqf..." })] }), /*#__PURE__*/(0,jsx_runtime.jsx)(Node, { onClick: downloadPreset, label: "Save" })] }), children: /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "presets" }) }); }; /* harmony default export */ const EqualizerWindow_PresetsContextMenu = (PresetsContextMenu); ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/EqTitleButtons.tsx function EqTitleButtons() { const focusedWindow = useTypedSelector(getFocusedWindow); const selected = focusedWindow === WINDOWS.EQUALIZER; const closeWindow = useActionCreator(windows_closeWindow); const toggleEqualizerShadeMode = useActionCreator(windows_toggleEqualizerShadeMode); return /*#__PURE__*/(0,jsx_runtime.jsxs)(components_ClickedDiv, { id: "eq-buttons", children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "equalizer-shade", onClick: toggleEqualizerShadeMode }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "equalizer-close", onClick: () => closeWindow(WINDOWS.EQUALIZER) })] }, selected ? "selected" : "unselected"); } ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/EqualizerShade.tsx const EqualizerShade = () => { const volume = useTypedSelector(getVolume); const balance = useTypedSelector(getBalance); const toggleEqualizerShadeMode = useActionCreator(windows_toggleEqualizerShadeMode); const classes = ["left", "center", "right"]; const eqVolumeClassName = segment(0, 100, volume, classes); const eqBalanceClassName = segment(-100, 100, balance, classes); return /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { className: "draggable", onDoubleClick: toggleEqualizerShadeMode, style: { width: "100%", height: "100%" }, children: [/*#__PURE__*/(0,jsx_runtime.jsx)(EqTitleButtons, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Volume, { id: "equalizer-volume", className: eqVolumeClassName }), /*#__PURE__*/(0,jsx_runtime.jsx)(Balance, { id: "equalizer-balance", className: eqBalanceClassName })] }); }; /* harmony default export */ const EqualizerWindow_EqualizerShade = (EqualizerShade); // EXTERNAL MODULE: ./css/equalizer-window.css var equalizer_window = __webpack_require__(4522); ;// CONCATENATED MODULE: ./js/components/EqualizerWindow/index.tsx const bandClassName = band => `band-${band}`; const EqualizerWindow = () => { const doubled = useTypedSelector(getDoubled); const focusedWindow = useTypedSelector(getFocusedWindow); const getWindowShade = useTypedSelector(selectors_getWindowShade); const selected = focusedWindow === WINDOWS.EQUALIZER; const shade = getWindowShade(WINDOWS.EQUALIZER); const setPreampValue = useActionCreator(setPreamp); const setEqToMin = useActionCreator(equalizer_setEqToMin); const setEqToMid = useActionCreator(equalizer_setEqToMid); const setEqToMax = useActionCreator(equalizer_setEqToMax); const setHertzValue = useActionCreator(setEqBand); const toggleEqualizerShadeMode = useActionCreator(windows_toggleEqualizerShadeMode); const className = classnames_default()({ selected, doubled, shade, window: true, draggable: true }); return /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "equalizer-window", className: className, children: /*#__PURE__*/(0,jsx_runtime.jsx)(components_FocusTarget, { windowId: WINDOWS.EQUALIZER, children: shade ? /*#__PURE__*/(0,jsx_runtime.jsx)(EqualizerWindow_EqualizerShade, {}) : /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { children: [/*#__PURE__*/(0,jsx_runtime.jsx)("div", { className: "equalizer-top title-bar draggable", onDoubleClick: toggleEqualizerShadeMode, children: /*#__PURE__*/(0,jsx_runtime.jsx)(EqTitleButtons, {}) }), /*#__PURE__*/(0,jsx_runtime.jsx)(EqualizerWindow_EqOn, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(EqualizerWindow_EqAuto, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(EqualizerWindow_EqGraph, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(EqualizerWindow_PresetsContextMenu, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(Band, { id: "preamp", band: "preamp", onChange: setPreampValue }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "plus12db", onClick: setEqToMax }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "zerodb", onClick: setEqToMid }), /*#__PURE__*/(0,jsx_runtime.jsx)("div", { id: "minus12db", onClick: setEqToMin }), BANDS.map(hertz => /*#__PURE__*/(0,jsx_runtime.jsx)(Band, { id: bandClassName(hertz), band: hertz, onChange: value => setHertzValue(hertz, value) }, hertz))] }) }) }); }; /* harmony default export */ const components_EqualizerWindow = (EqualizerWindow); ;// CONCATENATED MODULE: ./js/skinSelectors.ts const imageSelectors = { MAIN_BALANCE_BACKGROUND: ["#balance"], MAIN_BALANCE_THUMB: ["#balance::-webkit-slider-thumb", "#balance::-moz-range-thumb"], MAIN_BALANCE_THUMB_ACTIVE: ["#balance:active::-webkit-slider-thumb", "#balance:active::-moz-range-thumb"], MAIN_PREVIOUS_BUTTON: [".actions #previous"], MAIN_PREVIOUS_BUTTON_ACTIVE: [".actions #previous:active"], MAIN_PLAY_BUTTON: [".actions #play"], MAIN_PLAY_BUTTON_ACTIVE: [".actions #play:active"], MAIN_PAUSE_BUTTON: [".actions #pause"], MAIN_PAUSE_BUTTON_ACTIVE: [".actions #pause:active"], MAIN_STOP_BUTTON: [".actions #stop"], MAIN_STOP_BUTTON_ACTIVE: [".actions #stop:active"], MAIN_NEXT_BUTTON: [".actions #next"], MAIN_NEXT_BUTTON_ACTIVE: [".actions #next:active"], MAIN_EJECT_BUTTON: ["#eject"], MAIN_EJECT_BUTTON_ACTIVE: ["#eject:active"], MAIN_WINDOW_BACKGROUND: ["#main-window"], MAIN_STEREO: [".media-info #stereo", ".stop .media-info #stereo.selected"], MAIN_STEREO_SELECTED: [".media-info #stereo.selected"], MAIN_MONO: [".media-info #mono", ".stop .media-info #mono.selected"], MAIN_MONO_SELECTED: [".media-info #mono.selected"], NO_MINUS_SIGN: ["#time #minus-sign"], MINUS_SIGN: ["#time.countdown #minus-sign"], DIGIT_0: [".digit-0"], DIGIT_1: [".digit-1"], DIGIT_2: [".digit-2"], DIGIT_3: [".digit-3"], DIGIT_4: [".digit-4"], DIGIT_5: [".digit-5"], DIGIT_6: [".digit-6"], DIGIT_7: [".digit-7"], DIGIT_8: [".digit-8"], DIGIT_9: [".digit-9"], NO_MINUS_SIGN_EX: ["#time #minus-sign"], MINUS_SIGN_EX: ["#time.countdown #minus-sign"], DIGIT_0_EX: [".digit-0"], DIGIT_1_EX: [".digit-1"], DIGIT_2_EX: [".digit-2"], DIGIT_3_EX: [".digit-3"], DIGIT_4_EX: [".digit-4"], DIGIT_5_EX: [".digit-5"], DIGIT_6_EX: [".digit-6"], DIGIT_7_EX: [".digit-7"], DIGIT_8_EX: [".digit-8"], DIGIT_9_EX: [".digit-9"], MAIN_PLAYING_INDICATOR: [".play #play-pause"], MAIN_PAUSED_INDICATOR: [".pause #play-pause"], MAIN_STOPPED_INDICATOR: [".stop #play-pause"], MAIN_NOT_WORKING_INDICATOR: ["#work-indicator"], MAIN_WORKING_INDICATOR: ["#work-indicator.selected"], PLAYLIST_TOP_TILE: [".playlist-top-left-fill", ".playlist-top-left-spacer", ".playlist-top-right-fill", ".playlist-top-right-spacer"], PLAYLIST_TOP_LEFT_CORNER: [".playlist-top-left"], PLAYLIST_TITLE_BAR: [".playlist-top-title"], PLAYLIST_TOP_RIGHT_CORNER: [".playlist-top-right"], PLAYLIST_TOP_TILE_SELECTED: [".selected .playlist-top-left-fill", ".selected .playlist-top-left-spacer", ".selected .playlist-top-right-fill", ".selected .playlist-top-right-spacer"], PLAYLIST_TOP_LEFT_SELECTED: [".selected .playlist-top-left"], PLAYLIST_TITLE_BAR_SELECTED: [".selected .playlist-top-title"], PLAYLIST_TOP_RIGHT_CORNER_SELECTED: [".selected .playlist-top-right"], PLAYLIST_LEFT_TILE: [".playlist-middle-left"], PLAYLIST_RIGHT_TILE: [".playlist-middle-right"], PLAYLIST_SCROLL_HANDLE: [".playlist-scrollbar-handle"], PLAYLIST_SCROLL_HANDLE_SELECTED: [".playlist-middle-right:active .playlist-scrollbar-handle"], PLAYLIST_BOTTOM_TILE: [".playlist-bottom"], PLAYLIST_BOTTOM_LEFT_CORNER: [".playlist-bottom-left"], PLAYLIST_BOTTOM_RIGHT_CORNER: [".playlist-bottom-right"], PLAYLIST_VISUALIZER_BACKGROUND: [".playlist-visualizer"], PLAYLIST_SHADE_BACKGROUND: ["#playlist-window-shade"], PLAYLIST_SHADE_BACKGROUND_LEFT: ["#playlist-window-shade .left"], PLAYLIST_SHADE_BACKGROUND_RIGHT: ["#playlist-window-shade .right"], PLAYLIST_SHADE_BACKGROUND_RIGHT_SELECTED: ["#playlist-window-shade.selected .right"], PLAYLIST_ADD_MENU_BAR: ["#playlist-add-menu.selected .bar"], PLAYLIST_ADD_URL: ["#playlist-add-menu .add-url"], PLAYLIST_ADD_URL_SELECTED: ["#playlist-add-menu .hover .add-url"], PLAYLIST_ADD_DIR: ["#playlist-add-menu .add-dir"], PLAYLIST_ADD_DIR_SELECTED: ["#playlist-add-menu .hover .add-dir"], PLAYLIST_ADD_FILE: ["#playlist-add-menu .add-file"], PLAYLIST_ADD_FILE_SELECTED: ["#playlist-add-menu .hover .add-file"], PLAYLIST_REMOVE_MENU_BAR: ["#playlist-remove-menu.selected .bar"], PLAYLIST_REMOVE_ALL: ["#playlist-remove-menu .remove-all"], PLAYLIST_REMOVE_ALL_SELECTED: ["#playlist-remove-menu .hover .remove-all"], PLAYLIST_CROP: ["#playlist-remove-menu .crop"], PLAYLIST_CROP_SELECTED: ["#playlist-remove-menu .hover .crop"], PLAYLIST_REMOVE_SELECTED: ["#playlist-remove-menu .remove-selected"], PLAYLIST_REMOVE_SELECTED_SELECTED: ["#playlist-remove-menu .hover .remove-selected"], PLAYLIST_REMOVE_MISC: ["#playlist-remove-menu .remove-misc"], PLAYLIST_REMOVE_MISC_SELECTED: ["#playlist-remove-menu .hover .remove-misc"], PLAYLIST_SELECT_MENU_BAR: ["#playlist-selection-menu.selected .bar"], PLAYLIST_INVERT_SELECTION: ["#playlist-selection-menu .invert-selection"], PLAYLIST_INVERT_SELECTION_SELECTED: ["#playlist-selection-menu .hover .invert-selection"], PLAYLIST_SELECT_ZERO: ["#playlist-selection-menu .select-zero"], PLAYLIST_SELECT_ZERO_SELECTED: ["#playlist-selection-menu .hover .select-zero"], PLAYLIST_SELECT_ALL: ["#playlist-selection-menu .select-all"], PLAYLIST_SELECT_ALL_SELECTED: ["#playlist-selection-menu .hover .select-all"], PLAYLIST_CLOSE_SELECTED: ["#playlist-close-button:active"], PLAYLIST_COLLAPSE_SELECTED: ["#playlist-window #playlist-shade-button:active"], PLAYLIST_EXPAND_SELECTED: ["#playlist-window-shade #playlist-shade-button:active"], PLAYLIST_MISC_MENU_BAR: ["#playlist-misc-menu.selected .bar"], PLAYLIST_MISC_OPTIONS: ["#playlist-misc-menu .misc-options"], PLAYLIST_MISC_OPTIONS_SELECTED: ["#playlist-misc-menu .hover .misc-options"], PLAYLIST_FILE_INFO: ["#playlist-misc-menu .file-info"], PLAYLIST_FILE_INFO_SELECTED: ["#playlist-misc-menu .hover .file-info"], PLAYLIST_SORT_LIST: ["#playlist-misc-menu .sort-list"], PLAYLIST_SORT_LIST_SELECTED: ["#playlist-misc-menu .hover .sort-list"], PLAYLIST_LIST_BAR: ["#playlist-list-menu.selected .bar"], PLAYLIST_NEW_LIST: ["#playlist-list-menu .new-list"], PLAYLIST_NEW_LIST_SELECTED: ["#playlist-list-menu .hover .new-list"], PLAYLIST_LOAD_LIST: ["#playlist-list-menu .load-list"], PLAYLIST_LOAD_LIST_SELECTED: ["#playlist-list-menu .hover .load-list"], PLAYLIST_SAVE_LIST: ["#playlist-list-menu .save-list"], PLAYLIST_SAVE_LIST_SELECTED: ["#playlist-list-menu .hover .save-list"], EQ_WINDOW_BACKGROUND: ["#equalizer-window:not(.shade)"], EQ_TITLE_BAR: [".equalizer-top"], EQ_TITLE_BAR_SELECTED: [".selected .equalizer-top"], EQ_SLIDER_BACKGROUND: [".band"], EQ_SLIDER_THUMB: [".band .slider-handle"], // But the "active" pseudo selector on the parent, since clicking // anywhere on the track moves the slider. EQ_SLIDER_THUMB_SELECTED: [".band:active .slider-handle"], EQ_ON_BUTTON: ["#on"], EQ_ON_BUTTON_DEPRESSED: ["#on:active"], EQ_ON_BUTTON_SELECTED: ["#on.selected"], EQ_ON_BUTTON_SELECTED_DEPRESSED: ["#on.selected:active"], EQ_AUTO_BUTTON: ["#auto"], EQ_AUTO_BUTTON_DEPRESSED: ["#auto:active"], EQ_AUTO_BUTTON_SELECTED: ["#auto.selected"], EQ_AUTO_BUTTON_SELECTED_DEPRESSED: ["#auto.selected:active"], EQ_GRAPH_BACKGROUND: ["#eqGraph"], EQ_PRESETS_BUTTON: ["#presets"], EQ_PRESETS_BUTTON_SELECTED: ["#presets:active"], EQ_PREAMP_LINE: ["#preamp-line"], EQ_SHADE_BACKGROUND: ["#equalizer-window.shade"], EQ_SHADE_BACKGROUND_SELECTED: ["#equalizer-window.shade.selected"], EQ_SHADE_VOLUME_SLIDER_LEFT: ["#equalizer-volume.left::-webkit-slider-thumb", "#equalizer-volume.left::-moz-range-thumb"], EQ_SHADE_VOLUME_SLIDER_CENTER: ["#equalizer-volume.center::-webkit-slider-thumb", "#equalizer-volume.center::-moz-range-thumb"], EQ_SHADE_VOLUME_SLIDER_RIGHT: ["#equalizer-volume.right::-webkit-slider-thumb", "#equalizer-volume.right::-moz-range-thumb"], EQ_SHADE_BALANCE_SLIDER_LEFT: ["#equalizer-balance.left::-webkit-slider-thumb", "#equalizer-balance.left::-moz-range-thumb"], EQ_SHADE_BALANCE_SLIDER_CENTER: ["#equalizer-balance.center::-webkit-slider-thumb", "#equalizer-balance.center::-moz-range-thumb"], EQ_SHADE_BALANCE_SLIDER_RIGHT: ["#equalizer-balance.right::-webkit-slider-thumb", "#equalizer-balance.right::-moz-range-thumb"], EQ_MAXIMIZE_BUTTON_ACTIVE: ["#equalizer-shade:active"], EQ_MINIMIZE_BUTTON_ACTIVE: ["#equalizer-window.shade #equalizer-shade:active"], EQ_CLOSE_BUTTON: ["#equalizer-window.selected #eq-buttons.clicked #equalizer-close"], EQ_CLOSE_BUTTON_ACTIVE: ["#equalizer-window.selected #eq-buttons.clicked #equalizer-close:active"], EQ_SHADE_CLOSE_BUTTON: ["#equalizer-window.shade.selected #eq-buttons.clicked #equalizer-close"], EQ_SHADE_CLOSE_BUTTON_ACTIVE: ["#equalizer-window.shade.selected #eq-buttons.clicked #equalizer-close:active"], MAIN_POSITION_SLIDER_BACKGROUND: ["#position"], MAIN_POSITION_SLIDER_THUMB: ["#position::-webkit-slider-thumb", "#position::-moz-range-thumb"], MAIN_POSITION_SLIDER_THUMB_SELECTED: ["#position:active::-webkit-slider-thumb", "#position:active::-moz-range-thumb"], MAIN_SHUFFLE_BUTTON: ["#shuffle"], MAIN_SHUFFLE_BUTTON_DEPRESSED: ["#shuffle:active"], MAIN_SHUFFLE_BUTTON_SELECTED: ["#shuffle.selected"], MAIN_SHUFFLE_BUTTON_SELECTED_DEPRESSED: ["#shuffle.selected:active"], MAIN_REPEAT_BUTTON: ["#repeat"], MAIN_REPEAT_BUTTON_DEPRESSED: ["#repeat:active"], MAIN_REPEAT_BUTTON_SELECTED: ["#repeat.selected"], MAIN_REPEAT_BUTTON_SELECTED_DEPRESSED: ["#repeat.selected:active"], MAIN_EQ_BUTTON: ["#equalizer-button"], MAIN_EQ_BUTTON_SELECTED: ["#equalizer-button.selected"], MAIN_EQ_BUTTON_DEPRESSED: ["#equalizer-button:active"], MAIN_EQ_BUTTON_DEPRESSED_SELECTED: ["#equalizer-button.selected:active"], MAIN_PLAYLIST_BUTTON: ["#playlist-button"], MAIN_PLAYLIST_BUTTON_SELECTED: ["#playlist-button.selected"], MAIN_PLAYLIST_BUTTON_DEPRESSED: ["#playlist-button:active"], MAIN_PLAYLIST_BUTTON_DEPRESSED_SELECTED: ["#playlist-button.selected:active"], MAIN_TITLE_BAR: ["#title-bar"], MAIN_TITLE_BAR_SELECTED: [".selected #title-bar"], MAIN_EASTER_EGG_TITLE_BAR: [".llama #title-bar"], MAIN_EASTER_EGG_TITLE_BAR_SELECTED: [".llama.selected #title-bar"], MAIN_OPTIONS_BUTTON: [".selected #title-bar #option.clicked"], MAIN_OPTIONS_BUTTON_DEPRESSED: [".selected #title-bar #option:active", ".selected #title-bar #option.selected"], MAIN_MINIMIZE_BUTTON: [".selected #title-bar #minimize.clicked"], MAIN_MINIMIZE_BUTTON_DEPRESSED: [".selected #title-bar #minimize:active"], MAIN_SHADE_BUTTON: [".selected #title-bar #shade.clicked"], MAIN_SHADE_BUTTON_DEPRESSED: [".selected #title-bar #shade:active"], MAIN_CLOSE_BUTTON: [".selected #title-bar #close.clicked"], MAIN_CLOSE_BUTTON_DEPRESSED: [".selected #title-bar #close:active"], MAIN_CLUTTER_BAR_BACKGROUND: ["#clutter-bar"], MAIN_CLUTTER_BAR_BACKGROUND_DISABLED: ["#clutter-bar.disabled"], MAIN_CLUTTER_BAR_BUTTON_O_SELECTED: ["#button-o:active", "#button-0.selected"], MAIN_CLUTTER_BAR_BUTTON_A_SELECTED: ["#button-a:active", "#button-a.selected"], MAIN_CLUTTER_BAR_BUTTON_I_SELECTED: ["#button-i:active", "#button-i.selected"], MAIN_CLUTTER_BAR_BUTTON_D_SELECTED: ["#button-d:active", "#button-d.selected"], MAIN_CLUTTER_BAR_BUTTON_V_SELECTED: ["#button-v:active", "#button-v.selected"], MAIN_SHADE_BACKGROUND: [".shade #title-bar"], MAIN_SHADE_BACKGROUND_SELECTED: [".shade.selected #title-bar"], MAIN_SHADE_BUTTON_SELECTED: [".shade.selected #title-bar #shade"], MAIN_SHADE_BUTTON_SELECTED_DEPRESSED: [".shade #title-bar #shade:active"], MAIN_SHADE_POSITION_BACKGROUND: [".shade #position"], MAIN_SHADE_POSITION_THUMB: [".shade #position::-moz-range-thumb", ".shade #position::-webkit-slider-thumb"], MAIN_SHADE_POSITION_THUMB_LEFT: [".shade #position.left::-moz-range-thumb", ".shade #position.left::-webkit-slider-thumb"], MAIN_SHADE_POSITION_THUMB_RIGHT: [".shade #position.right::-moz-range-thumb", ".shade #position.right::-webkit-slider-thumb"], MAIN_VOLUME_BACKGROUND: ["#volume"], MAIN_VOLUME_THUMB: ["#volume input::-webkit-slider-thumb", "#volume input::-moz-range-thumb"], MAIN_VOLUME_THUMB_SELECTED: ["#volume input:active::-webkit-slider-thumb", "#volume input:active::-moz-range-thumb"], GEN_TOP_CENTER_FILL: [".gen-window .gen-top"], GEN_TOP_LEFT: [".gen-window .gen-top-left"], GEN_TOP_LEFT_END: [".gen-window .gen-top-left-end"], GEN_TOP_RIGHT: [".gen-window .gen-top-right"], GEN_TOP_RIGHT_END: [".gen-window .gen-top-right-end"], GEN_TOP_LEFT_RIGHT_FILL: [".gen-window .gen-top-left-fill", ".gen-window .gen-top-right-fill"], GEN_TOP_CENTER_FILL_SELECTED: [".gen-window.selected .gen-top"], GEN_TOP_LEFT_SELECTED: [".gen-window.selected .gen-top-left"], GEN_TOP_LEFT_END_SELECTED: [".gen-window.selected .gen-top-left-end"], GEN_TOP_RIGHT_SELECTED: [".gen-window.selected .gen-top-right"], GEN_TOP_RIGHT_END_SELECTED: [".gen-window.selected .gen-top-right-end"], GEN_TOP_LEFT_RIGHT_FILL_SELECTED: [".gen-window.selected .gen-top-left-fill", ".gen-window.selected .gen-top-right-fill"], GEN_BOTTOM_LEFT: [".gen-window .gen-bottom-left"], GEN_BOTTOM_RIGHT: [".gen-window .gen-bottom-right"], GEN_BOTTOM_FILL: [".gen-window .gen-bottom"], GEN_MIDDLE_LEFT: [".gen-window .gen-middle-left"], GEN_MIDDLE_LEFT_BOTTOM: [".gen-window .gen-middle-left-bottom"], GEN_MIDDLE_RIGHT: [".gen-window .gen-middle-right"], GEN_MIDDLE_RIGHT_BOTTOM: [".gen-window .gen-middle-right-bottom"], GEN_CLOSE_SELECTED: [".gen-window .gen-close:active"] }; Object.keys(FONT_LOOKUP).forEach(character => { const key = imageConstFromChar(character); const code = character.charCodeAt(0); imageSelectors[key] = [`.character-${code}`]; }); LETTERS.forEach(character => { imageSelectors[`GEN_TEXT_${character}`] = [`.gen-text-${character.toLowerCase()}`]; imageSelectors[`GEN_TEXT_SELECTED_${character}`] = [`.gen-window.selected .gen-text-${character.toLowerCase()}`]; }); const cursorSelectors = { CLOSE: ["#title-bar #close"], // This is not quite right. There are some areas that show this cursor // but are not clickable. EQSLID: ["#equalizer-window .band"], EQNORMAL: ["#equalizer-window"], EQCLOSE: ["#equalizer-window #equalizer-close"], EQTITLE: ["#equalizer-window .title-bar", "#equalizer-window.shade", "#equalizer-window.shade input"], MAINMENU: ["#main-window #option", "#webamp-context-menu .context-menu"], MIN: ["#main-window #minimize"], NORMAL: [ // Use this as the default cursor. ".window", ".window input", // Otherwise "#main-window", "#main-window.shade #title-bar"], MMENU: ["#main-window.shade #option"], PNORMAL: ["#playlist-window"], // TODO: This is should really only apply to the top part of the top. // The chrome around the playlist window is larger than others. The // cursor only applies to the same height as the other window's chrome. PTBAR: ["#playlist-window .playlist-top"], PCLOSE: ["#playlist-window #playlist-close-button", "#playlist-window-shade #playlist-close-button"], PWINBUT: ["#playlist-window #playlist-shade-button", "#playlist-window-shade #playlist-shade-button"], POSBAR: ["#main-window #position"], PSIZE: ["#playlist-window #playlist-resize-target"], PWSSIZE: ["#playlist-window-shade #playlist-resize-target"], PWSNORM: ["#playlist-window-shade"], // TODO: The target for this is not quite right. PVSCROLL: ["#playlist-window .playlist-scrollbar"], SONGNAME: ["#main-window #marquee"], TITLEBAR: ["#main-window #title-bar"], VOLBAL: ["#volume", "#volume input", "#balance"], WINBUT: ["#main-window #shade"], WSNORMAL: ["#main-window.shade #title-bar"], WSPOSBAR: ["#main-window.shade #position"] }; ;// CONCATENATED MODULE: ./js/components/Css.tsx function Css({ children, id }) { const style = (0,react.useMemo)(() => { const s = document.createElement("style"); s.type = "text/css"; s.id = id; return s; }, [id]); (0,react.useLayoutEffect)(() => { document.head.appendChild(style); return () => style.remove(); }, [style]); return /*#__PURE__*/(0,react_dom.createPortal)(children, style); } ;// CONCATENATED MODULE: ./js/components/ClipPaths.tsx // this.props.children should be an object containing arrays of strings. The // keys are ids, and the arrays are arrays of polygon point strings function ClipPaths({ children }) { const paths = (0,react.useMemo)(() => { return document.createElement("div"); }, []); (0,react.useLayoutEffect)(() => { document.body.appendChild(paths); return () => paths.remove(); }, [paths]); return /*#__PURE__*/(0,react_dom.createPortal)( /*#__PURE__*/(0,jsx_runtime.jsx)("svg", { height: 0, width: 0, children: /*#__PURE__*/(0,jsx_runtime.jsx)("defs", { children: Object.keys(children).map(id => /*#__PURE__*/(0,jsx_runtime.jsx)("clipPath", { id: id, children: children[id].map((points, i) => /*#__PURE__*/(0,jsx_runtime.jsx)("polygon", { points: points }, i)) }, id)) }) }), paths); } // EXTERNAL MODULE: ../ani-cursor/dist/index.js var dist = __webpack_require__(1894); ;// CONCATENATED MODULE: ./js/components/Skin.tsx // Dynamically set the css background images for all the sprites const CSS_PREFIX = "#webamp"; const mapRegionNamesToIds = { normal: "mainWindowClipPath", windowshade: "shadeMainWindowClipPath", equalizer: "equalizerWindowClipPath", equalizerws: "shadeEqualizerWindowClipPath" }; const mapRegionNamesToMatcher = { normal: "#main-window:not(.shade)", windowshade: "#main-window.shade", equalizer: "#equalizer-window:not(.shade)", equalizerws: "#equalizer-window.shade" }; const numExIsUsed = skinImages => Boolean(skinImages.DIGIT_0_EX); const FALLBACKS = { MAIN_BALANCE_BACKGROUND: "MAIN_VOLUME_BACKGROUND", MAIN_BALANCE_THUMB: "MAIN_VOLUME_THUMB", MAIN_BALANCE_THUMB_ACTIVE: "MAIN_VOLUME_THUMB_SELECTED", EQ_MAXIMIZE_BUTTON_ACTIVE: "EQ_MAXIMIZE_BUTTON_ACTIVE_FALLBACK" }; // Cursors might appear in context menus which are not nested inside the window layout div. function normalizeCursorSelector(selector) { return `${ // TODO: Fix this hack // Maybe our CSS name spacing should be based on some other class/id // than the one we use for defining the main div. // That way it could be shared by both the player and the context menu. selector.startsWith("#webamp-context-menu") ? "" : CSS_PREFIX} ${selector}`; } const getCssRules = (0,lib/* createSelector */.P1)(getSkinImages, getSkinCursors, getSkinLetterWidths, getSkinRegion, (skinImages, skinCursors, skinGenLetterWidths, skinRegion) => { if (!skinImages || !skinCursors) { return null; } const cssRules = []; Object.keys(imageSelectors).forEach(imageName => { const imageUrl = skinImages[imageName] || skinImages[FALLBACKS[imageName]]; if (imageUrl) { imageSelectors[imageName].forEach(selector => { cssRules.push(`${CSS_PREFIX} ${selector} {background-image: url(${imageUrl})}`); }); } }); if (skinGenLetterWidths != null) { LETTERS.forEach(letter => { const width = skinGenLetterWidths[`GEN_TEXT_${letter}`]; const selectedWidth = skinGenLetterWidths[`GEN_TEXT_SELECTED_${letter}`]; cssRules.push(`${CSS_PREFIX} .gen-text-${letter.toLowerCase()} {width: ${width}px;}`); cssRules.push(`${CSS_PREFIX} .selected .gen-text-${letter.toLowerCase()} {width: ${selectedWidth}px;}`); }); } Object.entries(cursorSelectors).forEach(([cursorName, cursorSelector]) => { const cursor = skinCursors[cursorName]; if (cursor == null) { return; } const cursorRules = cursorSelector.map(normalizeCursorSelector).map(selector => { switch (cursor.type) { case "cur": return `${selector} {cursor: url(${cursor.url}), auto}`; case "ani": { return (0,dist.convertAniBinaryToCSS)(selector, cursor.aniData); } } }); cssRules.push(...cursorRules); }); if (numExIsUsed(skinImages)) { // This alternate number file requires that the minus sign be // formatted differently. cssRules.push(`${CSS_PREFIX} .status #time #minus-sign { top: 0px; left: -1px; width: 9px; height: 13px; }`); } for (const [regionName, polygons] of Object.entries(skinRegion)) { if (polygons) { const matcher = mapRegionNamesToMatcher[regionName]; const id = mapRegionNamesToIds[regionName]; cssRules.push(`${CSS_PREFIX} ${matcher} { clip-path: url(#${id}); }`); } } return cssRules.join("\n"); }); const getClipPaths = (0,lib/* createSelector */.P1)(getSkinRegion, skinRegion => { const clipPaths = {}; for (const [regionName, polygons] of Object.entries(skinRegion)) { if (polygons) { const id = mapRegionNamesToIds[regionName]; clipPaths[id] = polygons; } } return clipPaths; }); function Skin() { const cssRules = useTypedSelector(getCssRules); const clipPaths = useTypedSelector(getClipPaths); if (cssRules == null) { return null; } return /*#__PURE__*/(0,jsx_runtime.jsxs)(jsx_runtime.Fragment, { children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Css, { id: "webamp-skin", children: cssRules }), /*#__PURE__*/(0,jsx_runtime.jsx)(ClipPaths, { children: clipPaths })] }); } // EXTERNAL MODULE: ./css/webamp.css var webamp = __webpack_require__(9479); ;// CONCATENATED MODULE: ./js/components/App.tsx /** * Constructs the windows to render */ function App({ media, filePickers }) { const closed = useTypedSelector(getClosed); const genWindowsInfo = useTypedSelector(getGenWindows); const zIndex = useTypedSelector(getZIndex); const browserWindowSizeChanged = useActionCreator(windows_browserWindowSizeChanged); const setFocusedWindow = useActionCreator(windows_setFocusedWindow); const [webampNode] = (0,react.useState)(() => { const node = document.createElement("div"); node.id = "webamp"; // @ts-ignore I think I'm supposed to set this with setAttribute, but I can't confirm. node.role = "application"; return node; }); (0,react.useLayoutEffect)(() => { webampNode.style.zIndex = String(zIndex); }, [webampNode, zIndex]); (0,react.useLayoutEffect)(() => { document.body.appendChild(webampNode); return () => { document.body.removeChild(webampNode); }; }, [webampNode]); (0,react.useEffect)(() => { const handleWindowResize = () => { if (webampNode == null) { return; } // It's a bit tricky to measure the "natural" size of the browser window. // Specifically we want to know how large the window would be without our // own Webamp windows influencing it. To achieve this, we temporarily make // our container `overflow: hidden;`. We then make our container full // screen by setting the bottom/right properties to zero. This second part // allows our Webamp windows to stay visible during the resize. After we // measure, we set the style back so that we don't end up interfering with // click events outside of our Webamp windows. webampNode.style.right = "0"; webampNode.style.bottom = "0"; webampNode.style.overflow = "hidden"; browserWindowSizeChanged(getWindowSize()); webampNode.style.right = "auto"; webampNode.style.bottom = "auto"; webampNode.style.overflow = "visible"; }; handleWindowResize(); window.addEventListener("resize", handleWindowResize); return () => { window.removeEventListener("resize", handleWindowResize); }; }, [browserWindowSizeChanged, webampNode]); const renderWindows = (0,react.useCallback)(() => { return objectMap(genWindowsInfo, (w, id) => { if (!w.open) { return null; } switch (id) { case WINDOWS.MAIN: return /*#__PURE__*/(0,jsx_runtime.jsx)(components_MainWindow, { analyser: media.getAnalyser(), filePickers: filePickers }); case WINDOWS.EQUALIZER: return /*#__PURE__*/(0,jsx_runtime.jsx)(components_EqualizerWindow, {}); case WINDOWS.PLAYLIST: return /*#__PURE__*/(0,jsx_runtime.jsx)(components_PlaylistWindow, { analyser: media.getAnalyser() }); case WINDOWS.MILKDROP: return /*#__PURE__*/(0,jsx_runtime.jsx)(MilkdropWindow, { analyser: media.getAnalyser() }); default: throw new Error(`Tried to render an unknown window: ${id}`); } }); }, [media, filePickers, genWindowsInfo]); const handleBlur = e => { if (!e.currentTarget.contains(e.relatedTarget)) { setFocusedWindow(null); } }; if (closed) { return null; } return /*#__PURE__*/react_dom.createPortal( /*#__PURE__*/(0,jsx_runtime.jsx)(react.StrictMode, { children: /*#__PURE__*/(0,jsx_runtime.jsxs)("div", { onBlur: handleBlur, children: [/*#__PURE__*/(0,jsx_runtime.jsx)(Skin, {}), /*#__PURE__*/(0,jsx_runtime.jsx)(ContextMenuWraper, { renderContents: () => /*#__PURE__*/(0,jsx_runtime.jsx)(MainWindow_MainContextMenu, { filePickers: filePickers }), children: /*#__PURE__*/(0,jsx_runtime.jsx)(WindowManager, { windows: renderWindows() }) })] }) }), webampNode); } ;// CONCATENATED MODULE: ./js/hotkeys.ts const IGNORE_EVENTS_FROM_TAGS = new Set(["input", "textarea", "select"]); function bindHotkeys(dispatch) { let currentPos = 0; const trigger = [78, // N 85, // U 76, // L 76, // L 83, // S 79, // O 70, // F 84 // T ]; const listener = e => { if (e.target instanceof Element && IGNORE_EVENTS_FROM_TAGS.has(e.target.tagName.toLowerCase())) { return; } if (e.ctrlKey) { switch (e.keyCode) { case 68: // CTRL+D dispatch(windows_toggleDoubleSizeMode()); e.preventDefault(); // Supress the "Bookmark" action on windows. break; case 76: // CTRL+L FIXME break; case 82: // CTRL+R dispatch(playlist_reverseList()); break; case 84: // CTRL+T dispatch({ type: TOGGLE_TIME_MODE }); break; } } else if (e.altKey) { switch (e.keyCode) { case 87: // ALT+W dispatch(windows_toggleWindow("main")); break; case 69: // ALT+E dispatch(windows_toggleWindow("playlist")); break; case 71: // ALT+G dispatch(windows_toggleWindow("equalizer")); break; } } else { switch (e.keyCode) { case 37: // left arrow dispatch(media_seekBackward(5)); break; case 38: // up arrow dispatch(adjustVolume(1)); break; case 39: // right arrow dispatch(media_seekForward(5)); break; case 40: // down arrow dispatch(adjustVolume(-1)); break; case 66: // B dispatch(media_next()); break; case 67: // C dispatch(media_pause()); break; case 76: // L dispatch(files_openMediaFileDialog()); break; case 82: // R dispatch(media_toggleRepeat()); break; case 83: // S dispatch(media_toggleShuffle()); break; case 86: // V dispatch(media_stop()); break; case 88: // X dispatch(media_play()); break; case 90: // Z dispatch(media_previous()); break; case 96: // numpad 0 dispatch(files_openMediaFileDialog()); break; case 97: // numpad 1 dispatch(media_nextN(-10)); break; case 98: // numpad 2 dispatch(adjustVolume(-1)); break; case 99: // numpad 3 dispatch(media_nextN(10)); break; case 100: // numpad 4 dispatch(media_previous()); break; case 101: // numpad 5 dispatch(media_play()); break; case 102: // numpad 6 dispatch(media_next()); break; case 103: // numpad 7 dispatch(media_seekBackward(5)); break; case 104: // numpad 8 dispatch(adjustVolume(1)); break; case 105: // numpad 9 dispatch(media_seekForward(5)); break; } } // Easter Egg // Ignore escape. Usually this gets swallowed by the browser, but not always. if (e.keyCode !== 27) { currentPos = e.keyCode === trigger[currentPos] ? currentPos + 1 : 0; if (currentPos === trigger.length) { dispatch({ type: actionTypes_TOGGLE_LLAMA_MODE }); } } }; document.addEventListener("keydown", listener); return () => { document.removeEventListener("keydown", listener); }; } ;// CONCATENATED MODULE: ./js/emitter.ts class Emitter { constructor() { (0,defineProperty/* default */.Z)(this, "_listeners", void 0); this._listeners = {}; } on(event, callback) { const eventListeners = this._listeners[event] || []; eventListeners.push(callback); this._listeners[event] = eventListeners; const unsubscribe = () => { this._listeners[event] = eventListeners.filter(cb => cb !== callback); }; return unsubscribe; } trigger(event, ...args) { const callbacks = this._listeners[event]; if (callbacks) { callbacks.forEach(cb => cb(...args)); } } dispose() { this._listeners = {}; } } ;// CONCATENATED MODULE: ./js/media/StereoBalanceNode.js // The Web Audio API does not offer an easy way to make a stereo balance // control. This is an attempt to fill that void, using an API similar to // [StereoPannerNode](https://developer.mozilla.org/en-US/docs/Web/API/StereoPannerNode) function StereoBalanceNode(context, options = { balance: 0 }) { let balance = 0; // ChannelSplitterNode cannot be told to use a `channelInterperatation` of // "speakers". This means that if we get a mono file, we will end up only // playing in the left speaker. So instead we use this dummy gain node to // convert whatever source we get (stereo, mono, or n channels) into a stereo // signal. // Idea credit: https://github.com/WebAudio/web-audio-api/issues/975#issue-177242377 const upMixer = context.createGain(); upMixer.channelCount = 2; upMixer.channelCountMode = "explicit"; upMixer.channelInterpretation = "speakers"; const splitter = context.createChannelSplitter(2); // Create the gains for left and right const leftGain = context.createGain(); const rightGain = context.createGain(); const merger = context.createChannelMerger(2); upMixer.connect(splitter); splitter.connect(leftGain, 0); splitter.connect(rightGain, 1); leftGain.connect(merger, 0, 0); rightGain.connect(merger, 0, 1); // -1 (left) to 1 (right) function set(rawValue) { const value = Number(rawValue); leftGain.gain.value = value > 0 ? 1 - value : 1; rightGain.gain.value = value > 0 ? 1 : 1 + value; balance = value; } function get() { return balance; } // Create our own version of an [AudioParam](https://developer.mozilla.org/en-US/docs/Web/API/AudioParam). // We don't currently support any of the "over time" methods, but maybe some day // we'll want to. const audioParam = {}; Object.defineProperties(audioParam, { value: { get, set, enumerable: true, configurable: true } }); // The way the `.connect` API works, we can't actually construct our own // AudioNode. Instead we have to take an existing node and monkey patch it. Object.defineProperties(upMixer, { balance: { value: audioParam, enumerable: true, writable: false, configurable: true }, connect: { value: AudioNode.prototype.connect.bind(merger), enumerable: false, writable: false, configurable: true }, disconnect: { value: AudioNode.prototype.disconnect.bind(merger), enumerable: false, writable: false, configurable: true } }); if (balance !== options.balance) { set(options.balance); } return upMixer; } ;// CONCATENATED MODULE: ./js/media/elementSource.ts const { ipcRenderer: elementSource_ipcRenderer } = window.require('electron'); class ElementSource { on(eventType, cb) { return this._emitter.on(eventType, cb); } constructor(context, destination) { (0,defineProperty/* default */.Z)(this, "_emitter", void 0); (0,defineProperty/* default */.Z)(this, "_context", void 0); (0,defineProperty/* default */.Z)(this, "_source", void 0); (0,defineProperty/* default */.Z)(this, "_destination", void 0); (0,defineProperty/* default */.Z)(this, "_audio", void 0); (0,defineProperty/* default */.Z)(this, "_stalled", void 0); (0,defineProperty/* default */.Z)(this, "_status", void 0); this._emitter = new Emitter(); this._context = context; this._destination = destination; this._audio = document.createElement("audio"); this._audio.crossOrigin = "anonymous"; this._stalled = false; this._status = MEDIA_STATUS.STOPPED; // TODO: #leak this._audio.addEventListener("suspend", () => { this._setStalled(true); }); // TODO: #leak this._audio.addEventListener("durationchange", () => { this._emitter.trigger("loaded"); this._setStalled(false); }); // TODO: #leak this._audio.addEventListener("ended", () => { this._emitter.trigger("ended"); this._setStatus(MEDIA_STATUS.STOPPED); }); // TODO: Throttle to 50 (if needed) // TODO: #leak this._audio.addEventListener("timeupdate", () => { this._emitter.trigger("positionChange"); }); // TODO: #leak this._audio.addEventListener("error", e => { switch (this._audio.error.code) { case 1: // The fetching of the associated resource was aborted by the user's request. console.error("MEDIA_ERR_ABORTED", e); break; case 2: console.error("MEDIA_ERR_NETWORK", e); // Some kind of network error occurred which prevented the media from being successfully fetched, despite having previously been available. break; case 3: // Despite having previously been determined to be usable, an error occurred while trying to decode the media resource, resulting in an error. // There is a bug in Chrome where improperly terminated mp3s can cuase this error. // https://bugs.chromium.org/p/chromium/issues/detail?id=794782 // Related: Commit f44e826c83c74fef04c2c448af30cfb353b28312 console.error("PIPELINE_ERROR_DECODE", e); break; case 4: console.error("MEDIA_ERR_SRC_NOT_SUPPORTED", e); // The associated resource or media provider object (such as a MediaStream) has been found to be unsuitable. break; } // Rather than just geting stuck in this error state, we can just pretend this is // the end of the track. this._emitter.trigger("ended"); this._setStatus(MEDIA_STATUS.STOPPED); }); this._source = this._context.createMediaElementSource(this._audio); this._source.connect(destination); } _setStalled(stalled) { this._stalled = stalled; this._emitter.trigger("stallChanged"); } disconnect() { this._source.disconnect(); } // Async for now, for compatibility with BufferAudioSource // TODO: This does not need to be async async loadUrl(url) { if (/^\d+$/.test(url) || /^.*-.*-.*-.*-.*$/.test(url)) { await elementSource_ipcRenderer.invoke('getTrackByID', url).then(link => { this._audio.src = link; }); } else { this._audio.src = url; } } async play() { if (this._status !== MEDIA_STATUS.PAUSED) { this.seekToTime(0); } try { await this._audio.play(); // TODO #race } catch (err) { // } this._setStatus(MEDIA_STATUS.PLAYING); } pause() { this._audio.pause(); this._setStatus(MEDIA_STATUS.PAUSED); } stop() { this._audio.pause(); this._audio.currentTime = 0; this._setStatus(MEDIA_STATUS.STOPPED); } seekToTime(time) { /* TODO: We could check if this is actually seekable: const { seekable } = this._audio; for (let i = 0; i < seekable.length; i++) { console.log("start", seekable.start(i), "end", seekable.end(i)); } */ this._audio.currentTime = clamp(time, 0, this.getDuration()); this._emitter.trigger("positionChange"); } getStalled() { return this._stalled; } getStatus() { return this._status; } getDuration() { const { duration } = this._audio; // Safari on iOS currently has a strange behavior where it reports // the duration as infinity if an Accept-Ranges header is not returned. // For now, 0 is better even though it's still wrong. return isNaN(duration) || duration === Infinity ? 0 : duration; } getTimeElapsed() { return this._audio.currentTime; } _setStatus(status) { this._status = status; this._emitter.trigger("statusChange"); } dispose() { // TODO: Dispose subscriptions to this.audio this.stop(); this._emitter.dispose(); } } ;// CONCATENATED MODULE: ./js/media/index.ts /* Emulate the native