From eebe18deac115529730ddf640637cc808f08c597 Mon Sep 17 00:00:00 2001 From: Alexis Jeandet Date: Fri, 12 Jan 2024 11:52:59 +0100 Subject: [PATCH] Reworked home page and added server statistics api resource Signed-off-by: Alexis Jeandet --- speasy_proxy/api/v1/__init__.py | 1 + speasy_proxy/api/v1/get_statistics.py | 13 ++ speasy_proxy/backend/__init__.py | 32 ++++ speasy_proxy/frontend/home.py | 36 +--- speasy_proxy/static/index.html | 65 +++++++ speasy_proxy/static/logo_CDPP.jpg | Bin 0 -> 31550 bytes speasy_proxy/static/logo_speasy.svg | 264 ++++++++++++++++++++++++++ speasy_proxy/static/status.js | 19 ++ speasy_proxy/static/theme.css | 145 +------------- speasy_proxy/templates/welcome.html | 22 --- 10 files changed, 403 insertions(+), 194 deletions(-) create mode 100644 speasy_proxy/api/v1/get_statistics.py create mode 100644 speasy_proxy/static/index.html create mode 100644 speasy_proxy/static/logo_CDPP.jpg create mode 100644 speasy_proxy/static/logo_speasy.svg create mode 100644 speasy_proxy/static/status.js delete mode 100644 speasy_proxy/templates/welcome.html diff --git a/speasy_proxy/api/v1/__init__.py b/speasy_proxy/api/v1/__init__.py index c6c9637..01c9e25 100644 --- a/speasy_proxy/api/v1/__init__.py +++ b/speasy_proxy/api/v1/__init__.py @@ -4,4 +4,5 @@ from .get_inventory import * from .get_speasy_version import * from .get_version import * +from .get_statistics import * from .routes import router as api_router \ No newline at end of file diff --git a/speasy_proxy/api/v1/get_statistics.py b/speasy_proxy/api/v1/get_statistics.py new file mode 100644 index 0000000..b297fd3 --- /dev/null +++ b/speasy_proxy/api/v1/get_statistics.py @@ -0,0 +1,13 @@ +from fastapi.responses import JSONResponse +from .routes import router +from fastapi.encoders import jsonable_encoder +import logging +from speasy_proxy.backend import statistics + +log = logging.getLogger(__name__) + + +@router.get('/get_statistics', description='Get cache statistics', response_class=JSONResponse) +async def get_statistics(): + log.debug(f'Client asking for statistics') + return JSONResponse(content=jsonable_encoder(statistics())) diff --git a/speasy_proxy/backend/__init__.py b/speasy_proxy/backend/__init__.py index e69de29..b8b9b59 100644 --- a/speasy_proxy/backend/__init__.py +++ b/speasy_proxy/backend/__init__.py @@ -0,0 +1,32 @@ +from speasy.core.cache import _cache +from speasy_proxy.index import up_since +from speasy_proxy import __version__ +from speasy_proxy.backend.inventory_updater import ensure_update_inventory, last_update +from datetime import datetime, UTC +import speasy as spz + + +def statistics(): + """Return statistics about the backend.""" + _up_since = up_since.value() + up_time = datetime.now(UTC) - _up_since + + with _cache.transact(): + cache_stats = _cache.stats() + cache_len = len(_cache) + cache_disk = _cache.disk_size() + return { + 'entries': cache_len, + 'cache_disk_size': cache_disk, + 'up_since': _up_since.isoformat(), + 'up_duration': up_time.total_seconds(), + 'cache_hits': cache_stats['hit'], + 'cache_misses': cache_stats['misses'], + 'inventory_update': last_update.value().isoformat(), + 'inventory_size': str( + sum(map(lambda p: len(p.parameters), + set(spz.inventories.flat_inventories.__dict__.values())))), + 'docs': 'https://speasyproxy.readthedocs.io/en/latest/', + 'speasy_version': spz.__version__, + 'version': __version__ + } diff --git a/speasy_proxy/frontend/home.py b/speasy_proxy/frontend/home.py index 321f269..bebdbc3 100644 --- a/speasy_proxy/frontend/home.py +++ b/speasy_proxy/frontend/home.py @@ -16,42 +16,10 @@ log = logging.getLogger(__name__) -_inventory_refresh_thread = None - - -def _refresh_inventory(): - global _inventory_refresh_thread - if _inventory_refresh_thread is None or not _inventory_refresh_thread.is_alive(): - _inventory_refresh_thread = Thread(target=ensure_update_inventory) - _inventory_refresh_thread.start() - - -templates = Jinja2Templates(directory=f"{os.path.dirname(os.path.abspath(__file__))}/../templates") +index_html = open(f'{os.path.dirname(os.path.abspath(__file__))}/../static/index.html').read() @router.get('/', response_class=HTMLResponse) def home(request: Request, user_agent: Annotated[str | None, Header()] = None): log.debug(f'Client asking for home page from {user_agent}') - _up_since = up_since.value() - up_time = datetime.now(UTC) - _up_since - - with _cache.transact(): - cache_stats = _cache.stats() - cache_len = len(_cache) - cache_disk = _cache.disk_size() - _refresh_inventory() - return templates.TemplateResponse("welcome.html", - {"request": request, - 'entries': cache_len, - 'cache_disk_size': filesize.naturalsize( - cache_disk), - 'up_date': time.naturaldate(_up_since), - 'up_duration': time.naturaldelta(up_time), - 'cache_hits': str(cache_stats['hit']), - 'cache_misses': str(cache_stats['misses']), - 'inventory_update': str(last_update.value().isoformat()), - 'inventory_size': str( - sum(map(lambda p: len(p.parameters), - set(inventories.flat_inventories.__dict__.values())))), - 'docs': urljoin(str(request.base_url), "docs"), - }) + return HTMLResponse(content=index_html, status_code=200) diff --git a/speasy_proxy/static/index.html b/speasy_proxy/static/index.html new file mode 100644 index 0000000..09e1b69 --- /dev/null +++ b/speasy_proxy/static/index.html @@ -0,0 +1,65 @@ + + + + + Speasy Cache Server + + + + + + + + +
+
+ +
+

Speasy Cache Server

+
+
+
+ +
+
+

This the shared cache server for the Speasy project. It allows to share Speasy requests results between + users across the world. +

+

You can access and experiment with the API here.

+

The source code is available on GitHub. +

+
+ +
+

Cache Status

