< \?Ln%NDi ])}@ 1Z]~oN2kvRαf$ƙ ہ h#A"ET'G' %*䜝]g-7jկU3S‡)m| ތ"$*XmPԘ-;_Ս\\Vj{BExm!&5o{ {&|h.be0=Dn 5g.DoLzJq\={٤Z"3mg1!2QQ=FAa6i1gx_EhomwmeJP# Wj?h,?k7,Y='?-7j ̎?|$]ؐ=EZrMЫ3dAdURM%ztgapTNww;}s|O;psQpy5C}u}Nl2kv}ߠZHH iphXАW6=k$x3 .._( pЗ]9l[9ˏ8PGɗД0cJ:if4ֵP9V K4vX|= !aY͢'DbH2Pxrn,]>~)2q[vA1쓎G±o$_W{@0<>l cl_ERޔYw?(߈pN1,":o5hBnp U[FԼDAPD`Z.%3=6̐gk40"?0/jhU(pX22>Vt'P@ Td+/*r/zx@9J~7/_LnhyZD m~{a WpWE9 lc'']6~[ڴjeg0EQijO -ZV/*;se!>votmϝ9JLWPoc)DE[8fCelZ7q 1[82nK?! Wkeȁc'b7Gǵ^0`72rb =DW1اcx9+O/EL1 .X&2^&ٹ쳦hUQ)*r66jpÏ#6Ylk=l\uzǨ1լ[ ŔjqѸ.߃HSql!ՒHWUmf>?,Tv2dY /H8(lŀJorCQ9 xaw3T E\\S5/5chy`@hM]))@ P>s[1ZSӄP@YRfc7}Nqh𗨾歶waJ\,a]~ltRxrc{NwgkjTga_BepH`\F=.#S>I?nu~u05j1w"0Y'<.zN1O'!(y*acS).jI 5i4d6#3ЭwTd|%YZfr$M~,Ei9N1\,'4WE3U7"#(q3h;ؒ X^P-16^'OvZ 9`KtfCFJq(.ÄX+χ?oieŃF/2̆HdC_4=tdeNt*L%H-^wӐ^b{HC_z}t*])4c"l 8@/OP%Va*#o]2 JWb;WVb>?uǐx㹼pƦ VN7ɞvri!Fe?G-(Z65݌='ZlʑkR]_`V/ (VՎsz -d 3F3 N`>ek#mevICХRg_I\qlu9 B떤u$Q1̳l(g=n_Bu`yb}Xwc-}ɜIs DCUp2hK_UT;%Wėo8ڮ?W'Xt{* I6^{ҴN:)VpٔE+Bp2H#*x%3-2Gһ: ϻb&8g?p٧JH'/z~aΥ=0!~t ПRώi.(de82Nן .v/z?8N+V)? xVS@Kn:P%GvW \1\:6u^K%mf )P 9ĦX)z)!z{e >x9pV%7v']Qj_wάAW44[j2?nF:xz3e`]v)y9/VDA@_ۋB(xPkBVIp,ؙ_ hh \kq=S@&xP97Btkh|9阖k[!9}ԍȹH**D 2eAG|כ֞mۀyY]wP}«vUȮgYlTXNg1V5]ᴆ6m+v`F5G z!գcziij#ՐQ}igd ,p- C1x"e+cIsаXk 5$vC)h7^7.{M]I4܉ [*^wMrߖ'֡_f`'\FZn u)~VBd  NB;!rI˺}Bݥφ-@RK_h3ox0 /,So2z? '(`-@8_4ZKIJl+ֹXlQv1G/^]Є<Jyɑz+Pq AykiLG/(TulU"wBem=kJ:@B{"US/0y/k lLCid@oW\?) ^!)̢@/ZRXE>#-pFk%qQBGWBt+۳ $eq,tx+5qPkNkuUNOn[Uэ< x*C gioS0_5|~De %!i5 \tRfXQZ8 gy{2|@#Rg i#`U={ 8@SJEfw"&A_G 2>B(ġ s)zzN +cAڣ&}_@9il}P->ayN$9[A?(޽֓mUP:]B su?[و|lUUKdAT\*BBૹqR{a1(ED5B 썤вW%& !z+uݔHxٞ)գ~o;;e7VwänGRe*ɱ2gZFR}7c?;6xw#` nx䨣RLT"v[.@ݝZDŽ]g܆ $=usc`2df(z d'%rd HB.# 0-ڿJg@z>`#3:$'𠵙I:9jQ 1uY|{u=9BIVXzc3)w"K( lR@d,y+ @݁I#XA~JgsrJ~.hgK0-;D.Hcd>oh^7Qz%Cmʊ%O3g&? 0<;8 H ɺ7 |"EXUR[;3Ho.i0MsBp71,'&!h6−m$MNAcRWu(2amJ}-tbAI^Qɒ6n̙v"(֩RC!jZQDt^ <+qk"&Z3|fCX"UwYzw9ܫ}cXP'f%9[e<6Sv}읣XǨYO"_-f46הi3U& k]552c=lth%)k,mI,~V&̀[,y_Ǖ1hA棛:RSo)#ؿ%_ÄX%=+ͻ~ӎ6} T*_ϕVFiX"Xg0+GQA_ip,rn*cwx1=S_IqlpI9GsnhE`v SɱЅEjx?V," gSB^ DN+<\ʪO@WrEIJ%3(gA\ ja. #W +jHu1LE^{>/1!QSɯa HaQ|ok@uUGf@^a8߯gӰ]*>'  ⚄tƪoMX:RS/B#tTD疅aR*k;ɲ8D =EHQL b#Ѣkc|`D {#/P-V yp2&B7V9n  Ա ƕL[0n@f¶X]j JVomO7_lEXAuQ*߃t7ơ%v~:wB {O&nL/_6Rϙ<2%D[`*pPrY?^~d"w)f@ {&}7nu5'g-YjP]ѽ- ĞB㿐А|Ǵ F✧RnK!-cUq9hiL R6ul/߆ VPLB '4Kھ~WȣQǹD~?K=CYV>JrC5Dd-+o\dcg=DWȠנ4dOz.ZD7 K`M !͔8=zn}UEE /gi=( &s?G \-4V2kqfϒO+nQPòm0B`aV%2p`bׅF٬a)!Fkh51zc8s` ,pgpcOWI4C+tk3Aɳ uF3ȭb.k34Nw FK6 iΣ ;Bԧ9^0΃ Oxz=4˧K'ƹ^sFҵGd**M6G(WMrBge ٲ return date_format(date_create(), 'Y-m-d H:i:s:u'); } /** * 开始一个任务,如果任务不存在则创建新任务 * @param {string} taskmemo 任务说明 */ public function newTask($taskmemo) { $this->cur_state = $this->data[Scheduler::$START_KEY]; $db = $this->localStorage; //设置任务状态 $stateInfo = $this->setProcessingInfo($this->actionid, $taskmemo); //保存任务建立信息 $db->setRoot($this->getTaskRoot()); $db->sets($stateInfo); $this->localStorage->save(); return $stateInfo; } protected function createProcessingInfo($actionid, $memo, $docode = 0, $state = null) { $stateInfo = array( "actionid" => $actionid, "state" => (empty($state) ? $this->cur_state : $state), "taskid" => $this->taskid, "execute" => $docode, "userid" => $this->userid, "memo" => empty($memo) ? "" : $memo, "time" => Scheduler::now(), ); return $stateInfo; } protected function addTraceInfo($stateInfo) { /** * 保存当前的状态执行信息到追踪列表 */ $db = $this->localStorage; $db->setRoot($this->getTaskTraceRoot()); $db->addToList($stateInfo); } //设置任务的运行信息 protected function setProcessingInfo($actionid, $memo) { $db = $this->localStorage; //设置任务运行状态 $stateInfo = $this->createProcessingInfo($actionid, $memo); $db->setRoot($this->getTaskProcessingActionRoot($actionid)); $db->sets($stateInfo); $this->addTraceInfo($stateInfo); return $stateInfo; } //获取任务的运行信息 protected function getProcessingInfo($actionid) { $db = $this->localStorage; $root = $this->getTaskProcessingActionRoot($actionid); $db->setRoot($root); return $db->all(); } protected function deleteProcessingInfos() { $db = $this->localStorage; $oldstate = $this->cur_state; $deleteKeys = array(); foreach ($this->data[self::$STATE_ROOT_KEY] as $state => $stateinfo) { if (empty($stateinfo[self::$STATE_ACTION_ROOT_KEY])) continue; $this->cur_state = $state; foreach ($stateinfo[self::$STATE_ACTION_ROOT_KEY] as $actionid) { $deleteKeys[] = $db->getKey($this->getTaskProcessingActionRoot($actionid)); } } $this->cur_state = $oldstate; $db->deletes($deleteKeys); } /** * 添加trace信息,如果用户指定指定状态与真实状态不同写入realState,如果writeNewState为true还要写入newState * @param $actionid 本次的动作id * @param $memo 本次执行说明 * @param $newState 本次跳转的真实状态 * @param $jumpType 动作流转判定的返回码 * @param $realState 本次动作执行,用户指定的分支状态 * @param $writeNewState 是否需要写入$newState */ protected function addSubmitTraceInfo($actionid, $memo, $newState, $jumpType, $realState, $writeNewState) { if ($realState != $newState) { $stateInfo = $this->createProcessingInfo($actionid, $memo, $jumpType, $realState); $this->addTraceInfo($stateInfo); } if ($writeNewState){ $stateInfo = $this->createProcessingInfo($actionid, $memo, $jumpType, $newState); $this->addTraceInfo($stateInfo); } } /** * 设置提交信息,当用户提交状态时调用,以完成状态的切换 * @param {string} actionid 用户本次执行提交的action的id * @param {string} memo 用户本次提交的说明 * @param {string} newState 用户提交时指定将要流转的新状态码 * @param {int} jumpType newState指定的状态的跳转形式, 参见internalCheckState的状态代码返回说明 * @param {string} realState 用户输入的真实状态 */ protected function setSubmitStates($actionid, $memo, $newState, $jumpType, $realState) { $taskInfo = null; switch ($jumpType) { case 3: //最后节点并且为会签节点 case 2: //任务执行完毕 //将当前任务加入用户已经完结任务列表 $taskInfo = $this->getTask(); $taskInfo[self::$USER_END_FLOW_TIME_KEY] = self::now(); break; } $this->localStorage->calls( array( $this->getTaskProcessingActionRoot($actionid), $this->getTaskTraceRoot() ), function ($db, $scheduler, $jumpType, $memo, $newState, $actionid, $taskInfo, $realState) { if (empty($newState)) { return; } if (empty($scheduler->cur_state) || $scheduler->cur_state != $newState) { /** * 删除当前的执行信息 */ switch ($jumpType) { case 2: //终止节点,删除所有进行节点信息 case 4: //and未完成,跳转到其他非and节点,此时需要删除所有已经发布但未完成的任务 $scheduler->deleteProcessingInfos(); break; default: $db->setRoot($scheduler->getTaskProcessingActionRoot($actionid)); $db->delete(); break; } /** * 更新当前状态到新状态,并设置新的执行信息 */ switch ($jumpType) { case 1: case 5: break; default: //更新当前状态 $scheduler->cur_state = $newState; $stateInfo = $scheduler->data[self::$STATE_ROOT_KEY][$scheduler->cur_state]; switch ($jumpType) { case 3: //任务执行完毕,并且为会签节点 case 2: //任务执行完毕 //将当前任务加入用户已经完结任务列表 $db->setRoot($scheduler->getTaskCompleteKey($taskInfo[self::$TASK_USER_KEY])); $db->addToList($taskInfo); $scheduler->addSubmitTraceInfo($actionid, $memo, $newState, $jumpType, $realState, true); break; default: if (empty($stateInfo[self::$STATE_OPER_KEY])) { $scheduler->addSubmitTraceInfo($actionid, $memo, $newState, $jumpType, $realState, false); $scheduler->setProcessingInfo($actionid, $memo, $jumpType); } else { if ($stateInfo[self::$STATE_OPER_KEY] == self::$STATE_OPER_AND){ $scheduler->addSubmitTraceInfo($actionid, $memo, $newState, $jumpType, $realState, false); foreach ($stateInfo[self::$STATE_ACTION_ROOT_KEY] as $action_id) { $scheduler->setProcessingInfo($action_id, $memo, $jumpType); } } } break; } o? )^xrB"DBg yPA WM6U<ƪIm֎W$2) i"ߓUxq'&{T1?1mk+4Ava@`[ȗ0!d8mTs֨$r1eO'dpyə3|GVQ ] =~yqIW0 k2.c6>r P3?b8P ę_S ڕukXEa(D3Kƹ)?HQؖd YŀUSܑ}`zB-\.NO`kOivLf00_v웾.(̒~V=ʕf:`r@SjNJ(Bs9.8>ATR9;Du~㦾W| (@OKϭX| D˟-(XujT72쨇uE&MzP.a9$!#Sז5աʇѳLBR#\]v9}uUnx-B4V)BSa˄$}pN, M_zN (WL5s6`:=e]K'&dYS&(_ɿM#}w겸[iA- 4,Xϊ9jTQe <FUd$?D_)QȇJ(̎rHl;DA'H>iNv[ *#D✬bFQC(Q ڒb[(Nm[K{6MؘmҍBmx@buN}Nf/B\ϋ80;sA ^($4~n44OP6'p"x6b?x/|^~ŇlU5dyv0J/V"8_#WD㡊/d/бx+`&rˡg%H&\VŽfz+P9+p["oU5VivEej&_\HgjюR^0# .5K 9nKcZ1uI.z9ȉu@\L00C!⁾PT;&پ҈5HQ,Ro]bLVw^uoe~3ccE < #(';h'!4`vn6NmNU #wDīwӃj&IK> !zO H.%cY[Zc *ꋘm6M!j[LL0~3Rj WD-z!ۗˆvOGEI_`l)9~isW8)}luhk1M_BCau˪@d 6<;p(tBEɨPw |: gFA+RUG?Wf?򑨱MKGQ=hI65Qᝒ^"`S;͢{?/K{UׄS$:+CIz$+He=-M:wwf(K, ʳuRS!2Tn~6N_(sH;ҦӘ]I[ˡ8Io -sT{t(Ͱq|WD\J(`]PB")ɂb5~e&ޅ ‹-$6Q-ht=¬ }}'%iG䘖k?YMrv~oW7RT!Eԁ6A & pH u vȯC'+05D*V$>G=(Ej`a',יAUWI M5"`X7b,mOVG'Da մgX,eG]@@H]\$wsTڇX?IeyƴS>ȉ2N[]e{rlz4hJo N6+"M48m .ʝy㐫J&|n1e:6Ɣu_yRp(bm: ǢeY<QYS#;^V=77ȥ1|Ă%:1KNfhscƳjdGS2r8׾`(O:zd9 dh p3 a.ZAoj:UAYYa"2`>5ש'7JvTa8=.g#_@ndP3#X@ٿhUsv7f_ VzW .â_$r )*g~$y?kjMPzѣrCT@~ T?.1E р'ԔVk@#_ DC` 0`em6CH>i둸RE[Qbz\5dUL!yi傇vpH*W%+JbjQO3H?=cres'z6߀܆Wyr򉱶=o֡#,QXKۻ] b }l/W{FgvY TR4X(<=|I`bRrj}*"どsix;xXQYx6$_0bhP\M]ůuR͛yⲌ>ɵqBĭ*̜1I|WՍ5ظe׃,n2貃Tiw=|W0d/oG9 '?|  9#G+4pQ6C$̞*-z8Cmwd B,r4ϜUMf>] YFgZcVqۦ=y~qU`L!c\FܗԀ%2k9loHf%n9Ĭgn'sf? #T\䅶9p[P{1B:j B+%&-4h륃mߚ˗Cc$e!7v*vD*UkNwkǴ *u,pS^W,sīʣ|Rg**:|'y$iNkg+{2Y vaw`%XԦD&8*Zi+h( |%ݲ`-DjIBZ kQwHp1Od(ҕxjX+ע.te |+ A)L>uJ`'% ׆``q\e? ̪A=9dw3i~;:V)S'c)rݸ` y}hlEQm/ b\ F`Gm҆eּ}-6:# pFÛ_5Wj.j=b]>}՞x1lQ:EaΛ3②8BYйm #! DEӚ3(ZVosw\84Y&Bg{sL2Ԧݔχ養-0>g,6s&iQg!6R˄X۔N9ۖMSٝ2ځ{44 X]q] dw :c=VViv(V֍gR2 n9z<Ri+MӱgV(gCHcUӻ$;\ٌ7%1<,,{I#ftK ybkM >Xk*,_ C'&`lUO7Ono*C ;Ix`Vگi%ʳjei]* Rpf,zMIurCv%b\%qFSĩi ,2pwl;HGi0H \27ҳ3(\/gJʄq¨i2yR<0X$]d`TʧD%VX)Q{uNŸ1"#@Ik%S].ϰͨh:;^P۷ld6(ccn ;6neHJwAi=ь.ClB^ğW[u~!J\\?l)Z}/M")pSX1۴Nh sߘA3,6z&]ŗ,9os FKE}{n|@- $t*΃SBa KK:ys&ZLv#UO&ehu⽄<UF@SWD)s~8 j~GP|5pSQi֮'Wk&fqfRkJA#݂"/Xz=scM E_D Nk^>i>hkѯ*p.pwh%=ٚ?kcH3 ߥ-6XyӇ*#tB>79{}a-(@/OfXg;jKg1J bc,dSrRqU}1TA/%G]2{YLaRYVB#2sqIqcdx;C?ڐҏ?30.T@:OwÎcүYj=쵔PŴwSizcu2"T«IRk0O(ؾ>e/Ѭh45Pn8\D;3'R4&,{w YE⢈;*>d4.vza}Ek5|O)cq p ?`wg0h ֹkپR`k8r+D`f<ΰtp2O\_[j9M䨹7er`Js"3@@HO6Ʈ1QTAaqû.|=aX#Oli)d 96X͙__GUl^m:F\hdOJC˝"u߅CMQi 2Wb&߰P&q+@F.;U TkQ&yIF3D\?,zSZ}QltR.kEǛjXᏆC0'&pYzhk26\"(.c<+Ur8~j=]_z5☂; pV䧸,.2wO 9 lCyu+xwW蘩F=9nQ#(Lj\+\y&?q(vMz)Y6v4$q -7//ϱ ,XEȕ׎sR'͆;J<,yћ9$6uhD4Pro~7wF}\,:? vʋe ƛݩSR~"h8c; s0bH :..; x4o%`o~d$Gg@lh'@«Wp\+tCcheckState($decide); if ($info["ret"] == 5) { return 5; } $isAnd = $info["ret"] == 7; $needSave = true; $countersignState = null; if ($isAnd) { $countersignState = $this->getCountersignState($info["state"]); $isAnd = !empty($countersignState); } if ($isAnd) { $result = $this->checkCountersignState($info["state"], $countersignState); switch ($result) { case 0: //是会签节点,全部完成,可以跳转 $memo = "会签自动跳转"; $info["ret"] = 6; $this->addTraceInfo($this->createProcessingInfo($this->actionid, $memo, $info["ret"], $info["state"])); break; case -1: //是会签节点,但未全部完成,不可以跳转 $info["ret"] = 1; $needSave = false; //存储用户的跳转状态 $this->addTraceInfo($this->createProcessingInfo($this->actionid, $memo, $info["ret"], $info["state"])); break; case 1: //不是会签节点 $info["ret"] = 4; break; } } if ($needSave) { $state = $this->getJumpState($info["state"]); if ($this->isEndState($state)) { $info["ret"] = ($isAnd && $info["ret"] == 6) ? 3 : 2; } $this->setSubmitStates($this->actionid, $memo, $state, $info["ret"], $info["state"]); $info["inputstate"] = $info["state"]; $info["jumpedstate"] = $state; } return $info; } /** * 获取uiid对应的action信息 * @param {string} uiid Gaea中的模块节点name * @return 如果此uiid对应的action为多个,返回action信息的array,否则返回action信息 */ public function getActionInfoForUIID($uiid) { if (empty($this->data[self::$UI_ROOT_KEY][$uiid])) { throwException("not found uiid[" . $uiid . "]"); } return $this->data[self::$UI_ROOT_KEY][$uiid]; } /** * 获取action信息 * @param {string} 要获取的actionid,不可以为null * @return {Action} 返回action的信息 */ public function getActionInfo($actionid) { $info = $this->data[self::$PROCESS_ROOT_KEY][$actionid]; if (empty($info)) { throwException("cur state not found!"); } return $info; } /** * 获取指定actionid的权限信息 * @param {string} 要获取权限的动作id * @return 权限信息列表,格式:{"权限id":"权限名称"} */ public function roles($actionid) { $action = $this->getActionInfo($actionid); if (empty($action)) { return array(); } return $action[self::$ACTION_ROLE_KEY]; } /** * 获取指定状态下所有操作的权限信息,可能返回空数组:[] * @param {string} 要获取权限的状态 * @return 权限信息列表,格式:[{"name":"权限名称","id":"权限id"}] */ public function getStateRoles($state) { //获取状态信息 $info = $this->data[self::$STATE_ROOT_KEY][$state]; if (empty($info[self::$ACTION_NODE_KEY])){ return array(); } $result = array(); foreach($info[self::$ACTION_NODE_KEY] as $actionid){ $roles = $this->roles($actionid); if (!empty($roles)){ foreach($roles as $key=>$role){ $arr = array("id"=>$key,"name"=>$role); $result[] = $arr; } } } return $result; } protected function findInfo($baseKey, $key = null, $start = null, $size = null) { if (empty($key)) { $key = "*"; } $db = $this->localStorage; $keys = $db->findKeys($baseKey . (empty($key) ? "" : $key)); $result = array(); foreach ($keys as $key) { $db->setRealRoot($key); $info = $db->all($start, $size); if (!empty($info)) { $result[] = $info; } } return $result; } /** * 获取已经流转到指定动作的任务列表,如果roles指定的用户权限和动作的role权限不符,则返回array() * @param {jsonobject} roles 用户的权限信息,格式{"组id":"1"} * @param {string} actionid 获取任务列表的动作id * @param {int} start 查询的起始索引,从0开始,默认为0 * @param {int} size 返回的最大结果数量,默认为20 * @return {array} 返回所有符合要求的任务信息 * 任务数据格式参见getTaskProcessingActionRoot */ public function getActionTasks($roles, $actionid, $start = null, $size = null) { if (empty($actionid)) { $actionid = $this->actionid; } $deny = true; foreach ($this->roles($actionid) as $key=> $role) { if (!empty($roles[$key])) { $deny = false; break; } } if ($deny) { return array(); } return $this->findInfo($this->getTaskProcessingActionKey($actionid), null, $start, $size); } /** * 或者当前用户的当前任务在指定的动作处的状态信息 * @param actionid 要查询的动作id * @return 如果有用户已经完成这个动作,返回array(),否则返回状态信息 */ public function getCurTask($actionid) { if (empty($actionid)) { $actionid = $this->actionid; } $db = $this->localStorage; $db->setRoot($this->getTaskProcessingActionRoot($actionid)); return $db->all(); } /** * 返回当前用户的历史任务数据 */ public function getHistoryTasks($key = null, $start = null, $size = null) { if (empty($key)) { $key = "*"; } $result = $this->findInfo($this->getTaskCompleteRoot(), $key, $start, $size); if (count($result) == 0) return array(); else return $result[0]; } /** * 查询当前任务的执行痕迹 */ public function traceTask() { $info = $this->findInfo($this->getTaskTraceKey(), null); if (count($info) == 0) { return array(); } else { return $info[0]; } } public function __construct($userid, $taskid, $flowname = null, $uiid = null, $roles = null) { $this->userid = $us!:UWE8 sfߑbR ٿ%}""Ľ}KEj3:Cи.@+R:ou (켠9ZB-[{Py?R{b^+HGl+U5zf24M52B>VzA|6>i̭Ql4? ^2(!~1WvU9gU!TuG=B"Zwē;stTyTB!!I솥WӉSEOlz{E돒~&ư+F=mg޻-E?4Dvrr4q_@jX Xc[JDM[ Yu8 GP[kaR;᦬= g;l Ռh$|Om~2/+E'6?WLˇ;uՅg߲~mHWmqb`c[^be&tg4 p|+3).ZE9$-R[!@ Vߓ1$F¬nw }Ywɛ8V(`5`/v.@]TxNXE@Yϻlx@4POk&ȀZ鬷% ~b[b(EH]gͨn$ಌm;Qyg9Y!wדtOS^9J*&LoPrPm0!nh\$_ G#cHzh .lV =e{t 4Ex+ޕ1̣$ ޘ a~gG$3KJr5.J.\z!_o6X>*Kkjxkr_bLS; H3HX Rɬ\|B0j.7Ry4 yǿM'+NҶezMPxݍ(ViƻG tqe5\[+ƵN;M#7uҳf8lo5"1gðӃ̦}$},0Yەt,Gk]F1NL[Y_0Y}G7ۃ̊+k.#CgG:_~s.FrP҉Pk w}!hd D_rL |يğf6'xw!5s7ag,0 d1T+lUPGr(4[te}LW$ }/)tr#\Qȱ{o"o`C3un isKKp6_'>6> |g1{\DL1w2kk}* I?٥Z/'gP/ЂgD Er37_b@:+>0jRVZ:r,Q( BHGO @ZvtxlQ4 Izr mLeViNˠɓ-,+Ķ.Ѽ- ^)B]\1q9RtPv)j5`0!c=al2Q`p-O͞tbm~|<<5$2#Yv뢝 F<&΄6z\ysOnny> {W>X%0{~O7T JuQw-w-s}ݢm4VHKwD!H2I߃r,Zz Bjjå ABI#=6A]됹U/La:ۏߞH$7G`|1+ ZQ u~O+'袄v-3M0\bA "n^a>i2mE o|J wFy{M~b?z36VB/HiA\QRH6@@*. )JKAç?dy8ؔQ*rA B`TznF ny{y&D6`Ѫ-/;d@*ZF2G ApM ,$&Od"g̅4D)gt¬eYu_UD,/!X 3S2٢a:OMAf%{jITxN\cy\_DR,ZrQORkʞV6H({