From 43de86ee31532b4c0690bbdd49798300e2eb3313 Mon Sep 17 00:00:00 2001
From: ninemine <1371605831@qq.com>
Date: Wed, 26 Nov 2025 14:35:58 +0800
Subject: [PATCH] Init
---
.gitattributes | 2 +
.gitignore | 13 +
.gitmodules | 3 +
CMakeLists.txt | 11 +
CMakeSettings.json | 27 +
README_TEST.md | 112 ++++
Tracy_Macro_CheatSheet.pdf | 143 +++++
UNITY_INTEGRATION_GUIDE.md | 802 ++++++++++++++++++++++++++++
main.cpp | 355 ++++++++++++
thirdparty/tracy | 1 +
tracy-0.13.0.zip | Bin 0 -> 12259626 bytes
unity_examples/CMakeLists.txt | 298 +++++++++++
unity_examples/QUICKSTART.md | 494 +++++++++++++++++
unity_examples/README.md | 484 +++++++++++++++++
unity_examples/SimplifiedPlugin.cpp | 287 ++++++++++
unity_examples/TracyExamples.cs | 396 ++++++++++++++
unity_examples/TracyManager.cs | 269 ++++++++++
unity_examples/TracyWrapper.cs | 257 +++++++++
18 files changed, 3954 insertions(+)
create mode 100644 .gitattributes
create mode 100644 .gitignore
create mode 100644 .gitmodules
create mode 100644 CMakeLists.txt
create mode 100644 CMakeSettings.json
create mode 100644 README_TEST.md
create mode 100644 Tracy_Macro_CheatSheet.pdf
create mode 100644 UNITY_INTEGRATION_GUIDE.md
create mode 100644 main.cpp
create mode 160000 thirdparty/tracy
create mode 100644 tracy-0.13.0.zip
create mode 100644 unity_examples/CMakeLists.txt
create mode 100644 unity_examples/QUICKSTART.md
create mode 100644 unity_examples/README.md
create mode 100644 unity_examples/SimplifiedPlugin.cpp
create mode 100644 unity_examples/TracyExamples.cs
create mode 100644 unity_examples/TracyManager.cs
create mode 100644 unity_examples/TracyWrapper.cs
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..dfe0770
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# Auto detect text files and perform LF normalization
+* text=auto
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..02d0cd0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,13 @@
+CMakeLists.txt.user
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Testing
+Makefile
+cmake_install.cmake
+install_manifest.txt
+compile_commands.json
+CTestTestfile.cmake
+_deps
+/.vs
+/out
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..2df36a2
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "thirdparty/tracy"]
+ path = thirdparty/tracy
+ url = https://github.com/wolfpld/tracy.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..25780fb
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.14)
+project(TestTracy)
+
+# 可用的选项:TRACY_ENABLE,TRACY_ON_DEMAND,TRACY_NO_BROADCAST,TRACY_NO_CODE_TRANSFER , ...
+# 在add_subdirectory之前设置选项
+option (TRACY_ENABLE "" ON)
+option (TRACY_ON_DEMAND "" ON)
+add_subdirectory ("thirdparty/tracy")
+#链接 `Tracy::TracyClient` 到你想要用Tracy进行性能分析的目标。
+add_executable(MyProject main.cpp)
+target_link_libraries (MyProject PUBLIC Tracy::TracyClient)
\ No newline at end of file
diff --git a/CMakeSettings.json b/CMakeSettings.json
new file mode 100644
index 0000000..0c5fbf9
--- /dev/null
+++ b/CMakeSettings.json
@@ -0,0 +1,27 @@
+{
+ "configurations": [
+ {
+ "name": "x64-Debug",
+ "generator": "Ninja",
+ "configurationType": "Debug",
+ "inheritEnvironments": [ "msvc_x64_x64" ],
+ "buildRoot": "${projectDir}\\out\\build\\${name}",
+ "installRoot": "${projectDir}\\out\\install\\${name}",
+ "cmakeCommandArgs": "",
+ "buildCommandArgs": "",
+ "ctestCommandArgs": ""
+ },
+ {
+ "name": "x64-Release",
+ "generator": "Ninja",
+ "configurationType": "RelWithDebInfo",
+ "buildRoot": "${projectDir}\\out\\build\\${name}",
+ "installRoot": "${projectDir}\\out\\install\\${name}",
+ "cmakeCommandArgs": "",
+ "buildCommandArgs": "",
+ "ctestCommandArgs": "",
+ "inheritEnvironments": [ "msvc_x64_x64" ],
+ "variables": []
+ }
+ ]
+}
\ No newline at end of file
diff --git a/README_TEST.md b/README_TEST.md
new file mode 100644
index 0000000..3a5c502
--- /dev/null
+++ b/README_TEST.md
@@ -0,0 +1,112 @@
+# Tracy 性能测试代码说明
+
+这个项目包含多个高性能计算测试用例,用于展示 Tracy 性能分析器的功能。
+
+## 测试内容
+
+### 1. 矩阵乘法 (Matrix Multiplication)
+- 200x200 矩阵相乘
+- 展示计算密集型操作的性能
+- 三重循环,复杂度 O(n³)
+
+### 2. 快速排序 (Quick Sort)
+- 对 100,000 个随机整数进行排序
+- 展示递归算法的性能特征
+- 平均复杂度 O(n log n)
+
+### 3. 质数计算 (Prime Numbers)
+- 使用埃拉托斯特尼筛法
+- 计算 0-1,000,000 范围内的所有质数
+- 展示循环嵌套和内存访问模式
+
+### 4. 蒙特卡罗π值计算 (Monte Carlo Pi)
+- 使用随机采样方法估算π值
+- 10,000,000 次迭代
+- 展示随机数生成和条件判断的性能
+
+### 5. 斐波那契数列 (Fibonacci)
+- **递归方法**: fibonacci(35) - 展示递归调用的开销
+- **动态规划**: fibonacci(90) - 展示优化算法的性能差异
+
+### 6. 向量点积 (Vector Dot Product)
+- 10,000,000 维向量点积计算
+- 展示大规模线性代数运算
+- 内存访问密集型操作
+
+### 7. 复杂数学运算 (Complex Math)
+- sin, cos, tan, sqrt, log 等函数组合
+- 1,000,000 次迭代
+- 展示浮点运算性能
+
+### 8. 内存密集型操作 (Memory Intensive)
+- 创建 1000x1000 二维数组
+- 填充和遍历大量数据
+- 展示内存分配和访问模式
+
+### 9. 多线程测试 (Multi-Threading)
+- 8 个线程并行执行
+- 每个线程执行 50,000,000 次计算
+- 展示多线程性能和同步开销
+
+## 如何使用
+
+### 1. 编译项目
+```bash
+# 在 Visual Studio 中打开项目
+# 选择 Release 配置以获得最佳性能测试结果
+# 构建项目
+```
+
+### 2. 启动 Tracy Profiler
+```bash
+# 从 Tracy 仓库的 profiler 目录运行
+# 或使用预编译的 Tracy.exe
+```
+
+### 3. 运行测试程序
+```bash
+# 运行 MyProject.exe
+# Tracy Profiler 会自动连接(如果启用了 TRACY_ON_DEMAND)
+```
+
+### 4. 在 Tracy 中观察
+- 查看每个函数的执行时间
+- 比较递归 vs 动态规划的性能差异
+- 观察多线程的并行执行情况
+- 分析热点函数和瓶颈
+
+## Tracy 宏说明
+
+- `ZoneScoped`: 自动追踪整个函数的执行时间
+- `ZoneScopedN("名称")`: 追踪代码块并指定自定义名称
+- `FrameMark`: 标记帧边界,便于区分不同的测试轮次
+
+## 性能优化建议
+
+根据 Tracy 的分析结果,你可以:
+
+1. **识别热点**: 找出耗时最长的函数
+2. **优化算法**: 比较不同算法实现(如递归 vs 动态规划)
+3. **并行化**: 识别可以并行化的计算
+4. **缓存优化**: 观察内存访问模式,优化数据结构
+5. **减少递归**: 递归调用会带来额外开销
+
+## 预期结果
+
+在 Tracy Profiler 中,你应该能够看到:
+
+- **矩阵乘法**: 相对较长的执行时间,CPU 密集
+- **递归斐波那契**: 大量重复的函数调用(可视化调用树)
+- **动态规划斐波那契**: 单次执行,线性时间
+- **多线程**: 8 个并行执行的线程,清晰的时间线
+- **质数计算**: 循环密集,但相对高效
+- **蒙特卡罗**: 稳定的执行时间,随机数生成开销
+
+## 提示
+
+- 使用 Release 配置编译可以获得更接近实际应用的性能数据
+- 多次运行测试可以在 Tracy 中观察性能的一致性
+- 尝试修改参数(矩阵大小、迭代次数等)观察性能变化
+- 使用 Tracy 的统计功能分析函数调用次数和平均执行时间
+
+
diff --git a/Tracy_Macro_CheatSheet.pdf b/Tracy_Macro_CheatSheet.pdf
new file mode 100644
index 0000000..d5e2949
--- /dev/null
+++ b/Tracy_Macro_CheatSheet.pdf
@@ -0,0 +1,143 @@
+%PDF-1.4
+% ReportLab Generated PDF document http://www.reportlab.com
+1 0 obj
+<<
+/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 5 0 R
+>>
+endobj
+2 0 obj
+<<
+/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
+>>
+endobj
+3 0 obj
+<<
+/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
+>>
+endobj
+4 0 obj
+<<
+/BaseFont /ZapfDingbats /Name /F3 /Subtype /Type1 /Type /Font
+>>
+endobj
+5 0 obj
+<<
+/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
+>>
+endobj
+6 0 obj
+<<
+/Contents 13 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
+/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
+>> /Rotate 0 /Trans <<
+
+>>
+ /Type /Page
+>>
+endobj
+7 0 obj
+<<
+/Contents 14 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
+/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
+>> /Rotate 0 /Trans <<
+
+>>
+ /Type /Page
+>>
+endobj
+8 0 obj
+<<
+/Contents 15 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
+/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
+>> /Rotate 0 /Trans <<
+
+>>
+ /Type /Page
+>>
+endobj
+9 0 obj
+<<
+/Contents 16 0 R /MediaBox [ 0 0 841.8898 595.2756 ] /Parent 12 0 R /Resources <<
+/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
+>> /Rotate 0 /Trans <<
+
+>>
+ /Type /Page
+>>
+endobj
+10 0 obj
+<<
+/PageMode /UseNone /Pages 12 0 R /Type /Catalog
+>>
+endobj
+11 0 obj
+<<
+/Author (\(anonymous\)) /CreationDate (D:20251016122249+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20251016122249+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
+ /Subject (\(unspecified\)) /Title (Tracy Profiler Macros Cheat Sheet \(Complete\)) /Trapped /False
+>>
+endobj
+12 0 obj
+<<
+/Count 4 /Kids [ 6 0 R 7 0 R 8 0 R 9 0 R ] /Type /Pages
+>>
+endobj
+13 0 obj
+<<
+/Filter [ /ASCII85Decode /FlateDecode ] /Length 1664
+>>
+stream
+Gat%#gN)%.%"6H'i).V+MF:CP^,^)%kt[^Sm,h`s1HV[3gM/%^.oAmoY@!BcAB>X!'Ak2L`&Rrd!-,ikQ`Im]%,c"([keh*!fJqGe>BJF#k&R27NQ9K@u!NiNru!Y0%`"$grK`TURi-Q:i+Vgf,,#=C.C8LHEbK+Ej&pA',EOL^qWs1'(Nf5JP?3l7j^3(46).,B[[F@#ja9c4[2!5m/U-UDeB4.:pD65EO-DaMtc_;&F1V'"ajd!+\GiLKUH^
s1klq1DYnG#"LRR/q;No9SQGV&o%e5k:K;@:TMiOZJf_(h"'BM3X*?Y<5!P_K+>bC9JCtsBGEm<`Kc%<]!cI&98<33TLF-:GGaLdIB8!HJ.W8$u\8-?n"Q=9!P'^Vb]j]m(t3oK&]%A?U;=PmB:Om`DrL#_'&!Cfbr!!f]4EI]/Q'"+KS5WhK7%;Ma.@P#6NP3[n,"/,:O!9DX$6NGNuL'R)NV]-[4:J\G]HiPPK*PD2/(-?`Bc;%*$q3V/(A6\oQGJ^V[7)FT14'ooqZBL-d43ET7C]N:"5f_9bU?KTk,S?,a&=/?TKkV^0HeI,nMdZRc&hfhUCoa>*pA\lgn4CjPFFOlY4@J?W9.Se8Q/pAks2Z?_Zc[MRY;0E00g$le(Ql?ti-d"$YtUbaAH8Ka`Ami#ah$>/;?G>5/n0c2n*HLDVT05'LM:[=HC9SoBSs$kOg1EnGfFfMfrKn4/m)F,W&rp2XkYC@OA^ca<-]tGMZ$)rM6;0Z7E42\B$-t,s(FjO!JKZd4#@0V@3:HWO_S?W]"YiaeN7k8lu;I\YROK1md,qi#p/M1jYlqs\'c*`RC(f&LY`-p&3Y0u%3&endstream
+endobj
+14 0 obj
+<<
+/Filter [ /ASCII85Decode /FlateDecode ] /Length 1259
+>>
+stream
+Gb!;bgMZ%0&:O:SbbML@)3WQnhn#-g/N,mQ1!g^=Kd'I(G',<(2=#^>LD4;MNj$QJJW4*%)9n[3]Z_6JT_MsX2^na`:#YZ#!TPk.J[r^QkpQ6c*Ed`"b`me39I>>Z"q6;,;&8sm4P-?*#]cU`Qj"#"9-Sc+4I?m_:g!rNP\OjFQ9LYTbn7k9[W1XD+=`tIEO[D#;m([ckhOM2TpaJV>f_Y.[A"5`k6GaA@0T6j+l7$E.JRa1aP[(@9K7gK"$r:(ad_ZONI6o^:MHF`0Qi8.A<[sW7*qAo4u!gnU!)m8p^Yh9+C*j.Z6'8UZ=<=1IV3fXW#W/9_ZZ\,gY^n0W$_/VXXQT32Ap(O]>L5j`Pc0U&KL@SciTBl\8ZG["AQuQ:a041>+P[P']ndJ62U:sQ4D&ZBFI"+T/@Jr3>P4>]jVD:nIqJ>2I*:$V,C>o((b6%&a0+9-ZJI6E.HZ%r]_4Fg2b0?1kAN;XC$W?nC2\FQ#M/*bNT5Jq:6YX'8f,#S$=o'@NG[b7@]d<;g"s]-4oH%?_OiTdCE^;RV<2^RlGNU:dDg3UUc%@X\c\@S*ERa>'/_a#X*bD"Q'LVL]!"Q"'4F$cVYhC*U%Aj?[A$bRhaHqu0&NR"oXT1Q$1<-:g'"Fm%r;ogH)48L%W$/TF4d1f#Gn_meu+ZP)$82$0OsYBr,oS]fbd.fN0gQ(14p(.)U>QnVI,$&XdiWendstream
+endobj
+15 0 obj
+<<
+/Filter [ /ASCII85Decode /FlateDecode ] /Length 1262
+>>
+stream
+Gb"/&9lJcG&A@sB%!kg/PUd(@H&R]8%sH'T>DkDIlD)R'c+]h]X:'`'$YN5K`K_qp-9[![A)GiKu69Y8lA%Yj.;9#J[Cn[+e<]i2t4EZ'9Nnbp@hIN#8B:FIWp3>N8-Ra/:Pq$3Ca55XNb$0@]>t`8Q,j%Y\!>JPpN!.gZP`:Z^ClcmKCSX_7Z=dS,poSC71Y$%`I5ZY#uGuXOIY/h_(1/"?i9$1Zd(ZbjW^UT34d8=/YlZLRapb#/>oQ_$2npQ68F;?sV\^%7:StU;@C<_>2i^17hW%U6Un0LgD(\;F8Dm.c`'``QM1^L`?Mm)[^212?%["C6(5NJ(J33Z2o'uB@f?[%RUUIeDM/YTr_@)$.Z$qeW]>@W>jLJ\IR!R_=.4YHX?beBAn>:SoE][">:#?<=^cOf_8O9*)57Wc[?T\1:H4S*&]9e^L?lO/iCOd%[9UZ>UknQ6.&`2<_93klUE;M)^X<#J-0d^qD4al\R3lY5:L!-1dOiWiT21-1"7$8Z'2Ab^e&bThl*2l9]Vl(hHS`15C+=Jck557n9[KIFVVlJBZI:]q-/,"#R3)^jlPt&6`*TsELu_gcXL\2a_'DPGP5iW\d9DW9M0582g>i[_qM+KfU\ON]YJDoLp"lIo(&pj:4@H`2#!m^-lBe%oml2^O]Q*q]F69"6H/~>endstream
+endobj
+16 0 obj
+<<
+/Filter [ /ASCII85Decode /FlateDecode ] /Length 996
+>>
+stream
+Gatm9?#SFN'Rf.Ggo$!PRVP"1=5RZu.oQU%7&qe;67E%.#GFf=fD4EU6B"@!7N2i36br)F\K&^n$3/]=+s1,c^`^SS.?F5Y5S#QY75W2K9:^Frj&0N!:L*SHAXo%d\Mt&g6+Q$p3Jl,a\#MOhJGI\9s.A,&ENR&C.sMo=H`a@'pA=E]ZJ0*c["q!S(QpU.ZI`ZX(=B8h:GEkZKu'S:+8oj`\t+Tp1)b,&jGJr*S7n$Yp5!Os%c&`O$sLQTEi/79,mN7ehCooh-nqFL.=tO.[8,jk!_&N+e$Z]GZOifQ$KEfSaKL):fBt6lZl6h-a_A#p#TbM'us"[HDendstream
+endobj
+xref
+0 17
+0000000000 65535 f
+0000000073 00000 n
+0000000134 00000 n
+0000000241 00000 n
+0000000353 00000 n
+0000000436 00000 n
+0000000551 00000 n
+0000000756 00000 n
+0000000961 00000 n
+0000001166 00000 n
+0000001371 00000 n
+0000001441 00000 n
+0000001758 00000 n
+0000001836 00000 n
+0000003592 00000 n
+0000004943 00000 n
+0000006297 00000 n
+trailer
+<<
+/ID
+[<4aefb1af7e31205ddcd23c78d196600e><4aefb1af7e31205ddcd23c78d196600e>]
+% ReportLab generated PDF document -- digest (http://www.reportlab.com)
+
+/Info 11 0 R
+/Root 10 0 R
+/Size 17
+>>
+startxref
+7384
+%%EOF
diff --git a/UNITY_INTEGRATION_GUIDE.md b/UNITY_INTEGRATION_GUIDE.md
new file mode 100644
index 0000000..e9855c5
--- /dev/null
+++ b/UNITY_INTEGRATION_GUIDE.md
@@ -0,0 +1,802 @@
+# Tracy 集成到 Unity 的完整指南
+
+## 概述
+
+Tracy 是一个强大的 C++ 性能分析工具,要在 Unity 中使用它,需要通过 **Native Plugin** 的方式集成。本指南将介绍两种主要的集成方法。
+
+---
+
+## 方法一:通过 Native Plugin 集成(推荐)
+
+这是最常用和最灵活的方法,适用于所有Unity项目。
+
+### 1. 创建 Tracy Native Plugin
+
+#### 步骤 1:创建 C++ 动态库项目
+
+创建一个新的 C++ DLL/Shared Library 项目:
+
+**目录结构:**
+```
+UnityTracyPlugin/
+├── src/
+│ ├── TracyUnityPlugin.cpp
+│ └── TracyUnityPlugin.h
+├── include/
+│ └── tracy/ # Tracy 源代码
+├── CMakeLists.txt
+└── build/
+```
+
+#### 步骤 2:编写 Plugin 代码
+
+**TracyUnityPlugin.h:**
+```cpp
+#ifndef TRACY_UNITY_PLUGIN_H
+#define TRACY_UNITY_PLUGIN_H
+
+// Unity Native Plugin 需要使用 C 导出
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// 平台定义
+#if defined(_WIN32) || defined(_WIN64)
+ #define UNITY_PLUGIN_EXPORT __declspec(dllexport)
+#elif defined(__APPLE__) || defined(__linux__)
+ #define UNITY_PLUGIN_EXPORT __attribute__((visibility("default")))
+#else
+ #define UNITY_PLUGIN_EXPORT
+#endif
+
+// Tracy API
+UNITY_PLUGIN_EXPORT void TracyInit();
+UNITY_PLUGIN_EXPORT void TracyShutdown();
+UNITY_PLUGIN_EXPORT void TracyFrameMark();
+UNITY_PLUGIN_EXPORT void TracyBeginZone(const char* name, const char* function, const char* file, int line);
+UNITY_PLUGIN_EXPORT void TracyEndZone();
+UNITY_PLUGIN_EXPORT void TracyPlotValue(const char* name, double value);
+UNITY_PLUGIN_EXPORT void TracyMessage(const char* message);
+UNITY_PLUGIN_EXPORT void TracySetThreadName(const char* name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TRACY_UNITY_PLUGIN_H
+```
+
+**TracyUnityPlugin.cpp:**
+```cpp
+#include "TracyUnityPlugin.h"
+#include "tracy/Tracy.hpp"
+#include
+#include
+#include
+
+// 用于管理 Zone 的结构
+struct ZoneContext {
+ tracy::ScopedZone* zone;
+};
+
+static std::unordered_map g_zones;
+static std::mutex g_zonesMutex;
+static int g_nextZoneId = 1;
+
+extern "C" {
+
+UNITY_PLUGIN_EXPORT void TracyInit() {
+ // Tracy 会自动初始化,这里可以做一些额外的设置
+}
+
+UNITY_PLUGIN_EXPORT void TracyShutdown() {
+ std::lock_guard lock(g_zonesMutex);
+ g_zones.clear();
+}
+
+UNITY_PLUGIN_EXPORT void TracyFrameMark() {
+ FrameMark;
+}
+
+UNITY_PLUGIN_EXPORT int TracyBeginZone(const char* name, const char* function, const char* file, int line) {
+ std::lock_guard lock(g_zonesMutex);
+
+ int zoneId = g_nextZoneId++;
+
+ // 创建 Zone(注意:这是简化版本,实际使用中需要更复杂的处理)
+ tracy::SourceLocationData loc;
+ loc.name = name;
+ loc.function = function;
+ loc.file = file;
+ loc.line = (uint32_t)line;
+
+ // 实际使用中,你可能需要使用 Tracy 的宏来正确创建 Zone
+ // 这里仅作示例
+
+ return zoneId;
+}
+
+UNITY_PLUGIN_EXPORT void TracyEndZone(int zoneId) {
+ std::lock_guard lock(g_zonesMutex);
+
+ auto it = g_zones.find(zoneId);
+ if (it != g_zones.end()) {
+ delete it->second.zone;
+ g_zones.erase(it);
+ }
+}
+
+UNITY_PLUGIN_EXPORT void TracyPlotValue(const char* name, double value) {
+ TracyPlot(name, value);
+}
+
+UNITY_PLUGIN_EXPORT void TracyMessage(const char* message) {
+ TracyMessage(message, strlen(message));
+}
+
+UNITY_PLUGIN_EXPORT void TracySetThreadName(const char* name) {
+ tracy::SetThreadName(name);
+}
+
+} // extern "C"
+```
+
+#### 步骤 3:CMakeLists.txt 配置
+
+```cmake
+cmake_minimum_required(VERSION 3.10)
+project(UnityTracyPlugin)
+
+set(CMAKE_CXX_STANDARD 17)
+
+# Tracy 配置
+option(TRACY_ENABLE "Enable Tracy profiling" ON)
+option(TRACY_ON_DEMAND "Tracy on-demand profiling" ON)
+
+add_definitions(-DTRACY_ENABLE)
+add_definitions(-DTRACY_ON_DEMAND)
+
+# Tracy 源文件
+set(TRACY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include/tracy")
+set(TRACY_SOURCES
+ ${TRACY_DIR}/public/TracyClient.cpp
+)
+
+# Plugin 源文件
+set(PLUGIN_SOURCES
+ src/TracyUnityPlugin.cpp
+ ${TRACY_SOURCES}
+)
+
+# 包含目录
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${TRACY_DIR}/public
+)
+
+# 创建动态库
+add_library(UnityTracyPlugin SHARED ${PLUGIN_SOURCES})
+
+# Windows 平台设置
+if(WIN32)
+ target_link_libraries(UnityTracyPlugin ws2_32 dbghelp)
+endif()
+
+# macOS/iOS 平台设置
+if(APPLE)
+ set_target_properties(UnityTracyPlugin PROPERTIES
+ FRAMEWORK FALSE
+ MACOSX_RPATH TRUE
+ )
+endif()
+
+# Linux/Android 平台设置
+if(UNIX AND NOT APPLE)
+ target_link_libraries(UnityTracyPlugin pthread dl)
+endif()
+```
+
+#### 步骤 4:编译 Plugin
+
+```bash
+# Windows
+mkdir build
+cd build
+cmake .. -G "Visual Studio 17 2022" -A x64
+cmake --build . --config Release
+
+# macOS
+mkdir build
+cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release
+make
+
+# Linux
+mkdir build
+cd build
+cmake .. -DCMAKE_BUILD_TYPE=Release
+make
+```
+
+### 2. Unity 端集成
+
+#### 步骤 1:将编译好的 DLL 放入 Unity 项目
+
+```
+UnityProject/
+└── Assets/
+ └── Plugins/
+ ├── x86_64/
+ │ └── UnityTracyPlugin.dll # Windows 64位
+ ├── x86/
+ │ └── UnityTracyPlugin.dll # Windows 32位
+ ├── Android/
+ │ ├── arm64-v8a/
+ │ │ └── libUnityTracyPlugin.so # Android ARM64
+ │ └── armeabi-v7a/
+ │ └── libUnityTracyPlugin.so # Android ARM32
+ ├── iOS/
+ │ └── libUnityTracyPlugin.a # iOS 静态库
+ └── macOS/
+ └── libUnityTracyPlugin.dylib # macOS
+```
+
+#### 步骤 2:创建 C# Wrapper
+
+**Tracy.cs:**
+```csharp
+using System;
+using System.Runtime.InteropServices;
+using UnityEngine;
+
+namespace TracyProfiler
+{
+ ///
+ /// Tracy 性能分析器的 Unity 封装
+ ///
+ public static class Tracy
+ {
+ private const string DLL_NAME = "UnityTracyPlugin";
+
+ #region Native Methods
+
+ [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
+ private static extern void TracyInit();
+
+ [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
+ private static extern void TracyShutdown();
+
+ [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
+ private static extern void TracyFrameMark();
+
+ [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
+ private static extern int TracyBeginZone(string name, string function, string file, int line);
+
+ [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
+ private static extern void TracyEndZone(int zoneId);
+
+ [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
+ private static extern void TracyPlotValue(string name, double value);
+
+ [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
+ private static extern void TracyMessage(string message);
+
+ [DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
+ private static extern void TracySetThreadName(string name);
+
+ #endregion
+
+ private static bool s_initialized = false;
+
+ ///
+ /// 初始化 Tracy
+ ///
+ public static void Initialize()
+ {
+ if (s_initialized) return;
+
+ try
+ {
+ TracyInit();
+ s_initialized = true;
+ Debug.Log("Tracy Profiler 已初始化");
+ }
+ catch (Exception e)
+ {
+ Debug.LogError($"Tracy 初始化失败: {e.Message}");
+ }
+ }
+
+ ///
+ /// 关闭 Tracy
+ ///
+ public static void Shutdown()
+ {
+ if (!s_initialized) return;
+
+ try
+ {
+ TracyShutdown();
+ s_initialized = false;
+ }
+ catch (Exception e)
+ {
+ Debug.LogError($"Tracy 关闭失败: {e.Message}");
+ }
+ }
+
+ ///
+ /// 标记帧边界(通常在每帧末尾调用)
+ ///
+ public static void MarkFrame()
+ {
+ if (!s_initialized) return;
+ TracyFrameMark();
+ }
+
+ ///
+ /// 绘制数值(用于实时监控变量)
+ ///
+ public static void Plot(string name, double value)
+ {
+ if (!s_initialized) return;
+ TracyPlotValue(name, value);
+ }
+
+ ///
+ /// 发送消息到 Tracy
+ ///
+ public static void Message(string message)
+ {
+ if (!s_initialized) return;
+ TracyMessage(message);
+ }
+
+ ///
+ /// 设置当前线程名称
+ ///
+ public static void SetThreadName(string name)
+ {
+ if (!s_initialized) return;
+ TracySetThreadName(name);
+ }
+
+ ///
+ /// Tracy Zone 的作用域包装器(使用 using 语句自动管理生命周期)
+ ///
+ public struct ZoneScope : IDisposable
+ {
+ private int zoneId;
+ private bool isValid;
+
+ public ZoneScope(string name,
+ [System.Runtime.CompilerServices.CallerMemberName] string function = "",
+ [System.Runtime.CompilerServices.CallerFilePath] string file = "",
+ [System.Runtime.CompilerServices.CallerLineNumber] int line = 0)
+ {
+ if (s_initialized)
+ {
+ zoneId = TracyBeginZone(name, function, file, line);
+ isValid = true;
+ }
+ else
+ {
+ zoneId = -1;
+ isValid = false;
+ }
+ }
+
+ public void Dispose()
+ {
+ if (isValid && s_initialized)
+ {
+ TracyEndZone(zoneId);
+ }
+ }
+ }
+
+ ///
+ /// 创建一个 Tracy Zone(性能追踪区域)
+ /// 使用 using 语句确保自动结束
+ ///
+ public static ZoneScope BeginZone(string name)
+ {
+ return new ZoneScope(name);
+ }
+ }
+}
+```
+
+#### 步骤 3:创建 Tracy Manager
+
+**TracyManager.cs:**
+```csharp
+using UnityEngine;
+
+namespace TracyProfiler
+{
+ ///
+ /// Tracy 管理器 - 负责初始化和每帧更新
+ ///
+ public class TracyManager : MonoBehaviour
+ {
+ [Header("Tracy Settings")]
+ [SerializeField] private bool enableOnStart = true;
+ [SerializeField] private bool markFrames = true;
+
+ private void Awake()
+ {
+ // 确保只有一个实例
+ if (FindObjectsOfType().Length > 1)
+ {
+ Destroy(gameObject);
+ return;
+ }
+
+ DontDestroyOnLoad(gameObject);
+
+ if (enableOnStart)
+ {
+ Tracy.Initialize();
+ }
+ }
+
+ private void LateUpdate()
+ {
+ // 在每帧末尾标记帧边界
+ if (markFrames)
+ {
+ Tracy.MarkFrame();
+ }
+
+ // 示例:绘制一些有用的性能数据
+ Tracy.Plot("FPS", 1.0f / Time.deltaTime);
+ Tracy.Plot("Frame Time (ms)", Time.deltaTime * 1000.0f);
+ Tracy.Plot("Total Allocated Memory (MB)", GC.GetTotalMemory(false) / (1024.0 * 1024.0));
+ }
+
+ private void OnDestroy()
+ {
+ Tracy.Shutdown();
+ }
+
+ private void OnApplicationQuit()
+ {
+ Tracy.Shutdown();
+ }
+ }
+}
+```
+
+#### 步骤 4:使用示例
+
+**GameManager.cs:**
+```csharp
+using UnityEngine;
+using TracyProfiler;
+
+public class GameManager : MonoBehaviour
+{
+ private void Update()
+ {
+ // 追踪整个 Update 方法
+ using (Tracy.BeginZone("GameManager.Update"))
+ {
+ ProcessInput();
+ UpdateGameLogic();
+ UpdateAI();
+ }
+ }
+
+ private void ProcessInput()
+ {
+ using (Tracy.BeginZone("ProcessInput"))
+ {
+ // 输入处理代码
+ if (Input.GetKeyDown(KeyCode.Space))
+ {
+ Tracy.Message("玩家按下空格键");
+ }
+ }
+ }
+
+ private void UpdateGameLogic()
+ {
+ using (Tracy.BeginZone("UpdateGameLogic"))
+ {
+ // 游戏逻辑代码
+ for (int i = 0; i < 1000; i++)
+ {
+ // 一些计算
+ }
+ }
+ }
+
+ private void UpdateAI()
+ {
+ using (Tracy.BeginZone("UpdateAI"))
+ {
+ // AI 更新代码
+ Tracy.Plot("Enemy Count", GameObject.FindGameObjectsWithTag("Enemy").Length);
+ }
+ }
+}
+```
+
+**PhysicsController.cs:**
+```csharp
+using UnityEngine;
+using TracyProfiler;
+
+public class PhysicsController : MonoBehaviour
+{
+ private void FixedUpdate()
+ {
+ using (Tracy.BeginZone("PhysicsController.FixedUpdate"))
+ {
+ PerformPhysicsCalculations();
+ }
+ }
+
+ private void PerformPhysicsCalculations()
+ {
+ using (Tracy.BeginZone("Physics Calculations"))
+ {
+ // 物理计算
+ Rigidbody[] rigidbodies = FindObjectsOfType();
+ Tracy.Plot("Active Rigidbodies", rigidbodies.Length);
+
+ foreach (var rb in rigidbodies)
+ {
+ // 处理刚体
+ }
+ }
+ }
+}
+```
+
+---
+
+## 方法二:IL2CPP 后端集成
+
+当 Unity 使用 IL2CPP 作为脚本后端时,可以直接在生成的 C++ 代码中集成 Tracy。
+
+### 1. 配置 IL2CPP
+
+在 Unity 项目中创建 `il2cpp_custom.cpp`:
+
+```cpp
+// 放置在: Assets/Plugins/IL2CPP/il2cpp_custom.cpp
+
+#include "il2cpp-config.h"
+
+// 包含 Tracy
+#define TRACY_ENABLE
+#include "tracy/Tracy.hpp"
+
+// IL2CPP 钩子函数
+extern "C" void UnityPluginLoad(void* unityInterfaces)
+{
+ // Tracy 会自动初始化
+}
+
+extern "C" void UnityPluginUnload()
+{
+ // Tracy 清理
+}
+```
+
+### 2. 修改 IL2CPP 构建设置
+
+在 Unity 的 Player Settings 中:
+1. 切换到 IL2CPP 脚本后端
+2. 添加额外的编译参数:`-DTRACY_ENABLE -DTRACY_ON_DEMAND`
+3. 链接 Tracy 库
+
+---
+
+## 方法三:Unity Profiler 集成(可选)
+
+可以创建一个桥接层,将 Unity Profiler 的数据转发到 Tracy。
+
+**UnityToTracyBridge.cs:**
+```csharp
+using UnityEngine;
+using UnityEngine.Profiling;
+using TracyProfiler;
+
+public class UnityToTracyBridge : MonoBehaviour
+{
+ private CustomSampler[] samplers;
+
+ private void Start()
+ {
+ // 创建自定义采样器
+ samplers = new CustomSampler[]
+ {
+ CustomSampler.Create("Render"),
+ CustomSampler.Create("Physics"),
+ CustomSampler.Create("Scripts"),
+ CustomSampler.Create("GarbageCollector"),
+ };
+ }
+
+ private void LateUpdate()
+ {
+ // 将 Unity Profiler 数据转发到 Tracy
+ foreach (var sampler in samplers)
+ {
+ Tracy.Plot(sampler.name + " (ms)", sampler.GetRecorder().elapsedNanoseconds / 1000000.0);
+ }
+
+ // 内存统计
+ Tracy.Plot("Used Heap Size (MB)", Profiler.usedHeapSizeLong / (1024.0 * 1024.0));
+ Tracy.Plot("Total Allocated Memory (MB)", Profiler.GetTotalAllocatedMemoryLong() / (1024.0 * 1024.0));
+ Tracy.Plot("Total Reserved Memory (MB)", Profiler.GetTotalReservedMemoryLong() / (1024.0 * 1024.0));
+ }
+}
+```
+
+---
+
+## 平台特定配置
+
+### Windows
+- 使用 Visual Studio 编译 DLL
+- 确保链接 `ws2_32.lib` 和 `dbghelp.lib`
+
+### macOS / iOS
+- 使用 Xcode 编译动态库或框架
+- 注意代码签名要求
+
+### Android
+- 为不同的 ABI 编译:armeabi-v7a, arm64-v8a, x86, x86_64
+- 在 `gradle.properties` 中配置 NDK 路径
+
+### Linux
+- 链接 `pthread` 和 `dl`
+- 确保 GLIBC 版本兼容
+
+---
+
+## 使用 Tracy Profiler 查看数据
+
+### 1. 启动 Tracy Profiler
+
+```bash
+# 从 Tracy 仓库构建或下载预编译版本
+# 运行 Tracy.exe (Windows) 或 Tracy (macOS/Linux)
+```
+
+### 2. 连接到 Unity 应用
+
+- Tracy Profiler 会自动发现本地网络中的 Tracy 客户端
+- 点击连接即可开始分析
+
+### 3. 查看性能数据
+
+- **时间线视图**: 查看各个 Zone 的执行时间
+- **统计视图**: 查看函数调用次数和平均耗时
+- **内存视图**: 查看内存分配情况
+- **图表视图**: 查看 Plot 数据的实时曲线
+
+---
+
+## 最佳实践
+
+### 1. 性能开销
+- Tracy 的开销很小,但仍建议在 Release 构建中禁用细粒度的 Zone
+- 使用条件编译:`#if TRACY_ENABLE`
+
+### 2. Zone 命名
+- 使用清晰、描述性的名称
+- 包含类名和方法名,如 `"PlayerController.Move"`
+
+### 3. 合理使用 Plot
+- 不要在每帧绘制过多数据点
+- 专注于关键性能指标
+
+### 4. 多线程支持
+- Unity 的 Job System 需要特殊处理
+- 在每个 Job 中调用 `Tracy.SetThreadName()`
+
+### 5. 移动平台
+- 注意无线网络连接的延迟
+- 可以使用 Tracy 的文件保存功能,之后再分析
+
+---
+
+## 故障排除
+
+### 问题 1: DLL 加载失败
+**解决方案:**
+- 检查 Plugin 导入设置中的平台配置
+- 确保 DLL 与 Unity 架构匹配(x64/x86)
+- 检查依赖库是否缺失
+
+### 问题 2: Tracy Profiler 无法连接
+**解决方案:**
+- 确保防火墙允许 TCP 端口 8086
+- 检查 `TRACY_ON_DEMAND` 是否正确定义
+- 确认 Tracy.Initialize() 已被调用
+
+### 问题 3: 性能数据不准确
+**解决方案:**
+- 使用 Release 构建测试
+- 禁用 Unity Editor 的 Deep Profiling
+- 确保 V-Sync 和帧率限制的设置符合预期
+
+### 问题 4: Android 构建失败
+**解决方案:**
+- 检查 NDK 版本兼容性
+- 在 `build.gradle` 中添加必要的链接器标志
+- 确保所有 ABI 的库都已编译
+
+---
+
+## 进阶功能
+
+### 1. 自定义内存分配追踪
+
+```cpp
+// 在 Plugin 中添加
+UNITY_PLUGIN_EXPORT void TracyAllocNamed(void* ptr, size_t size, const char* name) {
+ TracyAllocN(ptr, size, name);
+}
+
+UNITY_PLUGIN_EXPORT void TracyFreeNamed(void* ptr, const char* name) {
+ TracyFreeN(ptr, name);
+}
+```
+
+```csharp
+// 在 C# 中使用
+public class TrackedMemoryPool
+{
+ public void Allocate(int size)
+ {
+ IntPtr ptr = Marshal.AllocHGlobal(size);
+ Tracy.AllocNamed(ptr, size, "Memory Pool");
+ }
+
+ public void Free(IntPtr ptr)
+ {
+ Tracy.FreeNamed(ptr, "Memory Pool");
+ Marshal.FreeHGlobal(ptr);
+ }
+}
+```
+
+### 2. GPU 性能追踪
+
+Tracy 支持 OpenGL、Vulkan、DirectX 的 GPU 追踪,但需要在渲染管线中集成。
+
+### 3. 锁竞争分析
+
+```cpp
+// 在 Plugin 中
+#define LockableName(type, varname) TracyLockableN(type, varname, #varname)
+```
+
+---
+
+## 总结
+
+将 Tracy 集成到 Unity 中可以提供比 Unity Profiler 更详细的性能分析数据,特别是对于:
+
+1. **Native Code 性能** - 如果你使用了大量 Native Plugin
+2. **多线程分析** - Tracy 的线程视图非常直观
+3. **跨平台分析** - 统一的工具链
+4. **帧级别分析** - 精确到微秒的时间线
+
+根据你的项目需求,选择合适的集成方法。对于大多数项目,**方法一(Native Plugin)** 是最推荐的方式。
+
+---
+
+## 参考资源
+
+- [Tracy 官方仓库](https://github.com/wolfpld/tracy)
+- [Tracy 手册](https://github.com/wolfpld/tracy/releases/latest/download/tracy.pdf)
+- [Unity Native Plugin 文档](https://docs.unity3d.com/Manual/NativePlugins.html)
+- [IL2CPP 脚本后端](https://docs.unity3d.com/Manual/IL2CPP.html)
+
diff --git a/main.cpp b/main.cpp
new file mode 100644
index 0000000..6ed808c
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,355 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Tracy性能分析器
+#include "tracy/Tracy.hpp"
+
+using namespace std;
+
+// 矩阵乘法 - 计算密集型操作
+vector> matrixMultiply(const vector>& A, const vector>& B) {
+ ZoneScoped; // Tracy追踪这个函数
+
+ size_t n = A.size();
+ size_t m = B[0].size();
+ size_t p = B.size();
+
+ vector> result(n, vector(m, 0.0));
+
+ for (size_t i = 0; i < n; i++) {
+ for (size_t j = 0; j < m; j++) {
+ for (size_t k = 0; k < p; k++) {
+ result[i][j] += A[i][k] * B[k][j];
+ }
+ }
+ }
+
+ return result;
+}
+
+// 生成随机矩阵
+vector> generateRandomMatrix(size_t rows, size_t cols) {
+ ZoneScoped;
+
+ random_device rd;
+ mt19937 gen(rd());
+ uniform_real_distribution<> dis(0.0, 100.0);
+
+ vector> matrix(rows, vector(cols));
+ for (size_t i = 0; i < rows; i++) {
+ for (size_t j = 0; j < cols; j++) {
+ matrix[i][j] = dis(gen);
+ }
+ }
+
+ return matrix;
+}
+
+// 快速排序
+void quickSort(vector& arr, int low, int high) {
+ ZoneScoped;
+
+ if (low < high) {
+ int pivot = arr[high];
+ int i = low - 1;
+
+ for (int j = low; j < high; j++) {
+ if (arr[j] < pivot) {
+ i++;
+ swap(arr[i], arr[j]);
+ }
+ }
+ swap(arr[i + 1], arr[high]);
+ int pi = i + 1;
+
+ quickSort(arr, low, pi - 1);
+ quickSort(arr, pi + 1, high);
+ }
+}
+
+// 计算质数 - 埃拉托斯特尼筛法
+vector sieveOfEratosthenes(int n) {
+ ZoneScoped;
+
+ vector isPrime(n + 1, true);
+ vector primes;
+
+ isPrime[0] = isPrime[1] = false;
+
+ for (int i = 2; i <= n; i++) {
+ if (isPrime[i]) {
+ primes.push_back(i);
+ for (int j = i * 2; j <= n; j += i) {
+ isPrime[j] = false;
+ }
+ }
+ }
+
+ return primes;
+}
+
+// 计算π值 - 蒙特卡罗方法
+double calculatePi(int iterations) {
+ ZoneScoped;
+
+ random_device rd;
+ mt19937 gen(rd());
+ uniform_real_distribution<> dis(0.0, 1.0);
+
+ int insideCircle = 0;
+
+ for (int i = 0; i < iterations; i++) {
+ double x = dis(gen);
+ double y = dis(gen);
+
+ if (x * x + y * y <= 1.0) {
+ insideCircle++;
+ }
+ }
+
+ return 4.0 * insideCircle / iterations;
+}
+
+// 斐波那契数列(递归)
+long long fibonacci(int n) {
+ ZoneScoped;
+
+ if (n <= 1) return n;
+ return fibonacci(n - 1) + fibonacci(n - 2);
+}
+
+// 斐波那契数列(动态规划)
+long long fibonacciDP(int n) {
+ ZoneScoped;
+
+ if (n <= 1) return n;
+
+ vector dp(n + 1);
+ dp[0] = 0;
+ dp[1] = 1;
+
+ for (int i = 2; i <= n; i++) {
+ dp[i] = dp[i - 1] + dp[i - 2];
+ }
+
+ return dp[n];
+}
+
+// 向量点积
+double dotProduct(const vector& a, const vector& b) {
+ ZoneScoped;
+
+ double result = 0.0;
+ for (size_t i = 0; i < a.size(); i++) {
+ result += a[i] * b[i];
+ }
+
+ return result;
+}
+
+// 复杂的数学计算
+void complexMathOperations(int iterations) {
+ ZoneScoped;
+
+ double sum = 0.0;
+ for (int i = 1; i <= iterations; i++) {
+ sum += sin(i) * cos(i) + tan(i / 100.0) + sqrt(i) + log(i);
+ }
+
+ cout << "复杂数学计算结果: " << sum << endl;
+}
+
+// 内存密集型操作
+void memoryIntensiveOperation(size_t size) {
+ ZoneScoped;
+
+ vector> bigArray(size, vector(size, 0));
+
+ // 填充数据
+ for (size_t i = 0; i < size; i++) {
+ for (size_t j = 0; j < size; j++) {
+ bigArray[i][j] = i * j;
+ }
+ }
+
+ // 计算总和
+ long long sum = 0;
+ for (size_t i = 0; i < size; i++) {
+ for (size_t j = 0; j < size; j++) {
+ sum += bigArray[i][j];
+ }
+ }
+
+ cout << "内存密集型操作总和: " << sum << endl;
+}
+
+// 多线程测试
+void threadWork(int threadId, int workload) {
+ ZoneScopedN("ThreadWork"); // 命名追踪区域
+
+ // 模拟工作负载
+ long long sum = 0;
+ for (int i = 0; i < workload; i++) {
+ sum += i * threadId;
+ }
+
+ cout << "线程 " << threadId << " 完成, 结果: " << sum << endl;
+}
+
+void multiThreadTest(int numThreads, int workload) {
+ ZoneScoped;
+
+ vector threads;
+
+ for (int i = 0; i < numThreads; i++) {
+ threads.emplace_back(threadWork, i, workload);
+ }
+
+ for (auto& t : threads) {
+ t.join();
+ }
+}
+
+// 主测试函数
+void runPerformanceTests() {
+ ZoneScoped;
+
+ cout << "\n========== Tracy 性能测试开始 ==========" << endl;
+
+ // 测试1: 矩阵乘法
+ {
+ ZoneScopedN("Matrix Multiplication Test");
+ cout << "\n[测试1] 矩阵乘法..." << endl;
+ auto A = generateRandomMatrix(200, 200);
+ auto B = generateRandomMatrix(200, 200);
+ auto C = matrixMultiply(A, B);
+ cout << "矩阵乘法完成 (200x200 * 200x200)" << endl;
+ }
+
+ // 测试2: 快速排序
+ {
+ ZoneScopedN("Quick Sort Test");
+ cout << "\n[测试2] 快速排序..." << endl;
+ vector arr(100000);
+ random_device rd;
+ mt19937 gen(rd());
+ uniform_int_distribution<> dis(1, 1000000);
+
+ for (int& num : arr) {
+ num = dis(gen);
+ }
+
+ quickSort(arr, 0, arr.size() - 1);
+ cout << "排序完成 (100000个元素)" << endl;
+ }
+
+ // 测试3: 质数计算
+ {
+ ZoneScopedN("Prime Numbers Test");
+ cout << "\n[测试3] 质数计算..." << endl;
+ auto primes = sieveOfEratosthenes(1000000);
+ cout << "找到 " << primes.size() << " 个质数 (范围: 0-1000000)" << endl;
+ }
+
+ // 测试4: 蒙特卡罗π值计算
+ {
+ ZoneScopedN("Monte Carlo Pi Test");
+ cout << "\n[测试4] 蒙特卡罗π值计算..." << endl;
+ double pi = calculatePi(10000000);
+ cout << "π ≈ " << pi << " (10000000次迭代)" << endl;
+ }
+
+ // 测试5: 斐波那契(递归 vs 动态规划)
+ {
+ ZoneScopedN("Fibonacci Test");
+ cout << "\n[测试5] 斐波那契数列..." << endl;
+
+ {
+ ZoneScopedN("Fibonacci Recursive");
+ long long result = fibonacci(35);
+ cout << "递归方法: fibonacci(35) = " << result << endl;
+ }
+
+ {
+ ZoneScopedN("Fibonacci DP");
+ long long result = fibonacciDP(90);
+ cout << "动态规划: fibonacci(90) = " << result << endl;
+ }
+ }
+
+ // 测试6: 向量运算
+ {
+ ZoneScopedN("Vector Operations Test");
+ cout << "\n[测试6] 向量点积计算..." << endl;
+
+ vector v1(10000000);
+ vector v2(10000000);
+
+ random_device rd;
+ mt19937 gen(rd());
+ uniform_real_distribution<> dis(0.0, 1.0);
+
+ for (size_t i = 0; i < v1.size(); i++) {
+ v1[i] = dis(gen);
+ v2[i] = dis(gen);
+ }
+
+ double result = dotProduct(v1, v2);
+ cout << "点积结果: " << result << " (10000000维向量)" << endl;
+ }
+
+ // 测试7: 复杂数学运算
+ {
+ ZoneScopedN("Complex Math Test");
+ cout << "\n[测试7] 复杂数学运算..." << endl;
+ complexMathOperations(1000000);
+ }
+
+ // 测试8: 内存密集型操作
+ {
+ ZoneScopedN("Memory Intensive Test");
+ cout << "\n[测试8] 内存密集型操作..." << endl;
+ memoryIntensiveOperation(1000);
+ }
+
+ // 测试9: 多线程测试
+ {
+ ZoneScopedN("Multi-Threading Test");
+ cout << "\n[测试9] 多线程测试..." << endl;
+ multiThreadTest(8, 50000000);
+ }
+
+ cout << "\n========== 所有测试完成 ==========" << endl;
+}
+
+int main()
+{
+ cout << "Tracy性能分析测试程序" << endl;
+ cout << "请确保Tracy Profiler已经运行并连接" << endl;
+ cout << "按回车键开始测试..." << endl;
+ cin.get();
+
+ // 运行多次测试以便在Tracy中观察
+ for (int i = 0; i < 3; i++) {
+ ZoneScopedN("Main Loop Iteration");
+ FrameMark; // Tracy帧标记
+
+ cout << "\n\n============ 第 " << (i + 1) << " 轮测试 ============" << endl;
+ runPerformanceTests();
+
+ // 短暂休息,让Tracy更容易区分不同的测试轮次
+ this_thread::sleep_for(chrono::milliseconds(500));
+ }
+
+ cout << "\n程序即将退出,按回车键继续..." << endl;
+ cin.get();
+
+ return 0;
+}
\ No newline at end of file
diff --git a/thirdparty/tracy b/thirdparty/tracy
new file mode 160000
index 0000000..be23d93
--- /dev/null
+++ b/thirdparty/tracy
@@ -0,0 +1 @@
+Subproject commit be23d9354ad6c0ac3a4e0c210738f76b0572e635
diff --git a/tracy-0.13.0.zip b/tracy-0.13.0.zip
new file mode 100644
index 0000000000000000000000000000000000000000..d54fd4a3d811aa946c75703b691b9711cbe666b3
GIT binary patch
literal 12259626
zcmV)LK)JtAO9KQH00;mG091WzTL1t6000000000001*HH0CaL;V|guOVQ_SHa%C=M
zcxB|h3w#vS**|_Zvmq-4Cg29+r4n_-=vYk+)zDF!fn7KQvxo&P)*CcPq26dNKrJd^
zvnJcaP_$@mODk0S*7vP%Yy0|gQEYc}+1$8<`$dJ|b(aMRAd(xIpU-n0dCobW@2wyLA;eAyF-=0&6aKG=eEz=^5_prW<8u+JnNB19xcoL{sXxs<&WgfdnDI&+qB$=AD#Wcbwh^^
zmaIH-YPMc=&x>oyV*l@W>xMG=;+nFzuDPe|KK%S$`3(I0efgdE`BM1;{9Ii={lzt9
zS6;rl{4RWUb=lDu*OYC&=H+rHe%@DhFMhsQ4xitdS3DQ;kClC@n~>R04I)3f>->4K
zYwhH6G9+!-wIu8$q}{-4Gxs_P$>L37gTL@SjgUdsGqF#S`yy{dLWn?SR>U5Pef0mG
z@|A3wwT8c7>hDM!e73G3my{(XnE5->_$DE_fz_mNfWBA~SWWUiOV;+c)mA}c|FX$m
z``P>Oy0Qlr!E3Jn(5ffYy-)gFLS|l9GJ96pEJB8rF2g)Y*)l?oI8)LU5mIy=PexvK
zL7~TUPI#7s9%>H)IVLy()}(eNB8Se?zHbx
z?~%d{&?D4XEX^>pKR)Rslh-3Xs06@tMM52
z;aadGM`MjN82Pp?1hsjMkXo0Uw0TXW`Bw@(9ihTD8tlrUtcC`|-=;#VHZOp;gjRT!
z|NP{){gR$GDQl$jYA}hF30@U~{R+qHS2WG48@$38`p!oqNqy(B0QC={#xw^tsH47P
zc$%5ra||k83y-FB31zoCsFD7`M|mC>YuDlr@B3ShK@P`nJ!TAD*Rs-u~E0sFA+;LwJ#pXsJHW
zKYq67SMle|`#w*-NAjpK^nX7bNz82XXi8lN=)bR>E&rQ&{@;A$h1C3A{xo>fKgm&>
z$S#zOPNbh-%j|Ag(2W6eSPLnMe$>F8H+A5`ye$zuQK+(tN
z@CHsQdAyyH_=7^&z5g#?PS!1=@=|ePlSP<9N1lrP!%&fE~*ELP*l3>2Oda%x#sc(DvZh*p>
z8VhK07nMU)X?Q%dVY~x!(fva75}h?@Y&&IJ!nUo@Z1$TP#yhx56qpNc7d<2n}Yr3j(hc8JHr@<=`JIN#wA0cE;!xH#)9?&1^pXhiwqdco%yShG~
z*a>Bg;fppqN&JcEoyoZdBbaMhW@;YyJEGTb$Sr~te~84};KHI$Lsr&s53>IICMU1-
zD3F(#6a?(<9F0AgtFh8NOKfnw6d|5yIpO7Rz$24$!#@5cFT5DP457ZJvO#9{rTD_h
z4(q3gKkv?>zPHLArrtMJgQZwrOvnB@kVeSD9IE`fF^!N?5eDoHj}0R$sJE`@?ppYH
z#bd*ud%Y_JLh8GRgK}lwYJp&thXXlex|DCWCLX~r)V%VSVdRQMIF=LgiPVsS?0+`;
z7o>;3V<*J>6DN6M7`$$JI{)?L3CezwL)nA5AkRfqIa78w4CvT+rtBtaOer$6fBvD9
z_yVHu1Riv5gyh*Hl5ucp&p_7cQYQrlaG4&l;ReK2`1=|sAxE!0=1z4W)?@@0E
zp{c%OI3}aYsq+7#Y+5d5lXIxjTsAb^aUm3Od=B-G&jprS1S*#T?VZZW?gp?*8=itn
z^_u3BX7*DbILW3BX;_}e@OwIbe+0jCar{1f-{e9V1=2t5jyu1rPFL?#q2Z_M?6|w&
zeceCHq5EfL>Hb+cx_?%#?w^%M{kP}q{#k{(e^!ysnqP<9)b(~8dP9HnKJXkd>?EN|
z>E+Lw+U8+X@-Ypvk!5(%%s%>&ljy}8rB~rb^+vopaLU?`oJ3<&ax^v}kIF$B>=1ON
zW5GhY-sJyA=}L!KbwwH>8oMu-%KK=rTbN{Io`FsYzkLa`UDyM+SfhvCnd4D*l#NR0
zdp5%3znuDq13%HcH4cxmqx>*s+rmq8ph#PF(AB#%V@giA?P5YycEs&7#pRFM2!a0J
z5Qev0x1JANze~!0U9hUa8pF%GOmj}dgqsNoO}G{1$>qN+)~ML)J;T+U`i|i$G$(yM
z4drE_nSJy<5WnRs5KZt2NL_&Gvmkvw^{Yjg^r!DRi6uZ!p#b?`lb$DpYyh+guUrR8
zIv+|_2=Ygvuk&2~*;1~~8g(Q6k2xTk1x;pl#RrhoB^6O$K&%Xc{{9=6Y~O!Fx$qrX
zz+5_?bOC=Ez8u~MREvndpJHR)nX4&x=9LZA*xS^9gXW!(>xf>c8}mT>D@Co$_)<(Rna*B|yVlG;{JxW{Ftgu-52z=_(P3tnyz3+@!k1h?QYd(wFJy6j
z1Bz31P@7svi*L_@*HAX5l^RbJp>Ye`5ooKKJ^o!7zh#-$$a22xB%3Op)Iq6~pWiT1
zhkX|b9`?vO%)
z4uc@g#MeN+p^3K;HZdPX+2$_NnI}I*OX*UPnf>5Ch_;jlc<v29k}N+#mc#uXsemM@1Tm>8IFFxLc+R0((uyNR*rn-9?y)SHN+}<&?5FH__*+LzbIC1^U#)>F9c2@N#Tb>+
zd`RJUNqO8X_BN%(U1>UNQP&e2RPy0As2Y;B-P9O*-R_Yj+!-~^==GMnZxv=_X7?Nf
ze_5pj(uK}G5$rY?;%0V!8=&7ZUZ{di;f`0GgjUo+sqeq9kA-IWLw4;NNy00lrfHFp
zGY2f2C1JmzzP&@8uHJ#1#CS!@f7>+Iw@QSB2Z57GZmaLO`ZXya0cKvkQF;}=EV{Z<
zTFt*KlUDFAE2Sm;%PMKUge`gF-BwHbW?lj9@ve(?qA$_Rj_ya{8D(Zi_B+XjQ+P47
zA8Oe6dIlCY05^EKKRAFl%5HCUL)ffFl1-*k_kCPhPsj{u%@1K`Wlv=TJ_Yi3J>}mT=QyfLSffu|TBgCozTz#G`TUz;z
z&ny_B**rwqEqi{uhD6@PA@;SF->$(Niz0u)3qxQ3?HcH}w?WOdM}7hN?|*HPpYfZ&
z!J7x)b`qd0(Zx8rKLWPi;F6|tZ8&rhCi?5!PHw2Uq?rxwB}FI}o+W1Xwtc`+rb|=7
zt1^>%yKPkTv~rSB(T$mjQ<^C&ucqRkzd_e$|7qf($DDtfNKb!Ak)f#&bImW%}J@?j9BfEF|NRDdnyv;4ek^JRr;pH2`rnw$;NVEb)V;eSL
ziQQ
z;`~)y>)SYrkek!QN+4-B3*6|q*w*79yy)v1YCtVtj^F0K)YadLAxQ=Gh;GtYr
z&-6D}u7SsW3(}y9#*$Hlgx&uIz2jRk>a!fW
zvgY^HcV)e~8pbgD&8wpl$wvRzXU%oX;+1Q__v~wh>Uvzy4{Bb)+5?!3o
zSQngB6R_3QUOg#D>bvgRQh(xm+vw
zC48_0lw*Jz*=Kg(-7e_PyZFPq;rr$fAmz{}e!hl;{}NBVm8aedDP&0P`}B!xs4;X0
zT=*3}vL(DUo_sY=z5(v`bYSK`hVSz+r7<^?5KZ0^o^>Mjz@z+um5`{VBR+&??6Zc@
zcTqFx(v0vK%;Fwt24%IH^7iBB(TZAf=u~=iFnzkalkPs-fH?^X-?NBpN^msJGiJ`xe}tANFHT4k~Y@>;Grv?$O~P
z*A0iMpkUWUiFqJeTuYVK#TlV=&ogU?4dfSO?(s9G866RF|Iilljj$173#EVknKgU}
z&ktV@IT!mHM-jl7${z?;gQSn%X_`}5WngC71%Mq@+p&FSz~K7hY15?MH`_;nlk5s=
zJlh8H>V30g6d@uNC-UFM&{9a;`<`if-+X%%Ixido0?`k7Whird~ahenME#fookXEcn`Br(uV}x>;qL?H)AjjzL%@AqCs@XUO*|TitE5B
zS_`l;mnwV3%3s28`@1zw8A###25_oy@J@lyV4Iz?XLI4TLMv6C%@d)hm!?5WlsG)#
ziyWQ?UAK0^plX*?=)S=ORRHb*mr-Q8{4QyR#?Hj`rz)T@6WoeaJMU8YWW3brUkMoS2Rm)Zhg@6fbCFyr4m9Wb3V1Uk_x}`iW_(
zy$#gcFv9h%#bD>Sq#5GUt9$vFrwM6_j7h=
z1Eto1;z^Zzq`9K+i8GMZVsN&CD_Y(fe)}j$S{p6S-o1Pcp{$t(4-KM5`b({*sT=F_
z|F(wcLZ?|%@$P3_amnKuX0x}s!>sXV|6%zW;xQ%`>C7ksg$B?LV|p@RE-MUW5Rb9Y
zrY`yR*FB>9G&pzV5cPHlPki%lKxE?M!Fx=g?4Twe(2GNwF~vrO7RvU7$E|mgP{y_1
zkezzFg(vq~dXvfk{Z}1DCIn#0ZXc$D^9Ma!Q1^?W?t|LmO7#4lmJ%HSUySVYn}O<}
z$=tq!GeKXV?8*%k_`{9A=Psl9U|QI%;mR7r{}BcG3FUqJp)OAfwGzXe`TZFP2Z<~z{
zX@sl6`mPy)y5M7XwP?&!$RB9p4+Nvxlm+Rwu=kLS4hh1g0Hm%zabKXm>wE2#HHU2{
zko?qlHD%
zlW2w~C;Xy~kQJ{}^nz^;XTJo-BUJT`TpK9}L`qMYX4nKnan6e7D+yWrjnw}=16+&!
zzhE@~+A0?%;j|L}CTFS(De7+RtMseB^>O)zEHObln-FNk(tLVJeqH!Wgf$h|vK_dA><=r`dfu1%f)a{B^h
zgH&&aP%cytuYGEG-}%AV{P;e~&I9MhB+8~a!p{NrupyL9%cAl&>V3C^R&+slR7nnH
zY6tb!Tm|*@MjX`JIcnj>P}LiL=OhIIaH{#oJE(tr7N5E-2)GNH+;GDs<#NaB%dLqC
zxs>`}WBEQ|a<2dqL3@1b!-NZz*S&E~qV7;^^UB`M1I-V2f*YGPrp(q6bot?0J;x_76vnV@G
z{c4V7ep9oy(0);Q2YoXx`^r0FRTZk&ZgJs7;Pdz2l|>uW91+yqxBucKA$tLdPQjp^
z#ZbIPkt+2I#SJ5|r@~YTQgK{_8XjACt{pI7x4jlbdknP;0|9_O}}f#X&3DZ4!f
z`rF$jF1Qwjqvo6g<}w&CHYiBLcplf&FdmyWBoIDqz^4@RPq_;MeBeB~`CRcb=Y^j<
z49=ORW+!>wVa*w=`Yn#ixTYwYcE@*dMk^2f`rtAfPFXjFN&6a&g=x?fU`|O(Oee8U
z4Jh0<(Z!}^QMnmJYbyHM**3tmnYuC8Mz3`YU7#6@C5NW$Eg!2Xtz{!AOVj;>skg>q#YkyND^5s7
z=TpNzSYxL&rJjo8+cl+Kta=XI3{O#IN7*GYdFb;vjm>BM^$cLvZ4RpJD;rg?J5>Dm#!w@QRLD;yz2cYW~qG{`aPS1@o9(ZjHx
z#+F1FvA{F`{(%R@_nMOj1w>|2UsHJo3VmTMt?0x8+)54gDyjq*+=}y%zeZ9Ao+>9~
z3fP1hn%P5|F{mVP74^2YQ9teA*?8*;BQt*OB;jB0O`Y$EH$OdnO`qmxLF(@dxZ=80
ze4f)Mg>Lw>iU@Htn`+pzVESr__|$SRrNBdFn)RKJwCP4gP7#EvgJH+AbmM6V?bU=4
zb?-htfk%|9~`WyKXtIR{!CY0{Ramd
z>rX|u*Y`eodmHtJZRML(M$`r{w#hB*-<86e>t(t#CeaAvxY@9Dg|2%r?
zQ)bR-#SxgQU|3peY=Ba_3qJL*Hgs6|0%aL&FBL{b1&tk0*|xCR3*)O&3gEC>B{kyA
z@iGafRaNhL$i`lpt0`}lUF`NXJu%WV_Ekp_A>~8e{#W6q#@^EXqjYwGR(u>LY3L;5
z+Dk!r^EBn~f+={3D$!CGtCj0j{}OnHS8;^efWP9^jEde4d+A^+W0i$;wgYmNTQL{i
ze}V3Q1q0l4|6*y8ro1Kk^udsF1w2sE1(}H6ucyPMYUomBo9Mk1epYnC)Q?#8Z975x
zQgm03kyM;=izsm%5kf)1vstrq=MLaCr
zC3m6D)#ZrGztL*7&Y|M6!vf?gXvQ>~wt*1x#@ib&-m0<|Ro<+Le-6@Mc#P`LTteC4
zH=qqP@y|`XJTw>?lj>ikR`&7M3T5%0!hh1!k&Q7Sou0d|Oo(ipIEmd}l
zRo@4v2^&1w7;`n~J^pI9U!dZjAx?OVTiIH2zG_s!+6z?)lw_!E(AYs`88G~FqfhH>
z8A^e>V7sP7RMxDr8u1rFP5DIpMZniscAdC(f=P`#O|@`>=`kjl<(GJrAW!FE?cy(j
zl%3F&otV0OJIu
zmh2Hr+^X@AbX*N(v{#$~@9APbe@EHY(;oy6XF%9x&0o#%l`n(KnwOjk-ScW~rfCY{
zqU!6Z*$^G9ifiivZFaRfLo+gO*5$2p674&Q*~K{Wbe6P(PRygM6VN4>dh5HXac^f*
zdR1Jvo3gEQ^$fP4tO2jP-IL7%DBLU*qvQ
z{3c1gS@IDz+-IoLSUQZ^#-^1!s5fY*-WoeK+$LPk64%-0SU1wBws@&*eL6rqmqq-er${VulLOV9s=|dnz&=1hw>Co`3nRF73#uG&8FpLbR?{?HX#sb2hVFk2JJZ7s
zc$7~>?@Balr}V1EoxL%IrOLZpjE}m+AcLUrlO%F>dSRoJ+i
z9M!Pm@K0x3ft?u!bOt?rh#C`Z6q?^)IEgLnqCyQ-f(u`v-ZNs!cS0HM)F?kr%?4W0
z3!+|f6Fkqh!fX}W|5uX+qZvA@4Uhf3Gx2(%n{r`~m4OQFI@?-QeN*(jB5`efpv?|K
zui12^<<7K94x_wPz<$*46v!MzFwMf}U%$X}e(2yS1
zt;=1W;zJ(cJy6D=|3DAsfv&U^Ws;WEj56sIH;zy_?nqLO8~Z88x+LYOiGSV%ory|P
zMgP!>6n%I}wQe}8wc;S^!xq$sovHe82G@tG;f1b-948xNWVb&JrKFz%T%Do-PbVqB
z2v>l&aP^$zKkcgzHDym9edtkw|C~O2_OdUh53^tVg8GoMt(xHkm6(V}v!54d?#-4y
z)P$Zdpbyu43i@zDl0FPjr55zzU|Qga>BE4f@@ixHkl!S!H$fkI&QK*-I*d8S4hFRs
zu=JtFgv(jtI>#LAhNTbdK_5B_2ZKHgfKFk7e^4K0_n79tO&?U4BlAtR=24=FLLJ+`||s(b({05f6(1#m)D~
zVc_*sCmGJ+Xyki*+db^KCc3t3a##}%1K}_9__j|noWl}5O_5}auCQ)Ac50kqzYtV%
zp5Kf7+_>E~-mvEYCC~L^0aVu1;EkzfP`S*ev)Y(s_%pp+?{eYcvyiBM
z#|bL1Q`K04q||={yjuyCoToCoG}cYZE&wHz3)$qwgdJyn+yzal+^#7HRMw=jAgbwO
zTum1y^t0R44Y#Qlx+GIGrc20J8~77Cdlw#JVNKc1HFRr2LmzR=AA_%J21>Ke8r0Jt
zph(6vbxcjy$JF!?ur>hAHP!GOS3{)Tzf1zRSVbo)YdNlcwk9d-xxaA|#?vKqbz`*{
zQ`PmTs=<{u$#7n;%coP
zoqB7#L0x;4F41>Y8Yq}eI@_kpn{`2#3U#GL7bmuO47F2J8cT1Ek=Kn$gV_Lt{-I
zrMc9pF`HH(h`s`t$TT#o9L=Q{#tL{j4(t>{458EuhF}p;?Ki9^_ShwmQW5KEtD!Ir~VCBPgcAAq1)iq
zk;*RAYY==n)y=j=7F+;W!9@uNZ~|O4`GCd(I@`);j1ATYV>RPv+|<}%nHqn9*@cpc
zXlj%u!|SyJ!|Rskog{{-LN`|*aZGiHYipCti&~g!FdM=vpLY^fHeE)hf^~qgFg5b(
z$RtbS{cQBZh?QN#pl;lmW?WmKvK3iqUPM_1e9`5@%+C#ulZbtCtA8cxNsn(kBBW+G
z2P1X@NCL=FNH?{7u)AP8T+fXT_pmNq?$Cu!fW=&Q!FJ&Jg&J$|_*XbMAiMq5Io#M8
z*57*JHcLZ#+-3pHOg1-zsRm0^U*LqU&5c1OJB-H4em58^?*d#Re7Yp6%15a;a7qQU
zrB$q&fbbbAy%cWdxmYFEo7t;fLO?UdWFV#{1L~M_0O~aesP!cdl*d73Bd`tPQ2ITD
z((S4oPPKRra45}Bm^d!U^cXG)&H*4a{CN<1<#Pz3
z;V%rKbG`(A?gIR*k67#cxnYyQPcU`v?MD0@orIrT06(Xm4L{%beEj^6|LgcEXazRW
zcf;B6bM(I$KT~n@a}2hphkrr%yeb7g#Zlz*@e{#QO$!VJpRWu6pU)@5=hgk-^MZcx
z3GLYrKJnte1wMcN`S3{%_bG(XHqrZ+0RdE%cO@`XWk)!S9*voxeF0Q6oB*PQrC)>4
zo;(lhV)hD)1haN3lu5ZlBY^4{096jC{%e%_k_)*Ciz8|T5%s%$5VcGyL@=G-WsO>$
zy~I^g!FEmlI0-^IekOV8+!k~$lQ?$niP@(|A>31wd#tGvs$xXl$5f&0~02C>dq@&6jvsJ9Acp+c95-sqyJjo+_UPcOkH)
znObqs%~}9`bs?adwYuVx3dO1w>4YfLr5W64rBpZ^&D4x*FNoo+#vG{_i|xpz{04=S
zladjZTR8-PI|vNeOF<;_L9OLMzEe5pgGVDe2VePwrW}i7uO~L$avKkN^5X&-SW5#7
zYWO>$7JyG{-6l2eIG6wNut%xu=YRazEgu1Bp8JKN`ADV(%~J-3=KKMn`KQbKLo+bR
zndidik5ceCGZmj_OLHxJ&QI94SH27GD9gSDRECKekJ2sro&o@a>BJT)*XwK>R;L!C
z;A61-%^0LP`@r%gfDhKaLH{B=w&cni;&|NdQI3ngIkp%c?@6&|GeqArq#quGr6v0O
z4O8|Cw{PQ03wO&x>p*T*<#teA{^c4kg^>{!fEOhoJ2BgK(DxTqZez2ddkCkHFg+rL}#rk+u>m+J*+l{
z>M;aI*Ksn8$DuouL$}Tj^+oSX2cc;!@9u9E17aIfZD%ozdAyjL*_Y{P7Q0ysP=-R)
ztYwGMdiNO4WeCyiU4Xk8^2fO5V!D(sR{g>9FV8F;GTE|+X>>?jp9<}OmqlO`<1*|o
zW*E!X?iLRLwV57wIlsim5bo~*QBskKaf{ibe4J!4pXR82H@v$LMrIM;_kg*qU7oNX
zu`d1R4->|95`wqIW)MSXHLkxnf?tz90D`xD9)dSM)!#pjOPW5%Nqu(vI)>kc3H$ni
z{c-%h)533E;sEYL0Ix#;4-E+5V`89jejhZsc+QG{7k;PM(*xpn2HMmAkKy;Qv*CBz
zzZk#k5Wm~L6n;NwOLz$q@ZHBlaAgX5e*yn`DtuoVhi^|m_*P=@JqWc6Sk$m55h#Ux
zkMgeQ-JW7wQ})_G;LWXTj^AO#Z|Cx4_(n^c<9Fs$iZ0Cr_$~vo&`pKo0N-O0@O|x4
z3$@Q?THn*pw4Rz=p2bq0#*W5Sqy^mh5wVL0%dE59)An`1_H|zueXjd@R|S~h2VI79R15=SXiNPS;HhSn2$>uip#c`DtVU-%
zHj!4;K?G)eHyDWbt)qVGxP$K?co?UZ9|eQgKO;*wo`t<{secg!l`QmeM;6AP_x#>KGlLB
z+cj^mDEeN&Wi*qHgBxAhCwf0fPqLTAwE{J3b)g+@RW+v*aSo8LpV&%qkv`j>g
zar3RZVv0-u2p5dZOR3T#F8ysfAs(eitojA6Qy$lbW9+B!L+(z*!**l|^&P|Q3hdPf
zI|sRxENa}HOAWiCDGenDDccvlgc{?H!CPP=KWBlSU>L4a7lTZH_+oQcuQp`=k%!`71}k(`mmkXk7E7awu6oeoj=8}-|A5s
z#HB58LD?)Wt$`I3ymvHXTtHU>qW3OX<0mQH>N3&m~K8RA;iRz1-su2s{jC#H#ORiS#Kpt8yp4%-EU3XRO>
zpJ>;LD_7*fZ@Do#lS24PqCik$EEFtO#}a4RQ5f)*OYcC4w&A9>)1^EOHcM0;nt!50
zT&HHuQT-FMB0F$tAqQqF{!!ivco~m})D#oqe;@;9MqWH)n#=|y#_y7(=(j*$!!P)A
zIg4Gs0_x|Ia;sg^Wz{a}@@kiKMYT(ks$J5R)h=mtwM)7R=@9f|{I%2@%%H)Dped#%
zPHcey_dg!+z3t?xdNw)$-YOI!K3L1pJ@-e8ZrAb|cCK7Ilkj31DG
zK7Kk(v2t-5XQGDvRtnvfUi-kY_T*6%rglGKrw(;5PH2Iis6e|v8!mj
zt57RcPKQ;vI2!!$4cdB1uO;#!JN0M4Xn`d;u~Fflm_>zN-k&bk&f2kbyllP)a73YG
zwNP)(ajNVWy{nS+OCwyVg19WMUpk@xK`{x(HQxUv^EJbMDa5w@0CPgE$|WH(9oEL+
z-I{XEqjW8Fd0K-?nT+LmwTy|pmV
z=F7EaV>Gm$Qx~|}XZ;-D)6^`$DA+0%Hy3RZD}Tr#3Kv=V=XOy4qOis~b^pvZt+G3NBarc^{anSw|k^hKndc1}QWAFFg&kOH+>`lcN!>gK@ogET^-cY##H
zr8qR)n8p#PMEX1^cmT&mzn9G5kP^qdi;^+#H4?+TpT{xpaSQV-C6=D`%s+~EgZm*<
zLZAGpdPb>T4llR>CbY;swgipQ{d|KECpMGHB(*Uxd4-8Y+t@z4d%8f8JT{GO>
z9>c?7YPSVbqvJ5O;{PH({T$=Zl`~2B^tOdh4d=k8$C|zfKK)~`^vFQ4w3_tOpD}#$
zCE-)qPm-|d(HJ((iDOgb{v=Sk&7+)II4J>2(-r_Iy@q0vgiN6AIV>%fW?Go^kTf5>
zr?{1G?;Y!WM91dpTt
z?i}4%fzadsNtm*I9)EEgWgQ9g$>VP61Sd?#gSx3+)06)B
z7@q21)K1xP-9HnS`s@C=ZMyMa=q+F?@qHfSfi`#%?vN|gc#0c!p-IIvA#_~0BD!&7
zoctuTd&lhYpBZr?Of2Fmr^t2VkcAaPBXOQ9(IB%$3^eg?J0OSh?*h9yW?Wj
z2zxT#+3g(fG~?P^sd7wQdQw0wa3fW=h)X|&AIcH2YC2w3Io?f#^?7n{GTsdWeRETN
zN7e+?H#cQbV?iz-)b*fmjz=%i4D}d)OS@QQ7vhg)Xu_wIZK3Q;SO{2Rx*5eZl;(X;
zg!c7zi=uB2cAPHdscgT;Pg;`SCd2r>EUHpNN_%Id8>UpMTsuGEW5&lk9k
z#lFCW?WLJi2x_2wPNyZAXxE%0;TF(R#u!;swu;_fY9&TZJ1g=Y+BAD~)__fTF#P%torDT!aA&Xvs_b2G6Xr?{r=q@&sz>P(y|3UdA6w&i
zD6X}SMcqY}u96cG19$YO)%gA%Klq_lekydsY{8>vuy9$T*PhG}UX0tCOD%>_Hb17m
zFVKzjm%U$|otc8)y`YbKBYS(kV$*WVKxo{ni4(#3Qg%H8ac^W62jX)haH!-Ur2VF4
zOj0E*Ry|=2JIzoz_&$t->@;6*X}>AH-u(>V?{OF{yEgV8EihEdA4;+(x4T(QZ2Si_
z<@mypH=AW21NN3>YQkQiq*Q5uFlX>PgpvhW#egdC%CgevbWyfA5mYz_Z$9-Q9L8___X
zSfOY@SPxc?NN=>8&nLSr3V1^~17CSi8vAAwKA)e-Ot42*a#=rL5>
zEr@fAJ(iZIY`-Ra%DKfB;1=(R;VG}DaEnkHs_V){XH3)5F{rwLf1@_r5+mZZcFKu*
zD!u3)xTwB6@!UXN$}4EnjN6Y>h?|;l#x&=wi0S`ExK?$;8PiPg3kj50oL`7bot#J9
zNR^PdGy{KJduyb;hhNo{py)deKa`_lRk+7Ak!4`GqVoq%;+9VX!HDeXG0nJpR_%L!
z6>Q`NM<=MbpORnA!tIF@iTZ5?W1Rq?=4dSJDc**Aq3wf>cP>;n0FQ9P$sibWG3!0k
zjGS@cE>jL5Y`#VZpILkvDFW;>f$rpU72+r=uSAD_Yb&vmBh64wPZwpD{Yo#HB5
z^z9>@Clpd|O%E)J#m(9J@EMe6)1J&{j@vn(nFN|o*&{A(LvJ(eL7dD{>cpiDmcJR+
zCV5=~e;uWK*PYU#xG@-{d%+G3bgiN(n?&yr8|N~JNj^J&s7PZy7MCg0$gpH(}9uheKTYAZIhcnIV$_&Gxo9r9p;rF#ORh
zC(#5GL7)ymU@R{Iw1@F<8;Gz)YkrTkW)nD~QwR+ti&V!*%}$W|HO&SGjZ3)VhkthKoAkBk=^pxxjOKy+OA@{{zBvG;$wC+N3U3r-5_``z>B1
zF0HWfS-V1zX;{3sSSpM<@B@#u7+~N{LD#`1(HpR(&>pdBj4eK(j&SNDR*i+!u|Wm0
z_{vPAKhQR30qs`^KSwIo9`1rBk1??w-Q2jS9^3*k=*~+!J9Pj2ue`-*yu~EY&k6Z8-@!`G?d90eKxjhtRM8^gkzzWnfKy~*03@?Ople~jl1IF
z^(GS{;XWskH*z1p)iJ8j8%_VaiG4nsyI-c_>P)`fBjYs1XFl;ATHHWw<8!EOyaP9o
zoe#S};{L$6WM)W=is%*<*~+&$+!cQGW7yBW!xw-v{TlEvAE6#LL`=#izQ3%CRpg)_
zrc0MA9QbV?WfeFDAp~IHlA;Bp;lM-)j}AY5H|(>>;QQ+)9{z-vAG;g&2TkWkTD}3<
z_`SLKHwXV-f+c-}7x;}Vd`|b~%?2uYE%r8aDI-57f8)NhG*
zqx3TDowz;|4$(Xh1NC0PBVS=L}Dn1*4;{xh}KgqKD
z-Awm8>br+mO3S!>bJuBthPQ^Tc3^A=U&2#1)-W4rvLZRFx#|OtXex7
zB4~dGa;CEFF822vRAeh9aOJqf2?4jf6C`VB!cZ~CnYP!l{nT-Ki@n$iL@8JZcK
z<6q{6VdnC?o+YXoa4R(>bqq3Q@3@#QErKojXS)2)LJ7btJXf7J7_y_m$Z+0{Fp})u8
zAo>=-QC+aX*d)74-s};YVP!mD5f3GesjT>Zi2!OqmA`xY#FD4%m)Q6(h~GEvvU`em
z=)!bqu1DD>`kn@fhDEj2Re>csNU`5myFXzF=7?
zkk0wgscsf(sKocdYM}78&iOQ8+WyxDq(;LumyVHw$^&
z1Zrf~6CUVLCa60Cys_D)upQ1NVk@zFZWiJJ??QW6haAJv*{X6-V>|J5udP%Z#}kIH
z!@H_-uw*=y&uB_dx#AkTSXxv%hSj@S==9zJU&$Ya7KU<%Bd1OCGmBLSV>hrJxS22H
z8W1OjaCA%nRQVm1HK^>Eky)Uz({d1-P#hnL%;<&fB^%&kJzgx$
zia*4TMaBY8F6RBDDZ8)(HMSWK5LbewW7sZ@HBh-m-GKW!%5|Dh1D>|3QN5c+fY#>?eq<(LZ}BhOxffcqv#;AWlu-htm5+;W}Ezf!8h)%zyw
z;O1uU2#u<-6tLL1y|*H0n!Tn{L)o)P5&gW&T;hZ#%9=H~8Blp9EbjyKooG1oEYzj`
zWm1j}>|*;^3%TJ`DQjZ@m%Oha;CD&0;kdm@T(k`^Jj2Zz5rxH3=LTY`w9s<_@jcS)
zm~{0+V|AW~^h4sCA=Ib%Wb8;`aTNKC+u`yzUz50e^lV(;kkL67kEIB}gT$DA|PHQW?^s|3L20@3$#0XK%AzE8_2jBi$>$t{|UYv!f|
z_2Ncf;K$c%a0c^aQWlYQjzt55UeVb=ud(l%FjS>-vo~m0cteTHp8;}G
z3}a_Cf?K8lYwTjDr^00*0T4|QCjskI_X+t=_70E$c@@em74`!WxCzd@f(E`W%_0IG
zAOh5wX7>o2kqqe4d|jNV1Ha{DAl^QGx0vhOKL7bI;{zUH7qWrhTVYZ2JxU{=cEY|K
zfD&BamlCAx=fnA1PT%r=HT?+;fs3vOv>eylaH3g?1h@JEKmNLh)l*}#smrx|6|OF~
zp#RFI7TO)HM0Hfx6cJWZ*2G6F-@CGY10RN*@EiHB)%4RGD9F%Z^-O)#wl!m`XV
zLAcOF$Hfu-KT-g{S!j%`Oa}a$&AzvUS^b=z+b%lhyqSvRJI!k
zjKy9Gnv(g;bryf|Ab)X5vyr^~zTILOY%h09twQY=9fKDk89$TsH4DlIARiI%E&*}a
zrz-6wJApWaIB{rHmD8nz;USQM=pgP$W(TOS&o#E7{68(mFxjpur(=wv&0-9hIAemV
z5S7!&7)Du)q2Y5F!}eqS7()vcI>HyVBV+i1s+^87hL!|l=sCt2!|9Rn}5O{Tx*XOyQ9Th_!H7nrLjoCtkwQ;AS;I9WZK#
z?Q_MRf^!@rb*FhLpGS;uh;bnYa3I)4y2?OnNVHsbt1cv;KcLPV
z4y?yxXf~BK#>rIXa~7AH<6ky`6Dj+17LVE#llxZdxDMP8-TxeCQN!XSYRq!wl(_V^
zK{%l5P)?7z*hA86PjM|2`DF{;K`9}h%8BtQo~5ds7MDJNowAaTlj6-Tc7U>=F2AG6
z0bMv4Cscz?(f2qKsw+fa87EX8UjR-6-x?!Sp=3gJ9qct{OffZicZ^Vl`1)1*@IqUR
zPicnTfqV+xFtE8e=TePmoht$03l3T^SoFO_68ne4jRard_m`*M2jhJ5!263&KHL7{
zwW<4y2S2kz7N1;W?hk`|>QsMS%nBV6{8X(qT5=(*^%kOX}+u)kN*tK%H$c;u(R
zkvh`K-^Mhm5-r)2K);d}RXJ8VBHj^lj4dwlgS}ll%T7~C+$hlNIHX20I@D^wFa!6$-
zRi##(*e=Jp)cY|m^%jyS^uwGsGOv$2VU8!}K>3?Ab__Ohd^rhEEXYumlcM)vC-_D<
z*8%L&i<8)tUd)jjNDt0BSR2~|^Vy4A(`E{Q^0*0-vR|yc5tiN!m21IPsQ~y@^rJt
zLTopc8#dbIx1_OdjUDx{Qyz9kle;vtKCw54cO&{iN!jHPqjLHq
zYD{$Cj#@$uZo5;76G~#$or6Ien_|iLsj(1twQi5?#Zd(3J+RGv_u}y0>a@f~h{h$v
zDv-5D2eKNWU9B!Bnpq!f!RX*3acu+cE;LAE+hc;D$-82*ps~$U4EyzQytfaJA6(c7
z@f@7GtKzyHx^Qfc+zQ9ze)_a-v#D)~ChlotWPP%KR!19P23?1yPiz5AnUl#tlko
ziqU*ixD4v;6iXhoi_{wt)#^dCqO;dVNJ)PDQ3st@lLoROG$!%CIckHOK!ikn8ucEw
zl^>&gGo})eRzz^#IOHa#X4b3K9%z?XxuWT5jcWBU5JkSiCqM-kcrOott;21e9U!nv
zlD06>;T+JITc-^Cetd!_CS83-UBo=el_3}9ZKV@H{F+svkroF*-r~~N3LGa{^i*$`
z{qYN81G?{MPDoLP4Iw(mJXZ4fB(E~~1iho-E_%Myhp9_wi?JIP9ArND3Y%v<#@37Xn
z*>Ig(z!H%aTtrX<`ndrgSp}yv7q@6aOH_>6>y}NbD@~P_O`))}slY
zBw!no1ng_rFdtcMYHgSX(N|T~>6UEW(O0&{fI-|}wpNWzmaP<-`aF38$1}peIdy>e^=_fJ;1Bp!P`Gj9qe&TYo3cJ$7T5jR#Hc$XacN9v0!!7jJ_Rp)4&~d@+N0oT67_rbaD{)lYG&>TG6+EV%@UR
zQp=meKV`gcR)5~uK1(01N=xdaANA{_>jwsyf2e<^fZ>`L;}KYYpB99xYW1KCqQh76-*JSbuwh?f1;yzkj
ztI2^F_{jC(^??~=Z%3xMOhd2Z!#0%7dq6frZW5PGWnkHSy5Ov`Y1QcLB3kVR%>g@U
zdgNWH@;NCXpSYi9LOyqce15G8LQ35zo3ywEe6uKGKjb1-?Itl1yNM>Y)cp$iX*4}8
zSnVcy@s1=e4H~|$#Az((kx#(U-p2CS&VSHv!fwr5mmVD-A3up~;=1N+PkMXP$_L@&
zcHgIE*J-dHFoXxxEx6pXq;!ltq99v0Hf`tT3G
z;Uuuo*z$Tm50qVgMOp!zD1W?Rzb-cPpv4L;-CJZ?+SJAaWg+}9szF@cR8|iM;CQ<-
zJrG^7LtF_VBCz=_t3>I7bu_G!JFsDWu+FwXd@P*r4Izo)ao^-23lKW#3p|+-s=A8U
zi7h$u@+|S2)BX={-vS>+b^SlPvmqN2oM2duiV|V1scUUC{@UPT&A<%YfmuXF#WyyT
zVx={OM6rdKumm%`45h#J*PpijkUoF@TdTCRNl=Tsn{0NI@JPZdfIz@s+l>(nKF9;e
z{Cm!w*+(8eet-MtM>H4&pFsKT-CV9%=Llp=zg$=1j-*2tER(Ud=+;Q`Xfjw))#ON
zE|ymSw~Oy3ba(958&P$^7K}YUa9-WJRNLsrYM3RO$uKiHVPUKaK
z79ReX*^vN2^|opcx>o}RWSIpz)%^fL6=t`|p8eWF_hOkp0C!*_LJZ+#g4p`aHXR{H`SXOh(*3gT|TeiA0~YQKV7NcoTP;Fwxje3r!1HBbUkaExIrc
za`~wRIW0|woL;{XaW3b0*i?fGJqz6k@gyz$DN+Fbv@*@apRN+Ur-ikbq(EJQbU)%;
zb`d_LVgOTV
z)Y3ROWhcX3EseuO67W=p5eZv1
zXUT+hVTnfL?e07h7<^3AF@stR+W)>u;MA!{ndLxvC9#|RmI+WvV@q1FV-ts+;X
zjl>hSKoN;iiM=7zg+!r_t>e(BlIMivX%{_>+u05A!uq#|OlYr#DKUk1&~ysAWM^_2
z?41Pk6>O937TgR?EL8sueAvC6!rHgs587m+iiNd1(YY!D!lj3;{fI0+mV_+6O{o4Y
zrZS^U>$f}LDsGuZMDH<#3&l*h(9zZe!1&n8`z(O*0t6UG#xOQ9p?VignAi)zAfV9w
zgzq)^Cj*L+Kf;ZVDRjRK@>SB;H(MEa=$HvNz5sCJGWRlu9EyA*atN(m-)sG3xbeOf
z`HJ_$r>5b27Cmo?v`M6=5o>%l32VImJT^7FH1RbP7zI7u{jKu}Y>ndG2be6=HiXWr
zr5360NfSDZK3o$im$B`qe8UPxX{8u)1U?H5>3f>IFl
zneep%y^cW0f^i|4*Iy3DA6Je9%(PEQ0A`5(^bm+r%O!d|?w9jZbTp&u^AS07(iE)-
zlgw253W#O;515-8)7OeL=m~=)YGP=#h3?g|K6^-}2P8fqdZUtQ#uoKTkiUF1ED5u_
z=sFa%R8I&%F@*si-z0&`JQXtIIV4d*;tzrxw}f_Ts7me!$!tLaIHVqO|w2Ilw9z
z^7vc|44I@zegq}IE8{4dyGNFH!btpag7xPGL!QorlQI!kP~6dm58f{j&vByPZenOu
zPeiD7WX1tB*1&xS6lZ`x_CDxdUhyr!9q(2=yFtEM4!+*}E*v2nOn*o=Qj$Q&e;fgy
zc`;d#n?J(KXa=+TElZM4E1n(|JyQb6nIq*-<3do_EYYAygNQk9mu>+7UvRio`bBGx
zWdjhU(q&944aTl-gx#TE@kbmz*TDyyg|Qh8K2u{tjE~8*QS`pM;t&WDCU|C-=smr1
z0yg>vwrpius1|5CD6Wa1$t?ec6+|3BG{oO@PNqT8dpZS3^Y0A_AkFEOUuRJan#%8^
zWv~E(EFsaRvBU{0XOt;OLjqGHC6LIX_p~C++#k~#5Kgl!0jD_)TmKS3Y{2)&8W@)5
z^a?o{OH%}*#p;zeV%jlb$xNtF=>FK$1`|a?_XBVSTd+~2A6nQMjDYfYScklZ@a$2r
zx_Ar}EY6Mq&%DHtFw1aX@%9S-zYQ3MCB+Y-6wiEdP4S(EP2t;r)D+^`jv7`?W(s``
zRU&LxQs|$UEdM(u%l8rfBgyl3*r7x^`3DmJwk6ANH1&eaJ4Q;C-@j|at!WA1X*~OB
ztI8h~r`v_<>ugDKgMKG2iaxqW^)xH`?G6>-g@=YMigD?E*;vy1gP*_jUf2OkV)Cj2
zU`HBK`Z^WQ9z}N)fvht>s+KfYH$Od9(dQbs>ywHUBOuh;X2O1$x~g=?SCnhP1)T0o
zT2d5#mojomfi8tH1idBHHCQvzv}{YB6P`oKXM|_W{;@>SXAtOW7E*pie_gM3ZHu%m;Rti8c@b0#it9UDbedmd3#o6je$*B^|Kl}}uN2pp0L
ztO_EqYLVz4yjUrTBCblL9m4HxX#Xe)0lPuc8xKPF>8c0r=w!1PN*f8c`UgfCM%8Bgc_
zd{l#O%S9dN@0kMhfI?qS_Okcvht}b+i;t?NtSy;H6H9iN^hq~K5IRfd+i=}(u?_|z
zbG`>}dr6;kohf=to@3Tg03GmU+T`;DHOalYFre}g)xu+Rn!>n5`$2>S;rnixM&C?m
zMZy1XY`pp&BFxz{8eTo2{9qNaBygs~Fh%fKLIn4gxfcs-e>M)!9C0DsW%joj+<-C?
zJgn2dgY>;9!<4>PqxAg)Q~F*4uo3148nm{UBtiVJDTs^Hr3?erGeUKpC62$65XXHM
z@&X+!;WF72|3LDo`~%}Fks6mt(M9mXBp1QB{&nle>0keAq<`S&D9<%xL&OF2CBnvE
z#|88y0BL{LrxWU>+aT{EPZi6a>D|pboq~eKW*?kG&O|cMUc=Q_VHFw*#
zR000SBLw)WWC8xx5t>*J6W~`R3-GH)72uaL0loq>%0Ww`92IH%XtMi_#JnO^W{XE9
zn|78MkBIo#vigJ!p9F$e#{$7`Hl_HtFpcQ#1`vEx5(xe@T-mp0R5>1;J5h|E&X1Jh
zB^t1#_(Crpy!V=Z+kzONc4zAsC0EBsBJCBrXJ
zt>~_vV~V%4oJi9d#(L$~knB@97((4*ch#BVyu}Y2lR@Iohyd#7^_&JZCKK#$u>|`Y
zQw00l4UykDs%*bX^q#RcEWuxm!7VTh)yqk_Ep)F2iT{|LxftReY{siW4V!d|Ff9Uk&p9y>^D3H)VZ!`c$D>u#Y9{
zgPhNnR7IcTP-!PySp#q%`gl_46smu3OZBN@_o1_IFQk5h#Z?*2pGwh{(fz3uZ!p!L
zssY6PMUMEQgbq2(cXAAg|2k9RPX~!V9`EwwB>yGC#*gB26OI7Q*2<)SN+D_<0g@M`
z?q-xGQ-$Syrm!4i!gAOYmX|2rgGoa2*DPU00U2ZVvbngivg}u4m2$O
zL$l`)8)cqg{8aNi=%q`N4m2v93m|Jm0GKypgNA#ao;4AqR)!2<@4@D=?uTiX&qwFV
zA{8!CG3@aW8=FiV!B*^<1~`ye#1^w|*N4ohVw2@mQOTvq{>xDI*Gb%|q79uYLJA*@
zyOuJiiUYEzU4%HPd|Mo>4hI1dPXgC}{7Ha$R0Pd)R085Rpjs}H^j#nQ&_~ZJMx){x
zjQbVDu~uc%7@S?vCAWoQ1zncc3@!5P^Pk{av2!@kEPuizvs?JLt9B#m`HI9j2bGQw~XcTL*pmD5n0ger_p&LvW?-1bI
zOI5mCqG(EKhQvhKHBONFx|PPKgF0Mulp1IDMpUGO`r34Go5&n#~C{DNHEl_amF+Tpc67(
z&Mk$H6)Q{IfEuOlJ#PcftwrIRdz?wDDMVm`WijqI=1l0Xl19}F@lo}HHL73}2;dgY
z7QAywqw7f7RilnB#Tyo$<;Ix<>!INT%RBnOn(0g(Sjhv573Y%{xVTsk)1
zd-ULcJ+5f~23XXXFin0^&s8DsvBo5We&qw;Tm#vYolJFYc*XsrE4s5^k&
z@)L8K?2KJ^KlBY~Dw8LADjxsHNaqSx!7a(o72hAxK{t)*0Q0}|QneKsb^8|OaL;{L6VbGI0+b9Xq#oP(dRpeM~eHoQO1-vZ~I
z2)-FRW4=Y7av`5;Ek&bGM9{c=yuZb06H)pcQ3~d3J=EXNQQM9pyIVjkqraOo)ZUeLQYfXd_(PGi*Zq!4{toAB;93
zzM>dSqxyF2R`f|<^LdUfh5Jk|8|Kf^uJV0LMbANn?vDBHhLfc={+sOJ+W~NB#F^=H
znRCZuBb+-56xulEcpeACxrq(uUb9!MQGHQ-RF5+hqe-l}NHLnM4CB5XhjC-EwiIhX
zCwpp`E|;DUz-?lrgGV^6M~P3^I9X4+C9jT72kspg#TP+fV!C-qZsz9^e)4L|&*N8^
z{kuNBe59MlRp{n17iO;M=Fyny=CO0Qn@6LOGs?CGHtd=i?j#=%hg;DfblWhld8`Ii~cvA}9
zYay=S<^~^)q&Rsz#GB3?>n-Pwgrft-|1Q2ur3rtHAF;c=iyhz=wzdjp`j1$UrI185
zMC^M4l79aMiSLxXtt%gpX*{jI7#@GJTUBfot@wpk$1Pa5HI8_CjRX}$NA`hk9OhRvxmylVtv1W)7pCm7ehqRtTgd
zqEt1(CCe(`O9zEFw}GR|*@pD;Y=|RYfO)jWW?#tR{6n@i={qt|W?N85py&zEDBuq>lAw>P8!EqZR0f?#C-n;2t{KYE6~$NoIS(6=wd%V(}62
z!G{`R=UYa+OBqk2`bXV;&%NS8@ow=Rbd$=*c|D-eGusO|8;8N}Ps)X-4A-@}lQ>dx
zgF@d@_;;;9=rBTyeDtkED7k|mIxJ9WFWk(ui0Hl#iHQ^?pax#{WsZ9dy?`+OJUAxR
zgNG38vU2D(Lx7I$Csl9Y$`1}z@yPO^uV*JlhEP$xCxmAw+>mr%k{K|bHmI}?=L5zU
z>17yuLZ3w|x2H+sQ9pvNMDz&WJxO0=jz9;^$ntcr2^0m*hO`5Gc}Ro-E8rhoonXUT
zs7gg|R4a2|Pv{<)O9jI0Htj)J@L;*~w91|XQ2k04w1&CSbxM4jw$SaCs8gnYgO#@w
z^?avbUM_~};_+B@=S#E_=K(~*Km+-5cb?@CL}=%m!-LNkq{O_<`mt&DW+88f&x9tt
zE|g+H7=QYpyI3`gBWs&1pP-^7pCFmuT!S`o$xS5h`@-6L(mAdt*Yu~NW$x=OW)MOY
zS|MM8U>;xs_oSorXhdat7}kAoFoS^ZW!Y46OQNR=^oj$8!R)a9uz8VA7Sk-AIsYP*uT^PsR-@ezcoYRE{Geue_|di3PxDE
zZ5Y|@Z(ORS`!Wl^a9|{U!Q}h77`KUkwVQClx+;#vc1F9lNJ9V%vPSE-a0Oulm3TT;
zPk`veF!89q)PQb1x5jPHe;;9*-j`&W?pd4qt<*4#!VWY)9jo{f+MGTR>5$?v*udgf
zy9)^456ZqG!oo(bc9-^Kz$mQ#55)91zT%bKlJG2eed!NhkPAC@WTT;xnVFlak5oJX
zaw1#ehEnxMB5j+iJ1!OK0-_NJ4myN77ML5_!rLm*W?7isDhjh3C1FmJM7t!uL#Br$
z@7~p6y4;;7`Uh-JPLu(d)dW6-o-^H-*%`h8vjfYz7&oo2l&k-z{5zulq)~mUyn-@8
zS1t_D2DG%e|#jsB0J*k@set4S%(BY%yA3+1FtymS{sP<9QGjScc}E0zF^)D^wm*
z%+s^JfQEb1lqGr2bVD3){{?&b+h!5GWp4M114$8iTOiAVxbKT+kLc~ALuj|-2c}Oc
z{~gFH3+C#MTSRXktWpwfQ1tJBM@|gfY@U41ihc)Cc^5EjY`A<5W&YcQHlSfWJkp8{
zQ$@e$T%B^ow^`FF;ic@Dj6@QQ^3(c7n@Fh}=*Z5j9~!psA)`=7HS^v+Z9
zmNoFS=`WuJf&GhD&al$b@R*2L=I?Vr;rGNQJZC!FAS;QMx!r(75WP*3FsE1aoP`j*
zdm+BRtay(;Rm@;PM-A}C<6Gr;WPeGRbq2-@>~(C@!;NmCyGX*jH3tl%dm{^VD_WM+
zG@17Gw6K|49s>L6^=8EXqNIrbH!2Xn?ttP6FqsscaYBl>;i+2{+OMhZ>lKdy;VV`V
zeh?=QNgABis1UuopPB$e<6gW^YN5LbO6q^Z4YS`SR8O=sRAs&l+bEB}mb)d(m>>3p
z(3byBk`@j?y=>Q3=%3xp1@C1yyB+h-Zf3?m4I8?`pBCwi4fMF@D1X?~fCl_um{-9S
z08qe)f(VokvYTeZz({O&2Y?#gqwAX-q*T!OdF956ZC^pxs-nW2=|pD@kzixP@KWbb2IV-~gN1CuYI
z=SWG=M^C6`iBwOoVgwb>IXK8H8YBE#5R}MUQHgwRim61tk13JU<2tkHs6=iat}}c3
zbPg+CyfA!gJp9sw&|ke`&5eo?G)tJINKRL1>s)=3pm>_&`VuTd_C>9cX8qZ0rNxCNt8HPQo@JGcOVZ_JY3v55^Wlnjbe?VA$m8^?r
zu#RG1Oyt{wgXuIBj7>2Dd`RSj7EVMi>@dTx$eJ%p(&yVmP3FXi4CX;#CTn*)J`F=z
z^G%lY`F2s0v!M(TITsyQw7VyL8gl(%Uex3~F(SiZn4=A{cDGyBeAoNW39GM^^jTxk
z@(rZq4L3BkxE(Y)Vni-7Grn2W9-1L)a)GwmeZA-%5H>WTYFSwQ4N0FJXXw-KmQ1FH
zgFRFD!~8Kxe*h|-vwDiGi>Kl_8x2XB^KBA;Sk~q`L?b9_<3(+SQ`YW3ulPgRl6OzV
z8$I{Sv|aHItiIEy`y}FzTwwSti5?OCgUEX3$Fsh}AsQi3%Mi8iI%Vy?^NK&1P5kfK
z%HJR*W$x<>kG#pQAUHty4($yyP--85!Wjf`zKsM=I23+YM8w|I?sG)MEY`2me$EJJ
zHlokBkCw=8CGrRCn2H}Q6`x4OYc_A6u#sG59%T~aUoH8E%AbInoeNa&ugwK3?=r+d
zkzkiY;lmafgqWfKXf`d*7S`P|p5wfsXIv0$nDEW|OkSKW?c#(D!Ca<1EyaaxuS{=t
zi+@FR!9T}xDQYWTV5q%Kpkbgd<)TvQFroEKeHd104eEkC5kf2TMZNG;$Jz{|Q*`C676iV#X61g`mG{tHzn38(Es3Z0kO})oucZ_k!vp
z!p7Uiah%aA7j|I9EM=rsI{)h`-5#*WhJ@`(C)O|$G3i5Jdzoo6ptkT
zU!e}T!=aRfRKC;aJv2%*5)AI%>hpG*f!%qb`pw2KSfQE=6de+2jLo0n=ka*diQxzGh$PGjOSC_6AaA70
z!7HB4ZFVr1&|?Y_&1bqdbBTj_>bbmJt~Sa`>4R=bufW@Ke)wr`%PGVYD_##|vMf9p>s;UrRojd(NmP1T~L7=yrR{+{J?b<#UG7-ERWocX?O4
zi&sQw*b`yr^f#af7eibOTv(~<2J?ZZg&y}_V9_z~2A%%^tH*+bFKZKiEd$@Z1F@DG
zu%!1Y{w9a_!pgf9-EkEl;8n9B6}&}fR1iGW7_vn8yT2xWU}xBOmG6!1u0ibkQusi;
z7p${4gT60xFOK~I6L>E`K#XI=`=FbYPoKWrowu?ueoh|?@4gV$Zq>ai_E?SOxOxyY
z7_`h?>}^7?RfWaExYpJCb13JW4f*t3tW{8}85%)*B++8fvM$lM91iy9fTd7DJ
zS)2&MQ1*lc$Dw~>$MWMWHqJ3mk3=W`K;(NE{j-aa`D(X2S$`H0jXiKQpM}g1ig3<6
zK=^iCz{gpK^3+f`1xborT{J`Cv{?ZAo2^Spn0`9}ut)ti`$W0V8((i;R#GwBRQ1Fl
zvYLlE4uXo8SUsm&TmJR&%Ssw8I63g}wD7^6zl_#jrD77M9J-}j@*MJn<4E#X;qFKO
z1^$@{)*TPs`^Ixz{7`*mVLV5e%)eyb8yB3-HsNVzx
z$g~T>G+N>!M(UHa)o!~cMSx;}(*b~j;fpu0^4l_v(te+3H;a$;@sgc_W}6eGn$mAT_hWs8y0XzsG4Y$3Y~ryUU?*7mEogQlvLi
zygX>%I2Pd6mP|AtreS$o-_H(y4nZ~B0
z!p3~lB2*yK9)cHlY7e?470pZ+C!3jerOK5%=z(~syS*S+zGYr@hJ6N}{;dg};at=i
zV!XTEDf+@;@+A|`?jKveWC>>fYs^j93}|y|M~l<%M_8PmH!V(N42#p7V_BTG4)4Lw
z+2RBxm%K+S9+K#8k@mn6;EA%Hgb|9}iM^X7eP)c1KKqhwNyF8iFj`P@jtigviT>ay
ze4=_l+@6iMqaG19t}>xnD1aW5>3}JJw$IfaIVgVyhsmGbJ>Ux|%#Mh{?654%*#nyd
z-yuREroF4fuv4R#5IraQ`)yCUByW@O>q{yQpHVmYg
zt7qL{3Z%1`K#H3^DEirjO=#Wl_6h!bKq>{bh~Kc6N4?A4?iHaV7tLBG7SaYQVw+V7
z5hSD*dX#x#M$Kp|&khq$iWR{0fv(pFk-U-7{0g)Y90v3d=onE-aS>eKU`g&t%ctyq`i=MXL+cC-&N!xMSvn
zZUQnVSe2N>YB^-?TXC)8J&!VL+z}H85x*x%W_@@lB}_#Yrl4oLXX72w%iU6P+_vtO
zx1b@KIoQzyB5fj`kc{{4C;-n2JvCjT9iVFQdD>8u5
z5Di4dAf<7!G-$&hA;sVY`WGAsW$t_?Hbccc5%5Iy|J*biq3A%HRJz<6qvM1>CV9>=OvvO7GJnqG_v}1dJie~!|5*$Y>dgt`kx2Iv&jFBC`Gc?#
zyvL1@Q+@m{xCIq<0op!%BZwQ1HjQOGs`~tmM-XgaSH-O|JxIGjGL0eHDQpU-(D-l{
zW6u}j>*H=~ee?$%Y>9j`(MixPA{w0I2A(F#Gay08mPlMAePhTlybNW}>^z;QA4swD
zm=bAeMec)yF*|zt>V<8x8znkv}Bsci2FI
z;2%WQ`^>Rb?;#7V>uI2uSY`pfP0?rD2t@H)80OYY79&!aSp*_d7=e?rwlJI}Y74_0
zT)6THr2#!Q?HIc-2Ge?re1}BGDf(=?XD{Ic5+5o&B73DUwGnZ(G7<^}nXoNsp!nce5ATOJik*Oms5fTlF!PpcKcKMLZ2SGK>2SmCs%qjY8
zUi5UZ;*3!k)hrA}Oj-~Eb^q0Ys_%Zq`=0Q_GSn&@ko4Of00a)6bSR+s{%0oskdx`a
z_bdKDmJcEzuuErEK4!&05#Kmvz=G2!dHx~x9rNiAN&Z`GLiHMi*ky~}!HQfkqK8OH
z8?jvJ`3`z>8zAaMdU(usPxR1Xe*-^DpK+1j$XR{m9Nm#+r5t9L;1BDQuA*ps=(!OH
zB)a!C(7XfT^cg{pXxm@b*z7XvKITM%bKAioYQn+IVC45Nz~+Hlxs*p@>Qj5PhzV
z@ExCM2+?QTNlBFO&0<8_W%cbY2mDGghKQQ93+gdu;$)i$Choa}wbzKkftkdJC`OZM
zyRl-gdxwM#5x8`)q=^m@J|I&m>=ZryGF8J4QW7yorc=H%Pqr=%ahx3@MyWn2Z3WO`|{oq_T`%t
zBLw|4(*NvI#nYkCmNEU$RQ@1bEplF{Ye>{%spyF;6*W7UeXUwzl|R=(+Q*i3l^h-*Qm`f3&z?jSo(0jib5q+z#$M^8myRqRqqBH7#Mq
z(>(l|mTr6)9Hifp#)hAu*^Be}`okAU%$^JYle~^^y66zWt6d9lrtZ@?W`3J3@w^=>!8QpuQ
z@-yQLSl4H$B}Y~Mh~+g7E@=xC+Nhehk1L)Y9}N**Pja>)utP=CdWeQhGS=}B~~
zLK{aTH?LxeFdv=k6n!Rh(TO~Hm4C=4tV6G1&!D0|VGzCA^3Nfjn4;h8A^r=(io3-o
zdoR(~oUsP7<)d@6)t9M0I(a+eeK}&{!+k6vvE~-+w=njb9Tq2@*i;%u?%=I+uob;^
zR+-*9H8|3jyBEQ|EEqnGKcyA)WLk|P7oJk+Zo{=GmILS^Qq`D`&NSk~;zQztk39U)
z0}VUT3jqBA&@bn>d2N^J#h~~HmaMpj&%j00VE*W6^-k;O7RbjUy(~_Mj}mRsGw#dF@lQbRH!rYUZ@QPy6pBgqKh_r
zhoW)PbuD6Lut2KGc%*?)TZFr@pr8OX+nVi>23VW26J=8MD_>l?nZu%8k&<6>nR+H;
zfi6oV&_!FkP>RMWGRqqQIq|(ougt+rXYtSj8W-<`ag6UgJ1i*KkHE3S@%^RREIZL>ITVdEUt^_V
zEabvK$s;AMzi-*X5&hp9P7WCaCfbgIz%Muw>>5Y-ej@}3g#wjEs!pbJT;-Z{qs8CS
zZ-i9Zthrv^vV~Ln4iS1>h5rt!0%<1I%}={v@oh@~5_*U!w9^OwwJB8tF&qu3>fD|(
z6efdLfZ1eq>+b1V`y#hg)WGU%@3|Zs{L(~<%20t=lkL-I*?gc($JaE%n!6=%!ftQ3
zcbM%g*Eq$+u10hK|B>`u%g?+kXC_S!V59V%U~@y^;b@i-dkq6sO74OPm-lTb$4FMM
zaf{~kPkkI5XX<}2cy&!44SQ*ktQnwRc0aH>FH?rS9Bi|8B760H(
zPku?!=iVeXaW^EUCG1U}7Si5L_!biE9#}B?&!K03i5c<4As*?JcpF_cgS{*yZuK$nGZWphZ20}O4ZYb{dr{AggR$c
z@a^IKWWGwS+hMV?p+K(5#qJ;$ElHwHZX7b4!F7i#8w$jlMZDNl?6^ho4_bMjOwgwx
zeOf`{{jg5!5Gz9ka?OHqVpDPYh#s?=2?CSoS;ZuHf>%9<5)~%?{*gTzukcu%>4XX|
z8MU!eN5fbxW>$IhCQGXFm`#SY9iz#dNbf8#+aid~@$rq9AvP6{=U9^^`~{2eV#|CQ
z|8rR8U0E+~;Rx*{!MDc|{;(0a#$48;{%F4u(9+)e*%l0B+Sf@05+t`~U(0c8u25-^
z=&nVJH=`eDO&_diASC2H&_MLNio^Z)1{zPCyDms><%(b6)=UbYyU%s!&tAmT5E-wq
zqvv55zT9_FweAhBxfGI2F_T_FZ_G9G-mD6u11NC2%Esq$%>W;E`{F;
zH^Kid^AFm}XExauLS2mD(ui#)$LiE%n={Hg-ze|q#a~$MG2H*x|E^P|E!EBCE>d4$
z{v(>bW~P()8=VbAo9tHgJJX1MrMP%AC&FDs$?+@d@4K|F-KXDqzVAfvoe7VHpg%m(
z`YF{tcStlyTg1Mu;5%uLhn7g5fXoMA*Uw!lYBR^_j*G3o9g4rlR{j@4C%bV`%D|k>
z@o}$2+vUO|Ocu)T6q@gMOOQhal|DGX6giMPzo*4K}
zyRw}jDSMx34E4SrWL{5JN&!!(3&^x+`9(x`t$k=S_c{!xo?=qZ$ei4|j$AQDA}%NL=X{0Bt)
zDxs0c9H=|jJvAN94l$zNx}kH(Alu`O8I0YmPU{9edQo+tJV$(U_c?$ryuqRfO5o$E
zSMEAz81hYLtrpJ4z~Oib%#6vjAE|wGzv%DZDQw6FXVU7x)7f%iGdg97udhNCx~vny
zA{2w&j{4~v-!2j#YtEK(IGG+2gKs-Tf5R#`d=&+|FZKs7>pRi@j{Ys9`jk)u>&R@O
z?&aHi{V#H|r&ILztg@IX^sr