From d593fce014cca23046276c887d1a4e98a39346f2 Mon Sep 17 00:00:00 2001
From: Table
Date: Sat, 29 Nov 2025 03:27:19 +0800
Subject: [PATCH] init repo
---
.air.toml | 45 +++
.dockerignore | 65 ++++
.gitignore | 83 +++++
Dockerfile | 57 ++++
Makefile | 237 ++++++++++++++
PROJECT_SUMMARY.md | 236 ++++++++++++++
PROJECT_SUMMARY.pdf | Bin 0 -> 243591 bytes
README.md | 410 +++++++++++++++++++++++++
README.pdf | Bin 0 -> 265958 bytes
cmd/main.go | 102 ++++++
config/dev.yaml | 41 +++
config/prod.yaml | 41 +++
config/stage.yaml | 41 +++
docker/docker-compose.dev.yml | 48 +++
go.mod | 78 +++++
go.sum | 242 +++++++++++++++
internal/handler/router.go | 133 ++++++++
internal/handler/user_handler.go | 381 +++++++++++++++++++++++
internal/middleware/auth.go | 125 ++++++++
internal/middleware/cors.go | 31 ++
internal/middleware/logger.go | 49 +++
internal/middleware/rate_limit.go | 207 +++++++++++++
internal/model/user.go | 94 ++++++
internal/repository/user_repository.go | 105 +++++++
internal/service/user_service.go | 235 ++++++++++++++
localhost.session.sql | 2 +
pkg/auth/jwt.go | 131 ++++++++
pkg/cache/redis.go | 187 +++++++++++
pkg/config/config.go | 135 ++++++++
pkg/database/database.go | 98 ++++++
sql/init.sql | 62 ++++
test/config_test.go | 156 ++++++++++
test/middleware_test.go | 171 +++++++++++
test/user_test.go | 90 ++++++
34 files changed, 4118 insertions(+)
create mode 100644 .air.toml
create mode 100644 .dockerignore
create mode 100644 .gitignore
create mode 100644 Dockerfile
create mode 100644 Makefile
create mode 100644 PROJECT_SUMMARY.md
create mode 100644 PROJECT_SUMMARY.pdf
create mode 100644 README.md
create mode 100644 README.pdf
create mode 100644 cmd/main.go
create mode 100644 config/dev.yaml
create mode 100644 config/prod.yaml
create mode 100644 config/stage.yaml
create mode 100644 docker/docker-compose.dev.yml
create mode 100644 go.mod
create mode 100644 go.sum
create mode 100644 internal/handler/router.go
create mode 100644 internal/handler/user_handler.go
create mode 100644 internal/middleware/auth.go
create mode 100644 internal/middleware/cors.go
create mode 100644 internal/middleware/logger.go
create mode 100644 internal/middleware/rate_limit.go
create mode 100644 internal/model/user.go
create mode 100644 internal/repository/user_repository.go
create mode 100644 internal/service/user_service.go
create mode 100644 localhost.session.sql
create mode 100644 pkg/auth/jwt.go
create mode 100644 pkg/cache/redis.go
create mode 100644 pkg/config/config.go
create mode 100644 pkg/database/database.go
create mode 100644 sql/init.sql
create mode 100644 test/config_test.go
create mode 100644 test/middleware_test.go
create mode 100644 test/user_test.go
diff --git a/.air.toml b/.air.toml
new file mode 100644
index 0000000..55d3c51
--- /dev/null
+++ b/.air.toml
@@ -0,0 +1,45 @@
+# Air 配置文件 - 用于热重载开发
+root = "."
+testdata_dir = "testdata"
+tmp_dir = "tmp"
+
+[build]
+ args_bin = ["-env=dev"]
+ bin = "./tmp/main"
+ cmd = "go build -o ./tmp/main ./cmd/main.go"
+ delay = 1000
+ exclude_dir = ["assets", "tmp", "vendor", "testdata", "build", "doc", "docker"]
+ exclude_file = []
+ exclude_regex = ["_test.go"]
+ exclude_unchanged = false
+ follow_symlink = false
+ full_bin = ""
+ include_dir = []
+ include_ext = ["go", "tpl", "tmpl", "html", "yaml", "yml"]
+ include_file = []
+ kill_delay = "0s"
+ log = "build-errors.log"
+ poll = false
+ poll_interval = 0
+ rerun = false
+ rerun_delay = 500
+ send_interrupt = false
+ stop_on_root = false
+
+[color]
+ app = ""
+ build = "yellow"
+ main = "magenta"
+ runner = "green"
+ watcher = "cyan"
+
+[log]
+ main_only = false
+ time = false
+
+[misc]
+ clean_on_exit = false
+
+[screen]
+ clear_on_rebuild = false
+ keep_scroll = true
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..db2cdf0
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,65 @@
+# Git
+.git
+.gitignore
+
+# Documentation
+README.md
+doc/
+
+# Build artifacts
+build/
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool
+*.out
+coverage.html
+
+# Dependency directories
+vendor/
+
+# Go workspace file
+go.work
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+
+# OS
+.DS_Store
+Thumbs.db
+
+# Logs
+*.log
+
+# Docker
+Dockerfile*
+docker-compose*.yml
+.dockerignore
+
+# Development files
+.env
+.env.local
+.env.development
+.env.test
+.env.production
+
+# Temporary files
+tmp/
+temp/
+
+# Node modules (if any)
+node_modules/
+
+# Test files
+test/
+*_test.go
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e337e78
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,83 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, built with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# Dependency directories (remove the comment below to include it)
+vendor/
+
+# Go workspace file
+go.work
+
+# Build directory
+build/
+dist/
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+
+# OS
+.DS_Store
+.DS_Store?
+._*
+.Spotlight-V100
+.Trashes
+ehthumbs.db
+Thumbs.db
+
+# Logs
+*.log
+logs/
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Coverage directory used by tools like istanbul
+coverage/
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Environment variables
+.env
+.env.local
+.env.development.local
+.env.test.local
+.env.production.local
+
+# Temporary folders
+tmp/
+temp/
+
+# Documentation build
+doc/dev/
+doc/stage/
+doc/prod/
+
+# Docker volumes
+docker/data/
+
+# Air (live reload) temporary files
+tmp/
+
+# Test cache
+.testcache/
+
+# Go module cache
+go.sum.backup
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..585c14a
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,57 @@
+# 多阶段构建
+FROM golang:1.21-alpine AS builder
+
+# 设置工作目录
+WORKDIR /app
+
+# 安装必要的包
+RUN apk add --no-cache git ca-certificates tzdata
+
+# 复制 go mod 文件
+COPY go.mod go.sum ./
+
+# 下载依赖
+RUN go mod download
+
+# 复制源代码
+COPY . .
+
+# 构建应用
+RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o main cmd/main.go
+
+# 最终镜像
+FROM alpine:latest
+
+# 安装必要的包
+RUN apk --no-cache add ca-certificates tzdata
+
+# 设置时区
+RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
+RUN echo 'Asia/Shanghai' >/etc/timezone
+
+# 创建非root用户
+RUN addgroup -g 1001 -S appgroup && \
+ adduser -u 1001 -S appuser -G appgroup
+
+# 设置工作目录
+WORKDIR /app
+
+# 从构建阶段复制二进制文件
+COPY --from=builder /app/main .
+COPY --from=builder /app/config ./config
+
+# 更改文件所有者
+RUN chown -R appuser:appgroup /app
+
+# 切换到非root用户
+USER appuser
+
+# 暴露端口
+EXPOSE 8080
+
+# 健康检查
+HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
+ CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
+
+# 启动应用
+CMD ["./main"]
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6586b3a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,237 @@
+# Makefile for Yinli API
+
+# 变量定义
+APP_NAME := yinli-api
+VERSION := 1.0.0
+BUILD_DIR := build
+DOCKER_DIR := docker
+DOC_DIR := doc
+
+# Go 相关变量
+GO := go
+GOFMT := gofmt
+GOVET := go vet
+
+# Docker 相关变量
+DOCKER := docker
+DOCKER_COMPOSE := docker-compose
+
+# 默认目标
+.PHONY: help
+help: ## 显示帮助信息
+ @echo "可用的命令:"
+ @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
+
+# 开发环境
+.PHONY: dev
+dev: ## 启动开发环境
+ @echo "启动开发环境..."
+ $(GO) run cmd/main.go -env=dev
+
+.PHONY: stage
+stage: ## 启动预发布环境
+ @echo "启动预发布环境..."
+ $(GO) run cmd/main.go -env=stage
+
+.PHONY: prod
+prod: ## 启动生产环境
+ @echo "启动生产环境..."
+ $(GO) run cmd/main.go -env=prod
+
+# 构建相关
+.PHONY: build
+build: ## 构建应用程序
+ @echo "构建应用程序..."
+ @mkdir -p $(BUILD_DIR)
+ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -ldflags="-w -s" -o $(BUILD_DIR)/$(APP_NAME) cmd/main.go
+
+.PHONY: build-windows
+build-windows: ## 构建Windows版本
+ @echo "构建Windows版本..."
+ @mkdir -p $(BUILD_DIR)
+ CGO_ENABLED=0 GOOS=windows GOARCH=amd64 $(GO) build -ldflags="-w -s" -o $(BUILD_DIR)/$(APP_NAME).exe cmd/main.go
+
+.PHONY: build-mac
+build-mac: ## 构建macOS版本
+ @echo "构建macOS版本..."
+ @mkdir -p $(BUILD_DIR)
+ CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 $(GO) build -ldflags="-w -s" -o $(BUILD_DIR)/$(APP_NAME)-mac cmd/main.go
+
+.PHONY: build-all
+build-all: build build-windows build-mac ## 构建所有平台版本
+
+# 依赖管理
+.PHONY: deps
+deps: ## 下载依赖
+ @echo "下载依赖..."
+ $(GO) mod download
+
+.PHONY: deps-update
+deps-update: ## 更新依赖
+ @echo "更新依赖..."
+ $(GO) mod tidy
+ $(GO) get -u ./...
+
+# 代码质量
+.PHONY: fmt
+fmt: ## 格式化代码
+ @echo "格式化代码..."
+ $(GOFMT) -s -w .
+
+.PHONY: vet
+vet: ## 代码静态检查
+ @echo "代码静态检查..."
+ $(GOVET) ./...
+
+.PHONY: check
+check: fmt vet ## 执行所有代码检查
+
+# 测试相关
+.PHONY: test
+test: ## 运行测试
+ @echo "运行测试..."
+ $(GO) test -v ./...
+
+.PHONY: test-coverage
+test-coverage: ## 运行测试并生成覆盖率报告
+ @echo "运行测试并生成覆盖率报告..."
+ @mkdir -p $(BUILD_DIR)
+ $(GO) test -v -coverprofile=$(BUILD_DIR)/coverage.out ./...
+ $(GO) tool cover -html=$(BUILD_DIR)/coverage.out -o $(BUILD_DIR)/coverage.html
+ @echo "覆盖率报告已生成: $(BUILD_DIR)/coverage.html"
+
+.PHONY: test-race
+test-race: ## 运行竞态检测测试
+ @echo "运行竞态检测测试..."
+ $(GO) test -race -v ./...
+
+.PHONY: benchmark
+benchmark: ## 运行基准测试
+ @echo "运行基准测试..."
+ $(GO) test -bench=. -benchmem ./...
+
+# 文档生成
+.PHONY: docs
+docs: ## 生成API文档
+ @echo "生成API文档..."
+ @mkdir -p $(DOC_DIR)/dev $(DOC_DIR)/stage $(DOC_DIR)/prod
+ @echo "请先安装 swag: go install github.com/swaggo/swag/cmd/swag@latest"
+ @echo "然后运行: swag init -g cmd/main.go -o doc/dev --parseDependency --parseInternal"
+
+.PHONY: docs-serve
+docs-serve: docs ## 启动文档服务器
+ @echo "启动文档服务器..."
+ @cd $(DOC_DIR) && python3 -m http.server 8081
+
+# Docker 相关
+.PHONY: docker-build
+docker-build: ## 构建Docker镜像
+ @echo "构建Docker镜像..."
+ $(DOCKER) build -t $(APP_NAME):$(VERSION) -t $(APP_NAME):latest .
+
+.PHONY: docker-compose-dev
+docker-compose-dev: ## 生成开发环境Docker Compose文件
+ @echo "生成开发环境Docker Compose文件..."
+ @mkdir -p $(DOCKER_DIR)
+ @echo "version: '3.8'" > $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "services:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " yinli-api:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " build:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " context: .." >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " dockerfile: Dockerfile" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " ports:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - \"8080:8080\"" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " environment:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - APP_ENV=dev" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " depends_on:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - mysql" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - redis" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " volumes:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - ../config:/app/config:ro" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " networks:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - yinli-network" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " mysql:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " image: mysql:8.0" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " environment:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " MYSQL_ROOT_PASSWORD: sasasasa" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " MYSQL_DATABASE: yinli" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " ports:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - \"3306:3306\"" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " volumes:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - mysql_data:/var/lib/mysql" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - ../sql:/docker-entrypoint-initdb.d:ro" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " networks:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - yinli-network" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " redis:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " image: redis:7-alpine" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " ports:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - \"6379:6379\"" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " volumes:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - redis_data:/data" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " networks:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " - yinli-network" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "volumes:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " mysql_data:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " redis_data:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "networks:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " yinli-network:" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo " driver: bridge" >> $(DOCKER_DIR)/docker-compose.dev.yml
+ @echo "开发环境Docker Compose文件已生成: $(DOCKER_DIR)/docker-compose.dev.yml"
+
+.PHONY: docker-up-dev
+docker-up-dev: docker-compose-dev ## 启动开发环境Docker容器
+ @echo "启动开发环境Docker容器..."
+ cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) -f docker-compose.dev.yml up -d
+
+.PHONY: docker-down
+docker-down: ## 停止并移除Docker容器
+ @echo "停止并移除Docker容器..."
+ cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) down
+
+.PHONY: docker-logs
+docker-logs: ## 查看Docker容器日志
+ @echo "查看Docker容器日志..."
+ cd $(DOCKER_DIR) && $(DOCKER_COMPOSE) logs -f
+
+# 清理
+.PHONY: clean
+clean: ## 清理构建文件
+ @echo "清理构建文件..."
+ rm -rf $(BUILD_DIR)
+ rm -rf $(DOC_DIR)
+ $(GO) clean
+
+.PHONY: clean-docker
+clean-docker: ## 清理Docker资源
+ @echo "清理Docker资源..."
+ $(DOCKER) system prune -f
+ $(DOCKER) volume prune -f
+
+# 安装工具
+.PHONY: install-tools
+install-tools: ## 安装开发工具
+ @echo "安装开发工具..."
+ $(GO) install github.com/swaggo/swag/cmd/swag@latest
+ $(GO) install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
+
+# 全流程
+.PHONY: all
+all: clean deps check test build docs ## 执行完整的构建流程
+
+.PHONY: ci
+ci: deps check test-coverage ## CI流程
+
+# 版本管理
+.PHONY: version
+version: ## 显示版本信息
+ @echo "应用名称: $(APP_NAME)"
+ @echo "版本: $(VERSION)"
+ @echo "Go版本: $(shell $(GO) version)"
+
+# 默认目标
+.DEFAULT_GOAL := help
\ No newline at end of file
diff --git a/PROJECT_SUMMARY.md b/PROJECT_SUMMARY.md
new file mode 100644
index 0000000..2d60f11
--- /dev/null
+++ b/PROJECT_SUMMARY.md
@@ -0,0 +1,236 @@
+# Yinli API 项目总结
+
+## 🎉
+
+以下是项目的详细总结:
+
+## ✅ 已完成的功能
+
+### 1. 项目基础架构
+- ✅ 基于 Gin 框架的 RESTful API 服务
+- ✅ 清晰的项目目录结构(cmd、internal、pkg 分层)
+- ✅ Go 模块依赖管理
+
+### 2. 配置管理系统
+- ✅ 使用 Viper 库进行配置管理
+- ✅ 支持三种环境配置:dev(开发)、stage(预发布)、prod(生产)
+- ✅ 配置文件保存在 `config/` 目录
+
+### 3. 数据库集成
+- ✅ MySQL 数据库连接和管理
+- ✅ GORM ORM 库集成
+- ✅ 用户模型和数据访问层
+- ✅ 数据库初始化脚本(`sql/init.sql`)
+
+### 4. 缓存系统
+- ✅ Redis 缓存集成
+- ✅ 完整的 Redis 操作封装
+- ✅ 用于频率限制和会话管理
+
+### 5. 安全特性
+- ✅ JWT 认证系统
+- ✅ CORS 跨域支持
+- ✅ 基于 Redis 的 API 频率限制
+- ✅ bcrypt 密码加密
+- ✅ 多层中间件安全防护
+
+### 6. 用户认证接口
+- ✅ 用户注册接口 (`POST /api/auth/register`)
+- ✅ 用户登录接口 (`POST /api/auth/login`)
+- ✅ 用户资料管理接口
+- ✅ 管理员权限接口
+
+### 7. 构建和部署
+- ✅ 完整的 Makefile 构建脚本
+- ✅ 支持多环境启动命令(`make dev`、`make stage`、`make prod`)
+- ✅ Docker 容器化支持
+- ✅ 自动生成 Docker Compose 文件
+
+### 8. 测试框架
+- ✅ 使用 Testify 测试框架
+- ✅ 配置系统测试
+- ✅ 中间件测试
+- ✅ 接口测试框架(需要数据库连接时可启用)
+
+### 9. API 文档
+- ✅ Swagger 文档集成准备
+- ✅ 支持按环境分离文档生成
+- ✅ 文档保存在 `doc/` 目录
+
+### 10. 详细文档
+- ✅ 完整的 README.md 说明文档
+- ✅ 技术架构说明
+- ✅ 开发调试指南
+- ✅ 部署说明
+
+## 🚀 快速启动指南
+
+### 1. 基本启动
+```bash
+# 进入项目目录
+cd /home/table/Workspace/go/src/yinli-api
+
+# 查看所有可用命令
+make help
+
+# 下载依赖
+make deps
+
+# 启动开发环境
+make dev
+```
+
+### 2. Docker 启动
+```bash
+# 生成 Docker Compose 文件
+make docker-compose-dev
+
+# 启动 Docker 容器
+make docker-up-dev
+```
+
+### 3. 运行测试
+```bash
+# 运行所有测试
+make test
+
+# 生成测试覆盖率报告
+make test-coverage
+```
+
+## 📁 项目结构概览
+
+```
+yinli-api/
+├── cmd/main.go # 应用程序入口
+├── config/ # 配置文件目录
+│ ├── dev.yaml # 开发环境配置
+│ ├── stage.yaml # 预发布环境配置
+│ └── prod.yaml # 生产环境配置
+├── internal/ # 内部应用代码
+│ ├── handler/ # HTTP 处理器
+│ ├── middleware/ # 中间件
+│ ├── model/ # 数据模型
+│ ├── repository/ # 数据访问层
+│ └── service/ # 业务逻辑层
+├── pkg/ # 可复用包
+│ ├── auth/ # JWT 认证
+│ ├── cache/ # Redis 缓存
+│ ├── config/ # 配置管理
+│ └── database/ # 数据库连接
+├── docker/ # Docker 相关文件
+├── sql/ # 数据库脚本
+├── test/ # 测试文件
+├── Dockerfile # Docker 镜像构建
+├── Makefile # 构建脚本
+└── README.md # 项目说明
+```
+
+## 🔧 主要技术栈
+
+- **Web 框架**: Gin v1.11.0
+- **数据库**: MySQL 8.0 + GORM
+- **缓存**: Redis 7
+- **认证**: JWT (golang-jwt/jwt/v5)
+- **配置**: Viper v1.21.0
+- **测试**: Testify v1.11.1
+- **文档**: Swagger (gin-swagger)
+- **容器**: Docker + Docker Compose
+
+## 🛠️ 可用的 Make 命令
+
+```bash
+make help # 显示所有可用命令
+make dev # 启动开发环境
+make stage # 启动预发布环境
+make prod # 启动生产环境
+make build # 构建应用程序
+make test # 运行测试
+make docker-up-dev # 启动 Docker 开发环境
+make clean # 清理构建文件
+```
+
+## 📡 API 接口列表
+
+### 认证接口
+- `POST /api/auth/register` - 用户注册
+- `POST /api/auth/login` - 用户登录
+
+### 用户接口(需要 JWT 认证)
+- `GET /api/user/profile` - 获取用户资料
+- `PUT /api/user/profile` - 更新用户资料
+- `PUT /api/user/password` - 修改密码
+
+### 管理员接口(需要管理员权限)
+- `GET /api/admin/users` - 获取用户列表
+- `DELETE /api/admin/users/{id}` - 删除用户
+- `PUT /api/admin/users/{id}/status` - 更新用户状态
+
+### 系统接口
+- `GET /health` - 健康检查
+- `GET /swagger/*` - API 文档
+
+## 🔒 安全特性
+
+1. **JWT 认证**: 基于 JSON Web Token 的用户认证
+2. **CORS 保护**: 可配置的跨域资源共享
+3. **频率限制**: 基于 Redis 的 API 调用频率限制
+4. **密码加密**: 使用 bcrypt 加密用户密码
+5. **中间件保护**: 多层安全中间件防护
+
+## 🌍 环境配置
+
+项目支持三种环境配置,每种环境都有独立的配置文件:
+
+- **dev**: 开发环境,详细日志,宽松的安全设置
+- **stage**: 预发布环境,生产级配置,用于测试
+- **prod**: 生产环境,最严格的安全设置
+
+## 📊 测试覆盖
+
+项目包含以下测试:
+- 配置系统测试
+- JWT 认证中间件测试
+- CORS 中间件测试
+- 请求 ID 中间件测试
+- 基础 API 接口测试
+
+## 🚀 部署建议
+
+### 开发环境
+```bash
+make dev
+```
+
+### 生产环境
+```bash
+# 使用 Docker 部署
+make docker-compose-prod
+make docker-up-prod
+```
+
+## 📝 下一步建议
+
+1. **数据库设置**: 确保 MySQL 数据库运行并执行 `sql/init.sql`
+2. **Redis 设置**: 确保 Redis 服务运行
+3. **环境变量**: 在生产环境中设置敏感配置的环境变量
+4. **SSL 证书**: 在生产环境中配置 HTTPS
+5. **监控日志**: 添加应用监控和日志收集
+6. **API 文档**: 运行 `make install-tools` 安装 Swagger 工具并生成文档
+
+## 🎯 项目特色
+
+- **完整的企业级架构**: 分层清晰,易于维护
+- **高度可配置**: 支持多环境配置
+- **安全性强**: 多重安全防护机制
+- **易于部署**: Docker 容器化支持
+- **测试完备**: 完整的测试框架
+- **文档齐全**: 详细的开发和部署文档
+
+## 🔗 相关链接
+
+- [Gin 框架文档](https://gin-gonic.com/)
+- [GORM 文档](https://gorm.io/)
+- [Viper 配置库](https://github.com/spf13/viper)
+- [JWT Go 库](https://github.com/golang-jwt/jwt)
+- [Redis Go 客户端](https://github.com/go-redis/redis)
diff --git a/PROJECT_SUMMARY.pdf b/PROJECT_SUMMARY.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..d71ce8b79bd8ebb5d0ab62fb17413a7765c57118
GIT binary patch
literal 243591
zcmeFZbzEJ`mMu(z1P$)Cu@E4*y9NvHt{ZoEm*DO}gF|rl;1)c%ySw`XPIAw=eNT74
zzWu%bzRi!d*Q!-ZYwj_}tTC%dqyz*hX{i{YNmf>e#-O2T0W<&$9b;$?4r)0kOFaNJ
zzqYNmsf7VFwUoAjo(+KRX}=6KwWOV`sge29Htq8PGF)8Hdgj3A)v$~L
zimX`3Mi|OS7zarUQ;NS$2YwnR|A>c{*o%&sJ#9awcd&3Lf`LcOUi~%ku$K%-4+8=i
zPpcOVNH-kZfV+p8oT0GSddplQ;bQSU8HXzfrpWv0Zt&$!djbqTn4ummz{gw
zI8vF%`*r0f1LKB`4Gry*@I#ss%f(bxgF$0zRdev4CDZUFHPZ(25!%DswYfMsKQ9iV
zFCU#!x6GjTvUV(fZokZJ*~cm2o?m?2^rO`YLPWdm_*w^4MjJd&7~gV2DWiVdrH-Mh
zrJ)s9^%hn`D{wfZa#W=0qd-Ho^;+=t``5hl^1}u?dJ7h;>
z8^ANEe){7M={DjKeYMJrfty?*X7UHMH}&ODe#z!G?|b|+|4+EzDg
zr$$VzKzk@vSCZ$3PEf*?2;78zH)}*GLWIDdkG1P6+py|glD-D|1=x@WAATXXi@xaQ
zZk!7Lc{|)y_nMI0hh#n;;(S6xx*B#V1)%Lf!fo{IJJF)Md0tuB3p
zyd~TldK;h)P187mu^-;WlspqGeyH+c&Lo|>7_X>m1~;c@+RT5d&N>>gHyr6CGx|cv
zK-Dcl>GE6s4QDhZ1RTf)dAxw><$>AR+M$Hb&!U-K7LaY`cxcXcgTvcf(y
zav|>SsKs``b)N<66nUEKx@_(PQey?HHZw{{@x1rqxRz$bEEWFd>4tB2U%^!M%9nuZ
z2bQnsIE}G^+glFk$VtG&r#2;?v}p~7zWCTVA&;^7^Umfgp(L5&S3t$yoS{vl=mLOtZ!o8zIhT+6HF+0*#X
zCAqorZ$>z$sHotJ=XW)M*l_O8;PwlLe#6`grai+PEiD7W_5K6Cz8v%n
zoBx8Ze+AGYB{P#XCWMCr&E@bqKKX$yT)tKfcA*TRlDh2SaG`RMnt^q`1C=fKoyWbN
zIMZH}hTU>61X?^!X9jv_251@y?seS^AUD>-3C%DQtOk5%JM+gTY8eO6WTUmObBpMU
z^E`n$HHY{?g__|*lHKLbkNnp;bB`Jz4zLlsQE$+>LB}vBL+z^QV(%AjZE}dGg%0m*
z8ZOlc;fqlCsl>y{MST%tgFQ)UyJ7I1i6u@egbho@puY>F(0G{|QJ%Rb&mZ?WDo{#}
zj7DH-83$s2u-fHL*MSJ_(}5sslgC%Hrr*lR5J!truwGC8C|w2fDYbTuK%v9$(>@^-
z^bpT$rJgcF1t~uF+QVL$bC9V2GV7+By(i=w?*8|?HY(j)FlxzT+`0gIZ53^hC#a6@K$_OT}
zI_IlXBM!Yb8Z&L@o>9F#DLJGGf+RuO8j_^M$B&st*hIULZq@;r=bhs7a#~n89^01NQxqlkBG5=|PqkayvJoUPprNL70MxnZRy>+(LXZI6BIULC3YLv+1wx`fEP
zOyhI1le377=<7L?2un~(jJz$E6frS{kH&j3JJo4Fl0P7KSgFBBp7~R-E+@r@wpgN{
zX;^l~AX`fuc1}B&;LcOnWsXP9NaCPXraJ57gqCflR?a;(MqeBp!gD`jWT}icnNQXi
zq+Sdf5#N77H_2*?S7kAHFjzR^o^PhOx1bJ@)0Qb>WFU>i>yaS}RPE7!K#!%9@ejH|
zB=Uu~ZZZ*;+`zb{n{8t`ZP`EfcpP|2}yBUSpoPiM|OWoJm~0@$0Kx
zgCvFpJ~vKA3gD}oH6)l6Q)ew>;;B}_uSSi{fgS!`yQ-V0BSN2+mdd_{&afAOPH07+
z8G~`tf4$Y>`HaUZ0HY13mKj>=|L1$tdxfVyW|~U!Jq91^i|YX+^w-k%B(Pe)AeC2>
zs%TkL5#GmC2vA)fqQ@A+G3QxBhUmT+udJ
zdFk=U4JOJF@Q4c`K1w9dd3p23JYgQm|HosS^-y7s^^|Z{14??c$l;jBE7dW6l)nS#
zXFz-bXF3Mje;_C0U(op%Gi7{%nEoAynMlU
zT4-uMJ_|>HDkC!;70uHJz|8n-g^`u{R|)eUD^G|nqi17bXRZ50ou4SSl(mJfte!1E
zmHLT>t8+bl{^YxMG9uQXw2+OvsEwX{d(Pp7Q8-=kcaITq@ny34$x@d*{Pd88;-uQg
zNstPdXZNhWi~>y5hs%P3+qjAxc=5XledJV?XqPG?lNr5*$12gY480NGIP;U^9n)A+
zvPrh-Bm`@7QKyR;7)%FI>&kMlK3dCxlMfRWwz3!qjL|YU3Z{S3N+nO)nwb9i3U29h
zEY*RGUx$ySfh6tw^fu13&{htnPRV!ZyGbA44q!@52`NnnQfFc%+DPk+#({?_96(N+
z+jOHNx9V8JC2!jlR?4MLRjaP4cSTE|Nh&&%=bfC%lluEqAKc<#&M^2)mUF(*r!#
zIzpONx5-F`ZBg8lzw<47!r(Uivo%
z@Y1f&20+L9r*nR8>tBxZPv`s`*I4U4`Pg59jkq4rNc*KZpItE1Q#8ZOO84T3&268m
z*#H<`{PcflM?s6HGd#7YAT5CL#j`)z2OWU%#l1hR(gPTOhd>Mf#$P88WCSq&cHB$=
zrWcR@)c*f$698&CJxALo%YdflH8;0-x<2Cze|ReRO$eC&60-d=Yo=ch^EZUxw^=_~
z_3wb|+5Dg5E!uwyw?d`+&D&@Y8gD5!gtL)8dx}INAnjL)BJ%FMvZB%VlIsXV%KX0Q
zaGIX0P(a;Kfj1D=ZR{}LnO%@i+
zwyXQtusii{gXk*!&96yls6337H8H-;kogNIG~g#47wfqwjq;F(x^0ve`pTzmM^ri2r*qO3)5FfD$}Lum3+XRi#!@zT6O0>TunWwhzQMiZ~zfn-#b|$$j(>XJA)}VEav=RNzH(s7?Ops*x
z)fn7l=88`>`^K;DyaSlwjM+rBT6O=?2ZQVutvc}pS;#_zSWpH`ocI7cUB`EZ05KCw
zn2ISJmdMR1EB+M@B*QyGfa?cdopZm
zb8=A)~?g^}oHM_OnB%RzW~Cx!bTOYC{vESV3vH%1IRJBG10kuyci
z-+zYl@bPKwNcLn%FF?T>LSOJC}uozx6(U#
zdp1tvD2apAHl9XP{NNj_PI?HN$da7#K;A+zJ~Y9V=|0uQRe*1QTCcbOy{)4~o;I|V
zO5%OEf;0aKLBdFFf|LI0ZGG-RotfRR&;a?!SSm_H%l$Q;{H$h-88C3E{vm8)E!C8(a-(*Y-(q82WIvWgBXPH%A&xK1e1X?*76HB$*67v$K*
z(BveyxF;B?S)?vt=-YvSh+>-ngd7L?w8537;&gJe++L%YwczAxKG>;@%{`J6r}Cb`xWKf
zC2kk^@c8E3k`6pc&66{-Ha>hsam5eAfPp@WErkp8{R`alD=jgWy3PIWZb|$WF`KuB
zM6loURV8P8@7t0^)Z?)zad!pl!f_(+Kh3E9MWpUVycf;9>oag6Ie_CAW!;)+XeF`PJRlwh)<6({td
zu5Pn&lag()dQznMyAVi?uETcc0ULV44imJQ8N~j~+q%KE+3QCTs%rb!f9E5gec!W>
zq-Cb3`-hYKUHFgw=jR@j|1n8p`o-)2iERHjB<qxNv=PTayjZTx-8B%yo8JL!@02$rP`sM1Lx1tr1
z1EuI)AxFBNoze{zQ^f!TosS_H*gnl!32RDT12`$)hen7#gD)#Z?!5Msl4UJSBj+z9
zd~`df$YWYHtfZ+^G7PcIS2Fx|l&=I65m2QSs8qPBW{ot93WikXS>#H9R+=)<@j4Sj
zq*EnA{u{VTr^>w?rV8qHrqX`CsAQI2RS{h?7pL4JL>_?*2dBIyPtZ*<*M0FYWT?tG
zT{BEhLJ}U^w9**c4c?DzK>L+(O3Q&H5tNs#1L7NiAxlB^ZmJBI8ou+T#3<;rtw1
zev`yLJW`jKUP3+=Aftz0S$w59%c!xxC+zSF2MLjTZmN6;M-)03q9p2ZnzH>dO%eBA}?;*qrkYnV&UQfV@gA(z>8>4D{0z;N;Xhj$gJee
zS$qN#^jteb#iLw~`fQA|{$=2pcUE~c#W)AXFb3
zrG$5*1t!8L1gYa3l1}<`vE?zm617DHC7$(##4kMXlitk_i+wd)fl&~3vJXA&sW-S)~kwcIAcyW-&bIN
zmLfJCVq3l?lW)c1qlb&%ve*y#oZ>gbjk8EbLa`kc30zVn?^%z^Kv#xBIAfz`_8Kn9
z#no~}2mHKz!obX7aZt{W5AV~gwh}B?4M1=DS5@!cy?(W6L;FQYQGcYFwL^~C!Clhf
zI-x3rfR{WKiF^x7MO`KVvk~J;h5nOk?_{PA1ypIYeK!-42WM+{HLD%mY-7ZxcDBsP
zT?+@;VLsf#HzC7K?G}-RkpOO{;XD)Laxj;lV7oOX!Mnye#ePXW@rwD&9wV8cNPh=M
z&p*`X-!2QwpIrt_|JvEg^gCwz*B|tYeDwqe|B$Sz6r4C>Ot9S-E>qmf1|sICY6RnG
zdYYqqB)-tnWAtnNNFRNdZ%HUpjl_z|W~&l0Mo2jmHk$Kwum`bVY=khj@A9q3)~(y-
z(5ZUM;%Vcg%l*Nv`@yFBqa!s)k1hy!NHL0+Fvi|~S3pRR{t`YYSl+9T>2E5hl0z7d
zT0A$lyFc4lTqcapUq!E0OgLy$PMd2!G?tBr-N4sz^M&>IFQu<@NHsH|apJ72zt8RV
zhiJ&W;{pMLX7=j`_k7QLj(c1|n+0Yhb_Y+}yMn@1uqk|wg2xWJPV#;-SX>l2<1R)H
zeQ;gl%R2X3kRwhdo)N-0S)vY}Gnxon{Jt`w5tXvD2OFvQ`*o-HHS5HsBN!*jG1SSs
z9%w3t~gwrl)8q6VXDZfJ~%;k*(UKp9&vlBisvFa~u#rlq+khXK~7CY$V!+
znLhwtDf7G`=Rw|jP4pcs?mHR_2>KG#9S;B!Tw059$rCK%wJ!i>&65&pZF%e0eAZ-aF}nTZ&t-wutp_&w0Z$2n=zY-?(`pCcGZghMNM>
z0ISeaoWg(Wr`URI$=3LG(8r+_)soW{*4&4>jd}S^DVRIBBq0a^k!S!@n}AXPJ5qoE
zkyQY~bN~uqU6^y!+m?{Chf~12QIJd55(CTMOIrtrhAV*v_DyuybO2eKoOYPb3{5=k
zB@KT9)DMRbsD)vSoin;_Wsy^krf5v~s$rZVoS{wLZl1WU?j6gPqAdK$l!I^3{XTUR
zb)zm{tg2Y4*K*C#m?MRE7cPk(hh6b-U{kkku2LL#AE6&P91~qhg3<8?Yl$2Y3Lt~|
zs`0UA1X`wA#?y!Hv>HAYm6l6+v%_GD~?kqRi$!~xv1VVVf~uy
zmE3@%YM%Kdm15Sp*NHeKHTt=xy9T*Nx<=pGUDJX$dV6{2zE&iVT#jfX@zciQ8_TX6
zW2r2vgqT5{fy5PJ&bl2%-u64w+-f?5`Uu|H8MGWU9W)-ai9#Y85aktBB2z9?HVT#f
zSyU6v@PnoLchyoG-hS@}n4FmL81)#ZKJdPxKKPiHJQ_I;`6xO2!pcGp`OdtgJSxQj
z8P0U)kLOib>I1x?nF{IleEWfH-^{<_eQVaZkGP>c7l9Lpvj}Af6%GA_Rl*p{pw58I
z*v~Lz5@s?|nOu3LqNjphsX>Q=SsVfs1Yf1oTMu!8YmE;n?9w8XXNo0L_&7usMx>p6QlJ?O^G&
z<#2%UnrV!=oQ3TohQSXy3AzOf*KRPTGA0q4e5N`x=r1z~C*qf1E+{*wDplVrDYcZQ
ziD=i;(I*c4AfP9y$kwmZ-`BT5+olZCsC1DY`g*uAvC+E$w*iUv`(mZaIg2riHS3O+
zg4#i@qh8TIQ#Wl^&Teu!z0jor^k{pqc$32)#UI^1h15>cNCNlCAJ-0NI?OH%iPT><
zWQ>n`miv-yTOU(J}g?7_tW_FMx80=z}|>u?Q8
z@FAKZ@*x8aHjQJA0S)AZiG|&!2G>%q2d)OU8#hK**5=S=WcO-!>^rJk**pHb!n-tT
zMrCrf8BCBjSKxb47-~5!Vx`|W5x{OB4xn7IfEY1&XS3FGC+X|s{hDB^V4GlFNQ2CRVUV_%!TiGlt-Iu%qqhy8Q=3UMdrQzG(+Fu9lNC7`&9?BU
zn6-el2{Zx8yY&zr-U#B_N6px5h$>;vLv8xK+wE
z+p2FLrFwFj>4lVgm&3bE?loyN*EZVY8>Km>W$74w6w21n6Iq`u@GW>VZa!YbxWmY9
zl5=5mxyZR>ot~|bSzUV3&->6SWVc{vb`EjA{@L;~9ek4^q{Y^C;asGCru|^uW!%jEM6^miX<6Nq4631%CPNUb2
zr}XF(>Ir+IyUuR34=a|JNe5n^BI6G
zzvg}7@#bV?Bl=JD^-Pt_P~A9PgYKrT!$!4Z>oxhA!tKdxkKRZ5)2^+7{1)|xW=2F-
z+7pE<`wjIGm)J`ot`85xoR|#Pd%Aty+xgy-CY{Wy7AcGO
zE%1X`KYrXTiT{vNZA-W$!E0oxW>M~lz(TwHxh7W@ff&`bafBh}|Fh$6(N)xx1Y~~}
zM9Q76Bm*+Z<;QikGS5=ltD#K-(XDd6Y=0-pDm;)0;(~bK(W(LC<&snvyp0yb>53y?
zDoB$tOImyde5!y!P=5KfelVjIS$pXBc4fgQq=?~#RzQ?~hDst4<
zuQ%7-?=$(J?YJ|04+gOBngTP%4;yDG~pZAo%}Usd(zM
zW(F|-m!idU_JXN}wXCJKuHLgaBA}$k?C
z%Jd?aJj)*cP&uAUeudV5yptC_1n8#>7KgXnOK;pSZG-p0ko`4RIJP_
zPx=iF9ThVR4dauD!)IX)d`du5eZFm)r|o}8dSXWACQk~>^IiTrxvs5|h51tr0JXe~
z2=wy;@ZQkY){>2y`Y9g`Xr@PH2Bao?QS5%-BJ;lrG0gwD5cAhKp((zYK4BJNBp#vt~oe!g!JG;Vt_9M098#>+x+y
z4$Nw19;><@r>i9^r$c^>y|XNd2p_PmYp=Oz10y>uSF{4A(*;X3nzRi_{U!a{(`hQ)
zdo7glLlNID69Jpavq=LFknQQzi`95&MAT
ztw%ngh1rQEmZ`MLpZ=29<)?dnWWuV2gG^SHl~ainej1lzcZ;Y_6&
zweL+>(q-^TQPEeJz`{UFo9SmH#9LRiasBFg2s^!ZcOB}4
zt9G>ep|Kn=yF_2Q8p_-6RvW;YhS-0;uW}4q!<(icXbd}Kd^1$K*!xqvMJ;kP@i+vt
zV%78_B3{@J*lMFLCz?Z>@NKtU*a=VY9#qiZ(vqIjaA%nxy&40Jh4QO?y%e^rdgrj9
zVs|LXBHVVh)z}~++H}yUFltI(26PaOs@g6pdQ!T;;mRd5Z+(!Gw=X4YaS1huISa2a
zSVz-icqjE7dIXi{!+Yu$0+E3ZOX^h8MdIHMIi(9ZaA-Hcqgo+Q_n_>4G
z$(fmi+s)x-*onRjSF5^uIzTE7L6wANINRVWi_4JGuLYFv*(n;3Afe2MH2Z%;lwSr|
z4^~sPhiP$#?imxZ9rCUs%=CCeFi{&f9Zrc8rU|kR!j%a)?tT=KTdwH%Z>stUBbJOF~Hu#d>nvF6&Y68BbSI3fHs+m
z#1n2uD`>!DPd8uLn)UZ!t!RMc+5ljQlHYBSG*hBY)9k`xVDgv;}FnP+Ey=i|ia
ziYZ$1$LkRNh5RwtH@OtV@H*PN!}^%JkGD&e!#xQ;ztxp5RC
zRf!Av&-#_7zVaqcccK|jlv>%aoa32t*1^<%R|2-
zRV#XxDKlrmifcQ57ij$$G7ANR+XU<7h1h0a(`{%LJv+qcm>fTA#ByO_+gNxN|5Jh5
z#Lg#bQKSv~Xdn5IU~SWd#dXwt>l48~v1T~CThZiCe#zq&@Xs*Sd>1`fjhnXvxkdGo
zhpS5^MsPoihI!VfBs!XPrY6{uGmS?YS9DSFOCHIJ3$sSzX0Z>rtA@nM|HikxfX_<@
zD-A3CpFsK_arEEnV12>5r##?))3^NAyZ>K!k-s<%=6_XOng8z;*CJ(g3!EBMw?$3b
za2e3C#`wif!taB{Ooj+VMue5{;`nOQ3b8%*T5q6Ed~Ud1Sop1bM#2<`1iUlm>DQJy
z*XrWe5_~%(9U5qz@8ll(&RTEImd9oX8d^-VAQf&3eC$;sT0dW+0)3%jkwCu-eTU{O
zRcRGe_&(5;9%)kQqNU&~Ok>CJ@Tw*a9H9;=2ZQKKhdd35Ye-Hhg+2h(B`5>1B$|Qt
zUMAE!$K6??$Y6ER^a0zTsAb`2^j;4%Y1MA=qNxU+d^f|&qN4mb+s*9uz}DEyKg7)%{A}NZcC_FTNZzW$LFqzkZgTxEErK+cqpBv?x6@rTW4&vaeA!1UEj}5
zV02|O2~i|jMdL5Q<`lkc))c$EGbB5UbHKZ?EB+``Fg&$)TH#j(aP!7e%5pd(tzqvd623`0%vFiK^m-Si7U1?|$mnrIjLh4|D2?
zCEjrE+NC=gdfKk1XRV$k8jlQW#At^XF5tdImIYKzbRvR)u#iU
zUCNSemu4v;mGG0LfrWE>t5zFjR$66-1sXRXpHy`OT#lb}w>q0A?qV)gDCAPwtMy_k
z+X5p_k0VON9O~-*c7M#6Sak~5WJiahO8F`gSrz}M2EhXF$W$su=hB{{dh^~0y#`U!
zc{e|$(UYDeVOD4p-!}4xM83jeRRxUX-Z8c^xK6gR9MZ3=Ds`hFA5Sr@pZ3K4uqCb#
zHRUgr_y#Rg5>wEKe#en-H%YntPJn%;1bJ5K8$z(zD+l^2pTsq+vanRyq#birj446v
zlBj6}4)q*@{g{bcMx?S{&I;mjbzKp*sIa0$r)~&^g(7NMxOGu_c=1gnVi8X8xGPIF
zZT5!ugT{9^QMoZL=Dmdte9%#CU+>2Y0t?9|i2bGAg~OU`E4EIyKXZ1evfY2c6(02=
zO?J0myf@>pF%0>vbJ3FsO5vEUTY}zYiWkln1cBOX_TE5ZabZzsvZG+Hon6hT@uIF8(4
zGA9cx`2^Jj1=7~iTFqeVv*{&~;k+ZQwB3<@Y{aMl{o0hc2)|Q^JYlt2mZ89}?}Btt
zzQEctn93r%ijj~1T4A{2|_mmwtbtU&uyA6l*
zYx2GZp6;qkWnK?_E_~I7={$PM}+}3K`*G9b@MmJpulJ6>I*{1MCk0W+zs;
zN`j`H1L?;KKPaDf2zqT_(c?@jqeGOeAlaj#In1uH%wnux}z
zc|vcn?(~n!n`dr6yAqmTe|%Hth@J!xB%wPNNH&6r5DMdfDyPX6TeVJ{>QQLUs=s>rRphK{iQN9|4uLbS5fM(ab}V7tT{F_g4?9x
z)(9Cw9DO6Y;Hx5q*HNEygkjI>%2LjvDtVDmw%)9ByVN$UMfF*epq6Pnx(N@S|FBee
zM{r!__QYpg`&!n|wC>N2j;&5N8pIuH$ZFW3+l;WQ9pJwlhBuOMuQ*sR)v)7M686un
z_S@Ot&Du2`z;l})K1>N`e7NY_?r8@Xdh6f=?k!YUgxK*83)5GzBNNm4Q}RIV^$C#e
z{m0>{6Z_S7L}r%W-i))C;A?&g3#RHIOGF616H}`hKYL!+E=tkx8TZp)yiGveds1R5
zEivrH%VB_YfIiU#2fi_43SEVWv14G=!EzmL7AZE8bxUu~yRG?m4bka)mPnkS(GRx+
z79ZQv2*0ukp1Fs~quMrPlTp%MMitnG_Im0Ohn$~}s2XKQ3W>}iR%EH)iTgXxjCip#
zanN|n6O@(udn1K?j)m%!b&gkym4OGXayV;Sx;iRcQRDpThbAFnr&{$LGrE1$O;x`m^wj!
zuk;O$kH?K~^lLTWQBY8eVerZAum~xb4T~nL=#6Fr^>)OGcafy+5Q3`eqw>0-Tj=`1qYM?dhk(wtzTtZ}Qb*6A2qA~i>AZP_Dw@kHr973BC
zs+T`cRDBaNnC_fvOI}c2R4D}Ajrc>*aEx&2mP&QIj5LxGw04SzZk1sG1)R
zA%DNuTPF_E$p1#Fbu7e-%`je}|8;vdEO3gkmnx#y^F4)jo*Ff&GA6&GAc=*+wm-N#
zVU($`FmF2;DubAmJxgG!m&l_NmI7}}n1APpx4&WiTZXf%Fu1x^exDFD!g~aNnL$=M
zLLy#F4ZZ%c{ew*dA_7cW-4HZ0!I{BA!NpD>u@VWcaX$lowDwMI(ry?#Wohfwfmn8e
zC=_$1*VM*UrH<&w9pMH1P_w+kI7w`d0zaQw<1H{>dxZ;tvNYcC#Nv>q0nxa`BD
zthtlfLU+zeWhZ46z8!bIRbSGeXLc=#Ya#rm9`#rRb!&|Pf+|oz-qrnikz0JblV?bx
z_{2)t@gS>*q=K1(@WL@t8B%Bvc3H+4jF*{S7PsKs2-kT+g_%y4l9|3j=Vx{z!BrDZ
zOQE*R5}~Z}RP9
zfagMoxh)ri5RD+2sIO~MIPlimSOyXR>O>TpSf=?yKNWl0SGgt8?gH^|%8v_os7Smb
z8-wvKx|`-$U1$opjn{|Ih#2dOgA6amx}45LxeMv5($csdZ!WBQWux$@Zxco*88mi`
z@f~y9w@hiuXQydRn{p90h1UvFF|eF=1}An2|)=oWH{VCz%)
zW}-8R0Ej6I4iK(ib{NB(ZB<;nxR^kHUia}G-P$OZ;C2u5VgAvZ+ZBdy{Z>90ANZ8cp_3ag9?j)>7S+Ds0La}@J
z%96vdzvBtNDZx`B*`NI!f63hVU-Y3f|4QHbH~TsMl2i5y{>_V)jI
z3d%oud!^YhVn$fE!;-viOk%!0mYQ+se5(1^P+5N4_&gO2?Rp5KC!SY;2jtwsDACc_
zq+or`>h8esedKO?Xx}xD`F7s1JBoYic>FF(?q*ju*M}W|AM>alG=x;d2EK|@F0a>?G>krtpQq;bo*11OMg-(={
zpndW;bmhXgm}j){tQj!n!m4p=K$2cj1*9Tik+U4Xteyvf35!kKa&nv?jMm!VSEMYE
zhSTnLX40LjAJp}mL!ZAqnm3#teqLpLKhybW&AoBENO2gx2oZ~wx6AFisQ$eNN+6fL
z?t_L8Mn^APJ1oQOU`b?|zYj5cVZmE%`PkKuBG4-UdSt6tiJFz!Ry~O3`lL=@K5AYk
zU}JrD|2j6z`~$V$2C~fk|v|nEGX6*
zd6T%J#aM4iu7fzihDhyie1k|hMFrv-duW5joCG}DqIE2mp^U4W^tfY5v_w@Er>cuf
z-DW91hYaSA`wc~UR7{%mOuqaog3)H<
zz~mhpu;-d9^Bc=;eHW?`J-*B^$#PK^-z6tG7>1Q6Uf3{EMj8pGfcYXpyr`_U97H^a
zI%V#cjxiXe-D)JXFUJl7%>qXb{8*JcbnWavD
znwl&w+&~PDkRgGHGPV(E5BK3Z7Duwp^?wMn#ZeP>ZFd>x2;<9#_H*G3Tg~S+C{vTg
z%Go!$o0KlFP3FjgGcZiHU;P=rU{)J31(KSD?VsN(m?8IWbADci3(@a1?84eIsyWuj
zYCDJ~N&5269ZuUTZ{PLqz?EH6lNhDmRjr=Yqqbo_UGBuQrq(|53yyw6FGO~I9Z^sH^kMFfHse}DxuczyQ~cjvVZz8%bX4SQs&g#Dd}NBA!;k1z
z3f}`pah8W@)^!=s9Z1?pOKc?qj|sFsVy3-L+X;yU#u-RKCLyM%R`|g2z!#QC
zUpOie1(h@I1f+_f;U|T1XMW($GhlS5;TXYI-^tn5o)gTwWv+|^mDJK%zgGs4fy
zx#ap=81TU3mLH-!pxg-D%S`>R;G}hR5lx?Jd{_@?N-=*hB}yHrt)a&_Sn+ZZQn|
zcK@U-G0J1A)Ua}K=Zpu*JeLm5@KD^4Ib!2j*1&MhkX@9uoG~=?)%Z|zbCN1Kgs0YZ
zj1eL(Dp@Tw2d(Zzpo!(2Aq)32S!a1yljuyR4)Z2V^00op(St$h1R-%&M8;7Qhg6@8St`{b_B42+t^R-lfx$g@zS$W}
zM0jOZO5|H;*HqpwEl5ZsOM}L?vt4x9(a&o_btOmSkai8h_qrC&cN-S5C09rDTaY_88kKIvKiN*Jq#IVIa^5FnQ3
zTUG=yoU2z$UgM3xbN4P%0x3I1~`?geOPUQIZxRy+}@N>d~pW1he!<>%f+ShBRCmP9bYiD9d
z@y)aLbdu~?J0ZR_#!uEXKFHL0YRiz><_5z<-0R6ZP3ivFbb=L!HG2w-eJ%#SHXX(E
z9n@k9*=}i8MW&Tme6Fyq7o^__;Vq{sozy_X0b<{@2J?5;_!|-FSpG!GmjS^4WR1@QPyUi@B4=%<_Z*Tu<)b`h
zz`Tq~p_WqOefm(y>KRz*$%|0R>X{koSeOE#sXv-OO_O9~ZUCSb*VdJ>Fw-{wUGl39
z`3<$L0Z#*HsKvBxY+p9$7@ww4QZxeE8a~ZALiZwgz9hUnLDzr$dm0}9RL1yp%M3J6
zo5ykB*i0$)=uTCK>=M-E;r#)7e@6
z_g67v&h~4K<*6f<^^are
zU+VsOhW~%gEvx~o&wKwmS=UR!zu4-ZNBnUH32n2diNOBV
zHhFDypGVHq(lE0^KV^6Qu|-M8NCQnR@-%6fkuI;ffvFzgX;ao#&rIQYguK|8CNKk=7wdh#(?6zBpnRG~0YJ$>$MlrK#mWkxrDJ9J^(0R&R*w$wWMco}
zA)X6@)<_NCZZ`vVIr+
z2KX8@u@T~RA_o+dF9K4Jr{MxTBryqZ79ru+Hl8L_7|}DrqVSz_=chp_q0WU;(zE3E
zKPP5QW?N)b>#iWl&qtsW=c+DQqtT}>E^Z$#8!m4XdKU~1t1dOd7gb#LZ3feMK)yq=
zdwtgG@5)(VbTgAATxSH)F{!K8GG3kYaxoLf|;&4Kk?xXo$@RuZ}YBz=H_`rJt&$YD6i?j3aV$ULwPM0mm!;R{N
zsv6FFlRfSbwot-QkgCrrU;=O+=lt)^S(d}00
zhxg`~$4=5y0A1`$Slqo`#$zV_cy}IA9zvE;#vAZ2
z@R0`ViF5fQ+T)k49r7XW9iQJ*W#TUzx@2Lgw#WB{-hHafmJb3rgp;kYYjHO$1n6;d
zfPHD1hCq_6{6FlSMQ|R$mZfc3%oej`F*91s%*@QpELqG9znGbsnSL=dGc&Ws?@jmg
z>zR(2SaR&V`d9mxec<{G?__#m*dM=f
z{RmL&hNLr$@Oj<7)c2U$Kv=DZu+d|6>U|@>
zg2d7LY;d5^JJ7#Jc7wGE^2OMD-}>qZIsjf9?{5(v<)U`G_PAV1Mk1^;_2tg+=E=Za
z<1WMDrd17d37s@wV`>GG&CFHzT)<(hPZvO0CTRm6$v@x#y(oDeZqnPm=X!zDN`%n!7eS6$&Z~Wx&~xbES&_Geo>n;?ucQNYuB>1s-A@2|Cm6rV=`7JW
zP^>Z8ZhylFP$PvZeLgC+vPd#nWNqP2_H~Vl3bBhyRGZy)X(y&d{Yu_O{8VNQtBfxM
zKd}KwsT1-`|DX}fzd9iLdAsqe!VeG))u
zAorQ(pC-@L=|Epv4g?pY*!TZ@dmf%XzWG27`34ZybZI4_`c*1P990pxOahipyi5jf
zf`@R0U&rT|zqEX6ZrxVKzngB?M{r$goasEf<;;|qZn@379YH}4%Ci^t2T~bph~q%J6ZF!yV+qh1&FopTwCWk
zp)6$5pBAxz`yneM0NmxU7^yUMrL=dk9kC;ZNGiuUdcCFd8tUCUaXh8p@^7x-HHr5C
zHuvza5UO=S(212%XQiWO=_RSgXM@*WtR|;ECRjt|YE4~Wd@2=7Ifv2KlWbdxOZ-m=8J`(7i(eW8Srxk^c2m-eo-JV
zP8&NF)H0(ujQIdd<4GS_7jR-Qif~v;6)Ki?dBO~Vrlu+jtcgi&DGx}hvo&_hCs;!+
z$`cr=?DjItZ0GR|Wf~`?8oxyOO&csK64>b34&5`##!aQ{&~xOVvS8P+uy$?Gy@V?WP%07_lF#Ohd_BVJC7QO&ojlp|dRG|sZE%PYiW
z5dtxsTL(?Sd5#uc=4vaZ7&jPCPT4^;`1v*><6^Y68AX6!f&Tl4rYBc{)PgY##j
zdoPKJMvIE#JUAJdIvH8H=R`Hlh_Uc%ci
zNZ>jm6g4s;ifKC0=T!Yru8d(QNK;7q(PEz4MC;s0l*Rk)Rr$pl)EGK{W+?6ywu9Fn
zpJinurE&gRB#Z+I8<794M{7)x88Zd!t=;}P))yt=B+V?z@lAu1&K7&J)@_;#z_n#@
zCkLZzNFhBkUwYs~*SdZiIU0*1cvp*Z$51Y(t12E4x&q;P2EB+lHXw6qC2mD+Y)-JB
zCWeQ_y`d&ChgT+5+>%%`q!H}mQ1Nl`vkRH%z33xXCenr?#Sbl%gFN{nxeXkw&g)vQLqWxb?ZDnfe1Cz
z7U&;-B->?)1owfRD4rr}W9OZoMTUcd;4z$q8o*y?dXN@udR;5HuDE0uNu(uiXm3Uj
z2E@wx`Q1NqRGyM#Hd>5RPB?arL1yf*Jqv2r5fvL1!|y>e7?M7XRf1@mabScwf|@)E
z3VN4Gek_(C1~k7OtiarORYt@xn?I)s;-M^uwFCx>1NjJxIME6AZ@+s&a&!-}hyh_0
zzn1dYu%OXV4()Ng>G=RAzj{CS!(QIm5;K=RsMe4LijovBz~c}jx_2m8J(yEIno6+tOZ!bW*q}{!
z$GwC(hdRd(b+?Gp&$67VDm{H~@Acb`_q4S4jsx;8kNb+)yx-s+UhfictBszOMV8;q8%pj!yQEapE^{}Go+M*A_o~l{6u6&
z6VC09b?8v;5ziUt92sP(P!FaP+c>oh8Kl9k?CbBT5o>e)Vek6~EV>`_)y~jk|R;-?1kw)vNX@
zY(;(VPSqd_U0#o5Ux)>l{sn$t0fTp)1Z7jklWTXg*UcO(r2F5UHUvUKmKB@kP3IbA
zOA)n%yogB11~a_1ScAOtXvI^Of&qEQzr32B|4bd#!)6ZvV>&X}ebIQrTevxVe$tJk
z;hS7zuwou9tEuP}9=
zKf7Pt2*y3BLLMGHW@8LNjt+gh>+ds1ekeHb$^?&x3}Tu;8~`!h=5vB^k0&1(qz#
zH)6~*{n?Ve5e54QBT}cEOCeP0?hmkWQ6yWdw2(+qcI*pXKMlYe4#?B1!|kJRd~ACJe-N(+
z7obhr$Ve<;Oy2_+Fo_!FMN}Y>nhkx47VgA}0?nUH;0hTVX*y8w-o-U9!57KPb}_ZX
zLMvdv$Yf&oT_luAX>0on|t)O>E-D2BXKNvpBD`}BX~Q1Q4zmAT(ZAmhfx%=WiQvZxae;MZ0XE*85K2q
zMNM_*{)&}f304E-SA!j%&F3gv%V8f=(d3V~u^YvIl(VBr_qGVa%zMb}jY#j`u5;M%
zt2sKU8t&p}=AOYXMg=|}DVrmR_@KD6-p(8T7>LsAtW53YL}|H0VRuAvyHI?!OhD7tZn066-|AGYd;@lE7d1vyL4_Z17CdOj
zY_&XhChj`>b(BlY9<#V=i?4DqxQdGm#d9%GG|zIjGn)Q>xy<`Kv@m`Apc%8Zo*c97
zYHU0Bv^uIg{Ol{gx=?Q@Ioh0nNtaZ-{%jzqE+r)Lwr5i1_EhI{f=D)=teQmMxC7|t
zRQB=Z6HNFA$^Dd?7`8JCc_0i7fLGNc*bikY*;UY{RkkRzB}gojSEt3cROyaikR@cF
z*R0LZkp3w)mD9d9m
zK3MR4=$+-KYp%a4Im0k#u&(9%y?M&B!ON23
zYo_m~_5dvxUK(wpl{?DHaWHIA9ZlR0agqc>X{t^h{HAVUR*~y}-FOL9>8<5^xE+w3
zv4u8%qi!e!)aJAk1+uNLatgSmZRzy|cKtB>R>ze3`X}?~9@P0x#TRW~Z9QNgG8?fp
zblvCv1%}vXpK75;OnrZ3SY+n`#+S4feMGh8jriLwfy7SlE%Q0Sz|c+00i<+}P0WHU
z-uo^L4oNJ%NAg+#4N(Eag+*hssIXi6_bW=h5FLEOItA%EuTdB0(X1!p;yE0%#@AME
z^ern|*a{BU=sgjlD`2(^Str*-gIVD##r~Q9cn%Y7T!|BD14(?dAkU-IzbTY2W
zmK_1i%Uj3~<_#t#?!|MizyvqQKCGi0_pE`zH^;kB&5wB?gFpt0!V{lSA&tuPXEHU}
zS_i4J1=otW#B+W+euu|m&{9xp*N`%uj+My#80&!#Rm_(vrlbB33&ATb6NpR^c0@)j
z_sJn__&_%u$ACd3OJYv;1}7XhEB6CzXxC)EInJPLys-UYdiPx_gRu9VcbFd`F(N(_
z=AxekSnPL0*l~2N*)d)|Z_-4Ne9+-qed`(68AEHK5|wR41&92D{Noxr$`uOct+-s(
zbBuwd^k}9tZ*Ym{CLtM`YDnhX=;p`@Go6k>OTNJ!d*7H5=AKe-^d(I3m
zEcyn|?lIM96X)`FQuB*|I=sFTKQzQfAYI2DVMiY!
zF^Mmc*mjnQkDk21d79hBcr23lX$ZQ0#N;ms0iPLY4(4V$=7a1RVp%F|N
zQW|r;v1r+Ou*vDlUHZC89L2J&IRj(T+cTqiKPj^C*7}Wd_vQa^N2S#
zt7Vs?ZaBP-TwrsG)Yk{(&D2{=nrfHtmK>yC{%yC&3u_0R1@zFLGz_=KG)SoZD!IPt
zV_(p@iY9Hz2`F)>j3imH=~U;w+*sO499MFqCNpNc`i)Bo0ygZV3&Hxqz_|brw#@>2
zTv2DoNOLR4f;msr@m$@QL>OMK>z>UI)6IxTq@{G*EDq_{HO(jW;jlG`v~0^BqbI0T
zT#hgE1-LhOt%$U%K5AFB2U?!Vlwa7jip_zs28X|ftY%s6_!Hu6@iHyfqs$lj9#a9t
zziIkgV04l{#7Vhsm(6vU!Br|CsY@y+cs*5~m5m8%oXiPaSAx_*J_;{rVUN8QfGJc=
z0rtOTstMtf1Z`CUHuVVf=6CBcHL?%-zunI171{U8Knq-{GE6h%1-%bf6Qu_s@E{I5
z6Z0Su;)@z6F(6zJ(yE3dLWpvHHhU
zeckUh%Z_{}v=ZR}4>c7{zR-i*ogWJL)hO&*-yf&fm748fR65=KybS
zTZ9wcBsX;Lc4~7zrCo=8&B)nzqet5z6`ARLu_c0P{ihbj&
z@dGmf+hc~W#N^xR-x#*ng0+E4*Xh&@05^F3)2Dcb=wX2;p00hv=rTifG#;eN-UFQl3Z}1j+wyR*cR<>5*xH>UAmozDq{B$I3{&+!)+(+n(icVGI;!Z%VaQ-RH*r*9>a237qI
zS)a+1(_*{Ch&%dRU>x_k2&;0t2HxR&8(fYaStxfqo4f;l-52V
z+9}g2ehE~{s}_i@<%vz;td46*O=yhEQ`-&Jf0Wlb3a!I`J|C~9Ksmvv4LxhtW(Ly`
z9?ShIZWJ&d^BA>Omu;Pp&4EE)t;=%ITvW9Aw|g{a6wT5MGM@Rf(SD;0Z574q$q!zj
zHd`oBv9h>UhBQBu37@QoJz)}7qblKxqCyKHj;#6{
zWkVkX5H1q-(n~^*-#R~H^<$zrb>8G)qgXhPe
zBHpW*XoQyuv<)Tc^63~z3D$`(_vFdpQln@%*7}bkKR3fI*_cMrG8RT-k>fT;%*OPf
zPK9Pp49-{?tk7#7tgS?_t%Opo&)Lj1BEm&xS_$)?7`k0@Y2^{3*Z6^N@)5LJD$SMZ$rR|e3-n&lHw4g7K7`K}-ZGv)E{kfhtB
zJo|G^XVjoC#9XAv0&4*)1E-mjmP|HJktE$+(0P(eunccR9ik=$BTO^H)L7Ojeni)?
zmBg9;;xtC?TXmGM8&JxsW+&zYTK2+}JyHwY7Xp1H}jFP&?oyLSubu=(xNulxev)Rhm=<| z`Qb+S4rNiuLYvSpJ9g&SEWR5&$DZOP@`nOh>kS8%I%Pm2pNz&Y0(@An9
zS!O+-F3;m+!nT&Xg_D2VS|@%p&i-@^f1)6_InKyFL81*k>9|axSe&yy=^({c&lrBY
zUovTwWo~exLIO`a(XQy)H(rZFXd27vVk3u%t>$8FsADaFC0z2uR0!w=J!M(6f2%%v
zi93bnZ5S%t_;Qtz?7MeDER+71dPxjn_ohx;B9eYoWVTpcF5Rrmu-KdV0LZMHDf!%$
zN^+|*H95YLW{}i%ACQ|V8jZNSCG0*)ncSHiFh?GK%Aj4~hG*y7Qv;Q&9dt&JJYvhe
zUaher5=k+-&r;H+K6#%FU~@@LI0q{wM;v6HwNeb7Znrg3S2dCXOOt-14a1`m^gRg9p~M=b|(;qct+KnK4TeNA#FS
z#th@m`SBObi`wLS<+%TG7@MyG8sMt7%J^c88_deUROmht6G-L}A7#kQP%Ndh0CWgC
zFE<&y9LsK%-rAm-FkF19CEplm8EY5gaVN_<_O%5Snren7H_RW)#qlh^X{azxBoRYq
zh*;bmraVs~Y($|rVK*#f%$nqCOv@BRWv|Z4v}cUbs3@<+H{htk5n3$nq|DHb>Ns9y
zG}B`oja`#qtxvwu37#)>qftDZK_w9@1@c(anW)Ppt45XYo2HSBrjlD~ggDuc_l;=K
z=p*H)(e&%k+*ZqpM8rNJ4aJ+lK}_Zq>EDvfR<
zQYPw}7RG}eZ~)d6hFEeVjwqT3?kL&HqmU0j7i=kffR&U67)tckLpM~tmT(p_FLXmQ
zzg+~Vfk}nqvq`X>j9^R_7Yd8m%@U7FQ1!ui5)9;nkBrn2z?yR7#tO*`P@9BW&50qP
z>Bu80g)@|(4aeEYCb@p+??bBJX{FC~$tw)Xrxs{o##Smn>)j620u$?xlNw`0im44>
zK&6e`=bMq8!$caN(H}#{Nq*~8yS*xCk)H~~B9|?VGK_2uxKDm9d!letscsg&>$(FR
z4mNs{Tz{x;!oAzNu@RU~Qe8oO+IHc`cDf$m_9nT4s&4+&au=m%N!N9krGMe(N6DnR
zg0AYIYPqf2_FZcSX=6+B1%l9PNPm671AP3cHo0-pc`pFA`pzGZ>`M=8$eV7+YfCnR
z7KU^x8{BHv%P2>yH77$8VIP_XxO2Z34Hq_plr>E&$}8`ZZAnP)2ff>gdpqIAmJEXu^r8a`0gw3PG)VXTuMO(Y`~AGa%9@5VD5{VRL^BnAUgrnTo|ya}9Y02pa9o
znQ!)_YE-(K-MdX|9yx&Ne3Xu2dwHse=o!--ReHzVg~#_Ivd2WB>+W{+B7-Y#57?uo
zUwP5>qCP+AmUQ5APq}B~Z+C>$!r~MJ6bB4B*4q1VUdeeP=;eYg9Wf;L#Ix%brOoRa33ozi$cL#Y
zSqb#k79{o{-r%Y08`cci;L>9xX*Rknj&(YSSDR^y+4-q}=HvWag=Yq`UlR`tj2)fjV*
z`#_A_6Qdf(vTXPF#d*|0BQ%Cz=qxE+h-vq9f_lq9e`R;`3vM(Dlb6OpTJhJN%fa8m*rE
zUML>Ni9SABR!P8Ith|QD__&i}FdONdrOe|%f!jD!yuko5QwQH+ZjU>GL9aF6A-HS8
zX5<_u4ho{A1brdffmyg-lUmfhuT#ssAWIs+^k
zMANU8Pc?^j8zv`bNLQ3t6IE#eRnomf!Wx5k|M73B&1MP_
zJcIZgbNAYSO1-{GKa_ZSM^kHxAeum#W%D*Oc8OElqVP-oZ1Ut6MFeXXCpW0F!Xos@
z0mY-t$NdP4PhQ~7>q4WI;7*{UM~W?SJlk-|yIK_Uope}0A^SGb|5
zsYPOT(V$eFio~Pl4*7iF0C-Fh`~|YJpa1q>U_Sq(3H|{X{56*Ok2ryUy8Hhh?8N^I
z=OaL+EU9lUDD$rb&)*b@{{VOxng0XeVfaU)#D5R}y$1ii5B~cz`2Q~j{{`Zv
zw#qi<|Hx=0;P|I!%D?cZ9RK30@;{ra{xfLyuh`hXOWnW0VjOHt|H6v>g}eS=Sh4>_
ziv88ae+9+O}laKEyVJqYLzeh4_XxbOD2-*Gs>4b)>7V7|Oh@g8IKXD;(+_x9Y0&%#`<@O`}4
zc{ie6yLEI=4ZCrHbFJEMXJf^d7r^<7rJ)>h~*Y})HHGX~c730>hNC&QCqIpM+uWg5$n!2L7^_1^UFsj3w1Vt?_Vk}c`y0MS-
zZkwRDVy>S{z}hUvA+xRRn~xe9oEqJ3o3y`6XIDHhv{;LrSph~oZ0y%EhBVfj2uv;Y
zPa8EfkJPEg%wfTYc(+Y%5aQmSLqvSu`=>Y6-whMf2YG2C2YG9|(Y};M0(?_#o&hCH
ztuzS-O*^`EKlgN@8C>ctR<7yJmx6r{w5*?(qH3R;s~)zlZ3B*;pM)o|Ke=Nern2<8
zJmqPyvobw!vjSX4cQ~l0Zg6BAIk-gU)IyGq%Qi;lrd;RTml2WmHtEP@yQ?%z$z*L+
z4o7Q9x_a=c?1+nc)vbp{w$?b7QYzfKr4~J2Q6D{GI{fP2J2Ry^-ak|t5Al3~n0L>d
zlN|^NBVpZZp}kvRtuI{aHh8}1{YNSyN3XhMcS?sy>ZRkTjPj|5s@zE&ZIU^R-6d&!
z#y$)15R`Xne=iI$$~!?3zfq8Otaqac>^>u9{1R%6%;{LtgoII$Vgfn!8g_p&f9g{ps(>pK)vid)eWK
zqt9eA-b1`|os6HUm+3cj>Ksg;NsXh=Q@VYTzQvNp@1Ap;2h6ElsgDL%w!4OrM5r
zJG}mnRAaofKiFP?Nwk`1E&aDK!Ow(WW+z6%pA0sufV$py5EKa23)?tfDS784di76|
zz9hF7pg=K&dmWc#0F~hlbyS97T?SQFA(iQ1y__dY!h!lth0}4k>EHKJ&oQ*S!ruIM
zk2e&v$Sms2GppMuXPNIrE`UtcqMC4*zt6Sx;vT}zGpHM;zt8!6Adc~J{7tlRVtl(2
zS%l?BSy58ERl%NPT^4WSSVrE{hnH5=H)ky>>QmS^wuCw~HbX&6K$^P3u@n2}^zc9Bf;0PvTh3<4HSb+b5n5ELV%9=RR{kUBBbyR4^xb>G^@xxWycKXSr^!
zV1y4EaJk6B0`Et#W!9gIY;XIo$2AQY_A|OZ9~Id??h?MBVtA1Rv%|XgSCNL=dU&?U;8t3%FQ!e!1jUJ>O{l>glCIz~yncUseXnYI)zL
zS;}VmjHI6FcznRoaeD5J*|xnTYub7awyx>A12e1J&MrMKJFga=c(2nS@I5a2V>&Kp
zfIbH|WLaLPCrjNsQMMk3D{S2dmA0OjFU{S1nO7c9o<0wqS8t6^zS{x#uh*hHueCA0
zy9wDIJ9F7D=SMytY(95)y3f0SuJ@#^*HhcC$)&E(_U@-Q-|Hye_k3HQvzYFW%&X6l
zr>?JJ-^U~08vt+U$1JbNxdeTGHJ0u7m|C@pIBHU=L8BXq2FD#uG1~V5x3Q^e3ak(V
z$c+$?J-quZnl%RA3%11=R?(31&f{Ng-X`NCYpZ9BDNNhDpC{#Ll?p9K^Yx`x*(RUxy(Xk7=G|ei@63QFioEl)wD=>EcvV>eTuIcOjYcP9I#|j0$N9)@4V;5Ce)x{6h
z1Fe$j)DVl?f*X&OQSJQi|I;6u_YEu@5xBX;lTf%$33pP}H4^0O{={;J^~<)#<6SY!
zF#VBK3S|%SBeK@75?)JsOARg;*|Gs%QEjQg^m*^+t-&M~j{ilnuvr=}T>-bz!!c9UqytPJCi9w4;@%
zR#sgeyOXx8-z;ONf{22EY9hM=E&-Peyt2*#pqFD&w6|;IgUdTy9e>9YJ-lJ8*J^P=
zISrx-4Mo{$T8+yc!T0fO(GnXg5DnEEnYook`^2j-%wfBlSoQH|NY3cCTIxHB8(~n8
z02EpaiwPKTPJUtI4RzAA<3@El&76%T8=}`{w3;EKt%Md4jXgv+<>`&25p^yk(
z7taDqqtH0Et6RT`5buD3bc)z)yA2oA7a>zL9G^J4WU7ff4rwj~=Y!N!Su)lmUxp
z{OP8Sz8TL#F=CDT+bC;wrZ}!w&E;+S*J3yjA@d8CC$KuwI&uP76-v;aiEC32#)~^M
z^m`Ycx&g;HVg;pF8Omy5txm&{nPoM6?b!R+Q|(tpP=pM3iJgw74V;gAGm{~2IQQWJ
zxVPjg*bg|C%SH%{ghtwDHE6&Huv!Shm5>Pki0!E|b<=0o(8A%$B~XTLeM2}D`99y#
zKPOOZi8AVv9#We#=$&apW)>g?lT-<7{YwCwa5D3vx~%7n&~Lzlm^@~yGnlN^{+hj*
zJkDE2!}Xg=b~MTL(lz_Qa+ix2%Wt3hc7q7CJ|{I32Ae!c4KLV|IY$PeqT{LU5Kq=Z
zh0X0jOwuK!TNG5%F;fI0%5X=(BosU4p)B_k)kD?mr@^2|;$=%+e5utbHlNv!BMV=_
zyxtY=@hEoIFry7BgmaheZo`e@u-tx2qkWn2s8r0{de)~`P9jnU6@UBb
z&ni-Ks*aWE$QJd8!K10eBncIz4MW;6JL-vVo$4s~wme@fUJ!Wxzg?`)7uCk^0S;C(
z?aZ&n5ezj3aSEIo+cS0$8uGSa-V~be?awm(+Tnm>ZuA_&S7f)}HjZJnH(vt57FA+s
z67IH)M!&PMA+?5BTWrkzXRIb>I7v@C#q%Vi9fY`I9xq%GWsE%`upzVYHaU`6?8_9g
ze4}dSlO0F^v1-RVe!Q?uvuKHO9*B%MWDfqA@9}d>kJ|VJDIa*UqDjOotL3Si51WZo
z4_G1478$f{r8jaTD<3w5JxX>QZq(;>m`MI*pfR>9V~K=fjHshMKfb&nK45ZcQBGRn
zme+4L=!?G{-L7ykgrdkT!DoFbzEfyLNH-DIWEw|ssIdI5Ek_NI6qOuqG}t12wO67W
zOoGlGNajhxDPZlo`+#7-YZ}M0Q_rJp*8vJZ>&<4X&xU?va=rMsyet=)%o1jB
zH2s3VgSEN3`%|@%sjS|E!Iy$bqdWIUIi~eY_Mt_CPIOJgfli|4)`+vYXo^tXtPB{l
zvF3(qJmMk1%5OwVxmAUhXtq}c+fY4~D^UO(@bx$WnO(j{h5C2R$*gN)_okrv)fnDx
zn>)%j7kItjiSY@BY$`hC^o`E)(yzg4_qWdViAzD2MiriCfn1RvhwZPTBEk?+o&f>(8g0V*M9v<9;ML_bAd(4TxAzYy1pOL)vyJbc`_~j%cl=&R0(Owp)lo0
zbTsd<9MFTQ3)$0EnR^v}Qe|cJIs%$jt}4;skeuRaIdzD6LFj+*ppDtM;kw=M^Tj(w
zhU&pecqo$W6qpd51osdvA}KN*xf5p-Q;oe{(h*|)k)@JAAo9oGZS{sDHjcVuzM%2L
zllZuC)o-rMsE~Vzi0BAuPn1h%X+_Z6EAD$3wJOn}dLUz~hvGax_wO447Qgz%h~Q&Ql<&J463*+mGmjwW;6{wHfMLu9n;F
zFF@g6Ty4J%RM1@0y-Q6LnUKTNz1JjJVNVql#lE!)Pk)%x5O~u+6l1_$D{^j^PFD|~
zSkAgeig7X=Gh=MnSg$9K|D3rz6UHLhc*Z%v2c;!H>(a>bcqV7MH~EG_mcn<>%sqOs
zU93nF3$x4<9ZRGp1o|_zU5iY3J^5BK--kh|bO+DcWQpANDMU+FQ)VkVs@^#8v%k|R
zZ@!s7M3_Xu^b?D{wU-A*FRv@}F-Re$)@f(GA;|iGnOlgyZoaRaA&dLFlvqh_X+Q}4
zR`(DfAfpA@_R6;7t02Blh?0$+IhrVw1H$=r%+1kC`dm3KNyUoUpkin|D_WOll{t!a
z&5{}WOqKFcm;-6T7&EV%$ybqfQ7Ir)2(1CtJ_wS+SP^TVJIc*Ir^IUZp%ndJpJJxj;c
zKkVXCQdwzp<1y>Y79pA+PgI=C#vxkyyes1@l>ES(C2>n>_;qq
zj=Xw(*OOL>nt+;d^uowi5+QNn?0x4Naw(fGw&S(dH3%pso~LmL<&5@qK9^R)nmeC3
zj4s{bTS@xXBo#+*MMuquB6{~L$Zj2-8sbRY|r=LsEk;k=o6RDoZl3n7N
zwX4=JwzmmQXPl0lu0bDQCDN>lKwkrFeBdE+^`w3>A8CYXJrlm%yuGqs5)CPy%We&})Q~siIX2OiIG|GiPy+3EQzm=J2Hiq5&^<5S-sL)@0XupM8
z&~`_f@zJU6EmMDZuL51CNDp`Ebe3jP=oUg5~uQB=0kS!LBq`oDCR%
zr?3#TX+f@U^4@^^(VxR`=Y8hOlO+o~009gEDZPjcVH{kq4e*TlRt$Vsjnj9GccQpR
z&lLR4AD_0n8lCre2L`*TWUnzYB#T#yF^tG)`_u9bW*Da}81p`fdUCHZXo~0P`}U85
z#Hz4Y9KoY6yf50#zdanAh@P6~oiuO7$(6p}lk1fi@h^zOFA{!>|2lK(rQ8;$L+zbM
zg0uDBxIQLyk1VKw@UQSLTCzcG7$MS*d)a!78jr8H%NVPpR_Y?VnA2{{Vl
zKVM~VIwFg|yf8i?%~YN0pcpfWf!Y5ivEnfxjZiH*ge?Zs>;Q(CN2rDj{SyI-afp_}
zv@E?as4Cr2s;?ezhOaDz{C;j;D?1;x?oBii&rR*uNdhOa$FoNdCJbev;RqDnr%Fb_x3Fz$Y57Gh};c%5UrQXX|X9EU`)K
ziV3sgE84NWb=5kyMA?BxIPERbx7iDg|2itvdPff$)-DNMP`
z3Bh%)Q{RmU^X|-u3?ULtCZr?%nb)b1@@Zf*e!#wCb1nAu9Oa2!=ZUFp{e(iF5aO$Z
zK?zuE&j{&U&@IW%n+g^!e_k-FAAAMW@hrec4S{9PNB3_%GUf%sLX`1@F6YY5IOZ$~o4d_3m
zO-gLm&u@si>1ARS$e`2|Q!N|Kl=FV)M1p0Ip%y*+sr6XRo5K_XL%3PnIKMW0<>W0-
z(;FmpG}GLny8b%*3BI_p`df&s4r+?f&0&j=fM(j1U3-}8!Tl#7CD*imBPWgj@MR;N
zgaSNrkI|?z4x<)s*=&bW6C)E+-3d?Wp-ld5kJc5OXV0}4{B8X0hd=GI4IdwbXs$Es
zFxW4NKNdV4JWCU{Aw0#aM5r0>y(pFVF
zz3o6O0)X1#6$(#p(@a@*I{p#FlbJh>3NhShW>Yvd3i_8ZaU?1t^&s$*KRqm(JjtDe}E=Hai9MT$&sP(0_IeH17tz!Hv_cUQP9Iq)rH
zyIztXUC*~GOaAN~3Dsa`26mGxFK<6-wFSoKFqRMm%1A&9^ePrOv3`FkziW5=xZYbb
zz>oMaX#igf`xOy)AHiURNtC<}t54rC`$M-AWO`;y`@!wzE%}e(OW0yWL~pBv1ugOr
zWCNkYrj|Kq{sBm%Qf%I*NMZhUL+SgeL(@EA=w$Tg)^+!(K4>Z#vbJQ6uigD;QQ!i=DJx0Z=Ob9i>*(~=tXRKP}rndtyK
zeuFitl;0-gqcf?5q72~apgo3Fqg_!UJcb?9O0~rQh?A51;OrMuZe*af4ZgAG+he-r
zFhZcgN7|@>M0
zdmpiJgh53w8lO9leEq**Z9|obyrYu^Eox0ZL4;3eL#jEvW}KIIgtyOOdyOSF#BzQ6
z&d>AtU#fHvm+-MT9U&Nuk&x5_pnE4pq42s?OIm?3GMf)-u?>n{Z-UJJ-lG|{uT>DC
z>R06f?q;-{vTk$&7maz>g_^YGfe#l*Y``&n_x$;x5cPMzr580QkgfIO4SQq;fe3N)
zB#b7TXLwR%I#Y1p<9m=Cxpqzt@G_!P^GD#te)Nf0o@hq!3%@E)$ZbKRlTrj
z3y?T9$*83ft^Ms?_QrO{x^`vRxE8qbpZS
z>ddiQXSr|k?V5yfhb0|K@sqR;Swa$W`z&O8WTm`9`Z*n0v$-m9gPtn8XJFVg=|N7z
z50!L~e3Ek`BK>x<7$b@!)}zgPxKTKA)b*3G$*cSQc@p&t&1+6A^521O?qSo(hJRK#
zlYTp~xI1h?MbT{~eY}J$WHi{QmFacv40=o^a^-1`1><1wQyCi7l>EDU$2vuT2azm(7&sLVgFZh_8ipJT{8mQ3IPA
z{Wju10}4iza=I$=i;mP`t?{iWQB-cPQ+U+{nTe-yse}pJDufW#yf-mFEK!M)S?!+H(=g0i>9h@cV)B%O;|>+Z`Z0D*Ap`Y%L`JOgya>eC>5puNQ`SI+po
znjs1I-e3C;)PEp&K7{Zid8!wn$K~~5E3Y_xhu2HkyPMxxCH}lUzrr@-no--Dm-pyt
z;B|HXqiT&1)jzzi*BqbIFFlwgr*!r50?V8
z#TJABB3vsTaV69|850!+>1Wjs|I$3r6$a?|VPb8LSRu+d-KB0QDRZ#&TYnFBbe0)8
z#PuL%j5)k3eBRLOeKCyIVg$_oAGxuu=NjVwZDZPru3TV8C{BG0VI)4E=2db&
zq_)a_VbS;{?*9WvK)AociuhuXP4AlDvQtor@!YnJU(VlXRr0NNnjvY_z_$7wVb5-q
z5js%j_0?n>C#*2*g;nrB92Y#3B?AkUwm>9l;5Vc+A{0r2LCoP+?Yr{)KY%vAJeH2_
zik*yV-;2a%ySv}ftEjH@CN7vt=|F~hWN}d?l#u-Dh
zRN@u+@0{hYJ+wzTaDCZrn*yS&T;0ousa&$241-#}lox@`#6;+4PoF*jVj~Nt-8`}O
zy$AXp&Y{c;n0PEjzM5ZVU-A4c+<0QVnl8ndc^m5LVzH_
zaliS-=@L+Il^?F={ID_p$?1YERhO`II;2Pl1?&cWw>Y=(1En!z@#aMT3sr>TBC_An
z^B=)y@I-7MaNP%6nYDgtqNXkKJJ&xO&DB!XzN9l_8xL)sSO>+;ez$GS-@xMrphYw_u+n2DdpbAW?Wv7=Gv??Q~j%QGK~mR`k1mNH;P_KvpE
zvtx>C3DK(X{K~nj^Q3dApr?14m-{POvy@9{bFpM6feXa>^*RpB&@L36GBS0fu1&_v
zMxm$DaFo{_x(DB;2(fD=dcQ-6I`A=vVEe#NijrVAmlG1Og^(QMLs>XY+ev}{V9RD3
zGc3EcBZFMlx9T2GxtVQgn$~e$48zG|yVrs7T~NOs3T_2uzmG8{ry7SF0^pcomG7~m
z_HDTvc%-Ek#^uJhd=jsVC4qguKlZuU*V-6&@oehUKPwG9)WKCo
zS6U*yoxEpJ%Pw)D(h3vm@aihAwZwwh@+ZIO45ziK3e|I|`2yb&ecm!RGG3p{@GKLa
zK`j>b_5^#77>YHE7`daCwrtxqG{s7fmRu+4FZ`#Q(tUwcES@(Q(Jr_*33iu2{R>*T
zmT=2S&MNU*$reI)=`}czP**wCaXh_VLE$Wo^F*)*2u3`=QAtl$dbo)b+EGTq<_X5i
z1S4lu?ghfed2x%6P`Qp25!k4eumOAwX$OSgUl{ca!`QZMLX9(1pDJ|=ksrAEh?@W%
zMCg&q&%fyl3RITqMz&}mK(3$u^k9F%b3r+0fBs=Ohu89&5MG(N`MKzF6oB*xLd^j@
zn4*MvoFyuMNaNoKb=;Obh^Upx67GiI(9trnkXZ{G55FxMlae>*x@YDE|1c*wS}Yvs
z)+S+<+P)hZefR}9gP`@-d{}U1F8m}-(0?4sD6PBhPvMk^)+JcDYsOuRLzNNZGeKg3GbF7%z?G{@-E{
z^)3ytMU)%8sC|8rfH#)Iojcn@nPGsZEFl1U_ezf9G$;YQK;{AGc7TjCHr1P}8HFcB
zG~0N@_l>)Zh#>`YM1c++4Lo8NQN7Q$x!vyz>~7X^W(|&_+PJahYx#7!>)36`7@G0H
zU-`f*vp5i`Yx5q<3*mq&@ij1b{t<{~I#4-=P3lyT6kCAR;Dq)hm*Ed$*vz*^lJch(vMwgVjI^PE7V1
z2-+Z87Li$O4vr6*^+vW>6^D^k^eC+FGJn%*Mf(Wv{QR8U^Xp4eBf
z<@+Z=^>3c}C)crUXU)M&=GP5bV`D%xvFZVFl`iH(-JfRRWM9Fdp_|aPTvuZ*q?Slc
zbnCc>tm7M?YUDC~XoKxC14)~^9ubB8@IX-PrjKpwm)tB7u6XV999h
z%pKE+IAga;HCL;xaR`g%rXA@Qvc9VM%y%vA6BZq4@toi~MZ#|9Un
zbS^WFKFIjQJ<`Z#*SoGe bN((
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 |