From a2c56938e7b6c5ac012dd5d7e395c928fc1533fd Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 22 Aug 2007 22:56:00 +0000 Subject: [PATCH] Recovered from cvs revision 2007-08-22 11:25:00 --- ase/awk/Awk.cpp | 6 +- ase/awk/Awk.hpp | 8 +- ase/awk/StdAwk.cpp | 4 +- ase/awk/run.c | 4 +- ase/change.log | 1 + ase/net/Awk.cpp | 179 +++++++++++++++++++++++++++++++++++----- ase/net/Awk.hpp | 45 +++++++--- ase/net/StdAwk.cpp | 12 +-- ase/net/misc.cpp | 4 +- ase/test/net/AwkForm.cs | Bin 1881 -> 5108 bytes 10 files changed, 215 insertions(+), 48 deletions(-) diff --git a/ase/awk/Awk.cpp b/ase/awk/Awk.cpp index 4eb95116..67381b77 100644 --- a/ase/awk/Awk.cpp +++ b/ase/awk/Awk.cpp @@ -1,7 +1,8 @@ /* - * $Id: Awk.cpp,v 1.48 2007/08/18 15:41:46 bacon Exp $ + * $Id: Awk.cpp,v 1.49 2007/08/21 14:24:37 bacon Exp $ */ + #include #include #include @@ -568,7 +569,7 @@ namespace ASE ase_awk_setmaxdepth (awk, ids, depth); } - int Awk::getMaxDepth (int id) const + size_t Awk::getMaxDepth (int id) const { ASE_ASSERT (awk != ASE_NULL); return ase_awk_getmaxdepth (awk, id); @@ -1014,7 +1015,6 @@ namespace ASE { Run* r = (Run*)custom; if (r->callbackFailed) return; - r->awk->onRunStatement (*r, line); } diff --git a/ase/awk/Awk.hpp b/ase/awk/Awk.hpp index b7f0e71d..b87ad1f9 100644 --- a/ase/awk/Awk.hpp +++ b/ase/awk/Awk.hpp @@ -1,5 +1,5 @@ /* - * $Id: Awk.hpp,v 1.46 2007/08/18 15:41:46 bacon Exp $ + * $Id: Awk.hpp,v 1.47 2007/08/21 14:24:37 bacon Exp $ */ #ifndef _ASE_AWK_AWK_HPP_ @@ -409,8 +409,8 @@ namespace ASE DEPTH_REX_MATCH = ASE_AWK_DEPTH_REX_MATCH }; - virtual void setMaxDepth (int ids, size_t depth); - virtual int getMaxDepth (int id) const; + virtual void setMaxDepth (int ids, size_t depth); + virtual size_t getMaxDepth (int id) const; virtual int setErrorString (ErrorCode num, const char_t* str); @@ -477,7 +477,7 @@ namespace ASE virtual void onRunEnd (const Run& run); virtual void onRunReturn (const Run& run, const Argument& ret); virtual void onRunStatement (const Run& run, size_t line); - + // primitive handlers virtual void* allocMem (size_t n) = 0; virtual void* reallocMem (void* ptr, size_t n) = 0; diff --git a/ase/awk/StdAwk.cpp b/ase/awk/StdAwk.cpp index a3e05524..7bf20155 100644 --- a/ase/awk/StdAwk.cpp +++ b/ase/awk/StdAwk.cpp @@ -1,5 +1,5 @@ /* - * $Id: StdAwk.cpp,v 1.22 2007/07/15 16:31:59 bacon Exp $ + * $Id: StdAwk.cpp,v 1.23 2007/08/21 14:24:37 bacon Exp $ */ #include @@ -22,7 +22,7 @@ namespace ASE StdAwk::StdAwk () { - seed = ::time(NULL); + seed = (unsigned int)::time(NULL); ::srand (seed); } diff --git a/ase/awk/run.c b/ase/awk/run.c index 6405dc44..6fdaa7a8 100644 --- a/ase/awk/run.c +++ b/ase/awk/run.c @@ -1,5 +1,5 @@ /* - * $Id: run.c,v 1.9 2007/07/25 07:00:09 bacon Exp $ + * $Id: run.c,v 1.10 2007/08/21 14:24:37 bacon Exp $ * * {License} */ @@ -1724,7 +1724,7 @@ static int __run_block0 (ase_awk_run_t* run, ase_awk_nde_blk_t* nde) (run)->cbs->on_statement != ASE_NULL) \ { \ (run)->cbs->on_statement ( \ - run, (nde)->line, (run)->custom_data); \ + run, (nde)->line, (run)->cbs->custom_data); \ } static int __run_statement (ase_awk_run_t* run, ase_awk_nde_t* nde) diff --git a/ase/change.log b/ase/change.log index 5ce4f5a5..192db5fa 100644 --- a/ase/change.log +++ b/ase/change.log @@ -8,6 +8,7 @@ * added the error code ASE_AWK_ELXDIG to indicate a wrong digit in octal number tokenization. * added setWord/unsetWord method to the awk com module (com/Awk.cpp) +* added the .NET interface to the awk interpreter (net/Awk.cpp net/StdAwk.cpp) * changed the wrong macro name WIN32 to _WIN32 in utl/stdio.h * changed test/awk/Awk.cpp to include an option(-w) to utilize diff --git a/ase/net/Awk.cpp b/ase/net/Awk.cpp index 36a5726c..0f6f8da9 100644 --- a/ase/net/Awk.cpp +++ b/ase/net/Awk.cpp @@ -1,5 +1,5 @@ /* - * $Id: Awk.cpp,v 1.17 2007/08/20 14:19:58 bacon Exp $ + * $Id: Awk.cpp,v 1.18 2007/08/21 14:24:37 bacon Exp $ */ #include "stdafx.h" @@ -15,6 +15,8 @@ using System::Runtime::InteropServices::GCHandle; +extern "C" void outputxxx (const wchar_t* x); + namespace ASE { @@ -76,6 +78,89 @@ namespace ASE return n; } + int setWord (ASE::Net::Awk^ wrapper, const char_t* ow, size_t olen, const char_t* nw, size_t nlen) + { + this->wrapper = wrapper; + int n = Awk::setWord (ow, olen, nw, nlen); + this->wrapper = nullptr; + return n; + } + + int unsetWord (ASE::Net::Awk^ wrapper, const char_t* ow, size_t olen) + { + this->wrapper = wrapper; + int n = Awk::unsetWord (ow, olen); + this->wrapper = nullptr; + return n; + } + + int unsetAllWords (ASE::Net::Awk^ wrapper) + { + this->wrapper = wrapper; + int n = Awk::unsetAllWords (); + this->wrapper = nullptr; + return n; + } + + void setMaxDepth (ASE::Net::Awk^ wrapper, int ids, size_t depth) + { + this->wrapper = wrapper; + Awk::setMaxDepth (ids, depth); + this->wrapper = nullptr; + } + + size_t getMaxDepth (ASE::Net::Awk^ wrapper, int id) const + { + this->wrapper = wrapper; + size_t n = Awk::getMaxDepth (id); + this->wrapper = nullptr; + return n; + } + + void enableRunCallback (ASE::Net::Awk^ wrapper) + { + this->wrapper = wrapper; + Awk::enableRunCallback (); + this->wrapper = nullptr; + } + + void disableRunCallback (ASE::Net::Awk^ wrapper) + { + this->wrapper = wrapper; + Awk::disableRunCallback (); + this->wrapper = nullptr; + } + + void onRunStart (const Run& run) + { + if (wrapper->OnRunStart != nullptr) + { + wrapper->OnRunStart (); + } + } + void onRunEnd (const Run& run) + { + if (wrapper->OnRunEnd != nullptr) + { + wrapper->OnRunEnd (); + } + } + void onRunReturn (const Run& run, const Argument& ret) + { + if (wrapper->OnRunReturn != nullptr) + { + wrapper->OnRunReturn (); + } + } + + void onRunStatement (const Run& run, size_t line) + { + if (wrapper->OnRunStatement != nullptr) + { + wrapper->OnRunStatement (); + } + } + int addFunction ( ASE::Net::Awk^ wrapper, const char_t* name, size_t minArgs, size_t maxArgs, FunctionHandler handler) @@ -121,7 +206,7 @@ namespace ASE int closeSource (Source& io) { - IntPtr ip ((void*)io.getHandle ()); + System::IntPtr ip ((void*)io.getHandle ()); GCHandle gh = GCHandle::FromIntPtr (ip); try @@ -135,7 +220,7 @@ namespace ASE ssize_t readSource (Source& io, char_t* buf, size_t len) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); cli::array^ b = nullptr; @@ -154,7 +239,7 @@ namespace ASE ssize_t writeSource (Source& io, char_t* buf, size_t len) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); cli::array^ b = nullptr; @@ -189,7 +274,7 @@ namespace ASE int closePipe (Pipe& io) { - IntPtr ip ((void*)io.getHandle ()); + System::IntPtr ip ((void*)io.getHandle ()); GCHandle gh = GCHandle::FromIntPtr (ip); try @@ -203,7 +288,7 @@ namespace ASE ssize_t readPipe (Pipe& io, char_t* buf, size_t len) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); cli::array^ b = nullptr; @@ -222,7 +307,7 @@ namespace ASE ssize_t writePipe (Pipe& io, char_t* buf, size_t len) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); cli::array^ b = nullptr; @@ -239,7 +324,7 @@ namespace ASE int flushPipe (Pipe& io) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); try @@ -270,7 +355,7 @@ namespace ASE int closeFile (File& io) { - IntPtr ip ((void*)io.getHandle ()); + System::IntPtr ip ((void*)io.getHandle ()); GCHandle gh = GCHandle::FromIntPtr (ip); try @@ -284,7 +369,7 @@ namespace ASE ssize_t readFile (File& io, char_t* buf, size_t len) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); cli::array^ b = nullptr; @@ -302,7 +387,7 @@ namespace ASE ssize_t writeFile (File& io, char_t* buf, size_t len) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); cli::array^ b = nullptr; @@ -319,7 +404,7 @@ namespace ASE int flushFile (File& io) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); try @@ -350,7 +435,7 @@ namespace ASE int closeConsole (Console& io) { - IntPtr ip ((void*)io.getHandle ()); + System::IntPtr ip ((void*)io.getHandle ()); GCHandle gh = GCHandle::FromIntPtr (ip); try @@ -364,7 +449,7 @@ namespace ASE ssize_t readConsole (Console& io, char_t* buf, size_t len) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); cli::array^ b = nullptr; @@ -382,7 +467,7 @@ namespace ASE ssize_t writeConsole (Console& io, char_t* buf, size_t len) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); cli::array^ b = nullptr; @@ -399,7 +484,7 @@ namespace ASE int flushConsole (Console& io) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); try @@ -412,7 +497,7 @@ namespace ASE int nextConsole (Console& io) { - IntPtr ip ((void*)io.getHandle()); + System::IntPtr ip ((void*)io.getHandle()); GCHandle gh = GCHandle::FromIntPtr (ip); try @@ -524,7 +609,19 @@ System::Diagnostics::Debug::Print ("Awk::!Awk"); void Awk::Close () { - if (awk != NULL) awk->close (this); + if (awk != NULL) + { + awk->close (this); + delete awk; + awk = NULL; + } + + if (funcs != nullptr) + { + funcs->Clear (); + delete funcs; + funcs = nullptr; + } } bool Awk::Parse () @@ -536,6 +633,13 @@ System::Diagnostics::Debug::Print ("Awk::!Awk"); bool Awk::Run () { if (awk == NULL) return false; + + if (OnRunStart != nullptr || OnRunEnd != nullptr || + OnRunReturn != nullptr || OnRunStatement != nullptr) + { + awk->enableRunCallback (this); + } + return awk->run (this) == 0; } @@ -543,6 +647,7 @@ System::Diagnostics::Debug::Print ("Awk::!Awk"); System::String^ name, int minArgs, int maxArgs, FunctionHandler^ handler) { + if (awk == NULL) return false; cli::pin_ptr nptr = PtrToStringChars(name); int n = awk->addFunction (this, nptr, minArgs, maxArgs, (ASE::Awk::FunctionHandler)&MojoAwk::mojoFunctionHandler); @@ -552,6 +657,7 @@ System::Diagnostics::Debug::Print ("Awk::!Awk"); bool Awk::DeleteFunction (System::String^ name) { + if (awk == NULL) return false; cli::pin_ptr nptr = PtrToStringChars(name); int n = awk->deleteFunction (this, nptr); if (n == 0) funcs->Remove (name); @@ -565,7 +671,7 @@ System::Diagnostics::Debug::Print ("Awk::!Awk"); System::String^ nm = gcnew System::String (name, 0, len); FunctionHandler^ fh = (FunctionHandler^)funcs[nm]; - if (fh == nullptr) return -1; + if (fh == nullptr) return false; cli::array^ arg_arr = gcnew cli::array (nargs); for (size_t i = 0; i < nargs; i++) arg_arr[i] = gcnew Argument(args[i]); @@ -574,6 +680,41 @@ System::Diagnostics::Debug::Print ("Awk::!Awk"); return fh(nm, arg_arr, r); } + bool Awk::SetWord (System::String^ ow, System::String^ nw) + { + if (awk == NULL) return false; + cli::pin_ptr optr = PtrToStringChars(ow); + cli::pin_ptr nptr = PtrToStringChars(nw); + return (awk->setWord (this, optr, ow->Length, nptr, nw->Length) == 0); + } + + bool Awk::UnsetWord (System::String^ ow) + { + if (awk == NULL) return false; + cli::pin_ptr optr = PtrToStringChars(ow); + return (awk->unsetWord (this, optr, ow->Length) == 0); + } + + bool Awk::UnsetAllWords () + { + if (awk == NULL) return false; + return (awk->unsetAllWords (this) == 0); + } + + bool Awk::SetMaxDepth (DEPTH id, size_t depth) + { + if (awk == NULL) return false; + awk->setMaxDepth (this, (int)id, depth); + return true; + } + + bool Awk::GetMaxDepth (DEPTH id, size_t* depth) + { + if (awk == NULL) return false; + *depth = awk->getMaxDepth (this, (int)id); + return true; + } + } } diff --git a/ase/net/Awk.hpp b/ase/net/Awk.hpp index bd1d70bb..658daaaf 100644 --- a/ase/net/Awk.hpp +++ b/ase/net/Awk.hpp @@ -1,5 +1,5 @@ /* - * $Id: Awk.hpp,v 1.14 2007/08/20 14:19:58 bacon Exp $ + * $Id: Awk.hpp,v 1.15 2007/08/21 14:24:37 bacon Exp $ */ #pragma once @@ -7,8 +7,6 @@ #include #include -using namespace System; - namespace ASE { class MojoAwk; @@ -22,6 +20,9 @@ namespace ASE typedef ASE::Awk::real_t real_t; typedef ASE::Awk::char_t char_t; typedef ASE::Awk::size_t size_t; + typedef ASE::Awk::ssize_t ssize_t; + typedef ASE::Awk::cint_t cint_t; + typedef ASE::Awk::bool_t bool_t; ref class Argument { @@ -297,7 +298,7 @@ namespace ASE }; - [Flags] enum class OPTION: int + [System::Flags] enum class OPTION: int { NONE = 0, IMPLICIT = ASE::Awk::OPT_IMPLICIT, @@ -317,22 +318,46 @@ namespace ASE ARGSTOMAIN = ASE::Awk::OPT_ARGSTOMAIN }; + enum class DEPTH: int + { + BLOCK_PARSE = ASE::Awk::DEPTH_BLOCK_PARSE, + BLOCK_RUN = ASE::Awk::DEPTH_BLOCK_RUN, + EXPR_PARSE = ASE::Awk::DEPTH_EXPR_PARSE, + EXPR_RUN = ASE::Awk::DEPTH_EXPR_RUN, + REX_BUILD = ASE::Awk::DEPTH_REX_BUILD, + REX_MATCH = ASE::Awk::DEPTH_REX_MATCH + }; + typedef ASE::Awk::char_t char_t; Awk (); !Awk (); virtual ~Awk (); - //bool Open (); - void Close (); + virtual void Close (); + virtual bool Parse (); + virtual bool Run (); - bool Parse (); - bool Run (); + delegate void RunStartHandler (); + delegate void RunEndHandler (); + delegate void RunReturnHandler (); + delegate void RunStatementHandler (); + + /*event*/ RunStartHandler^ OnRunStart; + /*event*/ RunEndHandler^ OnRunEnd; + /*event*/ RunReturnHandler^ OnRunReturn; + /*event*/ RunStatementHandler^ OnRunStatement; delegate bool FunctionHandler (System::String^ name, array^ args, Return^ ret); + virtual bool AddFunction (System::String^ name, int minArgs, int maxArgs, FunctionHandler^ handler); + virtual bool DeleteFunction (System::String^ name); + + virtual bool SetWord (System::String^ ow, System::String^ nw); + virtual bool UnsetWord (System::String^ ow); + virtual bool UnsetAllWords (); - bool AddFunction (System::String^ name, int minArgs, int maxArgs, FunctionHandler^ handler); - bool DeleteFunction (System::String^ name); + virtual bool SetMaxDepth (DEPTH id, size_t depth); + virtual bool GetMaxDepth (DEPTH id, size_t* depth); property OPTION Option { diff --git a/ase/net/StdAwk.cpp b/ase/net/StdAwk.cpp index 0581327c..54bf417b 100644 --- a/ase/net/StdAwk.cpp +++ b/ase/net/StdAwk.cpp @@ -1,5 +1,5 @@ /* - * $Id: StdAwk.cpp,v 1.5 2007/08/20 14:27:47 bacon Exp $ + * $Id: StdAwk.cpp,v 1.6 2007/08/21 14:24:37 bacon Exp $ */ #include "stdafx.h" @@ -136,20 +136,20 @@ namespace ASE if (fp == NULL) return -1; - pipe->Handle = IntPtr ((void*)fp); + pipe->Handle = System::IntPtr ((void*)fp); return 1; } int StdAwk::ClosePipe (Pipe^ pipe) { - IntPtr ip = (IntPtr)pipe->Handle; + System::IntPtr ip = (System::IntPtr)pipe->Handle; FILE* fp = (FILE*)ip.ToPointer(); return (::_pclose (fp) == EOF)? -1: 0; } int StdAwk::ReadPipe (Pipe^ pipe, cli::array^ buf, int len) { - IntPtr ip = (IntPtr)pipe->Handle; + System::IntPtr ip = (System::IntPtr)pipe->Handle; FILE* fp = (FILE*)ip.ToPointer(); int n = 0; @@ -168,7 +168,7 @@ namespace ASE int StdAwk::WritePipe (Pipe^ pipe, cli::array^ buf, int len) { - IntPtr ip = (IntPtr)pipe->Handle; + System::IntPtr ip = (System::IntPtr)pipe->Handle; FILE* fp = (FILE*)ip.ToPointer(); int left; @@ -228,7 +228,7 @@ namespace ASE int StdAwk::FlushPipe (Pipe^ pipe) { - IntPtr ip = (IntPtr)pipe->Handle; + System::IntPtr ip = (System::IntPtr)pipe->Handle; FILE* fp = (FILE*)ip.ToPointer(); return (::fflush (fp) == EOF)? -1: 0; } diff --git a/ase/net/misc.cpp b/ase/net/misc.cpp index 59f13a16..6cc82ee6 100644 --- a/ase/net/misc.cpp +++ b/ase/net/misc.cpp @@ -1,5 +1,5 @@ /* - * $Id: misc.cpp,v 1.1 2007/07/20 09:23:37 bacon Exp $ + * $Id: misc.cpp,v 1.2 2007/08/21 14:24:37 bacon Exp $ */ #include "stdafx.h" @@ -52,4 +52,4 @@ char* unicode_to_multibyte (const wchar_t* in, int inlen, int* outlen) *outlen = WideCharToMultiByte (CP_UTF8, 0, in, inlen, ptr, n, NULL, 0); return ptr; -} \ No newline at end of file +} diff --git a/ase/test/net/AwkForm.cs b/ase/test/net/AwkForm.cs index caedb5dd9b5b73d494429175d607df41bdcbeeb1..d5648fd60b80a82324d0377e3bc4294bd28ef20e 100644 GIT binary patch literal 5108 zcmcgw(Q?yP5ZzbxD}uIGH;K(iGD%?gi2hPv`V)K$ zaL!$?@4b>0iH9&697(>rckkJ=XV-lBypmGpvXCQ5TG?=u5%BvZ zMD`Hfe6#ml-Xmr*BhD$U70(1aesrF6_e6H&2F|j?#n_dLLw9a6NO@@({pe0~AS3YX zcZX26J|X`W;PA>}Ngf@_Ypfo-x20TW`NDZxVdVlAg?rk5+8soz-)FLmh&2njymZK~ zV42D<_!rhu21b*oGsJx0PBh#^bttzHWhRV(x$}NPypqkH&2?9~pCM9Vf1WMO;0++b z3|barM!o|!b5wDPO46&1KQU76HANIz4JB|o!rcSxaPAPD;qDAO4P~&|EtOk%!`fl~ zD|{2;sr(}o+oHaJ4)VI{s2Q{Er7=?jr(5IgLi!kWe*9e`evc~Wr4egAC|AA}XY=$u zaJIcdZfK{|zSAB%b?6~`sd#Qq^-~v0F>3N)!rsW7esQ+qZ8rNmT{#H3& zuoJ7T>ROkjMjF<$*<0PKhY;mCs)7}9ZNr4;?zF7eA>yd>l(P;yM&(d!ejlrA{NRvJA?oM&Ui zHTdf00Q*?12le@yC~)4$P+g`)u|*S|J}Rdeb0#vc+Y~PT#Yj|}Z!A8}VN0-@8eWen z?AN>C5`S}tYtx`w!rU6R_RgN)y2@#v4Rt1{*Y#D+ik5TbRDD;krWvM!9K1L}Ma;nY zrc%Tz(NCT9tkyT%cdzH9D_X6|wmGo55C3;#0-Y=y`M2!V+0&IpGK#;?3v>+rk5_%q U^2(m)|$RB2tSQf&_vnoPKYhq00E6uOH4eRqxtZJLKp z0utZv`|dkaI;rPu{Omle`f2&<#D_*HD7-Y<@o%8P%Ho~HYHc)Ve{E)<8p;ddMN?$O z2Gcd9_ptR1(J!fIX5;v!u`AcmUETE4RErh3wJ3lI2OgZ);M12hS(j5K3$_;4OQBey zgmY}LSyCYOiP0lX&~9%SRoO9$NSs`0NuKgA3{7kHV^gp1O8t9?U@kK={ewJU z4)hFcmyMpVJM7Xic-2HjoeU9R0>9@>!-kO0j>#y=^G9P@Cbef0mAyVbKC`nPy_}u~ zlYoEH5&-9o5fVS$j!kI`xGDX*^qhEup*kIEBB+N*Rij$;!647EFg}>gE=wI~opo@K zoh~~IAAGM+P2?lXj>z^_SO;01_ex{hF00Q~9aVo7dy?cDoD*~SYPNj5Fq^CsVlc4Q z*iMX(U^LAr+lXwUB3kZ3;h-FZmzN3%q+vKF!ApDld}|2Ub5=~Zqxu{Gs;~)`dt$nK zb1)*O#qt){q*cv_3n-Q_>sK5>n8O0-7&bqlyqf5Vfz)(c2jN$Ep*XxlN{!1+^9it4 zre9buOg!!!>Z)yuD}$kkJW&>0CNW0R#-d9VVHQ@(0%vMog*z%