Repository: ArcletProject/Alconna (language: python)

Issue:
[OSPP] Alconna 2.0 版本设计与开发 
## 描述
Alconna 1.x 版本存在诸多设计问题和历史遗留问题，这些问题需要在 2.0 版本中进行集中解决。仓库主分支目前已在2.0-alpha2阶段，清理了部分冗余功能并且提出了一些2.0设计。此项目需要基于 Alconna 1.x 的基础设计进行 2.0 版本的项目设计与开发，并且需要将 Alconna 的上游基础组件库一并进行优化与设计迭代，这将涉及到对文本解析算法、系统架构、文字样式排版、语言底层原理的大量工作。


## 项目产出要求

1. Alconna 2.0 主体架构
	- 全新的或改善过的命令体构造方式，并对开发者友好
	- 对模糊匹配、命令补全、消息帮助等功能与解析器/执行器进行解耦合，抽象为可拓展组件最佳
	- 优化解析/执行逻辑，使得解析过程是具状态的，状态可复制的，控制流可移交的流程
	- 减少代码复杂度、增加可读性
	- 命令配置项读取方法更新
	- 配套的测试文件更新2. Alconna 基础组件库更新

2. 类型验证&类型转换组件库的性能优化，可使用cython或pyo3等方式
3. 字符串分割组件的优化，例如使其可识别全角引号、识别自定义特殊符号等
4. 更新样式组件库，可提供更多样式
5. Alconna 2.0 外部接口，需要总结 Alconna 1.x 版本现有的外部衍生项目，抽象成统一的对外功能接口，并尽可能提供具体实现

## 项目技术要求

1. 完善的python 基础，熟悉 python 语法特性，掌握装饰器、描述器、生成器等特性用法，了解python底层原理，对性能优化有一定知识
2. C语言基础，了解 python 的 C-API 用法，了解 Cython 工作流
3. 结构设计能力与抽象能力，能够系统性策划该架构各部分的功能






Discussion / hints:
相关项目：
#74 
#84 

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2abdaa65..78067086 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,16 @@
 # 更新日志
 
+## Unreleased (2.0.0)
+
+### 新增
+
+- Sistana 命令解析引擎。Sistana 是重新设计的新一代命令解析引擎，支持软关键字（Soft Keyword）、快照等新特性，提供了更高效的前缀匹配、紧凑参数/指令、分析中断等能力。
+  - 该功能当前属实验性功能，不默认启用。
+  - Sistana 与部分 Alconna 特性冲突或使其不工作。
+  - Sistana 尚未得到高度优化或活用其特性，可能存在性能问题。
+  - Sistana （及其上游库）仅支持 Python 3.9 及以上版本。
+  - Sistana 对各种特性的兼容性尚未完全测试。
+
 ## 1.8.30
 
 ### 改进
diff --git a/pdm.lock b/pdm.lock
index b2e64214..ac617509 100644
--- a/pdm.lock
+++ b/pdm.lock
@@ -5,10 +5,22 @@
 groups = ["default", "dev", "full"]
 strategy = ["inherit_metadata"]
 lock_version = "4.5.0"
-content_hash = "sha256:ee42e99b22bc711ceb7a84cd89a57a776b2cd95733acb2ed38752667c7cbaaa3"
+content_hash = "sha256:6dd5edcfce3511748f98289d9eb064d7cec92f699affa1052d7fefe6af365d2e"
 
 [[metadata.targets]]
