From c879f501ff01b1a3c577de776a1f7100d78f8dd5 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Mon, 16 Dec 2024 12:01:37 -0500 Subject: [PATCH] Revert "fix custom `assetFileNames` issue (#12449)" (#12746) * Revert "fix custom `assetFileNames` issue (#12449)" This reverts commit e6b80172391d5f9aa5b1de26a8694ba4a28a43f3. This change caused source maps to be left in the client folder, exposing them into the server. * Add changeset --- .changeset/loud-emus-look.md | 5 ++++ packages/astro/src/core/build/index.ts | 4 +-- packages/astro/src/core/build/static-build.ts | 28 ++++++++++-------- .../astro/test/custom-assets-name.test.js | 16 ++++------ .../custom-assets-name/astro.config.mjs | 4 +-- .../src/images/penguin1.jpg | Bin 11621 -> 0 bytes .../custom-assets-name/src/pages/index.astro | 2 -- 7 files changed, 29 insertions(+), 30 deletions(-) create mode 100644 .changeset/loud-emus-look.md delete mode 100644 packages/astro/test/fixtures/custom-assets-name/src/images/penguin1.jpg diff --git a/.changeset/loud-emus-look.md b/.changeset/loud-emus-look.md new file mode 100644 index 0000000000..ec07dec9c1 --- /dev/null +++ b/.changeset/loud-emus-look.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Remove all assets created from the server build diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index bcc7fb96d5..2988575163 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -205,7 +205,7 @@ class AstroBuilder { key: keyPromise, }; - const { internals, ssrOutputChunkNames, ssrOutputAssetNames, contentFileNames } = + const { internals, ssrOutputChunkNames, contentFileNames } = await viteBuild(opts); const hasServerIslands = this.settings.serverIslandNameMap.size > 0; @@ -214,7 +214,7 @@ class AstroBuilder { throw new AstroError(AstroErrorData.NoAdapterInstalledServerIslands); } - await staticBuild(opts, internals, ssrOutputChunkNames, ssrOutputAssetNames, contentFileNames); + await staticBuild(opts, internals, ssrOutputChunkNames, contentFileNames); // Write any additionally generated assets to disk. this.timer.assetsStart = performance.now(); diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index 242822613b..5a86992b2b 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -104,26 +104,21 @@ export async function viteBuild(opts: StaticBuildOptions) { // For static builds, the SSR output won't be needed anymore after page generation. // We keep track of the names here so we only remove these specific files when finished. const ssrOutputChunkNames: string[] = []; - const ssrOutputAssetNames: string[] = []; for (const output of ssrOutputs) { for (const chunk of output.output) { if (chunk.type === 'chunk') { ssrOutputChunkNames.push(chunk.fileName); } - if (chunk.type === 'asset') { - ssrOutputAssetNames.push(chunk.fileName); - } } } - return { internals, ssrOutputChunkNames, ssrOutputAssetNames, contentFileNames }; + return { internals, ssrOutputChunkNames, contentFileNames }; } export async function staticBuild( opts: StaticBuildOptions, internals: BuildInternals, ssrOutputChunkNames: string[], - ssrOutputAssetNames: string[], contentFileNames?: string[], ) { const { settings } = opts; @@ -136,7 +131,7 @@ export async function staticBuild( settings.timer.start('Server generate'); await generatePages(opts, internals); await cleanStaticOutput(opts, internals); - await ssrMoveAssets(opts, ssrOutputAssetNames); + await ssrMoveAssets(opts); settings.timer.end('Server generate'); } } @@ -417,21 +412,28 @@ export async function copyFiles(fromFolder: URL, toFolder: URL, includeDotfiles ); } -async function ssrMoveAssets(opts: StaticBuildOptions, ssrOutputAssetNames: string[]) { +async function ssrMoveAssets(opts: StaticBuildOptions) { opts.logger.info('build', 'Rearranging server assets...'); const serverRoot = opts.settings.buildOutput === 'static' ? opts.settings.config.build.client : opts.settings.config.build.server; const clientRoot = opts.settings.config.build.client; - if (ssrOutputAssetNames.length > 0) { + const assets = opts.settings.config.build.assets; + const serverAssets = new URL(`./${assets}/`, appendForwardSlash(serverRoot.toString())); + const clientAssets = new URL(`./${assets}/`, appendForwardSlash(clientRoot.toString())); + const files = await glob(`**/*`, { + cwd: fileURLToPath(serverAssets), + }); + + if (files.length > 0) { await Promise.all( - ssrOutputAssetNames.map(async function moveAsset(filename) { - const currentUrl = new URL(filename, appendForwardSlash(serverRoot.toString())); - const clientUrl = new URL(filename, appendForwardSlash(clientRoot.toString())); + files.map(async function moveAsset(filename) { + const currentUrl = new URL(filename, appendForwardSlash(serverAssets.toString())); + const clientUrl = new URL(filename, appendForwardSlash(clientAssets.toString())); const dir = new URL(path.parse(clientUrl.href).dir); // It can't find this file because the user defines a custom path - // that includes the folder paths in `assetFileNames` + // that includes the folder paths in `assetFileNames if (!fs.existsSync(dir)) await fs.promises.mkdir(dir, { recursive: true }); return fs.promises.rename(currentUrl, clientUrl); }), diff --git a/packages/astro/test/custom-assets-name.test.js b/packages/astro/test/custom-assets-name.test.js index 67fef15510..63cd3eb171 100644 --- a/packages/astro/test/custom-assets-name.test.js +++ b/packages/astro/test/custom-assets-name.test.js @@ -2,7 +2,7 @@ import assert from 'node:assert/strict'; import { before, describe, it } from 'node:test'; import { loadFixture } from './test-utils.js'; -describe('custom assets name function', () => { +describe('custom the assets name function', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -14,15 +14,9 @@ describe('custom assets name function', () => { await fixture.build(); }); - it('should load CSS file from custom client assets path', async () => { - const files = await fixture.readdir('/client/assets/css'); - const cssFile = files.find((file) => file === 'a.css'); - assert.ok(cssFile, 'Expected CSS file to exist at client/assets/css/a.css'); - }); - - it('should load image file from custom client assets path', async () => { - const files = await fixture.readdir('/client/imgAssets'); - const imgFile = files.find((file) => file === 'penguin1.jpg'); - assert.ok(imgFile, 'Expected image file to exist at client/imgAssets/penguin1.jpg'); + it('It cant find this file cause the node throws an error if the users custom a path that includes the folder path', async () => { + const csslength = await fixture.readFile('client/assets/css/a.css'); + /** @type {Set} */ + assert.equal(!!csslength, true); }); }); diff --git a/packages/astro/test/fixtures/custom-assets-name/astro.config.mjs b/packages/astro/test/fixtures/custom-assets-name/astro.config.mjs index 866a05044c..cfcddecc5b 100644 --- a/packages/astro/test/fixtures/custom-assets-name/astro.config.mjs +++ b/packages/astro/test/fixtures/custom-assets-name/astro.config.mjs @@ -18,14 +18,14 @@ export default defineConfig({ const { ext, dir, base } = path.parse(option.name); if (ext == ".css") return path.join(dir, "assets/css", 'a.css'); - return "imgAssets/[name].[ext]"; + return "assets/img/[name].[ext]"; } } } } }, build: { - assets: 'assetsDir' + assets: 'assets' }, output: "server", adapter: node({ diff --git a/packages/astro/test/fixtures/custom-assets-name/src/images/penguin1.jpg b/packages/astro/test/fixtures/custom-assets-name/src/images/penguin1.jpg deleted file mode 100644 index 1a8986ac50923dbb9b36ad43e1af1415928ea912..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11621 zcmZ{KWl$Vl8|(s$+rr{5%VNRZVQ~-cPVnHG;O-7V76=j?0tC0MhmVi%@00)U{U7|Z{O8U82hRfl0t~>iI<3v+1mED9%a%kB`&{sH=R@$E37SJYG`6Tz(zJ= zREDVaqSGH1sWIVGo8;a_9{RMR!xK6jjsd2Z<81p+I~G!9a02mO`dY$a8?I}e%)+1kkJk3;eh9=0-HH7!O#4j zG|s79S2CfkyG$BMf9tg_UfVYNMR(2RPrzzel!2$1@nlQkrx^-J7!j4ZrXY8X)eEhj ziwa1^@Xa?Cg-`U1Ea)!X&CI5&W@csaDk1!Bu9m?sstNjA`-l*1!HJG)@d27%{A@ZM zl1m9`W{1_Uzx<*4z{|B~0Q6MF*WxVc`+!MBTo}WuR22}Tvbt5+P`R~v6Z+AxCCJ)=}(hvfO;gfxTYUbCS{n=}c5p{Uk z>>6yn&G8vL$Cr7wl3qbnVU1cWuZn#qoLAbjn%@ssuVcz*r$FlwVuJB_IhEv`BmFvS z^b@aP{9kt$SS@&Jk^?ho-liP>;dCmlzBBtsUzjAXqk1$D(R4eF61KFGFTU-)md##%aS2{tVV* zlm2@6>d7(7DlbZcqqmS%r5qU7Ugob9$&mp6uM+<*0Z2g9e}#w)`YXhDkj^ZoK85^u z+NpG|^kYn)a-2-Pw(3ZxMRsr+*6`Lc9MU)si4J$l7MaQu!0Uo7aio&T`E!)Bs$&C2 z0{Li+n2hon`rou0Hjg;%zm^~S7_huC%J@P*TvYjG48M(j+OUD5TqRwV1QVxH`|cgtNC1@oSmJ+fK|)3W{!0+$AA*qpz?XAiK0lk4M8aSRaSN;9 zh7g@oW?H#m`M`+)MyC&2ESy|Dp>B64N5FNGE)l)FdI5xxT~n)C2WQ5}+qgl_8x%67 z7h2&0Y83f19~#G)J!_O&;JRmgA2lgY1D^qZSe$qoY8otWM~FxC z^!bCcg2qE|z1`F z=15ILO@Bm=%UgMO&&8YG{0van+n2k@5SnAZb=4Rp(cxl(Q>Cj+xQ2iy&BKzj@`+X7 zm(+;c4$;=;(EQZBQfSIVcok6TQmnp_FH3)mx(V(H-1spU)%Og*H-~w&*Y_!|ow88i zDjSAqE~Xl5fAFgNutThQzyHU@>!TL(6PTSg$~KRqXu*@bE*_6ltpD=w=b8Nz=bv33 z)u^IPUr{i5I?zyXfS+*~g=^n-u_xfal1wG+m;EjwVE#Vj{bBwS4uy~VR^s#_ktgwx zZPDgd-|^8UM1;c25r^G){6^_YD(gd}H(%ba#KrQ3A1^ciS9}LNC7fNh#}FN3rLf_p z$m>+a-%``eyx$c+$goK*-QJs*#PbxH6=py!UbM{)KG5zjh`xD}Wl4b#a zr7W8N(bDwu=GM?1{$=XPMEr$0%H7nvd@*~TqEt#6K2vPY+l^U$leABdm}UYliPuvC zA_g%NNiTYH7C#LTN|QCP@Y6DnL8}VA&56q}%+%i>n*}tBP_UfT>i=A&KS*lG1N%&QJL2+_|MpeQ9S zv&Vd8rdPulc+}GN^ggI7&`~)6>&S1sB+puaY8|)P^cg_npEu0Th7fcNfgO3ttEx1k zaqL(OY0#!5(I0*a%euS4dIA5O@UenJM z@)Tw&2IaRZY~aZhJioKsYgIh$RneL!eHeQmR8IQ({7x*1kqXdZ!vmag{K3-vL#=MAWZ|?|8+Ks6jGFC zlADPxs>u@oH&(HK+4PevehgvUFjX)aU2S}_l3b`Rf<+%x_De+yk7W~mxFo$>KtY0J zaaatCF^{aZs-Eu+aJM0g`j|n{vW~F}#t3<_-pbNbX<44FMaKHu093MP*LEtmv4GK6 z!%wtaQfY-@N@St?6*QssdVK6^wP=e94Cjn|n4_*R&F6C{M_N^HCx3a!kXsy=`Bqws zI&Rd7EWXBwu)wFfk|jfyU{N?eHJSxGzGy;-F$ok;9F7IlQ((77)e>lF!fN>zc{s(w zi*u!UIj7U$SFF^7A&sMw1;4-`AW3}X`PONg89699K}k%#<=$=YFt^#=n3h)dFvl%q zMTmbCqfl2CIkcD9%>?X$AwNc;;$-L83*nAs1Fq)uStsqLHPq&*mBwMYCOa-?Zo}QU zi7=Zhy7TRSqMx}_V|92K8Y%h;JbeCTI;z#u5wZKdY9>!9$UnFNF+R*yE-R8@_7xe2{4zYvj z!jYy91f&C;rP9@TIm`~@0&NXK4jsTX<0TFn+!E5r1tIEKq2{BFJP+6@*o>R)@9}`u zIoVNrSfu;u9;nM+ok#tgDJxWSGo*&>`T*8bBK>d3ds)DeAK>VJ_1e0 z#DflgvR_CI;6Lli3+4`S)H1MWc#)xgc7%neuHl2pu@N>3VP=zw?z$`h?|$C zA{eda=;w~}CRg+7b4b+emEw9tWN^K#EnG|7%+K-fOS6FK0-+JjkIK#6s};>`$l>Y5Kr1Vw>nUG}+5n++&o0%?HWHz{p=L>+&Kc)9*8sXun@BGcy#HGt#K_t zh3%-S0C;G{b>7CL*80bLpvkI-IB0tOz1l=J>2J8^+S&C?{8G%tUF7QO%A!%P2vjsX zUkn`es)9+h%}pad_pz9N1M@aj&91UgsT2D(-b=V#5|eL*J_Vj$j}(bckY1_N>@Bmo zo5F$8Q?7ddH+udpG2Q7+oB^~0g0AaQ1qIHMPbD_NMcIhB=_wc@amf3DSx^;jW{ew) zkwyiMBT=}k$nz?&S{2=w&;lUi6CH?QC>~{6Q%SWfY&Y9Qvql+2&#e@B4d1AKBN#%0>~~3D0Mb2byR=vBIKgtTwkzhkdB+m z?<$bX(Z&A7y{CF?HCVJ}Qg5i4;3FnagZ zua2W+#c|^9kRi9-LPB3|A z48xVyS#{_6@uxy5hLSC0A?X<~5%i+hxBnxV{Pd$DsSOH#r-M&4rO>nB;pl*7Yo6yyzcQ7%(qh%cs$oC}HKc?05V#B~ zQL^v9g!MjTbn|rIW2DV#XRREDk*nA)0R6DDIo*@O!7h_#&hgFTA8E7M)7t=vGUZlg zA>YJ0@n$FZ(7wRk)E)VpZwWMFMTYBy0JaP`7~<&Fc{J)D#j{fe&5p|STBDC-yBAhI z02kgs6Q!k1NgV6zO0#L=M{N_!i@dk#nyFWNl}4HsY&ikI?j-b5G4WjkBJy!!F93hA^Uw5ur? zD64S8uJT*3HtD+dSMz$P=HGwWp`^KoiWptE0vd1nnaV_ zX7+!=E##YDJc`^Bw-f0<$? zH6KN9UU=*T!(kG>g*UkS&SFb_!#V_U(Km|B3oalp`W3 z?~$11Mm-^MUk&_Aj_^d^?%L?Cgd5vT$7Apk?qfDmuFTw(Rnz8TEX(16 zQXNXM|87S2T3rY<9XY=Fis~$QcWb2!r){_S7VUeZBMvpA%r-i8f^oRg)Wp}E=#>r2 zX8`65_x75ULC?|qN#pP5ewU&26^iIM9qXYaaAcofKnn|4a@McJoQ`7g_Kv|^jo0TK zZu68^IvalJ$R%@heTja|{JJ?3^SZBBs)S-AsLnMUYEIASd^9*h_q%*VF>W*%pm>O9 zzz?m{b|d$}bDmxJ#=L{P=MRlAg3gO3Naq}x)|Zk@cSa-?FJsuYvFYhr?0&bp?<6#~ zAPq2_Z|(E0h=82S#pC$}W@(s&sx@3QbHyQnr-;^kLjAMdv` zjrIlBH$N`a4Y6Yb)2_6T)j)(hBk=Va$whxJU}+L91&PUn9GVbAyQ0M&;(DoS8aH#s zuBCPjG9~^M&PR;T00(WEuL4~WJyzJO1NIE8ruK^y5BQuX1-7!%}8B z%}vJ>3H{7BITLAIc$v2b6#GS+KfByI0R9YM?L@fjyX^c{_p(Hbk>_4-PKxdqtFDt( zmG%WU3U5fSOGMd5hf@m8uAwT?DfE?uOaF=VQTWwTb_NwZ?Kfulk~4D-i|a-5RpLKR z5VM^RGcF_4;A2~uS(d16as=l61%uFm}4t+&1sFGqvp-^N~{6Lc2D)n_v*PBswF>(Glqp@ z-vX_4@f|->*Hf@)UE=v)k# zBSPpKnyykIDkabLKh`&MQ28Re-PJ9UvIXLjrsolpSQkxjI5a6ek$eQlXTBy@9tnm@ z?6w4*X#@8TYsSewue04x(E~=X|0V?}=x;Lk7yl&vf0F_MJ>YLn_%|gqg8DD#wyyqf z*p~vOHr~deC6dJ@A7GqGdg%A$W$j6 zBHRQU4cb4&;Bsl#VSBjHsHVVIBMFk6s0AzkK$nqi_=moQyrkZ^x7jfb65UzyDI z`{}Bn_FR}JKbbDi*YFcV3`MNZ-Jx7r)~TR{5p7ndycl*CT=v>++Z3>a9UrNMO@*{(c~_i`*f4CdhgVJ6q*5{>aBiCp|>wJ*kQteyOA~?jrnJE zO$-LMGawi2U#hEj0E&PVeW)po_pF12X zijm!!;nDHn`-%DFB2Bd6QvNE#S=l0m?&-kCt>sV62#J~<3_r=X@HL4U zjPw+En%glPm8!BK2s$n-(ka>7ItMx6nE&EC_Iz|ufD2!l7(fw?%)w2bW<7%wF0_d|F#-p z85^)shaf{o3zOI35UzVMyr)9E83=O>3M`%Il^ltW*xeAJGeS4j3r__jVmfe}hwk&V zt%#Msow@sLc=0valX{~Rj8~hcs-ZdTe*8V%x!6!t{rI2;xcA9(m$}w9(a-j?ala+g z?!lU{DgPU;bz7M9>}>nG-5tZU)=ijN|C|Lp>Zhz(y;`_?Qd!#nxxw2#O^tO*=0#F5RV_~S5jT(=a6KMCMLEEW$$085buKBi4 zm+jKmw82;W=&1oRp+MFClo??CQh$F~TZeSapY*s$yD2v(>h$K}j0qg;}CuBp2ouwPsxhKW@;xFW03t9Pt;i4hk4Q%_$L9tn>OkzOtMki3uf8p?pcRtCq9E zEgNzJX(-H{W`Q#52W?~7gmWDr<&r*akVVF)eK&SP)sY>$po==33Be^pT_?FGsD%^Z z!Fpzp9Z{3mywebBE(6NCmwp>)c9+0uFS~T^M5Hv>cYy%W*mN0^FMsYm6X8W$&CWNG zQg%cKwS$bMBTbgXUyDc|?aEWuP7^yJolW*j!fB}(xdwyx<3~tl15auqGEkS#I&sMP z%>*}*mQCX+;+v=HxD%iK9(N~+Dw!mGG8zuCS2ZvEEA25=?uQR)7zbtqUVnOu0S(K> zKwQ9cS$JVo0Bu3#wq5!BZ^StQrLIf9g7xG z$$d-1yIX2aix%Q<%y?u_=0*ZI&3cHw##NsCwDYkxGBSqS?c4SlEh-JuJ7`+}7n94V z1BdK>dVbu`7U+S6CL!zzG%t+$=O;hR-;#wc>gwQ7OXy$+ zSXGKQ)|y<@Ee8xU$n@hsSXVLZR$i5BOs?Z2c!wd1>=&_PH&}Dbzib1!1DK99cnQ1% z#ZaRgy|Jw6@NH_v7E~L9qEC#lOuJ#!sqgad1_->#B<1OE zqvU)uGKLgq=w#P<@WCEW?o6o8x#7$`$t?KjC+NSqHhF1yQ5a&X*Qaw$LDeKz-};Sd zhqtgop}7)G(Tc8dP|bE9NoEi}NeQz(T-5R%QDKuy6I$%r6auhxCNVxEUAd(cXqm1$ z4f#zj5Xo7f-|JK0;3afF!QzLK zNL2y?En`bq6u6P=jcnd+?ywRQ$VDnwJp1p?VNi#=l!4`=?}m#{G=XXv~%kArha5@fE@}6zxN}cYD1J^kP?mdb~v7 zfbN6R_2to$Fh9VBiPy>a`vrQO5U;My1G+3Or@OlN+*U1JqBQ&bN}e$O zG=_-IrmHvzR)P5E-+eDtzfuQZqaM^3Af7HmYdQK4hJwAk!}S!mc|khLkXB!s&PPiO zBJMv%M#B|avG)$SA{$4(0cLkndx1{fG{@YL5mLjqsu_#|_aZSS}jjSh)Yq`+tg6Il( zbESVm04u^U9|A%a`5H2p8qNw2M^t>eFers(`0j%(I_@u;uR zv@ZJQz|%EgtS?+cF3|bG20M{gI;FC2W+bd?Z>Q_8{D;ozF_bR?Kr7{g?K)($TeCrb zW#Gc%s!zUhlP`y>R@!HA*6)~lPfn=f>SIWjZpqcn6!t*0H@G2FrYnp@7Njq18IeA8 zS@j(bXvPdcY4WEW`2t#H(5Bai{EU_f1UFOxb++xH$D$Y>GH~9E(A4^0381cVWz^p9 z33Zmyc7&5mwIKa=_?$7F<@K0FT>qvz1}o_}8V@u75MyOT=i_GB2AKkA>|)P=##5SC zI{oyx_Jk4806FrF8CC$vfjJ9dfLP{?k0L$6nO~!_#ePq#BNG*Rht+=%s&r<0;hquL zXv}LE$tHNr$pzn?Hfwr(2GDa|9^$|OYn08*2<(@>s;`AiYI(SMc{uBp&%PVsxu6zH zLZ!%F1Eed~g|r@bAsh7EE!yNGw~&{7>#365dg{pVEJ5bCiSfo%sLb)S55p6>aWZc+ z<984WM69vQp+-mDqL_tsv}ml-F+NVGX+gV)Ds7OY&C&_6vaX@c)Sdq*VS|#AfX}3T zx4#~!AjMbr>&OWxj!;l^FWK4LlNH5NB|z`dCaoCD+dIR;BMk$m#Kj`TjwK{%IDBOi#9g}M1*bPkil1_F%{H{A+Ivfvy z@q5@3RXuN?$z!gzqRjr1iR1!H78R%#$n?}0X*uNRzin`_VGu@w#8OA_r@J*Wfi=nB zg3OSY3>o_b(vUvYc3--K(T@M-{&bAcVQiffH3CU?X#=K&%m&3i%m{qq zD#QqaVu>!D5T5pQ%@4~JqJRdhYnY!hlmNHI6K>K8-SF_#HMdABmD{qpLm7f;={O90 z(j7E*`z4fbuC6kFQrJemJ-QgrLlK45ydH^mM^D$Z8Fs^)2B?MgEOhN$Fi)s55RSee z{46}cAj(9+D#Nq;)!5b*TXqB+_l!~wXSvgIygEyv%>#)xQG8lrb)6My?z7pew8+dv zTH9k`c;@uJbmj_PXCgg%Lx_W?PpB-Rd=+LxofS^lB(XRSwfx(DBWcx0zVq{DxaDFT zX#8pC&)^nF{oWds={!0_QHH9M#v^ec{(FkoJr5Zp;%(>>GoAd)(5!!A-s) z`<{BfmwPuXP;sbf(#(>6ZyvfW|CCdy4AZS8U?Cpndb9hbp97jC>m^~Xo|-$<8Y?&G zH&4yR=%P?o8CstR7)L5oH8?sknNXY86^@C8gRO{Po}qPX{!E7Iy#UsUQwLwYfD#gg z@qZFvzO>qG%~5=jLOD-QMx>sr^GE*~a6`-jRMATv43?S?O-Dins;*NEnNTp;-KUuB z#E!{>=$kOw&7+wC$nRq(Zr^WE565D&xxU<7BaTJ9=V2^Pt#xoN*t1f{rP<3tkVTCR z9YR7ianm1jexyP!i5%3s!|_CIwV8<_^dM8}hf3y7y?`R@a#=tE5k4_xAv2ay8KMDCJW}yJ2KnMuJUuv;6!?YEv2@`@b4D20J$*fUK_vYyaO-5MKm-} zgVp=B1HJJxK*DxT{XI|M=Os8HYVB#4W%T2A|5O3#B#6}SDr@^?U-K2;?{Q=$x?Ns6 z%%tmA+9Qj|-N5P13B0c?iY9TlU0!l8nVN(%Nf+=V^w$ z{+nNQ*06P6Lq?fK=m`~m{D50+Hz32Z%X+PF2%!Y>f;d_HX$R@AdK>9pcxT?t`g_)W zrHtbWx2~2|*V0yW46Cy_0+(lL$t$EFk;!IVCPX06Bs- zG}|-#{xb9D6|^|YfO}OUo&yGzvUUq^mA$t^NMXu^zUelzMON&6GPr8VOH+?qddNy) zgqLUvA7ZHDi%m-Lx4=WiA6`X*ZiGO*{hOQuS#)v@Izt@yA%aQDWP_g8vL{FsML)ypY2|ZuijX24GM<1?Ww(1HHwF z3^Ep!N%y@JIEqN71Ew=ZBi??BKyn%xlG9KVfl-N}JlKT#SX1#+i@faS&0B~xKrTjz zhv-juHTkz1eN*DqJ+%#73EY)V{~@Eyf*~>XZF4M(kd4+evag&3O&+okTPQrn%MT+K z^b-H(Govh*349${XJVRHoESztY%?HT9$*TEu)1jL&Pz$EJClvLCX-tdoh`I&VEs5+ zJBMc~3Gv9?g5OPYBJLo&tuCB^6o>Dey43z;hF0lp0Xq=sjP#ugVR zFvBR ztxbW|8h?qB{v(0nCu>UcunOCCBY2;eZJDm(y9)sUBn|ZnqSy^zP7UK2aE02vtxb@| zT`&BgvqH657G}%K0sbAdBP_}!$vPVL3^1jNS%_;o1!Ku3j+NM0i9;u$9iw?rU)4VJ z^tyxt%*goKrsi5IPgppMRiOR-Xc*M8Q+Vf!ToRVrSXl!WSQ7EDWCS$67pD%icX6C! z=4JaK>6P6OpF!LwL00T&R>xti>OT+~JHfPHh{ZCpOjo9yzw6gBuJn}dJxB3}yPF3sn{+eqBP0rPHp8SBH+NRkZtNg2@rM%+ z$`m8MN&>$96libLAM}q86On;CVj*N@($O_n2M`R7TnUy61OQP8$=y@AbF#;JDdZgT zeFSK#A92J|iBNMCB-ZS|L#TvxV?)zPc8wSVJ~Bp2$c@I-#u3!WVJqb)U*V}Dn~qfb z-FW3q{La6txl2rMQnF6;Uz7_DvK{|~BZC3q{z>DE_3pj)saOjyWK!V8m1MF=qHEY`j3m_JD+;T)t`82Bi^sH2c0;0c%aZ1{#RuGM4`J8f< zhP6?z<8ltV3uSOiI4M5{$ed6C^|?QdP|&=VH0mabOq{;}@@UkAjj++(u+PJLCqBf7 zxSAUIzCIe$ZRDeY3ye%y=$QrDoy-L7VE)t4n6p%{aVq4@P{%y&QIxxov zOrA|tMefVY%T4&F%fwCace?nuihzm^{BQja2^m0u0;K05WZ;$2@&FN8{VgN(gXtRQ zP+{8t88jjzAxQzyXAB?9JvdF<)zCzY&tx)aiIG-OI8FH+FAJRDIjglk5?6NOTc;!1 zerOzsZ82}`eQKMKsoPN+WShnGZ!aX%s&v!+6Y4oJWo^E`U+4}z)pQtG+>v@&XsLMA zf`)5;Kl@f|YW2DUjoz5Wn;B5Hav;l8QAe>_){;x9pB5m`Xv?wm460o*l}j_JJDLEe5L5NvDW`S z!q7x$c!mTq&cBmhTfCr2-h7Rxk+!l*3h-eSy4n!@5WlqTFx?2Hb+yOp18Q>T=djXslh5F*R{LT)@ zQJtS26fGEeIL@8ex-w)_5?wU97KW+@vG}yYa#m?G=dD>Hc{bR-piHh+>kG&Z;JtUX z9;#b~Os&GEoq`+rGdU8;b6iTS1C!q7x0QcH&~UR1aK#>1*nQvP^VPIJq7~A^9h%P{VQ3InJNVmxd#PNt^_kdEJDGD3$K=LzLUopt9yQ57Ts&0#GgJRp^uWJU_5W2~k&p>^ zPzdQ|Kw4lrpa%oYs`x*3zJH|dJU6>Yegy-KReYKM#Z%2vOqDrIa>*fNKQs=DJPg=W z87}K7B9tT(aGd|UUnaLm&8u~4WlDzEs_4kNu1VK{<|%QFM+P=KIO|umTLFt->|W~=cOf4DJ2i|HvaPjULP zMeX;JbxfmU+4L)|KQNAB`5#ee-M^WYGeMKq zJULXEMZCw3n;SIV=6t*6qVOy(@p2BQXs#+gc_TZYV!MM;!%)nrB`g_P^fj4V*~`|( z8Eutn_ghh;V1vBSSjl6C9(^@qhS%Z7D6_(z>F@Q!^#@jg2(MpUL|!pl{KjXbgwVO+ zG98=dcKJr5!1&W*F4i9=zeH4 @@ -9,7 +8,6 @@ import p1Url from '../images/penguin1.jpg';

{title}

-