第一章:go test测试单个函数
在Go语言中,使用 go test 工具对单个函数进行测试是一种高效且标准的做法。通过编写测试用例,可以验证函数在各种输入条件下的行为是否符合预期,从而提升代码的健壮性。
编写测试文件
Go语言约定测试文件以 _test.go 结尾,并与被测文件位于同一包中。例如,若源码文件为 math.go,则测试文件应命名为 math_test.go。测试函数必须以 Test 开头,参数类型为 *testing.T。
package main
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
expected := 5
if result != expected {
t.Errorf("Add(2, 3) = %d; expected %d", result, expected)
}
}
上述代码中,t.Errorf 在测试失败时记录错误并标记测试为失败。每个测试函数应聚焦于一个具体功能点。
运行指定测试
使用 -run 标志可运行特定测试函数。例如,仅执行 TestAdd 可使用以下命令:
go test -run TestAdd
该命令会匹配测试函数名中包含 “TestAdd” 的用例,支持正则表达式,如 -run ^TestAdd$ 精确匹配。
测试执行流程说明
- Go测试框架自动查找所有
TestXxx函数; - 按字母顺序依次执行;
- 每个测试独立运行,避免相互影响;
- 输出结果包含PASS/FAIL状态及耗时。
| 命令 | 作用 |
|---|---|
go test |
运行当前包所有测试 |
go test -v |
显示详细输出 |
go test -run TestName |
运行匹配名称的测试 |
合理利用这些特性,可快速定位和验证单个函数逻辑。
第二章:理解go test的基本执行机制
2.1 Go测试函数的命名规范与结构
Go语言中,测试函数的命名需遵循特定规范,确保被go test命令自动识别。每个测试函数必须以Test为前缀,后接大写字母开头的驼峰式名称,且参数类型为*testing.T。
基本命名结构
func TestCalculateSum(t *testing.T) {
// 测试逻辑
}
Test:固定前缀,标识该函数为测试用例;CalculateSum:被测函数或功能的描述,首字母大写;t *testing.T:用于错误报告和控制测试流程的参数。
常见命名模式
TestFunctionName:测试具体函数;TestFeatureDescription:测试某一功能逻辑;TestEdgeCaseScenario:验证边界条件。
表格:合法与非法命名对比
| 合法命名 | 非法命名 | 原因 |
|---|---|---|
TestValidateInput |
testValidateInput |
缺少Test前缀 |
TestWithBoundary |
Test_with_underscore |
使用下划线,不符合驼峰规范 |
TestParseJSON |
TestParseJson |
JSON 应全大写保持一致性 |
遵循命名规范有助于提升测试可读性与可维护性。
2.2 go test命令的默认行为分析
当在项目根目录执行 go test 时,Go 工具链会自动扫描当前包中以 _test.go 结尾的文件,并运行其中以 Test 为前缀的函数。
默认测试范围与执行机制
Go test 默认仅运行 Test 开头且签名为 func(t *testing.T) 的函数。它不会自动递归子目录,除非显式使用 go test ./...。
测试流程示意
func TestAdd(t *testing.T) {
result := Add(2, 3)
if result != 5 {
t.Errorf("期望 5,实际 %d", result)
}
}
该测试函数验证 Add 函数的正确性。t.Errorf 在断言失败时记录错误并标记测试为失败,但不中断执行。
参数行为对照表
| 参数 | 默认值 | 说明 |
|---|---|---|
-v |
false | 显示详细输出,包括 t.Log 内容 |
-run |
“” | 正则匹配测试函数名 |
-count |
1 | 执行次数,用于检测偶发问题 |
执行流程图
graph TD
A[执行 go test] --> B{查找 *_test.go 文件}
B --> C[解析 Test* 函数]
C --> D[依次运行测试函数]
D --> E[汇总通过/失败结果]
E --> F[输出报告]
2.3 -v、-run等关键标志的作用解析
在容器化工具如Docker中,-v 和 -run 是启动容器时常用的关键标志,它们分别控制存储卷挂载与运行时行为。
-v 标志:实现数据持久化
docker run -v /host/path:/container/path nginx
该命令将主机目录挂载到容器内,确保数据在容器生命周期外持久存在。-v 参数格式为 主机路径:容器路径,支持读写或只读模式(通过 :ro 指定)。
-run 标志的语义解析
尽管 -run 并非独立标志,它是 docker run 命令的一部分,用于启动新容器。完整语义是创建并运行一个实例,结合其他标志完成资源配置。
常用标志组合示例
| 标志 | 作用 | 典型用途 |
|---|---|---|
-v |
挂载卷 | 数据持久化 |
-d |
后台运行 | 服务部署 |
--rm |
临时容器 | 测试环境 |
启动流程可视化
graph TD
A[docker run] --> B{检查镜像是否存在}
B -->|存在| C[创建容器]
B -->|不存在| D[拉取镜像]
D --> C
C --> E[挂载-v指定的卷]
E --> F[启动容器进程]
2.4 测试文件的识别与加载流程
在自动化测试框架中,测试文件的识别是执行流程的第一步。系统通常通过命名约定或配置规则来扫描目标目录下的测试脚本。
文件识别策略
常见的识别方式包括:
- 文件名前缀匹配(如
test_*.py) - 特定目录归类(如
/tests/unit/) - 装饰器标记(如
@pytest.mark)
加载机制流程
使用 pytest 框架时,其内部通过 pkgutil 和 importlib 动态导入模块:
# conftest.py 示例
import os
import pytest
def pytest_collect_file(parent, path):
if path.basename.startswith("test_") and path.ext == ".py":
return parent.session._collectfile(path)
该钩子函数拦截文件收集过程,判断是否以 test_ 开头且为 .py 文件,符合条件则纳入测试集。
执行流程可视化
graph TD
A[扫描项目目录] --> B{文件名匹配 test_*.py?}
B -->|是| C[导入模块]
B -->|否| D[跳过]
C --> E[解析测试用例]
E --> F[加入执行队列]
2.5 单函数执行的前提条件与限制
单函数执行模型广泛应用于无服务器架构中,其运行依赖于明确的触发机制与上下文环境。函数在执行前必须满足一系列前提条件,否则将导致调用失败或不可预期行为。
执行环境初始化
运行时需确保语言环境、依赖库和配置参数已正确加载。平台通常基于容器隔离每个函数实例,冷启动时耗时主要集中在此阶段。
触发源合法性验证
函数只能由预定义的事件源触发,例如 API 网关请求、消息队列事件或定时器。非法调用将被拒绝。
资源与权限约束
执行受限于内存、超时时间和 IAM 策略。以下为典型配置示例:
| 配置项 | 默认值 | 最大值 |
|---|---|---|
| 内存 | 128 MB | 10,240 MB |
| 超时时间 | 3 秒 | 900 秒 |
| 并发执行数 | 1 | 可申请扩展 |
执行逻辑限制
函数应保持无状态且幂等,避免依赖本地文件系统或长连接。以下代码展示一个合规的处理函数:
def handler(event, context):
# event: 触发事件数据,如HTTP请求体
# context: 运行时上下文,包含函数元信息
if not event.get("data"):
return {"error": "Missing input data"}
return {"result": process(event["data"])}
该函数接收事件输入,执行轻量处理并立即返回,符合无状态与快速终止原则。平台据此保障高并发下的稳定性与资源隔离。
第三章:精准运行指定测试函数的实践方法
3.1 使用-go test -run匹配函数名称
在 Go 的测试体系中,-run 标志支持通过正则表达式筛选要执行的测试函数,极大提升了开发过程中的调试效率。例如,当项目包含大量测试用例时,可精准运行特定函数。
精确匹配示例
func TestUserValid(t *testing.T) { /* 验证用户合法性 */ }
func TestUserSave(t *testing.T) { /* 测试用户保存 */ }
func TestOrderCreate(t *testing.T) { /* 创建订单逻辑 */ }
执行命令:
go test -run TestUserValid
该命令仅运行名为 TestUserValid 的测试函数。参数 -run 后接的字符串会被当作正则表达式处理,因此支持更灵活的模式匹配,如 go test -run User 将运行所有函数名包含 “User” 的测试。
常见匹配模式
| 模式 | 匹配目标 |
|---|---|
TestUser |
所有含 “TestUser” 的函数 |
^TestUser$ |
完全匹配该名称 |
Create|Save |
包含 Create 或 Save |
使用正则能力可实现精细化控制,适合大型测试套件的分步验证。
3.2 正则表达式在-run后的高级用法
在自动化脚本执行中,-run 命令常用于触发任务,结合正则表达式可实现对输出结果的精准提取与条件判断。
动态匹配运行日志
使用正则捕获 -run 后的输出信息,例如识别任务ID:
run_output="Task-12345 started successfully"
[[ $run_output =~ Task-([0-9]+) ]] && task_id=${BASH_REMATCH[1]}
上述代码通过 [[ =~ ]] 结构匹配字符串,([0-9]+) 捕获任务编号,存储于 BASH_REMATCH[1] 中,便于后续调用。
多模式条件处理
可构建匹配规则表应对不同状态:
| 状态模式 | 正则表达式 | 动作 |
|---|---|---|
| 成功启动 | started\ssuccessfully |
继续流程 |
| 资源不足 | insufficient\smemory |
发出告警 |
| 权限拒绝 | permission\sdenied |
终止并记录 |
异常分支控制流程
通过正则判断跳转处理分支:
graph TD
A[执行 -run] --> B{输出匹配正则}
B -->|匹配 success| C[标记完成]
B -->|匹配 error| D[触发重试机制]
B -->|匹配 denied| E[通知管理员]
这种机制提升了脚本的自适应能力,使自动化系统更健壮。
3.3 避免常见匹配错误的技巧示例
在正则表达式中,常见的匹配错误往往源于对元字符的误用或量词的贪婪性理解不足。例如,使用 .* 匹配引号内容时容易越界:
".*"
该模式在文本 "name": "Alice" 中会匹配整个 ": "Alice",而非独立的 name 或 Alice。应改为非贪婪模式:
".*?"
通过添加 ?,引擎在遇到第一个引号时即停止,精准捕获目标内容。
使用字符类限制范围
避免使用过于宽泛的通配符,可用 [a-zA-Z]+ 替代 \w+ 以排除下划线和数字干扰。
锚定边界提升精度
利用 ^ 和 $ 锁定行首行尾,防止意外匹配子串。例如验证邮箱格式时:
| 模式 | 说明 |
|---|---|
^\w+@\w+\.\w+$ |
确保整行完全匹配邮箱结构 |
\w+@\w+\.\w+ |
可能误匹配文本中的部分字符串 |
防止回溯失控
复杂嵌套量词易引发性能问题,可通过固化分组或限制重复次数优化。
第四章:提升测试效率的配套技巧
4.1 结合-buildflags加快编译速度
Go 编译器提供了 -buildflags 参数,允许在构建过程中传递底层编译选项,合理配置可显著提升编译效率。
优化编译器行为
通过设置 -gcflags 控制 Go 编译器的代码生成行为:
go build -gcflags="-N -l" main.go
-N:禁用优化,便于调试;-l:禁用函数内联,减少编译复杂度;
在开发阶段关闭优化可加快编译速度,但在生产构建中应移除这些标志以获得性能优势。
并行编译与缓存
启用编译缓存和并行处理能进一步加速:
go build -buildvcs=false -a -o app
-buildvcs=false:跳过版本控制信息嵌入;-a:强制重新编译所有包,结合缓存策略更可控;
常用标志对比表
| 标志 | 作用 | 适用场景 |
|---|---|---|
-N |
禁用优化 | 调试 |
-l |
禁用内联 | 快速编译 |
-buildvcs=false |
忽略 VCS 信息 | CI/CD 流水线 |
-a |
强制重编译 | 清洁构建 |
合理组合这些标志,可在不同阶段实现编译速度与输出质量的平衡。
4.2 利用-cover查看单测覆盖率
在Go语言开发中,测试覆盖率是衡量代码质量的重要指标。go test 提供了 -cover 参数,可快速查看单元测试对代码的覆盖情况。
基础使用方式
执行以下命令可输出覆盖率统计:
go test -cover
该命令会遍历当前包中的所有测试文件,运行测试并输出类似 coverage: 65.2% of statements 的结果。数值反映被测试执行到的语句占总可执行语句的比例。
详细覆盖报告
若需深入分析,可生成覆盖概要文件:
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
第二条命令将启动本地Web界面,以HTML形式高亮显示哪些代码行被覆盖、哪些未被执行。
覆盖率模式说明
| 模式 | 含义 |
|---|---|
set |
语句是否被执行 |
count |
每条语句执行次数 |
atomic |
多线程安全计数 |
推荐在CI流程中加入 -covermode=count 和阈值校验,确保关键路径被充分测试。
4.3 并行测试与-race检测的竞争规避
在并发程序中,数据竞争是导致不可预测行为的主要根源。Go 提供了 -race 检测器用于识别潜在的竞争条件,但在并行测试中需谨慎使用,以避免误报或掩盖真实问题。
数据同步机制
使用互斥锁可有效规避多个 goroutine 对共享变量的竞态访问:
var mu sync.Mutex
var counter int
func increment() {
mu.Lock()
defer mu.Unlock()
counter++ // 安全地修改共享状态
}
该代码通过 sync.Mutex 保证同一时间只有一个 goroutine 能进入临界区,从而消除数据竞争。-race 检测器将不会报告此段代码存在竞争。
并行测试中的注意事项
运行 go test -parallel N -race 时,并发执行的测试若共享资源而未加保护,会触发 race detector。推荐策略包括:
- 避免包级变量共享
- 使用局部变量替代全局状态
- 利用
t.Parallel()前确保无共享可变状态
| 策略 | 是否推荐 | 说明 |
|---|---|---|
| 共享变量加锁 | ✅ | 安全但可能降低并行度 |
| 使用通道通信 | ✅✅ | 更符合 Go 的哲学 |
| 忽略竞争警告 | ❌ | 可能埋藏严重 bug |
检测流程可视化
graph TD
A[启动并行测试] --> B{是否存在共享状态?}
B -->|是| C[加锁或使用 channel]
B -->|否| D[直接并行执行]
C --> E[运行 -race 检测]
D --> E
E --> F[输出结果与竞争报告]
4.4 清晰输出日志辅助调试过程
良好的日志输出是排查问题的第一道防线。通过合理分级、结构化记录,可快速定位异常源头。
日志级别与使用场景
合理使用日志级别能有效过滤信息:
- DEBUG:详细流程,用于开发阶段
- INFO:关键步骤,如服务启动、配置加载
- WARN:潜在问题,不影响当前执行
- ERROR:异常事件,需立即关注
结构化日志示例
import logging
logging.basicConfig(format='%(asctime)s [%(levelname)s] %(message)s', level=logging.DEBUG)
logging.info("User login attempt", extra={"user_id": 123, "ip": "192.168.1.1"})
使用
extra参数注入上下文字段,便于后续在 ELK 等系统中按字段检索。时间戳、级别、消息体标准化,提升日志解析效率。
日志采集流程
graph TD
A[应用输出日志] --> B(本地日志文件)
B --> C{日志收集Agent}
C --> D[集中存储ES]
D --> E[可视化分析Kibana]
通过统一的日志链路,实现从生成到分析的闭环追踪。
a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a i a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aa a a a a a a a a a a a a a a a a a a a a a aa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aa a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a aa a a아피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피피