+
+
    +
  • Last updated: 2024-01-11 18:31 CET
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • +
+
+
+
+ +
+ Speasy logo + Speasy logo +
+
+ Copyright © 2024 Laboratory of Plasma Physics +
+ + diff --git a/speasy_proxy/static/logo_CDPP.jpg b/speasy_proxy/static/logo_CDPP.jpg new file mode 100644 index 0000000000000000000000000000000000000000..abd0ae512c03ac7680ce08ade263d8d691241127 GIT binary patch literal 31550 zcmeFZcRZY3w=g_HbS8r6Mvx$)_d3y|CwiZVPW0Ypf*=GFBqWlM5D|ol-i=-&qLUDv z=**~tnek0>x96Pqe$I2wdB5NH&-YwhX3xIXUVF8@_S$Rj%h}hnIlu)SO>Ip85fK1D zMEC)m%>&+Rgt$2a0NUEu0OSAwfD~|%i1_EDUpFh!`Cp%Agzs#>m+c5;{@-EF5z1mj z=KvQ7p9CZTw|J6Y@Ii#~&+9&x5^#a{w8G*_!GHLpx?b;6gxVIINfvdbn*)DC%}sRl*AvD=z_~lg8%~D zoc{^v&nJI^`pB#KIoStz`~@dvz~4wql}lSgO)7yHv$R%gmI+AEhQ$&&GpwK%YS$z zEx?&%yhb)c>Gdg&;kD zf|2<_O;T1&R7zZ0LPAzlTwFs+U0Oq3L+)={NU6z6$f(N^G$X5_ zE}<$VrKuq+qpl$(Eu|r$srfg3sEMn~N=Zpct4K*`Y7ijgWF@3kBsEpl2z_cwXiEN{ zef;Jo9lae0D*j6Z(sB|GPWJX|0k}W zX7Z+<5Qj+3w;<8dIl9E#Y(C07B{H9EizgYe| ztrL(FM$%2UpH>k1yC#jDeE-xb*DtpyZ}0G%9Xb4TDo&2vzgN5c%?SM0qv$u3!LCjO z!~Da~h{~FX$;gYz%8N<=;b(pW^Y?ZR2)6fgQgI`ghb0uJ&FoPJ}o>g!})3 z51D`E|Nf4Tzwz?_3+ew4_;B#{3Uc!M2TSs?_p>L2F;0H|O5DzV-kx0cK0f!{9Dcbk zksvR}-y^9%jhQRJo9iEDgnue9M<+kGe^C8DcJn6o!&_^&PPU(QhfUu)=>xA<+) zi~MJQ@Y{Fw-=wJdQ!&2+9r?c-`5ONX+ap9h@&s4>znFV}>(~4LX72rICBK;chY)#Uiw*>wzfqzTj-xBz@1pfagfxi-UPF{qlJeZJ%JKF-N-}*C& zA|WgakX6;zCn5Qj`{QFLvH}pZUD0AEqy^6@zGpwD0wDh*k;r~d6F~ZVGVyE*pavj5 zckbse;UXdYo+m$lo`mE)B^enhIW;9UH5DZl6%Fmh3pBKJv{Y0VE?uCbXJBMxqy{oE zUt(as$iT?(6A2M9p$*A-iu30w7-*bW?)=5eVk)Hcx9!Qe zeHp}~Qs0pCsFt-d8V#X%CGPq~Q&3)FVrF5za+Qx?;F_eAw2Z8ryqda(rq)eu9b*$y zGjj_|D+fm>XBSsDcmIIEpx}_uu$Tw2aq$lm64TP3Jk7{__B<;$?`{6Og7<|*^xWc6jOOi-BfN38K;GFfX_IK(5Xsxcis_pIUE(j66C1=|-5h!J zWIAo#`y#(kXGH&^;Z#Mdyr80$P)gncMW%wI=_Qm5mI8k-d=mjegRl%_T}=1R0N>`sI+|zAd?&G;j3R)1{9fe31+#_6rhM z0~P$-{b~IAmda|Gh5C&%Kyy^l_!*!E)LCpvtX$>dM`oI7@R0Zn5OLq50cY859fCUp zpnzbUZ{Lfm{3DS)ut81Itq*MZ&=3p^Pbs#jKxVj=L%YWMGP1Mg`Mo7rQ(ZTKma#c7 zhF_$8madnvx#9d7Ahy6qM%ORe<4&YZK|kinxyF-YVfnaHCOfO_YPN@dSlvn&mz4r6 z@w#!hyMh@wUePiyq`?4wYe>pk->OSx*Tzz>ylZCaNotN)RVjNAg0XR-n|2Voba)YU_pVdVO-~3)h@5kGc$AklEey zp&|*$d$SKXnS!+&?Y$$f?b}MT2&+YMFcjdGtc~87)u0w;b6u|3m{Ni|vg}GY#|`+W z6OXlw&j8WMSh=dmjC%8jA_HJ~>yAff0Jsit&7$NCa9#ja%d0idVVhazmP>Y=wSUPt zB@+_Y#}!bA=q&mKNM3AdiX=9VI_i z-LP^6hYUEfi{MU!!1?r_d}M5dzPrMb7pz2cH!vmlF?))D>p$4^Kic>Ir0h_u=h6hYEX!pEO2pc~4H4AI zG#alW57>~6@4vnY;QL5i46?TYbs;B-)iGN3OLa^qOT8~5m8Dw`U3j(;8*30!tQIDH z0hEx{?#_B}Y9oU!k0t&31~jd)N`^Fs7(R8BssPTI9Jw8>DRr=5<4Pg^@gA+mWs#`FeaVS0AXw-!|RNy*Kw|rDnjids3rV>CDtT zBw5PTtOAwM5L7bsX2kgpjH61|6l1(-d&PDqf~Rzn8@H0F|J($s;PGOE!P_ekW)h}L zV>huBwC}x8u~kmT`Aho`J^OwpzJH&0@Qi*AyWJifu%g?O&?D9MT5 zqZLNisEeAi(l>0knx07ydg~PeT7K-3_vTaWp`!WsSpazMwUuGwmFgj7ZY|Q7B4s+M z5X~t$L(jRiyGnA)p-TuB>_NnxrPDF9-hl#}u!%=0eWIAJr|8Ot1AHSqzt7*s;2fkO zvtdl>`Dxkt(O|mbPOdbWTc6fdjDV^@U*qjB;S=Ug?s#jLRfW zHT?xkI84P@=(4=;?%qrMs}S!FEAPb0a3$-TP4Txz5O*zK*G84632cMkuLG^H?VwDv z7Q>9N&doDGX~D*~AQxS+f_@s_8r$R|0iyo%_c!e9H>n*eeJBnY$kM;bX!;i=N#Wu?>OEKN)tLv{1ImzAX4Cp#gNo z@TBSt;F{cBJ%ht2(nQ=l77&teez+%Ad&11@ZyL65YkAP!1)F@-0wH-55;$$RW!2T+ zoA>pub;kau6>?xP-7HIIgf3bQPszAA%dB|V%oIJ_#_E5LBy}OYk@G=MJ0oFV823LW-6>&o zSSpaypKeHh!<_-mDv;}c@z zB2IC!9TUHvEcSCDawlhigJh4@`XBkPZ63W6xz#XI%JjB6z0v?YryFB|7WUHuM-}^` zz|wIRbRf|xfBkMJ_8UuT*Ax+{&+k2vGTgezzCT8w3yJ6uO!24?{(`J3PV++TF=QCh&rQ+o>8=>3bU)^SV zSMfL`&z7i-ul}U$r=UG6JP2htJg7!XbD7=z%Ph?qz|)WvQ`zZR%G=D0^dUM`*%L}Q zd>n8Fh`I*%w>twk6k4yF_4>O>2Ak~)FJ+O^eo!Jbj_~3mgHQ-t4f^66a^Bq8V;5Ft z$G9ijy+D}O1!X*A7afq?+_NcoC&Y03#`*v8ZOqZOnDpa5>9I!#%oRL&Zekw#^2964 zp&re<_H2=tv6?Keb~`+FC+Vf{tDO`GQwjbO#;4Ny>Ue3ZuAs}RHT+e)ZE;R_L8&s) zM3qOAw^7}w_ligHMyA`5@K2cbL|6qk%0laO zq5*Gm1~7Bk2rJpHDzt^ne%B5RSI9_n16}Vp=>3rJu+I}@Xk%JO>K}EVj8945B$eV= z(_ow24o0gmu_3^(+2;sT?lLM?=$$TqF_-gXDSPZ2Rtj@vVc-!{xTKKSs&LF)Pha`@9I30gl!lhs)M6dXKG+c<%Ep!Uf==#WY>-g5)FR}~^ z^S-Te`wR`ZWS{Q`q2>;0==ioB%8=c$c{Evk<(8!lU43|zPhbzKk<`CY^r^e7vKBT_3c3@T9@}o* zZfvq9$P2Yk>@evV4ZPM+ZOBX=iMtk3x3&=-=CHA5>)q!4fRi87zo0(UC|1DMi+=9q z_^I_?UDq*)nK*7S&BuoZnu;aIB{Z_2GMEE7teCN;3mWZ_rH9vBi5=dGvAM#b&_|=B&;SCZW$orbnypO|@th zMa#$@nQ}M3LYZUfRonO%GdnqjvfM&uz2Dv_dw zGXX3)iDJIIg78MZi-$;HFW^u03xZ^Y>vXd9TkGC)N-A-Jdq*&PlOHXOZt`@~$A zX)_g-LNeJ*Hd2NkN`?QhYKkaN*^e6C|IwJ>P-YYyc;%>KGQ~P3y3$Q+TPtN6+5;v> zFnM6E^^)Pl(<}yllnQ2yodNFT#9BRuRam-P-S&zb#!Y#Te4d49JQv$A=$Cb7e(%9r ze)^66(?==Er_8t>OhpF_Wk7ZD!z3`t>n^yRGta#owzz5zI_eK)N<0JD6DGfA<`k`p z@(MJAKswT(wtcat_v%QFeHKoHM{@Q$rzqf%aeZikI#49hW~LbXA>>&$W1k0B%ol2i z-G<6~%rJ~MUJ39FY`V6mUCZIn7?lTpzk(`qYZ*Z3p&@1UrLp#nJ@l5n0*)-XqSxsx#9 zD4{;b>3YbT9aDILt(%OW)$Ek6gFoFQ>ie7I(Gx~laDHS86I*;|@laOgyE8!0%8JEi z17lRCF!u|1=`3Fb^Q*8No1p%nW+F`4LQY&Jw>NM@;#-%&O7)jj-ZMa$^rsvIY3*C% z)NY8cQA&3FaD)5p0z1X07v1*5vNaSnY$Qild%JXtf?TG~090VlEkVmP1u%;h%)#cR z$W%#GxbsFIu<;eLQBFy0VE9D2$sX}lEBxJzTBIBQCw;F4b^8Ox@c8E|r6>1N>>3{Q{3jJIE?<*SN#dTN5z zmjCjx`BM1{9BuD|ObuG~^dRHSyqZGgr|VA7Se%)k4Ox55I!4UEUZ`Dd8MuHK%5A8r z>8o4Fp~L#a(Da?b_5FMH`Nx+ZvOnYo1v0Irr+-hk(P-I}1q75>){?kznVEhGhnk+2 zu-MECVYPx?6?!9TWYJdXdCpMjhSF437(C4364ho0?f-M@XXOA zbfwE?ppEZ|`HG^(D><2%_9mu|iDkUYRwGl}nyOrexJ+}|Bkb%do#rj}m+3S4xmll? zSP%oiDbkAb>yc|zqfF+Hzgai#^^~cxX1e&DyDy&>P6T1aM&L>iQf!Y(s9I%c+??yQ z0|N;(@gbi0?;`BNvcGafUMIDMh!tiJ9N#)$W8>ElhiIlz?T14-< zr!T>sko{+Xrzr&gR0-+m57MR?NRi5?8S^aFug_^ydJQ%GB+~@}S<8lCy%!_{<*23H zcERYA_WE^?YbyZy*^k>EUoG?$&9C1nS%r%;f7jOvHAz24?kTyn=TsYZ4p8W@iZBhl zSIv7Ccr$I@BJ5&c1DYo5AbeoTxb+OcfxRpf(=3AVKfS`&`p9mm{bqFq_123|asgB6 zkMny;qD4cGkLHG=nKP*GEU9>&mxQPK7F3<;Kr?(0UQ24&Je^PVR;5F1K!6o zw4VP_;KuZ*QT4Ti-TG}oHI|Lj_XegnWVv3}aA-utxhWzk@oXm6eybA*Ed4%vZnndt zT#9fkXOWc`%|F^4YX#1Qf9m)MWaeVJg%$Cz1cK*)a7Z0oa5!2Jk@@*DnFXk zR0$orN9c_%nvY6>fom+pV!giC%Ymm0N=OVEF$m&_a7M|r)dpcQJIq)eqr|KGuO5F5 zSFdw8Hjl+T!c+3iaY#GEb%qYM?j+$4?xc`UjqFtK^lSLEi}#D^d<_c=u36t#qFAoe zq&Ndqj!h7jm>PxiX=i{|kqEbo88zs4$v+m82R}a}tRIN7en{Kp;J+{=y=Msg(YQE zq&j(|7Fb}jY(H-$H4a`CUjh&(J>`Jw)Vl0t9h#c+Hf$91B%t=~MLaZZ(6;i(>~2!9 z2QVt9d?n7jEt{k!vtvTkS77AaR_%*7p`~m@y$3fwkr7S{+g)Dt#t6VWJcBInq7F0P zV(!lJ3WhrG2A(v`1951GY{V^$@j^~aGhez2TJyQ^^N_}lm6gPRFT@>-ab#0Dw`lyh z(pr3omH_^k2}Jy-k7-qwP;@iG8XuqeuwTpvH>%W8FLXVev+UG7!VXQHGy%CF^{g-O zl0WVV^!9niSi*z^>kj4%XqG}Vd=9J3s%ixnPf&3hT-)RW_}eWj3X!idU)k0AV%9m4 zUH$?l9Y*>bjp#nPS9}GL+^9yJvQcCpalrNw#=37v4gCgUYLxG-=-geWLtraLJr`?f z4tPni&&*>w$V%)UIMTW=N4J}py^_S=oIAl^OK*}-gGfi#%)v4IKi;RQF(qO}yn{hn zwZl%XIqN)rDue(aHc}4NcbJKRp^f_s9a zf(oZcUDs=HibdA1jdC{b%gRcjLa+t&nGOARO5?LA;PCF}BZ@3x3kAbt!m?U;#asJJ zWFcd_3rFGDV$MzVPX=;}FX2{8SWi?#JBaRjKk{LKhpmQ>sZ*--rx;wOjX0jPe*0Cd z2#IN%|GVSYo7g1xp#m#m#=CEGw2G9kW1gOp8#-QTL}?Zt#x5f(syr?iulMb@#RU&Oyt{e$!H@wXqJge{el@4mt@`9? zUQ($4yE)){C6m)=n#drsgfa%!tyM3(qoa^an zU00Y%kEld;q~HcP5mrX5_5%`f=?oy)2Xlf{tFZeJ+=S5VbHp>O%Dg_L&FW=VP(^`_ z+eG0&x=*Y&ar>Zj zaelUQmLWo-!7@N!fARjSVaxu#R=!eW@cY(MhI6F;#_t7_Qp6s63>9l;bJM;u$%|F#-Z$-A39zo22|8iNj&^zKw!qcQG5YM3Z>FjDUDqQPd~^Qh0Vz_cV{T*qO0ONQ$jP?@uuF?`h~g*C z5vtqTp;Yx_O_d7psqcX-9%`&iinaSeM%I zMlw80tquNpZ<8j1xX`9QG*GFtqeODIF7yhlaXXY3ryogkYL01~anA~lzw9$)MHJ{m zH2>DS7C7igSgXfItoe@abwaD!WkrhTn;J7JCYDFA13&Qc{hSh@16QzLc8(14n8loo zs5l>^i<*HY;N>fax-grA$2AqSh39aaAmcW8X}GzR-;L??E?QXT0iqh_goul2g%ZJU z*Xy}wwOA)m0kdSwPT%A2Uxb!y*=2`5gSpH*@nijlU^zXgS_mKh>t_cF#B}#eX71Xa z3&M@nsrgZXwS{F{#$h%3!)^5#%7>)q;IA2BimdL1EK7m?3N=;Gt5fL>;G#E-6!Ro`#W7OR;=tIM*i|ZMjWL+0lHhyi-sdu0Xf1>J90!8bN^dDe9)yN8;Cffk=1u(cA8n zuV$(zHDuG0T`k{!vXsPGJLi(M9RWn`SYw_q+^p269NA(r2v#iV@Zp+ksJS7B4Wm4r zm>bxvm=}q?trC3YZP>)ar>1X5h0`yyWpk^w0Vie}UyjJW$t<<>kST{C95%(NW9YL^ zhmP*lq~n;3=R~NXpU(jF5rOQ%tmY38`fp@|{zGe}A-=iK?vq^zwGeUFb zkT%eirsgTWo}O+GW-r%bCV5=+b{P%`&%z1OJw2_(YQNJ_ceVU@ZZFLjUWkY;?x?NL zyrm=fV|L{PRAP_OI8}x%CR+;v1SB5I@J)5$adei_9A;fJa1v!Vv=~CUpGF;xavIM3S zM(Y~vrN~mCTNd%IW%R1?=l+;a=R{-h=SP!5gW~hzDZeT&BL|N05dAbq%KS2m&VIg< z9NnWmWwiv^SM!JmEzK6)n&X+fnpUev@=rTzWc+mfeFeSK+@{|K^EHUc@qHhwLcJ&E za`;NQv!6rT8=~6DCLJDS%L@aF=vhC23}6NKIjtBX$2Xxe*PR6~e1H8yQGSn*iV-*t z0dGzS6=Ndf7HbM_gqt_JH?wAS&|TMvMBA9v<-Rw|mlu0q_d3wtU;fETuM*4B3^O_> zQJHaL(E?Rn6aHph@aSD-WUk7~tpGW5$e{(@7UT`29JzIzk2PzmKoz8hQ9DI++I?8^6D*${E7*dWF_4ZGkX>tnC)eoC~!6$oRNlccY}w3Y2i zPU%uzzg190V_0eYHeVM!x|t2LF}IOS+z~WYkx|u{1e71P8`caD>QSU?Mf4aZ!OjyB zXATP-6A!AwgX?OIo4>4+r}Xt`D>&Xze!#d+E_Eb>rC&L0sKpfK*R&5X%^c4N4bSae z_x|BM<8Id13e0J`?!cmCX<&HmGqfjNr@WylaaY&Esqq0r%KRef&9Sn_A3_1>;bwZ8 zWW*Dbrvjx;lZ5>PuuA70SLgjjGuq*u6A5&C8>GCu6VBYtUhf?h2)lwZv+jw_eH`~|9WYX=%??|f>w(92{E`OV~C`m`8>On#%WQKi4fv$tDW|yAPyIm=5U3t9}Px!btH~BUdwlqT!YzR_04*eD6S~}nRj+WjYpcL* z!Wd_2n}yG9PS#A$SFFYcx z*8s(e7@Jb)ynOO{bHc>IELnaqU|mDDX=F@d5l9GHoZq~wtie+?%EuzF2b|`T6mKGu zz=Ly1!2=*U_xdYG@dp&wtEl8Y2rtTplwRoi1dRvf=-{jbvs-W;Y3Q1EAT5DB>67i} z=jXaE+IVJ2te47hG%QASMwUW48CNHn^MA!q(NObOK9|@S!)ht~bdMnfe_#T2X%qX- zT1V@@1-XH}iA$+^MU>x&%I_V&ckEqeplTy>T0jILtV|Vyx8{z*oMzyWLa%U@)#kqJ zicI7Vfnc>n92>@!Zli-RfZ6Tj((A2=ZX=$?Tx)5M<7-9j;dN{3MQ9kZ@alP$_U_&sAw!P2# ztSSxES8Fg3ODp&mg?uChr?90;<}<1-^Bubjdy1SfemwgS@vz&c>RR^UB^yM=7%U5G zIObOh?ij3643L`$%sT_{VL-2)_U?xT_sg=Mntz_TfGZN-8skP^$`ZbPgC^K%x9;T4 z;x5mc-SONRfN3pTW|%ZT-|+B}QKt;!H8tATF>6^EMQ7{87VvDh!G;NxFt2{4p3;-t z5!&2$T_w}8;zx*{aQ$`oJr*5kRYN5F)j524FupB<$F= zb2vNRsnBPxR*iJL6Ti=kXKbQ0XtEfAxaA+cwD_*tW?y6;t|4>8vxs2BL>n?ok%X~&=qiG#G`+3e<&V( zYN=2sJzG3Fjk!Hnu}Ih{%+gHe&ZrEH*!V!J_?GP%2r*4qbepdR&^^qfEFv8wykE-s zbPu@cIe+<;e}|F4^sc39_xsgdnCuzA>LkJ3D|BgM39J7oB*~@R@TOqI5o~!E{HB&( z*g~&nkG%hEl)$OM-QyR=Tf z=X5pqV_qO+;u@(+*7<|_Xey3fh6bokQXx5$4~cHD-*EsT4se92kiM>loC%Mk$9yR9lX`H+)eXF?`6-#nosrc%ILBrUApa&JR-H+WLrqRr|{CUcV%+b7* zW1}BwwY#OZk!A7i`xA&5(lcn74qjW8bykD;%ZZ z<@Ct87ncM&@)+;^xIv%vz_HQ_*PWhyH$S#jzdg8MCS)g0h|x?GzzlF0K^`EC2d~FG zTkJMEA6gUpT&F9q3}J<8=eC(DWA|b_?HAO1;fgoucU&>OdgM|cp@7oUC*ehW4o^II z1S5K1)nlOibO5VZm!w6jbI9FPI%QnRYBy{i2(`^}5bP?huFt7+l(S=;cc||EVyA#o zhq%1bIoDpmxR;XGqXG1ccXnx%{F#jw(71p=TwA)2T#osZ@76Z8kYZDJF%`?`1tOaZVNdy#925eUr98* zhOUqPK;BBi`FgC#jp3fI_IAXTQxp8B+Zff!jV|R2H3Dz1IwD7md97%{q0HSU%?)BIt(MHpXcic_56?;mrzI? ze8<3-HGNOx3;^II+BBa*>dk+jG$ovl6Kv?ccUn3yh&4_U=bty9@cA_8HEjFh8{%r{ z6Easa7QV7Ihz7m~%m8XrRx||K>elE^Fl$N-D?A2feBEl;&hcx0j(Ek@Gan}iG0fK0 zedfjG&w!S1^eUkKK&u9P(~2nXn!lXX{^h};2YPj&uN)h(``J^`MCK8)Xua7L=K?1K zTZOPs2%!c#Jr=#sxn?aa25uE;bJ<1f*>}&iB(9TfK%z#I3j5ov3!GurgT<8ld1gRu z-if@?NQT=+UJSQ201VIabMIev6oMN(2%8XEG>o(3Kp(t`w;tiDzayHyHFX`fUAqJm zao_MyRHZSMugJf0&9h*d{ovz%*@b`&4IPm@b7fWZ8DKM}$W7U4B9^d+S|xOB@8+kf z*WCJ%kuWP3Y-B6y8V!kH6~Yd~@{Y0K4WoTxOgy zyNv%~uec%fd_?lgsIUILYa>PD#T1 zG!P$OHl)FLEQVwLCGej@|4+B*<0isUDi0--_W9|HorV(Ak{w|WY+y2=r{R4xW4lLN zE+LL+>3Hw-hn{vf6e0%TxU?p0TvqWjW5fK}@9;+pC);s`mZjB@aC0n>llix0#s_5#u42SE4;(64+Gia`&#cl=gli_S>g*9=_M>p-RPD zvtMU5ZNYO(O!w`p1nah$vkPblJC0lO82GK#W7&1^)5zshK3k#gmT4j)w$~mHztVOO z5KdunU#l&tib}L~L|!$FFH5Shtnkse4No zeNLN*x;`@#bN%*v+M*5`;lZeUzvnbcOVt^ z#aBNJtX!Wuw=|{v1_kUmUzH-6VM7;{ZkNy0VG&!ch&~u#MC0OW-;gp>j&t%p){64+ zUCUbNSe7iixT5zGNax^p0`2U6&NGSiMY9ULNxgXM^EUt`svl+|5t_0>CRcP+kD1hV z;v3B(WK=?AVJ{eG)qsX%RO)+z6CFRQ#&o8HQXegZ&vhP4Eobe|=X-hNPaN1TfBe?( zBVY0@*dc4z_h~6K=E=Ox#kz#B)+J(DmX$TaQWkYnw+=djHk#n;6)4b#YxegHEMtrJ znx-ONN#vjqBOnYfByMu56?x%c_d$2~d#i7}ui)uyb;PJwFnNsPH$<`S@^Rh)b&<#h z-7#KkmGx!Dq2xM0B3gO#j}x{D>A@`B93Cr(Deu-^L37)@`}5_}gqBlPA_P zRAJMIH>WtkewZ6j08bv$=_m{ND93WZ+`W;wFTS3ZpOnwP^BH+5q^_TNqOZ8k!@wLP zn71b`*0LhIxVum(gaJ*UKVT-j$P_s#c4kk;Fk!?q$Vj-_@x|&BP$<5Owa*@uZuf!PLi=8f>g;wo>Hf0*{bRat7Bk0$7^lld{KT>7}N&V$@;Sa{#hS{A_eBr!% zX{mnP6J*A$|HpNK{QF#C!!cQC!w;7d^%BMTiCo|IyyfG7&)=ZUecrI4!>07`HQ8`Q<^6ajdaOlZoagQ!@N6PeCg19bQ*eM?jpvrF=4|F1;$OuuRUh~WEw0s z(((J;i9bXDKlb=3di<5JviV1Hk{s9tnP&J0Z&z^!~%FOKsvU3IXmK&JI>wG>ioPW7X0?2CO3l-=0YFIj`g1^x{JX zS{^rkLu;|$60wrmTyW?q6Y`GWWO>xSD1+Dd%rWLAxx#CgHC~33-1!XKdF(OYbSt8J zHEtB4*i9@kfqCP|>di4{b0r9h)Z={l=Zi@=o+T^HGE*@-bppf05L z{B>2ILY3`TcpMmEj6%?fdPx=D9q;!;nrt_pzP$9-w}F^<$sb|{ZEu#2i)6DwbqvGa zTI-3}lk5)FQeqCxZl3`n6ORpzn7zN0L?~jSV5q*X49?3VT}RdaD>n>ChB!HZqXGL| zoMQ*in<*AQ8s~u?1+F6p9QJ0|K93teH}24#pR|K(9eF|XinsXy@Dh=GsS_ps$|UIR zR5Y+XV{#@rsOFOY`=vYLGJ*El%waJ3wWk#r^ZB%-H+(FDk}!+mV#-0|ciY*8DLlhS z1>{^Yh|2lfyvW1q)aA=GdG55}2NxZq;MID4Ic6#|NOh|78#eGx!+0yg)@=Ob$^)sl zvjywb{lt$+SD)>siJab?w*i?lj>L2*N`;JW9WyViUe{nT-i89#PU706vCVl(8>Pco zl?sqdfmI8p7&QUG@S(}fQSgUcqO)$hcWx>#cR*UNajv(g&c5fmpkY7d9>U=d`Cwn> zme1eBa(q=rb-*>HR z6z6WGlc0a4rEza-LAX5~jCYHr-6P+HM zUTUNtK_L>p_+Hb$4cCVpgFK(izcelpuIIMm&uw-+x$)aFSM|om4VnS&MyA6)w22i{ zYj_{WlviNrLRE737B$Df;5E7f?xso2Ns3j#7ws0rmz>Gs1uTpnfBA*2w7vAB+>Gj) zJ5bAf**!<*O&^A^2LoXz)bV83?WAdEHUqs!oc3J0&~^^gwAMy4NAEr~ha+pzJt?RH zrBJM(&R4qBB(&uq?fn3DV7|Lmp>UD7?uA-nrH#XmW21X`tM>>&o^8li#7z&8*rUuO za;B^YDJAPgjId|+81uo<7JOA_1S={51#SleSHCn|jUKad+JCyc3tRl`QQZk8duDEt zWNTII!sl%ee=x4~Amn;=EQMDtV*LP?u;;SXdV1$8z6VMBp^E&&!dRo}2VGuPvsVgR zNt-sklFwG|I+2p`*29g!LV+TfYv3)m$Vf$W$nZ>;jGx)elt#rj<^h0L!V8cY-%L{< zp33C2GIxZ?aSD@OgZ&quh*2_-4Pm{pjvyRjjJ|_qMFA6#j{Qt#jlTS48$V$^&>75fCM3U8ABC!=ylkCL?nfrE6Ayg0_`fl z3!|BodN@!WabIiB`{kSz<(_d0;_7grcvgJ$N}U%BT9>jVW@$0kSfc1$=?0cYo*} znfJ;3s^B5;u(mp7;j#Mt(LX&Sk; zZoi`Z$;>c8p2`t~Wp}Q}JP=D~bp}A!hfx`$EeMAW3}J2rfk_Z@H?30eGXQh(2@uPu zaF{S$r5pZYfYD;ZY;~?G<4xWadH&&5{-HC#PC8ET(BnVLYoZN?GWU+viCQ>sHo|-bilsRZp+wvBGn0s}dZC20&xk&ci_7j0Zo^F?b+jbXK? zgi+0_4^_5eU(2fNOsQ}1WvH@P8ouei<*`86{O;b$N5{+ow_Z8cB!v{M!q){iu6vMn9&21_Ws;msB#oLifJfv1NJ38Nr*`tcmB*W)TM z6KsBEwlW^az)Ub$L;Ev8mjIy#SsBFxxKT9%*?K3qJHA9BF^4Hp*&1_H;hgaMigP5(iJqGZ>o&=xr1lz9_XF?-Xu~i(1R_K?6A0@eB`b*m97YDqco~bw2T{a;f>ZkfLO}YBN6PS zInOcW3!IvF#^Oof3zhq?&6NqS1;l4Vhp*iPU!doyIn;a1~ArKgz_Q}Kit4+c5cJB3#GDc5K;qKe1+5kuN4#W}GE`z;F zPy}QSiRCK+W2T8mv9^R>a-hSY{aX$Mb5)8bnCt7`Oql*<2#zf!M)M>1R2Aup{7;HV zMLM4W9&|Y18DY^l*peN=dn^W!7Azlat`T0?@;vi{cX z5$KdL^&^Uza$UasDH(ChS3Gj^yH@ZyeTGNZ#rXpQxQdAfqvc~D_aUfTIh3n2RJf1O z%Wj;U!&{O{*T^bd?*(AY`0qNGM@_i{&MiNO6Bi=Bdw)BAgeAjxZR$#dc_XCT9&U6IShj7JAk0I`Cye=<>#V*n)8SbW4oDsXJCGW6eAugTC8G zY{Dz3X7w9b=dj%BQ=IaX?1`G$H@gwH<3c{BQ)8x+pC&dPH z9F5UHJ&>26IAJ^huOhvtL7%q1ea8`FZkLKYgmQ$0VZqNvEH#?oM{V=STOK8d9Hb-g zQfdBN@ifh>xSRiWvj4DvxYknZ8Gzb+kU!WzS`c-wn-*1D|0G8Xqhvk@vv#zoO6hYo zx2`QdDFH3WXCw*^C@qMKhajF2UL66(mCI`_^vUWzEOkklYHdE$Ry#f6-!bhbtg)SNwokAebjRB! zNsykl%Q2p2Ffr<~Xq)A3=Nug6d}3}S#0s7Gw{kYrVAjb&c~BGIQi+suzqTIkCGh9Gou zbVl#;!eySV=so65K9OhlY2Q~gUxjV9o(6T>(-g!)uT1xRdKNd(p+^fBAvwo6Q5%YhvS5gNNJB&*&SQu0Mqmy~N6Bp5avRSclFPPn zM?A}{nZ)n?z_ewm&&)TIBR;7;nFQorL~`?`+B88#yj9hpUh37X;*ba7%#X~Gx}tAP z?Ice36~k&ND`!5QRw-J1ZwPcxIFj-67=De*f?ogr|Frg|BjdZ>M#r7znvg};W9k90Ia@3ITyAvMse?YGIX|8Tu zO%m?VaHj^Ev;ycvEC_k9SI?1;NO)q}@3BbA+>3o#jAUZVF&slEGQ|Nd*& zAR-g(&6A!p=O6Jtp?fFg`-`Ee;>pd`h_RLTn0S?R>G)!B!!OV zu{J<13Geidx%pw3>5~7gk8yCu{U!f0`?F~+&TQ*Jj^>TN_O#8T8_v3`LvL%ygyLUg z<(4JQGFh9lqI!?Cw~Ck(&f9Ow5v9h|@0AS`0p@xdpvw=M8cfoV%7$j~sa1wweB+w4 z6OHah$bC$4jZ>ArXn4b}T9Okt+RQ=bTdSuM+o}CR*}_1{ z%@0kb`O!;g(cL)6z>o#MerTzC-F4$PW2`6dgjdHv0pu2@kZF8(i_3uI2D2XGaEa{5 zd+@xG_;&n0jnWBm|R9|Wppw8!$=a9Wdqib2~?Deaa*IM>A zVXho97}yZb48qI2Sk15^H91KV`5n>oPL7L5+|l#i?^pC9pE>HkDHDGRF9MufAs|w>qO&Q<# z0~*aN9Cm_z0&vjaZ{tBXgbwt8Q>__Ie?a%^@&TzK9-acFnr`gsCUUUbg8(#>BK!jPZtH3PjM(nT{lMMg{9@XE7xWew~Lv1BdviP-#jI(fN91f_Y|J)u}Y<5L_Ah* zP)x=%fmeh-xi@&{T^!qoskwiJ`G~N^C1I}5c(!O^VAPag;o%3o6QTj)~`V;Ih$-hkO8a-!f+c=Y@OV*k{oUS73a- zs~F0~L?t{&ku88d>$)`@oZbvO`wcm{SNhL@A}+~Qv9B%a2!j+sEW*~~NcDV8w;0eK zs9$M-G$w0|sT9kKf|A~{btfU`9!aV)Qa?B%Y&-TOz6Q}&_p%N(;TmEijG`_Si@4g{ zXDCB%@Y-R$frq{ZPsg@X^TO{=G;r2=>iFjg>CLi_9rG2yRE3U|#f-|wcypcoB>S|| zMY`T#*LHSVkU4`mO^WV@ORTurQc>Z$R#^ATW_?~;o;uIoUj}J%e@sqJ&hhy02NZRe z@drT2e{cZIGvt7$gREF4y{Fih_ptXqG8~uf{Xc93urEv+;ZP2E9jbatiORoFk{l%|I(C4w2vBw> z;lxmGD2CidHzuB~StWU%`lFPDK34Y80(NWiz6OE&&2EOsJ8!oqcg61p$oTNBTPEhu ztOPq1WV;-9xC7|!sQMziE{Ot)MSCF51rt}w-xeFESwBq!Ega*2g?0JfYp?R9NPP7L zXt{^m!Pmq~5|=hC&vzG}A4#_}DifEf$cbL|s=nu&51+G}D>jdJw--IY-lTf)k`D5L z4OTpe(8qinkZ3ZZb^rl9wE@tKYga5mVA$)sECc@yQjoY?g6)QOprY0{H6`N`W^nHA zY3(+=a?eC3EO%_sAEg$6ISe@i z5s0<{h4bofU?y=FFF@l(#3fCJlzyV79TqPm;!WYl9#`|Nc^vJlc7v*SaWS>^?&!EQ zv~TzJ`5M_T3nmoQ+MAE%LJdjEn`&;#bxos|v~5ajNbc%!g_4C{0Sa@NwWLtiR6Ks; zh%@%X^v{_mbg{@9%|O2oNp`Z1xe-%wyIhNWzwU*($;_Z%xb8a@51=04$Wd z)&jC@*=X=p^U~`nBoBJ%b5q5EKB=53?36`FhYmEZJh84if0~l9geqxz@qmLM3OH3L z5>PJK$l%2*7~a!Iygv4<+ogpG2aYffz&(xQiY<`rx3B?g#uRfNd(bvlg&tgtRU2bo zKo2-nMk^(SDaj!nj_Yf8Bj2N^t}Hxw8s*`6ldzBRz6-s|_tQx(eqWg>MOCwS2C$5r zcP{l-%9%Q)wH;E<=3w=>3Y}$+!defj*iW$`$*IVA=D>#zkv`nKr9v=n6M8|HlN!+j z6;v0jrPfDps9U{Lqes}ZNbNF=e=KINjWPVB zy_+j~CLfb<=~`UNdb@9BmTDaL@h z6dU`^b->4NyRFBgBu&X>5g!+xAUQIJb0$iQO`Q8)MMs!^w(z2x_Xll5uR*}5c5_`- z6t@qfx05iVJ_HIWzao5tpK|*ZMK6j%9~7qdFf=PZ)F-ZV5YBJ(ZZEhux%X-n5lr6(elamPVDM?&0o$GK-s zq*4Q~qR#af!b;$p$%1*5 zlFq@{r~4-N!p$Pa&bA(BwCo!oelH?F{9u&c$svz`zs6s${i=~H`Mk^pCt+8)gS`g? zYS&Qn+F`cBPvpVz8ErMZ;2puJV?Ezf$R{?cITO?@G{ORlezYvpfru6U^buP&#nWw} zr3)f4epK1t8givR;9jtS{+_`V5=&! zV0l%tpmj2B;iiKATo6RER(mW{IsHwrT>lD4`p^L<-ehvQx8c=BBo=jF?|enh#W2XK zApW03))*$=G1jEV2r9PX^Rnjg@>|8!=#F23@?==T1*-@1N(32$p2_it(wi!Gs+=r> zzpu+?JmZsHdQ}N^ob*43DE*Wx`MiF#CQ{KCNiq5T)3#V8&Q@hMHOEwXSllMo3)9U?k1@dYuKM(Tp(-m~T3gf&xCmGx+{SMVt zu~D?Tzofox%siEXAksC5Ps$h}ww1O6Yz}?UERlfT6|Y!>9cgH>)rVYc|B_&^=sb1wnFmy88^~Gq{e6 zV_z}U>1S_b?S))+b{-aJZ!u)WY5MyQ5QqUqqth0xhVyL?UR#2;)%S3K)^Mf(yDx@l zGN>B!THkKM9)Y-3>sp!=JP*aia)QzCT$3XX>WZIibQi4E3K}%yFje9}sr#3cy3~a0sd$ zegx(5&!RN@&=9n)$5A_NA>l3jmvwbo5vF1rQ0%L<&+bf$~z9hYN{8bO)%X_?* zsB%xMF!1XiLk~03X-f1gvHD0|4l?YNyMaMX#9E_GrutVo!^(r|&ued)2UL&CoSJp<8bIVjIYp#8|hyw70N> zIEE6jeM6jid%RVsJ|Yxcfhc~GJD#yx69#ekaOAf~H7cXfE3i(L;J#Jx5)a6m!mphJ zR~hiUKR`Y`50tpLt?84*t5C&VF7~ki67&>PhxG<-LUVpmjPSE&&o#aMWnW%8JNUh- zN3c$dlaq53i(Nf534h2XOetSa$uuQ1_(Hxn%0)M$K5+Ed*$n9@8;PT(Ru$b!;TkDT zutOn!cWm`GFJBSgQs4WYd-Dzjy)5wEEOaE$!#jBg+@>;Pew~4KKayN#E*KpPw#~M20X; zG6$ph&AWS4g^-usx}zI_9rW`OO-U_%F#)ZvZ4uqiJ zn2?50rN0L98^Hv9G8X_Az06>WR{bkU1W>w1zGT;~PBuoCGnLLa(=7PI2#K8>TT+A$ z>(0sdyN~s|0olSgh$c@QT2Cy_y#M2r$on5}eiUfmyOY%$r-tHdbDL1Vq6azIpF&wU zdy`Qq7zgD4wmP!6PTHncmcRr?NwyJ;4f-I%g~XVZ{eLkkfoL-bE|^K!iR1 z4c(r71?(0IXT8@IrMkgX5fQfx!fIao&pt8rQ?b-o{?3_X_hP#n8N@`gN|?5^);r31 zejgF859TCOpDb-~e0amSEcwnSw=S5FLJ3YEDh|>6{{1UKQ#EDOTsd;yfb#VzZ1+dC z-QA@Wm}SWE{cpIlAHsK*H(*VxD@gA*zLL_HEKls5nf7Acv9VFsdB^*l{-fmcEXJ%_ zUa?o4_py__5soHQ>QS(okxCJZ91lNt{`{-v)Jtr^gDtyS-P#%mwU0kWP5P33j254p z3|)!aN7Es!nD5P5oj_ON$&AvYFW*+PcslO(87nALjIN5Gh)!i*JrD(iZCCh|7ryQC z45GC6lR+`#&G7-xLLWL^K1C$q-jcXq-z}~FrLdS2Xfx)%#?a>t1MV%#AJ703KlU^< zI%R@p?i|m=cf)2m7Tg)8w4JWKe{RJ1&lclqeg#&HZ_4e4WB1R^E`rx>W2$H=Is}Rv zQvgfKMf5J@XC~D!LI+`;7Yrxc2c|v)1ENz?-gk#WY`@n;a0Y6maB{9X7dXZ44T-6g zjJy*~I!$SaHO`#~9mo-)8GRt3_}%T7D{U5mq|2YEub7Xb$tAooIx>W)ph*FyxGe0R2<1sY=D3K3F!=LEO% z{yE`msgyH8ORE(0S>MWATnUSOa$fvet(`(JCTIRE5DxEB=tIk$Z0+hMgY4wTHWtSu zyOS}{@VEs)AxO#r3;q%*Gd5`EXcqpO3s{pFV#md;0+Ux6$LYmx3`$5p^fp2e;eEh* zRj38L`;FOL$9loOpb7%aKSbES;RR4L$`+U*@7=}qS%9L`8d=!etDs!n@CWq#C6JR7 zt@kd~OPu2nENh6DIG+WVe&bW%oIOXxGgBbfsAwjCY3Ix{V;Wy9cKgZQ*H1n=+?M~A z(hI(BJB&QckS1ZHiV8c~;F{_NuKKm>1$O|nuShaS*3R=4sx=Hg(@N+SjvXyGB6wz! zLJ*F*91%gert-ufM&fO0aVpe4Ou#lL8jNcyC*3ELT3kXRRRBN52n@hib<)AgXJdbM`20tBE7f&sbTWo1!ztX=U!8F?IAmp$^EFxhs$$ckR;-q71L{M%=Gh(j1onF=0BTMLm7 z6V4i58<*UooU7oN{aZRafxhlGpQSI-!^>#^`}kbseYhXGsBq-p`bRvw{q`dNZoHyOx>E~QX(xWXyoKUl3qf;ZfxqRCCbE?;tds@$Aokdqr zo)j`He&rz@N-@oE)*q-SsU^)h&H9ODnU!AxJ-~EMe$H0(owlRjv(KBzm-}LM5`(g0 z8{W(WsxCU#t7%EiVTh7bPc8KZ^#*T!wzo=wX4?j6ky|(xHriogq1K=Op-#T=3p=T$ zY1wo>buRCTic6a|9b1Xy1>A_#ERHRVhdv9=Vv!f3-aO$Bj3ch)h*^H~(b>jJN@}Wi zkl5NzbO#J9^TAYei1UyTI_M+tu7{$iZghWIbnkh6VS_4-y&GZG9-3wYo+t29;-PEp zyT)}UefU*y8)`bf1Ad@Pf9x)MlpteKFE%(6aV28Hwn~0qdRB&HTjHK&QIP1ulb%>6 zWaCq0vbMH(Ozhl>pb<#2&3d?DV-V^4+D(u)ztPD{{DG{^cwiUWI*Q!dZ_Rlgb6Zk> ztF8Fl$7bo(1eS|M?WF%e3xqy*p=|vFLasi|RW>n7)MWjr7Sn@fK+k3fhfw**1-T19 zOl3x82j?^WmmvYAmuB&zt_vc;34cH*u(Lh4rX-pO(a4EEpz8F@H9_jU=f$IIp@#Rx z7EN1y*%gj{r^Ve|o*&q{;&7-uc>19#B|U)QirdY(;2yCzr_@VM>Lte)9Pw>mwf?rK z)wd^Zvk|L%r5Iu5&^odmudT+i>9DD9tVz2^4$uvUVtw?>Y#q7x2rHVm5=VBK-kcAS zui5Q@Zz>Ni{t3WLqu9{#P|S%Ap;_aJbq9_cS1*40vW(XCzlECQc2gN(Ey+0M5bfFi zQ){}X_=?nbpuegCdMh&?$}b2=m*w9kx*1+K_Qw9BJ1`KiB4qvZGI}G7%1H~{74KAZ zZ>)iMFws>5zhyoa+aS?Q{CI#iK!yYSAV(N47VxoRhs20c>ZN*qW|;MFQ(q+fzG-ON zNQ{$`$ck zf1O7IndB2qeY{c_jdhxNcY0Ucy7G0XPK$kPaP_=FMBDPJdDEliI7U!6ih4_eLPNN8 zaLS)~II$ia%rAzb1uU`^S=C4d#3z#oXD6|_#_qhfPsv+;pLjISS#+^`Z;XAq( z-bI!zXU5XL3DLQ6DnBN6Q;Qje)-;L!hKX9GK})|$hk@vHoQB-TIMOR46UpB4unXXq z#pNF3-u+6*Ac&@Lul4-vU^7SsV5@>|Xg1ytb&qdR19LmhrFIMyU9aRTww_~lKg(&^ ze-L_=z*U|Wy1F1xju?-2KRFF}*=V1X6dqzeNDp#nCN({O|84%?YG{8#NTQePyNREi9zZ+D!;tUL*)bIWr*g?j8;D5 zMQ!~1AFXSwgemaLqyyZCnVr%&F1SQDojn96!&4zUohuGnxE;VX^}E1Lcsyow;lDxh ze}m<}j@JW}n|<83ZX6DJZgTXlh|3|#?eA<&R+cWuVtt0k;7R3;2j44d=odfB7fXfa z?We0#Sj7#4o<=Q>x}S?Jx_4FM`6D{Xi~TVLdCjA4eGqBZi<@tV*Jw8lm!IfF7P+it zUW0Cl{hl+X3o|00EcZ8$U^zYOZ>g+|pqJtAW%x~N_6ayxO!e_#?c!jd_XFBBYd)QJ zJ19{TYy|kaVcu=*pJZA-<(&2(*0Uh>ZkC_sn*x)0#yI?nRstV|dC3McUm{o@TLQ(0 zPNI9V$JEOhncxeR`>}=XpC5o{P*4VEcdH~2LH!LrJ2=xKzTmorvL8x&x6h&35zYf7 z?9}gt=vb?w@Vo7xZ$qT}c;Mz=_eu@J%!PnL zQ#c;}wbavvC(V?n*_2!HVA-P&*2eEa_sdF1S&sL^eVwf)=5l`BimMWeJNN$mU(I2` zC;8EALr^GY-;Ldq0r+Qb)zgH5;pZya+(%G?Nuv6>abJPx_rBS*5s=b209G z#>_b}~k2UVsy z=hCnw&cs#@#)}%fkUO6zf2Gh&0<^idQLC7c8q93tuwzQ6HVdHPy?yZ|SeB0w%S0jn(O>4m?A#H>Rd< zp_aB0xfW2AdVDVj(vf=>pQ%tRV*zfp4>FGRq=SrOaz^z(8{uG zv}+tk9E(zx3JG$CFjIUyI)dn^DeNBLZ*S3z~M@C09-z}LDj;rx> zbr9L-VOqKAY1ybV*}Dm-m}LTnR(ui-s`eeusa-OcE>sEklzgXJl052rogEty@$RH~ z(>x9nrrL{?9=Ux!I!4`GR-~=2IR&~jF+9r*U?d-0izjo&NrUH{9xfgD14>rH>>mtM zRB0gY2XY~x&8+3~Nn3Bzf&>}5z)Vi7?Db3XU0?yNEzifxfPkTFpBUSEaeT~mIj*)T zU9VvLA?nA3d31>$MWrFL>x6?9>e>E4NSWQL?`~$MkG(N#_xo+|8})7vOpQvX3U9Fv z8r`h@q!W5(e8FuI`$YsZisNx>$)dwAlkdpC`U4V3vSZi0IpmV>-x+PipddMA7*X(t zn0fpZ{3M%*I_!V&ORGZIEm!>d*1l+-{7UyVcI|g(IpD>}V?e%Y4eOpMqonXg?b)r} zW*c3DDl$iHzVEmKER|pjLA)aW3Wy|SbS!u>n3EFX3P{=?wx5!R@37! z9A5Np98=D`g(cqsN>>tCX`1nx2hF1gd7mPwHU2)9vFX2A7mJ3?fna0{L@vL{0^Kld!3GTvzioc{@=qGY9jA_LA46Z^>o|oktN{Ym2a`Y8aQ7Kd5AqWy4J4hv&8m zu~H!-4D&CKn$?fw>YxTZEoPQ53@!;=3ZcZkQ6ehwamGwodP{m$SfA(O(Rd&--8hV} zZfJey|G^Yz>-}4APyDcbK|@>#1gK(UqlchCsSd}lYx)VzYf;!n>@70+^kVx~5NfgZ zCq$I>vUa*d<1^Xe%2}OW7p_6fle+djv3>ot2m;#dX=1KA$%b6kfu+tw1GMuB#ypzz zq$H!(3R7CeI_)x^(v|82+R4|o#ozbic0T`R@?tc z=>COK{}YCpn*Te=`OnZ-kK-#u-!_o+i6CXEQRqcIv1JoN&481O`DdqUd*`mIp2azn zp0GVaCr%v5lQU+F>fFZJB9uk_#=9mX0oO)n_*YU$eHeqLdTGI(b&A2D|8UntXVX}E zk{RQ%^+e%mOaxfq59lE}7JkI_6(YC8cGBh%jCoxO4jG9Sk4;t7Njl9r(>$Ur+9y43 zyX7Er_V$AS?(%kJu}Y;AjJ#|LM`6uWE>h8-5) z$bZD@jkJ|(t;yfPL`&y1gAHH?uXy?No)02FGO+Ap`Xs%7R2iu5to5k1lvAtsn-lr! z2Tr?CCYEM^3cX8@O*bHUVETT9Ck3+VCOz&GomwA4b+%W3Oxbe>~Nk()!d4IK$-Cy7ZKcmh$GW`9pcO>`lG;N|C2EpAxM`4^sk4i8QK2&t%PRP zyYJjwyEf~W&Twp3EdK+9DwwmX!X)HuyBJC!(BAYuGGR0UX;huz9g*~VzrtO-R9NrB z&J;t?2pV%>yI9bUK8Vaggs_kKQWq^Bc-nSJo}Ks>V3>7I8u~l|!whZ#xaFtbc5iMq z7&yGVR@92IZTh{DXWRHGhOzb(2JPrvu*kmHcgc#81t%mketYxJU9Y^Bs8;4v*^~dK z^|@_6!kGS)k-G?2UX?sdkc*|&xtEI_MYC#BAG2%s&oAJkTSce|A!;hTtM)p)2dAcc zfyznmZQHB-JS&jecB@#R0(7C61sE`2!|)ieo$>4NA4q3}Ci@tUW?-)%R~eLxc&eJ% zue;_4>{^@4VHk_9G#4rX?9m{#F6(5oF}WOe=U(^-pf;#XT^;(3{vb$4NFYRV!OQAP z6ZlKD$hj8bExcut!HfLTXwBj!XFgUMM1UdHvlkShwpzh2(l9Pqfq{HZtK%CJq+~RP z3SE@Zpc#9g;#T&3Z+-I@r&$e;0#-8rak>-56lW81`_tB=Qmb(1n1@4ttYE9Olatwo z5By`}?9aVF2vD8>?+ci~|IhT30-xEr_lIUsd*g@OKgJ!ttCTvE>IEHo^zlX9`-C6a Xh613Q|JMQrZvXpVB>o?df2RKn?H1x| literal 0 HcmV?d00001 diff --git a/speasy_proxy/static/logo_speasy.svg b/speasy_proxy/static/logo_speasy.svg new file mode 100644 index 0000000..20caa8a --- /dev/null +++ b/speasy_proxy/static/logo_speasy.svg @@ -0,0 +1,264 @@ + + + + diff --git a/speasy_proxy/static/status.js b/speasy_proxy/static/status.js new file mode 100644 index 0000000..a0b1ca5 --- /dev/null +++ b/speasy_proxy/static/status.js @@ -0,0 +1,19 @@ +async function update_status() { + const current_url = window.location.href; + $.ajax({ + url: current_url+'get_statistics', + type: 'GET', + dataType: 'json', + success: function (data) { + console.log(data); + var status_container = $('body').find("ul#status-container.container"); + status_container.find("li.version").html('version: ' + data.version); + status_container.find("li.up-since").html('up since: ' + data.up_since); + status_container.find("li.cache-entries").html('Entries in cache: ' + numeral(data.entries).format('0 a')); + status_container.find("li.uptime").html('up for: ' + numeral(data.up_duration).format('0,0') + ' seconds'); + status_container.find("li.cache-hits").html('cache hits: ' + data.cache_hits); + status_container.find("li.cache-misses").html('cache misses: ' + data.cache_misses); + status_container.find("li.cache-size").html('cache size: ' + numeral(data.cache_disk_size).format('0.00b')); + } + }); +} diff --git a/speasy_proxy/static/theme.css b/speasy_proxy/static/theme.css index 0f4b1a4..d2648cb 100644 --- a/speasy_proxy/static/theme.css +++ b/speasy_proxy/static/theme.css @@ -2,10 +2,13 @@ body { font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; font-weight: 300; - color: #ffffff; - background: #bc2131; } -h1, +h1 { + font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-weight: 300; + font-size: 2.5em; + margin-bottom: 0.5em; +} h2, h3, h4, @@ -17,138 +20,4 @@ h6 { p { font-weight: 300; } -.font-normal { - font-weight: 400; -} -.font-semi-bold { - font-weight: 600; -} -.font-bold { - font-weight: 700; -} -.starter-template { - margin-top: 250px; -} -.starter-template .content { - margin-left: 10px; -} -.starter-template .content h1 { - margin-top: 10px; - font-size: 60px; -} -.starter-template .content h1 .smaller { - font-size: 40px; - color: #f2b7bd; -} -.starter-template .content .lead { - font-size: 25px; - color: #f2b7bd; -} -.starter-template .content .lead .font-normal { - color: #ffffff; -} -.starter-template .links { - float: right; - right: 0; - margin-top: 125px; -} -.starter-template .links ul { - display: block; - padding: 0; - margin: 0; -} -.starter-template .links ul li { - list-style: none; - display: inline; - margin: 0 10px; -} -.starter-template .links ul li:first-child { - margin-left: 0; -} -.starter-template .links ul li:last-child { - margin-right: 0; -} -.starter-template .links ul li.current-version { - color: #f2b7bd; - font-weight: 400; -} -.starter-template .links ul li a, a { - color: #f2b7bd; - text-decoration: underline; -} -.starter-template .links ul li a:hover, a:hover { - color: #ffffff; - text-decoration: underline; -} -.starter-template .links ul li .icon-muted { - color: #eb8b95; - margin-right: 5px; -} -.starter-template .links ul li:hover .icon-muted { - color: #ffffff; -} -.starter-template .copyright { - margin-top: 10px; - font-size: 0.9em; - color: #f2b7bd; - text-transform: lowercase; - float: right; - right: 0; -} -@media (max-width: 1199px) { - .starter-template .content h1 { - font-size: 45px; - } - .starter-template .content h1 .smaller { - font-size: 30px; - } - .starter-template .content .lead { - font-size: 20px; - } -} -@media (max-width: 991px) { - .starter-template { - margin-top: 0; - } - .starter-template .logo { - margin: 40px auto; - } - .starter-template .content { - margin-left: 0; - text-align: center; - } - .starter-template .content h1 { - margin-bottom: 20px; - } - .starter-template .links { - float: none; - text-align: center; - margin-top: 60px; - } - .starter-template .copyright { - float: none; - text-align: center; - } -} -@media (max-width: 767px) { - .starter-template .content h1 .smaller { - font-size: 25px; - display: block; - } - .starter-template .content .lead { - font-size: 16px; - } - .starter-template .links { - margin-top: 40px; - } - .starter-template .links ul li { - display: block; - margin: 0; - } - .starter-template .links ul li .icon-muted { - display: none; - } - .starter-template .copyright { - margin-top: 20px; - } -} + diff --git a/speasy_proxy/templates/welcome.html b/speasy_proxy/templates/welcome.html deleted file mode 100644 index 856dba5..0000000 --- a/speasy_proxy/templates/welcome.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "layout.jinja2" %} - -{% block content %} - -{% endblock content %}