From 2042a3f513b78a6c37688c770701b85efe91d980 Mon Sep 17 00:00:00 2001 From: rene Date: Sat, 6 Jun 2026 19:51:20 +0200 Subject: [PATCH] Routenvorschlaege: Schwierigkeit aus Distanz+Hoehenmetern + Yaro-Navi mit echtem Gebell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Schwierigkeit (Wunsch Rene): ORS elevation=true -> ascent; leicht <4km & <50hm, mittel <=7km & <150hm, sonst anspruchsvoll (vorher NUR km — flache 6km galten als 'anspruchsvoll'). ACHTUNG: elevation=true codiert die Polyline 3D — eigener _decode_polyline3d (Roundtrip-getestet), Track enthaelt jetzt alt; Hoehenmeter im Vorschlag als Pill ('X hm') + in der API (hoehenmeter). Navi-Sounds: echtes Schaeferhund-Gebell (Renes Aufnahme zugeschnitten): /sounds/wuff.mp3 (0,34s Einzel-Beller, 2x=links 1x=rechts) + /sounds/klaeffen.mp3 (2,8s Sequenz, falscher Weg — spielt 1x statt 4x); mono, loudnorm -14 LUFS, Fades. /sounds-Mount (main.py), SW-Precache (bellt auch im Funkloch). Synthese bleibt Fallback. pytest 39 passed. Bump v1243 --- VERSION | 2 +- backend/main.py | 1 + backend/routes/routen.py | 41 +++++++++++++++++++++++++---- backend/static/index.html | 24 ++++++++--------- backend/static/js/app.js | 2 +- backend/static/js/pages/routes.js | 12 ++++++--- backend/static/landing.html | 2 +- backend/static/sounds/klaeffen.mp3 | Bin 0 -> 34175 bytes backend/static/sounds/wuff.mp3 | Bin 0 -> 5087 bytes backend/static/sw.js | 5 +++- 10 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 backend/static/sounds/klaeffen.mp3 create mode 100644 backend/static/sounds/wuff.mp3 diff --git a/VERSION b/VERSION index e90170d..1c49fec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1242 \ No newline at end of file +1243 \ No newline at end of file diff --git a/backend/main.py b/backend/main.py index 5cbb96b..b473156 100644 --- a/backend/main.py +++ b/backend/main.py @@ -371,6 +371,7 @@ app.mount("/css", StaticFiles(directory=f"{STATIC_DIR}/css"), name="css") app.mount("/js", StaticFiles(directory=f"{STATIC_DIR}/js"), name="js") app.mount("/icons", StaticFiles(directory=f"{STATIC_DIR}/icons"), name="icons") app.mount("/img", StaticFiles(directory=f"{STATIC_DIR}/img"), name="img") +app.mount("/sounds", StaticFiles(directory=f"{STATIC_DIR}/sounds"), name="sounds") # Yaro-Navi-Sounds # Selbst-gehostete Vektor-Tiles (.pmtiles) — liegen im data-Volume, NICHT im Image. # WICHTIG: Starlettes StaticFiles/FileResponse liefert hinter unserer BaseHTTPMiddleware diff --git a/backend/routes/routen.py b/backend/routes/routen.py index db57d55..ee3bac7 100644 --- a/backend/routes/routen.py +++ b/backend/routes/routen.py @@ -73,6 +73,31 @@ def _simplify_track(track: list, max_pts: int = 40) -> list: return [track[round(i * step)] for i in range(max_pts)] +def _decode_polyline3d(encoded: str) -> list: + """ORS-Polyline MIT Elevation: Tripel (lat, lon, ele), Präzision 1e5/1e5/1e2. + Das polyline-Paket kann nur 2D — es würde die Höhen-Deltas als nächste + Koordinate fehlinterpretieren und Müll liefern.""" + coords, idx, lat, lon, ele = [], 0, 0, 0, 0 + n = len(encoded) + while idx < n: + deltas = [] + for _ in range(3): + result, shift = 0, 0 + while True: + b = ord(encoded[idx]) - 63 + idx += 1 + result |= (b & 0x1F) << shift + shift += 5 + if b < 0x20: + break + deltas.append(~(result >> 1) if result & 1 else result >> 1) + lat += deltas[0] + lon += deltas[1] + ele += deltas[2] + coords.append((lat / 1e5, lon / 1e5, ele / 1e2)) + return coords + + def _parse(row) -> dict: d = dict(row) if isinstance(d.get('gps_track'), str): @@ -249,6 +274,7 @@ async def suggest_route(data: SuggestRequest, user=Depends(get_current_user)): }, "units": "m", "geometry": True, + "elevation": True, # Anstieg/Abstieg für ehrliche Schwierigkeit (René 2026-06-06) "instructions": False, } @@ -282,16 +308,20 @@ async def suggest_route(data: SuggestRequest, user=Depends(get_current_user)): except (KeyError, IndexError) as exc: raise HTTPException(502, f"Unerwartete ORS-Antwort: {exc}") - # encoded polyline → [[lat, lon], ...] - points = _polyline.decode(geometry) - gps_track = [{"lat": p[0], "lon": p[1]} for p in points] + # encoded polyline → Track. ACHTUNG: mit elevation=True codiert ORS 3D + # (lat, lon, ele) — der Standard-2D-Decoder würde Müll liefern. + points = _decode_polyline3d(geometry) + gps_track = [{"lat": p[0], "lon": p[1], "alt": round(p[2])} for p in points] distanz_km = round(distanz_m / 1000, 2) dauer_min = max(1, round(dauer_s / 60)) + ascent_m = round(summary.get("ascent", 0)) - if distanz_km < 3: + # Schwierigkeit aus Distanz UND Höhenmetern (René 2026-06-06) — vorher nur km: + # eine flache 6-km-Runde ist nicht „anspruchsvoll", 3 km steil bergauf nicht „leicht". + if distanz_km < 4 and ascent_m < 50: schwierigkeit = "leicht" - elif distanz_km <= 5: + elif distanz_km <= 7 and ascent_m < 150: schwierigkeit = "mittel" else: schwierigkeit = "anspruchsvoll" @@ -319,6 +349,7 @@ async def suggest_route(data: SuggestRequest, user=Depends(get_current_user)): "gps_track": gps_track, "distanz_km": distanz_km, "dauer_min": dauer_min, + "hoehenmeter": ascent_m, "schwierigkeit": schwierigkeit, "weekly_remaining": weekly_remaining, } diff --git a/backend/static/index.html b/backend/static/index.html index 88c1392..bc12e79 100644 --- a/backend/static/index.html +++ b/backend/static/index.html @@ -86,14 +86,14 @@ Ban Yaro - + - - - - - + + + + + @@ -612,11 +612,11 @@ - - - - - + + + + + @@ -626,7 +626,7 @@ - + diff --git a/backend/static/js/app.js b/backend/static/js/app.js index f3a7937..6f467eb 100644 --- a/backend/static/js/app.js +++ b/backend/static/js/app.js @@ -3,7 +3,7 @@ Router, State-Management, Navigation, Initialisierung. ============================================================ */ -const APP_VER = '1242'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen +const APP_VER = '1243'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen const APP_VERSION = '1.6.0'; // ← semantische Version, wird bei make release gesetzt window.APP_VER = APP_VER; // global verfügbar für andere Module (z.B. offline-indicator) window.APP_VERSION = APP_VERSION; diff --git a/backend/static/js/pages/routes.js b/backend/static/js/pages/routes.js index c458736..8a19671 100644 --- a/backend/static/js/pages/routes.js +++ b/backend/static/js/pages/routes.js @@ -102,13 +102,16 @@ window.Page_routes = (() => { function _barks(n, pitch, gap) { if (!enabled()) return; const sample = files && (pitch > 1.3 ? files.klaeffen : files.wuff); - if (sample) { // echte Aufnahme: n-mal hintereinander + if (sample) { // echte Aufnahme (Schäferhund, /sounds/*.mp3) + // klaeffen.mp3 ist bereits eine ~2,8-s-Bell-SEQUENZ → nur 1× abspielen; + // wuff.mp3 ist ein einzelner Beller → n-mal mit Pause. + const reps = sample === files.klaeffen ? 1 : n; let i = 0; const play = () => { - if (i++ >= n) return; + if (i++ >= reps) return; sample.currentTime = 0; sample.play().catch(() => {}); - setTimeout(play, gap * 1000 + 200); + setTimeout(play, gap * 1000 + 350); }; play(); return; @@ -672,6 +675,9 @@ window.Page_routes = (() => { ${UI.icon('timer')} ${UI.escape(durStr)} + ${result.hoehenmeter != null ? ` + ${UI.icon('trend-up')} ${result.hoehenmeter} hm + ` : ''} ${diffLabel ? ` - + Ban Yaro — Die Hunde-App für Deutschland, Österreich & Schweiz diff --git a/backend/static/sounds/klaeffen.mp3 b/backend/static/sounds/klaeffen.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..3fe5beddb4871ae7bc75c50367897112e7ea5f22 GIT binary patch literal 34175 zcmce+gID5DQLFsJlA5JKDSY-u>M` zUtjSqKgnHw4QoFKF(H0oenBMi?$!SS=C3dMfARnCuIldKarZ!acRd3D!qEU+Faa?s z1r-e)0~0HpgNuhxP((~zQc6}{QCU@8N6)~>*zAe5t-X_ryQlZF=K-&RL&GCu6OvNW zGIH|^i%ZLE>KfiOw{^bj`Or7;addoYW^QTa^OyC_-TlMk?>{bn|M~mxzVN#`+TPVs zQ1JfYe*umg@PE;8bZo-vfBF8G^#8;Cj?W+fK)iBz>-#$x^q|b?fzS`oUAcazi+d84 z&IKOPEVO+ej8|h&xrCvRDhgRoNkrtoe}%9^F@Fr@a%JPczkfGFNOfDko~}=!qpJ5p zR9roFv`g-iul&ypDm`9p6{as^?!&*+7wi7PZ-SV8{eN*_Gh&YXgEv@CF+X0GXD2U| z@==D#v5asA7hDV0RwW`0V|9*c7ILD;Y1D_%Tdj`3dd|_s0g3Ce)6l-^a9u5T zP)ln|dxskeJyNHe<06)w^i?rcSc;H~)&BjfVG)DV!ZX!}7xWP~;y=?X!WeBmyZ@ZI z1YQ0~leyAnc+gvKc(V53u3kU2F_=H}w^$4>FuN4Kxh^2+J@*fMLtSpgJ@n>kOoiYh;|S#3&mjKWtLj2M1YrwR5=_x0Sm*w`ucUgtS-o+hqa`PUep zH1taGZMVl}FV|uN=GSk-L7rzKBMz6+r~js(eGHhQURQnmIptr&W_n!Bl0L`3xr*#m z#E}=JDVJ>rHj0f`Do{2KyI(LzN+y0PH#mDG9tHqL0%#`mjd!Bm*oiitHP9)gMi5Eh zUv21As*MzAsYE^+bfT2He9DlY$-9s;Q{P4t>sny?^qmY9&zMMR!)bNA&?aqhp{0=HVu<%4g`?P3?@6Svqo`KAFG% zC*N(2T^l!Dm-3^UOHC&F)W6d@Dkvl9UWk6v4n0A0gI#DfkhV|`ql_61(73}?yM_YM zI2$qaX0Lx97Co8yN+87#(!90hd@gUx)~ zBiLa$->gUkVj{x&CmySOUNc#(usM6HqWlI`UHiimn;7^~n>GxUh`p7Hi@9|dX3ocS zMMa}KI5iyQIdWxu5-^zCHzM88gyPyyjwSoG0HCo#Fhmx$7!s^R1XWYBHoE774}iQ^ z*KO!I?YpRP;i_cfbQl9euKMIanhf!O)2H7~C;*7)ab!c4RH9}V+>>XAyL~==_o5z@ z9SdNMHP&dJ-t8}q93Tw)ouFINrVz!579VeJdN3O+qQ2Lb^(AEa{Rf7)UF%vJt0rG2 zDty_i^gF5EZop6y&SZUdcf6}&<1v6V_+F^h6KiL%BNl%OeF}bqCw8a-_Pp8> zO=6J{Q#FqdR#XcjqJ7 zW4f9z6U{DRfGy%m-(rG4`M$7fTs@yRw9kNpeIvoF8bTsC{3+YTDEDGGfYLm~S)qVi zFGnY$D56Btwlw+`oPFIQ7MER^?mE1Ko(=sVny-vT0sgng9#&-#Gks_PgV| zOQxVZE*K2%YI9)_8RIX}pj!kFK>vKymQPkfLqwS@Dc->s$QCl+$ca)XT~T(q5`9 zL+o`-%x%&Y>BH5@HB`byI@5!vteL06|Ajgez(;9384QLEfQ7TRP+$f56v|A8FPm=y zz3$>n$y&?L-n{2SjFkfZt)bc6K1a_~quDOEQBg{>(-%bymVKSw)D;mO^8RB;-k>HJy*F&E@Se~ z=AaED_w{NMJ-~5#Z=y4BvbSYQ01cNX@C@}0V@xL2BD5mXCRF~wRuxjxu(bUrSMTMf zSQKV_5J}%j{}exT6iB7&lZKDNpRvZnlkIWX9US1iVR?1WhY*H_$-+pDPCQcMoW; zT>IbTR*ic=GNSG+2c;%KHrblfQFGv?7j*uK7cOWcPFW5qp-wT{&wO4Y_vO47W}8Ob z`i$CPT>735BQSB|R9AEJsca=v&CgbX71pZU4+b6j_K4y`RHET^6;!+S4<9#W)Rul8 zP8Z0@fH{dVKqOb~SxUOX;Aq!a&(hscxv~#B(_kD%$s}!_t-aZ%| zTPYMgzzkxgLjX}$;?dY@2Gm4^7RQS~NQRMm73~L&%J8oP-phdwE?d~Q`fpQQFBQgn zG2%C70kyz67vz4U3huvdLI`$4}XE>$|jELpTPSpWHZIBukrGTLg+XOm_bY|4G9-2 zmz6WB^&O(YqP5o`W@&iXvQK*u`6b6Lbl|5?^w;qEkEsEtk=lwCFyUdp>4i39>*rH)#886Z5`idEsjMQzA9uwmsN) zIh&hTy>|;>1{T$Z?((bCqn?-HwnLIt_;YfW$7x3u%~xQtk91u5vuG*dgiN**O<1L0auP5*IW8fUrtS~B16pQ;BxZto2uJrr^*kIxh&h<8=>Eg*E7+M%I;JDlhkeAHr z6krnKw#CK#wDM=YV|gnj74-f39P?&-5dgyRu;+Z8KTbgEVi1}iJ=_r8mNh-McF)HT znBe;F5g)uWrKqUdBE4|cU=pZq)++8@#{S{8X;`=0$3Jh=Kg59NnRA~z55>&)m?%+R zzhg28-``vu1}kzQbPPBse~pX;Zz~*9+S>nFd1PxlE}RgX6jSr(Bg0*nUZoQoFp)yz zNr}kjA{v(9jT!`a#*dmL#0+pe6p)I^W(3`Bc7dS?O(V#UUe{)rD%5nRKc=coCiDrFH;m5Z!JBXUHFj$q z5@+c%>MF9%#9{|et=&_NZh8miKXNCQ-SbHaOJpaO)L=JGnJd{-jjxcbn>tWV{TofK zYcE*fBO>?&)X=DolzhJ$5(4;p9RK- zhvpom^GzTdPT^8wOAfYdG|gFa2oNaf4;<(befZ*_2^T=lD;Ryoh)u)RLna^0An{1S zUdho%Ie%Lb=ZK%0{dK`MAlgPd`3H=#aOZZ=3zf zSkpVSrl>ii9ovaw?VuJDKXB-Y-EkmRdeSpb!bec{q@>#=RMmo3?I&)US7l&|+H1Y^ zdp_lWgi%sSSEzB{yE-S%pNJn$fA<0$A%IXo$YsCCME_R?t4~}*6J1F^za?lhM%z@s zVvM$x?r~M`;B$WOWDebMI;+_g!cW#q$R*sW5L1{wQTIpQg$I8aW@NdFQIji;t)VIm`86FgdtG6#6 zr+Z6M>ZC~at5sO36CBi47tKEkqUmbZOV|H>}L1L ztI4Y8&sVN2G@b_%g&Jp`ER5C}m@_au4!ZhVN(^AZ1~6;VegkibYRl0>)^N93p1m39 z7JMml%hBe74&mdpLIyxHD$^;2!CgXz$XKF)u}xcr7>O+ZCyTDWr!Uf;MCU!@PCZ$r za90a(=%;_e_gNsfV>0rRq^RgYTp< zS05%_B=W$U`k=k3gC80r)1>|$OV!wrMEhKZC25(=!GsS`}F3NUB761bl7Y1Igt8E8|Z>%rn$Q zU!Q(gbJQi(6g;}qh_l7rVw_HQ}Ux4Q0wM(b|b zoDeqJBio>_>F7_`f%KKj0#zF9}( zNMpJF@I<23Ij7d^l~hFZtbj>0Txr$a(DzZMY&5=42QIft1*7`NW1J*E2d%z?Yt{Fv z+X=;}0u~z=vCAx@Dhkpt5+*qzWAh~wu!zRUIU}9nMeNn3d=NM$=*FsxlZ*_9S`JUQ z2R0$MBde?Q)14ii?A#6W(gjIgwtR3=Q+Zb-VtCJIBX~;GL?|lTu)p*TJ5}TZCw3!+ zC7hTBh4-q}fGTqG+J-+s7-L5nVZ z;Pe871G;A1TZ z5xe@hbaTRkJN`#`X)Q5!P`yvAN|4>&V>BV#ggo`r(%1czQq+&$=6}y$8cSjWu-Hzw zN7KUi$tb*x2LiC=(}dU*!_(lAY=FUecKvyIWvPX-b~m9>EPY+!NGw+cAu0;XOc~d0 zS1n~V4=Q*Abt58}pZerr#nBnkX7{Z*_^%;!XI#x+T!~uW! zWw<9|d(uHc#2Q=4fWd*}qsdF}QKcAUyN^OsKfXxGM^v_Fzq-biZx0p)HZ@s?gp;aV z7zaJeuu3Q4rzYRwm~fuJC_w`#E)kZL@JEUZ{BP0{U7_x)xr+`35+wv8@m~Q#tVEsz z;5Fx2P7YQd)4ij!sX`lAVbJ@{?l)3$IJ}g9bCrD0VuK^4evd5XhqfGNL4g1(+QP6u z{U8%Mngz1&48U1pu14;Fn9Ug*N_XDE=Lfge$;tMnxh{buw&D}k(Q-C1AggL$R}B|$ zRr8lNH@>*cc*?-OXoBLz&JuZm&LUJ|61tfTx4h@G4}g5(VVHo=4^%L)QhhlPkDw7M z)`W$LG>uVW`4UjjQ$Mj4x9j7_Wko8)BlQsmDou3$@z#kf&|_}tUO~d4tWdQq-VSRl zeH(pM-so|Ks9AnxS^Eln$Hf__RXDiyOsPH=NfuHrW}_E@rn6E}|cD#_4Y` z0jEWR;s5|&R}4|$1As51dHhWj zxmGGj)Ug(*ga0zE!Zf+3h5hKM5*1Jg5K&(tq5q7)Sp8Qu8eeTlZBdmh&DyszK#0fs&bZM{H@>+ZKTb=>Z8VINM?`0J<&EF3{juI6W z!wK~Ou^=K`fIJ&%GBJ^=AT4Ubq3rT+h>1QwFoAVZ2>Oyi9@3=A&jr(grK@blBd!qQyAREv`i5#9| zG{?dA{Cv0pM9(jQo1EzY8gJyNneD}#1YtCnMlF;z4AB4pK+swkhX{I&OjInLe79|#A(Hf zK&m;xl%Y_U3WT4Q{cqgXm=D)JE7|&p`69ffO)Ai1I)X#L4@%Q6VT^}T6z*1{2! zjrsg!?h3Q|X?^%7!w&s{!z6ihuYV+4$UUEsJNrhn#&>5PIU(kQg!j_iy#RnT$OcFW z=nbiiDM<_zK!ZjF(iE>g8WDyf>!#?#xTVmzgapFkYW4llRA7Q^++ef>r+6K!5sd@L zC84L0lx!7*PT_0(lKZKK)lh@`Pq_ehjlaq@1f5@QTx$vbB0^YLxpgXid3W;j&-$j` zibyVNOWYeA>^e<&ONE6UB_*6e!cqyMHVXWhKX~kF)fL5R3$DRp1y9BbT2V+j!C36Z zo+KX*yH3(6^p$*<5j-F>ELPa1uHOSylQC52ik~p!b`1j#VLKRFQ#b5={J)a1y z#2t)|8+!+^ubBI8f4XI36+>N!K)trEuLO%(P-~^locYLIxu=qt>9jK~+9O}ilw%W) zrI3l%mW`H&Y~_X0a(}k4g$z=58Z1f_{#zQE7zCk`1n=#ytit9w3~A&Jo^x|-!3z>$K3f{FSoLb!7Iw`BrtR?*iZUbdhN zwLLaxmg?vT2zp%SvqKD}wfJB8_PRm>%vJ6}NEj3X%$AePaZxTXr-D+71cwd~5^t9! z^EUnaK@v&u$drOXMPSgya}1!jq3T14#6HQc1H`kUt6~|=S}l#fd1uz5Wu?RetRk)Q z_nTfl1U}ul&?Mw860$s~i2EiiPLZLJkzts8*LW71r#7;w zR;ZiWQ&Xl>wl9DS2G^5^q;bVv}A)_LNn%^zm`A`InY5rjjJbOR`*@ z(H0!0Jgle~&9X4CvG2tcuMCY}9%lSb)*5u991QnX{_A`L9C+}uaX$~1qu>CDETpDx zTLHWiL+xrE-ArY`cX$Cw!4eRt4dJEmLx~XGyj==E6Y+u~(roG-dNXt#g#L)$8h+a8 z3^I;9;@dO49j`LDXXA`IXkIdl78^Q1Zb7;A}v7zCi~gGxR*ts#&o3 z5H#3wOsfGAvbmR^t`HJ*t1Q1WkL+}glkAGpBNR1dw8`vaj3d@EOBl~LA$2$=Z&z@qT6;Z56oZ3 zhSMP3#`ZgjuZ-db;Ns;N5)zD>LuDd~xLQ>L;N;~(@$v-mp&EAz-hSc-G*_Hmg9m{( zCx{HeI_%6B^U00w{PU5`Ihrcn4U}k~`f^11Zo7x>VvDw(B5?LMD^UbLBww-eOX{z= zFmjq*2{1VQgZYOQ`kltVUr~m6vOjD+dm=_?KqG8EOyyfWBuYp@F}x<_d7J`DWTafw zF{EVbBb6upm}DX=5=xND&EQCq_Zes4M4}#zG83QIlE|fK49c0~1RT&fP z$i+}qQ4bNjm!0E1wcr$0Wg9O4!5$brm}P-3ghH{-f9Eo;DgDK~SRT8A%?n}Sw}VxU z(+;!SbxRH|Z9{w41E@u;V3Z2k0J48rYhH~age-$Nm4Z(d!RvXfN~R&Zantr|Xg}PR z{HNr&n(YP?V{BQ?obpos+>w8N=eLe>zX;PGJ4Vo5IQ4=^b-lv8TOXg~kq#fZM~BbH zvkp<7vGg(bq7HbQLr6qVQ}#ZiA1zosKY1f?*5Gc))z+u5^$nx|iamegk3RL+lhcz3 zwN82+!=@rhej#XoX?B*1XyVr5;p3iz%f-1h0CbWHwub?8NUI?eLZyN=4` zYB)|~Q{#)Uu})5cD4cJy;%$J-m~&?hfdDLm>J}Cv?XNPp@D?XT^G0Rji2x~BM7>lrCptVOOhsFsG# zr6!@lsYty@j4c@_m)mnEJNrDkAIIK*xp2zf2&KGZDK8m`cyjH|&Y4oI*_x_7Fc%%E zs~7UtR81ac?_)nnnJleE@K23^o0=N(K8K2gmU+-RznS#Svyc%&*?l%BmM#e09&~5I{2Xll-`uu%A?*7@kJk zH71LWZPcO^dYvzC{&sd^ZQGOq8*8zl(WXD^t$ zCrZ!N6kz0LoFPyAI!O2O|Eb1m%zmt+0&w3dvZ1j2=NSkneR`!i4WD78tUL)JY6EXC znL@pPR*c#&GH5ouBXC-kCn_S08QG}p_F%W(7vIY2`QWjzkVB7GoYvh68?h6b+Hm66 z6tV)z@^awx=|plV#;3C=UDFT;dxSPHsSNTF1kOcL3u_WuaH|^U#dKmE6{v^6c_nV& z7vhf-o_@sokIyfV?!Urc<>iwDOwH>mm$uF)PA_0r{beF+iAu;41k3(xO6&k2EGrbU zDz=qCw~^C=Yi4c)7(JvkFPMQF(tELSXc%d8N1>{rut$vpf&n5IFgp!4rGF|$Cw|@Q zx2tIOwCs$EVK}j(dJmQkL70}7AQ|r_4@Hf%j?xowE;%^?v0vxXN^A^`*G|cc{jwyz zWBVpea67ma2TC+7VJC!XGvTBf|6e)r7036KeX+;R}%w5t=lSgT1 z<9z8+nFMs&5bG!-&0`ImJNc?g+TmEpjLbNDQzpDKeD61S#Z9T`#q(^z5OHxlAQp!L zqmKeW5~bz`h%BW|wW&7MCkp1#_@~6zz@0MoJ&l#`UVg@d=}Lm=HKZl5Z0j7JWwjdD zJn-T8h^Nq}Ns0e4RO6+ESWeEqy)r8a02_dFm7QFnyHO2Pa0R>zD&6W7&ku*OAe>&$ zME!K{!7Mt{!8FUdk!HC*8h*|sn)a|st+9DbV zOHc7zDNVV>twccvxZ5~n%H$@)i4{%8^(hvLiY@6*zs4;7Qc_xrtdrHJUi;awYY{`mVy% z3FMtz)C6=k6yI)c&x>CUkcuRy?SIVJVC9=s$*NsdG<_3G)BE?gaaUT+&}_svQaTx= zi*ek-k{RzkpFqI8Y62f##k0Ooe2C;T*pC;}Klu_i?fHHGCSkGzSU+H5j7nH^t2Qp4 z<92cLsh|MVWg;z9wm&M^HNVm3s~f;(E5ccRcrmE8Qk6YDjMt{JUmtbTq%?}pWVE}` z`1B!`Q3vJI7)p0d(4?y3N<)pGvz)*v39FDj(MU6&uKu z;G|%J7(d8<%)}4R7z9obkdKmmbv;Qsv}uW~;BP!)|VE}$#d=0xw5IObGrPB3D{ z>%ws&mz^fhiqz$))|NGPkXtDl2jY=251Hv6UG5!On!UK^^Bka^;UkP!KHksOh_H{O zJ+R23nHl-$ATvGCn*4eGSO2sA0paV5pz|iwop0aFmW8nFs|VwMJffZQv?)mw2c>ev zhNWjBA1tK#573iV){~%Kd5eZvePgxL)rF1br3vP-TFGPy%qVG}*as}rFjNoNUv zyjF_iFOtMsHi7|4k$JpAm#vwdBd5(7CMzz5Y-|d+fiPF%=Oa=&VzPA%xC@U&;@<%^ z32YFQD`bNs2LZW8>2A>M7J)`RyHLiBW|MJ_f61UJ#k8lw=o8iH7O?H_{emy!tCs$~ znBN?nKlBX(q4#_O0JCHk$g1+ienK7x>+qZnPBZfT-6|c$UNqXLYNx$>!sGc;3;!+! zE;lCtu)kQ+tpXafQ=)6CYG@jVpX*pdgGZr8w)??f#ov40^b;K~;$rK<0Svp3MvB_4>3u(G)L1k2 zTc?IC0*o!eM5-*FtrP}&N?o6m;GMkuEzVZ?=^r1P5 zs$sr@{sEjquI^%59fD|#E)UaH%s-f@wP3U(G83{tQmv@vwq+{26}Sz$*%~U5mc=KG zrXrZx@@73`V$s=Euzfg7z-9P(N8p2UjxXi}o;AJQC4O4O^j^2}-nkZ%$Anh{)+Y^F zaL=wfB#9RPzxjt)Gf1|oTwQjQXHVxmQ6hE9^COo+YI)69(k9wyTbi~Zq3B}g>e5eN zUl^598NX;=r*DUyZzb6&+txi&Ri62YV>)*D>r|~cyQ@%WDmPoh_o>&b<($v|_+Cv{ ztKuc;MZJ~SuLjb5MCJ^MKS7Y>^3RYI8^?^&8qf2I%*Dav`uz%ObALst+I?W! zBp_gNn&Fy7?7ohf7z`(u0F{PDO7|mO(He*6gtiP+T?OL?$f-o)5P^u^mTw6eBwGkl zZJAbqUNv{BA)=s|Rf%;SAhrwcXeq?uVGC>G;3hn{G0L68ay33K)?rF18T$7sV*@Q3HY&yO z?_L=^({D8)uAfY+E6Y^6pfZ_i(~3A=5UcOu4ov=9c*H&yWvex`*imDvoYG72l8%I= zbRarWyjp@qERu@1xV#%1ykK);gPkxh?zVGd`92^nBrcko1e*lg>(o3!n z>5sp3wF>|O2)O4{3rHw1lg5QM_f6M1Le8i=g^(!EL7X&#vUpxw@w^@(Et_H$5f!^8 zXnZh<2r!b;{6b?UST5V!M)2_>$!_YcOd15MbIw#~A=WobzMpz85uvDLKmb(?NoaPmL^u&`M$U3&u5&G6XmkP*fWg$r*kNXcgdY!S z#*am!0iGbGh?ig9T-BUtR|)^_MO#_K8zHPPtHuF%?Q4it^JyHPBjxX z{+RMR%L%@*I44?OZ)BNlib-Se7jdFHUQ&WM8Qyo0ES+8{OWzc(tfqy+6C(JiPgcc>}%F6&ds! z^Q~iU`4~med*=$cCa8UD1Oc`dSJ!$1@~0>m_S1)DS&YjdCov$=nx*BVl`6L7CcdjMY>zkh9#1p|dVW2_{=t6Gt97baSJfJkL;f%i} z$0oal13>!U^BD{#z51thvT-!K0KKyxN@afyX%nu&3idR|L7u{P_j?&5OWMD3E|a*9 ztqKcB+8K>~#12m_Z%%infgSSXK{F>frqj5^DO4Nx>fV}RA~l_NnxO}94Rr6d_h}A* z2%9rtBu)`U#A&spmcWKw9?%Q0CYzDXhu5&+G< zK^}RAhR;3~??Z8u`bBsc8eeZjv$kD$#p3q`bm;m=+T~3|0Qop}x7-KTx;s17E3q+@Ry zQ$1~&l&qUF`72g#`N`kV@^BCM4l`CcFV*WY#c%D{7Y&t_HKmhx3|$m$MGl`;?!YVg z4l;cS_&x4S8Ck!t4?!R_z<^AynZxJ9sr=;8qlao;rK4$sjM0y4%pm}w@dCg!Jp^tV1+KIhC8g}WVmS@ zIpmSKueGpKDdNA-V&;Um@L}7x6}b2uFs1(~l(=on%>L)LeBL{aNsGatt*x>Fbk@mw z(}K|bQN^@6J|Z|=%mzO8Ei7(C6E~W$fQSSoOr{|LvOfA@V^VhBlsD< zV2!w!pPjJ8_{}^2OoM)b?0wmu50I-64Vc%6(FNag%cog+v*Pj_B?@AW7gDZ8uLu}U zTvn>)f$*0W)$ZLcqZ<+Ih7%m0p9*-aQU}3e*+m&@ekHxfV909YB0^ZKf>XlLz*aU& zQXa$u+5FL=G%9d>Y>gn~c$`jfDdCr`q}@@WlxE~L!{cBTUSKM%EO#+j$Ngr8vqbRlk4Jy0Lo1YhO%%TMHdK~VR=UV(GF&W%Z5H>AgcVZD6YBR~B7 zSTMpyWY7u90sm^usni20){?a*3kD8Z&C^9_CCm%HfX{}W;pb~$ORzT3Mzc~X(FSKb zC#FhBo=knUGGK#xQnDm-*Ad&>1fxs)mP?OG?)e;q&GL@Q@gE$K6J}S3OuS!lFdzDQ z*~#A%KgK6gUCL0oQ_tCU{Hr=mS$C{|REk1ICxmxC z-}BiIn^y0OiC9od_m?1boxatZU@ggQ>cO4EC?rZoptx7$rQ^Y6_uh@ z5;J|dCCehVN?xjZJTN$aMVB)@g1oZ=(F)TOgn_T@C5`N9%^joPdBI{KNwi8`bb!U2 z*VMU#0s9mMUS0iJd9nC|dvv)oHh@0#ujT+6)Cie>Jhm|bqMI&In+lt3lEh~U$oKvU z!x$d9+!J$?rXruQ{PCnME{cc?xTRnuW!g7e@lgZjh?F43BIPTuhRgvRv7j^&UpA7} zQ&Ep!xi5NeF)wSbFrP7O305Fl$Nk_t8%OusNMC!r-CI3SiyRI z$-|*6NT>!jL&Su`Xnn=E06kbnI8inE(SPy-OgUdy`0ji}_O9T-d6MB;&~8^~lu99Z z+=`an{8t7)gzQ*g@$+X_H)K;@{WF{J{1<#Ht5i+X-V)Dfr>cJGvb4ERA!lPn{Oy?WX^TQsWBM?gIw&2P+QQSL~ zQB`L|!c9RAs6%6n#Ab2mKEAEZ^Z$(;wyfm8KG)}bO=9wnNiF(=+UNCM9)wIx>o*1e!jm&fknV zYa}KTL5W;dXCs}mH**FmX`O3CycFs8SU@P>(fxS)en=QMwhDQO{fT*eTVE&<5#O^H zS>kQeSX=Jz=KWHaR5*5<-1F3V*XFG%>{kJS%c?U?M2mzd^xq=d6QwOU-z`S-4 zY(if(yD}9dm4kZt+zgSXs6gy4wp7bzXm-7>qNH_$#cK(Th^!v(sP^~Imn;M#&7A`I zhZ+{gALJ}$Sp9f2`oh3=x`)<5;e!>4;*P%rM!(1#+?p3PuQ|NA3bG+9WP5N9CIu?q zit*j~puWLihC}7K0RSf1@6_0=R4Qi>JlV8pALa5%f=Hn5P^xi>hX#_2)Ck;30^VT# z;7>8j5O$XL z9*TlV|LgqQ?T?1IMRfc^jD~+ze3Dk-+dat%NN1Mrwvg6*%&v;mho0*tfbBEkh9tWJBg3jN6a*MaGql^_wVO{yw zz19Bf|J833YZLSsmpzWsPUU-W8o4UDd3&q@XFYDJ4h3vhRYAE?cT|2qbF$Ene7Vs6 z^P}5pct)$jr!_r;E^EpkW_%$HL!X^}wOq*b_jn$Q{(;U=8rnMz*z2_F{l>U@qUtEi z#=w)cGOvk!WVQ!C=sf&YEZ%`Rx0`tXh0lJ@9<%+C8+ErPLLuV1PWeecyqvLJ6#bfD zS481|Y}kfytWb7vGR7AlCSm#lom8_=xfTiCS&O~b}Ep5 z$af)EJdPIOMS2SBH^ti5IKA5>>pD2Sm=4U{IslaFD!|M| z5tI4&ounFwXq%SR1BA4zSx6?P<|K|eKj3HNsS-;lP`3O{l0^S#5fONjvdaDVbnAih zg7$6%fim%ePD^TU$PdYzdp^Cu6quRFF}z1klE;2Cs!-fz@reKGrNzz?>=`5r(q#aUwzA>~}200M=quWapFha%d44zHUS zWQ?CK*Vqs^PSP~3#e`0Im>3_h5!BC~bNcbRt*|VtQLTr5ID3SKDhjUG;*D1dlSB)5}CR1w7{W&SN;oLBI2!PiJuQAK3>Q z(xiO{oQ}`JOIJ35$d`=9hq?~(tL1`B-yARmIJc$2;Q(l-KD)PN6!BHo*w@*uQAaD$ z+KsmvW81^tt<@9dTYN7MQsK(hP-5D!YaeIWILn#W7gV~Rcxd+sz#bjfIZ_`uZIfay84J96bdIV z(^(YZTb>4gL*yuhR~%Ksym}(%FG(l(g`x=D6!i?fp1pD#kOFaF!XfUc5PUUlSu;|q}NWg$w0Z0`HYgRl;d^~Y`HqsOrrWl7VEfqIXW z2UA)y>|aR-vnNVfE5_qYcCuj}y_Qy*{&&g!nV~9M4K}Aul`~b-THDh8-DvIiU+C{= ze!^k}v)#21Ya-u~_f5w{dWSjt(+OfjSg>ggjMZ}-YySyxm;tfee^t!&0 z3$gR9K96#<`4PHjn5y4D+)AeS9Z7K+3Q~5%;4LL6?a61dT1YV06}i4SngdowHoH{9 zWV5$8WGeYc`*-zHLv23kAe{_%xy*Rxzqq`Gl@0LhS25dByFsgM4byOm_J=cv+HEbGd`JKIOhvZkKr&a6H}^v0$v{b1|~qs5kzg^KY|+ zFjng)_w|^ipifShSUzsf(zPv%&aTAgB(RTui?_OmGmST=meWDM#rw{tXBXi9MK_Lr zBg}GVDvjbQ(at89t0Wy0}3S zi-DOcebdrE=bPKR-rG>}B%&N%krKDOkh!L6m5_hm{G?CjoYL-YvJ|K%=~#igDSQou zWW6mfrDu(pc+caE4?w6J>Jh(w64}4er_pla$RF@p(yia61ls{Pz+%GkMEM%qB4U+I9>>Te z(BpvF!VvkTOsZMFr0A`(K}% zbDrlsXJ5?4T@EWWpC|-Fo)eQ7iYUUlo4aE`AfI%j>Rx3x(l= zq-CG$&T5$S6jsPHnR~4a=06(7qqP|6 zaMs!Mv6$4M4E%-q?$YA$-J5af^}YK$w5$i}-R$_igxjQjjdvO&@9Z4$e^l1dctSvI z1Ru3fZ|mhc@j;H7c@iz|jC)c=n13~yo6J{k?5KifO^mg>Y>vg}neB9|k(=G}`Hq=O zcM>CI{|h3j=AwwA-8QV6PZide#6xe=YA4!yHb0rzOVj;4A*%6K->{0NP$@bR7KTrE zn(F@mLE7};+WW(}+%c>3o*p|ule^076B`u*Htrb@vlfUG8%ylw8fRn6@^$ zVQklwxcVigAAZg_CaBXbS;{BC#d6E%Tj(6Ug=hl$_W+QebMcH$uZ8C&1yw1NK9NXp zXi8!qHeYdb9v)KK86LLu_vN>k|QNjP{pMiWV0-lkly z&OC0LaKeQejEpLk6?Kl`?_BsStf?zLhEVCOuHa{STpIIUiLCapy9MocWAc=D`j*cr z1}f_!SBL&SpjcaB9Fb|At8j%X;GoksaEc(0YWIiC=C>4z>GOQ$E~y*fF@G}GOTIV5 z*kac;!Q^`5Yy3-BDE#yaUnvA9^g0IMa{vgo>>Y$$`|pn-7%Hqk@50$W5f%AUyZPls z8q$y_&rYB+O2Yl@TYMNi2Io7>UQATmee11Jh9TTbY)sOT%6vl)hNuJ00P^AYEH0&R zE(GR>*WtQiGjGFQ_$Sipw+LdJg+E&kKj?bM96)>j)wQ5mgRymWe0qCm-QqrpbPNdP zS%Qhg003;JRmBld`o7F5JnRL>Xr$ac^=cM_t*hM0$R6xzF?sH zR#N=*v~khAPSqVH-1w4vyHdm?AS_c71`{0}L8VCVY6sZUu-q5Iw=^1HQs!V7nEjQh zCW(I@yYAx9qnpP%m@VJ!Ysfx9p6x;Ms6U?M#%x=+?=eqqEC@dg?)M`)w0Uu7hRRH-DCFDIXbC+ zc<_Qjgl5jEg6fLF&Z1*5$k5U)pZ8&@#TJU5HnsgbMb%p!1!$kCyRRs|7N9j~T92yk zcUSFjy0j?Z{T|Cn-&pxz@<+-EAde4a>Yx3Qz&fEsejWbknl0wFJT5rovYsGq`;PUB zXZu}B?bAuWYLn|h8A;IZW+kwK6CnAtsJoFE4I($`{bgrG0iG_Gp{xhoLZ|ed_1(2 zBRNTtM5syH$boLEc*x6Ghfk2*!tKqQPj@Bn5Qkj4iL;%9`_lMGK+Hr0G4w~pjYU}- z&bwG_bzVi#s{*hJDXxaBIJqcEJuVIM0RzJ(lhwTsoRDz17n`I}XsAocEuS@T;^>K< zM_CI+TY*b|M+OQGPl~hy0yG}pEmys->UJl8B*^Y;2*@EEgI63z?8mJ^3lpMzwzZaR zo=;)c|9P_O>$H^cyYaJ*%aDCGd?dw;tSO3 z_tfl?RtPFE&?#gQUx4j!l!LjW8v)4DLFEwUfsS$}7WwCi$^+>&68_6|uA5@>9z0zj z0wYMwxyC+PF}Hb@3e4y(GC3Ypo{OR~c3!&hw((A!QVS=DEq)CSW4p|qT>_#^mpaM| zulMhZ*oE9&^S`~hnaA$-KWU5_u?mI54l^=C``Gxg*hVEzj2A2^wCiC2W7aR#tFaUe zsr`pk1w0xi2J>Pm2kVKCw|q`RQ}ND}zdGDc!7HpzY$vX+`AkbJa7qpCt*M;@7aJ!0 zyy_|=0IUXA@)>Ey)91OaW)4)Rl#*txr*)2zat}KF@nvmRj;Bib)-vgIvx}=Mfyaj5 z2tbmteYltc0H^^qFLNX?DyraFQxa0AMNR@yXQfKsf`G7{n5Zyul)>;gB$SA=rp|;s ze1wm5K{d>{Gh2sm=ZuIzeNRC5S9{#THM8QbjXwS2$8Kghj?KkL{(Oqq!+?!~KfAL0V^@+|DyxN--h{=TeTt0Q*Ro-#<aFR39pG(nMaF9R#vUu;`Fam(ijoH_+o{jzh4 z9WLS_E34UtI_MKcsUV*|GHtB@mI8JDbsR=+ zqyXi#=g5rKviTc>b#%55rENPFR&$uL?i`@fV~GZqF$S8ajoGN?+a^B>A6MYZn68;T z$Qf}H6)>?pM0gA*582d+?4YMyqpVpCa2;Nc+$9;Of1g? z!pWaf?lx&}?d_W3P0mjXfwvD!4eyuvkJT*uFfjdeBI>%7e#{mLq#=EUoC1`z*}2e4 zWtXbcDEUKtIU47e`RszN=az%<_cw!9gO>b0(jLEeTEcz_@YHx_P~S^2(j)%wu5Vgf zf#l#t8eKl@j4E+4QJK#q(VL7G-a83mNSJ*|hSAi17(vF$m7v5O5iuA5qaq(w0tn+1 zXKTdf=`x|Z^2eFtQja})gZt(Ph!FPfV2J1wd~$07cb>><%iH)l4o@!XQvb65bskPz zHT7E7wTS%WVx{P*x>&E9L8T`1Uxx1QEgDRk{I8xemdg1%G*=&%W3}|&5@?JX(>x`f z&Ej#UNt={I-E3TG*I>$(^p7sD@nr`#4fPQvU88lDptO^BN@qe7cT@|ovocq836Q7@g*PHCp=N^+rn_Gu16?dm?=xsOJfVN>6j+eNH_Im&HZ$E zvKXJ11FQ}4zyeI3@(MOeRUXK9mm56pd@*7gZ4hRMYp+F8Y*|(~$_1kY)0Yzvy%q_l}Ao06&Yc zNmvV~1>Otm>+9FD1(4gQfFgxmj;Z$rj!{kYfo8-!wb`Wq#SajxJRwQ$a2f_h92|8N ztZR(>U{DTuhgc+1ankOEK{K0)A~(k{7NNvsR*j?)u3@^;Gy0T#v`vhuULn968d_EhCtd!Qqu?!b7v05EnJe&j& zV+MEtknCG877=13jD2Uq;b2@A(d@3?;=v)Zzhon}m@t|3q^_A3y`ACyIDDC+#Eb;g zJ#%EzJKL}PUTMiJKq4dwfJxZ>*Um)B6B1mwh`Jaece5KHVnPAkzlT_$=Kvn)Ub88o zqJFIhDgOGKx{mH!ru-Tm_?MmQS$!OxDz(B9+c^fRGo$xV-kjAatqpFF>KkLEN~MyV zGFwN!_|hhS_ljpVI9Wg1x#S{Ao@8JudyZpQWQMoX=haqMGBeG2!38)BmVnwT*r z70@_`t&X(gsW*5eX8spe(#Ze;8saK1>Vny~rF*x=>7S9e&6Ju1nl63)f{>B$R?*Fq z)2(q9ljrNdrc}KwPBy7<&?mSYq)|*8A4>!GQ%==EYzmjjVtl`TpAi{W&pLq=% zI6<^4s$NBCc5iQKXoY0&j`*@cQ{qCZYjJZv^?9gNaGtEm^I3EtYH_LZOP~Hv=`qa& z$|P5Tv_u_OWVG_Y0t&hOm%4>cez{+s2_;nox1ep#P?l7kdx-7E#+1pED|tdy*!?26 z-f9lC3BOQS$!jX9YKmB>zmr-r8;swWXKb$RU!mdbB)aZ>cH+08<1EC%`TEtE-ZNt} zT}tz0UQ)5!@pXow+$uOHY~t_#-cq>d4Fhm9PPt?S&;(8>P#vc(SC z-&H08PdaJ`r&6SSKYE3<=h$zjTjjrHXCKm2lqR4wqd!pHES+aJ>2c+=U^f%cfu_@P zwJ}#QMpSJE$?2gMN4F{a`u7hg6krNz+tzz|Kl~Cid^Aj3W`fUmms>vHfU`>l=M@oslp-SUF$?U! zoAUkU`0q>~Dh(j;ShH*d)8^3;J7DMhRH?FY@`th;*`0BotC`_ISdzoX^3PJiLC;py z#-Ddv=x1bQ$P+;UKq@+~Kv#48$0Aev&-@QydAU^ZDf~2Eqhyb)Eu|$7(X#z-i>eee zaZalj4}W*5wrjfkr$s)7C)l`0>-x{D9PY-gE5K5pRaWS7H0VBkLoz!0ZgpR%0qd?p z5Gz>ZTU2OE`rAsq`*0kUm%CGn0L-W(rka8h6b%A-Y1NN=2q%Zex9nzmT+=ds*^U!w zYSYP=x=_BY7o$}(e7F+)QR-E(y{F8S8Q80N0Nzcnp#E>fz=5ANopY$`6m-{2hnanI zf!@_V<|x+tzx*6N8(VM=W?u)9i#(La!W6g)!Zjxnb1Fleid?nte}wo!OgDZvHa8|@ zd@9pmF8eV+8LCpQ;2tQ%p~y!m7#e3IX0M(F!84`^kCP*fJc5KC=7H~tB}X70S1%mE zMi6Im!H(0;4qcqIZCq3gstHZ@P<`H{s#Flahs57i&($G7Zr(7He)@LVLoKnQFT#sM z#e<5Di_{u&cWtou<}Mo)lbF7Crt6m%RvqZ;NJbU~*uR|i<1$YVHePPEviCPI%0@(q zsW(ZqxN}PwNUF}piOF%DAe8sSebz)nDgO_Zzzb*%}9sb3EMGgb+<3b^I-88};Aa8X$|HP6%X9&?`E zX;HLCkdxz?+74CAq(}Zi3^<=Hadn^iBtzGF624$S!&%dYQ?N4t?8 z6IxDTf}MEREwAX3EMc_w6E}M&Vt(S`Qj>8u+}y|)cev@ zATGS}m7<8TZ>)(~{BfS2n!<$7%W$cRvWVViPL~W5dAcFbV|nii8_3lC~ zDS4mv`h!Q-zrN;hLAqsrU3@wn^!lkB;;4i6A}(N}y37ARKERo!g5TvuQv(9H_?at{ zeBIOYzGUxH%okdBi)D&ApjCPv_npQ%pY|2Gfkp*Ussz_fVU=;4vzT znpO1O4g4lD&k|>H?<}iZst0aduXFE1OV`st6Sm5VU&7m4qAs6YIb8Os7Ce*S3dGIK zoIctLQsRj=pPEyMQ*4qQJwdcDt5nlxpt~FLgZi zb@7O+U3%N;IPvYZ!>?~GHH`LE^S|4CBuqr>jbi_L*=%hPO*Q^qM75cuP=PGd6s*hlH2>`FuaAUsE!9}M&i-3GHm$R z(+PgDy;Lr+WYDsfEUj+9ZU}E4tL8V!^K@&eV(JRq<=Pid6-idN#h>dtPTaCjZtXAc zJ>o8Hj^l9E33sMc?qzTkuhHaDhyZ}o$pcMvn8JVYG!DNF7Bn!_ID08mrc|Ue*W`m< zx6ROg!cWhy|3SX#n@!`!P786hr;F@pO+TC2QJhX=FLw1=?C*h>W#@|LLFEZkc`gn| zjL0;IrCml;?+NhLP(wcmu(wk%k4X!BjoP?d@D!Lcw`cbiQpTrXlQ4NvFCYfilz%N{FPI$lP*rCP9+pl&E#Qdw<(&o3UFvwM{% zvh&_BNtcfiLaP@}FS*Mb+ei?G9|Mo|>Z^)z2f86~4hP={2I2lx*2Dlf5ljgHlbKW1 z5|JFxLlS@)U=V5ubq;-zusjAJ6{JB!?QYBJO9>a=O_Tt7V>}5#n}CsM07jlV0Sa>R zZzeIMI+UswSAK^vg`1&^z|Tpn8HxmpP=JpbWwvF@Wf~nqGFYRE?8Om`xVQ)bn=qsN zdy3!hk#6>PM9SJk?rW5&s5;jRUv|&={7xW*B@Qm$^7#gsJIeb(5D8cKDqKjLfB~X% z6VbmRMed=EZdIA(Hb1P}&|s!AvuHLF=tZL{^r?Kr@%$%GrA z6T&3-^qNHGh{P;?MOUB17P4ndfY@lgvxnXKZLr!c*1l=f1D#D}Tsz0LVFYU;B-d6C zh|EjAOBv9FCR?LzXdV)Te5i8F_mi3Ve7;8}-EVoAlhdnvMdNPgE0fz&;8M4jDAX)E z9KzdSpujc5=fZ6lvgN~C9(ppsuRD5L`qum^R#_;}|J%2-0SmfR)q{h=gsot$YIx6s zFFUIdQwh(aeLK=W{JS~(clYY%)32xiG0!jV=-0n}3h!Rk%4Ujm)Bx}u?X`QER&7p3 zzVo@_bN<&K{tdt)0J)~G0f60KxrT^gK$%D(G!!m*np0t2eTOdY)$iX008+}myb0-z z+@-)$_*>fV*QJ67S2XWXAEah~scDbz+rxrF7$zrAscT;IuI;>C8AkNIdSlgR*u}-d z&FgvZ<-*Seifj8>E9vR!^eiTkAF+GEUlNP;ca@TTx`3p10X9clJJ(h{0yUsgjc6#;B!EoPlN}FY@Y$3P( z=JWJQ(Zm$*;}g|}@2kT!-r$U-U)97P9#M&(OwYgh5r@G85bI{b1ORBsqQSw&{;p_6 zPWwu5bj2OK5i&i12-HiR)?R*qJfm|6Xh;~kKClm@4SnN8ZRdQzM{v)u=uq$1vDi^@ zJG07+%p1z#N_r|a$)-j&y$IW~QLSGI?eUhY58v6|7jcws9MiXe?ME?;OqNS z*Qy4GA7v!7d+O*=(O4Az_}Es_-p`+lFCf+Pwg^}Lc=SOh;-~)|ghx#}|MmV*%bUt8 zd~bkJ!aZVe-PtW4OCT-KPV=j*kY+EBv&slvD!4mAJx}Oc>nvC#K1m0!U-;?sCHZh_ z*hp!VJ1;Hd;|RPn1_BjAqgqDrf#QiJ3~Zb8GI!l5T&w*=WFJWyS7N8rCDd%NesImMomgkx?UV_1Jh4`(Z2|3h*BKCq#M+Lte$UHUxWne9`Y^{^3QC-nK9y*!c z`M4s}K9zFf{=4Bl(KRO%x4hYESZSEUHPz#5gPLpsC+cJ?uR%@#$QK`^e>kv%=tm@L zs;VG!0J<&#m$8EcK`g9(iq4?#7`*C3J6p3POoi^9mT>vvagZJcqGPn;;;PbX9qmP{ z8pAr>f;1|piL-0`E*Be`60T3lT@@prKa#824U`qAmbv943{I!HudFL$IQ|;JHN2T2 z-LNobR2o+vnt>HtUp6!i7Ll&zyGOLnFxvNmX=God?xv=eslIL_WPFTBtSzQ9@g|L9 zD8cIwBd+O_mzO?G-6YqL5fudlZY%f64nY8##DaV1SB1zBnbc3^O4~B(cdkmB*;^(j27W^M?2XkN;to z&x$LVf<;l3&%5l%cF)bVu$G23JKv|tdD;fqZ)%Nyx_>KoCMxCyAFlkp6cvB>2LLeaSZlS~*szs4`U==+ z9Y`MsC=vXpFCYoWqFPivj^Y(5SzHp^S=Qa%lPa~){)WKJA%5+n)Pz--WOntmsZ%=K z7Mu|phDU6j4B^yVHkr!}dnhzQa4?r-Kdi@nPwzgtwlRmLIclPkE4)*Jb@cHaoRDz<`c(%gUNPz#)M?e@o21Z&JdB1}iD_E1$tBF0& z&7^OVKC($uNillrjBO#eFb2G^_b znQxsnKI8gKt3dbTWzX}$>FMce_D9!`SgI)P=Z*5rWwpXrbKK4_!63;V`oWbec|A&V z8odi_FUTw|sPpY70)lNaSXL|Yl!7>vQk&6qbP(=UbeVw9Zh+3F*eQW#_dy_NxJz=1{rph%&Lh)H`89$E-QEG#GCpr&;{_h!7l!gI;enQl?9&_Q zi{bMUa3fCKWB5hym6r z+uyn6Lyhw{?$Q0~!ZkNmP{Z9?Q;Vl)H0!GpwRWu5v;2{CW_6Pc=Hl4`NHanGN$aL% zmAWTnV?gTTOMl;hc>=_-fIu~f*Jo1>eZFuCiu`X4B4AN-6e0%+q+5b04z zsx}pu(!3J0-ro1+W)O)ya0gLN4dXN;!+7w%Vgp}7z$0`?74X?C0`wNk$-V+aXh_>5 zqOb(i2>Ivf#wNL`N$XTAWk*zF)E^OHDV?_1q54kd2*xWspXRgoAvZtu?lEzS&fAM- zmCOQgn<&W=z4a+20W4^2HY%rhEHoYz2dN)&R5hiPAwZK`hwk7<@hHMT5QOV!YtcZT zvwNL8b0|ly^Iut`uT;LdcHpogXHgb(`Yj(WU{cyQ9i6OS^rLx)KPT&jevvg8H0JP` zG=*6k0aRzP<#nYS88*<;Et&xJI@~Sz=@prfr$~$I7z29pRdHlzRh>KHAMH@HEpKmA zM5m~w_fIfa6LQ8AJvq;n0Y6h8&QT#oXO(DHQJHW~<)6^n>b8pTap)a#GE$Cl61+ol zmv>aP*B-VTS?v?%?Gn)CNqg;NFUCH0d!H@#xatIV#G4-|=ckrDMYq=ufB`8o#VKH) zm-+X`gtWX4k^Od+_Cc>87wO|buH>gc$R@b)6qjL{JWuJJDkZpzCP=Qg|0ziiJnq72dHvSMeP8TB2NPwIT~3@-l9_q#@3G-v9fccg_6%^@}V^&e$_r zStPsCJN)?4>^AFc>-2{EqknIbph;x(gcM7CxR3{U0pWiBrXnOn=wkh1U&TU(0F?zw zC|cgJFEwri0`f8=_CxuysI7LNRM@8+w@?_jVghq~KKWVp%L!adWWJ$FQH_e+(?<4v zV0Yx{u(P4i!d>LQ7+JL+eI02Ftl=q{H`fCM_)L`mpgi@a5hP+Q@o7*});s|Nq6-E` z+6~1sLu88Gh|A1URDf}uVU4$Zw1A1P$y9WT+vmE9tGG+W*E?XBaEY#_S7Yu}q|F>A zemm2;D^Rb7>>W>c!Vu0!TF)v{rYqHVwUhQj*q@7bpWJiJyt!ge&{oH9HF^ zkrcE}10W-Ikmg`S+m@>7ilqz^+DrK=iQW+^YUNQ;CaeO&C1;V-=y^qX#m$DMBAQ4S zTLpo?KIZp(ye$FST%7OyRN&gQPaW`9z1#Ku1fEvzAej{-T3=(;6^8~II+qX9Fi3yO z`Rto(BY&I^e-hQ5N6!!y?W*%#s!dO(U6I@HuEC08q|x zEFr+zvwCuNui8qT*>;>M)&yUxCnJ2H>4h0_9hNwPPdnX#jzih)4{y_lTRyhn#4lu$ zI%OvPbu_zEc^v4o#q6Z(Mjk>KZXp0Ohnt%w>Sa{tmvI1|n{d^l4wcp)TXnk!si)P2 zm48IPNa>5}(6OY;$L^#$in^SoXojLL16yLFKs7owFntjlO&H|&T=8l@rc@AX6Zb;r z!CJH2+iWF*D>(`VB!g|WqXKIDt-q$r4+;jGogn}*!a7>Q`w2VsU2cf7dNSyZ86||A zZ?I=h!0}V~2@t{J6WUQi@`>_+AOC2Z-@>mcaBmZxCU9kb6amVKIqyy+vKsm7r z+S!vWEU%#AYbTou4E4ub5fTHjn%hf<^=~mvUsk6KE0=GH#rfjLaHSeq z3W4(tdkzou(2f}=RN@VR$LXZLuJ?2O?U6cVGr_Zu#WRwZUtBL(y$)QOyWg3hv{xhX zBB|Y$X)54oA~3(F*Y$O9gqTq4m7sp)$w`Y`43}>ro(rv<%W)p|&o_H*A+ry)DK&8o zNh`9U<$s5rICv-k0Lkgo)-8pM$&{AmfI&Qe!u_anbyTJZmkpAvpCJ;+)%NxmH9sC1 z5m2hIyHwAIWCh+pefK0rAY4d@IGlrRlNUkufJgmYsDOG;b7Mu`vmfMm8$VgVDV2gh zWiVgh+m;Ui@2n?qnpZ#r^ktpv!P{SF!pYmQ&vgnwHJ?DO>It4Y|uHe=B(LGVY(el_2*Gr2~8?TCQmH2Qb~ zT5FD6T|Hl7v-RACDE+I`Iyj)}xwX1Ny%5mnK=FL}!$WVrX-CFaFT1;nQ_Xy=GSeoq z-tF%dK_MUpZ6)Kx^0BW~E?9fbTRx2#vi^eKr4iP^cP)>so3gr;67A;rIsBT<)eeuv z3CLP#kqUon<|C=yMoCx24Mu2@sxAsq-hYnvp6rbq6GUq#M}%q2^Ausp$;qqgsjY>Y zGE&P+_BGEZbTe&BNNwNeV&ElV3biB=m%La;`Us*(00!XOZn+?>iW6>b934D*STCer z`{4tXc#tSo0Xxk1X_8Xl>rqPMl6vnB14Cr3wv&n~(|Gu_Vhh?e%4p#Z^*69w6y~S) zPJ{##&AuJuJyPoY51y%u95pk$M|2g6W(i)oB|i?kloq)4!evqj@uWVxwm6xNNlY7Q z1Q_lvRiwQ=_j~Q1sj_hJQ$u`tlr05O+uIHUSS9O}mPm@P8Ag9C78x&~+*iEiGXj_< z%ellOof{h#d1M_y)`cz3&T5iR|EtQ-B8l_JLD;M8dVb5;s|T4iBAb&9pE7Gqt^x0Q zDl0(ptBr}JrHJH*mS8+&#(Hbwd?~S8{G1O*z`&pqTSYsaHv zlA|4YFy@{?-Bi`aS#+o%{ke@=e9^RE(|;vdCj+})C!V(`8{5V?w}rBfuJjOhkFyP+ zsMDwNk2y53vhfj?6fjpe)-3z3ob6JlZx5E1@BhIv;Wo!ZwbCeJt~{>3u0mbRZZc$R z1;$^~uP){17j0Zeq~fzE0Eyjg;}qX~_7`ujonhp1+$$?e(-W&A=b3$;ZyxY|QDD2? z^F!;F6i+nO)w9}&%44tg6SLN!|N0ZwL#Kf`f65cK=zE(V8MTmgxtQ^a-C5EqO00gC zQhgz4Ci}xMigMg#+KkA6mT6sk(0EJD_pQ3BfOvGCOT>wp$z~Z{%5qKjkNIU9`-C4a zlaH+d%2bL_;|TZPnn)_8*(yCwjpxUcO43wOp}20#JB&!t^D^cF^AGH z?T$D#d@#6tFisMU!NbWswDrPJ%hW!i_VKy!IH`+!Zsc}1qLCDN9i>pXzW)JU4BnZ0 zUND%LT{S5NLPHX_p@vdR#wQN*_T16?jE{)*P2LvRd)=hY8RJGp31zY_wAD!VV(jB3 zgwq53fI{@5ohE9SkB577 zTM=`q0Od*hl=rBk+h&{V3;F%39S=GsZAV80LYblQP|M)raF&ztvhxKOodbz}nz*C- zP0t;6eks@<`PPJKR${fo0`seU0OAlT%at*Y;?0Ld03@yOhWw)Axos7MMm1blz2n|A zS3KS&Jk*pz*mO>_NkZ{dDx8O6LQ9tX-M^TL1qnHf$G?{oEFAXfS@x#d8xe?^PQUwN z#JkS#D(b`gM}J+>d+ip@#s+45%U=T88Z9pJvg&jxn-xmq`S#>Atk1b~_{D{{j z?MFl)0}t^iUoA=L7&||<;gQMKY}>Z^@}wmung_{Xo~mv3@_QhIIcOtmF;oR2X;i=H zr-mPz0Z(CGr4}EyZoBvaJ z0N_j76Otw>l#}QUnl@L9902(fYWvIZ1a^9fE?!JO=BC;2%K9s($F+9CeO;}JO4l?& z@v0g6^qv^!Cd9r*tV_;2HYJy^98#$$9|!Um&m2#;ut{|QUjroKvmy{v#Ebv+Clq5C z(zR6Tc0?ACLi^sC6_RLsXjr}aBmHr0}PtqIQsSNeAhCDuWeZ(WZkox;h9E$ z{`U^#TCUKC_LYUg<{%cyZijC?Usm6(^pR0;17bhd|IK$AER8by`_Mc8&=p?|6O|T= zFe9eT&!~T>Zz8DWFlREni*FtJfbKSaOaU{O4@9HOCdPraj@XFoC-TYe@}*k)UxGUt zd8JTk8rhTYTk0tvPC!d(hg`!8dL$Pg8*nAUPygunZ@kMo?j8Ggt|O8$^XY}#MaW~i zXSoM#9gfkIsSJ$Z<0h~b|D7fIES#J7pnM(=>|KzYW#)p)p9SDhqq27%nq3*t;EFZZ z${kkk8x<^Nqg2;;rGnJXA(j={>$K>96?4J-N1v%Z{zrR`*YrUc$YAc94*7!elr@Fy@Q%W_NZWBF6&b z{0BNAdb%=#;3-(TAp4;kC2>=Bj@F!1|7_O-9!8^o`_sGvF+apt=Py_oXz?Tc{?qSR z0cK<^#G}h57108YHc_;lh@BVU%FH(b$-nnLQFR^&{3W_POq^*JekgAzGS<~{#V2>k ze=;d2%TQHb@lfV5Rv5d|;nPKvlWlvL_brr0e783zF?n8kXV3esgIf@Ioumt>r1^{BV}-7NToPmZ zNpIGK=}GGsLtWmLWu?4_Vl}i|?yCCM=P`M3|U#*Er*T}hvjIsIH91b>vc`{BhS1(ZQV%)N{e`t~l`gTxoBDp)FTKctO zMgsSNej%DTlSIbD!b$jzJv*s5@}bV05)f-Iu!d8#6b;slp5s>k%!v_QZSq=s3NdGh;tyz|EetIm zKPK{Vnr3?V*Vc)THTt7-omzoy#*J;Eh*$%Z5cJPJ7Ase2o+uKxt4jkOe*7^M{3lWE zmXA7kA>T=utnpvm<3h*KDVg62|CtS3?oudC!zj@R5Jx1?anT>97hpqtN*qT{2}y>v zRD@xEE~z4+%6n6<@R7<;oV{s(oCTF9Hb&dSqSV*sL_sAOIjf6*hevWPm+%SiWGerq zo4#eu>1KpG9fA#^8YG#W)sd=iXMlch~lCNT=;W8 z@_A;(ru4g(33Cd0)s4azC?ZIe0YVH$3_uYLF_Mj+t@4tGja##tLt;V6{1oZQ{*`9J z`|IHZKmsJ+Vuh7sCfUgPK>lDu?kyi7@S^;sG`Y=pMGD5M{wbNNsB5}^&f}rhmdeo% zCftFdNe|U$|JglPqT%))jmqCPlo&H>DB~Fq#3@j&OK@ zt^~G2ZS_t=n|-KF&jnb=q+Ny=Nw2bKx~d=J_a)ZA+6kUMwkVWCAL4cMZ9d`dpRoZf z|Aa?bYc^jQ*&*RcI!nc)qv0@nlIN z>V6@Owxx`y>;uBxtQgWIFQhA--VD?_@yrB?2F9KU*VUN98__G*nWB?BbI;^g!pzzMpBO;tciDqrt#%L#deL6-=SzUX4y#7(@J>yPE%AUfJDh5mw-$m zKNQl?iC65s5uO?cotaTh{S_D3eUZ`-Y*6?e5tzEjYNd^TJt4+;swQ6|&}n$0x> z^6k#V5StUkkV-eoGef{=E*&b1x1Q9AvEPs&%spxtgmScN^eL!6Ocy62x?dOL!2l9B zRgB=G?!Yww%PT$y;FARx|Bxr(mud!ivBZ_(H%THA`ID`ekQQ@K|LdPu15Ta3Gvs&R z)tJt9wW)h;TGhsu0A>0lO3JLEMT{YiqrgMaxe*`;$dCrQHdu$k*lZ(ur5AotZI2mKZA~e}2+g8Fhhf+iKuqW=R zcd)++803jdbu5E-6|3MQ#AVs4>}D7jU}m@LlqrjX-qXq$Q`JA=J2xk(QZaz1=1S`K z@qg37q^H0vaN)id2!VuqswIj49W`YzH36M7P>K&ff&>zZv0{&)A7VEjMEKCW?Xw|S zz8Yooft)*BVKw-hZ{x>2bgFUeKIs>(xdm8tac{XVX#^EBGY7|GXJqn;`(c59vndVP zw!Nrg|J?b4>PMvfVxBo(S+f-&%XHhqSV+zqN5o`G#iV$41K7V z2a16QWs0QKCzUZPASa_FDFT962y8+Tf*Ak`-5HsCmfBNpY$A4 zh`y?w__CrD%&WVUsT-upR)*3YBhGft#ZPUv(i}_FHLA}(diUU#k7sC7QIB^0QS@93 zU3GO`ldEjm&0)>087&h$Q-Kc4ltyjcXV%1CqJ{Wqs(1d*qcYhhqpGM${nHMKdsl9) zm4dF&|JHsXW%W09j$$BvoK^IB(ELQ$dMhlQS~-X_kSel}AWw>)S_ z_lrC7K#~A8 z{c9g7H*b0A!P;)DR`U<#ICGCeeOug1()o>h?#T?5YUaI{o?!9|C7S^I^%?W2%gH!* zQQjGu{lY)=iWuA|22kUxHiiNm(G(z{LW0lv?j7wcG_kgQ)#!kg$wwQNokXZ*y^=gd zsPzWOqG2haaXg#nq3VhJu%&7FxWBq$8QV4n;>kX9Uhw;tPZn-(0Zs`@Ca+UoW~}pura{`BpOJkM!sV0HH%8yrNAo^+B2;7?iWFd5 zJnE2YH`1>d|OkPacz$M|XQ%u_-v7X)W5@{jGn+(|3yLa|Op;-cHR= zZXD3Y18;=W7Gkm^EN)1mNa40o1O;eVHs-}sx`daf#1{lIvjpLY3a(CiB-{uJ`+-68 zF}kOZbIO4M5oESa3IOXya@XDVVY%DQ9>kwQSlIz*=)kly#!MK4K002(tpGl68cVJ( zu1qKz4Ha(ugdGl3k4vWXO1)__`B|f_praxpAcRKO{2y$$eEI;;vTu_9c>vJ4DBGZf uJm7z`pZ}`^{cra9|NGy!e4c{)0KhUP+$$GuVitqbjsE|B(*F<7?|%V>C$M+` literal 0 HcmV?d00001 diff --git a/backend/static/sounds/wuff.mp3 b/backend/static/sounds/wuff.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..648ceeba874abb6698ed37101852c88e70f90460 GIT binary patch literal 5087 zcmeH_PfEi;6o+4Faj9bWGJ?2kY0}n}8^JD0TM!x{x{YkX+p`O%uZoK;E;igYdE!TK)i> zDDYs}D<(b1$KJ#aBPZ~ouIX7*V6z{1V=H!guAT0VXgj___r^61jHaRE5eK-k+aJxR zLpvPZ_yf_iT{qqnCDA#pik9p6SGF7D+l_9wf$KMMecPH05A|}jtW_#l%2<5Hvn=!2 z^oIdXw(!{oC<@pmO2iS-A}&%K;+A+I9#fu(XJSsgro0m$#DYi;$8YT8H)>ik$=Kgm zrlN@6&b_SsOC$Puf&2_|Q#?=r)b0Ta?c+{^M4qj%ro6J|uT2s^ci;W2`AOwxd4H52 zHlXegtB?leN2-O3$`7lM2IWVpg^S7$tB?leN2-O3$`7lM2IWVpg^S7$tB?leN2-O3 V$`7lM2IWVpg^NG&!<+t5_yYQBON;;j literal 0 HcmV?d00001 diff --git a/backend/static/sw.js b/backend/static/sw.js index 31f22ab..f652d26 100644 --- a/backend/static/sw.js +++ b/backend/static/sw.js @@ -4,7 +4,7 @@ ============================================================ */ // ← EINZIGE Stelle für die Version — STATIC_ASSETS und CACHE_VERSION leiten sich ab -const VER = '1242'; +const VER = '1243'; const CACHE_VERSION = `by-v${VER}`; const CACHE_STATIC = `${CACHE_VERSION}-static`; const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten @@ -32,6 +32,9 @@ const PRIORITY_PAGES = [ '/js/map-offline.js', '/js/map-gl-markers.js', '/js/map-gl-mini.js', + // Yaro-Navi-Sounds — müssen auch im Funkloch bellen (zusammen ~40 KB) + '/sounds/wuff.mp3', + '/sounds/klaeffen.mp3', ]; // index.html wird NICHT pre-gecacht (immer Network-First)