-requires_python = ">=3.8"
+requires_python = ">=3.9"
+
+[[package]]
+name = "appnope"
+version = "0.1.4"
+requires_python = ">=3.6"
+summary = "Disable App Nap on macOS >= 10.9"
+groups = ["dev"]
+marker = "platform_system == \"Darwin\""
+files = [
+    {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"},
+    {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"},
+]
 
 [[package]]
 name = "arclet-alconna-tools"
@@ -25,6 +37,20 @@ files = [
     {file = "arclet_alconna_tools-0.7.9.tar.gz", hash = "sha256:bded24c4157e13e2d803fe7b77ee246fda456206451337015513f150d1e4449c"},
 ]
 
+[[package]]
+name = "asttokens"
+version = "2.4.1"
+summary = "Annotate AST trees with source code positions"
+groups = ["dev"]
+dependencies = [
+    "six>=1.12.0",
+    "typing; python_version < \"3.5\"",
+]
+files = [
+    {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"},
+    {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"},
+]
+
 [[package]]
 name = "attrs"
 version = "23.2.0"
@@ -39,6 +65,20 @@ files = [
     {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
 ]
 
+[[package]]
+name = "bashlex"
+version = "0.18"
+requires_python = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4"
+summary = "Python parser for bash"
+groups = ["dev"]
+dependencies = [
+    "enum34; python_version < \"3.4\"",
+]
+files = [
+    {file = "bashlex-0.18-py2.py3-none-any.whl", hash = "sha256:91d73a23a3e51711919c1c899083890cdecffc91d8c088942725ac13e9dcfffa"},
+    {file = "bashlex-0.18.tar.gz", hash = "sha256:5bb03a01c6d5676338c36fd1028009c8ad07e7d61d8a1ce3f513b7fff52796ee"},
+]
+
 [[package]]
 name = "black"
 version = "24.8.0"
@@ -67,10 +107,6 @@ files = [
     {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"},
     {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"},
     {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"},
-    {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"},
-    {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"},
-    {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"},
-    {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"},
     {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"},
     {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"},
     {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"},
@@ -79,6 +115,121 @@ files = [
     {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"},
 ]
 
+[[package]]
+name = "bracex"
+version = "2.5.post1"
+requires_python = ">=3.8"
+summary = "Bash style brace expander."
+groups = ["dev"]
+files = [
+    {file = "bracex-2.5.post1-py3-none-any.whl", hash = "sha256:13e5732fec27828d6af308628285ad358047cec36801598368cb28bc631dbaf6"},
+    {file = "bracex-2.5.post1.tar.gz", hash = "sha256:12c50952415bfa773d2d9ccb8e79651b8cdb1f31a42f6091b804f6ba2b4a66b6"},
+]
+
+[[package]]
+name = "certifi"
+version = "2024.8.30"
+requires_python = ">=3.6"
+summary = "Python package for providing Mozilla's CA Bundle."
+groups = ["dev"]
+files = [
+    {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"},
+    {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
+]
+
+[[package]]
+name = "cffi"
+version = "1.17.1"
+requires_python = ">=3.8"
+summary = "Foreign Function Interface for Python calling C code."
+groups = ["dev"]
+marker = "implementation_name == \"pypy\""
+dependencies = [
+    "pycparser",
+]
+files = [
+    {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
+    {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
+    {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
+    {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
+    {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
+    {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
+    {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
+    {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
+    {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
+    {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
+    {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
+    {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
+    {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
+    {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
+    {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
+    {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
+    {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
+    {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
+    {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
+    {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
+    {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
+    {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
+    {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
+    {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
+    {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
+    {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
+    {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
+    {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
+    {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
+    {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
+    {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
+    {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
+    {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
+    {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
+    {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
+    {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
+    {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
+    {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
+    {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
+    {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
+    {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
+    {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
+    {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
+    {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
+    {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
+    {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
+    {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
+    {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
+    {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
+    {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
+    {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
+    {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
+    {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
+    {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
+    {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
+    {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
+    {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
+    {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
+    {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
+]
+
+[[package]]
+name = "cibuildwheel"
+version = "2.21.2"
+requires_python = ">=3.8"
+summary = "Build Python wheels on CI with minimal configuration."
+groups = ["dev"]
+dependencies = [
+    "bashlex!=0.13",
+    "bracex",
+    "certifi",
+    "filelock",
+    "packaging>=20.9",
+    "platformdirs",
+    "tomli; python_version < \"3.11\"",
+    "typing-extensions>=4.1.0; python_version < \"3.11\"",
+]
+files = [
+    {file = "cibuildwheel-2.21.2-py3-none-any.whl", hash = "sha256:60c3bd4e374c459dda09c4be5da5084e86e19310dbd9052f630b76bf3942aabb"},
+    {file = "cibuildwheel-2.21.2.tar.gz", hash = "sha256:57b04c8afe1db6e03e78f9a4af8525410344a65a585a3369755433ce5fbc7754"},
+]
+
 [[package]]
 name = "click"
 version = "8.1.7"
@@ -94,6 +245,46 @@ files = [
     {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
 ]
 
+[[package]]
+name = "cloudpickle"
+version = "3.0.0"
+requires_python = ">=3.8"
+summary = "Pickler class to extend the standard pickle.Pickler functionality"
+groups = ["dev"]
+files = [
+    {file = "cloudpickle-3.0.0-py3-none-any.whl", hash = "sha256:246ee7d0c295602a036e86369c77fecda4ab17b506496730f2f576d9016fd9c7"},
+    {file = "cloudpickle-3.0.0.tar.gz", hash = "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882"},
+]
+
+[[package]]
+name = "cmake"
+version = "3.30.4"
+requires_python = ">=3.7"
+summary = "CMake is an open-source, cross-platform family of tools designed to build, test and package software"
+groups = ["dev"]
+dependencies = [
+    "importlib-metadata>=1.4; python_version < \"3.8\"",
+]
+files = [
+    {file = "cmake-3.30.4-py3-none-macosx_10_10_universal2.whl", hash = "sha256:8a1a30125213c3d44b81a1af0085ad1dcd77abc61bcdf330556e83898428198a"},
+    {file = "cmake-3.30.4-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9f69b3706ae93fa48762871bdc7cb759fbbbadb04452e5eab820537c35fabcb6"},
+    {file = "cmake-3.30.4-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:969af8432a17168e5b88e2efba11e5e14b7ca38aa638975b7ce1b19044c5183f"},
+    {file = "cmake-3.30.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a5929e21af39a3adf4058aea54aa2197198e06315ebad541dda0baf20e2b32b"},
+    {file = "cmake-3.30.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e9808d3744e57c6fd71d93e2ca95142d67578a13a8867f7e8b000f343799899f"},
+    {file = "cmake-3.30.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a223c62cfeebcb7b90f715c16bb2e83ee37e8c3e676efde83b094d62c278ec2"},
+    {file = "cmake-3.30.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08466455fbac67287a4868819ae0e0ab16d60c02eb209ae5e6d70e0e35d0e601"},
+    {file = "cmake-3.30.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8a4b0e638ddbabd16cad8b053b5a66733ddaf652dc3d46d55b3887314022fe"},
+    {file = "cmake-3.30.4-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:a8f3160cc2b362c0ba03d70300a36bca5a58e1f82c345f4f54a4da7f59b7b2b4"},
+    {file = "cmake-3.30.4-py3-none-musllinux_1_1_i686.whl", hash = "sha256:13bd1afa2e9988973f18c2425823081a044929e80685731601f093ff673d2db7"},
+    {file = "cmake-3.30.4-py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:d2ab1018a42e03cf2e843f9565bc2ff7465a1a66c1cbfaba30d494a5e26f763e"},
+    {file = "cmake-3.30.4-py3-none-musllinux_1_1_s390x.whl", hash = "sha256:2d6367a438c11f0863c9cdea843acd09514e94534ce0d115bc8f7905aaff243d"},
+    {file = "cmake-3.30.4-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:e4cc37735bdc7ba058abdddd3f94ac9dc32cae0f94ae68661565b39f64a9a22f"},
+    {file = "cmake-3.30.4-py3-none-win32.whl", hash = "sha256:a08e9a987be5da69941f4a26dd7614fcbb5039394821fbcce9716c20a1571c0c"},
+    {file = "cmake-3.30.4-py3-none-win_amd64.whl", hash = "sha256:2d128d0831924788c1e87d6ca9abe4594e2ccde718712b0fa2c8c3a99b0d1282"},
+    {file = "cmake-3.30.4-py3-none-win_arm64.whl", hash = "sha256:2825874fb84bd9d05c40b1a4347366d9949c9f6bac7a9ace97ac7faf9d573b8b"},
+    {file = "cmake-3.30.4.tar.gz", hash = "sha256:fedd88495e742a1316078c283c2b4c2eeac4c34eca3234401d28f09ee58a320f"},
+]
+
 [[package]]
 name = "colorama"
 version = "0.4.6"
@@ -106,6 +297,20 @@ files = [
     {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
 ]
 
+[[package]]
+name = "comm"
+version = "0.2.2"
+requires_python = ">=3.8"
+summary = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc."
+groups = ["dev"]
+dependencies = [
+    "traitlets>=4",
+]
+files = [
+    {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"},
+    {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"},
+]
+
 [[package]]
 name = "coverage"
 version = "7.0.5"
@@ -133,16 +338,6 @@ files = [
     {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:411d4ff9d041be08fdfc02adf62e89c735b9468f6d8f6427f8a14b6bb0a85095"},
     {file = "coverage-7.0.5-cp311-cp311-win32.whl", hash = "sha256:52ab14b9e09ce052237dfe12d6892dd39b0401690856bcfe75d5baba4bfe2831"},
     {file = "coverage-7.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:1f66862d3a41674ebd8d1a7b6f5387fe5ce353f8719040a986551a545d7d83ea"},
-    {file = "coverage-7.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:790e4433962c9f454e213b21b0fd4b42310ade9c077e8edcb5113db0818450cb"},
-    {file = "coverage-7.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:49640bda9bda35b057b0e65b7c43ba706fa2335c9a9896652aebe0fa399e80e6"},
-    {file = "coverage-7.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d66187792bfe56f8c18ba986a0e4ae44856b1c645336bd2c776e3386da91e1dd"},
-    {file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:276f4cd0001cd83b00817c8db76730938b1ee40f4993b6a905f40a7278103b3a"},
-    {file = "coverage-7.0.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95304068686545aa368b35dfda1cdfbbdbe2f6fe43de4a2e9baa8ebd71be46e2"},
-    {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:17e01dd8666c445025c29684d4aabf5a90dc6ef1ab25328aa52bedaa95b65ad7"},
-    {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea76dbcad0b7b0deb265d8c36e0801abcddf6cc1395940a24e3595288b405ca0"},
-    {file = "coverage-7.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:50a6adc2be8edd7ee67d1abc3cd20678987c7b9d79cd265de55941e3d0d56499"},
-    {file = "coverage-7.0.5-cp38-cp38-win32.whl", hash = "sha256:e4ce984133b888cc3a46867c8b4372c7dee9cee300335e2925e197bcd45b9e16"},
-    {file = "coverage-7.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:4a950f83fd3f9bca23b77442f3a2b2ea4ac900944d8af9993743774c4fdc57af"},
     {file = "coverage-7.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c2155943896ac78b9b0fd910fb381186d0c345911f5333ee46ac44c8f0e43ab"},
     {file = "coverage-7.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54f7e9705e14b2c9f6abdeb127c390f679f6dbe64ba732788d3015f7f76ef637"},
     {file = "coverage-7.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee30375b409d9a7ea0f30c50645d436b6f5dfee254edffd27e45a980ad2c7f4"},
@@ -157,6 +352,280 @@ files = [
     {file = "coverage-7.0.5.tar.gz", hash = "sha256:051afcbd6d2ac39298d62d340f94dbb6a1f31de06dfaf6fcef7b759dd3860c45"},
 ]
 
+[[package]]
+name = "coverage"
+version = "7.0.5"
+extras = ["toml"]
+requires_python = ">=3.7"
+summary = "Code coverage measurement for Python"
+groups = ["dev"]
+dependencies = [
+    "coverage==7.0.5",
+    "tomli; python_full_version <= \"3.11.0a6\"",
+]
+files = [
+    {file = "coverage-7.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2a7f23bbaeb2a87f90f607730b45564076d870f1fb07b9318d0c21f36871932b"},
+    {file = "coverage-7.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c18d47f314b950dbf24a41787ced1474e01ca816011925976d90a88b27c22b89"},
+    {file = "coverage-7.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef14d75d86f104f03dea66c13188487151760ef25dd6b2dbd541885185f05f40"},
+    {file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66e50680e888840c0995f2ad766e726ce71ca682e3c5f4eee82272c7671d38a2"},
+    {file = "coverage-7.0.5-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9fed35ca8c6e946e877893bbac022e8563b94404a605af1d1e6accc7eb73289"},
+    {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d8d04e755934195bdc1db45ba9e040b8d20d046d04d6d77e71b3b34a8cc002d0"},
+    {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e109f1c9a3ece676597831874126555997c48f62bddbcace6ed17be3e372de8"},
+    {file = "coverage-7.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0a1890fca2962c4f1ad16551d660b46ea77291fba2cc21c024cd527b9d9c8809"},
+    {file = "coverage-7.0.5-cp310-cp310-win32.whl", hash = "sha256:be9fcf32c010da0ba40bf4ee01889d6c737658f4ddff160bd7eb9cac8f094b21"},
+    {file = "coverage-7.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:cbfcba14a3225b055a28b3199c3d81cd0ab37d2353ffd7f6fd64844cebab31ad"},
+    {file = "coverage-7.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:30b5fec1d34cc932c1bc04017b538ce16bf84e239378b8f75220478645d11fca"},
+    {file = "coverage-7.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1caed2367b32cc80a2b7f58a9f46658218a19c6cfe5bc234021966dc3daa01f0"},
+    {file = "coverage-7.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d254666d29540a72d17cc0175746cfb03d5123db33e67d1020e42dae611dc196"},
+    {file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19245c249aa711d954623d94f23cc94c0fd65865661f20b7781210cb97c471c0"},
+    {file = "coverage-7.0.5-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b05ed4b35bf6ee790832f68932baf1f00caa32283d66cc4d455c9e9d115aafc"},
+    {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:29de916ba1099ba2aab76aca101580006adfac5646de9b7c010a0f13867cba45"},
+    {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e057e74e53db78122a3979f908973e171909a58ac20df05c33998d52e6d35757"},
+    {file = "coverage-7.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:411d4ff9d041be08fdfc02adf62e89c735b9468f6d8f6427f8a14b6bb0a85095"},
+    {file = "coverage-7.0.5-cp311-cp311-win32.whl", hash = "sha256:52ab14b9e09ce052237dfe12d6892dd39b0401690856bcfe75d5baba4bfe2831"},
+    {file = "coverage-7.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:1f66862d3a41674ebd8d1a7b6f5387fe5ce353f8719040a986551a545d7d83ea"},
+    {file = "coverage-7.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c2155943896ac78b9b0fd910fb381186d0c345911f5333ee46ac44c8f0e43ab"},
+    {file = "coverage-7.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:54f7e9705e14b2c9f6abdeb127c390f679f6dbe64ba732788d3015f7f76ef637"},
+    {file = "coverage-7.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ee30375b409d9a7ea0f30c50645d436b6f5dfee254edffd27e45a980ad2c7f4"},
+    {file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b78729038abea6a5df0d2708dce21e82073463b2d79d10884d7d591e0f385ded"},
+    {file = "coverage-7.0.5-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13250b1f0bd023e0c9f11838bdeb60214dd5b6aaf8e8d2f110c7e232a1bff83b"},
+    {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2c407b1950b2d2ffa091f4e225ca19a66a9bd81222f27c56bd12658fc5ca1209"},
+    {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c76a3075e96b9c9ff00df8b5f7f560f5634dffd1658bafb79eb2682867e94f78"},
+    {file = "coverage-7.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f26648e1b3b03b6022b48a9b910d0ae209e2d51f50441db5dce5b530fad6d9b1"},
+    {file = "coverage-7.0.5-cp39-cp39-win32.whl", hash = "sha256:ba3027deb7abf02859aca49c865ece538aee56dcb4871b4cced23ba4d5088904"},
+    {file = "coverage-7.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:949844af60ee96a376aac1ded2a27e134b8c8d35cc006a52903fc06c24a3296f"},
+    {file = "coverage-7.0.5-pp37.pp38.pp39-none-any.whl", hash = "sha256:b9727ac4f5cf2cbf87880a63870b5b9730a8ae3a4a360241a0fdaa2f71240ff0"},
+    {file = "coverage-7.0.5.tar.gz", hash = "sha256:051afcbd6d2ac39298d62d340f94dbb6a1f31de06dfaf6fcef7b759dd3860c45"},
+]
+
+[[package]]
+name = "cython"
+version = "3.0.11"
+requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
+summary = "The Cython compiler for writing C extensions in the Python language."
+groups = ["dev"]
+files = [
+    {file = "Cython-3.0.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:44292aae17524abb4b70a25111fe7dec1a0ad718711d47e3786a211d5408fdaa"},
+    {file = "Cython-3.0.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a75d45fbc20651c1b72e4111149fed3b33d270b0a4fb78328c54d965f28d55e1"},
+    {file = "Cython-3.0.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d89a82937ce4037f092e9848a7bbcc65bc8e9fc9aef2bb74f5c15e7d21a73080"},
+    {file = "Cython-3.0.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a8ea2e7e2d3bc0d8630dafe6c4a5a89485598ff8a61885b74f8ed882597efd5"},
+    {file = "Cython-3.0.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cee29846471ce60226b18e931d8c1c66a158db94853e3e79bc2da9bd22345008"},
+    {file = "Cython-3.0.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eeb6860b0f4bfa402de8929833fe5370fa34069c7ebacb2d543cb017f21fb891"},
+    {file = "Cython-3.0.11-cp310-cp310-win32.whl", hash = "sha256:3699391125ab344d8d25438074d1097d9ba0fb674d0320599316cfe7cf5f002a"},
+    {file = "Cython-3.0.11-cp310-cp310-win_amd64.whl", hash = "sha256:d02f4ebe15aac7cdacce1a628e556c1983f26d140fd2e0ac5e0a090e605a2d38"},
+    {file = "Cython-3.0.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75ba1c70b6deeaffbac123856b8d35f253da13552207aa969078611c197377e4"},
+    {file = "Cython-3.0.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af91497dc098718e634d6ec8f91b182aea6bb3690f333fc9a7777bc70abe8810"},
+    {file = "Cython-3.0.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3999fb52d3328a6a5e8c63122b0a8bd110dfcdb98dda585a3def1426b991cba7"},
+    {file = "Cython-3.0.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d566a4e09b8979be8ab9f843bac0dd216c81f5e5f45661a9b25cd162ed80508c"},
+    {file = "Cython-3.0.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:46aec30f217bdf096175a1a639203d44ac73a36fe7fa3dd06bd012e8f39eca0f"},
+    {file = "Cython-3.0.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ddd1fe25af330f4e003421636746a546474e4ccd8f239f55d2898d80983d20ed"},
+    {file = "Cython-3.0.11-cp311-cp311-win32.whl", hash = "sha256:221de0b48bf387f209003508e602ce839a80463522fc6f583ad3c8d5c890d2c1"},
+    {file = "Cython-3.0.11-cp311-cp311-win_amd64.whl", hash = "sha256:3ff8ac1f0ecd4f505db4ab051e58e4531f5d098b6ac03b91c3b902e8d10c67b3"},
+    {file = "Cython-3.0.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:11996c40c32abf843ba652a6d53cb15944c88d91f91fc4e6f0028f5df8a8f8a1"},
+    {file = "Cython-3.0.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63f2c892e9f9c1698ecfee78205541623eb31cd3a1b682668be7ac12de94aa8e"},
+    {file = "Cython-3.0.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b14c24f1dc4c4c9d997cca8d1b7fb01187a218aab932328247dcf5694a10102"},
+    {file = "Cython-3.0.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8eed5c015685106db15dd103fd040948ddca9197b1dd02222711815ea782a27"},
+    {file = "Cython-3.0.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780f89c95b8aec1e403005b3bf2f0a2afa060b3eba168c86830f079339adad89"},
+    {file = "Cython-3.0.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a690f2ff460682ea985e8d38ec541be97e0977fa0544aadc21efc116ff8d7579"},
+    {file = "Cython-3.0.11-cp312-cp312-win32.whl", hash = "sha256:2252b5aa57621848e310fe7fa6f7dce5f73aa452884a183d201a8bcebfa05a00"},
+    {file = "Cython-3.0.11-cp312-cp312-win_amd64.whl", hash = "sha256:da394654c6da15c1d37f0b7ec5afd325c69a15ceafee2afba14b67a5df8a82c8"},
+    {file = "Cython-3.0.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4341d6a64d47112884e0bcf31e6c075268220ee4cd02223047182d4dda94d637"},
+    {file = "Cython-3.0.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:351955559b37e6c98b48aecb178894c311be9d731b297782f2b78d111f0c9015"},
+    {file = "Cython-3.0.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c02361af9bfa10ff1ccf967fc75159e56b1c8093caf565739ed77a559c1f29f"},
+    {file = "Cython-3.0.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6823aef13669a32caf18bbb036de56065c485d9f558551a9b55061acf9c4c27f"},
+    {file = "Cython-3.0.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6fb68cef33684f8cc97987bee6ae919eee7e18ee6a3ad7ed9516b8386ef95ae6"},
+    {file = "Cython-3.0.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:790263b74432cb997740d73665f4d8d00b9cd1cecbdd981d93591ddf993d4f12"},
+    {file = "Cython-3.0.11-cp313-cp313-win32.whl", hash = "sha256:e6dd395d1a704e34a9fac00b25f0036dce6654c6b898be6f872ac2bb4f2eda48"},
+    {file = "Cython-3.0.11-cp313-cp313-win_amd64.whl", hash = "sha256:52186101d51497519e99b60d955fd5cb3bf747c67f00d742e70ab913f1e42d31"},
+    {file = "Cython-3.0.11-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0fc6fdd6fa493be7bdda22355689d5446ac944cd71286f6f44a14b0d67ee3ff5"},
+    {file = "Cython-3.0.11-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b1d1f6f94cc5d42a4591f6d60d616786b9cd15576b112bc92a23131fcf38020"},
+    {file = "Cython-3.0.11-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4ab2b92a3e6ed552adbe9350fd2ef3aa0cc7853cf91569f9dbed0c0699bbeab"},
+    {file = "Cython-3.0.11-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:104d6f2f2c827ccc5e9e42c80ef6773a6aa94752fe6bc5b24a4eab4306fb7f07"},
+    {file = "Cython-3.0.11-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:13062ce556a1e98d2821f7a0253b50569fdc98c36efd6653a65b21e3f8bbbf5f"},
+    {file = "Cython-3.0.11-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:525d09b3405534763fa73bd78c8e51ac8264036ce4c16d37dfd1555a7da6d3a7"},
+    {file = "Cython-3.0.11-cp39-cp39-win32.whl", hash = "sha256:b8c7e514075696ca0f60c337f9e416e61d7ccbc1aa879a56c39181ed90ec3059"},
+    {file = "Cython-3.0.11-cp39-cp39-win_amd64.whl", hash = "sha256:8948802e1f5677a673ea5d22a1e7e273ca5f83e7a452786ca286eebf97cee67c"},
+    {file = "Cython-3.0.11-py2.py3-none-any.whl", hash = "sha256:0e25f6425ad4a700d7f77cd468da9161e63658837d1bc34861a9861a4ef6346d"},
+    {file = "cython-3.0.11.tar.gz", hash = "sha256:7146dd2af8682b4ca61331851e6aebce9fe5158e75300343f80c07ca80b1faff"},
+]
+
+[[package]]
+name = "debugpy"
+version = "1.8.5"
+requires_python = ">=3.8"
+summary = "An implementation of the Debug Adapter Protocol for Python"
+groups = ["dev"]
+files = [
+    {file = "debugpy-1.8.5-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:7e4d594367d6407a120b76bdaa03886e9eb652c05ba7f87e37418426ad2079f7"},
+    {file = "debugpy-1.8.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4413b7a3ede757dc33a273a17d685ea2b0c09dbd312cc03f5534a0fd4d40750a"},
+    {file = "debugpy-1.8.5-cp310-cp310-win32.whl", hash = "sha256:dd3811bd63632bb25eda6bd73bea8e0521794cda02be41fa3160eb26fc29e7ed"},
+    {file = "debugpy-1.8.5-cp310-cp310-win_amd64.whl", hash = "sha256:b78c1250441ce893cb5035dd6f5fc12db968cc07f91cc06996b2087f7cefdd8e"},
+    {file = "debugpy-1.8.5-cp311-cp311-macosx_12_0_universal2.whl", hash = "sha256:606bccba19f7188b6ea9579c8a4f5a5364ecd0bf5a0659c8a5d0e10dcee3032a"},
+    {file = "debugpy-1.8.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db9fb642938a7a609a6c865c32ecd0d795d56c1aaa7a7a5722d77855d5e77f2b"},
+    {file = "debugpy-1.8.5-cp311-cp311-win32.whl", hash = "sha256:4fbb3b39ae1aa3e5ad578f37a48a7a303dad9a3d018d369bc9ec629c1cfa7408"},
+    {file = "debugpy-1.8.5-cp311-cp311-win_amd64.whl", hash = "sha256:345d6a0206e81eb68b1493ce2fbffd57c3088e2ce4b46592077a943d2b968ca3"},
+    {file = "debugpy-1.8.5-cp312-cp312-macosx_12_0_universal2.whl", hash = "sha256:5b5c770977c8ec6c40c60d6f58cacc7f7fe5a45960363d6974ddb9b62dbee156"},
+    {file = "debugpy-1.8.5-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0a65b00b7cdd2ee0c2cf4c7335fef31e15f1b7056c7fdbce9e90193e1a8c8cb"},
+    {file = "debugpy-1.8.5-cp312-cp312-win32.whl", hash = "sha256:c9f7c15ea1da18d2fcc2709e9f3d6de98b69a5b0fff1807fb80bc55f906691f7"},
+    {file = "debugpy-1.8.5-cp312-cp312-win_amd64.whl", hash = "sha256:28ced650c974aaf179231668a293ecd5c63c0a671ae6d56b8795ecc5d2f48d3c"},
+    {file = "debugpy-1.8.5-cp39-cp39-macosx_12_0_x86_64.whl", hash = "sha256:0a1029a2869d01cb777216af8c53cda0476875ef02a2b6ff8b2f2c9a4b04176c"},
+    {file = "debugpy-1.8.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84c276489e141ed0b93b0af648eef891546143d6a48f610945416453a8ad406"},
+    {file = "debugpy-1.8.5-cp39-cp39-win32.whl", hash = "sha256:ad84b7cde7fd96cf6eea34ff6c4a1b7887e0fe2ea46e099e53234856f9d99a34"},
+    {file = "debugpy-1.8.5-cp39-cp39-win_amd64.whl", hash = "sha256:7b0fe36ed9d26cb6836b0a51453653f8f2e347ba7348f2bbfe76bfeb670bfb1c"},
+    {file = "debugpy-1.8.5-py2.py3-none-any.whl", hash = "sha256:55919dce65b471eff25901acf82d328bbd5b833526b6c1364bd5133754777a44"},
+    {file = "debugpy-1.8.5.zip", hash = "sha256:b2112cfeb34b4507399d298fe7023a16656fc553ed5246536060ca7bd0e668d0"},
+]
+
+[[package]]
+name = "decorator"
+version = "5.1.1"
+requires_python = ">=3.5"
+summary = "Decorators for Humans"
+groups = ["dev"]
+files = [
+    {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
+    {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
+]
+
+[[package]]
+name = "devtools"
+version = "0.12.2"
+requires_python = ">=3.7"
+summary = "Python's missing debug print command, and more."
+groups = ["dev"]
+dependencies = [
+    "asttokens<3.0.0,>=2.0.0",
+    "executing>=1.1.1",
+    "pygments>=2.15.0",
+]
+files = [
+    {file = "devtools-0.12.2-py3-none-any.whl", hash = "sha256:c366e3de1df4cdd635f1ad8cbcd3af01a384d7abda71900e68d43b04eb6aaca7"},
+    {file = "devtools-0.12.2.tar.gz", hash = "sha256:efceab184cb35e3a11fa8e602cc4fadacaa2e859e920fc6f87bf130b69885507"},
+]
+
+[[package]]
+name = "distro"
+version = "1.9.0"
+requires_python = ">=3.6"
+summary = "Distro - an OS platform information API"
+groups = ["dev"]
+files = [
+    {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"},
+    {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"},
+]
+
+[[package]]
+name = "elaina-flywheel"
+version = "0.6.0"
+requires_python = ">=3.9"
+summary = ""
+groups = ["default"]
+dependencies = [
+    "typing-extensions>=4.10.0",
+]
+files = [
+    {file = "elaina_flywheel-0.6.0-py3-none-any.whl", hash = "sha256:d01ff36ba61308c21ff239a709fbaa28288f073a7c8dfe0d993a74193ce48e23"},
+    {file = "elaina_flywheel-0.6.0.tar.gz", hash = "sha256:dbc072ad7eeb250df35c638e5365de037f134965bbe374bbeefbc53f18b5c55a"},
+]
+
+[[package]]
+name = "elaina-segment"
+version = "0.4.0"
+requires_python = ">=3.9"
+summary = "Default template for PDM package"
+groups = ["default"]
+files = [
+    {file = "elaina_segment-0.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06dc2928c68a8de9e829a367e84fbfcd2a2d510cf4e1655e5ba8d03e415dabeb"},
+    {file = "elaina_segment-0.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:55f2282f79919bed01ec2d30be30023482d741a645c95c5739017cd6849f7300"},
+    {file = "elaina_segment-0.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b77097199bb97e5497063a9e89ac3180b71d52cb58253441d027ec131c6d1ced"},
+    {file = "elaina_segment-0.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:06b266b5e1d97a7c52689fc67a149553fe67976c2e62f7598141062f56e3ecc7"},
+    {file = "elaina_segment-0.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:108e4ee5a54610eac341f035f61130140733b086c1f2cd4f09892033a6179bf9"},
+    {file = "elaina_segment-0.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bafef61c1f281e952180f5a67ff236685091eb5e4d7f7ccac5b3b51986c2cc7b"},
+    {file = "elaina_segment-0.4.0-cp310-cp310-win32.whl", hash = "sha256:25f6d74f4786f2324122ad7fa70a04ec2175de4955041078f64bcbe6f6507fa0"},
+    {file = "elaina_segment-0.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:3a02e90676c8b6fa117f52aa0c08574d82296dfd241732ab2095be30b434d0e5"},
+    {file = "elaina_segment-0.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7de558fff394a0f0b5977615d403448e946c34f32db11566c9c2b2c2d351fcb7"},
+    {file = "elaina_segment-0.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:921979113cd97ace662a7273498c3ffa945d5f3f30a67e47bbfd1fafa5473215"},
+    {file = "elaina_segment-0.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad163a2259325a6f33d3d001d19e77ea317b5dc80f92fee67c5073bc3b4b0b40"},
+    {file = "elaina_segment-0.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4fb3eab83e72c1d8fc91926abf9de5a1283c1e85b12503763c15c1ca7dcf7db"},
+    {file = "elaina_segment-0.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a67987b90ae2171752ac32d9d5dd700e2937007616b90b3a9522b6f78e37c4b5"},
+    {file = "elaina_segment-0.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a091f1aecd45fac12d72d23a3f935b7bb22fb7e688a77e7eed499904430b46ad"},
+    {file = "elaina_segment-0.4.0-cp311-cp311-win32.whl", hash = "sha256:e8db8ca0387f5429600dbbfbdcb7b791fbd21e3cb60d835b6645a90e2ffe98f8"},
+    {file = "elaina_segment-0.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:7bacb1f41c3adda71043a158fa31b16d454b90cec5c168b5d32117beeb1df5ef"},
+    {file = "elaina_segment-0.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0436e858ad3aedf3699bada99b04936d7a4347fe30f271b1840051f92691f118"},
+    {file = "elaina_segment-0.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1b24d1c4f9da9bac6377645538388900750f6c57ea3550c3876b065c31512c2"},
+    {file = "elaina_segment-0.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a92b5ba1990183c7ec8e41dd96e4833ed2b9d38890f453b594b3fa53be4723c9"},
+    {file = "elaina_segment-0.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84b6518582796f1d663ac9ef301a7cda0d6f00454b9a828503408cfae49268be"},
+    {file = "elaina_segment-0.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:959805562561f2cfec95f7006ec7628e74a4fe18619da31796e996ddd70f81f2"},
+    {file = "elaina_segment-0.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a3bde1ccefcaf8dce68101c02f7953913c34afb8d994134ac619070dc4e1027d"},
+    {file = "elaina_segment-0.4.0-cp312-cp312-win32.whl", hash = "sha256:b70d87555089c30cb47bcebb9031a58ec865bb8ddfe24c8976236d6ea63965f0"},
+    {file = "elaina_segment-0.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:22cec03f9b8903a4f18e69254d08f6be122a34b5e3dce0d1bdb03978a3da54f6"},
+    {file = "elaina_segment-0.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:23e863f66d0b9840962cf5280e9cd76039b3a01e91c5e08449d3ac94e18bb98c"},
+    {file = "elaina_segment-0.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4753fa111130488df2efd13b95cbd2a78cf1b7d8ddafd4237aca119bffb461f8"},
+    {file = "elaina_segment-0.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37e33e1a142b9c9a6ad117b64157ef090a7418ba4114bf9b573c6e03926ef524"},
+    {file = "elaina_segment-0.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3a0fc9efc50ec01f9b6393595c5b53c6f1362223c15ea3a0ce7ce96e5494e8c7"},
+    {file = "elaina_segment-0.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b67118291a6c8a99d4cabf6f7962de66599e0102df7c1fc2a5cef3a61d98ab30"},
+    {file = "elaina_segment-0.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ec3b3431e59101558dbf07a369e8e4c4d50ed478f95af9ab82438324f3322af4"},
+    {file = "elaina_segment-0.4.0-cp313-cp313-win32.whl", hash = "sha256:652b02e5033c51e50f866a0b9777f41dba4cfa0aedec2d0965f96f52d89f1c58"},
+    {file = "elaina_segment-0.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:17ea773ba1e34e9c52fc09cb2d99460b4a2d2c9068cee273e0a110e4caa931d3"},
+    {file = "elaina_segment-0.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a58680070d3d6872a5831c138f06a5384418b9f0bce5177933c1c4f97adef4a2"},
+    {file = "elaina_segment-0.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bbd4dfba5d539aa9d855b4fca824b4415b2d64fb80e95a13f487005ff262998b"},
+    {file = "elaina_segment-0.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfb97d9fd2f74c0bec4b7f72412eefe1d3429b3b1192d574eefcc5ec17fed2e6"},
+    {file = "elaina_segment-0.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8192df9b47ed13174f844e54e0929d2cf69e7e33e09bd3ec17a97a6c75c76c23"},
+    {file = "elaina_segment-0.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:79141efc042942115db562b1603d1bb8bbaaf8ed8769787398d9be9d225bb485"},
+    {file = "elaina_segment-0.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f1c99b89a62a8d546584eb0943e112870b6e6ae9ecd919be2c31a1fca0184c90"},
+    {file = "elaina_segment-0.4.0-cp39-cp39-win32.whl", hash = "sha256:001c21f189e32a0443b4cc43b0acb916ee98c772516cbc5b310f7ccf7d6467d1"},
+    {file = "elaina_segment-0.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:965d4e7eb12fd35576a1c4324eb4e0203074885c3779d619015e202be856f54a"},
+]
+
+[[package]]
+name = "elaina-triehard"
+version = "0.2.0"
+requires_python = ">=3.9"
+summary = "Default template for PDM package"
+groups = ["default"]
+files = [
+    {file = "elaina_triehard-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e51685c8bb1e8ffb8986b0d38bc6c0b26e51c9ddfddfb29aa33e8219616e4303"},
+    {file = "elaina_triehard-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:35d27857d43f8f53720f52d7890d5625bc129eeb171f0adb746835bd2175c5ed"},
+    {file = "elaina_triehard-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:820ce95710abafc4afe27b183c41a217683d157a9c41daecdc8def79abe19238"},
+    {file = "elaina_triehard-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf4a762578f66572aab32ade0c25a43502559a9840047f7b7cd59ad91209ff1f"},
+    {file = "elaina_triehard-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:10071f04f6a7416f9fe28d82af33e56103ab3de4dbf142b60cf424aac0626180"},
+    {file = "elaina_triehard-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:120f7d361cf71b735830e26954c087ad545a58057dd91ea174dbd38f609ecabf"},
+    {file = "elaina_triehard-0.2.0-cp310-cp310-win32.whl", hash = "sha256:1ab5f371d947658e4a0a9f64dc2feb255a8da16c893646c6413df9d68b678221"},
+    {file = "elaina_triehard-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:af6857ed442294bcb5e0864fc4abb98ad06358c819773fe50f489434234e7e5d"},
+    {file = "elaina_triehard-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:77486ea0d4935ce716060bb4bb78f653ed0fa3ce5a78eda9ed08439fb80b85a2"},
+    {file = "elaina_triehard-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:844d9a853f4f840e81f29aad89665712c9de5d420583797ae978b7ad6b5934e4"},
+    {file = "elaina_triehard-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a309fff1fa277f536fd80adf7eab5d6a48c4863435e9310565cae3ce6b5cdfc2"},
+    {file = "elaina_triehard-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:390e2407148e8525f11f505b0ab3989e24fdd35b33d3fa068a77dcb74366eb82"},
+    {file = "elaina_triehard-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:536be1f72d30b689874395084e8feb1b13b66233d021f7941d902f08d0f89d96"},
+    {file = "elaina_triehard-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:316c9fb0cae47cc92c43edd0be6421d560bcb0ac07854a96c2f85c4ef5d0f8c1"},
+    {file = "elaina_triehard-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5d07e9da55143e3ba69e0203f69d7f93e59614c62e0a165d140ce19f4ecb1298"},
+    {file = "elaina_triehard-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:18ec3d86915a904dfe18f613b0accc0b6e87e1e93ad785cc729b9c2f4589209e"},
+    {file = "elaina_triehard-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3af8813d6f98c6189bbd7d895f53caa7fa4df8977d7ec1584838dc92dff0cc9b"},
+    {file = "elaina_triehard-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05e0ef1a93691da19b8b3e49a4a283365b91cdf9961980f77d9fcef02bf4344a"},
+    {file = "elaina_triehard-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a68260a6d7905ff47cf534f615a17ef5267013c0deb6f1b7faf5f8869fe691b"},
+    {file = "elaina_triehard-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fab994d45f2f3039921b40fa5f797478770f252d563247e4eb7b0f1a9c1f63b1"},
+    {file = "elaina_triehard-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7921e173a1ab1c792011d755f6284894e714356b2ead5b597b94760c7dd13686"},
+    {file = "elaina_triehard-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c08ea3653c53d729e28c12868bed46cbfd4a2577241c8802554597de3be2ff"},
+    {file = "elaina_triehard-0.2.0-cp312-cp312-win32.whl", hash = "sha256:6decc5b98bbbb48f3ee4ea7567de9515a0db5c670fedd7abedacd9664d0ac1fd"},
+    {file = "elaina_triehard-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:1aaf56a2867a5e8d7dcb253255068af97096df4e3f4286b6ab1cdf70d01375f7"},
+    {file = "elaina_triehard-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fe51ae0b5508c8686d8a236631a3f51e50e9e9e23ce61ab287315df39b022c72"},
+    {file = "elaina_triehard-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:80a0d2372eb7e7a7aa8b362f7ee13208d137c26481149ef8c6754efcab79b04e"},
+    {file = "elaina_triehard-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0aec018e0925039bf6009513ecd480fcd44a58627ae9c2f6381e39fddcf894a7"},
+    {file = "elaina_triehard-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8f582acdc8f3e7527f588d359ce81ec8cb036ed33684e5c9a6624c30659677f"},
+    {file = "elaina_triehard-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d1860a7ca58ba5e1a46f581a4d71d0b494fa6a6ee1c6b9bbca2d4a2beb5e8300"},
+    {file = "elaina_triehard-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ff0db00616d263eb9b2ba92f51b87c9d64a2f1a7d7213e98db90bdfcb8a8ae7e"},
+    {file = "elaina_triehard-0.2.0-cp313-cp313-win32.whl", hash = "sha256:3e0b9d03f6a7c4489ded108e7406eefaf6175e6a3e550dc341771a5e5d2fde48"},
+    {file = "elaina_triehard-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:6dddea4514979c93ba8d0d84498371523a331e45e3ce3670ba07368e5af87f71"},
+    {file = "elaina_triehard-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:74c00028847906e9eda6c61929e856b284fa9b968e4ee570940e021c21efc05e"},
+    {file = "elaina_triehard-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e01a4e3be15bb553a4cd02b254f7aac365644486ada425f0ad056cafed91b67f"},
+    {file = "elaina_triehard-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab024b820e8796bdea26691508bfba0b93f2ea692539dae5a824ba47c842e82a"},
+    {file = "elaina_triehard-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05c7822b11c5c5cfecad45f6b6385b767419b0cc7bfff7b19de6847f5b54eaaf"},
+    {file = "elaina_triehard-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4b54e19c4c4f9f97dc4c6d27967455be0432c4eec760d5050edfaadfef3e8a59"},
+    {file = "elaina_triehard-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9681395894e36e8c6d6f4db5c01abb1bb25945504ae09c45999fb2dc885383d1"},
+    {file = "elaina_triehard-0.2.0-cp39-cp39-win32.whl", hash = "sha256:7e5ef229cd7931909238664a0ebd498debd8c5bb00f23b01c3d7afd3e4d4b0c1"},
+    {file = "elaina_triehard-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:2912b47a395190851191572eafd339ee62497cac862723648cbcdf6cd6e86fef"},
+]
+
 [[package]]
 name = "exceptiongroup"
 version = "1.2.0"
@@ -169,6 +638,28 @@ files = [
     {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"},
 ]
 
+[[package]]
+name = "executing"
+version = "2.1.0"
+requires_python = ">=3.8"
+summary = "Get the currently executing AST node of a frame, and other information"
+groups = ["dev"]
+files = [
+    {file = "executing-2.1.0-py2.py3-none-any.whl", hash = "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf"},
+    {file = "executing-2.1.0.tar.gz", hash = "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab"},
+]
+
+[[package]]
+name = "filelock"
+version = "3.16.1"
+requires_python = ">=3.8"
+summary = "A platform independent file lock."
+groups = ["dev"]
+files = [
+    {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"},
+    {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"},
+]
+
 [[package]]
 name = "fix-future-annotations"
 version = "0.5.0"
@@ -184,6 +675,22 @@ files = [
     {file = "fix_future_annotations-0.5.0-py3-none-any.whl", hash = "sha256:45b5e73b36c514a23c2fbb2b7ff26448496399bda3b98a7b78a14439639f2e59"},
 ]
 
+[[package]]
+name = "importlib-metadata"
+version = "8.5.0"
+requires_python = ">=3.8"
+summary = "Read metadata from Python packages"
+groups = ["dev"]
+marker = "python_version < \"3.10\""
+dependencies = [
+    "typing-extensions>=3.6.4; python_version < \"3.8\"",
+    "zipp>=3.20",
+]
+files = [
+    {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"},
+    {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"},
+]
+
 [[package]]
 name = "iniconfig"
 version = "2.0.0"
@@ -195,6 +702,56 @@ files = [
     {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
 ]
 
+[[package]]
+name = "ipykernel"
+version = "6.29.5"
+requires_python = ">=3.8"
+summary = "IPython Kernel for Jupyter"
+groups = ["dev"]
+dependencies = [
+    "appnope; platform_system == \"Darwin\"",
+    "comm>=0.1.1",
+    "debugpy>=1.6.5",
+    "ipython>=7.23.1",
+    "jupyter-client>=6.1.12",
+    "jupyter-core!=5.0.*,>=4.12",
+    "matplotlib-inline>=0.1",
+    "nest-asyncio",
+    "packaging",
+    "psutil",
+    "pyzmq>=24",
+    "tornado>=6.1",
+    "traitlets>=5.4.0",
+]
+files = [
+    {file = "ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5"},
+    {file = "ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215"},
+]
+
+[[package]]
+name = "ipython"
+version = "8.18.1"
+requires_python = ">=3.9"
+summary = "IPython: Productive Interactive Computing"
+groups = ["dev"]
+dependencies = [
+    "colorama; sys_platform == \"win32\"",
+    "decorator",
+    "exceptiongroup; python_version < \"3.11\"",
+    "jedi>=0.16",
+    "matplotlib-inline",
+    "pexpect>4.3; sys_platform != \"win32\"",
+    "prompt-toolkit<3.1.0,>=3.0.41",
+    "pygments>=2.4.0",
+    "stack-data",
+    "traitlets>=5",
+    "typing-extensions; python_version < \"3.10\"",
+]
+files = [
+    {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"},
+    {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"},
+]
+
 [[package]]
 name = "isort"
 version = "5.13.2"
@@ -206,6 +763,328 @@ files = [
     {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
 ]
 
+[[package]]
+name = "jedi"
+version = "0.19.1"
+requires_python = ">=3.6"
+summary = "An autocompletion tool for Python that can be used for text editors."
+groups = ["dev"]
+dependencies = [
+    "parso<0.9.0,>=0.8.3",
+]
+files = [
+    {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"},
+    {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"},
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.4"
+requires_python = ">=3.7"
+summary = "A very fast and expressive template engine."
+groups = ["dev"]
+dependencies = [
+    "MarkupSafe>=2.0",
+]
+files = [
+    {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
+    {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
+]
+
+[[package]]
+name = "jupyter-client"
+version = "8.6.3"
+requires_python = ">=3.8"
+summary = "Jupyter protocol implementation and client libraries"
+groups = ["dev"]
+dependencies = [
+    "importlib-metadata>=4.8.3; python_version < \"3.10\"",
+    "jupyter-core!=5.0.*,>=4.12",
+    "python-dateutil>=2.8.2",
+    "pyzmq>=23.0",
+    "tornado>=6.2",
+    "traitlets>=5.3",
+]
+files = [
+    {file = "jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f"},
+    {file = "jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419"},
+]
+
+[[package]]
+name = "jupyter-core"
+version = "5.7.2"
+requires_python = ">=3.8"
+summary = "Jupyter core package. A base package on which Jupyter projects rely."
+groups = ["dev"]
+dependencies = [
+    "platformdirs>=2.5",
+    "pywin32>=300; sys_platform == \"win32\" and platform_python_implementation != \"PyPy\"",
+    "traitlets>=5.3",
+]
+files = [
+    {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"},
+    {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"},
+]
+
+[[package]]
+name = "line-profiler"
+version = "4.1.2"
+requires_python = ">=3.6"
+summary = "Line-by-line profiler"
+groups = ["dev"]
+files = [
+    {file = "line_profiler-4.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4344c1504ad1a57029a8ab30812d967a0917cad7b654077e8787e4a7d7ea3469"},
+    {file = "line_profiler-4.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0720b356db3e9ca297c3260f280c5be3bb4b230eda61ce73b4df5e553418d37a"},
+    {file = "line_profiler-4.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:09f742af37166768f92495bd3d3a71da1ba41d3004307a66c108f29ed947d6e1"},
+    {file = "line_profiler-4.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:443a5df10eb7910df694340c8a81c1668a88bb59ca44149a3291f7b2ae960891"},
+    {file = "line_profiler-4.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a906f9d1687eea7e5b22e3bd367d4b63706fcea1906baaad76b1cc4c1142553d"},
+    {file = "line_profiler-4.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3b2c8cc34a776c5cfaa4a4a09a51541efcc9082dce15b19e494000e82576ced"},
+    {file = "line_profiler-4.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:55ca0a78eb8d52515486c374ec53fa9e65e3c4128e8bbc909d8bfce267a91fdd"},
+    {file = "line_profiler-4.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:f4a11389f06831d7984b63be0743fbbbae1ffb56fad04b4e538d3e6933b5c265"},
+    {file = "line_profiler-4.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:32fa07f6fecfd209329559e4ae945dc7bdc0703355c8924bbf19101495b2373f"},
+    {file = "line_profiler-4.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6f8e9e8af6660629f214e424613c56a6622cf36d9c638c569c926b21374d7029"},
+    {file = "line_profiler-4.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4753113c4e2c30a547937dbc456900d7f3a1b99bc8bc81a640a89306cd729c0f"},
+    {file = "line_profiler-4.1.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f0989302404850a2a041ba60afe6c7240aea10fdd9432d5c1d464aca39a0369"},
+    {file = "line_profiler-4.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f4b25ee412b0cd624614edd16c4c0af02dbeb73db2a08a49a14b120005a5630"},
+    {file = "line_profiler-4.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93c6a49009ee75dcd8ff644c5fd39eeb8bb672d5a41bacdd239db14ae1ba3098"},
+    {file = "line_profiler-4.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b96964cdb306741a01b95d210d634cc79ed70d2904336cbd8f69a9b5f284426d"},
+    {file = "line_profiler-4.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:46a8cad2cb4b6a1229ddccf06694b1d01fd5acd1cf8c502caf937765a7c877de"},
+    {file = "line_profiler-4.1.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a102fd8e13abd367379e39fd9426fd60e1e3a39fcd80fa25641618969464c022"},
+    {file = "line_profiler-4.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44ee51bce974d6b2269492299d4abae6db1b06ae7617760c7436c597dbdbd032"},
+    {file = "line_profiler-4.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e4cafd9a1effe1b9646f6a86716dbd291684fde1f8a297930d845d8a9340299"},
+    {file = "line_profiler-4.1.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b433a2918e522d6dd0e6bdcf1216cede15c4f201f7eeb0d816114fbac5031cd7"},
+    {file = "line_profiler-4.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad96accb1f5cdedfe2e6607f9be86d28196d3f743229e2b67bd28a40f76f133"},
+    {file = "line_profiler-4.1.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4eb9df035861f7c2e9852773dff72a3324e2e5aebc0b8c7c2ba22437387ef5e7"},
+    {file = "line_profiler-4.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e733c0e6626d0e9f1b434da40b93ed1c00ea503f3ced04f5a58c22d1163fe1c1"},
+    {file = "line_profiler-4.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:8cc0c24384e29e99da5627669dbf312a23d11138de0169aa58d4ea5187522ba0"},
+    {file = "line_profiler-4.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:62776d67dfc6c358de5c19d606eccbd95e6feb75928064850be0232e9276f751"},
+    {file = "line_profiler-4.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:060d71ba11ff5476d7c10774a34955566bab545ab5ff39231306b4d84081725d"},
+    {file = "line_profiler-4.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ad13e1d5a174336508bbf275202822c8898cd1f014881059103b748310d5bc84"},
+    {file = "line_profiler-4.1.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77824dfc1f58dc7fe62fb053aa54586979ef60fea221dcdbba2022608c1314f"},
+    {file = "line_profiler-4.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c8ffc44a030789f7bc6594de581b39e8da0591fc6c598dd4243cf140b200528"},
+    {file = "line_profiler-4.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4729820d8da3ed92f14e30dbd28a851eeefe2ba70b8b897f2d9c886ade8007c1"},
+    {file = "line_profiler-4.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0bce5c04d0daf6dd19348540012b0a6d69206ae40db096de222e6d5f824922e8"},
+    {file = "line_profiler-4.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:a65b70d6ecef4f2e61cf504a5c77085718f1dae9508b21c9058ad483ae7e16ee"},
+    {file = "line_profiler-4.1.2.tar.gz", hash = "sha256:aa56578b0ff5a756fe180b3fda7bd67c27bbd478b3d0124612d8cf00e4a21df2"},
+]
+
+[[package]]
+name = "line-profiler-pycharm"
+version = "1.2.0"
+requires_python = ">=3"
+summary = "PyCharm Line Profiler helper package with which one can visualize profiles from the 'line-profiler' into PyCharm"
+groups = ["dev"]
+dependencies = [
+    "line-profiler",
+]
+files = [
+    {file = "line_profiler_pycharm-1.2.0-py3-none-any.whl", hash = "sha256:2d4c47c6894ab81f48fbb132ac4830490813b13c297016ae0d97bc7ef12041ad"},
+    {file = "line_profiler_pycharm-1.2.0.tar.gz", hash = "sha256:16cacf234952420fc324f17704c0cc2145d5afd2ec0593e359796927bcc0debb"},
+]
+
+[[package]]
+name = "line-profiler"
+version = "4.1.2"
+extras = ["all"]
+requires_python = ">=3.6"
+summary = "Line-by-line profiler"
+groups = ["dev"]
+dependencies = [
+    "Cython>=3.0.3",
+    "IPython>=7.14.0; python_version ~= \"3.6.0\"",
+    "IPython>=7.18.0; python_version ~= \"3.7.0\"",
+    "IPython>=8.12.2; python_version ~= \"3.8.0\"",
+    "IPython>=8.14.0; python_version < \"4.0.0\" and python_version >= \"3.9.0\"",
+    "cibuildwheel>=2.11.2; python_version < \"3.10\" and python_version >= \"3.9\"",
+    "cibuildwheel>=2.11.2; python_version < \"3.11\" and python_version >= \"3.10\"",
+    "cibuildwheel>=2.11.2; python_version < \"3.8\" and python_version >= \"3.7\"",
+    "cibuildwheel>=2.11.2; python_version < \"3.9\" and python_version >= \"3.8\"",
+    "cibuildwheel>=2.11.2; python_version ~= \"3.11\"",
+    "cibuildwheel>=2.8.1; python_version < \"3.7\" and python_version >= \"3.6\"",
+    "cmake>=3.21.2",
+    "coverage[toml]>=5.3",
+    "line-profiler==4.1.2",
+    "ninja>=1.10.2",
+    "pytest-cov>=2.8.1; python_version ~= \"2.7.0\"",
+    "pytest-cov>=2.8.1; python_version ~= \"3.4.0\"",
+    "pytest-cov>=2.9.0; python_version ~= \"3.5.0\"",
+    "pytest-cov>=3.0.0; python_version >= \"3.6.0\"",
+    "pytest<=4.6.11,>=4.6.0; python_version ~= \"2.7.0\"",
+    "pytest<=4.6.11,>=4.6.0; python_version ~= \"3.4.0\"",
+    "pytest<=6.1.2,>=4.6.0; python_version ~= \"3.5.0\"",
+    "pytest>=4.6.0; python_version < \"3.10.0\" and python_version >= \"3.7.0\"",
+    "pytest>=4.6.0; python_version ~= \"3.6.0\"",
+    "pytest>=6.2.5; python_version >= \"3.10.0\"",
+    "rich>=12.3.0",
+    "scikit-build>=0.11.1",
+    "setuptools>=41.0.1; python_version < \"3.8\" and python_version >= \"3.6\"",
+    "setuptools>=68.2.2; python_version ~= \"3.8\"",
+    "ubelt>=1.3.4",
+    "xdoctest>=1.1.2",
+]
+files = [
+    {file = "line_profiler-4.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4344c1504ad1a57029a8ab30812d967a0917cad7b654077e8787e4a7d7ea3469"},
+    {file = "line_profiler-4.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0720b356db3e9ca297c3260f280c5be3bb4b230eda61ce73b4df5e553418d37a"},
+    {file = "line_profiler-4.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:09f742af37166768f92495bd3d3a71da1ba41d3004307a66c108f29ed947d6e1"},
+    {file = "line_profiler-4.1.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:443a5df10eb7910df694340c8a81c1668a88bb59ca44149a3291f7b2ae960891"},
+    {file = "line_profiler-4.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a906f9d1687eea7e5b22e3bd367d4b63706fcea1906baaad76b1cc4c1142553d"},
+    {file = "line_profiler-4.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e3b2c8cc34a776c5cfaa4a4a09a51541efcc9082dce15b19e494000e82576ced"},
+    {file = "line_profiler-4.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:55ca0a78eb8d52515486c374ec53fa9e65e3c4128e8bbc909d8bfce267a91fdd"},
+    {file = "line_profiler-4.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:f4a11389f06831d7984b63be0743fbbbae1ffb56fad04b4e538d3e6933b5c265"},
+    {file = "line_profiler-4.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:32fa07f6fecfd209329559e4ae945dc7bdc0703355c8924bbf19101495b2373f"},
+    {file = "line_profiler-4.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6f8e9e8af6660629f214e424613c56a6622cf36d9c638c569c926b21374d7029"},
+    {file = "line_profiler-4.1.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4753113c4e2c30a547937dbc456900d7f3a1b99bc8bc81a640a89306cd729c0f"},
+    {file = "line_profiler-4.1.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f0989302404850a2a041ba60afe6c7240aea10fdd9432d5c1d464aca39a0369"},
+    {file = "line_profiler-4.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f4b25ee412b0cd624614edd16c4c0af02dbeb73db2a08a49a14b120005a5630"},
+    {file = "line_profiler-4.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93c6a49009ee75dcd8ff644c5fd39eeb8bb672d5a41bacdd239db14ae1ba3098"},
+    {file = "line_profiler-4.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b96964cdb306741a01b95d210d634cc79ed70d2904336cbd8f69a9b5f284426d"},
+    {file = "line_profiler-4.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:46a8cad2cb4b6a1229ddccf06694b1d01fd5acd1cf8c502caf937765a7c877de"},
+    {file = "line_profiler-4.1.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a102fd8e13abd367379e39fd9426fd60e1e3a39fcd80fa25641618969464c022"},
+    {file = "line_profiler-4.1.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44ee51bce974d6b2269492299d4abae6db1b06ae7617760c7436c597dbdbd032"},
+    {file = "line_profiler-4.1.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0e4cafd9a1effe1b9646f6a86716dbd291684fde1f8a297930d845d8a9340299"},
+    {file = "line_profiler-4.1.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b433a2918e522d6dd0e6bdcf1216cede15c4f201f7eeb0d816114fbac5031cd7"},
+    {file = "line_profiler-4.1.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad96accb1f5cdedfe2e6607f9be86d28196d3f743229e2b67bd28a40f76f133"},
+    {file = "line_profiler-4.1.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4eb9df035861f7c2e9852773dff72a3324e2e5aebc0b8c7c2ba22437387ef5e7"},
+    {file = "line_profiler-4.1.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e733c0e6626d0e9f1b434da40b93ed1c00ea503f3ced04f5a58c22d1163fe1c1"},
+    {file = "line_profiler-4.1.2-cp312-cp312-win_amd64.whl", hash = "sha256:8cc0c24384e29e99da5627669dbf312a23d11138de0169aa58d4ea5187522ba0"},
+    {file = "line_profiler-4.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:62776d67dfc6c358de5c19d606eccbd95e6feb75928064850be0232e9276f751"},
+    {file = "line_profiler-4.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:060d71ba11ff5476d7c10774a34955566bab545ab5ff39231306b4d84081725d"},
+    {file = "line_profiler-4.1.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ad13e1d5a174336508bbf275202822c8898cd1f014881059103b748310d5bc84"},
+    {file = "line_profiler-4.1.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d77824dfc1f58dc7fe62fb053aa54586979ef60fea221dcdbba2022608c1314f"},
+    {file = "line_profiler-4.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c8ffc44a030789f7bc6594de581b39e8da0591fc6c598dd4243cf140b200528"},
+    {file = "line_profiler-4.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4729820d8da3ed92f14e30dbd28a851eeefe2ba70b8b897f2d9c886ade8007c1"},
+    {file = "line_profiler-4.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0bce5c04d0daf6dd19348540012b0a6d69206ae40db096de222e6d5f824922e8"},
+    {file = "line_profiler-4.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:a65b70d6ecef4f2e61cf504a5c77085718f1dae9508b21c9058ad483ae7e16ee"},
+    {file = "line_profiler-4.1.2.tar.gz", hash = "sha256:aa56578b0ff5a756fe180b3fda7bd67c27bbd478b3d0124612d8cf00e4a21df2"},
+]
+
+[[package]]
+name = "markdown-it-py"
+version = "3.0.0"
+requires_python = ">=3.8"
+summary = "Python port of markdown-it. Markdown parsing, done right!"
+groups = ["dev"]
+dependencies = [
+    "mdurl~=0.1",
+]
+files = [
+    {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
+    {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
+]
+
+[[package]]
+name = "markupsafe"
+version = "2.1.5"
+requires_python = ">=3.7"
+summary = "Safely add untrusted strings to HTML/XML markup."
+groups = ["dev"]
+files = [
+    {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"},
+    {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"},
+    {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"},
+    {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"},
+    {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"},
+    {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
+]
+
+[[package]]
+name = "matplotlib-inline"
+version = "0.1.7"
+requires_python = ">=3.8"
+summary = "Inline Matplotlib backend for Jupyter"
+groups = ["dev"]
+dependencies = [
+    "traitlets",
+]
+files = [
+    {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"},
+    {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"},
+]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+requires_python = ">=3.7"
+summary = "Markdown URL utilities"
+groups = ["dev"]
+files = [
+    {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
+    {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
+]
+
+[[package]]
+name = "msgspec"
+version = "0.18.6"
+requires_python = ">=3.8"
+summary = "A fast serialization and validation library, with builtin support for JSON, MessagePack, YAML, and TOML."
+groups = ["dev"]
+files = [
+    {file = "msgspec-0.18.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:77f30b0234eceeff0f651119b9821ce80949b4d667ad38f3bfed0d0ebf9d6d8f"},
+    {file = "msgspec-0.18.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a76b60e501b3932782a9da039bd1cd552b7d8dec54ce38332b87136c64852dd"},
+    {file = "msgspec-0.18.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06acbd6edf175bee0e36295d6b0302c6de3aaf61246b46f9549ca0041a9d7177"},
+    {file = "msgspec-0.18.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40a4df891676d9c28a67c2cc39947c33de516335680d1316a89e8f7218660410"},
+    {file = "msgspec-0.18.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a6896f4cd5b4b7d688018805520769a8446df911eb93b421c6c68155cdf9dd5a"},
+    {file = "msgspec-0.18.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3ac4dd63fd5309dd42a8c8c36c1563531069152be7819518be0a9d03be9788e4"},
+    {file = "msgspec-0.18.6-cp310-cp310-win_amd64.whl", hash = "sha256:fda4c357145cf0b760000c4ad597e19b53adf01382b711f281720a10a0fe72b7"},
+    {file = "msgspec-0.18.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e77e56ffe2701e83a96e35770c6adb655ffc074d530018d1b584a8e635b4f36f"},
+    {file = "msgspec-0.18.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5351afb216b743df4b6b147691523697ff3a2fc5f3d54f771e91219f5c23aaa"},
+    {file = "msgspec-0.18.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3232fabacef86fe8323cecbe99abbc5c02f7698e3f5f2e248e3480b66a3596b"},
+    {file = "msgspec-0.18.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3b524df6ea9998bbc99ea6ee4d0276a101bcc1aa8d14887bb823914d9f60d07"},
+    {file = "msgspec-0.18.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37f67c1d81272131895bb20d388dd8d341390acd0e192a55ab02d4d6468b434c"},
+    {file = "msgspec-0.18.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0feb7a03d971c1c0353de1a8fe30bb6579c2dc5ccf29b5f7c7ab01172010492"},
+    {file = "msgspec-0.18.6-cp311-cp311-win_amd64.whl", hash = "sha256:41cf758d3f40428c235c0f27bc6f322d43063bc32da7b9643e3f805c21ed57b4"},
+    {file = "msgspec-0.18.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d86f5071fe33e19500920333c11e2267a31942d18fed4d9de5bc2fbab267d28c"},
+    {file = "msgspec-0.18.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce13981bfa06f5eb126a3a5a38b1976bddb49a36e4f46d8e6edecf33ccf11df1"},
+    {file = "msgspec-0.18.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e97dec6932ad5e3ee1e3c14718638ba333befc45e0661caa57033cd4cc489466"},
+    {file = "msgspec-0.18.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad237100393f637b297926cae1868b0d500f764ccd2f0623a380e2bcfb2809ca"},
+    {file = "msgspec-0.18.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db1d8626748fa5d29bbd15da58b2d73af25b10aa98abf85aab8028119188ed57"},
+    {file = "msgspec-0.18.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d70cb3d00d9f4de14d0b31d38dfe60c88ae16f3182988246a9861259c6722af6"},
+    {file = "msgspec-0.18.6-cp312-cp312-win_amd64.whl", hash = "sha256:1003c20bfe9c6114cc16ea5db9c5466e49fae3d7f5e2e59cb70693190ad34da0"},
+    {file = "msgspec-0.18.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:974d3520fcc6b824a6dedbdf2b411df31a73e6e7414301abac62e6b8d03791b4"},
+    {file = "msgspec-0.18.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fd62e5818731a66aaa8e9b0a1e5543dc979a46278da01e85c3c9a1a4f047ef7e"},
+    {file = "msgspec-0.18.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7481355a1adcf1f08dedd9311193c674ffb8bf7b79314b4314752b89a2cf7f1c"},
+    {file = "msgspec-0.18.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6aa85198f8f154cf35d6f979998f6dadd3dc46a8a8c714632f53f5d65b315c07"},
+    {file = "msgspec-0.18.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e24539b25c85c8f0597274f11061c102ad6b0c56af053373ba4629772b407be"},
+    {file = "msgspec-0.18.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c61ee4d3be03ea9cd089f7c8e36158786cd06e51fbb62529276452bbf2d52ece"},
+    {file = "msgspec-0.18.6-cp39-cp39-win_amd64.whl", hash = "sha256:b5c390b0b0b7da879520d4ae26044d74aeee5144f83087eb7842ba59c02bc090"},
+    {file = "msgspec-0.18.6.tar.gz", hash = "sha256:a59fc3b4fcdb972d09138cb516dbde600c99d07c38fd9372a6ef500d2d031b4e"},
+]
+
 [[package]]
 name = "mypy-extensions"
 version = "1.0.0"
@@ -232,6 +1111,51 @@ files = [
     {file = "nepattern-0.7.6.tar.gz", hash = "sha256:07bd5b2f3b9b9739b703bf723ffd642ca93738a32df7b699d57d6f338d46bad0"},
 ]
 
+[[package]]
+name = "nest-asyncio"
+version = "1.6.0"
+requires_python = ">=3.5"
+summary = "Patch asyncio to allow nested event loops"
+groups = ["dev"]
+files = [
+    {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"},
+    {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"},
+]
+
+[[package]]
+name = "ninja"
+version = "1.11.1.1"
+summary = "Ninja is a small build system with a focus on speed"
+groups = ["dev"]
+files = [
+    {file = "ninja-1.11.1.1-py2.py3-none-macosx_10_9_universal2.macosx_10_9_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:376889c76d87b95b5719fdd61dd7db193aa7fd4432e5d52d2e44e4c497bdbbee"},
+    {file = "ninja-1.11.1.1-py2.py3-none-manylinux1_i686.manylinux_2_5_i686.whl", hash = "sha256:ecf80cf5afd09f14dcceff28cb3f11dc90fb97c999c89307aea435889cb66877"},
+    {file = "ninja-1.11.1.1-py2.py3-none-manylinux1_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:84502ec98f02a037a169c4b0d5d86075eaf6afc55e1879003d6cab51ced2ea4b"},
+    {file = "ninja-1.11.1.1-py2.py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:73b93c14046447c7c5cc892433d4fae65d6364bec6685411cb97a8bcf815f93a"},
+    {file = "ninja-1.11.1.1-py2.py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:18302d96a5467ea98b68e1cae1ae4b4fb2b2a56a82b955193c637557c7273dbd"},
+    {file = "ninja-1.11.1.1-py2.py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:aad34a70ef15b12519946c5633344bc775a7656d789d9ed5fdb0d456383716ef"},
+    {file = "ninja-1.11.1.1-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:d491fc8d89cdcb416107c349ad1e3a735d4c4af5e1cb8f5f727baca6350fdaea"},
+    {file = "ninja-1.11.1.1-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:7563ce1d9fe6ed5af0b8dd9ab4a214bf4ff1f2f6fd6dc29f480981f0f8b8b249"},
+    {file = "ninja-1.11.1.1-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:9df724344202b83018abb45cb1efc22efd337a1496514e7e6b3b59655be85205"},
+    {file = "ninja-1.11.1.1-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:3e0f9be5bb20d74d58c66cc1c414c3e6aeb45c35b0d0e41e8d739c2c0d57784f"},
+    {file = "ninja-1.11.1.1-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:76482ba746a2618eecf89d5253c0d1e4f1da1270d41e9f54dfbd91831b0f6885"},
+    {file = "ninja-1.11.1.1-py2.py3-none-win32.whl", hash = "sha256:fa2ba9d74acfdfbfbcf06fad1b8282de8a7a8c481d9dee45c859a8c93fcc1082"},
+    {file = "ninja-1.11.1.1-py2.py3-none-win_amd64.whl", hash = "sha256:95da904130bfa02ea74ff9c0116b4ad266174fafb1c707aa50212bc7859aebf1"},
+    {file = "ninja-1.11.1.1-py2.py3-none-win_arm64.whl", hash = "sha256:185e0641bde601e53841525c4196278e9aaf4463758da6dd1e752c0a0f54136a"},
+    {file = "ninja-1.11.1.1.tar.gz", hash = "sha256:9d793b08dd857e38d0b6ffe9e6b7145d7c485a42dcfea04905ca0cdb6017cc3c"},
+]
+
+[[package]]
+name = "objprint"
+version = "0.2.3"
+requires_python = ">=3.6"
+summary = "A library that can print Python objects in human readable format"
+groups = ["dev"]
+files = [
+    {file = "objprint-0.2.3-py3-none-any.whl", hash = "sha256:1721e6f97bae5c5b86c2716a0d45a9dd2c9a4cd9f52cfc8a0dfbe801805554cb"},
+    {file = "objprint-0.2.3.tar.gz", hash = "sha256:73d0ad5a7c3151fce634c8892e5c2a050ccae3b1a353bf1316f08b7854da863b"},
+]
+
 [[package]]
 name = "packaging"
 version = "23.2"
@@ -243,6 +1167,17 @@ files = [
     {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"},
 ]
 
+[[package]]
+name = "parso"
+version = "0.8.4"
+requires_python = ">=3.6"
+summary = "A Python Parser"
+groups = ["dev"]
+files = [
+    {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"},
+    {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"},
+]
+
 [[package]]
 name = "pathspec"
 version = "0.12.1"
@@ -254,6 +1189,20 @@ files = [
     {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
 ]
 
+[[package]]
+name = "pexpect"
+version = "4.9.0"
+summary = "Pexpect allows easy control of interactive console applications."
+groups = ["dev"]
+marker = "sys_platform != \"win32\""
+dependencies = [
+    "ptyprocess>=0.5",
+]
+files = [
+    {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"},
+    {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"},
+]
+
 [[package]]
 name = "platformdirs"
 version = "4.2.0"
@@ -276,6 +1225,79 @@ files = [
     {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"},
 ]
 
+[[package]]
+name = "pprofile"
+version = "2.2.0"
+summary = "Line-granularity, thread-aware deterministic and statistic pure-python profiler"
+groups = ["dev"]
+files = [
+    {file = "pprofile-2.2.0.tar.gz", hash = "sha256:edd57f35f2b3fb84e7d01aa310a44bfabacc66ffc353dce147348ec14de3c7d9"},
+]
+
+[[package]]
+name = "prompt-toolkit"
+version = "3.0.47"
+requires_python = ">=3.7.0"
+summary = "Library for building powerful interactive command lines in Python"
+groups = ["dev"]
+dependencies = [
+    "wcwidth",
+]
+files = [
+    {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"},
+    {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"},
+]
+
+[[package]]
+name = "psutil"
+version = "6.0.0"
+requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
+summary = "Cross-platform lib for process and system monitoring in Python."
+groups = ["dev"]
+files = [
+    {file = "psutil-6.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c588a7e9b1173b6e866756dde596fd4cad94f9399daf99ad8c3258b3cb2b47a0"},
+    {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ed2440ada7ef7d0d608f20ad89a04ec47d2d3ab7190896cd62ca5fc4fe08bf0"},
+    {file = "psutil-6.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fd9a97c8e94059b0ef54a7d4baf13b405011176c3b6ff257c247cae0d560ecd"},
+    {file = "psutil-6.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e8d0054fc88153ca0544f5c4d554d42e33df2e009c4ff42284ac9ebdef4132"},
+    {file = "psutil-6.0.0-cp37-abi3-win32.whl", hash = "sha256:a495580d6bae27291324fe60cea0b5a7c23fa36a7cd35035a16d93bdcf076b9d"},
+    {file = "psutil-6.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:33ea5e1c975250a720b3a6609c490db40dae5d83a4eb315170c4fe0d8b1f34b3"},
+    {file = "psutil-6.0.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffe7fc9b6b36beadc8c322f84e1caff51e8703b88eee1da46d1e3a6ae11b4fd0"},
+    {file = "psutil-6.0.0.tar.gz", hash = "sha256:8faae4f310b6d969fa26ca0545338b21f73c6b15db7c4a8d934a5482faa818f2"},
+]
+
+[[package]]
+name = "ptyprocess"
+version = "0.7.0"
+summary = "Run a subprocess in a pseudo terminal"
+groups = ["dev"]
+marker = "sys_platform != \"win32\""
+files = [
+    {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
+    {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
+]
+
+[[package]]
+name = "pure-eval"
+version = "0.2.3"
+summary = "Safely evaluate AST nodes without side effects"
+groups = ["dev"]
+files = [
+    {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"},
+    {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"},
+]
+
+[[package]]
+name = "pycparser"
+version = "2.22"
+requires_python = ">=3.8"
+summary = "C parser in Python"
+groups = ["dev"]
+marker = "implementation_name == \"pypy\""
+files = [
+    {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
+    {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
+]
+
 [[package]]
 name = "pydeps"
 version = "1.11.2"
@@ -290,6 +1312,28 @@ files = [
     {file = "pydeps-1.11.2.tar.gz", hash = "sha256:06c69e83e7f93c0409e0421938fbf34df3c364e2fd848cb0da8ed225d2490641"},
 ]
 
+[[package]]
+name = "pygments"
+version = "2.18.0"
+requires_python = ">=3.8"
+summary = "Pygments is a syntax highlighting package written in Python."
+groups = ["dev"]
+files = [
+    {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
+    {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
+]
+
+[[package]]
+name = "pynvml"
+version = "11.5.3"
+requires_python = ">=3.6"
+summary = "Python utilities for the NVIDIA Management Library"
+groups = ["dev"]
+files = [
+    {file = "pynvml-11.5.3-py3-none-any.whl", hash = "sha256:a5fba3ab14febda50d19dbda012ef62ae0aed45b7ccc07af0bc5be79223e450c"},
+    {file = "pynvml-11.5.3.tar.gz", hash = "sha256:183d223ae487e5f00402d8da06c68c978ef8a9295793ee75559839c6ade7b229"},
+]
+
 [[package]]
 name = "pytest"
 version = "7.2.2"
@@ -311,6 +1355,244 @@ files = [
     {file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"},
 ]
 
+[[package]]
+name = "pytest-cov"
+version = "5.0.0"
+requires_python = ">=3.8"
+summary = "Pytest plugin for measuring coverage."
+groups = ["dev"]
+dependencies = [
+    "coverage[toml]>=5.2.1",
+    "pytest>=4.6",
+]
+files = [
+    {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"},
+    {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"},
+]
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+summary = "Extensions to the standard Python datetime module"
+groups = ["dev"]
+dependencies = [
+    "six>=1.5",
+]
+files = [
+    {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
+    {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
+]
+
+[[package]]
+name = "pywin32"
+version = "306"
+summary = "Python for Window Extensions"
+groups = ["dev"]
+marker = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""
+files = [
+    {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"},
+    {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"},
+    {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"},
+    {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"},
+    {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"},
+    {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"},
+    {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"},
+    {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"},
+    {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"},
+    {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"},
+]
+
+[[package]]
+name = "pyzmq"
+version = "26.2.0"
+requires_python = ">=3.7"
+summary = "Python bindings for 0MQ"
+groups = ["dev"]
+dependencies = [
+    "cffi; implementation_name == \"pypy\"",
+]
+files = [
+    {file = "pyzmq-26.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629"},
+    {file = "pyzmq-26.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b"},
+    {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764"},
+    {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c"},
+    {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a"},
+    {file = "pyzmq-26.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88"},
+    {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f"},
+    {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282"},
+    {file = "pyzmq-26.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea"},
+    {file = "pyzmq-26.2.0-cp310-cp310-win32.whl", hash = "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2"},
+    {file = "pyzmq-26.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971"},
+    {file = "pyzmq-26.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa"},
+    {file = "pyzmq-26.2.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:8f7e66c7113c684c2b3f1c83cdd3376103ee0ce4c49ff80a648643e57fb22218"},
+    {file = "pyzmq-26.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3a495b30fc91db2db25120df5847d9833af237546fd59170701acd816ccc01c4"},
+    {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77eb0968da535cba0470a5165468b2cac7772cfb569977cff92e240f57e31bef"},
+    {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ace4f71f1900a548f48407fc9be59c6ba9d9aaf658c2eea6cf2779e72f9f317"},
+    {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a78853d7280bffb93df0a4a6a2498cba10ee793cc8076ef797ef2f74d107cf"},
+    {file = "pyzmq-26.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:689c5d781014956a4a6de61d74ba97b23547e431e9e7d64f27d4922ba96e9d6e"},
+    {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0aca98bc423eb7d153214b2df397c6421ba6373d3397b26c057af3c904452e37"},
+    {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f3496d76b89d9429a656293744ceca4d2ac2a10ae59b84c1da9b5165f429ad3"},
+    {file = "pyzmq-26.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5c2b3bfd4b9689919db068ac6c9911f3fcb231c39f7dd30e3138be94896d18e6"},
+    {file = "pyzmq-26.2.0-cp311-cp311-win32.whl", hash = "sha256:eac5174677da084abf378739dbf4ad245661635f1600edd1221f150b165343f4"},
+    {file = "pyzmq-26.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:5a509df7d0a83a4b178d0f937ef14286659225ef4e8812e05580776c70e155d5"},
+    {file = "pyzmq-26.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:c0e6091b157d48cbe37bd67233318dbb53e1e6327d6fc3bb284afd585d141003"},
+    {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:ded0fc7d90fe93ae0b18059930086c51e640cdd3baebdc783a695c77f123dcd9"},
+    {file = "pyzmq-26.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:17bf5a931c7f6618023cdacc7081f3f266aecb68ca692adac015c383a134ca52"},
+    {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55cf66647e49d4621a7e20c8d13511ef1fe1efbbccf670811864452487007e08"},
+    {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4661c88db4a9e0f958c8abc2b97472e23061f0bc737f6f6179d7a27024e1faa5"},
+    {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea7f69de383cb47522c9c208aec6dd17697db7875a4674c4af3f8cfdac0bdeae"},
+    {file = "pyzmq-26.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:7f98f6dfa8b8ccaf39163ce872bddacca38f6a67289116c8937a02e30bbe9711"},
+    {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e3e0210287329272539eea617830a6a28161fbbd8a3271bf4150ae3e58c5d0e6"},
+    {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6b274e0762c33c7471f1a7471d1a2085b1a35eba5cdc48d2ae319f28b6fc4de3"},
+    {file = "pyzmq-26.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:29c6a4635eef69d68a00321e12a7d2559fe2dfccfa8efae3ffb8e91cd0b36a8b"},
+    {file = "pyzmq-26.2.0-cp312-cp312-win32.whl", hash = "sha256:989d842dc06dc59feea09e58c74ca3e1678c812a4a8a2a419046d711031f69c7"},
+    {file = "pyzmq-26.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:2a50625acdc7801bc6f74698c5c583a491c61d73c6b7ea4dee3901bb99adb27a"},
+    {file = "pyzmq-26.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:4d29ab8592b6ad12ebbf92ac2ed2bedcfd1cec192d8e559e2e099f648570e19b"},
+    {file = "pyzmq-26.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9dd8cd1aeb00775f527ec60022004d030ddc51d783d056e3e23e74e623e33726"},
+    {file = "pyzmq-26.2.0-cp313-cp313-macosx_10_15_universal2.whl", hash = "sha256:28c812d9757fe8acecc910c9ac9dafd2ce968c00f9e619db09e9f8f54c3a68a3"},
+    {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d80b1dd99c1942f74ed608ddb38b181b87476c6a966a88a950c7dee118fdf50"},
+    {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c997098cc65e3208eca09303630e84d42718620e83b733d0fd69543a9cab9cb"},
+    {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ad1bc8d1b7a18497dda9600b12dc193c577beb391beae5cd2349184db40f187"},
+    {file = "pyzmq-26.2.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:bea2acdd8ea4275e1278350ced63da0b166421928276c7c8e3f9729d7402a57b"},
+    {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:23f4aad749d13698f3f7b64aad34f5fc02d6f20f05999eebc96b89b01262fb18"},
+    {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:a4f96f0d88accc3dbe4a9025f785ba830f968e21e3e2c6321ccdfc9aef755115"},
+    {file = "pyzmq-26.2.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ced65e5a985398827cc9276b93ef6dfabe0273c23de8c7931339d7e141c2818e"},
+    {file = "pyzmq-26.2.0-cp313-cp313-win32.whl", hash = "sha256:31507f7b47cc1ead1f6e86927f8ebb196a0bab043f6345ce070f412a59bf87b5"},
+    {file = "pyzmq-26.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:70fc7fcf0410d16ebdda9b26cbd8bf8d803d220a7f3522e060a69a9c87bf7bad"},
+    {file = "pyzmq-26.2.0-cp313-cp313-win_arm64.whl", hash = "sha256:c3789bd5768ab5618ebf09cef6ec2b35fed88709b104351748a63045f0ff9797"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:034da5fc55d9f8da09015d368f519478a52675e558c989bfcb5cf6d4e16a7d2a"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:c92d73464b886931308ccc45b2744e5968cbaade0b1d6aeb40d8ab537765f5bc"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:794a4562dcb374f7dbbfb3f51d28fb40123b5a2abadee7b4091f93054909add5"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aee22939bb6075e7afededabad1a56a905da0b3c4e3e0c45e75810ebe3a52672"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ae90ff9dad33a1cfe947d2c40cb9cb5e600d759ac4f0fd22616ce6540f72797"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:43a47408ac52647dfabbc66a25b05b6a61700b5165807e3fbd40063fcaf46386"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:25bf2374a2a8433633c65ccb9553350d5e17e60c8eb4de4d92cc6bd60f01d306"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:007137c9ac9ad5ea21e6ad97d3489af654381324d5d3ba614c323f60dab8fae6"},
+    {file = "pyzmq-26.2.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:470d4a4f6d48fb34e92d768b4e8a5cc3780db0d69107abf1cd7ff734b9766eb0"},
+    {file = "pyzmq-26.2.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:b1d464cb8d72bfc1a3adc53305a63a8e0cac6bc8c5a07e8ca190ab8d3faa43c2"},
+    {file = "pyzmq-26.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4da04c48873a6abdd71811c5e163bd656ee1b957971db7f35140a2d573f6949c"},
+    {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d049df610ac811dcffdc147153b414147428567fbbc8be43bb8885f04db39d98"},
+    {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05590cdbc6b902101d0e65d6a4780af14dc22914cc6ab995d99b85af45362cc9"},
+    {file = "pyzmq-26.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c811cfcd6a9bf680236c40c6f617187515269ab2912f3d7e8c0174898e2519db"},
+    {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6835dd60355593de10350394242b5757fbbd88b25287314316f266e24c61d073"},
+    {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc6bee759a6bddea5db78d7dcd609397449cb2d2d6587f48f3ca613b19410cfc"},
+    {file = "pyzmq-26.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c530e1eecd036ecc83c3407f77bb86feb79916d4a33d11394b8234f3bd35b940"},
+    {file = "pyzmq-26.2.0-cp39-cp39-win32.whl", hash = "sha256:367b4f689786fca726ef7a6c5ba606958b145b9340a5e4808132cc65759abd44"},
+    {file = "pyzmq-26.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:e6fa2e3e683f34aea77de8112f6483803c96a44fd726d7358b9888ae5bb394ec"},
+    {file = "pyzmq-26.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:7445be39143a8aa4faec43b076e06944b8f9d0701b669df4af200531b21e40bb"},
+    {file = "pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072"},
+    {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1"},
+    {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d"},
+    {file = "pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca"},
+    {file = "pyzmq-26.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c"},
+    {file = "pyzmq-26.2.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cdeabcff45d1c219636ee2e54d852262e5c2e085d6cb476d938aee8d921356b3"},
+    {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35cffef589bcdc587d06f9149f8d5e9e8859920a071df5a2671de2213bef592a"},
+    {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18c8dc3b7468d8b4bdf60ce9d7141897da103c7a4690157b32b60acb45e333e6"},
+    {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7133d0a1677aec369d67dd78520d3fa96dd7f3dcec99d66c1762870e5ea1a50a"},
+    {file = "pyzmq-26.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6a96179a24b14fa6428cbfc08641c779a53f8fcec43644030328f44034c7f1f4"},
+    {file = "pyzmq-26.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4f78c88905461a9203eac9faac157a2a0dbba84a0fd09fd29315db27be40af9f"},
+    {file = "pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f"},
+]
+
+[[package]]
+name = "rich"
+version = "13.9.1"
+requires_python = ">=3.8.0"
+summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
+groups = ["dev"]
+dependencies = [
+    "markdown-it-py>=2.2.0",
+    "pygments<3.0.0,>=2.13.0",
+    "typing-extensions<5.0,>=4.0.0; python_version < \"3.11\"",
+]
+files = [
+    {file = "rich-13.9.1-py3-none-any.whl", hash = "sha256:b340e739f30aa58921dc477b8adaa9ecdb7cecc217be01d93730ee1bc8aa83be"},
+    {file = "rich-13.9.1.tar.gz", hash = "sha256:097cffdf85db1babe30cc7deba5ab3a29e1b9885047dab24c57e9a7f8a9c1466"},
+]
+
+[[package]]
+name = "scalene"
+version = "1.5.19"
+requires_python = ">=3.8"
+summary = "Scalene: A high-resolution, low-overhead CPU, GPU, and memory profiler for Python"
+groups = ["dev"]
+dependencies = [
+    "Jinja2>=3.0.3",
+    "cloudpickle>=1.5.0",
+    "pynvml>=11.0.0",
+    "rich>=10.7.0",
+    "wheel>=0.36.1",
+]
+files = [
+    {file = "scalene-1.5.19-cp310-cp310-macosx_11_7_universal2.whl", hash = "sha256:78480f92f5098fffdcba4e4cd540fdb6b7a95ff933ee93e1056b0aa2ab746643"},
+    {file = "scalene-1.5.19-cp310-cp310-manylinux_2_24_x86_64.whl", hash = "sha256:1da57151f00c70446309c9b52843ce7b437bbf32d336a7c309d4fe0b8deda2a2"},
+    {file = "scalene-1.5.19-cp310-cp310-win_amd64.whl", hash = "sha256:cdb9be734cfb6b42eef1105fee1876a5c465eb72e109c0d0ceea6e6bdbce21c6"},
+    {file = "scalene-1.5.19-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dd2b29bd13eaafdd98090108357680c1a6fa88067b4e71313252aa065bbe6ec1"},
+    {file = "scalene-1.5.19-cp311-cp311-manylinux_2_24_x86_64.whl", hash = "sha256:2dac52555518c7159d2fd9c8c7c31ffa8b6a74f21d1b40a9d315a77f4a7f97ed"},
+    {file = "scalene-1.5.19-cp311-cp311-win_amd64.whl", hash = "sha256:eeef31408df35972e54a39ae2d2f1aeab111f2d53d0a78061e45dcf024c6e01d"},
+    {file = "scalene-1.5.19-cp39-cp39-macosx_11_7_universal2.whl", hash = "sha256:6c08f3bc0b6355db3c34f0e9aea1b291e64675bb832e19758ee751918787cac0"},
+    {file = "scalene-1.5.19-cp39-cp39-manylinux_2_24_x86_64.whl", hash = "sha256:d8bc53334b13e486ed6ba03fe4b7595ad4038d05537793eed9999952ba1b34c6"},
+    {file = "scalene-1.5.19-cp39-cp39-win_amd64.whl", hash = "sha256:d1fd5d83f3c022ddc46049f29823351b8dbdb8590f5803358fa6034784601f24"},
+    {file = "scalene-1.5.19.tar.gz", hash = "sha256:59c5eaaa64f4990444f9606e841b268d49f55dcd7467162e48f9658150a9cd1e"},
+]
+
+[[package]]
+name = "scikit-build"
+version = "0.18.1"
+requires_python = ">=3.7"
+summary = "Improved build system generator for Python C/C++/Fortran/Cython extensions"
+groups = ["dev"]
+dependencies = [
+    "distro",
+    "packaging",
+    "setuptools>=42.0.0",
+    "tomli; python_version < \"3.11\"",
+    "typing-extensions>=3.7; python_version < \"3.8\"",
+    "wheel>=0.32.0",
+]
+files = [
+    {file = "scikit_build-0.18.1-py3-none-any.whl", hash = "sha256:a6860e300f6807e76f21854163bdb9db16afc74eadf34bd6a9947d3fdfcd725a"},
+    {file = "scikit_build-0.18.1.tar.gz", hash = "sha256:a4152ac5a084d499c28a7797be0628d8366c336e2fb0e1a063eb32e55efcb8e7"},
+]
+
+[[package]]
+name = "setuptools"
+version = "75.1.0"
+requires_python = ">=3.8"
+summary = "Easily download, build, install, upgrade, and uninstall Python packages"
+groups = ["dev"]
+files = [
+    {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"},
+    {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"},
+]
+
+[[package]]
+name = "six"
+version = "1.16.0"
+requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+summary = "Python 2 and 3 compatibility utilities"
+groups = ["dev"]
+files = [
+    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
+    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
+]
+
+[[package]]
+name = "stack-data"
+version = "0.6.3"
+summary = "Extract data from python stack frames and tracebacks for informative displays"
+groups = ["dev"]
+dependencies = [
+    "asttokens>=2.1.0",
+    "executing>=1.2.0",
+    "pure-eval",
+]
+files = [
+    {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"},
+    {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"},
+]
+
 [[package]]
 name = "stdlib-list"
 version = "0.10.0"
@@ -359,15 +1641,6 @@ files = [
     {file = "tarina-0.5.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:dbc6e78e3ee9b24f9c0feb2c14c17d9696098abf6530ae63d6f4158ab7038c38"},
     {file = "tarina-0.5.8-cp312-cp312-win32.whl", hash = "sha256:4e1a08f1c3d40f935cc8c9507b7ea669b002a53dc7334c9b0ede9f71cf9d1cba"},
     {file = "tarina-0.5.8-cp312-cp312-win_amd64.whl", hash = "sha256:ab90fd830ec05d5f7cd001906fdd1a3e00d8c9fd221772d02bb87a7aec947925"},
-    {file = "tarina-0.5.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f5df6b179284bd5b1d609d97f6b941a1928ab29fbcd364d183a49558a74a7b1c"},
-    {file = "tarina-0.5.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a88f45116b8b76ad50b4cdaf350730cdf35edee7a4ebe1c6373b460f202965ae"},
-    {file = "tarina-0.5.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e80b99cd0c43c0c8b8b99c8348a5970721eca60198032b041af3efe8f661f3c3"},
-    {file = "tarina-0.5.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99193e0b51c7220f2b3edb06102a37b8c76bb5f1ce0c9bcfba7020d907e72cca"},
-    {file = "tarina-0.5.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47811cfabd57f24da6825b3b65fd0d7417d2950474782bde5c003c3ad2847d80"},
-    {file = "tarina-0.5.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a36874609c532e52e3b71f64b1d35efe38d6ea7a43d96dba64d1e4c036203430"},
-    {file = "tarina-0.5.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9734c9ed62fa6eb62ea7e8f5c32057eda6ca1405e63a12d1951d15bf9ee453e1"},
-    {file = "tarina-0.5.8-cp38-cp38-win32.whl", hash = "sha256:2c1391003564baaad6c8ecf847e64d66c0521c871d87cad2a83a90540ba05f3c"},
-    {file = "tarina-0.5.8-cp38-cp38-win_amd64.whl", hash = "sha256:c81e3ccff2e89f93b26b76df5d73c5a79c82456b89fc4054ad7482549dea940a"},
     {file = "tarina-0.5.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7130939147f54f08eda3c6e0eb4cf8c20a4dfa079de9c9e5a3db7a3f3663674c"},
     {file = "tarina-0.5.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0763b338533c7bdfca688219a80c905216c7d5e9c854fd1e299f92ae66ed5659"},
     {file = "tarina-0.5.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a35a155318588dd936348c8bd72618069d2a8bb268d74f070be368fc2b068190"},
@@ -404,6 +1677,37 @@ files = [
     {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
 ]
 
+[[package]]
+name = "tornado"
+version = "6.4.1"
+requires_python = ">=3.8"
+summary = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
+groups = ["dev"]
+files = [
+    {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"},
+    {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"},
+    {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"},
+    {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"},
+    {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"},
+    {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"},
+    {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"},
+    {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"},
+    {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"},
+    {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"},
+    {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"},
+]
+
+[[package]]
+name = "traitlets"
+version = "5.14.3"
+requires_python = ">=3.8"
+summary = "Traitlets Python configuration system"
+groups = ["dev"]
+files = [
+    {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"},
+    {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"},
+]
+
 [[package]]
 name = "typing-extensions"
 version = "4.12.2"
@@ -414,3 +1718,101 @@ files = [
     {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
     {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
 ]
+
+[[package]]
+name = "ubelt"
+version = "1.3.6"
+requires_python = ">=3.6"
+summary = "A Python utility belt containing simple tools, a stdlib like feel, and extra batteries"
+groups = ["dev"]
+files = [
+    {file = "ubelt-1.3.6-py3-none-any.whl", hash = "sha256:2a38f260e7f3c25d3618f653d5c900230dc5af56bf0bc1ff85cfdbe9d0c88f0f"},
+    {file = "ubelt-1.3.6.tar.gz", hash = "sha256:327a516a1fc95595096727ae3ae879379bc56fc11fb945857b971ef85a74f698"},
+]
+
+[[package]]
+name = "viztracer"
+version = "0.16.3"
+requires_python = ">=3.8"
+summary = "A debugging and profiling tool that can trace and visualize python code execution"
+groups = ["dev"]
+dependencies = [
+    "objprint>0.1.3",
+]
+files = [
+    {file = "viztracer-0.16.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:3a39fcee0ffd35639b75565afce9a48ea92a4386f4c2f4a2752b4ec068f273cb"},
+    {file = "viztracer-0.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c223312ecf4adb2271ca4ea84b546b278ec2dbe15b5ace5aa630cb07c2b53d4f"},
+    {file = "viztracer-0.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1320a6ebb89d691a1eced48f5d842d5d459d79bf85ad4fbf004e46bbf417c0d5"},
+    {file = "viztracer-0.16.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a96df402baacdca90c23559c4632e517db2e91628d191a7670d95809960ca8e"},
+    {file = "viztracer-0.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff04b25518eac932fec618c8297794c9894ac75db543b1c872cea945ae986feb"},
+    {file = "viztracer-0.16.3-cp310-cp310-win32.whl", hash = "sha256:8f56dad6111e1f3a0bd1f6de541d87c0c145fd88d4fd2b613b0c0d1f538b1a29"},
+    {file = "viztracer-0.16.3-cp310-cp310-win_amd64.whl", hash = "sha256:59c32b87b4c5ba25b78dcb993b255512106b669042ce2b31bb7b6a92edc43d67"},
+    {file = "viztracer-0.16.3-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:cca0a017635f6ade7cd73474bcdc19b2730cdc468f338912afe749234c6ebe30"},
+    {file = "viztracer-0.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8d6a938c197f4f723ad2f8d7b8e1aa0449e249dd4702e67445aaf42392786378"},
+    {file = "viztracer-0.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8721e1fd177b4abff0cbee141a31d6b819867833c92866f238815b321178c6df"},
+    {file = "viztracer-0.16.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73c0e88ecc68572599405cca54f52d7d9b7dc811992bf8edbee1860486627542"},
+    {file = "viztracer-0.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73697d43ed42f6e5110166387c3b4d76b4e181bf70822bac3f7f3e39b12be21e"},
+    {file = "viztracer-0.16.3-cp311-cp311-win32.whl", hash = "sha256:dac628f38a23154a184bd5f37e215d8ada83e33892593036112584dec83b7369"},
+    {file = "viztracer-0.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:13df50118ff0e3266c32b66f0ff26df202f7c4d9583a550dc537098303141cec"},
+    {file = "viztracer-0.16.3-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:4f07b263abe9ade8390253eebdd4658eb44288e98d1b7b9afae42a54d15197f1"},
+    {file = "viztracer-0.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f4b0b59cd97f7d6fb37766105cb062d042df87648670f560a3d730050026087"},
+    {file = "viztracer-0.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a2f9b2bf4f8e051cf9ee70bd7e6ff91c33239bcd01fa37005423915bfccaa64"},
+    {file = "viztracer-0.16.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69971a9b24801259511545ec2a3b5a4f90733f64fca799268fb6d64d72c9e93e"},
+    {file = "viztracer-0.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2f208a89c79a87ba563ee39f035df924a0109c4a2300a8098181e25f1f8afea"},
+    {file = "viztracer-0.16.3-cp312-cp312-win32.whl", hash = "sha256:bf23e06d8f9a870711a3441123c364ac6a5d0caa288c6acdd116212f81e46b2a"},
+    {file = "viztracer-0.16.3-cp312-cp312-win_amd64.whl", hash = "sha256:594e9dabf5cca584654d6813844be0377ae292e8dd507a013e9e427fd10d6fbd"},
+    {file = "viztracer-0.16.3-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:38d330348f6be0f17628657a2e454b760de40383f3065ad48fe6e2ae57478d7a"},
+    {file = "viztracer-0.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bbb88d7cbfe3d12021f97d7f58b7a21eae20d799ea7092f55d2a60eff1dbe2"},
+    {file = "viztracer-0.16.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bf1378cb93f62e58976ee31d394ad9b667eca5d0edfe8371609e2e68c6427e03"},
+    {file = "viztracer-0.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7c5bad11791c952b107f88b3a6a2a39848b0d0d6b8499222575854789722936"},
+    {file = "viztracer-0.16.3-cp39-cp39-win32.whl", hash = "sha256:65d072348f96e402dd28d21e36e6d3f513f26dc79bf89cbde0efe594f239f8f5"},
+    {file = "viztracer-0.16.3-cp39-cp39-win_amd64.whl", hash = "sha256:b8e35a109e9b1d5515ffeb0806e834274c0133a73d0a2a2b2fd24f031a1f43b3"},
+    {file = "viztracer-0.16.3.tar.gz", hash = "sha256:943cb874cf92cdc786cd87938ac64ea081e3ae06ef73f577deac5b4a2a9621d5"},
+]
+
+[[package]]
+name = "wcwidth"
+version = "0.2.13"
+summary = "Measures the displayed width of unicode strings in a terminal"
+groups = ["dev"]
+dependencies = [
+    "backports-functools-lru-cache>=1.2.1; python_version < \"3.2\"",
+]
+files = [
+    {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
+    {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
+]
+
+[[package]]
+name = "wheel"
+version = "0.44.0"
+requires_python = ">=3.8"
+summary = "A built-package format for Python"
+groups = ["dev"]
+files = [
+    {file = "wheel-0.44.0-py3-none-any.whl", hash = "sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f"},
+    {file = "wheel-0.44.0.tar.gz", hash = "sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49"},
+]
+
+[[package]]
+name = "xdoctest"
+version = "1.2.0"
+requires_python = ">=3.8"
+summary = "A rewrite of the builtin doctest module"
+groups = ["dev"]
+files = [
+    {file = "xdoctest-1.2.0-py3-none-any.whl", hash = "sha256:0f1ecf5939a687bd1fc8deefbff1743c65419cce26dff908f8b84c93fbe486bc"},
+    {file = "xdoctest-1.2.0.tar.gz", hash = "sha256:d8cfca6d8991e488d33f756e600d35b9fdf5efd5c3a249d644efcbbbd2ed5863"},
+]
+
+[[package]]
+name = "zipp"
+version = "3.20.2"
+requires_python = ">=3.8"
+summary = "Backport of pathlib-compatible object wrapper for zip files"
+groups = ["dev"]
+marker = "python_version < \"3.10\""
+files = [
+    {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"},
+    {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"},
+]
diff --git a/pyproject.toml b/pyproject.toml
index ca00b931..a4d27b2e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -12,9 +12,11 @@ dependencies = [
     "typing-extensions>=4.5.0",
     "nepattern<1.0.0,>=0.7.6",
     "tarina>=0.5.8",
+    "elaina-segment>=0.4.0",
+    "elaina-flywheel>=0.6.0",
 ]
 dynamic = ["version"]
-requires-python = ">=3.8"
+requires-python = ">=3.9"
 readme = "README-EN.md"
 license = {text = "MIT"}
 keywords = [
@@ -57,6 +59,7 @@ dev = [
     "fix-future-annotations>=0.4.0",
     "isort>=5.13.2",
     "black>=24.2.0",
+    "msgspec>=0.18.6",
 ]
 
 [tool.pdm.scripts]
@@ -135,7 +138,10 @@ skip_gitignore = true
 extra_standard_library = ["typing_extensions"]
 
 [tool.pyright]
-pythonVersion = "3.8"
+pythonVersion = "3.9"
 pythonPlatform = "All"
 typeCheckingMode = "basic"
 disableBytesTypePromotions = true
+
+[tool.ruff]
+line-length = 140
\ No newline at end of file
diff --git a/src/arclet/alconna/_dcls.py b/src/arclet/alconna/_dcls.py
new file mode 100644
index 00000000..8871aa6b
--- /dev/null
+++ b/src/arclet/alconna/_dcls.py
@@ -0,0 +1,22 @@
+from __future__ import annotations
+from typing import TYPE_CHECKING
+
+from dataclasses import dataclass
+
+
+if TYPE_CHECKING:
+
+    def safe_dcls_kw(
+        match_args=True,
+        kw_only=False,
+        slots=False,
+        weakref_slot=False,
+        **kwargs,
+    ) -> dict[str, bool]: ...
+else:
+    from inspect import Signature
+
+    _available_dc_attrs = set(Signature.from_callable(dataclass).parameters.keys())
+
+    def safe_dcls_kw(**kwargs):
+        return {k: v for k, v in kwargs.items() if k in _available_dc_attrs}
diff --git a/src/arclet/alconna/_stargazing/__init__.py b/src/arclet/alconna/_stargazing/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/arclet/alconna/_stargazing/compiler.py b/src/arclet/alconna/_stargazing/compiler.py
new file mode 100644
index 00000000..cfa2a220
--- /dev/null
+++ b/src/arclet/alconna/_stargazing/compiler.py
@@ -0,0 +1,295 @@
+from __future__ import annotations
+
+from collections import deque
+from typing import Any, Iterable, Sequence, overload
+
+import tarina
+from elaina_triehard import TrieHard
+
+from arclet.alconna import Alconna, Arg, Args, Arparma, HeadResult, Option, OptionResult, Subcommand, SubcommandResult
+from arclet.alconna.exceptions import ArgumentMissing, InvalidArgs, InvalidParam, NullMessage, ParamsUnmatched, UnexpectedElement
+from arclet.alconna.sistana import (
+    Analyzer,
+    Fragment,
+    LoopflowExitReason,
+    OptionPattern,
+    Preset,
+    SubcommandPattern,
+    Track,
+    Value,
+    AnalyzeSnapshot,
+)
+from arclet.alconna.sistana.err import ParsePanic, Rejected
+from arclet.alconna.sistana.model.fragment import _Fragment
+from arclet.alconna.sistana.model.pointer import PointerRole
+from arclet.alconna.sistana.model.snapshot import SubcommandTraverse
+from .flywheel import build_runes
+from elaina_segment import Buffer
+
+
+def _alc_args_to_fragments(args: Args) -> deque[_Fragment]:
+    alc_argument = args.argument
+    fragments = deque()
+
+    for ag in alc_argument:
+        if ag.field.default is tarina.const.Empty:
+            default = None
+        else:
+            default = Value(ag.field.default)
+
+        frag = Fragment(
+            name=ag.name,
+            default=default,
+        )
+        frag.apply_nepattern(ag.value)
+        fragments.append(frag)
+
+    return fragments
+
+
+@overload
+def into_sistana(alconna: Alconna) -> SubcommandPattern: ...
+
+
+@overload
+def into_sistana(alconna: Subcommand) -> SubcommandPattern: ...
+
+
+@overload
+def into_sistana(alconna: Option) -> OptionPattern: ...
+
+
+def into_sistana(alconna: Alconna | Subcommand | Option):
+    if isinstance(alconna, Alconna):
+        alconna.compile()
+
+        subcommands = {}
+        options = {}
+
+        for subcommand in alconna.options:
+            if isinstance(subcommand, Subcommand):
+                pattern = into_sistana(subcommand)
+                subcommands[subcommand.name] = pattern
+                for alias in subcommand.aliases:
+                    subcommands[alias] = pattern
+            elif isinstance(subcommand, Option):
+                pattern = into_sistana(subcommand)
+                options[subcommand.name] = pattern
+                for alias in subcommand.aliases:
+                    options[alias] = pattern
+
+        return SubcommandPattern(
+            header=alconna.command,
+            preset=Preset(
+                {
+                    alconna.name: Track(deque(_alc_args_to_fragments(alconna.args))),
+                    **{
+                        option.name: Track(deque(_alc_args_to_fragments(option.args)))
+                        for option in alconna.options
+                        if isinstance(option, Option)
+                    },
+                }
+            ),
+            options=options,
+            subcommands=subcommands,
+            prefixes=TrieHard(alconna.prefixes) if alconna.prefixes else None,
+            soft_keyword=alconna.soft_keyword,
+        )
+    elif isinstance(alconna, Subcommand):
+        subcommands = {}
+        options = {}
+
+        for subcommand in alconna.options:
+            if not isinstance(subcommand, Subcommand):
+                continue
+
+            pattern = into_sistana(subcommand)
+            subcommands[subcommand.name] = pattern
+            for alias in subcommand.aliases:
+                subcommands[alias] = pattern
+
+        for option in alconna.options:
+            if not isinstance(option, Option):
+                continue
+
+            pattern = into_sistana(option)
+            options[option.name] = pattern
+            for alias in option.aliases:
+                options[alias] = pattern
+
+        return SubcommandPattern(
+            header=alconna.name,
+            preset=Preset(
+                {
+                    alconna.name: Track(deque(_alc_args_to_fragments(alconna.args))),
+                    **{
+                        option.name: Track(deque(_alc_args_to_fragments(option.args)))
+                        for option in alconna.options
+                        if isinstance(option, Option)
+                    },
+                }
+            ),
+            options=options,
+            subcommands=subcommands,
+            soft_keyword=alconna.soft_keyword,
+        )
+    else:
+        return OptionPattern(
+            keyword=alconna.name,
+            soft_keyword=alconna.soft_keyword,
+        )
+
+
+def _reason_raise_alc_exception(reason: LoopflowExitReason) -> None:
+    if reason == LoopflowExitReason.completed:
+        return
+
+    if reason in {
+        LoopflowExitReason.unsatisfied,
+        LoopflowExitReason.previous_unsatisfied,
+        LoopflowExitReason.switch_unsatisfied_option,
+        LoopflowExitReason.unsatisfied_switch_subcommand,
+    }:
+        raise ParamsUnmatched(f"LoopflowDescription: {reason.value}")
+
+    if reason in {
+        LoopflowExitReason.out_of_data_subcommand,
+        LoopflowExitReason.out_of_data_option,
+    }:
+        raise ArgumentMissing(f"LoopflowDescription: {reason.value}")
+
+    if reason in {
+        LoopflowExitReason.prefix_expect_str,
+        LoopflowExitReason.header_expect_str,
+    }:
+        raise InvalidParam(f"LoopflowDescription: {reason.value}")
+
+    if reason in {
+        LoopflowExitReason.prefix_mismatch,
+        LoopflowExitReason.header_mismatch,
+    }:
+        raise InvalidArgs(f"LoopflowDescription: {reason.value}")
+
+    if reason == LoopflowExitReason.unexpected_segment:
+        raise UnexpectedElement(f"LoopflowDescription: {reason.value}")
+
+    if reason == LoopflowExitReason.option_duplicated_prohibited:
+        raise NullMessage(f"LoopflowDescription: {reason.value}")
+
+
+def _sistana_to_alc_result(traverses: list[SubcommandTraverse]) -> tuple[str, SubcommandResult] | None:
+    if not traverses:
+        return
+
+    first_traverse = traverses[0]
+    mix = first_traverse.mix
+
+    def extract_values_and_args(name: str):
+        track = mix.get_track(name)
+        value = ... if track.header is None else track.assignes[track.header.name]
+        args = {k: v for k, v in track.assignes.items() if track.header is None or k != track.header.name}
+        return value, args
+
+    value, args = extract_values_and_args(first_traverse.subcommand.header)
+    options = (
+        {opt: OptionResult(*extract_values_and_args(opt)) for opt in first_traverse.option_traverses._by_keyword}
+        if first_traverse.option_traverses.traverses
+        else None
+    )
+    subcommand_result = _sistana_to_alc_result(traverses[1:])
+
+    subcommands = None
+    if subcommand_result is not None:
+        subcommand_name, subcommands = subcommand_result
+        subcommands = {subcommand_name: subcommands}
+
+    return first_traverse.ref.last_value, SubcommandResult(value, args, options, subcommands)
+
+
+def dump_arparma(snapshot: AnalyzeSnapshot, message: Sequence[Any], matched: bool = True, head_matched: bool = True) -> Arparma:
+    subcommands = None
+    main_args = None
+    subcmds = None
+    options = None
+    result = _sistana_to_alc_result(snapshot.traverses)
+    if result is not None:
+        subcommands = result[1]
+        main_args = subcommands.args
+        subcmds = subcommands.subcommands
+        options = subcommands.options
+
+    return Arparma(
+        _id=-1,
+        origin=message,
+        matched=matched,
+        header_match=HeadResult(head_matched),
+        main_args=main_args,
+        subcommands=subcmds,
+        options=options,
+    )
+
+
+def process_adapt(pattern: SubcommandPattern, message: Sequence[Any]):
+    analyzer = Analyzer()
+    buffer = Buffer(build_runes(message), runes=False)
+    snapshot = pattern.prefix_entrypoint
+
+    matched = False
+    head_matched = False
+
+    try:
+        reason = analyzer.loopflow(snapshot, buffer)
+    except Exception:
+        matched = False
+    else:
+        if reason not in {LoopflowExitReason.prefix_mismatch, LoopflowExitReason.header_mismatch}:
+            head_matched = True
+
+        if reason == LoopflowExitReason.completed:
+            matched = True
+
+    return dump_arparma(snapshot, message, matched, head_matched)
+
+
+def patch_alconna(alconna: Alconna):
+    pattern = into_sistana(alconna)
+
+    alconna._sistana_pattern = pattern  # type: ignore
+    alconna._parse = lambda message, _: process_adapt(pattern, message)  # type: ignore
+
+
+def _sistana_debug(alc: Alconna, message):
+    pat = into_sistana(alc)
+
+    print(f"{pat=}, {message=}")
+    analyzer = Analyzer()
+    snapshot = pat.prefix_entrypoint
+    buffer = Buffer(build_runes(message), runes=False)
+    res = analyzer.loopflow(snapshot, buffer)
+    print(
+        res,
+        snapshot._export(),
+        dump_arparma(
+            snapshot,
+            message,
+            res == LoopflowExitReason.completed,
+            res in {LoopflowExitReason.prefix_mismatch, LoopflowExitReason.header_mismatch},
+        ),
+    )
+
+
+def patch_global(debug: bool = False):
+    def cached_parse(self: Alconna, message, _):
+        if hasattr(self, "_sistana_pattern"):
+            pattern = self._sistana_pattern  # type: ignore
+        else:
+            pattern = into_sistana(self)
+            self._sistana_pattern = pattern  # type: ignore
+            # self._sistana_debug = lambda s, message: _sistana_debug(pattern, message)  # type: ignore
+
+        return process_adapt(pattern, message)
+
+    Alconna._parse = cached_parse  # type: ignore
+
+    if debug:
+        Alconna._sistana_debug = _sistana_debug  # type: ignore
diff --git a/src/arclet/alconna/_stargazing/flywheel.py b/src/arclet/alconna/_stargazing/flywheel.py
new file mode 100644
index 00000000..eb0f6455
--- /dev/null
+++ b/src/arclet/alconna/_stargazing/flywheel.py
@@ -0,0 +1,12 @@
+from __future__ import annotations
+from typing import Sequence, TypeVar
+
+from elaina_segment import Runes, build_runes as _build_runes
+from flywheel import wrap_anycast
+
+T = TypeVar("T")
+
+@wrap_anycast
+def build_runes(input: Sequence[T]) -> Runes[T]:
+    return _build_runes(input)
+
diff --git a/src/arclet/alconna/args.py b/src/arclet/alconna/args.py
index 0ca7c583..bf7c76a8 100644
--- a/src/arclet/alconna/args.py
+++ b/src/arclet/alconna/args.py
@@ -3,24 +3,17 @@
 import dataclasses as dc
 import inspect
 import re
-import sys
 from enum import Enum
 from functools import partial
 from typing import Any, Callable, Generic, Iterable, List, Sequence, TypeVar, Union, cast
-from typing_extensions import Self
 
 from nepattern import ANY, NONE, AntiPattern, BasePattern, MatchMode, RawStr, UnionPattern, parser
 from tarina import Empty, get_signature, lang
+from typing_extensions import Self
 
 from .exceptions import InvalidArgs
-from .typing import TAValue, AllParam, KeyWordVar, KWBool, MultiKeyWordVar, MultiVar, UnpackVar
-
-
-def safe_dcls_kw(**kwargs):
-    if sys.version_info < (3, 10):  # pragma: no cover
-        kwargs.pop("slots")
-    return kwargs
-
+from .typing import AllParam, KeyWordVar, KWBool, MultiKeyWordVar, MultiVar, TAValue, UnpackVar
+from ._dcls import safe_dcls_kw
 
 _T = TypeVar("_T")
 
@@ -244,7 +237,7 @@ def from_callable(cls, target: Callable, kw_sep: str = "=") -> tuple[Args, bool]
                 anno = type(de) if de not in {Empty, None} else ANY
             if param.kind == param.KEYWORD_ONLY:
                 if anno == bool:
-                    anno = KWBool(f"(?:-*no)?-*{name}", MatchMode.REGEX_CONVERT, bool, lambda _, x: not x[0].lstrip("-").startswith('no'))  # noqa: E501
+                    anno = KWBool(f"(?:-*no)?-*{name}", MatchMode.REGEX_CONVERT, bool, lambda _, x: not x[0].lstrip("-").startswith("no"))  # noqa: E501
                 anno = KeyWordVar(anno, sep=kw_sep)
             if param.kind == param.VAR_POSITIONAL:
                 anno = MultiVar(anno, "*")
diff --git a/src/arclet/alconna/base.py b/src/arclet/alconna/base.py
index c520e004..6677e116 100644
--- a/src/arclet/alconna/base.py
+++ b/src/arclet/alconna/base.py
@@ -165,6 +165,8 @@ class Option(CommandNode):
     """命令选项别名"""
     compact: bool
     "是否允许名称与后随参数之间无分隔符"
+    soft_keyword: bool = False
+    "是否为软关键字；仅 Sistana 支持该特性。"
 
     def __init__(
         self,
@@ -179,6 +181,7 @@ def __init__(
         requires: str | list[str] | tuple[str, ...] | set[str] | None = None,
         compact: bool = False,
         priority: int = 0,
+        soft_keyword: bool = False
     ):
         """初始化命令选项
 
@@ -194,10 +197,12 @@ def __init__(
             requires (str | list[str] | tuple[str, ...] | set[str] | None, optional): 命令选项需求前缀
             compact (bool, optional): 是否允许名称与后随参数之间无分隔符
             priority (int, optional): 命令选项优先级
+            soft_keyword (bool, optional): 是否为软关键字；仅 Sistana 支持该特性。
         """
 
         self.priority = priority
         self.compact = compact
+        self.soft_keyword = soft_keyword
         if default is not Empty and not isinstance(default, (OptionResult, SubcommandResult)):
             default = OptionResult(default)
         super().__init__(name, args, alias, dest, default, action, separators, help_text, requires)
@@ -270,6 +275,8 @@ class Subcommand(CommandNode):
     """子命令默认值"""
     options: list[Option | Subcommand]
     """子命令包含的选项与子命令"""
+    soft_keyword: bool = False
+    "是否为软关键字；仅 Sistana 支持该特性。"
 
     def __init__(
         self,
@@ -281,6 +288,7 @@ def __init__(
         separators: str | Sequence[str] | set[str] | None = None,
         help_text: str | None = None,
         requires: str | list[str] | tuple[str, ...] | set[str] | None = None,
+        soft_keyword: bool = False
     ):
         """初始化子命令
 
@@ -311,6 +319,7 @@ def __init__(
         if self.default is Empty and (defaults := {arg.name: arg.field.default for arg in self.args.argument if arg.field.default is not Empty}):
             self.default = SubcommandResult(args=defaults)
         self._hash = self._calc_hash()
+        self.soft_keyword = soft_keyword
 
     def __add__(self, other: Option | Args | Arg | str) -> Self:
         """连接子命令与命令选项或命令节点
diff --git a/src/arclet/alconna/model.py b/src/arclet/alconna/model.py
index 517f733e..c07fb142 100644
--- a/src/arclet/alconna/model.py
+++ b/src/arclet/alconna/model.py
@@ -1,34 +1,80 @@
+from __future__ import annotations
 from dataclasses import dataclass
+from typing import TYPE_CHECKING, Any, Optional, Dict
+
+from nepattern import BasePattern
 
 _repr_ = lambda self: "(" + " ".join([f"{k}={getattr(self, k, ...)!r}" for k in self.__slots__]) + ")"
 
 
 @dataclass(init=False, eq=True)
 class Sentence:
+    """句段
+
+    句段由 `Analyser` 编译而来, 代表选项或者子命令的需求前缀。
+
+    Attributes:
+        name (str): 句段名称
+    """
+
     __slots__ = ("name",)
     __str__ = lambda self: self.name  # type: ignore
     __repr__ = lambda self: self.name  # type: ignore
 
-    def __init__(self, name):
+    if TYPE_CHECKING:
+        name: str
+
+    def __init__(self, name: str) -> None:
         self.name = name
 
 
 @dataclass(init=False, eq=True)
 class OptionResult:
+    """选项解析结果
+
+    Attributes:
+        value (Any): 选项值
+        args (dict[str, Any]): 选项参数解析结果
+    """
+
     __slots__ = ("value", "args")
     __repr__ = _repr_
 
-    def __init__(self, value=Ellipsis, args=None):
+    value: Any
+    args: Dict[str, Any]
+
+    def __init__(self, value: Any = Ellipsis, args: Optional[Dict[str, Any]] = None) -> None:
         self.value = value
         self.args = args or {}
 
 
 @dataclass(init=False, eq=True)
 class SubcommandResult:
+    """子命令解析结果
+
+    Attributes:
+        value (Any): 子命令值
+        args (dict[str, Any]): 子命令参数解析结果
+        options (dict[str, OptionResult]): 子命令的子选项解析结果
+        subcommands (dict[str, SubcommandResult]): 子命令的子子命令解析结果
+    """
+
     __slots__ = ("value", "args", "options", "subcommands")
     __repr__ = _repr_
 
-    def __init__(self, value=Ellipsis, args=None, options=None, subcommands=None):
+    if TYPE_CHECKING:
+        value: Any
+        args: Dict[str, Any]
+        options: Dict[str, OptionResult]
+        subcommands: Dict[str, SubcommandResult]
+
+    def __init__(
+        self,
+        value: Any = Ellipsis,
+        args: Optional[Dict[str, Any]] = None,
+        options: Optional[Dict[str, OptionResult]] = None,
+        subcommands: Optional[Dict[str, SubcommandResult]] = None,
+    ) -> None:
         self.value = value
         self.args = args or {}
         self.options = options or {}
@@ -37,13 +83,41 @@ def __init__(self, value=Ellipsis, args=None, options=None, subcommands=None):
 
 @dataclass(init=False, eq=True)
 class HeadResult:
+    """命令头解析结果
+
+    Attributes:
+        origin (Any): 命令头原始值
+        result (Any): 命令头解析结果
+        matched (bool): 命令头是否匹配
+        groups (dict[str, Any]): 命令头匹配组
+    """
+
     __slots__ = ("origin", "result", "matched", "groups")
     __repr__ = _repr_
 
-    def __init__(self, origin=None, result=None, matched=False, groups=None, fixes=None):
+    if TYPE_CHECKING:
+        origin: Any
+        result: Any
+        matched: bool
+        groups: Dict[str, Any]
+
+    def __init__(
+        self,
+        origin: Any = None,
+        result: Any = None,
+        matched: bool = False,
+        groups: Optional[Dict[str, str]] = None,
+        fixes: Optional[Dict[str, BasePattern]] = None,
+    ) -> None:
         self.origin = origin
         self.result = result
         self.matched = matched
         self.groups = groups or {}
         if fixes:
-            self.groups.update({k: v.validate(self.groups[k])._value for k, v in fixes.items() if k in self.groups})  # noqa
+            self.groups.update(
+                {
+                    k: v.validate(self.groups[k])._value
+                    for k, v in fixes.items()
+                    if k in self.groups
+                }
+            )
diff --git a/src/arclet/alconna/model.pyi b/src/arclet/alconna/model.pyi
deleted file mode 100644
index 7638e593..00000000
--- a/src/arclet/alconna/model.pyi
+++ /dev/null
@@ -1,74 +0,0 @@
-from __future__ import annotations
-
-from typing import Any
-
-from nepattern import BasePattern
-
-class Sentence:
-    """句段
-
-    句段由 `Analyser` 编译而来, 代表选项或者子命令的需求前缀。
-
-    Attributes:
-        name (str): 句段名称
-    """
-
-    name: str
-    def __init__(self, name: str) -> None: ...
-
-class OptionResult:
-    """选项解析结果
-
-    Attributes:
-        value (Any): 选项值
-        args (dict[str, Any]): 选项参数解析结果
-    """
-
-    value: Any
-    args: dict[str, Any]
-    def __init__(self, value: Any = ..., args: dict[str, Any] | None = ...) -> None: ...
-
-class SubcommandResult:
-    """子命令解析结果
-
-    Attributes:
-        value (Any): 子命令值
-        args (dict[str, Any]): 子命令参数解析结果
-        options (dict[str, OptionResult]): 子命令的子选项解析结果
-        subcommands (dict[str, SubcommandResult]): 子命令的子子命令解析结果
-    """
-
-    value: Any
-    args: dict[str, Any]
-    options: dict[str, OptionResult]
-    subcommands: dict[str, SubcommandResult]
-    def __init__(
-        self,
-        value: Any = ...,
-        args: dict[str, Any] | None = ...,
-        options: dict[str, OptionResult] | None = ...,
-        subcommands: dict[str, SubcommandResult] | None = ...,
-    ) -> None: ...
-
-class HeadResult:
-    """命令头解析结果
-
-    Attributes:
-        origin (Any): 命令头原始值
-        result (Any): 命令头解析结果
-        matched (bool): 命令头是否匹配
-        groups (dict[str, Any]): 命令头匹配组
-    """
-
-    origin: Any
-    result: Any
-    matched: bool
-    groups: dict[str, Any]
-    def __init__(
-        self,
-        origin: Any = ...,
-        result: Any = ...,
-        matched: bool = ...,
-        groups: dict[str, str] | None = ...,
-        fixes: dict[str, BasePattern] | None = ...,
-    ) -> None: ...
diff --git a/src/arclet/alconna/sistana/__init__.py b/src/arclet/alconna/sistana/__init__.py
new file mode 100644
index 00000000..7f282670
--- /dev/null
+++ b/src/arclet/alconna/sistana/__init__.py
@@ -0,0 +1,43 @@
+from elaina_segment import SEPARATORS as SEPARATORS
+from elaina_segment import AheadToken as AheadToken
+from elaina_segment import Buffer as Buffer
+from elaina_segment import Quoted as Quoted
+from elaina_segment import Rune as Rune
+from elaina_segment import Runes as Runes
+from elaina_segment import Segment as Segment
+from elaina_segment import SegmentToken as SegmentToken
+from elaina_segment import UnmatchedQuoted as UnmatchedQuoted
+
+from .analyzer import Analyzer as Analyzer
+from .analyzer import LoopflowExitReason as LoopflowExitReason
+from .err import CaptureRejected as CaptureRejected
+from .err import ParseCancelled as ParseCancelled
+from .err import ParsePanic as ParsePanic
+from .err import ReasonableParseError as ReasonableParseError
+from .err import ReceivePanic as ReceivePanic
+from .err import RegexMismatch as RegexMismatch
+from .err import Rejected as Rejected
+from .err import TransformPanic as TransformPanic
+from .err import UnexpectedType as UnexpectedType
+from .err import ValidateRejected as ValidateRejected
+from .fragment import Fragment as Fragment
+from .model import AccumRx as AccumRx
+from .model import AnalyzeSnapshot as AnalyzeSnapshot
+from .model import Capture as Capture
+from .model import CaptureResult as CaptureResult
+from .model import ConstRx as ConstRx
+from .model import CountRx as CountRx
+from .model import Mix as Mix
+from .model import ObjectCapture as ObjectCapture
+from .model import OptionPattern as OptionPattern
+from .model import PlainCapture as PlainCapture
+from .model import Preset as Preset
+from .model import RegexCapture as RegexCapture
+from .model import Rx as Rx
+from .model import RxFetch as RxFetch
+from .model import RxPrev as RxPrev
+from .model import RxPut as RxPut
+from .model import SimpleCapture as SimpleCapture
+from .model import SubcommandPattern as SubcommandPattern
+from .model import Track as Track
+from .some import Value as Value
diff --git a/src/arclet/alconna/sistana/analyzer.py b/src/arclet/alconna/sistana/analyzer.py
new file mode 100644
index 00000000..731a32f7
--- /dev/null
+++ b/src/arclet/alconna/sistana/analyzer.py
@@ -0,0 +1,196 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from enum import Enum
+from typing import Generic, TypeVar
+
+from elaina_segment import Buffer
+from elaina_segment.err import OutOfData
+
+from .err import ParsePanic, Rejected
+from .model.snapshot import AnalyzeSnapshot, ProcessingState
+
+T = TypeVar("T")
+
+
+class LoopflowExitReason(str, Enum):
+    completed = "completed"
+
+    unsatisfied = "continuation@process#unsatisfied"
+    out_of_data_subcommand = "continuation@subcommand#out-of-data"
+    out_of_data_option = "continuation@subcommand#out-of-data"
+    previous_unsatisfied = "continuation@option-switch#previous-unsatisfied"
+    unsatisfied_switch_option = "continuation@option-switch#unsatisfied"
+    unsatisfied_switch_subcommand = "continuation@subcommand-switch#unsatisfied"
+
+    prefix_expect_str = "panic@prefix-match#expect-str"
+    prefix_mismatch = "panic@prefix-match#mismatch"
+    header_expect_str = "panic@header-match#expect-str"
+    header_mismatch = "panic@header-match#mismatch"
+    unexpected_segment = "panic@subcommand-process#unexpected-segment"
+    option_duplicated_prohibited = "panic@option-process#duplicated"
+
+    def __str__(self):
+        return self.value
+
+    def __repr__(self):
+        return f"<loopflow(::) => {self.value}>"
+
+
+@dataclass
+class Analyzer(Generic[T]):
+    complete_on_determined: bool = False
+
+    def loopflow(self, snapshot: AnalyzeSnapshot, buffer: Buffer[T]) -> LoopflowExitReason:
+        mix = snapshot.mix
+
+        while True:
+            state = snapshot.state
+            context = snapshot.context
+
+            try:
+                token = buffer.next(context.separators)
+            except OutOfData:
+                if mix.satisfied:
+                    mix.complete()
+                    snapshot.determine()
+                    return LoopflowExitReason.completed
+
+                # 这里如果没有 satisfied，如果是 option 的 track，则需要 reset
+                # 从 Buffer 吃掉的东西？我才不还。
+                if state is ProcessingState.OPTION:
+                    mix.option_tracks[snapshot.option].reset()  # type: ignore
+
+                return LoopflowExitReason.unsatisfied
+
+            if state is ProcessingState.PREFIX:
+                if context.prefixes is not None:
+                    if not isinstance(token.val, str):
+                        return LoopflowExitReason.prefix_expect_str
+
+                    if context.prefixes is not None:
+                        prefix = context.prefixes.longest_prefix(buffer.first()).key  # type: ignore
+                        if prefix is None:
+                            return LoopflowExitReason.prefix_mismatch
+
+                        token.apply()
+                        buffer.pushleft(token.val[len(prefix) :])
+
+                snapshot.state = ProcessingState.HEADER
+            elif state is ProcessingState.HEADER:
+                if not isinstance(token.val, str):
+                    return LoopflowExitReason.header_expect_str
+
+                token.apply()
+
+                if token.val == context.header:
+                    pass  # do nothing
+                elif context.compact_header and token.val.startswith(context.header):
+                    v = token.val[len(context.header) :]
+                    if v:
+                        buffer.pushleft(v)
+
+                else:
+                    return LoopflowExitReason.header_mismatch
+
+                track = mix.command_tracks[tuple(snapshot.command)]
+                track.emit_header(mix, token.val)
+
+                snapshot.state = ProcessingState.COMMAND
+            else:
+                if isinstance(token.val, str):
+                    if (subcommand_info := snapshot.get_subcommand(context, token.val)) is not None:
+                        subcommand, tail = subcommand_info
+                        enter_forward = False
+
+                        if state is ProcessingState.OPTION:
+                            owner, keyword = snapshot.option  # type: ignore
+                            current_track = mix.option_tracks[owner, keyword]
+
+                            if not current_track.satisfied:
+                                if not subcommand.soft_keyword:
+                                    mix.option_tracks[owner, keyword].reset()
+                                    return LoopflowExitReason.unsatisfied_switch_option
+                                else:
+                                    enter_forward = True
+                            else:
+                                current_track.complete(mix)
+
+                        if not enter_forward and snapshot.stage_satisfied or not subcommand.enter_instantly:
+                            token.apply()
+                            mix.complete()
+
+                            if tail is not None:
+                                buffer.pushleft(tail)
+
+                            snapshot.enter_subcommand(token.val, subcommand)
+                            continue
+                        elif not subcommand.soft_keyword:
+                            return LoopflowExitReason.unsatisfied_switch_subcommand
+
+                    elif (option_info := snapshot.get_option(token.val)) is not None:
+                        target_option, target_owner, tail = option_info
+                        enter_forward = False
+
+                        if state is ProcessingState.OPTION:
+                            owner, keyword = snapshot.option  # type: ignore
+                            current_track = mix.option_tracks[owner, keyword]
+
+                            if not current_track.satisfied:
+                                if not target_option.soft_keyword:
+                                    mix.option_tracks[target_owner, target_option.keyword].reset()
+                                    return LoopflowExitReason.previous_unsatisfied
+                                else:
+                                    enter_forward = True
+                            else:
+                                current_track.complete(mix)
+                                snapshot.state = ProcessingState.COMMAND
+
+                        if not enter_forward and (not target_option.soft_keyword or snapshot.stage_satisfied):
+                            if not snapshot.enter_option(token.val, target_owner, target_option.keyword, target_option):
+                                return LoopflowExitReason.option_duplicated_prohibited
+
+                            token.apply()
+
+                            if tail is not None:
+                                buffer.pushleft(tail)
+
+                            continue
+
+                if state is ProcessingState.COMMAND:
+                    track = mix.command_tracks[tuple(snapshot.command)]
+
+                    try:
+                        response = track.forward(mix, buffer, context.separators)
+                    except OutOfData:
+                        # 称不上是 context switch，continuation 不改变 context。
+                        return LoopflowExitReason.out_of_data_subcommand
+                    except (Rejected, ParsePanic):
+                        raise
+                    except Exception as e:
+                        raise ParsePanic from e
+                    else:
+                        if response is None:
+                            if self.complete_on_determined and mix.satisfied:
+                                mix.complete()
+                                snapshot.determine()
+                                return LoopflowExitReason.completed
+
+                            # track 上没有 fragments 可供分配了，此时又没有再流转到其他 traverse
+                            return LoopflowExitReason.unexpected_segment
+                else:
+                    track = mix.option_tracks[snapshot.option]  # type: ignore
+                    opt = snapshot._ref_cache_option[snapshot.option]  # type: ignore
+
+                    try:
+                        response = track.forward(mix, buffer, opt.separators)
+                    except OutOfData:
+                        mix.option_tracks[snapshot.option].reset()  # type: ignore
+                        return LoopflowExitReason.out_of_data_option
+                    except (Rejected, ParsePanic):
+                        raise
+                    except Exception as e:
+                        raise ParsePanic from e
+                    else:
+                        if response is None:
+                            snapshot.state = ProcessingState.COMMAND
diff --git a/src/arclet/alconna/sistana/err.py b/src/arclet/alconna/sistana/err.py
new file mode 100644
index 00000000..88545d70
--- /dev/null
+++ b/src/arclet/alconna/sistana/err.py
@@ -0,0 +1,47 @@
+from __future__ import annotations
+
+import re
+from dataclasses import dataclass
+from typing import Any
+
+
+class ReasonableParseError(Exception): ...
+
+
+class ParseCancelled(ReasonableParseError): ...
+
+
+class Rejected(ReasonableParseError): ...
+
+
+class CaptureRejected(Rejected): ...
+
+
+class ValidateRejected(Rejected): ...
+
+
+@dataclass
+class UnexpectedType(CaptureRejected):
+    expected: type | tuple[type, ...]
+    got: type | Any
+
+    def __str__(self):
+        return f"Expected {self.expected}, got {self.got}"
+
+
+@dataclass
+class RegexMismatch(CaptureRejected):
+    pattern: str | re.Pattern[str]
+    raw: str
+
+    def __str__(self):
+        return f"Pattern {self.pattern!r} does not match {self.raw!r}"
+
+
+class ParsePanic(Exception): ...
+
+
+class TransformPanic(ParsePanic): ...
+
+
+class ReceivePanic(ParsePanic): ...
diff --git a/src/arclet/alconna/sistana/fragment.py b/src/arclet/alconna/sistana/fragment.py
new file mode 100644
index 00000000..aed84333
--- /dev/null
+++ b/src/arclet/alconna/sistana/fragment.py
@@ -0,0 +1,95 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Literal
+from dataclasses import dataclass
+from elaina_segment import Segment, Quoted, UnmatchedQuoted
+
+from arclet.alconna._dcls import safe_dcls_kw
+
+from .model.capture import RegexCapture
+from .model.fragment import _Fragment
+from .some import Some
+
+if TYPE_CHECKING:
+    from nepattern import BasePattern
+
+
+@dataclass(**safe_dcls_kw(slots=True))
+class Fragment(_Fragment):
+    type: Some[Any] = None
+    cast: bool = True
+    prefer_checker: Literal["msgspec", "nepattern"] = "nepattern"
+
+    def __post_init__(self):
+        if self.type is not None:
+            if self.prefer_checker == "msgspec":
+                self.apply_msgspec()
+            elif self.prefer_checker == "nepattern":
+                self.apply_nepattern()
+            else:
+                raise ValueError("Invalid prefer_checker value.")
+
+    def apply_msgspec(self):
+        if self.type is None:
+            return self
+
+        t = self.type.value
+
+        from msgspec import convert, ValidationError
+
+        def _validate(v: Segment):
+            if not isinstance(v, (str, Quoted, UnmatchedQuoted)):
+                return False
+
+            v = str(v)
+
+            try:
+                convert(v, t)
+            except ValidationError:
+                return False
+
+            return True
+
+        self.validator = _validate
+
+        if self.cast:
+
+            def _transform(v: Segment):
+                return convert(str(v), t)
+
+            self.transformer = _transform
+        
+        return self
+
+    def apply_nepattern(self, pat: BasePattern | None = None, capture_mode: bool = False):
+        if pat is None:
+            if self.type is None:
+                return self
+
+            from nepattern import BasePattern
+
+            pat = BasePattern.to(self.type.value)
+            assert pat is not None
+
+        def _validate(v: Segment):
+            if isinstance(v, (Quoted, UnmatchedQuoted)):
+                if isinstance(v.ref, str):
+                    v = str(v)
+                else:
+                    v = v.ref[0]
+            return pat.validate(v).success
+
+        self.validator = _validate
+        if self.cast:
+            def _transform(v: Segment):
+
+                if isinstance(v, (Quoted, UnmatchedQuoted)):
+                    if isinstance(v.ref, str):
+                        v = str(v)
+                    else:
+                        v = v.ref[0]
+
+                return pat.validate(v).value()
+
+            self.transformer = _transform
+        return self
\ No newline at end of file
diff --git a/src/arclet/alconna/sistana/model/__init__.py b/src/arclet/alconna/sistana/model/__init__.py
new file mode 100644
index 00000000..9dd6103d
--- /dev/null
+++ b/src/arclet/alconna/sistana/model/__init__.py
@@ -0,0 +1,19 @@
+from .capture import Capture as Capture
+from .capture import CaptureResult as CaptureResult
+from .capture import ObjectCapture as ObjectCapture
+from .capture import PlainCapture as PlainCapture
+from .capture import RegexCapture as RegexCapture
+from .capture import SimpleCapture as SimpleCapture
+from .mix import Mix as Mix
+from .mix import Preset as Preset
+from .mix import Track as Track
+from .pattern import OptionPattern as OptionPattern
+from .pattern import SubcommandPattern as SubcommandPattern
+from .receiver import AccumRx as AccumRx
+from .receiver import ConstRx as ConstRx
+from .receiver import CountRx as CountRx
+from .receiver import Rx as Rx
+from .receiver import RxFetch as RxFetch
+from .receiver import RxPrev as RxPrev
+from .receiver import RxPut as RxPut
+from .snapshot import AnalyzeSnapshot as AnalyzeSnapshot
diff --git a/src/arclet/alconna/sistana/model/capture.py b/src/arclet/alconna/sistana/model/capture.py
new file mode 100644
index 00000000..0fbce9a0
--- /dev/null
+++ b/src/arclet/alconna/sistana/model/capture.py
@@ -0,0 +1,95 @@
+from __future__ import annotations
+
+import re
+from dataclasses import dataclass
+from typing import Any, Generic, Tuple, TypeVar, Union
+
+from elaina_segment import Quoted, UnmatchedQuoted
+from typing_extensions import TypeAlias
+
+from arclet.alconna._dcls import safe_dcls_kw
+
+from ..some import Some, Value
+
+from elaina_segment.buffer import AheadToken, Buffer, SegmentToken
+from ..err import RegexMismatch, UnexpectedType
+
+T = TypeVar("T")
+
+CaptureResult: TypeAlias = "Tuple[T, Some[Any], Union[SegmentToken[T], AheadToken[T]]]"
+
+
+class Capture(Generic[T]):
+    def capture(self, buffer: Buffer[Any], separators: str) -> CaptureResult[T]: ...
+
+
+class SimpleCapture(Capture[Any]):
+    def capture(self, buffer: Buffer[Any], separators: str) -> CaptureResult[Any]:
+        token = buffer.next(separators)
+        return token.val, None, token
+
+
+@dataclass(**safe_dcls_kw(eq=True, unsafe_hash=True, slots=True))
+class ObjectCapture(Capture[T]):
+    type: type[T] | tuple[type[T], ...]
+
+    def capture(self, buffer: Buffer[Any], separators: str) -> CaptureResult[T]:
+        token = buffer.next(separators)
+        if not isinstance(token.val, self.type):
+            raise UnexpectedType(self.type, type(token.val))
+
+        return token.val, None, token
+
+
+Plain: TypeAlias = "Union[str, Quoted[str], UnmatchedQuoted[str]]"
+
+
+@dataclass(**safe_dcls_kw(eq=True, unsafe_hash=True, slots=True))
+class PlainCapture(Capture[Plain]):
+    def capture(self, buffer: Buffer[Any], separators: str) -> CaptureResult[Plain]:
+        token = buffer.next(separators)
+
+        if isinstance(token.val, str):
+            return token.val, None, token
+        elif isinstance(token.val, (Quoted, UnmatchedQuoted)):
+            if isinstance(token.val.ref, str):
+                val = token.val.ref
+            elif next((i for i in token.val.ref if not isinstance(i, str)), None) is None:
+                val = "".join(token.val.ref)
+            else:
+                raise UnexpectedType(str, type(next(i for i in token.val.ref if not isinstance(i, str))))
+
+            return val, None, token
+        else:
+            raise UnexpectedType(str, type(token.val))
+
+
+@dataclass(**safe_dcls_kw(eq=True, unsafe_hash=True, slots=True))
+class RegexCapture(Capture[re.Match[str]]):
+    pattern: str | re.Pattern[str]
+    match_quote: bool = False
+
+    def capture(self, buffer: Buffer[Any], separators: str) -> CaptureResult[re.Match[str]]:
+        token = buffer.next(separators)
+
+        if isinstance(token.val, str):
+            val = token.val
+        elif isinstance(token.val, (Quoted, UnmatchedQuoted)) and self.match_quote:
+            if isinstance(token.val.ref, str):
+                val = token.val.ref
+            elif next((i for i in token.val.ref if not isinstance(i, str)), None) is None:
+                val = "".join(token.val.ref)
+            else:
+                raise UnexpectedType(str, type(next(i for i in token.val.ref if not isinstance(i, str))))
+        else:
+            raise UnexpectedType(str, token.val)
+
+        match = re.match(self.pattern, val)
+        if not match:
+            raise RegexMismatch(self.pattern, val)
+
+        last = match.string[match.end() :]
+        if last:
+            return match, Value(last), token
+
+        return match, None, token
diff --git a/src/arclet/alconna/sistana/model/fragment.py b/src/arclet/alconna/sistana/model/fragment.py
new file mode 100644
index 00000000..235d0a10
--- /dev/null
+++ b/src/arclet/alconna/sistana/model/fragment.py
@@ -0,0 +1,46 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import Any, Callable, Iterable
+
+from arclet.alconna._dcls import safe_dcls_kw
+
+from ..some import Some
+from .capture import Capture, SimpleCapture
+from .receiver import Rx
+
+
+@dataclass(**safe_dcls_kw(slots=True))
+class _Fragment:
+    name: str
+    variadic: bool = False
+    default: Some[Any] = None
+    export: bool = False
+
+    separators: str | None = None
+    hybrid_separators: bool = True
+
+    capture: Capture = SimpleCapture()
+    receiver: Rx[Any] = Rx()
+    validator: Callable[[Any], bool] | None = None
+    transformer: Callable[[Any], Any] | None = None
+
+
+def assert_fragments_order(fragments: Iterable[_Fragment]):
+    default_exists = False
+    variadic_exists = False
+
+    for frag in fragments:
+        if variadic_exists:
+            raise ValueError("Found fragment after a variadic fragment, which is not allowed.")
+
+        if frag.default is not None:
+            default_exists = True
+        elif default_exists and not frag.variadic:
+            raise ValueError("Found a required fragment after an optional fragment, which is not allowed.")
+
+        if frag.variadic:
+            if frag.default is not None:
+                raise ValueError("A variadic fragment cannot have a default value.")
+
+            variadic_exists = True
diff --git a/src/arclet/alconna/sistana/model/mix.py b/src/arclet/alconna/sistana/model/mix.py
new file mode 100644
index 00000000..6ce00d02
--- /dev/null
+++ b/src/arclet/alconna/sistana/model/mix.py
@@ -0,0 +1,213 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from ..err import CaptureRejected, ReceivePanic, TransformPanic, ValidateRejected
+from ..some import Value
+from .fragment import _Fragment, assert_fragments_order
+
+if TYPE_CHECKING:
+    from elaina_segment import Buffer
+
+
+class Track:
+    __slots__ = ("fragments", "header", "cursor", "max_length", "emitted")
+
+    header: _Fragment | None
+    fragments: tuple[_Fragment, ...]
+    cursor: int
+    max_length: int
+    emitted: bool
+
+    def __init__(self, fragments: tuple[_Fragment, ...], header: _Fragment | None = None):
+        self.fragments = fragments
+        self.header = header
+        self.cursor = 0
+        self.max_length = len(self.fragments)
+        self.emitted = False
+
+    @property
+    def satisfied(self):
+        return self.cursor >= self.max_length or self.fragments[self.cursor].default is not None or self.fragments[self.cursor].variadic
+
+    def complete(self, mix: Mix):
+        if self.header is not None and self.header.name not in mix.assignes and self.header.default is not None:
+            mix.assignes[self.header.name] = self.header.default.value
+
+        if self.cursor >= self.max_length:
+            return
+
+        for frag in self.fragments[self.cursor :]:
+            if frag.name not in mix.assignes and frag.default is not None:
+                mix.assignes[frag.name] = frag.default.value
+
+        last = self.fragments[-1]
+        if last.variadic and last.name not in mix.assignes:
+            mix.assignes[last.name] = []
+
+    def fetch(
+        self,
+        mix: Mix,
+        frag: _Fragment,
+        buffer: Buffer,
+        upper_separators: str,
+    ):
+        tail = None
+        token = None
+
+        def rxfetch():
+            nonlocal tail, token
+
+            if frag.separators is not None:
+                if frag.hybrid_separators:
+                    separators = frag.separators + upper_separators
+                else:
+                    separators = frag.separators
+            else:
+                separators = upper_separators
+
+            val, tail, token = frag.capture.capture(buffer, separators)
+
+            if frag.validator is not None and not frag.validator(val):
+                raise ValidateRejected
+
+            if frag.transformer is not None:
+                try:
+                    val = frag.transformer(val)
+                except Exception as e:
+                    raise TransformPanic from e
+
+            return val
+
+        def rxprev():
+            if frag.name in mix.assignes:
+                return Value(mix.assignes[frag.name])
+
+        if frag.variadic:
+
+            def rxput(val):
+                if frag.name not in mix.assignes:
+                    mix.assignes[frag.name] = []
+
+                mix.assignes[frag.name].append(val)
+        else:
+
+            def rxput(val):
+                mix.assignes[frag.name] = val
+
+        try:
+            frag.receiver.receive(rxfetch, rxprev, rxput)
+        except (CaptureRejected, ValidateRejected, TransformPanic):
+            raise
+        except Exception as e:
+            raise ReceivePanic from e
+
+        if tail is not None:
+            buffer.add_to_ahead(tail.value)
+
+        if token is not None:
+            token.apply()
+
+    def forward(
+        self,
+        mix: Mix,
+        buffer: Buffer,
+        separators: str,
+    ):
+        if self.cursor >= self.max_length:
+            return
+
+        first = self.fragments[self.cursor]
+        self.fetch(mix, first, buffer, separators)
+
+        if not first.variadic:
+            self.cursor += 1
+
+        return first
+
+    def emit_header(self, mix: Mix, segment: str):
+        self.emitted = True
+
+        if self.header is None:
+            return
+
+        header = self.header
+
+        def rxprev():
+            if header.name in mix.assignes:
+                return Value(mix.assignes[header.name])
+
+        def rxput(val):
+            mix.assignes[header.name] = val
+
+        try:
+            header.receiver.receive(lambda: segment, rxprev, rxput)
+        except (CaptureRejected, ValidateRejected, TransformPanic):
+            raise
+        except Exception as e:
+            raise ReceivePanic from e
+
+    @property
+    def assignable(self):
+        return self.cursor < self.max_length
+
+    def copy(self):
+        return Track(self.fragments, self.header)
+
+    def reset(self):
+        self.cursor = 0
+
+    def __bool__(self):
+        return bool(self.fragments)
+
+
+class Preset:
+    __slots__ = ("subcommand_track", "option_tracks")
+
+    subcommand_track: Track
+    option_tracks: dict[str, Track]
+
+    def __init__(self, subcommand_track: Track, option_tracks: dict[str, Track]):
+        self.subcommand_track = subcommand_track
+        self.option_tracks = option_tracks
+
+        assert_fragments_order(subcommand_track.fragments)
+
+        for track in self.option_tracks.values():
+            assert_fragments_order(track.fragments)
+
+
+class Mix:
+    __slots__ = ("assignes", "command_tracks", "option_tracks")
+
+    assignes: dict[str, Any]
+
+    command_tracks: dict[tuple[str, ...], Track]
+    option_tracks: dict[tuple[tuple[str, ...], str], Track]
+
+    def __init__(self):
+        self.assignes = {}
+        self.command_tracks = {}
+        self.option_tracks = {}
+
+    def complete(self):
+        for track in self.command_tracks.values():
+            track.complete(self)
+
+    @property
+    def satisfied(self):
+        for track in self.command_tracks.values():
+            if not track.satisfied:
+                return False
+
+        for track in self.option_tracks.values():
+            if not track.satisfied:
+                return False
+
+        return True
+
+    def update(self, root: tuple[str, ...], preset: Preset):
+        self.command_tracks[root] = preset.subcommand_track.copy()
+
+        for track_id, track in preset.option_tracks.items():
+            self.option_tracks[root, track_id] = track.copy()
diff --git a/src/arclet/alconna/sistana/model/pattern.py b/src/arclet/alconna/sistana/model/pattern.py
new file mode 100644
index 00000000..30d6afa3
--- /dev/null
+++ b/src/arclet/alconna/sistana/model/pattern.py
@@ -0,0 +1,188 @@
+from __future__ import annotations
+
+from dataclasses import dataclass, field
+from functools import cached_property
+from typing import TYPE_CHECKING, Iterable, MutableMapping
+
+from elaina_segment import SEPARATORS
+from tarina.trie import CharTrie, Trie
+
+from arclet.alconna._dcls import safe_dcls_kw
+
+from .fragment import assert_fragments_order
+from .mix import Preset, Track
+from .snapshot import AnalyzeSnapshot, ProcessingState
+
+if TYPE_CHECKING:
+    from .fragment import _Fragment
+
+
+@dataclass(**safe_dcls_kw(slots=True))
+class SubcommandPattern:
+    header: str
+    preset: Preset
+
+    soft_keyword: bool = False
+    separators: str = SEPARATORS
+
+    prefixes: Trie[str] | None = field(default=None)
+    compact_header: bool = False
+    enter_instantly: bool = True
+    header_fragment: _Fragment | None = None
+
+    _options: list[OptionPattern] = field(default_factory=list)
+    _compact_keywords: Trie[str] | None = field(default=None)
+    _exit_options: list[str] = field(default_factory=list)
+
+    _options_bind: MutableMapping[str, OptionPattern] = field(default_factory=dict)
+    _subcommands_bind: MutableMapping[str, SubcommandPattern] = field(default_factory=dict)
+
+    @classmethod
+    def build(
+        cls,
+        header: str,
+        *fragments: _Fragment,
+        prefixes: Iterable[str] = (),
+        compact_header: bool = False,
+        enter_instantly: bool = True,
+        separators: str = SEPARATORS,
+        soft_keyword: bool = False,
+        header_fragment: _Fragment | None = None,
+    ):
+        preset = Preset(Track(fragments, header=header_fragment), {})
+        subcommand = cls(
+            header=header,
+            preset=preset,
+            compact_header=compact_header,
+            enter_instantly=enter_instantly,
+            separators=separators,
+            soft_keyword=soft_keyword,
+            header_fragment=header_fragment,
+        )
+
+        if prefixes:
+            subcommand.prefixes = CharTrie.fromkeys(list(prefixes))  # type: ignore
+
+        return subcommand
+
+    @property
+    def root_ref(self):
+        return [self.header]
+
+    def create_snapshot(self, state: ProcessingState = ProcessingState.COMMAND):
+        snapshot = AnalyzeSnapshot(command=[self.header], state=state, traverses={(self.header,): self})
+        snapshot.mix.update((self.header,), self.preset)
+        return snapshot
+
+    @property
+    def root_entrypoint(self):
+        return self.create_snapshot()
+
+    @property
+    def prefix_entrypoint(self):
+        return self.create_snapshot(ProcessingState.PREFIX)
+
+    @property
+    def header_entrypoint(self):
+        return self.create_snapshot(ProcessingState.HEADER)
+
+    def add_track(self, name: str, fragments: tuple[_Fragment, ...], header: _Fragment | None = None):
+        assert_fragments_order(fragments)
+
+        self.preset.option_tracks[name] = Track(fragments, header=header)
+
+    def subcommand(
+        self,
+        header: str,
+        *fragments: _Fragment,
+        aliases: Iterable[str] = (),
+        soft_keyword: bool = False,
+        separators: str = SEPARATORS,
+        compact_header: bool = False,
+        compact_aliases: bool = False,
+        enter_instantly: bool = True,
+        header_fragment: _Fragment | None = None,
+    ):
+        preset = Preset(Track(fragments, header=header_fragment), {})
+        pattern = self._subcommands_bind[header] = SubcommandPattern(
+            header=header,
+            preset=preset,
+            soft_keyword=soft_keyword,
+            separators=separators,
+            compact_header=compact_header,
+            enter_instantly=enter_instantly,
+            header_fragment=header_fragment,
+        )
+        self._subcommands_bind[header] = pattern
+        for alias in aliases:
+            self._subcommands_bind[alias] = pattern
+
+        if compact_header:
+            self._compact_keywords = CharTrie.fromkeys(
+                [header, *aliases, *(self._compact_keywords or []), *(aliases if compact_aliases else [])]
+            )  # type: ignore
+
+        return pattern
+
+    def option(
+        self,
+        keyword: str,
+        *fragments: _Fragment,
+        aliases: Iterable[str] = (),
+        separators: str | None = None,
+        hybrid_separators: bool = False,
+        soft_keyword: bool = False,
+        allow_duplicate: bool = False,
+        compact_header: bool = False,
+        header_fragment: _Fragment | None = None,
+        header_separators: str | None = None,
+        forwarding: bool = True,
+    ):
+        if separators is None:
+            separators = self.separators
+        elif hybrid_separators:
+            separators = separators + self.separators
+
+        pattern = self._options_bind[keyword] = OptionPattern(
+            keyword,
+            aliases=list(aliases),
+            separators=separators,
+            allow_duplicate=allow_duplicate,
+            soft_keyword=soft_keyword,
+            header_fragment=header_fragment,
+            header_separators=header_separators,
+            compact_header=compact_header,
+        )
+        for alias in aliases:
+            self._options_bind[alias] = pattern
+
+        self._options.append(pattern)
+        self.add_track(keyword, fragments, header=header_fragment)
+
+        if not forwarding:
+            self._exit_options.append(keyword)
+
+        if header_separators and not fragments:
+            raise ValueError("header_separators must be used with fragments")
+
+        return self
+
+
+@dataclass
+class OptionPattern:
+    keyword: str
+    aliases: list[str] = field(default_factory=list)
+    separators: str = SEPARATORS
+
+    soft_keyword: bool = False
+    allow_duplicate: bool = False
+    header_fragment: _Fragment | None = None
+    header_separators: str | None = None
+    compact_header: bool = False
+
+    @cached_property
+    def _trigger(self):
+        if self.compact_header:
+            return CharTrie.fromkeys([self.keyword, *self.aliases])
+
+        return {self.keyword, *self.aliases}
diff --git a/src/arclet/alconna/sistana/model/receiver.py b/src/arclet/alconna/sistana/model/receiver.py
new file mode 100644
index 00000000..462eed9e
--- /dev/null
+++ b/src/arclet/alconna/sistana/model/receiver.py
@@ -0,0 +1,46 @@
+from __future__ import annotations
+
+from typing import Any, Callable, Generic, TypeVar
+
+from ..some import Some
+
+T = TypeVar("T")
+
+RxFetch = Callable[[], Any]
+RxPrev = Callable[[], Some[T]]
+RxPut = Callable[[T], None]
+
+
+class Rx(Generic[T]):
+    def receive(self, fetch: RxFetch, prev: RxPrev, put: RxPut) -> None:
+        put(fetch())
+
+
+class CountRx(Rx[int]):
+    def receive(self, fetch: RxFetch, prev: RxPrev[int], put: RxPut[int]) -> None:
+        v = prev()
+
+        if v is None:
+            put(1)
+        else:
+            put(v.value + 1)
+
+
+class AccumRx(Rx[T]):
+    def receive(self, fetch: RxFetch, prev: RxPrev[list[T]], put: RxPut[list[T]]) -> None:
+        v = prev()
+
+        if v is None:
+            put([fetch()])
+        else:
+            put(v.value + [fetch()])
+
+
+class ConstRx(Generic[T], Rx[T]):
+    value: T
+
+    def __init__(self, value: T):
+        self.value = value
+
+    def receive(self, fetch: RxFetch, prev: RxPrev[T], put: RxPut[T]) -> None:
+        put(self.value)
diff --git a/src/arclet/alconna/sistana/model/snapshot.py b/src/arclet/alconna/sistana/model/snapshot.py
new file mode 100644
index 00000000..e376f928
--- /dev/null
+++ b/src/arclet/alconna/sistana/model/snapshot.py
@@ -0,0 +1,151 @@
+from __future__ import annotations
+
+from enum import Enum
+from typing import TYPE_CHECKING
+
+from .mix import Mix
+
+from tarina.trie import Trie
+
+if TYPE_CHECKING:
+    from .pattern import OptionPattern, SubcommandPattern
+
+
+class ProcessingState(int, Enum):
+    COMMAND = 0
+    PREFIX = 1
+    HEADER = 2
+    OPTION = 3
+
+
+class AnalyzeSnapshot:
+    __slots__ = (
+        "state",
+        "command",
+        "option",
+        "traverses",
+        "endpoint",
+        "mix",
+        "_pending_options",
+        "_ref_cache_option",
+    )
+
+    state: ProcessingState
+    command: list[str]
+    option: tuple[tuple[str, ...], str] | None
+
+    traverses: dict[tuple[str, ...], SubcommandPattern]
+    endpoint: tuple[str, ...] | None
+    mix: Mix
+
+    _pending_options: list[
+        tuple[OptionPattern, tuple[str, ...], set[str] | Trie[str], str | None]
+    ]  # (pattern, owner, triggers, header-separator)
+    _ref_cache_option: dict[tuple[tuple[str, ...], str], OptionPattern]
+
+    def __init__(
+        self,
+        command: list[str],
+        traverses: dict[tuple[str, ...], SubcommandPattern],
+        state: ProcessingState = ProcessingState.COMMAND,
+    ):
+        self.command = command
+        self.state = state
+
+        self.traverses = traverses
+        self.endpoint = None
+        self.mix = Mix()
+        self._pending_options = []
+        self._ref_cache_option = {}
+
+        self.update(tuple(command), traverses[tuple(command)])
+
+    @property
+    def context(self):
+        return self.traverses[tuple(self.command)]
+
+    def enter_subcommand(self, trigger: str, pattern: SubcommandPattern):
+        self.command.append(pattern.header)
+        self.state = ProcessingState.COMMAND
+        self.option = None
+
+        key = tuple(self.command)
+        self.traverses[key] = pattern
+
+        self.mix.update(key, pattern.preset)
+        track = self.mix.command_tracks[key]
+        track.emit_header(self.mix, trigger)
+
+        self.update(key, pattern)
+
+    def enter_option(self, trigger: str, owned_command: tuple[str, ...], option_keyword: str, pattern: OptionPattern):
+        track = self.mix.option_tracks[owned_command, option_keyword]
+
+        if track.emitted and not pattern.allow_duplicate:
+            return False
+
+        track.emit_header(self.mix, trigger)
+
+        if track:
+            track.reset()
+
+            self.state = ProcessingState.OPTION
+            self.option = owned_command, option_keyword
+            self._ref_cache_option[self.option] = pattern
+
+        return True
+
+    @property
+    def determined(self):
+        return self.endpoint is not None
+
+    @property
+    def stage_satisfied(self):
+        cmd = tuple(self.command)
+        cond = self.mix.command_tracks[cmd].satisfied
+        if cond:
+            subcommand = self.context
+            for option, owner, _, _ in self._pending_options:
+                if option.keyword in subcommand._exit_options and not self.mix.option_tracks[owner, option.keyword].satisfied:
+                    return False
+
+        return cond
+
+    def determine(self):
+        self.state = ProcessingState.COMMAND
+        self.endpoint = tuple(self.command)
+
+    def update(self, key: tuple[str, ...], pattern: SubcommandPattern):
+        exit_options = pattern._exit_options
+
+        self._pending_options = [
+            (option, owner, triggers, separators)
+            for option, owner, triggers, separators in self._pending_options
+            if not (owner == key and option.keyword in exit_options)
+        ] + [
+            (option, key, option._trigger, option.header_separators)  # type: ignore
+            for option in pattern._options
+        ]
+
+    def get_subcommand(self, context: SubcommandPattern, val: str):
+        if val in context._subcommands_bind:
+            return context._subcommands_bind[val], None
+
+        if context._compact_keywords is not None:
+            prefix = context._compact_keywords.longest_prefix(val).key
+            if prefix is not None:
+                return context._subcommands_bind[prefix], val[len(prefix) :]
+
+    def get_option(self, val: str):
+        for option, owner, triggers, separator in self._pending_options:
+            if option.compact_header:
+                prefix = triggers.longest_prefix(val).key  # type: ignore
+                if prefix is not None:
+                    return option, owner, val[len(prefix) :]
+            elif val in triggers:
+                return option, owner, None
+
+            if separator is not None:
+                keyword, *tail = val.split(separator, 1)
+                if keyword in triggers:
+                    return option, owner, tail[0] if tail else None
diff --git a/src/arclet/alconna/sistana/some.py b/src/arclet/alconna/sistana/some.py
new file mode 100644
index 00000000..e44e74ab
--- /dev/null
+++ b/src/arclet/alconna/sistana/some.py
@@ -0,0 +1,16 @@
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import Generic, TypeVar, Union
+
+
+T = TypeVar("T")
+E = TypeVar("E", bound=BaseException)
+
+
+@dataclass
+class Value(Generic[T]):
+    value: T
+
+
+Some = Union[Value[T], None]
diff --git a/src/arclet/alconna/typing.py b/src/arclet/alconna/typing.py
index a1758fc0..950e2f6d 100644
--- a/src/arclet/alconna/typing.py
+++ b/src/arclet/alconna/typing.py
@@ -27,7 +27,7 @@
 from tarina import generic_isinstance, lang
 from nepattern import BasePattern, MatchMode, parser, MatchFailed
 
-TPrefixes = Union[List[Union[str, object]], List[Tuple[object, str]]]
+TPrefixes = List[str]
 DataUnit = TypeVar("DataUnit", covariant=True)
 
 


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index c6dda18d..503c836e 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,7 +11,7 @@ jobs:
   test:
     strategy:
       matrix:
-        py_ver: ['3.8', '3.9', '3.10', '3.11']
+        py_ver: ['3.9', '3.10', '3.11', '3.12']
     runs-on:  ubuntu-latest
     steps:
       - uses: actions/checkout@v4
diff --git a/tests/sistana/__init__.py b/tests/sistana/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/sistana/asserts.py b/tests/sistana/asserts.py
new file mode 100644
index 00000000..de814f64
--- /dev/null
+++ b/tests/sistana/asserts.py
@@ -0,0 +1,183 @@
+from __future__ import annotations
+from contextlib import suppress
+from dataclasses import dataclass
+
+import pytest
+from elaina_segment import Buffer, AheadToken, SegmentToken
+from elaina_segment.err import OutOfData
+
+from arclet.alconna.sistana.analyzer import Analyzer, LoopflowExitReason
+from arclet.alconna.sistana.model.fragment import _Fragment
+from arclet.alconna.sistana.model.mix import Mix, Track
+from arclet.alconna.sistana.model.pattern import SubcommandPattern
+from arclet.alconna.sistana.model.snapshot import AnalyzeSnapshot, ProcessingState
+
+
+def analyze(
+    pattern: SubcommandPattern,
+    buffer: Buffer,
+    complete_on_determined: bool = False,
+):
+    snapshot = pattern.prefix_entrypoint
+    analyzer = Analyzer(complete_on_determined)
+
+    exit_reason = analyzer.loopflow(snapshot, buffer)
+    return LoopflowTest(exit_reason), SnapshotTest(snapshot), BufferTest(buffer)
+
+
+@dataclass
+class LoopflowTest:
+    exit_reason: LoopflowExitReason
+
+    def expect(self, *expected: LoopflowExitReason):
+        assert self.exit_reason in expected
+
+    def expect_completed(self):
+        self.expect(LoopflowExitReason.completed)
+
+    def expect_uncompleted(self):
+        assert self.exit_reason != LoopflowExitReason.completed
+
+@dataclass
+class SnapshotTest:
+    snapshot: AnalyzeSnapshot
+
+    @property
+    def mix(self):
+        return MixTest(self.snapshot.mix)
+
+    def expect_determined(self, expected: bool = True):
+        assert self.snapshot.determined == expected
+
+    def expect_state(self, *states: ProcessingState):
+        assert self.snapshot.state in (states or (ProcessingState.COMMAND,))
+
+    def expect_endpoint(self, *expected: str):
+        assert self.snapshot.endpoint == expected
+
+
+@dataclass
+class BufferTest:
+    buffer: Buffer
+
+    def expect_empty(self):
+        with pytest.raises(OutOfData):
+            self.buffer.next("")
+    
+    def expect_non_empty(self):
+        v = None
+        with suppress(OutOfData):
+            v = self.buffer.next()
+        
+        assert v is not None
+
+    def expect_ahead(self):
+        token = self.buffer.next("")
+        assert isinstance(token, AheadToken)
+
+    def expect_non_ahead(self):
+        token = self.buffer.next("")
+        assert isinstance(token, SegmentToken)
+
+
+@dataclass
+class MixTest:
+    mix: Mix
+
+    def __init__(self, input_: AnalyzeSnapshot | Mix):
+        if isinstance(input_, AnalyzeSnapshot):
+            self.mix = input_.mix
+        else:
+            self.mix = input_
+
+    def subcommand(self, path: tuple[str, ...]):
+        return TrackTest(self.mix, self.mix.command_tracks[path])
+
+    def subcommand1(self, *path: str):
+        return self.subcommand(path)
+
+    def option(self, owner: tuple[str, ...], name: str):
+        return TrackTest(self.mix, self.mix.option_tracks[owner, name])
+
+    def option1(self, *path: str):
+        *owner, name = path
+        return self.option(tuple(owner), name)
+
+    def __getitem__(self, path: tuple[str, ...] | tuple[tuple[str, ...], str]):
+        if isinstance(path[0], tuple):
+            owner, name = path
+            return self.option(owner, name)  # type: ignore
+
+        return self.subcommand(path)  # type: ignore
+
+    def expect_assignes(self, **kwargs):
+        for key, value in kwargs.items():
+            assert key in self.mix.assignes
+            assert value == self.mix.assignes[key]
+
+
+@dataclass
+class TrackTest:
+    mix: Mix
+    track: Track
+
+    def expect_emitted(self, expected: bool = True):
+        assert self.track.emitted == expected
+    
+    def expect_cursor(self, expected: int):
+        assert self.track.cursor == expected
+
+    def expect_satisfied(self, expected: bool = True):
+        assert self.track.satisfied == expected
+
+    def expect_assignable(self, expected: bool = False):
+        assert self.track.assignable == expected
+
+    def get_fragment(self, name: str):
+        for fragment in self.track.fragments:
+            if fragment.name == name:
+                return fragment
+
+    def __getitem__(self, index: str):
+        frag = self.get_fragment(index)
+        if frag is None:
+            raise ValueError(f"Fragment {index} not found in track {self.track}")
+        return FragmentTest(self.mix, self.track, frag)
+
+    @property
+    def header(self):
+        if self.track.header is None:
+            raise ValueError(f"Track {self.track} has no header")
+
+        return FragmentTest(self.mix, self.track, self.track.header)
+
+@dataclass
+class FragmentTest:
+    mix: Mix
+    track: Track
+    fragment: _Fragment
+
+    @property
+    def assigned(self):
+        return self.fragment.name in self.mix.assignes
+    
+    def expect_assigned(self, expected: bool = True):
+        assert self.assigned == expected
+
+    @property
+    def value(self):
+        return self.mix.assignes[self.fragment.name]
+    
+    def expect_value(self, expected):
+        assert self.value == expected
+
+    def expect_variadic(self, expected: bool = True):
+        assert self.fragment.variadic == expected
+
+    def expect_default_exists(self, expected: bool = True):
+        assert self.fragment.default is not None == expected
+
+    def expect_value_is_default(self):
+        self.expect_default_exists()
+
+        assert self.value == self.fragment.default.value  # type: ignore
diff --git a/tests/sistana/test_analyze.py b/tests/sistana/test_analyze.py
new file mode 100644
index 00000000..4ebfc5d9
--- /dev/null
+++ b/tests/sistana/test_analyze.py
@@ -0,0 +1,622 @@
+from __future__ import annotations
+
+from elaina_segment import Buffer
+
+from arclet.alconna.sistana import Fragment, SubcommandPattern
+from arclet.alconna.sistana.analyzer import LoopflowExitReason
+from arclet.alconna.sistana.model.receiver import CountRx, Rx
+from arclet.alconna.sistana.some import Value
+
+from .asserts import analyze
+
+
+def test_analyze_simple():
+    pattern = SubcommandPattern.build("test")
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test"]),
+    )
+    a.expect_completed()
+
+    sn.expect_determined()
+    sn.expect_endpoint("test")
+
+    sn.mix["test",].expect_emitted()
+    bf.expect_empty()
+
+
+def test_analyze_slots():
+    pattern = SubcommandPattern.build("test", Fragment("name"))
+
+    a, sn, bf = analyze(pattern, Buffer(["test hello"]))
+    a.expect_completed()
+    bf.expect_empty()
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied()
+
+    frag_name = track_test["name"]
+    frag_name.expect_assigned()
+    frag_name.expect_value("hello")
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test"]),
+    )
+    a.expect(LoopflowExitReason.unsatisfied)
+    bf.expect_empty()
+
+    sn.expect_determined(False)
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied(False)
+
+    frag_name = track_test["name"]
+    frag_name.expect_assigned(False)
+
+
+def test_analyze_option():
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name hello"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    sn.expect_determined()
+    sn.expect_endpoint("test")
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied()
+
+    track_opt_name = sn.mix[("test",), "--name"]
+    track_opt_name.expect_emitted()
+    track_opt_name.expect_satisfied()
+
+    frag_name = track_opt_name["name"]
+    frag_name.expect_assigned()
+    frag_name.expect_value("hello")
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test"]),
+    )
+    a.expect(LoopflowExitReason.unsatisfied)
+
+    sn.expect_determined(False)
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied(True)
+
+    track_opt_name = sn.mix[("test",), "--name"]
+    track_opt_name.expect_emitted(False)
+    track_opt_name.expect_satisfied(False)
+
+    frag_name = track_opt_name["name"]
+    frag_name.expect_assigned(False)
+
+
+def test_analyze_option_unsatisfied():
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name"]),
+    )
+    a.expect(LoopflowExitReason.unsatisfied)
+    bf.expect_empty()
+
+    sn.expect_determined(False)
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied(True)
+
+    track_opt_name = sn.mix[("test",), "--name"]
+    track_opt_name.expect_emitted()
+    track_opt_name.expect_satisfied(False)
+
+    frag_name = track_opt_name["name"]
+    frag_name.expect_assigned(False)
+
+
+def test_analyze_option_duplicated():
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name hello --name world"]),
+    )
+    a.expect(LoopflowExitReason.option_duplicated_prohibited)
+    bf.expect_empty()
+
+    sn.expect_determined(False)
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied(True)
+
+    track_opt_name = sn.mix[("test",), "--name"]
+    track_opt_name.expect_emitted()
+    track_opt_name.expect_satisfied(True)
+
+    frag_name = track_opt_name["name"]
+    frag_name.expect_assigned()
+    frag_name.expect_value("hello")
+
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"), allow_duplicate=True)
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name hello --name world"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    sn.expect_determined()
+    sn.expect_endpoint("test")
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied()
+
+    track_opt_name = sn.mix[("test",), "--name"]
+    track_opt_name.expect_emitted()
+    track_opt_name.expect_satisfied()
+
+    frag_name = track_opt_name["name"]
+    frag_name.expect_assigned()
+    frag_name.expect_value("world")
+
+
+def test_prefix():
+    pattern = SubcommandPattern.build("test", prefixes=[".", "//", "/?", "///"])
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["hello"]),
+    )
+    a.expect(LoopflowExitReason.prefix_mismatch)
+    bf.expect_empty()
+
+    sn.expect_determined(False)
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted(False)
+    track_test.expect_satisfied(True)
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["//test"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    sn.expect_determined()
+    sn.expect_endpoint("test")
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied()
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["///test"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer([1, "test"]),
+    )
+    a.expect(LoopflowExitReason.prefix_expect_str)
+
+
+def test_header():
+    pattern = SubcommandPattern.build("test")
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["hello"]),
+    )
+    a.expect(LoopflowExitReason.header_mismatch)
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer([1]),
+    )
+    a.expect(LoopflowExitReason.header_expect_str)
+
+
+def test_compact_header():
+    pattern = SubcommandPattern.build("test", Fragment("tail"), compact_header=True)
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test1"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    sn.expect_determined()
+    sn.expect_endpoint("test")
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied()
+
+    frag_tail = track_test["tail"]
+    frag_tail.expect_assigned()
+    frag_tail.expect_value("1")
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test 1"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    sn.expect_determined()
+    sn.expect_endpoint("test")
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied()
+
+    frag_tail = track_test["tail"]
+    frag_tail.expect_assigned()
+    frag_tail.expect_value("1")
+
+
+def test_subcommand():
+    lp = SubcommandPattern.build("lp")
+    lp_user = lp.subcommand("user", Fragment("name"))
+    lp_user.subcommand("permission", Fragment("permission"))
+
+    a, sn, bf = analyze(
+        lp,
+        Buffer(["lp user alice permission read"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    sn.expect_determined()
+    sn.expect_endpoint("lp", "user", "permission")
+
+    track_lp = sn.mix["lp",]
+    track_lp.expect_emitted()
+    track_lp.expect_satisfied()
+
+    track_user = sn.mix["lp", "user"]
+    track_user.expect_emitted()
+    track_user.expect_satisfied()
+
+    frag_name = track_user["name"]
+    frag_name.expect_assigned()
+    frag_name.expect_value("alice")
+
+    track_permission = sn.mix["lp", "user", "permission"]
+    track_permission.expect_emitted()
+    track_permission.expect_satisfied()
+
+    frag_permission = track_permission["permission"]
+    frag_permission.expect_assigned()
+    frag_permission.expect_value("read")
+
+    a, sn, bf = analyze(
+        lp,
+        Buffer(["lp user permission permission read"]),
+    )
+    a.expect(LoopflowExitReason.unsatisfied_switch_subcommand)
+
+    lp = SubcommandPattern.build("lp")
+    lp_user = lp.subcommand("user", Fragment("name"))
+    lp_user.subcommand("permission", Fragment("permission"), soft_keyword=True)
+
+    a, sn, bf = analyze(
+        lp,
+        Buffer(["lp user permission permission read"]),
+    )
+    a.expect_completed()
+
+
+def test_subcommand_compact():
+    pattern = SubcommandPattern.build("test")
+    pattern.subcommand("add", Fragment("tail"), compact_header=True)
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test add1"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    sn.expect_determined()
+    sn.expect_endpoint("test", "add")
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied()
+
+    track_add = sn.mix["test", "add"]
+    track_add.expect_emitted()
+    track_add.expect_satisfied()
+
+    frag_tail = track_add["tail"]
+    frag_tail.expect_assigned()
+    frag_tail.expect_value("1")
+
+
+def test_option_compact():
+    pattern = SubcommandPattern.build("mysql")
+    pattern.option("-u", Fragment("username"), compact_header=True)
+    pattern.option("-p", Fragment("password"), compact_header=True)
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["mysql -uroot -ppassword"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    sn.expect_determined()
+    sn.expect_endpoint("mysql")
+
+    track_mysql = sn.mix["mysql",]
+    track_mysql.expect_emitted()
+    track_mysql.expect_satisfied()
+
+    track_u = sn.mix[("mysql",), "-u"]
+    track_u.expect_emitted()
+    track_u.expect_satisfied()
+
+    frag_username = track_u["username"]
+    frag_username.expect_assigned()
+    frag_username.expect_value("root")
+
+    track_p = sn.mix[("mysql",), "-p"]
+    track_p.expect_emitted()
+    track_p.expect_satisfied()
+
+    frag_password = track_p["password"]
+    frag_password.expect_assigned()
+    frag_password.expect_value("password")
+
+
+def test_switch_from_option():
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"))
+    pattern.option("--age", Fragment("age"))
+    pattern.subcommand("add", Fragment("tail"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name alice --age 18 add bob"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+    sn.expect_determined()
+    sn.expect_endpoint("test", "add")
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name add alice"]),
+    )
+    a.expect(LoopflowExitReason.unsatisfied_switch_option)
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name --age 20 add bob"]),
+    )
+    a.expect(LoopflowExitReason.previous_unsatisfied)
+
+    # unless option keyword is soft
+
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"))
+    pattern.option("--age", Fragment("age"), soft_keyword=True)
+    pattern.subcommand("add", Fragment("tail"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name --age --age 12"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    # switch to subcommand and subcommand keyword is soft
+
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"))
+    pattern.subcommand("add", Fragment("tail"), soft_keyword=True)
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name add add alice"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    track_test = sn.mix["test",]
+    track_test.expect_emitted()
+    track_test.expect_satisfied()
+
+    track_add = sn.mix["test", "add"]
+    track_add.expect_emitted()
+    track_add.expect_satisfied()
+
+    frag_tail = track_add["tail"]
+    frag_tail.expect_assigned()
+    frag_tail.expect_value("alice")
+
+    track_name = sn.mix[("test",), "--name"]
+
+    frag_name = track_name["name"]
+    frag_name.expect_assigned()
+    frag_name.expect_value("add")
+
+
+def test_unexpected_segment():
+    pattern = SubcommandPattern.build("test", Fragment("name"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test alice bob"]),
+    )
+    a.expect(LoopflowExitReason.unexpected_segment)
+    bf.expect_empty()
+
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name alice bob"]),
+    )
+    a.expect(LoopflowExitReason.unexpected_segment)
+    bf.expect_empty()
+
+    # but name is alice.
+    track_name = sn.mix[("test",), "--name"]
+    frag_name = track_name["name"]
+    frag_name.expect_assigned()
+    frag_name.expect_value("alice")
+
+
+def test_determined_and_exit():
+    pattern = SubcommandPattern.build("test", Fragment("name"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test alice bob"]),
+        complete_on_determined=True,
+    )
+    a.expect_completed()
+    bf.expect_non_empty()
+
+
+def test_header_separator():
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"), header_separators="=")
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test --name=alice"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    track_name = sn.mix[("test",), "--name"]
+    frag_name = track_name["name"]
+    frag_name.expect_assigned()
+    frag_name.expect_value("alice")
+
+
+def test_stage_unsatisfied():
+    pattern = SubcommandPattern.build("test")
+    pattern.option("--name", Fragment("name"), forwarding=False)
+    pattern.subcommand("add", Fragment("tail"))
+
+    a, sn, bf = analyze(
+        pattern,
+        Buffer(["test add 111"]),
+    )
+    a.expect(LoopflowExitReason.unsatisfied_switch_subcommand)
+    bf.expect_empty()
+
+
+def test_header_fragment():
+    class LengthRx(Rx):
+        def receive(self, fetch, prev, put) -> None:
+            le = len(fetch())
+            n = prev()
+            if n is not None:
+                n = n.value
+            else:
+                n = 0
+
+            put(le + n)
+
+    pat = SubcommandPattern.build("test")
+    pat.option(
+        "-t",
+        Fragment(
+            "verbose_level",
+            receiver=LengthRx(),
+            default=Value(0),
+        ),
+        header_fragment=Fragment(
+            "verbose_level",
+            default=Value(0),
+            receiver=CountRx(),
+        ),
+        allow_duplicate=True,
+        compact_header=True,
+    )
+
+    a, sn, bf = analyze(
+        pat,
+        Buffer(["test -t"]),  # verbose_level = 1
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    frag_verbose_level = sn.mix[("test",), "-t"]["verbose_level"]
+    frag_verbose_level.expect_assigned()
+    frag_verbose_level.expect_value(1)
+
+    a, sn, bf = analyze(
+        pat,
+        Buffer(["test -t -t"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    frag_verbose_level = sn.mix[("test",), "-t"]["verbose_level"]
+    frag_verbose_level.expect_assigned()
+    frag_verbose_level.expect_value(2)
+
+    a, sn, bf = analyze(
+        pat,
+        Buffer(["test -tt"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    frag_verbose_level = sn.mix[("test",), "-t"]["verbose_level"]
+    frag_verbose_level.expect_assigned()
+    frag_verbose_level.expect_value(2)
+
+    a, sn, bf = analyze(
+        pat,
+        Buffer(["test -t -tt"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    frag_verbose_level = sn.mix[("test",), "-t"]["verbose_level"]
+    frag_verbose_level.expect_assigned()
+    frag_verbose_level.expect_value(3)
+
+    a, sn, bf = analyze(
+        pat,
+        Buffer(["test -tttttttttttttttttttt"]),
+    )
+    a.expect_completed()
+    bf.expect_empty()
+
+    frag_verbose_level = sn.mix[("test",), "-t"]["verbose_level"]
+    frag_verbose_level.expect_assigned()
+    frag_verbose_level.expect_value(20)
diff --git a/tests/sistana/test_capture.py b/tests/sistana/test_capture.py
new file mode 100644
index 00000000..cfcecafb
--- /dev/null
+++ b/tests/sistana/test_capture.py
@@ -0,0 +1,111 @@
+from __future__ import annotations
+
+import re
+
+import pytest
+from elaina_segment import Buffer
+
+from arclet.alconna.sistana import Fragment, SubcommandPattern
+from arclet.alconna.sistana.err import RegexMismatch, UnexpectedType
+from arclet.alconna.sistana.model.capture import ObjectCapture, PlainCapture, RegexCapture
+
+from .asserts import analyze
+
+
+def test_object_capture():
+    pat = SubcommandPattern.build("test")
+    pat.option("--name", Fragment("name", capture=ObjectCapture(int)))
+
+    a, sn, bf = analyze(pat, Buffer(["test --name", 1]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",), "--name"]["name"]
+    frag.expect_assigned()
+    frag.expect_value(1)
+
+    with pytest.raises(UnexpectedType, match=f"Expected {int}, got {str}"):
+        a, sn, bf = analyze(pat, Buffer(["test --name 1"]))
+
+
+def test_plain_capture():
+    pat = SubcommandPattern.build("test")
+    pat.option("--name", Fragment("name", capture=PlainCapture()))
+
+    a, sn, bf = analyze(pat, Buffer(["test --name hello"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",), "--name"]["name"]
+    frag.expect_assigned()
+    frag.expect_value("hello")
+
+    with pytest.raises(UnexpectedType, match=f"Expected {str}, got {int}"):
+        # Quoted
+        a, sn, bf = analyze(pat, Buffer(["test --name '", 1, "'"]))
+
+    with pytest.raises(UnexpectedType, match=f"Expected {str}, got {int}"):
+        # UnmatchedQuoted
+        a, sn, bf = analyze(pat, Buffer(["test --name '", 1]))
+
+    with pytest.raises(UnexpectedType, match=f"Expected {str}, got {int}"):
+        a, sn, bf = analyze(pat, Buffer(["test --name", 1]))
+
+    with pytest.raises(UnexpectedType, match=f"Expected {str}, got {int}"):
+        # raise for first segment that is not string
+        a, sn, bf = analyze(pat, Buffer(["test --name '123", 2]))
+
+
+def test_regex_capture():
+    pat = SubcommandPattern.build("test")
+    pat.option("--name", Fragment("name", capture=RegexCapture(r"\d+")))
+
+    a, sn, bf = analyze(pat, Buffer(["test --name 123"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",), "--name"]["name"]
+    frag.expect_assigned()
+    assert isinstance(frag.value, re.Match)
+    assert frag.value.group() == "123"
+
+    with pytest.raises(UnexpectedType, match=f"Expected {str}, got 1"):
+        a, sn, bf = analyze(pat, Buffer(["test --name", 1]))
+
+    with pytest.raises(RegexMismatch):
+        a, sn, bf = analyze(pat, Buffer(["test --name abc"]))
+
+    with pytest.raises(UnexpectedType, match=f"Expected {str}, got .*"):
+        # reason: match_quote = False
+        a, sn, bf = analyze(pat, Buffer(["test --name '123", 2]))
+
+    # tail
+    pat = SubcommandPattern.build("test")
+    pat.option("--name", Fragment("name", capture=RegexCapture(r"123")), Fragment("tail"))
+
+    a, sn, bf = analyze(pat, Buffer(["test --name 123345"]))
+    a.expect_completed()
+
+    frag = sn.mix[("test",), "--name"]["name"]
+    frag.expect_assigned()
+    assert isinstance(frag.value, re.Match)
+    assert frag.value.group() == "123"
+
+    frag = sn.mix[("test",), "--name"]["tail"]
+    frag.expect_assigned()
+    frag.expect_value("345")
+
+    # match_quote
+    pat = SubcommandPattern.build("test")
+    pat.option("--name", Fragment("name", capture=RegexCapture(r"123", match_quote=True)))
+
+    a, sn, bf = analyze(pat, Buffer(["test --name '123'"]))
+    a.expect_completed()
+
+    frag = sn.mix[("test",), "--name"]["name"]
+    frag.expect_assigned()
+    assert isinstance(frag.value, re.Match)
+    assert frag.value.group() == "123"
+
+    with pytest.raises(UnexpectedType):
+        a, sn, bf = analyze(pat, Buffer(["test --name '123", 1]))
diff --git a/tests/sistana/test_fragment.py b/tests/sistana/test_fragment.py
new file mode 100644
index 00000000..fdcf7682
--- /dev/null
+++ b/tests/sistana/test_fragment.py
@@ -0,0 +1,63 @@
+import pytest
+from elaina_segment import Buffer
+
+from arclet.alconna.sistana.fragment import Fragment
+from arclet.alconna.sistana.model.fragment import _Fragment, assert_fragments_order
+from arclet.alconna.sistana.model.pattern import SubcommandPattern
+from arclet.alconna.sistana.some import Value
+
+from .asserts import analyze
+
+
+def test_assert_fragments_order_valid():
+    fragments = [_Fragment(name="frag1"), _Fragment(name="frag2", default=Value("default")), _Fragment(name="frag3", variadic=True)]
+    assert_fragments_order(fragments)
+
+
+def test_assert_fragments_order_required_after_optional():
+    fragments = [_Fragment(name="frag1", default=Value("default")), _Fragment(name="frag2")]
+    with pytest.raises(ValueError, match="Found a required fragment after an optional fragment, which is not allowed."):
+        assert_fragments_order(fragments)
+
+
+def test_assert_fragments_order_variadic_with_default():
+    fragments = [_Fragment(name="frag1", variadic=True, default=Value("default"))]
+    with pytest.raises(ValueError, match="A variadic fragment cannot have a default value."):
+        assert_fragments_order(fragments)
+
+
+def test_assert_fragments_order_fragment_after_variadic():
+    fragments = [_Fragment(name="frag1", variadic=True), _Fragment(name="frag2")]
+    with pytest.raises(ValueError, match="Found fragment after a variadic fragment, which is not allowed."):
+        assert_fragments_order(fragments)
+
+
+def test_nepattern():
+    from nepattern import WIDE_BOOLEAN
+
+    pat = SubcommandPattern.build("test")
+
+    pat.option("--foo", Fragment("foo", type=Value(int)))
+    pat.option("--bar", Fragment("bar", type=Value(float)))
+    pat.option("--baz", Fragment("baz", type=Value(bool)))
+    pat.option("--qux", Fragment("qux").apply_nepattern(WIDE_BOOLEAN))
+
+    a, sn, bf = analyze(pat, Buffer(["test --foo 123 --bar 123.456 --baz true --qux yes"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",), "--foo"]["foo"]
+    frag.expect_assigned()
+    frag.expect_value(123)
+
+    frag = sn.mix[("test",), "--bar"]["bar"]
+    frag.expect_assigned()
+    frag.expect_value(123.456)
+
+    frag = sn.mix[("test",), "--baz"]["baz"]
+    frag.expect_assigned()
+    frag.expect_value(True)
+
+    frag = sn.mix[("test",), "--qux"]["qux"]
+    frag.expect_assigned()
+    frag.expect_value(True)
diff --git a/tests/sistana/test_mix.py b/tests/sistana/test_mix.py
new file mode 100644
index 00000000..2052c9ab
--- /dev/null
+++ b/tests/sistana/test_mix.py
@@ -0,0 +1,87 @@
+from __future__ import annotations
+
+from elaina_segment import Buffer
+
+from arclet.alconna.sistana import Fragment, SubcommandPattern
+from arclet.alconna.sistana.model.receiver import Rx
+from arclet.alconna.sistana.some import Value
+
+from .asserts import analyze
+
+
+def test_assignable():
+    pat = SubcommandPattern.build("test", Fragment("arg1"), Fragment("arg2", default=Value("default")))
+
+    a, sn, bf = analyze(pat, Buffer(["test n hello"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",)]["arg1"]
+    frag.expect_assigned()
+    frag.expect_value("n")
+
+    frag = sn.mix[("test",)]["arg2"]
+    frag.expect_assigned()
+    frag.expect_value("hello")
+
+    track = sn.mix[("test",)]
+    track.expect_assignable(False)
+
+    a, sn, bf = analyze(pat, Buffer(["test n"]))
+    a.expect_completed()
+
+    frag = sn.mix[("test",)]["arg1"]
+    frag.expect_assigned()
+    frag.expect_value("n")
+
+    frag = sn.mix[("test",)]["arg2"]
+    frag.expect_assigned()
+    frag.expect_value("default")
+
+    track = sn.mix[("test",)]
+    track.expect_assignable(True)
+
+
+def test_header_edge_case():
+    class DoNothingRx(Rx):
+        def receive(self, fetch, prev, put):
+            ...
+    
+    pat = SubcommandPattern.build("test", header_fragment=Fragment("arg1", receiver=DoNothingRx(), default=Value("default")))
+
+    a, sn, bf = analyze(pat, Buffer(["test"]))
+    a.expect_completed()
+
+    track = sn.mix["test",]
+    track.expect_emitted()
+
+    frag = sn.mix["test",].header
+    frag.expect_assigned()
+    frag.expect_value("default")
+
+
+def test_variadic():
+    pat = SubcommandPattern.build("test", Fragment("arg1"), Fragment("arg2", variadic=True))
+
+    a, sn, bf = analyze(pat, Buffer(["test n hello world"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",)]["arg1"]
+    frag.expect_assigned()
+    frag.expect_value("n")
+
+    frag = sn.mix[("test",)]["arg2"]
+    frag.expect_assigned()
+    frag.expect_value(["hello", "world"])
+
+    a, sn, bf = analyze(pat, Buffer(["test n"]))
+    a.expect_completed()
+
+    frag = sn.mix[("test",)]["arg1"]
+    frag.expect_assigned()
+    frag.expect_value("n")
+
+    frag = sn.mix[("test",)]["arg2"]
+    frag.expect_assigned()
+    frag.expect_value([])
diff --git a/tests/sistana/test_pattern.py b/tests/sistana/test_pattern.py
new file mode 100644
index 00000000..10f2b429
--- /dev/null
+++ b/tests/sistana/test_pattern.py
@@ -0,0 +1,60 @@
+from __future__ import annotations
+
+from elaina_segment import Buffer
+import pytest
+
+from arclet.alconna.sistana import Fragment, SubcommandPattern
+from arclet.alconna.sistana.analyzer import LoopflowExitReason
+
+from .asserts import analyze
+
+
+def test_aliases():
+    pat = SubcommandPattern.build("test").option(
+        "name",
+        Fragment("name", export=True),
+        aliases=["--name"],
+    )
+
+    a, sn, bf = analyze(pat, Buffer(["test --name hello"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    pat = SubcommandPattern.build("test")
+    pat.subcommand("sub", aliases=["subcmd"])
+
+    a, sn, bf = analyze(pat, Buffer(["test subcmd"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+
+def test_add_option():
+    pat = SubcommandPattern.build("test")
+    pat.option("name", Fragment("name"), hybrid_separators=True, aliases=["--name"], header_separators="=")
+
+    a, sn, bf = analyze(pat, Buffer(["test --name hello"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    # no hybrid separators
+    pat = SubcommandPattern.build("test", separators="|")
+    pat.option("name", Fragment("name"), aliases=["--name"], header_separators="=", hybrid_separators=False)
+
+    a, sn, bf = analyze(pat, Buffer(["test|--name=hello"]))
+    a.expect_completed()
+
+    a, sn, bf = analyze(pat, Buffer(["test|--name hello"]))
+    a.expect(LoopflowExitReason.unexpected_segment)
+
+    pat = SubcommandPattern.build("test", separators="|")
+    pat.option("name", Fragment("name"), Fragment("aaa"), aliases=["--name"], separators=",", hybrid_separators=True)
+
+    a, sn, bf = analyze(pat, Buffer(["test|--name|hello,aaa"]))
+    a.expect_completed()
+
+    a, sn, bf = analyze(pat, Buffer(["test|--name|hello|aaa"]))
+    a.expect_completed()
+
+    with pytest.raises(ValueError, match="header_separators must be used with fragments"):
+        pat = SubcommandPattern.build("test", separators="|")
+        pat.option("name", aliases=["--name"], header_separators="=")
\ No newline at end of file
diff --git a/tests/sistana/test_receiver.py b/tests/sistana/test_receiver.py
new file mode 100644
index 00000000..adc4d2e7
--- /dev/null
+++ b/tests/sistana/test_receiver.py
@@ -0,0 +1,47 @@
+from __future__ import annotations
+
+from elaina_segment import Buffer
+
+from arclet.alconna.sistana import Fragment, SubcommandPattern
+from arclet.alconna.sistana.model.receiver import AccumRx, ConstRx, CountRx
+
+from .asserts import analyze
+
+
+def test_accumrx():
+    pat = SubcommandPattern.build("test")
+    pat.option("--name", Fragment("name", receiver=AccumRx()), allow_duplicate=True)
+
+    a, sn, bf = analyze(pat, Buffer(["test --name hello --name world"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",), "--name"]["name"]
+    frag.expect_assigned()
+    frag.expect_value(["hello", "world"])
+
+
+def test_countrx():
+    pat = SubcommandPattern.build("test")
+    pat.option("--name", allow_duplicate=True, header_fragment=Fragment("name", receiver=CountRx()))
+
+    a, sn, bf = analyze(pat, Buffer(["test --name --name"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",), "--name"].header
+    frag.expect_assigned()
+    frag.expect_value(2)
+
+
+def test_constrx():
+    pat = SubcommandPattern.build("test")
+    pat.option("--name", header_fragment=Fragment("name", receiver=ConstRx("hello")))
+
+    a, sn, bf = analyze(pat, Buffer(["test --name"]))
+    a.expect_completed()
+    sn.expect_determined()
+
+    frag = sn.mix[("test",), "--name"].header
+    frag.expect_assigned()
+    frag.expect_value("hello")