From b95cd8b157e902a920699618cf1e61d1f615fd31 Mon Sep 17 00:00:00 2001 From: Roy Li Date: Wed, 20 Nov 2019 22:21:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=9C=A8=E6=A8=A1=E6=9D=BF=E4=B8=AD?= =?UTF-8?q?=E8=BE=93=E5=87=BA=20proxyTestUrl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/command/generate.ts | 1 + lib/generate.ts | 1 + test/cli.test.ts | 13 +- .../plain/template/template-functions.tpl | 4 + test/snapshots/cli.test.ts.md | 290 +++++++++--------- test/snapshots/cli.test.ts.snap | Bin 1838 -> 1898 bytes 6 files changed, 162 insertions(+), 147 deletions(-) diff --git a/lib/command/generate.ts b/lib/command/generate.ts index df3407776..c9587d9d4 100644 --- a/lib/command/generate.ts +++ b/lib/command/generate.ts @@ -37,6 +37,7 @@ class GenerateCommand extends Command { return '生成规则'; } + // istanbul ignore next public errorHandler(err): void { errorHandler.call(this, err); } diff --git a/lib/generate.ts b/lib/generate.ts index 9c14ca5cc..1c95a99ed 100644 --- a/lib/generate.ts +++ b/lib/generate.ts @@ -226,6 +226,7 @@ export async function generate( await Bluebird.map(providerList, providerMapper, { concurrency: NETWORK_CONCURRENCY }); const renderContext = { + proxyTestUrl: config.proxyTestUrl, downloadUrl: getDownloadUrl(config.urlBase, artifactName, true, gatewayHasToken ? gatewayConfig.accessToken : undefined), nodes: nodeList, names: nodeNameList, diff --git a/test/cli.test.ts b/test/cli.test.ts index 598394354..ce7b9b3b7 100644 --- a/test/cli.test.ts +++ b/test/cli.test.ts @@ -9,14 +9,19 @@ const cli = path.join(__dirname, '../bin/surgio.js'); const fixture = path.join(__dirname, './fixture'); const resolve = p => path.join(fixture, p); -test('cli works', async t => { - const { code } = await coffee.fork(cli, ['generate'], { +test.only('cli works', async t => { + await coffee.fork(cli, ['generate', '-h'], { cwd: resolve('plain'), - execArgv: ['--require', require.resolve('./stub-axios.js')], }) + .expect('code', 0) .end(); - t.is(code, 0); + await coffee.fork(cli, ['generate'], { + cwd: resolve('plain'), + execArgv: ['--require', require.resolve('./stub-axios.js')], + }) + .expect('code', 0) + .end(); const confString1 = fs.readFileSync(resolve('plain/dist/ss_json.conf'), { encoding: 'utf8', diff --git a/test/fixture/plain/template/template-functions.tpl b/test/fixture/plain/template/template-functions.tpl index 1098009a1..325659806 100644 --- a/test/fixture/plain/template/template-functions.tpl +++ b/test/fixture/plain/template/template-functions.tpl @@ -9,3 +9,7 @@ {{ getMellowNodes(nodeList) }} ---- {{ clashProxyConfig | yaml }} +---- +{{ proxyTestUrl }} +---- +{{ downloadUrl }} diff --git a/test/snapshots/cli.test.ts.md b/test/snapshots/cli.test.ts.md index 6d62a89d8..3a1b87cf4 100644 --- a/test/snapshots/cli.test.ts.md +++ b/test/snapshots/cli.test.ts.md @@ -4,149 +4,6 @@ The actual snapshot is saved in `cli.test.ts.snap`. Generated by [AVA](https://ava.li). -## custom filter - -> Snapshot 1 - - `🇺🇸US 1 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, obfs=tls, obfs-host=gateway-carry.icloud.com␊ - 🇺🇸US 2 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module␊ - ----␊ - 🇺🇸US 1, 🇺🇸US 2␊ - ----␊ - 🇺🇸US 1, 🇺🇸US 2␊ - ----␊ - ␊ - ----␊ - 🇺🇸US 1␊ - ----␊ - Proxy:␊ - - type: ss␊ - cipher: chacha20-ietf-poly1305␊ - name: 🇺🇸US 1␊ - password: password␊ - port: "443"␊ - server: us.example.com␊ - udp: false␊ - plugin: obfs␊ - plugin-opts:␊ - mode: tls␊ - host: gateway-carry.icloud.com␊ - - type: ss␊ - cipher: chacha20-ietf-poly1305␊ - name: 🇺🇸US 2␊ - password: password␊ - port: "443"␊ - server: us.example.com␊ - udp: false␊ - Proxy Group:␊ - - type: select␊ - name: global filter␊ - proxies:␊ - - 🇺🇸US 1␊ - - type: select␊ - name: provider filter␊ - proxies:␊ - - 🇺🇸US 1␊ - - 🇺🇸US 2␊ - - type: select␊ - name: sort filter␊ - proxies:␊ - - 🇺🇸US 2␊ - - 🇺🇸US 1␊ - ␊ - ----␊ - 🇺🇸US 2 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module␊ - 🇺🇸US 1 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, obfs=tls, obfs-host=gateway-carry.icloud.com␊ - ----␊ - 🇺🇸US 2, 🇺🇸US 1␊ - ----␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, tag=🇺🇸US 1␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, tag=🇺🇸US 2␊ - ----␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, tag=🇺🇸US 2␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, tag=🇺🇸US 1␊ - ` - -> Snapshot 2 - - `🇺🇸US 2 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module␊ - 🇺🇸US 1 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, obfs=tls, obfs-host=gateway-carry.icloud.com␊ - 🇭🇰 V01 HK 1 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, udp-relay=true, obfs=tls, obfs-host=gateway-carry.icloud.com, tfo=true␊ - 🇭🇰 V01 HK 2 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, udp-relay=true, obfs=tls, obfs-host=gateway-carry.icloud.com, tfo=true␊ - 🇺🇲 V03 US = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, udp-relay=true, obfs=tls, obfs-host=gateway-carry.icloud.com, tfo=true␊ - ----␊ - Proxy:␊ - - type: ss␊ - cipher: chacha20-ietf-poly1305␊ - name: 🇺🇸US 2␊ - password: password␊ - port: "443"␊ - server: us.example.com␊ - udp: false␊ - - type: ss␊ - cipher: chacha20-ietf-poly1305␊ - name: 🇺🇸US 1␊ - password: password␊ - port: "443"␊ - server: us.example.com␊ - udp: false␊ - plugin: obfs␊ - plugin-opts:␊ - mode: tls␊ - host: gateway-carry.icloud.com␊ - - type: ss␊ - cipher: chacha20-ietf-poly1305␊ - name: 🇭🇰 V01 HK 1␊ - password: password␊ - port: "443"␊ - server: us.example.com␊ - udp: true␊ - plugin: obfs␊ - plugin-opts:␊ - mode: tls␊ - host: gateway-carry.icloud.com␊ - - type: ss␊ - cipher: chacha20-ietf-poly1305␊ - name: 🇭🇰 V01 HK 2␊ - password: password␊ - port: "443"␊ - server: us.example.com␊ - udp: true␊ - plugin: obfs␊ - plugin-opts:␊ - mode: tls␊ - host: gateway-carry.icloud.com␊ - - type: ss␊ - cipher: chacha20-ietf-poly1305␊ - name: 🇺🇲 V03 US␊ - password: password␊ - port: "443"␊ - server: us.example.com␊ - udp: true␊ - plugin: obfs␊ - plugin-opts:␊ - mode: tls␊ - host: gateway-carry.icloud.com␊ - Proxy Group:␊ - - type: select␊ - name: all␊ - proxies:␊ - - 🇺🇸US 2␊ - - 🇺🇸US 1␊ - - 🇭🇰 V01 HK 1␊ - - 🇭🇰 V01 HK 2␊ - - 🇺🇲 V03 US␊ - ␊ - ----␊ - 🇭🇰 V01 HK 1, 🇭🇰 V01 HK 2, 🇺🇸US 2, 🇺🇸US 1, 🇺🇲 V03 US␊ - ----␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, udp-relay=true, fast-open=true, tag=🇭🇰 V01 HK 1␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, udp-relay=true, fast-open=true, tag=🇭🇰 V01 HK 2␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, tag=🇺🇸US 2␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, tag=🇺🇸US 1␊ - shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, udp-relay=true, fast-open=true, tag=🇺🇲 V03 US␊ - ` - ## cli works > Snapshot 1 @@ -365,4 +222,151 @@ Generated by [AVA](https://ava.li). - ss4␊ - 测试中文␊ ␊ + ----␊ + http://www.google.com/generate_204␊ + ----␊ + https://example.com/template-functions.conf?access_token=abcd␊ + ` + +## custom filter + +> Snapshot 1 + + `🇺🇸US 1 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, obfs=tls, obfs-host=gateway-carry.icloud.com␊ + 🇺🇸US 2 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module␊ + ----␊ + 🇺🇸US 1, 🇺🇸US 2␊ + ----␊ + 🇺🇸US 1, 🇺🇸US 2␊ + ----␊ + ␊ + ----␊ + 🇺🇸US 1␊ + ----␊ + Proxy:␊ + - type: ss␊ + cipher: chacha20-ietf-poly1305␊ + name: 🇺🇸US 1␊ + password: password␊ + port: "443"␊ + server: us.example.com␊ + udp: false␊ + plugin: obfs␊ + plugin-opts:␊ + mode: tls␊ + host: gateway-carry.icloud.com␊ + - type: ss␊ + cipher: chacha20-ietf-poly1305␊ + name: 🇺🇸US 2␊ + password: password␊ + port: "443"␊ + server: us.example.com␊ + udp: false␊ + Proxy Group:␊ + - type: select␊ + name: global filter␊ + proxies:␊ + - 🇺🇸US 1␊ + - type: select␊ + name: provider filter␊ + proxies:␊ + - 🇺🇸US 1␊ + - 🇺🇸US 2␊ + - type: select␊ + name: sort filter␊ + proxies:␊ + - 🇺🇸US 2␊ + - 🇺🇸US 1␊ + ␊ + ----␊ + 🇺🇸US 2 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module␊ + 🇺🇸US 1 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, obfs=tls, obfs-host=gateway-carry.icloud.com␊ + ----␊ + 🇺🇸US 2, 🇺🇸US 1␊ + ----␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, tag=🇺🇸US 1␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, tag=🇺🇸US 2␊ + ----␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, tag=🇺🇸US 2␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, tag=🇺🇸US 1␊ + ` + +> Snapshot 2 + + `🇺🇸US 2 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module␊ + 🇺🇸US 1 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, obfs=tls, obfs-host=gateway-carry.icloud.com␊ + 🇭🇰 V01 HK 1 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, udp-relay=true, obfs=tls, obfs-host=gateway-carry.icloud.com, tfo=true␊ + 🇭🇰 V01 HK 2 = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, udp-relay=true, obfs=tls, obfs-host=gateway-carry.icloud.com, tfo=true␊ + 🇺🇲 V03 US = custom, us.example.com, 443, chacha20-ietf-poly1305, password, https://raw.githubusercontent.com/ConnersHua/SSEncrypt/master/SSEncrypt.module, udp-relay=true, obfs=tls, obfs-host=gateway-carry.icloud.com, tfo=true␊ + ----␊ + Proxy:␊ + - type: ss␊ + cipher: chacha20-ietf-poly1305␊ + name: 🇺🇸US 2␊ + password: password␊ + port: "443"␊ + server: us.example.com␊ + udp: false␊ + - type: ss␊ + cipher: chacha20-ietf-poly1305␊ + name: 🇺🇸US 1␊ + password: password␊ + port: "443"␊ + server: us.example.com␊ + udp: false␊ + plugin: obfs␊ + plugin-opts:␊ + mode: tls␊ + host: gateway-carry.icloud.com␊ + - type: ss␊ + cipher: chacha20-ietf-poly1305␊ + name: 🇭🇰 V01 HK 1␊ + password: password␊ + port: "443"␊ + server: us.example.com␊ + udp: true␊ + plugin: obfs␊ + plugin-opts:␊ + mode: tls␊ + host: gateway-carry.icloud.com␊ + - type: ss␊ + cipher: chacha20-ietf-poly1305␊ + name: 🇭🇰 V01 HK 2␊ + password: password␊ + port: "443"␊ + server: us.example.com␊ + udp: true␊ + plugin: obfs␊ + plugin-opts:␊ + mode: tls␊ + host: gateway-carry.icloud.com␊ + - type: ss␊ + cipher: chacha20-ietf-poly1305␊ + name: 🇺🇲 V03 US␊ + password: password␊ + port: "443"␊ + server: us.example.com␊ + udp: true␊ + plugin: obfs␊ + plugin-opts:␊ + mode: tls␊ + host: gateway-carry.icloud.com␊ + Proxy Group:␊ + - type: select␊ + name: all␊ + proxies:␊ + - 🇺🇸US 2␊ + - 🇺🇸US 1␊ + - 🇭🇰 V01 HK 1␊ + - 🇭🇰 V01 HK 2␊ + - 🇺🇲 V03 US␊ + ␊ + ----␊ + 🇭🇰 V01 HK 1, 🇭🇰 V01 HK 2, 🇺🇸US 2, 🇺🇸US 1, 🇺🇲 V03 US␊ + ----␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, udp-relay=true, fast-open=true, tag=🇭🇰 V01 HK 1␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, udp-relay=true, fast-open=true, tag=🇭🇰 V01 HK 2␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, tag=🇺🇸US 2␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, tag=🇺🇸US 1␊ + shadowsocks=us.example.com:443, method=chacha20-ietf-poly1305, password=password, obfs=tls, obfs-host=gateway-carry.icloud.com, udp-relay=true, fast-open=true, tag=🇺🇲 V03 US␊ ` diff --git a/test/snapshots/cli.test.ts.snap b/test/snapshots/cli.test.ts.snap index 2fdaf0db6b73ecad2db9727f9c5332af84e1c1ea..8fe38b2af48d7dcbc1b994223c54427f4156a381 100644 GIT binary patch literal 1898 zcmV-w2bK6iRzVPvwYT2VFDQimfZj?@{R5$dLNEOZeP?9LBiY{7ZtPtpySwYPW;B|4p3(d9%t+UB zx!n2OSD$=&{gu})UV8HOr)z(FJo@EaPW-%iF_+7~)#-ilL;cFy?vuxVJ^p6MBojs#kt{0Jq85>c*Q$&5vJ!a~xpo@Qa+-z(Xc zLxYa!I9K6@$esIWXFCyNh^1A%COB@H-G4Z{CoW};u zDUr!Q`Hj1Gx5UIqW(zJA99=vl)0xPhM(eGeob?KD)qTO$vog=4(Wun6-ClBTYx}@o zFP|8C(dk0?Pk;ORpP#;!7QQni40swP`70m`&=b#S8rAhicfC%uMt!ZV)jAELz1yib zw6*m%?zGqH#OMNp5gYsYh-n_?{iZGt`vi9Yc5?#&n99U_eh<3WuJwSPS=gkX*^Yzt zdZ~;q+gp9=lK0S!t$QduMt8syE3InFK#n~iXcJqa>fp`C&0^dy7~DdIfFLw(StzsNXbd>xBvV%5uo(8B+rVT)IR2jKp2QR>>l^E_PTN zFJr9soWWO&d~9cbKYIA|y9Ypn>~djNkjBU^v7n-$2h7(UYGFqQ$~t4dCQF4P!hVm5 zCK^);MrEy3hF?Q%;KdqLYwEe7Qow|1MrB>Ix^1-yRSLkxC{-^|sLe2Lw`0Sp+!}^aj$PV5h-*(Nw0(jHBWxIOg9y~inFB-cIh>VU zL)%Wr2L~tOf~dp120yVpUqouEj7maT714GmJ*1q7HC%L=Olh$ajJ}@M_Pdm+nTw#tnN-4u|uc;DV0ieVXl@sTj6s}ze z2O9N=J1#4Lg?;2jl$i@ON+Po&Qw0YRO#^UB@6ysvd>#&W?`x~S_w{9QRx`{Di0XbI zgf=)LhW*so42W7@>XPPImYAU`Njq{n#Wr_=HkwRS;M+pN&CP2e+(|$?0jSFGahnMR z!cqNW-Y^iNmpDQ?YlMuj;xT7#Cgh*kkWsEQg`$XtRV0KmR+!{P67x0Br<_{UX(j|h z{46XHd^~JU!6j6OiZzzz(}m~RM0%#gGOWa=(nyAq=o_San)vX(8hZ4rF5zI60|;f8 zL|T|(ukVtGm$W!1lCJHgiE1jTcyQXw8r2?FYGgDR|1WO*kB6iWj zvhYL`E!=2Y3f;;o=sqJZsqmHvORmXRe-p%tMIo~tmG{Ayq~ftbf~<_mivS*vy#u<_ zW9^`-kJHve^_v1!{n&0nY%gdj1ZxKqTraPTpI8K>At;kmj3Z=usxXSgw~BO}q+(RY zWP-p3vZ;16MRV+cKKcNzC^TweG#IBmKpf(NJEcy+c-PlN`lLAC`JM2W8^9<&k%whl zIX1R2c1N{3v2-|eKnuTT62{Rnq>3~9W5|#vi*-sS_{_ItST@XPNA7u=@)DJ`s4^C5m5OO! z6F(1+)%s*FiYdUXh3NoRAi_6#l=eb%(tE@uK4_0tr5tu(yAYptFkDcnmCLHR5rzu$Lw9>kPYjK;p465DkRcu+1#af&Wh}*<%tCNqt z74z?f)A(M&NxT(vz{8z%=Vx1;E$_3pykC%!X2N36p>6D-t}TRKs>ryoE4XmS24Q=c z&gKTg#W7rLo2Bf1Zd5g9tv7pK`T|A6naPenBtE@Qa#ut=b5D$C<~El3e|+`K5syul zJcQ5B=ziHi8@IE_XGw3xCYff=td_|%T!-8*S6}4!oR_XHv-mXS6sg{LAX+BpV|s-2 zjFgvZewn4LhNkC*aN0#vnoXny>kp-JjvvfBGiT#zJgbqsj`viY?P8y|F^%F(znM_w kDc?0rOycv1dKD@?`wM}S26U)*S;vm?KfYPhVh=a~0DE4m*8l(j literal 1838 zcmV+}2hsRJRzVr00000000B+ zTg{8xMih5aO293JLN7fO1{XpCmSy>4cdKIBB!p~9mn=Bj271_zq_Hh5dxS<>@0NZX zb0|Hwr$TSNr5}OP&_AHpoca%h5(>Ta+*99-YS=SK`mFuN4YkeDwLvmtJ}E>a#aKUj6;S z=;uqK*IF$UUMO4Sbj2F#M}kHJ5}P&8Oa;QLi@3$j6M0XyBAlFARNV>Uw}jm9881A}eAfu<0-)!;nkT zZ_(k91Z+LRdb@plXa{?Ks1Gm;NiglG45$-%q>QN5VXe?(@sZY}ENpdgNJe;1vvCmY zRb1Pnk;6q7B`USNQ7LNhBO^4*NXDD(e0o&evl-CcJ+p|AhQd9cn20fGAY{9Kj|Aod zwqnQ-4`93^l6Oz^U?xX#Hw{7)l|Y3h(FTp|@Cj5Mi&K%~o2Y|5M&c{IsOt_*v5r!Q zM*WbPq5~mN6<~qo9=G{&n`q&BFNJPx`EJ=AeMu$Xv0 zxY8wwKD60&SttrF+;JTe97b5Gv$o$13{;U-dTsucDeKMOEjQ1Ys&dB7|STc-IjuC`G97os2vya)I7P*G) z2tGfd52^-Qzne!s5WKX2czCZB2GJq;fuVJ%xGu#scV@LrrrbOq1JgPJ8$GW)m!4f7 zL%Ma5^=7B5I-+HA7Uq(B%1brB+)|cZ(^(;$wP?bgchver>YTF==AB6iO0=4!*Q%s) zT7+81t4Vk{B{vsY`E2m$K$L;CCBt!hoLSB&@hqY~jx0U@g}`Y8%D7U>#!!lvZ%gN^ zKFEC?_V_#}x$PnGJYdK8_X2W0>(4Rw;`;sjn_Mx1*@8EU4ZmshK zQ&P;QTOeM$(FJ;DX@h>^dLGuBl`6XCZuaPqyp3*cZlU-X-GiN2+pcdL$aDJyZD5;s zJ-Ci;_#o~>V%>E^eWlvu@SEt`-Szt$@0a7TcZl7m*U<*GT#x8R^S04gD^1APmP5YC znCvLxL_H^d7qHdxh)q=C8Fm?CjWY&cF3w^*`}4`8=ifX88e})*W(8r4>=GL~N_xZs z-J>@4bfBy=7HFbXDkB_p86ToCsbSPsD^>V4}ipx%(r4WtGpOfzb0n%%MFAyjGr z7o$?!4qdxX!fhOdJ$d9kSs0w#28keWd*C$XVSRZR#+Ic_Cv#gdjH+^}br9FC)UX1A z`y*@^us{U*h2}I~H^W&W8pb+K02`d}3lf0`J3&z zN-2aiR~+Pd5DPRvpdq!X*P2NX)U!|`1bEPzf}6=YWUNY<&*q-ff%GC1%W)<)O^t*r zNxmU<&*C56m0gei&X9y)m3?q!S9w^CpZ863u4PUU+P*Z$#oK=8@A32FGxU^BBFifl ziA+0b?}KlaiqHBpWQ9*&1n^|+9nk%MtR1rIlYZ5ro&{C&#Fjw07qk?Dje`lURgaAy zF9Na<6v0X12vMF&jFRMAMmi2s3Y9ULC~|>prn{MZIOeYszXw;8RvNK47>7JS9OHtO zl2tIi>uVx?(j4FUo$wbofRU=m!?LZN7+ZziQLT=b4u^JV@pmd<934X@KeIoE9PMOY zr{sdqd`pJ1A!WAXGDI=mB>$a)jthnva&gk01YZGTrYuNKijvAiN-iFY8y8(-Tgjz@ za&~-qsibbiX{EC0Eubjyw2(06Js{Y=nO+83_@@p^XOe{RzG*JQTk);3BTJr!yqV5M z(y4e_sbeZ@vd`mVxqnuQWD20QI2=F)!uLj((r#={dY24I0J+C@tr`n(hv1)fFkDb; cRI9SNrT!2^bX=%@q3VnO0b`xy?4&mU0Qw<&J^%m!