From 5fa9d25d8eb8ff6553318beeaefeaff41337353a Mon Sep 17 00:00:00 2001 From: smallchi <564952747@qq.com> Date: Thu, 29 Aug 2019 16:50:30 +0800 Subject: [PATCH] init --- doc/img/design_model.png | Bin 41589 -> 56916 bytes .../JT808.DotNetty.SimpleServer/Program.cs | 2 - .../Dtos/JT808SystemCollectInfoDto.cs | 33 ----- .../Dtos/JT808TrafficInfoDto.cs | 20 --- .../JT808Constants.cs | 31 ----- .../Codecs/JT808TcpEncoder.cs | 17 +-- .../Impls/JT808DatagramPacketImpl.cs | 4 - .../Impls/JT808DownlinkPacketEmptyImpl.cs | 17 --- .../JT808SourcePackageDispatcherEmptyImpl.cs | 16 --- .../Impls/JT808UplinkPacketEmptyImpl.cs | 17 --- .../Interfaces/IJT808NettyBuilder.cs | 3 - .../Interfaces/IJT808Session.cs | 20 +++ .../Interfaces/IJT808TcpCustomMsgIdHandler.cs | 20 --- .../Interfaces/IJT808TcpNettyBuilder.cs | 2 - .../Interfaces/IJT808UdpCustomMsgIdHandler.cs | 20 --- .../Interfaces/IJT808UdpNettyBuilder.cs | 2 - .../JT808.DotNetty.Core.csproj | 4 - .../JT808BackgroundService.cs | 74 ----------- .../JT808CoreDotnettyExtensions.cs | 12 -- .../Jobs/JT808TcpAtomicCouterResetDailyJob.cs | 38 ------ .../Jobs/JT808TcpTrafficResetDailyJob.cs | 38 ------ .../Jobs/JT808UdpAtomicCouterResetDailyJob.cs | 38 ------ .../Jobs/JT808UdpTrafficResetDailyJob.cs | 38 ------ .../Metadata/JT808TcpSession.cs | 5 +- .../Metadata/JT808UdpSession.cs | 5 +- .../JT808SimpleSystemCollectService.cs | 30 ----- .../Services/JT808TrafficService.cs | 46 ------- .../Services/JT808TrafficServiceFactory.cs | 33 ----- .../JT808TransmitAddressFilterService.cs | 102 --------------- .../Handlers/JT808MsgIdDefaultTcpHandler.cs | 18 --- .../Handlers/JT808TcpServerHandler.cs | 79 +----------- .../JT808TcpBuilderDefault.cs | 11 -- .../JT808TcpDotnettyExtensions.cs | 6 - .../JT808TransmitAddressFilterServiceTest.cs | 75 ----------- .../JT808.DotNetty.Hosting/Program.cs | 10 -- .../JT808DotNettyWebApiTest.cs | 44 ------- .../Handlers/JT808MsgIdDefaultUdpHandler.cs | 15 --- .../Handlers/JT808UdpServerHandler.cs | 71 +---------- .../JT1078UdpBuilderDefault.cs | 18 +-- .../JT808UdpDotnettyExtensions.cs | 6 - .../JT808MsgIdDefaultWebApiHandler.cs | 118 +----------------- .../IJT808DotNettyWebApi.cs | 41 ------ 42 files changed, 40 insertions(+), 1159 deletions(-) delete mode 100644 src/JT808.DotNetty.Abstractions/Dtos/JT808SystemCollectInfoDto.cs delete mode 100644 src/JT808.DotNetty.Abstractions/Dtos/JT808TrafficInfoDto.cs delete mode 100644 src/JT808.DotNetty.Core/Impls/JT808DownlinkPacketEmptyImpl.cs delete mode 100644 src/JT808.DotNetty.Core/Impls/JT808SourcePackageDispatcherEmptyImpl.cs delete mode 100644 src/JT808.DotNetty.Core/Impls/JT808UplinkPacketEmptyImpl.cs create mode 100644 src/JT808.DotNetty.Core/Interfaces/IJT808Session.cs delete mode 100644 src/JT808.DotNetty.Core/Interfaces/IJT808TcpCustomMsgIdHandler.cs delete mode 100644 src/JT808.DotNetty.Core/Interfaces/IJT808UdpCustomMsgIdHandler.cs delete mode 100644 src/JT808.DotNetty.Core/JT808BackgroundService.cs delete mode 100644 src/JT808.DotNetty.Core/Jobs/JT808TcpAtomicCouterResetDailyJob.cs delete mode 100644 src/JT808.DotNetty.Core/Jobs/JT808TcpTrafficResetDailyJob.cs delete mode 100644 src/JT808.DotNetty.Core/Jobs/JT808UdpAtomicCouterResetDailyJob.cs delete mode 100644 src/JT808.DotNetty.Core/Jobs/JT808UdpTrafficResetDailyJob.cs delete mode 100644 src/JT808.DotNetty.Core/Services/JT808SimpleSystemCollectService.cs delete mode 100644 src/JT808.DotNetty.Core/Services/JT808TrafficService.cs delete mode 100644 src/JT808.DotNetty.Core/Services/JT808TrafficServiceFactory.cs delete mode 100644 src/JT808.DotNetty.Core/Services/JT808TransmitAddressFilterService.cs delete mode 100644 src/JT808.DotNetty.Tcp/Handlers/JT808MsgIdDefaultTcpHandler.cs delete mode 100644 src/JT808.DotNetty.Tests/JT808.DotNetty.Core.Test/JT808TransmitAddressFilterServiceTest.cs delete mode 100644 src/JT808.DotNetty.Udp/Handlers/JT808MsgIdDefaultUdpHandler.cs diff --git a/doc/img/design_model.png b/doc/img/design_model.png index 297e9aa962039cb1130cc645ec8f915e1588d644..207d690baaf4b55616817f07340cfbd0b9285c0c 100644 GIT binary patch literal 56916 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
YQ`A zFR(EiTjos`6XMU9_k@7gq@2aN=FOZ^l8u>xbqc62oFAUNG4i)5;Q zh}?dnbNub0OhNCIESNN5LT_fJf*A}K&!o8t_O5bS>YVpna>irwge6EQL%k#%Q3DUM ziT^LU&Ag>cx5HFwq1(Stfs_;z@h&49-JCRo(wETImwLdxnUX~2JioQdrP7r|_M6LkAJTu5o^r`*E zug`mm6kXa%lfVM^Xt_`RWN(XD){ob2#sSri%no#-J%n#5>_5HP_T?_GqqFX(bV8nO~CcQ`cZrVw7 z+}mf>_}84iq$>`pI(e%W8mqP70542m!u8nq`#3AAxWEy9zL{dT;%R<4r9an zywZ~=Px5u+;J;1mWN53iNdG{);6(r^2uxNuxg~f)Wg-GQ^BV;+0FNW&sc8u6PsKeDblLxKuIZjr3>}nZm=yfo+xYk z5!~By(VtF0kpkRJicC)S+)OWfR0OT=!`^K!Dsmmxn^GCu_ivm@w-U|BH5DO&6ne<~ zyU&PG6u2Fz+I%C|Lif`CG1v@678;UXOnExg|M(HBj%8o!H0gg?kAd?K^tb)Uzw&K0 z8Rml5p(iFo%*@TJ%Tjv*CkoxFc9Hs+1`4Zz@*$jT;>F0O>l1;Qm> z4Ln0lD@B%@Z>^b}`yi5I_ zsam>38Zmx8?r_pCxPG&GaLWx&6KgL)Mnc3HvgQqM;}>3!<^meOSq~9(|KmV5hr#{Y z@81Jox3eXG!fX+aUDo^A_W;?bZv{&cT3p=Yz;sCBWh0KJzZ`YQrmXi%oh~i+BU%UB z9u-my{Hr%l{lu^?au{=doT6NfPp&U*oIk7~k%>p6tOdSheHK(!M4#uU% zbd6i|FR@oi)1>8Ezh@0B`p3z|dFD({6Wyt`Q@0OOP;0rD+bQsAqb;|ZCV~982?>%D zl7>Wr$MMn}_sDqKtxus_v+Sg|e7APcDK&>fH%CD&R6K_Nezn##iP32{qoeYQik{_X z=QS}v9x~!sk&+M;{LvfRx9|KbQs)0MW9!4Mb_Xjp)@Wvt78H8i23!?XCjt6I&mT-P zTh`8j$3>WN2SMTes`wrcN#7|_ zC1Pme=CSA+A4Bx*0&^4G4$!px>j2?H(bSmjsDH_?h#K1z5kT!&^IZFo`KzfOGp?m$ZGh;jqn*Qs37|g`UzNu74cSZ^38MmSgVLzg~wFg zld9+K1((mahFt%(k&>6_ZvU!m5P=ocu&5+W$j_6LyRNhd@CJ7fhzdiSB)hdxoU40o zi9DfIy!e8B>EikzI*kz~%)6Q0L+{IfFfXPDl8;e7vSwie@{AjsvFsJ<5vtJDQ~)}M zY#KbAoXY!{=k~K!i8(5*bSv0_3USN^wyCHLE>9a9f`tPzopYY9!p@s!wG%_-q)()D zinq~L0po%w{7LeKanHSGOqeji&veE@Ddo?FD?_|Nxtow;)UpUbfde) z4Pc7MGVY|JBD3=0vuByTb`@5BqzK(Wuj0*n{01ZBzG*-6TnD+yzi%8KuFzw%lIFo@ zyPMm!ELG6#MY+CB}r1U~0xnqxUK>01(D1&IN^cV5wTAc6)Vvt%S9yHU4}V>J&5R z)NYH&n{rkTlR>V$r`p(bkkRXwHA#{=xd56%?IZiCM+u5>CvrJ!ZUY03?Ck7>M{o1* z3vKZz@s^-IYYrRM395k^#sObShe?_wbEm+lS@-_cv3G_3-zPX+{O@5Dn?G25VXRr$ zPrLm4;qg8yX02Ntj|x)LXbtaqD`8kf+Nv2u8=C$0P+1To-7F|5a5IEB$!0?vacQ5; z)Tz0Iv5sB4daj#&W1SlExsd1p^`J>o-;$Ny1S`4S2o24B4Uzaq+Zmc(mPP@6b!IvZ z*s8ke+N@5-A-}WLK4mnUQS3dVoPQ##VJQ7Ua^ysG`YHy9N$}8Bv3}Igo+zUv{mLlV z+%EqQ4bs>;D zX%|TAUCWFrF&fsz^rVvJblYeL4GW!M2klC=80#*ZVp|WEG2IU8E&X%yL_YMLo&O}7 zmV9BjADzNND}7eC-SX{f$x3hUl-)t=a0fK=@$ork{I-wg$c(;T$}f)g(TpD^WSY|> zEZtR4%?i`+=i8tS{C~Rbt1ZtrvKYO3$0SHYG0+hdgyoX*86ndfUd};&cgbC-zx=`sBa1VWQ%c7k)3QE$!2@dC+%F9} zF(3U7+4wyjyR&14`q=Z<78W+<3B@6OJSQkExm6#y)+*?Z`MZ+{nhU@JUbcQ^pLcSR z%%-CY92^`@8o$x>8c#?NzXQAXT*1aY9d|B!KJ|gG^2Io%H(mRCTO@63r`EBfK?HE= zn%x)q&p|)8Z_X?2Qkmg6-q!!<=Ht;rTQ0w2moBS2nuf%T|L1o>Se^|Fb-hf~^emnI z6fh=F2dZn%$O(xI3yY1oFz|1tyy<*TN-Gvwbi{aYf#aEZ=zMt51YOjUw zt(MEP;q^x^a!D=g`W*?6++t!^(7X=IS-QI_@7ft9@rfUZ&-+!;3W2&k^8q zrOOX5dHffn!Gn?Ep?RhMzRbQ!nFEtDYd(w)%S*5Du$56Ap!u|8WQSnhto~8Qlpt9R znRXf*6Qfs4Ijr=VW;5TH9(61e0?#)Scj&KQ-~12dLYic*evcX}OG{U8pUDwYsD%YON?7o-zG%m%i#@0Im+@dZO{ z*fobW8+SCgHbJBH;YIz@hr5nrm@4mb`sWDk%2ASUnAZS^b!5=(<>Tb>kcvo{RYIWwdOY}<`WZ+0aozqjX&R7Zxze+w#!=@fw34g0iib{9f6g3l?9<|LN?qD~eL&KZ93gy8$4u77TD#^t zD6l^?cU3jJ{UbqxmOeS(PI9EAT5i@T+zNy>`DCo{fSB*?KvA@0N4L8M`{IlTergW0 zK5Uab{Q07nDP=WR4MwZRYra0)#=@etgrBWTie4=(EnO?lr8A5jHfYS4r?G_`4tL=} zJ@hj@28|j?KSp*_I2`S}hHzuJPh8fc#r5`*7pD*yFfNmh2{%z}1H7^|;2%oV!4F45 zC^Q9uK=V7Ickd&Pi*hV2EY57cQO;Lt+;)(-QDC7iK9G>DT_+~;k}N14;h7QG+fe4V zmMoXqG;eOTh4`f{tfZaWpc_RlU8XK0k`dVuV1pH*J zGeE}mM=v%sG_;jyg+HuNsa5K@v&OCY5s!PKXp4YdIJqfw_rf+SkA5wiBWHiC~r2 zCgbYWOVYv6nG6h-ljrqVf8P-$oRkEnyKZYX|In8EpI}{~A`z~?R-te7u_aKDz!f|? z*Zx;(<$>O$R0OseTYBPW%fBXL)`uyl_yL6?nu;aH|Ua9)LE9SZV z_vUz}gxr6W7Ou3>k9YUqzw36vBx%E z*%iLV8mWDO&WW0N`T4`9K0P_(0k7mh|0U(~Ls>q%TD~hzMj{Tqw#t32kD6^^-C9Rx za{A6CRby}(*n3mleU4W68+plyCBt@To#a@Z@->HvnaBF4c7bPkZP_}apI5t<^|D=Q zW4qZyfls6J*G;)M_*{B=`KMjnb%?m@n%Xwy@6tzGk2z|uyt!fo6>ZB^mf5$J2#eH~ z3&5aX=QoF94wIP5-n`XYGrrS2u^|HUrGqbx>h)CTB*NU7{B;E}1KUcJ%=}~WrNUyJ zCQnvS9>2<`n}vtExb3pH(u|CL7HGhf>2TU{8{Fh~SMMXdmO1UXWT-_JSmig6qXdRd zpls4~eVd>k_UYFzM}6MGn8&qH(j^kRe6J)giROUSjQ_x>S~KhM@zJvIh`ZWST3oG@ z`g?uM{Hcsb1xp7nM)_@xhKD*J3sI>P4KsT?0RgKMHgiIO2>J~3NfzEx7H{B_@806* z`GJ9fPke4n{*b4h82yW`pcapsSKv?7c~*$NzEOP6``gqgT703lkpwHX0s|F}MBf*38rKdpG%yFO}>%2KLIF&)^eut0!(1O7uqYg(V6}ts2y9T3&oYky7iU$UEl$z z0}yS(wZHKfW3SDQDQnA3+7|Z-ZHZPp?E>XBmd3>@^Y=MW?ze$#&Md?sS(^DKlE{T| z4bTvUvhEiw_TC{9i4iB0BFj;K;s3V1;9LR&o?Ft?5Ze80cY8C|v4hKY%RW#-w?ml` z6gP|{SU{KkYc&!7&MQt7lxecsEyfE&InS#w)}S-fpU|6gvji;;TG`TPmpf94S|Vgc zkow*D3x!?Ofdk=CbPv9#I}=D?Ro|gF>^~bCbys{0^l9-;4E9DAO`SYhO!oEM?lLA>%;x0@2cEi2AV|TfWb#ur|Gq_% z-O)KW)|F#p{rt_yyKB7`%V(NfB`pI~1uM-#a3S1OZsz8;1@T{q?+|A;ulUxzldxTZ)61~yhs-I>k4H~%|5Onp$x{@am#U>0qz(cfQh%df0X33x$@ zF21m2#i7AI_PGMox?lN0Ra zB&dr!Roy?dO~|;p7(vv~Tlp%>Y{*Ka)Us$VZ^5V#1yo%V;BGf0+itEj5qb!&v0+p| zX%NDG5*y}ynOO=MfLJOdc3`UUbm6P8 zkf<{RVGOlSqJ`0iy?oHK7fRFHpoPmDLe3ob8xWp9S5G2Q9)I_Ib>!A>ex749#%MZY z4hJoM?z&#;>dWKM$1$z%Lb5^qCx+|?_Hw?DFtQY0hTo{w-hwmdax34jZCgH!393tl*pt%UUcQ$XsKmntAH?NW+~^lrOFt2a}E+d*ZVmik3v8(Ymu?dIpKqjPAaF z|2xmd%*RXsuwC4~chR2yNUnx_8*`Ls1s_&lczXyV7Q#=q;5B$&6ReS`xmNv)jOwv-jZM~Wp{SSIy&PrUhv}96Zq5*73Y#mSO0A+ zTJOec*~i38aNLM>VqEQnZ&!$ts5w8WUih4wFub3SUH*16$9_5&IVTM9tt`lR+9JPZ z;_WS_t9k&hDdru~b3Tm^weC#vAXyv;$|x*?b|Xc1XjB(r*$2Kv#UE5 zj`4ALA|fMfI!1mSIWlKFz!GQ2)8tKmw-z%-bxdEf2!3=Z!roMji{b8HGCZT&v7)Oe zvNPiJB>{nP1E;{PV`!~X2hnenS=ou{DSI-iAA^91i7?xwx3+dWnz&8T!(N6w*nW>VN7^GkmyH$-vCy%Afr*0-$JqSX?N_%8C<7a<|K zVPxcMvYg@Is>bgg2fvQu-oUkduHWjda||~HNp29U=lE_f_}!+$>@UW?C%YA zc5yi{<>#Ws%i9It8?^O*s=<9>VPQ}0@~?6;$NH~#Pzb#CqW|v<-_HjYeGi}FJAtBn zYfJ65(=04OA|P|C+&4amtCyu82Hk8WNsRVfnr==3C(y;PStT7MP#sPsyj^K{(fR|( zxs=3AR;3lSTDO*pa{d)_zbb_l9lA_MmLe%%8eBVYM&Y1A&a(gKx}$E+9o_2eU5{00 zadVFS9{&7j-Ory3G?Y5pZWUO7*Esk`t0c?Gf#s*l?pVzx?=HKT%0$$DNJ1Iag@4h4 zF<^9iTNc!aiIN~n2kQBEADm*%FeoT2Io4r{wQw|#vNN;p-gtHu_52cdQ6yejCkbYz zYGBwQS+IaYpK#``oCF%#&!?K|+~Mq&JB&s?Fhr8hnSqk=wyJ88_6wh!*Omx*o#KVV zP%@+?eBrr8G)!78KmX{D=Otf`O%v0X$PT&M3TlSRtTf%)v5C>gLI(F4Gv@d4Wt!C7 zEuc%@=84*uT4go=Z7|`zDWmJYSK{pK-0w*)5>#OkB^kX28^T?mL&Cy7j1@8M%x5b} z1zd?u^H=QMY=7eK-wK@ThfF%ZgMLh!*Auj?lQMf;za{?Z0$!>Fm*U1D=rrPT_T5Qf z=$d#7jqK2_!QbIXWzE$aO?SM4cDHI#Lb21SWt`|SFVNLC zxvXaD(~-k?JmXt#Hx>@6)LDQeb&%eJqQk|5z%9-dhG5#od#nAHpPsS_oMLYa!qhvd zsax=|XZe0zBK6=#<;@ovR#vykwzUUV_Ly*V`0ov;$w zA$f8gW(h6u#4iSZ^0Q5V5Fms_n}zxK`88-KsrBM1bP!LWwS=>#o#LatjwosVrhH-i zHKqlEK*^R;@)#>U37gN%HhM>-Ffw@}zO`nq_|^qLB__e62>DnAM?w}*1%{36kTSWG z*(sXAPT?w@GU?3sCg(T^24TeluDq@R&}V+J>4t^c62KPv^8_&48p?t&eO=a9_2+EG$Lh`ncLB zR837j2Gpv5&)};GZ+pw%sHy)aF0uoonO~Jm0354*uDq38IZ^sCdAd$%Z*32y;6RE0 zwlg0V1Ox^SR)9|Hq!c|wyYie_SZ}M`aqD;6Enn@UU@<;t4A1wS&!few+iTpOB6(0# z-!zD=us6rXmP@Igpl$ATt$vkLZ~EvCcUnNdNb4k*`3D{^zHm^ryF3rN&%YSroA>W$ zbjeWf9%VQ7ZPrR+nkuy@SZEgwi{`cq0-mk!$lFvEZ}Xi4{n-MO(WwASOH@0G&q(<9 zGtk5)huh@`D&C)Q!a?!H1uo>@wlr@M_wXEnFbAubm|DTHFl}9!9!?V10((=v;n145=HMq9E-$M?aQI!roin0F_;{HNjZ3K8448@>PFbbS6Z zH9o0w$sqsY9PMbmqrH1}jJGHaSzQotxt+!{RkhY#_74c|&*liXku839@80J@k`)Gq zDmvYHs~&qL679-vR&CANbT-qyW)e_wbi-x3$Z5)z2cR~kj(>h|$fxcp*Cdigi*C-K3_1;@WAi6Qfh4T1y@nj8+bm<;~?^ z<~4alMsAQ}v+ofg^ZI8uk51Fj?{RObWHfHIURJqgZI+ZAyZ07eV`TI&+vJizZ$9`R zU)dv~s&()g$r*v(M@ELqB|D}R$!fGxRcmXk>Ko3&=g+%DvBt$818uQL#UGoNt;S#N z+$}&k@#p`!AIpDUETz=Z01?*znj-a)2>03x-bGXC>~S5sf8O0++?<FxCS+G4ZF_y z?u``1U|8OA@kKFF7d$KJ7F)J`de4^MWbk`mGTI|>NXTed#l`13D2RKQr67JkG%6@+ z6{96T5ko$SYbwqjI$)LR8S2=uPZ8pu&G}zp!={if-bQZU%>SOXqXhx;^6F%|_{<`m z?8IoQ=ndg_7>q8|>-J`|(j`?j`7RZ+wLLO#&du}k>FqFoqFuhfhQ*Zx>7%p>LYAU6( zI-8F4>U7noWRmrM-)5^}YNkDc$B^K{<7XinnbBo@#>eXFfO^{8yFZ(6+f1tb`n7o< z=k%P2{Wwv(W|DSII}M#aGb&^?)+9z}6y*0b@QB$wtFmv%guQmhZl-@?^j{XDG$Sc` z#%86m^mFG@Eys_4E^}n`EAKG__w4na7huq9Pj`Z>&N6YqND9~B^uI>xm$mlV%}Uqv zCMuum*DfP@!;Kr$?#(%)*jLVv2Ei=MNs?xnF!XUj!N5He&0Ik~>d-bU?icbv@?e7Y zVI{LiZKw4z9p83~uVU~<%g!hMhYL_`^}UtkTD099hE<)JkKbK6cUFfICO%JOHjNt; zGEMs1)j2CZN*!;TmA&DphxFzCNtwPk?yK#!vqa1O5e3+%biZaN*ZZ3*E7v$Ja8P0? zT+|?+bhgXCD0$Lqp?1i^-bp{&OuIX7Xg_%kH*Q)I+j^yg>?()klG(xX`t5%-Gz?*$ z>yqN2(_T`N((n7C#jc$Bi>62##iafX0ILn`pLnEwReOOCAjIh&Lm4nnuUpj4of}S_ z(uF~oP|6O<*BLla9<2vo zv!`)2{LQ-a#S06+o}0zfkk!zXd}uFYZsFkYsGpHbeMDvDEFMd!hh+}+$njqmFw=X; zX*@w^aIs_agJTU0^saf`Xgl|>*}c5Hv%k_uTmw_o zA0R{5RaH$Z)AVMlg^gFTy>jL8=b&#K~f?dnA59@I`Fuut-2UBh*p z)-w+DL+IJXaT7pKqs91Npa;N)k?mAX9UWDczq}rSC`EWN3+6fQaN7`-z?CR+Z!hPy z>*^dH&AOCnM{m8RLhPoh!LD{ruIt?cVmj`a79gd2?pcb#r2R2sH1@q?w{9Qcx)3aq`yR4j?8PW_Oq)LaoGi|wJNK6976t;1!hJ!(?It8B&k3S_ko6)LG z*~d#4_tXj>HcNJ>Y=(^!E!#$#oOl)h#jFLOk9_$y?@7Sm^cgF^y&5OvsfsTQcI>fR z4(2fsd0iK)oQ1c(y9F5Z^wb#=>>)FH&VB=VqQ)KzpvJ2@;lmtdQBb}(@(O1VT-QYZ z@&RZP8b;-Z(aUt`7XkWmflY*y$$Tu@B_T?S?D9WTqu};t)o^P=JKRX>ciLU=FjqDB zu>>(`zcD@^dgE^L052QFza_S>4GQU?R&jmc-ohPk7wuLnJ}5UadQyneO9~tPFiAmD7OvNSqx)EpCk2mI^om{SF_{G5kmsF0x zJ1+nm3hw~ho2s*2f1a8H2QP2<5F{A)IRYB@*O+%jdsD%B^5IE16+TUK51j?EptKub zG=y>Jslj|+RnfAq-_sozJpSm!@m#YwtZPd1mj29ScA@9m*0|Q%I(#Wo0WK25hJ2=3 zGjDfNQyYY?Abj<924mv5I^`t?0*^!ya_$?U`CizM%qsBcKr|bP)3*IQFiiWUgK} zA&z)-V)vy>uZd93nZ0m+6-awLeuye{Gfp`HiH`yhd*t>P)o=)~^xJJiu1h2YPidI4 zR)9IerdI&|)J*4GgSmA z0Oj%BSEHRVk^ke~wd9Zb4M)ibjS$nrW7q2OBG3dr`DfaWOjb3RdMoklPG}eK60>Dz z{?Nr;==VpNO|MNPW>R7o!>VPTvtxEmv%xt@pDE*LrlylMK$cRpK!U>R_dw4#KG zS}5NlVH~d6!nGW`ru=+`3uu%d*88br95?B1Y06I_11VlzvbQqqd%EYJ9wzIID4mek zsc!3Vo$FA9C!x@DWZ~jZfStpd9~MseF)T)Mhrm3Q+- z^Pd%vQtO&n(PB~!>GhYk873=i*Ze59 z60Te}aYkFkjEv(t&s{c$nK?$4(=z}qg{`0vnbi%&0%a>I19gFCxoH%0sIr=64oNdf9PjD(Bxg7Sz~l|eDp0I9=9k9Km+ z@EU*T_U%0CkGq8Z0_3OAa}%QtW+<_Dbg5yNzBmKBvyE#~{$QEv z@ZlwH*V-O3@V1P^MbIZ_GKRx-g3KV_T+lUwPzYmZ5g`MVcv{@(Rq3 zn^!-ABf-0?s4Q4T)U3+GLUDq2Qowo|k==aJUGG@3*hFo*htCJ_BK3~jGf45p(Q{S- zF^Q4l@XxHTkqC8+h5&)0S@m4KzdC3s>RT^t9={VazeBUN%a8qYary@R3Hy$IKwZe!PsX6Dr9 zkWDBN+nxC84~t;X#U0_{x8O@KBsY~9xVN=AII?|_k$tAOT!|+hM*35elPW)-J4WHR zu*Ya<6h1xrbD zE=mYwbaw{Y{%^Jp=$&+%$?s+?m)+J_2v6WmHp$r-1=r#;@tRO%&O}y3MPY}=sDmD1 zW}N2@L8W07dSGU$a%lSkd95VFJujoIkViBQeu|)6B2ExudYx@Q)p#?L+j!=~QFd=& zW-tyP!to)}L{~wMs9J{jaBbbovL7b9xGsck3Gm!6dsWJ*A@0Z#+RJiv_#$PLODmMs=DEPFKG1aUs$n7M*x|@Dx7l^2O>rvC)1GF6Y8unzO zG-}z3+BUG=BLpqNz+??`#2iX!sdsB$W7?(ta&21~8JEnLTtB5$C_TQ*nvSlS{v9!D zOnXvm^<_a11c8?9Se$#qnwlkf1|9KfiYoP>3%bLPW4*Hpiw@<>y);?}HhhU-S{6ov zehm<^EI*hXCYK!|tlWJl;`vpBd1es(W*9AmHp^lA&n9zXMT6Gev`46JUP5GQ$c`qB%t`j1sRCyTAd z;b{_nKYvsQNmY@Gvhw`6FHbI{l&(gIIh4GNMT{^t*X+~B{kmmBfLUtUjfnU|S;{9e z^G1G}E><7uLbx-8!p%xxJ6sNG7%Y^}WL5={AA@6GMx&IM5eXHtNVwn2wOyG3RrSp} zfL(`$m6bc!_2K0W6WF<%*sr2F{slKwTt3@|NIMUx5Q@4vwS@TKHT9)4R{Hq~i&O;} zX&QRxH#QMVr@02V|G4i$h;T?l5P$B)3ZJSS5a6V%<02Uolbq>rd^eAQNjGq(Y+;8m|>)r_y+%j`yDynjHF zssj)Y{-<`zKA}~Vv~4w;uwlCeluaZA*|(nLEe9%3zq7lIrjtewTN zU9;G0WMwN{4uoMoqP-)~ysFl^US25$!+GQlMFoZ19KXC7B4KZi3qw{U6nO|kYdPcg zON{yzW?qB<0Y#bh(j+R5s{Mt&8|JeZWB(dRQIPamb- z`1{YmqRfr=rwXbSf!v+rPxp;pB?{wtu7aFR^cFXZ5wALkGX6(OJ$uS)v=%mx-4tXn zVHK*Us(Jea0UE(gWq|LC9x&PJ&i%%?0{zL^C;4}K%sjNoX!3sJlMrQ$IZ9ylY>nF* zlIwV}RHYoqfnQ&z_Q~FQt6=e^Zj_OcQTdg#FQ}3ICP-yQKg-?2wrw*fz(~E*kHOb& zw8)dn<%@1o+JA$ka;v1IGu!Z-lP`mH*fYh?wwhz_AexG8)kw93btA~XDTE{es0n8S zhT1bbHV-p^U==J(p-oRkr!(KPm}PsB#w>ZUEWVVp zd4QFseFqFk0OAt3F5atdXRKUKtFYMij&J2KjSJGY36N5plPg!FoYMme z6~#~j6!Tw{sji)&rEJ=4PMfr#um+B2BtSb0q zduNQ#kK-JyS}$1>RR3`^yvD0eJ)3F91gP6sah^clrBUa@Ccjdzg0)@5KZ+VIIJWck zXU5ydTUg9xH>o@&33P7$m1|P?l}Hy1ITQllUqO;way>pKDk_+0I8%RoL2AY(Tw}%p zkl-WZM%7Y7FDP*T}*>F{2_KXGWLFqfAc;ZsGLrD|){`+Z2+T)lSzD))iwpS?Sd zAH+UDa1l4CGu+rfDl>AXsIPBYwT24wGE2X-oFuYvd3tve@tGP5zUc;BW zA#jeeTX&{(@p=x3xYTP_YTrr^`Jbv~)RpcF*}OZyDkz7ZzB54go@jVQyG^52%mE9K z3FTSC>7$1#%E{e=+9(%cV1k43Z9zY!pm{}satrGKQQuJ0yn=rb0+o_qIlJnuCGIWH zo*Cvm4tH@4e*1CXR;5;Grv=T9wxna1E}Lm9=domdvEq<5v~Qn7>vr#6Kgj-J&_s^V zScd%pS`8@ebebQv6S*Z*}f0Vez z4=%7_IArKrxyb__Yz_#`whQ<0SU$V%Payq)8jxxB*?HMYN=m^jes}&+oJ}cKM%~^| zo1mpfvd=XQ4SN_Kx}SLuuw?_iJ7+!K%sk_onoFOlq@uEgAm>*5CP(6BV+TFRoRTO@ zbEi0Y5AdXLiuz>C_k_(N1DG}pG13>h;P4Y8*Zfb}jcHsSLJo`_nx57_8<5nbY?_1j z|Mdr<{CKV7@mf>!Bv^P@IEVH+voS!{T7?0GlvT z>l5dkp7$Ryq6?j0Hq{~QYnN00lrkaBoGp{{xP0piW;|PX;@r9*y8Qx z(2Y8gSj?8V1@cwl3A?eSvbk~t<@cv27sL`Un=nBZonPTsKYTDL5j6U|{W`Q9k|%P7 zfr6aPa}eQU(3Zh@r}5`*96M&dbyc|G%LBY+4NjL}+;LH7h*jC?T_RkUzROP3eKhEZ zPrm%wIe)A<1Bz7yniaKc7qJQ;ppAM8r7Phkqj5T(9@`o+h_Z^JV7RoR7pd-5b@f&h z=1vORmqAQvc(B!XT)3U9>D~NO`hu`bZ!jWPOr|(7qLqlqwAK$&W(=vj0tY0UXmIaz zw2+lQy>$BhSnMipLQ~o}!!@7{pr=Yn#{MrK?(G|zt*>jd!TPOg;&G3k$I+t%&c|H) zGSZ1PauUFPUB?pn-I#T{Y)^ZLd1XqCc6ciiz2H%DRE219#U>EZnFc=R?(P8sQqKJ6 zV~Swez6f}))>L=6*@C(gC+jWb_qQZjc$+urN^v+c<`kS>pmW*mQE}X2=I<|8MO*m) zwRh$3Sha0;6Dl+)R47p?QzV2;)lE;PA~LJUJVr85bLf z*R2Z|lnDyEeYOqSVkH4LqqC$Uo=fQKv=IV8RtJ6G_g;^d zn(l}HVq9(qhJ;BJpwCBAtS9*YUX9~-s7xu{6M3&8cv0@znN_1!wM07(-tN>yu8)|a z+;x*fOOwk>>&VD5(DRj0H+g{taCvagzMvbFLJ~l5AK$a$Axfh<0I#S4MOP`5op320 z>I(2TOl0WCRdj;XiMMryz>Uput5C(y&!I+zPFu*dF$yQnuajqf-vSB9ZFLNmdHooR zkg4K_$3FU?V8L-$Y>mWD5d4@OwxZ<+mlV_QL`Ex(-Ampxf^F(b%c?D5>fhi|))&7B zGN(;7XywZdnIEVUYX2DT*+jWvID{0+n9o3o3B?E#dG%3r4s{I&dEq26T`8Paa!mZ6*53nUb4C&U z9e6ouD(V!5z2DZx1#zCT$qrn-Rp~h~AYcx3Mdokgctz+J(25w6V~O`26`mJNGOB3pW6+r4pB3McEV_?T$fCbp~7Vjf|lO*y9Sur)sfBKe_(AgqOIJ~aC z0X4;0^z<1gk{A(UBIaMcj3r+Uhnn8YHBC)xV69VwS`4I#&BWHm0n{^?lT@!vptrsJ z*p`}{N+4jgqNrqLF^OVnOI>=JH9Rq~jj=il2QKnT9Fi8C;mJZuMKFyiXy{4jgx!}# zO;^lv3HtNz?~d}H1)?&P9*#L|u^%N7y;?1&jSnVWhT>f8BgW;3Lo0zuiI@+2eoR6_ z3<3*S*f$3fa!E)?=(sHtc5U>_j8k4GxsjV5YO4t`grdLgEJbatJVraDFXm61^;IH} zE-VR?5Qal0K^j#?0GiZd6@7wq?rFL!3gIK53{h*2r|UgFOo{Ci2OVuKaP88G6DO`L ztCVy-nTY%`&;%?QcnXrFTf|veqC#_ zsl`VA$xUvmZqw;Ai0#-GDz}DTnGXky%=MU-*aPd}LsM_=^&zsScImJk55=!??GPAV_I4l_7+OMO8V`bE+>*?#p}t{ z(&x-(*ImAd&IVvSu`K!7dvdzav z|1vZ%ATP7zX7+5Jz|w3h)FsemDB{Adqf#~W>*;YRTZ28z!?Uy3kkj*?wcUirKiyJ0 zlGmr(cME8@!h_SC#|n7R^dpr&uV?ep?ez={27mitsBpSJXx$sk-JAnBiPZHs>J{N- zyW_oIj9oORTSID1tj0MwaPUL`N7KYO7i@TpEPTK2Ld<$>{r9M-sMiD~#TDJfWj7#b zYNx2ECbp6tz;&b11sc(47)Trd{}q9vEhOYGd;7^`Jc5 zIJ0^9e!6}3d=^O-I)_8UGOvr4st^wRC#MKKWy6ke#m~Mj$Op)RtNRy}M9KCsB#8Za zz_LHCvAKEf6?_?wTKEidotNX&Gc)_v9Um37i(DJfs|FPKdsP;?T6Thq#(V5gJ_(-P z8WjjhYukeNxIPz3cU8oJTB9>_hbaoj<7R0IiQ}|Pk8XGoLx+C~9sVvMA$9J(W_wU2 zXD_R-iFo)>JSP3`bo-+pJfvcqwyb%5Y^S92qe>^)Ski!vS*^WsrF#LolV|roNA)L>Bl^fTGu~2 zJfytxv3Oobpfy`Y-FxYAzQ73-{4^M&F#5?gz4Xg4diJWJ!DFqpf^Du*Id@d6bQY5; zF2*_fEk6U)a!y|hQvrK{s znNH?!Gcz+`7Zr|TJOx@P;ynzb+*{$wzhBM99asLv1lPQ3D3Q!Pwh|xj#)k(tp|tm0 zQ{gdPcr7o-$~@PSnV3bSTsHv~t>lm~-dEL!|M(4i<4A7zkr}&LXL(+H2mNi_E0x}9 zkz6COY?(3MyU{8=_i8^?qx~J@b0^{jI#*hLem+m_SCnXhrY#A=}{RXT};C+;VOhR;^~4g*mE4%C~Dd zxpVGWb9YW62-Wdw(E)nP%z1w!RJMdTA>(~oLK`Q_XLO9RPNB9I+_j4t74seukry~@ zpWy{moPM?xAprp%^&BRKdIz~*e-yBJ7k#3Cc}mW25V z=W)oX{4Ij+6N9QPRdw+ZygZhf3XsQIv9-IeAuEi&qoH9MjK`Fg^pX{V2SQ= zpDCH>iPDo7boV;q&dQb4`>}WW&H28Mo#l(hboPw+lllp2x`CtZf5EUbyzkG1S9XbW zPWd$J61w@)p;U#O_&?~fSFSh1{{FlC@F7j7)2a=x#3J*)r;*R+;z-7>gDVp+fyaDx zVPt7Kx=NMqSw7e8cttsq_w!<{h~Th8*EoCN!Q;qQDqs&h0J`=1J3FVhxpIyY&X}zR z2!}11mx$FM1t=E!?AlWZs@Ta*d@?Q}VKPQv8L@P*#%ITPvJ@GZM~_DMr4jJ8j;klJ z_iUpieSg>`h~8sp-<>-VdO^-{nu<51W#_#9qWs{a-(b-?mBsaSb#(+*ag1%UnK3HK zsnkhO9xor$?bV>^tSDYU#XsBpIzdBI)BH*O7Iv2KCr3S356%&Dyx|Y~Cwh2eqpP}4 zSphR>FyNg;l~zZxc7c|B#`ar-DcEpqHH6M3@VL@^Zx9He17t=2@cG5o6K!juI%Ru` zKPfIuqQJU?=h=~?;`j7Kv}r7Sir&vUO!RA#@HCxn;I~IxwIY zQ1J9+yk}l|Z#Emwc!*|pC}#P!J7fZph^3AAqkf zN88)0)V;msprp-(fj8td$)A?b_evN3cL5KgitZ$Vo^lt=Pk&juUvtJtRFEGiaFMu} z*i)|$y8>3H`&upOoj4H)6$h2!0G7vOzMkilt zGPJjG{1ctIwJFlOfU5x!z44tez z{VNdH(S4Kq#Kp&x)9pnsm)O23=`3Wm&*d?4}BiHHyZD$~JkwPHDH^l+nJ6 zqTA$j4^}MhO#Vra+CnE&U!VJ} z(<RKm7l^^=V@dGs_r-Wal075LV|{`n4+tvTU_r%q|;>D{Sc zIH3P5Up!*ybwfgD<>h!&CTE+<|13`2!(Q+DL=KrX)>02H?n&FAerxj;K)VM=PI-2h zdOGHHs7!A%rxQL5)4t4t&l?;H)-rGRR65?8f11IF^o1lPQ9naRYMmPFH~y6f_@!Cm zJDbTkB^p}y{9k%yO!^^(>uaJaS1nV-Y&i39#h062fu}tBTu7`&lAIThrap9V@Hml=2lBnH&psv0~UA**6;~nWA?7m zBUu&BAf8;yzh8$h+8!zZg^EPVHp428Yd!@m;=&SzISS0?HU+B-oGzEt;3J9zD0&|^ z$*kRa4p!oNIJRF&L|-<6Jc;0z+j?+fAhb?E_2_`9u5JX>hIKws!GIOr9!)B&k$~0df5wJ? zf>YFm+FF!MabpbV-?5pXl8P=T*$1%hpLtV+58dAG=ce34QHGiw8)hsQSSuPwMepNK zUcKM({8dLO4&D7gp9^@{uV0~V=#@g05qNU^Z*uRke6+XXw3 zH3uNj>1+er2tX?j5f+4wYyq}*Q7&3dmp4W$S^nD3vm}1u)d1HU6DzE=y#jY1oRqZvqPfww<1^07tT#C4JOH6i zY>Hq;#r+c1>URi^1dw==SU>0{M>I?2fJnE^hR5-kE@#MNrGHL~ws?VW)HO3>r)KcO zmQeP^^>F667MMi$jL-Q~g|_f(1aw*lX-UN0yRDoOeWL>d17}d|64wyIIZ{327cZ$i zX)j$=w}4levnEcvi4z*)Rc@acE&OH;5a!2qYAg)?t?88oix6fF<|^IqiEVeN13>nD z^hu7Ogv2_H$AidwEZKpdZwM=QksN5>P%u#5S;-@`S?Y-VHyHvy(j`FhDRX6EPikd9yy^ zH9j-d{S|3a542jguwP&1h?oF;gbGM9-v76~+pfmahrm~Wa@GTtOd3;&)Eo9RPr&OH zo%DCrJL%Y_9khXPYNBjzf4tAo7TA?!7#l|6Z4)PhAg4j`xXJMmyj>P#7NGb~IPQo{ zgA6I7SxUxnDl;0!ta+)`b1Rs;YU~S)p>>~o7Yp7d3-Q67nEsl!m zV+t3{y|~`Z9w_@j_$(q(oe0oxq3*Y%ygW{SYW&4+!V3JmofifWPBYvW7L1_Wfcc&! zinEcV8|yhZ-u2#CFC`)(^2~GW6hf%h5@6WFT-Uf7TL?60gi)SADK8ls9< zQZ6Nf+(Z}P4V9HSo2Yae#IKY16U0=BxP}vWh}7TL*|%JUh>yfRjR0PElI2BD8vF+_dd0f!Ab8>Y1kKQq!0`7f_;W~3cxKzO4J8sG zUYc)IazxCFii#RSTATmAuijcV_8{fWTFoZ-o}b8tcfzV20ewu!wFJr@TeVKKe|lzy zK#yPtHeuYq*`O*hQe)+mA@u}&xRbx)&Y*Pr9h4S>Bv0TW;o!1~Qa1c7&HRd;X@`F8Ojr7CQ_F+zei z;Ckwb=eny_)48L4Rm!}MDm64+m2Hnh=SN{kU!-UslU}b9d7{*vvLE0J$ z^iN^9PM&MUPc7O#qpS{2COL_`uEitf^kq%qSx$;>G=viI3=WgcQs-7dFCKJpga655 z2#+DmC0-9_f$=o^Jkr@sI~P@R=I0)9aq<4Uv| zU!VP`=c7-$RG*h}2b6C}N?+&IdwwP1Kj+3nQH3#oGvZAyFXw|s6tMWe0PkQ|apl`L zr+M?ejGa_}9|UndL>0_^e+S|+mHh-t+0G2@zaPYj?6QN030f1+s40p~~JqpG#3r5BnQ%epEX(YPiAm8oXz#nVJY3jnk zXgdtmArTotdK&&1XLYS}9EQp;W3xk4v?0nEZk)5CUu{BPRng9Q`uhH+uevR9EW5sZ zDaeQUZ*KAwdcD}98n5zTR(}@Rpl=HSIq3+`ZVuc>xp)Nho{{W7s`8ry&tRhX%UWpP zzCa(PhNHQ9$lE|)KQS?pf<}!@r4iy9HvqPirPRXe#|vX>nLDBd;fLj};35ndKvZ@QnPLZ7Fmh_e7}*)IB4YX|xS za}RO(-rw?J&&81t9v!TFe#Q`n^&VMY&ak{~?*U=urH)b~IXU?)(tYTEuoB5QF@(5N z#qve+IX|PKqcPs{Vm4l$r5R+`f%Piojx(rJ-Gf`2IQhqE8B&C%4<1mOP=rHe;XdU5x+f6CW?Sz$4jzDu}=Bl`!0jA1Zhr_Vz9om6%_seC}>@(%AUx`Kr{^f1{!n zs>o)&7D|u6!@eLVTJ6#Tv~t$G`*vgb!jwOI;&6fK_WHa?>L+(~ zk;dbbf|d+tu*JPz^72akHb>)ZIW>}RPZ#mSi-Kx7E9&TfHd0oE3Y2@o`=|@fBcDCwy zwbTl|Or^lJRQKt!lD?IJ&m9lMF8FZ>pVWwA_^Cs4$DC+($iU6NT+qO|&yV+b)%8_5 z?kNKbb+BuEZX29@A7zgzMd>N2rEbc+QJFt~uf4!|D@CI+)^qd}Xq6A@v-BTK)6WjM z>?papvfcAf&$DOGJfLV1`|htl5R4kzuL{74lBfBku%J?;o)W_k)!FFXblcXYQd6ct z*2Uc^Qk1pDb5RyI9a^P}_M3Lzy#Mn?9kl#rQZD@1leBBPSMlFE)`B%6lq zT#xtnobwNyU(e@u^Z9%-p0DTg@wkuceqGn&>93|Dzk_lgB?Se=4n+kS4GN0&Eff^% za<^{AcT#Ll+`#{AyP=@xKtZv6H~Cse5fjHiL9w4gQRa-6OWb&`tAWv5)skVbhspRL86xYDIrc*=Dzjr3M_-~az#|F3IspYPx>_5KQr z&(FhdUb!-GI3Ve>2m{rzJ+gM2$8TLZEhwuVkddK3{(UTIr*q)Cq&>3!I@-rJ-}jn# zd6HonDwkZGmGR5;@ZrqN^78VTVV6rsw*{%BEvadLS$&&%`k=!WPG1@`x@6vZ7Hw_S zg8?s3v9n*US(qC!X=I6@agFC}3Hd%Spt0}T1`#c~XY^{jpDRsz+8nyE`!z1h)z5Ha z|Ni~`i3Vcd8f22cSQc$yX=1rgBRwdak#X-}fKYE|XQ#uD>Y()DVEOx{=fX$i3$C>$ z)!x~%vuBU2#g>9i2CHR3K|wnn9ljuX>X3GZZ+tw9sHmv!#fv8RkDHCP^^VgX9uhM% zGass|cJ1A3?#8-jPgVBCqSvl-siXMDW4&wZ-g;?k|Lg4TUc348<5SK^cc-f-Z+`Xa)iCw>t?Z55l9CD2(>In^Ryqr>?{zEt_WGCe_3LBh-Yb7D z6rB9An+j)Kj;dZw;T`^+RmSmMuL!Js(FMPnb$TA~iw*8W~pu@1zk7GP)>JeYv%2rd0P4Mxq77s_<{`@LF6fm2Y#CvMpMT(0T zFaB!J4T+6q%E`&W4Gifg#TjN~&@wYO`tRmBfsf=-P2dz2{rXyrzT=tz1AU^{&0oHZ zm5p-+`V&&858B$=rrXg=-{ys)JvS z&B#zuqkFc=M=trPMO*6c@y>^vckEMpuEs9xH}8_3o<6^@kY~}x9n5_4_B&&NoWuh2zJ95yMhGTbYYwH81tT2{S>JzG%@%QyNpn`x;2k+6ef3%7_!#F2}yUfdk}Dj(~_yh(0pY3Y3A{8q(; zyEGh2;SV21AG=Qf#%W@`!lru*OG`(E9dxA!w{4PiwLyBEMS2{6OX2hDOQ!IR{?qye z*Uo%@f47OrfLc*SW%%RMvo3CKvO-Vf z@291u&HUNBZrwUfipn4V=#q>Nf2_+_NxQx+OI^G0_MJN$*u0ko`@?-hhqg4Y0qc9^r-kkhnV8(Wo3gQd(0}So{o*W7gI-A?xGQefCeMN%Y z`G&U*4S@qyfw4yBRW1+a=Uu#(XXO7*^{KkJocR0quZZopxLpV2j1eVWtAlk9`3zo% zK6$bq5q_qx+;g-&H_^h=slnBtQB^--x0bf2)s}9gYpT2Fz=v(YEaGxsGPFlOr)!qn z#I+p9z6NdDPXEHJDaLVZ@z0pNrRAZquh|VRJQ||}TmEtT(nO0njWZ;AEvDO@_)=L{ zSJ&H|aLT=fJRUVY%3Rv0W6ArB4E{}$yc#L@#XJ`sy9%$HPrfjEex)iv(EYDf%(3g$ zjnTr23JOu_Uo10u0|uV9k3DQ+x#V@+_$>tmEiJ8Xg_mcEX-JHaDWxAZOVYVVhkpP1 z61ba31wo}_^R2Y*rKyGTmOHm^GYDSUNKa4iIN1}8g7nh(-FjwbW|yUjqI|>PlghE8 zK_)f9d6z5i)o>5?dHyp@ZOFY;k#O1Y(IM@hU$bLJ3um^}Rd~O?T4=B}EPtPO%m(Y4n19AaW_2R=U2O4s1iFHlI= z%TFz?6pD44=ptps^z(CdUq3(Ztr1qONwO_x{ivTsiN9L5`fz_2MNfryUxWnH<5RzK zD^}MVzq`E&*SH&d-1bxU#p77T>s`aBC|m~*`Xh>?yjB*~u@KxUakZ(+u}XCgPW6Im zek=hmpJ74x3`-&q#bM3y;&atZwluqTy+eFh^p&3yix0-OnRgt`9MlarV>gQ1cg*sI z{m?nNpnX+eGA~>|9AMvARrSo|^y#;X4mI2#0<}WJ&4=FI*%C-6JE~Fc;ff+RH^IB_ zWV%ka{_1oMm_FnVWOyS>$Yw0-o3kp+ZJ}2Hg0QhcB^3Div0B_?AdzZsC~Gu@7=q0qo2483=E!YrGIkpW|h8Q zbNJ#bzJ|v~N7_`Ss#;od`EKZDe);?N-@iVK$qru^bxNh#tS^>QoA1#d(brm;d^1I- z7`K*dP;8H#zQ0p){&bMPKV#|_%cF}+OWwAVuPIB49Y$t(1GG zRD#wH|0WG7uuq$ee@#b5M9828qJMQB;yEm}@_V;z09~E^3WA{i_NMK;h9x4W-2Z;4 zsoA2cs*3Pen((U$VQcAq<81M*^yIVikGTbB)>eEsQ!yA@HlX%Q)v%7CU>Q_+#Utoi zpPt=PzPfn*YnI*}^j=}}W=?MId!`MMyJ%=mKjc=Po|&mDkXy4$Is2TZxaI5DNZCO8 znT3(We3Ke#CgWI@G$y3q-v0vJcYT<|n4_4vw)V)n#@OSkh=7>lv-J*fadA<{Z4-p7 zIs|-NvGv|@C+s*ndhCXHRK>dogP4w=xY19cqoX5Y)e)L3AMz4c)_-MHcRjak^XYTv z&PAFs$=|J0IjJWodblnikKVod0VDa<{(fV0$*RaB7a6e0`+}x7yIjCbzd-Q-qAYNqk^>kZC*o;6rJ24OQQ+wukO?R)tLk*x(b zy)hp?$cWm0v+9xpOsIRv<1lB|W%bVRjngylwbc+$Z|VCzmoHy_S76b0!_o0-T{zc1 zZEf$5mWA3YD=R!4XFL7Z=j?ybnJO{9|5|V6g`@jKt{G3d%x0m9e#|#lr5OAC`SUZn zo>m=uB@d6%(c(vszGzN}qsqO1|9&3XvM?NLJCE}3|KP#Zt^$ix>j!niW$ynztz1Ot zW@TsR8>;A(mX>}T`;%HzarfT6^%hb&`?HmWP8%4+jh3m#i#>X2+Av$S_tM95&!sfW zA69gG_S`kf9eJoK`91Jx`4bs`TBT^AyGV9nuVohkkG_?;kABJAizK;P6U-vvGEH&k z-P?)oqRuk+>IJy%bjpKFowzkmN4 zKvC@c(h{4Xvy!X&l`9+wfn`J%Ma0odt9i<_LMB=4Hys@}zU}N}^a%~6X%o#YUpyoq z!a9W9Js~b0OKXs=v!pd7ktt+aPeV)lzA5(jLCsXE<2F4MZ=0K`nV6U;Vni(7PgSfn zqdr9oTwb4V-jZtF{YqC~KlSk8g9i^b{4jXq6okvxYgKwJ{k2Asdvsa+&O4vn+@onK z@mK024l2cnY@I!4SD6&30D4d&Bh zw_be=80@+9_ZamK(S4zVCwJSH{h<#I4mK$FV0`=e)`SI#d931e9ZzEaWuyGpXy%o-?!vks%XBoVGHW!=)Lj=m6I(QC}bZ0dYzRJ87Ron^^@I2xufD8 zBs4{>6l7$&ZoW_m<4A4x4gGqHmyhoOR#5HPxjm9glRw>(M(er!ZR^e zdu)ypv7lvVXCLn>4D2ql{V_1`9;1R@zS#~u39#Y!krDX{uN8%J=Y)=(6m-KUbJ@|q zR|0gN$JR2U;Uaq`fg>fw;wP=kjMxB@d}}QhN;>bUq#fSrSorEys{6mmVd|O>#sUmm z!o4lG)AJdRetLG2S=|jK?YQW+pTB-6A$UQKM~Xnn^O-UfJ{pl$D)w7-=2~ zI{wWi!#?55(o}`*K65uz5>75IL67+xl8ZkNw25+^i!fgLJHagJ5mjB!&pYZlMhNw12hwJQ; z*Vab8u6kwN{n~zr60-^2QKPsEmpmU~1024;-=vwHn8ZuI2ka$i*2vICbr);xv9|JW zesOWO|J?>FE32PvX**e2St-Ul^6p&nUU@WCz7&k?p|CjXw&#fcXF7Q$C8c|!&(S|d z(3MiHI$!F2eX{bm+ZI8}pm6?EOWesjk00+%mJ2%99yX?kN_?lN=y*WVvV3lPZqwgj zADztXoD9pIPu?W)+N`dwx~{r&wmFRKAUk(#M_qlgcXE~)Lu1yko*4rjhwc5qK$G{r z+kgcqJ{%7CbRoChR@m7O)mp?u^Q()B@-siQn!`oX z>DT9N-rnB#s9EZ8cgUVNxTxKRf>ms?~FY;+F^Q z?iHkN3P_@1WnKMz)~&dtWME>#dYLLQO5)Ay*QFV)*W4tPVlK60n{g!>=f8MyI=S@) z+6C1Z2_DTQn**30joc@Wm9PB0xZm1wC;q9Sso6T}h&H)X;d;YVe}Cwb?dh#EGMIe{ z{61Pfe;Y%ter86AY+75;*Rel=jV!S=M^9zzWVTxt{)!eh|2(c+>XNtEEI#$z&dyHH z#$mXTQ9JWXMqXZCs;Q);WJYFYW=u>>hEa*5;up(8OBtCDCLxdF;Tq4A8RC+DoxS*im#l&|NeQ7$GO_pZ7xLpeb?udT&-+@YNVb9W!Qj5Yu)rWj( z2C4)YsD1%(v6dM%@+2PLyJ!8ZcawvKPdL|kNxRC32)eJims&`Qp7k-kfPV1x>(^@{ z``Vsw52QbG1r?N0?4Z|N({YrZ?S~H^#;DT-U_1Zak8OT+>9<2TnTP-kO#~RGr>Bi; zL)lXqyCRQXYOZ1PZbZ^--LYc`UGS-Dq9o%$hIZyxVb#`Ug(HTe^7PjW^s_Peo;tQq z*;!lL^sN;bn-&>$I?4I|4fT(Yl6z86QDH^D%EZ+8XAV=NxBWKhLFI*0uKb(U5+6<2 zA--ghJ0-!os=%$U9Y<+_V2691`!;6U8%u-%)Qftc(m;Oz)WoRGfH+cQ_)3fufV}D8) ze`RXr7(`>>NE`F`!^f(eux99<#Y>qHvqCwvSA8ifBjXIV7_*1U(BC|8aD#D0-`oQ6 z*TPQYx=G2&Z+N)5Ssm@{Mww}7rb9qG4CoF18$8+lz~tjTbL$PdWp2lSiA2gosoOSv zEU?fN*|!5@Ptt{4qtSbZu766|hT=bhX~Pu5pH)|Z|K06-HBc3(YO?k6xiLCDQ+p~s zDn=y`a)hVvvd;72lUxFud< z1SRDfo$L&SL?cTejr9GrQ+eZfIh6&aPeO#tfL{L+)RZKhz>eU_P8s{~Wm z?$|3@&(+oi$(>bG3r){AT3cNi?W>SN3sgRy!=G}K!K3GOYgNFW%F4<+fJZ`h12WvI z35|#%phUL{{1_y6L{TGEItzfv`2O{tk;aG_*B=uJhO}1Uq*6nt~$#rBb>~>XSH6- zkq~2#sNMVi*7ks;EadcI7sa$IEmJ%Gt*ujfcw9my?@HA*EN#W|?D^o$#^&ZVTi86_ z{uyh}kK6YeYbqlrXW##J9R>QhtcC_{<-HvnKBZoJ_44KWZ{HG*UH=-zy5?n=p_R@Y zxYRnh5LUIh%xG$4YHBUrDAyU8q~Gt*uMy0mOE}pD?SoIEGcu$s3cIWa*Cb}62mi&4 zX!`s`nf;u7@t;4FYLvjOol?u8c0Z~GuYKGP2!B5$WCU|}r({3Iz>|(YX$WoxKEYI) zh*C8$JRF&$xHUyNv(&avl8klOa7Iaw6MK&uU2V@X#Kb9bw#i9Liw=0qD>4^*kk2ym zkU@Okp@490>m0Y)!8*{=QL{Imm#|uPsom_fJ&{mTd!hv#@`rr?pdj!=hdmaC9&g;d z*~#9{ZUMBTadGhvw^r=G2hIF6XujxRxfxsho(XUfn4Vc6rRf%_HDgm#Ss*qBQ7he7 z+>Cko`Cv!#F>qbEa)lSj6e~+QOsX{|L(oKK{cmrjDl!3Uqqh$}zU1{3kTZhcP^|4G zTQ;L@_bcm?b{26brJ|K&Wts;pbnNci1`xmxRCh|+nGh~?{f%`|&)P=gw6!Omq7{PW zdYNBASn%27;PHSXqku&3Y~CTQ9jvn`7``7IVCh(Eaq{@>y^qatNLq4i4wrt4|hn zNyy8}ww8OkV;ZEoOS#8h0+IeRKXM2>E*I`_Mzi`S&qL46F~7|!j;zCr$;63 zE>xA|suz5MLWCSjkz!1Kbg>eP?<^umGEPdWKgtwVcroap+}QTH;sqGD~A zL(OkajX6G2)Q(iACKsO?&@qaba#!5EaU=7(QVtFd-GXaj#g%n)q}!Sdc)acFTYFyo zV;2!4YE@@FXQ`fJP4-cJu+(U_P3jFrX#=1t3W9| zO9e1A3plV^1Zo2^nLkHm80e*(t`OJPBco&7ah2nEe5*bq3JM{v^NQ%p#mnKQWOcE#Y8+9 zt*B*x5xEH@Y}%4=ih?&l$Pg5wwB>($#GY{eR)(vWZ$|srS|;zg>-~R0+5K!y-g2?X zrpj0V1eF20Zb!+@!>8PS8{_W@37Xtm@M-MNnk+4eE$RCsI%*HiDSo@HBx20V-5@0| zCznCSF|_0H?xK*v!K)5_k4?buk|*$7{C)ZFcqa;8#@m+2$jID83D?=s;vc*J+ZJ9* zgZvdY-XpZEXBxDMj(&jT<+f;HDg>zQx-Q)kljrn$zyvR}XT&^OZFd z*xBkT`CF~Pr9zJqNJh#~AD*tuZ>_xgGF>OrdW+Ki2M?@@Jr?Y}Ru{}MI!fbFEIMAW zBV2@>pNBk(iK)*ssp%-N*o~6lS-@C-#yA06E}7zg@4u_%fZHDN(?a%?z5PZQd`pp- z%bV{!eOy#jlntDW^#186hFJ)S3hHy4tl(6{#Q)IvGe2sGasYy&qeJ({FJ0q1?~HZr z(UW$YQEC3S>(8cNapeAu)T-xYpeU!TGAQCw8?RWvSMh>KHDQ&Yb#DM@M@y4i7bauueJaqA8CZ?{uCDse6aiknYM^zX=0RZ{A4#B32|uubm2Fu6MY ziMvH^=fjpqZ|gx}(fJ1iSZ48_6W7-6mXnjS1XJGtx?Y^w7)d?9PQr&5Tk0ttn@#z&Z3yW_T%!WlGX1Ud@#}L@o;fzABSMZ#{K!r zIy_6@!2k^^UP?Om!DAU2a)$$GcgSoI3@Hs>zg}Cr3~ieKqQ3s-#l^+yil6_WWgt#o z%7>4n{T3)bwKVXQEpfUt1Mxn?GtO-cQA)Ra7nC9Y6Ev}*$Oyyckbey!B`{O{ z=(er!%;>=7D`RcT>p%$1ul(y%R$P60*6(L`(NPKnqEg(6FpyG&O+bJAqg6xh^+Us% zaPt}IiOzgK?6WZVbkI@?3JUvAo{R>yk=kv85McaUhTSBL7@maj>oLpE_kmF~K`T>@ z@$r2s9|j{mT=wtVhW(IoQc^g9wKt#6)-NQOlCYN(}+|1wb2k^4`(3g_*ER1zhXG1stO zG&^^Wk^;BxJ?@0z=_#5O6{FBbCZ<@bF*X)!6D%Llv<@}Br_B8^rcPRV zdN~=Hjo`B(x}>>7z6pzpQn0rd0-==Zt*N1bp_0H~U0q${%a@4&rM#xEr+3-hTpm68 z(<#I|fgPY&pJCS`4rM3QRr29TYOMy|irAGE78pFe~u>e3D|xs9WQ;hUR7Hg4^e|fEw=ly zxjpyN2r?d`BMsI}OG_)5nFqiB`Lh=7?%j#SRN~^|^^r%;FU$_58x#v^XX+4XLMvPU z5iQrbC%or^KOFLPaoe_STTi)XY{lAYEM|__1SW6Cz6x))JMTi1YaoMzr3s6O_}yb_ zA+j%E?@^n@R-?QtvdkSFusAZ1Kijx#PgzZdiczonyHIzW*_!Tli9<5lG zzHvhUw0Gl632p6d)YQ#i^D?zFt3jiZLXXfy$ekiA;Fc|Zj@>JN+Ak5ri^0HLcQ0g< z*LFVyf{z$}#O~NnbRBC>lxjh+k^vA;k0Fb@!4tfT(yN^JV=ra)PM}` z*b+#0Fg!=6bKdr;^j$TGK9`r{O&d?szGc5B1*!k0voSh;yCJf ztQ_3}x58%_G@X3x16p!w%%J>~(VjzETZ81#dlW7RTQ7$tgojH5C8rj4;*yB=-HePD z8S9RJz0JfH9dAN`C{sjor5lxr<(AG;;=|I=^$>@{)$&JXc@-0?whKb0v4k>flkxx) zluEpqELb#QE8DD_fB*dP%!r|sRsRY0dB;8xW5AKPlMX~WN$EE0ExB2`wz|YD;S!2q zij7%ML{qFm8`j(0#m`j}V8yMB6-*9U@u7yt&;x5<7)A@3KG%45uEZ}n`2ZHYu3%eZ zzJSs11bG7kW>R-iCwgAn9q9dmOT~#h2LtaAHJc)U?w~Y=2F%OU`q}jHD*rm1=A`fc z#-M!C{V$(+bKG}K9|mP^j|fd(VvRh0uJ&|2rXNxvKxt?^mEMHkkOwTse9@RFLO4iN0(!%nv zHkQ+s{-_Md0UxL-oxui^tO%hxVjTD?*) zb+Lc?8Znl3pJZ0Rf_f?F<%tf7=Cm4v4ea8fbc0d zP!e;19t5zqH_o<@E1{om0cfORlZ?X$310cIb-(qs5`-TFmATJ#!lCSTSUj`Io?f+ewAy*1;4A?YcJ4$O0kX-nNabKO-#-vN_r{@ z?qCt4+qrWm<(@+y5bU$cOC8_~SC{8hAw^Bk%?Sr7TmiWa>;hn$40Z>bTk*N922ZU- zVoE!c9uM&zsX#}EF`Y*#1ca-@{Pbl|xz|2ESx43b?a==6?oHtt83v^;Vc^pTe*CBe zv#mVhAghk36#et-OEP#e(#b)4owv3SMLb1KUOUq@!VK}JGvAz~Dv4{bT;n~(4?*`P zwO%9D5fWpn;zRDwIffS{M?7R!H3rgw6wZS|`lUHx!pyCb*7l4^h`Jxw1;gQo9mH6o zf_mT|7?_N~DoZ!-HhAP9Q1QYRpE%wAjz?Q8Kq$w*H9;&WwcCO?!UN=Ciz)Z=KL8r{ zUY^;4j0es2z}I&pS!i6&qCJNN0uuZ!f78F2*l21$0^OAd6&%Z`bgU5@Osp6XG|5bF zac`OqZSo}C5-^K==Vg?&QvqmtM6VgQd6UWU}6eVaTy>lb%@{! zcov`*(HuX1oV3Jh-tDh|9UYeE?EvELK{!GwJeHjam_;}oqBD_vcp$X&;A|U|=?X`l z+Q*YS0!Pv$Yv??%s~q_sx{U>1c&)e*F&xORy_D3hY=M>wWQn#8+wm@Jpxu+ z@!YwAJ3A#$r?s^{JHHneoXZ*3Dhdk5AWjHT2qsq2E@Ngd7xEle$}?@CZ>v23+Pn16 z*NX+#-Sp7(dRS&;x&Z%HSI7G*5+QEW?A^P?=i$TMkP*@__-Zg6nSJ!}qZ&rUN)&RW zg2<8Fi$(lcns>du@c^9lA!mhA_)tjZkVC+QG_U4mQw=v~ zPk2Aa+0w!xUN_gKprq8ew=f?7jPM!=n;5xT7ieIxdoYoUcXf3&?xHsUT4z3S!v|q& zzxdl?f3~6$_>G@^6>H~vhcySSGcuCe$MlM9SRf0gax(%lrQ%8PY@(N(1NfgyOG|fD zcuS!V{(ua7TE8M5f=z3hDjP_kgr%?pb@?=|Q97C0>$J34_F=I3F&8m2#eKk4T}H5idwRLvOa2oc5*oG#NMXtt=MRY8M^d z#uR0~FJqkIdUPa%FrX5n4?|7y;m3ffc9RRx3E(5^!73WT!Y^h zak!eaUzmYv9P3U@HfUi_TCe@=DHevT67j0>=q;$(UW=nVPLn_DclH@fkO{u`s!_>;9#+bd0u{7hoZ}w_ylkU})s$ALHI&-&bKM6P8Gv^Z? zhKCb9y91H5FX$eoo*4j$bKM{Q+ax^I3yhvx+RspHJQhdOMpF~_4(MTK5w+>51)jx_ z_yl1LnfX}di-dt8hnWG{)up~Q@DO{z2oU}YdF;Vn`0=R2?DDM2DQ;gz0_$Ol@xf;G z_xHbr48$Pe@`AH@Ar4jz+`Spl6l(knlnBY?>9gq9CX*j!B%J{V(5+!9VTF$D0lpN; zdXCn7UCNF#uhG@e`Q$L!0oql8=f_ez_~|@RoaOtlog|CTx(x)J15}!0=RfCO>g&1e z&pi0+m*wIcBXk~6aD5_qK{Tpkm_$qeeRIbo{tE^+bmKw(N40O?zrP(Kxp*JprU4)V zLWPiYBhB%`&et|YV(&^R&YU>|ToF}UtAPIU0Z(=HLI3&;SVj2sUizW{(;{6$+0QEd zn4}Cd+(ON4Jl+3}pj#lc{?SoIG?Ye`$l6L!?ugnHtT$*dA#m_$5{)c6w>Yt3#e4z+ zA02l=2|J99bpKwKR2BHF^;(pqrx+^DF|LmxDj|F_I$GL9o>2mokLbq8Rs)7C<(1ym zK&&r}nP!N4n4$zOzu%~nYt*zof#LPrhlgL&6#qm~MMU0MTlGY*t20mZv z-D#fK3L6W4?gx-X+K96*N65uDPDjumkNj`(Qqps=cK-W7I&Xk9{DXS0Z?HqjBdR8f zP_%f~dfA)->A`SJfkb?Px#e2-t0QpdMSNJ`O2$LL9E4i?9R!5O-%fKf^@{U_$+Lj% zCXfW)8~Ao^I6EJAR^VWBaCRo*I7V#&?^VJgU7ZZ2q$&>I9(EpCFL(Mhg?5J4W#B#y z_ut_fba$b`5tkjjzk08%qKnVcx_(6dk~GT55HhKz8dc)6_k{%wMF?^`Oc25l-HdU~ zjieB60(oYPX%!_-2xd#5<3^TnfdgRmhnwRA(VK}i3;<`CT5*sa-Vfv7KU?9Z5&{B6 z#kHLbm033nEnOI{0xgoE!xl!VrVO!t_ zyn}x~$vD*KF}Gv$op(L#{t{Pa2C6X75wiZ9_nN1J-vP=e>o#mA|0eu5bYbw{|1d&u z_`%T=`u6QJ(+?gK>3JWge)Bm1Z2Lloj!>Kmk8FlAL2qIPP338mw%)tFXM)Ad!yIenlukuF+ zg2_)~X*qmuZte%zFs&@zF!Y*eapoCXv{@-sqd|Nd!%I)k_rZ&#Qs04{b?000snP?L zpZt};1pxVPN@?QYF)~61ZF+(s2fG$?a^H;5i-Lj_6o@LUDH=RYCz%U}8aQjURrK*Lty1ESL$UFot_w^;BvS_@#T4xZTb=3?>ORQxDmR|y( zo)TXyW|@eI6;BTjifgEmHg}^&TK2&1#s#Jm4#()os;a8im!{{5kO@brQUlnWkhC-& z;Arph`j(X2gOkj1M?rUEiSFofBq;xeqCKv_5J(z zGiVM`*f%hYjfql;Sk!z>4MYg8!v7~w6B-$5I)JrpXiZiViP7VZ_n^}&mb8QEA)N<% z(u(<*xVnvv_aDBHa}_A2qqFl_w-MYbSE?u}x?WjtPbnN-B3yAdcr{`TZMzOu!3+XA ztf0>^Fql+75G+)!0M@`ak}!{faQy8*BNYPor1~*D{PzP}NOgrfMzKpW&rg37zd+_zl;iO5@GJYGYg<}&!ikrd zc&TJ?0b{fXTA;k&Y&Yyx$g`_xxvGyOK;}h4CX6;3shLy5sOdAF=q=-hf-tl3xb3&A zD3g3frBMJO6??W{g^k{w6)dg?gIM@ zIsR0`dTu#gWYgP$lOpJ>Oa3GRDWpLIT0i!Y+XZz5(4QM%4NoAhrdl zt&%rfa@7?}KfFRKt{q)8_&zz=3{s7-5ztXi>j!yY5I^BC{9tqq(hHzXbude;$<(n! zhbZCxr{~js3r!aam=Np)jd`;{v%g$_w#L}c{6>9SsB6bH$`aFjQ1{G>C&4wT_DF%_ z2m6+fwA??jF{N#kkO{kX?V^Y{r2WfPy3r2Fl?+DiKMx{+2-GbY#9cu$V3F_N-wJIs z{bEs$MIte>VbRU5uVpdV)&%3|2$q6HUS1xQT@CnJVlg}*_dua&g)G*I8&5_HGco|* z60t3pZEX`r1;LABaH(_b#in&)zycb9$g#@@odA3tC1IK|iU9c4w6ugkZ`+M=0S=LL zkg_Eyr-~RVc>YcG9Y2DpJo7^Cz|c??9`l(FZ(=}D5Ya>d2mMg3V7*ky)XBcqRd5h0 z3I)pVhN}y`qJDclb9gW0Fr%`<1sNS~e(BOB$(7%lsY=neD=MTWCnwMI zwaSXV1PVCSboq^if|tZj#;Jj-4<824Eo{PpEsj1lx+?l>s}iORwikyZ;ElWSqk0EL z+mWJDojK4^m(i)~fdx^FHxO}s^wV8c$%Tz?KcD%8##^9@wDAuPt~M5suv^O_S}Njw z?#qQstuP@W4&}i$kiLdL9p!%;ElAzJ_Ijfsiil0GSpQnl`G*f5x{ky#Szs95@So@>~31x>Dk%$4Go8T?SCwA<*bULI2nsaz=vj zU3~Qb*qM}h1ZdSrqPLBH1=#@M0D#RGI5C1B#oJuTKZy@UJx!iF<1qiV*rO+9NuXa%Y zU&5ubDsZ!411c&Tw&>hriJdHBpCbmL-YhjHoa!#%=jFW*l$;M|%l_=Sp1qem-l2n8 zfIvz$B^Gm}x#^Nan6!dk(lC&rX!eCD(;gp>f0`9tqKWZzo&A zka<|=#3w@5l9?Rj1tB#xYd&E1Al-xhs1a2PS2nsfqovIeKE4h>5|h5}IiaruogEzl zH-BlRs>I{$Cd8VU7;6Ucr;>Fb0TO-%*Yv-;1DoH`f_#0We+ACZAVtn~Q0L3x;Kx(+ z@l-RWYKKaQyvjHif;pqMa8B0i#09A8#ugU-M!CQnH4&W0A~L=gSU-%4szqsU<7x?sgjQss$+#AY$i~7_ z6n_&eA^UOPiePAzBgbE#{ee(T-7*WYeng*QWlb2Ou{rr2V(Yta-z2+*!+YV}g_h-5 zsddcalP|F59tgK^RPgF#G3@0xAnXSPYSOKCBlja0m&}hnyn=@U6D16a@jIBBWWX^X zVjoyeW`RRf$C&4Bfu!M=3~!NKdVrsP|Mlw}{8U0#<`x#w-<=Mo+wF}Qdi;b%FB}3%Qtec7$3fTc|XmYUYqFvuoh z;o-M+GB>UET_qm4RF%MJ+`8ZjFHuJ^79h?-VJbo1GQtYl6uVZjryraTnd6Dq;^hN) zv#&0&&UU-jcJv4w&(+=(trX57Lr>%?oPmVVX_wzlHZx4XusRDhhz3+&yj~rA=j0I% zj@waD3`ow1$&D+V0Lj%j5CMn+urrS$HV-J$YFUU~hp!VfIF8osfoifF{0KtV1+M-4 zLT??yS`%1-@!ZD7#sk({9LpsHIB5HqaWP_m$~Y|$WpmvNb2<)t^0(D#vZle%1MZ+7 zLruwRsb63?;lF3Eq|pYcI!fEsb7eV!!M)!+70}oN-rZ$Pyg)Hz#Ffa)el4&Qv>u`8 zKq-+^K`75&;|uTMl~Gt?9WGdQ%E9Ds4pyN9?y`F~d<(ipz<)(qrmr|+Tl6iCnD*f3lfyu7V#P8XdH9#0rV!aU0X5$E5`PaI@?C3QZz z)QweWmEpM8&Z@RB1iat)!~`VJr+|pS(i?%5%I62Rqm$%oJNy_Qr+N$R(}Anpb#Ay7 zXdVhb!%6$Aum0t~dS!;v7I(@$61?{;yxPXr)=emSm%Gg7r@w3E8pZP)mI&Zr6igjg zN<3rYSAXHC9J*xNDKHOh*EN^ zpt}gCy_#p|;mP5^9-VDEhtrqnr&sV<ez&wF9U1$eT(9? z%M+Ct5k+epIxGP^R9d6Pcy|G*lw(<_|E03>tYL*$*&>o86GHqi&=jA6LSgXDfJ~-U zR$BTQX6o~QW@j~)evc*ttE%kSwoTpB(~}(D%|t2Ez?r`*hujg^#D(9LqPV*dUFsJO z``Q29P$vWYq>cM$mGW9Hu1B}Nup4#=%S3Rl={Q2of=S1L<<0)u=3;i?7WZ<95?bJ9 z$gTY$-q~S$nPzc7_>3=>UphKEcx>JP?07h{f}xBg-vhOf2`!+-Kt;tMcJ8pn9N&kt z)d}4#^;K1yFf8z2Dp%6g?QnQ}fecIm=%66oh`8PpSdKR}-^7o3flhZJxu36$K zhh~S>^C)^V)6@ImgaqBQ?&J{#GzeorUu1h*$<6D;miNlGuNlHM=sUfHIvVi6YMEc2 zfBCh3XO7!$^eEykLzvh9vA%Rc@o<`842$WW>8 zEY3;$V_$c(vNi+trH*>d{b!fyczW z4To8o{mrdUJ;<@UZQHk3q7z)WaKX^;z|TDwT49*mfakKR68%92T|<+y~!m`uDrDLqOTk z4k*D-k zXgyV!#CGXjt?ljR;FCab+K+b#LR;gkZ+|3gSr`LwWCzt3wu1#65|nY?@%=6#w7{m2 z6H>5vp+cSYn4vfF=TrnDj>mb|hrlEFIfy`?oXSI*AM^}p0@R?r>w)8kse(+wplAX% zmc$|P2&oTQ2dJ|S)#tfUSxHVM?YR?orQZR->b<GJP3RpOk%cuUT4t4HR9l8_DP0H$rim0rAjc?C@dT-PPekEU_@*#zPcZU$#b0K@#s z%F4(Gg^?Kyge#OVL=o{X;QWGo`{iw19hjlXVMB|uO-Jb8{h%yZ-fxLIS=86aa~ltf|-6XNHW=Z2fmHGYbT zJf-^B*7gGvn;FV3o`R$dK89$H_(t1Jm)q1tmcqD0_6R?{3r8V_iPTFKURTuY1)o0| zquBVgR8U0ZDuj4~kkOqIFsa)i2=OTFzt$q9$>|RuAnePQ0|yR(NNkd4^Gq3g;VV>& zv*e&E?ZKj=iUh(l0ZscE)My;yJXatZNnWNwj&5Qll5{fj3JXo~1_@9VvYbs-3V7%z z2jFwxh115ypeu-%3m^&POf!O)96Zmd+-)>~c;>rQ&J4IlLFQxP>OjwPWR6ygL^+#* z!1)Pu9buRt8iGa`K$H-^1E3>N@~^4dwQIb1;9)RMS4~ZE=(!3=gxJ;49!jWldv?|3 z@Bc}sNFMWa@Ck;6!XQQjDg0t7dL0l_BR&Ck#0-NHr3 zv|+;r$<=ui#Cl_af03ovlqaB@nO-ZUe4N#E4e6z6Meu*@oOeS``> zS^`icf(UGeV!#@Mv4ef@_IzGT3Hdl-iun}C*qKRGbI1Gy8EL5b7E zIZ(GZSu)g4V+QRN6ljW*T&i2B7<}Hm5wEVU77JFRY2uXjPt!WY<@4mplXkBP z%U8P?7<6?n?}-Lbn?;VzqDF)!B#`0^eliIoM3Vg-YN8LLy1c-7B6LatQPEV4-&8DO z1)sgr86lqCx^)X-i$jCCV>cYnJ=0kC>_?9pO*kiv4j-_PCtYV#3^dEZreaLp1}}_Y zXyL|y2M-28*fXDUBeWRBNkc~{b1gpWHmDtX#5GwTIqW^6EE#+LaO*7JRxV<0Comiq z1yk5pmQm%&xo0qrtx(z^jrzyN#=gFK!56j{;?sdRFai(JX_f7L2qZ?4YijArF?V08 zK2>|7k*=1mg#r2d#6%E69RycDc83^?P-gmvhvjhnbeyj9KVM(JK{1@1p#f<4fm<~w zbJO;kjCcO_6ztjSH*YkP<#w>h9h3-}57~9DboT4)auys$@W(YmF)arBP605C-)qY= zk=Hu(=x4j`RurtQu!{jUfs2C9zkcxZ$Rthz<3Xz4zn892r>Ab6U6wM<9$Ij<=__x- z@a~VBgzzvsiwZ}e7s4qB1{_S1UoS_P;uI4zC>g?NlP?LcWnHfvP)p=v0dh4Q?&e7p zNj!eDf&N_LY=Xpfh42p`!^rVJoGj)!a9~3%J7{%0zyKc>{6b|12_=1 z1oSM>au`ku4Myz7@%d!L1IkNQV_~EJ;DUGk`PnRXMPjcVK{q0q4~DVcP@Il(6G*-% z=y@W5Mi3k@glG^3AWhVFqwj10uY#n5Ej^#Sp58p zB^Vae`F_m3gw!Y~5TStW_^ta?nLLsoBpknRcH`~PSm~$zK-WX~B5!;F%hnI-0858+ zka0a_CLjwah?yr#PneMVfDg|vRh0jH6%m581%1UvdIB~Boe8-wcb#~ih>ipaClK`O ziJFKj1R817!ma>zp$+mJ@sh!+iQ$(l85Y>?*XM&2(Gd>Xml99sdntR$?Q2( zS6jOuZv%kM1gCs!(Wm`GLLMg`7ZLdYV1l;$F~?B6v8m}ML-u|;DL||L@qL~R=bY@T zXu*vUK^cegzoWL|Z6CKG@7Lz$fhWO9MI0An!UtihAOT;juo)CCiFdFnz^dSf&tZbc zu&qCKkd6|+W$`tOkq9p6e}F=1p9}f7FYHF;jj$gc9ws9q7~b%Ngl5dXc2N1ZQG2{L5)mbuzJVuz}wL^$#QrDTtGULwYqDI_}hUYin!b#hEIdqb3gsW-lr_ zde7XhtyQw5tKVZ_Wc)rj=!?7yoqM;Jfk6Sn9U=pBHWT=#hZqW9darpc+{A?RP)Y=V zqv4`$*+-xH?iI~kbu2aAFD5oGPf$5Vhd2qGHMx})fDh^Udjs)RA3-n3M9x8kYE&?5!cVL(Kf!q$jSqUh$i;eB5RN8g4u=h|9kO8$v24lY3<5ecDiE1>C zwNT}9P~uEVs-H_*0rX$*YNrRauME%?|8MvXZ?hjm~#M9 zFjs6M>^s3%WRyiXW034IJj085;TF^e$Q6XeY?%Wz!*==N8S0KGfG-8%6&@P8zla_S z4wS&}T|2b;qM^P%T&lyqNQsGo!T9P`&Z4X6#U__8-zqLXiIBA49$Hv<3=y<@<>98M zbZrIW^g4yqkIuH{=4ohKLwc+r$`BmS<=-J{74w^+GjUCvcKpI*+z4Uu_)3nV_iXFnWxBo$y;o21Lk%=-$}o z29~bzc%MflUV@>X`6cDqGrYSo+T{7D$sgaMB4QL z=29M|eV#QfC8H8eEf!8?R<_V_WeP~fZ(2I+Sgc_B6VeLcd?e#YoHG74jLvPQb& zu5w)D3EIZ@v9ZHakd}7!{_(xSrJr#3%3fMpX&mwZ0E89cF3fQhCwq^`1vA(AZrcqt zy~^Q|_up|nyu1s?sihOty8#kRVf2D8C`}>c%*Skev;+JkhJNancnjk%F<)AF4@U1( zmpo=R0nZ)z>WTMYz+p7OZ&myJ)VvTCyiVxrU~TDr(7&$lpjyWK8jV+2 zeO&|*4nN%)FXDX0J46DIg&^X?-?+e~^9iaD8t_FbdG?o-N)Up?M(7`T8iITUBf$B0`NhiXw#1Tz$G9bub7*sJ))D9l@$ab48V2d=ypoV z0kkc=J!~uLtJlKNULqKADw4SyE<2*)88Y8{vZ00g#2(6KRP6F!nh8U!4(xP2SZ?^D ziAYmbKD8Wfj(&)?abY}f>(E05EUz<$G^g6fqP%+> z_K*4y*rbm1{rmH$$(eQ!D5}MOQ>wVkx&ou4Ti?gxh7SPwjnOkPo&R6uoq06Z+yC!B z&GW33CKVCQlrog&C=wwuG*U#R6e5~VM``**N}+)iNs~mOQ&CaKSZG9&BZWd4?qi?x zy=&cj|GB@r?z(^7v%cTe8TbtQz4vQ)4zGOms9{f^9t5mILf`Pl@9<&QrZasHrX8{j-WsE} z_UW*Z%y<$!coub)WkXxd?_e-#*M~Y(Z7} z=i$SOii+V2e@5#?c00to@$$=}%z9uA2Bo;nxI@o(g@tm!t+R_ljXb+bwTI8#WrZH_ zxG3s6&z?@<|A0LsghZ5tE@gX&$I09Nm}+1gx#2@B#3OQ^Q)kYU7in&Ea5zYQFpIj$ zWZV26E_U5tc%{G53})(0UQqBoQ>{spj$>J(u86gKI3;tz+_{_4JZV2UZ=?)Xr74UL z0HlD+YwYb01P2c#Z_KONDf_koA2D>&d%!!@a$|1!-VscPam$HA4p= zCfkVSC53t(xc!UrN9mmNMo+DmsE-Sj1FWWy--5`2$~={i6~Ci;7}DAINMj`f2M!c6 zRdiUwrcQYJOuB!+u>Gv8{{McVwgmDre)8;0?-0N<2rK281W?f+i%x(yzr=4*C|67@ z%)UaEE08D3s%PocWp{TqYx2wl`G@HBKdlQxLu@B%Xb4JH2+z<%5W=>(wdZtq`u9DJ zcqFL>1+oOm79?TrMxh`Pz|N^JU-khCe)-E{A4Ov6JGIj8o9{#2(qn-0enTr>QdxP3 z959pNugKWL$Sg>7uxz;wT`-~Z?4`Z`+0tEbCOpAXCOSx(qT_)DS1nK<$x^RwKt}{K zrRjIGDZ8K`f|6W_;J_?IJ%Ch@WqUwB{IADrdBV0aqEUc_6nzi9NTuesS-rdZ{BN$ya$HAp_9rju)Yim?G=Sgkr?2K$JRbVdn%h3>LQgGK3HVs8+&TR0zpt!7yadidp8kw{A-RlO_dh0-+$i%UPx^F?5$!T^ z5bEBizzhP0pyUvOHL$n)iHYu&(Q%*O+|%H<9)UO%jOe!Ko7~)*rh{bcH8gKFw&#u1 z0hD{lbltCG)Ma9)=l#3xKdqqmsdYxa-z&YgefxKvcR@i#M2|GJ`sx2p@&ezPkg(Rj4<{YF^?u=nBud=`R6+&b zh?sRb$Tq3#Ju^MS|H11_d+#%smzK+}CkIVAH!91L&(>ZpEFz+yjf_;GY-dH)^jq63 z+MaCGi7-+wE#N;a(hskhvDri#Hu!<bAOocG@pC>gyl$oXNAI78K(B7Y67LjAbwX z-qhVzq8yNxynBsQVQ4hdOkY#ihV_59X}vD=1* z04_T@HR22r({e>p#oBh@>|7u}u}ytdd+jlL81TEa5y!vU5(9&(Zk`nDSvEuilLZz) z7_`*ORQj{}H1FlHb{{8CoTzN{Zt9EY=E!c!$;sg1E{v}OP_b+~u7B5*I{f0x!j0X# zz6uTrX<2|uI$L$vP5I6#pD92@eKQyoj%_U91b`eOQ4k4sM@P-Ug9b&@GkZfi=D}olRlcL!VV2t!@;-~0 z>fQR=R>G-6TP=s{LG#FBWj!#K$Jmy|{)ZQ%@SDtZK7sb){eK)dc9!z)v=ud10U(1F z^@7MvXWOv7*W(q$gO!5xfkt}hfy)NxjhN6Z%ChF)^)#h}3CqF&N4={WnfGNCDdv&C ze)#a~)0CAzD<9kR#Bo;dg9p$a!WoUmy+!^7l>duLHU{{;?{k_$x-=o{MyB*!d~OCK zydb0Ufd_8ts7Q*we?%WYkUM#=kYz;wa!2t6kGg;TeZ$x8zV4^D1M*&`8# zZ)#0plof*xsq@9KNiiz=a<6fn73ZE_5>iCC2w+!?n%Mn4jG3LNPPMew;1n);|JDe* z^gt|F!X`}u*;st{cveBSGEyS_oq+)WRkAj zjvYH7f&6EKSbP4+GZzpdOzTNRIsz^fsy({Qu*z@k&ll(9xJu^f@uF+ju5I7$5t~nF zvuT$ezjzUytCSHxXy8B~T><6`u{||F*OklX&rj{&sZ%F=>nBQ`*I84siBHKErs{^L z9B_PEw@uISE|NsVcv{K>F-claZ?)fD`OlUX1|j|R!(BoY^kzsEUPFR(V2uU-9Afiq zS}A|ces>AJmR{*Gp#*t_yq+|g34Eqkmf5!Z=n*O}v)j+FJH3NG(?Uf0rV1|sQhw>W z{NdKMc6Jafu0!YVPOQz)YN8kxDG1+``1$$s|A3*|=Muekt#tpwaN|LQ5rYRBtWpzG zhlHwElwua<(Pp*G66`bZ@*AB7x_jZ=nKxh!#fNpmwh<#oURZc%le2S%n7WIW(FXuZ zs_?>GC19|ris|bO&a(UZ>PDNXG2OduyLLC?;_PYM6+P0*gwyJ_de!9byvi7($=l)L zDJg!Y{np<4sXKLoS6M-#n7r{XNRZ?*=P~una-;$0Q%!P-k;~&<6se|&FhV+M{G)?z z@3f%FdF5P65YJ$PkHdA3@(VZFjq^}#gxqVPmv*Zu?ZPpwxk+nsg3t)oI}kGTeiNqF zl_;#mzzGu8IX5P)NvmBrR+wS|J66#XHC`+E{P~pqY0K!0xU#0!mg-jKx#@+JA+fqZ zTXB%a2Yjb_kP*)D_-Zian_ag__Q>DQBC?@fxyZJs54tp0DMQi=K>x%xon1|Lbz=^r z_NMqFwKWHHyvB=lMaGKd=uCAj-$a;ZN%fMiZxhpz0WpgGME>+T$N+HOo<5+zCiFg% zVcKpF=qg|#a<5vLIEr=|OGIr=3E@FZT*jowEW1pN5E4;Y(W?srI9d(w>o;V2U$o33 zM)1+L4LvFEzi8bUcQfqvF|g}8LPbhrX}f&hC~fVtXnAk#sJ3C}i0PUL<4R%v#1wE( z6yL(w&3AT4bcPWeGTkLiw@n9PKMq0q&Cv4cv6hFA9_@u^H?y`FSOx}N%$*Txj&xI% z{?s%zzB*H<4p_7(T{cw|8!)J8oFI3)xTEBZ(A{1BblJY=+k6qnPzzqaetjjYmf3vM zO71YtDjoKx-&P1WYR8_zV}>FGJII%Kwb2Rj@z3hXDAT-K?rWd0!GQNFeyh^4oW4D$ z2kci*mygJ^nzLldQ7SJ-r-H03f&Qmea`wN$AEq58wlzSmyJ6h9g3%qt_wm7_aABR| zo&we~<@xi!-IE6dM^V_rVXQ*HB{+1Rv~S-(_nd3DZnV3ZN;P05ugGvt7=p zk(oH+%X9>^jcM@h!aOSU?4dJ)X$!8i#9*nh4l}(ufZ`B#I1&Xsj?#bruD?HjehPup zm_5cF##NBupt=uJQ%7gk($fgqAN?J%dYfbU|~zd@d2TuSea z22XNos*`2NfK2IH%I~W-iI%&HsbjS(nYC$?#1LF}Apm&*d)M^PiIY$Zm)CasxTg}h zj&?4VxA_1_dpk%-qW6g{%OaO`p@obMh9rDy{tN7;w5lxWmux?i>knt4w4$ir0;U7O z*x>;}(G-k+jPg83xev2C(WP`DVwE{y;FLFOn;O1bcJa_N1p-N8ULrB)37=Pt$(uN7 z5^-&h(KUaNoN(jUi=?;PuSEZO5X3jJZVH&dI=}>Ed~5~_E$cU4Q~@=0zPqf0 zcB{}HPp~dvro)Iie@t|*Su5!MXw4fOHAV}!o+rz7aCW^8#V=med&OUYFbBhWcJ6$) zIq1O1&SixJ4n)<67JUg;Uo_9k%4xezWYctXxn_e3e0}g<3L=)kf5q;tJHNf(Z5DUH zzHCM-@P^PT*3z2^krVjUps5=fk2!#rNhroe4w{GwhTN)Tu5GL=1KeP2_zEm8ov=kW z_3=@!nWYG@#UvGR=4z7Er`)c+MRtL_{ew;%sI$G`$2PvbKgiM15v-1RX^h7UrG@}H zcnIhz0C%v2@R5C*iSN@r8z$103L2h?w3O{#X2%;3klOE8(5sZ30F>|VHhMJlHF}}2 z*s;KRaDX4m$`mK0$5b8%{`(egyZFaJW0X;lSSnTYX~Jr*zJuEIToG3O;>-f-{rsEavIkrlCg&eU zwKftR_JMH`-K*fn-}UO+RkJy5aG!lHfAesmV9?eYf9iLV4#}7?-Q_ceBcA-hY_b-= zVLCzZ$Vsg&J4GVlJwzh3-PNc_0XBw&NSTlp^S!RFy^EaUk>N8l*i$0CvMQHYWg*OP z{QF5Qdv)U4r@et(2C?a(G(^CG$6AWg7A~&>1t|$x;L-#(I)V+1{}97}z}_H1d&|jL zsI${>HU9+S!dBG-!~Equ{YA`!aV7CT*teXgoAN`jef5LmIDP!KZ()R#z}> zx>5y!1^O7joH@WH=~Vg8n=>*o8?B_gv>f+WW*Vf`>7%@JBe^LM(1cgQugZt#LaE*fv2)8vyRydtGYhvIPlD6*< z=`-Vs<^#D4T{rRK6EM6>9N2*@FRfJHd{V)eT2s3`2k)Yco35MQH%hK&&uU?=)9Orn z&r;UYcdfZ|a@@+R$ZU(mReE%J{~ zdGdtvSzhTo7Ny1v!%N0j@Kb&s9JurgB|Z`fg(*{FBQ9QCbC?yrtWkJQ-oGzq#0#XR z7#$1Z$3#>D)UavoKIkVD+g>G&PQ((Xs?XDe={UQ|+uq>N^*?~DZIjL-up-L=MokA> zIT<<=$pm43ig3^a0*SOp1zY;s8G;E^01K*DU_p~HWq9j7&2BefS! z)X@nRgLS}!VXe_2J8f^>hudvue*SL{&k5@Au(*M&cb)dgmzqYNu-B7XwGn6DCMqfN(qbz(OEtUa zqWAbjSg;(IdHVEeF(qKr*=fVkmlD;pVDYsxbs(_7XOdt3wB3(SMbHVFuKKVz_u6V5 zbSj7Q5Lp?EBT^j!(rn(G6?v(4GDVJVhHPP zmv`n=`Sqp4jGB?V-$30ZAE9c2CSF8q(gjtGev5V4rTBz6(!09_F-f>@g%apnvaxI2 zrg!-c9lmCVccT&5Rk5Wft{Z|gBWE6YR=z{q6)Zf6JRpa0M}2+A zP4ip-SuKbqV}BkM6a)fHF$XAfvZ?dZ-Up4Z7>2Ylf9h>yJIk7YiCsSn!ox1(>=Wwg5;`&aCo)Vw+EXDY2bJXzNvXDhW*FermFbI&w_P~C!Pct9AY?@O z4rNHS;;d~2*}3b15-x$WiQ+AM+$NZtw#r6*&5eO!Zm||E4JExWwp?%xaHa_q20?1# z94J>F{gK$%ShIF}=I?q_7_yGuB=D-L3YuZi>8kili1jm2jvHbZ&M|BPK@bB=o-??c zoldQjGiT-rWWquY=1k&2o(o&kl)hRp|L~hQ?Q~vb2<= zy_VLSLjXrh-BV`e%pRdV9KY#Z0R?4j1So3QnRhWxx zLh+BYwNbU6U;{xKn+$2N2q2d2k^mws$ccpebx<;*O%?;0#aKkqDzi{G5HY&FipY-1{1#u4GD945aP@HCxJ{AbEd_a2@w+9Wz5a{+@?(mRh72 zy0Q}!id1B}HqKcCkK}GsQd(Mjf;Sl#W-#dxwI zS{SgO9(g>-%HD6?o7}_ zcQ(a(nelGp@99v59#!>G##j8`|4H<*?p@=>t%Pbej@Kb zB*>vpib2lIpRWrm_ncD=s=sh8={X+Z#Y(^Xx3^XaF1XU7BzJk};K5O~C(9v3phoHo z6|Wy$ac$TBC4kZgcig@pfB!tEJ1M_X)EGa%zWJT~gYwXwzNyT4aL{Dw@LdffNQVUP z#4XPj&Qk6kG-#8U#7GBzT)`J|Grnj(e#YH*wlYV5sneX^T`%8O%3R`8NU@XmWw3d% z&_v|Jiw7q(IULP0o@R~DU*y2glb6j>R?}agR#9u+cAKS3Ik^*G&S|8v>AoTu z)>Q2cXMve3gKK6K5iVtDVJAzlruuabKmxg9)o!Bk! zzY0tXo+BGg^)i(_)gS#`U0sDjlH;c4Tzq$AsInp=ANn@b2M<|BJl1^yjE|`r%XFae zV8(;3a*;liD_tDgKok++8 zHh!VUOl1(PnIK50=nY!{kP^lM z*SP3O#b7x8)hc>QF&=@HZ7bSgNX>4`zFtv=H|D%_ki??Jg)etmgXEv7v$e5LMhk3^ zV29UHXwC#nFk-=F?45oj12h3Dfq_@eV}^m9sAe}0I4N9!sMA`T-?cvL5{VTBi@4^I zu@P1kd`s7%se{F~L7v5Qy59liTGzRzlDbmVmd7K?2SBsxyT%>H=yAZuoVtillXB-B zjod^qWEwbeI}hNPaO6@UeSq6y6xs45&*_ZLU4>Fy+#ckExOu<|zX`%&L1KB(LMf+g z{bW?!y0OJQ8m=03YJikMY+1k=`yx$UH=u)IWm^H@sKY++-1LR9KIWP>= zU?HI*AUiv|#(D?un=O<%PXr+cZtf4JH}=L1RlFW9TeqIz--InwDXREYZEn?~V-wtz zvHzy%BwaRdJ_ctsYX5-)vW+buP2=M4-d)IWqGQ5rS+1?YT%Zlu?TnW#^OqSsSQX&O z>=$dJp!e%tqaE!E&rIqMr>Q4Z5Y8iGDvfZkS^ja1rlzHMc~p001?zv3NJenR4d~dU z{-;lmp^Vgn6r6wyYxyZYTR3T3cG$c7?zLew;(EAU{n@+W@OX>Z5Xb2;qFuX_0^L{d zeA!|&+1q16v7mxB40ps)S~-nFgSCJj_)4&!j7!z(r2p-Zc$Y-(8JU!&(@v!8?V@HVmt zy(`P~sSr-&I=CLMo`B}Z@|NA|_J$>>h9+9CmtTlKO z0pxsaB9@^m@E_S|_rwpQN?HUfU*I9cCjO|wrfX{I11q_&_IRDdApa3#0`$j>AOAJ} zNq<)T3Vj3F+%g@nUKow)Ctup9z^c}HH_G3Bt(BIW`&JRcYigNF8UUB$9~|6VT(Zjq zhn<{;^I5UDAZYPVe~#)r!8qhZx$&FwMq6o8Qp;zYol%1SVld>Q8+8%sPoJKnDxPrm z>IiOKq|Zz@`TZq`qL%Kk%|dKB!`u0%Yb2fK40sZVAeR7q@tI!-h=i7`uJnkN58 zHCG_Fw%hb(4aU(l0Nli$jJR}(!SyQUotMK>0IEjdECt0*Q@h$fLI|4>@4#M)f}gCp z>iE~p;^MOu@nYf<<@PgLDRNUUYTJcU|7xEKp@6MNhyT9D@kfFJbyA+uxe)FupRj#;Zf8PUTld zxH{efm))zr1ng!EPDO=2BN}$z;SRU zA(rcUKly*u{GE#(epvYY7&1tB>GS}ETDUiknVfMaeu~k1aOLhDA6&45bHx62ieX{Y zY{~)pK;IUnzhi-!Iq>+Od&XLhYYk=z#N6JH-w92>9x-A%nCIex5KYwlXU?n$aaH#| z3WLcY<2BLcHg`4wpCN{L1zf)ML^;rBo9O|ETza{6>($G9Lu=iCR{G3iGk>8a1ncSi zfVNP7+v)~zLP6+J4B`+$sjxKU#H?sD$L5~6Nxw5(+4<2jVom-{6st@dk@s#fJT-Ad zW~m-HcY*d+rm*1W;4vIVYqEvI=x z)5J0V7|3B-k&GEjqJWEcy%Y~&6-&c;YXrhzAlCdPOL{Sef?_EudS%m;$ub3E??%iU&;TZG=?A6IKE;jCISb<;={?^drsd zZa7A&5vzU4&!4X3FN1g}I1+uCkuu_vCgjV^>W?uSlPd+_nJ;c^1-1M5_uqc;@$pTq zRS=BqtWwvlfrUBzrN3{=;id6`I@R4?i=i6GG;W{Vkk;6yrp3g>#CBTL1-sA`FPlF4 z2PU7;ZimbvK=_Jp|HGXCvO$3zEJ#{wF5}XAD~`;Y6#8zT%6@U@pXc`!SpkadpZ#H- zv-6BDFRkZ1RpdFcQ_IGjZy+1@8$9?B4Hg{0q+?t4JSebrGZwbeN^{@U%W^}NkMG~h z$90dtcW({z@^BKwO6`4!>|!DlL+4K^`F88slMI=(3W+J55b1d{w`AX92Z<~5=wP2X zHV?BAclWvdsv83^B<__4yBOf`Y%%I>7(>zJq9mur7DW&~uXZ%B1GCqFTnRx%`}0!4;DOWE=qri~DyFtI`*L zfG}Of5K4*Qvc!B?Atgax#!93Bp75}$7nOLwZn2fwiOi(}_>2iC4+*`h$8+3Hyz06F z6BvO;Nn3jepigwYu3rAX29pspXAsDREOEvRn;9{}W)zd?WsuD*ct1S6U_t^KLm&@T z)AIoq2obnZ96cI5#8$%hBL zu(4P4IWkNq4c0FlUrLAT7UzxpdT^PQXGOPk`4{K@xX^UL*iy_{1o8Fd;BuwY{NFM& zQr7%;Ex^wz;i+nx<$uNwG^wCeA%!81jzfV37#oA!m|$5Ja_oSZf`CB`C^{_fpbYnW zfjHU*H87}sIF~E*&C669HEJ)n&h$nCPF%477Un$aZ=A z_N{nCG=A5aUnhy)s=sR-0$L~SBGZv9m!k#OsG7y~c;Vhn9+@y%Pds%@4}w0Y*g&9W zvnx?QT*WB;7UUuX+xUI&7QVi?p?CMLT~)Tmm!|uNpR|{>81!6ld0FH=#B}eT2TeId zqsll)zuC>Y=x@YOWZF zuKWcJPu-DL{hG%XzwWaI2;yq?oVd3FSxWS-RuDnm4Bfdze|LALm4Y7SMNSxkP7LQ5 zmXQUvwxMXA*H_sS>S|h@kgemD6BAMQyAu)wCIC1-# zX;hK<*RN}XwhX{qGT_eckHBA%7Fdt||fWE7xG|Y+TaYwlF>D*$hm%g{a3JFxw z7@t{LQIYtq@dBpx?=>}oIY#S#&PaJAE$}(iGa<_Py8Dbp9V1k-oQmlmrf6tnZk=vg zJBxv=#_reO)3 z6VtLOYOh46iTf;2D!gV~8^Gfcu9qDmBcq^M-?hVbW@U*+EAYdfvn|iWl~%>@xb?rWTQh+*1I zFYo*!_ak}zrH27mc?fokCa-3)LEPbDuP~GhL^evGPMkjBJw*g2Jf<8GZn%+Bnzx(C zbz+_?a7ddqRG65F??hBs(5Vz)wco@sexbfx5-$du&ztuBRph1P8z1 zpST61D=BCVR_~z4uVpvG0{+rf$aok*6h@ z)!_yd36hdlm}H52Vy1wQw3CWRvSKt0&p;?+;I$a+-kF%WnBg+VM=c=JOG>RQEbhBa z0u;MMl_9WZ1Rb|9>AUM1?Q*qpr6cWvcuCBlWg*Fst9i=W9(4-~&UaDF<=0Rg$g!6M z;nupTI^*I+mFk&CyzLgs59+KiOINSWUS)kvjvf2FW`^OgKTd~+#t2$GJUl!tJ)MhxqypK@OL^R8eS(}NX~7Z2u3ZO+=%f%x?u*e!)gUiUx>7$~~@ z#$BWAC&P}G2M^WSu8?Wv|3^r?YtmPAUQz6zC*cxownR>18e(D7|ZHqlWEpPW)jO z>YaLVm4m~F*OlI@wt9-IZW#>F5FB=oLAjl{n`ruG&Vtmi_^(Jhg@XqV8WZ&L;e7_OnDyh^UHQ&Tb5N3LT+2YEnoo6{q66ONV=Y+s$zL+iVnA8^f8cO}A`3Dij0! z{XhFEg&4t!Oks%hkE)^qt-niWZ>fqca6nA)i>4k@bL6A`U9he4{8A zgT0Y8SxCb#R=;fXG<8PGzwvHu?y-7m4^g#l-(}zR+jg+N0UZON`CrHa=G`0U4P<@bKna*lPz0roHdN7m%D_}(}_BQ1?1yr z(+|dQul5{X(&O{_1NWaCV0jXM7CJ_p-Jf3a{WJWvlX}7Y4^1Cc%@vVibWv7TzMElp ztA|EvvHX~tQr96p4?wwvA+(6%3jrFOfJ`XeJdOX!FhZa#e%nVw?xUZlqM{O6LrGGS zmX?+cwDZriT(|DZ<;#~ZWg9z9E%Nr8WQ$(RqY`0*gQ3ba#ZT@tVyVrBPIs9*K5!A9 z0Yp02cQt)qKq>cy&y~ka0CjSrp3*1v@#Dt*IAX26f}0B>c6=>J^P2=M7BW7u&iL@a zNwa~iSql|a)g0cxfB*jBbZZ+B1HOIxNh<9djc7{M>}pmIjpB1a3n3;>t`(dIaR|^0 zU%GH%ezjtd|-Mw*uMkVBkKH9 z90=DZLw9_RjJlS+HB%=7%=(Q>`Zzh{czmgAG$@YXDCk797}T*WbW`F|$Fy2)jd%^u z(bTUwhS^4X%}!HS?9h9o=(_Yx^IN~LW@(aIs;APJS=qmC-@biTv(Wa$EH~!{;Qhf( z>el@Yd%n!}4Y^+Ae9wRPVWoLGf?wXkDX&+aV>_}-UtUM`69-9si`tUkVrRUA2mM9fv~lu4Y{8T|QDx%>-!TB}wjDQS@Vjw$h zjUNx;BKXC6q9VCJG_0RSo}A{k%gAL!wbe2#vmdXU=l^KyiNuw?CF5myx*|y&JeWPa zwPAq>1x!>85J1E@tGh;sA97P@wXD_+yLr`@@3MZ$v{VMY#u9E8=2vGV426=>8%Jj*x>tD_; zu-bYUuTUNWDr@($0NK)QUWbntRpnEkV`3M;tRo78w}ac6dUpBeyR2Rv`DS2e-4b25 zjy~O%k<45f2K$BCcexZdvD~&L(gFcOpSfnMS6@&-HEAZkAtu~tTAs@w2eCHWI#jY5 zD8Is~Y{%&6SQA15$_ve5QKtZMLMDioe6dbv^)`H!^4Gml3t%!`K!w9hB1EbQ0S^(EXHC1fW6y*!~sO-}xl?fA; zfM=amF+~ z8?K9MRH{qpnbBzFQ-b=RITJ-pC4{PKX%#KVTTw!$;Nu<|pRf=&VM3{NQ7(f~s>QWV z5%;x*N|w*!+mFuRf%BgUj#_1!{U41`@$ewaM{@9|2OIX6l{K#%G=A*ZWqNwParW^S zG~#Qv>X~|6TCxkzxKZ?id$moTc35-&^{$+RMOQ)=AARwt8CZH#==qk?|)M9I%(H%v#0F{?TdQX zUvE65P{A29b#QPf+w_7@&^99H3ILAC$5Mqg&qodqEbTYdR#uYRZ|B;zrE+?sysSG* zB!?f&1VLP&H#up1SkjbQ*EYI3lOWP9cL5CAzutIfs?<`?r6ECCB9S{bN-Fi6)Eap5 zgWDn_W9T}pFh9`W>{~WT9mBVVWCQ3>B-z???cHaau-XJ!}^|i zF;!bpvCL-EOU&KZ)clT$q%Rt5L}v9w#z)Q4(5wHav# z&ORxbUZp89dbZ){ps8mLmvsFy82{AKl5*< z^+F4wRT(u*-J1PUZjC)^ci03+i?Vc-v%lQD^4gtSIx#Z5zR^1|<5El7EEBSkk-1_0 zh)xpw$Ifw~HLpHwzc>BbIU9~nt}ip;JV!q>eKgYC!s50459?k&e@wt1r)O-|<4{jh zz^M47%2_$=J|iV?XP3j120Jdly^1X2{==rXPwIn(mKJk<>rYzS?#I4w-Opv5UG3H} z!mQ2NLk>@R|FP%%3^r=+AaC#1yvV}ArJVXGFH_#3`eyq0A_u?5aO0dzoMkJ#%z6h6 zVMR0h@cX35h6EXP$*zBnpULv&m#Jg(D`ueRiK6CtT~*gcBHMS3 zAL^ATyuXz+n&z|z;0k#RgGg-rbOu}_@GFB%^`vwTn>SzY*lXBTq;J&z3#E0Wxb@J% zq5u{225kyL2j)~wnto%lXFs|9Rv5R!oARn+tDr9#~P?2=Y0Ww`W)>;<;LNl zc$0AgO-7FDdgo}+vL>&FU++3>9-mQm*F|%DV7m5?ToXvQNuy`Xcnh)}l$~vie`Z*1 z{)$bfZ{D1IA|%9_U1zXr)%h*=-i%gL%PFQJw@dRMlR9t>x%kDnxZ>5~8VYfDh>4Aj zGi^CDygj3TZ`TaYYe^m;Bje_sfs5>C5bgZS;%zwwWYa08h4p{GUIPZRtI#VX3cJ_A zlC;sbt@nIf>$KY)&ZUg@KXKwBjn<>0?FjOsD6grNa~WpATQ4Fjo_ssXM@WQLECmw#~YdDV7D8t{a#36=N%nhyUV>_(41WI+Pg1tvGm zqvWGazgbj8IpY85gAoy&IkD=^Rhzs`D4jC@mTfD!>}|i(!xirOZO&mvPaSE5&-I&> z%J9BSGQp#r4tZrR!I^5uJ{3B~OraRpsq#SnDQ;^RO-WT`)+kfS$$Y-a`}YdrEvc>{ z#Hn$`750>-h_pKdjWH@JlUWNfGxHOUpr7NnQU&I}x#M&OUrc1abN@$Evj*noT|Z0# z%ay|Jg=-!>do&fH(Q^=s7x+V~tnHEVfTyN1?k^Y5Zx)BmGV((&?}okfAm)CPl82et z>}p)6hCPRK^wk=&FcW`LA@ljtnbmk2ATbE~KrU`Nf}C1NkQIfkr&qt4|7dQeT2^PV zv4I}5`EXyI&S>qp1`&DrUDGFxw|4+2m=Jb0(CcJiAP|L>QQ};sUhST}ctP#kS$0rc z*K?dMX=GC?bHa{eFRp5yK4QdQzdf_g&0^UFLcxs?(f7V4q~F_!*GmXrn4^9HC*wi^ z1Hk0Drt~+@wR|MNGUAkq6Ud?fITU6l+m2d7IK)%CuEI;F;r-sX^&J3C5hB&;w8P1nk>NHdA1~4hBDw(MCvTSay zL&3DOu)fp#=dMVX*{GcPA2!~bGj-}ehwS|N5?CftZR0Yo3|tg#dj~ZD^Yj#i;t38o z2e2R(R@tG_i$c+Z|2r0^3g~O&l7$P6EG$kl&LjrAQ1H!;l%d%7G(&Yd_vrRv(E6|t zk1u1Ggt7wBmuaDD{hi!xb9~^aL$(*8;JA)vX?b`RuSBt)!_{d%lW>hB;5}+aLKs9^#V3$i%N34{Q;mey4;O zkDD-oit2QIyXUfrbD1Y{688Eww}OD_6n|OKcJm)NAtPa~KBIofpVLbx4C*QJ?%m}C zpObOl-?g@w3mk;IpD%;vmX((~VtfS>wtL!td}p5gah`m=;ezt*_vqk8=tbu5#V%8(6pw=yG>kAIMKH>FuR0P!54TPaD#R*8t`53OvNH(Q z{0A{6`X+aw4$F=2XDH1XDo0z_sEprZob7jXw!aIRC~8-{Wa*a z5+lSsKApC&d#;w5d-pyGJ2vEl=sMqe)xSwli3tiydfqN}1WD}`L#!@hi?To&$#9aO z9X}5q+_IO)xVPR;i9l)?QR{bSIL#Iqo){JXi|BKe=r3{~g{=cwj#(_1V5uVk4$GSp zEtY=o@bQnq&X==8m@o6K$GPLIbpUO_n82cqQ-6GYvjWKW@|J0TJ}G%gj$2+iHA`K5 z@%03vU)Tx-qNwxp)f$1K6g$W5XoM32X;H+5Pj#Y~?Rz6*%A0RtQ+bsvD4n{$Z)HY$ zx3);bzyRNDFLHX@Y`yK}Jkv|hwao3a7i~+r^r2nWH?+=q3B~lDB;mJwkgA`Sffp+% za1V>(htn6u+*2yF~o2n@wG+HIsE55tcfmwV(EmnUg*7=Pk1~>B!8?IQ5 z4+Jv}4;k#?E0OeQ!*SZj%q)xO7tV32GiJ2h|N6u^&b&)T0Lacqzf|L#MeQZ)JD;lU zKuP((??HXnj_M?lw5imaJ8RkheH;6KR>g{PQzFSthCpsi*f)9t*YXu8z8_1AAX#r| zC2jhY8A{jtEy_g{rKk3PnKLf&IXbrNA zc*Gs$RaDXn6nXVYMIATKQcK;)k6un2c() .Builder(); }); diff --git a/src/JT808.DotNetty.Abstractions/Dtos/JT808SystemCollectInfoDto.cs b/src/JT808.DotNetty.Abstractions/Dtos/JT808SystemCollectInfoDto.cs deleted file mode 100644 index 23c883c..0000000 --- a/src/JT808.DotNetty.Abstractions/Dtos/JT808SystemCollectInfoDto.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.DotNetty.Abstractions.Dtos -{ - public class JT808SystemCollectInfoDto - { - /// - /// 进程Id - /// - public int ProcessId { get; set; } - /// - /// 进程分配内存 - /// 单位MB - /// - public double WorkingSet64 { get; set; } - /// - /// 进程分配内存峰值 - /// 单位MB - /// - public double PeakWorkingSet64 { get; set; } - /// - /// 进程分配私有内存 - /// 单位MB - /// - public double PrivateMemorySize64 { get; set; } - /// - /// 进程执行CPU总处理时间 - /// - public TimeSpan CPUTotalProcessorTime { get; set; } - } -} diff --git a/src/JT808.DotNetty.Abstractions/Dtos/JT808TrafficInfoDto.cs b/src/JT808.DotNetty.Abstractions/Dtos/JT808TrafficInfoDto.cs deleted file mode 100644 index 594c355..0000000 --- a/src/JT808.DotNetty.Abstractions/Dtos/JT808TrafficInfoDto.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.DotNetty.Abstractions.Dtos -{ - public class JT808TrafficInfoDto - { - /// - /// 总接收大小 - /// 单位KB - /// - public double TotalReceiveSize { get; set; } - /// - /// 总发送大小 - /// 单位KB - /// - public double TotalSendSize { get; set; } - } -} diff --git a/src/JT808.DotNetty.Abstractions/JT808Constants.cs b/src/JT808.DotNetty.Abstractions/JT808Constants.cs index bc65121..db24035 100644 --- a/src/JT808.DotNetty.Abstractions/JT808Constants.cs +++ b/src/JT808.DotNetty.Abstractions/JT808Constants.cs @@ -12,32 +12,10 @@ public const string SessionPrefix = "Session"; - public const string TransmitPrefix = "Transmit"; - - public const string SystemCollectPrefix = "SystemCollect"; - - public const string TrafficPrefix = "Traffic"; - public const string TcpPrefix = "Tcp"; public const string UdpPrefix = "Udp"; - /// - ///获取当前系统进程使用率 - /// - public static string SystemCollectGet = $"{RouteTablePrefix}/{SystemCollectPrefix}/Get"; - /// - ///基于Tcp的添加转发过滤地址 - /// - public static string TransmitAdd = $"{RouteTablePrefix}/{TcpPrefix}/{TransmitPrefix}/Add"; - /// - /// 基于Tcp的删除转发过滤地址(不能删除在网关服务器配置文件配的地址) - /// - public static string TransmitRemove = $"{RouteTablePrefix}/{TcpPrefix}/{TransmitPrefix}/Remove"; - /// - ///基于Tcp的获取转发过滤地址信息集合 - /// - public static string TransmitGetAll = $"{RouteTablePrefix}/{TcpPrefix}/{TransmitPrefix}/GetAll"; /// /// 基于Tcp的包计数器 /// @@ -54,11 +32,6 @@ /// 基于Tcp的统一下发信息 /// public static string UnificationTcpSend = $"{RouteTablePrefix}/{TcpPrefix}/UnificationSend"; - /// - /// 基于Tcp的流量服务获取 - /// - public static string TrafficTcpGet = $"{RouteTablePrefix}/{TcpPrefix}/{TrafficPrefix}/Get"; - /// /// 获取Udp包计数器 /// @@ -75,10 +48,6 @@ /// 基于Udp的会话服务-通过设备终端号移除对应会话 /// public static string SessionUdpRemoveByTerminalPhoneNo = $"{RouteTablePrefix}/{UdpPrefix}/{SessionPrefix}/RemoveByTerminalPhoneNo"; - /// - /// 基于Udp的流量服务获取 - /// logger; - private readonly JT808TrafficService jT808TrafficService; - - private readonly IJT808DownlinkPacket jT808DownlinkPacket; - private readonly JT808Serializer JT808Serializer; public JT808TcpEncoder( IJT808Config jT808Config, - ILoggerFactory loggerFactory, - JT808TrafficServiceFactory jT808TrafficServiceFactory, - IJT808DownlinkPacket jT808DownlinkPacket) + ILoggerFactory loggerFactory) { logger = loggerFactory.CreateLogger(); - this.jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.tcp); - this.jT808DownlinkPacket = jT808DownlinkPacket; this.JT808Serializer = jT808Config.GetSerializer(); } @@ -43,8 +32,6 @@ namespace JT808.DotNetty.Core.Codecs try { var sendData = JT808Serializer.Serialize(message.Package, message.MinBufferSize); - jT808TrafficService.SendSize(sendData.Length); - jT808DownlinkPacket.ProcessorAsync(sendData, JT808TransportProtocolType.tcp); output.WriteBytes(Unpooled.WrappedBuffer(sendData)); } catch (JT808.Protocol.Exceptions.JT808Exception ex) @@ -58,8 +45,6 @@ namespace JT808.DotNetty.Core.Codecs } else if (message.HexData != null) { - jT808TrafficService.SendSize(message.HexData.Length); - jT808DownlinkPacket.ProcessorAsync(message.HexData, JT808TransportProtocolType.tcp); output.WriteBytes(Unpooled.WrappedBuffer(message.HexData)); } } diff --git a/src/JT808.DotNetty.Core/Impls/JT808DatagramPacketImpl.cs b/src/JT808.DotNetty.Core/Impls/JT808DatagramPacketImpl.cs index 71421f2..1a482ec 100644 --- a/src/JT808.DotNetty.Core/Impls/JT808DatagramPacketImpl.cs +++ b/src/JT808.DotNetty.Core/Impls/JT808DatagramPacketImpl.cs @@ -13,19 +13,15 @@ namespace JT808.DotNetty.Core.Impls { class JT808DatagramPacketImpl : IJT808DatagramPacket { - private readonly JT808TrafficService jT808TrafficService; private readonly IJT808DownlinkPacket jT808DownlinkPacket; public JT808DatagramPacketImpl( - JT808TrafficServiceFactory jT808TrafficServiceFactory, IJT808DownlinkPacket jT808DownlinkPacket) { this.jT808DownlinkPacket = jT808DownlinkPacket; - this.jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.udp); } public DatagramPacket Create(byte[] message, EndPoint recipient) { - jT808TrafficService.SendSize(message.Length); jT808DownlinkPacket.ProcessorAsync(message, JT808TransportProtocolType.udp); return new DatagramPacket(Unpooled.WrappedBuffer(message), recipient); } diff --git a/src/JT808.DotNetty.Core/Impls/JT808DownlinkPacketEmptyImpl.cs b/src/JT808.DotNetty.Core/Impls/JT808DownlinkPacketEmptyImpl.cs deleted file mode 100644 index 7ba5593..0000000 --- a/src/JT808.DotNetty.Core/Impls/JT808DownlinkPacketEmptyImpl.cs +++ /dev/null @@ -1,17 +0,0 @@ -using JT808.DotNetty.Abstractions; -using JT808.DotNetty.Abstractions.Enums; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.DotNetty.Core.Impls -{ - class JT808DownlinkPacketEmptyImpl : IJT808DownlinkPacket - { - public Task ProcessorAsync(byte[] data, JT808TransportProtocolType transportProtocolType) - { - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.DotNetty.Core/Impls/JT808SourcePackageDispatcherEmptyImpl.cs b/src/JT808.DotNetty.Core/Impls/JT808SourcePackageDispatcherEmptyImpl.cs deleted file mode 100644 index f17ae75..0000000 --- a/src/JT808.DotNetty.Core/Impls/JT808SourcePackageDispatcherEmptyImpl.cs +++ /dev/null @@ -1,16 +0,0 @@ -using JT808.DotNetty.Abstractions; -using System.Threading.Tasks; - -namespace JT808.DotNetty.Core.Impls -{ - /// - /// 原包分发器默认空实现 - /// - public class JT808SourcePackageDispatcherEmptyImpl : IJT808SourcePackageDispatcher - { - public Task SendAsync(byte[] data) - { - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.DotNetty.Core/Impls/JT808UplinkPacketEmptyImpl.cs b/src/JT808.DotNetty.Core/Impls/JT808UplinkPacketEmptyImpl.cs deleted file mode 100644 index 11a1b04..0000000 --- a/src/JT808.DotNetty.Core/Impls/JT808UplinkPacketEmptyImpl.cs +++ /dev/null @@ -1,17 +0,0 @@ -using JT808.DotNetty.Abstractions; -using JT808.DotNetty.Abstractions.Enums; -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; - -namespace JT808.DotNetty.Core.Impls -{ - class JT808UplinkPacketEmptyImpl : IJT808UplinkPacket - { - public Task ProcessorAsync(byte[] data, JT808TransportProtocolType transportProtocolType) - { - return Task.CompletedTask; - } - } -} diff --git a/src/JT808.DotNetty.Core/Interfaces/IJT808NettyBuilder.cs b/src/JT808.DotNetty.Core/Interfaces/IJT808NettyBuilder.cs index 5f1600d..5ffc289 100644 --- a/src/JT808.DotNetty.Core/Interfaces/IJT808NettyBuilder.cs +++ b/src/JT808.DotNetty.Core/Interfaces/IJT808NettyBuilder.cs @@ -10,9 +10,6 @@ namespace JT808.DotNetty.Core.Interfaces public interface IJT808NettyBuilder { IJT808Builder JT808Builder { get; } - IJT808NettyBuilder ReplaceSourcePackageDispatcher() where T : IJT808SourcePackageDispatcher; - IJT808NettyBuilder ReplaceDownlinkPacket() where T: IJT808DownlinkPacket; - IJT808NettyBuilder ReplaceUplinkPacket() where T : IJT808UplinkPacket; IJT808NettyBuilder ReplaceSessionPublishing() where T : IJT808SessionPublishing; IJT808Builder Builder(); } diff --git a/src/JT808.DotNetty.Core/Interfaces/IJT808Session.cs b/src/JT808.DotNetty.Core/Interfaces/IJT808Session.cs new file mode 100644 index 0000000..22ad240 --- /dev/null +++ b/src/JT808.DotNetty.Core/Interfaces/IJT808Session.cs @@ -0,0 +1,20 @@ +using DotNetty.Transport.Channels; +using JT808.DotNetty.Abstractions.Enums; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT808.DotNetty.Core.Interfaces +{ + public interface IJT808Session + { + /// + /// 终端手机号 + /// + string TerminalPhoneNo { get; set; } + IChannel Channel { get; set; } + DateTime LastActiveTime { get; set; } + DateTime StartTime { get; set; } + JT808TransportProtocolType TransportProtocolType { get; set; } + } +} diff --git a/src/JT808.DotNetty.Core/Interfaces/IJT808TcpCustomMsgIdHandler.cs b/src/JT808.DotNetty.Core/Interfaces/IJT808TcpCustomMsgIdHandler.cs deleted file mode 100644 index 42fb845..0000000 --- a/src/JT808.DotNetty.Core/Interfaces/IJT808TcpCustomMsgIdHandler.cs +++ /dev/null @@ -1,20 +0,0 @@ -using JT808.DotNetty.Core.Metadata; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.DotNetty.Core.Interfaces -{ - public interface IJT808TcpCustomMsgIdHandler - { - IJT808Reply Proccesser(JT808Request request); - } - - public class JT808TcpCustomMsgIdHandlerEmpty : IJT808TcpCustomMsgIdHandler - { - public IJT808Reply Proccesser(JT808Request request) - { - return default; - } - } -} diff --git a/src/JT808.DotNetty.Core/Interfaces/IJT808TcpNettyBuilder.cs b/src/JT808.DotNetty.Core/Interfaces/IJT808TcpNettyBuilder.cs index 0e67228..9bd50c9 100644 --- a/src/JT808.DotNetty.Core/Interfaces/IJT808TcpNettyBuilder.cs +++ b/src/JT808.DotNetty.Core/Interfaces/IJT808TcpNettyBuilder.cs @@ -9,8 +9,6 @@ namespace JT808.DotNetty.Core.Interfaces { IJT808NettyBuilder Instance { get; } IJT808NettyBuilder Builder(); - IJT808TcpNettyBuilder ReplaceCustomMsgIdHandler() where T : IJT808TcpCustomMsgIdHandler; - IJT808TcpNettyBuilder ReplaceMsgIdHandler() where T : JT808MsgIdTcpHandlerBase; IJT808TcpNettyBuilder ReplaceSessionService() where T : IJT808TcpSessionService; IJT808TcpNettyBuilder ReplaceUnificationSendService() where T : IJT808UnificationTcpSendService; } diff --git a/src/JT808.DotNetty.Core/Interfaces/IJT808UdpCustomMsgIdHandler.cs b/src/JT808.DotNetty.Core/Interfaces/IJT808UdpCustomMsgIdHandler.cs deleted file mode 100644 index f9c4698..0000000 --- a/src/JT808.DotNetty.Core/Interfaces/IJT808UdpCustomMsgIdHandler.cs +++ /dev/null @@ -1,20 +0,0 @@ -using JT808.DotNetty.Core.Metadata; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.DotNetty.Core.Interfaces -{ - public interface IJT808UdpCustomMsgIdHandler - { - IJT808Reply Proccesser(JT808Request request); - } - - public class JT808UdpCustomMsgIdHandlerEmpty : IJT808UdpCustomMsgIdHandler - { - public IJT808Reply Proccesser(JT808Request request) - { - return default; - } - } -} diff --git a/src/JT808.DotNetty.Core/Interfaces/IJT808UdpNettyBuilder.cs b/src/JT808.DotNetty.Core/Interfaces/IJT808UdpNettyBuilder.cs index 8efc02b..7a55635 100644 --- a/src/JT808.DotNetty.Core/Interfaces/IJT808UdpNettyBuilder.cs +++ b/src/JT808.DotNetty.Core/Interfaces/IJT808UdpNettyBuilder.cs @@ -9,8 +9,6 @@ namespace JT808.DotNetty.Core.Interfaces { IJT808NettyBuilder Instance { get; } IJT808NettyBuilder Builder(); - IJT808UdpNettyBuilder ReplaceCustomMsgIdHandler() where T : IJT808UdpCustomMsgIdHandler; - IJT808UdpNettyBuilder ReplaceMsgIdHandler() where T : JT808MsgIdUdpHandlerBase; IJT808UdpNettyBuilder ReplaceSessionService() where T : IJT808UdpSessionService; IJT808UdpNettyBuilder ReplaceUnificationSendService() where T : IJT808UnificationUdpSendService; } diff --git a/src/JT808.DotNetty.Core/JT808.DotNetty.Core.csproj b/src/JT808.DotNetty.Core/JT808.DotNetty.Core.csproj index d538217..ce0e709 100644 --- a/src/JT808.DotNetty.Core/JT808.DotNetty.Core.csproj +++ b/src/JT808.DotNetty.Core/JT808.DotNetty.Core.csproj @@ -7,10 +7,6 @@ 基于DotNetty实现的JT808DotNetty的核心库 - - - - diff --git a/src/JT808.DotNetty.Core/JT808BackgroundService.cs b/src/JT808.DotNetty.Core/JT808BackgroundService.cs deleted file mode 100644 index cda2139..0000000 --- a/src/JT808.DotNetty.Core/JT808BackgroundService.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Microsoft.Extensions.Hosting; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.DotNetty.Core -{ - /// - /// - /// - /// - public abstract class JT808BackgroundService : IHostedService, IDisposable - { - /// - /// 默认次日过期 - /// - public virtual TimeSpan DelayTimeSpan - { - get - { - DateTime current = DateTime.Now; - DateTime tmp = current.Date.AddDays(1).AddSeconds(-1); - return tmp.Subtract(current); - } - set { } - } - - private Task _executingTask; - - public abstract string ServiceName { get; } - - private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource(); - - protected abstract Task ExecuteAsync(CancellationToken stoppingToken); - - public void Dispose() - { - _stoppingCts.Cancel(); - } - - public virtual Task StartAsync(CancellationToken cancellationToken) - { - // Store the task we're executing - _executingTask = ExecuteAsync(_stoppingCts.Token); - // If the task is completed then return it, - // this will bubble cancellation and failure to the caller - if (_executingTask.IsCompleted) - { - return _executingTask; - } - // Otherwise it's running - return Task.CompletedTask; - } - - public virtual async Task StopAsync(CancellationToken cancellationToken) - { - // Stop called without start - if (_executingTask == null) - { - return; - } - try - { - // Signal cancellation to the executing method - _stoppingCts.Cancel(); - } - finally - { - // Wait until the task completes or the stop token triggers - await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,cancellationToken)); - } - } - } -} diff --git a/src/JT808.DotNetty.Core/JT808CoreDotnettyExtensions.cs b/src/JT808.DotNetty.Core/JT808CoreDotnettyExtensions.cs index 818fb72..1ac35bd 100644 --- a/src/JT808.DotNetty.Core/JT808CoreDotnettyExtensions.cs +++ b/src/JT808.DotNetty.Core/JT808CoreDotnettyExtensions.cs @@ -58,13 +58,7 @@ namespace JT808.DotNetty.Core } IJT808NettyBuilder nettyBuilder = new JT808NettyBuilderDefault(jt808Builder); nettyBuilder.JT808Builder.Services.Configure(configuration.GetSection("JT808Configuration")); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); return nettyBuilder; } @@ -83,13 +77,7 @@ namespace JT808.DotNetty.Core } IJT808NettyBuilder nettyBuilder = new JT808NettyBuilderDefault(jt808Builder); nettyBuilder.JT808Builder.Services.Configure(jt808Options); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); - nettyBuilder.JT808Builder.Services.TryAddSingleton(); return nettyBuilder; } } diff --git a/src/JT808.DotNetty.Core/Jobs/JT808TcpAtomicCouterResetDailyJob.cs b/src/JT808.DotNetty.Core/Jobs/JT808TcpAtomicCouterResetDailyJob.cs deleted file mode 100644 index 54b438b..0000000 --- a/src/JT808.DotNetty.Core/Jobs/JT808TcpAtomicCouterResetDailyJob.cs +++ /dev/null @@ -1,38 +0,0 @@ -using JT808.DotNetty.Abstractions.Enums; -using JT808.DotNetty.Core.Services; -using Microsoft.Extensions.Logging; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.DotNetty.Core.Jobs -{ - internal class JT808TcpAtomicCouterResetDailyJob : JT808BackgroundService - { - private readonly ILogger _logger; - - private readonly JT808AtomicCounterService _jT808AtomicCounterService; - - public JT808TcpAtomicCouterResetDailyJob( - JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory, - ILoggerFactory loggerFactory) - { - _jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); - _logger =loggerFactory.CreateLogger(); - } - - public override string ServiceName => nameof(JT808TcpAtomicCouterResetDailyJob); - - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - _logger.LogInformation($"{ServiceName} is starting."); - stoppingToken.Register(() => _logger.LogInformation($"{ServiceName} background task is stopping.")); - while (!stoppingToken.IsCancellationRequested) - { - _logger.LogInformation($"{ServiceName} task doing background work."); - _jT808AtomicCounterService.Reset(); - await Task.Delay(DelayTimeSpan, stoppingToken); - } - _logger.LogInformation($"{ServiceName} background task is stopping."); - } - } -} diff --git a/src/JT808.DotNetty.Core/Jobs/JT808TcpTrafficResetDailyJob.cs b/src/JT808.DotNetty.Core/Jobs/JT808TcpTrafficResetDailyJob.cs deleted file mode 100644 index 5e5dcad..0000000 --- a/src/JT808.DotNetty.Core/Jobs/JT808TcpTrafficResetDailyJob.cs +++ /dev/null @@ -1,38 +0,0 @@ -using JT808.DotNetty.Abstractions.Enums; -using JT808.DotNetty.Core.Services; -using Microsoft.Extensions.Logging; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.DotNetty.Core.Jobs -{ - internal class JT808TcpTrafficResetDailyJob : JT808BackgroundService - { - private readonly ILogger _logger; - - private readonly JT808TrafficService _jT808TrafficService; - - public JT808TcpTrafficResetDailyJob( - JT808TrafficServiceFactory jT808TrafficServiceFactory, - ILoggerFactory loggerFactory) - { - _jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.tcp); - _logger =loggerFactory.CreateLogger(); - } - - public override string ServiceName => nameof(JT808TcpTrafficResetDailyJob); - - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - _logger.LogInformation($"{ServiceName} is starting."); - stoppingToken.Register(() => _logger.LogInformation($"{ServiceName} background task is stopping.")); - while (!stoppingToken.IsCancellationRequested) - { - _logger.LogInformation($"{ServiceName} task doing background work."); - _jT808TrafficService.ResetSize(); - await Task.Delay(DelayTimeSpan, stoppingToken); - } - _logger.LogInformation($"{ServiceName} background task is stopping."); - } - } -} diff --git a/src/JT808.DotNetty.Core/Jobs/JT808UdpAtomicCouterResetDailyJob.cs b/src/JT808.DotNetty.Core/Jobs/JT808UdpAtomicCouterResetDailyJob.cs deleted file mode 100644 index 1cd668f..0000000 --- a/src/JT808.DotNetty.Core/Jobs/JT808UdpAtomicCouterResetDailyJob.cs +++ /dev/null @@ -1,38 +0,0 @@ -using JT808.DotNetty.Abstractions.Enums; -using JT808.DotNetty.Core.Services; -using Microsoft.Extensions.Logging; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.DotNetty.Core.Jobs -{ - internal class JT808UdpAtomicCouterResetDailyJob : JT808BackgroundService - { - private readonly ILogger _logger; - - private readonly JT808AtomicCounterService _jT808AtomicCounterService; - - public JT808UdpAtomicCouterResetDailyJob( - JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory, - ILoggerFactory loggerFactory) - { - _jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); - _logger =loggerFactory.CreateLogger(); - } - - public override string ServiceName => nameof(JT808UdpAtomicCouterResetDailyJob); - - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - _logger.LogInformation($"{ServiceName} is starting."); - stoppingToken.Register(() => _logger.LogInformation($"{ServiceName} background task is stopping.")); - while (!stoppingToken.IsCancellationRequested) - { - _logger.LogInformation($"{ServiceName} task doing background work."); - _jT808AtomicCounterService.Reset(); - await Task.Delay(DelayTimeSpan, stoppingToken); - } - _logger.LogInformation($"{ServiceName} background task is stopping."); - } - } -} diff --git a/src/JT808.DotNetty.Core/Jobs/JT808UdpTrafficResetDailyJob.cs b/src/JT808.DotNetty.Core/Jobs/JT808UdpTrafficResetDailyJob.cs deleted file mode 100644 index 620a80f..0000000 --- a/src/JT808.DotNetty.Core/Jobs/JT808UdpTrafficResetDailyJob.cs +++ /dev/null @@ -1,38 +0,0 @@ -using JT808.DotNetty.Abstractions.Enums; -using JT808.DotNetty.Core.Services; -using Microsoft.Extensions.Logging; -using System.Threading; -using System.Threading.Tasks; - -namespace JT808.DotNetty.Core.Jobs -{ - internal class JT808UdpTrafficResetDailyJob : JT808BackgroundService - { - private readonly ILogger _logger; - - private readonly JT808TrafficService _jT808TrafficService; - - public JT808UdpTrafficResetDailyJob( - JT808TrafficServiceFactory jT808TrafficServiceFactory, - ILoggerFactory loggerFactory) - { - _jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.udp); - _logger =loggerFactory.CreateLogger(); - } - - public override string ServiceName => nameof(JT808UdpTrafficResetDailyJob); - - protected override async Task ExecuteAsync(CancellationToken stoppingToken) - { - _logger.LogInformation($"{ServiceName} is starting."); - stoppingToken.Register(() => _logger.LogInformation($"{ServiceName} background task is stopping.")); - while (!stoppingToken.IsCancellationRequested) - { - _logger.LogInformation($"{ServiceName} task doing background work."); - _jT808TrafficService.ResetSize(); - await Task.Delay(DelayTimeSpan, stoppingToken); - } - _logger.LogInformation($"{ServiceName} background task is stopping."); - } - } -} diff --git a/src/JT808.DotNetty.Core/Metadata/JT808TcpSession.cs b/src/JT808.DotNetty.Core/Metadata/JT808TcpSession.cs index 6d0e651..27c4338 100644 --- a/src/JT808.DotNetty.Core/Metadata/JT808TcpSession.cs +++ b/src/JT808.DotNetty.Core/Metadata/JT808TcpSession.cs @@ -1,9 +1,11 @@ using DotNetty.Transport.Channels; +using JT808.DotNetty.Abstractions.Enums; +using JT808.DotNetty.Core.Interfaces; using System; namespace JT808.DotNetty.Core.Metadata { - public class JT808TcpSession + public class JT808TcpSession: IJT808Session { public JT808TcpSession(IChannel channel, string terminalPhoneNo) { @@ -25,5 +27,6 @@ namespace JT808.DotNetty.Core.Metadata public DateTime LastActiveTime { get; set; } public DateTime StartTime { get; set; } + public JT808TransportProtocolType TransportProtocolType { get; set; } = JT808TransportProtocolType.tcp; } } diff --git a/src/JT808.DotNetty.Core/Metadata/JT808UdpSession.cs b/src/JT808.DotNetty.Core/Metadata/JT808UdpSession.cs index 7984202..909ac4c 100644 --- a/src/JT808.DotNetty.Core/Metadata/JT808UdpSession.cs +++ b/src/JT808.DotNetty.Core/Metadata/JT808UdpSession.cs @@ -1,10 +1,12 @@ using DotNetty.Transport.Channels; +using JT808.DotNetty.Abstractions.Enums; +using JT808.DotNetty.Core.Interfaces; using System; using System.Net; namespace JT808.DotNetty.Core.Metadata { - public class JT808UdpSession + public class JT808UdpSession: IJT808Session { public JT808UdpSession(IChannel channel, EndPoint sender, @@ -31,5 +33,6 @@ namespace JT808.DotNetty.Core.Metadata public DateTime LastActiveTime { get; set; } public DateTime StartTime { get; set; } + public JT808TransportProtocolType TransportProtocolType { get; set; } = JT808TransportProtocolType.udp; } } diff --git a/src/JT808.DotNetty.Core/Services/JT808SimpleSystemCollectService.cs b/src/JT808.DotNetty.Core/Services/JT808SimpleSystemCollectService.cs deleted file mode 100644 index 2482cff..0000000 --- a/src/JT808.DotNetty.Core/Services/JT808SimpleSystemCollectService.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JT808.DotNetty.Abstractions.Dtos; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; - -namespace JT808.DotNetty.Core.Services -{ - /// - /// 简单系统收集服务 - /// - public class JT808SimpleSystemCollectService - { - /// - /// 获取系统当前进程使用情况 - /// - /// - public JT808SystemCollectInfoDto Get() - { - JT808SystemCollectInfoDto jT808SystemCollectInfoDto = new JT808SystemCollectInfoDto(); - var proc = Process.GetCurrentProcess(); - jT808SystemCollectInfoDto.ProcessId = proc.Id; - jT808SystemCollectInfoDto.WorkingSet64 = proc.WorkingSet64 / 1024.0 / 1024.0; - jT808SystemCollectInfoDto.PeakWorkingSet64 = proc.PeakWorkingSet64 / 1024.0 / 1024.0; - jT808SystemCollectInfoDto.PrivateMemorySize64 = proc.PrivateMemorySize64 / 1024.0 / 1024.0; - jT808SystemCollectInfoDto.CPUTotalProcessorTime = proc.TotalProcessorTime; - return jT808SystemCollectInfoDto; - } - } -} diff --git a/src/JT808.DotNetty.Core/Services/JT808TrafficService.cs b/src/JT808.DotNetty.Core/Services/JT808TrafficService.cs deleted file mode 100644 index 6740ff8..0000000 --- a/src/JT808.DotNetty.Core/Services/JT808TrafficService.cs +++ /dev/null @@ -1,46 +0,0 @@ -using JT808.DotNetty.Core.Metadata; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.DotNetty.Core.Services -{ - public class JT808TrafficService - { - public JT808TrafficService() - { - receiveCounter = new JT808AtomicCounter(); - sendCounter = new JT808AtomicCounter(); - } - - private readonly JT808AtomicCounter receiveCounter; - - private readonly JT808AtomicCounter sendCounter; - - public void ReceiveSize(long size) - { - receiveCounter.Add(size); - } - - public void SendSize(long size) - { - sendCounter.Add(size); - } - - public long TotalReceiveSize - { - get { return receiveCounter.Count; } - } - - public long TotalSendSize - { - get { return sendCounter.Count; } - } - - public void ResetSize() - { - receiveCounter.Reset(); - sendCounter.Reset(); - } - } -} diff --git a/src/JT808.DotNetty.Core/Services/JT808TrafficServiceFactory.cs b/src/JT808.DotNetty.Core/Services/JT808TrafficServiceFactory.cs deleted file mode 100644 index 1e3bc3d..0000000 --- a/src/JT808.DotNetty.Core/Services/JT808TrafficServiceFactory.cs +++ /dev/null @@ -1,33 +0,0 @@ -using JT808.DotNetty.Abstractions.Enums; -using JT808.DotNetty.Core.Metadata; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Text; - -namespace JT808.DotNetty.Core.Services -{ - public class JT808TrafficServiceFactory - { - private readonly ConcurrentDictionary cache; - - public JT808TrafficServiceFactory() - { - cache = new ConcurrentDictionary(); - } - - public JT808TrafficService Create(JT808TransportProtocolType type) - { - if (cache.TryGetValue(type, out var service)) - { - return service; - } - else - { - var serviceNew = new JT808TrafficService(); - cache.TryAdd(type, serviceNew); - return serviceNew; - } - } - } -} diff --git a/src/JT808.DotNetty.Core/Services/JT808TransmitAddressFilterService.cs b/src/JT808.DotNetty.Core/Services/JT808TransmitAddressFilterService.cs deleted file mode 100644 index 7fd1078..0000000 --- a/src/JT808.DotNetty.Core/Services/JT808TransmitAddressFilterService.cs +++ /dev/null @@ -1,102 +0,0 @@ -using JT808.DotNetty.Abstractions.Dtos; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using JT808.DotNetty.Core.Configurations; - -namespace JT808.DotNetty.Core.Services -{ - /// - /// JT808转发地址过滤服务 - /// 按照808的消息,有些请求必须要应答,但是转发可以不需要有应答可以节省部分资源包括: - // 1.消息的序列化 - // 2.消息的下发 - // 都有一定的性能损耗,那么不需要判断写超时 IdleState.WriterIdle - // 就跟神兽貔貅一样。。。 - /// - public class JT808TransmitAddressFilterService : IDisposable - { - private readonly IOptionsMonitor jT808ConfigurationOptionsMonitor; - - private ConcurrentDictionary ForwardingRemoteAddresssDict; - - private IDisposable jT808ConfigurationOptionsMonitorDisposable; - - public JT808TransmitAddressFilterService( - IOptionsMonitor jT808ConfigurationOptionsMonitor) - { - this.jT808ConfigurationOptionsMonitor = jT808ConfigurationOptionsMonitor; - ForwardingRemoteAddresssDict = new ConcurrentDictionary(); - InitForwardingRemoteAddress(jT808ConfigurationOptionsMonitor.CurrentValue.ForwardingRemoteIPAddress); - //OnChange 源码多播委托 - jT808ConfigurationOptionsMonitorDisposable = this.jT808ConfigurationOptionsMonitor.OnChange(options => - { - ChangeForwardingRemoteAddress(options.ForwardingRemoteIPAddress); - }); - } - - private void InitForwardingRemoteAddress(List jT808ClientConfigurations) - { - if (jT808ClientConfigurations != null && jT808ClientConfigurations.Count > 0) - { - foreach (var item in jT808ClientConfigurations) - { - ForwardingRemoteAddresssDict.TryAdd(item, 0); - } - } - } - - private void ChangeForwardingRemoteAddress(List jT808ClientConfigurations) - { - if (jT808ClientConfigurations != null && jT808ClientConfigurations.Count > 0) - { - ForwardingRemoteAddresssDict.Clear(); - foreach (var item in jT808ClientConfigurations) - { - ForwardingRemoteAddresssDict.TryAdd(item, 0); - } - } - else - { - ForwardingRemoteAddresssDict.Clear(); - } - } - - public bool ContainsKey(EndPoint endPoint) - { - IPAddress ip = ((IPEndPoint)endPoint).Address; - return ForwardingRemoteAddresssDict.ContainsKey(ip.ToString()); - } - - public JT808ResultDto Add(string host) - { - return new JT808ResultDto() { Code = JT808ResultCode.Ok, Data = ForwardingRemoteAddresssDict.TryAdd(host,0) }; - } - - public JT808ResultDto Remove(string host) - { - if(jT808ConfigurationOptionsMonitor.CurrentValue.ForwardingRemoteIPAddress!=null && - jT808ConfigurationOptionsMonitor.CurrentValue.ForwardingRemoteIPAddress.Any(w=>w== host)) - { - return new JT808ResultDto() { Code = JT808ResultCode.Ok, Data = false,Message="不能删除服务器配置的地址" }; - } - else - { - return new JT808ResultDto() { Code = JT808ResultCode.Ok, Data = ForwardingRemoteAddresssDict.TryRemove(host,out var temp) }; - } - } - - public JT808ResultDto> GetAll() - { - return new JT808ResultDto>(){ Code = JT808ResultCode.Ok, Data = ForwardingRemoteAddresssDict.Select(s=>s.Key).ToList() }; - } - - public void Dispose() - { - jT808ConfigurationOptionsMonitorDisposable.Dispose(); - } - } -} diff --git a/src/JT808.DotNetty.Tcp/Handlers/JT808MsgIdDefaultTcpHandler.cs b/src/JT808.DotNetty.Tcp/Handlers/JT808MsgIdDefaultTcpHandler.cs deleted file mode 100644 index fcebc15..0000000 --- a/src/JT808.DotNetty.Tcp/Handlers/JT808MsgIdDefaultTcpHandler.cs +++ /dev/null @@ -1,18 +0,0 @@ -using JT808.DotNetty.Core; -using JT808.DotNetty.Core.Handlers; -using System; -using System.Collections.Generic; -using System.Text; - -namespace JT808.DotNetty.Tcp.Handlers -{ - /// - /// 默认消息处理业务实现 - /// - internal class JT808MsgIdDefaultTcpHandler : JT808MsgIdTcpHandlerBase - { - public JT808MsgIdDefaultTcpHandler(JT808TcpSessionManager sessionManager) : base(sessionManager) - { - } - } -} diff --git a/src/JT808.DotNetty.Tcp/Handlers/JT808TcpServerHandler.cs b/src/JT808.DotNetty.Tcp/Handlers/JT808TcpServerHandler.cs index ed23021..a374868 100644 --- a/src/JT808.DotNetty.Tcp/Handlers/JT808TcpServerHandler.cs +++ b/src/JT808.DotNetty.Tcp/Handlers/JT808TcpServerHandler.cs @@ -3,14 +3,11 @@ using DotNetty.Transport.Channels; using JT808.Protocol; using System; using JT808.DotNetty.Core; -using JT808.DotNetty.Abstractions; using Microsoft.Extensions.Logging; -using JT808.DotNetty.Core.Handlers; using JT808.DotNetty.Core.Services; -using JT808.DotNetty.Core.Metadata; -using JT808.DotNetty.Core.Interfaces; using JT808.DotNetty.Abstractions.Enums; using JT808.Protocol.Interfaces; +using JT808.Protocol.Exceptions; namespace JT808.DotNetty.Tcp.Handlers { @@ -18,111 +15,48 @@ namespace JT808.DotNetty.Tcp.Handlers /// JT808服务端处理程序 /// internal class JT808TcpServerHandler : SimpleChannelInboundHandler - { - private readonly JT808MsgIdTcpHandlerBase handler; - + { private readonly JT808TcpSessionManager jT808SessionManager; - private readonly JT808TransmitAddressFilterService jT808TransmitAddressFilterService; - - private readonly IJT808SourcePackageDispatcher jT808SourcePackageDispatcher; - private readonly JT808AtomicCounterService jT808AtomicCounterService; - private readonly JT808TrafficService jT808TrafficService; - - private readonly IJT808UplinkPacket jT808UplinkPacket; - - private readonly IJT808TcpCustomMsgIdHandler jT808TcpCustomMsgIdHandler; - private readonly ILogger logger; - private readonly ILogger unknownLogger; - private readonly JT808Serializer JT808Serializer; public JT808TcpServerHandler( IJT808Config jT808Config, - JT808TrafficServiceFactory jT808TrafficServiceFactory, ILoggerFactory loggerFactory, - JT808TransmitAddressFilterService jT808TransmitAddressFilterService, - IJT808SourcePackageDispatcher jT808SourcePackageDispatcher, - IJT808UplinkPacket jT808UplinkPacket, - JT808MsgIdTcpHandlerBase handler, JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory, - IJT808TcpCustomMsgIdHandler jT808TcpCustomMsgIdHandler, JT808TcpSessionManager jT808SessionManager) { - this.jT808TcpCustomMsgIdHandler = jT808TcpCustomMsgIdHandler; - this.jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.tcp); - this.jT808TransmitAddressFilterService = jT808TransmitAddressFilterService; - this.handler = handler; this.jT808SessionManager = jT808SessionManager; - this.jT808SourcePackageDispatcher = jT808SourcePackageDispatcher; - this.jT808UplinkPacket = jT808UplinkPacket; this.jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); this.JT808Serializer = jT808Config.GetSerializer(); logger = loggerFactory.CreateLogger(); - unknownLogger = loggerFactory.CreateLogger("tcp_unknown_msgid"); } - protected override void ChannelRead0(IChannelHandlerContext ctx, byte[] msg) { try { - jT808SourcePackageDispatcher.SendAsync(msg); - jT808UplinkPacket.ProcessorAsync(msg, JT808TransportProtocolType.tcp); //解析到头部,然后根据具体的消息Id通过队列去进行消费 //要是一定要解析到数据体可以在JT808MsgIdHandlerBase类中根据具体的消息, //解析具体的消息体,具体调用JT808Serializer.Deserialize JT808HeaderPackage jT808HeaderPackage = JT808Serializer.Deserialize(msg); jT808AtomicCounterService.MsgSuccessIncrement(); - jT808TrafficService.ReceiveSize(msg.Length); if (logger.IsEnabled(LogLevel.Trace)) { - logger.LogTrace("accept package success count<<<" + jT808AtomicCounterService.MsgSuccessCount.ToString()); - logger.LogTrace("accept msg <<< " + ByteBufferUtil.HexDump(msg)); + logger.LogTrace($"accept package success count=>{jT808AtomicCounterService.MsgSuccessCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); } jT808SessionManager.TryAdd(jT808HeaderPackage.Header.TerminalPhoneNo,ctx.Channel); - if (handler.HandlerDict.TryGetValue(jT808HeaderPackage.Header.MsgId, out var handlerFunc)) - { - IJT808Reply jT808Response = handlerFunc(new JT808Request(jT808HeaderPackage, msg)); - if (jT808Response != null) - { - if (!jT808TransmitAddressFilterService.ContainsKey(ctx.Channel.RemoteAddress)) - { - ctx.WriteAndFlushAsync(jT808Response); - } - } - } - else - { - IJT808Reply jT808CustomMsgIdResponse = jT808TcpCustomMsgIdHandler.Proccesser(new JT808Request(jT808HeaderPackage, msg)); - if (jT808CustomMsgIdResponse != null) - { - if (!jT808TransmitAddressFilterService.ContainsKey(ctx.Channel.RemoteAddress)) - { - ctx.WriteAndFlushAsync(jT808CustomMsgIdResponse); - } - } - else - { - //未知的消息类型已日志形式输出 - if (unknownLogger.IsEnabled(LogLevel.Debug)) - { - unknownLogger.LogDebug(ByteBufferUtil.HexDump(msg)); - } - } - } } - catch (JT808.Protocol.Exceptions.JT808Exception ex) + catch (JT808Exception ex) { jT808AtomicCounterService.MsgFailIncrement(); if (logger.IsEnabled(LogLevel.Error)) { - logger.LogError("accept package fail count<<<" + jT808AtomicCounterService.MsgFailCount.ToString()); - logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg)); + logger.LogError(ex,$"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); } } catch (Exception ex) @@ -130,8 +64,7 @@ namespace JT808.DotNetty.Tcp.Handlers jT808AtomicCounterService.MsgFailIncrement(); if (logger.IsEnabled(LogLevel.Error)) { - logger.LogError("accept package fail count<<<" + jT808AtomicCounterService.MsgFailCount.ToString()); - logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg)); + logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg)}"); } } } diff --git a/src/JT808.DotNetty.Tcp/JT808TcpBuilderDefault.cs b/src/JT808.DotNetty.Tcp/JT808TcpBuilderDefault.cs index 369071d..7b247a1 100644 --- a/src/JT808.DotNetty.Tcp/JT808TcpBuilderDefault.cs +++ b/src/JT808.DotNetty.Tcp/JT808TcpBuilderDefault.cs @@ -22,17 +22,6 @@ namespace JT808.DotNetty.Tcp return Instance; } - public IJT808TcpNettyBuilder ReplaceCustomMsgIdHandler() where T : IJT808TcpCustomMsgIdHandler - { - Instance.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808TcpCustomMsgIdHandler), typeof(T), ServiceLifetime.Singleton)); - return this; - } - - public IJT808TcpNettyBuilder ReplaceMsgIdHandler() where T : JT808MsgIdTcpHandlerBase - { - Instance.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(JT808MsgIdTcpHandlerBase), typeof(T), ServiceLifetime.Singleton)); - return this; - } public IJT808TcpNettyBuilder ReplaceSessionService() where T : IJT808TcpSessionService { diff --git a/src/JT808.DotNetty.Tcp/JT808TcpDotnettyExtensions.cs b/src/JT808.DotNetty.Tcp/JT808TcpDotnettyExtensions.cs index 43ffb3f..0e8250a 100644 --- a/src/JT808.DotNetty.Tcp/JT808TcpDotnettyExtensions.cs +++ b/src/JT808.DotNetty.Tcp/JT808TcpDotnettyExtensions.cs @@ -10,7 +10,6 @@ using Newtonsoft.Json; using System; using System.Reflection; using System.Runtime.CompilerServices; -using JT808.DotNetty.Core.Jobs; using JT808.DotNetty.Core.Interfaces; using JT808.DotNetty.Internal; @@ -22,18 +21,13 @@ namespace JT808.DotNetty.Tcp { public static IJT808TcpNettyBuilder AddJT808TcpNettyHost(this IJT808NettyBuilder jT808NettyBuilder) { - jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); - jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); - jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.AddHostedService(); - jT808NettyBuilder.JT808Builder.Services.AddHostedService(); jT808NettyBuilder.JT808Builder.Services.AddHostedService(); return new JT808TcpBuilderDefault(jT808NettyBuilder); } diff --git a/src/JT808.DotNetty.Tests/JT808.DotNetty.Core.Test/JT808TransmitAddressFilterServiceTest.cs b/src/JT808.DotNetty.Tests/JT808.DotNetty.Core.Test/JT808TransmitAddressFilterServiceTest.cs deleted file mode 100644 index 0cf5c65..0000000 --- a/src/JT808.DotNetty.Tests/JT808.DotNetty.Core.Test/JT808TransmitAddressFilterServiceTest.cs +++ /dev/null @@ -1,75 +0,0 @@ -using JT808.DotNetty.Abstractions.Dtos; -using JT808.DotNetty.Core.Configurations; -using JT808.DotNetty.Core.Services; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; - -namespace JT808.DotNetty.Core.Test -{ - [TestClass] - public class JT808TransmitAddressFilterServiceTest - { - private JT808TransmitAddressFilterService jT808TransmitAddressFilterService; - - public JT808TransmitAddressFilterServiceTest() - { - var serverHostBuilder = new HostBuilder() - .ConfigureAppConfiguration((hostingContext, config) => - { - config.SetBasePath(AppDomain.CurrentDomain.BaseDirectory); - config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); - }) - .ConfigureServices((hostContext, services) => - { - services.AddSingleton(); - services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); - services.Configure(hostContext.Configuration.GetSection("JT808Configuration")); - services.AddSingleton(); - }); - var serviceProvider = serverHostBuilder.Build().Services; - jT808TransmitAddressFilterService = serviceProvider.GetService(); - jT808TransmitAddressFilterService.Add("127.0.0.1"); - } - - [TestMethod] - public void Test1() - { - Assert.IsTrue(jT808TransmitAddressFilterService.ContainsKey(new JT808IPAddressDto - { - Host = "127.0.0.1", - Port = 12348 - }.EndPoint)); - } - - [TestMethod] - public void Test2() - { - var result = jT808TransmitAddressFilterService.GetAll(); - } - - [TestMethod] - public void Test3() - { - var result1= jT808TransmitAddressFilterService.Add("127.0.0.1"); - Assert.AreEqual(JT808ResultCode.Ok, result1.Code); - Assert.IsTrue(result1.Data); - var result2 = jT808TransmitAddressFilterService.Remove("127.0.0.1"); - Assert.AreEqual(JT808ResultCode.Ok, result2.Code); - Assert.IsTrue(result2.Data); - } - - [TestMethod] - public void Test4() - { - var result2 = jT808TransmitAddressFilterService.Remove("127.0.0.1"); - Assert.AreEqual(JT808ResultCode.Ok, result2.Code); - Assert.IsFalse(result2.Data); - Assert.AreEqual("不能删除服务器配置的地址", result2.Message); - } - } -} diff --git a/src/JT808.DotNetty.Tests/JT808.DotNetty.Hosting/Program.cs b/src/JT808.DotNetty.Tests/JT808.DotNetty.Hosting/Program.cs index 30c39f5..b786a06 100644 --- a/src/JT808.DotNetty.Tests/JT808.DotNetty.Hosting/Program.cs +++ b/src/JT808.DotNetty.Tests/JT808.DotNetty.Hosting/Program.cs @@ -54,19 +54,9 @@ namespace JT808.DotNetty.Hosting services.AddSingleton(typeof(ILogger<>), typeof(Logger<>)); services.AddJT808Configure() .AddJT808NettyCore(hostContext.Configuration) - //自定义日志下发包 - .ReplaceDownlinkPacket() - //自定义会话通知(在线/离线)使用异步方式 - //.ReplaceSessionPublishing() - //自定义原包转发 使用异步方式 - //.ReplaceSourcePackageDispatcher .AddJT808TcpNettyHost() - // 自定义Tcp消息处理业务 - .ReplaceMsgIdHandler() .Builder() .AddJT808UdpNettyHost() - // 自定义Udp消息处理业务 - .ReplaceMsgIdHandler() .Builder() .AddJT808WebApiNettyHost() .Builder(); diff --git a/src/JT808.DotNetty.Tests/JT808.DotNetty.WebApi.Test/JT808DotNettyWebApiTest.cs b/src/JT808.DotNetty.Tests/JT808.DotNetty.WebApi.Test/JT808DotNettyWebApiTest.cs index bbb9014..3ef93bd 100644 --- a/src/JT808.DotNetty.Tests/JT808.DotNetty.WebApi.Test/JT808DotNettyWebApiTest.cs +++ b/src/JT808.DotNetty.Tests/JT808.DotNetty.WebApi.Test/JT808DotNettyWebApiTest.cs @@ -22,24 +22,12 @@ namespace JT808.DotNetty.WebApi.Test var api = HttpApi.Resolve(); } - [TestMethod] - public void GetSystemCollectTest() - { - var result = jT808DotNettyWebApi.GetSystemCollect().GetAwaiter().GetResult(); - } - [TestMethod] public void GetUdpAtomicCounterTest() { var result = jT808DotNettyWebApi.GetUdpAtomicCounter().GetAwaiter().GetResult(); } - [TestMethod] - public void GetUdpTrafficTest() - { - var result = jT808DotNettyWebApi.GetUdpTraffic().GetAwaiter().GetResult(); - } - [TestMethod] public void UnificationUdpSendTest() { @@ -61,44 +49,12 @@ namespace JT808.DotNetty.WebApi.Test var result = jT808DotNettyWebApi.GetUdpSessionAll().GetAwaiter().GetResult(); } - [TestMethod] - public void GetTcpTrafficTest() - { - var result = jT808DotNettyWebApi.GetTcpTraffic().GetAwaiter().GetResult(); - } - [TestMethod] public void GetTcpAtomicCounterTest() { var result = jT808DotNettyWebApi.GetTcpAtomicCounter().GetAwaiter().GetResult(); } - [TestMethod] - public void GetTransmitAllTest() - { - var result = jT808DotNettyWebApi.GetTransmitAll().GetAwaiter().GetResult(); - } - - [TestMethod] - public void RemoveTransmitAddressTest() - { - var result = jT808DotNettyWebApi.RemoveTransmitAddress(new Abstractions.Dtos.JT808IPAddressDto - { - Host = "127.0.0.1", - Port = 6561 - }).GetAwaiter().GetResult(); - } - - [TestMethod] - public void AddTransmitAddressTest() - { - var result = jT808DotNettyWebApi.AddTransmitAddress(new Abstractions.Dtos.JT808IPAddressDto - { - Host = "127.0.0.1", - Port = 6553 - }).GetAwaiter().GetResult(); - } - [TestMethod] public void UnificationTcpSendTest() { diff --git a/src/JT808.DotNetty.Udp/Handlers/JT808MsgIdDefaultUdpHandler.cs b/src/JT808.DotNetty.Udp/Handlers/JT808MsgIdDefaultUdpHandler.cs deleted file mode 100644 index 0092851..0000000 --- a/src/JT808.DotNetty.Udp/Handlers/JT808MsgIdDefaultUdpHandler.cs +++ /dev/null @@ -1,15 +0,0 @@ -using JT808.DotNetty.Core; -using JT808.DotNetty.Core.Handlers; - -namespace JT808.DotNetty.Udp.Handlers -{ - /// - /// 默认消息处理业务实现 - /// - internal class JT808MsgIdDefaultUdpHandler : JT808MsgIdUdpHandlerBase - { - public JT808MsgIdDefaultUdpHandler(JT808UdpSessionManager sessionManager) : base(sessionManager) - { - } - } -} diff --git a/src/JT808.DotNetty.Udp/Handlers/JT808UdpServerHandler.cs b/src/JT808.DotNetty.Udp/Handlers/JT808UdpServerHandler.cs index 41bb207..950c07d 100644 --- a/src/JT808.DotNetty.Udp/Handlers/JT808UdpServerHandler.cs +++ b/src/JT808.DotNetty.Udp/Handlers/JT808UdpServerHandler.cs @@ -3,14 +3,9 @@ using DotNetty.Transport.Channels; using JT808.Protocol; using System; using Microsoft.Extensions.Logging; -using DotNetty.Transport.Channels.Sockets; using JT808.DotNetty.Core.Metadata; -using JT808.DotNetty.Abstractions; using JT808.DotNetty.Core.Services; using JT808.DotNetty.Core; -using JT808.DotNetty.Core.Handlers; -using System.Threading.Tasks; -using JT808.DotNetty.Core.Interfaces; using JT808.DotNetty.Abstractions.Enums; using JT808.Protocol.Interfaces; @@ -21,96 +16,39 @@ namespace JT808.DotNetty.Udp.Handlers /// internal class JT808UdpServerHandler : SimpleChannelInboundHandler { - private readonly IJT808SourcePackageDispatcher jT808SourcePackageDispatcher; - private readonly JT808AtomicCounterService jT808AtomicCounterService; private readonly ILogger logger; private readonly JT808UdpSessionManager jT808UdpSessionManager; - private readonly JT808MsgIdUdpHandlerBase handler; - - private readonly JT808TrafficService jT808TrafficService; - - private readonly IJT808UplinkPacket jT808UplinkPacket; - - private readonly IJT808UdpCustomMsgIdHandler jT808UdpCustomMsgIdHandler; - - private readonly IJT808DatagramPacket jT808DatagramPacket; - - private readonly ILogger unknownLogger; - private readonly JT808Serializer JT808Serializer; public JT808UdpServerHandler( IJT808Config jT808Config, - IJT808DatagramPacket jT808DatagramPacket, - JT808TrafficServiceFactory jT808TrafficServiceFactory, ILoggerFactory loggerFactory, - IJT808SourcePackageDispatcher jT808SourcePackageDispatcher, - IJT808UplinkPacket jT808UplinkPacket, - JT808MsgIdUdpHandlerBase handler, JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory, - IJT808UdpCustomMsgIdHandler jT808UdpCustomMsgIdHandler, JT808UdpSessionManager jT808UdpSessionManager) { - this.jT808UdpCustomMsgIdHandler = jT808UdpCustomMsgIdHandler; - this.jT808DatagramPacket = jT808DatagramPacket; - this.jT808TrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.udp); - this.handler = handler; - this.jT808SourcePackageDispatcher = jT808SourcePackageDispatcher; this.jT808AtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); - this.jT808UplinkPacket = jT808UplinkPacket; this.jT808UdpSessionManager = jT808UdpSessionManager; logger = loggerFactory.CreateLogger(); JT808Serializer = jT808Config.GetSerializer(); - unknownLogger = loggerFactory.CreateLogger("udp_unknown_msgid"); } protected override void ChannelRead0(IChannelHandlerContext ctx, JT808UdpPackage msg) { try { - jT808SourcePackageDispatcher.SendAsync(msg.Buffer); - jT808UplinkPacket.ProcessorAsync(msg.Buffer, JT808TransportProtocolType.udp); //解析到头部,然后根据具体的消息Id通过队列去进行消费 //要是一定要解析到数据体可以在JT808MsgIdHandlerBase类中根据具体的消息, //解析具体的消息体,具体调用JT808Serializer.Deserialize JT808HeaderPackage jT808HeaderPackage = JT808Serializer.Deserialize(msg.Buffer); jT808AtomicCounterService.MsgSuccessIncrement(); - jT808TrafficService.ReceiveSize(msg.Buffer.Length); jT808UdpSessionManager.TryAdd(ctx.Channel, msg.Sender, jT808HeaderPackage.Header.TerminalPhoneNo); if (logger.IsEnabled(LogLevel.Trace)) { - logger.LogTrace("accept package success count<<<" + jT808AtomicCounterService.MsgSuccessCount.ToString()); - logger.LogTrace("accept msg <<< " + ByteBufferUtil.HexDump(msg.Buffer)); - } - if (handler.HandlerDict.TryGetValue(jT808HeaderPackage.Header.MsgId, out var handlerFunc)) - { - IJT808Reply jT808Response = handlerFunc(new JT808Request(jT808HeaderPackage, msg.Buffer)); - if (jT808Response != null) - { - var sendData = JT808Serializer.Serialize(jT808Response.Package, jT808Response.MinBufferSize); - ctx.WriteAndFlushAsync(jT808DatagramPacket.Create(sendData,msg.Sender)); - } - } - else - { - IJT808Reply jT808CustomMsgIdResponse = jT808UdpCustomMsgIdHandler.Proccesser(new JT808Request(jT808HeaderPackage, msg.Buffer)); - if (jT808CustomMsgIdResponse != null) - { - var sendData = JT808Serializer.Serialize(jT808CustomMsgIdResponse.Package, jT808CustomMsgIdResponse.MinBufferSize); - ctx.WriteAndFlushAsync(jT808DatagramPacket.Create(sendData, msg.Sender)); - } - else - { - //未知的消息类型已日志形式输出 - if (unknownLogger.IsEnabled(LogLevel.Debug)) - { - unknownLogger.LogDebug(ByteBufferUtil.HexDump(msg.Buffer)); - } - } + logger.LogTrace($"accept package success count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); } } catch (JT808.Protocol.Exceptions.JT808Exception ex) @@ -118,8 +56,7 @@ namespace JT808.DotNetty.Udp.Handlers jT808AtomicCounterService.MsgFailIncrement(); if (logger.IsEnabled(LogLevel.Error)) { - logger.LogError("accept package fail count<<<" + jT808AtomicCounterService.MsgFailCount.ToString()); - logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg.Buffer)); + logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); } } catch (Exception ex) @@ -127,13 +64,11 @@ namespace JT808.DotNetty.Udp.Handlers jT808AtomicCounterService.MsgFailIncrement(); if (logger.IsEnabled(LogLevel.Error)) { - logger.LogError("accept package fail count<<<" + jT808AtomicCounterService.MsgFailCount.ToString()); - logger.LogError(ex, "accept msg<<<" + ByteBufferUtil.HexDump(msg.Buffer)); + logger.LogError(ex, $"accept package fail count=>{jT808AtomicCounterService.MsgFailCount.ToString()},accept msg=>{ByteBufferUtil.HexDump(msg.Buffer)}"); } } } public override void ChannelReadComplete(IChannelHandlerContext context) => context.Flush(); - } } diff --git a/src/JT808.DotNetty.Udp/JT1078UdpBuilderDefault.cs b/src/JT808.DotNetty.Udp/JT1078UdpBuilderDefault.cs index 1fcd18f..f894297 100644 --- a/src/JT808.DotNetty.Udp/JT1078UdpBuilderDefault.cs +++ b/src/JT808.DotNetty.Udp/JT1078UdpBuilderDefault.cs @@ -1,10 +1,6 @@ -using JT808.DotNetty.Core.Handlers; -using JT808.DotNetty.Core.Interfaces; +using JT808.DotNetty.Core.Interfaces; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using System; -using System.Collections.Generic; -using System.Text; namespace JT808.DotNetty.Udp { @@ -22,18 +18,6 @@ namespace JT808.DotNetty.Udp return Instance; } - public IJT808UdpNettyBuilder ReplaceCustomMsgIdHandler() where T : IJT808UdpCustomMsgIdHandler - { - Instance.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808UdpCustomMsgIdHandler), typeof(T), ServiceLifetime.Singleton)); - return this; - } - - public IJT808UdpNettyBuilder ReplaceMsgIdHandler() where T : JT808MsgIdUdpHandlerBase - { - Instance.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(JT808MsgIdUdpHandlerBase), typeof(T), ServiceLifetime.Singleton)); - return this; - } - public IJT808UdpNettyBuilder ReplaceSessionService() where T : IJT808UdpSessionService { Instance.JT808Builder.Services.Replace(new ServiceDescriptor(typeof(IJT808UdpSessionService), typeof(T), ServiceLifetime.Singleton)); diff --git a/src/JT808.DotNetty.Udp/JT808UdpDotnettyExtensions.cs b/src/JT808.DotNetty.Udp/JT808UdpDotnettyExtensions.cs index 5f93ce9..9e74f3d 100644 --- a/src/JT808.DotNetty.Udp/JT808UdpDotnettyExtensions.cs +++ b/src/JT808.DotNetty.Udp/JT808UdpDotnettyExtensions.cs @@ -3,13 +3,11 @@ using JT808.DotNetty.Core.Codecs; using JT808.DotNetty.Core.Handlers; using JT808.DotNetty.Core.Impls; using JT808.DotNetty.Core.Interfaces; -using JT808.DotNetty.Core.Jobs; using JT808.DotNetty.Core.Services; using JT808.DotNetty.Internal; using JT808.DotNetty.Udp.Handlers; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Internal; using System; using System.Runtime.CompilerServices; @@ -21,16 +19,12 @@ namespace JT808.DotNetty.Udp { public static IJT808UdpNettyBuilder AddJT808UdpNettyHost(this IJT808NettyBuilder jT808NettyBuilder) { - jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); - jT808NettyBuilder.JT808Builder.Services.TryAddSingleton(); jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); jT808NettyBuilder.JT808Builder.Services.TryAddScoped(); - jT808NettyBuilder.JT808Builder.Services.AddHostedService(); - jT808NettyBuilder.JT808Builder.Services.AddHostedService(); jT808NettyBuilder.JT808Builder.Services.AddHostedService(); return new JT1078UdpBuilderDefault(jT808NettyBuilder); } diff --git a/src/JT808.DotNetty.WebApi/Handlers/JT808MsgIdDefaultWebApiHandler.cs b/src/JT808.DotNetty.WebApi/Handlers/JT808MsgIdDefaultWebApiHandler.cs index 0c7c775..83ab43d 100644 --- a/src/JT808.DotNetty.WebApi/Handlers/JT808MsgIdDefaultWebApiHandler.cs +++ b/src/JT808.DotNetty.WebApi/Handlers/JT808MsgIdDefaultWebApiHandler.cs @@ -18,8 +18,6 @@ namespace JT808.DotNetty.WebApi.Handlers private readonly JT808AtomicCounterService jT808UdpAtomicCounterService; - private readonly JT808TransmitAddressFilterService jT808TransmitAddressFilterService; - private readonly IJT808TcpSessionService jT808TcpSessionService; private readonly IJT808UdpSessionService jT808UdpSessionService; @@ -28,32 +26,19 @@ namespace JT808.DotNetty.WebApi.Handlers private readonly IJT808UnificationUdpSendService jT808UnificationUdpSendService; - private readonly JT808TrafficService jT808TcpTrafficService; - - private readonly JT808TrafficService jT808UdpTrafficService; - - private readonly JT808SimpleSystemCollectService jT808SimpleSystemCollectService; - /// /// TCP一套注入 /// /// public JT808MsgIdDefaultWebApiHandler( - JT808SimpleSystemCollectService jT808SimpleSystemCollectService, - JT808TrafficServiceFactory jT808TrafficServiceFactory, IJT808UnificationTcpSendService jT808UnificationTcpSendService, IJT808TcpSessionService jT808TcpSessionService, - JT808TransmitAddressFilterService jT808TransmitAddressFilterService, JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory ) { - this.jT808SimpleSystemCollectService = jT808SimpleSystemCollectService; - this.jT808TcpTrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.tcp); this.jT808UnificationTcpSendService = jT808UnificationTcpSendService; - this.jT808TcpSessionService = jT808TcpSessionService; - this.jT808TransmitAddressFilterService = jT808TransmitAddressFilterService; + this.jT808TcpSessionService = jT808TcpSessionService; this.jT808TcpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); - InitCommonRoute(); InitTcpRoute(); } @@ -62,19 +47,14 @@ namespace JT808.DotNetty.WebApi.Handlers /// /// public JT808MsgIdDefaultWebApiHandler( - JT808SimpleSystemCollectService jT808SimpleSystemCollectService, - JT808TrafficServiceFactory jT808TrafficServiceFactory, IJT808UdpSessionService jT808UdpSessionService, IJT808UnificationUdpSendService jT808UnificationUdpSendService, JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory ) { - this.jT808SimpleSystemCollectService = jT808SimpleSystemCollectService; - this.jT808UdpTrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.udp); this.jT808UdpSessionService = jT808UdpSessionService; this.jT808UnificationUdpSendService = jT808UnificationUdpSendService; this.jT808UdpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); - InitCommonRoute(); InitUdpRoute(); } @@ -84,27 +64,19 @@ namespace JT808.DotNetty.WebApi.Handlers /// /// public JT808MsgIdDefaultWebApiHandler( - JT808SimpleSystemCollectService jT808SimpleSystemCollectService, - JT808TrafficServiceFactory jT808TrafficServiceFactory, IJT808UnificationTcpSendService jT808UnificationTcpSendService, IJT808UnificationUdpSendService jT808UnificationUdpSendService, IJT808TcpSessionService jT808TcpSessionService, IJT808UdpSessionService jT808UdpSessionService, - JT808TransmitAddressFilterService jT808TransmitAddressFilterService, JT808AtomicCounterServiceFactory jT808AtomicCounterServiceFactory ) { - this.jT808SimpleSystemCollectService = jT808SimpleSystemCollectService; - this.jT808TcpTrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.tcp); - this.jT808UdpTrafficService = jT808TrafficServiceFactory.Create(JT808TransportProtocolType.udp); this.jT808UdpSessionService = jT808UdpSessionService; this.jT808UnificationTcpSendService = jT808UnificationTcpSendService; this.jT808UnificationUdpSendService = jT808UnificationUdpSendService; this.jT808TcpSessionService = jT808TcpSessionService; - this.jT808TransmitAddressFilterService = jT808TransmitAddressFilterService; this.jT808TcpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.tcp); this.jT808UdpAtomicCounterService = jT808AtomicCounterServiceFactory.Create(JT808TransportProtocolType.udp); - InitCommonRoute(); InitTcpRoute(); InitUdpRoute(); } @@ -161,44 +133,6 @@ namespace JT808.DotNetty.WebApi.Handlers return CreateJT808HttpResponse(result); } - /// - /// 添加转发过滤地址 - /// - /// - /// - public JT808HttpResponse AddTransmitAddress(JT808HttpRequest request) - { - if (string.IsNullOrEmpty(request.Json)) - { - return EmptyHttpResponse(); - } - return CreateJT808HttpResponse(jT808TransmitAddressFilterService.Add(request.Json)); - } - - /// - /// 删除转发过滤地址(不能删除在网关服务器配置文件配的地址) - /// - /// - /// - public JT808HttpResponse RemoveTransmitAddress(JT808HttpRequest request) - { - if (string.IsNullOrEmpty(request.Json)) - { - return EmptyHttpResponse(); - } - return CreateJT808HttpResponse(jT808TransmitAddressFilterService.Remove(request.Json)); - } - - /// - /// 获取转发过滤地址信息集合 - /// - /// - /// - public JT808HttpResponse GetTransmitAll(JT808HttpRequest request) - { - return CreateJT808HttpResponse(jT808TransmitAddressFilterService.GetAll()); - } - /// /// 获取Tcp包计数器 /// @@ -265,61 +199,12 @@ namespace JT808.DotNetty.WebApi.Handlers return CreateJT808HttpResponse(result); } - /// - /// 基于Tcp的流量获取 - /// - /// - /// - public JT808HttpResponse TrafficTcpGet(JT808HttpRequest request) - { - JT808ResultDto jT808ResultDto = new JT808ResultDto(); - jT808ResultDto.Data = new JT808TrafficInfoDto(); - jT808ResultDto.Data.TotalReceiveSize = (jT808TcpTrafficService.TotalReceiveSize * 1.0) / 1024; - jT808ResultDto.Data.TotalSendSize = (jT808TcpTrafficService.TotalSendSize * 1.0) / 1024; - return CreateJT808HttpResponse(jT808ResultDto); - } - - /// - /// 基于Udp的流量获取 - /// - /// - /// - public JT808HttpResponse TrafficUdpGet(JT808HttpRequest request) - { - JT808ResultDto jT808ResultDto = new JT808ResultDto(); - jT808ResultDto.Data = new JT808TrafficInfoDto(); - jT808ResultDto.Data.TotalReceiveSize = (jT808UdpTrafficService.TotalReceiveSize * 1.0) / 1024; - jT808ResultDto.Data.TotalSendSize = (jT808UdpTrafficService.TotalSendSize * 1.0) / 1024; - return CreateJT808HttpResponse(jT808ResultDto); - } - - /// - /// 获取当前系统进程使用率 - /// - /// - /// - public JT808HttpResponse SystemCollectGet(JT808HttpRequest request) - { - JT808ResultDto jT808ResultDto = new JT808ResultDto(); - jT808ResultDto.Data = jT808SimpleSystemCollectService.Get(); - return CreateJT808HttpResponse(jT808ResultDto); - } - - protected virtual void InitCommonRoute() - { - CreateRoute(JT808Constants.JT808WebApiRouteTable.SystemCollectGet, SystemCollectGet); - } - protected virtual void InitTcpRoute() { - CreateRoute(JT808Constants.JT808WebApiRouteTable.TransmitAdd, AddTransmitAddress); - CreateRoute(JT808Constants.JT808WebApiRouteTable.TransmitRemove, RemoveTransmitAddress); - CreateRoute(JT808Constants.JT808WebApiRouteTable.TransmitGetAll, GetTransmitAll); CreateRoute(JT808Constants.JT808WebApiRouteTable.GetTcpAtomicCounter, GetTcpAtomicCounter); CreateRoute(JT808Constants.JT808WebApiRouteTable.SessionTcpGetAll, GetTcpSessionAll); CreateRoute(JT808Constants.JT808WebApiRouteTable.SessionTcpRemoveByTerminalPhoneNo, RemoveTcpSessionByTerminalPhoneNo); CreateRoute(JT808Constants.JT808WebApiRouteTable.UnificationTcpSend, UnificationTcpSend); - CreateRoute(JT808Constants.JT808WebApiRouteTable.TrafficTcpGet, TrafficTcpGet); } protected virtual void InitUdpRoute() @@ -328,7 +213,6 @@ namespace JT808.DotNetty.WebApi.Handlers CreateRoute(JT808Constants.JT808WebApiRouteTable.UnificationUdpSend, UnificationUdpSend); CreateRoute(JT808Constants.JT808WebApiRouteTable.SessionUdpGetAll, GetUdpSessionAll); CreateRoute(JT808Constants.JT808WebApiRouteTable.SessionUdpRemoveByTerminalPhoneNo, RemoveUdpSessionByTerminalPhoneNo); - CreateRoute(JT808Constants.JT808WebApiRouteTable.TrafficUdpGet, TrafficUdpGet); } } } diff --git a/src/JT808.DotNetty.WebApiClientTool/IJT808DotNettyWebApi.cs b/src/JT808.DotNetty.WebApiClientTool/IJT808DotNettyWebApi.cs index 3f6613c..e96248b 100644 --- a/src/JT808.DotNetty.WebApiClientTool/IJT808DotNettyWebApi.cs +++ b/src/JT808.DotNetty.WebApiClientTool/IJT808DotNettyWebApi.cs @@ -29,38 +29,12 @@ namespace JT808.DotNetty.WebApiClientTool [HttpPost("Tcp/UnificationSend")] ITask> UnificationTcpSend([JsonContent]JT808UnificationSendRequestDto jT808UnificationSendRequestDto); /// - /// 添加转发过滤地址 - /// - /// - /// - [HttpPost("Tcp/Transmit/Add")] - ITask> AddTransmitAddress([JsonContent]JT808IPAddressDto jT808IPAddressDto); - /// - /// 删除转发过滤地址(不能删除在网关服务器配置文件配的地址) - /// - /// - /// - [HttpPost("Tcp/Transmit/Remove")] - ITask> RemoveTransmitAddress([JsonContent]JT808IPAddressDto jT808IPAddressDto); - /// - /// 获取转发过滤地址信息集合 - /// - /// - [HttpGet("Tcp/Transmit/GetAll")] - ITask>> GetTransmitAll(); - /// /// 获取Tcp包计数器 /// /// /// [HttpGet("Tcp/GetAtomicCounter")] ITask> GetTcpAtomicCounter(); - /// - /// 基于Tcp的流量获取 - /// - /// - [HttpGet("Tcp/Traffic/Get")] - ITask> GetTcpTraffic(); #endregion @@ -87,26 +61,11 @@ namespace JT808.DotNetty.WebApiClientTool [HttpPost("Udp/UnificationSend")] ITask> UnificationUdpSend([JsonContent]JT808UnificationSendRequestDto jT808UnificationSendRequestDto); /// - /// 基于Udp的流量获取 - /// - /// - [HttpGet("Udp/Traffic/Get")] - ITask> GetUdpTraffic(); - /// /// 获取Udp包计数器 /// /// [HttpGet("Udp/GetAtomicCounter")] ITask> GetUdpAtomicCounter(); #endregion - - #region 公共部分 - /// - /// 获取当前系统进程使用率 - /// - /// - [HttpGet("SystemCollect/Get")] - ITask> GetSystemCollect(); - #endregion } }