From 6503b7cb4ae8b114132553404148f1d6c19ddc59 Mon Sep 17 00:00:00 2001 From: Alex Stoica Date: Thu, 11 Feb 2021 16:00:55 +0200 Subject: [PATCH] Add new data structure, update API to version 5, add more tests --- .travis.yml | 2 - README.md | 72 +++++++++---- composer.json | 12 ++- example.php | 70 ------------- examples/getMoreCIFs.php | 21 ++++ examples/getOneCIF.php | 18 ++++ phpunit.xml.dist | 34 +++---- response.PNG | Bin 37669 -> 0 bytes src/Client.php | 162 ++++++------------------------ src/Http.php | 65 ++++++++++++ src/Models/Company.php | 111 ++++++++++++++++++++ src/Models/CompanyAddress.php | 59 +++++++++++ src/Models/CompanyTVA.php | 99 ++++++++++++++++++ src/Parser.php | 66 ++++++++++++ tests/Integrations/FlowTest.php | 51 ++++++++++ tests/Test.php | 50 --------- tests/TestCase.php | 17 ---- tests/Unit/HttpTest.php | 16 +++ tests/Unit/Models/CompanyTest.php | 50 +++++++++ tests/Unit/ParserTest.php | 29 ++++++ 20 files changed, 687 insertions(+), 317 deletions(-) delete mode 100644 example.php create mode 100644 examples/getMoreCIFs.php create mode 100644 examples/getOneCIF.php delete mode 100644 response.PNG create mode 100644 src/Http.php create mode 100644 src/Models/Company.php create mode 100644 src/Models/CompanyAddress.php create mode 100644 src/Models/CompanyTVA.php create mode 100644 src/Parser.php create mode 100644 tests/Integrations/FlowTest.php delete mode 100644 tests/Test.php delete mode 100644 tests/TestCase.php create mode 100644 tests/Unit/HttpTest.php create mode 100644 tests/Unit/Models/CompanyTest.php create mode 100644 tests/Unit/ParserTest.php diff --git a/.travis.yml b/.travis.yml index 641c415..593a583 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,5 @@ language: php php: - - 5.6 - - 7.0 - 7.1 - 7.2 - 7.3 diff --git a/README.md b/README.md index 74fdf33..b24ea7b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ Librarie PHP pentru verificarea gratuita a contribuabililor care sunt inregistra Date care pot fi obtinute: - Denumire/Adresa companie + - Numar Registrul Comertului + - Numar de telefon - Platitor/Neplatitor TVA - Platitor TVA la incasare - ~~Platitor Split TVA~~ **OUG 23/2017 privind plata defalcată a TVA a fost abrogata incepand cu 1 februarie 2020** @@ -35,63 +37,89 @@ $anaf = new \Itrack\Anaf\Client(); ### Pentru a verifica doar un CUI foloseste metoda ```php -$cui = "123456"; +$cif = "123456"; $dataVerificare = "YYYY-MM-DD"; -$anaf->addCui($cui, $dataVerificare); +$anaf->addCif($cif, $dataVerificare); ``` #### Conform exemplului de mai jos: ```php -$cui = "123456"; +$cif = "123456"; $dataVerificare = "2019-05-20"; -$anaf->addCui($cui, $dataVerificare); -$raspuns = $anaf->getOneResult(); +$anaf->addCif($cif, $dataVerificare); +$company = $anaf->first(); + +// Metode disponibile +echo $company->getName(); +echo $company->getCIF(); +echo $company->getRegCom(); +echo $company->getPhone(); + +echo $company->getFullAddress(); +echo $company->getAddress()->getCounty(); +echo $company->getAddress()->getCounty(); +echo $company->getAddress()->getStreet(); +echo $company->getAddress()->getStreetNumber(); +echo $company->getAddress()->getOthers(); + +echo $company->getTVA()->hasTVA(); +echo $company->getTVA()->getTVAEnrollDate(); +echo $company->getTVA()->getTVAEndDate(); + +echo $company->getTVA()->hasTVACollection(); +echo $company->getTVA()->getTVACollectionEnrollDate(); +echo $company->getTVA()->getTVACollectionEndDate(); + +echo $company->getTVA()->hasTVASplit(); +echo $company->getTVA()->getTVASplitEnrollDate(); +echo $company->getTVA()->getTVASplitEndDate(); +echo $company->getTVA()->getTVASplitIBAN(); + +echo $company->getReactivationDate(); +echo $company->getInactivationDate(); +echo $company->getDeletionDate(); +echo $company->isActive(); ``` ### Pentru a verifica mai multe CUI-uri in acelasi timp foloseste urmeaza exemplul de mai jos: ```php -$anaf->addCui("123456", "2019-05-20"); -$anaf->addCui("RO654321"); // Daca data nu este setata, valoarea default va fi data de azi -$raspuns = $anaf->getResults(); +$anaf->addCif("123456", "2019-05-20"); +$anaf->addCif("RO654321"); // Daca data nu este setata, valoarea default va fi data de azi +$raspuns = $anaf->get(); // SAU -$cuis = [ +$cifs = [ "123456", "RO6543221" ]; -$anaf->addCui($cuis, "2019-05-20"); -$raspuns = $anaf->getResults(); +$anaf->addCif($cuis, "2019-05-20"); +$raspuns = $anaf->get(); ``` -# Exemplu raspuns -![Raspuns ANAF](https://github.com/itrack/anaf/blob/master/response.PNG?raw=true) - - # Limite Poti solicita raspuns pentru maxim 500 de CUI-uri simultan cu o rata de 1 request / secunda. # Requirements -* PHP >= 5.5 +* PHP >= 7.1 * Ext-Curl * Ext-Json * Ext-Mbstring -# Tratarea exceptiilor -Din versiunea 2.0.0 am adaugat exceptii pentru tratarea erorilor, pentru a nu afecta mediile de productie te rog sa tratezi aceste exceptii prin try -> catch - -Exceptii: +# Exceptii: * Itrack\Anaf\Exceptions\LimitExceeded - Ai depasit limita de 500 de CUI-uri / request; * Itrack\Anaf\Exceptions\ResponseFailed - Raspunsul primit de la ANAF nu este in format JSON, exceptia returneaza body-ul raspunsului pentru a fi verificat manual; * Itrack\Anaf\Exceptions\RequestFailed - Raspunsul primit de la ANAF nu are status de succes, verifica manual raspunsul primit in exceptie. +# Upgrade de la 2 la 3 +Versiunea 2 nu este compatibila cu versiunea 3, daca aveti o implementare vechie, trebuie refacuta pentru a fi compatibila. + # Contribuitori [![Contribuitori](https://contributors-img.firebaseapp.com/image?repo=itrack/anaf)](https://github.com/itrack/anaf/graphs/contributors) # Linkuri utile -https://blog.turma.ro/api-anaf/
-https://webservicesp.anaf.ro/PlatitorTvaRest/api/v4/ +https://webservicesp.anaf.ro/PlatitorTvaRest/api/v5/ diff --git a/composer.json b/composer.json index 06bd389..69d7a8c 100644 --- a/composer.json +++ b/composer.json @@ -1,29 +1,31 @@ { "name": "itrack/anaf", "type": "library", - "version": "2.0.1", + "version": "3.0.0", "description": "API ANAF pentru verificarea contribuabililor care sunt inregistrati conform art. 316 din Codul Fiscal", "authors": [{ "name": "Alex Stoica", "email": "0x01.alex+github@gmail.com" }], "keywords": [ + "api anaf", "verificare tva", "inregistrat tva", - "api anaf", - "webservie anaf" + "webservie anaf", + "date firma", + "mfinante" ], "license": [ "MIT" ], "require": { - "php": ">=5.5", + "php": ">=7.1", "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^8.5" + "phpunit/phpunit": "^7.5.20 || ^9.5.2" }, "autoload": { "psr-4": { diff --git a/example.php b/example.php deleted file mode 100644 index cbb75ef..0000000 --- a/example.php +++ /dev/null @@ -1,70 +0,0 @@ -addCui(123456, "2019-05-31"); -$anaf->addCui("RO16826034"); - -print_r($anaf->getResults()); - -// Gather data about more CUI's using an array -$anaf = new \Itrack\Anaf\Client(); - -$cuis = [ - "RO123456", - "123456", - 123456 -]; -$anaf->addCui($cuis); - -print_r($anaf->getResults()); - -// Gather data about one CUI -$anaf = new \Itrack\Anaf\Client(); - -$anaf->addCui("14080700"); - -print_r($anaf->getOneResult()); - -/* -Output example: - -stdClass Object -( - [cui] => 14080700 - [data] => 2019-06-01 - [denumire] => REALITATEA MEDIA SA - [adresa] => stdClass Object - ( - [raw] => MUNICIPIUL BUCUREŞTI, SECTOR 1, ŞOS. BUCUREŞTI-PLOIEŞTI, NR.172-176, BL.CORP A, ET.3, AP.CAMERA 5 - [judet] => Municipiul Bucureşti - [localitate] => Sector 1 - [strada] => Şos. Bucureşti-Ploieşti - [numar] => 172-176 - [altele] => Bl.corp A, Et.3, Ap.camera 5 - ) - - [scpTVA] => 1 - [data_inceput_ScpTVA] => 2001-08-01 - [data_sfarsit_ScpTVA] => - [data_anul_imp_ScpTVA] => - [mesaj_ScpTVA] => platitor IN SCOPURI de TVA la data cautata - [dataInceputTvaInc] => - [dataSfarsitTvaInc] => - [dataActualizareTvaInc] => - [dataPublicareTvaInc] => - [tipActTvaInc] => - [statusTvaIncasare] => - [dataInactivare] => - [dataReactivare] => - [dataPublicare] => - [dataRadiere] => - [statusInactivi] => - [dataInceputSplitTVA] => 2018-03-01 - [dataAnulareSplitTVA] => - [statusSplitTVA] => 1 - [iban] => RO53TREZ701505001XXXXTVA -) - */ \ No newline at end of file diff --git a/examples/getMoreCIFs.php b/examples/getMoreCIFs.php new file mode 100644 index 0000000..2190654 --- /dev/null +++ b/examples/getMoreCIFs.php @@ -0,0 +1,21 @@ +addCif("14080700"); +$anaf->addCif("RO16826034"); +$companies = $anaf->get(); + +foreach ($companies as $company) { + echo $company->getName(); + echo $company->getCIF(); + echo $company->getRegCom(); + echo $company->getPhone(); + echo $company->getAddress()->getCounty(); + echo $company->getAddress()->getCounty(); + echo $company->getAddress()->getStreet(); + echo $company->getAddress()->getStreetNumber(); + + // ... etc +} diff --git a/examples/getOneCIF.php b/examples/getOneCIF.php new file mode 100644 index 0000000..59d7c35 --- /dev/null +++ b/examples/getOneCIF.php @@ -0,0 +1,18 @@ +addCif("14080700"); +$company = $anaf->first(); + +echo $company->getName(); +echo $company->getCIF(); +echo $company->getRegCom(); +echo $company->getPhone(); +echo $company->getAddress()->getCounty(); +echo $company->getAddress()->getCounty(); +echo $company->getAddress()->getStreet(); +echo $company->getAddress()->getStreetNumber(); + +// ... etc \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d86ec31..e4565ca 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,19 +1,17 @@ - - - - - tests/ - - - - - - src/ - - ./tests - ./vendor - - - - \ No newline at end of file + + + + src/ + + + ./tests + ./vendor + + + + + ./tests/ + + + diff --git a/response.PNG b/response.PNG deleted file mode 100644 index 27ae7da981b0907eef9592d8978e879050c199ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37669 zcmc$`c|4SF`#&tvCT)ruqQz1Xi4ob-B1@=|>`SR+#+oc+8)^F#QiPHj3duT&v5!F^ z#Z0ytW^6Sv7-Jh_nKAs%@%h~Mb3fnL@A%c1mFan-t069|ezBmu?`1+iY3cVGKlJRBPKZpy z3~$-Jsqxs6-H&dPPBn!uWF28*brGT*)WRyy)7i&xmA}9b;F}q)2VvR73N%U4%; zmCm=N)`4G$$5ceXhj#U+9pGbVqTwv~h$;~iTf3Gzf{>K%n7SQ#RxA9CUz}WMS8Tn(Ij1;P(sIK z2}DP*1@|4yZC`PUVAO+w?rn}8L+=Y_p`|0*3xL zSJZqMKAZlC)uY<)9&*zv`Z&-~qt$JH($pn3kj>h)A-?ib6Ivmp0rx!N%+hNyM3>^r z$D#4+K2&Qko^}pzHJ^{*JKzsgr1#|(FBL^S%4))6J@3k!yzZJS|AOA)9DTq{D9>HDdx+pZ-ehoN)7aO6tOD^AJJE}kP{JGDFxX5Biq4v8!J}{ztJ1sGzx{t)ERzP zGL5?zT(4>xSC@q~ZmWSaYBMb0=Yy@!o5mHm=p5{LqXhjONTk^#f)C_^&8VB|UMB4J zJB8|X-7=jbJk)>-R)kW^XzKBo#>uVucPGWP`g32BZYkuRw1Q{po;Vw?-nvUqAprtr zUUs3&T@zlmO@!oHMy43qAKd9jQPBMG^x@qDu89>NbFF_WD!$J$PKg>N-#nUor8e{Z zt1dgsv#%)L#sbMk4JrdIX^dItC*@@&AvsnQ{SMvbvv@7evCqV zd>Ry;xzbUFRoOcB&5m^QECCaa+5&{-aKp8lr$M^k(3sj2+iE^kL_5BVxvojxB? z*ne=R0u*w^(UF4uRFMNjuF5RkH zy^{zTq@-iVE`VF3O2${dpauI~rou$JBJq+xFc=c|Lz(75kUhz8=K6>E=2H`o{h8q zFuDDlfNBv6A+l&Nv$(Hc6}ew9@Rx=LI?gn1DxGQT#}emeH7#(IYYa?Uk_Quj!jWT3 zUFkG=uW0P-{-VJ5PzZPIg6YS`AmFjuaeX)O%1zcb0tYjws-idWBoWdbX%0Ia$L58O zO`f#B1dp9M-;w}1s&k?>_|C#h`O#evdULi&V+HA1&{-DUn33@T?ZFcUt0>_*T=WTKi5|T7Hek_f6jVg5K+o_I#iD0d2BU!DucSkOD72 zxNH|v^L?mR{Msrrj;SV6PX9b-%Qw1)8tFHUt6nLT;mz&DemNIxdm&8f9Hwg%gG#XY zQ%t_n;0C+aOT46uY3HN{VOU~hO z^ju3aZl=HiLy=#4p#(KEeS|36kXz%MWBxr>)|N&*4_OF7A*jeaHL$G6+)vXX-X~6P zvD9Fb{J)`(=f0#847GNZrEpUfeaakO+Zv=~XElWwHbD21)MzOdEctdESjgDgLXH7x zY9A0UN=cN!mnc9n-Gsm!NAH(pX<{>KUUgMG-z92+tlcoiSb3mLgUa%q`ibBEY)f#l z(6yQa3Q~vNBPoj&KYP(=?7W5W@9pwXn5%E4b>{Y!W+p8;E&&p;Y98#OQW&sWkr!la zhH&a6l54@57uy87Q17X;2`$q0?nsY|nNy7}Shw%`$x8b$?;VkZGA)dax#<&yHfmG6 z_aIk8-l0m@bQWuljw~{^(A_?aFZA?qbOl2#!>|9Ext0L=;`&Fao~fU)-{45;_5$9J zwrF)p^W1N@kdd)0W4upa80U%(*7&W-(@DR*aksQqBb}S$#SFd%;?SN*jQqZ?Qfu1U zCOd;o*4p75R()m_DS@w9Ir7qiSI{qvqxTyRP$+?k*fj@i29n|(<8RGNH++;`Rf{$usB_gWHZq--?=t-p*=m^#zf#tmz-3;^ah zsNr%D-nr1)f6>@-s*xC z`|bvcqv&UaGEM&${eAiPb~>{JA<>x;l8b&5tOT9p&P>oQO1^%=9^JKj##!=FUG1k7 zmdr5&LP5SFgt9y#2!JP&$xsyd|;8W$lg7f;Tb( zp|D-_1rl~WxogwIz%51#35~UwJJ>{Fy5gqo4_Vo@S{qsSgDmM#xsCI5{t+T}cTdjj z%wC?q;oGhw&vUG9$I>DW{rW`f0}eJM6Idwy%*h(9?JAk)&q;msn5`?>`_bSkt~39R zuj`cq1Peog>HCk{C$NvICACE7*}6)qCFSW^&GF1QULnK^m1A5*mR34S{jAT0Bz6Ju zX`c~nc!rkcFj^2$O|1AabE7-ED?aG1dz^7{wX#G%xA+};;6|AF z`|6Fdw^_J#^Lz(S8K@-ful1bSjp06^;(1lsC3|`6A#Z$!qAan6>>hKr*(^s@fBV8H@aQ4cK-W;(xikKRqq*wa z4p{%x+ZXH@#H*Y$lnM;a>nnN`P8sJj7xH~SkK69E>mFa#lOJV`Rj;jS;j^?oF>Pg;-9qw7k@y1pp#k` zxz}1MjTk+890AiH;7%g|1`{h{K^LGFh6@oD0}JkHb&ItwRcBCF%b>aKqr0T*>GKX> z-cRb;=uZxVm=Luc1m<$dAx&yV9*;S5zzY5+P>~|H?#G|xIa9a(?iLza{xWRGV)sJ# za`2W>#d_LrJL5p=iX3X6Z)@~aYFVhKip{#^L@p;RJ6=B#!U};o(pP22z3dZHODbR< zfqMAtp!rl@>dIEF)wkr8yJEu2xS3bvkmB$sP?ar2>w0DcuvNKTz-cSgjS1(CaeC2^ zk__eTa9G0)Sn?{g{A6x>X}gGlXW!u9LZo@UH#W7OT?e)*~d#R$GDKR(DaLs=J2dJF|?PJW>ygj{iYDilery=N!px-{6}V zRcNl&x}H(dMy@EV_4+IcWq;37w-KF|@Jw51Hg1@QxssM|RXcZ@%GHN=a9d+3cY}gv z&)c}>+_kvP5=|cOip{YLz6liT4hcpjj1YXwM+%kN=p`lPT9_b}c8F9{DFsqwN*`~o zHh3<@1=>Gw9N0HJN@IKShnBxocf1jCe4vv1Qb7u14$msKY$C^9m+flwE~A!7u5g{9 z*h|;(137Z^4!sd7l$Ch!s2fH!A)hIs6r$*Ts;r=;!+zp;S1!cLHx~=UawDzlTeF7Y zf*Ad1q5m-e3VYmL0^+m!LsX^&SS2J8XrFn#^Fg~*5vRt74Lws9a21lWwH>zHBtl<8 zXym>-FQ8U3pUK{Im0`^A{E=E3DCSXYTVSn&8GyNlwM8__=e~TC&U*xQy&}TtaxDeo zqp9yPB|v07g0SCs=CjyD4rS5;Sax0C)OP=NKC>RIY5~5FTyUuGH<)Qf%#P) z<8&7wGIkgEKxihIu2I_C2{x6xn~{osa~$zGL^2VErUKLAQW2BN1L&^TtN>puwC~Pc zkEXW*1R4Zj0d_ao)4Gph+OttrV%OdaWlJe-`d}Kj95i<&!*KIthnG_9*%;Van<{jt!&Z7z zcCn>!r6=sLj5$J+ggc{dkFmXd^1~^+{`}MItS0Ab+05dcbdL^tgI0o1+XtSeFH=2U zRcQNprjy-+@tL_{b3`Sj?*Y@@TlZ0k=9v2}yCFJQ z1#Nj%XTAg-gb=VZ!?&Y!mrfY%`?3y}DWh*c*-G(t@q z1#_1d%|n>C{?L$#{mBs?7g`nBk=5j?n+Yt_S3-d1&cWzDwXOi@ zs9Yv&TrNN2x2kU%hh+vQrsAm=)n!eS(J z=RyLe)~|Cn#H8@-Uh}+&61|Y)lePyJ)f_BE^nxQt!W?WoOnHl=1;K3A{D^u=OGSx@ zRR#IVt|M{**W;-29haxnn=HZrc$_u>8$nKhEM#~=`Zlcd-JwF9?Aj|D9N{)7>Xlhn zP^hu33nqNC&(cEp{q0uwbgps;VZ)=kARCr8WxS9@8R3BAQ`f`=3zY6e`$Ua+)l9Iv zSwQ6i#{?$AI3Y363k$&TKDW3}xmVndV4Xk#p-X|+L_ElTlx6Ie`f2aRhuNotk7lHc z+)Ava2mSuqTsEV1o4zmXw401*-ThDaF55+0J`@+=nr77)c_9pUr0|?)gvLy--5W|G z&wz}{_Ums(B#b0Ek_LQm0S87z@=C94%jM5!m zjrWEx9g`yqy^qG)d{YZCIOjwM3gt{>AfNqde8 zY^}7~5Sxq50YWVhSu|(o_F}Ip5q@M8yx3GhE0a=Y=M`CB)_XuNv3>pH`;s?fw>&hN zbQRfu+W=_{RDNU)V8f1TUqX2kql-K*Q@h`6sH>-6ON2-Z*F0VJhq@E>_MdpZegd4F zSdc!fH^$xcdYdG}y2LfNfBdVt=M<(V=2|YkIQ8_Kj;c$<+kHMuh016oEYl~PMVCyM zdMW@veg(kzVoc+9zmAK>scw3^0nr(yD*73DqB^x}bWrva)bGcGxhi$5@B?n)K0b)| zB8{0fnuB?KGsH=6dTm*`|B%74?dunn=HJ_-QtT|yl|`%VNGo<4I^FGf^1M&g2Xvmk zT4BJ7(L3cerMnH3j+z1grL|%(YL+^L6(`RgDA+7wjaK~YZFjB-T$6jo??#v9y$H#k zYjH@IRd3Tc9JJ^vbit);LnjW~gC!sN)t*W`*q2}9(&*CFise?ZO>l4-Byu@K*`9foc$3?LzcS#ZASvs+RkjHg9Es z6U`zI+?^feRgtY<@o2?2wN^Cq;E`;H)puATIBiV({&x=OrYTQcqCDOFo*;9y`0CS( zggKj%K?-*9H26M!^!mYfKS(UXYUE0_b2I|{RQKf3Bazyo!GRzF#ANK0JlWZw{mWYk zeDQ-^KUg{c#fX3^a;*p1WTBx=*AMRV)d#u})wx-$r4*!8m?T?2!A#oc?M#~1vOs>P zuOHM&7vv6wJR~Gf(rH$LCvP^K6$ZK7f#`o`*)_hF2HL!qtpe#T*epm_{hbHWe(>pq z0_(}+P-(#dQ%2=q$>9HS8Wl`H{CB4KMTxoVah~gxARXMz`wN@ST)3kWTyB0caM`U%&aW!bZ)!S!_Vh`4r`fxdo|J?iS{K-0vy_Dxx%SUJRKk8;gizr z?tr{|r;5O2wI-T(GLu+W+xR{y_~*^b5&Y1u-2GOF>*C6^r(}1QAz zSav}il`^1&(Jk~x5q!iEdaJ&{wT~UQGEcmodzvdzVPoJ{69U;p5R5A;h#JleCm?+Z5+#6ue zuJnnM9whN0hPMk!t<=(s8$yCY`!|W{RL`FvthV5Li&j6@n692ZVNYl_{LKOY|4w== zpI+4*jzU?bFDITp921tzO|LQObDj37k1;Mr&k5^9-e)l&_|ar)ZYs|?cR+DieLKQI z7lVTqc;!U+%aymgkYp*zw+K5ts!;MDn6zd09YwafWo~L9>00v<-nu7XkfFD*8uA>Q z9dwbA4JW{}*fSCMR?;6LoLm_?iQwVHNS)*c`~6*AM~`6xu9lUOpbU>snj@~|kD*mK zJ6?J9cx<-`54VIXPe_xWfOZ=N8%E#()3Zs#2y%dfmCQhSsa3rp^WZqgJc|aYn%n!ni9lNZZ|!NCL+$ zk8-wHqfbZT1P66>%lzwL_QNVeBz8e*X3=zTb^Ty+(n!0(KHf^TRQ!C4ewg~Eriv5u zy<*=JZs^vFO*+rW-G}Mg1Q3+FY4VVOYu9uz-O%tV^pcu#zk9OFtLo-Uk-r>Z)EM9| z)pBLn<9!RKNsngqN?h|(o9DcnNSXYuf`GO@1hqGY;mKr?Iu|F}T)qIP^ijv~u(|t6 zAi^$FnoTA2H`kVRb@g|+_%_cJVB+xS>07^FOP2~Hukw$jEwwR}Tvl_|FZ@Dw;&^2! z>9PslBx%@3+_j(nz7g8zOCXc%K5Jrb%T0Q#G@XpVw-HK)J)phxSZ^Ie+M`El{Zz3F zrzc$b^_OO)q9htkD}&W0m7yiv-Br9n-?kK?t+uT(=(ki~8~q>6X@6bvIdA4_!S&&qJeNLNbHVC+Lt0Ei zhf8dC7t(b2wK8L67D*)0G7yBp=5bVP{vOQ5>fF7q-F>cTh9oAZu-wo}%tOs^dp303 z2A%#gTYa?(TF{O?S2BlNaCbn;ivW>v$S%4!~mv1}XnnM*cz&e4|pmVF_eD#>Ha z!Ut>9qC~pjMKUkG69Yo#14qHt$y><25 zz+Zl^Uf?N9Bj&%EiqKD0FE@;L*<{AP!(&nKj@U9w>w)-NKu)C|j+BBf%U`0wWmEV< zdJ6*=*!Rw@6~~WdcE@Jlby=#MBC9#(%&Y%U``%BV^d63nD|L6wwY6qkuyJ>J8`kC$ zyJy5kubj>p<1_O3RQX6*mZvuw!EnL3R!{4B?;(z#w?MxKnne8a{WKYqUf=N=)ej+m zw-fNmMl-yN|6A?SDJ0+X3lvHTO>D{1PrQ@;67VoN$x6 z;Fx}H4|ekdbn{E>SS^|Cm&4C9$Wf+y&cAbx8PN%uB2*5nr0Ev{qjF&eopxu1O!DJu z=F-qx1Va1rYFpc%jH@zr^KLmxUSS`3=M0cuL7$qbp(L4~b2rpa|8c(_mWwS^^P?l7 zs}a?l7Ib?JkQfE$`lMaWm>=`KfN0{$&%`^x;9#*cVm_%Ckytaj)7v$-G*fHUCtj^3B_&!5srbFht%zB!hI#}) zmx{HBX0+?7q{UGy%gOTyDNIg$=u|jngNIsNA-pirf{|1Fw?7(RVHr%|ZrwtK^)I^E z=h!xN7XG?tag0V&!Rbz%Q!;2~GRr>xhQbM`x6vH4fY)u_Z4)}3EYe62ysK7G^EN%S zA&YRTR<)q$mnF}}zsW(FzAydD2;qy}2c%PDqz#^oAB)AYd)}etRsKwnU5-%C)vRov zUOq6$*%;B)H23qC)$8Ip5!9GmlEr(JU5dqu(RXsObNua4=_q*z2~y|J8|aI? z?ewa4j@xlF#49fYLvwe7e#qpz$-&7?7e__DWNBc-OaZz$W73-brs&rJ$1f4*>8&m( zh%zbWm}hzlwP$MZ!yPO}8m0LmHDK;lkZKZkbC_XDrz~M!FSZc-x3C}xx+iwQ{Rg?S zkYaf1*gS$?P|J?Z4veToU$gtxTZq5hCHs3cYToMM6*(5KRCOVpcFuOO*(;|eu#iU}x%C@z+rv@nn8XGfp)CQ*yIm4BfpP=f$ha@v1ZS%@a^+sA^ zJlaBF=thB7tsL5~Zw1G=zWh{ZtXp=+>LQ45^{u@ z{cVZ*v)tvwz-x8b@6XS*zKWbTLv+zXBa@q!ndDE#{e*rS53j^$d}kW1dJ;HD^`8OdQ#7! zBUL&4Im2V-RF8wzqyOLt?jzZ0K zPQ0ND4IqStVw-=fUu4$k3GD4HWug&^#TQaIU z();ravNW;fG>{8S&s}Xs&l}H2Isl|kifWV&W+Pc7o+ZULzbOgmu;nX-8T*AzM& z8`so{Sv@Pwf^g^sJ=pFNE?I+&o8eZKHJl~-upZsu>>#CI?KgCxKj`k>he`=skgr;G zf>(!3FLd(H&4U^SIN4y7e>e~FNLPvi~mP-MrxKWnAZ_0W)+{%T9y^}Uf zNlqO!m0VE9Y2bt8zDz*jnhS1)WD@B+mvYSDB75aDmetr#MKst|s|J#W^8!ss_wU5J zrrLHxd}!E4WFflv*^H*^umi-L7K|#qL7;NYJ#g@dSwvt}V4j{8^KXg1|Gi_oRbCeI z;2nt#nM$U?JtJy;jqB5j2$G|!c5j0pwIu3SX{9=zT75DWGrTO7S?e_))BZ88-fJu0 zJ**R1RBpWx?Wl_xt{l9@U|j#PlBMq9t-^oM9kcq&!R1SngD#7+99~Y!X|L!YY0#T5 z1e%4F_!S`*^4pb`F)JGn?PYs`gY|&JU<~$DS zJKJlRb8rMnrH&yTt}Q@ZcvMGD-#%x#Sf1e+q;_6rf;f0jpR2L7*Rgva;EQetu$V(+24;1Eq2f8qil(;fxY!@2#(N#fUfz4(hh0C|K zU3%_QVpj99ZlgGMqtc~&D+=U&&xdsut9!8Q#r&{eu`@gV_tJ#mxCiPM-+IN<=ijPC z@JwBUb9_xet-@PC>Y*%3CPDa=Yxt^-Ii8HW((_^QGoQS$5gUb~5(TFctt(fSI2Sxj z;aUDy6^@m4>6=}5rg4z;9$vK)WUWrRh@s*@CIkw zF%sDs^}Jf-Jm!uaazSsJ{9F^hz&p-ckOW;x6DF9 z?_WRQrN)6erw6iRI^9!OYx`5nF?zf9y-kGJua+D@?kMlwM8SXTved)er75#+4wG6D z&Y@mqgPj5Pr!X8rBsGIyBKG}3(r_i*zBdXUTmD}YTSR9Dde`BgxmPwNe5iNi{L-RIADL?pQq;urBp(22TmtD3NmE+j0HRKENZBwBirAb`K zH6kKN%D8C0GLeh;A%$Uglit{p_X!DEDgpifd?3_9+7GXuTO9WOhIzkjcI~XL1o=_| zq$JEl5hu(A)q6TDkrO{Cu_bV&y|3D#Abhe%R!BP{+_U!*andGD|W&HFGtsa<}i@_$WiIJIoR0PUl_#X~Hj|*unsrn*1B|~*Kn;&8LIF|7{|r}JLL>pQF`-L4bJ0f`2!;U!1=#KZrpwhBy*!2dJt`?==?2FqN~X>w{jRVK(w9T99Q zpc0Wd$`xAvWmtxjoKQbJcRim+Jbu7B5!I{L?+1JM3z)DT(@kToa`vSiW?cDf}S?!P@Ud&<(*3 zuoZw4lkOtS5M%qQDcKGh3z2-{d<|F)W;gH&-RmarPA3z@-(AJ>n328%zTUbqbo-^g zID0ve5&Qw`2Lv=~?_96E+@=9uvEkswlrFopi`cu9*(Jr4NL*@hX}WY`Q@S2uo1iK( z4N8D%{lHnOzL43Na;5I=cSX7Lp}y?Xc>&wCb5KiDvJ!*hmnAM0b=jNCc0JE|kLGap zEuDd7b}LCsQa(+*JY%PAXcK_dmX1pb%su^tpLUVeDp!7?O$X4zBJY2CQ4*#Dm=4cN z&XkDDvI%9r+hu5kfhX(e8xtV+{q$m3_uRip9E@Sk+=Cr%TUhBa>2VoH%om=*ahsJo zk>oZ!*Gr|yykBP`5t10{T@5AOH~D{t&fhk=rQT6ibN;hXX# zZRok1$~?SF=PluS`EvC6tj==|%rM<}dE@>*1gYtF)m6-wq5)-gtH9sa$?X)xlAjBc zS;o#o6onlh)_Ld*6?z6_6U}BbLcv0JPad%Qe6k4e9x%1mhc%o_QY(E;wx|@YF-WIV z!J8r;)Ji2lvd?IU$!3bwU*+aUl2`mq`yug@l(Jaw#<@cI zzyMc6>6Q+#l5?gYznURX8mikgV1oAR9bxSfP9(uhj2Lq>3tCUMKe)t-pWHi2jpG%F zDN@G2K8+zJ%!H*%#Db_-Y!-m=z3``ir%H793kZ8;^OTA@FfPJ!DLfd7cHTXW^N zz*cO`4(M#&x(=0q(!QxAn*E?)(4fL1Rg1cEah-cx2)w!PJ2y?FW)D3V&QO)HKDxuw z8-F~vz07rh4d^4lqZepsOtJ|J3wr0p32 zypV?yFA5k*L!IEFDglkk@vV2upX=S4iGLv|!Y#i3ujqegiIdyIc`d_1ato|oF3N20 z!)eWcXQcb&Eoo*$3hhq~fl9g9R8!yEv>q_V1ab3USzy{Bg^SNkw(6yH?bY#{a1_7q zI2*y=!bE@3^S`&EK24(w-54s9)1dH8mC>Ss*qPzZ4*ilaO|}l z)=4Y0I+2_W?VGFF>l(wgw=sd0diz?z3oz+a_0>Em2u~F+N*vAMT^p7W9OL^JU30`7 zKGe6&Sw0+^d{~Aa3(2elOtoS_uyf!;^!DA;kFJ@GY$I!$Jr0N0UYXXT5vW#ZQUy-w(WDp2OA>j!hy z#m3g8x6W zDz0;u7u~XuaYJ3mUQ7?f56!fKaO(M{soOtWe#t`N$WXcq&IS%P{vvfrS6kL z?oI_s+2O{h_gb%I`s;s+e(uzweST*-9stWJLO&hP7(+TASUoG(wwFDV<4+=cd?se| zA<7hc=jsbrUg%6IU%LAzVncv8bDP|5hhE~iPIwU34Dp&cI?la-ut6~0e{jmt>34Mr zzW;0)U|2@@os`_D9UL*Fvsd)up8A_BiyzX}hH_*pZ?5>@(;a<#)XNo)?nHX) zwdvd;lCoq$bXWo?!}$WtJ=JM6VRQT$oPg@2F0WCGswMaurs)0h!=4h4V%JukMjpyE zKel^v!=eCU#52eK7-6-Zz8JUIb?K#>_$lNqJ?FvlADZiM2B5wg6)#A`r)C*TKD0C} zKe#P4Gt2m`or&pV)o+sz2Ab)2J8LJKyg9eb142&cz8ncedC7w#3&-K7%bW8b(`>6F z8~KGZ-$S@Jo3wvj?G-H3Ljbd3XEPM9U$M@yIG<&pSU;r);LEQ!{xok#X@ksnCl?2; zc7OA|A~jdeEKSfGquh;5F&@u!9VC}&yohPGHgSj}eW?IU{2^^{fDZB_9fjq+kmmwi^tJ&mL@VAHgX!KUE>z3D;Mm6I7*>!dD| zc&uZ2 zz;b{VPXpFP8hVZBDA;U($;&s^%(dzat>)RO<`KHE+W^zoE*_oqV@f zb2t|X2Zs~Gz^hIN3kLre(^1R(X*BErde;%2{Pt^H>J5rN{)gV?P5{qE121w`>$92w zPH;>Qj@0+Z=#39YO!}7rjtD3GIPV)|<;NCAv#r&7A(>-qh7@TFbJqjlNxOIks|c+^ z4i<%Bm}jJ44MeK8OBR59iCrOp(vt#xK2lw}LAQwH zd$J(#)aoo+MeX#7+!?|uFkU$wtgp)#)Egjzx_ttmaG_4W@7aLzhVT9d^uw0V&&NbW zI?gxMZs=z9;T5LS#wkNf2Je?t3+umguU7SSaB(Ayn;b7q-p|@c@5H|HLgNERn|eiv ziDj5@+BuqW=)@u+vr5f=vzZ6;t8dwf?NN>X)&-cKU zXk#3d0Sh7O9FSta1B|}%V_{AW*RQrb3kufEBbIepU|&U$G(`G3#8U z9=38lFWk2RH7Zu$@#oC_Ty>w#qwkkK1Yvq(_T=ApkQUm&P;~uKHqfCbMpwZR4s1!F zA-yaQ*w~?MXP=iOQNu3^)zm)bv249hy3KGr`lfCcHk-zMr#$?w?<_;=?5L`x7YGYo z7WjASnGBiOdxW};MwW}_%Vr1gdxzp4ynuijMp?kZ^STmw4o*MhDZ_CEvGCnRB`?J5 z=wEG=yU@!jb2uFnOO_@=x8!(F5p16jf$4=K)%UL-N`>|z3D<~>aVDu^u*HFt2+0q- zT%1F5*tGfuhKB{a82{a;}%UvM{O=7m`S-ZAD zL;+{psFP1kE*Afd#4F|Q+~_Nj4gInHOZORnX3dsoVLj+y{ZsIdo1z?n=x_OMj>;G0 zyCts3%~488${H9nN^!~ zcDpJql+2@&iT!VdNyVUC^K^t(=ppk7yYX&J*c?2vNSEbKSv>vg zhG8yWW!+B_f9&Q(Z&>C@JLgE3Thv;5$y`SbC=Jje@j*=^VE`}fXFI?$XP3&Wa`w=X zFp6axQdnpx4k%-hxQH1DYzEUNsdd@nJB$fm7uJ1o`sqVg|SD#&5XY7wo^FuDDM30@_u^NUCbGgU@q{kXT4%QTI0+$(oeV}sHe94u@ULcu+ zGgy?NK%G9*a#sgji_DG7o0JkD7Z?3r=%p6H0YYgO zb|xcCE{k~%_~s!eK>u;R0ov34A^b>5?iwF>JUhtR z-1jvE&qsA`65G6_w{|CJvWu$L1Y-_eZ8&>3g+@ZH{>{AvKMBsLimHaE8hvmf z0>9D+vb4^UvM63<>-Wicd-JZWuSC%7x|Myb03_3eCO~__fN26m;*q+uk43b5YQ<<) zwW^{~q-{|3wbm(sNjtO&*c3NFrWcyl0&_%OfzeSZj$uz4RF-xqC_L7x`U86I5Zu?r zqcdUDTXAZJ5ApEfr_?^H?GfWC3euxK68f)^LX^n zZncZ##IBV^LUX({$RhYtNMY#)0=*Pk{0P{C2-CQ{C_@El#itL#h9X!GCU-xy8dnh+ z5pz!^h$_Hyl%*$$J-43gjwYT{Q#ve326Q^1c|niV@gd*!Gmn_T?dVmlslaCnq zcwSm^y!`&**NGYDj_gIrS0IP#>09BKk?CaobBInaLQd-VQK$i_*3{QTt8 zMxp8*4^wt2#<+uAlY&|7`CF{L=1(7jhe>7uc9%qs|IIDV1QfqQMQCXDA7hIsya&uZ zE#oih{&)@BJM2W$xUQ5nRbIRR?y^yWhO(nVS9GK*wKt*0SxRvR`|fT|*x4x3*x+~> zV+mJLxEwv-;ppLFWxU4qoxTDDucZWy{&U7`%cTbsVMA!t<++doN-RId|{L*G|*8P-kHe?0?8ndGkYqy>c;zegSEB?!?kA87=b2&U zEu&A$Pu9#8$|!hTg0~LtI=n^@eD_~vc^c^YGc2VP8h*f@fC&^ddA5y7#U|-58cPEc zKP70ZRD{+FNQyW?#{1~~+1xWFR`76FLIab~VTsU|4^Id#xH52Yk{8OagswVkoA=Yf z;ljR`ua0Ob-=2=MEhXiYD#rP>rqHr1D_o(0laHa{3ca@N6tC5Ee$}WI5is?SfQc5K zBtlRf+YmjX?Vb9*!VTq<=D*Sc-QOsxo*pZTY0+VR_n|z~;F%Mt6P2%o7h5XWpEb)( z{amd*j#P^vs*NtVI!9lx!KO5dTx(Zi0NYYoYYGLKYeLfxFltIRA&6ixmUh7?{BSDc zr*TT3UD}swl7pv#+K)t?D|eOjH$KsogO6+S2I5Z@xiXe!S|#=)40J%o*zE!!1E&tD zh+-tJ*X?pmcYb@M2A{ETDJmg8m~1SytZ6ipMQC8nc<+FgN)>e9KtUspi}>bx{eY;_ z=B3!PedUGMm(m*PW7MrgV>oJgklri~ng}YG47{&gul***OLBoLDfRR@R}Ue`P;^JlWPIF1764~Sf=@C*-Cr18eU%O@P zO2;{!HWy7#0|EDwBJi2ocAKzm51t(9nT#%Ol~{+g(d{-fvUI|blv5d3tKJ?gP5bm( z#4CyJX;bh^D|agFEnTFZ+lLr|e!fTiTbv3Gdn-Gvz&5lqJPmrH)Y^s8@0BB#CK|_WOdsP4E(MH$_1(dpu28|@wzV)RK1XI z>jzZbHVYH=DvoS8j2;ilONvgb2&dXwM0JUN&R)8=g>@-DXv3>K=87TDvWrI{s3 zN*AaZhGw6#)X%T;f&7>U{k2z_KAd*H^N={OZ%tnse>o>6%Qq{ z0hUN!Ydd(D?N+k=@@b0`?HdA&PS7Zx(Nuf%*?!ZZl5DhS#3vmJNn=~&ZPPfic8_fN z%#Qg}r5etJ0lgz{$zh@5h`IZ7CNlD>ZTKLUmT?_rrDE#r*%N(*5kGw#GJl7-*r=xm z&OqiB-AVH*X%sW`^#~8l>*n#0=*kNol}&3~@(Qeirl6gvA{tEEa4#ot7KvZW$WQx% zy#j3_w-X>w*0S$C*1(>3FN>FZ`9_d<&3}9!{e@Qhi+^=`b&R9q4w~P`jwOaE?9T={AHD$^hROMN_RjY`WTe zWvWXFT8nl4#le$LSpC_}3o}~t6?&2pfmuy6hMx<^$&Vs6ew3aD-#O@;k*t5BCaW1?^H@=P0iz! z`N_Y6``#3Pyho(!-ils2&z7N%CP>Ewge=%Aw+VWW1ua6h5^33W0f)>*S_j}Ks%n?D z9yZX#LP?4;x80vlZm_UAccIrz>@bICc*?fN-t$Sf1V)ZIxsp4?<#S=5i-ji1p$ z%1bJ`EBA9?dLA<&Ray^9UQ*>&7Z&{=taTzI2_=BOE}%lhmnV1KdB7Uu*dH2l5%|`I zej&vD+upi}V_c-j_#6KWCk@OM#|TtORJe82emv{O%_na7?M*3$=JIQ}h}ToZujtTL z3Y2WB^&?h&ZPC8J6W5s}jv)LTpmPz-tJ#CA9U#psv@8y+NAkfJl^2)b1D|)2k%xX3 zj3GXVYo-X#KPhC9#&a@)PUeJLoQm~OSO3|gY-h!~*AllROWLKO;hEOkzpJtNIJzWU zJX41#OGuaw{SUucd5-~LaorSXLiat|qayP7%At(o(xRwBy%X3?n)y_F=(bBKiJJkM z>z*lHw*;FW{3u6iPJldU?rGW_jSD>byyR7#{b>)r^TFK0BkH@7aPBG!yMkPEpq|_E zJp{)LTd*(XyS*fZzvvCIgjWv?wXPpXI#W`GhBI3pX3yt0fdtrSxBMvsbl2!5M%Bs3 zWDG!EsJ8+ThIRCz^+v?}jlrS}1(5f~r+xju4f*-pWrpQz6}zpPr%FrgbxhRCU3D-P zrf~zX4!1FCKj3i!&lQA;VLxkL>Y`aeB2NC<)r!?-jD{;(VLM^M3U{#k7eEU$0chvS zV*rel>u*c7~lV?j{ zqUD1?YeYQs6e_IgmjG%2KP{F6cazvPbaV{_uD$>(Il3r4aQ1RV+iJ*?*fVkwjPa4{xTe`P-4O;W#HNpc3Sld%&( zDqAp&JT&OD6^yPz)h7}!B&vik2lfzeoJ#im{a&IFDL4S7A=Vb}@b|s5DG3mP1Bo9z z4m%z5e>(f}c&OL+Z^=?rDnewbEEOfENDNXPWe=5oDMgGW$yjG>CmlsZc4HJmma&bU zQ9_g%`(SKYvy7!-Ft+FZjK1f)Jm1&vIlt$>)4^xCKlgRr*Y&>M*ZZ0}t5W2~jm~%* z=B&y)xiCjHP5>4SQFuVov(T)1>D_DA`J&Q8p?Na+`jmz4fWat@z;T4|uKBdVF$#xk zm8+ z>hj*ipUsjzReV9q)_2?2Z)i8YDdE+G91E2gHuL%qV@=QW2X$hukLTz6R&cH`(BldM zG;V%eCJ}LOcCSCrCvdAh(6N$xPf7DvSeHT> zOU_inlFPOb&kzRI{dpFqjm}mTpFe>{w-%|2)VG?`8CuTYh#$Qx1sjW=@-|XMrfu!) zX{*s`#+~ZX7qRO$C-3=en%csF(JyF$eP+fX#;In-(^L8|wKgxBed37PgF8w`V#p!f z>>Xa)E~B0?g!_I#4MXa$%`ERP1&g*U8SJ^J-X4`(LHWrNF z?JDMGC(i)Y2l_PbEC;13qSKR3k&LfGBdU4H0}9FYMV=(=M{$K4^+jE|dLTQkrEEf$XRbT9LhCjT z3c`LPu|eQ;G1bxFWY<|#-t{yu?Logz-7|@=mQ{i`g08|FJ1os^I)oCfl6mY&l8gw* z<7Qfcqn<X13NOnC;B2gSoXtDnYzq5y4>}HwYlQjE zwR!eoZXlJVbEoyM1&nUPZl zniOl)>V3iYKtXPe8LKL$+kI@(akOcNSO66OfWuk6CMGA($hI>RHx&qnrRYb#5%o+$>Hcb9gPvO5uGmYzVL#V?)8n+S~HV}SGWaV?E zO-U+?VP^o2624qNgec!UIr+nXa;itQ2+#@}!KqD>VB5({i+p6WWLa{XfbdYx%8RP- z{*~oEWQ)UhzQwskK+VaS-HO9`Wh}3mS(#MSkv`we)4~(#-CW--I|Y?bXpaTEPvZ$5 z-Z2%TPuHpVx$-Essq;UYomc!H zx({uQ$-Gly(ehj4+Z>^mYdJvuUqNdC8FVM2-&~JpXf8fZu)wyCH8Ij5>juhM1i0J*?Me*YYl=5@2qZHckkd!%@eb znFE$yx~>mR#U`%G)84~EPzB#+Sp3wE0hZ)L%D22ryg?aXu3q7Oc4m90-2`>{o4 zkle;Y2hO$7!}3bq&ce2@$q~_cg!{M5XG=xws6)@Hg;h(QHWblRlRF=+&(oe9B-nhX z^I}j=Cd(Vtr%^B50qF_hbbr*%E9fWwGeuHYAP8j9OPahTsmD;UMzGk>8cIoSQ z8sU=+l@mU&8L4Dhmx<1EG!9R%7R37=il;nZRR?up?$S9 zx9NKR`%!%Qu==(1=arsQs2wE+vZi^&UQ|>1gQ08~c?@FsXqA4+`rH22eP` zj+e*Mj-?eKc#}!kob3l2;XkJ?htA~S2c?Y#+-gMH5?X}uKl=(D#>=Bje9)L|lgS=9 zb}tvXabrXH#-!x@dM=gT3alXmf+J~PXTK<%kJ~VaV!yd!WqEbfYOr1AzLVEw>qmZv zn#m@s^_jWbjs`Xh{N&Zxv1O}f4t!ZGbA38)jwFjaviVam`Yd5P#Ok_L2j^u}%M*C$plDbmRSZ8m-0C0LD{pqDFEX4=d7auL14qig59NTT6 z1k(SdxRSxA-(>8`;oWC_lI52Zs?X$6<)d(VZqgF_1?s)R8_Nr~!rFx&P`zQL>Z-Bb z)n&m)I7Z`>>vFO2NA5Ok#Q7D!&ze zPg?PIGP#prQ^SkKk=Du++y`5YT=xt3gk4s)U0k#5Fe)y2wmb;86fqTH8eW3pvd!Q6 zw@>t&CvF&YY##2|4(wn(m~Q2%Ss^csfAij|+15|TVhilGBA}P^Eqy_YJQh24Tb{D5 zLI9yaBPkUjL5c}XU;27aYQ4Uce}h1BifAZwvMTX%o^J#ub=%L}(j7Ho^=VQQxg0~D zqKnL%peE*Dtkcs*j?U19=M9TIhK5?U&Z3*NJ5VY^kMIV)Po3swyuPm3b*|)~am(|a zIn)jJ`zT8`u=_4hq|mP&&szEoKDgTm6KE6$&Rx^zl1mX8pE*~!>^|6Tv62}&hni$U7H@_1H=S_^tdm$oQNq3FRFIs^6;8_`V*I25(Tg+D!#OY@SQ5zk~;5( z+z;0wKJ7p~Jy7RXQjSde_xm%9DpfE^>lq|3;sp?k)mnmYsC=kc)1gX(Lic?# zhq0VgCf*#ANrv$M6;23?8MAQCcDWW;t$hC}axE7UKzOLcUGM6FA+}Zt*|gvNUUc=n zOVOUbuahcA^>nPJs3!`&Lbgz5n20xymTWrlBNPz+hBwef(;J7@B!fx1gKX`qCoWt%U>*CQ7gxV zsPl(W4O&$UX5nXh2y^^j$nmW73yb|3;V;)YW*)eC>KU9&FzWZ4D|08nT-6orVZX{! z&6D6twc23apD~s5SgY@PY$nff!c32aa))y9#b}<^iR*50njZXr#BlQtSTJq&OgD6V zFvfJpC`)xJ6BX?oNYdc*rm>_eI;gqUI(u^fMkNbUWvBAuz&6F*25Ch2<^$r4a(JDB`$wg zyP|-P=p}aWC8Yxh@Bc2E8@tywj*r330qNsdC zXHVl2bYlGr8b`)si=%3?x;d9NgePkW?&N zj@P>pP(JTo9~wvCYn+_tJHsm#2A?fAO(sc|tfe8sgHVIX5xr9kJIvm(!!}lO$D;f$ zzfN1T(h)*bN2Ucvk~V9PnawV!I|@FvwFfvEllPd0YdHW_*_B4pVD!S0Lbw62T_`qr%Z*#TCm%-=~|#z8X7K6189 zl|~;CsQNHOZnp#<_B_BaA+r_s3loVYRpp+{p|s;dV~}84dZiY)Fh7*K?}^ab zWy`|^zzosCX!fQfyWn?}f^LWkip#$U@Gk5#O3XLr{L=Vw$@Gbh_{UpQPJeHg;%7b@}`^TR(-d(=) z3lWXzEE6QAGK~5i0{s%%B_?-wLhygE?Y%)`_5SYHl;YdXjx~qp&cY21QcHQhKnhm; z9;Bh->aZE}*=&id*Qmk5U>y8>R71zNvw*H>kqS7-|5!s8@hi?j?cZg3Pm3nA1f7mM zwu!6ce9-9b?RsS(>ruv0_*M@Oi;K@X5P!gEIy`j?Rh>KuWTvEZiC>zNmnr>uI@P`# zX0(~S9wS(6Z$idqe0QZPt(J>}5@|h8`D-%>h-M7q_G%l7_OLzEA5OTqYZFp%6tln8 zp}WmTdu{O8RM(;Z&I&H6^T+P70@&L_T~jPGHN`4XidsIj9~ZRqZhu4Gd^#4a2$XWW zPaW+x<@XUFlMf#_0te_C2fqj_ID8p;wze_n#Wd92|8anzs_kQK}-UC&8a*fD+-n5nwfr)lw>uv)q!}4jYgu$|8L(8=e!;nU`jl1t^gvCO?Qc3)>W8_KTIpoytY{ef8lRl5B7P<$W z!yJrrI7)HKNpf_XFrzb6xDaPE;5ou_{Y`7uQ8&BeS^A6Rg7vO;R4XC94x{xr5V72L z;VmPfcyCVa!-aD-8@{tn3jJVNH{yj9E0b_?f(c%*&zaZuT^`*ue**lbbrHBPa2}%P z(X6x;#g0nx3TrO}d%dZ@ahEQ_LtSBuCr6LDZ+$e+B&A9rxj9Xp(r?D85vHbtP8&$H zH^_8=QAX#Gp%a6w-KizEP8o7x4R>JI7H!_ud?4lb7@3x8_~|RzYs2kQOA)p!?eiKf zHDFu$T7vI-KceRcb3Lpqbnfn#XYR>+4%$(^H7IeJ+o`!Vjd+fXed=&?=@OF$)%prA zQqH&|?6iL}3{jZ3Si?th|Guw9#PAY+M1Xf)lVa;(J4U&U2^$*Zx`H@L#bn&i}b>JfZg&Hi`)vTj|THznamSp(Zvuf7}&37XHC9Q?5Nht)p% zI$Ucse&E?_EsqO-l!(jO!p$?ys)OrmrfG2dfvYd=#)Rm&p$Jdl!#(j}@ywXp#rE+4 zby#6o9?PFI6zR?7O3XD2gA|-X@_w}^E&XP4Hrbg)5pOaD^d1_dDn?i-Uh^2;BB$Mc zdg*rxc>E8&*!^I2p4fUs)1PDj>=*EV!6WZ(Uo%q*#*1+U09{_meVTl`Kfge{2*pomFW%4m9Dgi>>FHtL^x?C9>o@pQ>UTMUcC`EFla=LJ z-*uqo+-*hJ$}c8wL?4qo z&&DhFfbX85%}YD`d}I3J12?Y8JF+Xzj^T=2;j)xF84faMA_cHixeU{HrVOY#2F z5x&8}UE8mw$gc#TN=vQkUz%9|qhQvr$Q^<8078YR=Svh`xLaAj#E^f%?d@OwC086c z2p1?o)p77;$P}`IZZZSr@wF>%!o?->;px9+$r@vaewAm7_##xH@^~q%A9XI8!V|?wS*2h8?EXF^?gm=Jub#+la?`Bm?hL;HEjnah!fSw~AVb6%Aj!R!Y5-z)_ z{9C-g4Pn@jJE=wQ#QW00=YAw3Rq9Mr%KLPa%zp%aRk>VvJj>N({SYkUx*Go*88JCF zEq4QQ)Rj%kZN(2}MZpvxT~t0pdaSroLr~B!K93z4Yzz;fn+mzPh=Zy$d?%!^-`}Vb z(fMfEr_fU#yeX<0-1sGEwjBNz)M;XH@*q@r-4}Ie6k(VcF3aXV_X$y0xyx21<|L5cmm%=1-S*UNQ_ zEnj!ZCH;#t@wt;}hMNz&ZzZ>W2Ok{tqNoImqFiFc8K`iEHzAAdQz)`Nx9_SEbIUR! zS?}C!oT0V=Y{+H6Mv9dGTb91i7a7XtK-o4;H{^%&iv*+#&${9mpz&@%m;t6V$W!VJ2n>PoXU>f!wQ zW`#wfw--LzX70%P3sSBV+`ObBIKCbfXy4<2D_k7_+dG%7n3SK}Y;Z)Z@Au?dQ3{i~-cEQ^AVXoRUNydSZYrfjC> zP7Nq()WW7#$z2#28sw2KX?b_Ub$(f>dYT zIM-1sB*!360`=|xUg`ilP&M@CHz zlqM3^=EtLuaw-+jFEBp712aXBt+CD%@J2g4bUI&^+iv-+J+KP%m?tyBjaq$h_p>bT zzq)h)y#;zjEP1JK*6Bz%OMP0)Fh!iQd|PE}-W3hvEurv5qwsR01V5z=Mv~tYV}eO9 zjpiX$ppXLT<;1jtnhQY1n=~K_?(Js^nMYbfilTz9hyidZ+PjxC=T4Tn_#J3Otd;BZ z+4qZhw9s>e++4S^FplRe4yx+>(4Lo=625d+3nUEPcEGqZp3GHGBYpHSooB?sL>;D8 z3V7BdyD6`yhZQt$hc*`}aoO$->@}VU*qoIW$JtoMZC7F2H{SOtoqnfSUo*1YM9xa~ z!Fmrp`Huu21Mw`6XNufrZ*sd04luo!vU>H@smfNj(3>2k@Pllh$N z@*s3pD42t9*Oj6&wR`&G$=dnd@Lz2(QFbYI$z(LQd2g3Q4*R>Z9^m!G5G!FWn zMvP;4wUS{&JvYE@c~%d&*m-`1<|+6RHgZ)Ml!vNQe-lCzS)*|qj|iH9YwLm;BY&y2 zm)vZ69UIhE-Dd)3xg@i+mILC#DiF?dc2%tzkzWYd1jz>@{)I-0+{dnwRv%d5yE0Zp z0GuEIJSdH$c!fh1tJAUgl#>mZbZr@_CvjC*!+&b%5# z>63Knv(ILo1Sw>tpQTTvL%rTz+@>w6d2v)Uy6BrEkgmJtR(i=f>GqxRt!Y}KNK&pmDQ+)W#2QFf3A$ zql88tL7KJEwYeqi52Sx?h^hAZU6t0Z0N#tA0oD~q$*-D~4f>qm-#?$vxV*m7M8l^I zyItOIx6Ku>;CSqGM%bwj5`1CqmZq53WoSpNgxlxQ*3eP*mz>LI0^8(I>8eeLa&7UEL!vmSVpqrG1huHdMuSWtfD`i~t+{G?@~^#Lgdg zSmvduBBcX^_YQ)&1Q(zSCV17mKS^vT%2&BV0U@Hi_^G>uwmbu?If!Lr4Dry#Gci&u zq?aEbZCvKKmtWnZ+v%Z`kH2N-v~_KG5GN}{3ibkUM*Zkla>(KRhJuY3zN}*%?SOzv z(Is$HSw+$v8ie9-v4e_5_Kx71+j+pw;cA=OdIu4}ITlUrKHqW^@09iq;MkSh(BOyoM?2AYP ztUi4gY8<#cFsRbQoh!SBjpL3zT2foF=2@^M0iA)8RBN9sw92sMBfIsu*eFG$&pp8- zRDr|HlG*u_=Z$B;Zh{H z>v`}x|4BdBeB4h{<|t;rA;EEGvg=oP+|hS$2>kwP7jVIwg=r1LA+GoqD=s>u!oalU z4jxcU&JwUN6E0AoxcfEu26DT`$4lsl@bA8o6{3R;gSw^3ED5#MSMlG+NK*V1%Ov#x&c9Oah;z1%jeHwz1B61 zCqstIdPt@QCo3)~TcZthL%Dt;;c5k$$YK8TZ;U7B+A2z>V-3zV*xpKyJx`A#{it_#|b$`@qJ~kiFO;wnyNNe!6;@tbE zxqB91ll3fW20}|%G0osVt{b`ZS&q|z8OV#ly}PJi(`yo3*=;H5r36O- zP`_Yeoa(Y!uLCE(V<%4MC$l74uv&{PbY^L!whEAgD*>l08kug5>g(PtSYv;7 zjsTYyCSM~FD1A$bk`iYct3dv$s%mpBas(PV)M5ji%y1OgXSrf>!PXUflMP#Y*;4cu zFc&=#-=Jibc>#djS5z)_Li{KotiK$0BP8kWy0nGe??GlIY@ch8=K8QP;&zRXZYz6ArGORguW(Ug{$CUS{w*#2r>T`zFsKoCMV&wOt~=cE5` z1N&uPiysOmzTA^X%+p~co)8P_*C?@O5^*^}oasZ* z*3$RHB9^P?Ybu?ccTBH*h%68WOwS$Jz{n$QWWvB%<(~>2E!qxG)mAS?fK)mF5br*^ z4(hJEajza|_~-?Mqonh>#*kgG_sdTVPEKc=dpMR5PRpJ@`t?CL#ux+IXY3EuS?W9k z*7rU{3@pY0h^>2gL7icI`Einh6YdUyqc}w046-(ndG*KKGZVpF`&P>?BbDbjf$>CS zej%Tl{W`5kocr{p3rkG#M)^!NmR$t2M z=@Q?T>y>`?CT_hjuQy-p&*JY)>d(t!A4}(YnIQ+J24po_;-mm@)U|w6>wj;HKT8n{ z;R!XA%;V5$xIp|{0|i0A_N&$eN%ajKM;0~q9Rr-VQa|ag?FtmO`!d&%Ba{hBfV1R3 z$hOH`DU%;P;Z$QFTN1QPNA64=Qq7HB0Zzc*51Ju06xYeWg6`{=Pu`3Yz{fDK^BL%D zqydNI5&JpjGMJ4AT#V<4FLZ({f}1!55;ls&1@7HHUZYYe&!`?5YM(0}otZpHikG-A z>@Kl+L{;y>@vMUHZkPIG_qk902NZO?;GQ-Rzv*A5KDh)z+t3g>7r=Pc;D2iC;m|*$ zt*Z5ov%(G|Q^0!#Tf!~LSCLY#_sa36Lq8cM_M5>wQEevaf8af7P1RfOw@YpJ-)MS) z+MnSzKNHIRyB4)#ouN;GgcN6(6rc%t5UO*F7{x8;qPlkmcIe9UraxUPvs!SUZ}jLQ z>>8xi&i_eHIzu{LTIpC43{24k-?Zg!^JN8Iunn1G&95TwnW00#z-u*t-%4buZ^L={ z3y4ei73$w2H}Bqf!Q@?zR)|P0;gjV1l%}pyBX55&_xHE|0pa}PJRGHoLFV`zI;6o+ z5YC1SH3$ALSeDiq3JhbO>5vh3(NjE2pW4$bm%}*!e18L`!oYSR6(zvl&pL$6tDC(b z03Cn+RR#Q4NPs)~@37wfo?I2^A&OYj4-EFBvTgRQX z0dF!a4Ll=S1|soOTXT0&q%k_e8W+cwc4~$=szesUZQJY`9H1V3}nzq*exO zvRwr(0UkxZHQ5p~(DoScB&tHrd18=k^`@ehZMtAo5%av`29QXMCy64j*geg4vP+8F z8!7FC_UU~zH&AvXJlo!GcDF{@-CwEPD&Mbj?4xgTQl?j;ItU=Iz+5sm%l8(tcPJ@q zzNa{%jlec6<(8B#^wR6DE<_hV)^aXN&UX)43#l_70qk#>F;ol8mfe$-I_#J17)Q$5 z`a(>a;ZoyyPjA%I1{lsdMKXw9KpqA0+`y33Z zy%NV(c`wjf{2XYq_XS1yZKa z2d89c*ZeVn3&PFvGQiV9i9#G5_C}O~aguUW0V#1g&GC2uDLz!Pf#7wk7W3Ujw062P zBRcehS}W_*)RV8@4A>U?qNDb6b}qyfZTb6%bvoL_z=l?4*B3G&7t^;d?+)_X7YBpX zorU;i5O|1?0iyXmKN9^_S<9UAl@2Tz`VWxo=ltUsJs|5xz<3J*k16NC>h32>HTHn4;jacR`wvEu z)9c8SGVC=zxT29KiEOh$eB7)uSxG*aP=@j%{7xzLEi|BHxEL~qR4~}ok~&mp62)#O z1e!9LFwl@SYzhinyV9|1>DQ0ug-P)=@I!wH98d87`6RLC_fb5VC~hIB5_^0pldoH- zx+^sgy>ywY*X(*^hM8p#yg44eYe_Zhg1i**wSW2HiB6moxjHg1T# zxm+w1TJB(J(R=au6PN7-aqbU|LfE=ika~&ldzYr0h5i<^?E5>$(L@k($G1*NnwJa`7XX{;C;3fFRbDuG%uNDosC(uCsA(pJ#;xGqlz~R=lenRO;2fX8 zw|smC_=p#3NS9-A=Q^|Z_>!$vS&M^UDVC0s2R==P1UJiGdO^if;7H3ho2y6QJt2+V z&15itvY?esG74_}uH+QOo-&QMG&y+%T0l1_0IL)DZF3;P%yc1QV4iNtxtT6}dgCjxo z$a4`GWUbxt+WE9$#1d)cTxu(| zZRk$+vpgYUC%p}9?og6>Y1xS#7hT&z8oHwg@{ai6Crx}(d)-d6E=0LbKD2j^8b+O} zb>PdDa2@V&TAJNQjM#?H{-|zL5bUMPECx1nN&iN0fA!mTenQSvm z0{(+b;`;rAWeW37K7D8Aj9}Qj&0)v1^3ZLcjk1pbv+~#!0E1^sB)`Mj6V4`WKhjJ6 zT<87Ui6Spp(}nedQ83QcKNiG(@ZHa!S*PuH25t7cy#Co{k35?XX3hcxg2OSP){ft% zQNucW$qM{N3)!*Edg5j9NSc>ECgKnrNIdAQr zAwtWI1?5^28%KJr1gBWkc~K&ayZFWnf8U>dNy@0>-@7t}NZJYWn+31II5yHmigIi6%SBjY zz^3Q^7gRGqQQL?i_+HM0m(v>8$Bx3i80PHRGJt;$-Vcey{-|LnPX9B zaN=Hv>D*gY89gzM$gNqu!*ZL07DdX^1ebgGb{jgaZcBY~`d;V!#G;tV5W0H(!(}2k zDj@_0x9ig>>o|)RbafUwShMOybMHKwJPGxV zwE#xI-J%0h?hcLS{a9V4aCx;u%dyRKo8O$2DqUXFy~lOK&e=z?Z+alfUWE^+$qnNj zRKt5zPhnx7V^)}6r#W!v1JIoVuASx&abCo1-9c`-+4;2AyoKJM^CLOaQ8_MqZ^Ve= zjEm~&;_5P$g5{c#%43Q|qU$ZCiF!8#iTy)tO7(q_wl(c!U@L2Q@;TYy4`y7vI+a7+oXpASerZ z?f0Ne8WT7OA;mXDc=}jcW{z=Mny)#W*_|}!8)vEG$hg>n(-_P@4ymOve<2Z;1N?1 zjVX)*&d{@c}C zNybD<(mG$wy-^^Z2PB^3sli@I3%p-jKXM%;8nubww1r0r45^Z^!=@jBGR&JRy(e3b z1yaI&St(vMXWZjF81lGXCK#h3s{+h3<(B{I_sJ_lL`cQS6(kz~vgd4YSxNDn>A|?Y zN>i_#>-9|(-CkSnzh?=|T)}Q2>3zsc-HRpr*U$Y`rG~(|&~nZvR+VON8;(Mqw0XhE zNpD|+R6nV2vy1wbX0&RAIq}TDcHxg>KDK^g{@!c0A0m|o-}3ZPlK}$`6{jfdquXt5yJ&xqCCfuRGm{(|% zy{m>PD8GK2P%kCd^V_$<;MQ-cENZGNCar_rN7)yt)_AUW)J;$R7UZ5)zJ?ml+){%K zd9VD(gb5e55c+I$^LlcY5Gk8pZDD>5M5IYo1PsKk8lj69Aq<9<;#VFBFDeobi-Z*iTRb`Grwv=lN8fF!x;x!DH|02_{&P75 z_*4~5&#=x{aEZSpwHFDX)7gIr8n0`RZ?b1!>M(w%DgR*Jo{OZu5auPCtdxg@cB8qW zo#W+vEA;y8xlnW9K5u*XpIl8AfBMt4Wb=kk6%0$zME8w-Y`^?4iTL=vz}~`{g1 z09WB}1;r$q`D?43-c&b^5lJ<34(1zv>CPhDY~HSiQw-a5WiOvcIUf51#Kh;1=F6A# z;$FyJ0&@48p1gqzwwRw=hQl?hv?voa82Z!DJuOX{`qF$kF)7zK_XAD2GG@nXxq}me zY3miR_kZutCxDh&|Ky$id?|`Hx3r;!fA6=G2R=~&tb={@%_0#n$x@d;#QXeika~!A z32x_&6u6}~$wSIYH0tX2(E_k$(NhA)-nTWr?n6azdu^yd_6^ighPePbBB`)`ZR8Jv z>J)>Z?(e4s0#1!E)$0Z}qJJ47po$DCf;N53(6E&r5Nkp)#G3M7{>?yhjTS{RcaCx) z8`CFV1Ic^`G<8Ae1bEwh(5du`G2-;{%`vab3j^6`j%$&}*J@DDmZx+4&<+gmQa)+Z zg0#Y_mQLU~H$B4fo94C;R~mD~3suS_efTGqi74Dz;I$wI3Y6k~&DCJjo*ZDQBd$~? zcN*VOTKSah?v?;FnSi=pAsKgnTeVnHMr(AV#?o>Kf;<|)A0A;IYoT%Ysvf>#)mJHC z334Qle|ni~f&*oIq>%w1g9M^POES%AHXq6!L%|---g^pk!}Aa9&)+Ed^AlOfJ2j;! z53OMAG=J;M?w)6|D}czJvT|rvui>t5cEeTC>YwF;X5IOKSng?QvHsEWKO(-4=M4Q3 z0(c_OpzpA|59hs7i}Jp7<-2nTBO^RwgAzNe>86L2a}W0S18m;CX-3nIrZb-XRKUDI zA|BTD$rP`YS<2=aEjM96yOe$r^r(&ySLAGp)9#jMGu4vJLkkC9f?0dk?%jk2S&ybL z*vCkE^PKgcbKY^CR{OveJM+G`C#Qd|ZB_4_m|c`|X#`&ApK;d+`ee2P4Pd?gI|Pz1 zxvtg~x3DJ`D03&ij0H^IS8~l))O&UNmDfV%_MTbJ09V<22AQe_4Bu8}$KZ(k3Z&j5 z%qunA_C(!~`954tVAXTJ5RIO2zxx7C!w+xh? zeXes5O$sZIce7MwoqOq`8sBv^dv6+PTAGN=udvHP-;MFN=Vs^Bi2rdQu-0s1`Kli|PEw_fx{B+~Qdc;id=6$!gyvxI=C|IpJ zgLWd5@6}qDS9&9u94aZDNEgW|LN(+KBu`Rr{w4V1I}XGgkBNhvRWLM1Qm$D{uDf_| zpzHY<=DNkQ$`q$6uG2jtSonIGeSWF!;M|u_gQU>4_{H0p*b+)x&(E!nLA}74x3dOd zLfSVuB&ClqL!FMiHCjE(tr;$hDkP)`t(Q4xz)zaufA~IqSPJh4&20;Zz>0II-Kajb zXDxzfR)?9QTwNuPmiJHGcy?LO_^B#!i$1_smAVCIo{G<-JPzZXC{>xLv}-V2j@!_# zw{ui%u=U+E=Ov6eY|9}BDD8w-)aI28A*-5sOit7rg7K7Wo16Ee)Wq#spft+ldliZ{ zYL!_7F6<`^Nlr=pfpFrhC>n(BTK=coGWHLe`gJWg`@;N>T}O|3DfiEh&9pv5>cN*%ef zK3F4k+%%{ih?tty_0`ZG*%7_MutOqdmXmtj;s42 z`P`N2#Z1&pe=uKIYxX)j;BQ^_qkEAlY%E#;vR_HXZKvq%)3}IDh;$ zAiz$N+_my)Fpn+C=A$KB08*+Sdrl2kVbqrVDrkE#?&Z3bVzyh6Tz|jOWENuZJQj7# zF6%D^(J+RWV`uKF_<#%@k~|3EHc)QAN*WD}%P6+B{&!XW4{o()~Z& zN@lHc5-*?u)gasj7fL|Veftd^N2 zx~PQLSBDb~#LVk-knYLOcClXRKQ*?!dL?HW5wNR6hHyR_AjUX4v1f+VnbTVU~b z17E3RVtil{A1-h<8{~Iexdf7Eu6DW(IcyKyC-w$b!s4pGl4LO?M|6<;RNzd(sZ-j# z6Gn0qOVn=*Why;k+UxtHn9FnUzQ_r;`Ljt~?Y*W`a4f=MI;SNYuL7@hSy3s`>yCe8 z1bZI5_AuP(D`&_{=gn9$0KdWPY9OvzyLoU&OPv8AGu(G=A&4DM%eD?~4Jd4`cTT$4 zGq865(!W#O&07P7phTA$;K-R!v2&_mra(EzcU3=4EXV3}3G#vYdqb5&vNW~1`K1>Sus^OVQ`sNT32%Jbk1R#azs+50- z^bU{xWM*(@nDAHc4qt%yPX0spOothh!Tqi7Zv+uL!2e@Hg*9@`wKM+f^^(Y63cV71 u;H+aJd|*5>7du!J@W}sDELs2*a78W^9{GKjiVXs~oW}3E*YmDg2mT+jC90eN diff --git a/src/Client.php b/src/Client.php index 3aab1dd..a522441 100644 --- a/src/Client.php +++ b/src/Client.php @@ -1,48 +1,45 @@ cuis[] = [ - "cui" => $cui, + // Add cif to list + $this->cifs[] = [ + "cui" => $cif, "data" => $date ]; } @@ -51,131 +48,30 @@ public function addCui($fiscals, $date = null) } /** - * Get results of request - * @return array + * @return Company[] * @throws Exceptions\LimitExceeded * @throws Exceptions\RequestFailed * @throws Exceptions\ResponseFailed */ - public function getResults() + public function get(): array { - $results = $this->callApi(); - foreach($results as $company) { - $company->adresa = $this->parseAddress($company->adresa); + $companies = []; + $results = Http::call($this->cifs); + foreach ($results as $result) { + $companies[] = new Company(new Parser($result)); } - - return $results; + return $companies; } /** - * Get first result - * @return mixed + * @return Company * @throws Exceptions\LimitExceeded * @throws Exceptions\RequestFailed * @throws Exceptions\ResponseFailed */ - public function getOneResult() - { - $company = $this->callApi()[0]; - $company->adresa = $this->parseAddress($company->adresa); - - return $company; - } - - /** - * Call ANAF API - * @return mixed - * @throws Exceptions\LimitExceeded - * @throws Exceptions\RequestFailed - * @throws Exceptions\ResponseFailed - */ - private function callApi() - { - // Limit maxim numbers of cuis - if(count($this->cuis) >= self::ANAF_CUI_LIMIT) { - throw new Exceptions\LimitExceeded('Poti verifica simultam pana la 500 de CUI-uri.'); - } - - // Make request - $curl = curl_init(); - curl_setopt_array($curl, array( - CURLOPT_URL => self::apiURL, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TIMEOUT => 10, - CURLOPT_CUSTOMREQUEST => "POST", - CURLOPT_POSTFIELDS => json_encode($this->cuis), - CURLOPT_HTTPHEADER => array( - "Cache-Control: no-cache", - "Content-Type: application/json" - ) - )); - - $response = curl_exec($curl); - $info = curl_getinfo($curl); - curl_close($curl); - - // Check http code - if (!isset($info['http_code']) || $info['http_code'] !== 200) { - throw new Exceptions\ResponseFailed("Response status: {$info['http_code']} | Response body: {$response}"); - } - - // Get items - $items = json_decode($response); - - // Check if have json because ANAF return errors in plain text - if(json_last_error() !== JSON_ERROR_NONE) { - throw new Exceptions\ResponseFailed("Json parse error | Response body: {$response}"); - } - - // Check success stats - if ("SUCCESS" !== $items->message || 200 !== $items->cod) { - throw new Exceptions\RequestFailed("Response message: {$items->message} | Response body: {$response}"); - } - - return $items->found; - } - - /** - * Parse company address - * @param $raw - * @return stdClass - */ - private function parseAddress($raw) + public function first(): Company { - // Check if raw is empty - if(empty($raw)) { - return $raw; - } - - // Normal case from all uppercase - $rawText = mb_convert_case($raw, MB_CASE_TITLE, 'UTF-8'); - - // Parse address - $list = array_map('trim', explode(",", $rawText, 5)); - list($judet, $localitate, $strada, $numar, $altele) = array_pad($list, 5, ''); - - // Parse county - $judet = trim(str_replace('Jud.', '', $judet)); - - // Parse city - $localitate = trim(str_replace(['Mun.', 'Orş.'], ['', 'Oraş'], $localitate)); - - // Parse street - $strada = trim(str_replace('Str.', '', $strada)); - - // Parse number - $numar = trim(str_replace('Nr.', '', $numar)); - - // New object for address - $address = new stdClass; - - $address->raw = $raw; - $address->judet = $judet; - $address->localitate = $localitate; - $address->strada = $strada; - $address->numar = $numar; - $address->altele = $altele; - - return $address; + $results = Http::call($this->cifs); + return new Company(new Parser($results[0])); } } diff --git a/src/Http.php b/src/Http.php new file mode 100644 index 0000000..ed5a340 --- /dev/null +++ b/src/Http.php @@ -0,0 +1,65 @@ += self::CIF_LIMIT) { + throw new Exceptions\LimitExceeded('You can check one time up to 500 cifs.'); + } + + // Make request + $curl = curl_init(); + curl_setopt_array($curl, array( + CURLOPT_URL => self::apiURL, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_TIMEOUT => 10, + CURLOPT_CUSTOMREQUEST => "POST", + CURLOPT_POSTFIELDS => json_encode($cifs), + CURLOPT_HTTPHEADER => array( + "Cache-Control: no-cache", + "Content-Type: application/json" + ) + )); + + $response = curl_exec($curl); + $info = curl_getinfo($curl); + curl_close($curl); + + // Check http code + if (!isset($info['http_code']) || $info['http_code'] !== 200) { + throw new Exceptions\ResponseFailed("Response status: {$info['http_code']} | Response body: {$response}"); + } + + // Get items + $responseData = json_decode($response, true); + + // Check if have json because ANAF return errors in plain text + if(json_last_error() !== JSON_ERROR_NONE) { + throw new Exceptions\ResponseFailed("Json parse error | Response body: {$response}"); + } + + // Check success stats + if ("SUCCESS" !== $responseData['message'] || 200 !== $responseData['cod']) { + throw new Exceptions\RequestFailed("Response message: {$responseData['message']} | Response body: {$response}"); + } + + return $responseData['found']; + } + +} diff --git a/src/Models/Company.php b/src/Models/Company.php new file mode 100644 index 0000000..3344f63 --- /dev/null +++ b/src/Models/Company.php @@ -0,0 +1,111 @@ +parser = $parser; + } + + /** + * @return string + */ + public function getCIF(): string + { + return $this->parser->getData()['cui']; + } + + /** + * @return string + */ + public function getRegCom(): string + { + return $this->parser->getData()['nrRegCom']; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->parser->getData()['denumire']; + } + + /** + * @return string + */ + public function getPhone(): string + { + return $this->parser->getData()['telefon']; + } + + /** + * @return string + */ + public function getFullAddress(): string + { + return $this->parser->getData()['adresa']; + } + + /** + * @return bool + */ + public function isActive(): bool + { + if (!is_bool($this->parser->getData()['statusInactivi'])) { + return false; + } + + return !$this->parser->getData()['statusInactivi']; + } + + /** + * @return string + */ + public function getInactivationDate(): string + { + return $this->parser->getData()['dataInactivare']; + } + + /** + * @return string + */ + public function getReactivationDate(): string + { + return $this->parser->getData()['dataReactivare']; + } + + /** + * @return string + */ + public function getDeletionDate(): string + { + return $this->parser->getData()['dataRadiere']; + } + + /** + * @return CompanyTVA + */ + public function getTVA(): CompanyTVA + { + return new CompanyTVA($this->parser); + } + + /** + * @return CompanyAddress + */ + public function getAddress(): CompanyAddress + { + return new CompanyAddress($this->parser); + } +} diff --git a/src/Models/CompanyAddress.php b/src/Models/CompanyAddress.php new file mode 100644 index 0000000..b612ba4 --- /dev/null +++ b/src/Models/CompanyAddress.php @@ -0,0 +1,59 @@ +parser = $parser; + } + + /** + * @return string + */ + public function getCounty(): string + { + return $this->parser->getAddress()['county']; + } + + /** + * @return string + */ + public function getCity(): string + { + return $this->parser->getAddress()['city']; + } + + /** + * @return string + */ + public function getStreet(): string + { + return $this->parser->getAddress()['street']; + } + + /** + * @return string + */ + public function getStreetNumber(): string + { + return $this->parser->getAddress()['streetNumber']; + } + + /** + * @return string + */ + public function getOthers(): string + { + return $this->parser->getAddress()['others']; + } +} diff --git a/src/Models/CompanyTVA.php b/src/Models/CompanyTVA.php new file mode 100644 index 0000000..d0125aa --- /dev/null +++ b/src/Models/CompanyTVA.php @@ -0,0 +1,99 @@ +parser = $parser; + } + + /** + * @return bool + */ + public function hasTVA(): bool + { + return $this->parser->getData()['scpTVA']; + } + + /** + * @return string + */ + public function getTVAEnrollDate(): string + { + return $this->parser->getData()['data_inceput_ScpTVA']; + } + + /** + * @return string + */ + public function getTVAEndDate(): string + { + return $this->parser->getData()['data_sfarsit_ScpTVA']; + } + + /** + * @return bool + */ + public function hasTVACollection(): bool + { + return $this->parser->getData()['statusTvaIncasare']; + } + + /** + * @return string + */ + public function getTVACollectionEnrollDate(): string + { + return $this->parser->getData()['dataInceputTvaInc']; + } + + /** + * @return string + */ + public function getTVACollectionEndDate(): string + { + return $this->parser->getData()['dataSfarsitTvaInc']; + } + + /** + * @return bool + */ + public function hasTVASplit(): bool + { + return $this->parser->getData()['statusSplitTVA']; + } + + /** + * @return string + */ + public function getTVASplitEnrollDate(): string + { + return $this->parser->getData()['dataInceputSplitTVA']; + } + + /** + * @return string + */ + public function getTVASplitEndDate(): string + { + return $this->parser->getData()['dataAnulareSplitTVA']; + } + + /** + * @return string + */ + public function getTVASplitIBAN(): string + { + return $this->parser->getData()['iban']; + } +} diff --git a/src/Parser.php b/src/Parser.php new file mode 100644 index 0000000..ebba597 --- /dev/null +++ b/src/Parser.php @@ -0,0 +1,66 @@ +data = $data; + } + + /** + * @return array + */ + public function getAddress(): array + { + $address = []; + + // Normal case from all uppercase + $rawText = mb_convert_case($this->data['adresa'], MB_CASE_TITLE, 'UTF-8'); + + // Parse address + $list = array_map('trim', explode(",", $rawText, 5)); + list($county, $city, $street, $number, $other) = array_pad($list, 5, ''); + + // Parse county + $address['county'] = trim(str_replace('Jud.', '', $county)); + + // Parse city + $address['city'] = trim(str_replace(['Mun.', 'Orş.'], ['', 'Oraş'], $city)); + + // Parse street + $address['street'] = trim(str_replace('Str.', '', $street)); + + // Parse street number + $address['streetNumber'] = trim(str_replace('Nr.', '', $number)); + + // Parse others + $address['others'] = trim($other); + + return $address; + } + + /** + * @return false|string + */ + public function getRegisterDate() + { + $rawDate = trim(str_replace('INREGISTRAT din data ', '', $this->data['stare_inregistrare'])); + return date("Y-m-d", strtotime($rawDate)); + } + + /** + * @return array + */ + public function getData(): array + { + return $this->data; + } +} \ No newline at end of file diff --git a/tests/Integrations/FlowTest.php b/tests/Integrations/FlowTest.php new file mode 100644 index 0000000..b2dcd56 --- /dev/null +++ b/tests/Integrations/FlowTest.php @@ -0,0 +1,51 @@ +addCif("RO16826034"); + $anaf->addCif("RO14399840"); + $results = $anaf->get(); + + $this->assertEquals("DANTE INTERNATIONAL SA", $results[1]->getName()); + } + + public function testCUIList() + { + $anaf = new Client(); + $anaf->addCif([ + "RO16826034", + "RO14399840" + ]); + $results = $anaf->get(); + + $this->assertEquals("DANTE INTERNATIONAL SA", $results[1]->getName()); + } + + public function testOneCUI() + { + $anaf = new Client(); + $anaf->addCif("RO14399840"); + $results = $anaf->first(); + + $this->assertEquals("DANTE INTERNATIONAL SA", $results->getName()); + } + + public function testAddressParser() + { + $anaf = new Client(); + $anaf->addCif("RO14399840"); + $results = $anaf->first(); + + $this->assertEquals("Ilfov", $results->getAddress()->getCounty()); + $this->assertEquals("Oraş Voluntari", $results->getAddress()->getCity()); + $this->assertEquals("Şos. Bucureşti Nord", $results->getAddress()->getStreet()); + $this->assertEquals("15-23", $results->getAddress()->getStreetNumber()); + } +} diff --git a/tests/Test.php b/tests/Test.php deleted file mode 100644 index 0bbe739..0000000 --- a/tests/Test.php +++ /dev/null @@ -1,50 +0,0 @@ -getInstance(); - $anaf->addCui("RO16826034"); - $anaf->addCui("RO14399840"); - $results = $anaf->getResults(); - - $this->assertEquals("DANTE INTERNATIONAL SA", $results[1]->denumire); - } - - public function testCUIList() - { - $anaf = $this->getInstance(); - $anaf->addCui([ - "RO16826034", - "RO14399840" - ]); - $results = $anaf->getResults(); - - $this->assertEquals("DANTE INTERNATIONAL SA", $results[1]->denumire); - } - - public function testOneCUI() - { - $anaf = $this->getInstance(); - $anaf->addCui("RO14399840"); - $results = $anaf->getOneResult(); - - $this->assertEquals("DANTE INTERNATIONAL SA", $results->denumire); - } - - public function testAddressParser() - { - $anaf = $this->getInstance(); - $anaf->addCui("RO14399840"); - $results = $anaf->getOneResult(); - - $this->assertEquals("Ilfov", $results->adresa->judet); - $this->assertEquals("Oraş Voluntari", $results->adresa->localitate); - $this->assertEquals("Şos. Bucureşti Nord", $results->adresa->strada); - $this->assertEquals("15-23", $results->adresa->numar); - } -} diff --git a/tests/TestCase.php b/tests/TestCase.php deleted file mode 100644 index b3b748b..0000000 --- a/tests/TestCase.php +++ /dev/null @@ -1,17 +0,0 @@ -expectException(Exceptions\LimitExceeded::class); + $this->expectExceptionMessage("You can check one time up to 500 cifs."); + + Http::call(array_fill(0, 501, '123456')); + } +} diff --git a/tests/Unit/Models/CompanyTest.php b/tests/Unit/Models/CompanyTest.php new file mode 100644 index 0000000..b2b2cd4 --- /dev/null +++ b/tests/Unit/Models/CompanyTest.php @@ -0,0 +1,50 @@ +getMockBuilder(Parser::class) + ->disableOriginalConstructor() + ->getMock(); + + $parset->expects($this->any()) + ->method('getRegisterDate') + ->will($this->returnValue('2011-12-09')); + + $address = [ + 'county' => 'Municipiul Bucureşti', + 'city' => 'Sector 1', + 'street' => 'Şos. Bucureşti-Ploieşti', + 'streetNumber' => '172-176' + ]; + + $parset->expects($this->any()) + ->method('getAddress') + ->will($this->returnValue($address)); + + $parset->expects($this->any()) + ->method('getData') + ->will($this->returnValue([ + 'cui' => 123456, + 'denumire' => 'Test', + 'telefon' => 07676000000, + ])); + + $company = new Company($parset); + $this->assertEquals(123456, $company->getCIF()); + $this->assertEquals("Test", $company->getName()); + $this->assertEquals(07676000000, $company->getPhone()); + $this->assertEquals("Municipiul Bucureşti", $company->getAddress()->getCounty()); + $this->assertEquals("Sector 1", $company->getAddress()->getCity()); + $this->assertEquals("Şos. Bucureşti-Ploieşti", $company->getAddress()->getStreet()); + $this->assertEquals("172-176", $company->getAddress()->getStreetNumber()); + } +} diff --git a/tests/Unit/ParserTest.php b/tests/Unit/ParserTest.php new file mode 100644 index 0000000..7ea6e8f --- /dev/null +++ b/tests/Unit/ParserTest.php @@ -0,0 +1,29 @@ + 'MUNICIPIUL BUCUREŞTI, SECTOR 1, ŞOS. BUCUREŞTI-PLOIEŞTI, NR.172-176' + ]); + + $this->assertEquals("Municipiul Bucureşti", $parser->getAddress()['county']); + $this->assertEquals("Sector 1", $parser->getAddress()['city']); + $this->assertEquals("Şos. Bucureşti-Ploieşti", $parser->getAddress()['street']); + $this->assertEquals("172-176", $parser->getAddress()['streetNumber']); + } + + public function testRegisterDateParser() + { + $parser = new Parser([ + 'stare_inregistrare' => 'INREGISTRAT din data 09.12.2011' + ]); + + $this->assertEquals("2011-12-09", $parser->getRegisterDate()); + } +}