From 8cf06fb0df7606be3aaba21141a0569e0eb3ba2d Mon Sep 17 00:00:00 2001 From: okxlin <61420215+okxlin@users.noreply.github.com> Date: Sat, 1 Aug 2026 04:08:38 +0800 Subject: [PATCH] feat: add Polaris app --- apps/polaris/0.16.1-alpine3.24.1/.env.sample | 5 ++ apps/polaris/0.16.1-alpine3.24.1/data.yml | 67 ++++++++++++++ .../0.16.1-alpine3.24.1/docker-compose.yml | 26 ++++++ .../0.16.1-alpine3.24.1/scripts/init.sh | 83 ++++++++++++++++++ .../0.16.1-alpine3.24.1/scripts/uninstall.sh | 5 ++ .../0.16.1-alpine3.24.1/scripts/upgrade.sh | 4 + apps/polaris/README.md | 49 +++++++++++ apps/polaris/README_en.md | 27 ++++++ apps/polaris/data.yml | 30 +++++++ apps/polaris/latest/.env.sample | 5 ++ apps/polaris/latest/data.yml | 67 ++++++++++++++ apps/polaris/latest/docker-compose.yml | 26 ++++++ apps/polaris/latest/scripts/init.sh | 83 ++++++++++++++++++ apps/polaris/latest/scripts/uninstall.sh | 5 ++ apps/polaris/latest/scripts/upgrade.sh | 4 + apps/polaris/logo-LICENSE.txt | 4 + apps/polaris/logo.png | Bin 0 -> 1998 bytes 17 files changed, 490 insertions(+) create mode 100644 apps/polaris/0.16.1-alpine3.24.1/.env.sample create mode 100644 apps/polaris/0.16.1-alpine3.24.1/data.yml create mode 100644 apps/polaris/0.16.1-alpine3.24.1/docker-compose.yml create mode 100755 apps/polaris/0.16.1-alpine3.24.1/scripts/init.sh create mode 100755 apps/polaris/0.16.1-alpine3.24.1/scripts/uninstall.sh create mode 100755 apps/polaris/0.16.1-alpine3.24.1/scripts/upgrade.sh create mode 100644 apps/polaris/README.md create mode 100644 apps/polaris/README_en.md create mode 100644 apps/polaris/data.yml create mode 100644 apps/polaris/latest/.env.sample create mode 100644 apps/polaris/latest/data.yml create mode 100644 apps/polaris/latest/docker-compose.yml create mode 100755 apps/polaris/latest/scripts/init.sh create mode 100755 apps/polaris/latest/scripts/uninstall.sh create mode 100755 apps/polaris/latest/scripts/upgrade.sh create mode 100644 apps/polaris/logo-LICENSE.txt create mode 100644 apps/polaris/logo.png diff --git a/apps/polaris/0.16.1-alpine3.24.1/.env.sample b/apps/polaris/0.16.1-alpine3.24.1/.env.sample new file mode 100644 index 000000000..5f94d5db2 --- /dev/null +++ b/apps/polaris/0.16.1-alpine3.24.1/.env.sample @@ -0,0 +1,5 @@ +PANEL_APP_PORT_HTTP=5050 +POLARIS_MUSIC_DIR=./data/music +POLARIS_CACHE_DIR=./data/cache +POLARIS_DATA_DIR=./data/data +CONTAINER_NAME=polaris-compose-check diff --git a/apps/polaris/0.16.1-alpine3.24.1/data.yml b/apps/polaris/0.16.1-alpine3.24.1/data.yml new file mode 100644 index 000000000..c4d80d00d --- /dev/null +++ b/apps/polaris/0.16.1-alpine3.24.1/data.yml @@ -0,0 +1,67 @@ +additionalProperties: + formFields: + - default: 5050 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: HTTP Port + labelZh: HTTP 端口 + label: + en: HTTP Port + zh: HTTP 端口 + zh-Hant: HTTP 埠 + ja: HTTP ポート + ko: HTTP 포트 + ru: HTTP-порт + ms: Port HTTP + pt-br: Porta HTTP + required: true + rule: paramPort + type: number + - default: ./data/music + edit: true + envKey: POLARIS_MUSIC_DIR + labelEn: Music Directory + labelZh: 音乐目录 + label: + en: Music Directory + zh: 音乐目录 + zh-Hant: 音樂目錄 + ja: 音楽ディレクトリ + ko: 음악 디렉터리 + ru: Каталог музыки + ms: Direktori muzik + pt-br: Diretorio de musicas + required: true + type: text + - default: ./data/cache + edit: true + envKey: POLARIS_CACHE_DIR + labelEn: Cache Directory + labelZh: 缓存目录 + label: + en: Cache Directory + zh: 缓存目录 + zh-Hant: 快取目錄 + ja: キャッシュディレクトリ + ko: 캐시 디렉터리 + ru: Каталог кеша + ms: Direktori cache + pt-br: Diretorio de cache + required: true + type: text + - default: ./data/data + edit: true + envKey: POLARIS_DATA_DIR + labelEn: Data Directory + labelZh: 数据目录 + label: + en: Data Directory + zh: 数据目录 + zh-Hant: 資料目錄 + ja: データディレクトリ + ko: 데이터 디렉터리 + ru: Каталог данных + ms: Direktori data + pt-br: Diretorio de dados + required: true + type: text diff --git a/apps/polaris/0.16.1-alpine3.24.1/docker-compose.yml b/apps/polaris/0.16.1-alpine3.24.1/docker-compose.yml new file mode 100644 index 000000000..7893d9b13 --- /dev/null +++ b/apps/polaris/0.16.1-alpine3.24.1/docker-compose.yml @@ -0,0 +1,26 @@ +services: + polaris: + image: "quay.io/connectical/polaris:0.16.1-alpine3.24.1@sha256:2d29b66af8a555f8789203b55c81c1a5da6312357e18357a88acb6d49e55d75e" + container_name: ${CONTAINER_NAME} + restart: unless-stopped + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:5050" + environment: + - POLARIS_PORT=5050 + - POLARIS_CACHE_DIR=/var/cache/polaris + volumes: + - "${POLARIS_MUSIC_DIR}:/music:ro" + - "${POLARIS_CACHE_DIR}:/var/cache/polaris" + - "${POLARIS_DATA_DIR}:/var/lib/polaris" + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/polaris/0.16.1-alpine3.24.1/scripts/init.sh b/apps/polaris/0.16.1-alpine3.24.1/scripts/init.sh new file mode 100755 index 000000000..c11b41ae2 --- /dev/null +++ b/apps/polaris/0.16.1-alpine3.24.1/scripts/init.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}" +POLARIS_UID=100 +POLARIS_GID=100 + +fail() { + printf '%s\n' "$1" >&2 + exit 1 +} + +read_env_value() { + local key="$1" + local value + value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)" + value="${value%$'\r'}" + case "$value" in + \"*\") value="${value#\"}"; value="${value%\"}" ;; + \'*\') value="${value#\'}"; value="${value%\'}" ;; + esac + printf '%s\n' "$value" +} + +reject_symlink_components() { + local path="$1" + local current="" + local component + IFS='/' read -r -a components <<< "${path#/}" + for component in "${components[@]}"; do + [[ -n "$component" ]] || continue + current="${current}/${component}" + [[ ! -L "$current" ]] || fail "$path must not contain symbolic-link components" + done +} + +resolve_path() { + local key="$1" + local raw="$2" + local candidate + local resolved + + [[ -n "$raw" ]] || fail "$key must not be empty" + [[ "$raw" =~ ^[A-Za-z0-9._/\ -]+$ ]] || fail "$key contains unsupported characters" + if [[ "$raw" == /* ]]; then + candidate="$raw" + else + candidate="${ROOT_DIR}/${raw#./}" + fi + reject_symlink_components "$candidate" + resolved="$(realpath -m -- "$candidate")" || fail "Unable to resolve $key" + [[ "$resolved" != "/" ]] || fail "$key must not be the filesystem root" + if [[ "$raw" != /* ]]; then + case "$resolved" in + "${ROOT_DIR}"/*) ;; + *) fail "Relative $key must stay inside the application directory" ;; + esac + fi + [[ ! -e "$resolved" || -d "$resolved" ]] || fail "$key must be a directory" + printf '%s\n' "$resolved" +} + +prepare_path() { + local key="$1" + local ownership="$2" + local resolved + resolved="$(resolve_path "$key" "$(read_env_value "$key")")" + install -d -m 0755 -- "$resolved" || fail "Unable to create $key" + resolved="$(realpath -e -- "$resolved")" || fail "Unable to verify $key" + reject_symlink_components "$resolved" + [[ -z "$(find "$resolved" -xdev -type l -print -quit)" ]] || fail "$key must not contain symbolic links" + if [[ "$ownership" == "polaris" ]]; then + chown -R --no-dereference "${POLARIS_UID}:${POLARIS_GID}" "$resolved" || fail "Unable to set $key ownership" + fi +} + +[[ "$(id -u)" -eq 0 ]] || fail "Polaris init must run as root" +[[ -f "$ENV_FILE" && ! -L "$ENV_FILE" ]] || fail "Environment file not found or unsafe: $ENV_FILE" + +prepare_path POLARIS_MUSIC_DIR readonly +prepare_path POLARIS_CACHE_DIR polaris +prepare_path POLARIS_DATA_DIR polaris diff --git a/apps/polaris/0.16.1-alpine3.24.1/scripts/uninstall.sh b/apps/polaris/0.16.1-alpine3.24.1/scripts/uninstall.sh new file mode 100755 index 000000000..1c9e63146 --- /dev/null +++ b/apps/polaris/0.16.1-alpine3.24.1/scripts/uninstall.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Music, cache, accounts, playlists, indexes, and the database are user data. +exit 0 diff --git a/apps/polaris/0.16.1-alpine3.24.1/scripts/upgrade.sh b/apps/polaris/0.16.1-alpine3.24.1/scripts/upgrade.sh new file mode 100755 index 000000000..a0676288e --- /dev/null +++ b/apps/polaris/0.16.1-alpine3.24.1/scripts/upgrade.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +exec "$(dirname "${BASH_SOURCE[0]}")/init.sh" diff --git a/apps/polaris/README.md b/apps/polaris/README.md new file mode 100644 index 000000000..c42d6fdea --- /dev/null +++ b/apps/polaris/README.md @@ -0,0 +1,49 @@ +# Polaris + +## 产品介绍 + +Polaris 是一个自托管的音乐收藏与流媒体服务器,可通过浏览器和移动设备访问个人音乐库。 + +## 主要功能 + +- 扫描本地音乐目录并建立可搜索的收藏索引。 +- 使用多账户、播放列表和浏览器流媒体功能管理个人音乐库。 +- 将账户、播放列表、索引和应用数据库持久化保存。 + +## 部署说明 + +- 容器镜像由 Polaris 官方安装文档认可的 Connectical 容器项目提供。 +- 安装后访问表单中配置的 HTTP 端口,创建管理员账户并添加 `/music` 音乐目录。 +- 音乐目录以只读方式挂载;缓存和应用数据目录由 Polaris 的 UID/GID `100:100` 管理。 +- 应用数据包含账户、播放列表、收藏索引和应用数据库,升级前应备份数据目录。 +- 卸载不会删除音乐、缓存或应用数据。 + +## 数据目录 + +| 变量 | 说明 | 默认值 | +| --- | --- | --- | +| `POLARIS_MUSIC_DIR` | 音乐库目录,只读挂载 | `./data/music` | +| `POLARIS_CACHE_DIR` | 扫描和封面缓存目录 | `./data/cache` | +| `POLARIS_DATA_DIR` | 账户、索引和数据库目录 | `./data/data` | + +初始化脚本会拒绝配置目录中的符号链接,并将缓存与数据目录递归设为 `100:100`。请为 Polaris 使用专用目录。 + +## 访问说明 + +安装完成后通过 `http://服务器地址:配置端口` 访问。首次使用时创建管理员账户,将 `/music` 添加为收藏目录,然后开始扫描。 + +## Introduction + +Polaris is a self-hosted music collection and streaming server for browsers and mobile devices. + +## Features + +- Scan a local music directory into a searchable collection. +- Manage multiple users, playlists, and browser-based music streaming. +- Persist accounts, playlists, indexes, and the application database. + +## 参考资料 + +- 项目主页: +- 源代码: +- 容器说明: diff --git a/apps/polaris/README_en.md b/apps/polaris/README_en.md new file mode 100644 index 000000000..2e2c5f231 --- /dev/null +++ b/apps/polaris/README_en.md @@ -0,0 +1,27 @@ +# Polaris + +Polaris is a self-hosted music collection and streaming server for browsers and mobile devices. + +## Deployment + +- The image comes from the Connectical container project endorsed by the Polaris installation guide. +- Open the configured HTTP port, create an administrator, and add `/music` as the collection directory. +- Music is mounted read-only. Cache and application data are owned by Polaris UID/GID `100:100`. +- Application data includes accounts, playlists, the collection index, and the application database. Back it up before upgrading. +- Uninstalling the app does not delete music, cache, or application data. + +## Data directories + +| Variable | Purpose | Default | +| --- | --- | --- | +| `POLARIS_MUSIC_DIR` | Read-only music library | `./data/music` | +| `POLARIS_CACHE_DIR` | Scan and artwork cache | `./data/cache` | +| `POLARIS_DATA_DIR` | Accounts, index, and database | `./data/data` | + +The initialization script rejects symbolic links in configured directories and recursively assigns cache and data ownership to `100:100`. Use dedicated directories for Polaris. + +## References + +- Website: +- Source: +- Container documentation: diff --git a/apps/polaris/data.yml b/apps/polaris/data.yml new file mode 100644 index 000000000..637bdd507 --- /dev/null +++ b/apps/polaris/data.yml @@ -0,0 +1,30 @@ +name: Polaris +tags: + - 多媒体 +title: 自托管的音乐收藏与流媒体服务器 +description: 自托管的音乐收藏与流媒体服务器 +additionalProperties: + key: polaris + name: Polaris + tags: + - Media + shortDescZh: 自托管的音乐收藏与流媒体服务器 + shortDescEn: A self-hosted music collection and streaming server + description: + en: A self-hosted music collection and streaming server + zh: 自托管的音乐收藏与流媒体服务器 + zh-Hant: 自託管的音樂收藏與串流伺服器 + ja: セルフホスト型の音楽コレクションおよびストリーミングサーバー + ko: 자체 호스팅 음악 컬렉션 및 스트리밍 서버 + ru: Самостоятельно размещаемый сервер музыкальной коллекции и потоковой передачи + ms: Pelayan koleksi muzik dan penstriman hos kendiri + pt-br: Servidor auto-hospedado de colecao de musicas e streaming + type: tool + crossVersionUpdate: true + limit: 0 + recommend: 0 + website: https://polaris.stream + github: https://github.com/agersant/polaris + document: https://github.com/agersant/polaris/blob/0d75a85724f43b064410c3dff7e1a78fe5aab04f/docs/CONFIGURATION.md + architectures: + - amd64 diff --git a/apps/polaris/latest/.env.sample b/apps/polaris/latest/.env.sample new file mode 100644 index 000000000..5f94d5db2 --- /dev/null +++ b/apps/polaris/latest/.env.sample @@ -0,0 +1,5 @@ +PANEL_APP_PORT_HTTP=5050 +POLARIS_MUSIC_DIR=./data/music +POLARIS_CACHE_DIR=./data/cache +POLARIS_DATA_DIR=./data/data +CONTAINER_NAME=polaris-compose-check diff --git a/apps/polaris/latest/data.yml b/apps/polaris/latest/data.yml new file mode 100644 index 000000000..c4d80d00d --- /dev/null +++ b/apps/polaris/latest/data.yml @@ -0,0 +1,67 @@ +additionalProperties: + formFields: + - default: 5050 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: HTTP Port + labelZh: HTTP 端口 + label: + en: HTTP Port + zh: HTTP 端口 + zh-Hant: HTTP 埠 + ja: HTTP ポート + ko: HTTP 포트 + ru: HTTP-порт + ms: Port HTTP + pt-br: Porta HTTP + required: true + rule: paramPort + type: number + - default: ./data/music + edit: true + envKey: POLARIS_MUSIC_DIR + labelEn: Music Directory + labelZh: 音乐目录 + label: + en: Music Directory + zh: 音乐目录 + zh-Hant: 音樂目錄 + ja: 音楽ディレクトリ + ko: 음악 디렉터리 + ru: Каталог музыки + ms: Direktori muzik + pt-br: Diretorio de musicas + required: true + type: text + - default: ./data/cache + edit: true + envKey: POLARIS_CACHE_DIR + labelEn: Cache Directory + labelZh: 缓存目录 + label: + en: Cache Directory + zh: 缓存目录 + zh-Hant: 快取目錄 + ja: キャッシュディレクトリ + ko: 캐시 디렉터리 + ru: Каталог кеша + ms: Direktori cache + pt-br: Diretorio de cache + required: true + type: text + - default: ./data/data + edit: true + envKey: POLARIS_DATA_DIR + labelEn: Data Directory + labelZh: 数据目录 + label: + en: Data Directory + zh: 数据目录 + zh-Hant: 資料目錄 + ja: データディレクトリ + ko: 데이터 디렉터리 + ru: Каталог данных + ms: Direktori data + pt-br: Diretorio de dados + required: true + type: text diff --git a/apps/polaris/latest/docker-compose.yml b/apps/polaris/latest/docker-compose.yml new file mode 100644 index 000000000..ca80f998b --- /dev/null +++ b/apps/polaris/latest/docker-compose.yml @@ -0,0 +1,26 @@ +services: + polaris: + image: "quay.io/connectical/polaris:latest" + container_name: ${CONTAINER_NAME} + restart: unless-stopped + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:5050" + environment: + - POLARIS_PORT=5050 + - POLARIS_CACHE_DIR=/var/cache/polaris + volumes: + - "${POLARIS_MUSIC_DIR}:/music:ro" + - "${POLARIS_CACHE_DIR}:/var/cache/polaris" + - "${POLARIS_DATA_DIR}:/var/lib/polaris" + cap_drop: + - ALL + security_opt: + - no-new-privileges:true + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/polaris/latest/scripts/init.sh b/apps/polaris/latest/scripts/init.sh new file mode 100755 index 000000000..c11b41ae2 --- /dev/null +++ b/apps/polaris/latest/scripts/init.sh @@ -0,0 +1,83 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}" +POLARIS_UID=100 +POLARIS_GID=100 + +fail() { + printf '%s\n' "$1" >&2 + exit 1 +} + +read_env_value() { + local key="$1" + local value + value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)" + value="${value%$'\r'}" + case "$value" in + \"*\") value="${value#\"}"; value="${value%\"}" ;; + \'*\') value="${value#\'}"; value="${value%\'}" ;; + esac + printf '%s\n' "$value" +} + +reject_symlink_components() { + local path="$1" + local current="" + local component + IFS='/' read -r -a components <<< "${path#/}" + for component in "${components[@]}"; do + [[ -n "$component" ]] || continue + current="${current}/${component}" + [[ ! -L "$current" ]] || fail "$path must not contain symbolic-link components" + done +} + +resolve_path() { + local key="$1" + local raw="$2" + local candidate + local resolved + + [[ -n "$raw" ]] || fail "$key must not be empty" + [[ "$raw" =~ ^[A-Za-z0-9._/\ -]+$ ]] || fail "$key contains unsupported characters" + if [[ "$raw" == /* ]]; then + candidate="$raw" + else + candidate="${ROOT_DIR}/${raw#./}" + fi + reject_symlink_components "$candidate" + resolved="$(realpath -m -- "$candidate")" || fail "Unable to resolve $key" + [[ "$resolved" != "/" ]] || fail "$key must not be the filesystem root" + if [[ "$raw" != /* ]]; then + case "$resolved" in + "${ROOT_DIR}"/*) ;; + *) fail "Relative $key must stay inside the application directory" ;; + esac + fi + [[ ! -e "$resolved" || -d "$resolved" ]] || fail "$key must be a directory" + printf '%s\n' "$resolved" +} + +prepare_path() { + local key="$1" + local ownership="$2" + local resolved + resolved="$(resolve_path "$key" "$(read_env_value "$key")")" + install -d -m 0755 -- "$resolved" || fail "Unable to create $key" + resolved="$(realpath -e -- "$resolved")" || fail "Unable to verify $key" + reject_symlink_components "$resolved" + [[ -z "$(find "$resolved" -xdev -type l -print -quit)" ]] || fail "$key must not contain symbolic links" + if [[ "$ownership" == "polaris" ]]; then + chown -R --no-dereference "${POLARIS_UID}:${POLARIS_GID}" "$resolved" || fail "Unable to set $key ownership" + fi +} + +[[ "$(id -u)" -eq 0 ]] || fail "Polaris init must run as root" +[[ -f "$ENV_FILE" && ! -L "$ENV_FILE" ]] || fail "Environment file not found or unsafe: $ENV_FILE" + +prepare_path POLARIS_MUSIC_DIR readonly +prepare_path POLARIS_CACHE_DIR polaris +prepare_path POLARIS_DATA_DIR polaris diff --git a/apps/polaris/latest/scripts/uninstall.sh b/apps/polaris/latest/scripts/uninstall.sh new file mode 100755 index 000000000..1c9e63146 --- /dev/null +++ b/apps/polaris/latest/scripts/uninstall.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Music, cache, accounts, playlists, indexes, and the database are user data. +exit 0 diff --git a/apps/polaris/latest/scripts/upgrade.sh b/apps/polaris/latest/scripts/upgrade.sh new file mode 100755 index 000000000..a0676288e --- /dev/null +++ b/apps/polaris/latest/scripts/upgrade.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail + +exec "$(dirname "${BASH_SOURCE[0]}")/init.sh" diff --git a/apps/polaris/logo-LICENSE.txt b/apps/polaris/logo-LICENSE.txt new file mode 100644 index 000000000..58459191a --- /dev/null +++ b/apps/polaris/logo-LICENSE.txt @@ -0,0 +1,4 @@ +The Polaris logo is copied from the agersant/polaris source repository and is +distributed under that repository's MIT license. + +Source: https://github.com/agersant/polaris/blob/0d75a85724f43b064410c3dff7e1a78fe5aab04f/res/branding/logo/logo.png diff --git a/apps/polaris/logo.png b/apps/polaris/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8d4b467f634863be04944815c43595359244cc43 GIT binary patch literal 1998 zcmah~dpy%^8~=@0(oka#l{e?!)D!h4a?0~CF^A=pQ;Nv>P(s#(99~(%oRZ_jjM9uY zTZXNNC+Fit%;}vLO=eDsglDS%pU>yIulsv_@9TTrhd-_xZHq9MIB?_u000tj3z)rN zChv{?!UBIldR^c_Fk5R!Gj|fJq_Pv%u^iku9MU)}00I+$@Yh43w7oF4e(-5^S6IV4 zi?+p)Br=N1gtadvk_H4mfjsb#G=L%W2r#UD8ATcTDbFGFlvlLBDE;eaX!@gOJb7?0 z?FTM?-kJKU|0foZwb)h+u`jK*@5#&VtePGHpG)Y$RtZieC@YZsQvJ%`tMH2?mbT(? zZ9n-+Tw6K5eGj)Unf{QpW;c)4_B#r!!ELas>c@|kSizH0P)^Sioc1*1R%th63 zPy!=z?-B$%Vn>hN6g+59ggwFmBxX|7DdRx;b0O(k%5!D$MGeP8b0&^4E=YRX4P{Ac zi`n`L#jhfmKd_>%mtNAk;Qf(s{_I8R#jL4_57m8R#dUn{%GT3oJJ%LkCA5+j%2)0Fgd8><>pIig zJbmIgN$7YT{rt-8gJGwt`bb{twN#2Gi^tm8+2wD6R)hjeBQwnV8~Ww?0C-75_}r8j zr1gyWKikCFq(f@^_VFbq{_S&G2byuPjX&LJeBZCkP>Nx!t$$(dYH+as5<)(s{nCsy zgX_fsLC_nYZ1#P2)+$mcLds)R3KSHS%S5Fa9{s9MEDYzJH^cs0vCX9PBee||Nb*i&b?_gwFigwH!9&52>P;{d1)R5`b?kM+} zPv7Jr0R;ZqNC-Nms#eF7CKrT0N27hyref$VzcrI{=q(MN&{Xvf!5zrm$PruMrhy?|$n$ElI!GQtjj;A=G|ZbM1Ht)pvJZecta68H$b~9p*VCRU zdEc0mYv|yeCDol!sffq9DzQh@Y=_Y)ZNL5QyIL^db;&kNIKb|#leWqcD|qRm6(gzV zVpq@&u8GVEF%`CCo{6l1779uloC8Bo7YFmC?1au(!`9>p=8#NpfHGD*dQOSiG!}DKIy+U1dGE>W9=*)wVYP!@^ zq*v5g);;!>o9q5g8<<+jQ52Fd4e@Cf-(S$}(p#;&-%6Bp5a;2n1_b9h#IF}R8w@g| zGvgN>So1lWJs?}3?pH4fwGmmGmf0?FSrCxSkTi&+qZf0IM#Ew%%?b5?H8WKy5_(Pe zfC79j%2HY^DrRI~?cufDZHwpb8SsE79tv)`HE#azliu^RRw=r|9yE?kVwGZmiWFYN zBJNAn^rez-cc<+xbJMe&Ra7j2ah_%A6=3YjO5mH|DqRs~9w&l6*(42ox1eV{UTb++ zd=WR^TcHX1CarFwv@KZbJS6<_!5Q2+6JRmP9=rd(zc*e7o9l|ME#1(M zLB1PYX0jEgZYlKRwzBDeNE*lK=?DDlG=FI_PfJuWQTYFzmFdd_%+6NTV6YBiJz=@g zmlVeNShsP1rD4p_NWaO3shAR?QCv_VkLX|-W+o7yUU?}?y7s87Y5q}(JjM{KFjcs5qu~B+zbJ$ IG4V|J8~M2prvLx| literal 0 HcmV?d00001