From 1cc94f2c9966965b2dce7985c512e363a78fb703 Mon Sep 17 00:00:00 2001 From: Justin Harms Date: Sat, 6 Jun 2026 07:54:44 -0500 Subject: [PATCH] initial commit --- .gitea/workflows/ci.yaml | 69 + .gitea/workflows/fmt.yaml | 31 + .gitea/workflows/release.yaml | 199 +++ .gitignore | 63 + Dockerfile | 41 + Makefile | 59 + README.md | 70 + cmd/helix-proxy/api.go | 1279 ++++++++++++++++++ cmd/helix-proxy/api_branches_test.go | 453 +++++++ cmd/helix-proxy/api_errors_test.go | 345 +++++ cmd/helix-proxy/api_test.go | 467 +++++++ cmd/helix-proxy/https.go | 32 + cmd/helix-proxy/listen_config.go | 45 + cmd/helix-proxy/listen_config_test.go | 105 ++ cmd/helix-proxy/main.go | 134 ++ cmd/helix-proxy/main_test.go | 183 +++ cmd/helix-proxy/router.go | 65 + cmd/helix-proxy/router_test.go | 72 + cmd/helix-proxy/run.go | 132 ++ cmd/helix-proxy/run_test.go | 72 + cmd/helix-proxy/startup_test.go | 146 ++ cmd/helix-proxy/test_server_test.go | 87 ++ docker-compose.yml | 30 + go.mod | 23 + go.sum | 38 + internal/auth/jwt.go | 131 ++ internal/auth/jwt_test.go | 128 ++ internal/certificate/manager.go | 365 +++++ internal/certificate/manager_test.go | 230 ++++ internal/config/paths.go | 110 ++ internal/config/paths_test.go | 158 +++ internal/models/models.go | 155 +++ internal/proxy/engine.go | 1252 +++++++++++++++++ internal/proxy/engine_test.go | 825 ++++++++++++ internal/proxy/integration_test.go | 546 ++++++++ internal/proxy/whoami_test.go | 618 +++++++++ internal/store/bbolt.go | 854 ++++++++++++ internal/store/source_validate.go | 110 ++ internal/store/store.go | 111 ++ internal/store/store_test.go | 513 +++++++ internal/version/version.go | 82 ++ internal/version/version_test.go | 61 + internal/www/404.html | 27 + internal/www/embed.go | 9 + internal/www/index.html | 29 + internal/www/page.go | 34 + internal/www/page_test.go | 39 + proxy-manager | Bin 0 -> 13868622 bytes ui/.gitignore | 23 + ui/.npmrc | 1 + ui/README.md | 42 + ui/embed.go | 15 + ui/package-lock.json | 1766 ++++++++++++++++++++++++ ui/package.json | 26 + ui/src/app.d.ts | 13 + ui/src/app.html | 13 + ui/src/lib/FlashBanner.svelte | 70 + ui/src/lib/Modal.svelte | 53 + ui/src/lib/assets/favicon.svg | 1 + ui/src/lib/index.ts | 1 + ui/src/lib/labels.ts | 130 ++ ui/src/routes/+layout.svelte | 9 + ui/src/routes/+page.svelte | 1776 +++++++++++++++++++++++++ ui/src/routes/layout.css | 1 + ui/static/robots.txt | 3 + ui/svelte.config.js | 20 + ui/tsconfig.json | 20 + ui/vite.config.ts | 5 + 68 files changed, 14615 insertions(+) create mode 100644 .gitea/workflows/ci.yaml create mode 100644 .gitea/workflows/fmt.yaml create mode 100644 .gitea/workflows/release.yaml create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Makefile create mode 100644 README.md create mode 100644 cmd/helix-proxy/api.go create mode 100644 cmd/helix-proxy/api_branches_test.go create mode 100644 cmd/helix-proxy/api_errors_test.go create mode 100644 cmd/helix-proxy/api_test.go create mode 100644 cmd/helix-proxy/https.go create mode 100644 cmd/helix-proxy/listen_config.go create mode 100644 cmd/helix-proxy/listen_config_test.go create mode 100644 cmd/helix-proxy/main.go create mode 100644 cmd/helix-proxy/main_test.go create mode 100644 cmd/helix-proxy/router.go create mode 100644 cmd/helix-proxy/router_test.go create mode 100644 cmd/helix-proxy/run.go create mode 100644 cmd/helix-proxy/run_test.go create mode 100644 cmd/helix-proxy/startup_test.go create mode 100644 cmd/helix-proxy/test_server_test.go create mode 100644 docker-compose.yml create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internal/auth/jwt.go create mode 100644 internal/auth/jwt_test.go create mode 100644 internal/certificate/manager.go create mode 100644 internal/certificate/manager_test.go create mode 100644 internal/config/paths.go create mode 100644 internal/config/paths_test.go create mode 100644 internal/models/models.go create mode 100644 internal/proxy/engine.go create mode 100644 internal/proxy/engine_test.go create mode 100644 internal/proxy/integration_test.go create mode 100644 internal/proxy/whoami_test.go create mode 100644 internal/store/bbolt.go create mode 100644 internal/store/source_validate.go create mode 100644 internal/store/store.go create mode 100644 internal/store/store_test.go create mode 100644 internal/version/version.go create mode 100644 internal/version/version_test.go create mode 100644 internal/www/404.html create mode 100644 internal/www/embed.go create mode 100644 internal/www/index.html create mode 100644 internal/www/page.go create mode 100644 internal/www/page_test.go create mode 100755 proxy-manager create mode 100644 ui/.gitignore create mode 100644 ui/.npmrc create mode 100644 ui/README.md create mode 100644 ui/embed.go create mode 100644 ui/package-lock.json create mode 100644 ui/package.json create mode 100644 ui/src/app.d.ts create mode 100644 ui/src/app.html create mode 100644 ui/src/lib/FlashBanner.svelte create mode 100644 ui/src/lib/Modal.svelte create mode 100644 ui/src/lib/assets/favicon.svg create mode 100644 ui/src/lib/index.ts create mode 100644 ui/src/lib/labels.ts create mode 100644 ui/src/routes/+layout.svelte create mode 100644 ui/src/routes/+page.svelte create mode 100644 ui/src/routes/layout.css create mode 100644 ui/static/robots.txt create mode 100644 ui/svelte.config.js create mode 100644 ui/tsconfig.json create mode 100644 ui/vite.config.ts diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml new file mode 100644 index 0000000..92a7557 --- /dev/null +++ b/.gitea/workflows/ci.yaml @@ -0,0 +1,69 @@ +name: CI + +on: + push: + branches: + - "**" + pull_request: + +jobs: + test: + name: Go Tests + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Verify Go modules + run: go mod verify + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: npm + cache-dependency-path: ui/package-lock.json + + - name: Install UI deps + run: npm --prefix ./ui ci + + - name: Build UI assets + run: npm --prefix ./ui run build + + - name: Run tests + run: make test + + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Verify Go modules + run: go mod verify + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: npm + cache-dependency-path: ui/package-lock.json + + - name: Install UI deps + run: npm --prefix ./ui ci + + - name: Build + run: make build diff --git a/.gitea/workflows/fmt.yaml b/.gitea/workflows/fmt.yaml new file mode 100644 index 0000000..7681f2b --- /dev/null +++ b/.gitea/workflows/fmt.yaml @@ -0,0 +1,31 @@ +name: Format + +on: + push: + branches: + - "**" + pull_request: + +jobs: + gofmt: + name: gofmt + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Verify formatting + shell: bash + run: | + files="$(gofmt -l .)" + if [[ -n "${files}" ]]; then + echo "These files need formatting:" + echo "${files}" + exit 1 + fi diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml new file mode 100644 index 0000000..5fb0d3e --- /dev/null +++ b/.gitea/workflows/release.yaml @@ -0,0 +1,199 @@ +name: Release Artifacts + +on: + push: + tags: + - "*" + workflow_dispatch: + +jobs: + validate-tag: + name: Validate release tag + runs-on: ubuntu-latest + outputs: + tag: ${{ steps.meta.outputs.tag }} + prerelease: ${{ steps.meta.outputs.prerelease }} + steps: + - name: Validate tag and determine prerelease flag + id: meta + shell: bash + run: | + set -eu + tag="${{ gitea.ref_name }}" + echo "tag=${tag}" >> "${GITHUB_OUTPUT}" + + # Allowed tags: + # - Stable: 1.2.3 + # - Prerelease: 1.2.3-alpha1 | 1.2.3-beta1 | 1.2.3-rc1 + if [[ "${tag}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "prerelease=false" >> "${GITHUB_OUTPUT}" + elif [[ "${tag}" =~ ^[0-9]+\.[0-9]+\.[0-9]+-(alpha|beta|rc)[0-9]+$ ]]; then + echo "prerelease=true" >> "${GITHUB_OUTPUT}" + else + echo "Invalid tag format: ${tag}" + echo "Expected one of:" + echo " - 1.2.3" + echo " - 1.2.3-alpha1" + echo " - 1.2.3-beta1" + echo " - 1.2.3-rc1" + exit 1 + fi + + build-and-release-executables: + name: Build and release executables + needs: validate-tag + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Verify Go modules + run: go mod verify + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: npm + cache-dependency-path: ui/package-lock.json + + - name: Install UI deps + run: npm --prefix ./ui ci + + - name: Build UI assets + run: npm --prefix ./ui run build + + - name: Run tests + run: make test + + - name: Build release binaries + shell: bash + run: | + set -eu + tag="${{ needs.validate-tag.outputs.tag }}" + commit="$(git rev-parse --short HEAD)" + mkdir -p dist + + for arch in amd64 arm64; do + out="dist/helix-proxy-linux-${arch}" + + CGO_ENABLED=0 GOOS=linux GOARCH="${arch}" \ + go build -trimpath \ + -ldflags "-s -w -X helix-proxy/internal/version.Version=${tag} -X helix-proxy/internal/version.Commit=${commit}" \ + -o "${out}" ./cmd/helix-proxy + + file "${out}" | grep -q "statically linked" + done + + - name: Package release archives + shell: bash + run: | + set -eu + rm -rf release-packages + mkdir -p release-packages + + for bin in dist/helix-proxy-linux-*; do + name="$(basename "${bin}")" + archive="helix-proxy-${{ needs.validate-tag.outputs.tag }}-${name#helix-proxy-}.tar.gz" + stage="release-packages/${name}" + + rm -rf "${stage}" + mkdir -p "${stage}" + cp README.md "${stage}/" + cp "${bin}" "${stage}/helix-proxy" + tar -C "${stage}" -czf "${archive}" . + done + + - name: Generate release notes + shell: bash + run: | + set -eu + current_tag="${{ needs.validate-tag.outputs.tag }}" + prev_tag="$(git tag --sort=-creatordate | awk -v cur="${current_tag}" '$0 != cur { print; exit }')" + + { + echo "## Release ${current_tag}" + echo + if [ -n "${prev_tag}" ]; then + echo "Changes since \`${prev_tag}\`:" + echo + git log --pretty='- %h %s' "${prev_tag}..${current_tag}" + else + echo "Changes in this release:" + echo + git log --pretty='- %h %s' "${current_tag}" + fi + } > RELEASE_NOTES.md + + - name: Create release and upload archives + uses: https://gitea.com/actions/gitea-release-action@v1 + with: + tag_name: ${{ needs.validate-tag.outputs.tag }} + name: ${{ needs.validate-tag.outputs.tag }} + prerelease: ${{ needs.validate-tag.outputs.prerelease }} + body_path: RELEASE_NOTES.md + files: |- + helix-proxy-${{ needs.validate-tag.outputs.tag }}-linux-*.tar.gz + + build-and-release-docker-image: + name: Build and release Docker image + needs: [validate-tag, build-and-release-executables] + runs-on: ubuntu-latest + permissions: + code: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Resolve registry and image names + id: image + shell: bash + run: | + set -eu + host="${{ gitea.server_url }}" + host="${host#http://}" + host="${host#https://}" + host="${host%%/*}" + repo="$(printf '%s' "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')" + image="${host}/${repo}" + echo "registry_host=${host}" >> "${GITHUB_OUTPUT}" + echo "repository_lower=${repo}" >> "${GITHUB_OUTPUT}" + echo "image=${image}" >> "${GITHUB_OUTPUT}" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to registry + uses: docker/login-action@v3 + with: + registry: ${{ secrets.GIT_REGISTRY || steps.image.outputs.registry_host }} + username: ${{ secrets.GIT_USER || gitea.actor }} + password: ${{ secrets.GIT_PACKAGES_TOKEN || secrets.GITEA_TOKEN }} + + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ secrets.GIT_REGISTRY || steps.image.outputs.registry_host }}/${{ steps.image.outputs.repository_lower }} + tags: | + type=raw,value=${{ needs.validate-tag.outputs.tag }} + type=raw,value=latest,enable=${{ needs.validate-tag.outputs.prerelease == 'false' }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03b43da --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +# Binaries +helix-proxy +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Explicitly include the cmd/helix-proxy folder +!cmd/helix-proxy + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool +*.out + +# Dependency directories +vendor/ + +# Go workspace file +go.work +go.work.sum + +# Env files +.env +.env.* + +# Build / dist +dist/ +ui/dist/ +ui/node_modules/ +node_modules/ + +# Data (user runtime, volumes) +data/ +logs/ +*.sqlite +*.sqlite-shm +*.sqlite-wal + +# Keys / secrets +keys.json +*.pem +*.key + +# IDE / editor +.idea/ +.vscode/ +.playwright-mcp/ +*.swp +*~ + +# Screenshots +*.png + +# OS +.DS_Store +Thumbs.db + +# Misc +tmp/ +*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..30b4119 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,41 @@ +# Multi-stage for true single binary with embedded Svelte UI +# 1. Build Svelte UI (if ui/ present) +FROM node:20-alpine AS ui-builder +WORKDIR /src +# Copy the entire context (cheap for this project size at this stage) +COPY . . +# Always ensure a dist exists +RUN mkdir -p ui/dist && printf 'Helix Proxy

UI placeholder (run make ui-build for the real Svelte SPA)

' > ui/dist/index.html +# If a real ui/ with package.json was copied, build it (overwrites the placeholder) +RUN if [ -f ui/package.json ]; then \ + cd ui && npm ci && npm run build; \ + fi +# Put the final dist where the Go embed step (ui/dist from module root) will find it +RUN mkdir -p /out-ui/dist && cp -r ui/dist/* /out-ui/dist/ 2>/dev/null || cp -r ui/dist /out-ui/ 2>/dev/null || true + +# 2. Build Go binary (embeds the dist produced above or the placeholder) +FROM golang:1.25-alpine AS go-builder +WORKDIR /src +RUN apk add --no-cache git ca-certificates +COPY go.mod go.sum ./ +RUN go mod download +COPY . . +# Copy the UI dist produced by previous stage into the location the embed expects +COPY --from=ui-builder /out-ui/dist ./ui/dist +RUN TAG="$$(git describe --tags --exact-match HEAD 2>/dev/null || true)" && \ + COMMIT="$$(git rev-parse --short HEAD 2>/dev/null || true)" && \ + CGO_ENABLED=0 go build -ldflags="-s -w -X helix-proxy/internal/version.Version=$$TAG -X helix-proxy/internal/version.Commit=$$COMMIT" -o /out/helix-proxy ./cmd/helix-proxy + +# Final: minimal image, single binary +FROM alpine:3.20 +RUN apk add --no-cache ca-certificates tzdata wget && \ + adduser -D -u 1000 -g 1000 appuser +WORKDIR /app +COPY --from=go-builder /out/helix-proxy /app/helix-proxy +# The binary contains the UI via embed. It will create ./data (and data/www) relative to CWD on first run. +USER appuser +EXPOSE 80 81 443 +ENTRYPOINT ["/app/helix-proxy"] +# In practice run with: +# docker run -p 80:80 -p 81:81 -p 443:443 -v $PWD/data:/app/data --workdir /app helix-proxy:dev +# (or set DATA_DIR etc. to move things) diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..32d96dc --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +.PHONY: build ui ui-build run docker docker-build test clean help + +APP_NAME := helix-proxy +GO := go +UI_DIR := ui +DIST_DIR := $(UI_DIR)/dist +DATA_DIR := data + +# Inject git tag and commit separately; version package picks tag → commit → dev. +GIT_TAG := $(shell git describe --tags --exact-match HEAD 2>/dev/null) +GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null) +LDFLAGS := -X helix-proxy/internal/version.Version=$(GIT_TAG) -X helix-proxy/internal/version.Commit=$(GIT_COMMIT) + +# Default target +help: + @echo "Helix Proxy Makefile" + @echo "" + @echo " build Build the Go binary (embeds UI if dist/ present)" + @echo " ui Install UI deps (npm ci in ui/)" + @echo " ui-build Build Svelte SPA to $(DIST_DIR)" + @echo " run Build + run (uses current dir as cwd)" + @echo " docker Build docker image (helix-proxy:dev)" + @echo " docker-build Build docker image" + @echo " test Run go tests" + @echo " clean Remove build artifacts and ui/dist" + @echo "" + +build: ui-build + @echo "Building $(APP_NAME) (tag=$(if $(GIT_TAG),$(GIT_TAG),none), commit=$(if $(GIT_COMMIT),$(GIT_COMMIT),none))..." + $(GO) build -ldflags "$(LDFLAGS)" -o $(APP_NAME) ./cmd/helix-proxy + +ui: + @echo "Installing UI dependencies..." + cd $(UI_DIR) && npm ci + +ui-build: clean + @if [ -d "$(UI_DIR)" ]; then \ + echo "Building Svelte UI..."; \ + cd $(UI_DIR) && npm run build; \ + else \ + echo "No $(UI_DIR)/ dir, skipping UI build (will use empty embed or stub)"; \ + fi + +run: build + @echo "Running $(APP_NAME) from cwd (data/ will be created relative)..." + PROXY_MODE=development ./$(APP_NAME) + +docker docker-build: + @echo "Building docker image helix-proxy:dev..." + docker build -t helix-proxy:dev . + +test: + $(GO) test ./... -count=1 -race -coverprofile=coverage.out + +clean: + rm -f $(APP_NAME) + rm -rf $(DIST_DIR) + rm -rf $(DATA_DIR) + @echo "Cleaned binaries and UI dist." diff --git a/README.md b/README.md new file mode 100644 index 0000000..770d1d3 --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# Helix Proxy + +A pure-Go reverse proxy with embedded web UI. Supports proxy hosts, TCP/UDP streams, redirections, dead hosts, certificates (Let's Encrypt + custom), access lists, audit, and more. Single static binary. Single built-in admin (no multi-user registration; defaults to "password", first login forces a change which is then bcrypt-hashed and stored in the DB). + +**Key features / differences from traditional setups**: +- **Entirely replaces nginx**: pure Go reverse proxy (http) + TCP/UDP stream proxy engine. No nginx binary, no config files on disk for routing, live updates. +- **Single binary**: the modern Svelte SPA UI is built and **embedded** (`//go:embed`) into the Go executable. +- **Storage**: default is a single `data/db.bolt` (cwd-relative, bbolt embedded). +- **No magic paths**: everything defaults to paths relative to the process CWD (`data/db.bolt`, `data/www/`, `data/certs/`, ...). All overridable with env vars (`DATA_DIR`, `WWW_DIR`, etc.). +- **www/html lives in data/** by default (single volume tree). + +## Quick start (binary) +```bash +make # builds UI (placeholder) + Go binary with embed +./helix-proxy +# Admin UI + API on :81 +# Proxy on :8080 (or 80/443 when you have perms / run in docker) +``` + +Visit http://localhost:81 + +Data (db, certs, logs, www html) lives in `./data` relative to where you ran the binary. + +## Docker (recommended) +```bash +docker compose up -d +# or +docker build -t helix-proxy:dev . +docker run -p 81:81 -v $PWD/data:/app/data --workdir /app helix-proxy:dev +``` + +PUID/PGID + DISABLE_IPV6 example (see docker-compose.yml for full): +```yaml +# user: "0:0" # root to allow chown+drop inside +environment: + - PUID=1000 + - PGID=1000 + - DISABLE_IPV6=1 + # PUID_NO_DROP=1 # for low ports (80/443) + PUID: do chown as root but do not drop (stay root to bind low ports; default with PUID drops to non-root after chown, so use high ports or NET_BIND_SERVICE cap or run without PUID for low ports) +``` +Binary auto-chowns data tree (if started root) then drops privs (unless PUID_NO_DROP); umask support via UMASK env. Files 0600, dirs 0755. +Note: privilege drop happens early (before listeners); low-port binds require either root (with PUID_NO_DROP), capabilities, high ports in config, or external setuid wrapper. + +See docker-compose.yml for full example (exposes 80/81/443, volume for data/). + +## Paths (all overridable) +- `data/db.bolt` (or `DATA_DIR`) +- `data/certs/`, `data/logs/`, `data/letsencrypt-acme-challenge/` +- `data/www/` (default site / custom html; `WWW_DIR` or `HTML_DIR`) +- etc. + +## Status +Core features implemented and verified: +- cwd-relative + env-overridable paths/storage (single `data/db.bolt` primary via bbolt) +- pure-Go engine: proxy hosts (full: locations, advanced_config parser, ssl_forced, block_exploits, websocket, hsts, caching w/ HIT/MISS, access lists, custom certs, LE), streams (tcp/udp +ssl term), redirection hosts (full forward_http_code/preservePath/scheme + CRUD), dead hosts (per-dead custom content + CRUD) +- certificates: custom PEM (meta keys compat) + full Let's Encrypt issuance/renewal via lego (http-01). In PROXY_MODE=development *all* LE certs are self-signed test certs (domain-based sim tricks removed). +- single admin (defaults to "password"; first login forces change; hashed + stored in DB; no registration or multi-user) +- audit (userId=1), settings (default_site + letsencrypt_email etc) +- live reload on all CRUD, dual https/http + SNI, embedded Svelte SPA (full tabs, pickers, edits) +- single binary (go build embeds UI after make ui-build), docker multi-stage + full PUID/PGID/umask +- no nginx, no .conf files, no external processes for proxying + +LE note: for real certs use a public DNS domain pointing at your server (port 80/http reachable). By default (production), real LE http-01 is used. Set PROXY_MODE=development and *all* letsencrypt cert requests will produce self-signed test certs instead (for dev/testing; see TESTING.md). Real LE will be used otherwise (requires valid email, port 80 reachable etc). + +## Development +- `make ui-build` (once real Svelte UI added to ui/) +- `make` +- `make docker` + +Contributions / v2 features: open an issue or just ask to implement the next piece (advanced config, full certs with lego, streams, full Svelte UI, SQL backend, etc.). diff --git a/cmd/helix-proxy/api.go b/cmd/helix-proxy/api.go new file mode 100644 index 0000000..781856b --- /dev/null +++ b/cmd/helix-proxy/api.go @@ -0,0 +1,1279 @@ +package main + +import ( + "encoding/json" + "log/slog" + "net/http" + "strconv" + + "helix-proxy/internal/auth" + "helix-proxy/internal/certificate" + "helix-proxy/internal/config" + "helix-proxy/internal/proxy" + "helix-proxy/internal/store" + "helix-proxy/internal/version" + + "github.com/go-chi/chi/v5" + "golang.org/x/crypto/bcrypt" +) + +type streamAPIResponse struct { + store.Stream + Listening bool `json:"listening"` + ListenError string `json:"listenError,omitempty"` +} + +func streamAPIResponseFrom(st store.Store, eng *proxy.Engine, s store.Stream) streamAPIResponse { + out := streamAPIResponse{Stream: s} + if s.Enabled { + st := eng.StreamStatus(s.IncomingPort) + out.Listening = st.Listening + out.ListenError = st.ListenError + } + return out +} + +func streamsAPIResponseFrom(st store.Store, eng *proxy.Engine) []streamAPIResponse { + streams := st.GetStreams() + out := make([]streamAPIResponse, len(streams)) + for i, s := range streams { + out[i] = streamAPIResponseFrom(st, eng, s) + } + return out +} + +// mountAPI registers all /api routes on r. +func mountAPI(r chi.Router, st store.Store, eng *proxy.Engine, cm *certificate.Manager, jwtMgr *auth.JWTManager) { + r.Route("/api", func(r chi.Router) { + r.Use(jwtMgr.Middleware) + + // Health (mirrors original /api style) + r.Get("/", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + major, minor, revision := version.Parts() + _ = json.NewEncoder(w).Encode(map[string]any{ + "status": "OK", + "setup": st.IsSetup(), + "version": map[string]int{"major": major, "minor": minor, "revision": revision}, + }) + }) + r.Get("/proxy-hosts", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + w.Header().Set("Content-Type", "application/json") + hosts := st.GetProxyHosts() + _ = json.NewEncoder(w).Encode(hosts) + }) + + r.Post("/proxy-hosts", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + var payload store.ProxyHost + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + if payload.OwnerUserID == 0 { + payload.OwnerUserID = claims.UserID + } + created, err := st.CreateProxyHost(payload) + if err != nil { + writeStoreError(w, err) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(created) + // audit + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "proxy-host", + ObjectID: created.ID, + Action: "created", + Meta: map[string]any{"domain_names": created.DomainNames}, + }) + }) + + r.Get("/access-lists", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(st.GetAccessLists()) + }) + r.Post("/access-lists", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + var payload store.AccessList + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + if payload.OwnerUserID == 0 { + payload.OwnerUserID = claims.UserID + } + created, err := st.CreateAccessList(payload) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(created) + eng.ReloadFromStore() + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "access-list", + ObjectID: created.ID, + Action: "created", + Meta: map[string]any{"name": created.Name}, + }) + }) + + // full access list lifecycle (update/delete for complete parity) + r.Get("/access-lists/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims // read is authed; no owner gate for GET (consistent with list GETs) + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + if al, ok := st.GetAccessList(id); ok { + _ = json.NewEncoder(w).Encode(al) + return + } + http.Error(w, "not found", 404) + }) + r.Put("/access-lists/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetAccessList(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + var payload store.AccessList + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + payload.ID = id + payload.OwnerUserID = existing.OwnerUserID + // preserve CreatedOn on update (server-set on create; do not lose on edit) + payload.CreatedOn = existing.CreatedOn + updated, err := st.UpdateAccessList(payload) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + eng.ReloadFromStore() + _ = json.NewEncoder(w).Encode(updated) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "access-list", + ObjectID: updated.ID, + Action: "updated", + Meta: map[string]any{"name": updated.Name}, + }) + }) + r.Delete("/access-lists/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetAccessList(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.DeleteAccessList(id); err != nil { + http.Error(w, err.Error(), 500) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusNoContent) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "access-list", + ObjectID: id, + Action: "deleted", + Meta: map[string]any{}, + }) + }) + + r.Get("/streams", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(streamsAPIResponseFrom(st, eng)) + }) + r.Post("/streams", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + var payload store.Stream + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + if payload.OwnerUserID == 0 { + payload.OwnerUserID = claims.UserID + } + created, err := st.CreateStream(payload) + if err != nil { + writeStoreError(w, err) + return + } + eng.ReloadFromStore() // will handle streams too + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(streamAPIResponseFrom(st, eng, created)) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "stream", + ObjectID: created.ID, + Action: "created", + Meta: map[string]any{"incoming_port": created.IncomingPort}, + }) + }) + + // full stream lifecycle + r.Put("/streams/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetStream(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + var payload store.Stream + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + payload.ID = id + payload.OwnerUserID = existing.OwnerUserID + // preserve CreatedOn on update (server-set on create; do not lose on edit) + payload.CreatedOn = existing.CreatedOn + updated, err := st.UpdateStream(payload) + if err != nil { + writeStoreError(w, err) + return + } + eng.ReloadFromStore() + _ = json.NewEncoder(w).Encode(streamAPIResponseFrom(st, eng, updated)) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "stream", + ObjectID: updated.ID, + Action: "updated", + Meta: map[string]any{"incoming_port": updated.IncomingPort}, + }) + }) + r.Delete("/streams/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetStream(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.DeleteStream(id); err != nil { + http.Error(w, err.Error(), 500) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusNoContent) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "stream", + ObjectID: id, + Action: "deleted", + Meta: map[string]any{}, + }) + }) + + r.Get("/certificates", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(st.GetCertificates()) + }) + r.Post("/certificates", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + var payload store.Certificate + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + if payload.OwnerUserID == 0 { + payload.OwnerUserID = claims.UserID + } + created, err := st.CreateCertificate(payload) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + // If LE, perform issuance now. + // This will populate meta["cert"]/meta["key"] + expires_on and write files. + // Challenge tokens will be served automatically by the proxy Handler. + if created.Provider == "letsencrypt" { + email := cm.GetEmailForCert(created) + if ierr := cm.Issue(created, email); ierr != nil { + // mimic original: on failure remove the partial cert record + _ = st.DeleteCertificate(created.ID) + http.Error(w, "letsencrypt issuance failed: "+ierr.Error(), 500) + return + } + if c2, ok := st.GetCertificate(created.ID); ok { + created = c2 + } + eng.ReloadFromStore() + } else { + // custom/other cert: load PEMs into engine for immediate SNI/https use + eng.ReloadFromStore() + } + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(created) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "certificate", + ObjectID: created.ID, + Action: "created", + Meta: map[string]any{"provider": created.Provider, "domain_names": created.DomainNames}, + }) + }) + + // Delete a certificate (removes from store; attached hosts will fall back) + r.Delete("/certificates/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetCertificate(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.DeleteCertificate(id); err != nil { + http.Error(w, err.Error(), 500) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusNoContent) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "certificate", + ObjectID: id, + Action: "deleted", + Meta: map[string]any{}, + }) + }) + + // Renew (re-obtain) a certificate. Useful for manual trigger or after domain change. + r.Post("/certificates/{id}/renew", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + c, ok := st.GetCertificate(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, c.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + email := cm.GetEmailForCert(c) + if err := cm.Issue(c, email); err != nil { + http.Error(w, "renewal failed: "+err.Error(), 500) + return + } + if c2, ok := st.GetCertificate(id); ok { + c = c2 + } + eng.ReloadFromStore() + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(c) + }) + + r.Get("/redirection-hosts", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(st.GetRedirectionHosts()) + }) + r.Post("/redirection-hosts", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + var payload store.RedirectionHost + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + if payload.OwnerUserID == 0 { + payload.OwnerUserID = claims.UserID + } + created, err := st.CreateRedirectionHost(payload) + if err != nil { + writeStoreError(w, err) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(created) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "redirection-host", + ObjectID: created.ID, + Action: "created", + Meta: map[string]any{"domain_names": created.DomainNames}, + }) + }) + + // full redir lifecycle + r.Put("/redirection-hosts/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetRedirectionHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + var payload store.RedirectionHost + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + payload.ID = id + payload.OwnerUserID = existing.OwnerUserID + // preserve CreatedOn on update (server-set on create; do not lose on edit) + payload.CreatedOn = existing.CreatedOn + updated, err := st.UpdateRedirectionHost(payload) + if err != nil { + writeStoreError(w, err) + return + } + eng.ReloadFromStore() + _ = json.NewEncoder(w).Encode(updated) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "redirection-host", + ObjectID: updated.ID, + Action: "updated", + Meta: map[string]any{"domain_names": updated.DomainNames}, + }) + }) + r.Delete("/redirection-hosts/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetRedirectionHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.DeleteRedirectionHost(id); err != nil { + http.Error(w, err.Error(), 500) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusNoContent) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "redirection-host", + ObjectID: id, + Action: "deleted", + Meta: map[string]any{}, + }) + }) + + r.Get("/dead-hosts", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(st.GetDeadHosts()) + }) + r.Post("/dead-hosts", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + var payload store.DeadHost + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + if payload.OwnerUserID == 0 { + payload.OwnerUserID = claims.UserID + } + created, err := st.CreateDeadHost(payload) + if err != nil { + writeStoreError(w, err) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusCreated) + _ = json.NewEncoder(w).Encode(created) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "dead-host", + ObjectID: created.ID, + Action: "created", + Meta: map[string]any{"domain_names": created.DomainNames}, + }) + }) + + // full dead lifecycle + r.Put("/dead-hosts/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetDeadHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + var payload store.DeadHost + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + payload.ID = id + payload.OwnerUserID = existing.OwnerUserID + // preserve CreatedOn on update (server-set on create; do not lose on edit) + payload.CreatedOn = existing.CreatedOn + updated, err := st.UpdateDeadHost(payload) + if err != nil { + writeStoreError(w, err) + return + } + eng.ReloadFromStore() + _ = json.NewEncoder(w).Encode(updated) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "dead-host", + ObjectID: updated.ID, + Action: "updated", + Meta: map[string]any{"domain_names": updated.DomainNames}, + }) + }) + r.Delete("/dead-hosts/{id}", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetDeadHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.DeleteDeadHost(id); err != nil { + http.Error(w, err.Error(), 500) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusNoContent) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "dead-host", + ObjectID: id, + Action: "deleted", + Meta: map[string]any{}, + }) + }) + + // enable/disable for redirection and dead hosts (engine only loads enabled) + r.Post("/redirection-hosts/{id}/enable", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetRedirectionHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.SetRedirectionHostEnabled(id, true); err != nil { + http.Error(w, err.Error(), 404) + return + } + eng.ReloadFromStore() + w.WriteHeader(200) + }) + r.Post("/redirection-hosts/{id}/disable", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetRedirectionHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.SetRedirectionHostEnabled(id, false); err != nil { + http.Error(w, err.Error(), 404) + return + } + eng.ReloadFromStore() + w.WriteHeader(200) + }) + + r.Post("/dead-hosts/{id}/enable", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetDeadHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.SetDeadHostEnabled(id, true); err != nil { + http.Error(w, err.Error(), 404) + return + } + eng.ReloadFromStore() + w.WriteHeader(200) + }) + r.Post("/dead-hosts/{id}/disable", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetDeadHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.SetDeadHostEnabled(id, false); err != nil { + http.Error(w, err.Error(), 404) + return + } + eng.ReloadFromStore() + w.WriteHeader(200) + }) + + // streams enable/disable + r.Post("/streams/{id}/enable", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetStream(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.SetStreamEnabled(id, true); err != nil { + if err.Error() == "not found" { + http.Error(w, err.Error(), 404) + return + } + writeStoreError(w, err) + return + } + eng.ReloadFromStore() + w.WriteHeader(200) + }) + r.Post("/streams/{id}/disable", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetStream(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.SetStreamEnabled(id, false); err != nil { + http.Error(w, err.Error(), 404) + return + } + eng.ReloadFromStore() + w.WriteHeader(200) + }) + + // Full proxy-host lifecycle (list/create above; get/put/delete + enable/disable here) + r.Route("/proxy-hosts/{id}", func(r chi.Router) { + r.Get("/", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims // read authed (consistent); no owner gate for GET + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + if h, ok := st.GetProxyHost(id); ok { + _ = json.NewEncoder(w).Encode(h) + return + } + http.Error(w, "not found", 404) + }) + r.Put("/", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetProxyHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + var payload store.ProxyHost + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + payload.ID = id + // preserve owner on update + payload.OwnerUserID = existing.OwnerUserID + // preserve CreatedOn on update (server-set on create; do not lose on edit) + payload.CreatedOn = existing.CreatedOn + updated, err := st.UpdateProxyHost(payload) + if err != nil { + writeStoreError(w, err) + return + } + eng.ReloadFromStore() + _ = json.NewEncoder(w).Encode(updated) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "proxy-host", + ObjectID: updated.ID, + Action: "updated", + Meta: map[string]any{"domain_names": updated.DomainNames}, + }) + }) + r.Delete("/", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetProxyHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.DeleteProxyHost(id); err != nil { + http.Error(w, err.Error(), 500) + return + } + eng.ReloadFromStore() + w.WriteHeader(http.StatusNoContent) + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "proxy-host", + ObjectID: id, + Action: "deleted", + Meta: map[string]any{}, + }) + }) + }) + + // enable / disable actions + r.Post("/proxy-hosts/{id}/enable", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetProxyHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.SetProxyHostEnabled(id, true); err != nil { + http.Error(w, err.Error(), 404) + return + } + eng.ReloadFromStore() + w.WriteHeader(200) + }) + r.Post("/proxy-hosts/{id}/disable", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + idStr := chi.URLParam(r, "id") + id, err := strconv.Atoi(idStr) + if err != nil { + http.Error(w, "bad id", 400) + return + } + existing, ok := st.GetProxyHost(id) + if !ok { + http.Error(w, "not found", 404) + return + } + if !canManage(claims, existing.OwnerUserID) { + http.Error(w, "forbidden: not owner or admin", 403) + return + } + if err := st.SetProxyHostEnabled(id, false); err != nil { + http.Error(w, err.Error(), 404) + return + } + eng.ReloadFromStore() + w.WriteHeader(200) + }) + + // Settings (global for now; default_site drives unmatched host behavior in engine) + r.Get("/settings", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(st.GetSettings()) + }) + r.Post("/settings", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + var payload map[string]any + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + for k, v := range payload { + if err := st.SetSetting(k, v); err != nil { + http.Error(w, err.Error(), 500) + return + } + } + w.WriteHeader(200) + _ = json.NewEncoder(w).Encode(st.GetSettings()) + }) + + // Audit logs (basic) + r.Get("/audit-logs", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(st.GetAuditLogs()) + }) + + // Login for the single admin account (no registration, no multi-user). + // Default password is "password". On first use (when no password has been set in DB yet), + // login with "password" succeeds but the response includes mustChangePassword:true + // (skipped in PROXY_MODE=development for local dev convenience). + // After the admin sets a new password (via /users/me/password), it is bcrypt-hashed and stored in DB. + // Subsequent logins use the stored hash. Email is ignored (always the built-in admin). + // No 2FA/TOTP. + r.Post("/login", func(w http.ResponseWriter, r *http.Request) { + var payload struct { + Password string `json:"password"` + } + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + u, ok := st.GetUserByEmail("admin@example.com") + if !ok { + // fallback to seeded values if lookup fails + u = store.User{ID: 1, Email: "admin@example.com", Name: "Admin", Roles: []string{"admin"}} + } + mustChange := false + authed := false + if u.Password == "" { + // initial / not yet set: default "password" is accepted + if payload.Password == "password" { + authed = true + mustChange = !config.IsDevelopment() + } + } else if isBcryptPrefix(u.Password) { + if err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(payload.Password)); err == nil { + authed = true + } + } else if u.Password == payload.Password { + // legacy plain (should not happen after first change) + authed = true + } + if !authed { + http.Error(w, "invalid credentials", 401) + return + } + token, err := jwtMgr.GenerateToken(u.ID, u.Email, u.Name, u.Roles) + if err != nil { + http.Error(w, "token error", 500) + return + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(map[string]any{ + "token": token, + "user": map[string]any{ + "id": u.ID, + "email": u.Email, + "name": u.Name, + "roles": u.Roles, + "totpEnabled": false, + }, + "mustChangePassword": mustChange, + }) + }) + + // Users: single admin only (no registration, no CRUD, no 2FA). List and /me kept for UI compatibility. + r.Get("/users", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + // Return the single admin (store may have legacy, but we present the fixed one) + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode([]map[string]any{{ + "id": 1, "email": "admin@example.com", "name": "Admin", "roles": []string{"admin"}, "totpEnabled": false, + }}) + }) + r.Get("/users/me", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(map[string]any{ + "id": claims.UserID, + "email": claims.Email, + "name": claims.Name, + "roles": claims.Roles, + "totpEnabled": false, + }) + }) + + // Change the single admin's password. Works for the initial "password" (when DB has empty pw) + // as well as normal changes (requires current password to match stored hash). + // New password is bcrypt-hashed and persisted. "password" is not allowed as the new value. + r.Post("/users/me/password", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + var payload struct { + CurrentPassword string `json:"currentPassword"` + NewPassword string `json:"newPassword"` + } + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + http.Error(w, err.Error(), 400) + return + } + if payload.NewPassword == "" || payload.NewPassword == "password" { + http.Error(w, "new password required and cannot be the default", 400) + return + } + u, ok := st.GetUserByEmail(claims.Email) + if !ok { + http.Error(w, "not found", 404) + return + } + // verify current + if u.Password == "" { + // initial state: current must be the default (or empty to be lenient for first-login flow) + if payload.CurrentPassword != "" && payload.CurrentPassword != "password" { + http.Error(w, "invalid current password", 401) + return + } + } else if isBcryptPrefix(u.Password) { + if err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(payload.CurrentPassword)); err != nil { + http.Error(w, "invalid current password", 401) + return + } + } else if u.Password != payload.CurrentPassword { + http.Error(w, "invalid current password", 401) + return + } + h, err := bcrypt.GenerateFromPassword([]byte(payload.NewPassword), bcrypt.DefaultCost) + if err != nil { + slog.Error("password hash failed", "err", err) + http.Error(w, "password hash failed", 500) + return + } + u.Password = string(h) + if err := st.UpdateUser(u); err != nil { + http.Error(w, err.Error(), 500) + return + } + _, _ = st.AddAuditLog(store.AuditLog{ + UserID: claims.UserID, + ObjectType: "user", + ObjectID: u.ID, + Action: "password-changed", + Meta: map[string]any{}, + }) + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(map[string]any{"ok": true}) + }) + + // Dashboard (counts, like original) + r.Get("/dashboard", func(w http.ResponseWriter, r *http.Request) { + claims, ok := auth.RequireAuth(w, r) + if !ok { + return + } + _ = claims + data := map[string]any{ + "proxy_hosts": len(st.GetProxyHosts()), + "redirection_hosts": len(st.GetRedirectionHosts()), + "dead_hosts": len(st.GetDeadHosts()), + "streams": len(st.GetStreams()), + "certificates": len(st.GetCertificates()), + "access_lists": len(st.GetAccessLists()), + "audit_logs": len(st.GetAuditLogs()), + "users": len(st.GetUsers()), + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(data) + }) + + // Version (like original) + r.Get("/version", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + major, minor, revision := version.Parts() + _ = json.NewEncoder(w).Encode(map[string]any{ + "version": version.String(), + "tag": version.Version, + "commit": version.Commit, + "major": major, + "minor": minor, + "revision": revision, + "api": "v1", + }) + }) + }) +} diff --git a/cmd/helix-proxy/api_branches_test.go b/cmd/helix-proxy/api_branches_test.go new file mode 100644 index 0000000..1cbd1f5 --- /dev/null +++ b/cmd/helix-proxy/api_branches_test.go @@ -0,0 +1,453 @@ +package main + +import ( + "bytes" + "net/http" + "testing" + + "helix-proxy/internal/store" +) + +func apiPutRaw(t *testing.T, url, rawBody, token string) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodPut, url, bytes.NewReader([]byte(rawBody))) + if err != nil { + t.Fatalf("request: %v", err) + } + req.Header.Set("Content-Type", "application/json") + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("do: %v", err) + } + return resp +} + +func TestAPI_UnauthorizedEndpoints(t *testing.T) { + env := newAPITestServer(t) + paths := []string{ + "/api/proxy-hosts", + "/api/access-lists", + "/api/streams", + "/api/certificates", + "/api/redirection-hosts", + "/api/dead-hosts", + "/api/settings", + "/api/audit-logs", + "/api/dashboard", + "/api/users", + "/api/users/me", + } + for _, path := range paths { + t.Run(path, func(t *testing.T) { + assertStatus(t, apiGet(t, env.BaseURL+path, ""), http.StatusUnauthorized) + }) + } +} + +func TestAPI_BadIDBranches(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + cases := []struct { + name string + method string + path string + want int + }{ + {"proxy-host get", http.MethodGet, "/api/proxy-hosts/nope", http.StatusBadRequest}, + {"proxy-host put", http.MethodPut, "/api/proxy-hosts/nope", http.StatusBadRequest}, + {"proxy-host delete", http.MethodDelete, "/api/proxy-hosts/bad", http.StatusBadRequest}, + {"proxy-host enable", http.MethodPost, "/api/proxy-hosts/x/enable", http.StatusBadRequest}, + {"proxy-host disable", http.MethodPost, "/api/proxy-hosts/x/disable", http.StatusBadRequest}, + + {"access-list put", http.MethodPut, "/api/access-lists/abc", http.StatusBadRequest}, + {"access-list delete", http.MethodDelete, "/api/access-lists/abc", http.StatusBadRequest}, + + {"stream put", http.MethodPut, "/api/streams/nope", http.StatusBadRequest}, + {"stream delete", http.MethodDelete, "/api/streams/bad", http.StatusBadRequest}, + {"stream enable", http.MethodPost, "/api/streams/x/enable", http.StatusBadRequest}, + {"stream disable", http.MethodPost, "/api/streams/x/disable", http.StatusBadRequest}, + + {"cert delete", http.MethodDelete, "/api/certificates/bad", http.StatusBadRequest}, + + {"redir put", http.MethodPut, "/api/redirection-hosts/nope", http.StatusBadRequest}, + {"redir delete", http.MethodDelete, "/api/redirection-hosts/bad", http.StatusBadRequest}, + {"redir disable", http.MethodPost, "/api/redirection-hosts/x/disable", http.StatusBadRequest}, + + {"dead put", http.MethodPut, "/api/dead-hosts/nope", http.StatusBadRequest}, + {"dead delete", http.MethodDelete, "/api/dead-hosts/bad", http.StatusBadRequest}, + {"dead disable", http.MethodPost, "/api/dead-hosts/x/disable", http.StatusBadRequest}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + var resp *http.Response + switch tc.method { + case http.MethodGet: + resp = apiGet(t, env.BaseURL+tc.path, token) + case http.MethodPut: + resp = apiPut(t, env.BaseURL+tc.path, map[string]any{"name": "x"}, token) + case http.MethodDelete: + resp = apiDelete(t, env.BaseURL+tc.path, token) + default: + resp = apiPost(t, env.BaseURL+tc.path, nil, token) + } + assertStatus(t, resp, tc.want) + }) + } +} + +func TestAPI_NotFoundEnableDisable(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + cases := []string{ + "/api/proxy-hosts/9999/disable", + "/api/streams/9999/enable", + "/api/streams/9999/disable", + "/api/redirection-hosts/9999/enable", + "/api/dead-hosts/9999/disable", + "/api/dead-hosts/9999/enable", + } + for _, path := range cases { + t.Run(path, func(t *testing.T) { + assertStatus(t, apiPost(t, env.BaseURL+path, nil, token), http.StatusNotFound) + }) + } +} + +func TestAPI_MalformedJSONOnCreateAndUpdate(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + createPaths := []string{ + "/api/proxy-hosts", + "/api/access-lists", + "/api/streams", + "/api/redirection-hosts", + "/api/dead-hosts", + } + for _, path := range createPaths { + t.Run("post "+path, func(t *testing.T) { + assertStatus(t, apiPostRaw(t, env.BaseURL+path, `{`, token), http.StatusBadRequest) + }) + } + + ph := apiPost(t, env.BaseURL+"/api/proxy-hosts", map[string]any{ + "domainNames": []string{"malformed-ph.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 1, + "forwardScheme": "http", + }, token) + if ph.StatusCode != http.StatusCreated { + t.Fatalf("proxy host: %d", ph.StatusCode) + } + var proxyHost store.ProxyHost + decodeJSON(t, ph, &proxyHost) + + al := apiPost(t, env.BaseURL+"/api/access-lists", map[string]any{ + "name": "malformed-acl", + "clients": []map[string]string{{"address": "all", "directive": "allow"}}, + }, token) + if al.StatusCode != http.StatusCreated { + t.Fatalf("acl: %d", al.StatusCode) + } + var accessList store.AccessList + decodeJSON(t, al, &accessList) + + strm := apiPost(t, env.BaseURL+"/api/streams", map[string]any{ + "incomingPort": pickFreePort(t), + "forwardingHost": "127.0.0.1", + "forwardingPort": 9, + "tcpForwarding": true, + "enabled": false, + }, token) + if strm.StatusCode != http.StatusCreated { + t.Fatalf("stream: %d", strm.StatusCode) + } + var stream store.Stream + decodeJSON(t, strm, &stream) + + redir := apiPost(t, env.BaseURL+"/api/redirection-hosts", map[string]any{ + "domainNames": []string{"malformed-redir.example"}, + "forwardDomainName": "target.example", + "enabled": true, + }, token) + if redir.StatusCode != http.StatusCreated { + t.Fatalf("redir: %d", redir.StatusCode) + } + var redirection store.RedirectionHost + decodeJSON(t, redir, &redirection) + + dead := apiPost(t, env.BaseURL+"/api/dead-hosts", map[string]any{ + "domainNames": []string{"malformed-dead.example"}, + "enabled": true, + }, token) + if dead.StatusCode != http.StatusCreated { + t.Fatalf("dead: %d", dead.StatusCode) + } + var deadHost store.DeadHost + decodeJSON(t, dead, &deadHost) + + putCases := []struct { + name string + url string + }{ + {"proxy-host", env.BaseURL + "/api/proxy-hosts/" + itoa(proxyHost.ID)}, + {"access-list", env.BaseURL + "/api/access-lists/" + itoa(accessList.ID)}, + {"stream", env.BaseURL + "/api/streams/" + itoa(stream.ID)}, + {"redirection", env.BaseURL + "/api/redirection-hosts/" + itoa(redirection.ID)}, + {"dead-host", env.BaseURL + "/api/dead-hosts/" + itoa(deadHost.ID)}, + } + for _, tc := range putCases { + t.Run("put "+tc.name, func(t *testing.T) { + assertStatus(t, apiPutRaw(t, tc.url, `{`, token), http.StatusBadRequest) + }) + } +} + +func TestAPI_UpdateConflict409(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + t.Run("proxy-hosts", func(t *testing.T) { + a := apiPost(t, env.BaseURL+"/api/proxy-hosts", map[string]any{ + "domainNames": []string{"conflict-a.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 1, + "forwardScheme": "http", + }, token) + b := apiPost(t, env.BaseURL+"/api/proxy-hosts", map[string]any{ + "domainNames": []string{"conflict-b.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 2, + "forwardScheme": "http", + }, token) + if a.StatusCode != http.StatusCreated || b.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %d", a.StatusCode, b.StatusCode) + } + var hostB store.ProxyHost + decodeJSON(t, b, &hostB) + assertStatus(t, apiPut(t, env.BaseURL+"/api/proxy-hosts/"+itoa(hostB.ID), map[string]any{ + "domainNames": []string{"conflict-a.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 2, + "forwardScheme": "http", + }, token), http.StatusConflict) + }) + + t.Run("redirection-hosts", func(t *testing.T) { + a := apiPost(t, env.BaseURL+"/api/redirection-hosts", map[string]any{ + "domainNames": []string{"conflict-redir-a.example"}, + "forwardDomainName": "a.example", + "enabled": true, + }, token) + b := apiPost(t, env.BaseURL+"/api/redirection-hosts", map[string]any{ + "domainNames": []string{"conflict-redir-b.example"}, + "forwardDomainName": "b.example", + "enabled": true, + }, token) + if a.StatusCode != http.StatusCreated || b.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %d", a.StatusCode, b.StatusCode) + } + var hostB store.RedirectionHost + decodeJSON(t, b, &hostB) + assertStatus(t, apiPut(t, env.BaseURL+"/api/redirection-hosts/"+itoa(hostB.ID), map[string]any{ + "domainNames": []string{"conflict-redir-a.example"}, + "forwardDomainName": "b.example", + "enabled": true, + }, token), http.StatusConflict) + }) + + t.Run("dead-hosts", func(t *testing.T) { + a := apiPost(t, env.BaseURL+"/api/dead-hosts", map[string]any{ + "domainNames": []string{"conflict-dead-a.example"}, + "enabled": true, + }, token) + b := apiPost(t, env.BaseURL+"/api/dead-hosts", map[string]any{ + "domainNames": []string{"conflict-dead-b.example"}, + "enabled": true, + }, token) + if a.StatusCode != http.StatusCreated || b.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %d", a.StatusCode, b.StatusCode) + } + var hostB store.DeadHost + decodeJSON(t, b, &hostB) + assertStatus(t, apiPut(t, env.BaseURL+"/api/dead-hosts/"+itoa(hostB.ID), map[string]any{ + "domainNames": []string{"conflict-dead-a.example"}, + "enabled": true, + }, token), http.StatusConflict) + }) + + t.Run("streams", func(t *testing.T) { + port := pickFreePort(t) + a := apiPost(t, env.BaseURL+"/api/streams", map[string]any{ + "incomingPort": port, + "forwardingHost": "127.0.0.1", + "forwardingPort": 9, + "tcpForwarding": true, + "enabled": false, + }, token) + otherPort := pickFreePort(t) + b := apiPost(t, env.BaseURL+"/api/streams", map[string]any{ + "incomingPort": otherPort, + "forwardingHost": "127.0.0.1", + "forwardingPort": 10, + "tcpForwarding": true, + "enabled": false, + }, token) + if a.StatusCode != http.StatusCreated || b.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %d", a.StatusCode, b.StatusCode) + } + var streamB store.Stream + decodeJSON(t, b, &streamB) + assertStatus(t, apiPut(t, env.BaseURL+"/api/streams/"+itoa(streamB.ID), map[string]any{ + "incomingPort": port, + "forwardingHost": "127.0.0.1", + "forwardingPort": 10, + "tcpForwarding": true, + "enabled": false, + }, token), http.StatusConflict) + }) +} + +func TestAPI_ForbiddenEnableDisableBranches(t *testing.T) { + env := newAPITestServer(t) + adminTok := env.loginToken(t) + userTok := env.userToken(t, 2) + + ph := apiPost(t, env.BaseURL+"/api/proxy-hosts", map[string]any{ + "domainNames": []string{"forbid-enable-ph.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 1, + "forwardScheme": "http", + "enabled": true, + }, adminTok) + var proxyHost store.ProxyHost + decodeJSON(t, ph, &proxyHost) + assertStatus(t, apiPost(t, env.BaseURL+"/api/proxy-hosts/"+itoa(proxyHost.ID)+"/enable", nil, userTok), http.StatusForbidden) + + strm := apiPost(t, env.BaseURL+"/api/streams", map[string]any{ + "incomingPort": pickFreePort(t), + "forwardingHost": "127.0.0.1", + "forwardingPort": 9, + "tcpForwarding": true, + "enabled": false, + }, adminTok) + var stream store.Stream + decodeJSON(t, strm, &stream) + assertStatus(t, apiPost(t, env.BaseURL+"/api/streams/"+itoa(stream.ID)+"/disable", nil, userTok), http.StatusForbidden) + + redir := apiPost(t, env.BaseURL+"/api/redirection-hosts", map[string]any{ + "domainNames": []string{"forbid-disable-redir.example"}, + "forwardDomainName": "x.example", + "enabled": true, + }, adminTok) + var redirection store.RedirectionHost + decodeJSON(t, redir, &redirection) + assertStatus(t, apiPost(t, env.BaseURL+"/api/redirection-hosts/"+itoa(redirection.ID)+"/disable", nil, userTok), http.StatusForbidden) + + dead := apiPost(t, env.BaseURL+"/api/dead-hosts", map[string]any{ + "domainNames": []string{"forbid-enable-dead.example"}, + "enabled": true, + }, adminTok) + var deadHost store.DeadHost + decodeJSON(t, dead, &deadHost) + assertStatus(t, apiPost(t, env.BaseURL+"/api/dead-hosts/"+itoa(deadHost.ID)+"/enable", nil, userTok), http.StatusForbidden) +} + +func TestAPI_LoginLegacyPlainPassword(t *testing.T) { + env := newAPITestServer(t) + u, ok := env.Store.GetUserByEmail("admin@example.com") + if !ok { + t.Fatal("admin user missing") + } + u.Password = "legacyplain" + if err := env.Store.UpdateUser(u); err != nil { + t.Fatalf("update user: %v", err) + } + + resp := apiPost(t, env.BaseURL+"/api/login", map[string]any{"password": "legacyplain"}, "") + if resp.StatusCode != http.StatusOK { + t.Fatalf("legacy login: %d %s", resp.StatusCode, readBody(resp)) + } + var loginOut struct { + Token string `json:"token"` + } + decodeJSON(t, resp, &loginOut) + if loginOut.Token == "" { + t.Fatal("empty token for legacy login") + } + + assertStatus(t, apiPost(t, env.BaseURL+"/api/users/me/password", map[string]any{ + "currentPassword": "legacyplain", + "newPassword": "newsecure123", + }, loginOut.Token), http.StatusOK) +} + +func TestAPI_PasswordChangeEmptyNew(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + assertStatus(t, apiPost(t, env.BaseURL+"/api/users/me/password", map[string]any{ + "currentPassword": "password", + "newPassword": "", + }, token), http.StatusBadRequest) +} + +func TestAPI_ListEndpointsOK(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + lists := []string{ + "/api/access-lists", + "/api/streams", + "/api/certificates", + "/api/redirection-hosts", + "/api/dead-hosts", + "/api/settings", + } + for _, path := range lists { + t.Run(path, func(t *testing.T) { + assertStatus(t, apiGet(t, env.BaseURL+path, token), http.StatusOK) + }) + } +} + +func TestAPI_DeleteNotFoundBranches(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + cases := []string{ + "/api/redirection-hosts/9999", + "/api/dead-hosts/9999", + "/api/streams/9999", + } + for _, path := range cases { + t.Run(path, func(t *testing.T) { + assertStatus(t, apiDelete(t, env.BaseURL+path, token), http.StatusNotFound) + }) + } +} + +func TestAPI_PutNotFoundBranches(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + cases := []struct { + path string + body map[string]any + }{ + {"/api/streams/9999", map[string]any{ + "incomingPort": 1, "forwardingHost": "127.0.0.1", "forwardingPort": 1, "tcpForwarding": true, + }}, + {"/api/redirection-hosts/9999", map[string]any{"domainNames": []string{"x.example"}}}, + {"/api/dead-hosts/9999", map[string]any{"domainNames": []string{"x.example"}}}, + } + for _, tc := range cases { + t.Run(tc.path, func(t *testing.T) { + assertStatus(t, apiPut(t, env.BaseURL+tc.path, tc.body, token), http.StatusNotFound) + }) + } +} diff --git a/cmd/helix-proxy/api_errors_test.go b/cmd/helix-proxy/api_errors_test.go new file mode 100644 index 0000000..477abb6 --- /dev/null +++ b/cmd/helix-proxy/api_errors_test.go @@ -0,0 +1,345 @@ +package main + +import ( + "bytes" + "net/http" + "strings" + "testing" + + "helix-proxy/internal/store" +) + +func assertStatus(t *testing.T, resp *http.Response, want int) { + t.Helper() + if resp.StatusCode != want { + t.Errorf("status: got %d want %d body=%s", resp.StatusCode, want, readBody(resp)) + return + } + _ = resp.Body.Close() +} + +func apiPostRaw(t *testing.T, url, rawBody, token string) *http.Response { + t.Helper() + req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader([]byte(rawBody))) + if err != nil { + t.Fatalf("request: %v", err) + } + req.Header.Set("Content-Type", "application/json") + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("do: %v", err) + } + return resp +} + +func TestAPI_ErrorPaths(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + t.Run("auth", func(t *testing.T) { + assertStatus(t, apiPostRaw(t, env.BaseURL+"/api/login", `{`, ""), http.StatusBadRequest) + assertStatus(t, apiPost(t, env.BaseURL+"/api/login", map[string]any{"password": "wrong"}, ""), http.StatusUnauthorized) + assertStatus(t, apiGet(t, env.BaseURL+"/api/proxy-hosts", "not-a-jwt"), http.StatusUnauthorized) + assertStatus(t, apiGet(t, env.BaseURL+"/api/proxy-hosts", "Bearer"), http.StatusUnauthorized) + assertStatus(t, apiGet(t, env.BaseURL+"/api/proxy-hosts", "Basic dXNlcjpwYXNz"), http.StatusUnauthorized) + + assertStatus(t, apiPostRaw(t, env.BaseURL+"/api/users/me/password", `not-json`, token), http.StatusBadRequest) + assertStatus(t, apiPost(t, env.BaseURL+"/api/users/me/password", map[string]any{ + "currentPassword": "password", + "newPassword": "password", + }, token), http.StatusBadRequest) + assertStatus(t, apiPost(t, env.BaseURL+"/api/users/me/password", map[string]any{ + "currentPassword": "wrong", + "newPassword": "newpass123", + }, token), http.StatusUnauthorized) + }) + + t.Run("proxy-hosts", func(t *testing.T) { + assertStatus(t, apiPostRaw(t, env.BaseURL+"/api/proxy-hosts", `{`, token), http.StatusBadRequest) + assertStatus(t, apiGet(t, env.BaseURL+"/api/proxy-hosts/bad-id", token), http.StatusBadRequest) + assertStatus(t, apiGet(t, env.BaseURL+"/api/proxy-hosts/9999", token), http.StatusNotFound) + assertStatus(t, apiPut(t, env.BaseURL+"/api/proxy-hosts/9999", map[string]any{ + "domainNames": []string{"x.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 1, + }, token), http.StatusNotFound) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/proxy-hosts/9999", token), http.StatusNotFound) + assertStatus(t, apiPost(t, env.BaseURL+"/api/proxy-hosts/9999/enable", nil, token), http.StatusNotFound) + }) + + t.Run("access-lists", func(t *testing.T) { + assertStatus(t, apiPostRaw(t, env.BaseURL+"/api/access-lists", `{`, token), http.StatusBadRequest) + assertStatus(t, apiGet(t, env.BaseURL+"/api/access-lists/nope", token), http.StatusBadRequest) + assertStatus(t, apiGet(t, env.BaseURL+"/api/access-lists/9999", token), http.StatusNotFound) + assertStatus(t, apiPut(t, env.BaseURL+"/api/access-lists/9999", map[string]any{"name": "x"}, token), http.StatusNotFound) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/access-lists/9999", token), http.StatusNotFound) + }) + + t.Run("streams", func(t *testing.T) { + assertStatus(t, apiPostRaw(t, env.BaseURL+"/api/streams", `{`, token), http.StatusBadRequest) + assertStatus(t, apiPut(t, env.BaseURL+"/api/streams/bad", map[string]any{}, token), http.StatusBadRequest) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/streams/9999", token), http.StatusNotFound) + + first := apiPost(t, env.BaseURL+"/api/streams", map[string]any{ + "incomingPort": 29100, + "forwardingHost": "127.0.0.1", + "forwardingPort": 9, + "tcpForwarding": true, + "enabled": false, + }, token) + if first.StatusCode != http.StatusCreated { + t.Fatalf("stream create: %d %s", first.StatusCode, readBody(first)) + } + dup := apiPost(t, env.BaseURL+"/api/streams", map[string]any{ + "incomingPort": 29100, + "forwardingHost": "127.0.0.1", + "forwardingPort": 10, + "tcpForwarding": true, + "enabled": false, + }, token) + assertStatus(t, dup, http.StatusConflict) + }) + + t.Run("certificates", func(t *testing.T) { + assertStatus(t, apiPostRaw(t, env.BaseURL+"/api/certificates", `{`, token), http.StatusBadRequest) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/certificates/9999", token), http.StatusNotFound) + assertStatus(t, apiPost(t, env.BaseURL+"/api/certificates/9999/renew", nil, token), http.StatusNotFound) + assertStatus(t, apiPost(t, env.BaseURL+"/api/certificates/bad/renew", nil, token), http.StatusBadRequest) + }) + + t.Run("redirection-hosts", func(t *testing.T) { + assertStatus(t, apiPut(t, env.BaseURL+"/api/redirection-hosts/9999", map[string]any{ + "domainNames": []string{"x.example"}, + }, token), http.StatusNotFound) + assertStatus(t, apiPost(t, env.BaseURL+"/api/redirection-hosts/9999/disable", nil, token), http.StatusNotFound) + assertStatus(t, apiPost(t, env.BaseURL+"/api/redirection-hosts/bad/enable", nil, token), http.StatusBadRequest) + + first := apiPost(t, env.BaseURL+"/api/redirection-hosts", map[string]any{ + "domainNames": []string{"dup-redir.example"}, + "forwardDomainName": "target.example", + "forwardScheme": "https", + "preservePath": true, + "enabled": true, + }, token) + if first.StatusCode != http.StatusCreated { + t.Fatalf("redir create: %d %s", first.StatusCode, readBody(first)) + } + dup := apiPost(t, env.BaseURL+"/api/redirection-hosts", map[string]any{ + "domainNames": []string{"dup-redir.example"}, + "forwardDomainName": "other.example", + "enabled": true, + }, token) + assertStatus(t, dup, http.StatusConflict) + }) + + t.Run("dead-hosts", func(t *testing.T) { + assertStatus(t, apiDelete(t, env.BaseURL+"/api/dead-hosts/9999", token), http.StatusNotFound) + assertStatus(t, apiPost(t, env.BaseURL+"/api/dead-hosts/bad/enable", nil, token), http.StatusBadRequest) + + first := apiPost(t, env.BaseURL+"/api/dead-hosts", map[string]any{ + "domainNames": []string{"dup-dead.example"}, + "enabled": true, + }, token) + if first.StatusCode != http.StatusCreated { + t.Fatalf("dead create: %d %s", first.StatusCode, readBody(first)) + } + dup := apiPost(t, env.BaseURL+"/api/dead-hosts", map[string]any{ + "domainNames": []string{"dup-dead.example"}, + "enabled": true, + }, token) + assertStatus(t, dup, http.StatusConflict) + }) + + t.Run("settings", func(t *testing.T) { + assertStatus(t, apiPostRaw(t, env.BaseURL+"/api/settings", `{`, token), http.StatusBadRequest) + }) +} + +func TestAPI_ForbiddenNonOwner(t *testing.T) { + env := newAPITestServer(t) + adminTok := env.loginToken(t) + userTok := env.userToken(t, 2) + + al := apiPost(t, env.BaseURL+"/api/access-lists", map[string]any{ + "name": "owned-by-admin", + "clients": []map[string]string{{"address": "all", "directive": "allow"}}, + }, adminTok) + if al.StatusCode != http.StatusCreated { + t.Fatalf("acl create: %d", al.StatusCode) + } + var created store.AccessList + decodeJSON(t, al, &created) + + assertStatus(t, apiPut(t, env.BaseURL+"/api/access-lists/"+itoa(created.ID), map[string]any{ + "name": "hijack", + }, userTok), http.StatusForbidden) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/access-lists/"+itoa(created.ID), userTok), http.StatusForbidden) + + ph := apiPost(t, env.BaseURL+"/api/proxy-hosts", map[string]any{ + "domainNames": []string{"forbidden-ph.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 1, + "forwardScheme": "http", + }, adminTok) + if ph.StatusCode != http.StatusCreated { + t.Fatalf("proxy host: %d", ph.StatusCode) + } + var proxyHost store.ProxyHost + decodeJSON(t, ph, &proxyHost) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/proxy-hosts/"+itoa(proxyHost.ID), userTok), http.StatusForbidden) + assertStatus(t, apiPost(t, env.BaseURL+"/api/proxy-hosts/"+itoa(proxyHost.ID)+"/disable", nil, userTok), http.StatusForbidden) + + strm := apiPost(t, env.BaseURL+"/api/streams", map[string]any{ + "incomingPort": pickFreePort(t), + "forwardingHost": "127.0.0.1", + "forwardingPort": 9, + "tcpForwarding": true, + "enabled": false, + }, adminTok) + if strm.StatusCode != http.StatusCreated { + t.Fatalf("stream: %d %s", strm.StatusCode, readBody(strm)) + } + var stream store.Stream + decodeJSON(t, strm, &stream) + assertStatus(t, apiPut(t, env.BaseURL+"/api/streams/"+itoa(stream.ID), map[string]any{ + "incomingPort": stream.IncomingPort, + "forwardingHost": "127.0.0.1", + "forwardingPort": 10, + "tcpForwarding": true, + "enabled": false, + }, userTok), http.StatusForbidden) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/streams/"+itoa(stream.ID), userTok), http.StatusForbidden) + assertStatus(t, apiPost(t, env.BaseURL+"/api/streams/"+itoa(stream.ID)+"/enable", nil, userTok), http.StatusForbidden) + + redir := apiPost(t, env.BaseURL+"/api/redirection-hosts", map[string]any{ + "domainNames": []string{"forbidden-redir.example"}, + "forwardDomainName": "elsewhere.example", + "enabled": true, + }, adminTok) + if redir.StatusCode != http.StatusCreated { + t.Fatalf("redir: %d", redir.StatusCode) + } + var redirection store.RedirectionHost + decodeJSON(t, redir, &redirection) + assertStatus(t, apiPut(t, env.BaseURL+"/api/redirection-hosts/"+itoa(redirection.ID), map[string]any{ + "domainNames": []string{"hijack-redir.example"}, + }, userTok), http.StatusForbidden) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/redirection-hosts/"+itoa(redirection.ID), userTok), http.StatusForbidden) + assertStatus(t, apiPost(t, env.BaseURL+"/api/redirection-hosts/"+itoa(redirection.ID)+"/enable", nil, userTok), http.StatusForbidden) + + dead := apiPost(t, env.BaseURL+"/api/dead-hosts", map[string]any{ + "domainNames": []string{"forbidden-dead.example"}, + "enabled": true, + }, adminTok) + if dead.StatusCode != http.StatusCreated { + t.Fatalf("dead: %d", dead.StatusCode) + } + var deadHost store.DeadHost + decodeJSON(t, dead, &deadHost) + assertStatus(t, apiPut(t, env.BaseURL+"/api/dead-hosts/"+itoa(deadHost.ID), map[string]any{ + "domainNames": []string{"hijack-dead.example"}, + }, userTok), http.StatusForbidden) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/dead-hosts/"+itoa(deadHost.ID), userTok), http.StatusForbidden) + assertStatus(t, apiPost(t, env.BaseURL+"/api/dead-hosts/"+itoa(deadHost.ID)+"/disable", nil, userTok), http.StatusForbidden) + + cert := apiPost(t, env.BaseURL+"/api/certificates", map[string]any{ + "provider": "other", + "domainNames": []string{"forbidden-cert.example"}, + }, adminTok) + if cert.StatusCode != http.StatusCreated { + t.Fatalf("cert: %d", cert.StatusCode) + } + var certificate store.Certificate + decodeJSON(t, cert, &certificate) + assertStatus(t, apiDelete(t, env.BaseURL+"/api/certificates/"+itoa(certificate.ID), userTok), http.StatusForbidden) +} + +func TestAPI_CertificateFailures(t *testing.T) { + t.Run("other provider create succeeds without issuance", func(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + resp := apiPost(t, env.BaseURL+"/api/certificates", map[string]any{ + "provider": "other", + "domainNames": []string{"custom.example"}, + }, token) + assertStatus(t, resp, http.StatusCreated) + }) + + t.Run("LE empty domains rolls back in production", func(t *testing.T) { + t.Setenv("PROXY_MODE", "") + env := newAPITestServer(t) + token := env.loginToken(t) + resp := apiPost(t, env.BaseURL+"/api/certificates", map[string]any{ + "provider": "letsencrypt", + "domainNames": []string{}, + }, token) + if resp.StatusCode != http.StatusInternalServerError { + t.Fatalf("empty domains: %d %s", resp.StatusCode, readBody(resp)) + } + body := readBody(resp) + if !strings.Contains(body, "letsencrypt issuance failed") { + t.Errorf("body: %q", body) + } + if certs := env.Store.GetCertificates(); len(certs) != 0 { + t.Errorf("failed issue should roll back cert, got %d", len(certs)) + } + }) + + t.Run("renew non-LE fails", func(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + create := apiPost(t, env.BaseURL+"/api/certificates", map[string]any{ + "provider": "other", + "domainNames": []string{"renew-fail.example"}, + }, token) + if create.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %s", create.StatusCode, readBody(create)) + } + var cert store.Certificate + decodeJSON(t, create, &cert) + + renew := apiPost(t, env.BaseURL+"/api/certificates/"+itoa(cert.ID)+"/renew", nil, token) + body := readBody(renew) + if renew.StatusCode != http.StatusInternalServerError { + t.Fatalf("renew: %d %s", renew.StatusCode, body) + } + if !strings.Contains(body, "renewal failed") { + t.Errorf("expected renewal failed message, got %q", body) + } + }) + + t.Run("renew forbidden for non-owner", func(t *testing.T) { + env := newAPITestServer(t) + adminTok := env.loginToken(t) + userTok := env.userToken(t, 2) + + create := apiPost(t, env.BaseURL+"/api/certificates", map[string]any{ + "provider": "other", + "domainNames": []string{"owned.example"}, + }, adminTok) + if create.StatusCode != http.StatusCreated { + t.Fatalf("create: %d", create.StatusCode) + } + var cert store.Certificate + decodeJSON(t, create, &cert) + + assertStatus(t, apiPost(t, env.BaseURL+"/api/certificates/"+itoa(cert.ID)+"/renew", nil, userTok), http.StatusForbidden) + }) +} + +func TestAPI_UsersList(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + resp := apiGet(t, env.BaseURL+"/api/users", token) + if resp.StatusCode != http.StatusOK { + t.Fatalf("users: %d", resp.StatusCode) + } + var users []map[string]any + decodeJSON(t, resp, &users) + if len(users) != 1 || users[0]["email"] != "admin@example.com" { + t.Errorf("users: %v", users) + } +} diff --git a/cmd/helix-proxy/api_test.go b/cmd/helix-proxy/api_test.go new file mode 100644 index 0000000..f971a79 --- /dev/null +++ b/cmd/helix-proxy/api_test.go @@ -0,0 +1,467 @@ +package main + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "strconv" + "testing" + + "helix-proxy/internal/store" +) + +func (e *apiTestEnv) loginToken(t *testing.T) string { + t.Helper() + resp := apiPost(t, e.BaseURL+"/api/login", map[string]any{"password": "password"}, "") + if resp.StatusCode != http.StatusOK { + t.Fatalf("login: %d %s", resp.StatusCode, readBody(resp)) + } + var out struct { + Token string `json:"token"` + } + decodeJSON(t, resp, &out) + if out.Token == "" { + t.Fatal("empty login token") + } + return out.Token +} + +func (e *apiTestEnv) userToken(t *testing.T, userID int) string { + t.Helper() + tok, err := e.JWT.GenerateToken(userID, "user@example.com", "User", []string{"user"}) + if err != nil { + t.Fatalf("user token: %v", err) + } + return tok +} + +func apiRequest(t *testing.T, method, url, token string, body any) *http.Response { + t.Helper() + var r io.Reader + if body != nil { + b, _ := json.Marshal(body) + r = bytes.NewReader(b) + } + req, err := http.NewRequest(method, url, r) + if err != nil { + t.Fatalf("request: %v", err) + } + if body != nil { + req.Header.Set("Content-Type", "application/json") + } + if token != "" { + req.Header.Set("Authorization", "Bearer "+token) + } + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("do: %v", err) + } + return resp +} + +func apiGet(t *testing.T, url, token string) *http.Response { + return apiRequest(t, http.MethodGet, url, token, nil) +} + +func apiPost(t *testing.T, url string, body any, token string) *http.Response { + return apiRequest(t, http.MethodPost, url, token, body) +} + +func apiPut(t *testing.T, url string, body any, token string) *http.Response { + return apiRequest(t, http.MethodPut, url, token, body) +} + +func apiDelete(t *testing.T, url, token string) *http.Response { + return apiRequest(t, http.MethodDelete, url, token, nil) +} + +func readBody(resp *http.Response) string { + b, _ := io.ReadAll(resp.Body) + _ = resp.Body.Close() + return string(b) +} + +func decodeJSON(t *testing.T, resp *http.Response, dst any) { + t.Helper() + defer resp.Body.Close() + if err := json.NewDecoder(resp.Body).Decode(dst); err != nil { + t.Fatalf("decode: %v body=%s", err, readBody(resp)) + } +} + +func TestAPI_PublicAndAuth(t *testing.T) { + env := newAPITestServer(t) + + // health (no token) + resp := apiGet(t, env.BaseURL+"/api/", "") + if resp.StatusCode != http.StatusOK { + t.Fatalf("health: %d", resp.StatusCode) + } + var health map[string]any + decodeJSON(t, resp, &health) + if health["status"] != "OK" { + t.Errorf("health status: %v", health["status"]) + } + + // version (no RequireAuth in handler) + resp = apiGet(t, env.BaseURL+"/api/version", "") + if resp.StatusCode != http.StatusOK { + t.Fatalf("version: %d", resp.StatusCode) + } + + // protected list without token -> 401 + resp = apiGet(t, env.BaseURL+"/api/proxy-hosts", "") + if resp.StatusCode != http.StatusUnauthorized { + t.Errorf("proxy-hosts no auth: %d", resp.StatusCode) + } + + token := env.loginToken(t) + + // me + resp = apiGet(t, env.BaseURL+"/api/users/me", token) + if resp.StatusCode != http.StatusOK { + t.Fatalf("users/me: %d", resp.StatusCode) + } + var me map[string]any + decodeJSON(t, resp, &me) + if me["email"] != "admin@example.com" { + t.Errorf("me email: %v", me["email"]) + } +} + +func TestAPI_ProxyHostCRUD(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + create := apiPost(t, env.BaseURL+"/api/proxy-hosts", map[string]any{ + "domainNames": []string{"api-proxy.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 8080, + "forwardScheme": "http", + "enabled": true, + }, token) + if create.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %s", create.StatusCode, readBody(create)) + } + var ph store.ProxyHost + decodeJSON(t, create, &ph) + if ph.ID == 0 || ph.OwnerUserID != 1 { + t.Fatalf("created host: %+v", ph) + } + + list := apiGet(t, env.BaseURL+"/api/proxy-hosts", token) + if list.StatusCode != http.StatusOK { + t.Fatalf("list: %d", list.StatusCode) + } + var hosts []store.ProxyHost + decodeJSON(t, list, &hosts) + if len(hosts) != 1 { + t.Fatalf("list len: %d", len(hosts)) + } + + get := apiGet(t, env.BaseURL+"/api/proxy-hosts/"+itoa(ph.ID), token) + if get.StatusCode != http.StatusOK { + t.Fatalf("get: %d", get.StatusCode) + } + + up := apiPut(t, env.BaseURL+"/api/proxy-hosts/"+itoa(ph.ID), map[string]any{ + "domainNames": []string{"api-proxy-updated.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 9090, + "forwardScheme": "http", + "enabled": true, + }, token) + if up.StatusCode != http.StatusOK { + t.Fatalf("update: %d %s", up.StatusCode, readBody(up)) + } + + dis := apiPost(t, env.BaseURL+"/api/proxy-hosts/"+itoa(ph.ID)+"/disable", nil, token) + if dis.StatusCode != http.StatusOK { + t.Fatalf("disable: %d", dis.StatusCode) + } + en := apiPost(t, env.BaseURL+"/api/proxy-hosts/"+itoa(ph.ID)+"/enable", nil, token) + if en.StatusCode != http.StatusOK { + t.Fatalf("enable: %d", en.StatusCode) + } + + // duplicate domain -> 409 + dup := apiPost(t, env.BaseURL+"/api/proxy-hosts", map[string]any{ + "domainNames": []string{"api-proxy-updated.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 1, + "forwardScheme": "http", + }, token) + if dup.StatusCode != http.StatusConflict { + t.Errorf("duplicate domain: %d %s", dup.StatusCode, readBody(dup)) + } + + // non-owner forbidden + userTok := env.userToken(t, 2) + forbid := apiPut(t, env.BaseURL+"/api/proxy-hosts/"+itoa(ph.ID), map[string]any{ + "domainNames": []string{"hijack.example"}, + "forwardHost": "127.0.0.1", + "forwardPort": 1, + }, userTok) + if forbid.StatusCode != http.StatusForbidden { + t.Errorf("non-owner update: %d", forbid.StatusCode) + } + + del := apiDelete(t, env.BaseURL+"/api/proxy-hosts/"+itoa(ph.ID), token) + if del.StatusCode != http.StatusNoContent { + t.Fatalf("delete: %d %s", del.StatusCode, readBody(del)) + } + + logs := apiGet(t, env.BaseURL+"/api/audit-logs", token) + if logs.StatusCode != http.StatusOK { + t.Fatalf("audit: %d", logs.StatusCode) + } + var audit []store.AuditLog + decodeJSON(t, logs, &audit) + if len(audit) < 3 { + t.Errorf("expected audit entries, got %d", len(audit)) + } +} + +func TestAPI_AccessListCRUD(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + create := apiPost(t, env.BaseURL+"/api/access-lists", map[string]any{ + "name": "api-acl", + "clients": []map[string]string{ + {"address": "all", "directive": "allow"}, + }, + "items": []map[string]string{ + {"username": "u", "password": "p"}, + }, + }, token) + if create.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %s", create.StatusCode, readBody(create)) + } + var al store.AccessList + decodeJSON(t, create, &al) + + get := apiGet(t, env.BaseURL+"/api/access-lists/"+itoa(al.ID), token) + if get.StatusCode != http.StatusOK { + t.Fatalf("get: %d", get.StatusCode) + } + + up := apiPut(t, env.BaseURL+"/api/access-lists/"+itoa(al.ID), map[string]any{ + "name": "api-acl-updated", + "passAuth": true, + "clients": []map[string]string{{"address": "all", "directive": "allow"}}, + "items": []map[string]string{{"username": "u2", "password": "p2"}}, + }, token) + if up.StatusCode != http.StatusOK { + t.Fatalf("update: %d %s", up.StatusCode, readBody(up)) + } + + del := apiDelete(t, env.BaseURL+"/api/access-lists/"+itoa(al.ID), token) + if del.StatusCode != http.StatusNoContent { + t.Fatalf("delete: %d", del.StatusCode) + } +} + +func TestAPI_RedirectionAndDeadHosts(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + rh := apiPost(t, env.BaseURL+"/api/redirection-hosts", map[string]any{ + "domainNames": []string{"api-redir.example"}, + "forwardHttpCode": 302, + "forwardScheme": "https", + "forwardDomainName": "target.example", + "preservePath": true, + "enabled": true, + }, token) + if rh.StatusCode != http.StatusCreated { + t.Fatalf("redir create: %d %s", rh.StatusCode, readBody(rh)) + } + var redir store.RedirectionHost + decodeJSON(t, rh, &redir) + + up := apiPut(t, env.BaseURL+"/api/redirection-hosts/"+itoa(redir.ID), map[string]any{ + "domainNames": []string{"api-redir.example"}, + "forwardHttpCode": 301, + "forwardScheme": "https", + "forwardDomainName": "other.example", + "enabled": true, + }, token) + if up.StatusCode != http.StatusOK { + t.Fatalf("redir update: %d", up.StatusCode) + } + if apiPost(t, env.BaseURL+"/api/redirection-hosts/"+itoa(redir.ID)+"/disable", nil, token).StatusCode != http.StatusOK { + t.Error("redir disable failed") + } + if apiPost(t, env.BaseURL+"/api/redirection-hosts/"+itoa(redir.ID)+"/enable", nil, token).StatusCode != http.StatusOK { + t.Error("redir enable failed") + } + + dh := apiPost(t, env.BaseURL+"/api/dead-hosts", map[string]any{ + "domainNames": []string{"api-dead.example"}, + "enabled": true, + "meta": map[string]any{"html": "dead"}, + }, token) + if dh.StatusCode != http.StatusCreated { + t.Fatalf("dead create: %d %s", dh.StatusCode, readBody(dh)) + } + var dead store.DeadHost + decodeJSON(t, dh, &dead) + + if apiPut(t, env.BaseURL+"/api/dead-hosts/"+itoa(dead.ID), map[string]any{ + "domainNames": []string{"api-dead.example"}, + "enabled": true, + }, token).StatusCode != http.StatusOK { + t.Error("dead update failed") + } + if apiPost(t, env.BaseURL+"/api/dead-hosts/"+itoa(dead.ID)+"/disable", nil, token).StatusCode != http.StatusOK { + t.Error("dead disable failed") + } + + list := apiGet(t, env.BaseURL+"/api/redirection-hosts", token) + if list.StatusCode != http.StatusOK { + t.Fatalf("redir list: %d", list.StatusCode) + } +} + +func TestAPI_StreamCRUD(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + create := apiPost(t, env.BaseURL+"/api/streams", map[string]any{ + "incomingPort": 29001, + "forwardingHost": "127.0.0.1", + "forwardingPort": 9, + "tcpForwarding": true, + "enabled": false, + }, token) + if create.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %s", create.StatusCode, readBody(create)) + } + var strm store.Stream + decodeJSON(t, create, &strm) + + up := apiPut(t, env.BaseURL+"/api/streams/"+itoa(strm.ID), map[string]any{ + "incomingPort": 29001, + "forwardingHost": "127.0.0.1", + "forwardingPort": 10, + "tcpForwarding": true, + "enabled": false, + }, token) + if up.StatusCode != http.StatusOK { + t.Fatalf("update: %d %s", up.StatusCode, readBody(up)) + } + + if apiPost(t, env.BaseURL+"/api/streams/"+itoa(strm.ID)+"/enable", nil, token).StatusCode != http.StatusOK { + t.Error("enable failed") + } + + enabledUp := apiPut(t, env.BaseURL+"/api/streams/"+itoa(strm.ID), map[string]any{ + "incomingPort": 29001, + "forwardingHost": "127.0.0.1", + "forwardingPort": 11, + "tcpForwarding": true, + "enabled": true, + }, token) + if enabledUp.StatusCode != http.StatusOK { + t.Fatalf("update enabled same port: %d %s", enabledUp.StatusCode, readBody(enabledUp)) + } + var enabledResp struct { + store.Stream + Listening bool `json:"listening"` + ListenError string `json:"listenError"` + } + decodeJSON(t, enabledUp, &enabledResp) + if !enabledResp.Listening { + t.Fatalf("expected enabled stream listening after edit, got listenError=%q", enabledResp.ListenError) + } + + if apiPost(t, env.BaseURL+"/api/streams/"+itoa(strm.ID)+"/disable", nil, token).StatusCode != http.StatusOK { + t.Error("disable failed") + } + + del := apiDelete(t, env.BaseURL+"/api/streams/"+itoa(strm.ID), token) + if del.StatusCode != http.StatusNoContent { + t.Fatalf("delete: %d", del.StatusCode) + } +} + +func TestAPI_CertificateCRUD(t *testing.T) { + t.Setenv("PROXY_MODE", "development") + env := newAPITestServer(t) + token := env.loginToken(t) + + create := apiPost(t, env.BaseURL+"/api/certificates", map[string]any{ + "provider": "letsencrypt", + "domainNames": []string{"api-cert.example"}, + }, token) + if create.StatusCode != http.StatusCreated { + t.Fatalf("create: %d %s", create.StatusCode, readBody(create)) + } + var cert store.Certificate + decodeJSON(t, create, &cert) + if cert.ID == 0 { + t.Fatal("cert id missing") + } + + list := apiGet(t, env.BaseURL+"/api/certificates", token) + if list.StatusCode != http.StatusOK { + t.Fatalf("list: %d", list.StatusCode) + } + + renew := apiPost(t, env.BaseURL+"/api/certificates/"+itoa(cert.ID)+"/renew", nil, token) + if renew.StatusCode != http.StatusOK { + t.Fatalf("renew: %d %s", renew.StatusCode, readBody(renew)) + } + + del := apiDelete(t, env.BaseURL+"/api/certificates/"+itoa(cert.ID), token) + if del.StatusCode != http.StatusNoContent { + t.Fatalf("delete: %d", del.StatusCode) + } +} + +func TestAPI_SettingsDashboard(t *testing.T) { + env := newAPITestServer(t) + token := env.loginToken(t) + + set := apiPost(t, env.BaseURL+"/api/settings", map[string]any{ + "default_site": "404", + }, token) + if set.StatusCode != http.StatusOK { + t.Fatalf("settings post: %d %s", set.StatusCode, readBody(set)) + } + var settings map[string]any + decodeJSON(t, set, &settings) + if settings["default_site"] != "404" { + t.Errorf("default_site: %v", settings["default_site"]) + } + + dash := apiGet(t, env.BaseURL+"/api/dashboard", token) + if dash.StatusCode != http.StatusOK { + t.Fatalf("dashboard: %d", dash.StatusCode) + } + var counts map[string]any + decodeJSON(t, dash, &counts) + if _, ok := counts["proxy_hosts"]; !ok { + t.Error("dashboard missing proxy_hosts") + } +} + +func TestAPI_WriteStoreError(t *testing.T) { + w := httptest.NewRecorder() + writeStoreError(w, store.ErrDuplicateStreamPort) + if w.Code != http.StatusConflict { + t.Errorf("conflict: %d", w.Code) + } + w2 := httptest.NewRecorder() + writeStoreError(w2, io.ErrUnexpectedEOF) + if w2.Code != http.StatusInternalServerError { + t.Errorf("generic: %d", w2.Code) + } +} + +func itoa(n int) string { + return strconv.Itoa(n) +} diff --git a/cmd/helix-proxy/https.go b/cmd/helix-proxy/https.go new file mode 100644 index 0000000..3d0cbcf --- /dev/null +++ b/cmd/helix-proxy/https.go @@ -0,0 +1,32 @@ +package main + +import ( + "context" + "crypto/tls" + "net/http" + "time" + + "helix-proxy/internal/proxy" +) + +// serveHTTPS listens with TLS and serves the proxy engine handler (SNI via eng.TLSConfig). +// Shuts down when ctx is cancelled. +func serveHTTPS(ctx context.Context, eng *proxy.Engine, addr string) error { + ln, err := tls.Listen("tcp", addr, eng.TLSConfig()) + if err != nil { + return err + } + srv := &http.Server{ + Handler: eng.Handler(), + ReadTimeout: 30 * time.Second, + WriteTimeout: 60 * time.Second, + } + go func() { + <-ctx.Done() + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + _ = srv.Shutdown(shutdownCtx) + _ = ln.Close() + }() + return srv.Serve(ln) +} diff --git a/cmd/helix-proxy/listen_config.go b/cmd/helix-proxy/listen_config.go new file mode 100644 index 0000000..5864389 --- /dev/null +++ b/cmd/helix-proxy/listen_config.go @@ -0,0 +1,45 @@ +package main + +import ( + "log/slog" + "net" + "os" + "strconv" + "syscall" +) + +// applyUmaskFromEnv sets the process umask from UMASK env (octal) or defaults to 022. +func applyUmaskFromEnv() { + if u := os.Getenv("UMASK"); u != "" { + if mode, err := strconv.ParseInt(u, 8, 32); err == nil { + syscall.Umask(int(mode)) + return + } + slog.Warn("invalid UMASK env (ignored)", "val", u) + } + syscall.Umask(0o022) +} + +// adminListenAddr resolves the admin API/UI listen address from env. +func adminListenAddr() string { + port := "8081" + if p := os.Getenv("ADMIN_PORT"); p != "" { + port = p + } + if os.Getenv("DISABLE_IPV6") == "1" { + return "0.0.0.0:" + port + } + return net.JoinHostPort("", port) +} + +// proxyHTTPSListenAddr resolves the TLS proxy listen address from env. +func proxyHTTPSListenAddr() string { + port := "18443" + if p := os.Getenv("PROXY_HTTPS_PORT"); p != "" { + port = p + } + if os.Getenv("DISABLE_IPV6") == "1" { + return "0.0.0.0:" + port + } + return net.JoinHostPort("", port) +} diff --git a/cmd/helix-proxy/listen_config_test.go b/cmd/helix-proxy/listen_config_test.go new file mode 100644 index 0000000..c094009 --- /dev/null +++ b/cmd/helix-proxy/listen_config_test.go @@ -0,0 +1,105 @@ +package main + +import ( + "testing" +) + +func TestAdminListenAddr(t *testing.T) { + tests := []struct { + name string + env map[string]string + expect string + }{ + { + name: "defaults ipv6", + env: map[string]string{}, + expect: ":8081", + }, + { + name: "custom port", + env: map[string]string{"ADMIN_PORT": "9090"}, + expect: ":9090", + }, + { + name: "disable ipv6", + env: map[string]string{ + "DISABLE_IPV6": "1", + }, + expect: "0.0.0.0:8081", + }, + { + name: "custom port ipv4 only", + env: map[string]string{ + "ADMIN_PORT": "3000", + "DISABLE_IPV6": "1", + }, + expect: "0.0.0.0:3000", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Setenv("ADMIN_PORT", "") + t.Setenv("DISABLE_IPV6", "") + for k, v := range tc.env { + t.Setenv(k, v) + } + if got := adminListenAddr(); got != tc.expect { + t.Errorf("adminListenAddr() = %q want %q", got, tc.expect) + } + }) + } +} + +func TestProxyHTTPSListenAddr(t *testing.T) { + tests := []struct { + name string + env map[string]string + expect string + }{ + { + name: "defaults", + env: map[string]string{}, + expect: ":18443", + }, + { + name: "custom port", + env: map[string]string{"PROXY_HTTPS_PORT": "8443"}, + expect: ":8443", + }, + { + name: "ipv4 only", + env: map[string]string{ + "DISABLE_IPV6": "1", + "PROXY_HTTPS_PORT": "9443", + }, + expect: "0.0.0.0:9443", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + t.Setenv("PROXY_HTTPS_PORT", "") + t.Setenv("DISABLE_IPV6", "") + for k, v := range tc.env { + t.Setenv(k, v) + } + if got := proxyHTTPSListenAddr(); got != tc.expect { + t.Errorf("proxyHTTPSListenAddr() = %q want %q", got, tc.expect) + } + }) + } +} + +func TestApplyUmaskFromEnv(t *testing.T) { + t.Run("invalid ignored", func(t *testing.T) { + t.Setenv("UMASK", "not-octal") + applyUmaskFromEnv() // should not panic + }) + t.Run("valid octal", func(t *testing.T) { + t.Setenv("UMASK", "0077") + applyUmaskFromEnv() + }) + t.Run("default when unset", func(t *testing.T) { + t.Setenv("UMASK", "") + applyUmaskFromEnv() + }) +} diff --git a/cmd/helix-proxy/main.go b/cmd/helix-proxy/main.go new file mode 100644 index 0000000..e656625 --- /dev/null +++ b/cmd/helix-proxy/main.go @@ -0,0 +1,134 @@ +package main + +import ( + "context" + "log/slog" + "net/http" + "os" + "os/signal" + "path/filepath" + "strconv" + "strings" + "syscall" + + "helix-proxy/internal/auth" + "helix-proxy/internal/config" + "helix-proxy/internal/store" +) + +func main() { + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))) + + ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) + defer stop() + + if err := run(ctx); err != nil { + slog.Error("run failed", "err", err) + os.Exit(1) + } +} + +// --- permission helpers for granular object ownership + role checks (admin can do all) --- + +func isAdmin(c *auth.Claims) bool { + if c == nil { + return false + } + for _, r := range c.Roles { + if r == "admin" { + return true + } + } + return false +} + +func writeStoreError(w http.ResponseWriter, err error) { + if store.IsConflictError(err) { + http.Error(w, err.Error(), http.StatusConflict) + return + } + http.Error(w, err.Error(), http.StatusInternalServerError) +} + +func canManage(c *auth.Claims, ownerUserID int) bool { + if c == nil { + return false + } + if isAdmin(c) { + return true + } + return c.UserID == ownerUserID +} + +// applyPUIDPGID chowns the data tree (and key subdirs) if PUID/PGID envs are set +// and the process is running as root (0). This replicates the spirit of original +// entrypoint scripts for Docker non-root runs. After chown, if root, drops privs +// via Setgid+Setuid so process runs as target user (enables low ports etc only if +// needed before drop; matches summary/README "full" PUID claims). +// umask handled early in main() to affect creates. +// To support low ports (80/443) + PUID (which requires root at Listen time), set PUID_NO_DROP=1 +// (chown still done as root, but no drop -- process stays root; or use high ports/caps/entrypoint drop). +func applyPUIDPGID() error { + puidStr := os.Getenv("PUID") + pgidStr := os.Getenv("PGID") + if puidStr == "" || pgidStr == "" { + return nil + } + uid, err := strconv.Atoi(puidStr) + if err != nil { + return err + } + gid, err := strconv.Atoi(pgidStr) + if err != nil { + return err + } + if os.Getuid() != 0 { + return nil // not root, skip + } + dataDir := config.DataDir() + dirs := []string{ + dataDir, + config.Resolve("certs"), + config.Resolve("logs"), + config.Resolve("letsencrypt-acme-challenge"), + config.Resolve("www"), + } + for _, d := range dirs { + if err := os.Chown(d, uid, gid); err != nil { + slog.Warn("chown skipped", "dir", d, "err", err) + // continue for other dirs + } + // recursive for subfiles/dirs (use WalkDir for modern Go) + filepath.WalkDir(d, func(path string, de os.DirEntry, err error) error { + if err != nil { + return nil + } + if err := os.Chown(path, uid, gid); err != nil { + // ignore some + } + return nil + }) + } + slog.Info("applied PUID/PGID chown", "uid", uid, "gid", gid, "data", dataDir) + + if os.Getenv("PUID_NO_DROP") != "" { + slog.Info("PUID_NO_DROP set; skipping privilege drop after chown (remains root for low-port binds if needed)") + return nil + } + + // drop privileges (setgid before setuid; only while still root) + if err := syscall.Setgid(gid); err != nil { + slog.Warn("Setgid after chown failed (still root)", "gid", gid, "err", err) + } else if err := syscall.Setuid(uid); err != nil { + slog.Warn("Setuid after chown failed", "uid", uid, "err", err) + } else { + slog.Info("dropped to PUID/PGID (non-root)", "uid", uid, "gid", gid) + } + return nil +} + +// isBcryptPrefix detects bcrypt-hashed passwords for strict compare (no plain fallback). +// Supports common variants; used in login to prevent hash-str itself being usable as pw. +func isBcryptPrefix(pw string) bool { + return len(pw) > 0 && (strings.HasPrefix(pw, "$2a$") || strings.HasPrefix(pw, "$2b$") || strings.HasPrefix(pw, "$2y$")) +} diff --git a/cmd/helix-proxy/main_test.go b/cmd/helix-proxy/main_test.go new file mode 100644 index 0000000..7e66e2a --- /dev/null +++ b/cmd/helix-proxy/main_test.go @@ -0,0 +1,183 @@ +package main + +import ( + "bytes" + "encoding/json" + "io" + "net/http" + "testing" + + "helix-proxy/internal/auth" +) + +func TestIsBcryptPrefix(t *testing.T) { + cases := []struct { + in string + want bool + }{ + {"", false}, + {"plain", false}, + {"$2a$10$abcdefghijklmnopqrstuv", true}, + {"$2b$12$hash", true}, + {"$2y$05$hash", true}, + {"$2x$10$hash", false}, + } + for _, tc := range cases { + if got := isBcryptPrefix(tc.in); got != tc.want { + t.Errorf("isBcryptPrefix(%q) = %v want %v", tc.in, got, tc.want) + } + } +} + +func TestIsAdminCanManage(t *testing.T) { + adminClaims := &auth.Claims{UserID: 1, Roles: []string{"admin"}} + userClaims := &auth.Claims{UserID: 2, Roles: []string{"user"}} + nilClaims := (*auth.Claims)(nil) + + if !isAdmin(adminClaims) { + t.Error("admin should be admin") + } + if isAdmin(userClaims) { + t.Error("user not admin") + } + if isAdmin(nilClaims) { + t.Error("nil not admin") + } + + if !canManage(adminClaims, 99) { + t.Error("admin can manage any") + } + if !canManage(userClaims, 2) { + t.Error("owner can manage self") + } + if canManage(userClaims, 3) { + t.Error("user cannot manage other") + } + if canManage(nilClaims, 1) { + t.Error("nil cannot") + } +} + +func TestSingleAdminLoginDevModeSkipsMustChange(t *testing.T) { + t.Setenv("PROXY_MODE", "development") + env := newAPITestServer(t) + resp := postJSON(t, env.BaseURL+"/api/login", map[string]any{"password": "password"}) + if resp.StatusCode != 200 { + t.Fatalf("default login failed: %d", resp.StatusCode) + } + var lr struct { + Token string `json:"token"` + MustChangePassword bool `json:"mustChangePassword"` + } + json.NewDecoder(resp.Body).Decode(&lr) + if lr.Token == "" || lr.MustChangePassword { + t.Errorf("dev mode default login should not require password change: %+v", lr) + } +} + +func TestSingleAdminLogin(t *testing.T) { + t.Setenv("PROXY_MODE", "") + env := newAPITestServer(t) + st := env.Store + + // initial default "password" login returns mustChangePassword + resp := postJSON(t, env.BaseURL+"/api/login", map[string]any{"password": "password"}) + if resp.StatusCode != 200 { + t.Fatalf("default login failed: %d", resp.StatusCode) + } + var lr struct { + Token string `json:"token"` + User map[string]any `json:"user"` + MustChangePassword bool `json:"mustChangePassword"` + } + json.NewDecoder(resp.Body).Decode(&lr) + if lr.Token == "" || lr.User["id"] != float64(1) || !lr.MustChangePassword { + t.Errorf("default login resp bad: %+v", lr) + } + + // wrong default fails + respBad := postJSON(t, env.BaseURL+"/api/login", map[string]any{"password": "wrong"}) + if respBad.StatusCode != 401 { + t.Errorf("wrong default should 401: %d", respBad.StatusCode) + } + + // use the returned token to change password (initial case) + token := lr.Token + authH := func(req *http.Request) { req.Header.Set("Authorization", "Bearer "+token) } + chResp := postJSONAuth(t, env.BaseURL+"/api/users/me/password", map[string]any{"currentPassword": "password", "newPassword": "newpass123"}, authH) + if chResp.StatusCode != 200 { + t.Fatalf("initial pw change failed: %d", chResp.StatusCode) + } + + // after change, login with new pw succeeds, no mustChange + resp2 := postJSON(t, env.BaseURL+"/api/login", map[string]any{"password": "newpass123"}) + if resp2.StatusCode != 200 { + t.Fatalf("new pw login failed: %d", resp2.StatusCode) + } + var lr2 struct { + Token string `json:"token"` + MustChangePassword bool `json:"mustChangePassword"` + } + json.NewDecoder(resp2.Body).Decode(&lr2) + if lr2.MustChangePassword { + t.Error("after change, mustChange should be false") + } + + // confirm stored as bcrypt in the test store + uu, _ := st.GetUserByEmail("admin@example.com") + if uu.Password == "" || !isBcryptPrefix(uu.Password) { + t.Error("password not stored as bcrypt after change") + } + + // changing again requires correct current + token2 := lr2.Token + authH2 := func(req *http.Request) { req.Header.Set("Authorization", "Bearer "+token2) } + badCur := postJSONAuth(t, env.BaseURL+"/api/users/me/password", map[string]any{"currentPassword": "wrong", "newPassword": "another"}, authH2) + if badCur.StatusCode != 401 { + t.Errorf("bad current on change should 401: %d", badCur.StatusCode) + } + goodCh := postJSONAuth(t, env.BaseURL+"/api/users/me/password", map[string]any{"currentPassword": "newpass123", "newPassword": "finalpass"}, authH2) + if goodCh.StatusCode != 200 { + t.Errorf("subsequent change failed: %d", goodCh.StatusCode) + } +} + +func postJSON(t *testing.T, url string, body any) *http.Response { + t.Helper() + b, _ := json.Marshal(body) + req, _ := http.NewRequest("POST", url, bytes.NewReader(b)) + req.Header.Set("Content-Type", "application/json") + return doReqClient(req) +} + +func postJSONAuth(t *testing.T, url string, body any, authSetter func(*http.Request)) *http.Response { + t.Helper() + b, _ := json.Marshal(body) + req, _ := http.NewRequest("POST", url, bytes.NewReader(b)) + req.Header.Set("Content-Type", "application/json") + authSetter(req) + return doReqClient(req) +} + +func doReqAuth(method, url string, body any, authSetter func(*http.Request)) *http.Response { + var br io.Reader + if body != nil { + bb, _ := json.Marshal(body) + br = bytes.NewReader(bb) + } + req, _ := http.NewRequest(method, url, br) + if body != nil { + req.Header.Set("Content-Type", "application/json") + } + authSetter(req) + return doReqClient(req) +} + +func doReqClient(req *http.Request) *http.Response { + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + panic(err) + } + return resp +} diff --git a/cmd/helix-proxy/router.go b/cmd/helix-proxy/router.go new file mode 100644 index 0000000..c26fa94 --- /dev/null +++ b/cmd/helix-proxy/router.go @@ -0,0 +1,65 @@ +package main + +import ( + "errors" + "fmt" + "io/fs" + "net/http" + + "helix-proxy/internal/auth" + "helix-proxy/internal/certificate" + "helix-proxy/internal/config" + "helix-proxy/internal/proxy" + "helix-proxy/internal/store" + "helix-proxy/ui" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +// newAdminRouter builds the admin UI + API chi router (no listeners started). +func newAdminRouter(st store.Store, eng *proxy.Engine, cm *certificate.Manager, jwtMgr *auth.JWTManager) chi.Router { + r := chi.NewRouter() + r.Use(middleware.RequestID) + r.Use(middleware.RealIP) + r.Use(middleware.Logger) + r.Use(middleware.Recoverer) + + mountAPI(r, st, eng, cm, jwtMgr) + mountSPA(r) + return r +} + +// mountSPA serves the embedded Svelte SPA or a build placeholder. +func mountSPA(r chi.Router) { + spaSub, err := fs.Sub(ui.Dist, "dist") + if err != nil { + r.Get("/*", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprint(w, ` +Helix Proxy + +

Helix Proxy

+

UI not built yet — run make ui-build then make (or go build).

+

Health: /api (cwd-relative data at `+config.DataDir()+`)

+

All paths (data, www/html, certs, logs...) default to ./data/... and ./data/www/ relative to the process CWD. Override with DATA_DIR, WWW_DIR etc.

+`) + }) + return + } + + fileServer := http.FileServer(http.FS(spaSub)) + r.Get("/*", func(w http.ResponseWriter, r *http.Request) { + p := r.URL.Path + if p != "" && p[0] == '/' { + p = p[1:] + } + if p == "" { + p = "index.html" + } + if _, statErr := fs.Stat(spaSub, p); errors.Is(statErr, fs.ErrNotExist) { + r.URL.Path = "/" + } + fileServer.ServeHTTP(w, r) + }) +} diff --git a/cmd/helix-proxy/router_test.go b/cmd/helix-proxy/router_test.go new file mode 100644 index 0000000..a8842be --- /dev/null +++ b/cmd/helix-proxy/router_test.go @@ -0,0 +1,72 @@ +package main + +import ( + "net/http" + "strings" + "testing" +) + +func TestAdminRouter_SPAFallback(t *testing.T) { + env := newAdminTestServer(t) + + resp := apiGet(t, env.BaseURL+"/api/", "") + if resp.StatusCode != http.StatusOK { + t.Fatalf("api health: %d", resp.StatusCode) + } + + resp = apiGet(t, env.BaseURL+"/", "") + if resp.StatusCode != http.StatusOK { + t.Fatalf("spa root: %d", resp.StatusCode) + } + body := readBody(resp) + if !strings.Contains(body, "Helix Proxy") { + t.Errorf("spa body missing title: %q", body[:min(120, len(body))]) + } + + resp = apiGet(t, env.BaseURL+"/some/spa/route", "") + if resp.StatusCode != http.StatusOK { + t.Fatalf("spa route: %d", resp.StatusCode) + } +} + +func TestApplyPUIDPGID(t *testing.T) { + t.Run("no env", func(t *testing.T) { + t.Setenv("PUID", "") + t.Setenv("PGID", "") + if err := applyPUIDPGID(); err != nil { + t.Errorf("empty env: %v", err) + } + }) + + t.Run("invalid PUID", func(t *testing.T) { + t.Setenv("PUID", "not-a-number") + t.Setenv("PGID", "1000") + if err := applyPUIDPGID(); err == nil { + t.Error("expected error for invalid PUID") + } + }) + + t.Run("invalid PGID", func(t *testing.T) { + t.Setenv("PUID", "1000") + t.Setenv("PGID", "bad") + if err := applyPUIDPGID(); err == nil { + t.Error("expected error for invalid PGID") + } + }) + + t.Run("non-root skips chown", func(t *testing.T) { + t.Setenv("PUID", "1000") + t.Setenv("PGID", "1000") + // tests run unprivileged; Getuid() != 0 => no chown, no error + if err := applyPUIDPGID(); err != nil { + t.Errorf("non-root should skip: %v", err) + } + }) +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/cmd/helix-proxy/run.go b/cmd/helix-proxy/run.go new file mode 100644 index 0000000..ae9473b --- /dev/null +++ b/cmd/helix-proxy/run.go @@ -0,0 +1,132 @@ +package main + +import ( + "context" + "errors" + "log/slog" + "net/http" + "os" + "time" + + "helix-proxy/internal/auth" + "helix-proxy/internal/certificate" + "helix-proxy/internal/config" + "helix-proxy/internal/proxy" + "helix-proxy/internal/store" +) + +// run boots the admin API, proxy engine, HTTPS listener, and renewal loop until ctx is cancelled. +func run(ctx context.Context) error { + applyUmaskFromEnv() + + if err := config.EnsureDataDirs(); err != nil { + return err + } + + if err := applyPUIDPGID(); err != nil { + slog.Warn("PUID/PGID apply partial", "err", err) + } + + dbPath := config.Resolve("db.bolt") + slog.Info("using data dir", "data", config.DataDir(), "db", dbPath) + + if config.IsDevelopment() { + slog.Warn("PROXY_MODE=development (all letsencrypt certs will be self-signed test certs; not for production use)") + } else { + slog.Info("production mode (real LE only; no test cert simulation)") + } + + st, err := store.New() + if err != nil { + return err + } + + eng := proxy.NewEngine(st) + eng.ReloadFromStore() + + cm := certificate.NewManager(st) + jwtMgr := auth.NewJWTManager(os.Getenv("JWT_SECRET")) + + go startRenewalLoop(ctx, cm, eng) + + r := newAdminRouter(st, eng, cm, jwtMgr) + + adminAddr := adminListenAddr() + srv := &http.Server{ + Addr: adminAddr, + Handler: r, + ReadTimeout: 15 * time.Second, + WriteTimeout: 30 * time.Second, + IdleTimeout: 60 * time.Second, + } + + go func() { + slog.Info("admin UI + API listening", "addr", adminAddr, "note", "use ADMIN_PORT=81 in privileged env or docker for real port") + if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { + slog.Error("server error", "err", err) + } + }() + + proxyCtx, proxyCancel := context.WithCancel(ctx) + defer proxyCancel() + + go func() { + if err := eng.Start(proxyCtx); err != nil && !errors.Is(err, http.ErrServerClosed) { + slog.Error("proxy engine stopped", "err", err) + } + }() + + go func() { + httpsAddr := proxyHTTPSListenAddr() + slog.Info("starting HTTPS listener for cert-enabled hosts (pure Go tls termination)", "addr", httpsAddr) + if err := serveHTTPS(proxyCtx, eng, httpsAddr); err != nil && !errors.Is(err, http.ErrServerClosed) { + slog.Error("https server error", "err", err) + } + }() + + <-ctx.Done() + + slog.Info("shutting down...") + shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + proxyCancel() + _ = srv.Shutdown(shutdownCtx) + slog.Info("stopped") + return nil +} + +// startRenewalLoop periodically renews LE certs until ctx is cancelled. +func startRenewalLoop(ctx context.Context, cm *certificate.Manager, eng *proxy.Engine) { + initialDelay := 5 * time.Second + if d := os.Getenv("RENEWAL_INITIAL_DELAY"); d != "" { + if parsed, err := time.ParseDuration(d); err == nil { + initialDelay = parsed + } + } + + renew := func() { + cm.ProcessRenewals() + eng.ReloadFromStore() + } + + go func() { + select { + case <-ctx.Done(): + return + case <-time.After(initialDelay): + renew() + } + }() + + ticker := time.NewTicker(1 * time.Hour) + defer ticker.Stop() + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + renew() + } + } +} diff --git a/cmd/helix-proxy/run_test.go b/cmd/helix-proxy/run_test.go new file mode 100644 index 0000000..7686311 --- /dev/null +++ b/cmd/helix-proxy/run_test.go @@ -0,0 +1,72 @@ +package main + +import ( + "context" + "net/http" + "strconv" + "testing" + "time" + + "helix-proxy/internal/config" +) + +func TestRun_BootstrapAndShutdown(t *testing.T) { + t.Setenv("PROXY_MODE", "development") + t.Setenv("DISABLE_IPV6", "1") + t.Setenv("RENEWAL_INITIAL_DELAY", "1h") // avoid renewal work during short test + + adminPort := pickFreePort(t) + httpPort := pickFreePort(t) + httpsPort := pickFreePort(t) + t.Setenv("ADMIN_PORT", strconv.Itoa(adminPort)) + t.Setenv("PROXY_HTTP_PORT", strconv.Itoa(httpPort)) + t.Setenv("PROXY_HTTPS_PORT", strconv.Itoa(httpsPort)) + + tmp := t.TempDir() + config.ResetForTest() + t.Setenv("DATA_DIR", tmp) + + ctx, cancel := context.WithCancel(context.Background()) + errCh := make(chan error, 1) + go func() { + errCh <- run(ctx) + }() + + adminAddr := "127.0.0.1:" + strconv.Itoa(adminPort) + waitForTCP(t, adminAddr, 5*time.Second) + waitForTCP(t, "127.0.0.1:"+strconv.Itoa(httpPort), 5*time.Second) + waitForTCP(t, "127.0.0.1:"+strconv.Itoa(httpsPort), 5*time.Second) + + resp, err := http.Get("http://" + adminAddr + "/api/") + if err != nil { + t.Fatalf("admin health: %v", err) + } + if resp.StatusCode != http.StatusOK { + t.Fatalf("admin health status: %d", resp.StatusCode) + } + _ = resp.Body.Close() + + cancel() + + select { + case err := <-errCh: + if err != nil { + t.Fatalf("run returned error: %v", err) + } + case <-time.After(15 * time.Second): + t.Fatal("run did not exit after context cancel") + } +} + +func TestRun_EnsureDataDirsFailure(t *testing.T) { + config.ResetForTest() + t.Setenv("DATA_DIR", "/nonexistent-root/helix-proxy-test-"+strconv.Itoa(pickFreePort(t))) + // Parent does not exist and cannot be created under /nonexistent-root. + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + err := run(ctx) + if err == nil { + t.Fatal("expected error when data dirs cannot be created") + } +} diff --git a/cmd/helix-proxy/startup_test.go b/cmd/helix-proxy/startup_test.go new file mode 100644 index 0000000..659e5f3 --- /dev/null +++ b/cmd/helix-proxy/startup_test.go @@ -0,0 +1,146 @@ +package main + +import ( + "context" + "crypto/tls" + "io" + "net" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "testing" + "time" + + "helix-proxy/internal/store" +) + +func pickFreePort(t *testing.T) int { + t.Helper() + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("listen: %v", err) + } + port := ln.Addr().(*net.TCPAddr).Port + _ = ln.Close() + return port +} + +func waitForTCP(t *testing.T, addr string, timeout time.Duration) { + t.Helper() + deadline := time.Now().Add(timeout) + for time.Now().Before(deadline) { + conn, err := net.DialTimeout("tcp", addr, 200*time.Millisecond) + if err == nil { + _ = conn.Close() + return + } + time.Sleep(50 * time.Millisecond) + } + t.Fatalf("tcp %s not ready within %s", addr, timeout) +} + +func TestEngineStartup_HTTPAndHTTPS(t *testing.T) { + t.Setenv("DISABLE_IPV6", "1") + httpPort := pickFreePort(t) + httpsPort := pickFreePort(t) + t.Setenv("PROXY_HTTP_PORT", strconv.Itoa(httpPort)) + t.Setenv("PROXY_HTTPS_PORT", strconv.Itoa(httpsPort)) + + env := newAPITestServer(t) + token := env.loginToken(t) + + upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("X-Upstream", "ok") + _, _ = io.WriteString(w, "upstream-body") + })) + t.Cleanup(upstream.Close) + + u, err := url.Parse(upstream.URL) + if err != nil { + t.Fatalf("parse upstream: %v", err) + } + host, portStr, _ := net.SplitHostPort(u.Host) + port, _ := strconv.Atoi(portStr) + + domain := "startup-tls.example" + certResp := apiPost(t, env.BaseURL+"/api/certificates", map[string]any{ + "provider": "letsencrypt", + "domainNames": []string{domain}, + }, token) + if certResp.StatusCode != http.StatusCreated { + t.Fatalf("cert create: %d %s", certResp.StatusCode, readBody(certResp)) + } + var cert store.Certificate + decodeJSON(t, certResp, &cert) + + phResp := apiPost(t, env.BaseURL+"/api/proxy-hosts", map[string]any{ + "domainNames": []string{domain}, + "forwardHost": host, + "forwardPort": port, + "forwardScheme": "http", + "certificateId": cert.ID, + "enabled": true, + }, token) + if phResp.StatusCode != http.StatusCreated { + t.Fatalf("proxy host: %d %s", phResp.StatusCode, readBody(phResp)) + } + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + httpAddr := "127.0.0.1:" + strconv.Itoa(httpPort) + httpsAddr := proxyHTTPSListenAddr() + + go func() { + _ = env.Engine.Start(ctx) + }() + go func() { + _ = serveHTTPS(ctx, env.Engine, httpsAddr) + }() + + waitForTCP(t, httpAddr, 5*time.Second) + waitForTCP(t, "127.0.0.1:"+strconv.Itoa(httpsPort), 5*time.Second) + + req, err := http.NewRequest(http.MethodGet, "http://"+httpAddr+"/", nil) + if err != nil { + t.Fatalf("request: %v", err) + } + req.Host = domain + resp, err := http.DefaultClient.Do(req) + if err != nil { + t.Fatalf("http proxy: %v", err) + } + body := readBody(resp) + if resp.StatusCode != http.StatusOK { + t.Fatalf("http status: %d body=%s", resp.StatusCode, body) + } + if body != "upstream-body" { + t.Errorf("http body: %q", body) + } + + httpsClient := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + ServerName: domain, + InsecureSkipVerify: true, + }, + }, + } + httpsReq, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:"+strconv.Itoa(httpsPort)+"/", nil) + if err != nil { + t.Fatalf("https request: %v", err) + } + httpsReq.Host = domain + httpsResp, err := httpsClient.Do(httpsReq) + if err != nil { + t.Fatalf("https proxy: %v", err) + } + httpsBody := readBody(httpsResp) + if httpsResp.StatusCode != http.StatusOK { + t.Fatalf("https status: %d body=%s", httpsResp.StatusCode, httpsBody) + } + if httpsBody != "upstream-body" { + t.Errorf("https body: %q", httpsBody) + } +} diff --git a/cmd/helix-proxy/test_server_test.go b/cmd/helix-proxy/test_server_test.go new file mode 100644 index 0000000..cd25e77 --- /dev/null +++ b/cmd/helix-proxy/test_server_test.go @@ -0,0 +1,87 @@ +package main + +import ( + "net/http" + "net/http/httptest" + "os" + "testing" + + "helix-proxy/internal/auth" + "helix-proxy/internal/certificate" + "helix-proxy/internal/config" + "helix-proxy/internal/proxy" + "helix-proxy/internal/store" + + "github.com/go-chi/chi/v5" +) + +// testServerMode selects API-only vs full admin router (API + SPA). +type testServerMode int + +const ( + testServerAPI testServerMode = iota + testServerAdmin +) + +type apiTestEnv struct { + BaseURL string + Store store.Store + Engine *proxy.Engine + Certs *certificate.Manager + JWT *auth.JWTManager +} + +// newTestServer boots a temp store/engine and httptest server with the chosen router. +func newTestServer(t *testing.T, mode testServerMode) *apiTestEnv { + t.Helper() + if _, ok := os.LookupEnv("PROXY_MODE"); !ok { + t.Setenv("PROXY_MODE", "development") + } + tmp := t.TempDir() + config.ResetForTest() + t.Setenv("DATA_DIR", tmp) + if err := config.EnsureDataDirs(); err != nil { + t.Fatalf("ensure dirs: %v", err) + } + st, err := store.New() + if err != nil { + t.Fatalf("store: %v", err) + } + eng := proxy.NewEngine(st) + eng.ReloadFromStore() + cm := certificate.NewManager(st) + jwtMgr := auth.NewJWTManager("test-jwt-secret") + + var handler http.Handler + switch mode { + case testServerAdmin: + handler = newAdminRouter(st, eng, cm, jwtMgr) + default: + r := chi.NewRouter() + mountAPI(r, st, eng, cm, jwtMgr) + handler = r + } + + srv := httptest.NewServer(handler) + t.Cleanup(func() { + srv.Close() + if c, ok := st.(interface{ Close() error }); ok { + _ = c.Close() + } + }) + return &apiTestEnv{ + BaseURL: srv.URL, + Store: st, + Engine: eng, + Certs: cm, + JWT: jwtMgr, + } +} + +func newAPITestServer(t *testing.T) *apiTestEnv { + return newTestServer(t, testServerAPI) +} + +func newAdminTestServer(t *testing.T) *apiTestEnv { + return newTestServer(t, testServerAdmin) +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b18a144 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,30 @@ +services: + app: + build: . + image: helix-proxy:dev + restart: unless-stopped + ports: + - "80:80" + - "81:81" + - "443:443" + volumes: + - ./data:/app/data + # user: "0:0" # required when using PUID/PGID != built-in to allow binary to chown+drop + # working_dir: /app # binary uses CWD for relative data/ + data/www/ + # environment: + # - DATA_DIR=/app/data + # - WWW_DIR=/app/data/www + # - PUID=1000 + # - PGID=1000 + # - DISABLE_IPV6=1 + # # PUID_NO_DROP=1 # if using low ports (80/443) + PUID: chown as root but skip drop (stay root for bind; default drop runs as PUID after, requires high ports or NET_BIND_SERVICE cap) + # To use optional SQL backend instead of default yaml: + # - DB_TYPE=postgres + # - DB_POSTGRES_HOST=db + # ... and add a db service + healthcheck: + test: ["CMD", "wget", "-qO-", "http://127.0.0.1:81/api"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..95502f4 --- /dev/null +++ b/go.mod @@ -0,0 +1,23 @@ +module helix-proxy + +go 1.25.4 + +require ( + github.com/go-acme/lego/v4 v4.35.2 + github.com/go-chi/chi/v5 v5.3.0 + github.com/golang-jwt/jwt/v5 v5.3.1 + go.etcd.io/bbolt v1.3.10 + golang.org/x/crypto v0.50.0 + golang.org/x/net v0.53.0 +) + +require ( + github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect + github.com/miekg/dns v1.1.72 // indirect + golang.org/x/mod v0.35.0 // indirect + golang.org/x/sync v0.20.0 // indirect + golang.org/x/sys v0.43.0 // indirect + golang.org/x/text v0.36.0 // indirect + golang.org/x/tools v0.44.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ec4ddff --- /dev/null +++ b/go.sum @@ -0,0 +1,38 @@ +github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= +github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-acme/lego/v4 v4.35.2 h1:uVQg+KC/yj9R2g7Q9W5wDqhvQvxV5SMu5eqFVoN5xZU= +github.com/go-acme/lego/v4 v4.35.2/go.mod h1:pX2jN5n8OphMGY1IaMjYm5DAEzguBaKRt8AvJAgJXpc= +github.com/go-chi/chi/v5 v5.3.0 h1:halUjDxhshgXHMrao5bB8eNBXo/rnzwr8m5m36glehM= +github.com/go-chi/chi/v5 v5.3.0/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/miekg/dns v1.1.72 h1:vhmr+TF2A3tuoGNkLDFK9zi36F2LS+hKTRW0Uf8kbzI= +github.com/miekg/dns v1.1.72/go.mod h1:+EuEPhdHOsfk6Wk5TT2CzssZdqkmFhf8r+aVyDEToIs= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= +go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= +golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= +golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= +golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go new file mode 100644 index 0000000..676e2b6 --- /dev/null +++ b/internal/auth/jwt.go @@ -0,0 +1,131 @@ +package auth + +import ( + "context" + "errors" + "fmt" + "net/http" + "strings" + "time" + + "github.com/golang-jwt/jwt/v5" +) + +var ( + ErrInvalidToken = errors.New("invalid or expired token") + ErrNoToken = errors.New("no authorization token") +) + +// Claims for our JWT (minimal, matching original style). +type Claims struct { + UserID int `json:"user_id"` + Email string `json:"email"` + Name string `json:"name"` + Roles []string `json:"roles"` + jwt.RegisteredClaims +} + +// Context key for user info. +type contextKey string + +const UserContextKey contextKey = "user" + +// JWTManager handles signing and validation. +type JWTManager struct { + secret []byte +} + +// NewJWTManager creates a manager. In real use, load secret from secure store or env (never commit real secret). +// For demo we accept a secret; in production rotate and use env/JWT_SECRET or db meta. +func NewJWTManager(secret string) *JWTManager { + if secret == "" { + secret = "dev-only-insecure-secret-change-in-prod" + } + return &JWTManager{secret: []byte(secret)} +} + +// GenerateToken creates a JWT for the given user (1 hour expiry like typical). +func (m *JWTManager) GenerateToken(userID int, email, name string, roles []string) (string, error) { + now := time.Now() + if roles == nil { + roles = []string{} + } + claims := Claims{ + UserID: userID, + Email: email, + Name: name, + Roles: roles, + RegisteredClaims: jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(now.Add(1 * time.Hour)), + IssuedAt: jwt.NewNumericDate(now), + NotBefore: jwt.NewNumericDate(now), + Issuer: "helix-proxy", + }, + } + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + return token.SignedString(m.secret) +} + +// ValidateToken parses and validates the token, returns claims. +func (m *JWTManager) ValidateToken(tokenStr string) (*Claims, error) { + token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(t *jwt.Token) (interface{}, error) { + if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"]) + } + return m.secret, nil + }) + if err != nil { + return nil, ErrInvalidToken + } + if claims, ok := token.Claims.(*Claims); ok && token.Valid { + return claims, nil + } + return nil, ErrInvalidToken +} + +// Middleware returns a chi/http middleware that validates Bearer token and injects user into context. +// Skips if no token (for public endpoints like /login we handle separately). +// On failure returns 401. +func (m *JWTManager) Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + authHeader := r.Header.Get("Authorization") + if authHeader == "" { + // No token: let handler decide (some endpoints public) + next.ServeHTTP(w, r) + return + } + + parts := strings.SplitN(authHeader, " ", 2) + if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") { + http.Error(w, "invalid authorization header", http.StatusUnauthorized) + return + } + + claims, err := m.ValidateToken(parts[1]) + if err != nil { + http.Error(w, "invalid token", http.StatusUnauthorized) + return + } + + // Inject into context + ctx := context.WithValue(r.Context(), UserContextKey, claims) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + +// GetUserFromContext extracts claims if present (for handlers that require auth). +func GetUserFromContext(ctx context.Context) (*Claims, bool) { + claims, ok := ctx.Value(UserContextKey).(*Claims) + return claims, ok +} + +// RequireAuth is a simple helper that can be used inside handlers for protected routes +// (alternative to middleware if you want per-route). +func RequireAuth(w http.ResponseWriter, r *http.Request) (*Claims, bool) { + claims, ok := GetUserFromContext(r.Context()) + if !ok { + http.Error(w, "authentication required", http.StatusUnauthorized) + return nil, false + } + return claims, true +} diff --git a/internal/auth/jwt_test.go b/internal/auth/jwt_test.go new file mode 100644 index 0000000..faf6b68 --- /dev/null +++ b/internal/auth/jwt_test.go @@ -0,0 +1,128 @@ +package auth + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + "time" +) + +func TestJWTManager_GenerateValidate_Roundtrip(t *testing.T) { + m := NewJWTManager("test-secret-123") + token, err := m.GenerateToken(42, "user@example.com", "User", []string{"admin", "user"}) + if err != nil { + t.Fatal(err) + } + if token == "" { + t.Error("empty token") + } + + claims, err := m.ValidateToken(token) + if err != nil { + t.Fatalf("validate: %v", err) + } + if claims.UserID != 42 || claims.Email != "user@example.com" || len(claims.Roles) != 2 { + t.Errorf("claims: %+v", claims) + } + if claims.ExpiresAt == nil || time.Until(claims.ExpiresAt.Time) > time.Hour { + t.Error("expiry not ~1h") + } +} + +func TestJWTManager_DevSecretFallback(t *testing.T) { + m := NewJWTManager("") // empty -> dev + token, _ := m.GenerateToken(1, "a@b", "A", nil) + _, err := m.ValidateToken(token) + if err != nil { + t.Error("dev secret should allow roundtrip") + } +} + +func TestJWTManager_BadToken(t *testing.T) { + m := NewJWTManager("s") + if _, err := m.ValidateToken("not.a.jwt"); err == nil { + t.Error("bad token should err") + } + // wrong sig + m2 := NewJWTManager("other") + tok, _ := m2.GenerateToken(1, "e", "n", nil) + if _, err := m.ValidateToken(tok); err == nil { + t.Error("wrong sig should invalid") + } +} + +func TestJWTManager_Middleware(t *testing.T) { + m := NewJWTManager("sec") + token, _ := m.GenerateToken(7, "m@e", "M", []string{"admin"}) + + // with valid bearer + h := m.Middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + c, ok := GetUserFromContext(r.Context()) + if !ok || c.UserID != 7 { + t.Error("claims not in ctx") + } + w.WriteHeader(200) + })) + req := httptest.NewRequest("GET", "/", nil) + req.Header.Set("Authorization", "Bearer "+token) + rr := httptest.NewRecorder() + h.ServeHTTP(rr, req) + if rr.Code != 200 { + t.Errorf("valid bearer: %d", rr.Code) + } + + // no token: passes through (no 401) + h2 := m.Middleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(204) + })) + req2 := httptest.NewRequest("GET", "/", nil) + rr2 := httptest.NewRecorder() + h2.ServeHTTP(rr2, req2) + if rr2.Code != 204 { + t.Error("no token should pass") + } + + // bad token: 401 + req3 := httptest.NewRequest("GET", "/", nil) + req3.Header.Set("Authorization", "Bearer bad") + rr3 := httptest.NewRecorder() + h.ServeHTTP(rr3, req3) + if rr3.Code != 401 { + t.Errorf("bad token 401: %d", rr3.Code) + } + + // wrong scheme + req4 := httptest.NewRequest("GET", "/", nil) + req4.Header.Set("Authorization", "Basic foo") + rr4 := httptest.NewRecorder() + h.ServeHTTP(rr4, req4) + if rr4.Code != 401 { + t.Errorf("bad scheme: %d", rr4.Code) + } +} + +func TestRequireAuth(t *testing.T) { + // direct, needs ctx with claims + m := NewJWTManager("s") + tok, _ := m.GenerateToken(99, "r@a", "R", nil) + claims, _ := m.ValidateToken(tok) + + req := httptest.NewRequest("GET", "/", nil) + // without ctx + rr := httptest.NewRecorder() + c, ok := RequireAuth(rr, req) + if ok || c != nil || rr.Code != 401 { + t.Error("require without claims should 401") + } + + // with ctx set via context value + req2 := httptest.NewRequest("GET", "/", nil) + ctx := context.WithValue(req2.Context(), UserContextKey, claims) + req2 = req2.WithContext(ctx) + rr2 := httptest.NewRecorder() + c2, ok2 := RequireAuth(rr2, req2) + if !ok2 || c2.UserID != 99 { + t.Error("require with claims failed") + } +} diff --git a/internal/certificate/manager.go b/internal/certificate/manager.go new file mode 100644 index 0000000..f192b41 --- /dev/null +++ b/internal/certificate/manager.go @@ -0,0 +1,365 @@ +package certificate + +import ( + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "log/slog" + "math/big" + "os" + "path/filepath" + "strings" + "time" + + "github.com/go-acme/lego/v4/certcrypto" + "github.com/go-acme/lego/v4/certificate" + "github.com/go-acme/lego/v4/lego" + "github.com/go-acme/lego/v4/providers/http/webroot" + "github.com/go-acme/lego/v4/registration" + + "helix-proxy/internal/config" + "helix-proxy/internal/store" +) + +// Manager handles Let's Encrypt (and future other) certificate issuance and renewal using lego. +// It is the pure-Go certificate issuance manager (using lego for LE, no external certbot). +type Manager struct { + st store.Store +} + +// NewManager returns a cert manager bound to the store (for read/update of Certificate records). +func NewManager(st store.Store) *Manager { + return &Manager{st: st} +} + +// account represents a lego user/account. We generate ephemeral keys for v1 (new LE account per issue). +// For production persistence of account key, we could save to data/certs/lego-account..key . +type account struct { + Email string + Registration *registration.Resource + key crypto.PrivateKey +} + +func (a *account) GetEmail() string { + return a.Email +} +func (a *account) GetRegistration() *registration.Resource { + return a.Registration +} +func (a *account) GetPrivateKey() crypto.PrivateKey { + return a.key +} + +// Issue obtains (or renews) a certificate for the given store.Certificate record (must have provider=="letsencrypt"). +// It writes PEMs into the cert's Meta["cert"] and Meta["key"] (for engine loadCerts compatibility with custom certs), +// updates expires_on, and persists via store.SetCertificate. +// It also optionally writes PEM files under data/certs// for inspection/backup. +// email is the contact for LE registration (required for LE); falls back to "admin@example.com" if empty. +// Respects meta["staging"]=true or env LEGO_STAGING=1 to use staging (recommended for testing to avoid rate limits). +// Respects meta["key_type"] = "rsa" | "ecdsa" (default rsa2048). +// If PROXY_MODE=development, uses self-signed test cert for *all* LE certs (no domain tricks). +func (m *Manager) Issue(sc store.Certificate, email string) error { + if sc.Provider != "letsencrypt" { + return fmt.Errorf("not a letsencrypt certificate (provider=%s)", sc.Provider) + } + if len(sc.DomainNames) == 0 { + return fmt.Errorf("no domain_names for certificate %d", sc.ID) + } + if email == "" { + email = "admin@example.com" + } + + // In development mode (PROXY_MODE=development), *all* letsencrypt certs use the + // self-signed test path (no real LE). This is for dev/testing only. + // In production (default), real LE http-01 is always attempted. + if config.IsDevelopment() { + slog.Info("using self-signed test cert (LE simulation; all certs in dev mode)", "domains", sc.DomainNames) + return m.issueTestCert(sc) + } + + staging := false + if sc.Meta != nil { + if v, ok := sc.Meta["staging"]; ok { + switch t := v.(type) { + case bool: + staging = t + case string: + staging = strings.ToLower(t) == "true" || t == "1" + } + } + } + if os.Getenv("LEGO_STAGING") != "" || os.Getenv("LE_STAGING") != "" { + staging = true + } + + keyType := certcrypto.RSA2048 + if sc.Meta != nil { + if kt, ok := sc.Meta["key_type"].(string); ok { + switch strings.ToLower(kt) { + case "ecdsa", "ec256", "p256": + keyType = certcrypto.EC256 + case "rsa4096": + keyType = certcrypto.RSA4096 + } + } + } + + // Create lego account (ephemeral key; see note above) + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return fmt.Errorf("generate account key: %w", err) + } + acc := &account{ + Email: email, + key: privateKey, + } + + cfg := lego.NewConfig(acc) + if staging { + cfg.CADirURL = lego.LEDirectoryStaging + slog.Info("using Let's Encrypt staging for certificate issue", "certID", sc.ID, "domains", sc.DomainNames) + } else { + cfg.CADirURL = lego.LEDirectoryProduction + } + cfg.Certificate.KeyType = keyType + + client, err := lego.NewClient(cfg) + if err != nil { + return fmt.Errorf("lego client: %w", err) + } + + // http-01 via our served challenge dir (lego writes token files, our proxy serves them) + webrootPath := config.Resolve("letsencrypt-acme-challenge") + // ensure layout exists + _ = os.MkdirAll(filepath.Join(webrootPath, ".well-known", "acme-challenge"), 0o755) + + provider, err := webroot.NewHTTPProvider(webrootPath) + if err != nil { + return fmt.Errorf("webroot provider: %w", err) + } + if err := client.Challenge.SetHTTP01Provider(provider); err != nil { + return fmt.Errorf("set http01 provider: %w", err) + } + + // Register account (or resolve). For ephemeral this always creates a fresh LE account. + reg, err := client.Registration.Register(registration.RegisterOptions{ + TermsOfServiceAgreed: true, + }) + if err != nil { + // If already registered for key (rare here), try resolve; otherwise fail + if reg2, err2 := client.Registration.ResolveAccountByKey(); err2 == nil { + reg = reg2 + } else { + return fmt.Errorf("le register: %w", err) + } + } + acc.Registration = reg + + slog.Info("requesting LE certificate", "certID", sc.ID, "domains", sc.DomainNames, "staging", staging, "email", email) + + request := certificate.ObtainRequest{ + Domains: sc.DomainNames, + Bundle: true, + } + certs, err := client.Certificate.Obtain(request) + if err != nil { + return fmt.Errorf("obtain cert: %w", err) + } + + // Populate PEMs in meta (used by engine for tls.Certificate and by custom cert path) + // Use compat keys "certificate"/"certificate_key" + "cert"/"key" (for data format compatibility) + if sc.Meta == nil { + sc.Meta = map[string]any{} + } + sc.Meta["certificate"] = string(certs.Certificate) + sc.Meta["certificate_key"] = string(certs.PrivateKey) + sc.Meta["cert"] = string(certs.Certificate) + sc.Meta["key"] = string(certs.PrivateKey) + // keep original meta bits like dns_challenge etc. + sc.Meta["letsencrypt"] = map[string]any{ + "account": email, + "staging": staging, + "issued_at": time.Now().UTC().Format(time.RFC3339), + } + + // Compute real expiry from the returned leaf cert (more reliable than LE response) + expires := "" + if block, _ := pem.Decode(certs.Certificate); block != nil { + if xc, err := x509.ParseCertificate(block.Bytes); err == nil { + expires = xc.NotAfter.UTC().Format("2006-01-02 15:04:05") + sc.Meta["cert_info"] = map[string]any{ + "not_after": xc.NotAfter.UTC().Format(time.RFC3339), + "issuer": xc.Issuer.String(), + "subject": xc.Subject.String(), + } + } + } + if expires == "" { + expires = time.Now().Add(90 * 24 * time.Hour).Format("2006-01-02 15:04:05") // fallback ~90d + } + sc.ExpiresOn = expires + + // Persist files too (under data/certs//) for serving live certs + certDir := filepath.Join(config.Resolve("certs"), fmt.Sprintf("%d", sc.ID)) + if err := os.MkdirAll(certDir, 0o755); err == nil { + _ = os.WriteFile(filepath.Join(certDir, "fullchain.pem"), certs.Certificate, 0o600) + _ = os.WriteFile(filepath.Join(certDir, "privkey.pem"), certs.PrivateKey, 0o600) + } + + // Save back to store (updates meta + expires) + if err := m.st.SetCertificate(sc); err != nil { + return fmt.Errorf("store set cert after issue: %w", err) + } + + slog.Info("LE certificate obtained and stored", "certID", sc.ID, "domains", sc.DomainNames, "expires", sc.ExpiresOn) + return nil +} + +// GetEmailForCert tries to find a reasonable contact email for LE from the cert meta or first admin user. +func (m *Manager) GetEmailForCert(sc store.Certificate) string { + if sc.Meta != nil { + if e, ok := sc.Meta["email"].(string); ok && e != "" { + return e + } + if e, ok := sc.Meta["letsencrypt_email"].(string); ok && e != "" { + return e + } + } + // fallback to global setting or seeded admin + if settings := m.st.GetSettings(); settings != nil { + if e, ok := settings["letsencrypt_email"].(string); ok && e != "" { + return e + } + } + users := m.st.GetUsers() + for _, u := range users { + if u.Email != "" { + return u.Email + } + } + return "admin@example.com" +} + +// ShouldRenew reports whether a LE cert is within the renewal window (30 days before expiry). +func (m *Manager) ShouldRenew(sc store.Certificate) bool { + if sc.Provider != "letsencrypt" { + return false + } + if sc.ExpiresOn == "" { + return true + } + t, err := time.Parse("2006-01-02 15:04:05", sc.ExpiresOn) + if err != nil { + // try RFC3339 etc + if t2, err2 := time.Parse(time.RFC3339, sc.ExpiresOn); err2 == nil { + t = t2 + } else { + return true + } + } + renewBefore := 30 * 24 * time.Hour + return time.Until(t) < renewBefore +} + +// ProcessRenewals finds LE certs due for renewal and re-issues them (sequentially). +// Called by timer and on demand. +func (m *Manager) ProcessRenewals() { + certs := m.st.GetCertificates() + for _, c := range certs { + if c.Provider == "letsencrypt" && m.ShouldRenew(c) { + slog.Info("renewing expiring LE cert", "id", c.ID, "domains", c.DomainNames, "expires", c.ExpiresOn) + email := m.GetEmailForCert(c) + if err := m.Issue(c, email); err != nil { + slog.Error("renewal failed (will retry later)", "id", c.ID, "err", err) + continue + } + } + } +} + +// --- dev-mode test helpers (all letsencrypt certs become self-signed test certs when PROXY_MODE=development) --- + +func (m *Manager) issueTestCert(sc store.Certificate) error { + certPEM, keyPEM, err := generateSelfSignedTestCert(sc.DomainNames) + if err != nil { + return err + } + + if sc.Meta == nil { + sc.Meta = map[string]any{} + } + sc.Meta["certificate"] = string(certPEM) + sc.Meta["certificate_key"] = string(keyPEM) + sc.Meta["cert"] = string(certPEM) + sc.Meta["key"] = string(keyPEM) + sc.Meta["test_cert"] = true // marker that this was dev sim, not real LE + sc.Meta["letsencrypt"] = map[string]any{ + "account": "test@localhost", + "staging": true, + "issued_at": time.Now().UTC().Format(time.RFC3339), + "note": "self-signed simulation (only in PROXY_MODE=development)", + } + + // parse for expires + expires := "" + if block, _ := pem.Decode(certPEM); block != nil { + if xc, err := x509.ParseCertificate(block.Bytes); err == nil { + expires = xc.NotAfter.UTC().Format("2006-01-02 15:04:05") + sc.Meta["cert_info"] = map[string]any{ + "not_after": xc.NotAfter.UTC().Format(time.RFC3339), + "issuer": xc.Issuer.String(), + "subject": xc.Subject.String(), + } + } + } + if expires == "" { + expires = time.Now().Add(90 * 24 * time.Hour).Format("2006-01-02 15:04:05") + } + sc.ExpiresOn = expires + + // write files + certDir := filepath.Join(config.Resolve("certs"), fmt.Sprintf("%d", sc.ID)) + _ = os.MkdirAll(certDir, 0o755) + _ = os.WriteFile(filepath.Join(certDir, "fullchain.pem"), certPEM, 0o600) + _ = os.WriteFile(filepath.Join(certDir, "privkey.pem"), keyPEM, 0o600) + + if err := m.st.SetCertificate(sc); err != nil { + return err + } + slog.Info("test self-signed cert stored (LE simulation, dev-only)", "certID", sc.ID, "domains", sc.DomainNames) + return nil +} + +func generateSelfSignedTestCert(domains []string) (certPEM, keyPEM []byte, err error) { + priv, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, nil, err + } + + serial, _ := rand.Int(rand.Reader, new(big.Int).Lsh(big.NewInt(1), 128)) + template := x509.Certificate{ + SerialNumber: serial, + Subject: pkix.Name{CommonName: domains[0], Organization: []string{"Helix Proxy test"}}, + NotBefore: time.Now().Add(-1 * time.Hour), + NotAfter: time.Now().Add(90 * 24 * time.Hour), + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + DNSNames: domains, + } + + der, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + return nil, nil, err + } + certPEM = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}) + + keyDER := x509.MarshalPKCS1PrivateKey(priv) + keyPEM = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyDER}) + return certPEM, keyPEM, nil +} diff --git a/internal/certificate/manager_test.go b/internal/certificate/manager_test.go new file mode 100644 index 0000000..52c904b --- /dev/null +++ b/internal/certificate/manager_test.go @@ -0,0 +1,230 @@ +package certificate + +import ( + "crypto/x509" + "encoding/pem" + "fmt" + "os" + "strings" + "testing" + "time" + + "helix-proxy/internal/config" + "helix-proxy/internal/store" +) + +func TestGenerateSelfSignedTestCert(t *testing.T) { + domains := []string{"foo.example.com", "bar.example.com"} + certPEM, keyPEM, err := generateSelfSignedTestCert(domains) + if err != nil { + t.Fatalf("generate: %v", err) + } + if !strings.Contains(string(certPEM), "BEGIN CERTIFICATE") { + t.Error("no cert pem marker") + } + if !strings.Contains(string(keyPEM), "BEGIN RSA PRIVATE KEY") { + t.Error("no key pem marker") + } + // parse and check + block, _ := pem.Decode(certPEM) + if block == nil { + t.Fatal("decode failed") + } + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + t.Fatalf("parse: %v", err) + } + if cert.NotAfter.Sub(cert.NotBefore) < 89*24*time.Hour { + t.Error("validity too short") + } + found := false + for _, d := range cert.DNSNames { + if d == "foo.example.com" { + found = true + } + } + if !found { + t.Error("dns names not in cert") + } +} + +func TestIssueTestCertPath(t *testing.T) { + // use temp data dir, reset config + config.ResetForTest() + tmp := t.TempDir() + t.Setenv("DATA_DIR", tmp) + // ensure dirs so writes don't fail + _ = config.EnsureDataDirs() + + // minimal store: use New which is bbolt in the tmp (via reset+env) + st, err := store.New() + if err != nil { + t.Fatalf("new store: %v", err) + } + if c, ok := st.(interface{ Close() error }); ok { + defer c.Close() + } + + cm := NewManager(st) + + // create a cert record (simulating what API would do) + cert := store.Certificate{ + Provider: "letsencrypt", + NiceName: "test local", + DomainNames: []string{"mytest.example.com"}, // any domain; in dev mode all LE become test certs + Meta: map[string]any{}, + } + created, err := st.CreateCertificate(cert) + if err != nil { + t.Fatalf("create cert: %v", err) + } + + // dev mode => all letsencrypt certs are test/self-signed + t.Setenv("PROXY_MODE", "development") + email := cm.GetEmailForCert(created) + if err := cm.Issue(created, email); err != nil { + t.Fatalf("Issue test cert: %v", err) + } + + // reload from store + got, ok := st.GetCertificate(created.ID) + if !ok { + t.Fatal("cert not found after issue") + } + if got.ExpiresOn == "" { + t.Error("no expires set") + } + if v, _ := got.Meta["test_cert"].(bool); !v { + t.Error("test_cert marker not set") + } + if _, ok := got.Meta["certificate"]; !ok { + t.Error("certificate pem not in meta") + } + if _, ok := got.Meta["key"]; !ok { + t.Error("key not in meta") + } + + // file written? + if _, err := os.Stat(config.Resolve("certs")); err != nil { + t.Error("certs dir missing") + } + // the per-id dir + perID := fmt.Sprintf("%s/%d", config.Resolve("certs"), got.ID) + if _, err := os.Stat(perID); err != nil { + t.Logf("per-id cert dir %s not present (may be ok): %v", perID, err) + } + + // exercise non-local LE path meta parsing (staging/key_type from meta) in *production* mode + // (real LE path; will fail on obtain due to no DNS/reach, but pre-LE branches + meta covered) + t.Setenv("PROXY_MODE", "") + c2 := store.Certificate{ + Provider: "letsencrypt", + DomainNames: []string{"nonlocal.example.com"}, + Meta: map[string]any{"staging": "true", "key_type": "rsa4096"}, + } + created2, _ := st.CreateCertificate(c2) + email2 := cm.GetEmailForCert(created2) + if err2 := cm.Issue(created2, email2); err2 == nil || strings.Contains(err2.Error(), "not a letsencrypt") { + t.Logf("non-local LE Issue err (expected without public reach/DNS; meta parse covered): %v", err2) + } +} + +func TestIssueRejectsNonLE(t *testing.T) { + config.ResetForTest() + tmp := t.TempDir() + t.Setenv("DATA_DIR", tmp) + _ = config.EnsureDataDirs() + st, err := store.New() + if err != nil { + t.Fatalf("store: %v", err) + } + if c, ok := st.(interface{ Close() error }); ok { + defer c.Close() + } + cm := NewManager(st) + c := store.Certificate{Provider: "other", DomainNames: []string{"ex.com"}} + created, _ := st.CreateCertificate(c) + err = cm.Issue(created, "e@e.com") + if err == nil || !strings.Contains(err.Error(), "not a letsencrypt") { + t.Errorf("expected reject non-letsencrypt: got %v", err) + } +} + +func TestShouldRenew(t *testing.T) { + config.ResetForTest() + tmp := t.TempDir() + t.Setenv("DATA_DIR", tmp) + _ = config.EnsureDataDirs() + st, err := store.New() + if err != nil { + t.Fatalf("store: %v", err) + } + if c, ok := st.(interface{ Close() error }); ok { + defer c.Close() + } + cm := NewManager(st) + now := time.Now().UTC() + tests := []struct { + name string + exp string + want bool + }{ + {"empty", "", true}, + {"past", now.Add(-40 * 24 * time.Hour).Format("2006-01-02 15:04:05"), true}, + {"near 29d", now.Add(29 * 24 * time.Hour).Format("2006-01-02 15:04:05"), true}, + {"far 31d", now.Add(31 * 24 * time.Hour).Format("2006-01-02 15:04:05"), false}, + {"rfc3339 near", now.Add(10 * 24 * time.Hour).Format(time.RFC3339), true}, + {"bad format", "not-a-date", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := store.Certificate{Provider: "letsencrypt", ExpiresOn: tt.exp} + if got := cm.ShouldRenew(c); got != tt.want { + t.Errorf("ShouldRenew(%s) = %v want %v", tt.exp, got, tt.want) + } + }) + } +} + +func TestProcessRenewals(t *testing.T) { + config.ResetForTest() + tmp := t.TempDir() + t.Setenv("DATA_DIR", tmp) + _ = config.EnsureDataDirs() + st, err := store.New() + if err != nil { + t.Fatalf("store: %v", err) + } + if c, ok := st.(interface{ Close() error }); ok { + defer c.Close() + } + cm := NewManager(st) + + // dev mode: *all* letsencrypt certs (any domain) use test/self-signed path in Issue/renew + t.Setenv("PROXY_MODE", "development") + + // LE due soon + dueExp := time.Now().Add(5 * 24 * time.Hour).Format("2006-01-02 15:04:05") + leDue := store.Certificate{Provider: "letsencrypt", DomainNames: []string{"due.example.com"}, ExpiresOn: dueExp} + createdDue, _ := st.CreateCertificate(leDue) + + // LE far future (no renew) + farExp := time.Now().Add(40 * 24 * time.Hour).Format("2006-01-02 15:04:05") + leFar := store.Certificate{Provider: "letsencrypt", DomainNames: []string{"far.example.com"}, ExpiresOn: farExp} + createdFar, _ := st.CreateCertificate(leFar) + + // non-LE (ignored even if "due") + nonLE := store.Certificate{Provider: "other", DomainNames: []string{"x.com"}, ExpiresOn: time.Now().Add(-1 * time.Hour).Format("2006-01-02 15:04:05")} + st.CreateCertificate(nonLE) + + cm.ProcessRenewals() + + gDue, _ := st.GetCertificate(createdDue.ID) + if tDue, _ := time.Parse("2006-01-02 15:04:05", gDue.ExpiresOn); time.Until(tDue) < 80*24*time.Hour { + t.Error("due LE cert was not renewed (expires not extended)") + } + gFar, _ := st.GetCertificate(createdFar.ID) + if gFar.ExpiresOn != farExp { + t.Error("far LE should not have been touched") + } +} diff --git a/internal/config/paths.go b/internal/config/paths.go new file mode 100644 index 0000000..e7c81df --- /dev/null +++ b/internal/config/paths.go @@ -0,0 +1,110 @@ +package config + +import ( + "os" + "path/filepath" + "strings" + "sync" +) + +var ( + once sync.Once + base string // resolved data base dir +) + +// DataDir returns the base directory for data (db.bolt, certs, logs, www, etc). +// Respects DATA_DIR env (absolute or relative). Falls back to "data" relative to CWD. +func DataDir() string { + once.Do(func() { + if d := os.Getenv("DATA_DIR"); d != "" { + base = d + return + } + // default relative to cwd + wd, err := os.Getwd() + if err != nil { + wd = "." + } + base = filepath.Join(wd, "data") + }) + return base +} + +// Resolve returns an absolute or relative path under the data dir for the given subpath (e.g. "db.bolt", "certs", "www"). +// If the corresponding *_DIR env is set it is used as base instead. +func Resolve(sub string) string { + // Allow per-subdir override e.g. CERTS_DIR, WWW_DIR, LOGS_DIR, CHALLENGE_DIR + key := "" + switch sub { + case "db.bolt": + key = "DATA_DIR" + case "certs", "custom_ssl": + key = "CERTS_DIR" + case "logs": + key = "LOGS_DIR" + case "letsencrypt-acme-challenge", "challenge": + key = "CHALLENGE_DIR" + case "www": + if d := os.Getenv("WWW_DIR"); d != "" { + return filepath.Join(d, "") // allow override to point directly + } + key = "DATA_DIR" + case "html": + if d := os.Getenv("HTML_DIR"); d != "" { + return filepath.Join(d, "") + } + key = "DATA_DIR" + default: + key = "DATA_DIR" + } + + dir := DataDir() + if key != "" { + if override := os.Getenv(key); override != "" { + dir = override + } + } + return filepath.Join(dir, sub) +} + +// EnsureDataDirs creates the expected subdirs under the resolved data location (and www inside data by default). +// Also pre-creates the acme-challenge subdir layout that lego webroot + our handler expect. +func EnsureDataDirs() error { + dirs := []string{ + Resolve(""), + Resolve("certs"), + Resolve("logs"), + Resolve("letsencrypt-acme-challenge"), + Resolve("www"), // data/www by default + } + for _, d := range dirs { + if err := os.MkdirAll(d, 0o755); err != nil { + return err + } + } + // full layout for http-01 challenges written by lego + acme := filepath.Join(Resolve("letsencrypt-acme-challenge"), ".well-known", "acme-challenge") + if err := os.MkdirAll(acme, 0o755); err != nil { + return err + } + return nil +} + +// ResetForTest clears the cached data dir (sync.Once) so tests can change +// DATA_DIR / *_DIR envs via t.Setenv and observe fresh resolution. +// Call at the start of such tests. This is the supported way to make +// config testable without globals leaking across tests. +func ResetForTest() { + once = sync.Once{} + base = "" +} + +// IsDevelopment reports whether PROXY_MODE=development (or "dev"). +// Defaults to false (production mode). +// When true, all letsencrypt certs use self-signed test certs (via the cert manager's +// issueTestCert path). No domain tricks (.localtest etc.) are used. In production +// (default) real LE issuance is always attempted. +func IsDevelopment() bool { + mode := strings.ToLower(os.Getenv("PROXY_MODE")) + return mode == "development" || mode == "dev" +} diff --git a/internal/config/paths_test.go b/internal/config/paths_test.go new file mode 100644 index 0000000..79bd77f --- /dev/null +++ b/internal/config/paths_test.go @@ -0,0 +1,158 @@ +package config + +import ( + "os" + "path/filepath" + "testing" +) + +func TestDataDir(t *testing.T) { + ResetForTest() + t.Setenv("DATA_DIR", "") + // default should be data under cwd + d := DataDir() + if d == "" { + t.Fatal("DataDir empty") + } + // once behavior: change env shouldn't affect without reset + t.Setenv("DATA_DIR", "/tmp/should-not-affect") + d2 := DataDir() + if d != d2 { + t.Error("DataDir ignored Once") + } + + ResetForTest() + t.Setenv("DATA_DIR", "/tmp/testdata123") + d3 := DataDir() + if d3 != "/tmp/testdata123" { + t.Errorf("DATA_DIR override failed: got %s", d3) + } +} + +func TestResolve(t *testing.T) { + ResetForTest() + tmp := t.TempDir() + t.Setenv("DATA_DIR", tmp) + + tests := []struct { + sub string + wantBase string // suffix check + }{ + {"db.bolt", filepath.Join(tmp, "db.bolt")}, + {"certs", filepath.Join(tmp, "certs")}, + {"logs", filepath.Join(tmp, "logs")}, + {"letsencrypt-acme-challenge", filepath.Join(tmp, "letsencrypt-acme-challenge")}, + {"www", filepath.Join(tmp, "www")}, + {"unknown", filepath.Join(tmp, "unknown")}, + } + for _, tt := range tests { + got := Resolve(tt.sub) + if got != tt.wantBase { + t.Errorf("Resolve(%q) = %q want %q", tt.sub, got, tt.wantBase) + } + } + + // override CERTS_DIR (uses as base + join sub per current impl) + ResetForTest() + certsBase := filepath.Join(tmp, "mycerts-base") + t.Setenv("CERTS_DIR", certsBase) + t.Setenv("DATA_DIR", tmp) + wantCerts := filepath.Join(certsBase, "certs") + if got := Resolve("certs"); got != wantCerts { + t.Errorf("CERTS_DIR override: got %s want %s", got, wantCerts) + } + + // WWW_DIR / HTML_DIR (special case returns dir directly; overrides conditioned on exact sub to avoid cross-contamination) + ResetForTest() + wwwDir := filepath.Join(tmp, "mywww") + t.Setenv("WWW_DIR", wwwDir) + if got := Resolve("www"); got != wwwDir { + t.Errorf("WWW_DIR: got %s", got) + } + ResetForTest() + htmlDir := filepath.Join(tmp, "myhtml") + t.Setenv("HTML_DIR", htmlDir) + if got := Resolve("html"); got != htmlDir { + t.Errorf("HTML_DIR: got %s", got) + } + + // mixed overrides: only HTML set should not affect Resolve("www") (falls to DATA_DIR/www); vice-versa + // (explicitly clear the other *_DIR to counter t.Setenv lingering within one TestResolve func) + ResetForTest() + t.Setenv("WWW_DIR", "") + t.Setenv("HTML_DIR", htmlDir) + t.Setenv("DATA_DIR", tmp) + if got := Resolve("www"); got != filepath.Join(tmp, "www") { + t.Errorf("mixed: only HTML should not affect www: got %s", got) + } + ResetForTest() + t.Setenv("HTML_DIR", "") + t.Setenv("WWW_DIR", wwwDir) + t.Setenv("DATA_DIR", tmp) + if got := Resolve("html"); got != filepath.Join(tmp, "html") { + t.Errorf("mixed: only WWW should not affect html: got %s", got) + } + + // CHALLENGE_DIR (uses as base + join per impl) + ResetForTest() + chBase := filepath.Join(tmp, "ch-base") + t.Setenv("CHALLENGE_DIR", chBase) + wantCh := filepath.Join(chBase, "letsencrypt-acme-challenge") + if got := Resolve("letsencrypt-acme-challenge"); got != wantCh { + t.Errorf("CHALLENGE: got %s want %s", got, wantCh) + } +} + +func TestEnsureDataDirs(t *testing.T) { + ResetForTest() + tmp := t.TempDir() + t.Setenv("DATA_DIR", tmp) + + if err := EnsureDataDirs(); err != nil { + t.Fatalf("EnsureDataDirs: %v", err) + } + + // verify layout + dirs := []string{ + tmp, + filepath.Join(tmp, "certs"), + filepath.Join(tmp, "logs"), + filepath.Join(tmp, "letsencrypt-acme-challenge"), + filepath.Join(tmp, "www"), + filepath.Join(tmp, "letsencrypt-acme-challenge", ".well-known", "acme-challenge"), + } + for _, d := range dirs { + if fi, err := os.Stat(d); err != nil || !fi.IsDir() { + t.Errorf("expected dir %s: %v", d, err) + } + } +} + +func TestIsDevelopment(t *testing.T) { + ResetForTest() + t.Setenv("PROXY_MODE", "") + if IsDevelopment() { + t.Error("default should be production (not dev)") + } + + t.Setenv("PROXY_MODE", "development") + if !IsDevelopment() { + t.Error("PROXY_MODE=development should be dev") + } + + t.Setenv("PROXY_MODE", "dev") + if !IsDevelopment() { + t.Error("PROXY_MODE=dev should be dev") + } + + t.Setenv("PROXY_MODE", "production") + if IsDevelopment() { + t.Error("PROXY_MODE=production should not be dev") + } + + // case insensitive + t.Setenv("PROXY_MODE", "DEVELOPMENT") + if !IsDevelopment() { + t.Error("case insensitive") + } +} diff --git a/internal/models/models.go b/internal/models/models.go new file mode 100644 index 0000000..56c3486 --- /dev/null +++ b/internal/models/models.go @@ -0,0 +1,155 @@ +package models + +// These types are the core domain models for Helix Proxy. +// They are used by the Store interface (any backend), the API, the proxy engine, +// and the certificate manager. + +type Root struct { + Version int + + Users []User + ProxyHosts []ProxyHost + AccessLists []AccessList + Streams []Stream + Certificates []Certificate + RedirectionHosts []RedirectionHost + DeadHosts []DeadHost + Settings map[string]any + AuditLogs []AuditLog + + // meta for internal use by store impls + Meta map[string]any +} + +type User struct { + ID int `json:"id"` + Email string `json:"email"` + Name string `json:"name"` + Password string `json:"password,omitempty"` // bcrypt hash; empty for demo seeded admin. (API responses manually omit the value) + Roles []string `json:"roles"` + TotpSecret string `json:"totpSecret,omitempty"` // include for bbolt persistence (API never returns the secret value) + TotpEnabled bool `json:"totpEnabled"` +} + +// HeaderRule is a name/value pair for request or response header overrides. +type HeaderRule struct { + Name string `json:"name"` + Value string `json:"value,omitempty"` +} + +type ProxyHost struct { + ID int `json:"id"` + DomainNames []string `json:"domainNames"` + ForwardScheme string `json:"forwardScheme"` + ForwardHost string `json:"forwardHost"` + ForwardPort int `json:"forwardPort"` + AccessListID int `json:"accessListId,omitempty"` + CertificateID int `json:"certificateId,omitempty"` + SslForced bool `json:"sslForced"` + CachingEnabled bool `json:"cachingEnabled"` + BlockExploits bool `json:"blockExploits"` + AllowWebsocketUpgrade bool `json:"allowWebsocketUpgrade"` + Http2Support bool `json:"http2Support"` + HstsEnabled bool `json:"hstsEnabled"` + HstsSubdomains bool `json:"hstsSubdomains"` + TrustForwardedProto bool `json:"trustForwardedProto"` + RequestHeaders []HeaderRule `json:"requestHeaders,omitempty"` + ResponseHeaders []HeaderRule `json:"responseHeaders,omitempty"` + HideHeaders []string `json:"hideHeaders,omitempty"` + AdvancedConfig string `json:"advancedConfig,omitempty"` // legacy; engine falls back when structured headers are empty + Enabled bool `json:"enabled"` + Locations []Location `json:"locations,omitempty"` + Meta map[string]any `json:"meta,omitempty"` + OwnerUserID int `json:"ownerUserId,omitempty"` + CreatedOn string `json:"createdOn,omitempty"` // server-set UTC on create (via store); preserved on update; empty for legacy DB records +} + +type Location struct { + ID int `json:"id,omitempty"` + Path string `json:"path"` + ForwardScheme string `json:"forwardScheme"` + ForwardHost string `json:"forwardHost"` + ForwardPort int `json:"forwardPort"` + ForwardPath string `json:"forwardPath,omitempty"` + AdvancedConfig string `json:"advancedConfig,omitempty"` +} + +type AccessList struct { + ID int `json:"id"` + Name string `json:"name"` + SatisfyAny bool `json:"satisfyAny"` + Clients []AccessClient `json:"clients"` + Items []AccessItem `json:"items"` + PassAuth bool `json:"passAuth"` + OwnerUserID int `json:"ownerUserId,omitempty"` + CreatedOn string `json:"createdOn,omitempty"` // server-set UTC on create (via store); preserved on update; empty for legacy DB records +} + +type AccessClient struct { + Address string `json:"address"` + Directive string `json:"directive"` // "allow" or "deny" +} + +type AccessItem struct { + Username string `json:"username"` + Password string `json:"password"` // plain for demo access lists (separate from User bcrypt) +} + +type Stream struct { + ID int `json:"id"` + IncomingPort int `json:"incomingPort"` + ForwardingHost string `json:"forwardingHost"` + ForwardingPort int `json:"forwardingPort"` + TCPForwarding bool `json:"tcpForwarding"` + UDPForwarding bool `json:"udpForwarding"` + Enabled bool `json:"enabled"` + CertificateID int `json:"certificateId"` + Meta map[string]any `json:"meta,omitempty"` + OwnerUserID int `json:"ownerUserId,omitempty"` + CreatedOn string `json:"createdOn,omitempty"` // server-set UTC on create (via store); preserved on update; empty for legacy DB records +} + +type Certificate struct { + ID int `json:"id"` + Provider string `json:"provider"` // "letsencrypt" or "other" + NiceName string `json:"niceName"` + DomainNames []string `json:"domainNames"` + ExpiresOn string `json:"expiresOn"` + Meta map[string]any `json:"meta"` + OwnerUserID int `json:"ownerUserId,omitempty"` + CreatedOn string `json:"createdOn,omitempty"` // server-set UTC on create (via store); preserved on update; empty for legacy DB records +} + +type RedirectionHost struct { + ID int `json:"id"` + DomainNames []string `json:"domainNames"` + ForwardHTTPCode int `json:"forwardHttpCode"` + ForwardScheme string `json:"forwardScheme"` + ForwardDomainName string `json:"forwardDomainName"` + PreservePath bool `json:"preservePath"` + Enabled bool `json:"enabled"` + AdvancedConfig string `json:"advancedConfig,omitempty"` + Meta map[string]any `json:"meta,omitempty"` + OwnerUserID int `json:"ownerUserId,omitempty"` + CreatedOn string `json:"createdOn,omitempty"` // server-set UTC on create (via store); preserved on update; empty for legacy DB records +} + +type DeadHost struct { + ID int `json:"id"` + DomainNames []string `json:"domainNames"` + Enabled bool `json:"enabled"` + AdvancedConfig string `json:"advancedConfig,omitempty"` + Meta map[string]any `json:"meta,omitempty"` + OwnerUserID int `json:"ownerUserId,omitempty"` + CreatedOn string `json:"createdOn,omitempty"` // server-set UTC on create (via store); preserved on update; empty for legacy DB records +} + +type AuditLog struct { + ID int `json:"id"` + UserID int `json:"userId"` + ObjectType string `json:"objectType"` + ObjectID int `json:"objectId"` + Action string `json:"action"` + Meta map[string]any `json:"meta"` + CreatedOn string `json:"createdOn"` +} diff --git a/internal/proxy/engine.go b/internal/proxy/engine.go new file mode 100644 index 0000000..d0e184d --- /dev/null +++ b/internal/proxy/engine.go @@ -0,0 +1,1252 @@ +package proxy + +import ( + "context" + "crypto/tls" + "encoding/base64" + "fmt" + "io" + "log/slog" + "net" + "net/http" + "net/http/httptest" + "net/http/httputil" + "net/url" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "time" + + "helix-proxy/internal/config" + "helix-proxy/internal/store" + "helix-proxy/internal/www" +) + +// Engine manages the live HTTP reverse proxy (and later streams) based on the store. +// It replaces all nginx config generation / reload. +type Engine struct { + mu sync.RWMutex + hosts map[string]*Host // domain (or wildcard key) -> config + handler + st store.Store + srv *http.Server // the :80 / :443 listener(s) + started bool + + // streams + streamMu sync.Mutex + streamHandles map[int]*streamHandle // stream id -> live listeners + streamRuntimeMu sync.RWMutex + streamRuntime map[int]*streamRuntime // incoming port -> live listener state + + // TLS certs per host (from certificates) + certMu sync.RWMutex + hostCerts map[string]*tls.Certificate + certByID map[int]*tls.Certificate // for streams SSL termination etc. + + // redirection hosts + redirMu sync.RWMutex + redirHosts map[string]store.RedirectionHost + + // dead hosts + deadMu sync.RWMutex + deadHosts map[string]store.DeadHost + + // simple response cache for cachingEnabled + cacheMu sync.Mutex + cache map[string]struct { + body []byte + headers http.Header + status int + expires time.Time + } +} + +// Host holds the live config for one (or more) domain(s). +type Host struct { + ID int + Domains []string + ForwardURL string // default backend + Enabled bool + ForwardScheme string + SslForced bool + BlockExploits bool + Locations []store.Location + + // Access list (resolved at reload) + AccessClients []store.AccessClient + AccessSatisfyAny bool + AccessItems []store.AccessItem + AccessPassAuth bool + + // Additional flags from ProxyHost (applied in Handler) + HstsEnabled bool + HstsSubdomains bool + AllowWebsocketUpgrade bool + TrustForwardedProto bool + ReqHeaderSets map[string]string + RespHeaderAdds map[string]string + RespHeaderHides []string + CachingEnabled bool + Http2Support bool // noted for future http2 backend config +} + +func NewEngine(st store.Store) *Engine { + return &Engine{ + hosts: make(map[string]*Host), + st: st, + streamHandles: make(map[int]*streamHandle), + streamRuntime: make(map[int]*streamRuntime), + hostCerts: make(map[string]*tls.Certificate), + certByID: make(map[int]*tls.Certificate), + redirHosts: make(map[string]store.RedirectionHost), + deadHosts: make(map[string]store.DeadHost), + cache: make(map[string]struct { + body []byte + headers http.Header + status int + expires time.Time + }), + } +} + +// ReloadFromStore rebuilds the in-memory routing table from the store. +// Called on startup and after any host mutation. +func (e *Engine) ReloadFromStore() { + e.mu.Lock() + defer e.mu.Unlock() + + e.hosts = make(map[string]*Host) + + proxyHosts := e.st.GetProxyHosts() + slog.Info("store root for reload", "proxyHosts", len(proxyHosts), "accessLists", len(e.st.GetAccessLists())) + for _, ph := range proxyHosts { + if !ph.Enabled || len(ph.DomainNames) == 0 { + continue + } + scheme := ph.ForwardScheme + if scheme == "" { + scheme = "http" + } + u := &url.URL{Scheme: scheme, Host: net.JoinHostPort(ph.ForwardHost, "80")} + if ph.ForwardPort > 0 { + u.Host = net.JoinHostPort(ph.ForwardHost, itoa(ph.ForwardPort)) + } + h := &Host{ + ID: ph.ID, + Domains: append([]string(nil), ph.DomainNames...), + ForwardURL: u.String(), + Enabled: ph.Enabled, + ForwardScheme: scheme, + SslForced: ph.SslForced, + BlockExploits: ph.BlockExploits, + Locations: append([]store.Location(nil), ph.Locations...), + + // access list + AccessSatisfyAny: false, + + // additional flags + HstsEnabled: ph.HstsEnabled, + HstsSubdomains: ph.HstsSubdomains, + AllowWebsocketUpgrade: ph.AllowWebsocketUpgrade, + TrustForwardedProto: ph.TrustForwardedProto, + CachingEnabled: ph.CachingEnabled, + Http2Support: ph.Http2Support, + } + h.ReqHeaderSets, h.RespHeaderAdds, h.RespHeaderHides = resolveProxyHeaders(ph) + if ph.AccessListID > 0 { + if al, ok := e.st.GetAccessList(ph.AccessListID); ok { + h.AccessClients = append([]store.AccessClient(nil), al.Clients...) + h.AccessSatisfyAny = al.SatisfyAny + h.AccessItems = append([]store.AccessItem(nil), al.Items...) + h.AccessPassAuth = al.PassAuth + slog.Info("loaded access list for host", "hostID", ph.ID, "listID", ph.AccessListID, "clients", len(h.AccessClients), "authItems", len(h.AccessItems)) + } else { + slog.Warn("access list not found for host", "hostID", ph.ID, "listID", ph.AccessListID) + } + } + for _, d := range h.Domains { + e.hosts[strings.ToLower(d)] = h // later: support *.example.com wildcard matching + } + } + slog.Info("proxy engine reloaded", "hosts", len(e.hosts)) + e.reloadStreams() + e.loadCerts() + e.loadRedirs() + e.loadDeads() + e.cacheMu.Lock() + e.cache = make(map[string]struct { + body []byte + headers http.Header + status int + expires time.Time + }) + e.cacheMu.Unlock() +} + +func itoa(i int) string { return strconv.Itoa(i) } + +// Handler returns the http.Handler for the main proxy listener(s). +// It does SNI/Host based lookup and reverse proxy. +func (e *Engine) Handler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Serve ACME challenges for LE (before host lookup) + // lego webroot provider writes tokens to /.well-known/acme-challenge/ + // so our serve must look there (standard layout). + if strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/") { + challengeDir := config.Resolve("letsencrypt-acme-challenge") + acmeDir := filepath.Join(challengeDir, ".well-known", "acme-challenge") + file := filepath.Join(acmeDir, filepath.Base(r.URL.Path)) + if data, err := os.ReadFile(file); err == nil { + w.Header().Set("Content-Type", "text/plain") + w.Write(data) + return + } + http.NotFound(w, r) + return + } + + host := r.Host + if h, _, err := net.SplitHostPort(host); err == nil { + host = h + } + host = strings.ToLower(host) + + // Check redirection hosts first (independent) + e.redirMu.RLock() + rh, isRedir := e.redirHosts[host] + e.redirMu.RUnlock() + slog.Debug("redir check", "host", host, "isRedir", isRedir, "numRedirs", len(e.redirHosts)) + if isRedir { + code := rh.ForwardHTTPCode + if code == 0 { + code = 302 + } + target := rh.ForwardDomainName + scheme := rh.ForwardScheme + if scheme == "" || scheme == "auto" { + scheme = "http" + } + target = scheme + "://" + target + if rh.PreservePath { + target += r.URL.RequestURI() + } + http.Redirect(w, r, target, code) + return + } + + // Check dead hosts (blocks access, serves 404 or custom) + e.deadMu.RLock() + dh, isDead := e.deadHosts[host] + e.deadMu.RUnlock() + if isDead { + // per-dead custom html via meta.html (for full parity/custom content) + if dh.Meta != nil { + if html, ok := dh.Meta["html"].(string); ok && html != "" { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusNotFound) + w.Write([]byte(html)) + return + } + } + // Serve 404 page (data/www/404.html overrides embedded default). + if data := www.LoadPage("404.html", map[string]string{ + "MESSAGE": fmt.Sprintf("This host (%s) is configured as dead/blocked.", host), + }); data != nil { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusNotFound) + w.Write(data) + return + } + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("404 Not Found (this host is configured as dead/blocked)")) + return + } + + e.mu.RLock() + hcfg, ok := e.hosts[host] + e.mu.RUnlock() + + if !ok || !hcfg.Enabled { + // default site behavior driven by settings + ds := "congratulations" + if settings := e.st.GetSettings(); settings != nil { + if s, ok := settings["default_site"].(string); ok && s != "" { + ds = s + } + } + switch ds { + case "404": + if data := www.LoadPage("404.html", map[string]string{ + "MESSAGE": fmt.Sprintf("No virtual host configured for %s.", host), + }); data != nil { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.WriteHeader(http.StatusNotFound) + w.Write(data) + return + } + w.WriteHeader(http.StatusNotFound) + w.Write([]byte("404 Not Found")) + return + case "444": + w.WriteHeader(444) // close like nginx + return + case "redirect": + tgt := "https://example.com" + if settings := e.st.GetSettings(); settings != nil { + if r, ok := settings["default_site_redirect"].(string); ok && r != "" { + tgt = r + } + } + http.Redirect(w, r, tgt, http.StatusFound) + return + default: // congratulations + if data := www.LoadPage("index.html", map[string]string{"HOST": host}); data != nil { + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(data) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + fmt.Fprintf(w, `

Welcome to Helix Proxy

No virtual host for %s. Use the admin UI on :81 to configure hosts.

`, host) + return + } + } + + slog.Debug("host matched", "host", host, "hasAccessClients", len(hcfg.AccessClients)) + + // Access list IP check (before other processing) + // Reuses getRealClientIP (defined below) with TrustForwardedProto gating to avoid dupe of XFF-trust logic (see also injection path at ~431). + if len(hcfg.AccessClients) > 0 { + clientIP := getRealClientIP(r, hcfg.TrustForwardedProto) + slog.Debug("access check", "host", host, "clients", len(hcfg.AccessClients), "satisfyAny", hcfg.AccessSatisfyAny, "ip", clientIP) + if !checkAccess(hcfg.AccessClients, hcfg.AccessSatisfyAny, clientIP) { + w.WriteHeader(http.StatusForbidden) + w.Write([]byte("access denied by access list")) + return + } + } + + // Basic auth if access list has items + if len(hcfg.AccessItems) > 0 { + authHeader := r.Header.Get("Authorization") + if authHeader == "" || !strings.HasPrefix(authHeader, "Basic ") { + w.Header().Set("WWW-Authenticate", `Basic realm="Authorization required"`) + w.WriteHeader(http.StatusUnauthorized) + return + } + payload, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(authHeader, "Basic ")) + if err != nil { + w.Header().Set("WWW-Authenticate", `Basic realm="Authorization required"`) + w.WriteHeader(http.StatusUnauthorized) + return + } + creds := strings.SplitN(string(payload), ":", 2) + if len(creds) != 2 { + w.Header().Set("WWW-Authenticate", `Basic realm="Authorization required"`) + w.WriteHeader(http.StatusUnauthorized) + return + } + user, pass := creds[0], creds[1] + authed := false + for _, item := range hcfg.AccessItems { + if item.Username == user && item.Password == pass { // demo: plain compare; real would hash + authed = true + break + } + } + if !authed { + w.Header().Set("WWW-Authenticate", `Basic realm="Authorization required"`) + w.WriteHeader(http.StatusUnauthorized) + return + } + // if not pass_auth, strip the header so backend doesn't see the creds + if !hcfg.AccessPassAuth { + r.Header.Del("Authorization") + } + } + + // Basic ssl_forced: if configured and request looks http, redirect to https + if hcfg.SslForced { + proto := r.Header.Get("X-Forwarded-Proto") + if proto == "http" || r.TLS == nil { + httpsURL := "https://" + r.Host + r.URL.RequestURI() + http.Redirect(w, r, httpsURL, http.StatusMovedPermanently) + return + } + } + + // Basic block_exploits + if hcfg.BlockExploits { + badPaths := []string{".env", "wp-admin", ".git/", "config.php", "phpinfo", "shell.php"} + for _, bad := range badPaths { + if strings.Contains(r.URL.Path, bad) { + w.WriteHeader(http.StatusForbidden) + w.Write([]byte("blocked by exploits rule")) + return + } + } + } + + // HSTS (set on responses for this vhost if enabled; typically observed on https) + if hcfg.HstsEnabled { + hsts := "max-age=31536000" + if hcfg.HstsSubdomains { + hsts += "; includeSubDomains" + } + w.Header().Set("Strict-Transport-Security", hsts) + } + + // Support custom locations (path prefix routing to different backends) + targetURL := hcfg.ForwardURL + reqPath := r.URL.Path + for _, loc := range hcfg.Locations { + if loc.Path != "" && strings.HasPrefix(reqPath, loc.Path) { + scheme := loc.ForwardScheme + if scheme == "" { + scheme = hcfg.ForwardScheme + if scheme == "" { + scheme = "http" + } + } + port := loc.ForwardPort + if port == 0 { + port = 80 + } + u := &url.URL{ + Scheme: scheme, + Host: net.JoinHostPort(loc.ForwardHost, strconv.Itoa(port)), + } + if loc.ForwardPath != "" { + // simple path rewrite (mutate request path only; target URL stays host-level + // so ReverseProxy joinURLPath does not duplicate the prefix) + rest := strings.TrimPrefix(reqPath, loc.Path) + r.URL.Path = loc.ForwardPath + rest + } + targetURL = u.String() + break + } + } + + // Websocket upgrade support (if enabled for this host) + if hcfg.AllowWebsocketUpgrade && isWebsocketRequest(r) { + r.Header.Set("Connection", "Upgrade") + r.Header.Set("Upgrade", "websocket") + // ReverseProxy will handle hijacking the conn for the upgrade + } + + // Compute real client info (respect trust-forwarded if configured) + clientIP := getRealClientIP(r, hcfg.TrustForwardedProto) + forwardedProto := "http" + if r.TLS != nil { + forwardedProto = "https" + } else if hcfg.TrustForwardedProto { + if p := r.Header.Get("X-Forwarded-Proto"); p != "" { + forwardedProto = strings.ToLower(strings.Split(p, ",")[0]) + } + } + + // Apply configured request/response header overrides. + for k, v := range hcfg.ReqHeaderSets { + r.Header.Set(k, v) + } + + target, _ := url.Parse(targetURL) + proxy := httputil.NewSingleHostReverseProxy(target) + + // Director to set X-Forwarded* and any request header overrides (after default director) + origDirector := proxy.Director + proxy.Director = func(req *http.Request) { + origDirector(req) + req.Header.Set("X-Forwarded-Host", r.Host) + req.Header.Set("X-Forwarded-Proto", forwardedProto) + req.Header.Set("X-Forwarded-For", clientIP) + req.Header.Set("X-Real-IP", clientIP) + for k, v := range hcfg.ReqHeaderSets { + req.Header.Set(k, v) + } + } + + // ModifyResponse to apply response header adds/hides + proxy.ModifyResponse = func(resp *http.Response) error { + for k, v := range hcfg.RespHeaderAdds { + resp.Header.Set(k, v) + } + for _, k := range hcfg.RespHeaderHides { + resp.Header.Del(k) + } + return nil + } + + // Basic caching support if enabled (for GET; simple in-mem with 1h TTL + HIT/MISS + no-store skip) + if hcfg.CachingEnabled && r.Method == "GET" { + key := host + r.URL.RequestURI() + e.cacheMu.Lock() + if c, ok := e.cache[key]; ok && time.Now().Before(c.expires) { + for k, vs := range c.headers { + for _, v := range vs { + w.Header().Add(k, v) + } + } + w.Header().Set("X-Proxy-Cache", "HIT") + status := c.status + if status == 0 { + status = 200 + } + w.WriteHeader(status) + w.Write(c.body) + e.cacheMu.Unlock() + return + } + e.cacheMu.Unlock() + + // capture response for cache (note: buffers full body in RAM; no size cap yet, see review) + rec := httptest.NewRecorder() + proxy.ServeHTTP(rec, r) + + // decide to cache: skip if no-store/private in resp + doCache := true + if cc := rec.Header().Get("Cache-Control"); cc != "" { + lcc := strings.ToLower(cc) + if strings.Contains(lcc, "no-store") || strings.Contains(lcc, "private") { + doCache = false + } + } + if doCache { + e.cacheMu.Lock() + e.cache[key] = struct { + body []byte + headers http.Header + status int + expires time.Time + }{ + body: rec.Body.Bytes(), + headers: rec.Header(), + status: rec.Code, + expires: time.Now().Add(1 * time.Hour), + } + e.cacheMu.Unlock() + } + // write to client (MISS only set for actual cacheable paths; omitted/BYPASS for no-store) + for k, vs := range rec.Header() { + for _, v := range vs { + w.Header().Add(k, v) + } + } + if doCache { + w.Header().Set("X-Proxy-Cache", "MISS") + } + w.WriteHeader(rec.Code) + w.Write(rec.Body.Bytes()) + return + } + + proxy.ServeHTTP(w, r) + }) +} + +// Start begins listening on the proxy ports (80/443 in real; for dev we can use high ports or require root). +// In production docker this will be able to bind because of how the image runs. +// Respects PROXY_HTTP_PORT env (e.g. 80 or 8080). +func (e *Engine) Start(ctx context.Context) error { + e.ReloadFromStore() + + port := "8080" + if p := os.Getenv("PROXY_HTTP_PORT"); p != "" { + port = p + } + addr := net.JoinHostPort("", port) + if os.Getenv("DISABLE_IPV6") == "1" { + addr = "0.0.0.0:" + port + } + + e.srv = &http.Server{ + Addr: addr, + Handler: e.Handler(), + } + + ln, err := net.Listen("tcp", e.srv.Addr) + if err != nil { + return err + } + slog.Info("pure-Go proxy HTTP listening (no nginx). Use PROXY_HTTP_PORT=80 (and privileges) or in docker for real low port", "addr", e.srv.Addr) + + go func() { + <-ctx.Done() + _ = e.srv.Shutdown(context.Background()) + _ = ln.Close() + }() + + e.started = true + return e.srv.Serve(ln) +} + +// StreamStatus is the live listener state for an enabled stream (not persisted). +type StreamStatus struct { + Listening bool `json:"listening"` + ListenError string `json:"listenError,omitempty"` +} + +type streamRuntime struct { + wantTCP bool + wantUDP bool + tcpOK bool + udpOK bool + tcpErr string + udpErr string + tcpDone bool + udpDone bool +} + +func (r *streamRuntime) status() StreamStatus { + if r.wantTCP && !r.tcpDone { + return StreamStatus{} + } + if r.wantUDP && !r.udpDone { + return StreamStatus{} + } + var errs []string + if r.wantTCP && !r.tcpOK && r.tcpErr != "" { + errs = append(errs, r.tcpErr) + } + if r.wantUDP && !r.udpOK && r.udpErr != "" { + errs = append(errs, r.udpErr) + } + if len(errs) > 0 { + return StreamStatus{ListenError: strings.Join(errs, "; ")} + } + return StreamStatus{Listening: r.wantTCP || r.wantUDP} +} + +func (e *Engine) StreamStatus(port int) StreamStatus { + e.streamRuntimeMu.RLock() + rt := e.streamRuntime[port] + e.streamRuntimeMu.RUnlock() + if rt == nil { + return StreamStatus{} + } + return rt.status() +} + +func (e *Engine) initStreamRuntime(s store.Stream) { + e.streamRuntimeMu.Lock() + defer e.streamRuntimeMu.Unlock() + e.streamRuntime[s.IncomingPort] = &streamRuntime{ + wantTCP: s.TCPForwarding, + wantUDP: s.UDPForwarding, + } +} + +func (e *Engine) markStreamTCPResult(port int, ok bool, err error) { + e.streamRuntimeMu.Lock() + defer e.streamRuntimeMu.Unlock() + rt := e.streamRuntime[port] + if rt == nil { + return + } + rt.tcpDone = true + rt.tcpOK = ok + if err != nil { + rt.tcpErr = err.Error() + } +} + +func (e *Engine) markStreamUDPResult(port int, ok bool, err error) { + e.streamRuntimeMu.Lock() + defer e.streamRuntimeMu.Unlock() + rt := e.streamRuntime[port] + if rt == nil { + return + } + rt.udpDone = true + rt.udpOK = ok + if err != nil { + rt.udpErr = err.Error() + } +} + +type streamHandle struct { + cancel context.CancelFunc + running store.Stream + tcpLn net.Listener + udpConn *net.UDPConn + wg sync.WaitGroup +} + +func streamListenerConfigEqual(a, b store.Stream) bool { + return a.IncomingPort == b.IncomingPort && + a.ForwardingHost == b.ForwardingHost && + a.ForwardingPort == b.ForwardingPort && + a.TCPForwarding == b.TCPForwarding && + a.UDPForwarding == b.UDPForwarding && + a.CertificateID == b.CertificateID +} + +func duplicateStreamListenPorts(streams map[int]store.Stream) map[int]string { + byPort := make(map[int]int, len(streams)) + errs := make(map[int]string) + for id, s := range streams { + if owner, ok := byPort[s.IncomingPort]; ok { + msg := fmt.Sprintf("incoming port %d already assigned to stream %d", s.IncomingPort, owner) + if _, has := errs[id]; !has { + errs[id] = msg + } + if _, has := errs[owner]; !has { + errs[owner] = fmt.Sprintf("incoming port %d conflict with stream %d", s.IncomingPort, id) + } + continue + } + byPort[s.IncomingPort] = id + } + return errs +} + +func (e *Engine) markStreamFailed(s store.Stream, err error) { + if s.TCPForwarding { + e.markStreamTCPResult(s.IncomingPort, false, err) + } + if s.UDPForwarding { + e.markStreamUDPResult(s.IncomingPort, false, err) + } +} + +func (e *Engine) streamPortHeldByOther(streamID, port int) (int, bool) { + e.streamMu.Lock() + defer e.streamMu.Unlock() + for id, h := range e.streamHandles { + if id != streamID && h.running.IncomingPort == port { + return id, true + } + } + return 0, false +} + +func (e *Engine) clearStreamRuntime(port int) { + e.streamRuntimeMu.Lock() + delete(e.streamRuntime, port) + e.streamRuntimeMu.Unlock() +} + +func (e *Engine) stopStreamByID(id int) { + e.streamMu.Lock() + h := e.streamHandles[id] + delete(e.streamHandles, id) + e.streamMu.Unlock() + if h == nil { + return + } + if h.tcpLn != nil { + _ = h.tcpLn.Close() + } + if h.udpConn != nil { + _ = h.udpConn.Close() + } + h.cancel() + h.wg.Wait() + e.clearStreamRuntime(h.running.IncomingPort) +} + +func (e *Engine) reloadStreams() { + all := e.st.GetStreams() + desired := make(map[int]store.Stream, len(all)) + for _, s := range all { + if s.Enabled && (s.TCPForwarding || s.UDPForwarding) { + desired[s.ID] = s + } + } + + e.streamMu.Lock() + running := make(map[int]*streamHandle, len(e.streamHandles)) + for id, h := range e.streamHandles { + running[id] = h + } + e.streamMu.Unlock() + + portConflicts := duplicateStreamListenPorts(desired) + for id, msg := range portConflicts { + s := desired[id] + e.initStreamRuntime(s) + e.markStreamFailed(s, fmt.Errorf("%s", msg)) + delete(desired, id) + slog.Error("stream port conflict", "streamID", id, "port", s.IncomingPort, "err", msg) + } + + stopIDs := make(map[int]struct{}) + for id, h := range running { + want, ok := desired[id] + if !ok || !streamListenerConfigEqual(want, h.running) { + stopIDs[id] = struct{}{} + } + } + + for id := range stopIDs { + e.stopStreamByID(id) + } + + for id, want := range desired { + e.streamMu.Lock() + h := e.streamHandles[id] + e.streamMu.Unlock() + if h != nil && streamListenerConfigEqual(want, h.running) { + continue + } + e.startStream(want) + } + + e.streamRuntimeMu.Lock() + activePorts := make(map[int]struct{}) + e.streamMu.Lock() + for _, h := range e.streamHandles { + activePorts[h.running.IncomingPort] = struct{}{} + } + e.streamMu.Unlock() + for port := range e.streamRuntime { + if _, ok := activePorts[port]; ok { + continue + } + keep := false + for _, s := range desired { + if s.IncomingPort == port { + keep = true + break + } + } + if !keep { + delete(e.streamRuntime, port) + } + } + e.streamRuntimeMu.Unlock() +} + +func (e *Engine) startStream(s store.Stream) { + if !s.TCPForwarding && !s.UDPForwarding { + return + } + ctx, cancel := context.WithCancel(context.Background()) + h := &streamHandle{cancel: cancel, running: s} + + e.streamMu.Lock() + e.streamHandles[s.ID] = h + e.streamMu.Unlock() + + e.initStreamRuntime(s) + + if holderID, held := e.streamPortHeldByOther(s.ID, s.IncomingPort); held { + err := fmt.Errorf("incoming port %d already used by stream %d", s.IncomingPort, holderID) + slog.Error("stream listen blocked", "streamID", s.ID, "port", s.IncomingPort, "holder", holderID) + e.markStreamFailed(s, err) + return + } + + if s.TCPForwarding { + listenAddr := ":" + itoa(s.IncomingPort) + if os.Getenv("DISABLE_IPV6") == "1" { + listenAddr = "0.0.0.0:" + itoa(s.IncomingPort) + } + if s.CertificateID > 0 { + cert := e.getStreamCert(s.CertificateID) + if cert == nil { + err := fmt.Errorf("no certificate for stream TLS (cert id %d)", s.CertificateID) + slog.Error("tcp stream tls listen failed", "port", s.IncomingPort, "err", err) + e.markStreamTCPResult(s.IncomingPort, false, err) + } else { + tlsCfg := &tls.Config{Certificates: []tls.Certificate{*cert}} + ln, err := tls.Listen("tcp", listenAddr, tlsCfg) + if err != nil { + slog.Error("tcp stream tls listen failed", "port", s.IncomingPort, "err", err) + e.markStreamTCPResult(s.IncomingPort, false, err) + } else { + h.tcpLn = ln + e.markStreamTCPResult(s.IncomingPort, true, nil) + h.wg.Add(1) + go func() { + defer h.wg.Done() + e.serveTCPStream(ctx, s, ln) + }() + } + } + } else { + ln, err := net.Listen("tcp", listenAddr) + if err != nil { + slog.Error("tcp stream listen failed", "port", s.IncomingPort, "err", err) + e.markStreamTCPResult(s.IncomingPort, false, err) + } else { + h.tcpLn = ln + e.markStreamTCPResult(s.IncomingPort, true, nil) + h.wg.Add(1) + go func() { + defer h.wg.Done() + e.serveTCPStream(ctx, s, ln) + }() + } + } + } + if s.UDPForwarding { + udpAddr := ":" + itoa(s.IncomingPort) + if os.Getenv("DISABLE_IPV6") == "1" { + udpAddr = "0.0.0.0:" + itoa(s.IncomingPort) + } + addr, _ := net.ResolveUDPAddr("udp", udpAddr) + conn, err := net.ListenUDP("udp", addr) + if err != nil { + slog.Error("udp stream listen failed", "port", s.IncomingPort, "err", err) + e.markStreamUDPResult(s.IncomingPort, false, err) + } else { + h.udpConn = conn + e.markStreamUDPResult(s.IncomingPort, true, nil) + h.wg.Add(1) + go func() { + defer h.wg.Done() + e.serveUDPStream(ctx, s, conn) + }() + } + } + st := e.StreamStatus(s.IncomingPort) + if st.Listening { + slog.Info("started stream listener", "port", s.IncomingPort, "tcp", s.TCPForwarding, "udp", s.UDPForwarding, "ssl", s.CertificateID > 0) + } else if st.ListenError != "" { + slog.Warn("stream listener failed to start", "port", s.IncomingPort, "tcp", s.TCPForwarding, "udp", s.UDPForwarding, "ssl", s.CertificateID > 0, "err", st.ListenError) + if h.tcpLn == nil && h.udpConn == nil { + e.streamMu.Lock() + delete(e.streamHandles, s.ID) + e.streamMu.Unlock() + h.cancel() + } + } +} + +func (e *Engine) serveTCPStream(ctx context.Context, s store.Stream, ln net.Listener) { + for { + conn, err := ln.Accept() + if err != nil { + if ctx.Err() != nil { + return + } + continue + } + go func(c net.Conn) { + defer c.Close() + target, err := net.Dial("tcp", net.JoinHostPort(s.ForwardingHost, itoa(s.ForwardingPort))) + if err != nil { + return + } + defer target.Close() + done := make(chan struct{}, 2) + go func() { io.Copy(target, c); done <- struct{}{} }() + go func() { io.Copy(c, target); done <- struct{}{} }() + <-done + }(conn) + } +} + +func (e *Engine) getStreamCert(id int) *tls.Certificate { + e.certMu.RLock() + defer e.certMu.RUnlock() + return e.certByID[id] +} + +func (e *Engine) serveUDPStream(ctx context.Context, s store.Stream, conn *net.UDPConn) { + buf := make([]byte, 65535) + for { + n, clientAddr, err := conn.ReadFromUDP(buf) + if err != nil { + if ctx.Err() != nil { + return + } + continue + } + go func(data []byte, caddr *net.UDPAddr) { + taddr, _ := net.ResolveUDPAddr("udp", net.JoinHostPort(s.ForwardingHost, itoa(s.ForwardingPort))) + tconn, err := net.DialUDP("udp", nil, taddr) + if err != nil { + return + } + defer tconn.Close() + tconn.Write(data) + tconn.SetReadDeadline(time.Now().Add(5 * time.Second)) + resp := make([]byte, 65535) + m, _, _ := tconn.ReadFromUDP(resp) + if m > 0 { + conn.WriteToUDP(resp[:m], caddr) + } + }(append([]byte{}, buf[:n]...), clientAddr) + } +} + +func (e *Engine) loadCerts() { + e.certMu.Lock() + defer e.certMu.Unlock() + e.hostCerts = make(map[string]*tls.Certificate) + e.certByID = make(map[int]*tls.Certificate) + + certs := e.st.GetCertificates() + certByID := map[int]store.Certificate{} + for _, c := range certs { + certByID[c.ID] = c + } + + for id, c := range certByID { + certPEM, _ := c.Meta["certificate"].(string) + if certPEM == "" { + certPEM, _ = c.Meta["cert"].(string) // compat our old + UI + } + keyPEM, _ := c.Meta["certificate_key"].(string) + if keyPEM == "" { + keyPEM, _ = c.Meta["key"].(string) + } + if certPEM != "" && keyPEM != "" { + tcert, err := tls.X509KeyPair([]byte(certPEM), []byte(keyPEM)) + if err == nil { + e.certByID[id] = &tcert + // also index by domains for http proxy hosts + for _, d := range c.DomainNames { + e.hostCerts[strings.ToLower(d)] = &tcert + } + } + } + } + + // legacy per-host for proxy (now covered above, but keep for compat) + // re-attaches using ph.CertificateID even if cert's DomainNames differ; supports hosts referencing cert by id only + proxyHosts := e.st.GetProxyHosts() + for _, ph := range proxyHosts { + if ph.CertificateID > 0 { + if tcert, ok := e.certByID[ph.CertificateID]; ok { + for _, d := range ph.DomainNames { + e.hostCerts[strings.ToLower(d)] = tcert + } + } + } + } +} + +func (e *Engine) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { + e.certMu.RLock() + defer e.certMu.RUnlock() + if cert, ok := e.hostCerts[hello.ServerName]; ok { + return cert, nil + } + // fallback to any + for _, c := range e.hostCerts { + return c, nil + } + return nil, fmt.Errorf("no certificate for %s", hello.ServerName) +} + +func (e *Engine) loadRedirs() { + e.redirMu.Lock() + defer e.redirMu.Unlock() + e.redirHosts = make(map[string]store.RedirectionHost) + + redirs := e.st.GetRedirectionHosts() + keys := []string{} + for _, rh := range redirs { + if rh.Enabled { + for _, d := range rh.DomainNames { + lower := strings.ToLower(d) + e.redirHosts[lower] = rh + keys = append(keys, lower) + } + } + } + slog.Info("loadRedirs done", "num", len(e.redirHosts), "keys", keys) +} + +func (e *Engine) loadDeads() { + e.deadMu.Lock() + defer e.deadMu.Unlock() + e.deadHosts = make(map[string]store.DeadHost) + + deads := e.st.GetDeadHosts() + keys := []string{} + for _, dh := range deads { + if dh.Enabled { + for _, d := range dh.DomainNames { + e.deadHosts[strings.ToLower(d)] = dh + keys = append(keys, d) + } + } + } + slog.Info("loadDeads done", "num", len(e.deadHosts), "keys", keys) +} + +func (e *Engine) TLSConfig() *tls.Config { + return &tls.Config{ + GetCertificate: e.GetCertificate, + } +} + +// TLS + streams: https listener (with SNI via GetCertificate) and dynamic stream mgmt +// (reload + per-port listeners/cancels) are implemented in cmd/helix-proxy/main.go +// (using eng.TLSConfig()/Handler() and reloadStreams on every ReloadFromStore). + +// checkAccess implements basic allow/deny from access list clients. +// satisfyAny means any allow is enough (after denies). +func checkAccess(clients []store.AccessClient, satisfyAny bool, ipStr string) bool { + if len(clients) == 0 { + return true + } + ip := ipStr + if h, _, err := net.SplitHostPort(ipStr); err == nil { + ip = h + } + parsed := net.ParseIP(ip) + if parsed == nil { + slog.Info("access check bad ip", "ip", ipStr) + return false + } + + hasAllow := false + for _, c := range clients { + addr := c.Address + if addr == "all" { + if c.Directive == "deny" { + slog.Info("access deny all", "ip", ipStr) + return false + } + hasAllow = true + continue + } + // try CIDR + if _, cidr, err := net.ParseCIDR(addr); err == nil { + if cidr.Contains(parsed) { + if c.Directive == "deny" { + slog.Info("access deny cidr", "ip", ipStr, "cidr", addr) + return false + } + hasAllow = true + } + continue + } + // exact IP + if net.ParseIP(addr).Equal(parsed) { + if c.Directive == "deny" { + slog.Info("access deny exact", "ip", ipStr, "addr", addr) + return false + } + hasAllow = true + } + } + + if satisfyAny { + slog.Info("access satisfyAny result", "ip", ipStr, "hasAllow", hasAllow) + return hasAllow + } + // satisfy all: if we didn't hit any deny, and there were allows or no rules, allow + slog.Info("access satisfyAll result", "ip", ipStr, "hasAllow", hasAllow) + return true +} + +// (no more config ref needed here) + +// --- helpers for new engine features (hsts/ws/headers/advanced) --- + +func isWebsocketRequest(r *http.Request) bool { + return strings.EqualFold(r.Header.Get("Upgrade"), "websocket") && + strings.Contains(strings.ToLower(r.Header.Get("Connection")), "upgrade") +} + +func getRealClientIP(r *http.Request, trustForwarded bool) string { + // X-Forwarded-For may be comma list; first is original client (when trusted) + // gated on host's TrustForwardedProto (also controls proto; used for IP trust per security review) + if trustForwarded { + if xf := r.Header.Get("X-Forwarded-For"); xf != "" { + parts := strings.Split(xf, ",") + return strings.TrimSpace(parts[0]) + } + } + ip := r.RemoteAddr + if h, _, err := net.SplitHostPort(ip); err == nil { + return h + } + return ip +} + +// resolveProxyHeaders returns header overrides from structured fields, falling back to legacy advancedConfig. +func resolveProxyHeaders(ph store.ProxyHost) (reqSets map[string]string, respAdds map[string]string, respHides []string) { + hasStructured := len(ph.RequestHeaders) > 0 || len(ph.ResponseHeaders) > 0 || len(ph.HideHeaders) > 0 + if hasStructured { + reqSets = map[string]string{} + for _, h := range ph.RequestHeaders { + name := strings.TrimSpace(h.Name) + if name != "" { + reqSets[name] = h.Value + } + } + respAdds = map[string]string{} + for _, h := range ph.ResponseHeaders { + name := strings.TrimSpace(h.Name) + if name != "" { + respAdds[name] = h.Value + } + } + for _, name := range ph.HideHeaders { + name = strings.TrimSpace(name) + if name != "" { + respHides = append(respHides, name) + } + } + return reqSets, respAdds, respHides + } + if ph.AdvancedConfig != "" { + return parseAdvancedConfig(ph.AdvancedConfig) + } + return map[string]string{}, map[string]string{}, nil +} + +// parseAdvancedConfig does a fuller (but still best-effort) parse of the advanced_config string +// (in the spirit of advanced config / snippets) to support common cases: +// - proxy_set_header Foo Bar +// - add_header X-Resp baz; +// - proxy_hide_header X-Foo +// - proxy_redirect (parsed, no-op for now as complex) +// - comments, ; or \n sep, set $var ignored. +// Returns maps for application via Director/ModifyResponse so headers survive proxy. +func parseAdvancedConfig(adv string) (reqSets map[string]string, respAdds map[string]string, respHides []string) { + reqSets = map[string]string{} + respAdds = map[string]string{} + respHides = []string{} + if adv == "" { + return + } + // normalize separators + adv = strings.ReplaceAll(adv, ";", "\n") + lines := strings.Split(adv, "\n") + for _, line := range lines { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + lower := strings.ToLower(line) + switch { + case strings.HasPrefix(lower, "proxy_set_header "): + // proxy_set_header X-Foo bar baz + parts := strings.Fields(line) + if len(parts) >= 3 { + name := parts[1] + val := strings.Join(parts[2:], " ") + reqSets[name] = val + } + case strings.HasPrefix(lower, "add_header "): + // add_header X-Response-Header "value" always; + parts := strings.Fields(line) + if len(parts) >= 3 { + name := parts[1] + // take until ; or end, strip quotes + val := strings.Join(parts[2:], " ") + val = strings.Trim(val, `"; `) + respAdds[name] = val + } + case strings.HasPrefix(lower, "proxy_hide_header "): + parts := strings.Fields(line) + if len(parts) >= 2 { + name := parts[1] + respHides = append(respHides, name) + } + case strings.HasPrefix(lower, "proxy_redirect "): + // best-effort: no-op here (would require Location rewrite in ModifyResponse for full) + default: + // ignore set $foo, etc. + } + } + return +} diff --git a/internal/proxy/engine_test.go b/internal/proxy/engine_test.go new file mode 100644 index 0000000..ae613f4 --- /dev/null +++ b/internal/proxy/engine_test.go @@ -0,0 +1,825 @@ +package proxy + +import ( + "bytes" + "crypto/tls" + "encoding/base64" + "net" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" + + "helix-proxy/internal/certificate" + "helix-proxy/internal/config" + "helix-proxy/internal/store" +) + +// --- pure helper tests (table driven as recommended) --- + +func TestItoa(t *testing.T) { + if itoa(80) != "80" || itoa(0) != "0" || itoa(443) != "443" { + t.Error("itoa wrong") + } +} + +func TestIsWebsocketRequest(t *testing.T) { + tests := []struct { + name string + h http.Header + want bool + }{ + {"none", http.Header{}, false}, + {"upgrade ws conn upgrade", http.Header{"Upgrade": []string{"websocket"}, "Connection": []string{"Upgrade"}}, true}, + {"case insen", http.Header{"Upgrade": []string{"WebSocket"}, "Connection": []string{"keep-alive, Upgrade"}}, true}, + {"no upgrade header", http.Header{"Connection": []string{"Upgrade"}}, false}, + {"no conn upgrade", http.Header{"Upgrade": []string{"websocket"}}, false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &http.Request{Header: tt.h} + if got := isWebsocketRequest(r); got != tt.want { + t.Errorf("isWebsocketRequest() = %v want %v", got, tt.want) + } + }) + } +} + +func TestGetRealClientIP(t *testing.T) { + tests := []struct { + name string + r *http.Request + trust bool + want string + }{ + {"xff first (trust)", &http.Request{Header: http.Header{"X-Forwarded-For": []string{"1.2.3.4, 5.6.7.8"}}, RemoteAddr: "9.9.9.9:1"}, true, "1.2.3.4"}, + {"xff ignored when !trust", &http.Request{Header: http.Header{"X-Forwarded-For": []string{"1.2.3.4, 5.6.7.8"}}, RemoteAddr: "9.9.9.9:1"}, false, "9.9.9.9"}, + {"no xff use remote", &http.Request{RemoteAddr: "10.0.0.1:1234"}, true, "10.0.0.1"}, + {"remote no port", &http.Request{RemoteAddr: "10.0.0.2"}, false, "10.0.0.2"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getRealClientIP(tt.r, tt.trust); got != tt.want { + t.Errorf("getRealClientIP() = %v want %v", got, tt.want) + } + }) + } +} + +func TestParseAdvancedConfig(t *testing.T) { + tests := []struct { + name string + adv string + wantSets map[string]string + wantAdds map[string]string + wantHides []string + }{ + {"empty", "", map[string]string{}, map[string]string{}, []string{}}, + {"comment and blank", "# foo\n\n ", map[string]string{}, map[string]string{}, []string{}}, + {"set_header", "proxy_set_header X-Foo bar baz", map[string]string{"X-Foo": "bar baz"}, map[string]string{}, []string{}}, + {"add_header quoted", `add_header X-Bar "val with space";`, map[string]string{}, map[string]string{"X-Bar": "val with space"}, []string{}}, + {"hide", "proxy_hide_header X-Baz\nproxy_hide_header X-Qux", map[string]string{}, map[string]string{}, []string{"X-Baz", "X-Qux"}}, + {"mixed sep ; and nl", "proxy_set_header A 1; add_header B 2; proxy_hide_header C", map[string]string{"A": "1"}, map[string]string{"B": "2"}, []string{"C"}}, + {"unknown ignored", "set $foo bar\nproxy_redirect / /", map[string]string{}, map[string]string{}, []string{}}, + {"trim quotes in add", `add_header X "v";`, map[string]string{}, map[string]string{"X": "v"}, []string{}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sets, adds, hides := parseAdvancedConfig(tt.adv) + if !mapsEqual(sets, tt.wantSets) { + t.Errorf("reqSets = %v want %v", sets, tt.wantSets) + } + if !mapsEqual(adds, tt.wantAdds) { + t.Errorf("respAdds = %v want %v", adds, tt.wantAdds) + } + if !slicesEqual(hides, tt.wantHides) { + t.Errorf("respHides = %v want %v", hides, tt.wantHides) + } + }) + } +} + +func TestResolveProxyHeaders(t *testing.T) { + structured := store.ProxyHost{ + RequestHeaders: []store.HeaderRule{{Name: "X-Req", Value: "1"}}, + ResponseHeaders: []store.HeaderRule{{Name: "X-Resp", Value: "2"}}, + HideHeaders: []string{"X-Hide"}, + } + sets, adds, hides := resolveProxyHeaders(structured) + if !mapsEqual(sets, map[string]string{"X-Req": "1"}) { + t.Errorf("structured reqSets = %v", sets) + } + if !mapsEqual(adds, map[string]string{"X-Resp": "2"}) { + t.Errorf("structured respAdds = %v", adds) + } + if !slicesEqual(hides, []string{"X-Hide"}) { + t.Errorf("structured respHides = %v", hides) + } + + legacy := store.ProxyHost{AdvancedConfig: "proxy_set_header A 1\nadd_header B 2;\nproxy_hide_header C"} + sets, adds, hides = resolveProxyHeaders(legacy) + if !mapsEqual(sets, map[string]string{"A": "1"}) || !mapsEqual(adds, map[string]string{"B": "2"}) || !slicesEqual(hides, []string{"C"}) { + t.Errorf("legacy fallback failed: sets=%v adds=%v hides=%v", sets, adds, hides) + } + + // structured fields take precedence over legacy advancedConfig + both := store.ProxyHost{ + RequestHeaders: []store.HeaderRule{{Name: "New", Value: "v"}}, + AdvancedConfig: "proxy_set_header Old 1", + } + sets, _, _ = resolveProxyHeaders(both) + if !mapsEqual(sets, map[string]string{"New": "v"}) { + t.Errorf("structured should win over legacy: %v", sets) + } +} + +func mapsEqual(a, b map[string]string) bool { + if len(a) != len(b) { + return false + } + for k, v := range a { + if b[k] != v { + return false + } + } + return true +} + +func slicesEqual(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} + +func TestCheckAccess(t *testing.T) { + tests := []struct { + name string + clients []store.AccessClient + satisfyAny bool + ip string + want bool + }{ + {"no clients allow", nil, false, "1.2.3.4", true}, + {"empty allow", []store.AccessClient{}, false, "1.2.3.4", true}, + {"deny all", []store.AccessClient{{Address: "all", Directive: "deny"}}, false, "9.9.9.9", false}, + {"allow all", []store.AccessClient{{Address: "all", Directive: "allow"}}, false, "1.1.1.1", true}, + {"exact allow", []store.AccessClient{{Address: "10.0.0.1", Directive: "allow"}}, false, "10.0.0.1:123", true}, + {"exact deny", []store.AccessClient{{Address: "10.0.0.1", Directive: "deny"}}, false, "10.0.0.1", false}, + {"cidr allow", []store.AccessClient{{Address: "192.168.0.0/16", Directive: "allow"}}, false, "192.168.1.2", true}, + {"cidr deny", []store.AccessClient{{Address: "192.168.0.0/16", Directive: "deny"}}, false, "192.168.1.2", false}, + {"satisfyAny: one allow sufficient", []store.AccessClient{{Address: "1.1.1.1", Directive: "allow"}, {Address: "2.2.2.2", Directive: "allow"}}, true, "1.1.1.1", true}, + {"satisfyAny: no allow", []store.AccessClient{{Address: "1.1.1.1", Directive: "deny"}}, true, "9.9.9.9", false}, + {"satisfy all (default): denies block even if allow present", []store.AccessClient{{Address: "1.1.1.1", Directive: "allow"}, {Address: "1.1.1.1", Directive: "deny"}}, false, "1.1.1.1", false}, + {"bad ip", []store.AccessClient{{Address: "all", Directive: "allow"}}, false, "not-an-ip", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := checkAccess(tt.clients, tt.satisfyAny, tt.ip) + if got != tt.want { + t.Errorf("checkAccess(%v, %v, %q) = %v want %v", tt.clients, tt.satisfyAny, tt.ip, got, tt.want) + } + }) + } +} + +func TestEngineReloadClearsCache(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + eng.cacheMu.Lock() + eng.cache["k"] = struct { + body []byte + headers http.Header + status int + expires time.Time + }{body: []byte("x")} + eng.cacheMu.Unlock() + + // use public ReloadFromStore (exercises the cache clear inside it) + eng.ReloadFromStore() + + eng.cacheMu.Lock() + if len(eng.cache) != 0 { + t.Error("reload did not clear cache") + } + eng.cacheMu.Unlock() +} + +// --- helpers for handler tests --- +func newTestEngine(t *testing.T) (*Engine, store.Store) { + t.Helper() + tmp := t.TempDir() + config.ResetForTest() + t.Setenv("DATA_DIR", tmp) + _ = config.EnsureDataDirs() + st, err := store.New() + if err != nil { + t.Fatalf("test store: %v", err) + } + eng := NewEngine(st) + eng.ReloadFromStore() + return eng, st +} + +func doReq(h http.Handler, method, host, path string, headers http.Header, body []byte) *httptest.ResponseRecorder { + req := httptest.NewRequest(method, path, bytes.NewReader(body)) + req.Host = host + if headers != nil { + req.Header = headers.Clone() + } + rr := httptest.NewRecorder() + h.ServeHTTP(rr, req) + return rr +} + +// TestEngineHandler_HostMatchingRedirsDeadsDefaults exercises core routing branches. +func TestEngineHandler_HostMatchingRedirsDeadsDefaults(t *testing.T) { + eng, st := newTestEngine(t) + defer func() { + if c, ok := st.(interface{ Close() error }); ok { + c.Close() + } + }() + + h := eng.Handler() + + // no hosts: default congratulations (or index if present) + rr := doReq(h, "GET", "nohost.local", "/", nil, nil) + if rr.Code != 200 || !strings.Contains(rr.Body.String(), "Welcome to Helix Proxy") { + t.Errorf("default congrats: code=%d body=%s", rr.Code, rr.Body.String()[:min(100, rr.Body.Len())]) + } + + // set default 404 + st.SetSetting("default_site", "404") + eng.ReloadFromStore() + rr = doReq(h, "GET", "nohost.local", "/", nil, nil) + if rr.Code != 404 { + t.Errorf("default 404: %d", rr.Code) + } + + // 444 + st.SetSetting("default_site", "444") + eng.ReloadFromStore() + rr = doReq(h, "GET", "nohost.local", "/", nil, nil) + if rr.Code != 444 { + t.Errorf("default 444: %d", rr.Code) + } + + // redirect default + st.SetSetting("default_site", "redirect") + st.SetSetting("default_site_redirect", "https://def.example") + eng.ReloadFromStore() + rr = doReq(h, "GET", "nohost.local", "/", nil, nil) + if rr.Code != 302 || !strings.Contains(rr.Header().Get("Location"), "def.example") { + t.Errorf("default redirect: %d %s", rr.Code, rr.Header().Get("Location")) + } + + // create a redir host + rh := store.RedirectionHost{ + DomainNames: []string{"redir.example"}, + ForwardHTTPCode: 301, + ForwardScheme: "https", + ForwardDomainName: "target.example", + PreservePath: true, + Enabled: true, + } + _, _ = st.CreateRedirectionHost(rh) + eng.ReloadFromStore() + rr = doReq(h, "GET", "redir.example", "/foo?x=1", nil, nil) + if rr.Code != 301 || !strings.Contains(rr.Header().Get("Location"), "https://target.example/foo?x=1") { + t.Errorf("redir preserve: %d loc=%s", rr.Code, rr.Header().Get("Location")) + } + + // dead host plain + dh := store.DeadHost{DomainNames: []string{"dead.example"}, Enabled: true} + _, _ = st.CreateDeadHost(dh) + eng.ReloadFromStore() + rr = doReq(h, "GET", "dead.example", "/", nil, nil) + if rr.Code != 404 || !strings.Contains(rr.Body.String(), "dead/blocked") { + t.Errorf("dead plain: %d %s", rr.Code, rr.Body.String()) + } + + // dead with meta.html + dh2 := store.DeadHost{DomainNames: []string{"deadhtml.example"}, Enabled: true, Meta: map[string]any{"html": "

custom dead

"}} + _, _ = st.CreateDeadHost(dh2) + eng.ReloadFromStore() + rr = doReq(h, "GET", "deadhtml.example", "/", nil, nil) + if rr.Code != 404 || !strings.Contains(rr.Body.String(), "custom dead") { + t.Errorf("dead meta html: %d %s", rr.Code, rr.Body.String()) + } + + // custom 404.html file fallback (not just meta) + wwwDir := config.Resolve("www") + _ = os.MkdirAll(wwwDir, 0o755) + _ = os.WriteFile(filepath.Join(wwwDir, "404.html"), []byte("

CUSTOM 404 FILE

"), 0o644) + dh3 := store.DeadHost{DomainNames: []string{"deadfile.example"}, Enabled: true} + _, _ = st.CreateDeadHost(dh3) + eng.ReloadFromStore() + rr = doReq(h, "GET", "deadfile.example", "/", nil, nil) + if rr.Code != 404 || !strings.Contains(rr.Body.String(), "CUSTOM 404 FILE") { + t.Errorf("dead custom 404.html: %d %s", rr.Code, rr.Body.String()) + } +} + +// TestEngineHandler_ProxyHostBasic + locations + ssl + block + hsts + ws + xforward +func TestEngineHandler_ProxyBasics(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + // create a simple proxy host (no backend will 502 but we can check early behaviors before proxy) + ph := store.ProxyHost{ + DomainNames: []string{"proxy.example"}, + ForwardScheme: "http", + ForwardHost: "127.0.0.1", + ForwardPort: 9, // invalid to not actually connect in test + Enabled: true, + SslForced: true, + BlockExploits: true, + HstsEnabled: true, + HstsSubdomains: true, + TrustForwardedProto: true, + RequestHeaders: []store.HeaderRule{{Name: "X-Custom", Value: "reqval"}}, + ResponseHeaders: []store.HeaderRule{{Name: "X-Resp", Value: "respval"}}, + HideHeaders: []string{"X-HideMe"}, + } + created, _ := st.CreateProxyHost(ph) + _ = created + eng.ReloadFromStore() + + h := eng.Handler() + + // ssl forced on plain + rr := doReq(h, "GET", "proxy.example", "/path", http.Header{"X-Forwarded-Proto": []string{"http"}}, nil) + if rr.Code != 301 || !strings.HasPrefix(rr.Header().Get("Location"), "https://") { + t.Errorf("ssl_forced: %d %s", rr.Code, rr.Header().Get("Location")) + } + + // block exploits - use TLS set on req to bypass ssl_forced redirect (which is before block check) + req := httptest.NewRequest("GET", "/.env", nil) + req.Host = "proxy.example" + req.TLS = &tls.ConnectionState{} // simulate https so no ssl redirect + rr = httptest.NewRecorder() + h.ServeHTTP(rr, req) + if rr.Code != 403 || !strings.Contains(rr.Body.String(), "exploits") { + t.Errorf("block_exploits: %d %s", rr.Code, rr.Body.String()) + } + + // HSTS set on response (simulate https to reach hsts code) + req = httptest.NewRequest("GET", "/ok", nil) + req.Host = "proxy.example" + req.TLS = &tls.ConnectionState{} + rr = httptest.NewRecorder() + h.ServeHTTP(rr, req) + if hs := rr.Header().Get("Strict-Transport-Security"); !strings.Contains(hs, "includeSubDomains") { + t.Errorf("hsts not set or missing sub: %q", hs) + } + + // X-Forwarded injection happens in director, but since we hit error backend we may not see, test via other means later + // for now check advanced req set happens early? but applied in director too. +} + +// Test locations forwardPath rewrite +func TestEngineHandler_Locations(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + ph := store.ProxyHost{ + DomainNames: []string{"loc.example"}, + ForwardScheme: "http", + ForwardHost: "127.0.0.1", + ForwardPort: 80, + Enabled: true, + Locations: []store.Location{ + {Path: "/api", ForwardScheme: "http", ForwardHost: "backend", ForwardPort: 9000, ForwardPath: "/v2"}, + }, + } + _, _ = st.CreateProxyHost(ph) + eng.ReloadFromStore() + + h := eng.Handler() + // we can't easily assert the rewritten without real backend or spying, but at least no panic and host match + rr := doReq(h, "GET", "loc.example", "/api/foo", nil, nil) + // expect 502 from revproxy to bad host, but routing happened + if rr.Code == 404 { + t.Error("location host not matched, got 404 default") + } +} + +// Test access lists IP + basic auth + passauth +func TestEngineHandler_AccessLists(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + al := store.AccessList{ + Name: "acl1", + SatisfyAny: false, + Clients: []store.AccessClient{{Address: "10.0.0.0/8", Directive: "allow"}, {Address: "1.2.3.4", Directive: "deny"}}, + Items: []store.AccessItem{{Username: "user", Password: "pass"}}, + PassAuth: false, + } + alCreated, _ := st.CreateAccessList(al) + + ph := store.ProxyHost{ + DomainNames: []string{"acl.example"}, + ForwardHost: "127.0.0.1", + ForwardPort: 80, + Enabled: true, + AccessListID: alCreated.ID, + TrustForwardedProto: true, // enable XFF for spoof tests in access list (default false would ignore XFF) + } + _, _ = st.CreateProxyHost(ph) + + // ph with default TrustForwardedProto=false for testing XFF spoof ignored in access + clientIP + phNoTrust := store.ProxyHost{ + DomainNames: []string{"acl-notrust.example"}, + ForwardHost: "127.0.0.1", + ForwardPort: 80, + Enabled: true, + AccessListID: alCreated.ID, + // TrustForwardedProto: false (default) => XFF ignored, use RemoteAddr for access decisions/injection + } + _, _ = st.CreateProxyHost(phNoTrust) + eng.ReloadFromStore() + + h := eng.Handler() + + // deny via explicit deny client (note: 11.x would be allowed under !satisfyAny if no deny hit; use the deny addr) + rr := doReq(h, "GET", "acl.example", "/", http.Header{"X-Forwarded-For": []string{"1.2.3.4"}}, nil) + if rr.Code != 403 { + t.Errorf("access deny exact: %d", rr.Code) + } + + // trust=false + spoof XFF (deny addr): should ignore XFF (use Remote which doesn't match deny) => no 403, reaches auth + rr = doReq(h, "GET", "acl-notrust.example", "/", http.Header{"X-Forwarded-For": []string{"1.2.3.4"}}, nil) + if rr.Code != 401 { + t.Errorf("TrustForwardedProto=false should ignore XFF spoof (reaches auth 401); got %d", rr.Code) + } + + // allow by cidr via xff + rr = doReq(h, "GET", "acl.example", "/", http.Header{"X-Forwarded-For": []string{"10.1.2.3"}}, nil) + // will 401 because basic auth required next + if rr.Code != 401 { + t.Errorf("access allow but no auth expected 401: %d", rr.Code) + } + + // basic auth fail + rr = doReq(h, "GET", "acl.example", "/", http.Header{ + "X-Forwarded-For": []string{"10.1.2.3"}, + "Authorization": []string{"Basic " + basic("bad", "bad")}, + }, nil) + if rr.Code != 401 { + t.Errorf("basic bad: %d", rr.Code) + } + + // basic good, passauth false so stripped + rr = doReq(h, "GET", "acl.example", "/", http.Header{ + "X-Forwarded-For": []string{"10.1.2.3"}, + "Authorization": []string{"Basic " + basic("user", "pass")}, + }, nil) + if rr.Code == 401 { + t.Error("basic good should not 401") + } + // (502 later ok) +} + +func basic(u, p string) string { + return base64.StdEncoding.EncodeToString([]byte(u + ":" + p)) +} + +func TestEngineHandler_Caching(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + upstream := NewWhoami(t, WhoamiConfig{ + DefaultHeaders: map[string]string{ + "Cache-Control": "max-age=3600", + "X-Upstream": "yes", + }, + Routes: map[string]WhoamiRoute{ + "/cpath": {Body: "CACHED-BODY-FOR-/cpath"}, + }, + }) + _, _ = st.CreateProxyHost(store.ProxyHost{ + DomainNames: []string{"cache.example"}, + ForwardScheme: "http", + ForwardHost: upstream.Hostname, + ForwardPort: upstream.Port, + Enabled: true, + CachingEnabled: true, + }) + eng.ReloadFromStore() + h := eng.Handler() + + rr1 := doReq(h, "GET", "cache.example", "/cpath", nil, nil) + if rr1.Code != 200 || !strings.Contains(rr1.Body.String(), "CACHED-BODY") || rr1.Header().Get("X-Proxy-Cache") != "MISS" { + t.Errorf("first MISS: code=%d cache=%s body=%s", rr1.Code, rr1.Header().Get("X-Proxy-Cache"), rr1.Body.String()) + } + + rr2 := doReq(h, "GET", "cache.example", "/cpath", nil, nil) + if rr2.Header().Get("X-Proxy-Cache") != "HIT" || rr2.Body.String() != rr1.Body.String() { + t.Errorf("second HIT: cache=%s body=%s", rr2.Header().Get("X-Proxy-Cache"), rr2.Body.String()) + } + + noStore := NewWhoami(t, WhoamiConfig{ + DefaultHeaders: map[string]string{"Cache-Control": "no-store"}, + Routes: map[string]WhoamiRoute{"/p": {Body: "NO-STORE-BODY"}}, + }) + _, _ = st.CreateProxyHost(store.ProxyHost{ + DomainNames: []string{"cache-nostore.example"}, + ForwardScheme: "http", + ForwardHost: noStore.Hostname, + ForwardPort: noStore.Port, + Enabled: true, + CachingEnabled: true, + }) + eng.ReloadFromStore() + h = eng.Handler() + + rr3 := doReq(h, "GET", "cache-nostore.example", "/p", nil, nil) + if rr3.Header().Get("X-Proxy-Cache") != "" { + t.Error("no-store should not set X-Proxy-Cache") + } + rr4 := doReq(h, "GET", "cache-nostore.example", "/p", nil, nil) + if rr4.Header().Get("X-Proxy-Cache") == "HIT" { + t.Error("no-store response should not have been cached for HIT") + } + + eng.ReloadFromStore() +} + +// Test X-Forwarded* injection (respects trust), ws header munging via whoami upstream. +func TestEngineHandler_ForwardedAndWS(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + up := NewWhoami(t, WhoamiConfig{}) + _, _ = st.CreateProxyHost(store.ProxyHost{ + DomainNames: []string{"fwd.example"}, + ForwardScheme: "http", + ForwardHost: up.Hostname, + ForwardPort: up.Port, + Enabled: true, + TrustForwardedProto: true, + AllowWebsocketUpgrade: true, + }) + eng.ReloadFromStore() + h := eng.Handler() + + hdrs := http.Header{ + "X-Forwarded-For": []string{"10.9.8.7"}, + "X-Forwarded-Proto": []string{"https"}, + "Connection": []string{"Upgrade"}, + "Upgrade": []string{"websocket"}, + } + rr := doReq(h, "GET", "fwd.example", "/ws", hdrs, nil) + if rr.Code != 200 { + t.Fatalf("forwarded/ws proxy: code=%d", rr.Code) + } + got, ok := up.LastRequest() + if !ok { + t.Fatal("upstream saw no request") + } + if !strings.Contains(got.HeaderValue("X-Forwarded-For"), "10.9.8.7") || got.HeaderValue("X-Forwarded-Proto") != "https" { + t.Errorf("X-Forwarded* injection: ff=%s proto=%s", got.HeaderValue("X-Forwarded-For"), got.HeaderValue("X-Forwarded-Proto")) + } + if got.HeaderValue("Connection") != "Upgrade" || got.HeaderValue("Upgrade") != "websocket" { + t.Errorf("ws munging: conn=%s up=%s", got.HeaderValue("Connection"), got.HeaderValue("Upgrade")) + } +} + +// Test ACME challenge serving (before host) +func TestEngineHandler_ACME(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + h := eng.Handler() + + chDir := config.Resolve("letsencrypt-acme-challenge") + acmeFileDir := filepath.Join(chDir, ".well-known", "acme-challenge") + _ = os.MkdirAll(acmeFileDir, 0o755) + token := "testtoken123" + content := "challenge-content-xyz" + if err := os.WriteFile(filepath.Join(acmeFileDir, token), []byte(content), 0o644); err != nil { + t.Fatal(err) + } + + rr := doReq(h, "GET", "anyhost", "/.well-known/acme-challenge/"+token, nil, nil) + if rr.Code != 200 || rr.Body.String() != content { + t.Errorf("acme serve: code=%d body=%q", rr.Code, rr.Body.String()) + } + + rr = doReq(h, "GET", "anyhost", "/.well-known/acme-challenge/missing", nil, nil) + if rr.Code != 404 { + t.Errorf("acme missing: %d", rr.Code) + } +} + +// Test loadCerts / GetCertificate (SNI, compat keys) +func TestEngine_LoadCertsGetCertificate(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + // create via cert manager's test path (dev mode makes *all* LE certs self-signed test certs) + config.ResetForTest() + t.Setenv("DATA_DIR", config.DataDir()) // already set in newTest + t.Setenv("PROXY_MODE", "development") + cm := certificate.NewManager(st) + certRec := store.Certificate{ + Provider: "letsencrypt", + DomainNames: []string{"sni.example"}, + Meta: map[string]any{}, + } + created, _ := st.CreateCertificate(certRec) + email := cm.GetEmailForCert(created) + if err := cm.Issue(created, email); err != nil { + t.Fatalf("issue test cert for load: %v", err) + } + // now attach to host + ph := store.ProxyHost{ + DomainNames: []string{"sni.example"}, + ForwardHost: "127.0.0.1", + ForwardPort: 80, + Enabled: true, + CertificateID: created.ID, + } + _, _ = st.CreateProxyHost(ph) + + eng.ReloadFromStore() + + // loadCerts called in reload; should succeed with real PEMs + cert, err := eng.GetCertificate(&tls.ClientHelloInfo{ServerName: "sni.example"}) + if err != nil { + t.Fatalf("GetCertificate: %v", err) + } + if cert == nil { + t.Error("nil cert") + } + // fallback any (there is one now) + _, _ = eng.GetCertificate(&tls.ClientHelloInfo{ServerName: "unknown"}) +} + +// Test streams reload (at least lifecycle no panic) +func TestEngine_StreamsReload(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + strm := store.Stream{ + IncomingPort: 0, // use high? but test may bind fail; use invalid port to just test start path without real listen success + ForwardingHost: "127.0.0.1", + ForwardingPort: 9, + TCPForwarding: true, + Enabled: true, + } + // port 0 not good; pick a likely free high port for test? but to avoid bind in CI, just create disabled first + strm.IncomingPort = 19999 + (int(time.Now().UnixNano()) % 1000) // somewhat unique + _, _ = st.CreateStream(strm) + eng.ReloadFromStore() + runtime := eng.StreamStatus(strm.IncomingPort) + if !runtime.Listening { + t.Fatalf("expected stream listening on port %d: %+v", strm.IncomingPort, runtime) + } + // now disable and reload to exercise cancel path + strm.Enabled = false + _, _ = st.UpdateStream(strm) + eng.ReloadFromStore() + // ok if no crash +} + +func TestEngine_StreamListenFailure(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + port := 19800 + (int(time.Now().UnixNano()) % 1000) + ln, err := net.Listen("tcp", net.JoinHostPort("127.0.0.1", strconv.Itoa(port))) + if err != nil { + t.Fatalf("bind probe port: %v", err) + } + defer ln.Close() + + strm := store.Stream{ + IncomingPort: port, + ForwardingHost: "127.0.0.1", + ForwardingPort: 9, + TCPForwarding: true, + Enabled: true, + } + _, _ = st.CreateStream(strm) + eng.ReloadFromStore() + + runtime := eng.StreamStatus(port) + if runtime.Listening { + t.Fatal("expected stream not listening when port is taken") + } + if runtime.ListenError == "" { + t.Fatal("expected listen error when port is taken") + } +} + +func TestEngine_StreamReloadSamePort(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + port := 19700 + (int(time.Now().UnixNano()) % 1000) + strm := store.Stream{ + IncomingPort: port, + ForwardingHost: "127.0.0.1", + ForwardingPort: 9, + TCPForwarding: true, + Enabled: true, + } + created, _ := st.CreateStream(strm) + eng.ReloadFromStore() + + runtime := eng.StreamStatus(port) + if !runtime.Listening { + t.Fatalf("expected stream listening after initial reload: %+v", runtime) + } + + created.ForwardingPort = 10 + _, _ = st.UpdateStream(created) + eng.ReloadFromStore() + + runtime = eng.StreamStatus(port) + if !runtime.Listening { + t.Fatalf("expected stream still listening after edit reload on same port: %+v", runtime) + } +} + +func TestEngine_StreamReloadLeavesOthersRunning(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + base := 19600 + (int(time.Now().UnixNano()) % 1000) + portA := base + portB := base + 1 + + a, _ := st.CreateStream(store.Stream{ + IncomingPort: portA, ForwardingHost: "127.0.0.1", ForwardingPort: 9, + TCPForwarding: true, Enabled: true, + }) + b, _ := st.CreateStream(store.Stream{ + IncomingPort: portB, ForwardingHost: "127.0.0.1", ForwardingPort: 9, + TCPForwarding: true, Enabled: true, + }) + eng.ReloadFromStore() + + if st := eng.StreamStatus(portA); !st.Listening { + t.Fatalf("stream A not listening: %+v", st) + } + if st := eng.StreamStatus(portB); !st.Listening { + t.Fatalf("stream B not listening: %+v", st) + } + + a.ForwardingPort = 10 + _, _ = st.UpdateStream(a) + eng.ReloadFromStore() + + if st := eng.StreamStatus(portA); !st.Listening { + t.Fatalf("stream A not listening after edit: %+v", st) + } + if st := eng.StreamStatus(portB); !st.Listening { + t.Fatalf("stream B should still be listening after editing A: %+v", st) + } + _ = b +} + +func TestDuplicateStreamListenPorts(t *testing.T) { + desired := map[int]store.Stream{ + 1: {ID: 1, IncomingPort: 9000, TCPForwarding: true}, + 2: {ID: 2, IncomingPort: 9000, TCPForwarding: true}, + 3: {ID: 3, IncomingPort: 9001, TCPForwarding: true}, + } + conflicts := duplicateStreamListenPorts(desired) + if len(conflicts) != 2 { + t.Fatalf("expected 2 conflicts, got %d: %v", len(conflicts), conflicts) + } + if conflicts[1] == "" || conflicts[2] == "" { + t.Fatalf("expected errors for streams 1 and 2, got %v", conflicts) + } + if _, ok := conflicts[3]; ok { + t.Fatalf("stream 3 should not conflict: %v", conflicts) + } +} + +func closeStore(s store.Store) { + if c, ok := s.(interface{ Close() error }); ok { + c.Close() + } +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} diff --git a/internal/proxy/integration_test.go b/internal/proxy/integration_test.go new file mode 100644 index 0000000..b3b9553 --- /dev/null +++ b/internal/proxy/integration_test.go @@ -0,0 +1,546 @@ +package proxy + +import ( + "crypto/tls" + "encoding/json" + "io" + "net" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "helix-proxy/internal/certificate" + "helix-proxy/internal/config" + "helix-proxy/internal/store" + + "golang.org/x/net/websocket" +) + +// TestEngine_Integration_FullSetup wires proxy hosts, redirections, dead hosts, +// access lists, certificates, locations, and streams against configurable whoami upstreams. +func TestEngine_Integration_FullSetup(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + // --- upstream mocks --- + mainUpstream := NewWhoami(t, WhoamiConfig{ + Routes: map[string]WhoamiRoute{ + "/health": {Status: 200, Body: `{"status":"ok"}`, Headers: map[string]string{"X-Secret": "hidden"}}, + }, + }) + apiUpstream := NewWhoami(t, WhoamiConfig{ + ValidPrefixes: []string{"/v2"}, + }) + authUpstream := NewWhoami(t, WhoamiConfig{}) + tcpEcho := NewTCPEcho(t, "STREAM-OK\n") + + certRec := issueDevCert(t, st, "secure.example", "stream.example") + + // --- access list --- + al, _ := st.CreateAccessList(store.AccessList{ + Name: "integration-acl", + SatisfyAny: false, + Clients: []store.AccessClient{{Address: "all", Directive: "allow"}}, + Items: []store.AccessItem{{Username: "testuser", Password: "secret"}}, + PassAuth: false, + }) + + // --- proxy host: headers, location rewrite, access, cert --- + _, _ = st.CreateProxyHost(store.ProxyHost{ + DomainNames: []string{"proxy-int.example"}, + ForwardScheme: "http", + ForwardHost: mainUpstream.Hostname, + ForwardPort: mainUpstream.Port, + CertificateID: certRec.ID, + AccessListID: al.ID, + TrustForwardedProto: true, + RequestHeaders: []store.HeaderRule{{Name: "X-Injected-Req", Value: "yes"}}, + ResponseHeaders: []store.HeaderRule{{Name: "X-Injected-Resp", Value: "yes"}}, + HideHeaders: []string{"X-Secret"}, + Enabled: true, + Locations: []store.Location{{ + Path: "/api", + ForwardScheme: "http", + ForwardHost: apiUpstream.Hostname, + ForwardPort: apiUpstream.Port, + ForwardPath: "/v2", + }}, + }) + + // proxy with passAuth=true to verify Authorization reaches upstream + alPass, _ := st.CreateAccessList(store.AccessList{ + Name: "pass-auth-acl", + Clients: []store.AccessClient{{Address: "all", Directive: "allow"}}, + Items: []store.AccessItem{{Username: "u", Password: "p"}}, + PassAuth: true, + }) + _, _ = st.CreateProxyHost(store.ProxyHost{ + DomainNames: []string{"passauth.example"}, + ForwardScheme: "http", + ForwardHost: authUpstream.Hostname, + ForwardPort: authUpstream.Port, + AccessListID: alPass.ID, + Enabled: true, + }) + + // --- redirection host --- + _, _ = st.CreateRedirectionHost(store.RedirectionHost{ + DomainNames: []string{"redir-int.example"}, + ForwardHTTPCode: 302, + ForwardScheme: "https", + ForwardDomainName: "target-int.example", + PreservePath: true, + Enabled: true, + }) + + // --- dead hosts --- + _, _ = st.CreateDeadHost(store.DeadHost{ + DomainNames: []string{"dead-int.example"}, + Enabled: true, + Meta: map[string]any{"html": "

integration dead

"}, + }) + wwwDir := config.Resolve("www") + _ = os.MkdirAll(wwwDir, 0o755) + _ = os.WriteFile(filepath.Join(wwwDir, "404.html"), []byte("

INTEGRATION 404 FILE

"), 0o644) + _, _ = st.CreateDeadHost(store.DeadHost{DomainNames: []string{"deadfile-int.example"}, Enabled: true}) + + // --- default site modes --- + _ = st.SetSetting("default_site", "404") + + // --- stream (TCP) --- + t.Setenv("DISABLE_IPV6", "1") + streamPort := pickFreePort(t) + _, _ = st.CreateStream(store.Stream{ + IncomingPort: streamPort, + ForwardingHost: tcpEcho.Host, + ForwardingPort: tcpEcho.Port, + TCPForwarding: true, + Enabled: true, + }) + cleanupStreams(t, eng, st) + + eng.ReloadFromStore() + h := eng.Handler() + + // --- redirection --- + rr := doReq(h, "GET", "redir-int.example", "/foo?bar=1", nil, nil) + if rr.Code != 302 || !strings.Contains(rr.Header().Get("Location"), "https://target-int.example/foo?bar=1") { + t.Errorf("redirection: code=%d loc=%q", rr.Code, rr.Header().Get("Location")) + } + + // --- dead hosts --- + rr = doReq(h, "GET", "dead-int.example", "/", nil, nil) + if rr.Code != 404 || !strings.Contains(rr.Body.String(), "integration dead") { + t.Errorf("dead meta: code=%d body=%q", rr.Code, rr.Body.String()) + } + rr = doReq(h, "GET", "deadfile-int.example", "/", nil, nil) + if rr.Code != 404 || !strings.Contains(rr.Body.String(), "INTEGRATION 404 FILE") { + t.Errorf("dead file: code=%d body=%q", rr.Code, rr.Body.String()) + } + + // --- default 404 --- + rr = doReq(h, "GET", "unknown-int.example", "/", nil, nil) + if rr.Code != 404 { + t.Errorf("default 404: %d", rr.Code) + } + + // --- certificate SNI --- + cert, err := eng.GetCertificate(&tls.ClientHelloInfo{ServerName: "secure.example"}) + if err != nil || cert == nil { + t.Errorf("GetCertificate secure.example: err=%v cert=%v", err, cert) + } + + // --- proxy: main path with auth + injected headers --- + authHdr := http.Header{ + "Authorization": []string{"Basic " + basic("testuser", "secret")}, + "X-Forwarded-For": []string{"10.0.0.5"}, + "X-Forwarded-Proto": []string{"https"}, + } + rr = doReq(h, "GET", "proxy-int.example", "/health", authHdr, nil) + if rr.Code != 200 { + t.Fatalf("proxy /health: code=%d body=%s", rr.Code, rr.Body.String()) + } + if rr.Header().Get("X-Injected-Resp") != "yes" { + t.Error("response header injection missing") + } + if rr.Header().Get("X-Secret") != "" { + t.Error("hide header failed: X-Secret leaked") + } + if got, ok := mainUpstream.LastRequest(); !ok { + t.Fatal("main upstream saw no request") + } else { + if got.Path != "/health" { + t.Errorf("main path: got %q want /health", got.Path) + } + if got.HeaderValue("X-Injected-Req") != "yes" { + t.Errorf("request header injection: got %q", got.HeaderValue("X-Injected-Req")) + } + if got.HeaderValue("Authorization") != "" { + t.Error("passAuth=false should strip Authorization before upstream") + } + if got.HeaderValue("X-Forwarded-Proto") != "https" { + t.Errorf("X-Forwarded-Proto: got %q", got.HeaderValue("X-Forwarded-Proto")) + } + } + + // --- location path rewrite --- + apiUpstream.ClearRequests() + rr = doReq(h, "GET", "proxy-int.example", "/api/foo", authHdr, nil) + if rr.Code != 200 { + t.Fatalf("location /api/foo: code=%d", rr.Code) + } + got, ok := apiUpstream.LastRequest() + if !ok { + t.Fatal("api upstream saw no request for location") + } + if got.Path != "/v2/foo" { + t.Errorf("location rewrite: upstream path=%q want /v2/foo", got.Path) + } + if rr.Header().Get("X-Whoami-Path") != "/v2/foo" { + t.Errorf("X-Whoami-Path header: %q", rr.Header().Get("X-Whoami-Path")) + } + + // --- passAuth=true keeps Authorization --- + authUpstream.ClearRequests() + rr = doReq(h, "GET", "passauth.example", "/", http.Header{ + "Authorization": []string{"Basic " + basic("u", "p")}, + }, nil) + if rr.Code != 200 { + t.Fatalf("passauth proxy: code=%d", rr.Code) + } + got, ok = authUpstream.LastRequest() + if !ok { + t.Fatal("auth upstream saw no request") + } + if got.HeaderValue("Authorization") == "" { + t.Error("passAuth=true should forward Authorization to upstream") + } + + // --- whoami JSON echo on default route --- + mainUpstream.ClearRequests() + rr = doReq(h, "GET", "proxy-int.example", "/echo-test?q=1", authHdr, nil) + if rr.Code != 200 { + t.Fatalf("echo route: code=%d", rr.Code) + } + var echoed WhoamiRequest + if err := json.Unmarshal(rr.Body.Bytes(), &echoed); err != nil { + t.Fatalf("parse whoami json: %v body=%s", err, rr.Body.String()) + } + if echoed.Path != "/echo-test" || echoed.Query != "q=1" { + t.Errorf("whoami json echo: path=%q query=%q", echoed.Path, echoed.Query) + } + + // --- stream TCP forwarding --- + waitForTCP(t, net.JoinHostPort("127.0.0.1", itoa(streamPort)), 5*time.Second) + conn, err := net.DialTimeout("tcp", net.JoinHostPort("127.0.0.1", itoa(streamPort)), 2*time.Second) + if err != nil { + t.Fatalf("dial stream port %d: %v", streamPort, err) + } + defer conn.Close() + _ = conn.SetDeadline(time.Now().Add(2 * time.Second)) + if _, err := io.WriteString(conn, "ping\n"); err != nil { + t.Fatalf("stream write: %v", err) + } + buf := make([]byte, 64) + n, err := conn.Read(buf) + if err != nil { + t.Fatalf("stream read: %v", err) + } + if !strings.Contains(string(buf[:n]), "STREAM-OK") { + t.Errorf("stream echo: got %q", string(buf[:n])) + } + + // reload lifecycle: cleanupStreams t.Cleanup also exercises disable path + strms := st.GetStreams() + if len(strms) == 0 { + t.Fatal("no streams in store") + } +} + +// TestEngine_Integration_Websocket verifies end-to-end websocket upgrade and message echo. +func TestEngine_Integration_Websocket(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + wsUp := NewWhoamiWS(t, "/ws") + _, _ = st.CreateProxyHost(store.ProxyHost{ + DomainNames: []string{"ws-int.example"}, + ForwardScheme: "http", + ForwardHost: wsUp.Hostname, + ForwardPort: wsUp.Port, + Enabled: true, + AllowWebsocketUpgrade: true, + TrustForwardedProto: true, + }) + eng.ReloadFromStore() + + proxy := newProxyServer(t, eng) + ws := dialWhoamiWS(t, proxy.URL, "ws-int.example", "/ws", http.Header{ + "X-Forwarded-For": []string{"10.9.8.7"}, + "X-Forwarded-Proto": []string{"https"}, + }) + + if err := websocket.Message.Send(ws, "hello"); err != nil { + t.Fatalf("ws send: %v", err) + } + var reply string + if err := websocket.Message.Receive(ws, &reply); err != nil { + t.Fatalf("ws recv: %v", err) + } + if reply != "echo:hello" { + t.Errorf("ws echo: got %q", reply) + } + + got, ok := wsUp.UpgradeRequest() + if !ok { + t.Fatal("upstream missed websocket upgrade request") + } + if got.Path != "/ws" { + t.Errorf("upgrade path: %q", got.Path) + } + if !strings.Contains(got.HeaderValue("X-Forwarded-For"), "10.9.8.7") { + t.Errorf("upgrade X-Forwarded-For: %q", got.HeaderValue("X-Forwarded-For")) + } + if got.HeaderValue("X-Forwarded-Proto") != "https" { + t.Errorf("upgrade X-Forwarded-Proto: %q", got.HeaderValue("X-Forwarded-Proto")) + } + if got.HeaderValue("Connection") != "Upgrade" || got.HeaderValue("Upgrade") != "websocket" { + t.Errorf("upgrade headers: conn=%q up=%q", got.HeaderValue("Connection"), got.HeaderValue("Upgrade")) + } + msgs := wsUp.Messages() + if len(msgs) != 1 || msgs[0] != "hello" { + t.Errorf("upstream messages: %v", msgs) + } +} + +// TestEngine_Integration_Caching exercises cache HIT/MISS through whoami upstreams. +func TestEngine_Integration_Caching(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + upstream := NewWhoami(t, WhoamiConfig{ + DefaultHeaders: map[string]string{"Cache-Control": "max-age=3600"}, + Routes: map[string]WhoamiRoute{ + "/asset": {Body: "CACHED-ASSET"}, + }, + }) + _, _ = st.CreateProxyHost(store.ProxyHost{ + DomainNames: []string{"cache-int.example"}, + ForwardScheme: "http", + ForwardHost: upstream.Hostname, + ForwardPort: upstream.Port, + Enabled: true, + CachingEnabled: true, + }) + eng.ReloadFromStore() + h := eng.Handler() + + rr1 := doReq(h, "GET", "cache-int.example", "/asset", nil, nil) + if rr1.Code != 200 || rr1.Header().Get("X-Proxy-Cache") != "MISS" || rr1.Body.String() != "CACHED-ASSET" { + t.Fatalf("cache MISS: code=%d cache=%s body=%q", rr1.Code, rr1.Header().Get("X-Proxy-Cache"), rr1.Body.String()) + } + if reqs := upstream.Requests(); len(reqs) != 1 { + t.Fatalf("upstream requests after MISS: %d", len(reqs)) + } + + rr2 := doReq(h, "GET", "cache-int.example", "/asset", nil, nil) + if rr2.Header().Get("X-Proxy-Cache") != "HIT" || rr2.Body.String() != "CACHED-ASSET" { + t.Errorf("cache HIT: cache=%s body=%q", rr2.Header().Get("X-Proxy-Cache"), rr2.Body.String()) + } + if reqs := upstream.Requests(); len(reqs) != 1 { + t.Errorf("upstream should not be hit again on HIT; requests=%d", len(reqs)) + } +} + +// TestEngine_Integration_ProxyMiddleware exercises ssl_forced, block_exploits, and HSTS +// against a real whoami upstream. +func TestEngine_Integration_ProxyMiddleware(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + + upstream := NewWhoami(t, WhoamiConfig{}) + _, _ = st.CreateProxyHost(store.ProxyHost{ + DomainNames: []string{"middleware.example"}, + ForwardScheme: "http", + ForwardHost: upstream.Hostname, + ForwardPort: upstream.Port, + Enabled: true, + SslForced: true, + BlockExploits: true, + HstsEnabled: true, + HstsSubdomains: true, + TrustForwardedProto: true, + }) + eng.ReloadFromStore() + h := eng.Handler() + + // ssl_forced redirects plain http + rr := doReq(h, "GET", "middleware.example", "/ok", http.Header{ + "X-Forwarded-Proto": []string{"http"}, + }, nil) + if rr.Code != 301 || !strings.HasPrefix(rr.Header().Get("Location"), "https://") { + t.Errorf("ssl_forced: code=%d loc=%q", rr.Code, rr.Header().Get("Location")) + } + + // block_exploits on https path + req := httptest.NewRequest("GET", "/.env", nil) + req.Host = "middleware.example" + req.TLS = &tls.ConnectionState{} + rr = httptest.NewRecorder() + h.ServeHTTP(rr, req) + if rr.Code != 403 || !strings.Contains(rr.Body.String(), "exploits") { + t.Errorf("block_exploits: code=%d body=%q", rr.Code, rr.Body.String()) + } + + // HSTS + successful whoami proxy on https + req = httptest.NewRequest("GET", "/ok", nil) + req.Host = "middleware.example" + req.TLS = &tls.ConnectionState{} + rr = httptest.NewRecorder() + h.ServeHTTP(rr, req) + if rr.Code != 200 { + t.Fatalf("proxy ok: code=%d body=%s", rr.Code, rr.Body.String()) + } + if hs := rr.Header().Get("Strict-Transport-Security"); !strings.Contains(hs, "includeSubDomains") { + t.Errorf("hsts: %q", hs) + } + got, ok := upstream.LastRequest() + if !ok || got.Path != "/ok" { + t.Errorf("upstream path: got=%v ok=%v", got.Path, ok) + } +} + +// issueDevCert creates and issues a self-signed certificate in development mode. +func issueDevCert(t *testing.T, st store.Store, domains ...string) store.Certificate { + t.Helper() + t.Setenv("PROXY_MODE", "development") + cm := certificate.NewManager(st) + rec, _ := st.CreateCertificate(store.Certificate{ + Provider: "letsencrypt", + DomainNames: domains, + Meta: map[string]any{}, + }) + if err := cm.Issue(rec, cm.GetEmailForCert(rec)); err != nil { + t.Fatalf("issue cert: %v", err) + } + rec, _ = st.GetCertificate(rec.ID) + return rec +} + +// TestEngine_Integration_TLSStream verifies TLS-terminated TCP stream forwarding. +func TestEngine_Integration_TLSStream(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + t.Setenv("DISABLE_IPV6", "1") + + certRec := issueDevCert(t, st, "stream-tls.example") + tcpEcho := NewTCPEcho(t, "STREAM-TLS-OK\n") + streamPort := 20000 + int(time.Now().UnixNano()%10000) + + _, _ = st.CreateStream(store.Stream{ + IncomingPort: streamPort, + ForwardingHost: tcpEcho.Host, + ForwardingPort: tcpEcho.Port, + TCPForwarding: true, + Enabled: true, + CertificateID: certRec.ID, + }) + cleanupStreams(t, eng, st) + eng.ReloadFromStore() + + if eng.getStreamCert(certRec.ID) == nil { + t.Fatalf("stream cert %d not loaded after reload", certRec.ID) + } + + trust, err := eng.GetCertificate(&tls.ClientHelloInfo{ServerName: "stream-tls.example"}) + if err != nil { + t.Fatalf("GetCertificate: %v", err) + } + + addr := net.JoinHostPort("127.0.0.1", itoa(streamPort)) + var waitErr error + for attempt := 0; attempt < 3; attempt++ { + waitErr = tryWaitForTLSStream(addr, "stream-tls.example", trust, 2*time.Second) + if waitErr == nil { + break + } + eng.ReloadFromStore() + } + if waitErr != nil { + t.Fatalf("tls stream listener on %s: %v", addr, waitErr) + } + + conn := DialTLSStream(t, addr, "stream-tls.example", trust) + if _, err := io.WriteString(conn, "ping\n"); err != nil { + t.Fatalf("tls stream write: %v", err) + } + got := ReadStreamGreeting(t, conn, 64, 2*time.Second) + if !strings.Contains(got, "STREAM-TLS-OK") { + t.Errorf("tls stream echo: got %q", got) + } + + // plain TCP to a TLS listener should fail handshake quickly + raw, err := net.DialTimeout("tcp", addr, time.Second) + if err != nil { + t.Fatalf("raw dial: %v", err) + } + defer raw.Close() + _ = raw.SetDeadline(time.Now().Add(time.Second)) + if _, err := io.WriteString(raw, "not-tls\n"); err != nil { + t.Fatalf("raw write: %v", err) + } + buf := make([]byte, 16) + if _, err := raw.Read(buf); err == nil { + t.Error("expected plain TCP to TLS stream to fail read, got data") + } +} + +// TestEngine_Integration_UDPStream verifies UDP stream forwarding. +func TestEngine_Integration_UDPStream(t *testing.T) { + eng, st := newTestEngine(t) + defer closeStore(st) + t.Setenv("DISABLE_IPV6", "1") // bind 0.0.0.0 so 127.0.0.1 dials reach the listener + + udpEcho := NewUDPEcho(t, "UDP-STREAM-OK\n") + streamPort := pickFreePort(t) + + _, _ = st.CreateStream(store.Stream{ + IncomingPort: streamPort, + ForwardingHost: udpEcho.Host, + ForwardingPort: udpEcho.Port, + UDPForwarding: true, + Enabled: true, + }) + cleanupStreams(t, eng, st) + eng.ReloadFromStore() + + addr := net.JoinHostPort("127.0.0.1", itoa(streamPort)) + waitForUDP(t, addr, 2*time.Second) + + target, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + t.Fatalf("resolve stream udp: %v", err) + } + conn, err := net.DialUDP("udp", nil, target) + if err != nil { + t.Fatalf("dial stream udp: %v", err) + } + defer conn.Close() + _ = conn.SetDeadline(time.Now().Add(2 * time.Second)) + + if _, err := conn.Write([]byte("probe")); err != nil { + t.Fatalf("udp write: %v", err) + } + buf := make([]byte, 64) + n, err := conn.Read(buf) + if err != nil { + t.Fatalf("udp read: %v", err) + } + if !strings.Contains(string(buf[:n]), "UDP-STREAM-OK") { + t.Errorf("udp stream echo: got %q", string(buf[:n])) + } +} diff --git a/internal/proxy/whoami_test.go b/internal/proxy/whoami_test.go new file mode 100644 index 0000000..60db90d --- /dev/null +++ b/internal/proxy/whoami_test.go @@ -0,0 +1,618 @@ +package proxy + +import ( + "crypto/tls" + "crypto/x509" + "encoding/json" + "io" + "net" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "strings" + "sync" + "testing" + "time" + + "helix-proxy/internal/store" + + "golang.org/x/net/websocket" +) + +// WhoamiRequest captures what the upstream mock received. +type WhoamiRequest struct { + Method string `json:"method"` + Path string `json:"path"` + Query string `json:"query,omitempty"` + Host string `json:"host"` + Headers map[string][]string `json:"headers"` + Body string `json:"body,omitempty"` + RemoteAddr string `json:"remoteAddr"` +} + +// WhoamiRoute configures a response for a specific path (and optionally method). +type WhoamiRoute struct { + Method string + Status int + Body string + Headers map[string]string +} + +// WhoamiConfig configures whoami upstream behavior. +type WhoamiConfig struct { + DefaultStatus int + DefaultBody string + DefaultHeaders map[string]string + Routes map[string]WhoamiRoute // key: path or "METHOD path" + ValidPaths []string // exact paths allowed; empty = all + ValidPrefixes []string // path prefixes allowed (checked after ValidPaths) +} + +// WhoamiServer is a test upstream that records requests and returns configurable responses. +type WhoamiServer struct { + Server *httptest.Server + Hostname string + Port int + + cfg WhoamiConfig + + mu sync.Mutex + requests []WhoamiRequest +} + +// NewWhoami starts a whoami upstream and registers cleanup on t. +func NewWhoami(t *testing.T, cfg WhoamiConfig) *WhoamiServer { + t.Helper() + if cfg.DefaultStatus == 0 { + cfg.DefaultStatus = http.StatusOK + } + w := &WhoamiServer{cfg: cfg} + w.Server = httptest.NewServer(http.HandlerFunc(w.serve)) + t.Cleanup(w.Server.Close) + + u, err := url.Parse(w.Server.URL) + if err != nil { + t.Fatalf("whoami url: %v", err) + } + w.Hostname = u.Hostname() + w.Port, err = strconv.Atoi(u.Port()) + if err != nil { + t.Fatalf("whoami port: %v", err) + } + return w +} + +func (w *WhoamiServer) serve(rw http.ResponseWriter, r *http.Request) { + body, _ := io.ReadAll(r.Body) + _ = r.Body.Close() + + req := WhoamiRequest{ + Method: r.Method, + Path: r.URL.Path, + Query: r.URL.RawQuery, + Host: r.Host, + Headers: cloneHeaderMap(r.Header), + Body: string(body), + RemoteAddr: r.RemoteAddr, + } + + w.mu.Lock() + w.requests = append(w.requests, req) + w.mu.Unlock() + + if !w.pathAllowed(r.URL.Path) { + http.Error(rw, "whoami: path not allowed", http.StatusNotFound) + return + } + + route, ok := w.matchRoute(r.Method, r.URL.Path) + status := w.cfg.DefaultStatus + respBody := w.cfg.DefaultBody + respHeaders := map[string]string{} + for k, v := range w.cfg.DefaultHeaders { + respHeaders[k] = v + } + + if ok { + if route.Status != 0 { + status = route.Status + } + if route.Body != "" { + respBody = route.Body + } + for k, v := range route.Headers { + respHeaders[k] = v + } + } + + // If no custom body, echo the captured request as JSON (whoami-style). + if respBody == "" { + b, err := json.Marshal(req) + if err != nil { + http.Error(rw, "whoami: marshal", http.StatusInternalServerError) + return + } + respBody = string(b) + } + + rw.Header().Set("Content-Type", "application/json") + rw.Header().Set("X-Whoami-Method", req.Method) + rw.Header().Set("X-Whoami-Path", req.Path) + rw.Header().Set("X-Whoami-Host", req.Host) + rw.Header().Set("X-Whoami-Query", req.Query) + for name, vals := range req.Headers { + rw.Header().Set("X-Whoami-H-"+name, strings.Join(vals, ", ")) + } + for k, v := range respHeaders { + rw.Header().Set(k, v) + } + rw.WriteHeader(status) + _, _ = io.WriteString(rw, respBody) +} + +func (w *WhoamiServer) pathAllowed(path string) bool { + if len(w.cfg.ValidPaths) == 0 && len(w.cfg.ValidPrefixes) == 0 { + return true + } + for _, p := range w.cfg.ValidPaths { + if path == p { + return true + } + } + for _, p := range w.cfg.ValidPrefixes { + if strings.HasPrefix(path, p) { + return true + } + } + return false +} + +func (w *WhoamiServer) matchRoute(method, path string) (WhoamiRoute, bool) { + if len(w.cfg.Routes) == 0 { + return WhoamiRoute{}, false + } + key := strings.ToUpper(method) + " " + path + if r, ok := w.cfg.Routes[key]; ok { + return r, true + } + if r, ok := w.cfg.Routes[path]; ok { + return r, true + } + return WhoamiRoute{}, false +} + +// Requests returns a copy of all recorded upstream requests. +func (w *WhoamiServer) Requests() []WhoamiRequest { + w.mu.Lock() + defer w.mu.Unlock() + out := make([]WhoamiRequest, len(w.requests)) + copy(out, w.requests) + return out +} + +// LastRequest returns the most recent upstream request, if any. +func (w *WhoamiServer) LastRequest() (WhoamiRequest, bool) { + w.mu.Lock() + defer w.mu.Unlock() + if len(w.requests) == 0 { + return WhoamiRequest{}, false + } + return w.requests[len(w.requests)-1], true +} + +// ClearRequests resets the recorded request history. +func (w *WhoamiServer) ClearRequests() { + w.mu.Lock() + defer w.mu.Unlock() + w.requests = nil +} + +// ParseWhoamiBody decodes a JSON whoami echo body from a proxied response. +func ParseWhoamiBody(body []byte) (WhoamiRequest, error) { + var req WhoamiRequest + err := json.Unmarshal(body, &req) + return req, err +} + +// HeaderValue returns the first value for a header name (case-insensitive). +func (r WhoamiRequest) HeaderValue(name string) string { + for k, vs := range r.Headers { + if strings.EqualFold(k, name) && len(vs) > 0 { + return vs[0] + } + } + return "" +} + +func cloneHeaderMap(h http.Header) map[string][]string { + out := make(map[string][]string, len(h)) + for k, vs := range h { + cp := make([]string, len(vs)) + copy(cp, vs) + out[k] = cp + } + return out +} + +// TCPEchoServer accepts connections and echoes a fixed greeting. +type TCPEchoServer struct { + Listener net.Listener + Host string + Port int + Greeting string +} + +// NewTCPEcho starts a TCP server that writes Greeting on each accepted connection. +func NewTCPEcho(t *testing.T, greeting string) *TCPEchoServer { + t.Helper() + if greeting == "" { + greeting = "STREAM-ECHO\n" + } + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("tcp echo listen: %v", err) + } + _, portStr, _ := net.SplitHostPort(ln.Addr().String()) + port, _ := strconv.Atoi(portStr) + s := &TCPEchoServer{Listener: ln, Host: "127.0.0.1", Port: port, Greeting: greeting} + + go func() { + for { + conn, err := ln.Accept() + if err != nil { + return + } + go func(c net.Conn) { + defer c.Close() + _, _ = io.WriteString(c, s.Greeting) + }(conn) + } + }() + + t.Cleanup(func() { _ = ln.Close() }) + return s +} + +// pickFreePort returns a likely-free TCP port on 127.0.0.1. +func pickFreePort(t *testing.T) int { + t.Helper() + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("pick port: %v", err) + } + _, portStr, _ := net.SplitHostPort(ln.Addr().String()) + _ = ln.Close() + port, _ := strconv.Atoi(portStr) + return port +} + +// UDPEchoServer responds to each datagram with a fixed payload. +type UDPEchoServer struct { + Conn *net.UDPConn + Host string + Port int + Response []byte +} + +// NewUDPEcho starts a UDP server that writes Response for every datagram received. +func NewUDPEcho(t *testing.T, response string) *UDPEchoServer { + t.Helper() + if response == "" { + response = "UDP-ECHO\n" + } + addr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0") + if err != nil { + t.Fatalf("udp resolve: %v", err) + } + conn, err := net.ListenUDP("udp", addr) + if err != nil { + t.Fatalf("udp listen: %v", err) + } + _, portStr, _ := net.SplitHostPort(conn.LocalAddr().String()) + port, _ := strconv.Atoi(portStr) + s := &UDPEchoServer{ + Conn: conn, + Host: "127.0.0.1", + Port: port, + Response: []byte(response), + } + + go func() { + buf := make([]byte, 4096) + for { + n, client, err := conn.ReadFromUDP(buf) + if err != nil { + return + } + _, _ = conn.WriteToUDP(s.Response, client) + _ = n + } + }() + + t.Cleanup(func() { _ = conn.Close() }) + return s +} + +// tryWaitForTLSStream returns nil once a TLS stream listener accepts connections. +func tryWaitForTLSStream(addr, serverName string, trust *tls.Certificate, timeout time.Duration) error { + deadline := time.Now().Add(timeout) + var lastErr error + pool := x509.NewCertPool() + if len(trust.Certificate) > 0 { + if leaf, err := x509.ParseCertificate(trust.Certificate[0]); err == nil { + pool.AddCert(leaf) + } + } + cfg := &tls.Config{ServerName: serverName, RootCAs: pool, MinVersion: tls.VersionTLS12} + for time.Now().Before(deadline) { + conn, err := tls.DialWithDialer(&net.Dialer{Timeout: 200 * time.Millisecond}, "tcp", addr, cfg) + if err == nil { + _ = conn.Close() + return nil + } + lastErr = err + time.Sleep(20 * time.Millisecond) + } + return lastErr +} + +// waitForTLSStream dials addr with TLS until success or timeout. +func waitForTLSStream(t *testing.T, addr, serverName string, trust *tls.Certificate, timeout time.Duration) { + t.Helper() + if err := tryWaitForTLSStream(addr, serverName, trust, timeout); err != nil { + t.Fatalf("wait for tls stream %s: %v", addr, err) + } +} + +// tryWaitForTCP returns nil once a TCP listener accepts connections. +func tryWaitForTCP(addr string, timeout time.Duration) error { + deadline := time.Now().Add(timeout) + var lastErr error + for time.Now().Before(deadline) { + conn, err := net.DialTimeout("tcp", addr, 200*time.Millisecond) + if err == nil { + _ = conn.Close() + return nil + } + lastErr = err + time.Sleep(20 * time.Millisecond) + } + return lastErr +} + +// waitForTCP dials addr until success or timeout (stream listeners start async). +func waitForTCP(t *testing.T, addr string, timeout time.Duration) { + t.Helper() + if err := tryWaitForTCP(addr, timeout); err != nil { + t.Fatalf("wait for tcp %s: %v", addr, err) + } +} + +// tlsConfigForCert builds a client TLS config that trusts the given server certificate. +func tlsConfigForCert(t *testing.T, serverName string, cert *tls.Certificate) *tls.Config { + t.Helper() + if len(cert.Certificate) == 0 { + t.Fatal("tls cert has no certificate chain") + } + pool := x509.NewCertPool() + if !pool.AppendCertsFromPEM(cert.Certificate[0]) { + // X509KeyPair stores DER; re-parse for the pool + leaf, err := x509.ParseCertificate(cert.Certificate[0]) + if err != nil { + t.Fatalf("parse leaf cert: %v", err) + } + pool.AddCert(leaf) + } + return &tls.Config{ + ServerName: serverName, + RootCAs: pool, + MinVersion: tls.VersionTLS12, + } +} + +// DialTLSStream connects to a TLS-terminated stream listener. +func DialTLSStream(t *testing.T, addr, serverName string, trust *tls.Certificate) net.Conn { + t.Helper() + var cfg *tls.Config + if trust != nil { + cfg = tlsConfigForCert(t, serverName, trust) + } else { + cfg = &tls.Config{ + ServerName: serverName, + InsecureSkipVerify: true, //nolint:gosec // test-only self-signed dev certs + MinVersion: tls.VersionTLS12, + } + } + conn, err := tls.DialWithDialer(&net.Dialer{Timeout: 2 * time.Second}, "tcp", addr, cfg) + if err != nil { + t.Fatalf("tls dial %s: %v", addr, err) + } + t.Cleanup(func() { _ = conn.Close() }) + return conn +} + +// waitForUDP sends a probe datagram until a response arrives or timeout. +func waitForUDP(t *testing.T, addr string, timeout time.Duration) { + t.Helper() + deadline := time.Now().Add(timeout) + target, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + t.Fatalf("resolve udp %s: %v", addr, err) + } + var lastErr error + for time.Now().Before(deadline) { + conn, err := net.DialUDP("udp", nil, target) + if err != nil { + lastErr = err + time.Sleep(20 * time.Millisecond) + continue + } + _ = conn.SetDeadline(time.Now().Add(200 * time.Millisecond)) + if _, err := conn.Write([]byte("probe")); err != nil { + lastErr = err + _ = conn.Close() + time.Sleep(20 * time.Millisecond) + continue + } + buf := make([]byte, 8) + _, err = conn.Read(buf) + _ = conn.Close() + if err == nil { + return + } + lastErr = err + time.Sleep(20 * time.Millisecond) + } + t.Fatalf("wait for udp %s: %v", addr, lastErr) +} + +// WhoamiWSServer is a websocket upstream that records the upgrade request and echoes messages. +type WhoamiWSServer struct { + Server *httptest.Server + Hostname string + Port int + Path string + + mu sync.Mutex + upgradeReq WhoamiRequest + messages []string +} + +// NewWhoamiWS starts a websocket echo upstream on path (default /ws). +func NewWhoamiWS(t *testing.T, path string) *WhoamiWSServer { + t.Helper() + if path == "" { + path = "/ws" + } + w := &WhoamiWSServer{Path: path} + mux := http.NewServeMux() + mux.Handle(path, websocket.Handler(w.handleWS)) + w.Server = httptest.NewServer(mux) + t.Cleanup(w.Server.Close) + + u, err := url.Parse(w.Server.URL) + if err != nil { + t.Fatalf("whoami ws url: %v", err) + } + w.Hostname = u.Hostname() + w.Port, err = strconv.Atoi(u.Port()) + if err != nil { + t.Fatalf("whoami ws port: %v", err) + } + return w +} + +func (w *WhoamiWSServer) handleWS(ws *websocket.Conn) { + req := ws.Request() + body, _ := io.ReadAll(req.Body) + _ = req.Body.Close() + captured := WhoamiRequest{ + Method: req.Method, + Path: req.URL.Path, + Query: req.URL.RawQuery, + Host: req.Host, + Headers: cloneHeaderMap(req.Header), + Body: string(body), + RemoteAddr: req.RemoteAddr, + } + w.mu.Lock() + w.upgradeReq = captured + w.mu.Unlock() + + for { + var msg string + if err := websocket.Message.Receive(ws, &msg); err != nil { + return + } + w.mu.Lock() + w.messages = append(w.messages, msg) + w.mu.Unlock() + if err := websocket.Message.Send(ws, "echo:"+msg); err != nil { + return + } + } +} + +// UpgradeRequest returns the HTTP request observed at websocket upgrade time. +func (w *WhoamiWSServer) UpgradeRequest() (WhoamiRequest, bool) { + w.mu.Lock() + defer w.mu.Unlock() + if w.upgradeReq.Method == "" { + return WhoamiRequest{}, false + } + return w.upgradeReq, true +} + +// Messages returns client messages received after upgrade. +func (w *WhoamiWSServer) Messages() []string { + w.mu.Lock() + defer w.mu.Unlock() + out := make([]string, len(w.messages)) + copy(out, w.messages) + return out +} + +// cleanupStreams disables all streams and reloads the engine on test end. +func cleanupStreams(t *testing.T, eng *Engine, st store.Store) { + t.Helper() + t.Cleanup(func() { + for _, s := range st.GetStreams() { + if !s.Enabled { + continue + } + s.Enabled = false + _, _ = st.UpdateStream(s) + } + eng.ReloadFromStore() + }) +} + +// newProxyServer exposes eng.Handler() on an httptest server (needed for websocket hijack). +func newProxyServer(t *testing.T, eng *Engine) *httptest.Server { + t.Helper() + srv := httptest.NewServer(eng.Handler()) + t.Cleanup(srv.Close) + return srv +} + +// dialWhoamiWS connects through a proxy front to the websocket upstream path. +// The vhost is embedded in the handshake URL (Host header); TCP dials proxyURL directly. +func dialWhoamiWS(t *testing.T, proxyURL, vhost, wsPath string, hdrs http.Header) *websocket.Conn { + t.Helper() + proxyU, err := url.Parse(proxyURL) + if err != nil { + t.Fatalf("proxy url: %v", err) + } + wsURL := "ws://" + vhost + wsPath + cfg, err := websocket.NewConfig(wsURL, "http://"+vhost+"/") + if err != nil { + t.Fatalf("ws config: %v", err) + } + if hdrs != nil { + cfg.Header = hdrs.Clone() + } + conn, err := net.DialTimeout("tcp", proxyU.Host, 2*time.Second) + if err != nil { + t.Fatalf("tcp dial %s: %v", proxyU.Host, err) + } + ws, err := websocket.NewClient(cfg, conn) + if err != nil { + _ = conn.Close() + t.Fatalf("ws handshake %s via %s: %v", wsURL, proxyU.Host, err) + } + t.Cleanup(func() { _ = ws.Close() }) + return ws +} + +// ReadStreamGreeting reads up to n bytes from conn before deadline. +func ReadStreamGreeting(t *testing.T, conn net.Conn, n int, timeout time.Duration) string { + t.Helper() + _ = conn.SetReadDeadline(time.Now().Add(timeout)) + buf := make([]byte, n) + got, err := io.ReadAtLeast(conn, buf, 1) + if err != nil { + t.Fatalf("stream read: %v", err) + } + return string(buf[:got]) +} diff --git a/internal/store/bbolt.go b/internal/store/bbolt.go new file mode 100644 index 0000000..f3626be --- /dev/null +++ b/internal/store/bbolt.go @@ -0,0 +1,854 @@ +package store + +import ( + "encoding/binary" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "time" + + "helix-proxy/internal/config" + "helix-proxy/internal/models" + + "go.etcd.io/bbolt" +) + +const ( + bucketProxyHosts = "proxy_hosts" + bucketAccessLists = "access_lists" + bucketStreams = "streams" + bucketCertificates = "certificates" + bucketRedirectionHosts = "redirection_hosts" + bucketDeadHosts = "dead_hosts" + bucketUsers = "users" + bucketAuditLogs = "audit_logs" + bucketSettings = "settings" + bucketMeta = "meta" +) + +type bboltStore struct { + db *bbolt.DB + path string +} + +// NewBboltStore opens (or creates) the bbolt embedded database at the standard +// location (data/db.bolt by default, overridable via DATA_DIR etc). +func NewBboltStore() (Store, error) { + p := config.Resolve("db.bolt") + if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil { + return nil, err + } + + db, err := bbolt.Open(p, 0o600, &bbolt.Options{Timeout: 0}) + if err != nil { + return nil, fmt.Errorf("open bbolt db: %w", err) + } + + s := &bboltStore{db: db, path: p} + + // Ensure all buckets exist + if err := s.createBuckets(); err != nil { + db.Close() + return nil, err + } + + // First-run seed (admin user + default settings) if nothing exists + if !s.hasAnyUsers() { + if err := s.seedDefaults(); err != nil { + db.Close() + return nil, err + } + } + + return s, nil +} + +func (s *bboltStore) Close() error { + if s.db != nil { + return s.db.Close() + } + return nil +} + +func (s *bboltStore) createBuckets() error { + return s.db.Update(func(tx *bbolt.Tx) error { + buckets := []string{ + bucketProxyHosts, bucketAccessLists, bucketStreams, bucketCertificates, + bucketRedirectionHosts, bucketDeadHosts, bucketUsers, bucketAuditLogs, + bucketSettings, bucketMeta, + } + for _, name := range buckets { + if _, err := tx.CreateBucketIfNotExists([]byte(name)); err != nil { + return err + } + } + return nil + }) +} + +func (s *bboltStore) seedDefaults() error { + return s.db.Update(func(tx *bbolt.Tx) error { + // Seed admin user + default settings on first run (empty data dir) + admin := models.User{ + ID: 1, + Email: "admin@example.com", + Name: "Admin", + Roles: []string{"admin"}, + } + if err := s.putJSON(tx, bucketUsers, admin.ID, admin); err != nil { + return err + } + + // Default settings + b := tx.Bucket([]byte(bucketSettings)) + defaults := map[string]any{"default_site": "congratulations"} + jb, _ := json.Marshal(defaults) + b.Put([]byte("data"), jb) + + // Advance user sequence + bu := tx.Bucket([]byte(bucketUsers)) + bu.NextSequence() // advance past 1 + + return nil + }) +} + +func (s *bboltStore) hasAnyUsers() bool { + var count int + s.db.View(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketUsers)) + if b != nil { + count = b.Stats().KeyN + } + return nil + }) + return count > 0 +} + +// --- helpers --- + +func itob(i int) []byte { + b := make([]byte, 8) + binary.BigEndian.PutUint64(b, uint64(i)) + return b +} + +func btoi(b []byte) int { + if len(b) < 8 { + return 0 + } + return int(binary.BigEndian.Uint64(b)) +} + +func (s *bboltStore) putJSON(tx *bbolt.Tx, bucket string, id int, v any) error { + b := tx.Bucket([]byte(bucket)) + jb, err := json.Marshal(v) + if err != nil { + return err + } + return b.Put(itob(id), jb) +} + +func (s *bboltStore) getJSON(tx *bbolt.Tx, bucket string, id int, out any) bool { + b := tx.Bucket([]byte(bucket)) + if b == nil { + return false + } + data := b.Get(itob(id)) + if data == nil { + return false + } + return json.Unmarshal(data, out) == nil +} + +// --- Store interface implementation --- + +func (s *bboltStore) IsSetup() bool { + var has bool + s.db.View(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketUsers)) + if b != nil { + has = b.Stats().KeyN > 0 + } + return nil + }) + return has +} + +func (s *bboltStore) GetUsers() []models.User { + var out []models.User + s.db.View(func(tx *bbolt.Tx) error { + out = s.loadUsers(tx) + return nil + }) + return out +} + +// --- ProxyHost --- + +func (s *bboltStore) GetProxyHosts() []models.ProxyHost { + var out []models.ProxyHost + s.db.View(func(tx *bbolt.Tx) error { + out = s.loadProxyHosts(tx) + return nil + }) + return out +} + +func (s *bboltStore) GetProxyHost(id int) (models.ProxyHost, bool) { + var h models.ProxyHost + s.db.View(func(tx *bbolt.Tx) error { + s.getJSON(tx, bucketProxyHosts, id, &h) + return nil + }) + return h, h.ID != 0 +} + +func (s *bboltStore) CreateProxyHost(h models.ProxyHost) (models.ProxyHost, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketProxyHosts)) + if h.ID == 0 { + seq, _ := b.NextSequence() + h.ID = int(seq) + } + if h.DomainNames == nil { + h.DomainNames = []string{} + } + if h.Meta == nil { + h.Meta = map[string]any{} + } + if h.CreatedOn == "" { + h.CreatedOn = time.Now().UTC().Format("2006-01-02 15:04:05") // centralized server-set (no longer duplicated in main.go POST handlers) + } + if err := validateProxyHostSources(s.loadProxyHosts(tx), h); err != nil { + return err + } + return s.putJSON(tx, bucketProxyHosts, h.ID, h) + }) + return h, err +} + +func (s *bboltStore) UpdateProxyHost(h models.ProxyHost) (models.ProxyHost, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + if !s.getJSON(tx, bucketProxyHosts, h.ID, &models.ProxyHost{}) { + return errors.New("not found") + } + if err := validateProxyHostSources(s.loadProxyHosts(tx), h); err != nil { + return err + } + return s.putJSON(tx, bucketProxyHosts, h.ID, h) + }) + return h, err +} + +func (s *bboltStore) DeleteProxyHost(id int) error { + return s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketProxyHosts)) + return b.Delete(itob(id)) + }) +} + +func (s *bboltStore) SetProxyHostEnabled(id int, enabled bool) error { + return s.db.Update(func(tx *bbolt.Tx) error { + var h models.ProxyHost + if !s.getJSON(tx, bucketProxyHosts, id, &h) { + return errors.New("not found") + } + h.Enabled = enabled + return s.putJSON(tx, bucketProxyHosts, id, h) + }) +} + +// --- AccessList --- + +func (s *bboltStore) GetAccessLists() []models.AccessList { + var out []models.AccessList + s.db.View(func(tx *bbolt.Tx) error { + out = s.loadAccessLists(tx) + return nil + }) + return out +} + +func (s *bboltStore) GetAccessList(id int) (models.AccessList, bool) { + var al models.AccessList + s.db.View(func(tx *bbolt.Tx) error { + s.getJSON(tx, bucketAccessLists, id, &al) + return nil + }) + return al, al.ID != 0 +} + +func (s *bboltStore) CreateAccessList(al models.AccessList) (models.AccessList, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketAccessLists)) + if al.ID == 0 { + seq, _ := b.NextSequence() + al.ID = int(seq) + } + if al.Clients == nil { + al.Clients = []models.AccessClient{} + } + if al.Items == nil { + al.Items = []models.AccessItem{} + } + if al.CreatedOn == "" { + al.CreatedOn = time.Now().UTC().Format("2006-01-02 15:04:05") // centralized server-set (no longer duplicated in main.go POST handlers) + } + return s.putJSON(tx, bucketAccessLists, al.ID, al) + }) + return al, err +} + +func (s *bboltStore) UpdateAccessList(al models.AccessList) (models.AccessList, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + return s.putJSON(tx, bucketAccessLists, al.ID, al) + }) + return al, err +} + +func (s *bboltStore) DeleteAccessList(id int) error { + return s.db.Update(func(tx *bbolt.Tx) error { + return tx.Bucket([]byte(bucketAccessLists)).Delete(itob(id)) + }) +} + +// --- Stream --- + +func (s *bboltStore) GetStreams() []models.Stream { + var out []models.Stream + s.db.View(func(tx *bbolt.Tx) error { + out = s.loadStreams(tx) + return nil + }) + return out +} + +func (s *bboltStore) GetStream(id int) (models.Stream, bool) { + var st models.Stream + s.db.View(func(tx *bbolt.Tx) error { + s.getJSON(tx, bucketStreams, id, &st) + return nil + }) + return st, st.ID != 0 +} + +func (s *bboltStore) CreateStream(st models.Stream) (models.Stream, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketStreams)) + if st.ID == 0 { + seq, _ := b.NextSequence() + st.ID = int(seq) + } + if st.Meta == nil { + st.Meta = map[string]any{} + } + if st.CreatedOn == "" { + st.CreatedOn = time.Now().UTC().Format("2006-01-02 15:04:05") // centralized server-set (no longer duplicated in main.go POST handlers) + } + if err := validateStreamIncomingPort(st, s.loadStreams(tx)); err != nil { + return err + } + return s.putJSON(tx, bucketStreams, st.ID, st) + }) + return st, err +} + +func (s *bboltStore) UpdateStream(st models.Stream) (models.Stream, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + if !s.getJSON(tx, bucketStreams, st.ID, &models.Stream{}) { + return errors.New("not found") + } + if err := validateStreamIncomingPort(st, s.loadStreams(tx)); err != nil { + return err + } + return s.putJSON(tx, bucketStreams, st.ID, st) + }) + return st, err +} + +func (s *bboltStore) DeleteStream(id int) error { + return s.db.Update(func(tx *bbolt.Tx) error { + return tx.Bucket([]byte(bucketStreams)).Delete(itob(id)) + }) +} + +func (s *bboltStore) SetStreamEnabled(id int, enabled bool) error { + return s.db.Update(func(tx *bbolt.Tx) error { + var st models.Stream + if !s.getJSON(tx, bucketStreams, id, &st) { + return errors.New("not found") + } + st.Enabled = enabled + if enabled { + if err := validateStreamIncomingPort(st, s.loadStreams(tx)); err != nil { + return err + } + } + return s.putJSON(tx, bucketStreams, id, st) + }) +} + +// --- Certificate --- + +func (s *bboltStore) GetCertificates() []models.Certificate { + var out []models.Certificate + s.db.View(func(tx *bbolt.Tx) error { + out = s.loadCertificates(tx) + return nil + }) + return out +} + +func (s *bboltStore) GetCertificate(id int) (models.Certificate, bool) { + var c models.Certificate + s.db.View(func(tx *bbolt.Tx) error { + s.getJSON(tx, bucketCertificates, id, &c) + return nil + }) + return c, c.ID != 0 +} + +func (s *bboltStore) CreateCertificate(c models.Certificate) (models.Certificate, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketCertificates)) + if c.ID == 0 { + seq, _ := b.NextSequence() + c.ID = int(seq) + } + if c.DomainNames == nil { + c.DomainNames = []string{} + } + if c.Meta == nil { + c.Meta = map[string]any{} + } + if c.CreatedOn == "" { + c.CreatedOn = time.Now().UTC().Format("2006-01-02 15:04:05") // centralized server-set (no longer duplicated in main.go POST handlers) + } + return s.putJSON(tx, bucketCertificates, c.ID, c) + }) + return c, err +} + +func (s *bboltStore) SetCertificate(c models.Certificate) error { + return s.db.Update(func(tx *bbolt.Tx) error { + var existing models.Certificate + if s.getJSON(tx, bucketCertificates, c.ID, &existing) && c.CreatedOn == "" { + c.CreatedOn = existing.CreatedOn + } + return s.putJSON(tx, bucketCertificates, c.ID, c) + }) +} + +func (s *bboltStore) DeleteCertificate(id int) error { + return s.db.Update(func(tx *bbolt.Tx) error { + return tx.Bucket([]byte(bucketCertificates)).Delete(itob(id)) + }) +} + +// --- RedirectionHost --- + +func (s *bboltStore) GetRedirectionHosts() []models.RedirectionHost { + var out []models.RedirectionHost + s.db.View(func(tx *bbolt.Tx) error { + out = s.loadRedirectionHosts(tx) + return nil + }) + return out +} + +func (s *bboltStore) GetRedirectionHost(id int) (models.RedirectionHost, bool) { + var rh models.RedirectionHost + s.db.View(func(tx *bbolt.Tx) error { + s.getJSON(tx, bucketRedirectionHosts, id, &rh) + return nil + }) + return rh, rh.ID != 0 +} + +func (s *bboltStore) CreateRedirectionHost(h models.RedirectionHost) (models.RedirectionHost, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketRedirectionHosts)) + if h.ID == 0 { + seq, _ := b.NextSequence() + h.ID = int(seq) + } + if h.DomainNames == nil { + h.DomainNames = []string{} + } + if h.Meta == nil { + h.Meta = map[string]any{} + } + if h.CreatedOn == "" { + h.CreatedOn = time.Now().UTC().Format("2006-01-02 15:04:05") // centralized server-set (no longer duplicated in main.go POST handlers) + } + if err := validateRedirectionHostSources(s.loadRedirectionHosts(tx), h); err != nil { + return err + } + return s.putJSON(tx, bucketRedirectionHosts, h.ID, h) + }) + return h, err +} + +func (s *bboltStore) UpdateRedirectionHost(h models.RedirectionHost) (models.RedirectionHost, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + if !s.getJSON(tx, bucketRedirectionHosts, h.ID, &models.RedirectionHost{}) { + return errors.New("not found") + } + if err := validateRedirectionHostSources(s.loadRedirectionHosts(tx), h); err != nil { + return err + } + return s.putJSON(tx, bucketRedirectionHosts, h.ID, h) + }) + return h, err +} + +func (s *bboltStore) DeleteRedirectionHost(id int) error { + return s.db.Update(func(tx *bbolt.Tx) error { + return tx.Bucket([]byte(bucketRedirectionHosts)).Delete(itob(id)) + }) +} + +func (s *bboltStore) SetRedirectionHostEnabled(id int, enabled bool) error { + return s.db.Update(func(tx *bbolt.Tx) error { + var rh models.RedirectionHost + if !s.getJSON(tx, bucketRedirectionHosts, id, &rh) { + return errors.New("not found") + } + rh.Enabled = enabled + return s.putJSON(tx, bucketRedirectionHosts, id, rh) + }) +} + +// --- DeadHost --- + +func (s *bboltStore) GetDeadHosts() []models.DeadHost { + var out []models.DeadHost + s.db.View(func(tx *bbolt.Tx) error { + out = s.loadDeadHosts(tx) + return nil + }) + return out +} + +func (s *bboltStore) GetDeadHost(id int) (models.DeadHost, bool) { + var dh models.DeadHost + s.db.View(func(tx *bbolt.Tx) error { + s.getJSON(tx, bucketDeadHosts, id, &dh) + return nil + }) + return dh, dh.ID != 0 +} + +func (s *bboltStore) CreateDeadHost(h models.DeadHost) (models.DeadHost, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketDeadHosts)) + if h.ID == 0 { + seq, _ := b.NextSequence() + h.ID = int(seq) + } + if h.DomainNames == nil { + h.DomainNames = []string{} + } + if h.Meta == nil { + h.Meta = map[string]any{} + } + if h.CreatedOn == "" { + h.CreatedOn = time.Now().UTC().Format("2006-01-02 15:04:05") // centralized server-set (no longer duplicated in main.go POST handlers) + } + if err := validateDeadHostSources(s.loadDeadHosts(tx), h); err != nil { + return err + } + return s.putJSON(tx, bucketDeadHosts, h.ID, h) + }) + return h, err +} + +func (s *bboltStore) UpdateDeadHost(h models.DeadHost) (models.DeadHost, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + if !s.getJSON(tx, bucketDeadHosts, h.ID, &models.DeadHost{}) { + return errors.New("not found") + } + if err := validateDeadHostSources(s.loadDeadHosts(tx), h); err != nil { + return err + } + return s.putJSON(tx, bucketDeadHosts, h.ID, h) + }) + return h, err +} + +func (s *bboltStore) DeleteDeadHost(id int) error { + return s.db.Update(func(tx *bbolt.Tx) error { + return tx.Bucket([]byte(bucketDeadHosts)).Delete(itob(id)) + }) +} + +func (s *bboltStore) SetDeadHostEnabled(id int, enabled bool) error { + return s.db.Update(func(tx *bbolt.Tx) error { + var dh models.DeadHost + if !s.getJSON(tx, bucketDeadHosts, id, &dh) { + return errors.New("not found") + } + dh.Enabled = enabled + return s.putJSON(tx, bucketDeadHosts, id, dh) + }) +} + +// --- Settings --- + +func (s *bboltStore) GetSettings() map[string]any { + var m map[string]any + s.db.View(func(tx *bbolt.Tx) error { + m = s.loadSettings(tx) + return nil + }) + return m +} + +func (s *bboltStore) SetSetting(name string, value any) error { + return s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketSettings)) + var current map[string]any + if data := b.Get([]byte("data")); data != nil { + json.Unmarshal(data, ¤t) + } + if current == nil { + current = map[string]any{} + } + current[name] = value + jb, _ := json.Marshal(current) + return b.Put([]byte("data"), jb) + }) +} + +// --- AuditLog --- + +func (s *bboltStore) GetAuditLogs() []models.AuditLog { + var out []models.AuditLog + s.db.View(func(tx *bbolt.Tx) error { + out = s.loadAuditLogs(tx) + return nil + }) + return out +} + +func (s *bboltStore) AddAuditLog(log models.AuditLog) (models.AuditLog, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketAuditLogs)) + if log.ID == 0 { + seq, _ := b.NextSequence() + log.ID = int(seq) + } + if log.Meta == nil { + log.Meta = map[string]any{} + } + if log.CreatedOn == "" { + // set now if caller did not provide (callers in main rarely do) + log.CreatedOn = time.Now().UTC().Format("2006-01-02 15:04:05") + } + return s.putJSON(tx, bucketAuditLogs, log.ID, log) + }) + return log, err +} + +// --- Users --- + +func (s *bboltStore) GetUserByEmail(email string) (models.User, bool) { + var found models.User + s.db.View(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketUsers)) + c := b.Cursor() + for k, v := c.First(); k != nil; k, v = c.Next() { + var u models.User + if json.Unmarshal(v, &u) == nil && u.Email == email { + found = u + return nil + } + } + return nil + }) + return found, found.ID != 0 +} + +func (s *bboltStore) CreateUser(u models.User) (models.User, error) { + err := s.db.Update(func(tx *bbolt.Tx) error { + b := tx.Bucket([]byte(bucketUsers)) + if u.ID == 0 { + seq, _ := b.NextSequence() + u.ID = int(seq) + } + if u.Roles == nil { + u.Roles = []string{} + } + return s.putJSON(tx, bucketUsers, u.ID, u) + }) + return u, err +} + +func (s *bboltStore) UpdateUser(u models.User) error { + return s.db.Update(func(tx *bbolt.Tx) error { + return s.putJSON(tx, bucketUsers, u.ID, u) + }) +} + +func (s *bboltStore) UpdateUserFull(u models.User) error { + return s.UpdateUser(u) +} + +func (s *bboltStore) DeleteUser(id int) error { + return s.db.Update(func(tx *bbolt.Tx) error { + return tx.Bucket([]byte(bucketUsers)).Delete(itob(id)) + }) +} + +// --- load helpers (used by Root and lists) --- + +func (s *bboltStore) loadUsers(tx *bbolt.Tx) []models.User { + var out []models.User + b := tx.Bucket([]byte(bucketUsers)) + if b == nil { + return out + } + b.ForEach(func(_, v []byte) error { + var u models.User + if json.Unmarshal(v, &u) == nil { + out = append(out, u) + } + return nil + }) + return out +} + +func (s *bboltStore) loadProxyHosts(tx *bbolt.Tx) []models.ProxyHost { + var out []models.ProxyHost + b := tx.Bucket([]byte(bucketProxyHosts)) + if b == nil { + return out + } + b.ForEach(func(_, v []byte) error { + var h models.ProxyHost + if json.Unmarshal(v, &h) == nil { + out = append(out, h) + } + return nil + }) + return out +} + +func (s *bboltStore) loadAccessLists(tx *bbolt.Tx) []models.AccessList { + var out []models.AccessList + b := tx.Bucket([]byte(bucketAccessLists)) + if b == nil { + return out + } + b.ForEach(func(_, v []byte) error { + var al models.AccessList + if json.Unmarshal(v, &al) == nil { + out = append(out, al) + } + return nil + }) + return out +} + +func (s *bboltStore) loadStreams(tx *bbolt.Tx) []models.Stream { + var out []models.Stream + b := tx.Bucket([]byte(bucketStreams)) + if b == nil { + return out + } + b.ForEach(func(_, v []byte) error { + var st models.Stream + if json.Unmarshal(v, &st) == nil { + out = append(out, st) + } + return nil + }) + return out +} + +func (s *bboltStore) loadCertificates(tx *bbolt.Tx) []models.Certificate { + var out []models.Certificate + b := tx.Bucket([]byte(bucketCertificates)) + if b == nil { + return out + } + b.ForEach(func(_, v []byte) error { + var c models.Certificate + if json.Unmarshal(v, &c) == nil { + out = append(out, c) + } + return nil + }) + return out +} + +func (s *bboltStore) loadRedirectionHosts(tx *bbolt.Tx) []models.RedirectionHost { + var out []models.RedirectionHost + b := tx.Bucket([]byte(bucketRedirectionHosts)) + if b == nil { + return out + } + b.ForEach(func(_, v []byte) error { + var rh models.RedirectionHost + if json.Unmarshal(v, &rh) == nil { + out = append(out, rh) + } + return nil + }) + return out +} + +func (s *bboltStore) loadDeadHosts(tx *bbolt.Tx) []models.DeadHost { + var out []models.DeadHost + b := tx.Bucket([]byte(bucketDeadHosts)) + if b == nil { + return out + } + b.ForEach(func(_, v []byte) error { + var dh models.DeadHost + if json.Unmarshal(v, &dh) == nil { + out = append(out, dh) + } + return nil + }) + return out +} + +func (s *bboltStore) loadAuditLogs(tx *bbolt.Tx) []models.AuditLog { + var out []models.AuditLog + b := tx.Bucket([]byte(bucketAuditLogs)) + if b == nil { + return out + } + b.ForEach(func(_, v []byte) error { + var a models.AuditLog + if json.Unmarshal(v, &a) == nil { + out = append(out, a) + } + return nil + }) + return out +} + +func (s *bboltStore) loadSettings(tx *bbolt.Tx) map[string]any { + b := tx.Bucket([]byte(bucketSettings)) + if b == nil { + return map[string]any{} + } + data := b.Get([]byte("data")) + if data == nil { + return map[string]any{} + } + var m map[string]any + json.Unmarshal(data, &m) + if m == nil { + return map[string]any{} + } + return m +} + +// Compile-time check +var _ Store = (*bboltStore)(nil) diff --git a/internal/store/source_validate.go b/internal/store/source_validate.go new file mode 100644 index 0000000..8d9b3db --- /dev/null +++ b/internal/store/source_validate.go @@ -0,0 +1,110 @@ +package store + +import ( + "errors" + "fmt" + "strings" + + "helix-proxy/internal/models" +) + +var ( + ErrDuplicateProxySource = errors.New("duplicate proxy host source domain") + ErrDuplicateRedirectionSource = errors.New("duplicate redirection host source domain") + ErrDuplicateDeadSource = errors.New("duplicate dead host source domain") + ErrDuplicateStreamPort = errors.New("duplicate stream incoming port") +) + +func IsConflictError(err error) bool { + return errors.Is(err, ErrDuplicateProxySource) || + errors.Is(err, ErrDuplicateRedirectionSource) || + errors.Is(err, ErrDuplicateDeadSource) || + errors.Is(err, ErrDuplicateStreamPort) +} + +type domainRecord struct { + ID int + DomainNames []string +} + +func normalizeSourceDomain(d string) (normalized, display string, ok bool) { + display = strings.TrimSpace(d) + if display == "" { + return "", "", false + } + return strings.ToLower(display), display, true +} + +func validateUniqueDomains(domainNames []string, selfID int, existing []domainRecord, errSentinel error) error { + own := make(map[string]string) + for _, d := range domainNames { + norm, display, ok := normalizeSourceDomain(d) + if !ok { + continue + } + if prev, dup := own[norm]; dup { + return fmt.Errorf("%w: duplicate source domain: %s", errSentinel, prev) + } + own[norm] = display + } + + used := make(map[string]struct{}) + for _, rec := range existing { + if rec.ID == selfID { + continue + } + for _, d := range rec.DomainNames { + norm, _, ok := normalizeSourceDomain(d) + if !ok { + continue + } + used[norm] = struct{}{} + } + } + + for norm, display := range own { + if _, conflict := used[norm]; conflict { + return fmt.Errorf("%w: source domain already in use: %s", errSentinel, display) + } + } + return nil +} + +func validateProxyHostSources(hosts []models.ProxyHost, h models.ProxyHost) error { + existing := make([]domainRecord, len(hosts)) + for i, host := range hosts { + existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames} + } + return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateProxySource) +} + +func validateRedirectionHostSources(hosts []models.RedirectionHost, h models.RedirectionHost) error { + existing := make([]domainRecord, len(hosts)) + for i, host := range hosts { + existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames} + } + return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateRedirectionSource) +} + +func validateDeadHostSources(hosts []models.DeadHost, h models.DeadHost) error { + existing := make([]domainRecord, len(hosts)) + for i, host := range hosts { + existing[i] = domainRecord{ID: host.ID, DomainNames: host.DomainNames} + } + return validateUniqueDomains(h.DomainNames, h.ID, existing, ErrDuplicateDeadSource) +} + +func validateStreamIncomingPort(st models.Stream, streams []models.Stream) error { + if st.IncomingPort <= 0 { + return nil + } + for _, other := range streams { + if other.ID == st.ID { + continue + } + if other.IncomingPort == st.IncomingPort { + return fmt.Errorf("%w: incoming port already in use: %d", ErrDuplicateStreamPort, st.IncomingPort) + } + } + return nil +} diff --git a/internal/store/store.go b/internal/store/store.go new file mode 100644 index 0000000..342c42e --- /dev/null +++ b/internal/store/store.go @@ -0,0 +1,111 @@ +package store + +import "helix-proxy/internal/models" + +// Convenience type aliases so that code importing "helix-proxy/internal/store" +// can refer to the domain models as e.g. store.ProxyHost (historical API surface). +type ( + Root = models.Root + User = models.User + ProxyHost = models.ProxyHost + HeaderRule = models.HeaderRule + Location = models.Location + AccessList = models.AccessList + AccessClient = models.AccessClient + AccessItem = models.AccessItem + Stream = models.Stream + Certificate = models.Certificate + RedirectionHost = models.RedirectionHost + DeadHost = models.DeadHost + AuditLog = models.AuditLog +) + +// New returns the default Store implementation (bbolt, a pure-Go +// embedded transactional database). This is the recommended constructor for +// normal operation. +// +// It provides real ACID transactions and good concurrency while remaining a +// single static binary with no external database process. +func New() (Store, error) { + return NewBboltStore() +} + +// Store is the interface for all persistent state in Helix Proxy. +// +// We use bbolt (pure-Go embedded transactional key/value store) as the one and only +// implementation. The interface exists primarily to: +// - Make the rest of the code (engine, cert manager, API handlers) easy to test with fakes. +// - Keep a clean boundary (in case we ever need to evolve the storage layer). +// +// All methods are safe for concurrent use. +// +// Models live in internal/models. + +type Store interface { + // --- meta / bootstrap --- + IsSetup() bool + GetUsers() []models.User + + // --- ProxyHost --- + GetProxyHosts() []models.ProxyHost + GetProxyHost(id int) (models.ProxyHost, bool) + CreateProxyHost(h models.ProxyHost) (models.ProxyHost, error) + UpdateProxyHost(h models.ProxyHost) (models.ProxyHost, error) + DeleteProxyHost(id int) error + SetProxyHostEnabled(id int, enabled bool) error + + // --- AccessList --- + GetAccessLists() []models.AccessList + GetAccessList(id int) (models.AccessList, bool) + CreateAccessList(al models.AccessList) (models.AccessList, error) + UpdateAccessList(al models.AccessList) (models.AccessList, error) + DeleteAccessList(id int) error + + // --- Stream --- + GetStreams() []models.Stream + GetStream(id int) (models.Stream, bool) + CreateStream(st models.Stream) (models.Stream, error) + UpdateStream(st models.Stream) (models.Stream, error) + DeleteStream(id int) error + SetStreamEnabled(id int, enabled bool) error + + // --- Certificate --- + GetCertificates() []models.Certificate + GetCertificate(id int) (models.Certificate, bool) + CreateCertificate(c models.Certificate) (models.Certificate, error) + SetCertificate(c models.Certificate) error // used after LE issuance/renewal mutates meta+expires + DeleteCertificate(id int) error + + // --- RedirectionHost --- + GetRedirectionHosts() []models.RedirectionHost + GetRedirectionHost(id int) (models.RedirectionHost, bool) + CreateRedirectionHost(h models.RedirectionHost) (models.RedirectionHost, error) + UpdateRedirectionHost(h models.RedirectionHost) (models.RedirectionHost, error) + DeleteRedirectionHost(id int) error + SetRedirectionHostEnabled(id int, enabled bool) error + + // --- DeadHost --- + GetDeadHosts() []models.DeadHost + GetDeadHost(id int) (models.DeadHost, bool) + CreateDeadHost(h models.DeadHost) (models.DeadHost, error) + UpdateDeadHost(h models.DeadHost) (models.DeadHost, error) + DeleteDeadHost(id int) error + SetDeadHostEnabled(id int, enabled bool) error + + // --- Settings (global) --- + GetSettings() map[string]any + SetSetting(name string, value any) error + + // --- Audit --- + GetAuditLogs() []models.AuditLog + AddAuditLog(log models.AuditLog) (models.AuditLog, error) + + // --- Users + 2FA --- + GetUserByEmail(email string) (models.User, bool) + CreateUser(u models.User) (models.User, error) + UpdateUser(u models.User) error + UpdateUserFull(u models.User) error // used when updating without changing password + DeleteUser(id int) error + + // GetUsers avoids needing to fetch the entire root for user lists. +} diff --git a/internal/store/store_test.go b/internal/store/store_test.go new file mode 100644 index 0000000..9bf4f52 --- /dev/null +++ b/internal/store/store_test.go @@ -0,0 +1,513 @@ +package store + +import ( + "errors" + "reflect" + "strconv" + "sync" + "testing" + + "helix-proxy/internal/config" +) + +// --- test helpers --- + +func newTestBbolt(t *testing.T) Store { + t.Helper() + tmp := t.TempDir() + config.ResetForTest() + t.Setenv("DATA_DIR", tmp) + s, err := NewBboltStore() + if err != nil { + t.Fatalf("NewBboltStore: %v", err) + } + return s +} + +// closeIfBbolt helps cleanup for bbolt (interface doesn't have Close but impl does) +func closeIfBbolt(s Store) { + if c, ok := s.(interface{ Close() error }); ok { + c.Close() + } +} + +func TestNew_SeedsAdminAndSettings(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + if !s.IsSetup() { + t.Error("IsSetup false after new") + } + users := s.GetUsers() + if len(users) != 1 || users[0].Email != "admin@example.com" || users[0].ID != 1 { + t.Errorf("seeded admin wrong: %+v", users) + } + settings := s.GetSettings() + if settings["default_site"] != "congratulations" { + t.Errorf("default settings wrong: %v", settings) + } +} + +func TestIDGeneration(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + h1, _ := s.CreateProxyHost(ProxyHost{DomainNames: []string{"a.com"}}) + h2, _ := s.CreateProxyHost(ProxyHost{DomainNames: []string{"b.com"}}) + if h1.ID == 0 || h2.ID == 0 || h2.ID <= h1.ID { + t.Errorf("ids not increasing: %d %d", h1.ID, h2.ID) + } + if h1.CreatedOn == "" { + t.Error("CreateProxyHost did not populate CreatedOn") + } + al1, _ := s.CreateAccessList(AccessList{Name: "t1"}) + if al1.CreatedOn == "" { + t.Error("CreateAccessList did not populate CreatedOn") + } + st1, _ := s.CreateStream(Stream{IncomingPort: 1}) + if st1.CreatedOn == "" { + t.Error("CreateStream did not populate CreatedOn") + } + // explicit id should be honored? (current impls assign only if 0) + h3, _ := s.CreateProxyHost(ProxyHost{ID: 99, DomainNames: []string{"c.com"}}) + if h3.ID != 99 { + t.Errorf("explicit id not kept: %d", h3.ID) + } +} + +func TestProxyHostCRUD(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + // create + h := ProxyHost{ + DomainNames: []string{"example.com", "www.example.com"}, + ForwardScheme: "https", + ForwardHost: "10.0.0.1", + ForwardPort: 8443, + Enabled: true, + Meta: map[string]any{"foo": "bar"}, + } + created, err := s.CreateProxyHost(h) + if err != nil { + t.Fatal(err) + } + if created.ID == 0 { + t.Fatal("no id assigned") + } + if !reflect.DeepEqual(created.DomainNames, h.DomainNames) || created.Meta["foo"] != "bar" { + t.Error("roundtrip fidelity lost on create") + } + + // get list / get + list := s.GetProxyHosts() + if len(list) != 1 { + t.Errorf("list len %d", len(list)) + } + got, ok := s.GetProxyHost(created.ID) + if !ok || got.ID != created.ID { + t.Error("get by id failed") + } + + // update + created.ForwardHost = "10.0.0.2" + created.Meta["new"] = 42 + up, err := s.UpdateProxyHost(created) + if err != nil { + t.Fatal(err) + } + if up.ForwardHost != "10.0.0.2" || up.Meta["new"] != 42 { + t.Error("update not persisted") + } + if up.CreatedOn == "" { + t.Error("UpdateProxyHost did not preserve CreatedOn") + } + + // set enabled + if err := s.SetProxyHostEnabled(created.ID, false); err != nil { + t.Fatal(err) + } + g2, _ := s.GetProxyHost(created.ID) + if g2.Enabled { + t.Error("set enabled false failed") + } + + // delete + if err := s.DeleteProxyHost(created.ID); err != nil { + t.Fatal(err) + } + if _, ok := s.GetProxyHost(created.ID); ok { + t.Error("delete did not remove") + } +} + +func TestProxyHostDuplicateSources(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + h1, err := s.CreateProxyHost(ProxyHost{DomainNames: []string{"a.example.com"}}) + if err != nil { + t.Fatal(err) + } + + _, err = s.CreateProxyHost(ProxyHost{DomainNames: []string{"a.example.com"}}) + if !errors.Is(err, ErrDuplicateProxySource) { + t.Fatalf("expected duplicate error on cross-host conflict, got %v", err) + } + + _, err = s.CreateProxyHost(ProxyHost{DomainNames: []string{"A.EXAMPLE.COM"}}) + if !errors.Is(err, ErrDuplicateProxySource) { + t.Fatalf("expected duplicate error on case-insensitive conflict, got %v", err) + } + + _, err = s.CreateProxyHost(ProxyHost{DomainNames: []string{"b.example.com", "b.example.com"}}) + if !errors.Is(err, ErrDuplicateProxySource) { + t.Fatalf("expected duplicate error within same host, got %v", err) + } + + h1.DomainNames = []string{"a.example.com", "c.example.com"} + if _, err = s.UpdateProxyHost(h1); err != nil { + t.Fatalf("update own domains: %v", err) + } + + h2, err := s.CreateProxyHost(ProxyHost{DomainNames: []string{"d.example.com"}}) + if err != nil { + t.Fatal(err) + } + h2.DomainNames = []string{"c.example.com"} + _, err = s.UpdateProxyHost(h2) + if !errors.Is(err, ErrDuplicateProxySource) { + t.Fatalf("expected duplicate error on update conflict, got %v", err) + } +} + +func TestRedirectionHostDuplicateSources(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + _, err := s.CreateRedirectionHost(RedirectionHost{DomainNames: []string{"redir.example.com"}}) + if err != nil { + t.Fatal(err) + } + _, err = s.CreateRedirectionHost(RedirectionHost{DomainNames: []string{"redir.example.com"}}) + if !errors.Is(err, ErrDuplicateRedirectionSource) { + t.Fatalf("expected duplicate error, got %v", err) + } +} + +func TestDeadHostDuplicateSources(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + _, err := s.CreateDeadHost(DeadHost{DomainNames: []string{"dead.example.com"}}) + if err != nil { + t.Fatal(err) + } + _, err = s.CreateDeadHost(DeadHost{DomainNames: []string{"DEAD.example.com"}}) + if !errors.Is(err, ErrDuplicateDeadSource) { + t.Fatalf("expected duplicate error, got %v", err) + } +} + +func TestStreamDuplicateIncomingPort(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + _, err := s.CreateStream(Stream{IncomingPort: 9001, ForwardingHost: "127.0.0.1", ForwardingPort: 80}) + if err != nil { + t.Fatal(err) + } + _, err = s.CreateStream(Stream{IncomingPort: 9001, ForwardingHost: "127.0.0.1", ForwardingPort: 8080}) + if !errors.Is(err, ErrDuplicateStreamPort) { + t.Fatalf("expected duplicate port error, got %v", err) + } +} + +func TestStreamUpdateDuplicateIncomingPort(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + a, err := s.CreateStream(Stream{IncomingPort: 9001, ForwardingHost: "127.0.0.1", ForwardingPort: 80}) + if err != nil { + t.Fatal(err) + } + b, err := s.CreateStream(Stream{IncomingPort: 9002, ForwardingHost: "127.0.0.1", ForwardingPort: 80}) + if err != nil { + t.Fatal(err) + } + b.IncomingPort = 9001 + _, err = s.UpdateStream(b) + if !errors.Is(err, ErrDuplicateStreamPort) { + t.Fatalf("expected duplicate port error on update, got %v", err) + } + _ = a +} + +func TestAccessListCRUD(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + al := AccessList{ + Name: "test al", + SatisfyAny: true, + Clients: []AccessClient{{Address: "1.2.3.4", Directive: "allow"}}, + Items: []AccessItem{{Username: "u", Password: "p"}}, + PassAuth: true, + } + created, err := s.CreateAccessList(al) + if err != nil || created.ID == 0 { + t.Fatalf("create: %v", err) + } + if len(created.Clients) != 1 || len(created.Items) != 1 { + t.Error("clients/items nilled?") + } + + // update + created.Name = "renamed" + up, err := s.UpdateAccessList(created) + if err != nil || up.Name != "renamed" { + t.Fatalf("update: %v", err) + } + if up.CreatedOn == "" { + t.Error("UpdateAccessList did not preserve CreatedOn") + } + + if err := s.DeleteAccessList(created.ID); err != nil { + t.Fatal(err) + } + if _, ok := s.GetAccessList(created.ID); ok { + t.Error("not deleted") + } +} + +func TestStreamCRUD(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + st := Stream{ + IncomingPort: 1234, + ForwardingHost: "127.0.0.1", + ForwardingPort: 5678, + TCPForwarding: true, + Enabled: true, + Meta: map[string]any{"k": 1}, + } + c, err := s.CreateStream(st) + if err != nil { + t.Fatal(err) + } + if c.ID == 0 || c.Meta == nil { + t.Error("id or meta") + } + c.Enabled = false + up, _ := s.UpdateStream(c) + if up.CreatedOn == "" { + t.Error("UpdateStream did not preserve CreatedOn") + } + if err := s.SetStreamEnabled(c.ID, true); err != nil { + t.Fatal(err) + } + g, _ := s.GetStream(c.ID) + if !g.Enabled { + t.Error("set enabled") + } + _ = s.DeleteStream(c.ID) +} + +func TestCertificateCRUD(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + c := Certificate{ + Provider: "letsencrypt", + DomainNames: []string{"ex.com"}, + Meta: map[string]any{"cert": "pem"}, + } + created, err := s.CreateCertificate(c) + if err != nil || len(created.DomainNames) == 0 || created.Meta == nil { + t.Fatal(err) + } + created.ExpiresOn = "2099-01-01" + origCreated := created.CreatedOn + if err := s.SetCertificate(created); err != nil { + t.Fatal(err) + } + g, _ := s.GetCertificate(created.ID) + if g.ExpiresOn != "2099-01-01" { + t.Error("set cert") + } + if g.CreatedOn != origCreated { + t.Error("SetCertificate did not preserve CreatedOn") + } + _ = s.DeleteCertificate(created.ID) +} + +func TestRedirectionDeadHostCRUD(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + rh := RedirectionHost{DomainNames: []string{"r.com"}, ForwardDomainName: "t.com", Enabled: true, Meta: map[string]any{}} + crh, _ := s.CreateRedirectionHost(rh) + crh.ForwardHTTPCode = 301 + rup, _ := s.UpdateRedirectionHost(crh) + if rup.CreatedOn == "" { + t.Error("UpdateRedirectionHost did not preserve CreatedOn") + } + _ = s.SetRedirectionHostEnabled(crh.ID, false) + _ = s.DeleteRedirectionHost(crh.ID) + + dh := DeadHost{DomainNames: []string{"d.com"}, Enabled: true, Meta: map[string]any{}} + cdh, _ := s.CreateDeadHost(dh) + dup, _ := s.UpdateDeadHost(cdh) + if dup.CreatedOn == "" { + t.Error("UpdateDeadHost did not preserve CreatedOn") + } + _ = s.SetDeadHostEnabled(cdh.ID, false) + _ = s.DeleteDeadHost(cdh.ID) +} + +func TestSettingsAudit(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + if err := s.SetSetting("foo", "bar"); err != nil { + t.Fatal(err) + } + m := s.GetSettings() + if m["foo"] != "bar" { + t.Errorf("set/get setting: %v", m) + } + + log := AuditLog{UserID: 1, ObjectType: "test", ObjectID: 99, Action: "create", Meta: map[string]any{"x": 1}} + added, err := s.AddAuditLog(log) + if err != nil || added.ID == 0 { + t.Fatalf("add audit: %v", err) + } + if added.CreatedOn == "" { + t.Error("AddAuditLog did not populate CreatedOn") + } + logs := s.GetAuditLogs() + if len(logs) < 1 || logs[len(logs)-1].CreatedOn == "" { + t.Error("no audit logs or missing CreatedOn") + } +} + +func TestUsersCRUD(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + u := User{Email: "new@example.com", Name: "New", Roles: []string{"user"}, Password: "pw"} + created, err := s.CreateUser(u) + if err != nil || created.ID == 0 { + t.Fatal(err) + } + created.Name = "Renamed" + if err := s.UpdateUser(created); err != nil { + t.Fatal(err) + } + if err := s.UpdateUserFull(created); err != nil { + t.Fatal(err) + } + by, ok := s.GetUserByEmail("new@example.com") + if !ok || by.Name != "Renamed" { + t.Error("get by email or update") + } + if err := s.DeleteUser(created.ID); err != nil { + t.Fatal(err) + } +} + +func TestGetUsersAndIsSetup(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + users := s.GetUsers() + if len(users) == 0 { + t.Error("no users") + } + if !s.IsSetup() { + t.Error("not setup") + } +} + +func TestFidelityMetaSlices(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + ph := ProxyHost{DomainNames: nil, Meta: nil} + c, _ := s.CreateProxyHost(ph) + // impls normalize to non-nil + if c.DomainNames == nil || c.Meta == nil { + t.Error("should have non-nil slices/maps after create") + } + g, _ := s.GetProxyHost(c.ID) + if g.DomainNames == nil { + t.Error("get returned nil domains") + } + + // audit fidelity (CreatedOn + Meta) + alog := AuditLog{UserID: 1, ObjectType: "t", ObjectID: 1, Action: "a", Meta: map[string]any{"m": 2}} + added, _ := s.AddAuditLog(alog) + if added.CreatedOn == "" || added.Meta["m"] != 2 { + t.Error("audit CreatedOn/Meta fidelity") + } + gots := s.GetAuditLogs() + if len(gots) == 0 || gots[len(gots)-1].Meta == nil { + t.Error("get audit meta nil") + } + + // access list nested slices fidelity + al := AccessList{Name: "al", Clients: []AccessClient{{Address: "1.2.3.4", Directive: "allow"}}, Items: []AccessItem{{Username: "u", Password: "p"}}} + ca, _ := s.CreateAccessList(al) + if len(ca.Clients) == 0 || len(ca.Items) == 0 { + t.Error("access nested create") + } + ga, _ := s.GetAccessList(ca.ID) + if len(ga.Items) == 0 || len(ga.Clients) == 0 { + t.Error("access nested get") + } +} + +func TestConcurrency(t *testing.T) { + s := newTestBbolt(t) + defer closeIfBbolt(s) + + var wg sync.WaitGroup + n := 20 + var mu sync.Mutex + ids := []int{} + errs := []error{} + for i := 0; i < n; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + h, err := s.CreateProxyHost(ProxyHost{DomainNames: []string{"c" + strconv.Itoa(i) + ".com"}}) + _ = s.SetSetting("k", i) + _, _ = s.AddAuditLog(AuditLog{Action: "cc"}) + mu.Lock() + ids = append(ids, h.ID) + if err != nil { + errs = append(errs, err) + } + mu.Unlock() + }(i) + } + wg.Wait() + if len(errs) > 0 { + t.Errorf("conc errs: %v", errs) + } + if len(ids) != n { + t.Errorf("expected %d creates, got %d", n, len(ids)) + } + seen := map[int]bool{} + for _, id := range ids { + if seen[id] { + t.Errorf("dup ID %d in conc creates", id) + } + seen[id] = true + } + // final fidelity post-conc + final := s.GetProxyHosts() + if len(final) != n { + t.Errorf("post-conc hosts count %d != %d", len(final), n) + } +} diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 0000000..30ee19d --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,82 @@ +package version + +import ( + "strconv" + "strings" +) + +// Version and Commit are injected separately at link time via -ldflags (see Makefile / Dockerfile). +// Version is the exact git tag on HEAD (empty if untagged). Commit is the short git hash (empty if unavailable). +var ( + Version = "" + Commit = "" +) + +func resolve() string { + if isSemverTag(Version) { + return Version + } + if Commit != "" { + return Commit + } + return "dev" +} + +func String() string { + return resolve() +} + +func Display() string { + return resolve() +} + +// isSemverTag reports whether tag looks like semver (optional "v" + major.minor.patch, pre-release suffix allowed). +func isSemverTag(tag string) bool { + if tag == "" { + return false + } + core := tag + if i := strings.IndexAny(core, "-+"); i >= 0 { + core = core[:i] + } + core = strings.TrimPrefix(core, "v") + parts := strings.Split(core, ".") + if len(parts) != 3 { + return false + } + for _, p := range parts { + if p == "" { + return false + } + for _, c := range p { + if c < '0' || c > '9' { + return false + } + } + } + return true +} + +// Parts splits the git tag (Version) into major/minor/revision for NPM-style API responses. +// Returns zeros when there is no semver tag (commit-only or dev builds). +func Parts() (major, minor, revision int) { + if !isSemverTag(Version) { + return 0, 0, 0 + } + core := Version + if i := strings.IndexAny(core, "-+"); i >= 0 { + core = core[:i] + } + core = strings.TrimPrefix(core, "v") + parts := strings.Split(core, ".") + if len(parts) != 3 { + return 0, 0, 0 + } + major, err0 := strconv.Atoi(parts[0]) + minor, err1 := strconv.Atoi(parts[1]) + revision, err2 := strconv.Atoi(parts[2]) + if err0 != nil || err1 != nil || err2 != nil { + return 0, 0, 0 + } + return major, minor, revision +} diff --git a/internal/version/version_test.go b/internal/version/version_test.go new file mode 100644 index 0000000..b5d1134 --- /dev/null +++ b/internal/version/version_test.go @@ -0,0 +1,61 @@ +package version + +import "testing" + +func TestResolve(t *testing.T) { + tests := []struct { + tag, commit, want string + }{ + {"v1.0.0", "abc1234", "v1.0.0"}, + {"1.2.3", "abc1234", "1.2.3"}, + {"v1.0.0-rc.1", "abc1234", "v1.0.0-rc.1"}, + {"release-candidate", "abc1234", "abc1234"}, + {"latest", "abc1234", "abc1234"}, + {"v1.2", "abc1234", "abc1234"}, + {"", "abc1234", "abc1234"}, + {"", "", "dev"}, + } + for _, tc := range tests { + Version = tc.tag + Commit = tc.commit + if got := String(); got != tc.want { + t.Errorf("resolve(tag=%q, commit=%q) = %q; want %q", tc.tag, tc.commit, got, tc.want) + } + } +} + +func TestIsSemverTag(t *testing.T) { + ok := []string{"v1.0.0", "1.2.3", "v0.0.1", "2.10.99", "v1.0.0-rc.1"} + bad := []string{"", "latest", "release-1", "v1.2", "1.2", "abc1234", "v1.2.3.4"} + for _, tag := range ok { + if !isSemverTag(tag) { + t.Errorf("isSemverTag(%q) = false; want true", tag) + } + } + for _, tag := range bad { + if isSemverTag(tag) { + t.Errorf("isSemverTag(%q) = true; want false", tag) + } + } +} + +func TestParts(t *testing.T) { + tests := []struct { + tag string + major, minor, rev int + }{ + {"v1.2.3", 1, 2, 3}, + {"1.2.3", 1, 2, 3}, + {"v1.2.3-rc1", 1, 2, 3}, + {"", 0, 0, 0}, + {"abc1234", 0, 0, 0}, + {"1.2", 0, 0, 0}, + } + for _, tc := range tests { + Version = tc.tag + major, minor, rev := Parts() + if major != tc.major || minor != tc.minor || rev != tc.rev { + t.Errorf("Parts(%q) = %d,%d,%d; want %d,%d,%d", tc.tag, major, minor, rev, tc.major, tc.minor, tc.rev) + } + } +} diff --git a/internal/www/404.html b/internal/www/404.html new file mode 100644 index 0000000..3da5121 --- /dev/null +++ b/internal/www/404.html @@ -0,0 +1,27 @@ + + + + + + 404 Not Found + + + +

404 Not Found

+

{{MESSAGE}}

+ + diff --git a/internal/www/embed.go b/internal/www/embed.go new file mode 100644 index 0000000..ee0eeb6 --- /dev/null +++ b/internal/www/embed.go @@ -0,0 +1,9 @@ +package www + +import "embed" + +// Default pages for unmatched hosts and shared error responses. +// Override by placing the same filename under WWW_DIR (default: data/www/). +// +//go:embed index.html 404.html +var defaults embed.FS diff --git a/internal/www/index.html b/internal/www/index.html new file mode 100644 index 0000000..d737671 --- /dev/null +++ b/internal/www/index.html @@ -0,0 +1,29 @@ + + + + + + Welcome to Helix Proxy + + + +

Welcome to Helix Proxy

+

No virtual host is configured for {{HOST}}.

+

Open the admin UI to add proxy hosts, certificates, and streams.

+ + diff --git a/internal/www/page.go b/internal/www/page.go new file mode 100644 index 0000000..d14fb47 --- /dev/null +++ b/internal/www/page.go @@ -0,0 +1,34 @@ +package www + +import ( + "os" + "path/filepath" + "strings" + + "helix-proxy/internal/config" +) + +// LoadPage returns HTML for name (e.g. "index.html", "404.html"). +// A file in WWW_DIR with the same name overrides the embedded default. +// Placeholders use the form {{KEY}} and are replaced from vars. +func LoadPage(name string, vars map[string]string) []byte { + wwwDir := config.Resolve("www") + customPath := filepath.Join(wwwDir, name) + + data, err := os.ReadFile(customPath) + if err != nil { + data, err = defaults.ReadFile(name) + if err != nil { + return nil + } + } + + if len(vars) == 0 { + return data + } + s := string(data) + for k, v := range vars { + s = strings.ReplaceAll(s, "{{"+k+"}}", v) + } + return []byte(s) +} diff --git a/internal/www/page_test.go b/internal/www/page_test.go new file mode 100644 index 0000000..13e79b7 --- /dev/null +++ b/internal/www/page_test.go @@ -0,0 +1,39 @@ +package www + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "helix-proxy/internal/config" +) + +func TestLoadPageEmbeddedDefault(t *testing.T) { + t.Setenv("DATA_DIR", t.TempDir()) + page := LoadPage("index.html", map[string]string{"HOST": "test.example"}) + if page == nil { + t.Fatal("expected embedded index.html") + } + body := string(page) + if !strings.Contains(body, "test.example") || !strings.Contains(body, "Welcome to Helix Proxy") { + t.Fatalf("unexpected page: %s", page) + } +} + +func TestLoadPageWWWOverride(t *testing.T) { + dir := t.TempDir() + t.Setenv("DATA_DIR", dir) + wwwDir := config.Resolve("www") + if err := os.MkdirAll(wwwDir, 0o755); err != nil { + t.Fatal(err) + } + custom := []byte("

CUSTOM {{HOST}}

") + if err := os.WriteFile(filepath.Join(wwwDir, "index.html"), custom, 0o644); err != nil { + t.Fatal(err) + } + page := LoadPage("index.html", map[string]string{"HOST": "override.example"}) + if string(page) != "

CUSTOM override.example

" { + t.Fatalf("override failed: %q", page) + } +} diff --git a/proxy-manager b/proxy-manager new file mode 100755 index 0000000000000000000000000000000000000000..f2fb4d5b63ca2a42b051d13fa1731ea811edfaee GIT binary patch literal 13868622 zcmeFad3;pW-9J9rVA#B)1PKB%!Dy3KB|*?ch)y8D8JIv2uu-taLQ||(Bbk9Hh`~uD zx0lhWsI}F8OZUBYv4E&GAxK!P1W*=f6>+=cSOsh$kji}D?{n^*nM{K8`+J_}_4@ts z@FH`Ub3SMJ?B{cq`@j_6)bzA8hy5?zah-!t?xjM$@>mJQ>DCP{9!IgGAAY~!$aD0; zbEbT!(mi<3fA+Q0D%!p}Tr$~_feYc@)ztI5nn&K)*AeQq!@k-rBn5sn9x_0^xA2mVCz*1!1$VUtXI(uOBJ8VEK|A{5D%)v2pY3Ajx39C`^Dj~@ zIU7Xx_cmPjxBu@?><0hhb-O&O5DO3YjI!{p-a6dY)xLxQoDAPEM$x5VjDkB#L?->S zinYn(2qKN}@oaIrD)?d7j!J@d^r*i9z?n(#?)!c$^Skd`D6csdbbsq=zU)f$^^&{*W~e&v*RyI9|q*;2jSr zc*g?@zD8w}_4C%Q$G*-1JmtxLZm{4REcl}-@OJyHZaL}!pOFmTpz3dEQ1x%I3%1H( zACmvo;sqtg&Q={%@YO*Dzs;&Bwf{E$4ZyNY8{X5b;62R>zW&PO+IrIe@f7%$^$Naa zy#;^%=fnRX1-^Kjf-l~t;JZVswkE&(WeU8NKCYjX z-l^@bEaP%xXP=w`-!NY3sfO_izTVDgUEL|qUkCCj`|tcD}R0Q{N`nf7pUQY{B2QwmSmd zc0tzlf)x1bSN6!1>Q^3>*CmzRJK&aY6F=l*w$bkY;SsON#KR*VlUFg$=4|=saH~uF zcO>qT;XSkW$u!UGC*<|;r=MRx^^1hJ1zJKSe$IwJJI5B>$Qn{Jx>ftDyH~IB+Q7J; zI17Aru7V%&Ps^@aFe$}3i0$6$Uom8zgjlw+JN{DP)A1tp9RWXG`y&beMfscfNzMBf zlH|LT{*Qc2!T)t&b^_SWoAjp0u0I9-!*%OruDLIKe*bgN0)O2tnwf#fR z0{`)QTP1w|SxJq>Z7Tc>3*N@E?f2RKpzZhBrKG~&hy==@4d0@9WY!kTFU*rqiJ$Jh zaX4;AQZl^lKiYofq6DbCONB2(gKXJL&iehQ_sYjVq%=6?(eW&D*=o`XMLr`_#v zOj)|+0gG7Y6PaGsSnsvKwxg=UujJYGCQTU!6VkuG?;sWz$kn7fhQu z&+-0cdPC=`Gw&C@qQ$b-ZOxqdQuecB?!5i0SC1QW=b|g_y#1~~{T21aS6^}UxGU@K zzH+RiY+l*id2@u`C4wJ0&6%^D4zK>QxfG)>Va&)8#vGS0>YT!upwyB;;_XN@zUe5_ zx0n|rzpub7*B52DMR1E#H|O6{wxH~mwi<0zBU&4{`z&@m40qT~ZublPYJfVL!N38nj z0Nbkj^YVp0H?L6WzPw_eUY_Ui;Z8KR_^;6l%JV9<0$*OWRxmfORx5ZquK_Sx!B6tS z^7@;+b@KXb-tXo0g}fGAg)#EBFN7SM2I2lMRKg-udMZ|p_XEsoG!~c@p}BcZp?@qw zjd@3rqrE)ONp&w!ze|M5^W1ndu+VywW0pv;t6t*J(42?|a~gim(nAr-x_8DCsKz0h zTKwk={Y=sJqCG{i*kO!r)keaXvjUUGPL!~$H^^16IWM$wMt$7EH zdv`h#gT)U2)u{C?K7>k5UO)zCd)Di?rI|Dz1E4VQE>eqOYf^hrK3)LoSIBDKk8DjX zfj^<-Z?Tki>3Bqc9Op+x@8Cx{qUnUt-x1oBH--L|`8d3FVGI^V1t>AkAxd`C^+m^W z=HJpLjI1AA8bZ6qFTUqCWGXIdF)u?k=I#;YjxZ2vl#W4Fk;?KQ)iK((xrE^ zYg@q`zvzm^Z2C#ut@?vs z%S?VU4ZtVANVylrGEo2eO%$ETBPcgjU%|dK<8=yH{IP6ajrK`PQ40m-pJ0jCsq6(x z(>DiOJX%3!HWYidi$8Au6qYuirX_D9C6ka)d6{G)M^TFf(U`psk6J-v_V2B0i*+R- z75HnU>pDD^>7Svbbd-`VOQ~pjS8Mz>61+xco)nv+LqgBYGhYK5q9e3X4M^**kK58j zu*>5g?Ul+_`|*LgXs9ktiCnNP&HNP!fE8dQ zaoX|5(mj=m`_G`YW+Vq4rkWAZD<8=RX+Ymsc|MeHC@V*KM?C8pB7>;WCp*E8mGj#Y zRY-f_(|3Yzi)sIrn9=&=2t7NGK7gBMPg0LJ`EK+rwp$q4dBR|R{gc>Ulv)h^lPETR z$M(NO%$ZBjc4{8!RDG)5oq^^z@*ih=?EFpV&c7!)|GabL z7e+0_w%Gh_GLSnN$YOQ7J+)5cek3{f@$957#O=48ztV*o0CHzC$V(|8@NZJ{`;zlN za`ybP@G;4mznYR+*=M_a;6FL@_~gu~G)sP-1OFR7_>E;>rVp;~kL`=?ExQ%A1|IJ% zVAS4tDj6R9`yP1LrLFIPVcd7gTChuLJ1-^s9>|72(sW{}n>=FNO5S(DpJ_dk38@$= zj0HojS8(t2R`Z@|PDePoY~Ire1&=R)v{AeCXpXktGckL79q3PF z&^X@GW?n-NRzIMgB*x7}mvDRoj7MMW*5A|zSu(UrAG-BXxIwqHc|!u`VT2cdH)-qr zX=$SA(2A?|lfm~N@ao&>G3neua!&%SWhYu10^2Zd$jlHSPdf0wVhFfXoIEH>b}z{i`d%RHeP3UP z`8IyS=JWl~K83Tw(H71kHE}bd+Q(=w+o!E}o!FdiA?tIRsIB=PAkNuLSg<#M_e0T4 zZ)iIE*4+Hxp`?D$yz+2gNUblgHi5sU?b<`{ zN}s1O?@834t)H7WtJx(&vmx^P#7Q9M^!33bX(A1yq7`|IeW7V--jbtU&39CU7UWG4 zC42oNrLH+59=S*>&_}TfEtZm5+6Jb#UB{L~~Vn%gP1X6>R-X z=)0_T`EqxOv@;m#10l%&v=V}nPyH^`XO_##EL5-BvJP#!rOl^r^Xa=yXBirzAJrH? zF}pl`=rBLURoT%3-1+p5=NO*}o5Pcy%=6^KHko9mB|rT0dI=sHS^vx&l(*|IjO_VB zS+D-=21nU*kQK*s!|`MKoP8YT>NQ|9j9)`pe}8eB!>s=^9z!F4y=ji)InJBFv9!S- ziGyQY>LTonIP4Dr8#X5Z7*ZFv@}L4d-xYao@_2rEb9r8YxqpPhJX|{I2rvt9?S^$h z7O1+sg2-BUunDyjzmrx0{z-*Vt^tLNoK zA7>-%dSQB%qrzNHnd=`i*9Y;Y_IhK(=fq9-`GG#d5FT1cG^j06-rr?;`@0v@=!l#; z*(+vLKD&IlWR9e=j>)p3|G#K|$$zE&hO=Zq;9_lq$gC-ukr~LwT_4=_3G_FFvt))- zd#okJBkYbp=|AOIT$J-%f2cU~7Z-uY5vYQD5$9X;s*93&G}>+zgTa$v3qUg5%y0&> z4dE)8;R+0t(c==4^Z704=D$HRa5xBWINuD)h#?;#6Zz&i%ANAB<87k-HlG^StzFM_ z@7^o4&z;IX$87r?+|oeP6GoBYXdfQ~RYzgRw8j#cxuWe6T1(O13Tq#Of4}|y{xCgL z;BTFX7QtQ6R{s_SiO@Z1%76G&doaWo1v^D(d8~(C4xY+f@${EnB8|a7j z_0cwc02L-<>BL^ODA?@_-GmAjKw|a3c~2hlwsu`#k^4qPXhb^SR>4Ke2n?R0ZOBfq zDO+{=?z;l_@m2H-_{|L5g@nuDULkZ{w(7IHYXY}SgZvDheU^MIdW9K-YXC%P9bP8U;J+C75-R6aS3}x*?{9 zlqz~ayy$P?h55DarEX-1)5v-x106F4g>i`@HrwJBvF%_W?cvoZxS>AB;r|e$sA0mW zay9Pp-_~U_p-le}FU*$-g-)PMlrCfX&4VMigXu7sZGd3MTH!*Kli?0(Aq~yf){k>~8qQoE zcsJr?Z(<;?Oy8k}d@_9^iCP+XFH+8QxKWD#JG9VWP%rxZWIDQEvP}#2B_|{L(t0?{ zXNK4Z|QX^%Nn8B?0) zmVgFvmgs_IHOE~m(fDyY(0DP?_~S_mgJ=xV{1_iYS(*RG=CB}MkUsMXm?-RbENt~P zu$d3y2mG}h7a+lp>Zdi&9WYG9T0}{w7HX0asX>eI9(}00lzvs~+r*a_uO@FTA0WF> zuF{vhV2)*>SFkjAL+|0b5lR7Q-fbShgS6ed5&Ac$%crBzS)`BoynKAayb9MaaSqmk zlVL8*PS%@|*Lp;zl_FK+I|K7&mW`+c7WzIZ9OjYbY0#1$3N|n^Xb&(WbcFW?O)ui? zfp8%)-%5N&CJHxFzob$Nkt$>dLW5TQh@irQ)C*N=B~lk#sb5#A)kr;6C`+yt?G1Ed z`>C2Ae~;kJ4eIHD%+oAcqP>A}Q!ax8aQS+fZJm1hlgjpcKD9S&!^LXqAlcOB7L_fe zvUSL8S$~SHm5W+Ld)Du*+hFPT{3jd^KYXY`VZ1Y=MV#Wr0B8mfopnE7J&C0vQ?xI~ z7Ws^Emv%x1jm$hH-X2c>L4GJN#-M6s#(d^%UV?3i<_x)xwH;V$baF<7nS8s zMw^pxhZt(G^s_IpFL%r|2Byz6=BB%58Vl0hGmS;*g)@yi(>*hd73r1J4PScobR^XJ z^fwV7Ky4NJfC@xHy?ULiLSL9uq2B?kvpgR-DD>*{i)R{Z(i>3EOyjY1(#32qjKlas zgZ}XB4UU=mz;xV>81n>fed#W?EuRb^+g40heb85-f|=;X{fR48#zJNk#Ei^XB{P2f zbCuD9jJvFimCU#}p0QqL++k&`M#i688EdDvH>Q)jth|lsPvSvlUnjGxz5t?5LadQp z3U+2_p)HDx-~CLI@mstoGA`pS$mmNVzAeIOs#l@hs){ zsWBEmNoroflH%0-0-m~2lRTWD<``MpH~w>KnjfRG|5sw3zA_F2r0o7)oS2iZ_#9$> z7h+};bGVgJ5i?G8MNGeyk;FW4xhhc+GoDcqbC#8n#C+At7$>HMm?UC;Nj5Z2%pXVy zo0yqe=rTpjSGpuIU*sj&hIzrPU-1^iobZy;7~>EA8UpF>kYxNm5`(4d^K6xHKc3A4 zS0t;1ZxCJ|c?U0{8J`I#eZ+m7PACb+eVjQIM87QII?RG_Oz6aD&hK=?B039U5uF}b zL}#V)Z@OgRgCS>9{=E8f$lqkh-;8`rST5X5rH4X7L)L$Z%5yHtLM8c5tF~h5lp&YD z#%yy@MQF$)Rz7Ixa;LEKffz^|XyxiXd~9mR0O+PK|61dmyD8h-o8q`umtEl9%jCUme5uSeiT?zZNvOHd15 zl?OZfY7dS?>2QxHHT&`=69eQ1DgVQJRExzbaEP)|QU>~Qq(EZAiAOeMF#bm3FAE*g z)-TALoV&MqXz90j=CL*+o#m6%YvUo_~m%lc*uVt%Dos_zNxZ| z!tFwN`*tR77vMHQ;6-SEH*BrK5(adop{|d>6yYsxoWoSSP?DMzNMY|lldOR#ROL_p zHGek1>4@CMaWnEdfsKLMk3b|BJezC=STML4p{5I-L*WiBtplk}yd9W2iGV;Wn|0Pn z5IH{e+T-K+C>P5mFtZ5%N|elT1#;ol=M>M$2_TA5IjnfjumIvIFy+JH|INobVUi#1 z?>?YD(m&Y&i$0MuaJ3$l|Me(D!D<7vK&3Mt{zQCnj#F!T3teD~*cz>AH=fucwhyh+ znp)HgwoGgKlggWK`~P$DwWc4acZGm2)SAAnvctV5e6iNlpk9;|&neNG>SW$I!iKLD zTGOoxz7p`2TGMQmy-LAXX-yvW;-=y`H)%~*Dfq>4_{Cb&Cy8L5yy^9U&~io(+m7vAAT|=y?8C(XieW& z$=}7LcrAamrf=a_7~x;=QnHp8jFFA-@6|Iefp4Hh@_g}H{s!jbkqlS7mcIcXa&N;8 zpm_;Q#B+yw<|S}BvLC=r@ml@{M&j|HeB>_%&*0fYI_t#<`45*IR;#)^v`5 z3OP6_#(2EX{TM`KzpdBKM%k-7C@#s+3HTwp(n{tbYX3cZ=2! zF*S%`4nbY4Hn>>1=>jH!)$NHIAnEm+bZG z9X`$1<_&f_wFlP&7I)V#y`Z7=)M%{j(;9z>Y>@%@!F$)z`B>x82Y*_P=HFJM?Qa$1 zW0*?|d=Zl~E)i^Zd4r}a`Wl`J@l+VaVzaGo+_|Hel~*~0_QC;C)bg!?7hgMYl=ht# zu+bFobxby4=>TCM60Ko$9?+&6<$XFa^6A@&M}I(Q+l01V6txQN#qDCRDT0R)inD;H zhX%fk#yc>j>Yss-O6M|2+tpF$bi?1LQ|$d1)58d)$hX(??FtmS_Y=<3YOe}ymnb^v z&qlesm^Ju5%MHjzp``*b@shpT4_YvVEJEdFv9{ikpf%+J1Zh)U_?hMEjv}q83sEqp zx|!-uP2Fpy7BaOkHTBnwpar*jfJzTgjK5Bg_R#HkE0w~_XYRfbf1~hM~q#6bCI@P*5aqTV|@=55&u_!R| z=eWX2$s^YwVlBb0$fLbxsS(;;Ej3!T^;g>hccaU-V!5|{i=-hY`LOm&3%*W*hRQEK z8qG^GFCGU_WHaFIPqmGEylLRLb{OLJrSFR1JDUFrM3P+uE;#6IN7xtKyZ5wr?-2kx zE!6Jzd1d8~iX0faj$G>aI3#JKO7MJ9~A$ zi;wmK*HHS@C`wn;#h{MFhA*_>;uc@%@{6||xxXHgHL6jT-1CO^85AChzpuMr{)hkI z%YXMrK-#_d`zt$yzwJPXH|-TNi?8IZl^wp4Py7`={jIaYf#xt`ZqaWC(04t0<3a5< z@?tR{f!GoX)kGHncuAqV{n$|2jxj}=KPxg8E;X&5GEv{c%z_VVzw;xfd*zD+{OYs8 z=Mdf<+4Q;a;2tP5x|ouW9^~$!hSGdlW*zk_xl1ZL&{e84TyLb*-pZdEO6cAESxRYq zfYOM_t$#26-oxL?8tu?#{JoFAEl`3Twm6Ak)UygPJ*eiVp*XN~R8f)jEhz=|``}N* z-;ET~Tiq{z=6@T4`r*s3AEI>bOD!iB^KT((P!uk4Uch?nF6YwW!a%5hC}5yk+wlh# zTe2JL&ygE$#l@ZQJVrrt?xvjsgu{OgJb=HGt)L{6R3zww%zHmh(vR>@01EwBa1tuA zhoKZD2LevfP7fEn&jrVCVckol$<`LVr5iUpBa5sIqNGDx-30d<6D=++*evfl)0d5{ znF0?!GpuYD(VJ8iPrt?2UXT*`zabS*}(2XT~+MvIR-mK8oy9+4?TKo()VB1)Ix^ z1&)6MMrKb`b~N&9WHtQ7|7Kl7lM2}vp_7jV$IfM=D^y2M3F8_cd-jP;QO%7;ZdduV zWs~g6yr`^`Kr(-#wof9Z%!}$kYSj1hq;mE~xFHhtxt0}uS_aj}!j6HXhk}WBgK>|G zRiFsm?#9|Aus0(gl1GA_qn1_M)f2qjaa5MlO96@Y9EtoEz{s+on2PTJYWXx?3nw~l znmiYwY@inRvVtwGD^=s(hFA=hO6{}#pR#R`fW0LX)_l z_%NjGFeL1sR+-s$hRu*GZ+iwSqKHNBXehnlBB`10fQCWq25P}Nw8I;!b=92QdQ{UI zZ$N^DP5;niUS(*!1)SQkbauE#yY@D1AZA^b=J?WfiIS5`{=ru>V|=&l5fNG$6KT7A z1^d1Fgx+*0hX>G@bMsuBigDA&M_l(bY(!phviPvBCZm)3X*oY;0G#%(SWoiLgb-&8JXKtZuI zzLB``9R`TFu?2+x)si>rc6ecKk&t9h^@Dqlw0`Jfj^8k~p>%4FB;8k0eB7uW?ru<} zKCxK_Nkb1|4h;S&?Boj5Hj%KZDrtaZ57k_-&tB9eTYVb!A*naoDg5`ec)zf8UypRl zqBSR_C!!AV(Iy6<9?bFPiEi;7bIGS_L|BPP2ga!^9RCuL6EF@(tA*Nn?EUHvy37Lg zs33`gRKIGB36BUd7H7k$D*}T>49gndNM6|0A;&KRxFQl0o13v^2u||KDICv~ho*Iu zHFWk{c7=E2ch$dPP;$$LiL?_~Pq-dy31NyJ=)f>!=@wZ);z!a4Rl*zJL@vR<2e6K2 z*%fRC-huJ>uL19tW~s`tj^N~*NETZ8R!(d?!gBGdjf~`uS@$x&BrGg>IGC=&j4^ih zghn14fY{f<4!$cE3(t5L9^E*MT1zfQsKB^d-;4OtA^8gH>$iBY5y&2pt6%_^8R=X? zg!h-5_jLAUyixf-DvZEIMsSJp%klnlIZK?{MA^RaiS}XERezO(di^adi9jnhrm+F- zZBGL|=FH^AB*FuXOqj<{B0?UopHYnHk6w92mhVZFpWOfc3|O=C`mUlAUj3*St68zS zR<74D-vM^H!d3P=QB|Vj=BjQLCORB7k~;Z0_1}|Jzv`>1eIt(^F&Cbze!1H*Y<8VU z?slRTbVc)P!ja{`TT**cZ@nDfVEh7{zolh~(zK(o*wP{5g+`eL)P|O1t;apJoK*~_=!wIAyyYu`)@-#t@c-w*0o{V!eM8f z!$2x^H%#UK;IBp@iJfmrXge}MFgJ2g% zLW{x0@$yRvsIC4cv)Icxf%<|D5&AX@rXoUMxl*)tVkzb}lC@T(9c2@+$ma9~FI|8J zA+jN~S^FW>A745Lp^i5HWds6e?>6oA#Z}}D4^3^cEJQAS5NSKOHpp7xdh~f7R8X|t ztbyS~7s}BltXpb&((1Ed5zxP<25%b7SK2H@+D5*HRW&TO3R)3!izFTIdZaI^0p85n$f@q8*)V8-7w)MA>&)mUV!@BXThOZBJpW>u{?OxCqQYr?OTLf}K>*($8;ONMYlh+H=c=Sp|3pcbBB!|& zjR>bGQM2rLPs#jds>i0}a~}$^eIBM1N%z3g(+A8$Ov1*= zJFswd1vcqm7Kh!*F*hTD`)dyQ5y>8z{ZkTU&=6d-FSh_qsuVh=cs?$)FK*Vpyq(u= z$F;A(DgnCa5R{Y5CqWXAC~wP8WO*;+l3ZRWYu;V9&bsa4UXXJ6v7SijO!Ai!npfQ^ z{5+1`b4S^8L(8t1Ock>j3mlisg1@eu z!79k-+gT3t!V|F=CK&r$BoeYqxvEQ}?JlXe1Jv7rNpH>XTwr&F&2dTIG9Ub;C#9}T z?Vj{Mw1=Kf^zT2W&t^I64sBMZ}-jo z{l_+$rpEh`wEtuggi8|XEc;Ke1!E)n*^_E+a~~Y=o>Y_i8TN6_L1_;j%WEMxR;WJ6 z!>ed)oAH8sRRZ6<4dh=|FARIn3w(5J3tN#F_zPVOIB(_+AJT?kHNd^HG;7;zs1kEk zYgEIyj#Y*w3~RGML7ON*oO?26ni}&OP!88qLJPzDk%j;}I;{HAI+#V-K{BO}ObJ#{ zOnLHn@7FzY;fLkHW+PMdjeWkJDuu>KFI1MA*Rv8ZR> z@ysh*g1jui?0gd}ewE7iB}zg4=c_DxI|RgfQ~J4zmtd^Gf{muoJ^R>M3YnvxA~a|8eHV(jV|W$~CL#It^`VmP%P_CM;C554cP>6XS8~|#`Zzu<1 z*%Ic0p=Sni&y&hagQK#;8Z?UB&2mYp7qfubciMF z^K7J>A7QDt+1Dj=KJbxkpZBc>iows7<{DLgPQ3gs+Hy3#(mY?4|4{ex4^FkY|(_gUE}AGFIa*chbC zMnOfeQD$HCgiL}_(h3MYc(FDyB3hg>BDxmJM=}#QvX&UDx0YZ7tJNfG)mdR7A7&TZ z5A1?TkyY`aT)~ZX&`(pyON($(+-ki)@RWRi5SOI)s7~obX&zIlJJ&oXb&GmZ_Z7Ln z;umUv#mvmO{pldqKteh1p}&yVDKWlA9={WYyYqr1zPwq7BzZ#&%bOP52pFrdyeh5k z1D{Az=#RzuV;$4m6`$Z%-nZZi+X#e5GoZDo3W`NY@tRqPfji$oaj0F1a(+AO;P)PN z1ajeA9>9&c6TU!Wi`H~K>=yBkVVSjsu_S93bB;#NSDEvN$QfqVzr*l$&k8fw^sIbq z?ft|ql6+bicG9+Yn!UdM!SiHY>L7?Hw$iA4iS&pp$~q_l+?LN?fbZlWCvNWG3e((O zYdSyb&D?RMyCzeX1UOsAN^{=Gx1lmvVz{6fKxq$tgKtn%r6|CBn>RPf8eePP9zARGrcZbjS%aMEb? ze!iCN^P|3!quOc)*QC}K1+P-3(7s)Wot}yBiEI}T-UebjG@_XFmiKboCd&XwrNVD8 zmKL~4ie`l1kRIj_0k{t7e{{Jx zzU5dQbs#nX8?|an2X1M&2L1gzQWd<3i&OkDiV+SR!uWsCeF|=Q zDxBPS)2)74hP1;_tn``^Ez^&gqx;JJ5r_KFzc^?P#-sTv9?b3h*@B;QSR`(D!XaY7 zm-)my=h9v@_}EQ?%n>if`tf0!@=vJHE&l}k3}YJYC&SF0+(6HrVMHk90g{IhHnV`K z$lA%HpUcgM&9kufip6AW$QGRE$5@snZH17wB`YapG02&{U73rdAa8(x@|u{={Z?Aj z9Z+jEtFB#$1#;E6ZMZKz0R5#k&B22mZ$Su{j!z*W0z-IPT(hbKd(Zkc+>7k?xdZTG zkW-Eb2?6Xso&}s&;wKg7=7b|XP#bAaSOSGV&QDtSgIcm&d+7aj5^YMAhvTl^Ux97z zJ*Gm(Tg$?o&YCgbg!e7ofWTe;+wZEm8>L%r zz+~GE7#D$zNjHG83h4%HkOkAShDQE%igE)amx5cvOvAQkR!%oyoxEB$C|N(7QWGIa zajjC1;E^O>pgP4DxDsO^pdD%!{6KdgxTT&1fSE}+0jWTz*mOvEl{Gphgfa4}$E1fp z4i`yC_4e;;<=Z!LvEQ0EWl3-HJ?dX2OX~S;&L&D!yh_K|GrEs)~O+Xjd^!R^eiN2kT=| z^oc(BIbW5pcQ60YigUZB-+8MCk5Z$%lU&oe_JAZV`Ra!L={n`VoQDM>*7*4V$qgPv z*i3S&?Z?1P$Fs5!%8wy~NUw#=EN_52b+ZjOv^>m0p;(72{TMQ~4}J_YvJyhlk7>b` z|9DSW$TgV-%uy&p$_+BV>10_@P;rx1k~Qp6cqJpDnR9Ss4uE=rshL8Ksig1Hz#>bs z1~V7-*bTaXx!zlA#RuuX%(q;fM0WZwfpu(?qu5D(NpZ+N)W7t9qjR z7v@W(|1v4P=uo7BB}?rohv}Bz;x;SaIg9qx);uj6BTXYTsE_4Y8njsYD`WWvvL~oY zp*pEe_s55O9aN=oOFE#`BOzHkjVN3O`0tq1Z^5wz(iz7wC{}0z3rTqTLMRilWLuv> z--o8jtWf^ao3_GUZu9XYy)~WwCA}^LW`Q4i4fJO2;*)GW^*h&}++d}nNjrR@>Hn_K zcX&@8^und`taDBqNc{)$Z5LigclpGFW04X?t^q3!$Hng{W zP?hALhz`@jQ$(mqK#myN*NI+sh1Hr2)5$P*0wHAy(NzMuusAWWsWsl5df6_zg#dQF*FO|an1qg zG_I?*96+0?tSQ0po*2iT_^?#arMM(zu>vx7em`8mf~|~R#4zude9Qw)P(N(S8_A_e2iE^J`>o@@*A=&3^lxB1>%XTj5o5pf(@^1E9La>_6AH|joP zq!E%GSc6Ma2avEtCDe6G2qS{G3nc<8apxx1DsmAU%)~KJx8nUt3LzRPCwlFuK-{%j zVN>?1o-IaT8S!z**D>H38}c)#^dV6vwTHLz4J58slpNO{9LT2QAeGgfe9aL}M_f0^ zqe;kI*u$PV81m8SzCvqafE62#2d6ijc56+=?Ef}S5hZA9yX&9J(6DdAS$6_#F@q%k`@#d~GQdgxw~j5aaVxC+$4h`D%YSr{ zh25-5?myv5vPX`CJQ!K*iDuxO8d37<%CBk z@j<~xaR@>gcARfrIUMu%JUD3*vMpU+-aOFCk{OQv7I;|Z;i zdJWr?+}J*)hCuwnZ1-NC^9Ctd?cX#tV-l~(V^87WmPU= zj0J|AKALZA&ob)WzJgsiZ!3Nx$4>NWuupG^?UQ4Yk0hpWdaW>4=8MokoIN=+pE|A) zYZrjB8&yZRL5P$q6votEdz1C~z2R93V;c7a1U+Po>`(ZwLkI6aUxsljaDouF8$~V$ zugHOAWHjznB$4Ar?1A07ngTPjofoy(1JD?6W`$J3!*+sN|77JcvgCVXRKKlFN z^bIF==kYXSj&GKKfI%n^8FI-(i~c4L2HKaRpPowSC&8MlXs)VhaToKLLG#2+HUdj5 zj3tY;P4B1I^#%UgKqO;2p5M->%S1r3AJD)#OdJ4#b+>iLgfYEJXwPgD8PlubZ8$}S zEUq8O?Z=uDgz{JcNIa?7{MS@efL9*6CkRP;Vd-J{xAC#iTqdiR3A2&70Fc@P={}bedHr`? z!ESJGjdioJ`DkpRDXhjq4pn0d6OGL`cT^BpNsV>O#wHqC{{b5c8o>mFquFSw`GlOH z#&c>T!;zcWFkl7^k5B!s-pwlb4!D5SVXax@s#MLVNUZG77Zdue8-3}RU^SiwRs5&h zDjnv>#W?eV@iD9?F>k9^9q~Xvpe7C=xO3^D5fpu#!QFZ|gZ9g((I z>^>y0TiEii-qcpVO>qvbjnVsU{jfh4r{E||o;Ng^0~zhbJ)(Upx)~E%`98V8aT{#A zI>OdIYI2Xrg$6l+W0$xj59I+GhdH(uwO}x~e4~RSjFa!zeqC~@Fz&1L>McU=^qxFi zJKb`WI+md)GP;Ec9c+!-_mYS0(#rQY&vpklx14;Vd3G)^q5rND{o~1;QvSlg0`SjG ziY4So#pKov{Fl^M$!{|EA)cJZjFb%u!zlFGU6PsX~eMNi3$rDV&g46rl#3mA| z%&(8+9{I}m$R{{wYAykw$D+SW-205oeQJIdljb;&1AF3~(TBP0=jveTg%T2?05V2p zn9L)Ln_T7?m6v?YkJbMUSnJSSrik?-}UmQwVK zC&7PiZT*}+#g*_nuaJBs5wU=tJ=ZY7EfO$iIWP?u@C|OVPW^`T*lC`RMLa|RG{%w~ z)}2$dJGbXvh6-Fi$tOss!mlpgpYQoY#?7PVfmY#YCX!Q^F z;phR+S{Q&l2xX?8 z*-=pTpT~CJ#>LAZ3#=O3FEXt<7Sun zI0}=es*p01K$-hMnGQ)n$~ZKQL=4Z!n2n?8fWGxN^(lZB-I)-Sa0Aa|g`gYKk zBaULHBzdkteu5+IRaj~l`hSG|KU`r9JSzJyYaWjC6r9nWIHXR}r(m}{FkS3DBFn_l zs{2F+b>}i3L5nP3?vu!(>cv^Gds(m0Cqjl%@4@>KjlrRNSaWC8qTW@iUNWxvvnabe zK{D;DkSMoxAfI^!7PUyn@sv55>szR)Pnkn;+bdUM{IUF%v+(7Ek}sA1ql0GocW!91TYsFh@a()Rr%mLxyViuV-A=UJBwjx^=lU_)Q4^6cId=7RZD%kInMXC!`Sf?O+on2hLc%eH2+;!pH`ktQwO_Fi#-2`N(iI zN@62Ubi4=1Hcqn4W|QN%YO~jVr5cBC?CgP%$cf&K1Ef^prz?RUi4Z|Sgr%(oCsJ7& zR|nsIfb0CR^`g4vxQ1`QIEF%L=?xm__2*5G&L6XwwxDA@5_M&VkL? zK5X@VoO%GIFF_lj2Vh`Nii{<&Pg|YF4U5Af1C7=;9m%K(v!tu3RozhO&q4Bt!a~Jv z3Waz`L7`H3qj&VcBP(-9wkIP~;g2VSSo~GR!WNUOY6WHp8d#%+M>LptlzQ!4$ovA4 zi5+}4GFc|=JkeUqiF_6e{*=i5DJub?+&*J6kUK*mcOT({t2eN^BA`Ensf7`q(tfi5UhT=rAFv z5Cqt1yLpNL2vw2*691qijZ76?Ye}}T?EO|U4&obNjvUY>(R7$*j6VE0JWYFMD+Z!2 z=wqj9IhM3y;)89^7sg~v@*;jeu`hIU-kWh-SxL<0N6~K1k?O&oI;c2|9gK5WxiLwx7}0q+qpp;VEtYQVm9jD4`8yjU&2KUN zJI1Yy^UXiJZ#95g9COhtsC*zNKvg)**5)*4m+*11h)JJ8p)8b@J$R6KdE#`L^C=v_8~Iz z{6ld@MkgTz(Mx$mg6cCIh2OkOJmS4qzlyGhSD);HKbIr)Lg_fPPogk6woY>6FV_P) zRCc3-@8x7VaDPU!HnXXcxGMVGmY@$t>saF`4>W-x4Qq|rNF!ljM5!czLm@4x8y)=T zP*~C-Met4VE7GO3+Dqs-+s zvO844IGR!7U+=*Ba-bhd4Tl{-47ZkDk`~2xH*kw{`&A?8SjBBDcT~z`5iD^8T<|aE z-@%5<&~ury;oi}Xz=i18@Oa1OS6k`Y`m)i%qiM}$qk;7NTiT2{7#bf*!x>9hX%~eX zKN%F-Y5p2Z*MUN)2j*h@)8jNx%NH43Xq!CZjH4$hX^u{FvM% z4f~7E!XPPYj#D4|@XYk1mgerw>O91ng@_@3fsm9jo5)Lt{Vu@ye+MWN(5Dy(MNuy< z95k1`O$Bt7XovB|p&X-xfiPCE-s!-GHncfkjsLr@SM)&_ZmJ?Iy@fYK#!c`R+MLEc zROPT>h-zfijSQ9^+D{D!Zpkp;#$oL6$wfPcttcNmz{`rw-^k)v3Wspv@YYOM11MPx zAydD=J`_oJt-Qar2PKJ6H}q>{LMlZQvd23`U+(6$=u7$YqwU3xK%a*COC0{W3E`7+ zhY60X71@^D;rzl|RNW9fh$p=F(ZOSB%>vSeql@MI9ePVIOl~rqYjUk{lxJ9hh1thq z5%c7m^Q0G?Dg{IAYRq}E7Nn<00r(pm7E5;AKLN2pkZ$7sFt#H4KcpRZNs|S~1K)d6 zDpD#3V3ui0IKe{E7lk_dVXNm7hdSalj$_E@@|I-WMqWulC-Jw`-hT)!DLn^)swD?c zhQ8Wq9w=2T;({68lrUmgJ4=P#4&0-8!Ia~zGP>0p{Z4nX#h)zsO!$Y8O546ka^Z6W zS&#e>rfAvl&p zVg7cU0)ln`cS%bC&(>UuC3C^jTVJD`LsOFLP-tNk3(DlZaG7;~2P9v5bsPpb12Tp_ zDeD$%7bS0Lq0MYQR31!t<{6B%SI)qs%$ZJnFd$HduOh^JC9T+KhD?Y8cXnFe4-zH2 zv>^E_SbBIbk&F=iz)mv@waKW!3`PYyqfa4(O_p428kZ3_mL+$Cn=ya5Lc*^jJk=B& z5Jp{a0mHv)KKD1vQKI9Si3!i67RGEuaj`W@bVtV0Eoj=l^wMDI9Mu@0)n(S(1+do) z4s=A)kyAx%y0|t(4G@pY+fLKO7422}?+_l$r6x}9zXv~IQcUS5v+PA;)Q%!XxY<6= zw(%RqzdWDCwl7d2*(X{N>-bpW8^!@|tWWf45B(f38%|~WFSGF5a4JV@Q#hOL z*90*Hs9WiY3?@?r>phMD_+C53H4E3DY z>gM+-w_#hT{9d4?e~pXq&g3yi){9Wqfy3265x3H!$VB0x*`L;g8%}2|OIi!h&kSL> z0<#Cl@^Uh1DC@ffPk|-9FvkXGFK!`AglFj`mR|7`3d03Evm4P+^Es#_D(xN(U?H$r zt>`{Y8bYDquu2H(${Ey;ZWe}uFjSZglFg;_=mqtmtIa7-Vpm2>07ss2{s!O(l#S@m z*5sRBtG;zT8l9m1l;^wA{=yWk87IHmzifYhDBrC3Wnag0!zAJH@v%3-f}xQgUNgsG z&i!c?kwl}xTFiGhSrwe)`$LMqc<5E!zEN4p?i*wOgQx?J1hdA-@D#7)C{jfhFz#)g zV)$InvXWDQLm25+`_iym0y`o?9%ooJ6(i8y@G$oT%GhY-z(RpkN*vdq4RrOMm}rl_ zYHw710{emn+6Jc6Ou>|c26ds);rG1%8T?idzux}< zzmpUArH1Z~;PDe|1Z(qpM=+hGb7NTi7f>u+5p&GO9ypeMT4eoMk*x5`!*u@#`1ijD zzpt0r_H>~d+@AQwKIxFgv_)m%^xw%&bLgfLeV^+Ns_RD3bxwXa=CB;H2LRI6gqfv^7US1XL7V?PV~V6-Mrbg|*WCQ`v!9=(hd# zd@PVwGTn)xGCGf*$u3`Hj`_2+TF!VkkWh@}iK)Gd+bOAtm29qkws#&m$N6STK0CVc z2d3DlT&qcsdW%z(&G8810xLr6?ir!oVTHRpwDtH@9*&}9pnJ1)tjRuc+p~kV$Bwyr zyd|~Hz#eJ8IY>r~5uNrLIWnAm%pCr##EF|osv;h7Crv#Y2yUn+H`GSI%_Q6to%(cV zuypKp$YM=60Dlt^VTKv|o3nV6IaOESzf#!I@C_~X?F9d@{Mp-p*j%joF?lgqp zD<*o-clH^_t>Kt87{zh4fG|*5kBzq#$X&Bof!$DAKQaj+#PDlyxKgMLJ_=))J_;!{qk zNrX0Ohgfxr6Vl7De~u~xpK60=@Zt`^^ARCPTKNvRj`j>28wvfe+q?&jAabE&I3b2Q zufJiM0}fXGPpTc}UT@D35!>cA@BKrM?(+B|L>Dl=iwsAN33sl?o$7xi(SPtI$HgOWQ7M)T0J1+6I(W zqfbw-fuDbS4Y0MWZ>TJ$Z;iqsQ{Q*2DLJ-mVomGE88!M6e9j6~;QTHatf~@xdr)ND z%mMme5(D(BuFIgJw&N)%+M3`=LM!Ls_RQ<*Uhj^)OzA6O6+S=9neF zXHV>L5F45kdC#^w3P0aDi~dNmG{75FH$RZs8tIGJ8SDdkHV|KQ#Pl>mX|c@}3>4E- zN39rT&ZvZ3Z1-gd7rtj#2K!RuwT|kP^J~-?hHlLyVk^%wSlHpy7j{4SZK2@Mdr!ltV&2#UT* z@zcVZU_HKk(`X&}ofD_%ZralGyrF^p6iIjE+mt?I4ym}?mw}~yplyDIaS^G|Mq(YH zeXqdQ8ElaQy(ALhVptP&K;j|JCvf(2FFr7N0Y5HjO>=z#I$k*SeAA)^1yD*&`pKHJ-^RZDkDg#L{Q+BKd=Ue1k z)g>z7*VM(ZmF0?4Y&0N5YA(mbxRV? z1UZ#ffAlx1A{5q(Rv(v2Sc|}lzRP=!zp;i|+W&g))@qRQ;mIMLAjhXf>nDAEx$R1h zC*o_s52WEy$}#5gr5vxI97_(^PY$Ticb0L)DrM20CnsBo3Zp;YZnx!l8{~L<^lmz8 zNbBc~M;)1Kvz>JtxoA7HR&a&nQcCeJp@|3vDTY<4z(RAN7UXA7Y$;yMon7n>tsYv4 z{*d_fD8;{q!U8!l9`9P#OQN?Cs03y$!C8-$$Wf#Q7n&njS}zaCe=s5 zaZ0MWfSzrr);63U+fkzjD;ON}Zqm=~Hvg8w)R3R&fB89Vjrq9=-P{#hZN;yO zzi-DBh2_6gX&Y+Ov8!?^{#Mqsev*N8|Bmv4c3eD}xQaB)JWhP6rsNC`2?VPzrV@b^ zz`MluF7S&S*r*xi(2ZDGh3_mpxSGsF{Ra1p#uzb-S{KE#60=G~j-1RtxsU5WBHO{D zBo5Ph!DF{YBZ$77K&Tj-Ct5$u!dN3y3yy)T;=I1cTxHs?kCyAWiPVw3^nDR-5tZxY zp@L^(i5C1D!7ngAsLS@f3e$^1PN5L^X%1t>8khFtlXd;^S+uP68y|N>v8QA?n}0@R za5Cb0Nn4!9vA>g9)*{Ok#OeC-^yOHzko|+6gWHTLitKgDZh=FHE;24*ZUqd#1P2*g zjE_%87O|yidqgPvQPQCX!=QZ+WWsRt2S-#<n!IE@hEaBN>uxjrZ0f!xhg0zj zUQFN@3g0SZWekcG-@Eo{FKkr{JGMF+B!$ajEj8u3CliN6D*Ry0hjEgm30k?WXwHQ%= z=+GKmVnW&jf1d6N0|8Yk44f{B>LA53SdZayM7af0iOoizp*Q5n=POQP)}sdE$d4sf zttPyyqX|&3>u^NGRqxJYXF{3ae-E54tbfDYQ>WHA0#vCm1WoleUxpVSlkKOJH1z8> zxJcXmIP(;rr;B9abJCf0uBpb{HDtfdQ+3=#e~ZQ1s{G$=>uI9QQ$Ot?!I7`o=ZGo! zxUUNoaq}_Q&O23uxI5U zwctwx9%YCU%!N@NNCu9GYc0lPVhAuu`M`lxN^FnWV(W&|Rf-L~e{w&>77^;0f1^@Q zboKR5&DPPXU(nFq!ky7?*R->7dSxc~F<;v8$EQrA9sl?{u;T@#Btq7M>eWuZx)86z z2~W-3`jcdoMfRV?ctgu6{QV2{S@?4`Vyb5RCTezwaHY$<8Pnu)yvt=ZRW3P6{SrAB zGx#-FpYSJnk9mU!@SW<}_&QV@xFHtJ#O@b4DhJevykO~(=d2=YbIiW7$N_4(I9y+% z1?oWLm=!bFa1PS-GRTO>VNOVTlTU8N0kDA@TW_nHx&8{?m zx|!wRIo|S{DzOqEAH~A($+a^nD`+HX%+QaM5hn=~Ie2#L+4$pGt``1sNCwm+2c6PS z$7)--MxaA3Q2f-~z7G+J?SYkKD)eY&q0g9#O&|67+=M$5NcR?^4*-($4Zw?9HZ};> z&hpDS7K0%LFjnapE34>&6hrvheHl}$y`g%iv2?M>xUW)9x{?E=*~V3v^(WAdw-mu>@C2; zK2LtIG)>lx47I|%Oje3{)H-l~r9cfr+b}&{?z*h4!VWZTwGB5N@%4J!o zw;t}PT$QzztFpQ;_T!=~mlHdtgg3a{84KJmSLYow3*ZrfKNpc{KsbtK%u|I=55J+1 z1v*T3%Py_IA!(Viy^zt8gNRaCSQ4PZo zvp9nkmh)`(x-hIy$$}W4?_>)Q|6rLod)6i|{1db5FT{eJvc@_stks%>5rzwz%4svj zVhM#0Y)YmuzXgCE3_;N}EXoW6t8=H-Stv8!qKv?PEl|fx>g=jOm?2nt=2?q6^_Au& zvR&Z2<)DtJWWet(paBR?L;+9kL8OyJAHwNV{n$$|V-9@B<>Xu7`Y2fE7b z1RsnjvDV%l!3YFj>D0gn)!>5_dCr*D6ht#POoJ|imcc+3!F2Ni>|X_2+^959XbI%> zIQ%cP?GlSqfIoN~*nf9M&dQ;cviXr8fY5B}@p!W2tTa3Q0m&h(3GWdQfN~>CV6D{5 zYD@uyy`d3sNaa#NL@l!L?a+RhK)^XdxjSV27!8RkpWJc{+=!~^K-RW{Z_)(V=IehV zS#m7~z*k4jtuK%VtOb6GX}tQUJ{=vl`Gy<^dR55)eb6I)?ppA~@!%0ynp#TPSlE9l zXnPSu1ClWVqCIn(i?4m5f!9@pybL#Bu{D-w`K|+kD|5WT`*IxG!%tF>fLgbV4=U|mFfq%8ghn2Ivl0*gjyJktdPRFMJRnMTs6c} zMQkeYs{N68#X?|A(|*Ni-h(-BxyOQEa-CtVngkclj7#F1e;`0kclpIcb}!xCmZxc?hgtq%jnSH{|T8N=1Ja@&+T z^Vd9%vwbXEs1AfkPGvxOjJeCoA{hFHsG- zLq=<7<}ASi4H?>${x|}lGZ8w&_#2BP5zzXSorA5wkjgsMY|~DvyT|exP>g7wkNY;e7{ zeui6HU)!hPn7vC+(H|=B3ulFtnnHO-kft(w=5kyN2OQ93V z05Wm{23SFAO0@`7nZK|OGy>A-oDh}FnlEt}ktfJ^r)>>-<2L{Bot^~VfP_df>`xEH zV!crE&jTPV9Ru01*B8PK9eEdKt#a_)8NNjWASPVL|F7SW28jPK27Bt8$nzSGge7aL zJen&_E+Z_H%LrjTV0aclQNyE9q@ef^@hA{|EAyDI4MgKn2k;8ol}(4cAzVs- z{+axfx+D8VqiBMsA=vmKX=33L(D5_(PlNWrB&Y$q(xbvTYTD zMQ!KYG3G^e1Ho|^cY$aKf*=CZQFJ04#pgY;{&)ul8@Xtm`PU+Ag9wLUp{zGCAqQP4 zA2PAJj!}^g5rdV4OCWY7v1KX4Q?O^&(`!2;C?_As)hdVBQccyHtMm#Xv2k0tW} z+Mg52v}8)j&j+dW-<+U7k5NmdKeiB%{)v4|C-;H=^;HO@oRAFgwf|8D*cxYmL(vJO z|Lt-5k0Jf#xxES}f7|l7Bk`D-5$Az6AA+vE^1$)n`;rF`)9r-^j)vJu#RNr(*;q;f z0Fs$N`bXr1)lrWx^c8Z#n;cB+h;zdGpU(+uYm80Z3zB=1b{Y)vG2>e(a3px*ABZJ5 z>OQb}qC4n*Os2(=(2X^4{_~?fc*9IGsfs_ol8CQYOZ{*KUQobmsTb?vVKrD>f?#$i z>$7)ptjQ3(sX_Tys`6{C-E-1@f-Av7-Lyd-v;hi~HUsuGu?r@6ugej@XDzl#b7Rif zq4cE6C>O*cE)y(qF1a+G=jYw>*uE33RkTi)V(lMHcqReFe5h&b859Y)*^(-BWSrd* z(|?8PMwQHk5w_e$Fr9l{s-bFd{`mzs8J~JuH7vPOHj)bN1h>TAgDtVU^kdwf&n>a1 zq|e?WjC&zZ<4!Wh!6c>NI=K+3XwMY5hWAz=WOF`kaiz9lWoE3sMqio9d8w|N;L1!# z0InmV%{17BY|MMohe1fYTRUK)J)8+cMC(qhMj)W}kO#h2WDkf1<&&nwqZ3oR6}nlW zA3^y(Vs_`WbiyZ%MZKKII|Zc} z3pg>6R-wNYUCT-I7)}w(oQU&%&S*^|(F%02LYr~~e_irZqZL@Rjw!x&YX%QZMiKr$ zswFmn{{-Um@-*X4H`chm9)NL}19x_FczP&%G)G4Gh8u=_7+2$*uXY6Iv4&C~8h@3s zTuuvDVzn$3V*a$|fjO8!n3-9IncH%GW+ooaE5qb%xqcqDBYH#G#Vk{9fC77PmMoMt z%wH~gCrpSih9I<|$|!J$f>sNe2& z7WJqz`a>)JyfxK6w1HnN|6rpf`C1cvD!lwp{DWED%mZC2G*hmn>82B~|LniPN02VU zBMWU4@vDMvF2eJFi5tz(f0v6ujw+5`d2Sa0{`*zQPQqW~ra?Lhv*;vLz&SWHBP30i zD{kvE6U|OI2SWrb!6(u?h=|Z6j_Z{b-1lOJuSB6x84e$m#KDtY~fZ_S#xoYuj737J2v} zV0l?Bpdyyms;zY&kFBUJ4{6Q+`&+a3$vH`|z4w3b|MT}FIeX8ZS+i!%nl)?ItXY#$ z5%8Z$7A$!tYkG8qc6#FfI~~Ds!SSD~BbcU`NLOX+2gIoeG)2=7dNM)o4;x``Y2)Ab);jct)&q6J`+W!qD;nshlBp_t7lmutLTmGg{vYBg9S*wP%YkhC3 zLiPVlRVe-6RTU2S7pel@Jy-XtDx4!#p{`d|;k=Aq5UL8^9(9G%|Awy6E?v?o3;r9S zvQU16_~i4Ig}~COF6c38RX#PPSG6HChMjz`?Ha$0 zrr$?{@!KT*ewu2SE*Wpy{b6B4oc$r#C2vxT7{oz#wBVenyvhw;#xxd_J*xLj{?*U9 z5#lmt58fk!!Q14o&CP?_ZuK@f;~a?0)w(1M8*|Z1ZrD!iQthR?UAQIej&Bcjl=I9^ zlcU<3@6tB^w7{ShAeE``e`CznX2xu7Z;E|%!JPlKL5Iui|5!ht^zRJ1@?P}w&lz;h z-3J}pl2g8o7SUW%pV$irBF%QdFnYTYn=xFuSO-S0xn(6*5I+i6`Z#@ z@U%@ z#@x0hST=9N1W%l~aM|;QtO1x|X-&q2q%EFlb%|=(iQMuS&m$~J_>{RT5YnS0 zx8S}r>bfk8tfg1=D4`%~ZC__RntWGasd@q}V_o`#e3+ItBqlpM<9o6$)!`UgPk@JM z4b|fdTX5XK`YbDfSC?R8&}}hsoXKC*%I@Y0%m`R8N+qO`bw*wDP*tIzp&`C@*9PmC zm`ZrTAtpz-X>20~z41elOw&TxrmiGT! z{$x%K`LlYhVpv(fsecJi+?417}uqq?)-(ywzAHb|v zXbQWl8>24&pD}9sW@FTf{~n{J=V#b7m&(tu8)v3bk+L^#9dh#?xbvjdj{r5PNCwgVF zJ3Z`3GqVyEAd^$}UCuP-<_(~vEFNX>B1|3TPX!o<>e-YvD!<6uV;b5p(dkjOB3ba% z%i;9=w*wp*>_d<}OI4fq!sC=s7jE$5f7k;?J?58}b(+(~QToWnVHYNXHoex^qJV>{G+|O(D=^6Q*t95)!mf26)KgKdU+>EwDtZ}0d3vS#%x>A87 zxMXQ#ed4k*JOzJh^s%Cn@6iRrG@UQ(CTB`oIHOPuoh_gF%SSCLlFNMZK zprHyeZcdTec1u0S#_Hn#U_z4gE!S+4JuA8EOBxbGv__MQzn!z%g57p&h)a5kuBK4? z8WJOvZH?@?J7vxtz>$xJ`0J^!f}>e<&&2I!L~Uy)7G0g0g*sSs-{9Y;sT%S$B2&9U8}Z%@^)O zEp0I$2-Pazr~Zb&ztwiFpE6_umnARGG#XqCmr%fFIYC5!P6*KnY}k#%H?ePc?a}%W z-IN80BtioA>L6%Ba63`_TIwI|>enP3*8e3}{}k#ElPw&p{Mk5@89=gF3jr;$bhC}j z`J)3cZjZv!%>kSEC|SDuIJbEmAlU&J^reiR%vcPJ0?C5%7sIhQZIH%dNM@HIS7FW! z$3)SwC*e#o!RLJKfYlP61V-+o_+wPKcAkfKf@xmd$xif^CY8i&q}nz z;mAGUkiM&%7VY$t8@u$ACX@F%P#W0B-_#?+6Ha2QEXNdf1R`#GeK@c0v!81>i&?jy zro}WeLh3RM#in@}Y?VY#0?gljOC$b2UC~yxwX`0e#6YAW+YqulRd=mLPSFNBYA7l* zrMs)ln^HFmQD^*lrmWSl4u$mQ$K?A)Y;`sg+=dta?LRUtkKHevjItuV;bl(v7f#4_ zERkCwq27vU=EO{H3;0&>1=^Z(P{FinIm3ajIT}vyQmO0qs8UbvO{Gp>D*3{=JEQvn z(eBE3pr6c;h;=iIG~MJm(x!YOVftnRwtV?(Zslb2SEgtaTw8*2afemFsQ=)E~x&lMR@cmqX zc`q@1KNlcH`;EzhzCR4fFN(n%8AqwFH}@Dnsq=eLt&Ni%|9+!8|87(FJO2+Y`96n# zPaPNX?*vA)X!h^(Z}a~u|Jos~-uZX`M~#1R<=PUee~yaJ{vc5QdayBJxEvdQDg_5F zR*?8Rv$BhirT+~0KjdWAS6}^idD%2=<75}a@xR5%-}%4gWM*Fu-R&Q8^6C2{mvTE| z_`_Wt(Ve01zrH6!j}91G`u7H>f1lZ&Cv<0wmOc{ihw1Mi?4RaIjlU}Z)*>8k45?(4vp+M8|ODPH)lCG$hko-4(U-DMY^4u zqfbw=Q>BygIa10_|7(G-!quTJ+%2}fj%xp7?nCygujCS!V97Q zLXS-ecLiCmns7>S+oS{ww}!;Ab(wQ!P8~)kekoL)eN^YaG|c}?bpA1>6th0S>ET5? z4De66&qRKTz{i;6x)3R2YntgZ? zW)Y{=$J6e}b0grzXyVB*R`yUAEBnE+RuV%E(O;VC$BWBJXpAO;9H<4;kqDI*=KzO@ z(}^zXTFS}ultSvN?@)Z~xc;W#sJ_>Ckz3#L4VB|P#YY{XqyPRd-|ok;xI<&o(sBRi zvm(NnxXD0{tvqROR#mG%M zJnf%pHU9KA)yQ0dW2vh)j5uR;5AW|UPh?e|k7qFMvd+MY-zON-#^$op+J(dS5s=wY zou}pm`GkBOCFfu@$pH&==9%}&FfH>Iioissc|IJ_uNG=RyPRSOWg!0k;jxeN7EU-^ zrvm1^5RBY`YwG5$}l3TjI~qDyJ=s@T7UCgXJ-!&7mk6Ugm1HjE zE*E2pUNULbMf8 zRp(W;e1(VVs`IK_04Mbo0Z`$|)En`ixKhhxF13g2NV|x>v@?pMco>I&z5C1=NB5cT zbDwz_SK-g(bGnb6=$B7P7b!pedNzNgjzunHHPf~4AK}y-`(U;vVq@PxNSod=f)Vd= zRd=*4Ur$_G(xwaGIG=WhU5u5vYdBmuJ6W88Rb6w>+YrHipAc~l9wkXH{Ox3&mq1f=bU$WVS1JkGM ze9^_MwgRjGTI`>6Z7=wgIH1-oK&X%ZmD}o~$z2dJ(0{lealxUe_nHbC!Lh7jOw|j~ zw*Q2>vM<$FZ;IZwT{K6s)q2A|(Mh`<++Vc&3{T+?hQ8wEZE=WjnX3p`>_6HYWmu1L z3Fk~8No3ZJOAbds&B~LKVZDt^x}Q2V5oi|8EHoeD1++$&iGU)W*iRE-V|{XJUVDA@ zJJAK>1N^3uDEk+>2-9Tp_BS~ zJM949M*nA+qID(i3Pa&@QES#_jJuY45BM?FHq~{mYKXtf4R-l;u@~|is(%-~OXnst z1Gu63wP^BkQoLaw6XCQDe?VdicYJzA-O$(Sk{2TalLZSeZ-V@v;TNiNeD7=Po$J<$ za@av~cN$txp;-VOCuwR5m@1odvdbwx&^Fn~7R50W@jK9d-;%1>u~11H{ayTOWy#}z z@hGoPF4IdE!ZcH%|EB1IihzG6kA;7VM^^nU+V))t==g_w_mtJ<>-u3t#R>VRj%$Rx zp}*C&yvE4zkA`BgKMjdICVD~VW%Y^SM{-#tdcUpB5_Mh5?@i{YPNMd#l}1I|t!cYyKFa56N&NVk{v zN@^;MqS5WYR*YsJvh>kyhaIqqh=qi z{(Ut0b@-=#*e1L6_>~O*yjq_}KlT({U!T?sc}pSh-2Hmvq8!%wH&_ZGvq79R>UPIb z%WyoYj~ho_XOHXrAK5S6zLEO_cy8~SE+k-W6;SGTT$(*`m|`KNwluXi>mZ?#K^(gyT;`}-iV&t4vm=mo?M5ZX8FV&L;jbAVXVVy66SjK(o*MPR*Y?mTU9gum zFNTl7{0Q3x?W1Whui7`QO@4}-()*46`pSFqB6&!mfqR{q9F%7#gjV0`GiXOH(U%}@ z&HZYzJY%$I4)baaksZap1YAT(J{oV)Zv3$f2TQVMS8z6U*8bGJox0ZlKF(+ zUF}tGyQM!jiQVwW)TNXP@UYDV?e;X10SzR&Qt-r}6I*RQ$GKWG7M$HZt9v zw}n6k{^+l{{b}s-M~kFY>fa_h2Ng-}qob!0<)*AuCn;cv)#(8?iPehM8wB-EoxmUS z^%Vh{gLLq?ZrCSd@;200zY$#^m5JdzXb7#{IA+*}daiyRUA?lUqak@|UPJY((c4?e zQ9o>pyhe7|t>5)S-(oVWuYS`G?2Z-2WfEKE7R(K-6=*EMUPgCZgFSFVxXcjNEQOWw zva$*VbsI5xakz#>f``?3nn6`-waJm_2UuNATP0_|Sx0-tIrp z)H_2-N|qBJY5ATkdyc~#e_h+fU+4ftIU;xuf8n*!WlgI`mmLrxSYKlBn%aAiYJEBx z9;DMB$wMlxzc*q7WLxx!lcS4PwQX$~PR>VMPV67#Ejn=~w#e$WEzj`f9{WPrzk`4^73LF(6 znq=!tjpl+sT5DS6yJKo&d21qy?asUr&=*gP)4S{kHKubFp@uKuK@2=o~Zv zjblKe7eD1qePPLxkCB@#nUDhM=LD;-|2mZi=uM<9eb+0rlCZJtF~z&`uRW)))-*f{ zD^5s9{H!?tEnp-N|J#bSF(L4)0gp z{pGzPpR;~4_;UmJ)>mGzu4tB+g%eF(tWPe~z41hK(rL(cJ$v!T?F#w$l49QKIkH;t! z;+SX`z~qel_~UwreLAoO*PQmZ46eg0(eAr9Lom^9*7A6}@FeF>_f6=oY0V%9Kfw4_ zKCw`#wh-9hFGqLs6rUzis&X3DUi?0xAA3&O2DbEHv!INJgY`MnqC)>RU6nzL3R6`% zE$Zr9J-PPDUB7F7!Cq;@p93!lfpWa17y}c3&B;^UBb9$McNn5XrN0&}w(({-w@3GB zjev#H%6Yc7TDTiFws-JBozeLDoq;^`?~p1C){T;}Rf%>rH1W9FSH1a$y^Id&LCKr) z;!E@;{(9`4!x*R=sz00cLh1tAY2(UYFePYv`@f3s3giAtP6Q=TpqJ%$Kp#1{1@tL( zT19MEMawDPvP-9ZmH(^0=vD8hW&Zd=FS?FBw_S5@&<%$QbhG@{CUp2ihF^tDiUo0N zf8^3iGihyPnbF7V__HnnQv8jM&(5$r0*9YW=*0~ptYUQ$|84H8YGFm7CaotbT*o_o z;>MC*@^Q-;UnRGNZT>tl1XM3E8Zn$4+c<71=J(kR4ZO~`RwUmm2&~%leryn*|nFIo~&15Mo(WCS$5L#U%OGSn|R$6 zS=M}c=~a6DEw5W6@quNX9k5)!{VlY=13wuZy{@b*QKf9}k?l{B#Poc<{FRr#5FwA< z7woRvc-zjKH&Ac8cn2{O9jw>i>ve0y zIB;rx^xF6J=VP$A^%ol6%kud%HTu~L*l<65i@ewUW9rE0j2*@L`)V->AHK&QzK_&* zkayn)PUZ6;CDMoerp9RjZz0v`&2my|mt z1l)Ha@R}j;VK1c(f!7RyUP}vs*9?IV)gjA83czd@5+763b$=$q-;4;Gi^Xe4jes6-EK2qaS|Ivt;)=b4#jDs7y)m zTS(-WRr%Yh{7(WOavF($QiFe|%0KCq$lXd><*!V8{w z_cp$|m$tfLuRWDk-NE?kTpyi(Fz(rmv%dTrU(BELO8GOTLY?yP3OHX6KiLpG{NgPh zrXrBmAaquQ_rW4yB#1VUw#lB};Av|_66PJyK#b`zt;fIEqXrBTOsW6WW2eT~Tl`D$ zk1_PwZc-5({CP=#HtWwH!0Xal{#@0_pP5bknKND3#aaXG679jmJr4yB4?NC;c55P2 zk!(Ai4rlYxA-zVzpZ}bGq2vAmj6%=qh(xyG za8_{sU^LCfB&~oNwa?V!HBXV+H?sEQhr|^7zT8QT)<=n;gvuz(4 zo@ct8uUgKZWpZAvoWIG*d7;bM|Li-oz{@Xdt$A)7US7>#XrEVBhAMMwd+f5Z{C{`} znQ#i`h*HUdpB}-a9xwQ^dwcUFd%Hkyu@?%ZKb^Z*Bz1e&Y%KcEDh+3003=@Zq>r>! zHJN?Rf8c#?z4FheSo#&$WjTMXd{_U|j}iaT>*(qp{SSmL)gY(;v-k&PHsVj~t^6w! z{+;s0Dqr4P`FnaVA9AjC2wA82A6y&a?wV=sJ0z2fTdA~HgU-3L|Fa$appv5ARIc@w4*lVzE5CPb zOT=EDzx1xPi2+3$#7;4u5qPe7HqBHvW^n!{2>& zb~}27A6=k(2ZJ`Sn^vswo18K|x6o6(x#pSC#WUP}ZkR&|Bb>!II5ligEZV<6PPZ(} z;s_QC?uN?V^Z#m3`OSe(F>B+vAB?8==3Lk>vQ(=hxeW$4nk|2p{n^{93KYL%%CpoA z1+eFA@FITwpK~tJ<9^wO?DnSycI(F_k|@0`yn=p+E-tJZK)~=lWpVqjd(Mz3tp2>> zzg8@}&&%Py+jgyO;dX7;Is`S^`8R;k0us>&I)<*zK~yCg7Z8lUj}FIvxKV8ePy)jv ztA_aB##5w+BrL1X?$-2@3_{%=4F2(5@Y(&|&!98S!|@Kv=Ty|| z`22U^pDY&cCeHJ5%=pCebqZVTB{n`ZR8Jz*n;V}4JxtGwR)k}Zpeq== zU&IH@2BY!1d-TgDF|5pF(>1I%5iZ0(_LPE%-)~tssDAfr2Gx#tat4(x$o=n+%O;Gi z#ZzZ@8(rc2)C>N#5Wi9PNB__8zwG>;`0p$HuNn^iW0!{bA1wS&>ka>R>i&KFztKhi z;?|n?rb_=hw6$iNJq&KG@$F$?`|5(!h4)7C*uXf4e@EDS=)bX$a}mtBY>f^sYC=&>+H)pXj!e{lJH8gR2S(wCF+XK-%p85fwfql56jbb`C$vauMwV( zY=4yBH3n98U*Di@2VZw@WSbZ5=>o$a!xpwpf_@)ILo{P2lNeVUu2x1v3P!=+g|a z3#ZA?AX)ImYw-MB=kK?Q0DQ@!t0A2Dzf?V1t0%0cdc{cON5}5PURL(TaV)q;<-|B% z$j4FEfALSSX0l+a;=PnBVHpYN-*PTG=d6GwQ}db3ts`>!7lZdWuUHTVJ4 zH2#ilQuK;7*bh}Do#}jMv`LY~t3nQvkd$pvDXWdNb28hE7t5thdtsN!`d_7$ivL5d zqRAyRCff?HCW3xGa{%gq?bS`=h7aQXy}++Z3232+2hc$PEfLUz{e$N90*mgwn4Yz= zxdWoxoAu9y;n-l41GeL)<-|omn1L>Z4y7GDSHEO{vuIMgpSOpK#ZvJ+>aO_mD*BJ6 zroY{-)~;8p|H`0#5U%<7x1usp2aD#3#%ixf%E(iINGQlF6uj)r?yYwET1Y2e3z1IcNbpali_z#fFHCm`Tzg{2Udl&ua|ldRQ|&tnC=Mex0A^% z9y(a9i?&4(G_5u56OqHw`F(hSr^>`rtu?ci*gUXayOXw)1A}f7!qY{I*~r3Zo5Z=7 zY$k##{%a@Q(9f%$QFue8w$KAEF|s-NsPmOMtVWAVz@{vHJ!9-YjK<pE!QRmQgOT09rH|=eum9-WZh68g39ntYf6GC8!yh^P>3FjgEep(qXV9_bz16R}N{ubi&i#T>^v=U{a>)6uOZK4~ z=$b!@A}k@Q51NUF!nW&0g)^e9OAgdmJK_#kd&yr!^2MApm=k{y;b=EU(pI-xp0;(- z`G_ohmJB7gHH0bVqu1|tm_uCHTLScD_MCD$OZ+L%o#qPR@3C(`>nN|9 zmds$=CKzaBDdk=V*jO`{VUd?6V6}bLZmU=DkaqLp@NRsRJlfO*` zT0l~MHS|xdx~$Zn-6so#F1BIYw%m(-@*N z^o9+Wc^^DV+u&n&?om#nVh}H$d-4M%>MZt^5mOCx{>auP+Ofr%dvv1Uvvce!q*-G` z0O(O$vD&tuh2fL`DL(^5&Agf(jI@U{Bf9NoFu+AHDqGmdb3>xtQ!J3^Zwd zrkp>UoQIyoWnHpWHFE5X`|G|h&I_T1=aIovo^%{ahI8bu*3@vj!!qu$j~n*Pg1Z3} z9%|%u?gOHZ^FObL@a-ae@{Y1r{RSStB7ELb%E5o>y^JW8>+o?MTbGz#5pZTpITGlw zgYV&RzJLEAlnqdn(mS^6+%$M5PVv5e594ljMfKB#0Bs)1-st6nkOX@y0s>?5V(a>- zPH4QvaI+H$&1GXWJZEe6VthVT_7LC5c2=zB+ml&&wDc2>jAg{pWGPh$Cb>LyZWK&B z?t!?yqfhf8vA6#z=qf6gSAj7{kswE2^Pt$_&nK$Rq^vgsRvQ6JECztu{A=NasSm`}>qiOy!p)%#}pf13E{N*si>m zeMh!F_XI7CG#A#b8C(1&=NGKe!Tp*3DKuSUz0mGh%U~C-uU}#|4RCA{SGWmO_wz;D zTC}{;ft#y&!2A9HZO6w}vfC>9vZudy^!7P68|!E!195ik!e`3nflFq51Q6?!MGcQN zMMid(ZNv|$f8{#nuhb9~jm@sji_ZV0W=Uj`D%rlW6jPP#bEt(hrRmG7DAQN2{`i@V z?Z?=%`sM6=zRFn^FVUCD+7_!65Fa%f|E~3)+K+`99=P-Ktr81P#*{5K_jlsGkDvO4 z=;B3&ciX0x!6MdV&977H`tmW__Nd4}Vq+I}nnxyA;_l%Hrc>$?2mYhXpsCSxS%}mC zEpR4?nHf%N{e`YRqT^)h+t=#z|LVEQ4zS85>L~8Gin`d1g=nM<890A(D%}M*Y_or= zgLq7I@g1%OC_$@0MI~l?i9G*a2YCK}k(fFo17T`AL}g*!h?kOAYf*B8zWBM7ZiFQn zNSXfdU&0$N(;J*=Qp;NQ4%*4uJZ$14^eQAhHLHo_7O@8yCe64tOTr|=%M{#^AwNmO z(*px|u6aQtLtl1xFv9=Aj}Yr-w!LW?7MgoE@R}^x|41~Wf$D=FyhcK7Wl3G9F4w$e zsoG&TPBy3PaD;Rdsz0~b%X`H{wf`{^MT!Keb}Zd>YIJeH%R%S5pqGzG_Szt!0oLb( zGWfi|6nqMV56p!cVQL1~UB+LudV1lP*+I?L+v>8~y1w|ksWfpg)P;4`Ba3hSd1{+X z^xbRz&JROMOjpf`-|*T!&#X+IdgZyIw>;-&@{}vjnZ4yXA(JPcJo1nAhbUjN;K3t8 z${+Kp@UaWkw0vPaJNkZ;`+L-=>98BRlfLz}!(L&cXG47@@j8*JhfeXCr|%X z{$r1X?QLBGo)5fi^&gz6|FKs>dx%XT%t0l(59L73d!-iH*+2T!>N~ zFR|FsGR11nJsbPR zt&?2$yI~5y`%it=CqnDdM8tSd58mK}J^C}HcrB}5%Ob6y;Y^f7Cz{Ae9>%#p`E+WC znQu6L4xWt8hy2=pieBPpb;15t%H^=X{v#*t<;F*9M6YI_uzAitJt}Bh>HHP97WjLE zYHQ8PQM6-fdvhs{&ljk&MA2mXskx9JzYMg&snk~5{H1M${)yBILl>rhoC80)08kOHTcJ8Q8gR~9PS6?hLfgcc zF}X%>ssHs#*9vtN3sEXmSCytJd!wY|k2kyI7ou0u2RvI0_<{8P0L}QPUqxGi2 zh0)t3>)gtH#~(SL*m{-Tm$d`DQzqN$4bj^tlN6RmGrU7ev9R={VcF3s$)Zwre^FfM zJB_Mj!QEpUBmUK_1(X1fDU~Lay6NFO#(1pe^s#hB3*PM*Pjr>0Y$#mn>7UOocW}2C zrk3J#GXeP!oUUjIMcbH!8mGru7_u1L?F{2SvL#$-i{W0;5^l3|`)AF$NZ&@H( zY3?q1)=EQEuh@TwjqmJ>XLPVxjpA0A_=Q|lbGP!gHu<7m_X=pvuza=K4~s48wWSBGFr}^*$^+ji1}6C>Hd18 z9|_N%8d?^X=88kV?!;_KnEI5dGsEsZ9>S4jlr+PKzqi=JxR2b9f9^%U401MEAHSqL zbfZ)F7Y37IqLHtgnvbiiwpKSE0iNHR9`0Oxbd1)ll#!O&DggBUY_9Y>Ha7dhcQL&nth`dPi5yZ|x+BeqLCoUpv)f@gxY&$o^2`hFc zK@-j+?9cd;x;3@Mlx4M4TdVuA^qf8-R#Pbm+>g#BoD}ywe}a`Ie!+O%Bs#mc^`_x` zA6AcnG2T(R!X1*@HYWPS!s)QwNNvI&78#?pi=0o={mF${lB`_$xG6gSSX&6~<5f>! z(66PD($!n3oaN8{Yyd%~TG1CjA`}nPI?O8R$1kHF*VLAi6=F)!V`3~+ibO=LX0{}A z3mT7^Rv@;{5zS722~w4~#uP%5Mt>;nu}=;0BXm6~L}4&dNOx$`%2Meu(@8CdRM_E~ zN~ojOYK<4Kt{pClHMaGM)$FATn-8r|e4~nn*C)QYkWBt47z2?Za*5Pl{5E~%JcYjM zzgW%7BUKR9#4Ge)VLO_hp$h8(1wGRItgsy;V>LgpoX3DS_b6S6onacWkG4v`8bUSJ zqq=qQOnP(*xL;Muotr$5B&~LG`b)8zOAWx0R0V*>M#Y8%0Q6n%>ZNSJ5mVGm;|R(& zs=Sz&2>Rd9PFs8XNZW=SvtXaP*zBfA^Ipr3B{^NNJjxH_?T-sDh{WG`o&|EmI9G$L z)<0z(+zL6Fu_18g^se?Vj4Wse5GPjijK)?ot5GAR+P9p&V(v$TZX%!lTYcLS{X`dg zr^IR!Rv_vno;0E-E%(VN-6v*Inw~F*=WZG5*ku?8#5U+$2=li;;^zToQo~Q={x1Uv zBXE%{^!G;?#QmU2qiXfjaGzxj*8i9uzeV~IA?LUhfn33zW#xpLD8U)+w_e{10jHgg z=p(9&Wwn`aIT0Agip$;&_g1bMRUz(W?6s~!Sx;_$xESgOFsg(N6q;McoQCb0 z5#J=4IHsX`fu=&@Gk`Obqez(GD9)!Gu}c=*bY(bAtS@uZgeTgOMbKC>O;a11?E01F zFS4pE_t~e0WBY$e(#FoiHR_O`x`)sdeqZ*&jc;p9ASR-kHIo2fA)#ffCWK^wpzIVT<*qaze)YC1ZMT=$_W=(`+sP&6y& z{N$9+U;kMDhxSv@RMd=7g{BSI{OCW>LU+X6{y)g2U(V`$9$o)y1csV~Y?%m6ZnTmj z9n8HY{wJ4e9!VG5Tq3o+b8k0JpbXinBeSYCXc@d!*#p;~0&G#Q0zHr`30X(+!<^Of zoVR9VmAW?l6j2)va3iI}PhTO?M1rX>8T%)w8Ub4Z3^&aJdi1%w;jRul!|4_UNE=JcEJNKeo5} ziH731gqxW+Qomo>t!8ipKYy8gdV8zc_1}nIs{cl&`k?;~M+XXUXf*xqpHdEJNE2fT zoo-$8(7Nh7ZTL!)Z@!MfdOV~@eh(SyhATtUsadQU_xhUavnENt==?hXwr1qPCZX5h zK%h?J*T!Y~a83gT1Ip-Hj7+=lA#(6bFojO?nW@Bdv2?NhRC3HJ2q0s+*DZh+vEZJI z*sa~#3~7-6X8#|;ppMo2sX7?jT31+@0P;>K0spP+L^HHuCMPFgH5v^ptH}-Vi+SAVK^52CQR;hl}Y_e<&zE$PJ2AkUf7q# zQgcSE<`fmy()Jd#$C0Ri;|l$6TGn&ud7d(5nfCsnR6+&TaJob<-p=%UrNZQG-5O`wGQctE-0_jK=w5+mI&jJ_vWHOOhMcR$P0C&15W=L+BpBG7lM==<7f0exqR zzKurTldLR6nvzA|GXwfw*qBkxq3?ZG9Qu-+xPG$#bgi{c)r!82(#)f69~ylRs$2nS zmy5J^ygY~&zKM@cWL5Z8h{p6tZ%wP%UjN~JRkVse=&tU6hJBNL_J79h@5D|DX3k7tHO~UjKD8XPZkIUe@$@g}ml52p1X}Vh+eV9en_p&y^10Yq z@Q+6*l}acL7DjLh^W$3oq{|BsASRGC0Xa9;VkR0cozHoB^xK3_N|m+2`vsr?M2*fYCbKL zZ{bqslWh!eV8BpH@-U?>k|HZ>zvA<72H=gS;fdSqqiM`wHw^}h`( zc8BBE&$HPd+SL4&MB~ALZ1AU(5hF3=ca=#$*MMSY$L*(;`#-xYP=5o*Ip$xwq(|N9 z{*^1t)H}^q^mkS;9PPyMq5g~PRCZ(Q%z7SbWv%DEcCAkym?ElChZzwHQh#HVc(JNT z%XN;;J^zhMlp~-I=%OSB=&JngJ99B!g(ZMc9RYUj&KRJPXHwD`1KwM117uiUXbd=2 z2~-+gaEo=~WONw9qeXxIhSzs88r7n*R;5G5LnSh+q`%6QmD{-I+)q*Aui4x__|rfs zz%f_lVVUAo9+aoBb-TY3;2+X6>`K}ZEaN?YGnq1NA^-`lF#gJk@X+Thl|L)j!b{psK88{H58;crSf=tmZ*0eMGQ~=fa`MR(ksvt-3ud;%iyN zdnU$NvX@4h4<_1<-}h^7T-K_mQEnlZHF(eK{A1J!1+3MWBk~S;6Q}hwYI)~pbHO5#A=plEH=ZlW&yxHQLT>YW&Mv_WqpBU zz2z`fR^bif)c#sq*85ZcGY1VU1+oalYQAj1xun$kof8y|{v3lpM000WZ-&c#&fmbM zwor&Jz8IrI%)D`v1;_pvB0)aTgY%m_Cb6{MRH4!c8qZE6)W zDAt7;!kf8ivS$4zwMf>5z*35VVX`wYB*KGo0Jjn`@IT<4qM8AZ?jy`Hl-OPANpHkjL2r#?cr8mV7MbE+=2g$>B!g06kq> z!kq&fyuOXa6vHOX98%&0uvS+7r{8qE+9)pOgTX;OC(y5v&s*&?Lj#);>rdH?SbqjK zqbg8fRE?^_v9qEZ3Q|v0 zo5}c(fsr#roNJrbB<|S|aTj}_J?BmaJze1p5v39V)14t=o^ZES6Fr7-m9B|)$;5ZOq6&Gy?Q|~Y#d8>4I2NT9K^eyZ!r9Z1n^5asz95{{Xgsa=@`3< zfqlV-pD+9*d<$*prC-nx%NbuKlt;7D=He^MlJDpgLt$&eaMN}4;UK5^`A1yj=9hAMVi3aynLiL;9k5R=XKwlmLK2 ze_)6}dcH}B)|#u26c6v)T2pQF>)z4D1(iH0R%&a_p_W!0U0hT}w%EG7g+(XwfR;#F zL7CFl_E}gkgohlr@<958_M@+M$q!g{bQ!Unnd08Mkn<_aC%AbFy?LDlFY%)F>p5al zJ1QDku0LM%oEIez?%YDxx7IvKA>CvWt9e{c%_sT?R>MKbf&)`Xm~rIs7mmbb`chJ@ zmYY<|FV8n&H(6xBZnwJNDpK=I&MuEc`b3sSYAJZv8Tky*`-h1j7!iujQPE{=D%;ki z9iKm)B=Gd+O`;PP3Nt>)(ed6o1m^_5A)>`N8=e-mq^>>}r`h_}JhUj>6PD z)cL^vqp+d@j~U`jKNllxA;okF@!9eTY=v~`6Z|v>v%AR{GZSSl$HbFISv627x3Y2t zbK42@f7kw0A$wCR$FQ<^a&)5T06vX@f#-5SD7I|!VHCY}f1aB3G`0N(dUDw`JjDFFSbX|LmW1!>8cs3)Bf55kZ)9<|~WD@}^=o;%*{^J8uPs|Jz#V#UMx) zEiAh?LNK;iCcc>sYf+)ZEbC@*_21todz5z-3@1R zxFCxV8Qgh9S5Uf>FvzT_ZR>1C^b{O5i-skKBj9G`x&04s-e*3mlbdIHHTs=-vzNS{ z&o$3XB4>Q~8iFbvhKw?Pfh3`#SVK$N{D(rhXE&#T*i1t z#e4<%G2%;V$D)8#x7n~zZJatzv}<6fLdL6hwUUF6&s6v@3t^>tnF`Thx+P-jG{1{#EOJD~h1@!|9mr3T@YQ)*{@zj24(d5J6LpY;UeOg7EZ@Fr9!PqY%q%G@U zW!-j;_D7M4zbU`=R82 z#NL(FEb9jKi7M*2!vJMISVR5Si^4V@4`XDF{$Tze7qqPubkfI4)6( zhIV8z>asB@f_&sPzZFokt%1hvBHm+E`Ug1CWE?PRS z-Ibz61&ocYzOZT-Bl<W%5W%>Grqkyzcx4$E_Dbp8!IlW#b7UY^=h`fHWUSCr;%;A;^@8(WG6zVf81 zXq)0RD`j7$oOH^m+CM0DY0>$I@SyZlDnX(@FRDMamp;dK7e(hw$hFSi`y`zEvKt|I z2U`slC$$u}&K?MAzgBx`0`w66t9Z2%{K{RUsX3tAF3*=Tdv{5NzGqPUk-*}Xt|^ZgaZw)Q%`Owf_ww3h7-m#gkhgf zKIt^~>C~#`A(>BB@2RJp(((nBI{8%d_t)Yiw!83_vEI@dE!Q@G{hG^9aQ#!*a&m@e zq(>0{2w4)5+j}AMbt`+@vTr1d)^U4G7uPWVl_u~AWrXowzVy zM`X)VLkBg3D3gBi;RTV{&d%mzGxhCn^<8208IN9*sqNWIvugAIUdW03ZA{cTgM*iF zRAB!f2rz^$n_?R0?Va=7@jM&y@b%r(-~@fCi{B|v1zPl<`eFF660>8xCO);fNt(&o z3XS!F8uhmHvr+HI_v$|4Ij1`H0_1ByC+3PV{Zt@^2gdK7F2ysxlIrKFdVas5y8X-l z;-psb>ei=tmtdfSx;Kt@H~t4uHf*WJJoX#rb|Wo&Hl{iy&Mnn+2A%~aAfwRLCZDFf zsd>)CR>3*{fo$zRo$A1j?0EF0B~KCd5TGJm1ydR?hv9z$&Ou)<$zl&#*;GA^;e+D_M3#rv+Y7i(yI14OtlAjadCea$@m=)cwT zM2$R=>meQj0hKIhY(RhxBE|mzuj+RH&rmw`cBr4vx;mf@G-)owr|?eGpClgZK##7C z)$}#|qxc)@n_pn~(;OYjT{BN<`p?&C;f|D(DoM0UtRR6QrkR&9(;e>H(9@+ zsYKh>iqODs48EOmC*RPYV=FmQ_A-0E(L3)`7O?XY#A1E%=E(#@&p(X$XJqTnn&yHr zcusg)e!$c+wc40wVODON2qtEd5`Y}no^};G>1;6=vP7c2I?g>_CiC)PhpN>d{k^F3##Hh;E$((X;!f5V#Qi*wtD66B6AziKUvTq)u3? z-=MShapfK^b5*#`(j}SKm&&+e{Y4Rv`SBfZG z7w6Q?RzWyq;goZcKmP6s9`qVNZr10+?-&UDSKsdm-^8GQQBDOW0<+dfCYgFuJc2gX zCx1|;^O{ZsEn+(@5J4Ll_O;Q)gjV8!Yit@Hbhk~%JNcYqJ$m*xBWEWD^*=jN-@lN3 z^ut)0+$_USGklt<9Qc zteP#s67K(JaqT}e;U?hPWr2bV=S(bX_Lh}iK4ZppGrnlAb1FAgZhu}qG;+yh{H;%3 zT-H3M@=s$b|AKCgDMDA@)SJa)E>d9h!mG<>j9z$I+4Z`*W;%EKoz79>&Lg93;zZrI zULssO*VI+-jKv$vNg^c~4>oDCD<^Hq zergskCY*q*#MBn1&el(FjL!cjU!~t{jV86(B61ip{zES!#;F?rW7_`Ga=ZwlxGT?; zHMzQ;DVxrN2%?05AkXp`>4hHO{txK!>a%;M2MzCy9+2sC>G22X(H;=u4V|&m!8-Q3;}6Jxx@_i` zltVL;WRX5)Sd!ooLmq_slb+Go3o=o)GU?tKaUX39OSP3%S?LGM)~ddsfpuKJGcI}Y zAk>Ln{y>|0d*RYvnLX330nU;TRs};?RXDD9<34q@Msj?^Qd>v8a4^?0+S4+g!mhZu zt1CjL4!fdQ7^^Ez`d3|HC9Nwoe-2fPX{l0OXDFVOiPUbLaq;JOMy4m;+Cxv={T+JZ z*NUtNH7wJfd%}@N5?SO@PpExiPh6~?xa~+yC;uls@eX4m(-U7D681y|PxbMgM1S#* z->XwTvAAzWdtp9=}V>S+x+40J}9&&OP{o34tAW||JqJbLhBCnM0Oil`q&}v z)G)4G%V;oeefH;YX%YKiy2fFvRTsn_(3!=D$-vQ^j#NSHZ7v2JJm$5gNM{*g7KHgPzfB1WPV+xHoPs~)HMNf`(;C+Frj|3V zCeJ@6DBwBzZN)#^pQTb;l`C2Fjc*4vxri24QKSF2z@xCy|Awj=Lji~1Bd*lM2ZB;F zc;^^vUyizt*7@M&6y%*}zx_~34p3EQ8c7yi@~xmyO@LrxN}>N4eVaPRLH$yQ%fUeg z8eQv83vj8``b7Ta{$f&6LtL3}gst}BXd=!M%^pk+_D>=YuRMMdy$Js*kWu+LD*BcN zL9!?s68UF(ztqv#-xXNcr}=lOu5l{xb64QIA%1hS>l#EgXAPiGSU7I5YM)nqqvDitf8KS%tvSU`q2Ami=} zh-y6lHhMe`OUzOK4%qp{?-Fr`Ny0} zq~_$ne?EXeCl~$)^gBrYDn!!Xss!-&{ErZ_e7Y|e{&I2EeS$wE8~&vZJp7pp{|*QL z@(g^9F9-i_2mjPu_)`S`RKZ`4Z6-q>M}H6g+uxNB=yRNdUyy-6Bm=+F!QcFB4t;h@ zXl@2bYD!P|waEWm_`h~Uek4TFU#k%(%-5C=u_eE zQ? z2stqPWyj3l#o+gc3q!4Q{q?!oM>wuMe-<+m9USqGQG*H$%doGRfhHGXvG)H<8R7zv zEI2Y#VkaHzzd~wyN{FcjC)0Cn#Gm4FKNXV9UoST3LRb0+(B5bX>whfxPI2^0o1gtz z0upn9j5G7&(7)u)kJ)N-H~slT@DAq3TAO#$SIhWTs%QLf(MN3vYl!E;7{&TkZ|TsE=Im@>pT&7xllwiw8S3 zY!nsuH~rtWA*l>sb8~BwZG9&Umkk#&qyAUFr|WMpokw)xn>nMBAd&B4jNt zD;V}OgxZyp@JJInhHA@ z=wDY9;OWyL2Q9lIJJ``lqIVem=4{5Kz>;MNT_COGe*4X$Lb<<_xL~=PR?v?qH0pnO zM&9u!)0{`LKNM_3K#$wjkXWA_*@ydsZ#}{+#*OEn7g<^<_$)A8eVhF$ujNCZg;-y1 zTS$qz>J`!3ZVfwRzDG%9DLofYNsQpvo=%fa zP(ILIq2Kssf8nb%DRw(eIxG^seWnT%bm#UUjaLk~8}><=9i4eYmU32Y#v?DbfRFM4|dt75mc zBm2ffO6L77{qnAk(EApCwVNPA1DLAlkG^|}eX^B6U}F|}cLrIt=C`b*nW>4LhEfvL z9VPk&Tm`>o=t~Zsak$%@D7P$kI4coF&4fVKM$!ufIyv~{pSk@Hk0cQqdjlVA+0MR_ zf7C`OoHrS!htHD*r(H$Vu8&*wx)wvH{~kU?{5tu@vj?|V(OYj0JvXw{kO_MWXVOOj z?7y}NfE(r$CYIulhQ&?3sXU4M1#sA&J0zA3#~2wn_X|!^a25gwUm)iSwES-xUy5;> zx&pI>Kfv!7Ngb8h6w&zBNmw_&AEvp%_%`}M93vL;Eiu+<^Ne5rtVh+v_F&_cngMo&Ua~kfi$A|N(DA3g@Lfofz2J8oJV=wx!qjQm5<4@s*@IjEaW_Lazg4x?%-JqN zAJJMf(;g1;mYsOn<+Dz_wuMP=V%ecnae6rFYS^CBJTZ&TkQ{~A@Xo$BXpsk z!dPt;+N?XOzfG(k9g17~v4ZggQ!d5Iy-Qd4zbdwm-(>IE1squ<4S=r|{$qUd#|+f; ztno9&fmtz;oFxKt@o{!{bhH*@x%7`(%>d)xLeZw_>qLhd!=N};vfXLcFCD_XwNe$x~S!*=n8b`mzV zG~A^7!q(3EBD!DElE*EoTZhlt5w1id=)eih-s@3c`gQVL%rma=mD|&rCRTaRpR@1HFC2aLoridpzwu5UeCJM3 zt^^Uh>fiCWIE+1;$_<>Usqjud<$8Tg%r5jQ*;PUo?bPPajz5D7c_4HL{vtD}8l{1+ z+tj`re&w1lH*Xt_D5L~uDL+jwtWOji3$*%^YjKGyDz`_kv_4T>fAZk|dShKtr}&|q z>D^Knf2D56JN1e4O6n@rR8E<)W$lv6>ngSF$Iaq(@r@)=U47+h{{6;~0<~DjhWg~0 zxDWr9``AnsCHD%_cU44hZ-$|~%Fn#YPf`tCyek39DVTXX7DZT(S9W-nTfCDCuH@C* z@wTYKw7O(`NH|MsZ|}AjPx+B5kOg2^E`YN>7XbT@bEkRHXJ7HwtOm1AFFJa&mz;q- z{%r4?_paRZoOTlE#MsJRuz2~5;&z*Y?c$z73`VQk7y@VilV-x<+r1r|y}dv3UfCV{ zBO7po?(vfO8#1^46tBuE8&O%>@5b+sy5^5s%>j-0fAv}aO*qs7#T0$EPS0AGBu@F% zp5>Vp8_~C22mR)7FtM|RO&K{Ct?A1W0h|innK@qe;}K`cWwq?@nv!fLnVjbQtc59_ zA^)ZkpY>xaj(fM|sW^%;V6|Aa<}SwWq40^HQ|iTUDChk1-+-jpAU8PuVfQ~(-a=-0 z@e8;keVtc*PGR%eI`L8=obd-QxNqKA@PE<2*3R{scV4r;PNL39cpuI;pm+rB@BhT$ zfzNq-<4y>xe21547sb5Tt%Z?UY*QcR#rNZ|2R^Z!1ikoWvTo!g#zVCH=KXcb!b={! zRg~wvZ#3ZheNlo4e5z zXZdGzXuRF5xD3~M%kJHLlt18vypdkK-I^R$aw`eN&>%#CX6yW3^7>9MdE-A_;8KnJ zSKg|N{sdt&{5zZ%dRw^EMUPn_T%LO@gG>H43##-6qa%Or^3;utA%CymGmYYh#WtGm z4C!2-m|1-C^~K)M&E}Dj-rLLjj2GNO>XZ4~8j`ie?F|V+<*jIr)>W6Zyj@rA6}D_e ze4w3m8}E`C+5frmqhRR)eeKqh*fJmL+WKt%{*v^G!HMa2^FxH3#24!jsU08o@sg+C zivQSWGYDpDwt4t+d=k|)S<6-QZ}klWeC|4%4w7P~VN>oUPV(}$dvRQ!Pq~DEBl4=m zwlKP^ma%!1Dv_HdeHb33{H^*q_JRk6>7ME@%p$h&+?O?EoBtY&X?ccg0m!K9+-O=> zW*AZ*;LD{QH5Z>^d1ksE`yIC}EByRom;IxYmOqVJL5aSkmp_*;5n1Wis& zmuO2CyqiWJI~s)i7iLp{f%zV~lDvKVUy$IK+xNCQUq(Zo zevM$WPM-I{L!v47Cq@_FGN^X@n!M(7c{(8W-eGLif5+*Ja^FGyb zIC^^(h-i7H_58vIg9Wy2`ZTjvLGCpvMEqn4?-C3F7v$T`B9-gLRBpwSDqSr;fR)&8 zc7@f&(;yM$=qyeaQaE$52$3u3d{>#gE0f}N;z!oH^;3OyDjIu`HGo*Dv_Ad=TkYsR zlX7r}t(?Usaq)VvSm9suK>;~!f-z_Q;OoI$Go+2Gms9#2cv8+={2Ah?t*lkV24I!Y z&>G5LvyE)?w`wivBB50H6D_k@*v#j1qFU4}n<)O5x*(-I)gd^%GEkU)5*PO`RHf7W zZ~ql&q?gJ~cd(*}hD&Y{IQ23N7$$P&^W<2~1%K6KM)b6&tP9edvT#otSS9|~xntO7 zv^h)*qhBsbQ&0HadF!Tb0%qIRW=PUR{B0DVc`rOfU0+^hnAUY#)S2mqyO5)%Y*1x95OM$XeA!%lH=bi#fXxCNkTk{OLS$QYw%0YoCU~W}$q(U*8-G9Ab17 zrwTLHlTbgBk{-x+ceL+Fe^Idh+={&iC9v(6Xh<9bMjhHGD^@;(0wzFgv)X2QT%p+V zM`{3+dWnOH@%xL}v|17y;r>9YJu4)8XZkEu+GN3V?=6b>ZyZ1tw@_znqao#g=FcZ0 zhDI!tn<+?uQ%w-4T=YUu1EkY0{xElKdcOa+*O(Gdv?(!1g1Y%@Zddz?9d;VP8qx^# zg4q{g*O^%(J?`SPSpP)TR-v;-{Fb_ND0U*pE5=AOyF?3vWWiUT_q4x#4a@Oawv`ZD2CNr~!RjX$(wHBfuEyN;z8Z6az$2)vG1RX^HP*VE#w>ac6X1te)0W3R5pERG z5ggi59JYlsIke>obf0^=w`UfnvhM8}W$h9Ev(659i`vB*$%1}DGS85FKP4m&QH`Q> zHi09;X^L>#{ISCcx(-OcYPI`)!aCCrH6Um!d9DRB%CgQ_CZ9+pCxITTvRIn;1O#j-)zZqE~a~H<3 z%fKo6G{bFb9735%!n9cBE%X;`(pR3^)8Fm2*_lLZ|5-u%OQ@bR@KN9;2Y-K8P`@Jj ztNID5KHpXU?r2QF)Sg?p)!m=EHFVNHP$hyNT`&!>K^=6jbVbdct+R_G?j$DaA`#c@ zI7A~#jYpHP@79REN(3Juay)ku)PHiC{5YOJ@v>)UUv|i>hft;KmTWD5>Y1HSOq9l(HH;B@NmIe;U1eeYyBUc;y8m8!yM{OEURVB z{6v2)WeT}fXMeFI#q1Dp=7CW4=QH@)s%RvPUMpeVmKUq}nks66|8s`m&APm23rPCs zeW+P~KpLZpd7Zm%LG{Ae}n@LR}m~!Wog~bY16) z^q+-iqi8zWCZX}kL4Z6LE5x(wy)`S5P%=oML3bD=@0GWlp<$CZbc5Q7_PkcV5PGG~ z7I?`~CE>DV)F?F^SPP^p1Cgz3fJ7pK}fQbF_7x(vqyVceo~)JGLe;&2XjG z7#%iS9kzi;R{gYC`+$ANF`SaB8@e-nfwDCwu#b2{KTGdjmzazZi0bn`#=UD)03bh4-Jo`%A? zNnx3oeQjx^bcXpf^&x~Jz0|ATcJr~qmyt8Nqu2$He4-kBA^Wd{YEZ<0#JM7IYz6lw z+F)g~!ASP9;SsSwVxKHHl-?(&v_wj`(shY_ z5e%$$7~NX;FpJYDJa=U``92^K5Rbi+5fBxDfbjeUm5%hJIMF8V@v;R34VNw%bFoym zah{{+vyJcNJLuoV{Aus%Uw?t_xab=6|8oE4A6@<1+xUN7V_I6I#=kZ>Z2W6T2IF5x zdxF99eWixu-#RY67wpVPb>m;WOr%GR|Bl@8&-yPE0(*fW7RQ=anf*=T;E&_t6IT_QI2aeNUuDv&Nl!@oEWuFu z7bJY=3gm)>!m;Nh2i2aPxcC*52=CP=#u5_pE5%5KSC9&$U*YNES4!Gb=LfRklMj#$ zcm5q_iR(`rf86}QLl*0pXs~EK{>b&&Ol0!G1Y&A!mXI+0;h>EEm@G(a#KdwG1oOXo zg|?J-b8|xajqE8W=h@1CIaA)ra_Rnw@v`xG{|{?#0v~mC_5UZpKmx=GnqXwnL}LwV zYd~oeF*eZvGdN*U9*tsc>Jq8i79oi!D8Wg9VH_P0txMa-t*uL~TZ=4K6Ho|fm8Bwx zwID9vaa;hO%GQ$q`*ZJiCNn_wd48`yFU@?H`@QGhbI&>V+;h%7m(wR^Z>I}t<7Syq zFVKEG1VEu7vM8$>$qY^>8vt=qMocu+WD0Kh2$sp!B%7EJou9kMIDl;C$N245KWVB- z=s#BENDi%&S6~b4w*#ZW0-Laojf$a4ma8q!D!W^+K>5oeo-xbla%5W1vKK<~etK&TYiAvJQ}g1oFT?yGh;3 zL;RP1W!~jZa6_5Q_-^IBv)Fz$`~tojps!xLCfU%-I^1D4MzTYi=jv~-@r~O?%qr$o z<;3|#<-@$KNH{o2F$l0D1CxK$X`Z#|y&oT~QF z$3*Aw`;bmPR!E1!S#b5Ky7xIFSS6%2&KJgUZPeOK2pSzGo@bRCR}p+&(Ojs5;rx!v zECkZo%swC#-sV|uFlodqMUp6V zRUEMG}2;XIT@W!R42gG-5Xjq)y{-16;q($+2QV^IjcDgkDRq2kRN&I0F{Pb%e z_F(B=kxyeE=UCZrtgMK53i?1XdAxA-rz;a=qw&mjPJ7Lz9V0^ick8RV1b-(J4D};Z z3uDiOim||X2W~XdMRk@s^N_DPlEKdJNYTW348}|0c~&-S?T0q+5Bwy(ePM;liMDO~ zVl)0%^j)adl$r$=6KTQA;@X|w_UB7I85x~#Vi;yD3&Q3W+HC#$)*-&xEA&#nPNeiY zXJbU;Cc_1xgX@;40#I7$9_YvKAp_&yYJ9wNR?(XTj>vmBF8_`U;t5RrU2t!;H)v9o zMsn`TzJq0Lk1C(h+8PzjA(YVcTxXgC{D|l0;~BkyROfuKQw`Fqf-lUg2k%ORP_9nA zsz<(lX&OQwTl^@kfm_FT(NK7S7U~** zDdOu`+jg!9nP*1hnv?Z)duGE3K|ncekl@;-HRQz`7wPoD+?Q!Y#w*mR>Ns;NSi|uV!G!40x+QK(WWYzBAx`?nE*dt{llX1+iPGd>IYTn3IbQ*4y$Y z?o}{6AbwBF*2dug$eMbFsd}wCiyJ_d_`T2N6;sP=Y>aK_P5wGFPsV$4MbogR=F9g` zTAkn@s>&x}Mpkj58Vv|o{63(PUYzUQC4L$CZ8%X4*Y0J@{5^+UgRB&#b!CXDdW_RzYs?V4(Jn}msT zp(1N+v#B_^OfbwTZFVKeAe6~zR0j#8yU`BPVVg1(s|gPPq&@j7b|&JL^G!gAnIAjd zqg|Z^_)QMMq-JWVnnMWqVM)QY7HRFXg-62`=zpdrc{7KL-+a!P|A%U%sq`O!TscDo zSaLZcfux^hh@|86;8-459o_lE%dWVHeE>e(`R$wJ%Z$Va-y~mNfUsQo!t&MXaObUC zWcH_Tm?d}mrJ+s!@NK33C5hE_p!;02+)ggAYqY>_#|*)4e7nZhc$z}K@~_N{;vM-u z(MR5AHnBmw5XrR&MY{u^mRFe5!gJ`F*i&?vw8LBu)%kEnHr&dyuUB+y@HpD|XNSa~ zT@zMtnZ!e8<8jT)jB&If*QN9Ar&&5L6ftzpS1DbE7wW2Y!_4Cv`!z4sRy_`V=U{-u zq3>32tQwP;M;^G$j7Af|z4idfkRIUh4Q&?v>{%fmXt)dx&7L}u$&Z5=#huQ1?;b`@ zeIX~)QQpgHHhV3paUrA+h_7Nk*r~P4F_!j!6MVCq(Q4v-hkji-2mNy;7-OtGTwHC9yqx>i)z zy2hyaLZ)!*1_bNH^dI$XaFt~BwEj4ZhX3{Bg_x{%;f69QU=6lb7eP0uRQA+sWGu5$gT$wSG1JFPp+D88Gp0ojs1qj>fs;>tguE8|-HmV~U&NusGRTn7Vq`HWa z;1PxjwGAhkx>s>1AWD)(yOm_clMTh?10%o^RfdUnlBC zE%24^Z9FOvj!F`_4S?oZ(n5p&?6s!**o2iG<07d{$dQxWFez{QT}J(C*V%V-b!p~0 zXGkk_Z8dDIc=!6kOHA!t5mOLXDq5u796jTe5&xl=?awM5V7W@sJbV0NRM4_Ab}4X$ z)6SKCTa&8!LenVf=|rR-0)e?NYO8pYa|-Iee3u6 zG0P>U9UbQ3+*vG^q)yE;Orh{W?BWC=%N1%ZldG4yLQa!YuK2ycNbN&tTelh~zs=p- za27W+vwh{BFCSTuF)IfV`rfT>C@f++XFX35Zx3!*kEY==eOB5b5twkHsdDkLxKx!*!B8#Aj zS2P^lV0HH1K1w%{shkhxYu)W_-C;yiex0h|sd=WHn36C0zA~eU10+1>@LvDO&3%?G zrT=+b&!FJYHfw1!E?#NOk$3~g*-C>nD8MJsy%bhl3752zmQC<=s?`m)%c2k z_9&$pF9wnYh_TYZedD<`t5ghT9U3IF_(24=Gae;2_^V9~&R!>xmWzGwhqqw^99&PG zEaoGFfAk|R?uq)$x&nHgMR?1Qzk@E5Z`z9NmIs(XFQOXflZi%TZ#dW0)SXS{0by~W z{O)V`DxCALjzt-VnG?zUn!lA7jT>V++{>)52EGT$Mm)bAlo0>(*$qTS=NBj^{4C#Y z-v2!L{yN?}Bkfl$rHLtgA}w&odvOZnQ`z3}9t^R1=Z#|dq zAq3Vxymwk{t%XT|i!P%5Ui+*A zl5PJ8f$MK8e(pe`e5!9|? zunWxOCiO=8PN9Tf)srxYNSjO|B0n9VbVdpbisSDf(1X|{^j%u{y`_seAllE%QtxEekuWkte;#HUa&bclTbtsI9|X< zOZcBa!NGm*nvk)yH#g4pKcgs{Zd&?7EoyF*r|O_!G%wx8*BpNnRYu@$qK~apXlx&Q z?~J{Xj=14BYNWnFG55`l3Tj%jP2Uo|?P_&ZOShzO6@R+&(Hp!4xHaM84J;po{A)grg?nXWxc%MyO zZnLCa;wATI`DtH(FyQ(q!#nkqn$QG&?7dx<`*@BbT-|^#=0C+It#|(RH|-5u?*!g9 zjJNzQ7!Ud-Kjb*`VATKcK*kGazJ0LbG#;4M$<2B|-XP6W&L5};#(h*9UreCoB;Io5 zGb-P4f$)7hug}Z~oOWLuKhZ$Q-iGhn%xw+tL-TYM2oZ#z?b?^|k9b>@xmo&19lm=~ ztO+|CeM8;_(E;zscgIBX2C@ciI?BH+LEG#*XzIEnBmL3-_Rj{8i(YM<+Jo1ZC}3^8 zXnqQ21x9;U$ApYma@D~#zhE%IXd5@8!YOHNE6t^@t8NVv)ezxnso5X;pFsKhEC*Z# zK;+o+FD4U(CW{tW`o3MboZ`#m=r;6&oH<=z z&2YbxNJyZet549x*ht@#YRcbeI?gZIVq{{~U*rM_L@L&ezAz(xW!H;wk<(A|w|_nW z`_61MA;#QW^_L=B_VQ-RexDM(RlGO*I1I}cbk<$580$cM%*V0NX+f0Ge>p&w3!pP8AjZ0yAW(^PCC6*#ae!@qwT6F} zZ!~k}C$kbCoGR4;M)ukH@xgb^`!(NB%+I~u_fy>Y-@czeneR^!z)v-of_{M!wricu zJaO)Rn?HZFz*c3T7-?58^XKvl61D|n-%j=a{Sj8CA=Z+txr9{!rmooIDLdV*ek{e& z)sHJ>w3)2BYE@UAFO!YwB5mS6LVKJWZV;8NkXe6*T36?bT!6y6w&6+vs3q9Gw=eU3 zLeq&$p2be8t-hiI`o54=m~Y5ChH{8~^9^~^m@T6?#+~Vt#ZGb>wr*`QhYFWDSDR-h z&QUE1nvD&V!E&TaGhX(g*3gG^-Bj&VJ$>Z<8+%iXB(739=zoECj!50@KO6v5l!#y( z4qoQJHHf;X@L1@a@u?chRr3-vPd4^n)vSxmsMGL;`-)JgqoYyhYTX-`gwgC-6VEF2 zh3A=RlJ)VYh;1{)Ix~K%VW!UbCR^Sb1z!EiZG7x9+t4GcN3MU5HYVC%f>~_w#^fB! z{Ho4*gZCNnfc1i98e^<=VYqr7!-@yXSWbUE}zAO7!=>=&!3+M%-PZ zHA)_>mX>K%SLv)Mv)@pU*=kLC} z`2!54vjCl?o4ZkEwcxcmpTQ>Z?|>+8`{?b1?%OtdSe3GDUTF;+dwx)sk zFz--+*zb*hn%URL=A-_aU}i0*jeME$q)P~9EgkF243bI;mVfVO5=ii`Y--WY+l|eg z%hk6#z+&(j;O9H^!x78uOKK`3CMrDq>X#(!Z!7dYp*3?OOSjd8N`107{vCIH`2?!1 zIZtXeAsL_iD}I!B*|rQ!ES;;P+#e(uqL)9oH}|Hof$-P@oiRC*ki7ChXjGxEb5x0i zP7N7hW58pNPBiqqniJfY*?4qS^UKfaWkZ&K^(bS&!}RO&`fcnX7+vP~zSL2*w30G@ zZ}l1lj@)`JdlJT#j*8@EbMfP0^&`<8E*cf-n>{k(&#bT7)BZzzf;@d)dBZovM-YbK z-{_3=zDR1weU&xGZLKN7ZZf*8zB)9nlqyEoRdu#;GrA6dlWRCDFVOvx0;LMaI;4P6 zXs-lag@|&qv#DAN!_MW{b0mM2KUf^V+)puu9wO-AlJO+F#c_+gH9F)-Z$A>7k1D(g z?A}&@ohcBymG#TueSQInbfvnn&44Sbkd;hZ%*(Ox9<#i#nXMP>qrwmad*7qR_wa z%NmU8$mq^!b!d(mn9j_`V-f=s?HU;+s62s0w+)37zJ#z=-H(1iE_F_eHTOdwNP@V` zfL8buvf2nVBcYu?{@x{KHOkO;Y(z>hN-ANy*OtCFb}OQG+Iy%6zD-$kVN zV&iZ3q;N#O`zmIG1#j@DQllajPse3%Ij0wUY&^3xvh7YUU&TIC%$AJw{d!={rN?(Pz+#7rkl(SW4 z6>C6WS&jFl^;OF&c~Rr7-bf0~%3B*C*4on1k>UYdOcsTI)KoV*GHAfa$RtttN+|po z%b&dadqb~Khg>`7`SBuZHQ?VE z>@Xugk!B+N;Ws=a!k=mgUnY9H@1qj^m=&V^h#JaL)L`gkk`~IVG1Rk;cA^U?X|M4&XpXC2y7P*niUViw(KYOobhGz_==RD+u zGe&a`L+0p6-we_7$r*;8Cl;SPGJ8GinDx@nUH#(cd^0vYaT7FsnWXmXRWDW2OQiN2 zMru!n^sYo|pI*epEu!f!n$Thn$G|Rab0(BC-9sE4Jel{@l`WXHC(8n$TsU z<10nSmqEuXxw#BFzD#r+ujziB5!;^&sdbV#h(@AXM9;>f{2lavL(SiVlB+|nOTSzG zwUytMlHW`RQ1N&Cq1XKE14nw+iF77Qf|oEpr%3JhRW;uNIiH22AP{n#5pJkvoiebV zA~K~WLGG$f)*X!H=F`2Ijm!X}aY@7xRQ+ zE>v?dSAwtde(mxVo32IQmalxyhwLj?ePyP{|4(dnir~Xq9Ccvkk6q+HNSRJPxH}1f z#T1N13`2FO&GOSnOqyWMGTLTy(`LCU&P@teIU^qKNkbE>px7ISFq7q<(k}k_Kh7`3 zFEGDENOmy0(@ZiYOfp_gGKu&)cYaw3doaJ$eAG3+%spg&xz})=r}yr|=NBHZVLkROT{VaT+(B{8$$ZiN?DI>WxQj0i=pfnX^Z1?41X27{I%e&H2%6hng%Cj z;+n_g>`q+hx7^s7Yk{uJ%r%#*R33Zh*J(Val<)~v&hpo}kfS?4{U7=3)o0)@Q4eF! zph(Yd-HK;7I3p`VCxga4_K*Zbd?6^5kz%Ja7eidMkg{jJMntKNstYtT`z=gI8l ze7szPj(=ENP*ykVnf?)VgWg;T9244yor3N(2%>(1DoR+v(Y z+Jkxy^_BRBknbv~qObU+tD+;1lj`|B81rmd#@l@TtvdRV7Ee}?J|0OM==<+P=Y%~b zb5ciK^kW$8WT=S<3-k8nPE9*2(U3rZ0F)Rz}0=zVLl^ zJ-Jou$w_8CIXLf+jMv-+#<&>1DA(700@%DL*EwskC6UVTJk=VRfZi1~%Z($i1JyXg z$_P}Gdw?N<{a7_X2nEhH52jL_dRGuzaHN%lrN0FXu1kLf!HVVRJQ)p`?@-M|O=r1_ z-(JhIC>KA~XV<*FmdU~zALx6623u$2%g`|~ch#HXo@Fekpv;Zhr{4poz($RriDzuC z`1m;iV8+b(h%0~jok9omey8W}++)d2#y#3DIrl!0+MSr3=4%U5hMZr_dq}~>-tTl2d!zk3v6&ZTm*i#3jXty4*P?CRJukx6o_i>nk zv4gvKuhdZADAftR+DLveqps|9u0Pm=@~l9KCWUIEtzS3wiHz+G&DUMr+m#|_eg+TR zRsW@o_5=T$(XI?u6#ZGqJBooJH%xHbPN$qLDPT-a;v^9mGpEsCCf%QkIzzp&)m=ss zjepZ97k7AJ#v)NeON1FBeTY9Kqnp0r&w|H6vTq3McYD>k;Z{bc!+Btn8Q8=|1n1NH zT!8UMUH!XhhFgCj`#rm>X}R(5>r62@CeUI)7=o*S1TVT?W*&G)6HNblJ^K^dRh>NU zaAE<+K}|a)vG{ISu90JVjOXCj7vq1uH?<^g^`OFYyKv%+Pqa)`<;H#@Dl+{)IYIlx z4k0A1MKZL`;BRYhYVD#&r%$4iuJhZybDjWU$v%domhCr)?JqQJpFj9X*xnFKc=+~( z2)Ga?qVVudx@`Trv9IrC8l!)+;+3Q(%50Pm$3zhzT#SuF@r(vb$nR@4K38?P^3e!H zQ|3(}iekf@kM;;hxsb_uGek7 zL=wG7>>|%-C)b8jl3USy-4`gt%C|hR8_hQqmLPa%ojF!!hi~XQ6Jj+$fpKiUbkp7_ z+Zgn;k*8-7E{TPWsB5JgW4Y{WkDn3Tae`8xwmSo>W^W^2A;aGuJH2Z5_PsP9Q3om8 zl(weB7g}nX5Xs3#LEL?wH#aYvR5q7yA&qY>33e`jcenS_*Om2b$TdoCb14bR^gK6b zg1NuEJ!-SRwKsLAZdFTWo;USDo&8`fACaBs^tR5FyfyBqmzh+3Gz%p*-=`nOitX?d zC6qNlaAu)KvP3v%)4!rXLg-u0h((8m(P=1xN*tKrpVBVcQU<5Xm;lEVLR+?Or$F$` zycp6s+YGw%8nwpV@3G(icZz;thHxeilJXt4ya*q~MsMpx977ZaV^j`&7l$mV)nn9<4U+IllWL!qp1#?uatRBGpJs9|bbCtim(GFp zQfp0iWmQKvkU;W>M20(J8YB>LucNZYMtXE7xr}j{2#@}v&12b3iy<|OHMV5NO~lKe zo6%ScsUlG#gJa~wWcCTZh~u*#jdn@{7EcI#T=y+J;vRx-UCTx6Scx}0$B~=~i7$-) zdjXH_6dOL*Hl#05$7WSq**#KIbs%$fb;!hBR>^Lgmyl58r%PIHWiYCQI*wMa$~QF* zHdy%A6U3EV@^(57Y{4P4pZ&G#8(0A##yXtRYI(lo?!j#o@nq}0GtfNL7lgRE?ez5g zEil-}uc)NnVDjt77G)^-@+cFE*YJ1a=aMN~3290KMZ{d*f;>u&0KuEi6j6g zm(xyP`C1Z#MLdIRTwk2zbz*WHi*NP2(*!Th@Iy z!1+l~w?ZDwtdBaqClFfY+%v|K)_7m|ysW4Osf?li0QqKpDFbVYK`;O7hHACb&^*|De05>hePekf6#P{TYr`lu{C75-GINhM&0)Q z=lJZVLGJee!{oDBD}^3!nWiMP3eyzlu0&mC0ypx_{j!jy38+-;FuTOA)l6ap;Tv7= zm7+xN#p48moZnR@fvY3^CckF{#y3~I1Y>11R3bIleiEFHntztkQBB2Q)-_AdloiRs z**CP)fsh$^P0WTYSh#n+hJQ_TGh1o9q7Sogy}qTJ2_D>wPib$rY1gXF!5w>*j&jKR zq?PKX^uI~_?)hdocbSFW#!o6+{?YKFkL)+WilasN_6>Va)Gw^tuwY+ix{>nUy z-(eBuywKDw!)%Cgo_G#+OyDBX|K^HzWJpHCsRq%wv5G{erEa%fypxy6ka(%vQ=pi^ z{J|1vz>Y_v-o&q4f0=3nEy-*NnBLilU*H?EF+AmRJfZKS4-_iK)|UynWtpY@cGLpOm1WuZ1V5wsXw&KKV%E;xM6|No6c*R=n`{mqAf@IP4wTp zc>I-$)o(>#Ws00WIfELSZdmsz2D-jl8nAOSxH2nFuBGUGD#G-4u6OZN(wD8uWhYm7 zYGEAzfKdeuSFLk?@_<$ruJ#7$ukwYDG6>^LNq1wJ_p4F5F_SQ&f{saAte4-8 z_5`)JOTjkDrg5KucKB}se-dMiuSScj0(`5X^?}gq#1F3Vw&K44VV&NV-NGD80&t73 zG0UIXM)vuseFEWLflNTQ>oh(j#5!O3D({@m0JvKf6s&W%>sNWEQs@Z2WA{ z-?ODAQrqU=vlUx2F4MM}q7@_o==76PF?fInIF-n(x{l=Uv12rWhB~M+mc?ZX>KO4u z$1d^6httdFUA~@pk&U*{;ixrFT>Qd_GZkHucP6>*y>os*vt9qR(E3~O8wh*p+SCem z-v%Oi$0zh36Mt5qzH4vGIwrND?1|Xr_dY|89OB4_kV^aG4AzUj%uVs!-2O1K;$BB zgaj&c0+bvDx!M5I{zcEg5EdWWW51=!Y(DTSnX#PUAJ!D@V0ddz8ZnMJ67*{6>DDzJ97csM z{nbeXX0K3I@ztCT2rj}q|*7As7R@N^wNlWHwYAi zqRR2YXJCj^Dh-g>P)RYpNkGkQycuGdG)$ z{rCzPea1IXe!FS$6Rv6se6_t)Qw8${s}rZ(Z7frgv{zLlwx;bWq87&phU-)YlJecR zmDhy(?j+269XNx&0_E$be&jEotyOE&duV`xA@BIZ&lSSQ2EH>%jyg*R;r!#Tu~fv2 zW2lJvF+oR4FK7Uixd66NqvDU(P5qeq9o7H$Wc^w-+xib=CF{3PBA(q3v+^n71FfG1 zo|K|(9mZY>{nhfkYpy97yQCkYtB1%~W^RJo5nPQ#+c%mUq zB1LglwZ*?ny6~l^iq$g5g?qFs+taZkXSnQS@mNh*Mmh33D$J)%;{b;kSFz;~4UdWM zOkoUVXo~ECG0vnWZfySt;y)%AtIH1$Skie9YGpg^BbFbsYj8CjN;=L8s?z?UuN#`o zOGEg$mxz-^`a=XYVN;tQwF|<3z>v|e)l`&8$U`16XvwG@5V^Cv%+fp*luGlE5k*Av zP&!|js!cLPmntHj^B!`?%lUcHp@U`Yhm&0?h-2D!C0o-QzY|)!E@t}Qj5#3NxtO6K zII0{ClDwt~?XhR`^lR|6Ic2<+oju#vzN5R-`)Q*rYvr@LM+bxrWs_I<^;tXPj(V5n z%nK%#RI}ee9WO+{V{^bUQ{eM76C)d4Zf);d7|-nlf1pOQerU&f$NHf?*3%d1(I3Sp z%Jgw)y7j{dkgp5LJVq^3CY#wQO!~Ifz8ogM0o8LoxUQ>_3VE;tVih&+>t{+PE{m< zSS>xVOEaD+k+j!&`pz`<7}DV}qK(ol*+^C%o`vo1U>5fI@X<(XvgyalrQL$4BW%Ya zXOtE?yad1C^($-m1gBeqJMd=b^@+l}*$R5{&e1Foh)j~!3098-t8Hi$sG|PW3fM;Z z{LG@#A9|Z4Qp7nWl?V{%-}pK9vQ;&ag(49~V3jYjc%G<*IK=}(tiNar+Jf{~bMs!! zNhkWV|5g(^F>umR{-VFvWXA%bqvGXBbW0^(10c69LwPz00(Cf0L^ABxH70vD`c69D zmyL>ZyfsjNUSd+N|8=BQr@SA@Y$fo^U*d*&K-*wYlu}xhL zi}c|W{a3bRdSBe=3-|5k+ruiwSC%^F);=_dA#g_;_vH9e?~79iq}|kTa@2eK=i)ww zn@p1p3dfyZhVtE6wWN~gesA^O_<xLn4lP=pm1!NemYjirdAR3_R14PoM1T`o#Mp zH7Ue558QTEHXa+ftTMQxt-k#Io0ivyrj#;^8!HPT3uo6?m#=E73#g9BxJ)9`B7@E* zip}bK8~jDAl88++A#LBKf`$?zF^T0(Z_C$G(A5@&6z37MX-d?V5)Wb_r9#CRw`2>^ zxC-QDf7zgf@y#in<;s=VswBQG{tk5EuTr=|uF4FFgsqc=o$S2*C;`0d_(SCh2Xje<3^L20|NfOh_vVJn^gDwU#W z5dZ%a)x5@2g(97zm<}3*P&bw}-xM_pnT{;fm||bI-+xc1>E-DAC;8suO8SR0kXF&? zhi>3~U%j92zAts>?}yIMr|;+M z`)hb=-pB40X@SZt4SBAx3ub2$#nJ6nms+HZ*=EWX8lre)nG@8bT|EvV(%-6qIlHXQF@v6ElLfEGq*Ng$=+~j zBN)X=24B9!XcNSDI?GYzgzif9&}g`HQ{6!OER@>7`jrl`G^I+n5`XA`v=VYKnkr>M zIW|6>O&@H1Gmm(iYxUon^7{;^G9fkBsre>oLT~P&Al(|3u7njpP3R#PBxiQ`!pACi z^2p2$v6UJ{vz|Lde!AmRYrH~#1Em_M$-eS3Z|jNNHCL>SqF^?#-qpS)5I7x6k}8b8*#f3BSqrwcEXG1KAX6m8U)eOh{&1U%#y2)8Fu6~AZo z4;iFJqShC8W0PmRd)0b}qzchiOWeL8zKxB*&pX<1Koif#RYx5c-{9)`X>|)`WZ4kg_jU zA>nU3;_i5IhP8qQ;4_lArvz)VFO14Xc$KsGH-^89?oB9?C;#5IsZ2O4ar)~v;<@Vz zn9%IX@VM^_oe>h45zpq|^9tt~^6z*0)b4+RJ_qvNx%VOdJZFJqT@R3AN?QJ2-XAuN zcq*jB4$=2d@*rv6b>m|n=S4cF$|w>!--Ls!Q*3N+({G`j{UbRuN&9K!*MSd6wNHcS zrg7kBRNi!~sbumBdZ2NW4Z+N9-5~IuP29 zse*Hk0-=riK6a3ry^G7D{?OjwC$j<(U#4iT*VF+i_Op-FX2jLdwpcAz4c0u3eX%Vl zKSzxHGT5nDB*nI?l=m65n9lN>bQ;F_2+s8=JF#)%t0C_MBBMkJM%cvfoF6&hz?)?3D_P9Wu59Ai?duFq<}!ooS#A?%Mc? zuk$Tm5%$>*KK5}N8H5@tvk$7+YG3xjSPv0wXk$!UH7nJv1D zJO;AYfx#WUrvBC7_fx9%E*`-u!8R?b6bYRxYa*8!9fxlMMPJgws(HhrY7kY{U`uLk zyJ?O2-m8YUf1Cy20)vm>iY#ntzViK3ohDS~{fU~tuuZ^)_dfZF1@0Z$mx6597-T{! z`YkQj2)#^&`j;6m0jcqmK=2Pi0hUW9oY%pS?SNDJ|yYmr#2`%lAjl0l2hbTJ)~6!xnAQ_gcqjokEJ|P5Q8V zK*w%vQam+TZ+^twSv~I_{{#i6pm4Qp!Vb#j>g0$^DT;&CLw+7OdLpmlt>NFZ_H>b7K4Bc#$SRi5t`vVJoS*s4D2T6$PMz9;pVFWIiPGo^KzoGlVc+>*a;Ar`zw7yDhZZgNnuQc-O&jXHi?Qoe zh4xmi`_kuqxzjgfH!Q-wfa6SCG(klM?PU>Nsf=fA=-TUPBwj@}uJC0gdRANFTYa9) zbb|7yzXD}kv8G$u z%R{Oq&+SypN|f!Rhom$;f8PkqmQE)?JiADub;k-9-)<=^T<(5oDt9V$viL%qXl}9 z*pTzs-RA9Ylf|dm;&UPi73NA)+}&c(NO3zeGitfc$5Z%Pld|2E`C{sdAceTOwEWq^ zn7H&+DgR%gw3lXDiGH{-kzbt^C+ovHxk%d`vLB7l^e$e*lM^tBc4EjN0WX0K=o`k6 zxs5asC}YluGP6G!`akAw+Jv@cLgAg0CYt;|W-vYwAPoWdc>Q(IIj6`DbeZVDS89AQ z=CX_uPpCvSETM|(XoEPiG%CX2b^b!eLuFxYLn)WqL5p}M+(T^Z8t2rwMhDxw(a)^p zn06_Vk(DBraQ^%}k@)Z(`TFTgIxc_h`cH!&Aae2+Li+2~heGGET(wY5HZj?=ux>6~7Vj{7-#iupjGd9_&ayxSIzlx)pdWF#6TNU${eQ^eY=l zJeoN@O}=(?jbE)033Dh_f);wKD-At{^PfLvQ3l*Uh`lUd%b1SugwQUc&E|o9Z{!rQ zWq9W1QZ@;WzD|iOS2rNwW#>n;$FMPukylLai{t8bQCYuwv^Xu|Ic_cE@wXEa0-$tV z41VXxGIxQH=K_h&GXJ0YM5Fmj2hMb0@_amFU-A`-$6Pq zGE%W@ksViW`Lx=G6TB~8FwFbnjJhHFye|T4hIVW36VsLXh8!ddnYl6@gbGRl=yydy zA2Yl?dOIh&VIjQCzxb!jC44d&`S>Os-YKxiIB+q-eZ@)vbjDr<_4W*)h^J7^-g>+x zRhm4(h^_I6t*V6B`nS?9-3M;y<@$wC6dklRIgdDC!(GC3*j+=<+?AjKr}$^?u*U{; z4R$)~nmfzCa>cv+TM*9a=tp2$IBI4dLdJ$gE)E8re=Jszg$HK1r6bf_wkHP&= z)=6qPbU&R)x%t|;vbaY-U;DNkVv&}gnaL{pv6%}^Z24An2#+&&xQAI_E2r4HtR5wYK1twzLq`~E&%V_9+6EVL3i2E`*IhsXlMh2Up z3c&L4+(jAdV<2=;a681@H)ME8c&Eud)^eyomecPjFp1{kiOE~5qk)*PNt@Ox!*g@R z_8EyTtcmA1ubxGlQD+&2N_FK*%k4xdu627e{{PUMsr2T#Z|IEy!`56_j`79$!}Do^GzZZNAq;2_qiV=5;$%O504+Uh@_D5p2Tr;1&8N(7lC7MEA}TH z88iq{Eit#`YN|rNA|OapQfG%@X{P==LcB1%5E;{ncV2^$HV&b_W*izYX&8-(HZz#c zh5|ymc~VAt;ivSd%&f(o{TR35>O3Qw>E0E!3(0SWtYZWDiXg>Rigy__zN5z-#K}bZ3}m7yPKW5HxoX3vf?6`S%yIKEZ=( ziH{wb)u7NB#U{3>8kOZNzcwL$7MO&$hsanfUw_9(3He$doKcryha#NwqrQvSE0h_Y zR!jI>@5s%ab7ycB&kn7fdqHi8{m0rWe-UgmtxgIs2NVrxK@cQ_K%@urAgq6JR=14! z>4(3mWqkFjpHPXiiO5By%^P4g7f4P=Jb$T0@D{666M7^%WlB5SIV?h`$)gH-dKYKmIhAzf*z&#A)5@6}&t4>XI!KoDGkUXxxo!;5!E?UwSK!RR{v;>` zpqNFJK{dYy&+@NtotJ2pGd|IvcqoZwi{Gca@LR~Pq&Av6U%xz4D*xI=ITzwTGYoSl24g z*NsYVZo28TT%!bu*sn$$5v^(cYx*x2zcf83euF|B)-)a$&T)RWFrz%@WBxYvS_1WE z#IrR$nM+cN=dALy08vx2oY5TZ_ZtM~F&gUnZXng#7Y|&`PJ{cC@D9DO_Zsbv3*xk0Fj!pn>r>byG-1>8${B$5{E2?yEw6FVp zHr{%AEdICh-dSubt=q*bR1qMXNEvnoILkY@<8 zC7`8`xj=L2qd+`X5{)tnk(}?}xiDi+rgI50)Y*+1Vm4cbjiX3XwuIdctol8^qv@Ae z(`6oH)MJa&N;?yewP?(B#th|v(vPSy8nxpe$$2XxFc5-78ues3CntIooAk~66^J}m z{15?K_6Xw$p*f}>vp?Icm3{lUy zQ~27)fxZu!PZyb2x_{ig*SETV*4$4lK1DZ6+#8>6+RROhslh3deI)pj1$o;TXXqS5 zUYE~fc;yMO^z-1I&`%SuoPPQf5H(+`lBB>h0E7F6dFMW%#R|Kbdx)1q67>$nvC!foC=Ptn)J)|vO@*)yk=(_Hf{XUh3Pe=44=Z^P_D z!Jnd!iNFd_w3f@}+j6@p8{J;U^$k43<}`HhwXAePh7MZ0qL6pa^LnGuDBeswdV&F% zt4aYh&-}I&m*_YAE874L4Hh7hw_AU+G=*cGK4hPEM$P5VPq_?TQ&iL!4Q?wL! znA(0-Jf2@?Ym33^^q;`bCf(K;b5Mv|3RtGpa6QDiAubdJIK^%$wZQph7;qbe{?An# zm{hk($(<3MHeOAb%q^!$c558$ur)w6y>b+zXx2OL-obZ&=4pJeGuFQRu$`BsfT_oS zsn_?WSDQKQROcjH^tmjY(a6XQXQ2xI%oMa}#|@H+ia#x&hD;lENIP}}O*2&QrW{J{FQQU0CXz(CQN^?yz6}MncXY>HxSA z=y@syIyI!u$9fp?G$c#C?Upii_#|wDfH3k+6?Tnci8KEP2rHT3YNfD+epOuQ!Y?xr z7P;d+ro{MGoC9T&|1HJ$nNq(hF4XT;m|7MUm%1P5!|-L~-EJ{;IrFYl@LWrAv)(gN zlsb!VH|?$cm|k@gK2CPqYl@&Qlsd=QE`9ikE2o`qJYf8`>Qng40AWYH3!}$R1q1b7 z?@CNVF2wM)$YODng;#!%%HTcd1C;1n(+jYuUU*IX!-IMg@l^Lq#23tWi>i0Pf6z`X z|NT*->DRgMg=z_5>?`Zc{Ab7aG(g8MO2v3`Y@eNNKt1sTSOwW+yZNKdNdMP2k946O>3$*%hApa& zK^F!3{l<|t^flQI_H^@=oVjb7O*gOqFoCf$nyA*9A`Etk^Bp~jc=o8Dnv|V<^?X z1L3y8ihnl<+|i=X5q#=2F<{ODQ%U}cgLg}DrncG?RXft74~jFoHgiEGyL|f#Kse7N zGObBbw>x~Zx6@>EpvMp#gM@)f<&I0`HoFftew=jvnE7A2JI5dgm++M@^IdKH>5w;G zdVJG-7R#4Qh7GK2+2p-vg?I4=)=g7$*h-bl#k3wi4%1P|DwQksg~_dPaM-OUP5Tl0 zJYm5NGWO@ai6DHFRpvx%KV==(ovkWTfmdZ_8f~5tO6dCOm*nLr@O8fwtz$q+0SvH9 zMMH+aZ;@1x{?B6IkKEXmz++t56?~Uk?2NmFvW%l$@ftli_TYa|d|fgW{WV?e(jL0< zd2)37a;uv6b!#{k_+0dAEcHjm7uZeMk(?XG;b07{27{q>$j5=tE3E`RE3_z`PUDQR zOSY1PD!c4rw^8xC(@EdlS^6KvXuEBw)2uRu+yrO;8-EG*ty>wH z`)(}_gnPV682QwH-K{WkH@w^%l<`oU;8S3^7@>@CE_Qe5$do!7Mf!I3Ycsdsx|o>Z z+?q%zgWZfH=Vy;3|H^hb2+2i;S7+!}XeDxKCUL9;sAf%D<=4g-cb`tx#vLPDwlom& zfF}TN{Q7a>K_sn2wz3_fnHI#)Rzk7Dn(#GdMCcF&MItQSUKioeE&8LyNg3f6N}R+? z;(t^HIsICdN2$;kF7=0J6!^Q(EG95vs|g;#$F#R|6YFCon4m-8+>*osB2g?!I3NF) zi}Psg!EZF5yZ*09De_0Qjhl_yppk&SH#^6228JGAt|ypbeA7+86;>GSoGrVlNyh*# z%ABWq$?j(IW%!X@>hKWohQBi^(yVmmFJ$RsOGFk3Rbs6INGNFX$k@L`=!S<`{r&5P z?~(u&d&WN+v(dzRHNctwxGBGJt8SuAe~aVjf)8T>n!)Oz8w^J)3psvJm1i_w&&q!6 zek*fmQOfFGG3f*FWZUJvH@IJoX^-K!dvo^3#-qo2A5o=EQL_(o-R_iWr*sLD(qd)_Of5a_T6$$hJ}TxAPo7`T=iBA!`S;WfE(f$GS)>L=KOPRlu+ z9|kvPqHeLLn;+TvaN&pYzoWPMa-_bTcaLQ7&A)&Vqsplydx7Z6@m^*OXPPfuH1Axh zZaEh>K`#j-gWufj_l3`f{}mtfeX|#`d~;)d^Q_!n+QM{GVMD&Zd~>`9p^BStI=XS4 zUNo(ZBY22Y84xGdj)5THXK(Bmvi>q4h&Xv>0~fiJsTSp8pPcdS^2s}AMVEYlf1six zWPE_wY_bPrMhQEn!Y}V+a#O5SVdebkL}_=jQ8qH&7mX4uRXwMdwI9VaFI0y|7x;sF z&+!Hy;Er?rCWE?$eq+Lc)rHP2H@cgaFUT4bx_otEcw9ksq$-nqv<1=nXmH<%#Fb=cmqKBa2sq-y0bvsGDp2F-MEZu5 zXtf)PBJcqf-+!1l(Ho->?GpU$(KU14}f{zI`4O|A4ro^Mu1eBlT5izg$OYLvxm z`(lsDFH1ClE87?X*Xdc}y8i7LggRpPr<1|R38`cd>;E5xl${@r?;3vu5+c*KunhWn zT#ahgv=Cb9ZGBaDkzku?DP3TGx)X6@9O&v!8HaAp->kPpvbgqvromAYDwB9+nYhrY zlAwzJlKp0ws4}88p*aunTNBzD4TQ|2&fC|irikYU&tX2L>xD~|^!*jBEsQRr`FqkA zo{ZQyj5zQYNF+;uPFye#$lM|9hdOYsJ$F%-J(z5B?0YI4?k<7Lo(010_A#*A8CVWb zS4sB-v-jXId}JN4a&oTyg2Ny*bXmqvs|i-;vpCi`^aC_~*EkeayU~{);#a}X(W*|9 zOpFbXeMaE>=G8o2F}wCKx7zPV+R^~)yJnta#@rw``cUx0$=l4bA4t!HH6e46R#{R9 z3lJ(Di8FjP;XxfW9G1|s(cC;L4go*r{DwdC$iF(6U>Yf0PgIj;2L56@$T{A**BL@J z`Teg}@IRVXP2~DlYeHZ8_x#<@t|fna=MQU&4vb_@Ef`B8-kQjyLbEg&O-%qsG6c{2lMyuYhk-ht?3z7rEqBfBPrsl>2|^FM8*K$T{bbDZh|W zUeI$SrI>`-hqB3ebgjpX`Q+8-7l3kkkEgB^@69S`7mDJjJflBf56m12yW6z-L zESYBD`#E`10kj%px6W7(adhWu&ccZ8Lx#JTU+9wY`<`UtM)boO2BK|u;#=DS)s_Gt z+gA=09@-*Db8VK`nN$nAe3|=vSh*{Bxvy}(53!ZYKfdqH`4)d*5 zX03eEUI15rEmT=^Dq9AcTEDit)~dW?cMdsNzS}!` z6aK`$Q6$-d4|xxNf!CtYyL-0s$Usd-AL5|TrHE7}8fnh}&6OCv-cna~Rl zQG{O{N}YVr*~YeSGT+{BB%+m{TN^g`!ls-r^qih|h9nl_FC}W-cL%jbgupZQvW&F# z3!w(TBRC(!imd03Gzmn*^R`i2IDgM1P_VIm{|W7%9-sMc`~GgN8;py^J9cCF`f2^~ zDD^ZesFmS)>N-O9mnmto>|h=@Io`2*hHS#JJNkXR`Pppn@R-&LksP9tts%N!HCZI(I)4kx zO&cEwJhT+g@TV?j^r|7$fhTlVs7c?>Hn=mZykqL$!C=Bq0Dm3uC-A2&(ueiX_AlB+ zpQZ7W6tP8|n2*>3#fc4FGnWT)sC(WVjXQhIERC1vcCN+0m@dq@>_*#n)qP0{rg%Ry z!fsNgy=yvRIyh&5tMNnz4;BDI8(kgvTVpKfdI1NN&Y?1MM(Uve3l9aTgFA;s4a*z} zj=^7WKRHwSfSH6&gYXNBFTTX%NzL_ z-xI=h&NLD}n3c`M4jR*~b6v3Fv@1{*QHc?wXg>{P7JT0PxDRH2Rp=athut3<5x<|w z+Ny7>uS2FdRX+a4CLM|DyM{51DmBSgstILA1>3AB)CczxUnmA5tTpF%KbPZpg@%&52(+%>N8`Zw+u*0?B*l!MWUT<%jmV)6()l=5NPAdr811Zaw30TrUD(_J+#fq z$)KasVw4`l$iLu$oW}F?O(FgnV>~-Lj^S~z``%eT4b#`Xyy3uVbdC(C_sm1Wy47fw zs|Wft4tH{F6~F(4d1?fu;Xi$Uamx2=XB_gqu`sbZFoH{!RSE+Zf!H6{b~mUk0f`h! z^gHou<-@aG@&S}`NO;camn_Qgcdm&BTGx78XYo4F`ntEZiHmT4?zv$WNpIJg^<_3Q zlxJBF+S)a)%0uz2K|n@ue~*Sq!Tnj@*6pT9501=625R=nGW}aV`;hJgQQ=G~-vl|t zeosMjER%VA>mbb)^ zvwk>8A~59lKo|9TfbvMI6m z+2D_9V2i9Q2hC3ZT?nluT6;RDTwsZ9yf2hT#&iW|BhC#T%s`DkLhC9mDY$s}ZB;5B zVoj+-k`NtT?YrDrxMOHS{xZM>=a*P=8Ctf zpaw&mcmGT-7K%FAy27Z?k?@91cVGFOKe7Iun>goX_g{)5`+?*(0!MsR*Y3-wlgi^+19}Jv=ZZb{OWvKkRARnWZkJ%(bzF zDN?6v1Qee#g*Vm&(UT>v8Hd@QWic5Nmpl#}HC{!Z?%pvnV|g`=SvpcJdaRQct@cz6 zS(u@RT%OCNUIi;&g#XA}0w*5NGiS?>q+gNF;UXIA>BA#8(^JOIANoSMW>vsmyV0&3=jUDe%MJ6_AJs>`Ic$t8SS6_6DvO$sr8q$TpbDJwD2Ck*hOkN+kA4a z=H9G-1}0j6fm&aqYC?m@>IbX7{_UIviEiHO99;+Tga%(^O5{xBCs^^csZW?Vi+ks- z%TqB?q>>TO126cj%=@7n;hC0VSos!rT=a4;SN(!L72Uhruxu{Pj6OgVx1$M~-Pe0XW1Ki7Q=m|6?wg=f>yHs=!1 zRw6L({>ApjloOcg225gnW+VY+e+!`T7SNb0(Q)a;&lMd#T_Y-7rwhP9T6PV3o)tkilY{jQ-<-z)29@3v~ zOQ;%U&=otS7SNM_Ohem+PNF~Sm)riBasu=V1IUV^-BR{#^(?)g%-@aPp9?Avm7u31SZo3W6BB4f7f)8!DD#c zE!v*H_YkyYrK7FDf|-^M=I09mW3=@LmRYo!aspFkz$C_JL=w=1Zvm8R0rgG?^sgxZ zGOL=QE+A7*fZhsp_2+N@mFUmzd%F7Lj?W=I%CdkS{zDq#-kS-aJRz=QsqK*|CqVTn zfUZvhT95+BjL#upGAx+0)4_z2V1D9)G35lN^MbDa^hkmkb|{$4^zqp%8jpB3K9$y+ z9$V>+5u^K;*xs0O0&|}MlNg@|CngZLWl&MmLjXAzP-Z$H2j%k>bJ}Z(3&@lcpjC<~apl|VIFK!2AD05?Nd4Jn z!94I}8sdun3YbCaPy34&ai*NW{5S>7)k!eR?*3-9ZMI;}Ob2uCEr2o9c9{#tloOb} ze)T3XJ_jyL^ykuV0kqBnTKhy=f41HUAj7D;7Tf-qasqUh0c7Rdq9mC83%mMrWck)% z0sSN$Q2oyUWEgdx3&@lcpzovrIxPw4eisnL+dsXk$jvTt(2qu_vV^|*cVE{)e}IeF z4s>l-MSp!ft@D2vLq)kX*ZH46r&M!qN;MBAt2r*E<42;GHrws%(m~u#;w{_l1pmayfHKnoolDv>qlr5uE+A7*fL4v}Ld)yp6KMHK3ZNtP z=UEHpf#0X0tYR%-EdBq<_Q#YHm>;KrxjG4^n+t|v9G70zvE37@X_Kl-3}S()CPCi= zlNGf`En=vsXL?1EAJe9zX|D6#)Qa93)z$64;n}v-aC=uZulz2pYdM>!#>m8vUr1@s zyp(Dp$!gAbt4S_m4jH7!E%q)?2eIu_Kxl7@6BG!j!ITsBic-LQCkf`mySk|1NQ3l{ z1@q6}ruAf-bnz2;#rna8V+sn+(viXnVLjt~935)L;?M=Z~g!<{#GrV?5u|w%ue)$hiwMoI}eQK9A({#I)?FfrrHN{BONh&|m zC}mE4KNj(5z?G^a;`!AhX$XDic$!nJ{;qt+_P5S7=jxQ^{508|o80CkWyB!}tp&h{ zbO7&voDdLKx&W{+g3#_M0J4$*j{g<_;{ovQ!)ZOZbSVJLG9%LkfWZ|2k5qLb^!H;D z2z@R5%_QLiz|H9Z{&Ef|(mK=H4D zt8ln!*eYq$M-QcSde)Ler~A6isWi=by0WX&&*KQURJ3ir?KJiLI=!AHk5P{?zQ6i3 z-Ac?@^(oa{pRDHLu4*n$uO@#b)o2byf0>b5(cqMdPE1xbxvQd_^op*O&RZaIJS(-D zO+W1F)>gd4wp&BGs#*2lY3SK?fNF|V&F6ne>DFB-)htR@^JyrFomuJCyiX1b%N)N; zt;Uy9O--_zr@E>sORwhOW?CZ)g0XK-O0DYO=XQ0hTe7OjT~&Slo3xIVCp(sxTFv5= zYL<^q;-{;c-=$YGKhYxRuTQ1m=NGDmLk5|}Wuqh&TR8u-o`k>2-1#W=)`X5pysW{x zjD=Yq@HO)+0t2D^mnqFhzZ|lFkMi&1NBJdJRQlx|Y6bJh9^wy>gKASRm zAKUuL5u#SQ{0F|(I$M)@;QTCpGX8`Ax);Oe`gb@#^g$ZK0TA1Stc24Bw~q;%n2C5H zW`HPQ@bHT=qF(o3gT;mPCN^fo6CvUs*Z1rspR=hky)fy*srD7Y5kDpB&WcZ1X#UHa)At-C{ zM9*BynRV4`3niaM640g+WDoU+CKxynBHtC~sLY_``5Z77 zSZm@FxvE}Ug5QgJLk(-oaPh4zoHMvtCh{alOFw(Gor1TT;TPwseR$)7I;_a41#o z&XXi+kwPXHzmX6>NH{IBKCNP6PCXtLE0T@;{~H+|G_w&zxveb|Hk5AotdXJi>bYZbxkO&5 zT68gbT`LqwrFQ49k?d5Sqr_BIogHkEKrsCqSt}T4jYB3W*KwWF3``+NdR;Q=J9z;; z-%z~M7vYcdD-)&lvy8FfiEozpgDY}%7ED>7eB(5ZL|Zp>tC4n2{BB{>?I#@qki=J= zwnrh0NaVjlZ5|Vz`6daN7+KDjx|Aj{#J90ui6v;}`bGSwNCWX(~g5fk$M zW7DpeiknSEY#rNyd-jYwJUDeX!zhM3?l5oTxQp!-@&C?e=W14Vo!yyTqvwvAJA{T5 z(l8evMo;^DTQ|8qyRr__Z0?ku3{nh-6&ieAP8p%bD@z$;XrGrCkVD057> z`b~~w@1gY*NHtQ3D8Xumk<8a5cha9ih5Al0^RChV4ip{|2@_p{q$R*KXV)3jT0|_D zNXUd#L6MjRoPf5Txv{6RhSEzaF~b*e7z?N*Y{2~v^dvSNS@k4 z96=v{lWHEgk9y6r;q&DR8*ej{nq40qsFXI-cs#p&can$W5b^s4{k;Es@O60y$E!qg zBKL+f;x;6KsDV(W2sgA&;^`6y+gCoj4b~*@z=3=uhhH$Y>7e^WR z+&Q{Cnv0#fc!G<)Tr@porVJ7i9i}s-wo&^-9=E|6^N442g||Q|PGFn){Z+9*NZty9 z5@ZN~g88@USGf$%=35f89~=DOgy#K_**~=e4^A(IlxypRkJ$kFfJW4%( z>r{4qKDL6LdTidx+oW9t{dG!cd%XAT9Xb?&nHU}-T9k`8|a*?g4d__Zv{LojbL6 z?EAX31T!`K)VsJgFY)vuZjR*?Z1zKcsZFpqoeK@Gnf>F8 z&SDbB)%vjimGWE3fn$-{vUo9n$H$N7@056fp71``yx|aF-T_+!1SFoI1fzgPjT*cL6`K^JCm3`GgT_l0#aa|aYO5k7fPxq}0dhDVJ*c%_ z`n0sQYPDJ~Ed{YQ0p;o?;0@t<6}8m~u@$gYls@MF{jJ$235fN1|DQLXPtM+Zu4`u2 zthHv%nl;JGOTh0jCAH_a>O481L5gKX9>izGvTDm@JhDYC!p2I@ix1JcXri-RPjmUN z^VaZahz(YG8V8-Mnn8l-pDsOd_6O~^B6&<8Z%>_9Y8w$Ixe#6>rD5@^@y!J)grT+TeTw_OjWOwf=rKbizxDl<HMyPD@A5}?$m&j%cIAk5KB7+VN%j~zx6i;3@O;-yhFQ65vQiTzKei6gu9@ci99;7chy zk77;Jy?_A3#>^T=VsnA)N()`y0bQ3mk{b%l%)j+JIPU1m)VjQT`_H?mJX`|>T!mXK z`pDTc9Bfbza=W~2$m7N+PT8Y?tV&koR3*6^J9&PIEN6>d9sVddLwjnx{IC-xGjSyS z!lIZi+tv#b^rieGpvqYX2d4#F@zBqNUt_(qLY=uzMXs*NwDQ4cXr3q0kMX#8Mvl(a_#uij10^XY=M;-R|TVhv7eS zlSw$p?Z@cT2HZ|JGgBT!o-_Dn%o5!|t(wYRQgnCL${yJqHElu;RVV{czq_M*f}hE;mu6xqh_jYxm1o{~i&xEoXFcLLtjb4y!3&x+Z_$f4DCveB(aTX?9KW6uqhU`yL`zJI6Z%Kd0lKh{ zi*eR`)Im6F=Cq>5Zy-^iLqU5poMX@uVHG3!B2NZ#5a%-qAbwC=zcd*3^7W_&18y!* zP%{6W1Mz^mwzdZdp6B{CsV8@~M}MNDo`dl4@-p(XWxGe&`gLS`*s|5_pH3(9Kly55 z7XECQR`@T{(ufPmUXq{6bh{ntPn*w5pyhst8+>*Bv4JfFuj=vzc)Yn=+1k23Zt^65 z2Cp#Lm_?g#PLNKd^`_fB_wJIS`1|PdR#y_XN z{F((~RJqCgbE${59Q__KH85S@J6=AB(5&!`3%Dr(Z9LfLY=!~ z{@u_YE&aJ)XnKfiR%bZ_?5na{7 z>}N<(xR%L8@#}a;>kz#sQ-m69T4M=R?uFd0Y*Bd7+HY?{i1Y(#uOIkrr+&cE9}_C0 zZ$4-1Gkl4jga@FDKsobfqSxvK(vQiXCq^4yB6;#z!=?7@=pBFNGl)McDU+4*@A<7v zozNYj+R8g!4|IAS=of2p~hAbW+gp1{|o zT~L+MC;Vi2H%&W zFpSm#tQ_YPGyYKRdOxJJFUF{%~cF0 zXDYIMqIO4F9&gXtgKZ@vBL?CfAo6cONJPHmH<^1fA!W_C^i1S_$TuJ#j&2p{r7u0n zhQ${I>Q5*$j^L4eyD{vF?7FnZ&s zaHv?c0a@<`6_wqEX?mXNRUhtcG`zca|M~YsxzpXc6D{ia_ldH@s`rOc6J5(ti~3GGQDXI8{wErQ zJlQ=>tUHdoG+p3JA3K`WN`IAp@q z{wS2~*fjSl0oG2e;~|bE+yYlnh1aI4Fu`0jHF@pmxlG{W!CpOMxp)s>>6KN zPGdK3Er2mV;%2SoSq!s&8LQ%!W{UgT)5<@|%4bQ?08FDW7OR5_*$K+Dam}ByK^?Bw zgG8f(fU_F~BY!^swIX*5=;B{$JmkhIn*FhOuQ2N7eRt2Ktg@j#wrKlxqP4wWs>b}*xZNNUxUQ+l1u`{R^z4?zLS* zQ)#+;4>j~|Z6HkJ_}6_rR@(g91xi9Sgt6aWu^@6Gg(8Q2)`~rzzn|dU?xwfQ9YqYD zCsL6gGI`irf{2uWe=~~dxX-E>>BvWv%l){0<&Y&6nHARJ?xP07Dfj9?>KdPWEG0!3 zm)}SN(mji)CaP58@?c52RNQnqF;x(VW!AWh)z=vqU2m|XwITFCW%Ii(q#q@wkfaBT zT@gESdor!*s!&V|;#C|R10nH@t4ZP6xy?MHi?ON2`XG5Tv}m%Z-Daada`$sg1^T4O zSS60jm59gx&D_uME&c(b^E4|uVU%@)`47tf`Nzm>Oo>9yQr~ayP-o^KTi&A8{yr0k zv8B*)^RkV%j1-ChVGkUkvIciw;yq4%Rlu#7$%O&ydU3bs*@w$xe%E1#ov2YDc3oMu z53Atfm3EB@O63jS}=zwU)TgR~)ky5c|6XPy84Hu{{oUz2XoWdyalmv|H`=OPAl zju#J55ShlxwT)GMYWOe1ll^(-sD3Fp0)GTm7@b1s_XsM6et*mTnzG+10GIp{Z+cz_ z2_I+F>batEHa)o!z@9%Vs^QsKS#)~(SyjkE_v7=J7Xy;{NAm2l+URL3gyoI-eV~cR zxx}^ls5EOOUx#Bw6o!v7xAtG}e(zSq#!Y?tx3`u~h!a{m2U;-YIUxvOqBCJIl%p z!xPZvef}r1`^18d9jOvdr0|*NsKi`>@i?A}iuvTovx0Xv=n-M9Um9xZ_{)>nnY9uCKoJGPiGa&Bc<pqKhLJ=_8qYtEC$jSh~I|i6~bD_rP4Q#QoW3#-F2z zWn_@jFjjtAye*yN_{af@i~hcu_#gXZ*I9{?GkN%(>%LElT1CF6@M9vU@dy=`O@!WH zpKGL)T#Zr^9cI7CiaM4t+BnP2ro(~VfBYMDdB;clv6MDHyS{vI1SF~L*&azKm$=ZW zgt!CBSO7(CB#e*~74jPlB`kiBzAi4e{p7qwTyK^98U2@vG%(RJ-RdqrjFCp!7&(XQ zz7oyrThX#T|Jb9CK1ySC@Z!5%klXzJfkW1(`u0v$VXm2f1PL*U?Bk6hUnJ{UTNjem zoVV9wKslJ}Qz0Hh2_@Zt(D!LFzb`Owxm|t_o{)kE8C9myA|ATT=g3&YXSIFt_If}@ zK0_Ba_ZKWN6p^F-|Ji)76n?Ge^ zwHh0W0)m5-j}8Rr@IC9NRS!}WCNqqRwqjClVHOi?5rOV;qT=NnM1{TmN%Z#l5K@%w zkvmtLvOTgNFoU>M#Y{A%#8LKpf-6Bh2g|=;?+4t!b06BqUeA)nKm76UBY*zRyx{Zq zz@`0{Xah=a`nO3wL($Y{3I}_3_Mds-?$*JW0)GBJ8E^u1@_zg;_V=t7MB_L1RvV|3 za6?qzqk`0pXneoOuX|!;W#1!@H~m@LuR82&D486?$Uz%C%uK&yw@E)}JR`omr18QY zMSC|8#`9gOOA0>xWtFbM?d;Cy$4*RtDW~Wn8boROH@FD)47)m`=dD>kqg1 zBQkXmKb&|sKy@ecZ^e+-=0@5N&2!#DH972hBGh7qV}x~0_<67Yl>Mz@7x9U3b{!6< zf+24PDXx$*!)uYz#OLltboBPhPB%ilyP|b3y>RRxK@xUNrddBN0>;TiAsaDuMHAG%zfP+`ETfvy`G5t4ZK>XPNa5w znUr~{=Oq|F_}}f)N`hm;`(a<|EBgC)gc!=ArYVQ)>!#ZipSzYZvcfXvZqehI-1R;q zXE;y-k$|DNVz)tXpJ1cdIRY_T-)#P9FQf3#L3bpxdlSpRqteVexr-A0HW}9Mm?BPmdpC540Bl=><>+Dgyo;8ul$on18!O z^iq*KW@aY#qhY*YAl~jzX6vRSenA*7fQVn_^Djt{Uox<}HjEc^#6RHU-7CbKK5bMO zuMQ!8hL68W`ZgF}mODC(SBr=r>*HT-BVI~3*C&iu6Nw*qh{1nU2Yg!#8PFFCB$Gbz zZwv`*2f2&+qK(h3pbYDSl}htVLZLtWx~UAJTgY3y{2oNY>{-Vln}jDkQ^R)tm@(_L z6HguFIh>6A)2-D|L+LG|ix)?F<{|wCpjs_#J%>8=}YDChhGpA*)y66tb<~Imx~&bel-`h4Ri{)!tN9 zwr%EC4f#$b1D$fHTf}BH-|9bI?1%33N|ccW1i7{9FeseT6TjJ${e%BW-^EG(r~Z6DD(>u)RP1e5fSRFl+fd6O zGFZcJD=HROOJ=*~M`W!Ke#e{hl-km?t1-7?`W$&@03-9ob)+w+lGxP2ge^EXl>3`M z*+WEuQ=Hj+N2WDW;P0fOOKovfQPI-knto2ffYHFnW3m_0WZNhfx2n{sv!* zuGTdCxmNX$r2e+iEDHX67@Nj_>QSKq5}|YJeEQqo$+YLY!X?^cvDbMbJ9av;5;K_J zD(*8fxrNF}!kCJw^a-z9m}&N>Fi`hOm_z`!9u5&+YAF9Xh9#WO@*i9Ef&0QqSQ!l? zomK>IU=NM^2MI`{R6s8zB@fCW42iJ#Gy4j#L{d2#AH_-0 zZr-t*idz?;{EG`jc*4-0t$`Eys5z)Z{R z?nN8U<14enmu@|SFW&^Wt&OWjIN;pXp3%nVKiY>0SQ{;uNB;j?`!MbQ>FaTRWdr65Lb_v58icGC?7@} z4rQ??i6XwV6g4z^IPDN#nHi5U``;Ptx$Lf}m#T{fvtc~j?A3h6?sY>^ZuB<2UWcdbn3-p=R9vgYWVUl0va*a-02!G6<~Wsx6} zC^|Qrd4v2^y-h;lhPs22`Bj9oKX@jO|GYoA(ipqY4hz_hY3ygQG~#yH`xTl|nMFlv+EM-fkS zk(<4r#dPb4De*DKx@(AW@9%5(yN2c8JDT#%^taF4NEU3k7zTVS@Xhe`-}W8i83yDZ zWB|%9c8B`%e)#Kl4tR4~&)c;d zW%OLg^Pef5{3n*#gDK8zrj?kawA3V(>qhv_FV;?a+Tdk`YfqCsR4vD(zU&^I+n>Vx zo#4xQS^K_=u=GA}VW24(8VEG~!lLUn^t6lYP}sc#nM;~QCD+?S2h5Ui6^@p}QvJ$A1*!yO|GYt(k8*@)g}` z5!Shz*?{~q3fL|dJjwhqJXpipii2v|L_L`ui>Vyz`>eK2W|V45+k316C#bVhk<*bI z-Ob+z@c0W85l`>HL$*c~yDi(IEsZX&p9BPm<_EaRicCd*CAZ{;!tdqz)TQooW+PF5 zk^0Oi!Ahb;(+_~Y^X19vaQy9+vt zsJ9*f>G63H3$wr8%RsoWBl{U0*)LJ{{$zK*Cz0FQo1ciUZRly>Bc^7=*GID49lns; zxY59CDvL^zk-p(8lq51Jd=Gdp z2;V`8NdNG?koUasy}AIM_N4H|Oq7=| z!{}mnqmN$D($Ts~8a^2h&~5kS{|@&v zh6O(VvM|2Dt@rW2c#3$9u#bO$c+3p`K%_fYgLG|AYv796Bf+V`zgvZ9cJWQnaIUMK z!f2Ihv?k2T(0I3t%OnI}PV4$_pzj6IdHXQ=L;6t?FQ2hp(%IavYnMb^Q|Ib8H z@XVfjDc^1woAGE|yhDq@XA$I!yxJG(KgNY0(u2GZmkm>l{p~{`vs%vO_cl;O*<);I zbgMhl;C_IF?iApLTv`m=~RM2LTrA1F><=gAkim|tS=@CNB8Zm`5Zc?G(+ZBToA zeffR7X4M|FGLqH{XgQl_#yf-T?<~Vr1R8t;Dc{W0F{e;(A`SP2>Qt1vD<-REh3sa> zQPwi^Eq4SfUK@W@BkgtDT>c-V&vyI%5!tn=?q9aq_}(XM0s76xW#MMyYkS>nTtdPw zn~g5#wCpSs2q9~NDis;u6U-SR%sF;u2j*lSspXh3=Pd-dEr~d?SEA#zt~hWGBk+fT*3BaugbJ+Y=<=cAdx53;bhhy85T&wcd?pNSf_`HZe(F07 zy@J`RvU+593Z|L$Zx_AjdD#7E=TF^Pw)z%2deCyzn3LmnV%}e3JNYS2Nw12``7pz` zA}h4W$G-R@#y{>ae9>jnVAd5_zMx;i_OEpSq^oPIJKsJ3y`fV+LX^*cYZ--MWWzO~ zT!KYY-(1y+T^sD(n%96gXS=YVAmjhakU=yUsn1DLGltW|2=?p z0W+^{J^mjp3N2{vX)0{C#fZ%x!>9hNqJtDS@?d72=HVcHy>*~fTfjR9(Nw@`DTJHpq>__oB$dv(q%yg;;4^urQe2UVqQMS(6W!l|$#gDxO_F|43V_L23s3WIJ1r66ITu5|mV@ zzI$%!r`PWnm;V<_WhV@CmLObZwN)T{Y@XV0WzQ1E$S=s^vO8tMCz?b4fIWK z6zD#lA^=aXv@;&yk>P z)yz?Xx}%kQ1vDtzHT4Gqw6d`;o)XS#pOCIDYpQ!jpq{?6@;mLv6Zlozua&MykT&)| zEg14eC!oQhUjpa=xgRhw- zcw#Ji_evQ?RFqyCsXayu@4QC4;jKkC$Gry@=;m=|v?4}DR*vW?<)pMck-Gv{i<=K4rqRV2HLdmU|3-fpo!3A;nKsl<@0nG5 z6+Sge#b1K5O}8Gcx{4(`muPo$$ogP>O(k2XYlm(|e%2}gDh^{K9tFsl(v=wOi+#`M z{tf9p*_;d;b+jZmlTeF%qi*Lgx)%WV?`V`N%5%To7&gfC&aG(n_DUhG|8LB|POmf% zZL;Gw^gk}amZPW%tFOPQXI9-X&m6e&4y}g)X`Mg6&+c%}k&Goc;oo)E`}G0qTT`}Q zOMvfv59pU~?FOj!!aK=#cz*Hko%FjVt*-4*fY86uJ0vy8(+ZpVzGrn9Z&NV82ESU# znnIEKedSN-^G!OKQ&XthS>I9={jE4ogJ89YB^35!5uEm&HuT*bL4q62RWR9KP-j09=A3&k@9*V1yJ=U-UGgXwEiu`zL_OwD|6Wk#aEA>-h+ka{B3ae8+&|4AMmO8cj zG(73ANWy7Gu)^tyW_{EH+I91w%uhN1~D&4PRilN*&y+1 zFyw6*+N@!C#hHAZCR(=iq(PnzI%}jkJRS51?=+v+FPVEVH-fY`&ktgpa$Iu@hx|8+ zbd|j`4NXJLGiQvoI4ZrdYRFCvQ-Ye{m{AJD|69C?!iKJym(zJ(ybJ2utCv4GBiBJ6 zK+V0-xM;&%8$&1=IEAXQ#bwh{#u~9hfukye@oRz~t}&~@1h&t~$p{G0msh495+pE5 zPK^Q>Bb~8%LzB5@oMTNJ6>H0#vX74(%6+3ljj-%7U0-`CLsnkC(PrzI?Tkh-0I~ih zq|0ziLF1dy{u%wzgkYpW{rSC1`%XylSaW+J39#)btkAhAuC#rMfDjFfT0 zb;jp++3&h<7$QGDUG{GZ_Jp_eHJtj`*r=MJ?O^{?-_@n`#vexNX8O#1U24tRJzDc+ zka$IySoY?#6r%0%wQ9|U^}Dj`qLR@1e2nzZjLK>IZt8-sunL%F!5_3`f)B6X)uZlc zC4H;A=HFUNomRjrVWPZ{LuB~Gg`;2#C)xPzx*?L~nI>4|uG1MK&b7SGfNNpS{(gJ5 zsX8!FVEytx7XAJ;M9Wx%_17}uMS=3%_J3ml_~S45neR)6HmhJ4zDelMAWrX;70bLQp>2@Mgx##&}w z9wY~?=kn%_zz`hsOp6|~SGKpKU~K-!eyHbS%#UGLP~a_64UVyrpK(6*7Cllw_o>_V zL(?_*bfx??+QU|B;HalKxIwx0)^E&XP7Mdm{1-k5!Qy z`PCl0aMe4p1;&^?hmUFnj!-_v*hY%*B- z2^JbTOQC)9Qa$o4^gHFX&>eMWED9CDvImX8vG61553X=N)iE;0f5mdit7@@W?u>Hp%sY|{J=x0JgJc;t~ zXNUL~#6Lz3)A^Bp9sbqw%V@}~0rg83Q?y1YH6lAmNYK=_tN(@TmSSJrm?lL6&z@>u zvhiNN^v-FBdSx~>WZS0(*2qg}h6cx7%Cyo1D|IcqENa~(qNEx#{lxGvy1?DY)T2Qq zcM&b#(;#- zPTN)-i?qL_{n3qnfApM;5_|T?i^!xc(kFRh2DpSr<84LaavJMWp448iN7>+RZ!OH4 zR$4art2fz)Dq;2g#qU5tm~n4T8tR;4TV&`4U1-agoBT3;=x43#=^BH-Z176*O*^S< z@N(tH3ts-xZ_ZyV`DYUO3&@Y>G=!b}$?x8k)%p_zp!lxrXv0Uq6yMd&Vz!`1YAq%v znSV8fm%TQ5K-u6QsG5C;yyliO1Vfuz-yj2fX%-)ylMA9iC-{oa6Vjl+7{SMo*AN<_ z^WG;dH5L;RB>QgyBkmVQ#CP?mjl_3#ujAC?vyTvvrBgkFm%c%=#Qh3jVw?oTvZ1Nh zC+1m=7HpybURf z=-1cO4oVwWi7xiT*s!J+J)w~D0o%LejRRbZsP_9S5Rwwx-3rW0q+cGmomuD)0c%yt zR%C)FY zh49XhH>(rt02wLA4JSOv*7&eEs0rFv?pcY+^GQERCDKm{%68m(H^}kSHng~{|3b>t z@&+phtGLBiys@KV)PzicQ@>X6a-sjXRb0}g;^~=+OR2c^7OR&vxK^u;kbJj&O-OlI z*5qkn-=F?zov}Bqc!ziy@}EJ#67nDVc?3t#L}?a_F8QN?=NANJE9?5FE0gmymnyLN zl?aD^tGkh&aMgs|t;G-BQBVoB&YzH$d^b?aBjKJorFTQjVx1gDpEqy8v)bmmI$ICb zKWj{)?j{;^0HP57KiNqEue5wCcAtQXe#T{I>sh#Rw$k%XDv3!0)a(P?Q6GwCSF3&| zVt+*!bnZ&J9EJqOqb*5d3RfC)5kvBul>d||Y(L61_;y__uJ^B1aJ?20^gaH>|E6A& z;oU)EN6`EszF0q<=I=O``Z;?WVt3!_)VwSXlT}H9@hPU`qsy8RXgRJG9f40{>$TS~ zGQ`(;k$(ryli4OaSIDN!vBpIdM~=FUJ}-$2DMXnt)@Gcng6mbm6+mXA ztVqNPDTL{$5>TN(J%V}&_*MDQ2xJ$MBSxLh7(a%TYZ;9Rz!;WwB`@Lts-+l<+TG{=hdocSe5Q4qxhmcsl0_!l`-R#zp~ zRwvd}miC-=**VEUo6{o~j31wY53kdl%fFE* zRWhc&{HZsP)$0x#nH&!Tie*)l{kt}|GIc}uk!2s_HW=hE^-opmjOjv$NojX!H=zNV z8vJ+F6ECGS_%zA=vZo@#Ml+ASw-c%oYvevWXf0-11j*h)nr8(M z8{FsR)nmFbuKvsJwI%gm_NvA^E`kU;G2U{P(T) zRpK7x%jnaVv5QD#bhGzF?xj%UHj{2Z%d z-=tW#-KRX@D|r4f6cW;hang&kWmHJ9$74*hG)7#I_|namWepyAg|qH;`v`ZIdif7e z-~W~ojg5@CvsZMbTj|yZ!h`I4nR}h{?-r`e&{)|;Trg1r@Kx0;YJvkueG9!edL2^1bic2sF(AsnRtT0M1pbx zxyuU5hDIBHMnh$+7+)&wAM3y99dUJceCbXeS#>v6C2y}6`hdZg%D8e8zAxU=jEWG{ zwqM2%)^FGqmmjRTYcv%m?d}H)TSf+MCNqix0^cvJCi%qLPav^A^R|)EpESdX2jD&V zV3v0ETCdqJvrb}wcZpX?pw}y;W@>&5VN2|YjUN6XpK;(WooWgO}b?qynp=N3XF0$@)dm-PhH=DoEH{Tc04?UPdRHs}rx{Wf`rc{DPrA zkSSqwv<@Tv4EV60oZCbLwHzv_FQ2d;HfRp6Hnbh$supneS}pg0fCca+c4B>>$XRvo zmGx3qWw+fLa`qP2|1MZP1VG)ka<;{K!SZSOy-LshZ0bI#Gusn$_Vj`^M;eHvIYvv3 z!8G`O;l($3!Ah*&6RuS5Sn_LN#|VYTsX-HiluUdQJ&Lsc82z_O)JNFz8fI$D>d1(IIoswxd%u@RshQr30yZyQiqG~khMg5TSxYcw9T(WsEQNH|II zT@kIY4(Ku(UmuH7jm6URUYk<-|F$X2SB*u#-Ns@<8uJAk4R_MxP!~TiqV?|A&xI7e zwG8KjU!&`p0F(a*hP(+zpz|M`ftX8|z(3e)cF&>-Zrhkizvt8Pf6YJB8|xwIQfQ_{ z?A_;^x+pX={+X_%T-IOT;-87~v0ph6A`rq@(}2RX&dSFU!lt;J=F7(~Q)V6~bH~1< zLl{{|>iq~8(bgYrVoT0QiP-r>^xL0)jegj6TTp`I6`QXt&-!E0ZieZI%jK;01_sZ= zEcM5h#hci!|Kl`R#QdjZ_iZsy<@Z;Z$@+KNU#Uz+UgV>qY+JMe!#HM#Ip0DA^Q%h1 z=3X1n%`EhTd9|VO$R5%0Kcw&$!mY zOu}tO*yy;R`#r|J(4Hsk&3GTMp5kFWpnZ9={2<=T-ipp?2P*u}oQL-K^JW$&oaZ_) z8TltWon?_7{AO&*d$V+kn7IJU09-K70ic@ABa zCw`pc_PaW?C;K7s?gjRI=|pTX+<{9VAV1xcaD?BgKRR!Jra%Zou`O|rpbRg+4+M~8 zZff;iOyy|9dg_(fSO}8$BTaQO(v1g4CHCQwu39y3kwD{*UHNTI3w3{CZQs#}Pe&*2 zUqoozKBMu}%gu)`5vMg(p*~je(H>c2LHWNz9Z0TO!>bdKhX}&0@54MQ6S8&ab>7A=?5H5Z*rk-D_&_SmKt-9Q7|b{5;R}XMf^*kq!etrB?Ej zRL1R;k+J+ELh{At#VqdM-2395KJ@+f!!G?7#LNHj7e=TyLlK&w2)X@fl_b;-@zQoF z{D3bZxqIeQ4LIw7wo?En_hdDA73W82V8-7A7 zJ%2@lkKT^vNCLH2IHwo!MW>D;vE-W#buwX#31t4-b4RF z0E;Y@h(K;X5|V#SZC~-|#B4=j-j--)Y$6{&uaR5JYkn)Q?U6QqF+)Y%J|?7;q)X=h zb8~0E7^PfI>+^q3sL==;ntRFWKK;xPT6;dmU(fhsIHOu``o_UweB_^M5`2O!6!_Td ztcnfKXMdbSgS1R3P{WdGTaG;Ye&1-Ev$vT5v@0AEpTvy}oMd%a3_csFWWdi_=e% z2~)EZqVb=wn&u!=85O={L37c!s#_w!!ZDl$340 zQ{=tJ(&AvsDQ^mQANK5WQ5)miaX(vynQ&oWO5>}O+=OwPPtRt`BIS#7XqX$1;!QQ+ z_k_pLjOa4aKUgADm^km}DXcy<6L!11@0v|!Q$-D{R*3h@P63;f#7e1e4C#ZU&r5cD5)P&UcYfJcr4(9 z)X#i>vC31wqrX(At66UqBH_ko76n<}!Lx7{SEI#7s@k}K)*rJU+Eh(*vWS$O5ne?L zGv8{6!i_kv?9^ZsWYwO)V07rJUjMDvRjKaGu!#TB8#*?xIy;JqPcO`>9ZK%PjHc_J zz2vs`4eyda187BkX;!phq=qo%0m~F~?p}&KeS?SbyA#G-GVsYkzVbMbU3ByFbN_upM+YF~Y%B8Og) znW;0vSevO&Fb#=4sx_Rc;P==tey1S0UDLETifC8lYq@$dKo%VdPJpX^-?A;~JAN`BoC9~HordxOI{122h)$}Xk;j=BDW=%6i_U$D7tMcZ!hXX$GjZYVFc)OUn3PB* zbDL&WN{Oh<#|GnNTGn0LqvLdck7gsp9S!^>Q^j-HwA%sUMb6=LD@7;@!%vm7W)?xF zxE~P<#=mWQz=q+QK-d@xr2`#lvCdwPi5! zVl2pcpL!gZj2gRnhs|FI&ih7{Y^_T3RdWpIoezo0uc7?mju;X6OZWs%50 zU7FS69-tVh(~p5>_twkN?0D{@5uCU(mY3az@s)ptX4~4?|EA8$Hu$T`nr3~>RQ7p-^1SIUiV6sFv zGfpoIK3}1UTU!!+_JeLydUK1}nSC$H;>N$vSL6`xaSa)!n9$MDkEW&6rtw69IZ5kzLn;=Xi$#Mglld<_Bl(kU^~$pR7kK9sBW*8`!EhnfW=HRoX8Hj3 z52O&F9~hfYg(Wp2@bsrTNgWc@KPy~@-H|P8N=}8X+1rk)T#!EoJCl*fSDCQ=8+yi{ zf22rF(48JVMh@M;{umQrsmQ6i-l}JTaKzI{b#=#ReKGcC)lX#}2r$S{o@uD`0zd}G zh1JPCEv1eajfQA6tZ&fh)cE$%i7WG}X8-$ts4*J`)q;+){lM?6$>oP>-4E-pqFF)YVMn4wYtg*4a zOjN6;(9B9Wk`r2%Fue=dZN?so-Xj5@nM+i9aM33BkjEC3xBo@EN^El9y^04?r%DwO z%6?1p11sm~?L)05X;R|l3!c!_JkYI}s&uNI@yY9~AxL7c)m}TKI(ZfrlETm0!J|__ zdv)Sm=HeHAF8+gI9+j+Km6y&;##!#^S_)($e%}?3^%Jp#{O*A;_{?N}!S8k4d;q^w zOP2u>qDp=bzHq#OJBhCVjJvM6qYt3Of8O##l^0~QdBoY3R&M+<{O$^^p9v*kEvKFR z6c)3$42H6P{?0r~b2p04Hk`XtIwqqCQC^Vh|DD!5Gv&87+FMWAPZ96&+> zs4$&f#_rWaiTxiB5av}e94uaT54d#^sZ5xD(&R!ZWAbBjCj-y8dCe72(EFU({4Sb zMJ6eT7R1B@N?WTm`2ZuQlRK;Vg=&7W8_EW;O3G0I;K1${JCdUFg@uOXu-&S8E|H=#LncPbh=~tke1C!Rt)xYr(sq99i&f?%Jn(IU%A`^ z8`BzXw?`W;CrNbi^ec6VZglSH$^hUDUbyh3WhHi>bGNLigFEbhCly5Jo~H?#x(ClK zS*?r0$;$A5O8*Yb_ejqt!i+i#`_r}_RjJ8#ep8GvqEYW#9er+1b#&R9b5ecRNl}C3 zDXY8G$$9Po&ac{?j1SOG&39i;Rbu<-#M;rx-lK;smo)g;=)}6wLz=6xsa~YJ=S})B ze2i%rrVAfIlZ`BsFnn=W94f?T=nHM=y`m!={Ye_0iJJdo5uG$@G0z!QxyBEUMv2xO zsYxfc9%F>pV#DsrzMw#`a@EcSoF1J8(afI3#eM8;L>HfbWy{te`aGKvxQ^reNqgmr z62CjOw30Tuxi1J;f{EM;SrBAnQnp>dk8>~Yuimsl*%1ucr25C%)_FIsU{&{zj-CZ# zD>Qo>W=E_~)OUiqRVPh@*~^s*0y{D2J{|uwLD`p6?g^5^MKd|kbQUynr|3j&?v#^9 zB`#dW;qJ5Y+E#1unA963=qG;cd!$6gGA%M{5uj@O1-2TV&a99fNGkH=nb4WRYSNvj zS-`z=q}fjavlSrwlB^i#t4W^joI9?^FVz8=$YZc+kS?viiLx0Rh%J^T`Lsnv;c}!7Kj|-!-}za zO;RWOKa95;S|j`#7g8P#F!;srvvJjWmXQ_P6Kiolx{37CAxkM4{Zq}!tcAccooySk zrZO433=TdXFz%rC10!F2h>K|?pg zzt--f6U!^&@Au+{#dTm_#dE@@ir4;nPO5(&)Y4B#L^~u#Im-x-mw&Q^fLVo=(Ldc# zGP=x79>83WRWxLs6V zzf(~o8`g3W4@GaQ%-OH?FTBv5CEP!$L1re`%C_b0>cm@>i4R?`QW=lblSrl`bN|LO zUj9Q`m_6$z_h>T}r6McO$>?$pTeAjhk0y zw`WK!1N7?JLa0O>8SF~EC{-v#oXel&d_NZ{U&xAiS_l5ecsNsdn$T8 zAMUqJ*2)ViGL*LYP*o3+EpUBXh{a+l6Wl zPSPBl9v)+?rxDP==B)=oUrip0Wld(Yr|l?A;$Ar2tbvpL-_&sL561VI{hpV!`u1VN zjrGO`G1EfV?JvILq4bpPrug3d!?_vv*jFk56(rSVxi?;K!Y+w z7YA4Bg-%Ck;3dX^KnNtuKX)I8Ug^OXYUx(95Y4fYi4y+Lpk!iuTuZFH_PDJpJzO;* ze);(Svygb(zh4{12R?omWP|(@8;Lh{@1tRS%*Su`@sIy7Q~mrs4h$|h>btB8wVmJ zpQ0-9mc2o$B1aQ-bw>aY6%XCOU6e<<6MdcE8%3$2;O>`{%KnUk<1dWU?3L`%5}jAV z$Yt!Og+I)g$%DAZpq>LDQ~L&~r|QYh`{Z7>%539UwRq9y+C$yTka-$5;W#Qm(a|+NT5q=Eh91Ar* zE~=-g?be2|A$|;}Gu=I^f~p$@xMUF=*wkTu7$d*0y-f4p@-HC2yPD7te`upSg`soj zSs|u23cFjf^3ct#D-a22{lV^4(hAp(4O=hxhO4*%%IZ6r5dl$lJ5b^NbkE+&0r^{Z zby0TgAzSJ*qzZZUBAUi&D>-T~80Z;R!87fcgtO%JzaoEUYuj8kT@R?(MTl8>ic z9dKYyYd1yZ&Hg}qHM;l@2X$eqnetQpxt7qFD(#Ckd|uZ>b(xdaWQWDp!f}#dy0h|2 z_}93M*^ux(BRK+_6nc99UYuY)5vbhjCtAP>8zIBTDqsZxI4JS-^XG(wJ;k)lf4E-C zT`hf*!+ve=sIWUc*KNDy$3gPcbX(gW`l@-rUX4>NQ%uDHzW=koN}!>p4)dGFYWvnw~N`3s5p(%AVFMou+k6ACX>J6Ez&!c&pxM*lSX^;5s6-s;A>uIdu=RdiK z5%X`4bi6&;@g^zH$2N7mNjURiEgf$gc?%NvZqXw-30#^qMpexR6fRtUf7-tK8sfiR zpL%4Fn#|1*$G;s!&w4WhAs}IecRBYV^=r&whRE+zy?{VRBTP)RH_IoU zwg)w=Y?j$MeU}G>c)#jo-*<2~Ix^aCsoA!*uRwJ)vsI{7BVK|m#SPR4F+#I?v+K1h zpE~o6(7I3b-h0Se7P)`rm65b{gfh-=bim_M0LFRr#{tUQ??i7OLJ%oQ)$f^06#zOr@O-WQEW6Moy=jV`!WPx9Kv%_C@N82 z<086ICRBQ4BYSxB9Nx%Nn0CdqQ?)`!7S>zR`_lHfaXQ31$lgR@_cdBbE%0TtFZGlq z$o>?f(|7J?f6;bEwEAky?Pj7 zTs`gX)^2Vh^70>a#^g312PRApj%nPYbj)UkD?AnsyTyA{2s~R&OPWX$!p(sc5u3co zj?1hgo7*tM?#QQzw~3H~jMGPB(4VY|&ND=r``N5RDRxI#&MTme$X_QNyL^3HcfJT; zM0k*V(&N_--b7i2I--%u>0{*0Xzph-`(%n@Yc=tC{KIVdZ0r4bC!k}nMjS&gU$Q<7 z16%S2-#Au)U$&9(w`t64gaw5Vi<-hvc|H+F-rnr#6Q==t+)_Z2%T|l9j4Oox{`b@^ zBp*}QM)rPeZt)AU^UKT%QZ*cz8dDM^TKshno0mqY4Qdk;Tb)j-5wUprgO5M~P5!xE zdSW;1X(o6HKN8PQ4@r^D{|7)E%U{B8?r7_DZ*$$`;~@=X`fetZyOs<~4ph$?eVO6o z2TZ0=aDeq6@$Lv!W#b>tW@hd+7rgugVNL+bsG@O=H~lKN+NRGEpABWnp}cTkqpvx(rCQlJfCJpUF?nTApRI zc2L#Xt6j4v?7zvRcatc}oee0^7om2BcJVSsz|+9kH~~Dyz4)ZTa>M}YGMWD55R7r| zT3_r_S|YG_k>w5yqYB))K5F&NM0Myt)L^PB5L{s9YS-JhC+V(S>(aZiz#}8uYPq>f) zG9jF$Wr#}|(LL6P{to@bg0C@y=wf18mz&`3>BqsH^q)~pJB>Cb%H{F$UpyeK(DB%U zYCTRQ7N5MZt7~STtnW6|_DSvsAMTHUdLWRnS+?76sv^5Gu>n0j_hdax!O6kZl-a&6 zvDu%Ze|{ppT(#tctNuLws=-qiRcEiNTDrOT4~y2%>i$vHP@Mm<=e)Bb!Rf{Kf}t(! ze?@;UH>ZU`!g5xWZMd}?2M)%wNti#i4mqG~`P6{-EA`GTxbf*d*o~<}A`}i3xUKl= zz!v2|jaNZuy_L+){wCn=20i;6WxtDnQR-axL?T0jUkGWi@4q~7D5Sq^v7UavCU-+C z6Wg#&V=_();X~8zcgFfM0MlqLyd^lmk+pCd-OeJ1mBkHzNo=E*6(x2gi3|N<5E)w*l4;j?}!8` z0wkCqWGWSM$A;ox)6E#C(_?IdBs)%0=BCbRPb|<$O4fJLv=yRl@db94azPdVaVcav zVV6kB@#0=CXizONRT{P$>^yK^7Q3g=821r-!hXhdk|Q^H-q#5c`h#T|Ni-wT?Edug z>vc-)luz%yS3Rr6%lt7|@OXIvk*Q`<_|D}q(-kgmMtHiOXJ$!SU%uoX^)9Y=&A%{v z+oB40pQ~83PiIO%I8=6{wwU-f0>i0)_)Li)b8|O*R!Yr{bxP-4Tm4Wm5gL( zedI2f+qHXI@$FzTp4vb4ny~HIZ{XGKAakYDxSCo!hR#-3C{WGykYH(SA-Zh<`=j^; z%J(@WZn+<^$f0sAqf?QczeF8Ttl*Om`}&Z1{?gDDF6*M!YdV(Kq5eWEv=BxiVYI-s~vYf)sT zB8z_O%}4MkX9%X6l5F@fF^Ixj`VTWP_jeCtWLeP<^hR zf+lP^J$N)pbY3Poxdw(j1|N-R1YY5ML_23yv_lO&z(XYq6PEZbo?d43CT{DT5WcoJ zQ;m`u3qfFJOR+ufEzx7hrU0W#BA+bPXW2WGSrC0141puPNhsbfwdPqzEwYI9PFj%9 z%hpf5NIZ*r*P}65(M8F_ipuV*M?KDKLL@*;gbus_#SV;vx z`m8+2eiPL>b#204ipRUUk1v)bWirxk6AqPk2rk^dCab_eN&(bOB*ZV*Y961`L;k^G z&9mr-ZIko;eiS%TBGIg4?@5v@(h@{mYhPwUfh&E;gu+!L5i4_OwtM&q5%kKUJm~jk zd>4XyHIi~|_hCU88R{RF5${fUgrD;$#(n%7OMaqUWSF==HcVdN7W$G7llwO>y_)_a zj4yOIs-%w}=BJkj==F6_hvNj$fP*vC!97+VqEG8=i9iiFC#ucCAaj0DgXNJ#?%B;Y ztOO);(&+I{lVed%>S{of_uA?q`J|1BDFcw_)|*O@tB&_n31;uWJ`dKnYB>~#@#Hd$ zG6cX8Ey4Wrknv{wG8d{$xO$`)DtK0P6@|FhLDjGkEk41y_nzaI>#V}HW^7`)e{_@9 zjLYL&STk-7dbeakSuZwGf@un_7;Rd()l+*(KhV^MGVZcwd*wi`J3W|RQLw`3-_*?c zM$E_}cjwZ*EXUcu;NX_0zXcO!m)L8iv%;i56u0a_F(*KDg67; zm2!qm#FDGjTlVV8ZvEEtjSrE!gZ{E_b7_byls^zC#MAaSPB7R*GQc3o3k(#%xwVs& z(JibXT*J*W@5a8}gM?7;7XI2$>;3T|YI**+OIQW2vi?!NkA*}JgM@CmPyXOgqym|M zxb*`;BKMUl4*h6ug#pL1%GTa;^4twG%TkwSCpHU_n%^r7 zdb2-()Yt-hcP6+n}V1q>a6|m3&k|5fvx3N)`0q+GyvJ$ub+l@z(2mp zo%35uQN2GYv^}K$3*++w;*TfZt$C22zxuM)Widq#BBlHEAX>M(?4mDEpSt+xHRsSB zElr)rs)Q|x)s$HU~Iqu1snW=vyIOE&u z+oyG1IFjby7EPERNzMOaMsxh9`2AwwaH5QcZMB+pk8f5p%L`bSPV$0yP;ZUYk-kxH z_Q*8qCmI-0M2*5D&?uVpP`^x*rV(r61CdD)up`x;3SUTZrai9az)VvN#owC|Hb;ot z%C)W?O0_P-Nc*tg{h+gb#pz`31J^Fh5(mqwkKQdY>VRKz%zFoJ5Lo-&hRlFB@KmH5 zf%NYKTXktj>p2O_!sF6r6%*jhl&U8D+dP%5@bBaFgYZD7YUnizHlq6){R+Ikv z#*S+cIk>r3`8*Ywy$Jt%Zu3qEr?HuSBbiyr$Yg>!n7YCqVn5OqF#w38Zr|lhPW+a2 z_CzOP%*%Ze9W}(!w11U>5yxgv9M>ChG(9RD``N9hGycQM=m6~F-o)j1NWW9VzPFId z=MQMx2YG5(;6ISBq78WxGv;odnH#RS))CrIwse0mo!UoM}>|C<~%Z$0a~=xmu%~oNU?q7t>_Y;@8iEF{)F@eobQ-_9DU4TpLGsF@$%o@E)lk`j>gJP|gRrLMu!Sm{-Xu`tH`JKy*ogk9Rv{8g*Z)+>`e zC=Hg}f1m!|IGwUef+ZkhR@Sva1z*JJkZ8^6%en-!S^h8l?6+PA-fQ868tQS~al?#OugJf+q3 z&n8f~#*W1QcwI1iF(baTF_ZqHj`Rw0V>;5W^ywAqNg5R%HXIgFsB|s;GxWz@JuO2@ zhj&rtccD9(SJBt0<1$=Q^rD3Rc31!5D=hMnlSMMi&d#Yja^)F=vb9KA_ty8ama+lk zujcgr06wSUkaKY0at-htPXbThhj#+iGBpIMEs?3-%QqeOH>iHD_Dj3JVQwvYTwFhW zP*!cFE|UlfR>lUg%!X4?coxq*J#Dejd95C-gtbh&D0zyM*k2qjb6QGDr`;!iGF>LD zz!;9LKZj?4YQ3>5UCIFH`47HLGWb7EStpq?e!3tX4y4vovezgJa-wrNr3^{PiySyo zVTOwDXaDn06kNHGA$-CANc1C30m;> z^{r3S;Iv!)_}6rNW-P*8Y)O=T6or09hk852Pv?YGW-z}3 zS(j?l@-OU+hRz+1W-s4e{q-t(m`4+xJyH+Ew0%mgZurxFqyRIP=l=d*+!`Ln%wFtc zVqr@z!HRwJtfOf-+DNsUyCYh-n&p;0TQ2i2bDv9Qq#QmK!xXi3ifsls2rLc-(G_^&+ zvz-(FykaK)j>yrBAv5#5i3k&JjNZNVN-DBX3+QdnQjJFp4&Dh#BXaNyT7b| zT9 zK21GC9}{ujbnq8Co1N9pHBp=Eu7Gcy%gtQ>A8TgSx83$pS+7_ABv$8c{8wIaf4zweI(I|V;OnZ~A)O036rpd(y3Z@~3^Hrv zITGgbp*9+2TxGvgtSg(iCra115#k6wpk<7VltN{f>j4Pi^5v}Y(|UQeWf^Y#nvU+6 zBUYk$+JQtm^t&Yi+w)^#CeV^gOolx4k9@T)?n!(N3`@gI`BsD=-R{G|%Yo;VsJ!IV>pRY;3Ge@)L{K!V^DJGpcyt`9v)%)JFS zFZ-~2VDwa$r7}2dXwos!6mf0i*17!! zG0B|jlS3y(a82anaAFR1v=KGxX@(=Y(?63n2K)eb^S1%?35^w;jT=xjfILMsLeylz zW<`TE3EvyTQ3w!3#r`3kk}ChTZ|%h{<$Gf8kc+zb=QYVc?`x8ms03B0lCkl`grfLwDtAW05^y(=-^YABF2mZ{F`}qm&`}JV^8x5gauhh zbyM7p){&Q`pW6xaxo7gr(O$o9efmk~{H_+rBLs33Q%lbud5?BBp%1=~0GKNKoBdR* zx1U4a)KBs2pd#FMK2@kF{6Sb|R|^A+(*F01kbkPJlD4e=H)u>48X+eo_8&j8^tE$H z*AV;Tg7m0Mzs02=^c&I-Q2H@Jdc>t)=F;DZk#72@-a&e$_n(WdwpnOQ!5`)_-d;{d zPV|cWw-(5Lb0P4_a@2#94{NQPcO4s{=9oXmf&Juz`DTAlZvQ)cT^hPtd2&Yv`%jm# z^$aqaeeHZ@yhgR!`S#Acc|GO({5h9zUwUe~pPiZ>)yhUK`H1oAVEh(dsPkeF3v-9g z8IwwX**Ciqki1wcvnTCMI~r`pm;E80|M~efMZq{)>Ay@cY#GD^BV+G>uuvS#q4tmQ z>YT|4r6&|?IGY&xjkht@*!Sxlw%l4-3|y1hzdxjvCa6;CHHtHOyljew_2@>0XmRzCaQsHr`lD=LZ1gFUFWY9w>3$|$C0%l=&V)E?Ted_=`8Lhj3@&8$oylGPkoiizC#c{KL$u%g zu+Z#2wmv%)=3XtGB8EJC9?JAG6FF$SaOrvwo$(mbu7WwFMV?KZpXBV z&c57Vc%(7ZM!)yLHX*wQA13DmqMElD-nh@QTzQ;}{0UW&xUf+OEU{;UJ>dQdh$GTejVb*?C=JXZiH6Q$=aZ5bwF$gMU`M@Y1Dt zR%hLUuRJ{a7pmmBj@#Y;tVrRdOOf2gWRJ8QYtbifXQjQ}W#z$Mx@J8tZy&WYs+;VV z!cex3^32rN@}^HO_j>K3CmA~LrN^U$+Ul+QNYT~3fom1jl370l{BSkiYDOKUH#DAU zfX&;v#V^MLauZ`&IggAmCS$I-y>l?64|BZuV+Owj9CC156s zhK&7AGTtZ+)@T?!V-!wofoQx`-wj@$_y(X_F3$9@L_MzbZGJ|@BS=qsR-@X(cm9$A zYcu)Es$z}XtEwwi6)XwtnNX7CU~6*^FZ{i(~MnA|7oRxFS9n8F~@MJ>frYrSw)Wv6T7=53w!lRxslkT4IP9 z-SJZHXc=SZWGl+x!87p0!mN+<00M=R0YTL=);mvJ2DxP>q8s19T*)V1pD~|Ah0jU; zJzVnuECN&(g^NJjU~6o!lU_FjWuTH z{$W>9g!oTmxTtFenWvt@T35#9slysH*4y5Q4JKYAhou7>*flJ`ueXdl0x|><(RxhdBN7ZFGPbmZCA4tUT!b@*n{A=bLPyg%&$l3faUttI})RU0O zkX2^inU`M{xSX%b)kbO?|DkS_Khk~ueWCn4h4L%EOZl;d@|U@s6HjF$Gg#%nLHT{N zzpYnyokCsM-&0@8{sR4?Mn8~|+5RdF!J-VRz8d%+=N3ay_C9e1(ba;*8d@#h71M1! zt0AMurqsCOnU$cjkb`7A9~BCTLpkPD#Z*;Lyh8=J*;E&UHowW|%lRBjPK?&iYmC#X z|H5yn-A)TkW}62uFb3}*knddQb#R*B*^zLgy`=Ka58@xwMg)C}boEe^mGYEoEX{B{ z{G6+tYu8VcN5aHvzxqLgL56Mxxv|SCle}u*XwH4Fv)RH^&@xI?FFjE{N+tZ7?fbBR ze|>%{#J7!z@S?wMc?VK%z9{~J{YShuRQvV$Ma=`oU^IX|)x>HXT6ZF0B7AJmm2sin z#(=qYyd10D5uV%5P{vb}*xR=9MEUo_2?P+nMH( zZhoGS#G@LLAH>=}jEt?#wp2~7pY@Ne#ZwO?7f!10$eG4{st@12Bo`h#^qpMq&JSbT z-f3?2YF}<13SEBTwZAWn&g|u-zgx6vR8ekb3<1hLlTK&>JN4=vzNbAmu^tcDj!{K; z$}$bVP<%F9DWt-3@!>>15ya==UxR#*X8G4D`ujvjOsa$9rL|qKkldgP2Sq|!aFQFS zXc+brGeH-xTdfp^V|Fd@rrc`2<~VGm<+uEEv4q*{gwL%%i)glU4~ZTf7x~1`_$UH# zn>~dcOLJ$J+}Xvdx0Dm?61-__+dqov9+UQu4@$g0Dl=JD{0C2Fhj%C}Gon3h6~0m0 zFmqGGDl8JswHZFk%A>pFBu8T$ay*J0J|1i<$dk=gRmgS+Nt9@Ro0GTCkmuUL+g$m= zviI@tke!Mm60Gs3^9btmdmuNV7IU$M>UImRaf|GJdrcrDTyZ151SqlCPdz`i)Y}G~%^f`=zwTm6_V*DDU&i_Vj9B~TgJQjQ2;*@GHC?hnNUi}-##}dmpN+CNL8@QJ z?_RTSALr|p;is5r!w<^qFNxm*g-k!O)+=f5IXOA8Thc2DKUG@%+T^74dy_fG?bgx< z|KHNYTe~vzz(TOPaI#_@@_)op8lveb^6<5_yfnq){S>kPMSmmbS?d0WlWM}i7A?q7 zT8;5Z4^Z&>kGXo9bRKj#ROQka?kMRx_rPPNfA-h9jy%%Rm*0Qu=AW)b3Fe>m zzjod9Blqa=5bLnIxuSTV-F$qOb!37Zjjfx5>4tm06A30wk&3`h% zpEa(6E4GkpP@#Vtx9{D*YcJocf5Z3UERMp_@S-BV998aHoE>oZTi(Q}Oyi3j*$^N) z%0cHkH8uZ5{Vo55tTIYo5uPoR3&tlr|MxubiF;RmV>u;SQ;k>2$ConZV&}=L1Ix2; z`AekCC>@J>of~LQSVnyMZns?j=@_z?PaexD5wBkZ4mkzB$?so3t;ajiPA@K}=q2d6 z8*vJ0%%Om9s;1HpTL#{IV7UB6;QG*Bd*58j?+WUvOP%H=Z$qpf zmOIF=Ar}X+GstB+U_!S9xl?DAdv&UQYB^0WW&6Yj&9lt&&*-!N7nzo%LuV*NsA$Lk z)wbQp#?*2(mv$u^Q_B(mvkNoqL`&hx;YV!*_=##s(s}Vron#6r!b7#gik4K~bQM?+ zwjbi(iS6CO=>+B3;Ji@nrOr^KpSQil?d3%+Fz>o9;?mpd=C6QnypY>ieEYBE z$mnZZj`PnQLWh<`E7g|zL?#aGbxh9-e{8Jr!cg(ljpfkLZPyV^F3!C@cB|jcSmKLO z;lv{pXWb2rPR;BV8Qpzmx2oDV!*g}I;3amAYN<7{^xt7-bZrcb)mP?QC2pjYq$m*B zRjctF#t5(36?kCzvGM+WVZ7w2@%MS;dKEtNxO57hClH-ILcnl4%WYlRwOquR@#@FheWdZ zKyWwaKn7FFiC~k9N>x{!2XD(ACaP}Q2PVFI(cYN&O7nBVp7hsNl*&X=!iq(u4moiw z*JW2gVEsGLGeBR!UGDTxvv$gID9ni;HwC}3CKrBkV`ua>&EHu&=aCdnyrB%uT%wrn zdl}g4f&RPbM$p%{)JrG7=vG{`W=mpoamPw&aQoklD6+<_&kNAoYm)$;wTP<)W%AKjV8+gn0%A^iy;vxB3VtdEbfzWNbtdVz9m~9O|){jZf z?(a22GzJiqt0fu9r*_TMfsBAkoO~3Y$UMO9Yc^_pwTbDZV)fOZhjEFcQs{T*1;LnP z@5<9;fjRQv=<}PM_^+uwnx3wtc(F62c2jrX@`$=4j{} zdLBY@mSm0(SrJ2D=bJmr_7AwpWRO4Z$J9Jby}U!>hKRv``Zh~C;35_e*-7}<21yb6 zzrZCP@+^rKymMTT=+6KBTU`2nCz5XGTgQ-2+e|je7w}K3{EN|~%WB&1O}hW?4EuW9 zxg5zp(_K2fF7bshy*mvkk5Iq;jay5!vYq`LUxupuNX3?)qXGS8qp!P{4YdOKKibrZS5MI@a*rBD^<2-+ucRrPwsf;$0EgM)Kr7% zLrxHm)5E!Ad|K(6EH-l;E7&un`zE1xlx+P;z?~r77riGVVEy0tIjxBu_-leEw0w); zDcqjR`LkCilAHMhx_DOu$arC6M~8pyb%M|wT+*SY@6&VED(s&=rsw`Q&cnu#LlL)y zarAdhC;g2OJ#g6n>9r6K@>gHkuGN^{FE@a_%K`PY(t|_quI6hM|BP~12M6Y%4|wp; z{_d`hrJ=1nB7*4TCVj{SAr9bQK3o>r>Cgj@W7d^EWDyyj(U|_J7k{1u2H*!qVa_W1 znJU}y9SU)$DbJ4jTaI5Ex<_@Zs>@wfE&Hfymb#mJ+-kZ|HI;vFSBJlf{Xp)&j0uBO zPTq|10uu1Vy}I>F?3z4I^;F4c!iBz?V6UyOoZ{LXe%O? zp1aS#nr9Ov{nw9Dl&_W#vqQkStzG{669amioUy2eT^Yh2&l;a;R|T|J-a4bCsQJv) z_{LOGdg3n82dxhwI;?Sl@r{lRa7W69g~BE@fR?3G`_lOY<{nzdj55>dr$5Zk2rX~r zzLy72GDUgzraZ0e0h+x!`Z=C0US7Tvy%31*oSF`Eq0ex(eg=HEeb!q*)QT78Vd;q| zz7JW?S6J5pPS?00Rq@#0@8%AmTo2-}@Wjef8NP>YY%_74O}>fMbR;=XLo9Jtn_3XD zFHeU?e8%9Ov>ogs3Qoxok*Rfiar1$xiH*QtS-Y-zV|r@$+E1Hb$+CRF?fqv8 zo2`RuTMkVwoh6f$u4&Fi$*U`ue%VsDvPM#sDh2+yoW1*iB9QItZ@QNn+h z-YDezfv90mNz|2bMQ+h;hmiV@M`RI+)y5GGdsuB`oFgITo%hA=Dw>N;-0oOoB5Grg zc#1GT0Q6Qd*b#r^RO6&iuE|rwLoi$!3~*QVBKY@4$7$Q@^89x`>C{!_x4V?D4FIEE)% z*1?X%9}!{y7Hn)-CjD>fm;{=sL?bIjpIa>$mr^S9Pc(}o%H^U)Vna7#KS1kUGrl>J zj6IZ53_A0?|2huhYb!^@|4Z^(F74?}2dk!gEVa`Wv3JKyN%OeH6Va9y&DzJ!!`A$2)3@P?XnjxY z+P4M2fXhSE31sT#NIX5i6-eUgilesPUBrn=JCU%S)h93MY)rVL;k+xyFue&$dufwy zj3#ccyE8^vHjy>gkNs1=dh%P|J1vP&QsK70lL!7oEPjqnStMhr`citUTZBKOB#}&? zkEi~FNbc8p^=)H0qrt6v3m0lUd3i-qed7I|@#OYGh}2l|l1zQu>&@5Jx8779Y95fu z0~1RDg}ap|7v%-H$i2xHWP^2RK>gDCfn2oB$>rNbu=H153LV%sI_Ro~E)L1srX`w{ zYYH(uE3-@B3E|(a%GA#TqNhb;xgMd8;%PHk+x<(i^!n|LLm?Tr5s{{Y43i`p?z!<5O~qkN7QSJdNe zMi@?h4=3(ZmULe>3UA>YdvfSQZ4~+rMeJ;}jWL@8+Z6k&-WN4-@t7F6|ql3G|kB*ZjpY|`F8|~*T?L!{&d#7VkKv~{HVZ$sR@^5;P3i#>cjyZFb?u-68y~I{XcC`S4s%*fmz{IH zv-IjmgkHmU+X@32szjx%{ZV-KaPX8zez;9~uF17ihqas)*w5JhDV(rN3p(*X8$9kC z|Ks1oXnm7v>9YR{CuH2#W&Fmv@>mqdN_QW>J}Q47<+XeHdMTwC9KCCB9@K9-bgeJV zLtE9O_L@&-tWG#{kFheonkNQ^t1u!hOoV3cFNNY-qIn_{H|hf9eOtb)lat@=N@S9; zU-=nB@!kLJ8uFk?gUDnWq2Zc0$%Zua-^zD3J5`%gBha!ugzSnM%*HfPcf=KvWZ6$@ z5-zKsLJz3~)gt;s4(>oo#ViUacW;}Y3yLwg9xr6w04FOTOY4PR0*syf{=PAW{-yq3 zp$z@^JRtD@a!shnJ*_G{wetkicm^sWzI);GL;9Q!c~cR>j#1K0n@q!ynT#CVPam52 z5PlM2#sw5bl+$CYl3u*lr0w%=CGP=zKt7%#mgI8!-$D^Y-F*%XL~7*cK|#6|KgXqi zU;f4A6eoS>w@n<6_`^u^AHI%1%UvT2&j-Sz)#|HnmK50$;i2KD3SfnwT9yY(JX5@V zhJU;(Iws!$`WxyO)1Kk4x!!<#vYhw9DJ9N9_Fy_Q2#EM zIAiznBZKlb4BsM)pKan#i34PIh(1KrhXd$?js%{%nWbzQ%lgNtXrr9(ZVx98*51z+ zR2EY1)EdV^T1?dLzP(u1$F#lNj2_x-;aB@{5fQ}KxYx?H=c1Ln%j<9pIQkZAw)Tr~ z;xrTSoh-nzc4yUAVdBYAw8E7W%rA1{E%FCj`EO+F>SO}TDybmI+SXrFF*OdW;YXHx z-N#k7*8Kuq7OTfc)TgnSWE(@)KYecLIkZEUOq}9h-&?}2wxher&RrH;3n^;r?4-Pi zpwK&ZXRGACwth?YI=Cz>TCGxf{Yy z{=rb1VPnzSvcHDF2jINemFr#H5uN9p-rQS9e=(d8VH#?Ss=wotX_VpUkn zlf>w5EpH2d*@3)sWLG&ZeK2vBham+%VM4q{-bv6{MX#3ReAfgGIebedA??v>^7R8!^n z^yOtm^{xNt)_gF3yCeE*jWxJr2jeQqJ@&5w-*C>q2R!=?VI8Gs`#ECA{A6d z;GZPN`@R%& z!MCpj|Er+@{*QRr1O5fBZ+pSteRufpQO^VTOZS9-`p`W54cwp+z(0EASA~Dt%>nK! zoxRn$_3sUw-< zpKp-=i2oFe)2(t0XbLYSCa1EzdLMRTd|;vE=5_-zLhN+IR$jItvI8U zMp7nON|RDpir}+jZY3XHtln?!igFzvAl-KsP@Y z0-ryi3pnAYFs70K@8oNo_JfFcxW)m9rYQ?sueR61-)~2gc^EbogZ&oOnGVg{I3aL; zdS^0X2mIMzNJ{Qd{{olcn}rO|TL$6}2hhN_*gl7!ENWZce29Of%f7Z3Sk>W#e-GLH zZ>z3BeyK}*u8=rgiRbNAQG0W5?M4nuY%P}B1DmWv;Sz)Vyj zR8!WImBmb*szmIhW|iN+RQv^cN?BNr%Vrc@I-tjxDc;)oB3Rvt64Z!D!xriYhwH{gnhSE5 zE$c%ySSkgvI*9W{Co5&?j>jiYuJ=d?09LnbBTWu@*{gl^*5mxU@ei|uDxJdpk5b5A z&SYzTK5MroE(`sZulmP}qtNssPG&I$sa z*rrlDuvw-qwPT$0M38BrPZUt^fcoGf#7uK(Y}r}mZ|o3kF49)sIKwYKC7={z!r8SV zm%aY!fc}N5!qHxtw=DGT>#i5MsbIhCmzRP4A#vdK-B$0cc^@_Y^qh44qc_!x#fFC_z-`eHr#kS zxGN9tCuJ;ki*LkyUF8?Q4TG+KrLFQlu!Nxgt5%J032A0CHt*C(uc(%Y&1V;7J`s!l# zj{#Iv$ziOZbC*bJP^f1q2UE)w=w&_9cYnW(h0Y3lsiBr*D6cXeQzKJ{0M=5DpU)~+ zSkHq$?g1MBx&_;`_0!)NjDMrZ z!Iz^}fR%F@5HO=t1;fq=Ys;E>4s_#?FdF)b1=s04lHH#U$`DJG;9qm$ZlfyHR0=B* zzmG23(E6b2%GFk->WpNEF(7--07w7#Q)e)~5tELBQSHb1nNHlOr6w3hh1G2thg3lW zGzrN!Vlu3cCmSpE$Em{{1Rtu306+rzG_94!F0H0yzg(#q`pC*z;(WT1Q@u->8as{7 zbv^cCEeXyF+I9JHj6@tE`$rEA`iT7f75rPmbDrw#A7Gb?dIQ^##7#g>4AkZR+F)oZ zbuzTvKf*u;dm1-ynMQ;zFj|Qjl<4dKvXFg0e_Q_9<*kP$xl>T&GE{3I1GB4&ezlx= z!qvN>cdHDlizu-INw{L_MNaFc)QF`f2&bX=ZH%RVa!t@Sc)!yA=-saTB~f?6sjQyOy)ww(*>8~qt#AxETNAzzsR0w2 zi!Iwk+enPz*`IJd8;R5*QJ#(2X@A198v)wmEWKKN(X>d1j^%^od)YZ!4c(OEn^UwE znOVgUe}hcOfYc-xmb7S@r>LIbLMVd=AHRoY(-jQ2Jp`OqO(Bw zVn%N}zb#i@1p56PKQu3ElPEJqTH25{Te082zzrvhOm!gEYbjAQ&f?`ts=-)PJ9GT! za1FHqGyVgqb9~GstjXPPKmHan=_!)C2RhGT`V_kLNCZvJwTk@XS4qqZ{qAHi2xT5^ z_G;TJ;gCeD76(Y5d^c&3v5fE*PtIT;@v=-YG^Ox%u<0a@mL2D0*!^{DSbtT$cBQs+ z*Mqcd&rVik>-)(C-jj0iCMp4H^Xj`?AjxMCZm}=1GbTxBNkyN4GdTWw%W?lU{=~F= ze2a1b)aeS+b%~|0Vyn{=)r23_)n+NnbuTzauR_HjK;~;#i|i=XGqCzZh7@3oL)xvEX#J_0aK`Rz{#OMxr)Mp-+ATo^A?me6JQUwg+Q#cNs*rnZwXE{xgC7aE(u33P@LMYj@WFR6~LF9|veQ z7}+aLC*a`gBELC3#K|DS(Z|Rpjc?uehQU(8vu!7|EVNQ@{6oGy!qB;*<#3y^|0Kb0 z5*rCfqT(~Y5NL_M^wM1VkRqG(33_K+Sn+`+bCO=BI{C2C<%bQIEw{(A$N0(N4OF(s z<qwG6NvVV?b);ZKFdI34;=p@kvlc#(>zjPc^l zOTzI^tlop;QA;YcW~lnZ`~dPl^6Xa|$I}P6_V*XL!K9{A|64<_I-=fE+cBvp4*vO_ z@SEwHmr6cua3FVJ%2A3X$6@TGOyY$9U0x-YehFCh7|2>T>BZZY-{$K)__ zUu4pY3_K2F`xd=*5EG+M>obp0Klnv>P8||f4~YGAAD~LLcQpOnjlKx4lE-hfjdmVw zES7p>42{%2I#JJe4hWWti2|>YF0sb&RA9gV2Q8sSxJJyKNkwElSE2^jLj zkY&(sb7D2-d8-s0GF=uwW}*vz=I>8TLS@679Fv?+s7j}*6TQ@T1b`NW8WZ#+1|my7 zr?2c!Fy}bZOa0VSp4yk$qOqOb(7eB7UfVy7H2Y|)2)N9b+@xGDHOI=NeyYBD39Ap~ z{CDhY(q7}qIZA}zwZGjRU=IXlf90FNX^`R1$cQw0sd)xrDq}UJZz$H?gvWYG!yF;6 zr}iV>i>vnFd zY_r;bKwp_I4vWPyu0AMZ!MC|`6a5GL5$ElS2`^yZLevlJewo&AZ^of;!FgX)bF1@g zG~(6PS5C+3W&XKWK}Y*#T6c7tj^kkcl<*H1Vd<&=?>0fdQu{Bj`l{{sRl}`2io@Su zoC`e*$rW+?a$f_ghoG3=9RNUH0SGt0-XdqfADBJ}Fc5J%b03<_h4+b&(q%8qkzM05 z*7srGh43(R=?1$IK1X;VUm2f9XjHU5vK&Yje{;ByUc;&9!Vy#yq=%KhxHEl*(nbA2 z`o{#z^ncNrzG#o~FDw0y&h*l6P+lT)Q2r66U)h;HQR$J+^zSNtbZ7d#d!&C`>4$fw zZ`vb$g3`NnrdM;?(Y5}gmA)Bg-~c~U_DByaeQ{^{BBghM|6}53`oGAhFKyife(4)p zsC56BOx5SzS$-e3vQq5M+CGnt&3xBOBgspwDEkei83t`IqwMcbXZ#XoYc3w__o)h| zLAF>kz>R-@g!*9or-*-L<}qypTQ1a9+;|^Om~ldIPA*#rH7f(fOvfG4;n~&Jh@XwE zb<>e+bR@cB=;xW-G5#eV>Li7f&I(PP$dv|dRjt%g2*RYD{49OIgb_Zu6>njG;b$t1 z8&{_??B6LC$KZL98Iv?)<#n77_I<25=AOKK8+rBR5dGLv{Vqc|`1^c4F( zliNc+=l&Io#>1{Vp3Jd8gy)oji8w*rK_8ZZ(@u%iZfr>YH6A{jpLZLE{FSf{@uaV7 zT<%kz`tUtV#)hAKCzkwMe8|Rz+3&=|V{^GjGW83K5Nfx^!|nHKB&Z@rtf_eIYk{jG zOGphGhL-Ah^6Dxaoc)$7#8mTrGVKH)2IrP!i6_^^lke3(t!jM_AT=PIK)~}?PcQR^ za9ie`HWv603|XCjk?G_t!AS%&hJaOrN*lO)yMQQbA(s4$X(VirvmZfLnfTm!0(^2t zdXT;VIQ%LBXynmo5=Q=hk=}l7E}#$X#U_dUO!CJDqduu~)c=nv(Eal&&@LKKwVyI- z#U%gV-aj%W*sQwcV_jsovo?*nn>F^7EdAR`=q^lAypUsGd9m_bG=e^r|_hl=xJo` zT-8z~a-0!oI&QW3;+paT8&(Js&3zS8+pHx5MIMjKOzo8(zP(|{pBs{X{`?y6%uU#^o zE9W=Glh;>GvH35n+@?4-n-2n=u4|3Tfb%|k;Shuv8scwR;9{QQJSyQ%Cnr@%0SE1e zm|4G4k;S*1C}yO)f~0AGk(&oKQQLlF#VlG`n~N961Tb7eBzOX@K>)%ekua;0VP#%( z<0Lo5?o~+|tJaj5;xG7E)O)AZ(MhcTjzy*aU3~JORpfgDY`SG6KbEnMC7S92R?}}r zL+z&UcLp)*#-~fzkUO)q`GNhL66f5&gon-aKfQk2+A)KPaN4}k7{^$sq+eVfHFRKu z)d%)ti5;a=e@q~x`ae<*j5P{n?s)(fd3H7QZUKlA97fY^`4G8x(ilI_Ogvq5RCd_6DaEtoYe@4jh&l)8= z6^OarAH*X8QUd!Gd)eyjR|dNme;~gZp^EieY9Mfm5`(F(X#j_(!~TT_cjZ2UvC;|i z2-4L8u_k-t&M(v7PWxuCwvW&*qZFv!E~DJ`8kP2!6UvGy)*m~j(6$a>B0@J{v8&+V zu|{ve$4+nTL3`}2jI0fA7RiKaEknLn19+fCucDqjRWwFlh!t4VXSdZ9i&~`4ZxiH z?rzez?Jp|}@r&jEUpBPEKU;+px^e+tGNYZ%HbNBlPa@)W87TFR^CPT~_UK;jq0UBv zo+*A2_j$rh*+)D_WpqVcvgA-$;z82li@i?0U2fW}^y5}57D7EQ#-hx;+t^F4uQ926U}F`j%wGKtKp8gxp! z9ELF_xtR@8cn)2|rkHK8b+|`oR4Y1sn02^dKNY|iPW%^T#-)ZYZR-(F%_&9L1QlFE z-qC^Uy4<;mNp|qSSnY=T@DG>N_j)D2e#I33xTs{>p@>ZUBEBTsvtOeaZba&!HakQ- zYp8vG+PfstL8Pk3eyRon{bYFd3DT;hexPsh+SjMQNH~~jm_CQvGmQL6RO_Geq;qmN z++2rYOcye+`RYGW*_8}zg4+H+yHHa0m;VF5#77lH1o*|k$VBN>=lzkWyPjPn^=r#v zB7R63H7DDF8D2tf6%D>!NLRYx3wxgIy#y2*()fG zs=J{pKpgs>5Kqk)B6Y9);SGdSjLq87N^{}FJ4iw2r0!g))Ohl4{p7l19jctYhpxyD zV>0o|*)BJ@QO^scCAQmofjZVjC~%kl?9 z%;XR`KqROg%Z|9=LR73Xt4{Qbf5}FTW&g3K^FAs533~$LrTTJhf@|||jbv2gXF!G2 zhPxd2)TrYYBx=P)curS*@0h?#z=qHUGoD-}i|nVtf^32{%b5gmDzy0)fa_;LSDv!+ zL4-ZktT-#pb&e!3$5Fh_3#yvbg^y~3#{BrpkPmuhKB&h{{=(-~n+o&l*~NXK2b7vz zXZn!^r01b(TfuFHtoT7;Px{4MR6ZSQ{uU~k6PKtiZG@96by7>rF!P(3SlXoqu1Ud= zOUcAU%H$5mXQ`#E^IK)EymdPfwK~5bWQ8hJ{i9UhT6fwJY*@l=w}YM5y5sax*u8}R zYP%QiFlBDH3VoU*eq*z?AkG4<(?tCL&s~o**g^&~AHSD43*xb~>mT`u7R1%h2nc@! zCNy0ZM9D=G%?28NH|B%t2>(v}6Zs9yZpJAfuiu~At+4)8i)nyh>?)|pQ$^U1q7M=` zY{UVTdln^En>Qic&&C!05+`)@1VlkLH((n*#nQ8{E(ZT0dy#tIgJm4$Ejzm!m~me_ zdzc1x`c;|wr)j-t%pAgGQ(g8L$WKO$v3XZqnS5h)PG1|*+epHKK@K1UQIkp+7cD#c za#fXWlpGHY&*F8>p)EnxIJ7+~ z&Kl6}_lOU{E(+b(1*BPA(5;yJ=q8ED$+L&$4n%0FPp&R}7^68OT%^km{nq@VRNo&Z zCtMChHP$Pc(k?rDgjhrPsk4XqJCEQ4*kReL_rg!r%hB*E&E$yVKN~F_e0j;Uqh4x4 zQ~0TihhY%9((68<65yv8R){wgu`{P4b2!+#qS7IMe+=ydG`F;9#!=fi z(klA>k7=(ZpPAI_rAzvtKSxQP;ryXaGS$=xFulbvDv5f9$dBogaxdL#iUI<^<7{aP z?RA^Cma>X4R1z`K=xC~CCIOuP2**cAebv}EsaB)Eh1i1lpX2c4f1>ytgrtS*7Wr*_ z-WSb^)FL9aYX7bM0%2wk%GG`^q7lGAmiVdrG@C03d`^CTg3%7-yD9m(E9f&BX%rOv5tn+JXICPb6slX%2+a^cN}3K13$4;t3ZnlX-8^7 zmAfcAhp)zO)ew^rih`d*gXawg_H>l?b&lJT_rzqpvgjkDbW2MhzM!RMhFv z5EA?)f70iGi%E5j(v$|#S{t$YZAZIeO+r4hK%U>R8IL8`0IY$R?msYq8#;UDP*(EP zJS9jk;x!bnIVat>cZ0ifEIxQ;mNQNo4Lx|07KgGQ>Bm_|OycVudbNRHK2#_Sjh7q0 zn1z4pX?$S7J^!1hTGB;a*HLK@-vh-W zn=t&W^Su(s3otGSYVzG9MDP$3kQ!kDIz&&Gy)(?P{p^qO*xtxZ>j3)-;b8pl{?Q@L zri9`8kNVtbLl9sv5Cv*%(n`KPDkvk0#wWR?d?AFQX|#v_vrpIAkgW>H-tAwQe0lng zSPx7Ff`3O_>%MWYt!EEVX=~l(dSN}&J;#R{eUAJ~ci64*C)RV$1hl_k%x$r6(R73h zZ4E9iIN@7b>DZA3%iQD)4!i$<7CO`o0zxgzM;2k*@y9_P_$>fsnf$Xg@)`T;Ulu1l z*i7YBI9dVy&F6MSmAU)pOk==eiJ_X7Udn%FvrB_!1}0Y_&3`F5l?`d4@$#umq zk#*t5(%_11I_H4Y@LgoHum$;0yy^Y}y!73UA%9#(5CdW;*PAtR{kl!{+g9VD-!0dl zBhT<`PV9;%CvKSpEO9ZO)MZ44a2GGGv17f|EVrxv;`ZAQ_3B#r zKD9x4C$V{LcY9~ck;80Pjiu(TX6x=9J5M`!79#hWn)kH6x^lg}WX4_-vV(P^){EGA z82VsMn2EuE7TjN=FQ?Z8U;O#{AcZ4C$^2eO2?7#n#UGJs6?M1?nmUttB}MJ)#~Dle zYvYtJyv#qK+nDB;vIH^gYpxtXtbP?Af^$Vpn{g_pZh42-jvD9 zqLXk{j9!UQ6>U-`3e1?XGWYi?CC=!=G;w~MXs2mW|RU(x+rJS<6`MrDm=ka(2 zEN_V!{6r&FG{Qb!vQ$?&jpz9Q+5Hlh6muNCC%w`fyM^xg7up)>Ej!aeY{HJlafC_C zCf8ZS0X{L=&!qU6s&fBxgjxpS)^kD9@qp-GqfuiJD*XjDmbBvm#s}Y9?mr5Wq5=Nh z_-rbq9}}dPyY!7Ny;9CHeN?`8kRH&-LYMyQLisKF&^i7Kc=dn4(E5)#Am<&z_^NlV z{)NBTZ8-h$p{_%j$u8K7r50o_JvjWYrMf`=Vx0!rh`%O|dx=|0i&~E72eZGUWcr%~ z*Jc0=bGxK8lOuRF2FytarpMBtbShlu2#?@9v_j(`~by)+Mx)!*dQGf zPn}(gdbg!lbj0-X=5ijV@89xfMsL$LB1AYu-Zw&F+_a*&Sr#O5{S;ZOG1!Rf0pLtSmTmsSj`y|4VQ1*9RbtL+FD)|7W|AhRGrWxbs3F zf|vXzJiFN>I7c53>`5Q<5V`}>xO8Jc8dCz&U{m(5NMpNzwbCG6w z4|15;l^oEno?WW-r;{YYjwCi3Mf@d4R~X-eAc+o)uQ+O)356wWl`Lxc7Q_DIU%O$) zz`o0{KktUUuzxCy|7;t7pEF+lf>Vebf?0HlmSz^uO{W%kY%@^+my;I?w2T<-hSt=lDi7yBS+) z1DUdugt#V&*;An6bZAT%A?xTm`jHMj+Lz~%Ii4vp!jg|va#Ov!X@YWjw?ti2g=|N$ z(L))hz3~*&PUKE?^5)cPFLg_e|Mx>VU4jA|8-k0Gm75!q%VWu@@K8$e5Q!yk;lLBg zgn0~Pw?w?;`PE*Mh{Y70$g$q>9CGTK!{37sVqgLdswr%NiTODh|ggd+zgO5fK}P ze(nOhfAbRMxuB|gjI$#dD?^eo$@!Y@_42&i$0+CLFlLK}!?()7;gXTUVcD&H5OI$! zJByzT&Tik*EBA}qk93wvgusfZQZ+aasN|MWfjutuX<%5KpazX4JUD-9>{snVEGo=+ z$A3X;M5wOLzE@CMX#P*j-_KdOu$$=22gy3}IA7J5Tg%6*<#Gq}irxnE-TVmVXZ6aR z@AhMd$AbAzr3&WHL`0_mGjy&4RrgnLyY>B+e+Gd5tNS?-5Ay3*w3B|V{_m;&X{S*? zL1byvpYQW5f(59LNYtT~)+|7MlUFPBbrt$KtSC>$Jri|5-(O^mF9d5!ZlH+QhC65q zOrwAmO-lryEIFiPPwYdh{L(YaVbdmMj0b5}+jvOO z&WFZVC+d#xSHO8xH>jUq{prvfN2G6*)2p4L_has z!2=6|^S-CgyF0pKZO`emtP_b2e}C@8AN7f;gFgh|DEN8BO(p>LjBqNwAuGY;yjIGf zpYCI}_2w8wg!X~5fy3mO>qu(XxAbbgrM#4T*K5~L@7MCCUZ%aq9n(T>F3d?GPV0=f zmHk8xq1;LU*S(FhueJuFROi(^|kg@gsQblnf8KKP)^JHv4Vb1 zO`oG>A<&2>rZE(MGZ#~Ia**r+1(9+e@^u}2V{iG=^?#k~zxg(o|7+3Vk>5IsFE_^} z<_hOEgj!}~GlHbX|IR7?y}*J=NZ8`obq&LW1>-MX?VF&H4hxNMPOoTr-Fp9u zwp1J{WU}by(90Pr>3gIgLfn7|aq&<8h2)3`!Tz%#KfJ|oI{ERX;O5Uje*B2FW>*oK z(Qx8X<>6|ze=SAy5;OZhNfB;0(|nFi!8>{~1+O8f4*c(TA!F6k`4OxBnO;+6t@eZZ z-YqXTC{=UYQ^}O(wnJxtRLqrt-oH^3GY~udYwRU2yq}sE-UqbaUS7&+SMBu5<^jlS z(06wywyjl)Bf8ziwlA`6%%(1M_YH2g=t6f33QN^)beDf|^Y4csb~pZI{h85&{#-Vk z{-i^HDB=0rn|anKTk<6&qdyrTOgUy%ypO$(V>E~!kALcjv+}F5W3iaLf9Cf;4?2|{ zzxzCL@Mk;W-*dl}8*8f#!&kAXBU987+RR^#R=10>$WI@#kk@BWmKXhr*s(>=*#ds_ zJ-bOj>Q!r9l8i-!?u4nk{?AfH{zxwF6}3eQ-AevQT=Yu}rxiWAI<{=ieKe+j%#s-O z=wvqBklY$i-fvouZ4glEqp&HoF3v_GCr5I5J#AP7q5!#ju4P&zcT zJMIPdaSbEnJ_5kJ#37$ysBT2t9^+?qH9SDk=r`bX%X>}i~B=WAw8heQt@8=|92>u1< zh^&!k_94-dUjHRRt?^?JoEK{Qs{bF?sDEYmbu+GW9Y2t5*1X37d%Y+Np2qPUj0A$-S6YyDGc!0p9BLe|NgHszKf`ExAj3H zPPC0dLoqjWqr0W_20QPCKtUc`!Z*#tLW2} z)Sj2!k0Vr`|A1K`>jd1KTy3Q_%Q*_*0mgB~W4*ESUkZImdo_>|LSnfHwJ>E`+Pw5x zfvOS1`*eLl?N|`a&fXgIUnE(ct=xS{*^SH{eb4Ode?)-8Uf@DD{m$>WoBi4G#-!f- zC(q+H@~qBT@^B?j7muTJ6&zhZo}e{{;1)!`>`9PU_|w{J}BC=JhDDxLt$BXB-jdEwWKI;z$i^wV|$ z{Uyg4SK9Iq0>~U&_IrNBl{V@%RrUw_DR8BSEj1mgqhPQ~9X@vXH~hdj@!+@>c_h52K`iB^5LO#!~gtXk~F$ zXB-A|u~OeT#*p6NsvTfxO_rVEsy)np3e}cdYC5!>U%!vw6({ggoW`U>BXg|gr~EiT z^8Ly(&()pWVIZH!kMMD`UQ=b4*-xSFxTU5;*Q?+oCs6l2)NOEHqGtV(uCg{2JGQLB zvM0-0td_Ei?59xK*_N6P34Z@dDnq{2^^)mOnZ9ftVtvjEX~&j59-#7d!(rJ%`zciQ z-%3@m<^Qtjw+rJd$>s{=xaj z>dyHy0z!O>70gRFj)KGWkmS~1{3kv94K^xUbp#y#;nG~lxpavQzTI73T%3oz0cRY_ zkIq{Uf-UZp{fCHJrFW6DHl4MKDJAAFdlLu^Ea7v8my#=YxTQ^T}#M zT9rUzePfEDNt6R_);*F4ox?AI$(r{@JF+GXLD+CcGde2`J)El)U~WAU&ly zVAoj%Ae|?I^%vOGF8h_FlS2D=AJG1%ySLBBF73}GNc&pG|BRshSA+HorKVx!K>DFv zww@AJfzXFa6;Y%mqF{r0s}bnBlG9IXGP2HX8bdHaKr z#G3^pPw+wGe*n`XW6x__&W5YB={Z%F)=#qRJML||dz--zLRPxsTD{NhZ8eYQ**{B6 zB@x8uL9K(xM)-ig6DI1nOuzlS+J?VRoonR_nqrpt!^ctX*idK&(J z2D}j9kwR*<6-rP@>-V4|g&)4M0YhDBG33&r*MH8?9j2m#X2YNS|9PK2Ox#Bw0{H{F z5AYuW!4GuDHuA7miX%?$s0hzpqbG?ZGWYb_*xVezB2uK$$V4z%@K5fc?NOgD+at3W znx{lBlwrfFrS0Y0sYX(XPDDJnek)ceI6r+edVD2eYB7WCiMq#N*+m(r@EwtZ?_?^~ z(y9>DhiYgtlK1S3UA;FZ}4*eqkce;#EIDd6~%1*9_h*-b|>ZSeD5L3 zGmsII(LebMRpcTSxxwZ9Fv21Kv9uJ(FNwX^4`Dgt7r(dHA|lJ&NEVByg3F2x81Xhd$8Z(Un_$`G#Cm^ z#5wq48zXrLq@J}AWuPXB;Uj2K-k(0p;d(}ZYcKV9D{VrjI`4H?gA;X;1)}r*5qzXD zKxUfQ-SoSrv3xzNLYgvOj9csFK^x7)Yww=N*QwmcVh={@{!s|bY8vb3c1K*8;Voz7 zlMx=lCf*AO4S~7KDk!eVm5Xk(o2yD}s|DvUNz?0>JiiW61c$jJ9rpy0HB{ z?ma1C9gb>8QUu0r{5PH?P-Y_9b}SQcG-)+Zm(o$`h7-R4qh4|sXVqmotBz1K@hAHR z9V2mmF#|W>7C0uO>!t1$ilLx#@qlsvfCos}@YgPIJir>5(fX_infY;|#=Eig*&4kz z_vI+HyvYCceY-kxeKPK4;Ljb0XcT0W#yXZVpF$(6b$PqyQnnwgL4KL@1Qn<3f1)xJ z5R+N|d1Agando!c1yFgVpjpzY6@e4)2rt{1laAlp9>U2$qu<_(e6#25wFE%FxE`HB zBLV+uRDYU`#oadtFX5392R)W{txsDgTN;

VYd(bP2Bgt+BrhoZ~o9wHL6RGy~xe zNCYxvgR1nZR3#>DUg|ERp44OaiUI~%tH&tIk;;--(nzlpi`mY+q}yN#-)OiK`J_$@ zoH|-@A}U^{=;E@uB`DIzN93YGQO1+ie9ZP4ZXn9V#UT~ygH)`2tBOjyR7OH&%&yh! zfQl!i5AKH_-w}ja4=1K*lpF!w_=^JeZ^E|3Vc*|R2G$T^Y4%qEkC1=Ya_9d}m?nqh zSsy&g5PJA1EaDdyVcvTs13M>YtoSvBy1$oX#bj*HG8>(*OKc%9a9bk@#T(?`E{bVL zK989^F^L*#mxtS;45m_ANy*?UFSEfZuqEWPcxuw5c=A_O_mPyHT%vqynd?Wemzacq zmWU~w*pKhgc~4ZmMyA509{Kps<5Ka}GuU>wZwb%Z+}aUlj+FHCKbKWKh#Qf266>P> zSreY~NOvVa5xBFJtd~FWB5Fr1K1H4^tvsU!58rW%GNwlp;O6=89rCh|rzT8_4Otya zzK+{cj3BP^Y9T(QM|?_e@ZxdllHTe<$4Vl`w;9A^xvQ}E(6!ltloo$uC*0Nsv*4f^aQ@u1q2C8eg09XK2_9Ak#%WSgsfykHPIj7r~iJ)$su!Z+2+v_%frrJE#`X~=9 zv$}wxTzJ;o0fq+puNa%sF)KHs9j!JOQQAwLgS)hI7{YTkJVzeo@zgn!#wSbKIkuU# zM3jO#G6g7r2wczJB_ide@YS^G~yxE@^q zN0TV3o%$qNd6w$p45HwQr+($&OdtQYeO3b?dq!|^QUiTVOT(|Z+KB1R(TMX=82@_A z8n(yQaWB&Km_Vej!JGH$su{6$@8D6s9?5xov|-@dhQY5i3|B|c6y$ zs~vB?%;oma=hq8{(E=oGIl|T_M?Z4#h`(wR%MTxER8x$4HH!XusNfE!Rx91s%E|G2 z*V*KVDZ3u-&Z6S`9acp@#2?a$xjF{G5}U5*L6fh z-I+WJA&x8J+P9QR9GheZsI|MoZ7XTeas4CAIX)uBeWVzsCYE^pL`eZ&EIq%7l}PsD zyhaPcsB?xJm%3mPVhB=6TQ?TDaJ^$#cHbYY6%|G_DxSIRICWE-1I7X#-;5ZOE-{I6 zl4vvPf8W@fTXQ7GF=~9a`Ee7?Q>+QHQ^|?>n?p41YBE`@VF6lhUR`>!Soq8f&JI>Z zGIo|K(XL>Fvhb|;Y{JlK_We#m6x8+q4r(Vq4ila23AukYp#-&(*QnnSWw5b^&)p~3 z;KL8{Yhqe*mp=d_7UhnxHX&jz5q-#sg=hg0rp?8&F#*kyjBy}jrPKKDX2qAdIif!x zwiAMC6K?&@(;ecf_l3BKm~uqxTkWS)zadGIiv#5>MswlB{@_&YRfF(l3^3!>)}zb( zBB_8W^>0cbQ2YC_FA|6mLc{~B5DKejTd^zfdr~JMFXFpxIRXceDEk;f@2@A*qjz&vr79&B4@cz$_5tIQ{nOv;Y0Yf)Bk{WG{uM;g0jwo#vcUcHTP$prJ z0@+JM;dvI7lV!@XlBJqh3SOA_qIBlRS*{)FaAUEG^!&hxJ{R)7C;#w!aCL^saiZmN zHC&nf6sxb@ScAQ|{ogFcJCL7=WRdB*-FdzBY1=8Z0Px92-73Yz=j?>rw{V5t7!Uyd zV9ire)Ae011xqjK%@Y=x!S?O`k8hCUd9#iW6s{o^x@#?4b@!r9Q`-L=Ta+%H@Xva+ zEBsjurS<{3!LR#O8%cI7Zg`πEZywFS4J{-kOI?` zF>M=dd)`pIoo4>{NwSE@A+O?bi-;8~e#N!5s9|tB%|TxcwKO>b^~54YV$CyZCg=LleIxR5Cf67Grg+TR-xPnQ(*1rP|qQ-Ef< z3KqY?>ad^J{yxFbxJP2Am%hhp=wNT3XOM0{vA;&`uDE+JI4e7Ai6~2ie2=3oT_Q%J zwaoS<(IS#ajhn=T;EZ{tRzcVtJ2?B->djuqb40O-R(auPH;)P@Wc}#Ap(2ZDp{ouj zgg$gBWQ5yQ`u(?4YdZ9z+;I9)lb_HgpPf#T|Dz5|`t9W;fkfxd-{Ml|T}Nt2 zspBjag`bm;ZrNp}vzO&d9}}d*otfYMWiEY1A-#8yj`^h0N4oSuh1R!#3IESu1oEwa z8BYNIQ87DzY#@mbO1hxagq)20^H07_gNgWexttHm)1;i7uKop6U4yUgNL*c}yc*2ZN^ z1eth6#F3#@4|?9pujbPt`!$!bKNx{D6#L3&OKI{Go4Ve*wt_eV|b`LuH84sdbXD)4p?nutQjSr7ZtIb&D|6jrFO zW!K`+lsnvh+~nU_{|D+SV)N24_^-qln|hP0w~vzHAJom<`S_TiV%ytn%CF?X!|# z)A{9y!igI@(JA{NUY9`ownEsKkNd5cqM zk$o&NnDQhy8U5p`@SLAPbkyxO@+k5g<_b|gT4S@fy5Wt5$8HDN?~R(;tKK+5CU;~k z3Hf|fffkWrjD??ldsIwzSZ_#tW~A+3t3+NT=9yKEQ+qyVL)4o>$GAcgpge!=-$6n; zl=_V6WgMiQnWrvlFxZ6q=kBx&S2YHlz|FrwmJ1onAL`Pd`WoqCJT86bKU51+l|Ph8 zOani=c(?K!gY=1hKbL;{?&%AIbkF|;7Uy3tPyV@p>L2dl{ovC)ymwhn2e1DtSJ|CU zkjj!>9UWr`c%TQ(Pp6~4L;ZY!HT1Q2vz#?gZekP`WMm;SU*KqmR2bJ8$tSNm%e~>e}LK_ zN==Bt6Kz5s(q{!0VvCUVBfNhN{TuNJV0lkdD!&Mhhp*`%KrO}Ay{pB26OaCKyK*tO z#xSwN&7&tQ%^Qqz>>gJOajzjo{7HV?_2Z3{E!eDpo#RL ze=lB0I@5^$2kG>Se1XatxBR>LAo9DCjJDAIhh@Y7$p4|PFiwX;g*wg(l14CoE-iaO zzW!r^w7@@A_a{?!WT9+t(*1WoQR7ajWg*4`2B#&a%>cW{1RyVUFeeLd1WT0@zQo^W zZzEP~QH1$Cc7vPnrH%vS2DyE7=X`&Q`Tl7<`BDQb8FVp^+Oe0=BIK{+ECM zQrTMqxZ6L}Lqoy-fj!$e%J$2TJ$Pd5)29=j`qdk8`>HP`>_ry^HBlT0WryPTMlM0Z z9IB){+bbll`qJFtooZ}kxypv()v?;uHxjU&Q&#G%-7!_03K>-h6_T4G+K*NG?|*D# z_N}+`y}wAb0h6lqUr>+`%r%K-;et1e43eV$4Vok$FtC14)?Q_gn8T>F@~J4w#W7Xo z{++JsBMMdT6n$9LH@K=d-%r&DRsZfEa5?)>9cW=4R2i<+|Mp;dZ#KONPeo*`bn&cniUxTy|CmvP=Y(jBmq`t&65St}z zLPfdh(+MG~^Nhlo)gP@*>G3s8?1FVXhC&U+&0A7|AP)8R#~lXW%&VtS=1ScEGXQjo z``SFWZzfd1@Nyk8x>;pRW|vpIBUkIc{|VI3i5QL+az#lHHh`1nvdSf5ukt!b&KIAD z{lSw0D~P3NK#eDvqC?0h+hP_k!>u6f z55@qdRo+6CbeWJgHbUzO1_}8iu zgD@2=ShRJd9m}Fd(WqAYZ+~D7om81$7tRYRs`lr(hJGnQ+a!TggQOb&Vb%!W=MH4Q zy94x~O=L0-vi~*W9Kng**e!ZN3~BdI8}Z!#SzeX*KFgOx?q67ead$ zCE4dJ3eErjRd?BFlcRQNxa|it<7De2*gxdYWAD|pfCV9iA#I5nMR!+T5*DLylHOFH z{esdG+CNBIzf}X=*pkIAOOrYj(Y4yY`x-}tlLCDj8U9e!3M?W(FMFrWEu9e`QJ6i* z4+Z!_O78+er#=$Jj!i_^LtYh$77|!Y{u#M%cxwD^z=QqM^?BuIrye&AP^jV^PdO(w zX3>oLHZUgjaL@p{4|Ku@#EX|^2-;UV^;~Cup@Tx9nFFfzUikMb$0a%4NUkz1rGNL; z>VGimDW{m%`ma$Bj+^~+*b*}5ECA1HXZ5=P%ay#o%>NEA1sa}ZFQ^hh;4*>8;eV%+ zF^&dtUy4o{>i>!3h$6q(0Fo-wX@++n5Qvp~Eu3Q0={0Y>J9nLCEfiwl;_F8MN zz4qGIB&YYY%zuTn8N2epYe}Y^0+uP#NIZdHm&SHMvYaXc=}WXF5DLfG^V+XK;#>ZD zUSdRHIA`}L;}XXzGTio>U8k)J4}Lv7czrn0`!p7$)xoM}LO_Otqql@BT8QPy62G=M z6sdq{sy>UvQclH&TgOFYV+*c$|E%f#?OMtzSfdQ2>8Rb8E>J*8tPAWMNNOR6?2j=v zi2jZ3(HJ?4xb>}lg`OVVpL)qZ6H;Z^0j-MNX)Q|2Mh2{tE6p@IJj* z{Rv^@^FOT9_%Gl@^|g1kenr-CpX)I^2m4}v=2_qM3<0DM)kdF_7@s3Ti^|gYQ#1FZ z3B@C?BY&DUv3FwdiGh);Zfdt+!Nt#I@4HE%w))7%$Y2wK3idRJ08|s(FjoL@qR)xX z;W^Tq>fG{r{0{IQ8z&h!1+tXo8lF63Y;)DBd~(2ouvv|dMOKBPBP-s%7unTtB}Q58 zN4l48#}E@E_WQW}RJDxS)-58D_sdrhO~t<=~iue4{C;ijxua5yyaselD`!)8)?x43|VXS;BD1||Kd%J$l(29 zHput3MsiXSC2&^b&07jQ`*XPB_2BI-h*#$NTltar(bHSFYCsoWQfGd3>@O6oPRx0O zD>QGDpF383Q~P^fdG4$T&R;rFPWx~Ia@IF2#Dy2d^kV)BZT)RDulD;A6c4y&Sq!J4zTsXJHl4~ zRSHz^8>EB-^DoRzPKI{Zh&wanYZU ze;2ex2ERi@EcU)v zs*B;KzviA7A2H~>_+^8@_3?*n;y?h70F@93d-ZVJN!2;c;rIwTj<>+4;g>VxpOX%6 zN#o1#$u{-+`qwCzYUhJ{|7?2gAQu^DC8FS$ia_hrFR^ z$$yuwR6?tuRsL$aU?nkf#Y2R>)7r`XYn^f$B<1|6HXwk5pk~fi4>hUR6;;76<|$h7Wyal+hC3-N?q31bw-WkZk4AB^ z!s4}erL}Co2Kxt3#(2BmUBaVH{*_7oz}Sc0%Vqy;JGCY95?WOlW&LVSocgTF-TJXf zz3@R&4RX)*QVj!JL8|+|AMhu{Jf@cC55vLq6yP)Z-@r?J-kjx|_bUv5hC^rVFHSqC zBZ8H0I=|!V_g~7NtH_k$&)?DuqMCp8f@B4da=kH026Ww`BPH_NBcRqcd`4A zg!wbf?7T#75m){~?ptv@7`z+bjq2dJgt^>Y+pD_bo#}b-lXMUMRI}cT&dO&g+{8@q zWr4N=AEHr_=M*zzwOU}oYIdVT63FGK>g$n~>kWQd&sSk+ROo@G|N4sHwEo8L~Qk2)|{m+Mi%D^)vvAT7inmq_ruT zdnCg{8a0_31wf_LN-hx4UX}H-g7^o%#DqGG{pYnKCLh_RhuM=Br1X^Q6+}2@~mL{ILh8%%rN3ae`%rO5_oUq#WQBx^uzgHBw)aw zos(&H^|D??Yn5i5qaX*_Jx8^-3csBgiB@KV`xjbDogsVZqEEn9q={jE~=mT zp!qT53U6){X&g(FWsNJrRS`PaWh>CZ%xxJvTaX?HeduoD+@r za{qyjV@?^5L)zHr5k)eOp-V}#68RLmso#6h8udzeE=<)Shz<&%fp4-0U&zsQ!px*| z35A@)8Oitr)&VcAcebRXALeMq#(_wNmjitEIb_!2-Scf|NSzG91;BMg3Fc9QCJT%l z0|caDF|OkSXt+xX2b_b$CV(w}`6o4cFk)6xWYp< zIl+*pd9bG!PE2J1*5dGe@Lrrb^ZvHRoUa&z-h9YzC%CLF%@yfJbm@o=HUc`k5B@&! zH(wZW#5eeb`E2~aiF^5$Gk9t~|F>iDV~jg%wPBrER|tD7F|x4N>&0whOmW)t%duzh zhyU~!Fc=SimBdaGTdajAWCBUWL+!c|%4|s7v0N)U{JSy^zT$P-(HE;kfmYCtN+84O z3H>Y>EjCPyl}RK%AwL}a1>OZ!$e8HeAUP6yOOB}-XVlBd%Y7hy$Hy<)!pfY5ux~k# z#>%O-NX}ch?@&G*J&+%a7OCz;bQwArwu5&g!54O5J9rn{0cw;rA6&=@9L-U~qG2|M zpA#gjy<=L$luAFsATS|hAq2kRkY8u`ej&ohSwA*DXUi3>V!L0A$D`7yo+ zq5~@T=3MG>(Pmj2zFU`WRv9!USt~rQ zpy>tfGk%W`z!xIK_7LZAW9G$rM6&kEQ1ECp<{+3xoFGo4i&!?}FQ(hqW0aS066cO2@m?@@B0 zX#p`Fj$hP*HKkg&=(yOLx69TXj;%I}{^ ze+-JnCJ1zZ!*X?B8zlBlYKH)b7rgqcY|6FL6&}z4nGn$UGTTKiOb2^hyOHp5GY4w5 zAgJ9pOI)Ca7`*Mi=+Z8rA#+zUCv2=mH`T}Xy^PV*K$ok%8n#ph$i8RnXV<6opOu_T|G_fT)Gv2mt_GWE3Q`1!J_N>Yi1v1;T?jfwJnsRj*Z| z<9ozvIH&v6n~Eb}@LH4Mj|daA1FRfnd&DJoN$?{B-Kr;Hi#A;J6l)wbnuQMM#Llxb zxe{|`VEZ8*(63CT5@|(t1Ud|dCI36NSc9PE0`qe=uc!m3t@D+I6UXzxGnkP+(Pa0g z&Uj_^&1|F0%TC$AzsaMWMD7MZyiMwTNq%2)GAqzGbspEy*J>I!{0rWgQ+p-)Ek|2t z&|_`VuvPYMZ3$BV{)P_;xL#mz-QqN_(t=TzoSyx+I*AK&lIg09Jc7%zEJXZp>wzze zdJgrS@#4MNXneW_D0#3Fw>g(f)~F8iB^UDUjDAcwg!6JT#v)T+tHXM^Z9VPn^h$Az z)3A}zn}rJxF~fN2YTU}m=d++j4--WhOnCj%bmNR0J>8F){?F=Z7i@Sj01Ym-cEQEo z&CXzp4kBp_m>j`ghnbEsn)^(O>JJrEujcM+8CZGiBxqH(uztDvL zBgujl1x=2x+S7n#sSB9BSEr&HR#V*uqerMy_NG&dVg60CZU zyiLyD*7Wau{>7b47eYl&aP)5I=*;Ol=YD=hzMG3jJDJvtviAy@odp=vJr9be53#Is zN^|FGCvzrbbvQ8=H0{s7$mGY-dkvvZN0%#Q>sV0SpDZq<;+9fI?X<_l5npxyx1%%+M1B{ z`}3!BT&Mq92R6%W*uj#nhgL^i;E9pE8GAagX;so?DPotKH$T~x7O%-bDM)+@+>_1? z>p%`o+WP|SaO%X#-nX?-!zjX?(`oEBpSRWZ$IuM^9K%!Hd+CKL%XB_WC9}sz z{m*!nd+iboqm7#kSK09qGG3)a4XDexYtio7>U!xKxmI64XsbKILxnV4w65Swjbjr- zbJASlyN*wCamCWQP9P-d-sZ4{+|1#`=%#RD1j@&4IkGW*qcZ9Dyhy|C6tSTXmL=BQizR?fufda*OC0@{ub=CGL}Fci`x5MF)UW*Jb98 zpfvCe^WdXer-aqU{y;8~w)zk>jy5*XgzPJcywct@afF&UC)0%6`b!TT>80(xZhtcM zpPs2dIx9pBWHrMwWi3lx)CsTl5uczzvqO#jZM5G3>DOPO{>n`KaVG?+b<=5){oTK$ zp^xRaqK1TjcXp;RHbTc$;Dj%-O_x$ajhJq)Fc&Cbtr$|AXWljYzq*BofH_~%{ zB7JNm-v6`eob_hs`h#BQC3+ujOfWloRF`qYYz=-$xBVHnDm-9}&&5Z*GKceeM9Maz z;q9@$7>DvEU1iz5M;&?LOUGWfA{^sRGPcfk^mVS?eC!{(0V`VcCTFCcgVAfvA{|vH zoam3GnH`fzydP%wct07}ud1#X8>-tCu9#L>_er?o(xSSLv>YtO2H{?e>Y<*^Vq?Dc zRIiU_$HjEi)1KOUtF`AOSz=0)>BZ{$)UrLPpCXqy99?^oL0c}Dj+ybFxLv3-c5Ke6 zWY;&zi@jSTt-GIO*Tqi7&A{jw7(M+&kZxCRn3tQ}XSHqRLpso_*E1C{Bp#%b(!cSb zN~Tt7bYNpNJyH5g3Z9reio*WYSh=#>k+0@|d`yO{^&bQE1U###A7EKBqdec9Z~A`;QEYCiz8!@*9a2uf#cAnsSg+{-+uf%D)x8~v5n$+^Pjsnz%Yhl zP0@9TwSpPE?47NctNz zO?@6Tt^CVB+mKEDF`9IrJ_cd1o(T{0#K{|pMSLnR-DOM2L_FcE`;nN9SkE_9#a7*ILP=MPBZbi8 z++OVCi3T7exzgpae}z4LVkwM+-x*NlocyAslY^k0lV9TG%*xjTVRA5s$7dBf-RI;( z#EW&euAZEusgqI)Qv>#n~eXD)Qa)f0i2nQ~4&itltL>!o3Ej zV(|Ygb+{A6VzMw_B9Pt3ewvH@C^hj*QE$3n;n&jIgCFj`q!CW)pAVe3C)hAaDtA1o zC~lF-d2cMgx7`7jJ?`M`GKV`~;_$c(*B26XXC~Vk?#Xdrix<518#?LjS4ZOWRddUZ zs>IlCqYS-PL$BB~2cMhheL>Zb^^uCk-~#+T1JPC8;Dnszyh|Wz(^{KiPOO=Ak-Z3P z8K7{!Lg$6W=NLZ}EpCrgsp#k3gV9G!0d^>v`b{6?iL+KRgT#NpIvYfo;FInz-?3b~ z(z1uPs$NBz)^aZERSNPMh#JwyyW~vtx!+W4Hc&m6f5v%|XbWN!zf72ODx z689$5TQJPym(skX0#1|wU*t_%N*02)%i$lOy+uhSN%xd(7VXHGi(r_by+o|palpC4 zg@W@E_gXj-I4cEPYc00E^-2fSxWA@L?d&yG{%@v$_OI`{M}vnW`CYg3U@jSo-!p~7 zGR`ZfUiI>_8#yGYA*e(Nr7`=;@!&{R~usfcdHMdf9k-hH$Iio zkte~y@o@WJGb^o#?h(AZk7kUhTLU;j5^0KpX>;*om&*-Gqa$14LV>z|(G``NP`CB0 zUm+W4pmuU3e)}>W2NR23k7{Rjb?h^>GTn)qR&a^ChMebM^F_t><7i>){Z66ky3g@jujiLfHPmWG+m3k9nDZa+lPKW3E zKsAI{zsKaS*fjIgDiv?^|{cNs(bT=jAa+pM(H}p zRWD47O2bO@H`XNon?);g1BQ+`pZq4z)(;_%Cxc&i;>&=S$Qz(jAwh8Eu76F##2Un= zx31>f12$9Z8Zz}$re6;0FyqAH3XPKEp7c=m+_QpOe!!^<4r<@C{6z;ZJo=p^Px*S< zkf)257Ur(b?oNE5LXF|#Mv8n+%(iTt3+CoE-que^^RK6pNDN-mwko|ze7#5^N{;o& z9bphQ2Y19m*67eKqXEmAIGsnPMWx|u>PU_JQ|i?Yejs*n!?9=CJj+qdBE`q1FV_Zr z>>cR43cnO+VnXUNF>(}$=&O^2dKI8jloC_(0mysW^DJ08*Bon(y=y8xM)gBl6jWrz zpU&HJ%K)t~Dz$bwWK8hI3rf<(V>k%R@`}Aw?Kw|gqy4p!3WzrSTK3Fx$<@DG)xwL4 zj~P|}`4M#lK&T9is^8zMHpJilwY~To49@#5kTR=oJtW+Q{WJ~k-nq5UjH4rLtwdtI zw_#)EOYm+nO>O0R9fF`++&A$f!7GRWY_G|qgzm=nyDNB13WF$6z7I#czUvNr;NbLN zR9*Cw0|zCGj2JTV%eN2a8`iok!<4(vHB5FzJA-BRt#OP@Ej(`O;nXFQ{vU}RhUtTG&T&nH!VN6~Z` zy>-F62J*#Qzlm0R@G3S-+&}~HA2L12`B!+E4}G|7C$a&e(pIsR5Js$oV@p&@cSxZs zna4zKd3HHU;D)MlVcYk{2pfyKz&jFq;Qw0I6J=TD>|-MLjBF9uOq<3$_O{<9(oAil z>6rpZvuQoTIpGpcdgol?8LJZ*~yF`22=U6~4ml?#tuWWyG=0@C&MNEW|Ng^@00MeA%{pDR^-EfZbF+Bj=NV z9sdzbKyUmfRC60ia#WkSP*TrpD$8;rlMD7fb1wl@%nnneqU9FY?1T{fHBzxH82yZ< z9(c`b=P9uJ0~bW z6aTW6xYy_nfii{8nTMLVPE`h^Ld4_=9{6$vf|!u*H7|(0uVtsmZGApNUo}aezJ8UN zbQZtw)1HUla#24sLq4GJ#2SggsW7LqR=YrRdl9bR{pAix7rJ9svG4tyRqSbRNcUF& zx#;KJ?bfp3#f|v9o!At-c%6PX>VROW-*G75p+hn8}})nFuh;lZ^jr8cg!`E456)3SY&7mE;HjQhLbSnH^XqY zvaiOd6XAsTCepW~_LOl4_)L&C>^FCH0n5Z^OV2Y9*zvokeSS<44720}U2mH9SF>Im z3PKM_1&grSUu=GDpe`qVLB12cS>DQLP?xB4k`p&4aj2`7P+B4Du&$FqC3+D{@s14H zs?3=oYr;&-Dso~-ON?Po3>QNlN_l`?v0mW;#0o{cIc#PWEia-j#PLR_;s94+1OEh} zuh1BXKIm?wRExW7xkbbTZ)gM|s}n^sjIQ3UGe=GTBIe~rHiub}!s#lD%=~M`0SJ?* z`}~V4Z~Ap9eLavfjeWbbAz4Dhv#O54(DWJ`9dh<=b(;2_b$pR9k+U{Ba?N819P0u5 z$^`HXuVhd_8@rsh}8D2K`GZ=%`_%^}49e%)DpVO|>ro^2l-~>F$_*|5= zVrgdh8Os^@tg}!>D7HyZ6XMH^K7TGNo{BPj28G-|{Y_3?cbcAX(L2t_HE?(NFIChO z)-rn( z=AZe-Kri&B%*>=sO}clk(QukgFfWWqVo)#7{LHV+&u3s_#$2eopFttdFfksa`|tuI z;~{>t4AH&HdC3@}E$ue~yE}iqZ3WLGq@3-SY-qtdFG2pNiuhwJU(nZZ7)ny8$Y1EM zzT96g^msy+2mRsl_Uro3^8YVr^vh%rh9a=cT+`@I65E-Q;r855Hvc)wa@}=w&=jVSlMk|7C z$Fs%n;&%KR<}^zKHbwee5hhCI+4*`5z-exP)Lb`T(WMg-)nT+7Zk11O_R0 zCN_3L7=AcM(UyjUs$&kg!cBu)%$&3UDVEye*y> z_uDgENll7E87<@iLxS(qG5)TOcKYF5%EOu_Q?g=r@Gjk9=u4c)wQDq()d?IN%{Vp` zhg5CCM!dum02^x7BJ*V9Id}t2rB0*VD@E!P+-VXJm-ZYNaDR}ttaFmNU#7V-WO5{& z^61F39)>~H_0cj?ZKRKo{ygz9wpY9_=5BBuO+wsKc_hY?tFnX^^jk_1nsSN|Fdyns zV#_b-5a#ms->F~G{Y5K_l#F>u;lza(8Lx+VQv!ES4mZadk%mUTPej!-RT&+`ug@=O z+(WH~su=B1VZ=~jIFXxg^%vQf7D{$WM?K77$G~M^OVGX(zailMf{}OP zz1e5Gv$$h^&JbnDFPT*|4PRDKX+)+3CB?Hv3ytP?X|Y<&6z*hycsi@RDJR)!6qHBJ zC^)g+_~(wz;Refj{pgR?FSz)z&7JXhu8kSze!>$#by!Kc7ta-B`UYb`c*8tWldU|p z{BIcGdHipxsHa{8pvlRvQHcL}FA8zZD^{bO@?B}PYcb|>91%MYt9kaFxt+%>={?(X zMGN}m_pCm7s`SYfs^W%KqHd&sSoo>%8}YR+nH{6rHkl=8 zSb?IzuK^I`lw)70ou>Ylx_w(U#$w)7Sn7^`$I~V&tw=I|sSWC4+1!m)_{lpp^Jp5T z4eW4LqmY@+49sO7eeMa)yHwO8dl+a6q#}B&Xfaw$JEq-Tw`C(a^$W%Y5o7Vo5nvy` zB`Q*$EfanHB%_rC=Np5Ibdt!ArIT>6g;_USon*+RW1%T@602W-`qlIjsUu%y)fe54 z&jD+`&G*x?xgV2rk9&Ud`bWvnx}r0Sj#9I`AXbc`NVSx7)<5k0EB#OW?dZE;PE(g#{+7J-tMNA^ zSRf_W;Vdrq#{?BEc=;e)&hV%k-pb}tlHZH|^k1?mbsHXLHya~ye7G@AuoFYHwJo^9 z%cof0@Py>xyygcmQq8h16>098SzS<- z+Lc9B?NUJWHKWYaO#n%%0&A-Y+GGwI`_b;&L*%&ISk~sA$6N#jc-FKNulfUu#2@IC z)>r5T=X7nqorM@hBR${3Ap2syUA%P5^Mv@^Ph>BWo}~E7S|AqbmyH#y{(UaE<6f>@ z|Knp^yguxkzeom#d=?*eruiMhI=0}X$qZ|J*vb5qHL`z<)g48>!Hc86w74X@O6i{F z{ZSi%-D^_n)N!qM2RKu-uB`2q!-2-V@RJ;x{R|~5GMUX(YY!trM|5BA%#*C{WByKI zEwq7LzJHuqKYeP}PuQK)1D(ml-pHGGR23cDa1HkNZ!uJp3m&3~v=B1{v)D3+>&gD; zF8U)~j~85qV@G`0yFcfm`FP%0biQiHDxSvJry;xOa@mzhRw{X?@gqNL4xjhmI3|AY z;+`z;xV)*YiDkx|9r0n8EVx&dTv129SmR#BHevI7lsQ#2DmcEynY=lI8f+5?@Y+HI zB7ugwxYVMFQ;K(fBHf;0N2`-j3|cP7b@fyy;f)$fxmi3UI;j6IL#;-KPxN_AIAH)x zE>uo4i+DH2M+QQ+Ii3H*I=UiDxam524gig8mbDpUg4ekMYWiv zkK6SEoTlX%d#*>+cG+`nFf^z0V~w>DDbMv3Qs^*CL76oMQ$0Ap2e`n$NDLr4azFIR z&5)5e;;WMTC+}zFYQu-IUQCDly8N1w$x+KR0#yrcucds_*sr-};pwe+2f_n8&Muq8il9Ii8y4xqAgeKob$=Nb!Mc4OK z_pTL4_%$7=0nzSvV%X!1mwReEsENEUmf}%=GGE;Cpf3X5H!{Hg%C?~TgY$<&mwp>! zRh7vqoj+heM@9Gbs2yaau;kYSaWhz&v8b|eRQweWH=B|wq&Z5NZo!84DSnO0bLv~Z zA=UA7%ERfUX@)}9LIx6NM+<^^&Wm54);F~ee% zFJq>bErG@WLz)p!K!t|mB&w7d+0lAK7uk^)RI3OMc6j<6s%MbQ2GjcK<}d+68MC5d zV}p1ZNE@`t-HnCQ+#ozL---3!1mYdktn9xK%Mb6-+^jc-TEGa2zuX7tiM(z7nGHwN zN%zD@MLr~2{bAz6e0%H1{Q1o0oH2u(Cy>*oA2`&XJe>yEo%_RsvzjjV@6Na&!yn@8 zZpZtywFv7?GjPP0|Ip|nm_vz;t6tDbT7*jn3ERhIMBWk9)vnIN(ObBN8^etx=}rc( z>7QfYzN+{Ms~@iSiDd34o6Kk~^>l`p%>JU3ZoFkyrRXdAO`mfR6xEYk(9k~5o%s!h z+A1XG!RQu~3yvcTI{+BCCyM|QON~m9z9^$4V4|}cgxwhqPv$o5ymg@}h-HKO{x`tS z%J6M7$c$|Yuw0bbFcCnk!ofu@8LuhipB=)bR$J-fIh9c_l3Di8ImkHaPGu|| zH(I4Z=3h2&AjVR+-=8q3>Iq>2IEIG;hG__`WijBm8@H1O4M-Em?EGw_Kl_7K0k^+8 zLot(r4q%}t5`JuK$iMZHyEwza^VUU24!GT;+tb)zDFQ)_QI6SLNl{#-5PbcsO}_F?mD3oOIglKA550s(nA{!2?i zh5-$9u`+=}QwT(;Q1C@tyD@L_Zk93mw3YgUUi>9fxjJ0B@S@_cI|-{P8Q$cWzlw}B zr+AY2JC(oQhFM~mJoZ$DBRm?>HA!g2r)sBurwAxZXoiEKda1MZDg~ibiV_xjFH`|D zJM7v{%uKhsE+Y$^_eB9GrY@u-@`1NDq^sL`R-;o9OxQaQv?Ayt`A_9V%^_3Vzfa|GM!%#*MB?cC*PypN*aHVeFoU#pO4rOi3PR+4q2Q2c zsBvPw7}jNakB(e^tAJsbdZB4=C8r*c3r=&rUiA+)sa?d;Q_T6T{~RAJG{e{5LI;W2 zxGDGm;d3?wA80CXsnZT+h;d8gT@fT~;0RiC-^uGRTixquSDmo}KmF5;C_m_f9X~{p zFW*C1QLhq1dvQWP#I+35@GtLuIC9~PYQ$t7U(DfGc$)!eI@db%K7-`LNuD`EFWj6U z{t&5HKcgQDTe&}l z?`LI`(>)Qt1NGt^2omYMXbX5^#z^$7!2K7n&-gog(IKy(Syb)U{dQW#Ts(r{#D^ z+e(B<(T*!>^^ni-pV*&&>qJK3%y5gVb9D335}^L3Fb4*(Aao1sfN&sC&qreNCW;3V z5Wib~b;Td2^{&p@%8l3CXC9`vXTpgabGR@g{fls7l%l>sM+6n*D(QdSa;j6YX8P%h zY1H(QVki%2ziFEoaYu5#o7m?wkdKWX{TWM}2+`PD-I?-NF|P0K^*m+=YO?gT0SLV@ zpo>O@BXp;gA8-|PvAV&UX+@q7qS%vh%*(NhJWKT^102IqEX0b>W?Zdf*9PJd1G2*G z>9%teMB)-N1!_;r4_ADSmXotaeSkBq&8ianLB-lzI5NGRZs&%wQcPek+iYy7`v8;N zu9oiPDXA_n`kqy zjNwLFKgSUozM~}@ZBDVQRAwl5HS$#UKm3c~vb7Q>Z7I zDaR=sJ{hTKt_u$D&w)eG*AH_ zDYoEZrN+S^zp|LcJ z*o#E-WV0pZt0%@*(Hy)TlMxu=Na0v8w9XmwCTA4FYzlD8Gh-&o3J(THxn^1vg@>RZ zk_%6jjl{6Ybx4m4UgzX&AYMT@7}+Oc;@%L#%X3`n2L=GscCD6}JH1nXl^$I|LtK@9 zn!}W$tw=1FQ(2v9#Dpndt;os*)xV+;rYeP@EGjO#-%Xj{UGC4l--o^LE#`NVvaGS6 zBp+w<=-d8tcANOc|9GBgBX9Fv{?WiY z5*iHHg`pq!K-{DcamRc2qh05vJ2t)5rr(`OA4|G>ysb63khSa(M#CNYPpM@YzG=j` zfp6t^HK4w_Vum)=+-@PW{8LNDj0}(CQC=}Ubjt`;2N4=+ezuk7@k;3LY(nmdp^x(j zZ~`96k}jo&08JTgP`nUAl&!4vB<@*J&GTd0(nTA9W~0Bg+L;2(~qd_IPrYSJ4!A!ezM*s zCkCJXTL>%yvrtzSI7r!HKf@Q@beaw`QCejo^l!jM069^NaO--eE^QhXF2&U zz~@7gOD*LaiS3TPyu&zsrSoSxkL=T*T6BsGOG*_bljygDVF4Ue96|yyDk|QVuFFZ{ z-Ra}e84R)bzbZS9LJEi8l%kTYWUFYYdpdD5R|?77)RNbEJ0 z4SQ-|jje|?Y(G^E%lSm_je0tgh{|BhVdvd;{IqmWeLv0cPpmGxl1b$Jf-{UkduOoe z!cf~PpZ^lfmO^#7dDWuL$h1#Tmt@(x1>-_+g%f_rNLAdcaVJ^Ku3fivb1w4`nR@$R zD?_V+Tlyc=jz9IjBmRO5;1~hXy>atiKVz)2)Tn>!P5Tj`DuqqXzOz-t6DW>&3Q)n=0m#e+Ea*W?H1;14hHG05FnW(}x4l7IKl;CGG( zdyT-G)DT!^2D%9~f-Tdpi)|ogq!Y@30eZeqv-$v|)3H*X94BFRS&0vF-NjvOG^zwm zr9|1wWqmJoAOAg7MD3AKjs4OIKI8|9zjlNNAFPzvACjjO<;b(>tCi-`+rG4m@;~0m z6`R(?mWPxyb65wDn-o@TMpF}w-Z&sl_w(J<_Go+j@TCe{k^ zs7(8u5|th62|<-Hu5o#*NGkql@pk)>la{JE zA4GCm*~T;Ti^EG*a~{=v#zG{k6NAZ!nWIPk8Ch?)6RU5%kl`C;@oSi+_Z&iCJX$=} zJaS6-&f+O1SD$-skzx7hNA$z(8u6nSW}ePz^uJYQo2*O~f}UtGfw1RM4U&2(fcoH3F2!`qVqclmvYeZ6g(#M{%nVdDQEN@}kd zX2cqxB{;8M_>cGbtM|R0??yf-?ayc+q&1qff_3@<4&?1D=Ohm~{2EIo&cyRDMJxN0 zCcDgIs^ceS4cF&U^O1F;?_a?=pm}|4+Cr1Iv{-Fx7F0Sz_G)!FZx`ah^x!b{ApD@$ zpX6NLhVv%YFjerF4K_!n`XQ^#IB6teM?_-h8C4#`;<;GE8_WptT%>0W9M8<)i%V6< z1TB0gQ9&fJpbW^lucfg z`B=%vdHNXpuEXQ)_7O_Ec!Ea2&{XW=NhF>63c0vZGi*$1?>k@O1<$=fz@TI!NQxIcX`Wx@ zSx0bx#v3PZ>(}zWrhXHD32OGJnexO(t?k2tWV!qY+*9h|a&uo5?~x43n{l%sts)}U z{j&r~-eHf!)eC^i?T*OQxEHz=Fno9E&HQ!cf=_3XH<7ou8xs5&Qvv4>OnGC4 zzSEBNkhSi7)ssU#tgmdN(;lFV*$qE&r;N>c({Hj}FLEEYwN@nn>u_py^SvsI#9xQ2 zsuyqKPYe0n>uu(ox5#{yGPg=U0Z)$GS2^!g&R^S1n}6)L`63QZw7GYdZL`EZ-sT8B zOf}ltbMN=6DRI}&;dKnvSp8(8THQ0lbUgkiztyX~>^1HpWgnnc%WR$VenP9?piWzU zxSB>nPLWrM8HOiqWhXpKWdqc9p;y@ycf2ZF2gcmLlF6(OXWQJNOw&6g|24D>*fro+ zMYtM)`_FC833t-|NtyOn{=;brS6F~+da?t%|C1^)E3>Fv#DmR>bhE)I@8b2 zI)jCIx&=$PH}Fl&0>}NKfa$3Uift>sp9L7XMYyM1I4<+xD0d&TwVe^CHZ$yfJvhqU za|OpL&`JMVl?_M?3-BrV8e8_j77r5lPmH~f6xUVpD8)rTi)_|M?(=EkslWT`l7WAC zjjwpL5NWN89%1yO^L^b8u0MS^{(D$BzQyx*^{gxATzG!qN_qk*e!&|X- z&IdGwUD~~xT8)2926AI2h;5Tzifc{ok*bFMdDgL*)+(BA>(A3I1itJ)4smvyr?P_o z1Jli*KX)#u?xTUcjxkotzWxvC!xPTjhJ6Gv2mN^IrQZAzH`&7=xP5C)&L73R0k`P` zKVdiy)^q#KhrhGuP14w^Spn*10z8n|(C8PH-BSQNMNvm~Be z!k5^VSG<^pySWKsaAMGmAqscho#6G?u4iLk2j1;)`JwC{nVK6wed_OiHqF4l^c)Wp zUjHCAu+iVWS7hHu9WAjadw8MOQTJQvFYRM{|HdPoV{5^nObdm{W#|ON#B7?Y{-MmR z*dCZ3O83w7%>CNk{_=z#_jfO}&<*gRb60_Q1K56Xuv(Ds-fi;)e89~7*zu*XX#~8G zBIfWemIZcN1J1QA22t^$Tn~OaE8`H?#j_mefe*R`pf*&<14g9jMNaqHP>~bkfv=n_ zna(1hHbgYb>2$X?#KG6;D6DGEN9h&lM7woTOuKf~iF!STyN}q3i>~?X=iHha;;-P?3>}QicAL}v=%4CKY(fnHtehiW zQd23-Gv?5{8oo{de-psbHfIP1l^Un(YR*Z>(v|PbZ3>`v=*(cpJRW@!dFq_f=(1c9 z)vZV4q9a0MC=&~xK>Rteg%9b+EUK8ye|W|&h75g#JFkaKE`P?tpSa&@I*9gKDp##b zOs#QS>kuxcPIXt*Y;pw`jNq>(sUxXa!oIPZ*1!6Z1rzVZ7DK#t;v<~H@iMG3vRcL) zHmN>$Cud8g!D1~#`}Is`C0H=$yzS(v7WW_8Ofz0OWHIwoyBmog&}|6J)S}A=z|=G@ zIWQK{%jD*!Fyh3D`E)I^lD#-$Gh}Kv?Xh?*(vkb=P6I*T*M^(i?&kzw?A;^!{vq}f z(NSAINV3H?reS?8!Th@xPF)YdC3jZkQ}s9|#;_5e-V>m%Wwz(q(CMAe_1s4#lgW&8 zjpRcZv;``O4!w_@W8*_N3IIaQr$V|*8HNiS_a7EuU_o*p!DATXs4X87qMmT+FDhwF z!S8b2oZ;`A#k_pHg$QELO_l1cqQP50?&C-#vQIy2N@oj$Wa^MX){^{YsWcaXi2 zSZ$z#(QDXkMw!`%8P61n?M^i)yS1v!Jl#noO_n@It;DvOd%Zc9;`S)8(#!G2?VD`o zdE>^dB%%}d7xJrN>v15zY+5cC7Ti;KvB_8QWTmLP+-z?l3R6Go>SGgp(J7CukFLvg zqRX@r2m~W7v6kq1?4rxGkpo>2Cn>UC_g@49O&^AOZb)+XW%`h0d^`r*os@mQTTgcG z*Tgmvp?G|u4N?5QKg+Om>K>^eL178&f{p3$*xsgpgmh7LQ2Iy3#@hVVvAx>ThKGNg zQyIK>O=bD++KSk}qI1U=SLba9rr1;-}}2i=!sY~!UaQ4H@+^&F?r8c-i-^5 zOu@9`9(S(sZ!`7J_U1O6#^1Y^&Gqb3z2_(0Z_xzoP&*3>FyGcBl(aEE*sk51p$J+a zHQ)WA>gTDbft5iHrOXS3kRE13truL5;6?5j3y9fbr=Yc5C(nT-RF4QSl=_}{xX<4> zor&<4yXCan{JHy6Jl5qmbWf&!$y3?p=>D0R&$$iV(<3p9GFbiC>VS$KSxhE=Lv8SH zq%WUCyx!w|&gV1DLP9b+K@{|6T;~2L?w4W%g-Nj1T!d$=)+KBhHyZwuL{eixlT-qkD}ux_73g(+^weg+-_$IYe+*b(`9&D^hi;X)EcfX)|sZfFCk7 zfwMIxFP31c>npTm{$Ua|?)w7kP->x)e#wk0>J{Hn-0h}b9ce04mWKiA-2F;YfwQgr5_*^&e z-DLNV$26=9&U*v$VE&F;4r2-^LoYc5c;madjp*P9Mf^K2l!DkloH;3^DRV7};Ci_S| zH?^Rs4ph;*wo^2b*XIsCNGhZM&*l?zfx%-15h6HHe>WdIn|Y{dD3`MSsUI`RJ0jkD zv-r=YU)~s&s;){AfQmxf}ii7w1fD1qs^>|%NOI^d zOk{|S)LYi7iG68_zf1O3hSeMfZ|F~apdNIUh|I7j!!Q}$Lv#}giwe7bU-T|R9y8U$ zeW-qzs>kThHYmPWs(zX_;hN?D(O&%kRS!So48a~+IK+FPCNpHI=cETD@)nfP)^W7u zo=!WKjtmoE>s zi8mOg5PQ>&S!F^yE(9@7^f~hDV_5%OClN()%Y!V>VmqVAJ)=YW(sHPegmi;Q_}{eu z{?!L*pHqlEJGKAt3AFz|*M3?1E6&R9|No)=?{#XwY@Lw;ZcGGbIHK2owO{+C?Vs@< z+Yink2&sExP$VRlN`8-;V=24T1RAS5ZkhDzl~Ue7`t?tE_lLATp5aIE zvlr(`(od|nwa5zuF)=3Cm(ZgP`8%N*{ljmT5gWn()7VZ!`k2eB>Xl*w+~7E7?oA*^ z;gr9TF+8b`mTS;=*YiZ zNReQ}Or|wU$^7knWgEr-m5d>KMe#h~d zaid4u6ATimF@r=QHLoa8?@V56z(?_e=WT`d+{doaSp~_m$w$v03UYm<*0dv4j0BHC zgV}y#ba$eROC9|&Rt(Rc|EV89Pg#=G@SkxWd^KI*qwQX5n}PM4cWm=aLyp;+mLIC} zTdwi+Fn5gK=vVWPewNBS7)lUviGnxA-5W4>a(ibJ;nf|pRBZ5Uo0f+*OYbr+ZyMq&anPp=BBhPe0F}+{_sBJx7{Cp z4L!^BbM7bgoT7-1eCD)RpsjWeQu-Fu?4}hAPFs3Bnxmp9rpI7E9a%X#7_f<^?`8P6 z)~|W|)B!s$LGE(h%R4U6xkv`WQ2>nqTf;Yz1>-<`P(Y* zOMPPM9>@*OQ;@AH@OLuTrQiB;ry9l2bxyX1`t^^;3Erdj?*tkKu-0_9wkDi8?|PMP zI+H*1>!16tdddW&g){*xo)Mq3v~pjl22G{bPr>#*o`J1|I#YY$9edXt zSp>SJ2L?thpT^%Y!7)u^5;ZgTt{G(CSRK^!6aeADhSgGr=)F3k%buJ5h0n@IJxA#t zPL|175U&VT<9|Bu5i(XW9xN!A7SAGg^d*C`{NVj4Gdqbr>Bc{$E_$WWl7E460q#(D z*G@FZ`wbowgSvI@1*p9?e6I&>>NEq8t%Ncf?$|bzC7;M>J;FEXuLmY-T=Mn|VSY(z zbgzTKvmfK9FJc@)pI?rEbXVG1K6uoZ6YID5 zil+FBJMo*oRPJjdUUlRE9#^YG=G_9l<`zRFMk7GU>}^gog~Zl?AmA=x=cWVMz_%*J zQCB(3UccbdMT<{eRwb7tGrrIIWmaZia#iJl_; zx}y%>+(F@YMBo#A_~%mmAn@qnMtOrV8b3lJ>EgiwL`ty%GEEhSGMmzqILk<1)3XzVhO~Bou52SnhPY2-t?gJ2k`xX6{&vo{pEpN7@cwPY0fPst5K=)114PyZU!;rp4@p*P;Cq6ZJyIl zaWk;hl6&U4FxbuMzGlVGlu`>|SLf>2-f{?m&vJ{>$IRPoZ5UN8xTN`cV(&&j%E{Ta zDc#Uow>$mD3f1ObibE3T)9I19>GL4?4bIQPci?Xt?8$>pP7x`4u2exg24>QcpE{nyRM>s>5+F;9NLw#qF(lH52iG z>IFcii8WYnJ5ypYrVUZzBycskQ5BcN$7?TVTjZp?Tl8bUmbz0eHhp+#9*pJ`s&(I% z4gff%?%&}FfSWrGYEhG(en48e+hWsNR(PJ=mOm{L{mh_7@)Sq+9g6WUk+-uOvrjlm=?KQ`2!MH(m|lH@r&Jw6qS+UBDRL{UHM#z!3FkE zM!^Y#w0~9bb$+5F7oWr8NtPP;N18QsUVzW8-QVU@=A>93cOa!K>x_=P@~FE(<$TQs zid6IF#E{#NiinZ@dk&9vCY2ECSb13^fO4M;DqG+WU*pd!QqE9$T{mTPAfjZ`o$}>c zmZr9o!L}*Xs)a;edzGC;U5cdy$q9eaQhJrd#nYWR5_uBF1#4^XDi7`r^_A2mFEB|TXWuhdZGn`c=vsw*?=XhSCf0=`6eY0a=(88EK7(rrXF|e zDfZ$)YqrM_leNIH>*GTJ(4)^nYu=%BN!dE|!(&)y<0S50_l`shdD6QFW#A z|DXSox)<+HU|W7L)_(y zYI%R&!)Nj-!KWkZ7I0>`fxENw{!*9}2_X*h-tiuzBVRaMV}|87Zw24nKSeZVr&q^x z6mrpJf+bAu?<}dcbkzYH)%&!gVKs>JxZyBoK6Z+ZYPLx1f%&*{` z_mIjcjEHHjFaBJObq$xyD#Ksf5*Oy*oaRT};Bv@hC-y_lyZ zmJHlVp0~EvvNvg0K81Du)%9SN=%>t!Qmtzy+dFx2% zh~u}v*9pfOP-_EAUA)i_78Aw;He9dee9T8vr7K25>@ zTt$VwdH8`IF!$m`YUCwB0SSsU>?6aA$}jJ{ljXM$zHG1pFSH69{;1yE4}0Kml+um484l3`C4H6Ns8j;-8Z=Qgy_D?+QG1CZu>L@WaxWfN$2s8%C_RSZ|M6X4+={bhJm`P zCv`4IWAMyMsLOB@kgunZySz(Ik3nS^_z^?0$s-;28|PQ?D;lj*jormglDVH~Wo+&` z^Fma_<|^vf9rqOHnGKr>`0=eJOMGq-9{>UlW70UT(mMaBX7ic!0O)id=?otI$cI7A zBWQsZqN>Puyw_s8nU>&wovw|Dty-qlSZvF~dk;91x5QSPSFP5#!17S~-m_RtH&;Kfy2O0E(?NvyoFYnfR;@bE?Ap ztu%kVm>kZEfuu6ssKEqM3Rgmzl_;N5n=-3UmI3U18KQM}aE`C5YQQ9%YmOsaz8d^X z7ous^OC^517SRh|B`X8&>dw_rtPmAnG+*S8SImsGlb9>Q@V2GrlzD(eAYH#5 z&l!~Wht$5DLiNl0V*QeNmR^J}y-an#HI65=vNurQNAT7C)rEY3j~1~$INzidj`i1{ zcPNeG3&{xoU1ZabU&^XM{dKSN((7&dY@1$NK>6NEA8XQq!Rqf5ZTjC{@XMd*rBC(N z4>tYDu-|?!(!o)QF?GWKNq1k2@TX<0fpq*a+9VA@UyKh360E^pKE$(bLYTm_zUz4k&xPLeES?9M zXMd#4a#JB>kdBjNRG*@aV0Lvtv!eght4q&)1Lh2Mdx97?T#kK~y$nu#+KTEp=KrXf zKf#9cw639ijp%2s0n%7dyg-hmOj3$CnX*mM%M$Nps$L9v2>`t;HYpw<@-D)(+B~Hv2*;xv`-hj_Xw!$=^k?3_EMPpl+#MQ9$_p~- z2R8lAOgiQ_lP+LMKTvJzzdn=xl$S2}NpH33kxcp>UixC2zS5?joJqgVOIH^uzsRQF z^ECYfrO-d=?(yoiH;IHFbyn|5{qo+(uf@-za}9heKRT8-KWzO^F7fBj zj`LI%g43oCwCOMZk@Q1Uo(&(9?w!v*09AwE?R|ZMe#)e0@ZW0F!XPl@>y!dtM;K?fLi@B zPO>M%Ln2`$vmYO%^>fxeGK~;xurb{y?&Pxn#P-v1rx4Bu`*`#~KEZ&OPpkW3?X@>t zeTq|&Ut6l%9IYEuxKs~4qsv`dz_k+PB?KIx4}Qw>iSc_y>ni`NdaZMeJY1^z*QI&)>m3_$e_xbcfBNZm^mMczf)?rC0OlA9 za1uwKdER+}<^AZJ`#d`RnyTU<^hP_L(hhkoA>agO-;5?_Qxkb5&+1YiG&-$6S|jW~ zD@IvfUp~9n<7$)Df96*Q*o+@%7I^;=zMqcw;p=yB_zbum;am7j7JS1q@ZHE~_jPVL z>j2;EW3zGhe}?Z4PQWZbQuv$3y8J)m5BIM;_vtM77LD`q*TQG_ObS z+9$H$o9+1cdyda;@6Pb89Qa@1Z~c#b_?~AM`#<9^7x+rD;cGqDhp(^TyZ(hv_#61& z!FOT?zJ6Z`zC7St`0FhE4bQ-LBcI*ZpYH_U?4$lG{M~WCkH2aAz6$<&0H6D-Ech0k z)m1f=(zs$nl#0-4*@Y(%jNhkOg75-=ZRc7oTFv=pdf?iX=S^-d@-|W%e zd%@6G?m~^)TuWFSZu^NJeX`zhdvs^3L3bFfq+iHptlqP+uT*68n?zptMij{b>TnJn z=HSky8&&f<)f`sM7wA2<*8Q3)M!!CSnwKA>X8Wm2{ZF1k{UO!=a|3ywUY+Xi=GDLI zx2FEt|GEC){Aa1p$C2zZk=QQZf1~0aEhOsZNVO`FniO)^qQ^JD*NnmZ{1WbeJsD%S zc6Lxo)2EnYN%0#?6ibKo3;XLPviZb(MQkU+Ia@#E3&$oFg=4d+lCw~;QT$FI!B`nM zB7nJpFSz|%Q&S@EtnbrpjhNdj!y%3RYtaC2{8MF}M4v&R)t|KikQpP~oo~BBD)VuS z&h;;K9G$E5&geA!raS6$CHnKeZgt0!@xo3S$9Wkik`bCsoP(x+qTss@4yh|)i5U~` z^NmiWj`vC(Z>ncyK+fE{KalhAPB{$ZF@se^ zP$SS=i>_Ol6G#(v42z|_kB>4d2(!nGy10q+;|fn*`<_+x+0P^Tw6Qd=N-Ki6@iE@& z#4pKboS@=MLj1B_!T~g{wfJjvLQ4d( zSpar^kzY9)jQeJPzk|p79rQ=dqe{mk$Fggh>9S{)(&-R+<;EZ!1#0FFyUe|IvC%Sg zYfY2LJ8+dxLu!Tx|JBvjsc34&! zmBMTd9;SIe=A&D4KCBc-YEnNHaPjd|jD4Y&!;7~P-k|EuebJGNhJdG90tZIk+-K?c zG~;lJVeHL)lnQV;3z6=oD(=?#MBJOAC}@rGxWF;Do8PA={IKi#`9aca^ZoGX)ev-PW=3-PRkDbqtBlbOsq5T7QB5X z`%>B?Th6=UUPni!O9byg&M>YZF%rL^$Q@!J?k-1H++;(MSl-W6u6cA3rN}aBD)cdh z+lD#zJSkkUb^5tt8-y2WGXBTJQ}}rGXyE&!7M56ihz&Y5I`VeYP>5D1xxZ$goS4jZ zw`}wzbHS%sq+K#4I`R@_3^sfd3IV5E_qjKj+=nZ-xpPh9kq1QH`u`#gipC0yP)+I@ zR$1=%`>`9;jVHT*5uE=x9L*d5DbQ|7L-**&&%RDO$=cqL_}PW-|FU<^Ef`Mo*@d=~ zXM>wJm7}(hTkcCD@e7OG5P*1BWmv>ia(wY@gO&Q>0R?2jMAbRWzM`&FR>v2L$P_DZ zQZ*w}&8XA`aT8gW+R1kYZ_4GXqa&{{4I;qujz2l#_iwK4p9$MhsmPv_Fz^oN|Jfn^ zDGJBKQ^WD|8IVgcWN^)$%J_3-rkj z4?HuG_gl{MyVq6QS?)Bj^eA|oPxSwI5M~8nP5OAqzlbB8F_Pea7Cx~)A*_Z6kN?5@ zVn<)4OjLc5s{WB-AYj#C*^FhX2V}|(;O+~|Iykl1wh? zzs&f)CGc14p$gcs@oB;*etTAg_IC`gz9E1bIh%#Dx0R64eq!8S_UN9B*%sH-IC5ZB zTZ^MKmk8-xk5{+DiGETKkLd|`=>;AnRz6K{=dYF5R0ZFfQ(R6PUx$JBS@|PvX5mPt z4>{VoW1GIQ_I!>4$o`@sW>5ju#hz=(qAC6&q@YgmHeU#v=To zAi{AX?`Z09_nl=&9Ldrw`B<7pIL>*C`El7>oat=)e@J^1_$rI*|NjQK5RrI;5FHLA~K7kjwSfi@V~t#jS3&Ur~!7E(BXPt%A6q zv=-M+j8)taMa}>HIrBU>3)uSm{(14reV&x*vm6||Bm`2C-bGZt6Mw8~GG|9+ofT1_r=f5Dub3p@wy#3he!87RG1f&-E|(RAtLi1j@;cCnAD_N$;{zy?kq!HjPryHsNKFEhCkm!B7@-3R|BK45>gEYL+ue|Gi{k%^8xj0{*46u&Al{XD+9 zg|BS=QQ9!R6Bes3b+fD(QQl8uF2+k$Bh}v8NI}hnsmby~tu%f^4=d3PwGR%Dubib< z{ZlN@RCOGpBP_w1WcjznAr#eapAJw|TRhObb;fdYp~lHf+D4aEFSqv$#zcIT$tcg4Ovlj)*Y^wB@Q?bLP>n)rt?oyzDjQuKYtU88BBxk`B3VNG zC9MB@fsCx&t_t1m?K^3PaZt_n2md2jffDp)F&WrH&WtTOj01wTLpdLyN(hgduC8_q zvD7oJh^Ey-e#?(N{&=ikR=cEm4iA}LM`o(>Vo$Cn8gXmvk#8#+4-=wkV$D{w?tqD6 zWLX6Et^}=9(}k|g_L*%!oKm8V>>bRSQsmFFv+`?iOkAE9sYR|l3*4gDW{(RF8F(hu zHrqwQ#@p4e0{}rwndlFH$qfL*dVuRp^g~%OV*u*v{~!(*eLj~kg@mkUIQcsT1Ecln zd)%Kh^_PL{RSJ)eG1}9IbB(n%U@j$aXPWK`+V=Aj~$;fUmWiubm&Yey;WY3#W%fguk$0NlzxI+DV9hr*a3G zH^Z}b)N~)qK3`J%>YOp&&>aMb!wOPGlY)OHCL-ljW;&B`Vy%u>rS9 zixu&-H+`}P!L}u=LA)!E9nOQ|ocRPdygTCfb)9Ff9|_MtzYbBK{9t%u#(~|Y>4^K_ z^l1aqr(gFYd^EbwtDr>k+g3a08e6m_-uire5IPKPXKH#UXY_)F-a!$&9mTF@FfSeC zypgd*JrRwwm5DDCllQ7jzIjzuY7Kjp%JpxK$yD|jnfH8Ea_fLAUv94Eb2eD9tB>U& zSEeepEz6n1;!%4n8#Snj(!}gb922SGSS`_Lb}{;u!%*w;k*Oxy>OwGevFkxtPi$G~NFqtB8b`g6}>*7!;r>sRNC-R<3i zN!-T&Mb^d5tJ;ag=naY`!wgDXhKSNXaoL1OE#2#_bHN2GDkmUA>Z02-3vq-Sx^epz zT=X~f%z!@?=Z+7xLc-7h6jj2a>aVS+PjliRZUH?3|RC0(xr z`Ln-rjg#Zw*%fK|md-`H%SV{Ne7l{d=`AF@YtV!8!#Nb!G*M zC=yNHf|zy9)=r6|BNee5R&elri zk(!qk`XBzayH3K>sx)Rj+n$r<)B0*I_T*FT11Gc~IPo)9%n8}Nct;_(#o_Y|h} znapaO+^V6bQ^v_M?;}bT;>Wssz!}giv=CLDpLlwnn(^`r_GRPvlK<+IY(3)4vWhbI zT6HmzVUjx|R!$yWRW?0;az#~Y`tT~`yQ-BH;{>sY0ZrYq%~h$2300X22)dj3|IYum zYsbYL!l-8V7Mxxwb(inU*EnyjgTQv8Cf9thua50w1^bVKEW0|Fy(Y*W9?1Vb{}+vX z&WK0c{Xu@I&+qT^*X8o(lJ73`jV}L)uX^dL8qd0Vj|fl9BBi%w>`dLq&4Q2ULl_MygH^bpLeyK&=d?&HR8H7+)wB^|zCc z+&7(2$|@ywDm9pl)Omi#X3rxpfCRGEcGVn06tdoSgr_q09AQh8Pme(?H3Nc!MB?8| z(J6Eg#@tStSU}0-)O-|`5EWqx3<)`8=j>wK8Y8aTU3rn97B{_f6@bZ_>c?jrow4)w z?V)aa4xp}(s<_&Vmzkn_)KvhsexL~nL`b#FZ9IOUy)I z%>jM#op>f^qFc{y=bt;H^C#_*jT)j2)Ez!~{`SW<{4;Gm{wsI@|Kk1Zs{**uc9T*} z3L^siIr(mXk8w0BduNx3Q{gIo&@Mi@kNZMrMl~Wb5UAIgqQPfX+59%O3wxYu2qQPJ3ip^2jdx{zMm`24r?)xLk@s2~_AWNG$i@nm_`PLNWz zw!gb&5VaFk_GBz9hln=vv9q|hl?v?u*D0l~vz&&Mr=;D|z=7+Pv!rR{Kgm_4>3M`X zN=9-I{u>F*9J4+GvKawFtR9q1|ztw@3$uOV2 zSJ3=+$S}FD-#O3t`i-x=SZwuoIV$83l~#X$>hD+@fZ8qty}FklBU_PQDBwK8`@_F! zMPAbyan(-fYQ>(f?CDqalW?PUtH*F%mnvZ_0Kr|hjTv(Nj>T*9Pm0Z+2nGWDPm=px zLSJ(Z*VuU{m*R9*t4*k16-rN|vE)~klkJ}M)r6kP9C0cO;kmb56B(Nxvzgd}HJj1S zZK)}ff_t2#*5U4%y$l_fOYf6Uh3>Et5}++sA3QVNKD>&5Y@=MuK}^;oT-JYbeE5l9 ze~=pZ>IgS^KPvf~im>TOP-8sZxK%&2SVWsqOtzu)Nd=glJD=->qM-M$^*46m&W5T5qF z+v%dSKWRirn_4%siUS;gsrr4rId(s=}8+J>*()3}MN-UO@ z7AUGRcHCyMWv=-C?NO8&gWq9QSz<9&RmN^uK5C~mBOAF`u&OLlduj69E?4YUnOv-P zy2NIwOwfNhE@q-{$v?7?R5w?6zL3AWQ zRw983l8h$GMQDOsdP5h^Q|LtEis(|l%R}@X*!>K29=8WMHuX;L$<%wH?3>n*d8!SC zMr&PNBZDe>5|tP`EQrm15N}4GBS?XoN|T!ut7(#yH?}~BYAnB(dHIV#BIvZ2$u^(e z&Y5}#D}YQ$UCK#c znI?7)nQK0S$Ptm_J(gv8pdmp`;A(Y zQsQ*B9;lr8;o2V8xLdI0n1YbgrTtBnQLAE7zhwF0254+dI^xc>;=$QV;6`s29W`ha zZ5157@;H9Ve|`$n{n}T&bzwq0gFC;wQ&Osy2-Ax?L{P-jSiJ%10pU>X356)@2(b+v zbcvU}HsyzsD&wJPb<@qqvH!p!Qjo{70kNB!FR4aK<({qyD|Aj*)+L@g3lq^yW&0ji z$Z$0V`}QrAGwI5V0#d!nes8;=&P4UwPq!zkui9xt+UO#D^7L^#cnc{_b@n4ZfK%dk z)5OSl(g+|@%Pryd1z3MljJKvg76(y4JUyKA1-(1bhfz|n-$)x{%2bE!f*6E5;udr^ zoI&n^Pl7HsS8BF+_@8TopAG)98dO}vBb?NyE6^^RT84%5c`f*FSl}TDpONE#w>3oE z8)q95CAG4vw@;)kC|h^M&i$Hu4+*g-9bB5&rrQdG{xL8_MjShm z_)_P3N}_2>VQ!tSLxt1riAXvX`9O=mM1?MFfyMyV1GP$a-V>QmSsPcs{x1DE>~F`w zoxuS5{=d<_|L7}pDdr;5VvA1cn|y1p#8tEofx%^>hfdL~ z8n}V8Anv#naARK>@pYHT5|m!NtRy@c3@bA*a!@t?9~<*@exm;bmDATBPacJSOrN1n zpsxB7aj|03~%Q)*vG6k*lYX87F}&eh=?y*U&@y> z*Zx{+cCGR0V&FJRbXeh)R_*?JyFy`y7x;*p4-7Wz=@Z7QNF3b2=GY$|WU+Z=PccQ1 z(KV(5u=Ix4pVyu&YLCYrt2!*6>9$kW<##1wZ=!r{H%$f3-@_!e6N8SMSY24@R=K-R z^8-aj4H-nhnKPQak2MbQdYIiC@g|}FN1*@1y_5eUJ|xutWu+lg8u7eOD&`)hX**83 zxd|h=XzE4i;mGzrzcg`wgc9&+kD;<~Vg*)Zu{GPD&dsxlXNeII9<(kqk zbza%SzyCp}J$%a*)D^3LJgB6i{$q4%U#wN##a&t^pfu%t`9p%+m1I%%+3gaudX>S_E?Pxo4` zhCfnW!%eUkN>Hb0*1Xutl+@Z<52D!NDyx|NC!WPjrevNblLeNS8njwPNGoJO#pfJX?ZNWv$Nb%~wcN;`tSu_;S1rNFH#bQo z;Mb2s+VEGbVjuzt>-i?rn4rUQ%faQ#2EDf!Doe!VeC=;OxdTC z^J`yJ!qn$%TXfo2^YH&DfwnWzOTOg!1j$*#gJmC~>}l{Ibq}0~Ri#eIUvX?9i;uO( zO(Zz0;#*cwl4VW8U}HwidcxC|6=jTU|dy|`BK1~*^aQ%CmEAkJIx1v`w>x1Hwsl0nd?jNZQ z@R=hq!Z$M%2RPca!u zEZ`rkr)QML)7N?ph;4rgv*~NKVxuvP)eobn$agvhUhbhFy0I+utYz47O5?5OAU0iW zp1BN@*EH4|SRy}9<`z#74Kz+3F^&oS$Y;a>Z&U-7$uGOb=4^pja`s=6@?!PpApr2y zCDyQx%*5h{DIBR8o>;ul9uA1tO)q?d^GCJ)(btyN7LH8M&BBl?%U&Z8IWq%igq9-x zDb$~x`4j5zEPnZDsyF4-k}icHxUpQgtyk5y=Q*4>dJ&{ z`e8Ll_plJnM2A=QYE2K@2etH+fvfCW>}@M0Q1xA^HY_H&jbDG7qs zYxKn<#_#uRUaIku=Bvrfx)#pkbx^g&)7{`k;*H!=G?vkCf`CB%gfRZ-!`A~@7@>L} zaj`fKG!`_L^=0D|>V~NW!*Al5x<<^;gcizGgLu-yrY%=O0NIGkG)G8qMv{>x9K;Gk zRP$%RYEPXCb)*UCvw00A8QQLs_ied~U-;-voyI>uR)4oIv{Oxy0>1Z(&AOfh-34WtPvLeiG9oXw-L8`Ss1TdzCZ#^s=9FKMn9R8 za=|9180c1DW_y*Xq8dGxOLD2&LgMS6ALJ7sufQNVUGXKncg9Fsoe|_$U?1o8AVG4xZ{;c3{K<~E zGZHZ2O!Rl3g%av05qB!BIMkh<^R71M8uDC(KskZp`TjPz=rP#R%M- zrJ1^Id9+rubLP5lq*44TZ`$Fh*SKng7x(B9;w+~R-V1v;vIJieHCtopzAB|#UXHWB z8r0H`gUVFT4QjF5iD9BMTNH89MszwJaaN`K&<|GE>x03BznmRp7Q1=9?7N-=I^b_a zkYD01CEtAj>Rb<6u#qfnKaw4xNMfu2idi`*K2h6rjQEEhiYu-QN$S-gtJoEI7_uP@ zjDL_<;y&J)rhl#W=lHs>2uryeuMCGvy9aRI+wEhwNQ65G&5_>CCwE$08O&hRaN5J` zwQ|MmM?rZWCs+Im#sx&thbvLOz5E8EJ>i?8M;yc3O5ThlRwPtDkpDZAhP`|GxQ#+V zOUOmhf1&Yn%ZdC4{%3q)VJG{LJPDnFdw^tj5sC2pK6r7Q&s=V*Ks=edu@RrNFN>M? z(1gU6kqb`QcCKinx8*sUjgde z=l{e8SG~P@H;}(qumA_}S8GkpE&uR8Z;NS|NfGJQgbvAz5(xrhXRP7J_TtE65sj;4 z@^MqjXJZXz%Db`~GUB1ifVq{eo7@{8E`u*#Rxt1N#>mv3fzKzd6_RQvBJFzkXAtlp zj@w)PznCq`0#}+n>|wE?K;K&tp|^e;tAA4YtdPSKmmio12Fb3#1+FALc|f}6VMHq4 zD>1NleXN3#mC3EG$R^81#TG5AYF#yE&Mu|uegZ#+r*>oQtRCpod2>w8N0yzLhEl5c71ELIFI1pVkfT6m z;K6u#EP*dGf8N-}azYlWC?;c^dtQpI>RpM!ap6V3zVQ5-Lx{m4sf=na%5uM4JJi#s z!O1VT)tr!Q>W1Jq4ewuVb{aOu>P_}mpNVKVZDxGPYoG}Ji|=8dX%~B4fT@K2BcDx# zhBcaeGdyjVj#ao19UUdM70BRAvK9Z$e0?eTeV>>O6aEQnfpI|DGdMWNzNirYc@}5S z(}kNtt%k_CIOMr6{vOO{+aU=eWMVS3{%-rv_ANiZPXgdzet`3k22GT6xHd=9(F^`P zFT&|Jf{IAhj=;@clGPZ={2VFBVvFXPn;XWi##_wI4P)0Xw(q$1L-rk?4`jz;YFHvR zPA6q--m0;L=xW+}441hb#m(7Ob(mHDq}e8nYp57_NipVm{0!apbz3DgPsavH}&$aDa^@ z_JV+aslNYwzB)Gha|W!9zF==T{$q1*rKU@c?A%1OWp+YZ^G^;C8gF>>CjE#v*V+5! zrOBtwAbM2|#xgPIczW(;{S5h1S9*N0L6k9O&`R_}91*R7vz9#{kB#9#lhi|H&u~>B zd#hrbNNzWrq=T8GwDc^iDSfNe%LR~St0oVLr{>zL5wZyo%mQYM+kG!FII}YNzp3T! zJY00PBZIMAg3*Z#nqS*~RnHBNx1a76jz6s7z)Tp3>Rd??eo(h;U=Utv`>O59#<%_V zU31?LYWsfCfBt@W*gg(qc%MW!T>yL1c8K+1Bdc;tZxTQI6^XoXe~1=p0}QQlzB`l3 zwdu@ndAJR(@X7O^J(xEkeOwefWLd01T0!lPVsjtTQ{k#lV&j&PwW{{`%h_(c$m5!6 z`&vTT*D zPQ+;g=!ruWq0Hoyf|u-*Lzh_!-nau2KOr|V*cYgjM|U>G}y1A~)GQRw#?5c|n85)N4YNo>3-j$S~;w6iL# zW}Srf0ga~*?oTfU9C8r|*yq9nS>&(CCt>ixTm~a+&*Gh5y>n7|&sXnMP<@%QzUt0} zIq{}1iI})1xxADL_Kh$8TQHjOFFw@WtW95aB{#O{t6#L<3gc<|2zOr8lRtWzBY{J{ z@?Y(Dq9QV9`dk|y@=E3m)w91;{d?M~r(nF#5H2Ug8u97!-L9{6r3ZyPHm__`ryG5b z59yOj;2B8%qONdFQlMm_d)^sNm{NwrYAALM)L@S#?s6U}_S`v)7i5V3i(>8_eQY#r zb>>^0g)Z}Q2n1iFKK)+jTkL#jY_`JRdq9ITq62nxMs(3v;t&@{mYh#<^!wd)U>%8! zd!jku%uNS5WOHA{7jI!)B;<{B@JB3?(QU}5@ywKf1ibvx+H=YiP|gL@K=7Hj>0I#_ zuUkybK?(xg3!MsK$6s@&S%-DN6kW`c3uxT)_lt zRSZVwEeH|+n3f-;wPIZ{^gis)V^-2#zWZTV>ki|82;dvSIJOJ1=t8U*nldK;3%5 zlw((n?A3oduix715MK8zWnXivU4r%HG4VmGz-6}q@h|Ki+a844@rQK{k?vJ|QT)^2 zcnYw2?D}9SXzsUzeM@`(ICZxGzxnRp9(k<3hCKN1Hal7lBL4&bZ~Oki?Y>|7J-$C6 zXy4@V;c6LK1Mx>=%F}CZcVhSW$!cJkeCo~(Yc`Rm<uJ5Tsg9ynt}+y6u*3$=9mCLytPX`2OwIw!TeJuO_M9>AH9*LC;-Z znuqJ|RZNKUpT9j%>Ot($n7_d9aI97Nl3pgkK~32>y{c?$Y<8{Y6jgy6-6(b+YK{n& zWOix2-OA7DQy0br`sh#HZV?HptlIri>bOjF(YTP?^@k$dmLMN-Mh&rdsFqrDx(=-+ zs8}W`PW7;z+uFL0MSU++pjr%p7^c0KDeXiDyBHo7b0Up%2nIjwZ$Z_iZm6_~R|~ZL z^=EI6RRZ6PT>ho^fne=~qZ%?06j%Q$auF97{#~0ZIk1uk?LiWL-xYULH~Op+_neMx zW}+8{gY4x0uda_16&5=zVaoqUF28?}&jwmL?jfsOYMT|Q%%Nzj0AEkV&A-z0Ss8ui zO-ZEUkkB9L?nWVbAy40VxLNJHhk=UW~a|2e!TN^xWGn$tIUq_Pa z@Yaq$B5&r_7as&*IzzNSK1QRNMRH2xn8?aRDTJec^rP#V#)t(~UKx$(@%mxYRz&;$ z6Q@5=wCkbX%iitrw@yl7RhVr})IijF8_XwCuU@NCv)8J6`Y{2s{)~STB>=;2 zL%EjK3{rLnZE-w}bs-gP*u?fuW3Qmn$?`upgW#H?s`PKYuD75Ze!L=j2!F9p7R>nv zsw7wfV_KB7XGqPAM0AtgX}2a<|Ct9NF5@wXq^RuAWou_{1S$KegKq-A@PeZ%DSBdx z>6ItLT%PHl9_Q%PmbWR2|IJm$MX(0PZ~GeOxuHx{&M&hgF8JaBq8Oa|LDx2Sv*<)?M?D;{X;%wxr(zD z(p$RdAG~?}g!V^5JsxtcYu$rm^%T94Y!vH!@3tKdO=Y5eMx_uW(X&>lb+`mr7xPFr zuGPmNlR2B+V9%#xeBao-6VJHps+ZK*M_s(+p0CBH_QSt=A!f4jPybG4?E#7MW_uV! zxtbwRO{VB#ep=V2qeK27wL#4QWag_tg3+T!V!DCr*T{5H50!ecrk^wgxl9n5G(0brM+&`3msAo6oaovByci;U}vz3h{mCuq?-q_*ts zUhYhB@$`Vfrsm^Tf(`I!k=#S7;eqbow9YN~GmoeyFUn>gXBwfbirz^|`=zb{c#19C(H)Uc42-P46C+hx}fpXYq;b7 zD)t=FZ}#Jx>A7#(f9V?yz9;I}RMw2yQbg%7o_=Z-z{ZnLKcq8-wS@bUenz5RPc80Vu={fh3#vzzxTa)Dr;3AQlg0bn-mu+=-z1P*E z4y_!y%oO$U^i7NPxexnwjjF0jUdEL>L({(%P!{{^Mm?by=05PmQwwPT{+}llFGfj`I%^_*i(yBMt4=skT(D}1 zV4P{s#RZF9K`g2R8i5X~CwHzs<^CgUl)H3h=}VV-*JiSh4rWPmPT~vXF>57RK1^R2 z{jr=OtsyMpNL_6o`aoe{Lw2T$eD-68a!Ze3C^^g^II*JK&tFD*z?Xzl`{Lj*JM9tH zt~Uz>Q@rf;DQAea1HxvY2|d7%o=Jz!oYT2OH*ORbS(zWU4lRBsU`_I8&vnSV614T{ zT>A*y<;*v>x`yzR8GJJGjjdjNn0lePwv#v((Dwv_YV@O58(3Wv(~sckNn7Qo=ks{G zf5c4E(BK~{c>INbtmbhnk5$R18a1G?1_FyiK1d_~EtDCt&J0~+J#p3UB$t`y=c%MB zozl=&e>BQ~o^81fKj&DpL#k9*Lp0)*}}^W7Z2 z55g(NQWV$QFi#Z za3r~byAvi@!ZE)fVW1Mqe8Pr5lOXxYmH32T%psvz34MLS@LWQ7pYYfkO6;c+pa0A% z-7-7;Spjf{HD1tAsY8MQpqZ-)!AOH@%VJqg&VoiYY@7Vo3kT2xm z8q~!0!=DYVupn;cbV&eB>SfW>vHOvzCii>K7WFp>F1&P*@OuO6xrv-^XV!by-T7Dc z&)a+$kE73L{YPQX`X3Z6@$+k=&;QXgCOPb(7n6aLkgL{oj>UG9^yZXwi&;&Owl91W8F(_*&NSZY|TzZewTQ?9|{z%=RZ1a zN5z|wtI`G2`7~bkaqVCMGxQOFF>=2w%AwttFp+lHcJwx{z!34Aj*XgZC1l!r-qGF&jpS{^>x|6;s0|Drv!0=KFONGhf)^dOthGE zci=v%z!C~#B*f=n`!4wAUY;^VudHPoKSwV2ndow!p|5SNc4b%G4s>u!;j^2Jll)~k z2)517t!G1ELQlRs^eNTNQ}f-S)N1@;Mu6L56~lLk+ApAXlaEJW;0Ayi0l*~dhj2B? zp7DSkx-3hyNL3w2Cm<1qIoOl1ifSWJ4Df+`Wl;>gVioU9#cs3*y4cnqL3YEFA!Iwc zAO6CQ@Bz->UH}n*!+J8XdA>kHsYy(dQY{}q!~X&6=`|wb2En65ZUF@@AhgdYum0go zGVNKYtvJvYxt&8ug8Ox`-^OOQ^Up6v57I?CkD^;>H$80W-{wU!N0er!;;*qKp6>Gr zD_-qC!AT)Tqn@q(1bs+m~MlnbT&VD9@jXzsK<>j~sREkB={pm+dYe(Ux7>l7^!HaN1fBn3O_TPH`0h6Jh z7)EnFHQx2b*Vw2Z9h@L#W%Shdu8GLil5)%F3v9IDQ&1P5ljqKcl5yx7ojbz zCF+{cut3R|zX-t%`vweVqQ5yDEe-Px)tS3vu1LSLa0%rUAZ-3qD?zx?ww<})Hs4ttIySNxzr0s2lhqh~xcjfG52M*r8 z1{$4?u3_|Z;PMyj;shgGZyn-W`<3f5CEx zdl~+nj{w?1`9S(}M#dfchi_UJM=HqJPy@KB=qXDzj|ZNrpD20)rH!?;=t=w}$~UZ5 zTe_(A@<&aUkEDw>K{Zm*nTrEg&?jh#z(w$Zn!(eP%X{eBYNlK@kjxu@992H+?z>C_ zZ%TB^#8Wpa9y~v5`AL>P{=6Dtir%=4clMvJw&VY^m6k606^*vljRRG5SWx%apzgTV z0M&i7uX};j{Zp$Oj`-Uw?|%KC5!QbqLdN{ zg07Td9st9e*MezNVf_4IFg@!jJh{$arOo{HO)~dKVk6fMdX1?OYk2X>omWKj-?=7| zms;Dhb2|F%D#mpl&AMLqfeUy}!(2WvhW+?k0CB^YT4l;FJO?Fd?NCNw98Vh6WO<5- z=x_I}AkC#QBePxt&ooA!Av}OoKJEEa^Z>Po@aZ?I#6CSK_vyR(v^w~7W%R|MNZXM? zy7vhynn~cRPN#`X1)A!Cqwb*h>7pa`Q??WRtrh2s@hmN$+^#AqY~v&JB|oAFt*j+SyM&1+ ztQ^@TUq+;4d72qPfXuP!UWG1;@p^1(=P{Xr>t8r2a#E^S7eFy4+B}xos!u1$(e(J{ zqj~lIQ5=tKSS6cLx}Z)CBc&joRJPkg?)j7B@GqSP&87-|N|9uFUu#o}@uPWnWi*>R zhaEjowP@WNI7CmG<64CbwrU~7ufdUQyn1yp{VL{R;-5lE|9oEK)vHVMaM@#$c$H)& zU;G)Se&h~3o4ugv<+BEG5lWg!S-;;z%Lhj9ZYCK{K>_0)uxci(DN)QLX2+waRwmbvP&Py$~?rn}RBQvVvMy)}dnpDICG z_xCja9P|cqu*o;0+h8l`D%dioBxcNF^&TsbDI6J zRsPYV>~bFLAYuFdk7wEjZNPchyGtI4>m&}McD(Gcnt`z3%*~S!R86V5q!@_fsTaiG zZwG89a`aTe@VAe}=yjT-VfD;i1PxU+ZlZKckt;O-n#M=&)P7>SUa-B01O!{__gQa{ zISeM3D8KRndLV(CP)sc&`0%MsNatmk5V_}B)rEN`R92vWimUnI)_hlma6o^er1Y>= zuv+Qw<<7PkTxHG(mx2=NoqdKa1)~4?Q~YXBB90AaJFW(QgfW_?%T@#TJT~gwW*}G$ z#MIjsgJNng32Pq-a3g~Hi^KXmtO#Sm`fWvUzX|KlEe6nHX?sJa`_;pO*F=bs1fX zkegL1yeWXl@)rj1v|Qh*X?wN#H&pE-9xYZ|$?~6ABOFI+RCVr5Yk_4wp;!IORbPSq zC0GBW-&KEX_PK5IuiB(L&Oc=3^icPfPET}FjwipuCA*jP1UF-r1J(t`K2iQg(>2go zcO0-=TMAv1qV(X-*RpMSw{)o9g zlIigD!}5>HHf)*Nv-SCuy|l!#{*YHZ*7R_M-1Nf{z{*@nJPC^fc2SmV+jkgILQ^E3 zp0$cTs`Uw4S0=ebunfD^Cwq#n=v>=()n$Ixveuw-Ykyz^Hjq0uQsQ2G$=LAIZ@_Tv z*hu9+Jinaa9{amxJ$EiyChF}MWR;+w@_hOw-OOs%xt>8@sh597kna|~!k=|CkQD+U z42_*Xkkk=~u^xyqArSCSwXKibP!GlE5DH)a{2;%?t$WR&JpKIul0g0n@=M)9^4&p# zZc2zev6}q@slCRqrtz$=FJSp$uFuVJ9*~SrUdlJ2(L{lJtWpu-9*F;z{ zu4-#>1u3)h+&wtFBc3k|t9uM>e23Ot10}-TTRP{$ljQ0Arf&9W?%%f7e)s%DI~exg zua8{YmrJ$-Dw0{So; zitK+zzap>HGPibveZHx!0Q^bxOFmBR?jiDB3l|Nz?lffPPgXe9-JYOXyK=Lt5dWNY zR_Vlzv})7peSx8mJbj++p_=ql@@;Od3Gxel{x%4fHKzt|J3qhf5AsoO2>y*C=raV= zrL<(=6n`f;?%!*zwhvwppke+7)fKySzWeXVkyDWP`bUJ|xJx}GpM{Y4{Qe<0?i4}t z9GG$c@~xyxI1+sXHMuQu6pxqs)WQE^bR_2o@T*m!!=2*WA2*Zs+s0=psbp(>N?$eL zE7}S$KJ$IP#;1^cccK8eh^90?CI5YVHojn$u9BQ-<8wj?kcV%nZ*=YW04wf*AU_zN zvtPFFUwVgp&;Nq_V0=c9?-nsMZXGSz_>_G2_>A??j0vHE|EYZtP~wJqNJfW{c=+ZA z`Gv+`p_J3#4IuIPGlKknZXsOH9VAGO_pQu4it#y0<8#LGA^#KmGm-u6`vUgI>Qg8+ zS99;Lb5eI3C-D652`UNX<3egEp@xH4E{|b-+tzK`aHjjSa>`?}AJlQObHa*kS#OIG z6NG`odcfHzV?mm~Bc3<>_L&LQ3=*vOLuSH9YMJRT`+NMqelfjfspkBf&p#;0-=$G~wPUK4x#?Ov02)=B8>PSG(4l8kbNDLqpV& z+H;^QK>OTbC5fkx7#y!#q0`E$y2Q1hK?b%MMn@*$9(9IkNZ`+%mpXUf z_BB`=e}O49eQKgx3m*Zd$#oLGI~7E-4^){@tD63Gr&ZfB_z$BH>m@t7ARwJvY8ti;nw#gS}05I~;Q_5W`zzP~yBkXxcr7P;Od%}&-dfE>f4}Y;^nZW#TiuCtL+Se0vQO5n z!Gh9>KteS53Yq)k*dh483}_*OiiX=gg!!t|m*fV{X6)|*;^H`C&ntFGFBHv}y%NSz zR{+w5#6M_8cNQuSU}Ls_3FG_pBVbT#!1HaqPfwoz z&7`S-6BMV9?In8b7nm^%-DRtdgRLrugPC>DNhDy3vw|Rh_*HRFsZou8tqF3&^+T*{ z>a+Zr=j$2%GwLB~Ou)b9SHi#C4R@jznY05gW&JxN+sY+bjnfq@9+H=4hS#m zvpc6p`(_&(HTXV6!w~uJ8vkW_-FX3P#IfYL!)S=D;gUo3GHOM8u8F+d$2|-P>Q%lL z42jEqT4n|Koe;LK*>+6bml6bPk20q3PvaTS_jhZhnieyoBaf>LtZkk~F?Rhk^&4y6 z%mFp*iGYP)g#ERmJtWNiKCYxaBv3`4=BYctj2}nC&y)bZe#vb+)t=6js6BZ_LI~k3 zMw5IdB2RbY58y2E;4BAeOx-$>h@3%*<@4+km2)4k;q&sp(M%XC223WF20%M^%yuBx z-q8+u2J-nHWKUoJr0M|13f#x5V~f^`!w;8U>3ObHBF@X|p{-AO`J=Cl18h@m{l}is zJC?kj?}ctt6%t>3AL$9kOMTjnSZBA$$pil{@j!X~%-gJ(F>{GI(2{N8@b7w9Lc$W-RO=e9lrKJ2L5Z%~%m zQMcwWex8lbVL{)C26k+|tAainqsOU|)WDJUQ!vVY%18T}@xF6OplNB^fqwyd3QS@4 zR}l{t6(>`K5r*2ZzyU_FRuQ@+j{~U#)Wd$(!;^pCsfU3lw{|9aM8zRg>R+<_ltrM^ z?q|vxK2L>v>3Stwt5znIrhg!{*DZ|^I|6_&Bv60MYHXt~=Mfb5qWxIc*?OZjc~%LNQfWBuTV`0?SEEXaW!Z(A~mM0fXB zt>`m<`@deFw2`fS)Ll9eO%PJ=1sdXsijS!8-B}lV1<}Md1yQfeNv)~5rY=H7WSS-| z_;Vvt5zQ4fWiCZUWXhuN*zsyMCzq&bBzDb@;7&58Hu7dV*Y{Sj0H3>2hNZJHx^!4H z(*+;=Nt3b<(h@8rRdB;<+@(Ae%!DLwvwOM=?t?T5(5NaEx1NYoTEtf#+YJ~=;R23y zN+}9>Mm6!&yyAT$k=BCa`94uz^QSh<^mIS@d7vW`W+sVHD{$p{vr+oVM}teFqObER zBhCcu>O1L}Woj$y;~3f1wY?aV?)7|S^0IEkn8JCP4_DecQTe#w**q$?@RV*yz|V|g zp};tTmzQq0N~k15Qbc8(N#`1e4^aB)hAQP$wpR9WBe1S?z)w6aaU}RQRp)zkDG1dR z8s|I9jG_k~bcto=TsFbO(p&-O2E5?yFuef+SEzdZ;A-@PtI@{-cl*I_w86J1@R>6i z{F^nl?4Ne5@W{F(cAf3v27je32>G1ASXp61<<8n+LHaTsGlTElbt~07K6U>_FT{dY z`y`sef|(?P$-&IG8&*J2lm78_E8h*qC+C_4Kxg}}ZES2h!7;$(a0D{xN^!FrLJ;`t zZ89Xd*nmKElO%UAZ-Tp86rj=?Z%if2YDctZ1d;|UL>Tt7kFnD)^1MPUX1K_N zzOxy@y19UY(st`msM~xLE5J&_Ims*rUydEJZfxEvxgC^kzM>owUye(v#zd6fwbHJW zsEUnxc1&j975_dt!sFk^vJZP4+fD7Cmy}QmR?bf!J2}#F4-J6pF{$OvavgSe-L1Un zlYhM?vUI_0%<b5yteSN+!ni$qZuhMIRGnFFF1bD6h2WrdmFy)e}Nq9UV$77_9s1Ew1+CBb%@ z-T4Ak{|NG7>e=|pCYVI4%c6^JS)lqSX@CdX{%ii)?dBK!3Evcu1`jsY`)qv3dYwn_ zpPOHrPG_!%ue+s>(T*Y)owb2}Jjh$3{FQs#xO3Dk!MY+2b+*t{;odi9t;2!yJi~f% z>du*CTT^ub$1>?w%T=9mtnU{g+x3B}G_lbA+xo_RUa9}6(G@#lU7x`0$wYU$0qSI0 zaK7S*Pf;SCBS6&gqLEkjOJ5Ku2s40$bH*A#&xC|+a(f`A64ABrvH5o};x;!y-K zGLHq?WBWPNd?E_PT%8ERB$sycsq>?sUw^0T!TbWqldw8-cVL1!m5<6 z&}05orAAknWX{8I_tM}hbL5Pm1oplo?fF}5mEw!1n@QL9lR!pb@&>YqED2~BUk;k|h+dm-&sux}s6 zfV$cn*uNGs33k-~w)iTE@)4OvHYt4*<+tC>JjXx0*NW(kJm$H{1v>QWo*iWJAX|Wd ze^K*)jjuAfjeix}J}Fbwl`g^`a3hG-Z(^hvO(r_1GWvJ#RNx*(zMC;J&u^_(R#vE^ zLVqD4e$Bo<%zLfpxgT=}O|txG@g~{0DMHMTu%tWc5p4~ykXFQ1h1-9fZWzf#_j;Ns zd+R#CBo(s2?J|YaR6XLEx#L7T>E5DGoTCoaTiNp3_u}cSa+2jQ-A79b&fj+?f9+q{n(PmI3FiMKIYK6= zLrqtUSleBn63FDB+}z(zg<@q#hHNK_o?dtYuuov&NtQoD4@BRwh9z*PbacZV^CGRQ zQqez>j{nC!B2=!`@?vlcHzq{qs?QHTBnInK?N;UEAgY2($f88y75XXaZ9iDvhi)PM zM%Q@jig?*8SL_*2|7bJ8gKIvj@8QF!kDN2--odPRZ@4dR6V*j00$xiuyYQ05^cd-0 zgu9^|QM}xuqM>Q<@9NQn+~Im|%-~k@^{oXTQGuAxgrOT-7E6MCg9M67f?bb`q5IQ| z8k_44e>#rO44f$U;esE}+!{k)E4SxDIiCrMUJ$TjFeF0#+}6#J_OT7?JDSK!yKupAn-jXsXZ|H zlscGK+qWvU%r-W}z}-ADw(unFYL>Tf|MW6aM&SZokb4w;>i(efS-oTRr^7wdkNG9r z`ykj$dmn_yY{h;|3-HLy8LiooshjkS-$1OPh|j}Qd$IZ+yj86nZ9#OKzmkZEfH2Xk zLsDA_l+RY`_F!Y%&hugC+{U*3)~5ZwR$H4}tSdzGJqZsnL*?y0 z;dj5L#NH~AB_S&c&36~Fs}*(UH!tmYp1CuF@$!WX6ajy+7-qS>eWwZN6|o4uMKkG{ zuBy?*v#w5AOjkdI_oWLalE)r4HSlLVXag(p^K7BwPk#x7>QR&q#us)(Z&|PXU-!!l zqQHfrDB$5^Jq+Pv&TtY$I)n+v*Qk0NOO1QvZLi{NZ$%V~^y_(Y$tt>NERC<-dvq9| z)!za|q-K!8|Hxy&cZl)sf@!1=U1sn#S8CR0qSqI5>(4cxY3QfJDkHT>e=wSCOM$!W z0pXe#5dgr!bWNKs@o=KqZ{ZL15?hW~Ot)Iy#0jFqp{mBtx3Q?{_8^nzd%F{;F6V=m z*D`c*q=K%WsPBURpURs5-&y$o-EZ`1C+1Qol!^ltW9Hyt zz7V5XM@;NDYGdxelwJ)MD|2dT+U9F!N^78y;>N5Uo$m!nFWkvMoWMYc^d!B<8CB{k z(MXjbO2_Kg(ONd0(h_a>g(udQ`!eZyk}ZNcO5dY9T{ zFJ$LAJf1?8eNn2j&_F#b=(e*@84T(X>u2)-Ml@M|!GZwhf)R_LquChGbMBbY5|WI@ zPX04_2f#m??`N%7n{+AM#<)xEz=G0p3S0CW9M9QaDrlRlh`DSko7!2(QKJZQEgl22Le*_#DZ7-Z0b@&q>{^VQIX% zpJpB?=Tokd(G|Un%t4*a)w(6GTEjeC(qXkrkM`o%@D+(&4bsPFcWTPHbEL9C$;0@u zJ}A`c>XreC@~3YR`S{lYcgLx0i&LnsOm~#C2rzSov)Pf)shua3_{90nf1;OuT(cX? z+Rcw3<;I%q{^V-bXMoq|tf1U)WS`H~=K{LaE#(}u2?TBG;eyQQ*3>MmjM*TqaW06$CA2s#OyVYWXJn4X<_P6nkn?oNKfy_(is^o=8!cKsEtf zL{otrIp6z+=6K>Z&52$bwqlJ~zZPU#d&a@~dbOp*T<5VMSif* zD9;4jzjVjtW}SEg(LS zaLvzbF1rf?E!6NfEmY6eH7Qd`F()`cht{7tG0)~iC&B8wgen2lI`=bMLTo&+|1G(h zsuJbT+z>1s1uyc%9@8I_{2weluHSOcQYzdbKxLe~fpjmwoV`MsRJ>xAAr2Ni-IhBE z5EYz1$MHJretbkHEde~z5aQ0pEza>?6jj9nBj4+;_#STDPwd$3#0kibE!slejwsqa2J~T46j~?LO-3q}eoX7T&Z~0%{X6qd6wjw}TVmTGE_e+3mk)pKt(ro>@4e0g zjy`k(eF@i&ffYU-tx2Y6EuG^ua8N|z)AfOn+}2K5zvf{->nrh-X-6c{4|&Nd_tOQX z%v;x5t5*Bupmt-%Z54KU^8EK4Kny8C)4si0AFALM9y^IkC`@MnOKS{=b;hxrM?(XS9TB1B(g==01BMw3L#gWZf#I&Loh*1^BG|vR$%4(7cI4cC zp#1o>(+`&>%KJ`7ii_1Z02vHK=YE;{CA=|}${#L5$s4P`L2v1N3=;`G!6~2?3H+IY z`>vpEiMN1RF64}RMP&;vD(}!(DLI0Dl$O&2+QZnVsf|=(~iq zb$>D9YNL<^m_S_rC4MOJIpZU7SiFR&LZdc>`yn>Q8jhfL*0+VX(DR06vHF96rgQ1^ zu(PNQbH$dLz63856~t5Jqe*Kmi1U{WHC$SAwuhkxMVL8`b0`RE@0r*H*uQJd^$}tMM~rioX94^Q!2+6|AMwm@MV*{Bx2b{S!BGo6@s{M4x8O?k|FphUobyb&v5|_>i?8PI zm~dcHR3LQC~efB3A^nZ|Cl_U@jKkXhiJMHf8%9py*~gfY5M^0l;~IC=p;d8!NWSQ!sw*g!Sr!&-NGXMSW7s-0a_5UhTw?I}Ibx72ZlJg99K~cGC#~BBWKQuO%Ih))td3 z1&y-%xoN(s3+{ybF|8x+z1w|F>^#rbVg^KbO)9lxnL_mYV$e+K!O?`(~@{gF6C9g7)>1TeraS-rF~T#MeI}1jk+K zA^9wX#OL=9!EvVulIOsY`94e1XRgZWTZm7P=yBS|h1)kSJYNER&&>?f`BiMvm=4Zbg63rn$-xEmF^XP$QMAwrJanV}jW zP<|M*v6~+uLCRV;goLbn=2C57BL6Kut{*>Lcpj|J=vGG#j2;v-6BQw87A@6o?E-~(~Rdk;=;_;QU?o}TDR?J$cAKigmw_<@b zsj11FZNc$Eex-pO4lf&HSPQiUX&qgdj!pxo!TMKLmrvi}f7cx!RG%pSNgXRxZ4W6} zvnW){e&`jdcnoc-ay9oaDratpI@#sUW!lDxQ7f32mUV!WqX)mG` zkzgWPJayY(HG%v>X!`oW;u7wo71+Yqp)~xEFiNUasqwTgnJmBOD$&$|O3)%DaRR$F zYBG1^y95!{haV#X6LK#6Ml~0!C_W|nBt5zC7h8&M>cw?O!ThiL_O$VbacMFhE)p?s zlZh!-54HPEcscKG@dMIn%`@wh?(RE+O?C}$Fi5~%jYC9w-U5A}DmsT`34jWc^<#a& zzt)1EC>8hSI3SpO@!ri;+hh!*-ck+t{RKR|ZVz$Tlk~7Vt|ZRMd%cq1_NqNs@>zje z%nVDD+*x%(jIQ*so@1^-K1ROXBC+U595%umOXE-Yk={`|R#gkOm>{Tfdf0itQkS+& zot7T9|E~#*y=7_-6GB@KPY?S62_w_d5x_7i)l}KEb+5`M_k&S+t9a}(s$p5B$-1Lr zCpC>MTTv0ac7>+pA&gp-N(25;toW~2@37Mb3|(oBpxH_vseT+CPaQEhXSsy_=3|TM z#AW|uWwW&5kkB_s#IXS+4z*yM4=Y_~bTtA>Zs~>tdv+8jcI&UqXWV?J_j31t=?Pww z2Kz4_6Kq*Ga|W0I62di9xKT|c%TK;Z)IY^W{4;Dc?h=^#;skZOedXXl`wK*zOofL? z6orU0rk)tQj34{#Nqu&+30+tF!Yn}zqm5AhLpRgI8fW_Wk)Ujs^srZWYuHi|yJ>~! zL4z;^w8p7iIPGg)BZm9&Bvj5RRmtmDwB(zASWvzi1w!dib+vx*W&wHI;H?5uTaSS; zzMBKDzuvMWayDF#tn^=o)$^UiVq0r#0-`ET4=bRyye*Jbgolyof`80_x`s4WmVI0i z`@Ja0Ye$0*YxmCv`V~JybmKWJM4KyPO{LkPTX=2am0qz6aJ$5SN+a|>c0;2-;i5o8 zuHkI{LR*W5R?ef)7qKVX_3g@S(YfPN&0of+c8~P1|CvnCu3_`}8_vF+ zptz_F99^g-YGezZ649~Ozzrw1{Ff=E(BQtu#vg=(?%C$w?+js%dCZUTLjhqH+V9na z`{_4b@bA+-CrkL(_k!1mfBk3hswI`en}XMI{`EC`mGgYM;N{?Xx>5P7*Foi{{y|&Q zyRK(}z=9;&S4A?^g45vMMXDmZVwQ6Aat5E9$hPwfcGe)nTM*~+09&oYi!XYTEm5YD$*B&vT@PP_XV4@e~pF4G_1LyGrHGvKBc2L-hjA zMidDAh(0mc59OnSHHKp#3k{xomx*HYL!9y`cgA@l+kj@m=@y#G&Y_hy%$>&DoSw}O zexdM~73?2+2T;A!P3?a-9G*(Jo=HB0({%<+6VS~s)Mp{WK$YfUz2z}Srr9}_lJv08 z>}gt5@D{;_Gv&XW2dU0EiV0*#%)2u~JTHsY{}See@^aY8DnfXvIo-pJaIB#cUY}D? zS3pvGkszKxY(hV>h=H{%Lr>T+XWgya8Bfzv0JMXcmfp?MQrdr_(?&!7NtH|KAF9hS z+gf&##bTumda``ebT|eY&21ct!++pFJAYFlQrbj$7>wg5>-OHhU2H!A-|>9;616(V ztcm08u_pvmr|N44#**e()G{Ux$4sHN~j0jhdpoK}|o?UN9iP z=2Ll*c7)?w%V?3n%l;O+l1AbKEpKEiB_Rf}rRG_|-#memu(S|Y?7~OJQ(hX*5?@l zxxg+%G^fTJ#}nlT)r1Jv3ESAgLa>YvjKFZ< z65>8P6QD(eti1m#x_98;7Q)j3aRPP{?RXh@&`cqzey|8w$V$*p&B;c7 z;jUSJjK?fV!(*;DHpH1v6^5JC>#(;PQGFV{1jXG+;!lj8Ui|tMYp82i&}DEx`_8er zo`%|3&s^R#79PM({qWS91wQ5k^C#Hi8}_kW zhQaeESs(LT4%L!;K)PtlC9Ksi))a&OqF1ogi1T#MaxCh~0=H!!b;>W9?!G{yFr5x$ zn=kkXm2^UA{P;2u0%C3!VxX6sNff;-;1_zimmi~-6qUOR7I-$ZW|Omxgl5=!{S(NkxO2D=tZ3<_%*?=_kz?wB+CAyWpd{z7UH?tm zECg%+H=i;ND`$mVC!QXSuF{iWqP*faA+4?^816p%ckz0MU_}*~iuYG*NJ@DzPL%r6 zUH+&i*y`L;s$7k>K7rxia-=6%CI4Ru_B%L`wa{KvaDN<+I{RPTDH7<&y#8|?NDuU% z#fV5ZVi}Co7I;gFMNw$kSye$Vaw|&D69Y}(qQw}?lN1N(CAKpEv-a(>^|dp!X`7lZ z=yov_zq+O%U2ujy#cpas1YM2za|&CaHM9NxZgtIZ2=6Zq0!yeC6`rl1X3Qb1)M$fA zaU1ge-0Btbj~-MfM)m)(_Ac;I7T5oO5?BqFxIq()0va@G;-v-^CBl75wC)ZE3eZ7A)*M6@5NVR{IRr@+` z64L$-*HM0CXSsZc#y299a@lg%a6)EZy1)s)31eArL>8WU!=ESK&~L(=>daMk;0V|tO5``PDr1}A?E4OcsVkbt# zP%-$k39O8-QTUel$_RcYruQdE`v|3^OGZfN_iO-~E)e=_RWolb>T6ri87ywH=LFaX z))d*EQATfESjD=cs0!9uT*c}CldIxOhsJl(!on)>UQ`9*IS+Y8vChi>behwazGev{|LLJ@ZlW!Q$Aza4 zx6@GmJ%o9F-r|)0F;ezcxba%8_Gm}l=}|xQJSi&UuT-`qL+BT)@v1&OOkQG|h`Bh? z_2HpDimG2USBCFLKivf_RTbOuM_WymmK5qWMj;bFS3ei^!}u>TReD);6ewm-x?eih z^|gmuZL^jC!n*yjyE_<-K(Ph_y+E0N67=k zp#KG^wq@*jF{Ki6@gen~alFMcLr0_&TnlGq3-!ONNuytNf{A3RPvz zwZ~IY^Dw`0agzcPHC9-^Ut9#zT@2!C-;j$Mx^h4>*hVSD9p%I_|GjLR_km#U7k`B= za6q`)Xx~Wc^SG4nGM?s{bLCfanK@q{Kj#DesD9n{*mI0CZPjGA9i**e`{%}g=lwCe z!67tO3|NN#xT}}Akn@$VPZ{dPm$$TqqJGzvUfGK9^k>y6iJtck^}9ihtHulZrp*zy=EWsi#{u3n=`c{c_Dd{#66gAYJqpzW5Z`FN} z{F9x`Ut}-Fob|w0bcGo=!FFXWoeW#F(LYi2#D_K469j5fJNS)6SpCCDB2$&h1;-Xs zg2jr%h{z^a3@d1&E1HL_0_$a3E;_U9OwV6I=(#lC_hcf2i(1loF8(nyJ#Y<3nn)nu77_F zR)hJi*v}a?M!Mlf`Y(g|Dcp!{CkXL#GSCtOs@Kw1h?PL1nP5VXyhgIxvbsKg&f(Xh zh0Mw4cS1MIYUy9D9!ZAmhcx9=Rg}cPu59!;{m=cj?_R*3K+{?j{l<+_K-de3!I;pC z{~ENU=DD^1Zih;;l9#DB!8LKF&uu}8&tqF-5)Z00I}$lDVQYF+;dOh3cckce!}5L9 zO%k1&x#5-Bp=Bqc(}##oaH^+Z~vGKiO_R*(#YS^$PTEGzbZnjshql2d_b?l`BDTeJaE+#2d3;KA{Vm2?1YB|m0Y^g(=1~Hg z%o%`@yuYJesW(TT9DGU9=R_~YCBAHdx+{C?%a@Jr5Ib|t@A^`_)8Wh%eL_FQ>Yh=a zpNo`oG!RWxPt>wN@*kX|BnY=QDT8>F79F@>x}4bf%1&$Lzy8_@sl}Qa(GXRsKu+Z& zp6=38TT(;v*NVKTW5@R!54`-4Ltxei*wh+^f|Kx z&v)KJq1+>_y|}i&hAWm6^zTi+H>2$d-pN~JNpuz=CUmbO(Lqhjy%i#ov*pMJw8-hl z9A)MYDtdv`ie?(0JBJ{=SHuTCq`-K;hk0b?KgzGIwv=isNa6_00b~C;y=f$~~ zN!G#mJbx~)9NM=X0iT^*RMQT;qM9kAB?^?P6Gk+#ds-!)uo`~uKR<_Zg##kDIfpKT zR8>2xW-OzpDq4SPL5-F_`0#w2%Od6wmV8tiZM2)=Md*;|U;Y#SGMh7P8qJeGC!eLq_a@Q@S5jhq`5>F~U^|!MZw=6b%=5|2 z$*ODM`jGKn6q=t$CXFG+11qgrb10W9=nxEW`>~m_k%M{d_c^cap?~sgYaOFnD+3-; z(DqBF9~(YQ;U%eXol%wh+3sfBXX1fY2(q)CbDkyqhNt}xnPq`;xOq;!$pv-4lSfVQ#$GQQ5t zoXs}6Fi&OK0m)iH!mNmP7Tc1GQ}T~=fI%5GA^^9@6}zo3zZv-^wMTHMiS|}Y#WOX@ zXc|b(FbMq5iMGV0P^oUKJ%(+6_D7&Bmk|7rMp-pmh*No*pV!y+3(tGrnlSqdjU5b2 zkwQmv2HWOaL{Q+__u^lOj96HzM{9)eLH^uQ=El^mCH8~km3BR%@_2nOr zOm%|x5nA)W4c$~K>81o*PYaoo&zhmn2XA(r;0g7G!ugF#QK}Y=dYLNm zZ)Ne#?9-uQ`ett^-{j@ffo7rl!@2+}NtoSCS0EC6X1!QL?A4kSYdz`0fJED_6RA7? z*#d|GeL{FuMK$&1tFHnh*askoqR==3ZZ+IIdzkR@jt=wDI!=5Lh#Q^fq$+Rt#NOnw z2mhPrTPoFPg~FLom(`w(*UdwbcwiFFnC`X0tc+wYI^G7^20TxYE!GjF!mRu#t5bRw zrBpzZ9Kv%nxf)NI|HmW0ooRBlXz~(AldE~XPc&)S(x1k|mQI^)nJ_(Cvo{OeLhRSE zz`rQYvB2fLwuj!}*Oob&7qxHjEb-o~5n7XkOb!Fo6kC%5`9HQs(qOpLeK-v4wB>Li z^gZ}{;D?tq!GS%dz!&JjY5oB#Xh6YjUGIHPzK22c}I0QSva3y=Bzt+uq^O$eZ2`~}4gGWXTmxL@uJAaV8YRw#uQngI@y z7gCV8`1L`2vFRm9?)g4HzjC$oJ&RiG^?ma`mP0fMHyb+5H5YJQh04SqG@oq+`|$Mr z_~{QFl0-`#bC# zT*qp2ao(8;ccy$+Zq2MUFt;3EwVxds(ExPSJ^2I#T=S0`~eEL9b&rc4c~#=QVikF zAga_n%itoaSSJw03&fvB2CDhEImJQnTnYlt&jxXWOfS`c4~{9#uUy%EPp51*{+aCE_&5Hn)cn@J zV}9!nZ3bhcR9%GFwe_;p{3h=%Ic7~y(V3OGD%62YUJ`cw8YXe;+FFyDU7q)*rloco zv+K_z9Q{>vOk3vQN7WwYtTg?hsPCBf|8px1=Qixjjwc4MQ{3?6o0Drhq`qQQ95!!^b^hggdz_`3hn9Vh_3WN|2 zTl_zqrlFQKKf5f$eE(cvwn|nry0VMtvuz}M7in&`|I1$dG25J?A+>ai#Y9SUHw6?W zd}SvO$RDv=U)v!cIr>SRO@Kf;h{I6;`%CCQ9(EL6fm+Br3EwhE;}DO0P5ZMmU|S2{CHLAB4Pd+-ZI#!sv;EwRjN4CO4WAQ7O)43?%xj&lboxu?DCP%2OfRN~J{z?- ztHtF7h+tUde;dM?DZ*BaBC z{zSek^`_btGv7;M&ntLI?2mfH%73J?YlnIMc&KbrVbqUpAUx`GuvHIxFKE<%Y!m}8 z>i58oB*RD^|vJUoF0Uz zbp0vOa0(?zW$Q0iesGOoy2OhudRk#qhQOl+{sC>T=i89*mCakd@QJNsyzuu|Yz>cS z;p^nhAhdiKiG=F2D9`34JNUrVkDo5Wj5M&iM$+@=Y0$mQf5~z2Da>CJO5G>@skqwi z{`0jE42mR9D>4ktS?t4WNFc*5W8NpM5Pwx19#2jF6WDCr+lbr_RJeSexr&=Up#L|u z7hgc}W*ID)BAkB0?1mSb37j`F_bH*uuAeWDK^eH?O@w|B=6)7W+3sJ@xJ-o3c$xWV zpaL2Qpal|gdY_Zx1wHqXl~R(02tK&Ww#+NL-K#y_lMCVawS&CY^M_L$%yZZ%jEZYm z%R2c9#D<fZ>;cT$J=?l_@(Vtx6g!&3ZN_gfulPCwYO zm5KIBP7H_r>i9EtFF{S^6Izu zgCvbGC~=}W7N&1oH!IY96Whkk9MMRG{{9Gu+0~N9Z_57>gc4w92&1BYDJbhWnWM5k zd^{*?&^ML!(B5UuR9Su`FFx~MLXn>?9|y<*$HGOSeC9W-Bc)ByY60LYW4?ND#(7<5 zh1QKpw=0xt*YC={0WUo|!_sb@kwebNdHc^T3bFIc#MImfDB0?WTzn_y2J0KE(AjG` z%t^aTXaA~`|F-|eVY-_IS^q7fLEmtHQP?`y3Sfkqfziifo|A8Y*Xq?O9N;E-E&ZAZ z-L-*n+7C>ct8P+9Lt$nmT!ttvA;_@9#OfCY2hrRg=%P1%KGGeV3)Tlge6G3A#b3~o zy^7*@kAZcqb(LOOLZw!q`#Uo(3i=A<-$AtR%&(o~h5rM#Z|v8!uZOE@;RmVq{SW|L z`!?TT+jnwH=k|>Zq6^F_7oD|t`vwQ`xn{15zo{d;+SfwXYujdxtn*P1)g8pous zG{vAa`AbL74u7-ZCqW%n|G_#{BdbX`ELNR=R1u}rSzo@uOG|%RpFNhD#nd}an`Be^ zAwb*VXBopw;-Z}2zrCwH&ePpW*RWH204Urzk65Rl9OJr5`^T&7DHby(U(9|lp}9xe z>0##~^WV5UG~+n1xc4jzSr;=6`!ZagS%{3)UXkaAo}{t%RP1BC=v3^rVBkl>z#%wj zNV5O)-)+NP#Wvg{QjvbmHk|F%%dVsRZ%wqFR7xks&J5&R`1FBUj}3MG_Yt@Z`j2(s z5ZDiXKIuDNyiv9jzjnlznw?i!;#`=QQkaho1PM48BDvo-jX{%H{b zplAD^gF$0X3~~qO(;sv3Z?pwm!E_JeOC5ih^GjFYi zA($21?$Fk)Gc)++_76(6|G*r9_K&bFc<-=u`+-0l!L@&s+RrLOA+%qgt-+^lKLKk0 ziz)a|405O1@8aJu>GlWlsrI}00creg5{6%MFfARPZogdqn-!=3hwWz$Du57>i|k}H zq%cJhyjaR$8gLw+_78XMKQ!Hbb%{8>?f?H#`_&zU6qq;k*&2Lu|AkpZfZD$(-TokV zN`L6$-}p4${vbZpeiuI=jlWI8@M{jHrB|lgztXm!%ODQa|A`LzXMK7&c3SE4)A%R- z%2}L^w8${GNTIa%`t<*PblT)0n3#K6gSm;>yb7e6zy723>ChDK4bQud=~pu?c63FZj_BwefiuWU|IVE(x0H*M+P>t@irMKQM7MUdu(iC z*DP$CQ7Ids+{%=y(r##aiBR6{-*suQ1W9@d-Bx)TU)-Q zs_1Ynf<94AK#U7JLiARuw_-1j=o>$EpJ}3gGP&w-(FoQCUGqw6>yOt?iXz-bj5}Gv zsAO?^rognQlGLiNMsJ1x4^<+aphyAMsoT=8w*UKg?tj}xo%PeSH&Zt$OD3qL(aF{6 zZ0VOEC*n2>4egfr_c@{5Dzdqs{gS-eQCfJhR9;_u9_#YS%sPpj8!U!31KBM!au-A~ z7*FAx;Nbp^KHu60+rl6Ms`a3vg#c5sqwh3KonLJGyfl=7{M|8bJpWP{As1cvvs9Q9 zFAmNT3s8UCA+&B6RO^P&_kbq(+fEg@`6WiypblsE_tc1#eMO&Jt$o>BQAbgrp}F>i zSvj||eJ1+tB%O^Q$Vz9!c`>it7)WPVQIr`tPJ8-lIN5W}m=e}8bdkWqz{z$nPxF1i zYeV_kArUzEr2*7Rw?oJI&3l{QbkoCswl&vxIM{pW773;k zdFARK!R6VF5W9ZZy~66pFcUPT7okAQ0-0clZOP`^(pfpLl8HXT*^@nY`$s-)AHBef z&EMw+*E6N;f?kfK#xUO7NGE^GmH*5BpW@y@R<@le+r2va`Bevfmx7!MzO3n1toGe8FXpJ@EkJ9(gsJ+p?S| z6)%_deu1SwLR&Q)GLrQaoo&W&lZ8eL{tpIs9u507&#li-N{!u4qH(slj#)t6i9D3) z#Ybejv1V=ou;kKINtVAvgZzM>^WC6L=J(62w7?+}GZpaAKm7E7)usa-eSEKLn!nVjm7~Pf$Es_`Rm_}RG*PDScS5pE z^@&jXIE1!5U~%K`IPLoFeG3u!26?`-Dx@^eT!D&E*-xCGk&PU6lXNgdRHPiN&#QN& zUSU3i`w4FqUTk7E@P~EL0EUQmhdj3PpzyRu`L>x^^2p?4B3AajCVKiA?!{U*cySLN zIkR5KO5{AQtzum!>QzW^iE}TPl(NhVqXPX6Ckj;ISkJdE)y3yXIxE-CpzDq>7s?cZuLH2LW7-=Kg^d1 zwOG?}9j+`b4aq@zExK${vBEooLhv>dQk86hP?-+dYWpe+E$9~Q%r5}|LW0?j4@nuJkk4C@U$e~8Hxiplgh z-#sp1oN7Ar1+zWyBZLx@WilL#I87moz5o74U-A;|@&-9I%kZDxk2zH1BNxUQb<>^3d;w!iDO>^e8L zkvXR?G#*;>2F2jPLG|crVbyEbZ*zpd$(ma4UYRa8{o=)ME!ylQ_%XvG!rb@x@0!Ia zh6Ezt%cohY+hcB{)PJ1XPih4PA5+seg^?b7866(Cv#whD7#-A?IE)gk`cTMyOMSo;&p9aJcJ*=iT_g zRfz4B`wMKU2a2-!jFo4WiC6Un=BHm5svdXPOmG;QbY_jU6L%jf(xN)vJ)Db^0pi2G zhGgqqMf0xf3x59HA*fsyVV{-iHl_!N(#wsNKQKuA)t;1BLCIY6BfE)=y9qw+MNbGa z0Ud!?>{XVT%|lZMf6P z+5XIjH9^PyIYclvAJ(Toa}K}lEphvd?W~x56!}^GVWwY5I`!=2qTzgv)mKuxg5z*( zJ73uf!}oA5j!JCFSm`XQ<%X;K<|r)Qq~hCcvASbMo;xvKiO50mv#ENJ** z8pXzcZ1M@E%-uI7=dy5epGsLk%EC6R(wxch=qO_M71yehgRA#O!C1zsh6)udCWOX! znf7gShLJe1a#nH@(eRofpf$uje|b7C0Cbc}y#uvmZDzul;#1CTYG?*qJM~ElCrVliz*`fuv7Jt z8dM>zLm5NJw#yd2f40T@XVaXr_X0yA-%c=K$m3IVT?e-io{YPBg?@5@KN(h!x2{UZMEPj=0M%&FQ zQxl(=epJw%tZxYHUO_Oy%rvl7;BWI{l7tK*_d+b2=xs3PWsqsFX@jfc~lm=z?zA2$17*;A} zE-4GzCZ;$;gpDrbZ|pCHzZ%Pg7}cXho~$4)FREZvBbhqZa5||wu?7<46cR*EFEi&T zMcPgff1(i9z_Ko*kYWlcO%?L~1$z}jf}Gb0B4=r4&NANYsC|wX(?u*R_UhP_UH4^u zQ!`4uGsUDR!_PVG40!|KimkTC-HNQeVI0$n)@H%ADz$}j$Qg}q0ZlW<(q;OL1a9JE zQbe`dEOtqr2sOMo1j(b{yIEJ`pX>$rQL4{7KUIW3Qx$=yGuxNN?YlyoV)JDslTmkc zY`)?%>Uw*v)@L&B8Ie}&onEi6e9hLottQnztAbRqsZ#sF8vZmfut1o1#C|Nq@`8%e z_L&0Wzk&y>gNmS$cKjWgf`U53%h*Oa2e9$q4NlCWBN-oGuV1(MdnmubDy^M$`7C8H zDID$}f6F(-U-%92Cw@bG_iu>b1TOzK_;f!-N4(_kb<9Ri{yr$BM`-wL4rs@@V!_Ec zSJWJFfw(^s_Mx$tvU$zm5MINpO6275=XjHtz0^KmC|b$08q%$7Z!o0x;=3dSmm&mj zNXx#Ke{{&dFIpofVb6iGkgvVI+ z5vu&zTLMaz5VuIA33%nUTa_!J9Vd5ZiE$W3Z|st!W~b zb6*{Z)BF?LQ4yZ8M9?7wHmUl=xMmJ2dfPwn5Y%zua<12(6~aATB~{vjSQy0jm}A)H zk)UkzWG-fk3g4@JHu>mNZ-C}1Eq6l;PP{MUjw5)P&&z~d7TKTD;gR;{XdM3#1w=gC zG&5toTuXn82(HjgvOWL?;0el8Z$@JCckr1}n@0&lQzhUOhp^ZviI~(FyjWs zyv`!g^RFG}`NPJ#9&E3)8*a?slcuN}UDvnam=pYS3&PIAyAFx^JzsAEKXsq$`;P0Q zL35*Juh$My=?|-!I*-4R{#uI4#tgGI!><3eXs{_#2%$0R$8<6NgBlc(R>E*?S`Bww zSjd~X8S@inn7tPG9sUo@to+WRtY%Hb5*GN@gtqN>`z-LCeDOER4R~+?1>;1aRu}XP zD{XJc00wmbXMDCt_dyp=Tegt28R6)1Cg7gvKYN=aI2yi}SqSNRA`K?;?>ON;XUfF3 z<&mk&#ozS%jV2r<^=rbV>+YwJ5tW1V7ZHxju0;Mhys)7Vc<`La#*6vl601k=8PB=1 zBACZVDSYr1gjW^ygkVEvcG5XBN08IhB-oj45VfpSI4;j=z1t23m!0OH@bpVbn3{u- zCyL_*ffIOU)aMXe^~dXcUhDOmnAyy$m#CS@ebi(YMu0)c}b$u{$|Ne-PqMak5mu zNVur-2L9_f>pm*nC|1G|z(L7F&7hw-5sUIG2PtiQRm-lUTQ>E{TpnK&+qj`*6`Kzu z5uy)opPkXNJLHXi#qRH{`3U==vc(ey67{b=xM)t~P2JoLNjztTzRFrAP-D(Q8`HI6 z`8=p(9uRv$6*>-3^lZbA)Z8JLw zSdRXF0F4LuuSg!$9{Qvlq0L@|Q)aKosXb4UkM_;O^OiAimNuzp{rqQ0he+31e9d{3 zFxFgppx>^09FY&NE^fYFAi3Yux8#%+rU2w;UH0&*=HD>D)N1HWXNM3}^M(enXa=efw zCXKsA8C{9-U`x_Ja!&3*)W>>~;bE2JwNS^gw98Rm)6!n#mR8b^b$e>_B1?f@+z}^M zo+Qy9TKb8WCKqXtn7`huD(%s{%78X2#}$$;R^E1eP#NZAN!+Yejxq<^D)_bz|E0{n zWE9#{>+#Bv(068>LpQ=N&jxYsDZkaKDjG zV+1%V1fBYWSicjdpSsN4K_4LdU!bqndVT4SF%5df5h?;pY)XtdO*<^!^0du zGF3D$`9$h`$nOBFqmD~4l}HXi1Gji-j#@SF1eJHvz|DPl#0MT>OCPw)eql!5&xW@* zdu3CbNsltNyq@xIe<@kb0R#o<&r4ibVexF2Kq0_!`m4vHK|@%IY=0ggZyB-2X?8y3 zi}OP@DVP`3Q;hj7_AX6k+95K}sbXIGhW*26;)bI6PIwiO+D3AD0VVnQuO2PsarmCQ zh(G|DUB?rlW+jnY9oCo6K3c=jS;!n_Zd;d`0e7PnEzHMCCHVv0{a8)5GnH#G+6boE zo8EDvm%=)4si&@e{{L$M*<`-Q4$fY49d2p1ltE=aCXh@)M_K?!Zbb;$GSx&k9W+@XtUzkXnP0) z`6jgVUsXimUY7nd>;J;Y2kR2>Jiq*Rq=(}Es0VT}EI~OQB!{^qE*@bG{__(yK7Tfk zSb3}1TwQm`jw%HwF8;t9h_U*O^=vh#Vyfd@Ge15%8V?O6Islp`+@!DCqN=j3lh5!* zzmGyIJazcNg1=uCQKYz04+WRG;A*}d{XOmA&a>%q^7WtuW*u>)pFV^3{RsBO?1m)8 zeYsuj>bH$YtUPSlGk)*$*Ya%!0BL%EG4zU3`sMH0N6z2$NQ8!|yk+dJ2@j)~9bQv- zJbwv~SozES!GrEh$@wMU=0moq(|1vaengP%yZeu#@20^hL=XW5NI;t?|8`aJmC2Lk zJ9`eziq6O;O-=h^BKA+|)(>2_Hv2b9J9;_wZre7S6~(gf^zLj3GKOlRa8|_HoWBxr zq2F^ElV6>5^T%Bx>jd?GpYaxw8oPVz>eV1xV>WIRht2r~ImPJ4ArFM7|30L)=TBE) zqU+-N^4Fn6oV7%ds6<82+1_~Eg73bEJ(QhwS z(sYB!-5OJF{UHi{@GrKQ!_z;}q8PuGe0hFm>MRJ8qLP`@dDNHpJyJOCj!h!#U^{+y zv#1i2y*{38#laVYIzDU?NIiw(_pt-sp8OpMQQq6U*MeV=4M|b`9Y_q4x-?f`S_#pmfji z!f|#yW>Ka2@leZ4Us6VR-ng_5#KV)?)W<0UapGZOA&n|;G+R3P&+{eunfN<8;)z(G zh?IXe8(-ZKZ>zlbNUEF~Vc`r62syt*Hy)JvRAlB@{#f8ErbO zFtqHwx(fAg^|a6H&e9CyS@*P8bF%5?W5ItXz(BN@f-DM=37)oVG?M*(e;;OuJ691DK-%|EY zc)%jDzu%wrXn%zc{Vi{r|I6MPe>GF;A|b)Lt0EGZ%t0_bPHf=`kSZ?HdC<_%m7iiGNz;#3q&^redp|p^dnlv1Kn~y!&WBm!J@GFXd*g>Hi|(TDaF>AGmaBQC?szCFv#t#9e7K@{>K9Z-RNR1l5-7#CgN5v}q6 zSP-9UdO1pX_7k$pgNWqi-^&ouF_#ixop1~# z!0u0)^@vVwYddL#_C})cH{tvMciAFZJA>YMQfmFWzMN?k9cN~a!thZTGR0JBQ=LnQ zIdX_yz+$9tnZS3c4{T&7pRyIX{$Vkm>K|M;Ey|TlJMBI?t-kzO_tD6QpR#r3Z*zfI|Cd;2->+cXoht<_2sen^{TGwtUrK9L1qezSi2E$0_GkBh%89lxA-_E0=4F8Y028oS`|pt*=9)EZZl&E19E;*aakwdG&&73CjC zB6Ev$oemb{jzJ9DzKqxcRvLNcA1rXFdDA^4?nB}+=$9B3&>QRWW;@4dC=Lof2JxO3 zychG{mv?hvi7jJb24x(g3Xh-!63Z$%7@zBd z_+qm~L-U>@etrd*wvk5_LmxZOu`PV;_f&Y4Dt!7;FldJSI}7;R*0XE0_mJG{%Z;DE zk}Vjc#cJiClp%y1FfI70b$@s!HLC4_%bVp5AIjmGs0GjI6OO_ueQhYVvs)c=A*AlL zi@O%v&gWO=u684%-pOQAyfyT#0c6fK$Dd%M!W#otW&RpO6__4Gnd!&! z^K;t80TtiBIkz}7)VvU}o;ZfsYc7QT2z!_M3jI02)d@C8dH2*i69nOx4)?WMfp z{vh)hdlh>HdVbfUSotq{!yN7|nw7H#U^(CsT!5bM=bT7@pP${6Eu2;12Z9?B>JG7; z2Dqczv|1N@#jZWa(VjC0>9qCCy^8AP=X^k%pa16`K~dZrm)lXyBHASQzU`z!Y$TW7 z-KiEU)0D8QhTU3I`WCo>R587~t#}B9lfTc|LS@biU(Nt1`NlpMgV0{ys@+bvRrb0U zzF3BuUC7D#*st1WRu%QJ1!PhH`rET~&d45aSw{ecvwm64oBrezzYo~yHeWr!IlgXb z_(iXy01go>5t>&-;r9(@rV?ojOC8aQUqX4NmufOS_U$Bqe>stW{;-|xia8za6)WWp zl_Rr)7(s@)oV~4mx>1NB^D)%z=MU;`b*+sJB(^f)M7<>LtH)>>RygHWNL|`fw7^@A zg(u@m`!IT!oxfc#!SARwu-0j=JzFeqJ_CUph&W%fLqkoo&z7fBmycgSnD+Ggj%fl? zd*xIf^~h}7X7GA{Vq(mw=jT;rmeOcmtJ`2a*KP80NpmL z-|s(~oq=z~n{0iM zM)+sV=1!Q45{+$JON33{_6Bc({JlL3{}p`h#g@|_jz7JJ#1Qajm9SQf1nQ>yUCcg52d417;k z-B^E8Zk2zYlm8=SJ8FB_{m+XE2k7iS&W^l>R*{{B-z(cWc>v50a%M7>ci82UZfwWV zZG*fr>uDLC7eJ|RE5HQzHvFU&6Y_TX_rhD=1<+zeV|(4<{`fq9QeUrZdu`A7c9(+gs3$_V$1kiEN7P9NzSb{|7C-{Y6@9f>2J~-D5Y+IB;NWj?AyBw+nmU6X_^t@g)3A-N!qxc? z*0{9}{6a!;EEOnI{De` z=1L>6$dLzwx_=CCod-E+WDAV83uTi5A!eHJd38}3SHWfgNS8y*a5wfv2p0^LLiXfq z=w7U}VtN8Ya#niy1@`AYSpyiz=9P+p-)`wEQZ}r#_9o=z`L;_}*Iwq8^{O4_E=EU5 zJ0$o0UE&5uhv5cwCoQR$+w9Dy0nH1cP?$QH}gfDeEoP(C{Nqbnv*3O#d zc6vH=UB^WO4qaC=Mmj*=>rMN2OWpq6_d53Pq|Be$Sk%m;$&6s%WS^Z( z?i-?5bwZ(6vfP`${)~BVPkq17d5i~d`zB6+9Lhxz=PC-48s&}7Ia@_(LgBqWc&{;M z9u5s9LjD8Di&`0*r;Zkt!zj(7el}`YJ5gap%~I6p(7|1F2?zYs#XtLYO4Pi?W^F90 zCo%HJBp3fL$?PC7!(12?J<;*+kuLt!-pHN36n|n6KhDJucJXKYi~M#u&^?GB8^rgu z@ZG+Ncy0BXO-DJ|?Z=}FHHUM*?DRWW3*+7)lP-O=N=emM-(s||u{k#bXsb(;| zH>}rCPi^z`d&hoaa?FYxoo!`iN77Up*&}mdQ=(3D5UpayIb*T^l4b~|r-CYfx+Vsx z%Q;&t3?LeZ8|MCL%Mu zkBxe_nJ7ylCj?Prp`VdQ+Q=LKN~A?=_aL$&=zkY~w;|s3ztBawgIs(c7eDgORK3g9 z;ZF$~G~5C?#gI<%{Duws4th7pAEc}&#ymq|=4L{YeN2{X(2?naZ&SfhLa96t-dIqw zl$Q5RS2Nn3NC|f1JilIxZXu`C%sb3BvSB$uS|UA;vM8o6?LWdsjY~&$x9v-hub_Q3 zZ>8|FN!TQBse^wv`OSk6hMB8MfUCHz{oi~J;S>B0R@8$wO8w0&-^ZNb!1-_jWkLz) z*D2H7MyTn@Pe=R6zX-B6SJ?caJKlld+Lzi&0{YOd>9l)Q-|9ncLuRK7t)x)aCpN2~ zx|vjv(=^Ql=1G_OqRoI{N6TRX;U5b1LkFuKdg*CW!ZS1MCxQS1+{I#aOpjex`W3lC z?pQOzX3|?&u>OWmGnAize&{gspiQET?YJgS6-8*G!X0J;jWEzCv@{d$W z^W0p3OwA%CXX)#+Gm_u7y#CLJ!|NaZ7PEH4tC}>>mM-r_g&}GU=*w2^Oj$jD=5UQA z>8vHPS`$s%Mt9cPk8jXdih{tv9KOv&N(4IFU3O@FDw?4g^@`o)c>4nycu3Oh--{xi zR34JdAw-57Mc!zO(t4#hA&9ge3&mOL2ub!chq#)KS0Ab-@pqMW1>t5(t_34Hn@Fc# zt)eW^uQ@X)u!%f0(#`c+!}$#lE6DcKT;+$h#+sX8$0mzB=%@RbM_jpcg?!t*Y!&&D zO&#EEw6k~(5aZAM%oZx!4S(il`;M)tt9wTf<$0r>eI%3NMBcU2powu@c;3vOyyHga zu<*S49KBW*9cm79P<*ixC@deEDt?|q@{fU-E_iDRv33C8U}M#oN8P-z{avCg`;G(| z9YC;LbCyD|ZvF{Lq`5N32e~IQK3&O2q~p2=al!o9$Hm`}u6YyvrD^9dM_=n*mra*{ zCCglw2l0ox_(d-M2kH3VsK2L$UE_id8!O}>vvHEHqr+VO-G?Zp8ah`aDN07`Fx_la z1jnn!Q?c!~OH}a5ir?{-jmo|Vm%O?k+zyrd^B5}MJE_x90q@ynQJef0NvOST+X19B zE8m_K$d=i$@-Mnd-r_7^==r-6mOf7b^q73q0L-2XsqyBQsNIIx^*iN%RPF=I~r%Jv~A19b2YrVUHujIODUxYfW=iVOPpIH{KOE#CPg z)D!q_!Q%Z?LMx}|YWZ+Rge|;8zZ^mq$XxJcQK@ykVMa{P%8+F*{-?Zlseew;l9sio zYGvAYdaN%F1+MQ?8Rx3z<>vtJ%*%_8r{s4P@y8MYOn~lCq~i|^y~+pkp6!dr*CX*U z17?^()1+@*{V5Ci#GZZn*sb5CQcJC2EU}!jt0~p~B7p=PmkN%*@a5-xcSlnO(B}!% zoa;d-gE>r+Qsj$1*76>m3<{JfVZ?Z*w%U?5W;^4r{hf1Ct&dPy)o$U*S7^Yd@umzg%t?suGnH67bI6@+za z6Rqs65co#7&bM>z%$3O8Zx@fu{IB@sL|=JVQnrS=^Q%Ag=Tu^7-^ddzUh|R_w$-;1 zYAzrwN$-;CYJH!@H~7KM-TkWXwWP&sjv09~0t?@|zl*DE^S?_5%&mUB82!oWF-?uD z>sBR~Sx$2arZSGxw07Xo@|P1V?fE&|WltNQsjZzRR&<8X_RuDN%^yG3*(=Rs_(!80 zal~w$j|`}`fHt08ME~cid47J#LQ#8zKk(%*n=;B)auA-KuExI;sT*2jd)n&`-j2lt z_fI~ueGeCI!q8f%s0k9hc)6Rf{iZo2hsQiEu&|HEBX?*H@A_-cd4jjZCCu9Pw!Zi~ zoCC5bYLZP{Hp;r(_T}g&S5Fy5*WIYHb&}{fe09trKQ@Y&C`@V}mFuO;z0f9YwW(B- zZj;Q`c^NKg-V%vFr`*X$b-Q!?jG}6^n6uHBG1F5iER3_%>L>FmbgBb?jy@mnpwC>t z$tt9t(@F!U6iy*kudm9o&2=AQ@Hg!WK2q}KwD#b_m}%?l`l|y9n@nq;{Z{0HfH=Qt zB`gPAagLYkKvSm#)&{2p!uM9!?5uvqm**K9x=B^c600DUqBNcz*la zoBMzJYs&elOFHcU< z%>SULX1{vs5Z#6wcj^UhQmEwzYo3ESLb$(1MM@68dwfO9o}*j-(I<07e0%JZ4JBI; zmhX|d6jXfHU+A@VdX3{t)RqVdYAz&M zV9j1uGAzX2xt$strVF~z9Yb^!#(kfq@6-5p9bta8A?O44Cm-wJReLF}f)C5TP7SzF zw)q~Z#XaOq0g))ZZ*&b{&ggFSWCS}tR+*|Lx$rNSx7~=56Ef-sUC(+4_8|xP7rpcl!pmq)6|@m&BK%-F#5IkbNlj z*tj9@@uFgCMSXJ=J=O54K%hl_^wnZ^E&R)0Ee=ism8*!`Ke6j@nZ+uX#JOAzvI0pV z4J5GhXWwqjUJvzQ{)9mn=srmX;j&scqjLyu@A>?EQY#v~&YeRMtj|zw4m?4@@qWcT zGV@R5*CHnE$ir6jhiodEeRS&Py8!wov8Z!r!*T4+`?n_T#cTk%00FeGnfJHOog_$^ zO8Sa^+D88G^xtI9(;gC#o+YDX?khNCYP~T2LbLEMGV@Q@+&3`(cFA%_kmFBE-|x8% znhb7YjUT3I7GHAbWz+bK_KR|xk}t&Ho?$8azy@lmQDHHX4eG5R7*H?k4^b&;M8a%x zK*V!J#Hq7_=j?NJXs*EIdc@S#q2M2~SPNUgIRPd#yfDSe4FTGGY{47sRC=EsaBE8z zQ`d2>eRq7!2<-}i%~gt2b#Jn_By%3in6fQ{7p~pNv2uegyS=$=<@j?FXO}|8(9MfG zg+{i8XNV;9Cy^jG5D9ih;`8SamV7xPW;PjF0h!==DL4ZkU82Z&* zR1A5P%CplMYV79Dazn}5%J}A0|EMh4jNx$IB=*L_jf(*y#WghPJkPf^Fgw#?ueEED zU8N>_?Kk&OA83Gw3CS?BVmXXDgCR<%aXYv!l%F23o|d7Kl)n%ENLJeUv$A1FJrzx0 z#4I7LHIrk%Y*c0949-O&>TRwJI>GK?)D4TqS16sf?Har2v|l{$bvv2S3!Szw8oN{_ zdiEYlf?>Wp4p^1QJB07m!{R;Hv@fYDTXOsQE63kNxQLLGDdu8u);E!tow$^h#a1m} z!Qczql{mH|v-X54e}-tUs-z{+GcyrsZ`i4sV0__>hpgm>U=lFw;Kfc(;^2u;pNn7^ z8c6W(-4pg=8RF_@#yg$c+e1xrf!;Ha{;z;nS&IF!fX^N(UWGFFT0{!TB-bg=$$s<`bCGkl2$KKRa9iD zMdshP?q;gf6_n6XW6|TvJ7SrGD>r~^g93|eS&cZq`)XtGJt0AXRT+UCh3kw)%STYp#EB5CHV#xYk_C4;1{BZ6)%S-L>B z>&c^9GlY&bg?NeaaL8KvNKWApGIw;p9mkN1z4?C$27#Q*Zr{k7q6?Doq5Plcm3+Z@ z{({?a&jWvGnJ@Rs3$3w~1`L>lg9nIp>FRtfV~zZO1ICs_1M})=G|jd#vjL8e@KtW!q9a zgSJSIYxRqSnKMakR_)}cCzN7N2r`R}w256VC{W95Fl9ktbsy(-{y4MqM~ObTLrA{; zk5s-Lx7mPyoX<+{GzEN00HOeEHuUpv1-!7W*Y31b+ra@Hf4>Pp0{)H(PfZuEY>gL= zzAO2pVK*h_h7+f$_uiE0|HoL2lH*I7r$^2|0`nU*De8kCh*lD&h*yoR=!%GKx6g z!}SFgF)auZGHOVKKCYv@`0MO%{Yc>0#hNQ?9A)A5V6_1p&PM>yu(9ULEdfAM`kp^l z%j%eXy;IUUoh<3AZmAiU>K40{R#gRNJr`4S2t&5vZ8vquwCa^6IUTdMd&ls~WZ+M% zk$$D+AIFqzY56d#WoMR*2r_pfnoqfy?aV<{C5u}&X0_}he6^Rk-0L#D7^$7E9iPPs z9OOrx#fh)>5`B;K5+k#4#fZ~C`M@c8Gg7vWu76wlj-NDN(}e8=+M3=AowlZfZc=Xn ze7TkxY!ZAEv!i|m@a^!=m8@v_B&%f)fNt|L z*Ls<|kx_49ksLuDUR}9;b9{9)(etqCL?o*^zBp2{G7|qHTCyaX=o+q0RAkZS>ayk9 zt)_2OYe!amC?#jv%$T#=|zLI}xhs z@oAgo0XH2pgU|0=M5;)CRPNAeAKxK|*_TA)Hw6C3qX<{`KpL9ORg8R8&aqEdj3ylm z5%GdZht*cvCnf04Wd{vfmQ=LECcVUTT|gupQCKp-~RMPGc`Nru*LiyPEc@ zAkG#vXAa6 zv;|!43Mh@Vc6|kSRM?S-T`r*ES3FN#-{<3t*^$e_=4esOP-P*pyaNBnWH;3-*N z*{<-^JwV|lD*0#)Pi@mj3GP6bd$GlPgXIRcCWOdcq`G%JD?+L)$j*~Z)dmb~JkM9(9^IcyM9n@AUC zjaW;TXu4(7G1{|l*?3H5i`Q*Au9@f7WIKfkTN2vZ4KMt#aD2~5qF(qg_jG0cNs%KW zQ8fOc+3`=Hj_)*0o85CPPiuP^jklReeCT z)a!FmkG(py@#EUphfZsk?qD%VEB{QhGA3Ldb-MaoGQq6H#*84#W_q#r3B#E!qQ@WjF6XElN=U+_iGWg!)ih7K5Tteuc(} zXMXv*=uA3kDWL;tA?4#q+K198eLpD5yj>9`iPv@pP^ads&QHld6H@!fxxQC8ZP^{Y zomzB;SIGKuu)5qXy#e~F=>UB+A*OL`3TSgg3Yg^colAD_w*2!0*(zI#igi$dH2uq= z%(nhc`zr#tC?MOv5xxShXP*nXgd0cMxeDDhJ5H6`|5eGH zU5W5e8DCR9dUe|_)}|eMNbwa&3zgQ7Kp^5cL674Z>Y&2px9|ZZz`fR2SXZ~3U5q%I zENQUSjzQvRfYM8>0?Og2gx(ukvZk`-BkJ9q6&d|HQ-{O^5~ALp_ADkNCoy~-b6NZcJih=dn@+<$z(>i9>z{R`x(O(Oj3vLXCe5U!K=dblL0J;f#Y z3>w=z$ z{)gtJsRwJqiT{nMC=zeA9M-?A0*NYGvL_->d+$3hdo1VAL)JaJG+Oq~U3sqmqGdb7 zGM7diUW%8yl6QE*d5G-5-}E1Art$lha!|dlpt{W5bx5Ra<%A<_`{XsZI&PA9>muVW zb{qyQgLfRmP#3)nEqSZ5W52Z)uNv}$iZw>tCnNXtjZ49)zky4y$5_{dRqealRD`*9fA z-_eJWh}faN)t(q0*mp+Jvsx+MoViIe14`Om<|Mr)LYXJB*eV4O^TQj&_*=~V7?Nlr z=uQGn7(;l%Kh{43>raHv|32x@R{9Hr^czWU=MXd8=GdKX1&GAPz)e9>XS%7 zR3}Cwt8JVxXlQ)Xu=wTcay>ud)?{VNZ$C;V1{gIb%7;8T+ZnDfHKj+QdBF(l8zdr^ z@ET0t?Ef#a5$~8EDHJ+YKblXlH3{bL^}Jrx+VwqRGKALl<%i5N z6X}8)#K`fd@`3@-+IO2+iY~j@Kl?r1O1qbBkJa%_(HSK|_{YpR#EK;D zpboS8cd7k5w~@N>Rfi8Zhqax4;0em{_pe|O!5lKYsR?p=jn${6U$dU+p}xH5CPAdL zK_|4Le6SXiExM=8&mZzEyPmOKxs$=?z*G2uYb|R#O)QDsVai!lNK>_JE`68`u^okV zTy{i~e}b(gq2ImL#8n!cKj@qii=m8gZs-C*(TgtS{i5K#BAly$UR=+`ONF9y$$mD` zCOl?$JG#E|Fdupz&J%P#^b8}q?t~?w^I4x~+V=hZ(^UILhV1k=Tw8YozfVds=nzJT_K}d1kbIqOb7sCQ)KB%D}Ug!_O(V8Fywc%(n5EP$Z=Tjb$64++w?|R$5F4D5&+-Uz6)M(*Y z`E%>&lW^luO(uT%A4p+Vd?+=+>AE|`dIS*?o**Jt9#djn%$GAu38&eFGQ7BhPyMz1 zO)I}d=!;K4@_&H7_}j6KM`HxGm<$m= zZ)Mq@3C(REst{KD=;)r1nMxu*Ms#@I8M)oI=;#x@KY5e3FuIV?&JX!|nRj++x1BCN zd-4{=H?u$#l_a~fU2sr#N9<m(<)ogbc;*S$Kf=?DK` zZ!kSa;;%*4d_Hu*rt@d!b!TFON#Hg0?zQ$JW-I1((hx0Z?#w8xu-k_I+o8g>U#shY zKREvYPko#kKa2jo8~*Uw-ytttDR9772O+|wH$Q(7hQw5n2>p!I=Frj5RL%<|Y%0r{ z%VWadbxBwL6THSgJQ`A&NHWjwY0nR$K_KHf%D6xRDvUjs*2=V}8}M3x7V0a(Hz9TZ zl*`mjnTjk}-?3ncZT(vZA1qki0gHehq|*9nBw*RPR)0jcY9|b{5oVrvS@Y|EcK?+2 z`U3n^2)#9S$3aF}letfLnOq{XTrkgSbZFr~nl}pM=$2;Hp#APT`F(R5C>KkEU=)~` zIS3!s@JFDi+T4H#r;dm(Es1C+hV7twSE+#`tvlIW)$izK65yM=D{1) z#d1FxZ_r&vV6s9Cj}?wt_)^gQZKbJB?=%Q3e#fQyUOCjB(*$F-h8h96H#ZxUFmbLz zIONOyh5{K>Go80H?=Fi6CL{*Y;&$AdR3Zc_~2I<-8ZJa)X({{aZ@*0*AvhcsCmvp+cO7b)kq6ZMDV1&5C_Bhz*PbOx}wO zdX1k>w3!#ytm$R3r6(q3%x0?vP%y6)qc6WtNQ$@#` zbDIXNAA@{Yn3aLu5t$&(WDkKN2H;obdOrWM+E>#4wB@bqt`pdFv@{j?uiB^0oj)Ca zZs=(LAk{E%+9TKqBS`2eLy2zHes(qbExG#EiU)`gBH3_|`hyvWDGjAKGm+`RD74!e zQgaka&B39aZQNVrV}#DQ4=wzeB%XeYc(C}1##`Ih(gOA(tdZ-j3sXj}*W2N`7w2Ho zEVX;1R(y8!J?U`?)>~z#a+LO7VlU~WM8=ftVE-piF;Z0bz^-q3lWc1rT8xUh51`!p z1~e7h(T>RqJyi^>rRF5c10E&{izdsz&JLi+jfZ|m5wY^RHzf_plVt6~NJ9^;QwR2m z#I?K9?>Yrl;Y68YmJH|y>M zq|x~U6dKRJl=TIV%Xq}fKUHvQbCqdSxT$ zs&>&cda&dpp5M2Zx#w+>9^Y1s9GRV*3KmK=JXf0B^%9k4(RusI2i-gPTQLx4$y_Y| z2%z!@4hG=F8KsE{nc9N!^VHLI9{?pDTY?58LTiUROg%GEwF}^Qes{qd&+ow_R{rW= zQg})}0iHft+i5#2w2mN$r>+5>G&0MU-gVPHc$)Db5as`RDG=plB`yV`)xw#%GNx*C z9;Tc$y6_L2bGHI4x~>+w&b2@|Jl&9j02IvtMb@}-rTHAokS24}pFq(@%dFh^e6IsP zSiFVSgOd}*g<3=Fc-0@P#Y9dkAC~N;uj?hNsU~~z^mMYbEO}OG!_%~xO3t4Kh0Iq; zHiK30h8xdxsT&mE6rR@Gecr-nW_X%2MmYX&g`=9m9%l6dw6 zhYe%DZrZQ+N=BV6y*j1H-0Cq`^QWa>+1k4AQOK9znytRN8gC&YLWbOUdX!EGry+CR zR%}N^*{V9(jWXsKJOkxsCxX7qHxSQl_mI^aqd@Z~e9Ea$s`_ z10FPprDTy%!Lu-U_SI8s%+l10U2GB{w!-CtNp};VI(5AY)f$L~zYm zD47&HK;A^5V8!6c+KAup7y+Z?M>*f-0R`I>Lh>)P^DJMyt&Zk#mawNke5_9 z26@{VKO=(7q!`Al?Iz_$0;0plgum5XcTm_rhA2I|1xbq47MrA)UnV9JE>(iJ!H1qN z@dS`U74?ORDhx_`z(w>`0XCv9zlbEtpEYT$`3?IU+EKL9cZ(ggYc^_OeZ;o@Tj^~y z5R*TuJJlSsY9FDt{_G-dJYaw^S2La-IE1~1-c)7^YAj*@HkvXdIM@aJlq;5Z zZHl{e^il`A%->zWZRr$mxq$Da172|fW$A$DUBId7GJfs?^3nlKE}%L_E#0Wa$=5+( z1%aX}bBhZYlnxl-0**}wcrM_Obii3IVCT81GLClvAEyKIT|oUqq_DP7T?x?svUzMS zBm2w)Xa<}V=J>mMeJ@F;HFP(!385T1dMf?)a{BGZ>9;@dW=F1{U;0>r`Dfq&9;~rK ztPk1$EZcI|NuGc9@+$uV_8^*T+oJx(xwjnjhA~k5NK~aN(CQ9sv>vwS@K`o}DHkOKLwM9q(1tG8ruq>-j~ z&mkRZW!Hz)l>Sv09_jG6oWfcBCG)q`jA4H;$O+_y(CQ;!WL)I&WQIfjlAuule}N_W zr@y2LQfu`$yMNPJ3P%b~<}bfnBE$}}e}E<5J@*Hr`=`g)6b`)xajx&xk1prnt+*K>NA@`aWl05%rO?VJsUtm44SP#AaY`vZyGh z{x8yY7Tf)Tmq6BDQ~+|nls6u*54jpg4Mz*ag(_@{0-)MBNR-R`Oh08DUMU)}Z#g@N zqcYr$rCI3gOgiTDCyt<-`Yv=6?14J@&%6~ZvP<5RzN*7H#`&1AVT*qxBCJsp8p+|- zPwZ!fni))~o;WbIr@4TE!t5u6{+V7}o9Jsx3O2J<9d3p{b+EmQszAHI=52Qss+%*p zcDF_JS(>>}??hE2el;>RsH)24GMLa(v{xv5w|nhujbHY!(Uni2N_)9Gg=N$7srlK=N)R_tShzsNFmJ#<~FjvADXW?TTp)94HHo0_G<`7*4}pG zZL?;7ZN|;firj_~OYSJR^~TvZG?dO*az~%~8&OBHX&DTrFk5kqB;WjKIi2*e^8xx{ zHptK3pJe-q(+3wqthLV=k62#Mj8(R5hN~^sZDk@SyJq(L9#*y)yqUL=URZ(gAK4m8 zJ_4-j#DJFS#5DzxibD;55?aHuQ`JQhxRK~iE%W40Xh@6XUef+q@3irzIkY45U1bJo zpwC?Ki-W|)*-Dr`+)u1BJ~VFU&^?^o85wj+SY!E00m&WBNE1SXG2CTd{55u_N&L~vMt;$6T%yzkP+;fFR`y zBij_e@UH6Ef%f`4mK@;o^Yyo9lZUr&YrvNr!I=6#|BkDl-g(7h)#&tX?Pl=nehRtn zNgrz01$7Atl`koYw9bspwMx+aorJxOs%}IhLMA7MdQG_}3HJ?T}%GQ}iz_$4b z&B{EMMdDHPQEYJ(w&<~_30q`@@0zFnl~MVCl$r2H@Wd_-`S)zTLcQOqqhiT~UUI40 zfN6x=ZuQX|_=C+{=mH0o;h<0;9n_XwRIte@AWL*k?yY7rj3cG46q#{6I;z&{I1Ku* zuJC^ulckTPbi{W1-=L3V2YnR#3;aUXO_oI@J9?!swGzBqF$XW2GA^_xZ*sI^)7)yV zs?WPTk;k1g8|&Y+6r{DPs0u!l3=^O%jQ#R0hkg2Gr?FkBB|^aeJuUx5nIF53SkG+y z-?s!^Q2ll|!NEc;(5U?czs&sT2Y%nQ^b}gADtOF3WdT8DX(IeeLU!Z#P)GlO#qPq< zB2dNq+toFK3hZ8Zb!g4VtG$X(=6+FFFT|}g&r6IfBWclKdOhyy!|L`$LAT*wk%|xN zH#QyTB`3@@KlhnHsk%k0R1d8RXTDDd*?9OJym>Q?myZoA2=+bR7+lL_KdrlK9{HEu zmBJuPw4EO8{FocekIjwp7Qmfhg(iAx#O`Hi(pE^eMWpBr<%LoF*T~O=Y5ZBYK33J# z|4ECB9p3`j#!RyXHXx)IK;JeP1DBk)%uJb|@qI18#Bas9vb{2Y<5CGrjCR1%GqSC< z=ZkrB`~m>#GM2h4_<-Y!N+vLiLPqSIW>3mye zvT4G)+C`2=&SqR8T)$?#&27z!er2o1$5@c$b}s1Xyd=rH))K9K#6Fy?tDdEiIhnjj zvLV;{a-xY0CAn${1^?efZ_&i)tYcT`tA*U0z!IhqXf z$F2Bs$;Hh7^1m_v&n2Jv^>^j-;#bNDF`h>>nL_fC|EKM?4x^k926i;z>X(1`+iF=P zF^}bKU;R{7eF;w3N8P~@uG^KTEdLP{#zr6vyzn`<%`_ox#4`siN;@y#$UtD(kw@o(pE}j7~o%A zo4LhyO}_e?+RVe_wB!)XgCM%e7&VO#tr-xhW|tbf4_}F38e3P*x4;6?9*T zdy9KkHRYA0e}wkD3hnPHsEwEMoJu#NA;j}08h^dYo!KI~YscI85r4s_k|=zr*{T!6 zOR6hwcQ0#M% zp-$>J9`;a4qe=#0G+Y0OagKYAyhI)=sk@=etoiNX_9hf=&pnw!d2BBNY@twwdmswU zt7!0a0ieFv3jnVyh{kg^hetx!S7{@;%Cg8v;wss&76?TBK>WAyZkGPLTUZ^RUKEYbWEIR6Cl`&XU?X6v@dUkl4G&dK|DwfSW^}Cb2@4=-ZkXl* z0RP^9+T1YB^&+vmimm=D)KqL8<=oM&Xxx}yZ#t&&03EVa5D-^DNx`UD`bodZemz!M zVp|g8nsHIJ`7D<5>i7wfElc#Of05+9RwPQf$T{PdaRw*OAK7hZb(5KI>nAN=*PO$7ESbz{YgwKjPRI zi&kXIFEtM{(;>gG0C4{HB}pW!N*Z|+HwSU5#9}4@VtN13bp=5|AF{`wrE#jWVhKy_ zttB(%6jB#OJx$PjmWRIR{#nvSPp;1u8k8OH|YdVYa ze7r!>048cnNvIozhh;Q0Im2N#k+GVcJ_uL7EHRqix;VXB_wJt0$Taof2w`EAlcwS? zoVwgjc8P~K$0{%RFIriDd4$C3#MNv>P~h^w zzQqkr*QQs;ffk=wh_zsTLHbLyi}Sxfr6SJ%mRH*ouUDf5tSL0-xEg>?0o{ClWznYr zjre>r8lPAjaI5rjz*bMD#VT)C1s489`g%38K}~`AHFj(k5jfnx0e@m4cwuZ8*91H{ z{UgxlRZOgLhSpeRA5~I+3VKLZhsCw#oDTQ_&C}_{HR;=qz`MozHh_bFi}n|OA~>Id z_F4-R|M>q$Xm=~XG+R-CbT-f+eeKhBSpSzu=QxsEBGN<*wMf63J82$QKLBrW9=16D zf(8G-#d$cud1e#{4>z0_tNfk?J``k!LAGc4v)S-ec0@a4JZv`@c8+VSXY4>~t|#V) zHEU@mL|83|p{Bdhr!pnN=5hxteHS0(vpkLSU)vWINXR}9_9U1H%C9&{%+PWYz)rL0ip$elY;&(!U(q4e<4;m_c4t^MI`aX z!iW?Ih!RK`n!&%umjO>O(LdzGw0=ovNM^a2{HhQr))Cp_NWWSNj>wkr1$@iNoXwpg z7Vs(60vbU-!E*e%sQ{)uzA+7$hsMh%I9%0u*GPZ;-Nn*H+h{Wfg|kBQhvP%P_@34< z&fRPoulPcez|yT`j)2Wl#JQ5PNr~tQ96Vd2$OfUGy&CC`g2Qa@OaEasJ86>~>O8`< z#QCY1U7*lXW6IQ6uf5y9TvLa>FUi>n&_2%`u{*tv7Ferh8({214z08gg~3BH4=C8* zzyU;yo^nRv`vrW~ukwlLR8WCulwIFT^-jxwt_D)Bh-E?=8A@AEODk&GZv@n7`%d z3_wur6i#_;^x{*>DNE{w<()j>i^GCc7)r8 zx?t2b@KPFRFR5)c&3L6Cjon&uDGG++kwEzoW%K)r@DTsVY9}}-giU*HZlvO`p}V)i zXQRpCJ*$(qb?cyyiuXcy-=T4+_$0LKuRK&I^Wutq!Jr|3aF8<;+pTm|(bcG;t1B`g zxtAi*kB)oE#d)DMpYx%*9=}tAZ;2eg@*{`nBSc^nrvGE08Ne*KUP zZvB~N-`kW_!y`K!l^t&%TlDqfYyoo~kK+_YZkH+HF|?*0{Em%}yunxXI1La-Y@9Yn z`)3_jy?g&(p!Q_6q+QpaMUs6u^Ac(Ib{&Afpb?vU87z8a1V!YWi)Nr!yfjdIJN?go zZhfb`)JJz`dRtbv$NUf{6#wx%JW89r%cOYnJKSv3ZA>^!-nzkEsB+`tP%|wlCQp6W1UX zPXfZ7#jHP=3&xb0-@VJEi^<|-9#3EZ+8U_P|IPCEca*>7=<*Bv`ir?KxHPBUS`Evr zb%pyMFq|Gk(QJJms!BnpH0I@Af(5JZWRb8nZ^f-WP3vmXS`M(M9lx?GAZzsOK&_cY z%R11Qz5!yj_K~?~`0WEH!p)chYZdn8qdnHq9P@=qQA6f80cPBem@3jDL{RpLnW@NV9CNT?gu zifR2gK`l!m5iBU)GS*2O$^4NY$O&lxIwmRCAg=kL_3y%8=3I?q^SKYP`p(PeXhP;P zbIVa?@PsS_sA#<{RaOn9mojat0CcUI$=z)hWCT@pGJo6qgv3Xo-a-wzbH)MxlH@FT-;M~Pb^ebne;J9Xz$mYqA8E8_&e-m(jv${{DTIX@s=k&g z$`dkjBXxQl`DS*RLw)>qnq8tRp8#J;^k)fze=1U@CQ5QPG`ERRC7l}Z3j8xI=R2^F zdmbj3A;2}aoDncINZ4Y%$eJ&u*e^BjE%)c3ZW3dz1*}XQyfpp9QGT3me#vFspI;uH zDA+n^`{vFB|9fx$pFBL=1A^b}2%ZRaf5JF9@bm8}U~}GyES!ZY7pLLFaiP}G_(VZ8 zIpF;9I(O7V;;nWJw7X8!GSddM5N+Y)mv^G(T$%aG3(odep1^<+w)lBg=mhP>mfX$F zR;-2~#o_3?m8e?kLw-zXD6AZsQ#^0MTd>uQ6r;pYiv$A~ipxW5YH(7k7mWQJKb`^G zpbCK-_99e$ksQHvpC^I8b{$}YvE9q%j560hy0L`?h0!1Pb_g#O9l8r5q|mEFdw+(2 zg)`SXqA4>UZlNhLdp$$vzdpo#Q^pZ>6)BC~QI^~ArmR%4b=oB4H2hXagt)lvS90ro z;O#4*|0bB_f3wj`^rzh?AB%q8YF2!E$f^O3^-AWOa3cZJ^Gd+%=^0q{2c3QtNts8Q zk0PY>i|i$iWY2;9yMsR$H|54E2a4gi8$4_ff+C`p=tSA=yj7tviWHhhFtJz1KbDr% zD#oXw%$ZY!j-j|ZepzWW-XCWM9U#4Sfyt(Gnb~6o7-$|4k*c5PzC>;P#CK`Gn=8%M32Zop{W=h zjteq;p}?GNGtlX2K#(U!OZ|{o<=fv@gUDV}Zh8hSQXL+3R0X-7>y+z{SiEh!U9MQ= z_k+Z$u-R-AIR~#!-5#cytOAWehAE!;q0JEV!=n`qwBq_8N0nz{M}Y7`YbIPcBVKjk z3>`N+uDwOivC4C70am98H1l%XTQ70FXO;!vFJsFuHQh7}1{3TSg(1a#cFP10N@V>@ zi=(T3LPSZda_<8|1g?5DSYP0e=Fs;$_cNUNOssN^%>y}22owJ!NLN=c563FMZBtnR zfQiF_d9@>h+CnBYQ&nMAZ#$Lk(1Z(_oVamC5_8ME=L55_*Zn!28166)M@AfwFc5FE z0aj!nj%{Tnw7H<2SY?rI0O#|jlt&Whn>(rBw@aZPw^T01WjS{^3K2!(y%fb=3p}jA z(wTOMW#}%5AA5V*oX>g{lL|SlS23wTKAo>O zKAJfV{rKRMgSnlp)rKc7Hmyti8SYohQlUk-IL(bG*=g?9hvJU;jfa(+h;pYQj5(Iq zkG=R|I|X-%!zUIMc@>AaqdjipTUNY2mopcenT7mi7K+Q4%e#P+t&56t8srW^bWt3o z&8+|EDq$w_tWQL-&!y4st8ijb7>EA`&IQ7&(>v{qe&m~WMn{>^+rB4?xkTzpFMcu7 zV*Khd<{>kAk`bRaQlcLez+dgep$V@;K| z$zBF9Kefq>#MPepg-iCfOtf<=v}P(Z_G)JA!Q8pWaTf{CUVJjRoXW&tZxWwW9IO0_ z1%TW7RCJ~jJhQ5!4$ahXrmr7_3F_jEU##+CTYzDiT5h>*;&S-;)I#%(j)E|7tNRb8 zJikSnZg%Q#nNX%@>!1WN9B^>`fz{e;7i6#qq8j=@BZWEjXA5bZz+J>BwAU9T7ME4r zSvHS-@F$!v23V#=KGgkL05Yr9FlC?Qg#M{fwDx1jiG>60~l7*RqyN*CF0Y&>`>}d9Vw9djyH#ceqXb6#Tw+ua6e++ude727cGsOj-Qy{f=r2 z^7;6^KL7-N*9RH8;J0{FU|c9V>4+u5Ji6fD$FI(xyy2YdB;Q*iUh>`p44V|3Yx!mF zi5rHRUgIUTa$rj$#noP+W+|Z+5;wU};{W2EUdKtGH4m!+x9NOfdGW-rUCfz}(ZyBk z*$K5*#oo%lJbBdsA`BdyRJCCeK%zuaj#lidKUcQZM=ez67h~h4*|P^1vgegz)TSm} zYG8?tqTwi)`hA6pqMf6$IcvYmAB8HzpJ>~Ls_Lm%n%xAIB#6g}4S0{QrK>ElegC>L zm9s1tHyL#p#X|OhMGiVSVt;0)+}RneTJVdkmMOjVpAfL{yVK!!HLJXjU)Refi(gM+ zI}?p+wYsF1q|7h>gS}=lf68#i*q$33$sOUsfRfFRe@Kw*w;n#M`$-QeCkYxVA5^0r z0VR+rbEgB-_0*yZsx1}Q!4)(WjeC|H7Z|5|6Tcuv*kC^YxTd(l&kz4mB0Jw z^0g{oO8;H?+-&)!e)&?<_I-+8pz@a=UA|7`i|PM&Z2z~G2KXD}moGMJRsIvYZu%Wn zzR|G~oa$31;^aHFUr@cXEaMk%{rQOs{_=O1+E*GG<0R2Gumb@VB`i|;m zO1;nj(`RH(e;4t^2xKz` zHhBNn1>35H(JA-C?T+d z>{@14&hfk9Hmj^+>5EvHkCMFH2ftS}oc!ytIsb(i=aCvKH}Jzz{H7NC`+GN5{=~la zB8yJv*C=v)rbl~=9p6}6Rd6%LfUuVwb!&e@n2dgzZNO`&xARi7e^2WOtA)2FYRG;l z($TVG8$~hAc7xrl{aZF-uZMlA*d))DHjvFGR81Q@I3m-Q} z``WU`%AHH;YD3S)%FTMHKZ&&Nvw_jKzMtQ}K}7fAw7Uhx-EPyo#DL9`x+mCl+m4d> z#@0XQr+Dr@=PShg+kyx+KG7!?Ne)O=g?`dHZh5cFAan1;!}d;dx^=jS^!kF4fy^n(a=cJzzP zJ)F{3n!wB%MO$7&e}$$Oy~0(@vE_=MgFR!&mfm!F<9KFp%m$0-^mknqm7C+f(JjY5 zAwMy1Qko&=_E|1GQrdKq=Nx{n1K&P=3dvh+@pC#K9ez&WDT|+#{f@-XhpOgV(wu1Jr!~5O$`gk`@*{3^sas%+;SN#FdnQNb1B|o=0`FT!u5MF4MEnqVpjkhZB z(7@AZSr;O@0_D;vvf^cV$lAda2pGvYdn_DA!c?^-z0kOq>EoBduDAR|h-fKp?zV`T zKb8pwG>`pE7#KM=yxq6=AJB1TszD!#n4|=~)pAoBnhY={jUXS;ma=v#**x*XE*i2_ zT5bonm38*-tZZqdLMe-(hIeRV<_*TmAbJG}&;(LuQewg|EZT`^Q+A%bCgfu_qR`_$HAkp`| zWdvqg|7PFWp|ySK8T#EJ_TEaZ4BVV)Kbna;f@0s9f45=>S$Aya#8)@}wAb|OC~jP< z(APN)r?SSDu~cs5g+UB8F(GoAx;3sZI)jJ$g(+^ph5Dq zS~4+Y-J603voqt6t zz2kmPLf|yDgqlTjl4D$|h=&(tQAJql>e(bj<%fYQz)dTvUfWRxx|;MWPB>o6^I&mbQe8n=(_a%>E5Kc!}CF+R&&rFc(VAhcprF5+;u`N2oj* zy(?hXzO^|1q;e8A#-=V=T*y*S{Gz5QGyyM*%2db=0G8)O0xi5w;tsvg<46INDBrA%BXwm>N#J20qW zK&-N^S<^M2As{xEO_M!ks0TLyJnP4@F5U9mgCxmvTW6j@(WYt`#BKFhV*8YsrCp2o za9wxYxUgtJ9qj%-e>c-TnV&u>kgs3(CLf@R8guX)HtCXIk_4^gn8!#mO|HQ0ZG079 zHQ&HB`xr7tFl!T|?p{Dxo_+P_B<2*PmK<)ROnu)Oso3Ge4Sn3J?DiaT6U7lV&MrjU zQqC&B^Nv)`@?3w~xFF1Ti9@$6hgT;?5`B1I!@Dd*#hD&_eVniJKtb#C#XzD{2NW>+ zw^Ioh@C&}K*H<$>;kVXrUs+<{`*$jAQ2jY9C+}7xL1~@0ZhG(~o3 zuj3k4`P$mQtTB!hyreu^DDL#b=8~fp1<7x3bo2ddSSXucQoZaU!s0K*Ud3yn<-g>U zJ5`apne)t{*wcJ~Kh%qF_(!{-q==k#>?}>d@N|3gNiuqNe7&NOcbt%eTvrtFUexja z^+welpHeL1q<$ib;6nt+X-qE;6#I`fu13arX|02AOIjZmvqV8o&8`vgNkwk;veJrwOC4_t zdUa%{%m3G%hCy^|ZV89(-@@daPlUox4y>Y^=eNHc5Y3S^7|cHirc4UWa&7fWN{B!``IP0OHj~?rYw%3po_>`X}QJ& z0|SOK=j)E46q(2Fu}M!PabFn5AemZ{%muE%Z-?=TPsII8e-6ky=>vPVNE)j>S^T?5ENL?Jt86$-1-rN#!6|Kf|** zk{WxV4ntd8uZD|&k_QyQAO;%t&bIbl|5n+d1P!EtS|8d5HH?T=h9#{xl#bU>0LC`O z;eRh@5sqq$B=+MuUY_iO+&-`^mu*0w?d(y339;bR#avF&s?$@kg9qz}Ah30xGpO z@4z*icMBG4C3POh=bSkM)pE0z#Y-a02J#3_7B2k(?#R zmSn&;xe%*3aeU~JjdS`r{42ZmC$Y9u8?Zdmg4~9}#K8C*%jo@qq8+(&PBKrU zWmg&1pLH&#{{5|Nu`zyNVgYk-<1NeIlO)#m@Ru zEqxD6C1m015S7`6X9f__qmciYT$Neud&KUh-3_IQzT+&&h6uh)L+Ur;%k(YeLv#Ex zW^pxPhs{i$i0z+PqPon*enZ1vVx6trcedxa$hHyt%m!MiHLb?%`V*8)*HE#bR=69K z*wz2#+k>F8HVWsaro9dMDdg(@iM|_1VveN}%(1fvew&}fsKtC6_Ho6og?UYTGh=a8 zJIl;(whU+T8StV4HR;_Xt=!00)>OtK$E^NV7Y-=CXX8I1ul7$R`c47r+Qx4_kdxM3 zL3{}FLHDzz&*9yXoKJZ2OZCS*{_Q^i-BO=7U90E4ZQ1w46@^gEz4i?PG=lxxf<&v4( zBgrBpnay3ZfU$nFh{iasWMswGg}+U$g`vaV!q}IY$eABN*24i%4uBPK1Jm3U040a# z&*xZ2qVF%i1|Sykid`F2S!nX6(Bxh5UCk|XPfrYdltebNcf~~#LzeNA7 z?1wgHx>+JlrSD{u6{yGB8hs5!7mJ^5-?Z!9&e!hEG!2S0yNc7(IiAl_>(-|-sK{TR zK5eI_h2{Y|E!JF>RTf?Mcj6c(u4;uguF@W1Tx+3~$ju9A@ig=J#;RjRC7{?3oA}c^ z#^k!d{6OjKQVWCi^#pSGTO^L8j%Oaa^8ScPOtU*jE;gfj~@Mdl&AYNjHGG__`Ai`Ole;6rtFi-1QK|=$4YX#%sC4%kj zw1TGY%zkMy_EO$U!~z7Xmy?~P;SPP>hOPwMixlrW`ss! zl`W=tn4DnZvxBYp?7b8->|o*SXEMi|<5W!*CDBjtNQ80bn%ZoBitmSccMK^|4&-#C ziT(X+jy>7F`KcZ_{;acFS@Sh5;+P5ITeC~J(~0g8x{?F$xl7VQ-qI1fmlwwS*!abmrpbk{GzgiYPk zrC|&mYF4LOy|u^?tZdMy6xTTT-=xs9n~WSBB2s8SLMk6?LsoPZ2yPs_ZtIE$@S_V{OikAW z!tg45w|3+M_c4X3`(T-0&DR`U-nZRKA% zaEvth?|t@=;{RAqi{hv6UoS-Yuz#+6e1dBc-sBSu@k?jh0vl|BA7l$Wr2?CeDDbc= zFv1mBX$#EB7FekQ_a9MUo+~i(8Dz5uhuifVI-%eEH7lKUi5YGY?W~COK8&!&2VW)Ak>jn!a>jvNp z&7T%npywV{QVO=NQ7mF7wib%?LND&3{g%2hDrhDjJ;WfptGoe z$cbuey<3V;Zd`Ab(+&L_*V|RQAzMo3GIGX8mVi_@$+ZR-ne*=Mf~!EAL{(OO!mlmd zTPnr#F;ExG>D?)hzMi7_!9<@v%uNGxCxT$M@X>W{NdD_OyCS{Qdw_q$^vaY!?2tne z%FtBmunu8kDk=b_=5Y=~9zhTctWeoec$1dEdL0umG_La)URZR7kKCa;) z>7mbgtr-j{15RLX&ilc9R*-IUm<{(8w{OMh9p^!flEmdDMUThs&#PStoc_4mO6>O7 zT- zh);2~n}kCSsd!D?zsNWHzIlm~rE@O>TUSqE$=H2N4(9NuZEipbzVg>8wlOAm*F_Jo zkGpOa>lknai}Fn$AW{r?iH&}b*`?BO_2lfzt&$KzppqszdiKS;W$s3Lf9duKyl=JPdR zpfFf8JI#TPUQZ}%Tx)UKFaiUbhjkL!xV9$c>&$ttldhcKnbMIn;hlr6Ilc-Df$5{FBY`P2=J%I&$f5wEtaZUyEW-qtV}pvk^pl6^;$rIU5Mp@+?%c?RB_zKQ$Y zzTAvGsR#C}1Kk?@wj(|Fq7)tN)v0a@-1I-lA%it?U(Mv^1X_osxSKe?hqh`bE~G!@ zez>{C{wOj^`I#5Tg0>-VkDSKxALe}3JIEjA89-!SI&x_2o8^C<%m2ice>y0?!Ip3M zXXQi7q~!A3fZlM=oCyT(vpYteGG%=BzZGg!>;-Q5y|Hrk zmtYh4ugnmy#;UDI{( z*03F3?pCvrb)}=AOHmc(vH3wlOlLtQolX6X9hAuz5c}trw;2#+FX)g6?Ezm?80~E5 zS9{ep157N`qj=>Z=(V^oHU+bWs zve0U7x>wf_CP-TgU^8h&}+ zKb(Go&19(QBgkq-Y~cCu9HNwi0%21pmqW>wm%g#=$Gc z-2JYIw1(w$R*^OB?f2rCqUZAguAjThBNljLPR{JTf>^9$h)`y!`TaP-R7Wj2DEcvA zhu#tFjxG||Wd1j!e6ZJneb#-rv5F6NgELSc;4FD+Md__@7LaGp?>rdkM&Ef!-+nAA zbK{e}7bf-|Z5a6a`}g2U<2?s3BzG`|k+}8!lhIBsLDL^bJ3p8K^|%a=Tuk0p)9Z}3 zcKfAUD!lT}=~?wlit7}(R%%(5_8_-1G zx8S8HYluytUE@pUNsD-3=wy6Yc8rpW-W z4kiO+Xg!RP7wZu=>{IyMfCRbCgXqZ6} z9^()7SByoy0OX_vqjs+KSdxMHorx^PEfjIp zida|?jAt(zrw$KNFixne@j%|3u`75Ft>!${b|0hT*v&&IoZ*DV0(2Lr%&kkiQiCIe z%vt{ECn&#QS{Z{f#da9Tql@yr%$fLHu=`%al97iA5ci3O% zYyT0A@5{#bK0nla4#@-uY5p+O+@Hr-<$r%s+~G`|>Q;amoMLlw=JdpubZ>eel*WRf zey01fa*o)SxdD#&KcDBq_|2$1&L_)5Ms9EWt(lIdmM>_h)3HB&*?ZdLVlOic_S!g>7n=1sQAO0P>i zDf?NfdEeaL$;;d0EA^HMxezqEq;sXN-At^MsWf>zhJz>dBx(Kls>bK6GiZH5WXpuY z*KGU^Dh$l8+rT_t7rLR?A%En>!Gihr>$y4WPS-FT{BpOP_D#D?rP$%Tzj=u#x2i|T zQ`}mxUW)RZ`YZeeBoy1kD@^80e<7(v3Po5{=VqnM*A{E);Hzlz_dBXBwM=rBc?P!P zx5{2goVisHIqJ*;s)gxBJD`cDyJ&2&}kogw(^Q!B0>N=;x_tslq zUdVB~4${nj)Dco`2O;%p|4rOd6?9~Gp`xQFEgf0vK~6};*IPP5J~$>FWvk{*=^HH z=3BaK+|juEE3VSw%U7_L55x{iMM+`H0Jb1*n~e({R|$)&%o*-;l&2+$L(nh+WN7H) zl8gV*ZVP=~h5pjWw)Z=3;poJa2}3tuqJpI*M0Qqb$k% z|B=+%j~-k2)BeCj6w1uKz-!;+?fSDW^w3=VSi?QbdH=adY1eONX76BTrs^kUr>6Fv zOwCjMsrjGRXQw77G=ICm^%n7oEGD0Ts`LtCo@q{^Pw7oe4@p*ux#f%)^3|Lh?5dV{ z_C&i9FKHJM%pNAz%yh(`2pLc7*EG#^;FLRNN{eeGMKMbsI?+wg7p(^9S@)LPWZ|W+ zq`vIJKCjN7k>)m@K+)UZ21RnV<$kigM{Fle?`D4$w4xRAV|FSYEj;pt`B@lR_5+C4 zpP#f_5s)VR;+H2*IjANSX|H=)b@D6iktM7|OhBS345`(+ zU8x}1#hHBjQ(duX_R?zI+i`~^g^Jd>Kd{nlH1}mf^fF6+aX}Ce?0)O@q5gYPj&5Ee zwQsk?7m;T_G$%yFqwJ1Ta{9O%EUmuv9s}_i2Esgbvm@xR#k=`|UX%IfZ^vu|hsFQd zPxnkumvq7lBz05Ld_SqkynhqZVAyp2`0yXj!oPCQ5#wxyB&#;C8*%g7OF9p`XboW# z-GTaAnm+MUHxX|9u~7x%Ka&`PMJ(GN(=r6}l1BX|Ji1j=Zo{9=DsaS+fIe{OM>Z*J z;8AWkr6Vboma zr?m@Dw9(#l$>-hWevGgdrq-SEi(|&D@>`>7MJAeGmni-%FN8Ni(&VC!+MGq$jO96< z7!y{(+MwWwcKpeDACX_gHJ={i9oh?-w?D)>Q#Ky^H#sSn_@G-Cedxs6yu>M-3mn}q zn()e-_b%k79k4QeZ!~v@S5aH4PTyzSm)VS!t8eVdghd$%v5@Ibs`>y5EO&|#Yn}vFxZ-x@#RzAWxblaH?t;^tS*RFYzxJvL&%Z% zj!0|fxCx=vr<_W_PR+Th*xNlK@n1*dZ&vNjRPEc8TmS3oj-^i|!VIPWllo7WBUneI&w%0TDzm;=_BKw|lay0%u zJw|x+k`K0H5%<^~eU7F1OeCWr&mdra7!9=!_O>inKK;w|C8hE~r64n%>JhP9mHX@W z27(gf(lIt7*{f#?F*UuH$tu>^VsrVSHMTU_xZZrCNB6m&(eMZC`_q2Z;-^a<);sru za#1J{9_3BfGYB75jlL6EfB&)$-C&)QJ_M~QM75eErm>UX>WW=+3dgUsm$2cq>8^!O z`Ndd~{R=$^wmqeY8(dv0<{3RbO!2v|DbTy>uFie68e3E5*BVu@+U5=0DiRyE!~D@o zZ~jmvA98_3-nX0aE+0>_+Ks2(peCkD@e@>uxEs{TH8<{_;wWKN<5P>XfzUM%k4W8ttZKLN}F(TbPn9>?hJn*CBFzCFX? z82|b>oJWzf%Dm(%H)sd!w%3mDcI~_fzv|}NvpxmyN_Vr;=Elw4{vl&*#U?~+v|2j9 zkv>7|WitO^g@>`KA9fObCI4|cnSlYqqmoG zq2Wd;mtuC`nA1=kTQ9gd4TFN+NCOrvdmc4*XI^eSL<>3lrYk>uPa^ zmTdQ!2S2wp7k213UYBr!xDj{@kUX z^n4&_pXH~oaOn@a^nW}Tr1$dE8(sPWm;P(TWwG@AXEj!0p{0K_&84r)mfvpEn=CqK zu>W%D-_52!?w99y3G>GccIgXuQ@U>u#jQ)@yJT;KI=-Bt-i{O`Kz9zQ|aR zQ$KWbqkS;>Jq7I;^>1#JER^($pJkj`4QNQU9ssufjXye?Wh*Hz@Hvxv-d#8uSx5oOSCKJo`r`Jp}g#DSknF% zv9Hj$U4)>Yy~wK=IEdug4Hjwu&F-|;S>j9UxJR~c>_E&#c8~6QYYEhP4!QB$U~}K+ zCSYtMQq`xPE+;yUr{d7 zH`Lnn(Vv0-bd<>4Lb@5RQrR}zDf=ji;E!iVd#3dYTe4raWSNDGcw~O`1)J3TF+^qi zJkTcj6K;h|UHwcza{I4wwLNU>cd5mzgVa5wnx|c5lgntPbTektb{X;6f4PKpIYIv( zx4`nhQR@1)_iEdeYlj5=TPbiiQp(~teWF(30lFS1-88Gx?D)Zc zebo2$8}lyEkWGX7fmdceay3mC;+f!JSNvm|-y99U`3+f2PiVuGI6&|22G9^CU9iof zWx$X5aFRZp#)p4r-Rofc-b_93q%iwCG50Y2-;l>_)hS_gyE$uN3n0Jm6Mv85{h|rR ze6TtZC!uw8nYhL*8;)iz`97?YVg>(aR-dOQ+fn}9Lb`8PpVKuij6jR67mKjz??!6l zTi4`RF6HohNLUB|<>q#`fb9?`&ZCq|xAY4fi~q}AmUBKJi{_Q^W6S$f@?4jG?UOz+ zkp7^bZWptDF8zxa(Mm05q%ZK(MZV^JvHfIzG-v|p)BN-mO8<>ZFYA;_iZOPr*os`V0B$(r0HPByfK+xD1A)pm@&@|U1N>x36z)td9JvPsRF!H$B^ z57^Wu3)l2>D4cPC44O(Be?MLQHSaqB1NM?GW~A}=(`Ab=zj5i^i>O21Qz z6Qr9o$ToRuCFl(>j#a!c+(`xwcanj_SsD1B4ah50fd1_4$Lx4KA%BJv)w%u!%Xm_E z(e(TBMdmx>{cx?9!Fy^sh|;lD(fak^XFKm! zGWT?8fzyx5MC9wosk0oZ={tP!Bgo*U+GqAKd+a>1+TyzcL-I^AM7ejMVt=Sf?lU+y zhnlbC!Rke9Ot4!T*D9<+j(xdqWePI~kyGv4mCCF=%m^c=^=X`6+QY_h!)Hw{z%@S8Hd^xXRt4lW zNgr@|&{kRVV2}>a%N5x393Rj)=a`fD0CliGHBXfIgPkt%65|5 z_}0lp?o2D4VUzdV0-(HsjPS|l%?M`#Y z4NlQU)`90JYa-gKApHnUOVRLYlQEl3B@6XpvaiCYy6yD4P7`dFP%fO2A%9>cxsa0Z zrn07^0o^iFXe0K2m7aei71(pXT9J!vBmo`6lmo&`=Hww5_=*3w#hLGmocaFkK{ET> z@I@A)OvX3}JeRgs60X+@{4=Gtv+{Lf#EjS-bvX@hsb|GjkuMrx#_cexPZ2Z)57{!d zl#Xdc-r5}4Cg-cJ+FEobBu&q^bgG`HhXFU3C$uAm=lRjTI2~fP%3Jx#*kufShY2VOKh~NL} z;&dc@-be#;FqPk6WW_ zOlo*X&Y=BXMO9&_c^5Dgr`~Thjo#(ESIzQbt;Ny=)+SDtQ)?9aE>u}###&%fQV{8b zdZrX4&e!z^r*ch5Lw~DRkGh|7i?(UX2z}<78+WHBAF8PCG#5>ot-P^Kj&`5*~S0Eo7Cg(iP8hct~E;qxDet(9d4MK#47+$V*Nu$n@eI z@7_$F{s!g?YTzK;R`U!>T7cZWU2R9uD$3v}%5Nc*p+J z)+uRboQ(Hb{pNVCw_P<5^o-Xf{v#nG=rD35B?*vRpixJmcwMWD@a)-n3$6H41m8aqBBlbZ$ol{JY ziClcxjX#m;zt*gu1-r(X!F;Wh0m|}o%SL>S@pK!^YNkns?G#^dHM3F56ZDUsoBp#* ze>fGKq4MWU|9sMH|IA)LeWv+{DNXuAcrjYR%B63x=|K<(ahS*SC7FLiuFogT13n1P z^mA1_@d#Bg1= zYkvAUTlwHpAX)Y{*l(XLBfE&{>Du>oX{4+wt4*z9NNUYjT^GN%+gA}FU+(o2>&z4q z&8jN?{Mc1;_XR<7SFeGcySC0sT+di+HGll9YwH7kTj7uHz638Ai(CiggUx)!Xvv+ zTLz?u&3z8Dmt|{+*(~ypW!3AoCef6(Wlqq8QFPF>HO^Er$5j)Uw%TC={x9LN!$4?DO@;uunUrRhBiP$ zyowd#X!9~z{=^q)KIZOWPu8M5cZF8>-MiMK{(&w0>}xF~U{<2OfQnM_KlB1%k1%y);}Sp<>9As?fLSiuDgy4qj!K`Su#L7{6S7*k`!feSIwET z#A97vZ`k2T{G-VJJ(1P}pNkCT+9G?+B){J}Yn1H^Ef;|0@8H!n7X$gVh%spcqT{4BNF+@3-9khy~)?G_Z zOvnZRN#7zBhrg@)(A1af!rT^fE58hKpZ{j6S-tNiPX(l}4njrNA%tp8>p*`Ns19@? z*42ZAbb-J3)jY8KlSw}9TO8G@(KGEq&|>?yOfX9Yovv87K-r;^yjnAfLS3$w@+|g3 zSQ~q$U6+3VwGd0qz3wtYAH?E{}y@5k+`l68=CtnGFn!wL6rX=GCQ`SGi4{~JLvn6y}hX`FHZ%N0m z15DdG%nipoOfh{`g860VFhYq+Fph=-s zsZ6g(vbNA`-xlSvQoJKiio{>hC1H_VZr>gU@l?FH=zr3uh{56y%b8eflBtIpSc^Ub z{$lOLixuFsod5F+L(AW$*XxS;li}cD8}5-HR}bm-n_ zvZN?d(H03s+o~(xtbZ=sQadk;gi=QF4WCoqSm|(UIVEWI+XpfkAz`#w80G%N^lY)o z_#wYpoHd5e_83X&_<{B6rnyt@C|onVCg7MopZGM6c~7CMwV*4<#D;N9?)3i_|J?U) z@XwD!$8OyJ$Nba!-~QYD^PGRyiT_{m&*}d+`R8T*{>d}&qER4>h0g-3xsFSGq^XisJa=%8vfyBHKcovDl&F#i4mO(f+-2uYSImbloxvOQ42V zY&VuJRyV}Ko7)$jr?U+EU-2ro%o`|ffn%xm)_C5&PUB@1VppGU&Q&{a)}IpoAkfEK z&B1eNV0@2bCg-2Qa5qv@8zyY?qL+Fzztdg{aw>A!^f#V2I>Gme4J z+0G2n_|!->b0;gh7$7hB`0df4puA#`U-UxJgE;Hee^zT0+}cWhvQ5AOOYCB)7bo}G z3<#kg(cNSC_}<^Ub1!U}bd|c|+8^mypCFvTb6+*qqD|UIP~-N^+}2E(zeSbAtIa#1 zD%Q4mF}E|1$<4g2))grVgoNN-W+j*v0ePyWR@{r*EniW$YBFnumvaeGP`sF4Y(YNj zwEoX2QyXu~2`&FA=(OX3|2U98G%pKBY)Rt8rL#Z*rUeEdw&MuZb~BUdF(KZkF(RA5 zfkl_o(mt0|#SSc9oX_qgbCFj0Y(o#2H!pPafHqpEZXns^r^;$&)CDF26-6pOoc$UA{kn}Y?%;s2%%{LfVJ`4XZU!GbnX zl5vRrQo;{T8H`3)U9U-u{)U(2v$aG+IOZdZcm>yxA<0sdi_tj0L$4e_ttVH-uEndp z3&nQ3qz|Gbtr;*ia}^f4#iF{_ zKlh-#>}8?Y!!FY;wOz~4SqRvtg0kqkQ`YYvg=;=IMT4{Ct(-SR!ZMEPkR}NK@*SGo zViT4>R_v&^CRYyU@9}b>h8^ZDSiL5BvCCoeGHPX-1m!|PDTuZ^-ks~l(KNHGlmZy0 z)mrnm|6)_t_%FhP+0Kg_0B8R=&c}cH-eXacqo4aa@K0EN7!QCP>dXC*I$?0DP&&2b z^ylhEPElbnR;QO7bmP-ZF}-MjMsoz00eYVSI_w5WQ9wBfF^srmq17WV^5u)ejE_;d zWaVTH-I|f}GS_&?C*AnG4|Wf`@sWQ4nYK@L#e?xx`GiXf1?4%L@ubEG`J>`vjnc~+ zr9Zh*vK;$Ejgt1~8|FDK%rK}Y+yi^MLq4ks;chLvPv)&K7igJgxa@*QW}W-8OiGRi z44I|dGKP$hJS-V@$OL~dekyvmqjs+UVn;34e-U!b0KFvhPr&ibxdCqaelU+rtz6`& zx61c22m|Zk8{>-6f4OD?>sL;&it_eHBmj9>E>=?a$%17W{-pIN5*V~+=`t1*w$YEBVnXe$Fi;T(Xsmc>Q{dI3R4j8 z3wNLyzJLKX6DHC)x!a`viR+aGqw^VcV9}Xi&o1!kc*%Q3Visty*er+>JzHWAv?re} zDN}-UH;#XF=x|Bxu06e!`d4{#VXZm5fVg23~Ycb%i7gi zUus+JtG2aOtEGTe2`Fz`1yL*VuSNY=C$4Q#TVAVqzP~efHwmDBpXcGD*?aHYJ9FmD zd7Cq5&e$>9=Tgjnvm_pNpg%WnLcS=z^;p537_;zi80*@ofhok3js`lfp>K2(iO7?s zq{l40Gj^jn^yYfpwYBAhc}<@vqs(j+(4s{FEeo~)wpoKaO=A-db^OS$jVo}i?GkIg zJT7aI6=-(*g&)$mugH4}19ortihOyT@Q0DRuqx|E!YsQ^op9CK#`+QK>I+w3G^-xQ z`jT<9zmfjk*ws+3Q$g}v#AMDpc5YQ-Ox;j0)r@!BH=wMK=a!p(y68~sqww(rlwM!{4s9mDJ%k<}Q{lWhK9BG9nuToZp zC^o{)5RyWsQs)&?LtWuO+4zO?w$%Yza1(1ez>z(pjxdokVYqsA0KaJtn%$&9%N|4x z8W;vJvbd?@%#IZFNdBlY^iRF|&_Kl%fhLDODi{%NnJCs~N%-?B5myeEn!STOh)-TG zGVr6h#-(py)19rL*yNKz#|lLTxgi~$oyJBF)2#qDQcw3dHob+QDRY3D(!=t%ccI7! z^e*@I4Nxt&`&>+|+3brdw(21-dr)$LwhEBp%N9E~t<%$&y zdCSP~suvsU(?z`|q+<_|cgMavRhZ2&kb#>n{`ZCB7zEb0e6L;Ww-r>EW0&0AAcQ%6 z3fVtzepqBH6fv*s^+1sJTgLL5cQ5&r`kY5^$0ge3h{Zfj^H0*6H%|^yct>vcA}+D2 zMB^hd*K>Y4KKveORY|L)=!`LA6`C5V6Jy>SWGEpjvfT9@CY0ciqF#ivliTlf1EAX`CiID6q$dI8lYtl%2y2(i2t!XmP_

}kCbLJp+*Y7FN+ZD)lbii;TxXR)qa=! z|3VHv@WUrv_z?}hf(OcCkM zwBkjc8kkOWx)WdaGA®Oab4+wS3$^()tmb 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%0A=4jhX!ByGG8SJ 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

t2B(kZ;|zX}2rXHq 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 z