From bfd33ce3af295fc37114f1aa275bcd9949264757 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Mon, 19 Aug 2024 18:11:01 +0200 Subject: [PATCH 1/2] Remove depreacted Log hook --- .../architecture/architecture-overview.md | 6 +- docs/docs/architecture/hooks.md | 3 +- docs/docs/common/logging.md | 33 ----- ...setting-up-a-simple-application.feature.ts | 6 +- packages/core/src/common/utils/index.ts | 1 - .../core/src/common/utils/log.hook.spec.ts | 123 ------------------ packages/core/src/common/utils/log.hook.ts | 60 --------- packages/core/src/index.ts | 2 - 8 files changed, 9 insertions(+), 225 deletions(-) delete mode 100644 packages/core/src/common/utils/log.hook.spec.ts delete mode 100644 packages/core/src/common/utils/log.hook.ts diff --git a/docs/docs/architecture/architecture-overview.md b/docs/docs/architecture/architecture-overview.md index 11a2b5fb9b..6d395d3511 100644 --- a/docs/docs/architecture/architecture-overview.md +++ b/docs/docs/architecture/architecture-overview.md @@ -76,7 +76,7 @@ Controllers may have sub-controllers. Hooks can be attached to the controllers o Here's an example of what a FoalTS application may look like. ```typescript -import { Context, controller, Get, HttpResponseNotFound, HttpResponseOK, Log } from '@foal/core'; +import { Context, controller, Get, Hook, HttpResponseNotFound, HttpResponseOK } from '@foal/core'; import { JWTRequired } from '@foal/jwt'; @JWTRequired() @@ -105,7 +105,9 @@ class ApiController { } } -@Log('Receiving a request...') +@Hook(() => { + console.log('Receiving a request...') +}) class AppController { subControllers = [ controller('/api', ApiController) diff --git a/docs/docs/architecture/hooks.md b/docs/docs/architecture/hooks.md index ee868b7d9a..5bea7760a8 100644 --- a/docs/docs/architecture/hooks.md +++ b/docs/docs/architecture/hooks.md @@ -23,7 +23,6 @@ They improve code readability and make unit testing easier. Foal provides a number of hooks to handle the most common scenarios. - `ValidateBody`, `ValidateHeader`, `ValidatePathParam`, `ValidateCookie` and `ValidateQueryParam` validate the format of the incoming HTTP requests (see [Validation](../common/validation-and-sanitization.md)). -- `Log` displays information on the request (see [Logging](../common/logging.md)). - `JWTRequired`, `JWTOptional`, `UseSessions` authenticate the user by filling the `ctx.user` property. - `PermissionRequired` restricts the route access to certain users. @@ -73,7 +72,7 @@ If the user makes a POST request to `/products` whereas she/he is not authentica > If you need to apply a hook globally, you just have to make it decorate the root controller: `AppController`. > > ```typescript -> @Log('Request body:', { body: true }) +> @UseSessions() > export class AppController { > // ... > } diff --git a/docs/docs/common/logging.md b/docs/docs/common/logging.md index 8bbb66ebc2..bb2a61d6a1 100644 --- a/docs/docs/common/logging.md +++ b/docs/docs/common/logging.md @@ -274,36 +274,3 @@ logger.addTransport((level: 'debug'|'warn'|'info'|'error', log: string) => { // Do something }) ``` - -## Logging Hook (deprecated) - -> This hook is deprecated and will be removed in a next release. Use the `Logger` service in a custom hook instead. - -FoalTS provides a convenient hook for logging debug messages: `Log(message: string, options: LogOptions = {})`. - -```typescript -interface LogOptions { - body?: boolean; - params?: boolean; - headers?: string[]|boolean; - query?: boolean; -} -``` - -*Example:* -```typescript -import { Get, HttpResponseOK, Log } from '@foal/core'; - -@Log('AppController', { - body: true, - headers: [ 'X-CSRF-Token' ], - params: true, - query: true -}) -export class AppController { - @Get() - index() { - return new HttpResponseOK(); - } -} -``` diff --git a/packages/acceptance-tests/src/docs/architecture/architecture-overview/setting-up-a-simple-application.feature.ts b/packages/acceptance-tests/src/docs/architecture/architecture-overview/setting-up-a-simple-application.feature.ts index 58ab23456f..2bce691a82 100644 --- a/packages/acceptance-tests/src/docs/architecture/architecture-overview/setting-up-a-simple-application.feature.ts +++ b/packages/acceptance-tests/src/docs/architecture/architecture-overview/setting-up-a-simple-application.feature.ts @@ -9,9 +9,9 @@ import { controller, createApp, Get, + // Hook, HttpResponseNotFound, HttpResponseOK, - // Log, } from '@foal/core'; import { getSecretOrPrivateKey, JWTRequired } from '@foal/jwt'; @@ -58,7 +58,9 @@ describe('Feature: Setting up a simple application', () => { } // Commented in this test to avoid noise in the terminal. - // @Log('Receiving a request...') + // @Hook(() => { + // console.log('Receiving a request...') + // }) class AppController { subControllers = [ controller('/api', ApiController) diff --git a/packages/core/src/common/utils/index.ts b/packages/core/src/common/utils/index.ts index 57c5dcd9f9..8c5c1a7dc2 100644 --- a/packages/core/src/common/utils/index.ts +++ b/packages/core/src/common/utils/index.ts @@ -1,5 +1,4 @@ export { controller } from './controller.util'; export { displayServerURL } from './display-server-url.util'; export { isInFile } from './is-in-file.util'; -export { Log, LogOptions } from './log.hook'; export { streamToBuffer } from './stream-to-buffer'; diff --git a/packages/core/src/common/utils/log.hook.spec.ts b/packages/core/src/common/utils/log.hook.spec.ts deleted file mode 100644 index b428de27ab..0000000000 --- a/packages/core/src/common/utils/log.hook.spec.ts +++ /dev/null @@ -1,123 +0,0 @@ -// std -import { strictEqual } from 'assert'; -import { mock } from 'node:test'; - -// FoalTS -import { Context, getHookFunction, ServiceManager, Logger } from '../../core'; -import { Log } from './log.hook'; - -describe('Log', () => { - - let logFn: (message?: any, ...optionalParams: any[]) => void; - let msgs: any[]; - - beforeEach(() => { - msgs = []; - logFn = (...args) => msgs.push(args); - }); - - afterEach(() => { - mock.reset(); - }) - - it('should log a deprecation message.', () => { - const hook = getHookFunction(Log('foo', { logFn })); - - const ctx = new Context({}); - const services = new ServiceManager(); - - const logger = services.get(Logger); - const loggerMock = mock.method(logger, 'warn').mock; - - hook(ctx, services); - - strictEqual(loggerMock.callCount(), 1); - strictEqual( - loggerMock.calls[0].arguments[0], - 'Using the @Log hook is deprecated. Use the Logger service in a custom hook instead.' - ); - }); - - it('should log the message.', () => { - const hook = getHookFunction(Log('foo', { logFn })); - - const ctx = new Context({}); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 1); - strictEqual(msgs[0][0], 'foo'); - }); - - it('should log the request body if options.body = true.', () => { - const hook = getHookFunction(Log('foo', { body: true, logFn })); - - const body = { foo: 'bar' }; - const ctx = new Context({ body }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 2); - strictEqual(msgs[1][0], 'Body: '); - strictEqual(msgs[1][1], body); - }); - - it('should log the request params if options.params = true.', () => { - const hook = getHookFunction(Log('foo', { params: true, logFn })); - - const params = { foo: 'bar' }; - const ctx = new Context({ params }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 2); - strictEqual(msgs[1][0], 'Params: '); - strictEqual(msgs[1][1], params); - }); - - it('should log the request query if options.query = true.', () => { - const hook = getHookFunction(Log('foo', { query: true, logFn })); - - const query = { foo: 'bar' }; - const ctx = new Context({ query }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 2); - strictEqual(msgs[1][0], 'Query: '); - strictEqual(msgs[1][1], query); - }); - - it('should log the request headers if options.headers is a string array.', () => { - const hook = getHookFunction(Log('foo', { headers: [ 'my-header1', 'my-header2' ], logFn })); - - const headers = { - // According to RFC 7230, each header field consists of a case-INsensitive field name. - 'My-header2': 'header 2', - 'my-header1': 'header 1', - 'my-header3': 'header 3' - }; - const ctx = new Context({ headers }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 3); - strictEqual(msgs[1][0], 'my-header1: '); - strictEqual(msgs[1][1], 'header 1'); - strictEqual(msgs[2][0], 'my-header2: '); - // Test the case - strictEqual(msgs[2][1], 'header 2'); - }); - - it('should log all the request headers if options.headers = true.', () => { - const hook = getHookFunction(Log('foo', { headers: true, logFn })); - - const headers = { - 'my-header1': 'header 1', - 'my-header2': 'header 2', - 'my-header3': 'header 3' - }; - const ctx = new Context({ headers }); - hook(ctx, new ServiceManager()); - - strictEqual(msgs.length, 2); - strictEqual(msgs[1][0], 'Headers: '); - strictEqual(msgs[1][1], headers); - }); - -}); diff --git a/packages/core/src/common/utils/log.hook.ts b/packages/core/src/common/utils/log.hook.ts deleted file mode 100644 index e414a7925d..0000000000 --- a/packages/core/src/common/utils/log.hook.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { Context, Hook, HookDecorator, Logger } from '../../core'; - -/** - * Options of the `Log` hook. - * - * @export - * @interface LogOptions - */ -export interface LogOptions { - body?: boolean; - params?: boolean; - headers?: string[]|boolean; - query?: boolean; - logFn?: (message?: any, ...optionalParams: any[]) => void; -} - -/** - * Hook logging a message with optional information on the HTTP request. - * - * @param message The message to print. - * @param options Options to specify which information on the HTTP request should be printed. - */ - -/** - * Hook factory logging a message with optional information on the HTTP request. - * - * @export - * @deprecated Use the Logger service in a custom hook instead. - * @param {string} message - The message to print on each request. - * @param {LogOptions} [options={}] - Options to specify which information on the HTTP request should be printed. - * @returns {HookDecorator} The hook. - */ -export function Log(message: string, options: LogOptions = {}): HookDecorator { - const logFn = options.logFn || console.log; - return Hook((ctx: Context, services) => { - const logger = services.get(Logger); - logger.warn('Using the @Log hook is deprecated. Use the Logger service in a custom hook instead.'); - - logFn(message); - if (options.body) { - logFn('Body: ', ctx.request.body); - } - if (options.params) { - logFn('Params: ', ctx.request.params); - } - if (options.query) { - logFn('Query: ', ctx.request.query); - } - if (options.headers === true) { - logFn('Headers: ', ctx.request.headers); - } else if (Array.isArray(options.headers)) { - for (const header of options.headers) { - const headerName = Object.keys(ctx.request.headers).find( - head => header.toLowerCase() === head.toLowerCase() // Header names are case insensitive. - ); - logFn(`${header}: `, headerName === undefined ? undefined : ctx.request.headers[headerName]); - } - } - }); -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 346fa2760e..99997606b2 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -17,8 +17,6 @@ export { AsyncService, File, FileList, - Log, - LogOptions, UserRequired, ValidateBody, ValidateCookie, From e8bd827cd2aed529729c83e4f1d92b35b972371c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Poullain?= Date: Thu, 22 Aug 2024 14:45:02 +0200 Subject: [PATCH 2/2] [Blog] Remove the deprecated Log hook --- .../assets/version-5.0-is-here/banner.png | Bin 0 -> 16990 bytes docs/blog/version-5.0-release-notes.md | 19 ++++++++++++++++++ .../version-5.0-release-notes.png | Bin 0 -> 34686 bytes 3 files changed, 19 insertions(+) create mode 100644 docs/blog/assets/version-5.0-is-here/banner.png create mode 100644 docs/blog/version-5.0-release-notes.md create mode 100644 docs/static/blog/twitter-banners/version-5.0-release-notes.png diff --git a/docs/blog/assets/version-5.0-is-here/banner.png b/docs/blog/assets/version-5.0-is-here/banner.png new file mode 100644 index 0000000000000000000000000000000000000000..2270aaebc4178fc0595c539181f854793ccb3e4f GIT binary patch literal 16990 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 Wt>f5a{e~jos;;b~RHN|UoBs#q5 literal 0 HcmV?d00001 diff --git a/docs/blog/version-5.0-release-notes.md b/docs/blog/version-5.0-release-notes.md new file mode 100644 index 0000000000..b3aecf93e8 --- /dev/null +++ b/docs/blog/version-5.0-release-notes.md @@ -0,0 +1,19 @@ +--- +title: Version 5.0 release notes +author: Loïc Poullain +author_title: Creator of FoalTS. Software engineer. +author_url: https://loicpoullain.com +author_image_url: https://avatars1.githubusercontent.com/u/13604533?v=4 +image: blog/twitter-banners/version-5.0-release-notes.png +tags: [release] +--- + +![Banner](./assets/version-5.0-is-here/banner.png) + +Version 5.0 of [Foal](https://foalts.org/) is out! + + + +## Removal of depreacted components + +- The deprecated hook `@Log` has been removed. To replace it, you can use the `Logger` service in a custom `@Hook`. \ No newline at end of file diff --git a/docs/static/blog/twitter-banners/version-5.0-release-notes.png b/docs/static/blog/twitter-banners/version-5.0-release-notes.png new file mode 100644 index 0000000000000000000000000000000000000000..118c134a68a844798a0cd0bb3c11daf0b952d6ef GIT binary patch literal 34686 zcmeFZhd-77`v-o=9*6Ah*dbXN*(b^#*&|!_CPYSvjI6Q=*(;-CWF%yd>^(w4R!YeH zz3$Wd^Zor1zu)`usJuD%eZOAU>v>(*^Lk#_ElNv6k(hvv00x5*D=R5z!(iBWFc@Yy z9uD}9YTdLv_y^xz$;b-^qvC-6U?^*|{{-K}@X}Vi3wt-rum%1H%MPiIgu!a!3C}ID zVX#PYWd)?JAI8oiVHShklZ~^D-K`G}w(Ku&r92j_ZSP2;c9X#wXtop+#W-ST#~S3= zkf(BHp3!_koHZ2XWn!46zRKX7^vP9}eO7(=&g=|nEmw%;d*wkR=aiWx;`%V>SnFA` z6dP4K)0;*a&9{Y3i*w4}l{J*PO$skcPwKT*NoVZ6dGk?oXre7=BXDqU+H?bK3i>bP zAof^Z?Xpr?`923CmDGP*=UfKq$pV7znH5a_I zdp9)_1AU`N$-s}lMbBO|Z8HEo$raIB_q!2SUH|YM-e6VDQpx^wt7>uIgW*yax?X|@ z0-ewxG0s5Ns6o_+?;EWttF}IithRpd#Unr7wDm|y08mA&m7pJYLzdw+qwJ4}Aihl5 z-Fk-iw^+av>IJ)Kz(?{KT)3Bh3l9+DChODhwJHuilBLR`2#;3ttKlzI*xnqtBl`0F~rtYoa+RZ>+QgElk#@s@~Vv6{^ z*YCs+IehzTd@qdEZ$LkPfE5n@k?uDq9C7}rVe@4-yOhq^=JbWQX7K&N^8pn7HE^{6 zdcpp&%d^`NVRIT4$zh9d+{sN1H`4x7X|g5Jxj3*Ne_~4Xt$K;vsAj!P?qoF^Yp;x? z_A{Hq$5eR;pid}10M8l`ULcUJoEdl5ii{|DuA$D<{P5eS*1gx(Z5OoQ$6JbWAViE@ z3;neF%QwLCA>Ed@HDglk{wu6-@8x@qf_RK51YZaDU$yMK< zC%Fu8bGh4r1gANHfG}lv4=G-v6J6CZTaFr!Zmt;n`ko;qqf)F<(cunA35J0v8gL*L zWJBExDowyk-u->zX6(Uauhh8VBe?!$IFFwYtVll<0{rGa_;OPym{_JE$#uGN_8t0Q zd&hIGrw6CkTZ3on-Hj0hyQFpypa}=(+OlzU9ucNe&iQz#>rVi*^YSnP2x+(QIgh_r z7K)e3o0Hu+PyTv?@;Uh7VmnwKf%ZxOF}fkO=WjE+`Hy~H`ddc_o}^4tX@EBsNvJ5p)QfKf&;rx4&{ z_K2HGyv&AeJ%qTWbZS)t%e=N1ldNAZaTEWA*zfj&;5z#R58&@Nma9 zuXX(LdenW38m#8FB6>Bk)I<_y0^%)3gKy?rM(|rVMp8fDIeY}nBKHrz6S*t7wEU5w zba1!})nN(m5^oX1ujq*I-~7#7HKJhiaugWQ-w*G|38l8GD{xWfAA^H5z-U580pU+z zxrhh|F|dRA=q?j$t#TYOQ?B0J|MxWSLSZjt!7CrxbKTClm?m3WP1VC^x5;SmC#Rcf z$8*~K55;dmDF4O)1uaCwxxP+=pL@^z!k-^$+F9hki`n>kqM=y-O%DkkVr41RA- zo{koor2{Mcmva6Jw#;T~OEu|)G{J+7vZz0@Lw7;@A%YquG-&D;SBAXp^*7*i#WLHk zonZH32HxOR5nxLybifqiw&$MeoYQ_f#26l?)HF{JYK71qnsCQ>_fdD%Q3vor%!*#h{l~oc+1HMv(}QON0!PuG z3x~*@P27i7Y1fi#sG*|m&#`+HcFU%$X!j68AKS?9^As!Jmq=5mgcK|9vG%jiPY$Y} zL*+$7bylEhoDkOm_@U{O_h}#zdwrD=jCsGOtP7kt#OywlApErjUMPg6Gs^P3eHH!8 z^~2$PLF3YY_!xHu>-9H=&doo8zMEniL~hXzWCgrZe=#6FZ6N3-%|i(HG3bX$_Yhk} zh(+)X1YNpexq&*6_1{uEDmQHws!{uVbO;?SwMJGkBNQ zBDm$gJ2z>>)-&!ms}_(!L9_q^f{BG5wqDo;o0WGZ(l|O1_aEAC=Y|4PR1gFhhSi%j zg(*dd5+)GNc}leyWdYYT$|{7`QNe?G7Y3{5S@5wU#`irh0e*qio2}|bkx%*lY|nF= z1C%5n^AsY$YE4%Sh=16P%d*yP*x}(Ox*3Z!AHVU`x)j9#xsVU- zacv2;XDSv$yTtDK)hrM4UvGMO6<}HeES+eO699{nzYcrwyLd6h+HMa8p5Tq&f`dsMceEFSK&IaJxvoMe}CtDtxv(C9&nm>B#mzsH^?m zxDOA$2k!GPgN-fMbKBBLOOTnP>~*P%Rri9Y~80 z_kE*BQ`Qd3A*|`3@#wN*K-3f=Hm*&Cn$P2p^4c62%>fP^B5FYlna%2w6#Mx1sWdAc zTw4SWHBGrs2^?4)cdrnlG$=|85IF4#8wyXNj~iKVLg2IB*=eKMt5O$6f=x0k$>HER z#OO#qKt{wey4v19p=b0(!a;6Y*BByk`q5B=8xd+NoGHx9jR>P7!`x(Yxx;kpYJss) zGwV6+6hvnR&@PywSpHw0#i^FK)jCSNHT1Dr;k!8%SnWDG$DyE@rcdnJqyZ}khx6Y# z4GBn4f$mQL(IGijq{#uG=}vpOg)~a^mERecb}CgH1=xT&mC=5eLD10-2(~)+t#{X9 z+#0=6zW{+Y;I@!10CFx4#9HOl+ZA-P zll*tH0XkY0!p@}|Vn%c3JI$|yRo+KiLJzg1bR{QX;s#t|^YQQEdllS0L;}DV9_T|4 zS&rTWh9LS;VAX-lZ6MYw3rUv%?)n1_cC3XEK;nBvWcSs1aT53oMab}RZgnzqgO+w2v>_VUqPV2H11Q24R5zsqbDRp>w>=BLbeFDi66fV=ZR zi$nAPM>ciRlD`J~ONL_DrpLwv*(e&yeV#WAgVju;MHnVnaA3a_P2vFGWU+kIU-R}4 z&3_dU!mdSy1(Y6Watr&l3)rna_QA*I&*_qk@05Y);2DO#Q%4ou?F%-u$*)D*STI)j z64!7{aMx?-8EC#EG`u|O>wDDWT9dkPKXG?pr;>KnD>L;O!0);%Btq8wkd< ziE=r97kAD2ruHs4029s{08=C=BgG9LvVH$CkB5uFE`~B1TnhN?+=?_zB!z|SkYfYgfutB$sXL)=;iVpu_?Wb0`ojEzpo=H*S_F z-S9vJFV|(qeZ=Q`?{eSYo~!KM^MML=@N^vX)8nI2C#FwgKutml$F$F^5xFMPiLCS3 zpto7e+@lh%7oMRS^#QBge+wdI2ouH53lf)KWjNF3e6W#QoniN8n;a^({w}1f^;{ZK z!7raQ!g(N{J{ws!1)pOM? z*qkc1lo|LPYIwH($?7aTX1*Z@l0&>B?lIeti*iiAYOuVdS)|EFUu2l^)r7} z;5I%i7jyom}cWgrdFWry~%w2cSg>yj`q84FgY%7VFq0~ymz#w{Iw2MgI_eF)tG_Z z6PO^JRriOMAzipXe&4uvA7IV9e%oB>sy&$uLPf(EYXA5XfX-Vgpo(dg$<#W?BDAeUOe=| z-6qD|EU~IVn25bprfXzbp`7kLA#g8vESWOBbFK#uf105?mDIWE$LHTwg^b|%lBHS#rEuIp|1+~cO%1*2Lk4Jr3tiQosQ2gs31s9+1>j$D zkq(o&RPc<;>xoXX%HnAr&AwXFFKpiIx{H_ivoN4s7HV}wFE_8&TN7D<n{IFPqi zb;{I?hTxpG)aTE`74skS%tLICd|7~rgA@QD3#KdR8DA$dpHmA7Hr>0mcSR03Cf0Ls zAr1QS*KFTw8=__dNLDQ1vBcE<7%cm3Z$GTrQ5C-G?uoE*wvqEs)|Yl|{k|*Y-{}@` zEgR4bMfB0wULwdE3JuF~d>2`JBc+MBkax44`KR37pYB#4N)Y2WI5*$zUOwM%5i{nA zA;al>1FoEh>g198KB_f4ttK|(k3-Kb`~{Qz-^pX-)o<8>O}=!SxiKH~Ghch*qV4&- zAvhm>$h@d$=A&;V-?#<1J_cpKnt#k8HaB@4n z4418+*P|11D5jtYA+Eq{(?CJ*!Zj6dCF(miN<$u-_<7=C=`LS)*hOGEP&?*4TQ2mf z5)bHQI6SvV9w>v;pg#~50~~;&)NJ(L;p5i!(d^K3kjIo!k_rI90luNV-D1czB(Cq9jJK=2u{fQS{2xON_&-|he`DDf`+PKnnmnqCP{Iw z-LH{hbN-o%{%yW3r*yPuT)t7U=IR{K7Ue*}AV(NVKxxW;bsC@m)HGQ1krjJg8!=zE zv7p~p#OOjqm`osps9Wnp(S@Jff>l9P0d!~^#fbo-qV&m)+lM6He790eX%ca>*_Q|} zK|vC;L$zDcCbv!VE3LUCJKJ=ymPSSMU8>_NF2Uc$&qG13NrIGX1O_qgV%h6~Wj@cY z0PGj@^$-lbLl3?!^iLrs9J-t${93ylESg-tkPK}7G3Z?&Z!-$2CQ)2k0N(cps@mkP zHF<3XZL*$B2PL_aJ|4A-W!INz_j~HBH1+bAak-+&yM{f#y4beA%Tb`}f*gQd0UPX_ zINA3WNG!D*qKTkdn|Ql|fKK-^e}Du}gn_|a@}|9pNgVF-&$hmSd=neXtDF}%2eqJ7 zcI}*l5GKdCCvhyf#Ob-49Uf+He}=Q+9}6;bl09Gkc6!;Yvl5A@0>}nxgUXc>1<$ry|-ddv@PI>7FQWUIf8_ z2I7wi?kY7OVpFV8aa7jq9y>c$s^qaTU7^mi;ylkW_1t!IUFNEq_5uNPh}_`C<(WJ~k_7f%SnJCn4Z`5(C!D z@e*e-yB(q{P((Kror_7FAjjRvc%wKU#lI+^B0ht?<`ii&zeJ*PMG`n1nBQw^8|ru$ zCZ}!=}SaRwV1Njz8$OwqQ&WO zB1k!kARvS+RP)LYZtqi!K4bqxAlOc$EIn@%deHsY$!18aEw>qE>~&Ud#)fu#DWT>YPZ8JmAPXZe;Mdc;XK_J~jTRbwBT2@$r`!un!8rje4cr4xU8a zk_$e?$Iy3lZUlxQyAxCt6i^cp2KIto?sl+1xMz0}*girAlY0XNHK8hht}lsW2X6S) z+5y0FTCGQ`AT))CaX)Ah=kwxfGpU2KOoEk5K?>-%XnLw2AD35A;#E>?pH!UZKlyto zeg8m*vGUX60fdJ!%kPC(4=x!WB$YM1wg(#HHyDUx2m^2CFN=T2vwkMGQCo2MxG|F= zqE4{Zpp+;YOE6}A+I7WZDM8a6zPC?22X;dX$;`cx{r=jQ#^HOxJ#E~dR0M#vX8F27 zR-C`h2_WR)AS8TX!$IZEW7?f;Z4(9yVStusV?08of9bp*-ORGG!wqC<{OX59H;`m! zPT^r)GM7Y}uRf4#esCi7Uthm09fhTeTEpa04pQ-92s;M+vb+7vg*x&0)eOLecLjn~ z^6mtO*60(F!HdQ}Tr(%(8IqpViFFXh0dh<*NGY{L2PU7hEOy&}=0BZN#=Luz1UT`8 zHSWg3m+-JHk$|T;;iI`idvjqv!Ga)dh1^`@rvOa|J)h0zMrn7SHg2pjwA8drI1Bvp(B`AYkk$qZ_lwZ_MnJ1|FN3D zeKKKc2JRzrc+u?6=T|G&+1mGsSLOZ(i=jO{uj8|_qm$UzMetGE*c2$RnTdb6p;YyJ z3qM`fYeaGttDIy?iXZ3=Avd8|YGYi$F=*;;)dgU=DdrhExn@#(~ zL*>1{{R5##bTpf<9_O1q=cWwb5`FwFQAJ>r1SRCkl2>Z#35UtqLUs`vszP{&b*PBj zFC^o(en}SY8>@*dXxuOd`9OazCP&%_xfkrLJtEU(h4gVY<9*(NjcnTbwmKVCys%7e z#zd3tPXe|-0-7qlsLhNAmS={BjM{fxEcI3F+PLJ%0(^;8sdi*lUQBABL8uSMjY{)x zA3O+Lx!&A5qac4*Os*h<6qewD1&;cmU~*mI`PEMAr@~juR0w?2Fag52oWhGb({uOg znVy{KR;$zAe6yb$25=lVx+led({n$LehvYCIdwoy1klLC*OU0FWn6^|4=+(o-#GS| zIX|?T5oML&UVYrSO%lzFuirq8>jbD=!nJcsux6>s^A`<~f8}|?jPG8Yo;yI;A5qfp zK;Dy^VG0jxwfoWAxrEUcDsWOrdihS^NQeSRfegWYFxam?!<=2wwR{rj^K&ur*`}}i zJ|tN@68#U2Zs`)|N;dOup==s9jg*yLu#gsXGze{dWmhFkxkGX4(oMvJBsVHWNcs36 ztA*CA<%L9r5S!A%YomYc*8u!s->yMO6x%5y4KN>x$N#fEJZtyaDC>Ien?*^X z+DniD4HP=t59(&qY_rAQlb_jmoZ9$>UShte5Zi3c({*|RisIU6kjN5vUF%-pJR{?! zsqw*7MbYLzt3c7ndbn#;OKsoB#m5bp`LMx^H_b#*!-JUCn>Z!B*Dlj8@k1Ert`e*iCR{QSs@d7JcYN`;z0QLFf!j`khHG?@pb zh{G^B9iw0Ysd&jxD)TY48knG2dpU*y`xYlS+D{sgQDgq#trKaAz3~0PBjSrB>@U|z zIp6MnPIaZ>U>JOnzIL|oWyvDR-P7ZQe+2rnDMcaSB>xM$gEscS}&#w~YMyNF!?ADPmxgf~LraC;QN z@pFCb*bz^6zGmgt9MrHFiDhKV(Xi@7GS}DtzAW|06ifyg<0%xkzM1KDDLr!GA;wR) zC0eeJMNw;hNx}N#0BTK9`th>s8QFegL$Hg45nY$Rty9)kAP$?MpU69>y<_Ob$4f|_ za%HE5|I{emLJiw8&{#xCJWX9kk*THwi64VonVawj7X$VLQssL27HJQCa2Gk(EDrpE zU2(!CMrnFgVh)0)m@6D?N|sH1NoR#6Ycy4;dFMUIO@l|ePr)*!&{TDX&zq-5t(tr* zB3zM~>{}*8%d=j}X5!(M6CWM-eLuL46wMB}#MqZ(ry=5^4lsY)3doKdIv5ce533bc z8s6sgt`ONF9*<2-$M4qh;z-Z3CcbM@W0=54uUM#+8+5bW+rNe;z&P;c4T`xK3>f4u zpD6W7PA&7=2#qqN6f!-A9~HKq7?t6&-G(@sT6EyKa+V(TFvIJvtyjsjIx7@weyKHr zSf7D$*Q!`xa;~&GruWG1{2&oD%1S01kM(jnj>G5+y->u*3k(nY`?LR9+YwwhCF2i` zWfu|#dwUXt2SBiwkmP5Q97>B}N@lo5BvJP?+o|TI#&C z@%Q!GbK9xZP1v)7!JwA-i|T2%+ui0>Wwq8HlrlY-c9#+p|KNH_wfi{_!B#AW2N{+( z7=KE}hTVIVzuQH`g8};_51=QfrsZOFOe?uGI!24x(b5M%2iPuqd<1Sx?USbp3H;-V zOvLr;mMa$G{vgaMKnT~e6v@KwQ7<_Etc6UIpLGy4d)>kf$y1#rh+tdJ7J?2Hb-(qt z1lh_rTU}sR(DF*$9T~;Qb_|>JZrJ5qx7&M-V6G*Dm)UuVwu9!dOJ;Y0R<7|)x1u^}FRmTegHNq@lC$uKNkZ3;two}{0n zsGYh%UG(w8Zr5lBa-SHnEj0nhgpqccYk*$Gd7LnLrZ=rop4NOUwH?-MYBGNJ6Gwhd zhQWqePw__aK%u85T$|iSsW0)kCdZ+o??oGs1*&KG?3(sBnFv+2LbIy9LwP!+AYb;n zgOB$=9v7s}^kiaDpWZ2eF`%K?QwW4dm?)t0Fe^2I#u+U9yqf81o-1?z=MLRQVxkW% zLOn=mndy^i5;2e;)tQ4n)8F8jV!fU$=65a@(sAbx=sZKrSWa!`@%I<4j(Viz5@y&e zF5R>Bk@(%x@=)&V41Jm@>m>)cV`JpYWiy68jO?#BcERbOPt@YTmri}e#Cg~JbTa(3 ztINoPlLWuk3GHANngW~*;ch;weLt1FI~iTaxk39hmlIm8BVM#>XdP~4_MnO$!FcR@ zm*XR6RJrYw&;uZubs({d7XILNIdX|k%}XU8S#dQ@fz0z0DlbT_c_dT!G;9PW4MQ0< z%(ph>LwEZ7vDSLv!^%|uMJvHXo~MN2{NtXGE)&)J27^9>iYaf6ct}u}a9WKfEtDJ`^A*1DZ6*EvoKduV9MJ z`pR@On*}k*nr+eIBTgU8`G^lO;qGp7hv6oLQXr{B@YiR(9&Q|X{5Md9I1ct1hjl)pT*m9A=nudq(M$O;G|Z4`k{R@ zoU94N=MsMU;0vHkvFstN11`#{nYu3CTHi)IRXe?Pg^%>Hc@$c+6d!-NiL>?i+O&)sb?Hb4lNKb@gRZk9k#H z1xm~(ZK}WFL=?W)jCn84RwT~a8v*#1dGLDm*|YU0r(M{X9k0iaR>!&=1TRPEWEoIb zlVV8Y`%3X$ZWh7rkE{Iwmegq-IdR-%%3!(O&&<@_;afrYFLbiRzgpyTCooC*W z^ED9ZNHIV_R;MXXo-zI{QKSH2y_-b@SYSZ=M51B`hvmhU)p&F%@Ers#WlyK zIW4VNXcxgnY#BS$K==(`s*qUfgE@sw-ja=m?LQ$Vx#j`L%(Tel9kE zakuN|s8yEhM$VPf@%tL8=XJce=y9_IB52e23e+vWng<$H=hUe8*-zC*noAJj@%Y_a zb>1GvAi363J^6V#uKwOsK$!51IY{G&vYlMAk&plK|GJW_~zRicE=fcfZeNUws;e_M%C3i2*Xv?PRiOIByj0bIWFrDABby_hJMown>WS4-*wz zuN~1<2T?XK@%S~1qo_d(i2+(1-%nrhPL6|0y{g#h@7)sNtua*AC9hs_ApM8bc788a zd&J+Hf3e8g@yjOz3Kqub-QP`gq-e;{>Zq^pA1-?%&qXU4BOJPPR~&CSPe+%uXwn(@ zylGY`iZZjz=)u7!pu7LG8X@aFZloE_UY@^X>3tQztPZK>Vpgm#+7Bg;&!-o^935J1 zFJ|;V0D>7<89KONU&<5l9kxsjcJ`^gK@HKtB1>l@h?Qo@>ljOZN18wCQ#q<5;$eo(`^ z*W@4p&7K%-3U}&Hsntm%#JHUp8STd5wc@-Qci0v7XMkW1+hp6MN3k_4m`G%K_A+-Cr&nQ@QpS73B8nmGy{uA;Dj~AEs zrHk2?#ZQs8p+@hcfY8Hvb-5Rydpz#&<7ek2*Ax$Z!E5M~(EO*xJvEf4K)qX&0;Q$q z%>4jCo-~Ur4V|V-i|V6Xg^0V)U4UW-gWaTtc0E9`O#N~PMdwyr=N%eSO%1dkm2!xd z$q6XbwQkQoOn zdz3vrL$uZ_n)U+;WbJrtU(mh3CdT0Ht5Lbau|9rC5sBm|?Z&b`q0vf`QKc?^^sARm zTL8PJ7oeg}vaa$iNbAhtv?Jl&4tK$_1yG!%5*qlR(;GZSN0DzEb;>DL?^$SS@sZ4-lAn zzkrgMK$A#G@MY zD&;pBZ?$&ZUPH}(%)1ftwo5$l9D`$2d?bT{|C0W8_;biw(1Ey+?&TW0bRXpo{gMT4 zO9H}}V7s{Kt*ko;LSe2>@^k#|#2{->5@Ns%??CZ&j&%W9*Bo;}aJK=+)&poYrL1bN z7A5iUScJUV^Fjq4*?NmdwHXm>Bgv%!v7LhkfSJMF(e(#?8n^&ex+Fz08n-^Wf6v7-(F<;k zuu%Om+6l$55he(bsHnDlx(Y=a+Xyqt*t{Web&$a%MU>^zIE8zTKjge@ODp$PTXtRyTA`Gze2gtNr8zfR%4t((WnEd@lzce#&c4z<2`)Js4 z=E!z;RsW*~wxxs?5^tHX*f30h4=Rv%KI<%9zXDTXZsr$A4#=@k=}l&nz(;$fTyqK(HUq$JR(3*|0NYW$-3n>o}^&X?Sw+g6QxVzZxX3 zBjv5t*oMMGuC`1SgnftT+MFurfP^GN)okw2>b4Dba(K}E!$O84h_g@Dxlk_e z1a?CgiPjm$Z{L{8)j~)_i<3F6Yk{pK(D73AcezRIGAoyvUf#0JPVlYlr?H}IdP$(v z=rNcvYjO1kw6HXHw~KI`YoU{K!Qy_z>zR375YWxg&`=_!IORII7k&xf>xdP96^XT& znvB803utM*t(@pP6E-EHOFF9XL0r!)LgwPHzdFNSboHlat`S#l0 zIDWTNd5rf6az|SIF?Ayc zezRdL>;F@#Fj=K-&bwHtzyo~7>!F%jpNobZ z&RRLl?1!-DufLz9EA!wkAWC9Csaat#MhXo=j@T4yL zWQ;f;3{o<>@W09S<9QgACsaD~W&?zNiTE}$&~Qft@O5n7wkAi>1J2l$F3GVO2WV|W z?d4aFH8!DL9%tLNx$o#TzJj(T(oLV`w!q*Uf4Ry-VgZ$nJtvcJp+y`{AjLq5a&X+-bYGA{` zu#n>}*9XQRD(Hvqcd^$x0GYOZF04I?D7oryPaWBOUKX%u9GZB9c^6NG2Q;^DT@F_V zM{5ZAfYw2Fa`MqCXnbeBQAF2&m<7oZVIq-qB1XG{8t)Kd>^uPP^bp=RZ}%8G%YLkKVl)Rd zJokOQ+YJ>esc8g)f%b>*G$YoS>k+`t{m|qW0`)Ho>Hyo>Lwi~0+vWyNXa0A(aDOg( zpvH~cE?62l2+H`>`@|er1m`$2F<(dQ0$1(pnCP?Dd(6&I;0bo=ir%H_xyA=25Nzx4 zsBJ%|OR;apR)mL@>Bo5dPpCo|B2PhK{aI3LZC%9x(6U8zRZMMQhNqK8nWozdc zYqudlQ53TSl(yKB{{!D9chhAq{uCpsA^N@&7D!o)=OXwpxzt9N?oslNZ0jrczgLhR zqtR;>bMQaZ@u&ZqW{y=Cs9zR1fR9;#h~I#Q-XqJ=Se-uXO2*Y+!Kyv>!h7KWu9`#1 z3t#?;RTr3tNzb>)g(MGj8$aesjxNsM>W;xJPql@?VA*$}x-M10*Jn2wm&34RS$cVa z`}o@Kt3r1zE}Hmw;=ZQQ9koaIgMfTQ%@C)HH-|mh!4Ak?(@V5N$4q_J4ZZ6WZuTJur{m4S!DP<;J$1Ya| zv?8UK!%Ts%?3}yHcdfWr71adMVnyi zjHM>p5%_r^RdEcjKkeIlAyC#1tfE!neHbp-BWbooLS&>|JzUL^~GmL z8iKV7a*fVlVHH5|X{Twmw>%AhDE>R}xcY#%z{%zrngpXy%8*0E_l3I6!zeHgEbdi| zRXLy%a8Rm@^Ey{-2$DJRQW?D)TsiBrFrg~A;ub{Lv{~(i-gz(068;q)@_TZ$N0)Nb zZ-srgYf~LCsjttUk-d{GaeL|K79Z}G1V|I?(+?=m}7eK*Yg5HjUw}66dZ(LsJz^k^G$SxwEa%5z|0=)6f;;p zHuQNVHm)YBydWQ_W4nOKNpr0n>iKCKrya%3kjGrCB8`D&q(q6f5_>I^LE)mfxQk_q zB?sS3D;qt=$~gZmyb-4&xGY`E==JEz9E2KB#1MSwTSt|xyy29ZJaOsfvKQ6>Gp-hY z2Gw>5JCJO;gg_ebf$&$L)~M>jGeCm#Tc*(ahagf2g#0(@{P-iPwgW3)0rq<7%7Anb zr6$ZN4w?MljdMqDeH?eLnywRI{k=_1H7G7+D^Ney2ntx3lo?eO=DhHd$qe? zzxv@wUqmaGntrtUDhBf~qqH;Lk1|ZV^!Yp8>)QMv$oZqS3bN6<)7@?>Yd&TB&nyUM z9$w0DU6QxcKv{R6kGa@Q9-9CBe7j627gQ>TP|8BwTXpipz8BtZb+w+o^I;rCE0zej zSurO#Q4?U29mWz}(ugZVH~;D*P!yG-H3yZ?ypB7LnfF1oqv^w-!1$*{Kh7uF!@=_HT}Bx!4vnz z!OlP?GKLI0t{6~*$UnFROGNg{q=db0qnFmUUb zn&$UdJ6%uFo9 z+=-%{P639hkbPk$v|UeqHaX1cDFB9k{ jqNg&d2>QstTlgVw@egS* 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