From 064d717b9ff61093b7b1349913ddb2dfee8d67c5 Mon Sep 17 00:00:00 2001 From: ewowi Date: Tue, 30 Jun 2026 11:27:45 +0200 Subject: [PATCH 01/11] Add HueDriver + WaveEffect; fix 1D effects to run along Y MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three additions plus an architecture fix. HueDriver drives Philips Hue lights as a projectMM output — the bulbs become colour pixels of an effect (paired over the Hue v1 HTTP API, listed in the Devices module), with the master brightness/colour-order correction and a smooth cadence-matched fade. WaveEffect ports MoonLight's travelling-waveform effect (six shapes) fresh onto our EffectBase. And a correctness fix surfaced while bench-testing the wave: 1D effects now iterate along Y (a vertical column expanded across X), matching MoonLight's verified convention and making a 1D output the natural first column of its 2D form. PC worst-scenario tick:474us; ESP32 tick:903us(FPS:1107). Core - platform::httpRequest: new synchronous outbound LAN HTTP GET/PUT/POST seam (plain HTTP, no TLS — the Hue v1 API allows it), reading the response straight into the caller's buffer so a multi-KB body fits and a fire-and-forget PUT (null body) still executes. Desktop + ESP32 over raw sockets, off the render path. - DevicesModule: lists a Hue bridge a driver has connected to via a new static upsertHueBridge(ip, name, colourCount) entry reached through DevicesModule::active() — the AudioModule::latestFrame() static-seam shape, so the light-domain driver registers the bridge without a structural core↔light dependency. The row carries the bridge's colour-light count (for sizing a layout) and round-trips through persistence. DevType gains Hue. - Layer::extrude: 1D effects now run along Y — a D1 effect writes the (x=0) column down Y and extrude duplicates it across X (then Z), so 1D expands into 2D by adding columns (the 1D output is the first column of its 2D form). Was the reverse (X-row extruded across Y). Verified against MoonLight's effect source; 0 D1 effects existed, so no effect behaviour changed. Light domain - HueDriver: Hue lights as a colour effect output. Pairs (link-button poll), fetches the bridge's lights, and drives only the colour-capable + reachable ones — each window pixel → one bulb, RGB→HSV (textbook integer) → {on,bri,hue,sat}. Rate-paced by a millis() gate in loop() (one bounded PUT per interval — never blocks the single render loop, and keeps TCP connection churn bounded), with a transitiontime matched to each light's refresh so colours glide. Applies the shared Correction (brightness LUT + channel order) like the physical drivers. Exposes a colourLights count and lists the bridge in Devices. - WaveEffect: a waveform (sawtooth / triangle / sine / square / sin3 / noise) that travels across the grid leaving a fading trail — MoonLight's Wave behaviour reproduced on EffectBase + our integer primitives (sin8, scale8), the colour routed through a single palette-ready seam (hsvToRgb today). D2; follows the 1D-runs-along-Y layout convention. UI / wiring - main.cpp: register HueDriver and WaveEffect in the factory. Tests - unit_HueDriver: RGB→HSV mapping, the {on,bri,hue,sat} body, the changed-only diff, and the colour-capable+reachable light filter against a real bridge /lights shape. - unit_DevicesModule_hue: the Hue bridge row + its persistence round trip. - unit_WaveEffect: each of the six waveform shapes maps phase→y correctly and stays in bounds at any grid size. - unit_Layer_extrude: the D1 stub now writes the x=0 column and asserts it spreads across X (the flipped convention). Docs / CI - architecture.md § Dimensionality: corrected the D1 definition and added the unified expand rule (1D→2D adds columns across X, 2D→3D adds slices across Z) with the reasoning, and that a 1D output is laid out 1×N. - HueDriver.md, WaveEffect.md: new specs (with the three Hue screenshots); DevicesModule.md: the out-of-band Hue-bridge listing; backlog-core.md: the pair-once-in-DevicesModule + mDNS-discovery follow-ups; EffectBase.h / Layer.h comments updated to the 1D-along-Y convention. - Plan-20260630 - HueDriver: the saved design plan. Reviews - 🌊 WaveEffect ports MoonLight's Wave (Ewoud Wijma) — behaviour reproduced, written fresh against our architecture, credited as prior art (no code/structure traced). - 1D-along-Y convention reverse-engineered + verified against MoonLight's own effect source (RingRandomFlow, AudioRings, FreqMatrix, NoiseMeter, PacMan, PopCorn all iterate Y). Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/architecture.md | 10 +- docs/assets/screenshots/Hue device disco.png | Bin 0 -> 73925 bytes docs/assets/screenshots/Hue driver.png | Bin 0 -> 86751 bytes .../screenshots/Hue friendly effect.png | Bin 0 -> 132258 bytes docs/backlog/backlog-core.md | 2 +- ...Driver (Hue lights as an effect output).md | 83 ++++ docs/moonmodules/core/DevicesModule.md | 4 + docs/moonmodules/light/drivers/HueDriver.md | 47 +++ docs/moonmodules/light/effects/WaveEffect.md | 31 ++ src/core/DeviceIdentify.h | 3 +- src/core/DevicesModule.h | 48 ++- src/light/drivers/HueDriver.h | 377 ++++++++++++++++++ src/light/effects/EffectBase.h | 6 +- src/light/effects/WaveEffect.h | 178 +++++++++ src/light/layers/Layer.h | 21 +- src/main.cpp | 4 + src/platform/desktop/platform_desktop.cpp | 71 ++++ src/platform/esp32/platform_esp32.cpp | 62 +++ src/platform/platform.h | 10 + test/CMakeLists.txt | 3 + test/scenarios/light/scenario_perf_full.json | 8 +- test/unit/core/unit_DevicesModule_hue.cpp | 51 +++ test/unit/light/unit_HueDriver.cpp | 65 +++ test/unit/light/unit_Layer_extrude.cpp | 40 +- test/unit/light/unit_WaveEffect.cpp | 57 +++ 25 files changed, 1139 insertions(+), 42 deletions(-) create mode 100644 docs/assets/screenshots/Hue device disco.png create mode 100644 docs/assets/screenshots/Hue driver.png create mode 100644 docs/assets/screenshots/Hue friendly effect.png create mode 100644 docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output).md create mode 100644 docs/moonmodules/light/drivers/HueDriver.md create mode 100644 docs/moonmodules/light/effects/WaveEffect.md create mode 100644 src/light/drivers/HueDriver.h create mode 100644 src/light/effects/WaveEffect.h create mode 100644 test/unit/core/unit_DevicesModule_hue.cpp create mode 100644 test/unit/light/unit_HueDriver.cpp create mode 100644 test/unit/light/unit_WaveEffect.cpp diff --git a/docs/architecture.md b/docs/architecture.md index cf101a8a..933ca244 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -373,13 +373,15 @@ Effects know nothing about hardware, protocols, physical LED layout, or mapping. Every effect declares its native dimensionality through `EffectBase::dimensions()`, returning `Dim::D1`, `Dim::D2`, or `Dim::D3` (default: "I iterate every axis the layer gives me"). The Layer uses this to **extrude** lower-dimensional output across the unused axes after each effect's `loop()`: -- **D1**: the effect writes only the row at `(y=0, z=0)`. Layer copies that row across every other y in z=0, then copies z=0 across every z. -- **D2**: the effect writes only the z=0 slice. Layer copies z=0 across every z. +- **D1**: the effect writes only the column at `(x=0, z=0)` — **1D runs along Y**. Layer copies that column across every other x in z=0, then copies z=0 across every z. +- **D2**: the effect writes only the z=0 slice (the front `(x, y)` face). Layer copies z=0 across every z. - **D3**: the effect writes every axis itself. Extrude is a one-comparison no-op. -D1/D2 are **opt-in promises**: declaring them tells the framework it can fill the missing axes, saving the per-effect work of iterating z (or y and z). Effects that don't make that promise stay at the D3 default and iterate the whole buffer. +D1/D2 are **opt-in promises**: declaring them tells the framework it can fill the missing axes, saving the per-effect work of iterating z (or x and z). Effects that don't make that promise stay at the D3 default and iterate the whole buffer. -Hot-path cost: extrude pays one comparison and returns for the D3 case. For D1/D2 on a layer whose unused axes are size 1 (a D2 effect on a 2D layer, a D1 effect on a 1D layer) the inner loops are guarded by `depth_ > 1` / `height_ > 1` and never run. Real `memcpy` work happens only for a D1 or D2 effect on a layer with more dimensions than the effect writes: exactly the case where you wanted the framework to do the duplication. +**Why 1D runs along Y, and the unified expand rule.** A lower-D effect occupies the *low* axes and the framework expands it across the *next* axis: **1D → 2D adds columns across X** (the 1D output is the first column, duplicated rightward); **2D → 3D adds slices across Z** (the 2D front face, duplicated in depth). 1D-along-Y is the deliberate choice (shared with MoonLight): it makes a 1D effect the natural **first column** of its 2D form — write the effect once down Y, and expanding to a panel is just "repeat the column," same math, no special-casing. (The alternative, 1D-along-X, would make 1D a *row* that expands *downward* — a less natural fit, since a strip is a column and a 2D effect's columns are what you tile.) Concretely: **a one-dimensional physical output — a single strip, or a row of [Hue lights](moonmodules/light/drivers/HueDriver.md) — is laid out as a `1 × N` vertical column (width 1, height N), not `N × 1`.** An effect that draws a shape on Y (e.g. a waveform) then renders correctly on it; an `N × 1` layout would collapse that shape to a flat line. + +Hot-path cost: extrude pays one comparison and returns for the D3 case. For D1/D2 on a layer whose unused axes are size 1 (a D2 effect on a 2D layer, a D1 effect on a 1D `1 × N` layer) the inner loops are guarded by `depth_ > 1` / `width_ > 1` and never run. Real `memcpy` work happens only for a D1 or D2 effect on a layer with more dimensions than the effect writes: exactly the case where you wanted the framework to do the duplication. Each effect's `dimensions()` is a claim about which axes its loop iterates, not which axes its math could in principle vary along. A "D2 fire" can in future be promoted to D3 by adding z-aware heat propagation; until then declaring it D2 honestly describes what the loop does today. diff --git a/docs/assets/screenshots/Hue device disco.png b/docs/assets/screenshots/Hue device disco.png new file mode 100644 index 0000000000000000000000000000000000000000..cec4b46138a1aef0693ed850386c9fde34a9b3c2 GIT binary patch literal 73925 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�=R@ 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 DKdv^Z literal 0 HcmV?d00001 diff --git a/docs/assets/screenshots/Hue friendly effect.png b/docs/assets/screenshots/Hue friendly effect.png new file mode 100644 index 0000000000000000000000000000000000000000..57e92a4603c26b279c35e09bafa54c7727f36188 GIT binary patch literal 132258 zcmeFYWmFv7wl<7~5D3BDo#5^koZ!LT-DzBd1&2UzXe0!8clQt)2=1Gxg^Y-g2n7X&EF&%c0Sf9R9~2Z!8Uj4zjwGys zEff@Dm6e#7l8l%bsgkpUxs|OM6qIy$V)9E>6)lX9$KHF<*a$?T$I@sBq*NDBKU<n6il=fd`cxL*@o7eZ9uv zPR772iY|V$$3gSsEYvC{-H5}ppN65A$cPWhgDsu$J=90rh}pf=3^>X+p3U$`(8laqdQEFECy{C;yvRjVBQChveGOGn#WA2h-v|Tn0epG ztbc>M8Fdm^kzMZ@H4GVHWnN-;iIJceqXhRyE~Wy0V2|vOD!fUa#qea1dC2Ik9OMOU zO2J7x%f7ixzjjKVl~_lWVH5~xSa@jGkN1_9f0jM;NiwyUG){>%C7C_HJ%{^oo3f`I zzt|{%GU}P-7~a9sBVV1wLM6REDtnqVJHakS1z`W&!z;`!T^%Z8yOPZd|I|q^7JzaB zMHW^MEq#gCdJwfIx~PGu5q|S39M6T?dBMXa>7$AL`-bYu>KBH0Mn;FVd^3_1B_RNQ4Ej^& zYfWgKRRrAtnv)j+q_4$;wm!n5zoSD9VEBy0^$|u1u0B97n~)GHv{TuUFas`nm9P=6 zJTN^Q>EdIkA=K+297966z_$p2j;Jrbihlo0{q1F{h&n2)^Ctl^e_FVRPsTZL(oo?! zx|S5GaET&YWA6&_@9_AL^a9Jpmd1Q7QSpP8MY0SrAoTfB3P9@k#BrS{L!EjgZ3kNjwLN)0$xObv($^P#!9EOXx5CysA>_# z;!`6Zl2^4;bA*e2IT;3~#h z`vX)rn9!cL8*+{cjUt2u$pQ48hh0QHdc8~i$QwedG9L1+Sj$KxK{%`DCwVvc4=*0< z9uWK@NX5n|cu-+p>2}j~t9KiTvaewqrLagOP~oEj!;E?<*Wr!vs$x7sW)*#8$>VBe zuD%(fXVqq^O7gvHmc*y@r5uin9y;30GiCKex3ms`-vRyv=!6dw(0UoHLKnwTrln>v%%r{;<@A1|IkiF zOs!$_Wy7de)smePnNyuJp2MF5SLZtO@cQy9@|NqiFOoG4JBz7es)g<=Y$7YVUTu^pIAgrq*0nt z-kKgoDOwNhoMo1BGOMkvNrt7akpSnBR&Z>ROA z!KLY?2Fx56YJg>pyI33A)F>#zsj9ZIH^5Dk#XXXtZeBF=4i= zfUD51aB?6xo?2!U!X**TIu!C{aK#Q)8^OP>JJ;J-*p|9Nx}?AMUUxWPK6B82&3vWT zYU1SoQU4=pHY+MzHHDkFWJ7GH`|58syJ?prk`H!e1&PV!)yt26Z|8u=NR z*Eak*$&9(BUDwR>``J1DH;qb-jEKHo$^PkHKl7K>^m7JSko!*ZxdF{BC6TmO7Ga7H<*m+p)Azn~LY!Qe zr6LNS87y^*s@S~E8pgymNeQI^(hG@POlKHsd18CRKhxPZ&aKXV+R^$WT1#mqi7jOAj>v$KuDY@L#=0`F%k)+Sf&OvZ z(=Pn_r%mLJZLQ73&9(*HrYc?oL4V(;G56(_DQs!1FvL49UVFY1!8`A#YhZdA_wn3A z-De$-+`+GfwYvb;f}4JnB;ka|6Fb?5Bv4ts&b332J%%lK>8SeAGTc^1VQ4I-k00Od zr#tqMPlHWgIXDkV7Uh8Y2>Y0r_MF*fKDWhUA#-#qd`l3^9_!M3>dJok-jBq6MFy0o%7$FfGZgV~=ZdIN$n+*7GjM5P5&I6x?xUYg8j!h686Ovjh90^EXq1u$^g z`;%9GCA78X6w7kTEYBF`(xmV7wXIE!$$6^54}V@~1+Z?PXUMq@Gb;0@!Hpa1&boMH z<$c0`qH8GF!hyw}W4X3%Zp>)H zXgn|HT8*L$y@R>DDRE(#9{1!7u3EU z^q2#*$i6{6iw2aAj%>d!iNHjS;;`Rl7MU#4=W6f!vLrMu6zm`OVW6Nwt)Srk zRYw7G{q^|_Ie)eJ^9mdP3F;-}7dqth$cFi=_DjBO*uTm!X^>}7?^MKOWFS`+6K69s zdw`{b%Nm`A5ah-yM`Gj2V*lP4?D+S z{XhwL@Ii`pW-dmg9(K0&06q^v@;_?uLCU{wGn144QN_hZkX%zFvokq3TQIZo^71mXuraf-F+yrE z0zBf6NW&jgsD@PYA2Yb?A{TdlNxVi|Elm8m%_vg>|H1n|fdn9|n zzorG5AoH&$%&bf-%)k4FG!^)Dmru#c!^~Do+{z9@GsqZ1TwGiNf7JhvCx4IlkCvK$ zw`AqvWcg>)e?0o1P1OKq&SDOBkTG3^{$8(tHU8(re>D_f{x$V~km64||8W;WXdy%a z=HH7ZggE8;0JFIis8cy;OicKh3?b6r zb|a9r(b(%)O%&mBd10dA8twX&l2XYt-lGx}bz#qYov`8?!(_44RxjoAP)J?*8S2&l z>i9^2c9K1|C+Qw3Mg@&d`oB0>;AmaWB1K>*|2M~~8>Dvg663~4nU8SN|BD0CH~;^p zV@RF<>-#?m^?x+^Kbrg}1^)BS|MAKHA8Dci1+B%6dNdbb)SlO1lSiy!ujqNddFLuF66VQT{ait8fhDj4ba2e)9Zpg8A;_NB_^? z%wEO3`_e|7r`1AbVc{Dp^)9ETr%*HQpRY~1{5&m}hKi3LxHmy#(jCl-@a9du!o{wI zrzfx5(PE^0dOaSrYKRKsNFYrgh&W`lUuG4N6cv{fp+4JkXh18b`s;*7XB5wi|5%`a z5}=5*c>Lz!Ye_qa%*_LVWg|jNKK`f(tl!$iV%A40XRg%UA9FPoJ*8SR?`!kjv*hF{ zgoPh3kV!z9g}b)Xs3v;N@Lf&2$R;z0|)8 z$<*1r{5`oZQzNJ>+`5*P0DF<&;6p%fjEt#%zvnfLqyA=87(!1F3X_CS>)rFU@6gCd z4`8$mQ&wlBN~)^n_!vP-1SXjo`nghkSJBS()pyxyrj-C^)8FI#T^N&r=`wm%c^jJ3 zOgZu3vgwQnB+BXK`(43aVYPLzXnorxb}2SHJA2q#K}~H+v;N>k1}{LpU!v-~x|x^o z^($RTIMH>=K(L#2ScJ;MuAuD9K?%wym zhdYvm3n_{tg@DE|J>Lc;@d%8q=~#l>_tcXufQUo$iH$*l`_ z=gvL(ZLF=8m6Zd2{HWn^rGu4<%@lWXl938sF7tZ4yX^T)W|bdZTFRdP9LZTIkT0K3 zrz;Sbl@&`N6;oeGOh_2KnP4g|A|9S7w=jJ^KX38=!M|n4Yon#}WSpW661)&e6JR z;gH;!3pZ|JV1R%tJxk|DL47^^n`hW9WYMsr`N z-txZM7>MT7n@vBsvD_G-rKfjjkTt7vTr1mtn5&s%>$i((wwCo-a-EoOU6G0t3 z{9dIb8r-FkC2?_Rg{7rzXw>EQ&mRsik5@=eUpXNlzhWK7U1&INoum>_{DaTNBw)DG zkYm$D>J?Gy>ul;9T~HWph%n0M==oQr#2vA3N#v(l4yqc93x0W zGk}n>ygVXWfaopA=wf|;=WZZjgtc7jz?kLNj7Q>g!fI_}qsQ9Dwcv=&S0}2ag(q~k zYl5bkE&-m#(UaTF5PHP747P+YnYb767mF0ca5;r{y1E%w=DA^od3kwd=?4>!ya4mH z^U)3#lcR}%%Jbn&s1VTb6SmXG-;DpeutX}7Q$uj#b@%fHl6`_iJ#>CLj)5*2lC7EG zl3ByNMu5}V=Bu!nBMWT)I@ah?9+w-IdIxZdQc3sGXEL!LJl}_hPx}cR+^pqtrD7BM zu55^AHg|AV6E*Z*4*)@ba8ai#oa(A}rC~W5uTAm6;QI=(cQG$18$rmC+SBt!IKt2U z{a&x}*Fu9gp&HUcpOz*`NJxge>)mtt)TC?YeDeGaDEuJX62uSoW~i>I8!O@l-<)pD zc03!VUzZ8ysKl=LoXeB{yc?{0`7Ih_+p7+$eJd&5lu3WK#hqCpQ_i7gshy9<{m9nm zYK|Ha=<5o*SZII{I(kB<*O5_`!WTdFPwblTEJD-f>OTccH zx-ikHnGPGIR<@j~uOG@Ko&iOEEJ*eqk=pqT1loP2Yin(lYgYi4AbPfGsajs1pR@aq zYENnRjXJG%qES!;=ntt$j&|q+@8nagN22qr1LBBdB{BEps<(B3FV*lQ-3_7~@=ckv{@hUjHJ3msx6A~~dM!*#ntVor1mqpVbWs?{r z#l?d+Tr5Hq^b)*wb6)$w6UTqOTV#IX@Cn18Cr=4Xsk8K4zQ5~v~3M~eeu^0iz6*VKMP-|xcFyVYV;KB*|& zn7xS#)<}(XE;}w>LX!>S%{E_@gh)Ya$vZ2p*9&&RoI49wt3lUz;JQn&aPOFr*tl>` z2Lqv(33%G>tlz%|IXxn3V<1-Y!-x2AN!5jxg9F`f1r~mi<;9AW1X%ki_!?O~ z)S?Cl-#30%Kju`^&_JrQs|!}3FRrui*U^p`8t`H6I~J^s8e91Vex zb#sooN1#SNgXc}lrWQLb3qlZlUfS*Pa@%#Fh1`zYotIAErdEx`AchB^I0!{}akeP= zO$)mpGqd9P2R%8tD69Os*&@-Vh^nN)CcuupscFWMLUQs*9VQ=hx=vTXe|jM=paM!n zcM0hOr!V#OoW!hyHZhgMs zb7ni-+o zplmQB%Jkjlt?A5%DMJKG^!0gI^$q6}Jx-b#PDncM}%S;g^Xat0)~H~&dqpiyOA@_(K4lag4&Ut zPKhVcrGsRy_DsZ>=OOai$(0?p@#0~7u}FcxqT24H<$J8b+TE3fWu`P54qDnlgo=*) zr4`*}Uz;3ue*TxIXU2(q;+91f6+L&C1Vr5{eZdN46{GLzsP_R$*b@0kE$Q42ho5DG zn+ikykSB1C?yk8`8bzJEctsdN<#cK#!E}nkXLqRT(9Vw>&v@I|-3BR9j zR5O>&OnPO`ba~Ya@e;`KOTxjI~Ui8X{zkS7!_E?J<8*`O$JN6vHz_CQl(=`f-hDZ*`C~Ji3_Dutg zi(9?HNcgu%qr^n4n;l_;+UDNwkcJcqcEQgSNfs4tZbI|x%ihVN=M`3PJx`A>31?i~ zdeBwWlyvL%T_K8Gt)(bqulY#YTO?Vx)`v5?aDB!kiT+xJS3vb32%UzL1i_lKwIKc# z#gUFWs|lRy8*RhjeF!38w6yp+I}n_Fr!R>pUr5oIhVZbCBh1BoYI|R(-uuoytBJ~mDxLo*|nO7d#W)5W`uS!Hz zgV<+gme*gdAA4;!zQc-zaCxhiC04f1;Ihx^E0ijD@8t;+h&CCB(V1e3RJ4dw(UZLh z>43ns(M{j+dg|?JE~(|M8@5V>@iQR2aC>k|7F{w29zl5P9n%g*SauS+mxuQ z(K!p=ZcdQva!Gk>ch44GxU^1uk5^-~y=;|)Egtl|IYE>9()`(Nm=Vb|jqwUWm#X)^UUR}kp2VE~NJ@@OlbOrtg&}Mpd@Myzt#_kGasOa7XKKlCkxrS9(}cX7}!DR}lHC zpYeRHpOx_Sl6$Nc?F@oebi&ln2?$Z!={4Ht$@wT~rOSeFQU~=$D2kJ6we6et;7#~T zBb}{}ZLrz~nmdaZL8j)sM|rN9S%2){Jc#1#>A7r#2;BEsvvaoJKaWik^uEFijfi{& zyp#LNTvDeo*{(i!C4ol~_X#VVISk_F>VrWLov)eHJy$z-iL8mHj=`Y)=VmYm|BhcYE-MTM zO-wTP@i67U79v13SFHUaFEq+5xkjSctPHHH!E7nJd+@$vemb5iGP*CD>N|C$bb)cH z_C#?dzoTJsmEn}M#*%tKMdLSI`lPIeA5(68+8ob2UnLrbzvhgHJC*CVZNnTvl%L*8 zBQfOMWPPu>*-Ptth#7da-1aid|0%?6>g$hm?g7nd-i2|63=U`&kk)F^WrgHoF=wVE ze9bS0>ztDNI9->#v(zzPW>eOJj)(V_cdlTlJk)7fsUa#N;=NN%RUk&2qv6#-s$}U@#vv$=F-L_0!=e3_x)dW6y)N|d@arS^ zyaMr4+C(j5+yr`*n#c6r9q=&n>u5_7Y~)o1?*jMWaO9m}(@(?@5dC3{v(Rsh`-2O% zFix)GaN-{WA#P3wKZr+!xkP5+a2-+Iz|L>q`ukQ*zSMveG0uRu8iXmh+9hf0nVQGW zwkiY=9U#^_d@G{1Hbc(2T~+Fc^r)p%DwRS#&nzfLGF*FoKMHTcOxX;Rjg9T(YGLH6 z4q{{l%+BK0tk&Btypf`}dj-@xyiT*pPg#`5_bfKvah;JL*d5P}k}r>N18o23?h*^F zQWn>amF5DXNjkrBK_P>|=~3R+C*UE-uC%>Fw`d2T35wC+z7sl=baRq{f^> zmPgyTBDV)Xkhbuimlp|yzgBf}rGrL=l&?NMxWb@Cs;Ex`}d?#HoGbC5$gy_@u(5#TJAi=X625^mB~vtt3n$o#ExjC#l54| zBk9=3GuDoN;|q;qnkurof`V(m(x;@sITN6Jd~~`jm~<&E4Ig4M?`UMq%H-4p z8N62iAI_9r0LlG?w6177K)2N+POH@G zZf}QjeO$`c=9oLVXze}8`pXX^x8S69x-h=y<9HUn*NnA=sHjU@?m z78QkVYx{0{d&Mcb_l*xB3WFSo5=)dBOJZ)E5C|Ht1rh1o^5`I~H}CQ|u0mOsPc$~- zo(oo$^F!42>4>r_Nya~d(VbJ`hTjuT8_z*HN+}w#5aX#IehIi!F|I35PRYqJZ8GLa zfc_!PPI1Xj;f}lX>(}nh6xAG+ET@ZthDc9T9I$3xoG-+N>dS1OE1yimQu)i*dyx^&z%KKW#bBzU`m6a8K zIFZ)v!|uV5gTMmyzq`#G@t|*|v@ONie0*T@hNvf1v2x4nyT#?_scv?i=`ztd3dZx> z>q&231P_l1C>dyk|NQzIuQ~F=%4exihg&s>5Z9Tpb}<`%rWF+pJne+N#4gC(LN}<*DXwL+d3%BB^DTVI5CAW~ zDv9)s6}$@5x=}qn1@YrVNH~z`ds!v!edyD`GFtI4i56#BhHse-WBelU6^M4i(J*!B zT(%urTvU{J+iG>^nE9pdan=MSofgIB`9sz(ix>&}Oxs{WIj6=KJU`dZrE%z^mSJB) zJ8*LY7eycpFGD_P?Fq4jlv;HDQdIusnhyuCPT=3&)E{LL;6C-HNh`FJjwE0KkDT~5lV58? z;wp2W!zi`9PXZ*})RVRvzgeB_^7NOy-&JME^1H*EY#(ltOJ$QednM09qb;=MvGHgu zTA-Z<@k;jOr@Dft#d6^?A|*Ncd&P&1P1%!Mp1!^%s&v2JYUWP#IuV;s3RVVr$SbE#{-jn{g+y};NHs3MBS zZ&EA$j!x-bBx&4!+OI>+ZQ(s*>8IrH-@&E$5+0tEg=H|*WO0TcPaKTMG7=Ij$$0<(fVSpz(dzABE=t!nIMi;z-4L8) zcZeK0@GIc58bS5T6*r{eThnS}F;GO|O3R43)hQo|2$V;kD!ST~C%$ZS(}x7|7Hx$1 zLJtmXF(iuolP{%Y9gu)@)%)iWh-D=j6%a?pj@_-^?d5LRSkYr%etv{X?;y5b%a^g# zlvxsplcMJnGJ#HO=}giXujiS#iCK%uKsomL;Rw)aV}P9Z?U0L>mfBl#cUHHeJMFUz5Ij61#mqYb z@^9k^uh9s0oJ1BOFO z9DwQ9U+Ak{DSuf`eLgLl_HxqFsOc^6K9%-CLoG#~@f<7Lt)76KxUUw~)lt$rK02zZ z-X~r6BQV*-GvF*Vf`w^OeI3z)>0|4TH2?iOu!SW?zU76vx_bTGG^a`}Yw=*GJyR6wKVmfj0OAhm5w9Oofg|ontv-QHR1+W`j(uF z%dSLNe3y5xt2Q51&tj93lHR-6@tA`$$Y2~Y(3&_4EcNxzZ;spC-*Q+NH8zU(E^rey zNvf!*IDYw|^%}a$d}P6R*e$=!=#=M=kYN>^>fkR2^`>v8buXy&f)8`kqp>KuOwwgu zJ`*HaRY4@sjdD74WM)uOUw5~Wk)_h%(?;cDEex>}FOF?8orE4C&Sc6`Ze8zn;lLO~ z;QV#1)eP@?Uar>43XF(95>E^?bj zEoYjJM7DkG@&1iwOSK`7D#Nik-&Le+#M;)Low%)Fp}KR4dfWc$Zs8#EAGYIrgjriI z&!!zO3b*|PP74c}cNE{L1OdLl(AKVPA<~RP8#_NYxlFue8*(G}w|lbyXXhV)=q`;Ha^pQ3Z(RnBa7mcG{FaRF^=mb%a@J_{~`ne($SAvT8Ga;Dt#bG#DI$NU9-SU z%lPw0z0LLyyR8U>ng0q4{v~G{84$$93&LxXVoTow9SMf#r&lMtxfraozr84xQr5rL zzoLqrc42P!hv?0>x3|?N^)lj3d&U5Kvq4Lyp^4N2Gb2ly_r2P~O`4vRQ{8H1x(jq& zU0o@(O<&Oa-pDr86|SZ_-EnY5GTM3@8)?szVq6woF4*|bI-<>)kBA!?L93VhsFm=& z*SK#xZqGwNLSpBo;%xW^NOkWa{3a7@V`lc^>2?$csHo@S{Ub#=-ooWh0=zpkKac%knr2-Bu|6OhIfM`~n5CP_QPRZ?8yxPJ4>=jnEveqG+*LSgZjJ`w;z zSIRN_GsIXsG&eT~W)8ih!?d>YvnqP`^l6gd6l89*VE*WgTXT+k;ZV9wdVP7x8koC` z!AK{5Wj>yf!S8;AMR23{$xQL8O#NG$m&hHf+nX@LD`R@7Ncio;D0lLL|~R^ zP_ejm@lQpJK<{K2CtD>a9@V`YUg!mdM@@NhDO z?MDbUi=Q1Q7Y@ zz0`7@hM@2Ws{SnE4T-VVOMUu7Z2mJ$j02OTr1sf&+3wUCPsgHvt=O}%7zm1LquIZj z7AWMt^|T=Mfy6CJ@AQ&}k-LGwHkw8ZBw`YK*B`leO%3GJFV|DYY0e4?AVP+W!I%eXPO39fhZ-oOH8F|b=wn{ zk5XPAovC|xSi|UW9=ShaadedWhzlB*hZZj#SEikzn(5Sfpe8r&OD$RiTSn2l&Z)#!Da<0nb z_D3WyK%dM}{{Z4G=oCX?l#r8iskrbdQsAK3I3KM@&|RhakQkSdyzWYsSuo~FwLF!X ziV*_JT-yhg!NcG5DEdWgIfUiwj_Y>hN*0h&aS}Hyd9kmf-{lq;s7~@-HgOK<2{z{g1f-#k%MJp0D9A z5?hyV6WFJOgUeg;N6*}>g+S2+!VoPgE3*dq+o07_QOO}Y7nl0iB4>$jjxD9=8VhCn z=eH1Z=3K{d?scd6xrD7QCbc|%eLgGl4P<*Jb6;T)M%X4V4yqNz+mz%-CZ@=o^TnEP|`>mU+i`@K9;wjq2Y!6D6P@# zI5P3MI>j-TN&l#9^2unrbPfUW)w?g^Uei-k6f`s>iRepK$sPXTuUIQ@@4mh}1LSA% zgji&1Gob+sbh#wC#Q%{n<9LZ)8BB)=99e;etb#w%f6f3aV7su1`rJtAvyfv;zCvV0|j$>pA3@D7pu}C@lDR}U!BCnC?H7<%34|> z@$nxpags?Pi6=CQ=8y!RlSMNSOaZa=T>cc7@Gt$llUyWcg51f~A0F<;s5e`h@*1V5 z+nZRTV-{|5YC5~|8{u978`=~z;pu6WWnqb!j56By_p-_wDimkbsHnJMgMQ-(;bEUU z%rXnh%e(c%;e6K}Mu#r%&XE5-X~!k@BbDl9!WiBzNrVIQE&Kky%}GJxN<#AWehc@i zTe;hmfbNt6f6qZ(Pa7vn2?-*w&CO;G?JtY!<2||~wty@4j>Kpt5aR_Xb8C27X7xLj zNY459wgzBoYP&7Fvov8~8=})v>jDcnsYPP2l_70r^(5w&Y2l_MXg;MTT8#5rGa4A8 zgbKD?cW>`R8ufhY92n4WcHiCz?+^&Vpz$_eE35&S`~HDpf5!bXi*-_5>?2bjr8?yqv0LB$fA0`aLKz6ETR%;&EU1RqiSm#H;H z)nZ=(Wj0Q4x>s<2K2wNV9H}w5z`uac_7`O!?@eUr$VSkbYbrz!=%9J8xT0b6LtPk? zkCFU=@-MxOG=K@s(ba_}WQ1u6ULUff#sWnkmf(v18O}v4@d0kniordZ0?;ft3s#!M z{^tE=cO}^)D-Yu<1Fs9^$;rvJu_s@ibf8_-m`zEslC~}-lJ}JHo?58aZB=Ahvv!q~ z!~iK*PDi*4PqjaaPpbf{MVFnlG_eOrV(E>y3C5W-plUs2rqXVpT`1#i%inIB0CSjq zYt~ACLi5)$J&nO0y%CkEq@o2DzOaE?R4h7{EY{!YmEYDs5}zsFjeUbV*Hr~-1k*Xy z4l-7BMuNEwHv+_H85n7%i75?VsV$-LQCXpyD{4ph89knY@-39qt@5B@;0?rgqYz~~ zqg6<{Q(JRyJa$T!((>rHb6_3S_(5O7W25_hBON46#Z%6WYJg1LPiGp-qMj04FLs&% z*)-eZ(;lUM5EViqbl~6Q!7mhu{v~2J(q~3;z%Y_Z(w{eD-oy)xT_Pk108him8xN;% zrRBnUGJ*U~)bvR5)nOXS>eLQS8eJ0$Fa4mQsVi#r7#6Jimg`lW-I6e|yEVx9U%tkV zI`L!WaoQwpHRV+51EqMNiR4Aop-H>jE`P$JUy)2@K&<{dq$6U0j)3&0JHsir(s9%A zHKr50(jrZ3YwH-LdY%50-$^9+WtNEl=CM%lS-df&p0FCoJNHiR4SxE;Ni0HW!Q|-Z z_pWj=sZ$bqgTB4e#rBM!SW695s;*MI8N!FMDV#>(YqfW|9qW<44*V&<^18Thg?^-; zeJr}avQS+6qF2FN4nFtAs)9)1O;gYkYxCLX~K(W>hQ4(oCPjLMdt8}QqDH-VdLzA+15D%0wp!An8i}| zL4I%SBG{K?P9k&)KpyM)bk_~WlP?eI3+=NJGa4PSa!gQe=SQc`f9=(PBXk5T8<2Ot zVprfMB>T6I)Oyp<1O7#h;|duhkBZD_pU30wR)$-?aP)1kh9gufd5=<7B6HKw;RzxV zdb%G8hm4-g0nS=9=>Kz*Cb?{PUhidEB4V{e|wvoYoin zQ{u#&4kurQ;k4+r>C5J|nz}uh!Y^yK5Krx7u7K3seF{1E0tw8+z6n4FTV?U9K#hAob^UIGY*X15#b*$I|_p;O5v z^HuZr`xLTq@hOIG1XLu4^}u^2rsp@fT&ARV0|VMqCwn;jm2OK?F^@;~jb6lu(F4EG z*gM!G;~(njA4>OP0#t|scbn4^;nj_k7$pu(@7Js0u*gVm(SrP>v$z*6-46ngZ~~HR z9cN*AX>h2x)7{G#-(j?nBh1L?<(%EG6y@F(Zk7j{9;n9EHdaFAh1}8(@<&4QSXe9_ z@xK}yJMG_~p{dfCOg74B)}6VwHo2K_OM!-eXD3TTwB(0PPmA${)0?Z-xs$6)2}74} zh2F>~k>R3EVd2Z`&TAz2!gm}IUBc{ zbhJf3hQ_RIO&y0hdOgiw?YnI@Le^7a_u}fTPqE`dAn+lbQA)rHgItmJADtkon|_akDm2f zZNrYl^=pU5P3OX>ihGNIbVLI-zN9T04665}H1UpXRu^j*@*8UyEc>9EWU_ySl$?RQ=lm0Vu9T+mqHnriB(up(%<^RomAF# z$?uZH|ESy2^VMG}2!vEIol!ZK=^)_*N+Y{!+#zQJR#-uj)udY-A`r|HzwD**P%CHfHJs*-N(I}`HzPT;w{#Vo z3;91R4WN|=mM0YNTiec8BVnPx;A3E%3d`OOe(>6>t5fQlpeqYez~ZPA4-VBQ9V<_= z{K;r19-?jMx;=qj+)VDGfX7P`Y3@7V;!f*}l$jXzV|wd@Xu%Wz8iD&`mq0qWZnW%? z>P^PtWOJ(Qk-G&kD7xhr+YJym4%^OCrJdg<+Q{v{0xy2map?SZn)|~ZD9-wP(BNOC z;CestOEQT3e@KQ!$C71!V_q^8=x(-v|_|2 ziVG%LzW$bbG*ol%xI2lxDDcQSz`As^P<%{AvGaK-py)QpKIQIX)u6TV-lBs3sa5OE zkwet(-1KcEk;?Gg&8*`EQgLD!$nrc&M(_$30FtjX0NOjxX zHZ?ih96AFaPiB^us~^~yjgN|T6ADmr7nI(G`=%q)C;-hsP4wv zhMhj94J|`}d*Q6vpsb;%1>hvBq9eq;;TT(EAx02fi_I|Q?DqK^M&)~N(H+~W#x|p? zy8QVr3YwGdVH-l`rIB=AWI%aGe+GTRPQ%LMtyKwc6?rsTz=hwy6G`R`%^65*!&+_y zRu;$j=JUJlhxQ<;DxWExm}ZdZ4%or}V;TPyA1Fk6dBQ=!jahVbZk3qFXEAC>IfsBC zNofiz=Nu9S3}_rwJ(qh1TO3Q7x$eE7Xo5r^adu@Rgq!_So33tB_0ATbnQ>|XMX*b$ zp@4;Q>w%_``g&N{hf`pM5UoASyKR^J*4CQ_v*Cr}`8<<|3TuFEGyj25$OqSzQ|?V`F0$Z;(LvL8+vK7M=o;z(+y;`axr5Sji~-$l5rQRUAx)$dISmHUN#A z!%EayJo#$^R(uKcSNJ$Mkv8T(*qgpi_R9k#?Uq`Jj@w$4gC~%1(wf5Vs6a8?2mQY<|pcK5*aF!{6R3zRS)a@j9=^Q!Ve;?8%U;B(Z;IS3?f&rz!;bo5Wp zu*V0)4h79RWc1-nl6^9W+l4+D zIWnK&d1X#H5RW3#cI{}+R4jKr3%wXfN#$n?G(xvuh^@!PRpnm>y6 z+=VKG*br{u|3}$d0L8g9VWSZUkf0%f1PJaf!DVrm;10pv7q=k6g9i8D9^5TJ@WtJN zySpshmz;CH9L~LU>;J2$t*x!8neLvJXS#a^heO?ekmf%}vzi7d_O@Lg1kXqytq-5zF@5Y_+6RGf3WJ-E$j zCuAA2*~w$Qh3#Z?B%n2Y)Ks-`esGKgPLeM@shJ#`c7rnH-c4exk1CyYkAZ9iy{j-d z-hD}$$<3u@(7V~DT3}|W;ZTx6p%bap6k*}b;JyA#!f)Y3#IK99?tr5e77My))N5wK z_V8$mqj$g;M#lRzb-cC=^o+96U{s7LMjxOL4fl4wc)e;6=hDv{5GKQ4I$4*@Q(oU7=|@YeK-!ryi#DBPvj;8~Hg>;9 z#^ii! z9;OU7v#uI5V$a;{*WY_K&;+daHLK(1BFk)V*6{}FgLCUUWt#6^!vwAt#~8&l`(<>F z^jC!m=H-7%m<7%6G@p%gn9tM>m~WRzAS5qb9YI9{%siB!`Xdev$E}^AX7%Md2#U$C zIg&HzS$Eyht=w(|6Wca&2c3ae-HbG}Dk4%r&dR~D*fZueW39!I3`Hj7#o}@=qjTF8tn=~Qfb6=bvd2@SW0^Q8oYgIBh-C5}+xh(3`gfg~OV&Oj zf#ri`xK#Tjx)REtC8@PC7$G}Ol7#Fdk)&*pWR7|~nWjT@kp;B$(u?sq&zEQ{qq0Vq zuFV}Odi^grfzGHeXD)@e8&;&%G6weXKxcOoDN-|9@VeW;P^g_k9xftg#BsgEouRMn zTuD*MkAYh&S$~Y7iY7aRDACV0dh!f9Ka5MWl7sX_!U#Dz)sG~iiSR|gy&-NkjA}$H zHyrrv$qWDd=%`c&+Np9m%^~Rf44)Z-{W@|Rd=W=cvsw(N^8#KtOQT+I#xRM?1~E{q z`z6I96+5?=n7m`4J{>F@T`wYvkv<6_N_0U{{##dpB90mKD&iD2KbnDoS|nO zrsK5i9R;XwG5sHv7FYJR5|*YEMUi)U1O^IsRY=_Sw85QaNPc6v4(t_*YN$~pRr($g z5dox39vzz|ND=K5$1XbRpf@TBOt1Lw<;C9W_2bzKO&$d~iyLKQWbZ-Ke zUr^<^+(iA!SVi};b#OodrHg64w~sE9I?Yf~UUy(XkU7MnjC}8xD1UnkM;@B={PG|3;VWWJCso?<#oCt#D3c!6 znu%@j2qC^|v*QyJOOA9rv_mE9>pO0(g@F?EcL{Xy0-kD@Qu?cSjy&$&yMQj*w-uY_ z*w@#U@K>&RFc0;Xl|=kBo4-WmT)mtd%OYD}c&zws5pOH?L9`^!GRhmRl1`{~3EEs@W`<{S3ugw|)< zn0}9+Ug-^{>4)GjXb>{B*<1_~tgNjD4yuy=FnlB~5uBAu+86Ko)Z3frgPNSTQHuN9 zM3#NN58Z(%(dzF3v`L7$KjeNgw(Uvem-+uP>h0)WTQCaw;Ym)&VIlELE z2p#&M?eCqWVUxlZ7&ob6+^!!T;O;E+`QQa2zpdQMhDP@fbad0713NrFanVJ;ew83P zh>FI8P2%q?=F!x!viiAgc#l=NIgk+zrCzR%5^TDFvfv8$EVcJgmE=;`^Dfrt1BtiA zHlzOFBe%^aPIWw%Yg5kafz^U97n>TbsvBUQy@n!ozB?c}d_+Q4UvQs{(Ar2M=QlcL zy4=RT3+caJFmV*cdRIV)t5w*SXbW1CYFbdR@yI*UonTAd-r`D{8MIKY9I4Zs)282d z>5F3-O3Fu%I4+SX;!SZIaQ$|&!j;r%b}EoQ692sVPmK7Ta1aG9Hvf|5H!_<|up(n5 zhD?s4m*h;f+PV`fOlyE+eRIb|{uwS+u||LP`} za3_X&7W$4e2&YtqijF4YGk2n()*4W!;wR)-C!jD$qYfWioO1-VQ96Xo(gqiyR2MLY!6$ytMMxueTLNJD!A>Z7}ihIz|D7Jh_HtSt{%F9NARttWvX#r=0?Qx5)f&6aK%ovo!v9GgcsI5Qmoh$OkG3@uy3WHENmay}^UCOKPCjsik zCp$h)OJn=hQ%SKothmj~)uLbU#@3vP@ikHpGK=w$X~J{bEU}eA3?)_!BUYGB1>@aP*zK^E$s~W+GZ_XZCswbZ7X7?~ zLQ``Kiu`gi1-}G`wMEujiYPd-QT9?sM0?=CA>;8YT6_`Y&J2i-_n%A^!YAc{#dE(v z&{DZ{P;Xme_=5{JY@Sqii0FxaLh?9jSS6#gpIZ4$ZH4xpshqJR{z)98&C9DCWM8h9 zG>vaB^+=AGcnMi|kN8!h1U)fUd+g+7BUTtEW@B)H3fD^=g?1TdXBsy0Hv|L(x#&9b zL_7;1k0&zb3!k^N%8C_hk03LaEtxj`1K|ld9%EbQ-|hB4J7f^~BmIOrF0B1(biLC7 z(iS7|2^3-ox+a_wM{zwqDPQ{v&2KEGo{MN2rQ4m(;C<{3ZCpz_+QEG7<;+yVmmnBq zDqDJt;^~Ufp}RRVr~4aBLEWAn>}zY0co)Z(#w*rO?S1uh2gC9|A^ae(Y@($xy1oJV zdLO^={)%6oK>jX*g?=h&y7K%(;zD{=@peyXN|OKa@2UWY{36SroX=mWGL6SDvtmF- zrq9*#hQUufB{?)^90=JPeT|)<*5LiyXFz%^>LwLr_x^hEEcW0Qb08i{LA0hfw6o6! zu?J@qH$A(%3Y(ES9p_&MQW6JY6CR_M@(D&Kd$kL(Hd3s?jJt}3#YHVlR#3#Zgh>t+ zh|*HLZi3uvv({A4klvZl9v@bUfm$|0z)2j@p>n0gMd+?fu9`@p@7T#%s=QR(&bb4` zM1?aNPPNq(gQ0N9Z?=CSEdRt;Gq<8@A1@Lod~+uL-pJCXbfw}bCIF(Z`lJHewWg)T z+Wcn2jyh*>YDm4q<$o4KONzR=>eT_&8v>~u1xbAUmd!^_OC=mGXasb zrRC^0ky5pGh+5uE^zc-Gbbqz;?&vZ5>Vk_E5fA2JSJ`tqpAZ!~-GMmgq#f55 zXX6W|Z7j>_s$9)*@6%S-OSI)Oe=O&(YWoJ?J)-_6eeePc%h`G7L^_a>n)ge9$B6Jk z(8d9=Nb)#;&a^WWI9#H+K<1Se+HX7LC9KyAt#pPDu-{EU2aZbctI6AT!bFq({4IIt zytnxJp;Jl-Cn)wRi}{1K>yw??YQXj6g59)F*2aRH_^NS3@Jf}P7Mcn>qg_K1tLSCL z$6w(;=LVqq`orS$&|;t+yGgSr9LDkUz_T~rK=$J*Tk@n7Qz zy>kS8Vw9K4r8p0#j1oHti$?_`)s~ljzjyMNX`DRsvT1!>!$XOKg!P32`4yHun`OIk z2oB5aWDU?BnV_*jifN=-1fSS+5ZN`r(QUuEyGs*O-5QD4h*qm>wM{ah$Y66w807Lz zEhTWv)NF`+DAi!~wUe|UB#e*2hWVU>u4F<$Z8aaJSyHdI)+Gz0U47LfG+e?< zrsYO@hglU3kQG7bJCNTGZ~m_VA61n#5$IHtdbyktbC{Tj$=2b!ciFLJOKlF$4qpqr zFC~tGZDcI9=8SU2f+chsHyic#_0LAeA->GtiR@*5;D*CY|*LJEO{*IRQW8YAZ+{n+ zN!$L_CGdBTj@`Z2xIM$RVz)J>JX_$p{v>F-#<}-tZQ*k0X)lg%QDPm)7|C%xu@sP%_Eh|IC5BAE- z^Fe((C9`AVF8N9@TJY2ORAPHVkrpA5sn7}zxpVRpU!f>LJJQz9-iehbr$>!5}5XZw~eN+||rbR4u&sig;3B|10Z?Acl-29IyQ-xPdMjxPSX2Wi_H zQQTG8RZYd}zupJkk~XwYbx?X3_9c2d(@*Fx z>^{$MoG7}%+9kVw+-UZFZP}2ol8Jv^fb|ZCNUp@DBIA-v+i4wy6H}9ika3Wu?un2X z)|>%JRq{Yry|kb+Wv8qxU8D$hgf&qe4wzA3sGSbS}v^0I{%O4Mi}pIqbkd z43mWf^)m$}oEF==nJ)B4kiUL)u<*+Ll6QdmkN*K)4@>wIl)&J1Tfzb1;8-m~JlgBOnh7_a9&U0gc5TZYM5u zK$fC4q{JMHv)%2?hB640>T{T0|H~8qr8+IIdDBWhLqhT0j=rS+a$2+OOFbj$OZdLx zEddm7m%h5(e$iWh4s_5nkdNBI?~>}lO``Gz;wO~GjF-5yXpayMqHmH72>pZw{fHQqoH*?Nd8$7nf5j zYA6bdV*$*TLe&^|92_F!f9?%>1)~ibMWOL|yph-bLLS(2Qhh1GVOv@d9b5IhKs-V- zAMD(q1K)7{xn`%&BA(LoqYJLKTO&z>oo;E(?ui%{?EcAY-QV%-& zy#>!Bsf#J|>}l;3H#F6${()%7gvt9HVS9&6YS%?Y98mnwx2+X~44XNi9VBv{r8ioT zNFv5GD2Rg#LB=+9=Z8;uvOA7)&Zmz#A)=Btwu?ad3A?^7xJ7_y0> zQPS90yO$>ko*jAR*Y89)iNISk%hej^1{$1aXD@!P8z0R2O)t}W-c^%R_M5op3tSWV zW$AWxJ&xmXE~DNMeB-K$5;$9NdDZQ$NrQ~X?(KcUHF*Oit{XuoAtA|)Xh=4lGsLu! z=bm#DY6uApMN2IEpdh9-aMbhMS3)|KkK*ada~Zeqi*^lniy6_{{Yr?@e zMjfTezZ&E&r)6kPapkbFq!g{ei~=OTOr08=X4H?r18{L_yE^XOfA@iR;N^zJZ@ifP z8FeaRiu-UH1;;_|O6ioaGz=?=O=-Rg#X-ZP>KDwo$L;&2)!psH9MBru?a|eOUT6Ag zsQdaCt9fX%Xwcg&woLxbl9Z+i9kgw>#fo$*j|KYE$068^5`}tClOT^Mt@pTY2zX|z zo@Bj_oEgqDezg{c=QeJ$V!S3z?Yf*33aw&!){Vm)q-bYz6~vsNctUgRJzPFX#m+uq zrAixYUWPi+!3ehYti|Jrvw?DzCcQJa{qR~s3-a{ZL1(gyAs{CAGrF#x>lOGJ7WP*A zI19X16U&=G`SF7WVwVvKo&sX;^2`c_!dWh2G9%ASQW8E$9GA>CXg=h8!c#iEJor2y z_J0NO6Wqtq}*BKBUxSLQnKa5a#MLmj5gF%?}c)ifG8G z)271)Nqy5sn!~#?zk5=_uKaW6Y1L~w_fa{KH6-@GVYy{hIIa4#v~s^TCjPe{ON$iz z>O%H`0Z|6YrqdIhC?J=QZ~32Q;7sg-F49`uQGbO^Hb%(w7$ChQPCVzTL$Wixg(#@UT`~wIv0Htj*a70!?!!L|yhF}PR zBmlvpeb%`epV=Z#rCc#cQ;p^Mi=z+n@)p!a1_-EUKZT=GM`o0r1O*B6JUs>dMbczL zC&Voa{QREPvQ|3jPW5(uz2W)&2Fl;vdeSiOQ)_b&*)sDm1a5ZUM4|eRdXyf-Vm4!S z3^%7YVO;8VH#5|~nt4H4XQ8|;ZSLY)81rFOJblC&`D*_us1)z)1a(HYw9J0&xXKQ% zZuj@~i}B^{UFdv*|9$__d=qf!{ZnB1`{G#Kr+VO7yw;aEsG-<7JigsTmbULRYFX|o zjuP1tJ%8Bjm`)AOa_Xde9ViwsqH%0*ZAtN@n30jR4$OqkV9@eee+U5HxgJWUbXkoa~}WYvji*e{e3qlVI@>GYONrFt>A0G481?4Lq~ zHS9}x!Kb97C9o4;zoUbv*z%m~RQV(8ZA4S4v(_)AanlLOZpel1ZQ@JfPV zvZckDYZFLAll6C|-jf+=c@R(v0&W)hQ))n>mlxm9*@E!x84LjfuCO zXM0b1A$5?u3&$SF*?gqbekSXa^z->F1j+z>mz3Sn`sORpKBWG*B&Em3h)>8|G}@B< zr5Eo83_m;qL8Ddo83!ll>K&B3mnnXVqnuNH9lBv?lyb?vdhSA6ufsENes1OD#bA z5l#^%IeFBn{XC|;5uRh&E`#|AJpQLg|9sGI!A4SSXfW(cUS8DRjqWBWjP67)6kRIk znHBDwsg)JSv0HrWON}6vh{YqbGo%@$lu50qtm^iWDU5D=Euuek0`7)DBFD&*iSqJH zI0P;Hxeh~=ESe7dlvvqFKy;e6jPga79Es}F1~U*SR(KT&6&Y0cFQNg;-(-Gzr+@}_ z;9o*p!0tIC+z1)?GX8J+KDFdxims)Vcg&EhJ2X;;HG};jts^{JC1chpAH_-`Q|#5e zq4BKBYyIlF{k503aP=!qBB{~YYf9|LHQg_bISJRbZV)Ia6LR@-m2q9Kgn-6Sq{R`i z>90*On}QYPym#I~pRGW<)BHLyErL22bt$YB@r{8gBIMsAiBf9Sm*CEUo%2%8+g z$u6fxFQwKfH9V?DMq`1LaeEaqijd&UX;&s^plg!em&z%@mGa7Yx9Hs9E?t~KU=k9q zMU7sTV2=yQDl^_RMF3x{o}=)P>|4!n%jNXhp#4q4W0;?%e@R74pKHmrd`1f<`LK2f z>oe7re*()|h?dKJv@TxM_+yz!xeHrZDk>@@w!m!AVInwG*c7P1ge6-D++)I=7<{7W6+2{KPx_{MFaK*Ev)|TLq4R&25~d?`A1XB9-4uczYq|6;1Qx z^87->!vl6g>pwg3GvpE9dR(nS68S&s43H~E6&|flYV!7S$)YHF&F_d|Gd!A8_WDDb zd+rDi4z2>;K|oj-z$V>)*whmS*zD7wlz#PZHeXxU%9AuZ#f;ruZE>rOO|fKC&r)ov z^|K2MOcB_NIEc4^YHD{61NM*5!9Ul9%>JiH_mh0=gGU92#!GYr68@2B_~?^(c64Iy z@(qzAVa_J%mU+UuOwgRFbPeonPz5{5)w?Hg-yOi;Lxl7M)EJ-;PL6RVc7~gI8i`6UK&myPWao6F z8U9c&Bg6eQ&aQ*VP{bP&muDRCXD@(nAvBM@A*J?>Z0i5wB~rB|eNju;Ay09NJqAaT z#K=rO+AyirH-!ba)aE7l=b9kZzeeA4jsS38EAbQIU%C{2^2Cr$MMkYkk=cZjELr+I zml5F^R4FSjUSf3J0_#Y};c(*`kmK2ITfsjH`kSpTj(0a1KPEuib$|cEv$^V{~B~1K{kcAMMe;mp0rM(yk0DUK=MJEe} zPCg9_&mnUCdgQCOpmW1_SmQO8dz%+1DUC0k+@fxB4 zCgCV~Vf6VSE#YqfTH4vlFdy*$arAx%>m+_45d6{I`)|Y_0GWHm?L2=V+&5BBV3IR7 zO|5Ak?A)U#ff)E3k`?6F0uMk)2Xm5W&ZbmA_OB)j z_4pnL4pp>)mwp4&Q$&3|cEHS?bz9h!;Qxbq#L^ZgWRB$GSKVEdF%=iu(?^vZC)4w7JPMnXoT8*9u!~$dNzTXoj?Lq73I7uNOk;N12LylO_2msB z6L>1aR2d+ux9f3O$tu*q0Y*XK@Q1{3|I3E~3P?mrpW-c@GeUFOQQk32vtwrUHS}x^ zt#b9(1BMA#3q~0 z9C$g(4Mmk1Ua@xnLj-^Ezd;xtBa2V#m;f15rIR}KuWLxS$bm@?WHktTuyji<>Ki(~ zoZi)lo5-mc6EnNlcDA8Gj+kU#57ZEhNuP0`uOF>KH>$Y%mA7T0QTE9MDwq^CO7o%3 zXNY}lfJuHkMRJAL)3LN~T)FogSL$cdi~oqQf;T_(=dyHn`1l&p@U+5fsIGS^8kqFW z*SY^pCv-oZvk=oMC~~BTz^s3;lKKJt0On9`LDV$!`+n+JA?AL%N5C!X4Ix-HSbs3A zr3)b>Hm%(Hhno#sk_(yjXJ7u-h^MPv4+cGY0(~BL=h54h@)3HjF4X}Ct-_Oh>J4e# zD5ZHoKYbAFPl-X3JAX5YxkwopWxE+?p$|wURiItIit|r zhCDmw{ohFZpM8BJ3wTwu)%Ax;0bm_Kz`I#F%MXa;)divo`f``n13d?V3OW!}27(_V z;zv(3fzkD!4*msH?pOV&0{ra%Io{`CG+b5&eCLgpy30c!6k-U_H{@o|#`@6hBi=(6 zui$oye?b;N>6ZboZ-=9$Q0MzVg%EQ9KW=SmNBv-uM~~G%rH#b=;(Q?BPc5GS0^!!K>$@^n*I?mr$+k>kla(%bbbTJ+EE&e+^Zm@)<4gH2e$i-m^0p_K432 z#M=<^Ki*IiKeZ90jGBub>UWHLe683zU=A*66eE5mzVntOQKam&y4mpsE)+qv1OS@A z<75vgeB?C`Q0^L~!~H*r^X@!B7VD*c72BJU=$qL#K?yi*MH&-Ia*+{TN=d2c~_hN}d*F6$qQR^3id)K>31osf>WbMqNF zqK`jRRrq!QF1>}rkops#>k!zIEyV^XhfWDh%<^!V2y*7o&>gakFgE4=E0~qV=r^jh zu?Ek7Pkwfu-I4)H-!4 z^HO+UQsDSz)q7mrQ4_Mic8wJd*fpVMOIO8Mt3VHe)`1{W+KMxk`tz~4vmJ6ObuJ~( zgpN@@tcQMWSqL!f1`V;R|HX!o5a9HQ$byd(Uk-8^6+9)9y=HeYBswM^_h_HC)OSI< zmPH>66Wk>`W5P>_X&XbiW&>cA-McBO|0&Hq@Q2(JazF+^HiPRg0UpxvwTp8R((5`IyP|=A zeiB0ek4@|WAZt!a#pfRz3&{jxywK6}AWUGfEgEa-S8TR;&0AFxw#I9h~~&`}%*} zcEKCR#m7feFs=1RZk8K$e-%T|%EcFvo25lye-;Dg;3wETfXl3_;zP#G51-?7>`g&& z6gQKX_;F?Yo6XF>^@I-j?|nrB3)la@G({NDlsD5*(vblUJwv-C52V6HVc9J%6NLlqIdN)V1P5sQ z5Tq(KFjrKG;lKGh?vUz)uJM@l%ATz)0`(x%MSp%6w#;dYQI+1RPBQ)jxk(HiKed1?i#mtIdL1iPa5Wd zOwZ1gf8{^2`g@0k6|L!S~kJrTEcZ- zSJt~4A_*ygWEBMmmvJ64y6HG4^Nx9b(MZ||oqg-4i}x$D+BSkL``qN}62Y~c-GL{%Gg!~U|LrOw7dpAlEVrPyD^j>CoR3$E z%PI>M9re)V-cL7W)qs8v6BuMyP>zKDCj@H%mYSsfi($6$eUT~q`HG3{b~KZ|tyn(t z%=#gBfmmRah@EG^R%nZ{ou#@{s(eCJvYUv8sFZ9*z z>$sZJ#pmZMM5Y^d^;G=iMIL#1!N+;m412q=o9s!dYAI1h9oZU8uONKON{Eb)r+rKE z`6?qzN^J|9cyNfoS)MFd-4nS|X?$Y3a{jjzlT@ojExGRQ)YebRMViuy*l>cjZ*(n^ay^JmL7D@c5}r!&+Y>{J`&Yx^ zTw#@XrB&FGQIfx;|ME~?n%INIeg$}EHURJd$Nwv8{dTjT(xT2=jL}79BqE}ZC03{9 zZ4GpEiu4U@+E<6eM>6=@`!2D-rY6Be@;DT#SAiBm9<`^n$lE!JYD?qmUKj|Y0BT-! zI2?-!)-EV>+kJegh(% z2(_uo^-pf+UY!P=^X&>hzIeL3yeatfmgTbIcp&C77*kA4$I{5wWVm}C1BqFx>+Q)k z$yiqNy0KwlM!VEPXH?$fTtE0K+FHtj_l+IeuR~Mm6 z{7kbOE4#GaDbvf$B-i%e0Fj^blsTvf=LMYB{hX$~bsRsijQG6;+^6%iaZD!s5i6^P z5|#5{dCR#FruVD|NCqInYePK$G$y&vo&Pa&h8L*dpOUY~4(wvxWqO_)`AtC2y7zmU zdMp;#x!%O_is{5?*t(@_ROL#Ek8F2jr00z6R;~5fVMwFNY)T?jF$Xc}d9w|_-~cT$ z`Zs~KMgVw3Q=a;j~pt#zBs zCwxZwLkS2_Dvy~^)<08W^pIh`BZ7TvB3B1)$}|p8ZPqJ!Z3c`8ZH zjE*z+q~czgRaZszimw#PEA@ciEsbh%yx-u^kfo7kl;TweDsHcG#|VUQ{&&O!W zWjGKuQYV1ql}a?o(JMHrnRd`kERK6DcW0u^w8z*fukjpeME&WT_JYbY*4o_`R~_|_ z;p)HD8EIg=vpZRM9Klj#u`B1CDU6JhAL+QTfL5ugEz^g@X{70r(ig`hQ^w;WbB3j| z6x8ymSw>yh`{vQ>6V313j|2{=f5Q-XX@>NANd?f$%G5516gkD9 znP>K^l~uvwD%^dL0)?l?60C{k5Sq-(8bl$G3kUZ-M&aK4j{Fd3rD+4v(<9Ku90=V+ zy=h7quUEQ^AXHIIIWcB$hG^ej@rA}y$&itwiJ=C5X}j@xF!{jm6$Dl8-#VeF0TKgv5BjpcyS5-Y`AuInUyY_NYXnO^(c5?We$#iXIY{ciS9OvRZHL z41n;TOx=q)@TI#8#vfF_y_j2NXCzh1vk{6&NrWBOa(rks-Wy}#N~jzx;xjFy>E0wc z{;Mp9BzLpuGTdz@)LoWtAW6y40<*HrpNy2(ZG(=ktGH2sDajbcf2V58R}ZtBJ*Q+? z8}6z;&3`pOiD&NkpqxY7Zej66YC@A(o-A5;cX4xFJC>DMB}jwE4%)#eB(Q!PgYy1^ z=Sg0yZe89_m}Da@w-m{Ec6Fq^mXG>31I z_=d8TMExxf*LS=6XUTJIC-YUCW{m(;CEehM0AH9v*+;MYmr}L$CTBWC8f1cCE;;0h&3f|L!ABnICD9s z%iDRxRgp;m&2Zy;ogu?mB*)kG;Qb=D>o3RY>3-J}mqg|1{R>g{oVuvE0cFk#+{ge`B|UYM;>O!3$| zJvc5#QKF8gicNC0ofvxwWPD~;wq1J^w1jB06GnaIp)`OxEq}Aq9}ZECjGXoyoJw!r zCdFLu8Z)AfEJO@@UscsBvA-8B#Yt5d1ZnbyAfto#rU|xFxUfji96j6{E#Y22MdFBs z@CflZY+)7(fMMK@f<F{CB7}k`&%cSk|sAFwc%HoT@Fl43vW+-@z>)Sz!?id;{{HK&8>G~(?7YYH(6fW9nNfBYnYPH>btSLHg>jXyFS{fW8Ka1 zxlOrOR{sApW!33ve{wk>BOU&&ibjrwT}F;s!WUx7sLYVlafP^7>qrTH^QEV zA!}j}rwziSdR>v)m{^Bcb)v(%SM{mNVP zCCLI)#h!ZdqtS&PRP))OAize?ACv>tDg6@`yTs~GNBCox+RFo3hYEzEI7|q*I!u<_C7@i zr+6%?%CWe|C@p564sUI2r7=4c353S0Q8SUQiDfBaS9X`mhkd3!F#1Aw145?hLYgMt({}(lp${;zwi> zr5^Dp*ZEt>q6WJj$!4b2qpZpz$!#~AonlG}N-Q1~I}{6qV@UqHIg9(!&_S2gS*Esu z{_no~=AJxT0?nge!Kz%_f)xF!lis_yPNO93nYH%*v@| zO`8+n3Au%?zris-_LrgJm{HHlC=xO)z{<+7PQST|)^K*}$L3CYT>zwvsb9R(&+PR~ zat)$RW$DNtKiLTPB+UgIr>%DPj`z^LgH@+mlFW@)ilchB`;Ma__ZElYaZXd*H-a2R zG$ZIowB+^b{!CZ3?kPfw%}u3Km3m0qg{4sR&Bau#zR_v~pAC&Fy+m=%!Fw}23m2?m zf`8ruz*4&zD8U=0?9EV&XZ2i)JQyq=XgKg|I6RBVU5an5g*T{_LlxQ%1 zB6ieW04c{!r2Kx@c+6*F!u4*rV;uTHpTug9GK8s@8bRgu+OX+W6a+pV;68_ayf%N-B7kFch5P$c6d(pIke3 z41DV*>!}0=BZj6zMu>bl$m_U>&rT*1mBK%I|2Dla+ zN8V@y*ch-Us`X@&*c5QEeI^P@1JQXgRJJkD3=*cyRov(e|EMS%{*>hIickdGh5uYwYyUX)0!wyqR_T3rwSNlI;X#T=E zj=hN7mKaQ|Wwm>2**LDXD-BWl9ZSyR^77qx(7W0h50k+K^trHk=`J2*J|ips!arHn z-zBRJ`A=!(GAUZxl7fS^PHTa-iwLPPi1HDWZ7)X&RHPK!X7F&Ks7Ki^nu$ipz#jM( zEY4;#3l;sEb5$ukHeR#fR>vRPjT}a+VSCpNuMHETUl8Z1aY4D? zJ)^5*%we;NbUV}oAzPJIFFl@_e)&_b(zF#3-Gm>ODJk>vq$)#8;MovLxgD5-v}1C;$km1WvFPcs~e#S#ea}D5RD+o!L~S%5_W^es^V8#8r8g+$0?~0hkry zbLzog`>8V8GzLPjSB_1pwsv-vTk37KN#!Rh)ybX<~e^5kKPBY=}Vi{Jk zux{PB)GiI>_kZ#*#u=qcRbonbM4{Lw!=ztm++yU{V!w5p0Iumv<*JuXS!kNchrxl5 ze%l1xT(HYp@qDFlyPH+L63v=H)!%%%Dx=mmovXCLOYTp{hhK-^1BIt4@Z&o zZe5{P?T5a>N<#*LkMkv7Vk?Zbg({X!w=c~UCl-yaUvTs%c}-~AgjN>i(cYA#&JpdZ zSzrxB2BeMj@tGEf1qw)3n(6;4x1L9=-HK!?ls7dtjhOK~<*goJdS(cbVrn*Oe6|3Z zAn=ib-Tmkd8SvN|J_wI2X{uBmZ@N&bUUtyb@rK9`aBGrECk{CdUdocJuY5zK=$D$% zwj$j@-1^?}nEk^XDWJbienrfkyMqLwD7$kM+jn)v+a`z`wE*HL-njYk8Z?+#oE-?7 zB&eRd6EZnuap3g7^_DL8s@>d@P@XrmsJ}kAKJqteny>&ti{40r2+xyqp>gh7ZhK;7 zANRo9`+H-tDHL=KH&w{k$&{T%adctam0HEulT$})KT#@WZnX{a4838?NZs8^v1IzwVn&PQB#9a&S3WoFKi>_fRvMJfCaJE32QYz`cq5ogRUn zb}4*I#1@i#U8{<`N&d8X==p*m&EGlmz&hI!!B_^5r+k2c!!Z@7vtzHrCVacjQJjTP_FKfbse>c4j!kzC&VJ@ujZw*1@kn-^#Z}?c*JBl&^n97>H zYYL=m(YB2oQD{WYRWV(VfRM^cV=t`aEum4wJ}x0eJ2J z_Ko*;-U;rB?1cR{Nq~hS`X|{VNhuu+<_qATSI3F>ML~EJeWZ&v-tSjxVW6)h9BVPw zE3C;-MVlDFDv7GA&XA*UH>-;H9Be^(hxWe|*KZACdm``8k%671>1d-~?JGN#o%5GcbAOk3esFn_SeQhO9RvYOsp7*&L~x9LLZ zvv|Kbnc7xGfM8k^YS(wKz& zJ(=;^g_LZ^nH2*sKhgDPyyn0X%&y^D)N}MuIcImrEz`Q|-1dC?T5kSuk~Qm_gLX}$ z^FbDsXJIr_)Q@dRMV~xNa+)~G)Y=2>BIqPt!gp{rva(q|r;((_o73sre3YUdX{N#= z)w*ZNXFNOm+0WZf79q_y!CxoZZ*^u)2y@&{<;l9dyRq;UEK!rc$q!d<_2k*D#_JFl zRq%lxv5e8`eoj4ut5KWLr&Qgt-%z8`w@pYVWtyFa{6Dp^YEb#4N{d##p8-9%+l_>x@(H{;w|L)fq{E7ZB7|kRjTy-c7Tr( z_j{KQHI=FCj(INZ$>f?Y>~}{>MlyPe$h|&APWWZg0uHXYm?sH433qBsvZI(tyv+Ih z$LPgd#GM>7tv)t7=Nn34*}|J~i>u4pr8%WfjE41_g*8BW{%3irHqzZ%j*m$7#8l`@fE|Lz9^hV&lU z{b)cHG&Seiyiq_syz!(0Fw(E^358;%EsrHQXhYNJK)R-P(&U3|aID*28Wl_T=`S@M zC~A<>q2%7wB-VGycoH-L=I>0Ag_`bezg+AzyiXU-nOE)tus#c?QQafeY?}r;iyZXd z%Ywm4T2CsqPm<)wH}KIW8C2#(=GIhn=j06H?uAT(2I-jYM)7sstrCYjEbfCt4=ko~;l(H3T zclB&j-x7yRQ#WD=%YxP59L*&Af;qNT?wwR_Rw`HwT6#r_mO6piVnr=y7h0it;Ih35 zP}!j;_+um0TrF`i6y;-U7#K{Yrd|x}egIc3slTd{E?(kd6^3px3#7wvPT1~)saTh~ z%X4^GVP&X_qqjBKDF?o=!eDK@v!(OGCg#Q=$L$P7IRLovngfYcA<^#f;zhovLWR<3 z8>8LC=dMNjGZz2sk<(aTo14JZd*4c&&l!%#L?9x04_tPK150+#h?UDnQQDav!kR1V zPmez@8>}DJk3i!EY>Im~)!y=L<*yAQgPG2bO`~Q7b|P>RV%h=u%gm3Bhc&#qz-4zz zP@8o)9vWUYF;2kI){03Y^e`uh(RHSXh9tT1ZMg_YIh)aeyNiJMtucJdbDw*>7%sR_ zknh6PXz%aat)61)>rp@N6zm(E1cYovdBU@HSp4U88&h`A*2ehwo^O|8_wvel_pYiB zxa`l~;45ce?|$cQI5uI{r$w8K+a2P*IBdJkYSl_&zcoo!$TxcoudmemRs-zE{low* zzt*Ns;yt=h^>Z;lV|GCPg6GDo?WUUu*WhfWrl*>-K`U=!NLozWmtUNZVgo9&q=Q;I3^ zNp^h zMc0t-*T!9^(T}5NzwnMEB+Zte{;&9s)exH+Gmu(-8>8+4%MYnDQ=!OZqypQj+>Xum^ed;(a4QKdh1?+Y0T~g<%nf_zSrQjLt$q0S8K=70 z&EzLD$##be8GG4wjV8of%!TKo9OiBXqr&kiUhvw`HDLFmW3{WW?C^n0xN0HK=H6F9 z_<#W?3R-u~)+oBL`v5mh=Pl5;J=)x8@eIsH3*X%O!@W{_%syaE1>^^g)WVg9iMdrQ zM$f*T@G1wZPPV#EeRmu+QCdD$pEhB(Dyv!uq6=oX^s8r*oBhiTK|Dmxr}kERK-6Oe z1p}V+Sj{XEXPos%kI)6)(u;L5Rq%+u=rv4Vy>Q(;axcy8Lb|)C*syx;)T$$|Buy#a zso)roTeZA};NejwT7zDB@x`-YY^~_-eNFD=u{2Uwm0{wLB!Lqd<zlR-H;6dJg(;+07XW z!ZNTIwfG+fbJm8~$?c44Jyr;ZT-w#w>j})4#CF4CpKzO~SF0tr$Sg@HXo&fN(Z!`b z64~?g+*@B9cbN_EO$v~nS@RTNLjbE1pzcLPTyau&iXK~t<1NL=sGOmzP^t`G56Pq< zb^5@dUGw^b>%6#N?wP#(C-p|<)-uzNnUxu8o)JFj1r?%J1^tASWj!gvck|b(MI@t4 z--lAvR$7f#@3Q32y@gMYT_D+DOB*k%uXH!oAsp^=utr!;fqm@C5V1MSYYs=zm;6XDUBE_(1;HM&jS#PWy z_k+n6NFjpO>nKJK4t~|K21O5pd?58Pf@8>yT6nBwo1BfOz}f%8c!9Bul!JkFPT}Qo zHXJ*{?5vzf3U&wO)`)CP_AaA>M%C9hETVwC^*}OAc->}!bSW;@3^>Kl3;$9F(>~$| z-R#*epO@y7rhc86xn1AjSHM2GI;mKXWP5fycVX-!tHJD?X|-FAnf&A!!IsLxIR&Yc zalcxzRbgFrex*e;48p;(>a#u_b}WP4ZtTSzXrn$~&~k7uw~$pi2M~a76;3cY$1JvPPAzl$e64u$bKkCa}D7 zAembv^x}-=Lb3@LyglMS20`s48QyDIqVEzk1{r;-Kc50)^sNL= z9*;~V2vjXckysI}m|fi3d^PG$4b(^-nI*=Doco$F713q))YXn^I%cvvL9)rTk2*#3 zV|s@M7?7rO8r&vSJlEeM3erw^v`0tX2x|^ogMABzNt;o$9wMqeA&}nKl+K>I9zz$a z^#UK{2|nWXJi<t@Sh}1!AO~olKUKF^#{4BVnru!2bZ1Wi{hm%Haq8uE?_w_%*{($mROMBl&R@DXtWvq_S`auqw%Oc zKJQS=ySE;P^!s+=$x+PFutrPC1}3*brj9hXL9BE9T5B3CpjX>9A)V`;t$v?jHn)7n z{LLi^Q)RDoqs3K~sB{ytIdRF+H(&EfL)KntrMySJrJYNcThB-4u;@mq*eEB@vPa2i zmH0Zb_O*8pOEzzv3_&naRJL7ksBatY@zG>bxI^K==?iD8j17t(*sN`I?_!70T(1Du&aA{E|+GNlDgo zt6wVb#(e1!;N2;+UpbC#Rm6zE-+nJ%APA06^ z{ndL5k@6rD33D9q5;duNpZm|$VcV&n<0VJ3k*DXo(LCPLn>srFIxQb+EMvjD^ z;PPaB;#^^CKi|K70c=4s4aK7(5!j#WWM@rtCM(2c*oDj{+l9s(z_wHtQyc^W-2}W> zUoA8vN`Bl$`8hn7tTHv(8nA@9YFP5_5>&MTbL6Pgd zC$7KPVNKmgQ5SYe z!~BqvSTu(q-e~(WPKnw(sQEn@gNiEjj1KJTy2DQ~&))axEzJ-0L&H;U8Y@?%8yS9X zpNrHS#q5Z$krk?@`QEGrH)!{D0KL)?3*x&#%_T4!g~u-h(a@FsG@m#j+U4 zi&s4v&I`^k9VqkHeE7gVj$5opGd;Ac0?g-U0Bj2c^+MH+*d4OL=b%lS=Wq@C?$_(= z3LPdN<^{MpEe34^767`%d^b(RcOu8t@M<&{R%UoX0K%&JW-v>-}!UmL!&(F&;insaTha z;pon5^0xRLu)bCo!1i!InwQsBqd*IeC0_=6)Kw{H?&%2BL)NKn1TKqZ{ST0PJ9oP< zK7z@Yw;Um-MNgFKKsn`-7Y!a6Lo|{Hvw?=klJy!SIg*-Vv40hOx=4W)>Dt$KrVK6h zS&0ruHr?Dzqe2{n$AiCPmjRW__}O3et`*|P04D+TGQXGt8C%$r|Aka$R5#kTRZnhX zWMxG@h5#oP6VIZZoR`69GPI1_XxPDa@26ysu-S17>nv1apfNgcpLf0bxM&A2*aMcP zQl69T95vNJB>pg>Xnn$#hiW=DniClh4<-uh^rbjycCB5=Fp|vV(HfjK zdAN6%O5@fbz5>Lof1C-dHC`p40pS77Yf`)zLjNXtMkIk z^xX1=*vOYC%tjpGKPDADV>=~z&^K4#$Os(8)m0alq7He~oAsL%Zm+_7`R+RWnsyi@ zdERFrvsqIh`LZ8hjd;@GLMv$&DA#-2Ti!^;Lgb;oeEhDoi#G{aOY6Y*Oq|bSdZUef zvA3*%?d`o`N&A(FjuW^1ixji`WQEyMPHo38M2+?Z8^bAn+pfQEXPX!o(<#G2i8`~} zk$#6=ZKLy8x7;QQFSqL0;P4@r*@*G*DD~PPqQF#$-a*;co&rB}*K&ek{r*;O^uj>& z)=IWo$B*urOghKjBba~eo041O+LZYK3%4N{8dO_o$_O=oAdaqT|{DJ2ue5)h`=oO@gOxWe5 zZl3P$oSu~`Okf)7{q9aNEYA9)(DD*Jr`gD#b8Yp!pAdCY>x<8(m6H;QL+r|OV176x zCg?;M+?&28Co)5Y(G^|Fg_0!sc9Xex&-gA+n$$RcKW#V>&^dXjNCjkZ$6%_SZT8bT zo_&5fq*}pd!1}Z_7rpO#Ko6Xg5BQv|kp`q)vPrTmSK!{zz)78mr3%;8n$1it<}Mg0 zI1|6Z@$DRX{!*Qi1PmfdTnb5svi))+&djH5ETwyDdkaQBw~6JUwicgDq0;p+*D7Kj zFM(9sh+pvCX(W#UP&IXu^2T4;y*J8Vx=OrrpLb(1Fu(7+Lg7WTD@gH$k+!H9zlTso z#3RFw1rr6Teofk*gW;cpYeRXdpTlCoG_(cpl@-b*YB9AYGj%g%mIt7OqI9{TwVmyAYN6Wk567u)Km(XU zhn0<~JWaE$Cgrng1qBV-yL6ZxZUkHPV~LD6bC-}~Iz+1aA!huM~7fjw19shC}Ew6rF4ueUD;rR2s^8IY|@_pjr@N5kt>0Z1! zf8Sm-XXo*i;8~Ciaqu`MJC(o@gFa1rWAQV-y5rH@(c*@l0273vI!`0_jhFz7Q&mkq zC%r2gNJiT>JHc+lVY*^m=OAUOd}+2O->FtUZw^Q)s@^|{LlN!a)nPK)*V@(A$(;iB zc-f!vy)7rrNmhV_g~=qcie#oMt@np|#Ijg@URW&(n`t93>3@?lJV{QT-|)JxGd$s) zLPsoPHmEXD!w+n~60Jb5qG<_E6VH_uUK`u8h+3Z-b=(@}W+pHk&t#8U_yrJ2 z;fi~+*G$DvgsJeSpK^Zo0)n5o=?iP1YIO;3f&0I^kAAxq9gn9x-R?UtOx@~*k)?9z zX$$+sq(wsojSd`K2kgp*)?x^72+z;h&ovq!tnBa9B$C9K_SIgT+%gl>gde1!f_l!E zrIZZaC2zRJH@`V1EH1VjFzF=6)7@vja>A+DUb4 z%i+lmdA^HJpF3 zvqFZbXxxX*}O8!RMB}UEa{i1?gx~CsmslKhozmm|Ysp$Sl!h`2rDN?QWH4 zG0D+4Og9M`XUI4F)X@equ`(;pktb3QUlg}7Rf1^v!6m~365e$%C6F-@_ZBo1sL^3< zMEQ0KhefSLaCa$-yIOueUEMue;5;fQUE(C{b}0n_9|8othLUAawLmJ?al(5F2g_f& z$n!xmQyzuFm?sH?B=CrYc`QE?jO_O`>>`HUU?u|v>eU|JYyw9QHe`!aXp(3Wq@J*z zCrj8bKcCB5*3n`zzUTo4kZOML0^(!2&RisnYDZ&?6ADG8)~J`V0f)4M>2zw=I669>-m^Mt zZm3*1U$#UO*k1R-@8n?4Rb?40$v4CRL5zg`Q8@3yKbz{j+B{>&c4UgxVBmB&|JWU) zNX8BdHaspkN>3>e1rgzgC34Eye(9vF%zA0NXa9I|im2ne7+xhld}MX7vp1xy+$E#9 zK-shtOU$B`-{y{n{o^U5ST@*W+Bnw$Hn#GPTfvP?N4)11$R8-6eKWV6fs?qR{_kVg zIYq2e`vahHpP}9Dt7x&4bgK6s3*B^YG|)HrJ`}5vUR9>*S0q*XRhs7q;Yz5KnDNs7 zez{vlO{)CiHt1Z}Oaccmkd>xKCAL2#u5_|3&0IuRJB}e$NTG^L)^I&uLfeN4;9&95p2PdC4-t_ ziAzz6;ArTkqqywyI6Cq^{o_ZC{D*LF0>?WU`C5Lfu-o@IvEA^;2>-%Xm`1*&BAj}h zH!Qz#`W(q#&Fd9jh)3cCfT3_ExXbd_&;CAeE7%7VIPld5ES2M%jH}Oasd?8Knpm2J z;9AWa^K12D{Ep1pssY3Y0O~+{5 z>GGVvOBmvu|Kz;Rhfk5tFW-FI=|>LBWkVSb4mFgZJk`@bZJjG|T%fS@WXCklO&oYu~f=AHqKe6kwb z3aWGxRF9{->rnGs(t7@PFdQLqi8Nag=&L*BpZX^6A55sa{1oqsd?b_ki$^`9KHozY z0yZb<7@0kvA-WV0&(FJI)4q#+uEr4sg9V!5E)c1zg|XJ~#CeD?l-fg92<1)#H};e@J<^cT*IOgzVSj0<69Olu-= zt!x?1!^sYuKH&(#`Q0-gf)%fHXjXVlo38`R+ytxx=8Zt9e@9YtkBgGAR92HIxBzSQ zSw;TCok|TaNbHd<8>1n=9JY1MR5n4c;Yv0)<^7${l^JcIqi+djzkzY0e+(proPl0I z7@L90#{a@xdEEqX=P*A72L9VxgUUq&z-U#_@zgf3#U*J(CTvQ@_4z(@i~CLY^ap_M zk#(S!=lQ_Dz%-Z4PUZww8#DUTR9Z()~<1Bz) zv+)}O=ZJ&E9qqxNP=o-S)NhcAf9LMXZG=e>4U$xX0o^=b=N(V^>HK+(ST2ZI?r?f@KK`0SH0Z zU%yNL%h$_Ke~RK|Zv%kg7$CWh$?_O6oH?7Nr&r$CRE0pftBj5c`WLGOVb#;r0l*4H z9TMrQr>-BL0ez=k5ZL%$?Zp`}_+XVt{;R#TAR^a*F`}z@gMwrX08~)s4F25IN0wAUqtZvj?Ein#2U>x0Rwo|<#nQ!WVi4TgV z7YEV-f9o;u$*ULvF;!83XLJo>3Iwo9&Pkk${7Nrmv;cwOKUtvSSDN3f0L_0w&E4Av zC>*cFDE#jj0VDd23>f^ahyPK=OPU@c#$zq-cooo-5>X{;t7YYSjX+$0zyVt-F08AR z1OVa_G=SD_a+Ozl2=tKv9YJZ*t1@VUkiiBdqN~kf2mqsnx~=`IsI_7-04ZOejz73M zYk~-6WSqPrCSp~l?Ynzl3czzJ#zHG^q4YZ&|JlX z3cvseEVco2NnY)x4uN`ENiX4fwHIArGn>fJ8uKc2DA^m}*L$M>6$gY`Mga6B{~EiN z_jvOj800M4&q!T8XZA&ihpbNRlt}u z1P&^jHcl_CvR4-~mx!TsJf#~}L>Glj!{c?svVZ+IAjNWkL~)}sAwe!v-T(XvFaX%( zrNbB9Mdc;<<_FJX8Vy6kbaCMLsgDqOc7es?5p6A})^Qf65ykQ9<>V<~N1?^l9P6Wp)~BU*BKwbcxF+XpKSHUjc`%}?9eH}ef%q9 zaPFwX;7CeEp!_T)VdE-*mKXxx%}Wagr1>)*EiLM!>QUWNWth<>T53Vp>jPA0pt->kSz=cJ9hsmmjVl{1-dA{*q z=RrPLX6x2mlr%gFK=y7PRRJo`_qM_UR^h}md# z92*+cqcYE1CNdL&*uW~_c@6s`SR?;sPSXycf|!Mzul_qjzy=c-kgFyp6RQ`H`btp@ z3LST|(z<$+_+Mw<@$Gg%MI(z*n|>_6LuxuCLtXfrvf^+jE-}*)u;oAD7jUAj8bVJW z-CbG{E2~NN^FFa*rS{<#b97*QrQ~AhMAjkVD8>OP&#Ou9h2Gkv5U9QCOf0mEl7=2? zI-2aY;9qE2R#DE$yIR$1`_o2}vUPKixw5?GAnlpM(TwokPMpI?4Pjxuti%`CVm$zc zBqmi))c7{#5#Hh|E%yS%iI1{e9m6cjxo_MYs?x6}AHlqw=#da1^|WM4=wTR8VliH! zm&9A?(UM%~&wYMjw9R{CKBsrXGt=0REp5i2t759wrkUf8o_F)u{zEe4dm$nE!eku+ z7M!*5)8=7Pj+~J`_mL>QWQE%w5h?`GR}^DxaTJso)^dm#vV1~ z%H)$p2t8wI!yWaN-cBq|J!l2rME0>AWUj=&538PNO29e& zeqa4bqT{KI)9ekZ3gzJ;a*>!=k=Mgr!k!OO6nbB=8V-x92rZAvxl}FIh`hL|ye%^u zrKD{3!O}{^xSr4Q+MTUWXarMOZ4K+ZufzU}k@?*C*n9u+gAHGL`!%VYqGAa$Ma*to zloSGKIqBZ@sP54mI$cZX2;Wn>Y{8k3*WEE7?Qh@FHz(HVN8Yw43Qshk9=mQ6kCIU^ zik$l2G@mLVyo-tVmGs`5*XOd`jc?-a1sZ1Euk~~}l&YGRns84Mf`E#bOVh^aEQdfg zfKh@91#XNc`ho4GZYFbF20+ZCKB53h5Y?&Sk;G9tlrf8Rb!bl}Pl^*^~A)z3r zuGrR{$1le*Z1%6)4*vOj5(o_6L%1jCpO)VreoRpUEUR${R9qQyGr8{vu~kqW9a@Lf zOs%=IeNjD%@d?kzv5{w{YhOImsX<{f;+1|BJzw}lJ;!!t;d#|u=WT#9?6v9*LS45@ zsr5QC?8+6k^CljlyA#sc({V1r3hQT?oR*MK4BS>lSj*uNF>1Fd+q5orrQa1fnicUx<|=-iQc5+FGr3)1IZImC zMtt?6M6Yuy!IV-@mr~BF?KdBCE#H$}39uA*c)$`@tCTgqS&QZ9miv(9;`p4W43zRg ze?=-b%$tRg>H)^jPF~u#5IPlY$D2#tG00R|=Swnue#%%|0@m9-Vlq;Ln#r9QITBg@ z$Ag5qMMr{Oj@lQQdzu~xz3XMdR3AvV-f1>c&Y2nMo=?HpDwmi^-qAU0&klT)reerB zO(I5&Zxa|F-E){ugA2_@1(%}4d0+Ib=Iuym#DA^NcynFp8zc26gbs>o_Tx>e~^EqZ_@En)YF@GccV6v=+nE`$Sjzxl2L0r&(yjpNey=v@7 zAjA=nyqbE}6a{djY}3t+dsu_1LBUo3@n;(4x@6P5iMcCdfx+l?&U@1#-Q&naLbaS2&ELMr55 z-Z)jlS4rrHAV{Ot=8(SH4v@xwNt%s}(DH70Mx3|8NAbW+pQRPeVpDAXbNy}no~i`Q zs)Su*OA`^TdW~9-;YHXpx09DWH**qV!I4()R;l$fA#X+-TAU9y+0}6>Z`|5{|LY4K+ePf4L0x5lMeso&sexwzIdR^|{~F-w?Y zH_%#Yy*mXfa|Cs5kB0*(s~9CeFbbH$Z~1K)m$H%^tT3kldU#-UH08)Hx?oUgSGG1< zMfKN}DS!W65kLYiVGU+?d-8Y7UzaJ8dD(>lrgJ3Th3cJ!g#3qvANzX4 zH8R#ec5Hr~-9(v-^XtM*D6GaOoRV@rjph6x-9K{=oHDP-G!XbCafH2UE{b1qReUAD zu{&q8*QXcVCU=IpKuM{SE_b($XI)NH9c6JPfmUccOvFw%lqiwz)v}veh4I0!z^mRb z`2t0DWy5o6BlK$fd*ohPV9;qA(u+a~PUnvl6^GxRErFk;E4>_*#d2cQ<|4%FO`I^u zPiyzz*`VKUrqR_q2uq9#V4n5BNWiT1$eFIl81|;QC?=vZh-`+{KLD|^%C~B{@^w?& z71evcLfxIp-8N|l#3)CeO;7pAf!aO?=1L-8Uibwy*9_MN$^aN#iBD&6H2Pj^H&eXh z>xAn7c5nl)d&B1s!nFXx^*k-`dgFt}fBvv<<@w;9pKaD;X(Lmheu0AICAd@95FS6h zbkZIDtf1pF%Eao4ujr#kxO!cOXHO%DQd30mKuQ{ouD`h1*eiXsML%?X-kx@fcij4D zK>FsQS#PsIhA2MRr4;f8FrpT`opU*8U z4{55FdM~s*Ufe*pVJe@BR>4KTMn!3EcbB}RR*h2fv4)bV2+`(xs;wVgUwZp`xOMe; zRxPV-w+gkIk=runm4DgW+nS$`2yW9Vk?Pf{fZ9lZ!dK0d5_zptq zz0&&{u0>d4KZwW#Q(#1@FQvV%KhrA&%u3%^k@=A850OP7JX*%^57p})?aj{pnW7T8YomEc=0$=KjGOnFuV0S^T*W8@7^0(h&XL!N6HB&2JVaPv z{>N8$Fo4qJU0x`$ zmB0R?eous3BQ-nx&qaB^e`6g7a1P2)^~ZZC@81TxlM|e0yxyB2Qav>wCZqSp|JJR4 zR0`b^!R@0HyTj`bJ(C4UzGD*mEkdZn@eTbka3vGWCmUW=v~{zLQB!2o4jD?RA#FJC><;VTAwZy1l>F`}c8gVk@RUHr6rK z3BHdlD5-!^mzY_k{ygX5|2z$k(*Z$f+xpr*j{U78HXTD2CE;cxL~0>mn%qwRnuZu* z-wgi*UaCs|F+L%GS4L8}u?LXj#uUR>*M3N8ZHb5p@9?`HUT4oafwlb%4O9hZ2xfiw`L-Dc(a!;#rVBY3Kzfg?f3PcDf@D-z0jIO0cf zC7AQF3w_Vzc!yF-R6%$=TM^%#M*&d5uIT(fgq#~;);1W6J3CAQ?K-`0qo}N#1=ioR zeR+*Oz{rKSW_~O_a3v^D0K4;v1N}+GZ2s9FpfpD2j71&hUaaIAgb}kebE!yPV+3Tc zu2~H0t%o5AU_*c5cpW|A?DYPfgH=u1|HB%fxV(+S?a9vt`ujUy;-T0Y-t*U&jJ+;M z)RGBRp!}V(p){q2lM+BdBx}s$uZz;1n}CiMmw(?aKzH$;$o!b6lwziKT_chOP-0%= zX5Fvw5KkLeC|H3O{9lMGNY}&C^8;pg#;I!v5ZBsn6A>wRaTp zUA`7Ho%jQ`5fyxPpr$8qg=>H+_tPUB!NP1f5vDyU$s&^ec@%=S8eBA5~`WaQ~SGKO`X;C+NE(Vk;HHADsbQW$t&qv`>m z)#53vUxU$e|ImOYM3nbzs&*|BSg7keUvm-3jQ|tV`^R;X*blF11mNERib_>}p*O|~ zLFUB9$*xi*=mS_N`IUejik7u&^iV!~hH&%fM+L4K{o^?Ji8NPj?El}>>MGTw@4GsL zr;irnI-OpOf&BhGsh5I|X`@WnoB8KsOOsGPKi(Rumk9n>lHS+8<`T%fRDpn)RarUJ zf(WqsW_(-(zvqrisrCSf&z)tdxlOOArxJpN;j;ho9%5ojmt|1Q z{t#buU}ErZ`QK+jMg@~UtNJIld2{b(X)Du`)Z!0CUvaB`c3K|aGAm6A>K>b%HsCh; z*5TEo^2ehe%h<-8(JPJ*_jSpG6YrI4K@bv9CxdGC&o#Qg-`I2m2vE42(E3x{P{G9S zcmDBZ$tuXwJflcY9#@z?F)Ae3D2x}`VAC)kj2Fi?3bb{^v|@_@jReME`ok`*N}?L*mx|@Tp$|iQ0c* zkxdQ5;pL&@>(H4(o*kr{9iyx3S`EFw=b#T4n1ie{2ZSY<^nBv{N8tNh;?h5$11?M* zE6De^ZSFNhGRzhBwF2=>CxCt>qsa(uyT%`s%30hc3~uI_P2_*HFo2zMI7$o1zxl=I z9}li-#toEjPcLoyvun~4kFp~4ady(4L*|xfPfM2L9RkBD*uBab!9ED&JTT5rZgZb) zrlDa*2i6a_8O1qRjo809&we@sg`DXxNRLbu(*1gx=kZ$jslD&*|G}IlBh2Xvj`3{c zIq8WJ{8qCb;iYZAQQ|M5%d*(}aquYSuY3`ch&nHxc~;K4n*d^tK>+IgJc3~+(3 zm$uE}wR9cA_AvsZn*OukEmOk()b~s$oLSV zR?;CZ$}NX;>x|MlF1`J|JXMBXcq2*>c3;!l`NsZ&%;uuOot@Ij_%~=VHdRmFe-Xvr zz@;w{+3A+rBcmGlqF#90?C^GxNz(1xRE9&GU*4?=q|qiKR{LHa#fIU{9HO`t@@0q4>f+6vOsR$XK1S}^W|`yt3Xin@eebLm+wL!g0RYJ zsXFkRR0@n+`xkIebu-Y~B^h6|8z$g@Q__y-l%s36@-sV=rlfla98$8a_WlkzRE z$h}wEq^f-#L%!9UYvgJ@bB`3&)ZBSq;mv^~+8Uwj%`cURh(Zt<**@iikP%_oZ$n0k zvA6PB7QPN*Mg?zH?|ix*M2eBMAy#eqw^RD@HP)L4%4l}h2O?w43g2@Ze98*pM~*X{ zV`6Th_QWJHjr;T^ZUu*z%AUi&KQ_v|HE&lrOSal$dXV;OigHAY!mNP9T0r0y5=Q>$ zusftTw;_khese2L3k~cKad~D|MtT8{Q{`x3=!}d@eBAVNmHM5FZdw)3=9qK$2P5TU zn+4=)u^!iq0`alETKV|R8>oVmp}EL6w)Ny;(f_GE4jvv4ki+qoN@h_aAQ{eyhe5FI}n zUBQ+BX_)^rBmG+=VMg^J()P)y&%f-ZW!X5&_oq~8*zHqTMSOZ=^D*Z25ScOF$x6XpV_MSvEAC`R{;GXW( zxCZnFwVZcyovwm!RBW;~@O@-NBkL+Fd?jN#EJ!ANLqCU zj^(jDd}~SBx$gAG(Wu0#kcbWn_?R2pdXj1uI1Kk|FDbR8AYCTYaELd+6f#e#CGB@w z`}LMgx+fWkm z?OS`Z+)s&-S+sf03Wu;=iC85fJ_)UWJYylFpXTY5YR@gwZS5;eB0|d_YFQYZ=Q-Rh zYLxZqrAE=xus00qof^7Pz(4DclQd>i!cvovjxXMHroyhf%7&Ix=g51aePi3=W?WYF zt4ixSvnCYPg+QM&WSSC%htENL_-f)PkK@3;-RUnWKks1QpDQh>d&tNyuon4)mRX31 zj;_4{n`%r&lbo6L<$3MfCK~rB48V$<2(O%WeMw45t*DZ@hmVlc0UB<-&Zn=FSRTfj zh;!N2Ju0lLm-||9bhZqda`DlSNs`I4ymYPhZ5>qNHNYL-p$RKON>Y3hoo4+E%#Qma zt6eTWK`PsRLPk$7Kp;VM8Awo`G1||RF8F;HC!S$MZuEJogvI2a8>B1Kj7!AK z({FKR%rxV9#vJlE>0zD2Wb?4I)uey({LB`xKuS!OoKnGC1Qn-L$=PYFmO~8M=9SlN z0-kZc`BaF0sH;{K(D^6@>ieGN#;nZ)?&-bzg)@0olsPg?x|_Jfth$erL@{EMZx}!CO_YM(@LE9Ly>J!$w=7>9o7C1>qfD< z#gjV=1OibO&rpP@Doa9|#$Pm13a}k>ANNpW9#g>CL@hh%6} z%*SCK?N{DDjH8lSX{BlXv2+J`uj_HCl>Q&~-ZCi8tqT`CNl35+mk^xbPH-C6;O>?{ zaCe8`8r-3Q4uJ+5cXuZ=?(P=ceVUxyx#xV}t+{h+{!Uf@daGXPz4!8Gt*58V?a||g zLDA}4N-)<|(XrNJ(;Df1NN>xR6-OB$moO$rLaW^c{BQ>6FCY)M)jTfF$W!grb47P@a4yMu*Buq%eaNt4#gqSp&06Fj@&*@ zbe>`u1#0bo-O8(h>c78~_vl%f2vV_g65n(m4}|`Jqw7YksO09kRopJLL0bM8LtLbb z01R91{EXq}oQzmv^Sal6zc}T>Q7jawK6Jdii7fL`HmqZS`1a_ImX)@E#`&T%atb~} zFqVr8SLR)4j$zPy0X{KgMGF>fw9=k7jKi<*IWg^uUE^(*f^SmIU+cR*qsO63?d;l# zqkeX5Mi!z)pGVEuQ!LVR)WFH#89G|vn>o$R^ISJ?`&%jQ4X69Yq|fr0h=qS;JtohV zd>zs$SSNczx9T3-v+>b?*(>JYEeq-dSaDy6&4Y|FmG7BNQww(XsY90Vl=YGq)|4I# z{(zb_to2bWMvmqC%?kAWygRxR|6d8eg>M_-#D46!4zkr|9X=)xEGu&1TnRMV>)OEc zB07!y_Kq(qa(}PqX&0Ty=Kmw0hXqlcPYLz1D*7@;M_Mhi<7M4_p)H<{6(LYcOWt5cS!AK|IXe~x`RQx%c-XGT_dX95Szz8sLc`$X=B8X^( z!Mi!Q2CMmI0ac2T(4ft~A``Aw%y#BS^54bgIco4A!$zA0yhC)FOC#e!OZJ-j^*I~F_^t~n;YmZCoCcsn!J zgSpS~TL;YAolSZDj+V~cmh8r!zaEsFLb*Tjn}T}v3@=-EC&zI2qSrL&RsZ4&K;`^3 zit5qC?oOop=Hrt(R}c8lT+0)_g!0Kt3pGMOF~|y(OTa(<(iNk;#zH!h;-|7RIVEt9=|G#mUC-^#@e&X z?ys4SxKDEZSS%u)Jp|XUHAI({xw*PhUd9nW6yRJ%HBbat5%LC3xDF*nNoeMb{VxLkiUWgkYS;e?UI!aSILC}H&NB2H44gdRD| z_ibS@Hev7tMzD>}<cKk@ADbjkN!Haz8-@Q6A$hH3^_RH z{o55|Gu$5XfQ@re+~0P1Z1dt23_MX2yPrScR><3j;F2`Eo>KJ2&UY2$r2~E34!o?E zLTto`vLP%xFdz6=7~0VP!a0D0DJGV(*KI48u99>d3iXt2eDEYHZeXy zi|7YNoUIe=w^23U=cu9&-T{6sp1Bh z5f>**rkAMpY8hL?#B+qTv>q@dwr8KbUhxJ?Ekr<)blb>oT2_Pk{j;T(Twyp|RJ|F4 zB<5BseiiI4cQz_Q1ER5K-)~Cs!3gLHm8e(^B;i~nL!hq)EV@BTN2l4BBd~a8Y zg)VNJ$*ZjQtd6rV#1*$@eyy}9LK6W~fuPW5yiu`qB&PuH@;!t_{Th*yTr1qc%&=4N zH^dCO*wTiCiSxGt?$q%J1ya%w_$a>9;?41KI%h1Ngsgliso1^OzG`)nHHX{dTgLZ_MozcQ1)r>X16k+k|H3ze6*Em_ z=tXSN%4i)6o_X)@62E6)0dP&aRPzV#2g@PbF-l-0ru*P`Z^)uf?$j!)sD4$Se7Jti za6H$>$Vgj$ZBQ3xaCMshJc^Wb-#-p)#4z!F+#D;;YLmwf=|cqeewFZ zBzyQ8nz$vZLFk8Ph+|56es(*d7Pz_K{E2<>aXn{vtnEJF>WdENq4e7fc1G9YH95(1 zJNnygo4jHsWWAgA?>2^_lUK{f$PnW8kyx*`HP;5@rTXI}GUuIG!lUWA#~kiYXHuGE zuYBBgTK0mqh?EnC*k(Tn2SBAie2tRQw#yS5Y%E#_ytuONMoix-6rYbKWkyZ9OP4$m zR1Qs_Jz5vaKmbbhe&wq03>Mv{FA-NZd$D*F(TO>DZ5lG%^&J^_j6zpFCb}K(eX~4c z3(ix~XDE6WKLxkEC$z2d=A*li>^hsdCr&ux6w}A{nk206BZh6+hh2u(;uQ!tK$IjZ z$*d(rYL`(Lri@4mLva#*3PiQOuAKyh3S)G3tNgyBe1%Ff)9bWU3Z0^mG@|PxDQb=I zh2lCc1{8D-)m|-bn^+GSGK8Cr%ix;wSCe1RMb?A!b?luVRu5u>TGA`w>kcf`a!V%DCfA1zJ*r+rL9_rk%u>@oe!{n|Hz$hMXm(b1TyYoaS+Em$ z@<&PxZ-InhEzc`4@svAOlCPMHTz6`n&~CIcRyk29yix)4;^YO!)T5fw_tr6|gMR4E z_HO#`5T>|0KQqc@`Y2~epHg6sHl9;KN3Dq4^L(#q;bMyS%o~OZaqe>cFI+*iU?!}v zGy`^hZ_S$+2n8@bHghq_hlfic%)2j(SVf{}H}ZDgg>vCzx~Dtn8e(U7KTgF)6;Wz% zVt^`|^TpF+Xxcmg2d?D7)7dun8af$OZPJ8+P%W1nE|xL>DZrd&-MO2myQyx2bbpgu z(mK8a_iV6)rTWgeP&gQI$nyvveP~t(a7xKAlAhzf;MB0x9<(rUE+R|PZ1yna*8|IX zycJ$x-@TFWQ2VrByiNGrPA&Xr*DElB%f=gqqYzA?P;X`6;MM0@q4gXMG)}1iDDTFH z1Y`rX4>amv_edt^?yu`pV+6q9-4&(+VJkOQy_3l9Q`x$cx8ty60ertXzW;N-`3WOM zVG{@!kCihdWY|hrC@JAvGl{YVHmIUNPWZT*!+CEzqS7LKhTNcD^y+NqgZ&l**V?-~O#2xF4+72WrN zgZu42jZJNN(QAJ= z@U;i;8XXsEvsnD1xB*qGf?Sil&Zd^@Ae-LkW8zR`A{T6PE)7sHVMSi*X*r?Bx_RgO z9$%y=Nuv2w+s{hxo0DqscQjY$Qb{|&c9dEiUKic4z#jT2knc%LUfP2n zJp>8JPPnT$rg|EhG;sw096D;)j{I=_LUDbxdShG^1>N1*Dj#FG+EwM(VJRZgMv6O{ z!!6{}l+p%6gXetTGqbY3e557QYZOUOUtN@uk{K7CsxL496j>wWh%&CO(m^kG_@hw9 z&eeT*bUGmDM(f9yFYUBYxy-2-B?0vpZ1w0=!uhhDLu#244zV>VQ|*jfVX%0{hfzPg z17npVo%r$R8M%)8ib`X}jq>;er}@`*bRN|Z%?kGyLf#kJonAyY4aV)spjx?38r9u* zsYhGj#gU7Nnp3e>EyoeI{aV(kjp$!&^VfBOvraW3Rj2}W!gK0N?if6W^&3j-2qvoh zi{1*D)>Zy`-eZAb9|NHZxSLe)Q_BlhOpZLUwt-N5#v3Hc*J=4x$IFl<5eExp@V=AN zhgmmA%b`5yGiOZEVHFE?4IN)hu>=L{l`TE}aQw~{P1kba^lQC+htmjzsf`4u8>^

N>;#Brd9f+Ju;>%&+YAmoVr6AzZ*GY zi>p?H!tCzL*VvJ>y`xj7!#xF;A|Pd|_Wx)pcq&K8Ji&&v2Qb2g!5G{n>0S~IM`hk_ z$@jf!0!Z~A4x3JvVp4cj{PT~O9v&Pz}FcIFWZ&|#fJ?g&^u!xl2&`~6HDFM33Hz-tlMA>xVWB92h zH2xf^JuN>pyS=ITcB^Kv59Rbj?c0*6eI1_bBiB-B1#>}@air8k&0rqUBbtqcLlZ~1 z!%>^M4~f$(y@!6?u0UmDE{Kzk(JUXVWxCcbN$t$eHY*fW^TM%EucJ2ec_qjLW-bJTdG+KE{bFPgbJZTtrq0kE8a@ z&sSpuPC}fTQJfXe5zo+lwYyQfwz@aovycjT3<(7mTVtskyIV7+W7JPF35cqSQJ7j; zif)#EPL1BNF>in1YY?Ni6f}0`c+O9}TVN5Lkr4@cFK*r<{wax*Y8_IQD>pw*lw4%z z>Ny5>wVNWX{CICF#RW@a?9)Cwlg`u+SXY)SjC|e|D{Z{oD0w}*Kj$ntJ?jLRW6x<< z@m@Qi^WSXUN8+Ox~&zQT!GBvPJ6aNr|I`}#)y$XZzGCxVZX5bLdk~!=t zlcTb&at*Q3b#0kkJBiBdhQ7xK?CSNl`6xGPT0l+|W7Vurb&6ZPM8~u-*;xl^a5n zKHD^?%ggt&I{Z2-(q3XF_?&pt#Y7$e#oa9-+R9} zOE`U+(kN+c`;?SJM0h=h8#pXOb}O*nDhA=Yp_Ix7&U z_RUnkE@hL_-PUJR5uIuEDAUNWG+U`%PKvSF;={Y+^IG}kcL~o1re%`H2$`wENl2$; z$PQ9gWsW$dG$!8l4bfclc?D~s<=Ob@>u9Qy-4Ke?Vpvi}m@{@7&%M2?WWz543kx{2 ze_R+b!=^HAY}zON44d+_+Biy+rrnvd`(|jwESz<%UDEj{5pJ;8Nu&4eh*~w5)dJ;pjF1}+ulC?DN(mfdU_ zCH$h{{Pt+?gIza;6*E<{MBDl(fm=O5+wlcHE(sH-ZbP&CnziTMj*yl9V=i3eq1U~; z+vnVUm+6X<;2PSfb z%MMWFW}dogAEhO=WD{qg*Iy`%Fj}FsA%UG$08339HDr{jRjmEM8*Q^5x)toh+FyXT zi8B{}N$Yybcb64)aE)Jwc9;kurn)0yOM}1Fqp1(pDYpdFa0&$KN^n*+fEDKRc0pws zsH#JOJRe*z_+2s#^NE^&NjUQ?GD&rf<>b%4xB+0weF9x0 z{8}sjgvYRDPu`Ltq61vjV+*ffUB(t_XbTnuqBa|BY-54HOGKuT!+nVh@xq85Ubl+n z^|X$!>|P0;9I$Py_lS{41ZJ$ySY1Dge%wDKi*a2!?&U=1A^aRr{H;dYcEHbd-c1!n zi(!Y$`#aLy<46deGdI@7t8xVlreOo(8Jf(RNz}57`qncZ1Yg|Lqzt+0H zO$B78zQZo&_-c57b7#6wbr0(^^;Oy!SN?3FdOX0Tr`?Pg9F0#hDYGk|6t2zmfrI!LdpXBKP~?Rah5yUX$t8NEv4K(@E!1GswMp-9(#7m{8(y zpXhaBlf{Lo3lPVIvW~_cUBGL1t>C7lRaG>%10`zDdG@lw4mBaeZg_!El3WOr0C8N; zo3Tij@NkD~_&L9+h{c@&r#FO8;GT)m zkrJk4Om9@N*N7Agqsv~~aE1+BZ1VF!es2dDI zjkFdbmmYRfGf7l8zvJ?CE>0CcF!iy|Zk{Pl)xVQ4?nj$%IFq>9H%&~BLTx_r+UM#^ zp@dF8qUhb89q|;-pYSF^n+eAxhNhq;bN7ij{FmSR)XjR_lb5cQi!nHVvbT8<Rw{9rt}~CM$^nxJ1R?@c`GZLa`mY01cME!w`D`YhcmZOI6T6?66@i?w(ye5aZX~ zW(#H2sNcQ(e)7yb=0gW8pJ-@tL5|yOcl%K$nFSxkEqOshHz;g1uCxab!|KjRU;H^1 zQu;j8%9YUN@e9+tGyv)jtcu_Nn!~6N@6l8FO;FCwQH>Mk(YSVZ2od4!DhpzO$nuB2 zG{ERQQbWMC^T%dcibV~vVR~LogblMyj|a>3Z|~lOc7?ek%BQ`D%7eK$?@w+?NT9g| zqXy$@s%@kK__TdC%F5XY*<{{Q+xwjXqU015Ak_ecjVm2pjW8-P1oHzl6rOau0-g~r zo+Le<7h{y07P@)SGXo81*~L0+n95WU!@E`sZU~Uc!%VZg8LCK3izW5jKu3&A4`*P5ukl%aF@T((OSP(Tm@fPOrM8YBho@z*BLaW!@ zn^TZ52_(9TR(=Z+y)Yw9ks3VJF6-Rl-{s_VRt5gLB&q1 zGxb;J{C(`9hKr@@>-~s{>@y&=e_@wp2n#J0mEYWZOP+HEX=06eL}>hDbll| z`rO^TdiUc#|2zGrE7^NA{id6qkMfotXt@XK`vGBj@-0j&W@0;|r@pkHv&-0l)5Moc zU;9&XrFw>2+PXXD70DJV;h2a%a)pfaO_Xl+H4@~1mk;|gvK)kgzY-Blq24Us8QyB< z-$x;A;zu3*{kbWbNgM*uI%<6fOJd6oQQJc}^v8+d5#eugPbp4$6vdG z+86g>NKQG5Ga7j?2En)*b``PY$f5G3W21V@?1zU zOSLp<9_4SnI)moTc4SwH20g(xE8(l#DxZNJ4E<;qT^28DE#xT7(=d+W)K5wc_0w4C z=Q%W@;3CMP2~4{ZLXBU?5X2vJQ@YUz3QtX{z89KL4ae09Q#9fA;b3 zEVipA6>)~=>CTBr_9f-tI!PZf1-Dz1rMKE3kU_W4~a}+ z5}mFBQdU(&g|s+NM8(9~&H^=Ir2z2ay-|aicIV3JW9K=#2_M53w|hOTL_$Hk2^O}R zFb4_Yl%OC>LfHK-O4Vt-`TmboZp?%n8$9N8QH|H{$Lk@LXx_B(nRJl+S zf;(?&oe3AHKig!YRO9VLip4i01D&pNEd)m6cuP$}43!2Jtd34^(6?JqemV3clTq33*jGo$@VM@3JazY67s82zL|HDjE*&(200pHzoO2 z&Ml^GuPdT&jM-?FoMGL`%BtuhHYhQ?qDm}47N36g&N9JvQmxF4D#Ss#=}M7y#VX;H z0pJpH2V}{X3>Z^$lWeDI0qpMLqdSEk{PovcOG!~7l_Mod29CsuR{YH&NeQ?Z1R(AZ zko+2}2R==s>N8dK!M4u2N`iPetNg~XiWp)_6n_&2EpDbBtY8p=Jd~M5m_c3K=}=NM z!Bpko=nQM6#?^V)fzn0CPhVV`3|#o9(lJj9#sgr-{M#_M(YlTf>!o$kR(Wcif={^T z$t7Rxcj4(JkBz7-dnd?A`)+X7iLZp#Qzf}M!knsdF!Hu;CcpMR=w+dRc{>ns}B98U03POp5LgJ6_jNRFn$fir1?Y?Ea&Ov#FP4hvbW`(t-cg? z?leVwQ#|&8D80qU@r!R)etUCM!ouX9}n5F5mJ4Jj*N0gVOh&f?9?DZBScA z?nwI~?sRK;7Wu#oK0muPDUF4tG3OM_TLVEB<>lfLLWZNBMr+HRwAq7H~E+TLlYlsjh$Kn%@GVJmC_Sl$mTS z@9-~(<_d_#8&&N$EIr;dCza~ApShDufJ0KvQ0xrCxTscqWD!yN26p@?hF&_9+dIxu zaDoF~s>#XI_!`?eaD?^di^?Ku&QUst4bxZ`3g*-{@k1oCa>Y84ndaZ<6`sBB>1ZB{ zq$!F)SrQI}q9om%Gb@3V0}Jl98scovS9!TcsSw|zf0HFsp_Tw60GVgR{=yl_wZ!GH z;SS>Dj5iqI@3YdN`<^2oKS9)wdN|k_Yjf z`dPT(F1Fn;Et#pH4ipF7Tji~`4FsM_6wB*ClpU!Hy*MR1J6Wn$*d!02>@*hFo4-p= z*}1l-uk#(Te%JNB=k{o1^4=Wx7zO`9vN*pqr+`}B)HGx?g8+!xvuWlgT$Q#lSDrwO zPZs|-T;kn8Q4;T0MedUZ*?tKR^-r*LT-Cj8i!R?~c(VJh&HRBMj7oM)88*$kSkGn) z#A&PoaQD!)0?QHj<|O@Wg+;v7mxmOmlosvH1&_VThrQB*RtG)B2ZuYJzr7au`~1Cp z9AfVn#oUb$wAI5T!j5?lslCf|_hYmL@D$ z0tXn4r77n7L}a4^3RQ&zLNIA{iu5}}1&abo5A0;k==p zU*R#WymjK!0>^)dasf{ogn4YG4`i#>lI~LVuK8BZX>rTpyNoDSf7x_L|I#6Ez(BWg zF}>z)T0N4Hl#E-#9@KK3lf~foC~Bl1A-@#Ue#+lx$R^mZRub@P5xBpdSFgh!pqp!V zEQnLr>MuHhb6<=VXumNTzoOHfFOC0~K$Tzz?n61dFZQVHzI$Dnnr4#|TA=cqp4 z32BsJ@X6NWB%v)q@|d&y`tdt5_6Q6I3&rx>=zkm*9)q+9%%K!^rxFgVi+vkoV%=Fo zStvk&3pZITXkyNRLbhMg`uT<(p~>#-^Pcg4GncR_X(+Pa%HX6S9$O#4X7WLW`O%Au zAsszZXB~Off3*AR>XkUP`j$VL{bX=R`pvyFI-n&*EA$>?^rA>;eLEr!m!tVS!Gf)( z9=h6xs}3ssK6qb{$!czKR`1Nt_yq3OMTbTIPaPZo{P`xsI;vSI6G^#3V8?u-6^3c( zkv(m}A;_NnQ-lRN%hjPI+$u2bu53Z}h&$~1vdwT6<+;&uGhBeYxBT~$KJ+kzK;8l@ zIG0N#PCT-=OJ-a3TsNr+BpBZ+w_B3h_k~5|b(}5U`$Myc@i5oM-Z`U?%Wu9Cz4p^6 z_S;l%Ef{P$@UePzi@JniG;O?^wz3GxZmx{C`3{^{XyI{{5|a+$(>c%p({Y;jxbqQi z&Azxwtw3{V3|{FC^EWhjPQOEDOxdemjsT<~bEM>=_)%o<*zesK;(}vG8-j*}c=*n= z7~8i(XmvlVmF7EG-`?YuIShCLeP`!5DV3ncR@Y>Tv$guZPJL}*l_OX}eT@e{5c|mMh(V3c>0gLka&5*TvZk;y*>sVbGqKpCW;#M4Ys^un|w~ zN2GWf4Q@;vR=4!Al+Zl<1K#!`7jbwN=RXN`*Tg?zbW)fUKz z20LxJVYMmLAPe1c*%;m;j_VI#vQKgWFp4Ki8}4B(N{|ICvo=Qpvg{hvTnjR>z;5)| zV}t+R(C<%Xf$}iG15Z(PVBOvPLC5c!4UF6$`-}-4P9;#~#epOf7rpQZrcVhHK zO_xz~g6*Axl=WNI`cL5$2-wC}SL6wV?e zS`0&Bo@(l8hAY|m>`yCa?YpQkr8?9rjNpTm&jH@kuj#oTIk@&uMhEgor$@hH^mP>l z41K*DRCg<^7z=7cr((QN&M7XF5*;y7P#DEoRTm)M`8zB9V{K{=oYTLgz@1lkpsNz} z6a?~ld6w0)n-hswjbVe?&SR4i=CD=4y34u~`-9ib8NvJvXXWO(I_GCRPO#+>*p#cN7J7;NZ@bV2(V3f!t!p@_@vNma0!RLUh z{F(B}Rv6b@qBH|nsWL#e$U3hv74+F`f+E2|u1*Dt+?Of@bW1AFl>gRm^Pitb5J>bfz-(N1c zwpnHs>w?`~>@VgvT5EajU4&!;O=wxK5I^sqXVEPC4=IQ5?qayE>p0tgIAN_|F&rm{ zf#u}dUFt>Waj6_cibC9SP8xoZ^XDIb;{3483B-eXd@`AGILyab1n@CPBCF4kaEB!* zc(v8B^|GMhvB)Phz=z^xjd;Y>vQ@KV16B{B#B|alY~wVm+y( zsbCTIA7;Nj#2}dh+;3-pAWsHmu5|ycf0kg~(leJ4?{`2gzadZF4e9YdK8H!v#q`^b zy@VY__1e3~!xjSZ^;Rrws@qe@R166U0kPRfD#=KfH2$}q?3^Fndca>l1fCe@XlOP`{^us3S_Rj0tAd+`C% zT$BWb>sxgnw89TQ{i?|V8>!33+G!8Pfgw$nn}Z)7N7_!!CC(uyE;!-RIgk%_SJzxV zcR3ij&g*!p{pNC?=Gxe&?OZ$Xrp_>>nC~xSTP(NS6%A)~OEpWrTTyKd`KGq$VGY6S zUweaB^Yy4=i@Ge^CsK-PtDJC^#uh%-Grzo$>FY}&LX~zd4=9(#RR@Qp+huq5(a4c2 zM|y@TOToQ{qy2n=9RfLJ_N?kUQdb*L(*ZiknocVR*H^J?#5tl9@mMDvOUd*T^}`Nb zH(=FvZzI3f?9Q8w{YJq=PB?)Rk!mlFnY01RFjl^m#!Z$12bq^auTRx9Cc2u;JB-92 zF1iy(J);)HpmDEA=zTdQ!lgJr%m9SfJ zWrscC>Ikzpv8@2V9k-Fl?3M%8-?~Tt^q?T~Pak!$n%{p8mw3`PelTs5tP!+Ka-+Td z+SzhBvVS0DT?TV15|#Y`$?l{pu_0$oWx^E`n2%vR^&H!vq^_#WFo7{jHHX&h2kx{lCXW2OR&)Rn~aAI}i$xGj{Bnti%RfAmbW()yV~YJ<9tD9KvzE-GE8 zyPg@#O9smd^J-brQ1h;IWe?%5_`jhrHAm-6Uq61$Kl7>Y) z<%jSDM4=ie#)42pyx;sA{%E@OdED#wHi>_O zl+3dH-X`_a*EI`&w#imK=={I?fL}cgu6@?FXawGZ`4=1OuB4j?V1s*v%I(&^dsDb4%_D z7GxEfir!DY^YkRajlx;a%9;ebHMXZ*!Gy$_lNj6)rj5&GyB`9y)zB)-cEaKZAnK$m z2S$*$tRGf}K*sE(j(!U3eCNt43Z1TOLbNHO?Z_C~9bUeWWRypAq01fQ9;-Me*2k$) z+0YwLU^mzkLMGBqh{)c6p`f+l^}-3CqmE#myEl>=84lGg)w=G5h znlpBk6JDL%QOd{*1Wh4Ru60#0yydJ!52s=?G;l`#5Z6@Nr7gOSMWtd-wi-M7DO5fw zJqVGD@-weImWRS&b?eU2=SeuGSiaz4ElvNEShYgHcIPQRrh>}ga8(%l0IX$^;Hcwy zrsvB}J{t`ATD&6r&e6+1?b&;O+OspM|4-VpS>B2p#zhy5>FDVs=|rYTN_-kDZ)bz zzz?-xOhI8QDY|)Iq|CYNOb3HU)f$?zmaf4&5O!GuUuvZf4A?t+KeN$u=E=lJFcHxw zq7}W0wbH|g!U@J!Q|DdP3B@>2gEJ17)sUV9*wEdbV;_xAWakvWe3^qoKL_+<_t?iU zu45q9Q|ER2Jw68OnQk6ze=pqL{%NVtr}{r>srNTyb7N%1F`8J31$Dj6SQEedNJU_% z6M~;gSqv3h-PIxC!Vue5d9DrF2EuGh2d_=&kkWD!M(N85ZbvSAItkF%aY@@NNGoCtK2_qw^dv{=e+-mqmI?!sodCCkX9)f-;n1+6c_%6s4 zWOBalB)#MfhePt{M)5@M;QRjN35@HQ$p*jy?>NP59codhZ}JR@9BNF|(-gaC|wEV?5jvIQIM# zSJL_&LSi z<)@r;$ocgHWd}NGc`z=j(ToB-jcv2c>$?T+G@z}yi{%!cwTA26_6A;&4-z7`eC3Bm z0^c!;Xn1TmU`74S=E|J=fHM=3k#N`Xe0WyHc01<3Ss1<=!q^3@u>-QkirlZb(hB2B z^@_IJl}t1Bt#&R7DxJO5w|F3_Y97wcUqqH9h^wwaB@Z_mHo@?-3rUoTLliw`D|g5) zv-LUKo|D|>y4jlboR@TaDzYlK+$vtTDSrO@bw5c?p~6Gr$-7ci6SBy>OibNc1yo4> zDjs%OZBwawRx0eXh(BE!$5!Rh1efCx)`eaQZ53uUyIoZ;mRp5Oq$t?&UXpFo*B=G^ zVG{a7o3ISyl>lqMB;9s|5dHj{R>=2JlLVC(fyYGkY_Ox|JaJ!@w?80ktuCoVXp8Bu zzy5lBG+eTs`5!Zge=Q(->TG!}-kNZHVxE??eQ^oI;#9mfU`VvoJSmt}!lH8Cpf-!E z?c0~F|IxHBJ673bH7lQ%Hpk(#3+tutQEMCs|I#<>5{@Nlr{6|ME@S|2{B`Ewk+1dZ zGoz6!|_g8ue1*SUc?2D{%77@&nm> zut8*K?ea}@NA7br70u^7>VSVm4IqB=-s& zhw%>R2?sU&o6Rv3#x8LK5wU*+$q(<8c!SvgUUaN%K@u!Q613_FR->dZEY^O{h30~? ztVAZONxiJ*6wHZos+*GL+Ky|}hkJVvdGfaj>LhHD|3$5Eln>js7M`H2G5vcXi@zB+ zsLg#r<{z<5R85-aG7ryXFQ9f+`z^Cu@)s962lpon51u85_WMJZYjN}5esX?L&%^dY z)PFsdIs`@=BBVjpsN@Gl96J{N!bYL zGg!aXzU>L}b8>JtZo0iYm2VB2t#Y32dZWI_FezsfIl{|PKF%v;<-t?~S+?T_`NEb2 zk*CB`ensB>-Q68|J<41+apK=JJA@9iL2g29RFn45JZPv zzk!TB-9=paKY7Uh@>PP75Rq@wcim@L{gZ>qmkf6OOdX64yGy|I%|E0z2S!gMIjk9W z%QyEgzHl+v^_>#A_prNshTr{TJ)~f)EOA*CSeG8vc>g@NVG3ViO9~W+-Sv?5N5+0H zR{ZzBgs6l}XbvtdS^x231T4^R>G}5mZ^ZAz^Z#$eKji=at3>#&qW5mr<@@rML{0qh zcLZ5rb^yZ>XY4^r`(MHr@LTw<{|Mh#ftRmDWN+*|GSQ99Kh2^U2F`$I<#q?G^lq4B>z^!ES$P`IF% z>4}c@j~mYi3zIxI{RZbxbs!Fxx;r?p15)1m%ivnp-|ny8FWs}+daR!opYgd8{gFQ` zm@$BfWZ5rB<-Zu3q+ldjWBPz6xqMP}%p1=|+Kd^O9X}h3w|x>s-Wr-Lr}(B-?bv*u zUb1mfQCzIGV*3%jA)w>)Vf`()EnwYBjy6GUlrdkWpYeqNyft`YaWUt;EZFgCo91vU z#t`hZ`X&5BN`z6m5Ysk6-kIa$rr!{a`uAsl)MvEGZxzgYs8slG&Nb=?m`(hwLshTl z2Mz5%=7Gyi6D;N#yLZG+$75P9EP;$JJ^m88$G@O64;e(WToto*I z?!SA@>n}2qq2eMZ#d$>e_uFI&o)%&2$AN7l-aqvc39}-MF)6ekd(#OH7-(lygn*UQ zdKB$IvP@rrG|1$6kbU!wioZyMo`)h0GwO0@sO9FxeV6{@$I#{<&xLTEwGzOPeaH8+ z^+@tKfAr>&w?Lvqf5LVYZqci!g&#R+WFz>e@|2Q(TKId}Kgv@kP|$i&mQ&PfGAKf~ z{!8)0dX%>WM2$W*Y%{`bD4QdFU*MrhVDiDAivHK@H^=})o}N#3@K1k2un%!u4LWRi z`B1%E@a}9~`cbzBN<=O7;>omqpSLq(`{!Sc&-lI7>3>vkvZHSsH#fX6v~sdoudw7{ z<`9xwZ$FxL;%zfMmNtypa(!57IJE*QjpGI^$w&13KKoKaS(F?iEsl?m`Sty;Y#e+} zPFqGiBo?XrWvQM_Q9ogl_`ht|&ToHg2=Q;*<=cn-HaTic)zO&MY|th>pQ`2LaDutQ z+CI%L@NjZ*B&VnOsKn{lRUPQF<%`9))hf<!J7gDabjX3zp(JyvisY#suJ*+yd*YZAV%6h}s^K^hp ztEm{z!bB$$TTNdD>O2X4rxO0_VZwUvHL1gEy_aBByWBA|ruB%PHCiSnbtk8Dqp7W6 zDn}=${E`xRY;0`3=@euh_yWNFu<+~?ZJJC`>%}F?Za#QvxW?xw)@#Znx0;3D=Q0S7 zU5l+n$iaBV^p)n$&ueFPLIKD{B+*iJBfU;Bljpj=x%l}nbSuY%bOu7OQ|@_fs&eZiRJqzY{Nzu0^4zogs#ef-KYE3>U;re<9>%u$(|TeGq>H3x3A zGQ~Xt!L3=^uxz@w<^pjc;+~l!5hn_WGbaL;iUZN_tFG(*+?>z#B6^;q+7Tm>jPaPlO}gBAuf|qwWx%+ED>RQ!_98E> z+i(bY!OHQqpKiOsF8?3P$?%6(y>TrYUM)R-1GB{e!L$;6XQonNYBdK~1jIrKVY%t( zFJQ+h66@Lh2UG%zz!D%K#7ZReodf1~Kv8S@`?WOZ7WUrgRpV`Naoj zrx_2ck1*&wZx4N(-E&8{QlTI~-3&!j7_bfWK5U~BvRU1kqDJF;ApG)1L_}d060=A7 z?b*|znp)gLEBB=YOdK4tR;V+Lom=Y~DW6NAasGamUwD;-r~3j{&YE0EcJaW5UdyO3 zBgM19Ki5^*OY15D&ueLsfu|7OB}Hq+)-Xxicx&5s+GfEk7!g&9Q2F&`U^78{P_ zjBM4kOkVFq*uFxoIduhei7a$DmI%NOm_jAvfQV9cd#ts7LU3S|=^B6cR=^5l85wKC z{Sh?>OT`Q|IEUa;h`;i8xS$tQXrQmp_rbK-X1DqBcZA*fjYNSql_A9RZfdD>_y9Tk zC}g=NXT+?1>K@|T>q^NW)>xIPP^AANGGvWLSSvXVUjoiw8!-D;Y}qA43)qJHw-E&a zw{dnWhq-r(dsf*F{ZOl^Sy5tE+HHyd%I>t8J^L}Qk;(8fscW$A`wa8(2>yRsx;j;U|Dps#3;YWT2 zrmdgP>&EbHYwH-WatZt43#CgMkgt*f`3Z8-UE?5ewbj<4>+)G?G# zM$;+@L0G;fVQrwAPznqgRsJ*2oEo+MT|?m?@g&Qr!XVv+;0n#|pC#h287a?fIcuU7 zPwzCv5;PtcPT>oFU3yd+u;m>z!_arhEfn(CeH)%!SW}~;!a6BZ>AA|UxG@+cHkix3 z=y-riC5a3aADv$MN(`DSN`ozpOE#)|eY2t#J%}Iba`f=lqUFh<$%uu|WlYhK+U%0s z76*p{YKR3EmrOx1*a3!;*LB&t3O&2P4RKF!NB8XI1;ZWOqCu;+oQAp${t6`}y8z`$ zKJ&x?6+xI|iF2089p15tN?L;px-L&<#mk7}=Is2wsyq$4x`4fjJ$zLF2-@efxc5U8v4ZrB||f`$KpEERnOt z(zV)7C%rzS*`;)#{n)U4ycXor@xEzwC=MTV^-}6PUK``t*Qdvxh+|JSSu;huE_%{M zkN9nLA9RTdk1p8P3-Ye~wT1`!H%8-eKBKL(hY$8!%1=#;R_GKvt-WAF6=f{2lOusE z4yZkPQ;eU%!3$B#m22zKXBfi46Qo$&TVZ(cdM3`f`Ga3msxpi-w059k?k^nh9AvRq zmL}KM?8s)N`j1hO6JY%8a3`-a8hIv~VIC4{YO3R{K(0hM*xk_ZE%1Q!&6~~l zx@K!37QdZPX5V+Da>#0j@VemE6hTJ)UdF)G)xOyucB^T)WsLxz=fhOLM>a1*Hk<3F zsm#sJ4bKqPPCJ74Tw|vWV@)5QpOWcWyENicGP&@=eSHR!wQwiR>6@$XYFu@>hvb{ z&3gR=OLKQ^=j^2%JHJ~&oSkF#GBX_w)fGNer9s0W8VmkV3aD^*j#)_)*1GS4E zWJ=+FhCb18GT&je4vVz)4>bb~*^a`)S3WPJ1ZRnORQ0ro3Mu1Us=qYO-`xs#L#zUV zL9oBfF8bSl3&z^abX6-Y+e#pXKM>JOW{N+!#SpA|8#ax1^#T4=4#Y(__Uc?T}n3^qPg~NtXhYBmWZ61W82Ldn^RgxWfSp(UIb@$enlF_+;F2e z9QgvQN=nnzmuz)0VFis%&BC;D5_9B^?YnFU(fVw8fosn(Oeo6N)5)o;djhgltP@fg zrzj!oevq{H^46+Ypv?nz^4KljwI7StEnrWX8Q8(iHO1g5ee5O1(I8k(B17E1Zdykc zLlc;J$+IQPWH9S~2$B(j8}6c<%C=hlUy+2wKFQqvXzktG035pR#vRc8Xm@hcMTxBu z*{!a`sw=n$9!^CxGwDx>9~YD9&#TuIsrF4zJAXt7T0;ug2A_NUG?S}70bAt|s!R2m zZ%&X|n^g*PU-`b(3~)#z8!)Fml#ta5p6`-c1f0(tZN$&vyqAw*ej&PVT5K(iuR^$6 zM&%Og;{%?ro85w<#tu@Fio2NRb<1J?{_JX>s*oYzHm#9}Q9Pak4EshCu)@`xjaX9$ zC@FZ+uqt{U`g9R&W78F1mL?ZHhv8J2+ieW!RTHSqkYfaS^W;kCv_bR3%VC}4vkF$P z{^I&5H7ZG+?ugIy5U$)JvP0}Yj8IcOR|a#`)0!6{e&+_&)}9Xdth>=(L=3x}%cDXm zmFetS&V(ZD`yeTu@-fH(&f$_y#o1OR3>%wQbC4s$+-Y^}8L^8eU(cXx2y3_o#_EFmSDtnXOId8Z<9_Yo&7WLYhe6ypb!|9eGOW{7 zSz0j4@rwQQvGqpTp=mx|3T!;TcDYHhx_`)X@$qoEcg4`jl&!_W;46;(G99q=Z0q2K z-c;AEF%#R+wUCXumKwH>GV%0@lvd8s2NymAn6cFh_l}q^40!4S@XYe`peVV>u~@W{xtqB|@zo1<;?kEq z-r+W9RIH-Q;=02b+a->7_U+?8o^g$=Zam-0nTttTSn!2CqbY7Zw;d8D}92IB4o$+5=G|5Zp+)6@uzd zT|G#y@nEcgzMZIPsatz$PG?pv#s+$%i}@}wWL^9w{IRg49y?Wz*x4m`9cLlL*rD{6 zO5$+e+mTK3GosOq;Nf2siocjWXB&#wv<063UTloRMc;MonmwWB>WEexn9ShDTvdKm z-Zh*hw&jNE+|PR)s+FTM_`Ne*%yX??+SR8;f9In8RAbAC|9IxBo8MXj*5lZ$lh@M4 zIBt;$*5-5O@YSgwdek42g&L@`C{g#}qPt?XuA@F%Y|j)>0E7@1d&AA6Yh>+t>JsDJ z%*m!E5kG-d!!6dp@=G3O7mWa)ZDn*rVUFl4%2}ple7Dd5Bqc6WX))8!qv3mgK~9d2 zzP|qO$z+CREueS;$rS(QD{YSD=I5L0>%R&9Z?>tIcdzt#NzAuMTU&JWg~BVnwaN3$ z?%0tb_d4tL<oaXGh5c}o zc5~}`C9!BKus7gf#aPqkxG;fY6YI@{%gm@!dOVr9$XW109 zQOP_xQfW`#XZ%Ou0q{XHSB}0Dctlz?)j|Vd-8^jUShpjMUm{ zeHFNv2gLvF&sGU6z{-Hv@or$cI%%TEK1@1hswPmv5+HnTxFtAkU*pN7zB@ zADNs*RKcE_48``QkH50VVv%t1zHN1H+5%82g)7!3AmTdGdht(9K|;&Ob0fhk^)DPN z#ofX8XJZ6yLkNwHO~cDJU9%o;R6h$so$}B9tT(QLw1$JjqiQQ?#0o7M$MPK*D75_i zb{LU~;6Mr)T~#V?eFvah<*#}U4p$6URoD}ZMAW=Ht2Sw=TQ7jRi}+P0h*MQ~K4peb z^M&oVxO}l%*T~#&y(5wmA<7;HQa4Cy4u5n#x-P&w_jJFSxC_s>+JzY&kUh z+c;pwK)=xxnh&S)$%A^ z8r#Te!cS3Qb;9IATCdt_C+jIWVCK_@wofsndl&>2o~)Q-Tu0rcdDeXrTr~%x3?^q^8D)g??=8#b3G|Ok0U0D&g`BPY*uVFgA6x$m(4xCKhp2(g6_Qbgq3q_rTMXv;G|N{kI6N2_l>y`^~_(C z$x_69=>q8sHm=X#mU?Gr>1zZzSDBM$k*d^@Fpo{d^vtG#k5+Etz6Z$I`7*{_E2r6CmHHfij_f%yKbBbYLTX=M#D{hQ0hoa7!Zq$)*jY{w~!tR_9ZVKy&n@XHNme*??I)zTfh&w3zqSg0L*bCMgr82ZdhY3mIOZ(G@~^M}nFChe3&q zABI8S1<tzbDdK*wDINc}P6SiAL$#as*LO|nJs#9*{ zY_3;qo}0h;7Te3h+|Bir_K%M^~O2tVGD<2aYoIt-1!&N^TFj zKIN4La^Er(MI5SFi9^^iQf;~_*!6o8P6e?aY$uY-Yh zvUzxgQ-hS}ZSv3rgn*;HL9k{=bG`c17@eaC?Y_!aM&>W$c^`hv`!q~}-Yq!M&*!7y z?+yBEWdv(PGm|}`d~d3Zu13i=m%7K%QFsgKB68-xQLxmqaPB8#Q+!_?oThs&0UB<`|#^Apfnk&-+=4` zQ2hK$-5!ZfiX9XmV(vGunBANb4mwS3o8t8!!vbfcZp|)Gj73nr+PFZ2Z&S92oB9;Q zIG6+brpV8v)n-f^PW}$-Ighs{YX0m%{q^MHucF`~@{Zp)z~nS3BFoNBafc;Sy|avG z#}4v=#YAD7s}SpIHnpe}tME6PSGZ~(D^pbQp&9>8=m1a6m@CzC-MplHr(HoZV~tT$ z@W}f~4lhhj;ow6ELYC)v;jTB+$86HPZJ#o#eQG?0s;z_zth3{n<&nAPF$CLoUcRF* zpUu%|{4Z_t%Vm5s&o1niiF5b#T#3l{iPkHqDfsa69h57sde@F!*>5y)oHviRGx2US zoW)*8_Pz>n2BK9eu@Gve{bqgrL*@N*Ba_+J&wppz(kct>Hg`~~r-CcQUFfE%hf&`K z4=oES6K38}4PBW(&}T#!7k?848qCyEzHLMS@PO>h$&7{O=)C>Pg}d%or!DH*wm<2MT|O#T`7f;&Zl$vr8VbiBTk+?h z?msBEvRgj-<{#O@{R|+F?@B&OMfi$rtAZ}&0e|taJ&2@uW~N%|u%YICGVlKVTY;D7 zZE7B;|L#}m2`H{Vq#P7gE(qBO2+2RAllc6)f!;Nt0-|7z_L+a6SnJ#0jmTiu-~X?- z`p;C3S%jux>g&xb{Ofp<<>rv4wxULchN+4plOPXKLmj{pk9dja1U!_P?>O(0T4l#! ziwzX2ZC*(HhS_*U{J=c7%sRW2RkvDD`*S%pcVy}Z->xB>B&`5p!N-*d`&M#bB1Zim z#FDN1OV0pBvebqJw{2&+Bv9y~#wAxjaztSQCqos1_Kwz*u?IO>DIVvot2&a5(1Z|{ zco6G7kEyks5)=W4!D*gbjGT3vrz*OP#dzY?%c}$~y3^Vw6ZtzV)x&W>)#U!A)}`y6HoWIf zcud)9tWRskDP0-(d-Npwi~GL@f%=_IU{oAQ=1))?=Lnem=G?u1Wj$%WyY?N02@qJl z#{XHwoZpM6zH*MZJ zU6$77`{}B1?*!APT|ncr{Y z>zH7CL2j>u8i9taKqvgP>)Dy47bgn;5G?)mB=ENYX$l(h5WGFcGyq%1drKvqAL#bH zcq91dFf>Jf%bXU=Rf;A5TtLk?IM8%nhh{BwOy z-Ma+1VOY0;Q!@~U9!}i+a~SV*0GJ!rsmd_O-?z0guiKX3X+)cF5TZz{--hsg4t|EN1in7?7xuq`P4^~Ckip7Y0}$TZB{ ztXplwvdv~z#ZfhaBC~emW8s((-y+ek&_iwgD?eJI>vosl&3meQx5c427a(}$F`m3< z+8L43?&sbm!Rks#ORYQ=|C1psP955F;r^EXhvKcXFISReXQ~dv1U|(^|EZk$i>ue} zS27E-F|$R#0GE(Hg(u$$k&pUQlNwrID!Av_>3zEzby+@nBQoJOK$y<^R{3YT{p-n* zL%-CZ=Xk=zn~_t#Z`wb*uac#j2G&u}w`oIrEl%BUB1Q}qVU0akEFI*+MI0j1peLAm zZYQ>d=u1Msz+ify57WrjD97vXDLybQqR8RTM6zSoS?&5?R7iooL_oiwr|haV00ffa z08sVkf@R|XLDJT`;-Njr43{#I`+LYjeRrxpZw%bt-s9}mJ#}dR#Y3+L_r?k}R}uU) zcx#>jsYSqXJ1<>-RS=jcgy(sq(M@}~>aU04>zKDr{C^C-_vR@85z_B0l}RR-IA1;c zKzt@?*P~&sKL>RvuJc#sr&DkHMYp%RR_}JiI2Tp|8Ym9Mu5|x@|K*d6qeV(eVE!E8 z0-`i0C>huRL$V_v{5T=+xh)g#xoh}~o>_6dW-P7<$vL)gVvfsDcD{7%^UynEc+-fm zChgA*U9ZC>;6^?s6yrf|28->vMh!79S5h)*Tm4)Xodz|o@RQq?W$&;55?Iw4?reAm zf}34D`EsqUxOAHs{FUyh=y|Mer;M=HR|90y_wY36hXy~D?Z2h+7b-A(TPaugH2q5W z^}~R^uflgX{D&Kl^uJo{-!p%bci8L9mq$H!m>*cdtb?Q7C<0UQyDta6h2V^j8=8r1+6Xlr?|^ma_7s|5h5WB&2(+Z9s#0Ijm6 zrj6N~ZP4|U*B!w5^m-Pye;QgJy$3iZ@bU;@yL}#N1#Ayed(%>E+eq#`1ja2v9CMS| z_VMUZV1TKxUHI+x`w9dM&>|oTzTIz|rGWtsadc?g-S7fnok>4s(*7fV{6`X{c?ZB; zF^_PV?mwYUsOILcst(eY@TX}2&QkzrHW%B`zGt_MFSPy|Fz$&oukBzeRI>rVX1oR+ z!hh)4fv@eg2AZn=E3($xd#$U$bb1TbwEss3a~crQOMQsSh~GBA`m4XdXX63B{jN~> zpijZNUTE-7^N`ohZ+yBI)E~bMNIj=+YM+}uAJuT6eYy8VfsnU-yH%_3v@%3>@4Ay} zbY2D1m~%r+Uq9saN`ZFJRakS1{GirSukS;XK)Zs}nWQlhpm}Zcl(y|_fmW#m&?vF& z@$*j&y(!1&0z$*_{SGC=geM`3OK0<^61c;jx_Z@oKk&o>J#g(99G~w8eiHO-9{Na4 z&Nu&xtH>w3l}5LbpHIp{yUo^MB$V^rzRnmgId#9}Wc%)iHoO zzXoTC%3e+mr|y0`p9xdQ49+@+3kjh2WIjWvxW7FdVQZ;j!>|FjPGGnaaTE6{=CHc7+WG$sBTMdm4KA)^*F~45ChV zKH_DJWnFmIJ*T3Oc_nS}gc=8#8;emKYq2ajV>@HrCGNiDqFUWu{LF*rqch(A?9$$u z%1_I@U9oHeGV6}3y6rGY)FB!+G#u>F6eFpe2#^_Fx^jXh#@-`Il3hOc+1FF^hYZ`s z(k?51Gks; zOY~BMvd4F11#q>)C@bkfG2ho)Q<^^TJSpM?9g;S=Wahy!Ex7+{-k#5k*o~MvAsZfU zo)9v{p=P0DQ_{=Mmr)ip=J4Ty!;w3*%x72Bg4&m?a+a;9{S1$F^8!K-QKwDafj!>-HK00mIQG7> z+JgUP&8;0PxCBmgEVgd08VVJujt#j6`eWZMBb$TE^w#o2v3Fqe)*A6Kh zpn^sw!|)Mqy1ZO>r1{QaPkk_Z$}QIqPr5Q6B|$j>ZMh1)xDs`N!iRWq@j*+2GWuet z#7^ay{WJ^Z{0RXkghd+N|3#5pjzU8!<67|rBFLfC32qfR?TCfh-dl8x0NL>y->gW! zdY@;5zBM5uL`y9d*^!L9nLm74|d#`K>RNUKXG z{Cx6~7&drNXrXpNh84Y%%~JXqtVoKrl^iatWr;2)Ih#XzEq%n)a#p(q9Ol(4WSi3u z+Sw*p`(O0d!i2{I4>aGLk}<9TOHRp{`f=RCFS;Ik4DtQWx@ZaQu2pUpk^koifTS3xe`lBKwOWEmoel)Yq_SHGW@ znp=~ZJT@j>;aSy?IDBxxPQcOeC_MOfRq|g5;&}JbSGy99?JL{AD}{wyh1u;<&Ive( z3ECDuf%6W)$3=EF%Z^{>{sNa zJ?=M9JO{!pyPSC%$Ax&6KMKHDmR%%>7G%US`3@rYqOiG6nYsI1*}g_~*(I2Kid3xN zi#U_4@K%t37t!LF(wTR}`FmE2P0rFdm(n$OV2SvVllzsyll0ZdUU=-YaHnK}o+Lfs z*^bZl94!&Uh`tYeC>3GTSadq|x*>|Y2yv2mpS((wB?Y``y>Ro}729%4lXy^cxEyA# z#Oms~v}S0d04&C`%QAa?u82EXE4+GV`$VLJ%?rnt<$xp3;F;UNa0}1muzlv;$YGuN zorqn4h(5QM%MdXOjdqrb<=?YQ`V!_Smt=m3i{m3xcaDjrNLNRN7O)h3)4CEH`N&KG7};s358TB-X67VB zo*}am6kD8z8R1oC_xlY69~7aRv^)^@9(~Q}oGYp`w&=I3oDWG+YJ^Ud6BYnBO8{lId#YeDkU&E6l@nl2hRXuFKuMMoI-a3_nX&3Sm3 z==3W2Sar?Hyo8GABF=r9n+H|mCHEXPyH3x_v>#|zYuYvBF~8|}5tl}4#HWSFH@wol zId|e1_MM!9?@J=#gb>Vj91*PG%8xTcrtm6H2zaq9y5g@PblX@0v{VIDBi)o3*5%gN zIQxC+U|)o@T@y%Uta0-QqCYYIZt|Nc8`ls7$g)*Q=ViUI#8Y1SJl2mG%er~oD{G#m z*I_O5L(Sn_1If;hrAG9KmD>j~kW6qdsT&~-+QF0IVW8(=GW}uDqjTR#p4kn{`l(_7 z)Xb439oY^wcYZbT1i0uKK?VJ zl+SiNG(@HV#v@ge?n>8;M9t3^7jp&l1PLH5>*MEsTqmGko>5M4HiFdixzP@^7TFl2 zb*jehUdKxI75W(QUUT1t*{2e0=^TC6%-3;Xrz9>CHMJDwUQ5_lvvZ5(+jBt5`f|du zky#Bq2{jOGTg15LkWSjHeOH!svCqw3yHfl9vt;H@mxC2=!xLSh!yTmxg|}VtLAZ;bId>udMj~Xq#FLweO zTf_%;)hZ2&t6o$d&dD5lm&o`qk83yJ&6;3oy+UM34VLP~hWF?kC09ulOz=F?%H=yu zl|Pr8*RlK_JQO?3 zmWm-*Xxj5XWs&Y!ib(|Y%;EGhr1Q!_er1-|f*8|8gnq-5qK`*;hIJOlwHqQ_KkzIr*zZ<9@EwI5w5{uXV$?gihe%JM6*EibU%XU>g&9WIko3B#NKRm}N= zWNgy+RoR-UXo~~?-%W5u?pU#SM3b3>6G7~FfdVeuqW%j%f>Jt-$S zm{n0cAxrjSX^~t(_KnCgm>98P(-HO44JYni)#rinC5z(&Yr)-xuJ+y9I<(+&%-;hq8NTQzH=;Bb&~%MQMvS zYy$GHxSN|;=@541x63{1Pd1BpY&x8icU!o@*0CQ8B5L^XS)ztN2^2;-QPCi)@*dikdgrN3IyEk5t?qkoO%@KZM!W zxjPX$sICLj3rnadvw?ad&9ER+<%4HW8F!;pW$vi>oeFLU>(o|r39izi^BC(U6@S!} z*%e)u{v5MkP1Tsf=_wX>0`o&i`BosA_$+_kYv5MW{n&OTnI!K9XfV4CL> zDS>oz>K!Ey3(5@?XjFl2Hc-4%04{2_Rq?SMmb5bU<5OZ?Z;B}~zT-c40kk|es&{-= z7K$Mn94M{(2_$xS_;@;Az(BT)U=$5@%Z&<@v1F@IZh?%Zp0)Q<+&xyF!XMjUIMSpm zbS^{SNIK(M{`Q0JKnoK<35BMTZwaoYaf@ZGx~Ky-x#5#?^0>USheZo z)Q!Y<@P22r=ozF6<%60sbtJp#C5HU*nsfA1eTB$Fkj;ZQK5MS=sWBUm!wcZaz3Acx zCn1)OW}ZCjuJcEHKzEz$-sR8~63~2VZrUDJqa+W-sKJ+;G7CeAlD*!%Eh;rGVX8Hx zs}}lLZn=V2iLO$k%3Zcfm+%hn1Idy5t_+jBx3QGsfxtcp{}%gM zeua^CLg5BTO#?ZYbmbUm%G^7cqAJgPW<$ZN-Rb@MA}TlXE)XPZyNTFAqa8~H&* z9e#xz_h7?%Z-`qtv*d0as-9j-FiFIZ`87;6Qgc`$g%|ziUbxMB2n!?}R+V9WxTu?A zpXp*#SWe89E$^${Nta5}Oa|NV=OjLt8>wpnXXWrF(H9>sA|#;(hk4cPNj0w`$_7uS zz|VGGwFJ`b9i0-PZFp1jJ-{m&Tz_71uLD11;jH}#Z-yp5o2GTP_gh&j*+JV~+~cei zrHJ39MHD{Ke|+(y&#Gl1{147*R$3~=q4CuC^RuUO-nrNCJ0IF35^iE=0xYt~E} zd`FxM@5!D#Osy?2=5_PXL8R3k5?}KD%R`3nDO_G(LE}4$>Ep^yFO3>Jln0@NDfGGD zYdey9v;;7SVEC;_vpWOSll`ywqTw~V@(Sj2k7R;sE?_CDDE)xSWriMDx%3+dvAfS6 z^we38)7uuk`=3&Ctok<= zpDN>O?$FI9XB#{3RwY(pzUV|0Rb1PtAP9NX$%QHdXC_S2OmUAtX2?z5ons{4$@w0E zrI&>+ZmNiVPuq)kRaut-sGT58#v8-nvNmMkUL?h+gnn^iES zKa%k{PwBAa?&UH4=tqetQM>f4?T4^Kp3qPbJVv508+O{8}lUi!!|S~0aay?SMLKctB-$E|$qgUxA6ZnR|O<2T{m2XDy-m_#F|Vo*a< zWqhQ-GA;ISVuyq|l>{h<>H6NnXR+pZS*vDdL8I^uUx_T^m>JKDUUjLjr=fu=`wim!ISB-vsr{stky$2gkx38{4q%B z(fl%(&cXRLq7Ig2nJ{#e^jMpeJx(j9&kfShoY-sCw*C`YWaR zzh^p_!B-1wjf7*}PGEYb%6k2oGf|gU2ENY0D07sSp^@(1blidJ%Tt@T&u6d|f}J`z zZKlSu^Bbf%HdSQBef1sQPlF}5*chOJ>F#JrS$a%Cs?6`YDQp|m_mjA(*x#+fLOiF~ z;;5N|xEhZt9odUh=)Rv77jKQAwedVYs~zc=R}?$r3i%=xqbjywv5+iWTHMe|bL%9l zACY@jfw+X{cn;>uiJVDw!zoBt*g|R3Zz@7sy6MWjMAfOy=tVPU($J(mLt`*dQ>XK! zD0FK>h_^JjIH)kn$^d*V3*6F@Ks4{C#YE%Y_?PKl?xtp^iUqoMaEgD%71;SdRU1ae zbP6Qnc>h##W&&wfC-VDR8A=vqbXVbHj6$qz|8rMGCy-kTzDX#4DHOVty$ms)GdNdT zxKf%z^EFiYpwmB(Cp+`l={k8wCpp05U7_dEe9O+zt9dHOoeKF2-*;b$JW6$Kl2O`L{>eRPrnAu}6L7gw+cfnxNn&Uy zd9U!}atCu<)Mnq*`?8604n(i0q!;wqY;gMP^-iJ07z+()px{BdS&YTocVv%8m4^cd ze+a(O$@oG#Xyr+7`(Rg@1fb%SR6@}}wN6=cio*qD2b$a9boeV%gU8{c67Vov)RgMh zaN?Y55!hQ0UY3Gw@7(-=n(ugoaw{iSDA>?<`$RA>k_N&q^}^Zk$2!N4Q}hMyKSFC5 zKR1mI*6OYg5P&C@UXW6z=P_W&ach9CBSK`ppOEc3JySh%r^~N9qc5y8zF*F#_m#D3 z=-soKM+KuOArKKz^+<#x_En}hdc14 zx}9;r9X`(`oLegW(UpsjQp1zgcDNfpTlUDl4mn%J_2AWI$AO&E2hLUlh5KixJ4DJM#GNxw)DyPjVh39g(i~ ze0rk5+NmkcjFOaRBGR${R1Vu@j%kp)IH;5ywDJNpDry9r_Qt#S<_gNxU3e1V_X=I1 zg}tcg-_-xr5pRBeZfbm~W$(2M!e7hkCc>1X=DXLVWhJ{yb%d(WH=IRI!lRSGq=Oek zhup-cud_2ym`Juk{9K)wO$YT))9;QN`+2|{U#8o+3>d6_cQDoRXxHgf)5lR?8Kv!=M+M*>xT3{o---hk4v@EW zLyvcu+3Fioae3zn0NtUxVi7&chmtIHNe_`!(xFUCs^I3Cm~^+DEV1zi67GK&mV)>U zrn813w9v`#yXWvbsEc`4=pob0c5+dBhKY5X($^vG6a{W_F^B3una4|BE(5_u_aeVd znMsFBIB9FN#8^s91N6eym;LxsKNHR&uc$IZOa6dVzP&*nI?#`?7{ZFW5Ew$zsCUe53y|;fkbRwaPW6C-6JgH zZzX#;@n~g+v4g_iAFqX(%V9viyLI#7X72Zs?jumvGd{VEN@Z3J>REV7d>K?ApCp*B z!nQvlOL7bEA;r(>c^d1?h+lNDbG3GD+8ZFAld3SZ91cQcub`BdU+cRTQ>W%t?YC;~ zL;VCu*Sq|dMamo-taz1UXKY$5-95=u`jKACu4DXrK1GBIpYWw-@XZyaKYg2|W^+Oq zZ}#6SsBGQ?H97xf{rNk3^44OnJo@mUZ`kUGQJ}qM7w?PbjEo;JCjoZ$6~hrB_d>5* z`$x@SH-nU&y{BQekF|*f7{3qdAfbUN>@Yw|1^=9o^L~__=qE$+s%6HjM(z|Glw*NoXK}$L6`lk)I$((9GJ~c1 zZ6>|dsqIbs%s{zcBT(SY1#|+m>B>#Wdd>&v(lju#v(kfZ*wDo|?qor!h1b>#@y;|M zPM@=n$~}|9R^WL!+lo7Kiqv%EnjXL8ilM}`)BGnqo;2WXOK0O~Ll-qlD?C@o@jH7% z_E1b6pN!9{^i6^u7ZiU~cC>DtHHcZD>^;g5{0P2+{#8ax)#!s71c4QtnJHM}xC4Su zT1G^ICD{#nuyRX1(0PE@GzTmqMvyUjk{0w9qU+fC@(BHr!mo3OzdOHip}>aj>XKRc za3vgs-siqghS=nTbF%M04GPatkj<$(*u}B}O@}{L(uw-Wc&q-G2BkOiNqAl7pS@6Eo*;me>KbWi6>Vg^Qht_&H|rF zQ@gk~w{2n-wjgeKytLr@d z>&dIv*O!Ix)s|MA$mN8ZJgf98V!OLDmGcYbCc~5Q3VjR3ViJ8d0|rLL=@Ih!&rck% z%C)RO8bLj*v$Di$jO5HZg(b!biByG0Xw;lrFgwl4t+R8}UivBj(@i(#GwaD)-}i(c zOQ^anFU&Me=CiiOxS=zAFlVdV+x*k}OHi~`E&00jGd@fT61eQc_$^<&GGA=|X)}I7 zOyf8feq~U*{h5MQnWbllsp)EfD>X3L5;cC8ZXCqYkvvE*se4*EUsyFR^dLNKaSmRL z1t(RYWC|i6fuwNdi7rLrNmCStRwK+-h@0>*i5iUL{CGtIp8Q1yReF^K-#pgzypXyBy*9p0$9MG#A zls*zsNbknkbvhA@LOMtamB|DCDrWA`p-#LLUSEs4*yb-yxrffhC!hG)Hk21juFVJS zul(3RILYh}@GNy*p?J&AyD6!u?VRQwtgu0>pbbt2`w{1lK{bztr?ul}( z8{3`jqfHzZ1T*<8t0WZ&!X+&7fU2LX6T@`{sXQ{Pl&|=a2j-Fh+^SNBjL7ZR^e7T{ z6+_=~f;!ym7kC`Awh_8DqjtZJ?*aQ0D9!y&4CPXj!(7Rla!#+Y5Z);Uf6kXi&Q}iz zi6+X5TpP8MqJAn9Pd5>`?Wr-CS?5=v!yN3&O;$6z948ecU0za?mwp+IRdmFTmBkg* zRoOxXTMFjG)&0y6iNI9z2d3uc`%s1weWkLW?~)xCl4aIjf7_{T*-ZRg`u*c%0z&T% zw-f&>@|03o;f|>v9QPtRW0~OOez9-G=Zq($; zJpXt;OIK*xT3{==+gb!C?nW^d=zxh36_srVM3awmK4sK`9k6eqm^;+t1~U^r0zF@@ zn|agfgc4<*4?T=F2=JHl&pG!w_QPe*J(O=X*>R!>;2e5wCwH=gtvqC6^c}YO$k9se z4<4J8Gda{lWz^wA!1M3=b>eQZg@&_F2wzJ#%dAlIuaOy*y+&KT7s+*N6V+8`fU<5yyLQ1-CEal}QNs1AGT2>hBS_qq~s=(t*36`^!?sO+qK9o7zFH;n#n zB-{u;A>H5?2@04{L)ry=bcx9~^K;iWat9MTM_WICm{YB^gV?f*{aKzSmCLXDRBEP7 z^|K2xCQG8gu6q_~Fy??;VXRC!e+zqm0c`uWd++Oc+`Q@@;YMQOt;VeffYRTa?oul7 zoe1F^s}{oIH(_A^uX0~pX`9WoaewgGThIG{Tu#tjNB04Me3F!x!u3iXCrIv`*2n}^2G3S*)^vn=Gv zlz=1t9+6V3NuoRSTe(Ve@%Rcx%xm>El$^Uqr&YLn{+MPiuv0b~@^s*R?h%jfPF#<2 z!0FtS&e_XXU5XSkXBtZ#sRBJnLxO1&898)Tu%GZcXvAS1qm037S8bKxBdDeA){5rS zSNDEC6A5wdtf5_Hmh~qDag0HD%-XIcc z?ei??G=0yLtfi=!^M>f#g#4W1dmfoMV2aEbI&ewQSwrH3kdH<4CXPOQ_*#|wP<1nx&Z!f;U9aqA8oDVDriXpcjV6sy(K|;f(qeG#2D2staJc?k&B})p z57FxzY6>B9E})LwG9+buKIg6^8kWk(!|4>Kub~9{Dkk6Y=SXCkzJJT@4u$T{`2YBN z>!7y2uY0%!THFf7inOH#T3mzEqNNlo?oM!bEk%n{C>|hqaSiTn2^1$dEeS5c^-Vv| z^OfH`Gw;m(<4!V@N$xq>d+oK>KAT%c%U*K>GY-v|ZW4qso`JOVrSK8rT0_emeR@iz z?gtd0z*D)83?lKq#l?Y^HK!j7Q|3pH0W9?Gu&_Nt8@O8ji=v%xC%7`79ZNnQl(01_ zfOGCy^Kpfvt{9~^NLl`N3gvEd(ELxE587`?jyC1-#`TWy$uazFG;C1koUK99PRl*s zBp=<-`?OsGJ!$aO06A1Z0axd6(Rcx%3Mr?+P8K0MoBe0~xY>SttF@eA_9W+?846TQ z1EBn%KJ--SZ3%BsRo_IP_bUG^_QY}Yb}3KuUUQxJ{kwVrcFuj6YK5fFP7uBSWw-+l zJmSf%z(CFzrq1X{=VIosFgUB*twA3EfUvq=hUV+C?JinK<%yr0>&tm4$K}+T8hmD@ zFRjXPeg2!R^zHs0`Uok%>9J{QEqDw1TdptDD{zpr5SMNy|5!LAW*BeH(9+g$L+|qS zy8x?s?@zuRMiV`7TH*wxJetv-MK@)!1M-LA?x=zL3zzTNiS`cp>ycw_!Flh;wNpgy}rt`@*S zotjeH*dk9S2iv+(Xkm*N&xzer{FrSG^M6h82lgd2vzi}J?64P;?z}V>IcCE)yf?_d zpr{;QZ(O^C0Y#g3`q>ZbINz1FD*nm(oFtLB#cwlmCsxo6&>ghSE5S0AX`+*gIYT3o znkM0u=}-P@7T_f*;>%M!^dZu|VID8IZvUDojIwL~-H+2*|JPOU4(M)o(KX1t&ewTifnP?Fa$7 zWHAZH>-%|M;)})#)aZ4ZAs6!byDwPy@2bw3hLT_FKwiPOJ@m=-KI%VVc0RV)aR1KP zGQZ@PvE+CTPcot%P!iB-Xq5Y&!KMJwU>kb7+m>j|JRwpD104ua(mug>nDG3e)BdW^ z@73j|)69F{15g?&^W6XFw}gi=Y{%i%mbYyIU5TJ~S~(zIW?qrH>}u)b6i>L#izGg5 zk5@jEx%bO`fT+Iv@U>VDBCGWU^D7IEO|j0<8ssA&l3u!E}5 z&-)jhwVsCQvSPe+qJD@AN_jDXK}z!Qf3MUTtXFPIUoQQ3KfIA7*%6EJDmxY^iyXDU z#t((!3ZBJ?hV+r%%g!y%tVDBqwtv~vQ#XMQeV>`Z*qX0}E;(=zj1hG33hn_%#y4{~+`2Xrnu>&DMmF z>n#TPtcKt(4n|f`BooOFG7m(waR@Myv^yV4$PnCaYj75_Ik?1m%i?zR^0nWlkncNH zqC4Xe`8vnIM{VT7WCO&{;gbn^e~PV>d+-xZUnJ-RbDW!fapd1|%vw^qX9{>f{%KFv zdlQaB1)h9rQJQ)#pd1wfJ))MC9J}zcwk4%fT1}R5tX*jjK-RBC@pEFleEzSCOA+@2 zGV?)CIH|D*^mExc|2pOmfSL6~8Lpts9jz(wUfwSc_1bQXw&%fam zb0kn>?*#m5av&bqsZ3(-07lY7eWT!sBSK4GVy~$7B)b)W9_{$`!?+@GSa+40L{Dzk z!KYt&t|a$oBLrvJPK8A!@Wjx#tgoyNkVD%JtTK85S z$BDbpB;%l30=OtgM)^Gh%|ZD)nZ#PxB}2aP&@|VKG^r~E1EhZszVJ409EkT(OlPj} zsJ~MlyIb;D<@+j8o_`jofOqs^TDJ}!$oKw8hrmH>bI{|r8_!B^eJW~|S*6{Ju1CW6 zjlk1>#OKx)LNU4X+;Bjx)jjcI0Lvj<{zaWG7EA#p=Ty;dQ6wlSCt6vElVx8qE8>&(6m+nLGkJo%+Dh zP!@T!V({LsXx#db4^VC`{vb+#O=+E%IMfb2sqn06i_QS&bpj+ch1U!pWOQkbArdR7 zhCIQpW#Onz%^+*M-{7rsQZxyX9y2g2FUp-eEv5HyldTTK9}k#GlPq%7q$$Jw`I|teQotun8lR~yO9ITP)0h@?S)OZncVrVhWqn8M1=*YNM^!S?VgLCb5 zr+{1gm72Md(4>;4z}IMgGG|-%tG07h^xXHFpU{A8p;(n|?+^p{8j26)tLnK7k&{GR zd}0Kk#SJ46XO#Sy&Xb zeMB*;+qaUY)7p58oB!)u_t(Oih%Y$*zR1bZ5sJ(hn#R(j>xe1#=$W&cGnpkeKI4f# z(b$9)Yrt|XzTWzP6C3<1{YQ`z+ei)fjZZbHumKCIS&*llOZcrTWKJNyOF|8~7)gRj zP>WizHf0_&;Ty|Hd3A(+K+G!#GznQ4ooDVrA5{1$SrYM}{iKHqLhDvIPR(H{I3*lK z529Z@U3<&N2Bbw|yj?2CrCpLD-HUl>7r+ryI|dys*mnGox4+~twM6@Vy2g}TLj>jX zZ0DEF3Op`&Wk>p&34aJhZ=RMn_pQLnpD{V`ihjZRMe7TRwnv~hWpRCXi-kRN^5EL+ zEKn6yU}yBO^JiyN^RX9cPNxu}OF7qcf`)neF4BGM)y9Vtcd+lhK%MBh;IFakibiE| z2V;wogkipyk?s-REAkm*umKxGUl0#)P0>;IRSV%mn1hcy1YKq_c`M_BHZa-#uFumx z{)-;sJ5bwkibz&(lt>npe-C$Z`~4ZrSYxC7Y~lX+sgJjEFb}nTyX`Gwqx&CBfwqpz zec(9dUi#x#)6)OR6(kRfo}m9f50gvfo;sj7!C(4`Msj`BuklBEw$xiOJGR9_*sIOv zKqlhMKJLQRWy7*ZN57~9$XiHr2j$CabB2lVKt@|c#PC^n4aX!f(km* zx`Ff@-Ti%`q}|*=%*hVN<7FB!3V$We6!j2@r~I1Wo9>Fa-()%lCKs}s6|>!oXaG%Cs^=IomqF~1EbF< zVJSQf!^C_8qwFTwmm57sbYugJGB)w&0Zg_JI;=hBSVvUNXO4YM*#Ve88Cxpr6bvh1+S4DjS%nB3**`C5u(&~? zBR+<%1!V%y+lc#S1VThBQ7ymHY{jR{4_Lsiej%^jVxbC>2&De9&Cd{MLvEh?e{#Wd zjLD!cAyC|^V?Rq|t4Q6GXK&mD!Yp&U0ZnxGvRvFR%)<)LGH|W>=E4QDcl*zRHs&bo zAt<*j*hajLSp$Z)h0M{=lh|`~Xp&X}UfoA8b&Ca4w9k)>*OLol&o?LaNVfa1xLnN@ zwVF8Nb@&_M>`+i>Ds^T4fzZ-+QU+2DScdz!CBp`DOmrwl1g@&rpe|GVA+Cz75!Q7Q zG0k9g*M_@kQ4CMN<5OcCwhTF;DY$?*;T7obRAn2q7#kQR#>zxcDE8;Z{94W}|EfyD z<8jM6b5$B0yV6tP6g_THO};PFd~wd{+y-i)>O{R?4v4X;qrkS;Tl8sesYyFW=A?%f z)sQzaatCK77G}lqqpsELBC*m(e~KpOptPXY7&@)DHau4P34Pz)#eLi<@|rtcB$!g= z>Kk}NgW-=4yA$PUJ&VVw^T&nGF~z6K@;<2Tn`uvV(=1E`G6lI-66Tos(qQ_&af67c zAqmRuJJ(m5GdyhE7Hd~+-Y!-nUd8$$EKbx8>mH}Bz`fjse_kNHjnuyyPkvNiIU@PE z$?oxauTp!Ktp_(li}Mk52G|jEG9jk5$jkuv0Njorv@=F7JS7*Qe6fMRj(Ssfs+|scU_+ z72VUWr(dpG5Bg8+kLYZ~LFaACiV1*&Bs)EeE-bz{CY7#O`kSZABN|4hLdAB8kD0Vl zj`&%5vv#J*9);LWuL9^>$e8WHsLYYHOQB>{<=Y$fW_gQ{=>bBdiMCj&#QBP+qz9g{Q1e9?1KwqZda5B-g zzx@0KPlL5-=kF2Ki%YW*s5oAxy~I5S&%oKH!dSmXT(m~Gmk;Cm{GW(sns~P#aklqI z4w>yNF2|@Y9$1!qK)bHLD2y75#Vxrp3q0=a)~bvWbP`tz2M|DowNUi)5o>SwqXr>UU*H#DO zV;c>vKMmI2VNE}ERUv14uP`g`7OO3ho}e!p;O;Fp{8HltdY0!{g})~TBvF=?gWuFx zY}mU-xSvdN{B--ex81SpWf^20UcEGEUm+j|e5D>qZBa{t`@`hNM} z5-bbA_Hm;D^L`HN{Q9)G`P4sRG+|t*UTb_Bq$r7)c218hN0(BM{@6-{lTzIGA5j$ z@-N#|UU3?En_n=QLA8F&tP_hLHk@4{8vNs47EwCtIdk4DulD&zbKTsgbVzf1JUGxj zH?h-qX=pQW2)4>)P`*26a5~vVUdE;X7QcE{UgHc$mAbafO{z0}GmtatS2nsAR?~?S ze?ExwZT8pZO7lJEn;DLGax30`Yu{k)TdnBH?x@xKclLio@y3dd`WSBH9k?rAxrJfK zG#=Pz_x|z*%&&Vp$ng?fuMXK?OrYmfSpLuxpHM@CJw^2avVX7PLm=5-gmIQZ1hysS za@&J8)=JG*w<8Y5ZS)Ld=nknM)u1WZ&$$s+a9C#y!`^Sjw6fo)qjLMr^ff^F$`Cxp&t!$K3&$)ArHRSiK!UxjM@{pTHT70ecQ>WHh_oc8KK&G|Gap7qcqHG|1b?M#>qkl0ato$+;OWh!_oK(8C#}z^H32W;YtgS-BMy16SbYuY|G2 zi#zF&fSaA#d$UhRXX|0Jf{b7kO_w#`KlqPD1>=b@b7vJwHMm8JwVL}^MF03F^^2Ee zPE*yyCjEVudx4Yzk7LADJa#doUB@oX0T5!^0f;s)q%clMKo0SiHBvcQy1HVHkTVq8 zy?uu5L9BbB=|}>vd9nF3ciehPANy&X2tGqzr@ek=x8o9JcXOx=QOWJJmitK8L%*YN zXFKr^8nZzKezK1VM{2Yo6LEx|$$1q)jM#X^($|wnJ9*=kLUGZ1FWNDpr@~SM2JpkK z2bK6waGSTBmZ^U$x(j4wrY?`H$>*Rw^%QIs%PSvo8|$g>(CoNYl)4 z^x&ks_d;Clr5p!Sf3Ww$;@%z3+=S|%ZrP{#2vS$)2 zH|&`^g0X2oT(_Doa6@iV0yZ*KY9-(|ikUWIA?r@m`^y*HQyS0)<+g8GH4+5_b`?`v zoV|{%=Mp@-b@F-%^=+EO*~=#3-$6z#w+(ip6Ni9i0c!ykd-|glgCtAqw3en*RNmV z5VFXjw@W*)@7=K#8${6li>^}>59Evoq7J_-t2w|hj06Exb1p}FWXMH1-I;!i-INyR zY!TO|0<0$Q9{R0atJ;aLegfC#zYM-AWYb*S?I}OkFoEWF*Qf=0K0&1C&7ou&46jr% zn2Ckeo)d6Js^HjXHK_$;7jo5WS1@9)Z+7p0W;)6$5TYW6(Jrd zFI;c*TmV>R^QugPs#iC^_1QyMJhN8&>~+Zwu--YoQ=A-)4!sRGJPUZW+IG|({}v^^ z&unP+=+F~jVjKr-7kzR=px)$&eeK(T7K)bG_OEmV{35N3O=rQ4x7}CSt!EZ?LKlmD z({U5{Rn-omw|765Bx+=SMX?IiRs|3S+*U|zR;GesJ!_JP%ygNH-)(^=j^cx&>Gvmj z61A@Sn`Z#Su#U_2`w*e&D3_=Tc_g19_#W}|-VU)eN>}_dfS(b1W4+Jbesf|p_Y&w3 zG&FhHBzHG)Hpgd}eSbU^I9%S%cyLEc0n-6?1X|A$A9h0mTN+^T^RY$G+UuBywT&4Co_jLC1{Q@V zJ*&L??_xmzA56g!iY6q49WiIZ|Cf+pW%_5MA6-m!l4I6p zqw>h}4OsFNfK{EsNeyUJil}%Fd1)S%ncNeiq-L-&?uPpQ>TdPc1TRa9u?yr?9;1mM zkb$~cen8&*A~xGSasEq3KvXndkj7|aX>v{94V$#u3x z2|d(9L9Wo17BKxMg$>h3Wb0>E)=1mKaE2QZ-&#fNfd0iqqn5^z?0}POdq-I8a;-PQ_LEK8{Ei$l1vPv4XG;1aRZ&g=!!&H(hLzBW!FP)c;}~y{j6sB28yY#pbSM$*%=4_kf@`qL-Ehs_zF17c!($-4&=m zZU^`5^B`c5{T!;>X(cxYm#%Gh#tf%T*OzrR928<_N_ZfA(h`=!xvfz|_aN)A+q&ge zn|CY*qJmR2CP>i{sv+QV-Rkei!5a4Lkkc?qh}a+RDY@uaL}q4@>hjF>Th?TnU8%ZL zzGfmjDMYD+%w`hrp1B318%5T)#(Ij|P{V~_sQ zk26|-=||o)NyM$=J^3b7|E3U+8eIFz&-z^j>2g>Ko6JDv-3jN)ZxF!m)(RD1G!8A& zA%ANzIA2BQ0b%X zX7-bGXU84BH^h7TX=fRvfpgrY zzjiqKgqc+#Vp6sb?W5^5{*&s^InS8qA9iFG@1LE{St8r&1ZKLze5WIAg98dwKJ|1o6eAm`hV#I zAipL9&GWzdKxwucmzzCaQC#Er?4M8I$sUp(8AXZ`YSYG}Wju90gJDm1ojkh6)x}Nv z-K)=(Qn@~9X7PlBXf}v|t)yo$TwsA7RDiM}VdEqa(HZSalh3yUyTT;Iqq@q~$daAA zIsf3N{BR@c?UGYG&d=C34U%o7S-@jJ-w`Q1b7cnJ@@ z#ylZ%(|2wt`6aw~f2Q0WqRDR zL4QWTY6m>m<}Ii*@On1RwVZm}+xrr^6!W406#xGu3#|qSj`;wUj0qs zcYfK?W_N2PiO5)J{R6+4&MM-7!`P@eBKH46_M2n;GmlyL<`9Xn>i}*2i#)c)KvS~z z^X~ZY1D4YI5C6hH{{SJTkiR@(Co-5)2FJ9m=wY13a+pS+tG7BL?i_H5#eVnYzf`-| z(C9Whj4H*;7nW${ZvP+U&Xa3lQyRmKz%RgI%+wDJu>TnMDonim1Rd@2s%)z~+6KT=dGwL` zT(+<2+YqqbKW5*)Sz7qJlZm^p1lBh^<8VtCO+MvKPsMxr?OqA&T36Lz$?Qtx%Aw{^ zH$Fe;BkJ+go}++r7bwB^$|1eAXeIDc!Q-~FVN6K1ruIPe?(Q3GVSx4$;YokRP+XoG z4#}GI5L{clYMGJvs;4Dx+;N+65b)T4g2Pu_iy5_PH!z2p7Hw=l1IUK^>TqaYzq?}m zf0Qz^5AP%qSeeC=?twrN-xLfm7n&m}q{*T-uW8U_K)0ZBWaUz<( z`7AkdKZqn&NbLA?w|1}vzh3Jm8E>A{;TvGL13yREiAGzd)QT7*pr6)aHFSL39#@rc zN2fi7p7_yTS_uV+$5MI_7*7WAi6pmL?RX$hJ;5tp6Y1piH|9Ut-6(!|ZT;CAKa1v? zx?^ARI#%e!5K}`vlY^p`PEtvDSG(hA;G>I zWPGb4`uU=I6wM~muF;cD%yCCnKLP6ZtYC27`;Y+I5kLhDgkTQku|w?!Lv?+(pQ$>J z_^Lq1(Zj)9*W!|dn#G!i&$9$0TsiL^1d|K%p6pAHrU}i(f8WwTx=DPDgVyVt zw~Gkgx(?xhqTvY(K_7Q^$bWcL{pb(%cjJU)8aVz|N2e^La^bj;t|HT0IYdvxEr%v& z@`&^Wu^N5?r@rgy?2+Bx1*NI)rk z;0tG_COTa@JLVL<)Nwn>YCy={T`n??exs&|6m-c8g*rX|DshYKnA7kp6#z_E_7Ch| zsrj}51#VfF=gy{zU&d&wj__duQKIVs@BytsAD*T^?s z=oxz*LBWC|r$16Vd9UWU&1-~Rxh!1p z^q<|>`;yO*mai0NxoG=8ZpCRjB+4?D;Nz1%?#-H8;W%E0tE zrQWx+K?BzNTGWt2^m*g+;fWGTF9QbWVIo>{#L5=jZyj|bUNf}NO|v2<%tkI5KD99~ zIBgfSSy{wFv*-pAtha^?zQ<-Zm)NNGih>Hrg;|pw-g$-9KC%`GFZuBvmS7-=8f_pE zX{7tm`=yRojqEo^iMl0sb1gCBo`GCA^kYDms|QOU6GLI4&;u=>XTYVph<}|0@b<{y zLhRZ_aSV=@hK|w-e>#BMdJ|;$iKLu($o}ar(z)9A9#xlBj z?_jp$=E|(r1dn{ z+>A`q@5%w4tiFtF1Vv>lDsk-jDy^@28otL4g{s>U*94Q>W$Jg6dX;Repm~Ec$h9hu zXF{SLCTov0mi)35He_R$cSZX9S7yrNAJ5V^MmGz}eR_Eur8+X`LCXc?BBh}Dc>QvA zA9;&d#w4`Da_)NQ6N{Mny{9e-Tu$$=n3Ki@1)hLA_r4Z);QBsbgN)1j zgJRRN05P$|HF|*Ym!$#2`nZg1-bE3VjhL|Q@XnDh@jd4?36uWOz4vxUPH6|f=LcV( zk(%>$j>v{WQ3c}ZF>DUXg1sNJM+iCv$A7qBQ>(T z=SUoS;U6hXl;ZP-=(Jsy^apa;FLYoWb}7B{Zy{j~v)I5r8L^50L3_{n3XyA?f_GyKa_Nw!GS%USRiKhRy`$mhtvC!M!@fW#T|z zS%kxn@!=-zi#fWJR)Yv*8E!ul;KI;HV7z?3Q^1Jo?)^4C67G|vWPLIt&wEpt7&VKp z#TC8U&7bNH3s;?~i(H-%7e{5jsVmC8ji}Gg8*d`qs}v0#9r}61l(DPOIh@S+!}_-q zq#kV^7#gfcd4B{3FwK|o6s;+A1mQrs4wgrpN%s)rUbD262FbK<$#!>#mGds-*)>ww)nv~VzEmN?u0xMfKNIp zjlCptYW>lH$>Fa>j}A`30jp@&!RrR@zTeS&muz~?O1Wjlcq7l2!xo0U&zcvr{YZpM zKiVG2LxgClhEp6C{Lq#Xz0piDvxk}-jZa@l1g6$dsUDutbVdG`iLh$!G|;VGj_@gidyzHaGs`{;Ce@obO7cf~NQZ^`|{!Us%WxaY@( z(0{L&`rVQyv*WtqK5EULS-hr4Jv;#NEMMZk%Xe>uzgQ@p2}?ps;VCb+Iit9`Gk&t% zHuE7;&69=EEuH9(!O7;0EMjCXT}bvDZ%`75(rSB~TL)M&R9H1b))Quo2cT@>%6OSh zrV#xSNQrWFFq>N#xRyfuSuB5KZ;`StacS=Hgrgtp5GaHNiu9YFB{b)%vzl)^t{c`r$|UWUc9}7fm3us z3CtUuJn2AiCX8z0`lYh}8NW-2T3s#P!6)!_NiuyH2* zh|2HiBa;M|st9g^X2)fMsm1o_uO~0nE7RfzN5PAxJp#_Xb~aqGT@b^}6*nrmj_bF% zzRE=2xWbES@eChtjE_5Kt7v&wP9G-mMwfRq63}<>N|nmNsq)NV&ye78>O24tf*Q*b zjBT8g{b^3|>2rL{^8}qJhjY0HE0OqmLMK8A%W=O>5^;PWs3*JYg1Hwg<o>)Rx{U;=@* zzfJW-TW17(FXm4NTO`5@=Sw+7Ds)H`Pf$(PU>0p*4)CN`cEE)}cHg=X!BcVB>Kf`B zIDR(b;Q8Hy^pKZe*C#pK@&DO9tHyr?lX0)zb>O%PK(l#sJ)uUgx}q_tNjNxmWSZKn z{m1^vbI1upkEf4OUqEKoyN`f771H6LdUBE3%k{>%%jcA8?|9d2K}@!FwUhVnrn)IM zef+qo``@JSihb#Cerc&y#qnkpM3cn0mg4qX0z*C4kyA_bZzq9IKq? zdqjFH20)V|xin>Wx<}UHC{gjEMR_SLLzm~lK`3Vt075m4B6g28`XOf1^{@fy`^KLX z(*!0W_ieVS)m5>0TPkk>Sx2A!;=O5NR*}xc{^ujw)*|YArM_9+K#3a}yb}i>=DQ@r$d$&jwqID5S=OT>cEEfxN=# z6B;V~9@u8=fB6Xuyj{p^nsyZ8H!KcBpIKVlaCw>RxHc^&(PVcmaXokce%vUeZNO+? zgOh05@j{lNEyKhcSQ&KWbOT32^FxiZo7OaiLufriNE#7mKd(FLE_?0AlCrZi2jtfw z`eLgaP?37rA_v{gIY%anZXPYJ<7R(EW;*2y=lloy z3#R|&8w9dRMG#<`1H1}jqCr_Ug4x_(2sYyMWNG3aa8{M8YkRVAbS)8VOz2my;hi>q zclXEMBiq-`W#0%wD^EpAR~W)gDYCXbcmcpKmuk02&!@>>G|5e^rfLX6p={zVK&%l2 z@$DCn$TT(|nIc}DO$M4?Kwwu8CUzS^wG1iyRuV;YtE+6Fgqd^&lqUSoHZ9U5bu3YJ z7d{o95=cAn4U^tHRpN&~U#Kb--a`H!A*a0AGUmf62e$WHnIw;BfVjVy0Ejd#AC?^M z%2f!);F!?y_Ob6;ES4&yoivJ}4U>1aWIX9$N{NI*f6sH6Uz;-O zZSS5ZJn^#KPAhd4vst+_B%cKcm58OOV^~L~FNJ&N{s}!`bhhJ+&q;ai>Ot{YUayuE zwrGdg9`#94+ifM6oh03>6ShudWT}DV4W9C}H7QjsM4Wqyzkb$=+lxLkI8JfMGD?;xr^5}C%DBor3YXcfB_V!Dtq z;!LAV#8YP5K&QB6vmMZ8U%`?lZ?a$(m0aE1OW?vi!0W*$^f~6%_X^I!lhH+;sE3AA z97c2o|3T@Qvgma8N_#Y<(qKC)#=YzDqHZ%4>MJjj`-2fo^nCO~El^@8p;FEiaikBU z-~B*8@Xb!-Ds``zWaP#U!}C$@oQgU4&2QOI=N-3q@+x1p_%Uc)UB%}adb8|EaAPe! zd>o(&NW}^zVLonRWxTk>t)8&gGNYFpW&s%rj16-8iOL7pTd%z;c)uxLV;@~8Q2V&X z(v`f;-WFSK4vAt{pVrl`S&o6zv&d~6n}*f#(+7JyFq7f^IR8Ad#d6l#znGbkJJ<2Z z3b;HV$=0r8tFd-X-c9LDB2Wsy7Th zYl^VYG8^~B#`fhKFP-#zjJQUD7(VJmLemm)EDfcoL{`sfHxID!vWedOl}(D%Ytqh$ z%EeB~G)W(lQc$QR@>h8BNQBi%!L)NIx+(EK0_mbM# z@`8UtXnBU?>p?#Qd|b17m9H91vfXL8(NX+&++b$><7m|L*Q3vPp2^!CGCKvPg@%%g zfK(RdjyfF2yJw2AD+?tFbaptS7c&{x)I0^6gn_UeEyRB6nR#vbT$r#5n&Qv+UZmbrG6j4 zE^F#3gyF|-fdj{8C&0)nK5%#t)xn9 ziaoBF!wxV%?fy}ttv`A)d>DyIY}XfnMCcY(Uu{+pp9e$K`p?<*Irq_Ejs@1NLD*I7 zEWMe%ky>_tq~4-7ggd%#hs6Vmw_phJX3n4QR-m{g(1E+~go#z2uct_SSjCdUR}O!I zHgepAW1dj4$$rB%(c2tpfxR-r9`RZ{1_Prq;aB4|LSazFciW$W;BPufAbl^A$}+=c zeLQBkLhP$@soGTnd_sWVt@9smAcftCiVWvsV(rHw_!~NNJ%KMMwd5c9oyM>f$^rij zH@x5(385i!UVRr}m~HKW!R#YE;cCUaVCaoEv~lgtt13D|zWENaSf2vfCaqtNMO#Pl zrlKx*zSdo`K^tIZsIK0WX_*W@#?knCv~849a%NL^Bl<4|GcS)`#J>$3|8AQ3pBt(u z^paH%e(F5N;e9^?#@M+bY^?NSrwH9S<_WQn%!+aLaivK>{minTOAuH3R-3(?`Oj)? zno@|jl$J7ObmMtq>`2PDw#|iJi4w*v3^>&TsTw>euj7m&9yzDJL_CmsS#@5zgO3EFqA3qU@^dWS8NW$Ka#OuI>ZTm!Rn{chT@B0>75t)=wcWc6_$)ZND=UFo zQVL(^fIVNd0&g;L(j1h&>yzA!x12=nZGS@Pq#zaZ?6nxAX3p|}%%DtR>KXyfRSzCa zdq4UMpjNI+55|<8o#c`tzN%;`4<{$g>->RFY{SBGCNLWw(&Tyz^Co-i&iqWn11n+~V?iMv3DZD4FU{ zJAvp=5IkJl*FH-Jn5|KlRlKS%juqpfp=Dyx>nFT8&7M4Nf%tj4pFZ8Selzy2ABZ3K zuFnsHB%&F7!v)>{B)R_)*ZN- zIyym>Hips)2j@Zby+d9i5JJ8UV6}mj><(7lvQRkAWJZ0YP(rfzdSfk1Xu;ae@h)Fh zrm7DBWHE40FS|KUeQu)16hfgD5dIj1WX(y(7#j}b(*$@|nW*BRY%p0YIR@Wl{r)=Y z?Lse3H^ACrcJdo5Hv2rMMFJMm{!L&sVq?tV(?(%S+sSTpPWw-sKfD-+S4#kK>Fq~B zybIZ~*gbd*#w=54+#`cB3@f!@nferj?%p<`kF=s)B^`ZP!xrp)9?q4x+(5dlaA)dq zqh{7J@wKS$A)O{qRM#0+vygF)#mIB$?aN?k*LGa8lmyWDql(Wy@EI+z>9pw7N;Sq0 z1t6m|Ovy3J%VQxc6Vv&GN4gwW2i|^5)x0&9W`YCXQeV`l$Kf=&SSZwBvDcQZt|iLK zIochKgCX3$O3nC)Ou*4+?n65A2b&nsXNHo*DKhdlrB>EHyq))C+%#0Ig!+ghKT+wS z=Kb=pm8igJFN^v}x@Uwgcw1D~uY?AKY1eA!yx_vh5y|61?Rse2{QuvdaomN`D*0u! zkGiR%vH1R5y&?VhdXILcxSf8Fs#oQFXnLA9I;)S<$J0z}8w;9;jY;rF81#`Nr2J@C ze_h_#o-0)Ec(ArMh3>v+L+T}>wED~5(0mV3^9A8SPR2s%t5sNTl8GJV=j*jB>31+*xj6@QUd<%HX~8cbu`A%2Uqt5GFDURtxFCNfm-7wR@O#jfp`Tj zxbCxD)K!u^xQ!5m^nt;AQmzBdYF6l;lSJ5Ao-ZW`Q*UcX$jeNEv*>0aN2`c+SI$_V z56X{Ht*s!fKiMCpgh9P#A2d_vLi`cVnb*?~3Ao(Kr+MGS!Kae)n!(HjSkyL+w0A;^ zEI=IiuYL<0Em&A(@$WEAR?lNAIJMiZH>N*<&NC6`_^eF!$(QE#6}L@4f5dQ=NV1EG zXyw3MnX`lN-?;HKzzG?+WVv}2h>@eJ(!V&LBNxWdVNH~rKyB6Tb zxVL*|-H-ni7yo0r(f{^04U(pRIX$uX8Yeb_&qa1XRM|P4+f;m-k~d0e>Gf8kXI{x3 z+hKTkT#73QI`u#b?7>66E#FGA5=D0MyKb&}eYE1o4uBjp6P%s}lHG0P|1`n-yPIHh zm(3I*aj)D|q?XzJNjZJZW^2ifYqL8mgc80rH1E?RvRRRRdP)m!&TM*)09NHDm;%kl z&vwhqBc@c0KYYk|8^`CGZNBwd@B?Xc@FhKQ_BXT1JFGK$?DQfqGvY%AH1~Wj%+tHt z%bs+5Gh9WL?496xsAr^)KVu4q(rS_V&PBf4i zn@E~MFBO&byhKYzg^%~kyPuR<&sKvnz%k!3sR&${4{^3hhbWysdgwg9#2SJ7xisfG|uMdzB$;-2hsWo3#n zmWr37$F5txY_%ece3p`zx@OnI6m6fMbpB+IFSO5($>NfZlkQoStIL_%;_kvJ+VVfY zq@=7A7Mhyex5(_b4BRy7Y{pcD;kB1-O9bhN}wKvgHc=&Iit{*m@sXix>#YmT2(h<^Zn3f8 z%KWaC?w0a8T^|Kaumj#N0x8k@+aW8HfqQ5d+gY!uVEoyJ+YB~3rl(qFWilQNzkopr zEH!kr)w2tLMZ^Ghi&XWn5BxSK>S;qnx1Wf+$jD)a^I{Poxk)Q=geh@cgQvMrJ11A$nsNPg|lTMSKG`R&TmyeA8vKF`s1LMYP?oZ~{zTsiQv9n7P7 z6@w5;bY%OFU`onAL*LQa*LTOvdrGU+hs+nS`W-4(V>^_whI078J$9+3capKL;u_;^ zGQ!Z`lTa3>;;mDys6u6B?QUPdMDIpiF8YB z6{u)%p9yg!i_&!)8S8`Jj~~8LqqusLbxL44KAqAJR%2oY(qJq5UM$CGo0`IQ-0-!a zqdC?Z$&y73sFV=Z9;cpyrvV{WtShg)h|)>wH=h>8Tv1`vm$C<)p%akBSNI;Mh0}f` z&?mH{?bjo>_lE?d3TB)3^y=j}+@f#W97}I;cz##KohOc*(YF2y>Tg&MAr&ypeB=a-Y-=b78#i4`sp4vvQ`hTxzHNp^#czTSC=UgLCuxg%?J< z{L%hsK9Y_~@%h96SY-(lDYWo4c}#A+_JHrnD9rj)NsGA41Va7)wfB`_QFiaX3MeQo zjiewTph&||gMf&%(y4SK4h#(fib_i7kP6b$(kLYzL#Hsn&r2nx_Z|QS4CeV?>$)ju8sqlRKDDQGh}!YX4l>5&XyoVqrvmd zJ&UmQ#Ev=EulTf)acjkcEUUQX()Hv=a6gr~TRy)30@vT3)=+rH|ijaX7)M5$eX6SjE%4`6(uaJHxhTnje;dnt$nJ8kc_$cM15Sh5>8nW@& zAeNK)Z*0td`@%H&bcxQUD370y*5u zm%#K5$(#6Z%1ZhD%7wBQt@z?%`kE0z_GzSoi#j-~AeqPQFJzquqNAbfawy{AJX6 zlsDsuf~lz4CD%J$eD`S)9oF(29o0H)T{IvVaNy!OJqo*QTVbXCb?=fIPJ1=!rv_rT z>8^6%3IxhN0qG66EOGx^l}106FpA5QT3!KGbd#D=S%EDA{U4Al>$gYQBo7;1nPjm0 z-t7=7b|=3>)DH?N(RHQyF}_JZCRt5=ilb3cjc@0_yfdW3rj4amfSd9f6Z@#C1Q(lN z&yp1}z4%FJH6!M5z{SnXm7Z#2WM}eYjBNmvr$UIN!}_Kza8m}ePnqIT2WZ;ADKYCO zugY8-*7(+ZP)|;A;w|&JJ~wHr_Cl>&lznE@T-AlBGu}}k9@n4*X z8Y-lqpCo}dbr6#bBk$;Bi$~(>g1F07{jrcHG5=D>Et zTi0Q!RHa+Bd9MU1{oiu&IvrxtNY@iJnjLaWM0I?{^Wxcn+_8QD=TR_Zp);oIl2l5E zeje3o5#AD{2XFO1|JY3{TV@yrnj8g7Sr;qZd9MBGNJ)UAcf~3IhO)Sd7_n?rLQGh0 zI&WU_+9(F@>R*I3dNd%~$p!8hP&@F-7mj#sGsTL@aCO0GdR&ft>sz<4XfQjH$4U;+ z5dVZCkrfS} zx1-Y;Rs4i~*!vIKRhqw)J^ZyruzeJ&ir{=gQ%YYJ#OkS8#<{(wy6 zIFPL?Ry4`j$!`RMnh^F3yKrOD=F=_<48wtEu{kRe+jeV`rlT_M?m(wrqJbOb{p5aK zM~~WyX!zd5mAjk^nL`Y3O8U|`Z{Z1wrgH`g^V_*OQ&0208huPZhjLhhj)^kc=%Q;LYPBf@-u4ISIt3e@!MZ1S>AI6@YHM(C_IX-$PVn5;U1N?<*N{p z=Lm{n#m2pVS4aIWL`vY`&a123kPu=C;d;Nc%+TE^{pS0TO~1NYO|D{!Svn?V4$Zd; zDbc=9UB#0cgql&6k$Y6Iy{Ke+-3J%AeR(w-Pe$2NaGhRo{kEYi`N?$#m2Z-?#bRuR z_nAE&TKVBbx)m%eS|+)YH^5o$*fozvEQrv`av8terAhzcI{Bb7nZTzy`H8;A;D!M; z^$4SgeiRI&xr!Hyt6{{As!~8j{rml_IkqGbKWMhh#>(T@?19sPSa&|+zoDmF{rYg0 z4?_nOEuA=-;D@ZTOxM^-vM}C*3p9?oh0(oZ>g*|{iU^Dti(B2^e$E%)5FOV(>|u`k z+9H$ZYhZw@A=x)g0nF6V3Y_jlzZZ&P7<0UAN)Q;=3&yQq3q#(~OjkMmlNI4oypqbD zT8F}TPkMsNVKUiO!8?odU?1^^4_7k<`A`xWq*=zX{F6q}lL%7oVr>@Al((5tcT4LQ zKRv4!MKaFiBV#IcYTI0c7;GPZL*2!Fn`ye=)Rop_Q#w3t={JJt_%`z09(n{tE=}je zaE-phT-a;fik5}UJiZ1SGUMl}W4Iezaj7$}Gl<|jGB*I{U41Op{1Bhf^N9zEHWEI5 z<^(|%FpYD{&jlzy>c^ybKoT+ZV}A;1@FaErA>h#19NmI@T1zQj^3@7UeH80T&P(Z$ zW3=h4(c2Cw<9Kt`{(7;8hqA+~E+vXL zN>w@G-W~mpI|&kIRtApOftO$QHs8-=z4Ic;=-p_9cJf_2YFzGj%%|CU9GBArD<}it z?~)+dyriIFQji$%ulKN9lEfcA*=%Fp6^`h1e}9!HsqU3}T?QD5tBWw&!kb^`Oam-MY3NEADs511EY|%8 zC40j+j4Ui{{2tyf#kXZrdEda_@>*o>nt6vNOarg@ge7^fW)IvO{n60V@C`(;rS&uI z!@Lx+SVnNq;#|!v&t$o9f5oDV$c6!rs}OJy`uXOIj2`dAnJw;s1U#lh#TVG(*y{Po zui9Ui0H>*w8h#Mrn(=hAzflTEmU_UtY9e|S-|D8|Y3y6tz*VYFS0+amH({bB4?+Na zg0l?g6TT{JQ-e(y`N`flAgDO zU=gyjnKOf{b*&rO-@!Y|621}<)N2g+K$qy}P%f4neV-R=1$0Vn&PwufSh?!;EstKH z1V}TDa0jJODc08}-}9H{hw`}L+BSHBp+|&@@Df#DPnwKm2@rU_Gd5w`rb4OWNdf!; z1$6gUmPwj`Kc|ZYD#oE{w0p3UJ zinTUj@HEvWs`hx267d|CEBESoF|qw^ z%%qT*-R~0TQ_XSd@bs;@9c`ltYdEEb;_t|M{F>)!_^6hjT(1(nV-r2KStL`vB9*vl z`e4Ycv%C(MQ1npOKTfb|oMv9q%;?37C7!1d>aeLzya`DotLU7Lp-=MU`am5tAs|Kft4tQ5_e zeOqmxY%RHY^qoJgS~_DxwXp^tS0F9z>&wQ$`snloTgex*0jAsS+*R3Lvqmc-H8I3C zN`_?~UW%ACY;i-+q=l8ZOqjYtIr&ZbwZyzve>7RFS~e;9C(vpKNHw{P&FISBGb4q0 zRYQMi#@ro3yOIo8U7n?eP z+rW(%jH##_xSj9O*7+2af%rsg=3K?qvG%D$UC%3C_{KgTZ4o>{q?-BVe8d|q3V53kqu|t%{JS))7|0&bvcf%|!Qi z3T^p1R4PXEG=`YG-PZ4aeDvUr}Y5|xW4%cA2l(wqRxM2>OY*%qVU9n z?Bt6DUQ!ld?fQ+SX6fUL%P|>2Kpf2JfKblp~UM9Km+ohUxJc>MjO0v zx{G6Dz!*{n7~1CTC%(wgGo7dVS8Y%t&Uk;OElAa&!lhTW}6x-1zPdvpOse^ zYYaMjqHiy*^kq@Hf#Rp!5X*WTsVLB8E9Z*{{LnlbvVUL>aY)C{&{?({g-ISwd2WB} z*at9!TJyK;=hE1tRB@TMPvQV{)T%*WFOG6t=!~G7s8^&W*B8l$*rOjxc?1cvyExJI zDgPJ3ESF=(8ho+`b`I8ntv)8<#&#ma96+*wB||H9QSh4|z^OQ}tF|9)$bD(ZY#t27 z6P2-F#Ge6UU$*{rE`O@EB45%;QgMWVtAJgnfkix{l_fhi#UPlh}oD^ z;m@|Q15}@Ix3DAz?J`6K%@fL$&$JWIv0>lQ)CCQ&F)4A=>0`KQxNlcKn{ZNP1tb()=+)& zvnLW|76(j$F8ILuMv^bNe0^ENJsec!nPwxw?7-xo)D`xZJ7S5ecO(L_Ql%20-#qzW zp1kGElNUOu@n5u`uXKQWD|nlMI$@wBKJXO?$Tkp4_L~-C`AImmBXK3ed=`4JN>i* z;#sxMlToFMnk8NT{;Z>3tL);79qC;GIMTc?{Pyrl*m5Y@h_Wf z^1mdm2!4=x59{w14*+nAKjh_xg$S&0R#?c4sTt6@ zIIdVb07@mnz?_;3Si=3!!o0B+zuHAj%eW1w6TEN5s^lUoXW<&8rEU9{c`TltL)a>< z(Ybe?6_uYr@8n;721NfF*ZkSIP`KdEKbq-tT32%zQk;{$d-W(mZoMY_q1!8!8*b~q z3^D;vu&$NmeAdc0s5scvQBf@@FyIi7ULuQPp~PX}|8S{~F_ndpv1V5QwN?Y^zRzpU zzzbnveVPR8?htlgEgdvi)X!-ki&cY4+=$glSHeIgPoT`k2p0*^d_8S#vw$a-Fl3)RC~&JbtvCxtdMC z=+ft)F44E~5s~fn5v7RKKYoNv=&Cy4hW^-lm+IJ$RyV}LQ!5}ja=<$&01i6#3)8w3e}bzyJ69x%Og_Y zG2T;S)bVoy)n=GbO{HA)7@z}rRwJP>}RJZot!=vSa7JzT3Rg$->u6hRhed>XT zX=KK1l(W^8@D9DR3#Wbs8~MHDn4^yFob*?hE(7op0ry&8@~OOr16rQ{B=Gwi;6r>6 zxX`bQZ#Mf*&ke^~6f4t$M@!nLD=^Q>-B76=ArK}T2S=bFMKyInofz++trm(P!2ZAJ zossF61NUgN-ix~SpC0}p+~bH9K;;NkfaU~K-Ume&XveQ;bxi3GIraxd)`t+Yy$@gL z$v56w=V#lYEK`n*j&5E?nKg1i41*jqbN$fAiwlg`F5}9%@xBIg`*m$Jur|N*F*Z8s ztJr7^l17w*?zj4O?f2dfHWB7KN6$Y_L zq66dMV{`>}?1uLavzeB-)xY$s`@vmk<{a0X8yKz_pFZWK<=R*qRABrIBtXdu*oTr^ z6BUmJ1(C%QjHc_LU7A{ZJbEEek~<>Hg~=6}g2vI=5J;r}#PCdae-8=xP_IP9rqSct zFTNgX2diw+ho4X8iM z%Xh&8r0C)RrxfDgfNr)wro={ThDEJ))((?U*BMJE61>|bR=l6DRh%o+IcD;wHQ#IC zm2`}x+vm`F$i}c>^E%Mz5mxrKMCd|=c57bfxXNn4Q#5?aSQ!?^lRhk;!zT^Eo~81I z|3n%V7VNH7g<|x-!cOtIf(66J%N9W+fx}0BS<>8C`x=7b*Ba2$x!mE+zt6v_-vLOB zk-UWc{s#Du>be?F!$sSipM_Y zEahq#D3*V)uPrq)#AG&Abg9X9}Pwprw)asHjpFZr2!|aF*T0$cfz66JdDkFBZ6(| zoNKN}qr=sv#!u(C?a(^Q2K+#dkI-%OK|zR#9M{I9Rt9Xr9^1aQm**lEhngZShXyRc z^x`K|#@}O&iv$e!N6K0f2DAKFv|MF7_8a|Jn^Z}2!(17a3`yz`9x>QA3Nv?2bAEh>vkuaP<_nqp2^6fjyMjn@}@x0 zy1P1?P$xd6V+DFuoaD^5L-u+krTC!39ZH&-D#Dj6P)=>}g0^Z<**Z0*8-9C!x8dePPVEh7 z)G~i(9rI$HcVC8VOl@zaQ`KxujJ(lw-$>ze_-K4KGHSr7i+0ReZt#;7PcnXMwZ`0b z4EaaYqoI5^*l2BfF{FjA^?>mGy;fwr6GwPyEJ;rI_IPiL<=do$iJ3uJyW!sQK8b(z z|B{axV9Yj9d8-HLx;f0!qXz^It)oHK(`d!bvbSDjq2lhklJd34&kczF28k#vJ+Yjv z2!ANt;48pJG;%#~e#NZc)FJT({Nvb^DuP^W~~!B9dmB2>rvhZl%vpkP}J=Ta=`yUMK5C z?Gf~c#vfCEO&@+lEUWa+ZdY_SD?at2Tn64fKtga}K~s&qqfHr~^F`oJ-NqURB1%|! zE+E@uP3+*^#|fFhAX5Ll(*>hZR0s%-!3-PtN{YR+CaJRn@ieEnWO3LY6N64YI<2Zq9ULCLy%R zaP3ges1&3*{xjLP>niI286o=vOI_!)4EzZxn!WNo*yNC3|kC ze)ZaPMlI144Q0uJ5A0p%Dts#f4c<$7%9>{m_;oqHoiXn|u`F7KJj-{B>gMCqE3=X; zYItFxVKA1$J7btAed!V%yPUM7+QgmxIh1!oshrd|@d<48ML}oauJ54S(;8XYIF9Vi z3fJX~uS@oZ?}c&A)b31q?n!Qh?RwWdX3+Zd;N@mV4q;<(L_r7cTiiH^75~?%Sd;R_ z>b-BJ6qnbLrb9rrzSG6-RmIuL_WR9Y5-+ny8+pDj<>7vBxGZ3 z?4JA3uQIpe$|PLSGJA&jzkpowaR%J_y4K!9bT@5wn_Za+O zE`t7PL5O3yv881WC9mU@O{Q_?ti$KUjr3&+;=t(6tc4e|DK*8fI6Xb=4qV2vx+jRa zYW7`h#!K!!B#a|^yL$ZXk@NNWkTywkOF2sg(6$J-+ppIvFR44kqDzwbPn%YHvq)O# zVkRVp1del+d*aG;OYOAB_kXM#O{QrYKTDo=I0%bjMl6LJw1qehEzuI5vY2&y->Gz5 zqGF{#*s#$waogxc+69i$9SxKPw63ROLIaf(cWNvmM6(58kje;XbME3ux``~_CU7_(;?QHD6u!1+lZYa(BM%jIw>H|=G2*|a-2ms{ zOiJXweIhzn$374LU1+ZC54!c@3n=PR{%X8APSCisud3Kx9h6Vc5 ztz}n=%s+-EDTZd6O;RY=Ix0tP(0l*9;;`a{G&A*f|7pIlhjP}?J9W9S7ffBP4D~vV zI3WCUMNDdf@Gaq6ps&t_@oTQ4M)rihY&Oby%uE5k! zf)f8^ub(4;L_tZ9o#ank0;eqEka8?=LRH`@lE@v6BF*y48w0pyS7JlOo!yJ7He$#W z@15=?Gfk{k0KR?1_(^;CuCRtgm*_#?u!L*3nVT8`2<~i@1Z~VL-n_Y9!IPA<-@W2K zXE*`c4LPk|0Im=oWL-!UMz-!9+Zq;(+unFk7Hsdm6wUcVp`nKU$nr_l@?vXDR~5Uv z$=Z@rJ7TO(B6H?oh*h6nUu667yeR7lhby0rtE+2M>3EFsjtJ|d^UpUUi|XYb{9}v> zNu(eoEwSTT`PgBR^T!OtA!3S489J*ZU#B6=5+WiX?zj?DT$B?5;u=!Pe2mG8rZJ@I zKvJS+C&=_CEWQG7V8u)IxHk7D2kK+5sb0xD+xU|AbUmPm&n3qr^7iF%b??Jn_9_&+ zVZoyNm;i0KGdLvV9&MHEVHqsVb8~ovPXC};5~19ct*q$VrF$y4pg`a4HX<`*HmBVA zRq({TE!1j>$CY`>!C|M+uq|Jm0Mred#|`thS=>0b7LTvt;1$W*S+;I9c5-(dDNFbw zE@`ewOV0rD+4E>vn9y#=wZiEF-%-gn>b2J^4{y3w0B_J1E zllCb8li~r{dkCoofh3YuxsIoAS7LB`Z;hVo9a#>AZMpUoogcza)>FVAe_U*AZqE*% z9UHc2Y{}~RQ&)SSD&vHa&Sj~aUqIdu-ko$jHB#CpiA0KTO>uu-Ul=YimGVGnW}2^8 zAEV zkmI32Af4>G?eq2d=5F!wn=V&bELeqjj>1ndr6lj;u&+D$>(#ROG5^dB|Kow#$^hLT zo>@DWB;UHm_cjIf~rG3B1l9*E{rzy-aO}zp~&mIMaTy6||g7foy$vzflOh!#BQKH#XLQX4G5H zV?OsZW*`T6VTS2qX{WB>ZAql1D%{u}{%}#O&;3(N7Xe6?Fz!PTvT8(&MPjGr>uGC3 z(fWY5lQQ(1!A`G)Y13)EgW)*e+}n{|;BHXd+cCMZ6cS%|W|qo3yST)V6eCk@zNW>+ zE!U9jFqdB+g{)>qMi$95lVhq0oh*061T(f~^JI97i{icT*F;#VPDXXR8znOA+#?+n zwj&{iI_xos+0uGcI)5AJ>au zPd2RE^IsS(G}kCA_Uj61J$!U(ziH67^~i7T=GtW0Q(lhGTh@U44WGy#gT9|U`Bi`j zGq>x^CkG+*dMaLa&U~F&3RSB_h#10Ku4RUj<=ghSj)o<__iOQHSpF&EEySgfH$ncY z7M_kio#%s|O}Pvi5$6nE>`DNcGbed zOV22u72f#;A>>|xiD{HyR|&%qbbsm1MuW8koo@I<+(0Nwxteo_#??hbPk14h=GEk8 zeK(>Id1_E&xwS0JTc z2O93_+?A~u?|q|=_|qplH9f+H9!t(f9UnX+CJJ;BMTSW?Oigtm~8vQ3MoQuX^zdRRwj!bvdRq$ zm!#!#W5J^Q##jw1MeJ(r$BbPeel+|p$&WBwfjLOrqM#R$x=77#0WSrKqL%<(4=V94 z(|j_y%67+flsGxWZ&ws>X=5qH-UZM9lU0|>Id7iK%yTvNMWJ%G+!rP@Tjbs`w-|1O7i0 z6Dq--vo-iVE=;@@+8aq#WCNggn|zfEz!(VMeeh!NS6fTI|V}hpz6tEqF|)>n^_| zwwv=ocwKnum(c0!_M-g07kf#T-T}g`@lIA#cXw!=ZC1pOevaE()ui*oexYpEpLQRpl6?~Rf^}(q_w;U=K(`^l1JgtI zH^&4Rj4uU4@ImtOx=qhpnPlX{KUe`t?b)ozt-!caej|5QEZFZbID}6@J~YoX!FUPc z+~{|DAg>4QEgebMqW7A&cW7y-Ypv?8MT7(*2!tfuvFz4nM)7lICKrcHMMUeM)BM^S zvn?l-yArNX^B?bwls+xktAC#SZi9)ib1ke&$asgup+%}Lgo!nY_HcEl)+T0Q$g9wH z=y`rumFLcq07I?Yw}Fv45&C0&fwxOeb^Gt@n5XTKE;|F*h=bOt94}!O*k&HH%D6-y zZOBy30h8;{+jSoC5Q$&Dl;STuqO2FY`m?$x=?F!gAd#%6R-o%~5bFFS*N#tN;|fbUnKCM>2^H{m5`98j`a-{VekxpR>trS#!1%$gn>>8P_Vd1Cp~X`O)=j*!r<6 zcw*v^R(%D`E~?_BcX#0V?FSuEf?Js>#i=sezoTzY_*t3Eva~bmPr&gZzkN3CrY(Gz zr(60yN&nD%da*CcUiRQ~-zeSf+qZl3Aj!l7v4`S}+3@vWG=P{^u%`{$~}olFuh-xeY*)8|dXG+=>zx%`&m5Re+k| ztJun0eSxfq-}(Y(0t#CKn^$;5(P{Q;0$IJG@G1_e zY>I6HbmIiG>s^$!W}`%MZH|zj6UCorJ0Ah)1d+ql(2-Qp2AXR(IAa7WKijM4E=2x% zztKEa&?9of5TA^nFt>IwjxFs={N=dh^-M0U_-Df_Giw?rNaskJ|aGqo{g)EqtI z)D!n^nd+zg(;FWzz&x+63LGs`zXB_z3`?2=zS(Hy=LR=qEwIoM)jWRR;|7C@U;Tn) zRf}E2PQcJq5>C>mUk$+dOjt+LmZxf8KzN_B6(mol|V(7+DPz`yT z@37JsfodDdH6+^=-`=g>@*Is$#D@ zIBu;@*12uR9(+G8v}p3J-mH1JLQzFP8Krr$vaH;gfHLglQ1(NJL17;>Pe!Y$HohmE zwsEXaK~#*~TnzSoO;I=C*r>KD#})Dx1))0y9@~{s4pVh&9UNSD?*u<3*neT*N^LVG zzMWCMS@P5K5JpZr>eNvM-6bh+ItaE#wGoaWVi({wh6elT-BU4GzPPBiUAhWyyk!ZV zf}^;hjF#Lh1#?lM)WDiX^EyoPWNAERrb)YdHi~e8Ux6X6h-1R?N@qa6pHxYm!L}%+bUSiPq1``L(Gt9qogd<5D=c}<` z!tZe;ks{=^=-S|UrVYXU=w=FzARX40G>>THvG`*LfK)AB0&2@rZgN%OcdQ3YdKB;} z*2s_K=q?3^PZ3aBxSn7-y2;iQ{Eo;n2Gr-E-WENq#hJ6Rx=1RTjo zqUO*znq)0{0hq~aj#!k@VKxJ-%VtO3#uv@JO4NXE+AmRo?um3AT^O9^rkkVg}q zP6{|Q6nlsIjz2(q-bmp5;Yz^(W@!+kJYVurFa z9;0Zs%b z^&#Ib9que?bhcnzJ*kI3A9)Mp8xrSec8u*~@}T<^0G1vwhJNMxja86i=r+e>o0k~JALB-%_YX0ZJ#=1^oF_3M$wIIT?Y|=EI znQqhWuj9nFkV_VEjzJ3=447MJ5EORE5}L0_H&<+>SD4P{^P(5gPw_1G=`C#eVndSvtQM5!kh_^9 zl?=%+(X9tCb)1juvn&0jh9$OB{5iFD`?XvpSz@_3xhPLJzRM&i@|@1Z=YcJA274@CRc|RLwJV5 z*|?_St0Pd`!zE>21*XJ~0%H>cTwLo5>3MeC-zf)t{hf2TU=SeywvWf-t(qrfWqi$9=Q!)1&sz;qLr zrT_B(_)rs&+mY*zAD`Eub5Pq4*?fa<&|MNrtO}Xo@uEF1ck^5eAx?oJ_34;p( z-`+&-EO8#M3vI5Sja=a~=KuImz+Hv~&a$tEXi@3{8K7&Gv#9ax0quFCyfAhZ8^Avn zHcf2qy6En%Bi2&hec^OFSU275v{-dNC28~3HXzfQIgJo@XYuB E06?|z?*IS* literal 0 HcmV?d00001 diff --git a/docs/backlog/backlog-core.md b/docs/backlog/backlog-core.md index 48e63761..6877a782 100644 --- a/docs/backlog/backlog-core.md +++ b/docs/backlog/backlog-core.md @@ -25,7 +25,7 @@ Forward-looking to-build items for the **core / infrastructure** domain (`src/co DevicesModule discovers via **passive UDP presence** (UDP 65506) feeding a [`DevicePlugin`](../../src/core/DevicePlugin.h) seam (shipped: projectMM + WLED plugins). mDNS is advertise-only so projectMM appears in the native WLED apps + Home Assistant; the WLED-app interop (list + live colour + brightness control) is shipped too. What remains is *growth on the seam*, each piece additive (one plugin file, no core change): -- **More discovery plugins** — ESPHome, Tasmota, Hue (*hub-shaped*: a bridge whose Zigbee bulbs are children behind it, with link-button auth). Each is a new `DevicePlugin` declaring its `discoveryPort()` + classifying the datagram (or, for a system that only does mDNS, a re-introduced advertise-side browse scoped to *foreign* services only — never the ones we advertise). Hue is the canonical "more than a flat device" case the seam is shaped for. +- **More discovery plugins** — ESPHome, Tasmota, Hue (*hub-shaped*: a bridge whose Zigbee bulbs are children behind it, with link-button auth). Each is a new `DevicePlugin` declaring its `discoveryPort()` + classifying the datagram (or, for a system that only does mDNS, a re-introduced advertise-side browse scoped to *foreign* services only — never the ones we advertise). Hue is the canonical "more than a flat device" case the seam is shaped for. (Note: Hue *control* already ships as an **output driver**, see [HueDriver](../moonmodules/light/drivers/HueDriver.md) — bulbs as effect pixels; the driver also *lists* its bridge in DevicesModule with the dimmable-light count. Two complementary follow-ups remain: (a) auto-fill the driver's bridge IP from discovery so the user doesn't type it (the mDNS-browse plugin above); (b) **pair once, not per driver** — pairing + the app key currently live on each HueDriver, so two drivers on one bridge pair twice. The clean end-state moves the bridge identity (IP + key + Pair button + light list) into DevicesModule and makes HueDriver a pure output that reads the paired bridge by IP — do this together with the discovery plugin, since both hinge on DevicesModule owning the bridge.) - **The command half** — `DevicePlugin::command()` (+ per-plugin capability/auth), so projectMM can *control* a discovered foreign device, not just list it: set WLED brightness via its JSON API, a Hue resource via the bridge's authenticated CLIP API, a Tasmota via `cmnd`. Built when a control consumer exists; the discovery seam is already shaped to accept it (incl. hub plugins). This is the **multi-ecosystem selling point** — one UI controlling WLED + ESPHome + Hue. Commands split by need (the rule, not "all REST"): must-arrive config over REST; latency-critical sync over UDP (~0.5–1 ms vs REST's 10–50 ms — REST would visibly de-sync). - **Live peer state** — a discovered peer's brightness / on-off shown in our list, refreshed by polling its REST `/json` after discovery gives the IP (discovery = UDP/mDNS, state = REST). The read-side complement to the command half. - **Non-IP transports (board-gated, far future)** — Tasmota-MQTT / zigbee2mqtt need an MQTT client; **direct Zigbee/Thread** (S31/C6/H2 802.15.4 radio) makes projectMM the *hub itself*, driving bulbs over the mesh with no gateway — the standout differentiator, the biggest lift. Same plugin philosophy, a transport addition + board gate. diff --git a/docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output).md b/docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output).md new file mode 100644 index 00000000..66b76c07 --- /dev/null +++ b/docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output).md @@ -0,0 +1,83 @@ +# Plan — HueDriver: Philips Hue lights as a projectMM effect output + +## Context + +The product owner has Hue lights and a bridge ("Hue Ewoud", BSB002, API 1.77, at 192.168.1.143). The reframe that drives this plan, from the product owner: **Hue is an *output*, not a device to list.** projectMM already drives "an array of lights" through the effect → layout → buffer → driver pipeline; Hue maps onto that directly — a handful of bulbs are a small **grid** (e.g. 5×1×1), an **effect** runs on them, and a **`HueDriver`** (a sibling of `RmtLedDriver` / `NetworkSendDriver` in the Drivers container) reads its window of the output buffer and pushes each pixel's colour to the corresponding bulb. The bulbs are *pixels of an effect*, not rows in DevicesModule. + +This is *Common patterns first* + *Concrete first, abstract later*: a new driver is the recognised unit of "a new output target," and the architecture already has the seam. No new core concept — one new `DriverBase` subclass + a small outbound-HTTP helper. + +### Verified on the wire (not assumed) + +- The bridge advertises `_hue._tcp` (mDNS) and answers N-UPnP — discoverable. +- **The bridge still allows the plain-HTTP Hue v1 API**: `http:///api/0/config` → 200 (not HTTPS-only). So **no TLS / self-signed-cert handling on the ESP32** — the single biggest simplifier. CLIP v2 exists (`/clip/v2` → 403) but is HTTPS-only + event-stream; **not used**. +- Hue v1 is HTTP + JSON: `POST /api` (link-button pairing → app key), `GET /api//lights` (list), `PUT /api//lights//state` (`{"on":bool,"bri":0-254}`, optional `xy`/`hue`/`sat` later). + +## Decisions locked (product owner) + +- **Hue is an output driver** (`HueDriver : DriverBase`), sibling of `NetworkSendDriver`. Not a DevicesModule entry. (Listing the bridge in DevicesModule + auto-filling the driver's IP from discovery is a **follow-up**, per *concrete first* — build the working output, add the discovery nicety after.) +- **Scope: on/off + brightness** from the effect's per-pixel value (luminance → `bri`). Colour (`xy`/`hue`/`sat`) is a clean later extension on the same PUT. +- **Update model: throttled, changed-lights-only.** Hue's bridge rate-limits to ~10 commands/s/light; a real-time stream would need the Entertainment API (DTLS) — out of scope. The driver samples its window on a **slow tick** (target ≤ ~10 Hz total across its lights) and PUTs **only the lights whose colour changed** since the last push. This is the standard way apps drive Hue from animations. +- **Plain-HTTP Hue v1 API** (no TLS). The bridge IP + app key are **controls on the HueDriver** (self-contained config, like NetworkSendDriver owns its target IP/universe); a **Pair button** runs the link-button POST to fill the app key. Persisted with the module. + +## Design + +### 1. Outbound HTTP helper (platform seam) + +The repo had `httpGet`; it was removed as dead code when DevicesModule's HTTP sweep went away. The HueDriver re-introduces the outbound-HTTP capability — but **minimal and with a real consumer this time** (the prior removal's lesson: don't keep an unused seam). Add a small `platform::httpRequest`: + +``` +// Outbound HTTP request to a LAN host (plain HTTP, no TLS — Hue v1 allows it). Builds the +// request, returns the status code (0 on failure), fills `body` (NUL-terminated, truncated). +// Synchronous + bounded by `timeoutMs`. Desktop + ESP32 over the existing TcpConnection +// (which has connect()/writeSome()/read()). GET/PUT/POST via `method`. +int httpRequest(const char* method, const char* host, uint16_t port, const char* path, + const char* reqBody, uint32_t timeoutMs, char* body, size_t bodyLen); +``` + +- Desktop + ESP32 build it over `TcpConnection::connect()` + `writeSome()` + non-blocking `read()` (the same primitives the HTTP *server* uses). Plain socket, no libcurl, LAN HTTP only — exactly what the removed `httpGet` did, generalised to GET/PUT/POST. +- **Off the render hot path**: the HueDriver calls this on its slow tick (loop1s-cadence), never `loop()`. A bounded blocking call there is fine (same rule as the old mDNS browse / the OTA fetch). + +### 2. `HueDriver : DriverBase` (`src/light/drivers/HueDriver.h`) + +Header-only light module, mirroring `NetworkSendDriver`'s shape: + +- **Controls** (`onBuildControls`): `bridgeIp` (IPv4), `appKey` (Text, persisted — the credential), `pair` (Button → link-button pairing), `start`/`count` (via `addWindowControls()` — its slice of the buffer). A read-only `status` line ("paired, N lights" / "press the bridge button" / "unpaired"). +- **`setSourceBuffer` / `setLayer` / `setWindow`** — standard DriverBase wiring (Drivers container passes the shared buffer + the active layer for dimensions). +- **`loop()`** — does NOTHING on the render tick (Hue can't keep up; never block the hot path here). The driver's window is sampled in `loop1s()` instead. +- **`loop1s()`** (the throttle): read the window slice from the source buffer (`windowSlice()`), map each light's RGB → on/off + `bri` (luminance), and for each light whose value **changed** since the last push, `httpRequest("PUT", bridgeIp, 80, "/api//lights//state", "{\"on\":…,\"bri\":…}", …)`. A per-light `lastSent` cache (small fixed array, bounded by the window count, capped at e.g. 32 Hue lights) drives the changed-only filter. PUTs are spread (one or a few per tick) so a tick never blocks long. +- **`pair`** (Button → `onUpdate`): for ~a few seconds, `POST /api {"devicetype":"projectMM#"}`; on success store the returned `username` into `appKey` (persist), then `GET /api//lights` to learn the light id list. The "press the link button" instruction shows in `status`. +- **Light-id mapping**: window index → Hue light id. First cut: the lights list from `GET /api//lights` in id order maps to window indices 0..N-1. (A future control could let the user reorder / pick which bulbs.) + +### 3. Drivers registration + UI + +- Register `HueDriver` in the driver factory next to the other drivers (one `ModuleFactory::registerType` line) so it's addable from the UI like any driver. +- The generic UI renders its controls with zero per-driver code (the whole point of the module tree). + +### 4. Desktop testability + +- `httpRequest` works on desktop (real sockets) → the PUT/GET formatting + the changed-only diff + the window→light mapping are **host-unit-testable** against a tiny stub HTTP responder (or by asserting the formatted request bytes from a seam, no live bridge needed). The product owner's real bridge is the bench cross-check. + +## Files + +- **New:** `src/light/drivers/HueDriver.h` (the driver), `docs/moonmodules/light/drivers/HueDriver.md` (spec — controls, the Hue v1 wire contract, pairing flow, the rate-limit rationale, prior art). +- **Edit:** `src/platform/platform.h` (+ `src/platform/esp32/` + `src/platform/desktop/` impls) for `httpRequest`; the driver registration in `src/main.cpp`; `test/CMakeLists.txt` + a `test/unit/light/unit_HueDriver.cpp` (request formatting + changed-only diff + window mapping); `docs/backlog/backlog-light.md` (mark the Hue-driver item building / add the follow-ups: colour, DevicesModule bridge discovery, Entertainment-API streaming). + +## Riskiest parts + +1. **Rate limit / not blocking the loop.** The throttle (changed-only, ≤~10 Hz, a few PUTs per `loop1s`) must keep the bridge happy AND keep each tick short. A PUT is a bounded blocking `httpRequest` off the render path — but many lights × a slow bridge could still make `loop1s` long. Mitigation: cap PUTs-per-tick (round-robin the changed lights across ticks), short `timeoutMs` (~200 ms), and degrade gracefully on a 429/timeout (skip, retry next tick). +2. **Pairing UX is asynchronous + physical.** The user must press the bridge button within the window. The Button handler can't block the loop for seconds — so pairing runs as a short bounded poll across a few `loop1s` ticks (a small state machine: "pairing… press the button" → key obtained / timed out), status-reported. Don't block the render loop during pairing. +3. **Re-introducing outbound HTTP** — keep `httpRequest` minimal (the lesson from deleting `httpGet`: an unused seam is debt). It ships *with* its consumer (HueDriver), so it's earned. +4. **App key is a credential** — persisted in the module JSON like other settings; it's a LAN bridge key (low sensitivity), stored the same way as e.g. a static IP. Note it in the spec. + +## Verification + +- Desktop build (0 warnings); `ctest` incl. the new HueDriver unit test (request formatting + changed-only diff); scenarios + spec-check green; ESP32 all variants build. +- **Bench (the real test):** on the product owner's bridge — add a 5×1×1 layout, an effect, a HueDriver (window [0,5)), press Pair + the bridge button → key obtained, lights listed; the effect animates the 5 bulbs (on/off + brightness) at the throttled rate, no bridge 429s, render FPS unaffected (the PUTs are on loop1s, off the hot path). +- Save this plan (done); mark `(shipped)` when it lands. + +## Out of scope (clean follow-ups) + +- **Colour** (`xy` / `hue`/`sat` from the pixel RGB) — same PUT, one more field; the obvious next slice. +- **DevicesModule lists the Hue bridge** + auto-fills the driver's `bridgeIp` from discovery (the product owner's "list it in devices" idea, done as the second step — discovery feeds the output). +- **Hue Entertainment API** (DTLS streaming, ~25–50 Hz) for true real-time effect sync — a major separate feature (TLS-PSK on ESP32, entertainment-area setup, v2 API). +- **DMX lights** as another such output driver (the product owner noted this is coming — Hue maps the "array of foreign lights" pattern that DMX will reuse). diff --git a/docs/moonmodules/core/DevicesModule.md b/docs/moonmodules/core/DevicesModule.md index 41a7f5b5..07090260 100644 --- a/docs/moonmodules/core/DevicesModule.md +++ b/docs/moonmodules/core/DevicesModule.md @@ -34,6 +34,10 @@ Foreign ecosystems hook in as **plugins**, not hardcoded branches — the adapte The plugin classification is pure and host-unit-tested (`unit_DeviceIdentify.cpp` feeds synthetic packets, incl. short/garbage → declined), with no network. The full pipeline is tested via `injectPacketForTest` (`unit_DevicesModule_discovery.cpp`) — and because `UdpSocket` works on desktop, the discovery path is host-testable with real datagrams, not just stubs. +### Out-of-band devices (Hue bridge) + +A device not discovered by UDP presence — a Philips Hue bridge, found over HTTP by a [HueDriver](../light/drivers/HueDriver.md) — registers itself through `upsertHueBridge(ip, name, colourCount)`, reached via `active()` (the boot-instance static accessor, the `AudioModule::latestFrame()` seam shape). The bridge then lists like any device, with a `colour` field (its colour-light count, for sizing a layout). This keeps the module domain-neutral: the Hue HTTP/pairing lives entirely in the light-domain driver; the core only stores the resulting row. (`unit_DevicesModule_hue.cpp` pins the row + its persistence round trip.) + ### Age-out Each sighting stamps the device's `lastSeenMs`; `ageOut()` runs every tick. A live-confirmed device is kept for `kStaleMs` (**24 h**) after its last presence packet, so the list is a durable "devices I've seen" history; a **cached** row (restored from persistence, not yet re-heard this session) gets only a short `kCachedGraceMs` (**60 s**) probation, so a long-gone persisted device can't survive forever across reboots — a live packet promotes it to the 24 h window. A **timestamp**, not a counter. The self row never ages out (it tracks the current local IP). Storage is a fixed `devices_[kMaxDevices]` array — bounded, no heap. diff --git a/docs/moonmodules/light/drivers/HueDriver.md b/docs/moonmodules/light/drivers/HueDriver.md new file mode 100644 index 00000000..ce825969 --- /dev/null +++ b/docs/moonmodules/light/drivers/HueDriver.md @@ -0,0 +1,47 @@ +# HueDriver + +Drives **Philips Hue lights as a projectMM output** — the bulbs are *pixels of an effect*, not entries in a device list. Make a small grid (e.g. 4×1×1), run any effect on it, add a HueDriver, and each colour bulb in the driver's window becomes one pixel: the effect's per-pixel colour is pushed to the bridge as hue/saturation/brightness. It is a [driver](../../core/architecture.md) like any other (a sibling of [NetworkSendDriver](NetworkSendDriver.md) / [RmtLedDriver](RmtLedDriver.md)) — it reads its slice of the shared buffer and sends it out, here over the Hue HTTP API instead of a wire protocol. + +![A HueDriver in the UI](../../../assets/screenshots/Hue%20driver.png) + +## What makes Hue different (and why the driver is shaped this way) + +Hue is an HTTP hub, not a strip, and these properties drive the design: + +- **It's rate-limited** (~10 commands/s across the bridge; true real-time needs the [Hue Entertainment API](https://developers.meethue.com/develop/hue-entertainment/) — DTLS streaming at ~25 Hz, a separate future). So the driver paces itself: **`loop()` does at most one bridge PUT every `kPutIntervalMs`**, gated by a `platform::millis()` check (never work-every-tick), round-robined across the lights. A single bounded ~ms PUT can't stall a frame; the rest of `loop()` returns instantly. This is **smooth ambient colour**, the standard API's sweet spot — not fast strobing. +- **Only colour-capable, reachable lights are driven.** The bridge reports each light's capabilities; the driver keeps only lights whose state has a `hue` field (an "Extended color light") *and* `reachable:true`, so every window pixel maps to a bulb that can actually show the effect's colour right now. A dimmable-only white, an on/off plug, or a powered-off bulb is skipped. +- **Transitions are smoothed by the bridge.** Each PUT carries a `transitiontime` matched to how often that light is refreshed (lights × interval), so the bulb *glides* from its current colour to the next instead of snapping — the bridge's built-in fade, tuned to the cadence. (The Hue default of 400 ms is too long for this rate and smears into a frozen look.) +- **The shared output Correction applies**, same as the physical LED / network drivers: the global brightness slider and a swapped colour-order preset reach the Hue lights too (each pixel runs through the brightness LUT + channel reorder before RGB→HSV). Brightness 0 → black → the light turns off. +- **It needs an app key** (a "username"): the user presses the bridge's physical link button once, then the device claims a key. The driver runs this as a short bounded poll across a few 1 Hz ticks — never blocking the loop waiting for the press. +- **It's plain HTTP, no TLS.** The Hue v1 API answers over `http:///api/...`, so there is no certificate handling on the device. Bench-confirmed against a BSB002 bridge (API 1.77). + +![An effect driving the Hue lights](../../../assets/screenshots/Hue%20friendly%20effect.png) + +## Controls + +- `bridgeIp` — the Hue bridge's LAN IPv4 (the [Control](../../core/Control.md) IPv4 type). Find it via the bridge's app, the router, or `https://discovery.meethue.com`. +- `appKey` — the Hue app key (username). Filled automatically by `pair`, persisted as the driver's credential; can also be pasted if you already have one. +- `pair` — a **button**: press it, then press the bridge's link button within ~30 s. The driver POSTs to the bridge until the press is registered, stores the returned key into `appKey`, and learns the bridge's light list. +- `start` / `count` — the window of the shared buffer this driver drives ([the standard driver window](NetworkSendDriver.md); `count` 0 = to the end of the buffer). Window index *i* maps to the *i*-th driven (colour-capable, reachable) Hue light. +- `hueStatus` — a read-only line reflecting the driver state: `unpaired`, `pairing: press the bridge button`, `paired, N lights`, or `pairing timed out`. +- `colourLights` — read-only: how many of the bridge's lights are colour-capable and reachable (the ones the driver drives). Size a grid layout to this many lights (N×1×1) to map every colour bulb to a pixel. + +Once paired, the driver also **lists the bridge in [DevicesModule](../../core/DevicesModule.md)** (alongside discovered WLED / projectMM peers), carrying its name and the colour-light count, refreshed on a slow cadence. It registers through `DevicesModule::active()` — the same static-accessor seam [AudioModule](../../core/AudioModule.md) uses for `latestFrame()`, so the light-domain driver reaches the core module without a structural dependency. + +![The Hue bridge listed in the Devices module](../../../assets/screenshots/Hue%20device%20disco.png) + +## Wire contract (Hue v1 API, plain HTTP) + +The driver talks to the bridge over `platform::httpRequest` (declared in `src/platform/platform.h` — a synchronous LAN HTTP GET/PUT/POST helper that reads the response straight into the caller's buffer): + +- **Pair** — `POST http:///api` with `{"devicetype":"projectMM#device"}`. Before the link button is pressed the bridge returns `link button not pressed`; after, `[{"success":{"username":""}}]` — the `` becomes `appKey`. +- **List lights** — `GET http:///api//lights` → a JSON object keyed by light id (`{"1":{…},"2":{…}}`). A real bridge's response runs several KB; the driver scans it for colour-capable (`"hue"` in state) + reachable (`"reachable":true`) lights and maps window index → light id. +- **Set a light** — `PUT http:///api//lights//state` with `{"on":true,"bri":0-254,"hue":0-65535,"sat":0-254,"transitiontime":N}` (or `{"on":false,…}` when the pixel is black). `hue`/`sat`/`bri` come from a textbook integer RGB→HSV of the pixel; `transitiontime` (deciseconds) is the cadence-matched fade. + +## Prior art + +The [Hue v1 CLIP API](https://developers.meethue.com/develop/hue-api/) (link-button pairing, `/lights//state`, `transitiontime`). The effect-as-output mapping (bulbs as pixels of the render buffer, driven through the window) is projectMM's own — the same shape its UDP and LED drivers use. + +## Source + +[HueDriver.h](../../../../src/light/drivers/HueDriver.h) diff --git a/docs/moonmodules/light/effects/WaveEffect.md b/docs/moonmodules/light/effects/WaveEffect.md new file mode 100644 index 00000000..38fbddd6 --- /dev/null +++ b/docs/moonmodules/light/effects/WaveEffect.md @@ -0,0 +1,31 @@ +# WaveEffect + +An animated **waveform that scrolls across the grid** — the classic oscilloscope look. Each column plots one point of a moving wave; as the wave's phase advances with time and is delayed per column, the lit points trace a curve that travels sideways, leaving a fading trail. Six waveform shapes are selectable. + +## Controls + +- `bpm` — travel speed (how fast the wave's phase advances), 0–255. +- `fade` — trail length: how much the previous frame is kept each tick (0 = the wave leaves no tail, 255 = a long persistent trail). Applied as `scale8(trail, fade)` over an own z=0-plane trail buffer (sized off the hot path, like [ParticlesEffect](ParticlesEffect.md)). +- `type` — the waveform shape (a [Select](../../core/Control.md)): `Sawtooth`, `Triangle`, `Sine`, `Square`, `Sin3` (three summed sines — a richer rolling wave), `Noise` (1-D value noise — a jittered band). The shape maps a phase to the wave's y-position each column. + +It is a [D2 effect](../../core/architecture.md) — it writes the z=0 plane and `Layer::extrude` duplicates it across z on a 3D layout. Runs at every grid size (a 0-height or sub-3-channel grid is a no-op, never an out-of-bounds read). + +## Orientation (which axis is which) + +This is a **D2** effect: the waveform sets a **y-position per column** (its shape lives on the **height** axis) and the per-column phase delay scrolls it along **width**. So height is the wave's amplitude axis — a grid needs `height > 1` to show any waveform; on a 1-tall grid (`height == 1`) every point collapses to y=0 and only the colour shows, no wave. + +This follows the project's [1D-runs-along-Y convention](../../architecture.md#dimensionality): **to drive a one-dimensional output** (a single strip, or a row of [Hue lights](../drivers/HueDriver.md)) **lay it out as `1 × N` (width 1, height N), not `N × 1`** — the lights map onto the height axis where the wave is drawn. An `N × 1` layout plots a flat line. + +## How the travel works + +Per column `x`, the wave's phase is `t + x·skew`: `t` advances from `bpm` (an integer accumulator, so a sub-millisecond frame time isn't lost), and the `x·skew` term delays each column so the shape appears to move horizontally. The phase runs through the selected waveform to a y in `[0, height)`; that pixel is lit, and for the discontinuous shapes (sawtooth, square) a vertical segment joins it to the previous column so the line stays connected. The wave's colour cycles slowly over time. + +**Palette readiness:** the colour comes from a single `waveColor(index)` seam — today an `hsvToRgb` hue sweep. When palettes land, that one function becomes the palette lookup with no other change. + +## Prior art + +[MoonLight](https://github.com/MoonModules/MoonLight)'s Wave effect (Ewoud Wijma). The *behaviour* is reproduced — the six waveform types, the per-column phase travel, the time-varying colour, the frame fade — written fresh against projectMM's `EffectBase` and integer primitives (the `sin8` LUT, `scale8`), with the colour routed through a palette-ready seam rather than MoonLight's `ColorFromPalette` (palettes aren't in projectMM yet). + +## Source + +[WaveEffect.h](../../../../src/light/effects/WaveEffect.h) diff --git a/src/core/DeviceIdentify.h b/src/core/DeviceIdentify.h index 3eacf3d4..6a774a9f 100644 --- a/src/core/DeviceIdentify.h +++ b/src/core/DeviceIdentify.h @@ -12,12 +12,13 @@ namespace mm { // What a discovered device is. -enum class DevType : uint8_t { Generic = 0, ProjectMM = 1, Wled = 2 }; +enum class DevType : uint8_t { Generic = 0, ProjectMM = 1, Wled = 2, Hue = 3 }; inline const char* devTypeStr(DevType t) { switch (t) { case DevType::ProjectMM: return "projectMM"; case DevType::Wled: return "WLED"; + case DevType::Hue: return "Hue bridge"; case DevType::Generic: return "generic"; } return "generic"; diff --git a/src/core/DevicesModule.h b/src/core/DevicesModule.h index fdb87c5b..6bdf0b82 100644 --- a/src/core/DevicesModule.h +++ b/src/core/DevicesModule.h @@ -51,6 +51,7 @@ class DevicesModule : public MoonModule, public ListSource { sink.append("{\"name\":"); sink.writeJsonString(d.name[0] ? d.name : ip); sink.appendf(",\"ip\":\"%s\",\"type\":\"%s\"", ip, devTypeStr(d.type)); + if (d.type == DevType::Hue) sink.appendf(",\"colour\":%u", d.colourCount); if (d.self) sink.append(",\"self\":true"); sink.append("}"); } @@ -64,6 +65,7 @@ class DevicesModule : public MoonModule, public ListSource { sink.writeJsonString(d.name[0] ? d.name : ip); sink.appendf(",\"ip\":\"%s\",\"url\":\"http://%s/\",\"type\":\"%s\"", ip, ip, devTypeStr(d.type)); + if (d.type == DevType::Hue) sink.appendf(",\"colour\":%u", d.colourCount); if (d.self) { sink.append(",\"self\":true"); // self is always "now" — no meaningful age } else if (d.cached) { @@ -101,9 +103,12 @@ class DevicesModule : public MoonModule, public ListSource { Device& d = devices_[deviceCount_++]; std::memcpy(d.ip, octets, 4); std::snprintf(d.name, sizeof(d.name), "%s", name); - d.type = (std::strcmp(typeStr, "projectMM") == 0) ? DevType::ProjectMM - : (std::strcmp(typeStr, "WLED") == 0) ? DevType::Wled - : DevType::Generic; + d.type = (std::strcmp(typeStr, "projectMM") == 0) ? DevType::ProjectMM + : (std::strcmp(typeStr, "WLED") == 0) ? DevType::Wled + : (std::strcmp(typeStr, "Hue bridge") == 0) ? DevType::Hue + : DevType::Generic; + d.colourCount = static_cast( + mm::json::readInt(mm::json::member(doc, el, "colour"))); // 0 for non-bridge rows d.self = false; d.cached = true; // restored, not re-heard live → UI shows "cached", not a time // Stamp "now" so the cached entry gets its kCachedGraceMs PROBATION window @@ -123,8 +128,40 @@ class DevicesModule : public MoonModule, public ListSource { controls_.addList("devices", *this); // this module is the ListSource } + // The boot DevicesModule (exactly one exists). A foreign-bridge driver in the light domain + // (HueDriver) registers a discovered bridge through this without a compile-time dependency + // on DevicesModule's address — the same static-seam shape as AudioModule::latestFrame(). + static DevicesModule* active() { return active_; } + + // Register a Hue bridge a HueDriver has connected to. Unlike upsertDevice (driven by a UDP + // presence packet), a bridge is discovered out-of-band — the driver already holds its IP + + // app key — so this is the explicit entry point for that. Idempotent: updates the name + + // colour count of the existing row, or inserts one. `colour` is how many of the bridge's + // lights are colour-capable, the figure for sizing a layout. Persisted like any device row. + void upsertHueBridge(const uint8_t ip[4], const char* name, uint8_t colour) { + Device* d = findByIp(ip); + bool persistChanged = false; + if (!d) { + if (deviceCount_ >= kMaxDevices) return; // bounded; silently cap + d = &devices_[deviceCount_++]; + std::memcpy(d->ip, ip, 4); + persistChanged = true; + } + if (d->type != DevType::Hue) { d->type = DevType::Hue; persistChanged = true; } + if (name && name[0] && std::strcmp(d->name, name) != 0) { + std::snprintf(d->name, sizeof(d->name), "%s", name); + persistChanged = true; + } + if (!d->name[0]) { formatDottedQuad(d->name, ip); persistChanged = true; } + if (d->colourCount != colour) { d->colourCount = colour; persistChanged = true; } + d->lastSeenMs = platform::millis(); // transient — keeps the bridge from ageing out + d->cached = false; + if (persistChanged) { sortByName(); refreshStatus(); } + } + void setup() override { MoonModule::setup(); + active_ = this; // The last-known device list is restored automatically before setup() by the // persistence overlay (the `devices` List control round-trips as JSON). So the // UI shows it INSTANTLY on boot — no waiting for an announcement to re-arrive. @@ -192,8 +229,13 @@ class DevicesModule : public MoonModule, public ListSource { // session. Cleared on the first live sighting. uint32_t lastSeenMs = 0; // platform::millis() at the most recent mDNS sighting. // Age-out drops a non-self device unheard for kStaleMs. + uint8_t colourCount = 0; // Hue bridge only: how many of its lights are colour-capable + // (the figure for sizing a layout). 0 for non-bridge rows. }; + // The boot instance, for active() — the foreign-bridge static seam (mirrors AudioModule). + static inline DevicesModule* active_ = nullptr; + static constexpr uint8_t kMaxDevices = 32; // a LAN's worth; bounded, no heap // Broadcast our presence every this-many loop1s ticks (≈ seconds). Slow + light, like // WLED's ~30 s beacon; a new device appears within this window. A departed device diff --git a/src/light/drivers/HueDriver.h b/src/light/drivers/HueDriver.h new file mode 100644 index 00000000..3f0cdc74 --- /dev/null +++ b/src/light/drivers/HueDriver.h @@ -0,0 +1,377 @@ +#pragma once + +#include "light/drivers/Drivers.h" +#include "core/JsonUtil.h" // parse the bridge's JSON responses +#include "core/FilesystemModule.h" // noteDirty — persist the app key after pairing +#include "core/DevicesModule.h" // DevicesModule::active() — list the bridge as a device +#include "platform/platform.h" + +#include +#include +#include + +namespace mm { + +// Philips Hue lights as a projectMM OUTPUT — a driver, not a listed device. The bulbs are +// pixels of an effect: make a small grid (e.g. 4×1×1), run any effect, and this driver reads +// its window of the shared buffer and pushes each light's colour to the bridge. Same shape as +// NetworkSendDriver (read a window, send it out), but over the Hue v1 HTTP API instead of UDP. +// +// What makes Hue different from a strip and shapes the design: +// - It's HTTP, not a wire protocol: GET /api//lights, PUT .../lights//state. +// - Connection churn, not just Hue's ~10/s command budget, bounds the rate: each PUT opens a +// fresh TCP connection (the bridge speaks Connection: close), so loop() does AT MOST ONE PUT +// every kPutIntervalMs — a millis() gate, never work-every-tick — so a synchronous round-trip +// can't stall the single-thread render loop AND the TIME_WAIT sockets don't pile up. Smooth +// ambient colour, not real-time (that's the Entertainment API, a separate future). +// - Only colour-capable, reachable lights are driven (parseLights filters them); each PUT sends +// hue/sat/bri from a textbook RGB→HSV plus a cadence-matched transitiontime so the bulb glides. +// - It needs an app key: press the bridge's link button once, then POST /api to claim a key. +// Pairing is a short bounded poll across a few loop1s ticks (never blocking the loop). +// +// Plain HTTP, no TLS — the Hue v1 API allows it (bench-confirmed on a BSB002 bridge). Prior +// art: the Hue v1 CLIP API (public docs); the effect-as-output mapping is projectMM's own. +class HueDriver : public DriverBase { +public: + uint8_t bridgeIp[4] = {}; // the bridge's LAN IP (from the UI) + char appKey[48] = {}; // the Hue username/app key (filled by Pair, persisted) + + void onBuildControls() override { + controls_.addIPv4("bridgeIp", bridgeIp); + controls_.addText("appKey", appKey, sizeof(appKey)); // persisted credential + controls_.addButton("pair"); // link-button pairing + addWindowControls(); // start / count — its slice of the buffer + controls_.addReadOnly("hueStatus", statusBuf_, sizeof(statusBuf_)); + controls_.addReadOnlyInt("colourLights", colourCount_, "lights"); // size a layout to this + refreshStatus(); + } + + void setSourceBuffer(Buffer* buf) override { sourceBuffer_ = buf; } + + // The shared output Correction (global brightness LUT + channel order), same as the physical + // LED / network drivers — so the brightness slider and a swapped colour order reach the Hue + // lights too. Applied per pixel before RGB→HSV; the RGBW/white part is irrelevant here (Hue + // takes hue/sat), we use the RGB result. + void setCorrection(const Correction* c) override { correction_ = c; } + + // A control click. "pair" starts the link-button pairing poll. + void onUpdate(const char* controlName) override { + if (controlName && std::strcmp(controlName, "pair") == 0) { + pairTicksLeft_ = kPairWindowTicks; // begin: poll the bridge for ~30 s on loop1s + std::snprintf(statusBuf_, sizeof(statusBuf_), "pairing: press the bridge button"); + setStatus(statusBuf_); + } + DriverBase::onUpdate(controlName); + } + + // loop() runs every render tick. It must NEVER do more than ONE bounded bridge call, and + // only when the rate-limit interval has elapsed (a millis() gate, NOT work-every-tick) — + // otherwise a synchronous HTTP round-trip stalls the whole single-thread render loop (the + // "never block the loop" rule, decisions.md). So: at most one PUT every kPutIntervalMs, + // round-robined across the lights. Pairing + the bridge announce ride the slow 1 Hz tick. + void loop() override { + if (pairTicksLeft_ > 0) return; // pairing owns the bridge during its window + if (!appKey[0] || !haveBridge() || lightCount_ == 0) return; + const uint32_t now = platform::millis(); + if (now - lastPutMs_ < kPutIntervalMs) return; // not time yet — return instantly, no I/O + lastPutMs_ = now; + pushOneChangedLight(); // exactly one bounded PUT this tick + } + + // The 1 Hz tick handles the non-render-critical, slower bridge work: pairing poll, the + // one-shot light fetch, and the periodic DevicesModule announce. Each is at most one bridge + // call per second — acceptable on a 1 Hz tick, and never in the per-frame loop(). + void loop1s() override { + if (pairTicksLeft_ > 0) { pollPairing(); DriverBase::loop1s(); return; } + if (!appKey[0] || !haveBridge()) { DriverBase::loop1s(); return; } + if (lightCount_ == 0) { fetchLights(); DriverBase::loop1s(); return; } + if (++reportTick_ >= kReportEverySec) { reportTick_ = 0; reportBridge(); } + DriverBase::loop1s(); + } + + void teardown() override { + pairTicksLeft_ = 0; + DriverBase::teardown(); + } + + // Test seam: drive the changed-light diff + PUT formatting without a live bridge — feed a + // light's RGB and get back whether it would PUT + the body it would send. Records the push + // (like pushChangedLights does) so a follow-up call with the same RGB exercises the + // unchanged-skip path. + bool wouldPushForTest(uint8_t idx, uint8_t r, uint8_t g, uint8_t b, char* outBody, size_t cap) { + if (!diffAndFormat(idx, r, g, b, outBody, cap)) return false; + if (idx < kMaxLights) { + lastRgb_[idx][0] = r; lastRgb_[idx][1] = g; lastRgb_[idx][2] = b; + sent_[idx] = true; + } + return true; + } + + // Test seam: parse a real /lights JSON body through fetchLights' colour-light extractor. + void parseLightsForTest(const char* json) { parseLights(json); } + uint8_t lightCountForTest() const { return lightCount_; } // kept colour+reachable lights + uint16_t hueIdForTest(uint8_t i) const { return i < kMaxLights ? hueId_[i] : 0; } + int8_t colourCountForTest() const { return colourCount_; } + + // Test seam for the RGB→HSV mapping (no bridge needed). + static void rgbToHsvForTest(uint8_t r, uint8_t g, uint8_t b, uint16_t& h, uint8_t& s, uint8_t& v) { + rgbToHsv(r, g, b, h, s, v); + } + +private: + static constexpr uint8_t kMaxLights = 32; // a LAN's worth of Hue bulbs; bounded, no heap + // One PUT at most every kPutIntervalMs (a millis() gate in loop()). Each PUT opens a fresh + // TCP connection (the bridge speaks Connection: close), so the rate is bounded by connection + // CHURN, not just Hue's command budget: at ~7/s the TIME_WAIT sockets pile into the hundreds + // and the bridge starts refusing connections (PUTs fail, lights freeze). 500 ms → ~2 PUTs/s + // keeps TIME_WAIT small and is plenty for smooth ambient colour (each light glides over its + // ~2 s refresh via the matched transitiontime). Real-time would need keep-alive or the + // Entertainment API — out of scope; this is the standard API's comfortable rate. + static constexpr uint32_t kPutIntervalMs = 500; + static constexpr int kPairWindowTicks = 30; // ~30 s pairing window (link-button press) + static constexpr uint16_t kReportEverySec = 30; // re-announce the bridge to DevicesModule + // Per-frame PUT (loop()) timeout. A successful PUT to a LAN bridge returns in ~20-50 ms, so + // this only bounds the WORST case (an unreachable/overloaded bridge) — not the normal cost. + // 200 ms gives comfortable margin over the real latency (a 60 ms cap intermittently tripped + // under rapid back-to-back PUTs, failing them) while still bounding a bad frame. kSlowTimeoutMs + // is for the 1 Hz calls (pair / fetch / announce), where the 8 KB /lights GET wants headroom. + static constexpr uint32_t kHttpTimeoutMs = 200; + static constexpr uint32_t kSlowTimeoutMs = 400; + + Buffer* sourceBuffer_ = nullptr; + const Correction* correction_ = nullptr; // shared brightness LUT + channel order (may be null) + + // Per-light Hue id + the last RGB we pushed (the changed-only filter). hueId maps a window + // index → the bridge's light id, learned from GET /api//lights. + uint16_t hueId_[kMaxLights] = {}; + uint8_t lastRgb_[kMaxLights][3] = {}; + bool sent_[kMaxLights] = {}; // have we pushed this light at least once + // hueId_ holds ONLY colour-capable lights (the bridge's "Extended color light"s) — a + // dimmable-only white or an on/off plug is skipped, so every window pixel maps to a bulb + // that can show the effect's full colour. lightCount_ is that filtered count. + uint8_t lightCount_ = 0; // number of colour-capable lights + int8_t colourCount_ = 0; // same, as the read-only control / bridge field + bool sawLights_ = false; // fetchLights ran → the list is trustworthy + uint8_t pushCursor_ = 0; // round-robin position across the lights + uint32_t lastPutMs_ = 0; // millis() of the last PUT — the loop() rate gate + int pairTicksLeft_ = 0; + uint16_t reportTick_ = 0; // counts loop1s ticks toward kReportEverySec + char statusBuf_[40] = "unpaired"; + // Off-hot-path scratch for the /lights GET response (a full home is ~8 KB). A member, not a + // loop1s stack frame — read once per fetchLights, not per render tick. + char lightsBuf_[8192] = {}; + + bool haveBridge() const { return bridgeIp[0] || bridgeIp[1] || bridgeIp[2] || bridgeIp[3]; } + + // Does the JSON span [begin, end) contain `key` (e.g. "\"hue\"") — used to read a light's + // capabilities off its state block (a colour light has "hue"; the bridge omits it otherwise). + static bool containsKey(const char* begin, const char* end, const char* key) { + const size_t kl = std::strlen(key); + for (const char* s = begin; s + kl <= end; s++) + if (std::strncmp(s, key, kl) == 0) return true; + return false; + } + + void bridgeStr(char out[16]) const { + std::snprintf(out, 16, "%u.%u.%u.%u", bridgeIp[0], bridgeIp[1], bridgeIp[2], bridgeIp[3]); + } + + void refreshStatus() { + if (!appKey[0]) std::snprintf(statusBuf_, sizeof(statusBuf_), "unpaired"); + else if (lightCount_) std::snprintf(statusBuf_, sizeof(statusBuf_), "paired, %u lights", lightCount_); + else std::snprintf(statusBuf_, sizeof(statusBuf_), "paired"); + setStatus(statusBuf_); + } + + // --- Pairing: POST /api {"devicetype":"projectMM#"} until the user presses the button. + void pollPairing() { + if (!haveBridge()) { pairTicksLeft_ = 0; std::snprintf(statusBuf_, sizeof(statusBuf_), "set bridge IP first"); setStatus(statusBuf_); return; } + char host[16]; bridgeStr(host); + // The pairing body is tiny, but httpRequest reads headers + body into one buffer and the + // bridge's headers run ~700 bytes — size past them or the success body gets squeezed out. + char resp[1024]; + int st = platform::httpRequest("POST", host, 80, "/api", + "{\"devicetype\":\"projectMM#device\"}", kSlowTimeoutMs, + resp, sizeof(resp)); + if (st == 200 && std::strstr(resp, "\"username\"")) { + // [{"success":{"username":""}}] — extract the username. + char key[48] = {}; + mm::json::parseString(resp, "username", key, sizeof(key)); + if (key[0]) { + std::snprintf(appKey, sizeof(appKey), "%s", key); + pairTicksLeft_ = 0; + lightCount_ = 0; // re-fetch the light list with the new key + refreshStatus(); + markDirty(); // persist the new app key + FilesystemModule::noteDirty(); + return; + } + } + // "link button not pressed" → keep polling until the window elapses. + if (--pairTicksLeft_ <= 0) { + std::snprintf(statusBuf_, sizeof(statusBuf_), "pairing timed out"); + setStatus(statusBuf_); + } + } + + // --- Learn the bridge's light ids (window index → hue id, in id order). + void fetchLights() { + char host[16]; bridgeStr(host); + char path[80]; std::snprintf(path, sizeof(path), "/api/%s/lights", appKey); + // The /lights body for a real bridge runs several KB (a full home is ~8 KB for ~10 + // lights) — too big for a loop1s stack frame, so the read buffer is a driver member + // (allocated once with the object, off the hot path). httpRequest reads straight into it. + int st = platform::httpRequest("GET", host, 80, path, "", kSlowTimeoutMs, + lightsBuf_, sizeof(lightsBuf_)); + if (st != 200) return; + parseLights(lightsBuf_); + refreshStatus(); + reportBridge(); + } + + // List the bridge in DevicesModule (so it shows alongside discovered WLED/projectMM peers, + // carrying its dimmable-light count for layout sizing). The bridge isn't a UDP-presence + // device, so it's registered explicitly through the static seam — no compile-time core↔light + // dependency beyond the same DevicesModule::active() shape AudioModule::latestFrame() uses. + void reportBridge() { + auto* dev = DevicesModule::active(); + if (!dev || !haveBridge()) return; + char host[16]; bridgeStr(host); + // httpRequest reads headers + body into this one buffer, and the bridge's response + // headers alone run ~700 bytes — so size for headers + the small config body, not just + // the body, or the body gets squeezed out. + char cfg[1024], name[24] = {}; + if (platform::httpRequest("GET", host, 80, "/api/0/config", "", kSlowTimeoutMs, cfg, sizeof(cfg)) == 200) + mm::json::parseString(cfg, "name", name, sizeof(name)); // the bridge's friendly name + dev->upsertHueBridge(bridgeIp, name, static_cast(colourCount_)); + } + + // Extract the COLOUR-capable, REACHABLE light ids from a /lights JSON body: + // {"1":{…},"5":{…},…}. A colour light's object carries a "hue" field in its state; a + // dimmable-only white or an on/off plug does not. A light that's powered off / out of mesh + // reports "reachable":false. We keep only lights that are BOTH colour-capable and reachable + // — those are the ones an effect can actually animate right now — so the window maps every + // pixel to a live colour bulb. The bridge response (~8 KB / hundreds of fields) exceeds the + // recursive JSON reader's node arena, so this is a lightweight forward scan: spot each + // top-level id key, then keep it iff its object span (up to the next id key) has both. + void parseLights(const char* resp) { + lightCount_ = 0; + const char* p = resp; + int pendingId = 0; // a light id seen, not yet committed (need its span first) + const char* pendingStart = nullptr; + auto commit = [&](const char* objEnd) { + if (pendingId > 0 && pendingStart && lightCount_ < kMaxLights + && containsKey(pendingStart, objEnd, "\"hue\"") + && containsKey(pendingStart, objEnd, "\"reachable\":true")) { + hueId_[lightCount_++] = static_cast(pendingId); + } + }; + while (true) { + const char* q = std::strchr(p, '"'); // next key open-quote + if (!q) break; + int id = std::atoi(q + 1); // light id is a quoted integer key + const char* close = std::strchr(q + 1, '"'); + // A top-level light-id key: a quoted positive integer followed by ':'. + if (id > 0 && close && close[1] == ':') { + commit(q); // the PREVIOUS light's object ends here + pendingId = id; + pendingStart = close + 1; + } + p = close ? close + 1 : q + 1; + } + commit(resp + std::strlen(resp)); // the last light runs to the end + sawLights_ = true; + colourCount_ = static_cast(lightCount_ > 127 ? 127 : lightCount_); + } + + // Push AT MOST ONE changed light per call (the loop() gate already limited the rate). The + // round-robin cursor walks every light over successive calls, so each gets its turn; we + // advance the cursor whether or not this light changed, scanning at most one full lap so an + // all-unchanged frame costs no PUT and returns fast (no blocking I/O on the render loop). + void pushOneChangedLight() { + if (!sourceBuffer_ || !sourceBuffer_->data()) return; + nrOfLightsType winStart, winLen; + windowSlice(sourceBuffer_->count(), winStart, winLen); + const uint8_t cpl = sourceBuffer_->channelsPerLight(); + if (cpl < 3) return; + const uint8_t* base = sourceBuffer_->data(); + const uint8_t n = lightCount_ < winLen ? lightCount_ : static_cast(winLen); + if (n == 0) return; + + for (uint8_t step = 0; step < n; step++) { + const uint8_t i = (pushCursor_ + step) % n; + const uint8_t* px = base + static_cast(winStart + i) * cpl; + // Apply the shared Correction (brightness LUT + channel order) so the global + // brightness slider and a swapped colour order reach Hue too — same as the physical + // drivers. apply() writes outChannels bytes; we read the first three (RGB) for HSV. + uint8_t rgb[4] = { px[0], px[1], px[2], 0 }; + if (correction_) correction_->apply(px, rgb); + char body[80]; + if (diffAndFormat(i, rgb[0], rgb[1], rgb[2], body, sizeof(body))) { + char host[16]; bridgeStr(host); + char path[96]; + std::snprintf(path, sizeof(path), "/api/%s/lights/%u/state", appKey, hueId_[i]); + platform::httpRequest("PUT", host, 80, path, body, kHttpTimeoutMs, nullptr, 0); + lastRgb_[i][0] = rgb[0]; lastRgb_[i][1] = rgb[1]; lastRgb_[i][2] = rgb[2]; + sent_[i] = true; + pushCursor_ = static_cast((i + 1) % n); // resume after this one next time + return; // ONE PUT — done + } + } + // No light changed this lap — nothing to send. Cursor stays put. + } + + // The changed-only diff + the Hue state body. Returns true (and fills `out`) when light + // `idx`'s RGB differs from the last push (or was never sent). Every driven light is colour- + // capable (parseLights keeps only those), so the body carries the full colour: on/off, plus + // bri (value) + hue + sat from a textbook RGB→HSV — so a colour effect actually animates. + // "transitiontime" is the bridge's built-in fade — the smoothing knob. Set to roughly the + // per-light update interval (a light updates every kPutIntervalMs × lightCount), so the bulb + // glides from its current colour to the next instead of snapping. The bridge's default is + // 400 ms (too long for our cadence — it smears and looks frozen); we compute a value matched + // to the actual rate so transitions are smooth but keep up. transitiontime is in deciseconds + // (×100 ms). The Hue standard API tops out ~10 cmd/s — true real-time needs the Entertainment + // API; this is smooth ambient colour, the standard API's sweet spot. + bool diffAndFormat(uint8_t idx, uint8_t r, uint8_t g, uint8_t b, char* out, size_t cap) { + if (idx >= kMaxLights) return false; + if (sent_[idx] && lastRgb_[idx][0] == r && lastRgb_[idx][1] == g && lastRgb_[idx][2] == b) + return false; // unchanged — skip + const uint8_t tt = transitionDeciseconds(); + if ((r | g | b) == 0) { std::snprintf(out, cap, "{\"on\":false,\"transitiontime\":%u}", tt); return true; } + uint16_t hue; uint8_t sat, val; + rgbToHsv(r, g, b, hue, sat, val); + std::snprintf(out, cap, "{\"on\":true,\"bri\":%u,\"hue\":%u,\"sat\":%u,\"transitiontime\":%u}", + val, hue, sat, tt); + return true; + } + + // Fade time matched to how often THIS light is refreshed: with n lights round-robined one + // per kPutIntervalMs, each light's turn comes every (n × kPutIntervalMs) ms. Convert to + // deciseconds and clamp to ≥1 (0 = snap) so the fade lasts about until the next update — + // continuous glide, no visible steps. + uint8_t transitionDeciseconds() const { + const uint32_t intervalMs = static_cast(lightCount_ ? lightCount_ : 1) * kPutIntervalMs; + const uint32_t ds = intervalMs / 100; + return static_cast(ds < 1 ? 1 : (ds > 30 ? 30 : ds)); + } + + // Textbook RGB→HSV mapped to Hue's ranges: hue 0..65535 (Hue's 16-bit wheel), sat 0..254, + // val(=bri) 0..254. Integer math, no float — the standard max/min/chroma formulation. + static void rgbToHsv(uint8_t r, uint8_t g, uint8_t b, uint16_t& hueOut, uint8_t& satOut, uint8_t& valOut) { + const uint8_t mx = r > g ? (r > b ? r : b) : (g > b ? g : b); + const uint8_t mn = r < g ? (r < b ? r : b) : (g < b ? g : b); + const uint8_t chroma = mx - mn; + valOut = static_cast(mx > 254 ? 254 : mx); // value → bri + satOut = mx == 0 ? 0 : static_cast((chroma * 254u) / mx); // saturation + if (chroma == 0) { hueOut = 0; return; } // grey → hue irrelevant + // Hue in sixths of the wheel, scaled to 0..65535. h6 is the position within [0,6). + int32_t h6; // numerator over chroma, in units where a full sixth = chroma*... see below + if (mx == r) h6 = ((g - b) * 65535) / (6 * chroma) + (g < b ? 65535 : 0); + else if (mx == g) h6 = ((b - r) * 65535) / (6 * chroma) + 65535 / 3; + else h6 = ((r - g) * 65535) / (6 * chroma) + (65535 * 2) / 3; + if (h6 < 0) h6 += 65535; + hueOut = static_cast(h6 % 65536); + } +}; + +} // namespace mm diff --git a/src/light/effects/EffectBase.h b/src/light/effects/EffectBase.h index 403f7584..1466cbbd 100644 --- a/src/light/effects/EffectBase.h +++ b/src/light/effects/EffectBase.h @@ -11,7 +11,7 @@ class Layer; // forward declaration // Dim enum lives in light/light_types.h so both EffectBase and ModifierBase can // refer to it without including each other. Used by Layer::extrude to fill unused -// axes (D1 row → y and z; D2 slice → z; D3 native) and by the UI to derive the +// axes (D1 column → x and z; D2 slice → z; D3 native) and by the UI to derive the // 📏/🟦/🧊 dimensional emoji (so it isn't repeated in each module's tags()). // ModuleFactory::registerType captures dim from a probe via if-constexpr — // no per-domain registration wrapper is needed. @@ -23,7 +23,7 @@ class EffectBase : public MoonModule { // Default D3 means "I iterate every axis the layer gives me" — the framework // doesn't extrude on your behalf. Override to D2 if you write only the z=0 // slice (Layer::extrude duplicates it across z); to D1 if you write only the - // y=0,z=0 row (extrude fills y and z). Declaring D2/D1 is an opt-in promise: + // x=0,z=0 column (1D runs along Y — extrude fills x and z). Declaring D2/D1 is an opt-in promise: // the framework treats slices you don't write as authoritative copies of the // ones you did. On a 2D layer (depth=1) the D3-vs-D2 distinction is free — // extrude's z-fill loop is guarded by `depth_ > 1` and does nothing. @@ -37,7 +37,7 @@ class EffectBase : public MoonModule { // layer's. Concretely: // - A D3 effect on a 1D layer (h=d=1) iterates only x; y and z stay 0. // - A D2 effect on a 1D layer (h=d=1) iterates only x; y stays 0. - // - A D1 effect on a 3D layer writes its row and extrude fills the rest. + // - A D1 effect on a 3D layer writes its (x=0) column and extrude fills the rest. // Hardcoding a fixed `z < SOMETHING` is a buffer-overrun bug — the buffer // is sized to width × height × depth × channels, no more. Tests in // test_extrude.cpp pin the D3-on-2D and D3-on-1D paths for the shipped diff --git a/src/light/effects/WaveEffect.h b/src/light/effects/WaveEffect.h new file mode 100644 index 00000000..942a849e --- /dev/null +++ b/src/light/effects/WaveEffect.h @@ -0,0 +1,178 @@ +#pragma once + +#include "light/layers/Layer.h" +#include "core/color.h" // sin8 (integer sine LUT), scale8, hsvToRgb +#include "platform/platform.h" // alloc — the fade trail buffer + +#include + +namespace mm { + +// A waveform that travels across the grid: each column x plots one point of a moving wave, so +// the lit points trace a sawtooth / triangle / sine / square / composite-sine / noise curve that +// scrolls sideways over time, leaving a fading trail behind it. The classic "oscilloscope wave" +// look. Prior art: MoonLight's Wave effect (Ewoud Wijma) — behaviour reproduced (the six waveform +// types, the per-column phase travel, the time-varying colour, the frame fade), written fresh on +// projectMM's EffectBase + integer primitives (sin8 LUT, scale8), no palette dependency yet. +// +// Axis convention: the waveform sets a y (its shape lives on HEIGHT); width is the travel axis. +// So a 1-tall grid shows no wave — to drive a 1D output (a strip, a row of Hue lights) lay it out +// as 1×N (the project's 1D-runs-along-Y convention; architecture.md § Dimensionality). +// +// Per column x the phase is `t + x·kColumnSkew` — the x term delays each column so the wave +// appears to move horizontally; `t` advances with bpm so it animates. The phase maps through the +// selected waveform to a y in [0, height); that pixel is lit, and for the discontinuous shapes +// (sawtooth, square) a vertical segment connects to the previous column so the line stays joined. +class WaveEffect : public EffectBase { +public: + const char* tags() const override { return "🌊"; } + // D2 — writes the z=0 plane only; Layer::extrude duplicates it across z on a 3D layout. + Dim dimensions() const override { return Dim::D2; } + + // Waveform shapes, index-aligned with waveY()'s switch. "Sin3" is a composite of three sines + // (a richer, rolling wave); "Noise" plots value noise for a jittered band. + static constexpr const char* kTypeOptions[] = {"Sawtooth", "Triangle", "Sine", "Square", "Sin3", "Noise"}; + static constexpr uint8_t kTypeCount = 6; + + uint8_t bpm = 30; // travel speed (phase advance per minute) + uint8_t fade = 32; // trail fade per frame (0 = instant clear of the old wave, 255 = long tail) + uint8_t type = 2; // index into kTypeOptions (default Sine) + + void onBuildControls() override { + controls_.addUint8("bpm", bpm, 0, 255); + controls_.addUint8("fade", fade, 0, 255); + controls_.addSelect("type", type, kTypeOptions, kTypeCount); + } + + // The trail is a persistent z=0-plane buffer (w·h·cpl): each frame is faded down, then the new + // wave drawn on top, so the moving point leaves a tail. Sized off the hot path (cf. Particles). + void onBuildState() override { + const uint8_t cpl = channelsPerLight(); + const size_t needed = static_cast(width()) * height() * cpl; + if (enabled() && needed > 0) { + if (needed != trailBytes_) { + releaseTrail(); + trail_ = static_cast(platform::alloc(needed)); + if (trail_) { std::memset(trail_, 0, needed); trailBytes_ = needed; } + } + } else { + releaseTrail(); + } + setDynamicBytes(trailBytes_); + } + + void teardown() override { releaseTrail(); setDynamicBytes(0); } + ~WaveEffect() override { releaseTrail(); } + + void loop() override { + if (!trail_) return; + const lengthType w = width(); + const lengthType h = height(); + const uint8_t cpl = channelsPerLight(); + uint8_t* buf = buffer(); + if (w == 0 || h == 0 || cpl < 3) return; + + // 1. Fade the trail (scale8 toward black) — a smaller `fade` = shorter tail. + for (size_t i = 0; i < trailBytes_; i++) trail_[i] = scale8(trail_[i], fade); + + // 2. Advance the travel phase from bpm (integer accumulator so a sub-ms dt isn't lost). + const uint32_t now = elapsed(); + phase_ += static_cast(now - lastElapsed_) * bpm; + lastElapsed_ = now; + const uint8_t t = static_cast((phase_ * 256) / 60000); // uint8 angle (256 = full turn) + // Colour cycles slowly over time (a palette substitute until palettes land — see waveColor). + const uint8_t colorIndex = static_cast(now / 50); + + // 3. Plot the wave point per column, joining discontinuous shapes to the previous column. + const RGB c = waveColor(colorIndex); + int prevY = -1; + for (lengthType x = 0; x < w; x++) { + const uint8_t ph = static_cast(t + static_cast(x) * kColumnSkew); + const lengthType y = waveY(ph, h); + plot(x, y, c, cpl, w); + // Vertical join: fill between prevY and y so sawtooth/square read as a connected line + // (sine/triangle are continuous, but joining is harmless — adjacent ys differ by ≤1). + if (prevY >= 0) { + const lengthType lo = prevY < y ? prevY : y; + const lengthType hi = prevY < y ? y : prevY; + for (lengthType yy = lo; yy <= hi; yy++) plot(x, yy, c, cpl, w); + } + prevY = static_cast(y); + } + + // 4. Blit the trail (faded history + this frame's wave) into the output buffer. + std::memcpy(buf, trail_, trailBytes_); + } + + // Test seam: the pure waveform map (phase → y), no buffer/time needed. + static lengthType waveYForTest(uint8_t type, uint8_t phase, lengthType h) { + return waveY(type, phase, h); + } + +private: + // How much each column delays the phase — the horizontal travel speed of the wave shape. + static constexpr uint8_t kColumnSkew = 8; + + uint8_t* trail_ = nullptr; + size_t trailBytes_ = 0; + uint64_t phase_ = 0; + uint32_t lastElapsed_ = 0; + + // The colour for the wave this frame. ONE place: today a hue sweep via hsvToRgb; when palettes + // land this becomes the palette lookup (ColorFromPalette(palette, index)) with no other change. + static RGB waveColor(uint8_t index) { return hsvToRgb(index, 255, 255); } + + // Map a phase (uint8 angle) to a y in [0, h) for the selected waveform. Integer-only. + lengthType waveY(uint8_t phase, lengthType h) const { return waveY(type, phase, h); } + static lengthType waveY(uint8_t type, uint8_t phase, lengthType h) { + if (h == 0) return 0; + uint8_t v; // the waveform value, 0..255, then scaled to [0, h) + switch (type) { + case 0: v = phase; break; // Sawtooth: ramp 0→255 + case 1: v = triangle8(phase); break; // Triangle: up then down + case 2: v = sin8(phase); break; // Sine + case 3: v = phase < 128 ? 0 : 255; break; // Square: low then high + case 4: v = static_cast( // Sin3: three summed sines + (sin8(phase) + sin8(static_cast(phase * 2)) + + sin8(static_cast(phase * 3))) / 3); break; + default: v = valueNoise(phase); break; // Noise (type 5) + } + const lengthType y = static_cast((static_cast(v) * h) / 256); + return y < h ? y : static_cast(h - 1); + } + + // Triangle wave: 0→255 over the first half, 255→0 over the second (the textbook fold of a ramp). + static uint8_t triangle8(uint8_t x) { + return x < 128 ? static_cast(x * 2) + : static_cast((255 - x) * 2); + } + + // 1-D value noise from a small integer hash (the NoiseEffect hash, reduced to one axis) — a + // smoothly-varying pseudo-random byte, so the "Noise" wave jitters without being pure static. + static uint8_t valueNoise(uint8_t x) { + uint32_t hi = x >> 4, lo = x & 0x0F; // cell + fractional position + uint8_t a = hash(hi), b = hash(hi + 1); + return static_cast(a + ((static_cast(b) - a) * lo) / 16); // lerp between cells + } + static uint8_t hash(uint32_t n) { + n = (n << 13) ^ n; + return static_cast((n * (n * n * 15731u + 789221u) + 1376312589u) >> 24); + } + + // Write one pixel into the trail plane (bounds-checked; the join loop can reach any y). + void plot(lengthType x, lengthType y, const RGB& c, uint8_t cpl, lengthType w) { + if (x < 0 || y < 0 || x >= w) return; + const size_t off = (static_cast(y) * w + x) * cpl; + if (off + 2 >= trailBytes_) return; + trail_[off + 0] = c.r; + trail_[off + 1] = c.g; + trail_[off + 2] = c.b; + } + + void releaseTrail() { + if (trail_) { platform::free(trail_); trail_ = nullptr; } + trailBytes_ = 0; + } +}; + +} // namespace mm diff --git a/src/light/layers/Layer.h b/src/light/layers/Layer.h index 9d6019cc..376ca333 100644 --- a/src/light/layers/Layer.h +++ b/src/light/layers/Layer.h @@ -130,7 +130,7 @@ class Layer : public MoonModule { eff->loop(); // Extrude a lower-dimensional effect across the unused axes so a D1 // or D2 effect "just works" on a higher-dimensional grid. The effect - // only writes its own slice (D1 → row y=0,z=0; D2 → slice z=0); the + // only writes its own slice (D1 → column x=0,z=0; D2 → slice z=0); the // framework duplicates that across the rest of the buffer. extrude(eff->dimensions()); eff->addAccumUs(platform::micros() - start); @@ -228,14 +228,21 @@ class Layer : public MoonModule { const size_t rowBytes = static_cast(width_) * cpl; const size_t sliceBytes = rowBytes * height_; - // D1: the effect wrote row (y=0, z=0). Duplicate it across all y in z=0. - if (effectDim == Dim::D1 && height_ > 1) { - for (lengthType y = 1; y < height_; y++) { - std::memcpy(buf + y * rowBytes, buf, rowBytes); + // 1D runs along Y: a D1 effect wrote the (x=0) column down y in z=0. Duplicate that column + // across all x > 0, so a 1D effect expands into 2D by *adding columns to the right* — the + // 1D output is literally the first column of its 2D form (see architecture.md § + // Dimensionality). cpl bytes per pixel copied from the x=0 pixel of each row. + if (effectDim == Dim::D1 && width_ > 1) { + for (lengthType y = 0; y < height_; y++) { + const uint8_t* src = buf + static_cast(y) * rowBytes; // the x=0 pixel + for (lengthType x = 1; x < width_; x++) { + std::memcpy(buf + static_cast(y) * rowBytes + static_cast(x) * cpl, + src, cpl); + } } } - // D1 and D2: at this point z=0 holds a complete (possibly extruded) slice. - // Duplicate it across all z > 0. + // D1 and D2: z=0 now holds a complete (possibly extruded) slice — the (x,y) front face. + // Duplicate it across all z > 0, so a 2D effect expands into 3D by adding depth slices. if (depth_ > 1) { for (lengthType z = 1; z < depth_; z++) { std::memcpy(buf + z * sliceBytes, buf, sliceBytes); diff --git a/src/main.cpp b/src/main.cpp index 23483ea3..fb22e967 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "light/layouts/WheelLayout.h" #include "light/effects/LinesEffect.h" #include "light/effects/RainbowEffect.h" +#include "light/effects/WaveEffect.h" #include "light/effects/NoiseEffect.h" #include "light/effects/PlasmaEffect.h" #include "light/effects/PlasmaPaletteEffect.h" @@ -29,6 +30,7 @@ #include "light/modifiers/RandomMapModifier.h" #include "light/modifiers/RotateModifier.h" #include "light/modifiers/RegionModifier.h" +#include "light/drivers/HueDriver.h" #include "light/drivers/NetworkSendDriver.h" #include "light/drivers/PreviewDriver.h" // LED drivers are compiled in per chip, gated on the SOC peripheral the driver @@ -86,6 +88,7 @@ static void registerModuleTypes() { mm::ModuleFactory::registerType("WheelLayout", "light/layouts/WheelLayout.md"); mm::ModuleFactory::registerType("LinesEffect", "light/effects/LinesEffect.md"); mm::ModuleFactory::registerType("RainbowEffect", "light/effects/RainbowEffect.md"); + mm::ModuleFactory::registerType("WaveEffect", "light/effects/WaveEffect.md"); mm::ModuleFactory::registerType("NoiseEffect", "light/effects/NoiseEffect.md"); mm::ModuleFactory::registerType("PlasmaEffect", "light/effects/PlasmaEffect.md"); mm::ModuleFactory::registerType("PlasmaPaletteEffect", "light/effects/PlasmaPaletteEffect.md"); @@ -110,6 +113,7 @@ static void registerModuleTypes() { mm::ModuleFactory::registerType("RandomMapModifier", "light/modifiers/RandomMapModifier.md"); mm::ModuleFactory::registerType("RotateModifier", "light/modifiers/RotateModifier.md"); mm::ModuleFactory::registerType("RegionModifier", "light/modifiers/RegionModifier.md"); + mm::ModuleFactory::registerType("HueDriver", "light/drivers/HueDriver.md"); mm::ModuleFactory::registerType("NetworkSendDriver", "light/drivers/NetworkSendDriver.md"); mm::ModuleFactory::registerType("PreviewDriver", "light/drivers/PreviewDriver.md"); // Register only the LED drivers this chip's silicon can run (see the gated diff --git a/src/platform/desktop/platform_desktop.cpp b/src/platform/desktop/platform_desktop.cpp index 80b85783..e27609ae 100644 --- a/src/platform/desktop/platform_desktop.cpp +++ b/src/platform/desktop/platform_desktop.cpp @@ -479,6 +479,77 @@ bool http_fetch_to_ota(const char* /*url*/, return false; } +// Outbound HTTP request (plain HTTP, LAN, no TLS) — see platform.h. Blocking, bounded by a +// receive/send timeout. Builds the request into a stack buffer, connects, sends, reads the +// response, and returns the status code + the body (after the \r\n\r\n). Used by HueDriver +// off the render path. +int httpRequest(const char* method, const char* host, uint16_t port, const char* path, + const char* reqBody, uint32_t timeoutMs, char* body, size_t bodyLen) { + if (body && bodyLen) body[0] = '\0'; + if (!method || !host || !path) return 0; + + int fd = open_sock(AF_INET, SOCK_STREAM, 0); + if (fd < 0) return 0; + struct CloseGuard { int f; ~CloseGuard() { close_sock(f); } } guard{fd}; + + // Bound connect + recv with a timeout (same SO_RCVTIMEO/SO_SNDTIMEO shape the rest of the + // file uses); the socket stays blocking, so the bounded request is straightforward. +#ifdef _WIN32 + DWORD tv = timeoutMs; + ::setsockopt(sock(fd), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&tv), sizeof(tv)); + ::setsockopt(sock(fd), SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast(&tv), sizeof(tv)); +#else + timeval tv{}; + tv.tv_sec = static_cast(timeoutMs / 1000); + tv.tv_usec = static_cast((timeoutMs % 1000) * 1000); + ::setsockopt(sock(fd), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + ::setsockopt(sock(fd), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); +#endif + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) return 0; + if (::connect(sock(fd), reinterpret_cast(&addr), sizeof(addr)) != 0) return 0; + + char req[1024]; + const size_t blen = reqBody ? std::strlen(reqBody) : 0; + int n = blen + ? std::snprintf(req, sizeof(req), + "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n" + "Content-Type: application/json\r\nContent-Length: %zu\r\n\r\n%s", + method, path, host, blen, reqBody) + : std::snprintf(req, sizeof(req), + "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", + method, path, host); + if (n <= 0 || n >= static_cast(sizeof(req))) return 0; + if (::send(sock(fd), req, n, 0) != n) return 0; + + // Read the response. When the caller wants the body, read into THEIR buffer (so they size it + // — a Hue /lights body runs several KB) and shift the body to the front. When they don't + // (body==null, e.g. a fire-and-forget PUT), read into a small local scratch just far enough + // to get the status line — the request still executes. The status line + headers sit at the + // front of whatever we read. + char scratch[256]; + char* buf = body ? body : scratch; + const size_t cap = body ? bodyLen : sizeof(scratch); + if (cap < 16) return 0; + int total = 0; + while (total < static_cast(cap - 1)) { + auto r = ::recv(sock(fd), buf + total, cap - 1 - total, 0); + if (r > 0) total += static_cast(r); + else break; // closed or timeout + } + buf[total] = '\0'; + if (total < 12 || std::strncmp(buf, "HTTP/1.", 7) != 0) { if (body) body[0] = '\0'; return 0; } + int status = std::atoi(buf + 9); // "HTTP/1.1 NNN ..." + if (body) { + char* b = std::strstr(body, "\r\n\r\n"); + if (b) std::memmove(body, b + 4, std::strlen(b + 4) + 1); // drop headers, keep just the body + else body[0] = '\0'; + } + return status; +} + // Improv WiFi — no USB-serial path on desktop. The module gates with // `if constexpr (mm::platform::hasImprov)` and never calls this on desktop; diff --git a/src/platform/esp32/platform_esp32.cpp b/src/platform/esp32/platform_esp32.cpp index c2cea406..c1eb4c3f 100644 --- a/src/platform/esp32/platform_esp32.cpp +++ b/src/platform/esp32/platform_esp32.cpp @@ -1108,6 +1108,68 @@ void mdnsShutdown() { // service this device // also hosts destabilises our own advertise — see docs/history/decisions.md. +// Outbound HTTP request (plain HTTP, LAN, no TLS) — see platform.h. A bounded blocking lwIP +// socket call; the caller (HueDriver) runs it off the render path on loop1s. Mirrors the +// desktop impl: build request → connect → send → read response → return status + body. +int httpRequest(const char* method, const char* host, uint16_t port, const char* path, + const char* reqBody, uint32_t timeoutMs, char* body, size_t bodyLen) { + if (body && bodyLen) body[0] = '\0'; + if (!method || !host || !path) return 0; + + int fd = ::socket(AF_INET, SOCK_STREAM, 0); + if (fd < 0) return 0; + struct CloseGuard { int f; ~CloseGuard() { ::close(f); } } guard{fd}; + + timeval tv{}; + tv.tv_sec = static_cast(timeoutMs / 1000); + tv.tv_usec = static_cast((timeoutMs % 1000) * 1000); + setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) return 0; + if (::connect(fd, reinterpret_cast(&addr), sizeof(addr)) != 0) return 0; + + char req[1024]; + const size_t blen = reqBody ? std::strlen(reqBody) : 0; + int n = blen + ? std::snprintf(req, sizeof(req), + "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n" + "Content-Type: application/json\r\nContent-Length: %zu\r\n\r\n%s", + method, path, host, blen, reqBody) + : std::snprintf(req, sizeof(req), + "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", + method, path, host); + if (n <= 0 || n >= static_cast(sizeof(req))) return 0; + if (::send(fd, req, n, 0) != n) return 0; + + // Read the response. When the caller wants the body, read into THEIR buffer (so they size it + // — a Hue /lights body runs several KB) and shift the body to the front. When they don't + // (body==null, e.g. a fire-and-forget PUT), read into a small local scratch just far enough + // to get the status line — the request still executes. + char scratch[256]; + char* buf = body ? body : scratch; + const size_t cap = body ? bodyLen : sizeof(scratch); + if (cap < 16) return 0; + int total = 0; + while (total < static_cast(cap - 1)) { + int r = ::recv(fd, buf + total, cap - 1 - total, 0); + if (r > 0) total += r; + else break; // closed or timeout + } + buf[total] = '\0'; + if (total < 12 || std::strncmp(buf, "HTTP/1.", 7) != 0) { if (body) body[0] = '\0'; return 0; } + int status = std::atoi(buf + 9); // "HTTP/1.1 NNN ..." + if (body) { + char* b = std::strstr(body, "\r\n\r\n"); + if (b) std::memmove(body, b + 4, std::strlen(b + 4) + 1); // drop headers, keep just the body + else body[0] = '\0'; + } + return status; +} + // UdpSocket UdpSocket::~UdpSocket() { diff --git a/src/platform/platform.h b/src/platform/platform.h index ab7a4a26..beb27ea2 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -204,6 +204,16 @@ bool http_fetch_to_ota(const char* url, char* statusBuf, size_t statusBufLen, uint32_t* bytesReadOut, uint32_t* bytesTotalOut); +// Synchronous outbound HTTP request to a LAN host — plain HTTP, no TLS (the Philips Hue v1 +// API, which HueDriver drives, allows it). Connects to `host:port`, sends `method path` +// with `reqBody` (NUL-terminated; "" for none — a Content-Length + JSON content-type are +// added when non-empty), and copies the RESPONSE BODY into `body` (NUL-terminated, truncated +// to bodyLen-1). Returns the HTTP status code, or 0 on connect/timeout/error. Blocks up to +// `timeoutMs`. Caller runs this OFF the render hot path (HueDriver on loop1s, like the OTA +// fetch / the old mDNS browse). Built on raw sockets, same primitives as the HTTP server. +int httpRequest(const char* method, const char* host, uint16_t port, const char* path, + const char* reqBody, uint32_t timeoutMs, char* body, size_t bodyLen); + // Improv WiFi provisioning over UART0. // ESP32 only; desktop stub returns false. Spawns a FreeRTOS task that installs // a UART driver on UART_NUM_0 (the same channel ESP-IDF logging writes to; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f869a009..adf84cb4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,6 +10,7 @@ add_executable(mm_tests unit/core/unit_DeviceIdentify.cpp unit/core/unit_DevicesModule_ageout.cpp unit/core/unit_DevicesModule_discovery.cpp + unit/core/unit_DevicesModule_hue.cpp unit/core/unit_WledPacket.cpp unit/core/unit_FilesystemModule_persistence.cpp unit/core/unit_FirmwareUpdateModule.cpp @@ -49,6 +50,8 @@ add_executable(mm_tests unit/light/unit_Correction.cpp unit/light/unit_Drivers_container.cpp unit/light/unit_Drivers_firstOutputRgb.cpp + unit/light/unit_HueDriver.cpp + unit/light/unit_WaveEffect.cpp unit/light/unit_FireEffect.cpp unit/light/unit_GameOfLifeEffect.cpp unit/light/unit_GridLayout.cpp diff --git a/test/scenarios/light/scenario_perf_full.json b/test/scenarios/light/scenario_perf_full.json index 4a90216f..aa70b011 100644 --- a/test/scenarios/light/scenario_perf_full.json +++ b/test/scenarios/light/scenario_perf_full.json @@ -1596,7 +1596,7 @@ "observed": { "pc-macos": { "tick_us": [ - 305, + 298, 1093 ], "free_heap": [ @@ -1609,7 +1609,7 @@ ], "at": [ "2026-06-17", - "2026-06-28" + "2026-06-30" ] }, "esp32s3-n16r8": { @@ -1994,7 +1994,7 @@ }, "pc-macos": { "tick_us": [ - 62, + 61, 195 ], "free_heap": [ @@ -2007,7 +2007,7 @@ ], "at": [ "2026-06-17", - "2026-06-25" + "2026-06-30" ] }, "esp32": { diff --git a/test/unit/core/unit_DevicesModule_hue.cpp b/test/unit/core/unit_DevicesModule_hue.cpp new file mode 100644 index 00000000..909cce41 --- /dev/null +++ b/test/unit/core/unit_DevicesModule_hue.cpp @@ -0,0 +1,51 @@ +// @module DevicesModule + +// Pins the Hue-bridge listing: a HueDriver registers a bridge through upsertHueBridge() (the +// explicit, out-of-band entry — a bridge isn't a UDP-presence device), and DevicesModule lists +// it like any peer, carrying its colour-light count for layout sizing. Also pins the round +// trip through writeListRow / restoreList so a persisted bridge comes back as a Hue row. + +#include "doctest.h" +#include "core/DevicesModule.h" +#include "core/JsonSink.h" + +#include + +TEST_CASE("DevicesModule: a Hue bridge is listed with its colour count") { + mm::DevicesModule dev; + const uint8_t ip[4] = {192, 168, 1, 143}; + dev.upsertHueBridge(ip, "Hue Ewoud", 7); + + REQUIRE(dev.listRowCount() == 1); + mm::JsonSink sink; + dev.writeListRow(sink, 0); + const char* row = sink.data(); + CHECK(std::strstr(row, "\"name\":\"Hue Ewoud\"") != nullptr); + CHECK(std::strstr(row, "\"type\":\"Hue bridge\"") != nullptr); + CHECK(std::strstr(row, "\"colour\":7") != nullptr); +} + +TEST_CASE("DevicesModule: upsertHueBridge is idempotent, updates count in place") { + mm::DevicesModule dev; + const uint8_t ip[4] = {192, 168, 1, 143}; + dev.upsertHueBridge(ip, "Hue Ewoud", 7); + dev.upsertHueBridge(ip, "Hue Ewoud", 9); // same bridge, count changed + + REQUIRE(dev.listRowCount() == 1); // not a second row + mm::JsonSink sink; + dev.writeListRow(sink, 0); + CHECK(std::strstr(sink.data(), "\"colour\":9") != nullptr); +} + +TEST_CASE("DevicesModule: a persisted Hue bridge restores as a Hue row with its count") { + mm::DevicesModule dev; + // The shape writeListRow emits (the same JSON the List control persists). + const char* saved = + "{\"devices\":[{\"name\":\"Hue Ewoud\",\"ip\":\"192.168.1.143\",\"type\":\"Hue bridge\",\"colour\":7}]}"; + REQUIRE(dev.restoreList(saved, "devices")); + REQUIRE(dev.listRowCount() == 1); + mm::JsonSink sink; + dev.writeListRow(sink, 0); + CHECK(std::strstr(sink.data(), "\"type\":\"Hue bridge\"") != nullptr); + CHECK(std::strstr(sink.data(), "\"colour\":7") != nullptr); +} diff --git a/test/unit/light/unit_HueDriver.cpp b/test/unit/light/unit_HueDriver.cpp new file mode 100644 index 00000000..9469a324 --- /dev/null +++ b/test/unit/light/unit_HueDriver.cpp @@ -0,0 +1,65 @@ +// @module HueDriver + +// Pins HueDriver's host-testable core: the changed-only diff, the RGB→HSV colour body it PUTs, +// and the parse that keeps only colour-capable, reachable lights. Live bridge I/O (httpRequest, +// pairing) needs a real bridge — that's the bench; here the seams run with no socket. + +#include "doctest.h" +#include "light/drivers/HueDriver.h" + +#include +#include + +TEST_CASE("HueDriver: a coloured pixel becomes an on/bri/hue/sat state body") { + mm::HueDriver hue; + char body[80] = {}; + CHECK(hue.wouldPushForTest(0, 255, 0, 0, body, sizeof(body))); // pure red + CHECK(std::strstr(body, "\"on\":true") != nullptr); + CHECK(std::strstr(body, "\"bri\":254") != nullptr); // max value + CHECK(std::strstr(body, "\"hue\":") != nullptr); + CHECK(std::strstr(body, "\"sat\":254") != nullptr); // fully saturated +} + +TEST_CASE("HueDriver: a black pixel becomes on:false") { + mm::HueDriver hue; + char body[80] = {}; + CHECK(hue.wouldPushForTest(1, 0, 0, 0, body, sizeof(body))); + CHECK(std::strstr(body, "\"on\":false") != nullptr); + CHECK(std::strstr(body, "\"hue\"") == nullptr); // off → no colour fields +} + +TEST_CASE("HueDriver: RGB→HSV maps the primaries to the right Hue wheel positions") { + uint16_t h; uint8_t s, v; + mm::HueDriver::rgbToHsvForTest(255, 0, 0, h, s, v); // red → hue ~0 + CHECK(v == 254); CHECK(s == 254); + CHECK((h < 2000 || h > 63000)); // near the 0/65535 wrap + mm::HueDriver::rgbToHsvForTest(0, 255, 0, h, s, v); // green → ~1/3 of the wheel + CHECK(h > 65535 / 3 - 3000); CHECK(h < 65535 / 3 + 3000); + mm::HueDriver::rgbToHsvForTest(0, 0, 255, h, s, v); // blue → ~2/3 + CHECK(h > 65535 * 2 / 3 - 3000); CHECK(h < 65535 * 2 / 3 + 3000); + mm::HueDriver::rgbToHsvForTest(128, 128, 128, h, s, v); // grey → sat 0 + CHECK(s == 0); +} + +TEST_CASE("HueDriver: unchanged colour is not resent, a changed one is") { + mm::HueDriver hue; + char body[80] = {}; + CHECK(hue.wouldPushForTest(2, 10, 20, 30, body, sizeof(body))); // first → yes + CHECK_FALSE(hue.wouldPushForTest(2, 10, 20, 30, body, sizeof(body))); // same → skip + CHECK(hue.wouldPushForTest(2, 10, 20, 31, body, sizeof(body))); // changed → yes +} + +TEST_CASE("HueDriver: parseLights keeps only colour-capable, reachable lights") { + mm::HueDriver hue; + // id 5 colour + reachable (keep); id 7 dimmable-only white (drop); id 10 on/off plug (drop); + // id 8 colour but UNREACHABLE (drop). The shapes the real bridge returns. + const char* json = + "{\"5\":{\"state\":{\"on\":false,\"bri\":77,\"hue\":8595,\"sat\":121,\"reachable\":true},\"name\":\"Bureau lamp\"}," + "\"7\":{\"state\":{\"on\":true,\"bri\":40,\"reachable\":true},\"name\":\"Gang lamp\"}," + "\"10\":{\"state\":{\"on\":true,\"reachable\":true},\"name\":\"Bureau\"}," + "\"8\":{\"state\":{\"on\":false,\"bri\":1,\"hue\":0,\"sat\":0,\"reachable\":false},\"name\":\"Nachtkastje\"}}"; + hue.parseLightsForTest(json); + REQUIRE(hue.lightCountForTest() == 1); // only id 5 qualifies + CHECK(hue.hueIdForTest(0) == 5); + CHECK(hue.colourCountForTest() == 1); +} diff --git a/test/unit/light/unit_Layer_extrude.cpp b/test/unit/light/unit_Layer_extrude.cpp index 9dd0fb63..88a7db8a 100644 --- a/test/unit/light/unit_Layer_extrude.cpp +++ b/test/unit/light/unit_Layer_extrude.cpp @@ -12,10 +12,10 @@ #include "light/effects/ParticlesEffect.h" // Layer::extrude lets a low-dimensional effect "just work" on a higher-dimensional -// grid: the effect writes only its own slice (D2 → z=0 plane; D1 → row at y=0,z=0) +// grid: the effect writes only its own slice (D2 → z=0 plane; D1 → column at x=0,z=0) // and Layer copies that slice across the unused axes. These tests pin the // behaviour so a D2 effect on a 3D grid produces identical z-slices, and a -// hypothetical D1 effect produces identical rows and slices. +// hypothetical D1 effect (1D runs along Y) produces identical columns and slices. // // A separate group of tests covers the other direction: a D3 effect run on a // 2D or 1D layer. EffectBase's contract says the effect must honour the layer's @@ -59,28 +59,29 @@ TEST_CASE("D2 effect on 3D grid: z-slices are identical (Layer::extrude)") { } } -// A D1 stub: writes a gradient along x in row (y=0, z=0) and nothing else. The -// effect doesn't actually iterate y/z — extrude is expected to do it. Keeps the -// test independent of any specific D1 production effect (none exist today; this -// pins the framework contract). +// A D1 stub: 1D runs along Y, so it writes a gradient down the (x=0) column and +// nothing else. The effect doesn't iterate x/z — extrude is expected to spread the +// column across x (then across z). Keeps the test independent of any specific D1 +// production effect (none exist today; this pins the framework contract). class D1StubEffect : public mm::EffectBase { public: mm::Dim dimensions() const override { return mm::Dim::D1; } void loop() override { uint8_t* buf = buffer(); mm::lengthType w = width(); + mm::lengthType h = height(); uint8_t cpl = channelsPerLight(); - for (mm::lengthType x = 0; x < w; x++) { - size_t offset = static_cast(x) * cpl; - buf[offset + 0] = static_cast(x * 4); - buf[offset + 1] = static_cast(255 - x * 4); + for (mm::lengthType y = 0; y < h; y++) { + size_t offset = static_cast(y) * w * cpl; // the x=0 pixel of row y + buf[offset + 0] = static_cast(y * 4); + buf[offset + 1] = static_cast(255 - y * 4); buf[offset + 2] = 128; } } }; -// A D1 effect writes row y=0,z=0; extrude duplicates that row across every y and every z-slice. -TEST_CASE("D1 effect on 3D grid: rows and z-slices are identical (Layer::extrude)") { +// A D1 effect writes the x=0 column; extrude duplicates it across every x and every z-slice. +TEST_CASE("D1 effect on 3D grid: columns and z-slices are identical (Layer::extrude)") { mm::Layouts layouts; mm::GridLayout grid; grid.width = 8; @@ -99,15 +100,16 @@ TEST_CASE("D1 effect on 3D grid: rows and z-slices are identical (Layer::extrude layer.loop(); auto* data = layer.buffer().data(); - const size_t rowBytes = static_cast(grid.width) * 3; + const size_t cpl = 3; + const size_t rowBytes = static_cast(grid.width) * cpl; const size_t sliceBytes = rowBytes * grid.height; - // Within z=0: every y>0 row equals y=0 row. - for (mm::lengthType y = 1; y < grid.height; y++) { - const uint8_t* y0 = data; - const uint8_t* yn = data + y * rowBytes; - for (size_t i = 0; i < rowBytes; i++) { - REQUIRE(yn[i] == y0[i]); + // Within z=0: in every row, each x>0 pixel equals the x=0 pixel (column spread across x). + for (mm::lengthType y = 0; y < grid.height; y++) { + const uint8_t* x0 = data + static_cast(y) * rowBytes; // the x=0 pixel + for (mm::lengthType x = 1; x < grid.width; x++) { + const uint8_t* xn = x0 + static_cast(x) * cpl; + for (size_t c = 0; c < cpl; c++) REQUIRE(xn[c] == x0[c]); } } diff --git a/test/unit/light/unit_WaveEffect.cpp b/test/unit/light/unit_WaveEffect.cpp new file mode 100644 index 00000000..fd561997 --- /dev/null +++ b/test/unit/light/unit_WaveEffect.cpp @@ -0,0 +1,57 @@ +// @module WaveEffect + +// Pins WaveEffect's pure waveform map (phase → y) for each of the six shapes — the behaviour +// that defines the effect. The animation/trail/colour need a Layer + buffer (covered by the +// scenario run); here we drive waveYForTest directly, no grid. + +#include "doctest.h" +#include "light/effects/WaveEffect.h" + +using mm::lengthType; + +TEST_CASE("WaveEffect: sawtooth ramps 0→top across the phase") { + const lengthType h = 16; + CHECK(mm::WaveEffect::waveYForTest(0, 0, h) == 0); // phase 0 → bottom + CHECK(mm::WaveEffect::waveYForTest(0, 255, h) == h - 1); // phase max → top + // Monotonic non-decreasing across the ramp. + lengthType prev = 0; + for (int p = 0; p <= 255; p += 17) { + lengthType y = mm::WaveEffect::waveYForTest(0, static_cast(p), h); + CHECK(y >= prev); + prev = y; + } +} + +TEST_CASE("WaveEffect: triangle peaks in the middle and returns") { + const lengthType h = 16; + CHECK(mm::WaveEffect::waveYForTest(1, 0, h) == 0); + CHECK(mm::WaveEffect::waveYForTest(1, 128, h) >= h - 1); // mid-phase → top + CHECK(mm::WaveEffect::waveYForTest(1, 255, h) <= 1); // back near the bottom +} + +TEST_CASE("WaveEffect: sine sits mid at the zero crossings") { + const lengthType h = 16; + // sin8(0) = 128 → middle of the grid. + CHECK(mm::WaveEffect::waveYForTest(2, 0, h) == (128 * h) / 256); +} + +TEST_CASE("WaveEffect: square is low then high") { + const lengthType h = 16; + CHECK(mm::WaveEffect::waveYForTest(3, 0, h) == 0); // low half → bottom + CHECK(mm::WaveEffect::waveYForTest(3, 200, h) == h - 1); // high half → top +} + +TEST_CASE("WaveEffect: every type stays within the grid bounds") { + for (uint8_t type = 0; type < mm::WaveEffect::kTypeCount; type++) { + for (int p = 0; p <= 255; p++) { + const lengthType h = 8; + lengthType y = mm::WaveEffect::waveYForTest(type, static_cast(p), h); + CHECK(y >= 0); + CHECK(y < h); + } + } +} + +TEST_CASE("WaveEffect: a zero-height grid never reads out of bounds") { + CHECK(mm::WaveEffect::waveYForTest(2, 100, 0) == 0); +} From 2b1d44387bcbd59a4478fbc0fef037d06fa92790 Mon Sep 17 00:00:00 2001 From: ewowi Date: Tue, 30 Jun 2026 13:27:21 +0200 Subject: [PATCH 02/11] Process CodeRabbit review; reorganise assets; stage MoonLight migration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three threads land together. CodeRabbit's review of the HueDriver/WaveEffect work is processed (real fixes + skips with reasons). The docs/assets tree is reorganised flat-by-type (effects/modifiers/layouts/drivers) so it matches src and stops being a 63-file flat folder. And the MoonLight effect/modifier/layout migration is staged as a multi-stage plan plus its decided foundations (palette design, folder structure, tags legend, effect inventory) — design only, no migration code yet. PC worst-scenario tick:448us; ESP32 tick:907us(FPS:1102). Core - DevicesModule: clamp a persisted Hue colour-count to 0–127 before narrowing, so a corrupt/hand-edited device entry can't wrap into a bogus value on restore. - platform httpRequest (desktop + esp32): send the request in a loop until all bytes are out (a blocking send can return short under backpressure); and bound the TCP connect by timeoutMs via a non-blocking connect + select, so an unreachable host can't stall the caller past the deadline (re-added the desktop make_blocking helper the connect path needs). Light domain - HueDriver: clear the learned light list + push cache when bridgeIp or appKey changes, so the driver re-fetches against the new bridge instead of using stale discovery data. - light_types.h / WaveEffect: comments corrected to the 1D-runs-along-Y extrude convention and present tense. Scripts / MoonDeck - screenshot_modules.py / update_module_docs.py: write/read module assets under the new docs/assets/{core,light/{effects,modifiers,layouts,drivers},ui}/ structure (an asset_dir_for(type) map) instead of the flat screenshots/ folder. Tests - unit_DevicesModule_hue: a case pinning that a corrupt persisted colour value (negative / overflow) clamps to 0–127 and the Hue row still restores. Docs / CI - assets: moved all 63 screenshots/gifs into docs/assets/{core, light/{effects,modifiers,layouts,drivers}, ui}/ by module type; repointed every doc image reference (82 local refs verified resolving), leaving the v1.0.0 tag-pinned URLs on their historical path. - architecture.md: added the canonical tag-emoji legend (MoonLight basis — role/dim/origin/creator/audio) and corrected the 1D-along-Y extrude wording. - README: credited FastLED as the prior art behind the recognisable colour/animation primitive names + the gradient-palette model (names carried, implementation ours, no FastLED dependency). - Migration plan (docs/history/plans): the multi-stage MoonLight migration map; linked bidirectionally with the rename plan's effect-parity gate. - References: moonlight-effect-inventory.md (47 effects by origin) and moonlight-palettes-data.md (~54 gradient palettes + the decided palette design: a 16-entry CRGBPalette16-model lookup, global active palette on Drivers via Palettes::active(), MoonLive-authored dynamic palettes as a MoonLivePalette type, hard-swap now / crossfade backlogged). - folder-structure-proposal.md: the domain/type folder decision (library is a tag + a per-library doc-page split, not a folder). - backlog: LightsControl + light-presets items (the global-control hub MoonLight has; pragmatic interim on Drivers); the HueDriver plan marked (shipped). Reviews - 🐇 Persisted Hue colour-count can wrap when narrowed — fixed (clamp + test). - 🐇 HueDriver keeps stale bridge/light state on a bridgeIp/appKey change — fixed (cache reset). - 🐇 platform send() can truncate under backpressure — fixed (send loop, both platforms). - 🐇 connect() not bounded by timeoutMs — fixed (non-blocking connect + select, both platforms). - 🐇 Backlog/spec wording (dimmable→colour, WaveEffect present tense, HueDriver plan (shipped)) — fixed. - 🐇 Remove the Dim::D1 extrude path ("effects must be 2D") — SKIPPED: D1 is a supported, documented dimension deliberately added this branch (1D-runs-along-Y, verified against MoonLight's own 1D effects); no such rule exists. Fixed the one genuinely stale D1 comment instead. - 🐇 WaveEffect should use micros() for phase + init lastElapsed_ — SKIPPED: elapsed()/millis with lastElapsed_=0 is the project-wide pattern (10+ effects); changing one effect breaks that consistency and the first-frame effect is nil on a wrapping uint8 phase. - 🐇 Generalise upsertHueBridge/colourCount to a domain-neutral external-device shape — SKIPPED (concrete-first): one consumer today; DevType + the active() static seam are already neutral; generalise when a second foreign device exists. - 🐇 Move the HueDriver PUT off the render loop to a worker thread — SKIPPED: the millis-gated single bounded PUT is the deliberate design (built + bench-debugged with the product owner); a worker thread is deferred infrastructure, rationale in the code comment. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 7 +- docs/architecture.md | 16 ++- .../{screenshots => core}/Devices module.png | Bin .../FilesystemModule.png | Bin .../FirmwareUpdateModule.png | Bin .../Hue device disco.png | Bin docs/assets/{screenshots => core}/Layers.png | Bin docs/assets/{screenshots => core}/Layouts.png | Bin .../{screenshots => core}/NetworkModule.png | Bin .../{screenshots => core}/SystemModule.png | Bin .../WLED Native discovers projectMM.jpeg | Bin .../Wled discovers projectMM.png | Bin .../drivers}/Drivers.png | Bin .../drivers}/Hue driver.png | Bin .../drivers}/Hue friendly effect.png | Bin .../drivers}/NetworkSendDriver.png | Bin .../drivers}/PreviewDriver.png | Bin .../effects}/CheckerboardEffect.gif | Bin .../effects}/CheckerboardEffect.png | Bin .../effects}/FireEffect.gif | Bin .../effects}/FireEffect.png | Bin .../effects}/GameOfLifeEffect.gif | Bin .../effects}/GameOfLifeEffect.png | Bin .../effects}/GlowParticlesEffect.gif | Bin .../effects}/GlowParticlesEffect.png | Bin .../effects}/LavaLampEffect.gif | Bin .../effects}/LavaLampEffect.png | Bin .../effects}/LinesEffect.gif | Bin .../effects}/LinesEffect.png | Bin .../effects}/MetaballsEffect.gif | Bin .../effects}/MetaballsEffect.png | Bin .../effects}/NoiseEffect.gif | Bin .../effects}/NoiseEffect.png | Bin .../effects}/ParticlesEffect.gif | Bin .../effects}/ParticlesEffect.png | Bin .../effects}/PlasmaEffect.gif | Bin .../effects}/PlasmaEffect.png | Bin .../effects}/PlasmaPaletteEffect.gif | Bin .../effects}/PlasmaPaletteEffect.png | Bin .../effects}/RainbowEffect.gif | Bin .../effects}/RainbowEffect.png | Bin .../effects}/RingsEffect.gif | Bin .../effects}/RingsEffect.png | Bin .../effects}/RipplesEffect.gif | Bin .../effects}/RipplesEffect.png | Bin .../effects}/SpiralEffect.gif | Bin .../effects}/SpiralEffect.png | Bin .../layouts}/GridLayout.png | Bin .../modifiers}/CheckerboardModifier.gif | Bin .../modifiers}/CheckerboardModifier.png | Bin .../modifiers}/MirrorModifier.gif | Bin .../modifiers}/MirrorModifier.png | Bin .../modifiers}/MultiplyModifier.gif | Bin .../modifiers}/MultiplyModifier.png | Bin .../installer-board-picker-collapsed.png | Bin .../installer-board-picker-expanded.png | Bin docs/assets/{screenshots => ui}/installer.png | Bin .../assets/{screenshots => ui}/installer2.png | Bin .../assets/{screenshots => ui}/installer3.png | Bin .../{screenshots => ui}/moondeck_esp32.png | Bin .../{screenshots => ui}/moondeck_live.png | Bin .../{screenshots => ui}/moondeck_pc.png | Bin docs/assets/{screenshots => ui}/ui_light.png | Bin .../{screenshots => ui}/ui_overview.png | Bin docs/assets/{screenshots => ui}/ui_theme.gif | Bin docs/backlog/backlog-core.md | 2 +- docs/backlog/backlog-mixed.md | 12 ++ docs/backlog/folder-structure-proposal.md | 99 +++++++++++++++++ docs/backlog/moonlight-effect-inventory.md | 69 ++++++++++++ docs/backlog/moonlight-palettes-data.md | 91 ++++++++++++++++ docs/backlog/rename-to-moonlight.md | 2 +- docs/building.md | 4 +- ... lights as an effect output) (shipped).md} | 2 +- ...630 - MoonLight migration (multi-stage).md | 103 ++++++++++++++++++ docs/install/README.md | 2 +- docs/moonmodules/core/DevicesModule.md | 6 +- docs/moonmodules/core/FilesystemModule.md | 2 +- docs/moonmodules/core/FirmwareUpdateModule.md | 2 +- docs/moonmodules/core/NetworkModule.md | 2 +- docs/moonmodules/core/SystemModule.md | 2 +- docs/moonmodules/light/Drivers.md | 2 +- docs/moonmodules/light/Layers.md | 2 +- docs/moonmodules/light/Layouts.md | 2 +- docs/moonmodules/light/drivers/HueDriver.md | 6 +- .../light/drivers/NetworkSendDriver.md | 2 +- .../light/drivers/PreviewDriver.md | 2 +- .../light/effects/CheckerboardEffect.md | 4 +- docs/moonmodules/light/effects/FireEffect.md | 4 +- .../light/effects/GameOfLifeEffect.md | 4 +- .../light/effects/GlowParticlesEffect.md | 4 +- .../light/effects/LavaLampEffect.md | 4 +- docs/moonmodules/light/effects/LinesEffect.md | 4 +- .../light/effects/MetaballsEffect.md | 4 +- docs/moonmodules/light/effects/NoiseEffect.md | 4 +- .../light/effects/ParticlesEffect.md | 4 +- .../moonmodules/light/effects/PlasmaEffect.md | 4 +- .../light/effects/PlasmaPaletteEffect.md | 4 +- .../light/effects/RainbowEffect.md | 4 +- docs/moonmodules/light/effects/RingsEffect.md | 4 +- .../light/effects/RipplesEffect.md | 4 +- .../moonmodules/light/effects/SpiralEffect.md | 4 +- docs/moonmodules/light/effects/WaveEffect.md | 4 +- docs/moonmodules/light/layouts/GridLayout.md | 2 +- .../light/modifiers/CheckerboardModifier.md | 4 +- .../light/modifiers/MultiplyModifier.md | 4 +- docs/testing.md | 2 +- scripts/MoonDeck.md | 18 +-- scripts/docs/screenshot_modules.py | 50 +++++---- scripts/docs/update_module_docs.py | 36 +++--- src/core/DevicesModule.h | 7 +- src/light/drivers/HueDriver.h | 16 ++- src/light/effects/WaveEffect.h | 2 +- src/light/light_types.h | 2 +- src/platform/desktop/platform_desktop.cpp | 56 ++++++++-- src/platform/esp32/platform_esp32.cpp | 40 +++++-- test/unit/core/unit_DevicesModule_hue.cpp | 24 ++++ 116 files changed, 642 insertions(+), 124 deletions(-) rename docs/assets/{screenshots => core}/Devices module.png (100%) rename docs/assets/{screenshots => core}/FilesystemModule.png (100%) rename docs/assets/{screenshots => core}/FirmwareUpdateModule.png (100%) rename docs/assets/{screenshots => core}/Hue device disco.png (100%) rename docs/assets/{screenshots => core}/Layers.png (100%) rename docs/assets/{screenshots => core}/Layouts.png (100%) rename docs/assets/{screenshots => core}/NetworkModule.png (100%) rename docs/assets/{screenshots => core}/SystemModule.png (100%) rename docs/assets/{screenshots => core}/WLED Native discovers projectMM.jpeg (100%) rename docs/assets/{screenshots => core}/Wled discovers projectMM.png (100%) rename docs/assets/{screenshots => light/drivers}/Drivers.png (100%) rename docs/assets/{screenshots => light/drivers}/Hue driver.png (100%) rename docs/assets/{screenshots => light/drivers}/Hue friendly effect.png (100%) rename docs/assets/{screenshots => light/drivers}/NetworkSendDriver.png (100%) rename docs/assets/{screenshots => light/drivers}/PreviewDriver.png (100%) rename docs/assets/{screenshots => light/effects}/CheckerboardEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/CheckerboardEffect.png (100%) rename docs/assets/{screenshots => light/effects}/FireEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/FireEffect.png (100%) rename docs/assets/{screenshots => light/effects}/GameOfLifeEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/GameOfLifeEffect.png (100%) rename docs/assets/{screenshots => light/effects}/GlowParticlesEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/GlowParticlesEffect.png (100%) rename docs/assets/{screenshots => light/effects}/LavaLampEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/LavaLampEffect.png (100%) rename docs/assets/{screenshots => light/effects}/LinesEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/LinesEffect.png (100%) rename docs/assets/{screenshots => light/effects}/MetaballsEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/MetaballsEffect.png (100%) rename docs/assets/{screenshots => light/effects}/NoiseEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/NoiseEffect.png (100%) rename docs/assets/{screenshots => light/effects}/ParticlesEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/ParticlesEffect.png (100%) rename docs/assets/{screenshots => light/effects}/PlasmaEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/PlasmaEffect.png (100%) rename docs/assets/{screenshots => light/effects}/PlasmaPaletteEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/PlasmaPaletteEffect.png (100%) rename docs/assets/{screenshots => light/effects}/RainbowEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/RainbowEffect.png (100%) rename docs/assets/{screenshots => light/effects}/RingsEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/RingsEffect.png (100%) rename docs/assets/{screenshots => light/effects}/RipplesEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/RipplesEffect.png (100%) rename docs/assets/{screenshots => light/effects}/SpiralEffect.gif (100%) rename docs/assets/{screenshots => light/effects}/SpiralEffect.png (100%) rename docs/assets/{screenshots => light/layouts}/GridLayout.png (100%) rename docs/assets/{screenshots => light/modifiers}/CheckerboardModifier.gif (100%) rename docs/assets/{screenshots => light/modifiers}/CheckerboardModifier.png (100%) rename docs/assets/{screenshots => light/modifiers}/MirrorModifier.gif (100%) rename docs/assets/{screenshots => light/modifiers}/MirrorModifier.png (100%) rename docs/assets/{screenshots => light/modifiers}/MultiplyModifier.gif (100%) rename docs/assets/{screenshots => light/modifiers}/MultiplyModifier.png (100%) rename docs/assets/{screenshots => ui}/installer-board-picker-collapsed.png (100%) rename docs/assets/{screenshots => ui}/installer-board-picker-expanded.png (100%) rename docs/assets/{screenshots => ui}/installer.png (100%) rename docs/assets/{screenshots => ui}/installer2.png (100%) rename docs/assets/{screenshots => ui}/installer3.png (100%) rename docs/assets/{screenshots => ui}/moondeck_esp32.png (100%) rename docs/assets/{screenshots => ui}/moondeck_live.png (100%) rename docs/assets/{screenshots => ui}/moondeck_pc.png (100%) rename docs/assets/{screenshots => ui}/ui_light.png (100%) rename docs/assets/{screenshots => ui}/ui_overview.png (100%) rename docs/assets/{screenshots => ui}/ui_theme.gif (100%) create mode 100644 docs/backlog/folder-structure-proposal.md create mode 100644 docs/backlog/moonlight-effect-inventory.md create mode 100644 docs/backlog/moonlight-palettes-data.md rename docs/history/plans/{Plan-20260630 - HueDriver (Hue lights as an effect output).md => Plan-20260630 - HueDriver (Hue lights as an effect output) (shipped).md} (99%) create mode 100644 docs/history/plans/Plan-20260630 - MoonLight migration (multi-stage).md diff --git a/README.md b/README.md index 96eb1a9f..50550342 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Drive large LED installations and DMX lighting from ESP32, Teensy, Raspberry Pi, Windows, macOS or Linux desktop. One source tree, multiple targets. -![Web UI](docs/assets/screenshots/ui_theme.gif) +![Web UI](docs/assets/ui/ui_theme.gif) 👉 **Try it now:** flash an ESP32 straight from your browser → — step-by-step in the [Getting started guide](docs/gettingstarted.md). @@ -90,7 +90,7 @@ The numbers above are observations. The **contracts** projectMM commits to, what **ESP32: flash from your browser.** Open the [web installer](https://moonmodules.org/projectMM/install/) in Chrome or Edge; it walks you through release, device and firmware selection, flashing, and network setup. The installer lists stable releases and a `latest` build (published automatically on every merge to main) carrying the newest unreleased changes. -![Installer](docs/assets/screenshots/installer.png) +![Installer](docs/assets/ui/installer.png) **Desktop: download and run.** Grab the build for your OS from the [releases page](https://github.com/MoonModules/projectMM/releases): @@ -113,7 +113,7 @@ uv run scripts/moondeck.py Open `http://localhost:8420`: PC tab to build / run / test, ESP32 tab to flash, Live tab to discover devices. Full per-command reference: [scripts/MoonDeck.md](scripts/MoonDeck.md). -![Moondeck Pc](docs/assets/screenshots/moondeck_pc.png) +![Moondeck Pc](docs/assets/ui/moondeck_pc.png) ## Documentation @@ -165,6 +165,7 @@ Specific people whose work directly shaped parts of projectMM. We study their th - **[hpwit](https://github.com/hpwit) (Yves Bazin)** — the clockless I2S / RMT / Parlio LED-driver techniques and the [ESPLiveScript](https://github.com/hpwit/ESPLiveScript) live-script engine behind the LED drivers and MoonLive. - **Christophe Gagnier ([@Moustachauve](https://github.com/Moustachauve))** — author of the native [WLED-Android](https://github.com/Moustachauve/WLED-Android) app. Its source let us reverse-engineer exactly what the WLED app reads, so projectMM devices appear in (and are controllable from) the native WLED apps. - **The [Improv Wi-Fi](https://github.com/improv-wifi) project** — the open Improv serial provisioning standard ([sdk-cpp](https://github.com/improv-wifi/sdk-cpp) / [sdk-js](https://github.com/improv-wifi/sdk-js)) that the projectMM web installer uses to provision a freshly-flashed device over USB. +- **[FastLED](https://github.com/FastLED/FastLED)** — the canonical LED-effects library whose conventions the LED-effect world shares. projectMM links no part of FastLED, but it carries forward FastLED's recognisable *names and models* for the colour/animation primitives — `scale8`, `sin8`, the gradient-palette model (`CRGBPalette16` / `colorFromPalette`), the `beatsin8` / `inoise8` / `qadd8` family — so a contributor recognises them on sight. The implementations are projectMM's own, integer-only and hot-path-tuned for our render loop; FastLED is the prior art behind the convention, credited here and in each primitive's notes. ## Contributing diff --git a/docs/architecture.md b/docs/architecture.md index 933ca244..9bb4688d 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -522,7 +522,7 @@ How lighting uses the core [multi-device runtime](#multi-device-runtime) (discov # Web UI -![UI overview](assets/screenshots/ui_overview.png) +![UI overview](assets/ui/ui_overview.png) The UI is a handful of hand-maintained files: `index.html`, `app.js`, `style.css`, plus two focused ES modules `app.js` imports (`preview3d.js` for the WebGL 3D preview, `install-picker.js` shared with the web installer). No frameworks, no build tools, no npm. Served directly by the embedded HTTP server. @@ -536,6 +536,20 @@ Adding a new MoonModule with controls needs **zero changes** to the UI files. Th The light domain plugs into the UI at three points: a fixed top-level tree (Layouts / Layers / Drivers pinned in `main.cpp`, root reorder disabled while child reorder works via drag-and-drop), a binary WebSocket preview channel ([PreviewDriver](moonmodules/light/drivers/PreviewDriver.md): a `0x03` coordinate table sent once per LUT rebuild plus per-frame `0x02` RGB point lists, so sparse layouts preview at their real positions), and per-role emoji for the chip filter (the `ROLE_EMOJI` map in `app.js` is the single source of truth: `effect`, `driver`, …, `peripheral`). Full UI spec: [docs/moonmodules/core/ui.md](moonmodules/core/ui.md). +#### Tag emoji legend + +A module's chips come from three sources, rendered identically on the card and the type picker: a **role** chip (UI-derived from `role`), a **dimensional** chip (UI-derived from `dim`), and the curated **`tags()`** string (a flash literal the module returns; the UI splits it into grapheme clusters, one chip each). Role and dim are *not* repeated in `tags()` — only the categories below are. The legend takes [MoonLight](https://github.com/MoonModules/MoonLight)'s set as the canonical basis: + +| Category | Emoji | Meaning | +|---|---|---| +| **Role** (UI-derived) | 🔥 effect · 💎 modifier · 📐 layout · 🔌 driver · ⚙️ peripheral | what kind of module (from `role`, via `ROLE_EMOJI`) | +| **Dimensionality** (UI-derived) | 📏 1D · 🟦 2D · 🧊 3D | native axes (from `dim`) | +| **Origin / library** (`tags()`) | 💫 MoonLight · 🌊 WLED · *(projectMM-native: none — the default)* | which library the module came from; the [migration](../backlog/moonlight-effect-inventory.md) files docs by this, the emoji filters by it | +| **Creator** (`tags()`) | 🦅 a named contributor (credited at the introduction site) | individual authorship credit | +| **Audio** (`tags()`) | 🔊 audio-reactive | reads `AudioModule::latestFrame()` | + +`tags()` carries **only** origin + creator + audio (+ any genuinely module-specific marker); a module can carry several (e.g. `💫🦅` = MoonLight origin, a named creator). Role and dim are added by the UI, so a module never duplicates them in its string. When migrating, set each module's `tags()` from this legend so the chip set is consistent across the library. + ## What we leave undesigned Genuinely open questions, *not* the same as a 🚧 marker. A 🚧 item has a settled, committed design (two-core handover, clock sync, device-to-device light distribution) — code is written toward it; the items here are ones where the *design itself* is still open, deferred until a concrete need forces the decision: diff --git a/docs/assets/screenshots/Devices module.png b/docs/assets/core/Devices module.png similarity index 100% rename from docs/assets/screenshots/Devices module.png rename to docs/assets/core/Devices module.png diff --git a/docs/assets/screenshots/FilesystemModule.png b/docs/assets/core/FilesystemModule.png similarity index 100% rename from docs/assets/screenshots/FilesystemModule.png rename to docs/assets/core/FilesystemModule.png diff --git a/docs/assets/screenshots/FirmwareUpdateModule.png b/docs/assets/core/FirmwareUpdateModule.png similarity index 100% rename from docs/assets/screenshots/FirmwareUpdateModule.png rename to docs/assets/core/FirmwareUpdateModule.png diff --git a/docs/assets/screenshots/Hue device disco.png b/docs/assets/core/Hue device disco.png similarity index 100% rename from docs/assets/screenshots/Hue device disco.png rename to docs/assets/core/Hue device disco.png diff --git a/docs/assets/screenshots/Layers.png b/docs/assets/core/Layers.png similarity index 100% rename from docs/assets/screenshots/Layers.png rename to docs/assets/core/Layers.png diff --git a/docs/assets/screenshots/Layouts.png b/docs/assets/core/Layouts.png similarity index 100% rename from docs/assets/screenshots/Layouts.png rename to docs/assets/core/Layouts.png diff --git a/docs/assets/screenshots/NetworkModule.png b/docs/assets/core/NetworkModule.png similarity index 100% rename from docs/assets/screenshots/NetworkModule.png rename to docs/assets/core/NetworkModule.png diff --git a/docs/assets/screenshots/SystemModule.png b/docs/assets/core/SystemModule.png similarity index 100% rename from docs/assets/screenshots/SystemModule.png rename to docs/assets/core/SystemModule.png diff --git a/docs/assets/screenshots/WLED Native discovers projectMM.jpeg b/docs/assets/core/WLED Native discovers projectMM.jpeg similarity index 100% rename from docs/assets/screenshots/WLED Native discovers projectMM.jpeg rename to docs/assets/core/WLED Native discovers projectMM.jpeg diff --git a/docs/assets/screenshots/Wled discovers projectMM.png b/docs/assets/core/Wled discovers projectMM.png similarity index 100% rename from docs/assets/screenshots/Wled discovers projectMM.png rename to docs/assets/core/Wled discovers projectMM.png diff --git a/docs/assets/screenshots/Drivers.png b/docs/assets/light/drivers/Drivers.png similarity index 100% rename from docs/assets/screenshots/Drivers.png rename to docs/assets/light/drivers/Drivers.png diff --git a/docs/assets/screenshots/Hue driver.png b/docs/assets/light/drivers/Hue driver.png similarity index 100% rename from docs/assets/screenshots/Hue driver.png rename to docs/assets/light/drivers/Hue driver.png diff --git a/docs/assets/screenshots/Hue friendly effect.png b/docs/assets/light/drivers/Hue friendly effect.png similarity index 100% rename from docs/assets/screenshots/Hue friendly effect.png rename to docs/assets/light/drivers/Hue friendly effect.png diff --git a/docs/assets/screenshots/NetworkSendDriver.png b/docs/assets/light/drivers/NetworkSendDriver.png similarity index 100% rename from docs/assets/screenshots/NetworkSendDriver.png rename to docs/assets/light/drivers/NetworkSendDriver.png diff --git a/docs/assets/screenshots/PreviewDriver.png b/docs/assets/light/drivers/PreviewDriver.png similarity index 100% rename from docs/assets/screenshots/PreviewDriver.png rename to docs/assets/light/drivers/PreviewDriver.png diff --git a/docs/assets/screenshots/CheckerboardEffect.gif b/docs/assets/light/effects/CheckerboardEffect.gif similarity index 100% rename from docs/assets/screenshots/CheckerboardEffect.gif rename to docs/assets/light/effects/CheckerboardEffect.gif diff --git a/docs/assets/screenshots/CheckerboardEffect.png b/docs/assets/light/effects/CheckerboardEffect.png similarity index 100% rename from docs/assets/screenshots/CheckerboardEffect.png rename to docs/assets/light/effects/CheckerboardEffect.png diff --git a/docs/assets/screenshots/FireEffect.gif b/docs/assets/light/effects/FireEffect.gif similarity index 100% rename from docs/assets/screenshots/FireEffect.gif rename to docs/assets/light/effects/FireEffect.gif diff --git a/docs/assets/screenshots/FireEffect.png b/docs/assets/light/effects/FireEffect.png similarity index 100% rename from docs/assets/screenshots/FireEffect.png rename to docs/assets/light/effects/FireEffect.png diff --git a/docs/assets/screenshots/GameOfLifeEffect.gif b/docs/assets/light/effects/GameOfLifeEffect.gif similarity index 100% rename from docs/assets/screenshots/GameOfLifeEffect.gif rename to docs/assets/light/effects/GameOfLifeEffect.gif diff --git a/docs/assets/screenshots/GameOfLifeEffect.png b/docs/assets/light/effects/GameOfLifeEffect.png similarity index 100% rename from docs/assets/screenshots/GameOfLifeEffect.png rename to docs/assets/light/effects/GameOfLifeEffect.png diff --git a/docs/assets/screenshots/GlowParticlesEffect.gif b/docs/assets/light/effects/GlowParticlesEffect.gif similarity index 100% rename from docs/assets/screenshots/GlowParticlesEffect.gif rename to docs/assets/light/effects/GlowParticlesEffect.gif diff --git a/docs/assets/screenshots/GlowParticlesEffect.png b/docs/assets/light/effects/GlowParticlesEffect.png similarity index 100% rename from docs/assets/screenshots/GlowParticlesEffect.png rename to docs/assets/light/effects/GlowParticlesEffect.png diff --git a/docs/assets/screenshots/LavaLampEffect.gif b/docs/assets/light/effects/LavaLampEffect.gif similarity index 100% rename from docs/assets/screenshots/LavaLampEffect.gif rename to docs/assets/light/effects/LavaLampEffect.gif diff --git a/docs/assets/screenshots/LavaLampEffect.png b/docs/assets/light/effects/LavaLampEffect.png similarity index 100% rename from docs/assets/screenshots/LavaLampEffect.png rename to docs/assets/light/effects/LavaLampEffect.png diff --git a/docs/assets/screenshots/LinesEffect.gif b/docs/assets/light/effects/LinesEffect.gif similarity index 100% rename from docs/assets/screenshots/LinesEffect.gif rename to docs/assets/light/effects/LinesEffect.gif diff --git a/docs/assets/screenshots/LinesEffect.png b/docs/assets/light/effects/LinesEffect.png similarity index 100% rename from docs/assets/screenshots/LinesEffect.png rename to docs/assets/light/effects/LinesEffect.png diff --git a/docs/assets/screenshots/MetaballsEffect.gif b/docs/assets/light/effects/MetaballsEffect.gif similarity index 100% rename from docs/assets/screenshots/MetaballsEffect.gif rename to docs/assets/light/effects/MetaballsEffect.gif diff --git a/docs/assets/screenshots/MetaballsEffect.png b/docs/assets/light/effects/MetaballsEffect.png similarity index 100% rename from docs/assets/screenshots/MetaballsEffect.png rename to docs/assets/light/effects/MetaballsEffect.png diff --git a/docs/assets/screenshots/NoiseEffect.gif b/docs/assets/light/effects/NoiseEffect.gif similarity index 100% rename from docs/assets/screenshots/NoiseEffect.gif rename to docs/assets/light/effects/NoiseEffect.gif diff --git a/docs/assets/screenshots/NoiseEffect.png b/docs/assets/light/effects/NoiseEffect.png similarity index 100% rename from docs/assets/screenshots/NoiseEffect.png rename to docs/assets/light/effects/NoiseEffect.png diff --git a/docs/assets/screenshots/ParticlesEffect.gif b/docs/assets/light/effects/ParticlesEffect.gif similarity index 100% rename from docs/assets/screenshots/ParticlesEffect.gif rename to docs/assets/light/effects/ParticlesEffect.gif diff --git a/docs/assets/screenshots/ParticlesEffect.png b/docs/assets/light/effects/ParticlesEffect.png similarity index 100% rename from docs/assets/screenshots/ParticlesEffect.png rename to docs/assets/light/effects/ParticlesEffect.png diff --git a/docs/assets/screenshots/PlasmaEffect.gif b/docs/assets/light/effects/PlasmaEffect.gif similarity index 100% rename from docs/assets/screenshots/PlasmaEffect.gif rename to docs/assets/light/effects/PlasmaEffect.gif diff --git a/docs/assets/screenshots/PlasmaEffect.png b/docs/assets/light/effects/PlasmaEffect.png similarity index 100% rename from docs/assets/screenshots/PlasmaEffect.png rename to docs/assets/light/effects/PlasmaEffect.png diff --git a/docs/assets/screenshots/PlasmaPaletteEffect.gif b/docs/assets/light/effects/PlasmaPaletteEffect.gif similarity index 100% rename from docs/assets/screenshots/PlasmaPaletteEffect.gif rename to docs/assets/light/effects/PlasmaPaletteEffect.gif diff --git a/docs/assets/screenshots/PlasmaPaletteEffect.png b/docs/assets/light/effects/PlasmaPaletteEffect.png similarity index 100% rename from docs/assets/screenshots/PlasmaPaletteEffect.png rename to docs/assets/light/effects/PlasmaPaletteEffect.png diff --git a/docs/assets/screenshots/RainbowEffect.gif b/docs/assets/light/effects/RainbowEffect.gif similarity index 100% rename from docs/assets/screenshots/RainbowEffect.gif rename to docs/assets/light/effects/RainbowEffect.gif diff --git a/docs/assets/screenshots/RainbowEffect.png b/docs/assets/light/effects/RainbowEffect.png similarity index 100% rename from docs/assets/screenshots/RainbowEffect.png rename to docs/assets/light/effects/RainbowEffect.png diff --git a/docs/assets/screenshots/RingsEffect.gif b/docs/assets/light/effects/RingsEffect.gif similarity index 100% rename from docs/assets/screenshots/RingsEffect.gif rename to docs/assets/light/effects/RingsEffect.gif diff --git a/docs/assets/screenshots/RingsEffect.png b/docs/assets/light/effects/RingsEffect.png similarity index 100% rename from docs/assets/screenshots/RingsEffect.png rename to docs/assets/light/effects/RingsEffect.png diff --git a/docs/assets/screenshots/RipplesEffect.gif b/docs/assets/light/effects/RipplesEffect.gif similarity index 100% rename from docs/assets/screenshots/RipplesEffect.gif rename to docs/assets/light/effects/RipplesEffect.gif diff --git a/docs/assets/screenshots/RipplesEffect.png b/docs/assets/light/effects/RipplesEffect.png similarity index 100% rename from docs/assets/screenshots/RipplesEffect.png rename to docs/assets/light/effects/RipplesEffect.png diff --git a/docs/assets/screenshots/SpiralEffect.gif b/docs/assets/light/effects/SpiralEffect.gif similarity index 100% rename from docs/assets/screenshots/SpiralEffect.gif rename to docs/assets/light/effects/SpiralEffect.gif diff --git a/docs/assets/screenshots/SpiralEffect.png b/docs/assets/light/effects/SpiralEffect.png similarity index 100% rename from docs/assets/screenshots/SpiralEffect.png rename to docs/assets/light/effects/SpiralEffect.png diff --git a/docs/assets/screenshots/GridLayout.png b/docs/assets/light/layouts/GridLayout.png similarity index 100% rename from docs/assets/screenshots/GridLayout.png rename to docs/assets/light/layouts/GridLayout.png diff --git a/docs/assets/screenshots/CheckerboardModifier.gif b/docs/assets/light/modifiers/CheckerboardModifier.gif similarity index 100% rename from docs/assets/screenshots/CheckerboardModifier.gif rename to docs/assets/light/modifiers/CheckerboardModifier.gif diff --git a/docs/assets/screenshots/CheckerboardModifier.png b/docs/assets/light/modifiers/CheckerboardModifier.png similarity index 100% rename from docs/assets/screenshots/CheckerboardModifier.png rename to docs/assets/light/modifiers/CheckerboardModifier.png diff --git a/docs/assets/screenshots/MirrorModifier.gif b/docs/assets/light/modifiers/MirrorModifier.gif similarity index 100% rename from docs/assets/screenshots/MirrorModifier.gif rename to docs/assets/light/modifiers/MirrorModifier.gif diff --git a/docs/assets/screenshots/MirrorModifier.png b/docs/assets/light/modifiers/MirrorModifier.png similarity index 100% rename from docs/assets/screenshots/MirrorModifier.png rename to docs/assets/light/modifiers/MirrorModifier.png diff --git a/docs/assets/screenshots/MultiplyModifier.gif b/docs/assets/light/modifiers/MultiplyModifier.gif similarity index 100% rename from docs/assets/screenshots/MultiplyModifier.gif rename to docs/assets/light/modifiers/MultiplyModifier.gif diff --git a/docs/assets/screenshots/MultiplyModifier.png b/docs/assets/light/modifiers/MultiplyModifier.png similarity index 100% rename from docs/assets/screenshots/MultiplyModifier.png rename to docs/assets/light/modifiers/MultiplyModifier.png diff --git a/docs/assets/screenshots/installer-board-picker-collapsed.png b/docs/assets/ui/installer-board-picker-collapsed.png similarity index 100% rename from docs/assets/screenshots/installer-board-picker-collapsed.png rename to docs/assets/ui/installer-board-picker-collapsed.png diff --git a/docs/assets/screenshots/installer-board-picker-expanded.png b/docs/assets/ui/installer-board-picker-expanded.png similarity index 100% rename from docs/assets/screenshots/installer-board-picker-expanded.png rename to docs/assets/ui/installer-board-picker-expanded.png diff --git a/docs/assets/screenshots/installer.png b/docs/assets/ui/installer.png similarity index 100% rename from docs/assets/screenshots/installer.png rename to docs/assets/ui/installer.png diff --git a/docs/assets/screenshots/installer2.png b/docs/assets/ui/installer2.png similarity index 100% rename from docs/assets/screenshots/installer2.png rename to docs/assets/ui/installer2.png diff --git a/docs/assets/screenshots/installer3.png b/docs/assets/ui/installer3.png similarity index 100% rename from docs/assets/screenshots/installer3.png rename to docs/assets/ui/installer3.png diff --git a/docs/assets/screenshots/moondeck_esp32.png b/docs/assets/ui/moondeck_esp32.png similarity index 100% rename from docs/assets/screenshots/moondeck_esp32.png rename to docs/assets/ui/moondeck_esp32.png diff --git a/docs/assets/screenshots/moondeck_live.png b/docs/assets/ui/moondeck_live.png similarity index 100% rename from docs/assets/screenshots/moondeck_live.png rename to docs/assets/ui/moondeck_live.png diff --git a/docs/assets/screenshots/moondeck_pc.png b/docs/assets/ui/moondeck_pc.png similarity index 100% rename from docs/assets/screenshots/moondeck_pc.png rename to docs/assets/ui/moondeck_pc.png diff --git a/docs/assets/screenshots/ui_light.png b/docs/assets/ui/ui_light.png similarity index 100% rename from docs/assets/screenshots/ui_light.png rename to docs/assets/ui/ui_light.png diff --git a/docs/assets/screenshots/ui_overview.png b/docs/assets/ui/ui_overview.png similarity index 100% rename from docs/assets/screenshots/ui_overview.png rename to docs/assets/ui/ui_overview.png diff --git a/docs/assets/screenshots/ui_theme.gif b/docs/assets/ui/ui_theme.gif similarity index 100% rename from docs/assets/screenshots/ui_theme.gif rename to docs/assets/ui/ui_theme.gif diff --git a/docs/backlog/backlog-core.md b/docs/backlog/backlog-core.md index 6877a782..aac5ef01 100644 --- a/docs/backlog/backlog-core.md +++ b/docs/backlog/backlog-core.md @@ -25,7 +25,7 @@ Forward-looking to-build items for the **core / infrastructure** domain (`src/co DevicesModule discovers via **passive UDP presence** (UDP 65506) feeding a [`DevicePlugin`](../../src/core/DevicePlugin.h) seam (shipped: projectMM + WLED plugins). mDNS is advertise-only so projectMM appears in the native WLED apps + Home Assistant; the WLED-app interop (list + live colour + brightness control) is shipped too. What remains is *growth on the seam*, each piece additive (one plugin file, no core change): -- **More discovery plugins** — ESPHome, Tasmota, Hue (*hub-shaped*: a bridge whose Zigbee bulbs are children behind it, with link-button auth). Each is a new `DevicePlugin` declaring its `discoveryPort()` + classifying the datagram (or, for a system that only does mDNS, a re-introduced advertise-side browse scoped to *foreign* services only — never the ones we advertise). Hue is the canonical "more than a flat device" case the seam is shaped for. (Note: Hue *control* already ships as an **output driver**, see [HueDriver](../moonmodules/light/drivers/HueDriver.md) — bulbs as effect pixels; the driver also *lists* its bridge in DevicesModule with the dimmable-light count. Two complementary follow-ups remain: (a) auto-fill the driver's bridge IP from discovery so the user doesn't type it (the mDNS-browse plugin above); (b) **pair once, not per driver** — pairing + the app key currently live on each HueDriver, so two drivers on one bridge pair twice. The clean end-state moves the bridge identity (IP + key + Pair button + light list) into DevicesModule and makes HueDriver a pure output that reads the paired bridge by IP — do this together with the discovery plugin, since both hinge on DevicesModule owning the bridge.) +- **More discovery plugins** — ESPHome, Tasmota, Hue (*hub-shaped*: a bridge whose Zigbee bulbs are children behind it, with link-button auth). Each is a new `DevicePlugin` declaring its `discoveryPort()` + classifying the datagram (or, for a system that only does mDNS, a re-introduced advertise-side browse scoped to *foreign* services only — never the ones we advertise). Hue is the canonical "more than a flat device" case the seam is shaped for. (Note: Hue *control* already ships as an **output driver**, see [HueDriver](../moonmodules/light/drivers/HueDriver.md) — bulbs as effect pixels; the driver also *lists* its bridge in DevicesModule with the colour-light count. Two complementary follow-ups remain: (a) auto-fill the driver's bridge IP from discovery so the user doesn't type it (the mDNS-browse plugin above); (b) **pair once, not per driver** — pairing + the app key currently live on each HueDriver, so two drivers on one bridge pair twice. The clean end-state moves the bridge identity (IP + key + Pair button + light list) into DevicesModule and makes HueDriver a pure output that reads the paired bridge by IP — do this together with the discovery plugin, since both hinge on DevicesModule owning the bridge.) - **The command half** — `DevicePlugin::command()` (+ per-plugin capability/auth), so projectMM can *control* a discovered foreign device, not just list it: set WLED brightness via its JSON API, a Hue resource via the bridge's authenticated CLIP API, a Tasmota via `cmnd`. Built when a control consumer exists; the discovery seam is already shaped to accept it (incl. hub plugins). This is the **multi-ecosystem selling point** — one UI controlling WLED + ESPHome + Hue. Commands split by need (the rule, not "all REST"): must-arrive config over REST; latency-critical sync over UDP (~0.5–1 ms vs REST's 10–50 ms — REST would visibly de-sync). - **Live peer state** — a discovered peer's brightness / on-off shown in our list, refreshed by polling its REST `/json` after discovery gives the IP (discovery = UDP/mDNS, state = REST). The read-side complement to the command half. - **Non-IP transports (board-gated, far future)** — Tasmota-MQTT / zigbee2mqtt need an MQTT client; **direct Zigbee/Thread** (S31/C6/H2 802.15.4 radio) makes projectMM the *hub itself*, driving bulbs over the mesh with no gateway — the standout differentiator, the biggest lift. Same plugin philosophy, a transport addition + board gate. diff --git a/docs/backlog/backlog-mixed.md b/docs/backlog/backlog-mixed.md index c477d657..99d50537 100644 --- a/docs/backlog/backlog-mixed.md +++ b/docs/backlog/backlog-mixed.md @@ -4,6 +4,18 @@ Forward-looking items whose work genuinely spans **both** the core and light dom ## Cross-domain +### LightsControl — the central control hub (palette + global params + presets + external controllers) + +The eventual home for **global light control**, modelled on MoonLight's `ModuleLightsControl` ([source](https://github.com/MoonModules/MoonLight/blob/main/src/MoonLight/Modules/ModuleLightsControl.h), [docs](https://github.com/MoonModules/MoonLight/blob/main/docs/moonlight/lightscontrol.md) — our own project, study don't copy). The concept worth carrying forward: **one module is the integration point between the device and the outside world** (IR remotes, DMX-in, MQTT / Home Assistant, hardware buttons, PIR) *and* the owner of the global light state effects read — so effects respond to one normalised interface instead of N disparate inputs. It owns: master on/off + brightness, RGB tint multipliers, the **active palette**, global **bpm / intensity** sliders broadcast to all active effects, and the **preset** system (below). + +**Pragmatic interim (decided 2026-06-30):** we are *not* building this module now. Its two pieces we need first live on the **Drivers** container (already the owner of global render params — brightness, lightPreset, the shared Correction): the **active palette** lands there in the palette stage (a `palette` select; effects read it via a static `Palettes::active()` seam, the `AudioModule::latestFrame()` pattern), and global **bpm / intensity** can follow the same way when a consumer needs them. When LightsControl is eventually built, it **absorbs** these controls from Drivers and becomes the hub the external controllers feed. Not a blocker for the palette work. + +### Light presets — save / load / loop a whole effect configuration + +MoonLight's preset system (part of `ModuleLightsControl`): **64 named slots**, each capturing the *complete* effect-tree configuration (all module control values), with save / load / delete, **preset looping** on a timer (rotate between a first/last slot), and Home-Assistant registration for external recall. The product owner has flagged this as **definitely needed**. + +Not a dependency of palettes — a separate feature, its natural home the LightsControl module above (or Drivers in the interim). Persistence already round-trips control values (the same overlay that restores the device-tree), so a preset is "snapshot the relevant subtree's JSON to a named file, restore it on recall" — the mechanism mostly exists; what's missing is the slot management + UI + loop timer. Complements the existing [presets UI note](backlog-core.md) (control-value bundles) — this is the light-domain, whole-effect-config version with looping. Build as its own stage when LightsControl (or its interim) is ready. + ### MultiplyModifier mapping-LUT memory at large grids (investigation, re-verify on classic) `scenario_perf_full` on the S3 (2026-06-17) measured the MultiplyModifier's cost across grid sizes. The finding, stated correctly: the modifier **reduces compute** (with the default 2×2 kaleidoscope the effect renders only the ¼-size logical quadrant — Noise+Multiply at 16K is 29,647µs vs 50,555µs for Noise alone), and its real cost is **memory** — the mapping LUT's destinations array. Measured modifier heap cost on the S3: 16²→1.7KB, 32²→10.8KB, 64²→23.5KB, **128²(16K)→93KB** (`nrOfLightsType` is `uint32_t` on a PSRAM board). On the S3's 8MB PSRAM this is trivial. Under the physical→logical fold build each physical light contributes ≤1 destination, so the destinations array is bounded by the real light count regardless of chain depth — there is no build-time fan-out. diff --git a/docs/backlog/folder-structure-proposal.md b/docs/backlog/folder-structure-proposal.md new file mode 100644 index 00000000..236a4f05 --- /dev/null +++ b/docs/backlog/folder-structure-proposal.md @@ -0,0 +1,99 @@ +# Folder-structure consistency — decision + +A *Refactor for simplicity* decision (per CLAUDE.md). Alternatives were weighed; the product owner chose. This records the chosen structure and the work to reach it. Nothing moves until each move is executed deliberately. + +## The three axes — and where each one earns a place + +1. **Domain** — `core` vs `light`. Already structured (src, docs, tests). +2. **Module type** — effects / modifiers / layouts / drivers. Structured in `src/light/` + `docs/moonmodules/light/`; **missing** in `test/` and `assets/` — added here. +3. **Library** — a module's *origin* (MoonLight, WLED, MoonModules, projectMM-native). **Used only as a doc split and a UI tag — NOT a folder axis** (decision below). + +## Decision: `domain / type` folders; library is a tag (+ a doc split) + +The structure is **` / / Module`**, flat within type. Library does **not** become a folder level. + +**Why library is not a folder** (the deciding analysis): an effect's origin is frequently *blended*, not a single fact — e.g. `DistortionWavesEffect` cites MoonLight + WLED + v1 + v2; `GameOfLifeEffect` cites MoonLight + MoonModules + v1; several have no clear origin. A folder forces one answer to a multi-valued question, and a *wrong* or *shifting* answer means a multi-file move (src + assets + tests + the registered `.md` path). It also duplicates the dimension the `tags()` emoji already carries (and the emoji can carry *several* origins; a folder can't). **The end user does not care about a module's library** — they filter by the emoji chip in the UI if they want origin at all. So library stays where it's free and non-duplicative: + +- **In code:** the `tags()` emoji (already there; drives the UI origin-filter; can be multi-valued). +- **In docs:** the page split (below) — the one place library earns a structural role, because docs have an explosion problem src doesn't. + +This drops every drawback of library-as-folder (fuzzy-origin filing, two-places-disagree, reclassification churn, sparse subfolders, deep paths) at once. + +### The target tree + +``` +src/light/ + effects/ EffectBase.h, Rainbow.h, Wave.h, DistortionWaves.h, … (flat per type) + modifiers/ ModifierBase.h, Multiply.h, Rotate.h, … + layouts/ GridLayout.h, SphereLayout.h, … + drivers/ Drivers.h, Correction.h, RmtLedDriver.h, HueDriver.h, … +src/core/ … (unchanged — no type or library axis) +``` + +Identical shape for `docs/assets/` and `test/` (below). `src/` itself is **unchanged** — it's already `domain/type`, flat within type; library was never there as a folder and stays out. + +## Docs: per-library pages with compact rows (solves explosion *and* giant-file) + +Per-module `.md` would be ~65 files post-migration (explosion); one all-effects file would be ~2100 lines (MoonLight's mistake). The middle ground: **one page per library**, each effect a **compact table row**. + +``` +docs/moonmodules/light/ + effects_moonlight.md ← ~30 effects, one row each (~120-150 lines) + effects_wled.md ← ~20 + effects_projectmm.md ← ~15 + modifiers_.md layouts_.md drivers_.md (where a library has them) +docs/moonmodules/core/ ← unchanged: per-module .md (stable count, no explosion) +``` + +- **Row format** (MoonLight-style): `| Name + tags | gif | one-line description | controls |`. Drops the per-module `Tests` / `Design notes` / `Source` sections — source is derivable from the name, tests are auto-discovered. ~4 lines/effect, so a 30-effect page is ~120 lines. +- **Why library splits docs but not src:** docs are the only area with the explosion problem, and a doc page is *forgiving* about fuzzy origin — a blended-lineage effect goes on one page with its full origin in the row's tags/prose; mis-filing is a one-line edit, not a multi-file move. So the drawbacks that made library-as-*folder* bad are soft for library-as-*doc-page*. +- **`check_specs.py` rewrite:** every registered module's control names must appear somewhere in its library page (preserves the anti-drift guarantee). The registered `.md` arg changes from `light/effects/Rainbow.md` to `light/effects_moonlight.md` (or `#rainbow`). This is migration **Stage 2** work. + +## assets + tests: add the missing type-split (mirror src) + +The consistency win that's independent of library — make `test/` and `assets/` match src's existing `domain/type` shape: + +``` +docs/assets/ + core/ DevicesModule.png, Drivers.png, … + light/ + effects/ Rainbow.gif, Wave.gif, DistortionWaves.gif, … + modifiers/ layouts/ drivers/ + boards/ gettingstarted/ ← kept as-is + +test/unit/light/ + effects/ unit_Rainbow.cpp, unit_Wave.cpp, … + modifiers/ layouts/ drivers/ +test/unit/core/ ← unchanged +test/scenarios/light/{effects,layouts,drivers,…}/ (mirror) +``` + +## The one rule, across all four areas + +| | core/light | type | leaf | library | +|---|---|---|---|---| +| **src** | `light/` | `effects/` | `DistortionWaves.h` | tag in `tags()` | +| **assets** | `light/` | `effects/` | `DistortionWaves.gif` | — | +| **tests** | `light/` | `effects/` | `unit_DistortionWaves.cpp` | — | +| **docs** | `light/` | the type+library collapse into the page name → `effects_wled.md` | (row inside) | the page split | + +`docs` is the one area where `type` is expressed as part of a **page name** (`effects_.md`) rather than a folder, because the migration compacts docs to per-library pages — and library, the only axis with an explosion problem, rides along in that name. Everywhere else: plain `domain/type` folders, library as a tag. + +## Impacted folders + the work + +| Folder | Change | Cost | When | +|---|---|---|---| +| `docs/assets/` | flat `screenshots/` → `assets/{core, light/{effects,drivers,layouts,modifiers}}/`; keep `boards/`, `gettingstarted/`. Move 63 files, update ~34 referencing docs. | Medium, mechanical | **Now** (clearly-broken flat area; PO specified the asset structure) | +| `test/unit/`, `test/scenarios/` | add the type-split under `core/`/`light/`; re-path the 81 CMake test entries. | Medium, mechanical | **Now or fold into next test-touching change** | +| `docs/moonmodules/` | per-library pages (`effects_.md`) with compact rows + the `check_specs.py` rewrite; delete the ~21 per-module effect `.md`s. | Medium | **Migration Stage 2** (already planned) | +| `src/` | **unchanged** (already `domain/type`, flat). | none | — | + +**Not reshaped** (correctly orthogonal): `test/js`, `test/python` (host-side; test scripts/installer, not modules), `src/platform/{desktop,esp32}` (platform split, already consistent), `src/{core,light}/moonlive` (feature sub-tree). + +## Sequencing + +1. **Now:** `docs/assets/` reorg (the broken flat area). +2. **Now / next test change:** `test/` type-split. +3. **Migration Stage 2:** per-library doc pages (compact rows) + the `check_specs.py` rewrite + delete the per-module `.md`s. + +`src/` needs no move at all — the leanest possible outcome. diff --git a/docs/backlog/moonlight-effect-inventory.md b/docs/backlog/moonlight-effect-inventory.md new file mode 100644 index 00000000..055953f6 --- /dev/null +++ b/docs/backlog/moonlight-effect-inventory.md @@ -0,0 +1,69 @@ +# MoonLight effect inventory (migration reference) + +The full set of MoonLight effects to migrate, grouped by **origin library** (the doc-page split: `effects_.md`), with audio/3D markers. Source: [MoonLight effects.md](https://github.com/MoonModules/MoonLight/blob/main/docs/moonlight/effects.md) + the `E_*.h` source files — studied for *behaviour*, reimplemented fresh per the migration plan's *Industry standards, our own code* rule. This reference feeds the [migration plan's](../history/plans/Plan-20260630%20-%20MoonLight%20migration%20(multi-stage).md) Stage-3 batches; it is *what to build*, not a copy of how. + +**Markers:** ♫ / ♪ audio-reactive · 🧊 native 3D. **Status:** ✅ already in projectMM · ⬜ to migrate. + +## MoonLight library → `effects_moonlight.md` + +| Effect | Markers | Status | Notes | +|---|---|---|---| +| Solid | | ⬜ | background/base colour | +| Lines | | ✅ | LinesEffect | +| Frequency Saws | ♫ | ⬜ | audio (Stage 3d) | +| Moon Man | | ⬜ | | +| Particles | 🧊 | ✅ | ParticlesEffect | +| Rainbow | | ✅ | RainbowEffect | +| Random | | ⬜ | | +| Ripples | 🧊 | ✅ | RipplesEffect | +| Rubik's Cube | 🧊 | ⬜ | 3D | +| Scrolling Text | | ⬜ | needs a font/glyph blitter (Stage 3e) | +| Sinus | | ✅ | SineEffect | +| Sphere Move | 🧊 | ⬜ | 3D; pairs with SphereLayout | +| StarField | | ⬜ | | +| Praxis | | ⬜ | | +| Wave | | ✅ | WaveEffect | +| Fixed Rectangle | | ⬜ | | +| Star Sky | | ⬜ | | + +## MoonModules library → `effects_moonmodules.md` + +| Effect | Markers | Status | Notes | +|---|---|---|---| +| GEQ 3D | ♫ | ⬜ | audio + 3D | +| PaintBrush | ♫ 🧊 | ⬜ | audio + 3D | +| Game Of Life | 🧊 | ✅⚠️ | **re-port** — current version flagged not faithful (migration Stage 1 proof) | + +## WLED library → `effects_wled.md` + +| Effect | Markers | Status | Notes | +|---|---|---|---| +| Blackhole | | ⬜ | | +| Bouncing Balls | | ⬜ | physics (Stage 3c) | +| Blurz | ♫ | ⬜ | audio | +| Distortion Waves | | ✅ | DistortionWavesEffect | +| Frequency Matrix | ♪ | ⬜ | audio | +| GEQ | ♫ | ⬜ | audio | +| Lissajous | | ⬜ | geometric (Stage 3a) | +| Noise 2D | | ✅ | NoiseEffect | +| Noise Meter | ♪ | ⬜ | audio | +| PopCorn | ♪ | ⬜ | physics + audio | +| Waverly | ♪ | ⬜ | audio | + +## Moving-head library → `effects_movingheads.md` (Stage 5, DMX fixtures) + +| Effect | Markers | Status | +|---|---|---| +| Troy1 Color / Troy1 Move / Troy2 Color / Troy2 Move | ♫ | ⬜ | +| FreqColors · Wowi Move · Ambient Move | ♫ | ⬜ | + +## projectMM-native (no external origin) → `effects_projectmm.md` + +Already in projectMM, our own (not from a MoonLight library — kept here so the inventory is complete): +AudioSpectrumEffect ♫, AudioVolumeEffect ♫, FireEffect, GlowParticlesEffect, LavaLampEffect, MetaballsEffect, NetworkReceiveEffect, PlasmaEffect, PlasmaPaletteEffect, RingsEffect, SpiralEffect, CheckerboardEffect. + +*(Several have a MoonLight/WLED lineage in their prior-art notes; "origin" here is the page they'll file under — settle per-effect at migration time, per the [folder-structure decision](folder-structure-proposal.md): the page is the primary-steward bucket, the `tags()` emoji carries full lineage.)* + +## Tally + +47 MoonLight-listed effects. **Already covered: ~7** (Lines, Particles, Rainbow, Ripples, Sinus, Wave, Distortion Waves, Noise 2D — direct equivalents) + GoL (re-port). **To migrate: ~38**, of which ~14 are audio (Stage 3d) and 7 are moving-head (Stage 5). The non-audio, non-moving-head remainder (~17) are the Stage 3a/b/c batches — the bulk of the parity work the [rename gate](rename-to-moonlight.md#must--the-rename-is-a-downgrade-without-these) needs. diff --git a/docs/backlog/moonlight-palettes-data.md b/docs/backlog/moonlight-palettes-data.md new file mode 100644 index 00000000..0ea8afc4 --- /dev/null +++ b/docs/backlog/moonlight-palettes-data.md @@ -0,0 +1,91 @@ +# MoonLight palettes — captured data (migration reference) + +The gradient-palette *data* captured from [MoonLight's palettes.h](https://github.com/MoonModules/MoonLight/blob/main/src/MoonLight/Modules/palettes.h) (a recognised public palette set), so Stage-1 of the [migration plan](../history/plans/Plan-20260630%20-%20MoonLight%20migration%20(multi-stage).md) formats the data into the `Palette` type rather than re-scraping. The palette model + names (`CRGBPalette16`, `colorFromPalette`) follow FastLED's, the established convention WLED + MoonLight also use, credited as prior art; the implementation is projectMM's. + +## Format + +Each palette is a **gradient-stop list**: `{pos, R, G, B, pos, R, G, B, …}` — `pos` 0–255, the last stop at 255. Between stops the colour interpolates linearly. On selection the gradient is quantised to a 16-entry palette (the `CRGBPalette16` model); the per-light read blends the two bracketing entries with `scale8` + a brightness `scale8`. (Storage/lookup rationale: see *Palette design* below.) + +MoonLight registers ~82 palettes via parallel `gGradientPalettes[]` (pointers) + `palette_names[]` (display names with markers: ⚡️ FastLED built-in, 💫 MoonLight original, ♪🌙 audio-responsive). The first ~16 entries are **FastLED built-ins** (Cloud, Lava, Ocean, Forest, Rainbow, Party, Heat) generated by FastLED, not gradient arrays — projectMM generates those itself (rainbow, fire, ocean, party are trivial). The named gradient definitions below (~54) are the carry-able data. + +## Captured gradient definitions + +```c +// {pos,R,G,B,...} — verbatim from palettes.h, to be reformatted into our Palette type +ib_jul01 {0,194,1,1, 94,1,29,18, 132,57,131,28, 255,113,1,1} +es_vintage_57 {0,2,1,1, 53,18,1,0, 104,69,29,1, 153,167,135,10, 255,46,56,4} +es_vintage_01 {0,4,1,1, 51,16,0,1, 76,97,104,3, 101,255,131,19, 127,67,9,4, 153,16,0,1, 229,4,1,1, 255,4,1,1} +es_rivendell_15 {0,1,14,5, 101,16,36,14, 165,56,68,30, 242,150,156,99, 255,150,156,99} +rgi_15 {0,4,1,70, 31,55,1,30, 63,255,4,7, 95,59,2,29, 127,11,3,50, 159,39,8,60, 191,112,19,40, 223,78,11,39, 255,29,8,59} +retro2_16 {0,188,135,1, 255,46,7,1} +Analogous_1 {0,3,0,255, 63,23,0,255, 127,67,0,255, 191,142,0,45, 255,255,0,0} +es_pinksplash_08 {0,126,11,255, 127,197,1,22, 175,210,157,172, 221,157,3,112, 255,157,3,112} +es_ocean_breeze_036 {0,1,6,7, 89,1,99,111, 153,144,209,255, 255,0,73,82} +departure {0,8,3,0, 42,23,7,0, 63,75,38,6, 84,169,99,38, 106,213,169,119, 116,255,255,255, 138,135,255,138, 148,22,255,24, 170,0,255,0, 191,0,136,0, 212,0,55,0, 255,0,55,0} +es_landscape_64 {0,0,0,0, 37,2,25,1, 76,15,115,5, 127,79,213,1, 128,126,211,47, 130,188,209,247, 153,144,182,205, 204,59,117,250, 255,1,37,192} +es_landscape_33 {0,1,5,0, 19,32,23,1, 38,161,55,1, 63,229,144,1, 66,39,142,74, 255,1,4,1} +rainbowsherbet {0,255,33,4, 43,255,68,25, 86,255,7,25, 127,255,82,103, 170,255,255,242, 209,42,255,22, 255,87,255,65} +gr65_hult {0,247,176,247, 48,255,136,255, 89,220,29,226, 160,7,82,178, 216,1,124,109, 255,1,124,109} +gr64_hult {0,1,124,109, 66,1,93,79, 104,52,65,1, 130,115,127,1, 150,52,65,1, 201,1,86,72, 239,0,55,45, 255,0,55,45} +GMT_drywet {0,47,30,2, 42,213,147,24, 84,103,219,52, 127,3,219,207, 170,1,48,214, 212,1,1,111, 255,1,7,33} +ib15 {0,113,91,147, 72,157,88,78, 89,208,85,33, 107,255,29,11, 141,137,31,39, 255,59,33,89} +Tertiary_01 {0,0,1,255, 63,3,68,45, 127,23,255,0, 191,100,68,1, 255,255,1,4} +lava {0,0,0,0, 46,18,0,0, 96,113,0,0, 108,142,3,1, 119,175,17,1, 146,213,44,2, 174,255,82,4, 188,255,115,4, 202,255,156,4, 218,255,203,4, 234,255,255,4, 244,255,255,71, 255,255,255,255} +fierce_ice {0,0,0,0, 59,0,9,45, 119,0,38,255, 149,3,100,255, 180,23,199,255, 217,100,235,255, 255,255,255,255} +Colorfull {0,10,85,5, 25,29,109,18, 60,59,138,42, 93,83,99,52, 106,110,66,64, 109,123,49,65, 113,139,35,66, 116,192,117,98, 124,255,255,137, 168,100,180,155, 255,22,121,174} +Pink_Purple {0,19,2,39, 25,26,4,45, 51,33,6,52, 76,68,62,125, 102,118,187,240, 109,163,215,247, 114,217,244,255, 122,159,149,221, 149,113,78,188, 183,128,57,155, 255,146,40,123} +Sunset_Real {0,120,0,0, 22,179,22,0, 51,255,104,0, 85,167,22,18, 135,100,0,103, 198,16,0,130, 255,0,0,160} +Sunset_Yellow {0,10,62,123, 36,56,130,103, 87,153,225,85, 100,199,217,68, 107,255,207,54, 115,247,152,57, 120,239,107,61, 128,247,152,57, 180,255,207,54, 223,255,227,48, 255,255,248,42} +Beech {0,255,252,214, 12,255,252,214, 22,255,252,214, 26,190,191,115, 28,137,141,52, 28,112,255,205, 50,51,246,214, 71,17,235,226, 93,2,193,199, 120,0,156,174, 133,1,101,115, 136,1,59,71, 136,7,131,170, 208,1,90,151, 255,0,56,133} +Another_Sunset {0,110,49,11, 29,55,34,10, 68,22,22,9, 68,239,124,8, 97,220,156,27, 124,203,193,61, 178,33,53,56, 255,0,1,52} +es_autumn_19 {0,26,1,1, 51,67,4,1, 84,118,14,1, 104,137,152,52, 112,113,65,1, 122,133,149,59, 124,137,152,52, 135,113,65,1, 142,139,154,46, 163,113,13,1, 204,55,3,1, 249,17,1,1, 255,17,1,1} +BlacK_Blue_Magenta_White {0,0,0,0, 42,0,0,45, 84,0,0,255, 127,42,0,255, 170,255,0,255, 212,255,55,255, 255,255,255,255} +BlacK_Magenta_Red {0,0,0,0, 63,42,0,45, 127,255,0,255, 191,255,0,45, 255,255,0,0} +BlacK_Red_Magenta_Yellow {0,0,0,0, 42,42,0,0, 84,255,0,0, 127,255,0,45, 170,255,0,255, 212,255,55,45, 255,255,255,0} +Blue_Cyan_Yellow {0,0,0,255, 63,0,55,255, 127,0,255,255, 191,42,255,45, 255,255,255,0} +Orange_Teal {0,0,150,92, 55,0,150,92, 200,255,72,0, 255,255,72,0} +Tiamat {0,1,2,14, 33,2,5,35, 100,13,135,92, 120,43,255,193, 140,247,7,249, 160,193,17,208, 180,39,255,154, 200,4,213,236, 220,39,252,135, 240,193,213,253, 255,255,249,255} +April_Night {0,1,5,45, 10,1,5,45, 25,5,169,175, 40,1,5,45, 61,1,5,45, 76,45,175,31, 91,1,5,45, 112,1,5,45, 127,249,150,5, 143,1,5,45, 162,1,5,45, 178,255,92,0, 193,1,5,45, 214,1,5,45, 229,223,45,72, 244,1,5,45, 255,1,5,45} +Orangery {0,255,95,23, 30,255,82,0, 60,223,13,8, 90,144,44,2, 120,255,110,17, 150,255,69,0, 180,158,13,11, 210,241,82,17, 255,213,37,4} +C9 {0,184,4,0, 60,184,4,0, 65,144,44,2, 125,144,44,2, 130,4,96,2, 190,4,96,2, 195,7,7,88, 255,7,7,88} +Sakura {0,196,19,10, 65,255,69,45, 130,223,45,72, 195,255,82,103, 255,223,13,17} +Aurora {0,1,5,45, 64,0,200,23, 128,0,255,0, 170,0,243,45, 200,0,135,7, 255,1,5,45} +Atlantica {0,0,28,112, 50,32,96,255, 100,0,243,45, 150,12,95,82, 200,25,190,95, 255,40,170,80} +C9_2 {0,6,126,2, 45,6,126,2, 45,4,30,114, 90,4,30,114, 90,255,5,0, 135,255,5,0, 135,196,57,2, 180,196,57,2, 180,137,85,2, 255,137,85,2} +C9_new {0,255,5,0, 60,255,5,0, 60,196,57,2, 120,196,57,2, 120,6,126,2, 180,6,126,2, 180,4,30,114, 255,4,30,114} +temperature {0,1,27,105, 14,1,40,127, 28,1,70,168, 42,1,92,197, 56,1,119,221, 70,3,130,151, 84,23,156,149, 99,67,182,112, 113,121,201,52, 127,142,203,11, 141,224,223,1, 155,252,187,2, 170,247,147,1, 184,237,87,1, 198,229,43,1, 226,171,2,2, 240,80,3,3, 255,80,3,3} +Aurora2 {0,17,177,13, 64,121,242,5, 128,25,173,121, 192,250,77,127, 255,171,101,221} +retro_clown {0,227,101,3, 117,194,18,19, 255,92,8,192} +candy {0,229,227,1, 15,227,101,3, 142,40,1,80, 198,17,1,79, 255,0,0,45} +toxy_reaf {0,1,221,53, 255,73,3,178} +fairy_reaf {0,184,1,128, 160,1,193,182, 219,153,227,190, 255,255,255,255} +semi_blue {0,0,0,0, 12,1,1,3, 53,8,1,22, 80,4,6,89, 119,2,25,216, 145,7,10,99, 186,15,2,31, 233,2,1,5, 255,0,0,0} +pink_candy {0,255,255,255, 45,7,12,255, 112,227,1,127, 112,227,1,127, 140,255,255,255, 155,227,1,127, 196,45,1,99, 255,255,255,255} +red_reaf {0,3,13,43, 104,78,141,240, 188,255,0,0, 255,28,1,1} +red_shift {0,31,1,27, 45,34,1,16, 99,137,5,9, 132,213,128,10, 175,199,22,1, 201,199,9,6, 255,1,0,1} +red_tide {0,247,5,0, 28,255,67,1, 43,234,88,11, 58,234,176,51, 84,229,28,1, 114,113,12,1, 140,255,225,44, 168,113,12,1, 196,244,209,88, 216,255,28,1, 255,53,1,1} +audio_responsive {0,255,0,0, 125,0,255,0, 255,0,0,255} +``` + +*(The full file has ~82 registry entries; the ~16 FastLED built-ins at the front — Cloud/Lava/Ocean/Forest/Rainbow/Party/Heat — are generated, not gradient arrays, so projectMM generates those itself. The ~54 gradient definitions above are the data to carry; capture any remaining few from the source when Stage 1 lands.)* + +## Palette design (decided 2026-06-30) + +The data above is half of it; these are the design decisions, pinned so Stage 1 implements rather than re-decides. + +- **Storage = a 16-entry palette, interpolate at lookup** (the `CRGBPalette16` model — the recognised FastLED structure WLED + MoonLight also use; we carry the model + name, write our own implementation). The gradient `{pos,R,G,B}` definitions live in flash; on selection a palette is quantised to **16 evenly-spaced RGB entries** = 48 bytes. At 48 B each, RAM is a non-issue (all ~70 resident ≈ 3.4 KB), so there's no "expand only the active one" gymnastics and **crossfade/multi-palette later cost almost nothing**. A fully-expanded 256-entry table (768 B, O(1) index, no per-pixel blend) was considered and **rejected**: 16× the RAM for a per-pixel win that doesn't pay — the lookup-blend is a single `scale8`, already cheap. +- **Lookup = interpolate between two of the 16 entries.** `colorFromPalette(index)` maps the 0–255 `index` to a position across the 16 entries, blends the two bracketing entries with one `scale8`, then applies brightness with a second `scale8`. Cheap, integer-only — the standard gradient-palette lookup. (The dynamic/MoonLive case below substitutes a native-script call; the **dispatch between gradient and script is resolved per *frame*, not per pixel** — the active palette's kind is read once, the inner per-light loop is monomorphic.) +- **Contract:** `RGB colorFromPalette(const Palette& p, uint8_t index, uint8_t brightness = 255)`. `index` is a **0–255 wheel position** that wraps (the established palette convention); `brightness` folds in via `scale8`. The quantise (stops → 16 entries) and the lookup-blend are the textbook two-point linear interpolation. The `CRGBPalette16` model + the `colorFromPalette` name are FastLED's, credited as prior art; the implementation is projectMM's, on its `scale8`/`RGB`. +- **Switch = hard swap.** Selecting a palette rebuilds the active lookup; effects pick it up the next frame. Smooth **crossfade between palettes** (interpolate old→new lookup over N frames, the MoonLight/WLED nicety) is **backlogged**, not a Stage-1 dependency. +- **Ownership / plumbing:** the active palette + its `palette` select control live on the **Drivers** container; effects read it via a static `Palettes::active()` seam (the `AudioModule::latestFrame()` pattern). See the [LightsControl backlog item](backlog-mixed.md) — when that module lands it absorbs the control. +- **MoonLive-authored (dynamic) palettes — design for it, build later.** The same seam must accommodate a palette that is a [MoonLive](../architecture.md#moonlive-the-live-script-engine) script, not a static gradient. The model mirrors `MoonLiveEffect` exactly: where a scripted *effect* writes pixels (`setRGB`), a scripted *palette* **returns a colour for an index** — the script *is* `colorFromPalette`, compiled to native code and called per-lookup through the function pointer. This unlocks **dynamic palettes** (colour that varies with time, audio, or any expression) that any effect consumes transparently through `Palettes::active()` — the effect never knows whether the active palette is a flash gradient or a live script. To not preclude it, the **`Palette` type is an interface, not just a struct**: `colorFromPalette()` dispatches to either (a) the 16-entry gradient lookup (the case above) or (b) a MoonLive-compiled `index → RGB` function (the dynamic case). The hot-path cost differs (a `scale8` blend vs a native script call), so a dynamic palette is opt-in per the same speed tradeoff. Stage 1 builds the static path with this seam shape; the dynamic binding is its own later stage. + + **Authoring vs selection (decided 2026-06-30):** a dynamic palette is **`MoonLivePalette`, a script-authored palette — exactly the `MoonLiveEffect` pattern** (a `MoonLiveEffect` is *an effect* whose body is a script, role still `Effect`, added like any effect; a `MoonLivePalette` is *a palette* whose `colorFromPalette` is a script). So: + - **It is NOT a new top-level role** next to effects / modifiers / layouts / drivers. A palette is *data an effect consumes*, not a pipeline stage; MoonLive-ness is an implementation detail of the palette, not a new category. (Same reason `MoonLiveEffect` didn't add a "scripted" role — it's just an effect.) + - **Selection stays on Drivers** (the `palette` control / future LightsControl): a `MoonLivePalette` appears in that dropdown alongside the built-in gradients, selected identically. The effect reading `Palettes::active()` never knows the difference. + - **Authoring is its own `MoonLivePalette` module** carrying the `source` text area (like `MoonLiveEffect`'s), where the script declares `@control` vars that become live controls. Open detail for the stage plan: *where the instance sits in the tree* — it isn't a render-pipeline child (a palette isn't rendered), so it likely lives in a small palette-holder container (or is owned by Drivers/LightsControl), not under a Layer. Decide when built. + - The host builtin signature is `index → RGB` (vs `MoonLiveEffect`'s `setRGB` pixel-writer) — a new entry in the light-domain MoonLive builtin table. MoonLive authoring of palettes is a projectMM **lead** capability the predecessor lacks; the seam is designed now, the body is a later stage. + +## Stage-1 work this unblocks + +A `Palette` holding the 16 entries + `colorFromPalette()` per the contract above; the gradient-stop definitions in flash (seeded from the data above + generated rainbow/fire/ocean/party); the `palette` select on Drivers + `Palettes::active()`. Generalises `PlasmaPaletteEffect`'s hard-coded `palette_[256]` into the shared type. Unit-pin: stop→16-entry quantise correctness (endpoints + a mid-gradient colour), the lookup-blend + wheel-wrap + brightness fold, and that switching swaps the active palette. diff --git a/docs/backlog/rename-to-moonlight.md b/docs/backlog/rename-to-moonlight.md index ea87fe74..2ac14878 100644 --- a/docs/backlog/rename-to-moonlight.md +++ b/docs/backlog/rename-to-moonlight.md @@ -105,7 +105,7 @@ This is parity-to-take-the-name, not parity-for-parity's-sake — projectMM's ar These are pointers to existing backlog items; the rename doesn't create new work so much as set a **bar** for which items gate it. Each links to its detailed entry rather than restating it. ### Must — the rename is a downgrade without these -- **Effect breadth at a credible fraction of 60+** — not all 60, but enough that the library doesn't feel thin. Today's ~20 cover the common families (noise, fire, plasma, particles, audio); a Must is closing the obvious *category* gaps a predecessor user expects (see Should), not matching the count. (MoonLive softens even this: a user can *author* a missing effect on-device rather than wait for a built-in.) +- **Effect breadth at a credible fraction of 60+** — not all 60, but enough that the library doesn't feel thin. Today's ~20 cover the common families (noise, fire, plasma, particles, audio); a Must is closing the obvious *category* gaps a predecessor user expects (see Should), not matching the count. (MoonLive softens even this: a user can *author* a missing effect on-device rather than wait for a built-in.) **This gate is executed by the staged MoonLight migration** — its plan ([`Plan-20260630 - MoonLight migration (multi-stage)`](../history/plans/Plan-20260630%20-%20MoonLight%20migration%20(multi-stage).md)) brings the predecessor's effects / modifiers / layouts across in batches on a shared palette + primitive foundation; the rename's bar is "enough batches landed to not feel thin," not "all stages done." - **Mapping / layout parity for real fixtures** — the predecessor's "memory-optimised mapping" across non-trivial fixtures (matrices, rings, cubes, custom). projectMM has Grid/Sphere/Wheel + modifiers; a Must is that a user's existing physical layout from the predecessor has a path here. - **OTA continuity for in-field devices** (also in Phase 2/3) — a predecessor user's deployed devices must keep updating across the rename, not brick on a dead URL. diff --git a/docs/building.md b/docs/building.md index 903d57bc..8b9d324f 100644 --- a/docs/building.md +++ b/docs/building.md @@ -59,7 +59,7 @@ uv run scripts/test/test_desktop.py # unit tests Or use MoonDeck's PC tab for the same operations with a status dot per card. The desktop run detaches and outlives the launching script — the same model as flashing an ESP32, where the device runs independently afterwards. -![MoonDeck PC tab](assets/screenshots/moondeck_pc.png) +![MoonDeck PC tab](assets/ui/moondeck_pc.png) Each host writes into its own build dir: `build/macos/`, `build/linux/`, `build/windows/`. The per-host layout mirrors the ESP32 side's `build/esp32-/` shape — one directory per target, no cross-target clobbering on a multi-host dev machine. @@ -126,7 +126,7 @@ On Windows, the `--port` argument is a `COM*` name (e.g. `COM3`) instead of `/de The ESP32 tab in MoonDeck wraps the same steps as cards (Setup → Firmware → Build → Port → Flash → Run). The Network bar at the top is the same one shown on the Live tab — it remembers which serial port and WiFi credentials belong to the current LAN, so moving the laptop between networks doesn't require re-picking. -![MoonDeck ESP32 tab](assets/screenshots/moondeck_esp32.png) +![MoonDeck ESP32 tab](assets/ui/moondeck_esp32.png) ### ESP-IDF version diff --git a/docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output).md b/docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output) (shipped).md similarity index 99% rename from docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output).md rename to docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output) (shipped).md index 66b76c07..7b98dc27 100644 --- a/docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output).md +++ b/docs/history/plans/Plan-20260630 - HueDriver (Hue lights as an effect output) (shipped).md @@ -1,4 +1,4 @@ -# Plan — HueDriver: Philips Hue lights as a projectMM effect output +# Plan — HueDriver: Philips Hue lights as a projectMM effect output (shipped) ## Context diff --git a/docs/history/plans/Plan-20260630 - MoonLight migration (multi-stage).md b/docs/history/plans/Plan-20260630 - MoonLight migration (multi-stage).md new file mode 100644 index 00000000..244438ab --- /dev/null +++ b/docs/history/plans/Plan-20260630 - MoonLight migration (multi-stage).md @@ -0,0 +1,103 @@ +# Plan — Migrate MoonLight effects / modifiers / layouts (multi-stage) + +## Goal & shape + +Bring MoonLight's full library of **effects, modifiers and layouts** into projectMM. This is large, so it is **staged**: each stage ships independently, builds on the previous, and is its own `/plan` + commit. This document is the *map* — the per-stage plans get written when we reach them. Stages 1–2 are specified enough to start; later stages are scoped, not detailed. + +**Why this matters beyond features:** this migration is the execution vehicle for the **effect-breadth parity gate** in the [projectMM → MoonLight rename plan](../../backlog/rename-to-moonlight.md#must--the-rename-is-a-downgrade-without-these) — taking the MoonLight name requires the library not to feel thin next to the predecessor's 60+ effects. The rename's bar is "enough batches landed," not "every stage done"; this plan is *how* that bar is reached. (The two docs stay in their folders — the rename is the forward-looking backlog item that sets the bar; this is the approved staged plan that meets it — linked, not duplicated.) + +Two cross-cutting rules govern every stage, from [CLAUDE.md](../../../CLAUDE.md): + +- **Industry standards, our own code.** MoonLight effects are studied for *behaviour and algorithm*, then written **fresh** against our architecture (our `EffectBase`, our primitives, our names). We do **not** trace MoonLight/WLED/FastLED structure or copy code. For *effects specifically* the **visual behaviour is the spec** — we reproduce what the effect looks like faithfully (the product owner's clarification), but the implementation is ours. Prior art credited per-module + in `history/`. +- **A shared light primitive library.** Effects need a common set of small math/colour helpers (a beat/sine oscillator, integer noise, saturating add/subtract, scale, fade, a colour blend, a fast PRNG, draw primitives). projectMM provides these, extending the `color.h` set (`scale8`, `sin8`, `cos8`, `hsvToRgb` already there): **hot-path-tuned** (integer-only, LUT-backed, no float in the per-light path) and **dimension-agnostic where it makes sense** (the product owner's steer: our 3D-native model means a primitive like `drawLine` works 1D→3D, written once, not re-implemented per effect). + - **Naming follows *Common patterns first* + *Industry standards, our own code*: the recognisable name AND our own implementation.** The LED-embedded world's canonical resource is FastLED, and its names (`beatsin8`, `inoise8`, `qadd8`, `nscale8`, `random8`/`random16`, `ColorFromPalette`) are exactly the ones a contributor recognises in 30 seconds — and consistent with the `scale8`/`sin8` we already ship. So **we use those names** (carrying the established convention), **write our own implementation** against our engine, and **credit FastLED as prior art** in each module's "Prior art" section. The point of the principle is independence-by-construction (own code, own architecture, behaviour pinned by tests), *not* a renamed copy — so the names stay recognisable; only the implementation is ours. Each primitive's design is justified at its introduction site, and we reorganise a borrowed concept when ours is genuinely cleaner (e.g. the dimension-agnostic draw set). + +## What exists today (baseline) + +- **Primitives:** `src/core/color.h` has `RGB`, `hsvToRgb`, `scale8`, `sin8`/`cos8` (LUT). `src/light/light_types.h` has `Coord3D`, `Dim`, `lengthType`. That's it — no beat/noise/blend/random helpers, no shared palette, no draw primitives. +- **Palette:** none shared. `PlasmaPaletteEffect` hard-codes a 256-entry `RGB palette_[256]` in flash — the pattern to generalise. +- **Effects:** ~21 already ported (Rainbow, Noise, Plasma, Fire, Particles, Metaballs, GameOfLife, Wave, …). GameOfLife (272 lines) is flagged by the product owner as **not faithful — re-port from the real algorithm**. +- **Modifiers:** Multiply, Rotate, Region, Checkerboard, RandomMap. **Layouts:** Grid, Sphere, Wheel. +- **Tags/emoji:** projectMM already has `tags()` + UI-derived role/dim emoji (architecture.md § Web UI). MoonLight's legend (🔥 effect, 💎 modifier, ♫ audio, 🧊 3D, …) becomes the **canonical basis** (product owner's choice). +- **Docs:** one `.md` per module (21 effect specs already), enforced by `check_specs.py` (it `rglob`s each `.h` → a matching `.md`). Moving to **per-library pages** (`effects_.md`, compact table rows) — see Stage 2 and the [folder-structure decision](../../backlog/folder-structure-proposal.md). This requires changing the spec-check contract. +- **Assets:** **already reorganised** to `docs/assets/{core, light/{effects,modifiers,layouts,drivers}, ui}/` (the per-module move done ahead of the migration). Stage 2's gif work is *adding* MoonLight previews into this structure, not re-homing. + +## Dependency analysis (what must come first) + +1. **Palette** — hard prerequisite. Many MoonLight effects colour via `ColorFromPalette`. Nothing palette-dependent can be faithfully ported until this lands. **Stage 1.** +2. **The shared primitive library** (beat / noise / blend / scale / random / draw) — most effects need several. **Stage 1.** +3. **Tags/emoji legend** — must be settled before batch-migrating, so every migrated module is consistent from the first batch. Cheap; **Stage 1** (a doc + a sweep of existing `tags()`). +4. **Doc model change** — must land before the doc explosion, i.e. before batch migration. A page per **library** (type-first name, underscore-joined): `effects_moonlight.md`, `effects_wled.md`, … (and `modifiers_.md` etc. only where a library has them; most are effects-only). Library is a *doc* split only — NOT a `src`/`assets`/`tests` folder (those stay `domain/type` flat; library is the `tags()` emoji there). Fixed by the [folder-structure decision](../../backlog/folder-structure-proposal.md). **Stage 2**. +5. **Audio** — audio-reactive effects (♫) depend on `AudioModule::latestFrame()` (already exists). A later stage; not a blocker for non-audio effects. +6. **Moving heads / Art-Net fixtures** — `E_MovingHeads` targets DMX moving heads; depends on fixture-layout + Art-Net (partly present). Last, separate. + +No other hidden hard dependencies: our `EffectBase` + extrude (now 1D-along-Y, matching MoonLight) + `Buffer` already provide the render context. + +## Stages + +### Stage 1 — Foundations (palette + primitives + GoL re-port) ← start here + +The proving-ground stage: build the shared tools, prove them on one hard effect. + +- **Palette.** Take **MoonLight's palette set** (~80 gradient palettes, [palettes.h](https://github.com/MoonModules/MoonLight/blob/main/src/MoonLight/Modules/palettes.h) — study + carry the gradient *data*, written into our own format). The definition format is the textbook **gradient-stop** one: a compact `{position, R, G, B, …}` list (position 0..255, terminating at 255), expanded off-loop into a 256-entry lookup. Our `Palette` type + `colorFromPalette(palette, index, brightness)`: the per-light lookup is an array index + one `scale8` (hot-path-tuned; the 256-entry table precomputed on selection, not per frame). Generalises `PlasmaPaletteEffect`'s hard-coded table. + - **Ownership (decided 2026-06-30):** the **active palette is global**, owned by the **Drivers** container (already the home of global render params — brightness, lightPreset, the shared Correction) via a new `palette` select control. Effects read it through a static `Palettes::active()` seam (the `AudioModule::latestFrame()` pattern), so an effect just calls `colorFromPalette(Palettes::active(), idx)`. This mirrors MoonLight's global `layerP.palette` without needing MoonLight's `ModuleLightsControl` — which, with **presets** and the **external-controller hub** concept, is **backlogged** ([backlog-mixed.md](../../backlog/backlog-mixed.md)) and will absorb the palette control from Drivers when built. Presets are *not* a palette dependency — separate feature, backlogged. + - Palettes are light-domain → live under `src/light/` (file split decided in the stage plan). +- **The shared primitive library** (file split — one `light/Fx.h` vs focused `light/Beat.h`/`Noise.h`/`Blend.h` — decided in the stage plan; recognisable names, our implementation, FastLED credited as prior art). Hot-path-tuned, integer-only, LUT-backed: + - *timing/beat:* `beatsin8/16`, `beat8/16`, `triwave8` (on `sin8` + `elapsed()`). + - *noise:* `inoise8` 1D/2D/3D (promote + generalise `NoiseEffect`'s existing hash — the textbook value/Perlin noise). + - *blend/scale:* `qadd8`/`qsub8` (saturating), `nscale8`, `fadeToBlackBy`, `blend(RGB, RGB, amt)` (`scale8` already in `color.h`). + - *random:* `random8`/`random16` — a small fast seedable PRNG, hot-path-cheap (not `std::rand`). + - *draw (the dimension-agnostic part the product owner called out):* `drawPixel`/`drawLine` (and later `drawCircle`/fill) operating on `Coord3D`, working **1D→3D** against the `Buffer`, so effects and modifiers share one set instead of re-rolling Bresenham per effect. This is the "core absorbs the hard part" principle — geometry primitives live once. +- **Re-port Game of Life** properly — the *real* MoonLight GoL algorithm (the cellular-automaton rules + its palette colouring + blur/mutation it actually uses), on top of the new palette + primitives, replacing the current 272-line version. This is the stage's proof: a real effect that exercises palette + random + neighbour math, done faithfully. +- **Tags/emoji legend.** Write the canonical legend (MoonLight as basis) into architecture.md § Web UI / a tags reference, and sweep existing effects' `tags()` to match. Lightweight. + +Stage-1 exit: palette + primitives compile (-Werror), are unit-tested (each primitive pinned: `beatsin8` range, `inoise8` determinism, `qadd8` saturation, `drawLine` endpoints in 1D/2D/3D), GoL re-port renders correctly + has a scenario, tags legend documented. **No doc explosion yet** (GoL keeps its existing single `.md`; the doc-model change is Stage 2). + +### Stage 2 — Doc model: per-library pages + +Before migrating dozens of effects (which would create dozens of `.md`s), switch the doc model. The naming + structure is fixed by the [folder-structure decision](../../backlog/folder-structure-proposal.md): **`src`/`assets`/`tests` are `domain/type` folders, flat — library is NOT a folder there**, only a `tags()` emoji; **docs** are the one place library splits, as a **page name** (type-first, underscore-joined, matching how you'd read the folder path): `effects_moonlight.md`, `effects_wled.md`, `effects_projectmm.md`, … (and `modifiers_.md` etc. only where a library has that type — most libraries are effects-only). + +- **New per-library pages:** each effect is a **compact table row** — `| name + tags | gif | one-line description | controls |` — dropping the per-module `Tests`/`Design notes`/`Source` boilerplate (source is derivable, tests auto-discovered), so a ~30-effect page is ~120 lines (avoids both the per-module explosion *and* the one-giant-file extreme). Migrate the ~21 existing per-module effect specs into the right `effects_.md` by origin (from each effect's "Prior art"/tags — see the effect inventory reference). A short index page links the set. +- **Rewrite `check_specs.py`** to the new contract: every registered module's **control names** must appear *somewhere in its library page* (preserves the anti-drift guarantee the per-module check gave). The `registerType` second arg changes from `Foo.md` to the library page (`effects_moonlight.md`, or `…#foo`). +- **Gifs:** the per-module asset *move* is **already done** (assets are now `docs/assets/{core, light/{effects,…}}/` per the folder decision). What remains for this stage: **download MoonLight's preview gifs** (the WLED-Utils `FX_*.gif` set + the user-attachment gifs listed on MoonLight's effects/layouts/modifiers/drivers pages) into the matching `light/effects/…` folders as the new effects land, crediting source. +- **Wire-contract docs** that don't fit a table row (the genuinely technical ones — HueDriver's API, NetworkSend's protocols) keep a deeper section; the library page links to it. + +Stage-2 exit: the library pages render with gifs, `check_specs.py` green on the new contract, the per-module effect `.md`s deleted (subtraction). This is the "kills the explosion permanently" stage. + +### Stage 3+ — Effect migration in batches + +With foundations + doc model in place, migrate MoonLight effects in **themed batches**, each a stage/commit: study behaviour → write fresh on our primitives → unit + scenario test → add to `effects.md` + gif. Batching keeps each commit reviewable. Proposed batch order (by dependency/complexity, refine per batch): + +- **3a — simple 2D/3D non-audio** (the `E_MoonLight` / `E_WLED` geometric ones: lines, scrolling, lissajous, distortion, starfield…). +- **3b — palette-heavy** (now that palettes exist: the gradient/noise/plasma family not yet ported). +- **3c — particle/physics** (bouncing balls, popcorn, blackhole — build on the draw primitives + PRNG). +- **3d — audio-reactive (♫)** (GEQ, Blurz, Waverly, FreqMatrix… — depend on `AudioModule::latestFrame()`; a shared audio-read helper may be its own small sub-stage). +- **3e — text/scrolling** (scrolling text needs a font + glyph blitter — its own primitive). + +### Stage 4 — Modifiers + layouts migration + +The MoonLight modifiers (mirror/tile/kaleidoscope/pinwheel/transpose…) and layouts (panel/cube/ring/sphere/spiral/fixture variants) not yet ported. Modifiers are pure geometry (they fit our modifier model cleanly — and per architecture.md, geometry transforms belong in modifiers, not effects). Layouts are coordinate iterators. Smaller than the effect batches; can interleave with Stage 3. + +### Stage 5 — Moving heads / DMX fixtures (last) + +`E_MovingHeads` + fixture layouts + Art-Net moving-head control. Most specialised, fewest dependencies on the rest; deferred to last. + +## Riskiest parts + +1. **Palette + primitives are the load-bearing wall** — if their API or performance is wrong, every later effect inherits it. Stage 1 must get the hot-path shape right (measure tick cost; these run per-light). Worth over-investing in. +2. **Primitive implementation is ours** — the temptation under deadline is to copy a source's implementation, not just its recognisable name. The names follow the established FastLED convention (what a contributor recognises); the *code* is written fresh against our engine, behaviour pinned by tests, FastLED credited as prior art. Guard: independence-by-construction (own implementation + own architecture), not a renamed copy and not a traced one. +3. **Dimension-agnostic draw** — making `drawLine` etc. genuinely 1D→3D (not 2D with a z-loop bolted on) needs thought; get the abstraction right in Stage 1 or effects will work around it. +4. **Doc-model migration is a one-way door** — deleting 21 per-module `.md`s and rewriting the spec-check; do it as one coherent Stage-2 change, not piecemeal, so docs are never half-migrated. +5. **GoL "done right"** — we already got it wrong once; Stage 1 must pin the real algorithm against a reference (the actual rules + colouring), tested, so it's faithful this time. +6. **Scope discipline** — "migrate all of it" is dozens of modules. The batching is what keeps it from becoming one un-reviewable mega-diff; resist merging batches. + +## Verification (per stage) + +Every stage: desktop build (-Werror), `ctest` (new primitives/effects pinned), scenarios, spec-check, ESP32 build, KPI (watch the per-light hot-path cost as primitives land). Bench on hardware for the visual effects. Each stage saves its own `/plan` and commits independently. + +## Open questions (settle at each stage, not now) + +- Exact home + file split of the primitive library (one `Fx.h` vs several focused headers) — Stage 1 plan. +- Palette storage (flash tables vs computed gradients) + how the UI selects a palette (a `palette` control type?) — Stage 1 plan. +- The `registerType` → category-page mapping mechanics — Stage 2 plan. +- Per-batch effect list + order — each Stage-3 sub-plan. diff --git a/docs/install/README.md b/docs/install/README.md index 0c0571f8..6fcc8ddd 100644 --- a/docs/install/README.md +++ b/docs/install/README.md @@ -62,7 +62,7 @@ labelled summary with a thumbnail: | Collapsed | Expanded | |---|---| -| ![Board picker collapsed](../assets/screenshots/installer-board-picker-collapsed.png) | ![Board picker expanded](../assets/screenshots/installer-board-picker-expanded.png) | +| ![Board picker collapsed](../assets/ui/installer-board-picker-collapsed.png) | ![Board picker expanded](../assets/ui/installer-board-picker-expanded.png) | ## Catalog schema (`deviceModels.json`) diff --git a/docs/moonmodules/core/DevicesModule.md b/docs/moonmodules/core/DevicesModule.md index 07090260..44db02a1 100644 --- a/docs/moonmodules/core/DevicesModule.md +++ b/docs/moonmodules/core/DevicesModule.md @@ -1,6 +1,6 @@ # DevicesModule -![DevicesModule controls](../../assets/screenshots/Devices%20module.png) +![DevicesModule controls](../../assets/core/Devices%20module.png) A **core**, domain-neutral module that discovers other devices on the LAN, identifies what each is, and presents them as a browsable list. It focuses on *all* devices on the network (including this one, marked as self), not on the host's own state — so its card looks the same on every projectMM instance, ESP32 or PC. Light-domain modules consume the device list; the discovery machinery itself stays domain-neutral. @@ -48,11 +48,11 @@ Because the presence broadcast and the mDNS advertise are WLED-shaped, a project **In WLED's own "Sync interfaces" instances list** — a real WLED lists every projectMM board it heard on UDP 65506. (The `undefined` columns are WLED-sync fields projectMM doesn't fill — the presence packet carries identity, not the full WLED sync state; listing is what we're after.) -![projectMM devices in WLED's instances list](../../assets/screenshots/Wled%20discovers%20projectMM.png) +![projectMM devices in WLED's instances list](../../assets/core/Wled%20discovers%20projectMM.png) **In the native WLED app** (iOS / Android) — discovered via the mDNS `_wled._tcp` advertise, validated via the `/json/info` shim, with live colour + a working brightness slider over the `/ws` WebSocket. See [HttpServerModule § WLED-compatibility shim](HttpServerModule.md#wled-compatibility-shim) for the wire contract (reverse-engineered from the [WLED-Android](https://github.com/Moustachauve/WLED-Android) client). -![projectMM devices in the native WLED app](../../assets/screenshots/WLED%20Native%20discovers%20projectMM.jpeg) +![projectMM devices in the native WLED app](../../assets/core/WLED%20Native%20discovers%20projectMM.jpeg) ## Transport boundary (discovery vs commands) diff --git a/docs/moonmodules/core/FilesystemModule.md b/docs/moonmodules/core/FilesystemModule.md index a8d37a6a..ce8c95bd 100644 --- a/docs/moonmodules/core/FilesystemModule.md +++ b/docs/moonmodules/core/FilesystemModule.md @@ -1,6 +1,6 @@ # FilesystemModule -![FilesystemModule controls](../../assets/screenshots/FilesystemModule.png) +![FilesystemModule controls](../../assets/core/FilesystemModule.png) Persists control values to flash so settings survive a reboot. Always loaded, runs first in the scheduler so its load hook fires before any other module's `setup()`. diff --git a/docs/moonmodules/core/FirmwareUpdateModule.md b/docs/moonmodules/core/FirmwareUpdateModule.md index 491eba50..0d7e9838 100644 --- a/docs/moonmodules/core/FirmwareUpdateModule.md +++ b/docs/moonmodules/core/FirmwareUpdateModule.md @@ -1,6 +1,6 @@ # FirmwareUpdateModule -![FirmwareUpdateModule controls](../../assets/screenshots/FirmwareUpdateModule.png) +![FirmwareUpdateModule controls](../../assets/core/FirmwareUpdateModule.png) A thin status surface for OTA flashing. The flash itself is driven by `POST /api/firmware/url` in HttpServerModule, which hands the URL to `platform::http_fetch_to_ota` (a task that downloads via `esp_https_ota` and writes the next OTA partition). The task and this module communicate through shared file-scope globals; the module polls them in `loop1s()` and the existing WebSocket state push surfaces the change at 1 Hz. diff --git a/docs/moonmodules/core/NetworkModule.md b/docs/moonmodules/core/NetworkModule.md index 419fd7d9..afa62b45 100644 --- a/docs/moonmodules/core/NetworkModule.md +++ b/docs/moonmodules/core/NetworkModule.md @@ -1,6 +1,6 @@ # NetworkModule -![NetworkModule controls](../../assets/screenshots/NetworkModule.png) +![NetworkModule controls](../../assets/core/NetworkModule.png) Manages all device connectivity with automatic fallback: Ethernet → WiFi STA → WiFi AP. One MoonModule, one UI card — the user sees "Network", not three separate technologies. diff --git a/docs/moonmodules/core/SystemModule.md b/docs/moonmodules/core/SystemModule.md index a9d00b06..27b4cb94 100644 --- a/docs/moonmodules/core/SystemModule.md +++ b/docs/moonmodules/core/SystemModule.md @@ -1,6 +1,6 @@ # SystemModule -![SystemModule controls](../../assets/screenshots/SystemModule.png) +![SystemModule controls](../../assets/core/SystemModule.png) System-level diagnostics and device identity. Always loaded, always visible in the UI. diff --git a/docs/moonmodules/light/Drivers.md b/docs/moonmodules/light/Drivers.md index ce91f3f2..da15def5 100644 --- a/docs/moonmodules/light/Drivers.md +++ b/docs/moonmodules/light/Drivers.md @@ -1,6 +1,6 @@ # Drivers -![Drivers controls](../../assets/screenshots/Drivers.png) +![Drivers controls](../../assets/light/drivers/Drivers.png) Top-level container for one or more drivers. The consumer side of the pipeline — owns the shared output buffer (when memory allows) and performs blend+map from every layer's buffer into it each frame. diff --git a/docs/moonmodules/light/Layers.md b/docs/moonmodules/light/Layers.md index ef475279..57c61ed9 100644 --- a/docs/moonmodules/light/Layers.md +++ b/docs/moonmodules/light/Layers.md @@ -1,6 +1,6 @@ # Layers -![Layers controls](../../assets/screenshots/Layers.png) +![Layers controls](../../assets/core/Layers.png) Top-level container for one or more layers. Each layer renders independently into its own buffer; the Drivers container composes those buffers downstream. diff --git a/docs/moonmodules/light/Layouts.md b/docs/moonmodules/light/Layouts.md index a96629e5..bd31f33c 100644 --- a/docs/moonmodules/light/Layouts.md +++ b/docs/moonmodules/light/Layouts.md @@ -1,6 +1,6 @@ # Layouts -![Layouts controls](../../assets/screenshots/Layouts.png) +![Layouts controls](../../assets/core/Layouts.png) Top-level container for one or more layouts. Shared by every layer in the Layers container — defines the physical light topology of the installation. diff --git a/docs/moonmodules/light/drivers/HueDriver.md b/docs/moonmodules/light/drivers/HueDriver.md index ce825969..5fd4dd08 100644 --- a/docs/moonmodules/light/drivers/HueDriver.md +++ b/docs/moonmodules/light/drivers/HueDriver.md @@ -2,7 +2,7 @@ Drives **Philips Hue lights as a projectMM output** — the bulbs are *pixels of an effect*, not entries in a device list. Make a small grid (e.g. 4×1×1), run any effect on it, add a HueDriver, and each colour bulb in the driver's window becomes one pixel: the effect's per-pixel colour is pushed to the bridge as hue/saturation/brightness. It is a [driver](../../core/architecture.md) like any other (a sibling of [NetworkSendDriver](NetworkSendDriver.md) / [RmtLedDriver](RmtLedDriver.md)) — it reads its slice of the shared buffer and sends it out, here over the Hue HTTP API instead of a wire protocol. -![A HueDriver in the UI](../../../assets/screenshots/Hue%20driver.png) +![A HueDriver in the UI](../../../assets/light/drivers/Hue%20driver.png) ## What makes Hue different (and why the driver is shaped this way) @@ -15,7 +15,7 @@ Hue is an HTTP hub, not a strip, and these properties drive the design: - **It needs an app key** (a "username"): the user presses the bridge's physical link button once, then the device claims a key. The driver runs this as a short bounded poll across a few 1 Hz ticks — never blocking the loop waiting for the press. - **It's plain HTTP, no TLS.** The Hue v1 API answers over `http:///api/...`, so there is no certificate handling on the device. Bench-confirmed against a BSB002 bridge (API 1.77). -![An effect driving the Hue lights](../../../assets/screenshots/Hue%20friendly%20effect.png) +![An effect driving the Hue lights](../../../assets/light/drivers/Hue%20friendly%20effect.png) ## Controls @@ -28,7 +28,7 @@ Hue is an HTTP hub, not a strip, and these properties drive the design: Once paired, the driver also **lists the bridge in [DevicesModule](../../core/DevicesModule.md)** (alongside discovered WLED / projectMM peers), carrying its name and the colour-light count, refreshed on a slow cadence. It registers through `DevicesModule::active()` — the same static-accessor seam [AudioModule](../../core/AudioModule.md) uses for `latestFrame()`, so the light-domain driver reaches the core module without a structural dependency. -![The Hue bridge listed in the Devices module](../../../assets/screenshots/Hue%20device%20disco.png) +![The Hue bridge listed in the Devices module](../../../assets/core/Hue%20device%20disco.png) ## Wire contract (Hue v1 API, plain HTTP) diff --git a/docs/moonmodules/light/drivers/NetworkSendDriver.md b/docs/moonmodules/light/drivers/NetworkSendDriver.md index 47dc3ccf..99bcfa33 100644 --- a/docs/moonmodules/light/drivers/NetworkSendDriver.md +++ b/docs/moonmodules/light/drivers/NetworkSendDriver.md @@ -1,6 +1,6 @@ # Network Send Driver -![NetworkSendDriver controls](../../../assets/screenshots/NetworkSendDriver.png) +![NetworkSendDriver controls](../../../assets/light/drivers/NetworkSendDriver.png) Streams the light buffer over UDP in one of three industry protocols, selected by a control: **[Art-Net](https://art-net.org.uk/downloads/art-net.pdf)**, **[E1.31 / sACN](https://tsp.esta.org/tsp/documents/docs/ANSI_E1-31-2018.pdf)** (the ANSI E1.31 streaming-ACN standard), or **[DDP](http://www.3waylabs.com/ddp/)** (Distributed Display Protocol). Reads the Drivers container's buffer, applies the shared [Correction](Correction.md) (brightness / channel order / RGBW white) per light, chunks the corrected bytes per the selected protocol, and sends the whole frame as one burst at the configured rate. The single-node-multiple-protocols shape follows MoonLight's D_NetworkOut (architecture studied, not copied). Compatible with industry receivers — pixel controllers (Falcon, Advatek), xLights, LedFx, and ArtNet-controllable software. diff --git a/docs/moonmodules/light/drivers/PreviewDriver.md b/docs/moonmodules/light/drivers/PreviewDriver.md index f4626fac..a6547d49 100644 --- a/docs/moonmodules/light/drivers/PreviewDriver.md +++ b/docs/moonmodules/light/drivers/PreviewDriver.md @@ -1,6 +1,6 @@ # Preview Driver -![PreviewDriver controls](../../../assets/screenshots/PreviewDriver.png) +![PreviewDriver controls](../../../assets/light/drivers/PreviewDriver.png) Streams a true-shape 3D preview to the web UI over WebSocket. The preview is a **point list** — only the real lights, at their real positions — not a dense grid. So a sphere, ring, or arbitrary fixture map shows in its true shape, and the per-frame data is just the lights that exist (much less than a padded bounding box). diff --git a/docs/moonmodules/light/effects/CheckerboardEffect.md b/docs/moonmodules/light/effects/CheckerboardEffect.md index bddbb9c4..7c04aaa6 100644 --- a/docs/moonmodules/light/effects/CheckerboardEffect.md +++ b/docs/moonmodules/light/effects/CheckerboardEffect.md @@ -1,8 +1,8 @@ # Checkerboard 2D Effect -![CheckerboardEffect controls](../../../assets/screenshots/CheckerboardEffect.png) +![CheckerboardEffect controls](../../../assets/light/effects/CheckerboardEffect.png) -![CheckerboardEffect preview](../../../assets/screenshots/CheckerboardEffect.gif) +![CheckerboardEffect preview](../../../assets/light/effects/CheckerboardEffect.gif) Animated checker pattern with two configurable hues. diff --git a/docs/moonmodules/light/effects/FireEffect.md b/docs/moonmodules/light/effects/FireEffect.md index 92aec26e..acde6c31 100644 --- a/docs/moonmodules/light/effects/FireEffect.md +++ b/docs/moonmodules/light/effects/FireEffect.md @@ -1,8 +1,8 @@ # Fire 2D Effect -![FireEffect controls](../../../assets/screenshots/FireEffect.png) +![FireEffect controls](../../../assets/light/effects/FireEffect.png) -![FireEffect preview](../../../assets/screenshots/FireEffect.gif) +![FireEffect preview](../../../assets/light/effects/FireEffect.gif) Classic demoscene fire simulation on the XY plane. Maintains a `width x height` heat field; sparks spawn at the bottom row, drift upward with cooling, and are mapped to a black-red-yellow-white palette. diff --git a/docs/moonmodules/light/effects/GameOfLifeEffect.md b/docs/moonmodules/light/effects/GameOfLifeEffect.md index 38ed7595..e65ac142 100644 --- a/docs/moonmodules/light/effects/GameOfLifeEffect.md +++ b/docs/moonmodules/light/effects/GameOfLifeEffect.md @@ -1,8 +1,8 @@ # Game of Life Effect -![GameOfLifeEffect controls](../../../assets/screenshots/GameOfLifeEffect.png) +![GameOfLifeEffect controls](../../../assets/light/effects/GameOfLifeEffect.png) -![GameOfLifeEffect preview](../../../assets/screenshots/GameOfLifeEffect.gif) +![GameOfLifeEffect preview](../../../assets/light/effects/GameOfLifeEffect.gif) Conway's Game of Life (B3/S23) on the XY plane. A D2 effect: it simulates the z=0 plane and `Layer::extrude` fills z on 3D layers. diff --git a/docs/moonmodules/light/effects/GlowParticlesEffect.md b/docs/moonmodules/light/effects/GlowParticlesEffect.md index 8b606736..2161eccc 100644 --- a/docs/moonmodules/light/effects/GlowParticlesEffect.md +++ b/docs/moonmodules/light/effects/GlowParticlesEffect.md @@ -1,8 +1,8 @@ # Glow Particles 2D Effect -![GlowParticlesEffect controls](../../../assets/screenshots/GlowParticlesEffect.png) +![GlowParticlesEffect controls](../../../assets/light/effects/GlowParticlesEffect.png) -![GlowParticlesEffect preview](../../../assets/screenshots/GlowParticlesEffect.gif) +![GlowParticlesEffect preview](../../../assets/light/effects/GlowParticlesEffect.gif) Soft-glowing particles rendered as a metaball field. Particles move with independent velocities and bounce off the edges; the per-pixel field summation produces chaotic organic blobs — like `MetaballsEffect` with more freedom of movement. diff --git a/docs/moonmodules/light/effects/LavaLampEffect.md b/docs/moonmodules/light/effects/LavaLampEffect.md index b078b933..e481f11d 100644 --- a/docs/moonmodules/light/effects/LavaLampEffect.md +++ b/docs/moonmodules/light/effects/LavaLampEffect.md @@ -1,8 +1,8 @@ # Lava Lamp 2D Effect -![LavaLampEffect controls](../../../assets/screenshots/LavaLampEffect.png) +![LavaLampEffect controls](../../../assets/light/effects/LavaLampEffect.png) -![LavaLampEffect preview](../../../assets/screenshots/LavaLampEffect.gif) +![LavaLampEffect preview](../../../assets/light/effects/LavaLampEffect.gif) Three slow blobs whose summed field is mapped through a black → red → orange → yellow → white palette. Atmospheric, fluid look — like a real lava lamp rather than the bright HSV of `MetaballsEffect`. diff --git a/docs/moonmodules/light/effects/LinesEffect.md b/docs/moonmodules/light/effects/LinesEffect.md index 9290b792..42f4cef3 100644 --- a/docs/moonmodules/light/effects/LinesEffect.md +++ b/docs/moonmodules/light/effects/LinesEffect.md @@ -1,8 +1,8 @@ # LinesEffect -![LinesEffect controls](../../../assets/screenshots/LinesEffect.png) +![LinesEffect controls](../../../assets/light/effects/LinesEffect.png) -![LinesEffect preview](../../../assets/screenshots/LinesEffect.gif) +![LinesEffect preview](../../../assets/light/effects/LinesEffect.gif) Sweeps one or more axis-aligned planes across the grid in sync at a given BPM. Each plane is a distinct colour: red (YZ, sweeps along X), green (XZ, sweeps along Y), blue (XY, sweeps along Z). Useful for verifying preview axis orientation — each colour names the axis it sweeps. diff --git a/docs/moonmodules/light/effects/MetaballsEffect.md b/docs/moonmodules/light/effects/MetaballsEffect.md index 660deea2..c48031ee 100644 --- a/docs/moonmodules/light/effects/MetaballsEffect.md +++ b/docs/moonmodules/light/effects/MetaballsEffect.md @@ -1,8 +1,8 @@ # Metaballs 2D Effect -![MetaballsEffect controls](../../../assets/screenshots/MetaballsEffect.png) +![MetaballsEffect controls](../../../assets/light/effects/MetaballsEffect.png) -![MetaballsEffect preview](../../../assets/screenshots/MetaballsEffect.gif) +![MetaballsEffect preview](../../../assets/light/effects/MetaballsEffect.gif) Four "blobs" moving on the XY plane via integer sin/cos, with a metaball field summation per pixel. Visually similar to a lava lamp — blobs fluidly merge and separate. diff --git a/docs/moonmodules/light/effects/NoiseEffect.md b/docs/moonmodules/light/effects/NoiseEffect.md index 2b32921c..9bda5f92 100644 --- a/docs/moonmodules/light/effects/NoiseEffect.md +++ b/docs/moonmodules/light/effects/NoiseEffect.md @@ -1,8 +1,8 @@ # Noise Effect -![NoiseEffect controls](../../../assets/screenshots/NoiseEffect.png) +![NoiseEffect controls](../../../assets/light/effects/NoiseEffect.png) -![NoiseEffect preview](../../../assets/screenshots/NoiseEffect.gif) +![NoiseEffect preview](../../../assets/light/effects/NoiseEffect.gif) Smooth animated noise. Samples a 2D field on flat (`depth == 1`) layouts and a true 3D field on volumetric (`depth > 1`) layouts, so a cube renders as a varied volume rather than stacked identical slices. diff --git a/docs/moonmodules/light/effects/ParticlesEffect.md b/docs/moonmodules/light/effects/ParticlesEffect.md index c4d6cc0c..13efe0da 100644 --- a/docs/moonmodules/light/effects/ParticlesEffect.md +++ b/docs/moonmodules/light/effects/ParticlesEffect.md @@ -1,8 +1,8 @@ # Particles 2D Effect -![ParticlesEffect controls](../../../assets/screenshots/ParticlesEffect.png) +![ParticlesEffect controls](../../../assets/light/effects/ParticlesEffect.png) -![ParticlesEffect preview](../../../assets/screenshots/ParticlesEffect.gif) +![ParticlesEffect preview](../../../assets/light/effects/ParticlesEffect.gif) A swarm of particles drifting on the XY plane with persistent trails. Each particle has fixed-point position, velocity, and hue. A private RGB trail buffer is faded each frame, particles are drawn on top, and the trail buffer is copied to the layer buffer (which the Layer clears every frame). diff --git a/docs/moonmodules/light/effects/PlasmaEffect.md b/docs/moonmodules/light/effects/PlasmaEffect.md index 489c50f2..3a8e832e 100644 --- a/docs/moonmodules/light/effects/PlasmaEffect.md +++ b/docs/moonmodules/light/effects/PlasmaEffect.md @@ -1,8 +1,8 @@ # Plasma Effect -![PlasmaEffect controls](../../../assets/screenshots/PlasmaEffect.png) +![PlasmaEffect controls](../../../assets/light/effects/PlasmaEffect.png) -![PlasmaEffect preview](../../../assets/screenshots/PlasmaEffect.gif) +![PlasmaEffect preview](../../../assets/light/effects/PlasmaEffect.gif) Animated plasma pattern from summed sine waves on orthogonal and diagonal axes. Default effect in the desktop and ESP32 pipeline. 2D on flat (`depth == 1`) layouts, 3D on volumetric (`depth > 1`) layouts so a cube renders as a varied volume. diff --git a/docs/moonmodules/light/effects/PlasmaPaletteEffect.md b/docs/moonmodules/light/effects/PlasmaPaletteEffect.md index 87be51f4..8dad1602 100644 --- a/docs/moonmodules/light/effects/PlasmaPaletteEffect.md +++ b/docs/moonmodules/light/effects/PlasmaPaletteEffect.md @@ -1,8 +1,8 @@ # Plasma Palette 2D Effect -![PlasmaPaletteEffect controls](../../../assets/screenshots/PlasmaPaletteEffect.png) +![PlasmaPaletteEffect controls](../../../assets/light/effects/PlasmaPaletteEffect.png) -![PlasmaPaletteEffect preview](../../../assets/screenshots/PlasmaPaletteEffect.gif) +![PlasmaPaletteEffect preview](../../../assets/light/effects/PlasmaPaletteEffect.gif) Same four-sine plasma field as `PlasmaEffect`, but colours come from a 256-entry fire-ocean RGB palette in flash instead of `hsvToRgb`. diff --git a/docs/moonmodules/light/effects/RainbowEffect.md b/docs/moonmodules/light/effects/RainbowEffect.md index 5cf87545..82290ce7 100644 --- a/docs/moonmodules/light/effects/RainbowEffect.md +++ b/docs/moonmodules/light/effects/RainbowEffect.md @@ -1,8 +1,8 @@ # Rainbow 2D Effect -![RainbowEffect controls](../../../assets/screenshots/RainbowEffect.png) +![RainbowEffect controls](../../../assets/light/effects/RainbowEffect.png) -![RainbowEffect preview](../../../assets/screenshots/RainbowEffect.gif) +![RainbowEffect preview](../../../assets/light/effects/RainbowEffect.gif) Diagonal rainbow pattern across a 2D grid, animated over time. Good default/test effect — always produces visible, colorful output. diff --git a/docs/moonmodules/light/effects/RingsEffect.md b/docs/moonmodules/light/effects/RingsEffect.md index 7f3d4449..c2dd6c50 100644 --- a/docs/moonmodules/light/effects/RingsEffect.md +++ b/docs/moonmodules/light/effects/RingsEffect.md @@ -1,8 +1,8 @@ # Rings 2D Effect -![RingsEffect controls](../../../assets/screenshots/RingsEffect.png) +![RingsEffect controls](../../../assets/light/effects/RingsEffect.png) -![RingsEffect preview](../../../assets/screenshots/RingsEffect.gif) +![RingsEffect preview](../../../assets/light/effects/RingsEffect.gif) Expanding concentric rings from random centre points. Each ring grows outward and respawns once it has expanded past the visible area. Multiple rings overlap with additive blending. diff --git a/docs/moonmodules/light/effects/RipplesEffect.md b/docs/moonmodules/light/effects/RipplesEffect.md index 5ef2d96c..5e051c93 100644 --- a/docs/moonmodules/light/effects/RipplesEffect.md +++ b/docs/moonmodules/light/effects/RipplesEffect.md @@ -1,8 +1,8 @@ # Ripples 3D Effect -![RipplesEffect controls](../../../assets/screenshots/RipplesEffect.png) +![RipplesEffect controls](../../../assets/light/effects/RipplesEffect.png) -![RipplesEffect preview](../../../assets/screenshots/RipplesEffect.gif) +![RipplesEffect preview](../../../assets/light/effects/RipplesEffect.gif) 3D dancing sine-wave ripples — a reimplementation of MoonLight's Ripples. For each `(x, z)` column on the floor plane, the distance from the centre sets a wave phase, and one pixel per column is lit at the height `y = floor(h/2 · (1 + sin(dist / interval + time)))`. The lit surface ripples like water filling the volume, with the hue cycling over time and position. diff --git a/docs/moonmodules/light/effects/SpiralEffect.md b/docs/moonmodules/light/effects/SpiralEffect.md index 7c268169..65efb77c 100644 --- a/docs/moonmodules/light/effects/SpiralEffect.md +++ b/docs/moonmodules/light/effects/SpiralEffect.md @@ -1,8 +1,8 @@ # Spiral 2D Effect -![SpiralEffect controls](../../../assets/screenshots/SpiralEffect.png) +![SpiralEffect controls](../../../assets/light/effects/SpiralEffect.png) -![SpiralEffect preview](../../../assets/screenshots/SpiralEffect.gif) +![SpiralEffect preview](../../../assets/light/effects/SpiralEffect.gif) Rotating spiral from angle + distance. Uses shared `atan2_8` and `dist8` in `core/color.h`. diff --git a/docs/moonmodules/light/effects/WaveEffect.md b/docs/moonmodules/light/effects/WaveEffect.md index 38fbddd6..60d72f1f 100644 --- a/docs/moonmodules/light/effects/WaveEffect.md +++ b/docs/moonmodules/light/effects/WaveEffect.md @@ -20,11 +20,11 @@ This follows the project's [1D-runs-along-Y convention](../../architecture.md#di Per column `x`, the wave's phase is `t + x·skew`: `t` advances from `bpm` (an integer accumulator, so a sub-millisecond frame time isn't lost), and the `x·skew` term delays each column so the shape appears to move horizontally. The phase runs through the selected waveform to a y in `[0, height)`; that pixel is lit, and for the discontinuous shapes (sawtooth, square) a vertical segment joins it to the previous column so the line stays connected. The wave's colour cycles slowly over time. -**Palette readiness:** the colour comes from a single `waveColor(index)` seam — today an `hsvToRgb` hue sweep. When palettes land, that one function becomes the palette lookup with no other change. +The colour comes from a single `waveColor(index)` seam — an `hsvToRgb` hue sweep — so the wave's colouring lives in one place. ## Prior art -[MoonLight](https://github.com/MoonModules/MoonLight)'s Wave effect (Ewoud Wijma). The *behaviour* is reproduced — the six waveform types, the per-column phase travel, the time-varying colour, the frame fade — written fresh against projectMM's `EffectBase` and integer primitives (the `sin8` LUT, `scale8`), with the colour routed through a palette-ready seam rather than MoonLight's `ColorFromPalette` (palettes aren't in projectMM yet). +[MoonLight](https://github.com/MoonModules/MoonLight)'s Wave effect (Ewoud Wijma). The *behaviour* is reproduced — the six waveform types, the per-column phase travel, the time-varying colour, the frame fade — written fresh against projectMM's `EffectBase` and integer primitives (the `sin8` LUT, `scale8`); the colour is an `hsvToRgb` sweep through the `waveColor` seam. ## Source diff --git a/docs/moonmodules/light/layouts/GridLayout.md b/docs/moonmodules/light/layouts/GridLayout.md index 1abe202c..f7780cf7 100644 --- a/docs/moonmodules/light/layouts/GridLayout.md +++ b/docs/moonmodules/light/layouts/GridLayout.md @@ -1,6 +1,6 @@ # Grid Layout -![GridLayout controls](../../../assets/screenshots/GridLayout.png) +![GridLayout controls](../../../assets/light/layouts/GridLayout.png) Arranges lights in a 3D grid, row-major (x fastest, then y, then z). Full-density — every position maps to a light. Controls: `width`, `height`, `depth`, `serpentine`. diff --git a/docs/moonmodules/light/modifiers/CheckerboardModifier.md b/docs/moonmodules/light/modifiers/CheckerboardModifier.md index ee6395fb..b2f4cfa4 100644 --- a/docs/moonmodules/light/modifiers/CheckerboardModifier.md +++ b/docs/moonmodules/light/modifiers/CheckerboardModifier.md @@ -1,8 +1,8 @@ # Checkerboard Modifier -![CheckerboardModifier controls](../../../assets/screenshots/CheckerboardModifier.png) +![CheckerboardModifier controls](../../../assets/light/modifiers/CheckerboardModifier.png) -![CheckerboardModifier preview](../../../assets/screenshots/CheckerboardModifier.gif) +![CheckerboardModifier preview](../../../assets/light/modifiers/CheckerboardModifier.gif) Static modifier. Masks the layer in a checkerboard pattern: lights in the "off" squares are dropped (they receive nothing), lights in the "on" squares pass through unchanged. Unlike Multiply, this doesn't remap or resize — it's a spatial on/off mask applied to whatever the effect drew. diff --git a/docs/moonmodules/light/modifiers/MultiplyModifier.md b/docs/moonmodules/light/modifiers/MultiplyModifier.md index 96b3d661..dc003d0e 100644 --- a/docs/moonmodules/light/modifiers/MultiplyModifier.md +++ b/docs/moonmodules/light/modifiers/MultiplyModifier.md @@ -1,8 +1,8 @@ # Multiply Modifier -![MultiplyModifier controls](../../../assets/screenshots/MultiplyModifier.png) +![MultiplyModifier controls](../../../assets/light/modifiers/MultiplyModifier.png) -![MultiplyModifier preview](../../../assets/screenshots/MultiplyModifier.gif) +![MultiplyModifier preview](../../../assets/light/modifiers/MultiplyModifier.gif) Static modifier. Tiles the logical image across the physical box `multiply` times per axis, optionally reflecting alternate tiles. With a multiplier of 2 and mirror enabled on an axis, that axis folds in half — the classic kaleidoscope mirror. Multiply subsumes the old MirrorModifier: a pure mirror is `multiply = 2, mirror = true` on the chosen axes. diff --git a/docs/testing.md b/docs/testing.md index 3cb322a4..cae3c299 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -389,7 +389,7 @@ uv run scripts/scenario/run_live_scenario.py --compare-baseline # check MoonDeck's Live tab wraps the same workflow: the Network bar at the top selects the LAN, Discover/Refresh populates the device list, the Live Scenarios card runs the selected scenario against every checked device. -![MoonDeck Live tab](assets/screenshots/moondeck_live.png) +![MoonDeck Live tab](assets/ui/moondeck_live.png) All scenarios use relative FPS bounds (`min_pct`) so they pass on any device — desktop at 10K FPS or ESP32 at 17 FPS. Settle time is 3 seconds to let the pipeline stabilise after rebuilds. diff --git a/scripts/MoonDeck.md b/scripts/MoonDeck.md index 600f5365..96e62fe8 100644 --- a/scripts/MoonDeck.md +++ b/scripts/MoonDeck.md @@ -21,7 +21,7 @@ Below: the UI behaviours common to every card, described once, then one section ## PC Tab -![Moondeck Pc](../docs/assets/screenshots/moondeck_pc.png) +![Moondeck Pc](../docs/assets/ui/moondeck_pc.png) ### build_desktop @@ -57,9 +57,9 @@ While the app is running, MoonDeck shows the button as **Stop** (a 5-second poll ### preview_installer -![Installer](../docs/assets/screenshots/installer.png) -![Installer2](../docs/assets/screenshots/installer2.png) -![Installer3](../docs/assets/screenshots/installer3.png) +![Installer](../docs/assets/ui/installer.png) +![Installer2](../docs/assets/ui/installer2.png) +![Installer3](../docs/assets/ui/installer3.png) Locally preview the web installer page at without tagging a release. Stages `docs/install/index.html` + `src/ui/install-picker.js` into `build/install-preview/` and serves them via Python's `http.server` on port 8000. @@ -117,7 +117,7 @@ The MoonDeck button writes the file, prints a `MOONDECK_VIEW: /api/history-repor ### screenshot_modules -Capture UI screenshots of every module that has controls and save them to `docs/assets/screenshots/`. +Capture UI screenshots of every module that has controls and save them to `docs/assets/`. ```bash uv run scripts/docs/install_playwright.py # one-time (or use Install Playwright button in MoonDeck) @@ -152,16 +152,16 @@ uv run scripts/docs/update_module_docs.py # update all uv run scripts/docs/update_module_docs.py --dry-run # preview without writing ``` -For each `.md` file, if `docs/assets/screenshots/.png` exists and the file doesn't already contain a screenshot reference, inserts the image after the first heading. If a matching `.gif` also exists, inserts the GIF reference on the next line. Safe to re-run — skips files that already have all references. +For each `.md` file, if `docs/assets//.png` exists and the file doesn't already contain a screenshot reference, inserts the image after the first heading. If a matching `.gif` also exists, inserts the GIF reference on the next line. Safe to re-run — skips files that already have all references. Also inserts MoonDeck tab screenshots and the installer screenshot into `scripts/MoonDeck.md` and `README.md` at fixed anchor points (defined in the `EXTRA_SHOTS` list in the script). -Reports unreferenced screenshots — any PNG or GIF in `docs/assets/screenshots/` not mentioned anywhere in `docs/` or `scripts/`. +Reports unreferenced screenshots — any PNG or GIF in `docs/assets/` not mentioned anywhere in `docs/` or `scripts/`. ## Live Tab -![Moondeck Live](../docs/assets/screenshots/moondeck_live.png) +![Moondeck Live](../docs/assets/ui/moondeck_live.png) ### live_scenario @@ -218,7 +218,7 @@ When the verdict is `CHOPPY`/`DEAD`, the *cause* (which close path fired on the ## ESP32 Tab -![Moondeck Esp32](../docs/assets/screenshots/moondeck_esp32.png) +![Moondeck Esp32](../docs/assets/ui/moondeck_esp32.png) The tab is laid out top-to-bottom along the firmware workflow. Each dropdown sits between the script groups that consume it, so picking a dropdown is the natural prelude to the buttons below it. diff --git a/scripts/docs/screenshot_modules.py b/scripts/docs/screenshot_modules.py index 309a2a56..4d086772 100644 --- a/scripts/docs/screenshot_modules.py +++ b/scripts/docs/screenshot_modules.py @@ -12,14 +12,13 @@ Also captures MoonDeck tab screenshots and the web installer page, and inserts them into the appropriate docs files. -Saves to: - docs/assets/screenshots/.png — module card screenshot - docs/assets/screenshots/.gif — preview animation (effects/modifiers) - docs/assets/screenshots/ui_overview.png — projectMM full-page screenshot - docs/assets/screenshots/moondeck_pc.png — MoonDeck PC tab - docs/assets/screenshots/moondeck_esp32.png — MoonDeck ESP32 tab - docs/assets/screenshots/moondeck_live.png — MoonDeck Live tab - docs/assets/screenshots/installer.png — web installer page +Saves to (by domain/type, mirroring src — see docs/backlog/folder-structure-proposal.md): + docs/assets/light/effects/.png/.gif — effect card + preview + docs/assets/light/{modifiers,layouts,drivers}/ — other light modules + docs/assets/core/.png — core modules + docs/assets/ui/ui_overview.png — projectMM full-page screenshot + docs/assets/ui/moondeck_{pc,esp32,live}.png — MoonDeck tabs + docs/assets/ui/installer.png — web installer page Usage: # one effect, raw (no modifier), good preview size, with its GIF, overwriting: @@ -71,7 +70,18 @@ from playwright.sync_api import sync_playwright, Page ROOT = Path(__file__).resolve().parent.parent.parent -OUT_DIR = ROOT / "docs" / "assets" / "screenshots" +ASSETS = ROOT / "docs" / "assets" +UI_DIR = ASSETS / "ui" # tooling / installer / full-page shots (not per-module) + +# Map a module to its asset subfolder (domain/type), mirroring src. Module screenshots live in +# docs/assets/{core, light/{effects,modifiers,layouts,drivers}}/ — see folder-structure-proposal. +def asset_dir_for(type_name: str) -> Path: + if type_name.endswith("Effect"): return ASSETS / "light" / "effects" + if type_name.endswith("Modifier"): return ASSETS / "light" / "modifiers" + if type_name.endswith("Layout"): return ASSETS / "light" / "layouts" + if type_name.endswith("Driver"): return ASSETS / "light" / "drivers" + if type_name in ("Layouts", "Layers", "Drivers"): return ASSETS / "light" + return ASSETS / "core" # SystemModule, FilesystemModule, DevicesModule, … and the rest # --------------------------------------------------------------------------- # Module catalogue @@ -125,7 +135,7 @@ # --------------------------------------------------------------------------- # Extra shots: MoonDeck tabs + web installer # Each entry: (filename, url, wait_selector, doc_files, anchor_text) -# filename: saved as docs/assets/screenshots/ +# filename: saved as docs/assets/ui/ # url: full URL to load # wait_selector: CSS selector to wait for before screenshotting (or "") # doc_files: list of repo-relative paths to insert image into @@ -701,7 +711,9 @@ def _sweep_orphans(modules: list) -> None: container_names = find_container_nav_names(args.host) core_names = find_core_module_names(args.host) - OUT_DIR.mkdir(parents=True, exist_ok=True) + for _d in (UI_DIR, ASSETS/'core', ASSETS/'light', ASSETS/'light'/'effects', + ASSETS/'light'/'modifiers', ASSETS/'light'/'layouts', ASSETS/'light'/'drivers'): + _d.mkdir(parents=True, exist_ok=True) captured, gif_captured, skipped, failed = [], [], [], [] @@ -716,7 +728,7 @@ def _sweep_orphans(modules: list) -> None: try: # --- Full-page UI overview screenshot --- (needs projectMM) if not args.extras_only: - overview_path = OUT_DIR / "ui_overview.png" + overview_path = UI_DIR / "ui_overview.png" filter_allows = (not filt or filt in "ui_overview") if filter_allows: if not overview_path.exists() or args.force: @@ -742,7 +754,7 @@ def _sweep_orphans(modules: list) -> None: for filename, url, wait_sel, _doc_files, _anchor in EXTRA_SHOTS: if filt and filt not in filename.lower(): continue - out_path = OUT_DIR / filename + out_path = UI_DIR / filename if out_path.exists() and not args.force: print(f" skip {filename} (already captured)") skipped.append((filename, "already exists")) @@ -768,7 +780,7 @@ def _sweep_orphans(modules: list) -> None: cname = container_names.get(container_type, "") if not cname: continue - out_path = OUT_DIR / f"{container_type}.png" + out_path = asset_dir_for(container_type) / f"{container_type}.png" if out_path.exists() and not args.force: print(f" skip {container_type} (already captured)") skipped.append((container_type, "already exists")) @@ -790,7 +802,7 @@ def _sweep_orphans(modules: list) -> None: print(f" skip {type_name} (not in state — ESP32-only?)") skipped.append((type_name, "not in state")) continue - out_path = OUT_DIR / f"{type_name}.png" + out_path = asset_dir_for(type_name) / f"{type_name}.png" if out_path.exists() and not args.force: print(f" skip {type_name} (already captured)") skipped.append((type_name, "already exists")) @@ -807,8 +819,8 @@ def _sweep_orphans(modules: list) -> None: for type_name, parent_type, extra_props, want_gif in MODULES: if filt and filt not in type_name.lower(): continue - out_path = OUT_DIR / f"{type_name}.png" - gif_path = OUT_DIR / f"{type_name}.gif" + out_path = asset_dir_for(type_name) / f"{type_name}.png" + gif_path = asset_dir_for(type_name) / f"{type_name}.gif" need_png = not out_path.exists() or args.force need_gif = want_gif and args.gif and (not gif_path.exists() or args.force) @@ -851,7 +863,7 @@ def _sweep_orphans(modules: list) -> None: print("gif-failed ", end="", flush=True) failed.append((type_name, "gif failed")) - print(f"→ {OUT_DIR.relative_to(ROOT)}/") + print(f"→ {asset_dir_for(type_name).relative_to(ROOT)}/") delete_module(args.host, actual_name) added_ids.remove(actual_name) time.sleep(0.5) @@ -911,7 +923,7 @@ def _sweep(modules: list) -> None: print(" Add module screenshots: uv run scripts/docs/update_module_docs.py") if "ui_overview" in captured: print(" Add UI overview to docs/architecture.md # Web UI section:") - print(" ![UI overview](assets/screenshots/ui_overview.png)") + print(" ![UI overview](assets/ui/ui_overview.png)") return 0 if not failed else 1 diff --git a/scripts/docs/update_module_docs.py b/scripts/docs/update_module_docs.py index 9ef7ee6d..7105d0a9 100644 --- a/scripts/docs/update_module_docs.py +++ b/scripts/docs/update_module_docs.py @@ -6,15 +6,15 @@ """Insert screenshot references into docs/moonmodules/**/*.md files. For each .md file, if a matching screenshot exists at -docs/assets/screenshots/.png and the file doesn't already +docs/assets//.png and the file doesn't already contain a screenshot reference, insert one line after the first heading: - ![ controls](../../../assets/screenshots/.png) + ![ controls](../../../assets//.png) The relative path is computed from the .md file's location so links work both on GitHub and in the MoonDeck /api/docs/ renderer. -Also reports any screenshots (PNG or GIF) in docs/assets/screenshots/ that +Also reports any screenshots (PNG or GIF) under docs/assets/ that are not referenced anywhere in docs/. Usage: @@ -28,14 +28,24 @@ ROOT = Path(__file__).resolve().parent.parent.parent DOCS_DIR = ROOT / "docs" / "moonmodules" -SCREENSHOTS_DIR = ROOT / "docs" / "assets" / "screenshots" +ASSETS = ROOT / "docs" / "assets" +UI_DIR = ASSETS / "ui" # tooling/installer/full-page shots (not per-module) -SCREENSHOT_RE = re.compile(r'!\[.*?\]\(.*?assets/screenshots/.*?\)') -GIF_RE = re.compile(r'!\[.*?\]\(.*?assets/screenshots/.*?\.gif.*?\)') +# A module's asset subfolder (domain/type), mirroring src — see folder-structure-proposal.md. +def asset_dir_for(type_name: str): + if type_name.endswith("Effect"): return ASSETS / "light" / "effects" + if type_name.endswith("Modifier"): return ASSETS / "light" / "modifiers" + if type_name.endswith("Layout"): return ASSETS / "light" / "layouts" + if type_name.endswith("Driver"): return ASSETS / "light" / "drivers" + if type_name in ("Layouts", "Layers", "Drivers"): return ASSETS / "light" + return ASSETS / "core" + +SCREENSHOT_RE = re.compile(r'!\[.*?\]\(.*?assets/.*?\.(?:png|jpe?g)\)') +GIF_RE = re.compile(r'!\[.*?\]\(.*?assets/.*?\.gif.*?\)') # Extra screenshots with fixed placement in specific doc files. # Each entry: (filename, doc_rel_path, anchor_text) -# filename: file in docs/assets/screenshots/ +# filename: file in docs/assets/ui/ # doc_rel_path: repo-relative path to the doc file # anchor_text: heading/line after which to insert (exact prefix match) EXTRA_SHOTS = [ @@ -74,7 +84,7 @@ def insert_extra_shot(doc_path: Path, filename: str, anchor: str, # Relative path from the doc file's directory to the screenshot. depth = len(doc_path.parent.relative_to(ROOT).parts) - rel = "../" * depth + f"docs/assets/screenshots/{filename}" + rel = "../" * depth + f"docs/assets/ui/{filename}" label = filename.replace(".png", "").replace("_", " ").title() img_line = f"\n![{label}]({rel})\n\n" @@ -169,7 +179,7 @@ def main() -> int: # Fix spacing around image blocks: ensure one blank line after the last # image in a block, and collapse any triple+ blank lines to one blank. - img_line_re = re.compile(r'^!\[.*?\]\(.*?assets/screenshots/.*?\)\n', re.MULTILINE) + img_line_re = re.compile(r'^!\[.*?\]\(.*?assets/.*?\)\n', re.MULTILINE) for md_file in sorted(DOCS_DIR.rglob("*.md")): original = md_file.read_text(encoding="utf-8") lines = original.splitlines(keepends=True) @@ -190,8 +200,8 @@ def main() -> int: for md_file in sorted(DOCS_DIR.rglob("*.md")): type_name = type_name_from_md(md_file) - png = SCREENSHOTS_DIR / f"{type_name}.png" - gif = SCREENSHOTS_DIR / f"{type_name}.gif" + png = asset_dir_for(type_name) / f"{type_name}.png" + gif = asset_dir_for(type_name) / f"{type_name}.gif" if not png.exists(): skipped_no_screenshot.append(md_file.relative_to(ROOT)) @@ -209,7 +219,7 @@ def main() -> int: # --- Extra shots: insert MoonDeck tab + installer images into fixed doc files --- extra_updated = [] for filename, doc_rel, anchor in EXTRA_SHOTS: - screenshot = SCREENSHOTS_DIR / filename + screenshot = UI_DIR / filename if not screenshot.exists(): continue doc_path = ROOT / doc_rel @@ -242,7 +252,7 @@ def main() -> int: all_docs_text += (ROOT / "README.md").read_text(encoding="utf-8") unreferenced = [] - for f in sorted(SCREENSHOTS_DIR.glob("*")): + for f in sorted(ASSETS.rglob("*")): if f.suffix.lower() not in (".png", ".gif"): continue if f.name not in all_docs_text: diff --git a/src/core/DevicesModule.h b/src/core/DevicesModule.h index 6bdf0b82..f843a035 100644 --- a/src/core/DevicesModule.h +++ b/src/core/DevicesModule.h @@ -107,8 +107,11 @@ class DevicesModule : public MoonModule, public ListSource { : (std::strcmp(typeStr, "WLED") == 0) ? DevType::Wled : (std::strcmp(typeStr, "Hue bridge") == 0) ? DevType::Hue : DevType::Generic; - d.colourCount = static_cast( - mm::json::readInt(mm::json::member(doc, el, "colour"))); // 0 for non-bridge rows + // Clamp the persisted count to the valid range (0..127, the HueDriver's + // colourCount_ range) so a corrupt or hand-edited entry can't wrap into a bogus + // value when narrowed. 0 for non-bridge rows (the key is absent → readInt = 0). + const long colour = mm::json::readInt(mm::json::member(doc, el, "colour")); + d.colourCount = static_cast(colour < 0 ? 0 : (colour > 127 ? 127 : colour)); d.self = false; d.cached = true; // restored, not re-heard live → UI shows "cached", not a time // Stamp "now" so the cached entry gets its kCachedGraceMs PROBATION window diff --git a/src/light/drivers/HueDriver.h b/src/light/drivers/HueDriver.h index 3f0cdc74..216314bd 100644 --- a/src/light/drivers/HueDriver.h +++ b/src/light/drivers/HueDriver.h @@ -54,12 +54,17 @@ class HueDriver : public DriverBase { // takes hue/sat), we use the RGB result. void setCorrection(const Correction* c) override { correction_ = c; } - // A control click. "pair" starts the link-button pairing poll. + // A control click. "pair" starts the link-button pairing poll. Changing the bridge IP or app + // key points the driver at a (possibly) different bridge, so the learned light list + push + // cache are stale — drop them and let loop1s re-fetch against the new config. void onUpdate(const char* controlName) override { if (controlName && std::strcmp(controlName, "pair") == 0) { pairTicksLeft_ = kPairWindowTicks; // begin: poll the bridge for ~30 s on loop1s std::snprintf(statusBuf_, sizeof(statusBuf_), "pairing: press the bridge button"); setStatus(statusBuf_); + } else if (controlName && + (std::strcmp(controlName, "bridgeIp") == 0 || std::strcmp(controlName, "appKey") == 0)) { + resetLightCache(); // re-fetch the light list for the new bridge/key } DriverBase::onUpdate(controlName); } @@ -214,6 +219,15 @@ class HueDriver : public DriverBase { } } + // Drop the learned light list + push cache so loop1s re-fetches (on a bridge/key change). + void resetLightCache() { + lightCount_ = 0; + colourCount_ = 0; + sawLights_ = false; + pushCursor_ = 0; + for (uint8_t i = 0; i < kMaxLights; i++) sent_[i] = false; + } + // --- Learn the bridge's light ids (window index → hue id, in id order). void fetchLights() { char host[16]; bridgeStr(host); diff --git a/src/light/effects/WaveEffect.h b/src/light/effects/WaveEffect.h index 942a849e..a83f1e07 100644 --- a/src/light/effects/WaveEffect.h +++ b/src/light/effects/WaveEffect.h @@ -13,7 +13,7 @@ namespace mm { // scrolls sideways over time, leaving a fading trail behind it. The classic "oscilloscope wave" // look. Prior art: MoonLight's Wave effect (Ewoud Wijma) — behaviour reproduced (the six waveform // types, the per-column phase travel, the time-varying colour, the frame fade), written fresh on -// projectMM's EffectBase + integer primitives (sin8 LUT, scale8), no palette dependency yet. +// projectMM's EffectBase + integer primitives (sin8 LUT, scale8); the colour is an hsvToRgb sweep. // // Axis convention: the waveform sets a y (its shape lives on HEIGHT); width is the travel axis. // So a 1-tall grid shows no wave — to drive a 1D output (a strip, a row of Hue lights) lay it out diff --git a/src/light/light_types.h b/src/light/light_types.h index ab20c3eb..fc08a215 100644 --- a/src/light/light_types.h +++ b/src/light/light_types.h @@ -54,7 +54,7 @@ struct Coord3D { using nrOfLightsType = std::conditional_t; // Dimensional support. Effects use this to declare which axes they iterate so the -// Layer can extrude lower-dimensional output across unused axes (D1 row → fill y/z, +// Layer can extrude lower-dimensional output across unused axes (D1 column → fill x/z, // D2 slice → fill z, D3 → no extrusion). Modifiers use it to advertise which axes // they can transform. The UI derives the 📏/🟦/🧊 chip from it (captured generically // by core's ModuleFactory, which detects a `dimensions()` method without naming diff --git a/src/platform/desktop/platform_desktop.cpp b/src/platform/desktop/platform_desktop.cpp index e27609ae..e35c5103 100644 --- a/src/platform/desktop/platform_desktop.cpp +++ b/src/platform/desktop/platform_desktop.cpp @@ -56,6 +56,10 @@ inline int make_nonblocking(int fd) { u_long mode = 1; return ::ioctlsocket(sock(fd), FIONBIO, &mode); } +inline int make_blocking(int fd) { + u_long mode = 0; + return ::ioctlsocket(sock(fd), FIONBIO, &mode); +} #else inline int sock(int fd) { return fd; } inline int close_sock(int fd) { return ::close(fd); } @@ -67,6 +71,10 @@ inline int make_nonblocking(int fd) { int flags = ::fcntl(fd, F_GETFL, 0); return ::fcntl(fd, F_SETFL, flags | O_NONBLOCK); } +inline int make_blocking(int fd) { + int flags = ::fcntl(fd, F_GETFL, 0); + return ::fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); +} #endif #ifdef _WIN32 // Winsock 2.2 must be initialized once per process before any socket call. @@ -492,8 +500,39 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* if (fd < 0) return 0; struct CloseGuard { int f; ~CloseGuard() { close_sock(f); } } guard{fd}; - // Bound connect + recv with a timeout (same SO_RCVTIMEO/SO_SNDTIMEO shape the rest of the - // file uses); the socket stays blocking, so the bounded request is straightforward. + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) return 0; + + // Bound the CONNECT by timeoutMs: a blocking connect to an unreachable host hangs for the OS + // default (tens of seconds) — and this runs on the driver's loop1s (shared with the render + // loop), so it must not stall. Connect non-blocking, wait writable via select() up to + // timeoutMs, then restore blocking for the bounded send/recv (which use SO_*TIMEO below). + if (make_nonblocking(fd) != 0) return 0; + int cr = ::connect(sock(fd), reinterpret_cast(&addr), sizeof(addr)); + // A non-blocking connect that didn't complete immediately reports "in progress": + // EINPROGRESS on POSIX, WSAEWOULDBLOCK on Winsock. Anything else is a hard failure. +#ifdef _WIN32 + const bool inProgress = (cr != 0 && ::WSAGetLastError() == WSAEWOULDBLOCK); +#else + const bool inProgress = (cr != 0 && errno == EINPROGRESS); +#endif + if (cr != 0 && !inProgress) return 0; // immediate hard failure + if (cr != 0) { // connect in progress — wait for writable + fd_set wf; FD_ZERO(&wf); FD_SET(sock(fd), &wf); + timeval ctv{}; + ctv.tv_sec = static_cast(timeoutMs / 1000); + ctv.tv_usec = static_cast((timeoutMs % 1000) * 1000); + if (::select(static_cast(sock(fd)) + 1, nullptr, &wf, nullptr, &ctv) <= 0) return 0; // timeout / error + int soerr = 0; socklen_t len = sizeof(soerr); + ::getsockopt(sock(fd), SOL_SOCKET, SO_ERROR, reinterpret_cast(&soerr), &len); + if (soerr != 0) return 0; // connect failed + } + if (make_blocking(fd) != 0) return 0; // back to blocking for the bounded send/recv + + // Bound the request send + response recv with SO_RCVTIMEO/SO_SNDTIMEO (the same shape the + // rest of the file uses). #ifdef _WIN32 DWORD tv = timeoutMs; ::setsockopt(sock(fd), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&tv), sizeof(tv)); @@ -505,11 +544,6 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* ::setsockopt(sock(fd), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); ::setsockopt(sock(fd), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); #endif - sockaddr_in addr{}; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) return 0; - if (::connect(sock(fd), reinterpret_cast(&addr), sizeof(addr)) != 0) return 0; char req[1024]; const size_t blen = reqBody ? std::strlen(reqBody) : 0; @@ -522,7 +556,13 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", method, path, host); if (n <= 0 || n >= static_cast(sizeof(req))) return 0; - if (::send(sock(fd), req, n, 0) != n) return 0; + // Send the whole request — a blocking send can return short under backpressure, so loop + // until all n bytes are out (retry on a positive partial, fail only on 0 / error). + for (int off = 0; off < n;) { + auto w = ::send(sock(fd), req + off, n - off, 0); + if (w > 0) off += static_cast(w); + else return 0; + } // Read the response. When the caller wants the body, read into THEIR buffer (so they size it // — a Hue /lights body runs several KB) and shift the body to the front. When they don't diff --git a/src/platform/esp32/platform_esp32.cpp b/src/platform/esp32/platform_esp32.cpp index c1eb4c3f..23467df2 100644 --- a/src/platform/esp32/platform_esp32.cpp +++ b/src/platform/esp32/platform_esp32.cpp @@ -1120,18 +1120,38 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* if (fd < 0) return 0; struct CloseGuard { int f; ~CloseGuard() { ::close(f); } } guard{fd}; + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) return 0; + + // Bound the CONNECT by timeoutMs: a blocking connect to an unreachable host hangs for the OS + // default — and this runs on the driver's loop1s (shared with the render loop), so it must + // not stall. Connect non-blocking, wait writable via select() up to timeoutMs, then restore + // blocking for the bounded send/recv (which use SO_*TIMEO below). + const int flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags | O_NONBLOCK); + int cr = ::connect(fd, reinterpret_cast(&addr), sizeof(addr)); + if (cr != 0 && errno != EINPROGRESS) return 0; // immediate hard failure + if (cr != 0) { // connect in progress — wait for writable + fd_set wf; FD_ZERO(&wf); FD_SET(fd, &wf); + timeval ctv{}; + ctv.tv_sec = static_cast(timeoutMs / 1000); + ctv.tv_usec = static_cast((timeoutMs % 1000) * 1000); + if (::select(fd + 1, nullptr, &wf, nullptr, &ctv) <= 0) return 0; // timeout / error + int soerr = 0; socklen_t len = sizeof(soerr); + getsockopt(fd, SOL_SOCKET, SO_ERROR, &soerr, &len); + if (soerr != 0) return 0; // connect failed + } + fcntl(fd, F_SETFL, flags); // back to blocking + + // Bound the request send + response recv with SO_RCVTIMEO/SO_SNDTIMEO. timeval tv{}; tv.tv_sec = static_cast(timeoutMs / 1000); tv.tv_usec = static_cast((timeoutMs % 1000) * 1000); setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - sockaddr_in addr{}; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) return 0; - if (::connect(fd, reinterpret_cast(&addr), sizeof(addr)) != 0) return 0; - char req[1024]; const size_t blen = reqBody ? std::strlen(reqBody) : 0; int n = blen @@ -1143,7 +1163,13 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* "%s %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", method, path, host); if (n <= 0 || n >= static_cast(sizeof(req))) return 0; - if (::send(fd, req, n, 0) != n) return 0; + // Send the whole request — a blocking send can return short under backpressure, so loop + // until all n bytes are out (retry on a positive partial, fail only on 0 / error). + for (int off = 0; off < n;) { + int w = ::send(fd, req + off, n - off, 0); + if (w > 0) off += w; + else return 0; + } // Read the response. When the caller wants the body, read into THEIR buffer (so they size it // — a Hue /lights body runs several KB) and shift the body to the front. When they don't diff --git a/test/unit/core/unit_DevicesModule_hue.cpp b/test/unit/core/unit_DevicesModule_hue.cpp index 909cce41..e22bbeb1 100644 --- a/test/unit/core/unit_DevicesModule_hue.cpp +++ b/test/unit/core/unit_DevicesModule_hue.cpp @@ -9,6 +9,7 @@ #include "core/DevicesModule.h" #include "core/JsonSink.h" +#include #include TEST_CASE("DevicesModule: a Hue bridge is listed with its colour count") { @@ -49,3 +50,26 @@ TEST_CASE("DevicesModule: a persisted Hue bridge restores as a Hue row with its CHECK(std::strstr(sink.data(), "\"type\":\"Hue bridge\"") != nullptr); CHECK(std::strstr(sink.data(), "\"colour\":7") != nullptr); } + +TEST_CASE("DevicesModule: a corrupt persisted colour clamps to the valid range, row still restores") { + // A negative count and an over-127 count (corrupt / hand-edited file) must clamp to 0..127 + // before narrowing to uint8_t — never wrap into a bogus value. The row otherwise restores. + struct Case { const char* colour; const char* want; }; + const Case cases[] = { + {"-5", "\"colour\":0"}, // negative → 0 + {"99999", "\"colour\":127"}, // overflow → 127 (the HueDriver colourCount_ ceiling) + }; + for (const auto& c : cases) { + mm::DevicesModule dev; + char saved[160]; + std::snprintf(saved, sizeof(saved), + "{\"devices\":[{\"name\":\"Hue Ewoud\",\"ip\":\"192.168.1.143\",\"type\":\"Hue bridge\",\"colour\":%s}]}", + c.colour); + REQUIRE(dev.restoreList(saved, "devices")); + REQUIRE(dev.listRowCount() == 1); + mm::JsonSink sink; + dev.writeListRow(sink, 0); + CHECK(std::strstr(sink.data(), "\"type\":\"Hue bridge\"") != nullptr); + CHECK(std::strstr(sink.data(), c.want) != nullptr); + } +} From d00559c38f3c09e4ccb0da28433cb991906ba333 Mon Sep 17 00:00:00 2001 From: ewowi Date: Tue, 30 Jun 2026 15:26:23 +0200 Subject: [PATCH 03/11] Palette feature, effect curation, and compact per-type doc pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a global colour palette (selectable on Drivers, with a gradient-swatch dropdown) that all index-coloured effects now read; curates the effect set (removes four, tunes others); and consolidates the per-module effect/modifier/layout docs into one compact-row page per type. Net −669 lines. KPI: tick:119/92/121/15/2/280/59/17/20/161/118/17/1/35us(FPS:8403/10869/8264/66666/500000/3571/16949/58823/50000/6211/8474/58823/1000000/28571) | ESP32:1274KB | tick:1236us(FPS:809) | heap:151KB Core: - Control: added ControlType::Palette + addPalette() with a PaletteOptionsFn seam, so the light domain supplies each option's {name,colors} swatch and core stays palette-agnostic (mirrors the Select shape for value read/parse). - DevicesModule: refreshStatus() now also runs when a cached device row transitions back to active with no persisted field change (a re-announced bridge no longer stays greyed-out); sortByName() stays tied to real persisted changes. (🐇) - platform_desktop / platform_esp32: httpRequest now tracks one absolute deadline across connect/send/recv instead of giving each phase a fresh timeoutMs (total could reach ~3× the budget). (🐇) Light domain: - Palette: new 16-entry CRGBPalette16-style model with colorFromPalette()/fromGradient(), built-in palettes, and a global active palette read via Palettes::active() (the AudioModule::latestFrame() static-seam pattern); default is Rainbow so effects render visibly before any selection. paletteOptions() emits the dropdown swatches. - Drivers: added the `palette` control (addPalette); selecting a palette recolours every palette-driven effect live via onUpdate. - Effects: converted ~14 effects to colorFromPalette(active, index[, brightness]) (Rainbow, Noise, Rings, Spiral, DistortionWaves, Metaballs, Plasma, GameOfLife→removed, Wave, Particles via Glow merge, AudioVolume, AudioSpectrum per-band); Fire/LavaLamp keep their identity colour, Sine/NetworkReceive/Lines have no single index. Lines stays an R/G/B axis test pattern. - Effect curation: removed PlasmaPaletteEffect (subset of Plasma), GlowParticlesEffect (identical render to Metaballs — Metaballs gained a `count` control), CheckerboardEffect, GameOfLifeEffect (to be replaced). Plasma default scale 16→48 (bigger, calmer blobs); Fire spark count scales with width so a wide grid lights its whole base; Rings calmed (count 4→2, speed 60→30). - WaveEffect: first-tick bootstrap so the wave starts at phase 0 instead of jumping by uptime; present-tense comments (palette has landed). (🐇) - HueDriver: pairing-success path uses resetLightCache() so sent_/lastRgb_ clear and the new bridge session re-sends all lights. (🐇) UI: - app.js: palette control renders a custom gradient-swatch dropdown (native table-cell HTML through (resolving the gif src to /api/doc-asset/) so the compact pages render previews + row anchors. - screenshot_modules.py / update_module_docs.py: asset_dir_for E701 multi-line rewrite. (🐇) Tests: - Removed the four deleted effects' registrations/tests; renamed the shared effect-render test to unit_effects_render.cpp (Checkerboard→Spiral as the generic D2 subject); swapped scenarios + zero-grid/extrude/phase tests to surviving effects; added MetaballsEffect count to the unit coverage path. Docs / CI: - Consolidated ~29 per-module effect/modifier/layout .md into docs/moonmodules/light/{effects,modifiers,layouts}/.md — MoonLight-style compact rows (Name+tags · Preview gif · Description · Controls · Tests), grouped into library sections (MoonLight/WLED/FastLED/projectMM-native); per-library file split kept as future growth. main.cpp registers each module's page#anchor. Drivers + containers stay per-file. - architecture.md: Tag-emoji-legend h4→h2 and role/origin rows synced to app.js ROLE_EMOJI. (🐇) - folder-structure-proposal.md: fenced trees tagged `text` (MD040). (🐇) - HueDriver.md: architecture link path fixed. (🐇) - README/FastLED attribution and the two saved plans (palette stage 1, doc consolidation). - 🐇 plan-archive: declined CodeRabbit's ask to rewrite the shipped HueDriver plan's "Decisions locked" to match what shipped — plans are the intent record, kept as written; the (shipped) marker already signals it landed. Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/architecture.md | 10 +- .../light/effects/CheckerboardEffect.gif | Bin 162807 -> 0 bytes .../light/effects/CheckerboardEffect.png | Bin 15120 -> 0 bytes .../assets/light/effects/GameOfLifeEffect.gif | Bin 65145 -> 0 bytes .../assets/light/effects/GameOfLifeEffect.png | Bin 14104 -> 0 bytes .../light/effects/GlowParticlesEffect.gif | Bin 219063 -> 0 bytes .../light/effects/GlowParticlesEffect.png | Bin 15180 -> 0 bytes .../light/effects/PlasmaPaletteEffect.gif | Bin 274901 -> 0 bytes .../light/effects/PlasmaPaletteEffect.png | Bin 13487 -> 0 bytes docs/backlog/folder-structure-proposal.md | 6 +- ...mpact pages (effects-modifiers-layouts).md | 57 ++++ .../plans/Plan-20260630 - Stage 1 palette.md | 40 +++ docs/moonmodules/core/AudioModule.md | 2 +- docs/moonmodules/light/Drivers.md | 1 + docs/moonmodules/light/ModifierBase.md | 2 +- docs/moonmodules/light/drivers/HueDriver.md | 2 +- .../light/effects/AudioSpectrumEffect.md | 26 -- .../light/effects/AudioVolumeEffect.md | 17 - .../light/effects/CheckerboardEffect.md | 22 -- .../light/effects/DistortionWavesEffect.md | 22 -- docs/moonmodules/light/effects/FireEffect.md | 47 --- .../light/effects/GameOfLifeEffect.md | 71 ---- .../light/effects/GlowParticlesEffect.md | 24 -- .../light/effects/LavaLampEffect.md | 23 -- docs/moonmodules/light/effects/LinesEffect.md | 22 -- .../light/effects/MetaballsEffect.md | 27 -- .../light/effects/NetworkReceiveEffect.md | 55 ---- docs/moonmodules/light/effects/NoiseEffect.md | 40 --- .../light/effects/ParticlesEffect.md | 47 --- .../moonmodules/light/effects/PlasmaEffect.md | 32 -- .../light/effects/PlasmaPaletteEffect.md | 21 -- .../light/effects/RainbowEffect.md | 26 -- docs/moonmodules/light/effects/RingsEffect.md | 26 -- .../light/effects/RipplesEffect.md | 28 -- docs/moonmodules/light/effects/SineEffect.md | 21 -- .../moonmodules/light/effects/SpiralEffect.md | 21 -- docs/moonmodules/light/effects/WaveEffect.md | 31 -- docs/moonmodules/light/effects/effects.md | 64 ++++ docs/moonmodules/light/layouts/GridLayout.md | 31 -- .../moonmodules/light/layouts/SphereLayout.md | 27 -- docs/moonmodules/light/layouts/WheelLayout.md | 23 -- docs/moonmodules/light/layouts/layouts.md | 21 ++ .../light/modifiers/CheckerboardModifier.md | 38 --- .../light/modifiers/MultiplyModifier.md | 45 --- .../light/modifiers/RandomMapModifier.md | 27 -- .../light/modifiers/RegionModifier.md | 48 --- .../light/modifiers/RotateModifier.md | 19 -- docs/moonmodules/light/modifiers/modifiers.md | 28 ++ docs/tests/scenario-tests.md | 307 ++++++++++++------ docs/tests/unit-tests.md | 291 ++++++++++++----- scripts/check/check_specs.py | 30 +- scripts/docs/screenshot_modules.py | 15 +- scripts/docs/update_module_docs.py | 15 +- scripts/moondeck.py | 38 ++- src/core/Control.cpp | 17 +- src/core/Control.h | 19 +- src/core/DevicesModule.h | 6 +- src/light/Palette.h | 167 ++++++++++ src/light/drivers/Drivers.h | 8 + src/light/drivers/HueDriver.h | 3 +- src/light/effects/AudioSpectrumEffect.h | 3 +- src/light/effects/AudioVolumeEffect.h | 13 +- src/light/effects/CheckerboardEffect.h | 66 ---- src/light/effects/DistortionWavesEffect.h | 3 +- src/light/effects/FireEffect.h | 13 +- src/light/effects/GameOfLifeEffect.h | 272 ---------------- src/light/effects/GlowParticlesEffect.h | 125 ------- src/light/effects/MetaballsEffect.h | 22 +- src/light/effects/NoiseEffect.h | 3 +- src/light/effects/PlasmaEffect.h | 10 +- src/light/effects/PlasmaPaletteEffect.h | 105 ------ src/light/effects/RainbowEffect.h | 3 +- src/light/effects/RingsEffect.h | 9 +- src/light/effects/SpiralEffect.h | 3 +- src/light/effects/WaveEffect.h | 19 +- src/main.cpp | 62 ++-- src/platform/desktop/platform_desktop.cpp | 27 +- src/platform/esp32/platform_esp32.cpp | 24 +- src/ui/app.js | 130 +++++++- src/ui/style.css | 61 ++++ test/CMakeLists.txt | 4 +- test/scenario_runner.cpp | 8 - .../scenario_MoonModule_control_change.json | 4 +- .../light/scenario_Driver_mutation.json | 4 +- .../light/scenario_Layer_base_pipeline.json | 4 +- .../light/scenario_Layers_composition.json | 16 +- .../scenario_MoonLiveEffect_controls.json | 4 +- .../light/scenario_modifier_chain.json | 4 +- .../light/scenario_modifier_swap.json | 4 +- test/scenarios/light/scenario_perf_full.json | 56 ++-- test/scenarios/light/scenario_perf_light.json | 28 +- test/unit/light/unit_GameOfLifeEffect.cpp | 186 ----------- test/unit/light/unit_Layer_extrude.cpp | 8 +- .../unit/light/unit_Layer_phase_animation.cpp | 19 +- test/unit/light/unit_Layer_zero_grid.cpp | 11 +- test/unit/light/unit_Layers_container.cpp | 16 +- test/unit/light/unit_Palette.cpp | 78 +++++ ...oardEffect.cpp => unit_effects_render.cpp} | 32 +- 98 files changed, 1423 insertions(+), 2092 deletions(-) delete mode 100644 docs/assets/light/effects/CheckerboardEffect.gif delete mode 100644 docs/assets/light/effects/CheckerboardEffect.png delete mode 100644 docs/assets/light/effects/GameOfLifeEffect.gif delete mode 100644 docs/assets/light/effects/GameOfLifeEffect.png delete mode 100644 docs/assets/light/effects/GlowParticlesEffect.gif delete mode 100644 docs/assets/light/effects/GlowParticlesEffect.png delete mode 100644 docs/assets/light/effects/PlasmaPaletteEffect.gif delete mode 100644 docs/assets/light/effects/PlasmaPaletteEffect.png create mode 100644 docs/history/plans/Plan-20260630 - Doc consolidation - per-type compact pages (effects-modifiers-layouts).md create mode 100644 docs/history/plans/Plan-20260630 - Stage 1 palette.md delete mode 100644 docs/moonmodules/light/effects/AudioSpectrumEffect.md delete mode 100644 docs/moonmodules/light/effects/AudioVolumeEffect.md delete mode 100644 docs/moonmodules/light/effects/CheckerboardEffect.md delete mode 100644 docs/moonmodules/light/effects/DistortionWavesEffect.md delete mode 100644 docs/moonmodules/light/effects/FireEffect.md delete mode 100644 docs/moonmodules/light/effects/GameOfLifeEffect.md delete mode 100644 docs/moonmodules/light/effects/GlowParticlesEffect.md delete mode 100644 docs/moonmodules/light/effects/LavaLampEffect.md delete mode 100644 docs/moonmodules/light/effects/LinesEffect.md delete mode 100644 docs/moonmodules/light/effects/MetaballsEffect.md delete mode 100644 docs/moonmodules/light/effects/NetworkReceiveEffect.md delete mode 100644 docs/moonmodules/light/effects/NoiseEffect.md delete mode 100644 docs/moonmodules/light/effects/ParticlesEffect.md delete mode 100644 docs/moonmodules/light/effects/PlasmaEffect.md delete mode 100644 docs/moonmodules/light/effects/PlasmaPaletteEffect.md delete mode 100644 docs/moonmodules/light/effects/RainbowEffect.md delete mode 100644 docs/moonmodules/light/effects/RingsEffect.md delete mode 100644 docs/moonmodules/light/effects/RipplesEffect.md delete mode 100644 docs/moonmodules/light/effects/SineEffect.md delete mode 100644 docs/moonmodules/light/effects/SpiralEffect.md delete mode 100644 docs/moonmodules/light/effects/WaveEffect.md create mode 100644 docs/moonmodules/light/effects/effects.md delete mode 100644 docs/moonmodules/light/layouts/GridLayout.md delete mode 100644 docs/moonmodules/light/layouts/SphereLayout.md delete mode 100644 docs/moonmodules/light/layouts/WheelLayout.md create mode 100644 docs/moonmodules/light/layouts/layouts.md delete mode 100644 docs/moonmodules/light/modifiers/CheckerboardModifier.md delete mode 100644 docs/moonmodules/light/modifiers/MultiplyModifier.md delete mode 100644 docs/moonmodules/light/modifiers/RandomMapModifier.md delete mode 100644 docs/moonmodules/light/modifiers/RegionModifier.md delete mode 100644 docs/moonmodules/light/modifiers/RotateModifier.md create mode 100644 docs/moonmodules/light/modifiers/modifiers.md create mode 100644 src/light/Palette.h delete mode 100644 src/light/effects/CheckerboardEffect.h delete mode 100644 src/light/effects/GameOfLifeEffect.h delete mode 100644 src/light/effects/GlowParticlesEffect.h delete mode 100644 src/light/effects/PlasmaPaletteEffect.h delete mode 100644 test/unit/light/unit_GameOfLifeEffect.cpp create mode 100644 test/unit/light/unit_Palette.cpp rename test/unit/light/{unit_CheckerboardEffect.cpp => unit_effects_render.cpp} (82%) diff --git a/docs/architecture.md b/docs/architecture.md index 9bb4688d..60c5a9d4 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -259,7 +259,7 @@ The defining line is the **data relationship, not the connector**: *does the mod Peripherals are **user-add/deletable children of SystemModule**: the firmware is identical whether or not the hardware is wired, so the user adds the module when they solder a gyro on and removes it later, reusing the generic child add/replace/delete + persistence machinery (SystemModule declares `acceptsChildRoles("peripheral")`). Direction is per-module, not a role: a peripheral may read (gyro), write (relay), or both, so one `Peripheral` role spans the category. Each is a header-only or `.h`+`.cpp` core module under `src/core/`, reaches hardware only through a domain-neutral platform primitive (`platform::i2c*`, `platform::audioMic*`, …), and gets a spec in `docs/moonmodules/core/` (enforced by `check_specs.py`). Most poll in `loop20ms`/`loop1s`; the exception is a peripheral whose data an effect consumes *every frame*: [AudioModule](moonmodules/core/AudioModule.md) reads + analyses its I²S microphone in `loop()` because the audio effects react per render tick, and its per-tick cost (one FFT) is part of the render budget. Automatic bus-probe detection is out of scope; the manual path is the foundation. -**An effect reads a peripheral's data** via the shared-struct pull pattern from [§ Data exchange](#data-exchange-between-modules), no new mechanism: the peripheral owns a small POD struct overwritten in place each poll/tick, and the consuming effect holds a `const` pointer to it. The first concrete case is audio: AudioModule produces an `AudioFrame` (level + 16-band spectrum + peak) that [AudioVolumeEffect](moonmodules/light/effects/AudioVolumeEffect.md) and [AudioSpectrumEffect](moonmodules/light/effects/AudioSpectrumEffect.md) consume. It reaches the frame through a static `AudioModule::latestFrame()` rather than a boot-time setter, a small variation on the pattern, because an audio effect can be added through the UI *after* boot and must still find the one live mic (a setter only wired the boot instance). The active mic registers itself in `setup()` and clears the pointer in `teardown()`, so add/remove in any order returns either the live frame or a static silent one, never null. A peripheral that only *displays* its readings (the gyro today) skips the consumer side entirely. +**An effect reads a peripheral's data** via the shared-struct pull pattern from [§ Data exchange](#data-exchange-between-modules), no new mechanism: the peripheral owns a small POD struct overwritten in place each poll/tick, and the consuming effect holds a `const` pointer to it. The first concrete case is audio: AudioModule produces an `AudioFrame` (level + 16-band spectrum + peak) that [AudioVolumeEffect](moonmodules/light/effects/effects.md) and [AudioSpectrumEffect](moonmodules/light/effects/effects.md) consume. It reaches the frame through a static `AudioModule::latestFrame()` rather than a boot-time setter, a small variation on the pattern, because an audio effect can be added through the UI *after* boot and must still find the one live mic (a setter only wired the boot instance). The active mic registers itself in `setup()` and clears the pointer in `teardown()`, so add/remove in any order returns either the live frame or a static silent one, never null. A peripheral that only *displays* its readings (the gyro today) skips the consumer side entirely. ## Multi-device runtime @@ -536,15 +536,15 @@ Adding a new MoonModule with controls needs **zero changes** to the UI files. Th The light domain plugs into the UI at three points: a fixed top-level tree (Layouts / Layers / Drivers pinned in `main.cpp`, root reorder disabled while child reorder works via drag-and-drop), a binary WebSocket preview channel ([PreviewDriver](moonmodules/light/drivers/PreviewDriver.md): a `0x03` coordinate table sent once per LUT rebuild plus per-frame `0x02` RGB point lists, so sparse layouts preview at their real positions), and per-role emoji for the chip filter (the `ROLE_EMOJI` map in `app.js` is the single source of truth: `effect`, `driver`, …, `peripheral`). Full UI spec: [docs/moonmodules/core/ui.md](moonmodules/core/ui.md). -#### Tag emoji legend +## Tag emoji legend -A module's chips come from three sources, rendered identically on the card and the type picker: a **role** chip (UI-derived from `role`), a **dimensional** chip (UI-derived from `dim`), and the curated **`tags()`** string (a flash literal the module returns; the UI splits it into grapheme clusters, one chip each). Role and dim are *not* repeated in `tags()` — only the categories below are. The legend takes [MoonLight](https://github.com/MoonModules/MoonLight)'s set as the canonical basis: +A module's chips come from three sources, rendered identically on the card and the type picker: a **role** chip (UI-derived from `role`), a **dimensional** chip (UI-derived from `dim`), and the curated **`tags()`** string (a flash literal the module returns; the UI splits it into grapheme clusters, one chip each). Role and dim are *not* repeated in `tags()` — only the categories below are. The `ROLE_EMOJI` / `DIM_EMOJI` maps in `app.js` are the single source of truth for the UI-derived chips; the legend takes [MoonLight](https://github.com/MoonModules/MoonLight)'s set as the canonical basis: | Category | Emoji | Meaning | |---|---|---| -| **Role** (UI-derived) | 🔥 effect · 💎 modifier · 📐 layout · 🔌 driver · ⚙️ peripheral | what kind of module (from `role`, via `ROLE_EMOJI`) | +| **Role** (UI-derived) | 🔥 effect · 💎 modifier · 🚥 layout · ☸️ driver · 🛰️ peripheral · 🥞 layer · ⚙️ generic | what kind of module (from `role`, via `ROLE_EMOJI`) | | **Dimensionality** (UI-derived) | 📏 1D · 🟦 2D · 🧊 3D | native axes (from `dim`) | -| **Origin / library** (`tags()`) | 💫 MoonLight · 🌊 WLED · *(projectMM-native: none — the default)* | which library the module came from; the [migration](../backlog/moonlight-effect-inventory.md) files docs by this, the emoji filters by it | +| **Origin / library** (`tags()`) | 💫 MoonLight · 🐙 WLED · ⚡️ FastLED · *(projectMM-native: none — the default)* | which library the module came from; the [migration](../backlog/moonlight-effect-inventory.md) files docs by this, the emoji filters by it | | **Creator** (`tags()`) | 🦅 a named contributor (credited at the introduction site) | individual authorship credit | | **Audio** (`tags()`) | 🔊 audio-reactive | reads `AudioModule::latestFrame()` | diff --git a/docs/assets/light/effects/CheckerboardEffect.gif b/docs/assets/light/effects/CheckerboardEffect.gif deleted file mode 100644 index b52a975606afe2fae109bdca1959ab165010cee3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162807 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 diff --git a/docs/assets/light/effects/CheckerboardEffect.png b/docs/assets/light/effects/CheckerboardEffect.png deleted file mode 100644 index e3795c781e98cb3f964810e675eadfa789d7e826..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15120 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 btU`hz(a6bToqH65egTt_P!z8gH4gf3Y1K;e diff --git a/docs/assets/light/effects/GameOfLifeEffect.gif b/docs/assets/light/effects/GameOfLifeEffect.gif deleted file mode 100644 index a0715a51b1697c1551676423658d4beffbc28ed8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65145 zcmeFYX;f49|L?n}Bs(D?I}k!Zh6DmeCc`Kokex6E1POx*h#CeJk!n=5h|>;)QIseS zsHkDk;@F^Qt+j2K1Qj(XDq3rUQj0^|sHoJUIsAX?-gW-x-23o8xoe%Zv-ZlvJjmz! zdB0!p_ct~!CO9M;2djXOW&nWPA=-2lbVpfyIzz}H2^kh1mexF`wI|bNI%esKF=tp| zLTei@Hp|n7Bedao+OoZDZGCLHo?JU0u2ZnRou|FMkG=iOY14eBJ`Rq)4!kf&hnbE% zPrk3Wi@T?*qn9i0Cz$2!=HTb%k>>8{J>4f_hKuJ6msAfgPmlC)Pu#~d*2gQb$a_Yi z_o{gBbw2Uvx0p> zM4LnKqag>ALYMf5Ee{Uo`-ac<311f!fqO?31V)rg#0O$=ewbu=kkrpdx+6R?Srj9j z8Iuzl8#6O*z9@ddaC}?j96`t&>7|6Su*4uy;;e?mIKRY$5pxs#lGZA5| zcFDR5V|(V#>2HX?aeU4|Y{5WL{LQiCTe6BD=8d0RJC^L<7D6UQ^$J{~D9Z z|8Ixn|4hjLnUMbtFD=zrCfe zju%s!WL5~)U9n#@OQDE6fBfd5U~#5F*Hn7@=rpfUhxm@R!A6^s`C4GS z?d~`7mSr89q7&3((^?CDy?(*--VyhbVbg&Nryicq|0?DEik8^ABTMgIKRo9_3+b56 zS-%|%zx(#LpBZ0woq1%f8|khh74TlAb`SJuTyI>!GsbeSHTbW5GVuNRKW=Lyw>u?X z?s##xE%nsmo0l)VdZ5d_aU}7Fi+}!dY2B+QH-Gr<@89%g7S408tRmC*Z}${`GO7%} z8`ilTH8hjnj>d#!>9ygXzM^w1HRkm5$9q+O#Lf^j0DRTgzi{2P`4X3ejXWDKMPFQY zPmA4x$AiCaYQL$L*sMg_L7Gxj+6&vU_jbbiE8PPge|wec3FP839w!@FLm=s+?a>g+ zDv&RHHta$R`8q(msK)Uu$CsC8>!r^|vXrAgC&9CDR~ z_eW`;7u;lZ(Hw4mwIU5-%F2@b4jaqjX7vk0^HUzqPh^_b)IfzP{X%PIX zeT#h8;i1$dx93IvvWW9pJ1`2u>$(-u@;EYyO5*76KLZ->^tq0j_2!i*|us<65oZigzBFlh|PpP`d zBu{!6mMDIzBOoCb@n-$=&;+pV1-r{r0?fh2@+$=6yQt3jk`+I!)iZk}OqoGJ`%c^E zodS?B%s?Fb-tzQLYmW-KLXixB_Hz}IfVN1-ETz874+C8jIxQxRv3zsmnp$b2D+lx7 z(c;Pi7XDtag4&70S~WnG^MKvMeGz^tK)VzN0ZpWMEE`?Z*ut7Ll&{lYh`OufMcWle z2R55(@*06H^Z}fVn_}oi0H-AwByAW5LaJI=-{~tHa*|QuXbx>BR>5}A_5>Bgg!`51 zZH(9R` z%N?|JHXw8f0^MIH*Y$g=VGAy4_FtXma)7IH{EU)(Kd~xFN_0iU1mSaQmql!2H;Y!R z7qqokv!k@TUrbt%ymV)&Kj!b`X$L^jV5r~3T>iw+AK}Lpsu@c7YuLN(o8tA*BE>Un z%k@!EgqB)>x;Aoe3KywIz1Ci70-0?{Lipf#*9WU- z?TN&!^8xz~72VssM{05VvE2?o-9R!9v7T0yJB$sYWCED)P=(uXeN%0z;E@gnm)r8R zDnm?6-so7X(3D(#N&+A(07Q9eAbrf$;q7@cYWYit^kzggPsEN!LC zrh^YH(-j$sH*hM?q+)7kLT)l&6B05MC$=&NKoH7bna z8!s~MAiG#Pi+b4k2Gsub+O*YK&-q)|s3TfSX=oL}O?gAIrmVl3asaP)y6a>i(3`_a z65NL5q9WllfGh=N_MTk;ij_Hy2bV!xuMi};9lrF`jxe?YHzZ*Y-Bi zul%WZ&Kp#R^yi>xzMf_Erkv^U;qIc5KNAkV-%%oq6z@(w>NK>bE~RMA@(-_wF0Qe9 zt1g!|tw2T&&=Nti%M1%3i4vwo=OyGoG`UpZ;){?Q?H+~fdgAY`gjVcvwd42dBprt> zm3h()v%3K>L{BV41}*+bJ3erou*lfc3EIofqH~+7B8zxnlDR6%rO3FNSX~Zd_=1%; zMkIh>nHY1XNGgfjstAk5z z*!(h3d-wOKjVUd>it3WAXN%4^^oGfI5ifUc2lgADx)oKWU-K9Q_ju`PO5YX!>}OcY zlIKooO;rM*)G`U^u_YTf=w>g4c&2Wu;6u%8F z?4?9wb=DLXza${Ud{s4lM5HgJ*Gd;rbrvtR%o1MFJt>F?z&9#@PQ=m?r_00~FD)P= zEZFyESP@@;?gfgpv|W1W$Z_=`84Occe$ZR^HODgKv=PkmL(e)#C1g)tcgQ;Jjb!d+ z9H#N0R+GgxGmjm=AeUnzoz$S7SmoM&oBL0ZQiXH~&hFF-ujC+)0mfp0(TBsW_c8VZ z^3PhT4;iY|($?W|$AdyxCNNf69oJADsRA(qIPDHj2P{8oEkk2nJFIDw2Id)n@fn~Z zJYq>Oc!;+mO#y6ru*TVxz%l}__EZ#(ZeO09JNqu611x_q?AYH4TIxxUmGm`AdY=Mm z2qr3c769J^7@bY|DYFG3p%rYxDr;iWHcB&of5Hd<|GK6~In&kj!TKk_sjL zvx0))TN2&@2MLQyA_USvC-CAKJRnrJx=7^jUCp`DOxllyU|MpE2HKCUtWr=N6;utz zN44ZzI6cis|4y-tIk+oQNvr2UNdz3LMVINIBt0}ogT@)RS_JI%Z~_S>b@K0Q-I036NKHl|k*j9Ut1T0hP-QPlg98VxP!drGXbxT23NOwkZ0Y!bU+ zHPv#u7Fe!hj^lJ|9k5R;-e;iwp`e0#AY!BCT7vNhfq0!*h2pzUYLIFzEmDhaRupg6 zZQ86{OZonwSGISF<^h%puS-M#Rc&08)9DeFQQnulrts#wab;;_zP^m%en@Y*QjL z6r?CETw@@4DM(&Q_{+6ox%zMlfBA6%_D}30I)31@JmwD#`Idp13IGfdh$v?ETZ1$s zz%c?8J%s>JFASiF0MHN($7_?DH0kqmN69(e|I`l?44Ia&3Sn7Y137v!p+)&hzz9cp zytGYR2bE(Ko*Z3l0(Xc=(=xncxM@@)7^{aUM7b?-Eb@_UVlH68!>cRuNj(ccI+{R+A?I2DE@R8Fuk7u^1kh$BZI*#lL%>Owzd6+j(iG&A zT3Y3C6X}wkY`46vy))9w^i3SEEm7IH`=$M!%aj^Gd({5Kp_ld(L!?y`l=&ESKJR49 zb^B}c;A$-zX(AC?_|U_XCt08q4`TA5E1&jX3bhX#T~cm;x^0a*HvjbX%cln(oxb(y zw88$&ozOEwnP={ooEbiN=F#Odj~|_R^68Ax{_NAxv!j`3pO>5+J9zfx<+HCJo&D?6 zS(E*@Z$rNw&;0g7$+r{NSs?g-p$jwMwH9y$76Fj}FlF7$)chq$*cJqX)fpa)aL>AH^;UV6y~UtQL0td#XZ;Oxs-3i(&EPm2pT$@&$7Bn@Oyqa%c&&jqG1z#yes!bK)7i`7 zpm$8&$$zugUbC2Azo4pL|Iw)jHRr% zCT-Nr__wf38oy$Qpo&KbVwxmBPj{8Y>ramK{<0aOg%)@zvU7g9woj7;o1}HYVq7DE zEwHkr;J~pAIgHA+_!@GXi5_}sbLlNUawWrx%$eV&nVFLCteP~}sY3#*)vk1!%?3hm z|4j63X%RNBSVD2kGwW1vUD~^Ac30cp)U^sEL<+>HN;`mGpRA9I_%JSVk~)fbbn!$X zi$JD%8RNtMJl&)}1V6oC5!&r=E|qMp0OJz3X$Z|sW8nzHo1;8Af9ET-9&yKISf~B3 zQT5YLojH3?fm8x;jh$#I05Tr+ue;&>R+N({2@v6t=(Wes=nQK?QRk8HVts;mP_4iP zpNCuxMb4?Xglx6BP;Yk+$R&%~vO-eg`38JvH?}Y*F)U`X&a~WGyQ{#vI>a$s1bY5nTiPoWOm?EweR|292uNj) z`b&Hw%(s)AlKIgCZfj_nX5)w_>_yEiEGu47@La{`y8`CGs=nF2?` zCBS!Xjm^eu&f?Y-vbU1aOqD(BeH&%pFfPhm!Ci0AyZt#?FPmM^?>E%+TZJ*#e87y#-n#YT|VFbgrM^Kor&gu8^mvS8;M21H!E3%JNW zwuP!M7rz{YEW#8E@K2P1#TUO}RDBc8F%j_dbN&{WdhLw_iD7m!Qa3e}m0pvThvu^^ zN-!zN$H?KuzSONfF5on|WsIK*$jFPdk5%H7tRM~ApofRxTO=1l^R~t}q91lum3!rZ z>AG&KBmI3PI)1rikBWR?tkXJ-RT@Aq^|t1bB4q95QB}))?EdM8o)eaNZNLgg-s91e zKyAv9Vu5IyWX7`gvP5MLGPHYMv~s9@n}KlrM;^n<9^Af(?gIEk5(rAnk#?S@yfW@4 z0YL1hD=(cdn<~Xax-)3Px0&Cx#RLxV2(%Cfm-R>cOv)*_!X|(<Av9*JGs}xb` z^jg4T-DIcrb7AC6T~owSU^#D(70vyAws{JFcOfhyZ$+pP2nma{&EAe%jcL9m14?V0 z3$t`@Rf)nJ+MYJpLW3jLUY+DpDLSY2IDG?=JL4x)Pk7230!!c_+ZI;+;-yh<80xmc zFI!54MgY@nhupa_fg46ZdH{gX0k!YiY?w3&+nDp=lnXpe;N^n3R%J^ro1|)j z$*wv3Yc}a~X6NnMJ%fWCwiIeD{v50HbTP4ojL{>G8iKk3tj#Re&f>~mrX2djoOimJ z!B^z4tjjrb<8D3s@=TTDH zv<+*r4um@zDY<4KNBC_QK^+s3#wJ}UMO?|17y~8ZwbpVASCzHwE`dzAIK7#GXOnYw z4*l*1Y-sM|VJ7zmlAaCm%R$Shz^{X`-Z_V&AEo0DY@-#8+%vX!8<)0!h3+YW&%a&O#Wm|X#p$}5dE-ri2eY?RCNT80r4~Yo z+Liroq$PPS)<0^b^>PI*)j$Mql2c}e85g!M>atlVj0w01s4mCnd3*E6Yd#yxJtm*g z%|N&Ks-Z&oTEnx&_4G%C8sR2ZbanzH4zFC54uHqClyGs{?xCbUEsO$ApwqQZ~C+K525VN%}l8Z%qxL>TyrJDe{-8gtDHXZ5XcMLt}JXJ zgMssGyL>HEtC}54xoc!LcLDP>E?Y2vjLta9?<@{aS6LG$+La$4G z@GGml31D1rCP-N<%aoo<-meqVS*`8l6+G9`R~wGn6Ybj_CtKLba+2GsmeL^YV~bNl z>8KZ}-aCbd+%Qsn4XAomM;W`u4Gn$7Dz|R~*k6XrY0yDO-ex_N_ZF~_i@+a0sBSFX zifdz29I2B$hl%t)CaNQE?I^S3RJEA-h(fh|yu~?9vt3H05@Q#ZKqRI9bS94)r|g15 zevjMegx9PWNP~oOy7;@uZ=2UbyO5)%DXz?@GcH``w|==6;o%fVQf@{zxLAkYoWEeW ziS;1c!%Q&EIGw5X^C$z048@uti+j2N7 zmUS!zTgUedL%4tCq7Mm+WV~{o!qdZu#+jsk&8c^7ZS)}Yywb8hAH9fBh^{~fwbDOWLA34l`%fFgjIg#33&>kMQ8lK&S;TZ&iG|C2^ME#GeIIVEX*U1Dk- zBWpUQ*m!@vaN54fhI31A?Dbl7olW(BHgL#+|K)~q*Ee$;aW`oLpeijV2bFm&mF<{+ z@GG^w*Wv4;!|q##oaDdO80`3Kj(4ne^i&?j*N@|xMYA;xBzobAct@_ws_S&ln@2Wr z{IbP+XTRAn{P5%7Pih?9W%#8ONKI!*@#4)B3JNXd`1?<(BD-%fF4?+gxG9oMbIe-5 zu*~xym0ICxF2is|#I5Bkl3TuW!{JM?uMZDzlI$+|oOSK(*RiVnv&Fd<1HedtZw0&6QO#RrDF4(VLB_M)Jl^b%;PO&C!Fcf3b@OL#F-Iv?r0Q}- zr{9Fyx)jn=he&JBA|h3QnfESEe3WbGOo~rbs9Bsnk}ialjKe`6i|^bBG4piUOW0w0 zi-?{{JR05p*?&JCC{L~xU&_iy;b{W5lp?bN$Rcx%_i(#6d)~!{-8D`uAX|^iW9(nF z){~)#MM`_xiXnZ%?B*y1*JjCh*)4~aT1}6==izZZB6vCjJ5tBj%fjA>au~rexB?@A znDll;y_YUK4r$XTg%5<8_9M{1V3N236?H;rFfK`OOr}%^X&P%tN4BNsRwK3=v;MlU zOc!|r=5TxR(Bp=uV1iu{pmOLD4CH|KGwqVVme*WDl<*xLSI0oaS&@YXpwc?#=sfi3mSc#SAsM@b4sCcrh zSNOZ$#Ymba*HnkVam%0B*B6Uk#&6yG;c*eWL3_i$qR}sbeY>%_J&C_)>Ys9Y()u>O zP1iCYc21nqzt*w`Ahg2R&2-*^EJwfPchfs=OeyknL6z*i<7=2516MCb#=u9MX*Z(E zuDb1?*t3MuFMCJwyP!3lYckU#dwk4O&cd!}Ag8<7(e76x{zR?w?PDt!q_owmkf<)_ zFS4jXf!5su2M~^O0fmi`a=Fi}t^4=lVH$Aq_f`RhgVks$gRQU0#l{G#Q^iqB%t(C3 z5XeWQIO&!H%7wx`n4aR^w8L|eMzsj%pnX_1-#>1M9F!nxo zKKAg5-(}zGf5u)qbFis-)~TprkmJ#Y$Uypti*F!NM6{LK;kXJNRdCk#t6Z?o&bsK) zZMG|LAU~U_x^in411FH@t{{o0fKeP4KWeW<1aF+#N&$&JwMw+l>?(`xhvz<1Wu$da zoyY_nqyz9#7u)6OQ9dzpAkaH%`cj-0<0Yz+Omtf6%a3FSuPJAuQJ(*H-^Q;GmQfqX zV40yW933(5C<>E+VtHR^4$ER|zRTKDeP3vSCcwgou7_Xfp<7j!{&bidYtrYQtWc2& z1$3yN7E4BY5gdym%<>LGtXG(9MU<#%a zZl?+i+sC5Lcivo{2BV5ng5tE#nK>?Lb=K&Y`si^Bf{$%6uq1Tikz< z{Uo7fY~gi@Crp|en>-*!{y;1xh_tat=Yz6}3nr1_4CCD%rTXRpWH*dev)fN$2e$- zhHyrspg@!&mSwB{F_k%|HP}Y~HSILH4JT=q?j{M_YZCJZE;>s9G)4rNFMA=wy2_AR z9TCuY(YE~+fvgqoJ$fwL@l|>SiDRmZ^DxxWr?j*KPeqDS^gXQyPB8`ek|_F?Mch<^MM&Y73S_JubAXb@PNS_^Us z?fqHdM(}ybhWqEckHq6v%Tm>4wo{IFg%d%ROw_HYo{(-?`Beux!MELtOMS-l#Pt|0 zY0Fp{V~+vK`-St%`BMeK?8_w4Qb8J5NkBpS;>xDK9}M3`P?u%X=QZ$c&ud+KI7U+3 zX@~{^)8fy4zL~!H-=5#iD!}HlMtYI7{j1kL*N`kK>VLY+g41>y9&baZ4c8CZw}0Dn zpp&@(6Q-k=BEw(uyI&oM;yYhsE|wZWULNlcZuL~`r0AdzMci0%e_{wdUEb8>mqFj8YEFP{U_X^1v@0Uvrzs!O@F*GX@p6)-iM?fI5 z9`Pp$%_~ST#rMLFGt9qHJF;y&9BNSW?{usv`tkyVyieM;~J4>w69*s${C)x zU5Y1ly#5@gneu}r zl0Ng(!OyWzNAT`jMv2NDVk4FE~%#BUZzsA$?w zH#i*FhlICACe7S#Q?v+X^Nh~K{Xltl@cXeG70GtTF=FEiiOG2(*DWI z{h=NC4SuhMx!GjTOh852zWC~VRH(3(uC0Ap{W6u+QJ|t?!I!K_0%5A9>zuDvND_`X z7}?RkYLgQJ#1jkLzN*f-2$po~FbSEMjEqHglkbo9F4 z7}|_eEGJVRlGs8mafk(o41DsCVnEzoY&3Q_WaFhX?@wksoa40S+~OT_Qoj|m8+dZt zUiRHp@RH5Dr_6M*v5GGX!g^f`hTbMweEj6QeHxQT&5dQ}d4sT-mvuGTS}l^CYJGpG zU_C#WfMTo&Q?2+;v4U_NlNS&)y*Bl~^o@D>oikSHU*AC-s}j5M4>JC_XG>&J+PW6h+I?~`oUjJpl*l4d@U`Bp_% z&DE6$Kj`@PXb1Vl(!)k+uG;?TCzqT-H=G=hrvme z$SdnJ3_zHdCK)*X`h1-`N@t$BxxoD4_G&~Z$3%BLNxYc(09l!1b1Jl)(d+nXj>X{nJQFf>IT6tkj_%OXns*Z%Eil`-dT}~Ye*DYV#%fAXP!=P%C80o4D zAEl;RC&O_1AF9Gd-tehUbyF1$T&SUJYZ%$*#vQ3Xu(#8C+eBZ;5e&sx}Hizg;6ql4k zqTX$-rM3`=Ge5Lju2CCF+`eE0I@Z+X@vOg#le-3w0XvZUkIpR|?kC~q1vK7}q&3hm_|drGE)?O(@Y zIonG#C|ggyDvI&GRG}poy4arYcbcwyM0p`tnaPXa+fh&kSvCRX$$Z53gE8#Y)QalC zNLY=8W+7P0pEnU}Gb!r!U8M)3(h(P>i8&L?whkihOGVF*_nV{VKqxlIe27Fm!U52- z3V<;nqeiD=yXT@Xpu*k8vu(UYz^F^9-=a>-IN4jxJy~nxUxxKARd_0y3zTQINvYe@ z)m!dB-wywHQhon@znx*cu6af$d1^0h;as$SWZVZa^ckc1cE8mrEH-fE1nh-ny}*ux z;wfK55M-Iv%uJ_UkHn2ynot-7Pn$@R3tzHqCR-d^^-#<~f(VhSBhx6$)=*N&2iRyS4Io9-M zVGGf8^BeLE0e5fR;bWWc=KuO`^v}h0RE)hLomc7nQxw$;Uv!8MUth6J;p_Kw&UId9 zOg`g|VAXE81(}&OMu1W6Yrekkaa^RA{j}{Ta+pp7Kq`O%39#>0A0pAoGlS{!mLuX` zcBH-60S})`+pI(B`*eLn%*0Fg4wMj@Qfl)4yw9!ym@0LML^`!<0zVMGF2E`w-vIo< zEcrL*P3FhdzXhtfNR|2R113Wy?6;v^m5I8`(mou2Kb$jitsb>1DQx*Bj{BpYd;*Ua zJd>?cgRtY<+iOmIKA*L=bSfzFd`)LtksSB%%khJgk+(SvnJLnq)9Nc{X7fjDyuS2z z>JjL~y!y3FOJsLGbK+d;T2xD52r4ItsL%aRtHhOF1_@#YrjmrR>Z@{!=*tuy;L<@79aT$op%HU;qy$E-M>ZppC9B5>&L@VoSy7mR?Nu8^Bi5N&M$ z;;duRrI6D$jUMGdomL>(kq*VW|1t4YC5@p5B~zHeyKjn#FWq?JUnICLNTYvu+xu<0 zIc08G=;z1-(?32=CCB?YMYXJDmB;B1Jd7IYgwNgMdLbtZ%KF5obyiH*pVHUe3*hjG zQ{fBIlc({Y@AS_=oQh3xf!%@;35w+zXT-7%7|rP?!^zq}r7m^9TTFsdf|k)CRRgEO zb17x6N2QK>A4ftdezyYdVqY5Dh^CXJq z&#r*Y*aS=yexCH76Bvt%Ui4Cyia>`J*_!S6^#s@609`tvOGYEvtH_KY(=~e>WvdG9 zqU7DK1&w~S4&S`a>Gsj;jIr#^W0tIZ9$r%0S0uM}D7db6JJ`7+d^y^o6J z7NHM;H#qE+rvPd6!kk)$GEMK$NSP^jSjI;mKxCo^K0mfgn9QRAhbt|>>E2u5#pXx_yD||1E ziY$aqGLdw~d0{7YdXTVGR^PdVm$x@SS2oYxZ0G{AQQQDrU%7)699q$Kwat*HA`#8@ z_qedAHW>zmeB19$k<-?$sfgCUhRV;W*|jF7>y#V2>K|+OC~%rJ|C_1IwcEdlU%4Db zHZj_|yyo&F#X2KBN~?AmBB~-@6V@c_n}~T&r=>FM70AbPD7>kj$0Y9fFP=ya(gOIr zNJgKBZT%M($PT_W|4@JQ42`bFb7I6r7)UYCX00I5YHFnzS!+Ud3GF8MA;JvgW~8xRyp`DS{y9?3Zb^`whb z=%sAV#p}DBzi+$9Y5Nn7n&?C6=gv9NM*%aIG6&;|F+!HU|L|mtcMTD;ZVaG z|Dv!ifH$1sL&zO1*53qJRRkz7Tr5@O^H&s0DIZL*^=pt6U7g|9z2|gp$r+k=e)@2& zq@0|tXI|B+DLy)LZ$%g*8<|#B`$1c`jb3X1au^Q3C~?TyT(O$GX@S%MDqWNYvzKEs zMw;PlGtdcJYoREv~R@QDF9MaZWaE2AXTNkUJO7m!{rfArSN5O8bIr*pF9w@F|S2rG#Xrm(-%5 zOT8_ zydBv|HeX!i+VOfx72U2NzPACCl2^Xj+IJdSXtQ~%2arztBmUiTG)6Szal1DBAAYbD1Yae7sRli?t_&HB`N3B=tUhWD{ z`?9|NuD5;7CC!U-@brzwYukia)BwQ)4sLiaithf%FMT!?ShlaaYRE`NOD})#5>2}q zyu!l;I7-{TFFY7_!f~x%?pMp+U;b z$ZE$Ja{f)R*Th99iEYQ%2B2(g-EAHkpeEd3y?%E)RQFJg+rA%%VZAO5kB#s6wk)p4B*m47mL(b)?K*%-thFVzs+E?PH@1s-l!|kt%*AC$IA$2Ny{i*?64XkDfm7cc|3Z zo#X=I0fr1~Tua2#0t|U%OP;1R#u{(l;kY|z@K}qI3pL%Ez3m#7* zapdymh`$J=da_68Y->)F-a1}5YV_^wFxTc#gSSoiCE7)0n5J#o@Fn-v6~|y*%R!Ep;G;|T{Ud&S=Yy}S_zq3q;Ji$&NR9)9~ z&*pescTt=~-b>w8Bwm!}4dRhboQ>)Fk~@QJ`}h|X>HgA`t8wdTVf8iA+p{$G+R5B* zQFQM;c|V+}0WR|w;UL72;{fBs~yGWP*m~#KEv1j=S78UC~RC)=1lU4 zoB9d;xjXW%i+I0;|8r$*M-RtvPu2Tbkd506Z#}nNT$wkO5@1oHeN)*Wu0os#rU*4T z5$}e7+GAbo_Pc)VkJBSRk0ko>!^96Vc--HUW_xiBy`qP~%{Tm)z4l9Bdo8B$V=JgC&D3_&wf!+R@$DAV z=y@=hn}Vc^DxPTNJf=J*?CBfI20Fs|u~-h2Xe>(_UB6y;VxOyda-=Q^&?i`GrGa0P zEn>CLScmY+X~Ws>5jo(0Di%%Zc>@qKZ!ixDllLR2z$S($oBjdc zkw*|vU9J^EU^|r#5?*;NO7=3DtCw>j$O`E4iQlD8X>6u#1*GgTldA3jVHu_WO{~#Y zxlKm0qSGPg4JKxUG7kX9qUQ*6JXA#l&|sWGy&!<}4DkMmmj+Jy(lM^~;JpdN<76@k zl<}aArY0%CQ046+Wq8{-V6fv@bj5dGEYM{+<5FFlEj1u%{ra3KCT$ zmoL&blTB9+)~lms?y{$}cnxBu#n7EjdDG0YNZ+J)0##!)Ni0uG43lr)*60FrG`A>T zI_^p7?{S_|uUvnilqE32&Un8d>XTJT|JeLLUo6Qz{I7}SdwK%lycR?^GNPyp z6449<%%Y(Y@n$&rm0_ zIRsZ?iJYSeinDFzjy31a4lNe_H;Tty@pubu=n}< z&DW^VHHq_8#jRKO|G7<9W&g#Yk4c#V5q^3d{@?QFO~CXiXZQagq-hP=|GD(GAwSr} zaag*~UBMlebXhNlKgt@o?XB0!*j53Ta6?Mi2D5;^2QxZ{ZwWH{;yl&UYey~OQh1#O zX($@7hvb>-ortQY!zu5P>#rAEmF_Bj z^Vkn49J?7kA4UUkc^W4j-?tGpb|uXU43>f0n7zwD*YCL5lDx5dvpVs^os>@IfT%ty zz?`nt+y5CASsu{*x_m@xC1}7QYaW5GD`F`?sUxP5&7RcUVTc3SJdJq2_AV3M$B0c{ z0lx<<9Nw2}Xng+o27V+XjFlL$Qdd=~G_%iN4L%xXkbFHO8&Jj2-eXhOdW~vB#E4pf z+59==I@Q?R+(aNwc_I*H)doLC0u zO};MMtQ(Zy?Dwyk`DV{@jh4JC-XIv6>N9MClZ}#qFPlrRiiiH$w>W+6j?kxYK#%Kf z@0O}q`#IG13`}g!x3U!DSN>Rt1P(o8`dNg%XO>KlcEbeL35F>D?-YE4Gbb@Ok%=jm zr+76C8LtaC0qS4L)&nXFn@5a*2XRHacvy%)psxvgoBlQ_On?~UBFv)QI2npn6DQF4 zu>Fw8lbDwMB2iBZ@tzA%LOS(tn4X*{IXT!Iw(o76&36L>)uh-s|7keay8)RaT$O-OMfsOS?gz^ z)q;*Dy*NzSbhY>F0zt7}xT><8l2z%wd78`~g+R&3iLw_{IhVP0gt=(5O9ol*w51^u zv}n+WJ-oX(%_!fwj61^IcX@8wbt7Y(s^-Ae!$C)|c6#+H7y9fjegRI3G*ztlDUR<# ztRbU?TK?CYIhzA2I5AVj_vS-4!#yq?j`+$IvB3I6zqAucA;@e|Juu*+AROlTMRA3C zv^JYQHwp(?6RpVRRLzV`S8hNXb3>?>w^{%z+hvvRF51H@(bn3!9z8OoL@{oTC3_gK zUo5PG#+!~JJDO-NlV#Sq{UnzwIx|fetX}}x-4Q#yBd)%m>RHMA!Y>*V*Po8$ za%6z}eb&zKfp1~jluJH0Qk6N;LSq`V6rN#P>`5u3QAlD5KvXDuO6Sk(ue7>Pco(+V zCK-BoN>`iI)@-|hVW}?7t7sF=`jGYgYa@^FKzGVGzoP#P-ZOvNdlRa z3bjv{I^hTDJmX#n1Xcu1z0g+221QKxebd~jn~TY8jIckc+L?*!feURFzRv-AE&zhN zno#i3)UM)XvvyC!=8>L~L_)-mc83ypQ8!gXIOPgUB7>XXlr6ApZ77hdXva0`MS0zH zD}u1AP2TQk)}usH4NK2GO3vYi_LKuoh3*HU`)6yG-cs|)V~ zq~qa#B6C$c7qyKzUlw(uR#$a4pZKw6}pm|&{Xqv%icl{7SV zL*TFEK!7|YzRGBucvqd;)@hD~w8ECkZvTkvifv(Csdn0KafFgA9=^!nT{`saOZKyE z0tNZ2Dv8A-T^W)_q%HfsH)5=v0<|f!pg4K@P%cP@b1km|6;x#R_R=A~*>-OJ=r3Ir z1W4D%qL<#5Vu~7Xe>Uj>umF7-$z4^3dK zKb$YmoyIHYq|3X>Q&6&>(ZJd|AaUikt8WH=xyh#RS|@M7W-LtFxz}>Q^%E1Ie{9_}5%R~wp8UX%V|Clz0>S^fQI`U~Ko$`8|8CR{0o>9-sPljMremLX zZe`jP9P2qT+@*Dznm3AtkP?Z9KCwAMFDGsH$lZ9MuwGgYbI`EJ_dk%-TR!xG|NNyq z*t?%D$yr&*cR1!@q%0^J5XF{Hd9;_!S^7ei^lf5i$fAX3z`bSfW1gP6PwJSzZ`r$7 zcMjBgAhgfBU)U!(4*%?78Th9?VhUWL_ur>;`0-blU_1Aan#Wrk10T@%g<0e597ua< z-ln$$EBSt88dD^%UH0IQpBY@CLW#Gxb~8AFF!@-Xv|)>HL!$iR`J7k=@6zjD{p04m zN4A+83X2Z7&Ww8Uk@g~iF3}Egr^;#dMXL`L_w)x1gb`m>A!Zu;A&v4Q(?WOx?TOY3ik zF23B)W5_*`wEE60m!T9X z;x8VJuMnz5ohg%SZLcc=wZ;3lD!ao)zs!c*KarnyAD2HZGhNGbrJFrYW!UCyMteGkTTQ z3TncqAl&(4Tf|6uCV%H+(lOJWUe89CC^;;0Jk8uX=+^#J?4VS}+xNWnt`7XC_k@-{ z_4(Wp*rA746LW)T&90uo7`YcO9@JIg;XEaWOligRLHphgBf!0S+5p5=4rS7hOlO}S~n37}0cx*MWRS+7|U3{37?Irw}-mH4CX6kyOHeBD8Yft0k zJ#wZvjdn-D4N6IW1^VWtvI&;WJC+}UhX|R@N07B z=Vm24Rd@s62pnF5e7CWDAeLH?Rd0{u_7CuQ?#Z#LfC+DSxxAceW87B9jtn{Ei7xZJ zM1DrB%a_DMJdV|eL2Z7(Y2%d{AA^-ejx`V{B5Dn|s45Z%&ReO`3`sc3wGd@o;3r>^ zU2boOy$$cqY&@kO3(na9sYsEEu?q}_^b6AS&!=|P`!h5cTLXZ;eU=?nz3u4oQf*KO zt(rQzRO>u|6Lm`lj)J^`Qd+#x*KnNwip9^B&1__=;k+S_4?H;hEjvQ>vRnuaUJ?7M zSY`c&8hU!C_`@3AoQYiKZ=?>Y|FgmMuY6&MV&_~5=td+!A{GMC7vEytz>B~;;u@r}Y&@oI(ve-(U^#x{2p1&H7TkdLY0I4u7At4e5|RXgo8 z2s(x!Sm@R<*~hsD5#XHk+HAHGyS?Jl{>JaR zv{VHuA#1%AbQ}X6O2+_CTqEnXccS=M~!U>#lavBt35T!Ax}(wttCk?pdRE z*b}g#>sIvOaQZKMT&Ob3#d8D>g)3J+=9=spP#q9x$zNC{2-)o5krb^jw{Y5FUmn7a z!5~))&aNJ(?p%L%H{rnSZpGI6>tfKUffA0qiMMFilb6&+>5W`@1>QA9KNFL1)|-+J zp8Kkifnn6W)>ylb5{eh$3)n23Oud=v)>HN5?OVxU ze;lidx_@>F^VfHzl|^JPuFtUZh6qwMeXagh(UTmAhWu9>SV)Wo|3fSw#)6KYwRZn2 zlisQQw`R%aU#>$Azj~f{a>P_8aeI=nD4)%T->M;}^tbr(6fpon+c0_RL5o*Swx0Ck0=>7{3o zK1D43Grn6R0LDdbKCXHH_asYCq{{9Yy%*ciyy)_z9pA2O0@Vj~Rpb9`9ihij?M`wX z%Jd3#2MuvC#BWnVojqKs?lV6**fHw~CAvs~@BX2R)wCt?#;IE3LtgQTN zW@)hS>x%pJeoe_sMO8;tg=^>7-Y4YO3ez7f@+q9)5cOj&$Ba>bSOC%TD`v_|SfBZ- zu8xKxP{Wgohf*}lq{Ms5`fm9#vP_FMIfP}))`W$TSd+shyj7X3137ge<&TGxLjGE* z!gDvQFOs=H*)68^w85cdu{O~3ZIU~#q{fU`__xHV8ZaRSNjHOT!nZ&r^|Qp__6**7 zCE!0H@ zg8=KVO{3ZVN+W#JI5gjLW8tTy@+T?%@mLyXbbS9TD1Y}z>w@bY!H65@!N#Mpu5yFg zJ2TN@a(Pg^y-U1&G~LgX!1Cgxz}d^}2L+}&lj*2&R`_MXAkb^Kzy{EW+2c;l zjdnuox4)J}N=SunzcyvLuZ-Ri=PZ9NKi-%36PWB=imF^r^$)doaPsx0I%`eGWO(0V zv&r-2NNy5z`r~jaGG}(o-SgahyuC7~`PKVBa;xsDz+&F^>s&_Dqeb0WCK5|fm#be! zwKsvaQ8jJJ=n|pjm(J_oO#>i8P-g8J^e}urk?CHFYlAOm-Y%2<5iw^rFH0nSoDl1* z^bd^gl={4pR7Kz`!Ib1|dp+Lr*^6j|<~Gx@y4MW9|! zjaeN`Y@A)mwl=ENNm2dP%UFl&rUVycgh$d50rznYXp6Y3A3m3zU$hRO&_z%#q5+fl z?l|p>My^maXJccHT%$yvbs(2REP_r>ZPWs^6M7$oyi;P^vWuI)tgotpm+K|2t?k4g ztCKq+vYQs8NLX`hZ!+U`xYyd%P|)A*5?>3DVkwWXDMw^StgPagmM<@z@*uldqC$xz zacfV7z0^2Wou`c475Iz9YViz5#PDugw^<)N-Tnm*>PVH61 zbLqJ7uwybh1WH$CV>8e$mfHaPL?pgkXKW7y_>I?AEhpNuDleqrP+@A+7Ctxeh8VH% z$wlV`hfV{2)@Rz?P&43Jg0Gsi>+;T;YQKuFlJdNYbc{&zlN8(zr2*m$X(%?RYW&(FdQ=pNozYa(oI`>*#jh6yu*=DFo~NXmnXqI1x_s3O@{g&(!tn9G zrnWP^v{O9W(R*~d@-SIlsjHC=AVwo7wR|6-T(?)mk{7<|SVZg)6w;C5VKz#_r{PLpHp zlSp5^PMf|jM)4@2@4;(klpfKTGCwTVtKb=Xy-|2)m9Kuzb?drq{;#YYVuD&PQju7U zk!o?>NY;~#Fpc!)RQHd$T}kh0+=pdXo3_(8G}||}lP*}iQv?%&*In%6R`0E3r$oJs z!~VFA2ClBp9g+TBVX2w9TPEML(pzh!($jd6OtHG=&Ne!|>^3VJY8II*rU!Fw>po?! zLr{4937LywAPfpJ(!@=&(3@;BuP<#z<;3>BI*;{ANdt6(b4@&Ew7q5>rKO4zr>2FO z_vpYS7M1Y8vEbUUfG|Tx5cIT%L#8#&lLHrMGO6sq^J;nFta!lW_i-Y$5`cqEeQ+4w z*HsS(XIvIPojA36{%L>B_d3^={k37FZ(jHEhmM5hi>!rn4v_gqPFhq=A@w@WH@Eg( zxU^up*=_XY5J)bMd#juUtSGPC?IbYKr$3!&X9n7B>Tv(wLE^SM)~>AKMvyjU&Q|Ke zFZ)ep%^JcLVCJD}pCWTkns0vIYgP;AoZC||Q&xXNG?$U5N~ZNp1Dv2IuW@RVR&i^_ zfSXcT?HRQyi%N;fNDbFwlhI<%nkjOU*GJ@LRmK5ZMts1>sK@Mwv-j+lP}qVKb^&u= zo}?l3*Y(%LWUbsQIgP0NORuL*wI366^!YgVa^^7A=W+^{6199`?3V}ppKh=7xy2T= ztIKa~YW>}}R1YE%0I8S1C(|L$jAl2dM1@&YS1x~>23+xU8hE!0Phe=kCx+~M;HpAf zNgHV{FlQFi1PsLo5%1x2*)iCgBA>jM)x~^!B4y*8TKb3PMCun^E7ee16Y;fdyox5WX^! zurS7SQvG<)^T}G%I)Or+ok?0iA5RGS7)+U6oVMXxJ9|pb9Q@{@R5$3kUCzt3AX>cN zqfz20J@Sr~9%#}zi`s)~)`XIXXX~=TfPXkMeW!oYhRRU4&EK{#rA;~RnnF{41kqh8 zF6U-q-A*o8tVXv6o1N&{6eFTcQ!1IZ@rMWK8yi& z?P;bQuuy}fR@)3+qSZ6W*zRphuUNEqD2L4h*_YSuLbtuiM|hfN4tsO zv)h02On|yDp{DwFU1H2BJ4)eqk^!fRAHRW68z2McRRAX=4df&GE?>c)UAJD{oc!5< zR&>_ff%e)33o&wV!*I1HcbLN;MckLSLkaR0%8tRWb-tF0xIz{9c=C#03v__WoQnnT zokV$kpP&R`5VJ^$@ztu{2+JPcb=L)605mgE%JwuAd@-a$+ww+S?vG0j6#sRx(+2vT zpg%x12MqNgIw3T-5kPP`HR&w~3!ncY73uGX=^@VpMsv=OQV^BrunPtj*nP0pIrTR) zr{En(=HDWy74V!uD(NF#r@t{;Jf~;H1x2#IpPQ(rbvY)jbbDynQvC9QvS|SM^BLGB-JfaycMJ* z-u2ei4`dw7tX?$ILWiuYz$~mv?S}a?6-z%`!pMb3ln$E}Aa|_-5)R;Y6p5fd{7pTQ zr36d$z8o&3C({6g`$&xAM1=$g_5mPa}PEe;6!?W5hlzH}`5{fnE$zu*_b z90+IhU%D|-wEmKiv@?Kd|Kpu3wL<^ClPSVMb!Qb35_21v3|H8>N9PSBo;=Vo#XbbX z^?d{)NGMD(cO9ivFsH67IE@+Gx38ZlCF8i{&}|*&W5_yNYj%;iS9^T3yy%ITYYWL! zDqE;Tf(wo^C4C*B+44eHF}^gIM1~fhU%!37GBAl@v+i&o06~7){mpof*@;wL_)kz2 z@5>G93Yx<^`b#6`BraQqqL=i|pnlDtdBMg#!JQhBd2_w_Lto2pTMy2)CO7i)9@#tP z-Tk|3N1hfw`}mw)D8Bsa{o@bTerwEtK(gmlA%+>hsoqxOIq?47WJdc|=lc7$lEUD; zOti&ofl1M>Z{0#Hv6wxZQ~}r6`?j`?t*6jr=d?KNDzsFK|2f7sxqO^>a}{(Ua5MJ5 zu(>I-kFUy?PI6CCN+^q4v398bZRl(cMZmuiS|5n9DWZo7P}m=uwRSO-uf5GAmosy@ zp|5lt38^J)JdNaJsQ=VyQ8J?US-I>y2f0P>loq$4#1c-iW%y3;;OhD!%v3pB_ozp{{LysxNU$g9gwA4G&j@1mYlb8~W z8aykSsQTKPP!;tg;|*DOp11beq}~2+mAhyR#r5fb;I`MZn<0Cv=_@p=_;ZM>0Dg%_ zP_v0bK{Ii#?d_YiDIZ(;O7OjN-a?*UPxL@bF5GdCYSusnkgM{vbE13JNJgSE+IlO} z=5_)=&g6wsg|`IRS{HP5uKA193&XR8KVK-XB=d{$PFSE9sp8&k+p~AJyHHM!9_5`> zW((!nDdDw^8L8Y{$4o9QwQSD*DI=El-^hF%Rg*o_i8%2&uch4lf6Z#Um3kGFo>|Ux zKT~#r_qnrPVb^j@?+_pQuvAt)^{J`3CVU3tU0swdMILlM{%%3Lo3^xT0fn8i20{LM zHp>i?-X8saimj%_J|-Upu80*KwhpE@@>YaGHn}llfZcx>A0&ilCFmVs_(7Ac$$_tx z7+X?_tZ%sk?NZj8x{y0&g{skphS2PHzZ}e#9qSG6Oi zy&X66YvB1`s$eIXzIw*H#Cl*83zf2FY?q(9<#ae?WCv_>bZq}?bubZ~z6+#JTFY{f zf%Z4_xz{)TG5^5|Ev+<%8If-w@`1||uS6hx#+sOBAG_y_Ptj(_QWF%=q@-q|gwzLc z9}ILODGJbf;ue-sPxbH+fwLMrC;fKYZmA2d+w?XEwV7paV6R$&?uz{^?V$(^ElZC{ zTzYiU2;0oy%H_R-4yN%0{}Oh^0;Lye=8An%iWykZBZMN$0ooIA zg(_nNa`ZJXloE8Kd}FzLSSj!o{XV!<*XgXusuX=31g=|hS#aBIsSvP%c7k=g_O*GR z>Q^XR<)$fIJpjj`DrTvHd0DQ}wfIb-^Rl`5qYlfKhpMug#%Kq}RdDfAdQ=_;vlBbT z-x|7A#m~@N<6SN@(@EixQgWrJ%Z9`@F%>4b(IR7_>6HOyJ{?)q19QxP|M`mOw^@~u zQiHNO@Cy*p<8xiHV_zkiNE@Yb4xiP1rFNZ__|$$PNLB^$c}AUZCI9B0>}A_J&hAtV(I)@_uvc#Hy4z{PS12{eJ6 zA|+`c!DDL}4tmJD#7@DNKbtuc-Wv@X34y0teHK5!sgUJFBOp311hhFB0Ux0Y@5mMiH^aQ zoUJtgv(#=aKZ8uxZ0#wWjJrZ?M9?$>#jU9zI{)cAKd%0U{y;;E>6v-@gn^uFiFKa{ zXlO`OOcCv;2V~)xaC!IA!c*;D(O*^IFBQNyUsYXtryfFxp$^UfIFYZ&zA!`w6VK*F zv>aCzf>dak3Ne_}(+QsE`a;klKIY=8J$Z*o{%ZW-4Jzv94}RY<4SG4edizKvQf-N4 zL(K@-C z_Qg!4#tH9<^cP?I3NlTuxUx6klJ?vz=)Y8+%7}SE4n+R~@msX3F<_4k%)Y zy&4r-u7(Y2W@tVhzLS@{csGUft?Yx!_jbiW1-S&*YdvO2hd%D=n6y<%E%;Mc_2RD| z3bPJ6yEJ|`?fHLBo@wG5uzNQgeK)VzU7+mYcu|mLeHyHPn8s)EP~DL$fekq9zG&h2 zr0qGwIs}zRKCpOJoH+R~?x#DPPW-cyOOg+}L~pNjPYPW$I{rmxg*|(u=UZ>9g!+gV zYuoczQ2$R~>}Su8JonX4FRCWH7TENFl6!t*{lolNz9g4|WK&+0JS5HA6>?h6NdDTr zxs%ykaUX;imvO4X`dWi)gPh({e*V+B4%@!Ma;c({>A&kP_VZs-j63 zHo%VEewKlWPVz%*BJ<3@NN$$j>CSLq}K#5%Q8=8rI>qnPrFDvgij*ADKbr=Y&c+u=vP5i z{ddv?lnGm_$?c!FxjG;q@6N3ts!WbjZaq)zm}(9iyDlE132uqe6h#*<`S!A(ajCDs zgY2R6N}kj++R`Boz_#CTXJr|*LA|x_(=@cv_jT^Sx4mJ7A!icgrT20QUC3;}a!ve? z0Kz%8@i%DzQwW&O!*K&LpVY(wIP5FNE}MEmrKVQ}4k5BLU&1)n52GhwX{I{${07R}vZoe$n$j9{wP`JE&@>-&{#h$BcQIDh>tu#AM=A{7&easOK zQm6{LI$gqysZ2_4V>WHL2rL|u5G;> z6l3(R%A}E;hEBfBI9a(`&3$7NvSF9APMA@FBJQ!8#m5Lkcz6ND019SlmbUW5NNR>A>3C4 zJI++qZgG=hhSJO8lJ=?qz}q`OCC~5`?Z|xG>9I>Vw^V2Z?xFzsH_Mf1o$&D7=5|j} zgZIBEmax>-=MCj}#O;J_ib3hn;SAEXrWy}nlPEyd44sjP$sj^J*{?8lqU$< z7nAvFuZTfapKt{DtB(x{Fcq*@7Jm4|jU2$FT;0FlJwccGR;2rZDKnIQ=AP&|?*xg; zd!;_?l7@V$YoQQ1e4w1#V5GKui8FC5Zu*Y)jtXVV?%vnWh+{UWTTu(kvx$>?_(i?Om*$}Tu9YI{SJW(coR;BShP%%@frJvGll7vGtWnjikX7(@8&^R< zlLN0{nH!!cBp{sC%Ne=!09chnbpctW7CPT?xohI~`Z0rolO|XBrWC;vt@R`YFtt93LtRU_*VP#*`l?reG88~VK=>uyPZrl087=nWiLJ#r~ zV=pt%WOq~#b6;RpTdaIE5;HAu9?E$4k2h&i3BiI?e;=STT$%feie~vO-<604Oh*sf zbJHtX0?hjhXsagzsUwc5TeoJX+o_K{1a)~n8`ucj^c_7ZP)a7t5#aID^lh56KEDN$ zv3Q`ujfgZZZTmx-mGyE_ou>JGM6u+aHdA%r!NZ_2+%>Zq@fqF7)-CpXYkJa1)FqLv zZBje#Se<(yL^p&ao_X+nJ#vOXiQsCygt#c6!=LPbIPK@SmgdRh4o^I(iHgJ%SVT*ewoRltPQxht6AdmMgL~3RQl@Sw<|ho8Qey&v+oDTP%gvj z{rLQr8FIH8p5$m248_gzt}N$5O{s9fPwO zk=7U3Yb%pIm-}8Ih$eOsvmy|5tLG(eikoyE-mEIWUj9YNXi;>3xiO;bKuI=t zMnMuewx0a;kGtpp!1q%@Jel6BikfPcIXGbVWW0xExzwotSioCT(19!b&0&Jv*#VDN zY2{zqa7D)?XTew+$ysL2qa+A!V>NKT9@qS?sR!&y51=$&7EeO*;MHtEH}fO+*ZH#D zc0O9`-m0k)x0DUlx!ILk>%{w%>RK1N@k}0-mg&V8kQ$w9DoCX}lzOV8mI`A*1fL zKqUY$WeQW!Xy$$?$knXykg*2FZcfcc-&W#bS$*X&&u6E+P5tU^+VsAOb%~Avkr}bv zbukS${5^OH@;$3E0M~1*2?sUVR+FH{pJp}O3KNxYOrLN0B_ZRwEibo6e12g)H`uAsMQ9 zJzH1;uQ(%pHf{^i5hI%!jq{Bg0fS!ghJdC1D*3F4b^ReJjwa=hHn=!ak4emJZ|nt- zJ-RIJW!73&gj3lSb~4y+t`qmg6fNkcXR2zCZgvSt37<`nhWiE=PNK&&D?i>6mRdLJ zr^4-nH!xOf-Zc;Vd71^(=EH;6BCE=lV`Oaa>l)`z^=*-|HFzukqdRksA2=bYi!D zXz=Wm%JS@-peNMKennk4{@gvb$DDvCp{g%N3GbQ|Ti(meE~=bdstU<&kQ!YJr?k zByeq5i?U{+pq-t`Q+a0*mt|-@BxMuXorh1>#wg)`_RmImtp|>~X(7$ZgvcG_&bSN{ zsZaUD`@Nz6}7)n!I4yiRU za%6-HKkBkR#HiXrK<#X!9k`eJqRaT89d7Lu6R80|J?Q9@4{$PXQ_!y48-HB}fDIDX z#+Q=H=H~z?YOgD4YT^Bv2#ev9Z5)5o7F(+dz|Qv|LIcPpiU;@tdNdK$wkyS5=Z&$v z0u8%obuh?*dadV6zI%E-km9~hg&g3!_2Q(^kVp0lF4RPUN7aqy=B*8@W_z7_pFoXK z>K5!(F$u#N_EN$#ZT-y$e42C8`^R8zUiv3^+DrnT)=dynHt-U{ewWu3maT|&&oZT* zs@J$EaoNd09a%V57Xb{CoCcIcQmrZuRqg&I2@iZbIM?Zwz<%6vB_zPO?n z@a?*iempidUl}x!esz{q0Wy1hB-~H!N!xU%T6+qC3^ty1aQu69r=1)B1)-AkT=3OE<|8Cw6Ijr!4~gB zP%J2~NvxvnUg?A!@^Gwz5|-zMfMG&qdRW_+ipBZywQG)qK{JU~Kx%AA{8AF@@<=wyTW~(Ezs;2x9)dQ9CrZxjr*{&e+4@4@?&Difc`E3(RD7&dNV#)u%d zJRFW_x>>mjgJ_II|I{(uK2SNjr>qOY0ZF;ES{IzyVdt=dtp|bXCp=vG29r40^t2()$&loA;##=uw=JZvR^*}q5;&uxAR+--N2k_bNk1M`ZJg~s9{p@}5sB`YkAK>@e6L-6A{w(^>=Gz9- zz2g6y0BmygnSBFSb^Z9|&ns#Dlpm5vjNRmdQo~D+vnkN_=Qh{kP{Dk1qV3EMLIMxl z@WaZB85#&fpZ?n-!1 zBQoDb1~bXcVE{%)?o4r0a(u|g`jr%j0^F+|LbMqq)L(gZkILSJkK$dNf_(=2a( zE=W2*PVi@KM93*Rcws-Nu;H;Jc#@*1?`r}io1|Xs)BiNdKZgs#xFsav>q_2!3W*Z( z)&!8Yo!t@3%~EWOd1}^s#9r)foKHc8qG54ojcT?(yZ;<2D7EnQhDGk-$x%j`{+Xnr z;4F$d;9sifkDNDY0q1L;&6{`%(h>?|CDFR-sJLhcY^K}jf0iyqlD@2m=3 z1MR0E4yN_!7hm5^W=8Fh;&OzhH87^zG^qM)kMjyW(T+E;*B$ChPYqA!VTX4rzslW8 z9>~`#@f*Cbl`KvceqFrlz}lNm*^9aLYdO362gS=T^nXWI0>e7j>7vH4(ba?*n7PUrJEeOky|^BNT|y^=AM20#ssunV=lpI6=&o!ff-> zStMpY&=f&l@aBp!|3Jf;C|lFon+}{?G3YvvMQdqDOHX>IUuL9U@0ylx+UdD%A^Mxx z0e^FIntHYkpOWr0aB(t?WnFr6%P*QDfd9fAtAqS}TIDjzqM6kih_0ua#G(aEv=>#QnGT zKqa|N3c}WF8rLkP|Gg8e)IgHw_N*(>azn717(o`dEeg&XW2N_Zc&-?~0@=JAK+;4H z=@hZD5@`lRXqrQ>-w}S?Z`zoulXD>3uCtJ;^3#>`HjPuK-ZL^&EMH*jKR`hz>k)ZO zuKiCq#qJ})JdeqNGYup}h=S9Aa;8jP;Yt`JY&@91I*Il!!b?Rv9hA9tR+ZQEBDc-5 zSoD=bOFeK`CHZF<{b=g;n;rfHr{hc^zR{nTCEjc{t^ZSpL8T% zYXCirxZ1;5Q*w-C|HLeixG1n2&XD^_-c#?*h1#VDUVEO2EDxRu@({)m<{UZM>t^XL zyF^(K7gvdzPEePKhH0;kg8t_%)g^lMZ1EbC%eN|gepvDJT5d3%YKA6_kJ^&iaceP1`jQto*Hi<=>8R@xIqD{)~0p+=}L6a!$-DAoUV z{Wc}D6M_lT%Sp+lCLYC*((iCRVN>v4uXg>b3|6NgkMAe1CIYlCIoC@o3Hs z1_qLOfDgvIg6reaIktJjOdUBsTnnn}1cFI$5}!-SQ2umHU_aRQpM|v$G{3C_K8_M` zeyp-kK;(sm;-zr z=I|lg>u?PzMp-?#wS`PBY!A?WsEZH{dd{~P4A%wRls$(8OkC{+uv6^tW|j<>dag9V zalHz_H7k7Og%&pXOt$0JLJ1sb1qwb_0#mYNSjJ)%o4Ij7vttkWAu&=C4=-D8Jmh9n z;}@FkX|3ooe5+RDwbrwLr;|X>;BO+qteeU6(b`JM7DoMzJQ?R7!+R{tG zyY9GIq(@9QHq=g25yM2*(EHw1GruO*+5eNu_*68U3&i|)>10u%h@@rwOS!M-!*=!o z1m%8>Ld!(`QXWPWN(n%#V+0Ni?yD&NyLAeV@xM!LBp3rp@A5JNQ$H~V{`}$Djs1@P znt`*ob{*cb9f?^`c{-rmj_3O}2GILkGXTd{NT;D81%I#o(RRUuX{!__t zVV1=rXl;^our&M#{PekZqVByJ15e+4ZOZQ6!K7!%6?n(WZOd)>19pcw->Mu$g3P1+ zJI_gw9bdc@Ej%|Xc3%q5_I=wlu!2c@dEswrm0RqY?>FsrKvbL7R((e<5n2h-YZ_T* zc_dqrjcR8(XioehzJU+-75Cr%)Zu%(<3F1=EhgNP%*?SGaeY4?7tis3hr(yuNU2mO zw|nqpYglgkVl?0>kvl|6J++(G8aoQySR*)*Jkt^ z>DYIl!iR;E(zVOqN6I-suj;0_j%Py2f(a>JnFGnN`%f9~K+X$m0yEhqXHY^dT*gM|h?J`eEfZhn(KXixZ5JXPbxn-6_JILwLHxjGmcDwkj zb7NiV_fxcTt*zJsINr^Cljwi9DZ4ii;~lzR0Y3=NMFfS>`tV0BG7$F7vK*IKw7=op zr!zCIi(lM)-HP+V?paUUde#xAp3M5M*}EF+Yo^&`qIBwgr;SO|PcCxxPsE;7zT|r} z1y>Nal7c5m90a2Fh0b|L%`g`h>1O^l>c@tI8?U?)=@cBK4u z%9Pbep6ZT=5|zB7gi8qbBKeAweN9+%=$LIKKP7q@@`hz_DtmVe)=vIWMQ&-W6rM+` z2BsV$X*ar85oz^s-hL+;KoLfSsxx{aDpRyeB2;)VGnCN&=Gq&P2`B@`?B5y^0!vkO zTTm1Hno^(+)Y=eR7wc7}CDIf)ViN7o+1ziG>;~uY# z7tPF^&K7{)%C8Nx=D3RWCRoI73Rgg|C#>?mhtq%Ze^DKExZS&z*vyKuaX2J>C(Q5#35Hz47!8W}*f8sWr|~ zdx91)K|5q2V}tCI>Ki z)6Z^Qp2?rf1_1W%aaL=#31mh-A3s*Lm$AwKsz)iIo6P{r(&FA?G}&4dX~l{ADT}=_ z;VgNDFecY&F5Vp!uLS8$N+e={VEbWe_bde^qRB)!ENAxQwaUSl@%CP#bAHHi)hJ%+ zl4($zh_cA3R;_1>oMZ<`%C0So4HBv}b8(PEknZn=`92NA^#Jh}l^0^7Yt0l*6y286DL>ej?zsQnf*gfpj3jCOX7KgO$unz=is&Oihf_8_k z)2L)P*$b)qeljN+!U{>AMFuy{hXvkIB#j_*P!rcW(0F^D`4sdi#kZcU=AZ5kLjI2_c5ZKrd7A)sDSF1-O2^Qcz+9P+o_XCaNe?QQ-dU-6{`xB@RQhuS#Qyn=o2O z)BuHLY&gXRDsbV@BU@Ix>v)m6W+dZ3H?%l(Hd;?VhQmm!=`8z~`fq1E3-HF35jPLg*y;1y-)ZhBbpVxfwR^wHQ3$JIZNxLu6 zf1xPR)OB*bhU1o+yne9G&vvg{ii6!OI`2qzToc&NT5l6YjpCp>wo2T&xdyrK^@M3( zi_#^7Qi_hfWpY>|uAo+-|(Z zpmntE`Rm2&pFs!iY}~APxAJ%;+q)Ze3LoU(i@Lmdad|_87p_ezIUb};08VY9wXBn^}6e2DpslboTV7M zF%9}>?JrYM;g3&9hX?leVtoO_Idc$GC{rqAs)5@uAX z{!JY_+ggE=-AyVftEkji!F722m-902zd_9`>-7aI8%>BDI+$)Im`DQUp)HF#Xc<&WSsxMA00@ZN-IqE0qz@`=U=`j$lXb#_ zQyzc{?(=xGb$1lr9oqRRc6kU`hd{>J=C0|#54;9wPG-HTWPhCI|0C<|<6_GH|NnE& zoS8W@%`|6f%5;6Iktj?TsFco3S5rz8A%y7yi6w*(&RkTZqKS};Wx7DDB^PV4*3MKE z!XU(EP2_T|ozmLaG{2X9e?Gt4=kxvi>DHg(^*qn#<8i;kbPE3UyOW&J3sv-z)T~4Y zf_gQYfd|7kC)Q{bM(~6?ArdFK0%jjv?=mL)>C4HGn}K6r1iQR0u0Cfktl@@c;KQ0w zk#CT0Tr8AO7P=?VG;8rw>0x2)Pq7^m6i^p$)LmNmU1!zwZFf203kWDKyid@fj`-7) zayeta#s9R_R!B&4+Om#UN-@nuwhq+PzXKJiw^5Lodr14t~QAD7;oG)K1uXV`Jhujv`h z%g4fg_)&0%X>LTaj`a>5W%673^Qg4Ev(eao z)h%%@NM;-JEh8$Ux}1YAlJ~!;zmo(vjxkNKE|tif@psqV+KMmS-R5`x?oK1aK4;A2 z)l2u}VK(`o2Wfqoi+F$3$U3Wq&XxUbCp61`J8@Ih#rM|wvnYCh23_(vS_dHJXUB(t=qx0%K4@F z*tn2qP6riAZ)+^j6;(qtex8~<3~_?O$(2KWTSmH@VK(SucQ?cZi0|-H%uODZ!q&)_ zX5M14F36?;4KrmFFM_gcQJ9Xn0)HOV%y29)v|X*;mIrbwj*Wo!XWF`69A*0lQRM%* z5}P~t+-@kRgxz&l8NBeh)2hxZVr=Tx%_au_YFmsA_V>h7*?O47;zI7q%QwqwToi6lmRfgmq6zM?Xtl>3 z6L*%LM8^5{xL&jrZ4Re7sccdO$Hcm+Rke&cdsVDh66Kv$Fl6#*w@G+d%C`(;)PNDq zRUqm8bwWb1o0Ur9i?h91T&#*rg^jfhJ+}>fY5tg3dmlc>9AkkG|E?*>XY8>F*yzTH8FlKqs`NK3)L~U zLd;p*sTlSX1f!h02+P07Zj<&X?Q7%#&*00_n!L1m^hxC_PfSlKzwIj4C4?bv_X}Fa z*gk`pRl&%i7Y|UtF^cg8RdrHIJSKkiv$`5Qvo37AM*8RyE@o_9)j-!eHhTW~DF#sw zw*FvfWXFVn4t$!FH~}6ZamLh+_V3O9dPeC`)-Vrw#j;l)m0`XJ^KTk#mu7)Qg$h&# zDY;cq%iPVa(Ft4x|0;jA)x-Iu`%NzcwBp}fHb#B zybP)^O9tD!QNmbiQn8jQX3mH>sPWqlGruZa4EyMKfX?`N6R{}lF=oC}NdfQ%u zgFvDg-cj?Bo|w~&sk#=}#Q=W-I5c{R_gzj`(Cl#7W8v>gnuwS@@7RYp*VCe3!qEVR z(C7v3F`s9gLL^iB(@7eCGdr3kOKY)X=uTelnS5{GHmvTIk8Xm0Ep}oELJHNnI@9oc z``2?S7P+V=fWin@DF1%Cozkhlo9&@U1ZVyA`xnQ6Iv#GZ4(f9&*^ zqV5d_oH13ox&P3wBUiLX#x^3AzZrDvMC>o_U0Mm|*#sgM#<+*0CgvC9{Pi4kt6#Db z$!EU;K`8%nRnwS*CsFRYd81F{1xPsdO_!`qePwg1P3PK*)*Gtz)7hSddt5Zcg5Nn# z?_MTjL(1zmg5U|f;LcejP!kW@b8;E8cK%nHam|WX{AfGy%T4EpP;(^aJ2-<*n@b|W z?>p~;UNnsn^$CMeeZBdG=lBKV0{-lG~}wHf}z} z?`yN?Y`80_wvD)^uX+^iCZ=q{?uPUwk3Ohh)dngS1H9m;ot`+WbmYfm-{bkvV~-yd zEA~mjj-gC3dbO1z9Ui?4WR6+t3=SA89D8gfG~N01TtF-!k-C@;YH@so>J~r_1-+rM zF4z~7X{1!W$jX^{pWc*IHGhMkd!}hv^I+7K$W>Gy&+U?X&##dpliW63{aXx7?|B&` znT1^2i;C}?PTh#ih18|2Shv&}Sa9&PTcbsTJKm9=8pG(>V^>-F`iEj<{jx5}%H~a%cWh6U@NBwlWqb)*x>2`cyo; z25ZrVKNj2ZB*$67NuxfS>!(cyO!*!PwhJ+nC_A`ZbmMWbw`ug|Dr<9_ z@1-w6H_tg@Raa$mIGWCkFM%D)nb)SkfawdoU%5>$Ud=w~^cAM~g0xExn%#^{p0q15 zE7_?t2}e**5q@J*|6ns{)%JZSe?Kf*AHtZs2yhEiWH#8zr_18xuj&k-xQNWMt9a9p zl~o~l7h3Fr9DbK&&$ib?Qq)J^I9$rDHcPr`F`y~;eo~MMzB2Pe8#4TT8kiu(s+cRm zV#Hetl|&Yhgd?;~Eyh*xOFbQbH=sV2Q;eDUSvK6xP7?Tu$7M$in_f^nnSeBNL1=B6 z9zn;0mVLF6=2yp;rUnTgBoeTlj6}}=;J3em+BW1edb zjN>tqFcUQ{oTkAvBzMiJGT&;zBM6Cd@NHD?f7de{DCZ_=VC9vx1tG*h+(a#Z%jWY< zh76;%9HD`GRb1>6;`u$Zv0}v7c=gD;jhuzyfb}fXkQXf#BaTZ1 z5$4?)&N_5fq31ZCkSpS2xE1~hJF?ZuLb-J5u5IqoSDE)iQ1B<-RH1?Pq#M?bC4^z7`sJwY${23r16Q>MU0g zj5pLU0IZ%klTn;Cn_!O@vvalP_Sj_#@peGhUq~QFdo@eB*fo;V&6`!&hPr*#vvd>jJnZwsS#U!f2(6-bW!c`?>i8}CS242`EnGjABIOgG-UPD@6 zD}ms?@|$GllIkn|-Ry}FO%Se^d@qLJ6{`$6E&YT|6)4nFOE(F{Md?6zy=$~qG+VxV z+j{~>SO$2uX4sVlQF-8 zx8?{v3kOS@w&QfZmgU6<1mD>fUQ9^Mm?zicLEum8SD;6(Y&^AL3@PQAz}TQrZWyjm zO#)uGtO2HA@QmAO9};zt87^1tcWG`pE4a``=P&zI;V8?rI&1`=n{N#V{{Fa;Ei+5<)j4Uk=wzxFkU_^SK{?nd^;p z&LlQcMwicKB;e$}CkuTL55`Kw)}Ti(-}&(K@W5mhYFNXNt=-N%fj0~55xWM8L~mJ& zzsnX+5SA~JMfa9YYngC>f3DRVQB+oR-Lpp{CzJo>=`EyV9)kyYkxOFaZeV|-A@7#vEOv>Wj5?S~wdR3YyT#;Gho? zZsu6Y9PRKe=0oiIaB?L-G zS|4gIx#j#){&zC6Wr5;bW%QRUrRTv0u}9P}SNv-Dht#H|qW8orTMR$ zh201%P0O41m)6Lz}NZWf%>NVmDA2~#>F&&0ftGvZS{lg5M6r?b?ls{gj1wX>HS z{DrGwhTa_XtkBXz`)_+APO5EjJKchfw7~O0x5svWq1~L2a+!8JvZqbW)TT{^l#;vQ zjgE7SN%CtG)};0&Y&uCI$-cTA^_9pPQ=W}`p5hTscW*m=!}Ttfe|=ch_v3Jey(_8O z^VDAl(OKaD^B>f->ITH)SUU~hdip$2(o*%$Z;!k<;H`sq!t`9=fz7xvVP_hYzWums z7&|mi*65Hjdm(FQR8Rm@I{J|axgHchSjRvEw;p~OZt@*=9c`XV!3>dspB!E;zgj10 z=f~NvLIX+=EL9jJAD0q>zl;8sd44mJpNQ`sdEL3X zH`a-?#E-8K0{0FV+YNL-!X{*dp$B)K=@bq&9DfcrU7u*>h?VH$o%;;%z1Jc-tnONM zJ2LefYgBTWCr-eK4K=7ccYDBltIJOpU#6}_5;MvJ^mt<}>DVc?bvI(cY{#kPchwog z@*#=OOH(F%=azihRTR&u-8OP@3!)+p%lF|kcSURm$<*vD25sVph9;kePV;QZ%O|W6 z-qy6NYmt|u%~hzQXcZ4+6-e!*w~1gsf8%)6R${Q_S;EAK8+L6?tcF+4& zc1`r1-+Uv%ZUnX6JE37N$v@$0)hpM5(80V;Zzs<*gL_8}PukD*XsJdc6G1-zxRK_W z*S3yvdPFt1#iKco7M7c#RC8ZtvXsN>6~=8T1zsL`uj%8j=h@CKtZ-yC+;+EqRD8=C zB<&+ZR6b-QL)w+$dWDSoWyo{ComUcZd!W^Is8<7TQL zmt0@BwZD@wZQudKQgC62BxwTBLxA+czjBy9pYPZn{}Kfk`e!gXgf16IQSEfeD2H_0 znr%QDp_1WKGqwebyq%_67^8>cR!jp;OwX5Q4EI0GZq}n1 zCu&Q2bp~KFNq~P1jXVpnN-60NK6VhANJb!^Mivs_*E85KrpgEvI?88W?>OV^TS$Es z)geoPtEgHEr|E36s-AJK>RXWUCWw|u^0(_+FeHq>c>0okRkNGvPMaIfa1eqri-`kvru)Z^+G*=v+Xq(NX32jro$f8W0myf-U zUa4*U1yVobyBiF&L8v?^T4|SJ8vP*u<2>b8JDo2`wo|AQAQ-#}dD6tYyXgbtW`cqe zbIb#nu^(}JEmy;d;~X1`+?Pxr3xGZ%2&PG)!=nRx^sZXMR;(s3i_4}q5FxESUjG3c z>Uo8Vm#&|Fgoh3l(Ej{RThGp{bgniaBm}Qch*R=7=*`I%DWOxGv|AYc^q(o(*H5TexywdcPW7P$oyNs$So43OcH{PQ8HaW}|Q%9%$?0s!3 zMRO%~u)z9<<@@lV@jzGQ%z8L#$@RxcQ=7gwQoL~O)2`5|YZ-o-aS@OIk$$YIXZy~! zTnZnKCD zPu=F*%zmdcY@4_&X$pHvLCu+H4t{qjzaZ&W{@M%~=Eh*{r!>%chB zF`2BG(dO3lIbuzD^!=py$OI3PQ)s>be5Q5>FKxV6*r=lypH z$g3}B#u=I>C|P!?qeEbc`tx7>_T8O&BM1@(o9|1P74;?v@qsHh14agesklocG16-; zwaR=`?>waWFQ}5(u+{aMk^~pIsmMQG)K|f>`MSdBlF7k6Ohy>#_G=(z9_#B9t`nKR zP3QT77i|w#RX#}_a_+wis)Z|E7_E69u9s&N75z#VrUMQ}tfJT3ofW>z_`hx};-0Cv ztE6bm7jvd8q8Nu98BW^OiR-X}PYV_aDivGFBt?KyBFKmSyP#Tsm|rzte=pfh~?wu zImadEBL>?&Ir(O#3*$nJlrGXi*CtvzV%6jOx>lBj@2aw|;CrSil+7!WVwKFF^wVrG z#^AJ@k<)$6Zq>$2vEf$42$B{mIXGA`_J#0{A%FCQ(KwpSQ{Nin4pg@RX9R-x`5CLN z(6tNJ0uIa7oVKGfFk$l}JL%mgZ{!RYak?Ch4{2%|Vb~A1MWzrI-m>0qZB}7MX{f>X zQ)4q0@~L0vyzCzbkrFu&7p;UH!~bb_ef|2hfx#6hQ~~$j1;&n}IKH^3uJPvy%be1P zqH&i8m0L-tY-l45Q%5F2sv zf9#awh$(}Hy0_vM_8L!_EaY*@kuAOk{t(%EDOFs)IeG~ppeUxR{KvYsLvei+Q?z}& zr!^%z`qcoFE0;IkYI*N*Di8Q$`L>(Dp4@&G<$0jD{Ps$kJcA!-hT)8d6wJ5CXpPM2uN#defn_65;54VIKX0^cnLWZ~&S26~SLVY#W zJmX`|NTB za6oGoW}*CQTV;NWc4Z@CyXSoTn>^Z;Z*W!V;`5n{>UaG7k<~)meO~R2N{iw;2;_0p z_2Kl>Wt-m-2tNcB51Qe(oK>FZMyVs-OUkMjP{`xvJM~_;3O|dl@AQ|64)<38sI1G7 zspu@bX#1=oH64Lbu?wVfSvPXOO-;GrQigR~?zt9fcyvPJ={HjD%G>ZLFU$eU(<}lT zBc1^gyVxb3#CZbg=aRF*1CBh>yu$vqa>A`%l$A)~&%{L^Z38F&y(QCCMO+DaK;ohA zYVAY|4Lb_eMZ%;#jCf1Kuu|et#A@DBqeJE`<#5%4q@|(3%ar3u$z>kW*}t zzm#C;4A%oqR6~I`ckw`p&ue2Dhl{Sq#Y)#)0(fql_@I@7w%K1u*3*Wq63Wop#$*P7=&Rs!P2kNOUBbW2R8HtEBi*}lekJUD`j>wF4 z%i_M_bMzDo9E=k3RP=cv%}fJ@E>412f2JamJQG7i^%T)P(fJ2d_~0?K(-&b0+y7Id zx?M_V6Vfp&VT|kn1=6-6JHe^a&A!k9<}9fj%;?!GjRxAJ?ZI#N+|+a+R^i-yihFJY zBRXe~9jIu!g#@S)*=TFXrsl{Y2mg|O5|1p{AIeRk`FLyWLLi2hyGePUt-+=PMB|WB zJ*mH&*0sb45+X&Ub{$i>PrfJMLKP+?PA>GpJuw+`ZORrB~fhVJE3%vi|IwdNnsd6hZmU5U5->q$rkmW%**#i^yk4%HpM zjH`{{q(N*eq2lUIh}Z%%ty6E3Gb2{)+H~z1zj&ZE!>HGg>7GedUhA&SIvm0pY&KXM zXm-DuiqWc^mww85=o%AaINt5yMKn1?>pk?Z&|e616oK@@N`in4kIU~(>pL5U*8YlH zTNz^F!}oD0>|uiMsf+4P?{o8NVv`$V*1rF7xhT#2BJ0T?xA@lHh>=qUf0}Z+$Is}u z;7|O29$+?rnnyA;?*HAhh&nTx{>5PwVxEStI1I-YCtN+s1W2I^4e3 zerLnJ{fxw6yJEsUqaJazPk#PRWFeb4czxrISAG%($B8BQ@NjEtWIA0SyG+%nixPI` z$PJ|9nQxc>V$rFqEQ^!ozhrnemam9HC4;iLxx?abMmpH6<242?|Lr^2MLys9dWp?% zc?HHaV^;QB;%U_@RBHN1kfmlF7@k>8*2P!9Uqdpc&#$>e+nQI?Fv2tom=<6zU_+KJ z&R$&Al50)ho+PpnXm*obgVTWNeo%dX3#~|56o@$WR?rzv!&E_^bL^B0B}>&IaAmC-*cB)Fr*C)h~*9De7wXt!W-YY2#E>gFSlaOH-xy+orM=_MYCY;V3C+R z(SOn$2fE;V86V8@s#`(JQqPnzZIb@Yai~N&R&a5Nv}>8OBkqz9%RwnG)+xEQd=CsFIyz#b?WeBv_e5PU~w1019q`vca2IPUI zvYi6%K9&^xmGU*NVYovra7wf45?1os%Ho}Gr0+m|R{A^hF>8CTteB<@v~l2R2$SoX z?eUT-EKVUo&n6gBqHHSrZi^a*vPg*!md|zr1_yG!)%VtGU9hWY-aSXX>r)&LD!gd}FJK!Pw3#*Mf!l{p6*Jr)G&tNOxp!?g6o}lW3Zs3b zV)t94TO9t<(Z)RH(-+HtA-B;m^4JQHBT=yr4KQtTCBW9QVAgXZ#d=L@TrDsjWNwaJ zqsK)4aS7N!bHw{QWvLjw04JfLx8D3&ZL0FSAOgwOY1o%BsDf;b9MoAajXYmDmY+wG zHjP`RW6^e2IcUzA#Uqm-`ZWvV;QLcWEV-VULmEAX->sNvu66&}HIDnTbCNOy6i__tHCwJn?SI)Dpd1K!JkQ}y!2+L-(wEJYFS(uL#c94glN8Lj7geq_@K0&VGpU; z?htA(x2?(dOClH9tJ>_d6^C~8>w${6#|ihj&zntC`0~)SsY_{I=DV1HM87gC-5bwh@23Od-La~<7lOWvh|KJp3>EBb;vTa!LY?H|$*a?RI=HB;(BK1-mX)&m?RMT7pn77qvdqF`uMX zcu-ipZzi)0qS-n2Rr>LA|R z<1{ptyd5vm&XtoT>3S7?oW)Q`0JmkDV%2j`3*ARY@e9n57g>%C!75%Vv1QLT3`wXg zO9y?Od0XUFT6y*F40v91(S{13BIZoBhL(630StvhSKwvk9^(CvNH%OEB5yY zND9jrBa@L?=8-;$`m7H*DY{Tts%@uFk) zzNuYpr@W;g(~$JfZqAHR6~5EPw43yamkSRZepFX;`tVI9ab(>;JKASy_mN8u{1i7; zq1FrByc{}z@A@U})%rxLG2gR@Iav}`_wYu?Yh{i!Q!3YWyuMTV z!=DFL;NQcSC|yl1Q?;h+i>msgxv1GLhvz~)_Uz%Q%_m2V`?O$$FxcCUZ8Ny9rn#ug z&&nP&me1m{DqURP9G*=7xV2&IBC8C4`QaCsH-=;QU^}k?z03R>2^}hYAee~DQct@1 zATF;*0PZG+D59Md_-`3b>9LaKV6h=#I?2hXpvQ^;NrrttG}&o^N!3Ig%^#n_u)Rtbv%TbjpE*qrx7f9O zte{~_&A{_4a$v9oJq4Y+oxiL~+vb!=6^(y^X?p(Gb_0K!fLB{$nDKHLM&f1OILsdY z>3Vppj)IHu&S$p4ijVgRMx{g^8~UQEW`xAP>Hp7?lDivFU*dU%@4-Q2kpSJW0DUAWEBm2b7;UQnH+F%;JFMQhn+3k zf{lE8%a7T>x*1t;p1EawlAuL9F0VY0&FXQ?H`d)=(Xre4ifF|ae?p$u5jo%WI6h&= zcFJ(lN+P`AU6-Qd;V(qL-+=y_H4)Es4R{T~TtW|hvl}KV>A&cU?oa&1ESch4C&<3( zyNmkJO55PrF|5sVzBzN1z^AQpG%MX=NPaxH>P9m9;<=6g$82Q2^xC@cJ1Wk{^psUd zrFXJ8ZLVR@xT(|rV4?0C2qg=kEmC4_W>hPg+XjQm=FYRX3Sxb&iNtTTv@RE)&Z*g% z(N23bq;l~&?mx-S4{6}S$5o?QFgbA)h?(ut4M>a?rpJ%9dxk9l6 z{0>^}@5k#{K?6%u{*bbTiiha!fgN0|b7bCWn9%-SOmcktUGo?DG*k- zXma`oobB}}i=yAv7$2V*Av2I7X z4F9|%*#%OMpF_4sg%h0B=ks6{VIu)BEgoJC74KaIITTlNJS$d4%Z-<43bdMZIAT}$JwQAU2wo#>E1Kk)yJ@HDUiX<{wvEB zAT$Em1pXq0gyIL{cE1+mJYfHw5zH9DCMeFa3dSy7lgD+~#zwI$)MMXotM;p_gDW%L z>hnl-@yi&1I8C2|{)t3gGrEEROXOg@1oHdPV z1|R$<{5skyxOHmVl4Y6GgWnpy>4;|e}X2YeMLTVj{#8Km^n&R9lDgE2UI2tYn zRL@#LR$7cpUX@Ptsn+#@xM?tqq7q*}cb^focaNh$ZZB4QT)~uP+vgBZcn=1k$#INl z+T_$I?(Mc>r(>sVehg*C*jq@q)Kgo$8W8>uQ-x7Jy3)e>XOJg3%?Il}Q}ph4kJCBK zk;1&owjm1cZ4-SVdUyCeZkBL-L9_#9E)kIm+RaMH=5r&<%U5L=gGEaqzpGPTHoJFf zlhn4}`z)fKP%b2$__mkF6OuU`Qw;M){7e<+FFquOqPXNoKyX}QS0-=51doeBqLnl07%ssN@zx7t5Stu`eB&4VM}O2# z+Fd%h0L;#BFhUYHE!?Fj&mDlv7K$mh{1kf%QPXA>LxQikjmD`&p}fguK)xsN!bs1# zTB?xStY@VoPV>cRAVt8KNHXly>A=+zNIMPG{BU0b^SHB z+^9lR&1JMZqb68aTxkDdzdfj!Le38QBLo%vn}c?3&m{_rHo%T;TS24+$^y|nz5<%T zK}L`BiyrGP*UjQRuQer&M~J+AvEzFyW~cfD{xIdKX4st)ej2q09%N4UX+-}@=wXdA zY1X>_Y^Q9mb@Vn+;Un|qZ$c=n3`~ybFee@-gE+VPqZA_@5VFVLDpbOz{x_@uJy)qi z?Hq9@n%2yo#o2=8w)+Z8)^mRI%N8Bse^|Y z;`hxhVQRvVPR}Gau%8ji=e|<@6B-w0p#u6dI6OVY9DhOsr!6P2G>KcWSq*+bD_Qfy z1N%&+I)ykmd(C+-pdjUm6tpW(CWB}?Y>UtPZq-xlu=5yI3|ec;6u;ghmcy*n%YD}> zH$3}sO*Jf*@FxomjPYCc6c4=a7n%lN4sW`~vq%V!HoJA7pfQYVm4AFUb)QhH zk305sV^Yrv*Y2l1;`HF5R`s9%>!MQ#iJ%k+Bw#TsWM#R^8udmsW|1M>=EJeUCU?tREe_|wh{6@!{_G-@2Jis=`}V1YH7Wg zEREP;Wh6FQl6Oq1k-II_DKs;D=HIJNe{F)B9T!={721SziemKg`xj9Xy@Uq--iS7F z_o7EXSzp_pKJxBbz58OU#?&7zEw<72?z%$MFxk0C)|Y+tQ{33iTj~&pPUZ198^yk3 z|HPH=WwNysY!0o{t(J0x>3;9T-K_^kJp7n6+wnwevi|7weO;qW-%eC^`HPce86!1X z0TTYGWUOP*ra8_g&Vh9W#mtP$ZdRLVI_WDF3C{RCh-bx|y#+_LMc0sr9qB=NFSNh> zyrR!)_%LPa?bWFAKdMZp^1pC8MwmzllIba=Aw>_tj-&K==BY0<7m4=H$J-NrF&o*G zwY-ms+Iq!Gu*=m!ZRt&+9ZLF^^R+79%Faa~E-u#XS^OSB@|;Sc>PZSW)4nz>b{ zGOQ%b>S~{MZS4Eb-mN4HNEyNlboa{n8DDcIY5t>(WMJ{XT9CZ7ZLGPvul15jqcbQ# zR0K~i>^3@|xc>3q>kw)Gz8%DA->3H7rZ7@<=;uBYIOe>-f+4ysJ9r_WlhKSB{4Jjx zH4HOYs>BKO-QOYV)+FCGd0BD8Pm+Dy;H1vXlBzUp3F@Z{CzS$oT2>2snj8G@c8H42 zti2$iO%M0JiGBQIf@xN3d)DvaPdQ?0G?KwL&=!61z8zV>0Ub=ZV0-eU%_74h$?_+c zQu5qD?CA()@{cPO~KO-g|5+) zc0k+FHpUv=O+FJq`=M6{c0^5ijU?xNrgLS=t)YARS59$y{Gzit(muL_V!63?J&Cj{ zz^?=uToJa|qm;#R7ilsz{Eb$ca`?*u=}g|O{U1t#e(P7vYi}QDedBr>#u~bv+Qjfe zYAQJa#0yKrSIL#QGS|}w{v#ej36YMO*zEpEhrkRFw5YEg)-Q{Kh(;wH?{OZav@}R> zvw0xO7VRW+UFFp5RGKhX96Qo#+l>zfH%JWpHV*@Ab8*ny>6VN(Zu=?vw55_wwD_h# zO)oF^Ma=kZ)#~7U7-17jiDg2@@cj@cEWd|%8iZw5{Vlqf?&k=Yr0x$qZ3X8o9)mdA zAyNp>$e;u(Swi}YcSh~{hNu`Q31}DFOou!-IF@@q4}`=43n2I~-a7tc9#>f)BQzF@ z8Ky^AdZ^6WIS<>lvu#shChVrAK%UCprRUaGtG<3zDy}?Pnd7(kv-?_$8t}`agc@Pn zIuoH?Vb0|KfnOOu6i|YN{3{Ig^OV!0^ak(gQ0(ZHVjFpMhOK*blmjVdjM8#Fr%S0C zmA5tSePM}kptFQ{aLU$3sP}|@0pwE2Qfj4yy@KT4Sy4h?YJi{|5(Q1*T;X%vATDOJ zDWwe<&qQ;z{J`G8_j+asIqRON$yhdSkY+#ke2d?3qGVZHtql?oJrO|8nQgGLuMBc< z4^a7@&tNw+(D@5{S@Y(ZBOLRZgj06ld1+1V_g+5>WA4m2S@Z@mE}@uj*N=~RyV~(}1Kp_{;4%{fOO8IGXxc`0yw#+H>XOoZ0y8Qk z;ZV}I32l45?%2-6YTb9I(MDdTIE!5+vx7dhjyRB^WhfwYo45sC8BbS2Uc(kz)T8o< z(Myt+APJ@>roq5;Y1szcp+%F{8*3Ji*6eV99UCzK(#hp&7{ZIVkr~j5#_y+Oz~8`Z zMGdwzAH9G-b1GMApDxfh2+8)?o#3;d%79!5ZA5tYmQ@@tZnEXT5m`!Cboq0S)U+sv zde5z6(}a~)UmtX-yoi%pLwB#1+Ta0YLHi{RQxwoQOBFPXSV*%MN?Zo?8W>F^HVlBp z)hX`!@ER5Ga~wBUek2*|!OvStob$FkRi#R-s%5}6b69MXYT9L&1-xD-u4KduGT@*Z z2zzTO-Yn81j`|0p^`|N#F8%F!M5Oh1@8-odh9ct%Vx`BFXlhRr_ZT5V&_>N>G?Nor zMZuFAwPe49IA%N*0;F#pIekPSGOBz@K=~_o9~##ZRR!4Mj#xdTilFfsQ%g4c!kmeU zP^~t~?axbw0RivzzE3;T2 z$2_{S1?)d?7y%?;kLunBHUMDqlG>Il1l4av(&(X6ES!RN+}R3Y{&_{y{c9QSLWzf? zQ8OIPWHGH4%9hboGNDUhz7dMGtNbcCX(V@T!S)}sj6QZ#I$COY7= zRioDL9f8Z+{*FwD(6J354ve`=MZxcPr2B@jL1Qa5qd2{xi3WbcbTk*WNNXV8>!^|s zZdxJw%p-u1(Y;cYQHLwK`0$B!D+%2!sEKvKqGqkh+lzJTd9uw0THVOhqbgCavL_+$oga8JtTc}68hXjc33SiRRvqvM!w*(3_^SlZ zWqQ3@vDQkV%S{YcBYa@kWLmdl-&z@`llmTBLaT(LfxA?$LgFTd>{?xdiiv9es$dA# zK^P7_h}nGL$m+3}TK@wqtcJtRstY{5XEO_=A+A-cHEWf52|__EK#=_ps@ZzT6L3i; z{=ah@NVnDeYl{(tWFW;~Z85>s87jWB{rFPXPmMHig18bk&p^j{OMF3mntt`8Lm#$a6)F*oz+kUZ3>&q0PvL zXISBBov{^ri#B`SKCn|^ObwgH3u}wm*Dj^a`~BRPy2jm$)%dmdv$gnSw^O*#*>Q;J zxpInTSYT8lUgmxhXAgb<(?^=>w`-o*oNDsCV&P5OfN*_rvMU>@ALy>@+?!o;51p9U zIL%_zh#xO=>HrHX`ZabC+1a#&cQ|jaZ1MJcNgd10jU#-lGBN!57bdNAkqqa!hkNfF z>6IgfB^%M7?GwZhGJoPi6qhGP3^w2-3b+@^jD(0P$z;dWsVuHAwPBd32LGGKy8Zp% zfFYh{aZHb`pBn3QRxg%~a_m_vU*)8;yCo8ky0(z>uAVjyYcUb5=8mc|eEqK$%(K_)xxgDb0XYZ2Geyk6cGkCt>Wb>b#4xwz_2{*hC}mDL)=it1D=}5EYkN=UhVW-D!u0l~i-r34}%CV*`}7=`EVX$wi?I zSlKgf1bPW)eyXlyY#QC**|_f3Ro4v6KD?G4XHh#_a|6m9sVQNh78=khhZf1VtUcj* z_nD|9{D#|Y*qWm!V>R$ixnkv)w-oHEw9R*|b$%3rhUKm(-dw1HTn6^A7gm-fmCL*m z@3I~S*PVazgK4FYXLQH|Pv-um{B>N&_=>86Sp^1KF&Q`RWnDM z+Wt2B@b?4T{l1a7)_=OQ1T>aJ`E@RHwXp%{v(ozjUG`in9r2v0npU5}onGA(nE+(p zP!sn;NHpT5Q_t#9V#@}gCu{C1>D8GY|Cls;W^CEF=B!$9XCO{AbjKElKxWC(I)c*( zvoV5opKKlDXsMVsSm&IDYhB8fR<;c|)m;F24OFq`+v+~&8@^j@T=FzI(KIgbV?{>y z(&LW9PIvWEK#!rtr2?-`2#SjEq6{Fuv=*RzDuV%*7L5I!E#SB@NSt8cuxc zW7~pUZ(w=%1#Cs$3*c%K*E#Ik&FHgPu9YC#d>N;_vztBI20V68QEppQUE}3_l&r@!MnI40Kylu5Hay;bbcWtQ*(}5$7my#};pt94N85ntF3qryItsaKV z)SJ(e?G+FO*V zETTy6IJwd}kx*jM-A-q;Qo&MO8M1dmxT8U0W5Bh;0SY~4z`z#x>HH$PT|dj{D4}Pq z2LkyenX>HC?uyLxXCCJPg{wn;bu-7?CAZ{Yd0)9&cm67kSFWj2JRPyadRKu6HZ(9rEM~0L^7Vp(c1x z5>G5@jvFQi2c8U0R(1E3mro3c-olFqcrs-t4559+<2f~Vu?8puH2+fjy||}LEsjH; zobw@oc-kXhbcAJ(=FScI%+Q;RLbNx4nvKO+$GK zh`~=KkyeZ3LoR}Mpo6}im*IoQuAcNc+%W|P8?$v=fF6TduFM2gW-}KFe z*f0v_$w;V}z=c=~^W66)GHqSbYCO|z?EAU#rU^Q_Fq7bb`>-aQp7pM2%D+7@Q>YUE zvq`*u8%_6x=haz(thWx9FtLEQo1q%myXJ0WhbaQ9HgNsrN|$->ulf2a>8nY)t-(<8 zcYth@;WEXnUy2W7X^!SZkQ^Sdda&QS<&EY|QuguX6eE0&`QvVWVkTajxzWU+ z-~l^_(-a1D!eGqfT-=5w0I18eXf{41(E}9yl?o!ts~$(n z=t|G}d_8gc(Bv%w|AFlj5+3~$`ALza9XP${Hp??7ZO7Wlvo1xNt0K&A&Wvnh#U7uP z6?`45i`?^`75?Vzk}I~Xp_Ve{2&xFB z9i)Ma*Cl(l=<)wo)_DgsasU7S?sA!ACqUR2h=>XrHVBeS2vd-tpg0?bii(Pel(q<$ z5T+nOP*KqaMa5BzqZM060;r&fK~d4tHYi#gtwB+#Me;j8{r<-H`}_a?f4}az9)6%I zn>Yuy3d$ZoZ;U04?ud4s=z60k4qm92La9Bzw`W|L;N1u@UKGSaPW@%eN$hCDys*pi zs3zG*DhvS7mbY?(oriJ9)(=iy@dB&TQHH2V9_?E9u6B4^aB=yyjEIVIZcO0Se5Hz5 zI*|@V+caj9rTmOFQZh@~%A@i!1EqvbkD?F$i^%maJftqzyA*+zcmmnj1;6w?fg))wwiDJyjLe*{R9soS%A)6C>bHO zt>YFd>fB=>oYcQ%QK@?GT`6}>&)G-+o$Aj}j+Al$oV5~#;sRMr(%7-mw_Rd%%G);H z4ar|d?P?MicB=`9MD)?YPg4%Y1<&c3%D(g;jPB#KMTsN^f~5S&_Rygf1PPlI_`PN{ zHqBP6oa^B;0L2je@2sf^J((#Y2Hn@EZlA?!?3Y&C#o;{NsLFn+yrTe&^_re?LjhfH z8IS{EKRq?0RHYV$!*|y0L0?Uz&kF;m{x~LKeAA!2mwO@j_N+Yotl1B(jAj2j}(UfJXq?6vSWY$k$M4J8dMT=Bpz|&;;QLH?lIW!764b2pbeunQ(+*6=Zz5$ z4Ao?{=zv0$JbMrTXnvguv~6>@4$7EwGhYiIJ+h-+y~{q(EVQ{f&@RdEBPNPc=UCh* z2^JJ#M}>y-Sz45fm#^)Y>2f{dQX}9ztw$^;P1v&M^Eyjm?jgeXH`a1dtCPA#8tmS4 zAI6uDZ^$__H#$C%p!#b8F$jEBPo9~iR8z*OlIaZqhp1-y3zUQ$9}q^-&LEOeXnp$e zw~E%PErVc;s1lp;LRdMszk|&*qxg=cDoXc+w?R;DpC>y=&j&bqRPBL6svr++ii14L1iNBIZ5#qopz_8OxM(O)qP32Q_hH%2QI5UO6^kdr;pTE)4!=)>-d;+4=3D}a)>IeK~UJz?iQv{@QkT6 z)&Po6(NjGTDL1;U-E~QJ$!tp%P@L{33wxEiovqL{(hM!+pAu{G94k)T&jlcHYcg5X zWdCWPMEDV;DRkjsXT_!7VG4k^WC2)m2qW`_75GF9q8Pt!jlXwOU|lY=8(T8pTc|aa z^Z!gKCC3Gwr4|fXedSu4pD;>~3OZ=N7PyKoF_F_1?fIOcrJ+suAPpi#=2AMDr}Sku zSzdF6?BtVSu1D?j_0`S|$IxfGq@nu8;!XBhbpS8ozx|Wv}D?VB?pAG`f|v1)hG)cR}u4`(i7Yr zKFdQ)S7o~-GP^`DVq$osD3M<}uzR3|Kx+t>OpI0}h;IM|br>z>Acl!3W0`| zCl4Q_csWOJjV;rlxGJ_~Jc_=ZUL0s{f*m=J@5^)6lI2oOO$%}MGqH-d?aM9uTK$o0 zTC3R;ZqSkxe2NOUD>CK|*x~WADkp;2oJxe&_wkBiB@Nlmn~EmtWb zK!vx-@i-=KIQ;j=+11tFin&mPZKU{y1Od09z&P_ho1(xxIWo1Av(wUg@{%RdoTQ!A3;jo@QXjL6qXpDj79o11>% z=`4vjhTBZEjO*z-Ky7Wtw(qFQd-}HbZwRlta;w4*OmwcCKI=*{+ z5vnJ}&58kLUXc;)Zc&tC_|Dp+AMan8L}bb^Htc~_JverGe7UTN5od`y^@YUIX`1DH zXtL{nm!n+pqe=2V<*1~A|B|Cb4a$GzsL=c&7iYK6aun6O1DN~fM(uc%3YVh@F#@~f zQ+sMvcFGrn0?z|zwq@Y&SXB5&?;(4;Pj9WEi0EboBQJB0cGuBwirIo{`*+XvAeGG) z<<3f0moBSag_+5XQ@*g6M8)^O_A9xU+@J631lB*=Z|Cljew4lo&H7NqX16W+ww1Ef z@~K^!Fv(Jt1#)@>uqmqRJL&_!EadO4eqe`)f>vlc>?vcz0uzHVTT|)Xxb?q zA|*ND-Fbrb97F-(gZ+oSmaHke9%7#GMG3@s3?-D>R|2`DM5F%THb#aX;^IvV5Rcg( z-54{EeQiekz$lH{B=%tY{XVhTk?7|~U^pMrTclw1{}ca8(JL}u7JRtPIw*oPo?j@s zr^#)#I+OSJc(hy{FT$0x*GW10GFt^Ah0b^3W+!)|&Oo>^SRC&TO*xdXFqNC3+7JI- zS1x%Hdj44WmE{)1B%*t@BS(8s4Ug!}hZ&bdL)shQe6c=l=qH^O(G ztL2qBl1};rIt~!KanFM)WBj2lp4!hlT%JBoi);5#+P0CEw~s zS(KcH>}8F#IpWtuR+p(a)HsteB;j6suZMZVyY!OLPG4HcE0n(C-_jdHAV?%}`V}>j zF1`hSTj_||{T{OFFJ@|*NExZF?S2H+s*G}tqiGxl_cGA;Kn$2Q$) zw`3hX>6CnD&)Zu-u}#LJxp~xcci`5!7z*7~Zyo6tq?!OAYCPQNNK+2ao1!&IU&LFC z7~8Q}BkpopniImN)iq0>%AHo?iLSC1)lEqm=0mqm3znyU?!QrW+KKRaGMoC^nzeSj zo07K@_Gp6Mj}m^47?xO#Ya|D}%Zf(ucQL;cYRlD5y)_-wBG&`WM!LGn)p>s%1dbiu zyJqkZUD$x$ey?S2nkdGR?qFWSI~P(HMe-pwl3yp! z;nMTF4i#E(^)RxQl_yS91aIOb;?<;sds z|8Uce)=bYpi9e&)r(ILh0|7{oXuPq8c1A^QPUUWLq%=(q(Wc8~U))QaXT9PhD>w-h z{4k($z|e|iZ6IeuuKvglLi{O@GGGgD+3QIhx0A02{yN6YagG7wRCq^SK>$+3YzZYp zeVOwuZnTuTlBRMXm|jFy(GO64=VRG?wJbspZ%#~c{CB7yBIBF&u3Go0aA=Ct}+;2tSk)omCRYiyO z@`9@GqWolv#XBuuV`p|%Pm`|(tL{GZ3>M@s7%ZJVRqUx|xv|%*^V(K>GZJAm2dUwJ z>`0ZzA2_60UXRVl_UXV=ex(9Iv)79?nvN3W^-bSF(@!RF>}kZZ3CNsq#qq5;~ZF zZQ6XngVtC*Avsf;@QI!Bdz_wBx^wN;g*r+j5)kY_Wy$;STXm$}Wi5NUhw-$Pb$-{G ze1d$Y!l1T?ul>aIkRc+ehSYj5kdNxgVHig1nR?Rg?;7YYefr|ic9-oQdO}`ebr#TM z0TlJ4gn(MBQtKpBd&pwU-iX6F8(+J0v|Mw^M{WK}H{nFY$);D@$)@pqz0XMIb`Y@mo-*$da2(K^TSJXsWpAbWyVMjmB#(P))WsEzQ#4;Fc708`9mju!3cTg znq|?akbfqx*S_h&tnszI_2c7`Acd-ymOy#l-f49|(XfveW=sp`bR2)h(Y>g!KM^y$UMBW$Du&4DIgfHlwmu?rzkiGK{hB@d;oht>V zZ7Y}VUN`samMYU91t#F-(xQ69n<2&)69x~4|I>n?@N5q$baC*Tmf?SD8A#!1E%!X_ z;@&AYqhhmtUhlvq#{Yu~C;*&*B;fyB`jHQS9sg;dHAV{!IA6$jZQQ_+3pF~@J$Eqr zjHr`J*l_7?fKU})Cr+PyDK8h1sfy4yC#4^+(^xhse=EH&8Graw&!l=9>dKA|ULgyQJl*%>{q>9J zn739?a-A2F(%Q55O-3hFO3&K&ac6MT8;KR0D^gsWw`a;X#gOtxBho>j?wGo}84X|D z>T};G9y9ORb#${ukTQOLy>{AKcaN&1?>I9L;pi^ajMYNG>zjel=P!Q%B7WLxNgHzG z>p|jU2cf`nI)K4!D_WDe^3DBq+Vg&FpUfAZLaIF$*c#IDxIF#mf;|my6Wl)-cT|Nf zg>i`j_G8NkP5>GkGA`m6vPH}F3#InElJ5Eqh}E|w#f{g?ew0tx!@RS^Li)3Evf3n{`En9V9)}IeBe)hzn?dTf3pA}a3 zYLvj%XfP1s+2G;lV^V(=G450G>YAO4#ZnTl;3$U(PK4K>K-Oty*l8G*5-iacBM7yP z-<`+cB>ki)`#w9p40g!;T1s{rNqHr?;^%hHOQ7`VJ8fy;%E&gE+?y<0zvL_u$5A-f z)i(CrAB4{$nK!IC-n7bAkqyQ|m)_O{m<8Sdacf#925~)g07NPHdg^&vkhpgHxN`@? z7W$4D;~`RrrGk?hA=~EBpqe~GSgQeP%_3PA*-kr{-rXBk|HldDMV}g!F!5x2NRtR9 zBpO5}Tra^Z@jk6K=K=RW&Bc*`K(50M>~p?&6prsQ-ww2B`Z_NrS>2(`dtAt0mk z;NZ`%ZA4}u__g+lVkK4ld($c#y0Li92hm&f8E-TSBXB(wdrO(72NJ$G?03BVeKJ4F z!_%m}{%T&h=q5mt8MkewKQ0`vqufyJ@}eXe7>Kyo9#QDyQ?b=HI_w`hMdgx}KAWl^ zyo=??diHzKa8nAmwW>XW(7g6H`%5jN052-#bg?9wJm+gphj1Q1Y`Wn>jc0?D*$Axz zxF%fN*YSGI%yPm$j6c~_rOl0wnsO8E78zabyBGu>a&@mK+f$R5Dlr7knO!y#4Ovk13f>R^CT0=1pp&lnxd?ym`C|FNhLm*Cy<9v@x|O?|7H1+uiq?v?>}m_>Ml|xX&?x z;Ufyhd&fxswT8q(`*5nh;VSuAr!`H7v6qe*M1`$HsSZObUzT||_SHm-F@y|f1Pq#M zI2!=SGpLh-KTJMBO*BLhZqHa1o)!9)T_VwrVqyEMY4^<6XTC2} zsUvg%iVxW<48Y_xVCR>QW8n`k{MG$WTsCK3cPtFj>eP?zHfxhfJvh##f0NCIHe;7Q zC3%lPQQ{}5)I8n6z|k~>KUJMJ8&(?ft=g@r9_&s#zzs&vP5^dJW+re zHWy?Kzc@F|p8%CENFFE+*ab(py>C`kxkUp|%y_4*&r0@WTdGZAkck}Rz0Ij$)>3v{ zHQVYAMk-(HcFk2k_2W=Yf&hVW6V&r{N=ka~LHi4U8fe7v6N<+<`!=I+o93t*Raz}I zCq`C1#b!o_+kcUXI^RoxAO)q<3lE8}~3Fv((eb3pxBWcKGBwz0J z(YtJkX|wImLGLA@0Aw(nMYftcDaxx}4rVDwAwUVaI!f3{<(dJ%Vcxl8oRlf;gtaX) zYb>$SqbH4r>q3$VU8QfFzPro+sQrxgRZb!u=w>2F7v_%)u78wHO96;@ZgK%`+piud z@ji|KHe+AfAOmY}K#2pCa{Yq>%Qy<;;*l||2@*qb9s9YL8Gd@Y9*wYGg`*zv39I^) z5|=Qn*p>s6*N+tIi)p2SbWrK4_=$b_$>nZ@4*81>ForI9^tBRp87UUARf?;4Zy?sa z9oS{t{r&mxA?SjX{_78`?`6%KH+YaQBYUu8%wVOTH^6)3xZ%e|FgRV4;q{VvfO(A5 zv~z8xE#JEo-{~KO3-pKGKJE|S z{oB}z3O(6|Ly5>&e%749Jk!e=h)LJ>d$b}io9OUL$B<`A9Tu{Sg$1VZ?%mzVR;~X8 znx$j{6_pW_8n*7qMQU&YgOgIsZmYXI@hA$f;+a*vi6^kM_)3B}`ySw@gC0)>&mS#1 zp_-Nb!Rdtz`{#Pm@Rz9$|ILrn;Ad4dfc_6@$+^cUH4*6y>(73is{y8xWL=r~vT~)9 zyUF0DCE0{>B*&LcV~4BV&A*kXA5>X~MpEXV84RwKm5TGbE)~PG1kE}5&Kag|Jf{Zx z{!n7zLN%OqqmwH;jpx=Gm@HZCx=2^B1Qylr{O1FD^uc-P2fIDl!f^Nt!q)abV~1qr zMQeMEqY72>y(D?37|GI7B)Hzv88^zf06$!!pm&rPIIucmqJr zZTMDCx-n&*#pB7g+F2|8!p{CUsFImixQi!rky+bLn7MPWpIs$XYv?Z*yMs{hVle_9 z`qWW_GEJ-TC{k-X)03mYq$FU;F1%))`KAUIXpk;vcMAWOMB@2ODYZ#a%8S@az)-X$ z5yjBQIvqCc&sV%|NvC#x4MM}7=~B5Gvj&zl4}fs@r$bEd*)%TGckj8kH8b9I4Po?uayT+-#R#6$}_qcPfcaeuJCM!;)5q~PHJ?_Hdf30^{Q zHo|WA`+Fi?ZioDvwAVJtZFBXQ$GeF`5WIPxC06T1jWhET@gg6K0n#;foB@1&3F3=> z%JeCi+Nk{%y0=+Q*g6$X75qM-j=J?P-C|H(Mw}M2UOH>d-5qhQJpD&F-x@FTx$a!> z=U32=7k%qdks^B+N^NOSp0$kJwelLvcU@1Qm`>fv-8E|rb9y~-#(xGfS-kcb;oUCX z9EW1>?_u`eke#cM?`1m%P=$hP$?u7$aXzt5z}M&%P_4emL)}s|d@~KvHsDJNCqBxtEP!ahy7eU2XnO-HWUi%&D9qBN)F zfSc1xk}8VgO)XS(%#5wo_~Jf6VT+pfe3fSiO$*yO; z#zSs+lqWUlvCGdmWpV_O2DU%~H};SfqurjSK?N_^rR4lN5Y`@a7y{a@w>}Qh+?xV< zz!CmyQ%TB3eDWG0h!stwWWR`T7D5b56Sn;%L^ywXTw}esuVUo(26BM*nWc%AlI5?| z6g{A^&lw`gThx?QBea8Gw=xSg;Y3R}K&VWt`5MpmaLX~UYszt^z{JMyQn!H9kxC$) zZt*B_!D*Uc;|XsT(mbtxejxet0A-NcV}}+_?8i1AxERNnuq#=Dr=rdRo&3pE(rjE9 zY8NelLzOb`hqtUJ1!cmIqcyk=X{&ZyxLj<+7S7YdbU;3H6^CdQs@sWfy;-`e-5EBu zySxkPlr#@fiu%)55QQ%#t27|B&H6uk3Ie0^PD9Bldo@OtZz{9LuLArK`qOkC47a-m z*PArFUK4Dkp%zvxP9QiL@x!(QT;FITFT1_o4|YdI?4>?LjNxx1CElunM4l2U3j`Oplblc6V?c% zDh89300`8MQcTz}ukU6QIWrI&p%#y|vMLevpu16RgGf2+$AR?$t*UneXX{p|hR!u! ztejDmYP|wgi*#m;!XI)`jYm1z^g*z~T!9dfgckx8rzOq05-D!ovYc$?i6L8Xz!GF! zn=#{`##HEG`!zlFbNVY9CqQPKv3MFx&wjSp$trRqIZ+2P0MLcBBQ$`gL5t)miVyhx z(AbSwn`5%A2J1;lx|LR|gT4@LsAWuRp2ayjKF{aWC}+jRCp-(DkovzGOF7^G$bj(w zaSYgW8o}cKXe^FF|7t9euf$C;9`^jn;Qr_x!_k?46;5F(D?dDA_j59<8${ARj(1*ruQ+geO0Ydw zz-?aneVm&9h3`CFQ?=s>)Tz^mQUZd!-Zx&GFNFwB^?$yWW>4%7xX9Tm|Ml(hwxj1I3BpfR6=J!Vw?)O z*s}m~GS18&YG1a}P!(-G&=g)u7sjpm{n}o8gZAcEftKBv3DEpzVIys9kY&x>ad6;7%5YbCf3)MhCP4P#GG}6l8fIJ6PqHxO)k zs6&l>zc00gTsBJCO`e}llUOKcw@cwH?Ex8216F(C!`t99|E_dtIws(!PtcTCBAA8=;^LULGA43my-Hn3?W7Y{2IL-(_ zChOe0&M!^rH~hCvx>0sC2rv~icg5ca(VeDI#^K*lZe@V@Q%7|0`Ni#&ppz4|v8>N~ zjOXC1(LDjn#bW?o7zKpINCc)FUzqCO&vM>#pVaMh*9ME_?QAVM?Yk+nJ>@O_S)o*!jyFlfMEq& zYJqMAHZ}9B(2dnwLD&XWaA1}Qk#6Rrzo3K^7Y#nruh3y|!sQBMTq^8F5S`329xY6n zRK>fm$tPTw^iKF1j$Mh*_?3A6(CU2Y;#6f{R^c0)sR8dB>bmC;IFI!!3<>8#q_=q) z+ZOd#ELuR=(-3|W`C}seMsULTd(lS0V!Qr<2bZR)h^#~{NSo7qsAk%wS7*u4g}t*l zU+=Gr2miQbSMi7E1I(ql*!f)f)i8<*DAOsSqw8Ye*}GMgd;sQT9+0=Xsk|~FBH_lp z*QbL7{(|`(z10l7%9du7BcRL`gBu67u%RmG}gy8Of2elq8VYq5r zD?HP=6Xis2oXorBoLd1q=vRRJMncU;wAMWs@y;78UJ#Dh=nh4es~qFa1YU!lEUXl= zmpo?)ZR4zn(=aex4RG+cl_uK5`FGs8UG$T&I$PJ|&<7ae!}e$eKHsl)^B_)d)KlkG zDb-J3+JOTUAg=$A^X~F%sC(C3bsOk(4=4c(AA&@j&|@)oxaX)~Vn4?H|zqlre&m zti$?B$W_&N1ulj(A-0;Tm2NK|>9CK=+kdPf4(C{u*}r&r<+o*eQ0WO+;gOShjRpax zlh5o`_8N2bU@1OByjFaCgwaWmD^)4C(bC1ZJaar#O1ko90X;}Z5)|xEl&GDRK~n3p zN+}~!Us1G7N<1-9mIL2`Y8g32lJBMh-~R-VM_7#(!BGaRhhk2q@wWfmn?bzOa#t?t_VFR(3G6=x4S{~DRXncBw0(QWZbWbF@x3LbhW;a1+UoM#IGsBC@ z2Pgz@6-aRfLalXSqGCso4M-oPeF zs@eD~k$*lwbQXgz@NN6>{9-0W0lqK!JA#WpxuVnM>3Ilr!l{c5-TJ)p)4O>)#yEv) z$oP*##Q1eumVzyyH^H^Re%;8Wi@z|NAqbz<$t-yu{>!lYS!py;xqMx6dh>(JySUOE z50L$VI$&5qIZ4cUl@T@UvEcrHd!Ebi=UM*$J2 zo$VROu;#@4jdiPr5#n9ngwB79gaV|;!eHMIb(H(OinrW*Skus z-7w6Job0yx;eHno`RcJDMxQM^^UZIb=PoyZkWJ1l0W~ASUQL`^6X0baL0@@ zj#Cnxn~QF2xN7-_AS}LSH8Lv~MbY%UZQpOKZhyntHYG*0>tjZjLdHsMpD;T|jNn{B zf?^H;LIeJoUcy{~0m7HB+!O@Dbj=EqW9(Rs{OaM_9$sCiS`AASZgKXO%sYxw%Hb#w zqFjuSQhs^$q-xsu1VJxxp!72(OG7jJmah2fFjsD?5l7o|bsv&uy~yNl3$t{cE(^~& z>Bfd_=a_H9$}n+5)bmtSFZwv>7V(vBwAR29jA1fYf*sqy^U!zmhyuSpkP*9h%aI6n zJSJlu7}?y*W8lSK5@Y1BUNUj=EzEZJKvm7Wm133G+W~H6NFEx_q<%a5-7aaMyX8=g zdv+H1M=4`Vwu-zibW==7U*q@-ITwA>>wUCTwt$yrlc6Fi?dw%V_)1_8ka%R#;90iD zh~dKjU6#bZK1z|$!IdX@ShU4u0fvbMOy~4T0yEcCpSnSMm4V}&xmoPm1b)B1$0ted z7E5M-wof?CR>{!w$tS&EUg3{9Nk>!aV!|$)-IJxP+0htG@f4@bv1ru^bEYeg08lKg zA0+x+Op97XdKmGGWNb3MLfV><*6VVo=}TimPUk_$T^%Y_*!H#EX-Xi*XX|I+Io?Pq z+lVqle{6+VZjm;c>fqvnV<+ywc*ekH+#F8x{*%scZ}5n-WVcBDl6+W!y3a(3d_NpS zWo|ua?Hnm+szNVMyuI#s`f9W#P`E!g=>D4YMVj|%x`JuNS_LM@m(ZHz~2vf(otRO#6JV!$q zyR(V~D~(^tn3I2U{QMNU6GTxf_r`A)rB<52NP*s*og=D?vp*-$WIL-b7V9#mrba&^ z(luTLE}tUlG(*f8)2G_x>j?Hsu(pii9%Q57l$gN{JN|kv~7XC1z&7GzX|1}qbhU=r% z9#Y`_()kWkez44yTOXyZ#!LDh^L>v{P7}B|UJ2%&)!?sWfH=}0-6R!&+&T55fR9ng zVAK1ju^Uh>?&+hUdcx4T7Syq|bhSywe5j9*1pr`RkD9r;N7&4f2N*$3 z^ypmB=JONhT~bu9WR zcKI&73*oD`hO*o5Qvs%K>ayP#AQVjR_tl<-U%0gjY56+lj+SDs&88Aqx9Nf%-d0W; z!ih%1ge?j=)7AVVzT84}!DL7S>h0WD!rO`tSv4L`6 zN+&%F0Yme{T?7{mnrwI zaTouyQV+T+vR#-M5M-;njYCupR|aMJ`%vfDUyxZT@$>UsDsgt3b_H$88i=+DB2e^{ zi9xd9ViR*31^tx2@Wr+pnYiNzxJ-hiMa4oQLAd3+_0=F;ZgQDoRxxA6D__w=cFjMo gFK%9s(F(>M8cQAKO;@hZS|r~FCAvgF5D@ae06k7hcmMzZ diff --git a/docs/assets/light/effects/GameOfLifeEffect.png b/docs/assets/light/effects/GameOfLifeEffect.png deleted file mode 100644 index 1fae96ad7d219aa823f506297996938ed29e1fb9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14104 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 Qc?C>TR8FK?=%@ex0ATLMdjJ3c diff --git a/docs/assets/light/effects/GlowParticlesEffect.gif b/docs/assets/light/effects/GlowParticlesEffect.gif deleted file mode 100644 index 704e78422a94c6b5f8d8ad32b24327e98ffa8a91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 219063 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

J&e>LNPdFgdKOjjf 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%0DC^VBxy8NqCw$W? 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

iu85zV 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

c1R`-`1tj2{0OB(hnW>bLqUs|Ex^`*KPveFMj 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 J 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ªG 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

g?dwwO{RS{KyeYv(UDv8F#J({p0KKbD3w= zxya7j%E;4yFFE7RweW2}z&`b7_-*qfN0OJ_vMV}0>s#LEKlV-Idi^=?`A&6K+hT0^ z0yaY2%PG3FWz1_T*GgH5&`#eiTt3Ms{eo~=-xMKwFz}XZ^B%)Zn-l)6E2nHQwD{Z# ze!1I!ct}Q`er9CQx`ZYuq9W5#&Pj~DYsdvRPBOC&`xX1+V z1`H+@?d*)Q)TQai_mjBN>N`8bs+0Syf~#}L7-jc*p+oL016(Ty047u26lM(ls`y4ZqE~wnxLriQsy`Io~CRm}@@k50LVLGYR(m z?QY1P(AqDD>H{MdzP4Vf7OYLqvMb%~d9qgbW(>ypJFovG>($t2y^0@?7{?vsp zwz;1WnQ*M>5jFmkOfZzQbb z%e9@hi(kuXGHympD%xBB(lW`_YFN&J!fhgA_fIGR;H`|ttV zg~Z}VJm?fR$_dCrj*5Hf8jZsHkq*rq#o5VuDyLGMdVzPI)e5ePv$zM1=Ho5No4HZ8 z$}UuZ;_ak-xv$fU3@zhp%6rYs!JzkotBTK<3 zn6Gs36%hGv1&rO}*Ji1Wb>h#GT>z4rJXH{%4UVpwESyM>UK2X2B7&vnD<*@3u%x#V zX2EzGYr<5u5E`-Fuj!lZHO5RgwAm!G)sBf>RWYS_*6HfVS+`BKk;kl|%!2DPoRVqj zynI?fkIMg{_@Ec$bne2LS5oK41a+*ur9%Kcv~!{GjCB&nP&sdm zmTvo;Dnps(m3~!%3J)6q2l?mVXp_dYRv*og(-v7V3g(?+q_dT?3j);q`W~BGu|h;x z#6|(Dbb@bSUC|SBx+RRHiasZU$0D(-J55m`XK8zh2Tt`{Nw|2Xwf`-@ag15cHaO?# z6?R4etE#0I-2eYH$99CgM%rhYMj27Kz3gQ*n3dF@jEdALYk>$F<|LLWrX9nvF1Nn5 zFD)ZxgDHhYv%n|7kD6TJzA(MJ$LE-l7K1)_I1OBc_w|Yp+SYUOQMHe+tj3P*7TGs! z@GPN{i-!NE1jZU190hfm^H@$zoqf*7q^dx6pYpWUz`JE`ax!Z#>Dh>nP)5nZ{zvY1 zgx4*trpI{yr4{aevWo*?CI~;ttFtF_Cb2$xzq~r>Vy}&J8Cg&v&ui*7IF{%Yo&oYg zuTxR#65}&lql{8yM5bJdBM0jx46DfAa7VxD)MMT>Nw#U1q6ILQi$bDE~%_4za5)s^gu$iAr^=u@YkX zMY4=hKG3}VIA>`pt$h;Ugr?0ZKM`_CLf_0IdO8nPi=Xn*MSOYsa=(!zj^IYsmPi-% zNOe|%?E1uke%IF=Kc=C@>u|$kYkO~5)dZ1DQ}=J}?l;>+iB zC+S%%=b(=go7J4Fw=}G-Y4iTDu3O}5w|LS>6^# zF?X4M()=hSW){n>_f#mnQvA^=`}1t}bI(uvKJt9z*of7B?5RgNt}6BcAJt7!O@)>t z7T0-g){3Axg!NBa!<@3&>&^XMw?s8(Guy1rWwg)aHcRNgb2hu)7dlm^VX?vpcB8J} zdAeKIRNr>HIu6k@?fXz56luTP2ov^%&QhF|*ze}LaH?@tJM90pZW@?&rdedp*0xVN zTO2t95>ON7Ngn0$)E=j-YEtgXDbxQDc#fKzqF%N+?j9D_p2)6=8cQn+`oRoBVr*B< zf=;)7IVN{v%W6|5awlOG2G=7r>Krt}dVAG{Ki@zkE+xSeDrUXGbU+G(769wd0XWx#nFVENM^v%A4gBCfX^h7rx0sYsm8Fe<+GD2 zR0TlL%fY#~ZExYhguAMkYR}+KRSO@E)WCeUiuO|9Is*yk!^s+DaR?G4g~5ip5I{pg zFqpJvRS5FqT=_=WKSx3@a8Gk>v3nkxsdK8{v99lEOy( zyY-@KMV9f%g@3CkD19-inrX%bm=8vG2Z>EI3kR@5W<`ML1lT0V)hU;BA6{a@r$}LL z5a9y_Sv-!PB!U4G6_Rn>f51P|r1GnX6tH39ayW!1oX-}9nN*S8%KA3Nx(%H`LcFjO zi47veO~B~`a6m<5NQ)|oi*xhB4&pEdpTy@x_SY&X*^0Vs!aGsFn+XZ;R?_AYf~zSa znsNyjiRDCbV^x`Eg~*JXWF~w9T#h+17WFF-MNMWYGewc@C2*Qf_{$AptqebXIA}Jz zdS-@-JeP1k4guIzK+9E1_O?ZNHB6~G+Q^CI!-4_bG)~Z!zxcMauDYW##~?)-3odBs zp(vD90=&C5Vi79MLn;0Y?0P0}j%b|J}T#eAtU%*Z>Mt&j*|p+-rG-;sOgYI+3% zaIQ!U&Z@xu?-Vj@Nm8^Ny!SlB@2 zZJBL`Z0~yH0d-(OhQcXhz!t*?CaBU;RgP4-Kqo)&5;vt=`GGoMeGy(7kMqC*Tn3nO zkk|^iuld)#7nEz=k)n1ve)x#{d{y*teDt_Nz<1;F<$@qZScNh<2%dwfe0BI4ou^`2 zbk@%~Q}_W~ts*{FB@wFT@Kw{Z30%zrt_~lBDFi{v^y2u~&RI8{;e=7SWloFg@+M{U zz&xRXz&LgJug7yAow+F(CnTHt!iE*zyMOi^0OueVPRlR(cf(n%fGjN`gB1v{AiFh6 z+YThV6HXo01!BtR?y#W(c!V`Gigx{?Ur?%u{P$es)$ReEzv|o_Br8ZYK2g<}791Vh zmHz=wik+WK^|N=5dS6_V3=vW~ZvXJpI-V9ku68Lk*%PO&n^e3lhTm_9mi=Ic<5QJMD$P*q)XFaqVn*<1jb zZHf=lA6w(0qCn7243cnFk|5Q{)|N^7Q<9AKtRN)$D9|gQbE8@AtsB8ntD>p(++TMT zDH+PN3RwPOAU6R?Q>b>m$Ka!I+#NV{Sotag2Oq_a-&Ljz5T+>=GX{2jfYl3(N(n#k zoT6pf>C+3iDhk$L2|*~zSs;ZQFX1BRUW&Y@2pd)Sj>_#aWKLo@C}>WoMinoUFWmeq zZ5BZD zFezUd+>N8@cHth?xV#VXOa8p)`k#{DHl( z8N?+33F4g21<;S42)sk3Y@%gB?&PYcDu5I%(W`3#XEZPzg%W3eQdP2tlk`YFo0w}> zEy^G+*s&u?N{n?^AMeOmGOWs#s;dHtxu`m2K)vqXY_vsY1rDM`GHa2H$;Ise`k{(P zhoL|r8T>F-j;&N|C^{xyd=Dp!*dI)q-QZu~w>HWPw zKX9@Bzy&ts**rK1Qtr;Z|E;QYPj2aq#mc;=8KsV|a>=E2yGHDu{jvG@pJx{*WDfpy z@7dq47VkjO|JPAe1pWUIk} z(N~LDPs+Kz^`$(lX{Slr-fLh4HkDgFes!IunL1ZK{SAR^e>!K+nYTfwK<3Cx9ev&L zbJ8yBgM4fv`}QB(Ph{N;kd&q1tLj}+?~0Cmn*QJzuSnqmw(oIA%tlUERo^A z%LwcKd3I%uWY@s@^23iq3%{7xKPD8CIsStKPe1(e+a8bL!U@B581%I&zx|N>?D-VN z>5{h-pFW(Mzi4;BmMOB+4}RNsA^j3+0sGv%H)${sdsPW_rVojGe$LzYb^qAdt6!(A>8~A;-|nm5?&H0w>$lKv zo2;+e#@(%Q34La}=Bjlz)Ptwq)hZJG^nJ3y&+8HTaWK51 zP<0e4O54Q zI}+Flhr50aQci*7^qh}FgW{hI`kt$AbuWIkN@a~1?DC{}b=Gr>1vP=K31F&@KU}Wk z&v~LJ*nBGPxNcR_I*UQE5sQS(v)enEq361_vMcYfJ8@3p0QYEbZh-rM)hRLIZTOmG z3qEmf!aOZzzfm076t-X4+(%Iw@|t|tiQP!PT0^gbA@59XSk`h0nGmB( zKYF+}X<=5c8*_bq1brh{9d1mn_JiG>KXsBg-*Gjo?nb(Xu_L*|ZN$lqjl%C0M5l=g z#wu(CjyDoRe)5ASJL6p*YZWvpRKH%SpeGK?H%cY5A}hLV1TDSIwX$i>K^~KTVMnm0 z^f1=73W!+)Q9++a0Ak{noK+sd?R8_UWZ_8ih-;iyvug4F`N$@Rz5KAAhVKj9Q4{xS zvy@l2syfoD5GD9dRh`Iut8mOQ^?FKW)DTRDp6Dh84rnb(|Lr4_-NZX*4PGZY)7shi z9+^j>pfM*%M#Z;9GIw&&m6sx|Y;z9@FHB(+eB4iB4!sTs@LrNm0g6%)>q=kHf-vD1b(b&Me?>s(sKY6B!=WR^YG61Mvt-# z;G{{3ZE9TD=VxGH&>1~$YH$YbwG^4DmpEN5?sKV@(PLkNzlqmmtxj&VQ$a*!i^8^A zaM|Od%;tQHg1(hoKerR-^xCv%s(y&Z@7zURJ}UeDR5K}9>h5?@*W);z+%T7ma~kW$ zqa`}}52F(K$8jO^CysiBki$z|j(J^eYYc}XoXn`&wM5diqC#e6;jMPPC}2usdu;!% zz8d~jM6VdYTWI%-ula3Q%B*-IpnhZxSPdLwu0Ge{f^qu7M~5ihMt9d2=3b}gV@*-Q zcBk(qwY@Qi$r~LhJ;mvpb6ZmDpTmd3>l2a0He}Pw4x0r*i~SFps<&wKskPnLg5}zp z7p+CEUrhb1QzK1W3S9q@MzH{f zlrq7dd=$b5{wZTPR}VVpR1<}v4pVw zbmFR@4pJE_X698rvZgqamq-m+|`Ulz|nGa{Qay z#nE?cB=sDFo5K>8Y+9>;)2B)_pFuFxwf{kHIQOzj)d&X&QIu|;^i)FA#oFtDUu+9Wv+CnYUF+%y6ZmKmpZZ$5Ki>FgiT$oBb5arkHqpBEb18{?Yogwz+-fo@H1J=eGu`r zm?4HpZ^W>#6k$M10XRX>6Tn`59t${-u!~xt6QM^QWbDwZUTaC`SWM9D(6Z?9z{8AW zCTM49ji^M=y!Sdf+rS(KW9e&P!mq&tf&^%RCbUG1#mr+7fF-)c`EfQ_QM-7 z5^fd(*@oE|2r@^$W}!et|EeQAi6ySrGOy?eFQhb~p8SS`?9nrUqYHU!ru*^HH!Q*- zGjpAk^ifX-TZz+5v~NaY9iMqcy8W6I-=)FfjZ-V#AQqOgQN-*Nquj$_$hGPTN*HQ*wyFE)weR`ktT}B~SwMa1|ij}`+l z{=tZs`3!-P_Sw8V+XNsgqQJ!1Wx*Uxrq&ZYxcd;PDx&-b3mGv}f#YS_1v;qij2o$u zqRA;@w-gcW6CZwQB6xG?|A^xsv$8*$kzYhn9VX^2d%(pIzj4q`7U~TwFJ{VWsBQHH z%Gej`0)Ff?6XTW<{#V>~7orPI44`tkC1Sd>_C=a$7g_E@IB2?&c~XS_qo-yYnc9fh zLX6qYgJ1H=ih!x#q~shkqYNmkq-2RXb)%8FO+)@yPug$NTC?#RS=t-SDmHL!l>_f$Vm=kfu8=mcHYXZta#wSFq7xbp)?tp zZs7m_GYt&?Y2USoMMwAOX9i)+aXm7snSMz1LpO^!E=GYyNF+K;=&Aj{B0VxP3pJB1 zCi<`r`Cz7lYSvXL;Es|kX3DuQlo_`PB7L!e&s@d>HY1|N2$9whlt$!l6HzW^ZWgzO z^3fM!!hMWUC}s@n;44DpZwy|gVbp0C#%m@!vZ&X<(Gf)3P9|H&Athh)M_I7n7iO29 zoN8hk#DJzE79YedH8JAFjJE)&lF}-T3=llE@b+wmXrGM8H5N6skB}!K0aeB>Ep>4x zy;YAJk|HZvOpO==mJgso%9B!GmC*LIKAfAxcfv_cm3 zXFO#&pStZ&*Ay0A3HTy2Ss|nxW--AqU#rD^%sjGPM+V zN*_kwET*5=LR>R+P)DC_v*fXk=mk-HF*5nDLd8coPy_p#Xt#8wlZu(s%gctv^u@gM zue#xjYvH+v3G>B)T|hwwM&`Qx^B@XGMEryid=C>p>(L|(PvH>l`R9B_ASIZ}bBJ!- zh+z>`!DCP~P=cB8NJrjaq;D`YL7_~kC#(eAg_OSmke+(AFQ57d4A(`}5-n{tm{Uu0 zbyC7FpYYc#ykbBUzG4xVbBMltRAEA2vB;;i^myr|djF~SG^F!?5w%)~sfUlx)xd7R z9s-{i1x~i1t<#}^i}=ZW>6VVfxI=uXS=J(g@ufrqkCLgO3;jsGQfi2fbd`lXG*JQb zQ=%aq*O2-&%B6Z-jWpnG`^j{_YgC5v!aM+Rg2^;+^iDLxv)r-`XCJX-MeG%$1Q?G&BTAid_9=`2Dz z24k$=m`(85d9;^zHI4%&X1Ep;F^fmb&@L^&s2nq#r0I*Zu*mDR@Xz|j=y7rr=n8^% zfEi5@!_E*gO{}gg!)f)v7zP8c%Wi4zTu_$bLu5X<&XXRj-TjmP2986F);sJLBh@{K2rzpw>Pl+&AI09|-+onTda)ob}sZf1&_%w&7Wh+i1*Pviro$OLPp{ zb=aB+lx6)G`J9n?@F?{rMlFQeo7Gs^zf&IcM$onc4FLd z+RpQIiHU9)1ePR#{UzZhx%6`=C(SgqmcCy{Es_$ayrLDFD1$okYaM(`H{8!6K46hf zo2a{>U+Qk}snXN4_4JD-w4amV2KXv7dP7Ve1W<&Dw&*h4Eu~;)+D?eB=BKorhk-w5 zmlQx}jFuSEZzSSpKJhMxEEhfOwk`&w>tzvopS0jh5mBzEg=x{P8Z-@L(bv19;Peb2 zZ9qyFWaez-pbIcsDTZR$57VT?X&{Yeyi*KZfhMw?MZ6qCO65^D0o2z7A2tI3bITbq z+71C1A-LfoO*4~&Ai&xnzvzjl`7r6-)Eipr78V8Ia~as>B5l;~EcmV&sRe;BEiFj; z=$wfRe2UAky^mPjjXXrJAr2VH+aPp%NJ^-Vng+l`9z1fDUL~dEwx&E~p+A~PTa2_b z4TPULq-s9B81Qwb;c{)%{`Zt60IuVZZ|Lk7WwIaPi0`Mn^fwXBH7S(LPA&l-=b2X{p0g+#f+iKyMH5$h{nDqm*)N z1<|OHHk&CO`g^POj6&=`!_H0(y+cdR44bFN&J&sZR3tQ6A@=}0#@q^Dx?00bW^qE(%`19#ybanM6j z%62|2*+}u6hn!nLUCkd%=FlR4q7+C?8jbB03_yx51)|@c975Ky5CYD9vxc;ecWE^+ zR|4|!MhASHg`5>pS4%1J5N*Rj(t7ijCO)-5dowVLy3R{^V3t6CUPK;(MrN)fR|N*v}BFTL2ZIF?pAgL(#} zBt=9wj6pj3d4-NzAR;bpBCi%R@@MbeV7|7Lj~v#&D|kx<9wWf=x&g|R>N1-{oCgs| zo5`=Vq`ED%9XuQvBJ9whuT4}yL0P0%yv$8NT=&#SxvHhMNRfRrVc-evIGO5sh`GT? zGhpQN8i;I$hIr_^bjB%DR|4vI zPfwV^1CN?yOiL~?k}hgyI%=R`h@OfK?J+B$Aw?B6HP`ie^I6pB=@OV@9+1=zP7OVK z_ig6wA}ddyT^BjYy5}{Fl#+n80jYnqHB=T9pB+1JFu8fooRt%gBg?k!PRm`);`P4& zUDPgQ(xBuQ_nnq+)O{KwcDB^bh-y4uHnnPaYQDx=Fp_-uwqMLMXDjN5zbDrNZBT_r zej@c}UVm@P(*w~zaxzv;KhXK&I@>QUx9ReQ9r#ps(dKI0?a!|>to%Zy*Co?Pdwh#J zSK5tO;qD{)(O4EK}l8o4@TO=anZd`sCiv%m+UvE$4mfntkJ8N2Nsi?ZwO2 zEw(G`hCg-voSoV7_#Q(LnYV&|$p1#7gUv_U@Y`8H8#n9q_4|Rv%f+5?<*z5Nl-2C=p;z04>aWV3yu)R$?2@(vc&GAGv(hct3)nCwQ$=()gC(cd zk-s!Q_`gxcrdb~9n=A2erf8&(ilZBoKJ%ij({Ho!4e5nr1-m@YSiRiiqh>$f8+4|* zqdT`mFjeEXC0WVlO?mdJKDW2!l_p2XHL%iM{R){eu5H5RCHO-1)*b7bBliSp9P+Du zuw>27w9@968ud5nQd`elQ7WK@}+)^Vpe>I)QnZLA0BA>qAT;X6_-9- z+9H27yU@C1a6Ed~%?ZzjaEE$whn1J_C(ot@U!^a%@|?*p_NC`sP}qi+;|SKlz7B?l z9PjnI@YsRaDHZ8c=2u$>CgK#+Xrcl^)hU*rCUWR@UG;|~S*4UkTc5rD!4 zr)Uf-f1|LCe9n)mjX$Vc`WucioP@cb;33RoxSDu0->Off2xJjj;`j>oSv1;fcNsZ? zyOg2hLFDz?&* zD^tw_exNy0fy*Tx8a(b!S;xK_{*!L2Kq;|ZF+hlkJB4}!agBZIAwERR0ueI&ik@(Ybs(?1t?=To&}VjY?Rb!4 zPD2GeXSv%2f4$nTDX4#{+OIxl;4hnUw$d-9dEo&^1w#^R*f$E*WNH7lx)IBDxg|PU zIOXi5_&YZpw3^z={q5TV6he>NkKE3!PG#JvUO@U@cB4J#`DB+h&n%POnveO5-0U`D zOMJL)!GyhTx~7&RQ>Vm`R?+*dGIzZ3oW951!>7(Vb+f_K+L6dr3J&K9H4cZ3gpju* zRvXwv&uYb@=>vaE-hBY}Ou>=c%_jp6ZBV)IZ$qQd7lEWlec`koS^&+>sX-UzJ}Nz! zG>E4kEtXGNELpVb>jtWY2}?nfa)2PH~)yXY8Tf zHAU6aC3Rm9_7Mb-^Y*VLJ_tn*pbs{BL{(Z zh-umzB*fy2H;R`}r^)Ig^tIMoelVQh;$5At%tKWgCD(VPC}hey+oKs#z7YcO zRMcCzkD~~fm0Z0rwyiAwai1&0jUw`hu_`b~vzHrvZ1X|2+uhsP(27mL}`g0+@R{J!4n>+;#q5`~wB6|{Ua%W9qJucyC zSXB4sp_&4No4wqu^u0zwi$AopPVlp2MBP5i-3ud*)u_s|psi{z|G8Cz7@odbg3jNb zXNy%RJsfdWf(e|}g=+XiKyz)(#202gzryRIHfq(cGVA@ENH3ZUP4AXj?dtx~nR}`_ z$1vhp$y&nREvSvE&)Z@wgq=&1S1-^AtfONLZX!Q4CQaNKwM_5xnpYKfOky8es(P75 zt&8JD9D5Q!FhClyKQX6cQeCys>-)f`uAJvKr>g%Im5iW~e+q0$q-vjpWO5Q;Zo65( z(Mva0)AI|c_KlNFt$@|g*<*8`PikFz zl77)Fw0~_@1{(p=RUG97KqbMZE+nE`IDL{EbwP0iL!QxRvrr>yV#TKMB}x zj4qaVWCp4y>9M%cGs`=a@!d)!4YTL}l3E-NmntVoy=Yo_=BPq44AXN$m`dfePMMW= zk0sjZ9o~*4vG7c(fXmTdc2haL#4%a?R-@`A<;pa1Bm<3TAB7S+k3?ggV{4TD#ma(U z`xw{<7?#pHkKKAcYs&^WtL4~{cDcZ;Op8V6Q#dzfS;z4A#8<#vuJ3eRWUNuYHPt7f zLYJyV(k=m+4k5i_=4Lq@TYMoV)@2p$=$DA7I5V7;G0Re-e6>0_ z7*gi8Mw?eF)6Dh-$v)G?z9~lU*kM()S$X5gkx)q48rc~$QT2SQBHE~bMLDM2z{P*< zEK~p{M9%Sc!2u3c;}8kLPon6x6C?pkIX{*#-#l$of+4a+nFAtH$t-2eF&F$-LVC-E zWFt~gLoaWhkz1h(Xn_TMWX<7Iym4E_$AL(l;rUm8K2MR}0t?N`VRo0l6izV{qBP2o zS+)NElKh7e(7Bq=2~f^cur!1aGrZ}sU%E~e9b_NEV`lS}3q^3Um>3HYZ-gA4-vTe@ zp2^bg3>8@&Z?&EFFK>y%uLXyl!Uy2wHLBd|7}7>!vBH1J{7JXv_-sBBFpflG>}%5- zVk+Qxvm#q>RL739Fk6$O?b``T3oJK&|xk{d~Te5T1dA{;T(xzcZBM zlf;LME+p_phBj&Nz~Fx-B+bjgP@Y1>ziIK)z?H&X1wC^BzZzA6_#1b%S8xh6=hBB% z%>9IHTexIYH4}xyS*px#c==pKmEhJAPC#P)*`-5p&iWnm$MvBV4e#3&nVkWDe^hMz z5M40D{d)olYk?b9!w(YT!eWWVWva{;RsI(cVEJ0K-iYDR9(M@olrUNw-N zKE)3BbXsH%99bI|XVbaRMt={ec{0C|>_jrA{$3?V24Y?|Een?f;_Svr`8yV7dQ!Xt z?_05PIScMDS$eOsdSQmAtmN_{iR#|61B;d{TvY10sQ4RX*9j506iA#7v7m+P(}$d< zuWNWv;X+yGa%7zgw9yXxVd;ak3lFwjzL@s#!8*GmKd92%LNY23JZNKgt8S)mM25F~ zt4ga1yg}eJ+!pu)MzO)AmS7sjcRJRuIDzLhG`eJNwacu3HQZ*J{9OS3@jOHGt*XTb z+tVP@JPmC6HoUVTv%~h`-lx0TJRfldr`w|*?O*t)?f(XCRzR*$A(RfFDhp&GJI9)T z$7Bd)B9dq3_sB`^?rE`OlHN*NJ4$`V7+;1X1o%$;VI0vb5C%sxt~>B+3??1mmI2;_ zXQ_AixBTF>njdFWpE>tB;j+tuooc5Arz?9Hd=R`mOlX$ckCzf`;~ zPJZL2ifac;H;L-nqZyYfEQ3Q#6uc7<`+} zu%ZB$<);yM)!QA}d3jwwPf^7;dG2DnMf;5gtx=2OM~!l}bG^Yyh|huI0?tqLAS~~} z-o$`Et8p>RvT;2zaNJ-+rLFYF3Eh5~(w8(ZZ(cHNRRxU@=6us_i*sJ4;}Ly7VePkk zEa)sHnr*UKFgGuwD~7eCzBwW6o54N0IdOcffBLum9#?&AY2w=oWU08{?+w3ikmX(4 zgLq#v%(~^9t>eM0t=%@%X${^zz)>@i*En~renibL*6|r3SBvqmI=@(v=&kG)!1nGs z6D8~g|4u(SPHYt$^q$v|z;Lv6s15j~-tSlI@Rt^jN>DHf#vC3c;HtR~I3Bm=R=41; zdfqg4{1$e(-pVlbYIh%Vu6o>0>3+5ac!mzgMkw7?m)0Z&-`p>YcDsP}HHDtZvG$qy z{N*;L59W=F^|?22ni*KwiBtQ09FA-Z*kXGM^?Wt95i^rEv zETt5Qz}wQaExNeR>E}@yO)pYkaYol$PsA~`x}SB&5BYa%@n6qOW&NJh1Af(t9;c&#LN>6P zUVM@;Z^V+g1?B1s4?EO)LXcbu0?1&qeAhEC zCV6ZzTL>O6mGm%k-&`Y(%osII9vz5s+{B@;nbJ<2Q7yw|u;YtbaMmBXV>lTa_42y} zmr#~r_McXb%i=mFzZ(^>b$-nC<-MeB=Bm&qy1q?MUbJo*Ace>JDS<)3wor=?dEV3D zV|HV`?Ay&_2GV+UTiBo6fXzLinykH2sk5%*c2Nk0EQIgMJvQ3ua%gX4hn!O4Dk zzRz|kEW7)Ba!ku^$3`7_jX08S(IB&{WqvP`+bdtOqMhJg<{I&_tjnnp{)0n5hlvSJ zS;IZvL4yR3^HgVP8?nX3a6}NQ{_VrA=lw5Z^ z`R3|!4yUv%nmlWN#4phkq}j9ERDE7j^03KwY*1GBWu({XqA1d-3#aCs`@yiA)3@}< zpXi#F4!q>J9eiYI(=cnQ740P{{EV)uPbnr>d#ERsNcMOt^-g2MeYU!hrd)3sqq+^x zz7k#I$s*c|-bf~&;WushsAL>FeBAn#QE^FRw*5Xl=2}WXoK3x!$%jS>WJt=IMTYR_ zp!c({$m_Pe&ExcEG|hctHL}G7+rJyXF>S(o?-q0>?QCYRt&Xks;=DVtaDftxteLAi z@4AeQ;u!q@q0R+~72;>w6`6F zZbi>QeaAz&glQrCtyxi>2si>_e%8~M1+`h-hY~44Bh@|}_hMnU0d|$jL$#5t#DV^h zK%+d{R?zeh7q)Me&}I$SJ7kL@+{Gq5;|bp0-qNm~y}_iKq309CCiM(Zc6ic?K{Jcb zbAA#uaNf4j0!{puM=`qy!cj`N2@aqQ0TI)$^z%FfC5|+>lGCik6+Q3jY)alX)`=?=fHKPkj$ap~vhOT+5dCCG#B*U#m zPwf>G&z#~g-huueT1HTLO(72HVNOd~lUpp`>UUPZb9-6+WK*79*yx*i9GMb_Yq#-S z+B0JuSLF_TbJ?hhnZZ(~gB7>Z>dTxzCADB<%=u*JoflR;j3Qec<8uZ~jkc?fF@7WM z)5kp7tfORi%RbK5~Q-DDyQBQlNL$jsKKUnZZ6R1Tk`^+M#dCZf*I{-%MEF#E2#fZ`WnJ5Bne&q{h zpN9AcNbriY?{v@rZ~gfo^`@3|KV{0Oo>nIIwR_DxtAj_ugNPAxTa;S}(MCCx16t-V z=s{_PVA=n7jvr~5I1YqBeA;(W$ajcgoyy#5M883dII-_~9U2<6F1?%lollG5F~4vS zy;f0ToXHZcDrhI0M2rHBeW4NkEG5_R0<(Psf+Iu#xRC;G;_VhjD9oQ zy%RAX1Sk8Yf9CvyM+myGyuJO)&A9b9IX`4myVAziLCS5{S$1+q~1#;zW$8tbFEe z=1m=ZybQnI54kF4TBPJ}JckcKCHMQY@HzYBO zZ0CLEEIw%ravF#viWP+FGWteT~kbIof$FdFLQqsx)KF9`;{+>X4OLXcppJuef}rBaXi#)e5x&>&zxl5I zJ8odH7AFbs`|M}$K$MW%Z)qka0_b4An)J@V%+eyaw79$uoL6JTCm>GJFs&r;Ct>+_ zO%iaq#CPB}=#WH+F{&p2z-kOtJ5&^ao&e2*w-^RBt5_8Ixrzm5>d``SmI2v5qryjO z8w`Q7D>ABqpM%g7a7#(n7(=x62GXE`F{LH1fJmRj)No1777Tck;Qzod71(Or^mu^D z;Qyowr9aPx4weJUik7rb8Vjs8);^?cgEUkSxj_s(C8U!Y;voUcjZBM`Fb?jez8Av1 z>e^*GaExXS@$f@B#8Dq+p=TqukcXJiC!rN!KNM5jAjU6hR=9xt1|;VI#iOGSNl3LS z*h5t#;vw!i$YTxuUl5NmASFQ0!J~rdb|uF6rY8ickTfCX9|_^cMcDFBcwEX@qGK(< z2$O0`5Y|wnLsqKrpgMQjz`}L{ffl__k6)l+Bk3VBJ*%Ea&Dx(>gk=Y+nPV97gO0vc z$}+rIc1g?HuA_g@f(anv!}FU5Y&G=)(hDK8NRQ+Tz(AFBMa+!RGdm@ucT(nJ4TAfp zsq7)4ON%6+tZypPIK;{X&1#}zi&3hI_Jr$Bhz=P02sRNT0 z3Ha-=M${zl?BlzH)G>(k7+9k)+5o*J(G9?G4E77$gh$ex}ee zySKlMNzS~}Q_pEK?uc2DLgXBJY_E_8(4#+vc)UbI#NqC!o5wWd3u`IITX^z(ui3|- zCG7$R--X--&DU$_n<3U_J^lVI)&+>volO5K^<#vXfl0YbENz{N5@Nrs!i7%EVgx3T z$d8xY2&cB!P`o0_jK>K9VSH^UC6NULKRnVo-SE^(#NUx+T=^- zI4$K2O6)M~c({Sqqx=D>T>g29Qv=iiIpC>Qtfv02i~|7?Gi@>sZoGEh0@|dQz>BctOj&-9zr?{fJZf=^5+vv~JDqITF@7j0*6fVE_SwHoO#c zSy}li`aKY>#6ZA}$hb=Sn@7E>Cma+YVG<^o{fiBh#{k~Y(5`5i>%Cbk2R){!RB;*NA5ANF6~6cjblx!j6&`n$bibL9Jff>d}%Mxm6MN(RgV3U=Wnkk^~5>W4=@URAsP~nsGj1VFA zhxE~MO)XGor5R`$TGGQVmc*61OG^)dSiVvsaAMU!q~C!e38H8X@N5vdGMqjwpcWZu zn`;RI6+tCj4Tzf_HGBa$Yj`9!IGiE_mg^y!H;-iXnpusNKQWLlN{REeEYJdxM(0o^XQ|C%7;v}ELRy!`f5AAiMXkA|p%2s$h7N8zukoMI!0!xjx|Fy8V>R`Y zKMS|zY7VqCy^iuu{Ct7N(UR}Y;ZP#dWkTg1C|s6uOn)yoakEqco32F5S? z7k|Z)kMYP4KLdF4?q6F-E#O|(Kp_lJq_~KYD*;!F0uD=szG6n;BytBGns$_tgwem) zp$}iJ=#&bhFlub4r5++xN~w04mwm9^|7@WiNx1sy8(;{D6)35hjbAZJ)tw|C*T6^E z_#`QQ)6^l_B5~Mq6o1Tvcn-Qcr5z5G45t|YuKcp2jIeDoQ+JYhnJ1~Ww)7rbPOs~= zH!R82ub44JIi{yvQj-Bka!Xh}Z%OL`HT{4-v!!9rWf3DsZB!votPE)QK* z&OEQ7Ul0h72}PcACiNTTop9S_-urevy&7Wu$D)3pM0TE~&`vJBC1J?lUOa<6|E!WM z7c6GSGPsp=LbW6x(vZ7TpFq@G0+S8_qfOm=t%XpnCaZ)b8IQVHLdlv!8HsxOBJqV| zD7@8?8lv@O&ZkRwv=j+tEiXMsLzO*$l%l6C7SL7$@=r|5{%b79KuNcwThAU_%%h|L zr=pr3a*EiXhk;g629XX3Izf)GRYR=T0R7h|iTX-z6`Cfc-hwE9OK+XT7$BP(8c%wx zrk%MNTgqLO zcCDV$V<30&hW3hE+dyv-CHG*zV_KF3V{Vgv?&3#P(`XY zfG;RDItok9$lx)zOIa15cVa+Xr+%YkS+L45=GEzxhdgwffF#m+=!Mh=YD)2UT0S%% z=&3Y3YL9@Ffl*%bP`Qc%;Y$1Km!1s$m&IqUYq%L-$}93b4B}xmp6BV zI;Xyq8xptO*L&U@{3}w5P2B9$SRO8Fv0cjYNhR(mfy9}+W7VUte+{$k?cKJggw&h+ zVr)fCP!JB@TTr_q%u@Ie!WB(@)rF&yp=?s=yG5E8JCjB--g6}LvqOr@`&V|<2>yu* zVUSL>zdKAnh2l&7poA_)9K)S^>E(j$rZqtUN%i+FdNSs33L7N?4 zn5n|I>LOUHCviuM(}%QS#b$afxJ^7aVZYm3_W-vma9u|jn$jjEMLSOx!oeY&M|N!c za-ocJIlUS;)sQqS8Dj`{R}I<-`+eoC$h%tN&ct%iBNOh;{;A4qBfs;0BKL@0RajGh zIBS{pBW1L+w9b|tbuL=DClP;jW|g42u%jmGk!VBIBE!cB)}pm5YFSib=!*c}o&jzakhnvomqxSf`v{^CDx8YgL7Ts{QpnLURTBJ7WNM+KVP)pTB`&+{-6!+-8~8vxYc~R z$ujPpq~lqpD~?vC&YLr2l#<o?Egfs=H=i5&eW-d-?os%!&y7Lhd*>($A^#ljzD7i7U02Wc za>v1FVCEY_dE%bzjufvpbz^1FgC=Ep+g&sajd`HUV81GKtTVJuymevt>U+=9`)GUgxTVy#K^BuBSn7M*95u{rI*DToM)$z|NG=yj} z?@Hx9>&P1F8}qpsmEbe0Z`RW8HU>DR&vfrQmxQ(#?v!+SiJPhK1M!xZnlR{e1DjF{ z7Ogr~DjeZank_K4VEqaUUaL=_Ius+(3%hYBxSFzq2dL2{ zc=lpdr|puwk~eeWh3kgpd^D|OK@H9nQ+L=|hm_iNw{ePnU}x*T;yK-Qrupg)&XkZg z^K+r`<$eq@*kY9OK~lPxtwl1VSRVC)d$fsQXHi!k+7fQHtEIzHB`k>;u{An4tU&tJ z)bs!x>%Tupw#Felmk+ga57dxsy7cl;rwrx|Og3w4>evtl}A`0SzF|x(URLb zl#YiC@ciHKdxN-bcDV@(-%|se(==6`Ug0ZG<6quLQ)pXC7_=k368X}4ZjL>qqErVZ@`an;0lNMUVc47aj zhl~zUlrvdrWg!nR@(g{eHE&>h%9Xa0AsH@H#_prn3x+~D*mxvuk)YU-@xrJ_9Oe`{ zUK-gWQ#??0BrOojrxT?rCKe7kI?dJcW5^8b#96W^_oaC4@@oA&eL1q^k;d z1(wX>LO&5yZ5C>w(i@bWKEYvK0)DC!R>)d%P|3@#YDN|MjVgm;#g@G^Ct=8?#sfX(oK^Tu>C`As^2gkZ4wX!7JVgw)xSpN4nJ{`IqE-$4%iUX zrV%6|d9kXDReGh;-S$)ICfrE-p|+?a#w%yodapwc=Ox=UX`77i%ukr=@3h;$nJWDG z)^GTgUHR?_>5blP+6z8JH*6~5cm8)fcH1`xd+{d?_vQfGX60Xwy*kSF)E@SpTgjI{ zqvsxW4;U|3w^=tyi(&)tb|&qf(*S1toibu`jQio=q&V`D3$NIVFC<+yB^6oCw#`^^ zy4r4|1G&<>Ep5wx}GLp3@DYtvUv8lRczbN%RTbjbp%)n74>c_uT2saWX zV+bT(w6s$4SGiflm9q)5+$~rr*EB!ETiI&5+4R5Zv-(!N{ew;})gPJu06XH<&1Wpf zI;LB%ofWyNjhz&geDz!Yg{h#Dl_{U*_df!=J-%CQ?c3n{nPW37Lt#>mU{I8D2 zA6{MdUt9O|nf&&6fBcRu!UpS^eXHmFRLi;27&aruqrBk3i}Yh}eHk@+lPP`%>Em@#>08W%`~B^?atmNCC|93RJb+Ge7Pcw zoBf)WRX#u$sT2;mA*JGtQ!mW68We68d_ieUIwxp6)C%R7L{8jecX+*arm-K)Ns2Ku zOAQ|rQC37b)j{T6ltLb^M67s0cjd}o{)8(fK5=B$6=%P9-AGEUNn@PUl{!0xyaxL} z>=Nz~zMw8XQ4v2bTRN;D-mbj4S(y?=7>bpPQCQf7RNseFWKAh5pZ_pLQi(jCqCkz| zB(c|A3V|?wjefh(t56=&RR3^LzECPR4U<{+%K>GfyRD3-1UV(+oYce+17S&a;Fhms zex8w;F&souc;qP;V(`3fq9_XTlpylt(^M76E%Kl!;y~~! ziZ~U8%FM(rB0Vvj(z-BD;jInjcbDJ<5Uc4#j6@NumZJ>iTrS+}d8%mB^-!r&Zox*9 z35#o#;u=NfFuY|E;m!$#uR$?aFaP^;CA14(AXYeU4YC$?`eK9>sgkgj7=2RI~OH&T=a(lE|ZV zR|2yYmQgr94qhNoL>uG@KFYLnCuY~UIVLN83@9+#tn`G#YhbtiU2E6Lf%Ea(lLI19 z*V2TfmdIyn;4l^3z0h6HhVNu3<9LzwO}O^$(A9OAOAX;_GGQtncX(SY-1`E@hl;*O zDHrLKiFH7GgX6!^ssf0~mI_CG;kG#9VyV~Zlf)?DtW=$H(YQjgHrhJdF@{pJNQbQ7 zD)Su{o_$1|lV;3!Ia01yT&Hs{HEU%ndeFf*z#M(JfoCE|c;@x3UyHkCL%IsZ3T?CyI?Ocxi;9an^5vi*e~Q+-dBK%aFtv%2?bwg2E89X#js!aHdP z%=bsbcj0308;moIF~%|0FxbC?OiHd4=z9@eFHo}V(8s@f(EF~Vgd->%i<|p#f^0Gl zjVkW`dur}6ue<;DU_j5qf#!Zx+`qDgWLHK=d=KYyJCo1EpStEVHH4ZTpSXB1#df4)K3Zwo-_fCi0o!eyR!iItmI&QB0lIgnp&N0W_ z_(!6X4;}rM+cNb1Yx$=O-hF-aZNaOaodrpp6=(nYX^BVt%IBZ4#-7Ch2a)!DG0TeP zX5a@ut^e;$k1+DFj^_ILZu3Cc@@MR)c8+lkb2}#|T^_Eg)N-I(F{hwYkz7e{dY$mK zYdOz--ef+9;JnCuURI-3LdHwlcKfO9NAFt0Rj6_2OwqbDxx5Vgz(4O>6%okpNm$*~ zlUKc##;Db*vHncPH2*aVa-=05;X2pcta&HrCrdEJ(wky=6xX*AyBYj#IH?8m`blyx^Z{Yh} z&mx|0zoEnJ;l!?+W+_oG!r1}R50zyHHJZL{#AyPEzVy@?WOf&?u9cIS$?4tO;X2w* zEl|tuItR71bs}N83B|Kt!ykxfh#ph0J2fB6?dMGx2pqRb4$ES3Tor-Sq89C#8N_Jq zpN@Ms>YP_g6LZ>s- z!0&ly%j{P)7Lt6&AGG&6VA;*3J|C`RK-Dy+h8T3WW^D(1^Kd%if60~F+=GoVHI z)Y)H?8aj+)#?pEMo<{Aw!HQXhuL!&|(Ew}P#cyw!hFCR6dW~TX(P#oXO7odQMO}av z;rDod%nR*e$7IXy>?~Ts!JoP7 z|FhFOJ&m);9~rn43_U$C7E-D!B(SP=gLA#ox^;wUPx?jWrZKAeJF}h$`R&0Kd8}T} z0msmVZZS!xcKAOT(KSNi? z9rNjYb#z{N*f2!?{;>;Mi)sr5%Ul|w;ix7xWAn%hn+eOG7lI4-^td|HU4vol6o@*s zNyL(OGGCIjVBFckN?MpOlzsZf16qtMK&|8W9+YMr)}pIZR{U3&QXc#{UxvLrXGMB4ZHlB40== zb8Ad984z^Mn5k1{ls8lbQNjXG^(k#0s2QJYI?VcoI|{Px$QIeKe{Nl=O>QeC4vIwa z2_?S@>=^U35GQqDO5p*&uk@eC$3$X2$Q-V$;1tM;1sW&P#;P7n=oJ}WQ(69Rx z2Xpw!Kuw0t&F-w(6NMGlGhbMKkvuS~DXh#>)RDC%H-fHV30ubokEk>^0@1XhhzAWe z9U29)jbFK>JA~CKj zn=>BiHPT#G`iIQw1-Ff@89*|eS{bi>$d=iX(wuQnQR2z{-+3seYwE2gRC30U1lgJ# zN~#ndFx6m1`6@eBjE^$#N}aM`NVX)N*X}rrUc{pi%ufpUd3>!apOGEH{V?2t+VimH zsnBR<>$hTyjc8YaWRBScuZyKIAnQRxS|TX+P46$>zrnOclqhn$72@L!I1vw5caO&! zLi$95>F~$X78-TY3(hZ_`@2)!G;965v5f2<%PxUa9r3-b+X}~hGQ0lER5vI2wB_1X zQ0plVda&2}a56CI)-ik^{AD$rL2#F@Ei$?%=ia;*;o*FWPB|Guw_p)i^G1_S0lGJSsQ7itb+*FfRk(M2@t`idq{yU2iE{VV(>g|l&`&X?e+N~!fYcn~01gDmE z>zrXi@Wfiu7vJ}nC!#)Zl3&-PGTyIwR}x9tBQ*bdnmvs+{jRlE_}8M6JyRP_e<24u zr9ImQ^r&X2*3ynsSPl2i?3G5^N(J0Ct~kbbb$Qhwzu3X4!Dhi1YF%Ul+;xetxvvh- z3L3Ap+gfjP8B_Z^*{Qa<;_|;s0gXF~q>jrympesxFxFp4`$I&6xY+93_`)?5TgohI zJ2g~a;nmG!47YT!o5bawVJ~eC^|x^za!lg&p(M}ouGyKGoJx0anDPlR-(Dpz;0{`5 zQDko0`6FmtJV_>u9Ip9yq(IZK?=$OH#HX&jpa#d)_6zUv(s5ZS8Kz-|Fmr1)jvBdz z^HirK%>!`I@GC22zs!x20JF}ix%pC=OADXq-k*+#r-nbjNfA@I*%DfpgmgigR&Ipy za4jI#3Xl=E37GVTukg5l6|LMVqs&D`^myU+N<*t@kF-3aUr*|lcA-TWSOLXxjI>(Ls!@ih1!trH=lK($r;!_K z(WNaUmkY`65ArFtPDNhZCGy3>cE(~uhy`P9$>!u%(n`0C$wK(KYg=XAr4 zpOR-kgZ z=dpcJKY^2oG5^-nz{U189m&SX_Y=lqt!MoKX2cRCR!E%`&_EgKFE#mqX5k_o14vPF zGz&BJ^skuvUl^jgj~rGLUrLcbfM^0^E|M@l>nV8~nDIO+FfjmI{Rl)lqeg(9{x2PL zDPq3dzzmbJqAyS_l32TY+Q>h&QcofXnpAB^{wtjAUV=GirE?h;$1@V)fK1Nk(qQFW+^5 zF+$okgdQ2;oPJ)c4jEGwgDG=NUVl5r6Tb9c+Q1E%RngNvtK8V zuqTRyFC^S(kc_Gce$a~Uyw$zy@wJ9sCq?iLIYDed{2)#~k2s1-o@l9#D7{NS91)s_ z8IZ(BY_u6Sl2s1O818=|*`|m?Cu>BDOGlYj(pf-x@LUQjAR1Vne4@|(j%^v0kla+D zripBk64WaEZ1n+|4!Hnv4(ajH8d4UD^cu8K6y4PBKF}52xd%y^E zQV$o;hW)3rDOx)udC*e*A|dQ5hafaLNUcWK@vor)DquM2@+eS(Y4(CdXx-6lG6et$*>{| zV!Z^G86I=n{M zbLQP+cpRfO>X36#)gm4X^bR?OdNz)6NE5$b%-RpKK%h~iXG}jyKaZBb#8N*A=`tZA z5i>yw1f3$0J`3o3g-E8D*{=R!S^AqsnRXOTZy=3Hsb}@91~s!^P1ftd+Yf>X&N&<< z_nx6nW&u?X>6Mr+d_u04fHw%1B|86G0%QItvR_XJZK8e&BTdUn)8^#p7-!U^+eGU5 z0p@u?jr=cbk|}1WP|~hJdb=9dtLd1U>9a2|=t&9&S!C*&!3P2zL|GTWI)jefF2$C* zP@sq-IlGIZABHZcH{sd1<=Pz%^OxQ@!k7~QSPmu_fd)Te?Ee@*I0|1=Qy+T!i7~?W zB0-EkHCCJX_il2#nsflo$%Tj&MT;{;3`|F85oWveGd4r#Z-b4l$4_!5q8QaEDefUI z`w1H_sP4M$JN7bli-GECpax1W`s?Wjv_al)xSyJ+-%Y09b|J_cNS~7F72sX;E#;V| z+~h3XQ$;C$IR89){nGIjmo;$uWx^~HNghF7C-9C`Uyp%8w_qzz;2<0IV#-;w3Tq{doV<%<3KAlrP^3%Q9uU`r@*t%zaV!eGFW0MW)y-7%mZ z(O}e-TIxJK^Tt!EQpl2s8KDpnOsJnqsJ$2!W|AhM8MCx~-r(`6dGwI1Ikq0~WeA;yqM=vG?7 z8Xd5Y!1>NUZ2IeUYF{yZt%0}|CD%(xD>Zm7#PE@1XbdEGP3{!WC0kG4$)kw1xS#aY zdD^+x1@JW<*+om3C8qjf^z1fz8U|oFc!nN-SwcBOd~l)<>Q>RW^$@4jIN;Y&p{rj* z@M|?O*8sbK$Qlpr){?R$j9~2X*XR!~fI=1EV+=se)0%0ZJl)Go{qEQz-eq1o!qfYM;qi-{oB@qZ{&Rro$hW`%^Mm(qYKrWwNb8Q@+WWAa9F5|0#@L_ViwjbEiZh!;;wz&&kZ1X3un z5b^~n=`t@ZR)}oT>sD%Rx9GEhl>{)7rI=H|62>}lkP4&rOixS0%vj$MPk*rKLXNT? zTBl}$2&Bh@o>GG@5PGG$OqUGkI)%h(&n2bUN|76CrlRoG;W<)TCh93C5$Dylo`*;q zKT#dEua`q4z^UX+sX^eX)luy$B#|mLCbW%sK&(^EWEFKg(B^~?j< z`>h$QcdHF`PZ%8<`Yp-(qaFi5SX3qz!M`&O>)&5PTVClY8AHs9X6kDe%l;(e@|4u{ z>=FpChkw@#LV()}@~zZRJ$DuSeS|n`4-G&|DdL$882ESQpZz>?ij)F0R4o}9mmyMv z6m|)rY44Mdpk$Vv>mt=`kG5D(|7{jA*q@dnrhR!$$`aDoX+JIy(QM6NCXb!I zo3u}ZWT@}-OR0}Fr|U3E1`jC{OS*)#!vcD}9#r+{SA|T#U{>;OrTlqsB8PN*20HH`s!ZwG|TtvdQXl<}+O$i1DU_o(_6t#D3-U^U9xiqbd+#5|f! zQ86-9)E7KTmyoZl(-1@#Ij<2>pg;Pv0S{WvIPb%GB`3)V3X`IV4J zT+P~|V;;d+zi6p|kp$7br99?7Jq-k&#D>42W|sxOhaQ~%?n7-&cel-Ko@sxOB6kjpvh5ijUfr<{ zmJ1qvj6CjF9-cdIk#yWK%DCQl$tx@y&e~bIw2-#1xwEjidhRyQgI2QGTf1wQ1nf&| zwPmp*L?K$-$L&WEs_pklOCI0cBCBNbk>|XIp6d(iR2y!Ey?tO}z2TSdggq zAr3z|G^aA}fxb=|=)M-&8TL@4+-@qAzS@}-b-ba(MVLIYOHk|EzE7}fVI9%A$L0O5 zab9#Ckvi@8OQ5@6@yh1q=_r2i@_-pf6_wZMH;op4~Xm{~e^GgePd z;XmrAiX7_Cp!$VM?aPy(M`0C_y%Yk?%5_3fo~6}|9hR~u$>oV!K^85lDcP>vYq-Ci zEyzx=Te3mqr~e5jiyJbMI{iQ^fc~A4V(}%?EOqPXvb~9z+tI4jd5<>LWLYJ2B|2CC z0ho|OhaP3EdFd26wJR&fV|rprlYzuZck(Faq?UhC%!~c?O~bzMBHx#Sx$WXthto3u zus9pWSs}sRj|B~uUvzpS=eT8E>&O5Nq(3SHX5r*Zonba$WS~Bgk@q+;V~4f7huqlv z>#&Gf#onkWpEIUwKzyIqk5$#qNFYdijh+(HW1Rm2y=Lr9YtrP*<}0Q`jBQ_4013wY zlUmryeF>W5;d_7ol|5vc5XSD>JE!rz=)gzuz9X7nzVcoHcT643Oa5Z5J?mK^%T>Q8R+)Q@Y0E|GHlw*u6cZagXzNN|m^_8LwrT3hk_>UC1$m^| zwgRkr#@s2+X(4Pryq6}>-DS!I9X5}7Wd-_^h^j{E*utZVhC zk=u}p*57*CbjOp9;4u|Bf!oH+>W2q&>x$ODe1X=Z;Gug>@%2eJUMub7^JY`-2I3jj z-EvUbp(Lf~#f4Ou-q>2SJiwM6kWBEH94(87+sJ#g5q8dn@M?9N$sgbz0_9VatlEvG zSUC6G0KxanfXTV>Fs5KFO(#F+m_FThJQ6pt4%3R)F;1c|PcMd(g`u3TsR=y2M_B6J zGeAA(1KUn$@zll;?ixX-P{y? zE5+IX(Lj)D`h<$UfP&}pr7P^*(@yV2K7cE-j7w8mP|}btgUDh6 zQWV(FwZ~_NrezKM?Bt|9qJ=tK`y+Q0=w1+K)DWf?^9QIa#?wr9Xk_aaVX$wC?Bwrg zm|aV25>Yq6xid^~JtT&aVad8{V>$jJ14h=5nEc{1OyP*`;odN9R#OfW5AR|2-7dg zS~`w~qWGxV|B|=K+D=B{9(N}UEahWuEdf=@A$fStaHsj zwtTmOcf#awQulz-U_GI`NlMCSqHrpF430sc(b@xJCbTk0(EVsTe7v6lI_1f(}KdN7IY&`kjps5i0YOXowSxlm>b#rNKO52u*cMr|u`Y;@`Gc@JD}71+o;(i?q`u{H?&}#lxldIVKOkc^J34hT9B2 zFy9yu9Mhdg8Q@8(?7OY)wNFrjif#Mv}a?};J=sBw!F0w*mYj9WEX|CjQX!8+pF+G&bIp&KW{CI8ljeVV`3dZ;wrkaS`=M~l$Ura$xQ(3;bzHr_GOEiA&!&ETl>YN^A#4k+p79gF^rM zuXQPE82>3Z-GuZv!K6)7syv-OeUHz%P3MehVdJCpL*N6a7kwPjG4S<a#97EMAf972)17Q&yY%3a+Gu}bmhN_bKYucE1$s*`V;kZ()ah;3F%u22& zag_<#aH0^;PnJgxUloFMl2DPDOt8-@{Jf4B?4(#KBnZ_+d(imdwJ($sZ77Op6i(v8 zQ$8iFXI&I;zY(>RRsvVHR1Alqzpw&M9vyJG;N1$%CEOFHs4QXzB@^_h1V!G!KI61=L4VuQWMym<@zM+2 zg|Bb|w+UGK4@Px(^(&(d*MuqzC!W466guk(N2?TpQn{r;6(QsUamq{xj?~DE^JKFz z`FOhgXMy6+kJBMvLaIu!Z(f8x6rZr__uRL~9Q#iV9O&}CC3J2n3|2%~>_47!r7(Xh zpidML!(D4u!5dB#T5uy*%siQ9Or?lP&wyX$0%j2 zke%_ZxI3rNQSjT**V28guZSi*RE>k^lp3eaXT9?9F1&Mr6nRkcY@twQ+aKxDaxDGq zxq>{IBPs&{34o6Xvuiie3Fkv)f;=x_^6mUEybuI}#nUdsd%YLRvqt@H58es^aUdsr z?|v_NLnJ@yHoR34gw`;JT~sJWcPc{LE3>pkb9o0YQ$5x^QZDKzX7noyqTtLzS(p!q zY~8sqpXYFv>e=uPe473PD(NlzC5aKsRA;)F9n?-mSWtnv6UtGOQl7cySVh`P%hhl~V; zqprBIfVqYV^4AIML)=|t92*^(YXX%b*j+>IT%&PF<#Tr|sSy6u`(M~y22}dV6=#&K zqeLCO{+0aR$9nZg@#=57)$~$J9K`PIF(Ojg|HiMr%ziKJ8ypq)Ot2t>7zZr1-%BbD z74PDvi$X90xLN_qdD+!67S9q^7&x!$&20FAM1U*jELW`##g9Z@oX$A>ulE z-1lYTY$D^>$G(vKL@#D**ww_D4i9XPh^`JKM*U`5rFsy!At|6U>H7bVFVRQ}3&@C- z>-ZY1UCEec;i}iXzzC#i>8{CDlF;ppsnv|=d-`B_+l%Z+qib%ktd_H0o`_g=|GJ&0 zv|GxtpL;m#PR_x3A1f&+*m!MP+ZemBc|ll$-KGKv^#asQFp*Y6#rtpPx!fnO^h+lLi(V>f%=Ke@W4$34)(?e)F$TZUe}A?(RHZ@RGi^Rol5k*CMz zRIe+=@-Aj77S4kowJBMtjyBo%^a7Ex!gt-kw*2S@Qeb*!y!qrxeqpi?-&XhVVqOn0!P>;THp3>jYIZ&QsW7`L5jk8-=zuy*z^oct zrLUY_I;LyqU@aWWppn|OZJc$Kww}QE>cn{Dc`Cjq;C)Xm}5q^^nb z`2Jvhuj!t`5I`EVWb`_v?c5_^pbs17to#aCR5#F*zr7w>hV15jy1+&RwqO#Ln!i2_=~ya2o8Lm7X%7 zG~Y54s75*sdYRc8pLSO8L?eg9N=;$U@&CmASY*cIhS&!mQ`vS}?k-{9ou%roQ(7E; z&=5aUFbt8n$MOc_{VxXK@QUZ-@;ms`MKESMIn%D}1kZrp@j0$4>}2hg;-NjlcnVUadeNA{U0ZXSG#bxYzfI_^#l5Ndpp)kM&)d{kf(g+;o#efgx;xM!HGRGDpv{^WT|wJ$ zu)Cs;`%X<@HDX;Mcs}!vhU~u1wq(mlgON}ma=6GY;-az8KbYMwWWx7PDw;oIX{3_3s=^a74!#|^y>8^anEdx0i8m(M2mSM?yrVJh#EwP^@oQfS+1eX+I;|nQJ zOtOo)6oiC8`^OhO>9J7*r*sSweTQ-JGuA2`j0b;r^a%+Z=_5M?Y_J5W7S{fA3L`P! z^ohWDhTtMRLs+=xgkN~~QT@W{Qd`&u{mrvlSme1%ZuI<-a%r^&oY$ypQ~R}D)>1V_ zjnfiiTEcvb>R>CakYTOE%t3djUctAZQXt|h4KqDzjoCZ36}dylr!@*05g-FJE1@E( z8zWeQJ;+R6ae<^gWPObg?qM6SkSS(QZ7ph4?Y4>p=CtXyrVF}T&1+5;+cDZLBcvhhuF=Y*2{lLEB(mw| zmH#4^F^)o=a41xil_Xk!Aa6A-7o%@}P|y5LT|E1eSV3NX!r0(+13fa!o02lermQK) zKW>1St!uEV>Lvs~#TC0-*-iViTjVmwLbpE3dMz`#p=MRWS?raiHU421fKiRa{< zjaYHen6M~g)fc2oA32*7SGif;MjsxIbpFL|*g;S~?cbXAPh)+wg-Lq*V{**pg0Ab# zwg&4SX{h77G?oKoo0(-_9N=0<{FoX_)s~QbF%^Al(%@!1aQ%Wx_AlcNrc;0 zP2hNuSHKV>rK6Bos4g;sKyOR4*SwG$%3IgRFc;&@_V$MwS+83Usnq7N+5RS*wX9z< z`IKihMDv{R;u%+7SZyl7yA3xhto5>ytnMNQQ$Bg41V24tjm+WeMdgBQ0($80*S30( zQm2{qb&kos)2k(=3!-H7Tf@44qu9jQT03rFl)`U|q&%SZ9R&5a-adI>XYC}nIUptk zK8z=`3R^8-sl%phuGE$Pr~`Ek<7SPAP`#Z9W`Sy%fBC?q;Xl4-npzgHm-l)R#$P$Q zfN@z(IEJ4ljb3KmC*KmqVdO3Fp)ZYqL8n_Q_yF6#)( zRB)7(@I=iFXh(7(nOcvZuVS576QApu=i1;nJzk?>N>qgAAMpwDcL0 zjjYp=t3DC}P`bB@pl|n@l+Zz-B2Gofm4Ia>QU`=PI_Qj7)6aw=?*J^Jf&(OkCqg7q zNc}FM`|?Q962jXCB0qz$0HVz{!2duj(3zP8?H?7K4(9YIk~F2q8#Um3j*xON?kp)i z8p1EvA$Qd9+Xe6%b;;s>M4}^4s%Z06KGge2msBwU;hKyDL?`;MfKq_)G9U8SJY}hBHPy`H$ii&P1 zD!P{7qKjqSP{khBhNx@6^2NH*wP4MC_jm3&_niAD91a9RCdvDGKF@OqPu0M$)$BAr z(+E++`5wM}{HGdSre<$8m+$7XEe_!zDWuC~}-RsPZxjpQBh=ONVgVWXF%=eY#%0&M*{Y2f(}|NQ7Zhd zCbZXxF+Uo>dp3M2ANkH>CaT#}I9n|}A(jEZtwx@!nMOjs0b+gzQ6F^xA>zmA@qabQ zYqM#$&(P8f(9Z;OBZeouU{{v2l@gj!SLrxVZfd$DmnhmKu2O2L9}TQ%$#kQD`CS5U zCGZn~KF}}(m&?9OaC;7)n@zgMXJ664m(RfcT82Qt`plX3iH{uC;!E_@Zz2p7SvIKQ z#sx~|>xR9;T)U)|q=$O+EyM)cl6!jijTHTCB%=G&%nS)WY=VzS;CW7zVJ#l2 zVg_l+ZGbESO`Uez={z3Uo?WNMjA}}@f!!p+{sf{Cuy?Kw(rS@+2E>%d222U?O*jLzh2K9mH zDSv&$W7GSpJ;<(%KLfn3mtgWu%p3*8Y1UtDXv^Jf+v@Y8Di~{JSQZThw?NmtpLz8 z)YE!=0YNrXLoXrf)!(olJ-%24yNTd-4YgHJeXvD?NLf8Vg(9Gz5nwz4mI`5i6S>bI zv=Mk0cxX~Ca~Us>;N#O&kQuM8M~!^dp}**v?hs|Qgfct@=4%u+2JDf9dQs1s1)b+< zX=NJPBT>*1qXCUoLtFtCOq^RM!U+L2ggadhCX$*P}43FxmWn0&JBl4fNOwp zT!q{L%j^;c=&sd3=pzntP+a{Bgt!BPgn$9?j4mAt#@?F?=#xXy6cNo=fMx5b_eID> z5wNN=q!l!JK<)l0#wv)snuBiBF$?dagqjHk{wu|l_;u8)D(Vy{c*V#6$h~d?IReqF zA&Rd7zAk~g2&@9rb-Y$-Cn4bY>{S~)IzS; zvNr+s0*4HeJP{)5(>3rjCu+NzBvxS?jB~W7qFv6%+(ySnS|U2A}G4T?_wl`PqOAPW*KO|hO;yD%sf3A)blz8oqIxQ z4AEsfJ1A#}`qrq8&6lKX5VLCqGkcD137^0&(Sqkc#%mt-*09#7q5jlRXRM{Y)lm-L zj*Zc?_uroqagJ32(W;-Zv-Qm6XDrb&=96Qn=Pbu_gf3j33wS zilIWzimQpO`Fh$}9t|+OuQeB6wlbB3=w{E{%lGcy05%mB_`5Jq-cGI5(?C5YvIKAD zpq&KoLpGyD%PQ8gY6R4@^3_9XMzNL&SS}TL%ilWcLmq8A0Z{mqN&_wJAT_t3-Yy$* z--&@(54DUD50W}O;74)k`UCFZaW@la2Y;O%5BM<-#kOLr_*lj;Wt9#nDKzv@gUwk! zZLx~(r*i!TYDw{?l?kZXI*N!F-eHby*VAIejQ_o{EGN(=6}nwQi?(00Sb|ydpuG32 z-=L{}YETSf6>I310UfJ`pZ#xDt^v26iQdtJ#Nf)mIj~L#OGVgX&6;Psu`(_4o)7G7S1fEHl}BG_yy5ujP5RI&g4I(fT&R!!SK^CVl)gPFixn@6A*e{eK22ue&&%% z)=vogKpod%!vv#h6n$?1t|{6*G1Gve-}%UU4gF68qs71$L$^PPv8OuP0(a!2_;#W{ zR?cHf`B4jNm14bY|K12G2VZVrZNHDbHWKt}y#E35<6}c|r5^jKLPj{)doA_sYV>dQ zojszJchXI}wTNDgzSiB*im?GP_DX~G^CX*i&rfKXMJmQRJ~OPCc34ka%zM?G&ukS4 zYxIHvHFgV_UjUK-Dszu^WvW=k1oNzzF@E_u7)svc)2ev1lX_-L6WXt)zS7W-Y{H%! zHU%D{Z5L4ZaU5r%kGX@)Z;FD?DeC9zfR6K-Do)*qj}Q_`8ppkBpSX zb2FAHm!umKo+#}4 z$_DFYF_LGTMWI={*Kg>*ewGZFja}z${JrMAxY8JwU!O(3m!HaAx?=g+PE)kedVO}i z$GMMT)fS7&G#{6w2nD3tiEL&X5qIxM)+$qB7gBC=wD3T+uzR)gR&Z>ade4zh1w|f? zjcB@=qVRTBe#Fd-Z#{9_Pj9( zZ?Zasd3VD;J;!Wd685z)fCrUXM#qeOQ2*AtYfpaWl?UBI=O3oaHZ1Pjk++o@g5o>WZhv2rhI-(Iu!JA^V$BR+VlkwSyIJqIkecVN+a~zFV#8HqQvNGZD$g5zIvTDm1=*Y}V`^#v3P{__2YZF|O98rU>LseU}Kef*V=~ z^jPS2{_?M3CXy{6x5GEx(>>9vVNWj8q+vjB%_|oI zq$8n-M&Zukm}KwtYp`>866V?HsEXgb2UcZ#8qa0ta7a1Csyw)PcW9y2F{?)RY-*jz z5l|#G73+Gf7Ku#qjP=XC?;kuEr)|nDOkHnva948SlEo8}I+i@O3GHYK-52zB_@HG@ z2<>3PBHyzy6Qj?)Q0$GUt~;?SBi=ucn;s#Q?@MUxnz$hPTD#+pEt}uQK+c)%a?`-- zFZsK-piQHku=isv?3#EI#ms9#C7&JVvQBR4@4Yv?K6KO&&PuZVlD~~_UHoKcXh2h0 zZltYUcuhFxKDi-+*Oh=LeRUb+B*W4J|8D6Ra%2bMCI{<;ygCO9f0se~2JfF%S_i9d zyu~|G&VA|KF|CyUjJ3?x1Z8Izw)a_dc$RO;Y_?w4hB_rBR?g3CLI=h2!E=LjfexgL z&xQj(>(*K3O-5;D0XlWpAU!W&bn5R>LXQGcMG?pVZSqs5ESGHcA8NL|=%SdeTf?yJ zMJDueA{;ZMte3r@a;&ql%r#N^bb>HXgUse!IdGOVnZ!@;X1S9p!aKSqWOVjUJfHzh zoF>NQ9f)NF33F{#V+ms+4nIlM34rHFE|uG6m>`P=Ncf6lLcGYMDnJbMCE_rX=OW64 z?ge*=Vyj65q~ z1>TzR!E;wYXSelO6C;|_!@bdv$0&u6&_9k_u5YicE^I=x0&>_jIw2!PRPHX%USA7Q z+*XMwo*7Lh9U_X;S5=jdKwceAgigM3uRP+IE8?RmV?<4nPkhKjM4e$={4CXgmIks*;egWtRZP&?2d=6Fnv@`&#EtPDm(7M0}fS)O)7g}DY?wmdx4 z%l93uj+uUkpU>}i$hc3H6f8YbIV5xY`%L8tD0wc*n~Iw>t8s+6p)|}jV~=jb&r54n4X*+!+sk8ya@a;`udVmU*2bi~Q~A7< z7v>;MGsZ9#sk^5>6>Z%W6oQ}Wgw5k0RK&d&&)6hQrs?ihoN#P5=`{3k%(H28GDqi# z{Q7J+I^y9j-4V*VTU}E;VBZT*nJT~O?$+KzZAf(Lz=1?4i5PCHig5Oh8mgK&Hh7A znVeaSin)HjpX4Ye&#FU{nSQ_5rk!w_HQ1i%7m~Jt=$-nrjs|VIeL z@jc_=Huc#{8gpa;O=I%OE`xKThT3vZ48SuuQcO_le)@nQ+`R-eh4|IX8Q(9d=O$Lf z%gH7u3t;~A9}TIZ9^Djj#J$lsm@ztc(YB{~}o1-=joH!RB7l@tg&n9nly9N&0?7FchOa|#wNwB|EUP(#gj z91C+g<>{LqX3y@G^x8aKKoh?XVb{4RViJncg5(^|83_E~c5rlOZy_^O4%gIGUA+2; z^=@gnl;Mbnxw*$n$ZWnt<2SsX5U<)eOU zj7UmNXpl|)Sxk>hG6uX&;P=@)1X-sJyMOB2UYae}DBEU)u}_tTtr802KoJPPy^+Gc zE1-XQCOuZMh2oG#rk=Om>%sJ$utI@k{&9@SWc-bw7Di$qCSt zd^lv^`B+k$Ys7oPJPMvKp1N}b>{m)gcm%Z#o`yNql*-e`{-hR2EnSXJh$5{HDT~n| z^%GI$D2Z+ObHi{&oSy;+F{mQKvOyN8L%JTwM~_Nb$4HK%6N+)F*?8+kKB;KPcjz6= z6cKQz)N*VR(2WFX)Yf{brIu*>R(=i86k_=_(SJ#yy{2xC+bPUg!e~am^$WP(lDW&oV^EO!ocVgU_EV4j8K__$s^hH`lhKS6)U(w3jPC51m zU(g-{omqAsUiP#-tg|DsRGv|B5p5y6VlpA;QhsaO(U# z;5W?T$h}3dYF+rPXe8RtDitJo29DdFcNTCFu7^FWDr<`MSRjXiEyPuniE;?I?br!f@s43vb@?eG1oxZ&7>4DWr2QsywecxQeL002_8bezucdpI~_7^ zF-LISi~DEH01{@f4B{wK3HSW2xL{1aFwOH~@9y{u^>Z8GpoTp&pgps%hEau}EhG<7 zqjSdP>pGB_7}>&c1Qdh*xV39;gCbW2{W7vOp(=WOgRKBNFmJppL?rj)DejXfJ`(wW z6=m*a%Hbp4nU3e|#>qTC*d3#+9l4%vkj+R_Aa3$&buvCA<4fdz;@^Lg_e2cI$mit1 zM>J)c{Ll{BG#15ps%j5w9vo*l&2N|_G*C>i^Aw0MNh^=yqB$=6w(!xc@q7vOPS8B!kFaNW6S&A8- zWXdI(s#EgaNFWhZuwQD`2AT3nwF4;@4bogiilpyuVP8tkcuL`&X5++U`G2{f zf**HR{3vJZQcOj6S3SelC?KmZjwD`MjZ0ct_|PjXgv2GvjyKA((h@?_%AaB7Ws?Zy z!L)n74N2#vL0HH(1d_$2MLxw=RYtw4I9yxWyVEDdYR+zoek-}+Fr^}@2KYcXr8m@= zyb?^P5fBxtCSM#&p9Kc*#r5?E@B7b9KiC(&JuhSX>HDuFliS`@aI-VEl@8ZvGmf54 zKlaD)(Rt~js^Mcb=_1$ptNrJ<&wFs}Sw=exgY3S*2puv))Bkh7N?HX#lN3 zW@FO@8X{C-wDGL=lW2pt0w-mopGkH^IoZuV7fWjDBUAkrgjK55S9en^+{gYcpyAH0 zv9Cq{MonnXI&ckIa;l|mdyq=varN|^tF;cZll7{cg8F0G*H=xI(&36~Cu97JqjzG> zES;Ss14AC+tb-XRORm#@J2O`2um>l3eY%;b*y5H=x5P*`of|%X+CS}l*o~H$M{hl@ zmfw6}%a4KfWJkO`5WMAYo68i1XgEuD)S<}Lbt_`#I)C4Y_A!8aBJ zZ+X7poo7eiHHSrie?J>qR1q^Z!wF{EGS%HjT%?}7AO-n`h+e`)uO9oH-n!|W9oy8qX?XBSoJaojc2Ek^ z2w1bm%qiEV2Z{zlX55UmgTiig-Db}^*(*gS>~l=2p8a;?zjRLG_kS_>2Srb6Jx(qw zuJCwZ{##ApV(wos=Va-QMINg@=wz1b$BPpJ-xh?1v*&&{qx<};@4+48mG5qP{rj+| z);C{1$I}0Q`j$8j5tp1JoHR5V8{kO>u_nLHPS&hz4NZL}fx5(NvN9X{P!6&2)MWR3 zk+9cN?A;RUQ7Py5(K0@CF@ye>2=JY`0U?V6JEI1BXnu{&*JnNsFfKxWQHnI`;%JFeQhQve~_?8$u1wG zRgkYsrp(GX=27kc_F8)gWX(^S?z>lS*v1G5^Q!gDHFu)Ao5sA`X1Y(jXq%@|aIoL~ z31>Tm`AP;Oy_D-rDOAVbdTM7x=6>n5$dTl1HJx1`tn_J&)eD&u>c$MgGaqUxW*-Y$ zE}IlKdg635v8XrrbbSju@Jy$gqL;wvU+Z;%&4aFadj&MXqZT$?>ye1JuNX z4dT#kL9O3+^w8zKIosUVirYP1+70TS;KJk`)>Brv2p}^PNV7V^(tpu4)0o>ic!1$U zQ?KbSos?lbam;Q!xCR_U7e0F0B)7cLd25?zq1Ytc>nCwSZhBC=;~&$x)7u%rUvpQ= zEo)27*t2K+-V|B*x4a$Z_BZq-%=9_X%&bmd8t4q4FIb7&$LSNJy`Jm(9Ljje;!b<+ zLEeL@H$GH(dpB7;g38^sYB&;lVso{CY&p!Eoi`NEILJYLm?p6MYm&`#Zp6f99h}-2 zI&m9#P2tkS&dzP2#WyH?FAP=(iS5`Y()zuOuu#c57SFq57r~+1ZIj4lrWqQ=iUT9% z-!3>zddR1|eOb3nvN4-^)^Oc<7s#o;4z>NWGjwvb$BbEW5=S?d!~1Sv=Y4Rn-KK^) z-FEDC)gi16F3MnCVuc56Z}YK@%G(81uDBg)8^jHD8EQiBTwW4?=iMc*A@RVK zt<1OI8=h=Kp7cO1V@javb#fUieu%tLBBeNSN2~W^-R5H)$Dk3d)tB);4$vI0>3qWU z)P=Zrx3g!JbtNuZ72?uuhcD-lsLGH_yhej!LFXKV@E=8kx>%HWdrU9h-uCkytJtL* zEF>d`8ojq}63G~uov^z^Xr%HvT^66!s8zj0>8ZDe|4NFOeV>pC4Tq_IlHTb9bqs(T zaARL~nZjK)Yh7|$-WMftVLLpxbaZl{YT#uVvDLP;Y|{6kKJ#u~YnVLSvZG6B4coQm zTnph0YpB6rHS(~h6(D!66x|Fj-%|91=|{-FDcj}gqNyhTc$No`c_ih3XyF1;p~v?w z_VtYpwh62r=QGiC0pwuYnRfYQysFmosUA2&sUFKym8AgFaTb&Z7dFYK>c>t7j+Y0o zYL_{=%%M8#NVC5VmOBhIWhSeHlgGQZ%~KF&?ZnvBYGjvBuYJeyQL5hu9ujK~(j|`$ z_;>IWo<>PC)7h_CP=Qj+0b;aQi~4EB6x&!m$))@PIHYRF<}u=@PQGP6`Y zM7^S|y;4Y;cm=RIF4=g_5J6!#2pBnPB&R-d=z7#c8DH5@d!pdt!e<&!h?|E9xn@O@eKv%Ea0@!Vc#1dTqc!?(L)|c4KFs zO%X3V`=O9E#4mTKRnsKi6wdp+ZtL~p&Z4J6ys<(#wMc_*PJV(%Ya;?qKxNiNvPtXp zyg<=c*rUjSY;`|_66=Al{!Zcy6OsH6BF2WI9!7N=wfAvYhd+@o9BjohA^H#?8JOkaqKJDHN>L$wdP)i~Xmlj(zEhE@bJ;G zJ}&n-%PN*+^S^>_&eKHPZ2foQHE6AKUJcmWIB#cE;iV6#)w+4Mzskb zcGw$rTSXj_X&)$<#oN`)V2(_I<%QM%Icc)rcETi=6$zDINAw?ba^v+JX)%5Jj#EJByonq>QMjmsa z_SVa}em!1}#bEot$7EC4vOAzK<-(Uu%*14#W1PfgX=KLsQgrH9Iioejfg7g@^C%jW zd6`p8#X9-4>0OE~joGWo7}+SFWH&onH8Qym>#-V=ZVj6LyX9O-ghvPmUDMFQRxVXq z*{oK6-O%IaafebV5qam~P#ahRPhQf@{2WR9u4a~rUE-RV*CJ@2^voCudIUzx<}x;k zA}e3u4S8;6kqp&vk7M~}S~!`34IG9Iv^0Ih^*$YVpR0d)#I9tC`=`D8T_|yObOiydtbJSBryCz*H67Pf%vJA*XftPB3nV z=*v5OoK`Y;BK9X8x=z5Z*Q0|VJ0M}aQB%E>>CqY%*!|wA!@+;1LBo{Z#le*M4MCf$ zWMEIz(ki#%4dm+6Tzh}urjw(xP2DU7cWXd2-u21?p(v>RgQnX#kv z~ ze~M`v30!_8EyCN`t(|mUgkJ`nik1-#;owpm@f*^mV+eTkaWPs8w(!O1M?Eayh@!PX zF9bi=vji#zfLfYc;3GPAjE?$4j41`IB^qR0g!_S>k_6Tp@B)zR;lS6yhsHC=W&ys0 z1HT1BR~=g~*nff#|9P0|$%%I&Llf0ZP|5jIPZ`nedO$E@2=*U*__H0twMT#xC`^C@ zgy$~<{$~fvS-|{YK>pN+x9Hh-CVmw8Y*Z-wF+1QJsr$%&S+SH;`${jCeWp5 z4eX((_`IELjg;*NIeHR|w|wNJk%z}=S&!B5AI+Q?3GJhSCY(tJ7>}L4>0L5t7BGR% zC}K6a_#;^3U}qBeu#R#PL4SbW1;JMGI3fY^fJ0uT$4~jOi}}%uHItq7tRW5ZuYm=m zG5r$q0}(2IM?d$4zE8&vgphY?#RnDo8+c^hf$)_SxefuCSeY2G35|gQ>^ zAJV{=!jLxvyh4R<<)_4GCIiagl7Rw5QG01L+h`WwP`9r|u?Gg&M+Ljj-)&gGV%TBm^H7qznnWOhN5_y z^gm=0lj*T%9NH;0D@O81{oD(8RMdf2s9FuNweTNXRctd-f`pMJ^X!sPx9XS~dfMYx z%nf3XWh&Mw0oovfO^VQ7K0RH(9?$M*=*iobcHP z=JY`G0{A#F%o8AIByf*@M>2xgN~%qq80kDFx)Sk_0CjO{qNFcU$24lNZr-J6BM*xZ zkU()KgU?LkFU}NHu>qY&HSVln^wrNMjK`$ zZ?)3Xh6baUWhY08VyA3=nj$jrM z7y+Rmy|o~cnyk59U|_`SX=NO=Hw-!<%{${LneZl z^9_t5J|j#;w@}ZLwL@3bjLjVSA`YHLT+HW3Jm$c+4M-J_UZ!UHsn(p)(+U7$B*1l< zE*toWR)r4eXgeS*gJ4t+Q_c&JGBG1mviu>(vS|9;M;vUAp1N7b?5d%h=TR#JtO5=o zG4HS9M;v)iUr3-8JlYk*Xhu5cj*#|28+N~o`6LASWYl9fwaks6Yb9ot>%l$A?Bs!` zmMAHYz40e4UyRrD*#$&|RLr!DLM}aB*#;cF96VIQF4waT^9k?Vru`arkBD)F7|Rym z8`Zy55qOfAolW4`eD*zY(;f-?oSMALn>!4lfV&#t)4F+#S_%E^GE@f@*BR(7n!6=h z91vGaRE%9JR*Rap>_&i=z|Qhnb$Z4{2P#&id8!RLVicf92=llRMw;ZW!vYjE+nydq)^ZS07MLsKw0k-F^)i3znbjue#it&(V=JBiBLNN zj}bRK(xK-CXdX1)z@t9bE*?HY-Ij?atLRYhrHcaehJ-wWLryjf(X%N4|KtOMT`K6$ zy|^TznW-SYh*l}aFX~u(4eZbR$na(Sh>mq!%slrW5cDlX#NK9vzK5PJ`KtZgOZ>}3HnuoLDHJ-r=w}i1wuo@NVfukd-d%( z@wG98_mLMZzhZ0_twgXdDdy@FC*yj9B>U)92me!+q;st;N`|d}b>02e!@Kqd#(bUL z-1;nOf+Ia8U{DxcGo@+qOI=4@1@pM?#oOMl@1OUxTsM>~Pug+xDuWzR#1H%Sj~3$i zEdQhZ40ZnG6-3q9&ZMV9d$*KSEb~OCnwZ<}be**F>2;HK{^Js@OUbKkGd-VoXc%*+ zSC3{D*3-&99!jd3b)ed$#e95d-~6fkA1m*cb9u{F7;7y|Zc%pItSQmFC{ez=+mC@u zV^#&t%x39tVT0tgRrsXXrQ)uUPjnlnqI}8zFCFNu$xB-r1G}rY(w%2sYL(3IJ+bZi zKUcboPOibMO_wh9+n@N{d=b13ZFqHs$T^o){jPV{Qgyp~UD%B%`D_6Yd+ZSAR0`al z{#*jC2U@<8k=i+)Pjgv6?pSTUr#Q#VE&heH)+}hS+tPgjZPdyusEb6miKq2&y)tR` zJ3%SOQ|={^gl$dytKr$?Mcsy{@T^1Q&RFVZrp(f!7<#{Fl8pa+vh}inys6F&_j@b_ zzT<|;Bzw_w(?ZVu$h!P^f21lb$Rol$(L6iUI3X*jP9n;{5BBd&4M==m?fJ+5><&FOt7v!3(w-P`Ic_-wx_^RLnf{w&AX z@Cg}o;q#rL)l-{pY;oo1*9k6;J8|Yb9a2<+I_N!_+8FDA4xAqxjkKYkBWq#qG<2e>NpNP@wz<@a|6DFs*$R|!M zYU;Mq;d}gc#8-O=iCHrxy}JdoXpW7(d+VO;2&}H_-RZ3qJlUBZa6gZ>4F0lstDUmc z8DI94SF$@pMa!*TXl{pAH?AG@sZPf)ha2S~%;IMzi#|!7nnas_LGl*6+;^(Zda9d( z=k{}R7~*b?Vpnoe-BZrqACkQK?er)H30i|OC(LK=?Asmm-1E64i7;uM5LOLbEm^)@ z{U(|4x_m~_PrLrQtbpJ9{Ik6WTmHQ{ZHv>6l>wyZlZ&9^2Xh1UUntyJ7w+dyxZk(h^~{ zF=(;FgqYl8ijAJ8!p9bKGMmF{=4#bp+fqkWy*24id5=x^4pQSfvdt?53f>KkJ-gJsfE=U zaEtl%ajM-zPih*c#k#Hn_DxDGcYZiZ(~S4>qwN?ur4bXlJ45{on^--WQtAp5?BkW} ztv;Derm3Z5->5-)K=Kpw1~C0THqI7k9oWy*@GNEz#Wu5xWE*|e>_ZxSF_X+VrLCCw zVXVymLN=#R4O_lft0s1;@daGD%|;W&Y$k=7KwRN<^Q(NH+POrh!-D5rRt4x#=1F{jXBVk;Z>_3vf%kXIhU99I4C4a1$y$Pc@rbzy>V2)1qJt%h= zP&L2%C^g;C5NeW>A)EMm#I$e-#Ot-Ut#6BIHG)n4KO9bDi>(Y49F3`FSjS@BZW)O~l$OgE`R+13%mkx%EDZR&(4VQc0^e)sux_kf#u2oW><{G-Y4 zwj!^A);4sqn!$?n-xZBB~h-sVkMb`+KF zzEp14AXVDswwRoW>eWR1Fuad7)3%rP<y;nkI3`iDRt$k9zh2IezAChI zv_qtlc{+BX#Tq-a-4fV5`gD1Entg9*X+*jIh4N%92m7@`HqBkA{CcR*W|#Wjj1=R$ zsw|=@dxJnRyiqR;9?IeTQ`l=A^o~AxV-x4L#?&GNs{H4KJ!kQazNrQ4(HEOTE_50w z-BV2HLavOSRV<(O(nl#+wdmJmj56t(fVE)Nea;!Z!RoH6B7La&Y8BS!vP-4va2YXg zF@(CLBw|UbQ{wZG+$GaP8PCm00=v7mc)->WwVl}>Rqy>zocqaKvXw$(>6G-QqU=aI z=Ooq#1{1WzO#3^lO8;?5X|KwZms!>m@Vy`*x+J%m^Q)@t&GR$mfi@xLS0m&u5p`7v zM*KyeO5}#Vsfu^0Ha#sVbaN+Fhvx0IA%G^{R+y2{NjACcvig5TBNfKa(W6$j^Od=i zMk*3GEYt1k2p3N&^KRcXh4<|+=YBAU{-vzo;#ipHsEQ#hZQfUb$p2iIh^1aQZpjeD zbFD{|OL_L@yMX0IORkLcE;DHxP}n&pRwY8CCbb2y4f>86_SD|=-&woNaC`Q6VC z>L?MG?$l^i8S@|?w$B^^>k17{{^?=vqmr6n7e4bkug^ZBUAV=IjGt*ZH)ViVdDdZ+ z)5euMxQd=C9_HXH+j_0nc=V^p&ChAtUqkvR`1G|?6oHJjXM z>$M50OS$OgNInv8$nt~3uAVI3;%o$_8nU1+nD zxTF_8rdfE7ZKD_;^FzJkDC!OM&eda zJz=*$POXU0ORa%h#ZM-Lw#JptoIgZ)y#DvVQnKy;VL1K;a5NW<8-gPZ@X2$edqXo> z8{sS-lNm)&{bcz&jA z5Gf_u@qJmXa@!*5(Qe3fygZ1jjN^w~nA@E}$er7y&eh!!hU1CNNCJn<9tv@Zvir*p z;Xfs@ONHfwiq9o~I_tu4t%G6=iq&f(+NNTFm(g1I_M961OYz}~+rsY})p|H%Ec}@@ zoDii*=69QSAD>$QM^-e(l)_e9Pi!GzhsIfB-E#ba4A@!}n!U148iPa*!E2@Nt~|FS zgIm-PP~6Ck*{!lbNPePDmRul@7;yWvT^7Ob9=AV!rTK`t=h00vIHB{m(^{8DC6r?x za41i)!KNR8EkfX?QOWB9_O%oZKAu22D~AaE#%AhorST^HbtpCQUe1gkTKo`KGAa= znI#X^dxbS9_@xt`Pd_^cnit<~6qyj2p2A zN?7TY=MO1f81mYNGDk9}eBJKtPhVz@>~!tR1!K&>7?-W&8Z7wX~zi4O3C|0C5AYZB`CJGcwXfRk>$ZCUDexpKd#I#shtp2xo zqW@7gA|zd_T+BmP7Amt#?f-s-E|eV38d5A4nNOrEi&V&3du5gu%~2`xD&)(tW2te9 z*kwvFFC}Bsoy9|lb%}hr3i+EcJ%_K%^+A)CDe?x;g`5M)TIHm+ld}^^K(DifM>1{r zkK$3dkj$b|B|cIsu5{%*Y3UD0VsX!;fn?@)Z_9X!g$OJ8n5s~xZk!}F8K+8i-UG}| z$&Y)b&r&x}N?prJmDQvwB==Ms+=kd9DV+}~A)?mJvu^5NwQfnXO^EGo>9zB~1qa$O z58GyuPAWa#@Fr!aPx|f}aEzC}@3h%$D`MBA`}_0mD@uI8RN9Jv9&8s*PSD~pH zKBmY}{Qm_y`B2LL2kD5VQVg}_`Kk5Nax&H2MWWYtDJblp(|GSj|5R887v3J9(R4}5 znmT3rz^T0c?ML6b_?yb3nD%1Jo$r0B>(yM3vNn(J!?EpnS}M@7GBLCitDiqr-bO{YdqJUYZKGXD3=r>!se@gni%t5 z^`BfgD#_F5cK(rjQ8(*+_YT#}-R*whY~0$~Hkz!G(^hI6XDxk-!WBOK zV}rN;w=HYG^YZlrN2XM-369se?x*d@ALJLkvtLv)B{EK9xQ z)K%ZG2oGFJsKj^;=Ls+H_f`Q!;bBQz{iDO2vtr0tF78nx8tmbb*Dc!SUoRgF#q6-B zpguI<5zfvRCtdUXQ5srh?I*9poGDKBI$E;JB6jf4ji&v-glFu_T(YS9vqItf9DU&salGtz%{bXa|WTqxkF=iAis8wmzxf zcNl8!Z7TDd%XH2Y6?gyg+l8cB|KZMJ^3DU_Wo*9=tgI*4dE;oc;E`l?8BVq^{(Id; z*!FvGFh%_Ixd77ZnI`4t+nGTR9+oIrM#qwPzi+oGAbiyd7QsHhHjB1dEGJRyeyAOy zr-T+sulj+5YKp~T>^=RrciQ&}CgI|wn?dh8OQOyMNWQUrHXBUj9&$&MZC<}cnM65% z?37(4Z+;W4vihL{m8wt)DK@bE*a&J82ivoP9tZr@L(3i8ULEj9tB1l=bIvPa%A#>i zxI^RZo=V(LB7}WL$e1MU}p1VUb;> zuLa?z3o~L4S4|?TyW@lVvDWhGhOtH0>@z(j2-+VXj!fl@%TQpsM_l6H`DLIPTQYK_>Ul} zQ=9%^PU#}<`XQlhb$gBHF(Ey$4GGk@R|HMZX7z#e(QOH=(LFJb8WZ91);y_6RugpFJ*QM}J?04@Q-7p9>TjV-yBCt+FRNjGg5o zq^rQ(T*6nB7-U@M>19g}sNr`nUNHabI{np!JG~Z|J&(F%Q=}z1wJ)LttMX<`24xN( zNH(7edTBWlMM2Rbv)MeE$HPSGgkC+XPjiW1tCmM_?5%w&NUZB5+zb<>ioKM+S`Tc- zswTWqwB5=^%35}9l)9oVbUJ^~7?h=XGI7Cp7pq}ch12vVtGj;vlQ*lnw}^ybrM=&e zXoB5Z$&<*Jg%fIvtJ76dCV5UTJ5yUx>>bS@B&hSzFO;;6Ju5e9Nn~sL^IMJ;T8?X} z{0|1$gBZ1(tL_ba+f~aKNzK$^GH*bDulmqpvX~QMnqz{xSGZ2zkXB|PsFPbqHJQAX zP<=)PQKHNyENVP5;JqEq3v;xbIw1A^YQj$C+FSg9!ddI})thfSnD1&sg0C2S?qBBF z-UK2NPbt2PV@F*bRqn9{k}uFdv06MPoHUwUZE6^q^jXzw-l~E?^4h;9>uZO z-qKxQ9`xJ;<{1OJCmF}PXnNhYb?PQsxgavIL@f>b@WduwKv~pPCo}Wwne=d|oAX^9 zeDd;J=)QgAjE!1ysJh20kS}w7X-Buz@XVg75q!OxwZgB9D&_9C&J|GKdXq3ID1?4} z%FMZI%Q@u=|c}i2?&Uw7>XE>5+D>Q z5{in58bFb@8f=SwLJFY=EB1h>*n@&%-B3kE4T>&{Wdpj3`*$_gMMZPpyber&zr(7h6*_O+mlGX?OI1muvWbuOtnt`|S8wD-FkJ|QgkNE4jF9N? zqnPaLdQv`blq_7CTgq9*MK>6qt9nLna0_{*>o$ecPvg-udiC&He1sC0);O`(P`S>? zMfAoSyaqL(y(S@%1_rlU3*LDo%EjCpR$BOO%)W9*DXqUPoT1iL=ZnMW20d)HhO5jjmNEuMqs;pQoXrQq zZIAQFHy27sVeZc@V@GBFFEN>2{0GNIyx;8V0*KinE^^AEaJKMD-G6pk52ck%J+eZU zJrK@L7e#Sy6w__gVYXc&k}bcT%)||xL!$o@rF7d*e)|(8QESJdznE>_$9W@>u_WzO z8*aPZaS_?&R4wXoN@^kFIQjoQuw+V`)FLX4#O+I}u(FcT)ITWZjUpri!zSF)cf41q z$&8LLTB}ZJa`3xd=Fmp8In-;-4|z}alyv0RX`?2!;8jy>FL3UNI;Z??<`J)|N5GL^ zpvwUoiWU&~Aj}6-@1I<_M$A5BWJht4D$sWj0d>HDxv>v zgsL#MLPr`DS0YS&8gt@|<{S3!3lX&@xWCBS{@6p09xNN6K zUS2%bb1wV@V=Yl5!blicKi23e%Pdd@4wPn)M#IbjninG+g0tQl$-wU62~-0Tc9D8! zDHnY$VYKC@gZR!n19TT-2S~_2HOy=-`vVWb4Q%pm$AxOTCKvgPu`%^*Rto)#*iUl= z&Wxgq#q8g~x~FAl5YQhQI>;_W%=h0WM#sT;qhtLfAe*@CdIP24DD;Ol0>V%|81zod zo+DuXFraaIc3ThQUkuI0YEq0Yu|^uW0w0jXMjP2+k8BaKM+i`aE5(XXeZPo6))TI) zDKFIYg%Z|Ff$E1zL)n0{&l;eA#mo#X{fk-xs!|C?)>i@43n7;!zkrSKUjxJ{As^@M zc!<)466Om7bWgyp_|Lh5#^T@-1Pu^EFB{padFPM8U%n`IT-V~ZpTxx<+y;Bsb^gTN(B)sP0cg{y@Z~%QUJ4$!~fGV(giaV z$62ugIyi8@O3yxO0DuQGmcTM%@EtunR78DmpzbrUPmADVa`I?A)to z>ot2%EnpdWq)h?NbZ{15!@k3Vzb^$u2Ww^&yU3Ouswd4hxQ>HC&?I8*79ar3^47VV z^i04`-O?RcOQ7)u^l=SzP|f0Kh_87lK!E1`%O1kW8jLP9xI~r~6sTEVBIv!AvR=bJ zXJk)1MsycLV2S&rM?47rImeK3J)k(CARX~7fpw^i8H+L9|J&3{3!=8Z;gZ*O5$79N z+-`t~(KR~aL^U*GwM(L50UmU=5z5D+^FjJULtF%t-V5kXK42oI|FQ!D<(>TdhfD?- z9I${e=35OksHHkPPatW@UySHxF}scnzb3$>_N708z5!$VId6V(o+{R}HwxhQIJCtM zIeUS+3V5Tmh>`~X5WuM>j6T^&dMtneL=}rkZ*F7p)#w)uRI+PoUmg0I2lt2$T`{mG zi;(Ke?pgUPr`K*&Dfyt7y-(fPVxTHd%oFpDi`BoZn9DG!696FaOpMU7S3dfe-KuWP zG*Bx}%p*(xb47_?vEN)^{&tJi^*1wC6vD^Yl5cD^Vb?|hjkOkeR89xpq$@i1z4HXt zbE;OwF49rHN)U;j<*8keDPa#AD4)gjR5fd+hWt|ucJPWmK>ZjdW*Asyt?X+ceIud( z%*9EZF&SqM@SrgbUn4-hc)TrIc9D?=id-SP$tMZ_u|&-Vk8uB%kXMV-uW{K59{UM~H0#J2&a^E?)+Pb#3r?ObqAVBf zRso|0cS^?n&`DWzH6}iQu~ZsyrfxzB&OTs-Z{p|^0&8a+y;aMiZ1)LxL^jaS?>I87 zr?#)9{>Ma!ft?Aq`U?MRq={VtjKItxw1Bx>$x8^fZy5RxqjcfSS-Fh$ zT=v90j0__a4A9*IekSr5&|JEyg&Rj?n~jW1JY-l)+dyC~4QDTv zu+B&-0p0L$<25fL!Ad}ViX)qJjD;fl4&DawOIoggxkn2+UX(7;1Q5!q1wa8#D=~CT zJq6taK!J_{_???Wj7#Zsko&7u|2Mi{*U&#va<1bjKoyd3=CPix%Mw(Hu?o5L3PZU9!QP`Efxi(J4UGOuu<2=Zc5}~OW&xtZk*V0uQ8E2x zIr)nL`i;wu&@pxss4?f5B?9Jvj&#jPyP!YXY{KyiTKFqA1DIhx3!umU5d^F`dTO?s z{=49mNI)s?ymr7y&(N`hacUcee8ea#pF>|Tq>77eo{e4hL`RLZ-;K08S|+F&MT#in z8U#R^Z!}EjHqvYXr3Ghi!CAYt9;s@`Q^(TjTa-BaxRxHU8~C9Z!Gmm}k#$%=eXk~! z%Bjx;$b;|9Clcyotl^-65&5unNW<_X&;kss_myk~&Tf^^uHVvcO-fz+gYrlK*Kwf& z0czr{>60*JI_iy5XdXb#2n?l;sntFX5FsM{tffZgRsvHdpv>%~dg9bN$;MI%^RS5C zricGp&RhcoGGC1pZ4=X^A*LXSBHUJxkSiykIwP`D zLAijoU8+vdwWLH5^-Uyl_!Pa&q<&QF1?%(tNLJ0)lHQ7{ zcJNp`CGbS`N+4OH7#QE(K|1k$HsK)jIYO z0m+=g=>XEKTaWh>V6~CDm&d3OF=KI7fk9B9*gS^VF3uR{cQnE`pEfsg#b+$&&QFl-6XFmMr5;CHimv+pPl2xUqK z1}_^jx8gE>(NevBqu+156Kzs==0#C?D;bYJf{!$~7Qn?4+A2bB;7fWEm;RD7>8}9n znDwXK1~j9emS&(k&EAF^&`Z(OG;qK{1Mk+3OnpL`i`BIn*;fcif{9&$!5spU{reu0 z6TyW`?~qXbFi_5N(H8E@%NlSMgqN*neV^sJgV(!W%Sh04oI1`(!37;^CP0awMIv7a zKwN}81L-#&U5PVxY2Fw#&>J4CjbYAFGk0<6_^BEoWqPHqs^!v;sE2CA|FLOjH&KSK zqbsIk)Mn_Jfp!zSBsENXhQCqkn7^wp4GXg07*UgiS}=hnRWmke*sU67nV4})O>Z|X zY5$W;d#0syOQ;4l4JeO*gK3Y1d0xlb&HMT1^dG>`^rw-^TFDp`(LS24e=?wi_Pg6J zM*q(ELEG`#?&2cgZjy1#Mx?~BN?Y2_mp1#NRy3U|l9kafI!W(e9reGroV$m zb}7^A7vqDM@L}Wtclp&V@29xAo5_jrQ0zcXf%UZcmxOtpE<#keyrwr{T%>GlFmt#&O009;kt8$c zRemztwsrr42J30bUtewCs?j-_g%!S*ab`HwKJQZfUq8=|{v&lWcv6z-=GNpt6x$XR z)<0L++`>r>i}Jmd*1u?UORIc-+Oi#@N2PKL58lmTM~^H(aQK9e)*J}wBYr-V)nr)8 z%pfEwEepT!nkysf0R*&6xqi(Y_r-VvW4WrR(bj5woI+3yXd+n?(+xzq55e0laYo3L z5gI&^P``~=nIx+Vv6D6^EQ<}p<}v>DjWvl)1}ES+8CzPD@}lW^83nD=pq@kj9Ny(y zINK>}VpE&kJa$dAdbW**@RNIkR@_fIf;cDWk1~mi@wb zWH{PTJS>IeI(cQzKvNV`ya9Wz3{;OrSLc7?D0lJx#!5`3_LbDbdqQ~9PBN)(l(b!0 ze-t)%%GU&%1?;_<%}L&ov_aw7A&Fux8Q{D$OIa-968XFZ3$3S)2N@38I_D|sQt+aj z>VhF(!6Z51)s*Ev6LrTxH7?dL1R@iv|eEr#k~~k7;6S+P7TLO z1h9izL+6c!voE7$zsoqy7bR`2;5?Zmt|hOC$uwD4xOYz&5>;#!IF~FoAT}lSp~1N% z^W9>hO-?4V;6|$7K&pjD zTDOi%?GB_NX3fA5%n!FeFOHfX?j+0-;OR9@3h>yq%#YI$kLSuACKjot8A(hP&~Nt= zRKdMr7WrvC*aqUQklYWBfP`^zTW~W3A2wT>E95wYA&F=QmTQ!GUcj`$>M)xfXo=&v zmd4#*V!2B1>e^-~=dbCYc7n&jQ@$8g34|=`qL?VVj3QMONnCm_Pw1V|Ug=#3+1xGe z^e&fFh8arOQbA|n^x?|M8PcR{eAdJX!<8ojI<5PFT43J$yRku1?B)9|-;5;Hbf9K$ zywdG}3|GaEaj`xL%ya3IMd>@)2ht+>YVR9?8JXCSPR}8EBZ>S;W>!WE2scCKbFUr%P6DZ_%o(3zR!*kdCqo~4vhWcHG?Nk<7}WU;&q?X*#@Dq^$? z%$IlV%Z>7YwqXlU2FF%qs-lWJ036UhWzOYtfjbF1*4A$Eh=9)N_)Nc0oW}am!VDV- zw>Xa}Oq02574}a$Xm=!X?m=(*Lc)k+fgx-{AG#oHO{ev4T^B8|MVVPRVqU9|`<_~- zuyYwE2@Ngv_LsKyRCcB#X{p@UZE8R9GqW;U`)`)n zl#GQ(|57FRky&fC9rQ=KCvoF4kl%wR{jDK$vPn@3S`^cow0@Ixnao3id)<3Yv915; zoy@B6W-D=FdDuXfMLvLZcFirFd8(e>qvN%LL${ztudNxnBRPNC}lwclp7-0SMl^ofi>eOJ@R&}2p}QCx3% zZm`pJ3uVNnHq3gjrpxV_xV)D^q8=ZFrd0n^7Cg0hMnN$&#qD2ok&bv5C|g|4oi00* z4h%6(UEFQ|gfM?s-fpsvnz*T`+&48mZ{BDceREh@TpwT8R{**C^(#$V{frU6Zs^3S9Pow{B{R zoHnEfMlO;?V$)ii%3)QZu)(rb6W+OAL=6;VnXPY9y7|B74$W&YzrgKrzB(Cy730M| zEFn9Hix7TLIO}klkhp|MPvsJ68*`!Sh!-QQuKf>LTIa+y{iQ)MZ>?7Fy6r;3%M%L2 znTR!H`9z1N?jXH6N9daLg_oVy7KUwW`rc)eNa6R2u*2@~xf$kGd}*vkR>1epS?tT%S4{WH;}F<&eDQvb!i0{Pe1RamHXlmWbe_H(u~AC$FwFEHgFQ18Ut=dO zjDhDH$$ohEw~}q|YE^8BGRoi>A%Mb0FHYuNJoEfFatpYy)!8*kBh8?tD&4mdd9hOk z4}-(7hWRlH06WQ1a?p-FXiI>Laot=*=GQ{4Vg4q)VC2^eVD}pq36?K+Gd0a6pl)y!^_8k>= z#EIOJb6pFdLqzm!R8wr!m@G`hbr+O`0qUt(p2UY{;tDS<$+NCGy6!CbgQE-oeC#E8 z>X%pgeMg82eO0V-)%_OTCRa{6(bnmg4x|PeI1uE%o=ffc+O(4~riD#VivBEUaqaF3 zjTS=>30{7UvZyAzHNFbJpra}L)4w_drW6M*(!kULd1CJkWi~{Pn~`XQN*w%#3Uq=^ z)ky?$a^1~tO5W`E%J+Wz1$(aI36n80#>#^UnK2A?gjtSVF;^pb?6f;Qn zC`8 zzG1gD@HKIi)+ZDxoEAGBUY{)ob86K_fMm%wpK2X?AWKe@16kAR2RGv46+)Rp`2qiQ zLLTq{3YJVuOe20eL3}kt!{Ud|2!3Q;wp)Hxok%x$6$#v2) z>_27CytD&3dSqD)6yS|4=vCe{L$Z0w=;QOUNB761AxmF*#s-7NjW)Impbl z6D3a-pntJMWs%>iSi49r#*=Bs)NVWDl^)$(wt^+)=p zJ45H^o^nWjtW}_Aj$A%5%|RV>>|G#ECLC&?_N3#-L|r64!Gi!vs&A}iL43StZbtOf z{kIOFop&;BUCZc%XGagTK1|K%e(H2jp*pc>&%OFr=;-j%$mIdm>@xlaGp_>R!i3O)R3 z@$H?ZfA4`Q)B)$^txF0w51^?LuP+8j_9+vS4&Pqyn~>h(-rrDBCs;i=kZYQMf4Pmn z^e>6WAJ4{THHV~koCx@w828H)m~E-XyfThX(^xIPJ8NXT1j)`6H1y5{dhOzq*nUWe51SUUeHY_Yc{r& zK)Me^co^+hSo*N!--^r<&#FbK*Z#&8mB$?xfbF zuD%<(O~0`OYilFVaWrA|WXrb(-vo@iBpI39EjR134vPtA&x)EF4{`6k@L_MBJXk@W z^&;LplKk%_PyM9oH(50^+w{`T&>H5o3fnk+5+kD(cZ&9SW0}I35T~xa6*}IwJ(k1Q z*Y}0K+<(6_botf1dtTMKNzeV~Pyd4Y{~Y`{gO%EJI{xu0gNby}XBGck>C6y%*XvLZ z#hNI^m2p|bgYLrZz2?!`4{Cy!@0WCpm@0qVGcOaa_!PPd9bj`l2bjxG;{*n}R-^nt9q1)mPqSI%s0`?J)iJEqHa zmzGGdoWs2$d79hjbTHj0b9_d)Gub(X?&^MH;tx@jc(0jl78GT>@2lK;K)~4YCW^j6 zvoCl~GZc`ja=iJvb3GqIqU#P%-$Ce{bhYTxh0oH7o2BwX(|9vPc+#`Tx;WZPqzqp9 zDU2E>?g?%xg6JD$j*WxiRCQSON)V|^Ay7j5q%gN|*zQe}#{A8E=G4Mc&KGVEt1pJN zd9Yj)G#k)RSMg*Bvc~3^P*2Uf8ezVfFk#j@ zGm5`uxZT4h_}P9bD~F$no~)zH><}X!c&Ed!V4IFPzTF zd(478ayuPL2_(C~ekQx8e8NX?P(i7yEEsH{1Q*Bi0=<<^4Bc{Abl>K`lGmqB)PYY9 z>~&&Vj}aVyv?=J%B$Xfz3p=+dXAHbIA@=%q$KJM7{>%Ovdx_5at)_J979K^^GRaIO zZlC_8mL4VwW4tyh9qT^Pfl-ArKesfHW!C@e^#=OR+~}!=W)w%wP1Rf4D{NbTgEm|CGo7(=;(l4~x38 zs6s)+^tWcEM_rw)#e*d0FJ{%#a)}limC{DVqc0s#rCtQ2NQM?#@gf&RwN+OTtvpKj z)|}rKcDxrHOCBLnV%thM#awt=@!_S>{0KkgH+H(VvnW`P%wl|F|ALbl-c3?Yr2ugN zTu&KKR?w{>JDB9e39g;(Zu}zP2sU{C?n3rP-$S$~0{bD|Uf-#D>q7_Ht@(V}hr4?6 zGA-FWSQAb-u9xk*=EZ2!!M|EGSN;CuFy}5`W+{}>?U-F_yK`6mT2X{JG=^`9)4`iJ zN~o)gCo!HrMJAl1+X%*zb#cvh(Dm165cvvwASd$qR!{eN(_#O(cZK&8C(3}+={(8d zl2S)+IHPNlSuns7W_>D`K@$D8yXah7vjB>Mu`(HpyBKb^$gq5dWS(i$>#bn!`WTBIhJ4Y z>m%Qge_ZY{!rGu<_hxczaW>lrg8~W7vJgC*GfN%eo%{>(OKLVHzwMCu1~GlPrTV^g z08a4GF;<}Q%FEmu?~Gi-lPwV%7Sq&ZtRzWB=MDRxs3V_2+22UFZ3z%(iCR zJDMfaaL}^4O1hot(qq{NMj9xL+L@~~*AZ9?u`u&{;){%w{?|Ee?bsaCSm}yKJ~#8+ zWVVfIq{$MeQoc&Ybmqwe9vNj}mCv6ga7ru~ne<=ABPfHp%G>kX;YA>++cO$v-zR3y zi6Jt21TvK7RGs5cWzoV9_u&a;Id}vmSxn)HLga4Pu+?Wgk|mr(HCy9*GM>8jocEku_LF2*js0z&n^cwD=499J-Vu5# z>FZoowsjmvcDgH8O2#`5jK?ULXcBvh+}YAx-0p77Jh`wko4IhT!zN9Fjav!`0?_Jv z>4YxqYJdauNQjF!*r{ZUx|k08gCh1Czf7yqwk{L9he*Q&9gdd>B;OBCs$lgAN{^v* z;$^Jr+Wn3RiXch|!CU2G6jT3H|EF4cr2$k5SpzPHBK8;$+K#cGh@j7}NT7Svt41#A z0cEn(wtdPO9U~b~G6Zy{8Y&YYquS_FJ-bCs&cf*a;6T5DwuM^)Kn{(BoJp9wkiY;$ z2aeI>_2jz-cD{!Ej}EfaF#nUR=LH?5|v6cd6sQuOh#nw|uLmm<+5TG4f)kU5t$U#=y!kQh)FS5?^>%HgevW&DS!Y z;p9UCVH}W>v~kJyN-_|cY|3G0T%iBpIhzO!x8eV22$0PI!jV6@*jshh55cmxIE!R9 zd#r!)rIbZqMA;@V_Niy_jedNA^UyJaA{b*I;*upr5YC62I?HRi<$m|s zLlJ&gMp+pGN0_!PfnXX+{2h={hkx;kPe$UyuMAcO_<6m9i98QEZ97rbCUX=RG^EIe6HU$Q!l$OQ(lv{Wd2cT zT+fI$Fi*Sr#fic{e`Kc+)HlPb`0838<1G8v%vhtfk2*S5K>f+3Y}T_qovXJ?m%YS+ zK*uJ9mlspQ?2s-S*V5BKeBfHnBJpz%*R~cC=t-zLqX|DM;r!Y|!l7 ztlPm!p~oMGf8rLUIgUoRojVpdnsBE5?Ct8>nsDL@rZ>Tv%gi-E9|=J~R+Fz`Z`VU3 zB6Opm>IjOiC$O^xl@0-|y9eH!+9EmhdKEK`k)h~Vu4_Q!s9 ziiGx250!ISX$HZ}KiFYL&<-Kp7O`fTG)zsed=3v;_fTmk#YhjSc?Ncw0DfzvDgmbf zG9|{0_X7E-fpX2b;e~`r8fIiXV1(!$BgAZ+SEH6tzhTtfdLXf(ewHA=VJxYh`c-6E zvy6SoFy%Kj{L@HXo=wl=BUAOBTQPQVU3opQB4DUPt{JtTI*cRljFc7~m7_%xVwm5# zUZ2(EW)Y>~ceDslXa?$Y9eVV?5u7<>AiIx1pT!JMHFQV<3|Z7VJp9 zoTn%I#<(sq(tdK`>Ai|S2@oJg00&eF+)x_wT{U}&#Q9sZ8Ty_Lc(O}4`lp0CT@49M zz05hfc?&VNOhnd*AQ^~t>0OqK*cT<>O%7Mf_<|-hWny}E1yOCxPI1kQcoH@)`D&Wr= zAeV`dI1Qsmd;XT-tca^liQwNkVwM=iX;kGN(o(*JO>+N2%>;cL0@7+gT`yQZ9cvaZ zj7a-PopitI3K;BxB*1`HpQk(aSCtWf^dZc>XuIE|#XATWsRJ|XIrerh&@wRXX10h0 z_H&eeK5BHb0gdtvs5S<=Bgi&SL9mwYL!f?E+7p z926Dgnzcy%cXp}(I0~!mA6KkWC-?{`pA}iXN_!-goylEvrHrgF?kAseE+uP-Gycoz!7W#^btpOTW`LT+^i>$$ z0b{P#Qa^|9AEMEt29id!s07HgwD6x|Mhq9R zGq4Uy(2s(>)dZ^CKx8xnXx(BA*jdPonqiwJ zNOaUV0Xq-qRYd43{mgI)@{&uvrlaJB10J2cAE!N%Ft>@&5Cg5jfIOG@7Z6z6jPL;r zHP`zN`y-=!5L{2ev1MIibPoYi@Ti{;&j1*;`(##xL5^$aIbwQ>i2f^vZc!uKG)RlF z^_T_%3A7d?N<9}-OFFngO-ZE&w+d*$m6AXJfiAR$O980D6AS`1s%<=ahJl$m(7%@e z{jP~b+-7D{Nt{e~^JpO{}4(iy03t1#CIzT%&bKxL4^5S zORII%jo^LTd;w4|8zdEu(&dh7YkQ6v!AO)pZUIo%F@d9_r>Uqb7oHz@*N+Y1`!tL- z#@B~5j4OEaOHttcBa12y2e#tODffK1ORGFxG&4iW=Q5U~Sez>0tAn{ z=@O3)6iV}SRGElTiq{Wg`m78Bg}Z5qmbOqW_`84+hPyrg#0WM}pI9S(807#U4>5|$ z$UbP&ry1QzydkPUvm@#!b*Y|KE1>0Qktb2`HO;S^#0Y3Zu_Z8lhAFy|9c> z>siIN-ZS3j{qcD8B#*x9K})^Gy3lf~DJ(U&n%O%0+nnK{^Z&Cvop)()X~VLx$(Rq$pJFXsV5ZekKW!j9(I_PNQ(LLgx&2v7#w<~U*)L#AR(TO8v z_uXPwnS5q-^l*52S*263Yw)mbv=ev zo2U0g@2Gb+b2qP_RC_)D58<9*b1KmW`#whTT~xWCs9V^fDK)>NI*tk5M=^sJWYuV_ zoESotad^o|*6G3pSNSp>$~;@@5pnh4Ib66wc+iMdR1o4OK>sE;P$^{to%ZlZ5x>U zqia{3dh;q9Y*|8=wdCi5M+-Aj|0>$Ol`u9rwIYbP)H>`-%#K9fUBZiP3;OV-WpNud zBeh#0Z`m$ayW#CL4~MTeEPTDZpI5rR&@@n@cNIgGTkgfIo}>DO_@Y+m`jV3+?ieLk zMtL0}ZR36U@oF1l-#B9F5o9K}rXcQ`GY3s!^8NGifCyXnbl!;h@;*ZkHb2M-v1mNR zKWZ||4uAdEp2Sn@8>%h;*3{Sv51Mt^#@rHo+a7ndqfzOZj%V$TtMi5&!z%NHC@0+# z;v`{3uC6X!O~bpw2E)49`GrMC>EXo&r?(3jnMzwaG?+{hj$n~k7`MM(VU=w5LOuV2 zKwgourfFE|d@2{J^YaVwdKMAjS1Y0%csW@ z=_!4~G>HVUq4g@~R(9B$aH;(cC+d%{26_d*JM;{pB1%G*OchIQU5HfyJG89nQw=sR zKAbPNBus*+UDI8fDZ}kV^RpbXJ?ac6>M~g?o4Oq5+#pdkPBx`l*!&<5jaHLXNtK_py$uy|(GEp|O9Q$VlTQveqxkfMnKz7O zxdPK>7zU}#>m3O~U9G4s%VL#G=#lSDTN>}oQtB066PHz_7MIv&)OA@a5w!Jqti^Rz zguCHaYVw<`w96dj)DNPnxKm4g_JRSxt+pa*G>d)0G$fxsZYZA}pJjQVzGT`OBAQy4 zNuN_!<}z@B5>r^hQ4V&v;5uJunZcoyZ>vtOr$4A9nKcx5Pjx0APUUylsQ6uJLH(*| z&U3Tz0hycEl zwe$IUs~pu4hunG_fojBd4o??a=k7q1NDEWzx~Ghp+eUZYUcH<1AScb25!Oe-UL7v+ z%55%7$SpZ}UOj&jD3)CpDb0aEB+GyM@o3?>6RR|pc@v9hb4ChJW<2bQ`58vJcPHy; z##4Yz_-Ie8cg^2D(E1`{O-y zw=6c7F~({kp##R->5U_djcKxnxy=vnikz+5H*A~s z)BCr}a;ekrL*%8o4@&#OvzWdca~=KPv!jFNXI2}xuSa%yB3X zazs0peOytu_|`Jcnlo#uens(}pEg4sA#2>-1r6-o;#aLNxFaD7e)IAY3(Hu##|VQ2 zP$ixug$rCI7M`|)rU)=< z;270gTfA1al@M_*i2Ll8k0)vwMp||H(W;!_VLQ*3%Sbq3Ak=T4blT=@Ymjhq^~zL4 zKF+E?D3M*@50*?${bs&{yPV^nS#f6VUe;y(?%3&Ovt4vLn)l&&0NBCGpV`>Kw5Dm} zlcAV2`=PUK(6lcSnaMtAm{!F(8=IF>3JyCWG5p9$?j1~L7c`YD4&z=|GeTZ4sFDZs z-Fz}T`9Ne8ByO9s*a`L5iqU)gF8lcYUjq3hbh}rb9&axwt<%DKye4!xq%*-~tAi5a zE_cp&UvJmKWvF|*JbKi@@S;N;+&&D|8%VJcr+Od30@%S?ba) z%hf&o&($g~@uJa#_9VKHTON8flNA}$ZtHJWT3T6eaTbTnuTP$*+1jiw;9X_||B-ND zd9fr}IC@R_*n#a43AvU=UZY3<{bu_Iiklqw*kXAiU(t2n~6bF4I-qjY*xu|q5PrmDQn=?a~F zDrHPQhF2v>ywkVs+^Vk0&5=AH~zU-%Y#`nFoeBglg>C}5PlqJ?2e zCFd2${X3dM1m@uN0*CXjlgY6fm7aHF1q6At$qUw;y)EdDR{4foUMx-}uNW`oja>_t zOrK#m@dp|Wd`PK-I8%k*r)KZjIW?tSoV~H;0QX z>NgAID};PS^(i=O5MI0f=Jo+AN}lyv@7X}3lA-}Vd^5)Y#eP5KwZCg8G#Q*jpV(vuAEGw$p-{@Zxz#V5DVG~S}+`T(AyuZTB7 zz;9X-Tu;T{$k=`JlkgSaEdCs`I?sdZQ#tKr?p=U4dfIBGg%J7>z zu21f~aJc)Ai{G&R&gHs8Zsf!=!V$N9s*f(!^*&RfOs`L;RK}@^Bf0nfI){E>+?!T( a@AJUDA204zXcFJQN&M+|j||X@S^o#DS--{r diff --git a/docs/assets/light/effects/PlasmaPaletteEffect.png b/docs/assets/light/effects/PlasmaPaletteEffect.png deleted file mode 100644 index b6d7610829ee503300d95174b8b96c8d3f2e6b6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13487 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 8` to stay integer). The hue feeds `hsvToRgb(hue, 240, 255)`, keeping WLED's slightly-desaturated look. Integer-only: angles are `uint8_t` and the [`sin8`](../../core/Control.md) LUT replaces `sinf`. - -## Prior art - -- **MoonLight — E_WLED.h** — the WLED port of Distortion Waves. -- **projectMM v1 / v2 — DistortionWaves** — same two-interfering-sines algorithm; those used float `sinf`, this is the integer-`sin8` equivalent. - -## Source - -[DistortionWavesEffect.h](../../../../src/light/effects/DistortionWavesEffect.h) diff --git a/docs/moonmodules/light/effects/FireEffect.md b/docs/moonmodules/light/effects/FireEffect.md deleted file mode 100644 index acde6c31..00000000 --- a/docs/moonmodules/light/effects/FireEffect.md +++ /dev/null @@ -1,47 +0,0 @@ -# Fire 2D Effect - -![FireEffect controls](../../../assets/light/effects/FireEffect.png) - -![FireEffect preview](../../../assets/light/effects/FireEffect.gif) - -Classic demoscene fire simulation on the XY plane. Maintains a `width x height` heat field; sparks spawn at the bottom row, drift upward with cooling, and are mapped to a black-red-yellow-white palette. - -## Controls - -- `cooling` (uint8_t, default 55, range 10-200) — heat loss per frame (higher = shorter flames) -- `sparking` (uint8_t, default 120, range 50-255) — probability of new sparks at the bottom row -- `hue_shift` (uint8_t, default 0, range 0-255) — rotate the fire palette around the colour wheel (0 = classic fire, 96 = green ghost-fire, 160 = blue plasma-fire) - -## Rendering - -Per frame (in this order): - -1. **Cool** every cell by a small random amount. -2. **Rise** — each row averages from the row below (4-tap neighbourhood), heat propagates from `y = h-1` up toward `y = 0`. -3. **Sparks** — up to 4 random sparks at the bottom row each frame, gated by `sparking`. -4. **Render** the heat field to RGB via the fire palette (or hue-rotated HSV when `hue_shift != 0`). - -Integer-only, no floats. Internal PRNG (LCG) avoids `rand()`. - -## Memory - -Allocates `width * height` bytes for the heat buffer in `onBuildState()` when `enabled` is true. Freed in `teardown()` and when disabled. Toggling `enabled` triggers a scheduler rebuild that (re)allocates. - -| Logical size | Heat buffer | -|--------------|-------------| -| 64x64 | 4 KB | -| 128x128 | 16 KB | - -`dynamicBytes()` reports the live size. - -## Tests - -[Unit tests: FireEffect](../../../tests/unit-tests.md#fireeffect) — buffer becomes non-zero after several frames of sparking. - -## Prior art - -Standard demoscene fire (Lode's tutorials, FastLED's `Fire2012`). Adapted to the integer-only, no-Arduino style of this codebase. - -## Source - -[FireEffect.h](../../../../src/light/effects/FireEffect.h) diff --git a/docs/moonmodules/light/effects/GameOfLifeEffect.md b/docs/moonmodules/light/effects/GameOfLifeEffect.md deleted file mode 100644 index e65ac142..00000000 --- a/docs/moonmodules/light/effects/GameOfLifeEffect.md +++ /dev/null @@ -1,71 +0,0 @@ -# Game of Life Effect - -![GameOfLifeEffect controls](../../../assets/light/effects/GameOfLifeEffect.png) - -![GameOfLifeEffect preview](../../../assets/light/effects/GameOfLifeEffect.gif) - -Conway's Game of Life (B3/S23) on the XY plane. A D2 effect: it simulates the -z=0 plane and `Layer::extrude` fills z on 3D layers. - -## Controls - -- `seed` — PRNG seed for the first initial state. Later re-seeds continue the - same PRNG stream, so each revival is a fresh soup rather than a replay. -- `wraparound` — when on, the grid edges wrap (a torus); when off, off-grid - neighbours count as dead. -- `hue` — base hue of living cells; a per-cell spatial offset is added so the - colony shows a gradient rather than a flat colour. -- `bpm` — generation rate. Roughly `bpm / 8` generations per second (bpm 8 ≈ - 1/s for watching gliders move, 255 ≈ as fast as the frame rate allows). The - step is time-gated, so the speed is independent of the device's tick rate. - -## Rendering - -Two `width × height` byte grids (cur/nxt) hold one cell each. The step reads -cur, applies B3/S23 (birth on exactly 3 live neighbours, survival on 2 or 3), -writes nxt, then swaps. Living cells render as -`hsvToRgb(hue + x*3 + y*5, 200, 255)`; dead cells are black. - -**Keeping it lively.** A random Conway soup always decays toward sparse -still-lifes plus a few blinkers — visually frozen, even though a plain -"nothing changed" check never fires (the blinkers keep flipping). So the grid -re-seeds when it goes **extinct**, **thins below ~3% density**, or **stops -growing for ~32 generations** (the live count barely moving). That keeps fresh -gliders and chaos coming. MoonLight does the richer version (pentomino -injection + CRC cycle detection); this is the minimal equivalent. - -## Memory - -`2 × width × height` bytes, allocated in `onBuildState` (PSRAM-first via -`platform::alloc`, like `FireEffect`'s heat grid) and reallocated when the -layer's dimensions change. At 128×128 that is 32 KB. Freed in `teardown` and the -destructor. Reported via `setDynamicBytes` so the per-effect heap figure is -honest. - -## Extension seams - -The simulation step and the colouring are decoupled: the rule lives in one -predicate (B3/S23 — birth on 3 neighbours, survival on 2 or 3) and the colour -in one render line (`hsvToRgb`). A different birth/survival mask drops into the -predicate without touching the rest; a palette lookup drops into the render -line in place of `hsvToRgb`. Nothing else is coupled to either. - -## Tests - -[Unit tests: GameOfLifeEffect](../../../tests/unit-tests.md#gameoflifeeffect) — B3/S23 rule (blinker oscillates, block is a still-life, lone cell dies), wraparound, grid (re)allocation and free, 0×0 survival, bpm pacing, and the renders-every-frame regression. - -## Prior art - -- **MoonLight `E_MoonModules.h` GameOfLife** — the feature-rich origin - (rulesets, palette colouring, blur, mutation, pentomino seeding, CRC stasis - detection). We take the proven algorithm and re-seed idea, not the structure. - ([source](https://github.com/ewowi/MoonLight/blob/main/src/MoonLight/Nodes/Effects/E_MoonModules.h), - Ewoud Wijma 2022 / Brandon Butler 2024). -- **projectMM v1 — GameOfLifeEffect** - ([source](https://github.com/ewowi/projectMM-v1/blob/54b50bc/src/modules/effects/GameOfLifeEffect.h)) — - used PSRAM grids and exposed `setCell` / `getCell` / `liveCount` test helpers - for deterministic rule testing without rendering; mirrored here. - -## Source - -[GameOfLifeEffect.h](../../../../src/light/effects/GameOfLifeEffect.h) diff --git a/docs/moonmodules/light/effects/GlowParticlesEffect.md b/docs/moonmodules/light/effects/GlowParticlesEffect.md deleted file mode 100644 index 2161eccc..00000000 --- a/docs/moonmodules/light/effects/GlowParticlesEffect.md +++ /dev/null @@ -1,24 +0,0 @@ -# Glow Particles 2D Effect - -![GlowParticlesEffect controls](../../../assets/light/effects/GlowParticlesEffect.png) - -![GlowParticlesEffect preview](../../../assets/light/effects/GlowParticlesEffect.gif) - -Soft-glowing particles rendered as a metaball field. Particles move with independent velocities and bounce off the edges; the per-pixel field summation produces chaotic organic blobs — like `MetaballsEffect` with more freedom of movement. - -## Controls - -- `count` (uint8_t, default 5, range 1-8) — number of glow sources -- `speed` (uint8_t, default 60, range 1-255) — movement speed -- `radius` (uint8_t, default 24, range 4-64) — influence radius (larger = more merging) -- `hue_shift` (uint8_t, default 0, range 0-255) — global hue rotation - -Same metaball field as [MetaballsEffect](MetaballsEffect.md), but the sources move freely (12.4 fixed-point, edge-bouncing) instead of orbiting. Fixed particle array, no heap. - -## Tests - -[Unit tests: CheckerboardEffect](../../../tests/unit-tests.md#checkerboardeffect) (GlowParticlesEffect shares the same baseline assertions — non-zero output, spatial variation — alongside other effects). - -## Source - -[GlowParticlesEffect.h](../../../../src/light/effects/GlowParticlesEffect.h) diff --git a/docs/moonmodules/light/effects/LavaLampEffect.md b/docs/moonmodules/light/effects/LavaLampEffect.md deleted file mode 100644 index e481f11d..00000000 --- a/docs/moonmodules/light/effects/LavaLampEffect.md +++ /dev/null @@ -1,23 +0,0 @@ -# Lava Lamp 2D Effect - -![LavaLampEffect controls](../../../assets/light/effects/LavaLampEffect.png) - -![LavaLampEffect preview](../../../assets/light/effects/LavaLampEffect.gif) - -Three slow blobs whose summed field is mapped through a black → red → orange → yellow → white palette. Atmospheric, fluid look — like a real lava lamp rather than the bright HSV of `MetaballsEffect`. - -## Controls - -- `bpm` (uint8_t, default 8, range 1-64) — orbit speed in beats per minute -- `radius` (uint8_t, default 36, range 8-80) — blob influence radius -- `intensity` (uint8_t, default 200, range 64-255) — how strongly the field maps into the palette - -Three orbiting blobs share [MetaballsEffect](MetaballsEffect.md)'s field sum, but `intensity` maps it through a black→red→orange→yellow→white palette (flash table) for the atmospheric look instead of bright HSV. No heap. - -## Tests - -[Unit tests: CheckerboardEffect](../../../tests/unit-tests.md#checkerboardeffect) — LavaLampEffect is included in the shared baseline coverage: non-zero output, spatial variation. - -## Source - -[LavaLampEffect.h](../../../../src/light/effects/LavaLampEffect.h) diff --git a/docs/moonmodules/light/effects/LinesEffect.md b/docs/moonmodules/light/effects/LinesEffect.md deleted file mode 100644 index 42f4cef3..00000000 --- a/docs/moonmodules/light/effects/LinesEffect.md +++ /dev/null @@ -1,22 +0,0 @@ -# LinesEffect - -![LinesEffect controls](../../../assets/light/effects/LinesEffect.png) - -![LinesEffect preview](../../../assets/light/effects/LinesEffect.gif) - -Sweeps one or more axis-aligned planes across the grid in sync at a given BPM. Each plane is a distinct colour: red (YZ, sweeps along X), green (XZ, sweeps along Y), blue (XY, sweeps along Z). Useful for verifying preview axis orientation — each colour names the axis it sweeps. - -Port of MoonLight's Lines effect. - -## Controls - -- **speed** — sweep rate in BPM (1–240). Default 30. -- **axis** — which plane(s) to draw: `all`, `x (red)`, `y (green)`, `z (blue)`. Default `all`. - -## Notes - -On a 1D layout only the red plane is active (width > 1 check). On a 2D layout blue is suppressed (depth = 1). On a 3D layout all three sweep simultaneously. - -## Source - -[LinesEffect.h](../../../../src/light/effects/LinesEffect.h) diff --git a/docs/moonmodules/light/effects/MetaballsEffect.md b/docs/moonmodules/light/effects/MetaballsEffect.md deleted file mode 100644 index c48031ee..00000000 --- a/docs/moonmodules/light/effects/MetaballsEffect.md +++ /dev/null @@ -1,27 +0,0 @@ -# Metaballs 2D Effect - -![MetaballsEffect controls](../../../assets/light/effects/MetaballsEffect.png) - -![MetaballsEffect preview](../../../assets/light/effects/MetaballsEffect.gif) - -Four "blobs" moving on the XY plane via integer sin/cos, with a metaball field summation per pixel. Visually similar to a lava lamp — blobs fluidly merge and separate. - -## Controls - -- `bpm` (uint8_t, default 30, range 1-255) — orbit speed in beats per minute -- `radius` (uint8_t, default 28, range 4-64) — ball influence radius (larger = more merging) -- `hue_shift` (uint8_t, default 0, range 0-255) — rotate the resulting hue - -Four `sin8`-driven balls orbit the XY plane (phase-accumulator, so `bpm` changes don't jump); a metaball field sum per pixel drives both brightness and hue. No floats, no heap. - -## Tests - -[Unit tests: MetaballsEffect](../../../tests/unit-tests.md#metaballseffect) — non-zero output, spatial variation. - -## Prior art - -Classic demoscene effect (1980s). Same integer field-summation technique as countless WLED ports. - -## Source - -[MetaballsEffect.h](../../../../src/light/effects/MetaballsEffect.h) diff --git a/docs/moonmodules/light/effects/NetworkReceiveEffect.md b/docs/moonmodules/light/effects/NetworkReceiveEffect.md deleted file mode 100644 index dec06bd4..00000000 --- a/docs/moonmodules/light/effects/NetworkReceiveEffect.md +++ /dev/null @@ -1,55 +0,0 @@ -# Network Receive Effect - -Receives lights-over-UDP data — **[Art-Net](https://art-net.org.uk/downloads/art-net.pdf), [E1.31 / sACN](https://tsp.esta.org/tsp/documents/docs/ANSI_E1-31-2018.pdf), and [DDP](http://www.3waylabs.com/ddp/), all at once** — and writes it into the layer buffer, behaving like any other effect: composable with modifiers, part of layer blending, selectable through the same UI. The receive side for industry senders (Resolume Arena, Madrix, xLights, LedFx, …) and the end-to-end pair with [NetworkSendDriver](../drivers/NetworkSendDriver.md). - -There is deliberately **no protocol control**: the effect binds the three well-known ports (6454 ArtNet, 5568 E1.31, 4048 DDP) simultaneously and validates each packet against its port's wire format — WLED's multi-port pattern. Whatever a sender speaks just works; the status field shows what is being received (`receiving DDP`, …). - -## Controls - -- `universe_start` (uint16_t, default 0) — first universe to accept (ArtNet/E1.31); a packet for universe `u` lands at byte offset `(u − universe_start) × channels_per_universe`. Universes below the start or beyond the buffer are ignored. E1.31 senders conventionally start at universe 1 — set both ends accordingly (see the sender's universe rule). -- `channels_per_universe` (uint16_t, default 510) — bytes each universe maps to. 510 = whole RGB lights per universe (the xLights/Falcon convention and our own sender's split); set **512** for senders that pack pixels across universe boundaries (Madrix-style). Also clamps each universe's payload to its slot, so a 512-channel frame from a 510-packed source can't bleed its 2 padding bytes into the next universe. - -DDP skips the universe math entirely: its packets carry a byte offset and land directly (clamped to the buffer). - -## ArtNet discovery (Resolume node lists) - -Controllers find output nodes by broadcasting **ArtPoll**; this effect answers with **ArtPollReply** (our IP, MAC, names, bound universe), so the device appears automatically in Resolume's Advanced Output, Madrix and xLights node lists instead of needing manual IP entry. The reply goes unicast to the poller via the platform's `sendToAddr`. - -## Rendering - -Opens and binds the three sockets in `setup()` (a taken port is reported in the status field; the other sockets still drain). `loop()` polls non-blocking at the frame boundary: it drains each socket (bounded per tick, so a packet flood can't wedge the render loop), validates each packet with its protocol's shared parser, and copies payloads into a **staging buffer**; staging is copied to the layer buffer every tick. - -The staging buffer is load-bearing: the Layer clears its buffer at the start of every tick, so writing packets straight into it would strobe black between frames. Staging gives hold-last-frame semantics. Sequence fields (and DDP's push flag) are ignored: out-of-order packets are last-write-wins. - -## Wire contracts - -The byte layouts live in [ArtNetPacket.h](../../../../src/light/ArtNetPacket.h), [E131Packet.h](../../../../src/light/E131Packet.h) and [DdpPacket.h](../../../../src/light/DdpPacket.h), shared with the sender. The receiver is liberal: any ArtNet protocol version, any E1.31 priority/sequence (no multi-source arbitration), any DDP data type. E1.31 **multicast is not joined** (unicast only — platform IGMP support is a backlog item); point sACN senders at the device's IP. - -## Tests - -[Unit tests: NetworkReceiveEffect](../../../tests/unit-tests.md#networkreceiveeffect) — per-protocol build→parse round-trips and reject cases, cross-protocol rejects, universe placement with `channels_per_universe` 510 and 512, DDP byte placement with hostile-offset clamping, ArtPoll/ArtPollReply layout, staging lifecycle, and a localhost round-trip driving all three protocol sockets at once. - -Live tier: `uv run scripts/scenario/run_network_live.py` ([MoonDeck.md § run_network_live](../../../../scripts/MoonDeck.md#run_network_live)) seeds real boards via all three protocols per round. - -## Design notes - -- Receive as an effect (not a separate input mechanism): any external light source is just another MoonModule that writes into a layer buffer. -- Processing is synchronous at the frame boundary — check for pending packets, never block ([architecture.md](../../../architecture.md) network-input rule). - -## Prior art - -### MoonLight — D_NetworkIn ([source](https://github.com/ewowi/MoonLight/blob/main/src/MoonLight/Nodes/Drivers/D_NetworkIn.h)) - -ArtNet/E1.31/DDP receive in one driver node (protocol selected by control; we autodetect by port instead). - -### WLED — realtime UDP input - -Multi-port listening with per-packet header validation, plus ArtPollReply for controller discovery — the pattern this effect follows. - -### projectMM v1 — ArtNetInModule ([source](https://github.com/ewowi/projectMM-v1/blob/54b50bc/src/modules/effects/ArtNetInModule.h)) - -v1 treated ArtNet receive as an effect within a layer, the same architectural choice. - -## Source - -[NetworkReceiveEffect.h](../../../../src/light/effects/NetworkReceiveEffect.h) diff --git a/docs/moonmodules/light/effects/NoiseEffect.md b/docs/moonmodules/light/effects/NoiseEffect.md deleted file mode 100644 index 9bda5f92..00000000 --- a/docs/moonmodules/light/effects/NoiseEffect.md +++ /dev/null @@ -1,40 +0,0 @@ -# Noise Effect - -![NoiseEffect controls](../../../assets/light/effects/NoiseEffect.png) - -![NoiseEffect preview](../../../assets/light/effects/NoiseEffect.gif) - -Smooth animated noise. Samples a 2D field on flat (`depth == 1`) layouts and a true 3D field on volumetric (`depth > 1`) layouts, so a cube renders as a varied volume rather than stacked identical slices. - -## Controls - -- `scale` (slider, default 4, range 1-32) — spatial frequency (higher = finer detail) -- `bpm` (slider, default 60, range 1-255) — animation speed in beats per minute - -## Design notes - -The effect picks the 2D (`depth == 1`) or 3D path per `loop()`. The noise value drives **hue, not brightness** — driving brightness would leave most lights near-black; full brightness keeps the field visible. Time is applied as a coordinate offset into the field (smooth drift, not a per-frame hash reseed), scaled by panel width so a 16-wide and 128-wide panel look equally fast at the same `bpm`; in 3D the z-axis scrolls at 1/5 the x-rate so the field flows rather than slides flat. `scale` defaults low (4) so the pattern reads on small grids; higher suits larger panels. - -## Tests - -[Unit tests: NoiseEffect](../../../tests/unit-tests.md#noiseeffect) — non-zero output, spatial variation, differs from rainbow. - -[Scenario: scenario_MultiplyModifier_pipeline](../../../tests/scenario-tests.md#scenario_multiplymodifier_pipeline) — full pipeline with noise + multiply/mirror, performance bounds. - -## Prior art - -### MoonLight — E_MoonLight.h ([source](https://github.com/ewowi/MoonLight/blob/main/src/MoonLight/Nodes/Effects/E_MoonLight.h)) - -Multiple noise effects (Noise2D, Noise3D variants). Uses FastLED noise functions. Time via `millis()`. - -### projectMM v2 — Noise2DEffect ([source](https://github.com/ewowi/projectMM-v2/blob/main/src/modules/lights/effects/Noise2DEffect.h)) - -Same hash-based value noise as v1. Uses PixelEffectBase spine. - -### projectMM v1 — NoiseEffect2D ([source](https://github.com/ewowi/projectMM-v1/blob/54b50bc/src/modules/effects/NoiseEffect2D.h)) - -Hash-based value noise with trilinear interpolation. Controls: scale (1-32), speed (0-255). Uses `timeMicros()` for animation. v1 ran scale 4 with a 0.1x multiplier (effective 0.4) — projectMM's default of 4 is informed by this. - -## Source - -[NoiseEffect.h](../../../../src/light/effects/NoiseEffect.h) diff --git a/docs/moonmodules/light/effects/ParticlesEffect.md b/docs/moonmodules/light/effects/ParticlesEffect.md deleted file mode 100644 index 13efe0da..00000000 --- a/docs/moonmodules/light/effects/ParticlesEffect.md +++ /dev/null @@ -1,47 +0,0 @@ -# Particles 2D Effect - -![ParticlesEffect controls](../../../assets/light/effects/ParticlesEffect.png) - -![ParticlesEffect preview](../../../assets/light/effects/ParticlesEffect.gif) - -A swarm of particles drifting on the XY plane with persistent trails. Each particle has fixed-point position, velocity, and hue. A private RGB trail buffer is faded each frame, particles are drawn on top, and the trail buffer is copied to the layer buffer (which the Layer clears every frame). - -## Controls - -- `count` (uint8_t, default 32, range 1-64) — number of active particles -- `speed` (uint8_t, default 80, range 1-255) — velocity multiplier -- `fade` (uint8_t, default 240, range 200-255) — trail persistence (255 = no fade, 200 = quick fade) -- `hue_shift` (uint8_t, default 0, range 0-255) — rotate all particle hues - -## Rendering - -Per frame: - -1. **Fade** every byte in the trail buffer via `scale8(byte, fade)` (integer multiply, no float). -2. **Update + draw** — for each active particle: advance position using 12.4 fixed-point math, bounce off edges, draw RGB into the trail buffer. -3. **Copy** the trail buffer into the layer buffer. - -Maximum particles is `MAX_PARTICLES = 64` (a compile-time constant). Particle state is a fixed array — no heap allocation for the particle list itself. - -## Memory - -Allocates `width * height * channelsPerLight` bytes for the persistent trail buffer in `onBuildState()` when `enabled` is true. Freed in `teardown()` and when disabled. - -| Logical size | Trail buffer (RGB) | -|--------------|--------------------| -| 64x64 | 12 KB | -| 128x128 | 48 KB | - -Particle list (`64 * 8` bytes) is part of `sizeof(ParticlesEffect)`, not `dynamicBytes()`. `dynamicBytes()` reports only the trail buffer. - -## Tests - -[Unit tests: ParticlesEffect](../../../tests/unit-tests.md#particleseffect) — buffer becomes non-zero after one frame (particles draw immediately). - -## Prior art - -Classic "snow"/"stars"/"fireflies" effect from many LED firmwares. The fade-and-draw approach (a.k.a. *afterimage*) matches FastLED's `fadeToBlackBy` idiom. - -## Source - -[ParticlesEffect.h](../../../../src/light/effects/ParticlesEffect.h) diff --git a/docs/moonmodules/light/effects/PlasmaEffect.md b/docs/moonmodules/light/effects/PlasmaEffect.md deleted file mode 100644 index 3a8e832e..00000000 --- a/docs/moonmodules/light/effects/PlasmaEffect.md +++ /dev/null @@ -1,32 +0,0 @@ -# Plasma Effect - -![PlasmaEffect controls](../../../assets/light/effects/PlasmaEffect.png) - -![PlasmaEffect preview](../../../assets/light/effects/PlasmaEffect.gif) - -Animated plasma pattern from summed sine waves on orthogonal and diagonal axes. Default effect in the desktop and ESP32 pipeline. 2D on flat (`depth == 1`) layouts, 3D on volumetric (`depth > 1`) layouts so a cube renders as a varied volume. - -## Controls - -- `bpm` (uint8_t, default 30, range 1-255) — animation speed in beats per minute -- `scale_x` (uint8_t, default 16, range 1-64) — horizontal wave length in grid cells (`step = 256 / scale_x`) -- `scale_y` (uint8_t, default 16, range 1-64) — vertical wave length in grid cells -- `hue_shift` (uint8_t, default 0, range 0-255) — rotates the entire color wheel - -## Design notes - -Sums orthogonal + diagonal `sin8` waves (256-byte LUT, no float, no heap), adding a fifth depth sine on `depth > 1`. `hue_shift` rotates the result before `hsvToRgb`. A phase accumulator (matching NoiseEffect) means a `bpm` change doesn't jump the animation. The default effect in both pipelines, paired with MultiplyModifier (see `src/main.cpp`). - -## Tests - -[Unit tests: PlasmaEffect](../../../tests/unit-tests.md#plasmaeffect) — non-zero output, spatial variation, differs from NoiseEffect. - -Default pipeline uses Plasma + MultiplyModifier (see `src/main.cpp`). - -## Prior art - -Classic demoscene plasma effect (sum of sines). Integer sin8 LUT approach matches FastLED-style tables. No direct v1/v2 module port — simpler than NoiseEffect (no hash/bilinear). - -## Source - -[PlasmaEffect.h](../../../../src/light/effects/PlasmaEffect.h) diff --git a/docs/moonmodules/light/effects/PlasmaPaletteEffect.md b/docs/moonmodules/light/effects/PlasmaPaletteEffect.md deleted file mode 100644 index 8dad1602..00000000 --- a/docs/moonmodules/light/effects/PlasmaPaletteEffect.md +++ /dev/null @@ -1,21 +0,0 @@ -# Plasma Palette 2D Effect - -![PlasmaPaletteEffect controls](../../../assets/light/effects/PlasmaPaletteEffect.png) - -![PlasmaPaletteEffect preview](../../../assets/light/effects/PlasmaPaletteEffect.gif) - -Same four-sine plasma field as `PlasmaEffect`, but colours come from a 256-entry fire-ocean RGB palette in flash instead of `hsvToRgb`. - -## Controls - -- `bpm` (uint8_t, default 30, range 1-255) -- `scale_x` (uint8_t, default 16, range 1-64) -- `scale_y` (uint8_t, default 16, range 1-64) - -## Tests - -[Unit tests: CheckerboardEffect](../../../tests/unit-tests.md#checkerboardeffect) (PlasmaPaletteEffect is one of the stateless effects covered) — non-zero output, spatial variation. - -## Source - -[PlasmaPaletteEffect.h](../../../../src/light/effects/PlasmaPaletteEffect.h) diff --git a/docs/moonmodules/light/effects/RainbowEffect.md b/docs/moonmodules/light/effects/RainbowEffect.md deleted file mode 100644 index 82290ce7..00000000 --- a/docs/moonmodules/light/effects/RainbowEffect.md +++ /dev/null @@ -1,26 +0,0 @@ -# Rainbow 2D Effect - -![RainbowEffect controls](../../../assets/light/effects/RainbowEffect.png) - -![RainbowEffect preview](../../../assets/light/effects/RainbowEffect.gif) - -Diagonal rainbow pattern across a 2D grid, animated over time. Good default/test effect — always produces visible, colorful output. - -## Controls - -- `speed` (uint8_t, default 60, range 1-255) — animation speed in BPM (beats per minute). 60 = 1 full cycle per second. - -## Tests - -[Unit tests: RainbowEffect](../../../tests/unit-tests.md#rainboweffect) — non-zero output, valid RGB, spatial variation. - -[Scenario: scenario_Layer_base_pipeline](../../../tests/scenario-tests.md#scenario_layer_base_pipeline) — full pipeline with rainbow effect, performance bounds. - -## Design notes - -- Test effect. Dead simple — proves the pipeline works. -- No palette, no variants. Rainbow is visually recognizable, which makes it easy to spot in tests. - -## Source - -[RainbowEffect.h](../../../../src/light/effects/RainbowEffect.h) diff --git a/docs/moonmodules/light/effects/RingsEffect.md b/docs/moonmodules/light/effects/RingsEffect.md deleted file mode 100644 index c2dd6c50..00000000 --- a/docs/moonmodules/light/effects/RingsEffect.md +++ /dev/null @@ -1,26 +0,0 @@ -# Rings 2D Effect - -![RingsEffect controls](../../../assets/light/effects/RingsEffect.png) - -![RingsEffect preview](../../../assets/light/effects/RingsEffect.gif) - -Expanding concentric rings from random centre points. Each ring grows outward and respawns once it has expanded past the visible area. Multiple rings overlap with additive blending. - -(This concentric-rings effect is "Rings"; the name "Ripples" belongs to the MoonLight sine-wave water-surface effect.) - -## Controls - -- `count` (uint8_t, default 4, range 1-8) — number of simultaneously active rings -- `speed` (uint8_t, default 60, range 1-255) — expansion rate -- `thickness` (uint8_t, default 3, range 1-16) — ring thickness in pixels -- `hue_shift` (uint8_t, default 0, range 0-255) — global hue rotation - -An age-based fade makes old, wide rings disappear softly. Per-ring state (position + radius + hue) lives in a fixed array — no heap. - -## Tests - -[Unit tests: CheckerboardEffect](../../../tests/unit-tests.md#checkerboardeffect) — shared rendering/smoke coverage: non-zero output, spatial variation. (RingsEffect carries per-ring mutable state — position, radius, hue — with random respawn; that behaviour isn't unit-tested today.) - -## Source - -[RingsEffect.h](../../../../src/light/effects/RingsEffect.h) diff --git a/docs/moonmodules/light/effects/RipplesEffect.md b/docs/moonmodules/light/effects/RipplesEffect.md deleted file mode 100644 index 5e051c93..00000000 --- a/docs/moonmodules/light/effects/RipplesEffect.md +++ /dev/null @@ -1,28 +0,0 @@ -# Ripples 3D Effect - -![RipplesEffect controls](../../../assets/light/effects/RipplesEffect.png) - -![RipplesEffect preview](../../../assets/light/effects/RipplesEffect.gif) - -3D dancing sine-wave ripples — a reimplementation of MoonLight's Ripples. For each `(x, z)` column on the floor plane, the distance from the centre sets a wave phase, and one pixel per column is lit at the height `y = floor(h/2 · (1 + sin(dist / interval + time)))`. The lit surface ripples like water filling the volume, with the hue cycling over time and position. - -Genuinely 3D (`Dim::D3`): it writes a height across the y-axis. On a flat 2D layout (depth 1) it degenerates to a single rippling y-row, which is honest for a flat grid. - -## Controls - -- `speed` (uint8_t, default 50, range 0-99) — animation speed; 0 = frozen, 99 = fast -- `interval` (uint8_t, default 128, range 1-254) — wavefront spacing; low = tight rings, high = wide - -## Prior art - -Ported from [MoonLight](https://github.com/ewowi/MoonLight)'s Ripples (via projectMM-v1), studied and rewritten against this project's `EffectBase` — we read the approach and implemented our own, reusing `core/color.h`'s `hsvToRgb` rather than MoonLight's inlined HSV. The wavefront math (distance → phase → sine height, the `1.3·(255−interval)/128·√h` spacing and `millis/(100−speed)/6.4` time base) follows MoonLight's so the look matches. - -Float trig (`sinf`/`sqrtf`) in the loop is consistent with the existing wave effects (Plasma, LavaLamp); the hot-path integer-math preference is for per-light colour work, not the handful of transcendental ops a wavefront needs. - -## Tests - -[Unit tests: CheckerboardEffect](../../../tests/unit-tests.md#checkerboardeffect) — shared rendering/smoke coverage: non-zero output, spatial variation, plus a 0×0×0 grid robustness check. - -## Source - -[RipplesEffect.h](../../../../src/light/effects/RipplesEffect.h) diff --git a/docs/moonmodules/light/effects/SineEffect.md b/docs/moonmodules/light/effects/SineEffect.md deleted file mode 100644 index df37a634..00000000 --- a/docs/moonmodules/light/effects/SineEffect.md +++ /dev/null @@ -1,21 +0,0 @@ -# SineEffect - -A 3D colour sine field: the red, green, and blue channels each follow a sine wave along one axis (x, y, z) with a 120° phase offset between channels, so the box glows through shifting colours that scroll over time. Every axis drives a channel, so it is a true 3D effect; on a 2D grid the z term is constant ([Layer](../Layer.md) extrudes a lower-dimensional effect across the unused axis). - -## Controls - -- `frequency` — spatial frequency, how many wave cycles span the box (1–20, default 1). -- `amplitude` — peak brightness, DMX-aligned (0–255, default 255 = full). -- `bpm` — scroll speed of the wave over time (1–255, default 30). - -## Rendering - -For a light at (x, y, z) the channel value is `sin8(coord·frequency + t + phase) · amplitude / 255`, where `t` is the time phase and `phase` is 0 / 85 / 170 (the 0° / 120° / 240° channel offsets in `uint8_t` angle units, 256 = full turn). All integer: angles are bytes and the project's [`sin8`](../../core/Control.md) LUT replaces `sinf`, so there is no per-light float. - -## Prior art - -- **projectMM v1 / v2 — SineEffect** — same 3D sine algorithm. Those used float `sinf` and published a normalized brightness via a KvStore for inter-module communication; this version is integer-only (`sin8`) and carries no KvStore. - -## Source - -[SineEffect.h](../../../../src/light/effects/SineEffect.h) diff --git a/docs/moonmodules/light/effects/SpiralEffect.md b/docs/moonmodules/light/effects/SpiralEffect.md deleted file mode 100644 index 65efb77c..00000000 --- a/docs/moonmodules/light/effects/SpiralEffect.md +++ /dev/null @@ -1,21 +0,0 @@ -# Spiral 2D Effect - -![SpiralEffect controls](../../../assets/light/effects/SpiralEffect.png) - -![SpiralEffect preview](../../../assets/light/effects/SpiralEffect.gif) - -Rotating spiral from angle + distance. Uses shared `atan2_8` and `dist8` in `core/color.h`. - -## Controls - -- `bpm` (uint8_t, default 40, range 1-255) — rotation speed -- `twist` (uint8_t, default 4, range 1-16) — tightness of spiral arms -- `hue_shift` (uint8_t, default 0, range 0-255) — colour offset - -## Tests - -[Unit tests: CheckerboardEffect](../../../tests/unit-tests.md#checkerboardeffect) (SpiralEffect is one of the stateless effects covered) — non-zero output, spatial variation. - -## Source - -[SpiralEffect.h](../../../../src/light/effects/SpiralEffect.h) diff --git a/docs/moonmodules/light/effects/WaveEffect.md b/docs/moonmodules/light/effects/WaveEffect.md deleted file mode 100644 index 60d72f1f..00000000 --- a/docs/moonmodules/light/effects/WaveEffect.md +++ /dev/null @@ -1,31 +0,0 @@ -# WaveEffect - -An animated **waveform that scrolls across the grid** — the classic oscilloscope look. Each column plots one point of a moving wave; as the wave's phase advances with time and is delayed per column, the lit points trace a curve that travels sideways, leaving a fading trail. Six waveform shapes are selectable. - -## Controls - -- `bpm` — travel speed (how fast the wave's phase advances), 0–255. -- `fade` — trail length: how much the previous frame is kept each tick (0 = the wave leaves no tail, 255 = a long persistent trail). Applied as `scale8(trail, fade)` over an own z=0-plane trail buffer (sized off the hot path, like [ParticlesEffect](ParticlesEffect.md)). -- `type` — the waveform shape (a [Select](../../core/Control.md)): `Sawtooth`, `Triangle`, `Sine`, `Square`, `Sin3` (three summed sines — a richer rolling wave), `Noise` (1-D value noise — a jittered band). The shape maps a phase to the wave's y-position each column. - -It is a [D2 effect](../../core/architecture.md) — it writes the z=0 plane and `Layer::extrude` duplicates it across z on a 3D layout. Runs at every grid size (a 0-height or sub-3-channel grid is a no-op, never an out-of-bounds read). - -## Orientation (which axis is which) - -This is a **D2** effect: the waveform sets a **y-position per column** (its shape lives on the **height** axis) and the per-column phase delay scrolls it along **width**. So height is the wave's amplitude axis — a grid needs `height > 1` to show any waveform; on a 1-tall grid (`height == 1`) every point collapses to y=0 and only the colour shows, no wave. - -This follows the project's [1D-runs-along-Y convention](../../architecture.md#dimensionality): **to drive a one-dimensional output** (a single strip, or a row of [Hue lights](../drivers/HueDriver.md)) **lay it out as `1 × N` (width 1, height N), not `N × 1`** — the lights map onto the height axis where the wave is drawn. An `N × 1` layout plots a flat line. - -## How the travel works - -Per column `x`, the wave's phase is `t + x·skew`: `t` advances from `bpm` (an integer accumulator, so a sub-millisecond frame time isn't lost), and the `x·skew` term delays each column so the shape appears to move horizontally. The phase runs through the selected waveform to a y in `[0, height)`; that pixel is lit, and for the discontinuous shapes (sawtooth, square) a vertical segment joins it to the previous column so the line stays connected. The wave's colour cycles slowly over time. - -The colour comes from a single `waveColor(index)` seam — an `hsvToRgb` hue sweep — so the wave's colouring lives in one place. - -## Prior art - -[MoonLight](https://github.com/MoonModules/MoonLight)'s Wave effect (Ewoud Wijma). The *behaviour* is reproduced — the six waveform types, the per-column phase travel, the time-varying colour, the frame fade — written fresh against projectMM's `EffectBase` and integer primitives (the `sin8` LUT, `scale8`); the colour is an `hsvToRgb` sweep through the `waveColor` seam. - -## Source - -[WaveEffect.h](../../../../src/light/effects/WaveEffect.h) diff --git a/docs/moonmodules/light/effects/effects.md b/docs/moonmodules/light/effects/effects.md new file mode 100644 index 00000000..e1deb168 --- /dev/null +++ b/docs/moonmodules/light/effects/effects.md @@ -0,0 +1,64 @@ +# Effects + +Every effect, one compact row each. An effect writes per-pixel colour into its [Layer](../Layer.md)'s buffer each tick; [modifiers](../modifiers/modifiers.md) reshape the result and a [driver](../drivers/) sends it out. Effects that name an index colour read the global palette (the `palette` control on [Drivers](../Drivers.md)) via `colorFromPalette`. + +Columns: **Name** (with its `tags()` emoji — see the [tag emoji legend](../../../architecture.md#tag-emoji-legend)), **Preview**, **Dim** (native axes; [Layer](../Layer.md) extrudes a lower-dim effect onto a bigger grid), **Description**, **Controls**, **Tests**. Origin is grouped into sections; the per-row tags carry the full (often blended) lineage and creator credit. The per-library file split is future work — see the [folder-structure decision](../../../backlog/folder-structure-proposal.md). + +## MoonLight effects + +| Name | Preview | Dim | Description | Controls | Tests | +|---|---|---|---|---|---| +| **Rainbow** 💫 | | 2D | Diagonal animated rainbow — always-visible default/test effect. | `speed` | [tests](../../../tests/unit-tests.md#rainboweffect) | +| **Plasma** 💫🦅 | | 2D/3D | Summed sine waves on orthogonal + diagonal axes; large rolling blobs (3D on volumetric layouts). | `bpm`, `scale_x`, `scale_y`, `hue_shift` | [tests](../../../tests/unit-tests.md#plasmaeffect) | +| **Spiral** 💫🦅 | | 2D | Rotating spiral from angle + distance (`atan2_8`/`dist8`). | `bpm`, `twist`, `hue_shift` | [tests](../../../tests/unit-tests.md#spiraleffect) | +| **DistortionWaves** 💫 | — | 2D | Two interfering sine waves beat against each other into a moiré colour field. | `freq_x`, `freq_y`, `speed` | [tests](../../../tests/unit-tests.md#distortionwaveseffect) | +| **Metaballs** 💫🦅 | | 2D | `count` blobs orbit via integer sin/cos; metaball field per pixel — bright HSV merge/split. | `bpm`, `radius`, `count`, `hue_shift` | [tests](../../../tests/unit-tests.md#metaballseffect) | +| **LavaLamp** 💫🦅 | | 2D | Three slow blobs through a black→red→orange→yellow→white ramp — atmospheric lava look. | `bpm`, `radius`, `intensity` | [tests](../../../tests/unit-tests.md#spiraleffect) | +| **Particles** 💫🦅 | | 2D | A swarm of drifting particles with persistent fading trails. | `count`, `speed`, `fade`, `hue_shift` | [tests](../../../tests/unit-tests.md#particleseffect) | +| **Rings** 💫🦅 | | 2D | Expanding concentric rings from random centres, additive overlap (calm defaults). | `count`, `speed`, `thickness`, `hue_shift` | [tests](../../../tests/unit-tests.md#spiraleffect) | +| **Ripples** 💫🟦🦅 | | 3D | Distance-from-centre sets a per-column wave phase; the lit surface ripples like water. | `speed`, `interval` | [tests](../../../tests/unit-tests.md#spiraleffect) | +| **Lines** 💫 | | — | Sweeps axis-aligned planes in sync; red/green/blue name the X/Y/Z axis — a preview-orientation test pattern. | `speed`, `axis` | — | + +## WLED effects + +| Name | Preview | Dim | Description | Controls | Tests | +|---|---|---|---|---|---| +| **Wave** 🌊 | — | 2D | An oscilloscope waveform scrolls across the grid with a fading trail; six selectable shapes. | `bpm`, `fade`, `type` | [tests](../../../tests/unit-tests.md#waveeffect) | + +## FastLED effects + +| Name | Preview | Dim | Description | Controls | Tests | +|---|---|---|---|---|---| +| **Fire** ⚡️🦅 | | 2D | Fire2012-style heat field — sparks at the base rise and cool through a black→red→yellow→white ramp; spark count scales with width. | `cooling`, `sparking`, `hue_shift` | [tests](../../../tests/unit-tests.md#fireeffect) | +| **Noise** ⚡️ | | 2D/3D | Smooth animated value noise; true 3D field on volumetric layouts. | `scale`, `bpm` | [tests](../../../tests/unit-tests.md#noiseeffect) | + +## projectMM-native effects + +| Name | Preview | Dim | Description | Controls | Tests | +|---|---|---|---|---|---| +| **Sine** 🌀 | — | 3D | R/G/B each follow a sine along one axis at 120° phase offset — a glowing, scrolling colour box. | `frequency`, `amplitude`, `bpm` | [tests](../../../tests/unit-tests.md#sineeffect) | +| **AudioVolume** 🔊 | — | — | A whole-grid VU meter: every light pulses with the mic level, colour indexing the palette by loudness. | `brightness` | [tests](../../../tests/unit-tests.md#audiomodule) | +| **AudioSpectrum** 📊 | — | — | The 16 mic frequency bands spread across X, each column lit bottom-up by its magnitude. | `colorMode` | [tests](../../../tests/unit-tests.md#audiomodule) | +| **NetworkReceive** 📡🌙 | — | — | Receives lights-over-UDP (Art-Net, E1.31/sACN, DDP) and writes it into the layer — the receive side for Resolume/Madrix/xLights/LedFx. See the wire contract below. | `universe_start`, `channels_per_universe` | [tests](../../../tests/unit-tests.md#networkreceiveeffect) | + +**NetworkReceive wire contract:** listens for [Art-Net](https://art-net.org.uk/downloads/art-net.pdf), [E1.31 / sACN](https://tsp.esta.org/tsp/documents/docs/ANSI_E1-31-2018.pdf), and [DDP](http://www.3waylabs.com/ddp/) simultaneously; `universe_start` + `channels_per_universe` map incoming universes onto the layer buffer. The end-to-end pair with [NetworkSendDriver](../drivers/NetworkSendDriver.md). + +## Source + +- [AudioSpectrumEffect.h](../../../../src/light/effects/AudioSpectrumEffect.h) +- [AudioVolumeEffect.h](../../../../src/light/effects/AudioVolumeEffect.h) +- [DistortionWavesEffect.h](../../../../src/light/effects/DistortionWavesEffect.h) +- [FireEffect.h](../../../../src/light/effects/FireEffect.h) +- [LavaLampEffect.h](../../../../src/light/effects/LavaLampEffect.h) +- [LinesEffect.h](../../../../src/light/effects/LinesEffect.h) +- [MetaballsEffect.h](../../../../src/light/effects/MetaballsEffect.h) +- [NetworkReceiveEffect.h](../../../../src/light/effects/NetworkReceiveEffect.h) +- [NoiseEffect.h](../../../../src/light/effects/NoiseEffect.h) +- [ParticlesEffect.h](../../../../src/light/effects/ParticlesEffect.h) +- [PlasmaEffect.h](../../../../src/light/effects/PlasmaEffect.h) +- [RainbowEffect.h](../../../../src/light/effects/RainbowEffect.h) +- [RingsEffect.h](../../../../src/light/effects/RingsEffect.h) +- [RipplesEffect.h](../../../../src/light/effects/RipplesEffect.h) +- [SineEffect.h](../../../../src/light/effects/SineEffect.h) +- [SpiralEffect.h](../../../../src/light/effects/SpiralEffect.h) +- [WaveEffect.h](../../../../src/light/effects/WaveEffect.h) diff --git a/docs/moonmodules/light/layouts/GridLayout.md b/docs/moonmodules/light/layouts/GridLayout.md deleted file mode 100644 index f7780cf7..00000000 --- a/docs/moonmodules/light/layouts/GridLayout.md +++ /dev/null @@ -1,31 +0,0 @@ -# Grid Layout - -![GridLayout controls](../../../assets/light/layouts/GridLayout.png) - -Arranges lights in a 3D grid, row-major (x fastest, then y, then z). Full-density — every position maps to a light. Controls: `width`, `height`, `depth`, `serpentine`. - -## Mapping - -A plain grid (`serpentine` off) emits driver index `i` at box cell `i`, so the Layer takes the **1:1 unshuffled memcpy fast path** — the mapping isn't *declared* identity, it's *measured*: the Layer walks the coords once and only skips the mapping table when the order is natural. `serpentine` wires odd rows in reverse (boustrophedon — the strip snakes back and forth), so driver index `i` no longer equals box cell `i`: the grid is dense but **shuffled**, which routes it through the box→driver mapping LUT exactly as a sparse layout does. A handy lever for exercising both the identity and non-identity mapping paths from one layout. The Layer buffer and driver buffer are separate when memory allows (for parallelism), shared when memory is tight. `defaultGridSize` (16) is owned here and also read by the composition roots to size the boot grid. - -## Tests - -[Unit tests: GridLayout](../../../tests/unit-tests.md#gridlayout) — row-major coordinate iteration, 3D grids, Layouts multi-layout offset. - -## Prior art - -### MoonLight — L_MoonLight.h Panel ([source](https://github.com/ewowi/MoonLight/blob/main/src/MoonLight/Nodes/Layouts/L_MoonLight.h)) - -Panel layout with serpentine, multiple panel arrangements. Uses `addLight()` to define each position. - -### projectMM v1 — GridLayout ([source](https://github.com/ewowi/projectMM-v1/blob/54b50bc/src/modules/layouts/GridLayout.h)) - -Width/height/depth/serpentine controls. Mapping rebuilt in onUpdate(), parent notified via onChildrenReady(). - -### projectMM v2 — GridLayoutModule ([source](https://github.com/ewowi/projectMM-v2/blob/main/src/modules/lights/GridLayoutModule.h)) - -Same controls. Uses LayoutModule base class. - -## Source - -[GridLayout.h](../../../../src/light/layouts/GridLayout.h) diff --git a/docs/moonmodules/light/layouts/SphereLayout.md b/docs/moonmodules/light/layouts/SphereLayout.md deleted file mode 100644 index 87ef07e6..00000000 --- a/docs/moonmodules/light/layouts/SphereLayout.md +++ /dev/null @@ -1,27 +0,0 @@ -# Sphere Layout - -Arranges lights on the **surface of a hollow sphere** — a one-light-thick shell, no interior lights. Lattice layout: every light sits at an integer `(x, y, z)` inside a `(2·radius+1)³` bounding box centred at `(radius, radius, radius)`. - -## Controls - -- `radius` (default 4, range 1–64) — surface radius in light-units. A lattice point is on the shell when its distance from the centre rounds to `radius` (it falls in the half-open band `[radius−0.5, radius+0.5)`). `radius = 1` is the smallest hollow sphere — 18 lights: the 6 axis-neighbours (d²=1) plus the 12 edge-neighbours (d²=2) of the centre, all of which round to distance 1. - -## Light count and mapping - -Light count is derived from `radius` (not set directly) — the lattice points landing in the shell band, growing roughly with surface area (`~4π·radius²`). The iterator and `lightCount()` share one shell predicate, so the count always matches the emitted points. Distances compare in squared integer space (no `sqrt`, no per-light float), so the shell is exact and deterministic across platforms. - -A sphere is **not** 1:1 unshuffled — the shell points are sparse within the bounding box, so it supplies explicit coordinates via `forEachCoord` like every non-grid layout; Layer/Drivers wiring treats it identically to any other `LayoutBase`. - -## Tests - -[Unit tests: SphereLayout](../../../tests/unit-tests.md#spherelayout) — shell-only (no interior/centre point), symmetry, count matches the iterator, radius-1 base case. Add / replace / remove / multiple layouts are covered in [Layouts](../../../tests/unit-tests.md#layouts) and the layout-mutation scenario. - -## Prior art - -### MoonLight / projectMM v1–v2 — layout nodes ([MoonLight L_MoonLight.h](https://github.com/ewowi/MoonLight/blob/main/src/MoonLight/Nodes/Layouts/L_MoonLight.h)) - -Prior projects expose layouts that call an `addLight(x, y, z)` per position; SphereLayout follows the same "a layout enumerates its light coordinates" shape, computing the shell analytically rather than from a stored list. - -## Source - -[SphereLayout.h](../../../../src/light/layouts/SphereLayout.h) diff --git a/docs/moonmodules/light/layouts/WheelLayout.md b/docs/moonmodules/light/layouts/WheelLayout.md deleted file mode 100644 index 7b0db846..00000000 --- a/docs/moonmodules/light/layouts/WheelLayout.md +++ /dev/null @@ -1,23 +0,0 @@ -# WheelLayout - -A bicycle-wheel arrangement: a number of straight spokes radiate from a centre hub, each carrying a row of LEDs spaced one unit apart from the centre outward. Spoke *k* points at angle *k / spokes* of a full turn; the LEDs along it sit at increasing radius. - -## Controls - -- `spokes` — number of spokes (2–64, default 8). -- `ledsPerSpoke` — LEDs along each spoke (1–256, default 10). - -`lightCount()` = `spokes × ledsPerSpoke`. - -## Coordinate iterator - -`forEachCoord` emits `(index, x, y, 0)` for each LED, walking spoke by spoke. A spoke's angle is `spoke · 256 / spokes` in `uint8_t` turn units; the LED at radius *r* sits at `(maxR + r·cos, maxR + r·sin)`, where cos/sin come from the project's [`cos8`/`sin8`](../../core/Control.md) integer LUT (signed component `val − 128`, divided back by 128). The whole wheel is shifted by `+ledsPerSpoke` so every coordinate is ≥ 0 within a `(2·ledsPerSpoke)`-wide bounding box. Integer-only (same discipline as [SphereLayout](SphereLayout.md)) — no `double` cos/sin/round. - -## Prior art - -- **MoonLight — ring/spoke layouts** (L_MoonLight.h): Ring, Rings241, and other radial layouts. -- **projectMM v2 — WheelLayoutModule** — spoke-based coordinate generation; that used `double` trig, this is the integer-LUT equivalent. - -## Source - -[WheelLayout.h](../../../../src/light/layouts/WheelLayout.h) diff --git a/docs/moonmodules/light/layouts/layouts.md b/docs/moonmodules/light/layouts/layouts.md new file mode 100644 index 00000000..71ccc2c1 --- /dev/null +++ b/docs/moonmodules/light/layouts/layouts.md @@ -0,0 +1,21 @@ +# Layouts + +Every layout, one compact row each. A layout maps light indices to physical `(x, y, z)` positions — it defines the *shape* an [effect](../effects/effects.md) draws onto and a [driver](../drivers/) sends out. The [Layouts](../Layouts.md) container holds one or more layout children and composes them into one coordinate space; a [Layer](../Layer.md) renders over that combined space. + +Columns: **Name** (with its `tags()` emoji — see the [tag emoji legend](../../../architecture.md#tag-emoji-legend)), **Preview**, **Description**, **Controls**, **Tests**. The per-library file split is future work — see the [folder-structure decision](../../../backlog/folder-structure-proposal.md). Preview gifs land with the [MoonLight migration](../../../history/plans/Plan-20260630%20-%20MoonLight%20migration%20(multi-stage).md) (MoonLight documents matching layout nodes — Panel ≈ Grid, Wheel — at ; Sphere is projectMM-native). + +## projectMM-native layouts + +| Name | Preview | Description | Controls | Tests | +|---|---|---|---|---| +| **Grid** | — | A dense 3D grid, row-major (x fastest, then y, then z); every position maps to a light. `serpentine` boustrophedon-wires alternate rows. | `width`, `height`, `depth`, `serpentine` | [tests](../../../tests/unit-tests.md#gridlayout) | +| **Sphere** | — | Lights on the surface of a hollow sphere — a one-light-thick shell inside a `(2·radius+1)³` box, no interior lights. | `radius` | [tests](../../../tests/unit-tests.md#spherelayout) | +| **Wheel** | — | A bicycle-wheel: `spokes` straight rows radiate from a centre hub, each carrying `ledsPerSpoke` LEDs spaced one unit apart outward. | `spokes`, `ledsPerSpoke` | [tests](../../../tests/unit-tests.md#wheellayout) | + +The [Layouts](../Layouts.md) container itself takes no controls — see its page for coordinate iteration, reordering, and rebuild propagation. + +## Source + +- [GridLayout.h](../../../../src/light/layouts/GridLayout.h) +- [SphereLayout.h](../../../../src/light/layouts/SphereLayout.h) +- [WheelLayout.h](../../../../src/light/layouts/WheelLayout.h) diff --git a/docs/moonmodules/light/modifiers/CheckerboardModifier.md b/docs/moonmodules/light/modifiers/CheckerboardModifier.md deleted file mode 100644 index b2f4cfa4..00000000 --- a/docs/moonmodules/light/modifiers/CheckerboardModifier.md +++ /dev/null @@ -1,38 +0,0 @@ -# Checkerboard Modifier - -![CheckerboardModifier controls](../../../assets/light/modifiers/CheckerboardModifier.png) - -![CheckerboardModifier preview](../../../assets/light/modifiers/CheckerboardModifier.gif) - -Static modifier. Masks the layer in a checkerboard pattern: lights in the "off" squares are dropped (they receive nothing), lights in the "on" squares pass through unchanged. Unlike Multiply, this doesn't remap or resize — it's a spatial on/off mask applied to whatever the effect drew. - -## Controls - -- `size` (Uint8, 1–64, default 2) — checker square edge, in lights -- `invert` (Bool, default false) — flip which squares pass through - -## Effect on the pipeline - -- **Logical box unchanged** — a mask doesn't resize the box (no `modifyLogicalSize`); only which cells contribute changes. -- **Pass or drop** — `modifyLogical` returns `true` to pass a light through unchanged, or `false` to drop it (an "off" square), so a dropped physical light has no logical source and stays dark. -- **Square parity**: a light at `(x,y,z)` belongs to square `(x/size, y/size, z/size)`; the square is "on" when the sum of those indices is even (flipped by `invert`). - -## Cross-domain wiring - -A Layer folds all its enabled modifiers as a chain (Checkerboard-then-Multiply differs from Multiply-then-Checkerboard). The fold + reject contract is in [ModifierBase](../ModifierBase.md). - -## Tests - -[Unit tests: CheckerboardModifier](../../../tests/unit-tests.md#checkerboardmodifier) — identity dimensions, the drop pattern for both `invert` phases, `size` grouping into squares. - -[Scenario: scenario_modifier_swap](../../../tests/scenario-tests.md#scenario_modifier_swap) — replaces the Layer's modifier between Multiply and Checkerboard and verifies the pipeline stays live across each swap. - -## Prior art - -### MoonLight — M_MoonLight.h Checkerboard ([source](https://github.com/ewowi/MoonLight/blob/main/src/MoonLight/Nodes/Modifiers/M_MoonLight.h)) - -MoonLight's Checkerboard drops lights by setting `position.x = UINT16_MAX` (a sentinel the layout pass skips), with `size`, `invert`, and a `group` flag. We express the drop as `modifyLogical` returning `false` (no sentinel needed) and start with `size` + `invert`; `group` is deferred. - -## Source - -[CheckerboardModifier.h](../../../../src/light/modifiers/CheckerboardModifier.h) diff --git a/docs/moonmodules/light/modifiers/MultiplyModifier.md b/docs/moonmodules/light/modifiers/MultiplyModifier.md deleted file mode 100644 index dc003d0e..00000000 --- a/docs/moonmodules/light/modifiers/MultiplyModifier.md +++ /dev/null @@ -1,45 +0,0 @@ -# Multiply Modifier - -![MultiplyModifier controls](../../../assets/light/modifiers/MultiplyModifier.png) - -![MultiplyModifier preview](../../../assets/light/modifiers/MultiplyModifier.gif) - -Static modifier. Tiles the logical image across the physical box `multiply` times per axis, optionally reflecting alternate tiles. With a multiplier of 2 and mirror enabled on an axis, that axis folds in half — the classic kaleidoscope mirror. Multiply subsumes the old MirrorModifier: a pure mirror is `multiply = 2, mirror = true` on the chosen axes. - -## Controls - -- `multiplyX` (Uint8, 1–64, default 2) — tiles along X (1 = no tiling) -- `multiplyY` (Uint8, 1–64, default 2) — tiles along Y -- `multiplyZ` (Uint8, 1–64, default 1) — tiles along Z -- `mirrorX` (Bool, default true) — reflect alternate (odd) tiles along X -- `mirrorY` (Bool, default true) — reflect alternate tiles along Y -- `mirrorZ` (Bool, default true) — reflect alternate tiles along Z - -The defaults (`multiply 2/2/1`, `mirror all on`) reproduce the canonical mirror-XY pipeline: a 128×128 physical grid folds to a 64×64 logical buffer, each logical light fanning out to its four reflected quadrants. (`mirrorZ` on is a no-op on a 2D/depth-1 layout.) - -## Effect on the pipeline - -- **Logical box shrinks by the multiplier**: `logW = physW / multiplyX` (etc.). 128×128 with multiply 2/2 → 64×64 logical (the effect renders a quarter of the lights). The effective multiplier clamps to the axis extent — `multiplyZ` on a depth-1 layout clamps to 1 (no-op), never blanking the layer. -- **Fan-out is the fold**: each physical light folds (`pos % logicalSize`) onto its logical cell, so the `multiplyX·multiplyY·multiplyZ` physical lights of the tiles all land on one logical light — the 1:N mapping emerges from the build with no fan-out list and no cap (see [ModifierBase § Fan-out is free](../ModifierBase.md)). -- **Tile vs fold**: with mirror **off** on an axis, tiles repeat (translate); with mirror **on**, odd-numbered tiles reflect within their tile (`size − 1 − pos`), so multiply 2 + mirror = a fold. -- **Integer division**: a physical extent not divisible by the multiplier leaves uncovered cells at the high edge (they map to nothing) — the same edge behaviour the old mirror had on odd widths, without a shared centre line. - -## Cross-domain wiring - -A Layer folds all its enabled modifiers as a chain (order matters: multiply-then-checkerboard ≠ checkerboard-then-multiply). The fold contract is in [ModifierBase](../ModifierBase.md). - -## Tests - -[Unit tests: MultiplyModifier](../../../tests/unit-tests.md#multiplymodifier) — logical dimensions, tile fan-out, per-axis mirror reflection, the pure-fold equivalence to the old Mirror, the multiplyZ-on-2D no-op, and the extent clamp. - -[Scenario: scenario_MultiplyModifier_pipeline](../../../tests/scenario-tests.md#scenario_multiplymodifier_pipeline) — full pipeline with the multiply/mirror kaleidoscope, performance bounds. - -## Prior art - -### MoonLight — M_MoonLight.h Multiply ([source](https://github.com/ewowi/MoonLight/blob/main/src/MoonLight/Nodes/Modifiers/M_MoonLight.h)) - -MoonLight's Multiply node tiles via `position % modifierSize` and reflects odd tiles when its `mirror` flag is set (`position = size − 1 − position`). We expose **per-axis** mirror bools and per-axis multipliers instead of MoonLight's single multiplier coord + single mirror flag, so X/Y/Z fold and tile independently. MoonLight keeps Mirror, Multiply, Transpose, and Kaleidoscope as separate nodes; we fold mirror into Multiply since mirror is just multiply-2-with-reflection. - -## Source - -[MultiplyModifier.h](../../../../src/light/modifiers/MultiplyModifier.h) diff --git a/docs/moonmodules/light/modifiers/RandomMapModifier.md b/docs/moonmodules/light/modifiers/RandomMapModifier.md deleted file mode 100644 index d1e426c0..00000000 --- a/docs/moonmodules/light/modifiers/RandomMapModifier.md +++ /dev/null @@ -1,27 +0,0 @@ -# RandomMapModifier - -A **modifier** that randomly remaps every light to another light — a true 1:1 permutation (every light goes somewhere, no two lights land on the same place, none are dropped) — and reshuffles to a fresh random permutation on a `bpm` timer. The image scrambles into a new arrangement every beat; the *content* is untouched, only *where each pixel lands* changes. - -It is a **dynamic** modifier: where a static modifier (Multiply, Checkerboard) shapes the layer's mapping once, RandomMapModifier re-shapes it on a timer. - -## Controls - -- `bpm` — reshuffles per minute, `0`–`60`, default `6`. `6` ≈ one new permutation every 10 seconds; `60` is the cap (one per second — faster would strobe, and the per-beat work is bounded for that reason). `0` **freezes** the current permutation: a fixed random remap that never changes. - -## How it works - -The permutation rides the layer's existing LUT. Like [CheckerboardModifier](CheckerboardModifier.md), it leaves the logical box the same size as the physical box (identity dimensions) and maps each logical light to exactly one physical light — here, the light at `perm[index]`, where `perm` is a [Fisher–Yates](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)-shuffled array of every light index. On each beat the modifier reshuffles `perm` and asks its parent [Layer](../Layer.md) to rebuild the LUT — the same rebuild a control change triggers, so no new mechanism, just a timer-driven trigger. The shuffle uses an integer LCG seeded from a generation counter, so a given generation is reproducible (and unit-testable) while successive beats differ. - -The permutation buffer is sized to the light count and (re)allocated only when the grid resizes — never per frame. If that allocation fails, the modifier degrades to identity passthrough (no remap), the same way the LUT degrades; an empty (0×0×0) grid is a no-op. On a **sparse** layout the permutation is over grid-cell indices, so a real light can be remapped onto a cell with no LED (it goes dark); this is acceptable for the current version. - -## Cost - -Each beat re-runs the layer's LUT rebuild on the render thread — a transient one-frame cost, like a device scan, not a steady per-frame tax. The `bpm`≤60 cap bounds how often this happens. Steady-state tick/FPS between beats is unchanged. - -## Prior art - -MoonLight has no direct equivalent; the random-remap idea is common in pixel-mapper tools (e.g. shuffle/scramble transitions). The permutation-rides-the-LUT approach and the bpm-accumulator timer are projectMM's own, reusing the [CheckerboardModifier](CheckerboardModifier.md) 1:1 mapping shape and the effect bpm-timer pattern. - -## Source - -[RandomMapModifier.h](../../../../src/light/modifiers/RandomMapModifier.h) diff --git a/docs/moonmodules/light/modifiers/RegionModifier.md b/docs/moonmodules/light/modifiers/RegionModifier.md deleted file mode 100644 index 09117cb6..00000000 --- a/docs/moonmodules/light/modifiers/RegionModifier.md +++ /dev/null @@ -1,48 +0,0 @@ -# Region Modifier - -Static modifier. Carves the layer down to a sub-rectangle of the physical bounding box: the effect renders only inside the region, everything outside is dark. The region is given as **percentages of the physical extent on each axis**, so it survives a physical resize — a `0..50` region stays the left half whether the panel is 64 or 128 wide. Default `0..100` on every axis is the full box (an identity carve). - -Region and Multiply are independent and **compose**: a layer can occupy a region *and* be tiled/mirrored within it (Region then Multiply), since a Layer folds its whole enabled modifier chain in order (see [ModifierBase](../ModifierBase.md)). - -## Controls - -- `startX` / `startY` / `startZ` (Int16, default 0) — region start, as a percentage of physical width / height / depth. -- `endX` / `endY` / `endZ` (Int16, default 100) — region end, as a percentage of physical width / height / depth. - -`Int16`, not a 0–100 slider: the UI renders an unbounded int16 as a **−100..200 percentage slider** so the window can slide **off-screen** (negative start / >100 end). Values round-trip through `/api/state`, `/api/types`, and persistence. - -## Region math - -Per axis, **half-open** `[startPixel, endPixel)`, **un-clamped** to the box: - -- `startPixel = floor(start% / 100 · extent)` — may be negative. -- `endPixel = ceil(end% / 100 · extent)`, **exclusive** — may exceed `extent`. -- window size = `endPixel − startPixel` (floored to ≥ 1 on a non-empty axis). - -Half-open makes abutting windows **tile exactly**: a `0..50` and a `50..100` layer split a 128-wide axis into pixels `0..63` and `64..127` — no overlap, no gap. `start` floors and `end` ceils so a small panel never rounds to an empty window. Default `0..100` on a `W`-wide axis → the full width. - -### Off-screen windows (move, don't rescale) - -The window's **logical size is the full `start..end` span**, so the effect always renders at a fixed scale — moving `start` and `end` together slides the window without resizing it (like dragging an OS window). A physical light outside the window is dropped; window cells with no physical light under them (the off-screen part) stay dark. A window slid **entirely** off the box (e.g. `start=-100, end=0`) maps no lights — the layer goes dark, the way you move an effect completely out of view. Because the span is fixed, sweeping `start`/`end` translates an effect across and off the panel without distorting it. - -## Effect on the pipeline - -- **Logical box = the region size** — `modifyLogicalSize` shrinks the box to the carved rectangle, so the Layer's render buffer (and the status line `w×h×d`) shrinks to the region. The effect only ever renders the region. -- **Fold + reject** — `modifyLogical` folds a physical light into region-local space (subtract the start offset) and returns `false` for any physical light outside the region, so everything beyond the region stays dark. A 1:1 fold, never fans out. -- **Fast path**: the cheapest carve is *no modifier at all* — then `Layer::rebuildLUT` keeps its identity-memcpy / sparse fast path with zero carving cost. The default is to not add a RegionModifier; a full-region `0..100` one is correct but not the absolute cheapest, so full-coverage layers simply omit it. - -## Cross-domain wiring - -Region is a normal `ModifierBase` — carving is its `modifyLogicalSize` + `modifyLogical` fold, composed into the chain like any modifier. See [ModifierBase](../ModifierBase.md). - -## Tests - -[Unit tests: RegionModifier](../../../tests/unit-tests.md#regionmodifier) — the region math (full box, exact half, abutting-tile, small-panel rounding, ≥1-pixel floor, off-screen / fully-off / wider-than-box windows, degenerate axes) and the coordinate offset mapping. [Unit tests: Layer](../../../tests/unit-tests.md#layer) adds the integration case: a RegionModifier shrinks the Layer's logical box to the region and the LUT maps only region cells. - -## Prior art - -The crop / region node of any compositor (After Effects' crop, a shader scissor rect): restrict rendering to a rectangle, the rest is transparent. MoonLight has no single "region" modifier — its layers map through the same coordinate-transform mechanism, which is the lineage for expressing this as a modifier rather than a Layer control. - -## Source - -[RegionModifier.h](../../../../src/light/modifiers/RegionModifier.h) diff --git a/docs/moonmodules/light/modifiers/RotateModifier.md b/docs/moonmodules/light/modifiers/RotateModifier.md deleted file mode 100644 index 2de85ffa..00000000 --- a/docs/moonmodules/light/modifiers/RotateModifier.md +++ /dev/null @@ -1,19 +0,0 @@ -# RotateModifier - -A **dynamic modifier** that rotates the 2D image around its centre, turning continuously over time. The one modifier that overrides `modifyLive` (per-frame, no mapping rebuild) — so the rotation is smooth, and the Layer runs its live pass only because this modifier is present (a static-only chain pays nothing per frame; see [ModifierBase](../ModifierBase.md)). Also the codebase's **transform-matrix reference**. - -## Controls - -- `speed` — rotation speed (1–255, default 1). `loop()` advances the angle on the timer; `modifyLive` applies it on the next frame (no rebuild). - -## How it works - -`loop()` advances the angle on the `speed` timer; rotation is applied each frame in the Layer's live pass (`modifyLive`), not baked into the mapping — so a `speed` change is a cheap live edit, no rebuild. A source that rotates outside the box leaves that destination dark. 2D only: the z axis passes through. The integer 2×2-matrix backward map is in the header. - -## Prior art - -- **MoonLight — M_MoonLight.h Rotate / PinWheel** — a per-light `modifyXYZ()` coordinate transform. Our `modifyLive` is the same per-frame hook; we carry an explicit rotation matrix. - -## Source - -[RotateModifier.h](../../../../src/light/modifiers/RotateModifier.h) diff --git a/docs/moonmodules/light/modifiers/modifiers.md b/docs/moonmodules/light/modifiers/modifiers.md new file mode 100644 index 00000000..df284e9c --- /dev/null +++ b/docs/moonmodules/light/modifiers/modifiers.md @@ -0,0 +1,28 @@ +# Modifiers + +Every modifier, one compact row each. A modifier sits between an [effect](../effects/effects.md) and the output: it reshapes *where* pixels land (or masks them) without changing the effect's drawing. Modifiers compose — a [Layer](../Layer.md) folds its whole modifier stack each rebuild; a *dynamic* modifier (one that overrides `modifyLive`) also runs a per-frame pass. See [ModifierBase](../ModifierBase.md) for the static-vs-dynamic split. + +Columns: **Name** (with its `tags()` emoji — see the [tag emoji legend](../../../architecture.md#tag-emoji-legend)), **Preview**, **Kind** (static = baked into the mapping at rebuild; dynamic = per-frame remap), **Description**, **Controls**, **Tests**. The per-library file split is future work — see the [folder-structure decision](../../../backlog/folder-structure-proposal.md). + +## MoonLight modifiers + +| Name | Preview | Kind | Description | Controls | Tests | +|---|---|---|---|---|---| +| **Multiply** 💫 | | static | Tiles the logical image across the box `multiply` times per axis, optionally mirroring alternate tiles (a pure mirror is `multiply = 2, mirror = true`). | `multiplyX`, `multiplyY`, `multiplyZ`, `mirrorX`, `mirrorY`, `mirrorZ` | [tests](../../../tests/unit-tests.md#multiplymodifier) | +| **Checkerboard** 💫 | | static | Masks the layer in a checkerboard: "off" squares are dropped, "on" squares pass through unchanged. | `size`, `invert` | [tests](../../../tests/unit-tests.md#checkerboardmodifier) | + +## projectMM-native modifiers + +| Name | Preview | Kind | Description | Controls | Tests | +|---|---|---|---|---|---| +| **Region** | — | static | Carves the layer to a sub-rectangle given as percentages of the physical extent (so it survives a resize); outside the region is dark. | `startX`, `startY`, `startZ`, `endX`, `endY`, `endZ` | [tests](../../../tests/unit-tests.md#regionmodifier) | +| **RandomMap** | — | dynamic | Remaps every light to another via a true 1:1 permutation, reshuffling to a fresh permutation on a `bpm` timer — the arrangement scrambles each beat, the content is untouched. | `bpm` | [tests](../../../tests/unit-tests.md#randommapmodifier) | +| **Rotate** | — | dynamic | Rotates the 2D image around its centre, turning continuously over time (the codebase's transform-matrix reference). | `speed` | [tests](../../../tests/unit-tests.md#rotatemodifier) | + +## Source + +- [CheckerboardModifier.h](../../../../src/light/modifiers/CheckerboardModifier.h) +- [MultiplyModifier.h](../../../../src/light/modifiers/MultiplyModifier.h) +- [RandomMapModifier.h](../../../../src/light/modifiers/RandomMapModifier.h) +- [RegionModifier.h](../../../../src/light/modifiers/RegionModifier.h) +- [RotateModifier.h](../../../../src/light/modifiers/RotateModifier.h) diff --git a/docs/tests/scenario-tests.md b/docs/tests/scenario-tests.md index d98db6fb..3fb86537 100644 --- a/docs/tests/scenario-tests.md +++ b/docs/tests/scenario-tests.md @@ -23,9 +23,9 @@ Baseline: the render pipeline runs with no audio module present. | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 32,258-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 20,833-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-12 → 2026-06-25 +- `pc-macos`: observed 2026-06-12 → 2026-06-27 #### `measure-audio-added` (measure) 📏 @@ -41,9 +41,9 @@ Pipeline still renders with the (idle, unconfigured) mic added. | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 34,483-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 20,833-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-12 → 2026-06-25 +- `pc-macos`: observed 2026-06-12 → 2026-06-27 #### `measure-pins-configured` (measure) 📏 @@ -61,9 +61,9 @@ All three mic pins set via the sequential install-fan-out order: pipeline still | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 32,258-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 20,833-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-13 → 2026-06-25 +- `pc-macos`: observed 2026-06-13 → 2026-06-27 #### `measure-consumer-live` (measure) 📏 @@ -79,9 +79,9 @@ Pipeline renders with the producer + consumer both wired. | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 30,303-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 17,241-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-12 → 2026-06-25 +- `pc-macos`: observed 2026-06-12 → 2026-06-27 #### `measure-after-mic-removed` (measure) 📏 @@ -97,9 +97,9 @@ Mic gone, consumer remains: pipeline keeps rendering on silent audio (buffer non | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 31,250-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 17,241-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-12 → 2026-06-25 +- `pc-macos`: observed 2026-06-12 → 2026-06-27 #### `measure-back-to-baseline` (measure) 📏 @@ -115,9 +115,9 @@ Both audio modules gone: back to the pipeline-only baseline, still rendering. | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 40,000-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 20,000-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-12 → 2026-06-25 +- `pc-macos`: observed 2026-06-12 → 2026-06-27 ## DevicesModule @@ -259,10 +259,10 @@ Add NetworkSendDriver and run the bounded FPS measurement (expected to stay at > | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | ≥ 20,000 / 7,576-— | unlimited / unlimited | — / unlimited | +| `pc-macos` | ≥ 20,000 / 4,608-— | unlimited / unlimited | — / unlimited | | `pc-windows` | — / 7,874-8,475 | — / unlimited | — / unlimited | -- `pc-macos`: contract set 2026-06-02 "initial contract" · observed 2026-06-02 → 2026-06-05 +- `pc-macos`: contract set 2026-06-02 "initial contract" · observed 2026-06-02 → 2026-06-30 - `pc-windows`: observed 2026-06-07 ### scenario_Layer_memory_1to1 @@ -312,9 +312,9 @@ Add a third modifier (Checkerboard mask) on top of the chain — a 3-deep fold. | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 142,857-200,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 32,258-200,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-26 +- `pc-macos`: observed 2026-06-26 → 2026-06-27 #### `remove-middle` (remove_module) 📏 @@ -324,9 +324,9 @@ Remove the middle modifier (Multiply) — the chain re-folds with Region then Ch | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 45,455-55,556 | — / unlimited | — / unlimited | +| `pc-macos` | — / 9,524-55,556 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-26 +- `pc-macos`: observed 2026-06-26 → 2026-06-27 #### `add-live-rotate` (add_module) 📏 @@ -336,9 +336,9 @@ Add a DYNAMIC Rotate on top of the static chain — its modifyLive runs the per- | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 25,641-28,571 | — / unlimited | — / unlimited | +| `pc-macos` | — / 5,405-31,250 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-26 +- `pc-macos`: observed 2026-06-26 → 2026-06-29 ### scenario_modifier_swap @@ -368,13 +368,13 @@ Multiply modifier active — pipeline live, LUT folds the grid. | `esp32-eth` | — / 1,580-7,752 | — / 172KB-225KB | — / 76KB-108KB | | `esp32p4-eth` | — / 5,587-6,061 | — / 33243KB | — / 376KB | | `esp32s3-n16r8` | — / 1,773-2,571 | — / 8350KB | — / 92KB | -| `pc-macos` | — / 50,000-166,667 | — / unlimited | — / unlimited | +| `pc-macos` | — / 25,000-166,667 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-25 - `esp32-eth`: observed 2026-06-07 → 2026-06-08 - `esp32p4-eth`: observed 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-25 -- `pc-macos`: observed 2026-06-07 → 2026-06-21 +- `pc-macos`: observed 2026-06-07 → 2026-06-30 #### `checkerboard` (measure) 📏 @@ -391,13 +391,13 @@ Checkerboard modifier active — masks half the lights; pipeline stays live (dri | `esp32-eth` | — / 769-990 | — / 170KB-225KB | — / 76KB-108KB | | `esp32p4-eth` | — / 2,747-2,762 | — / 33242KB | — / 376KB | | `esp32s3-n16r8` | — / 924-943 | — / 8349KB | — / 92KB | -| `pc-macos` | — / 15,873-58,824 | — / unlimited | — / unlimited | +| `pc-macos` | — / 9,615-58,824 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-25 - `esp32-eth`: observed 2026-06-07 → 2026-06-08 - `esp32p4-eth`: observed 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-25 -- `pc-macos`: observed 2026-06-07 → 2026-06-25 +- `pc-macos`: observed 2026-06-07 → 2026-06-27 #### `multiply-2` (measure) 📏 @@ -414,23 +414,23 @@ Back to Multiply — replace round-trips cleanly, pipeline live again. | `esp32-eth` | — / 1,587-2,278 | — / 169KB-225KB | — / 76KB-108KB | | `esp32p4-eth` | — / 6,329-6,410 | — / 33243KB | — / 376KB | | `esp32s3-n16r8` | — / 2,146-2,604 | — / 8349KB-8350KB | — / 92KB | -| `pc-macos` | — / 45,455-166,667 | — / unlimited | — / unlimited | +| `pc-macos` | — / 26,316-166,667 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-25 - `esp32-eth`: observed 2026-06-07 → 2026-06-08 - `esp32p4-eth`: observed 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-25 -- `pc-macos`: observed 2026-06-07 → 2026-06-25 +- `pc-macos`: observed 2026-06-07 → 2026-06-27 ### scenario_perf_full -`test/scenarios/light/scenario_perf_full.json` — Comprehensive incremental performance check (the SLOW, on-device companion to scenario_perf_light). Mutate mode + canvas-preparing: clear_children whatever the device already had (pre-wired apparatus like PreviewDriver/Board survives — clear_children only drops user-editable children), rebuild a known minimal tree, then add one subsystem at a time — audio, device discovery, a modifier, then EVERY output driver this board has (each optional + capped to 64 output LEDs so its per-frame cost is comparable, not its transmit-all-16K time), then a network driver — measuring the tick/heap delta after each so each subsystem's cost is isolated. Then sweep the grid 16²→32²→64²→128² (16K) for both a LIGHT effect (Checkerboard) and a HEAVY one (Noise) to bracket the compute range across sizes. LED drivers are platform-gated (RMT on classic/S3, LCD on S3, Parlio on P4; none on desktop) so each driver step is optional:true and skipped where absent — the all-drivers comparison is assembled across boards (S3 gives RMT vs LCD, P4 gives RMT vs Parlio). Subsumes the old scenario_Layer_buildup (incremental module cost), scenario_GridLayout_grid_sizes (grid sweep), and scenario_AllEffects_grid_sizes (per-effect size sweep, here reduced to a light/heavy bracket). Runs minutes on a device; not a per-commit gate. +`test/scenarios/light/scenario_perf_full.json` — Comprehensive incremental performance check (the SLOW, on-device companion to scenario_perf_light). Mutate mode + canvas-preparing: clear_children whatever the device already had (pre-wired apparatus like PreviewDriver/Board survives — clear_children only drops user-editable children), rebuild a known minimal tree, then add one subsystem at a time — audio, device discovery, a modifier, then EVERY output driver this board has (each optional + capped to 64 output LEDs so its per-frame cost is comparable, not its transmit-all-16K time), then a network driver — measuring the tick/heap delta after each so each subsystem's cost is isolated. Then sweep the grid 16²→32²→64²→128² (16K) for both a LIGHT effect (Spiral) and a HEAVY one (Noise) to bracket the compute range across sizes. LED drivers are platform-gated (RMT on classic/S3, LCD on S3, Parlio on P4; none on desktop) so each driver step is optional:true and skipped where absent — the all-drivers comparison is assembled across boards (S3 gives RMT vs LCD, P4 gives RMT vs Parlio). Subsumes the old scenario_Layer_buildup (incremental module cost), scenario_GridLayout_grid_sizes (grid sweep), and scenario_AllEffects_grid_sizes (per-effect size sweep, here reduced to a light/heavy bracket). Runs minutes on a device; not a per-commit gate. -**Mode**: `mutate` · **Also touches**: Layouts, GridLayout, Drivers, PreviewDriver, NetworkSendDriver, RmtLedDriver, LcdLedDriver, ParlioLedDriver, MultiplyModifier, CheckerboardEffect, NoiseEffect +**Mode**: `mutate` · **Also touches**: Layouts, GridLayout, Drivers, PreviewDriver, NetworkSendDriver, RmtLedDriver, LcdLedDriver, ParlioLedDriver, MultiplyModifier, SpiralEffect, NoiseEffect #### `measure-minimal` (measure) 📏 -Bare minimum at 16²: Grid + Layer + Checkerboard, no output driver, audio/discovery still on as the device ships. The floor for the subsystem-cost diffs below. +Bare minimum at 16²: Grid + Layer + Spiral, no output driver, audio/discovery still on as the device ships. The floor for the subsystem-cost diffs below. **Setup** (preceding non-measured steps): - `clear-layers` (clear_children) — Start clean: drop whatever effects/modifiers/layouts/drivers the device had (pre-wired Preview survives). @@ -447,12 +447,12 @@ Bare minimum at 16²: Grid + Layer + Checkerboard, no output driver, audio/disco | `esp32` | — / 7,692-8,929 | — / 134KB-147KB | — / 108KB | | `esp32p4-eth` | — / 14,925-17,544 | — / 33226KB-33245KB | — / 376KB | | `esp32s3-n16r8` | — / 5,376-9,009 | — / 8340KB-8352KB | — / 92KB-112KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 200,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-no-audio` (measure) 📏 @@ -466,12 +466,12 @@ Bare minimum at 16²: Grid + Layer + Checkerboard, no output driver, audio/disco | `esp32` | — / 8,621-9,901 | — / 134KB-147KB | — / 108KB | | `esp32p4-eth` | — / 18,182-18,868 | — / 33228KB-33245KB | — / 376KB | | `esp32s3-n16r8` | — / 8,065-9,901 | — / 8338KB-8352KB | — / 92KB-112KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 166,667-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-quiet` (measure) 📏 @@ -487,12 +487,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 7,246-9,901 | — / 131KB-146KB | — / 108KB | | `esp32p4-eth` | — / 17,544-18,519 | — / 33226KB-33245KB | — / 376KB | | `esp32s3-n16r8` | — / 7,752-9,901 | — / 8337KB-8352KB | — / 92KB-112KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 200,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-modifier` (measure) 📏 @@ -545,12 +545,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 6,098-7,194 | — / 131KB-145KB | — / 108KB | | `esp32p4-eth` | — / 14,493-17,544 | — / 33226KB-33244KB | — / 376KB | | `esp32s3-n16r8` | — / 6,452-8,065 | — / 8334KB-8351KB | — / 84KB-112KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 200,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-26 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-rmt` (measure) 📏 @@ -565,12 +565,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 6,579-9,174 | — / 106KB-122KB | — / 84KB-108KB | | `esp32p4-eth` | — / 15,873-17,857 | — / 33200KB-33221KB | — / 376KB | | `esp32s3-n16r8` | — / 7,194-9,346 | — / 8307KB-8328KB | — / 84KB-112KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 200,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-26 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-lcd` (measure) 📏 @@ -585,12 +585,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 8,403-9,901 | — / 126KB-147KB | — / 108KB | | `esp32p4-eth` | — / 15,873-17,857 | — / 33225KB-33245KB | — / 376KB | | `esp32s3-n16r8` | — / 7,042-9,259 | — / 8333KB-8352KB | — / 88KB-112KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 200,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-24 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-parlio` (measure) 📏 @@ -605,19 +605,19 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 8,475-9,901 | — / 135KB-147KB | — / 108KB | | `esp32p4-eth` | — / 15,873-17,857 | — / 33225KB-33245KB | — / 376KB | | `esp32s3-n16r8` | — / 7,692-9,434 | — / 8338KB-8352KB | — / 92KB-112KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 200,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-24 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-light-16` (measure) 📏 **Setup** (preceding non-measured steps): - `remove-parlio-driver` (remove_module) - `add-preview-for-sweep` (add_module) — Re-add PreviewDriver as the output for the grid sweep (the per-driver adds above each removed their driver; Preview is the cheap, every-board output for a pure-render size curve). -- `light-16-w` (set_control) — Grid sweep, LIGHT effect (Checkerboard is already FX). +- `light-16-w` (set_control) — Grid sweep, LIGHT effect (Spiral is already FX). - `light-16-h` (set_control) **Performance** (contract / observed) — tick stored, FPS shown: @@ -627,12 +627,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 6,711-9,804 | — / 134KB-147KB | — / 108KB | | `esp32p4-eth` | — / 15,385-18,868 | — / 33226KB-33245KB | — / 376KB | | `esp32s3-n16r8` | — / 8,403-9,901 | — / 8336KB-8352KB | — / 92KB-112KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 200,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-24 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-light-32` (measure) 📏 @@ -647,12 +647,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 2,801-3,367 | — / 134KB-144KB | — / 108KB | | `esp32p4-eth` | — / 7,246-7,576 | — / 33225KB-33243KB | — / 376KB | | `esp32s3-n16r8` | — / 3,049-3,597 | — / 8331KB-8350KB | — / 92KB-112KB | -| `pc-macos` | — / 333,333-1,000,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 55,556-1,000,000 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-24 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-light-64` (measure) 📏 @@ -667,12 +667,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 870-928 | — / 125KB-135KB | — / 108KB | | `esp32p4-eth` | — / 2,008-2,232 | — / 33218KB-33234KB | — / 376KB | | `esp32s3-n16r8` | — / 894-1,011 | — / 8312KB-8341KB | — / 88KB-112KB | -| `pc-macos` | — / 12,658-250,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 12,658-333,333 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-24 +- `pc-macos`: observed 2026-06-17 → 2026-06-28 #### `measure-light-128` (measure) 📏 @@ -687,12 +687,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 224-238 | — / 89KB-99KB | — / 62KB | | `esp32p4-eth` | — / 515-573 | — / 33182KB-33198KB | — / 376KB | | `esp32s3-n16r8` | — / 114-134 | — / 8291KB-8305KB | — / 92KB-112KB | -| `pc-macos` | — / 5,348-62,500 | — / unlimited | — / unlimited | +| `pc-macos` | — / 3,497-62,500 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-24 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-heavy-16` (measure) 📏 @@ -708,12 +708,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 990-1,224 | — / 136KB-147KB | — / 108KB | | `esp32p4-eth` | — / 2,865-3,367 | — / 33229KB-33245KB | — / 376KB | | `esp32s3-n16r8` | — / 1,100-1,361 | — / 8342KB-8352KB | — / 92KB-112KB | -| `pc-macos` | — / 62,500-333,333 | — / unlimited | — / unlimited | +| `pc-macos` | — / 47,619-333,333 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-26 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-27 #### `measure-heavy-32` (measure) 📏 @@ -728,12 +728,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 306-314 | — / 134KB-144KB | — / 108KB | | `esp32p4-eth` | — / 799-898 | — / 33227KB-33243KB | — / 376KB | | `esp32s3-n16r8` | — / 290-356 | — / 8339KB-8350KB | — / 92KB-112KB | -| `pc-macos` | — / 15,152-71,429 | — / unlimited | — / unlimited | +| `pc-macos` | — / 11,765-71,429 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-27 #### `measure-heavy-64` (measure) 📏 @@ -748,12 +748,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 73.8-79.4 | — / 125KB-135KB | — / 108KB | | `esp32p4-eth` | — / 196-229 | — / 33218KB-33234KB | — / 376KB | | `esp32s3-n16r8` | — / 85.2-90.3 | — / 8330KB-8341KB | — / 92KB-112KB | -| `pc-macos` | — / 2,924-16,129 | — / unlimited | — / unlimited | +| `pc-macos` | — / 2,119-16,129 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-21 +- `pc-macos`: observed 2026-06-17 → 2026-06-27 #### `measure-heavy-128` (measure) 📏 @@ -768,12 +768,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 16.0-19.0 | — / 89KB-99KB | — / 62KB | | `esp32p4-eth` | — / 53.7-57.4 | — / 33182KB-33198KB | — / 376KB | | `esp32s3-n16r8` | — / 19.2-20.8 | — / 8293KB-8305KB | — / 92KB-112KB | -| `pc-macos` | — / 1,094-3,247 | — / unlimited | — / unlimited | +| `pc-macos` | — / 915-3,521 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-mod-16` (measure) 📏 @@ -829,12 +829,12 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 144-149 | — / 111KB-122KB | — / 96KB-100KB | | `esp32p4-eth` | — / 438-486 | — / 33194KB-33210KB | — / 376KB | | `esp32s3-n16r8` | — / 119-162 | — / 8307KB-8317KB | — / 92KB-112KB | -| `pc-macos` | — / 23,256-71,429 | — / unlimited | — / unlimited | +| `pc-macos` | — / 20,833-71,429 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-26 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-mod-128` (measure) 📏 @@ -849,22 +849,22 @@ Quiet baseline: render-only, audio + discovery off. The cleanest render floor; t | `esp32` | — / 29.8-35.1 | — / 36KB-47KB | — / 24KB-26KB | | `esp32p4-eth` | — / 86.3-102 | — / 33089KB-33105KB | — / 376KB | | `esp32s3-n16r8` | — / 16.8-35.6 | — / 8202KB-8212KB | — / 92KB-112KB | -| `pc-macos` | — / 5,128-16,129 | — / unlimited | — / unlimited | +| `pc-macos` | — / 5,128-16,393 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 ### scenario_perf_light -`test/scenarios/light/scenario_perf_light.json` — Fast incremental performance check: start from the bare minimum render pipeline and add one thing at a time, measuring the tick/heap delta each step, so a regression shows up as a per-step jump. The LIGHT companion to scenario_perf_full — it stays small (≤64²) and driver-free so it runs in seconds. Mutate mode + canvas-preparing: the steps clear_children whatever Layouts/Layers/Drivers the device already had (the pre-wired apparatus like PreviewDriver/Board survives — clear_children only drops user-editable children) and rebuild a known tree, so it runs from any starting state and always measures the same minimal pipeline. Order: (1) minimal = Grid(16²)+Layer+a LIGHT effect (Checkerboard, the cheapest), no modifier/driver/audio/discovery; (2) +MultiplyModifier (adds the mapping LUT — the heavy memory path); (3) +PreviewDriver; (4) swap to a HEAVY effect (Noise) to bracket the compute range; (5) grid 16²→32²→64² to show the size scaling. Full 128²/16K sweep, real LED/network drivers, audio+discovery cost: see scenario_perf_full. +`test/scenarios/light/scenario_perf_light.json` — Fast incremental performance check: start from the bare minimum render pipeline and add one thing at a time, measuring the tick/heap delta each step, so a regression shows up as a per-step jump. The LIGHT companion to scenario_perf_full — it stays small (≤64²) and driver-free so it runs in seconds. Mutate mode + canvas-preparing: the steps clear_children whatever Layouts/Layers/Drivers the device already had (the pre-wired apparatus like PreviewDriver/Board survives — clear_children only drops user-editable children) and rebuild a known tree, so it runs from any starting state and always measures the same minimal pipeline. Order: (1) minimal = Grid(16²)+Layer+a LIGHT effect (Spiral, a light effect), no modifier/driver/audio/discovery; (2) +MultiplyModifier (adds the mapping LUT — the heavy memory path); (3) +PreviewDriver; (4) swap to a HEAVY effect (Noise) to bracket the compute range; (5) grid 16²→32²→64² to show the size scaling. Full 128²/16K sweep, real LED/network drivers, audio+discovery cost: see scenario_perf_full. -**Mode**: `mutate` · **Also touches**: Layouts, GridLayout, Drivers, PreviewDriver, CheckerboardEffect, NoiseEffect, MultiplyModifier +**Mode**: `mutate` · **Also touches**: Layouts, GridLayout, Drivers, PreviewDriver, SpiralEffect, NoiseEffect, MultiplyModifier #### `measure-minimal` (measure) 📏 -Bare minimum: Grid(16²) + Layer + Checkerboard (light effect). No modifier, no driver. The render floor everything else is measured against. +Bare minimum: Grid(16²) + Layer + Spiral (light effect). No modifier, no driver. The render floor everything else is measured against. **Setup** (preceding non-measured steps): - `disable-audio` (set_control) — Quiet I2S sampling so it can't pollute the tick (optional — device only). @@ -883,12 +883,12 @@ Bare minimum: Grid(16²) + Layer + Checkerboard (light effect). No modifier, no | `esp32` | — / 6,173-8,850 | — / 125KB-147KB | — / 108KB | | `esp32p4-eth` | — / 13,699-18,519 | — / 33228KB-33246KB | — / 376KB | | `esp32s3-n16r8` | — / 5,814-8,850 | — / 8316KB-8347KB | — / 80KB-104KB | -| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | +| `pc-macos` | — / 200,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-24 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-with-modifier` (measure) 📏 @@ -904,12 +904,12 @@ Cost of the modifier + LUT over the minimal pipeline. Heap delta vs measure-mini | `esp32` | — / 3,077-9,709 | — / 131KB-147KB | — / 108KB | | `esp32p4-eth` | — / 8,621-10,309 | — / 33226KB-33243KB | — / 376KB | | `esp32s3-n16r8` | — / 3,195-4,032 | — / 8330KB-8345KB | — / 92KB-100KB | -| `pc-macos` | — / — | — / unlimited | — / unlimited | +| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-with-preview` (measure) 📏 @@ -922,12 +922,12 @@ PreviewDriver is the pre-wired apparatus — it survives clear_children and is a | `esp32` | — / 3,067-9,804 | — / 132KB-146KB | — / 108KB | | `esp32p4-eth` | — / 10,417-10,753 | — / 33226KB-33243KB | — / 376KB | | `esp32s3-n16r8` | — / 3,802-4,274 | — / 8330KB-8345KB | — / 84KB-100KB | -| `pc-macos` | — / — | — / unlimited | — / unlimited | +| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-heavy-16` (measure) 📏 @@ -961,12 +961,12 @@ PreviewDriver is the pre-wired apparatus — it survives clear_children and is a | `esp32` | — / 265-826 | — / 130KB-144KB | — / 108KB | | `esp32p4-eth` | — / 1,603-1,880 | — / 33221KB-33237KB | — / 376KB | | `esp32s3-n16r8` | — / 562-715 | — / 8328KB-8333KB | — / 84KB-104KB | -| `pc-macos` | — / 90,909-333,333 | — / unlimited | — / unlimited | +| `pc-macos` | — / 76,923-333,333 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-25 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 #### `measure-heavy-64` (measure) 📏 @@ -981,20 +981,20 @@ PreviewDriver is the pre-wired apparatus — it survives clear_children and is a | `esp32` | — / 77.1-227 | — / 111KB-135KB | — / 88KB-108KB | | `esp32p4-eth` | — / 411-491 | — / 33195KB-33210KB | — / 376KB | | `esp32s3-n16r8` | — / 129-162 | — / 8302KB-8317KB | — / 92KB-108KB | -| `pc-macos` | — / 20,000-71,429 | — / unlimited | — / unlimited | +| `pc-macos` | — / 14,286-71,429 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-17 → 2026-06-25 - `esp32p4-eth`: observed 2026-06-17 → 2026-06-25 - `esp32s3-n16r8`: observed 2026-06-17 → 2026-06-25 -- `pc-macos`: observed 2026-06-17 → 2026-06-26 +- `pc-macos`: observed 2026-06-17 → 2026-06-30 ## Layers ### scenario_Layers_composition -`test/scenarios/light/scenario_Layers_composition.json` — Multi-layer composition end-to-end: Layouts→Grid, TWO Layers under one Layers container (bottom Checkerboard, top Rainbow), Drivers→NetworkSendDriver. Proves the Drivers composite loop builds, allocates its output buffer, blends both enabled layers and feeds the result to the driver without crashing, and gates the bounded FPS so the N-pass composite cost is tracked. The exact alpha/additive blend math and the disable-drops-to-single-layer path are pinned by the unit tests (unit_BlendMap, unit_Layers_container); construct-mode set_control can't apply controls (built post-scheduler), so this scenario uses each Layer's default blend (alpha, full opacity) and asserts wired liveness + tick, not per-byte blend output. +`test/scenarios/light/scenario_Layers_composition.json` — Multi-layer composition end-to-end: Layouts→Grid, TWO Layers under one Layers container (bottom Spiral, top Rainbow), Drivers→NetworkSendDriver. Proves the Drivers composite loop builds, allocates its output buffer, blends both enabled layers and feeds the result to the driver without crashing, and gates the bounded FPS so the N-pass composite cost is tracked. The exact alpha/additive blend math and the disable-drops-to-single-layer path are pinned by the unit tests (unit_BlendMap, unit_Layers_container); construct-mode set_control can't apply controls (built post-scheduler), so this scenario uses each Layer's default blend (alpha, full opacity) and asserts wired liveness + tick, not per-byte blend output. -**Mode**: `construct` · **Also touches**: Layer, GridLayout, RainbowEffect, CheckerboardEffect, Drivers, NetworkSendDriver +**Mode**: `construct` · **Also touches**: Layer, GridLayout, RainbowEffect, SpiralEffect, Drivers, NetworkSendDriver #### `add-artnet` (add_module) 📏 @@ -1005,9 +1005,9 @@ Add NetworkSendDriver and run the bounded FPS measurement over the two-layer com - `add-grid` (add_module) — 128x128 GridLayout under Layouts (above host clock resolution so the composite tick is measurable). - `add-layers-group` (add_module) — Top-level Layers container — the multi-layer composition host. - `add-bottom-layer` (add_module) — Bottom Layer (composited first — clears + overwrites the output buffer). RGB. -- `add-bottom-effect` (add_module) — A Checkerboard base as the bottom layer's effect. +- `add-bottom-effect` (add_module) — A Spiral base as the bottom layer's effect. - `add-top-layer` (add_module) — Top Layer (composited second — blends onto the bottom with its default blend). RGB. -- `add-top-effect` (add_module) — Rainbow as the top layer's effect — composited over the Checkerboard base. +- `add-top-effect` (add_module) — Rainbow as the top layer's effect — composited over the Spiral base. - `add-driver-group` (add_module) — Top-level Drivers container wired to the Layers container (composites all enabled layers into its output buffer). **Bounds**: @@ -1018,9 +1018,9 @@ Add NetworkSendDriver and run the bounded FPS measurement over the two-layer com | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 6,135-18,519 | — / unlimited | — / unlimited | +| `pc-macos` | — / 1,695-19,231 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-25 +- `pc-macos`: observed 2026-06-25 → 2026-06-30 ## Layouts @@ -1042,11 +1042,11 @@ Baseline: a single 64x64 grid layout drives the pipeline. | Board | FPS | heap | block | |---|---|---|---| | `esp32-eth` | — / 41,667 | — / 224KB | — / 108KB | -| `pc-macos` | — / 25,000-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 17,857-125,000 | — / unlimited | — / unlimited | | `pc-windows` | — / 32,258-37,037 | — / unlimited | — / unlimited | - `esp32-eth`: observed 2026-06-08 -- `pc-macos`: observed 2026-06-05 → 2026-06-25 +- `pc-macos`: observed 2026-06-05 → 2026-06-27 - `pc-windows`: observed 2026-06-07 #### `measure-two-layouts` (measure) 📏 @@ -1064,11 +1064,11 @@ Pipeline still renders with two layouts wired (buffer non-null, fps measurable). | Board | FPS | heap | block | |---|---|---|---| | `esp32-eth` | — / 37,037 | — / 223KB | — / 108KB | -| `pc-macos` | — / 11,905-111,111 | — / unlimited | — / unlimited | +| `pc-macos` | — / 3,953-111,111 | — / unlimited | — / unlimited | | `pc-windows` | — / 16,393-23,810 | — / unlimited | — / unlimited | - `esp32-eth`: observed 2026-06-08 -- `pc-macos`: observed 2026-06-05 → 2026-06-25 +- `pc-macos`: observed 2026-06-05 → 2026-06-27 - `pc-windows`: observed 2026-06-07 #### `measure-after-replace` (measure) 📏 @@ -1086,11 +1086,11 @@ Pipeline still renders after replacing a grid with a sphere (different layout ty | Board | FPS | heap | block | |---|---|---|---| | `esp32-eth` | — / 38,462 | — / 223KB | — / 108KB | -| `pc-macos` | — / 3,690-100,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 1,957-100,000 | — / unlimited | — / unlimited | | `pc-windows` | — / 5,848-9,009 | — / unlimited | — / unlimited | - `esp32-eth`: observed 2026-06-08 -- `pc-macos`: observed 2026-06-05 → 2026-06-25 +- `pc-macos`: observed 2026-06-05 → 2026-06-27 - `pc-windows`: observed 2026-06-07 #### `measure-after-remove` (measure) 📏 @@ -1117,6 +1117,111 @@ Pipeline renders with the single remaining grid, same as the baseline. ## MoonLiveEffect +### scenario_MoonLiveEffect_controls + +`test/scenarios/light/scenario_MoonLiveEffect_controls.json` — Exercise MoonLive Stage-1 CONTROLS end-to-end as a wired module. A script declares a control (`uint8_t speed = 7; // @control 0..15`) and uses it (`setRGB(speed, ...)`); the engine surfaces the control, the binding creates a real uint8 MoonModule control bound to the live control-values arena slot. The scenario: add the effect with a control script (the control appears, renders), change the CONTROL value live (a slider move — must NOT recompile; the arena byte updates and the next tick reads it), edit the SOURCE to add a second control (recompile re-derives the set, existing slider value preserved by the stable-address grow-only arena), edit the source to remove a control (the orphaned value drops), push a broken script (compile fails, renders dark, status shows the diagnostic, no crash), recover, and remove + re-add (resource teardown + re-acquire). A crash in the LoadCtrl codegen, a dangling arena pointer across a recompile, or a value change that wrongly triggers a recompile all show up as a failed measure or a tick spike. The codegen + live-read contract is pinned by unit_moonlive_ir / unit_moonlive_compiler; this is the wired-module gate. + +**Mode**: `mutate` · **Also touches**: Layouts, GridLayout, Layers, Layer, Drivers, NetworkSendDriver + +#### `add-control-script` (add_module) 📏 + +Add a MoonLiveEffect whose source declares a `speed` control and uses it. The control appears bound to the arena slot (seeded to its default 7); the wired effect renders one pixel. + +**Performance** (contract / observed) — tick stored, FPS shown: + +| Board | FPS | heap | block | +|---|---|---|---| +| `pc-macos` | — / 1,000,000-— | — / unlimited | — / unlimited | + +- `pc-macos`: observed 2026-06-28 → 2026-06-30 + +#### `set-source-with-control` (set_control) 📏 + +Edit the source to the control script. A source edit recompiles (controlChangeTriggersBuildState gates on `source`); the engine derives the `speed` control and the binding surfaces it. + +**Performance** (contract / observed) — tick stored, FPS shown: + +| Board | FPS | heap | block | +|---|---|---|---| +| `pc-macos` | — / — | — / unlimited | — / unlimited | + +- `pc-macos`: observed 2026-06-28 + +#### `change-control-live` (set_control) 📏 + +Change the `speed` control value (a slider move). This must NOT recompile — controlChangeTriggersBuildState returns false for a scripted control; the arena byte updates and the next render tick reads it. Tick stays cheap (a recompile would spike it). + +**Performance** (contract / observed) — tick stored, FPS shown: + +| Board | FPS | heap | block | +|---|---|---|---| +| `pc-macos` | — / — | — / unlimited | — / unlimited | + +- `pc-macos`: observed 2026-06-28 + +#### `edit-source-two-controls` (set_control) 📏 + +Edit the source to add a second control. The recompile re-derives the control set; the stable-address grow-only arena keeps `speed`'s live value while seeding the new slot. + +**Performance** (contract / observed) — tick stored, FPS shown: + +| Board | FPS | heap | block | +|---|---|---|---| +| `pc-macos` | — / — | — / unlimited | — / unlimited | + +- `pc-macos`: observed 2026-06-28 + +#### `edit-source-shrink-to-one-control` (set_control) 📏 + +Edit the source back to a single control. The control set shrinks 2 -> 1: `speed` stays bound (its live value kept), the removed `hue`'s value is dropped, and the value change path is exercised without an unexpected recompile crash. + +**Performance** (contract / observed) — tick stored, FPS shown: + +| Board | FPS | heap | block | +|---|---|---|---| +| `pc-macos` | — / — | — / unlimited | — / unlimited | + +- `pc-macos`: observed 2026-06-28 + +#### `edit-source-broken` (set_control) 📏 + +Push a broken script. Compile fails, the previous code is freed, the effect renders dark and the parse error surfaces in status — no crash. + +**Performance** (contract / observed) — tick stored, FPS shown: + +| Board | FPS | heap | block | +|---|---|---|---| +| `pc-macos` | — / — | — / unlimited | — / unlimited | + +- `pc-macos`: observed 2026-06-28 + +#### `edit-source-recover` (set_control) 📏 + +Recover with a valid control script — the effect compiles and renders again. + +**Performance** (contract / observed) — tick stored, FPS shown: + +| Board | FPS | heap | block | +|---|---|---|---| +| `pc-macos` | — / — | — / unlimited | — / unlimited | + +- `pc-macos`: observed 2026-06-28 + +#### `re-add-control-effect` (add_module) 📏 + +Re-add a fresh effect after the remove — exec memory + control arena re-acquired clean (it renders its default fill on add). Control re-acquisition itself is proven by the add-control-script step at the top: a freshly-added effect compiling a control source surfaces + seeds its control; construct-mode set_control can't apply a dynamically-added scripted control as the final asserted render, so the gate here is the bare re-add's liveness. + +**Setup** (preceding non-measured steps): +- `remove-control-effect` (remove_module) — Remove the effect — the engine releases its exec block AND its control arena (teardown). + +**Performance** (contract / observed) — tick stored, FPS shown: + +| Board | FPS | heap | block | +|---|---|---|---| +| `pc-macos` | — / — | — / unlimited | — / unlimited | + +- `pc-macos`: observed 2026-06-28 + ### scenario_MoonLiveEffect_livescript `test/scenarios/light/scenario_MoonLiveEffect_livescript.json` — Exercise a scripted MoonLiveEffect as a wired MoonModule end-to-end — the integration layer the unit tests can't reach. The effect compiles its `source` text to native code on-device and renders it into the Layer buffer each tick. Prepares its own canvas: Layout(Grid 16x16) + Layer + MoonLiveEffect, measures the default compile, then edits `source` live (a new fill colour recompiles and keeps rendering), pushes a BROKEN script (compile fails, the previous code is freed, the effect renders dark and the parse error surfaces in status, no crash), recovers with a valid script, and finally removes + re-adds the effect (add/remove robustness in any order). A crash in the JIT/emit path, a failed recompile that wedges the tick, or a buffer overrun on an odd grid all show up as a failed measure. The compiler + emit golden bytes are pinned by unit_moonlive_compiler / unit_moonlive_fill; this is the live wired-module gate. @@ -1350,14 +1455,14 @@ Re-enable mirrorY and measure — the heavy LUT path must recover (FPS within 50 | `esp32-eth` | — / 10.5-10.6 | — / 132KB | — / 48KB-50KB | | `esp32-eth-wifi` | ≥ 10.0 / 12.1 | ≥ 103KB / 94KB | — / 48KB | | `esp32p4-eth` | — / 5,319-6,098 | — / 33238KB | — / 376KB | -| `pc-macos` | ≥ 8,333 / 3,390-10,417 | unlimited / unlimited | — / unlimited | +| `pc-macos` | ≥ 8,333 / 3,356-10,417 | unlimited / unlimited | — / unlimited | | `pc-windows` | — / 4,065-4,854 | — / unlimited | — / unlimited | - `esp32`: observed 2026-06-02 - `esp32-eth`: observed 2026-06-02 - `esp32-eth-wifi`: contract set 2026-06-02 "initial contract" · observed 2026-06-02 - `esp32p4-eth`: observed 2026-06-17 -- `pc-macos`: contract set 2026-06-02 "initial contract" · observed 2026-06-02 → 2026-06-16 +- `pc-macos`: contract set 2026-06-02 "initial contract" · observed 2026-06-02 → 2026-06-30 - `pc-windows`: observed 2026-06-07 ## MultiplyModifier @@ -1571,9 +1676,9 @@ Baseline: the pipeline renders with one driver (Preview) wired. | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 29,412-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 13,699-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-13 → 2026-06-24 +- `pc-macos`: observed 2026-06-13 → 2026-06-30 #### `measure-two-drivers` (measure) 📏 @@ -1589,9 +1694,9 @@ Pipeline renders with both drivers wired. | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 17,857-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 17,544-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-13 → 2026-06-22 +- `pc-macos`: observed 2026-06-13 → 2026-06-27 #### `measure-three-drivers` (measure) 📏 @@ -1607,9 +1712,9 @@ Pipeline renders with three drivers wired. | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 38,462-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 17,857-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-13 → 2026-06-25 +- `pc-macos`: observed 2026-06-13 → 2026-06-27 #### `measure-after-first-remove` (measure) 📏 @@ -1625,9 +1730,9 @@ One ArtNet gone, Preview + ArtNet2 remain: pipeline keeps rendering (buffer non- | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 30,303-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 18,182-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-13 → 2026-06-24 +- `pc-macos`: observed 2026-06-13 → 2026-06-27 #### `measure-back-to-one-driver` (measure) 📏 @@ -1643,6 +1748,6 @@ Both added drivers gone, back to the single Preview baseline, still rendering | Board | FPS | heap | block | |---|---|---|---| -| `pc-macos` | — / 38,462-125,000 | — / unlimited | — / unlimited | +| `pc-macos` | — / 18,182-125,000 | — / unlimited | — / unlimited | -- `pc-macos`: observed 2026-06-13 → 2026-06-24 +- `pc-macos`: observed 2026-06-13 → 2026-06-27 diff --git a/docs/tests/unit-tests.md b/docs/tests/unit-tests.md index 5f96101c..972ae88a 100644 --- a/docs/tests/unit-tests.md +++ b/docs/tests/unit-tests.md @@ -73,29 +73,14 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - Calling free() twice is harmless; pointer and count remain zeroed. - allocate() refuses zero-count or zero-channels (returns false, no allocation, buffer left empty so a caller that ignores the bool doesn't get a partial state). -## CheckerboardEffect - -`test/unit/light/unit_CheckerboardEffect.cpp` -*Also touches: SpiralEffect, PlasmaPaletteEffect, RingsEffect, RipplesEffect, GlowParticlesEffect, LavaLampEffect.* - -- Checkerboard paints at least one non-zero byte on a 16×16 grid (effect actually renders). -- With cell_size=4, adjacent cells render different colours (the checker pattern is real, not uniform). -- LavaLampEffect has localised blob features that can land on identical corner palette indices at some t values (corner-pair check is too strict). Scan the whole buffer for any two distinct pixels instead — same approach as RingsEffect below. LavaLamp paints at least one non-zero byte (effect actually renders). -- Across 10 frames at bpm=60, at least one frame shows two distinct colours somewhere in the buffer (blobs move and the field varies). -- RingsEffect has localised features (thin rings); corner-pair check is too strict, so we scan for any two distinct pixels instead. Rings paints at least one non-zero byte (effect actually renders). -- At least two distinct pixels exist somewhere in the buffer (rings are localised, so corner-pair would be too strict). -- RipplesEffect (MoonLight sine-wave water surface) lights one pixel per column at a sine-driven height. On a flat 2D layer it still paints a visible wavefront — assert it renders something and varies across the surface. -- Ripples lights one pixel per column at a sine-driven height, so the surface holds at least two distinct colours (wavefront vs background) — scan the whole buffer, corner-pair would be too strict. - ## CheckerboardModifier `test/unit/light/unit_CheckerboardModifier.cpp` -- Identity dimensions — a mask doesn't resize the logical box. -- size=1: every cell is its own square; parity = (x+y+z)&1. Default (invert false) keeps even-parity cells, drops odd-parity. -- invert flips which parity passes — the cell that was dropped now passes and vice versa. -- size>1 groups cells into squares: with size=2, the 2×2 block at the origin is all one square (parity of 0/2=0), so all four pass; the next block over drops. -- Never fans out — at most one destination. +- A mask leaves the logical box unchanged. +- size=1: every cell is its own square; parity = (x+y+z)&1. Default (invert false) keeps even-parity cells, drops odd-parity. Passing cells keep their coord. +- invert flips which parity passes. +- size>1 groups cells into squares: with size=2, the 2×2 block at the origin is all one square (parity 0), so all four pass; the next block over drops. ## Color @@ -145,26 +130,46 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - Brightness scaling runs before white derivation so W = min of the *scaled* RGB values. - rebuild() can switch the output channel count between RGB (3) and RGBW (4) on the fly. -## DevicesModule +## DevicePlugin `test/unit/core/unit_DeviceIdentify.cpp` +*Also touches: DevicesModule.* -- _classifyDevice: projectMM from /api/state modules array_ -- _classifyDevice: WLED from /json/info brand_ -- _classifyDevice: a live non-projectMM/non-WLED host is generic_ -- _classifyDevice: a truncated projectMM body still classifies (modules is early)_ -- _extractDeviceName: projectMM reads the deviceName control's value, not the type_ -- _extractDeviceName: WLED reads the top-level name field_ -- _extractDeviceName: generic / garbage / null bodies yield empty_ -- _extractDeviceName: respects the output buffer size (no overflow)_ -- _devTypeStr maps every type_ +- _MmPlugin claims a presence packet carrying the projectMM marker_ +- _MmPlugin declines a plain WLED packet (no projectMM marker)_ +- _WledPlugin claims a plain WLED packet as WLED_ +- _WledPlugin declines a projectMM-marked packet (that's a peer, not a WLED)_ +- _Plugins decline a short / garbage datagram, never read out of bounds_ +- _WledPlugin tolerates an empty name (the module supplies the IP fallback)_ + +## DevicesModule `test/unit/core/unit_DevicesModule_ageout.cpp` -- _DevicesModule: a still-fresh device survives just under kStaleMs (24h)_ -- _DevicesModule: a device drops once past kStaleMs (24h)_ +- A cached (restored-but-never-re-heard) device is on a short probation, NOT the full 24 h — else a long-gone persisted device would survive forever across reboots (its clock resets to "boot" each restore). It drops once past kCachedGraceMs. +- _DevicesModule: a cached device drops once past the probation window_ +- A live-confirmed device (a presence packet cleared its `cached` flag) gets the full 24 h. +- _DevicesModule: a live-confirmed device drops once past kStaleMs (24h)_ +- A projectMM peer also answers as a plain WLED (its presence packet without our marker), so a later WLED-classified sighting must NOT relabel a restored projectMM row. This drives the downgrade-prevention in upsertDevice through the public path: restore the row as projectMM, inject a plain WLED packet from the same IP, confirm it stays projectMM. - _DevicesModule: restore tolerates an empty / malformed cache_ +`test/unit/core/unit_DevicesModule_discovery.cpp` +*Also touches: DevicePlugin.* + +- _DevicesModule: a plain WLED packet lists a WLED device with its name_ +- _DevicesModule: a projectMM-marked packet lists a projectMM device_ +- _DevicesModule: a short / garbage datagram is ignored, never listed_ +- The P4-bench bug: two DIFFERENT devices (a WLED and a projectMM peer) must each keep their OWN name + type — no cross-contamination between packets. +- A peer RENAME must propagate: a later packet from the same IP with a new name updates the row in place — the live-update requirement (the name rides the presence packet). +- A projectMM device stays projectMM even when a later plain-WLED packet arrives from the same address — the type only RAISES toward projectMM, never downgrades. (A projectMM peer could be seen via an unmarked packet too; that must not relabel it WLED.) + +`test/unit/core/unit_DevicesModule_hue.cpp` + +- _DevicesModule: a Hue bridge is listed with its colour count_ +- _DevicesModule: upsertHueBridge is idempotent, updates count in place_ +- _DevicesModule: a persisted Hue bridge restores as a Hue row with its count_ +- _DevicesModule: a corrupt persisted colour clamps to the valid range, row still restores_ + ## DistortionWavesEffect `test/unit/light/unit_DistortionWavesEffect.cpp` @@ -180,6 +185,13 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - Disabled child drivers don't tick: toggling `enabled` flips whether that driver's loop() runs. +`test/unit/light/unit_Drivers_firstOutputRgb.cpp` + +- _Drivers::firstOutputRgb reads pixel 0 of the driven buffer_ +- _Drivers::firstOutputRgb reports black pixel 0 as-is (caller substitutes the default)_ +- _Drivers::firstOutputRgb returns false when there is no driven buffer_ +- _MoonModule::firstOutputRgb defaults to false (no output module)_ + ## FilesystemModule `test/unit/core/unit_FilesystemModule_persistence.cpp` @@ -191,7 +203,7 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - Companion to the wiredByCode case above: when the JSON describes a different type at the position where a code-wired child lives, the position-replacement must NOT kill the code-wired child. Stop reconciliation at that index instead and let the next save re-write the file with the actual tree shape. When the saved JSON wants a different type at the position where a code-wired child lives, reconciliation stops at that index instead of destroying the wired child. - Round-trip persistence with children: write a Layer subtree that contains both controls and child modules with controls of their own, then read the file back as text and verify it parses as valid JSON. Regresses the missing-comma bug between each child's "N.type" field and that child's first control (e.g. "0.type":"X""0.foo":1 instead of "0.type":"X","0.foo":1). Saving a Layer with multiple children produces valid JSON — comma separators between child `N.type` and the child's first control field are present. - Singleton survives probe lifecycle: /api/types factory-creates a probe of every registered type (including FilesystemModule) to capture defaults, then deletes it. The probe's destructor must NOT clear the singleton — otherwise every save path (noteDirty, debounced loop1s, flushPending on reboot) silently no-ops for the rest of the device's life. The fix is to register the singleton in setScheduler(), not in the constructor. This test catches that singleton-clear regression. /api/types factory-creates a temporary FilesystemModule probe; its destruction must NOT clear the static singleton (otherwise every later save silently no-ops). -- Int16 controls preserve their saved value across a filesystem load — the load path does not clamp them to `c.min`/`c.max` (which are `uint8_t` and so default to 0,0, a range that can't represent an int16). Without this a 128×128 grid would reload as 0×0×0 and the pipeline would allocate no buffers; the test pins the round-trip so an Int16 value survives unclamped. +- Regression: Int16 controls (GridLayout's width/height/depth, Layer's start/end) round-tripped through the filesystem load path were clamped to c.min/c.max, which default to 0,0 because ControlDescriptor.min/max are uint8_t and can't represent an int16 range. Every Int16 control loaded as 0 — so a 128×128 grid became 0×0×0 after restart and the whole pipeline allocated no buffers. Int16 controls (GridLayout width/height, RegionModifier start/end) preserve their saved value across load — no zero-clamping from uint8 min/max bounds. ## FireEffect @@ -206,21 +218,7 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run `test/unit/core/unit_FirmwareUpdateModule.cpp` - The `firmware` control is always present and non-empty (either a real firmware key from build_info.h or the fallback "unknown"). The firmware card owns firmware identity (version/build/firmware) + the partition usage. - -## GameOfLifeEffect - -`test/unit/light/unit_GameOfLifeEffect.cpp` - -- Two cell grids of width × height bytes each. -- Disabling releases both grids (dynamicBytes drops to 0) via the parent lifecycle. -- A blinker (horizontal 3-in-a-row) oscillates with period 2 under B3/S23: it becomes a vertical 3-in-a-row, then back. Pins both birth (B3) and survival (S23) on a known pattern. -- A 2×2 block is a still-life: every live cell has 3 neighbours (S3), no dead cell has exactly 3 (no B3), so stepOnce leaves it unchanged. -- A lone cell dies (underpopulation: 0 neighbours, not S2/S3) → extinction. -- Wraparound: a blinker on the right edge stays a valid 3-cell pattern because neighbours wrap, rather than losing cells to a hard edge. -- Reallocation on dimension change: grids resize, byte count tracks new w×h. -- Must not crash on a zero-size grid (no allocation, loop is a no-op). -- bpm time-gates the generation rate: a low bpm advances fewer generations per unit time than a high bpm over the same elapsed window. Drives time via the desktop millis() test seam (Layer reads platform::millis in loop()). -- Regression: the Layer clears the buffer before every effect frame, so the grid must be re-painted on EVERY frame, not just on the (rarer) beats where a generation advances. A bpm gate that skipped the paint left non-step frames black — visible as "a flash now and then" at low bpm. Drive several frames at a slow bpm (most are non-step) and require the buffer stays lit on all of them. +- OTA phase is surfaced through the shared status slot (MoonModule::setStatus()), not a control. publishStatus() runs in setup()/loop1s() and maps the platform OTA status string to a severity: "idle" clears the banner, an "error: " prefix is Severity::Error, anything else is neutral Severity::Status. ## GridLayout @@ -244,6 +242,16 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - _apply-core: applyOp dispatches each op type and tolerates bad input_ - A per-control validator (like SystemModule.deviceModel's printable-ASCII rule) is enforced THROUGH the apply-core — so the APPLY_OP `set` the installer pushes over serial is guarded exactly like an HTTP write, with no per-transport special-casing. This is the point of moving validation onto the control: one backend check, every path. +## HueDriver + +`test/unit/light/unit_HueDriver.cpp` + +- _HueDriver: a coloured pixel becomes an on/bri/hue/sat state body_ +- _HueDriver: a black pixel becomes on:false_ +- _HueDriver: RGB→HSV maps the primaries to the right Hue wheel positions_ +- _HueDriver: unchanged colour is not resent, a changed one is_ +- _HueDriver: parseLights keeps only colour-capable, reachable lights_ + ## ImprovFrame `test/unit/core/unit_ImprovFrame.cpp` @@ -291,24 +299,40 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - _overflow safety: too many nodes fails cleanly_ - _overflow safety: nesting deeper than kMaxDepth fails cleanly_ - _input longer than the text buffer fails cleanly_ +- parseString must DECODE the JSON string escapes our own writer emits (JsonSink/writeJsonString) — \" \\ \n \r \t \b \f — so reader and writer are symmetric. A multi-line value (a script with `\n`) must arrive as a real newline, not a literal backslash-n. ## Layer `test/unit/light/unit_Layer_extrude.cpp` -*Also touches: RainbowEffect, NoiseEffect, PlasmaEffect, CheckerboardEffect, FireEffect, ParticlesEffect.* +*Also touches: RainbowEffect, NoiseEffect, PlasmaEffect, SpiralEffect, FireEffect, ParticlesEffect.* - A D2 effect (Rainbow) on a 3D layer writes z=0 once; Layer::extrude copies that slice across every z>0 — slices are byte-identical. -- A D1 effect writes row y=0,z=0; extrude duplicates that row across every y and every z-slice. +- A D1 effect writes the x=0 column; extrude duplicates it across every x and every z-slice. - NoiseEffect declared D3 still produces a valid image on a depth=1 layer (it honours the runtime depth instead of hardcoding z). - PlasmaEffect (D3) on a 2D layer same contract: valid 2D image, no buffer overrun. - NoiseEffect (D3) on a 1D layer (height=depth=1) writes a valid strip and never overflows. - PlasmaEffect (D3) on a 1D layer same contract: valid 1D strip, no overflow. -- CheckerboardEffect (D2) on a 3D layer: extrude copies z=0 to every z>0 (stateless D2 contract). +- SpiralEffect (D2) on a 3D layer: extrude copies z=0 to every z>0 (stateless D2 contract). - FireEffect (D2, stateful — heat buffer sized to w×h) extrudes cleanly across z on a 3D layer. - ParticlesEffect (D2, stateful — trail sized to w×h×cpl) extrudes cleanly across z on a 3D layer. +`test/unit/light/unit_Layer_live_modifier.cpp` +*Also touches: RotateModifier, ModifierBase.* + +- With a Rotate present, the live pass rotates the gradient each frame as the angle advances — so two frames at different times differ. A static GradientEffect alone would produce identical frames, so any difference is the live remap. +- PAY-FOR-WHAT-YOU-USE: a Layer with no live modifier must NOT run the live pass — the static gradient is byte-identical across frames regardless of the clock. +- A DISABLED Rotate must not run the live pass either (the gate keys off ENABLED live modifiers). Same static gradient → identical frames. +- COALESCED REBUILD: two beat-driven modifiers (RandomMap) on one Layer both ask for a rebuild on a beat; Layer::loop() must rebuild ONCE (not re-enter onBuildState per modifier) and the Layer must stay valid — the composed mapping changes, no crash. + +`test/unit/light/unit_Layer_modifier_chain.cpp` +*Also touches: ModifierBase.* + +- Region (left half) THEN Multiply (2× mirror): the logical box folds twice. On a 16-wide axis: Region 0..50 → 8, then Multiply 2 → 4. Both modifiers apply — the second is no longer dead weight. +- Order matters: Region-then-Multiply differs from Multiply-then-Region. Region's percentage applies to whatever box it sees, so the composed logical size differs. +- A DISABLED middle modifier is skipped — the chain folds only the enabled ones. + `test/unit/light/unit_Layer_phase_animation.cpp` -*Also touches: MetaballsEffect, CheckerboardEffect, LavaLampEffect, SpiralEffect.* +*Also touches: MetaballsEffect, SpiralEffect, LavaLampEffect, SpiralEffect.* - Metaballs visibly changes over 100ms even when per-tick dt is sub-millisecond (no phase-accumulator truncation). - Checkerboard advances at desktop speed (cells flip across 100ms). @@ -323,20 +347,18 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - Sparse sphere: a LUT is built; its destinations are driver indices in [0, lightCount), and the render buffer stays the dense bounding box. - Sphere + Mirror: the modifier's box-coordinate destinations are translated into driver-index space; no destination escapes [0, lightCount). - REGRESSION: a high fan-out Multiply (8×8×4 = 256) on a 128×128 grid must build a NON-EMPTY LUT that covers every physical light. The maxDest estimate (logicalCount × maxMultiplier) is computed in 64-bit; before that fix it overflowed uint16 on no-PSRAM boards (256 × 256 = 65536 wraps to 0), sized the LUT to ~nothing, and blanked the display. Here we assert the LUT actually maps the full light set, in range — the symptom that black-screened the device. +- Region carving: a RegionModifier shrinks the Layer's LOGICAL box to the region (so the effect renders only there), and the LUT maps each region cell to its box cell at the start offset — every destination in range, none outside the region. The driver buffer still holds all physical lights; cells outside the region simply get no logical source (dark). Default 0/100 = full box (the no-carve fast path) is covered by unit_RegionModifier; here we carve a quarter. `test/unit/light/unit_Layer_zero_grid.cpp` -*Also touches: RainbowEffect, NoiseEffect, PlasmaEffect, CheckerboardEffect, SpiralEffect, MetaballsEffect, PlasmaPaletteEffect, RingsEffect, RipplesEffect, GlowParticlesEffect, LavaLampEffect, FireEffect, ParticlesEffect.* +*Also touches: RainbowEffect, NoiseEffect, PlasmaEffect, SpiralEffect, MetaballsEffect, RingsEffect, RipplesEffect, LavaLampEffect, FireEffect, ParticlesEffect.* - Rainbow on 0,0,0 grid: no crash. - Noise on 0,0,0 grid: no crash. - Plasma on 0,0,0 grid: no crash. -- Checkerboard on 0,0,0 grid: no crash. - Spiral on 0,0,0 grid: no crash. - Metaballs on 0,0,0 grid: no crash. -- PlasmaPalette on 0,0,0 grid: no crash. - Rings on 0,0,0 grid: no crash. - Ripples on 0,0,0 grid: no crash. -- GlowParticles on 0,0,0 grid: no crash. - LavaLamp on 0,0,0 grid: no crash. - Fire on 0,0,0 grid: no heat buffer allocated, no crash. - Particles on 0,0,0 grid: no trail buffer allocated, no crash. @@ -352,6 +374,7 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - Disabling the top layer drops cleanly to the single (bottom) layer — no crash, the driver now sees the bottom layer's content. Pins the robustness path. - Drivers' composition/output-buffer allocation contract (architecture.md § Adaptive allocation). The driver output buffer exists ONLY when the pipeline must blend into physical space; otherwise the lone layer's buffer is handed to drivers directly (zero-copy). dynamicBytes() reflects outputBuffer_.bytes(), so it's 0 ⇔ no buffer. Pins all three cases in one place: 1. one identity (no-LUT) layer → NO output buffer (zero-copy) 2. two enabled layers → output buffer (must composite) 3. one layer WITH a LUT → output buffer (must map logical→physical) - activeLayer() returns the first enabled child, or the only child if all are disabled (so dimensions stay queryable during boot/toggle-off). +- firstEnabledLayer() is the output-selection counterpart to activeLayer(): it never falls back to a disabled layer, so it returns nullptr exactly when nothing renders. - If the container holds only non-Layer children, activeLayer() returns nullptr (the role-guard skips, never miscasts). ## Layouts @@ -427,6 +450,47 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - typeName/typeRole with an out-of-range index returns nullptr / Generic safely (never UB). - The factory grows its registry capacity dynamically — registering 10+ extra types past the initial size still works and every name stays discoverable. +## MoonLive + +`test/unit/core/unit_moonlive_compiler.cpp` + +- _compileSource: fill(r,g,b) fills every light_ +- _compileSource: setRGB(index, r,g,b) writes one pixel_ +- REMARK #1: every argument is an expression — random16 in ANY slot. +- REMARK #2: a literal / random16 bound may be a uint16 (0..65535), not capped at 255. +- _compileSource: out-of-range index is bounds-rejected at runtime_ +- _compileSource rejects malformed programs with a diagnostic, never crashes_ +- _MoonLive.compile(source) on a bad script leaves the engine !ok with an error_ +- VREG REUSE: a chain of calls must fit the small device register file. Each argument temp dies once its call consumes it and is recycled, so peak register pressure stays low no matter how many calls a statement nests — setRGB with all four arguments a random16 still compiles. +- DOMAIN-NEUTRAL: the core compiler owns no function names. With an EMPTY table it knows nothing — `setRGB`/`fill`/`random16` are all "unknown function". The LED vocabulary lives only in the host's table; a different host registers different names. (Remark #3.) +- _MoonLive recompiling swaps the program live (fill <-> setRGB)_ +- STAGE 1 CONTROLS — parse layer: a `uint8_t name = def; // @control min..max` declaration surfaces a DeclaredControl, and a declared name used in a statement resolves to it. +- _compileSource: malformed control declarations fail with a diagnostic, never crash_ + +`test/unit/core/unit_moonlive_fill.cpp` + +- _MoonLive emitFill produces a non-empty routine_ +- _MoonLive emitFill rejects a too-small buffer (degrades, no overrun)_ +- _MoonLive emitFill/emitAnimatedFill reject a null output buffer (no crash)_ +- _MoonLive compiles and fills a buffer with the chosen colour_ +- _MoonLive run on zero lights writes nothing (robust to empty)_ +- The native routines write channels +0/+1/+2 per light, so a layer with fewer than 3 channels per light can't hold RGB — run() must leave it untouched, not overrun it. +- _MoonLive recompile swaps the colour; free returns to !ok_ +- _MoonLive animated fill derives colour from the per-frame t_ +- _platform allocExec returns usable executable memory, freeExec releases it_ +- _MoonLive controls: declaredControls + controlSlot seeded from the default_ +- _MoonLive controls: arena address is STABLE across a recompile and the slot value survives_ +- _MoonLive controls: free() releases the arena (no stale slot after teardown)_ + +`test/unit/core/unit_moonlive_ir.cpp` + +- _MoonLive compiled fill is BEHAVIORALLY identical to the hand-encoded emitFill (golden)_ +- _MoonLive compiled fill is robust: zero lights writes nothing_ +- _MoonLive compileSource degrades on a too-small code buffer_ +- _MoonLive compiled setRGB writes one pixel; out-of-range is bounds-rejected_ +- _MoonLive control: a declared control reads the arena live (no recompile on value change)_ +- _MoonLive control survives a host call (kArg4 live across random16)_ + ## MoonModule `test/unit/core/unit_MoonModule.cpp` @@ -481,19 +545,16 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run `test/unit/light/unit_MultiplyModifier.cpp` -- Reports D3 — handles all three axes. Pins the ModifierBase default too. -- Defaults (multiply 2/2/1, mirror true/true/false) reproduce the canonical mirror-XY pipeline: a 128×128 physical grid → 64×64 logical (each axis folds). -- multiplyZ tiles the Z axis too: 128×128×4 with multiply 2/2/2 → 64×64×2. -- PURE-FOLD EQUIVALENCE: with the defaults (mult 2, mirror XY), the corner logical pixel (0,0) fans out to all four physical corners — byte-identical to the old MirrorModifier corner test. This is the canonical-pipeline guarantee. -- PURE-FOLD EQUIVALENCE: an interior pixel folds to the same two columns the old mirrorX-only produced — original + horizontal reflection. -- No multiplication on any axis (all multipliers 1) → identity pass-through. -- Tiling WITHOUT mirror repeats (does not reflect) — multiply 2 on X, mirror off: logical x=0 lands at physical x=0 (tile 0) and x=64 (tile 1, identity offset), NOT x=127. This is the difference from a fold. -- multiplyZ on a 2D (depth-1) layout is a no-op: the effective multiplier clamps to the axis extent (1), so logD stays 1 and the layer isn't blanked. Before the clamp, multiplyZ=4 made logD = 1/4 = 0 → empty layer. -- A multiplier larger than the axis extent clamps to the extent (can't tile more times than there are pixels). -- maxMultiplier is the product of the raw controls (the fan-out upper bound). -- REGRESSION: maxMultiplier() must NOT wrap when all axes are maxed. The product 64×64×16 = 65536 overflows nrOfLightsType (uint16 on no-PSRAM) and would wrap to 0 — feeding the uint64 maxDest math in Layer::rebuildLUT an already-wrapped (possibly 0) multiplier → empty LUT → black display. It must saturate to the type max instead. (Single-axis tests above stay under the wrap; this one crosses it.) On uint32 (PSRAM) the product fits and isn't saturated — assert only the non-wrap, non-zero invariant that holds on both widths. -- REGRESSION: an 8×8 multiply must emit all 64 tile positions, not be truncated to 8. The Layer's scratch buffer is sized to ModifierBase::kMaxFanout (64); a smaller buffer (the original physicals[8]) silently dropped 56 of the 64 tiles, so a 128×128 grid showed only 8 tiles instead of the full 8×8 = 64. -- Fan-out never exceeds maxOut even if asked for more than the buffer holds. +- _MultiplyModifier advertises D3 dimensions_ +- Defaults (multiply 2/2/1) → a 128×128 physical grid folds to a 64×64 logical box. +- _MultiplyModifier logical size on Z_ +- FAN-OUT (fold direction): with the defaults (mult 2, mirror XY), all four physical CORNERS fold onto the single logical pixel (0,0) — the inverse of the old "logical (0,0) → 4 physical corners". This is the kaleidoscope fold made concrete. +- mirrorX only: two physical columns fold to the same logical column (original + its horizontal reflection). The logical box is 64 wide. +- All multipliers 1 → identity: the box is unchanged and every coord folds to itself. +- Tiling WITHOUT mirror repeats (does not reflect): physical x=64 (tile 1) folds to logical x=0, same as physical x=0 — both tiles map identically, no reflection. +- multiplyZ on a 2D (depth-1) layout is a no-op: the effective multiplier clamps to the axis extent (1), so depth stays 1 and the layer isn't blanked. +- A multiplier larger than the axis extent clamps to the extent. +- REGRESSION (🐇): a non-divisible extent leaves a leftover edge strip that the tiles don't cover — those pixels must be DROPPED, not wrapped back into a tile (which would duplicate the edge). 5-wide, multiply 2 → tile width 2, covers pixels 0..3; pixel 4 is the leftover and has no tile. ## NetworkModule @@ -573,6 +634,17 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - With depth > 1, adjacent and distant z-slices each render differently (3D noise, not a stack of identical 2D slices). - Same z-slice variation requirement holds for Plasma — each depth plane renders differently. +## Palette + +`test/unit/light/unit_Palette.cpp` + +- _Palette: gradient endpoints land on the first/last stop colours_ +- _Palette: a mid-gradient sample interpolates between stops_ +- _Palette: colorFromPalette index 0 reads entry 0; brightness scales_ +- _Palette: the index wraps at 255→0 (no out-of-range read)_ +- _Palette: a degenerate (empty) gradient is all black, never out-of-bounds_ +- _Palettes::active swaps the global palette on setActive_ + ## ParlioLedDriver `test/unit/light/unit_ParlioLedDriver.cpp` @@ -640,16 +712,30 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run `test/unit/light/unit_RandomMapModifier.cpp` *Also touches: Layer.* -- A remap doesn't resize the logical box. -- _RandomMapModifier maxMultiplier is 1_ -- The core property: the mapping is a true bijection over [0, w*h*d) — every destination index appears exactly once (no gaps, no duplicates). -- A fresh modifier with the same generation produces the same permutation (deterministic seed → reproducible, which is what makes it testable). -- Reshuffling (a beat) changes the mapping, and the result is still a bijection. -- Robustness: an empty (0×0×0) grid must not crash — maxOut 0 yields no destination. -- A resize (different box count) rebuilds the permutation to the new size, still a bijection. +- A remap leaves the logical box unchanged. +- The core property: a true bijection over [0, w*h*d) — every destination index appears exactly once (no gaps, no duplicates). +- Deterministic seed → reproducible permutation (what makes it testable). +- Reshuffling (a beat) changes the mapping, still a bijection. +- Robustness: an empty (0×0×0) box must not crash — it folds to a no-op. +- A resize (different box count) rebuilds the permutation to the new size. - _RandomMapModifier loop() reshuffles on a beat (bpm 60 ≈ 1/s)_ - _RandomMapModifier loop() with bpm 0 never reshuffles (frozen)_ +## RegionModifier + +`test/unit/light/unit_RegionModifier.cpp` + +- Default region (0/100 on every axis) is the full box: identity size, no rejection. +- Half of an axis, half-open: end=50 on 128 → region width 64, not 65. +- Two abutting regions tile a 128-wide axis with no overlap and no gap. +- A physical coord inside the region folds to region-local (subtract the start pixel); a coord outside is rejected. +- Rounding rule on a small panel: start floors, end ceils to an exclusive pixel. start 33 / end 66 on a 4-wide axis → floor(1.32)=1 .. ceil(2.64)=3 → pixels 1,2. +- A region that rounds to nothing still gets a 1-pixel floor. +- OFF-SCREEN: a window slid half off the left edge keeps its FULL size (the effect renders at a fixed scale); only the visible half maps to physical lights. startX=-50 on 64 → window [−32, 32), span 64. Physical x 0..31 land at window-local 32..63 (the right half of the window — the visible part); the left half of the window (0..31) has no physical light, so it's dark. The effect isn't rescaled. +- A window entirely off the box maps NO lights — the layer goes dark on that axis, which is how an effect is moved completely out of view. The box still has a valid size (the effect renders), nothing just reaches the screen. +- A window stretched WIDER than the box (start<0 and end>100) renders the full span; the box shows the middle slice. startX=-50,endX=150 on 64 → window [−32, 96), span 128. +- Degenerate axes don't crash: a 1-wide axis stays 1, a 0-extent axis yields 0. + ## RmtLedDriver `test/unit/light/unit_RmtLedDriver_lifecycle.cpp` @@ -685,6 +771,10 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - _RmtLedDriver idles with a status error on a bad pin list_ - _RmtLedDriver with the empty default pins idles cleanly (no pin assumed)_ - _RmtLedDriver re-slices when the source buffer changes_ +- _RmtLedDriver window: ledsPerPin distributes over the window, not the whole buffer_ +- _RmtLedDriver window: count 0 means the rest of the buffer from start_ +- _RmtLedDriver window: a size-1 window at 0 is the onboard-LED case_ +- _RmtLedDriver window: a start past the buffer end yields an empty slice_ - loop() is a safe no-op across single-pin, multi-pin and zero-grid configs. `test/unit/light/unit_RmtLedEncoder.cpp` @@ -699,11 +789,10 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run `test/unit/light/unit_RotateModifier.cpp` -- _RotateModifier logicalDimensions are identity_ -- _RotateModifier maxMultiplier is 1_ -- At the initial angle (0) the rotation is identity — every light maps to itself. -- Every emitted destination is in range (no out-of-bounds index), and the count is always 0 or 1 (a remap never fans out). -- _RotateModifier tolerates an empty grid_ +- _RotateModifier advertises a live (per-frame) modifier_ +- At the initial angle (0) the rotation matrix is the identity — every cell samples itself. +- z passes through (2D rotation) — a 3D coord's z is untouched. +- An empty box doesn't divide-by-zero or wrap: the remap is a no-op-ish transform that the Layer's live pass then treats as out-of-box (dark), never a crash. ## Scheduler @@ -746,6 +835,18 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - Physical indices are sequential 0..N-1 over the emitted shell points (no gaps from the unindexed lattice voids), so the buffer maps 1:1 to emitted lights. - Default radius is a sensible small sphere (not 0, not huge). +## SpiralEffect + +`test/unit/light/unit_effects_render.cpp` +*Also touches: RingsEffect, RipplesEffect, LavaLampEffect.* + +- LavaLampEffect has localised blob features that can land on identical corner palette indices at some t values (corner-pair check is too strict). Scan the whole buffer for any two distinct pixels instead — same approach as RingsEffect below. LavaLamp paints at least one non-zero byte (effect actually renders). +- Across 10 frames at bpm=60, at least one frame shows two distinct colours somewhere in the buffer (blobs move and the field varies). +- RingsEffect has localised features (thin rings); corner-pair check is too strict, so we scan for any two distinct pixels instead. Rings paints at least one non-zero byte (effect actually renders). +- At least two distinct pixels exist somewhere in the buffer (rings are localised, so corner-pair would be too strict). +- RipplesEffect (MoonLight sine-wave water surface) lights one pixel per column at a sine-driven height. On a flat 2D layer it still paints a visible wavefront — assert it renders something and varies across the surface. +- Ripples lights one pixel per column at a sine-driven height, so the surface holds at least two distinct colours (wavefront vs background) — scan the whole buffer, corner-pair would be too strict. + ## SystemModule `test/unit/core/unit_SystemModule.cpp` @@ -769,6 +870,17 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - _sanitizeHostname trims leading and trailing dashes / invalid runs_ - _sanitizeHostname yields empty for all-invalid input (caller falls back)_ +## WaveEffect + +`test/unit/light/unit_WaveEffect.cpp` + +- _WaveEffect: sawtooth ramps 0→top across the phase_ +- _WaveEffect: triangle peaks in the middle and returns_ +- _WaveEffect: sine sits mid at the zero crossings_ +- _WaveEffect: square is low then high_ +- _WaveEffect: every type stays within the grid bounds_ +- _WaveEffect: a zero-height grid never reads out of bounds_ + ## WheelLayout `test/unit/light/unit_WheelLayout.cpp` @@ -778,6 +890,25 @@ Unit tests are the fastest tier in the [test strategy](../testing.md): they run - _WheelLayout coordinates are non-negative (centre-shifted into address space)_ - _WheelLayout different spoke counts give different layouts_ +## WledPacket + +`test/unit/core/unit_WledPacket.cpp` + +- _WledPacket::build produces a valid WLED header (token/id/size)_ +- _WledPacket::readName round-trips the device name_ +- _WledPacket marker is set only when stamped, and stays WLED-valid_ +- _WledPacket::isValid rejects short / wrong-magic / null input_ +- _WledPacket::readName truncates a long name to the buffer, never overruns_ + +## light_types + +`test/unit/light/unit_Coord3D.cpp` + +- _Coord3D arithmetic is per-axis_ +- _Coord3D modulo and divide fold per axis_ +- _Coord3D % and / guard a zero or degenerate axis_ +- _Coord3D equality_ + ## platform `test/unit/core/unit_platform_clock.cpp` diff --git a/scripts/check/check_specs.py b/scripts/check/check_specs.py index a0fbe30b..b9814cac 100644 --- a/scripts/check/check_specs.py +++ b/scripts/check/check_specs.py @@ -50,11 +50,37 @@ def find_moonmodules(): modules.append(h_file) return modules +# Effects, modifiers, and the leaf layouts (Grid/Sphere/Wheel) document themselves as one +# compact-row page per type rather than a file per module (docs consolidation — see the +# folder-structure decision). A module of one of these types is documented on its shared page; +# every other module keeps a per-module page named for the type. Keyed by type-name suffix so a +# new effect/modifier/layout is folded in automatically. (Layouts/Layers/Drivers are CONTAINERS, +# not leaf layouts — they keep their own per-module page, so they are excluded below.) +CONSOLIDATED_PAGES = { + "Effect": SPECS / "light" / "effects" / "effects.md", + "Modifier": SPECS / "light" / "modifiers" / "modifiers.md", + "Layout": SPECS / "light" / "layouts" / "layouts.md", +} + + def find_spec(module_path): - """Find the matching spec .md file for a source .h file.""" + """Find the matching spec .md for a source .h. + + A module whose type name ends in Effect/Modifier/Layout is documented on the shared + per-type page (its row must carry every control name — checked by check_spec_freshness). + Everything else uses the per-module page (stem match), as before. + """ name = module_path.stem # e.g. "NoiseEffect" - # Search all spec directories + # MoonLive is a live-script module under light/moonlive/, not a normal effect — it keeps its + # own page despite the *Effect suffix. Only the per-type folders consolidate. + in_moonlive = "moonlive" in module_path.parts + if not in_moonlive: + for suffix, page in CONSOLIDATED_PAGES.items(): + if name.endswith(suffix): + return page if page.exists() else None + + # Per-module page: match by filename stem anywhere under docs/moonmodules/. for md in SPECS.rglob("*.md"): if md.stem == name: return md diff --git a/scripts/docs/screenshot_modules.py b/scripts/docs/screenshot_modules.py index 4d086772..b15d5e68 100644 --- a/scripts/docs/screenshot_modules.py +++ b/scripts/docs/screenshot_modules.py @@ -76,11 +76,16 @@ # Map a module to its asset subfolder (domain/type), mirroring src. Module screenshots live in # docs/assets/{core, light/{effects,modifiers,layouts,drivers}}/ — see folder-structure-proposal. def asset_dir_for(type_name: str) -> Path: - if type_name.endswith("Effect"): return ASSETS / "light" / "effects" - if type_name.endswith("Modifier"): return ASSETS / "light" / "modifiers" - if type_name.endswith("Layout"): return ASSETS / "light" / "layouts" - if type_name.endswith("Driver"): return ASSETS / "light" / "drivers" - if type_name in ("Layouts", "Layers", "Drivers"): return ASSETS / "light" + if type_name.endswith("Effect"): + return ASSETS / "light" / "effects" + if type_name.endswith("Modifier"): + return ASSETS / "light" / "modifiers" + if type_name.endswith("Layout"): + return ASSETS / "light" / "layouts" + if type_name.endswith("Driver"): + return ASSETS / "light" / "drivers" + if type_name in ("Layouts", "Layers", "Drivers"): + return ASSETS / "light" return ASSETS / "core" # SystemModule, FilesystemModule, DevicesModule, … and the rest # --------------------------------------------------------------------------- diff --git a/scripts/docs/update_module_docs.py b/scripts/docs/update_module_docs.py index 7105d0a9..34db0d43 100644 --- a/scripts/docs/update_module_docs.py +++ b/scripts/docs/update_module_docs.py @@ -33,11 +33,16 @@ # A module's asset subfolder (domain/type), mirroring src — see folder-structure-proposal.md. def asset_dir_for(type_name: str): - if type_name.endswith("Effect"): return ASSETS / "light" / "effects" - if type_name.endswith("Modifier"): return ASSETS / "light" / "modifiers" - if type_name.endswith("Layout"): return ASSETS / "light" / "layouts" - if type_name.endswith("Driver"): return ASSETS / "light" / "drivers" - if type_name in ("Layouts", "Layers", "Drivers"): return ASSETS / "light" + if type_name.endswith("Effect"): + return ASSETS / "light" / "effects" + if type_name.endswith("Modifier"): + return ASSETS / "light" / "modifiers" + if type_name.endswith("Layout"): + return ASSETS / "light" / "layouts" + if type_name.endswith("Driver"): + return ASSETS / "light" / "drivers" + if type_name in ("Layouts", "Layers", "Drivers"): + return ASSETS / "light" return ASSETS / "core" SCREENSHOT_RE = re.compile(r'!\[.*?\]\(.*?assets/.*?\.(?:png|jpe?g)\)') diff --git a/scripts/moondeck.py b/scripts/moondeck.py index 0d744e80..11cc8d31 100644 --- a/scripts/moondeck.py +++ b/scripts/moondeck.py @@ -1633,6 +1633,42 @@ def _link_tag(m): s = re.sub(r'(?\1', s) return s + def _render_cell(c: str) -> str: + """Render one table cell. The compact module pages (effects/modifiers/layouts) + use raw previews and row anchors inside cells — + two tags GitHub/VS Code honor but the default escape path would turn to literal + text. Pass those two through (resolving an src to /api/doc-asset/ like the + markdown-image path does); escape + inline-render the rest.""" + def _img(m): + src_ = m.group("src"); width = m.group("w"); style = m.group("style") + if not src_.startswith(("http://", "https://", "/")): + abs_src = (md_path.parent / src_).resolve() + try: + src_ = str(abs_src.relative_to(ROOT.resolve())) + except ValueError: + pass + src_ = f"/api/doc-asset/{src_}" + wattr = f' width="{width}"' if width else "" + # Preserve an author-set width style (the cross-renderer size lever) and append our + # margin so the preview isn't flush against the cell edges. + style = (style + ";" if style else "") + "margin:4px 0" + return f'' + # No raw img/anchor → ordinary escaped+inline cell (the common case). + if "]*>', + lambda m: _stash(_img(m)), c) + c = re.sub(r'', lambda m: _stash(f''), c) + out = render_inline(html_mod.escape(c)) + for i, html in enumerate(tokens): + out = out.replace(f"\x00{i}\x00", html) + return out + def close_list_if_open(): nonlocal in_list if in_list: @@ -1706,7 +1742,7 @@ def _heading_slug(text: str) -> tuple[str, str]: # CSS handle the first-row styling. cell_tag = "td" cell_html = "".join( - f"<{cell_tag}>{render_inline(html_mod.escape(c))}" + f"<{cell_tag}>{_render_cell(c)}" for c in cells ) lines.append(f"{cell_html}") diff --git a/src/core/Control.cpp b/src/core/Control.cpp index 3a77774a..333af7db 100644 --- a/src/core/Control.cpp +++ b/src/core/Control.cpp @@ -33,6 +33,7 @@ const char* controlTypeName(ControlType t) { case ControlType::ReadOnly: return "display"; case ControlType::ReadOnlyInt: return "display-int"; case ControlType::Select: return "select"; + case ControlType::Palette: return "palette"; case ControlType::Progress: return "progress"; case ControlType::IPv4: return "ipv4"; case ControlType::List: return "list"; @@ -102,8 +103,9 @@ void writeControlValue(JsonSink& sink, const ControlDescriptor& c) { sink.appendf("%d", *static_cast(c.ptr)); return; case ControlType::Select: - // The selected index — the option strings go in the metadata - // block (writeControlMetadata) where the UI also wants them. + case ControlType::Palette: + // The selected index — the option strings / swatch colours go in the + // metadata block (writeControlMetadata) where the UI also wants them. sink.appendf("%u", *static_cast(c.ptr)); return; case ControlType::Progress: @@ -169,6 +171,14 @@ void writeControlMetadata(JsonSink& sink, const ControlDescriptor& c) { sink.append("]"); return; } + case ControlType::Palette: { + // The light domain supplies the option objects ({name, colors}) via the function + // pointer in `aux` — core stays palette-agnostic. Falls back to an empty array. + sink.append(",\"options\":["); + if (c.aux) reinterpret_cast(c.aux)(sink); + sink.append("]"); + return; + } case ControlType::Progress: // `bytes` (in min, see addProgress): 1 → KB label, 0 → plain count. sink.appendf(",\"total\":%lu,\"bytes\":%s", static_cast(c.aux), @@ -296,7 +306,8 @@ ApplyResult applyControlValue(const ControlDescriptor& c, mm::json::parseString(json, key, static_cast(c.ptr), maxLen); return ApplyResult::Ok; } - case ControlType::Select: { + case ControlType::Select: + case ControlType::Palette: { int v = mm::json::parseInt(json, key); const int hi = c.max > 0 ? c.max - 1 : 0; if (policy == ApplyPolicy::Strict && (v < 0 || v > hi)) { diff --git a/src/core/Control.h b/src/core/Control.h index a9524e15..59687a9b 100644 --- a/src/core/Control.h +++ b/src/core/Control.h @@ -126,16 +126,26 @@ enum class ControlType : uint8_t { // "control holds a void* into module-owned data" shape every addX() // uses, one level up. (Data-over-objects: no per-row object graph, // no allocation on rebuild — see docs/architecture.md hot-path.) - Button // a momentary action, not a stored value. The UI renders a button; + Button, // a momentary action, not a stored value. The UI renders a button; // a click POSTs a value and the module's onUpdate() runs the action. // No backing storage (ptr unused) and non-persistable — distinct // from Bool, which is an on/off STATE that renders as a toggle and a // toggle is the wrong affordance for "do this now" (e.g. rescan). + Palette // a colour-palette dropdown (ptr → uint8_t index). Like Select, but + // each option carries its gradient *colours* (16 hex stops) so the UI + // renders a gradient swatch per option, not just a name. The light + // domain supplies the names + swatches via the Palette type; the wire + // shape (options:[{name,colors}]) is serialized in writeControlMetadata. }; // Forward-declared (defined below the enum) so the descriptor can hold a pointer. class JsonSink; +// A ControlType::Palette control's options come from the light domain (it owns the palette set +// and the swatch colours). The descriptor's `aux` holds a pointer to this function; core calls it +// to emit the `"options":[{"name":…,"colors":…}, …]` array — core stays palette-agnostic. +using PaletteOptionsFn = void (*)(JsonSink& sink); + // Backing for a ControlType::List control. The module that owns the data (e.g. // DevicesModule over its device array) implements this; the control descriptor's // `ptr` points at the implementation. Serialization (writeControlValue) walks @@ -294,6 +304,13 @@ class ControlList { ControlType::ReadOnlyInt, 0, 0}; } + // A colour-palette dropdown: like a Select (ptr → uint8_t index, max = optionCount), but the + // options carry swatch colours. `optionsFn` (light-domain) emits the {name,colors} objects. + void addPalette(const char* name, uint8_t& var, PaletteOptionsFn optionsFn, uint8_t optionCount) { + grow(); + controls_[count_++] = {&var, name, reinterpret_cast(optionsFn), ControlType::Palette, 0, optionCount}; + } + void addSelect(const char* name, uint8_t& var, const char* const* options, uint8_t optionCount) { grow(); controls_[count_++] = {&var, name, reinterpret_cast(options), ControlType::Select, 0, optionCount}; diff --git a/src/core/DevicesModule.h b/src/core/DevicesModule.h index f843a035..7db9ee94 100644 --- a/src/core/DevicesModule.h +++ b/src/core/DevicesModule.h @@ -158,8 +158,12 @@ class DevicesModule : public MoonModule, public ListSource { if (!d->name[0]) { formatDottedQuad(d->name, ip); persistChanged = true; } if (d->colourCount != colour) { d->colourCount = colour; persistChanged = true; } d->lastSeenMs = platform::millis(); // transient — keeps the bridge from ageing out + // A cached row coming (back) online is a status change even with no persisted field edit — + // refresh on that transition too, else a re-announced bridge stays greyed-out in the UI. + const bool wasCached = d->cached; d->cached = false; - if (persistChanged) { sortByName(); refreshStatus(); } + if (persistChanged) sortByName(); // re-sort only on a real persisted change + if (persistChanged || wasCached) refreshStatus(); } void setup() override { diff --git a/src/light/Palette.h b/src/light/Palette.h new file mode 100644 index 00000000..f43812c0 --- /dev/null +++ b/src/light/Palette.h @@ -0,0 +1,167 @@ +#pragma once + +#include "core/color.h" // RGB, scale8, hsvToRgb +#include "core/JsonSink.h" // paletteOptions emits the dropdown {name,colors} objects + +#include +#include + +namespace mm { + +// A colour palette: the active palette is 16 evenly-spaced RGB entries (the CRGBPalette16 model), +// and colorFromPalette() reads a 0-255 wheel index by interpolating between the two bracketing +// entries. The gradient definitions (a {pos,R,G,B,…} stop list) live in flash and expand into the +// 16 entries on selection, off the hot path; the per-light lookup is then a single scale8 blend. +// +// Prior art: FastLED's gradient palettes (CRGBPalette16 / ColorFromPalette), the convention WLED + +// MoonLight share — the recognisable names + model are carried; this implementation is our own, on +// our RGB/scale8. The gradient *data* in kBuiltinPalettes is from MoonLight's palettes.h (a public +// palette set), reformatted; see docs/backlog/moonlight-palettes-data.md. +struct Palette { + static constexpr uint8_t kEntries = 16; + RGB entry[kEntries] = {}; + + // Build the 16 entries from a gradient-stop list: {pos0,R,G,B, pos1,R,G,B, …} with pos 0..255, + // ascending, ending at 255. Each of the 16 evenly-spaced sample positions is the linear blend + // of the two stops it falls between. Off the hot path (called on selection). + void fromGradient(const uint8_t* stops, size_t count) { + const size_t nStops = count / 4; + if (nStops == 0) { for (auto& e : entry) e = {0, 0, 0}; return; } + for (uint8_t i = 0; i < kEntries; i++) { + // The sample position for entry i, spread 0..255 across the 16 entries. + const uint8_t pos = static_cast((static_cast(i) * 255) / (kEntries - 1)); + entry[i] = sampleGradient(stops, nStops, pos); + } + } + +private: + // The colour at `pos` (0..255) on the gradient: find the bracketing stops and lerp. + static RGB sampleGradient(const uint8_t* stops, size_t nStops, uint8_t pos) { + // Walk to the last stop whose position <= pos. + size_t s = 0; + while (s + 1 < nStops && stops[(s + 1) * 4] <= pos) s++; + const uint8_t* lo = stops + s * 4; + if (s + 1 >= nStops) return {lo[1], lo[2], lo[3]}; // at/after the last stop + const uint8_t* hi = stops + (s + 1) * 4; + const uint8_t p0 = lo[0], p1 = hi[0]; + if (p1 == p0) return {lo[1], lo[2], lo[3]}; + // Fraction of the way from lo to hi, as 0..255 for scale8. + const uint8_t frac = static_cast((static_cast(pos - p0) * 255) / (p1 - p0)); + return lerpRGB({lo[1], lo[2], lo[3]}, {hi[1], hi[2], hi[3]}, frac); + } + +public: + // Linear blend a→b by frac (0 = a, 255 = b). Integer-only. + static RGB lerpRGB(const RGB& a, const RGB& b, uint8_t frac) { + const uint8_t inv = static_cast(255 - frac); + return { static_cast(scale8(a.r, inv) + scale8(b.r, frac)), + static_cast(scale8(a.g, inv) + scale8(b.g, frac)), + static_cast(scale8(a.b, inv) + scale8(b.b, frac)) }; + } +}; + +// The per-light lookup: `index` is a 0..255 wheel position (wraps), mapped across the 16 entries; +// blend the two bracketing entries, then scale by `brightness`. Hot-path-cheap (two scale8 + a +// blend). This is the seam effects call; a future MoonLivePalette substitutes a scripted variant +// behind the same signature. +inline RGB colorFromPalette(const Palette& p, uint8_t index, uint8_t brightness = 255) { + // Position across 16 entries: the high nibble selects the entry, the low byte the blend. + const uint8_t hi = static_cast(index >> 4); // 0..15 — bracket start + const uint8_t frac = static_cast((index & 0x0F) * 17); // 0..255 within the bracket + const RGB& a = p.entry[hi]; + const RGB& b = p.entry[(hi + 1) & 0x0F]; // wrap 15→0 + RGB c = Palette::lerpRGB(a, b, frac); + if (brightness != 255) { + c.r = scale8(c.r, brightness); + c.g = scale8(c.g, brightness); + c.b = scale8(c.b, brightness); + } + return c; +} + +// --- Built-in palettes ------------------------------------------------------------------------- +// Gradient-stop definitions in flash ({pos,R,G,B,…}). A curated starter set — gradient data from +// MoonLight's palettes.h (reformatted) plus generated ones. More can be added later as pure data. +namespace palettes { + +inline constexpr uint8_t kLava[] = {0,0,0,0, 46,18,0,0, 96,113,0,0, 108,142,3,1, 119,175,17,1, 146,213,44,2, 174,255,82,4, 188,255,115,4, 202,255,156,4, 218,255,203,4, 234,255,255,4, 244,255,255,71, 255,255,255,255}; +inline constexpr uint8_t kFierceIce[] = {0,0,0,0, 59,0,9,45, 119,0,38,255, 149,3,100,255, 180,23,199,255, 217,100,235,255, 255,255,255,255}; +inline constexpr uint8_t kSunset[] = {0,120,0,0, 22,179,22,0, 51,255,104,0, 85,167,22,18, 135,100,0,103, 198,16,0,130, 255,0,0,160}; +inline constexpr uint8_t kOceanBreeze[] = {0,1,6,7, 89,1,99,111, 153,144,209,255, 255,0,73,82}; +inline constexpr uint8_t kOrangeTeal[] = {0,0,150,92, 55,0,150,92, 200,255,72,0, 255,255,72,0}; +inline constexpr uint8_t kAurora[] = {0,1,5,45, 64,0,200,23, 128,0,255,0, 170,0,243,45, 200,0,135,7, 255,1,5,45}; +inline constexpr uint8_t kAtlantica[] = {0,0,28,112, 50,32,96,255, 100,0,243,45, 150,12,95,82, 200,25,190,95, 255,40,170,80}; +inline constexpr uint8_t kParty[] = {0,85,0,171, 42,150,0,107, 85,201,0,42, 128,212,32,0, 170,191,98,0, 213,128,160,0, 255,85,212,0}; // FastLED party-colors stops +inline constexpr uint8_t kForest[] = {0,0,100,0, 64,34,139,34, 128,0,128,0, 192,107,142,35, 255,0,100,0}; + +// A built-in is a gradient ({stops,len}) or the special "rainbow" (generated via hsvToRgb). +struct Builtin { const char* name; const uint8_t* stops; size_t len; bool rainbow; }; + +inline constexpr Builtin kBuiltins[] = { + {"Rainbow", nullptr, 0, true }, + {"Party", kParty, sizeof(kParty), false}, + {"Lava", kLava, sizeof(kLava), false}, + {"Ocean", kOceanBreeze,sizeof(kOceanBreeze),false}, + {"Forest", kForest, sizeof(kForest), false}, + {"Fierce Ice", kFierceIce, sizeof(kFierceIce), false}, + {"Sunset", kSunset, sizeof(kSunset), false}, + {"Orange Teal",kOrangeTeal, sizeof(kOrangeTeal),false}, + {"Aurora", kAurora, sizeof(kAurora), false}, + {"Atlantica", kAtlantica, sizeof(kAtlantica), false}, +}; +inline constexpr uint8_t kCount = sizeof(kBuiltins) / sizeof(kBuiltins[0]); + +// Names array for the UI select control (parallel to kBuiltins). +inline const char* const kNames[] = { + "Rainbow", "Party", "Lava", "Ocean", "Forest", "Fierce Ice", "Sunset", "Orange Teal", "Aurora", "Atlantica", +}; + +} // namespace palettes + +// The global active palette effects read — the AudioModule::latestFrame() static-seam pattern. +// Drivers owns the `palette` select control and calls setActive() on change; effects just call +// colorFromPalette(*Palettes::active(), idx). +class Palettes { +public: + static const Palette* active() { return &active_; } + + // Expand built-in `index` into the active palette (off the hot path — on selection). + static void setActive(uint8_t index) { + active_ = fromBuiltin(index); + } + + // Build the 16-entry palette for built-in `index` (rainbow generated via hsvToRgb, the rest + // expanded from their gradient stops). Shared by setActive() and the default + the swatches. + static Palette fromBuiltin(uint8_t index) { + if (index >= palettes::kCount) index = 0; + const auto& b = palettes::kBuiltins[index]; + Palette p; + if (b.rainbow) { + for (uint8_t i = 0; i < Palette::kEntries; i++) + p.entry[i] = hsvToRgb(static_cast((static_cast(i) * 256) / Palette::kEntries), 255, 255); + } else { + p.fromGradient(b.stops, b.len); + } + return p; + } + +private: + // Default to a full rainbow (index 0): always colourful, so an effect renders visible output + // before any palette is selected. setActive() (Drivers setup) overrides from the saved index. + static inline Palette active_ = fromBuiltin(0); +}; + +// Emit the palette dropdown's options for a ControlType::Palette control (the PaletteOptionsFn): +// one {"name":…,"colors":"rrggbb rrggbb …"} object per built-in, the colours being the 16 entries +// as space-separated hex so the UI renders each option as a gradient swatch. +inline void paletteOptions(JsonSink& sink) { + for (uint8_t i = 0; i < palettes::kCount; i++) { + const Palette p = Palettes::fromBuiltin(i); + sink.appendf("%s{\"name\":\"%s\",\"colors\":\"", i > 0 ? "," : "", palettes::kBuiltins[i].name); + for (uint8_t e = 0; e < Palette::kEntries; e++) + sink.appendf("%s%02x%02x%02x", e > 0 ? " " : "", p.entry[e].r, p.entry[e].g, p.entry[e].b); + sink.append("\"}"); + } +} + +} // namespace mm diff --git a/src/light/drivers/Drivers.h b/src/light/drivers/Drivers.h index 5c17e028..59eeeb60 100644 --- a/src/light/drivers/Drivers.h +++ b/src/light/drivers/Drivers.h @@ -6,6 +6,7 @@ #include "light/layers/Layers.h" #include "light/layers/BlendMap.h" #include "light/drivers/Correction.h" +#include "light/Palette.h" // the global active palette + its select control #include "platform/platform.h" #include // std::strcmp in onUpdate @@ -159,6 +160,7 @@ class Drivers : public MoonModule { // PreviewDriver reads the RGB source buffer directly, so the simulator is // unaffected. RGB-ordered outputs (some ArtNet/network sinks) flip it back. uint8_t lightPreset = 2; // index into kLightPresetOptions; 2 = GRB + uint8_t palette = 0; // index into mm::palettes::kNames; the global active palette effects read // Two ways to wire the source Layer: // - setLayers(Layers*): bind the container; layer_ is re-resolved from @@ -179,6 +181,7 @@ class Drivers : public MoonModule { void onBuildControls() override { controls_.addUint8("brightness", brightness, 0, 255); controls_.addSelect("lightPreset", lightPreset, kLightPresetOptions, kLightPresetCount); + controls_.addPalette("palette", palette, mm::paletteOptions, mm::palettes::kCount); MoonModule::onBuildControls(); // cascade to driver children } @@ -186,6 +189,10 @@ class Drivers : public MoonModule { // pipeline realloc. This is what keeps the brightness slider fluent: controlChangeTriggersBuildState // stays false for Drivers, so handleSetControl skips scheduler_->buildState(). void onUpdate(const char* controlName) override { + if (std::strcmp(controlName, "palette") == 0) { + Palettes::setActive(palette); // rebuild the active 16-entry lookup (cheap, off the hot path) + return; + } if (std::strcmp(controlName, "brightness") == 0 || std::strcmp(controlName, "lightPreset") == 0) { correction_.rebuild(brightness, static_cast(lightPreset)); @@ -201,6 +208,7 @@ class Drivers : public MoonModule { void setup() override { correction_.rebuild(brightness, static_cast(lightPreset)); + Palettes::setActive(palette); // seed the global active palette from the persisted index MoonModule::setup(); passBufferToDrivers(); } diff --git a/src/light/drivers/HueDriver.h b/src/light/drivers/HueDriver.h index 216314bd..30e1ad53 100644 --- a/src/light/drivers/HueDriver.h +++ b/src/light/drivers/HueDriver.h @@ -205,7 +205,8 @@ class HueDriver : public DriverBase { if (key[0]) { std::snprintf(appKey, sizeof(appKey), "%s", key); pairTicksLeft_ = 0; - lightCount_ = 0; // re-fetch the light list with the new key + resetLightCache(); // clear the light list + the per-light push cache + // (sent_/lastRgb_) so the new session re-sends all refreshStatus(); markDirty(); // persist the new app key FilesystemModule::noteDirty(); diff --git a/src/light/effects/AudioSpectrumEffect.h b/src/light/effects/AudioSpectrumEffect.h index 1c60c24c..a395793d 100644 --- a/src/light/effects/AudioSpectrumEffect.h +++ b/src/light/effects/AudioSpectrumEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + the global active palette #include "core/color.h" // hsvToRgb, RGB #include "core/AudioModule.h" // AudioModule::latestFrame() @@ -101,7 +102,7 @@ class AudioSpectrumEffect : public EffectBase { // Per-band: the column's hue at full brightness (a strip dims // its single row by magnitude instead). const uint8_t v = (h == 1) ? mag : 255; - const RGB c = hsvToRgb(bandHue, 255, v); + const RGB c = colorFromPalette(*Palettes::active(), bandHue, v); r = c.r; g = c.g; b = c.b; } else { // Height gradient: green at the base → red at the top. The diff --git a/src/light/effects/AudioVolumeEffect.h b/src/light/effects/AudioVolumeEffect.h index db2ade01..50808161 100644 --- a/src/light/effects/AudioVolumeEffect.h +++ b/src/light/effects/AudioVolumeEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + the global active palette #include "core/AudioModule.h" // AudioModule::latestFrame() namespace mm { @@ -33,12 +34,12 @@ class AudioVolumeEffect : public EffectBase { const uint16_t v = static_cast( (level > 255 ? 255 : level) * brightness / 255); - // A simple level-driven colour ramp: green (quiet) → red (loud), with v - // setting overall intensity. Fill every light identically — a VU meter on - // the whole surface; modifiers/layouts give it shape. - const uint8_t r = static_cast(v); - const uint8_t g = static_cast(v > 128 ? (255 - v) * 2 : 255 * v / 128); - const uint8_t b = 0; + // Level drives BOTH the palette index and the brightness: quiet maps to the palette's + // start, loud to its end, dimmed by v. Fill every light identically — a VU meter on the + // whole surface; modifiers/layouts give it shape. + const uint8_t lvl = static_cast(level > 255 ? 255 : level); + const RGB c = colorFromPalette(*Palettes::active(), lvl, static_cast(v)); + const uint8_t r = c.r, g = c.g, b = c.b; // Write logical RGB only: channel order and any RGBW white are the // driver's Correction (W = min(r,g,b)), like every other effect. Effect diff --git a/src/light/effects/CheckerboardEffect.h b/src/light/effects/CheckerboardEffect.h deleted file mode 100644 index a814ed5b..00000000 --- a/src/light/effects/CheckerboardEffect.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include "light/layers/Layer.h" -#include "core/color.h" - -namespace mm { - -class CheckerboardEffect : public EffectBase { -public: - const char* tags() const override { return "💫🦅"; } // MoonLight origin · David Jupijn / Rising Step - // Iterates y and x only; Layer::extrude fills z on 3D layers. - Dim dimensions() const override { return Dim::D2; } - - uint8_t cell_size = 4; - uint8_t bpm = 60; - uint8_t hue_a = 0; - uint8_t hue_b = 128; - - void onBuildControls() override { - controls_.addUint8("cell_size", cell_size, 1, 255); - controls_.addUint8("bpm", bpm, 1, 255); - controls_.addUint8("hue_a", hue_a, 0, 255); - controls_.addUint8("hue_b", hue_b, 0, 255); - } - - void loop() override { - uint8_t* buf = buffer(); - lengthType w = width(); - lengthType h = height(); - uint8_t cpl = channelsPerLight(); - - uint32_t now = elapsed(); - uint32_t dt = now - lastElapsed_; - lastElapsed_ = now; - // Accumulate the raw (dt * bpm) product; divide only at the read site. - // Per-tick `dt*bpm*256/60000` rounds to 0 on desktop (dt ≈ 0..1ms) and - // freezes the animation; see MetaballsEffect for the same fix. - phase_num_ += static_cast(dt) * bpm; - uint8_t phaseCell = static_cast((phase_num_ * 16) / 60000); - - RGB ca = hsvToRgb(hue_a, 255, 255); - RGB cb = hsvToRgb(hue_b, 255, 255); - - for (lengthType y = 0; y < h; y++) { - uint8_t cy = static_cast(static_cast(y) / cell_size); - uint8_t* row = buf + static_cast(y) * static_cast(w) * cpl; - for (lengthType x = 0; x < w; x++) { - uint8_t cx = static_cast(static_cast(x) / cell_size); - bool on = ((cx + cy + phaseCell) & 1) != 0; - RGB c = on ? cb : ca; - - if (cpl >= 1) row[0] = c.r; - if (cpl >= 2) row[1] = c.g; - if (cpl >= 3) row[2] = c.b; - row += cpl; - } - } - } - -private: - // Numerator-only accumulator (units of dt*bpm). See loop() for why. - uint64_t phase_num_ = 0; - uint32_t lastElapsed_ = 0; -}; - -} // namespace mm diff --git a/src/light/effects/DistortionWavesEffect.h b/src/light/effects/DistortionWavesEffect.h index 03ea06a6..45d86c74 100644 --- a/src/light/effects/DistortionWavesEffect.h +++ b/src/light/effects/DistortionWavesEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + active palette #include "core/color.h" // sin8, hsvToRgb namespace mm { @@ -55,7 +56,7 @@ class DistortionWavesEffect : public EffectBase { // Average the two sines (each 0..255) → a hue byte. The interference of // the two frequencies + the 1.3× time skew is what makes the pattern move. const uint8_t hue = static_cast((static_cast(sx) + sy) >> 1); - const RGB c = hsvToRgb(hue, 240, 255); + const RGB c = colorFromPalette(*Palettes::active(), hue); if (cpl >= 1) row[0] = c.r; if (cpl >= 2) row[1] = c.g; if (cpl >= 3) row[2] = c.b; diff --git a/src/light/effects/FireEffect.h b/src/light/effects/FireEffect.h index d2b4e481..262da44e 100644 --- a/src/light/effects/FireEffect.h +++ b/src/light/effects/FireEffect.h @@ -82,12 +82,17 @@ class FireEffect : public EffectBase { } } - // 3. Random sparks at the bottom row - if (h > 0) { + // 3. Random sparks at the bottom row. Scale the number of spark attempts with width so a + // wide grid lights up across its whole base instead of leaving most columns cold — a + // fixed 4 sparks fills a 16-wide grid but barely speckles a 256-wide one. One attempt + // per ~4 columns (min 4) keeps the bottom row evenly seeded at any width. + if (h > 0 && w > 0) { lengthType bottomRow = static_cast(h - 1); - for (uint8_t i = 0; i < 4; i++) { + lengthType sparks = w / 4; + if (sparks < 4) sparks = 4; + for (lengthType i = 0; i < sparks; i++) { if (rand8() < sparking) { - uint8_t sx = static_cast((static_cast(rand8()) * w) >> 8); + lengthType sx = static_cast((static_cast(rand8()) * w) >> 8); uint8_t add = static_cast(160 + (rand8() & 0x5F)); uint16_t newHeat = static_cast(heat_[bottomRow * w + sx]) + add; heat_[bottomRow * w + sx] = newHeat > 255 ? 255 : static_cast(newHeat); diff --git a/src/light/effects/GameOfLifeEffect.h b/src/light/effects/GameOfLifeEffect.h deleted file mode 100644 index a081784d..00000000 --- a/src/light/effects/GameOfLifeEffect.h +++ /dev/null @@ -1,272 +0,0 @@ -#pragma once - -#include "light/layers/Layer.h" -#include "core/color.h" -#include "platform/platform.h" - -#include - -namespace mm { - -// Conway's Game of Life on the XY plane (B3/S23). Two cell grids (cur/nxt) hold -// one byte per cell (0 dead, 1 alive); the step reads cur and writes nxt, then -// swaps. On extinction (no live cells) or stasis (no cell changed) the grid -// re-seeds from the PRNG so the effect never stops. -// -// Scope is deliberately the minimal classic rule — MoonLight's E_MoonModules -// GameOfLife adds rulesets, palette colouring, blur, mutation and pentomino -// seeding; those are out by design (concrete first). The simulation step is -// decoupled from colouring (one render line), so a future ruleset control or -// palette swap is a localised change. Prior art: MoonLight (Ewoud Wijma 2022, -// Brandon Butler 2024) and projectMM v1's GameOfLifeEffect. -class GameOfLifeEffect : public EffectBase { -public: - const char* tags() const override { return "🔬🌙"; } // cellular automaton · MoonLight / v1 lineage - // Iterates y and x only; Layer::extrude fills z on 3D layers. The cell grids - // cover only the z=0 plane (w*h), not the full 3D buffer. - Dim dimensions() const override { return Dim::D2; } - - uint8_t seed = 42; - bool wraparound = false; - uint8_t hue = 160; - uint8_t bpm = 60; // generation rate; ≈ bpm/8 generations per second - - void onBuildControls() override { - controls_.addUint8("seed", seed, 0, 255); - controls_.addBool("wraparound", wraparound); - controls_.addUint8("hue", hue, 0, 255); - controls_.addUint8("bpm", bpm, 1, 255); - } - - void onBuildState() override { - nrOfLightsType count = static_cast(width()) * height(); - if (enabled() && count > 0) { - if (count != cellCount_) { - releaseGrids(); - cur_ = static_cast(platform::alloc(count)); - nxt_ = static_cast(platform::alloc(count)); - if (cur_ && nxt_) { - cellCount_ = count; - reseed(); // fresh state for the new dimensions - } else { - releaseGrids(); // partial alloc → keep nothing - } - } - } else { - releaseGrids(); - } - // Two grids: report both so the UI's per-effect heap figure is honest. - setDynamicBytes(static_cast(cellCount_) * 2); - } - - void teardown() override { - releaseGrids(); - setDynamicBytes(0); - } - - ~GameOfLifeEffect() override { - releaseGrids(); - } - - void loop() override { - if (!cur_ || !nxt_) return; - - lengthType w = width(); - lengthType h = height(); - if (w <= 0 || h <= 0) return; - - // 1. Time-gate the generation rate so bpm controls speed independent of - // frame rate. Accumulate dt*bpm (ms·bpm) and spend whole "beats"; - // one beat = one generation. bpm/8 ≈ generations per second (bpm 8 → - // 1/s, 60 → ~7.5/s, 255 → ~32/s). Numerator-only accumulator, divide - // at the read site — same shape as CheckerboardEffect. - uint32_t now = elapsed(); - // Bootstrap on the first frame: lastElapsed_ starts at 0, so a raw - // now-0 would be a huge dt that pins stepAccum_ above the beat threshold - // for good (max-rate forever, bpm ignored). Seed the baseline and take - // dt=0 this frame instead. - uint32_t dt = startedClock_ ? (now - lastElapsed_) : 0; - startedClock_ = true; - lastElapsed_ = now; - stepAccum_ += static_cast(dt) * bpm; - constexpr uint64_t kMsPerBeat = 8000; // 8000 ms·bpm == one generation - // Cap catch-up so a long stall (e.g. tab hidden) can't run thousands of - // generations in one frame. - uint8_t budget = 4; - while (stepAccum_ >= kMsPerBeat && budget-- > 0) { - stepAccum_ -= kMsPerBeat; - advance(); - } - - // 2. Render the current grid EVERY frame. The Layer clears the buffer - // before each effect runs, so skipping the paint on non-step frames - // would leave the buffer black — the grid only advances on beats, but - // it must be drawn on every frame to stay visible between them. - uint8_t* buf = buffer(); - uint8_t cpl = channelsPerLight(); - for (lengthType y = 0; y < h; y++) { - for (lengthType x = 0; x < w; x++) { - size_t off = static_cast(idx(x, y, w)) * cpl; - if (cur_[idx(x, y, w)]) { - RGB c = hsvToRgb(static_cast(hue + x * 3 + y * 5), 200, 255); - if (cpl >= 1) buf[off + 0] = c.r; - if (cpl >= 2) buf[off + 1] = c.g; - if (cpl >= 3) buf[off + 2] = c.b; - } else { - if (cpl >= 1) buf[off + 0] = 0; - if (cpl >= 2) buf[off + 1] = 0; - if (cpl >= 3) buf[off + 2] = 0; - } - } - } - } - - // --- Test helpers (deterministic stepping without rendering) ------------- - // Mirror the v1 effect's test surface so the rule can be pinned directly. - void setCell(lengthType x, lengthType y, bool alive) { - if (cur_ && x >= 0 && y >= 0 && x < width() && y < height()) - cur_[idx(x, y, width())] = alive ? 1 : 0; - } - bool getCell(lengthType x, lengthType y) const { - if (!cur_ || x < 0 || y < 0 || x >= width() || y >= height()) return false; - return cur_[idx(x, y, width())] != 0; - } - nrOfLightsType liveCount() const { - nrOfLightsType n = 0; - for (nrOfLightsType i = 0; i < cellCount_; i++) n += (cur_[i] != 0); - return n; - } - void clearGrid() { - if (cur_) std::memset(cur_, 0, cellCount_); - } - // Advance one B3/S23 generation (no re-seed, no render); returns the number - // of cells that changed and, if `aliveOut` is given, writes the live count. - // loop() calls this then re-seeds on extinction/stasis. Public so tests can - // step a known pattern deterministically. - nrOfLightsType stepOnce(nrOfLightsType* aliveOut = nullptr) { - if (!cur_ || !nxt_) { if (aliveOut) *aliveOut = 0; return 0; } - lengthType w = width(); - lengthType h = height(); - nrOfLightsType alive = 0, changed = 0; - for (lengthType y = 0; y < h; y++) { - for (lengthType x = 0; x < w; x++) { - uint8_t n = neighbors(x, y, w, h); - uint8_t self = cur_[idx(x, y, w)]; - // Birth on exactly 3 neighbours; survival on 2 or 3. - uint8_t next = (n == 3 || (self && n == 2)) ? 1 : 0; - nxt_[idx(x, y, w)] = next; - if (next) alive++; - if (next != self) changed++; - } - } - uint8_t* tmp = cur_; cur_ = nxt_; nxt_ = tmp; // swap: cur = new gen - if (aliveOut) *aliveOut = alive; - return changed; - } - -private: - // One production generation plus the liveliness logic. A random soup always - // decays to sparse still-lifes + a few blinkers (changed never hits 0, so a - // plain stasis check won't fire) — so we re-seed when the colony goes - // extinct, thins below a density floor, or stops growing for a while. That - // keeps gliders and chaos coming instead of a frozen field. (MoonLight does - // the richer version with pentomino injection + CRC cycle detection; this - // is the minimal equivalent — see the spec's Extending note.) - void advance() { - nrOfLightsType alive = 0; - stepOnce(&alive); - generation_++; - - nrOfLightsType floor = cellCount_ / 32; // ~3% of the grid - if (alive <= floor) { - reseed(); - return; - } - // Stagnation: if the live count barely moves over a window, the colony - // has settled into still-lifes + oscillators. Re-seed to revive it. - nrOfLightsType delta = (alive > lastAlive_) - ? static_cast(alive - lastAlive_) - : static_cast(lastAlive_ - alive); - if (delta <= (cellCount_ / 256 + 1)) { // <0.4% change this generation - if (++stagnantGens_ >= 32) reseed(); - } else { - stagnantGens_ = 0; - } - lastAlive_ = alive; - } - - uint8_t* cur_ = nullptr; - uint8_t* nxt_ = nullptr; - nrOfLightsType cellCount_ = 0; - uint32_t rngState_ = 0; - - uint8_t rand8() { - rngState_ = rngState_ * 1103515245u + 12345u; - return static_cast((rngState_ >> 16) & 0xFF); - } - - // Row-major cell index (z=0 plane only). - static nrOfLightsType idx(lengthType x, lengthType y, lengthType w) { - return static_cast(y) * w + x; - } - - // Count of the 8 Moore neighbours that are alive. Edges either wrap or are - // treated as dead, per the wraparound control. - uint8_t neighbors(lengthType x, lengthType y, lengthType w, lengthType h) const { - uint8_t n = 0; - for (int8_t dy = -1; dy <= 1; dy++) { - for (int8_t dx = -1; dx <= 1; dx++) { - if (dx == 0 && dy == 0) continue; - lengthType nx = static_cast(x + dx); - lengthType ny = static_cast(y + dy); - if (wraparound) { - if (nx < 0) nx = static_cast(w - 1); - else if (nx >= w) nx = 0; - if (ny < 0) ny = static_cast(h - 1); - else if (ny >= h) ny = 0; - } else if (nx < 0 || ny < 0 || nx >= w || ny >= h) { - continue; // out-of-bounds counts as dead - } - n = static_cast(n + (cur_[idx(nx, ny, w)] != 0)); - } - } - return n; - } - - // Random initial state. The very first seeding (per grid) starts the PRNG - // from the `seed` control so a given seed gives a reproducible opening; - // later re-seeds continue the same stream so each revival differs — without - // that, every reseed would replay the identical soup and the effect would - // loop forever. ~31% alive: dense enough to evolve, sparse enough to avoid - // instant gridlock. - void reseed() { - if (!cur_) return; - if (!seeded_) { - rngState_ = 0x9E3779B9u ^ (static_cast(seed) * 2654435761u); - seeded_ = true; - } - for (nrOfLightsType i = 0; i < cellCount_; i++) { - cur_[i] = (rand8() < 80) ? 1 : 0; // 80/256 ≈ 31% - } - lastAlive_ = 0; - stagnantGens_ = 0; - } - - void releaseGrids() { - if (cur_) { platform::free(cur_); cur_ = nullptr; } - if (nxt_) { platform::free(nxt_); nxt_ = nullptr; } - cellCount_ = 0; - seeded_ = false; // a fresh grid re-derives the seed - } - - // Generation-pacing + liveliness state. - uint32_t lastElapsed_ = 0; - bool startedClock_ = false; // false until the first loop seeds lastElapsed_ - uint64_t stepAccum_ = 0; // accumulated dt*bpm (ms·bpm) - bool seeded_ = false; // first reseed derives from `seed` - uint32_t generation_ = 0; - nrOfLightsType lastAlive_ = 0; - uint16_t stagnantGens_ = 0; -}; - -} // namespace mm diff --git a/src/light/effects/GlowParticlesEffect.h b/src/light/effects/GlowParticlesEffect.h deleted file mode 100644 index 9ccc024b..00000000 --- a/src/light/effects/GlowParticlesEffect.h +++ /dev/null @@ -1,125 +0,0 @@ -#pragma once - -#include "light/layers/Layer.h" -#include "core/color.h" - -namespace mm { - -// Soft-glowing particles rendered as a metaball field. Particles move with -// independent velocities and bounce off the edges. Field summation gives a -// chaotic, organic blob look — like metaballs with more freedom. -class GlowParticlesEffect : public EffectBase { -public: - const char* tags() const override { return "💫🦅"; } // MoonLight origin · David Jupijn / Rising Step - // Iterates y and x only; Layer::extrude fills z on 3D layers. - Dim dimensions() const override { return Dim::D2; } - - static constexpr uint8_t MAX_PARTICLES = 8; - - uint8_t count = 5; - uint8_t speed = 60; - uint8_t radius = 24; - uint8_t hue_shift = 0; - - void onBuildControls() override { - controls_.addUint8("count", count, 1, 255); - controls_.addUint8("speed", speed, 1, 255); - controls_.addUint8("radius", radius, 4, 255); - controls_.addUint8("hue_shift", hue_shift, 0, 255); - } - - void loop() override { - uint8_t* buf = buffer(); - lengthType w = width(); - lengthType h = height(); - uint8_t cpl = channelsPerLight(); - if (w <= 0 || h <= 0) return; - - if (!initialized_) initParticles(w, h); - - uint32_t now = elapsed(); - uint32_t dt = now - lastElapsed_; - lastElapsed_ = now; - - int16_t maxXfp = static_cast((w - 1) << 4); - int16_t maxYfp = static_cast((h - 1) << 4); - - for (uint8_t i = 0; i < count && i < MAX_PARTICLES; i++) { - auto& p = particles_[i]; - int16_t sx = static_cast((static_cast(p.vx) * speed * static_cast(dt)) >> 12); - int16_t sy = static_cast((static_cast(p.vy) * speed * static_cast(dt)) >> 12); - p.x = static_cast(p.x + sx); - p.y = static_cast(p.y + sy); - if (p.x < 0) { p.x = 0; p.vx = static_cast(-p.vx); } - if (p.x > maxXfp) { p.x = maxXfp; p.vx = static_cast(-p.vx); } - if (p.y < 0) { p.y = 0; p.vy = static_cast(-p.vy); } - if (p.y > maxYfp) { p.y = maxYfp; p.vy = static_cast(-p.vy); } - } - - int16_t bx[MAX_PARTICLES] = {}; - int16_t by[MAX_PARTICLES] = {}; - for (uint8_t i = 0; i < count && i < MAX_PARTICLES; i++) { - bx[i] = static_cast(particles_[i].x >> 4); - by[i] = static_cast(particles_[i].y >> 4); - } - int32_t r2 = static_cast(radius) * radius; - - for (lengthType y = 0; y < h; y++) { - uint8_t* row = buf + static_cast(y) * static_cast(w) * cpl; - for (lengthType x = 0; x < w; x++) { - uint32_t field = 0; - for (uint8_t i = 0; i < count && i < MAX_PARTICLES; i++) { - int32_t dx = static_cast(x) - bx[i]; - int32_t dy = static_cast(y) - by[i]; - int32_t d2 = dx * dx + dy * dy + 1; - field += static_cast((r2 * 64) / d2); - } - uint8_t bright = field > 255 ? 255 : static_cast(field); - uint8_t hue = static_cast((field >> 1) + hue_shift); - RGB c = hsvToRgb(hue, 240, bright); - if (cpl >= 1) row[0] = c.r; - if (cpl >= 2) row[1] = c.g; - if (cpl >= 3) row[2] = c.b; - row += cpl; - } - } - } - -private: - struct Particle { - int16_t x; // 12.4 fixed-point pixel position - int16_t y; - int8_t vx; - int8_t vy; - uint8_t hue; - uint8_t pad; - }; - - Particle particles_[MAX_PARTICLES] = {}; - bool initialized_ = false; - uint32_t lastElapsed_ = 0; - uint32_t rngState_ = 0xACE1BEEFu; - - uint8_t rand8() { - rngState_ = rngState_ * 1103515245u + 12345u; - return static_cast((rngState_ >> 16) & 0xFF); - } - - void initParticles(lengthType w, lengthType h) { - for (uint8_t i = 0; i < MAX_PARTICLES; i++) { - particles_[i].x = static_cast((static_cast(rand8()) * w) >> 4); - particles_[i].y = static_cast((static_cast(rand8()) * h) >> 4); - int8_t vx = static_cast((rand8() >> 1) - 32); - int8_t vy = static_cast((rand8() >> 1) - 32); - if (vx == 0) vx = 1; - if (vy == 0) vy = 1; - particles_[i].vx = vx; - particles_[i].vy = vy; - particles_[i].hue = rand8(); - particles_[i].pad = 0; - } - initialized_ = true; - } -}; - -} // namespace mm diff --git a/src/light/effects/MetaballsEffect.h b/src/light/effects/MetaballsEffect.h index 4ce38120..e330cb5e 100644 --- a/src/light/effects/MetaballsEffect.h +++ b/src/light/effects/MetaballsEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + active palette #include "core/color.h" namespace mm { @@ -13,13 +14,15 @@ class MetaballsEffect : public EffectBase { uint8_t bpm = 30; uint8_t radius = 28; + uint8_t count = 4; // number of balls (1..MAX_BALLS); each follows its own sine path uint8_t hue_shift = 0; - static constexpr uint8_t NUM_BALLS = 4; + static constexpr uint8_t MAX_BALLS = 8; void onBuildControls() override { controls_.addUint8("bpm", bpm, 1, 255); controls_.addUint8("radius", radius, 4, 255); + controls_.addUint8("count", count, 1, MAX_BALLS); controls_.addUint8("hue_shift", hue_shift, 0, 255); } @@ -40,12 +43,13 @@ class MetaballsEffect : public EffectBase { phase_num_ += static_cast(dt) * bpm; uint8_t t = static_cast((phase_num_ * 256) / 60000); - int16_t bx[NUM_BALLS]; - int16_t by[NUM_BALLS]; - static constexpr uint8_t SPEED_MUL[NUM_BALLS] = { 1, 2, 3, 1 }; - static constexpr uint8_t PHASE_X[NUM_BALLS] = { 0, 30, 60, 120 }; - static constexpr uint8_t PHASE_Y[NUM_BALLS] = { 64, 94, 124, 184 }; - for (uint8_t b = 0; b < NUM_BALLS; b++) { + const uint8_t n = count < MAX_BALLS ? count : MAX_BALLS; + int16_t bx[MAX_BALLS]; + int16_t by[MAX_BALLS]; + static constexpr uint8_t SPEED_MUL[MAX_BALLS] = { 1, 2, 3, 1, 2, 3, 1, 2 }; + static constexpr uint8_t PHASE_X[MAX_BALLS] = { 0, 30, 60, 120, 160, 200, 90, 220 }; + static constexpr uint8_t PHASE_Y[MAX_BALLS] = { 64, 94, 124, 184, 16, 210, 150, 40 }; + for (uint8_t b = 0; b < n; b++) { uint8_t tb = static_cast(t * SPEED_MUL[b]); bx[b] = static_cast((sin8(static_cast(tb + PHASE_X[b])) * w) >> 8); by[b] = static_cast((sin8(static_cast(tb + PHASE_Y[b])) * h) >> 8); @@ -58,7 +62,7 @@ class MetaballsEffect : public EffectBase { uint8_t* row = buf + static_cast(y) * w * cpl; for (lengthType x = 0; x < w; x++) { uint32_t field = 0; - for (uint8_t b = 0; b < NUM_BALLS; b++) { + for (uint8_t b = 0; b < n; b++) { int32_t dx = static_cast(x) - bx[b]; int32_t dy = static_cast(y) - by[b]; int32_t d2 = dx * dx + dy * dy + 1; @@ -66,7 +70,7 @@ class MetaballsEffect : public EffectBase { } uint8_t bright = field > 255 ? 255 : static_cast(field); uint8_t hue = static_cast((field >> 1) + hue_shift); - RGB c = hsvToRgb(hue, 240, bright); + RGB c = colorFromPalette(*Palettes::active(), hue, bright); if (cpl >= 1) row[0] = c.r; if (cpl >= 2) row[1] = c.g; diff --git a/src/light/effects/NoiseEffect.h b/src/light/effects/NoiseEffect.h index f2e503f4..202039db 100644 --- a/src/light/effects/NoiseEffect.h +++ b/src/light/effects/NoiseEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + active palette #include "core/color.h" namespace mm { @@ -45,7 +46,7 @@ class NoiseEffect : public EffectBase { lengthType z = static_cast(i / wh); uint8_t n = (d > 1) ? noise3d(x, y, z, t) : noise2d(x, y, t); - RGB c = hsvToRgb(n, 200, 255); + RGB c = colorFromPalette(*Palettes::active(), n); size_t offset = static_cast(i) * cpl; if (cpl >= 1) buf[offset + 0] = c.r; diff --git a/src/light/effects/PlasmaEffect.h b/src/light/effects/PlasmaEffect.h index 891ad72e..ff44fa63 100644 --- a/src/light/effects/PlasmaEffect.h +++ b/src/light/effects/PlasmaEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + active palette #include "core/color.h" namespace mm { @@ -11,8 +12,11 @@ class PlasmaEffect : public EffectBase { Dim dimensions() const override { return Dim::D3; } uint8_t bpm = 30; - uint8_t scale_x = 16; - uint8_t scale_y = 16; + // Larger scale = smaller per-pixel step (256/scale) = lower spatial frequency = bigger, calmer + // rolling blobs. The default is high so plasma reads as large blobs, not fine noise; lower it + // in the UI for a busier field. + uint8_t scale_x = 48; + uint8_t scale_y = 48; uint8_t hue_shift = 0; void onBuildControls() override { @@ -73,7 +77,7 @@ class PlasmaEffect : public EffectBase { ? static_cast( (static_cast(s1 + s2_y + s3 + s4 + s5_z) / 5) + hue_shift) : static_cast(((s1 + s2_y + s3 + s4) >> 2) + hue_shift); - RGB c = hsvToRgb(hue, 255, 255); + RGB c = colorFromPalette(*Palettes::active(), hue); if (cpl >= 1) row[0] = c.r; if (cpl >= 2) row[1] = c.g; diff --git a/src/light/effects/PlasmaPaletteEffect.h b/src/light/effects/PlasmaPaletteEffect.h deleted file mode 100644 index 167b12d6..00000000 --- a/src/light/effects/PlasmaPaletteEffect.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once - -#include "light/layers/Layer.h" -#include "core/color.h" - -namespace mm { - -class PlasmaPaletteEffect : public EffectBase { -public: - const char* tags() const override { return "💫🦅"; } // MoonLight origin · David Jupijn / Rising Step - // Iterates y and x only; Layer::extrude fills z on 3D layers. - Dim dimensions() const override { return Dim::D2; } - - uint8_t bpm = 30; - uint8_t scale_x = 16; - uint8_t scale_y = 16; - - void onBuildControls() override { - controls_.addUint8("bpm", bpm, 1, 255); - controls_.addUint8("scale_x", scale_x, 1, 255); - controls_.addUint8("scale_y", scale_y, 1, 255); - } - - void loop() override { - uint8_t* buf = buffer(); - lengthType w = width(); - lengthType h = height(); - uint8_t cpl = channelsPerLight(); - - uint32_t now = elapsed(); - uint32_t dt = now - lastElapsed_; - lastElapsed_ = now; - phase_ += static_cast(dt) * bpm * static_cast(w) * 64 / 60000; - - uint8_t step_x = static_cast(256 / scale_x); - uint8_t step_y = static_cast(256 / scale_y); - uint8_t t1 = static_cast(phase_); - uint8_t t2 = static_cast(phase_ * 2); - uint8_t t3 = static_cast(phase_ * 3); - - for (lengthType y = 0; y < h; y++) { - uint8_t s2_y = sin8(static_cast(static_cast(y) * step_y + t2)); - uint8_t yx_off = static_cast(static_cast(y) * step_x - t3); - uint8_t yx_neg = static_cast(128 - static_cast(y) * step_y + t1); - - uint8_t* row = buf + static_cast(y) * static_cast(w) * cpl; - for (lengthType x = 0; x < w; x++) { - uint8_t xs = static_cast(static_cast(x) * step_x); - uint8_t s1 = sin8(static_cast(xs + t1)); - uint8_t s3 = sin8(static_cast(xs + yx_off)); - uint8_t s4 = sin8(static_cast( - static_cast(static_cast(x) * step_y) + yx_neg)); - uint8_t idx = static_cast(((s1 + s2_y + s3 + s4) >> 2)); - const RGB& c = palette_[idx]; - - if (cpl >= 1) row[0] = c.r; - if (cpl >= 2) row[1] = c.g; - if (cpl >= 3) row[2] = c.b; - row += cpl; - } - } - } - -private: - uint64_t phase_ = 0; - uint32_t lastElapsed_ = 0; - - // Fire-ocean gradient palette (256 RGB entries in flash) - static constexpr RGB palette_[256] = { - {0,0,0}, {4,0,2}, {8,0,4}, {12,0,6}, {16,0,8}, {20,0,10}, {24,0,12}, {28,0,14}, - {32,0,16}, {36,0,18}, {40,0,20}, {44,0,22}, {48,0,24}, {52,0,26}, {56,0,28}, {60,0,30}, - {64,0,32}, {68,0,34}, {72,0,36}, {76,0,38}, {80,0,40}, {84,0,42}, {88,0,44}, {92,0,46}, - {96,0,48}, {100,0,50}, {104,0,52}, {108,0,54}, {112,0,56}, {116,0,58}, {120,0,60}, {124,0,62}, - {128,0,64}, {132,0,66}, {136,0,68}, {140,0,70}, {144,0,72}, {148,0,74}, {152,0,76}, {156,0,78}, - {160,0,80}, {164,0,82}, {168,0,84}, {172,0,86}, {176,0,88}, {180,0,90}, {184,0,92}, {188,0,94}, - {192,0,96}, {196,0,98}, {200,0,100}, {204,0,102}, {208,0,104}, {212,0,106}, {216,0,108}, {220,0,110}, - {224,0,112}, {228,0,114}, {232,0,116}, {236,0,118}, {240,0,120}, {244,0,122}, {248,0,124}, {252,0,126}, - {255,0,0}, {255,4,0}, {255,8,0}, {255,12,0}, {255,16,0}, {255,20,0}, {255,24,0}, {255,28,0}, - {255,32,0}, {255,36,0}, {255,40,0}, {255,44,0}, {255,48,0}, {255,52,0}, {255,56,0}, {255,60,0}, - {255,64,0}, {255,68,0}, {255,72,0}, {255,76,0}, {255,80,0}, {255,84,0}, {255,88,0}, {255,92,0}, - {255,96,0}, {255,100,0}, {255,104,0}, {255,108,0}, {255,112,0}, {255,116,0}, {255,120,0}, {255,124,0}, - {255,128,0}, {255,132,0}, {255,136,0}, {255,140,0}, {255,144,0}, {255,148,0}, {255,152,0}, {255,156,0}, - {255,160,0}, {255,164,0}, {255,168,0}, {255,172,0}, {255,176,0}, {255,180,0}, {255,184,0}, {255,188,0}, - {255,192,0}, {255,196,0}, {255,200,0}, {255,204,0}, {255,208,0}, {255,212,0}, {255,216,0}, {255,220,0}, - {255,224,0}, {255,228,0}, {255,232,0}, {255,236,0}, {255,240,0}, {255,244,0}, {255,248,0}, {255,252,0}, - {255,255,0}, {253,255,2}, {251,255,4}, {249,255,6}, {247,255,8}, {245,255,10}, {243,255,12}, {241,255,14}, - {239,255,16}, {237,255,18}, {235,255,20}, {233,255,22}, {231,255,24}, {229,255,26}, {227,255,28}, {225,255,30}, - {223,255,32}, {221,255,34}, {219,255,36}, {217,255,38}, {215,255,40}, {213,255,42}, {211,255,44}, {209,255,46}, - {207,255,48}, {205,255,50}, {203,255,52}, {201,255,54}, {199,255,56}, {197,255,58}, {195,255,60}, {193,255,62}, - {191,255,64}, {189,255,66}, {187,255,68}, {185,255,70}, {183,255,72}, {181,255,74}, {179,255,76}, {177,255,78}, - {175,255,80}, {173,255,82}, {171,255,84}, {169,255,86}, {167,255,88}, {165,255,90}, {163,255,92}, {161,255,94}, - {159,255,96}, {157,255,98}, {155,255,100}, {153,255,102}, {151,255,104}, {149,255,106}, {147,255,108}, {145,255,110}, - {143,255,112}, {141,255,114}, {139,255,116}, {137,255,118}, {135,255,120}, {133,255,122}, {131,255,124}, {129,255,126}, - {0,255,255}, {0,253,255}, {0,251,255}, {0,249,255}, {0,247,255}, {0,245,255}, {0,243,255}, {0,241,255}, - {0,239,255}, {0,237,255}, {0,235,255}, {0,233,255}, {0,231,255}, {0,229,255}, {0,227,255}, {0,225,255}, - {0,223,255}, {0,221,255}, {0,219,255}, {0,217,255}, {0,215,255}, {0,213,255}, {0,211,255}, {0,209,255}, - {0,207,255}, {0,205,255}, {0,203,255}, {0,201,255}, {0,199,255}, {0,197,255}, {0,195,255}, {0,193,255}, - {0,191,255}, {0,189,255}, {0,187,255}, {0,185,255}, {0,183,255}, {0,181,255}, {0,179,255}, {0,177,255}, - {0,175,255}, {0,173,255}, {0,171,255}, {0,169,255}, {0,167,255}, {0,165,255}, {0,163,255}, {0,161,255}, - {0,159,255}, {0,157,255}, {0,155,255}, {0,153,255}, {0,151,255}, {0,149,255}, {0,147,255}, {0,145,255}, - {0,143,255}, {0,141,255}, {0,139,255}, {0,137,255}, {0,135,255}, {0,133,255}, {0,131,255}, {0,129,255} - }; -}; - -} // namespace mm diff --git a/src/light/effects/RainbowEffect.h b/src/light/effects/RainbowEffect.h index a1f49f5a..edf75ce0 100644 --- a/src/light/effects/RainbowEffect.h +++ b/src/light/effects/RainbowEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + the global active palette #include "core/color.h" namespace mm { @@ -38,7 +39,7 @@ class RainbowEffect : public EffectBase { (static_cast(x + y) * 256 / (w + h)) + phase ); - RGB c = hsvToRgb(hue, 255, 255); + RGB c = colorFromPalette(*Palettes::active(), hue); size_t offset = (static_cast(y) * w + x) * cpl; if (cpl >= 1) buf[offset + 0] = c.r; if (cpl >= 2) buf[offset + 1] = c.g; diff --git a/src/light/effects/RingsEffect.h b/src/light/effects/RingsEffect.h index 4ed648f9..d266b950 100644 --- a/src/light/effects/RingsEffect.h +++ b/src/light/effects/RingsEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + active palette #include "core/color.h" namespace mm { @@ -18,8 +19,10 @@ class RingsEffect : public EffectBase { static constexpr uint8_t MAX_RIPPLES = 8; - uint8_t count = 4; - uint8_t speed = 60; + // Calm defaults: a couple of slow rings read as clean expanding circles; more/faster reads as + // chaos. Raise count/speed in the UI for a busier field. + uint8_t count = 2; + uint8_t speed = 30; uint8_t thickness = 3; uint8_t hue_shift = 0; @@ -81,7 +84,7 @@ class RingsEffect : public EffectBase { // Older ripples (large radius) fade out. uint8_t age_fade = static_cast(255 - ((radius_[i] * 255u) / maxR)); uint8_t intensity = scale8(falloff, age_fade); - RGB c = hsvToRgb(static_cast(hue_[i] + hue_shift), 240, intensity); + RGB c = colorFromPalette(*Palettes::active(), static_cast(hue_[i] + hue_shift), intensity); r_acc = static_cast(r_acc + c.r); g_acc = static_cast(g_acc + c.g); b_acc = static_cast(b_acc + c.b); diff --git a/src/light/effects/SpiralEffect.h b/src/light/effects/SpiralEffect.h index 653d86d4..64a11937 100644 --- a/src/light/effects/SpiralEffect.h +++ b/src/light/effects/SpiralEffect.h @@ -1,6 +1,7 @@ #pragma once #include "light/layers/Layer.h" +#include "light/Palette.h" // colorFromPalette + active palette #include "core/color.h" namespace mm { @@ -48,7 +49,7 @@ class SpiralEffect : public EffectBase { uint8_t dist = dist8(dx, dy); uint8_t hue = static_cast( angle + static_cast(dist * twist) - t + hue_shift); - RGB c = hsvToRgb(hue, 255, 255); + RGB c = colorFromPalette(*Palettes::active(), hue); if (cpl >= 1) row[0] = c.r; if (cpl >= 2) row[1] = c.g; diff --git a/src/light/effects/WaveEffect.h b/src/light/effects/WaveEffect.h index a83f1e07..f714bcd0 100644 --- a/src/light/effects/WaveEffect.h +++ b/src/light/effects/WaveEffect.h @@ -1,7 +1,8 @@ #pragma once #include "light/layers/Layer.h" -#include "core/color.h" // sin8 (integer sine LUT), scale8, hsvToRgb +#include "light/Palette.h" // colorFromPalette + the global active palette +#include "core/color.h" // sin8 (integer sine LUT), scale8 #include "platform/platform.h" // alloc — the fade trail buffer #include @@ -13,7 +14,7 @@ namespace mm { // scrolls sideways over time, leaving a fading trail behind it. The classic "oscilloscope wave" // look. Prior art: MoonLight's Wave effect (Ewoud Wijma) — behaviour reproduced (the six waveform // types, the per-column phase travel, the time-varying colour, the frame fade), written fresh on -// projectMM's EffectBase + integer primitives (sin8 LUT, scale8); the colour is an hsvToRgb sweep. +// projectMM's EffectBase + integer primitives (sin8 LUT, scale8); the colour is a global-palette lookup. // // Axis convention: the waveform sets a y (its shape lives on HEIGHT); width is the travel axis. // So a 1-tall grid shows no wave — to drive a 1D output (a strip, a row of Hue lights) lay it out @@ -75,12 +76,15 @@ class WaveEffect : public EffectBase { // 1. Fade the trail (scale8 toward black) — a smaller `fade` = shorter tail. for (size_t i = 0; i < trailBytes_; i++) trail_[i] = scale8(trail_[i], fade); - // 2. Advance the travel phase from bpm (integer accumulator so a sub-ms dt isn't lost). + // 2. Advance the travel phase from bpm. First tick: seed lastElapsed_ to now so the wave + // starts from phase 0 instead of jumping by the whole device uptime (lastElapsed_ is 0 + // until the first loop). Afterwards advance by the real per-tick delta. const uint32_t now = elapsed(); + if (!started_) { lastElapsed_ = now; started_ = true; } phase_ += static_cast(now - lastElapsed_) * bpm; lastElapsed_ = now; const uint8_t t = static_cast((phase_ * 256) / 60000); // uint8 angle (256 = full turn) - // Colour cycles slowly over time (a palette substitute until palettes land — see waveColor). + // Colour cycles slowly over time: now/50 indexes the active palette via waveColor. const uint8_t colorIndex = static_cast(now / 50); // 3. Plot the wave point per column, joining discontinuous shapes to the previous column. @@ -117,10 +121,11 @@ class WaveEffect : public EffectBase { size_t trailBytes_ = 0; uint64_t phase_ = 0; uint32_t lastElapsed_ = 0; + bool started_ = false; // first-tick guard: seed lastElapsed_ before the first delta - // The colour for the wave this frame. ONE place: today a hue sweep via hsvToRgb; when palettes - // land this becomes the palette lookup (ColorFromPalette(palette, index)) with no other change. - static RGB waveColor(uint8_t index) { return hsvToRgb(index, 255, 255); } + // The colour for the wave this frame — one place: a lookup into the global active palette, + // so the wave recolours when the palette changes. + static RGB waveColor(uint8_t index) { return colorFromPalette(*Palettes::active(), index); } // Map a phase (uint8 angle) to a y in [0, h) for the selected waveform. Integer-only. lengthType waveY(uint8_t phase, lengthType h) const { return waveY(type, phase, h); } diff --git a/src/main.cpp b/src/main.cpp index fb22e967..865e98fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,18 +8,14 @@ #include "light/effects/WaveEffect.h" #include "light/effects/NoiseEffect.h" #include "light/effects/PlasmaEffect.h" -#include "light/effects/PlasmaPaletteEffect.h" #include "light/effects/MetaballsEffect.h" #include "light/effects/FireEffect.h" #include "light/effects/ParticlesEffect.h" -#include "light/effects/GlowParticlesEffect.h" -#include "light/effects/CheckerboardEffect.h" #include "light/moonlive/MoonLiveEffect.h" #include "light/effects/SpiralEffect.h" #include "light/effects/RingsEffect.h" #include "light/effects/RipplesEffect.h" #include "light/effects/LavaLampEffect.h" -#include "light/effects/GameOfLifeEffect.h" #include "light/effects/NetworkReceiveEffect.h" #include "light/effects/AudioVolumeEffect.h" #include "light/effects/AudioSpectrumEffect.h" @@ -74,7 +70,9 @@ static void registerModuleTypes() { // Second argument is the module's spec page relative to docs/moonmodules/ — - // the UI builds a help link from it. Filename always matches the type name. + // the UI builds a help link from it. Effects/modifiers/leaf-layouts share one + // compact-row page per type (effects/effects.md, …); containers, drivers, and + // core modules keep a per-module page named for the type. // Containers mm::ModuleFactory::registerType("Layouts", "light/Layouts.md"); mm::ModuleFactory::registerType("Layers", "light/Layers.md"); @@ -83,36 +81,32 @@ static void registerModuleTypes() { // Concrete modules. registerType captures the type's dimensions() via // if-constexpr when present — EffectBase and ModifierBase both expose one, // so the UI's 📏/🟦/🧊 chip lights up without any per-domain wrapper. - mm::ModuleFactory::registerType("GridLayout", "light/layouts/GridLayout.md"); - mm::ModuleFactory::registerType("SphereLayout", "light/layouts/SphereLayout.md"); - mm::ModuleFactory::registerType("WheelLayout", "light/layouts/WheelLayout.md"); - mm::ModuleFactory::registerType("LinesEffect", "light/effects/LinesEffect.md"); - mm::ModuleFactory::registerType("RainbowEffect", "light/effects/RainbowEffect.md"); - mm::ModuleFactory::registerType("WaveEffect", "light/effects/WaveEffect.md"); - mm::ModuleFactory::registerType("NoiseEffect", "light/effects/NoiseEffect.md"); - mm::ModuleFactory::registerType("PlasmaEffect", "light/effects/PlasmaEffect.md"); - mm::ModuleFactory::registerType("PlasmaPaletteEffect", "light/effects/PlasmaPaletteEffect.md"); - mm::ModuleFactory::registerType("MetaballsEffect", "light/effects/MetaballsEffect.md"); - mm::ModuleFactory::registerType("FireEffect", "light/effects/FireEffect.md"); - mm::ModuleFactory::registerType("ParticlesEffect", "light/effects/ParticlesEffect.md"); - mm::ModuleFactory::registerType("GlowParticlesEffect", "light/effects/GlowParticlesEffect.md"); - mm::ModuleFactory::registerType("CheckerboardEffect", "light/effects/CheckerboardEffect.md"); - mm::ModuleFactory::registerType("SpiralEffect", "light/effects/SpiralEffect.md"); - mm::ModuleFactory::registerType("RingsEffect", "light/effects/RingsEffect.md"); - mm::ModuleFactory::registerType("RipplesEffect", "light/effects/RipplesEffect.md"); - mm::ModuleFactory::registerType("LavaLampEffect", "light/effects/LavaLampEffect.md"); - mm::ModuleFactory::registerType("GameOfLifeEffect", "light/effects/GameOfLifeEffect.md"); - mm::ModuleFactory::registerType("NetworkReceiveEffect", "light/effects/NetworkReceiveEffect.md"); - mm::ModuleFactory::registerType("AudioVolumeEffect", "light/effects/AudioVolumeEffect.md"); - mm::ModuleFactory::registerType("AudioSpectrumEffect", "light/effects/AudioSpectrumEffect.md"); - mm::ModuleFactory::registerType("SineEffect", "light/effects/SineEffect.md"); - mm::ModuleFactory::registerType("DistortionWavesEffect", "light/effects/DistortionWavesEffect.md"); + mm::ModuleFactory::registerType("GridLayout", "light/layouts/layouts.md#grid"); + mm::ModuleFactory::registerType("SphereLayout", "light/layouts/layouts.md#sphere"); + mm::ModuleFactory::registerType("WheelLayout", "light/layouts/layouts.md#wheel"); + mm::ModuleFactory::registerType("LinesEffect", "light/effects/effects.md#lines"); + mm::ModuleFactory::registerType("RainbowEffect", "light/effects/effects.md#rainbow"); + mm::ModuleFactory::registerType("WaveEffect", "light/effects/effects.md#wave"); + mm::ModuleFactory::registerType("NoiseEffect", "light/effects/effects.md#noise"); + mm::ModuleFactory::registerType("PlasmaEffect", "light/effects/effects.md#plasma"); + mm::ModuleFactory::registerType("MetaballsEffect", "light/effects/effects.md#metaballs"); + mm::ModuleFactory::registerType("FireEffect", "light/effects/effects.md#fire"); + mm::ModuleFactory::registerType("ParticlesEffect", "light/effects/effects.md#particles"); + mm::ModuleFactory::registerType("SpiralEffect", "light/effects/effects.md#spiral"); + mm::ModuleFactory::registerType("RingsEffect", "light/effects/effects.md#rings"); + mm::ModuleFactory::registerType("RipplesEffect", "light/effects/effects.md#ripples"); + mm::ModuleFactory::registerType("LavaLampEffect", "light/effects/effects.md#lavalamp"); + mm::ModuleFactory::registerType("NetworkReceiveEffect", "light/effects/effects.md#networkreceive"); + mm::ModuleFactory::registerType("AudioVolumeEffect", "light/effects/effects.md#audiovolume"); + mm::ModuleFactory::registerType("AudioSpectrumEffect", "light/effects/effects.md#audiospectrum"); + mm::ModuleFactory::registerType("SineEffect", "light/effects/effects.md#sine"); + mm::ModuleFactory::registerType("DistortionWavesEffect", "light/effects/effects.md#distortionwaves"); mm::ModuleFactory::registerType("MoonLiveEffect", "light/moonlive/MoonLiveEffect.md"); - mm::ModuleFactory::registerType("MultiplyModifier", "light/modifiers/MultiplyModifier.md"); - mm::ModuleFactory::registerType("CheckerboardModifier", "light/modifiers/CheckerboardModifier.md"); - mm::ModuleFactory::registerType("RandomMapModifier", "light/modifiers/RandomMapModifier.md"); - mm::ModuleFactory::registerType("RotateModifier", "light/modifiers/RotateModifier.md"); - mm::ModuleFactory::registerType("RegionModifier", "light/modifiers/RegionModifier.md"); + mm::ModuleFactory::registerType("MultiplyModifier", "light/modifiers/modifiers.md#multiply"); + mm::ModuleFactory::registerType("CheckerboardModifier", "light/modifiers/modifiers.md#checkerboard"); + mm::ModuleFactory::registerType("RandomMapModifier", "light/modifiers/modifiers.md#randommap"); + mm::ModuleFactory::registerType("RotateModifier", "light/modifiers/modifiers.md#rotate"); + mm::ModuleFactory::registerType("RegionModifier", "light/modifiers/modifiers.md#region"); mm::ModuleFactory::registerType("HueDriver", "light/drivers/HueDriver.md"); mm::ModuleFactory::registerType("NetworkSendDriver", "light/drivers/NetworkSendDriver.md"); mm::ModuleFactory::registerType("PreviewDriver", "light/drivers/PreviewDriver.md"); diff --git a/src/platform/desktop/platform_desktop.cpp b/src/platform/desktop/platform_desktop.cpp index e35c5103..7baa1986 100644 --- a/src/platform/desktop/platform_desktop.cpp +++ b/src/platform/desktop/platform_desktop.cpp @@ -496,6 +496,16 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* if (body && bodyLen) body[0] = '\0'; if (!method || !host || !path) return 0; + // One absolute deadline for the whole request: connect, send, and recv each consume from the + // same budget rather than each getting a fresh timeoutMs (which let the total reach ~3× + // timeoutMs). `remainingMs()` is the time left before the deadline, floored at 1ms so a phase + // never gets a 0 timeout (which means "block forever" for SO_*TIMEO). + const uint32_t deadline = millis() + timeoutMs; + auto remainingMs = [&]() -> uint32_t { + const uint32_t now = millis(); + return now >= deadline ? 1u : (deadline - now); + }; + int fd = open_sock(AF_INET, SOCK_STREAM, 0); if (fd < 0) return 0; struct CloseGuard { int f; ~CloseGuard() { close_sock(f); } } guard{fd}; @@ -521,9 +531,10 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* if (cr != 0 && !inProgress) return 0; // immediate hard failure if (cr != 0) { // connect in progress — wait for writable fd_set wf; FD_ZERO(&wf); FD_SET(sock(fd), &wf); + const uint32_t cms = remainingMs(); timeval ctv{}; - ctv.tv_sec = static_cast(timeoutMs / 1000); - ctv.tv_usec = static_cast((timeoutMs % 1000) * 1000); + ctv.tv_sec = static_cast(cms / 1000); + ctv.tv_usec = static_cast((cms % 1000) * 1000); if (::select(static_cast(sock(fd)) + 1, nullptr, &wf, nullptr, &ctv) <= 0) return 0; // timeout / error int soerr = 0; socklen_t len = sizeof(soerr); ::getsockopt(sock(fd), SOL_SOCKET, SO_ERROR, reinterpret_cast(&soerr), &len); @@ -531,16 +542,18 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* } if (make_blocking(fd) != 0) return 0; // back to blocking for the bounded send/recv - // Bound the request send + response recv with SO_RCVTIMEO/SO_SNDTIMEO (the same shape the - // rest of the file uses). + // Bound the request send + response recv with SO_RCVTIMEO/SO_SNDTIMEO, using the time LEFT on + // the shared deadline (not a fresh timeoutMs) so connect + send + recv together stay within the + // caller's budget. + const uint32_t sms = remainingMs(); #ifdef _WIN32 - DWORD tv = timeoutMs; + DWORD tv = sms; ::setsockopt(sock(fd), SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&tv), sizeof(tv)); ::setsockopt(sock(fd), SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast(&tv), sizeof(tv)); #else timeval tv{}; - tv.tv_sec = static_cast(timeoutMs / 1000); - tv.tv_usec = static_cast((timeoutMs % 1000) * 1000); + tv.tv_sec = static_cast(sms / 1000); + tv.tv_usec = static_cast((sms % 1000) * 1000); ::setsockopt(sock(fd), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); ::setsockopt(sock(fd), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); #endif diff --git a/src/platform/esp32/platform_esp32.cpp b/src/platform/esp32/platform_esp32.cpp index 23467df2..3792522c 100644 --- a/src/platform/esp32/platform_esp32.cpp +++ b/src/platform/esp32/platform_esp32.cpp @@ -1116,6 +1116,16 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* if (body && bodyLen) body[0] = '\0'; if (!method || !host || !path) return 0; + // One absolute deadline for the whole request: connect, send, and recv each consume from the + // same budget rather than each getting a fresh timeoutMs (which let the total reach ~3× + // timeoutMs). `remainingMs()` is the time left before the deadline, floored at 1ms so a phase + // never gets a 0 timeout (which means "block forever" for SO_*TIMEO). + const uint32_t deadline = millis() + timeoutMs; + auto remainingMs = [&]() -> uint32_t { + const uint32_t now = millis(); + return now >= deadline ? 1u : (deadline - now); + }; + int fd = ::socket(AF_INET, SOCK_STREAM, 0); if (fd < 0) return 0; struct CloseGuard { int f; ~CloseGuard() { ::close(f); } } guard{fd}; @@ -1135,9 +1145,10 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* if (cr != 0 && errno != EINPROGRESS) return 0; // immediate hard failure if (cr != 0) { // connect in progress — wait for writable fd_set wf; FD_ZERO(&wf); FD_SET(fd, &wf); + const uint32_t cms = remainingMs(); timeval ctv{}; - ctv.tv_sec = static_cast(timeoutMs / 1000); - ctv.tv_usec = static_cast((timeoutMs % 1000) * 1000); + ctv.tv_sec = static_cast(cms / 1000); + ctv.tv_usec = static_cast((cms % 1000) * 1000); if (::select(fd + 1, nullptr, &wf, nullptr, &ctv) <= 0) return 0; // timeout / error int soerr = 0; socklen_t len = sizeof(soerr); getsockopt(fd, SOL_SOCKET, SO_ERROR, &soerr, &len); @@ -1145,10 +1156,13 @@ int httpRequest(const char* method, const char* host, uint16_t port, const char* } fcntl(fd, F_SETFL, flags); // back to blocking - // Bound the request send + response recv with SO_RCVTIMEO/SO_SNDTIMEO. + // Bound the request send + response recv with SO_RCVTIMEO/SO_SNDTIMEO, using the time LEFT on + // the shared deadline (not a fresh timeoutMs) so connect + send + recv together stay within the + // caller's budget. + const uint32_t sms = remainingMs(); timeval tv{}; - tv.tv_sec = static_cast(timeoutMs / 1000); - tv.tv_usec = static_cast((timeoutMs % 1000) * 1000); + tv.tv_sec = static_cast(sms / 1000); + tv.tv_usec = static_cast((sms % 1000) * 1000); setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); diff --git a/src/ui/app.js b/src/ui/app.js index c3938422..cad86f55 100644 --- a/src/ui/app.js +++ b/src/ui/app.js @@ -47,7 +47,7 @@ const dragTs = {}; // per-control last-touched timestamp (ms) // read-only types (display/display-int/time/progress) and the composite `list` // are absent on purpose: they always reflect the latest push. const EDITABLE_CONTROL_TYPES = new Set( - ["uint8", "uint16", "int16", "pin", "bool", "text", "textarea", "password", "select", "ipv4"]); + ["uint8", "uint16", "int16", "pin", "bool", "text", "textarea", "password", "select", "palette", "ipv4"]); const TIMING_MODES = ["fps", "ms"]; // localStorage keys per ui.md @@ -1173,6 +1173,100 @@ function createControl(moduleName, moduleType, ctrl) { appendResetButton(row, moduleName, ctrl, def, () => { sel.value = def; }); break; } + case "palette": { + // A colour-palette dropdown where EVERY option shows its own gradient — so the colours + // are visible before selecting, not just after. A native

#f>;iPJ3W{fs@fhLzgnfyqo6X$% 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 diff --git a/docs/assets/light/effects/GlowParticlesEffect.png b/docs/assets/light/effects/GlowParticlesEffect.png deleted file mode 100644 index 80760ec7678b2e619e667f50045ce27438eb0186..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15180 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 diff --git a/docs/assets/light/effects/PlasmaPaletteEffect.gif b/docs/assets/light/effects/PlasmaPaletteEffect.gif deleted file mode 100644 index bca860f42a2164dc8490d4b9614954419458b601..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 274901 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