From 4d7d0fd82be095ece2a84e43c9ab274237bb226b Mon Sep 17 00:00:00 2001 From: afornerot Date: Tue, 17 Dec 2019 14:56:15 +0100 Subject: [PATCH] widget only --- .../CoreBundle/Command/data/core-init-01.sql | 2 +- .../PortalBundle/Command/InitDataCommand.php | 51 ++++++- .../Controller/PagewidgetController.php | 36 ++++- .../PortalBundle/Resources/config/routing.yml | 8 ++ .../Resources/config/services.yml | 5 + .../views/Pagewidget/viewonlydoc.html.twig | 117 +++++++++++++++++ .../PortalBundle/Service/onlyService.php | 124 ++++++++++++++++++ .../web/uploads/icon/icon_onlyoffice.png | Bin 0 -> 9820 bytes 8 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/views/Pagewidget/viewonlydoc.html.twig create mode 100644 src/ninegate-1.0/src/Cadoles/PortalBundle/Service/onlyService.php create mode 100644 src/ninegate-1.0/web/uploads/icon/icon_onlyoffice.png diff --git a/src/ninegate-1.0/src/Cadoles/CoreBundle/Command/data/core-init-01.sql b/src/ninegate-1.0/src/Cadoles/CoreBundle/Command/data/core-init-01.sql index fdebccb3..949a0a76 100644 --- a/src/ninegate-1.0/src/Cadoles/CoreBundle/Command/data/core-init-01.sql +++ b/src/ninegate-1.0/src/Cadoles/CoreBundle/Command/data/core-init-01.sql @@ -8,7 +8,7 @@ INSERT IGNORE INTO `niveau01` (`id`, `label`, `siren`) VALUES (-100, 'DRAAF', '130007107'); INSERT IGNORE INTO `user` (`id`, `niveau01_id`, `username`, `firstname`, `lastname`, `password`, `email`, `avatar`, `role`,`siren`,`authlevel`) VALUES -(-100, -100, 'admin', 'Administrateur', 'draaf', '{SSHA}hTAPycxp8kXFhZIjteFA4fsB2CQcIenW +(-100, -100, 'admin', 'Administrateur', 'draaf', '{SSHA}Kvz21GjhkryG4l7EKniMJzVfwDufa+eI ', 'admin@ldapbundle.ac-arno.fr', 'admin.jpg', 'ROLE_ADMIN', '130007107', 'simple'); diff --git a/src/ninegate-1.0/src/Cadoles/PortalBundle/Command/InitDataCommand.php b/src/ninegate-1.0/src/Cadoles/PortalBundle/Command/InitDataCommand.php index 216cdd32..a4e56586 100644 --- a/src/ninegate-1.0/src/Cadoles/PortalBundle/Command/InitDataCommand.php +++ b/src/ninegate-1.0/src/Cadoles/PortalBundle/Command/InitDataCommand.php @@ -51,6 +51,7 @@ class InitDataCommand extends ContainerAwareCommand $activate_widmindmaps = $this->getContainer()->getParameter('activate_widmindmaps'); $activate_widmoodle = $this->getContainer()->getParameter('activate_widmoodle'); $activate_widnextcloud = $this->getContainer()->getParameter('activate_widnextcloud'); + $activate_widonlyoffice = $this->getContainer()->getParameter('activate_widonlyoffice'); $activate_widopensondage = $this->getContainer()->getParameter('activate_widopensondage'); $activate_widphpldapadmin = $this->getContainer()->getParameter('activate_widphpldapadmin'); $activate_widpiwik = $this->getContainer()->getParameter('activate_widpiwik'); @@ -58,6 +59,8 @@ class InitDataCommand extends ContainerAwareCommand $activate_widsacoche = $this->getContainer()->getParameter('activate_widsacoche'); $activate_widwordpress = $this->getContainer()->getParameter('activate_widwordpress'); $activate_websocket = $this->getContainer()->getParameter('websocket_activate'); + + $widonlyoffice_sync = $this->getContainer()->getParameter('widonlyoffice_sync'); $output->writeln('PORTAL = Default Data'); @@ -530,7 +533,29 @@ class InitDataCommand extends ContainerAwareCommand $entityItem->setUrl($widnextcloud_url); $em->persist($entityItem); } - + + // Item Onlyoffice + if($activate_widonlyoffice) { + $widonlyoffice_url =$this->getContainer()->getParameter('widonlyoffice_url'); + $entityItem = $em->getRepository('CadolesPortalBundle:Item')->find(-1000); + if(!$entityItem) { + $entityicon = $em->getRepository('CadolesPortalBundle:Icon')->findoneby(["label"=>"uploads/icon/icon_onlyoffice.png"]); + + $entityItem = new Item(); + $entityItem->setId(-1000); + $entityItem->setRowOrder(0); + $entityItem->setTitle('Onlyoffice'); + $entityItem->SetSubtitle("Application Bureautique"); + $entityItem->setIcon($entityicon); + $entityItem->setTarget("_blank"); + $entityItem->setItemcategory($entityItemcategoryapp); + $entityItem->setEssential(true); + $entityItem->addGroup($groupall); + } + $entityItem->setUrl($widonlyoffice_url); + $em->persist($entityItem); + } + // Item Opensondage if($activate_widopensondage) { $widopensondage_url =$this->getContainer()->getParameter('widopensondage_url'); @@ -1059,6 +1084,30 @@ class InitDataCommand extends ContainerAwareCommand $entityWidget->setParameter($parameter); $em->persist($entityWidget); + // Onlyoffice document + $entityWidget = $em->getRepository('CadolesPortalBundle:Widget')->find(-1810); + if($widonlyoffice_sync) { + if(!$entityWidget) $entityWidget = new Widget(); + $entityicon = $em->getRepository('CadolesPortalBundle:Icon')->findoneby(["label"=>"uploads/icon/icon_onlyoffice.png"]); + $entityWidget->setId(-1810); + $entityWidget->setRoworder(2); + $entityWidget->setIcon($entityicon); + $entityWidget->setName('Documents Onlyoffice'); + $entityWidget->setDescription("Les documents associés à votre groupe"); + $entityWidget->setRouteview("cadoles_portal_config_panelwidget_view_onlydoc"); + $entityWidget->setHeight("630"); + $entityWidget->setAutoajust(true); + $entityWidget->setBorder(false); + $entityWidget->setOpened(true); + $entityWidget->setAccess(["config","group"]); + $parameter = json_decode('{"fields": []}'); + $entityWidget->setParameter($parameter); + $em->persist($entityWidget); + } + elseif($entityWidget) { + $em->remove($entityWidget); + } + // Widget Séparateur $entityWidget = $em->getRepository('CadolesPortalBundle:Widget')->find(-1600); if(!$entityWidget) $entityWidget = new Widget(); diff --git a/src/ninegate-1.0/src/Cadoles/PortalBundle/Controller/PagewidgetController.php b/src/ninegate-1.0/src/Cadoles/PortalBundle/Controller/PagewidgetController.php index 187e21f7..7000cd55 100644 --- a/src/ninegate-1.0/src/Cadoles/PortalBundle/Controller/PagewidgetController.php +++ b/src/ninegate-1.0/src/Cadoles/PortalBundle/Controller/PagewidgetController.php @@ -2107,7 +2107,41 @@ class PagewidgetController extends Controller 'nbarticle' => $nbarticle, ]); - } + } + + public function viewOnlydocAction(Request $request,$id,$access="config") { + $usage=$request->query->get('usage'); + $group=$request->query->get('group'); + $user=$this->getUser(); + + $em = $this->getDoctrine()->getManager(); + $entity = $em->getRepository($this->labelentity)->find($id); + if (!$entity) throw $this->createNotFoundException('Unable to find entity.'); + + // Permissions + if($access=="config") { + $canupdate = true; + } + else { + // On s'assure que l'utilisateur à la permission de voir + $page=$entity->getPage(); + $em->getRepository("CadolesPortalBundle:Page")->getPermission($this->getUser(),$page,$cansee,$canupdate); + if(!$cansee) throw $this->createNotFoundException('Permission denied'); + } + $onlyservice = $this->container->get('cadoles.portal.service.only'); + $files=$onlyservice->getDocument($group, $folders, $firstfolder); + + // Render + return $this->render($this->labelentity.':viewonlydoc.html.twig', [ + 'entity' => $entity, + 'canadd' => $canupdate, + 'canupdate' => $canupdate, + 'firstfolder' => $firstfolder, + 'folders' => $folders, + 'files' => $files, + 'access' => $access, + ]); + } } diff --git a/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/config/routing.yml b/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/config/routing.yml index 7d56b011..6e2c5af4 100644 --- a/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/config/routing.yml +++ b/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/config/routing.yml @@ -795,6 +795,10 @@ cadoles_portal_config_panelwidget_view_groupmessage: path: /config/pagewidget/view/groupmessage/{id} defaults: { _controller: CadolesPortalBundle:Pagewidget:viewgroupmessage, access: config } +cadoles_portal_config_panelwidget_view_onlydoc: + path: /config/pagewidget/view/onlydoc/{id} + defaults: { _controller: CadolesPortalBundle:Pagewidget:viewonlydoc, access: config } + #-- Access user cadoles_portal_user_pagewidget_widget_sumbit: path: /user/pagewidget/submit/{idpage}/{idwidgettype} @@ -904,3 +908,7 @@ cadoles_portal_user_panelwidget_view_groupmessage: path: /pagewidget/view/groupmessage/{id} defaults: { _controller: CadolesPortalBundle:Pagewidget:viewgroupmessage, access: user } +cadoles_portal_user_panelwidget_view_onlydoc: + path: /pagewidget/view/onlydoc/{id} + defaults: { _controller: CadolesPortalBundle:Pagewidget:viewonlydoc, access: user } + diff --git a/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/config/services.yml b/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/config/services.yml index 56f25a36..b24f48a7 100644 --- a/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/config/services.yml +++ b/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/config/services.yml @@ -4,3 +4,8 @@ services: arguments: ['@service_container'] tags: - { name: form.type } + + cadoles.portal.service.only: + public: true + class: Cadoles\PortalBundle\Service\onlyService + arguments: ['@service_container','@doctrine.orm.entity_manager'] diff --git a/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/views/Pagewidget/viewonlydoc.html.twig b/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/views/Pagewidget/viewonlydoc.html.twig new file mode 100644 index 00000000..a49bc642 --- /dev/null +++ b/src/ninegate-1.0/src/Cadoles/PortalBundle/Resources/views/Pagewidget/viewonlydoc.html.twig @@ -0,0 +1,117 @@ +{% set theme = app.session.get('theme') %} +{% if theme is not empty %} + {{ include('@Theme/'~theme~'/function.html.twig') }} +{% endif %} + +{% import "@CadolesPortal/Pagewidget/constants.twig" as constants %} + +{% set stylewidget = constants.mystylewidget(entity) %} +{% set stylewidgetmenu = constants.mystylewidgetmenu(entity) %} +{% set stylewidgetheader = constants.mystylewidgetheader(entity) %} +{% set stylewidgetbody = constants.mystylewidgetbody(entity) %} +{% set stylewidgetbodyreverse = constants.mystylewidgetbodyreverse(entity) %} + +{% set color = app.session.get('color') %} + +{% set colorbodyback = entity.colorbodyback %} +{% if colorbodyback is null %} + {% set colorbodyback = color['main'] %} +{% endif %} + + +{% set colorbodyfont = entity.colorbodyfont %} +{% if colorbodyfont is null %} + {% set colorbodyfont = color['fontcolorhover'] %} +{% endif %} + +
+ {% if canupdate or canadd %} +
+ {% if canupdate %} + + + {% endif %} + + {% if canadd %} + + {% endif %} +
+ {% endif %} + + +
+ {% if entity.icon %} + + {% else %} + + {% endif %} + {{ entity.name }} +
+ + {% if files|length >= 1 or canupdate %} +
+
+ {% if canupdate %} +
+
+ {% endif %} + + {% for file in files|sort %} + {% if loop.index==1 and not canupdate%} +
+
+ {% endif %} + +
+
+ {% if canadd %} + + + + {% endif %} + + {% if file.minefamily=="text" or file.minefamily=="image" or file.minetype == "application/pdf" %} + + {% else %} + + {% endif %} + + +
+
+ {% endfor %} + + {% if canadd %} +
+
+ +
+
+ {% endif %} +
+
+ {% endif %} +
+ + + diff --git a/src/ninegate-1.0/src/Cadoles/PortalBundle/Service/onlyService.php b/src/ninegate-1.0/src/Cadoles/PortalBundle/Service/onlyService.php new file mode 100644 index 00000000..0558b75a --- /dev/null +++ b/src/ninegate-1.0/src/Cadoles/PortalBundle/Service/onlyService.php @@ -0,0 +1,124 @@ +container = $container; + $this->em = $em; + + $this->only_activate = $this->container->getParameter('activate_widonlyoffice'); + if($this->only_activate) { + $this->only_activate=$this->container->getParameter('widonlyoffice_sync'); + if($this->only_activate) { + $this->only_url = $this->container->getParameter('widonlyoffice_url')."/api/2.0/"; + $this->only_user = $this->container->getParameter('widonlyoffice_user'); + $this->only_password = $this->container->getParameter('widonlyoffice_password'); + $this->only_host = str_replace("https://","",str_replace("http://","",$this->container->getParameter("widonlyoffice_url"))); + } + } + } + + public function getDocument($idproject,&$folders,&$firstfolder) { + $files=[]; + $folders=[]; + + if($this->only_activate) { + if($this->authOnly()) { + $response = \Unirest\Request::get($this->only_url.'/project/'.$idproject,$this->headers); + if($this->koresponse($response)) return false; + $firstfolder=$response->body->response->projectFolder;; + + $response = \Unirest\Request::get($this->only_url.'/project/'.$idproject.'/files',$this->headers); + if($this->koresponse($response)) return 0; + foreach($response->body->response->files as $fileonly) { + array_push($files,$fileonly); + } + foreach($response->body->response->folders as $folderonly) { + $folders[$folderonly->id]=$folderonly; + $subfolder=$this->scanfolder($folderonly->id,$folders,$this->headers); + foreach($subfolder as $file) { + array_push($files,$file); + } + } + } + } + + return $files; + } + + private function authOnly() { + // Only Office est-il dans le domaine + if(stripos($this->only_url,"/")===0) + $this->only_url="https://".$this->container->getParameter("weburl").$this->only_url; + $indomaine = (stripos($this->only_url,$this->container->getParameter("weburl"))!==false); + + // Si hors domaine on utilise le proxy si proxy il y a + if(!$indomaine) { + $PROXYactivate = $this->em->getRepository("CadolesCoreBundle:Config")->find("PROXYactivate")->getValue(); + if($PROXYactivate) { + $PROXYserver = $this->em->getRepository("CadolesCoreBundle:Config")->find("PROXYserver")->getValue(); + $PROXYport = $this->em->getRepository("CadolesCoreBundle:Config")->find("PROXYport")->getValue(); + \Unirest\Request::proxy($PROXYserver, $PROXYport, CURLPROXY_HTTP, true); + } + } + + \Unirest\Request::verifyPeer(false); + \Unirest\Request::verifyHost(false); + \Unirest\Request::timeout(5); + $this->headers = ['Host' => $this->only_host, 'Accept' => 'application/json','Content-Type'=>'application/json','Retry-After'=>'5']; + $query = array('userName' => $this->only_user, 'password' => $this->only_password); + $body = \Unirest\Request\Body::json($query); + + $response = \Unirest\Request::post($this->only_url.'/authentication',$this->headers,$body); + if($this->koresponse($response)) return false; + $token=$response->body->response->token; + $this->headers["Authorization"]=$token; + return true; + } + + private function koresponse($response) { + if($response->code>=Response::HTTP_BAD_REQUEST) { + $this->mydebug("ERREUR ".$response->code); + if(property_exists($response,"body") && property_exists($response->body,"error")) $this->mydebug("ERREUR ".$response->body->error->message);; + return true; + } + + return false; + } + + private function scanfolder($folderid,&$folders,$headers) { + $files=[]; + $response = \Unirest\Request::get($this->only_url.'/files/'.$folderid,$headers); + if($this->koresponse($response)) return 0; + foreach($response->body->response->files as $fileonly) { + array_push($files,$fileonly); + } + foreach($response->body->response->folders as $folderonly) { + $folders['"'.$folderonly->id.'"']=$folderonly; + $subfolder=$this->scanfolder($folderonly->id,$folders,$headers); + foreach($subfolder as $file) { + array_push($files,$file); + } + } + + return $files; + } + +} diff --git a/src/ninegate-1.0/web/uploads/icon/icon_onlyoffice.png b/src/ninegate-1.0/web/uploads/icon/icon_onlyoffice.png new file mode 100644 index 0000000000000000000000000000000000000000..1579862e8a3c5bd3d5c46940746e47d298669db9 GIT binary patch literal 9820 zcmV-iCZpMjP)W4*S~2zC`FV(}iB0SuNA8e}8DTrvnt2n3SQ zIU3E~(>>Ey^-*W$@9iI%b#+%?(^b_Y&^MyHtFwOjd$01n-@ASKFfdph>h^f|r~E zTzAXxJ&Z_a3E(is+2iCBo9-0kL(QV`%K(J~ zuilZmWB>mBwi)v`MFIBg*&oX%Cl8A9Tg{mNmkz35NxPlz{oZHx=NdhA!xdo9p5N~% z#1mge5N_#C{s`srrSZ11P%%u!x*2TS!gyj0R_eP<#|HG|hUl9H>%x%Q1@y%ZXWbS}YK$7Q5_1EcNzbQH!}GkucY z>>x({)-k<2ykRKU@#nxFFZP5*EBWrdw_lIyHD6Z6XVHs1ZEi>X9_W! zr+4}^YceNE6sH=;X7iv1`L6+51Cs;Lgl9-?40%`HD#-)R~&JO_}UufWh7T~6vKXi%3c^vQ> z!C52VJ8{O_H!z&qOxEjSr37HGbY_NFJ$a0d>c1bjJqL9UDj#CRsIkobKsUc>aZuN=jQ`xD%MS zSU2yLi|*L@T0{9-B77%CI<=9})D|+a?nTSG88%@tq#f(iHGPIv6Gutr#t>aus~}dd zzwh&ReS5C==d%EU@?V?4(}GYDa`A4)yS9?<*htZd0rUHIE&mEpBdqx(rwTI1fcdmY z>QAjE#(38j#=ADtmLH=heT>e@)3`xlp2?aAHS#fFP6e3r((K-Q`%S3c+Z3+mK;Xof z>gZ>zdmEYLs&d|554xB&uF;rTQkv(SxyH_=BsHhjAL9mjIww!jGyWp++<5C9mYQo1 zeeUDmuglwq^DDbv=@6`PiQPJmLn#qzi4%4ZA(!Cdv zX*4*Y}srd;Losx{r$3XIb{e7>pTb%R*{2Coi+< z`>}RL*IvTdnq9O{ouzZ+Fzpj(5Dn(1ah@=SKLKufVGk3uKi#--^{)|5h`qQfCZ{HWafkTc(0k&86X?+5>Yag3KH{gTYvFn$FQ9 zq()xEDNLUq!*fH$n4S0i-N%nqADm?YjAQ@fJZvr*e!P>>&97xT)n5+k7OK>#%*DWr zwWQV37m&(!&rE@rWwKaBn8Cm-nQCZZWX=IgbPFQ*@f4%$uVj4P<+P_y(LL}pyj;U> z0}xgFd%&O0$;+*`-s%lyQzw9RjiBha^)Ptxui?9iMU7vqudf*=Qe&D`7n*1;ii^{E znW4Rk)bLiDel9&WsD@*U^gaJ=Vp9#f4PdY@Ik~xdkD$f^3}rjt4%!gm1El+}z{cAa zRhzHpC&M=?asS-oq&&%-*SxM~NN8|3^O;SJ zYne?IN{6e7SH{h$qzfFHIY1YRmzD?-^V?J@K$(T>ZrPvc3MPkW;6oTEQ(KwXbuAK) zEl|{{f3zmHs=4x7|F~Aam}AU>{-Ku7+67_i4y(i$GW%GW>O6tr9LF`6r~SwybdNtb zAHz$kov03|NbDI7ckQ(7u zxdWMbc(!Gb(#b+3q&jwAYtzQc38guziOeo2N$s!t?=QkG7!;c+5R8q|arP;?r;pA$ zXPM|OB&V(gz6DhZ5I%di!BC}V>M*IyNu~zZlj+%ktXhZLnM552)j0~fT1PErt*EMM zU^HB@(TnJEiSnTYJN}xjcs*S> z$ryH)iLUQ+!wW4{*`HL6v51<=-i~M_creBy2E^E!^Q1}`;zkDEv#1pU-+-+ZRyoOx zJb~1Nw_29%%+l6e%3%PT%~Kp5#~pr=p2=e*is^+5PRoSAJAm8E+`Mb=Z5tdlrnJ+eCiV4xBaX@H*R2W2(l?5PtQ>&dfqg^qximUnmHRaTPIPJh0^0RzOwI zz+i*Ws#FWMBy5>0YL@y6Ab?m)F`dCbJ3!m$3v^^o*_XUSNe_f*r7MV0#DL@2 zDj#1Poi7DqK%B_F1Ym=zOhP5HG@(P7RZ*A`4>%I8_WbZTGV~(t=@&>A#=_o0spU~s zo2~>F^CsZSp$kyn)KqG7LNV%-%np*soWUP@jLD9z_P|G~;g_2liE zufgj~5|ko&Q}X?hZ;-iKG8zvN0i!sv0IbFO2FD7;bcTsDL&&KoXip!;^RtLCNEn4i z{8laenfn>7f|1JrksIEB+eISgaI@)E2Y{+21<*+77F5d$pw^;lvC&^upX8b;oE<%k zJJ;a!Tt;$LH-YP7bph+rM2HARz!ZyQhsUtvKP8oUgyP`|{7e#X5iy8yFi};sWco#_ zUx!vfs$zkb1cCuuT@mM!CG4Iw5E?Fpst7*x1R5y@xbZxx{vo+lq1l<$66RVk~XlX}UI^Ce=5Las6n8mvVlkD{+j@*irJu zFLUJ|!{21T~Hif(Ql$r%tO(KSK$rc-pRJB#C0wN9&2j_r^rKBy=GL?IduVid9(T1vUc4_sNcolO27UPWv6UCw@#km5$Q(FdsD{ z;owsF*_8MyDMLupbu675&e6GHnEZ4H6DRwbINgVzk9s9$Z)!9hYS`ieYg)jF@8C87emywR0`mTRxuv#;>Ps z?RH|FZQ!|O*J1!$EK*2MGjZ-P?Zt1hHSsX<)JSFTKm=o=Vw99DPgTSoEp=lkR{>46 z5}5G(Y8!7HpRP@VbZs0WKheqf$qh^l^br(djlcNyu}XH|yl((l-z*9ukn9;})%N3b ztQ`htW-omGs7!4@;449(l^DQADI{7IHy`g#fXncrBlI_4N{b!M?x}CZWS^m z2QQ%o3$1%-1sn$)*I=B;DwHGs@-|}SGuOEe09c3g>3&W>z7y*=?Q50BT$HBSo3*=+ z)3dGg%%V~nR|h5EPL<8Xf`VfN*E4u=2z*PiU$Gz zB8KYy_Ua-`#rKpNK_pTHF_m(2N$4e);J6NsYr;~nscuLq&sO25G{=mvzxDhW3 zYYnG=+N_7LYTSk9DL}Go0>`N}d$Ubiy{K0KGppUpi3zUfpz7e~Ero)QS_`JE1LYtM zC z)cVt`* ztJau?!tjh>Dj^vbun0w^oJo{j0fHMdcyW(d%qcHXqe69_7b=^C+?!e|B;}Cxywujo7Ij5HvF-l)MW}LvykK0JR?e*kz23?_&Je0Etz{ShG3Hs{S_O zZBche*;LnVmQ*Zww3<{yGd%q)n0mRcL$ci^C|dG4A3tA2EO=t^YAQ5kQsvi0 z74jC;kx=Lf2gfNrjz&wtL1Zza!cWCagyYKTV8m55O{gvSh#@x>Fnl`0xsx3fMqi0$ z`)JV@s!qEoqdP%N$L(f}&Flo*l7 zU6m@5l|fbI;OMOIci2%hKAdCdc)F7f1S^E%%paDjv>0gy+cKE=vvu8^t( zg*A#|4e8-L14lCqAMd6xb`e_WLd2=vH)t^wMqEKoEb4hX4M9094=4L815XXmwQ-OQ7YVETJMa<;YReX&tN;RzDlXyA%#{fvTTC}&SiG4O&gF|dx}oN;uyJl4V>xF`t?2*gsr zA&BgbQJ3^+k<%}ZaprJ4xpO-R@?97S+rz5vIxT{8GqA`ZrhT*i#}p?(W%>ttckqptDwY3sC(Xt_W(I~1q131lLlt{7Z=UYR}1YmT0z z@8|@BkDcT2W|zX{t60Cihqf*U+v3N$S1i8AzHu6OTX;Rp?h1~QzNjl$ZRqDkEvRKpag^8O zUgYw^2@*Q{CdsKdJiAU9x+F#KD^|05Lpzuv&5maT0pDZj)FkPr&(Z&UhMj{#vKW50 zigGAtO(%~gw(~@6D|sh@nCfoe*IUy8IWjOJZ$mq1?|`tUs8Pxgrf`|G zW$?%-^5h5?oeX&6m|(P$1xVS7g<0Wxo#ck>XAWCT&CR>)QD z+%=Wo8GkFUW-CIM=C~&N48M|lo};lo9&5Xp!?6wIr8Q6HFBS;${#N zEdBl%ug^TkrTOC|Y<|wMHd@`P;cKWU1k`%<>hyJ1#droXo^oW3GIUWAZ)=K<-Zm0R z7gZ&f^_d#Z5FDML|45$gBZjzNPoR_&&-$yswi;0#-G_0({0aA%lj3K|9Xy`c#)#=` zW>E0dp@Ro5gPJFV@PKOL6=0n|%G)wOV@F{CcMdaO4MQk=KT4l;o|Rr3P1HMHLAx(p zaR!3H0+WvpGumd!dg0hL1>xeXkje|DwA!V1zUqLr`t8!#`pQxgJUA?T&;M$j;`+?v zygBa0)mf+1922P1eg>{WPfqB`&CQF<5`OqYz4#yhXv@L<1{hYu;cj0@nbSzDSI)qh~tFzD0Ve`u}WsX1`2%=p%U#m>N z)(U>6a?C}xdi>0Dt5Mg#mk(Cw{1p+qqPRkIf5P(6t_9wjd#ce2FzyvP%ikSPUIq`` zeRm#}C4cwq+)xTuaf~$NCuW3p2T~3sO{f^9TkgeBuCC4gky$?``l)?gdtT`tjv5-K z{=AL|2?shHNIHVopwH|Wp;#)MH3$OtmYxv^v!4|D4i5Q|oP!&5jBMy$v8Y(F(EOUs2ZU#kAM zMgb;Hb$p|1)8rW%aHo(6oN!k2soX1h2S?cDW$ATnL%&4H1riPf3OOs}qn^Gp57FO+ z6k)zgTO)i4O=jFcTr`Sh8!LD#4kOm#*d#^Bm``n%N!X3e~N?}z^q zl|Nc8B~_(Z$WbihvBex4{BvBTL%hbDU_&e*j%}D#DANQA7P6KoR;WK_CKmGl05Jmz z1F>dgW+G&9I9>GkQL&rHbuDMS9vm-$7fTR}FYamUiy-vh4jsJnqt!=dwZ^E`|1BbS zuuRn!5nL~Z7(?K=4EQll`fK^FKgA{aGrZ9qVQ0KZkE>B@cw>|yX~G_NUm+Vn-Y)iD zgxO;Zq0kdf7;`ihf)&GPU^rYz@Q}Zn=VT2Tw;k8>h`BLb*TXmsYYtU62>$PEF6v*-|{mYt0a^if7mmhq%~A=|P1)kP9GdmEt12 zj{u$tgSohAxMv3uayXnWIy_eB;3vUaPC7lP8^>`yT-U>KT#Rwb&lGA9?mu+!zzs7G z)>SVH2Mjbs0Yn6GT*Nr27|yy*Ayt-?5$X3p@&*f=|rN|zh;^)*Nt zI$UT+C|D(HLpNcyHeD?F_M`)zNMi*rV8t*N7@p6?c(~Bb)3TPdlfp?vLU&!9=sH!} z${PqZb-zb=PAWIv{NbM{^6JKNQR)i_@AS1nKoIx@ei7d<5-Vod>JRdIIm?x81^N?) z7>#oeWgZ9v$5Oy(BuXnAN`+{(8wT=*pXQVNC|JV@XBEDaD6e+ox;Vxu3%*Hs;ymoDL=s^D(1(U!yrG^}Rce!IO;o@e#ks0N(iPO9>G0Dyj zLzgQJ%^;fD1f|9>?hDUn93IYh@uXSHsMCo_gnm5{`F0aMKd||agwv1B_0GJMci+74 z5#aR==Vt~g&j$>!w#q6LizJFu>?oe$4dxtIrUKR{Jv^Gbb9sIc3K#}*mY-(hJX~DO zQLm4Jo2)VMCBZ`z%zRz0c=W!52j0LOW^|zt^UtXIdXZ+K?DLGlsEgxxST~02`2>D~ zXZ$Xn@wc&N;v83v5AZ8(1$Lx7QZ6+&m#zd<4Cw$~m{xw6?ci})$FSFfw8d~dkA&ml zI1a{fTD0105g>oeJU(r&50a>d8mr(qxYi}`Vp!j&5KHj5-^~-n zJpE&5xN2m8Yf?pabR|fdxeHA5m3S9(OvEr12ro<&_`!6XpP9`J##Tc-^zHHHrEuqi z$w2Ia-vGNP4sW=5-(Lybv3#DEhe`*rjpBqbRtWqe?Zq^g=ZK zd_OHbCL1^zUypQ#1)GH9wkm}?A3U`#F?IK11}>WGci(*bzcc8!mU2!jFxx5=@gvL7 zlON&I!byI$V~WeVM*3|q6OxHfi{*K`~D+hfEfY|{#FL>F=vPEF-` zBrW_P=;LH!1JN}S?#q@RlV`6pS$a; zOFhv!A8OA%{=;W?z3NRVY5Dzx=a142n8p}PBy7hxQI*aO|F*0)-&hFxmxn%g*Qd_s z-1ClRUcDoA2k@l@2VOv^Ug@E^FXi!3@#ZBceBg^$?&$pJ!o%ugS)caSTW|G-vZ?!l zw=HL$mvMd&_)fmN@XiPBzI*OltrnhRdAQ;C?np^7_%868<<9jomIC>4ESGu9J@=5Cw6Y$nX2p<~w1-tis=99;S*smZw+^9KU#!SeMMdg}%zi{Aq!)9#ML?!Im^ZOlz zMDibbIWTM}1iq8Eg_|Du{M{3coVVdc?R)O|)Kn~&x&ioNqv!r*g}}YzPU<%rEqrK# z0s!1|&;G(yJ5ujc_-h*8>HkXw74*Mfxg)jbd!N~#YX*U)S3P#`z5RMrKL_+Ro7OKF zhCx4Y=-^#nYbKGFl)ZlQeRpj1P4M>u*R+D(F93cdPVn3Jedd$Lnoa1u_5zlQXP$g$ zVtw!14ko*c3S7%eXcMW$P|&;kl2gC)`Tz4bqpcv=azWg5^KHLsF@FQRvemRNXb4YY z%^xhblc!N=i3O;}vrjyHe0}fRJ{|8YjEZnI;S*qfiJ=)0^B1vf>gIdD_!mc8O?^d8 z@eRLoN56Q%UjjF;Bp)jUg@00U|KR@5{?&<<;^Bhu#W%k1!*5l?e*t;(O7qeZ2oGD8 zKfV9po!?n`RxTji@PU2TiseuE#jPU#2=u=;JGEO1E+_>k;imV0_*GV9AMjpQAWms8 z6!8z3=UB?N^zc2VN2iP>nr% z_Q&$^$zL_d+g0@Kz@;n9(o+gw7m=^WvK{|g{Sd~N0$y?oFca^*+a>9(OwnLRyt41s+xS0lxoGqZ%_-3NLvDsD~SG`OsFZbBV$>EL#ya18ad*(N7!U zT~Vp%lu5t`GQddmGlX(d(4!VT>RR(mBO5U;6#RcqJ^M6;<%!?`0000