From 13bb37585f8734594f4f6d9b0f74a2ba104f4b36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E9=B9=8F?= Date: Fri, 17 Jul 2026 09:14:45 +0800 Subject: [PATCH] feat: add ProcessDock process and port manager --- .gitattributes | 4 + .gitignore | 9 + ProcessDock.pyw | 5 + ProcessDock.spec | 85 +++ README.md | 87 +++ app.py | 39 ++ artifacts/processdock-preview.png | Bin 0 -> 167351 bytes assets/processdock.ico | Bin 0 -> 26515 bytes assets/processdock.png | Bin 0 -> 13024 bytes build_config/windows_version_info.txt | 30 + build_exe.ps1 | 28 + docs/blueprint.md | 53 ++ processdock/__init__.py | 3 + processdock/models.py | 187 +++++++ processdock/services.py | 499 +++++++++++++++++ processdock/styles.py | 198 +++++++ processdock/ui.py | 764 ++++++++++++++++++++++++++ requirements-build.txt | 3 + requirements.txt | 2 + tests/test_gui.py | 66 +++ tests/test_services.py | 85 +++ tools/generate_icon.py | 54 ++ 22 files changed, 2201 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 ProcessDock.pyw create mode 100644 ProcessDock.spec create mode 100644 README.md create mode 100644 app.py create mode 100644 artifacts/processdock-preview.png create mode 100644 assets/processdock.ico create mode 100644 assets/processdock.png create mode 100644 build_config/windows_version_info.txt create mode 100644 build_exe.ps1 create mode 100644 docs/blueprint.md create mode 100644 processdock/__init__.py create mode 100644 processdock/models.py create mode 100644 processdock/services.py create mode 100644 processdock/styles.py create mode 100644 processdock/ui.py create mode 100644 requirements-build.txt create mode 100644 requirements.txt create mode 100644 tests/test_gui.py create mode 100644 tests/test_services.py create mode 100644 tools/generate_icon.py diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c395341 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +* text=auto eol=lf +*.ico binary +*.png binary +*.exe binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..49fddb7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +__pycache__/ +*.py[cod] +.pytest_cache/ +.venv/ +dist/ +build/ +*.spec +*.log +!ProcessDock.spec diff --git a/ProcessDock.pyw b/ProcessDock.pyw new file mode 100644 index 0000000..9ec792f --- /dev/null +++ b/ProcessDock.pyw @@ -0,0 +1,5 @@ +from app import main + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/ProcessDock.spec b/ProcessDock.spec new file mode 100644 index 0000000..86e8181 --- /dev/null +++ b/ProcessDock.spec @@ -0,0 +1,85 @@ +# -*- mode: python ; coding: utf-8 -*- +from pathlib import Path + + +ROOT = Path(SPECPATH) + +a = Analysis( + [str(ROOT / "ProcessDock.pyw")], + pathex=[str(ROOT)], + binaries=[], + datas=[], + hiddenimports=[], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[ + "PySide6.Qt3DAnimation", + "PySide6.Qt3DCore", + "PySide6.Qt3DExtras", + "PySide6.Qt3DInput", + "PySide6.Qt3DLogic", + "PySide6.Qt3DRender", + "PySide6.QtBluetooth", + "PySide6.QtCharts", + "PySide6.QtDataVisualization", + "PySide6.QtGraphs", + "PySide6.QtLocation", + "PySide6.QtMultimedia", + "PySide6.QtMultimediaWidgets", + "PySide6.QtNetworkAuth", + "PySide6.QtNfc", + "PySide6.QtOpenGL", + "PySide6.QtOpenGLWidgets", + "PySide6.QtPdf", + "PySide6.QtPdfWidgets", + "PySide6.QtPositioning", + "PySide6.QtQml", + "PySide6.QtQuick", + "PySide6.QtQuick3D", + "PySide6.QtQuickControls2", + "PySide6.QtQuickWidgets", + "PySide6.QtRemoteObjects", + "PySide6.QtScxml", + "PySide6.QtSensors", + "PySide6.QtSerialBus", + "PySide6.QtSerialPort", + "PySide6.QtSpatialAudio", + "PySide6.QtSql", + "PySide6.QtStateMachine", + "PySide6.QtTest", + "PySide6.QtTextToSpeech", + "PySide6.QtWebChannel", + "PySide6.QtWebEngineCore", + "PySide6.QtWebEngineWidgets", + "PySide6.QtWebSockets", + "PySide6.QtXml", + ], + noarchive=False, + optimize=1, +) + +pyz = PYZ(a.pure) + +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.datas, + [], + name="ProcessDock", + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + upx_exclude=[], + runtime_tmpdir=None, + console=False, + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon=str(ROOT / "assets" / "processdock.ico"), + version=str(ROOT / "build_config" / "windows_version_info.txt"), +) diff --git a/README.md b/README.md new file mode 100644 index 0000000..38c4de4 --- /dev/null +++ b/README.md @@ -0,0 +1,87 @@ +# ProcessDock + +ProcessDock 是一个使用 Python 和 PySide6 编写的 Windows 原生进程/端口管理工具。它读取本机的真实进程与监听端口,并提供搜索、自动刷新、进程详情和安全确认后的结束操作。 + +## 功能 + +- 查看正在运行的进程,以及 PID、CPU、内存、用户和状态 +- 汇总 TCP 监听端口与 UDP 绑定端口,并支持根据端口反查进程 +- 按进程名称、PID、端口、用户、路径或启动命令即时搜索 +- 点击表格行,在右侧查看程序路径、启动参数、启动时间和父进程 PID +- 打开程序文件位置、复制启动命令、正常结束或强制结束进程 +- 每 3 秒自动刷新,也可暂停自动刷新或手动刷新 +- 后台线程采集数据,刷新时不阻塞窗口 +- 结束前二次确认,并校验进程创建时间,避免 PID 复用导致误操作 + +## 环境要求 + +- Windows 10/11 +- Python 3.10 或更高版本(已在 Python 3.11 上验证) + +建议使用虚拟环境: + +```powershell +python -m venv .venv +.\.venv\Scripts\Activate.ps1 +python -m pip install -r requirements.txt +``` + +## 启动 + +```powershell +python app.py +``` + +不需要控制台窗口时,也可以运行 `pythonw ProcessDock.pyw`;在 Python 文件关联正常的 Windows 环境中可直接双击 `ProcessDock.pyw`。 + +若不希望启动后开启自动刷新: + +```powershell +python app.py --no-auto-refresh +``` + +部分系统进程的路径、命令行、端口或结束权限受 Windows 限制。需要管理这些进程时,可右键 PowerShell 或终端并选择“以管理员身份运行”,再启动 ProcessDock。 + +## 测试 + +```powershell +python -m unittest discover -s tests -v +``` + +## 打包为 EXE + +在 PowerShell 中运行: + +```powershell +.\build_exe.ps1 +``` + +脚本会生成图标、运行测试并构建单文件 GUI 程序,输出位置为 `dist\ProcessDock.exe`。目标电脑不需要安装 Python;首次启动单文件程序时需要解压 Qt 运行库,因此会比后续启动稍慢。 + +无窗口界面冒烟测试可以这样运行: + +```powershell +$env:QT_QPA_PLATFORM="offscreen" +python -m unittest tests.test_gui -v +``` + +## 行为说明 + +- 端口列表聚焦于服务端口:TCP 仅显示 `LISTEN`,UDP 显示已绑定的本地端口,不展示大量临时的出站连接端口。 +- CPU 使用率按所有逻辑核心归一化。Windows 使用批量性能计数器;非 Windows 兼容模式的第一次刷新用于建立采样基线。 +- “正常结束”在 Windows 上调用不带 `/F` 的 `taskkill`;“强制结束”直接终止进程。强制结束可能丢失未保存的数据。 +- ProcessDock 会保护自己的进程,防止从界面中结束自身。 +- 本工具只操作当前计算机,不连接远程服务、不上传进程数据,也不使用数据库。 + +## 项目结构 + +```text +app.py 程序入口 +ProcessDock.pyw 无控制台窗口入口 +processdock/services.py 进程采集、端口映射和系统操作 +processdock/models.py 表格模型、筛选和操作按钮代理 +processdock/ui.py PySide6 主窗口与详情面板 +processdock/styles.py GUI 主题样式 +tests/ 自动化测试 +docs/blueprint.md 需求证据与验收范围 +``` diff --git a/app.py b/app.py new file mode 100644 index 0000000..6f70fcf --- /dev/null +++ b/app.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import argparse +import sys + +from PySide6.QtCore import Qt +from PySide6.QtGui import QFont +from PySide6.QtWidgets import QApplication + +from processdock.services import ProcessService +from processdock.ui import MainWindow + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="ProcessDock 进程与端口管理器") + parser.add_argument("--no-auto-refresh", action="store_true", help="启动时关闭自动刷新") + return parser + + +def main() -> int: + arguments = build_parser().parse_args() + QApplication.setHighDpiScaleFactorRoundingPolicy( + Qt.HighDpiScaleFactorRoundingPolicy.PassThrough + ) + application = QApplication(sys.argv) + application.setApplicationName("ProcessDock") + application.setOrganizationName("ProcessDock") + application.setStyle("Fusion") + application.setFont(QFont("Microsoft YaHei UI", 10)) + + window = MainWindow( + service=ProcessService(), auto_refresh=not arguments.no_auto_refresh + ) + window.show() + return application.exec() + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/artifacts/processdock-preview.png b/artifacts/processdock-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..bbc39d06f475e610a2f35f42e99ab29655c90539 GIT binary patch literal 167351 zcmeFYWmr^Q+c1om3eqA-Do7(O-H3EINVjyyP%}eFgGhG>(j_1rBO=}14BZUP5X0~d z-p~DB&++|x|G(>iWAC+V&ULP{BSK9@78i>g3k?koS6)s^0}T!13JvYa@UwqVS0pxU z{ZR)@7dbt5G&H!n$dXq}Z3A{ZaJk z{9L2MuguNNm&i^I1G#(ZMtKYvv?STX3MLiuyNJQ{E%7=*bPRE!74_=TL2yN^Z}hp( zxF6%BH0404+*b!VJAnb!GiTMYJzUnqo7|lNCpWDlx1BtE`_EAD{C9{DRzWcSJ9#)R zh2>KHJO33-z4O0rADceAdGzmH5z-*gzcV!a(Es=9Uv&K6p$YTG4~>|Cwv3-#NhTqV zx0kR1NRKRaM# z`;3$_)|xB*$v>cbJp6y(4+zIWr;Q!qPE(R0wC76yso$1-?oZiC@=PiSq=L9*+u^S+ zS1Fs>#l`6im;Oh*`aSE5Q}4&-myiGbMDA+_!m_DdUj1Ml>(SkFns4vvh)+|I5shix zpNyzX;;rP1X7)XNX}Wt1Hul**-RyS#ub0oC4AjI7%@=-pO~CR3Q~HA$6k{3q`n;BP zVKI-JJZ9OLMw|*$;p$()`ZbZJRNgEUwUub?g%Fqy_u7wvQ z6IXQD9MtY#s*jG;l06o|Ydt%s zv1(S9gq!duL1K+G|33a6@*MLCS4k`{=}{ERrSxdk#D0v7MF51v?)u-wt<*CT9i!F| zEt9WObrd|%gxX0I{)^z3FTQbz|NAk7lH8vU&Kz+n)|^d{Qs|)sM5T<;9N|v~Yk&Ul zQ@?(#?$a{RWDOrm-@$Nilx1{^_^-U9yhXYzNFKz`{|r*KE0OHj2Du{c)Myyn9>96D zikp-)^yGrL<%0RY5222azg9J*nvu43tW1|R^6&7IF>Wmu^{X#vo>wz*E-&M@t79cl zlwwuf;s_59w_-Dy&$a_jUuJeX;V}|Kqz0gY-UpcWK41MV-ws&brF~(>^)C^iWv-ui zqbH03x2?%DJe`E67b+- ze#ym`uy&PeN7WPW!N>SG3JO@4XZ!gX|DiUAkIC$YHi)f^8~1H;UUL3r0vy!$v#8^a zyJO*5e2$}yuI)HN5@=}ZlKF*A()-){l{MaQ^gCm7vtMr-aN6=d+{c2MUSh#cpWY>( zF0|uey=cEO|MSBPmcH;8P@DaE-l65TsT2-=40J3;jrWqu|((&ulUM=dqdJn+)b zf~oYqJ)F9_n_6oM)hrDbqMKCGBgX7!Wbb~*m=O$&$570#t#zMmXV}?$dV0!a;ngBl z!lhbKm{$9`Gb{`&R64=MCWOPoSGEf(+nc1z;PA7-Tvtml#iJ_tWLi;|I&c#)#lB0wFnpqD5vgG)5H#F1@heBLWzo++DC^0-i7<~dk z8B{NC?~Wwf+Qy{nA%&x-u%M zD-G7F7j^dO**R(@JPu3x-?Ye|i(b4MNQaK>D-?WNZ+nE!DFMdM#a79*Y4VCOU=V+= z2|6PYM~t2>0X*T$6r(Y^{jN6hf1+{(fif$?0<(;klhK0mu_9TVg0HaA8rD~$BthWb zYt8rowUSxC9V7S>;7Agmagl#sceX+DfopfrlMCAX$}n)(IE=_c6CWsIW&Olvcl?L0 z@wM5}^4?Tg82o!+tnoq9eI6gIS`pRD@^5McJJxoyNjp16hkp3{)*#jWT8r2 zl!e{xbYj1z>hkxZ5DKCIVWY-T?`t=Ajd4?t1C(?>CVGK+bkc)i(!S`w`XRRYk3X_$ zZEuQr1JM>`wYxW!jPRER<3Gv071_cMo+#qQ3aPM-#rTe3RcvtDRZt*rMrgE1xO*O* zsovit^tU%oJ1T?s4|?4iAw|V1C5wM{WYmbnWAHJ9aG} zi#)CT+5y6IOwlr_xEo;HTW*~{RG`7d#6|r%-cqKMl|p>DSF6D^`zVSCc(i{o*Nx(g z(VwW@{GR>bzYe&?~5G$eYSWuqzbTqkdfta%s zPYJ6TRZCm$S{5QAu%UkN82B=9Js(juY|Jcpc9Q41_K40f#f{(l_(`0NH z@?0ycO&MM+XKG4>cusZFzMd8s%~S?cx0QptAI#EGf{JM#P^&XI_CeP*A5^yZ^O9>e zq-=nu~??;u8MAr?~?`!68!LwY=O5x+1ZR zs_-xlez0n5+1T6tz+>>HE2>aLXBbhu9x^G`a&maY?Q!!{80m||SXj@P;t&5&a&rc0 zJG)li@20Lrp7-cUh;OysgdH|nSC!hVg?6@pN#=ZCC~x+~-d`YLi`WJHd#r^0@d2Yd zuCd~Gh$G@?eAhd&u|(jt@qDE!r2SM=Ie$|(_ZQ$e74t0T_RK!^^W2f|h3QSbV;U6b zJg2!rB4X#;Kkhj|6&?Rmu`qNL0!l=sKKwIRj=Z)Y#47Sn4+08Y2y z>mGI^NI|_n-Di+QKBM@}?~F3am>pB^{;Fj^N3it1g_%7_4-{~aRS_i9}ul3rYw7}O@#P4S|LKKAYv-2gFg>*A=>9~s7MN^e(0(8 z)b^J<`=#nZ0L-9zA3CC9bLO-Q9yC6^>gI3~M6y)s&SVQ;Ry{5f#=1!go330$rj1{I zyxF<6k9#ms5rYw3ljg?L)J)iA{LXyw&1H=;!%!8FhsV|JI6hq{^17ER@Z%WbsPfqIh|Wf%x}=* zTM+O5x0W_A0#UY@&**rRj5PN>9Y`2KGO?ZeR&R$OcOAVUNncd9X%qQ z9R>u_!X5zLlwI&@bvZiyCM8wW0O`u2{2FbNopF{~*D#U~0mYp+L`Lo##>%F_#|LEf zQ~XkfeC#!Y$|7Q9Jf1hn^ub3+1dlM8e=q>#S;LhGbOT<^a-9l&d)X$TDp+kF?UtpZ?EZSPM8y96jX&ak2~DX zyIlA4`r15^UgjN(W&apEZi3j(9Bb)OQbb-vhNvpz)+zQ1L#$I4%iH^a0()Q7rKGl1 ziQKoe3h6||CQk%bIbc~bw~nGmeDvN=gq{CDj}82FrVV~m z?|x}JVW~=J0FbB#`W=P{X^v=u0QX&V=TVLKY1&ngb5kwhIWNn_pVVI#oR-VCM6fU& zYahp%+DJW%^W+b18oIBe>KAN@j*PUmcG;W(*#L7zT78zxW^VV`%APIW77e+df}!)% zIXE#Xf2BFNZI6HNB*xh}U3~oJ18U_YJ5j1RTVh{c5y(qv0fQ;-@iAR%)~et5?>wj3 zcS=sNfa9qR78kSQ6i~xMQdk@l-XUXKZ-|Lk{_ExPn=3Q4smyrS?rP+#*mBx>FyO|f zcEtCZLe>8XOnLvtj8u%Ex?J7ah8U}L2*2Y1)^fy`qUI6NXUWVCTh>UB^7yo{rsOkw zpiE&c>j5Wn()IMdD6?MUugoTyhSKha``?y2YCpama!9d$de=5uT|}4~;3~o4d^Y5> zx!0aE8<=#eYIwC=3(#xFYqgl4HIwLQf6ZS^aNGiSyu7^Jn|2kY@w1%RK9bMYOEUNb zjg+lwuK{e*K7Hy8K106JBY_|Acn%xG*1A0ah(s0m{mJPiY`#lq<+aEk$Z4}DW&Y}d zWKW{|Xv2fLe;A8_Rx$dHcSBo>{ImAPl0jC%VR)x-+~c!Pb!_yEk?c?rv2a{c`nwRw zks3{5<;h-OI>OcryS4QnKghT^&D9XUl;DU~zu$GMQ-i}?jdc#NzD%~OtIP8~zRP-3 zYE`ov&XZax)Os`3Nia}fo;u!1xU>l0O9q;~^-ET^St2HWAu)C9HZr*G{>Q;2ujUN9@w^Q)9(E>q|}lR=8awm0BnO244x01jbjmM zCXjTkB7X-e=+)Ra>}5~tjSc5?15k#mkSP~gqVi^v#~k2%wD(vxoy?4Tz{aOlKY9Cz zG4X<^-{MqK_j;Yqzq zPPmOie|Fa4ppZ9nEauHp+^H_e*VE`ra`;7wOBdd{o7^$>J z*XjEXDn0;`HVfH`8N|q;e=(M)?R$}=Y64m(V)qtp;v3i)o# zc{g=l6f1HO*N;#GJ6N190DvcX>u!G)oKxOcYb#3KzQS&FuU6-oq?ZnCF@}Qt<4zVC z*P-KxXb~%i{txiz)q3ivSM&q@3r6OC`9!DXgX`l@tjEB@su#)AicE@LhwM~!oPzBW z_XLLNIdQtgbF0S+XWW%i!dWT*pnOIPJqruPf)DmpW54Qu48r?xIFy5WRt%eXM61mSeLOux1Ays>1p!% z=RIu`Z)DUmHtFAryk%nVIm5d5%cB9Dr9Ym!TquRNHQVLXW(jt{Kfe?msLQh6(GJsv z*f~uCQDST`vPZ{J#lgCGYJoV%R@6Wsu2w!M{Ks(eSp$%T8Q(!q%?ix@NOrM?%`co4 z{%Tg#VwuZtqI<4lA(ETKq3ETsrmstbwD@sqZcg~3*1$;3cl$|bW4Z7BX5oI7l-TQ~ z^ov;X^`Vg}ZlP@GZk=Hv;<39~?WoD3aHNWXrnl$t@ZCPukAd8zTk)$@?hroL;XyT; zJOb{*FobLD~!RtR{ z=jef>txKk(*iRPU80_%xMZm@E+C8Do&TIy(hes&2fq}BthGBlUb>h}0b^B;^ir)Km zeihsJX~-zy;@Np;6QGOibZMHZ`~EjA!6UG5{>5sR`}XJO1kx%QV&_ZPGZpKC^`3{w z-CYP)z3Lv@Q8ITB85sKWcr<<~`5L1$q(PG(xpp>F#70XI@^aeBUEGBOJCbHa;4#)~~D&;4C})8;hWT~~lD z{H-T?Ob5{_%O#hc9Y<#K*vBG!b$kfzr^(rB-*5MDtWO>*$0XVJhi|B=d_e&LBec_h zYRYRX&v9+P!~hVQ;y6c3gNc6b0X?=34wL&ANF-8(vT9#ebw>*AKO}~CNgZZ)*MC?> z?2?nY#>I0K9sXy^?>9F|Ch3S^-w?3MsYGtE#vDt%L6_cz_k+79_+%BRP1xK>`rcFe zWr#SRSWs`ex5iU-fvmn^Am{KM@Uw3m27M?@;o2Yy7Bi3VzaSh#Rt$uHj{Fe8{Ay%u zDiQpi;Vz#T;pE$`*u$#ch@8E--MViyQyvFOwnY%pQ?*_cy_UwU&$`Q=Nde#7b1knI82f?o#@gPFd_G!sx+WVlQBnmd z)b4UXGPvh!Dg%s-Ztw2J=IVE6ccRdaZx4QuD;-P3Er5q4o!!&p4}6xE}m>pOlRO|<%r&o7UYjO8zPQ(-q6?~ zcNazg-+{l%ndeTzC*sm6t_DXMc#psJM_bP<0?!?J9->NU4YktOT<$8&F(!>X*}X4t z4ZPeaEi+yo4l}vc%)Qt}@1|#D;yyjaR%p@DcOp?5C}gPm`KOWjsbCI>X=tQ(-~a29 zbip;5!9vcNi>KC6&t2S!W5gb)o>As<)c$r@Lf|o(Ik&9Z(YwIb|GsN*2c`zD^giQe}!41m=*mVrAh%2@ia#g z{rISeQ(L?GH!<$LJ`88xeLBlil9PRoL>}#u;E>MHsJ!Ut)$Z%4>mq<^c#e?AVxs+p ze>{2;|Brkhp-@K7y_nY~x$YabDI2y@1RW)s6yt+S-fO?bGfP1X6@lSQG_&;?+o897 zxVX6Y*CSwdk=u}MFnXh|_NI0%_t zgmC-^&Nl>)Nt(})a&&sye5e7Uq1pZYQ(4x!^(yURgwkpZqePxcVCigZs7lOEu`P^! z{&Wqgm%+Y3zGmO=W@3_hD+GUL?;z@Wm_q_GXOUw>y#dLZx_kkM-V(7XK`;P!`FH7# zvGLAdJ||1JvlkeGKYa%==BzIB6B;cpbrt{yg@=C*rt)5&01)Ff+>d=7QUxC^+=86< z5A$!FZU-V3vR-p!oJ~WwW~bRmZx(Pl4zu9h(hHVBg{*!96LSWQvLbuFoKkc@omV9L zB?oercwO)Fz8z9NSlgrWThBcAVJ~PjwyYiK8+2RW7q(D+S4>P%l zOFyStam3GiOl1jUMPNcRxjKo4P{X?EMvZCXskB1R9JxDVj=Fk1u!bwPjLA;N?_Jm1bEV7O|Idk+2TaZiRpF53i-d zo}6A3OUu_q8vI*==t7wdLp|^yAiJmb0jmfsd)iNgx*)4eO)j zs6+vpZ%9*frZ$m#`g&Ppe|SGueIWsX^hlP~@v7(F zrFX&fzRBJq?H$GYT^+p>%thTHJ#kOz zkJX=Wf?;y1i{^}5(d8?==`31tSfcKV zT$EezuGqXeOg|+gh;uo}D|bE;znZ4lzrRo}=tc^nLSu6fzdMd77}esXBn>Hi0i2T= zce~ANOGO1)b;%s%SVLY3>r>&W$lZG#M9-M`xgW{*C_b0}Zeh&^e%p0v9e4lZU8jE) z^3U7B1{kT>g|0n+1&Bsrd{b2TO9}kKF*|{K2~blv!ej7>fp=v_(@yuH*v=fr zB!1@=yV)0K52iU~0k1a42rW(CF9CP2#rftQ+XY_=k_x|r`9h3tdJZn|JHW2O-k^Ew z<lqQbtipR@IoA1KhD?ksF&Qq8V)~?b2C# zEweX34@T5Ohbc|7P{;S6Us3V(iWyEs1qh)Zfi)lljFzwlO2H!<0sNkPvSfMhHaz)O~rJ_Y~Kg=Y| zl!wSms@{)~@a`$`lb;7$`iHJk#0;^kIP8x(+YXJ`Hqojm*tI~6Fz%1P_u^NWWTb2) zZBM#Ux!Jf+CvAJ=y#$(!+wl0d8Pmi)3-O{)S152B$rf#DYNC~i_P*Xsp{1p5nL<&; z@T}X}rC#Sg^%4Nj{LZh$o?7@(*wJ@|OtEimu z+w>w-WxEXddV2kEFz}QR&)LX67+Jse!a7V>Tl1y*Oga)yfscjdmwhU%yzD5<6$lTj z@cw#BXoD!MJMrb$M0zD->|_cGGqZc#6&Gup7=4`T1Jct{T~CNpT_;EwA_9!BR|;+Ia1{{XMP&6%zT9v=twxieNj7fY@sB zI~fYPBYn9Ed~mZ|W_mjUgI`y^+ZY3bZkcTNoQg}^?_n5En<$mG;dFVj%k6WDkaK!< z{PxS$;3_h5=P86ohyT(q;lh~LTN~QKulVn$7O$)9w5AHIhn(FO0J&{P=`Q{AgfH#= zws}$HhIY;nhW>Wb$M$If`+kYvvU88dFQ;sal|i!N$YLtrbGVeLp~Lw}(0I+MM&yBf z7+IQFH?;?KO!EL(eR0rSTHdAM z1jb2-{Uf?ht3KVpX&0xqW${2_bmy-R0pNuC!Y#w=f&}aI5VloXSU8!x^^crE)mOi` zqE(>1H4Y|;-~I6N$GrC@OIUO(m9j+y85m^fUZge5OizQ($7C_^UXi{t|D(v!=F#&S zaD0upRNd5XAXyjH)KXfF72R2z{TlAI?hvL0gqD?E62ukELW0M78>;4YcprR1JfCLX zbn#k8*H0l68R*R)+JR^7F=Y!z5pborf(YsLZvE;CguabEk%=%_tC zM%&WA?fpDifLZTo_0-^OU}39bF}l&fw!HM`Aho&IoD##le^r1VlfpofR84WO(^RbD zV=Jvv9uED5yLT=+?b>e>>7wH6OXi$2YT?8%9(?PhPhmkfC>j`cd|AKRlzRFWV(z%6 zm7b$LS$`i}LwD4uz&BOXHaUL&mW!Hqjw`-ck41ARr!BgI?$D*;8CpONcQP+h&GWD& zFTS{VRU}*L*Ru%y&Uc}!5mKNJ-(n$vt7rMcHV#edzBg`nVCRrf$|g@my_pqN3HE-w zE_vrK@|!%8)!J(V6a6e%2hgvVO2HSEB8r}1l;F`nD{Yk`B0zkKzdly9b#oohh?8HH zI#n3ZXnP!CTqO>GEi&f#yCD(R(ow`|wMc^or^BTd_)14Gt?U=WYIA814-b3|B&7{* z-H3xhrhMiNJhDGSO7c|@^7zMBzM|A0=GF>^_R^4v-Ot1Orgq;X2_nkiAGb*d&z_?+ zol<2jGIFug4GR;$tddo%HP!}t`Bm9W#kg@Q%`s}E8z54|72vHg3O!4Nt^#7=oRHg4 zK}d3SC9I9Dj(50fYAO*Ly!N-g@rsOvcl)$2aIz5h%aTTA@?<@)8Xt$E;$$H`w)$kb zx|WJ%>2+L54-udxz0W9X=hxF@UM6y_P3`_X_W}iNAa|9_ ztefCxGWs>YcQ_-4^CO%hVkU#zQ4#)Oqfgq7N)i)&{?Qz`AHMUr%%>vluC(J5F;tS$ zDyeu=olv;Vu2<^^D~YEO=i$FDDL2~w$qNmji<6@So~zgC-(7F#5UMLEL@F^XK*0AM z!5Fg9q$h~8k)A()o;|rs=;>F@{PybM3Mz~NmVJ#)jql& z`|&H|+S&0@aYVItM$75-&VSu<2k}}C_@Kyk8Qx+diEfy9@(Yv9CTE5I!XKUXc$P4O zdaDtYZN^0BkwijuSB1b}d^MR>ya${Ki1zRM*}VsH)eY)5JqxxAoG@jAS(g7_j#Xv|F%1n&! zy4)xXtgKxue@{nm)d#4+-fK2@s^WNXa09tj29`)sybrJ@k{;3*)SaIXfw)KEo_7VI z>OHe#WEs}KN365pg8YG+`T9oM+MdnloK;__SjpZJhFqUm;S_a4d&&R#&^bjOToulU z`z-O9y(18mX)EU^BRVyoe?M{D%OC#-cpQIYWMi`v^b|Y1H}k^J$0tj`)qJBjZXlVB zg8P$_^LK>NA<6-g(hjSQlH794d@n`B=htOnJ^f06wkrKKfy|cJ1rPlnpIBt+9#&rX zG4;lQG0u!W3HqC&3ctt}kNROuY)r_Qatk?ydbBYx+y_*PPMu63zP`C7U2%6gKR-ElqmY=k4O1qTbdvC%6E)EzL+aiE@If9%Fm~L3u$G7 zv}(PL0km_~>g`)boJ|28ZI%BDH;O=E{e*{9=(a6P@kw1?q$_0diwR*b}R+I3KP-gf=wiM z!%NLfK^Kl;!yik&lJ8IS1VgkovcLV9J8S&rrR_> z?m`l=UiQ)4UTQagj80)?!AMMwbDT2Nct|mc*_pYu5K?^MmuEs5j$335dIxzSZ9-nC zxW(GZ6Ok9;q&oSG9Mn+N-&7>O2CnI#-epz_HZ^KH*6g#^dI|Hn#RMjCf0S%&oQO}_ zhE15^#5n6GuiT`on~vLSG!%`>b{HeiqG)OC1lWs8N~EM#U+Vib3VcB%#M`+$NPuI7 zd*JjB98#{ud^nN_UChdnYX?sKLz5m~V{MHUCpgxw7k9ha&KzmLx6lPB=Zyn+AF;Uc zb1+ph?E42KL~T)4;$*bh&V7EiKZLfbsi7m{<*p1{jpSr5&1;k*fj{@qxoFqbJ*a^>7z((iUKaE(RzaM9+JaHaqgQWUf&rIK z!)) znR(x6%cQTU?Nk48WMY<|?5G7!XM=DWefdm(tbLzViI;s!c4JAVWYG;FLEn@c&DmCe z|GcXEA6NOcW?g>p%A}~GNZU(4_vbmKBguxn{K}x zVEEcJrfj}1hO)zSS?&GC_ad3|IBA45wO(;K=dU9qq}C1^ABVv=HRzR7q4}J^-;r5A z9bF3-ofN}f#~5-$pFijGn^4hpr=U6#X9^9?;u5cmP8gI+l8x{E$q` z>bH&)?)EtzX-e7(8($4sEUPiqH+{Bv9r8a_IK-^Wf3rE9FmGaePnlR;Z>#RCv8(jq%0~z{F*jfM&7VER zM3wxZsubS+d2)?;1b0H}dMz)8ZILU-M|mDJ-fo|Ivhg#sOtGi$-?T2Aain}Y;d?}<%~DDod*Og z;Dw`NHhh8MZ67Thb~;@Un!iM2R?U)R-G?tfnyTttW4M%ksD->rCu}C}oDix1T($@ydsL z3$tn3Aq$m@rpB*lPT%wK`dF1F){1gbdlGM2Z@eDq$2LrVE?rQtNf+e^wCayIzDUrZ!{Aj_bxqdAe!rw&`ANXyEZ7k(>EBWGMCpj;qp!`yO zJQe@-@7+ch_kQOlbyHJepHsR{P9xENOD@loa2RX%zLe`${n}R_3dbV1_>3Ml_hg`| z{9JAAVRB-Bw&>fVbhpUW&n0pGl+a-qm`Cn3@I7V;vhbG*UUzwL8C~6u?anKIJ=@ zg7k9BQK4!EvAFG`k)25&TgCe_?%gLMZ67TibfC=|dCk6}h5|xze4#z=)2_zG83`Ly zx+R4fB*>67s=c zoX>n@GGe0jFeXnxqAR1~J#{KtEe%8aei;*ELi@Cn!gbeK+?LDTY-i!UuxlS3e}7baA$JuP0pok5z@XNfskLLMVn3so;lXLXx}3?{tz_ofo>`xrZO{Kwrh zgi#gMD2Ax@J}Jl&?m6!-N!`KF9gcZL`Px3>z(CU7`lOh?o1Vt{DKe{wwT~sn;c$GN zrvwmM`^(wKSU)gt$QP1@^1b7VHdOR+-n6~r({=vhsPjvC4uHBXQL>KFsdEMG06tck z0ejU{qXH}KSaYIi-aosdIOrMB#V5&-4cUptxLWA|;=K`CI$s02ytc}YJ z!0QuP!UrkzFmT>SzkjnTwsj&UlFjty%{&xLH&BBkDTRa5Zz3Hd)N2^WHh-ClbJN-H z%cJa56R~(>VV`TBg}eIFeBoMqm_huj^r21D2E__m$!g zUwlpBu<%bo2iD6tX5fVULVb0FVscf)rV866k#U`2NbQL^>`Q({O1w&gl8TFQqvMxv z^>lZ^&3Gn)C@_CH;=^+uD(78zdDCwEo}n$RzLS7#7a~NA8;%?zl~h`rsT(X`HPkOn zW!uvX6~K)I+VUzx`)m2?8enOgcmcVyWbcH(5UWt`)3hIDr~jtyAsXME_}+u1J*}2) zhgBPk&L&^!s5uF>Dz%_G5cmW%O*>Z0+!&D%1{X z<&bd6H+;P~XSN#D4dUDT z=DD}sE<=wP8Dklm{Vh8SX}28f6+N0TR2=1XsMF5w$llTKHqoyW%Noz70afjPKhsEy`P0x{~{a`8?P> zr7EHhO4I_<$2WeyJ;-gY^2s$4##VP3Ij#4kIkWBCSHmHhp9{@B{!zhc9^Gs7B<_Ik z7(*tIkNTRaZQs<=TR&}`^0uA)ZPmMp(6N6J<#Q+c&~Us%9@8x)H8vI=kHKCtS$nF1 zhK+x-;%nKj`bVK4ud+?8>|9ycuGebNvFBBfiC7JFLmdWQg{y#qkj2T1Vacfq{nDmI zeIjUR6U{PTey&h6cgv^qjr89MyzF>COm-VI=XbZ9bu?46j1?EVJZt%qG*>n@#tvU? zm`kiola$pgKYEk3>=kGBu#u{2y4KGycelXSD4Kc?E~(;wp0^RmCSteX zJKLsBKrxT7Bhr_KM!}eH_Xla!{c z<+J8C(yFOVS_-#{rOSo$ordIs6qDj4^aN%BrqfvrS@fzjXU89!4^qbkFz$$20Zrb@ z8(S3p+G+FBy(ZcC$O>()ceI9yxVTa?uKF?h?zA{8bvjx~5upUl4X*}GUMl^*yr;+Z z7uM(g$-^Z#`7~&(8Yzpi<|6=KBJ*~q(z$I zvVIfj9TQs|&b6)&TOlP?JuoBZSOFRgxlew#?WW7<^|2ELEZQ%NXsRQ>y~LY7MoI6T zanyoV1eF+sJQYxFJI)PdAE^A*e2;TK6meg`e*IFSGpF?bk$=JZ2>qb|(82;39Q2u& z*B4*mTJi&(X3?e0C@PXg;$9m&wy`<9etVi9GEQdyodm1uh5GT&>%Np&huJ@vbrtfy zsM&x;f78<=l|O@q;^|DBzs3_7Ip2I#2Yl0!mY{7}Dkw5qVk!f)R{xrA4qM3R_0=C{ z{!?!)?20N_daw*Up}=5Nmm3pvDFnVOaVPrFleJTR)Ly2`bRI>FyL(B7KwL#c1nTJ> zZVHV$qRv1d1d{UUdww6KQI6-FeSICfyGhfyk3}~b^Fpx0utG$cYf4M%&gUShEwp7` zHBI5qBmY|qFc5lG$DGdR!&<^VTmRANpEuSOeh+fQ(H-k{pE#Qi>xam*c=U;>C}>%b zY>TbJgtoMJT*6b(z);i)dxPid_D|S@I=V_D|a5I|?xvD1j$G3iO(3ZB}Nr)3HxyOP*?Q475 zF|ywg>gr-}C^R4Is$5x^y?aop5Jmg8z_s`bFI5F=R^#y-CMG_?@bJuv_64>F892sW zksqsMOe@;Vef!buGIYLgLfBovI?a&rAK7_vFYU3Bl0PUVLzU6^r%M!91#f$p>SN&} zB1Qv}mo^Q&4_#Nk-gk4J{~@FX-|g4E7A{TZh<*PU71|AWG;EoNn(yt$l$1~_jS#yN zVWo*9sLeO~xo$nMn`6zwd-9W5Xg~j^3Kn_0V@>M28WOH+!lqjmBgOMo6C^I) zki-F~0aO@mg|vfW~ZYuj~YV>3b{OfyE= zF#c7(Q1clbf%@R!#XBjfKKt*o0GOPv+VRh6U+@4|lZuI!nb!>*Z(+V-hyUK>>ypv4 zFZrAGFk4`t&C)~nM?)OEQfvQHLpr^N^jD45(6%I(d21dnP+%6q`KsCFj zQ!Q5hFHB8fXm`dP2Thb*P@wTnR)E z6_x*pXt3J+!@A$6DxDuTc;3QiCTA!}*m2UtjOL@>LWT+yhx{%Vn|vXq_WyKw@Uqls_@v^bA+=K7>-tYUn>#qCvJ*>qn4tw_5@$~*Y z&k1|_f&df$@cx@ZsGmvb-udS(r=A~?MIhUPKSC0)puDhB(YJOA}0M>?B( zd}3QiJ7kj4?e%)R?4?TnduC!kKUalR=G0eQZ|K@YM(!T|&$W~yF=50>=FtcY-ulZ( zIV<_|t<9X1|71l0jUKu4Ve@f?)Wp{x)H)b42?F&io+>a9X zZxR}FzDU*XCdH4`$aR9z|EB@)`H&>0(=Z1i=7%^-$RzZC7EX9? zSP^Hel_7(H6c(i=#7;_b_z?B43KgCjAq=Xj6^e9(wN=)5bwXQ=G?5=WI!+b( zVWxnNz(RNDu;$_lk(luHME-XHzb22EonfmJajosMkzihWIO^q;X-%1u($d5kC+pZt zXN}Cst?klooFJ@n{^LLa-)^A*R?INEx=yNV^Q5s6Q5*;RUE%|bNNaTaOfWSq;OL0t z$~E}#m9ai?CGUZc40ScZ3uLg)oR9@_<_iR2AKY} zoBY2z(D>`^(gM_Y;v(TGwt3C}9YyJl9zGOs)dpA*|842*zkGJ_-#-EK?;8K~U#sBE z`QTsc52Ab|{;#QeV@M7Ig6==pQtSV(U%l}E!i-)+#@#3YW9t0~bb(J(Bm*H|T+hF%F@ZEZh>>u-7#Uz{~9{%3vg z+ams50SWU{`9}j#7q1B=1y53^yrD_-jJ!$o>uG?8@VRM#>m>~hHw`nl1VeC8P*6xf z0Oq+=Tb=H_MwerUM4M|n-6dNRK|TY^BNru>Or z-A}{`3>l)o^b4DCC(3UGU`9zv^%yC0CqhZZG1}jGrD06Ftu)eB$@#`}P zLca@NQbGBN^k zA|eVA8`?AA_HraabPsE^ROcUX*B@!6wVJzUf*nBKoQB+q{xZ`3exdEO(iJn$iP(Yz zL&H+?0(I{mdc#tyydaHFh&15|4G9Yi2_ck{4-J1C5FXq1*$DVD54ZUZYn-cET|+=>XtzAfPfek898}yI$`uHKHQT|5D1NrR~Rv~6wzZ86dd|kmuzDz z&&JG|j+@(7TS8YCV(;AqFzP@3_ZU&ua@n7pMCRq?T{3Z@y=$T+z7OK$Vqho`;>id^ zDX&f+9_GzJ(nKw>)5t&|2EQIi6RIS+owjq!Y$m4mX>w;a9`%y@nv^FKt={Z#mrv39SyJ!_^jUocB~Y@nJ`FB za(Xz>FWGTE7dK=L9fbe73oCDY$e24I?1v1A(v#LU_Loo=PO>&@j5U;!*j{2eP7 z_spX!HPIj3ixn^Ky3|F5?xZCIfN#6Ewx*}2Prs;getQJmHjqsrq@ef{cG+b|=_phJ zPy@%$9U>65^WTkXrUbdjxtje8pAZMza*?89gJ+&HYS_{-I72 zP}5Bh4EA-`7ET;!Z(oIWJ;Do@j?fZi^Zf1<0Vv!TcT{{xL`qH}MsH%&VfL(xj{R=& z2$$pY4l=wM5i))QK)(?wD@UrX8p=qAGDL@8Jgw*v<~9#WCnP846DMy3 zY(AcV9S~@l@sl|#L8vJy$sJ|>GQ3eV9I`faXA|qeo-UCGh`Cd)~RgeJQ zf{BXqauX5|MB-EJ!V2$!Krre%u1?JB?gpCE(n^mda75S2{sDnxdtYTiH}55HQE@#x zng%F@FEWw<7?89~SO40XNT>Y9$OxA(KhO{(QxNp#@)M(tOsF)KXfUuo-s2&R1#ax6 zfhevlE`Di0{d5pWrJaA5H!P_ENqtRlig*Buc=DI4i3kV?$Z2^HF@zG#4?%CtJBcPl zNL#?oe+3nAG$o^eQHq!zE{J-#`d$Obr)zpkCS())Q0ZwWX|4Z#QW#wGaGjpPN ze+M3It-Qd3CVv_pMi%&z|KS-xX(~@hY01e?T&FI|xQMXD&_HyUe@U-&`w4&5%Im+2 z*He>s5bF)poHA05G`qk8Q7ep$a97Mg_}!*9TOs^eheV(^-~XWqBO_l{W?M*qeM{Kg zYVN2qjO^{2-bb0c#k_01m@4))mw`r=x*it|)Zz>V zgCmr_B_XMSeZ&5{Z(J_TeS&xFL9N~-D6)F}y;ksIPsTQS?5S+oqxDh2?9mSXtu{`6QWzv(2Q1B@>Enf z8Vd?H%^|q$7FuuYk0@R+SVH=(yZQRUy)Jtk{$V*j%jrWLWh zYddSrS<*>VVCwS~pGH)$Jc) z*0f^ZVzJ)oJ$_kTVPa}SbU$o6DNQT{`T_*fnLkYE+Cb|0ndMY}>(O=Mj7|-x(lgGs zeBF@!!)uw9+m1?}Bd@ZbWGg9+qlBR^LX@eCyLoO(S;NM;&%fA57zFz8vLo;bKb#|= z@Ejpnpz|{KmE3l%cTPPtZ~nNAn`8I2j6*s=Tq#~H>z0@x24Xq{J$)m!m`9%u#jHGD z*E%$3lRN=fXOWUx`9bCn`Rv!F$tJtMm7Z0t>pbu;y`ZBykOue{O;6PlqiBBZmA%_c zzs%{=VfCgTqc}mtV8lkyvB|-L)vos+MOjMw0hev>L=VpHREKH;~bi@*lOK`O}m6jlETugXJ%ceOkyBxB&b@8^y6v~@7b@1 za2M(egJ)w0ccl|&ANq~rG%!!36unoesaBFnG;4kcTH-23%c<4GtGBgq)IbwktH#~P z2lnUNGQ;P(z2>TXZ5Velvzv{@1HG{m|HOLm0AVGYe=h>Uk)I!|cGV4pFLEQc;%VX^ zBeb^BuR5G`Cix~DhxL+gC=pT?!_2+OfdC&CRcn3jR~6J52V|?pf&v@1XkFI(!Gk<@ z!8LQeQk_XG?W2w&3X3WN5GX{>iLZt!Q;+t?j8;7}`gQ_4pX6j!#k=a8iju65Ar!#k zh_-&eo!PJ-VRDYpA^S*M<2XFkwq7G608S-r{I(5q@{euD0^qmZ39W*(OXTCY+!m;Hugh!2?vt={>nR4_nvP zXraW}3TZxWRy}IvsY?CUdC^Y<&Q0}Y?A;r{hYljJ##ktd=t0pLNt)P z%A|^%+-O7LCppU+kDd0>;dEpGvlm6ZiCn2-aKL3+PnCaC%7*^wEX&(>@!z!PZ1bQj zOu4U81F)I*=c>vsvVNt+-t8VSF!8cNTgE9_nY_ZRt9QT*_MX^WCD!k8i|ai$zG2{W z6gm=2qT9NYg>H6wP#&tCz$n%d^fQ??1Q2TaDi_;qr`eZLj#tk#w*GWMyTGtwutrDD zb)PtM2K*}_I;Bbb^6BtI={nmF4<)7KB5FXl8E&KVf2!7qZ@+N)I$bC}H#+#Wes3o! z&H7_N_sGtN9b1Fz?Z{%ka+1a^Cs^({W%-uLF4PSF5&@YH(WNDct;}#R$>% z5As88ULmd0Y|AgEvP#7M-81rU3}hUFUlP-zE;E20#@Oc3J`zf18uZ#LSUa$2T79<=_spyVdEo&-<;YoRH;aLODfulIgQ~3yJBFp^I?6nig`}Vk5E7Q#m6kx_x z*V-!5Y}#esOaiqdRR$Sylw^L54Qd2nAfP!l&{(HWr+6TIOm_R|$m)*m?~2mNo5;!Nw+6YsZl#9uxS%E4ru1*63SO?_^y;Ls)&%z5pUlZC z0loE^mQ7%GiciGrgWK)kclqUC)=mz}*NIK6^=hI5N~KWv`@~gUFF;6P80WCm+v65T zr4Lu>01l)#xH-nb0kghAc?0^r|9EHC>fm4$5Xpezs8D0mSKqR`G#OaweP2J|43Lwh z3ACV4NA9isen!s9KwJp1;{iJ8(AVtq1X+9|UzG>Dqos2H+nf#2#yER0P#$7kN=;xV zuL6iNIrlu9rnpeg0tD;^AfQji660`-6v#rO?F7?K&+LJu6(KvILV=+Ng)uS3Ub*Hq zKN1XSQR-z{Y)BGJg38YQ2`$rOm>Aa-q_Hy&+9J^WfY4X)|<@EVwuDt zBD72m81)1#y%^!p0wfzWWyRt9$D;aq8T%hP6NURKW4#LX8asvinkd)elH|ImU$%&~ zmO&nlEcR4puamZ7Nn^H!!m9SNiBotaTBa28n|ymxXv zD@s9c>KqgKR#9`{zzkKYQ?IhD^H2upRS(+d@vA)jVW}R*LlEcNFFLrf9ti-OaJpGzIj5`749gG#fwWvto%kSEob8UWmH?am&{l77ao~n|hK^qOq2~2> z>(lyG9P`Oko=j(JT=I*)?U-6BJa#%L-!6`;vzqFaG`4nNZD8SSrUc0|$ezkY>%09( zVTDfsgIua*?veur>7YqiA6X(fD=H=KDHvJG)co<5>+Y-!6Ek@Uwx1*V5>UPG0KK)a z=FSbw@y3528d24EfKhOx@Op@9QH2h3)tv)#y;lK)W#*y9;{nZ4oV|*34?#Aj=i{(a zte@CKBD;wK9IK=@N0_m9iaAU5j$NhW1^{g12 z&SqIU#^bCrPE%sjJVs)}$}@4N{C|!Tfm$BwB$VjZZU0;~3jGY&iKNxfnOT@M0kuY5 z&Dsei5;8Dd&3nHQG}wgBBUfj8(i*!kA=QQiMcD>9&Blib{_2Ifl-}u;E0R7Pb^$*$ zP=e8&Me>w%F3+e~=);Vjo;_gTY1OC6i=Etj+9+1QIJv6#&L$7{x&D4&OBLD0m&AUt zeh+krd8btM>=P1Gs|vZ1Aqo@`a6lg!>5)Pjkz2jYxYpY`PQ#w;t?aFIor|{+_WF6m zy#?Tqd=|U+tt( zkV3;pJIr3=VTVJ?*MR|QDj*5)rpOObaKUsnVS!rvM;hi@%-JUkJO zxuxDJiHRAIGWmgWx!M%#82TIOcfCxGf;fGHymkgudJUBH)OpPkuxm=9r-p` zs)qONJ>y1XX=!-{-!Z7ZY4#@~dpk1ngh-OxODU4G>T%4_f~+sWeBiI=#Xh-~0!l}w zKZqVeb7l{IT+JijB#_&-9c%eNmPDg|ZdQU~;b#!!=bt?Zcjy1A`g#}VTRj~Ock&k_ zUuo%XvqxJOA9{>{p1HW55O9gZwj!It%7bu?n-okRQZ)A!uf{gJGrk{@yhnO+wI-^n zqrb2zo(a3E0sP_@1r>D9fJkP8fU}|VQs;1Ghx3rw_dA!_=n8+Lk+3ZgRmO$5v3o}G zczAmuAS{PT^(8a&D;S`}ND1Y!9^;K|rbo{_ueJWlO!GZQK4ZE?ln4#<06!Co518J* zXjlx0J3snR>n9O1Ly$~RSYE*T;mJK|nJ@M+E2~F`fEiE4K=c@Qbo#?EdkYXq68Per zKuGwKo7*fN?LUD&yt^Qb3Q3gVBDuhKcZ;%G7gc7>dm#ML5NX6-#m5aF*3QnYiXn#L z<_DlRAO1#`#Qw$^bhqdc*7H9j-#CyTOARwtqJbn9rk_5>eVAM3BWYq6QTQIX^X#va zEq>>YBP3Wy#DrOkbZ{)36a4&rJOIlyBXFQumXWF>YC|0jB%98=n#)^)4Wd@N^S1E` zC74FU_!$f(}|r&B*v@@J;A%^XGTX6Yi!!?dvNK*gQZ_FKi-#$kiwAx5%<@0n#$` zvp)BL;LYFYh?1<)Yl#&az!ZJc4Tz)L={GNI?-~;@bMdGZ17WpV33_e6UWa=iS#jBp z{)k#xATo*19f*o}*~pbRd;tg>)r|5^{{N#b+TAw2pfe&wX3)?b09sT9pSk_$eVro6 zdkH(%jEs2-z+$IK0;BYf*t!s!*8^(C8S!IWV+#}A{R>|=gOE*fT@Wx7?e2CD2o-z! zGXh~bydS+^h5zTXyf-5Ns-mXRD&?S_m)$<#hHQ=yVKGWVeU023JAqYMZNv=6vF|jDf)WKVcU)-D7~Kggg+Z5aWvdq=_TZ} zWBrgO=_zL{@9(&zqHb7jKE$`#1}Y07S1KKLONlY~hznCG zgikLJrhT3xhpl4%VC$}dD{cLeVm%nLoblq`GlUy*uqz$a4!g4ZwFpHI^aO##IQ2bl zn}gF{A2Nzijmv1%DxTtTf!i^}C+O!gfC49%$!M6^sg3)1-7Wo}v!E+pppdC0G%{!u@>(w^aP z6Kc~SR;;o4%=){GckP@8T&U6xX{l%{->Lcs_R{@NOPVKYHMA>e)J77BiEMPljju3p zi1EP75Kff!3Wt6+rMXB=4$3P9otjVG=O5uJTw#wq=GD$mV)AI>v61DiuH7L7iSMl%rR!^#6Jtj@4_bHzCm zr{A(OBi%*0QK;H4Ca56TqWvq4Gm{-qb0; zK9p~xTg1VtTE{pnkvZlQPI5aa^YnE_n$^$~>wPcho&p(z#)%~!9E~d4PR;9?5pF6O}Q?LLmHideuJkd1b0;-XMAP`)`+9ohE1@R zC(ScN?e>xSu2X}+)>dIiZaT|m`3+s)G<1^@aM?hYOX-Z1230p<>PiiVaXzeKHu(uv zPHP9Z6|Mdi#)AK`MBQ`NE7rpOQQh#_f2^lv1RId!8_L}X;}d+jbLIm`YkqUe({9+#}D~s z$|A>1j*--0J~6K|C?m$Rdc5^DRNMMMyYpEn1;>=R`G*xl_%^Q@m;lr?0uS zjt!Shk4rpOcF6sQni6ggNBYtX0D)s<`l@VwZchJdTpdDz*!p^K5w3T9+#!mwkHcYE zK96pMWe3+vtY8g=QyVp$*6+tsIBxQCU)N|2^1%H$AgSTJVxR|@s_ms@32n~|R2EdG z95S1_l%>L^hh?hpylx|AgE7!(xC;#2>2h!S`855v3}9(Bt0KuKxYfdC+dr%h241-! z%K2bWQ(S{f>sKcyxfJsm#f{K*+q4e&6S3cJZE`3Bk9*Ln>bNMaQIc64edWZs}4g9f^6;U>`OenP^X@fu78VOp4@d#Bz* zIC_9QNOH5T2`p-phcde3&UQxodpdmEZBA**PrO>C!i{UbF_|+sXI&9By0YUs-9CSSMx zfeE8V(UmX5j@V?mFGymv)2eE{9 zJ**Rd*xawgN7f|pbvX$l_*}j9#3K&&C!k+64H)*eu?6vsS)6>0^6Ej%)1+%Y7S=KQ zWeUAQ{O_Ba%XPl~f}pDXU?eaCxsEsrVjN1@;wdD;xn~rEs7Qt!Q50_cMU58h>APIG=MB|oV&_e?{k&v~ys5LX zRpSWhDY<56J!fzCKi>o{iWBK+t6B>U&^YIh zC-JILky&&AQ`Ktw(ZgOo?YBstxS40WwJ|lweV0GGHPtXWla${4LRXy6;|vA8kH^px zupfQcjWdZ>cXVp)39I_#mSf6zE@GDMx>JjdJwnI+QrRwtQur@6 zw>C$yA$wHi_S;N!kB@;8Kh9%OLaaJ)+_Ng=N*NUevB^$oZg}%t%`(A|quBG`b50*V z^fJl8rl(8K24B%QqECmT+qL_NQMxp~wD7ohT>#$)YBW%>P9KkBiyBj14}6CkqpZA0 z2_iQh@yMPKUJe;}A-5aZ=8M2_RfbbZhY68r3GQw6ndxfeY(w|`lAhhyT;+JVQ+aw= zM)D21kI5DJh%t@H!>J`pl7q_a>KA7;ul24zd!G{cn3!0JgJ3Zr#L~;TYUt05QN@AY ztD!z17M?);&NwV6V2!+x;h3z&;B&LBbq=Xca+k*yhCl3PYd}P-)~)zwrfOV7oYPvf z?@1My*E#8G8qw=qeop-9&-=C=k^0HQYpb470Zm8(?ag7f<}*RzW&ngY#MSsCto%lw zdtCOjyOsOq`om9L9xL~Sm?_tsx?%@7W-q#RmzU$8g*9$22YTSmdXVznoV5L}GkEgo z%DA`g2ANX=FE}fNT2PApUe@pTSZh&Dls&oMLYH%cNJ@c25wNM^#-aIAN-@(_rKzC8 z1>=f?g~k4ctNPsXB0yOL$>}$p{9uGX@gg5{m~G#Mj=!H{=s)^pH8*4oD7Vi0^^WYM z>&}Z;>C$pxn{85klC3FqZF8gZuMJji^Y`mNyIjv6HP*v69PJ|67HpPY@b05ws((t` zVvMq`j5*|-lC-orJj)?Wc4!?uYn-#yxD-4Qqa?IKQwp@8Y%t*Ug}c@)EEnsR`&RCm z>U*AWaEQfhEKJ-3J)j(8**b3-SP057nd#9^uG7i4-w6jaw+ly#nU~Xr0MPmjdt{$i&oG3J|OLXdtnyS(EmE7{3z$?Q4aVm7nru0My17-=QQ3|0o^Wy(_ zwKlKQ1U|s5_fYh@oY{Ax9RLEi^Hl<#$~_;54g&EYw}A==p2|mo@h9*~__!pPm(e0$ zAv#^j)lCGUFRm_1K#<>bO_e$Krfv4@B5*}u>`Oi&65`#g?y((QQ;THywE9YGgJ-B% zYK+o*m=DX(p&%xd`F@s)r5Zux3*V@xQ(8|Ng8v)m?s{G%QC0KG${4Y(vE{UXLxJH1}~Go1Ge&!il@f_!bOhiL-R_Q&UBLd z(7E0VnoM6Z_PBvwqmdPXsHorV$7B1cZ84F1P1#!fROvNlTF1-5lM{NHVmF7(`6e!& zHXzVJsfD@AJL5phgR}s@6b5)~ZxnNO9$xrli&<=|ZXdmD7Cu2woC!zO>y_%?*%kV= zW^C#3>%-f#$m<`vt5~zWYcpWT4-{jPex`jNmrop%_nHxVgMsrG|LnQV5dZUoD!3>b zh?CvsHGRQz6uN4=b=S%z3AIb7>QEq*mG!bml?5W_xHhI|)M;G)@`#)#I!gHJ^PI~{ z$aUQGhI1S{G+q%iZq4(w)&KNRg@%2@fSv}?#rTYN;Y;A@eV_EBTQ!CuljgkaUm@1d z8SAg}8_A_`#z52^@^)?&PR2|iTg`Z;z@x48$%WKY{Ql(n*><1wR+Is^b(nXjP=VWu-~(p zWf2=(=$?b_lL)ZjH$);@q(bwq)*IBW_2a*sSgnq-{O+5T10N6~SFvXUPgJ6})u;$Y z7_A$THa3Da#Z%oW&cQjEiVR>IDUNydMa?=P~oI&eeJTT zBwd9}hIcJo?pcYKE|k?Z)wa+>R8(11@3~G1boOa5Pt(sL?JARlGRgRW0QRQJtL32@ zQV(l1hemy6&k&))8yF=jEM&`e;2fEIl_O$tzW*VR5r_-^%-Apyl_`EVlQ(|Abee}u zGN+vj7r*y#(fORd^{Y-?on>MCNmjgmk%!Ewp9fr_D@F|(?$b-^q zICk=ulKT?MIyS|%OBU>-pmalhkS;cNXnkzqb+f>8yZOY8C;|`^jV|C$RiWx;6E@C; zW}BwX=4T*Tm8Xmd%Np1C;f1!xSqQ1!AZ;x~&i(L#_>nGlvExAL`SpFAKwQ85e5M*g zz0#%wWMw?2&2x}MAi$e}C0lFtA}?1f`Q$T9i)JJ?^_M!UR)wk?UG+{UQ(=8I{Ew=( zQHe`i)h&bAIBEK>Vk7u7j70#-D}$mutV4ZuyN0KOGmf=+?)bK4^wg8aJux9+Y3XN- zjtW>|R&;xx-ZtVV!86lg{lm2i3$OIsSw0%>9VL|cW{&}un1IJXQzk2!o?F$8R@1;~ z2!>;fXV(bua=6RDYOQugqv^WEkMOb;zSV6~pyKQFV*#6iPAXURK_G9su7|s^_uYr< zbUbI?uG#Cr+MkRzNj~8VNl_BxY?trhx!@WC0(#NQJyov{+Ka|?nHkMf@Hy>frNh@& zyUwfIo4r?O*t*}CK)z5;#nbxC30ozcciF3tRlje|9#P=wXpHxg?0d|_zgCwcRn!dW zRE7@$P$Bu=SM-r_IIHP8gvjWkpI%#8@sx{$HBPJYUYEJyue?qZV)v@WcnJVF-3103 z$XPmKOOrYG(({=`L4Yii=3Ax}H{Lad)x4>)iQS)UI?&yPta67R4qgC65&vSHN)71> zKYqa7P+jE9vi7Uv`rXCv7X4rl{u_CYIkv=ZLgMy#(Bpkse~_3>PI57{JXnDH;C-e zlkV<4m}AT>`X=)5N6`u67f*cZ2Kj>92uq8bz<~Tu*p^{;?pZm8P04^COoZN! z)0=5sctxmjFjFP12sV1&Fg-IpYr8S}m?lZ^;(&O@0-hT0os0zviPor>sU@msSz!$w zThRUfbC+KEbu;AZLU(+8`k4w9Vr0_vmPX%$#lYt0Y_MHOGOJRWMjWdt4fAzSzMo23G_NPh;*ZLsw?wWTDQSdw>K-% zItGO5uBhedWj#o?sh|}TXo*L1fHK_mC>ZC8e)8kkUn}x;a~GRafS+gqQn{5wY4*uz zm+_P42B$OMq0ilf8*D7j?uq+z(r3X+R7-CC0}G{vFZHB58M-xMb%pBV?C=jrNReqg3SSDVbsHT8j&#B?TdAk*CGjo5%v8Z|| zz5BD7_^pZx0!wj?#YAkdPS4YRtg z-AM$qOupsDyX({^>xaLQ(XU(6U?Q5=$FG-n`{7<3WBdLgh^chv%Oio)YPKUd@~Fh( z82;S)I$4Rg5nP?TJ_}hpFba158;-z)z5P7ciJXJSjlA&)r0)}3CBIS%4Zh{`advfFv=oH^^*E^sbdxw{i?w@VA}PdRA|@~v85#0 zvPAy0&w-m$MJhC+yqBS`s&ia9*KpN_DV^P{kI3g~z2&QrSN=If%3UmvbqzK;uJxTQ zIp#`kQF}sJc9frmUh4{Zt|(oT7}qsJfL8^_ymL_u?2sdR^fuGS?O+t zbsp0=vxiv|$0L+HJZ*z%k{Bdk^3zJK_}D^kD1Kv*fF8l&>E6md0<$|ZT$a;vO~Nod zXnA0{nlGZ%+~W`tVJupazVP6i~%7 zlE7VQcBa4@>|QuHkn1>{bD9fR@Qq!hVKZoD+bU1xqKyubNGhvF-!l1o_SS zHcRL2$?N7-*Q@c53r)0{mnqILoYjG2qDaWhsM}U;mG;=>xrKutF`kZ+(4{uAKJ)od z`5&ix;ngb5zI5Zu91*;O*=q`nnp|b2^BZ&!7S8Iex0IGAiXtcRP9my1zO~9O|HYhO z@yAn5>)?2kO0)P01ELv`)q6bAmd;rGp~Br-CYgSaT!{I+$rHB72e~$B4_xtJ{Bhy! zLQW|@rvSoy{e6M-2fUMM`{bjpVoR#$s=`RyC&Y1T1$)yGLWk-hYZ8Vq9~N$B~Lz)K%-S$9ICFeqJQpXxj|Wv&r% zSW*Lji%n}zG-;BX_esT`#F!1f+n5tK8%!hrc@=kc&*1|7 zz@WSmy*l+L8t5iu?yKBq_6DbSm9EUnX9`ouuMZU)78$hf^PLqM@K*`kwr*n(j#k8H zpF~bwZYPVmRaT-_KV?pHu+JSA`b=875mD9N>d@ydmTfpIifA62oTJqDJXU9q%56t3 za;)Z;Y*XWxt1RhrfgNH=TVP9IRZJ^dySTq4=oUs<2@!^I}&M8eun6(KsP5$kxi8$vyl+%?AS z6O+!h!nApB>3$IYcVC4>^abIn0o-!o20#wHfa1X!a~1W7n@=wM7KF%k-B-S0TV$q_ zKxUwM8{4XrxjqL;^CdMLsPmh|DfR|rZm`dHnfqFaWO|k>@BJ2Dcc7qT}F;)M8MYgt(w!VjoW|{jxY}j_P4{cWWoWjON|zQ*X46y{pXGp&m-$}t>q}gx z?)mKCdH5|Zh!DRs&{HLUt>Y4HSO&-PW$5s7XzPE1lp+#DCyg(UP65!TaYp_aMO{z?tFetJ(W* zimXqJ)_R;*-DOT(=2nf!bS@wS*}}gy?EixW&>Kws)R7A3Xqp?XcM%m+S}yr%xhHzF z8h;6%Xb5d~hcsPAD#e|_>+E*J^=N2Te~{X0RvCNI8V4=!>3AW?FY%L)ZZB z5I264S=}~21dcv8S`InqE}L@NE{D4%ojRtHXtF$RKpv!<{dso~yLXU#ZsmUM&-b12 zdqyAd_7Vg}^=4WAaE;x5XgP(o-ToV*=87!9uUSbSx>{@xP7`zMl?D3|>5!Bl)2~VU zZ*In-i>UOBy#!`5(;?bR`y3cRPSGH+l1z4LHU*)&jk#v&z@d&idb&dX?5o8zb0S5@ zi$Oz-Gncu=VWGyc?x@L|l~_{BgoC|J092v)bYHF@2JDyArtfzhS?OqMWBT=D3sRh2 z!RxY{3kkjbeQ7qm{lbPUyxFz#rO59t0Qc<4x0-QlHMzNoil23Pth|>RPGMO(P|8Th zK!|m}es3~{0}Jm^W|&|963*z^u7uk^Q){j2w@}7CaZVeKA^nXMJU8`OA` z%ORZArho>zCs`{TAMlbrmyTA3`HN>}#U>P7VvIAoa4K;L5nes(=-`-ch_($ji%ep* zb29wlIT1EhA~M7(HNTbmN9c<_`62<>Ic8#Fd=pZ~sPE_PoniMLF{{|vm4 z&_`+SdK)qK*~jh+kg-Oa)LTUl`@k0{lT&^*_bjQ&@w9H#pgQ>3JN!uCtPjRMjXaTw z>&J!zj-NNIhr4>x(R2SpPufn6o7Hs3q;I8hc&u>M(IQ>_G;}N9qfoo1xhK~m$IAk~ zT4;&;%xSpkYwg+_fs58U@^itrGkx5YLX&YSi1yqh6hp%Ahym#8h)AqbQE4*(O@Y7G z4P@D0uk)Zni7ESdLh0#$x@4{Sry;j(b}P#us0|NTjb14|;LKYtmfztNsI9u?!8Sb? zzvr}%`gcldXPrGuv+b>kG&h+0W>;B_#XQb94CGvodWtw2IZ{*u>e=dl9nai0+ay!skg1(d}Quw(Ew%=oqqzbReQzC+q{*rl* zO-++NdYkrppk{HkiwLSLM8tCMpKwKk1|Tt#M}>4DvLL43^@a;qfA0o{gQQEZfh=RN*t@hOlv$jipHcoI%cOr-6{?lpXlT2EHp zm~Xrc)6u1~3=yzT*MDVqeyl)~$z%ZK;X%eFqK1y1T5kKQ?mhrv7QYXS%dkxaz*&D2uU`5R zB3}?x(b68R0k@d60_^YM{?B$Q-oSI;U}F79PymV<>7PD(oOFj80tI5mCj7BG^k_zOI!+D1HK$wF6WJ?ihh5ZMBw5ppZ zzoUdZGV%fQ5deUyt-S+4spbHa1A!#|=D7VA1C>rE#vXsU4nVdd)FN<)3tPsx%NyRtX$0R@_mQLjDYy9!m{yX! z^jOYY8XO{Gsj-|-G8`b_MUa0p>PFvs%igu1qo*T60(Fe!#&Xc@PA<00lK3qp7%JVg zYC80u1Xb{S_n<#`IvZB0a)4NWo9Q$WI^p1|zMO?ayk~(-EXWF>siEdz z!;HrSwGxucadGi-OVH99@hT3-_x^)nBsAw;#$eCNLp1oA6vTzIw3zQOYftQnnPO); zU2;}ZU7Osv>*F(2~K7ygnZyeB3EF`b!Rt9_<14uY}oj2+{cf2__%kNvWVXi;gQ^A zq+4B`-9|Lgf&C`j$;c~W0)i(5;=p9dm;%weDeW$wQab~=7x{v{muiw7=^ep5nCV|1 zK|Ot-NB!TAjDEOk%aQYee|>0Z;tc$ByZ`=S4mLIaJ=~fHx>P;VXC~6W>}G`MGKx=&R_7YS2NkLw=r0o=n3TM?K0LI_ zwEA7VYx6u&?)a5a9rLzdsg)_>2*j@8>~AkSx(x@QCg}Hu|}qsgdyqLC@%BM z3Zm}+Mu8CIOt+`PwQ_i1rp6R@VwIWQj)BJR>gL8}q^WKwzb_tiy3-MHrcnGP9L_1QzLSL3rqRuaV9U&uV8Ia+2bVSFR#hs0&3&u=;X}i4 z`$-;o;jZg*SkJuasAW^U$_f9|f-r7})O`H~{|{<%VX z^O=T*;q5@!YDzG)4B9*4tf#7(ab(G^IyF{EJIbdKKZ|@xTSINla2w8B?$-a6n?@{6+kF;s-e`Gc1*SVXw)( zBMAAG7rt=+IXY&jqv`o#)rd56sQ0O1Q@P`f(Q+KS{K~Sb0#*Im>Fd7z=He{1xt856 z6^GO_^;AWrRp)bPdVT?ZNKGo+;k$POZZQDu?>qL_qQo(%s#N(k0y?U5AE4gVNp2IS5E|4$=*G z_v|%meP^vTGvCS7;X}H_RYUJuF%Z(FE)+t8eC7KGzm@w=?sp{h=;WDe zfVe|5nh&Fpq2O)@?RPSfVE3!pU4w%f7KZfEv2+W+dd@)5+-?=(bZN~f%3U$%s5&{N zR$J0)yO7xA&5?_=hV06AJA#2t%_km_?qz*FN{Zk@#xEH&h;6lSH20-X6T>BR6=5^| z7fzpjPH19=%Q&yf#z$*Un2%|CnkW-TYZ0Z)B8@KY=`o4G=?4pj;(b@5*(YG@!a4Fp zm#_h!y<4S6$z;H$xTk63qP+s*J2^{sF9kR1nVQb%ryhqJRx#$ry{u;NeKGq;>)HF( zR`G|Rua8}fN>j;Lnd^q1&iD1P^jQIhJ)XYXKk|ppC}-Dr%Ay1&DYQeiaHb+sdr*j9fU$f|B_VAT>yY;~;g;>0x_Qr#1mJ1N&%GxvMyVk??XaaP7 zr<-LRU#Z#o1^B)(B>Czw{@&gjp2%QXv`}9L&RXs_T&nMH9(OCe)6MNM5s-2knM}65 z5-$|=M6J)&vee`7a%2^2hDB)TfN3&FT|mCD4bMvE8n zenVr)WLegnl^x{C!v!}_<)$>CLWC8(M3uGW{M+T*gf#L+2DSu<>jq2I2>pbCZt*M# zL-@fq>VMCecB0rVti}ujOoQk+O(T~oE81lHJwvHYQkXH`^M=d8^FNA=nA!P6>hx$YDRTi0K9mG8Aj20NCV}4b#X{rjCftKdz|;H z{%U7fj2j#D2rQM_?4O>vvyMJvKfTCZz2?RGs~?{eM)|w5a;Y3ICM}ibY^g$dvetz} zhO1)lS>Tlyo|vY1j((GK1_Y7EsN>jLGM=rOqr%msv$Zg}>&ZIB-TXe+wb@-3l!a+v zM)$~y(9?4~mlE_grX4)rU}A1%>})Y_T|3mrG6$Q~UMMQA>A!sxbb0NL2hLo5n%bhb z+rgZeonze3Pb+?cw9=&#}@krq1a*-w` z?@wA6h`zIq8r-D*o;g$U{vGJ-G0HbaU`2aLVO>dFqK#(JmYEwues~bU;sRIH^vNt; z=AYH{LAvUnnjXK_fW8yQ?b;p5l=y8f*E!F~!#2nWOau`$o2qB7cnG&qim*~l-jBZd z6H1!o}#%V z3CA6?5|Z_1Csow&={<{k2S#QKL~3pr!_gIwF#O-e&0U_xs*WYfo+V<$nUc z7W{g93wrK*{<+$%*y-X>dUmm`cjI!j(4FA5B+hjGda4s%o9hp5>|4)EPPI+dr%sJ# zUm}(QV81JY(=%SV`52h_sF_)*73!Qb8$cbfKnf3M7zxl|h;Ci_-u|(fzO9g=;NqRC zEbU)kl$0t`6&t{KO!x3IwGa~1kF4hzL1Ozbl^LT0|0hu4|uiWCyNy1FR`qRcWu*5r5Z&E#M_mf#84Lm#z zyx+)}P$oHi#M4g=C9hNY$w%=)9fnSL_YPfL@`P06LIFKIbGN|YUYnu{a8Jwt-$|ft z{4@6ovf%6T3M%JLZM=!+yQ`u27U`N%z~i1RbtN=&60JABxX^k~|D==u=I6TX-kXQm zsxo_~p|-9c&_KyV-W2m5RoR(LT+SLSwlxEBgI+}$ycT~xpObL8;6rvO7ANooDX<48 zt8EP1JX`Sdf1;Z0QGP8JczdhR75*4;tuaSC2Kq^gdxP7Fm6|bvF_~n_IYL|NM}Wk}mep*~3Nf zy_MMWHj}db@z8PHBt&q!@hB*QcHTKwSZZlznPTyUbK{&zR?Ai7YlX4$}&wOaF{ zI6xcHaZVz!`AW=}q$8L%4N%zf!dF0djPS%bUh8zQGSXJtEa!>()z)G7ywX5E`kr>|6V!H8{}^E=n$eo;wHJS+mG`bgH!;v9GsB=AJYAiNl9D z)ovcc#x2SHIIK}_B6Q@-@QgPB5F&+Km6whR!kOfO_^$9Z^@K}(eOw89!ngjN4=g39&w% zZh7*y>60Y3$bBtYN7R@z4+;$(jSKn-l@}S0VGRYJVb{YCe&PaK7Y()#H^gtKl6EUf z8ZtG~Ayl?vcBD>M6}$A)^H^&;Jv#!`zDYK^xPyz|dD6hL^8I6^Ey(ue&e}889$by~ z=JGh@(U15APZoR%Ob82N0DrYa+Bwg>LT1k!9i-Boz;TLJYw{rL7Xe!wF1H~PK-gMx z<3(t~*fyqwh)x~=uHy;`HCHi#)Uxk?yK{|-#JSf?Mea7el5vTogi`#hmu~;lHh&NN z80EN$R=y>I72mlIFwvnj{vXW1vPQB6R?ath4Z>sc7MOc8R2~)*wUw28b@$<=k&7bon)+#QU6=iP&-VWi#(Vqi}26)GkRra_i=oN5`(w%cf*5Am~Vq62t*nB znwfmtf?Pi_tKs4k58?g?ZMnx5JtsQZvqdnPI$`oeL4ii>>2%vlEBg!}Xi4s`J+s;& zQS~MlwHi5T5JjgNq8ewz*En(PHmo;_u5|qNO0Hq(Bfdxzdxa+4HLtBa;4o}KeJcPDUQm*mXP~8%yl7D>+q`v|@|> z*(tSef0Tagzujm{DspMBuH6Go^^uNb@P0^@D8i*OuDi3MvSwK_UW>Pyw%ZAaxrS%4b<9mW@x9fxN&rxZ2}^l(~E#*Noy#ge2r!V z>@m*pzL57rJDHW!1FF7;0Lg?SjA`ra=+kG<@yt_tC0YR>^4;_a(l*YtHcL<_-r{=rZ>U}^lUl@qc_NJ z7|39+Fmg`7EeH7ECz@X03pVi0%=mOX67v{`hU>4WItc=Ycgo5IwUv^+9;3f{Um(X$koAC=8BpNlEB7F_K45_2)U;2LtJYTB0==CD7kCn|xt+uM)vwSiAKHTq z`meiD1;fD z+>My8#|h0q$IxN?tVC1{!TfQK-@&OC*!{jugU@PlQhTSx=d=4e!h(_j2iU_tQ~fFo zSLnOo##@@k02xH(QJP+EPr*9qdHI}(P>!3>?s9TsYct>C4-qg$L@+GkYb#MAxE`y% zjT4TBw@ViEhaCHsYOi(ZM^`A?mECtUIt4kLFTBzZop(kb+tR&{lusrh%|22hc+Yfc zqveGrcoQQ2P58i4Ra#M3vUFhu(rr=mzPZlyJ~2^iZ4-9ME!CSjU^=mA6u{d5c+vaY zJGdWe2hI1^%Zj;VfUV7ZRP=DZLvg)~?GZAzgHk9wGK$apZ6)$1+4QUpuIBG@`s0HU zgAP7?_TC#1XckTC6wHP(N0BcTb|^icMj3Pnm-+iubblt9SYRKakE8JI^Lic*Mh#TjL z@gZ2A_t^~ZOmFoC7el24K*pNWu6b~W;16IdGrE?GNMI%5v-X~zOm+RNr#)56NqNV| z3nmvCV?frhfFyyUKGt^0}LN|e@W@G`icM|L46T?e=A_*Jvd}3@p8EB$Pl1@^N<$EJI8VZ zl$Xk1&v=PXzW}qJ41d$yy~b~FJP7Ch%dV#JFl8&c9WA*@fTTnX&4$ zNa8#e+Ge4`coLLaVWAyqksnAB=$lp_lUEliYsDSf!Xl=*;<<&!u~M{TsFxDf}e?Rc9${ebFJ6XH5eZ$z3y1WK;$u~(-|U`K*;RhY7Pflb8U z4j+g?C~oGIn6k(~pC(qyus~J4rZvUVDNk^^K^=MAK{b~}U!7)2>bfm!#^V4qiJiAr zF8)}etY`F*F(GBT72qAXuf@@0S_3ZQ8K!@R!~-h+=BmH1=rHR*0trceJiH?K2=r;_ z@ne?M@d}jO@gg*Z^tlKBypKaFR5jk5)?I=F#LgdyC=+2cARn)oC{jbAlRpQj(HI=U?C)Jr2*vOw&`_UdT5&8HaaOr3Qb{-^p%*&SQXxTWG3g60ec zBM^Hd{TlDus+14@SWmI89U4dh_g*YLa|qYTY)QdO3Z0i>5B&Shgv?HU1@dl1&sri} zz3kc<%7D#=5n;oo`@578;gcZ|O|P|ROB(nT_3x-$L?3*L{dF&^Lg=zFbg`FRO+LgB zkOc9lmazK@=H)brns<7l5*E--dcx$d=jTZOp1uHN2A5A1s(ctqTlQRG#k-B>0tiinio9a80sKA>9NbM+eS z_Ej#%#qDwVEGrXI6JD}uD0=^|0KQTbu{~n;lq)vuo?ffzk}B+L8bBnn)HG%%RDr@< zgfZt0e34R4x2q;K-2xASQ9zFzS0;RZ-iZHaEr3bQynv5(i={UqQGy&d@Y}p~tNpfP z(E_k9f@Nd}^xSBOVD}MP>cN$aI^N#t+7JpNE`8%i z^dJT1e_Lmzq|`oatE51*FT_F!m`X^zefqR?-VTB?J^58=$h;*tW-`L{DxIl-Hmc$q zJ%~z%r}^eO(04MMR^)wJG7;tBjXvON@D%|pybv6NOn}erA$TE(9m0E z!@}dfu}=tQYA)I7xV8v!nqhE1k1@--_gMs@PEr9W6S#l4 z?&IN&AL2D3mOaPkDU*0~=U$Kfi$9H7H_i!u;sJA8x)>U^Na4YoJxZr}*xAkN=2us_ zG=>x+q9=n+>_P0)|7a_8(d$al=jIDFE@eezboetXuD5{F8gTzGb7`l3e#~U;di5*Y z!+tDBr5Ja$F7(O5*K@wQ)IkhT#9;Qk<(m|=$HN5SiV$^Lx-P3aJYK~i>-yBkXf`~} z>ZR`^qUB{m!m$_qRYA#5|MqLu{9b|hk$=A-N$nis^xWOX+k5G2g4`?M)5gN~v|!R* z0ltC5mb_qQf^Yzq!b8+^)k~*IBIO|Ji)Hnp*F-3w@jlxcaCZT2!n7qo^s1gVY+6(L zF=yJmRy$I?G~+xx9L74}0W+*yK;)>Ga#_}CLnh3pT&t`kAgf; zrg+kZE$bGodBOo)C8?7uo$j%yvs8REl5=lsrg4ADkhm+^%iX4RX%K?aY15j;JszB@ zMMR7(9!TOzf?Pgsf*b?@GZKhYsj^a#M}uoK@LDYv_0nNmKtl~Thp<3D?xBQ3Djydo zL5{^TK|5Eu*Md6zQR8y}NQo2{YA%hR{Fm#pgQ#*s;6JpO$`SvZiv|4cPcQXfHf^yN zul`FFO%;X%jFtbC=iTW4eNKqs|4?&FaQr=U=I>28ME}Fl{r~#$3Z&bQ`R2-8Yo-lr z7Rp@HV63ib!V@gO01lLw*(${!0ew>YD|B-%%LF<6!`$bAa9$xK}0|(2KysewRZ3nFYwuPp!@maj4+fcPs?a9G` zgM-n~>Jxz7I0nE<#V;EV;<~xa0X+fm{QN7Q3y~=V_0>c1b{Ojy)1zP6S`yqwp4UU$ zPgatv0p<{(&_Tp&)(!Xl=dGuUrb9yyNQUVNaA@vZ%IMnM3SFL>6{RV&KBfJ%bCyj;U<;%YBH;;ft6aD?BHTpZG zTkS$cC zd<3PhQ2;8agNFCho2+(st^C-pU(Xw!=rEeD2Kd%Ydp0iTsTXh14JY^Q-=ClYwAhi5 zO&8fLRHR;NI+9FaP72f(`^XM1+w{ByfaG}liT3a#-AXCthjv1HuFV!5W$MMTu?0>X zz*26YWR@p$vv7!vnATuprQXCB4PpnR$J(( zVk%C>^!pB+zXA|*mQCgK(KcN2@3*ef_R*sTWGIp34so@ez}P&oqK@Lj5x>ixx31IP z)ZvI^b^H6y=Y4xxlK?Wx73^OK{dfqX+Uc_32E<}or;Rpz`?@qxeeR2I8cc-GJX3@v zQxaHT1e6Z;kBn*)_>JPNrY+Ni1-|$;!#vdf(G?<0lRc`^KMz5MU!-!MnvGD- zWG|a)OdeqUtt_QPELcRnjRxv^RHw~?n-P8x7Q&LQ7X0_0Vr44SzG;D<0QRP5*1(rW z@cSiy@r9`4&D{Kj5r3irg9A~Jm;$=n$B`4iTu|bc(kX z+UDK{9mh6(BWth!9pvnzg-Bi&wZ5{Fk53Ak_k;EP6lVE+y6s!+WA?qebkVgwYAk0# z_nj;Hzwbrow#g%9_k?&Q5+cYMjIoL;SG$l2zL|C&#UqWQ0n~n^=K?w#A?MghETcnw zO$_fOBzAZnJKUpPn&**;WcYKuF6VSC&x!c2HTK-UewoE3%T8O zMQUqo`IzGrvp5`MP9++m0nbm>~kM z4a`eQi* zY0qxYtyAo|RQ+q?kH&QLVa(Kq?k6rrrzZk;q$gZ^rAc7*^?Y|>E52IjpJoJRqQIZI3c9{oC|l+> z)qkpSj@5s*g`&CN&igZWGN(ST%+;hZ-hKAYV$rL{x8lr8fHBOr$bRH~-@uCl;`)7} z!sRxnq(i>eyq;z@V{cB*d-+hsjXYRoRw*cSm}H%Aeeb;Oz!m!fI-4e75P)M(g&P5F7O;ZC2?oElRfH*3H3(IFF=C+wQntaZc$8VQKPqj3%7waR% zu5ufN&!gqZ$_hA@?4WIim8gpY?XpeipJD3q36kHhb^xW&jhy3E`B zcSx&)^Nu?EMwXjs^~uO_b8QWr`xxnmmcZk5)a3ZIUQea(JcKv_ zHp|Y@XAlGnQviH$z=gJXCtmAz;Mh~zbwAT}S^1!*NyVhnuhfc2-&1zDlHu+f&gb`0 z#TOJrYuHqIsk>0}Si?Km=u08FU~!twotHSaXGNFwHzx!Vjm5;rUL}iLO}8fHS1E$) zZiLgsA~$Sh?grMaTbIDrVB^I6q$z&WJMze1h%7eu0GJwOl9)Byh`qVl^d56ETO@h%zkR7i4j9ExR|gQ@5x^ZS{P?UNMl zy9@nBx&7t=q8R?x6iItgj(|-fvG?aa{KPF1y@>Q@3VK5}9w@vIsu330E{4PL&MhbI zmF4U(Y0quW_g8MqG;3^CN1>k1z=_BF>(b~9E@sT~wC|0bfEp+EydPjwCO>Xw`(}jI zn;_z}IUAT3u-|zWT0bdosYmbKufiz3Zu`{n#UG^aJOqTU%;HbNi!{kypuxa8<k22M!p zbwmp~8T0RM9v={QgYyJF&15OJNXl}M1yeY1=#37%r52uET$GfkK7#78Pzy(n?%5pA zwrw#be5<=POWTQ8I)DW4N^xN5S5>zdnKZh;cK7?*evNwRwo=tX>qGml%gUl=c-B(@UD~FF$Qe*mw)s5HW!1+3*>>tA1QBh^;WTV^ z@S_f^8A%g|W@Y5bE0?S1u8sFT7jwF)f7f|zpkP@=dMpT}fexF3>X2GUGK|m1WiH?1 zp{}q1BQ!?n{xpkjoqCmLlHJa-_@uVdqD8`AcxHEDJC zu5^hWb4zGBBO=-qG#ydfdF=#?Q5-2G%lDOvt-IYyR`s7bRmbU9I3p{_N=SJr?z@BL zf3RaQ=hopKXQs&Ci_4Zv@?w9_=ycVNLoeSGo`Y(H5agv0thD*PZYEU|aASoi@K+dG4rR^ui56EsNUDk?Ud=*Np)eHzgmFN^8_MkB3}M& zwrThDm`5ZUg@`*^M}%QNQ8Hn455{v{QvZDi*H&bHj%9UEm9jYC8%Bm}N676Q9#uB> z^oZ_weGS<+&f)zc`gzqYjw#^}vjIjdI$1D*g*_P9zQK2{r*@y&0nSUty4aBO$=rjw zSK=!b-bIJDE8^fhW(EfACbD^=$@bT`%n3i3`@Ca1&N57Ck_d@7rpyIAIvetnwAjO$ z@$y$5gLe2;vS)lx%PmL^$M0Q$&43RcqReVg-!(TvU~_S z^7o*@4zW%noM>8+{}712H$zt`T7LO z>p49tOQ38T%YDX`K8!vWxa3`3B`BM;#JP7|txT~XDt9Jy|Wv z?dy`7s0-z<=-sB}zU{4nA}?=8@Y&)`Wmj%?tFf*udWaeYdAv86jN{eIN?n#b=vANU zBzfQQvW|2=Ub;GH(091eYzY#o-MegSZ;Oix(^XM%`f0@38~={r`rdbbE=l$dJ#80i zbC&WEHhDe-2S$?#wQdI4i6tYU#aHv055%LZz%=|mL(^a1K?--vWLz&R>--l;qfUM= zRm-`l6OSY)d&^6&gAHF0yL`VZ;&6ty?>E&^XDWOBKqel(jY&+}3GyyF(+*~dPpXk3I9jhFj8CREy86N1lLGKf2z|#K$ex@2e4faTtEfnTa44VLB_yT4Uu%avCf# zxx(V2uo^vDRvXjvDbj^HtHI|{rbmh$VGEuaNYA7@}j3Fx&67^wCOAD-Og$?3)jZ!*MWMO zzV79FzZLm` zW`^8@G1m!o0EY>axT#zMcxL2_sAX|dw%#xK;bOSqVF>+`IC+k7clu5Gi|u+P6+ zJXI&tYxl}OiWPdBar1o4&a*5JQeOG9>W%&L$m0fmtrXF>Pb-c!Yx4=q`^;T>&Qj9! z_^NYsv!>e|W-IsaGeG{bZ1&S$qxj~8Eb_K?dm`KAj!vg11Md*jfM@eQ_EAgg<%edO zo`Ag-o;R5ZCQzLUyo2J%Uv;0v;%B$8pJY{cKy1jX0c5Lpp

qjOO^fV(t-qc(=CG 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

-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 l$2@=EpsB!e8<2pvuW~*Y)@~ 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 AAwFxjT!-J=D9LOu{ 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 SMU~e6n8X2a$N&9L$^QZL4Ou$? literal 0 HcmV?d00001 diff --git a/assets/processdock.png b/assets/processdock.png new file mode 100644 index 0000000000000000000000000000000000000000..bd4fb1be35df5cc5de63fc9a562c8b2b2ce78f55 GIT binary patch literal 13024 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 literal 0 HcmV?d00001 diff --git a/build_config/windows_version_info.txt b/build_config/windows_version_info.txt new file mode 100644 index 0000000..dac9125 --- /dev/null +++ b/build_config/windows_version_info.txt @@ -0,0 +1,30 @@ +VSVersionInfo( + ffi=FixedFileInfo( + filevers=(1, 0, 0, 0), + prodvers=(1, 0, 0, 0), + mask=0x3f, + flags=0x0, + OS=0x40004, + fileType=0x1, + subtype=0x0, + date=(0, 0) + ), + kids=[ + StringFileInfo([ + StringTable( + u'080404B0', + [ + StringStruct(u'CompanyName', u'ProcessDock'), + StringStruct(u'FileDescription', u'ProcessDock 进程与端口管理器'), + StringStruct(u'FileVersion', u'1.0.0'), + StringStruct(u'InternalName', u'ProcessDock'), + StringStruct(u'LegalCopyright', u'Copyright © 2026 ProcessDock'), + StringStruct(u'OriginalFilename', u'ProcessDock.exe'), + StringStruct(u'ProductName', u'ProcessDock'), + StringStruct(u'ProductVersion', u'1.0.0') + ] + ) + ]), + VarFileInfo([VarStruct(u'Translation', [2052, 1200])]) + ] +) diff --git a/build_exe.ps1 b/build_exe.ps1 new file mode 100644 index 0000000..cd19a88 --- /dev/null +++ b/build_exe.ps1 @@ -0,0 +1,28 @@ +$ErrorActionPreference = "Stop" +Set-Location -LiteralPath $PSScriptRoot + +Write-Host "[1/4] Installing build dependencies..." +python -m pip install -r requirements-build.txt +if ($LASTEXITCODE -ne 0) { throw "Dependency installation failed." } + +Write-Host "[2/4] Generating application icon..." +python tools\generate_icon.py +if ($LASTEXITCODE -ne 0) { throw "Icon generation failed." } + +Write-Host "[3/4] Running tests..." +python -m unittest discover -s tests -v +if ($LASTEXITCODE -ne 0) { throw "Tests failed." } + +Write-Host "[4/4] Building single-file executable..." +python -m PyInstaller --noconfirm --clean ProcessDock.spec +if ($LASTEXITCODE -ne 0) { throw "PyInstaller build failed." } + +$exe = Join-Path $PSScriptRoot "dist\ProcessDock.exe" +if (-not (Test-Path -LiteralPath $exe)) { throw "Build completed without an executable." } +$file = Get-Item -LiteralPath $exe +$hash = Get-FileHash -LiteralPath $exe -Algorithm SHA256 + +Write-Host "" +Write-Host "Build succeeded: $($file.FullName)" +Write-Host "Size: $([math]::Round($file.Length / 1MB, 1)) MB" +Write-Host "SHA256: $($hash.Hash)" diff --git a/docs/blueprint.md b/docs/blueprint.md new file mode 100644 index 0000000..6f5a435 --- /dev/null +++ b/docs/blueprint.md @@ -0,0 +1,53 @@ +# ProcessDock 实现蓝图 + +## 需求证据 + +| 条目 | 分类 | 依据 | 实现决定 | +|---|---|---|---| +| 进程、端口、CPU、内存列表 | requested | 用户给出的表格字段 | 使用 `psutil` 读取本机实时数据 | +| 搜索、刷新、自动刷新 | requested | 用户给出的页头控件 | 本地代理筛选;3 秒后台刷新 | +| 点击行显示完整详情 | requested | 用户给出的详情字段 | 使用主窗口右侧详情面板 | +| 打开位置、复制命令、两种结束方式 | requested | 用户给出的详情操作 | 真实调用资源管理器、剪贴板和系统进程 API | +| 原生 GUI | requested | 用户补充“用 GUI 实现” | PySide6 Qt Widgets,不启动 Web 服务 | +| TCP 只显示监听连接 | inferred | “监听端口”及端口管理工具的核心用途 | 排除临时出站 TCP 端口,UDP 保留绑定端口 | +| 当前应用自保护与 PID 复用校验 | inferred | 降低危险操作误用风险 | 禁止结束自身;操作前核对创建时间 | + +未提供外部截图、源码或演示站点,因此不存在无法访问的外部材料,也不声明对第三方产品的像素级复刻。 + +## 页面与操作矩阵 + +| 区域 | 读取 | 可见操作 | 空/错状态 | +|---|---|---|---| +| 顶部工具栏 | 当前筛选与刷新状态 | 搜索、手动刷新、自动刷新开关 | 刷新错误显示警告条 | +| 统计卡片 | 进程数、端口数、系统 CPU/内存 | 无 | 首次加载显示占位符 | +| 进程表格 | 真实进程和监听端口快照 | 排序、选中、正常结束 | 无匹配结果页、权限警告 | +| 右侧详情 | 选中进程完整信息 | 打开位置、复制命令、正常/强制结束 | 未选择、进程已结束、权限受限 | + +## 领域对象与状态 + +应用没有数据库。核心对象是只读的 `ProcessSnapshot`,以 `(PID, create_time)` 标识一个进程实例。结束操作的状态转换为: + +```text +运行中 --正常结束请求--> 已结束 + \--请求后仍运行--> 运行中 --强制结束--> 已结束 +``` + +操作前重新读取 `create_time`。如果 PID 已被复用,则拒绝操作并要求刷新。 + +## 验收场景 + +1. 启动应用后,后台读取本机进程,窗口保持可交互。 +2. 输入进程名、PID 或已知监听端口,列表立即缩小到匹配项。 +3. 点击任意一行,右侧显示与该 PID 对应的路径、命令和资源数据。 +4. 点击复制命令后,系统剪贴板获得完整启动命令。 +5. 点击正常结束或强制结束,先显示确认框;确认后执行真实系统操作并刷新列表。 +6. 对 ProcessDock 自身,结束按钮禁用;对已结束或 PID 已复用的进程,操作被拒绝并显示明确错误。 + +## 交付范围 + +- 目标系统:Windows 10/11 +- 运行时:Python 3.10+ +- 依赖:PySide6、psutil +- 存储:无 +- 网络服务:无 +- 已知限制:受当前 Windows 用户权限约束;非 Windows 兼容模式的 CPU 首帧是采样基线;正常结束的温和程度取决于目标进程与 Windows 行为。 diff --git a/processdock/__init__.py b/processdock/__init__.py new file mode 100644 index 0000000..b3b2d89 --- /dev/null +++ b/processdock/__init__.py @@ -0,0 +1,3 @@ +"""ProcessDock - a local process and port manager.""" + +__version__ = "1.0.0" diff --git a/processdock/models.py b/processdock/models.py new file mode 100644 index 0000000..22315f4 --- /dev/null +++ b/processdock/models.py @@ -0,0 +1,187 @@ +from __future__ import annotations + +from typing import Any + +from PySide6.QtCore import QAbstractTableModel, QModelIndex, QRect, QSortFilterProxyModel, Qt, Signal +from PySide6.QtGui import QColor, QFont, QMouseEvent, QPainter +from PySide6.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem + +from processdock.services import matches_process + + +PROCESS_ROLE = Qt.ItemDataRole.UserRole + 1 +SORT_ROLE = Qt.ItemDataRole.UserRole + 2 + + +class ProcessTableModel(QAbstractTableModel): + columns = ("PID", "进程名称", "监听端口", "CPU", "内存", "用户", "状态", "操作") + + def __init__(self, parent=None) -> None: + super().__init__(parent) + self._processes: list[dict[str, Any]] = [] + + def set_processes(self, processes: list[dict[str, Any]]) -> None: + self.beginResetModel() + self._processes = list(processes) + self.endResetModel() + + @property + def processes(self) -> list[dict[str, Any]]: + return self._processes + + def rowCount(self, parent=QModelIndex()) -> int: # noqa: N802 + return 0 if parent.isValid() else len(self._processes) + + def columnCount(self, parent=QModelIndex()) -> int: # noqa: N802 + return 0 if parent.isValid() else len(self.columns) + + def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole): # noqa: N802 + if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal: + return self.columns[section] + return None + + def data(self, index: QModelIndex, role=Qt.ItemDataRole.DisplayRole): + if not index.isValid() or not 0 <= index.row() < len(self._processes): + return None + process = self._processes[index.row()] + column = index.column() + + if role == PROCESS_ROLE: + return process + if role == SORT_ROLE: + values = ( + process["pid"], + process["name"].casefold(), + process["ports"][0] if process["ports"] else -1, + process["cpu_percent"], + process["memory_bytes"], + process["username"].casefold(), + process["status_label"], + process["pid"], + ) + return values[column] + if role == Qt.ItemDataRole.DisplayRole: + ports = ", ".join(str(port) for port in process["ports"]) or "—" + values = ( + str(process["pid"]), + process["name"], + ports, + f'{process["cpu_percent"]:.1f}%', + process["memory_text"], + process["username"], + process["status_label"], + "当前应用" if process["is_current"] else "结束", + ) + return values[column] + if role == Qt.ItemDataRole.TextAlignmentRole: + if column in (0, 2, 3, 4, 6, 7): + return Qt.AlignmentFlag.AlignCenter + return Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft + if role == Qt.ItemDataRole.ForegroundRole: + if column == 6: + if process["status"] == "running": + return QColor("#129B72") + if process["status"] in {"stopped", "suspended"}: + return QColor("#D88918") + if column == 2 and process["ports"]: + return QColor("#5B5BD6") + if column == 7: + return QColor("#A73A48" if process["can_terminate"] else "#9AA3B2") + if role == Qt.ItemDataRole.FontRole: + font = QFont() + if column in (0, 2, 3, 4): + font.setFamily("Cascadia Mono") + font.setPointSize(9) + if column == 1: + font.setWeight(QFont.Weight.DemiBold) + return font + if role == Qt.ItemDataRole.ToolTipRole: + if column == 2 and process["port_details"]: + return "\n".join( + f'{item["protocol"]} {item["address"]}:{item["port"]}' + for item in process["port_details"] + ) + if column == 1: + return process["exe"] or process["name"] + if column == 7 and process["is_current"]: + return "ProcessDock 不允许结束自身" + return None + + +class ProcessFilterProxyModel(QSortFilterProxyModel): + def __init__(self, parent=None) -> None: + super().__init__(parent) + self._query = "" + self.setDynamicSortFilter(True) + self.setSortRole(SORT_ROLE) + + def set_query(self, query: str) -> None: + self.beginFilterChange() + self._query = query + self.endFilterChange(QSortFilterProxyModel.Direction.Rows) + + def filterAcceptsRow(self, source_row: int, source_parent: QModelIndex) -> bool: # noqa: N802 + model = self.sourceModel() + index = model.index(source_row, 0, source_parent) + process = model.data(index, PROCESS_ROLE) + return bool(process and matches_process(process, self._query)) + + def lessThan(self, left: QModelIndex, right: QModelIndex) -> bool: # noqa: N802 + left_value = self.sourceModel().data(left, SORT_ROLE) + right_value = self.sourceModel().data(right, SORT_ROLE) + return left_value < right_value + + +class ActionButtonDelegate(QStyledItemDelegate): + terminate_requested = Signal(object) + + def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex) -> None: + process = index.data(PROCESS_ROLE) + if not process: + return super().paint(painter, option, index) + + painter.save() + selected = bool(option.state & option.state.State_Selected) + if selected: + painter.fillRect(option.rect, QColor("#EEF0FF")) + + rect = self._button_rect(option.rect) + enabled = bool(process["can_terminate"]) + fill = QColor("#FFF0F1") if enabled else QColor("#F2F4F7") + text_color = QColor("#B53C4A") if enabled else QColor("#9AA3B2") + painter.setRenderHint(QPainter.RenderHint.Antialiasing) + painter.setPen(Qt.PenStyle.NoPen) + painter.setBrush(fill) + painter.drawRoundedRect(rect, 7, 7) + painter.setPen(text_color) + font = painter.font() + font.setPointSize(9) + font.setWeight(QFont.Weight.DemiBold) + painter.setFont(font) + text = "结束" if enabled else "当前应用" + painter.drawText(rect, Qt.AlignmentFlag.AlignCenter, text) + painter.restore() + + def editorEvent(self, event, model, option, index) -> bool: # noqa: N802 + process = index.data(PROCESS_ROLE) + if ( + process + and process["can_terminate"] + and isinstance(event, QMouseEvent) + and event.type() == QMouseEvent.Type.MouseButtonRelease + and event.button() == Qt.MouseButton.LeftButton + and self._button_rect(option.rect).contains(event.position().toPoint()) + ): + self.terminate_requested.emit(process) + return True + return super().editorEvent(event, model, option, index) + + @staticmethod + def _button_rect(cell: QRect) -> QRect: + width, height = 58, 30 + return QRect( + cell.center().x() - width // 2, + cell.center().y() - height // 2, + width, + height, + ) diff --git a/processdock/services.py b/processdock/services.py new file mode 100644 index 0000000..6025853 --- /dev/null +++ b/processdock/services.py @@ -0,0 +1,499 @@ +from __future__ import annotations + +import os +import json +import socket +import subprocess +import sys +import threading +import time +from collections import defaultdict +from dataclasses import dataclass +from datetime import datetime +from pathlib import Path +from typing import Any + +import psutil + + +STATUS_LABELS = { + # psutil exposes different status constants on each operating system, while + # the returned values are stable strings. Literal keys keep imports portable. + "running": "运行中", + "sleeping": "休眠", + "disk-sleep": "等待磁盘", + "stopped": "已停止", + "tracing-stop": "调试暂停", + "zombie": "僵尸进程", + "dead": "已结束", + "wake-kill": "唤醒终止", + "waking": "唤醒中", + "parked": "已驻留", + "idle": "空闲", + "locked": "已锁定", + "waiting": "等待中", + "suspended": "已挂起", +} + + +class ProcessDockError(RuntimeError): + """Base error with a user-facing message.""" + + +class ProcessGoneError(ProcessDockError): + pass + + +class ProcessAccessError(ProcessDockError): + pass + + +class ProtectedProcessError(ProcessDockError): + pass + + +class ProcessChangedError(ProcessDockError): + pass + + +@dataclass(frozen=True) +class ActionResult: + success: bool + message: str + still_running: bool = False + + +def format_command(arguments: list[str] | None) -> str: + if not arguments: + return "" + if os.name == "nt": + return subprocess.list2cmdline(arguments) + return " ".join(_shell_quote(argument) for argument in arguments) + + +def _shell_quote(value: str) -> str: + if not value: + return "''" + if all(character.isalnum() or character in "@%_-+=:,./" for character in value): + return value + return "'" + value.replace("'", "'\"'\"'") + "'" + + +def humanize_bytes(size: int | float) -> str: + value = float(max(size, 0)) + for unit in ("B", "KB", "MB", "GB", "TB"): + if value < 1024 or unit == "TB": + if unit == "B": + return f"{value:.0f} {unit}" + return f"{value:.1f} {unit}" + value /= 1024 + return f"{value:.1f} TB" + + +def matches_process(process: dict[str, Any], query: str) -> bool: + normalized = query.strip().casefold() + if not normalized: + return True + values = [ + str(process.get("pid", "")), + str(process.get("name", "")), + str(process.get("username", "")), + str(process.get("exe", "")), + str(process.get("command", "")), + ",".join(str(port) for port in process.get("ports", [])), + ] + return any(normalized in value.casefold() for value in values) + + +class ProcessService: + """Reads process/port data and performs guarded local process actions.""" + + def __init__(self) -> None: + self.current_pid = os.getpid() + self._cpu_count = max(psutil.cpu_count(logical=True) or 1, 1) + self._cpu_samples: dict[int, tuple[float, float, float]] = {} + self._last_cpu: dict[int, float] = {} + self._lock = threading.RLock() + + def snapshot(self) -> dict[str, Any]: + port_map, port_warning = self._collect_ports() + warnings = [port_warning] if port_warning else [] + if os.name == "nt": + try: + processes = self._collect_windows_processes(port_map) + except (OSError, subprocess.SubprocessError, json.JSONDecodeError) as error: + warnings.append(f"快速采集不可用,已切换兼容模式:{error}") + processes = self._collect_psutil_processes(port_map) + else: + processes = self._collect_psutil_processes(port_map) + + processes.sort(key=lambda item: (item["name"].casefold(), item["pid"])) + unique_ports = { + (detail["protocol"], detail["address"], detail["port"]) + for process in processes + for detail in process["port_details"] + } + memory = psutil.virtual_memory() + summary = { + "process_count": len(processes), + "port_count": len(unique_ports), + "cpu_percent": round(float(psutil.cpu_percent(interval=None)), 1), + "memory_percent": round(float(memory.percent), 1), + "memory_used": humanize_bytes(memory.used), + "memory_total": humanize_bytes(memory.total), + } + return { + "processes": processes, + "summary": summary, + "warnings": warnings, + "refreshed_at": datetime.now().strftime("%H:%M:%S"), + } + + def _collect_psutil_processes( + self, port_map: dict[int, list[dict[str, Any]]] + ) -> list[dict[str, Any]]: + now = time.monotonic() + processes: list[dict[str, Any]] = [] + live_pids: set[int] = set() + for process in psutil.process_iter(): + try: + row = self._read_process(process, port_map.get(process.pid, []), now) + except (psutil.NoSuchProcess, psutil.ZombieProcess): + continue + except Exception: + # A single unusual system process should never break the full refresh. + continue + processes.append(row) + live_pids.add(row["pid"]) + + with self._lock: + self._cpu_samples = { + pid: sample for pid, sample in self._cpu_samples.items() if pid in live_pids + } + self._last_cpu = { + pid: value for pid, value in self._last_cpu.items() if pid in live_pids + } + return processes + + def _collect_windows_processes( + self, port_map: dict[int, list[dict[str, Any]]] + ) -> list[dict[str, Any]]: + """Use Windows CIM's bulk providers to avoid hundreds of slow per-PID calls.""" + script = r""" +[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 +$processes = Get-CimInstance Win32_Process -ErrorAction Stop | ForEach-Object { + $created = 0 + if ($_.CreationDate) { + $created = [DateTimeOffset]$_.CreationDate + $created = $created.ToUnixTimeMilliseconds() / 1000 + } + [PSCustomObject]@{ + pid = [int]$_.ProcessId + ppid = [int]$_.ParentProcessId + name = [string]$_.Name + exe = [string]$_.ExecutablePath + command = [string]$_.CommandLine + created = [double]$created + } +} +$performance = Get-CimInstance Win32_PerfFormattedData_PerfProc_Process -ErrorAction Stop | + Where-Object { $_.Name -ne '_Total' } | + ForEach-Object { + [PSCustomObject]@{ + pid = [int]$_.IDProcess + cpu = [double]$_.PercentProcessorTime + memory = [int64]$_.WorkingSetPrivate + } + } +[PSCustomObject]@{ processes = @($processes); performance = @($performance) } | + ConvertTo-Json -Depth 4 -Compress +""" + completed = subprocess.run( + ["powershell.exe", "-NoProfile", "-NonInteractive", "-Command", script], + capture_output=True, + text=True, + encoding="utf-8", + errors="replace", + timeout=8, + creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0), + ) + if completed.returncode != 0: + detail = (completed.stderr or completed.stdout).strip() + raise OSError(detail or "PowerShell CIM 查询失败") + payload = json.loads(completed.stdout.lstrip("\ufeff")) + static_by_pid = { + int(item["pid"]): item + for item in self._ensure_list(payload.get("processes")) + if item.get("pid") is not None + } + performance_by_pid = { + int(item["pid"]): item + for item in self._ensure_list(payload.get("performance")) + if item.get("pid") is not None + } + total_memory = max(int(psutil.virtual_memory().total), 1) + processes: list[dict[str, Any]] = [] + + for pid, values in static_by_pid.items(): + if pid == 0: + continue + performance = performance_by_pid.get(pid, {}) + memory_bytes = max(int(performance.get("memory") or 0), 0) + raw_cpu = max(float(performance.get("cpu") or 0.0), 0.0) + cpu_percent = round(min(raw_cpu / self._cpu_count, 100.0), 1) + try: + username = psutil.Process(pid).username() or "—" + except (psutil.Error, OSError): + username = "—" + port_details = port_map.get(pid, []) + ports = sorted({detail["port"] for detail in port_details}) + executable = values.get("exe") or "" + command = values.get("command") or "" + create_time = float(values.get("created") or 0.0) + processes.append( + { + "pid": pid, + "name": values.get("name") or f"PID {pid}", + "ports": ports, + "port_details": port_details, + "cpu_percent": cpu_percent, + "memory_bytes": memory_bytes, + "memory_text": humanize_bytes(memory_bytes), + "memory_percent": round(memory_bytes / total_memory * 100, 1), + "username": username, + "status": "running", + "status_label": "运行中", + "exe": executable, + "command": command, + "command_parts": [], + "create_time": create_time, + "create_time_text": self._format_timestamp(create_time), + "ppid": int(values.get("ppid") or 0), + "access_limited": not executable and not command and username == "—", + "is_current": pid == self.current_pid, + "can_terminate": pid != self.current_pid, + "can_open_location": bool(executable), + } + ) + return processes + + @staticmethod + def _ensure_list(value: Any) -> list[Any]: + if value is None: + return [] + return value if isinstance(value, list) else [value] + + def _collect_ports(self) -> tuple[dict[int, list[dict[str, Any]]], str | None]: + ports: dict[int, set[tuple[str, str, int]]] = defaultdict(set) + try: + connections = psutil.net_connections(kind="inet") + except psutil.AccessDenied: + return {}, "权限不足:无法读取完整端口列表,建议以管理员身份运行。" + except OSError as error: + return {}, f"端口信息暂时不可用:{error}" + + for connection in connections: + if connection.pid is None or not connection.laddr: + continue + protocol = "TCP" if connection.type == socket.SOCK_STREAM else "UDP" + if protocol == "TCP" and connection.status != psutil.CONN_LISTEN: + continue + try: + address = connection.laddr.ip + port = int(connection.laddr.port) + except AttributeError: + address, port = connection.laddr[:2] + port = int(port) + if port > 0: + ports[connection.pid].add((protocol, str(address), port)) + + result = { + pid: [ + {"protocol": protocol, "address": address, "port": port} + for protocol, address, port in sorted( + items, key=lambda item: (item[2], item[0], item[1]) + ) + ] + for pid, items in ports.items() + } + return result, None + + def _read_process( + self, + process: psutil.Process, + port_details: list[dict[str, Any]], + sample_time: float, + ) -> dict[str, Any]: + values = process.as_dict( + attrs=[ + "pid", + "name", + "username", + "status", + "exe", + "cmdline", + "create_time", + "ppid", + "memory_info", + "memory_percent", + "cpu_times", + ], + ad_value=None, + ) + pid = int(values["pid"]) + create_time = float(values.get("create_time") or 0.0) + cpu_percent = self._calculate_cpu( + pid, values.get("cpu_times"), create_time, sample_time + ) + memory_info = values.get("memory_info") + memory_bytes = int(getattr(memory_info, "rss", 0) or 0) + command_parts = values.get("cmdline") or [] + status = str(values.get("status") or "unknown") + ports = sorted({detail["port"] for detail in port_details}) + exe = values.get("exe") or "" + username = values.get("username") or "—" + limited = not exe and not command_parts and username == "—" + + return { + "pid": pid, + "name": values.get("name") or f"PID {pid}", + "ports": ports, + "port_details": port_details, + "cpu_percent": cpu_percent, + "memory_bytes": memory_bytes, + "memory_text": humanize_bytes(memory_bytes), + "memory_percent": round(float(values.get("memory_percent") or 0.0), 1), + "username": username, + "status": status, + "status_label": STATUS_LABELS.get(status, "未知"), + "exe": exe, + "command": format_command(command_parts), + "command_parts": command_parts, + "create_time": create_time, + "create_time_text": self._format_timestamp(create_time), + "ppid": int(values.get("ppid") or 0), + "access_limited": limited, + "is_current": pid == self.current_pid, + "can_terminate": pid != self.current_pid, + "can_open_location": bool(exe), + } + + def _calculate_cpu( + self, + pid: int, + cpu_times: Any, + create_time: float, + sample_time: float, + ) -> float: + if cpu_times is None: + return 0.0 + total = float(getattr(cpu_times, "user", 0.0)) + float( + getattr(cpu_times, "system", 0.0) + ) + with self._lock: + previous = self._cpu_samples.get(pid) + result = self._last_cpu.get(pid, 0.0) + if previous is not None: + previous_time, previous_total, previous_created = previous + elapsed = sample_time - previous_time + if elapsed >= 0.2 and abs(previous_created - create_time) < 0.01: + used = max(total - previous_total, 0.0) + result = min(max(used / elapsed / self._cpu_count * 100, 0.0), 100.0) + result = round(result, 1) + self._cpu_samples[pid] = (sample_time, total, create_time) + self._last_cpu[pid] = result + return result + + @staticmethod + def _format_timestamp(timestamp: float) -> str: + if timestamp <= 0: + return "—" + try: + return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S") + except (OSError, OverflowError, ValueError): + return "—" + + def terminate( + self, pid: int, *, force: bool, expected_create_time: float | None = None + ) -> ActionResult: + if pid == self.current_pid: + raise ProtectedProcessError("ProcessDock 正在使用该进程,不能结束自身。") + try: + process = psutil.Process(pid) + actual_create_time = process.create_time() + if ( + expected_create_time is not None + and expected_create_time > 0 + and abs(actual_create_time - expected_create_time) >= 0.01 + ): + raise ProcessChangedError("PID 已被新的进程复用,请刷新后重试。") + name = process.name() + + if force: + process.kill() + elif os.name == "nt": + completed = subprocess.run( + ["taskkill", "/PID", str(pid)], + capture_output=True, + text=True, + timeout=5, + creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0), + ) + # Console/background processes commonly reject taskkill without /F. + # Treat that as "still running" below so the GUI can offer force, + # rather than presenting a misleading hard failure. + else: + process.terminate() + + try: + process.wait(timeout=3) + except psutil.TimeoutExpired: + return ActionResult( + False, + f"{name} 尚未退出,可以尝试强制结束。", + still_running=True, + ) + action = "强制结束" if force else "正常结束" + return ActionResult(True, f"已{action} {name}(PID {pid})。") + except ProtectedProcessError: + raise + except ProcessChangedError: + raise + except psutil.NoSuchProcess as error: + raise ProcessGoneError("进程已经结束。") from error + except psutil.AccessDenied as error: + raise ProcessAccessError("权限不足,请尝试以管理员身份运行 ProcessDock。") from error + except subprocess.TimeoutExpired as error: + raise ProcessDockError("系统结束命令超时,请稍后重试。") from error + + def open_file_location( + self, pid: int, *, expected_create_time: float | None = None + ) -> ActionResult: + try: + process = psutil.Process(pid) + actual_create_time = process.create_time() + if ( + expected_create_time is not None + and expected_create_time > 0 + and abs(actual_create_time - expected_create_time) >= 0.01 + ): + raise ProcessChangedError("PID 已被新的进程复用,请刷新后重试。") + executable = process.exe() + if not executable: + raise ProcessDockError("该进程没有可访问的程序路径。") + path = Path(executable) + if sys.platform == "win32": + subprocess.Popen(["explorer.exe", f"/select,{path}"]) + elif sys.platform == "darwin": + subprocess.Popen(["open", "-R", str(path)]) + else: + subprocess.Popen(["xdg-open", str(path.parent)]) + return ActionResult(True, "已打开程序所在位置。") + except ProcessChangedError: + raise + except psutil.NoSuchProcess as error: + raise ProcessGoneError("进程已经结束。") from error + except psutil.AccessDenied as error: + raise ProcessAccessError("权限不足,无法读取程序路径。") from error + except OSError as error: + raise ProcessDockError(f"无法打开文件位置:{error}") from error diff --git a/processdock/styles.py b/processdock/styles.py new file mode 100644 index 0000000..2ee8dff --- /dev/null +++ b/processdock/styles.py @@ -0,0 +1,198 @@ +APP_STYLE = r""" +* { + font-family: "Microsoft YaHei UI"; + color: #202534; +} +QMainWindow, QWidget#AppRoot { + background: #F4F6FA; +} +QFrame#HeaderCard, QFrame#TableCard, QFrame#DetailCard, QFrame#SummaryCard { + background: #FFFFFF; + border: 1px solid #E6E9F0; + border-radius: 14px; +} +QLabel#BrandMark { + color: white; + background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #6868E8, stop:1 #4C4CC1); + border-radius: 11px; + font-size: 20px; + font-weight: 700; +} +QLabel#BrandTitle { + color: #171B2A; + font-size: 19px; + font-weight: 700; +} +QLabel#BrandSubtitle, QLabel#MutedLabel, QLabel#CardSubtitle, QLabel#DetailKey { + color: #80899A; +} +QLabel#BrandSubtitle { font-size: 10px; } +QLineEdit#SearchBox { + min-height: 38px; + min-width: 260px; + padding: 0 14px; + background: #F7F8FB; + border: 1px solid #DFE3EB; + border-radius: 9px; + selection-background-color: #6464D9; +} +QLineEdit#SearchBox:focus { + background: #FFFFFF; + border: 1px solid #6262D6; +} +QPushButton { + min-height: 36px; + padding: 0 16px; + border-radius: 9px; + font-weight: 600; +} +QPushButton#PrimaryButton { + color: white; + background: #5B5BD6; + border: 1px solid #5B5BD6; +} +QPushButton#PrimaryButton:hover { background: #4F4FC5; } +QPushButton#SecondaryButton { + background: #FFFFFF; + border: 1px solid #DDE1EA; +} +QPushButton#SecondaryButton:hover { background: #F6F7FB; border-color: #C9CEDA; } +QPushButton#DangerButton { + color: white; + background: #C64B59; + border: 1px solid #C64B59; +} +QPushButton#DangerButton:hover { background: #B33D4B; } +QPushButton#SoftDangerButton { + color: #B53C4A; + background: #FFF1F2; + border: 1px solid #F3CDD2; +} +QPushButton#SoftDangerButton:hover { background: #FDE5E8; } +QPushButton:disabled { + color: #A6ADBA; + background: #F2F4F7; + border-color: #E4E7EC; +} +QCheckBox { spacing: 8px; color: #596273; } +QLabel#CardIcon { + min-width: 38px; max-width: 38px; + min-height: 38px; max-height: 38px; + color: #5858CD; + background: #EEEEFF; + border-radius: 10px; + font-size: 15px; + font-weight: 700; +} +QLabel#CardValue { + color: #1C2130; + font-size: 22px; + font-weight: 700; +} +QLabel#CardTitle { color: #687183; font-size: 11px; } +QLabel#WarningBanner { + color: #8B5A10; + background: #FFF7E5; + border: 1px solid #F2D79A; + border-radius: 9px; + padding: 9px 12px; +} +QLabel#SectionTitle { + color: #202534; + font-size: 15px; + font-weight: 700; +} +QTableView { + background: #FFFFFF; + alternate-background-color: #FBFCFE; + border: none; + gridline-color: transparent; + selection-background-color: #EEF0FF; + selection-color: #202534; + outline: none; +} +QTableView::item { + border-bottom: 1px solid #EEF0F4; + padding: 0 10px; +} +QTableView::item:hover { background: #F7F8FF; } +QHeaderView::section { + color: #70798A; + background: #F7F8FB; + border: none; + border-bottom: 1px solid #E8EAF0; + padding: 9px 8px; + font-size: 10px; + font-weight: 700; +} +QScrollBar:vertical { width: 9px; background: transparent; margin: 3px; } +QScrollBar::handle:vertical { min-height: 30px; background: #CFD4DE; border-radius: 4px; } +QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { height: 0; } +QScrollBar:horizontal { height: 9px; background: transparent; margin: 3px; } +QScrollBar::handle:horizontal { min-width: 30px; background: #CFD4DE; border-radius: 4px; } +QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { width: 0; } +QSplitter::handle { background: transparent; width: 12px; } +QLabel#ProcessAvatar { + color: #FFFFFF; + background: #5B5BD6; + border-radius: 12px; + font-size: 20px; + font-weight: 700; +} +QLabel#ProcessName { font-size: 17px; font-weight: 700; color: #1D2230; } +QLabel#PidBadge { + color: #626B7A; + background: #F0F2F6; + border-radius: 7px; + padding: 3px 7px; + font-family: "Cascadia Mono"; + font-size: 9px; +} +QLabel#DetailValue { + color: #242A38; + font-size: 11px; +} +QLabel#PortValue { + color: #4E4EC4; + background: #F0F0FF; + border-radius: 7px; + padding: 7px 9px; + font-family: "Cascadia Mono"; +} +QTextEdit#CommandBox { + color: #3D4656; + background: #F7F8FB; + border: 1px solid #E4E7ED; + border-radius: 8px; + padding: 7px; + font-family: "Cascadia Mono"; + font-size: 9px; +} +QLabel#LimitedBanner { + color: #805C1B; + background: #FFF7E7; + border-radius: 7px; + padding: 7px; +} +QLabel#EmptyIcon { + color: #6868D7; + background: #EEEEFF; + border-radius: 22px; + font-size: 23px; + font-weight: 700; +} +QLabel#EmptyTitle { color: #343A49; font-size: 14px; font-weight: 700; } +QProgressBar#LoadingBar { + min-height: 3px; max-height: 3px; + border: none; background: #EEEFF4; +} +QProgressBar#LoadingBar::chunk { background: #5B5BD6; } +QLabel#FooterStatus { color: #778092; font-size: 10px; } +QToolTip { + color: #FFFFFF; + background: #252A38; + border: none; + padding: 6px; +} +QMessageBox { background: #FFFFFF; } +""" diff --git a/processdock/ui.py b/processdock/ui.py new file mode 100644 index 0000000..209564d --- /dev/null +++ b/processdock/ui.py @@ -0,0 +1,764 @@ +from __future__ import annotations + +from collections.abc import Callable +from typing import Any + +from PySide6.QtCore import QModelIndex, QObject, QRunnable, QSize, Qt, QThreadPool, QTimer, Signal, Slot +from PySide6.QtGui import QCloseEvent, QColor, QFont, QGuiApplication, QIcon, QPainter, QPixmap +from PySide6.QtWidgets import ( + QAbstractItemView, + QApplication, + QCheckBox, + QFrame, + QHBoxLayout, + QHeaderView, + QLabel, + QLineEdit, + QMainWindow, + QMessageBox, + QProgressBar, + QPushButton, + QScrollArea, + QSizePolicy, + QSplitter, + QStackedWidget, + QStyle, + QTableView, + QTextEdit, + QVBoxLayout, + QWidget, +) + +from processdock.models import ( + PROCESS_ROLE, + ActionButtonDelegate, + ProcessFilterProxyModel, + ProcessTableModel, +) +from processdock.services import ActionResult, ProcessDockError, ProcessService +from processdock.styles import APP_STYLE + + +class WorkerSignals(QObject): + result = Signal(object) + error = Signal(str) + finished = Signal() + + +class FunctionWorker(QRunnable): + def __init__(self, function: Callable[[], Any]) -> None: + super().__init__() + self.function = function + self.signals = WorkerSignals() + + @Slot() + def run(self) -> None: + try: + result = self.function() + except Exception as error: # delivered to the GUI thread + self.signals.error.emit(str(error) or error.__class__.__name__) + else: + self.signals.result.emit(result) + finally: + self.signals.finished.emit() + + +class SummaryCard(QFrame): + def __init__(self, icon: str, title: str, value: str, subtitle: str, parent=None) -> None: + super().__init__(parent) + self.setObjectName("SummaryCard") + self.setMinimumHeight(92) + layout = QHBoxLayout(self) + layout.setContentsMargins(16, 13, 16, 13) + layout.setSpacing(12) + + icon_label = QLabel(icon) + icon_label.setObjectName("CardIcon") + icon_label.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.addWidget(icon_label) + + text_layout = QVBoxLayout() + text_layout.setSpacing(1) + title_label = QLabel(title) + title_label.setObjectName("CardTitle") + self.value_label = QLabel(value) + self.value_label.setObjectName("CardValue") + self.subtitle_label = QLabel(subtitle) + self.subtitle_label.setObjectName("CardSubtitle") + text_layout.addWidget(title_label) + text_layout.addWidget(self.value_label) + text_layout.addWidget(self.subtitle_label) + layout.addLayout(text_layout, 1) + + def update_value(self, value: str, subtitle: str | None = None) -> None: + self.value_label.setText(value) + if subtitle is not None: + self.subtitle_label.setText(subtitle) + + +class DetailRow(QWidget): + def __init__(self, key: str, parent=None) -> None: + super().__init__(parent) + layout = QHBoxLayout(self) + layout.setContentsMargins(0, 0, 0, 0) + layout.setSpacing(12) + key_label = QLabel(key) + key_label.setObjectName("DetailKey") + key_label.setFixedWidth(76) + key_label.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft) + self.value_label = QLabel("—") + self.value_label.setObjectName("DetailValue") + self.value_label.setTextFormat(Qt.TextFormat.PlainText) + self.value_label.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse) + self.value_label.setWordWrap(True) + layout.addWidget(key_label) + layout.addWidget(self.value_label, 1) + + def set_value(self, value: str) -> None: + self.value_label.setText(value or "—") + + +class DetailPanel(QFrame): + open_requested = Signal(object) + copy_requested = Signal(str) + terminate_requested = Signal(object, bool) + + def __init__(self, parent=None) -> None: + super().__init__(parent) + self.setObjectName("DetailCard") + self.setMinimumWidth(350) + self.setMaximumWidth(430) + self._process: dict[str, Any] | None = None + + outer = QVBoxLayout(self) + outer.setContentsMargins(0, 0, 0, 0) + outer.setSpacing(0) + + heading = QWidget() + heading_layout = QHBoxLayout(heading) + heading_layout.setContentsMargins(18, 16, 18, 12) + title = QLabel("进程详情") + title.setObjectName("SectionTitle") + hint = QLabel("实时信息") + hint.setObjectName("MutedLabel") + heading_layout.addWidget(title) + heading_layout.addStretch() + heading_layout.addWidget(hint) + outer.addWidget(heading) + + self.stack = QStackedWidget() + outer.addWidget(self.stack, 1) + self._build_empty_page() + self._build_detail_page() + self.stack.setCurrentWidget(self.empty_page) + + def _build_empty_page(self) -> None: + self.empty_page = QWidget() + layout = QVBoxLayout(self.empty_page) + layout.setContentsMargins(34, 34, 34, 70) + layout.addStretch() + icon = QLabel("⌁") + icon.setObjectName("EmptyIcon") + icon.setFixedSize(54, 54) + icon.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.empty_title = QLabel("选择一个进程") + self.empty_title.setObjectName("EmptyTitle") + self.empty_title.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.empty_hint = QLabel("点击左侧任意一行,查看路径、命令行和资源占用。") + self.empty_hint.setObjectName("MutedLabel") + self.empty_hint.setWordWrap(True) + self.empty_hint.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.addWidget(icon, alignment=Qt.AlignmentFlag.AlignCenter) + layout.addSpacing(12) + layout.addWidget(self.empty_title) + layout.addSpacing(4) + layout.addWidget(self.empty_hint) + layout.addStretch() + self.stack.addWidget(self.empty_page) + + def _build_detail_page(self) -> None: + self.detail_page = QWidget() + page_layout = QVBoxLayout(self.detail_page) + page_layout.setContentsMargins(0, 0, 0, 0) + page_layout.setSpacing(0) + scroll = QScrollArea() + scroll.setWidgetResizable(True) + scroll.setFrameShape(QFrame.Shape.NoFrame) + detail_content = QWidget() + layout = QVBoxLayout(detail_content) + layout.setContentsMargins(18, 6, 18, 18) + layout.setSpacing(12) + + identity = QWidget() + identity_layout = QHBoxLayout(identity) + identity_layout.setContentsMargins(0, 0, 0, 6) + identity_layout.setSpacing(12) + self.avatar = QLabel("P") + self.avatar.setObjectName("ProcessAvatar") + self.avatar.setFixedSize(50, 50) + self.avatar.setAlignment(Qt.AlignmentFlag.AlignCenter) + name_layout = QVBoxLayout() + name_layout.setSpacing(4) + self.process_name = QLabel("—") + self.process_name.setObjectName("ProcessName") + self.process_name.setTextFormat(Qt.TextFormat.PlainText) + self.pid_badge = QLabel("PID —") + self.pid_badge.setObjectName("PidBadge") + self.pid_badge.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) + name_layout.addWidget(self.process_name) + name_layout.addWidget(self.pid_badge) + identity_layout.addWidget(self.avatar) + identity_layout.addLayout(name_layout, 1) + layout.addWidget(identity) + + self.limited_banner = QLabel("部分信息受系统权限限制") + self.limited_banner.setObjectName("LimitedBanner") + self.limited_banner.setWordWrap(True) + self.limited_banner.hide() + layout.addWidget(self.limited_banner) + + self.rows: dict[str, DetailRow] = {} + for key, label in ( + ("ports", "监听端口"), + ("exe", "程序路径"), + ("create_time", "启动时间"), + ("cpu", "CPU 使用率"), + ("memory", "内存占用"), + ("username", "运行用户"), + ("status", "进程状态"), + ("ppid", "父进程 PID"), + ): + row = DetailRow(label) + if key == "ports": + row.value_label.setObjectName("PortValue") + self.rows[key] = row + layout.addWidget(row) + + command_title = QLabel("启动命令") + command_title.setObjectName("DetailKey") + layout.addWidget(command_title) + self.command_box = QTextEdit() + self.command_box.setObjectName("CommandBox") + self.command_box.setReadOnly(True) + self.command_box.setMinimumHeight(76) + self.command_box.setMaximumHeight(108) + layout.addWidget(self.command_box) + layout.addStretch() + + actions = QWidget() + actions_layout = QVBoxLayout(actions) + actions_layout.setContentsMargins(18, 10, 18, 18) + actions_layout.setSpacing(8) + utility_layout = QHBoxLayout() + utility_layout.setSpacing(8) + self.open_button = QPushButton("打开文件位置") + self.open_button.setObjectName("SecondaryButton") + self.copy_button = QPushButton("复制启动命令") + self.copy_button.setObjectName("SecondaryButton") + utility_layout.addWidget(self.open_button) + utility_layout.addWidget(self.copy_button) + actions_layout.addLayout(utility_layout) + + danger_layout = QHBoxLayout() + danger_layout.setSpacing(8) + self.normal_button = QPushButton("正常结束") + self.normal_button.setObjectName("SoftDangerButton") + self.force_button = QPushButton("强制结束") + self.force_button.setObjectName("DangerButton") + danger_layout.addWidget(self.normal_button) + danger_layout.addWidget(self.force_button) + actions_layout.addLayout(danger_layout) + + self.open_button.clicked.connect(self._request_open) + self.copy_button.clicked.connect(self._request_copy) + self.normal_button.clicked.connect(lambda: self._request_terminate(False)) + self.force_button.clicked.connect(lambda: self._request_terminate(True)) + + scroll.setWidget(detail_content) + page_layout.addWidget(scroll, 1) + page_layout.addWidget(actions) + self.stack.addWidget(self.detail_page) + self.detail_scroll = scroll + + def set_process(self, process: dict[str, Any]) -> None: + self._process = process + name = process["name"] + self.avatar.setText((name[:1] or "P").upper()) + self.process_name.setText(name) + self.pid_badge.setText(f'PID {process["pid"]}') + self.limited_banner.setVisible(bool(process["access_limited"])) + + ports = "、".join(str(port) for port in process["ports"]) or "未监听端口" + port_tooltip = "\n".join( + f'{item["protocol"]} {item["address"]}:{item["port"]}' + for item in process["port_details"] + ) + self.rows["ports"].set_value(ports) + self.rows["ports"].value_label.setToolTip(port_tooltip) + self.rows["exe"].set_value(process["exe"]) + self.rows["create_time"].set_value(process["create_time_text"]) + self.rows["cpu"].set_value(f'{process["cpu_percent"]:.1f}%') + self.rows["memory"].set_value( + f'{process["memory_text"]} ({process["memory_percent"]:.1f}%)' + ) + self.rows["username"].set_value(process["username"]) + self.rows["status"].set_value(process["status_label"]) + self.rows["ppid"].set_value(str(process["ppid"]) if process["ppid"] else "—") + self.command_box.setPlainText(process["command"] or "—") + self.open_button.setEnabled(bool(process["can_open_location"])) + self.copy_button.setEnabled(bool(process["command"])) + self.normal_button.setEnabled(bool(process["can_terminate"])) + self.force_button.setEnabled(bool(process["can_terminate"])) + self.normal_button.setToolTip( + "向进程发送常规结束请求" if process["can_terminate"] else "不能结束 ProcessDock 自身" + ) + self.force_button.setToolTip("立即终止进程,未保存的数据可能丢失") + self.stack.setCurrentIndex(1) + + def clear(self, message: str = "点击左侧任意一行,查看路径、命令行和资源占用。") -> None: + self._process = None + self.empty_hint.setText(message) + self.stack.setCurrentWidget(self.empty_page) + + def set_action_busy(self, busy: bool) -> None: + if not self._process: + return + self.open_button.setEnabled(not busy and bool(self._process["can_open_location"])) + self.copy_button.setEnabled(not busy and bool(self._process["command"])) + self.normal_button.setEnabled(not busy and bool(self._process["can_terminate"])) + self.force_button.setEnabled(not busy and bool(self._process["can_terminate"])) + + def _request_open(self) -> None: + if self._process: + self.open_requested.emit(self._process) + + def _request_copy(self) -> None: + if self._process and self._process["command"]: + self.copy_requested.emit(self._process["command"]) + + def _request_terminate(self, force: bool) -> None: + if self._process: + self.terminate_requested.emit(self._process, force) + + +class MainWindow(QMainWindow): + def __init__( + self, service: ProcessService | None = None, auto_refresh: bool = True, parent=None + ) -> None: + super().__init__(parent) + self.service = service or ProcessService() + self.thread_pool = QThreadPool.globalInstance() + self._workers: set[FunctionWorker] = set() + self._refreshing = False + self._refresh_pending = False + self._closing = False + self._selected_pid: int | None = None + self._action_busy = False + + self.setWindowTitle("ProcessDock · 进程与端口管理器") + self.setWindowIcon(make_app_icon()) + self.setMinimumSize(1080, 700) + self.resize(1360, 820) + self.setStyleSheet(APP_STYLE) + self._build_ui(auto_refresh) + + self.auto_timer = QTimer(self) + self.auto_timer.setInterval(3000) + self.auto_timer.timeout.connect(self.refresh) + self.auto_checkbox.toggled.connect(self._toggle_auto_refresh) + if auto_refresh: + self.auto_timer.start() + QTimer.singleShot(0, self.refresh) + + def _build_ui(self, auto_refresh: bool) -> None: + root = QWidget() + root.setObjectName("AppRoot") + self.setCentralWidget(root) + outer = QVBoxLayout(root) + outer.setContentsMargins(20, 18, 20, 16) + outer.setSpacing(12) + + header = QFrame() + header.setObjectName("HeaderCard") + header_layout = QHBoxLayout(header) + header_layout.setContentsMargins(16, 11, 16, 11) + header_layout.setSpacing(12) + mark = QLabel("P") + mark.setObjectName("BrandMark") + mark.setFixedSize(42, 42) + mark.setAlignment(Qt.AlignmentFlag.AlignCenter) + header_layout.addWidget(mark) + brand = QVBoxLayout() + brand.setSpacing(0) + title = QLabel("ProcessDock") + title.setObjectName("BrandTitle") + subtitle = QLabel("进程与端口管理器") + subtitle.setObjectName("BrandSubtitle") + brand.addWidget(title) + brand.addWidget(subtitle) + header_layout.addLayout(brand) + header_layout.addStretch() + + self.search_box = QLineEdit() + self.search_box.setObjectName("SearchBox") + self.search_box.setPlaceholderText("搜索进程、PID、端口或路径") + self.search_box.setClearButtonEnabled(True) + self.search_box.textChanged.connect(self._filter_changed) + header_layout.addWidget(self.search_box) + + self.refresh_button = QPushButton("刷新") + self.refresh_button.setObjectName("PrimaryButton") + self.refresh_button.setIcon( + self.style().standardIcon(QStyle.StandardPixmap.SP_BrowserReload) + ) + self.refresh_button.clicked.connect(self.refresh) + header_layout.addWidget(self.refresh_button) + self.auto_checkbox = QCheckBox("自动刷新 3 秒") + self.auto_checkbox.setChecked(auto_refresh) + header_layout.addWidget(self.auto_checkbox) + outer.addWidget(header) + + cards_layout = QHBoxLayout() + cards_layout.setSpacing(10) + self.process_card = SummaryCard("进", "运行进程", "—", "正在读取") + self.port_card = SummaryCard("端", "监听端口", "—", "TCP 与 UDP") + self.cpu_card = SummaryCard("CPU", "系统 CPU", "—", "所有逻辑核心") + self.memory_card = SummaryCard("存", "系统内存", "—", "正在读取") + for card in (self.process_card, self.port_card, self.cpu_card, self.memory_card): + cards_layout.addWidget(card, 1) + outer.addLayout(cards_layout) + + self.warning_banner = QLabel() + self.warning_banner.setObjectName("WarningBanner") + self.warning_banner.setWordWrap(True) + self.warning_banner.hide() + outer.addWidget(self.warning_banner) + + splitter = QSplitter(Qt.Orientation.Horizontal) + splitter.setChildrenCollapsible(False) + outer.addWidget(splitter, 1) + + table_card = QFrame() + table_card.setObjectName("TableCard") + table_layout = QVBoxLayout(table_card) + table_layout.setContentsMargins(0, 0, 0, 0) + table_layout.setSpacing(0) + table_heading = QWidget() + table_heading_layout = QHBoxLayout(table_heading) + table_heading_layout.setContentsMargins(18, 14, 18, 11) + table_title = QLabel("正在运行的进程") + table_title.setObjectName("SectionTitle") + self.count_label = QLabel("准备读取…") + self.count_label.setObjectName("MutedLabel") + table_heading_layout.addWidget(table_title) + table_heading_layout.addStretch() + table_heading_layout.addWidget(self.count_label) + table_layout.addWidget(table_heading) + + self.loading_bar = QProgressBar() + self.loading_bar.setObjectName("LoadingBar") + self.loading_bar.setRange(0, 0) + self.loading_bar.setTextVisible(False) + self.loading_bar.hide() + table_layout.addWidget(self.loading_bar) + + self.model = ProcessTableModel(self) + self.proxy = ProcessFilterProxyModel(self) + self.proxy.setSourceModel(self.model) + self.table = QTableView() + self.table.setModel(self.proxy) + self.table.setAlternatingRowColors(True) + self.table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) + self.table.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) + self.table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) + self.table.setShowGrid(False) + self.table.setWordWrap(False) + self.table.setSortingEnabled(True) + self.table.sortByColumn(1, Qt.SortOrder.AscendingOrder) + self.table.verticalHeader().hide() + self.table.verticalHeader().setDefaultSectionSize(48) + header_view = self.table.horizontalHeader() + header_view.setDefaultAlignment(Qt.AlignmentFlag.AlignCenter) + header_view.setMinimumSectionSize(62) + header_view.setSectionResizeMode(QHeaderView.ResizeMode.Interactive) + header_view.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch) + widths = (78, 190, 135, 82, 105, 130, 88, 82) + for column, width in enumerate(widths): + self.table.setColumnWidth(column, width) + self.table.selectionModel().currentRowChanged.connect(self._selection_changed) + self.action_delegate = ActionButtonDelegate(self.table) + self.action_delegate.terminate_requested.connect( + lambda process: self._confirm_terminate(process, False) + ) + self.table.setItemDelegateForColumn(7, self.action_delegate) + + self.table_stack = QStackedWidget() + self.table_stack.addWidget(self.table) + self.no_results_page = self._build_no_results_page() + self.table_stack.addWidget(self.no_results_page) + table_layout.addWidget(self.table_stack, 1) + splitter.addWidget(table_card) + + self.detail_panel = DetailPanel() + self.detail_panel.open_requested.connect(self._open_location) + self.detail_panel.copy_requested.connect(self._copy_command) + self.detail_panel.terminate_requested.connect(self._confirm_terminate) + splitter.addWidget(self.detail_panel) + splitter.setStretchFactor(0, 1) + splitter.setStretchFactor(1, 0) + splitter.setSizes([910, 390]) + + footer = QHBoxLayout() + self.footer_status = QLabel("就绪") + self.footer_status.setObjectName("FooterStatus") + self.footer_time = QLabel("尚未刷新") + self.footer_time.setObjectName("FooterStatus") + footer.addWidget(self.footer_status) + footer.addStretch() + footer.addWidget(self.footer_time) + outer.addLayout(footer) + + @staticmethod + def _build_no_results_page() -> QWidget: + page = QWidget() + layout = QVBoxLayout(page) + layout.addStretch() + icon = QLabel("⌕") + icon.setObjectName("EmptyIcon") + icon.setFixedSize(54, 54) + icon.setAlignment(Qt.AlignmentFlag.AlignCenter) + title = QLabel("没有匹配的进程") + title.setObjectName("EmptyTitle") + title.setAlignment(Qt.AlignmentFlag.AlignCenter) + hint = QLabel("换一个进程名称、PID 或端口试试。") + hint.setObjectName("MutedLabel") + hint.setAlignment(Qt.AlignmentFlag.AlignCenter) + layout.addWidget(icon, alignment=Qt.AlignmentFlag.AlignCenter) + layout.addSpacing(10) + layout.addWidget(title) + layout.addWidget(hint) + layout.addStretch() + return page + + @Slot() + def refresh(self) -> None: + if self._refreshing: + self._refresh_pending = True + return + self._refreshing = True + self.refresh_button.setEnabled(False) + self.loading_bar.show() + self._set_status("正在读取进程和端口…") + + worker = FunctionWorker(self.service.snapshot) + worker.signals.result.connect(self._apply_snapshot) + worker.signals.error.connect(self._refresh_failed) + worker.signals.finished.connect(self._refresh_finished) + self._track_worker(worker) + self.thread_pool.start(worker) + + @Slot(object) + def _apply_snapshot(self, snapshot: dict[str, Any]) -> None: + if self._closing: + return + processes = snapshot["processes"] + self.model.set_processes(processes) + summary = snapshot["summary"] + self.process_card.update_value(str(summary["process_count"]), "本机可见进程") + self.port_card.update_value(str(summary["port_count"]), "TCP 监听 / UDP 绑定") + self.cpu_card.update_value(f'{summary["cpu_percent"]:.1f}%', "所有逻辑核心") + self.memory_card.update_value( + f'{summary["memory_percent"]:.1f}%', + f'{summary["memory_used"]} / {summary["memory_total"]}', + ) + warnings = snapshot.get("warnings") or [] + self.warning_banner.setText(" ".join(warnings)) + self.warning_banner.setVisible(bool(warnings)) + self.footer_time.setText(f'上次刷新 {snapshot["refreshed_at"]}') + self._set_status("数据已更新") + self._update_visible_count() + + if self._selected_pid is not None: + selected = next( + (process for process in processes if process["pid"] == self._selected_pid), + None, + ) + if selected is None: + self._selected_pid = None + self.detail_panel.clear("该进程已经结束,请重新选择。") + else: + self.detail_panel.set_process(selected) + self._reselect_process(self._selected_pid) + + @Slot(str) + def _refresh_failed(self, message: str) -> None: + self.warning_banner.setText(f"刷新失败:{message}") + self.warning_banner.show() + self._set_status("刷新失败") + + @Slot() + def _refresh_finished(self) -> None: + self._refreshing = False + self.refresh_button.setEnabled(True) + self.loading_bar.hide() + if self._refresh_pending and not self._closing: + self._refresh_pending = False + QTimer.singleShot(0, self.refresh) + + def _track_worker(self, worker: FunctionWorker) -> None: + self._workers.add(worker) + worker.signals.finished.connect(lambda current=worker: self._workers.discard(current)) + + @Slot(str) + def _filter_changed(self, query: str) -> None: + self.proxy.set_query(query) + self._update_visible_count() + + def _update_visible_count(self) -> None: + visible = self.proxy.rowCount() + total = self.model.rowCount() + self.count_label.setText( + f"{visible} / {total} 个进程" if self.search_box.text().strip() else f"{total} 个进程" + ) + self.table_stack.setCurrentWidget(self.table if visible else self.no_results_page) + + @Slot(QModelIndex, QModelIndex) + def _selection_changed(self, current: QModelIndex, previous: QModelIndex) -> None: + del previous + if not current.isValid(): + return + process = current.data(PROCESS_ROLE) + if process: + self._selected_pid = process["pid"] + self.detail_panel.set_process(process) + + def _reselect_process(self, pid: int) -> None: + for source_row, process in enumerate(self.model.processes): + if process["pid"] != pid: + continue + source_index = self.model.index(source_row, 0) + proxy_index = self.proxy.mapFromSource(source_index) + if proxy_index.isValid(): + self.table.selectRow(proxy_index.row()) + return + + @Slot(bool) + def _toggle_auto_refresh(self, enabled: bool) -> None: + if enabled: + self.auto_timer.start() + self._set_status("已开启自动刷新") + else: + self.auto_timer.stop() + self._set_status("已暂停自动刷新") + + @Slot(object, bool) + def _confirm_terminate(self, process: dict[str, Any], force: bool) -> None: + if self._action_busy or not process.get("can_terminate"): + return + name = process["name"] + pid = process["pid"] + box = QMessageBox(self) + box.setIcon(QMessageBox.Icon.Warning) + box.setWindowTitle("确认强制结束" if force else "确认结束进程") + box.setText(f"确定要结束 {name}(PID {pid})吗?") + box.setInformativeText( + "强制结束可能导致未保存的数据丢失。" + if force + else "将先发送常规结束请求;如果进程没有响应,可再强制结束。" + ) + confirm = box.addButton( + "强制结束" if force else "正常结束", QMessageBox.ButtonRole.AcceptRole + ) + box.addButton("取消", QMessageBox.ButtonRole.RejectRole) + box.setDefaultButton(confirm) + box.exec() + if box.clickedButton() is not confirm: + return + + self._action_busy = True + if self._selected_pid == pid: + self.detail_panel.set_action_busy(True) + self._set_status(f"正在结束 {name}…") + worker = FunctionWorker( + lambda: self.service.terminate( + pid, + force=force, + expected_create_time=process.get("create_time"), + ) + ) + worker.signals.result.connect(self._termination_finished) + worker.signals.error.connect(self._action_failed) + worker.signals.finished.connect(self._action_worker_finished) + self._track_worker(worker) + self.thread_pool.start(worker) + + @Slot(object) + def _termination_finished(self, result: ActionResult) -> None: + self._set_status(result.message) + if result.still_running: + QMessageBox.warning(self, "进程仍在运行", result.message) + self.refresh() + + @Slot(str) + def _action_failed(self, message: str) -> None: + self._set_status("操作失败") + QMessageBox.critical(self, "操作失败", message) + + @Slot() + def _action_worker_finished(self) -> None: + self._action_busy = False + self.detail_panel.set_action_busy(False) + + @Slot(object) + def _open_location(self, process: dict[str, Any]) -> None: + if self._action_busy: + return + self._action_busy = True + self.detail_panel.set_action_busy(True) + worker = FunctionWorker( + lambda: self.service.open_file_location( + process["pid"], expected_create_time=process.get("create_time") + ) + ) + worker.signals.result.connect(lambda result: self._set_status(result.message)) + worker.signals.error.connect(self._action_failed) + worker.signals.finished.connect(self._action_worker_finished) + self._track_worker(worker) + self.thread_pool.start(worker) + + @Slot(str) + def _copy_command(self, command: str) -> None: + QGuiApplication.clipboard().setText(command) + self._set_status("启动命令已复制到剪贴板") + + def _set_status(self, text: str) -> None: + self.footer_status.setText(text) + + def closeEvent(self, event: QCloseEvent) -> None: # noqa: N802 + self._closing = True + self.auto_timer.stop() + self.thread_pool.clear() + super().closeEvent(event) + + +def make_app_icon() -> QIcon: + pixmap = QPixmap(64, 64) + pixmap.fill(Qt.GlobalColor.transparent) + painter = QPainter(pixmap) + painter.setRenderHint(QPainter.RenderHint.Antialiasing) + painter.setPen(Qt.PenStyle.NoPen) + painter.setBrush(QColor("#5B5BD6")) + painter.drawRoundedRect(4, 4, 56, 56, 15, 15) + painter.setPen(QColor("#FFFFFF")) + font = QFont("Arial", 29, QFont.Weight.Bold) + painter.setFont(font) + painter.drawText(pixmap.rect(), Qt.AlignmentFlag.AlignCenter, "P") + painter.end() + return QIcon(pixmap) + + +def create_window_for_testing(service: ProcessService | None = None) -> MainWindow: + """Small test hook used by the off-screen smoke check.""" + if QApplication.instance() is None: + raise RuntimeError("A QApplication must exist before creating the window.") + return MainWindow(service=service, auto_refresh=False) diff --git a/requirements-build.txt b/requirements-build.txt new file mode 100644 index 0000000..c2985bd --- /dev/null +++ b/requirements-build.txt @@ -0,0 +1,3 @@ +-r requirements.txt +pyinstaller>=6.10,<7 +Pillow>=10,<13 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6a25756 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +psutil>=5.9,<8 +PySide6>=6.7,<7 diff --git a/tests/test_gui.py b/tests/test_gui.py new file mode 100644 index 0000000..0bb6681 --- /dev/null +++ b/tests/test_gui.py @@ -0,0 +1,66 @@ +from __future__ import annotations + +import os +import unittest + +os.environ.setdefault("QT_QPA_PLATFORM", "offscreen") + +from PySide6.QtWidgets import QApplication # noqa: E402 + +from processdock.ui import MainWindow # noqa: E402 + + +class StubService: + def snapshot(self): + return {"processes": [], "summary": {}, "warnings": [], "refreshed_at": "00:00:00"} + + +class GuiSmokeTests(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.application = QApplication.instance() or QApplication([]) + + def setUp(self) -> None: + self.window = MainWindow(service=StubService(), auto_refresh=False) + + def tearDown(self) -> None: + self.window.close() + self.application.processEvents() + + def test_window_contains_table_search_and_detail_panel(self) -> None: + self.assertEqual(self.window.model.columnCount(), 8) + self.assertIn("端口", self.window.search_box.placeholderText()) + self.assertEqual(self.window.detail_panel.stack.currentIndex(), 0) + + def test_filter_finds_port(self) -> None: + process = { + "pid": 4420, + "name": "node.exe", + "ports": [3000], + "port_details": [{"protocol": "TCP", "address": "0.0.0.0", "port": 3000}], + "cpu_percent": 3.0, + "memory_bytes": 188743680, + "memory_text": "180.0 MB", + "memory_percent": 1.0, + "username": "wang", + "status": "running", + "status_label": "运行中", + "exe": r"D:\node\node.exe", + "command": "node server.js", + "create_time": 1.0, + "create_time_text": "2026-07-17 08:20:11", + "ppid": 100, + "access_limited": False, + "is_current": False, + "can_terminate": True, + "can_open_location": True, + } + self.window.model.set_processes([process]) + self.window.search_box.setText("3000") + self.assertEqual(self.window.proxy.rowCount(), 1) + self.window.search_box.setText("8080") + self.assertEqual(self.window.proxy.rowCount(), 0) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_services.py b/tests/test_services.py new file mode 100644 index 0000000..633743f --- /dev/null +++ b/tests/test_services.py @@ -0,0 +1,85 @@ +from __future__ import annotations + +import os +import subprocess +import sys +import unittest + +from processdock.services import ( + ProcessService, + ProtectedProcessError, + format_command, + humanize_bytes, + matches_process, +) + + +class FormattingTests(unittest.TestCase): + def test_humanize_bytes(self) -> None: + self.assertEqual(humanize_bytes(0), "0 B") + self.assertEqual(humanize_bytes(1024), "1.0 KB") + self.assertEqual(humanize_bytes(512 * 1024 * 1024), "512.0 MB") + + def test_format_command_preserves_arguments(self) -> None: + command = format_command(["python", "demo app.py", "--port", "8080"]) + self.assertIn("python", command) + self.assertIn("demo app.py", command) + self.assertIn("8080", command) + + def test_searches_name_pid_port_path_and_command(self) -> None: + process = { + "pid": 9824, + "name": "java.exe", + "username": "wang", + "exe": r"D:\jdk-17\bin\java.exe", + "command": "java -jar demo.jar", + "ports": [8080, 9000], + } + for query in ("JAVA", "9824", "8080", "jdk-17", "demo.jar", "wang"): + with self.subTest(query=query): + self.assertTrue(matches_process(process, query)) + self.assertFalse(matches_process(process, "nginx")) + + +class LiveServiceTests(unittest.TestCase): + def test_snapshot_contains_current_process_and_required_fields(self) -> None: + snapshot = ProcessService().snapshot() + current = next(item for item in snapshot["processes"] if item["pid"] == os.getpid()) + required = { + "pid", + "name", + "ports", + "cpu_percent", + "memory_bytes", + "username", + "status_label", + "exe", + "command", + "create_time_text", + "ppid", + } + self.assertTrue(required.issubset(current)) + self.assertIn("process_count", snapshot["summary"]) + + def test_service_refuses_to_terminate_itself(self) -> None: + service = ProcessService() + with self.assertRaises(ProtectedProcessError): + service.terminate(os.getpid(), force=True) + + def test_force_terminates_owned_child_process(self) -> None: + child = subprocess.Popen( + [sys.executable, "-c", "import time; time.sleep(30)"], + creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0), + ) + try: + result = ProcessService().terminate(child.pid, force=True) + self.assertTrue(result.success) + self.assertFalse(result.still_running) + finally: + if child.poll() is None: + child.kill() + child.wait() + + +if __name__ == "__main__": + unittest.main() diff --git a/tools/generate_icon.py b/tools/generate_icon.py new file mode 100644 index 0000000..e1a3ee7 --- /dev/null +++ b/tools/generate_icon.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +from pathlib import Path + +from PIL import Image, ImageDraw, ImageFont + + +ROOT = Path(__file__).resolve().parents[1] +ASSETS = ROOT / "assets" + + +def load_font(size: int) -> ImageFont.FreeTypeFont | ImageFont.ImageFont: + candidates = ( + Path(r"C:\Windows\Fonts\arialbd.ttf"), + Path(r"C:\Windows\Fonts\segoeuib.ttf"), + ) + for candidate in candidates: + if candidate.exists(): + return ImageFont.truetype(str(candidate), size) + return ImageFont.load_default() + + +def main() -> None: + ASSETS.mkdir(parents=True, exist_ok=True) + size = 1024 + image = Image.new("RGBA", (size, size), (0, 0, 0, 0)) + draw = ImageDraw.Draw(image) + + # Soft shadow and the same violet visual language used by the GUI. + draw.rounded_rectangle((76, 84, 948, 956), radius=220, fill=(28, 34, 67, 52)) + draw.rounded_rectangle((52, 52, 924, 924), radius=220, fill=(91, 91, 214, 255)) + draw.rounded_rectangle((82, 82, 894, 894), radius=190, outline=(130, 130, 235, 255), width=10) + + font = load_font(540) + label = "P" + bounds = draw.textbbox((0, 0), label, font=font) + width = bounds[2] - bounds[0] + height = bounds[3] - bounds[1] + position = ((size - width) / 2 - 14, (size - height) / 2 - bounds[1] - 4) + draw.text(position, label, font=font, fill=(255, 255, 255, 255)) + + png_path = ASSETS / "processdock.png" + ico_path = ASSETS / "processdock.ico" + image.save(png_path, optimize=True) + image.save( + ico_path, + format="ICO", + sizes=[(16, 16), (24, 24), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)], + ) + print(f"Generated {ico_path}") + + +if __name__ == "__main__": + main()