From 39b7b3ad53f4a96c7b8ab3a75934708ca547fcf0 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 20 Oct 2021 20:29:13 +0200 Subject: [PATCH 001/120] CCT (color white balance support) --- wled00/FX.h | 3 +- wled00/FX_fcn.cpp | 17 +++- wled00/bus_manager.h | 160 ++++++++++++++++++---------------- wled00/cfg.cpp | 4 +- wled00/data/index.css | 52 ++++++++++- wled00/data/index.htm | 17 ++-- wled00/data/index.js | 35 ++++---- wled00/data/settings_leds.htm | 72 ++++++++++++++- wled00/set.cpp | 1 + wled00/wled.h | 9 +- 10 files changed, 254 insertions(+), 116 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 4bdec48f9a..8a9691815f 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -247,7 +247,7 @@ class WS2812FX { // segment parameters public: - typedef struct Segment { // 29 (32 in memory?) bytes + typedef struct Segment { // 30 (33 in memory?) bytes uint16_t start; uint16_t stop; //segment invalid if stop == 0 uint16_t offset; @@ -259,6 +259,7 @@ class WS2812FX { uint8_t grouping, spacing; uint8_t opacity; uint32_t colors[NUM_COLORS]; + uint8_t cct; char *name; bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f89df5ed1f..05914e38e2 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -220,6 +220,17 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) uint16_t realIndex = realPixelIndex(i); uint16_t len = SEGMENT.length(); + // determine if we can do white balance + int16_t cct = -1; + for (uint8_t b = 0; b < busses.getNumBusses(); b++) { + Bus *bus = busses.getBus(b); + if (bus == nullptr || !bus->containsPixel(realIndex)) continue; + if (allowCCT || bus->getType() == TYPE_ANALOG_2CH || bus->getType() == TYPE_ANALOG_5CH) { + cct = SEGMENT.cct; + break; + } + } + for (uint16_t j = 0; j < SEGMENT.grouping; j++) { uint16_t indexSet = realIndex + (IS_REVERSE ? -j : j); if (indexSet >= SEGMENT.start && indexSet < SEGMENT.stop) { @@ -230,14 +241,14 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) if (indexMir >= SEGMENT.stop) indexMir -= len; if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir]; - busses.setPixelColor(indexMir, col); + busses.setPixelColor(indexMir, col, cct); } /* offset/phase */ indexSet += SEGMENT.offset; if (indexSet >= SEGMENT.stop) indexSet -= len; if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet]; - busses.setPixelColor(indexSet, col); + busses.setPixelColor(indexSet, col, cct); } } } else { //live data, etc. @@ -623,6 +634,7 @@ void WS2812FX::resetSegments() { _segments[0].setOption(SEG_OPTION_SELECTED, 1); _segments[0].setOption(SEG_OPTION_ON, 1); _segments[0].opacity = 255; + _segments[0].cct = 128; for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++) { @@ -630,6 +642,7 @@ void WS2812FX::resetSegments() { _segments[i].grouping = 1; _segments[i].setOption(SEG_OPTION_ON, 1); _segments[i].opacity = 255; + _segments[i].cct = 128; _segments[i].speed = DEFAULT_SPEED; _segments[i].intensity = DEFAULT_INTENSITY; _segment_runtimes[i].reset(); diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index 799019f30f..ffe6a04fea 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -10,6 +10,9 @@ #include "bus_wrapper.h" #include +//color.cpp +uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); + // enable additional debug output #ifdef WLED_DEBUG #ifndef ESP8266 @@ -65,79 +68,48 @@ struct BusConfig { //parent class of BusDigital and BusPwm class Bus { public: - Bus(uint8_t type, uint16_t start) { - _type = type; - _start = start; - }; - - virtual void show() {} - virtual bool canShow() { return true; } - - virtual void setPixelColor(uint16_t pix, uint32_t c) {}; - - virtual void setBrightness(uint8_t b) {}; - - virtual uint32_t getPixelColor(uint16_t pix) { return 0; }; - - virtual void cleanup() {}; - - virtual ~Bus() { //throw the bus under the bus - } - - virtual uint8_t getPins(uint8_t* pinArray) { return 0; } - - inline uint16_t getStart() { - return _start; - } - - inline void setStart(uint16_t start) { - _start = start; - } - - virtual uint16_t getLength() { - return 1; - } - - virtual void setColorOrder() {} - - virtual uint8_t getColorOrder() { - return COL_ORDER_RGB; - } - - virtual bool isRgbw() { - return false; - } - - virtual uint8_t skippedLeds() { - return 0; - } - - inline uint8_t getType() { - return _type; - } - - inline bool isOk() { - return _valid; - } - - static bool isRgbw(uint8_t type) { - if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; - if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; - return false; - } + Bus(uint8_t type, uint16_t start) { + _type = type; + _start = start; + }; - inline bool isOffRefreshRequired() { - return _needsRefresh; - } + virtual ~Bus() {} //throw the bus under the bus + + virtual void show() {} + virtual bool canShow() { return true; } + virtual void setPixelColor(uint16_t pix, uint32_t c) {}; + virtual void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) {}; + virtual uint32_t getPixelColor(uint16_t pix) { return 0; }; + virtual void setBrightness(uint8_t b) {}; + virtual void cleanup() {}; + virtual uint8_t getPins(uint8_t* pinArray) { return 0; } + virtual uint16_t getLength() { return 1; } + virtual void setColorOrder() {} + virtual uint8_t getColorOrder() { return COL_ORDER_RGB; } + virtual uint8_t skippedLeds() { return 0; } + + inline uint16_t getStart() { return _start; } + inline void setStart(uint16_t start) { _start = start; } + inline uint8_t getType() { return _type; } + inline bool isOk() { return _valid; } + inline bool isOffRefreshRequired() { return _needsRefresh; } + inline bool containsPixel(uint16_t pix) { return pix >= _start; } + + virtual bool isRgbw() { return false; } + static bool isRgbw(uint8_t type) { + if (type == TYPE_SK6812_RGBW || type == TYPE_TM1814) return true; + if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; + return false; + } - bool reversed = false; + bool reversed = false; protected: - uint8_t _type = TYPE_NONE; - uint8_t _bri = 255; - uint16_t _start = 0; - bool _valid = false; - bool _needsRefresh = false; + uint8_t _type = TYPE_NONE; + uint8_t _bri = 255; + uint16_t _start = 0; + bool _valid = false; + bool _needsRefresh = false; }; @@ -190,6 +162,11 @@ class BusDigital : public Bus { PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder); } + void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { + c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT + setPixelColor(pix, c); + } + uint32_t getPixelColor(uint16_t pix) { if (reversed) pix = _len - pix -1; else pix += _skip; @@ -285,6 +262,34 @@ class BusPwm : public Bus { _valid = true; }; + void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { + if (pix != 0 || !_valid) return; //only react to first pixel + c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT (w remains unchanged) + uint8_t r = c >> 16; + uint8_t g = c >> 8; + uint8_t b = c ; + uint8_t w = c >> 24; + + switch (_type) { + case TYPE_ANALOG_1CH: //one channel (white), use highest RGBW value + _data[0] = max(r, max(g, max(b, w))); + break; + case TYPE_ANALOG_2CH: //warm white + cold white + // perhaps a non-linear adjustment would be in order. need to test + _data[1] = (w * cct) / 255; + _data[0] = 255 - _data[1]; // or (w * (255-cct)) / 255; + break; + case TYPE_ANALOG_5CH: //RGB + warm white + cold white + // perhaps a non-linear adjustment would be in order. need to test + _data[4] = (w * cct) / 255; w = 255 - w; // or (w * (255-cct)) / 255; + case TYPE_ANALOG_4CH: //RGBW + _data[3] = w; + case TYPE_ANALOG_3CH: //standard dumb RGB + _data[0] = r; _data[1] = g; _data[2] = b; + break; + } + } + void setPixelColor(uint16_t pix, uint32_t c) { if (pix != 0 || !_valid) return; //only react to first pixel uint8_t r = c >> 16; @@ -295,14 +300,11 @@ class BusPwm : public Bus { switch (_type) { case TYPE_ANALOG_1CH: //one channel (white), use highest RGBW value _data[0] = max(r, max(g, max(b, w))); break; - - case TYPE_ANALOG_2CH: //warm white + cold white, we'll need some nice handling here, for now just R+G channels + case TYPE_ANALOG_2CH: //warm white + cold white case TYPE_ANALOG_3CH: //standard dumb RGB - case TYPE_ANALOG_4CH: //RGBW + case TYPE_ANALOG_4CH: //standard dumb RGBW case TYPE_ANALOG_5CH: //we'll want the white handling from 2CH here + RGB _data[0] = r; _data[1] = g; _data[2] = b; _data[3] = w; _data[4] = 0; break; - - default: return; } } @@ -417,6 +419,11 @@ class BusNetwork : public Bus { if (_rgbw) _data[offset+3] = 0xFF & (c >> 24); } + void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { + c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT + setPixelColor(pix, c); + } + uint32_t getPixelColor(uint16_t pix) { if (!_valid || pix >= _len) return 0; uint16_t offset = pix * _UDPchannels; @@ -538,12 +545,13 @@ class BusManager { } } - void setPixelColor(uint16_t pix, uint32_t c) { + void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1) { for (uint8_t i = 0; i < numBusses; i++) { Bus* b = busses[i]; uint16_t bstart = b->getStart(); if (pix < bstart || pix >= bstart + b->getLength()) continue; - busses[i]->setPixelColor(pix - bstart, c); + if (cct<0) busses[i]->setPixelColor(pix - bstart, c); // no white balance + else busses[i]->setPixelColor(pix - bstart, c, cct); // do white balance } } diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 13bcdd9642..d0bbc6f8e0 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -84,6 +84,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); CJSON(strip.rgbwMode, hw_led[F("rgbwm")]); + CJSON(allowCCT, hw_led["cct"]); JsonArray ins = hw_led["ins"]; @@ -530,6 +531,7 @@ void serializeConfig() { hw_led[F("maxpwr")] = strip.ablMilliampsMax; hw_led[F("ledma")] = strip.milliampsPerLed; hw_led[F("rgbwm")] = strip.rgbwMode; + hw_led["cct"] = allowCCT; JsonArray hw_led_ins = hw_led.createNestedArray("ins"); @@ -546,7 +548,7 @@ void serializeConfig() { ins[F("order")] = bus->getColorOrder(); ins["rev"] = bus->reversed; ins[F("skip")] = bus->skippedLeds(); - ins["type"] = bus->getType() & 0x7F;; + ins["type"] = bus->getType() & 0x7F; ins["ref"] = bus->isOffRefreshRequired(); ins[F("rgbw")] = bus->isRgbw(); } diff --git a/wled00/data/index.css b/wled00/data/index.css index f27024ac83..cb5aac3d1d 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -467,6 +467,22 @@ img { z-index: -1; } +#rwrap .sliderdisplay, +#gwrap .sliderdisplay, +#bwrap .sliderdisplay, +#wwrap .sliderdisplay, +#wbal .sliderdisplay { + height: 28px; + top: 0; bottom: 0; + left: 0; right: 0; + /*border: 1px solid var(--c-b);*/ +} +#rwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #f00); } +#gwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #0f0); } +#bwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #00f); } +#wwrap .sliderdisplay { background: linear-gradient(90deg, #000 0%, #fff); } +#wbal .sliderdisplay { background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #d4e0ff); } + .sliderbubble { width: 36px; line-height: 24px; @@ -492,6 +508,14 @@ input[type=range] { background-color: transparent; cursor: pointer; } +#rwrap input[type=range], +#gwrap input[type=range], +#bwrap input[type=range], +#wwrap input[type=range], +#wbal input[type=range] { + width: 252px; + margin: 0; +} input[type=range]:focus { outline: none; } @@ -527,8 +551,24 @@ input[type=range]:active + .sliderbubble { display: inline; transform: translateX(-50%); } - -#wwrap { +#rwrap input[type=range]::-webkit-slider-thumb, +#gwrap input[type=range]::-webkit-slider-thumb, +#bwrap input[type=range]::-webkit-slider-thumb, +#wwrap input[type=range]::-webkit-slider-thumb, +#wbal input[type=range]::-webkit-slider-thumb { + height: 18px; + width: 18px; + border: 2px solid #000; + margin-top: 5px; +} +#rwrap input[type=range]::-moz-range-thumb, +#gwrap input[type=range]::-moz-range-thumb, +#bwrap input[type=range]::-moz-range-thumb, +#wwrap input[type=range]::-moz-range-thumb, +#wbal input[type=range]::-moz-range-thumb { + border: 2px solid var(--c-1); +} +#wwrap, #wbal { display: none; } @@ -537,6 +577,14 @@ input[type=range]:active + .sliderbubble { width: 240px; position: relative; } +#rwrap .sliderwrap, +#gwrap .sliderwrap, +#bwrap .sliderwrap, +#wwrap .sliderwrap, +#wbal .sliderwrap { + width: 260px; + margin: 10px 0 0; +} .sbs { margin: 0px -20px 5px -6px; diff --git a/wled00/data/index.htm b/wled00/data/index.htm index 530f4cd443..5be885f7ea 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -47,22 +47,29 @@
- +

- +

- +

White channel

- + +
+
+
+
+

White balance

+
+
@@ -98,7 +105,7 @@
diff --git a/wled00/data/index.js b/wled00/data/index.js index 7bf47b25e4..26d1afe39b 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -51,7 +51,7 @@ var cpick = new iro.ColorPicker("#picker", { options: { sliderType: 'value' } - }, + }/*, { component: iro.ui.Slider, options: { @@ -59,7 +59,7 @@ var cpick = new iro.ColorPicker("#picker", { minTemperature: 2100, maxTemperature: 10000 } - } + }*/ ] }); @@ -854,21 +854,14 @@ function loadNodes() }); } -function updateTrail(e, slidercol) +function updateTrail(e) { if (e==null) return; var max = e.hasAttribute('max') ? e.attributes.max.value : 255; var perc = e.value * 100 / max; perc = parseInt(perc); if (perc < 50) perc += 2; - var scol; - switch (slidercol) { - case 1: scol = "#f00"; break; - case 2: scol = "#0f0"; break; - case 3: scol = "#00f"; break; - default: scol = "var(--c-f)"; - } - var val = `linear-gradient(90deg, ${scol} ${perc}%, var(--c-4) ${perc}%)`; + var val = `linear-gradient(90deg, var(--c-f) ${perc}%, var(--c-4) ${perc}%)`; e.parentNode.getElementsByClassName('sliderdisplay')[0].style.background = val; } @@ -939,8 +932,8 @@ function updateUI() updateTrail(d.getElementById('sliderBri')); updateTrail(d.getElementById('sliderSpeed')); updateTrail(d.getElementById('sliderIntensity')); - updateTrail(d.getElementById('sliderW')); - if (isRgbw) d.getElementById('wwrap').style.display = "block"; + d.getElementById('wwrap').style.display = (isRgbw) ? "block":"none"; + d.getElementById("wbal").style.display = (lastinfo.leds.cct) ? "block":"none"; updatePA(); updateHex(); @@ -1023,6 +1016,7 @@ function readState(s,command=false) { selectSlot(csel); } d.getElementById('sliderW').value = whites[csel]; + if (i.cct && i.cct>=0) d.getElementById("sliderA").value = i.cct; d.getElementById('sliderSpeed').value = i.sx; d.getElementById('sliderIntensity').value = i.ix; @@ -1560,6 +1554,11 @@ function setSegBri(s){ requestJson(obj); } +function setBalance(b) +{ + var obj = {"seg": {"cct": parseInt(b)}}; + requestJson(obj); +} function setX(ind = null) { if (ind === null) { ind = parseInt(d.querySelector('#fxlist input[name="fx"]:checked').value); @@ -1723,7 +1722,6 @@ function selectSlot(b) { cd[csel].style.width="50px"; cpick.color.set(cd[csel].style.backgroundColor); d.getElementById('sliderW').value = whites[csel]; - updateTrail(d.getElementById('sliderW')); updateHex(); updateRgb(); redrawPalPrev(); @@ -1748,12 +1746,9 @@ function pC(col) function updateRgb() { var col = cpick.color.rgb; - var s = d.getElementById('sliderR'); - s.value = col.r; updateTrail(s,1); - s = d.getElementById('sliderG'); - s.value = col.g; updateTrail(s,2); - s = d.getElementById('sliderB'); - s.value = col.b; updateTrail(s,3); + d.getElementById('sliderR').value = col.r; + d.getElementById('sliderG').value = col.g; + d.getElementById('sliderB').value = col.b; } function updateHex() diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 187fd289fe..650d0d7cde 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -247,8 +247,8 @@ gId('m0').innerHTML = memu; bquot = memu / maxM * 100; gId('dbar').style.background = `linear-gradient(90deg, ${bquot > 60 ? (bquot > 90 ? "red":"orange"):"#ccc"} 0 ${bquot}%%, #444 ${bquot}%% 100%%)`; - gId('ledwarning').style.display = (sLC > maxPB || maxLC > 800 || bquot > 80) ? 'inline':'none'; - gId('ledwarning').style.color = (sLC > maxPB || maxLC > maxPB || bquot > 100) ? 'red':'orange'; + gId('ledwarning').style.display = (maxLC > Math.min(maxPB,800) || bquot > 80) ? 'inline':'none'; + gId('ledwarning').style.color = (maxLC > Math.max(maxPB,800) || bquot > 100) ? 'red':'orange'; gId('wreason').innerHTML = (bquot > 80) ? "80% of max. LED memory" +(bquot>100 ? ` (ERROR: Using over ${maxM}B!)` : "") : "800 LEDs per output"; // calculate power var val = Math.ceil((100 + sPC * laprev)/500)/2; @@ -389,11 +389,71 @@ req.send(formData); d.Sf.data.value = ''; return false; + } + // https://stackoverflow.com/questions/7346563/loading-local-json-file + function loadCfg(o) { + var f, fr; + + if (typeof window.FileReader !== 'function') { + alert("The file API isn't supported on this browser yet."); + return; + } + + if (!o.files) { + alert("This browser doesn't seem to support the `files` property of file inputs."); + } else if (!o.files[0]) { + alert("Please select a JSON file before clicking 'Apply'"); + } else { + f = o.files[0]; + fr = new FileReader(); + fr.onload = receivedText; + fr.readAsText(f); + } + o.value = ''; + + function receivedText(e) { + let lines = e.target.result; + var c = JSON.parse(lines); + if (c.hw) { + if (c.hw.led) { + for (var i=0; i<10; i++) addLEDs(-1); + var l = c.hw.led; + l.ins.forEach((v,i,a)=>{ + addLEDs(1); + for (var j=0; j{ + addBtn(i,v.pin[0],v.type); + }); + d.getElementsByName("TT")[0].value = b.tt; + } + if (c.hw.ir) { + d.getElementsByName("IR")[0].value = c.hw.ir.pin; + d.getElementsByName("IT")[0].value = c.hw.ir.type; + } + if (c.hw.relay) { + d.getElementsByName("RL")[0].value = c.hw.relay.pin; + d.getElementsByName("RM")[0].checked = c.hw.relay.inv; + } + UI(); + } + } } function GetV() { //values injected by server while sending HTML - //d.um_p=[6,7,8,9,10,11,1];bLimits(3,4096,4000,1664);d.Sf.MS.checked=1;addLEDs(1);d.Sf.L00.value=2;d.Sf.LC0.value=30;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=15;d.Sf.CV0.checked=1;d.Sf.SL0.checked=0;addLEDs(1);d.Sf.L01.value=10;d.Sf.L11.value=10;d.Sf.L21.value=1;d.Sf.L31.value=10;d.Sf.LC1.value=60;d.Sf.LT1.value=80;d.Sf.CO1.value=1;d.Sf.LS1.value=0;d.Sf.CV1.checked=0;d.Sf.SL1.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=56;d.Sf.AW.value=3;d.Sf.BO.checked=1;d.Sf.BP.value=80;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=0;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=12;d.Sf.RM.checked=1;addBtn(0,0,0);addBtn(1,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=0; + //d.um_p=[6,7,8,9,10,11,14,15,13,1,21,19,22,25,26,27,5,23,18,17];bLimits(10,2048,64000,8192);d.Sf.MS.checked=1;d.Sf.CCT.checked=0;addLEDs(1);d.Sf.L00.value=192;d.Sf.L10.value=168;d.Sf.L20.value=0;d.Sf.L30.value=61;d.Sf.LC0.value=421;d.Sf.LT0.value=80;d.Sf.CO0.value=1;d.Sf.LS0.value=0;d.Sf.CV0.checked=0;d.Sf.SL0.checked=0;d.Sf.RF0.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=127;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=0;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=1;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=-1;d.Sf.RM.checked=1;addBtn(0,-1,0);addBtn(1,-1,0);addBtn(2,-1,0);addBtn(3,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=8; }

WLED Software Update

-Installed version: 0.13.0-b4
Download the latest binary: Download the latest binary:


Incorrect configuration may require a factory reset or re-flashing of your ESP.
For security reasons, passwords are not backed up.

About

WLED - version 0.13.0-b4


Contributors, dependencies and special thanks
A huge thank you to everyone who helped me create WLED!

diff --git a/wled00/improv.cpp b/wled00/improv.cpp index cf31cc0390..56ee9e0a05 100644 --- a/wled00/improv.cpp +++ b/wled00/improv.cpp @@ -189,7 +189,7 @@ void sendImprovInfoResponse() { out[11] = 4; //Firmware len ("WLED") out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D'; uint8_t lengthSum = 17; - uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.13.0-b4/%i"),VERSION); + uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.13.0-b5/%i"),VERSION); out[16] = vlen; lengthSum += vlen; uint8_t hlen = 7; #ifdef ESP8266 diff --git a/wled00/json.cpp b/wled00/json.cpp index 72cb4be044..4ac81fe77a 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -501,7 +501,7 @@ void serializeInfo(JsonObject root) leds[F("fps")] = strip.getFps(); leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0; leds[F("maxseg")] = strip.getMaxSegments(); - leds[F("seglock")] = false; //will be used in the future to prevent modifications to segment config + //leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config root[F("str")] = syncToggleReceive; @@ -563,7 +563,7 @@ void serializeInfo(JsonObject root) root[F("resetReason0")] = (int)rtc_get_reset_reason(0); root[F("resetReason1")] = (int)rtc_get_reset_reason(1); #endif - root[F("lwip")] = 0; + root[F("lwip")] = 0; //deprecated #else root[F("arch")] = "esp8266"; root[F("core")] = ESP.getCoreVersion(); diff --git a/wled00/wled.h b/wled00/wled.h index 331bcfead7..d173ff27af 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -3,12 +3,12 @@ /* Main sketch, global variable declarations @title WLED project sketch - @version 0.13.0-b4 + @version 0.13.0-b5 @author Christian Schwinne */ // version code in format yymmddb (b = daily build) -#define VERSION 2110110 +#define VERSION 2111170 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG From 4af1f62aab42c4ad0458b06d19fc8a71e4c7a3c6 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Wed, 17 Nov 2021 01:19:04 +0100 Subject: [PATCH 029/120] Revert testing PIO changes --- platformio.ini | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/platformio.ini b/platformio.ini index 52142fc7b0..e700ed2be8 100644 --- a/platformio.ini +++ b/platformio.ini @@ -290,20 +290,20 @@ lib_deps = ${esp8266.lib_deps} [env:esp32dev] board = esp32dev -platform = espressif32@3.3.2 +platform = espressif32@2.0 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32 #-D WLED_DISABLE_BROWNOUT_DET lib_deps = ${esp32.lib_deps} -#board_build.partitions = ${esp32.default_partitions} +board_build.partitions = ${esp32.default_partitions} [env:esp32_eth] board = esp32-poe -platform = espressif32@3.3.2 +platform = espressif32@2.0 upload_speed = 921600 build_unflags = ${common.build_unflags} build_flags = ${common.build_flags_esp32} -D WLED_RELEASE_NAME=ESP32_Ethernet -D RLYPIN=-1 -D WLED_USE_ETHERNET -D BTNPIN=-1 lib_deps = ${esp32.lib_deps} -#board_build.partitions = ${esp32.default_partitions} +board_build.partitions = ${esp32.default_partitions} [env:esp32s2_saola] board = esp32dev From d31e4c7815cc2997fb983682d434fa430db6bc5c Mon Sep 17 00:00:00 2001 From: cschwinne Date: Wed, 17 Nov 2021 11:13:07 +0100 Subject: [PATCH 030/120] Added getPinOwner Only disable builtin LED if bus to avoid breaking other things on the pin --- wled00/button.cpp | 7 +++++-- wled00/pin_manager.cpp | 5 +++++ wled00/pin_manager.h | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/wled00/button.cpp b/wled00/button.cpp index 39c1e4f7fd..aef18c77e7 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -299,8 +299,11 @@ void handleIO() #ifdef ESP8266 // turn off built-in LED if strip is turned off // this will break digital bus so will need to be reinitialised on On - pinMode(LED_BUILTIN, OUTPUT); - digitalWrite(LED_BUILTIN, HIGH); + PinOwner ledPinOwner = pinManager.getPinOwner(LED_BUILTIN); + if (!strip.isOffRefreshRequred && (ledPinOwner == PinOwner::None || ledPinOwner == PinOwner::BusDigital)) { + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + } #endif if (rlyPin>=0) { pinMode(rlyPin, OUTPUT); diff --git a/wled00/pin_manager.cpp b/wled00/pin_manager.cpp index 38e6e1621f..ece48c2485 100644 --- a/wled00/pin_manager.cpp +++ b/wled00/pin_manager.cpp @@ -125,6 +125,11 @@ bool PinManagerClass::isPinOk(byte gpio, bool output) return false; } +PinOwner PinManagerClass::getPinOwner(byte gpio) { + if (!isPinOk(gpio, false)) return PinOwner::None; + return ownerTag[gpio]; +} + #ifdef ARDUINO_ARCH_ESP32 byte PinManagerClass::allocateLedc(byte channels) { diff --git a/wled00/pin_manager.h b/wled00/pin_manager.h index 63f6d95e87..65d3196649 100644 --- a/wled00/pin_manager.h +++ b/wled00/pin_manager.h @@ -92,6 +92,8 @@ class PinManagerClass { bool isPinAllocated(byte gpio, PinOwner tag = PinOwner::None); bool isPinOk(byte gpio, bool output = true); + PinOwner getPinOwner(byte gpio); + #ifdef ARDUINO_ARCH_ESP32 byte allocateLedc(byte channels); void deallocateLedc(byte pos, byte channels); From 712e53ca8d1f88c3f2dc6c4b452c2116744cab93 Mon Sep 17 00:00:00 2001 From: Florian Heilmann Date: Mon, 8 Nov 2021 00:48:01 +0100 Subject: [PATCH 031/120] First implementation of AudioSource microphone code --- wled00/audio_reactive.h | 37 ++--- wled00/audio_source.h | 324 ++++++++++++++++++++++++++++++++++++++++ wled00/set.cpp | 10 +- wled00/usermod.cpp | 159 ++++---------------- 4 files changed, 367 insertions(+), 163 deletions(-) create mode 100644 wled00/audio_source.h diff --git a/wled00/audio_reactive.h b/wled00/audio_reactive.h index 3042e24083..6030fafdbe 100644 --- a/wled00/audio_reactive.h +++ b/wled00/audio_reactive.h @@ -17,6 +17,9 @@ #include "wled.h" #include +#include "audio_source.h" + +AudioSource *audioSource; // ALL AUDIO INPUT PINS DEFINED IN wled.h AND CONFIGURABLE VIA UI @@ -280,36 +283,16 @@ void FFTcode( void * parameter) { // Only run the FFT computing code if we're not in Receive mode if (audioSyncEnabled & (1 << 1)) continue; + audioSource->getSamples(vReal, samples); - microseconds = micros(); - //extern double volume; // COMMENTED OUT - UNUSED VARIABLE COMPILER WARNINGS - - for(int i=0; i> 2; // Analog Read - } else if (!doReboot) { - int32_t digitalSample = 0; - size_t bytes_read = 0; - i2s_read(I2S_PORT, &digitalSample, sizeof(digitalSample), &bytes_read, /*portMAX_DELAY*/ 10); //esp_err_t result = - //int bytes_read = i2s_pop_sample(I2S_PORT, (char *)&digitalSample, portMAX_DELAY); // no timeout - if (bytes_read > 0) micData = abs(digitalSample >> 16); - - } - micDataSm = ((micData * 3) + micData)/4; // We'll be passing smoothed micData to the volume routines as the A/D is a bit twitchy. - vReal[i] = micData; // Store Mic Data in an array - vImag[i] = 0; - - // MIC DATA DEBUGGING - // DEBUGSR_PRINT("micData: "); - // DEBUGSR_PRINT(micData); - // DEBUGSR_PRINT("\tmicDataSm: "); - // DEBUGSR_PRINT("\t"); - // DEBUGSR_PRINT(micDataSm); - // DEBUGSR_PRINT("\n"); + // Last sample in vReal is our current mic sample + micDataSm = (uint16_t)vReal[samples - 1]; - if (dmEnabled == 0) { while(micros() - microseconds < sampling_period_us){/*empty loop*/} } + // micDataSm = ((micData * 3) + micData)/4; - microseconds += sampling_period_us; + for (int i=0; i < samples; i++) + { + vImag[i] = 0; } FFT.Windowing( FFT_WIN_TYP_HAMMING, FFT_FORWARD ); // Weigh data diff --git a/wled00/audio_source.h b/wled00/audio_source.h new file mode 100644 index 0000000000..5e69aaeac6 --- /dev/null +++ b/wled00/audio_source.h @@ -0,0 +1,324 @@ +#pragma once + +#include +#include +#include + +/* ToDo: remove. ES7243 is controlled via compiler defines + Until this configuration is moved to the webinterface +*/ + +#ifndef MCLK_PIN + int mclkPin = 0; +#else + int mclkPin = MLCK_PIN; +#endif + +#ifndef ES7243_ADDR + int addr_ES7243 = 0x13; +#else + int addr_ES7243 = ES7243_ADDR; +#endif + +#ifndef ES7243_SDAPIN + int pin_ES7243_SDA = 18; +#else + int pin_ES7243_SDA = ES7243_SDA; +#endif + +#ifndef ES7243_SDAPIN + int pin_ES7243_SCL = 23; +#else + int pin_ES7243_SCL = ES7243_SCL; +#endif + +/* Interface class + AudioSource serves as base class for all microphone types + This enables accessing all microphones with one single interface + which simplifies the caller code +*/ +class AudioSource { +public: + /* All public methods are virtual, so they can be overridden + Everything but the destructor is also removed, to make sure each mic + Implementation provides its version of this function + */ + virtual ~AudioSource() {}; + + /* Initialize + This function needs to take care of anything that needs to be done + before samples can be obtained from the microphone. + */ + virtual void initialize() = 0; + + /* Deinitialize + Release all resources and deactivate any functionality that is used + by this microphone + */ + virtual void deinitialize() = 0; + + /* getSamples + Read num_samples from the microphone, and store them in the provided + buffer + */ + virtual void getSamples(double *buffer, uint16_t num_samples) = 0; + + /* Get an up-to-date sample without DC offset */ + virtual int getSampleWithoutDCOffset() = 0; + +protected: + // Private constructor, to make sure it is not callable except from derived classes + AudioSource(int sampleRate, int blockSize, uint16_t lshift, uint32_t mask) : _sampleRate(sampleRate), _blockSize(blockSize), _sampleNoDCOffset(0), _dcOffset(0.0f), _shift(lshift), _mask(mask) {}; + + int _sampleRate; /* Microphone sampling rate */ + int _blockSize; /* I2S block size */ + volatile int _sampleNoDCOffset; /* Up-to-date sample without DCOffset */ + float _dcOffset; /* Rolling average DC offset */ + uint16_t _shift; /* Shift obtained samples to the right by this amount */ + uint32_t _mask; /* Bitmask for sample data after shifting */ + i2s_config_t _config; /* I2S config */ + i2s_pin_config_t _pinConfig; /* I2S pin config */ + +}; + +/* Basic I2S microphone source + All functions are marked virtual, so derived classes can replace them +*/ +class I2SSource : public AudioSource { +public: + I2SSource(int sampleRate, int blockSize, uint16_t lshift, uint32_t mask) : + AudioSource(sampleRate, blockSize, lshift, mask) { + }; + + + virtual void initialize() { + // Make sure config object is "clean" before setting it up + memset(&_config, 0, sizeof(_config)); + + _config = { + .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), + .sample_rate = _sampleRate, + .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, + .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, + .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 8, + .dma_buf_len = _blockSize + }; + + _pinConfig = { + .bck_io_num = i2sckPin, + .ws_io_num = i2swsPin, + .data_out_num = I2S_PIN_NO_CHANGE, + .data_in_num = i2ssdPin + }; + + esp_err_t err = i2s_driver_install(I2S_NUM_0, &_config, 0, nullptr); + if (err != ESP_OK) { + Serial.printf("Failed to install i2s driver: %d\n", err); + while (true); + } + + err = i2s_set_pin(I2S_NUM_0, &_pinConfig); + if (err != ESP_OK) { + Serial.printf("Failed to set i2s pin config: %d\n", err); + while (true); + } + } + + virtual void deinitialize() { + esp_err_t err = i2s_driver_uninstall(I2S_NUM_0); + if (err != ESP_OK) { + Serial.printf("Failed to uninstall i2s driver: %d\n", err); + while (true); + } + } + + virtual void getSamples(double *buffer, uint16_t num_samples) { + esp_err_t err; + size_t bytes_read = 0; /* Counter variable to check if we actually got enough data */ + int32_t samples[num_samples]; /* Intermediary sample storage */ + + // Reset dc offset + _dcOffset = 0.0f; + + err = i2s_read(I2S_NUM_0, (void *)samples, sizeof(samples), &bytes_read, portMAX_DELAY); + if ((err != ESP_OK)){ + Serial.printf("Failed to get samples: %d\n", err); + while(true); + } + + // For correct operation, we need to read exactly sizeof(samples) bytes from i2s + if(bytes_read != sizeof(samples)) { + Serial.printf("Failed to get enough samples: wanted: %d read: %d\n", sizeof(samples), bytes_read); + return; + } + + // Store samples in sample buffer and update DC offset + for (int i = 0; i < num_samples; i++) { + // From the old code. + double sample = (double)abs((samples[i] >> _shift)); + buffer[i] = sample; + _dcOffset = ((_dcOffset * 31) + sample) / 32; + } + + // Update no-DC sample + _sampleNoDCOffset = abs(buffer[num_samples - 1] - _dcOffset); + } + + virtual int getSampleWithoutDCOffset() { + return _sampleNoDCOffset; + } +}; + +/* I2S microphone with master clock + Our version of the IDF does not support setting master clock + routing via the provided API, so we have to do it by hand +*/ +class I2SSourceWithMasterClock : public I2SSource { +public: + virtual void initialize() { + // Reserve the master clock pin + pinManager.allocatePin(mclkPin, true, PinOwner::DigitalMic); + + /* Enable the mclk routing depending on the selected mclk pin + Only I2S_NUM_0 is supported + */ + if (mclkPin == GPIO_NUM_0) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); + WRITE_PERI_REG(PIN_CTRL,0xFFF0); + } else if (mclkPin == GPIO_NUM_1) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_CLK_OUT3); + WRITE_PERI_REG(PIN_CTRL, 0xF0F0); + } else { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2); + WRITE_PERI_REG(PIN_CTRL, 0xFF00); + } + } + + virtual void deinitialize() { + // Release the master clock pin + pinManager.deallocatePin(mclkPin, PinOwner::BusDigital); + I2SSource::deinitialize(); + } +}; + +/* ES7243 Microphone + This is an I2S microphone that requires ininitialization over + I2C before I2S data can be received +*/ +class ES7243 : public I2SSourceWithMasterClock { + +private: + + // I2C initialization functions for ES7243 + void _es7243I2cBegin() { + Wire.begin(pin_ES7243_SDA, pin_ES7243_SCL, 100000U); + } + + void _es7243I2cWrite(uint8_t reg, uint8_t val) { + Wire.beginTransmission(addr_ES7243); + Wire.write((uint8_t)reg); + Wire.write((uint8_t)val); + Wire.endTransmission(); + } + + void _es7243InitAdc() + { + _es7243I2cBegin(); + _es7243I2cWrite(0x00, 0x01); + _es7243I2cWrite(0x06, 0x00); + _es7243I2cWrite(0x05, 0x1B); + _es7243I2cWrite(0x01, 0x0C); + _es7243I2cWrite(0x08, 0x43); + _es7243I2cWrite(0x05, 0x13); + } +public: + void initialize() { + // Reserve SDA and SCL pins of the I2C interface + pinManager.allocatePin(pin_ES7243_SDA, true, PinOwner::DigitalMic); + pinManager.allocatePin(pin_ES7243_SCL, true, PinOwner::DigitalMic); + _es7243InitAdc(); + I2SSourceWithMasterClock::initialize(); + } + + void deinitialize() { + // Release SDA and SCL pins of the I2C interface + pinManager.deallocatePin(pin_ES7243_SDA, PinOwner::DigitalMic); + pinManager.deallocatePin(pin_ES7243_SCL, PinOwner::DigitalMic); + I2SSourceWithMasterClock::deinitialize(); + } +}; + +/* ADC over I2S Microphone + This microphone is an ADC pin sampled via the I2S interval + This allows to use the I2S API to obtain ADC samples with high sample rates + without the need of manual timing of the samples +*/ +class I2SAdcSource : public I2SSource { +public: + I2SAdcSource(int sampleRate, int blockSize, uint16_t lshift, uint32_t mask) : + I2SSource(sampleRate, blockSize, lshift, mask){ + } + + void initialize() { + + // Make sure config object is "clean" before setting it up + memset(&_config, 0, sizeof(_config)); + + _config = { + .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), + .sample_rate = _sampleRate, + .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, + // .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, + .dma_buf_count = 8, + .dma_buf_len = _blockSize + }; + + // Determine Analog channel. Only Channels on ADC1 are supported + int8_t channel = digitalPinToAnalogChannel(audioPin); + if (channel > 9) { + Serial.printf("Incompatible GPIO used for audio in: %d\n", audioPin); + while (true); + } else { + adc_gpio_init(ADC_UNIT_1, adc_channel_t(channel)); + } + + // Install Driver + esp_err_t err = i2s_driver_install(I2S_NUM_0, &_config, 0, nullptr); + if (err != ESP_OK) { + Serial.printf("Failed to install i2s driver: %d\n", err); + while (true); + } + + // Enable I2S mode of ADC + err = i2s_set_adc_mode(ADC_UNIT_1, adc1_channel_t(channel)); + if (err != ESP_OK) { + Serial.printf("Failed to set i2s adc mode: %d\n", err); + while (true); + } + } + + void getSamples(double *buffer, uint16_t num_samples) { + + /* Enable ADC. This has to be enabled and disabled directly before and + after sampling, otherwise Wifi dies + */ + esp_err_t err = i2s_adc_enable(I2S_NUM_0); + if (err != ESP_OK) { + Serial.printf("Failed to enable i2s adc: %d\n", err); + while (true); + } + + I2SSource::getSamples(buffer, num_samples); + + err = i2s_adc_disable(I2S_NUM_0); + if (err != ESP_OK) { + Serial.printf("Failed to disable i2s adc: %d\n", err); + while (true); + } + } +}; diff --git a/wled00/set.cpp b/wled00/set.cpp index 65bc424839..1262e99577 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -572,13 +572,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage) } // Digital mic mode uint8_t newDMEnabled = request->arg(F("DMM")).toInt(); - // If the mic type was changed, reboot! ToDo: we don't need to reboot - // we just need to reload the I2S code to set up the proper mic. For - // now, a reboot is the simple solution. - if ((dmEnabled == 0) && (newDMEnabled == 1)) { - doReboot = true; + // If the mic type was changed, tell the user to reset the board! + if (dmEnabled != newDMEnabled) { + serveMessage(request, 200,F("Settings saved..."),F("Please reset the board for changes to take effect!"), 10); + dmEnabled = newDMEnabled; } - dmEnabled = newDMEnabled; // Digital Mic I2S SD pin int hw_i2ssd_pin = request->arg(F("DI")).toInt(); if (pinManager.allocatePin(hw_i2ssd_pin,false, PinOwner::DigitalMic)) { diff --git a/wled00/usermod.cpp b/wled00/usermod.cpp index d3a64a84e5..e1b42bed2f 100644 --- a/wled00/usermod.cpp +++ b/wled00/usermod.cpp @@ -14,142 +14,41 @@ * Not 100% sure this was done right. There is probably a better way to handle this... */ -#ifdef USE_ES7243 -// See https://github.com/espressif/esp-adf/blob/master/components/audio_hal/driver/es7243/es7243.c - -#include - -#ifndef ES7243_ADDR -#define ES7243_ADDR 0x13 -#endif - -#ifndef ES7243_SDAPIN -#define ES7243_SDAPIN 18 -#endif - -#ifndef ES7243_SCLPIN -#define ES7243_SCLPIN 23 -#endif - -void es7243_i2c_begin() -{ - Wire.begin(ES7243_SDAPIN, ES7243_SCLPIN, 100000U); -} -void es7243_i2c_write(uint8_t reg, uint8_t val) -{ - Wire.beginTransmission(ES7243_ADDR); - Wire.write((uint8_t)reg); - Wire.write((uint8_t)val); - Wire.endTransmission(); -} -void es7243_i2c_init_adc() -{ - es7243_i2c_begin(); - es7243_i2c_write(0x00, 0x01); - es7243_i2c_write(0x06, 0x00); - es7243_i2c_write(0x05, 0x1B); - es7243_i2c_write(0x01, 0x0C); - es7243_i2c_write(0x08, 0x43); - es7243_i2c_write(0x05, 0x13); -} - -#endif // USE_ES7243 - // This gets called once at boot. Do all initialization that doesn't depend on network here void userSetup() { - if (dmEnabled == 1) { + // Reset I2S peripheral for good measure + i2s_driver_uninstall(I2S_NUM_0); + periph_module_reset(PERIPH_I2S0_MODULE); + delay(100); // Give that poor microphone some time to setup. + if (dmEnabled == 1) { Serial.println("Attempting to configure digital Microphone."); - delay(100); // Give that poor microphone some time to setup. - -#ifdef USE_ES7243 - es7243_i2c_init_adc(); -#endif // USE_ES7243 - - // Attempt to configure INMP441 Microphone - esp_err_t err; - const i2s_config_t i2s_config = { - .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), // Receive, not transfer -#ifdef USE_ES7243 - .sample_rate = SAMPLE_RATE*4, // 11025 * 4 (44100) Hz -#else - .sample_rate = SAMPLE_RATE*2, // 10240 * 2 (20480) Hz -#endif // USE_ES7243 - .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // could only get it to work with 32bits -#ifdef USE_ES7243 - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, -#else - .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, // LEFT when pin is tied to ground. -#endif // USE_ES7243 - .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // Interrupt level 1 - .dma_buf_count = 8, // number of buffers - .dma_buf_len = BLOCK_SIZE // samples per buffer - }; - const i2s_pin_config_t pin_config = { - .bck_io_num = i2sckPin, // BCLK aka SCK - .ws_io_num = i2swsPin, // LRCL aka WS - .data_out_num = -1, // not used (only for speakers) - .data_in_num = i2ssdPin // DOUT aka SD - }; - // Configuring the I2S driver and pins. - // This function must be called before any I2S driver read/write operations. - err = i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL); - if (err != ESP_OK) { - Serial.printf("Failed installing driver: %d\n", err); - while (true); - } - err = i2s_set_pin(I2S_PORT, &pin_config); - if (err != ESP_OK) { - Serial.printf("Failed setting pin: %d\n", err); - while (true); - } - Serial.println("I2S driver installed."); - delay(250); - // Test to see if we have a digital microphone installed or not. - float mean = 0.0; - int32_t samples[BLOCK_SIZE]; - // TODO: I2S_READ_BYTES DEPRECATED, FIND ALTERNATE SOLUTION - size_t num_bytes_read = 0; - - i2s_read(I2S_PORT, &samples, BLOCK_SIZE, &num_bytes_read, portMAX_DELAY); //esp_err_t result = - - /*int num_bytes_read = i2s_read_bytes(I2S_PORT, - (char *)samples, - BLOCK_SIZE, // the doc says bytes, but its elements. - portMAX_DELAY); // no timeout - */ - - int samples_read = num_bytes_read / 8; - if (samples_read > 0) { - for (int i = 0; i < samples_read; ++i) { - mean += samples[i]; - } - mean = mean/BLOCK_SIZE/16384; - if (mean != 0.0) { - Serial.println("Digital microphone is present."); - } else { - Serial.println("Digital microphone is NOT present."); - // analogReadResolution(10); // Default is 12, which is less linear. We're also only using 10 bits as a result of our ESP8266 history. - } - } + #ifdef USE_ES7243 + audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE, 16, 0xFFFFFFFF); + #else + audioSource = new I2SSource(SAMPLE_RATE, BLOCK_SIZE, 16, 0xFFFFFFFF); + #endif } else { - Serial.println("Using Analog Microphone."); + Serial.println("Attempting to configure analog Microphone."); + audioSource = new I2SAdcSource(SAMPLE_RATE, BLOCK_SIZE, 16, 0xFFF); } - -pinMode(LED_BUILTIN, OUTPUT); - -sampling_period_us = round(1000000*(1.0/SAMPLE_RATE)); - -// Define the FFT Task and lock it to core 0 -xTaskCreatePinnedToCore( - FFTcode, // Function to implement the task - "FFT", // Name of the task - 10000, // Stack size in words - NULL, // Task input parameter - 1, // Priority of the task - &FFT_Task, // Task handle - 0); // Core where the task should run + delay(100); + audioSource->initialize(); + delay(250); + + pinMode(LED_BUILTIN, OUTPUT); + + sampling_period_us = round(1000000*(1.0/SAMPLE_RATE)); + + // Define the FFT Task and lock it to core 0 + xTaskCreatePinnedToCore( + FFTcode, // Function to implement the task + "FFT", // Name of the task + 10000, // Stack size in words + NULL, // Task input parameter + 1, // Priority of the task + &FFT_Task, // Task handle + 0); // Core where the task should run } // This gets called every time WiFi is (re-)connected. Initialize own network interfaces here From c7426046b7d90525bf893cdcfbaedaf1646dd5c5 Mon Sep 17 00:00:00 2001 From: Florian Heilmann Date: Thu, 18 Nov 2021 00:22:20 +0100 Subject: [PATCH 032/120] Don't allocate i2s_config on heap, change i2sadc channel format --- wled00/audio_source.h | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/wled00/audio_source.h b/wled00/audio_source.h index 5e69aaeac6..7524af4212 100644 --- a/wled00/audio_source.h +++ b/wled00/audio_source.h @@ -76,8 +76,6 @@ class AudioSource { float _dcOffset; /* Rolling average DC offset */ uint16_t _shift; /* Shift obtained samples to the right by this amount */ uint32_t _mask; /* Bitmask for sample data after shifting */ - i2s_config_t _config; /* I2S config */ - i2s_pin_config_t _pinConfig; /* I2S pin config */ }; @@ -93,9 +91,8 @@ class I2SSource : public AudioSource { virtual void initialize() { // Make sure config object is "clean" before setting it up - memset(&_config, 0, sizeof(_config)); - _config = { + i2s_config_t _config = { .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = _sampleRate, .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, @@ -106,7 +103,7 @@ class I2SSource : public AudioSource { .dma_buf_len = _blockSize }; - _pinConfig = { + i2s_pin_config_t _pinConfig = { .bck_io_num = i2sckPin, .ws_io_num = i2swsPin, .data_out_num = I2S_PIN_NO_CHANGE, @@ -180,7 +177,7 @@ class I2SSourceWithMasterClock : public I2SSource { virtual void initialize() { // Reserve the master clock pin pinManager.allocatePin(mclkPin, true, PinOwner::DigitalMic); - + I2SSource::initialize(); /* Enable the mclk routing depending on the selected mclk pin Only I2S_NUM_0 is supported */ @@ -194,6 +191,7 @@ class I2SSourceWithMasterClock : public I2SSource { PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_CLK_OUT2); WRITE_PERI_REG(PIN_CTRL, 0xFF00); } + } virtual void deinitialize() { @@ -264,14 +262,12 @@ class I2SAdcSource : public I2SSource { void initialize() { // Make sure config object is "clean" before setting it up - memset(&_config, 0, sizeof(_config)); - _config = { + i2s_config_t _config = { .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN), .sample_rate = _sampleRate, .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, - // .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, From 31b7cdff9b61f6ab4088c09a8989d9ac2d609875 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Fri, 19 Nov 2021 12:34:14 +0100 Subject: [PATCH 033/120] Change effect names to be more consistent --- CHANGELOG.md | 9 ++++++++- wled00/FX.h | 4 ++-- wled00/const.h | 6 +++--- wled00/wled.h | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5582843df9..ff04e1de1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,13 @@ ### Builds after release 0.12.0 -#### Build 2111160 +#### Build 2111190 + +- Changed default ESP32 LED pin from 16 to 2 +- Renamed "Running 2" to "Chase 2" +- Renamed "Tri Chase" to "Chase 3" + +#### Build 2111170 - Version bump to 0.13.0-b5 "Toki" - Improv Serial support (PR #2334) @@ -388,6 +394,7 @@ - Added support for WESP32 ethernet board (PR #1764) - Added Caching for main UI (PR #1704) - Added Tetrix mode (PR #1729) +- Removed Merry Christmas mode (use "Chase 2" - called Running 2 before 0.13.0) - Added memory check on Bus creation #### Build 2102050 diff --git a/wled00/FX.h b/wled00/FX.h index 4bdec48f9a..2c12740613 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -912,9 +912,9 @@ const char JSON_mode_names[] PROGMEM = R"=====([ "Solid","Blink","Breathe","Wipe","Wipe Random","Random Colors","Sweep","Dynamic","Colorloop","Rainbow", "Scan","Scan Dual","Fade","Theater","Theater Rainbow","Running","Saw","Twinkle","Dissolve","Dissolve Rnd", "Sparkle","Sparkle Dark","Sparkle+","Strobe","Strobe Rainbow","Strobe Mega","Blink Rainbow","Android","Chase","Chase Random", -"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Running 2","Aurora","Stream", +"Chase Rainbow","Chase Flash","Chase Flash Rnd","Rainbow Runner","Colorful","Traffic Light","Sweep Random","Chase 2","Aurora","Stream", "Scanner","Lighthouse","Fireworks","Rain","Tetrix","Fire Flicker","Gradient","Loading","Police","Police All", -"Two Dots","Two Areas","Running Dual","Halloween","Tri Chase","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet", +"Two Dots","Two Areas","Running Dual","Halloween","Chase 3","Tri Wipe","Tri Fade","Lightning","ICU","Multi Comet", "Scanner Dual","Stream 2","Oscillate","Pride 2015","Juggle","Palette","Fire 2012","Colorwaves","Bpm","Fill Noise", "Noise 1","Noise 2","Noise 3","Noise 4","Colortwinkles","Lake","Meteor","Meteor Smooth","Railway","Ripple", "Twinklefox","Twinklecat","Halloween Eyes","Solid Pattern","Solid Pattern Tri","Spots","Spots Fade","Glitter","Candle","Fireworks Starburst", diff --git a/wled00/const.h b/wled00/const.h index 37afca7f61..5b834bf364 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -313,15 +313,15 @@ #ifdef ESP8266 #define LEDPIN 2 // GPIO2 (D4) on Wemod D1 mini compatible boards #else - #define LEDPIN 16 // aligns with GPIO2 (D4) on Wemos D1 mini32 compatible boards + #define LEDPIN 2 // Changed from 16 to restore compatibility with ESP32-pico #endif #endif #ifdef WLED_ENABLE_DMX #if (LEDPIN == 2) #undef LEDPIN - #define LEDPIN 3 - #warning "Pin conflict compiling with DMX and LEDs on pin 2. The default LED pin has been changed to pin 3." + #define LEDPIN 1 + #warning "Pin conflict compiling with DMX and LEDs on pin 2. The default LED pin has been changed to pin 1." #endif #endif diff --git a/wled00/wled.h b/wled00/wled.h index d173ff27af..0c53f56c13 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2111170 +#define VERSION 2111190 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG From 8b323f1e59dfe101e7ce24ed313c6b6cd28015df Mon Sep 17 00:00:00 2001 From: ewowi Date: Sat, 20 Nov 2021 15:13:58 +0100 Subject: [PATCH 034/120] Custom Effects 0.0.6 to 0.1.0 Performance improvements New functions More modular: Search 'Custom Effect' in WLEDSR repository to see impact, all code now arti.h and arti_wled.h Upload new wled.json, presets.json and examples here: https://github.com/ewoudwijma/ARTI/tree/main/wled --- wled00/FX.cpp | 139 +- wled00/FX.h | 15 +- wled00/src/dependencies/arti/arti.h | 2441 ++++++++--------- wled00/src/dependencies/arti/arti_wled.h | 597 ++++ .../src/dependencies/arti/arti_wled_plugin.h | 302 -- 5 files changed, 1780 insertions(+), 1714 deletions(-) create mode 100644 wled00/src/dependencies/arti/arti_wled.h delete mode 100644 wled00/src/dependencies/arti/arti_wled_plugin.h diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d42e28ff4f..6ae669545c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -27,8 +27,7 @@ #include "FX.h" //WLEDSR Custom Effects -#include "src/dependencies/arti/arti.h" -ARTI * arti = nullptr; +#include "src/dependencies/arti/arti_wled.h" #define IBN 5100 #define PALETTE_SOLID_WRAP (paletteBlend == 1 || paletteBlend == 3) @@ -6454,138 +6453,4 @@ uint16_t WS2812FX::mode_2DAkemi(void) { setPixels(leds); return FRAMETIME; -} // mode_2DAkemi - -//Adding ARTI to this structure seems to be needed to make the pointers used in ARTI survive in subsequent calls of mode_customEffect -// otherwise: Interpret renderFrame: No parsetree created -// initially added parseTreeJsonDoc in this struct to save it explicitly but that was not needed -// maybe because this struct is not deleted -// typedef struct ArtiWrapper { -// ARTI * arti; -// } artiWrapper; - -uint16_t WS2812FX::mode_customEffect(void) { - - // //brightpulse - // uint8_t lum = constrain(sampleAvg * 256.0 / (256.0 - SEGMENT.speed), 0, 255); - // fill(color_blend(SEGCOLOR(1), SEGCOLOR(0), lum)); - - // return FRAMETIME; - - // float t = (sin((float)millis() / 1000.) + 1.0) / 2.; // Make a slow sine wave and convert output range from -1.0 and 1.0 to between 0 and 1.0. - // t = t * (float)SEGLEN; // Now map to the length of the strand. - - // for (int i = 0; i < SEGLEN; i++) - // { - // float diff = abs(t - (float)i); // Get difference between t and current location. Greater distance = lower brightness. - // if (diff > 2.0) diff = 2.0; // Let's not overflow. - // float bri = 256 - diff * 128; // Scale the brightness to up to 255. Closer = brighter. - // leds[i] = CHSV(0, 255, (uint8_t)bri); - // } - - // setPixels(leds); - - // return FRAMETIME; - - - // //Random - // for (int i = 0; i < ledCount; i = i + 1) { - // uint16_t color = random16(); - // setPixelColor(i%ledCount, color_wheel(color%256)); - // } - - // return 0; - - // //Kitt - - // static int pixelCounter; - // static int goingUp; - - // if (pixelCounter > (ledCount-5)) { - // goingUp = 0; - // } - // if (pixelCounter == 0) { - // goingUp = 1; - // } - // setPixelColor(pixelCounter%ledCount, color_wheel(pixelCounter%256)); - // if (goingUp) { - // setPixelColor((pixelCounter-5)%ledCount, CRGB::Black); - // pixelCounter = pixelCounter + 1; - // } - // else { - // setPixelColor((pixelCounter+5)%ledCount, CRGB::Black); - // pixelCounter = pixelCounter - 1; - // } - - // return 0; - - // ArtiWrapper* artiWrapper = reinterpret_cast(SEGENV.data); - - //tbd: move statics to SEGMENT.data - static bool succesful; - static bool notEnoughHeap; - - static char previousEffect[charLength]; - if (SEGENV.call == 0) - strcpy(previousEffect, ""); //force init - - char currentEffect[charLength]; - strcpy(currentEffect, (SEGMENT.name != nullptr)?SEGMENT.name:"default"); //note: switching preset with segment name to preset without does not clear the SEGMENT.name variable, but not gonna solve here ;-) - - if (strcmp(previousEffect, currentEffect) != 0) { - strcpy(previousEffect, currentEffect); - - // if (artiWrapper != nullptr && artiWrapper->arti != nullptr) { - if (arti != nullptr) { - arti->close(); - delete arti; arti = nullptr; - } - - // if (!SEGENV.allocateData(sizeof(ArtiWrapper))) return mode_static(); // We use this method for allocating memory for static variables. - // artiWrapper = reinterpret_cast(SEGENV.data); - arti = new ARTI(); - - char programFileName[charLength]; - strcpy(programFileName, "/"); - strcat(programFileName, currentEffect); - strcat(programFileName, ".wled"); - - succesful = arti->setup("/wled.json", programFileName); - - if (!succesful) { - ERROR_ARTI("Setup not succesful\n"); - } - } - else { - - if (succesful) {// && SEGENV.call < 250 for each frame - if (esp_get_free_heap_size() <= 30000) { - ERROR_ARTI("Not enough free heap (%u <= 30000)\n", esp_get_free_heap_size()); - notEnoughHeap = true; - succesful = false; - } - else { - // static int previousMillis; - // if (millis() - previousMillis > 5000) { //tried SEGENV.aux0 but that looks to be overwritten!!! (dangling pointer???) - // previousMillis = millis(); - // MEMORY_ARTI("Heap renderFrame %u\n", esp_get_free_heap_size()); - // } - arti->loop(); - } - } - else - { - if (notEnoughHeap && esp_get_free_heap_size() > 30000) { - ERROR_ARTI("Again enough free heap, restart effect (%u > 30000)\n", esp_get_free_heap_size()); - succesful = true; - notEnoughHeap = false; - strcpy(previousEffect, ""); // force new create - } - else { - return mode_blink(); - } - } - } - - return FRAMETIME; -} \ No newline at end of file +} // mode_2DAkemi \ No newline at end of file diff --git a/wled00/FX.h b/wled00/FX.h index 38f6e9b06e..a9c15f428c 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -312,10 +312,9 @@ #define FX_MODE_WAVESINS 184 #define FX_MODE_ROCKTAVES 185 #define FX_MODE_2DAKEMI 186 -#define FX_MODE_CUSTOMEFFECT 187 +#define FX_MODE_CUSTOMEFFECT 187 //WLEDSR Custom Effects -//WLEDSR Custom Effects -#define doubleNull -32768 +#define doubleNull -32768 //WLEDSR Custom Effects /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // End of Audio Reactive fork (WLEDSR) // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -790,7 +789,7 @@ class WS2812FX { _mode[FX_MODE_WAVESINS] = &WS2812FX::mode_wavesins; _mode[FX_MODE_ROCKTAVES] = &WS2812FX::mode_rocktaves; _mode[FX_MODE_2DAKEMI] = &WS2812FX::mode_2DAkemi; - _mode[FX_MODE_CUSTOMEFFECT] = &WS2812FX::mode_customEffect; + _mode[FX_MODE_CUSTOMEFFECT] = &WS2812FX::mode_customEffect; //WLEDSR Custom Effects #ifdef WLEDSR_LARGE // _mode[FX_MODE_2DPOOLNOISE] = &WS2812FX::mode_2DPoolnoise; //code not in fx.cpp @@ -1126,7 +1125,7 @@ class WS2812FX { mode_2DDrift(void), mode_2DColoredBursts(void), mode_2DJulia(void), - mode_customEffect(void); + mode_customEffect(void); //WLEDSR Custom Effects // mode_2DPoolnoise(void), // mode_2DTwister(void); // mode_2DCAElementary(void); @@ -1140,8 +1139,8 @@ class WS2812FX { bool _skipFirstMode; //private? not in AC (anymore) - //Custom Effects - double arti_external_function(uint8_t function, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); + //WLEDSR Custom Effects + double arti_external_function(uint8_t function, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull, double par4 = doubleNull, double par5 = doubleNull); double arti_get_external_variable(uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); void arti_set_external_variable(double value, uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); @@ -1442,7 +1441,7 @@ const char JSON_mode_names[] PROGMEM = R"=====([ "Wavesins@Speed,Brightness variation,Starting Color,Range of Colors,Color variation;;!", " ♫ Rocktaves@;,!;!", " ♫ 2D Akemi@Color speed,Dance toggle;Head palette,Arms & Legs,Eyes & Mouth;Face palette", -" ⚙️ Custom Effect@;!;!" +" ⚙️ Custom Effect@Speed,Intensity,Custom 1, Custom 2, Custom 3;!;!" ])====="; //WLEDSR: second part (not SR specific, but in latest SR, not in AC (Pallettes added in WLEDSR from Retro Clown->END)) diff --git a/wled00/src/dependencies/arti/arti.h b/wled00/src/dependencies/arti/arti.h index 8b7aca282f..5cdf4fdea5 100644 --- a/wled00/src/dependencies/arti/arti.h +++ b/wled00/src/dependencies/arti/arti.h @@ -1,8 +1,8 @@ /* @title Arduino Real Time Interpreter (ARTI) @file arti.h - @version 0.0.6 - @date 20211107 + @version 0.1.0 + @date 20211120 @author Ewoud Wijma @repo https://github.com/ewoudwijma/ARTI @remarks @@ -12,67 +12,48 @@ - Code improvememt - expression[""] variables - remove std::string (now only in logging) - - See for some weird reason this causes a crash on esp32 - - Code review (memory leaks, wled: select effect multiple times causes crash) - - Embedded: run all demos at once (not working well for some reason) + - See 'for some weird reason this causes a crash on esp32' - Definition improvements - support string (e.g. for print) - - add integer and real stacks + - add integer and string stacks - Add ++, --, +=, -= - print every x seconds (to use it in loops. e.g. to show free memory) - Add unary operators - reserved words (ext functions and variables cannot be used as variables) - check on return values + - arrays (indices) for varref - WLED improvements - - wled plugin include setup and loop... - upload files in wled ui (instead of /edit) - - add sliders - - if function not found in arti_wled_pluging then proper error handling @done - - replace strcmp in wled_functions and variables by switch / case - - remove error classes - - Add % << and >> - - add comment (// and \* *\) - - Error: parseTree should be array or object in pas1.pas - - add renderPixel to avoid the for i to ledCount loop - @done? + - create arti_pas.h as example file for new language (enables printf again) + - remove ARTI_WLED from arti.h + - why is sa = sampleAvg * 256 / (256 - speed) not working (just calculates 256 - speed) - why do functions starting with color_ crash the parser and color not??? - @progress + - Allow deeper nesting in wled files, nested calculations now possible + - rename visit + - if function not found in arti_wled then proper error handling - Shrink unused parseTree levels causes crash on arduino (now if false) - - Allow deeper nesting in wled files + - add sliders + - Embedded: run all demos at once (not working well for some reason) + @done? + @progress - SetPixelColor without colorwheel - extend errorOccurred and add warnings (continue) next to errors (stop). Include stack full/empty - WLED: *arti in SEGENV.data: not working well as change mode will free(data) - move code from interpreter to analyzer to speed up interpreting + - arti_wled include setup and loop... @todo - - why is sa = sampleAvg * 256 / (256 - speed) not working (just calculates 256 - speed) - - create arti_pas_plugin.h as example file for new language (enables printf again) - - arrays (indices) for varref - + - add button to show(edit) wled file in wled segments + - check why statement is not 'shrinked' + - replace Arduino by ESP???? */ #pragma once -#ifdef ESP32 //ESP32 is set in wled context: small trick to set WLED context - #define ARTI_PLATFORM ARTI_ARDUINO // else on Windows/Linux/Mac... -#endif - -#define ARTI_DEFINITION ARTI_WLED // currently also 'pas' runs fine on this as it has no own functions and variables -// #define ARTI_DEFINITION ARTI_PAS - -// For testing porposes, definitions should not only run on Arduino but also on Windows etc. -// Because compiling on arduino takes seriously more time than on Windows. -// The plugin.h files replace native arduino calls by windows simulated calls (e.g. setPixelColor will become printf) -#define ARTI_WLED 1 -#define ARTI_PAS 2 - -#define ARTI_ARDUINO 1 -#define ARTI_EMBEDDED 2 - #define ARTI_SERIAL 1 #define ARTI_FILE 2 -#if ARTI_PLATFORM == ARTI_ARDUINO +#if ARTI_PLATFORM == ARTI_ARDUINO //defined in arti_definition.h e.g. arti_wled.h! #include "wled.h" #include "src/dependencies/json/ArduinoJson-v6.h" #define ARTI_OUTPUT ARTI_SERIAL //print output to serial @@ -82,6 +63,9 @@ // #define ARTI_RUNLOG 1 //if set on arduino this will create massive amounts of output (as ran in a loop) #define ARTI_MEMORY 1 //to do analyses of memory usage, trace memoryleaks (works only on arduino) #define ARTI_PRINT 1 //will show the printf calls + const char spaces[51] PROGMEM = " "; + #define FREE_SIZE esp_get_free_heap_size() + #define CURRENT_MILLIS millis() #else //embedded #include "dependencies/ArduinoJson-recent.h" #define ARTI_OUTPUT ARTI_FILE //print output to file (e.g. default.wled.log) @@ -89,7 +73,14 @@ #define ARTI_DEBUG 1 #define ARTI_ANDBG 1 #define ARTI_RUNLOG 1 + #define ARTI_MEMORY 1 #define ARTI_PRINT 1 + #include + #include + #include + const char spaces[51] = " "; + #define FREE_SIZE 0 + #define CURRENT_MILLIS 0 #endif #if ARTI_OUTPUT == ARTI_SERIAL @@ -103,7 +94,7 @@ File logFile; #define OUTPUT_ARTI(...) logFile.printf(__VA_ARGS__) #else - FILE * logFile; + FILE * logFile; // FILE needed to use in fprintf (std stream does not work) #define OUTPUT_ARTI(...) fprintf(logFile, __VA_ARGS__) #endif #endif @@ -150,18 +141,7 @@ #define fileNameLength 50 #define arrayLength 30 -#if ARTI_PLATFORM != ARTI_ARDUINO || ARTI_DEFINITION != ARTI_WLED - #define doubleNull -32768 -#endif - -#if ARTI_PLATFORM == ARTI_ARDUINO - const char spaces[51] PROGMEM = " "; -#else - #include - #include - #include - const char spaces[51] = " "; -#endif +#define doubleNull -32768 const char * stringOrEmpty(const char *charS) { if (charS == nullptr) @@ -170,16 +150,134 @@ const char * stringOrEmpty(const char *charS) { return charS; } -#if ARTI_DEFINITION == ARTI_WLED - #if ARTI_PLATFORM == ARTI_ARDUINO - #include "arti_wled_plugin.h" - #else - #include "wled/arti_wled_plugin.h" - #endif -#endif +enum Operators +{ + F_integerConstant, + F_realConstant, + F_plus, + F_minus, + F_multiplication, + F_division, + F_modulo, + F_bitShiftLeft, + F_bitShiftRight, + F_equal, + F_notEqual, + F_lessThen, + F_lessThenOrEqual, + F_greaterThen, + F_greaterThenOrEqual +}; -bool errorOccurred = false; +const char * operatorToString(uint8_t key) +{ + switch (key) { + case F_integerConstant: + return "integer"; + break; + case F_realConstant: + return "real"; + break; + case F_plus: + return "+"; + break; + case F_minus: + return "-"; + break; + case F_multiplication: + return "*"; + break; + case F_division: + return "/"; + break; + case F_modulo: + return "%"; + break; + case F_bitShiftLeft: + return "<<"; + break; + case F_bitShiftRight: + return ">>"; + break; + case F_equal: + return "=="; + break; + case F_notEqual: + return "!="; + break; + case F_lessThen: + return "<"; + break; + case F_lessThenOrEqual: + return "<=>"; + break; + case F_greaterThen: + return ">"; + break; + case F_greaterThenOrEqual: + return ">="; + break; + } + return "unknown key"; +} + +//numbers should match with wled.json SEMANTICS id's!! +enum Constructs +{ + F_Program = 0, + F_Function = 1, + F_Call = 2, + F_Var = 3, + F_Assign = 4, + F_Formal = 5, + F_VarRef = 6, + F_For = 7, + F_If = 8, + F_Expr = 9, + F_Term = 10 +}; + +const char * constructToString(uint8_t key) +{ + switch (key) { + case F_Program: + return "Program"; + break; + case F_Function: + return "F_Function"; + break; + case F_Call: + return "F_Call"; + break; + case F_Var: + return "F_Var"; + break; + case F_Assign: + return "F_Assign"; + break; + case F_Formal: + return "F_Formal"; + break; + case F_VarRef: + return "F_VarRef"; + break; + case F_For: + return "F_For"; + break; + case F_If: + return "F_If"; + break; + case F_Expr: + return "F_Expr"; + break; + case F_Term: + return "F_Term"; + break; + } + return "unknown key"; +} +bool errorOccurred = false; struct Token { uint16_t lineno; @@ -301,7 +399,6 @@ class Lexer { strcpy(resultUpper, result); strupr(resultUpper); - // DEBUG_ARTI("upper %s [%s] [%s]\n", definitionJson["TOKENS"][resultUpper].as(), result, resultUpper); if (definitionJson["TOKENS"][resultUpper].isNull()) { strcpy(current_token.type, "ID"); strcpy(current_token.value, result); @@ -312,7 +409,8 @@ class Lexer { } } - void get_next_token() { + void get_next_token() + { current_token.lineno = this->lineno; current_token.column = this->column; strcpy(current_token.type, ""); @@ -320,8 +418,8 @@ class Lexer { if (errorOccurred) return; - while (this->current_char != -1 && this->pos <= strlen(this->text) - 1 && !errorOccurred) { - // DEBUG_ARTI("get_next_token %c\n", this->current_char); + while (this->current_char != -1 && this->pos <= strlen(this->text) - 1 && !errorOccurred) + { if (isspace(this->current_char)) { this->skip_whitespace(); continue; @@ -367,9 +465,8 @@ class Lexer { } } - // DEBUG_ARTI("%s\n", "get_next_token (", token_type, ") (", token_value, ")"); - if (strcmp(token_type, "") != 0 && strcmp(token_value, "") != 0) { - // DEBUG_ARTI("%s\n", "get_next_token tvinn", token_type, token_value); + if (strcmp(token_type, "") != 0 && strcmp(token_value, "") != 0) + { strcpy(current_token.type, token_type); strcpy(current_token.value, token_value); for (int i=0; i %s %s\n", token_type, lexer->current_token.type, lexer->current_token.value); } else { - ERROR_ARTI("Parser Error: Unexpected token %s %s\n", current_token.type, current_token.value); + ERROR_ARTI("Lexer Error: Unexpected token %s %s\n", current_token.type, current_token.value); errorOccurred = true; } } void push_position() { - // DEBUG_ARTI("%s\n", "push_position ", positions_index, this->lexer.pos); if (positions_index < nrOfPositions) { positions[positions_index].pos = this->pos; positions[positions_index].current_char = this->current_char; @@ -413,7 +509,6 @@ class Lexer { void pop_position() { if (positions_index > 0) { positions_index--; - // DEBUG_ARTI("%s\n", "pop_position ", positions_index, this->lexer->pos, " to ", positions[positions_index].pos); this->pos = positions[positions_index].pos; this->current_char = positions[positions_index].current_char; this->lineno = positions[positions_index].lineno; @@ -437,24 +532,25 @@ class Symbol { private: public: - char symbol_type[charLength]; + uint8_t symbol_type; char name[charLength]; - char type[charLength]; + uint8_t type; uint8_t scope_level; + uint8_t scope_index; ScopedSymbolTable* scope = nullptr; ScopedSymbolTable* function_scope = nullptr; //used to find the formal parameters in the scope of a function symbol JsonVariant block; - Symbol(const char * symbol_type, const char * name, const char * type = nullptr) { - strcpy(this->symbol_type, symbol_type); + Symbol(uint8_t symbol_type, const char * name, uint8_t type = 9) { + this->symbol_type = symbol_type; strcpy(this->name, name); - strcpy(this->type, (type == nullptr)?"":type); + this->type = type; this->scope_level = 0; } ~Symbol() { - MEMORY_ARTI("Heap Destruct Symbol %s (%u)\n", name, esp_get_free_heap_size()); + MEMORY_ARTI("Heap Destruct Symbol %s (%u)\n", name, FREE_SIZE); } }; //Symbol @@ -475,7 +571,6 @@ class ScopedSymbolTable { uint8_t child_scopesIndex = 0; ScopedSymbolTable(const char * scope_name, int scope_level, ScopedSymbolTable *enclosing_scope = nullptr) { - // ANDBG_ARTI("%s\n", "ScopedSymbolTable ", scope_name, scope_level); strcpy(this->scope_name, scope_name); this->scope_level = scope_level; this->enclosing_scope = enclosing_scope; @@ -488,7 +583,7 @@ class ScopedSymbolTable { for (uint8_t i=0; iinsert(BuiltinTypeSymbol('REAL')); } - void insert(Symbol* symbol) { + void insert(Symbol* symbol) + { #ifdef _SHOULD_LOG_SCOPE ANDBG_ARTI("Log scope Insert %s\n", symbol->name.c_str()); #endif symbol->scope_level = this->scope_level; symbol->scope = this; + symbol->scope_index = symbolsIndex; if (symbolsIndex < nrOfSymbolsPerScope) this->symbols[symbolsIndex++] = symbol; else ERROR_ARTI("ScopedSymbolTable %s symbols full (%d)", scope_name, nrOfSymbolsPerScope); } - Symbol* lookup(const char * name, bool current_scope_only=false) { - // this->log("Lookup: " + name + " " + this->scope_name); - // 'symbol' is either an instance of the Symbol class or None; + Symbol* lookup(const char * name, bool current_scope_only=false) + { for (uint8_t i=0; isymbol_type, symbols[i]->name, symbols[i]->type, symbols[i]->scope_level); - if (strcmp(symbols[i]->name, name) == 0) //replace with strcmp!!! + if (strcmp(symbols[i]->name, name) == 0) return symbols[i]; } @@ -528,110 +623,54 @@ class ScopedSymbolTable { }; //ScopedSymbolTable -struct charKeyValue -{ - char key[charLength]; - char value[charLength]; -}; - -struct doubleKeyValue -{ - char key[charLength]; - double value; -}; - #define nrOfVariables 20 -class ActivationRecord { +class ActivationRecord +{ private: public: char name[charLength]; char type[charLength]; int nesting_level; - struct charKeyValue *charMembers; - uint8_t charMembersCounter = 0; - struct doubleKeyValue *doubleMembers; - uint8_t doubleMembersCounter = 0; + // char charMembers[charLength][nrOfVariables]; + double doubleMembers[nrOfVariables]; char lastSet[charLength]; + double lastSetIndex; - ActivationRecord(const char * name, const char * type, int nesting_level) { + ActivationRecord(const char * name, const char * type, int nesting_level) + { strcpy(this->name, name); strcpy(this->type, type); this->nesting_level = nesting_level; - - charMembers = (struct charKeyValue *)malloc(sizeof(struct charKeyValue) * nrOfVariables); - doubleMembers = (struct doubleKeyValue *)malloc(sizeof(struct doubleKeyValue) * nrOfVariables); } - ~ActivationRecord() { + ~ActivationRecord() + { RUNLOG_ARTI("Destruct activation record %s\n", name); - free(charMembers); - free(doubleMembers); } - void set(const char * key, const char * value) { - - for (uint8_t i = 0; i < charMembersCounter; i++) { - if (strcmp(charMembers[i].key, key) == 0) { - strcpy(charMembers[i].value, value); - strcpy(lastSet, key); - // RUNLOG_ARTI("Set %s %s\n", key, value); - return; - } - } + // void set(uint8_t index, const char * value) + // { + // lastSetIndex = index; + // strcpy(charMembers[index], value); + // } - if (charMembersCounter < nrOfVariables) { - strcpy(charMembers[charMembersCounter].key, key); - strcpy(charMembers[charMembersCounter].value, value); - strcpy(lastSet, key); - charMembersCounter++; - // RUNLOG_ARTI("Set %s %s\n", key, value); - } - else - ERROR_ARTI("ActivationRecord no room for new vars\n"); + void set(uint8_t index, double value) + { + lastSetIndex = index; + doubleMembers[index] = value; } - void set(const char * key, double value) { - - for (uint8_t i = 0; i < doubleMembersCounter; i++) { - if (strcmp(doubleMembers[i].key, key) == 0) { - doubleMembers[i].value = value; - strcpy(lastSet, key); - // RUNLOG_ARTI("Set %s %s\n", key, value); - return; - } - } - - if (doubleMembersCounter < nrOfVariables) { - strcpy(doubleMembers[doubleMembersCounter].key, key); - doubleMembers[doubleMembersCounter].value = value; - strcpy(lastSet, key); - doubleMembersCounter++; - // RUNLOG_ARTI("Set %s %s\n", key, value); - } - else - ERROR_ARTI("ActivationRecord no room for new vars\n"); - } + // const char * getChar(uint8_t index) + // { + // return charMembers[index]; + // } - const char * getChar(const char * key) { - for (uint8_t i = 0; i < charMembersCounter; i++) { - // RUNLOG_ARTI("Get %s %s %s", key, members[i].key, members[i].value); - if (strcmp(charMembers[i].key, key) == 0) { - return charMembers[i].value; - } - } - return "empty"; + double getDouble(uint8_t index) + { + return doubleMembers[index]; } - double getDouble(const char * key) { - for (uint8_t i = 0; i < doubleMembersCounter; i++) { - // RUNLOG_ARTI("Get %s %s %s", key, members[i].key, members[i].value); - if (strcmp(doubleMembers[i].key, key) == 0) { - return doubleMembers[i].value; - } - } - return doubleNull; - } }; //ActivationRecord #define nrOfRecords 20 @@ -677,7 +716,7 @@ class CallStack { class ValueStack { private: public: - char charStack[arrayLength][charLength]; + // char charStack[arrayLength][charLength]; //currently only doubleStack used. double doubleStack[arrayLength]; uint8_t stack_index = 0; @@ -688,17 +727,17 @@ class ValueStack { RUNLOG_ARTI("Destruct valueStack\n"); } - void push(const char * value) { - if (stack_index >= arrayLength) - ERROR_ARTI("Push charStack full %u of %u\n", stack_index, arrayLength); - else if (value == nullptr) { - strcpy(charStack[stack_index++], "empty"); - ERROR_ARTI("Push null pointer on double stack\n"); - } - else - // RUNLOG_ARTI("calc push %s %s\n", key, value); - strcpy(charStack[stack_index++], value); - } + // void push(const char * value) { + // if (stack_index >= arrayLength) + // ERROR_ARTI("Push charStack full %u of %u\n", stack_index, arrayLength); + // else if (value == nullptr) { + // strcpy(charStack[stack_index++], "empty"); + // ERROR_ARTI("Push null pointer on double stack\n"); + // } + // else + // // RUNLOG_ARTI("calc push %s %s\n", key, value); + // strcpy(charStack[stack_index++], value); + // } void push(double value) { if (stack_index >= arrayLength) @@ -710,27 +749,27 @@ class ValueStack { doubleStack[stack_index++] = value; } - const char * peekChar() { - // RUNLOG_ARTI("Calc Peek %s\n", charStack[stack_index-1]); - return charStack[stack_index-1]; - } + // const char * peekChar() { + // // RUNLOG_ARTI("Calc Peek %s\n", charStack[stack_index-1]); + // return charStack[stack_index-1]; + // } double peekDouble() { // RUNLOG_ARTI("Calc Peek %s\n", doubleStack[stack_index-1]); return doubleStack[stack_index-1]; } - const char * popChar() { - if (stack_index>0) { - stack_index--; - return charStack[stack_index]; - } - else { - ERROR_ARTI("Pop value stack empty\n"); - // RUNLOG_ARTI("Calc Pop %s\n", charStack[stack_index]); - return "novalue"; - } - } + // const char * popChar() { + // if (stack_index>0) { + // stack_index--; + // return charStack[stack_index]; + // } + // else { + // ERROR_ARTI("Pop value stack empty\n"); + // // RUNLOG_ARTI("Calc Pop %s\n", charStack[stack_index]); + // return "novalue"; + // } + // } double popDouble() { if (stack_index>0) { @@ -746,7 +785,7 @@ class ValueStack { }; //ValueStack -#define programTextSize 1000 +#define programTextSize 5000 class ARTI { private: @@ -760,30 +799,26 @@ class ARTI { ScopedSymbolTable *global_scope = nullptr; CallStack *callStack = nullptr; ValueStack *valueStack = nullptr; + + uint8_t stages = 5; //for debugging, should be 5 if no debugging public: - ARTI() { - MEMORY_ARTI("Heap new Arti < %u\n", esp_get_free_heap_size()); + ARTI() + { + // MEMORY_ARTI("Heap new Arti < %u\n", FREE_SIZE); //logfile not open here } - ~ARTI() { + ~ARTI() + { MEMORY_ARTI("Destruct ARTI\n"); - - if (callStack != nullptr) {delete callStack; callStack = nullptr;} - if (valueStack != nullptr) {delete valueStack; valueStack = nullptr;} - if (global_scope != nullptr) {delete global_scope; global_scope = nullptr;} - - if (definitionJsonDoc != nullptr) { - DEBUG_ARTI("def mem %u of %u %u %u %u %u\n", definitionJsonDoc->memoryUsage(), definitionJsonDoc->capacity(), definitionJsonDoc->memoryPool().capacity(), definitionJsonDoc->size(), definitionJsonDoc->overflowed(), definitionJsonDoc->nesting()); - delete definitionJsonDoc; definitionJsonDoc = nullptr; - } - - if (parseTreeJsonDoc != nullptr) { - DEBUG_ARTI("par mem %u of %u %u %u %u %u\n", parseTreeJsonDoc->memoryUsage(), parseTreeJsonDoc->capacity(), parseTreeJsonDoc->memoryPool().capacity(), parseTreeJsonDoc->size(), parseTreeJsonDoc->overflowed(), parseTreeJsonDoc->nesting()); - delete parseTreeJsonDoc; parseTreeJsonDoc = nullptr; - } - -} + close(); + } + //defined in arti_definition.h e.g. arti_wled.h! + double arti_external_function(uint8_t function, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull, double par4 = doubleNull, double par5 = doubleNull); + double arti_get_external_variable(uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); + void arti_set_external_variable(double value, uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); + bool loop(); + uint8_t parse(JsonVariant parseTree, const char * symbol_name, char operatorx, JsonVariant expression, uint8_t depth = 0) { if (depth > 50) { ERROR_ARTI("Error too deep %u\n", depth); @@ -802,10 +837,8 @@ class ARTI { // } if (expression.is()) { //should always be the case - for (JsonVariant arrayElement: expression.as()) { - - // DEBUG_ARTI("%s Array element %s\n", spaces+50-depth, arrayElement.as().c_str()); - + for (JsonVariant arrayElement: expression.as()) + { JsonVariant nextExpression = arrayElement; const char * nextSymbol_name = symbol_name; JsonVariant nextParseTree = parseTree; @@ -813,69 +846,63 @@ class ARTI { JsonVariant symbolExpression = lexer->definitionJson[arrayElement.as()]; - if (!symbolExpression.isNull()) { //is arrayElement a Symbol e.g. "compound" : ["CURLYOPEN", "block*", "CURLYCLOSE"], - - // DEBUG_ARTI("%s New Symbol %s %s %s\n", spaces+50-depth, parseTree.as().c_str(), symbol_name, nextExpression.as().c_str()); + if (!symbolExpression.isNull()) //is arrayElement a Symbol e.g. "compound" : ["CURLYOPEN", "block*", "CURLYCLOSE"], + { nextSymbol_name = arrayElement.as(); nextExpression = symbolExpression; - DEBUG_ARTI("%s %s %u\n", spaces+50-depth, nextSymbol_name, depth); //, parseTree.as().c_str() - - if (parseTree.is()) { + // DEBUG_ARTI("%s %s %u\n", spaces+50-depth, nextSymbol_name, depth); //, parseTree.as().c_str() + if (parseTree.is()) + { parseTree[parseTree.size()][nextSymbol_name]["connect"] = "array"; - // DEBUG_ARTI("%s New Symbol to array %s %s %u %s\n", spaces+50-depth, symbol_name, nextSymbol_name, depth, parseTree.as().c_str()); nextParseTree = parseTree[parseTree.size()-1]; //nextparsetree is last element in the array (which is always an object) } - else - { //no list, create object + else //no list, create object + { if (parseTree[symbol_name].isNull()) //no object yet parseTree[symbol_name]["connect"] = "object"; //make the connection, new object item - // DEBUG_ARTI("%s New Symbol %s %s %u %s\n", spaces+50-depth, symbol_name, nextSymbol_name, depth, parseTree.as().c_str()); nextParseTree = parseTree[symbol_name]; } } - // DEBUG_ARTI("%s Next expression %s\n", spaces+50-depth, nextExpression.as().c_str()); - if (operatorx == '|') lexer->push_position(); - if (nextExpression.is()) { // e.g. {"?":["LPAREN","formals*","RPAREN"]} - // DEBUG_ARTI("%s Visit Object %s %c %s\n", spaces+50-depth, stringOrEmpty(nextSymbol_name), operatorx, nextExpression.as().c_str()); - + if (nextExpression.is()) // e.g. {"?":["LPAREN","formals*","RPAREN"]} + { JsonObject::iterator objectIterator = nextExpression.as().begin(); char objectOperator = objectIterator->key().c_str()[0]; JsonVariant objectElement = objectIterator->value(); - if (objectElement.is()) { - - if (objectOperator == '*' || objectOperator == '+') { + if (objectElement.is()) + { + if (objectOperator == '*' || objectOperator == '+') + { nextParseTree[nextSymbol_name]["*"][0] = "multiple"; nextParseTree = nextParseTree[nextSymbol_name]["*"]; - // DEBUG_ARTI("%s multiple / array found %s %s %s\n", spaces+50-depth, nextSymbol_name, nextExpression.as().c_str(), nextParseTree.as().c_str()); } //and: see 'is array' - if (objectOperator == '|') { - // DEBUG_ARTI("%s\n", "or "); + if (objectOperator == '|') + { resultChild = parse(nextParseTree, nextSymbol_name, objectOperator, objectElement, depth + 1); if (resultChild != ResultFail) resultChild = ResultContinue; } - else { + else + { uint8_t resultChild2 = ResultContinue; uint8_t counter = 0; - while (resultChild2 == ResultContinue) { - // DEBUG_ARTI("Before %u (%u.%u) %u of %u %s\n", resultChild2, this->lexer->lineno, this->lexer->column, this->lexer->pos, strlen(this->lexer->text), objectExpression.as().c_str()); + while (resultChild2 == ResultContinue) + { resultChild2 = parse(nextParseTree, nextSymbol_name, objectOperator, objectElement, depth + 1); //no assign to result as optional - // DEBUG_ARTI("After %u (%u.%u) %u of %u %s\n", resultChild2, this->lexer->lineno, this->lexer->column, this->lexer->pos, strlen(this->lexer->text), objectExpression.as().c_str()); - if (objectOperator == '?') { //zero or one iteration, also continue of visit not continue + if (objectOperator == '?') { //zero or one iteration, also continue if parse not continue resultChild2 = ResultContinue; break; } - else if (objectOperator == '+') { //one or more iterations, stop if first visit not continue + else if (objectOperator == '+') { //one or more iterations, stop if first parse not continue if (counter == 0) { if (resultChild2 != ResultContinue) break; @@ -887,14 +914,14 @@ class ARTI { } } } - else if (objectOperator == '*') { //zero or more iterations, stop if visit not continue + else if (objectOperator == '*') { //zero or more iterations, stop if parse not continue if (resultChild2 != ResultContinue) { resultChild2 = ResultContinue; //always continue break; } } else { - ERROR_ARTI("%s Programming error: undefined %c %s\n", spaces+50-depth, objectOperator, objectElement.as()); + ERROR_ARTI("%s Programming error: undefined %c %s\n", spaces+50-depth, objectOperator, objectElement.as().c_str()); resultChild2 = ResultFail; } counter++; @@ -905,21 +932,21 @@ class ARTI { else ERROR_ARTI("%s Definition error: should be an array %s %c %s\n", spaces+50-depth, stringOrEmpty(nextSymbol_name), operatorx, objectElement.as().c_str()); } - else if (nextExpression.is()) { // e.g. ["LPAREN", "expr*", "RPAREN"] - // DEBUG_ARTI("%s Visit Array %s %c %s\n", spaces+50-depth, stringOrEmpty(nextSymbol_name), operatorx, nextExpression.as().c_str()); + else if (nextExpression.is()) // e.g. ["LPAREN", "expr*", "RPAREN"] + { resultChild = parse(nextParseTree, nextSymbol_name, '&', nextExpression, depth + 1); // every array element starts with '&' (operatorx is for result of all elements of array) } - else if (!lexer->definitionJson["TOKENS"][nextExpression.as()].isNull()) { // token e.g. "ID" + else if (!lexer->definitionJson["TOKENS"][nextExpression.as()].isNull()) // token e.g. "ID" + { const char * token_type = nextExpression; - // DEBUG_ARTI("%s Visit Token %s %c %s\n", spaces+50-depth, stringOrEmpty(nextSymbol_name), operatorx, nextExpression.as()); - if (strcmp(lexer->current_token.type, token_type) == 0) { - // DEBUG_ARTI("%s visit token %s %s\n", spaces+50-depth, lexer->current_token.type, token_type);//, expression.as().c_str()); + if (strcmp(lexer->current_token.type, token_type) == 0) + { if (strcmp(lexer->current_token.type, "") != 0) { DEBUG_ARTI("%s %s %s", spaces+50-depth, lexer->current_token.type, lexer->current_token.value); } - if (nextParseTree.is()) { - // DEBUG_ARTI("( %s Add token in array %s %s %s %c )", spaces+50-depth, nextSymbol_name, lexer->current_token.type, lexer->current_token.value, operatorx); + if (nextParseTree.is()) + { JsonArray arr = nextParseTree.as(); arr[arr.size()][lexer->current_token.type] = lexer->current_token.value; //add in last element of array } @@ -939,137 +966,33 @@ class ARTI { DEBUG_ARTI(" %d\n", depth); resultChild = ResultContinue; } - else { //deadend - // DEBUG_ARTI("%s visit deadend %s %s %s\n", spaces+50-depth, lexer->current_token.type, token_type, nextParseTree.as().c_str());//, expression.as().c_str()); + else //deadend + { resultChild = ResultFail; } } // if token - else { //arrayElement is not a symbol, not a token, not an array and not an object + else //arrayElement is not a symbol, not a token, not an array and not an object + { if (lexer->definitionJson[nextExpression.as()].isNull()) - ERROR_ARTI("%s Programming error: %s not a symbol, token, array or object in %s\n", spaces+50-depth, nextExpression.as(), stringOrEmpty(nextSymbol_name)); + ERROR_ARTI("%s Programming error: %s not a symbol, token, array or object in %s\n", spaces+50-depth, nextExpression.as().c_str(), stringOrEmpty(nextSymbol_name)); else - ERROR_ARTI("%s Definition error: \"%s\": \"%s\" symbol should be embedded in array\n", spaces+50-depth, stringOrEmpty(nextSymbol_name), nextExpression.as()); + ERROR_ARTI("%s Definition error: \"%s\": \"%s\" symbol should be embedded in array\n", spaces+50-depth, stringOrEmpty(nextSymbol_name), nextExpression.as().c_str()); } //nextExpression is not a token - if (!symbolExpression.isNull()) { //if symbol + if (!symbolExpression.isNull()) //if symbol + { nextParseTree.remove("connect"); //remove connector - if (resultChild == ResultFail) { //remove result of visit + if (resultChild == ResultFail) { //remove result of parse nextParseTree.remove(nextSymbol_name); //remove the failed stuff - DEBUG_ARTI("%s fail %s\n", spaces+50-depth, nextSymbol_name); + // DEBUG_ARTI("%s fail %s\n", spaces+50-depth, nextSymbol_name); } - else { //success - //make the parsetree as small as possible to let the interpreter run as fast as possible: - //for each symbol - //- check if * multiple is one of the elements, if only "multiple" then remove all, otherwise only multiple element - //- check if a symbol is not used in analyzer / interpreter and has only one element: go to the parent and replace itself with its child (shrink) - - if (nextParseTree.is()) { //Symbols trees are always objects e.g. {"term": {"factor": {"varref": {..}},"*": ["multiple"]}} - for (JsonPair symbolObjectPair : nextParseTree.as()) { - const char * symbolObjectKey = symbolObjectPair.key().c_str(); - JsonVariant symbolObjectValue = symbolObjectPair.value(); - - if (symbolObjectValue.is()) { // e.g. {"term":{"factor":{"varref":{"ID":"ledCount"}},"*":["multiple"]}} - if (symbolObjectValue.size() == 0) { - DEBUG_ARTI("%s remove empty values for key %s (%u)\n", spaces+50-depth, symbolObjectKey, depth); - nextParseTree.remove(symbolObjectKey); - } - else - { - for (JsonPair symbolObjectObject : symbolObjectValue.as()) { - - if (symbolObjectObject.value().is()) { - JsonArray symbolObjectObjectArray = symbolObjectObject.value().as(); - // JsonArray::iterator toBeRemoved[10]; - // uint8_t toBeRemovedCounter = 0; - for (JsonArray::iterator it = symbolObjectObjectArray.begin(); it != symbolObjectObjectArray.end(); ++it) { - if ((*it) == "multiple") { - DEBUG_ARTI("%s remove multiple key (%u)\n", spaces+50-depth, depth); - symbolObjectObjectArray.remove(it); - // toBeRemoved[toBeRemovedCounter++] = it; - } - // else if (it->size() == 0) { //causes subpixel to crash????!!! - // DEBUG_ARTI("%s remove {} elements (%u)\n", spaces+50-depth, depth); - // symbolObjectObjectArray.remove(it); //remove {} elements (added by * arrays, don't know where added) - // // toBeRemoved[toBeRemovedCounter++] = it; - // } - } - // for (int i=0; i().c_str(), depth); - nextParseTree.remove(symbolObjectKey); - } - } - - //symbolObjectKey should be a symbol on itself and the value must consist of one element - if (false && !lexer->definitionJson[symbolObjectKey].isNull() && symbolObjectValue.size()==1) { //disabled as causing crash on Arduino - - bool found = false; - for (JsonPair semanticsPair : lexer->definitionJson["SEMANTICS"].as()) { - const char * semanticsKey = semanticsPair.key().c_str(); - JsonVariant semanticsValue = semanticsPair.value(); - - // DEBUG_ARTI("%s semantics %s", spaces+50-depth, semanticsKey); - if (strcmp(symbolObjectKey, semanticsKey) == 0){ - found = true; - break; - } - for (JsonPair semanticsVariables : semanticsValue.as()) { - JsonVariant variableValue = semanticsVariables.value(); - // DEBUG_ARTI(" %s", variableValue.as().c_str()); - if (variableValue.is() && strcmp(symbolObjectKey, variableValue.as()) == 0) { - found = true; - break; - } - } - // DEBUG_ARTI("\n"); - } - - if (!found) { // not used in analyzer / interpreter - DEBUG_ARTI("%s symbol to shrink %s\n", spaces+50-depth, symbolObjectKey); - if (parseTree.is()) { - JsonObject parseTreeObject = parseTree.as(); - for (JsonObject::iterator it=parseTreeObject.begin(); it != parseTreeObject.end(); ++it) { - const char * parseTreeObjectKey = it->key().c_str(); - JsonVariant parseTreeObjectValue = it->value(); - if (parseTreeObjectValue == nextParseTree) //find the right element to replace - { - parseTree[parseTreeObjectKey] = symbolObjectValue; - DEBUG_ARTI("%s Shrink object %s %s\n", spaces+50-depth, symbolObjectKey, symbolObjectValue.as().c_str()); - // DEBUG_ARTI("%s Shrink object %s %s\n", spaces+50-depth, symbolObjectKey, nextParseTree.as().c_str()); - // DEBUG_ARTI("%s Shrink object %s %s\n", spaces+50-depth, symbolObjectKey, parseTree.as().c_str()); - } - } - } - else if (parseTree.is()) { - JsonArray parseTreeArray = parseTree.as(); - for (int i=0; i().c_str()); - // DEBUG_ARTI("%s Shrink array %s %s\n", spaces+50-depth, symbolObjectKey, nextParseTree.as().c_str()); - // DEBUG_ARTI("%s Shrink array %s %s\n", spaces+50-depth, symbolObjectKey, parseTree.as().c_str()); - } - } - } - // DEBUG_ARTI("%s symbol to shrink done %s %s\n", spaces+50-depth, symbolObjectKey, symbolObjectValue.as().c_str()); - } - } // symbolObjectKey should by a symbol on itself and value is one element - } //for symbol objects - } //if symbol has object + else //success + { + //parseTree optimization moved to optimize function - DEBUG_ARTI("%s success %s\n", spaces+50-depth, nextSymbol_name); + DEBUG_ARTI("%s found %s\n", spaces+50-depth, nextSymbol_name); } } // if symbol @@ -1107,200 +1030,251 @@ class ARTI { } //parse - bool analyze(JsonVariant parseTree, const char * treeElement = nullptr, ScopedSymbolTable* current_scope = nullptr, uint8_t depth = 0) { - - if (parseTree.is()) { - // ANDBG_ARTI("%s Visit object %s %u %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.size(), parseTree.as().c_str(), depth); + bool analyze(JsonVariant parseTree, const char * treeElement = nullptr, ScopedSymbolTable* current_scope = nullptr, uint8_t depth = 0) { + if (depth > 50) { + ERROR_ARTI("Error too deep %u\n", depth); + errorOccurred = true; + } + if (errorOccurred) return ResultFail; - for (JsonPair parseTreePair : parseTree.as()) { + if (parseTree.is()) + { + for (JsonPair parseTreePair : parseTree.as()) + { const char * key = parseTreePair.key().c_str(); JsonVariant value = parseTreePair.value(); - if (treeElement == nullptr || strcmp(treeElement, key) == 0 ) { //in case there are more elements in the object and you want to visit only one - - // ANDBG_ARTI("%s Visit object element %s %s\n", spaces+50-depth, key, value.as().c_str()); - bool visitCalledAlready = false; + if (treeElement == nullptr || strcmp(treeElement, key) == 0 ) //in case there are more elements in the object and you want to analyze only one + { + bool analyzedAlready = false; - if (!definitionJson[key].isNull()) { //if key is symbol_name + if (!definitionJson[key].isNull()) //if key is symbol_name + { JsonVariant expression = definitionJson["SEMANTICS"][key]; if (!expression.isNull()) { - // const char * expression_id = expression["id"]; - // MEMORY_ARTI("%s Heap %s < %u\n", spaces+50-depth, expression_id, esp_get_free_heap_size()); - if (strcmp(expression["id"], "Program") == 0) { - const char * expression_name = expression["name"]; - const char * expression_block = expression["block"]; - const char * program_name = value[expression_name]; - global_scope = new ScopedSymbolTable(program_name, 1, nullptr); //current_scope - - ANDBG_ARTI("%s Program %s %u %u\n", spaces+50-depth, global_scope->scope_name, global_scope->scope_level, global_scope->symbolsIndex); - - if (value[expression_block].isNull()) - ERROR_ARTI("%s Program %s: no block %s in parseTree\n", spaces+50-depth, program_name, expression_block); - else { - analyze(value[expression_block], nullptr, global_scope, depth + 1); - } + switch (expression["id"].as()) + { + case F_Program: { + const char * expression_name = expression["name"]; + const char * expression_block = expression["block"]; + const char * program_name = value[expression_name]; + global_scope = new ScopedSymbolTable(program_name, 1, nullptr); //current_scope - #ifdef ARTI_DEBUG - for (uint8_t i=0; isymbolsIndex; i++) { - Symbol* symbol = global_scope->symbols[i]; - ANDBG_ARTI("%s %u %s %s.%s %s %u\n", spaces+50-depth, i, symbol->symbol_type, global_scope->scope_name, symbol->name, symbol->type, symbol->scope_level); - } - #endif + ANDBG_ARTI("%s Program %s %u %u\n", spaces+50-depth, global_scope->scope_name, global_scope->scope_level, global_scope->symbolsIndex); - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "Function") == 0) { - - //find the function name (so we must know this is a function...) - const char * expression_name = expression["name"];//.as(); - const char * expression_block = expression["block"]; - const char * function_name = value[expression_name]; - Symbol* function_symbol = new Symbol(expression["id"], function_name); - current_scope->insert(function_symbol); - - ANDBG_ARTI("%s Function %s.%s\n", spaces+50-depth, current_scope->scope_name, function_name); - ScopedSymbolTable* function_scope = new ScopedSymbolTable(function_name, current_scope->scope_level + 1, current_scope); - if (current_scope->child_scopesIndex < nrOfChildScope) - current_scope->child_scopes[current_scope->child_scopesIndex++] = function_scope; - else - ERROR_ARTI("ScopedSymbolTable %s childs full (%d)", current_scope->scope_name, nrOfChildScope); - function_symbol->function_scope = function_scope; - // ANDBG_ARTI("%s\n", "ASSIGNING ", function_symbol->name, " " , function_scope->scope_name); - - const char * expression_formals = expression["formals"]; - - if (expression_formals != nullptr) - analyze(value[expression_formals], nullptr, function_scope, depth + 1); - - if (value[expression_block].isNull()) - ERROR_ARTI("%s Program %s: no block %s in parseTree\n", spaces+50-depth, function_name, expression_block); - else - analyze(value[expression_block], nullptr, function_scope, depth + 1); - - // ANDBG_ARTI("%s\n", spaces+50-depth, "end function ", symbol_name, function_scope->scope_name, function_scope->scope_level, function_scope->symbolsIndex); - - #ifdef ARTI_DEBUG - for (uint8_t i=0; isymbolsIndex; i++) { - Symbol* symbol = function_scope->symbols[i]; - ANDBG_ARTI("%s %u %s %s.%s %s %u\n", spaces+50-depth, i, symbol->symbol_type, function_scope->scope_name, symbol->name, symbol->type, symbol->scope_level); + if (value[expression_block].isNull()) + ERROR_ARTI("%s Program %s: no block %s in parseTree\n", spaces+50-depth, program_name, expression_block); + else { + analyze(value[expression_block], nullptr, global_scope, depth + 1); } - #endif - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "Var") == 0 || strcmp(expression["id"], "Formal") == 0 || strcmp(expression["id"], "Assign") == 0 || strcmp(expression["id"], "VarRef") == 0) { - const char * expression_name = expression["name"]; - const char * expression_type = expression["type"]; - const char * expression_indices = expression["indices"]; - - const char * variable_name = value[expression_name]; - if (strcmp(expression["id"], "Assign") == 0) - variable_name = value[expression_name]["ID"]; - - char param_type[charLength]; - if (!value[expression_type].isNull()) { - serializeJson(value[expression_type], param_type); //current_scope.lookup(param.type_node.value); //need string, lookup also used to find types... + #ifdef ARTI_DEBUG + for (uint8_t i=0; isymbolsIndex; i++) { + Symbol* symbol = global_scope->symbols[i]; + ANDBG_ARTI("%s %u %s %s.%s of %u (%u)\n", spaces+50-depth, i, constructToString(symbol->symbol_type), global_scope->scope_name, symbol->name, symbol->type, symbol->scope_level); + } + #endif + + analyzedAlready = true; + break; } - else - strcpy(param_type, "notype"); - - //check if external variable - bool found = false; - uint8_t index = 0; - for (JsonPair externalsPair: definitionJson["EXTERNALS"].as()) { - if (strcmp(variable_name, externalsPair.key().c_str()) == 0) { - value["external"] = index; //add external index to parseTree - ANDBG_ARTI("%s Ext Variable found %s (%u)\n", spaces+50-depth, variable_name, depth); - found = true; - } - index++; + case F_Function: { + + //find the function name (so we must know this is a function...) + const char * expression_name = expression["name"];//.as(); + const char * expression_block = expression["block"]; + const char * function_name = value[expression_name]; + Symbol* function_symbol = new Symbol(expression["id"], function_name); + current_scope->insert(function_symbol); + + ANDBG_ARTI("%s Function %s.%s\n", spaces+50-depth, current_scope->scope_name, function_name); + ScopedSymbolTable* function_scope = new ScopedSymbolTable(function_name, current_scope->scope_level + 1, current_scope); + if (current_scope->child_scopesIndex < nrOfChildScope) + current_scope->child_scopes[current_scope->child_scopesIndex++] = function_scope; + else + ERROR_ARTI("ScopedSymbolTable %s childs full (%d)", current_scope->scope_name, nrOfChildScope); + function_symbol->function_scope = function_scope; + + const char * expression_formals = expression["formals"]; + + if (expression_formals != nullptr) + analyze(value[expression_formals], nullptr, function_scope, depth + 1); + + if (value[expression_block].isNull()) + ERROR_ARTI("%s Program %s: no block %s in parseTree\n", spaces+50-depth, function_name, expression_block); + else + analyze(value[expression_block], nullptr, function_scope, depth + 1); + + #ifdef ARTI_DEBUG + for (uint8_t i=0; isymbolsIndex; i++) { + Symbol* symbol = function_scope->symbols[i]; + ANDBG_ARTI("%s %u %s %s.%s of %u (%u)\n", spaces+50-depth, i, constructToString(symbol->symbol_type), function_scope->scope_name, symbol->name, symbol->type, symbol->scope_level); + } + #endif + + analyzedAlready = true; + break; } + case F_Var: + case F_Formal: + case F_Assign: + case F_VarRef: { + const char * expression_name = expression["name"]; + const char * expression_type = expression["type"]; + const char * expression_indices = expression["indices"]; + + const char * variable_name = value[expression_name]; + if (expression["id"].as() == F_Assign) + variable_name = value[expression_name]["ID"]; + + char param_type[charLength]; + if (!value[expression_type].isNull()) + serializeJson(value[expression_type], param_type); //current_scope.lookup(param.type_node.value); //need string, lookup also used to find types... + else + strcpy(param_type, "notype"); - if (!found) { - if (strcmp(expression["id"], "VarRef") == 0) { - Symbol* var_symbol = current_scope->lookup(variable_name); //lookup here and parent scopes - if (var_symbol == nullptr) - ERROR_ARTI("%s VarRef %s ID not found in scope %s\n", spaces+50-depth, variable_name, current_scope->scope_name); - else - ANDBG_ARTI("%s VarRef found %s.%s (%u)\n", spaces+50-depth, var_symbol->scope->scope_name, variable_name, depth); + //check if external variable + bool found = false; + uint8_t index = 0; + for (JsonPair externalsPair: definitionJson["EXTERNALS"].as()) { + if (strcmp(variable_name, externalsPair.key().c_str()) == 0) { + if (expression["id"].as() == F_Assign) + value[expression_name]["external"] = index; //add external index to parseTree + else + value["external"] = index; //add external index to parseTree + ANDBG_ARTI("%s Ext Variable found %s (%u) %s\n", spaces+50-depth, variable_name, depth, constructToString(expression["id"].as())); + found = true; + } + index++; } - else { //assign and var/formal - //if variable not already defined, then add + + if (!found) { Symbol* var_symbol = current_scope->lookup(variable_name); //lookup here and parent scopes - if (strcmp(expression["id"], "Assign") != 0 || var_symbol == nullptr) { //only assign needs to check if not exists - var_symbol = new Symbol(expression["id"], variable_name, param_type); - current_scope->insert(var_symbol); - ANDBG_ARTI("%s %s %s.%s of %s\n", spaces+50-depth, expression["id"].as(), var_symbol->scope->scope_name, variable_name, param_type); + if (expression["id"].as() == F_VarRef) { + if (var_symbol == nullptr) + ERROR_ARTI("%s VarRef %s ID not found in scope of %s\n", spaces+50-depth, variable_name, current_scope->scope_name); + else { + value["level"] = var_symbol->scope_level; + value["index"] = var_symbol->scope_index; + ANDBG_ARTI("%s VarRef found %s.%s (%u)\n", spaces+50-depth, var_symbol->scope->scope_name, variable_name, depth); + } + } + else { //assign and var/formal + //if variable not already defined, then add + if (expression["id"].as() != F_Assign || var_symbol == nullptr) { //only assign needs to check if not exists + var_symbol = new Symbol(expression["id"], variable_name, 9); // no type support yet + current_scope->insert(var_symbol); + ANDBG_ARTI("%s %s %s.%s of %s\n", spaces+50-depth, constructToString(expression["id"]), var_symbol->scope->scope_name, variable_name, param_type); + } + else if (expression["id"].as() != F_Assign && var_symbol != nullptr) + ERROR_ARTI("%s %s Duplicate ID %s.%s\n", spaces+50-depth, constructToString(expression["id"]), var_symbol->scope->scope_name, variable_name); + + if (expression["id"].as() == F_Assign) { + value[expression_name]["level"] = var_symbol->scope_level; + value[expression_name]["index"] = var_symbol->scope_index;; + } } - else if (strcmp(expression["id"], "Assign") != 0 && var_symbol != nullptr) - ERROR_ARTI("%s %s Duplicate ID %s.%s\n", spaces+50-depth, expression["id"].as(), var_symbol->scope->scope_name, variable_name); } - } - if (strcmp(expression["id"], "Assign") == 0) { - const char * expression_value = expression["value"]; + if (expression["id"].as() == F_Assign) { + const char * expression_value = expression["value"]; - ANDBG_ARTI("%s Assign %s = (%u)\n", spaces+50-depth, variable_name, depth); + ANDBG_ARTI("%s %s %s = (%u)\n", spaces+50-depth, constructToString(expression["id"]), variable_name, depth); - if (!value[expression_value].isNull()) { - analyze(value, expression_value, current_scope, depth + 1); + if (!value[expression_value].isNull()) { + analyze(value, expression_value, current_scope, depth + 1); + } + else + ERROR_ARTI("%s %s %s: no value in parseTree\n", spaces+50-depth, constructToString(expression["id"]), variable_name); + } + + if (!value[expression_indices].isNull()) { + analyze(value, expression_indices, current_scope, depth + 1); } - else - ERROR_ARTI("%s Assign %s: no value in parseTree\n", spaces+50-depth, variable_name); - } - if (!value[expression_indices].isNull()) { - analyze(value, expression_indices, current_scope, depth + 1); + analyzedAlready = true; + break; } + case F_Call: { + const char * function_name = value[expression["name"].as()]; + const char * expression_actuals = expression["actuals"]; - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "Call") == 0) { - const char * function_name = value[expression["name"].as()]; - const char * expression_actuals = expression["actuals"]; - - //check if external function - bool found = false; - uint8_t index = 0; - for (JsonPair externalsPair: definitionJson["EXTERNALS"].as()) { - if (strcmp(function_name, externalsPair.key().c_str()) == 0) { - ANDBG_ARTI("%s Ext Function found %s (%u)\n", spaces+50-depth, function_name, depth); - value["external"] = index; //add external index to parseTree - if (expression_actuals != nullptr) - analyze(value[expression_actuals], nullptr, current_scope, depth + 1); - found = true; + //check if external function + bool found = false; + uint8_t index = 0; + for (JsonPair externalsPair: definitionJson["EXTERNALS"].as()) { + if (strcmp(function_name, externalsPair.key().c_str()) == 0) { + ANDBG_ARTI("%s Ext Function found %s (%u)\n", spaces+50-depth, function_name, depth); + value["external"] = index; //add external index to parseTree + if (expression_actuals != nullptr) + analyze(value[expression_actuals], nullptr, current_scope, depth + 1); + found = true; + } + index++; } - index++; - } - if (!found) { - Symbol* function_symbol = current_scope->lookup(function_name); //lookup here and parent scopes - if (function_symbol != nullptr) { - if (expression_actuals != nullptr) - analyze(value[expression_actuals], nullptr, current_scope, depth + 1); + if (!found) { + Symbol* function_symbol = current_scope->lookup(function_name); //lookup here and parent scopes + if (function_symbol != nullptr) { + if (expression_actuals != nullptr) + analyze(value[expression_actuals], nullptr, current_scope, depth + 1); - analyze(function_symbol->block, nullptr, current_scope, depth + 1); - } //function_symbol != nullptr - else { - ERROR_ARTI("%s Function %s not found in scope %s\n", spaces+50-depth, function_name, current_scope->scope_name); - } - } //external functions + analyze(function_symbol->block, nullptr, current_scope, depth + 1); + } //function_symbol != nullptr + else { + ERROR_ARTI("%s Function %s not found in scope of %s\n", spaces+50-depth, function_name, current_scope->scope_name); + } + } //external functions - visitCalledAlready = true; - } // if expression["id"] + analyzedAlready = true; + } // case + break; + } //switch - // MEMORY_ARTI("%s Heap %s > %u\n", spaces+50-depth, expression_id, esp_get_free_heap_size()); + // MEMORY_ARTI("%s Heap %s > %u\n", spaces+50-depth, expression_id, FREE_SIZE); } // if expression not null } // is symbol_name - if (!this->definitionJson["TOKENS"][key].isNull()) { - // ANDBG_ARTI("%s Token %s\n", spaces+50-depth, key); - visitCalledAlready = true; + else if (!this->definitionJson["TOKENS"][key].isNull()) + { + const char * valueStr = value.as().c_str(); + + if (strcmp(key, "INTEGER_CONST") == 0) + parseTree["operator"] = F_integerConstant; + else if (strcmp(key, "REAL_CONST") == 0) + parseTree["operator"] = F_realConstant; + else if (strcmp(valueStr, "+") == 0) + parseTree["operator"] = F_plus; + else if (strcmp(valueStr, "-") == 0) + parseTree["operator"] = F_minus; + else if (strcmp(valueStr, "*") == 0) + parseTree["operator"] = F_multiplication; + else if (strcmp(valueStr, "/") == 0) + parseTree["operator"] = F_division; + else if (strcmp(valueStr, "%") == 0) + parseTree["operator"] = F_modulo; + else if (strcmp(valueStr, "<<") == 0) + parseTree["operator"] = F_bitShiftLeft; + else if (strcmp(valueStr, ">>") == 0) + parseTree["operator"] = F_bitShiftRight; + else if (strcmp(valueStr, "==") == 0) + parseTree["operator"] = F_equal; + else if (strcmp(valueStr, "!=") == 0) + parseTree["operator"] = F_notEqual; + else if (strcmp(valueStr, ">") == 0) + parseTree["operator"] = F_greaterThen; + else if (strcmp(valueStr, ">=") == 0) + parseTree["operator"] = F_greaterThenOrEqual; + else if (strcmp(valueStr, "<") == 0) + parseTree["operator"] = F_lessThen; + else if (strcmp(valueStr, "<=") == 0) + parseTree["operator"] = F_lessThenOrEqual; + + analyzedAlready = true; } - // ANDBG_ARTI("%s Object %s %u\n", spaces+50-depth, key, value, visitCalledAlready); - if (!visitCalledAlready) //parseTreeObject.size() != 1 && + if (!analyzedAlready) //parseTreeObject.size() != 1 && analyze(value, nullptr, current_scope, depth + 1); } // key values @@ -1309,14 +1283,11 @@ class ARTI { } else { //not object if (parseTree.is()) { - // ANDBG_ARTI("%s Visit array %s %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.as().c_str(), depth); for (JsonVariant newParseTree: parseTree.as()) { - // ANDBG_ARTI("%s\n", spaces+50-depth, "Array ", parseTree[i], " "; analyze(newParseTree, nullptr, current_scope, depth + 1); } } else { //not array - // ANDBG_ARTI("%s Visit rest %s %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.as().c_str(), depth); // string element = parseTree; //for some weird reason this causes a crash on esp32 // ERROR_ARTI("%s Error: parseTree should be array or object %s %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.as().c_str(), depth); @@ -1327,204 +1298,148 @@ class ARTI { } //analyze //https://dev.to/lefebvre/compilers-106---optimizer--ig8 - bool optimize(JsonVariant parseTree, const char * treeElement = nullptr, ScopedSymbolTable* current_scope = nullptr, uint8_t depth = 0) { - - // ANDBG_ARTI("%s Visit %s %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.as().c_str(), depth); - - if (parseTree.is()) { - // ANDBG_ARTI("%s Visit object %s %u %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.size(), parseTree.as().c_str(), depth); + bool optimize(JsonVariant parseTree, uint8_t depth = 0) + { + if (parseTree.is()) + { + //make the parsetree as small as possible to let the interpreter run as fast as possible: - for (JsonPair parseTreePair : parseTree.as()) { + for (JsonPair parseTreePair : parseTree.as()) + { const char * key = parseTreePair.key().c_str(); JsonVariant value = parseTreePair.value(); - if (treeElement == nullptr || strcmp(treeElement, key) == 0 ) { //in case there are more elements in the object and you want to visit only one - // ANDBG_ARTI("%s Visit object element %s %s\n", spaces+50-depth, key, value.as().c_str()); - bool visitCalledAlready = false; + bool optimizedAlready = false; - if (!definitionJson[key].isNull()) { //if key is symbol_name - // ANDBG_ARTI("%s Visit object element symbol %s %s\n", spaces+50-depth, key, value.as().c_str()); - //shrink + // object: + // if key is symbol and value is object then optimize object after that if object empty then remove key + // else key is !ID and value is string then remove key + // else key is * and value is array then optimize array after that if array empty then remove key * - if (false && value.is()) { //Symbols trees are always objects e.g. {"term": {"factor": {"varref": {..}},"*": ["multiple"]}} - for (JsonPair symbolObjectPair : value.as()) { - const char * symbolObjectKey = symbolObjectPair.key().c_str(); - JsonVariant symbolObjectValue = symbolObjectPair.value(); - ANDBG_ARTI("%s Visit object element symbol %s %s %s\n", spaces+50-depth, key, symbolObjectKey, symbolObjectValue.as().c_str()); + // array + // if element is multiple then remove - if (symbolObjectValue.is()) { // e.g. {"term":{"factor":{"varref":{"ID":"ledCount"}},"*":["multiple"]}} - if (symbolObjectValue.size() == 0) { - DEBUG_ARTI("%s remove object empty values for key %s\n", spaces+50-depth, symbolObjectKey); - value.remove(symbolObjectKey); - } - else { - uint8_t objectIndex = 0; - for (JsonPair symbolObjectObject : symbolObjectValue.as()) { - - if (symbolObjectObject.value().is()) { - JsonArray symbolObjectObjectArray = symbolObjectObject.value().as(); - // JsonArray::iterator toBeRemoved[10]; - // uint8_t toBeRemovedCounter = 0; - uint8_t arrayIndex = 0; - for (JsonArray::iterator it = symbolObjectObjectArray.begin(); it != symbolObjectObjectArray.end(); ++it) { - if ((*it) == "multiple") { - DEBUG_ARTI("%s remove array element 'multiple' key of %s (%u - %u)\n", spaces+50-depth, symbolObjectKey, objectIndex, arrayIndex); - symbolObjectObjectArray.remove(it); - // toBeRemoved[toBeRemovedCounter++] = it; - } - else if (it->size() == 0) { - DEBUG_ARTI("%s remove array element {} (%u)\n", spaces+50-depth, arrayIndex); - symbolObjectObjectArray.remove(it); //remove {} elements (added by * arrays, don't know where added) - // toBeRemoved[toBeRemovedCounter++] = it; - } - arrayIndex++; - } - // for (int i=0; i().c_str()); - symbolObjectValue.remove("*"); - // symbolObjectValue.remove(symbolObjectObject.key().c_str()); - } - } - objectIndex++; - } //for symbol object objects - } - } //if symbol object has object + if (!definitionJson[key].isNull() && value.is()) //if key is symbol_name + { + optimize(value, depth + 1); - //symbolObjectKey should be a symbol on itself and the value must consist of one element - if (false && !definitionJson[symbolObjectKey].isNull() && symbolObjectValue.size()==1) { //disabled as causing crash on Arduino + if (value.size() == 0) + { + // DEBUG_ARTI("%s remove key without value %s (%u)\n", spaces+50-depth, key, depth); + parseTree.remove(key); + } + else if (value.size() == 1) //try to shrink + { + //- check if a symbol is not used in analyzer / interpreter and has only one element: go to the parent and replace itself with its child (shrink) - bool found = false; - for (JsonPair semanticsPair : definitionJson["SEMANTICS"].as()) { - const char * semanticsKey = semanticsPair.key().c_str(); - JsonVariant semanticsValue = semanticsPair.value(); + JsonObject::iterator objectIterator = value.as().begin(); - // DEBUG_ARTI("%s semantics %s", spaces+50-depth, semanticsKey); - if (strcmp(symbolObjectKey, semanticsKey) == 0){ - found = true; - break; - } - for (JsonPair semanticsVariables : semanticsValue.as()) { - JsonVariant variableValue = semanticsVariables.value(); - // DEBUG_ARTI(" %s", variableValue.as().c_str()); - if (variableValue.is() && strcmp(symbolObjectKey, variableValue.as()) == 0) { - found = true; - break; - } - } - // DEBUG_ARTI("\n"); + if (!definitionJson[objectIterator->key().c_str()].isNull()) + { + //symbolObjectKey should be a symbol on itself and the value must consist of one element + bool found = false; + for (JsonPair semanticsPair : definitionJson["SEMANTICS"].as()) + { + const char * semanticsKey = semanticsPair.key().c_str(); + JsonVariant semanticsValue = semanticsPair.value(); + + if (strcmp(objectIterator->key().c_str(), semanticsKey) == 0){ + found = true; + break; + } + for (JsonPair semanticsVariables : semanticsValue.as()) { + JsonVariant variableValue = semanticsVariables.value(); + if (variableValue.is() && strcmp(objectIterator->key().c_str(), variableValue.as()) == 0) { + found = true; + break; } - - if (!found) { // not used in analyzer / interpreter - DEBUG_ARTI("%s symbol to shrink %s\n", spaces+50-depth, symbolObjectKey); - if (parseTree.is()) { - JsonObject parseTreeObject = parseTree.as(); - for (JsonObject::iterator it = parseTreeObject.begin(); it != parseTreeObject.end(); ++it) { - const char * parseTreeObjectKey = it->key().c_str(); - JsonVariant parseTreeObjectValue = it->value(); - if (parseTreeObjectValue == value) //find the right element to replace - { - parseTree[parseTreeObjectKey] = symbolObjectValue; - DEBUG_ARTI("%s Shrink object %s %s\n", spaces+50-depth, symbolObjectKey, symbolObjectValue.as().c_str()); - // DEBUG_ARTI("%s Shrink object %s %s\n", spaces+50-depth, symbolObjectKey, value.as().c_str()); - // DEBUG_ARTI("%s Shrink object %s %s\n", spaces+50-depth, symbolObjectKey, parseTree.as().c_str()); - } - } - } - else if (parseTree.is()) { - JsonArray parseTreeArray = parseTree.as(); - for (int i=0; i().c_str()); - // DEBUG_ARTI("%s Shrink array %s %s\n", spaces+50-depth, symbolObjectKey, value.as().c_str()); - // DEBUG_ARTI("%s Shrink array %s %s\n", spaces+50-depth, symbolObjectKey, parseTree.as().c_str()); - } - } - } - // DEBUG_ARTI("%s symbol to shrink done %s %s\n", spaces+50-depth, symbolObjectKey, symbolObjectValue.as().c_str()); - } - } // symbolObjectKey should by a symbol on itself and value is one element - } //for symbol objects - } //if symbol has object - - - - - - - JsonVariant expression = definitionJson["SEMANTICS"][key]; - if (false && !expression.isNull()) - { - // const char * expression_id = expression["id"]; - // MEMORY_ARTI("%s Heap %s < %u\n", spaces+50-depth, expression_id, esp_get_free_heap_size()); - if (false && strcmp(expression["id"], "Program") == 0) { - visitCalledAlready = true; - } - else if (false && strcmp(expression["id"], "Function") == 0) { - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "Var") == 0 || strcmp(expression["id"], "Formal") == 0 || strcmp(expression["id"], "Assign") == 0 || strcmp(expression["id"], "VarRef") == 0) { - const char * expression_name = expression["name"]; - const char * variable_name = value[expression_name]; - if (strcmp(expression["id"], "Assign") == 0) - variable_name = value[expression_name]["ID"]; - - // ANDBG_ARTI("%s Visit %s %s (%u)\n", spaces+50-depth, expression["id"].as(), variable_name, depth); - - uint8_t index = 0; - for (JsonPair externalsPair: definitionJson["EXTERNALS"].as()) { - if (strcmp(variable_name, externalsPair.key().c_str()) == 0) { - } - index++; } + } - visitCalledAlready = true; + if (!found) // not used in analyzer / interpreter + { + // DEBUG_ARTI("%s symbol to shrink %s = %s from %s %s\n", spaces+50-depth, key, objectIterator->value().as().c_str(), objectIterator->key().c_str(), parseTree[key].as().c_str()); + parseTree[key] = objectIterator->value(); } - else if (strcmp(expression["id"], "Call") == 0) { - #ifdef ARTI_ANDBG - const char * function_name = value[expression["name"].as()]; + } // symbolObjectKey should by a symbol on itself and value is one element + } // symbolObjectKey should by a symbol on itself and value is one element - ANDBG_ARTI("%s Visit %s %s (%u)\n", spaces+50-depth, expression["id"].as(), function_name, depth); - #endif + optimizedAlready = true; + } + else if (!this->definitionJson["TOKENS"][key].isNull()) { + const char * valueStr = value.as().c_str(); + if (strcmp(key, "ID") == 0 || strcmp(key, "INTEGER_CONST") == 0 || strcmp(key, "REAL_CONST") == 0 || + strcmp(key, "INTEGER") == 0 || strcmp(key, "REAL") == 0 || + strcmp(valueStr, "+") == 0 || strcmp(valueStr, "-") == 0 || strcmp(valueStr, "*") == 0 || strcmp(valueStr, "/") == 0 || strcmp(valueStr, "%") == 0 || + strcmp(valueStr, "<<") == 0 || strcmp(valueStr, ">>") == 0 || + strcmp(valueStr, "==") == 0 || strcmp(valueStr, "!=") == 0 || + strcmp(valueStr, ">") == 0 || strcmp(valueStr, ">=") == 0 || strcmp(valueStr, "<") == 0 || strcmp(valueStr, "<=") == 0) { + } + else + { + // DEBUG_ARTI("%s remove key/value %s %s (%u)\n", spaces+50-depth, key, valueStr, depth); + parseTree.remove(key); + } - visitCalledAlready = true; - } // if expression["id"] - // MEMORY_ARTI("%s Heap %s > %u\n", spaces+50-depth, expression_id, esp_get_free_heap_size()); - } // if expression not null + optimizedAlready = true; + } + else if (strcmp(key, "*") == 0 ) { + optimize(value, depth + 1); - } // is symbol_name + if (value.size() == 0) + parseTree.remove(key); - if (!this->definitionJson["TOKENS"][key].isNull()) { - // ANDBG_ARTI("%s Token %s\n", spaces+50-depth, key); - visitCalledAlready = true; - } - // ANDBG_ARTI("%s Object %s %u\n", spaces+50-depth, key, value, visitCalledAlready); + optimizedAlready = true; + } + else + DEBUG_ARTI("%s unknown status for %s %s (%u)\n", spaces+50-depth, key, value.as().c_str(), depth); - if (!visitCalledAlready) //parseTreeObject.size() != 1 && - optimize(value, nullptr, current_scope, depth + 1); + if (!optimizedAlready) //parseTreeObject.size() != 1 && + optimize(value, depth + 1); - } // key values } ///for elements in object } - else { //not object - if (parseTree.is()) { - // ANDBG_ARTI("%s Visit array %s %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.as().c_str(), depth); - for (JsonVariant newParseTree: parseTree.as()) { - // ANDBG_ARTI("%s\n", spaces+50-depth, "Array ", parseTree[i], " "; - optimize(newParseTree, nullptr, current_scope, depth + 1); + else if (parseTree.is()) + { + JsonArray parseTreeArray = parseTree.as(); + + uint8_t arrayIndex = 0; + for (JsonArray::iterator it = parseTreeArray.begin(); it != parseTreeArray.end(); ++it) + { + JsonVariant element = *it; + + if (element == "multiple") { + // DEBUG_ARTI("%s remove array element 'multiple' of %s array (%u)\n", spaces+50-depth, element.as().c_str(), arrayIndex); + parseTreeArray.remove(it); } + else + if (it->size() == 0) { //causes subpixel to crash????!!! + // DEBUG_ARTI("%s remove array element {} of %s array (%u)\n", spaces+50-depth, element.as().c_str(), arrayIndex); + parseTreeArray.remove(it); //remove {} elements (added by * arrays, don't know where added) + } + else + optimize(*it, depth + 1); + + arrayIndex++; } - else { //not array - // string element = parseTree; - //for some weird reason this causes a crash on esp32 - // ERROR_ARTI("%s Error: parseTree should be array or object %s %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), valuexxx, depth); - // if (definitionJson["SEMANTICS"][element]) - } + + // for (JsonVariant newParseTree: parseTree.as()) { + // ANDBG_ARTI("%s Array element %s\n", spaces+50-depth, newParseTree.as().c_str()); + // if (newParseTree.is() || newParseTree.is()) + // optimize(newParseTree, depth + 1); + // else + // ERROR_ARTI("%s Error: parseTree not object %s (%u)\n", spaces+50-depth, newParseTree.as().c_str(), depth); + // } } + else { //not array + // string element = parseTree; + //for some weird reason this causes a crash on esp32 + ERROR_ARTI("%s Error: parseTree should be array or object %s (%u)\n", spaces+50-depth, parseTree.as().c_str(), depth); + // if (definitionJson["SEMANTICS"][element]) + } + return true; } //optimize @@ -1533,7 +1448,7 @@ class ARTI { bool interpret(JsonVariant parseTree, const char * treeElement = nullptr, ScopedSymbolTable* current_scope = nullptr, uint8_t depth = 0) { - // RUNLOG_ARTI("%s Visit %s %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.as().c_str(), depth); + // RUNLOG_ARTI("%s Interpret %s %s (%u)\n", spaces+50-depth, stringOrEmpty(treeElement), parseTree.as().c_str(), depth); if (depth >= 50) { ERROR_ARTI("Error too deep %u\n", depth); @@ -1547,11 +1462,11 @@ class ARTI { JsonVariant value = parseTreePair.value(); if (treeElement == nullptr || strcmp(treeElement, key) == 0 ) { - // RUNLOG_ARTI("%s Visit object element %s\n", spaces+50-depth, key); //, value.as().c_str() + // RUNLOG_ARTI("%s Interpret object element %s\n", spaces+50-depth, key); //, value.as().c_str() // return; - bool visitCalledAlready = false; + bool interpretAlready = false; if (!this->definitionJson[key].isNull()) { //if key is symbol_name JsonVariant expression = this->definitionJson["SEMANTICS"][key]; @@ -1559,396 +1474,454 @@ class ARTI { { // RUNLOG_ARTI("%s Symbol %s %s\n", spaces+50-depth, symbol_name, expression.as().c_str()); - // const char * expression_id = expression["id"]; - // MEMORY_ARTI("%s Heap %s < %u\n", spaces+50-depth, expression_id, esp_get_free_heap_size()); - if (strcmp(expression["id"], "Program") == 0) { - const char * expression_name = expression["name"]; - const char * expression_block = expression["block"]; - RUNLOG_ARTI("%s program name %s\n", spaces+50-depth, expression_name); - const char * program_name = value[expression_name]; + // MEMORY_ARTI("%s Heap %s < %u\n", spaces+50-depth, expression_id, FREE_SIZE); - if (!value[expression_name].isNull()) { - ActivationRecord* ar = new ActivationRecord(program_name, "PROGRAM", 1); - RUNLOG_ARTI("%s %s %s %s\n", spaces+50-depth, expression["id"].as(), ar->name, program_name); + switch (expression["id"].as()) { + case F_Program: { + const char * expression_name = expression["name"]; + const char * expression_block = expression["block"]; + RUNLOG_ARTI("%s program name %s\n", spaces+50-depth, expression_name); + const char * program_name = value[expression_name]; - this->callStack->push(ar); - if (value[expression_block].isNull()) - ERROR_ARTI("%s Program %s: no block %s in parseTree\n", spaces+50-depth, program_name, expression_block); - else - interpret(value[expression_block], nullptr, global_scope, depth + 1); - - // do not delete main stack and program ar as used in subsequent calls - // this->callStack->pop(); - // delete ar; ar = nullptr; - } - else - ERROR_ARTI("program name null\n"); - - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "Function") == 0) { - const char * expression_block = expression["block"]; - const char * function_name = value[expression["name"].as()]; - Symbol* function_symbol = current_scope->lookup(function_name); - RUNLOG_ARTI("%s Save block of %s\n", spaces+50-depth, function_name); - function_symbol->block = value[expression_block]; - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "Call") == 0) { - const char * function_name = value[expression["name"].as()]; - const char * expression_actuals = expression["actuals"]; - - //check if external function - if (!value["external"].isNull()) { - uint8_t oldIndex = valueStack->stack_index; - - if (expression_actuals != nullptr) - interpret(value[expression_actuals], nullptr, current_scope, depth + 1); + if (!value[expression_name].isNull()) { + ActivationRecord* ar = new ActivationRecord(program_name, "PROGRAM", 1); + RUNLOG_ARTI("%s %s %s %s\n", spaces+50-depth, constructToString(expression["id"]), ar->name, program_name); - double returnValue = doubleNull; - - returnValue = arti_external_function(value["external"], valueStack->doubleStack[oldIndex], (valueStack->stack_index - oldIndex>1)?valueStack->doubleStack[oldIndex+1]:doubleNull, (valueStack->stack_index - oldIndex>2)?valueStack->doubleStack[oldIndex+2]:doubleNull); - - #if ARTI_PLATFORM != ARTI_ARDUINO // because arduino runs the code instead of showing the code - uint8_t lastIndex = oldIndex; - RUNLOG_ARTI("%s Call %s(", spaces+50-depth, function_name); - char sep[3] = ""; - for (int i = oldIndex; i< valueStack->stack_index; i++) { - RUNLOG_ARTI("%s%f", sep, valueStack->doubleStack[i]); - strcpy(sep, ", "); - } - if ( returnValue != doubleNull) - RUNLOG_ARTI(") = %f\n", returnValue); + this->callStack->push(ar); + if (value[expression_block].isNull()) + ERROR_ARTI("%s Program %s: no block %s in parseTree\n", spaces+50-depth, program_name, expression_block); else - RUNLOG_ARTI(")\n"); - #endif + interpret(value[expression_block], nullptr, global_scope, depth + 1); - valueStack->stack_index = oldIndex; - - if (returnValue != doubleNull) - valueStack->push(returnValue); + // do not delete main stack and program ar as used in subsequent calls + // this->callStack->pop(); + // delete ar; ar = nullptr; + } + else + ERROR_ARTI("program name null\n"); + interpretAlready = true; + break; } - else { //not an external function + case F_Function: { + const char * expression_block = expression["block"]; + const char * function_name = value[expression["name"].as()]; Symbol* function_symbol = current_scope->lookup(function_name); + RUNLOG_ARTI("%s Save block of %s\n", spaces+50-depth, function_name); + if (function_symbol != nullptr) + function_symbol->block = value[expression_block]; + else + ERROR_ARTI("%s Function %s: not found\n", spaces+50-depth, function_name); - if (function_symbol != nullptr) { //calling undefined function: pre-defined functions e.g. print - - ActivationRecord* ar = new ActivationRecord(function_name, "Function", function_symbol->scope_level + 1); - - RUNLOG_ARTI("%s %s %s\n", spaces+50-depth, expression["id"].as(), function_name); + interpretAlready = true; + break; + } + case F_Call: { + const char * function_name = value[expression["name"].as()]; + const char * expression_actuals = expression["actuals"]; + //check if external function + if (!value["external"].isNull()) { uint8_t oldIndex = valueStack->stack_index; - uint8_t lastIndex = valueStack->stack_index; if (expression_actuals != nullptr) interpret(value[expression_actuals], nullptr, current_scope, depth + 1); - for (uint8_t i=0; ifunction_scope->symbolsIndex; i++) { //backwards because popped in reversed order - if (strcmp(function_symbol->function_scope->symbols[i]->symbol_type, "Formal") == 0) { //select formal parameters - //determine type, for now assume double - double result = valueStack->doubleStack[lastIndex++]; - ar->set(function_symbol->function_scope->symbols[i]->name, result); - RUNLOG_ARTI("%s Actual %s.%s = %f (pop %u)\n", spaces+50-depth, function_name, function_symbol->function_scope->symbols[i]->name, result, valueStack->stack_index); + double returnValue = doubleNull; + + returnValue = arti_external_function(value["external"], valueStack->doubleStack[oldIndex] + , (valueStack->stack_index - oldIndex>1)?valueStack->doubleStack[oldIndex+1]:doubleNull + , (valueStack->stack_index - oldIndex>2)?valueStack->doubleStack[oldIndex+2]:doubleNull + , (valueStack->stack_index - oldIndex>3)?valueStack->doubleStack[oldIndex+3]:doubleNull + , (valueStack->stack_index - oldIndex>4)?valueStack->doubleStack[oldIndex+4]:doubleNull); + + #if ARTI_PLATFORM != ARTI_ARDUINO // because arduino runs the code instead of showing the code + uint8_t lastIndex = oldIndex; + RUNLOG_ARTI("%s Call %s(", spaces+50-depth, function_name); + char sep[3] = ""; + for (int i = oldIndex; i< valueStack->stack_index; i++) { + RUNLOG_ARTI("%s%f", sep, valueStack->doubleStack[i]); + strcpy(sep, ", "); } - } + if ( returnValue != doubleNull) + RUNLOG_ARTI(") = %f\n", returnValue); + else + RUNLOG_ARTI(")\n"); + #endif valueStack->stack_index = oldIndex; - this->callStack->push(ar); + if (returnValue != doubleNull) + valueStack->push(returnValue); - interpret(function_symbol->block, nullptr, function_symbol->function_scope, depth + 1); + } + else { //not an external function + Symbol* function_symbol = current_scope->lookup(function_name); - this->callStack->pop(); + if (function_symbol != nullptr) { //calling undefined function: pre-defined functions e.g. print - delete ar; ar = nullptr; + ActivationRecord* ar = new ActivationRecord(function_name, "Function", function_symbol->scope_level + 1); - //tbd if syntax supports returnvalue - // char callResult[charLength] = "CallResult tbd of "; - // strcat(callResult, function_name); - // valueStack->push(callResult); + RUNLOG_ARTI("%s %s %s\n", spaces+50-depth, constructToString(expression["id"]), function_name); - } //function_symbol != nullptr - else { - //this should move to analyze and should abort the programm!!! - RUNLOG_ARTI("%s %s not found %s\n", spaces+50-depth, expression["id"].as(), function_name); - } - } //external functions + uint8_t oldIndex = valueStack->stack_index; + uint8_t lastIndex = valueStack->stack_index; - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "VarRef") == 0 || strcmp(expression["id"], "Assign") == 0) { //get or set a variable - const char * expression_name = expression["name"]; //ID (key="varref") - const char * variable_name = value[expression_name]; + if (expression_actuals != nullptr) + interpret(value[expression_actuals], nullptr, current_scope, depth + 1); - uint8_t oldIndex = valueStack->stack_index; + for (uint8_t i=0; ifunction_scope->symbolsIndex; i++) { //backwards because popped in reversed order + if (function_symbol->function_scope->symbols[i]->symbol_type == F_Formal) { //select formal parameters + //determine type, for now assume double + double result = valueStack->doubleStack[lastIndex++]; + ar->set(function_symbol->function_scope->symbols[i]->scope_index, result); + RUNLOG_ARTI("%s Actual %s.%s = %f (pop %u)\n", spaces+50-depth, function_name, function_symbol->function_scope->symbols[i]->name, result, valueStack->stack_index); + } + } - //array indices - const char * expression_indices = expression["indices"]; - char indices[charLength]; - strcpy(indices, ""); - if (expression_indices != nullptr) { - if (!value[expression_indices].isNull()) { - strcat(indices, "["); + valueStack->stack_index = oldIndex; - interpret(value, expression["indices"], current_scope, depth + 1); //value pushed + this->callStack->push(ar); - char sep[3] = ""; - for (uint8_t i = oldIndex; i< valueStack->stack_index; i++) { - strcat(indices, sep); - char itoaChar[charLength]; - itoa(valueStack->doubleStack[i], itoaChar, 10); - strcat(indices, itoaChar); - strcpy(sep, ","); - } + interpret(function_symbol->block, nullptr, function_symbol->function_scope, depth + 1); - strcat(indices, "]"); - } - } + this->callStack->pop(); - if (strcmp(expression["id"], "Assign") == 0) { - variable_name = value[expression_name]["ID"]; + delete ar; ar = nullptr; - const char * expression_value = expression["value"]; - if (!value[expression_value].isNull()) { //value assignment - interpret(value, expression["value"], current_scope, depth + 1); //value pushed - } - else { - ERROR_ARTI("%s Assign %s has no value\n", spaces+50-depth, expression_name); - valueStack->push(doubleNull); - } - } + //tbd if syntax supports returnvalue + // char callResult[charLength] = "CallResult tbd of "; + // strcat(callResult, function_name); + // valueStack->push(callResult); - //check if external variable - if (!value["external"].isNull()) { //added by Analyze - double returnValue = doubleNull; + } //function_symbol != nullptr + else { + //this should move to analyze and should abort the programm!!! + RUNLOG_ARTI("%s %s not found %s\n", spaces+50-depth, constructToString(expression["id"]), function_name); + } + } //external functions - if (strcmp(expression["id"], "VarRef") == 0) { //get the value + interpretAlready = true; + break; + } + case F_VarRef: + case F_Assign: { //get or set a variable + const char * expression_name = expression["name"]; //ID (key="varref") + const char * variable_name = value[expression_name]; + uint8_t variable_level = value["level"]; + uint8_t variable_index = value["index"]; + uint8_t variable_external = value["external"]; - returnValue = arti_get_external_variable(value["external"], (valueStack->stack_index - oldIndex>0)?valueStack->doubleStack[oldIndex]:doubleNull, (valueStack->stack_index - oldIndex>1)?valueStack->doubleStack[oldIndex+1]:doubleNull); + uint8_t oldIndex = valueStack->stack_index; - valueStack->stack_index = oldIndex; + //array indices + const char * expression_indices = expression["indices"]; + char indices[charLength]; + strcpy(indices, ""); + if (expression_indices != nullptr) { + if (!value[expression_indices].isNull()) { + strcat(indices, "["); + + interpret(value, expression["indices"], current_scope, depth + 1); //value pushed + + char sep[3] = ""; + for (uint8_t i = oldIndex; i< valueStack->stack_index; i++) { + strcat(indices, sep); + char itoaChar[charLength]; + itoa(valueStack->doubleStack[i], itoaChar, 10); + strcat(indices, itoaChar); + strcpy(sep, ","); + } - if (returnValue != doubleNull) { - valueStack->push(returnValue); - RUNLOG_ARTI("%s %s ext.%s = %f (push %u)\n", spaces+50-depth, expression["id"].as(), variable_name, returnValue, valueStack->stack_index); //key is variable_declaration name is ID + strcat(indices, "]"); } - else - ERROR_ARTI("%s Error: %s ext.%s no value\n", spaces+50-depth, expression["id"].as(), variable_name); } - else { //assign: set the external value... - returnValue = valueStack->popDouble(); //result of visit value - arti_set_external_variable(returnValue, value["external"], (valueStack->stack_index - oldIndex>0)?valueStack->doubleStack[oldIndex]:doubleNull, (valueStack->stack_index - oldIndex>1)?valueStack->doubleStack[oldIndex+1]:doubleNull); + if (expression["id"].as() == F_Assign) { + variable_name = value[expression_name]["ID"]; + variable_level = value[expression_name]["level"]; + variable_index = value[expression_name]["index"]; + variable_external = value[expression_name]["external"]; - RUNLOG_ARTI("%s %s set ext.%s%s = %f (%u)\n", spaces+50-depth, expression["id"].as(), variable_name, indices, returnValue, valueStack->stack_index); - valueStack->stack_index = oldIndex; + const char * expression_value = expression["value"]; + if (!value[expression_value].isNull()) { //value assignment + interpret(value, expression["value"], current_scope, depth + 1); //value pushed + } + else { + ERROR_ARTI("%s Assign %s has no value\n", spaces+50-depth, expression_name); + valueStack->push(doubleNull); + } } - } - else { //not external, get er set the variable - Symbol* variable_symbol = current_scope->lookup(variable_name); - ActivationRecord* ar; + //check if external variable + if (!value["external"].isNull() || !value[expression_name]["external"].isNull()) //added by Analyze + { + double returnValue = doubleNull; - //check already defined in this scope + if (expression["id"].as() == F_VarRef) { //get the value - if (variable_symbol != nullptr) { //var already exist - //calculate the index in the call stack to find the right ar - uint8_t index = this->callStack->recordsCounter - 1 - (this->callStack->peek()->nesting_level - variable_symbol->scope_level); - // RUNLOG_ARTI("%s %s %s.%s = %s (push) %s %d-%d = %d (%d)\n", spaces+50-depth, expression["id"].as(), ar->name, variable_name, varValue, variable_symbol->name, this->callStack->peek()->nesting_level,variable_symbol->scope_level, index, this->callStack->recordsCounter); //key is variable_declaration name is ID - ar = this->callStack->records[index]; - } - else { //var created here - ar = this->callStack->peek(); - } + returnValue = arti_get_external_variable(variable_external, (valueStack->stack_index - oldIndex>0)?valueStack->doubleStack[oldIndex]:doubleNull, (valueStack->stack_index - oldIndex>1)?valueStack->doubleStack[oldIndex+1]:doubleNull); - if (ar != nullptr) { - if (strcmp(expression["id"], "VarRef") == 0) { //get the value - //determine type, for now assume double - double varValue = ar->getDouble(variable_name); + valueStack->stack_index = oldIndex; - valueStack->push(varValue); - #if ARTI_PLATFORM != ARTI_ARDUINO //for some weird reason this causes a crash on esp32 - RUNLOG_ARTI("%s %s %s.%s = %f (push %u)\n", spaces+50-depth, expression["id"].as(), ar->name, variable_name, varValue, valueStack->stack_index); //key is variable_declaration name is ID - #endif + if (returnValue != doubleNull) { + valueStack->push(returnValue); + RUNLOG_ARTI("%s %s ext.%s = %f (push %u)\n", spaces+50-depth, constructToString(expression["id"]), variable_name, returnValue, valueStack->stack_index); //key is variable_declaration name is ID + } + else + ERROR_ARTI("%s Error: %s ext.%s no value\n", spaces+50-depth, constructToString(expression["id"]), variable_name); } - else { //assign: set the value - ar->set(variable_name, valueStack->popDouble()); // pushed by visit value - valueStack->stack_index = oldIndex; + else { //assign: set the external value... + returnValue = valueStack->popDouble(); //result of interpret value - RUNLOG_ARTI("%s %s.%s%s := %f (pop %u)\n", spaces+50-depth, ar->name, variable_name, indices, ar->getDouble(variable_name), valueStack->stack_index); + arti_set_external_variable(returnValue, variable_external, (valueStack->stack_index - oldIndex>0)?valueStack->doubleStack[oldIndex]:doubleNull, (valueStack->stack_index - oldIndex>1)?valueStack->doubleStack[oldIndex+1]:doubleNull); + + RUNLOG_ARTI("%s %s set ext.%s%s = %f (%u)\n", spaces+50-depth, constructToString(expression["id"]), variable_name, indices, returnValue, valueStack->stack_index); + valueStack->stack_index = oldIndex; } } - else { //unknown variable - ERROR_ARTI("%s %s %s unknown \n", spaces+50-depth, expression["id"].as(), variable_name); - valueStack->push(doubleNull); - } - } // ! founnd - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "Expr") == 0 || strcmp(expression["id"], "Term") == 0) { - // RUNLOG_ARTI("%s %s tovisit %s\n", spaces+50-depth, expression["id"].as(), value.as().c_str()); + else //not external, get er set the variable + { + // Symbol* variable_symbol = current_scope->lookup(variable_name); + ActivationRecord* ar; - uint8_t oldIndex = valueStack->stack_index; + //check already defined in this scope - interpret(value, nullptr, current_scope, depth + 1); //pushes results + // RUNLOG_ARTI("%s levels %u-%u\n", spaces+50-depth, variable_level, variable_index ); + if (variable_level != 0) { //var already exist + //calculate the index in the call stack to find the right ar + uint8_t index = this->callStack->recordsCounter - 1 - (this->callStack->peek()->nesting_level - variable_level); + // RUNLOG_ARTI("%s %s %s.%s = %s (push) %s %d-%d = %d (%d)\n", spaces+50-depth, constructToString(expression["id"]), ar->name, variable_name, varValue, variable_symbol->name, this->callStack->peek()->nesting_level,variable_symbol->scope_level, index, this->callStack->recordsCounter); //key is variable_declaration name is ID + ar = this->callStack->records[index]; + } + else { //var created here + ar = this->callStack->peek(); + } - if (valueStack->stack_index - oldIndex == 3) { - // RUNLOG_ARTI("%s %s visited (%u)\n", spaces+50-depth, expression["id"].as(), valueStack->stack_index - oldIndex); - double left = valueStack->doubleStack[oldIndex]; - const char * operatorx = valueStack->charStack[oldIndex + 1]; - double right = valueStack->doubleStack[oldIndex + 2]; + if (ar != nullptr) { + if (expression["id"].as() == F_VarRef) { //get the value + //determine type, for now assume double + double varValue = ar->getDouble(variable_index); - valueStack->stack_index = oldIndex; - - double evaluation = 0; - if (strcmp(operatorx, "+") == 0) - evaluation = left + right; - else if (strcmp(operatorx, "-") == 0) - evaluation = left - right; - else if (strcmp(operatorx, "*") == 0) - evaluation = left * right; - else if (strcmp(operatorx, "/") == 0) - evaluation = left / right; - else if (strcmp(operatorx, "%") == 0) - evaluation = (int)left % (int)right; //only works on integers - else if (strcmp(operatorx, ">>") == 0) - evaluation = (int)left >> (int)right; //only works on integers - else if (strcmp(operatorx, "<<") == 0) - evaluation = (int)left << (int)right; //only works on integers - else if (strcmp(operatorx, "==") == 0) - evaluation = left == right; - else if (strcmp(operatorx, "!=") == 0) - evaluation = left != right; - else if (strcmp(operatorx, "<") == 0) - evaluation = left < right; - else if (strcmp(operatorx, "<=") == 0) - evaluation = left <= right; - else if (strcmp(operatorx, ">") == 0) - evaluation = left > right; - else if (strcmp(operatorx, ">=") == 0) - evaluation = left >= right; - - RUNLOG_ARTI("%s %f %s %f = %f (push %u)\n", spaces+50-depth, left, operatorx, right, evaluation, valueStack->stack_index+1); - valueStack->push(evaluation); - } + valueStack->push(varValue); + #if ARTI_PLATFORM != ARTI_ARDUINO //for some weird reason this causes a crash on esp32 + RUNLOG_ARTI("%s %s %s.%s = %f (push %u) %u-%u\n", spaces+50-depth, constructToString(expression["id"]), ar->name, variable_name, varValue, valueStack->stack_index, variable_level, variable_index); //key is variable_declaration name is ID + #endif + } + else { //assign: set the value + ar->set(variable_index, valueStack->popDouble()); + valueStack->stack_index = oldIndex; - visitCalledAlready = true; - } - else if (strcmp(expression["id"], "For") == 0) { - RUNLOG_ARTI("%s For (%u)\n", spaces+50-depth, valueStack->stack_index); + RUNLOG_ARTI("%s %s.%s%s := %f (pop %u) %u-%u\n", spaces+50-depth, ar->name, variable_name, indices, ar->getDouble(variable_index), valueStack->stack_index, variable_level, variable_index); + } + } + else { //unknown variable + ERROR_ARTI("%s %s %s unknown \n", spaces+50-depth, constructToString(expression["id"]), variable_name); + valueStack->push(doubleNull); + } + } // ! founnd + interpretAlready = true; + break; + } + case F_Expr: + case F_Term: { + // RUNLOG_ARTI("%s %s interpret < %s\n", spaces+50-depth, constructToString(expression["id"]), value.as().c_str()); - const char * expression_block = expression["block"]; + uint8_t oldIndex = valueStack->stack_index; - RUNLOG_ARTI("%s from\n", spaces+50-depth); - interpret(value, expression["from"], current_scope, depth + 1); //creates the assignment - ActivationRecord* ar = this->callStack->peek(); - const char * fromVarName = ar->lastSet; + interpret(value, nullptr, current_scope, depth + 1); //pushes results - bool continuex = true; - uint16_t counter = 0; - while (continuex && counter < 1000) { //to avoid endless loops - RUNLOG_ARTI("%s iteration\n", spaces+50-depth); + // RUNLOG_ARTI("%s %s interpret > (%u - %u = %u)\n", spaces+50-depth, constructToString(expression["id"]), valueStack->stack_index, oldIndex, valueStack->stack_index - oldIndex); - RUNLOG_ARTI("%s check to condition\n", spaces+50-depth); - interpret(value, expression["condition"], current_scope, depth + 1); //pushes result of to + // always 3, 5, 7 ... values + if (valueStack->stack_index - oldIndex >= 3) + { + double left = valueStack->doubleStack[oldIndex]; + for (int i = 3; i <= valueStack->stack_index - oldIndex; i += 2) + { + uint8_t operatorx = valueStack->doubleStack[oldIndex + i - 2]; + double right = valueStack->doubleStack[oldIndex + i - 1]; + + double evaluation = 0; + + switch (operatorx) { + case F_plus: + evaluation = left + right; + break; + case F_minus: + evaluation = left - right; + break; + case F_multiplication: + evaluation = left * right; + break; + case F_division: + evaluation = left / right; + break; + case F_modulo: + evaluation = (int)left % (int)right; //only works on integers + break; + case F_bitShiftLeft: + evaluation = (int)left << (int)right; //only works on integers + break; + case F_bitShiftRight: + evaluation = (int)left >> (int)right; //only works on integers + break; + case F_equal: + evaluation = left == right; + break; + case F_notEqual: + evaluation = left != right; + break; + case F_lessThen: + evaluation = left < right; + break; + case F_lessThenOrEqual: + evaluation = left <= right; + break; + case F_greaterThen: + evaluation = left > right; + break; + case F_greaterThenOrEqual: + evaluation = left >= right; + break; + default: + ERROR_ARTI("%s Programming error: unknown operator %u\n", spaces+50-depth, operatorx); + } - double conditionResult = valueStack->popDouble(); + RUNLOG_ARTI("%s %f %s %f = %f (push %u)\n", spaces+50-depth, left, operatorToString(operatorx), right, evaluation, valueStack->stack_index+1); - RUNLOG_ARTI("%s conditionResult (pop %u)\n", spaces+50-depth, valueStack->stack_index); + left = evaluation; - if (conditionResult == 1) { //conditionResult is true - RUNLOG_ARTI("%s 1 => run block\n", spaces+50-depth); - interpret(value[expression_block], nullptr, current_scope, depth + 1); + } - RUNLOG_ARTI("%s assign next value\n", spaces+50-depth); - interpret(value[expression["increment"].as()], nullptr, current_scope, depth + 1); //pushes increment result - // MEMORY_ARTI("%s Iteration %u %u\n", spaces+50-depth, counter, esp_get_free_heap_size()); + valueStack->stack_index = oldIndex; + + valueStack->push(left); } - else { - if (conditionResult == 0) { //conditionResult is false - RUNLOG_ARTI("%s 0 => end of For\n", spaces+50-depth); - continuex = false; - } - else { // conditionResult is a value (e.g. in pascal) - //get the variable from assignment - double varValue = ar->getDouble(fromVarName); - double evaluation = varValue <= conditionResult; - RUNLOG_ARTI("%s %s.%s %f <= %f = %f\n", spaces+50-depth, ar->name, fromVarName, varValue, conditionResult, evaluation); + interpretAlready = true; + break; + } + case F_For: { + RUNLOG_ARTI("%s For (%u)\n", spaces+50-depth, valueStack->stack_index); - if (evaluation == 1) { - RUNLOG_ARTI("%s 1 => run block\n", spaces+50-depth); - interpret(value[expression_block], nullptr, current_scope, depth + 1); + const char * expression_block = expression["block"]; - //increment - ar->set(fromVarName, varValue + 1); - } - else { + RUNLOG_ARTI("%s from\n", spaces+50-depth); + interpret(value, expression["from"], current_scope, depth + 1); //creates the assignment + ActivationRecord* ar = this->callStack->peek(); + + bool continuex = true; + uint16_t counter = 0; + while (continuex && counter < 1000) { //to avoid endless loops + RUNLOG_ARTI("%s iteration\n", spaces+50-depth); + + RUNLOG_ARTI("%s check to condition\n", spaces+50-depth); + interpret(value, expression["condition"], current_scope, depth + 1); //pushes result of to + + double conditionResult = valueStack->popDouble(); + + RUNLOG_ARTI("%s conditionResult (pop %u)\n", spaces+50-depth, valueStack->stack_index); + + if (conditionResult == 1) { //conditionResult is true + RUNLOG_ARTI("%s 1 => run block\n", spaces+50-depth); + interpret(value[expression_block], nullptr, current_scope, depth + 1); + + RUNLOG_ARTI("%s assign next value\n", spaces+50-depth); + interpret(value[expression["increment"].as()], nullptr, current_scope, depth + 1); //pushes increment result + // MEMORY_ARTI("%s Iteration %u %u\n", spaces+50-depth, counter, FREE_SIZE); + } + else + { + if (conditionResult == 0) { //conditionResult is false RUNLOG_ARTI("%s 0 => end of For\n", spaces+50-depth); continuex = false; } + else // conditionResult is a value (e.g. in pascal) + { + //get the variable from assignment + double varValue = ar->getDouble(ar->lastSetIndex); + + double evaluation = varValue <= conditionResult; + RUNLOG_ARTI("%s %s.(%u) %f <= %f = %f\n", spaces+50-depth, ar->name, ar->lastSetIndex, varValue, conditionResult, evaluation); + + if (evaluation == 1) + { + RUNLOG_ARTI("%s 1 => run block\n", spaces+50-depth); + interpret(value[expression_block], nullptr, current_scope, depth + 1); + + //increment + ar->set(ar->lastSetIndex, varValue + 1); + } + else + { + RUNLOG_ARTI("%s 0 => end of For\n", spaces+50-depth); + continuex = false; + } + } } - } - counter++; - }; + counter++; + }; - if (continuex) - ERROR_ARTI("%s too many iterations in for loop %u\n", spaces+50-depth, counter); + if (continuex) + ERROR_ARTI("%s too many iterations in for loop %u\n", spaces+50-depth, counter); - visitCalledAlready = true; - } //if expression["id"] - else if (strcmp(expression["id"], "If") == 0) { - RUNLOG_ARTI("%s If (%u)\n", spaces+50-depth, valueStack->stack_index); + interpretAlready = true; + break; + } // case + case F_If: { + RUNLOG_ARTI("%s If (%u)\n", spaces+50-depth, valueStack->stack_index); - RUNLOG_ARTI("%s if condition\n", spaces+50-depth); - interpret(value, expression["condition"], current_scope, depth + 1); + RUNLOG_ARTI("%s if condition\n", spaces+50-depth); + interpret(value, expression["condition"], current_scope, depth + 1); - double conditionResult = valueStack->popDouble(); + double conditionResult = valueStack->popDouble(); - RUNLOG_ARTI("%s (pop %u)\n", spaces+50-depth, valueStack->stack_index); + RUNLOG_ARTI("%s (pop %u)\n", spaces+50-depth, valueStack->stack_index); - if (conditionResult == 1) //conditionResult is true - interpret(value, expression["true"], current_scope, depth + 1); - else - interpret(value, expression["false"], current_scope, depth + 1); + if (conditionResult == 1) //conditionResult is true + interpret(value, expression["true"], current_scope, depth + 1); + else + interpret(value, expression["false"], current_scope, depth + 1); - visitCalledAlready = true; - } //if expression["id"] + interpretAlready = true; + break; + } // case + } - // MEMORY_ARTI("%s Heap %s > %u\n", spaces+50-depth, expression_id, esp_get_free_heap_size()); + // MEMORY_ARTI("%s Heap %s > %u\n", spaces+50-depth, expression_id, FREE_SIZE); } //if expression not null } // is key is symbol_name - const char * valueStr = value.as().c_str(); - - if (strcmp(key, "INTEGER_CONST") == 0 || strcmp(key, "REAL_CONST") == 0) { - valueStack->push(atof(valueStr)); - #if ARTI_PLATFORM != ARTI_ARDUINO //for some weird reason this causes a crash on esp32 - RUNLOG_ARTI("%s %s %s (Push %u)\n", spaces+50-depth, key, valueStr, valueStack->stack_index); - #endif - visitCalledAlready = true; - } + else if (!definitionJson["TOKENS"][key].isNull()) //if key is token + { + // RUNLOG_ARTI("%s Token %s %s %s\n", spaces+50-depth, key, valueStr, parseTree.as().c_str()); - // RUNLOG_ARTI("%s\n", spaces+50-depth, "Object ", key, value); - if (strcmp(valueStr, "+") == 0 || strcmp(valueStr, "-") == 0 || strcmp(valueStr, "*") == 0 || strcmp(valueStr, "/") == 0 || strcmp(valueStr, "%") == 0 || - strcmp(valueStr, "<<") == 0 || strcmp(valueStr, ">>") == 0 || - strcmp(valueStr, "==") == 0 || strcmp(valueStr, "!=") == 0 || - strcmp(valueStr, ">") == 0 || strcmp(valueStr, ">=") == 0 || strcmp(valueStr, "<") == 0 || strcmp(valueStr, "<=") == 0) { - valueStack->push(valueStr); - #if ARTI_PLATFORM != ARTI_ARDUINO //for some weird reason this causes a crash on esp32 - RUNLOG_ARTI("%s %s %s (Push %u)\n", spaces+50-depth, key, valueStr, valueStack->stack_index); - #endif - visitCalledAlready = true; - } + if (!parseTree["operator"].isNull()) + { + const char * valueStr = value.as().c_str(); + + switch (parseTree["operator"].as()) { + case F_integerConstant: + case F_realConstant: + valueStack->push(atof(valueStr)); //push value + #if ARTI_PLATFORM != ARTI_ARDUINO //for some weird reason this causes a crash on esp32 + RUNLOG_ARTI("%s %s %s (Push %u)\n", spaces+50-depth, key, valueStr, valueStack->stack_index); + #endif + break; + default: + valueStack->push(parseTree["operator"].as()); // push Operator index + #if ARTI_PLATFORM != ARTI_ARDUINO //for some weird reason this causes a crash on esp32 + RUNLOG_ARTI("%s %s %s (Push %u)\n", spaces+50-depth, key, valueStr, valueStack->stack_index); + #endif + } + } - if (!definitionJson["TOKENS"][key].isNull()) { //if key is token - // RUNLOG_ARTI("%s Token %s\n", spaces+50-depth, key); - visitCalledAlready = true; + interpretAlready = true; } - if (!visitCalledAlready) + if (!interpretAlready) interpret(value, nullptr, current_scope, depth + 1); } // if treeelement } // for (JsonPair) @@ -1968,330 +1941,264 @@ class ARTI { return true; } //interpret - bool setup(const char *definitionName, const char *programName) { - MEMORY_ARTI("Heap Setup < %u (%lums) %s %s\n", esp_get_free_heap_size(), millis(), definitionName, programName); - bool loadParseTreeFile = false; - - //open logFile - #if ARTI_OUTPUT == ARTI_FILE - char logFileName[fileNameLength]; - #if ARTI_PLATFORM == ARTI_ARDUINO - strcpy(logFileName, "/"); - #endif - strcpy(logFileName, programName); - strcat(logFileName, ".log"); + bool setup(const char *definitionName, const char *programName) + { + //open logFile + #if ARTI_OUTPUT == ARTI_FILE + char logFileName[fileNameLength]; + #if ARTI_PLATFORM == ARTI_ARDUINO + strcpy(logFileName, "/"); + #endif + strcpy(logFileName, programName); + strcat(logFileName, ".log"); - #if ARTI_PLATFORM == ARTI_ARDUINO - #if ARTI_DEFINITION == ARTI_WLED - logFile = WLED_FS.open(logFileName,"w"); - #else - logFile = FS.open(logFileName,"w"); - #endif - #else - logFile = fopen (logFileName,"w"); - #endif + #if ARTI_PLATFORM == ARTI_ARDUINO + logFile = LITTLEFS.open(logFileName,"w"); + #else + logFile = fopen (logFileName,"w"); #endif + #endif + + MEMORY_ARTI("Heap Setup < %u (%lums) %s %s\n", FREE_SIZE, CURRENT_MILLIS, definitionName, programName); + + if (stages < 1) {close(); return true;} + bool loadParseTreeFile = false; + #if ARTI_PLATFORM == ARTI_ARDUINO + File definitionFile; + definitionFile = LITTLEFS.open(definitionName, "r"); + #else + std::fstream definitionFile; + definitionFile.open(definitionName, std::ios::in); + #endif + + MEMORY_ARTI("Heap open definition file > %u\n", FREE_SIZE); + + if (!definitionFile) { + ERROR_ARTI("Definition file %s not found\n", definitionName); + return false; + } + else + { + + //open definitionFile #if ARTI_PLATFORM == ARTI_ARDUINO - File definitionFile; - #if ARTI_DEFINITION == ARTI_WLED - definitionFile = WLED_FS.open(definitionName, "r"); - #else - definitionFile = FS.open(definitionName, "r"); - #endif + definitionJsonDoc = new DynamicJsonDocument(8192); //currently 5335 #else - std::fstream definitionFile; - definitionFile.open(definitionName, std::ios::in); + definitionJsonDoc = new DynamicJsonDocument(16384); //currently 9521 #endif - // DEBUG_ARTI("def size %lu\n", definitionFile.tellg()); - MEMORY_ARTI("Heap open definition file > %u\n", esp_get_free_heap_size()); + // mandatory tokens: + // "ID": "ID", + // "INTEGER_CONST": "INTEGER_CONST", + // "REAL_CONST": "REAL_CONST", + + MEMORY_ARTI("Heap definitionJsonDoc %u > %u (%lums)\n", definitionJsonDoc->capacity(), FREE_SIZE, CURRENT_MILLIS); - if (!definitionFile) { - ERROR_ARTI("Definition file %s not found\n", definitionName); + DeserializationError err = deserializeJson(*definitionJsonDoc, definitionFile); + if (err) { + ERROR_ARTI("deserializeJson() of definition failed with code %s\n", err.c_str()); return false; } + definitionFile.close(); + definitionJson = definitionJsonDoc->as(); + + JsonObject::iterator objectIterator = definitionJson.begin(); + JsonObject metaData = objectIterator->value(); + const char * version = metaData["version"]; + if (strcmp(version, "0.1.0") < 0) { + ERROR_ARTI("Version of definition.json file (%s) should be 0.1.0 or higher\n", version); + return false; + } + const char * startSymbol = metaData["start"]; + if (startSymbol == nullptr) { + ERROR_ARTI("Setup Error: No start symbol found in definition file\n"); + return false; + } + + #if ARTI_PLATFORM == ARTI_ARDUINO + File programFile; + programFile = LITTLEFS.open(programName, "r"); + #else + std::fstream programFile; + programFile.open(programName, std::ios::in); + #endif + if (!programFile) { + ERROR_ARTI("Program file %s not found\n", programName); + return false; + } else { - //open definitionFile - definitionJsonDoc = new DynamicJsonDocument(12192); - - // mandatory tokens: - // "ID": "ID", - // "INTEGER_CONST": "INTEGER_CONST", - // "REAL_CONST": "REAL_CONST", - - - DeserializationError err = deserializeJson(*definitionJsonDoc, definitionFile); - if (err) { - ERROR_ARTI("deserializeJson() of definition failed with code %s\n", err.c_str()); - return false; - } - definitionFile.close(); - definitionJson = definitionJsonDoc->as(); - - JsonObject::iterator objectIterator = definitionJson.begin(); - JsonObject metaData = objectIterator->value(); - const char * version = metaData["version"]; - if (strcmp(version, "0.0.6") < 0) { - ERROR_ARTI("Version of definition.json file (%s) should be 0.0.6 or higher\n", version); - return false; - } - const char * startSymbol = metaData["start"]; - if (startSymbol == nullptr) { - ERROR_ARTI("Parser Error: No start symbol found in definition file\n"); - return false; - } + //open programFile + char * programText; + uint16_t programFileSize; + #if ARTI_PLATFORM == ARTI_ARDUINO + programFileSize = programFile.size(); + programText = (char *)malloc(programFileSize+1); + programFile.read((byte *)programText, programFileSize); + programText[programFileSize] = '\0'; + #else + programText = (char *)malloc(programTextSize); + programFile.read(programText, programTextSize); + DEBUG_ARTI("programFile size %u bytes\n", programFile.gcount()); + programText[programFile.gcount()] = '\0'; + programFileSize = strlen(programText); + #endif + programFile.close(); + char parseTreeName[fileNameLength]; + strcpy(parseTreeName, programName); + // if (loadParseTreeFile) + // strcpy(parseTreeName, "Gen"); + strcat(parseTreeName, ".json"); #if ARTI_PLATFORM == ARTI_ARDUINO - File programFile; - #if ARTI_DEFINITION == ARTI_WLED - programFile = WLED_FS.open(programName, "r"); - #else - programFile = FS.open(programName, "r"); - #endif + parseTreeJsonDoc = new DynamicJsonDocument(16384); // current largest (Subpixel) 5624 //strlen(programText) * 50); //less memory on arduino: 32 vs 64 bit? #else - std::fstream programFile; - programFile.open(programName, std::ios::in); + parseTreeJsonDoc = new DynamicJsonDocument(32768); // current largest (Subpixel) 7926 //strlen(programText) * 100 #endif - if (!programFile) { - ERROR_ARTI("Program file %s not found\n", programName); - return false; - } - else - { - //open programFile - char * programText; - uint16_t programFileSize; - #if ARTI_PLATFORM == ARTI_ARDUINO - programFileSize = programFile.size(); - programText = (char *)malloc(programFileSize+1); - programFile.read((byte *)programText, programFileSize); - programText[programFileSize] = '\0'; - #else - programText = (char *)malloc(programFile.gcount()+1); - programFile.read(programText, programTextSize); //sizeof programText - programText[programFile.gcount()] = '\0'; - programFileSize = strlen(programText); - #endif - programFile.close(); - char parseTreeName[fileNameLength]; - strcpy(parseTreeName, programName); - // if (loadParseTreeFile) - // strcpy(parseTreeName, "Gen"); - strcat(parseTreeName, ".json"); + MEMORY_ARTI("Heap parseTreeJsonDoc %u > %u (%lums)\n", parseTreeJsonDoc->capacity(), FREE_SIZE, CURRENT_MILLIS); + + //parse + + #ifdef ARTI_DEBUG // only read write file if debug is on #if ARTI_PLATFORM == ARTI_ARDUINO - parseTreeJsonDoc = new DynamicJsonDocument(strlen(programText) * 50); //less memory on arduino: 32 vs 64 bit? + File parseTreeFile; + parseTreeFile = LITTLEFS.open(parseTreeName, loadParseTreeFile?"r":"w"); #else - parseTreeJsonDoc = new DynamicJsonDocument(strlen(programText) * 100); + std::fstream parseTreeFile; + parseTreeFile.open(parseTreeName, loadParseTreeFile?std::ios::in:std::ios::out); #endif + #endif - MEMORY_ARTI("Heap DynamicJsonDocuments > %u (%lums)\n", esp_get_free_heap_size(), millis()); - - //parse - - #ifdef ARTI_DEBUG // only read write file if debug is on - #if ARTI_PLATFORM == ARTI_ARDUINO - // File parseTreeFile; - #if ARTI_DEFINITION == ARTI_WLED - parseTreeFile = WLED_FS.open(parseTreeName, loadParseTreeFile?"r":"w"); - #else - parseTreeFile = FS.open(parseTreeName, loadParseTreeFile?"r":"w"); - #endif - #else - std::fstream parseTreeFile; - parseTreeFile.open(parseTreeName, loadParseTreeFile?std::ios::in:std::ios::out); - #endif - #endif + if (stages < 1) {close(); return true;} - if (!loadParseTreeFile) { - parseTreeJson = parseTreeJsonDoc->as(); + if (!loadParseTreeFile) { + parseTreeJson = parseTreeJsonDoc->as(); - lexer = new Lexer(programText, definitionJson); - lexer->get_next_token(); + lexer = new Lexer(programText, definitionJson); + lexer->get_next_token(); - uint8_t result = parse(parseTreeJson, startSymbol, '&', lexer->definitionJson[startSymbol], 0); + if (stages < 2) {close(); return true;} - if (this->lexer->pos != strlen(this->lexer->text)) { - ERROR_ARTI("Symbol %s Program not entirely parsed (%u,%u) %u of %u\n", startSymbol, this->lexer->lineno, this->lexer->column, this->lexer->pos, strlen(this->lexer->text)); - return false; - } - else if (result == ResultFail) { - ERROR_ARTI("Symbol %s Program parsing failed (%u,%u) %u of %u\n", startSymbol, this->lexer->lineno, this->lexer->column, this->lexer->pos, strlen(this->lexer->text)); - return false; - } - else - DEBUG_ARTI("Symbol %s Parsed until (%u,%u) %u of %u\n", startSymbol, this->lexer->lineno, this->lexer->column, this->lexer->pos, strlen(this->lexer->text)); - - DEBUG_ARTI("par mem %u of %u %u %u %u %u\n", parseTreeJsonDoc->memoryUsage(), parseTreeJsonDoc->capacity(), parseTreeJsonDoc->memoryPool().capacity(), parseTreeJsonDoc->size(), parseTreeJsonDoc->overflowed(), parseTreeJsonDoc->nesting()); - DEBUG_ARTI("prog size %u factor %u\n", programFileSize, parseTreeJsonDoc->memoryUsage() / programFileSize); - parseTreeJsonDoc->garbageCollect(); - DEBUG_ARTI("par mem %u of %u %u %u %u %u\n", parseTreeJsonDoc->memoryUsage(), parseTreeJsonDoc->capacity(), parseTreeJsonDoc->memoryPool().capacity(), parseTreeJsonDoc->size(), parseTreeJsonDoc->overflowed(), parseTreeJsonDoc->nesting()); - //199 -> 6905 (34.69) - //469 -> 15923 (33.95) + uint8_t result = parse(parseTreeJson, startSymbol, '&', lexer->definitionJson[startSymbol], 0); - delete lexer; lexer = nullptr; - } - else - { - // read parseTree - #ifdef ARTI_DEBUG // only write file if debug is on - DeserializationError err = deserializeJson(*parseTreeJsonDoc, parseTreeFile); - if (err) { - ERROR_ARTI("deserializeJson() of parseTree failed with code %s\n", err.c_str()); - return false; - } - #endif + if (this->lexer->pos != strlen(this->lexer->text)) { + ERROR_ARTI("Symbol %s Program not entirely parsed (%u,%u) %u of %u\n", startSymbol, this->lexer->lineno, this->lexer->column, this->lexer->pos, strlen(this->lexer->text)); + return false; } - #if ARTI_PLATFORM == ARTI_ARDUINO //not on windows as cause crash??? - free(programText); - #endif - - MEMORY_ARTI("Heap parse > %u (%lums)\n", esp_get_free_heap_size(), millis()); - - ANDBG_ARTI("\nAnalyzer\n"); - if (!analyze(parseTreeJson)) { - ERROR_ARTI("Analyze failed\n"); + else if (result == ResultFail) { + ERROR_ARTI("Symbol %s Program parsing failed (%u,%u) %u of %u\n", startSymbol, this->lexer->lineno, this->lexer->column, this->lexer->pos, strlen(this->lexer->text)); return false; } + else + DEBUG_ARTI("Symbol %s Parsed until (%u,%u) %u of %u\n", startSymbol, this->lexer->lineno, this->lexer->column, this->lexer->pos, strlen(this->lexer->text)); - MEMORY_ARTI("Heap analyze > %u (%lums)\n", esp_get_free_heap_size(), millis()); - - // if (!optimize(parseTreeJson)) { - // ERROR_ARTI("Optimize failed\n"); - // return false; - // } - - // MEMORY_ARTI("Heap optimize > %u (%lums)\n", esp_get_free_heap_size(), millis()); + MEMORY_ARTI("definitionJson usage %u of %u (%0.f %%) (%u %u %u)\n", definitionJsonDoc->memoryUsage(), definitionJsonDoc->capacity(), 100.0 * definitionJsonDoc->memoryUsage() / definitionJsonDoc->capacity(), definitionJsonDoc->size(), definitionJsonDoc->overflowed(), definitionJsonDoc->nesting()); + MEMORY_ARTI("parseTree usage %u of %u (%0.f %%) (%u %u %u)\n", parseTreeJsonDoc->memoryUsage(), parseTreeJsonDoc->capacity(), 100.0 * parseTreeJsonDoc->memoryUsage() / parseTreeJsonDoc->capacity(), parseTreeJsonDoc->size(), parseTreeJsonDoc->overflowed(), parseTreeJsonDoc->nesting()); + parseTreeJsonDoc->garbageCollect(); + MEMORY_ARTI("garbageCollect %u of %u (%0.f %%) (%u %u %u)\n", parseTreeJsonDoc->memoryUsage(), parseTreeJsonDoc->capacity(), 100.0 * parseTreeJsonDoc->memoryUsage() / parseTreeJsonDoc->capacity(), parseTreeJsonDoc->size(), parseTreeJsonDoc->overflowed(), parseTreeJsonDoc->nesting()); + //199 -> 6905 (34.69) + //469 -> 15923 (33.95) + delete lexer; lexer = nullptr; + } + else + { + // read parseTree #ifdef ARTI_DEBUG // only write file if debug is on - //write parseTree - if (!loadParseTreeFile) - serializeJsonPretty(*parseTreeJsonDoc, parseTreeFile); - parseTreeFile.close(); - #endif - - //interpret main - callStack = new CallStack(); - valueStack = new ValueStack(); - - if (global_scope != nullptr) { //due to undefined functions??? wip - RUNLOG_ARTI("\ninterpret %s %u %u\n", global_scope->scope_name, global_scope->scope_level, global_scope->symbolsIndex); - if (!interpret(parseTreeJson)) { - ERROR_ARTI("Interpret main failed\n"); + DeserializationError err = deserializeJson(*parseTreeJsonDoc, parseTreeFile); + if (err) { + ERROR_ARTI("deserializeJson() of parseTree failed with code %s\n", err.c_str()); return false; } - } - else - { - ERROR_ARTI("\nInterpret global scope is nullptr\n"); - return false; - } - - - //flush does not seem to work... further testing needed - #if ARTI_OUTPUT == ARTI_FILE - #if ARTI_PLATFORM == ARTI_ARDUINO - logFile.flush(); - #else - fflush(logFile); - #endif #endif + } + #if ARTI_PLATFORM == ARTI_ARDUINO //not on windows as cause crash??? + free(programText); + #endif - MEMORY_ARTI("Heap Interpret main > %u (%lums)\n", esp_get_free_heap_size(), millis()); - - } //programFile - } //definitionFilee - return true; - } // setup - - bool loop() { - if (parseTreeJsonDoc == nullptr || parseTreeJsonDoc->isNull()) { - ERROR_ARTI("Loop: No parsetree created\n"); - return false; - } - else { - uint8_t depth = 8; - - //tbd: move wled specific functions to arti_wled_plugin (ARTI wled class extension??) - - bool foundRenderFunction = false; - - const char * function_name = "renderFrame"; - Symbol* function_symbol = global_scope->lookup(function_name); - - ledsSet = false; - - if (function_symbol != nullptr) { //calling undefined function: pre-defined functions e.g. print - - foundRenderFunction = true; - - ActivationRecord* ar = new ActivationRecord(function_name, "Function", function_symbol->scope_level + 1); + MEMORY_ARTI("Heap parse > %u (%lums)\n", FREE_SIZE, CURRENT_MILLIS); - RUNLOG_ARTI("%s %s %s (%u)\n", spaces+50-depth, "Call", function_name, this->callStack->recordsCounter); + if (stages < 3) {close(); return true;} - this->callStack->push(ar); + ANDBG_ARTI("\nOptimizer\n"); + if (!optimize(parseTreeJson)) { + ERROR_ARTI("Optimize failed\n"); + return false; + } - interpret(function_symbol->block, nullptr, global_scope, depth + 1); + MEMORY_ARTI("Heap optimize > %u (%lums)\n", FREE_SIZE, CURRENT_MILLIS); - this->callStack->pop(); + if (stages < 4) {close(); return true;} - delete ar; ar = nullptr; + ANDBG_ARTI("\nAnalyzer\n"); + if (!analyze(parseTreeJson)) { + ERROR_ARTI("Analyze failed\n"); + return false; + } - } //function_symbol != nullptr + MEMORY_ARTI("Heap analyze > %u (%lums)\n", FREE_SIZE, CURRENT_MILLIS); - function_name = "renderLed"; - function_symbol = global_scope->lookup(function_name); + #ifdef ARTI_DEBUG // only write file if debug is on + //write parseTree + if (!loadParseTreeFile) + serializeJsonPretty(*parseTreeJsonDoc, parseTreeFile); + parseTreeFile.close(); + #endif - if (function_symbol != nullptr) { //calling undefined function: pre-defined functions e.g. print + if (stages < 5) {close(); return true;} - foundRenderFunction = true; + //interpret main + callStack = new CallStack(); + valueStack = new ValueStack(); - ActivationRecord* ar = new ActivationRecord(function_name, "function", function_symbol->scope_level + 1); + if (global_scope != nullptr) //due to undefined functions??? wip + { + RUNLOG_ARTI("\ninterpret %s %u %u\n", global_scope->scope_name, global_scope->scope_level, global_scope->symbolsIndex); - for (int i = 0; i< arti_get_external_variable(F_ledCount); i++) + if (!interpret(parseTreeJson)) { + ERROR_ARTI("Interpret main failed\n"); + return false; + } + } + else { - ar->set(function_symbol->function_scope->symbols[0]->name, i); // set ledIndex to count value - - this->callStack->push(ar); - - interpret(function_symbol->block, nullptr, global_scope, depth + 1); - - this->callStack->pop(); - + ERROR_ARTI("\nInterpret global scope is nullptr\n"); + return false; } - delete ar; ar = nullptr; + //flush does not seem to work... further testing needed + #if ARTI_OUTPUT == ARTI_FILE + #if ARTI_PLATFORM == ARTI_ARDUINO + logFile.flush(); + #else + fflush(logFile); + #endif + #endif - } + MEMORY_ARTI("Heap Interpret main > %u (%lums)\n", FREE_SIZE, CURRENT_MILLIS); - // if leds has been set during interpret(renderLed) - if (ledsSet) - arti_external_function(F_setPixels); + } //programFile + } //definitionFilee - if (!foundRenderFunction) { - ERROR_ARTI("%s renderFrame or renderLed not found\n", spaces+50-depth); - return false; - } - } return true; - } // loop + } // setup void close() { - MEMORY_ARTI("Heap close Arti < %u\n", esp_get_free_heap_size()); + MEMORY_ARTI("Heap close Arti < %u\n", FREE_SIZE); if (callStack != nullptr) {delete callStack; callStack = nullptr;} if (valueStack != nullptr) {delete valueStack; valueStack = nullptr;} if (global_scope != nullptr) {delete global_scope; global_scope = nullptr;} if (definitionJsonDoc != nullptr) { - DEBUG_ARTI("def mem %u of %u %u %u %u %u\n", definitionJsonDoc->memoryUsage(), definitionJsonDoc->capacity(), definitionJsonDoc->memoryPool().capacity(), definitionJsonDoc->size(), definitionJsonDoc->overflowed(), definitionJsonDoc->nesting()); + MEMORY_ARTI("definitionJson usage %u of %u (%0.f %%) (%u %u %u)\n", definitionJsonDoc->memoryUsage(), definitionJsonDoc->capacity(), 100.0 * definitionJsonDoc->memoryUsage() / definitionJsonDoc->capacity(), definitionJsonDoc->size(), definitionJsonDoc->overflowed(), definitionJsonDoc->nesting()); delete definitionJsonDoc; definitionJsonDoc = nullptr; } if (parseTreeJsonDoc != nullptr) { - DEBUG_ARTI("par mem %u of %u %u %u %u %u\n", parseTreeJsonDoc->memoryUsage(), parseTreeJsonDoc->capacity(), parseTreeJsonDoc->memoryPool().capacity(), parseTreeJsonDoc->size(), parseTreeJsonDoc->overflowed(), parseTreeJsonDoc->nesting()); + MEMORY_ARTI("parseTree usage %u of %u (%0.f %%) (%u %u %u)\n", parseTreeJsonDoc->memoryUsage(), parseTreeJsonDoc->capacity(), 100.0 * parseTreeJsonDoc->memoryUsage() / parseTreeJsonDoc->capacity(), parseTreeJsonDoc->size(), parseTreeJsonDoc->overflowed(), parseTreeJsonDoc->nesting()); delete parseTreeJsonDoc; parseTreeJsonDoc = nullptr; } @@ -2303,7 +2210,7 @@ class ARTI { #endif #endif - MEMORY_ARTI("Heap close Arti> %u (%lums)\n", esp_get_free_heap_size(), millis()); + MEMORY_ARTI("Heap close Arti> %u (%lums)\n", FREE_SIZE, CURRENT_MILLIS); } }; //ARTI \ No newline at end of file diff --git a/wled00/src/dependencies/arti/arti_wled.h b/wled00/src/dependencies/arti/arti_wled.h new file mode 100644 index 0000000000..68c27bbecb --- /dev/null +++ b/wled00/src/dependencies/arti/arti_wled.h @@ -0,0 +1,597 @@ +/* + @title Arduino Real Time Interpreter (ARTI) + @file arti_wled_plugin.h + @version 0.1.0 + @date 20211120 + @author Ewoud Wijma + @repo https://github.com/ewoudwijma/ARTI + */ + +#pragma once + +// For testing porposes, definitions should not only run on Arduino but also on Windows etc. +// Because compiling on arduino takes seriously more time than on Windows. +// The plugin.h files replace native arduino calls by windows simulated calls (e.g. setPixelColor will become printf) + +#define ARTI_ARDUINO 1 +#define ARTI_EMBEDDED 2 +#ifdef ESP32 //ESP32 is set in wled context: small trick to set WLED context + #define ARTI_PLATFORM ARTI_ARDUINO // else on Windows/Linux/Mac... +#endif + +#if ARTI_PLATFORM == ARTI_ARDUINO + #include "arti.h" + #include "FX.h" + extern float sampleAvg; +#else + #include "..\arti.h" + #include + #include + #include + #include +#endif + +//make sure the numbers here correspond to the order in which these functions are defined in wled.json!! +enum Externals +{ + F_ledCount, + F_setPixelColor, + F_leds, + F_setPixels, + F_hsv, + + F_setRange, + F_fill, + F_colorBlend, + F_colorWheel, + F_colorFromPalette, + F_beatSin, + F_fadeToBlackBy, + + F_segcolor, + F_speedSlider, + F_intensitySlider, + F_custom1Slider, + F_custom2Slider, + F_custom3Slider, + F_sampleAvg, + + F_shift, + F_circle2D, + + F_constrain, + F_random, + F_sin, + F_cos, + F_abs, + F_min, + F_max, + + F_hour, + F_minute, + F_second, + F_millis, + + F_printf +}; + +#if ARTI_PLATFORM != ARTI_ARDUINO + class WS2812FX { + public: + uint16_t matrixWidth = 16, matrixHeight = 16; + + uint16_t XY(uint16_t x, uint16_t y) { // ewowi20210703: new XY: segmentToReal: Maps XY in 2D segment to to rotated and mirrored logical index. Works for 1D strips and 2D panels + return x%matrixWidth + y%matrixHeight * matrixWidth; + } + + double arti_external_function(uint8_t function, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull, double par4 = doubleNull, double par5 = doubleNull); + double arti_get_external_variable(uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); + void arti_set_external_variable(double value, uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); + }; //class WS2812FX + + WS2812FX strip = WS2812FX(); + +#endif + +double ARTI::arti_external_function(uint8_t function, double par1, double par2, double par3, double par4, double par5) +{ + return strip.arti_external_function(function, par1, par2, par3, par4, par5); +} + +double ARTI::arti_get_external_variable(uint8_t variable, double par1, double par2, double par3) +{ + return strip.arti_get_external_variable(variable, par1, par2, par3); +} + +void ARTI::arti_set_external_variable(double value, uint8_t variable, double par1, double par2, double par3) +{ + strip.arti_set_external_variable(value, variable, par1, par2, par3); +} + +double WS2812FX::arti_external_function(uint8_t function, double par1, double par2, double par3, double par4, double par5) { + // MEMORY_ARTI("fun %d(%f, %f, %f)\n", function, par1, par2, par3); + #if ARTI_PLATFORM == ARTI_ARDUINO + switch (function) { + case F_setPixelColor: { + if (par2 == 0) + setPixelColor(((uint16_t)par1)%ledCount, CRGB::Black); + else + setPixelColor(((uint16_t)par1)%ledCount, color_from_palette(((uint8_t)par2)%256, true, (paletteBlend == 1 || paletteBlend == 3), 0)); + return doubleNull; + } + case F_setPixels: + setPixels(leds); + return doubleNull; + case F_hsv: + return crgb_to_col(CHSV(par1, par2, par3)); + + case F_setRange: { + setRange((uint16_t)par1, (uint16_t)par2, (uint32_t)par3); + return doubleNull; + case F_fill: { + fill((uint32_t)par1); + return doubleNull; + } + case F_colorBlend: + return color_blend((uint32_t)par1, (uint32_t)par2, (uint16_t)par3); + case F_colorWheel: + return color_wheel((uint8_t)par1); + case F_colorFromPalette: + return crgb_to_col(ColorFromPalette(currentPalette, (uint8_t)par1, (uint8_t)par2, LINEARBLEND)); + case F_beatSin: + return beatsin8((uint8_t)par1, (uint8_t)par2, (uint8_t)par3, (uint8_t)par4, (uint8_t)par5); + case F_fadeToBlackBy: + fadeToBlackBy(leds, (uint8_t)par1); + return doubleNull; + + case F_segcolor: + return SEGCOLOR((uint8_t)par1); + + case F_shift: { + uint32_t saveFirstPixel = getPixelColor(0); + for (uint16_t i=0; i3.5->4) + int x = round(round((sin(radians(par1)) * halfLength + halfLength) * 10)/10) + deltaWidth; + int y = round(round((halfLength - cos(radians(par1)) * halfLength) * 10)/10) + deltaHeight; + return strip.XY(x,y); + } + + case F_constrain: + return constrain(par1, par2, par3); + case F_random: + return random16(); + + case F_millis: + return millis(); + } + default: {} + } + #else + switch (function) + { + case F_setPixelColor: + PRINT_ARTI("%s(%f, %f)\n", "setPixelColor", par1, par2); + return doubleNull; + case F_setPixels: + PRINT_ARTI("%s(%f)\n", "setPixels", par1); + return doubleNull; + case F_hsv: + PRINT_ARTI("%s(%f, %f, %f)\n", "hsv", par1, par2, par3); + return par1 + par2 + par3; + + case F_setRange: + return par1 + par2 + par3; + case F_fill: + PRINT_ARTI("%s(%f)\n", "fill", par1); + return doubleNull; + case F_colorBlend: + return par1 + par2 + par3; + case F_colorWheel: + return par1; + case F_colorFromPalette: + return par1 + par2; + case F_beatSin: + return par1+par2+par3+par4+par5; + case F_fadeToBlackBy: + return par1; + + case F_segcolor: + return par1; + + case F_shift: + PRINT_ARTI("%s(%f)\n", "shift", par1); + return doubleNull; + case F_circle2D: + PRINT_ARTI("%s(%f)\n", "circle2D", par1); + return par1 / 2; + + case F_constrain: + return par1 + par2 + par3; + case F_random: + return rand(); + + case F_millis: + return 1000; + } + #endif + + //same on Arduino or Windows + switch (function) + { + case F_sin: + return sin(par1); + case F_cos: + return cos(par1); + case F_abs: + return abs(par1); + case F_min: + return fmin(par1, par2); + case F_max: + return fmax(par1, par2); + + case F_printf: { + if (par3 == doubleNull) { + if (par2 == doubleNull) { + PRINT_ARTI("%s(%f)\n", "printf1", par1); + } + else + PRINT_ARTI("%s(%f, %f)\n", "printf2", par1, par2); + } + else + PRINT_ARTI("%s(%f, %f, %f)\n", "printf3", par1, par2, par3); + return doubleNull; + } + } + + ERROR_ARTI("Error: arti_external_function: %u not implemented\n", function); + return function; +} + +double WS2812FX::arti_get_external_variable(uint8_t variable, double par1, double par2, double par3) { + // MEMORY_ARTI("get %d(%f, %f, %f)\n", variable, par1, par2, par3); + #if ARTI_PLATFORM == ARTI_ARDUINO + switch (variable) + { + case F_ledCount: + return SEGLEN; + case F_leds: + if (par1 == doubleNull) { + ERROR_ARTI("arti_get_external_variable leds without indices not supported yet (get leds)\n"); + return doubleNull; + } + else if (par2 == doubleNull) + return leds[(uint16_t)par1]; + else + return leds[XY((uint16_t)par1, (uint16_t)par2)]; //2D value!! + + case F_speedSlider: + return SEGMENT.speed; + case F_intensitySlider: + return SEGMENT.intensity; + case F_custom1Slider: + return SEGMENT.fft1; + case F_custom2Slider: + return SEGMENT.fft2; + case F_custom3Slider: + return SEGMENT.fft3; + case F_sampleAvg: + return sampleAvg; + + case F_hour: + return ((double)hour(localTime)); + case F_minute: + return ((double)minute(localTime)); + case F_second: + return ((double)second(localTime)); + } + #else + switch (variable) + { + case F_ledCount: + return 3; // used in testing e.g. for i = 1 to ledCount + case F_leds: + if (par1 == doubleNull) { + ERROR_ARTI("arti_get_external_variable leds without indices not supported yet (get leds)\n"); + return F_leds; + } + else if (par2 == doubleNull) + return par1; + else + return par1 * par2; //2D value!! + + case F_speedSlider: + return F_speedSlider; + case F_intensitySlider: + return F_intensitySlider; + case F_custom1Slider: + return F_custom1Slider; + case F_custom2Slider: + return F_custom2Slider; + case F_custom3Slider: + return F_custom3Slider; + case F_sampleAvg: + return F_sampleAvg; + + case F_hour: + return F_hour; + case F_minute: + return F_minute; + case F_second: + return F_second; + } + #endif + + ERROR_ARTI("Error: arti_get_external_variable: %u not implemented\n", variable); + return variable; +} + +bool ledsSet; //check if leds is set + +void WS2812FX::arti_set_external_variable(double value, uint8_t variable, double par1, double par2, double par3) { + #if ARTI_PLATFORM == ARTI_ARDUINO + // MEMORY_ARTI("%s %s %u %u (%u)\n", spaces+50-depth, variable_name, par1, par2, esp_get_free_heap_size()); + switch (variable) + { + case F_leds: + if (par1 == doubleNull) + ERROR_ARTI("arti_set_external_variable leds without indices not supported yet (set leds to %f)\n", value); + else if (par2 == doubleNull) + leds[realPixelIndex((uint16_t)par1%ledCount)] = value; + else + leds[XY((uint16_t)par1%SEGMENT.width, (uint16_t)par2%SEGMENT.height)] = value; //2D value!! + + ledsSet = true; + return; + } + #else + switch (variable) + { + case F_leds: + if (par1 == doubleNull) + ERROR_ARTI("arti_set_external_variable leds without indices not supported yet (set leds to %f)\n", value); + else if (par2 == doubleNull) + RUNLOG_ARTI("arti_set_external_variable: leds(%f) := %f\n", par1, value); + else + RUNLOG_ARTI("arti_set_external_variable: leds(%f, %f) := %f\n", par1, par2, value); + + ledsSet = true; + return; + } + #endif + + ERROR_ARTI("Error: arti_set_external_variable: %u not implemented\n", variable); +} //arti_set_external_variable + +bool ARTI::loop() { + if (stages < 5) {close(); return true;} + + if (parseTreeJsonDoc == nullptr || parseTreeJsonDoc->isNull()) + { + ERROR_ARTI("Loop: No parsetree created\n"); + return false; + } + else + { + uint8_t depth = 8; + + bool foundRenderFunction = false; + + const char * function_name = "renderFrame"; + Symbol* function_symbol = global_scope->lookup(function_name); + + ledsSet = false; + + if (function_symbol != nullptr) { //calling undefined function: pre-defined functions e.g. print + + foundRenderFunction = true; + + ActivationRecord* ar = new ActivationRecord(function_name, "Function", function_symbol->scope_level + 1); + + RUNLOG_ARTI("%s %s %s (%u)\n", spaces+50-depth, "Call", function_name, this->callStack->recordsCounter); + + this->callStack->push(ar); + + interpret(function_symbol->block, nullptr, global_scope, depth + 1); + + this->callStack->pop(); + + delete ar; ar = nullptr; + + } //function_symbol != nullptr + + function_name = "renderLed"; + function_symbol = global_scope->lookup(function_name); + + if (function_symbol != nullptr) { //calling undefined function: pre-defined functions e.g. print + + foundRenderFunction = true; + + ActivationRecord* ar = new ActivationRecord(function_name, "function", function_symbol->scope_level + 1); + + for (int i = 0; i< arti_get_external_variable(F_ledCount); i++) + { + ar->set(function_symbol->function_scope->symbols[0]->scope_index, i); // set ledIndex to count value + + this->callStack->push(ar); + + interpret(function_symbol->block, nullptr, global_scope, depth + 1); + + this->callStack->pop(); + + } + + delete ar; ar = nullptr; + + } + + // if leds has been set during interpret(renderLed) + if (ledsSet) { + // Serial.println("ledsSet"); + arti_external_function(F_setPixels); + } + // else + // Serial.println("not ledsSet"); + + if (!foundRenderFunction) { + ERROR_ARTI("%s renderFrame or renderLed not found\n", spaces+50-depth); + return false; + } + } + return true; +} // loop + +#if ARTI_PLATFORM == ARTI_ARDUINO + +ARTI * arti; + +//Adding ARTI to this structure seems to be needed to make the pointers used in ARTI survive in subsequent calls of mode_customEffect +// otherwise: Interpret renderFrame: No parsetree created +// initially added parseTreeJsonDoc in this struct to save it explicitly but that was not needed +// maybe because this struct is not deleted +// typedef struct ArtiWrapper { +// ARTI * arti; +// } artiWrapper; + +uint16_t WS2812FX::mode_customEffect(void) { + + // //brightpulse + // uint8_t lum = constrain(sampleAvg * 256.0 / (256.0 - SEGMENT.speed), 0, 255); + // fill(color_blend(SEGCOLOR(1), SEGCOLOR(0), lum)); + + // return FRAMETIME; + + // float t = (sin((float)millis() / 1000.) + 1.0) / 2.; // Make a slow sine wave and convert output range from -1.0 and 1.0 to between 0 and 1.0. + // t = t * (float)SEGLEN; // Now map to the length of the strand. + + // for (int i = 0; i < SEGLEN; i++) + // { + // float diff = abs(t - (float)i); // Get difference between t and current location. Greater distance = lower brightness. + // if (diff > 2.0) diff = 2.0; // Let's not overflow. + // float bri = 256 - diff * 128; // Scale the brightness to up to 255. Closer = brighter. + // leds[i] = CHSV(0, 255, (uint8_t)bri); + // } + + // setPixels(leds); + + // return FRAMETIME; + + + // //Random + // for (int i = 0; i < ledCount; i = i + 1) { + // uint16_t color = random16(); + // setPixelColor(i%ledCount, color_wheel(color%256)); + // } + + // return 0; + + // //Kitt + + // static int pixelCounter; + // static int goingUp; + + // if (pixelCounter > (ledCount-5)) { + // goingUp = 0; + // } + // if (pixelCounter == 0) { + // goingUp = 1; + // } + // setPixelColor(pixelCounter%ledCount, color_wheel(pixelCounter%256)); + // if (goingUp) { + // setPixelColor((pixelCounter-5)%ledCount, CRGB::Black); + // pixelCounter = pixelCounter + 1; + // } + // else { + // setPixelColor((pixelCounter+5)%ledCount, CRGB::Black); + // pixelCounter = pixelCounter - 1; + // } + + // return 0; + + // ArtiWrapper* artiWrapper = reinterpret_cast(SEGENV.data); + + //tbd: move statics to SEGMENT.data + static bool succesful; + static bool notEnoughHeap; + + static char previousEffect[charLength]; + if (SEGENV.call == 0) + strcpy(previousEffect, ""); //force init + + char currentEffect[charLength]; + strcpy(currentEffect, (SEGMENT.name != nullptr)?SEGMENT.name:"default"); //note: switching preset with segment name to preset without does not clear the SEGMENT.name variable, but not gonna solve here ;-) + + if (strcmp(previousEffect, currentEffect) != 0) { + strcpy(previousEffect, currentEffect); + + // if (artiWrapper != nullptr && artiWrapper->arti != nullptr) { + if (arti != nullptr) { + arti->close(); + delete arti; arti = nullptr; + } + + // if (!SEGENV.allocateData(sizeof(ArtiWrapper))) return mode_static(); // We use this method for allocating memory for static variables. + // artiWrapper = reinterpret_cast(SEGENV.data); + arti = new ARTI(); + + char programFileName[charLength]; + strcpy(programFileName, "/"); + strcat(programFileName, currentEffect); + strcat(programFileName, ".wled"); + + succesful = arti->setup("/wled.json", programFileName); + + if (!succesful) { + ERROR_ARTI("Setup not succesful\n"); + } + } + else { + + if (succesful) {// && SEGENV.call < 250 for each frame + if (esp_get_free_heap_size() <= 20000) { + ERROR_ARTI("Not enough free heap (%u <= 30000)\n", esp_get_free_heap_size()); + notEnoughHeap = true; + succesful = false; + } + else { + // static int previousMillis; + // if (millis() - previousMillis > 5000) { //tried SEGENV.aux0 but that looks to be overwritten!!! (dangling pointer???) + // previousMillis = millis(); + // MEMORY_ARTI("Heap renderFrame %u\n", esp_get_free_heap_size()); + // } + arti->loop(); + } + } + else + { + if (notEnoughHeap && esp_get_free_heap_size() > 20000) { + ERROR_ARTI("Again enough free heap, restart effect (%u > 30000)\n", esp_get_free_heap_size()); + succesful = true; + notEnoughHeap = false; + strcpy(previousEffect, ""); // force new create + } + else { + return mode_blink(); + } + } + } + + return FRAMETIME; +} + +#endif \ No newline at end of file diff --git a/wled00/src/dependencies/arti/arti_wled_plugin.h b/wled00/src/dependencies/arti/arti_wled_plugin.h deleted file mode 100644 index 234c5f0e03..0000000000 --- a/wled00/src/dependencies/arti/arti_wled_plugin.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - @title Arduino Real Time Interpreter (ARTI) - @file arti_wled_plugin.h - @version 0.0.6 - @date 20211114 - @author Ewoud Wijma - @repo https://github.com/ewoudwijma/ARTI - */ - -#pragma once - -#if ARTI_PLATFORM == ARTI_ARDUINO - #include "FX.h" - extern float sampleAvg; -#else - #include -#endif - -#include -#include -#include - -//make sure the numbers here correspond to the order in which these functions are defined in wled.json!! -enum WLEDExternals -{ - F_ledCount, - F_setPixelColor, - F_leds, - F_setPixels, - F_hsv, - - F_setRange, - F_fill, - F_colorBlend, - F_colorWheel, - - F_segcolor, - F_speed, - F_sampleAvg, - - F_shift, - F_circle2D, - - F_constrain, - F_random, - F_sin, - F_cos, - F_abs, - - F_hour, - F_minute, - F_second, - F_millis, - - F_printf -}; - -#if ARTI_PLATFORM != ARTI_ARDUINO - class WS2812FX { - public: - uint16_t matrixWidth = 16, matrixHeight = 16; - - uint16_t XY(uint16_t x, uint16_t y) { // ewowi20210703: new XY: segmentToReal: Maps XY in 2D segment to to rotated and mirrored logical index. Works for 1D strips and 2D panels - return x%matrixWidth + y%matrixHeight * matrixWidth; - } - - double arti_external_function(uint8_t function, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); - double arti_get_external_variable(uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); - void arti_set_external_variable(double value, uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull); - }; //class WS2812FX - - WS2812FX strip = WS2812FX(); - -#endif - -double arti_external_function(uint8_t function, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull) -{ - return strip.arti_external_function(function, par1, par2, par3); -} - -double arti_get_external_variable(uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull) -{ - return strip.arti_get_external_variable(variable, par1, par2, par3); -} - -void arti_set_external_variable(double value, uint8_t variable, double par1 = doubleNull, double par2 = doubleNull, double par3 = doubleNull) -{ - strip.arti_set_external_variable(value, variable, par1, par2, par3); -} - -double WS2812FX::arti_external_function(uint8_t function, double par1, double par2, double par3) { - // MEMORY_ARTI("fun %d(%f, %f, %f)\n", function, par1, par2, par3); - #if ARTI_PLATFORM == ARTI_ARDUINO - switch (function) { - case F_setPixelColor: { - if (par2 == 0) - setPixelColor(((uint16_t)par1)%ledCount, CRGB::Black); - else - setPixelColor(((uint16_t)par1)%ledCount, color_from_palette(((uint8_t)par2)%256, true, (paletteBlend == 1 || paletteBlend == 3), 0)); - return doubleNull; - } - case F_random: - return random16(); - case F_shift: { - uint32_t saveFirstPixel = getPixelColor(0); - for (uint16_t i=0; i3.5->4) - int x = round(round((sin(radians(par1)) * halfLength + halfLength) * 10)/10) + deltaWidth; - int y = round(round((halfLength - cos(radians(par1)) * halfLength) * 10)/10) + deltaHeight; - return strip.XY(x,y); - } - case F_millis: - return millis(); - case F_setPixels: - setPixels(leds); - return doubleNull; - case F_hsv: - return crgb_to_col(CHSV(par1, par2, par3)); - case F_constrain: - return constrain(par1, par2, par3); - case F_fill: { - fill((uint32_t)par1); - return doubleNull; - } - case F_colorBlend: - return color_blend((uint32_t)par1, (uint32_t)par2, (uint16_t)par3); - case F_segcolor: - return SEGCOLOR((uint8_t)par1); - case F_colorWheel: - return color_wheel((uint8_t)par1); - case F_setRange: { - setRange((uint16_t)par1, (uint16_t)par2, (uint32_t)par3); - return doubleNull; - } - default: {} - } - #else - switch (function) - { - case F_setPixelColor: - PRINT_ARTI("%s(%f, %f)\n", "setPixelColor", par1, par2); - return doubleNull; - case F_random: - return rand(); - case F_shift: - PRINT_ARTI("%s(%f)\n", "shift", par1); - return doubleNull; - case F_circle2D: - PRINT_ARTI("%s(%f)\n", "circle2D", par1); - return par1 / 2; - case F_millis: - return 1000; - case F_setPixels: - PRINT_ARTI("%s(%f)\n", "setPixels", par1); - return doubleNull; - case F_hsv: - PRINT_ARTI("%s(%f, %f, %f)\n", "hsv", par1, par2, par3); - return par1 + par2 + par3; - case F_constrain: - return par1 + par2 + par3; - case F_fill: - PRINT_ARTI("%s(%f)\n", "fill", par1); - return doubleNull; - case F_colorBlend: - return par1 + par2 + par3; - case F_segcolor: - return par1; - case F_colorWheel: - return par1; - case F_setRange: - return par1 + par2 + par3; - } - #endif - - //same on Arduino or Windows - switch (function) - { - case F_printf: - PRINT_ARTI("%s(%f, %f, %f)\n", "printf", par1, par2, par3); - return doubleNull; - case F_sin: - return sin(par1); - case F_cos: - return cos(par1); - case F_abs: - return abs(par1); - } - - return doubleNull; -} - -double WS2812FX::arti_get_external_variable(uint8_t variable, double par1, double par2, double par3) { - // MEMORY_ARTI("get %d(%f, %f, %f)\n", variable, par1, par2, par3); - #if ARTI_PLATFORM == ARTI_ARDUINO - switch (variable) - { - case F_ledCount: - return SEGLEN; - case F_leds: - if (par1 == doubleNull) { - ERROR_ARTI("arti_get_external_variable leds without indices not supported yet (get leds)\n"); - return doubleNull; - } - else if (par2 == doubleNull) - return leds[(uint16_t)par1]; - else - return leds[XY((uint16_t)par1, (uint16_t)par2)]; //2D value!! - case F_sampleAvg: - return sampleAvg; - case F_speed: - return SEGMENT.speed; - case F_hour: - return ((double)hour(localTime)); - case F_minute: - return ((double)minute(localTime)); - case F_second: - return ((double)second(localTime)); - } - #else - switch (variable) - { - case F_ledCount: - return 3; - case F_leds: - if (par1 == doubleNull) { - ERROR_ARTI("arti_get_external_variable leds without indices not supported yet (get leds)\n"); - return doubleNull; - } - else if (par2 == doubleNull) - return par1; - else - return par1 * par2; //2D value!! - case F_sampleAvg: - return 9; - case F_speed: - return 11; - case F_hour: - return 24; - case F_minute: - return 60; - case F_second: - return 60; - } - #endif - - return doubleNull; -} - -bool ledsSet; //tbd: make part of ARTI wled extension - -void WS2812FX::arti_set_external_variable(double value, uint8_t variable, double par1, double par2, double par3) { - #if ARTI_PLATFORM == ARTI_ARDUINO - // MEMORY_ARTI("%s %s %u %u (%u)\n", spaces+50-depth, variable_name, par1, par2, esp_get_free_heap_size()); - switch (variable) - { - case F_leds: - if (par1 == doubleNull) - ERROR_ARTI("arti_set_external_variable leds without indices not supported yet (set leds to %f)\n", value); - else if (par2 == doubleNull) - leds[(uint16_t)par1%ledCount] = value; - else - leds[XY((uint16_t)par1%matrixWidth, (uint16_t)par2%matrixHeight)] = value; //2D value!! - break; - } - #else - switch (variable) - { - case F_leds: - if (par1 == doubleNull) - ERROR_ARTI("arti_set_external_variable leds without indices not supported yet (set leds to %f)\n", value); - else - RUNLOG_ARTI("arti_set_external_variable, set leds(%f, %f) to %f\n", par1, par2, value); - break; - } - #endif - - switch (variable) - { - case F_leds: - ledsSet = true; - break; - case F_ledCount: - WARNING_ARTI("Warning: arti_set_external_variable, cannot set ledCount to %f\n", value); - break; - } -} \ No newline at end of file From b3324d22f56eecdb24172d239c70e52a02191524 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Sun, 21 Nov 2021 23:46:44 +0100 Subject: [PATCH 035/120] allowCCT performance improvement --- wled00/FX.cpp | 2 +- wled00/FX.h | 2 +- wled00/colors.cpp | 31 ++++++++++++++++++------------- wled00/led.cpp | 1 - wled00/wled.h | 2 +- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a2b6a9596a..d0767713bc 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2614,7 +2614,7 @@ uint16_t WS2812FX::mode_glitter() -//each needs 11 bytes +//each needs 12 bytes //Spark type is used for popcorn, 1D fireworks, and drip typedef struct Spark { float pos; diff --git a/wled00/FX.h b/wled00/FX.h index 3b6bfab6a2..2195f6e57f 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -247,7 +247,7 @@ class WS2812FX { // segment parameters public: - typedef struct Segment { // 30 (33 in memory?) bytes + typedef struct Segment { // 30 (32 in memory) bytes uint16_t start; uint16_t stop; //segment invalid if stop == 0 uint16_t offset; diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 0377a198f3..e7e2b7d19e 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -73,7 +73,7 @@ void colorKtoRGB(uint16_t kelvin, byte* rgb) //white spectrum to rgb, calc g = round(288.1221695283 * pow((temp - 60), -0.0755148492)); b = 255; } - //g += 15; //mod by Aircoookie, a bit less accurate but visibly less pinkish + //g += 12; //mod by Aircoookie, a bit less accurate but visibly less pinkish rgb[0] = (uint8_t) constrain(r, 0, 255); rgb[1] = (uint8_t) constrain(g, 0, 255); rgb[2] = (uint8_t) constrain(b, 0, 255); @@ -248,20 +248,25 @@ void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw). (RGBW_M // adjust RGB values based on color temperature in K (range [2800-10200]) (https://en.wikipedia.org/wiki/Color_balance) void colorBalanceFromKelvin(uint16_t kelvin, byte *rgb) { - byte rgbw[4] = {0,0,0,0}; - colorKtoRGB(kelvin, rgbw); // convert Kelvin to RGB - rgb[0] = ((uint16_t) rgbw[0] * rgb[0]) / 255; // correct R - rgb[1] = ((uint16_t) rgbw[1] * rgb[1]) / 255; // correct G - rgb[2] = ((uint16_t) rgbw[2] * rgb[2]) / 255; // correct B + uint32_t col = RGBW32(rgb[0], rgb[1], rgb[2], 0); + col = colorBalanceFromKelvin(kelvin, col); + rgb[0] = R(col); + rgb[1] = G(col); + rgb[2] = B(col); } +byte correctionRGB[4] = {0,0,0,0}; +uint16_t lastKelvin = 0; + uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) { - byte rgbw[4] = {0,0,0,0}; - colorKtoRGB(kelvin, rgbw); // convert Kelvin to RGB - rgbw[0] = ((uint16_t) rgbw[0] * R(rgb)) / 255; // correct R - rgbw[1] = ((uint16_t) rgbw[1] * G(rgb)) / 255; // correct G - rgbw[2] = ((uint16_t) rgbw[2] * B(rgb)) / 255; // correct B - rgbw[3] = W(rgb); + //remember so that slow colorKtoRGB() doesn't have to run for every setPixelColor() + if (lastKelvin != kelvin) colorKtoRGB(kelvin, correctionRGB); // convert Kelvin to RGB + lastKelvin = kelvin; + byte rgbw[4]; + rgbw[0] = ((uint16_t) correctionRGB[0] * R(rgb)) /255; // correct R + rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G + rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B + rgbw[3] = W(rgb); return colorFromRgbw(rgbw); -} +} \ No newline at end of file diff --git a/wled00/led.cpp b/wled00/led.cpp index 172fabbc72..2c02d01acd 100644 --- a/wled00/led.cpp +++ b/wled00/led.cpp @@ -30,7 +30,6 @@ void toggleOnOff() { briLast = bri; bri = 0; - //unloadPlaylist(); // no longer necessary } } diff --git a/wled00/wled.h b/wled00/wled.h index dbe9d33875..ca3a68964f 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -31,7 +31,7 @@ #ifndef WLED_DISABLE_MQTT #define WLED_ENABLE_MQTT // saves 12kb #endif -//#define WLED_ENABLE_ADALIGHT // saves 500b only (uses GPIO3 (RX) for serial) +#define WLED_ENABLE_ADALIGHT // saves 500b only (uses GPIO3 (RX) for serial) //#define WLED_ENABLE_DMX // uses 3.5kb (use LEDPIN other than 2) #ifndef WLED_DISABLE_LOXONE #define WLED_ENABLE_LOXONE // uses 1.2kb From 80a657965e0726f3ec48b1dc47a8dba0876ed413 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Mon, 22 Nov 2021 21:41:04 +0100 Subject: [PATCH 036/120] Fixed preset cycle not working from preset called by UI --- CHANGELOG.md | 5 +++++ wled00/json.cpp | 6 ++++-- wled00/set.cpp | 10 ++++------ wled00/wled.h | 4 +++- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff04e1de1f..ba305fbb86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ### Builds after release 0.12.0 +#### Build 2111220 + +- Fixed preset cycle not working from preset called by UI +- Reintroduced permanent min. and max. cycle bounds + #### Build 2111190 - Changed default ESP32 LED pin from 16 to 2 diff --git a/wled00/json.cpp b/wled00/json.cpp index 4ac81fe77a..de40f5610f 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -339,9 +339,11 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId) deletePreset(ps); } - if (getVal(root["ps"], &presetCycCurr, 1, 5)) { //load preset (clears state request!) + ps = presetCycCurr; + if (getVal(root["ps"], &ps, presetCycMin, presetCycMax)) { //load preset (clears state request!) if (!presetId) unloadPlaylist(); //stop playlist if preset changed manually - applyPreset(presetCycCurr, callMode); + if (ps >= presetCycMin && ps <= presetCycMax) presetCycCurr = ps; + applyPreset(ps, callMode); return stateResponse; } diff --git a/wled00/set.cpp b/wled00/set.cpp index cfd737b959..eda22508d0 100644 --- a/wled00/set.cpp +++ b/wled00/set.cpp @@ -547,6 +547,7 @@ void parseNumber(const char* str, byte* val, byte minv, byte maxv) const char* str2 = strchr(str,'~'); //min/max range (for preset cycle, e.g. "1~5~") if (str2) { byte p2 = atoi(str2+1); + presetCycMin = p1; presetCycMax = p2; while (isdigit((str2+1)[0])) str2++; parseNumber(str2+1, val, p1, p2); } else { @@ -655,17 +656,14 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply) pos = req.indexOf(F("PS=")); //saves current in preset if (pos > 0) savePreset(getNumVal(&req, pos)); - byte presetCycleMin = 1; - byte presetCycleMax = 5; - pos = req.indexOf(F("P1=")); //sets first preset for cycle - if (pos > 0) presetCycleMin = getNumVal(&req, pos); + if (pos > 0) presetCycMin = getNumVal(&req, pos); pos = req.indexOf(F("P2=")); //sets last preset for cycle - if (pos > 0) presetCycleMax = getNumVal(&req, pos); + if (pos > 0) presetCycMax = getNumVal(&req, pos); //apply preset - if (updateVal(&req, "PL=", &presetCycCurr, presetCycleMin, presetCycleMax)) { + if (updateVal(&req, "PL=", &presetCycCurr, presetCycMin, presetCycMax)) { applyPreset(presetCycCurr); } diff --git a/wled00/wled.h b/wled00/wled.h index 0c53f56c13..54d9743eb3 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2111190 +#define VERSION 2111220 //uncomment this if you have a "my_config.h" file you'd like to use //#define WLED_USE_MY_CONFIG @@ -515,6 +515,8 @@ WLED_GLOBAL unsigned long presetCycledTime _INIT(0); WLED_GLOBAL int16_t currentPlaylist _INIT(-1); //still used for "PL=~" HTTP API command WLED_GLOBAL byte presetCycCurr _INIT(0); +WLED_GLOBAL byte presetCycMin _INIT(1); +WLED_GLOBAL byte presetCycMax _INIT(5); // realtime WLED_GLOBAL byte realtimeMode _INIT(REALTIME_MODE_INACTIVE); From c8d5218c65809b59d82050d48008bd27d0790277 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Mon, 22 Nov 2021 22:23:51 +0100 Subject: [PATCH 037/120] Updated outdated wiki links in readme --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index 506f7de737..e768210065 100644 --- a/readme.md +++ b/readme.md @@ -51,7 +51,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control See the [documentation on our official site](https://kno.wled.ge)! -[On this page](https://github.com/Aircoookie/WLED/wiki/Learning-the-ropes) you can find excellent tutorials made by the community and helpful tools to help you get your new lamp up and running! +[On this page](https://kno.wled.ge/basics/tutorials/) you can find excellent tutorials made by the community and helpful tools to help you get your new lamp up and running! ## 🖼️ Images @@ -82,7 +82,7 @@ Any | 5v 3-pin ARGB for PC | Any PC RGB device that supports the 5v 3-pin ARGB m ## ✌️ Other Licensed under the MIT license -Credits [here](https://github.com/Aircoookie/WLED/wiki/Contributors-&-About)! +Credits [here](https://kno.wled.ge/about/contributors/)! Uses Linearicons by Perxis! From b97b6dc144207bce7d41392c0c198b25c59f3558 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Tue, 23 Nov 2021 13:17:33 +0100 Subject: [PATCH 038/120] Remove F macro for "ps" --- wled00/cfg.cpp | 4 ++-- wled00/json.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 20bcdbd89c..a72af85bb2 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -220,7 +220,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(macroNl, light_nl["macro"]); JsonObject def = doc[F("def")]; - CJSON(bootPreset, def[F("ps")]); + CJSON(bootPreset, def["ps"]); CJSON(turnOnAtBoot, def["on"]); // true CJSON(briS, def["bri"]); // 128 @@ -593,7 +593,7 @@ void serializeConfig() { light_nl["macro"] = macroNl; JsonObject def = doc.createNestedObject("def"); - def[F("ps")] = bootPreset; + def["ps"] = bootPreset; def["on"] = turnOnAtBoot; def["bri"] = briS; diff --git a/wled00/json.cpp b/wled00/json.cpp index de40f5610f..1a546c7950 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -429,7 +429,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme if (!forPreset) { if (errorFlag) root[F("error")] = errorFlag; - root[F("ps")] = (currentPreset > 0) ? currentPreset : -1; + root["ps"] = (currentPreset > 0) ? currentPreset : -1; root[F("pl")] = currentPlaylist; usermods.addToJsonState(root); From 97b3c3db7b26b766cf4860336c2b9384876627e0 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Tue, 23 Nov 2021 20:05:51 +0100 Subject: [PATCH 039/120] Incrementing & random effects, palettes via JSON. --- wled00/json.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index 1a546c7950..a30aa68b1f 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -148,21 +148,21 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId) //temporary, strip object gets updated via colorUpdated() if (id == strip.getMainSegmentId()) { - byte effectPrev = effectCurrent; - effectCurrent = elem["fx"] | effectCurrent; - if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually + if (getVal(elem["fx"], &effectCurrent, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value) + if (!presetId) unloadPlaylist(); //stop playlist if active and FX changed manually + } effectSpeed = elem[F("sx")] | effectSpeed; effectIntensity = elem[F("ix")] | effectIntensity; - effectPalette = elem["pal"] | effectPalette; + getVal(elem["pal"], &effectPalette, 1, strip.getPaletteCount()); } else { //permanent - byte fx = elem["fx"] | seg.mode; - if (fx != seg.mode && fx < strip.getModeCount()) { + byte fx = seg.mode; + if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value) strip.setMode(id, fx); if (!presetId) unloadPlaylist(); //stop playlist if active and FX changed manually } seg.speed = elem[F("sx")] | seg.speed; seg.intensity = elem[F("ix")] | seg.intensity; - seg.palette = elem["pal"] | seg.palette; + getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount()); } JsonArray iarr = elem[F("i")]; //set individual LEDs From ea0f37f5b9c52a38f72c06c3db055c1832a5bc60 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Wed, 24 Nov 2021 11:02:25 +0100 Subject: [PATCH 040/120] CCT bus manager logic simplification CCT from RGB if none set (-1) --- wled00/FX.h | 10 +- wled00/FX_fcn.cpp | 28 +- wled00/bus_manager.h | 84 +- wled00/cfg.cpp | 4 +- wled00/colors.cpp | 52 +- wled00/data/settings_leds.htm | 4 +- wled00/fcn_declare.h | 2 +- wled00/html_settings.h | 7 +- wled00/html_ui.h | 1576 ++++++++++++++++----------------- wled00/json.cpp | 2 +- wled00/set.cpp | 2 +- wled00/wled.h | 4 +- wled00/xml.cpp | 2 +- 13 files changed, 897 insertions(+), 880 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 2195f6e57f..669d03660b 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -165,12 +165,12 @@ #define FX_MODE_FIRE_FLICKER 45 #define FX_MODE_GRADIENT 46 #define FX_MODE_LOADING 47 -#define FX_MODE_POLICE 48 +#define FX_MODE_POLICE 48 // candidate for removal (after below three) #define FX_MODE_POLICE_ALL 49 // candidate for removal #define FX_MODE_TWO_DOTS 50 -#define FX_MODE_TWO_AREAS 51 +#define FX_MODE_TWO_AREAS 51 // candidate for removal #define FX_MODE_RUNNING_DUAL 52 -#define FX_MODE_HALLOWEEN 53 +#define FX_MODE_HALLOWEEN 53 // candidate for removal #define FX_MODE_TRICOLOR_CHASE 54 #define FX_MODE_TRICOLOR_WIPE 55 #define FX_MODE_TRICOLOR_FADE 56 @@ -247,7 +247,7 @@ class WS2812FX { // segment parameters public: - typedef struct Segment { // 30 (32 in memory) bytes + typedef struct Segment { // 31 (32 in memory) bytes uint16_t start; uint16_t stop; //segment invalid if stop == 0 uint16_t offset; @@ -259,7 +259,7 @@ class WS2812FX { uint8_t grouping, spacing; uint8_t opacity; uint32_t colors[NUM_COLORS]; - uint8_t cct; //0==2000K, 255==10160K + int16_t cct; //-1==auto (no RGB balance correction), 0==1900K, 255==10091K char *name; bool setColor(uint8_t slot, uint32_t c, uint8_t segn) { //returns true if changed if (slot >= NUM_COLORS || segn >= MAX_NUM_SEGMENTS) return false; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index d516391569..eb7f7b5d5a 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -138,6 +138,7 @@ void WS2812FX::service() { if (!SEGMENT.getOption(SEG_OPTION_FREEZE)) { //only run effect function if not frozen _virtualSegmentLength = SEGMENT.virtualLength(); + busses.setSegmentCCT(SEGMENT.cct, correctWB); _bri_t = SEGMENT.opacity; _colors_t[0] = SEGMENT.colors[0]; _colors_t[1] = SEGMENT.colors[1]; _colors_t[2] = SEGMENT.colors[2]; if (!IS_SEGMENT_ON) _bri_t = 0; for (uint8_t t = 0; t < MAX_NUM_TRANSITIONS; t++) { @@ -156,6 +157,7 @@ void WS2812FX::service() { } } _virtualSegmentLength = 0; + busses.setSegmentCCT(-1); if(doShow) { yield(); show(); @@ -191,21 +193,6 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) uint16_t realIndex = realPixelIndex(i); uint16_t len = SEGMENT.length(); - // determine if we can do white balance and accurate W calc - // NOTE & TODO: does not work correctly with custom mapping if map spans different strips - int16_t cct = -1; - for (uint8_t b = 0; b < busses.getNumBusses(); b++) { - Bus *bus = busses.getBus(b); - if (bus == nullptr || !bus->containsPixel(realIndex)) continue; - //if (bus == nullptr || bus->getStart()getStart()+bus->getLength()>realIndex) continue; - uint8_t busType = bus->getType(); - if (allowCCT - || busType == TYPE_ANALOG_2CH - || busType == TYPE_ANALOG_5CH) { - if (cct<0) cct = SEGMENT.cct; - } - } - //color_blend(getpixel, col, _bri_t); (pseudocode for future blending of segments) if (_bri_t < 255) { r = scale8(r, _bri_t); @@ -226,14 +213,14 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) if (indexMir >= SEGMENT.stop) indexMir -= len; if (indexMir < customMappingSize) indexMir = customMappingTable[indexMir]; - busses.setPixelColor(indexMir, col, cct); + busses.setPixelColor(indexMir, col); } /* offset/phase */ indexSet += SEGMENT.offset; if (indexSet >= SEGMENT.stop) indexSet -= len; if (indexSet < customMappingSize) indexSet = customMappingTable[indexSet]; - busses.setPixelColor(indexSet, col, cct); + busses.setPixelColor(indexSet, col); } } } else { //live data, etc. @@ -618,7 +605,7 @@ void WS2812FX::resetSegments() { _segments[0].setOption(SEG_OPTION_SELECTED, 1); _segments[0].setOption(SEG_OPTION_ON, 1); _segments[0].opacity = 255; - _segments[0].cct = 128; + _segments[0].cct = -1; for (uint16_t i = 1; i < MAX_NUM_SEGMENTS; i++) { @@ -626,7 +613,7 @@ void WS2812FX::resetSegments() { _segments[i].grouping = 1; _segments[i].setOption(SEG_OPTION_ON, 1); _segments[i].opacity = 255; - _segments[i].cct = 128; + _segments[i].cct = -1; _segments[i].speed = DEFAULT_SPEED; _segments[i].intensity = DEFAULT_INTENSITY; _segment_runtimes[i].reset(); @@ -1162,4 +1149,5 @@ uint32_t WS2812FX::gamma32(uint32_t color) return RGBW32(r, g, b, w); } -WS2812FX* WS2812FX::instance = nullptr; \ No newline at end of file +WS2812FX* WS2812FX::instance = nullptr; +int16_t Bus::_cct = -1; \ No newline at end of file diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index cae4ac8622..af15d6953a 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -74,7 +74,7 @@ struct BusConfig { } }; -//parent class of BusDigital and BusPwm +//parent class of BusDigital, BusPwm, and BusNetwork class Bus { public: Bus(uint8_t type, uint16_t start, uint8_t aw) { @@ -88,7 +88,6 @@ class Bus { virtual void show() {} virtual bool canShow() { return true; } virtual void setPixelColor(uint16_t pix, uint32_t c) {}; - virtual void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) {}; virtual uint32_t getPixelColor(uint16_t pix) { return 0; }; virtual void setBrightness(uint8_t b) {}; virtual void cleanup() {}; @@ -111,6 +110,9 @@ class Bus { if (type > TYPE_ONOFF && type <= TYPE_ANALOG_5CH && type != TYPE_ANALOG_3CH) return true; return false; } + static void setCCT(uint16_t cct) { + _cct = cct; + } bool reversed = false; @@ -122,16 +124,18 @@ class Bus { bool _valid = false; bool _needsRefresh = false; uint8_t _autoWhiteMode = 0; + static int16_t _cct; uint32_t autoWhiteCalc(uint32_t c) { if (_autoWhiteMode == RGBW_MODE_MANUAL_ONLY) return c; + uint8_t w = W(c); + //ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0) + if (w > 0 && _autoWhiteMode == RGBW_MODE_DUAL) return c; uint8_t r = R(c); uint8_t g = G(c); uint8_t b = B(c); - uint8_t w = W(c); - // ignore auto-white calculation if w>0 and mode DUAL (DUAL behaves as BRIGHTER if w==0) - if (!(w > 0 && _autoWhiteMode == RGBW_MODE_DUAL)) w = r < g ? (r < b ? r : b) : (g < b ? g : b); - if (_autoWhiteMode == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; } // subtract w in ACCURATE mode + w = r < g ? (r < b ? r : b) : (g < b ? g : b); + if (_autoWhiteMode == RGBW_MODE_AUTO_ACCURATE) { r -= w; g -= w; b -= w; } //subtract w in ACCURATE mode return RGBW32(r, g, b, w); } }; @@ -181,17 +185,13 @@ class BusDigital : public Bus { } void setPixelColor(uint16_t pix, uint32_t c) { - if (getAutoWhiteMode() != RGBW_MODE_MANUAL_ONLY) c = autoWhiteCalc(c); + c = autoWhiteCalc(c); + if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT if (reversed) pix = _len - pix -1; else pix += _skip; PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder); } - void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { - c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT - setPixelColor(pix, c); - } - uint32_t getPixelColor(uint16_t pix) { if (reversed) pix = _len - pix -1; else pix += _skip; @@ -282,22 +282,30 @@ class BusPwm : public Bus { _valid = true; }; - void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { + void setPixelColor(uint16_t pix, uint32_t c) { if (pix != 0 || !_valid) return; //only react to first pixel - if (getAutoWhiteMode() != RGBW_MODE_MANUAL_ONLY) c = autoWhiteCalc(c); - c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT (w remains unchanged) + if (_type == TYPE_ANALOG_3CH && _cct >= 1900) { + c = colorBalanceFromKelvin(_cct, c); //color correction from CCT + } + c = autoWhiteCalc(c); uint8_t r = R(c); uint8_t g = G(c); uint8_t b = B(c); uint8_t w = W(c); + uint8_t cct = 0; //0 - full warm white, 255 - full cold white + if (_cct > -1) { + if (_cct >= 1900) cct = (_cct - 1900) >> 5; + else if (_cct < 256) cct = _cct; + } else { + cct = (approximateKelvinFromRGB(c) - 1900) >> 5; + } switch (_type) { case TYPE_ANALOG_1CH: //one channel (white), relies on auto white calculation - _data[0] = w; //max(r, max(g, max(b, w))); + _data[0] = w; break; case TYPE_ANALOG_2CH: //warm white + cold white // perhaps a non-linear adjustment would be in order. need to test - //w = max(r, max(g, max(b, w))); _data[1] = (w * cct) / 255; _data[0] = (w * (255-cct)) / 255; break; @@ -313,25 +321,6 @@ class BusPwm : public Bus { } } - void setPixelColor(uint16_t pix, uint32_t c) { - if (pix != 0 || !_valid) return; //only react to first pixel - if (getAutoWhiteMode() != RGBW_MODE_MANUAL_ONLY) c = autoWhiteCalc(c); - uint8_t r = R(c); - uint8_t g = G(c); - uint8_t b = B(c); - uint8_t w = W(c); - - switch (_type) { - case TYPE_ANALOG_1CH: //one channel (white), use highest RGBW value - _data[0] = max(r, max(g, max(b, w))); break; - case TYPE_ANALOG_2CH: //warm white + cold white - case TYPE_ANALOG_3CH: //standard dumb RGB - case TYPE_ANALOG_4CH: //standard dumb RGBW - case TYPE_ANALOG_5CH: //we'll want the white handling from 2CH here + RGB - _data[0] = r; _data[1] = g; _data[2] = b; _data[3] = w; _data[4] = w; break; - } - } - //does no index check uint32_t getPixelColor(uint16_t pix) { if (!_valid) return 0; @@ -432,7 +421,8 @@ class BusNetwork : public Bus { void setPixelColor(uint16_t pix, uint32_t c) { if (!_valid || pix >= _len) return; - if (getAutoWhiteMode() != RGBW_MODE_MANUAL_ONLY) c = autoWhiteCalc(c); + if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT + c = autoWhiteCalc(c); uint16_t offset = pix * _UDPchannels; _data[offset] = R(c); _data[offset+1] = G(c); @@ -440,11 +430,6 @@ class BusNetwork : public Bus { if (_rgbw) _data[offset+3] = W(c); } - void setPixelColor(uint16_t pix, uint32_t c, uint8_t cct) { - c = colorBalanceFromKelvin(2000+(cct<<5), c); // color correction from CCT - setPixelColor(pix, c); - } - uint32_t getPixelColor(uint16_t pix) { if (!_valid || pix >= _len) return 0; uint16_t offset = pix * _UDPchannels; @@ -564,8 +549,7 @@ class BusManager { Bus* b = busses[i]; uint16_t bstart = b->getStart(); if (pix < bstart || pix >= bstart + b->getLength()) continue; - if (cct<0) busses[i]->setPixelColor(pix - bstart, c); // no white balance - else busses[i]->setPixelColor(pix - bstart, c, cct); // do white balance + busses[i]->setPixelColor(pix - bstart, c); } } @@ -575,6 +559,18 @@ class BusManager { } } + void setSegmentCCT(int16_t cct, bool allowWBCorrection = false) { + if (cct > 255) { //kelvin value, convert to 0-255 + if (cct < 1900) cct = 1900; + if (cct > 10091) cct = 10091; + if (!allowWBCorrection) cct = (cct - 1900) >> 5; + } else if (cct > -1) { + //if white balance correction allowed, save as kelvin value instead of 0-255 + if (allowWBCorrection) cct = 1900 + (cct << 5); + } else cct = -1; + Bus::setCCT(cct); + } + uint32_t getPixelColor(uint16_t pix) { for (uint8_t i = 0; i < numBusses; i++) { Bus* b = busses[i]; diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index a641d41793..8539a486fc 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -80,7 +80,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); uint8_t rgbwMode = hw_led[F("rgbwm")] | RGBW_MODE_DUAL; // use global setting (legacy) - CJSON(allowCCT, hw_led["cct"]); + CJSON(correctWB, hw_led["cct"]); JsonArray ins = hw_led["ins"]; @@ -520,7 +520,7 @@ void serializeConfig() { hw_led[F("total")] = strip.getLengthTotal(); //no longer read, but provided for compatibility on downgrade hw_led[F("maxpwr")] = strip.ablMilliampsMax; hw_led[F("ledma")] = strip.milliampsPerLed; - hw_led["cct"] = allowCCT; + hw_led["cct"] = correctWB; JsonArray hw_led_ins = hw_led.createNestedArray("ins"); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index e7e2b7d19e..2677f61aa3 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -245,19 +245,10 @@ void colorRGBtoRGBW(byte* rgb) //rgb to rgbw (http://codewelt.com/rgbw). (RGBW_M } */ -// adjust RGB values based on color temperature in K (range [2800-10200]) (https://en.wikipedia.org/wiki/Color_balance) -void colorBalanceFromKelvin(uint16_t kelvin, byte *rgb) -{ - uint32_t col = RGBW32(rgb[0], rgb[1], rgb[2], 0); - col = colorBalanceFromKelvin(kelvin, col); - rgb[0] = R(col); - rgb[1] = G(col); - rgb[2] = B(col); -} - byte correctionRGB[4] = {0,0,0,0}; uint16_t lastKelvin = 0; +// adjust RGB values based on color temperature in K (range [2800-10200]) (https://en.wikipedia.org/wiki/Color_balance) uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) { //remember so that slow colorKtoRGB() doesn't have to run for every setPixelColor() @@ -267,6 +258,45 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) rgbw[0] = ((uint16_t) correctionRGB[0] * R(rgb)) /255; // correct R rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B - rgbw[3] = W(rgb); + rgbw[3] = W(rgb); return colorFromRgbw(rgbw); +} + +//approximates a Kelvin color temperature from an RGB color. +//this does no check for the "whiteness" of the color, +//so should be used combined with a saturation check (as done by auto-white) +//values from http://www.vendian.org/mncharity/dir3/blackbody/UnstableURLs/bbr_color.html (10deg) +//equation spreadsheet at https://bit.ly/30RkHaN +//accuracy +-50K from 1900K up to 8000K +//minimum returned: 1900K, maximum returned: 10091K (range of 8192) +uint16_t approximateKelvinFromRGB(uint32_t rgb) { + //if not either red or blue is 255, color is dimmed. Scale up + uint8_t r = R(rgb), b = B(rgb); + if (r == b) return 6550; //red == blue at about 6600K (also can't go further if both R and B are 0) + + if (r > b) { + //scale blue up as if red was at 255 + uint16_t scale = 0xFFFF / r; //get scale factor (range 257-65535) + b = ((uint16_t)b * scale) >> 8; + //For all temps K<6600 R is bigger than B (for full bri colors R=255) + //-> Use 9 linear approximations for blackbody radiation blue values from 2000-6600K (blue is always 0 below 2000K) + if (b < 33) return 1900 + b *6; + if (b < 72) return 2100 + (b-33) *10; + if (b < 101) return 2492 + (b-72) *14; + if (b < 132) return 2900 + (b-101) *16; + if (b < 159) return 3398 + (b-132) *19; + if (b < 186) return 3906 + (b-159) *22; + if (b < 210) return 4500 + (b-186) *25; + if (b < 230) return 5100 + (b-210) *30; + return 5700 + (b-230) *34; + } else { + //scale red up as if blue was at 255 + uint16_t scale = 0xFFFF / b; //get scale factor (range 257-65535) + r = ((uint16_t)r * scale) >> 8; + //For all temps K>6600 B is bigger than R (for full bri colors B=255) + //-> Use 2 linear approximations for blackbody radiation red values from 6600-10091K (blue is always 0 below 2000K) + if (r > 225) return 6600 + (254-r) *50; + uint16_t k = 8080 + (225-r) *86; + return (k > 10091) ? 10091 : k; + } } \ No newline at end of file diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 9e6d9277b5..b141b4d0fd 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -510,7 +510,9 @@

Hardware setup


Make a segment for each output:
Custom bus start indices:
- Allow WB correction:
+ White Balance correction:
+ Calculate CCT from RGB: TODO
+ CCT blending mode: TODO

Touch threshold:
diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index eda6bf34ae..1ba20b331f 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -68,8 +68,8 @@ void colorRGBtoXY(byte* rgb, float* xy); // only defined if huesync disabled TOD void colorFromDecOrHexString(byte* rgb, char* in); bool colorFromHexString(byte* rgb, const char* in); -void colorBalanceFromKelvin(uint16_t kelvin, byte *rgb); uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); +uint16_t approximateKelvinFromRGB(uint32_t rgb); //dmx.cpp void initDMX(); diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 83bc10f7a4..9cd514e8a9 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -77,7 +77,7 @@ onclick="B()">Back // Autogenerated from wled00/data/settings_leds.htm, do not edit!! const char PAGE_settings_leds[] PROGMEM = R"=====(LED Settings - +
diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 6060f7db81..34ccf90e1b 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -170,7 +170,6 @@ gId("dig"+n+"r").style.display = (t>=80 && t<96) ? "none":"inline"; // hide reversed for virtual gId("dig"+n+"s").style.display = ((t>=80 && t<96) || (t > 40 && t < 48)) ? "none":"inline"; // hide skip 1st for virtual & analog gId("dig"+n+"f").style.display = (t>=16 && t<32 || t>=50 && t<64) ? "inline":"none"; // hide refresh - gId("dig"+n+"a").style.display = (isRGBW) ? "inline":"none"; // auto calculate white gId("rev"+n).innerHTML = (t > 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog gId("psd"+n).innerHTML = (t > 40 && t < 48) ? "Index:":"Start:"; // change analog start description } @@ -306,10 +305,11 @@ - + - + + @@ -334,8 +334,7 @@

Reversed:

Skip 1st LED:
-

Off Refresh:  
-

Auto-calculate white channel from RGB:
 
+

Off Refresh:
`; f.insertAdjacentHTML("beforeend", cn); } @@ -402,9 +401,9 @@ } if (!o.files) { - alert("This browser doesn't seem to support the `files` property of file inputs."); + alert("This browser doesn't support the `files` property of file inputs."); } else if (!o.files[0]) { - alert("Please select a JSON file before clicking 'Apply'"); + alert("Please select a JSON file first!"); } else { f = o.files[0]; fr = new FileReader(); @@ -510,9 +509,6 @@

Hardware setup


Make a segment for each output:
Custom bus start indices:
- White Balance correction:
- Calculate CCT from RGB:
- CCT additive blending: %%

Touch threshold:
@@ -554,6 +550,19 @@

Timed light

+

White management

+ White Balance correction:
+ + Auto-calculate white channel from RGB:
+ +
+ Calculate CCT from RGB:
+ CCT additive blending: %%

Advanced

Palette blending:

Reversed:

Skip 1st LED:
-

Off Refresh:  
+

Off Refresh:
`; f.insertAdjacentHTML("beforeend", cn); } @@ -408,10 +409,70 @@ d.Sf.data.value = ''; return false; } - function GetV() - { + // https://stackoverflow.com/questions/7346563/loading-local-json-file + function loadCfg(o) { + var f, fr; + + if (typeof window.FileReader !== 'function') { + alert("The file API isn't supported on this browser yet."); + return; + } + + if (!o.files) { + alert("This browser doesn't support the `files` property of file inputs."); + } else if (!o.files[0]) { + alert("Please select a JSON file first!"); + } else { + f = o.files[0]; + fr = new FileReader(); + fr.onload = receivedText; + fr.readAsText(f); + } + o.value = ''; + + function receivedText(e) { + let lines = e.target.result; + var c = JSON.parse(lines); + if (c.hw) { + if (c.hw.led) { + for (var i=0; i<10; i++) addLEDs(-1); + var l = c.hw.led; + l.ins.forEach((v,i,a)=>{ + addLEDs(1); + for (var j=0; j{ + addBtn(i,v.pin[0],v.type); + }); + d.getElementsByName("TT")[0].value = b.tt; + } + if (c.hw.ir) { + d.getElementsByName("IR")[0].value = c.hw.ir.pin; + d.getElementsByName("IT")[0].value = c.hw.ir.type; + } + if (c.hw.relay) { + d.getElementsByName("RL")[0].value = c.hw.relay.pin; + d.getElementsByName("RM")[0].checked = c.hw.relay.inv; + } + UI(); + } + } + } + function GetV() + { //values injected by server while sending HTML - //d.um_p=[6,7,8,9,10,11,1];bLimits(3,4096,4000,1664);d.Sf.MS.checked=1;addLEDs(1);d.Sf.L00.value=2;d.Sf.LC0.value=30;d.Sf.LT0.value=22;d.Sf.CO0.value=0;d.Sf.LS0.value=15;d.Sf.CV0.checked=1;d.Sf.SL0.checked=0;addLEDs(1);d.Sf.L01.value=10;d.Sf.L11.value=10;d.Sf.L21.value=1;d.Sf.L31.value=10;d.Sf.LC1.value=60;d.Sf.LT1.value=80;d.Sf.CO1.value=1;d.Sf.LS1.value=0;d.Sf.CV1.checked=0;d.Sf.SL1.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=56;d.Sf.AW.value=3;d.Sf.BO.checked=1;d.Sf.BP.value=80;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=0;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=0;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=12;d.Sf.RM.checked=1;addBtn(0,0,0);addBtn(1,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=0; + //d.um_p=[6,7,8,9,10,11,14,15,13,1,21,19,22,25,26,27,5,23,18,17];bLimits(10,2048,64000,8192);d.Sf.MS.checked=1;d.Sf.CCT.checked=0;addLEDs(1);d.Sf.L00.value=192;d.Sf.L10.value=168;d.Sf.L20.value=0;d.Sf.L30.value=61;d.Sf.LC0.value=421;d.Sf.LT0.value=80;d.Sf.CO0.value=1;d.Sf.LS0.value=0;d.Sf.CV0.checked=0;d.Sf.SL0.checked=0;d.Sf.RF0.checked=0;d.Sf.MA.value=850;d.Sf.LA.value=0;d.Sf.CA.value=127;d.Sf.AW.value=3;d.Sf.BO.checked=0;d.Sf.BP.value=0;d.Sf.GB.checked=0;d.Sf.GC.checked=1;d.Sf.TF.checked=1;d.Sf.TD.value=700;d.Sf.PF.checked=1;d.Sf.BF.value=100;d.Sf.TB.value=0;d.Sf.TL.value=60;d.Sf.TW.value=1;d.Sf.PB.selectedIndex=0;d.Sf.RL.value=-1;d.Sf.RM.checked=1;addBtn(0,-1,0);addBtn(1,-1,0);addBtn(2,-1,0);addBtn(3,-1,0);d.Sf.TT.value=32;d.Sf.IR.value=-1;d.Sf.IT.value=8; }

WLED Software Update

-Installed version: 0.13.0-b4
Download the latest binary: Download the latest binary:

body{font-family:Verdana,sans-serif;text-align:center;background:#222;color:#fff;line-height:200%%;margin:0}hr{border-color:#666}.btn,button{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.3ch solid #333;display:inline-block;font-size:20px;margin:12px 8px 8px;padding:1px 6px;cursor:pointer;text-decoration:none}.lnk{border:0}button.disabled,button[disabled]{color:#aaa}.helpB{text-align:left;position:absolute;width:60px}input{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}input:disabled{color:#888}input[type=number]{width:4em;margin:2px}input[type=number].xxl{width:100px}input[type=number].xl{width:85px}input[type=number].l{width:63px}input[type=number].m{width:56px}input[type=number].s{width:49px}input[type=number].xs{width:42px}input[type=checkbox]{transform:scale(1.5);margin-right:10px}select{background:#333;color:#fff;font-family:Verdana,sans-serif;border:.5ch solid #333}td{padding:2px}.d5{width:4.5em!important}#toast{opacity:0;background-color:#444;border-radius:5px;bottom:64px;color:#fff;font-size:17px;padding:16px;pointer-events:none;position:fixed;text-align:center;z-index:5;transform:translateX(-50%%);max-width:90%%;left:50%%}#toast.show{opacity:1;background-color:#264;animation:fadein .5s,fadein .5s 2.5s reverse}#toast.error{opacity:1;background-color:#b21;animation:fadein .5s})====="; +const char PAGE_settingsCss[] PROGMEM = R"=====()====="; // Autogenerated from wled00/data/settings.htm, do not edit!! const char PAGE_settings[] PROGMEM = R"=====(WLED Settings
%DMXMENU%
-
-)====="; +body{text-align:center;background:#222;height:100px;margin:0}html{--h:8.9vh}button{background:#333;color:#fff;font-family:Verdana,Helvetica,sans-serif;border:1px solid #333;border-radius:.5em;font-size:6.5vmin;height:var(--h);width:calc(100%% - 40px);margin-top:2vh} +
+
+
%DMXMENU%
+
+
+
)====="; // Autogenerated from wled00/data/settings_wifi.htm, do not edit!! @@ -78,7 +75,7 @@ onclick="B()">Back // Autogenerated from wled00/data/settings_leds.htm, do not edit!! const char PAGE_settings_leds[] PROGMEM = R"=====(LED Settings + + + + + + + + + + + + + + + + +
+ + + +
+ + \ No newline at end of file diff --git a/usermods/RelayBlinds/presets.json b/usermods/RelayBlinds/presets.json new file mode 100644 index 0000000000..95b5871537 --- /dev/null +++ b/usermods/RelayBlinds/presets.json @@ -0,0 +1 @@ +{"0":{},"2":{"n":"▲","win":"U0=2"},"1":{"n":"▼","win":"U0=1"}} \ No newline at end of file diff --git a/usermods/RelayBlinds/readme.md b/usermods/RelayBlinds/readme.md new file mode 100644 index 0000000000..0c3d2a0ba5 --- /dev/null +++ b/usermods/RelayBlinds/readme.md @@ -0,0 +1,8 @@ +# RelayBlinds usermod + +This simple usermod toggles two relay pins momentarily (default for 500ms) when `userVar0` is set. +This can be used to e.g. "push" the buttons of a window blinds motor controller. + +v1 usermod. Please replace usermod.cpp in the `wled00` directory with the one in this file. +You may upload `index.htm` to `[WLED-IP]/edit` to replace the default lighting UI with a simple Up/Down button one. +Also, a simple `presets.json` file is available, this makes the relay actions controllable via two presets to facilitate control e.g. via the default UI or Alexa. \ No newline at end of file diff --git a/usermods/RelayBlinds/usermod.cpp b/usermods/RelayBlinds/usermod.cpp new file mode 100644 index 0000000000..ee61b0cce3 --- /dev/null +++ b/usermods/RelayBlinds/usermod.cpp @@ -0,0 +1,83 @@ +#include "wled.h" + +//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t) + +//gets called once at boot. Do all initialization that doesn't depend on network here +void userSetup() +{ + +} + +//gets called every time WiFi is (re-)connected. Initialize own network interfaces here +void userConnected() +{ + +} + +/* + * Physical IO + */ +#define PIN_UP_RELAY 4 +#define PIN_DN_RELAY 5 +#define PIN_ON_TIME 500 +bool upActive = false, upActiveBefore = false, downActive = false, downActiveBefore = false; +unsigned long upStartTime = 0, downStartTime = 0; + +void handleRelay() +{ + //up and down relays + if (userVar0) { + upActive = true; + if (userVar0 == 1) { + upActive = false; + downActive = true; + } + userVar0 = 0; + } + + if (upActive) + { + if(!upActiveBefore) + { + pinMode(PIN_UP_RELAY, OUTPUT); + digitalWrite(PIN_UP_RELAY, LOW); + upActiveBefore = true; + upStartTime = millis(); + DEBUG_PRINTLN("UPA"); + } + if (millis()- upStartTime > PIN_ON_TIME) + { + upActive = false; + DEBUG_PRINTLN("UPN"); + } + } else if (upActiveBefore) + { + pinMode(PIN_UP_RELAY, INPUT); + upActiveBefore = false; + } + + if (downActive) + { + if(!downActiveBefore) + { + pinMode(PIN_DN_RELAY, OUTPUT); + digitalWrite(PIN_DN_RELAY, LOW); + downActiveBefore = true; + downStartTime = millis(); + } + if (millis()- downStartTime > PIN_ON_TIME) + { + downActive = false; + } + } else if (downActiveBefore) + { + pinMode(PIN_DN_RELAY, INPUT); + downActiveBefore = false; + } +} + +//loop. You can use "if (WLED_CONNECTED)" to check for successful connection +void userLoop() +{ + handleRelay(); +} \ No newline at end of file diff --git a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h index 6a7e9f5ac9..9c3be7cc28 100644 --- a/usermods/SN_Photoresistor/usermod_sn_photoresistor.h +++ b/usermods/SN_Photoresistor/usermod_sn_photoresistor.h @@ -22,12 +22,12 @@ // 10 bits #ifndef USERMOD_SN_PHOTORESISTOR_ADC_PRECISION -#define USERMOD_SN_PHOTORESISTOR_ADC_PRECISION 1024.0 +#define USERMOD_SN_PHOTORESISTOR_ADC_PRECISION 1024.0f #endif // resistor size 10K hms #ifndef USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE -#define USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE 10000.0 +#define USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE 10000.0f #endif // only report if differance grater than offset value diff --git a/usermods/ST7789_display/README.md b/usermods/ST7789_display/README.md index 653fdd752b..b98d5be002 100644 --- a/usermods/ST7789_display/README.md +++ b/usermods/ST7789_display/README.md @@ -12,7 +12,7 @@ This usermod allow to use 240x240 display to display following: ## Hardware *** -![Hardware](images/ST7789_guide.jpg) +![Hardware](images/ST7789_Guide.jpg) ## Library used diff --git a/usermods/ST7789_display/ST7789_display.h b/usermods/ST7789_display/ST7789_display.h index bd501d08f0..19ad5790ae 100644 --- a/usermods/ST7789_display/ST7789_display.h +++ b/usermods/ST7789_display/ST7789_display.h @@ -118,11 +118,11 @@ class St7789DisplayUsermod : public Usermod { { needRedraw = true; } - else if (knownMode != strip.getMode()) + else if (knownMode != strip.getMainSegment().mode) { needRedraw = true; } - else if (knownPalette != strip.getSegment(0).palette) + else if (knownPalette != strip.getMainSegment().palette) { needRedraw = true; } @@ -148,8 +148,8 @@ class St7789DisplayUsermod : public Usermod { #endif knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownBrightness = bri; - knownMode = strip.getMode(); - knownPalette = strip.getSegment(0).palette; + knownMode = strip.getMainSegment().mode; + knownPalette = strip.getMainSegment().palette; tft.fillScreen(TFT_BLACK); tft.setTextSize(2); diff --git a/usermods/TTGO-T-Display/usermod.cpp b/usermods/TTGO-T-Display/usermod.cpp index 75e90b1ebe..9e08a001a1 100644 --- a/usermods/TTGO-T-Display/usermod.cpp +++ b/usermods/TTGO-T-Display/usermod.cpp @@ -110,9 +110,9 @@ void userLoop() { needRedraw = true; } else if (knownBrightness != bri) { needRedraw = true; - } else if (knownMode != strip.getMode()) { + } else if (knownMode != strip.getMainSegment().mode) { needRedraw = true; - } else if (knownPalette != strip.getSegment(0).palette) { + } else if (knownPalette != strip.getMainSegment().palette) { needRedraw = true; } @@ -136,8 +136,8 @@ void userLoop() { #endif knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownBrightness = bri; - knownMode = strip.getMode(); - knownPalette = strip.getSegment(0).palette; + knownMode = strip.getMainSegment().mode; + knownPalette = strip.getMainSegment().palette; tft.fillScreen(TFT_BLACK); tft.setTextSize(2); diff --git a/usermods/Temperature/usermod_temperature.h b/usermods/Temperature/usermod_temperature.h index 7c209f4754..40df0e5333 100644 --- a/usermods/Temperature/usermod_temperature.h +++ b/usermods/Temperature/usermod_temperature.h @@ -37,12 +37,12 @@ class UsermodTemperature : public Usermod { // used to determine when we can read the sensors temperature // we have to wait at least 93.75 ms after requestTemperatures() is called unsigned long lastTemperaturesRequest; - float temperature = -100; // default to -100, DS18B20 only goes down to -50C + float temperature; // indicates requestTemperatures has been called but the sensor measurement is not complete bool waitingForConversion = false; // flag set at startup if DS18B20 sensor not found, avoids trying to keep getting // temperature if flashed to a board without a sensor attached - bool sensorFound = false; + byte sensorFound; bool enabled = true; @@ -54,27 +54,47 @@ class UsermodTemperature : public Usermod { //Dallas sensor quick (& dirty) reading. Credit to - Author: Peter Scargill, August 17th, 2013 float readDallas() { - byte i; - byte data[2]; + byte data[9]; int16_t result; // raw data from sensor - if (!oneWire->reset()) return -127.0f; // send reset command and fail fast - oneWire->skip(); // skip ROM - oneWire->write(0xBE); // read (temperature) from EEPROM - for (i=0; i < 2; i++) data[i] = oneWire->read(); // first 2 bytes contain temperature - for (i=2; i < 8; i++) oneWire->read(); // read unused bytes - result = (data[1]<<4) | (data[0]>>4); // we only need whole part, we will add fraction when returning - if (data[1]&0x80) result |= 0xFF00; // fix negative value - oneWire->reset(); - oneWire->skip(); // skip ROM - oneWire->write(0x44,parasite); // request new temperature reading (without parasite power) - return (float)result + ((data[0]&0x0008) ? 0.5f : 0.0f); + float retVal = -127.0f; + if (oneWire->reset()) { // if reset() fails there are no OneWire devices + oneWire->skip(); // skip ROM + oneWire->write(0xBE); // read (temperature) from EEPROM + oneWire->read_bytes(data, 9); // first 2 bytes contain temperature + #ifdef WLED_DEBUG + if (OneWire::crc8(data,8) != data[8]) { + DEBUG_PRINTLN(F("CRC error reading temperature.")); + for (byte i=0; i < 9; i++) DEBUG_PRINTF("0x%02X ", data[i]); + DEBUG_PRINT(F(" => ")); + DEBUG_PRINTF("0x%02X\n", OneWire::crc8(data,8)); + } + #endif + switch(sensorFound) { + case 0x10: // DS18S20 has 9-bit precision + result = (data[1] << 8) | data[0]; + retVal = float(result) * 0.5f; + break; + case 0x22: // DS18B20 + case 0x28: // DS1822 + case 0x3B: // DS1825 + case 0x42: // DS28EA00 + result = (data[1]<<4) | (data[0]>>4); // we only need whole part, we will add fraction when returning + if (data[1] & 0x80) result |= 0xF000; // fix negative value + retVal = float(result) + ((data[0] & 0x08) ? 0.5f : 0.0f); + break; + } + } + for (byte i=1; i<9; i++) data[0] &= data[i]; + return data[0]==0xFF ? -127.0f : retVal; } void requestTemperatures() { - readDallas(); + DEBUG_PRINTLN(F("Requesting temperature.")); + oneWire->reset(); + oneWire->skip(); // skip ROM + oneWire->write(0x44,parasite); // request new temperature reading (TODO: parasite would need special handling) lastTemperaturesRequest = millis(); waitingForConversion = true; - DEBUG_PRINTLN(F("Requested temperature.")); } void readTemperature() { @@ -102,10 +122,13 @@ class UsermodTemperature : public Usermod { case 0x3B: // DS1825 case 0x42: // DS28EA00 DEBUG_PRINTLN(F("Sensor found.")); + sensorFound = deviceAddress[0]; + DEBUG_PRINTF("0x%02X\n", sensorFound); return true; } } } + DEBUG_PRINTLN(F("Sensor NOT found.")); return false; } @@ -113,16 +136,16 @@ class UsermodTemperature : public Usermod { void setup() { int retries = 10; + sensorFound = 0; + temperature = -127.0f; // default to -127, DS18B20 only goes down to -50C if (enabled) { // config says we are enabled DEBUG_PRINTLN(F("Allocating temperature pin...")); // pin retrieved from cfg.json (readFromConfig()) prior to running setup() if (temperaturePin >= 0 && pinManager.allocatePin(temperaturePin, true, PinOwner::UM_Temperature)) { oneWire = new OneWire(temperaturePin); - if (!oneWire->reset()) { - sensorFound = false; // resetting 1-Wire bus yielded an error - } else { - while ((sensorFound=findSensor()) && retries--) { + if (oneWire->reset()) { + while (!findSensor() && retries--) { delay(25); // try to find sensor } } @@ -131,7 +154,6 @@ class UsermodTemperature : public Usermod { DEBUG_PRINTLN(F("Temperature pin allocation failed.")); } temperaturePin = -1; // allocation failed - sensorFound = false; } } lastMeasurement = millis() - readingInterval + 10000; @@ -139,8 +161,9 @@ class UsermodTemperature : public Usermod { } void loop() { - if (!enabled || strip.isUpdating()) return; + if (!enabled || !sensorFound || strip.isUpdating()) return; + static uint8_t errorCount = 0; unsigned long now = millis(); // check to see if we are due for taking a measurement @@ -156,20 +179,26 @@ class UsermodTemperature : public Usermod { } // we were waiting for a conversion to complete, have we waited log enough? - if (now - lastTemperaturesRequest >= 100 /* 93.75ms per the datasheet but can be up to 750ms */) { + if (now - lastTemperaturesRequest >= 750 /* 93.75ms per the datasheet but can be up to 750ms */) { readTemperature(); + if (getTemperatureC() < -100.0f) { + if (++errorCount > 10) sensorFound = 0; + lastMeasurement = now - readingInterval + 300; // force new measurement in 300ms + return; + } + errorCount = 0; if (WLED_MQTT_CONNECTED) { char subuf[64]; strcpy(subuf, mqttDeviceTopic); - if (-100 <= temperature) { + if (temperature > -100.0f) { // dont publish super low temperature as the graph will get messed up // the DallasTemperature library returns -127C or -196.6F when problem // reading the sensor strcat_P(subuf, PSTR("/temperature")); - mqtt->publish(subuf, 0, false, String(temperature).c_str()); + mqtt->publish(subuf, 0, false, String(getTemperatureC()).c_str()); strcat_P(subuf, PSTR("_f")); - mqtt->publish(subuf, 0, false, String((float)temperature * 1.8f + 32).c_str()); + mqtt->publish(subuf, 0, false, String(getTemperatureF()).c_str()); } else { // publish something else to indicate status? } @@ -202,13 +231,13 @@ class UsermodTemperature : public Usermod { JsonArray temp = user.createNestedArray(FPSTR(_name)); //temp.add(F("Loaded.")); - if (temperature <= -100.0 || (!sensorFound && temperature == -1.0)) { + if (temperature <= -100.0f) { temp.add(0); temp.add(F(" Sensor Error!")); return; } - temp.add(degC ? temperature : (float)temperature * 1.8f + 32); + temp.add(degC ? getTemperatureC() : getTemperatureF()); if (degC) temp.add(F("°C")); else temp.add(F("°F")); } @@ -252,23 +281,21 @@ class UsermodTemperature : public Usermod { bool readFromConfig(JsonObject &root) { // we look for JSON object: {"Temperature": {"pin": 0, "degC": true}} int8_t newTemperaturePin = temperaturePin; + DEBUG_PRINT(FPSTR(_name)); JsonObject top = root[FPSTR(_name)]; if (top.isNull()) { - DEBUG_PRINT(FPSTR(_name)); DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); return false; } enabled = top[FPSTR(_enabled)] | enabled; newTemperaturePin = top["pin"] | newTemperaturePin; -// newTemperaturePin = min(33,max(-1,(int)newTemperaturePin)); // bounds check degC = top["degC"] | degC; readingInterval = top[FPSTR(_readInterval)] | readingInterval/1000; readingInterval = min(120,max(10,(int)readingInterval)) * 1000; // convert to ms parasite = top[FPSTR(_parasite)] | parasite; - DEBUG_PRINT(FPSTR(_name)); if (!initDone) { // first run: reading from cfg.json temperaturePin = newTemperaturePin; diff --git a/usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h b/usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h index 83f26e084d..210ec3f585 100644 --- a/usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h +++ b/usermods/VL53L0X_gestures/usermod_vl53l0x_gestures.h @@ -21,6 +21,14 @@ #include #include +#ifdef ARDUINO_ARCH_ESP32 + #define HW_PIN_SCL 22 + #define HW_PIN_SDA 21 +#else + #define HW_PIN_SCL 5 + #define HW_PIN_SDA 4 +#endif + #ifndef VL53L0X_MAX_RANGE_MM #define VL53L0X_MAX_RANGE_MM 230 // max height in millimiters to react for motions #endif @@ -42,6 +50,7 @@ class UsermodVL53L0XGestures : public Usermod { //Private class members. You can declare variables and functions only accessible to your usermod here unsigned long lastTime = 0; VL53L0X sensor; + bool enabled = true; bool wasMotionBefore = false; bool isLongMotion = false; @@ -50,6 +59,8 @@ class UsermodVL53L0XGestures : public Usermod { public: void setup() { + PinManagerPinType pins[2] = { { HW_PIN_SCL, true }, { HW_PIN_SDA, true } }; + if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; } Wire.begin(); sensor.setTimeout(150); @@ -63,6 +74,7 @@ class UsermodVL53L0XGestures : public Usermod { void loop() { + if (!enabled || strip.isUpdating()) return; if (millis() - lastTime > VL53L0X_DELAY_MS) { lastTime = millis(); @@ -94,7 +106,7 @@ class UsermodVL53L0XGestures : public Usermod { // set brightness according to range bri = (VL53L0X_MAX_RANGE_MM - max(range, VL53L0X_MIN_RANGE_OFFSET)) * 255 / (VL53L0X_MAX_RANGE_MM - VL53L0X_MIN_RANGE_OFFSET); DEBUG_PRINTF(F("new brightness: %d"), bri); - colorUpdated(1); + stateUpdated(1); } } else if (wasMotionBefore) { //released long dur = millis() - motionStartTime; @@ -110,6 +122,19 @@ class UsermodVL53L0XGestures : public Usermod { } } + /* + * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. + * It will be called by WLED when settings are actually saved (for example, LED settings are saved) + * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! + */ + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject("VL53L0x"); + JsonArray pins = top.createNestedArray("pin"); + pins.add(HW_PIN_SCL); + pins.add(HW_PIN_SDA); + } + /* * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). * This could be used in the future for the system to determine whether your usermod is installed. diff --git a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp index a93b20c994..79241b5e20 100644 --- a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp +++ b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod.cpp @@ -137,9 +137,9 @@ void userLoop() { needRedraw = true; } else if (knownBrightness != bri) { needRedraw = true; - } else if (knownMode != strip.getMode()) { + } else if (knownMode != strip.getMainSegment().mode) { needRedraw = true; - } else if (knownPalette != strip.getSegment(0).palette) { + } else if (knownPalette != strip.getMainSegment().palette) { needRedraw = true; } @@ -163,8 +163,8 @@ void userLoop() { #endif knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownBrightness = bri; - knownMode = strip.getMode(); - knownPalette = strip.getSegment(0).palette; + knownMode = strip.getMainSegment().mode; + knownPalette = strip.getMainSegment().palette; u8x8.clear(); u8x8.setFont(u8x8_font_chroma48medium8_r); diff --git a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp index 15ec58add1..fe53a46283 100644 --- a/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp +++ b/usermods/Wemos_D1_mini+Wemos32_mini_shield/usermod_bme280.cpp @@ -143,9 +143,9 @@ void userLoop() { needRedraw = true; } else if (knownBrightness != bri) { needRedraw = true; - } else if (knownMode != strip.getMode()) { + } else if (knownMode != strip.getMainSegment().mode) { needRedraw = true; - } else if (knownPalette != strip.getSegment(0).palette) { + } else if (knownPalette != strip.getMainSegment().palette) { needRedraw = true; } @@ -169,8 +169,8 @@ void userLoop() { #endif knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownBrightness = bri; - knownMode = strip.getMode(); - knownPalette = strip.getSegment(0).palette; + knownMode = strip.getMainSegment().mode; + knownPalette = strip.getMainSegment().palette; u8x8.clear(); u8x8.setFont(u8x8_font_chroma48medium8_r); diff --git a/usermods/battery_keypad_controller/wled06_usermod.ino b/usermods/battery_keypad_controller/wled06_usermod.ino index acc1bd8c44..b70682b438 100644 --- a/usermods/battery_keypad_controller/wled06_usermod.ino +++ b/usermods/battery_keypad_controller/wled06_usermod.ino @@ -54,35 +54,27 @@ void userLoop() switch (myKey) { case '1': applyPreset(1); - colorUpdated(CALL_MODE_FX_CHANGED); break; case '2': applyPreset(2); - colorUpdated(CALL_MODE_FX_CHANGED); break; case '3': applyPreset(3); - colorUpdated(CALL_MODE_FX_CHANGED); break; case '4': applyPreset(4); - colorUpdated(CALL_MODE_FX_CHANGED); break; case '5': applyPreset(5); - colorUpdated(CALL_MODE_FX_CHANGED); break; case '6': applyPreset(6); - colorUpdated(CALL_MODE_FX_CHANGED); break; case 'A': applyPreset(7); - colorUpdated(CALL_MODE_FX_CHANGED); break; case 'B': applyPreset(8); - colorUpdated(CALL_MODE_FX_CHANGED); break; case '7': diff --git a/usermods/battery_status_basic/usermod_v2_battery_status_basic.h b/usermods/battery_status_basic/usermod_v2_battery_status_basic.h index ab9cba3bc3..cb3c0867ce 100644 --- a/usermods/battery_status_basic/usermod_v2_battery_status_basic.h +++ b/usermods/battery_status_basic/usermod_v2_battery_status_basic.h @@ -21,10 +21,10 @@ #ifndef USERMOD_BATTERY_ADC_PRECISION #ifdef ARDUINO_ARCH_ESP32 // 12 bits - #define USERMOD_BATTERY_ADC_PRECISION 4095.0 + #define USERMOD_BATTERY_ADC_PRECISION 4095.0f #else // 10 bits - #define USERMOD_BATTERY_ADC_PRECISION 1024.0 + #define USERMOD_BATTERY_ADC_PRECISION 1024.0f #endif #endif @@ -39,11 +39,11 @@ // https://batterybro.com/blogs/18650-wholesale-battery-reviews/18852515-when-to-recycle-18650-batteries-and-how-to-start-a-collection-center-in-your-vape-shop // Discharge voltage: 2.5 volt + .1 for personal safety #ifndef USERMOD_BATTERY_MIN_VOLTAGE - #define USERMOD_BATTERY_MIN_VOLTAGE 2.6 + #define USERMOD_BATTERY_MIN_VOLTAGE 2.6f #endif #ifndef USERMOD_BATTERY_MAX_VOLTAGE - #define USERMOD_BATTERY_MAX_VOLTAGE 4.2 + #define USERMOD_BATTERY_MAX_VOLTAGE 4.2f #endif class UsermodBatteryBasic : public Usermod diff --git a/usermods/esp32_multistrip/NpbWrapper.h b/usermods/esp32_multistrip/NpbWrapper.h deleted file mode 100644 index 84cf8ac0d0..0000000000 --- a/usermods/esp32_multistrip/NpbWrapper.h +++ /dev/null @@ -1,515 +0,0 @@ -//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103 -#ifndef NpbWrapper_h -#define NpbWrapper_h - -// make sure we're using esp32 platform -#ifndef ARDUINO_ARCH_ESP32 - #error This version of NbpWrapper.h only works with ESP32 hardware. -#endif - -#ifndef NUM_STRIPS - #error Need to define number of LED strips using build flag -D NUM_STRIPS=4 for 4 LED strips -#endif - -#ifndef PIXEL_COUNTS - #error Need to define pixel counts using build flag -D PIXEL_COUNTS="25, 25, 25, 25" for 4 LED strips with 25 LEDs each -#endif - -#ifndef DATA_PINS - #error Need to define data pins using build flag -D DATA_PINS="1, 2, 3, 4" if LED strips are on data pins 1, 2, 3, and 4 -#endif - -// //PIN CONFIGURATION -#ifndef LEDPIN - #define LEDPIN 1 // Legacy pin def required by some other portions of code. This pin is not used do drive LEDs. -#endif - -#ifndef IRPIN - #define IRPIN -1 //infrared pin (-1 to disable) MagicHome: 4, H801 Wifi: 0 -#endif - -#ifndef RLYPIN - #define RLYPIN -1 //pin for relay, will be set HIGH if LEDs are on (-1 to disable). Also usable for standby leds, triggers,... -#endif - -#ifndef AUXPIN - #define AUXPIN -1 //debug auxiliary output pin (-1 to disable) -#endif - -#ifndef RLYMDE - #define RLYMDE 1 //mode for relay, 0: LOW if LEDs are on 1: HIGH if LEDs are on -#endif - -#include -#include "const.h" - -const uint8_t numStrips = NUM_STRIPS; // max 8 strips allowed on esp32 -const uint16_t pixelCounts[numStrips] = {PIXEL_COUNTS}; // number of pixels on each strip -const uint8_t dataPins[numStrips] = {DATA_PINS}; // change these pins based on your board - -#define PIXELFEATURE3 NeoGrbFeature -#define PIXELFEATURE4 NeoGrbwFeature - -// ESP32 has 8 RMT interfaces available, each of which can drive a strip of pixels -// Convenience #defines for creating NeoPixelBrightnessBus on each RMT interface for both GRB and GRBW LED strips -#define NeoPixelBrightnessBusGrbRmt0 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbRmt1 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbRmt2 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbRmt3 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbRmt4 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbRmt5 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbRmt6 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbRmt7 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbwRmt0 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbwRmt1 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbwRmt2 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbwRmt3 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbwRmt4 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbwRmt5 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbwRmt6 NeoPixelBrightnessBus -#define NeoPixelBrightnessBusGrbwRmt7 NeoPixelBrightnessBus - -enum NeoPixelType -{ - NeoPixelType_None = 0, - NeoPixelType_Grb = 1, - NeoPixelType_Grbw = 2, - NeoPixelType_End = 3 -}; - -class NeoPixelWrapper -{ -public: - NeoPixelWrapper() : - _type(NeoPixelType_None) - { - // On initialization fill in the pixelStripStartIdx array with the beginning index of each strip - // relative to th entire array. - uint16_t totalPixels = 0; - for (uint8_t idx = 0; idx < numStrips; idx++) - { - pixelStripStartIdx[idx] = totalPixels; - totalPixels += pixelCounts[idx]; - } - } - - ~NeoPixelWrapper() - { - cleanup(); - } - - void Begin(NeoPixelType type, uint16_t pixelCount) - { - - cleanup(); - - _type = type; - - switch (_type) - { - case NeoPixelType_Grb: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: pGrb0 = new NeoPixelBrightnessBusGrbRmt0(pixelCounts[idx], dataPins[idx]); pGrb0->Begin(); break; - case 1: pGrb1 = new NeoPixelBrightnessBusGrbRmt1(pixelCounts[idx], dataPins[idx]); pGrb1->Begin(); break; - case 2: pGrb2 = new NeoPixelBrightnessBusGrbRmt2(pixelCounts[idx], dataPins[idx]); pGrb2->Begin(); break; - case 3: pGrb3 = new NeoPixelBrightnessBusGrbRmt3(pixelCounts[idx], dataPins[idx]); pGrb3->Begin(); break; - case 4: pGrb4 = new NeoPixelBrightnessBusGrbRmt4(pixelCounts[idx], dataPins[idx]); pGrb4->Begin(); break; - case 5: pGrb5 = new NeoPixelBrightnessBusGrbRmt5(pixelCounts[idx], dataPins[idx]); pGrb5->Begin(); break; - case 6: pGrb6 = new NeoPixelBrightnessBusGrbRmt6(pixelCounts[idx], dataPins[idx]); pGrb6->Begin(); break; - case 7: pGrb7 = new NeoPixelBrightnessBusGrbRmt7(pixelCounts[idx], dataPins[idx]); pGrb7->Begin(); break; - } - } - break; - } - - case NeoPixelType_Grbw: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: pGrbw0 = new NeoPixelBrightnessBusGrbwRmt0(pixelCounts[idx], dataPins[idx]); pGrbw0->Begin(); break; - case 1: pGrbw1 = new NeoPixelBrightnessBusGrbwRmt1(pixelCounts[idx], dataPins[idx]); pGrbw1->Begin(); break; - case 2: pGrbw2 = new NeoPixelBrightnessBusGrbwRmt2(pixelCounts[idx], dataPins[idx]); pGrbw2->Begin(); break; - case 3: pGrbw3 = new NeoPixelBrightnessBusGrbwRmt3(pixelCounts[idx], dataPins[idx]); pGrbw3->Begin(); break; - case 4: pGrbw4 = new NeoPixelBrightnessBusGrbwRmt4(pixelCounts[idx], dataPins[idx]); pGrbw4->Begin(); break; - case 5: pGrbw5 = new NeoPixelBrightnessBusGrbwRmt5(pixelCounts[idx], dataPins[idx]); pGrbw5->Begin(); break; - case 6: pGrbw6 = new NeoPixelBrightnessBusGrbwRmt6(pixelCounts[idx], dataPins[idx]); pGrbw6->Begin(); break; - case 7: pGrbw7 = new NeoPixelBrightnessBusGrbwRmt7(pixelCounts[idx], dataPins[idx]); pGrbw7->Begin(); break; - } - } - break; - } - } - } - - void Show() - { - switch (_type) - { - case NeoPixelType_Grb: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: pGrb0->Show(); break; - case 1: pGrb1->Show(); break; - case 2: pGrb2->Show(); break; - case 3: pGrb3->Show(); break; - case 4: pGrb4->Show(); break; - case 5: pGrb5->Show(); break; - case 6: pGrb6->Show(); break; - case 7: pGrb7->Show(); break; - } - } - break; - } - case NeoPixelType_Grbw: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: pGrbw0->Show(); break; - case 1: pGrbw1->Show(); break; - case 2: pGrbw2->Show(); break; - case 3: pGrbw3->Show(); break; - case 4: pGrbw4->Show(); break; - case 5: pGrbw5->Show(); break; - case 6: pGrbw6->Show(); break; - case 7: pGrbw7->Show(); break; - } - } - break; - } - } - } - - bool CanShow() - { - bool canShow = true; - switch (_type) - { - case NeoPixelType_Grb: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: canShow &= pGrb0->CanShow(); break; - case 1: canShow &= pGrb1->CanShow(); break; - case 2: canShow &= pGrb2->CanShow(); break; - case 3: canShow &= pGrb3->CanShow(); break; - case 4: canShow &= pGrb4->CanShow(); break; - case 5: canShow &= pGrb5->CanShow(); break; - case 6: canShow &= pGrb6->CanShow(); break; - case 7: canShow &= pGrb7->CanShow(); break; - } - } - break; - } - case NeoPixelType_Grbw: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: canShow &= pGrbw0->CanShow(); break; - case 1: canShow &= pGrbw1->CanShow(); break; - case 2: canShow &= pGrbw2->CanShow(); break; - case 3: canShow &= pGrbw3->CanShow(); break; - case 4: canShow &= pGrbw4->CanShow(); break; - case 5: canShow &= pGrbw5->CanShow(); break; - case 6: canShow &= pGrbw6->CanShow(); break; - case 7: canShow &= pGrbw7->CanShow(); break; - } - } - break; - } - } - return canShow; - } - - void SetPixelColorRaw(uint16_t indexPixel, RgbwColor c) - { - // figure out which strip this pixel index is on - uint8_t stripIdx = 0; - for (uint8_t idx = 0; idx < numStrips; idx++) - { - if (indexPixel >= pixelStripStartIdx[idx]) - { - stripIdx = idx; - } - else - { - break; - } - } - // subtract strip start index so we're addressing just this strip instead of all pixels on all strips - indexPixel -= pixelStripStartIdx[stripIdx]; - switch (_type) - { - case NeoPixelType_Grb: - { - RgbColor rgb = RgbColor(c.R, c.G, c.B); - switch (stripIdx) - { - case 0: pGrb0->SetPixelColor(indexPixel, rgb); break; - case 1: pGrb1->SetPixelColor(indexPixel, rgb); break; - case 2: pGrb2->SetPixelColor(indexPixel, rgb); break; - case 3: pGrb3->SetPixelColor(indexPixel, rgb); break; - case 4: pGrb4->SetPixelColor(indexPixel, rgb); break; - case 5: pGrb5->SetPixelColor(indexPixel, rgb); break; - case 6: pGrb6->SetPixelColor(indexPixel, rgb); break; - case 7: pGrb7->SetPixelColor(indexPixel, rgb); break; - } - break; - } - case NeoPixelType_Grbw: - { - switch (stripIdx) - { - case 0: pGrbw0->SetPixelColor(indexPixel, c); break; - case 1: pGrbw1->SetPixelColor(indexPixel, c); break; - case 2: pGrbw2->SetPixelColor(indexPixel, c); break; - case 3: pGrbw3->SetPixelColor(indexPixel, c); break; - case 4: pGrbw4->SetPixelColor(indexPixel, c); break; - case 5: pGrbw5->SetPixelColor(indexPixel, c); break; - case 6: pGrbw6->SetPixelColor(indexPixel, c); break; - case 7: pGrbw7->SetPixelColor(indexPixel, c); break; - } - break; - } - } - } - - void SetPixelColor(uint16_t indexPixel, RgbwColor c) - { - /* - Set pixel color with necessary color order conversion. - */ - - RgbwColor col; - - uint8_t co = _colorOrder; - #ifdef COLOR_ORDER_OVERRIDE - if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER; - #endif - - //reorder channels to selected order - switch (co) - { - case 0: col.G = c.G; col.R = c.R; col.B = c.B; break; //0 = GRB, default - case 1: col.G = c.R; col.R = c.G; col.B = c.B; break; //1 = RGB, common for WS2811 - case 2: col.G = c.B; col.R = c.R; col.B = c.G; break; //2 = BRG - case 3: col.G = c.R; col.R = c.B; col.B = c.G; break; //3 = RBG - case 4: col.G = c.B; col.R = c.G; col.B = c.R; break; //4 = BGR - default: col.G = c.G; col.R = c.B; col.B = c.R; break; //5 = GBR - } - col.W = c.W; - - SetPixelColorRaw(indexPixel, col); - } - - void SetBrightness(byte b) - { - switch (_type) - { - case NeoPixelType_Grb: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: pGrb0->SetBrightness(b); break; - case 1: pGrb1->SetBrightness(b); break; - case 2: pGrb2->SetBrightness(b); break; - case 3: pGrb3->SetBrightness(b); break; - case 4: pGrb4->SetBrightness(b); break; - case 5: pGrb5->SetBrightness(b); break; - case 6: pGrb6->SetBrightness(b); break; - case 7: pGrb7->SetBrightness(b); break; - } - } - break; - } - case NeoPixelType_Grbw: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: pGrbw0->SetBrightness(b); break; - case 1: pGrbw1->SetBrightness(b); break; - case 2: pGrbw2->SetBrightness(b); break; - case 3: pGrbw3->SetBrightness(b); break; - case 4: pGrbw4->SetBrightness(b); break; - case 5: pGrbw5->SetBrightness(b); break; - case 6: pGrbw6->SetBrightness(b); break; - case 7: pGrbw7->SetBrightness(b); break; - } - } - break; - } - } - } - - void SetColorOrder(byte colorOrder) - { - _colorOrder = colorOrder; - } - - uint8_t GetColorOrder() - { - return _colorOrder; - } - - RgbwColor GetPixelColorRaw(uint16_t indexPixel) const - { - // figure out which strip this pixel index is on - uint8_t stripIdx = 0; - for (uint8_t idx = 0; idx < numStrips; idx++) - { - if (indexPixel >= pixelStripStartIdx[idx]) - { - stripIdx = idx; - } - else - { - break; - } - } - // subtract strip start index so we're addressing just this strip instead of all pixels on all strips - indexPixel -= pixelStripStartIdx[stripIdx]; - switch (_type) - { - case NeoPixelType_Grb: - { - switch (stripIdx) - { - case 0: return pGrb0->GetPixelColor(indexPixel); - case 1: return pGrb1->GetPixelColor(indexPixel); - case 2: return pGrb2->GetPixelColor(indexPixel); - case 3: return pGrb3->GetPixelColor(indexPixel); - case 4: return pGrb4->GetPixelColor(indexPixel); - case 5: return pGrb5->GetPixelColor(indexPixel); - case 6: return pGrb6->GetPixelColor(indexPixel); - case 7: return pGrb7->GetPixelColor(indexPixel); - } - break; - } - case NeoPixelType_Grbw: - switch (stripIdx) - { - case 0: return pGrbw0->GetPixelColor(indexPixel); - case 1: return pGrbw1->GetPixelColor(indexPixel); - case 2: return pGrbw2->GetPixelColor(indexPixel); - case 3: return pGrbw3->GetPixelColor(indexPixel); - case 4: return pGrbw4->GetPixelColor(indexPixel); - case 5: return pGrbw5->GetPixelColor(indexPixel); - case 6: return pGrbw6->GetPixelColor(indexPixel); - case 7: return pGrbw7->GetPixelColor(indexPixel); - } - break; - } - return 0; - } - - // NOTE: Due to feature differences, some support RGBW but the method name - // here needs to be unique, thus GetPixeColorRgbw - uint32_t GetPixelColorRgbw(uint16_t indexPixel) const - { - RgbwColor col = GetPixelColorRaw(indexPixel); - uint8_t co = _colorOrder; - #ifdef COLOR_ORDER_OVERRIDE - if (indexPixel >= COO_MIN && indexPixel < COO_MAX) co = COO_ORDER; - #endif - - switch (co) - { - // W G R B - case 0: return ((col.W << 24) | (col.G << 8) | (col.R << 16) | (col.B)); //0 = GRB, default - case 1: return ((col.W << 24) | (col.R << 8) | (col.G << 16) | (col.B)); //1 = RGB, common for WS2811 - case 2: return ((col.W << 24) | (col.B << 8) | (col.R << 16) | (col.G)); //2 = BRG - case 3: return ((col.W << 24) | (col.B << 8) | (col.G << 16) | (col.R)); //3 = RBG - case 4: return ((col.W << 24) | (col.R << 8) | (col.B << 16) | (col.G)); //4 = BGR - case 5: return ((col.W << 24) | (col.G << 8) | (col.B << 16) | (col.R)); //5 = GBR - } - - return 0; - - } - - -private: - NeoPixelType _type; - byte _colorOrder = 0; - - uint16_t pixelStripStartIdx[numStrips]; - - // pointers for every possible type for up to 8 strips - NeoPixelBrightnessBusGrbRmt0 *pGrb0; - NeoPixelBrightnessBusGrbRmt1 *pGrb1; - NeoPixelBrightnessBusGrbRmt2 *pGrb2; - NeoPixelBrightnessBusGrbRmt3 *pGrb3; - NeoPixelBrightnessBusGrbRmt4 *pGrb4; - NeoPixelBrightnessBusGrbRmt5 *pGrb5; - NeoPixelBrightnessBusGrbRmt6 *pGrb6; - NeoPixelBrightnessBusGrbRmt7 *pGrb7; - NeoPixelBrightnessBusGrbwRmt0 *pGrbw0; - NeoPixelBrightnessBusGrbwRmt1 *pGrbw1; - NeoPixelBrightnessBusGrbwRmt2 *pGrbw2; - NeoPixelBrightnessBusGrbwRmt3 *pGrbw3; - NeoPixelBrightnessBusGrbwRmt4 *pGrbw4; - NeoPixelBrightnessBusGrbwRmt5 *pGrbw5; - NeoPixelBrightnessBusGrbwRmt6 *pGrbw6; - NeoPixelBrightnessBusGrbwRmt7 *pGrbw7; - - void cleanup() - { - switch (_type) - { - case NeoPixelType_Grb: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: delete pGrb0; pGrb0 = NULL; break; - case 1: delete pGrb1; pGrb1 = NULL; break; - case 2: delete pGrb2; pGrb2 = NULL; break; - case 3: delete pGrb3; pGrb3 = NULL; break; - case 4: delete pGrb4; pGrb4 = NULL; break; - case 5: delete pGrb5; pGrb5 = NULL; break; - case 6: delete pGrb6; pGrb6 = NULL; break; - case 7: delete pGrb7; pGrb7 = NULL; break; - } - } - break; - } - case NeoPixelType_Grbw: - { - for (uint8_t idx = 0; idx < numStrips; idx++) - { - switch (idx) - { - case 0: delete pGrbw0; pGrbw0 = NULL; break; - case 1: delete pGrbw1; pGrbw1 = NULL; break; - case 2: delete pGrbw2; pGrbw2 = NULL; break; - case 3: delete pGrbw3; pGrbw3 = NULL; break; - case 4: delete pGrbw4; pGrbw4 = NULL; break; - case 5: delete pGrbw5; pGrbw5 = NULL; break; - case 6: delete pGrbw6; pGrbw6 = NULL; break; - case 7: delete pGrbw7; pGrbw7 = NULL; break; - } - } - } - } - } -}; -#endif diff --git a/usermods/esp32_multistrip/README.md b/usermods/esp32_multistrip/README.md deleted file mode 100644 index 87b895284b..0000000000 --- a/usermods/esp32_multistrip/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# esp32_multistrip - -This usermod enables up to 8 data pins to be used from an esp32 module to drive separate LED strands. This only works with one-wire LEDs like the WS2812. - -The esp32 RMT hardware is used for data output. See here for hardware driver implementation details: https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods#neoesp32rmt-methods - -Pass the following variables to the compiler as build flags: - - - `ESP32_MULTISTRIP` - - Define this to use usermod NpbWrapper.h instead of default one in WLED. - - `NUM_STRIPS` - - Number of strips in use - - `PIXEL_COUNTS` - - List of pixel counts in each strip - - `DATA_PINS` - - List of data pins each strip is attached to. There may be board-specific restrictions on which pins can be used for RTM. - -From the perspective of WLED software, the LEDs are addressed as one long strand. The modified NbpWrapper.h file addresses the appropriate strand from the overall LED index based on the number of LEDs defined in each strand. - -See `platformio_override.ini` for example configuration. - -Tested on low cost ESP-WROOM-32 dev boards from Amazon, such as those sold by KeeYees. diff --git a/usermods/esp32_multistrip/platformio_override.ini b/usermods/esp32_multistrip/platformio_override.ini deleted file mode 100644 index afdef67667..0000000000 --- a/usermods/esp32_multistrip/platformio_override.ini +++ /dev/null @@ -1,16 +0,0 @@ -; Example platformio_override.ini that shows how to configure your environment to use the multistrip usermod. -; Copy this file to the base wled directory that contains platformio.ini. -; Multistrip requires ESP32 because it has many more pins that can be used as LED outputs. -; Need to define NUM_STRIPS, PIXEL_COUNTS, and DATA_PINS as shown below. - -[platformio] -default_envs = esp32_multistrip - -[env:esp32_multistrip] -extends=env:esp32dev -build_flags = ${env:esp32dev.build_flags} - -D ESP32_MULTISTRIP ; define this variable to use ESP32_MULTISTRIP usermod - -D NUM_STRIPS=4 ; number of pixel strips in use - -D PIXEL_COUNTS="50, 50, 50, 50" ; number of pixels in each strip - -D DATA_PINS="25, 26, 32, 33" ; esp32 pins used for each pixel strip. available pins depends on esp32 module. - \ No newline at end of file diff --git a/usermods/mpu6050_imu/usermod_mpu6050_imu.h b/usermods/mpu6050_imu/usermod_mpu6050_imu.h index 965ab41b9e..4aa2a128fb 100644 --- a/usermods/mpu6050_imu/usermod_mpu6050_imu.h +++ b/usermods/mpu6050_imu/usermod_mpu6050_imu.h @@ -42,6 +42,14 @@ #include "Wire.h" #endif +#ifdef ARDUINO_ARCH_ESP32 + #define HW_PIN_SCL 22 + #define HW_PIN_SDA 21 +#else + #define HW_PIN_SCL 5 + #define HW_PIN_SDA 4 +#endif + // ================================================================ // === INTERRUPT DETECTION ROUTINE === // ================================================================ @@ -55,7 +63,8 @@ void IRAM_ATTR dmpDataReady() { class MPU6050Driver : public Usermod { private: MPU6050 mpu; - + bool enabled = true; + // MPU control/status vars bool dmpReady = false; // set true if DMP init was successful uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU @@ -84,6 +93,8 @@ class MPU6050Driver : public Usermod { * setup() is called once at boot. WiFi is not yet connected at this point. */ void setup() { + PinManagerPinType pins[2] = { { HW_PIN_SCL, true }, { HW_PIN_SDA, true } }; + if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; } // join I2C bus (I2Cdev library doesn't do this automatically) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); @@ -93,16 +104,16 @@ class MPU6050Driver : public Usermod { #endif // initialize device - Serial.println(F("Initializing I2C devices...")); + DEBUG_PRINTLN(F("Initializing I2C devices...")); mpu.initialize(); pinMode(INTERRUPT_PIN, INPUT); // verify connection - Serial.println(F("Testing device connections...")); - Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed")); + DEBUG_PRINTLN(F("Testing device connections...")); + DEBUG_PRINTLN(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed")); // load and configure the DMP - Serial.println(F("Initializing DMP...")); + DEBUG_PRINTLN(F("Initializing DMP...")); devStatus = mpu.dmpInitialize(); // supply your own gyro offsets here, scaled for min sensitivity @@ -114,16 +125,16 @@ class MPU6050Driver : public Usermod { // make sure it worked (returns 0 if so) if (devStatus == 0) { // turn on the DMP, now that it's ready - Serial.println(F("Enabling DMP...")); + DEBUG_PRINTLN(F("Enabling DMP...")); mpu.setDMPEnabled(true); // enable Arduino interrupt detection - Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)...")); + DEBUG_PRINTLN(F("Enabling interrupt detection (Arduino external interrupt 0)...")); attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus(); // set our DMP Ready flag so the main loop() function knows it's okay to use it - Serial.println(F("DMP ready! Waiting for first interrupt...")); + DEBUG_PRINTLN(F("DMP ready! Waiting for first interrupt...")); dmpReady = true; // get expected DMP packet size for later comparison @@ -133,9 +144,9 @@ class MPU6050Driver : public Usermod { // 1 = initial memory load failed // 2 = DMP configuration updates failed // (if it's going to break, usually the code will be 1) - Serial.print(F("DMP Initialization failed (code ")); - Serial.print(devStatus); - Serial.println(F(")")); + DEBUG_PRINT(F("DMP Initialization failed (code ")); + DEBUG_PRINT(devStatus); + DEBUG_PRINTLN(F(")")); } } @@ -144,7 +155,7 @@ class MPU6050Driver : public Usermod { * Use it to initialize network interfaces */ void connected() { - //Serial.println("Connected to WiFi!"); + //DEBUG_PRINTLN("Connected to WiFi!"); } @@ -153,7 +164,7 @@ class MPU6050Driver : public Usermod { */ void loop() { // if programming failed, don't try to do anything - if (!dmpReady) return; + if (!enabled || !dmpReady || strip.isUpdating()) return; // wait for MPU interrupt or extra packet(s) available if (!mpuInterrupt && fifoCount < packetSize) return; @@ -169,7 +180,7 @@ class MPU6050Driver : public Usermod { if ((mpuIntStatus & 0x10) || fifoCount == 1024) { // reset so we can continue cleanly mpu.resetFIFO(); - Serial.println(F("FIFO overflow!")); + DEBUG_PRINTLN(F("FIFO overflow!")); // otherwise, check for DMP data ready interrupt (this should happen frequently) } else if (mpuIntStatus & 0x02) { @@ -259,10 +270,23 @@ class MPU6050Driver : public Usermod { */ void readFromJsonState(JsonObject& root) { - //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); + //if (root["bri"] == 255) DEBUG_PRINTLN(F("Don't burn down your garage!")); + } + + + /* + * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. + * It will be called by WLED when settings are actually saved (for example, LED settings are saved) + * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! + */ + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject("MPU6050_IMU"); + JsonArray pins = top.createNestedArray("pin"); + pins.add(HW_PIN_SCL); + pins.add(HW_PIN_SDA); } - - + /* * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). */ diff --git a/usermods/mqtt_switch_v2/README.md b/usermods/mqtt_switch_v2/README.md index dc0e259fb5..148e4a5643 100644 --- a/usermods/mqtt_switch_v2/README.md +++ b/usermods/mqtt_switch_v2/README.md @@ -1,3 +1,7 @@ +# DEPRECATION NOTICE +This usermod is deprecated and no longer maintained. It will be removed in a future WLED release. Please use usermod multi_relay which has more features. + + # MQTT controllable switches This usermod allows controlling switches (e.g. relays) via MQTT. diff --git a/usermods/mqtt_switch_v2/usermod_mqtt_switch.h b/usermods/mqtt_switch_v2/usermod_mqtt_switch.h index 40241206d4..67dfc9cc08 100644 --- a/usermods/mqtt_switch_v2/usermod_mqtt_switch.h +++ b/usermods/mqtt_switch_v2/usermod_mqtt_switch.h @@ -1,5 +1,7 @@ #pragma once +#warning "This usermod is deprecated and no longer maintained. It will be removed in a future WLED release. Please use usermod multi_relay which has more features." + #include "wled.h" #ifndef WLED_ENABLE_MQTT #error "This user mod requires MQTT to be enabled." diff --git a/usermods/multi_relay/readme.md b/usermods/multi_relay/readme.md index ebf2056a87..2d933cdabe 100644 --- a/usermods/multi_relay/readme.md +++ b/usermods/multi_relay/readme.md @@ -5,38 +5,42 @@ This usermod-v2 modification allows the connection of multiple relays each with ## HTTP API All responses are returned as JSON. -Status Request: `http://[device-ip]/relays` -Switch Command: `http://[device-ip]/relays?switch=1,0,1,1` +* Status Request: `http://[device-ip]/relays` +* Switch Command: `http://[device-ip]/relays?switch=1,0,1,1` + The number of numbers behind the switch parameter must correspond to the number of relays. The number 1 switches the relay on. The number 0 switches the relay off. -Toggle Command: `http://[device-ip]/relays?toggle=1,0,1,1` +* Toggle Command: `http://[device-ip]/relays?toggle=1,0,1,1` + The number of numbers behind the parameter switch must correspond to the number of relays. The number 1 causes a toggling of the relay. The number 0 leaves the state of the device. Examples -1. 4 relays at all, relay 2 will be toggled: `http://[device-ip]/relays?toggle=0,1,0,0` -2. 3 relays at all, relay 1&3 will be switched on: `http://[device-ip]/relays?switch=1,0,1` +1. total of 4 relays, relay 2 will be toggled: `http://[device-ip]/relays?toggle=0,1,0,0` +2. total of 3 relays, relay 1&3 will be switched on: `http://[device-ip]/relays?switch=1,0,1` ## JSON API You can switch relay state using the following JSON object transmitted to: `http://[device-ip]/json` + Switch relay 0 on: `{"MultiRelay":{"relay":0,"on":true}}` + Switch relay4 3 & 4 off: `{"MultiRelay":[{"relay":2,"on":false},{"relay":3,"on":false}]}` ## MQTT API -wled/deviceMAC/relay/0/command on|off|toggle -wled/deviceMAC/relay/1/command on|off|toggle +* `wled`/_deviceMAC_/`relay`/`0`/`command` `on`|`off`|`toggle` +* `wled`/_deviceMAC_/`relay`/`1`/`command` `on`|`off`|`toggle` When relay is switched it will publish a message: -wled/deviceMAC/relay/0 on|off +* `wled`/_deviceMAC_/`relay`/`0` `on`|`off` ## Usermod installation 1. Register the usermod by adding `#include "../usermods/multi_relay/usermod_multi_relay.h"` at the top and `usermods.add(new MultiRelay());` at the bottom of `usermods_list.cpp`. or -2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY`in your platformio.ini +2. Use `#define USERMOD_MULTI_RELAY` in wled.h or `-D USERMOD_MULTI_RELAY` in your platformio.ini You can override the default maximum number (4) of relays by defining MULTI_RELAY_MAX_RELAYS. @@ -76,10 +80,21 @@ void registerUsermods() Usermod can be configured in Usermods settings page. +* `enabled` - enable/disable usermod +* `pin` - GPIO pin where relay is attached to ESP +* `delay-s` - delay in seconds after on/off command is received +* `active-high` - toggle high/low activation of relay (can be used to reverse relay states) +* `external` - if enabled WLED does not control relay, it can only be triggered by external command (MQTT, HTTP, JSON or button) +* `button` - button (from LED Settings) that controls this relay + If there is no MultiRelay section, just save current configuration and re-open Usermods settings page. Have fun - @blazoncek ## Change log 2021-04 -* First implementation. \ No newline at end of file +* First implementation. + +2021-11 +* Added information about dynamic configuration options +* Added button support. \ No newline at end of file diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index 9a92d4e221..6143a6b997 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -45,6 +45,11 @@ class MultiRelay : public Usermod { // status of initialisation bool initDone = false; + bool HAautodiscovery = false; + + uint16_t periodicBroadcastSec = 60; + unsigned long lastBroadcast = 0; + // strings to reduce flash memory usage (used more than twice) static const char _name[]; static const char _enabled[]; @@ -53,14 +58,15 @@ class MultiRelay : public Usermod { static const char _activeHigh[]; static const char _external[]; static const char _button[]; + static const char _broadcast[]; + static const char _HAautodiscovery[]; - - void publishMqtt(const char* state, int relay) { + void publishMqtt(int relay) { //Check if MQTT Connected, otherwise it will crash the 8266 if (WLED_MQTT_CONNECTED){ char subuf[64]; sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay); - mqtt->publish(subuf, 0, false, state); + mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off"); } } @@ -68,15 +74,19 @@ class MultiRelay : public Usermod { * switch off the strip if the delay has elapsed */ void handleOffTimer() { + unsigned long now = millis(); bool activeRelays = false; for (uint8_t i=0; i 0 && millis() - _switchTimerStart > (_relay[i].delay*1000)) { + if (_relay[i].active && _switchTimerStart > 0 && now - _switchTimerStart > (_relay[i].delay*1000)) { if (!_relay[i].external) toggleRelay(i); _relay[i].active = false; + } else if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) { + if (_relay[i].pin>=0) publishMqtt(i); } activeRelays = activeRelays || _relay[i].active; } if (!activeRelays) _switchTimerStart = 0; + if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) lastBroadcast = now; } /** @@ -105,7 +115,7 @@ class MultiRelay : public Usermod { for (int i=0; ivalue(), ',', i); if (value==-1) { - error = F("There must be as much arugments as relays"); + error = F("There must be as many arguments as relays"); } else { // Switch if (_relay[i].external) switchRelay(i, (bool)value); @@ -118,7 +128,7 @@ class MultiRelay : public Usermod { for (int i=0;ivalue(), ',', i); if (value==-1) { - error = F("There must be as mutch arugments as relays"); + error = F("There must be as many arguments as relays"); } else { // Toggle if (value && _relay[i].external) toggleRelay(i); @@ -199,7 +209,7 @@ class MultiRelay : public Usermod { _relay[relay].state = mode; pinMode(_relay[relay].pin, OUTPUT); digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode); - publishMqtt(mode ? "on" : "off", relay); + publishMqtt(relay); } /** @@ -252,6 +262,50 @@ class MultiRelay : public Usermod { strcpy(subuf, mqttDeviceTopic); strcat_P(subuf, PSTR("/relay/#")); mqtt->subscribe(subuf, 0); + if (HAautodiscovery) publishHomeAssistantAutodiscovery(); + for (uint8_t i=0; i= 0 && _relay[i].external) { + StaticJsonDocument<1024> json; + sprintf_P(buf, PSTR("%s Switch %d"), serverDescription, i); //max length: 33 + 8 + 3 = 44 + json[F("name")] = buf; + + sprintf_P(buf, PSTR("%s/relay/%d"), mqttDeviceTopic, i); //max length: 33 + 7 + 3 = 43 + json["~"] = buf; + strcat_P(buf, PSTR("/command")); + mqtt->subscribe(buf, 0); + + json[F("stat_t")] = "~"; + json[F("cmd_t")] = F("~/command"); + json[F("pl_off")] = F("off"); + json[F("pl_on")] = F("on"); + json[F("uniq_id")] = uid; + + strcpy(buf, mqttDeviceTopic); //max length: 33 + 7 = 40 + strcat_P(buf, PSTR("/status")); + json[F("avty_t")] = buf; + json[F("pl_avail")] = F("online"); + json[F("pl_not_avail")] = F("offline"); + //TODO: dev + payload_size = serializeJson(json, json_str); + } else { + //Unpublish disabled or internal relays + json_str[0] = 0; + payload_size = 0; + } + sprintf_P(buf, PSTR("homeassistant/switch/%s/config"), uid); + mqtt->publish(buf, 0, true, json_str, payload_size); } } @@ -266,7 +320,7 @@ class MultiRelay : public Usermod { if (!pinManager.allocatePin(_relay[i].pin,true, PinOwner::UM_MultiRelay)) { _relay[i].pin = -1; // allocation failed } else { - if (!_relay[i].external) _relay[i].state = offMode; + if (!_relay[i].external) _relay[i].state = !offMode; switchRelay(i, _relay[i].state); _relay[i].active = false; } @@ -313,13 +367,18 @@ class MultiRelay : public Usermod { */ bool handleButton(uint8_t b) { yield(); - if (buttonType[b] == BTN_TYPE_NONE || buttonType[b] == BTN_TYPE_RESERVED || buttonType[b] == BTN_TYPE_PIR_SENSOR || buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) { + if (!enabled + || buttonType[b] == BTN_TYPE_NONE + || buttonType[b] == BTN_TYPE_RESERVED + || buttonType[b] == BTN_TYPE_PIR_SENSOR + || buttonType[b] == BTN_TYPE_ANALOG + || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) { return false; } bool handled = false; for (uint8_t i=0; i 600) { //long press + //longPressAction(b); //not exposed + //handled = false; //use if you want to pass to default behaviour buttonLongPressed[b] = true; } @@ -371,7 +432,8 @@ class MultiRelay : public Usermod { if (!buttonLongPressed[b]) { //short press // if this is second release within 350ms it is a double press (buttonWaitTime!=0) if (doublePress) { - //doublePressAction(b); + //doublePressAction(b); //not exposed + //handled = false; //use if you want to pass to default behaviour } else { buttonWaitTime[b] = now; } @@ -379,9 +441,10 @@ class MultiRelay : public Usermod { buttonPressedBefore[b] = false; buttonLongPressed[b] = false; } - // if 450ms elapsed since last press/release it is a short press + // if 350ms elapsed since last press/release it is a short press if (buttonWaitTime[b] && now - buttonWaitTime[b] > 350 && !buttonPressedBefore[b]) { buttonWaitTime[b] = 0; + //shortPressAction(b); //not exposed for (uint8_t i=0; i=0 && _relay[i].button == b) { toggleRelay(i); @@ -477,6 +540,7 @@ class MultiRelay : public Usermod { JsonObject top = root.createNestedObject(FPSTR(_name)); top[FPSTR(_enabled)] = enabled; + top[FPSTR(_broadcast)] = periodicBroadcastSec; for (uint8_t i=0; i=0 && pinManager.allocatePin(_relay[i].pin, true, PinOwner::UM_MultiRelay)) { if (!_relay[i].external) { - switchRelay(i, offMode); + _relay[i].state = !offMode; + switchRelay(i, _relay[i].state); + _oldMode = offMode; } } else { _relay[i].pin = -1; @@ -549,7 +619,7 @@ class MultiRelay : public Usermod { DEBUG_PRINTLN(F(" config (re)loaded.")); } // use "return !top["newestParameter"].isNull();" when updating Usermod with new features - return !top[F("relay-0")][FPSTR(_button)].isNull(); + return !top[FPSTR(_broadcast)].isNull(); } /** @@ -570,3 +640,5 @@ const char MultiRelay::_delay_str[] PROGMEM = "delay-s"; const char MultiRelay::_activeHigh[] PROGMEM = "active-high"; const char MultiRelay::_external[] PROGMEM = "external"; const char MultiRelay::_button[] PROGMEM = "button"; +const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec"; +const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery"; diff --git a/usermods/quinled_digquad_preassembled_unofficial_v0.1/README.md b/usermods/quinled_digquad_preassembled_unofficial_v0.1/README.md deleted file mode 100644 index 39ae4edd11..0000000000 --- a/usermods/quinled_digquad_preassembled_unofficial_v0.1/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# QuinLED-Dig-Quad Preassembled Unofficial Build - -This usermod targets the [Preassembled QuinLED-Dig-Quad](https://quinled.info/pre-assembled-quinled-dig-quad/). Tested on board revision v1r6b, -and includes the following features: - - * **Multi-channel Support** - enabling use of LED1, LED2, LED3, LED4 pins to work using segments - * **Temperature Sensor Support** - pulls readings from the built-in temperature sensor and adds the reading to the *Info* page in the UI - -## Background - -As a starting point, you should check out this awesome video from Quindor: [How to compile WLED yourself](https://quinled.info/2020/12/22/livestream-wled-compile/). The usermod you are reading now just provides some shortcuts for parts of what were covered in that video. - -## Build Firmware with Multi-channel and Temp Support - -1. Copy the `platformio_override.ini` file to the project's root directory -1. If using VS Code with the PlatformIO plugin like in the video, you will now see this new project task listed in the PLATFORMIO panel at the bottom as `env:QL-DigQuad-Pre-v0.1` (you probably need to hit the refresh button) - - - -1. Edit this file from the root directory as needed: - - - - * `PIXEL_COUNTS` may need to be adjusted for your set-up. E.g. I have lots of LEDs in Channel 1, but that's probably unusual for most - * `DATA_PINS` may need to be changed to "16,3,1,26" instead of "16,1,3,26" apparently depending on the board revision or some such - -1. Build the mod (e.g. click `Build` from the project task circled above) and update your firmware using the `QL-DigQuad-Pre-v0.1` file, e.g. using _Manual OTA_ from the Config menu. Based on the video and my own experience, you might need to build twice 🤷‍♂️. - -## Observing Temperature - -Hopefully you can now see the Temperature listed in the Info page. If not, use Chrome Developer Tools to find the current temperature - -1. Open the Developer Tools Console -2. Enter `lastinfo.u.Temperature` to view the Temperature array - - - diff --git a/usermods/quinled_digquad_preassembled_unofficial_v0.1/images/json-temp.png b/usermods/quinled_digquad_preassembled_unofficial_v0.1/images/json-temp.png deleted file mode 100644 index 66e50112331c7801ff7e28f1087c761de94537d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 302754 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

B01AC;^PYLryI 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

)hqj9nZd1-N+|> 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

?s*l@Uhtc<0QhHq9{HMy( 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 diff --git a/usermods/quinled_digquad_preassembled_unofficial_v0.1/images/params.png b/usermods/quinled_digquad_preassembled_unofficial_v0.1/images/params.png deleted file mode 100644 index 64233f86bfb2c65856dd67e88367144040557320..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 70379 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�__ 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%0AyK*GjacL!Tdo%h{!*e-$b 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

rJNyb2r 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

QKjnygU?NfYK|v8%h^i`d5igMzmfz5_ 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%0DU-|HHpq1K3;8b z2C>Ae^Xtfzhh5STL%ZM`c1uNnWU@mirAWLNjnnHJo0Ae`j>isKlAz}8^*#-G->R`h%%`Qu-2BQaRmK_EGN>@a||-Nq8&eP+(#o9Zz$(8C8A@ z)(6kxMBaZ_3D!}Kvq!LRcQzJeLKy0tMCenI{3BL?bxe6oafIt=p&nQZ@f4pspQKWg zfYuU0dk<^#*o5VO6Wi7XEU9^A);;3^u=n~7+2=M<X`Ye0FTc5Nv=>_c5XA4rVr0W} zF6sA`zWu?w_pW?*rV}#drgJA5OSbRE-!dS4H<(_bQ>gwf1t*eLh{m7m5lV_ngTorS zB0f3G{vZ3rM%s#bSrLObTVF%HTIRRZBy-->q6e@~U5n0fVjd!*M0!cdJ{SH&uRJ0A zaJh^^^eo+9lw~3tDdV8g4tPV>lZ;!8P*wrekvYO=(B*n@mv%W&uPpu_Dt;{FaG&w1ig8D9s4&*5Z-;G1%W@gF=wki z+7AzQMpXjg#9GYmy8EkC@ykF*ZcAfbUg8w6ZyF40pRMN3ME3A#unpNa9_recu4r;h z#T$7zCqM~>IhNyHCNfn(1iI(9jOgxUSBd@K_l+2Qvl7-5(4z8po*xBo;6i3~Gp4EB z+|bPGtB9P_OWpcR%Z!}Yporw`bH{74LQk!1ge0iER?RS-n{|S^a(Vi`K&;vZK>bw? zZNUxP!FSL)QNWdJYwz%|g>~Pd)xX5;Q19%x<5_k<_SDjeh{+g&3_s)sY){WNTF&)Q zdgflhS3}&x%Xvw1ILHXWW16&a65F;abaw=+*fjX{sR<|_tuee-la@?EVe`NBZtPmJ z(q9>-Bk*l_O@8UqHhXEF8$Jys-b>z?%HbrU{`YlU=#K=iM;v8SLPJP`KOggS^nWER zisvjp8upYcZVGbf*vcrG+nivfIr$B`zm7;W(eA8jKnXGw`*D*irJ&! z*M?DjV!;BKv^*hdg#lf!AW_HxhbEjzJb{<3`AJNeu!}fF)Aq3Tya`%)Um}i>Q=hUv zNTEp5hkejt=HotrXKESiEp?kfGVo>10*6{;LhCpeD{h>?%rD^m7#5`m=r3bFrWmV_ zlOq*={b?>guQwppn`I8xCbSRjUcrTZvQ@r4(~3Wygg{bU7C+P%h3+GK1KE-dd4VG_ zH(>t1M!q;fiYe7A|F%D8bsf5w9J97MD7y_dcNQ#?D2V=u6PkXR85eWzdUmhzUY`tB zEWY@WkHBlDTLDJ9gucU%?~eycZX9%m_GZ}T>kyTsCmq(hy>>4KkZ5LIND;A4;_mlr zXl)Wl<^)@d^n};nXx55Pm@eQ=tpX`@y4=HXbu4>eLDyxL+J7Wn%NoM-=>0x8?nN#+ z^kh|A@tMaveZQ&SW#33yxi4dF)$^*V%3Jp)09K$`zqQvA_g;nV+N+a6+nvx;Rbfqm$T;CQU(vGEML zLEuTz>=w7UodUmS^DafTWik5R1w=UWM41N~lZVUle%pn=G;P?pJ_UEEDG3D;yNMK| zVm2$eOf97`)wS9Y_sk z>P&C{)*cUk0}tS$#rOEcd@y|#D~g$3);r__7mDnGv3h%CC9>B zF~XS|HnMx)CQ5>(+2Bh0JJ&cbn!8d?5HwH4X{m4fWpMNV{)FUs&Blv($Ea+U2guHxA$kaLq6UE*fJcQnU*C8iyQ8!hFKvWb43ra*D2CpmpnEm(FSJ8KU7oy^d>SW&&*RsXt!whylaKR2u97&o!8?fQ;gc$ zZ$Y~CN<~@T3Ct5}e2^W`U_DQm^*eGCs&hjFALK-dM;`KsV_|D@k{Lxjc1z7oJPZrA z#k+>O@&<;8uYtwAS4PN}U|9E0gHKDe)axOi%{iW{;G!?@%Q=&Oz*yLk0Sfyp&@(FEnoBWOGbS z;qj8Xt5_C0v`+&K*e%e_xTMI$XrFf|6v$&mj37HrC>EIu z5d~&^C=SCk29BkOzi+#!$CtP7b7%ZBSs+(nF*G-@jC}Di^2>FNw79JnIIbq1U^Io(#hF>*)iIBGNuvYAeWFd|wJkerQ95!IW zKU!tBGv+)%whJf^!>6*n?4p?eb3E%Fcl~^KG2&M$1GOcEK1R`G`OkOe02<-3XPnwV zb4sJgQ~*a?kQ-S~X~g=^d}qGS{j9GZ-gbbAOLjujxn>L! zVAc1SH|{==ewnv#->UUc_&dBwVkN)v_h6w*0$eR2{%GV_+>}#?FVL&xZ-v zvD&vrBZC-{ROcQ)njx^K^z5>MhkBRyOZB?v`Jkau)b z4wU#HRxkgnQMB8aWW0w=AXU%PLKzn6tn~%M#KCDgL2xReLIbfI3#I0gMYnz?oL6(5 z&`w0R!L>^9{&=I~3Y^JSc{WHv2Nic?*Toy+qP*B#9U|RthG9aY{x9bHLosI_-(!D! zi2gb5bU*`yq*YkvrAY+Cu*j+u(ti3}6euvv!b8~OLDSN-d9o`$JqE4_R&K4xaYsKq z*rI=%0wYnO$vM-}1(S?r$KlO{lI}%PEXis;Be~quysO||!G|-guG5F*IpeYT`qe?n3l) z4ez!(H>ryR-%X>U`g&u_;h^RG{I5sy zW2--vj=X(`a1Z7szjBFab87iw43d>%Uqu(F>~H@pr^B9ny@k#6+P6E6+pa)LLeJd%Y9H znW%NEBh)n0$0E(&pn@l?`EK9NZ@}s@^Xh5GXG`HUtQ){jyUUB`yi@t8sEOA|xS5E@ zg7K2t;TTo4Ncy@TZR283jK#ry>_X!*I7x}TIarml4~~62;qg39o!0D0SRwT)wLZod z(-2dCi=6~|D%g{OT8l|)%=i>0KASjJ!Q=46Sdy#9Lc~p6VZ==ya$*txe5ee8NUIWd z;)x0}amu~zk&iZ;Rr$yW`l;oF%`)C#=K8l- zT}LD7`9DAFz2EgWD-756ywzP4=#OEU5>hZ=BG45rS|q@FI+#;?ieL~4r0h?5q& z*M8FZD5Nh)2b;lXBnwKJS}vDiUHlUb%Ob=fQ`gLIOY%3HVvD1XtZn7-ND6=@)BBcw zo*z_0BHu_4T}j|hQqT&EZu__c6_}uYK}KFBa8V$W@tnTc)!W%Zh8L0Yr4lxkzC-^b z|L{Uw%dpDToucDfj~(S$b{3^8qyi{*d%hs{li=(3W6f8RWcw(Yu2iLfi#~L!pCB zxt#YIy)PovkD2GRt131}F8XZk+pXLP337y-$}@zF6EY41crqRj->q=uw0yfhO&$Ce zSU8lk|Hk8BNJzuRrmKNT270+Sp|5^hieAX8As!}YI$Q8l05QxjqeuS!^4KD%^LQ?L zLoGj`tKlFBM8Oc}5c}Hwmxb)91Ryqsy>a>%inYoYiE#of>k(3Dp-*a*V=^nzt6(|q zy(%QWV-va&XO(jU=X>th)6r!4Vw##tCZcs;D~o)S=2s<#rDmV?eRZREz*am)@fVn z#6wgoNT@4M5hRN}eu$EZT~A>ArYGw^kuFq_Y6{k9O+gHkpm52q6fS?pe3y@jtsEn~ z6SujEvJG)?5zA85)i*iq4egZ7K%Cx*T_?!9rzf0H(y`rDZk|)gB9Qp!Y53=f;3U$# zurk}{F;71E{1Zivz@a3AW1G0<&X&HG&)3IeD8#B>j!$n7Z!mqw%$KL0>NC~h+v0%P zrTb~-RjysLsm0+ej>VwA4vVI@<~79iZyNZ{7ahHR% zVNzJJgXLkF`RWmDITb)R6~ViZ;4(OF^-H|MbuZ`^*!kfz*0~at!yfP6sSsw(B8OSv zGZ}99ubT4kZ`G*qLicX{_nanM4Y?MH+AirJ>+zbZ>N)zrW6L89O~=HB8ttX2rKuv` zj^Qvs-ykZ!lXyWYsSAin1I0jOwq2pKs-u(pIJ2p{_i9L6-!(JlDY%2+9tK)Kis%*5 z?x2c^l9}GX?(LLgx?v#6MwO;=kyKA*C}R@dna?TEOTYeEZVXJ>_R&D7sfA%nS>I=3 zHCVzz5wpTp6+=1wl^7w-O6MdYg85j&8!15=!d3cc>;A{Xlg%S<`AWF^2Iw@7A9b%N zk$#wn{`Xh^^Xtc~a%X={*YibBpC9yMBzRd&+Jtra-MOb_ygGhabNOrfQe}LnPHRna zmbgrQZRy>mK#X{#>Q7EKk7JW_zndn2TRav}oLPyr}Eo6W*4<_J5`R zT%QY8pz)2-!qUgTtINRB?A&;+HN0@L_%$ zu&&OAhgZAiEN2|X{m>~7<$QkJH6rIpAnnr&JbTHQRRgJ_9RtPH-rSfmiyP@?z4;%+ zs|v}KP%R7Iq;bJZLq8dMJp8u=QAXdW5Jf(t>n$*tMvO~K^{Z&JtKnnCqK{2H6QZ=( z`Oae19j?;-Rc>u&6yr0xM=#DH^iHbM^GJ%bB>q1iv-qg60M1X8w>lD3>V;~*C#@=r z{W7M`8Y~o!8mtubC0_KHsncLsR}68-WJMxuJkVG6a)(~38VWWj8Y_*s2&f6**oa?= z8S8&W`jLZ#M;_kokxhRoW4mSDNM--R0E1v^Bd@!Vlkx_O(gGz@hD7!)2^A)+HleXJ zic>R*&rs(=ol@YFKn^Fbp`eEZWQj9AAG7ciC+rfj*D?x;V#8cHeR!02;puS)=V|Yn z8Rcrich@3{i+sn0r-t=DUxO@P);DsF7R_!RfP#j;xtsi)7zYsgl3nFXO=dLv?`oqe z1&#F8UG`09Zx(T(Isq!n{J1IOmiLxY-c16Mg5eziD=&a?P36vlcVpheJW5R(N_mH? z{`e3frY#4{UD<$F78lvCowXEW^Jyz=trBYYu{U2(V+Q}C{Y(_1kSQ~Ruh*xs)W-p_ zj_BFK_?{nOjCnwTJ$)Y7_ z*&ibLgql@3o2UTzMU5pa2h(19Oflrx0FC)fHWHXRN>YuA)e2L9zgehGj(fKA_U0r> z+0@YJY)=bJc|+>-{U+_$n1AXWfiprapaa%{ImS=Ut7RwKNlTfYbA#2+@Pi=O-TpTP z{W;4TP<_EW#XD6{_7T+4p3ehSPP0jH-o55uT~8cncYn{9{FazE07S>-q3K+!v%_0w z{+}&Ac$Y5|#iepy!1m~G=_ZiW+QMPqj(ph}I>#}6_m8jrF zVx=(Ojb)_$uD$NMJBm|C(aT)5`u`mqG4f3E0UO`0g|bFVx-4oStnX_GCuyu z2?DFipG~M_Zu6KI1TC)ey{on>s5S}%xTZ8a0H1RbgZQk`3yjx~f2y-Af&c#UBH%K8 zy#Qn%w1;+VSm$2{)~;1d0l4saAHDHBAi-2QuRMtxZ}i|e&lkGw!yt4lse`DSrdBWc z^8YT)2f~^!)!Nn%>mLl|4qlC$9}9JX6A{+~%qY(4iB^FiHA!;_tY2qSncUJ>z0|SJ zB~9G(3qWU+){FXgha-leDhm||s;VPC)S{aQDzY7*5qh6@6Wi5-^`H*)Yt)ju&a~0> zKJ-XOaADQu{c{lfp$TPfJ9^X&MGHK%*Fb)?+%7MOFWa88tc;?!`kWq6u|;pf1^Q9q zsc)pScM5$>0u2$a+UpIkS0(W_zKC~P2n})=8d0eB7(C(s60uF3i;aC_sd7 z0rUgTDTNl`E((Axu{>$tGjfjv>E8)&2)-u}wFY{CQjA(bpQ|((UdeB&v;YUCaBw;; zIrFhbXMYbcI_e_S!)}09GJm@Q^DA95(@fP!c3ydmU(ZFvrOgQ8^{l;ET`UF<8d5s| zN60-;Io;YGZ#AgM^L7ckHIkn#HUuFYgSpw*g5$u??3QAm`?(ssEqcdA#~dF#H^k!p zL)9eGhqu{|C8Txeg1D(V41f&8}hTx|3}8U@ZQbCCNhrd!Q=I8PR>6MP>!tv9$#bZB^vuWfD*vaKenH=UqL>8fT&CD4CKl(sz>or9D$)5E{%TjJtvls@Pq_!ggaEwo@aOMPqO{F40wlUx zEjJKfpZxi5+6QRI;eSFfh_ASgB!9Qk-TKVg)adF0Zt8y2v;-M*YEn`f?PrVeZ)Ph1 z9@Ok|y;o6kij4Mnzo=?T+ZOz=(}VZzoq1MO6VuA0-~Q$u7(C7orl$v3V8%;hiLpCC z)-x;rGmb|#0nnM;WCgw{NqIFfr2KqS2ONxS09f^6 z;>_=u8xP{E-8Dr2j=#rKtcVHgJRBK%yR7r>Z#~$+WDM}0qa4+dg7I^;`q8IQGVa@# zs1*nGEp8dM_1~{=PFP8{!JBayDGVSR14w&B?^^&^v*x#L!zCZu1L=!A5&!;$9|p5d z!THefq0HW!hkeu~(emt2Lp0ZVqZcrf+m5Kt&wv)=cTC_N-v$x3j?jIr}1+j#c?F7n{Y{dZ$s$b5V`8 zClTd&>W)9PI{4=DdU6Jy^1dInF--~mV4m#}62O~P7g3db+E=sqG2UUuF!Yk+-B$gi zhTZ!~`|#O^7Vyzeq6?rNcx!oUXYMpeZ0`X^*S39UJ70UqdH1y1j@f*pgJW=kGmr`>ewIh)GdIHRdE?rZY_aT3d)UmQ0 z`};5r?!Y>bA&VpzD|8q93}9CvJ=)f;lcvj$6@CBylC(Jym>j`7_9uP?_k<4b^f>g8 zZn4xCqy`*2QocO~utp<+I!j9aF$P{4m~pAs~A95Uht;R>$O*-At+IayrQ zaa^Qq%uj!+>vKBEG_6^r_LFn;s|^0TgKF7dciq z7+svngR?3GHEuFP*rT-Wb7ZAaoCl77(yHM6WBW)g&A-;_Jv{eNPMW>2Gqx4+i@yjBa*euV^lHH<;iB?0m%UZXDvW z)SODphMWW-w_d){3wma#DWR>vb7Tu4vU=TF?^V~1i4Y#-=hCH9R1XUV8ML!LfhKVYL8I%7bZo@l?9qRFwtYgRj|N| z8}3GSbiDStTv_+t>*MKy;Y_v3G9Xtv7VS!^=Ln{z{k{N|E^99ik%<-WcJ=Qqb8x3p zT5dM@+`wC;76DqUAjUxn?v4z<}p{OR6oN6@jLuYTYGDh!)>8$O1qo(>+CUqb+& z>^_#!>@ZTqZ*H`qfA9G{DKqWAB3Q3JbV=R(Sj0u?J`g;hV}4>;d|hi={l!Y@hg)LZsk(6qf+($MtPF>u7#Bf%q$w z;{sNgCj z>w}`Sba(?e)ZKL0Ivp1b@CEDWx)@h;vaKDpE|M8g_ z;6%Q#_0jxT)rZ0I8>@I%AW8^yKAJR<;vH8E^I0**SwB<0zq>ncq4&@H%rX3`W93_P zBv0;jI6b`6L63C^^yPg`#n1thm$Q`353K_$IrrXepd?8vK7GCQl+>fiOMh=z@H#Wj z=DWL3OE+=hZErj^MqG#g*I?Ag^D`E9!=(qEgogaU;ss+AN{qN?`iY?P z6*Pp?xPbyhHEkqfpRzi9mT4eTA50f<)nv`g>Rx}2WT{-!n$c}iTz${wTN{MDRFT9` zH1zpzeKjg>b4~iMIkKb*x(us^{c4UgFoB#F2{6ZTd|Vmmct^?qGT4lgX^^EvjbV|Pht+8kn!3$?$ zjQl&2gX;_6_?iT}$=x@9$u>>>^AT_fA81*~%8* zcFR6HT6e;D0Qxxp`g`ptXXAjEXWeEK96Ua?^f^%tkW^(`*?)JYs)|r9;*yOi>&C*u zarf6X@M(`?iJ$ccHFX>dmQ_2om*e#Ha~MR|ztk|!e>ZA1dk1X2o0hx#bNQqiXI4WE zW4W$dkRR*N-iD;0$=G=*>1eU%W9Filq(HA>9k~Rgo68hCJFGG~pH|{g6pY;W!caN( z4Bpt0r?i-6;jx1&bI|VNDI$2Z+!RhP{PCf6k7I@*=eh@)aO?8wacC2vX2|zj*G@@> zS$968ndNM@J5>{O!v4bHqb?ccwg7L3*04DH%~fpYK$(|!?NHV<qY%`Xn(M5l=ufBo+pw7vS6f;}7HcG4@##2I6kkupK>@ zqLH@O8OWM|g=7N-%$1kIyi>Z|iG%{~y~;it0U4|hpzFL)?QUhL{Gub zz2loyHMi~nV{$HX6?nYl>qGS3N8)3_>>%v*eW!>WO_^K^q-xbR=5kzHP-WYcXM>^vratr#b{VLF?L;r^58~>ZEHN}!JWRA`Z1K@=_+DUm zvS_?@D2sh~(&Dd|%r&wb*Du+|A#YCq)GudkhO8ffgM3CVjjgTmPPOG-jqL&OcX8*T zctB3TBhG`6!>nsE?=MN!sp)@&yj$rMZFA6cu172iM>l6i%JM$$Xu0NEIC!x?INAAn3&IkKAr%`q@few&<)0+Lk7Fz3e8P6c!WpPmiB zzkh!DHeKl=9h(nlZfIA{l_zO3Us5_uz2J1+n+BERg8=Z>R4kLqLMemz8IO5+EBjLi zOlbbF^HN?ytK67?EAG8N!ml^Tq$czj%g;K5W0$0*n7ItsB1S=dS&s)M2;CYucExGMx^c$@jerxi%fEvAvp!PoWc1 zp77`Nf4LDaNmlj}+M4nzV>W^ScBEs*OOoxY`O^b42N>MD15GahM3oyda1k8+-h&$| ze|@@3|58hI$F}jP+w7_5$_M;G<3o@gtH@J(SxFK3^@G3h+%hRb8#NlYfd6|FT~N;< z%`Z!{{J59E`U1Yf?J*F{vY#yZv$2NKSTp5Ke`za$L@+%?#u|Hy2t9bax|Zk1xEpCQ zVyHg4x3Dj5gy+xUH*bWDU(_Vwj1>e%Aa>THjuG)DN>ck9v-J1kD&;s%(&oJKMx0px z;IbVwC+C*Q-Y1Im=W9$$fr4P_&eeOwJyG6u{AkUs{#ZO2jDto2O*;8ZP0mZE2ny!k z|M9GycPhO{CY|_2rYNxdpf+S!Y`pQ9cgPw%%`fsAaT6Yruqk3P?xKxluv0qdHK+Hv@=Jju)Z zEObuA5{EU3YT#Zw?10@HvqtE;S{SpwGE1uX1rCx22#4PnCw=@5)$h`Nc67haCY&i3 zfHG`t^fI$#%$F(YNcWjl?+O&(f;i`A8^O>jY#vAMK4W!HmlosKlF1)}8?+A>n+EHn znFOr5tM2ZAJj@=+PrT)jG=)rl^II>e_E40yIZbOCRtm}kI*OJ+6fcW^BT1zw({ImR zzjydPJeNRgo2!+bz<0o18Eg7G@=EkeETi`DaOTF>b5&M=X=bjibxjb=ZY1#Fc5U4| zyx&zX)a`kp%{Fao^*dXo~tNlNW#yB%jibaE5RaWjB)}=?oG-ADM;E zK=+A-Ub_GOXl}p;DO_GZO=r1QV{U)8BLBrFF+7P6$8=AYJ9@{Pyxhi-Ev|Zx0^QZe z1aUjynLcN;ecI0bE0L;kVDF0cd1xUF?VRyZ&66Bu`lt?8H`j~S)E|YTVaQ0H zwe4(D%)6hIWBxq*k@kjlw-L=n3uYIwR`y@(o6{j7_nwE-S{v=h&_7kvXRui&(w_Y* z(2H^o+vV67_oooVp9+d4(VE)x+q9}0g>8z1evzV_?R|?xmZHb~5|Maj7k(Ejl0s$h zWaQ!p_nRvoOpI0y$U%oQz0n-A|G3{c;z1ja%p4uiJCI_hW4nT z8>JAXo*g&G?qRoX4Mws06B`9etMBk1)Q;;q_I23;pmLSW#-MO$XEVfWe{w1&FwYM1 z(G=7Bzbt?pdpB3^Y+!*ak?Uk5gdUZz5>$=|4%8MyGb!|jH3vjj_x_^vi$<$1y~6#Z z`TpYWk7j-)w|z-xGPZCGJxYorL*Q}cH>3Lc_qi)bFJ7bE=M>Jq*KODk_g!#rq9bnL z;+~x2fo6fnrcmO>iF4P~{ZMO#0ahjn23a$t)hiDVXtoy?7){--q3U~o&)thS<{4JG~N^(Sk9DNHTdW)$nxIcv1 zkdhu&NMq$o2r2*7@k1CgI>6E(uq8p7T-O71haqSe0urJY+Fwvma*ezZvN`PZ+a_pl z-fF$tqN2jaKgCuQHty_O{g=USkcguIgJ|M>YR|K}PNLVXpE0ZBOBYz<@Ast2O8rAm zK=CYr8ST-yJpaNfCA?`hf(g%VRmtf{tQEJ~%U#*RVIAy#D#B6eTp+No8PEeJ&hRdc-9cn!j?+1ugN?y+KTOw+%rh1(5fqaLE)*1CHZz`qWTF1EWw4>r(d1RBiwhJK-7nI5=h620kr^YB@A(ykaQwIoC?A(y=x!nvZ z)F?=t;|P5D5`Ceee8E_h8&qEblAtP|@2!gDLk!0<2g{1rQ5BhN^5|E4I5}U?Yu9SL z+~v>#A|ht5qBmM@ zHv)vjMFE`WW61Lzbw2_{*vR^k4Xz&?aaUx?1DW)q+GHG^o=0EAqXmguRcg=BG6c2@7cYHlD z=Ci}_KW+6f5D^0y5@*lTXc;<^r!?1 zxn_qCp@QO1lXz>lTY_ z596HQ;e?Py1Sk@LW_Kh^c=(G&@oO&;!iWlq42-}s_lKB;D_0N0RK1Ipu^}V5K_+b! zGXT^l$XN5@E)#TUN&Ve@7>wXNSYR|9(p~9s@#Tj_*i$C&|$kHBb>E8DKd>! zwZI6zfRUiy1-1Gui%QkvWD+16j!lH(-!KTvk~#EKet1ql6#DH7j7+yneU1urOyO;; z*3mj+&(D9M#}g(z54o(DMn&gm5q#vNvV-LqrZP-h2X~0yq>Az0`BCv>ts-gyiBjO1 zjS%(M)_cC|IDj{hLaf#rZ|Cc-e5^b4^40oAPe)i}dLvv`?5OMCToZ+5E*pkHA3~HU zI*~MoMSlg~ynTMDy3u|?K(Y)J#Kw!Yy2=(;-l78`S)-a#t+;HU-zBuHWI;fQ~H2Wv&yT^gP%cR;S zM&ME8!gASXj)P5SB7v{3Xz6KO{md(Ligti{lwpI@BM~}F_tlxz@Rp4wvgx?=4~*p1 zsIR#J5?$B(62)_$zLFTqoJ4w`m0%1FlN)LBZB|m)QHerId&`&TJn=czZ@w$= zI_v~+&~`|^kS9B(h3c_{2~5(tvP)Ec@p7{d zskpm}X%6yGNA0ynQ8U-H@H{e51WvLo?4#3T5>V5A!TKNTSFS9EJ+o=87UtHx2>Q2L z&6eKa_dqY!m5o5;i{P4hUg1>6W@+$v0x~7k&E!upl?*k4%oM$dHI91*hrVlT2oCsO z-su*H`pF1;X}_F7;Gl@P+2~#A>@8_g>z5-iGqP!fVfDB)&DbQn=ocEKgCa>KVf;b* zdE{Co-1dA$Z-aMI?l@$}D6}x%i9Afx_VO>3RWR5FCF@1%8Ep=`)PA8td$Xlb$HqO{ zBPP+TPl0?2S~C`?YSf%hgz&Q@ksLM($JfJ`QGb6%uUn@Sbwr8JYqsAb6aywevg)s> z2nT3n{gD!l6Em0br>uL{(X@1_&$4HQb=2LDP~*n2k-{dRNlxf$-jsOzYvF+p_UIo0 zNR#qTxXUDkRui+iA$Q@cmcUFzJsFZi;2;8;t$Z5ABl8?x`lR^Ua@%5gmWD$qCglE&~R0VzxH~DAeqJV(U$@3Ff_Yb4` z|6Z!`NRS2QZ3EOEFim`Kj59R~nyuay`&^%GP7Q}t0_TSPvr~$QXrcmNqSl5KTw&)Y zQm5m>$qQw0L!$d%6c-Aw5)~a<`3RKK@C2nS`cz5#!$d2g*}?cYtd~>)N1S)TsRDB$ z?Sf1;k8cK$`X?DSIwu_-6-Ie>T8L#SZ}q`Wo~AOpXqKZW;o;e=)+3Nty|SSc-R}qr zPZy{npQ2__&PmcUqf~c}F*UfQmV8-ymPty9u--`GU=iDZz*-SY&HaCDZ;CItAOz;J zRBI4}H@n)r{mHas$+MM(+Rr%_oxz;C^?1Uc?GvOLPVVz|P3SA?2h+9;LqUs`F)WTJ zkvJimiD$|9{YSImI;-$6M{yh+{gi*wcZ&ithsJVUnl4Xl0BRQXYoC*JY4S` zbBsRJ$; z(_SE`{qg_p)vY%KR$ZFH+6SjDp6~x~>XyhYTu{t>*X=+4wIRA^+b;pTzjb+ie(*PX ze(%M(%gOG~eY~IQ9Y3qze=6i~D=&P#k5+T_1vXD46sskerGxa7+p4+_)QB3FSO4A4 zH-3N-;kro;|Hw)s{NHy<(F0?-I;JW!?;Q^)7Vg<*%Txg04d9z8*BU}NAX)04bBwXt zm?^Bq_1bVDvwASKJ=K6l@=PO<2VOh>LIF-Jsce7uu=@h28O_u00KRh-SIX>QsB?t< z7t{a&qk6{_N-H{yFp(F357FqWTY>X3gVvOZH0XSNdu;#C{hImp9TIr8--Ci+L*l z`o8}gVOXx4_2I4D-5}F&0+DSMyLcu31FCtY zCmLi-AVj{J>1mg;V??>uiTvMW?Wlwu{#(lv(Czi9J-zblcvGv1^AxnBYh#}k019~ZonFH}#HagDE>>cm9x8?CW3V9kp%typ z49*MvYL!odUi+_^NTSbiWBUUYN5CbdCU@CLht)p`pz_HNfxk~INAl*DAuNB4<`q_UZ7j~bx(k5$@TA0W8bp&{~&BOsImk< z4a73=uDab$^g%74wdR4y_lcd8zr(+Eeb(y0Y^(Lut_JLMW`O=|$-wKt@II;f^Ia_b z&3XW!)dP9e^lrQG5;yJBRQ;GghYC6tb-1KVE3X+3|9iH+m-C^Yf4Yx-S-bDg8*2_v z0~1PGFvig7m^{bdy12R8vmZaO{W<$1A@0)fy$i`LHxWd>-80JFOj%tB(@t0Q*61IXyDd-b%fmDn{IlY4( zkjM$IgJZnpc-puo6X5AZ-sfW;)$#`XwQqWBS-%~m z1l+d#f2Gygi8QU1XR6Gs>1kd07bT^&r}ORo(Q}U6`kfy=OSo&RA-^q&zT9G%Svq;7 zlV)<5U8e>phZ!)MY#NytGav?wzJ1h%MyE$cpxSK-(nC@qJQjfoBbb(2h0Yg~-s0QY zKrI-|GB0jSRfpFD_Tu{N?Bp?*RzP>jRw=Dfyb3Av%?j{KTpaEOr5_U}@Y_b{-gw4YlG}&8+p9=eE_9!M;@&m0AAAmW z2YyEUk!z8dh@r%3^SP1iVXQn3@qgjx1kyqTx%f_N{we5(@OiD}T|RK`BFU->d&$5Z zQ6#nb7(W}YHlqlJLtwADkmfZ@;k1~~9#Nzu$$36TvlGv(cGczAQlY4P{~u6L4etD{ ztUAZ#ASicT-njM}fgE-BN4ZgXyGV&`YqanJfJqHS4L74-Q89H~?zH@gXV-YKwp&~| zaLRjh;>7x=CLFl#jWQ$^fqZqy)scHnRLs5Gg{{4nR|gY&=T2b@%&1KTx|Th z@9K38cO-lVMbGxLlsNWy&`CcDt_2F5Ky_A%J8a=y>946z0w~alWm~^w+Aj(M#nkZ} zz*6{JEg$T5c2#^Yf+*T~Rr75d7jde9jj;W7?tHZnLiB z;?UtCS_R$_@9TqaYV!{pO^ci6O`~Uj-ADTH7{w7y32v9Q&H{jO?Gyj(XnB#iW()v5 zT2??+^K-k({!g`F+tpF;*tFn2^-o%(7Z1MU2_96MO7&;Ke{aKW-kUJk75(dM?noB> z%YNt3yZvo`T*WHX+US zhl|wR08(XcflIx_i@sWMezhqOL3b)|zeeyu7MALpAL#hNYnFm?yr1$k$ZGLz`QDP!qa`PM%qS7G&%8Ry zi0{BmKzo7V*%m0?dg}e-AXfHQncW1Zmudlm{z~!Hnz)Ax##d4tMbZlwnaEe1Vyp4k z%?j%^Aq?V*ucHyJ5rSSZQ{6d9*IKnx%!)rtkK^88cAV2!&{GB!33rBae_MLaW6~C4 zMp~h>RW&fFHZRWS`fJ*90IpvoR@kG|rIYzNJu~q?#2WPi?5XyYaqy0kJ>DGXu+cxp zrW)@B8b%JCmqU%-BCrquEJ9C#eToM1gJ4|sGGBSr9Jb;@g8$MS)LGz6je zV4=ecY;2jhg2TCXZPT`O7;X&f-8>UN^%nfXL{AufLyq$nOE3%w|+DB(0yjE z^#1k&Ae*Q|dnn1W_q_73X^?&=aMX(?$ZxM*(CU3gim!X&X=Ukcq<;b!N^83W10^?c zh?{M~InXXnv~}VO;8mSO*U65HRJ>XM`|gY*19b=;uvbwPi*Xr9yy=X>t_Ssp;;@eW z15pWnuD2l!{yiA0#qH_*wr?=H3R+(@Z{%m$S>MQ8G8nAP*1HSnFKp60_u%JPP42X; z2E(U1fJ;8Ue_kwQvIKv4lqywxVK^)ybT<6MR@YOR+G8b_O_XK*r|0RU<<;wFnQpgU z$#chhe3|wl+dNSU{0hB~%rkAj&iT6YDX+JBS_NI7sE}TauE%*TsZNO57N-BV)PvG$^X^~WkCL&htV)=N zbb%|~?;`2=J{lc-W;xs-%221KarHxt$-B>xQ#NOd$@6>Mw-RS4K%pV_5TUK_I^sR; zOmBe;?t5!k4@{=YsGres^@+{Ti_P7ob>^CK@j;b@+zJ=%r1WR@8hOxLmd<1xB{}uv z$rHz9L!Z>2D|Wl?Zs^gmBCSEfm4U;w-fgXr2{l)D&^ixWDNX}B;sH0~P;5FA4YKd$ z9h;eF za*_H_uWDY&bmn@VthU6KC#`LDiJ^&I$b5{=jWUUuzXs!(MiNDFc^;X7^-M?_pS7Jx zdDH2X10g5Z@m7E5^zLS2V(ELz@PkJJMyL~9NF6|eepw&vV6Cmh4Nw-Nuh+%DKk)Zt z(wg`}rg{N7+J#WGN%Mf-`Uzzo*N0ThWR%7HDb)DQKL}kZZ$uvdRhbdlYp~{l_Gsxj z<{EAe^_eY6;-74}OE2+f^1P~ zeV}o+C&S%9#Tolg-5PjnwKpMDjx9&{PsYCAVRi@Vrwm9o`x z8abOs`_)pIVxmFvsx6MsOb6A3{=Z@+S;rY3_f)?6>`pG&j#aezq>{GVr}~f7V#b_ z|FqemQb2W+``+BkBr22Ijv~4oKnHau87|PraV>UBq3=`_T&;_vCo@waf11F}Sttu4 ztmgC8Uei2Nd&oR^PvN2%Bk^W>r3UX^_N+{n8Mii^^+Dx5RS*XOt*nVEBJ5n*9IvLl zA7)h9&(Aeki#;78q?Pptd;z16RWG4tWcS$z7&cQph0RhOpdNLafUlY})WE7m>2%N7 z``>P08ufwB{7q+c@w>VwS&f^YZ2rmq{QC#fuE*EVo$ANdl0_ud>buhNsI=?hBewp3 z?NOS)u=Zs}a%cvj2u&o`ax4i6sULu0^eYOCw8=UOxcspkIp?yiOe)gmX?k(3xTv1m zE$c^PHX$TwNS)a){Aaoq#)3NupU zAx9-I zR+L<>_(WVck$fe#?{{Q$?e0T*GYgSo`hsCO!AB0 z`SE(;Ay9!1X5s={et3n6wjb6xo)iASV>fB+mE(9Q4QZ^lu0!^nuAtB9mYhvcKcTG; zl-og`secW6@9GGD6cHNK!$N^`HJ|;%Ov~cQzTkaGYj5!L15n6dMjFB18yl56)b_D$ z1?mml8=l)wNjYK^K3YPJ(n1BW%KS`|T*~%jE_J+yo@1wyw}E($okD9(bXZmEV~qH3 z0bYg`#Csos8LwFkdrC?`OW!rI{B&pf&vAPWN1Zsha8-nATOH2-ij-m$-Mt|re82*`3jjCnu0QQ zA|1jzAn4%B2<_BstB?s<$9?hXREKKdT!j=9;^pz@ARSUHbsX;5N%04WDfUv4L6L;j z0b%Qp;v;#^wR6u)CmukA9Rms77sU@zzAcG4&9OwTbcZ3Wq(N=1Rh#tDH7hN!0{kTm z?=Gg2x|~IZ==V8NUyIcv~D!27ch*O7wSS)(9{cdF zBCbO6xsWNsJxnnhpvXA7ZSH^ztWkD;UNT8T(LZd5iHT>F0!!zvJx5Wj;@3Z(ik7@(M!A zwz-FhvQTkk-ra>Ofox33oY&Q)8#L z%f%dYLTZTSa4pQ*R-j~6@j+$6GFaB}m8N<<7aCLxd0t#B0Wzu9Bain)nU|NY)}%7#%o=zl6;@-r@*lc%-1+F|Q*wp{yIyP!o^Cg| z|A|6+@9$k}+C9+_*OKBZL!E*-Va7S`OeiPhaKkjYm>CUN(kS>Ru^-3lMyX)n;`awa z>KXAm3S@?+sW1u2eHe&n*sr6Y6%do8_lFU;k&PYq^c@crRsph=`+28xWI5#^xe}sc zh6o4){!lHyNXp(%GiUb!Nta9W=&R|<1EA?ETPKVUhL|(8nB$cbV4=<4HuDmiSP=oy zmcr56@?-!t`zF{YI{@kU_tw|z;2rR@oK6-CNXyi+ET_N-)W}pS(-QSXVY08Z1&`L~1S(wi79qJyCY+0NGB=loWBn&rs-B}>%-KS&`Mcc*Eg&oHZ* zg)rd-IS>ncu9}69Um;F)D5=BG{=%PJ)3Fh}>4*TwZp3bl@+wBWo`2Et4yd`;MypMr zid8X0{LtV`!nh!y&#e3D9|qV`zeSS>kHG%SU;P7{*>)_!m8E)=lN|+D8pT!+Z5UG5ftHKLv{|ZR9#Flfs=g zaDBv>4eGR~#Q!~mZ412#5exK(NC=l8LDKWo;2C8!UO$Qf+ozEWxSI|j`q9cSA8BCY zLuBZqKDYFK#2qAfC``fq=Pa7>nSPzi!Ii;vE25lYnTB<74cNDo>_0V z+CSV9wjMe_$dejTea2^5uhI7?35|C5VTlfvC?4B}-x1gJoLfegzZH5i_!#ok)>-l; z|I$DF#g7EgjxP=c_=B`bL}AIRs)}?HiY|vG>zN*nhned%2WuZvh~EAw$xsrMQMF?& z2=k@CG3D;0yIY+9A;aMj=gvwiAt8#o2U4w=&O;N{64ph;AL!51osH*%WK8BUBYhck zeo~f8@S^b?hrT*X{sQec8DsQW3MZe$QSSbt7Uh>7+|)3Q{Kb5|WMN5fq${b|I{_sz zMAv6L8aug$l~}B|Qu~`hi}d=Ij(`2t!Wi_qpVD={LHP&JG7!?%ZW=wr!CtM-_l_lJ zkrgs0c1psAT4=B9f9rie;a*JZyw-P^_BrD%AEiLCh>zeX|-`-HXip9*55EmIG7&3FyxP{DvMHpUNpe?zGK}6&F zZ)Srkzq>x-+g?!$NY14Y;V3#P?uF7*61xcpS36JV48HXX&D?k>yiKQow@+Hjt znQ;mw(`Gr53%2wc_|b!loQuGBX7#c@43=5-G`hZi9=V2Da9D7EcBMW zGA)T{1Ta=|Cgo{V4JNN-WOAJN=&ohI!6R6P@NXU)p2q`XhVWuRY3GNs*mVwWAage} z!7HxfQvN3l1X)wESjkhT!#U9_QUP(Lr?I9l)+N76VBn5@7S2!0#)Etha%BK<&}X2L zfPR%Bp3Nrh+2QDO+G?knDLtWzD|fbc~bD%-c?swe{9 za#bLMw45c@vUcm)!mdvPH0;R_crDF@7k@D}t&mgb^xTLOk6~J1^Mf`3@sIPXn*QPy z?!G0bH}N01)YBf1AJO^frYQv_zqe7wax@U~*BLi_m+Ve+S*$X$<^bH|KcUZf+m;r6 z7EHe*?zs$(TjA1dUMVtV-;_kT?SXZz8f)}=XQaT~TX{*Ww8Iu6 zm68~@vX~>0p-Y)!y~HnlM@P8M%VrKexTK0C0aUzq`wk5hN&VGBaG|w@*0%Zg)fWtP zcGM*ll{Gn(;K`(Al$QUo%jfc`0&jV$lQ}u|Af8Xr{ezxY`jR?LiOfVwZ^&#KY$`;5 zJ5_fd#dp8lG4xM0_o%Gs(Brd;1KpV=mop*?{*y@B!Uq3(lb z1^gj$5*n%vv2uBN;b`0t7XudNhg?;A#q~=sNjqBuf%SlJTG$@q&tKI$rcykt*Wh)a zhhte18_Fr2kiUvJomlqixH(9#>pK;VY0#sWt#V9ENI1W_Hi_q;w@2UnnG6^EHyMlo z^R@>}rVSq-7)5f8lN2)%Z4q5udvG3kHb3fHXBgpOU@{-^mpx!FDg%Jt_$XkW`bkRM z9P!t2xY-5p9!x&N9}2$`gh>?l&oF3-1#m93*F{<0ttfZXN|-31h6`niu|FB6OOYRo z8RAf|p%~%`mATSRM6NB{g(*Dgq&-NpR3kVW>`~R(p(7MM@TeSww^gQ)-X98NH`0t* zrX8g4XnR`Qdq|@cv-Yi`#gf*!@9C+|zW&mY+1H>@EFY)H#p)B}g* z;WLzdU~b41j?%TCVWTX4jE2saFG-~b(<}Evyl}Z*$a(hU{Eo}+ex)Q_Ax0CIm@Y_K zG$|J!Y4tfPQeaI(4@TjE_yBA6HF^=ExMU<2!n5ROe<<(o+Z6~m%Da*-bYHX8{? z#H-M3=|0$^hN4RyKO2ktGA5i)toZC#b8ZUdAW9OCwLVb@ zItD0}xHC8M}HvxdHZ@uj;GKVXX7Wa)vyAaIq6S(Gly8Ker8x?R&aQI5-feP z;qNW0kBdE1UrWa>3q%lUW7QFeoATWwupIw^A8KTobr&neT(o|~WP|O}f`j?azQvIc z)BTaQl2+t}%f?81*n}ZWK=ahlSm~OxetYTGA$taqxI8GKmp~r#p zS}tt{bg>|_WYifGfKDkV3nB18MH@GkJwlR*^#m9{fjj1vb)s zNSj8MU`2V9RIvavhrtqhzp~9Wx%~m({J7e)%5F`&CH{3yoD^8spNHNGf!|k(Gya#P zOm*ymb{XArq2bt$y8DGTk0ZGyB*ksLIK+;^?2#0z_>t>kyK^X%J5#YjO+y{)y5_^9 z;16|JD~Yj{#hVLLce{)}_s3e<@V8@qW}`ChzSG7n6v~)B2;IZPv8F$h7lIVAW4J6p zHM=Z3-%NXn&h>06uax(Bj^8RR>`N=H(C8qCDMVA&c`3DhMaE~g8E3{St1Ui=C?5QV3;@0e6{`M3!{i} zJN`FNk>$QF4qbk5abz(&UA|ZnEmmeA#A$__sAIO8NHsXUkZI;bXgMAK zLNGofa`&&Zxj;zq=1meat(GqPGK7$QQG1{~M#_(}NAq|vr@=E~wO0n_XX4Z8=fDxX z0U!*jo#?x*9|sO`AVQFbrHOie>2pi9ty zOI|BvFUGln2}rgihQ;S8UT6f0k2N~DmYjAA+@(yEl>_E3tJVAuA`2*@OmNB& zg`k5`ZPLnp4MTR&xlyJCC38f<$mIDc&6l78-g+M=)$fJVbsm^!zkM>8m$;dV4Z)7N zyYLdOcnUGN$Xr#>{&_IBAfipV=L|n%^{I$mkf$7*nj{0Js5?<4Sr|Ra|F2Ah0wlQUj{HXnJX6Nj^{VYG~IS@%%jI-H7GO(t( zJu~vU33uXt>`K@DO3b6BFrW}Vp4*7yvuJq!mbNwyo68Dlj?WWi z9~kJ1)!j+4%=CM=Qa zoww)n{~=m${{>=WJrqOJ6dM6~+9QmbR5K$Eq20#qA5n?aY`OeZZyeuKdy@PI?~8d2 zGZKaB{wK+k^6LLe@#T7FRWN^T=eZudx;VLT+daGS0e{>JJhu>~f6g+UGmp~O)Ax?9=H~aVga(}lo@0Gg z6t$XYx;))h3{Jwm`TQcxSb^B<-gB3@T|6;=vLUU`uIC8_zaf-3s5h6nx`#P>Bl03E zlvEX?^2wKR#icKg*t}S3?z=LM8u9&O|zR0bB2Qk99n!n;CONMn>79 zMzS|jGed=C&g%9v#mE+r$|@}>3nKfU9Ui9;da+(JFDQvt6q3pWL`!lrdz@SK$?5EP z|Df1cIpe}Bx{1{?94!z(k2!uB{q#31hA!;cL|Hab41@o4);-ZpJ#)%%p0>#FA$cnN zXU~!%UhDiT8cezUt^DtgVjeOhB_S%S@>D9z@j+ni0b2lNw`0<+9)W2aUbe~$DnC)X z(;q#E2M03QnC}uWKjKO`m@A>OYWKO$HP5vO9In_$GM)Mk49t`+xD8jus~WPDI+3zFV@$^%70CY8Jw1sgFdNHs0%dal^N~1$5x}s#v0}3z zH;iEgSIiQd)z-DG)^Hj)0tz5&h@PzcB7JA}4G_}5Q1O`ZE2jp>glYymqy&cU=HXJ#~x)IkJ-Z_sGCQEY0RvoGRoM^<^CxcvcPY0eK+z6)X)#&%StZ?!96kd!l@`u{@H0s;e4o4#yuP>&n|`+j5kFyMlLb8Z_h`$r?3Vl~S!KRuhAdgx*Hr#L%>Z_D-! zNIlvqFN?=R`~LfS%#fXfQ8vdtp`R}{_&j%O^S8h@ObU=`M_D6*rnZrlkS|+1U$?w?Rk?MI(a05f-J2IJvyq|gm8&2XmX~|fL^_Po%h0dA0l#M#g8Hu#{ zM*6ERz*Ds7F^en?Ba5oRlk2jlJjSW-vE(}Ut&#^`mp0S4N{euY@V^UBKmSW#nszt| z8nINud{7N80f(6npU}b`yzYur^Mo7dRDnv?_Zm&L>zQe4ii}$mbuL1E#BV@JltBAt zOG`_jc#SMgYC^z#pevhaqvzSK9WX680H;-Vk53WitReaacKxQCaW{y{&H*6{1Zbfd zts)+Wq?j8|)N7P8s`Y@G&o+4pppsrlzo z?1SyV!mZ`2h<*4()wIze(RDofIS*Z0y*%#a6_B?|} zHPp)pJS@WPnj6 znXsB0+=cZ`r|9V#;w<<(zgxAYVgIk|=6t)#lg-*Ot*eabUk7=+>*#-*nn#1(!q(q6 z#L#wM*b19U(yr>??^gT%W21s3ZKKhB4q<7;o;BEkYYyZ^Zz-jWa08bBbpY-OL1D z8N{0v=0hOTs|Bw>K>#;b`p#5!b)~w3I;Z(<=?ciQOn2)P)vjpD+z2!C+y9RX;Kww- za{%4A%Tl`+%I}6oP<$Db##Y~*9{?p4)>IT@jzJS= zs$Z}8^&;W!t-Fp}L6q(WIDlMkcYM;>Amnk2jcL;uP30;i=klfADKh|FqOk7>Ponv1 zAVW;r*aBXOt%-6|nF;hmVVAdY;)?;K*N-=NAX(}O48QYLXwN#uZ-&u(gbud^>DNV| zi>h+GUgh#F@Ad~YsnD)&+a4yGVfz8WET|X7YN>bKVj>psxkg^ix01zH=o`q+J@eiGf>FVgr4d(C;>caOhNtF!-T&aouANoRq7hMgB0r*FFQ-%Cd^Hynrb zBO2w|;)}-;iB@O2pM+^20dbc=E3$0E)O$Qf$D^~SBUUAYpVj5 zRbZ|!(TdWC@DGLb1$JSSQ2Y@~g|60YUi}0d@;*23w$FIw_blENvFiX3xk4yKVmRC)h{?Y(4=`P92H94>0ESx}i{UHw3- z(H{zdcC8Ph$MGq7MnUP`6cgtA)9uAO?_d6QT}y@G$6$+uBr(x!X_~+n+SfeymcqIC zKlfC+f|i=8hs(2Kdksh1I<@GVt6AVSbU!N00tcKOF#RbNI|1I83We3M_C61?>Sul8 zPhJO>^?A#*=<{F^aOu1r`GWl&0Wfg3)--WnpAi*lUa(zAE)WE$FNwwr9PS^${Wy*U zQl%PifwEx=(|^flBRs?&K=H$DYm(6DX;&|L=8XSoXPf_RMYdARb;XUv?lP^9 zBizSu@cSPlX94ToKfBe@VxXAnQsivxqjXf{!XxSbT-4R2;G>VPaoqytnk(pU?la|y z(G&T~VRYa~sj(R0MGH?Az;YoLuEmJY!Yjs#Q(vV})0UBsW$CHeFJs42J$< zPc*PD7ZtD!axmEU!O4k=n-+mA`?W6$sASA4&L^7>MePRCYZ=)PmOyIk1`=RLTvpYU z<`<6*A>4}s`0(X=_4Lp9(7r~WCWpMTylh&U?*3RWPC znsWwrw09%s;CX%4IQZe3f$u+80bnf+ptZoU2F7E;pMa;R1s>?pU*}8VyMVhVlmXa02r zQNr2vYKG7^zv5p|JK#+LTZ3Je|5u`~-@jsNlEH0&n{XE(ZqIEqWth4YL~?)^*L>zz@LKX>8pe> zWh-RmC<8n?{Kf@ljDAq>GStNHy6mt0+mI(|P=<9B6pXJkFl^T}9D~hsg7#|`eH+eE z(34FQyH!%Jxn!Q_eVM)l5;t6)8xo*Im>-L%w3aE`pL?)9Jo%h2!BvSI{TC^5TQL88 zpMgmw&EQwkheH@4V(1|_`O@_H+SuM!JnQ;S=BpSUnT(Yh&PP&v>jeMLLRk93)DRMPmb?pIP}@^nDEK*i08BBA#Vcx#C5 z-R4;=m2|5n#ynq4)%yHXPAp8fGLQJ>aip&wOn^OIGj8bXO+{|>05x5I7V7iW7~7Z2 z)&>s}0wc7s=L+-cbOImfgp@w>A7?(NmwN#ZF)p1fHYp~OTjwY%9HPyfiTpbG zQS}U`$64py*kWZSwFJSx!(J||lzX<#m-Z~__g1voBrZThx|Qq2jZW3uR~Q}lgiFws zUasmv)Q~iC^F~YH&we68o`wryx<|L0QI63it!TslZj=RjxYSw24JQhOp0A0-&f`IZ z28k^bd2#Q^S$++gCu^Ml7EN_?-(s0X-cgvp*VGD}Mm3v?zYe zGNs_nIqCKiCd@BHOGmwQZfZ9R-7xLC<(6((FVrScK7Lmv>!#xS1-KuHtMMp-x^p!O zjv*UfVEh=@W;psrK*c|5@V=yeSNONb%>{YN0I9Oz9Ar`KYTMK=oxGn^1<{@1AV~-d z#(!Y5tt~91U{1M-!&|kA}8o7x5 zsOgkx{jsx{-NqB1T8O|O&_Rs`r4>nr2j_3xG|In)=pDv3z0;K-b$MeS#h3IRC$78R zi{qYMSRVgK?%|=_g}BA+6>w8;GOrL+?X>|^_2=i3#j8uH_v9hLlEG36(KL;vDv}xl7rba-BjcF6SvGkD!8~k1vTJzaW zj&BEE(EYsj&&HV*#2>9NPKusJ<`6ZqB+!=9XRQBD`iF*2>oQaP79nQZJ{p3r2%g9zjAYJ zkO6peRp8z;al)1Iiu-KlA;R3jl1o)Gm$G9yN^XCxZi?J(IN~&Av(e|7RI|tiV!>2(U`QXe0lfLnsSwFWA)5(l&8+DB z)ZeiEOKwU?`Sb-4t=cbGh|tb4wHQRC4#IlOnVDoDyz}142X=*`PqK_T{ZPCrIGoIs zE5iML>kQX=30yASGJ<(2rE_FPJkj#JA%nCFk4v9^iB+Yj`)=9D>bAWua%ak+6`!O3 zbR9(A1O`=`d{RTJZFq7IAfxP-%~A?~h0*q3$iuriZ#rAh*&IJ6T2}6Kq#CI{gL*$5 zrYx|5bJItC-`|CDr_immBzdjv*CJ^y2rLSogQ-LnX3FCPf4_OA(|kHsPICIzy(fF* zwQ@Wot!G~^ai-~HwcnrrBN`9(coZ|y`7wl$g<8P;c!8QV@*F)R=+GEL$SgmWbUBPw(XUS$$t?|#KbqL_;ujgXvG-aT|uFGfI9`PQ?{ zzC#iN8U8wx9bRkCv}acDM9Rglww>peJ(CRW#X8-zxJrGhr{5KQ$3sL?Iu~inzhue5 zL6MQnSv3k;Uyz$M;OHTdUjV?RD{R~XOFG0JVkhbH1h)`v6$vMUZ(zU1H1T&>vdSJx zA~}#30dgJ(cl^Tk9URoDJKqLAv!DAT@7NvJS9bu2TG2XxtPFh<{Tt9W5C{1X7NzfR z>?D;#+dfsz+sPi9#nBGuT*9V^krechn<0&7|MV7TtEFM8wSKEaq?NU|GEcw0Y2BLH zO$(d)t%t<71ll#g)Lz~yk(r!I>Nek%zs!-Aj;!FEM|pCUT7}BQzFOwsHfh5FCE!1& zX~<^!R=VSNGAC9dLTSd0oP7l6HEaSpj`BsBkgrxeDVKaPM^O_9oSRd zn-dFb6YsrN;g)COR(xo{V8EHiXDw5%*JiiH&bEY!@O}d&%>mK5hWgFIqHD9c3^M*6 zGt4<%;`saNWvDg#fcOe2ubc`FRM1D@zKg((XZ+{m31K&?YdGXowiP4jumw50jpP5=0wag4%B3P>TOF6rJ(igYCy_& zYyA7pdtiT@J^5pp<U#SuGs$ zQF0ViYsK(%CrQ2RRzm^O!Ms0W)C{Xd?n?01#A?W?Ss;mro0x{oe{O) z+f?BPkOeET&2J@cja-I3*WdoG@_pA9xnEju*Kw3slHY(lc!W09aOz0uzUyaU#bf=w zntf*KPVa%``F?Nwa^h(E)o_HPbSGyxcOtHY|k^%X>2& z=`Q_J(P&!&lbuKM`)ZjWQ|u;SL({DW$Kmc%;3U6NlR*3ifT%679JvpK+sm<5`eIl7 z{i3hab_Ss$A~A0(Hz$IKrnA7>o?|#@vg{Lb%{HjQcB`Ay)Db{n`J*HCFT{tIj%l@p zNZp_;JS@!S%ppqKbm?R-ztY47KeUWf?#J z%1;I-C#e%@N;~!&iYvIuJ9MN8m{C6VaMUBdnmmalP0&#b};5FH@9^8-VO|OmOWU+14Ww6O# zh@7()*@lQ~1QWRAo~Uw(E+Q5DoLGsI9zA%Tkf^0oQTHm*subFs{m?&1vhi@Avh4D6 z2!C7mIxW$UJ~o^R_FSkd z=MvW_rZl|PgK$D94I8(q2kg4v6Yq}iXro~j@l;Ee0hDk98p#YZ1%nvmMXYRUGOgME z&@zWV|D+iyocEps7k>!G-CDPZ(&BP*?t4wtpOsUW`aW*W-5>8ggk{3|yOQ$)l6|*D zX3;4m1B3@sJwYyB7PTzN88Pe5CUJLFu8MUijRvFHP1Ro9aq@F9;0FrtFAuY@qAgXy zfvxcUjrDnG+?bN)V1QYR`ehqi5qoWlrXhSGaeFvB*c(mE5g#>SQ~;ZEG*I(!JGUF^ zWpr;x`$0TQ>cKOuWoV(E?f#UrIYVPM#O0XweON_zQpfUD9J$VJa`I)&Q2*mQgZ!j5 z4LDn911Cii2u_Ne*+=&GZsw^YuebY2*c)G8JZzR4Sh*|lVKCqu+$Nm5b13%EV_)$< zi=HQ{#~K}h>DyPB`xxdU#*rgLrtoSV?`Bc>@P((*`;7mBhM{G7h`=HV90?6q&1*DKTY zdg?tfBU&QmR5VA_k5PLO(&*ckj zHzvv}JvuL(%*JE5+$DyFWzo5Pvj#_)tJ|3avi(+Oq90_D`aQ0$T^rOAK(AX zuX^pSu`h_2hlS3#{Ej^3X&snGt{<>CJf7HJOs)l!=&5i<-ex2NB+v%YLVk_*v?^#W=*&U2B~DKfUgXF}2YuB!BD}0#0T($3h7#(`ex01HIreC8oqCm%yuc`-t4{- zmUpZ34?@}P*GkGLP%(hd19u!;#Ax3zoUZX8bnXaK$6M0(`;{9Z4NGJwwgEGocs4KW z%3ug-Lc&F4t21X>tL38*TtZ1(25EQ>2kIb_zT97YPkyQ@8Erpj4f)32y*&B*z0ING z{wpRDna^b2ep*Z)V?ID;i3Ux6+Rd^L(z-|?^Wo4{WVQ5hEBfOliTM2gL)cqKMb-9g z|1&hw(%mT`AqWm3-6bF;AteHe+Y!Fj96>3~Gbfm{rxSCID7qWb9yn)bIade1i@OV! zQ@MjVn7mq?OM~YzSKnulMKhi9t_$LZt`S_f6?=1HC4B>2{HIh!vp3zA7D?#YsR`Z2 z?VLPnLl2k>09e^%q_zcknW-FixZAF@UZD=S1?_wsvqj&{;#(s@v` zRR4aLmCpb1P4v3Tf-M9miiDk&rY;y=!Mis8L2UEXw4GU%m@A!{8AkwpVRA49bib0) zVb#Rdka`tPg>3x}^QnJ#kX23C=53b5eCKf7fqPIa$B}R$7e~YxQ`S-A-fg=n!_xi? znh|zsga#*uH%Gv&Y``tjH@Q~71|&a0x!T32kiF6{gRa<5-_%Lrv}sO95hBMc6`fs( z)K|UzpP0}ipQr7SVwi;uTJR$Al8<=%Y;?s=K_;SNUqfQs73|0$9#KKL67kiMrm{<{ zaUz(sqz65+-Je8o)V_qrUU;2_QBIDtmvWUQjL(FhZOu%(I8428c?6E z-HS1=InlKmXCtIIXzz$X;d<5|!)CH=7Dha`pDBg*TEw5@4A0c=Gfac98caM6R&=%{ ze(^kM2wZtN2rnKMiR~9in|!V%XxO+GcX@6RZy@yntfF$!iHt^*ez3w;;HQa;jLT5f zc2kTI9rql_!VGPiV;THDbbSfwo|)%V`Ss5=s~~_pm{AXPU(3`#F7s~d5n2&IAWH(MkkrXQj3+L`iVP=q^o@@|rM@ zr=UH%DM{SE7)!f}RdQU78$*CeER?l}7zubm-yHL_v7;Ml8|fGkQ+0@wO*6QF$DV_<9YXKNwzHD&A<^e;NI2&A+NU+lQxZrvG5_K)td7D#)J~T9#m@ zw;j(#BST!x!bS7^vag!aYQF+%cky7SBBx1J{?~&7{oETCYOtp-J<#>u)oZ$ij2BKY z`-bq0Sm9DB^<4-fCesJG|7o{J#SRlq!nyI3C8t4})%HA=t-LALf)S)Z`GZ(w@S{`# zCYMS+6i;A;50QHH@F~(#WE8%?9RU8=6!FUhX)$g($G;T0uO z9J4k8xTp>`luvVb$|EnB3GIyGWgSw*!|ZZRxsbwAjCg3i{O{naK(q`%zu3KNTU=7eSW7KiENsFRqC?py}9As2bT*y~Vm(ADoj)kRdK;L|uCR@!&G zDwd;{a(~rK_?fdJYPEc#H8WM|y=61#wq~RovwPKZM08Sn7o;VTmS;rI76;7Rc`b(6 ztJ~cXHFO1ehdOI_dMnj>NJ>;6je z;Fj48dTxC^5T?o2&b4}L^_j*6oQvOr&! zMc=koXgaHX-ZS+++!Tb+N4Wc&ej!45W=A8^2jc}{N9tO7tKhdKMJHQ)z?v8*^_vA1|eK zjE2F_?%+F#W28`A8B#gvt6Z+wi9s5LCs41|JPfW)w98fnPKn@Moqvgd?xa9k92lj_ z#1QPSi!4k-Nz6xyr6vvDg=5IMh<$6CUTblq;W#gSOL>_K;eV(#2(j)sJ;QP@&5LABK)Yx}=i5 zw<)nmDgs-Yx4yQr&Paay@~g%QT|i{Oc-K8lJ|%VOdn4Woh-#@C3_4gKAc-f749ztc z=XgXJR;4MgxA`<^)t#UAA}E5&6#1t|HDLd>&1gpJRO(l_X->I~-zlo@u2LRd@4?t6 zu>NK{Ers+zUgL7jC$p&%;T;TwxR|9{LtmLvq=A)&&iwOSD%`%Z2>)@dRmq@xST6+y z%wsr2xY|6?Zv&>McYyt;bYnUv%6z-{lb-k9aUb16LIkiz{vn{+ zfHBL-{Nb!sN$s61ySy&gRm%Xwn^NNb4ZS`krmP1GA`|AHSfABg{J?C^j*o4rsVNZW zEs3UC9(0IWkU?)`K3AHOcVky>Y~B4-yVx=9l*k~}dl4AO`o@%g(8Yq3VJ1Iy^3_M^ zVg^D{j1kJF+>zq=-wI$|(VoXDAFF%vL}D|F`+}7?$pqe5UwkzCDN`JonVN5Hr1tKQ zh7YLo!m1!oFjRmr?S<=Rwx%l%*nc)bd4-HCvO!R9>BzCYc_iI9kD*+Am}Xnws81qV)5R}_D|6eL3yJf<&gQyjNzj7-ZjSlSzwrV(($c|9MpMGw$BB56Hao zy_Q}N^q$pgHky^JJ#E-OtGvgJgtR zuSc|8`j!~P46aeh5zl^VN+etK2yuuvC%*pyv=rME-|{y(UjG#)fqHP0$Ov`&=U`I( z=g)LcoS5gX_bxjH8~uqb=-Zk`p31s>`Zi2>f6aE31h-2~`^qU!+JB5U{KHLZdDLC< zD~NUdop_kKH~TV1Ut?CdKuP3UmMCeF7SussFf3_bEt`{D!Zf6bgcDk%>zYaTf z&kW<|;SxNr`Qce#H!n@0^5;f*vquu&9JW0m@VdAmwFveKaEntn3?)$J1R)+t-nc{$ ziPPil;-Z4iq-2QQ(J1rjHM^sueybYte~W;X_hdZd*^=@2<^|W+9lae5gStCTjDr8w zyy9D71c+ER5&taAK)j=HZM}=pTKv0(7}~-F@kwy8;CCUPe^~geH$xSMOQBgnzxg zK}ic&^Pof!wqqe9Azm?#QPAVA5c?0cTxg4m!u9+i+J3G8Yek%-(UU`6g?d%7Nf2`% zEDP1Mi({TsKM*n_?aUlv|QiRL4CdqORFEI(@jTJUt=IiXjcN zXj#nSO+zf!x#4-LCb2xYt67N}u&Srw4eDEuXws@+LJo3X)i+CW&s{EZn%BgyN}ECP z^=4~4@8o3%=A&P$(~8Xhx`pHv&>m=db=(5-r=z5E@$oPeMChd8j**L zF9lJ*@uo0x-0viw8xh}t0Y!|$Mjjes`Uis(1!D^K30)6I&moLVKs~CzGmdYViTl25 z0y2`Htyqt^Gq7Y+0YB2^*6nyJPNU)huQx>!fXxZUtN#XiF1nbvqI}aJg{hE>iA+mN zY{=txX*)KNON%LLeeqpf62HzE$YrkJ9wzPJ&0QG@#k>7mY-xyMc%xh0yFscy@RMUh z=)QM(??*nEw#XUZ!DL7RWlYQ=S)t*H?^J_G(AC$YbJ(eNKAJOY>Qf?S6`|yeR}@kn zyjJlVm2vB%@IwLERMQEsz

X9*i&n-{Uo0X@qYzxNoo)b>KydV{JEkj50rHG5v)SMjV?+P+IR z2H3RWnNH!YZEM&KkXpr<?%&9K9}W^j5W-9Dv<=;=LrA6LxdDl5=Te8#0JghGYI*TF)TE->tLQTPC{Tdg00NosP-k5Z`;tr%?X7@kLk>hhc%ExYEKPm1bwZP z_YCt>lJ_{b9j@8dc%ToYFx#+>QKgSDrBWibj8-AVA&;x~B43j0d`;P({O)u`=>iZV zi<%kpq?u1eIu+)%fU6C!jmU|_K94fDaW^Y|(C^Q1^V6{U3jz7PjK~*t6y{5ghd(`@ z6>_q(>!10#twzZ?IY{?Joc|T=elmr&+-2YV3dEs)LuK1!aW^YLTwn446slXf4}A~D zzk-18N&e*3wa47BLI0rVljR)ZU5=qdeoH--2OH)M6d5SE>|qA*rGP9lo$y0nhrV7g z)cFO3EuSO<6(6U%U(T3B2rHtJrxgu&CnuRM8-pm|(y;GmFD!1M+i0>DVS-V(un0+- zML7#4QGBTe)Vl}7Jm-x0Z#Dc$o2J8SQFf0S=?0M+_<0s3;cdaOmJ#e{YThJNE?czO z`8k-Lnqb(MYB$|%s!<}e8fn44I-;O+ERsYEeHGUpNEZ4={a!68@a3a24hsm;I9NeO z`yq?(RY+gxFGtCg$hsVtBxM*lZY)hD{YQ=O)QQVQ#MO8d?W4@!XN;8|uJYg)vRP;7 zw4i~t>*?<`2{dX)5G!h$jpbM6Gfk(YXi#Z2RXtAXCQc2u?KX3y{PUh>TmU{bZ&SNQ zB%*j69e1sTQP+HPje0g1694s%r!!e=;JV3pa$oTOQUdRoC1kS&Y?HR4D1aaH(JNha z6L9|h-M8*1W35hw%@xL>K&Q9*Q~A$(_i7+9cd3A}zh@b8ulI>EsV^#8(6md+`?PNbZwUAQo>(pSs#`{XAQ~&~ zQ5xQ~MHz|g4vH1{nSL(XQ?U% zE#=3Z{lD_%=ibb*&%DZGn)A*Lh9X|LEnX>>4W{(DsQ__((GH8E+hpziFm;XbuMJxV zucsO>-~IMR#FjM$@7>KewQE{>#nBJ#O%u244*Kx;&jAt5PILBsT$PrU|A!AOeGv!&u~ zYmrYO+6sz%_~i8gEs3ytyAbVY#&mWAkxgG@i~+>{TQL{d7~~aNgo|a&%=yV75Xj9j zxk9c$kmGFI?SzcT>9ZKqy$^?>xLd>L2QXe^NpTXq?xA1*)KQtpM{_^BnXZ@{m?`pj zwAEm5kVDaM5T5zsMIp!71w4*vFwK>~ri-B3luBET9AUg-P08B45$?}LI#ckoa}1{W z;E2CRi-J5N2s5P-(xgn+@dF>j1|1F#U5QZN-Xp52=Skl%ICU;^3|~|}MJ<0_(gd^W z#81U>`qU}Wb@4bn5Gs2G^1h3m>YF@|C#E{RU8LHlucYfeh3CE(QX?cCAMMNyzrA?& z#7cPJ>u-)6%h!s?Tz--t+z$t@$iewxbJe55UxgLnKTNj>rYbCO>eI?w zx;|Q9SFS%kGiKc&5^{Jvy}EBoNJ#iGr-TMs?W?Z#V(c^JviH+>@>x09wM3*;sY(dm~T7X^pTKRWll#!~jG#!_R1za!MZoTi#=+82`|y zHqD))>eetWxf2`oyLO$b+XH{XZnyCiY;*Vv+`!Rpa}C!K`e+2dKAxHf0;|_gN-N~3 zsElr?KQfRA+GXXjWKrMX%$P=GBPP6X`naP`EzK7D=*uVd2;$_GVaWII)Tc_1pSb;y z{6N$*h0x$SMhr zfwS{Ug3^OlhE)BwN0qwI*K5=8BF}HUxr<@D;D%QnSU*Zh$S|?^;9G4^74n2Ko~_oB zz=V22N}jgk)8d~?3%A z%COqr&5_I+ZQvZfXB(dY&xny>F7itlxw%&O@#qY^_mu=5RAGJtMfT)^--R1BkLbi( zhl=go1PL7B4)HU{b0D}VY0SD?2?d<)zf^d<0@PO)zjnsufRxuJlhFXvMQ2dj|545B zs-QW5;Irm}8axK7l*5;wAwb~#y%C?P@&?x1s4B(p>?X zCd~q^h5G6{;qG?g(`V7$)U&()k?o$}*0^{MuExGh3ra;y?FTR9VWxfvLv1i4B`!oN zW8I`Hv}`^N2>P`VDQagAKH7W1b1PFHC0O%|bdxNhGnNNhY^Zo`E&IrtOzZ>GM_g#$`IpPqyn1O<}4ry!{LaRtdoLteQhP zQ7h`C6I4ELrAyj!?u)@$y4yWK#d!0)7g5n6q;E^+_k!Jy?=YUt1M>Y8FtAGh zOtdJFWI_(I_BfNY6@HoEcY{2}A58boZI}@P!iaUq4kEm+=sBqRM-bMkyn!!C6;42b zc5~Tl*cQ_km1+iCk_B@_+=E3qARZCM^=Mre7tOmk)%lfnqQ4aZ;~6c0nFNgExKF%) zju4yaAE>XsUGe@t)R+L`&e*S%&%t_}6@99M`29P9JKoL&QR>!WW?Itf{S1}BR{9~V zr=w4wtUCJj&_CY^P9QVzPu#IMjJuoXV>h_!c%Vh_Bi^{Isj(k2Wh?Y{0FDebxf z6Ntj23blQMa{3bMnQ9wy#Na9Y80g6z$q64x;cB+F&fFZv0oOmvu zN9QDWu>M_cp`PYKPwNJ&;@a6Z$mP+dRhsej#j&t#-KaOi_2)l;W1`vbHE*dAi&?}1 zJvSEZ!u4@%~^A9@}`TnaCr8T#|P#feDrRaDrA5Y=B0?>iM6 zHb2W|v(P0qS?BGH>Hj*-68sMO<@~$bsmMsP?C#=}aZMR_Y4Jr1;@n(#%Yxz^*w~vH zq)(*H+;-)v(GO;3x|s@?^WQ^ai3Q0aAmdfX&AQ)IW_>8-yOO}QF#7zepqRjuClcPD zM#Tgd7~4dVdo0@}q4fe4KSha`vV}mv`yi2jT>@&X^Y(OWYTg~|6Ltv1E5e(#y%Wx> z&qXmH$@@cgPJA>1?x}pbO;5yM`bH>p*kgDjE%KK23oSWhp~N%;XHNA)XZ}kzj&1Tr z3e7IU`>7M4;Gbw)e2QJ zzHwS|158};k~fMT-{M_S~_=HUaDWi{ZF?w-(wbk|~VQM_D~whG8m@tW!Cf=j`Rp<;K+UhTp#Bx_6O zMPS__qgl@;N&)jFpWZavwtbXTG&Qqlv`(@j`yDY27GHvV+EK9hPmEKTlZL?ZZT9e? z^Bd_eG7+gxBBd?)UE=b$7HPsgh?NE>pE1QsUbrch6h!=*FQ_?21e#tJk2r3pO}f#= ztQh5!h0=v;cE3o+h6xIn?)%6awd-HbR)Xt@F^p05L#eI>ZbKa_dZWN6IS6@VWqnRD zg5G2FkEAzt{T}Y%zT8o#P8TE{UuAn|^1$Q$nJ7~5ST_(Vyia*#7CKA8N&sR1_MG!& zbg<{mNliiD@e3b=NpeJS2%)6h9)cv2Sk@;?Xv2y-ml@(}z<0c1s$og8$RMG!W>$>I zpo5tMf3fFCkqXSs@BAmc_F7RHTPjWaAfk})DMu970jf@vR8#7_hZy?~dg zNir`RGX$5TrS@fQAov%A4eJ{4lJ8{)2?2L+T_kIk*O3O<5(f=t1eODw7IH;c#~JjKLNSAN zHP_1xo~B74=Fvknu=b2`q|(?Zv9K>`#NY>GRHSEjIz%Rxyy}o_K6UBfRNi zOA&FQ2fWJ68~j7}?V6^4xo_p=C_Qfv3}es6VPb5vN^#uMoSiPhzXgVxu9@Oh?{EMh z?w^LY_S1=5-HCgH|0V8S-X!PWrYjik9vd(vzSa8!|Mdja+N2tnC)9xtfVfwOf9Ouz z8|-=ZyB_)Vr!4nCMG;eaCMPs*bKY!QiEPz)3r?W!O|bCY#bD9~-aALD6M%Y|K}u~) zlX$^>w=4vguJel2=|G+aKh{} zu9W3xT3%a*D=PhNYGc{ls>Qfawi(kvRYSZM#Pq;ZUh3se%H7BHGYAN;Fh~lEsqB8E zi;37Sic!CD@pG{`tR1%I@z+KuOa&Pj7*juAF?(L2VhMFO3{MBp53|WDIzUppLTju1 z*~F=&Ak~q3%Di2=R5bf`Z2>{VuYWW(X5%xlW4v4KlxB!L1p|=xW}84=74ztup3THJ zSc>rze{Gy0UE^Q^E?lSk`v)C(+7y|DqYW+}iCN$Z@urhuLEhXuBb0m_)`!zULLj{( zzN1}hq)dTpxFUG)bNXym1)^4O)bb!cRC;D0R5mv9EAwY{z7gEX0GFyDXONd1s2Oje z^n{#K{CxI3R>_&@!~w*r;Rxq;YI9ig*dqB|U?T)1AWpoDlMVSmW;Xu}x+|O}`l~xb ziGQZ!?X2UcwKBwEA$)PgHc;W-8A5x^p-lp3B4&2DdxJ>S%}?M1=S8OPqb5^U)Yb)p zW!eAx5b|Pp-$KfbB+#xNqj=RJ*iaKEEf!q^H`@fB%NF0Wr>S+Sf@Y5StsjE$UWLFMdAk-pQ2qq;I8Ofl$OlQfVR_-=(i1d29hwl%ZSv*;?GV|CJG#oDnvCNyq%svN)LS^{*;X1h$@DD0H zXI$$HAwIV-Psu98j1h*3s&am;n$#tFQ{)uzr9H^-4b^2St7UUD(Gn?i9Dsl%aW#FlMOVngg^&|Pj$b-2=)MB1%08bL%zkq?|{5x{jnXMufT z7=QjQsEsynYu;2Iw>;P9rpp^P^;Bp$b?<&i+j5Ib+;NLI)k-P!6}ZVvKXo*ZAlzN7 z7<&tCYVQ>J5L*O&38;QVxS|@1Yg0LT9@4lBJ==Q8{b!706rgRyiVeZ>-I)%>GHSu# z`y1WGBq^;nU5UPCDbr}nXtNa6w$j&-cp1vv*Orlmdt52^OZB!#4kh)V2P5;s`rS)a zOLgWfKK~Ar7Iozy9)x3r?;=)#->{yca?`kU{&92l{J*)mh@>G;CUutN+E=zU?rUL zNs=?gTfus$iOQq|P&^n~hZ$KqM{=>G311>2ayA&1{>DYPsDO0VjXVAf(5u2)583IMcM?6<8a{GMUvmKAC)LTOC7gw-mrn)D}6Dt}u)W zi7>-GU|BJfM!^vtM(^mr8IJdMdmJc!FfB-~IXPXiIn-I8Cs2{0SL}KQw{+Om<+@XP z`hiHe=E^Tx-O=~ApLonxcEk+aN8-w)IbQ&YV({-J*F|j5M6>~XL zq(eOma%hg-tob|~%^K!)x72*?kDQpb>Xo`H8q7O;e$A*J#wf9RF0v$$w#$05f0r!7 z&h{|WJs(ei9F_ELWjLy9#Cn2omth7HWkgHqVbFct+mS$GI`yboKQ2og^!{j6FL~*_ zJ+A*ptCf)gvLtgPii!@+3|suoh_`H>46O}|y?qv@cLU1jr};%C_JMnb?%r{N7H-6SWe-W0X8TZMyaWrJ{g{*D0w@JS_coyCKXu^^u$6H%w~J zk4Zv~`HhQfa)<;h2T zc!;AxZvYU!iAW&mA6@|%!FOuE$<86Mp^0$%t;fFB9l;N_H!ABKr$D_|Rh6KSno_>; zv^l=PVwmbpM;!gOj!Din_CmqH?V18tqlVUD;W3avq`1_e%UQUO_TCC7p@_qr-HA&h zptJ|u`YB8;M*=?vYFJ_&Uepz0eS-6gFEb{|F*lhcHW;eS;6Nu0sWH z(aVYv8m_HBQz$J@j90>f&5!6lXH^nJT=SfX7}Hgn^~W=b^BF3^pO0L3IGpRy=plg^ zg!}OGFou)L54s?@jr9x!w|OI{VGKV;3P-}BlSx(hI$;r(o5SI_s4^QJG>)ATd7;U6 zr9fG}mmT5x4Uy}5H2d9IzF92F+W4zdGF+IWGL<;W9)@9pkj6(>sEIln>4E-6j+etb zdR&_cQL}>{T9p)8o@iz%fdnSh@#a~AScIm1tpllc1+L1=-;B;4lf-zUuS1dW(f(lp zG;CW5KWvHrX5Dw^bF>=2VE0}Vr429bzt6pSh)A6 zZJIkzHyu83>P7X~iuROwlH3clFuS>`bHGGzxA43S^9s1i<>^Yb(LWlxReMY{RDeox zdp_({z9%cin(uQl##>5!G02H8z6RglhdcT?DGq0gJz2qZPd z1tt2|10seJwE{VfxY)@1DRed)MW)Cros(q7LXE(LS0L6WgLaiqDMI8T(Z?>_)x--D zl`0n}*WTL^Nqu;CY&@tz*5(f~@y0R}{1o*=y$NHcOiB-&?HradaFf((3#f+fXUqi(&>L)ol7$*8-<>61z zS-b2%{pyVWDB-z*=7J*j)St0}DTOQd%5YqPQa&#Z?r()){DA2}^~{$%FZ8p4x%EaQ zhW(cih@OWdRoZfg0ssLi%8S1XnKI{^$g7AyHJ{>t>*)0Uz<$lK=VXTGJ)-xsY1=wt z{`LGS>7v!9vEx{s-`+V0-)dlaJY5Ep@G{DzOiP3Ub{CH8Z?{@H2b&l9rDmYdyfrl3 zPPCT8$9Jp+wt8!`__1MAowb9L>%-xtU456T4yU^hpuZiVp?z<@cN2%gvFmM~=kwqL z6Y(fn5q__gBlOjByrtc%VzbM^ex|grDKIrSjWYZ~nD!X`fEgsm+836jUy}UVp>432zT^RX-#NI zj`Y>bqt`s|&NegE+^u*Y>d=zOA*qMvvNZ-)+uzaUM4t6sWn&%Z$FRHmP;PQBezJ@| zFZfVNBd;No>WUQ}@BQ+PxbgZ{tPqMXEKjUrSl8`rLn`&Jd#LT^73zP@Lq1;6VEua& zt@fx7ho#})puC0GYXQk7phVRKGt{1A-N`vxwZipNu?i*tInfbcs*ybWV&rtz|hHf}00d zPlI5!?>}x%1VZu`ol8M1cC~59D@;mez1-hG45{jkT)rggU1yu7uHpNnHM}h?%SaRY za;-HI;`)%q#et^4j?Akq2sQ7&4wqc7v;R6=-cWrmZ0L(NqlwNb;#`f)02Y^Azj6L& zeVE!Fs>~jhE1wIMmffqT;TkGz*GnXkT#0DJLxf*q6iC;ZdFjKtVgIx37E`K*kS8xI z4W3S`tiES?U^-gFG?&8^dL8%NfEzd5nZih_&yG788`n&P7ml#KYA=N{>F*Y9Qb>jo zN+CF!N*w;)4AF!W%>rZLZV$_~nP|ZQemkMIH>v^&&i9}ijYM^Kp6RGW6sE3koFOQU)Nr`Dy@N4AImZm4S_;n zl9crEhA{+Td$}MCMaGR&tQ?F}sZ|u_g+th&bsREgd@0HO4lNfI5K;+&lgimch z@Y}+mO8$gXCrMH~v;zU`$5?WyPyKP92wbj>+Y`3ndXzxvQ0vX_i~GGww7NARu){O1XCtb#Q2rnbP1p6*fp zYH9VI?FbX{_ZMx=#w}mf#8J^!nNdX>fOhN7k8l^R7+g|U|@Gg;Bf<5aT`C*o#N)Z#3Af%v?f4J zy$cPMKZ=dt1f(KLQWjDt6`~Z|HuO$$by8G36Wok^FjOiQby?(nKL>}N|AltG=EKt74bS7#=AtyqN5r-e6t4pDTzrK6r#^)f5U*&iP+=?g5rtC4h7)vcl z+cLqjM+I*GJ;%euZQih?c1~IlaY!!L+5m6P!TgmI7Q(uZKzGrNUT)Y?C^7jT4x!ac}UIEJ1 z9LUz@z{HF|kdZ9S7z9lBH(cxkvMbr&bkdL=h^6lSx<9HAv@*3L1rCr+c!eK-ToR~LPl3xlj$$9Tql9TxM1Zx{3 znfP3AU7U1R;AP=QpD#0!!Ek<_b|gU}OmzyNw-!4@I6|p#CPK8hyA`y})X&1UD4jf_ zMd7u(q>S94EUxo%wBoZL=p}nQikQR1~Bxsj#o{o3zTh8!v!sMZ-Y=gE5ZOyQ0xSCPS(|E{5 z41c0HAj4_!4YqZFK?|Gd#zUw%hBi7L_yqZx#IscB+!ISCE(9XIIhQnKM}mO=-c(Wy zTYubUt^;3t=_3$$v*u<-7>9h#ZSLpk$4Ll2mDK3 zT(0BoI0I*DAN-bhg**_rv^_IhENg(44n43cY#p|_>CpX|D(qHwXOP0?x~jAs`wlDu z2L`vPUMgxlHa;MfLSWDi^qRKl2Bv?NV&f1DwA-jH1p0dpez%JlUeUh9Q9d{e1J*?G zOY|xqHQ?%JV-@$W@=ms5gbvy&b$j=BCv=^PKm1?(@F`SzmDz^qoz}oT8MQ8<0xh_0jJP$`vIsA~d zm&?agIJR_T7PbS#V-6H0fjKEkTWCIav7G&{iGKa_mH3Q2fY7?Dtkjw|vsdE%Rb&Dw zvR&5C4t}48@F6jdEoKA(RUfU7*%k>>R&@^z#)dR@6Poa-9HqSHS8a$f;TUd8d!5}pRca0p6-_a-?Ea!!c6?JpoaZ( z5Lj~LjC8}0laa$&F~karOp$Yu2ciN@B@ZemAkew-zmn|6BN{HjG^OC1rA$;EbG40s zi4n!B${;f7Wg|0S#&4~3mjG#FjnAYg+tuT0IBDYy$mj14x&iS#dOU!1(ysz)2`E0> zs}Ue+e)Qxix>;Xe#XgxobCP5Cc0$|F?1Qa@iPT7UCL)?irl}&msU09J)G`-7|8!_ZyAIxRxN9{u`cC#1o= zN*mjT5f|WyiQ--2B$9+FZxcDi0CCxrjEDJ25+OqKX^+?<%Ce|+98|w>*yZDx<%Vcr zv46|zo&4QHUvEy?Td4E49+ldiWjCRvP@azW?_Y(Y?M>Myct0%cX>B^l(D*XlWpNkC zMERg=#1xl2>m7p*84DO_YXWk~ko{e@?TY}4_vRn2sl^1Xx&)n+WIjT_?OU&uafRG9 zKlOLzAl{s5jM8_IJ#4<#>W5knJi=q|8aD3IkBJGlNrr{L>@us}=Z!P>!EzG%=5e_| zaQaI{;d`Cl?(Z$WS6f6wDQjCcwH10hr&eD}ez>>Ud|y^Q?QeTK&n0@ZNaX&wV)P>X z!{4KXZ3dyuE0^$w9_Qp4C9C72_+G{y-B~p3I9f*8tcc^3-AabipGwvyDrj7^PJEly zqw*Q~F_4Go)P?3@7cJiAD#}ZcMXgIqk|l3Nt{~WE>ieaqVu+(A%(4XJI3fHP&yaA; z50asLGQbi?QErWpGj4%3@M8j`9X%4naWu=J_SDw4tm$#>z6)z^1VV|pFNfgk@o4uO zAcwJjiK(!u2ZYS<<&OfpNiQ9ZjhEV}zk_a|aq__(AQ_sKRz|UT;iVkDiPR(w#T3%5rSdDJoUS@paxX!>}`$r&K>^qbOL?vR`p?1=If2k_F97A_QxQpr zjUJS>)G6tn3sn60ULwln)XaX~T2#C6<+qnYQ_awn<@eD+kKbA~T|(sbv&S_K3Qad1 z*OiO?g@`6E1Mn>lKIZo3xA3~8Rz36L{MZu#sv_-2>@BBHX(bt^VpK$GJ8Cw6bJ?q zuM%**1sKSJH~giu^i^|Xg;wod^t-nnfX7-q34dThA{Yy(nw7H6X~9AKi=5Ivy9a zyj^Q*an4D<=OgS_Us^Zh`QL3MK6Mo>5U3*=t%Z4iI(t(drf@ zFclrMwzPRhIbLKP1+ZU>_0W{uI9BxJQXfCPJ&1jla75j{((vdW!z4jD3hqOn>r~gR zJcLICOhZCFKw!w_DDz{oNRRjnpZxPD7!Ui;gG8@dJ^m4|p#ZYZOKNqUC5`CD?*lw!vpQA6ovgNzQTf1gMs~4wZr-p7V*KsP% z2M`aXn!O5Vn3wQr|MEb`w_Q)&4bKyve`J1Tp!!9%C87bNu$(17yjDN`adhiTYhU`# zAm&2({Awfh*^o$Jjj%h4FgU|4kEK;NjUj$Dxiy|}!Q81APF3|(+QywzVO?Fpu_*TdNE2YrfI@f2$o9DZ1{GXg*yy&-)F0ADYg;K|V|w zu6)Y`s8p@+aqyW%UXfEQ4IV2{QCRWbwaZypNyKGuVz46ZID%*jYc&gmzXN2c>H19b zf546^4w2C59U#cNG5B?%6k&cg_;I0>_XA^xN4Zm_;%F5g37lSb!y=c3 zILOu;AU93`(e2+{$9-DgKjJXw5F(EFE%mVv;f=YuJwK*W-z;~aUd@hAV(;F7mHf8( z0KD^J?XYF?8-TyAgTy)#j7Ns0i}kCXkux?mL_g)cR>B0V$5_PN3$%*9pZ?(5OIzU+ z0M?7KsA1}cb?eBgZmJ^p={4Bt)#0-b9#pQ_L|g{jC-cst82Fw5C2E(?G=2$nS+jbd|^xJ{OJ1kt`(EzW?`n3+ypb7uqQ%syFw`PL#O>e_(oe=q38`sI% z(u^X?5>00hf!(6~6x)(-EhZ~}>#1lW$Sh);#S#No~Ij?9MEG9)C#bn?(M|Rn`z0 zH>ivLO(aS%%uYTpGqhp0e=pWjg;cB<9MV1cUht?sV;|ha!!leaeFImJxJt3eOkVb- z-0OC%LX)up%(VG?6XIIkYQeF~n1ohkGuH)Kel%t3P@1{F+^KM-Chn+2s6c@xMu`Ws<4v;1|16_y9!`redpfWG8$ypZhxDW~_0Aq=!9}S!Gh|!Y7=`n*5 zZQp)2d0dj%NrIQ}Ot=dpP+$OW~x%e$# zE}H-iXT=u|-R-TLv+jTCt==xUKcC8IZ{=TVc{2c@A%hkR{{|=)DgpA&iRb54%D2oG zr-*+#s|l}*O$+{g?$_h8HLWP*45x6AvU+YGo&!%>hz6nZP#S7s*VrlxEQT1$lqb%1 z0`o_wrV<>fh+R4bT0aXmK&Wxaj~W^Q77KQNa*W6^VtizyrX~$9{k)fE%j$^Gm9?m)KD)B1_2O(TkaI7`!CPR0dPkG!25_5& zE9tYbBtN>2mU5q)u5{TNjG zI>QRQphw~tr-SryQwRt@!GFph`P@JlVfCsM@eSa#@->rR;w@y>*|=z$+th$B1Q`wL z9;Fw6(n2qw!SFb#aeih(0=gIJek!)=GE_| z#u8YOhTzlva(H#f^)Q7w*|q`N23SkokaO_D+ERw?GdQ=Q3u997zbY*QdGRqyGWAY2 zSdqgiNl}|4nK|ty?4_^86>h)X&RF0aWQ;Xh$G{-2{|k8-0b<-g1KQmM&0l#GK3U^V zFq8P?zE;J*fQJ~y>kZ2znYTZMhvu#ARsr&qS8Q+;9RLr@$@yXkIP`uO|F-)Abb?hU zr}NHf#{mLvBcG)fPHv`i7OhPof?~-cC^#ZqIU;N%^a@W#JIrk$C)OY-mh=YDx^|gm zFD}r0GAZ$e6e<274uGlcHHQ1`e)GID^?ZzGS~mC%MWC6<>tX%94)!r_|_p_*Qy zO_#}45;^y>JjVJBU?i^tt$_^>ZQ>;;e7L99SeNmjb5tRKx#=zA30`41<`n z5^MTj_`-N(+wihnor*8!b7dxPYliVs+5=yhPQa7<>6CF=3IVq&~DR%S}VRZ+8CS}wBg4)kBL6aFS{^l^FL)kjl%p_AOE+` zm#=~Bs;9QRkF=$Gd>>PXa-Z46v;i~uot@>?Du}k{m-sIE36}u!Q#u<>a6y0RDNEOm ziVo#v;r@~(6C_nA5LIn5`{{j&56Z_8%11P)X(2bfWnVt>T(9Iy0xLyjHkX4`emb%? z>R|C0oTpy_PC5*;PdEAh1p*@d1p?0Is%0{yEgX~VI)I7c3l5wtv7 zMR<$)&7vbA`fB6tjoV9|z6*;YpM}>2flh^L)7Tk+;M`|Z)=9*qasdo;H1?LplUON*VjUFm0Pg`PF@IWAJ0pC>_w9$Qee~XEkCW??;rOok5m8K(?lKl$1~Kp2+`1ndgcnGM0N)W1Hpa z`GJulE3YGUN`)MnR%I5PkdGs3Y?Tr9TiFg|lv>;~NruAT4=DDuB5Dpx+vXvyJxx2g z!7sjHNd6PK;L`SoK^W+T-SfWOUfqYKw1|t^qptKVT#g8g&;H}dtNS<$EQ?l*tIk_} ziFRbHLPE^W0V5d;Dy3`6P5%QR5k7Ns;o-eI54lVK_<07i=F9#|qd%71W~~DqcvU(d za{jBz)B7U-MV9LS0Z0XJ2RKE~G~E=A)#TkBs(eccJFA{VCD8wx&Pi8i5})jyj4(|Z zRv$RNUb|E$&1Fm^o{Ne`4{9&(7bA27c~}yz;(s4Xde1|1Z!$NWs-G?2T!bwL{Z!IF zY#VUfh?lBonVRD(P;q4BMnw!->kDe}7ysAj5oh*4 zjUM^;HSZdA=p=UNZ!{Ti?2LOm&`sb!YoQyD7d82$)%yWwnfdo(T?1y_<}k%3L~i?M z+iEOZgT&3FT810nWKi!t!VYNQ#5etx=JK;~c{Ztm&;}Zpq-eySJw8^sNUTJ&ANuF3 zS-)yuAtW-qMGnGmJtsobUTX5m>L-w`xH7I)I+YM;yvBlm0_8QLap7SIer9GuiB=?9 zCtkI|B@2cNS0{+I&C2?(W&^W3Go#L1`o>xQ$G=jWebeX>G#g$ivq&2xPv%q`yYe{H zj-}@FFX|_yFPm?zqJ>`T_I}xw#DF zK9|D*dP``euS?EXhm0VyE>GJG*2JEwwqK+#cnynID-=9k{Mzx*`;;6s&ENQ?{oQ*L zzsQY$zxn--n$3UeOGXd)6Q2e={@J~^^H66#v^XvKoUF+2l#PTI#cC!S&5#L4RTYV{ji4E8$TUL1 z(!{SkEI#;ZjU=CtcB`Mc`tbFQQ(*i2l@hmhD0yc?(63B8eH?}oCu!CGxc4r_bZ#Py zUc1lnu|%)7I)tU298!2V?9RPsQVHn-tHG`<$vnMv!Ur7_VjlFu!(G=n#E;m}i5q@B zA(#1a(9sK^y7T{mcxXS0kT?Tlq%#TR???M@-9B@+Zy#qx*Uc>eZJJ?YCsLb6Z~#XD zX>NEQGL&2V|5K-F+~_L+nt$BR)GrEq+zpu1q%f-9NM!}9jM>s?^%Gk&E1Fs=l}uNC zX#)EDs;8A|?@sK;e9A2z`hza?#V9VNi{C3+3l1INO^6X;{<7=>?ah2jDiV|p4tbTh zA1g41_)8$3v1R>K z8R#Gy=+tja0GOli5zb44z9(~bxqC}NzH@aMMMB1doD_E_Zz}$<7fD_3h<*BcVBqW3 zarQUv`ufen^P88h`+)}v=dI>9g-0K9gMFSpp6i@EAivwXJ^$mT-;tELem5sZ>c>@b z8egMJ&C36JYrf!-JJr;WmOlewCVk7`Dx{u3)?0R~7q| zg-q-2H0bQIt?D?ZZG6tIT%hvzvH!X8AEWV?GcR-7&i_^~Q|FMmArqu|wk9A0U?KH% z<<)&~UhWF@?G_wk!4GABz(w=KXmSJBmjpxr{i8$F7UQs48$l+w{ZO;KM#<*+b9%L)YLroAgYI zBV=giq&7SAW<^v$?2Bjc%UdNfn)9Qrf_Q(3Q16+TQ}oN0UF~I$P>_HAW4C@Epg={r z&&J{0XHSMjsD7skIK7;F!ajHClmh*S1&a1+-k!3XWf%b5PVzr2kO3XeJ39x-w0ljA zmKOt)Mb|+`1w-}$O+H#;Tv**r?t*kH7ogIo{$~0!h81LYciEQBc$v8)9ppnyM7)pN zelgkh&qad0dq7sd*M=~3Wr(YWzr^kHP-?H8)CH|?tU!>n3*68JuAcTZLg^WvV|)e6@m#?V8-TX{_Joe14H zB5gx)%j`9J$L4#?`Cq$|WnT}F8W?wG2>P2YQs&$4JaJMq;ZG^R3-n7^8%a~GvHgzz zHIXs?gceML4M}aSoW%H;O*4Cg4YCvT*y`f(YnN+RhxWk)@KAN;M+587i1gYV4NB`h z@T;OpDW1-CV?e9vuFBAsKoLwZubq9?IYmf~-?s^36+D26V0I1`__p}_Ik|1waU-yD z-nf75spQXd^Vha%Y->DwE_TLKuOvp_O|&Lki{sRn)Tb4!N`1~S%eax7E|s17Bf z&eq+qn12Y~?KOY+z;myZhaHoj+V_J1vjfrFq1tVWT_tCX?oxm#{rix^6NY3kOY=I5oNk zgNaK7YCo8q?n=3tpc94n7^joqzA}x-Hp^S?$?|y5g!$Yw_IQ3r)NN&(T4@_p&+=ka z@7qhcDxDwsasi;VbxkH)0)V{qVlQJ7wHcNiby4H_Mu9}#qY zl7A;WRL}Bd_4hgwePrg>J2St#N?%qHP#L5q^O<|tpyzDUf!Xn~<5S3AW~op6^$jjX zUDXR!CM!#R>-hJ>e*|I+OG$K>O31OFoD*A-&|{U+pbBPh?ad>IsKQK7{;s#w3O|f=U)sFK!XguY?Jg zxY{akAw1)%X=UQeV(fpy6wHwE78Jk#cyAv13&{$hPHsUGGyn&{=QnhA&$bkkfM)BH zk7?%CAXyjPh@)H6oGnK2BhohnM`!~N;-xS#&?!5WNmp{9giCx#U#-h!{zJw(`7eTB z-h&Yc#=s%wA-ELm2k{HDBvh)|LKc0zmPB zuq7rP+5#W4er@a3T{yHW*Fx5sl8ih8Z*w(~$MlJjUpS(9f{W=PjS5zxMrI?ybbPk; z%7Zv@haqxi{>j3KE_QR^KGWi69w36a>U~)Ccr;^YL>0?GU~;U{nIGsI9?+5wh?_V8MtU4&|W+KU0W3(azC9mAbqMV zu!LO@J^)x`JAsoC>-EAzu%Zxhz&A|M6dX(vP{W{-$CHl&Eg@g(9-@D#7c}ejfnY%O z!2-L^QFnk7O<$OID^yO!c5qIBpawL#`|zwKPQXMLNdDVYC4h@{`~Zy}r-7dlFZWHR zhw=rf$eL+)m82t@Ss~1SMPrC0QWs$1J9-?~s&q&!{N)5H;pc?!aS3*hwZm6Q9V@Bj z+d0!={BZM&7TtWX{-Y$79Uuas;|O_*$0%C*r^#$_G)EiJEX@A0-d+yw(x(+_c>hNh z=x3lq6d|6r8At@f1ZRxI$Mywo`mfBehjGuXLj-%xJmSt!?(s8oci*87f1U~#@0~mY zL#oBJcfNb`(=MQ`Tu5%5-#5(BJIh`kg!K1QC4>Q z@8>)*%rX@E$B}gu$ls3k(Apg7hlEa$N5EqMoUkJj!$)0l7V^C8Jd#89HlO0zE=b#z zJyi-&Z^BK#KcSv{BX^2hm<+n3e`}ireP0V#)Fvu^fK|p{wEBR16H#hPmKWcusqPkd zB9p{keZOCM`|7*jwyc?l?8j$UvX`21p8tE@m7*hljpDHkcN#q(9eE59EKD~Ko=XCE z$_r#i)X4QdAS;BX%5J(~6qtpmd63mrvYqE5;{8YXl)RnUWl$ksa85(|?EwV#hJsIk z5F7^?JWr(@T4l`H=n*3N5&JS4=haAL8!A6sa%nR2HP4@0m$W9ie*#&7Sg|o$?|!-~ z4oRb)GaG{`(5Py#P>DxU*%+h18r+TBwu{kroJx=}K3P^UEDo>LIgD!hlFmtGVV1kI zQ@Q;tRXmI(G0g}bs(|-(O3AWSZ#s8vUpbsU<7^gL#Z|&iTDDGF z^%Jz15Gc9AAD+3RDg%m-WlBj>UuAiZF!` zunDl3ZD5@Z_{*3?V;R4!ko1}%V`#lu9gK$1Sac7^^x=1Ff#37W3 z31iIE!we%)!mL+e9!JOi#90L@>~!fwCsJqR+E2pw9x?15lQ5B5KKMW+Z|qUTsw&5# zVf1W(QBH&!KM}LcnJv|!c85XZilblQoy7WvOcHB#pzJo`0$lBXIV4x8=sZM1njTH~ zmwmnapm4)1NYr@2aP6obH@t(`b4MBZWaqC2;_>`u8Z}M+dfy+QH~57~7=e8EM_~`p zF4|XK;qGcHr3#sXvk9O^_m3_R_A@Tdi7T+{jUwJh76HC^Ien;*Bb1gpi#rZSR~?yB zqN*P^-IM2u`&D{h6f}J-f|&hp0PpaN$yNcO;MY6Qx<>Q+?VF>z`vC|lHH(RG+;_qr zAF5mva^BtJHakgn`W}dXJ`6G$Vv~-z?W(q488KdM{G|W=vQjrn_XT-rmB6yI)avJ+ za*`_3GEpvDL4g6{GIb-!HG3@P{@*_HYphZYQ+6gaEBvKnJ~##wK!NNb!C}#qwkT#gkR~=6_wLuYU<;sOG>vM>0#t- zK$f>6m8d3(7+rLXW{wlc;{%7bUWG(TwG??g6Q=jOz0SSa`_G|NsWC3hjK+1Ue7?o8 z!KXD)z>7QYSx!KaT#TKIXgB1tkz4dmSQIrdwUOn$&FM(WWFk3)$0=YIcd5z6WT9fD zK7h7EPhWy8)h=4HsR$o-Fs@iM_m+RR&ek?36}=Lxw5+!rJ(wb}zcRuPWSdQai5*XP zwJMhkOBmhySE8^9VZsyAG0Z`(g9Ev%GzvqVpy>x29P+^d!Xz~O*2-m1t%~q;b!>+` zMg{~TLp#7qzwY~Au9{A;B*-2~X?PUb^(iSzPn?<;5AzJz#g75>+sZQ}>wJS0-}#rG zA5yGPR+isv6!ze@(=8?)!+O#=xuj!hJa|h^Lgk*|65^&LlM|4QH^dONG?!u;6@BX` zD;`uD!-CvTLhIA9oZNWA2+0tPDU>5)mMciqk`$-rfjn#<+WMthv0PCrq{%K?6xr;3 zSvnn$_ws-Iy1HDr_Ei1~)acTaO9oYh^|hNPdaAB+bYA29c0P! z`0f=Fg`@bX^c2WKt*BqcazBdVM@+swhD{X-F`z!7_n^`e{Z@3Am|mSLxJPRK;-&uo z+?mLiT#HpG5<*|{)7Pnmy|?;J>1?5x45&Q%WiYEBm6G{cr?U51M}Nq@k#_kZs<-pH za&BO!?^`S7i@7uNhQ2T|HmRGFgs{tDt&nhXO)qH{WxmN8iFBXIywCXU0GL zkns^-eyxn4DGplu136Zv4ZXUJK{-WflPf)f_l`t1-C68ap1lv4+mgcA-+zBd8~#79 zTjc&^rxG2}9=M@A*hNx5SyO-;5-anF%r3>{=>_U6Q zN>_A)a@>;?9_Z2BOy^-Nk>mqIYC4jB?xAH!90Rnq0+N8IMFwQ?51D`qtq7UB% zi)%*{R~FTQAu<}++I=R8Jfa~zh3qOC*hf1CMwUQ-WYz-%Pgc@{rhnD#0})FLa9yxk z+yanpSkygnhIneT3Dg)A%3tvGMsFlyD9LumbiW0@a-1Rqhg4Jz62ik04Yt`-;ZwOS zw(9!AZp zOQ3ujdHzBCH5Jf?cEcvBe||-BCd0;eph9(p&VS<@&Vk-=xj6s-E$eo`Ql*&yVH+R_HpDvaueqwAkKUQ zXu3*CX|UwjV@3BMGQpS*&&lb!{Y`|VbJE6BF;0rRzF0#);qk9n90Da3@s}Yv8XJ^S zg+=Y3B`oB!6pzRKiuLDGE4 z2k>b0Jv){3jfof^P>Rm&6aZSTho8rNuE$aQR}d*J^04#Bisnt7I0f%HIGD)z^x`{o z1iEGZ5;H`+g29&a@GD)}4yp9n9lh;57;fEC^-17KF708WR`=lqX_|NL3_R0ADG z7I3QbLEv5~Ov7W_3oo`Oi?BGB0T-UM13iJLrgh3eo{si@Jm5x^{-xlrOcWF$tD!v2}h!H)#q9f=g(E$R`8VCF9@ls9G%z=-Q73gyr zdKit^A9%i!_(sXZXcZ_LN%(q}VpmqLr1L!HC&lg(T|HqUQV6)d3(t;6# zeKh7J(-D#>M_C_`+jv6n-<>%Lb~WLXjQ&HiDWNN>V1#*-nQ}KG{yMo38;1i+Nba#Tw7MCbaOz}sX{ zF;09**~CLjdRm85*_7?z>-v*OZBPrHL`%9KH}~JQrI0&RFU4eT^M$D_=SjY~T)pIj zRQ2Tq#uC33@o#4qdM9Q=3(llszpy2|*$nv&G;6gKrqc{>!5F(yBb7%AAZ$e3+-StaW0Aj`y*4_sk#HTr%Z9lM79nD`xtoFDxrCXsvHz7wr zX*pljaeL(o(5$rP)6b3PCTgvxxGBd0M0$lh1Jd1~Zr#3Icqd`b{h>}SzfH_El4zWL zKr&~WKOHed&?AEa5eX;lt+VQ%zYF(4ZB#gsW4zVLP93|$`T$d1xePh{xet=K+^;+Z zp6Uf+-4Xv6mJgG75&91-Z%rtSM(;lv-kpqymIEuM3iYEX+!Adm(PrJ6cs7@CLSmJU z9i@2Ux46-G4_I_xJJOIn!G;)<{ZYhPl^Mu4$0w$LZ)*9o@EiM2Nykf0=C(pTa{r4h z!i94Ft?rD(A$us@JJ{RjA%w#U$T$hVBS)6-@U~f?hiAPMyU8}lt=d{Cnc>$%%z{MX z{Xq|ND#}p$d6k!|AZ^-buMl@+9(nz>g!>A1@Yi+9FZ9_Pg=H`PygoMF)FL@>`YTm0QqeThuLUCM32$+qdi_ zaQ^jv%@^P0_r@Dtqe1oGJDh&JzlqwbiA$GP{_e37iusws%&+SJb8*5}+VIsyCo17P zWCPs-57g;*I&<)9x`))Jm| zB@dhfw;<0B)836|om&A{cL@J^gZW}uB3Tf>Tc0{<5B(@T=0E>kSaV$(V|Kz*o@%l^+VRMM?iJFx_3#t%)K z2OhaCjd&v@jxCT0J_)SgMbNL^amTM2Cy>&1Ha``1>7f4$yvgddrb1CMGmlBn#Q7OJ9tUPw$5 zz$JJzru$UWLgT0Pog5TC%@sEQt1X=?Vuch~?+mG2fM0j4+MuSb@|m!5{xf4X5sS{c z;5in(pA8vXFD;rS@GfT&r9y0ZNT(mUV)-q(MF3-pi%ps_J>58Z zEk;TMQ{qA9IZWUO+%vmE2K05O?H$%VE*PgQB?36C z{V>zCvkKu?$ku3 z6Bt#~%lOZ8rY5ONm4@HVg3t|%R0>ooBG6I+!Q#1*kIKY@tU}o6Vy_~iE3C&uksio1 zu+dX=k169r!Ayq!t9r516qRs<24%%P zqU+7`o$u$)QtCE8|Ei1a*~7EfAA!4FTL-+fep5b?8&Wxr*?Ok5le zo*VQSBhXF2i@gh7ef8>{N@&CEeA`5hSKt zKi&W-USpGhN}TUaG^shFVbBWSaD4-P^2k**%E0t6WJUxoWj#=aF|aKhd*8R@1%m^7 z*gc(+_NMXLWmT;+zpgezkrl2(B3I(dNs6GCX*pTh_Ep?StlH=S_ULTmJ@o;&0N2EoEC%m*~ z-GV@eFDYLzYHR#W9hw z{K9&^8hMZ{WMsKkqS-AGmpww(Q>-c=SUrwdK zOYflUu+3jAUC(-rndyjz{y_fS{m_-yE9v5T(vq9gSdS6{H&V{N$@BO(%AAs@sQXVw z65xHkBC=lbDyxh)&TiEty!K2yTd)1W`GY^-^8q)k7Zr?9s+|eTVz#PB>LJHSp(W(0 zg6%La4o++2(9|_-OR1d{k&pSd>PBs!0aZamLa#2eegCn5RqOYFzE+qKx#Y_eG7Jpx zsQZGJGWEckh4OiLS{zP}6jUAQ?Fp5#4TcWGp4s`Nvrb>p^2#mc$prl|6*_$H*gg!N zsLK!$QKS7AUFba{$3mh;viQ&esu!;_KH7+^B5Ufm!Gd6^8#o?W`P0oM=YM*tVsskY zt|G}Z8%XX3aO>`>OT37Bi1}md5}dsp#EF)F@~xhnkrsJTsPqO*H%LES{OC)a^!fO< zZEA-Bwb&?l4CYtO>crU}#b0pxA&zz-%f;=>o{v?&*K95B&AG?hQQ;1=W|-O0c0w1v zC>g}leyKHg@#Z}Ke0VC(GwW&&npPq+`$h;T#kRqR{zNboFEy5IPcm6I9V^=ni-kyU z&DM?|oGl#GW*#N0iw>IIdb3aWog&n*(zC z7nCAL38-G$bpBW?+_DjYe&up6ROse-3H?vl3RU`~%c5R!u%wVY%1#jHPT|k0s&@p( z282{cdgLM}#43c0k6&?5mwhEE$8R(^Ee)1#v7HKP98mkK{q`hL%j`o#N=_N9rn;7f zITCUNX!bm)z=$=_GIO8|%>5l%S^`n81?N><9Z_us6JdmsDfhH~V_+~4qHIL;4kzQz0~v&iEe8xUmx4{* zhe6gh9?fy}uzsafc(l1Y%yv8{HTq&);SIU5I9lwsOpd_#wMkvjC0NSq)T32@a51o= zTqFwm>tZVvwEmUqH^-VCZqKG&Z1L2pt+xcresrQM2DJ)Ps?x79v3@dA8;vj0{_Q?% zvs7s#RZYf+cUE+D#fH;FB!B-<8ph}bJnT%P zgj~}4E?UyI$M^(RbZd(XD8*7*jxz>2OjxG>w!S5`VNKH(7-l8XoH^2J-z8tU8TFyU z2&D|SzE8x}1hIuPpY2TY(!v>9h%jz{#7|BT%GU|VS1y3F}WIaS?V47Gf7lI9U8Ka2=?)~4Gdj}dDwS1kq z&?oxonuL2ckg#?b7tI6Gu~{8T%vyAG^cjPTVe{Lh2J-~nd(4|3As2+Tc%gUqFhgEZ zV0Xo+{NPg4A;9rqaX_$(A0;Y8cD|slxq>CjJ+A+*L8BeCl_bdvW67CE(b!{j{U;M= z&7@}aUHRSzH3|p42$=~5I{BUyrP3Hy=AV-a%FhNqP{?BVPuC!2BBca7Zn^{PJZ0vD z*yC?>32+gzQhSY4*Tlp>=G8nzbPb6iJQm4`#%G#HJ1|{2$kwJk#I{rX$S*AtH%htH zyqRY5=27Zge_(VblHVUOb8X##Jo`)&Zy$mvuOP>CE_Yk)MsFw84g5?+=w~JibcbwD z`3qVn^>Px5u8k$Djuzu-67?GQCXJ{VY2~Y(8-yXQ__7=2s+*T%hO3EeO+p(VOnqc? zmU#q#22pHe6DxA;b-Q_LffZhSrqb3sr?2Yfqf@ERKtf9t zF|tw+c7(@71ESx9eDJH>h`q@EwnOuK-`FtdKtwF#`QP-!-35Xl2#K+pxm_?e9XQHHc8A)^)aFCU@809VfUHu&(z*%M6NXx zq_%w7SJ-LP4U#wL^UnEFA;sniR^w6Yb2hVEorz&`>|3X6y18GNSQw`3-U&AgJGm>p zLi8>BEq|OHMDEUAf40m?y4yB<`wSf8vz+qq#~uDr!PMj2#Hh!!VRkJ2s7F#0bnaJy zv|>JjS~up(wIlR){#zS#wLBHLei-!L6EYYBiB|j(0dcyl$Qf6s5uBzSk;{p}JlXY& zi7@*KmGaBp$Px{a6Z7IvC ztPGV^PR-X%&7+)9L$%Ky>Q;*2cSOqvhaHDc{v@?}GbC5jQ*lohU14AT(9*X_!2WYS zsBH5Q5>N%**!{d(WJYZ4*7hRE&b>uqYvGfdUAbSaR(~wjRKv@9yg%z*S%g8immxRy zcP%qrlO*gr+e>X(67b`1p?J(+0ryuLVnnkR`o~!E#x(JR_ipnR;+ucrR1Bw{U5r>XFGa99-*OF+y&GU4?3F%N}Vd#gC7taoXHmd!_r ztbNl~+tGKwhEy&fct5|SZ8Y4#mt`aaK5iLWEE}|iQSZ^0Fu#%t^JbSQ`>q5Go>cAZ z7-bm_cDNY5Taqr5F<5@yw%=F#bpk*Hqtz|cYJmT_P)r&h5 z%Vr88^qFaWQ*o=}#RiNIWY8pNmL_F$U~?G^l^I1x}^CXKA|icRJSzUr7``N<9fW6kB=L z?c3+I3&ve_=fvkYwH9Bq?bybDz6=B6jExpSmq`mh`rcq!HK3L9YKg<3-st?0B1N}AB_aSSSn7Ldm zR}#pAtAQaZyE2h+#T@_d{Q^mEbUY`+c`{_eFy7VbHNtZ zL}53x^A2@l%n=U4O*7THb-srxhsl?o0S7kywfHpqCmE+Wvq_tlo5+?Dt zZsuTrw(-O_gOFY}u72`tTnosh%z4uJjHpe_ zS^biOh#H8UCXA%=NXE_k)#iAOE#qrWZFh5t(tdSTjo0I*J+iQ=`J7hk6=ACkPW|6M zO#IEk7e#C-`Z(Q`zdO$KKL5tO1IyMDda|?Mp;xRLv9*)cQ|e;VO(^cW^HIbUCXtBz zNdDn9e;Eskq55ZV0kKHJ4qktm@KXcZR{r@MjR44xkz$v&(-{nyr-+gqh0^zL(KL@7 z3xnc=u1*ezTQTonWb>{@YgbtDh;;gXw<)MxA6*#&r%!9QS3f$gmRER+(#F|3V}+I( zRW~8)m4(756H@mf9e?*jjERGN0To&BlNrx>7?)m&507)@#qBHHh zbf!4QSH(CQ2LZF~qSB=C^PkL@JLLRea2J~?7K}S`?cmQFSXIjqpGvu*RBlE-!BA=3 z=aza-G@c;H#}EjrHWqgMMdMFMHDCcD+Bv?)%9fI-&$q8Ng=jHjk75VU?i2~f*_*X>0$K{!H@J-Sa&3kQ4q!0=!^r3 zp_7aWiUh9{ID3>Q%VK&k5=;26KinrzQ|Rzk%}G!deGu7dJ($cr&1#gJ8tX$8uZw{@ zF=zQNNUt}EZCGp39%^;A2C0NNjBtB-&-79Je(XiMGeZ8Gwa0k~n;q|D#V>?()uuBT z@k7;{AnkJQA+{)JL%zxo(JUY>XWiKrP3Im=xi4T_dB7`l#t^J(67!m7(_J0I!%U>1 z*t`7^&ggLR98T*;xv7%z+A+3av40B3C*?TobBZnvwPz#3SD97QcX+5g8~V8l_U7gl zTv`{A@Vr@#S=%CbPFeFznuhW18rTq_BPtFOmvK84-hWLJ#cdUwi`3}9@AjKW01ph? zQ$>OV6se?2&*Q|tW=cXtdWUJ=$Ii-a3w;xLK8GL>b9P&9v###A#aQ+qL_+iE^jGiE zVGS-Bafk0Lp`pgX@!lKAhB%V@!81m7a}Y+^ql=16Zrf--$xh6u2)k{j@msK8x4j1+ z!z295LdAiTo&|;tTZP494c{^AZe-!yCUXh>cdrO4(z1V}w0v56S%HkaJX+~irVy=-Oy|tg7tS-m9t;+#aVpA&Re^C46Vgd?4EO< zsE@j0xN(;g)GHNxht@ zdyb(U7Xsk{Yx?cAvrgF8k**BUQwbCDKG+MOJ$nP)0oitPE^OsBoM_@1=J;LO`Xu50 zV42mhEU!97(KnFhlPw{JU64O>2ho9M&z{N^M5;ltA3KN6E_x5H8gp~;YzXgqiYqBk zf?zx}N>D?z{xzA4n5xw0$?spzwG<42Dn+7c{QhryPy6(W_akXuhxO=`Sa`~eP4^OW zXL|VTOjE{fhn+i6w};6lLpRs{O&!Qm^R1DXh~5uAAE7f1a6w)0{aR^NU9^)=*EiMC z01o_3$UDS#wieDaSgQE>DkaD*Y9rM>-x)@XG%#Lk@WT7mys-QR)A8~lLU&TPq(#K< z9Yre`zvV|1a*b5ji<_zphr9-SXIzD!TNGs!mds~s*_we$U1*BaWycVSt;u{vV9wK# z>S>JU774y20;@02EC_Sx10yS22Ajz8gcbvyHDl(WPVXs;1skwR(EFVsOoz{$xek24 z!XZII)kj3Ah4aQ48vaXNCnnRrqa|u7Wf|x=%P!p+D-wu2ca{voK+bFSm8X*RL!^q~ zg!>!lN;Hz5jEVZ-*ewq)rJBCodx~7y;Yc^v=3enPMv1QmGT6lBP)n;-89`+?d(QPL zZlb5uOyLx-?6zNFCeFNe9YPed>)r_dTWEGmbgd)h=CZ*eSDK~!MS@G)2&PHK<6!$_ zOe&=Gt*y`2#8R5++Gzk7yHq;FR<9X}?dq0~!pfe9e}aWiJqChOqS%sC)NECzv<9bK zfRLN8n#Oc-klXz7Ofc9G2L(yuJG_UKthii4ffQ2$VfI^Fm87c z6EKyw9?4!FUDNj*Jz|ZcC*99INJ_m|>1y!^8gNmUFJ3E9Fea_Ms9~nlJ~ulC*c_Ws zV4G0I|F?Zi5VViQqA7-BhCcB3XTW9K#PKMuEprFm=bl@MW+$&(5_E3z)vYH_1Ja0F zVl+V%Ru;`6!4*YPUV(_LXUZf|B^A?Ne|=hdoc|d=n!_5W2DQ;grOh(>On34{_T(!Y z@#%O1YrP!rk3}n(`YsEGbNE)_DVaYJlmydV1Dpi#|6s)OxEoCn)Tg_TF(D1Qq|d2X z!=zF#%`CAWH#=X<>V}!X&>z@d;`el)C8*&t}q9S@DF$-^wh2L@F z)}4@-=n}=142k{KPZOOEeJV{8yq?Ft`wkdiH3Tg$4FIz9SnaSa_AlD3yYKr`>Uqj9C`^@yV>g zsa@f92`KS$#6$n?chs$@TE>~Lz46&zTr}!UjUuwdYes?YpAs*uZv{<)M;=&or^)m) zMNsHIF4a-R!@Awqi93O5#QFkh3|nq$pyllixbc$$+hn zkXDNFV!IjaX-1S#RfjhDa#|ogyX&BMDh!FaKb%3sz{{{q|KXpe(-4vzY6!7(=*8o% z@S|ktJQfT?zj%X%ZRb1E*zk!4(*v$)8$wmsIrz*7%Va3=ecW4^>g5g#E=NE4EDeg^ zdgr|m)RDAxRo~mIOmfXJ*_~gUm%H#~LSnXGpY&%OZNnHjR+MfI$ORKS zZ&iKx2C2%D(x@;fiqbM9&pG;kJyDj5+4o=Z^4oybhbxi)hCXH8d3;dt2n&MW8k>q1 z@9d6G<=G_vEZNMK;eTtLJ8?cqR~xx?@+&d&am5;VVfEVxGra2dj3MRBaS{1MrWUj! z1x1W_82u)r`|-6-3E;;DOoQK4!9$)cjK=N;B~}isvpb*l&h?r$V*WO`Y_!{&$oC2H ze1*;1uSIpBi}j4gsh3qrZ_DOu*73I~UG4YvIxT8X)f)ERklizW(%A`=!Mr9pXC~UD z2YgK;;PT2F`)}7#DC#3*K!ds1gUul-a0pjPJFU^ZFy5F(B#MY?S|g(>c%w5veDZB& zE$pfX_dRwQoU-tuD2)V0qKx3x#U~sr=^YYY~pJhuRVL^Gzn)h znpFw?i5j*M17D`-C8kST1NvKD{IUK0lAkL-J>y5_V~x*w?AY=G; zmK>&;(hbL z_4e%4L$~hpabFXyfTQ>S=_ax0u7~yZ{sMl^FP-Tk^X4m0A;K%^&10=$O4OZd%90)z zC_h*9H%Ze84hO?H2;*^+V9lwj$iua46{@H}Wrx?CS%Xivq0JHZ^a*kWAr#u{Q95zr z)G5`J!2>#`EfY%FxJbdam#xxqs8V<6nDhS&F_J^j_&lN4Tx`~{$ zJN)wL#??C4CtI&DDdQqm%oY+95nLc{avwo|!f zx0zYq(hY@gTCLH^%@n=KLHni>3pcyIzv*>e09nUVi!!HAXO6B}O-^43 z+uv=AR&}KPy~vu|@2Ro<{OK3>3svKf9#4O`9rT?3bP8s>v6D)s`_C~hwNW11s)jp< zJeCmtVGS?eB{ud(45Rd$TJBCBmQ4h7IF?+xoCB>3r9U6fhPQYFJN2O8NkMevi;7@B zP5+(o6jOrSk#M(`?c%1zprMopBI)<)TM2kdbA!$@p~qnV{V;N-kMrLc*}q?RV$k{{;Zm*tjoF^t_e00`^j%-LO5&IKLbxXTlhitrSESnxPwZ~ z$T=3TOr{X*h7@X*(bl|`etme^7@JrOFo=3P_hFGKgK0g=;?@MB94;tMjfSNZuPi$8 zz~~6Qm#=+?UB12b^zR2f4VWrs25Pg{-XUs2gA^|2qj~e!zVj!aEA*D<4dwpLeEs{? zUhquTB})o>8$cPkndx=Urw7t0vh5sNho)Y^1{E$T!5d`vERD ze8|e=(k^n26FaEnJ)g=47dpvQj=Is}53hNp>B~=!Nmd37PvB^Tf(E5&uC6^ogH`N>F_+vO(%*ElYaKB%Jx!+W? z-(YA-webHb;kVK2uw!pH8z?Yfq4Mk1liDNb`n;p}8C0vfaJh(3@CZu_1@tnm5&f=R zyH^6H0sElI`~@I#>(ZG8*0X7GM&FD5Xl-TIna**l>b@ZU&qa>xw9@?Z5JI_(bV`C! z8XmDv@0s_ul3Rht1WB?9(cQ$AnPnz^5oj&{s69hN5?+b?2^X@og{@ zDx!J4B3yLI4oeaN$IXf=wskxvc5HVkEq{Hl??T;)>UM*8CLUCwfpr2B(;jt zHZRCV1DO}=ZB$Wz3j0{OiS$?SS;du@W_Rp0ugCcWi!jerR5iWZ#_Ux3*F5#FP8wXz zc(^O}X$^zqo>`arvRZNI>cO|6}YeqoNMOcU=Yqq`?3I89+p&rMs1ek(TaG z=@=N05|Hjz>F(}O8l=0sn;`~f|M=J0XP^Dytoh1vEkR!2_j&I7x*oqEA5iHsepBdx zq1LYmiIzK1QeQtyCWJBQ8@xLBj>{iN7a}41T!T;i3@biUF5@;@<(@i2y@|f4_66Ez z|7Ubr9MQYVTpc`Rnu1rxKq-gJ7wTSxx_shdJmL3Wg&gX#+k8r(k&}gnea@cd2wkJT z2dbP32^opm;v5@uQp3`mzT|5}ka56oQc5Z9-VuJ)?dejs0DM{MLF zFn{=^zf~||z9>syuKDmW+kU1=MgE|@p@s#g|0r<%d_nsC3G+$>_)kaFV4=TQNR~gl zY#zY1UR8?6JIy=$=T}+{J}aQ~nOQRWnI<2Q^Ie?K@=tt1v7M@Af05Y9d#S8nQDwYP zvRwZ6S-12(pR~+l?=0TP>D&a2$>j60Z@x(=ek`1N#Q)*Lj+oI}=c5GL}sew$m*PbcB89fvq7_ z%1|-7`NQe?$ob-WB&56}EQ)gdKY!=AMo|I#dTrBQVNpyj<=1Ya)0>1ZS)LzLIBg8l zWAzcF%han4&6+fgZ(BLe?v&v}k>_0pRxiy(_>P?wunG0+9Sqs6hc`gp6hj#tMGlO zZ}4{KVZo=GWIdl=-y5bl zo=kjL>lG`ci`BX+fC3k)QvF@i90uyY>}4W|Rf0d96;FQT>@}~v(p_>KU_L~AO(=a# zq@9fg0=!Lw3`Gx+Bd3-NHO6xc+@0fh^6s6FDX91MwUjTRtA2w|HJU z9=9RI#=c7L=MU{Z>Yi(WNHw`I;`bah)wH!vMUiyPo14iIh*6f{`RD>U=cAkLOgDh0 zCZFsQpCkHTx$2VfTcDAh_%!>KGoX>vRlfuh(K#+YRc2;}>|K+ElY5WEf)Z{tcg+-1 zO%E+!HRWc=D+CnCfE;q-huY1WF~g@>QtPcVVDm#s=dqU7UtqL67ryC>8xZsQyyd$$ zBV-H^o2ttx2OLE5r2cUKwQPal(4_V_KBdqLwM=1EGuB7fh+_qTE?yKcqRxh7LY>^@t!5PUnAz!7lu}Omtm10>euv8_ow< zMK~2a55L1$9D%l01T#Ghh%^;eTe=s*PXF}L+CATytFex+{l(7+oahl(UIoLpgL$@y zt6*HdKWN(_M*tDcP56^++^kKN!eI0pad#p;;Ms6r7#A+fq%t}P{QUdxcOfv@iHqaq z5g?O4^Z>sz>cpV|-V|3N*dC$!p1aaOl;oIR(~8$-2E7(}{+HaoUsJz8_P1zF6$&yC zNSBIOPJ0${xgAbv4b@nT^`0mAoki>yAGMxu%a=X<>~otj-%z&wa4_uc;5atiNO&`d zb~e(=*!s+vcAoY46HA#fnVM*0a*i=X`bKu1j? z_!I@4Kvb)0As)znA}+j{Pw8FQBNbMSDSZ7L$`BRNycYn`mM*dtPN4=_#-?w-m;3 z8rU<#CapTXo*4LoQyGQWi>(UrxB8u|=tWT~)mFdAQ)fU{&iR(RZ z68W%gCw{hSBkrEn1z_5TCbU{1J5NQ=Na_85=4u(3K7UVl-#NoxH|-WSXa}*1Tl z!Pq3hH_j8eE&Z#zZDGaG!#1Q(?Qf7n4NwZ6v+@P{Ki$pS9I0XJslf84`;jgplMHNM z8-TWL`y^)cqT5IsLo;kknkz zSE+VZ)A{=`T5Z3n0iQAcl=w-x#}5;{q36DeK3#hlWCs`)xys@H6R)6W9=6O7Lr5P0|%FBQ$aeZxTCe=&j5-AW!huT!Z zn?G-sgMBa$$`)Lv7Y~rv*Xxnn6N3r(J27%BY?^D2hziUtw8ckn)45AG>3#}&3EVFwQ#&`r;d!cwgfCL(A)GZTw+mMqsFbJz=W3}fODIw|bm8@`fs%xU9OV_y z&qV7%-+;V=adTqrRy)!h=<6j@6}Mh)if8l~uZF=QvqKq~%N%_4uW0`JeO(E3)ViNP z;Cy}Kk=+p;RsP$7hWB}f_^z7PW_xTmR{VArmMg8|Jz--=5tC(qyM)MYR4-%aK(k9i zNK`?nS_7E^IB~2Hg(8KPfc%}usk6#XB6u?pkC?#2Id5Nuj3R1};P{gVHb)HOO6)Ah z70#3@1NNhhoUa`dHQT1e#k@xuc9jH4zs&&Xa;Clw><8Tkn?Ptb&fN(x5T$~;i^_&k z?jFlb1cXdy9FfVxloUD%Z7F`!wQw=NSBO3E}-0219rHX=Li ze*Ui&?;IkW06z<9lu6AKemHRDeIu6&9F7+4FVTBHSeyWllqQa0UYc1ND9~9=juo2y zrCqleifdNfxK}s@q_lgE3Q7Tn^K4JLh+bLF%SE%)VLSMuSAB;+B(5;c(6l=JxEe@l z+qC=9JXnwzq#S#<`x@V?M-1HyAJ|P{TuH(Y8iM)A&de(BK;;}3=>Jbp+YadYLyo=z z)e}xBzel!BU;G7#s%tain_T#afFbdcss=5*2!RLOGljq>=un$}Y#6`yOqbwcM&jOMF^(W6vb3tvR6{dRqm-hJ=AvFA1-dBQ{Va)oRp#}XG6XGYQ zf^Bsn8xj#2@P{U6#}@vV^>s*ix^4_3{f39fDRoo*R;w+f1(}n2G7Ph=ZQdqEm#Kj6 z8NNeM`dIP}9D+6^C_VmQu;R}Yru#Y4Yu8xP@ECPk+f`j^HQakIt%$hRYJT0!{CXVr z&`=)Jv|%7(!DvR>nSSpEqC%eR&)O|8Qr3r0+wI;SGzSWpFHbNN#lCou!1e)Y6zXfZ7_?2t;ojw=+d1L@Tba+iv%)r?}@Bjkd@f z;6O=;9LL-}oQ%sc4MI?{OhUzLHu!4XW61;g;pUMKP4%d3z>QiTLe3aRI(grLjaM81 zh>znVEqE8u?KFYT%3Aw-UpvW*h*+?3fr{R#UW?ts?&gzycAa7K3?Nbah5G1eu77wt zBJE~-tE*I{oP|GXi}2OSUb`)v`iL6)>Z6~O;^}0N1o_vK{6r8iwc~zXAMrgVN(UN?>Bdn;zz$! zs|!YX{^QGYpw2z6=ohiY8Z4DL#iY~>TpaXdCoo8e|Bv?$=qi4sc{9!nodY`Dyf};NQWsju`6%zbaMlj65yCg=eJ#(GZtu($MZ<^{Kh*{+yxle&Lbg)_DLdTO#>vc6JPpRLr2sJu`B21FCj zaDc^%pIEfM(zVLvIL4a6mq6i^75z0yl*K6LDu!%05p+n0G4k_GfIJTUj$%F~tV8gm+A!6xj$5VI`TMXb`78|9>?oH)~PkO20awTQIPKEEEBvbq~9B z0#Tjy^papj+eznJ0+x|-n$?q1J*ED^SFFHlS2uwPhf?SkyRF*2*pH7{#(eh}c!*g} z-ox9FTxB*G#gwV+B1_Qo zl8yS-V6f**y5}CDHh!u15OC-=V`jD7PhqvGI^E(H`3o&ld*ANT*;O3(YDmuKB+hD6 zI!;b6Sq1%l7 zjSOA737V8mw1HeN2DyzvTUohak@U*6gXaR)H z+7IQ|%f~QjXSKJLp_oa7im;2JgO7Lv)v!xsqKo=aF;s?K_IveZ)!e@gNF_4kykr|r z>&%0|kkD_lsp_>SGPZY<210NwMl~S0X(?q5FzK866-D|3}tWez^uicAyBm9jE+}Il?@BG*jWvd?$Q9 zSY>mSyx9;B>Id;U%T|GAYXKYf5N3H`_W`G^%?^mu2cA4Y6i zixJ?Smz_=H=%K+ zM>6y+FhaKdNxhM`&OiXP`+9P!Y#~j}ZQIs#W(AXVv`uVLz{F(fXnZ-p9; zWNvaMRqC5Z>tq*EmQTMBE2OMbo_pMVJ*T3iE=D?}vG zWqrnd&(7#T6Eu;+2qzkl^t0NY6KKz zNE7DL`;Ma0Id*H|!9X06>)8q7KW89al%W`t6i)iai^`-J!B>E5(DKYNffr6AW%3d* z52;J`iayb(#mDm1_9txEQ}$@(sMXC5DZy)apO_wHULKHq%y~+&R~_gKM#H)FiSH48 z+RQaQ$duf&mBMzFswVskgL7u?*Rs#{aQbs1evgCoNL3!@595^Ke-GHbx;J;57qyD` zQ7GH+n!}L?BQHhVQ?IU2TQ+mxiw%Ix{8Et2`=QIyl$%WNuQsQeh=u0Yy^iNi!w2v3 zCK(hK`df9Ek@@GPiGACl-fSFI%qG(j`%P|nrWh~8XZs7K_<8j072vFGs^GmDPnV|P ze_kycvN)%n%l|}TPn64&J^EJ$@d(bKJe%kyIg=FU))D9qCj%iAmYopUo(PKY@bS-h zF>(=NccFw4MqU>?hR0)fM~n|F#ov#fV{XA(kBy8~h)IR8p3gnS|p1mqO~KG|0G*u#kF( zT4X|s?^IQt+B64~BIbNFAfHm$GwNj$d{la~0;TFNAYJgxL2=wO|LYFi`D$jrnhgMO z1~=`DM+rdVC3zADY~b)p1|PXNMUd;|m;ohHr~d zKIX6=UNvuren-P^ILRQOS~v9DJ^`qfG@5IGm?L_rLz9l@0&!l#JQ!rxu$j<@f{7BT z2?2eO#EUiz(i>=*)-M~c>r#d z5(%S^UMerdlZ`xu)Gf^7T>2*IUSxn+5RjB2v2VqBS)(>EF#9R(NOwx19@2{de%wQy!-UZrkar;i*tq}3P3)k{8x72Q;N8Zc{qz>5hcnk_y z4n8sm{b;FmgWMjQTp>RBsC5z?4bxLLjC*Dom%F~y{sqD{o!c=*f+BpR0D=IHApY-c{Y`%ow!~bArGZ;~e z3eoukTlxG?#3%wmZxKBe76zhc5~Lptdr8!vK;B4!`Kivt)94Rmz|b-5RWXJEDwF_R zPc?PZiFX?zj3xi7*t0N+=@Fty*lJi`pXQv1n;L?{K`TW-S2|pobc5@us1AQLtzuWy zA5pRxsj{_Ka<|c+FfIGvHA|aTqZmYcFTK>Q1gj7HSp9~6-txS9skY9lGl0%U z^%YeZO;H#tm?$(+AOh}u6`u*Ds22mUo+DZ}GKUy>;m(t48k;4F(Y9A9)>wDI3|A}r z0032(M=YH*4;=`CYi75-`e-0>TF0=BGhscRL8(Bx?A z){>V9KWK#)FW`EyB9lS{gDJYF7Ir&Mxd;TW_wMO`)cJjTtR265jFxLB?fZ*8@u|za zG5$A(hJ_dg9RM$uGC#+;jum3XixWlI&aYstC4i5$JMUWOX5v-qn$;Kq7=52^k{iRw- zyv1o`>UIWF|DA$Q%EN>6Y9IZOMpZE$cGqW?8*rNb=mhD2A;W*O02bzJJ>=lw$I(pd zJkEF;wwuD&r*7~L0S=v7PjT-_uF{Uty}8!LDVAG&U(c&>jwE>)EqMhQz9vTD?sRs@ zOKskc%@?GIv=6_C=(T>5X^UP*zMDEH0T32<^pR1(tnj8YY(;KuLk`TB(>3edAC377 zQ(1F^dNQ(<&`XwbQ&sXZIw&rI#Tfgob|);VK=N~xcygEgFYRlm?iR08pH zQv*uh&aTJ3VAbsB_Th`&aRulj)?29BP;>3Zli*JiAHKqgcq>3=O(l~om?e0)-M7!4 z#IW>Xe~{WXxBU2@0c_*8s)T$-$m*DQkGOHOM18!5-GLY)!N*kyt?_-Z6Z`k`{$#E{ zeI#B@RP75w@P%03;4VuNZS=uy7CtfXlO%i6^xO<`d2q`xkFV{$6?bdKHah+qrT4;hru%b-*F z_PjUY@XyGlkZFN%WkM|atNaaq0H+4PkUzB{qtm2(j@csA+x{Q9C4ZwAMgwJ2 z3+3GPc*``0OmUEdBYhTr)&nQ%O0OTQ+OX7fgv{&zuA54up>{`8Q)cXaPLF|WemaX9 zah~cueSvMpn+&)#RH1J7I zPs<9#Ka^$gXMVMsH?9OO#MUN$@#6Z5sk$S&>6AF8I%SHl`xy|@>~1K1pML~(TQLZZp+{A_+U7Z0af)nm!pJOFxB zL}V|B z6y@(a*`6_%e`9KA_}Eqx7hzxz8zmw-dcqrvvGPq03)FLh@}k@2#v%sdVbbsdQ|h(yS zul&siVRw}y78R&KGEq4oT_BV4J4V{ zW%jl5eE?cAy1)5Lgx5*CEvYVgl3wgimt}U{ye=vOhz185@);VxGm=P|%TbvK*F=0d zuAe{4c!CUR|DN3tz(J2D6M20SpoXPJTui?AQSX|BZx1t7ma;ONTKv&U$O%{pok>4T z+i=KBqhqPDLDhnk)xH_^kE8fmZW1X65x)7DCk-rCRW1vDjKxK>oT(=6(V655+HkNl ztY<|7F0byxf9@gkg`>xI{iB<8PH-+iw4`+hAZR1YfkjT&P~& zZ*cP|IM&myj!C^r1^2kj37&5KCmgOY5Iw1R<>2h*d|TVgAr#xa6?n}smz3Dia=8Ly z>N*?fy~VdDEkFW>i&BJHtNKGvKJD&z4#> zed1#|Q51y$FHDGTM62v%B}nRRn!1n0(cw{P@KGw5sEIW5%b*-(DEPPqbLt;(>uTyl z(m6jh?>>e|o&ikN-+`3b))i;U(@O(~N15dRq}ob1{*Ku1Waxca1}*##BC?nl2jw?< z?{7LS9vPF|ekp#a%N|FG5BL-|nPs8c9}*a+Uk~e$c~_KuC|b ze~UWNe+qr_1FNGXAkI8j+ry9*Q+EZji(+3WysAIes}%A1>sTDkM~pWL!iHbk_O1?0 zI}_d`K4(2`cu%#7x)QM4FUUw*LRE?(ok=E+)`ig#yaGUmH^%axd<9)pP8^3#3eEj- zD?HXV|0Q65ssDzm%u65E49E>-D^UDB1SQ-PPUJ)WJ0n=W#uPOm6$6d8(07+%P6Mhf zrf7qAm;2j~rux$QHEbu|5S}aPQPjy9RMQSvXDlN&tk6fiyo`lkr5iA7aZ30uM5z*T zmVsY=eTv=<>O=i^^4{NQ2wFsh`Y$_&gwNTb;B{ktH%)|I^je`lk3{R)KSp!=!pPhB zNSpMZ@0LQ%ORtLNtLXK|*>5LP;qift4bvo(ZkbGaecqdi1;g+Gwe^E(cJe=8szr5c zP&hV+?&WVheYE9zg5(yi!eMR#T$*c?g@TId+SB$Pq?3Cj@Qo3?g-;wUba%K-r74U{ zZvPQ}- zEr5es(FndF+rtfneF<(tX(WVyo%L=%1LrV(b+;URl>nd3MJvXRCYfTzExL_X(%mQ! zzK)us75baKY8gW%JMqQ+^V8mfAC@pb3xMU?OeiQvBKWgzn8c3#IA>IsFy#SFDOOT6W;4{cmNUk{;qS{Ge0o=2sbWR1aF(>#PMKL5qnHUVL5 z`<(bYiy*W{yjK#7MRq!PsP5ah+L~z8H4n5(yNxFsT2k(}GFgYyuXWLQV)MTK4+@mb z92BA70^B@w0UX={uq89e^Dj?)y|>U%MUjZ{A@T+DXI&;j-lJRz)Q9Iw&m&Y*mO|V) zDSzaHagv_>_|B9R#|Thyayz4Y0osO=x#wpDM zqWt~ldnh30QYtt@8M107`;Oaa@^q|QErYYtDzd*wo)?Ejb1(5!RfIoE&11~vo4Qq1 zSku(~Kn>P#9{8Bsfo9Ks)yHPHEhfRG6ZiDp<2l37hg#K~!H94PgTd2VF1+2or<$eA z-_acmmB5_tTSMBLW8^6&|1;OfF^0Hq0V zeD~X7DR?9g&yUcGyCf8Up;Z6>?-;Om|70VCa%FISJ$sVUB^eO^G)e_by7(iKxBy3& zQ^$oW5(+kk8|1U&oZzl%c5(!o<5XwBp6j$+*+(4yx4rf^x>XQ5$~Pb;mA;xqWlT<>5SC*&eWm-7%LQ8De;>gWhIU z{;daOC^XhUW`qgHp_Xq6kdQtyqJ6f-nuWCvK-68BTuOVh*Wi`p?+qRT*)64gptmooY4N9^^GiTC|5)!p{Xh{ z-)S_R;`=w5S6$PAK6u3WJ|l%K)hb>3i${1Qv^?&vEhP(Kc86~%{%cDfZwks_?lLRc z2rB7YpKj0_N~|}Bm2SUd{g>5PX;ql+Dfzmx$m=M}^5}-3mC4m#0vG~-Zvzz2Zd9u5 z5}R(B=ZP81PY(ANI;W*xuIG_nrj+iIRnNUOw@DaY{7g_%JXCTn0PgpORqAEYX`0xRR=`_HBFg5x4ZF9 zDy4bI8r=87ss~b}?&B}oqk22S;+#3LNba! z27NUzVLiWCTrWApq2|*8rx9`i8nDm>)_(J#^j$n@0i9Mw= zuLF;DnC>Li>+|pJC-S42bQ>oQ-g&PIXy{Kwyo+*j9kQD)^+xr0egkktf3&%xx-SEP z;cquC5o-w`irI*;T6+#A`;US%b^sT>(rk!qcV=|(3)^-IN9>c%tCbG_F@UwQD(Ec5 zf)?@tEfnje0pmkfQO7l8KF$xevCaKm#rq_0OW4Y}%E8rj2-?sj| zk3mA7;8nq-&lAJOqT1aqQhlmy z(k#o)N%l_4$6H*H@(XLS9VHzdab%2YAh~oQqJ|baZ^PGc{T$RB{96^>TCUM*r0*2A z6c@V>3;V5HYojS(B?t)rq${~?!R4u%Y>myvJ@{46FQqE&7WuJoaANHiGvZm>5V9%U zwr?~mO`_u&HTt8dkNbcnCH0>$5|W6V+pGE0B@9hoyRqyLPMaA~cGG^7`-26`Vf-Ix z@l2Y^{4Sn4deDld*TPU<$uL|}_E%Jw`G*prFX(O3>XyN;&vps{d_vz~a@)Z5>9S_# z#T}rhkNt*@GiTWcj2jZ6XMMdu8;;XzX;6&zuP48Ywb3R0-@w@b+ew7@fXuy5DhU<%b z@pfF{gz^aldHU`CLL4KL@{6p)+s5l(!#N_YaiJXX!IYCq0`9%^ArLJ3$l9|Nl^)Ei zxat~KA0gKIXzek@pT#7KR9pcNx)+4TfL~;92k+XYoEobTQsAgkQ`>PGQgRvsN{1kP zO`qM_q--r{BO_y9%1xv;s?lqR`;gv3d-ogghng)_WDX!3c0Hz4GG;43Z`8pp`fa73 zw9KZ;w%>X*VY#Yk!zmMrcgMcKO044JBj*>Heq?M9r%`tpT~p-r>#MMHfob~2x8v94 zB$L?_O&TXr^w1`ZvtHSbq{Wz6R>~F{DWKZL&?Y*+6p-EfT_;=VJj=|g*3oEY1tsNk zvalZfrJR!($2TBdIpOy@yI)&^eTi2!CTHj!oqA;A1iF2c{7@?o1poHHWthTxtszro zeoOYfXoMM%r6}(B9T+Ak(S8}uv-Ca~pCSewhZsv`=I)a>-tn{Q$-m4Ef1X&- z%|kR-O8P!*9R(BCwIh?@o`T zn9AzMPUr|^v3m>7%d?x`!`MXLs~f(j*#tFC@`Wf7M!aq>c}T(+)%8y;M4#qoD0S6Z zlk4DaMOizk|K5YXOsQ{NK(NMv4t^sH5tg}~pnSioQD`Bek|$5?4Q^Ioh=2c{-1R`sHO_IlgXU~%Cv(Gu7q-={z*l7+Pt2pv zWB)UDKqGd$H$qqGxX9`zrgG?{&MtD9Y^=!9H1W;N$RVl2!Sz?oW}}ugw(;R_yF=!b zQMYPk305Uu=^9IGj+7m2&kNJxg|E-<$szrWnetJTdBfqOwhoHdDPJ1RVm-bKKFeCn zd0{pfrKq*6E_Fr8_f8*@Lc6*}&BM*0v%=69%h7~raR^LP49Fr`2D7KinhDTY4)Qo9 zbDHNk6joJIr*F()s#N-#$Yn~F(#L3UlRn%i7oxi0eW0M|L-bD2 zZ492G#gv*s_-f1pU*E2>oZowCDKcG4voD_dXO~UN;X`NN$0#_^aL>nD!xA`Yj|hhm zD5~c;-dEj3GHT@!X*xIQ^!xpNL*sZV%SD({-&==vu2*FUv;$T4-^t`|Ez1=`C*MK` zGBcD`ayl&dT6doF@fVf#5R`88Mt3Q$Z#F%XwdNKBV8kit)c1D;<$}4UKs4iAIY;*8 zY=cwqrb05i8Zb9E-M2~kYX=NMoNG|x@hZUH7eq}3bA!non*a{BI%@&2mseEG)T9iJ zevkjGT4kotB`6+rHG{k#olZm})yc;wSBH&J{qlL-=m(?hlE6ob7zAb`5aX zBaPDIjp@VVSugB8BlL!R*Ap6Rk|oIS`WpEW85xk$-ne z$!#EsjEtW1XT9{p6)0i+t0pAtd@5D|t?|Po(q}6%O(OVHXN8u@ACNw+fnKX_B&;eU z07>hWpksoq%@iKTYHa#vi{fmuJ6Xx|gLQ|jNBs>RaknIqI-K0CmQ%Wk6$XdwUM9@o~shB{ttaxe?ZXFlj%m;W04m3^XBZR;rwX)D78gBh< z#*s9(mN*9I_&BTqI+4F?Z&ejP%+?^ICSZtgX^+T1lb?v%<~D^riajVs;Fu!|jFHU` z$xva#pq_J$m{iL_|3RF1d?MI(x!FixhBqdHA>_ADFXG1_e}aykH08BWf#t)jy)<-D z{zb!>V(~Hs%JM9GcKpE>zm*<)!a$~q;-`b4V$V|sycuDqg9SIa_9+BY>gawPUui;? zlYW)&YvFdp#@_K;@5}A*q|9E6_xQDW+=>a#@!;qUvyTEf$yQ)H$s)+HuBq#{HciFS zTRr8i5?U$b4v~Uy((Gz#t_SvNQ^K65qib9w$|ikfLY#bEvgNh5dC${cHj@njLBSK$ z)Y^zE#gq$?l!PyIiv=nMbKZg2o6N_{ua=|Av!9WGY9)yghk=lHGPzoZYZqEEREz=lFHbjgY z4LVT!Bb15hpS`<-Q=XvkVM_$zhGh3lT;o&B;WXJ{qB*`u)*6uq0hh7IPa+#y=uP#8 zoF*Hi{>4edi?@C>Hx&|*{E2JoDm4MGwM|waHU$z^!4TP$sfJPY@n;3aJNe+>)(hH&5cF)((89G?NbfJ|ro=C_b-U7;HpG z2B!JtB)m(lIhGf1pF5PeDl)`L@Fg!tB6ffC=vK{Ss+=T8KJ3V`T^=O=)bq6K*z|nZ zJBCimtf9foqd>Pbzj?7Ckb;ep&!-SiY4%6d_Fw{^o-aaqSxS6E+`IXt!>!V8->!i{ zir8aii%j`)?;E?@M}j_>Tp|vd5ZQ`ge?PE17Hyqu=4`0j?ulXadPh22RniQf5MsC7 zYO6%H|B}}8pk}{pF{jP+NOojLRA(#Z=%+_dJX0{PC4JXIy+)y$!)ZSFBfWcZc_6(W zZ)+Lk+(Jql+Qpc|tUVzXkezdzY zm49wVA<%u{(tbajE^s)2#%+o7$#N{aiu`N($cuH=0_7kbx1-1|GyNWbJ{BQdq?}VZ zmMae00WcxC? zk5nt1l^T!h1H1VH`$+vcTDWNlY0gruS6g*MNv#n6M);`6z){N`-cwn6 zA#j6=8M6*^tQlf`)?_$NEW^?%RX(Lg+H45t$AY`K3hC%RHBPU{wNI|Ims2ra%Kb6> zY-3)Iv#pZ;-z#rbyJJKUT~k#52#hJJh8*<Q? z7OQ?3K-D7$&+G)d=Y)~O)Yj?SOP+J|=4YDs4GZ0EK4@F_6?L^H8uviD_l2+BPP&D7 z`c95>Kaqv|oRkJRZd}XU9ORK+5qr!!N`zyN{qEp$Tj3Qp3kHZS~Oo;C+gY1 zJYYKfd-7Cqq+1iGB@Jq1hKoQPRVg=#vo$=-IiAfQp#O%!C8Qv|Xl5@wXB%zVH^xI^ z#stfGiq&L}iuKjFZI)?_>4sx2$?N`*A#>;Ab6j&`*bQdfxZSM&6&vEw>o@y0pLI;1 zJvhO&uWTW0G)2?)6_-8w5SlE{+ISG8IxfOHxJXlUs`A$c7pqod3$jF&RYmovSc5)B zu!1Wga|21Mzy9VE3&OhhR;Hga^$J6;bAnY@`YM@}vueoAXkW`T`=i}?y61aOLN{SP zJ}-Vj6rJuzyd;GQBuYcx=7DYOhzcL7YOouuVs~;hU@|!M}Q(_FjFn0?1%A> zTM^;1@nlT#S(3?)dkF>?lb6cQxCi?3$>raZFkyC>uCcP?&H5@qM$F$H%#B2JUYP?9 zjqcL@g{fMO+iiYiYIDsI*I0=fjpf3P!Ym1==Qdoc&J+D6+l#zl>~`~g7SyL@<@O&d zUFxp=FDaAjC()_gO7 zG{jK#Du8tM0?o0=Lf8}UMj70A&tLFGu&wf0^OKLl$PRap^N^;E+I_|WuS|uQVP3A{HuCTamvegeR#NqC7u~Q+@Rm$S+jV+%)~T!r0#RF zLMbhwrqYAzY<>Gx&u^M_~I#CtS%?6o~mj$S7e?Q}fx@(xSRA zu7Oas2H?ZcbPBpK-!eV3oHx6_Jz1rBD-q;0ko#?2G3lgg@kOaV(#KW9<0#&#kThLm zt%;<4smYC!!@DKZ!}285L-QmcT{#jzb+qJ5h4Q5CF8d1bao}So#73Uhe*T)7a1l=V z1T6morp(~b6FJop^#dq$7p$Y{+G4Ilu5a73YJCs|?9dg)83M<(E;xLe9dCr@<(hQ( zhwMX0K>z4339_VGB)fujF#Z*TKSVbqqJTgF!_lUG6eq-fFczFs1siDhrl_!NEcZeT zqo9ip26RAVu8NZ-_|c*w_eRx^pgtDOD15^&qDWYhr1%%z!l0*fv1ez-%-QPk?9|5S z95k-FxMot8JUm%(C}*TN>T(en=?7far&l@t5#r$ug4X5IIH zINRt=_qV0+L)eokVg?eJ)^_XcOt?we`IqHy$Il#1hu)Ho=O$EJDr^5t=8%&V=-(rK zqBdne&!~y_-CXs`Xmo^QTYLJl@FTdwPm{`?1*exFb@YTCeo+m--;E$VX_-5MFFc)mI|>+6w=MA-Q2fG&G=0EnEc$}ylMH|n73Lp z^=G1Ocqj%Xs_kL6ET+nkt|KPBzr4hLqWzb!SRDbJ#urhkfbY2N9by~ zsK`*;vH@zESj8L}h3=iV;}F4AP-Lt%YLjSy{q^MfrvgIpJBk_{$-gvWoEuf9-N=6s z_*~8Tu64`nF@xLc-30xjsRm@8P$N95M7vHF$dezw=OWMX20|rfCD)GUYb+~4B<>YN z?XNt6+@%Rn`@Z^K16YBQh<2Wxjfh0&!KAjslnwxh_rU4T-Q$kiX8E1*?Uw?F8S4u( z)D&dACtNsbBT3<^)Q7RQAEASpBKm*B?(_xHU%meJ=3n`CDu~0ettyb zX>_lmChE_%E8SoQDsLuUMgi(A@8mXT7f!H|8AlFcyN-Xr{#?EP1zMaeaX*dzh1VB7 z3ZcG;gTFQuJi9_XYE=XzZo=mgbrIJYB*FcEDfJS!To}Dn#^4l!R#GyjjRvz?n)PO3 z6o-nYQ<$yXp5GSbO9ona`XpLJp5>MXZw^t%ZZTcDcCgGfr=q786OF_QG@-|n50V}4 zSlrhxDzh+^yBlhWj%mfaStpX;*NC&Xm$YU;7cT!S|LQ=siW z-e!py1+7@f-bqfuYx(`wa6Gdfe3dWq7rVsry5~2kUbTnG? zv*l9%DjLEnO}+QG4=bJzN!Vhfj-=oHX2CMVzE?A=o*0F(qNT#Y2}Ofv(KqC1DorG> z9P}0t+KUEes!1&!>+w-&`kdd@kTVNBLmq4PDR{GkHc{($G`m&Q^LkG7hvb@KMYTWr zhyyu--FlY@!ah~D5E)vgs z%Gz3MLAmS2Pxb2TMrJJ!(dN?X+8=ejMza>C7ZSez*yj%VQl!$NDa;`uiUs#Cf zH3UA9hE?*%I|}4>^Rx+^3pkZ{M&(6+!lFKA=UXrYjNpP_rY!Y}gK!QEB_NNkIPEv4 zHO&six|Q#I_9uSLi|gR%WLqc{-}JW+tNe-g`T$w;xqz-pq?0H}xKi=)gmD_18J+fP z4G0;xat}ZEH4)TSD~#p3vm0EJ%u|Bv;-kez9L#o}^qr{PyWHS4?lw9J&BZv)T^_)M z;;j~#c|dFfPnOCR-KddCgpnWg^I?9|Ao(}tEp4_^7()j4ZkQwwpu6+h{w>dHGS7wi zcIih38ly%;t@}^ECTZt_QI+CDjo~QO!xwR131iY8nuMbb+bv(+lymBJ9Z6z?Qd(sj ze!u%1vT&jA{tWp7+SBlI8QRmR-sFecZZK!jP7i4J;`XQW-M%d}jNl9ib-JkHErIR- z1Y2=5>|H&=THS8%Q!3~9P{OJwB|@P+%R0iUR2fLSg^W5QUJ#=0xW71x6hE?_Os`k0 z_8REQ?X9eth{RRjL?@zPDjlx84;$%636|rR+-JT5ChBtuH;AN?j|%hDMRM+@@W|)= z`Cs6%Bi*~b_cKN@&j^Q*&!%ogv)DcKw_sVl(||?#vzM+G@-tD%vnfbaN;c=$ zolwFq8{=G=*YR^aYV{s)o{@IK?axW;aev z?Xi@$>q4i|ChG}*ey`lp(gCvi<)ZjxsejD-tr3O3JnC9^Hz_on#lC_Rio!O<1GnESMMW}Kfcv>Fv?@gEN z-v_+@f(yM>efPORR(h@Zd1A~;efoFGBa+eB4UEjG&lf{ovnc_%mrHL#G}VCp<;Z;K zO?66sEt^1YzgVbQU%*as6l5yka^T{6xrJktu+;KTPI%H-8GJ_nmJ_yIICZ-I{z5V6 zz2c0lju*TcLPc1a?HuxY5bFjLhUNL-l)K`!S$lE(n|Uf{m}0T^*1Kh4$9SF0WCZ+S ze<~-MzFJl60#}D>=Hz5@pP~J0?Zt&}(h1f8%td^rHdJYZ@N|52Szgz(;OEMWO(B;- z|K+_(nJPhD=(vYP*n&^{w_0{bKS2`1(dfalevsjutZ0~dTrKh1tQDlc?#{XK@mSYm z{i3#R_3A!k>M_lZMR6%5dka=$aV-wKf9g`www#VaAaoPP9Djr&__(cLv3$nU`63w@ z+v6X?%v3ntUYuPUjBQ|7F1NLlLq-x=Zc{uk)7go8qTu76{I}Ld+wp0Nt@gNu3XL^9 zVd+9|pf=y)eevKd;ba&+YO8Vb@zNeA@R|D#w?xLw<+2EPC#J+r#07QV@vDyv!}CRVCG% z&_woG=cpv(#|Mba_Uzd0&`5x}zJ12X(`AT4FFJ(i7G!EU7bnMVKCh9`0-wNjnIe%; z?XW0vur6P(6bPPJb7n>G+)Ot5U^0+zrqfX+y*$rnB_f z^+u*YKh;5O&GpC6m1T7*UkelGls|Ozfm}np*0b}WN|teQS}w5*jN)_rmce+WGM*I0 zg6VX#iFl}Qq1GLzn0)M#q}|>15PUw%?R8`Us~L!Cv`;BGP%x}=W9Wa@3>Kxps@+q6H#Ij>gm@%}rZ;n;JCb-1p%_NiuL z{zsLkr(rhj&e@gFP$<&n3Xl7hipyz0onrgJtYRn0IJd(pI>s3J zOCEMlXCGoRa@Cr(RA~AX4SEY+hy7TIn9lWHG(0S9CLTD9fPAaPP8MGMW0zRZEJ&mj z(faKY`}BLGn#7kYsPckx`S4n~pf`kKqJuCd^uR&JIF3n z`KuIhMG0xv)vyMvEbV>dlKk!`ayQFjQ1=CF!;e_G9epegbwa%Fxg5*YR5C`!Z+^E+!}N98hpcTODMe zHQs|xoO-{meL2vfx>U1>q+y(Q3#^uCXEGYGhr8E1)>1vCQ)J=IKj>jSt|ABZwj-uP z)Z%3cM(DIn0ZMM7+#k;sv%)KBJ zjEf2kD0T?nm$Zpuqq)W8y(=BX?t0cf<%tn{Effgb)+)5u%;I}M_YS`lrhn4_Cmhq` zis%BE^B|C%6^kpwznc&Ahe?}pym38QX*@^Tfn-S1j_2WcUj&VnMX^M`i9-JATto81 zJxxPPJJ-UdP$9DcCTJd2K@45>K(*xORV`91{G{MWCILNI0Q*ngKwnM|H8P`oM(yL8 zdj}zcH30;2(|ml?sK6L$bGBgx0_;QfpK?P6ev0?Es{(3Z%dt9H? zsXW-B?q}I1!2~73K916^u6Gay4;GIEeC2!tmA%Xfb>Enq+AndnZG?o_adWf0pI$`2 zA%fRohF<3i(|*)Zv+6w#EYE@sWb-OwZ~o~s&N0%zJIcSGuzvQJmDDjoSZ5i&#$;jz zes>gxGY+rQxD%ssWoOw`aOAo~QQJe*X32AXO}6$JRzIWMZJI-1u6uMRv+8FP0W*Ev zd*4|LIiz18Gam=f(Z?yP2^4myJJ20L| zHkGUN-cK~bC|Z~hiP-HA4Y5)9R_wVV>;7s@bM@sI!fppaOYW~6xeV2dts$#?1#r0O z#;ynQ7^{NeZ<{`jDe6~X2%@Wj9Kf~@MEySxyyNqT$k}w@1}LxC4>9V&p~K&^O&=&u zbsc!!{qAy8wl_WS7}06Vvu)`D58+cFcs6rJJ?{X~?KnGrAS*O>lf(e)6KNN{AT!C2 zJ0p7(?{dey0|#lK05bt$W)_IBJO9ayHdTlQo#h`?gcD_O*X0GBO_!X_TpSM8 zOtCtw@#Z3$><+IQ78*5a$K{+Z|5>>+@y>2vcsU+5EaJ`~ujV))!*^W_-rDURH0qnA zhI0`^ICUb04}biJsQLHdhz)vgfS!fG3;Z6H#eZUIzYyNae9i}r=C_@dkXwG5v_HC9 zM*&4HW#O2*yW4ymm>~yXhV$>DORC`bLW)K15!6q|&jR00?ub)3d!GH0MW*Q2704tN z3s0~6GJE+eRQS8L^sG|SeK#taK?pzpS>w!{vL$H}1P6AR=YDsQWFe3UrJK!+ zDVLTZfvzGmQFnTTH|PhDJf~~?v28nA`X&;KBC^1NZ5!r>s{^%`i8!eY--1P@9kNLC z#rgu2;Py7h4d1l9_9)b}T5Y7SMGLe45Ge`B6ne-bSgY&0i!_Djb5MTG;dA{~Q{2V9LRdyUtGn7VZHsu5%uro1lehTz#!i}Wz*0@KLQ-hYw>Odp$u$V6zHl7dQWR97_#-IB zBiJg{M=DLTiIX4MZNg=lkR8OF2dw#yxLBXi!7=H}(ERNu+4a>ttE&uLTZB7i&nl8M zCzQ7|aw*)Un8e&iEgtqRu#X(BjdJ`#kDnyT2}deJBS15%p3pl2Lg9nyNd5%B#q&(m zt)dk^qs|Q)%5DNIMkcONj36LvE+AIm@0b0(I=tAC(G5Gi1Ow>ye8-Yr>EF1cl8FICFc(73Yy5pQpoaayZD}6oKWc6z_TUE7sxx&@%B5b zA_kM;jC5m>0KOl@^;ajhddgNO^b8M7y2IG-xj1Yr^*xP7E?rhy$D_7HqxtLCR6X(( zgxoI)bFhN<1mep|d9sxI)4BD&O8H%*F1PDlQK_cWIb1ONc=7^N`>&~j>!hteb)bbY z(Osbh3EbK9#j53O{ZwRO!M0@`;C)54;iPI4!_k9U?mj-#-{Kj+V|M(*67zTom?FU; zuNmm7cVHj-Bc9)ULUZQ5T|DpPzOfHp&+bn%Xi6Ry!5b3czx0ZM(>}rHrS@(%JQ#uG zk~lyVILKJu@@~1#@>hK;2Xx%fI|%Ow`P&G*7SuHbSUxmbaeGbq;HCT3d3J+>M`75# zBA@#U;ktu)@V$rpZT;hKU4yr8WcG0T@qRDKrBnF+ta3yl45x48#6|bM4y^Q1&ZxVn zP@^bU8maZ$%g)a&T;jerEB~1vCS-}wxRg|sUwpp)Xc8Q>op75MPcNY)sfIjunKWq^ z9CYZq|8<#h&hUt%-|0=T$}s)k%^xPgUNPHp=4K8yyZh5Jg8@1O_g#}qb$o6Zl}%zF zjHbzy2tiY0_0qjFUipDh;o_VD9ag^Ei>a)m%?NXbT$pZ+#%Ku>-?eR*tJjJ*T|0j+ zV^+}CJ-*D^KDSZwVmP7d>=_@JHjZ0+#B*H256@m_O;a=(;4ebU9ep&(coz2v;#7zD+~KHbekP5 z8-Wn%Eg@b3 zzS1N|%LuW<@NMAP^CxBUwJ%}$(1f}TIqA|(Q~_ywilqVi$8)Z_Z>UI1A*aZ+2XE{6 zeIuxXDLOmXrcJGoraJaM)-b``pU&xQ*gizg)z0uu+Hx721C~(7cqVY?oTEqv* zG1d(r@+KK}#}m}@MpHj{CF5?>l3CJ*SzFO%cyg^G&5r%ijozY<9ya%I9qJSf$~ir> z)&f1;9@lT1RUZ{y+ObIOgeGmprH>DtdX2@Ew?7OH0l#3uOAL{x`IbBO<6F@7Bz9@; zqGg!jPz}UrGjCL}N{p>gXHygL2*=Z_fiO;vxgN44`86ZtiUfC`EIMiOagRXf0%{1E^Xye;CJn9bXCUG}Uje1Y&gu0k)Bv z@*^Ly*3M8I?IK>3FGLkLl^Xxa_zK3r@rA23sjNtVzJIt< z$q}G`BoztQnl}m-?ev2*=Bg$`LjXec(+-IoGqIdbUHJrc9AqtpUZX0<$a0~AQhloy zhn(-7b?bwVWdgm*r(|v`>VQ#QT8je|y}+?lAz*9D2<9}y0tv!mxA$K_g^}kTsh0QX zNCiB#@3Aqx@0If9hB4$EqIc>cW+G6DXfFL{9-~cIRYr%Z=ImR3>t+XWvMG={k9^D1 zg>Q2_Vxl0)2P0r9+Fls07;^=Lblb}6^bHRC0bvl!Ml4VJ zH;x)I`%_h>(|L4mEH>6qUdN+E!?D!Gn|+8EyjJ*HjLQ8J&;=g{@FRn&m!#R%D6pFu zm-w9r_NJI{+pU3bK2N}}!m{ivjOBWFJgOL+L>Ro#Kkq80j`IH$?;<;R! zJYqn$sK%gL^1XdTKV*zx3NWT@z;cOW%J&QfwXHc#(7haZXEFq<;AI@z3 zsxp`;S!acZ=+AmKC?R(^UIKlb|4Kr@=~oYiRfT8kJy)DjDI!#>K2VqAUT;~|5d~3c z?XQ!i7Zb<DOHF)*fb*ohxFTd)E>4ZmvF;Xmj?=*NJ{U|OeDmwYY*O&~zt%j(hLXkqdslT)t)VSPZ) zo3F?2=yDunt@~73e+)>4H3=aOE$ZG)PN&R(E2G*$_{?Rg<%Pv+OJfVr9I05U$>oM) zK39T!g!m1R+T)#k`69S-{K) zcg3TD5kNw94ki)j!1Oe__Z1MnQzb$1bly+y7;jvvSxXIg4)KrPVSHxm&GbUho@+rq z@B(5QC%3uF+wP05N58|m0x)td7ORkWjnVn_bbn5o>GJ>XrsK^g^f>P&umxgzFo^$n z01*ar^#`a4gzScq0MsyCV>*2#^=4k%E-XxxIrvNX!rSl!k}cEggV`>oX9$hi)G3I) zUTdFO|Gr2)yd9kPObcDnec#AsAx9`auA>TAMEW>HO$Qcqi=sAy31Bkr*AbXg(1k7x z*aV8ZX~x8*NChxL9b=++em+<-btwACiNJ0DntUd%JZY>vq$z1M?x_$KEciSo98x~-F&KaA17UQ!U z4E(3{RdO z#|4(W$5|(8K-f6!cWRWW_Zbk}ZFLIoC-_1dpERa08Kh^?eM4NX<{C$ z)RiCISopD>= zjg-wlHEK2!3PRhT5x32PEBS8(6evQGy;)q*^Je4m_;L?YioPK6JO>Y2W5^kuosWO9 zrC*nO)g8>s^DIiwqEZxW{nF!#MCThI+|JW(w7vPT4^$r<;ab92wWVfqWz?#zjv6pY z`LCo8>JE$lPDV5X2-O9NWrK9{cb@gftJQMoZ$@a3$s5%0nKc;%oKDZ@QtU7!B1mh8 zvx-y-nZ8)Jf9AGcdRKyTYh4vTmKyhDduw92Q_?uK8fq*Gd1CF1=b0(}P&@kK&R?p1 zh^$&p`j(PGtt@ky~Q{W9ZeTXB*OcxdKUzGu=}HVRS=WHkKf zw+WPv+NANpM0lSRkkyeypes9Wyp<4TEJTJYG7@__nJuxbpf4U`uoMLYT&e74GjtgC z8rfs^&R?DM0HLvv`K_nwlTDq32zt6gwm2i_m6sUm^wR6mOO+!26yCZaX<^D3&Z(j$ zfs-XBv8fao5<$irtLTwktd0+V!pI;)bbs`J_w~nbhY#xyVUy?eQPUrhy8D?M!nFm0 zun8QsUviuMO20T4)v+E@ZtW=$qIqhhyUjG$FLCxaX#ti-A zLqMHg7*0wDUx+X=U|ov3zdm#`k5jh0*a9EpMAW@<)5w#hcS14Mhf_5^HDYS#VYUDX zQ24R+rqkj;4Mi(mE3f(3Gn_mQ6X;I?3BMrhn3HkGx|EJe+*Gokj$cK$HWf0Yn;*2K zA5@*RZW71a+DXzYs4M)@KVpGUTkV>7Yb^La}N&7k4B6 z8zj#8eWGK|VVWba;`V59`r<9ACr~DEv}26m!aQfp;h^K=_Cr{G6RToAmlg)e#byl; zAEU)?TZl^2*<2j>@IHjzQPzrq0{nl|nlc%rri@N=|u5YU1o2Y>86%ZS+ zR9_M>65dV9Uz0#=ZSmdnS@du)ZiZNu4ORjoaQQHPKz8S0*BtBSL-+%)SiCx^i?Z6i z1sP+gv6kvqt1byG@gr)gFj0JnU!B?y8Fe*Miu$Cbx>l-*;0DHz&+wKjt>Cg%X?&t zqCR_@_)>uOcF7i<)8XKVBv2RBI$mj1`dc#yAFt$2Q?HlV5O<+{l&s?wJqBua`Zmf$RM#aOySW{?)E&Izdn*sHyUW&z8d91? zOuF~a;6Asn;Wpj>_{T$xI#WD_Eqil4^+ZX9bIHx|z%HJkz~j5z@UN^-D#A4EN0XN? zc02vE9LbQE4zvXdx;u;diJxJKpxp@+3r}<>wCQ&Lf8669x;4PQFWIagXxl}A0In-B zKPM-^m97VHg}>&*yX*Nq^5{>CH2AszvT|%+fCGZD_Wjua;+3%7xE45x|;LBlR9tkrZf(_V!hv4tw_=;)QJKz+q!(R#h;p9^Tz|t(Mz}!Rm zE?Y{*VJw@o%Ar3hB@~)-Su*{%DBaLH>aW?`^Wm7stx}0^dP)>`Jaz)OFTk9R+EX1U z)MPM;P;K+Gd-&6z#niVJEqyNpQ&bM@UfSquHixHW*uTywJeef5*_n?h`&zcJ5LS3l zGP)ap;?eqW(oynz?}!8*GKK(^`^e6N^yIfj-|_rmKR}j^iG~+X2PVI(xFRh@tVrgm zEOEScS4nRv>GHI2Hj8=#%_{X!(CS8)y{?N3#yR$f_q{ZwI2b_aJ}WRU^!aX{W{4~A zLXD_(6lu!-Wp+Bd%(Kwo7nxviw1UI)Eh31QL9z%SUuy}jWovmJ`t#}=I;-K)Om zbEBT+3C1`mo6A9A*~MOV!~iO}Kgtfm#ldW`45aOG!yyGAf~xOBBN-{wP-XoN0CBFJ zzht6^ckbw~$d7)j6_#zG<*hfG&6g&C_;C>M0getw4A}y)-0Bl!1wxJaVDCd9=v!T9 z*dW5;^{O~kkX1uw`t#G%Hi4cxzA|J&0ryX-af1<)!z{N|Ah7{xRF_0|AlAt1nuL<{ zhkp-U!Su)_G`pP_wo^$jr?*~JfiMVIaLe|B36P%luO|2T+5k*76%obISrurqcaL3$ z?xa{V(V0+jpjf<>Z8&KToz$Tl1&@s(_UsD4mS901A1d?ofW1-51~Y zNFAjgC70pQlX3~P6TgS}529a{4|5O*1M2^?0ObfV`J zCYM>jKHPWDPSwEjhT+-V2WH(CI(5V4!?{upVh`EtRTxlbuy?Dj{EJR%8a)Hw<_=PT(iz1$;EtSOxL0X$$1xwMT5X6LXvj!$87=E zmRo~8rkIB+kz?S%`qz38sm{?6ds)BwNKxrHemx8%4j3XJ4BMeL zmj*4(L>11DR2deMjWc@OUsd{{0ynbNrEX78B7ZS9jL<*xdzU|&BL$+~h^xa9?>nZv zZ9gBM@P*BaP7}%+ilKXt7oufd< z(?Ar}O=GOVByaMl!ql)xPsd_hFsQSBZE^3c{I(y7`auej+r8BWB&n(c5)uC@VzG7@ zi@-0EhSwguS6B)lqVAH{6Gqe|Q%?mM2)C&?7Bl4Ci8F6t=7P00Mo2~?K73R=KnGui zJ9J&bk-rhicB~DPY(HFPPtfH;y>>K(+wB0zbWGv2T3Ikxasm2742v~ndVV3sW9}uj z!(LRPp@Ybt7GD58asiKBeU2lEl{aDbf0`VQh^SY^FUd(W?hQI*f-*%H{r5Gkcjb*g zu1WkPcm@cE=kp#FHn4bzf5!rogYj7E{@_0`Djh}?%!CDwmT&f-Mq+Ff9_9AW)=tFR zpOm~Vs2!?h;+ZOmvwQ88Qc=r#jtJu~*!agPe+pXn+?;0YGN-!%DH-}E=m*$)2OP?T z3A{(nW4$#$bkYYoful;oE83ZzUVa^rvbH#kaCZ0Uop(Ix!1es3_;)l|fiN=;7|EmJfN z15S+xUU}hP+L!-@ROl*-zA*eiX(I(AqlT-kkY9Qa6Z-eTlsuGa))u9*P~>|Nb6eCL zGX6^8ikG$ay*UM~mF}D5e+j=Eh^DC)azy5{Hf!|#N&Y_f`f%QS_DOwGGKD*B``kEr z@*0;a(2Za7{NY9INufe^N)Aw_>1enD$D_~>32U9 z;l}@xRexf22uejnI8Ej<-$+IDegFoN&64sEo1d@D{NbOR_#%dXAs-tQMAL*?c=qE> z{jH)TV^OQO(y^x4O#pkM8SOZ$d7^Zrh_ZR@=Ed~&11g=a9HC<~#_08OX&F47J7RXGh zOKE?@q&{%+l3a(W-wBwmq1Gl88cj#=<7cV6e`xbs(u8)xIfceS*&KF+k`tI`NcvMb zQjX}4K+xRIo$-|iFvPAhNz1J28(W4~3+Nl`h& z0$Yc^-J`mk=Xy^=a8Cr}M#gdq3sbZ+b=YJO&>$mR`XHme54O%rzsyVEQfPnV9!1h| zzyA z$a?}A;l{(pPA=SWehaYw(8m8#cmL3Lz2gY|QdQzLGb#-~8u+llW>t!G7!O+0x1xxqm`9o(u<$9ojpEwW* zgzh&9<?kfoC`Z{8)E)nn7~?oG9Exc= zIQs6YuC9QQw}@pwl>_hH4+l<(w1>@Zw*&#BirD1B`c4)m^)~|dY%|9%q0BF=?#=%4I?q7cu1>kIyXpxHg&ln+o z5!go4s(l3<-DT~OaS`D4kZ>M>VhN#fZBko*sYY9)W9B1^lR&KOhtLY8pc-Z3|ETGx z?NO%kWEf3HkJ2Ae^@W=_lvf0eZ#QL=I5cn%+2>0kFQq@MwzRmERmr$vlk*W-FJm-j ztmz$rqA5jD7F*5hQ#l1B{|Clu$l_S*_X<$~7L3suZO=5wa(0%R{fzd0K@rvNAj0n- z&xmh?P{Msa_TA)5-H(CXK3v?5YLJ z=uHa!cb->#?7yhU^pW*t>y0TLUIQ4=W@Q0&3yVPyMWr*;?TrF_U@4@sB>bEoUW9XBar}cyL!wc?#L^i)r;-_?3DCG6s z_nt&Oo04OUMsf$;&K6dWyvyupnvH<&3Wbcp2vEP}P3-*yyGl_k`*#uRJEuT!r9Xpns=O5YGEAb{K4pk{D%n^J4=sC$8}=We~!5J@GV8Y;xIwSjQJfXgH+7 z{OY(Q=&V69co^&XPre1JSvCeg!esJ{+xNc#NB#|$g!+F zFS;lNExVE5W|xzSNU%WBQ`Z%OYF=s13;#wg1RX5dTuZqhlUJ=lYtGBv!%WrBsT`M| zfCZZi#KPTtanmkAT&cu0&wND`*^hrI9ars`TKmz4k_?|YcHt_FQMgBj*fHH{>z`8` zU?8pV>^7D%jlW67ad0Wi7b3WeOaGH2R#|ar6Sc-oU<+DGa?|3D2_>8wKJ*J3iZ5Lr z#Voo65$(6dJ4vql-Wgpru*|kH>iiQn1H{ePpuGFajkM|W{B9CC*zY;w(%Bm@!_%|3 zqI-&Je1ZoDgpl8y0}ytbwY+^j08gIGm^y0y&qD0(eIft90{A)^-IovpAWa!&m{J{@QDja%pO!94~ z!`Vr>c)=tRkfSy_0Rx3B4Wyd(Vr(6{%WqVc82l95)RdF-&P#;bYKi1?T-$4&-%p7@ zYsX<$={Ph!k2!J)tAWf`#@H5%O`s}8s;MAvv< zPH%gm?2nt^AE+|khUZ_E0710r-O|%pOy$L84w$CVMQXCSnNPD?+f>ea`6lf`_IA}V zMlOO-q49Ap<;cV1YLKV%-TYtX^zYT+Pq@}wOWEti+2PS*6OjK5%yLHUAU;EH%Gjq| zQfwKg#E{3Of>CiEk-h<~%4m8X(!co>9 zkSUaOlxjcjmn^+ga^uedv@?!p6w!!x9`CxzY1%ekK??q73kJR(M(F&s{}n$HxhV*n z*zzVP*kkdP9(y86+g&>1!XqZ{s;R`H-*(L+t-<)J$JDs@W9=b#;^cakV!PF`d=aG! zz>g0gU4*67NuMHG4<$gJzWWGI|A})IzK!J*XV29Uee%%|P5)qy|E9NCHu%BiVv%g> zt})?g59E?L#$|cWw45N2^2ZAC4p^!dU-6kV8C)*6;>RL{-c|uf{$vkX_uZj2$EW{G zf)#B{AqwlrcH?!6e-%WENZk21 zzUt(@?Q2#Gt*|5IcUQOF9l|a3xLqw@Qdk50Y$;g7u8XESHqVnjBtwi5;R58C3Bb8> zU<9-)*;tjEGcrp5z4j_MVGgq_(j{LP zjXeNwZuTnzOY%21J=br?uh!Uv2%5-;Ve(ymF9N;nDYrLchRIX7pKAQ_%(l(40iD5z z`?K@Y)8eJIUt)a!%SAOD5e}Grz1AZI)b}YZZ7?J6^*e9d@sF5qxXWf@_*BbvOt_|# z=#Oo3WsQ%y9zC+b<8<#ocZUr8jPWr^*)E=QzG#GxfLP>D_<}QSJ8xs?{r-%^INV5U zjV3?63qW5gJT@8I+w_xMe$ZN)7HoU;^et+d`mY|39q@}~^JMwKDb6UsKrTmbW}eyd z8pwG7*oiw04kGoXMOyX0Sj>KPAwnhIC~p0m8)k8inD(H+XM$|3(so}t&K(a_^M1|$UUEWuT(P9 zvJT@mn=!SQFk=B3L%Q<@8X-W7jimBjPNB%L(t$Lr?+&RHRsb}lG=}pQl&mKf%<}!c=NFoJ-`r5>(ogZF%p zd9munfhJ-N{y>66isIwaknW?tGN70-5D$rwS+X~!Y6RKuRTz%P&xSIS*HWDz*tE*8 zysmuZwjbRq)C~OXtAi)>-G~Udg?}q=*^%wU$7&1jB%~%80S~%JmU2?uTfftw<=QG1 z>^{#EZs%qaFIobQ9n2N?%h70%m#67miN;9C$Ej!tl^*QJ8Rm2c1;McZ~+ezqDxhM*3XE;S7nWs^O-DHRk;EBR=x@}B) zf4!*{48PS^Zna422;WE;#I!;?$56}TDeD^KzClj3aVzWba(3GfiRrA3dKS<9Y=iwrCZS~1 zy8u32masI3t^!lQG+{Jfrc-4NY5T52zyyHd8w&uxK%M4?iZirOY0#P=?g^n|_iYA} z0v5mNM$_l=$ml8N@0=$o5l$^1LeDo9o-&Hs+Ql*q2>if`>k$c>ot{~T^=V--+?KCB zuDe516NA675gvn^9ZQAYQ1a`v$;rghQ5LI}*WF>~Ch*xA55~|&lxR1yha^5=;o#IK zpx2&md25SF?8PzbXhKtt|1|UPbM=GZm~>CwepV;qI)FYM7WFzqf3rNh9FV7<<@(J2ggcaVO!Pu{;9t|!Svr3+2U<4f?5DFp{liH@*cJBIq z7d`Nsw5s(fXF)z24G6^$klxaUUi$rTF3J~Y{(DU-ClW!^r)2SqV% z%T*@XNi|?g$;TwV2prL>kaWEz&pDFZUNnG@q8_gpt33ia4gF|6pQRJa6?(S*M!*V> zdF2l!o8$?4T}?_%Ws0IAN{Ry6vv`J{KcGN&?;@_H2%Y`Kmed^(By2R2$W}M%x&!DA zHOb5i{+5dU&654wW^D_+6_#`9=*W0~h@`t;NMXR*A8)iUewX?MvV8K!3w9;D;kj zC*X8)1=Xa)S)pPfj&)8##970NBG`bwmoUZFWO%lkfZ5D_)Zq{}? zuGM|wNjW9ZJv)!~%|+>CVG!Ca!^_7!t1;Zod86oOR1J>(j>7PMFV|#XjJtRKxQyY3E?h$1=w}B0Etcg zu+jo6rrwM5=n=X5RCAO}!}YEJ{4@5}wA#&uk5uBJtZpI}RSxc+K;=1`mAvsADq%or zWrgSgNSlNl!%6sDB5CY5WdV-l@2@x@NK|+@pP-=e-0}8W$UX?FSct z!e298r`?|0D{lCw*XB}(77uRw)=R9iLe*3mtqqqPm$X^mjlmN(X4M;POuQ08E!q_p9 zgzV_9oTwNZzqwWpS{LJPINB8MT}dPPZ1o-^R}A*lmeWu=gOxPKvP5<8{zI(EBnF`zr^>b)cbzp#ML4bAXM zSCC?l6bxP|)=jne@W}ot`uXSQm%$cZNBGR-iq9ifC!GX8bR?rJt9NQu!fvN_@~ zn?Wq*>(oO96gK~J1HqrfnRC1U%ylq8W3PTM;$enb?09&4C_Vi~I_g%2Q6(ytK3Ziv zfp_G^kC)%WqGOFM#VX7hWWGMLzCV*n&g%RfKpU+wVkEsLvhTLHVYzoMe7?}_T+8OD zSG>;+&>Sh;j%-86xBU(;kQfkj$WtXqN!VNtLz-(F5lUJ?ykpbV^?q{%2o`5Gf*Bgm zq|P)Or=t<{#%jgX($i)!EHm&ar~%*tTr}Q$wg^){EorX3jUOx+CFM4)$pb@OTdc{! zJE&zSUo6?w-?Xo%il?^K)A3hX^6OO~y zMQWuqcTrIicunDo;uX`4EL7#b=ka~C3;I$R;Umw;Fw{6N>M)8&G^Fj)qm1p|fxlGA zTX?{xnfi6l6?^GYE5y^9sAW@~dg6_()iV=3Gd#~g`tL0)CUz5kJGktbIo7q;W&`?| zsY+|rcLKV%Q@h%Z+!N0~;5%gjxbjHcGb^4vU^SnAR++3-@lxw6dW4o`l?cWoC>AiL zo~S zr5pm>UB1wU>T|9kNH@@PcYs*mli<)HhUV&}84323eFs5cy(j|^3R!8fc=suG{19WI zd}EC*NJa+tlhT1GFj`DqGn{9E6gz=exWI#bxe5KHo*y6fyp*3T;8S#|x^C-2^t_jD zkq(UbRp{@)nav@j=j6j3hae!cw+(7$}SKxr@w zJi5Z=yH9-pbyebj(hn9Ux+6TuhH6bH51~=bVXxCeAh7h8`9hvf!QU- zrawcZi%V%x+0=E1@Xv;0y?2k%I8a%r`&Dmnp_i-Zc4J~@o3Q{bi;m{YA?7j6;?>q^HGXjo(5em>|rxwr15&K=#C;Ilu@ z@l!in&f<8+vRLxt`QkmuaXFZwM%`Uw2fL{4jMmpH1+)r$bSM2hPf`xq$scbXCv=&J z!(6HVGYn==Tf*JrrmL=rr#U?^?K}V`cek?KaUS6;O2J&i@=i2`b0dT^d>Q2lN?MBZ z`t1k6wp4ggP1UeL;WB3*kl!;pI;um>KbW`Zwvmdb#3dFvpT})hIwX8;RqcEWT#NgL z!_=+@TwN2EZ*G1m|C|d)0o4_G_hk$-a}a=}Of_49Re0Z*oscL6k`8msW=Qgi=iUN* zsC={wU#kU_L)LBr5uhKW`HruZM(-it##ZT&gfyZf&dMy!En9meN6{*dA01;Lq; z#;?b3fU8YUw)(a@V2jtHtpZvfC#8T>g|ZO4<3=KhcE*z5{~hv&prz!$9pOS}@4##* zoeyL=+WMv&fL&6EnyDwoX;fLD#lkcTMQz?6{_Zurs#=hnk4#~D_tfw&%r^=H^92^Q z(ccGmli+2XC)}jI&dNcvS~2$|83W&!)1c1%bUPd9d^E^L_;i}U#jm`PieoWXm0|L{ z`R=OEj@{KWv%t8;wBF=6>g?<9 z^lc0s5TF5z_yB9Q)y>ghk=L)s|Jm#wHoS)s39cbe2ANnXGH{UOuiBGwn}&wfb9Xfk z9q6^!2P(3BJO~01-W;odSmu`H@kS39@kniroN2^h2#0oEEw>PZ5g+aTdpUY@=DNif zIo@=#6$ofogqPEr#6>O;CtQ?nVPP?d@O+c58)5%CfHFq7bS*8=`frN0nYMQdXbeDv zoiiw4jooEGMLQHQq3J+JGG0w%D;DAB*RxkgH0jKciwnY?ZZtpg*2wpaVD?W0EBrBB z5<=GgbQZEn?tc`HkYbrgq_73oHF6|PtuE@+`G+P%fG*^-!xyDbsB3X;=j3!N3As6+ zNdgq>UDMp1@kpUFhoTkA+N&Ls5I5XjQ@ZY7LX20WF-|*h!#4ElTLvq-QoZSr4&q(g z=0d00u;`>hEk~+uy$W;tvh7$`;AJeV|MV%&lJ-Zs#~v(zRAx{&jOyN8MxgA;YlfId zkIZRdp9(t6q|}K=|L;4!t)5j=cl)SJ^AcT}KDdoGYFsf!7Pvd|T?RfTR z1K(8+g{y42a4DsyDr~vT%-k``4oYw@y)>rP52A2l`(B=|PS`)q z4@azW{!qw0KJZFA8qLC!C1xBndXwCMX;97G9kMU}zbQ|%}vi=(-Dpj2V zULQ0G9V)r(1nKlgZ;%e0bae44!m*5=u`K0v)j<WTeX!(lTi<45nxN7E`BEDlO=cvUDP7GK&h#2s1{rCO*i9@OI>wW4WHpjko8UZI%CO=F^=^Y_E4vQ}`$48*GK}t{t^a(dIrFe&n)g%I6dhk&ciVAYS zz=>MYgXZ}OmcjLIZi2!gV_(`%{=K~$^Y)G{7U+@YDnveoezF?PKPe4wp z`Osg?>|HK;0U0ZhrYm>xZXM){zOc<|W;!IB^0`3u z8sz9z3`OLd*)t#~Bt1TZ6%pYQpO|VX_7T@v0U^} zclw`*15Ya%(kDaJxcUO-5p2ENUuWKHtj9Sxw^5Nea7m;I45&rs3~DN9y|sUa+1ZZ$ z%>+NPibXQ|Cw1eh#aEzWFjn0e#bNp!`~oZ!fbgp-0|Oel<9n5v3}~LAD+$H z)?4ybs5293vp1gnfZg95>sAa->Uj)cnlYN8eWpm28KZufQoy7dM{^N52y(ML8sB_= zF_T}H{1z8dN!?JJbTRk!tY$(1@w_qja$Z3Pv4@C@@mP-XkOxe;Qa{eVX~$p9iHC~t z55kvDMOuw7?4gy?D|G!6LUnZ$j($gvcVq;a4HEQ5y3=fR3^5m-QjFu9+?aZurLO;^nL}Vm7d3f zhfQA`fSZD^SMH$UXO%m@4R{#i9vcnlIvR{DdBldZ z)z|(L3X{5sc?yNNzlrr1m!{eF7h#kQ+yRc2uDw5HNhVCWRk((k=rUh@>1h8I`yrA` zq7lSrLh&6%6+A*y7?Pi=;!}d8dmI7wAoI1=_e#LqLHkX!LtF{@42g|^f)XRh`4&!n zsjd3U)=$tPRb8C3XPfz+r0RU&v|k=ue`qkt6olu#W}0FUWvQH`0>>m`0Ap2hmcteI!veQ{_8Mp|a7 zJNi;wnm%h`KwHxltaPEiYYKd_IEfTKoqKFL_az58v-`KZ_SId~nCtRU&rT*+T0;rp zzU)izfA0=YaUhw^*T-#xvvp7b$Q_zs8zKJrA(eGYXmEm8a%tw-lI)E5rV{jqku(eW zDoObHnJ>OX7xxXUu1LzeK*i)_^lgA#0{o@#=<;YwdAMv$tQDEu}Yhf)*W#KIu-UR za*TT07e7D$cKW8LaWxz&B=GTf?eQCBVdzL~27`HHvh$iuQxZzR3Oemg%1H zru>CMd;OMZ{ipeCJg;(~+O@H9p0sd4^Klb`d2MZX0^ajWz3*ALkmVjc0nj-{JDc96 zLA7cYc{FFrSM%kzbY;JBnaG%_ly*Z+2K*{5lVIsy78>qRX_ZE4xnjJb7p|To1v?j9 zt1BzPld6M{1$#~~_5SnU1J_*MzbJ;nSxe%E8X!(jXlf;@EbDk!_0MH6asd7;lF*|IGqm z|4j0H2#r4+?Zb9dx8G)V8W$SDL4u932^GvKgkBs7D%i=FmvRAAozst(M^wC){&x?! zsjnya_M9+)5?+!8w>wb|qve1vqS~4(K92mZo`1)2Th!Qg)9BquDzL-W&0Mcdns7z6 zR^S=vI8?^@>UUx(uPC`%(HxZR_IQXVI~5m86LHS9p8dUjPV4MRCt?1c0`=|6a`;B= z+$Nana5_0fkr%2j&4h>!>z))7X5Z;>4tSW-{~3MTsux z{;i8|mBHl;Wa!MxE(^j)qU*U=9lE3ve-u5Slrxq?W$VA*;`VE+F7SONW-oO|l=>}l zZNF4*_yTJX6FMIFVY^Ed)2CZM=V{CX-ID24&{&DW8*M0A`TO|t-%}mx8cGS&m-t4K zX(vbBy3fItz%v-gc=3l|Bv$r@3CisCNolQqhHV)7DswF-0P z$4GGUGGeX%e(4XMQ@+Av+HSMHd^uuQ!14SRQlHo6@4}0E8@=o5Ey!o@wb&jJQrTmH zScxi2*)isWZXq8FjuQRvD2uw`7kijasnxVRl<395<`uYn!Pi=u{sdp#;62*+v_LM4 z20eps?%U`oaqr_Ta|SOwk7!$}oie(s_lJyDyPB-Ny!!9;8@Pn)3$>`5(gmEkbX&Ne zZJQ0*-KTvQIo_$Y2}&dpw`p!)OQx6}&PpFtNFjZ=Vh{Y9wL#2|+SaZ>xdm@oY6%^z z`D%7|Vr?r=(aTre%U}CHN-AFWVdYe*ani2Zjg-yVd8dJ?BE*|TXQRJ{gDXz+|NHYq;GmaK=W9`q zuobrTd5Br!vu+AX=apmjje5Z@?24*>8@ggOds|0`{1sM%yH4GxF0Yk>Z{mE5c44_n z-t5P_qbAvJEA#gJ?)yTB)+_m5#PG!AG}$T$eD{Z)t`ep;LKB=EZWz+t7P34mgpSqF zsJ+eS2npEJV2!8J*-}w$*~Y<7_O7G{e~Bx?gap_4p~jA7F=MVOhuTbtNbINoeWR2N zgqBuB4Al>yOB6TQehiGV8YbH#6-GVBTyoKrYWpbKQ^Nn=uMo zIjmmJ5@1gi@k4VQ$Pv+#trV`1Otj8u!xH2#sF0JWudZjM@`m{kUC1oZax*z|R9vsl z>Nku$>Ao$=VUFPCzt5>zsKq|d2r&yA&r~)#)%LpD9E0J-sx}qf<2!DYw60q{{`UQ$ zp!uZMzNGJ1IZNeDLa|0x^dExT%SnBLmp%tk*rw@Z6T3u~mGkYke;OeXe0@F_Bf)4+ zim=iwtyB%)s4in|{w4{@0-GRl(6<3wge;)@IE*r=HUWsUMOMIJ8 zW}6S{X6BNZp@It36(2NbOV^(}j-Ay<-<~-onZ854e-0MDAoOI43~#V%%VCe5;7gW| z1XcECeiSu(#c}ZxNc$nc#0cHO;&LCSnQ8gzGFXOE1s zNo`MZ_!}nLiuTXA+(W5~s>Gm$ky1f}psAZi6EPtLwwo5i~@@)s&s%HH$+YCna zvM;$hxzS0@cHhxPK6Y1r02(pyLc-FiHAYXy5tK1Uo&6T@+^HVm#|0~q;I^X_a9(}` zp>XWy%m#eOb)YZdD}ZvDUDgG3t)IDijdis^fnIe@A**4AYK}rSAoES1H3J50Hqe83 z9oQkcfi4gW@tbdlYvbUN;TtWk24Z$l%>+M;$!SRtal^|SY&QSM=MgxkktIJ$nBjk9 zw})j(-Jtr-J7dpq9uEgHXiX;wIVme@N$4f2H(;HF(DOQb|^v>bzEaRQs6ZF}-T{ zPcB9iQ|wn`z8|Q2qC;|$&`>;Q^261xI>e##_8v?>$)mkgqPE-O%#WmiC;snCH7dkm zwqO=uCOdX!Y9@Qlya|C$MZsG>-VTY}TV*Sxe%mckjr+>%28fUYKsAwt9$-4Us=p-W zfY_n;Mf}ukWf13wjn`!-Qhq?MU z6VEGib6L9QE`F*>ugqAwowx%CNTbqK|8O0{$^(=?^~7NQW0d@>9RZffAzTSa=qLva z==xdwGIAm9KDRR3<(DO8dJV3J1rij^GI2}+3`DdCAF#>CqnIB#{us@YO};&wWzQuM zctpH@vHSK%^Fb+%;CM)SziFPs=C6krPZtxI@AYngTR#BQZkCkN@k%a64)wT@lKHm* zheu%l*<~SlwRn(YmM%O@%u%3{9CpC&CJE9_fAx+B_2TtGr9+{B%0$djGek73K)^SY zJwnJBW7wK^RMu=njFM|Ah6Ubx6)zgk^#x~*b}Lt&YbqxtXFN}x*|C#IlRwq7_H28C zS^L)a0;t#*Oe!A~=(GNL3DhN)Sran-`;AtyL*VzTQ@fU;80N14E`%4*shLHE@O0-F z;4O&5KDPRP6xFV--o>5ia(TeLpC<|;W7qDrt@(rLVu{*NX*pSUl%W5jNEY39!J&`U zbkXZP%=h+@$8npwrml(i?WtxiC*UJ;0;v$5=;6Tw2Nx?5$vJ86Owotj4MPh+Ttku1 z!_!H6Wf84Uxi)R%y_J>lc13jGEZuAUSsK1kJ^y|K;DK8N94|Bo>U$n`7D3*GJmoY? zu@4y20=$>w4noBm$CCsd2WjKLeqeh|_&N86Sl3uV_;U3n^_rr{t+D&breU$ajx~SI z(DfA{r`kf@H)%G$0-;&c@}|gP+vZ!-CDsaiK2+;tDE=MY1ln6;9tu>SHsU*a4E9GZ zpTuEkc&(CYT)7AIo=1@fIWv7PoLBu-otx&no1?|>ge916%M=@b^1sv+#}pGMRoi&Q zzYQ8DtH6By2+~G!H9>GV(z7y~9V+ZRY^vKhBgJk~`35R{b=#DOTZectg{yCHDeW^I zRMY>PGapMC@81orE`hFY=9%c>+lAq=DIH$ z9tYrnW{|=hGG{w$y>H#eigX1XN2M8RlgVEwrtN5aA%A7QB+5p80`xcz+KDudrb{5tRYv%tioNZh(jmnOJ-#uC~HyrDK(&494I zUiY_%n^@1)@Wr)X>8@+b>?O|K=a$a~!Ut(~zXs~KsL7ztw5ye_a?mH)=xUEG9|fth zr|q<~H_h}Ftx8eeNeoAGFuGMTt{!&&6h`Af;9UFph7L!Tk+lZqxL>F!Kr`ei>6=pC zP^OMqp>f%3^&;tHds{3%+ic%RdL8YSybt$A9;#kCNCoBG!R(hM80Nl<2byERbAEej z(GFSNMu@y9%IwLN{{{I!TJ)4BWJj%GXPtREgshFeO~dI-gJS|v<-zz`!M`s}HEgI{ zmr%eZw`?Wu3qU*f?mA%687LnT{wvC@U3)(D0aAVH1$eYw`s$eDXa~T|up>6P>E|AD z%HJ<|@<8Wop(>Tr&H)8jI2kDzKY^?XzHTCiSdb2iBw*EPW`4E@b^^KpQRiG6Fkq}O zgJT`nlRdd)-h?}@___z3gbVH=S5>#xr$8O(s4;~2%vU@g$L+MYlU`y~Si4i-%E9>Y zfef?3BIGD*fo-Wud9aWol8LFM4bC@h5%4CNs1-?)s)VthHXL>LgOB63(H@Lrm*TNxo z{?Tt{)dM_`;B3Q!*SXNScuWYTX*$q$-uzmVj_7b8dfMmyz3IcriiPsK{l6FJhu^J- zAZ8?JOHGQoCfdZKI*3R&=y(-wkNRpKcjJG-MAt8Hvnk1mLM_*vBW>Jd?I{XF^ueBcIPnsdDQ zX+j<~OZ3_^5WtCBPjMWypPfnOwf;!wfT*q~e_!9Mji}NRD%Njq5-fLKaNDRmertcZ zjPOu9UY9s)m;=I-e;4^`BB|TH;QRcQWpC_o+8$?Iqe9}yyneXp8q^=PY~`dF+fa?O zyXUDD#jag2P3;eJo`-XorA`aTCKW2%OSEHVE9|0G1>|~GmooaK%Wv(>w__%W-4@Ts zz7RtQ9)Xy98VF0q6wzx;z-wQy2|Ic@Q-!_iVk`iExx$1JvnATn9eW+q&h#`v*X=IO zq#**dj{TIuD2o(-Fv)3f2eH2(G;29U0^XOD5G3Zr+j)&%I(GV@VCGsvw1(fX90+N& zM`SzXIV6#Fkw}<;eYy95T{21RGiGft)*Ww34@8X`4pLyjx`^@qw~+r_fu zfW$QlUaNQE)NnydkSnw(lZ4;S0PzE(DZE_vfor(5YW?JI1NX#MNameC*>Wrldot5{ zvgbAMjM5BXRps(E7-raKKhHmNZkoD0q^;XJojjMV8wlZEZx4iUTlq_-WxQZWvHK+C zaS~3Gfz|P>@b1>u$=S2kF?>5S=KZv#jE%GY0g~hGj~^jG+4}a6&^(I&h&Pl&Xc6$U z%%p?y^6b+dhD6690ak5rL1jKKv$wWMy!W|Rm4kNO(UDE+ZdAcyzlrAQ^l0{x?tS)+ z*HL5ncQlMHG#2E+9g;|2?gFqNhV~i_0jS?uxnGqMtD9Ej{>G75EQNb1MgplY7n*SFu3*+PmL(igu8!3Gv!TH2vfSQF>*%#Da14gkEklnGwrKTLPWd5aD?Qi2R-;?fH(w-ahSSJwu;+I@q3un=~B zYFW;)QT7MFCCVl0(;L?B=n! zM}SZb&fQu4CDiKYrmaIxrvu4UE8bt?S+5rs`ldVYTAaCnzgxO)m)U{=mHR(a@dOm( z+ECLqB-RD)lRcq2!}+*jqxsEcanZGzcai&fNJ7vaherKte}seQwilCnUS_TjQjAwh z?e|Ex3$yCXt6wf9h9(O+Mx9?_sd93AWqpHe5xcbhw*&Twe4RhKI+WHHj=w6qtFHOK zH!rk0r^+>i-%S=otzRj3opm#K`ssGHg$RAf9Gb|}IO{AM7%O&do&aUM7K+_o1W)gD ziQg_D5~fhV45-|JEdduL_%iKJ;&ZOy8v7M1(b-8I;k#DdKfaC{O(;D*LAzVN zh%RLyf}tHx0t7=Dzaes6u!TJy@_^3nqAYmZ@o$;Z`U)=-8oe@k)3aK3MC>`y4 zFBtU~yJ-$MZ&sV6|HSB^jkeP8!n(0;L-Vae^%JocX)RjPS0NA?4i$^gC&ti=v7=~x zgrllR$qiEZLSsr{%yC#)I#RPbLi4l2>@-=edD|(n3Q3nUZmO%5|2MXj!K)&tpVYCk zTq}XW`K-}ncWLcg&2c1q7;sP>_R6(SOPLlcN*&hvwiA1d(M3#e5SugtTtUcvF9Cvl z=W?5Knuj&g`Q{xyzC^3Y@@G)NYa-@7%G;n0lcTbmQCarn2h%f`Ugo7{IECjy>z-s( z2DR`+US+XhI}EWy7d}9I=8M9YT)*GccUv=%$T@afb7ftl7)#CO>$6$XPF5GoYWU3> z%4<~hYO!UkEauk2b}rv!quGM z_g0QF`783pe{Fe>i9L5kcQVL}IeA9&-f%6lT>U=Tb8&PEXmmf#Gc{;lFx9lZ-b^?q z{$_dg9APhXcOXQNF<0NFH^|o8RCeW|E%>9Uk)1Dayzs+9;!PT?$&Ijdppp-VSKpIo z(Ql*m_Bv5z3ndHR^>Tu5;PwO5xh#yF(xzx{HqatNtQAl!UX5jVx4& zQ^r~78;NhXWwAVkKfnRjJ!UF6$LWbIdq4P@H3)+s9h7B{TCpwx$OPqr(41QP1L1t% zE^k5FF2@3h(xB@po9jj@>3wmTb6Ozl&U=&d)0gRTMUESTd4rKaTj6QtBo`YWGf>Pk zKoqbS1Ow>V+#b~VuWV;V95t~1F?~9a$qKt<|ow}qT zL0wDwD2h^~&`f?P#jaFbj+~&%jA(2w!|85cl?ek*UFbQ@T4v-^<+lW1qG~uVoT9}< zxpw}3SD?(K16gh**!094Nipn3nkgYw7<9{?YiSd0J#W_P_)R^C!dZ_bwIEWHEYWp^A_9*=CRyc(J3__F-ox6if}t# zH|1!xV$Vn^l+&T2UG|Tl3UoagRzG_lskIGAkb=slUPG`Ao&29g+NGnb5kK+)A8>l$ z?#jo}TgvCw`ArqG#!2V5vZ_e1=8qsu5<;{OwuC zp7Gx&B1!V(REEE&<^@3xn{^99l+-@w?WF7XdLFYWt~!p6PAdWHqhHxx(e2kR_UJfk zX@X+|aq9b6F0RN`yNkAe7bwq99FCNq<7N*J`u7*2T_r8r)U&fHY`uAPA)yrc4pKL7)E7i)qEcLr_s6(yDq5)rB-)1(W<1Wo!%`LH(+@}*=BL)Y-K}2St2)N#xAACb z_S~C;1z0k;0xD{rp>~Ge7^ak^4L}cXSBbtMVl>q#lxe_!GNOy}X1v1v^dsB#^?rVb zgT>aUiP2ienbelbb9PI(|A$%bTyROTZgS1HFG+vr5zH%t5kpDblLb1L$wG9C${%;C z3MUYjT3xJ(YR?oGX-TmI{_&wj`_URWykS0mw|df^5r^|DV|~Sq7HnH{3$Lt4r{ugh zgsSDg?I%|+UbY06%GcZMzBirN_el&MYFcs~YB-3VC)1mJCD71>v4(B^T=tpEqRX-H z_1w+nDHw*ApbbCDphT{9W(7X z5bHvCTYvuN(6mIiQ)D77UvjVAf_q-P85>8yZTout%d-KwN~X9}JTJJd*d^I)gx6?Z zvNU^>5gCe7*MYFtXo{-n)F%1WJDy>IL|WHszxRh0a+vUWn4ZW#R6-+OFn- zp(VX5SHk&^+B0P%6xnov(e(L386EOS^3!EY4&bvajML={Y`ZOe7Hmyf{X?@sXi^y% zfj1*+e|?aZ+$74R%HUB%+Zc+sW$(!oi=Qj77 zSEn;a;!gd$1hM71%>a#q$iKT>KWHbPDPMa$x7rC%Rhw1xPcG>BPW}Xr&B2(8$_$um z6@ffuhfav_#jx2dxBLL`!f;|&pn6$r1}=kAv`nhLm$QET@Ce_m=km3Ie`?_+u=N5( z2j)>i;?7_5&4@OmW!Zx7e)sDUj(;&vOBwl;8AH7HU$>+7v?Vzv=NlVwnwdgX{($e% zm^K3~jbh5l4^=I?!aCW$*oBGEI_r$Szv5=hj3Tz0+0)PNHpN|%7d7r|sz3P{cZK`3 zt)5*~YU=rDoBpWK7$9TQU)*C_KFqz*^Qc?4ITJiRYvubU)E9S}zq>6Ua!8IXs=xvX za!O?tw~A;SS5UdoKGpRc~Rvm1vu`wZLyctO$meeq#`c~uLux=BodUta)Dy_<#6f=nu zJ`}4XK&%U@5=NWSB03*Ra16hh(A0N6d#+dl*;49Wc7cWH50CL!{+>BjZlC{sU*`~(^0xqjZqGc6 zE=1EpA-1_ZOQQVBV)U4|%-qbQVM)W~cdl`d%HB42%Sj*mefo4wT;sQ|k4xN7^=+a> zwWmhJB8g~Y9CT+M6yWa0-xNMK_IOjORR6U|tD)3*T?vR}0qrTR=fc}Tm}eeaF2}d$ zeW@~4pT&!tZ;RYkOBrSy3ySKaGYAj4J1g5#TNk|`f4+;m-}q@))t`kvouA5CsLsMhxeCTPb$eUj z{_#z+<7z<$S_6^Vrxs%2mm4g#LC9U?(WZ_7^^;H4jZX}m=4uXYTcLTy1(js8Fgl}#~*Op0K`^p)X#!QQQ6(9A;4&=PecLA zMpIS*r0m?rIR`lU6j2C2s9(UbhD8=UJdv-?Q;=!HB=3Hxu6n(_w{GO&T`Lj1Y&t5d zN=Nkd8NimB2&!qZ|9uTS4uj+O_-v_6;>|J|G+()a|ar^sLf@@ zX4u^e9`buwg`Y9e``2 zSs_I*w$Vjnij?<~TcN{qBqaMg`8So>kTbtok!i&+-v`D%<2B&*(Ks=(vs%RUPTo0G zjO{-@zXAB%_aNPl(Zr7WB0@{=Xi55jD)GsuKsdUhXYcsoTCw}gbJMSc{7-}-SJEbn zrm2)O$4IE#sWd++)a#Qmn6xK&L$oSJ=3YshOqNsqBQ>?07D(6Ny|r{MLtMjv00YO% z|H1R0R|&o=h8w;~K@sCmtf~-S*k^Z0exoDQnzsRn;m`bzjQ!@H>Z){swrKAgYDHlL zQ#3_pQv^Xvwr+0eTC@&v->Q$ov+zZSnt{Odl12h0FW~ zE}FK@t0RD1tPX|2JBx*TyE<~ExZXG%!C$?*QCN5yt=_iwL?nwmk9VWU%>ifucky#K zl}81$$az~I+Zvj$v}mO`UY_*>f9Zx8?L)|3iL6h3_?GzkjAXDx`Df}*3;A`TB8yTs zJJGJ&j?5VnH>&Nv3gLORHn}J_!9+CRzdOY1xbAJ^U8W7FeRB!2@ji=~-|8!lF>LA) zS&ipaC^LH1i^=u%qBi?pqWE=u18ug?X4U_aWxqMjKGXF4Y~h1g{@7!D#T$6uQ&5{- z)u{WK^{<5g{m9+3CG9S%oPs;y+)%S^@Yqh$#fN@YK7Cs~kH3^-e^PkuPXS2!KaerJ zWD5#f#P+!Y0c{cS#${>&dd^THIjn{A^xy&O*Ww=qBo|oFQ_^V$z$<~-z07r@V`lm4 zeJ^Gvfz!``uKfQM?C+OVgiD1NF47zM6QaH&?0;-GS?^-&IAf7h`*%b|xy$W?D8Gxu z>jzy8?P?X4L-EoDy0o91cOR+SbQ37g)zRyXh?P+rNpUjH5gC7|sI*FlE?o!tnr);x z*KN7~xx~wO9IHQ>ADC;d`Sp!F8P6;D&JnCqSF+UlS_F`_RkEn+&Notsr?$M;vd~7 z#V@V21E-1xNvO%AxqI)E_4b*{E?pNfV+D(Mw-DsFvp8qrIts}C#jmvB+1ogYRGWRi0l|6@lpcToPc^WTZ1Ttv7Z(B>ZbI&;v9P*;fKsb~pI z1PC1AA8pFsT+m;X$qUhQK>rM(&u;k!T1)Lp(PSk(4v)DMr_6Ee&37b2FU%w%CG}^g z#*GkwV!q9jM(KS&5|6VB?Ag#vc>dbxSG*(C7344Y;GOTYje>nKFs1QyE#2T}N6K%5 z-e^c?jk!rIgXZNBX4>CCy|?k(a0=46I3UOtsH@kB@))Y+ws&OAVGT+C(QGr1wySmN zmON^l94Bu@S;oCfI z^IiJsS<%w|{C3?UHfoxBky?+ZS;SHahNrAbuFCUWg5ur)=85Q35wk4s-MY%XZ6xb- zM8jz6nCn@I_LS_b?{@)(5=I1{)rXPETFlrLZ8@3M_&m*G8@dbjLF?n;ho#W~d}C&O;y9kOG2)0Hidb`%8eu<%i>{A(k%BMwqXWR%Koy z7teYf#jWHq4Zhkmo@!K&7M7`?23H`IclzklYgkxd z=_+OVYfTEVa~PS(LNypvZSpkwO2fD@=w(zd zn7@plzboW^VrNa?zU_gSERbf){FkNr|Nkxc13XHs^_c7qeezRqYgt?0vdI%?9+lH?q8xl+5Wu@!;lISm|uFYhlR-Kk0Liht&B zLD}w&wU~$Nd4#|Fqv_F99oaPvjdL0o=B*!fK3>$vgNpC{zEWFH-Eien)wH#VoMRhS zOBn46@1!6Okq;>L8$`mf$q*0nD`byk0}f+e74Af-*6%*mJY+7ZLB;h=XECZ?O%Do>SD%WNUzA z%O4Q>6B&eV`)1;U+ad!*8y&cin|S+04LT{1zo_6BKr z7$BJP6w1XclQp~8LY4Y`fcL{9y^{zvpRZ~UhaGTi|D$KZPaYcL4h(-69{@mrel!R? zGHV?O(@z4zw(BSh*_$qm;vK&K5Oo6;Fep7YK_T+}*TuHlq;j`v#%PnJ%RG_?l9WUus`5^F0WGTj4VD%*S9>gX%xRNBGRGzPq z;C~U8I$Gti^K-1s32)F3*!Y`;7cHzW96ff*h&|G9iJn+))Re1+4}yK5y>kD5RYX2~ zeCq+U%AL5+4?Z5i0u5DJ0$0lV`oS8&$C~c-??qkni#p(0t2=pa2G?B+LK8fG{N8`Ysuc)Id!vpXmQLdZn-`mgjR6}5P3{%QL9Y+DvO)i`y zTHTrBrJECVz5|6%TOc^MFhWE<5YMUe6e;Z4+>G~BTTdcSB8m)K={j6Vh|5VTfblwl zRe&5htmk~t^K~=P2}wFW7T~9npnYAn6;DH(lWyNd8c^R=PFJM*cdphEv^ouA{Lila zZ}Bv+e{VpSn$7?^&4k1R(B$NUpFHO}0MfIggR74R1qJoKzixP9OK)?J>`NGb51Z!^Q0UKNg-a}b5B1og(a4VF1QLR0JFcO`v4zGC7g$2W z+(YmWK-C<%?cR-Vs`1K!zv?ce?xyrg;I((YM+WsD#k-gn?afVNo-8|{Vtr{Se*X>% z`n$mkk;PKFaYah5$klN_bUtOs@VeNuTkj;q!8qs9sPwnXS;G&FJ273m`BwQ=6s1S= zS+c~${;5mW>UnCxp(wv?YuDnfuWnq&rz5fd4`B0v?M=}_Hz$kJVXKiqHT$zGAOd9o z01qr{pyzw_`@9}|wK*`r93Qwk4gOHH(=qqJ83AZiKLAUv&gi(U#bry!yf8&Z(%6V? z0;U7c|HIZ&-aq(97tG8%@80|QKF{arqI892e*rKQ)AjDi5krESd!#;we=73zF*wQ! zEP^&E3Y;guWeD>(r#J6?j%6L?a)EPS@kHVJr}JNi5>=H%Cd^5h>m_Rqw%TymLtD-P z+D8Ex0Uo$}|Kdt;G}uNQHY55${l-A`l&)oWm(1aKk#9JanCK7F6i}D;qS9=L7k(1N zn8pD(3dJ}nq4-*}_ZGX#-IDq`UO3;3z{$I-c3+75y`)GiJ>p0!V|H$-I|2~S3S+ez)&Q{y5?1Vu@mgCkC9Rz`)bw-VQ6(0LJ zR+AITxxoBPFTq@x+55r^gUK(iaNsRH-BuKC*jJ^1t?ZNTe3YYchQ-fXe=y1Z%G9mo zz&zzrn3U|EuQBS$Gp5=_)via$&Br}%s)8HN#G%xgkiUF(|HQh#_VOv8Sq|xv$Y9`{ zyj*FkPjI(9AQCa@jZs%i%X{#I*N%M#5`9CjepR8h-#65RHitHa;K62_!oipGl;sdp+oGFz}poT$Pgr!A$0Z0FCr?51I(u++zH3(UK zh^A5Q)VhzS1xz)*+%A7uR!kL4M8hF@wCDr4%FxO=>v{?C#8@i^tl`qTA;9f& zTiHPJhy(8)evot3LW24zToo{S`a$J01$7>KX~RkIB_QL>qkd&i{^*&I4O!=IJv!-Q zuWyQH)g1Nqa1cc8<%4F2B4E(dhn_Cyt)*=Z%Q}Bna1gUFL;n_&2B=p}3s=G84Eho; zB)Xx!uU`DN!bb(~&AMOjM4VLlnWM;1Iq$vxuK|0D)YEKWLvv9*6MP+(j!^%v$@Li~ zWxl>%%VGVgI``*Mxs8#o^sqYZ9NVW~t}{H8ok!(L6FJwY!h356_L`TPHcqTb6FI|0 zEpmr$rV9+7M(k&M1wOH9;QaZc66OfJP|0!6wM;dY=1E(ySPY8T(tx{Av)4a(*<0Z+ z1kv;h{Q~T7xPbNV^MLE$oj>Z0nwP)@IyC^m7iRZnL7+H^d>L1k5{MZ5ap{f0@b$35 zrO%h(I8?)61HKLh@M|PqRp0OL@cNF-d(Wx_BgW0E`vM~^8pa`6_6&+;L^I-c$SPnH zLB(=Hdq)M41?kU&mKr$ZU5m)?gSS@=uoIqChs+irzD62eyikwdy zna={zM!KJ?RB!P27*(CuwYZ}OPQD^{Ockx@T4f$EH_l0@d|iLxU%5=OmZdd2zX zwf)zM_2nRrU~>CxTI1{hLFxUnEGa>m(^1iLy3 zWQnDu%2`KF9ar6G@8()RIkt~By@zUp{b@gs|0I#>sb5Vm_Q~q%j5|*2LOU~u z67Y9WyuAlKjGQYA@vbl&c-%`2?5R{5XIV^go*2T0IlIW$ z7zh%|q$QKw5;zQA`R@QTD9vll^NQVY2bOygii`m_4LkvV8c`R;n0?xwWW!{^mNN9z z>PYW7Dm`Q`D-pvBIC4i~MjHQ|QRF{vT(qEMZaN*>W&r1N@s{@V-Sw#1MWwA)%%pW~f`d4xTbr38Ujs6C5L z(c(8UZU(tOH~yc(&OjZC0(1M!c<@7(I?Q3qDN}N}QFQOxc9-Qqy0A|yeS(K6{REH? z>gJctL(G2xNOPWdk4Q;)=xBca9}D7b~3OxWhj(3ba- zBK8r)?XQ0>#kusZX8JhTjUHCjpup|NiL8}f{*XVw*BUjdRK&Y{pyhfk*ok6w2AK=T zgey-p`38Y53Ijdg&W$T(oEjQl%gJ#x_}1KoOTj<{p`9<)OVf0lCTD&Bx&fx~LdQTY zofWAt(rWj8InKGGyyb_|W+QAlZn0VVl$f~Cu+1(bmYQ@RK0 z4hBbDwupqTenjJW?#zJ4g|IC`x@+y?TTiPeVnP3>H3@HX34Gw|ZsGjS;BA&QcSkTu zr69J1LsQLi^ZTXb1z8do7WMhLP)bhUqAd8i{c)vSBK0G?ERpsk_2+~}evOXJ$@@64 zjiA1g)Yv@Y484HqRu#)EKfYR0fI-sY=Hxd`8F&aeWU(7Z3a``*MMG3Rnx zdDwbhvyD{p`;Ra;L3<)DtuzPA2C4R^m*WOuq9-;~_+hMnIzmY6gUUhER$O%uCb z(|qbe?h0sf)jq0}mSJrVK08`zAE0oYUr}!ia({EuzW^~jNauD`T9Ee+i-xA1v$@V$1{`P3DPTR1@hv%^+dj^NPm{Y{r!~-84B{+vH$qXqY2Fu;hls5(=C3A*akb4 z?>vyRVNPS|g7&7fxuP)z0lsq!s%KQfEu@_6To0LJ9K~MU`x`^%dq}m0(nN5P^}+EB!*j-`Jd}P63cSa9+Ic(`18&Q;@ z_M#t;W<a-@3T| z!Hf6%RN{BMQbzG1l6sZnLUjxoFD&6(f9IkyrNpHM}3~d~dy3EkM(fLFr@yQSsxPoSa%}mS_eMv&Vd*y@SJ(wgf6> z{Rw0R`9>%u?+Vo?1|7sK!-Ol8iJATaXJsOw29edMAKTzvd)W^%+#Yuw@_yJ3AfrA0 zY3&}I%wsxvy_J<*H)F2;;a?9T*b?Qh4{qsSo85DG2e7ontX$s3jcaWo%O_Z zmXc}mXClJ6VgORL9<=z9WMTgb=hU;b>CbF~*~_Cdvh)O1C2Nbt>rY9}uD#bAtT?|| zrn5wVH=wQO=<~n>l!ZySlIZ}?knnki#mJud>F?h%C22w4?3?Um1pY)_Uc7&QMw##1 zKkwGPk3g z!&94B*Cwp<&g))q5ZV5oU-*EfZF-U1J&yO&!vk&*)}w!N_8X?+wOV8Hpw^b|fg z?;s7o!fl!6+`~ZT`W{wD;O6urfc?)p*(3W1xE&s){o|t2p$a<9^$4jr;;u1tAf!kM zx(P`Xh2~b1d#dVj!LG%fmyvFC^AxT4SeV4wsvGPG%za58HE{%0B|cegfGbP!45IcT zE}EkkYSZ~S4k!0jE}A{S}O+ z-|%4^og8^a$9_tUjf;o$ywSZF(o{+noG5mpTl29k!CTYu!`!Ol{e}=~2zd7P@r47F zoPXE~vQjy+ysoPqS&>LBK*cXA8whaWQP)eM+z7GE?gj8v6JmpZY)jq!k2Q#-MxxP z$treK-DQ|YAo&~S_0fn=QA@)BdM^~pF$Nl&j#--W>@p2uLyj3mn; z#MTQwrX;ooyR3UHdOyp!KJ#kXQFKUl;ksg{=s(bw7V|!rdhY%+KKx71=?U&W@$H-0 zhE&w~4`)mMzPD3L9#g_68lCk%h|0}*_Z`3=nEH85=`n6**8Am;sydP|!6baWOCI~g zD{}9Tp2MFnx_6p?PlMF%Q^7sLkbKx&O|dKA@`AKkwY@^Z>?bkaaHSj9cf_{oN|eJr z?IaEmfe=d3V~+_Sko^o!i;LTE*y=!}R?rTTeIZfRP*ZX^Pd0k|+0b58^MxG=h1+U_ z%~AXn9& z?#XAP_Buk1ZwzE0CLXMpCuk@thkZvrTc>^xFOOe^2^whZxTS0(658^L#!V>-o<~FQ zxwh1_s+H3t7)vWu`evsI-b=GzqxTdd1sju7+T){7B>uv+cc~QD-Oq{V;sR=SsL!+4 zTe0qE`R={ve^G)f#I=S{U^0eJg(!_*i{x8moxKWyEoaV;uJ@>tCy4A<0ZV{c`odtb zcxBZ77=aY|K`_MDR5tNt<6+bF17&G@w4n8Lr&Srp0ZcJ%uaEf_V_9mcMjr|%o2+9^ z_NJxg!|C70;Xe9QY1u`>Mo>91{hj?^^9u)DD63XlLIliVJW>Xu!B}QhqT-Gws6L25 zaJB4r@SbB|g|2~OZfIo@s=rSHj8&~7dx7ifJ=X}#+4JTy;99p>yZjY;twcz({h!AZ zh0})(&0NBTQ$=CMIHZdmI-%lAMFcD5~?%mM0A>B+r%E^)H2jGtJ= zA1J+X-I*W}b+*HN+kQGXiZS!eG37qgGzSfy4mdw@9-lO&)2G_Tnw$D8cQ*`_=J`vZ z!R7K>*{Z`Po(1M}aHh-RR{b#-6T|*)Ft5@tl{+w{c@?kMrsL)U!pZzNhRl@=er9i}> z%>*Qc2&NcK|G1l6cT`xD45*b}a$LBMNEEr?Zf{)qizhg2ckrnMC(xmjshIqk$Myu@ zUO1DOU%{A_&sE~*a51adlsL?z^Q*bTH{WX0LU)<__RH(nK2tV=w9b6Ubz5n3(0br^ zU>FihcEO-B9~9WNBh|3(>{oiw;yRf!v@ZakH9b<8N;G3^gx%FtbWx7|Ca!?EPUnv( zO3iUA*%ul^zxDk}q9l_ZDvKr67qw7X?RRbP(1MF>YO^)d0j%?v!eB6S`L1Cf97!(tc*}YUpJ)cKBkA3HBzP7nyAyiNDbs|jA*e^UX3r~Q9vF?m+ zuQZ?LwTQ4W^-PSga5J9siscS%R*AmYTjo(}=^WIK?g+zBjGQ}%&-U{bsjOV%h0pg# zHg_|_yfbi|cP2Dd{=S4PR)9*mv)`@Szk-l{?1eKbKN0VG_tPC1ecWs2^)v1(i<;t>GiK>lW|HxB`|p)R6EVZqS@ewbDEpiuL)6}b5TkHv zwMlNGlv#&KKn!Vb_4cNyyGQpuh-r_X65d*3zF^xWvLXA#yK&-pV4;00=r`W+EvNn# zMXqN$OFu$Um~D08wuSD%?U#BJpN4?d%EqAW0liYy61);fb1te57YqMFbk%`P-wP$N zc+76}wK`o9c?nk`|9qJ&e}9a|yqeu-HF8pmrx~?p-|=$y$%39|y|FTzaP2-)&ec0) zv3mFSRzB78;!8!9=bvvqY(p1|OpG;lt;;~gXH| zgxcRcsG!{`t=nOCRE!sjai(U_snrtrFQA9yFGO$H%LKC_PZ&=3_P@dl@#BvANSU&y{Q zDbkJBO=CWL4_u4nnz62~{jJVXL&9VJDL*6>YkF$NTJPd38jg0hD(x3$FKi?g{^tCN zPkJ7zr$xL$)34MsU!nax=^(MsH)wC4$9{W*`+fFb>>B;9* z`DEl|e&Z`|<&OR`{}=XikF?2n1Hw47FG1bo$EW$DGa$cWlJ$bE?|dzcLa0th8MVuh z*1JXRzoX}xd#LzSH$}!N7d92yY{aYV@sM}^c@7nM zyv$>gb@|cHXBbVY$wfeiy=8k*4RV!+ZbtDQlGi2Jo}{XYb7<96YWa05TreoQ&E6x9 z53Z_#h{;xfjqHxUxBsKC#O}RYkxu=fq>{~sdTHgy=y%GY0KtK zi|7j5uu{aYiBEotJyAJ(4!1`0vc14wsVD#X*}dri%u(RSdFcxRyG5PNtRa;Xnmvqb zr|!Ep5=sowqz%nh96!)-ng_E#_KcdC?ind1PK~}F+^Ulu`v_-4sJwR_F#d%>DO_I%{qO(+a>gX8ApAmR@B#W4Abol zP#hAV`xMO)50zxGM1l}Qql_=lZ2!z1ID~A0!1kKB==(U~+p{r6F#=VsD*j2duqXVV zGPH_S<|6)M&0vDwT$e7stcmd(KO0QENOV5%OJSr7!cvKVIDgE7s{G@jaNa^fGB{f1 z{U&CG*eZ6i9JTMp)rWpo4781=s@4`Cv?zUKka^pmeh?M$-jOGsR{_ z5Y5>#QwgM<{jeFelKEB4-y8BpyMjd&V?GAs_b((Fz{BwPTkfmqwcQ=k+^eMJdfP*= zoFezvWA3fzBk0JEvT4F04Z;!WQs^oab;GZpQ1h94s{8aoKtFy60Z}h05PnNFz z)9Ay!Qzym@49@+*hR931oK{m*15+d zivAsVo*|I`Z~r_P;_3=VG@WWbB67o^L`48HuG_NePOOw9M8m!}+(z%0I$)1I-!X=YW_wtWhskuU(Z7tzuRNlriZBY*#Pl}r#b*+x5|$$s4y>TG z8~d+&zV-ic&;R!^@)hG`2*u-V&CRYv**~T}eBrlc!pjs?Xq(;$-wR(lHFTEXF6!36 zBWjMPj|en5n8L%k{S^G@B7GuWho5~Pn(|B8yB3TLn)}HrmB_&?>HeJt8=ronW%;_| zkv~ShRG5^H57l9WiGWVGh1b>?UDH{C$azm+)2wx{`<(DUYt4UnbN@FskMuA2a@kXQ z$a7q#J(;?v$7amuIv9Tm^q5E=|vefjk6-|IH z(x+{joZ_ptYO{zvoFX}~!mTa*UwNYc^Shc{sZ&x1FT`GM{r4BQ{=GN07K9`C-?Irb zk@raZN%Y`&Mg`=LA-^!0Wdf<;@^+La`dIhmZ|a>RG_LCtj4Q@YN%-OzzM<>CzodSy z-llrtYtBk1TGj#aMfNIPC!^1H;L5;L4hStJYD8Wge?5wk?jkb&vbH?koJ{l|Q_er` zp?`j2f5*TkyhF8neWnSICl=*@uQ6jvM2}y@^{R>E0qU=nYe=e~(;c1W8Ma0rx>W&& zMjxL2QO;{Om9tGh_dMfS=9w~W z2T5W_Fe$q=u-{p*)op$6kF8yu<=-73#v8N>|MVb_>B;wtTrzO2~XD;RUiRZ>W_(4RWDS_4JA%nP@piCIpel( zPxyF2V1Ps38a6oL)?wWCSkqId|qCyE=6N{DcV|hrecoI`^`u8m(tL%=E!d}Sc zZr-=v^~j(#y4STDp7Mgo^a(idpDr*Jn?8WsXsrWUaHw^_pvn+8{u;M-x`B|TOMFfp=CS$%rE9@HSKe?tITPwKS$C^ zkf)c#u<6VKIijT)^;*Y>MIc(|bCfQ8{r*FIS@LP64FtXfO##s%kZ<7K0r0h;tOKqF z$7afxFfy>lId5eK^ykFuemrPKc(haeD^Lw=6rZh-jzfdS89Uc(oIL?jz8@UiqH916 zO)%KYyK`+vh}w-IK$j#e5iVZl1A&-8PiO`~O_Nx#Cp*>u(Qi0|o>%X+$;GPK#0 zDDb6sJ{nA6Z9WR-{EQxPHKr?eB6uc}=O)pfzWkwyUVjE35qG;9b0>hBBo`8AtU?G~ ze!jNdhyt;mF%pD0LtfP3gPy`)kR}xv77RcLgxPLBw?c3G;$h3_+>z#K0(7WJe&aZKzPoqhf0oSb-aK>hUkWEFXq;hsY&;)nK%00Ekw-op9 z%*;$lMn=m$`Rmvg0YcAO$@Kqn%SZx9jVY~M!@kEWUE2P%+O|0mX43<^oc zStbS)&bo24KW%L2U{yH`zHC->l&71g+-bDOWXiZ}6&p#Gv)vR~HuLYL6IU_e_cy8n z8J-DC-xy_X4`Dj62AGmhyz#f_u7VC%F1qZ_1nL_Y7#P<5XjYD009d1?*nKon+&xHt6)Y7OtmeA$Pm6V-&|5QAsVf_d=N6)+QY$IS9S;97g z>kr*7Pm82Ek^i}>sgQCVP$t6!ck;72Lm3(Y-R%Id(s(H?1vTep!0GGF2ACT;-1DeZ zOp6)WQ)qRkF>oL0t15QXpN+~bkZ8eHbU~1Js?toUeBbX30J3V7^G8Q8P;Mc*x^4%J z7rI(vvI`)vWyQXxVk*nxafE?He|H@2Nl)kL6_SLXita@`IeoIq1~OQUxNqj&FBT5K zzvfw%b8Azs1ir5+@nE~aHDF>hW``eX__(y9k!r94iwjM;tg7yKy9Uh-s7#whSEYFd zkst9!!W`~?Lcwy6U$~yQynZ(up;0^f1`^RviQ}aq&Y2N+7#SF8au*;OPPu=NX}h*A zCnKjY@N&FEB)r0dV4NYRY`+;p(0Sc}UN?@G9%5%fNPgDqAVvNrjDcjnpNFL4VyQ<; zn-5d%wG+2MB^e(AVm(_L_Eo;(;c<5R1y01k*?DozZ0}^sm^by?!Ol;>OV?=c^!d=v z3u$>6{f2N%@|P7bhS9a>9Y#BacgL6{VFS@-0B z7{zQ9mgr&YR2Tv$+HJ+6mTyGrfHimIDO3iU9C5>p_7+Eu4oC0&$cMrS>*(AW*!E*( z#Y~XGfgGl!tr5KGWgXohT&=+jgrmMuo1+ln?kR z^qw46MjE32bE$`7LR`pF(G!4gZ&C6WSrExS02rZnBUOO(WX3LFPc{bPJ$}*scXvw3 zFb=uM6;S6aUn2b!I{0P8MXNv|3gV>N7}U+cgf^dOmS)isrI310PIDzNBfg82qWlc> zeclMqNlmjvN<0Ww11@)xr0d7JF)q4wJ@>z{M%iJCm|kpEz#urYha^Z$ojZsOxK#~a z>2{+sVaoMNqL;t#8-|QW#l}}621|?jw}jZYfkv0RKuYH!v{&YXWWP#E$ccjAaMXr_ zo`1gRYExL!v&2|Mddgyk+Jv}s?LyPY=H3NQ4|c~aH%Bzt%Vy*V?g@&rABnVHSNC&z zFpK|u5X@2{4Le#e3Kn?NH3|Hd*3_qfqryjt_<3LX@~!R(-9Cywu1S&=-3TxQ^;h&$ zYpNKcrV?0>cp|R#cI`5Zybg&dZ0EUCpP8f{H%~7j|0_Ljt&Gm-Wh9G~i|a?o%Q?P1q!D z%S`9vuEMsWkX|iZaD$WGo~6@mTLA75XB9f;*WW{F>CKqiRdqX8RZJtRDI?YoiO%-uE_FIUC9pnlh5<_6D+v!YZ`Yt$$mo_Ex0&Hwg*YdhJlBTcL*jia7sRJ zG-FVZwo?guQJtE|^BwFHH84n1&0>{JQZ-gaqk3WQ@)RL@6>FW}Dhn`RMSfHi?WncxlbCS)C_G>8Dba zg^*hUNIOjqP64hy-svMGIQGqI0wt3B8d{4;pE&o4mzlQ>e5eCgW)Ess3BS0})!sU~Go zZlb|5`D3E)4(&3jqo({Xzu@PL`g0?+v*g zrM-&-3RNPNg=;~lR0(S_?;9abWP2uL-~~_l=JW-ZfIY#>M7(w~llyx=PE~GwfR))A zy{`W2A6w7pM8uG0At;zsNesbMxpV%z+0Iz##LIe?`pv+3_M2i^NA(wx=|eIIDqUdc z7D^!6Alf9-HXKDe(1{>#V8za1;<-$3Ai3(|Obko*Cnj(B@8_^+IM401G<&Y+0OnSG zUcC(%{FrR-VFw+uEDfC@I^=hM|6RcQ%hJ2+Tn?TR>hw`|vVP*VuU43uUw!(PAJ-OP z<`0RnAj9RxusejngV(q6*K1p1Je9BRh*rDo{6fSTZn`8X+uUVqIX%W(!rIca_0?9C z{vlO2`CHzikK(@L;)7x9fs`;4K z+0LFO0N3Tk_vhmjBcWW5y# z{Gj)4(+g~-RJt?vB>!pYFcb)s1t04(7;=2X;PUA}*Q}@J{@7V%J{f!t9>^ch z_l#zp1^w86jjyni%V7VRAjye>nlSeTxJ2Pd<^3*H?A=hpAphi*YSqv1)=o12RLSGx zM=iR$iQ{nGbENg6%Vr?$!OoIL_)U?FA4?cF+DQDiQMJDleYh=kr^knEcUI<{DA-7h zbtiV|S+s{xtl*JB`fFEnD%3ATeC}*!B;_EOmOztr%hHC&?}ka=r)O#W7CEhG$MuV@p*m4 zMx^4oT2h5=kIGRZN$+rP3-KsjGD~LtLi2HZmGN8S(X6*0nQ}f;zy8a?tt2ri>?|dLno0=PD*7P%|$v2&_*n z@_SD=IIRx9;;^0VYL@b8c@gtg8RU(FtrLqD>Znv5^Ho#%oZzmwz*s`Oov!FaL1!QV z`w)OSl`AuN{VK^JW4|fGdN=*K#r(0VCQ|R?9wYQ`frCCBG`T@W(K?aGWF8KI6H8*Wk8tw3|G>)ZYvi&@m_ZBuwcl_$$irz+(YJf3y5=w8_mCDj>Ei-` z&l*o+KQJ@mmQGbu*N~+m*OKfS19f?(sj4vfE^a@g$*q`GzC;3d!6E8mF*6iif+a1% znRwr$KJKVLECzX~OMl9uztxOHwtNwP@_aR(hyijK+WDSG3)0wYiox3B{$|011nCo9 z6)osM=tXN%t8Z=4j*)5Y$MS_^$I&b*_B4Hw>S;XSmWUbY}vBg_)LLEz|nH5 zi|aP+V$72dH zikl6-i}zQKyi&(>lKKLY5bC}V`sAF?FQCc1IYh~&a}h{xK1M(}OoO^cb3vMk4BiPvG=~PBx~;lq zDDQ%OAl;=^o`Rdwc7%`E$RRpZ+$^pqijdoH+V~_+%evf*n!+SevcZCJ2uYCL0(z*u z=lF6H`Ey|?e`iEA1+`*Z2Ho>fYyzaaR$qj)AEG7oEq}#>4O9$UZvq-#2ON7}f!L(C z1-K0n;gomfjAEi%xgtlc>C37}*6V+WM6EK5YA#{HZ{-=8hVhA&zj8p7Oq}@NPzt?3 zCDZwcFL*TiWK+{r&Pp6TO5_ClJIqjSKZ|Wa%w(3a$<0MQ`ws^ImI->%i=nz6F7(}}*3XTCaWA?{y1!d5I50Vu zlT$BF&AihgOYUH~L7X7EjpM8p?FP3{;zv3{U|jfpd&~?@g@~gRFICI+@qUVe-#9%@dTitl&d?uhnhagLX)vxA&*!Yx9uI0R zT9%4DsH$WmCKJTL6T9K)VqgIqsmjBu9v(7}{ye30QwYWN^rBICnuARPJl$coAXkpU zp$`5OcaK863tB$9ROfo36HOqY+rJk6oFL@gd)gKpd$1|7a$#0|H`ePoOC9_OI6X_W_YKBtjP4Lrd?*3 z`igU-Q$4ax6)}UVaa85Us=vZ0Qo(U_(L)Y`rHwC?&Hdv!t>oTxQ5YU?FN%g)9p83# zUXjtJMEdnt_`r9cI5T-cHDgDMTldl1juSmbWH;#D-9_^gd@})z-!^1RD8;)agElVq zbe#x33Kw$k?&}ALQ*GLv?PvHSaiHCCDQ^5;5dGY0^gGo|lA-sE;uYJi<}ov za#m>@9yc~!J3q139Q=xPHE4JPd`rA7e%v6Q%U=5^n;kKY+I|8>RjN2)cZS`=_9+oG zL%7mj?;gA+qsx3r_LeR}Dl9}&Cg5F|G}G(u{MJl7H|a(yxI`FeOR{^3QUxl1)}LI4 z5L1ep>>}_)&W0sd*kYQjbFybDH(9H%cg8JL5&E~bL3<-c&OngRwAs~h%yFT6?E}$} zf=&QKmzmhv+Q+FM0;zg0MaUy`W{XkdiE0&=lYvy(L8;^F-pS6^e8`pf`j6L zv39ZVwg_~Vsb*hm3#dJ>gi-GnIKi8U5uRas-W)TYuTJMGSY9KcXpCyP0nGWd^bini zOtPlQO+YZH*`@jYjGdAx#t~iD_z=)c*l?wy%qZ4?t|zSD_&fL0-+fo#;y;ETH&2I} zmp!vfYe-%0L{lE%ZgqH^ZWO{vN7e>-$He&NilV7fDXkkjJDI=mWk{^}_A!BeunpplaYnIl z+8|Y{*`sUjohxr^-SvUz)nMrOQqo9$Vd-6c&(57;-5Kp$?fygk?5E!#bSg<6X+0$D z$)V!hE;!GI-ZW%Ww{r&*!0o7$Wz0T1O`GlTTgfbC%bX{C?8W(<`yh#4RZW%=HMLfF zY}C;_j!jk7c@Q$s;*y9?{i$DB;%|kTW^bU#MLj*Ij;?2V?}3rU#POUUD4fTBsc3(5 zp}cIeRTaofw|ZHC`mzlTy@g*DgTur{MY zHnKhBicWzt@pRD&9)_Lr{ylr|gd%DJ(`vjDq$T`>R9vHxDH~#dWYY^+K&>g`Us_R& z3!qV1G)=CMJr;6qB0&4O1{PJ?b84+ zfeAm8qGye+@pDW$ikJU8yjvE`lRWVP)@!v(CFj8OJ|1K*iCppmDZT{({f8gSQme-b z<7Aw-hDoD!Y@KJoG8$9OK9)=W#Ax{BNFGybISOa&t1MZSs_NtIJQ z`Ju0O&N}(Sdzn&hF@~FjMYq%E=t&A0U!l3#c#l4%DX9LzFg;o}Q?R}LI~P0htDVa7 zHxz4^De>_jv=5{XjkxybesZTnJ{ZFzM_u;0B)NzmF>U_w0DFcqiywg?cgGgzc|Nn* zYtG?L)glJy`|JFq4yGQU)V5e;#g5x$NFXoPb#>mL<#r?ay(bDuZsTi+?P}1S`^9ac z_K*PAS;bfw*k0NTAcL0sL}db`-(-nDFe9?Mq@ORn=N0)tc%-5HfA#l+x4v@ zEp73|8Y?ZWA8p-YONYS_0S^s5MJ;BOc}R2bPPytslgGuSvW$%$&i9YM&XeAUNQ+r< zjMR)SH@eLrCOb*if=eRV;XIX5$&tF%@PWjOTx_}oJAy6%kp!`|bD|3JN|7#l^iGgl zMgt#LOkasi^)rtVR&?lhrInFV;^A5!CBt6g$D}lyzGM zP!aeM1is~OKhFJ_t^Om5MK{hZU1`OTuSV zn=eUJ7P@LhwoIy(33m(NP{w5jyE1+1n~IExVqNVbGPL5`&*P?VybXP<_F_WCA%^S2 zU`ZPFu%r$-@;c`}%TC&7CK6y;2DoJx-0^sIx?-@fM-e8FPIH<=@YL!-3 z)7*BE;foi&mc4j5+2Ix{9xA>N0-;-%U)gka9+4oOXhiQM>A<|{pyM#^j%ap5UEQCG z#Po$j8!**TcOwIQvB7hErAsvkE}OLbNzbJ#PONG#qJ6@=3E`Q~>%l8ThjO4`;t9v({QETrH;J(oRyVBISkvNm!D2E zODg<0i*GF2J`|IfxWBq!uA=Y-V_td1pV5W}Q(ixE#9kAqdFDqc1uYdW0yDvn9#)G9 z3DtkF>@63vUEk!bPPac>-}cgHb`#_@L>mbrhzfho^hApiB}D0AN3=zCd7kU>+G8Fg z)SXwTCBIgK>xM(8{U3S%`>LY=*mD&f{Wsp$M^tXQg7)5|k>1cnQbulmeGsB=I*_uu(}ke!*U!m_sOiHrGQghW7D-&*KKDgkF+ia^GH~zY6oW zm02=VP+U&s@@4aWC3QCv{rs$>w7|3UaRD!Fi{O34wv_^u8+t@%oZhh2T-O4_?10h` z<+9Y9joGXH4vVP(s$7S=fhrJiMR`r-c4R;{R=+>lD6jbhO(EgPolF#MlAZH`h_L6E z`u!T7w|$sGs;4tZsZ3EIU*_Wq7Q-96zQ~>p!|4n>e5!-HWNV_@2#3YmknLeQaQZ-0 zSuBQdqk%)E=A?&sQ@-m(#Ra>E1k>0!WGY1tPvq}-^q)7iQj$xWSyU>(Q&!YX=>3$& zVV{)qv665*({T}vk-L!PK5fT;MZJHEdqpV(!=djy9a*sN`h7iH%k)hN;CwV*p9HbA zqrXctKW*U@Ryk%uNnkQkf@r%vhJc&Y+}M1Gbb!IWn}*#>aoHrf?kMWpFf{AWbii+= z*wszjaPgNfGnZm7NV*0WQU$FxcxTP&o_OD`hA2CP4y=A!a3MMxDc}Y~OQ$hpx(lHx1;e#^M&9}TUMgjVUBbA#6CdQ+;T$L@g?N+2~wO?>x z**dAX+ZC~~0)(M-qSg(^l0v(V)f4JUVPu8!>_x7Vr6y)ls=V(Er8YGyPuf5B5ebFS z0Q-F;c~@0&^Bww~Ms6|8os@!dZ(Uc_aDh3Mz%HeXY#FHf`*|bKYJ~-KT>hz5O%09p z@X1|M@l=ZMbpM~X`}x2B-cz%RGx7Fq&r@p*>Dgw3WrqY{*>}dm}sZJ3@AQL>&f=aIKA3!*AAzwzf=ehEBhFB zomrWg?OPgx7=^paGj@Dw{rYa9u(ZikKZ(FH%)@8V6M+IvQ|-dc*;Sn+KJvp+)l;1; zs@!ExCF^&>?}_gP@_O>XSN#hI2fbYP+0T?SxC1W$MWiI8TGV`myX!pvf2T&IaOVTHw5bD+XM5({rH zCsepaA*a!tWESNzECaj=oQB=~WZKk@{Np-%Z`4ynx)Xg;_^St?bNQ(lVX;3Osa6Wp z!2Q_&_IRx;9_2=mA;hRjGo!H6@1pa=&lebYA6+Ue zWwYuinj8e#&+ipAWeb&*fF_(8EzbH_cFQ(WD@BZhkllFxGBRx!*v#L?m+k0eQir5d z@5c*0P=iCN?Fz31mASw)S-&F;(kyc<;dgWdAn1;?aIFQ^RG(^ye_RJ#CZY5d@&sjMiCooP=r6-fo>-iH@Ec`HB zk6+olm2r7&RVZSkvX7A<)VmFZued8To}u_g93I|@2?Iz@RcsA(p;ueJ z&Q3HCj4au3!4;(w@NtW9FxEr_KyGM_^8*5K>C>YENGEB+7ku9_p-b8;2fXZEuSNap zKDlGg`a8c`x)D8QBuC!IZtNqyeMGOpkiXmaLg72K<(&692z?`n9qnxgZOfHy*plH3 zA(i`$L1>Gf05X_n)-2J{@fl%i=*Dc12ZgpplF{M+=Xxtd0O3;)LNv%1uPPm;JNU!j z|9W3=R7xsGAkIfG{u9$+M}||J8RgY&)ca5CDdK?xj~gdG{1u$kR!Uzj_nLlUHhK@lvlLJ+|^9# zD32hQNr;apRe$Pi%sc<-^-nNfU}!kQeZpMvJ0O}CkRDUHCJclu^nhT|H(uyP71pqh zDS?^HqbaDaBR0*z@LTRUTCDfsWp)^^#6Pc2Ba<$}d-@@g=cxLM-buu)k}f>HfxwF| zl>`4P3^$(~*<$^Sh0zREhW8IY4BvhfNxPCn=iEf=BwM>8D9u4nDo$`FioNIR$8WaF z{~5&F(;~;~x)jVAhCH8^nf$vq!)-AJpc?znUWJi1fWMnubx`7U0G>VKYO4AF&~=t! zQLgRRA3{P}l$1~qq#LABq@<)px~02YB$Sqx7?AFgZd5v?yN9l!Yk>D+KYRb5{d{=8 z%?A$;ow@HT&h=Ys6?JiZUWfYnkfwL9MWLW!m#vT!w0DT!9NZWsf9yOGkh z)?Kt^{eH8@?3isuQ16_LAJgNj6sDW19WG-TZ;9({GJpJA^C%+pMNyo^`x+k!moRCR zC8;#wG?(~7hoj5yAS&_a_ctEdXX}&C=XEbX=xP_JC>F37ke;Kx9gB-I6i# zF{Cp$#o>!5;6QLNP^C1K@J!2A*VXcQ>#8z<5Tv-$;_sMD&*fM)laM5$OCKkAit}Bdr-&vAR zxCQ9;4ojp~rjB``+}2FatlD^%RIxC*vP>9{G?%>W?cdhcG73;8c%F)R&*jr6!fno* ztneSiJ7mjxddva74CF{DBbX9M`mGh%PoxwfLKsq3a7oPw@9}f^C?O;g?Q<@t5YI!c zu#Yi4qP#;d(L{)EszwA&5RR|O9KJr0AikaaqWTk~NP0bX0zUrT?XOi6WYRz~YwoCm zs&(+xmOBBdlS53z0Vd7ob#AwUR6xqVKav|Mz6WTbAED+8VQ*UQO4CZ4PAi7&ACeg8 z8HMxAf(XH{Ll&?Y`H2k!Id zCAwyF4%MTJHU(g+wkCpPF5!zz)!MXNpH^1edo6<>+{ziiFBvP^yN-jx6FFxiQ>`C- z!4gzY<{#KiJF>dao->2zgmY6Jz=SX>T-|Ss7aF)dBIi3gshmTYFN`T;eV_RzNxi{M zbVE3gvi(;h`j_P;v@i@jWR?4s9|`MTrO4=Vjv5d@jii|Rod$zx?P6L#joDkM3@cL$ z8h%;#_-P)wIFiUG8jMbOl)qhpfLJA2DcaMYIM4B8yJexA6&8`l*(h*a=T)kf`ak}W zMaK+M|14G^1bL1G`cC|*?~-xKZN4$lj;n~@VJ!Kxko_obwbcA=d_S#UT^<6@HFVS% zMt(_vNT%v&`<^f>@jLn=+l$?zsW!dwsc4Z|?oa*pPne&nat0G(V`*uQfQs&zD&Smk zIglziGwO5vPGvCmYB7+toPY~xWUo-S_^h_Jcy#CD`o6u(sXM74zes}LIJ^48gM6Qy zj#Oj>K5HWwIH^=oSr5hP*|=hhD@>T1)MH5Xz(I%*`&eAJUzkKj_4nwEAef&gzE^Mg zqO3kr)z}nRVmv_g=#Bb^h9B1BL<>1Zjl4c2tP61u5lNFh7N>l@39#F*@Gd*5YPr_V zY~7zi8lq-A8k|SLoSYB8&|#mPso@gG#S|`lcx0QKFMFn^39z z*JnD%<3S628zt1k{a$kQHSV8`j7e&?X0l?*bH*43-zx5=nfc!%&zHc=-__$) z3~ACq>S@VS9}yAJ?WTK^DY3DxUDH%)rlO8=q&vtDe?e^cFgBnIpuEc+{0afeBX}F; z#I8Vdo<@x6>nRd{0RsOZOWXBtyDp))XCO=qla9iu0R^lG5pQ^Mt0gahskdYi#Z9HOQ|*s^o7OD5WO1<+xNT zdzNNT`BNh*H|I3vziGL*rI@qc1{CTnxemUo`yQDhA9=7{Iq3K~ttRPqt**pw7VGmH zwQBO}t*!SvSGB#qw`3EeiX5dA>{T45OXmr*J9wq8ET^~7UW;ml0-eAMA{0MY;RU2N z?}uUTeWHo#j{LhSBZqaRAKCUCE2XmHx6->DKDHl})+UvvB>rIPbersBuj)>wQYgZFOBg$k$7GlMBG^fv4bpsF|C<91Bd zbuciw$!hP0nKNa%P}A@q$aQDE5qvceMq24PTrc4T?70F-N-~ zQjpg$t@%RBkk%9&>pq}Xy#L|aer091n+_A5*tlb+JtJaB3hL2k1%4#p2v0X%j6kbc8l$O{x=-N~@@7LaQ zq-)T$)!F&d>^nDRJKI;YjT*Y*1$omxN5!spM{SksG1YuCaYp zZCSDUnUYp-|BH{?7>~u=Zf+csnLti+m6b& z^vHVDBb>1LltY?DM=7)QSOq#Y5r;_Hf-yh73bVcHY~CfVYq!0jDZf85YprlLa#=YG zy`B0Q7h598_Kp2lvCr&tyuHDLGtr_~bMMOgXsErO??~MTJ*!cpM}be((#&2p0e4DtZ&`COqBMST6bT%6t-KCb zUReqjS~ZcyiDyy%`1?E2VLcM~bIoN>ZoAmSA!&$U5152SOb^FD$4szAR}w&sD?=~S zUj|^S-hWr&^DTTS{Z4*#5f(k_8_gR(-W;JICU5x+DFwq2OXROfjDvJmlLYqM$pb{e z6IGTP4Ifa*^UN8WU|iWdxOmiN#w{QsFal?*ddieMSLs?#V6$=Syzb_5+nU0=c03Jd zuibg04?i6ToSnY?4)Dxgp-v%!?g_>lp~jn`PJ$4)Fshz9t3QS)c+4tSGH<&hHn7$o z(fZ9kMC3Uy@hR5lq@te_94gq%|C$i;j4~?VOK*%`sPmqWv`zXTj`wE{ed2s*vqW8? z`+ap!qfBx_Fo`fYcLj@Bt0whC;j6AFr8BRkK2tce@%FpN*W2TuE9&W2hzu?D5gl=2b~lyKvGjmiF%F~P-X>7 zqPSnNP-Y%Zb`K2jw%*0ekvzWz*^0EvChsXk{+tj}_fsQW7-pO^x-9r0D50p5sJ=cZY2H$5_ zWjbbYKD{{>ELxt3HG9gtpv7+Ml2g#7RZRf7#iU)q{EvMFA-?e)n~GWHe#C1cL0H`< zEg1&!WdkYB;Q%RNh8vkD2hT&%p+dZW=(CHeKRK+5)sYd*Cr-#ej?PsOegqrB3|EO) z;ZYa*n68Vq^-vC4B^h)RM=zmZ{nSKN$1lahZ7H0=@9V)>v;`NkySsad^$hPG7{>RW zJJi-%_xAS#r%_`}Q)9&Ai#mBIwsop^HPlp9HSzHT;oq`Pn3zrk#4o{o@)5ye6XS6G zegTZACato4YB$AkJc-p8fV?vpSLjq;WwmrnV<;)x7&UM18LcWuiVX_8xXM;UFL>@Z zw~WsGs31$(Z?jdO_gJ-Ivy7|mNWNWvA-jITuoKS5Kg^?D+7OqdzI&!x<0am5n%v)W zzuCLJXYBep14Z|sMcUz`Et9LNaqK9wX{9FP4mZMniy>B3hM3Zl-JLOk_@P2`|0MLy zShXINPDu~%cdSV~-KA=JJfur_+lI|9Pv6$JJ$J*m>NK@NWTH5=0msmyDEkx6u#YqW z3eWK(Jz&&MOVRBs?Ij@SYVSEM#bOVszT}Bvk^~27N_9w>dRAFN}PE6$BY=G zSaw%M_g?YIQM?Y|W@Hu4Uh04Pm$79N?bWSCgViEc8SX)_ey+Bm$Kv2k<}IvikUinWbYDvxV6zx+NDDum8B-1 z&2%zgQf1L;r5In-K^Kx=GF8NzpuREN^uufOuD8RyK@n^x#K$|J63~}ajy`Tn*br~8 zfCbt=llsEUEB!kGR|o_6);r)-Kc4+Sr}D;V$|^>#R$mdN&FWAgl8(pDCwu)y7;Pw{ zuRnSia%d4k#-O7Y#|=Wo|Hm5Q2W|Yw=9~5i=w1+N5J!5XV`D>j1}LTT{?ByhoAKMV zccY_J=kX+;_b`f3oIa2r@CF5z^7Cprlx=Fm6GXW+?b__+B-JZvuVu#fh4Cme2*^4;FWiqNbx6<9u=g z940M_$WRprx&i7_<5&OZFZ%}BtNRR!q*v#iM105@Ot=3^R-e({dK~4u`OAr4Y7unZ z!v&XktNPtL!pUvtTh5oU&W5CDW+jMqHYVgKx6yDL(>schy(%r?Su&#aEw|opzu)fr z-p)LF*yjxT9vuK|wwva;cag=~S2n^a$z3Nol!t7TPQC*N(%vIgc}U*(=y z57Ty@Y&!aR0tv`!Bx@kG=1gUc{*H#68feLYCPw}>Q9Cbu?U#T0m$ig3L~J_e!z1Zu zR+34%IP-&4ZO$?1KRZc${YB|L2h3a>_^B3Bx{zLk`d;<58V-Gu5G;y8k0rjn38cDU zeFNh%x!>a5v1$dATGiU!;7gpD7IR@=G^_xIB&LC zXdoI7k>-<|5vX8S=dENyL%+HD%a}DEA87B{dX`kd7>3_TYmoj+IF%n6rTaOkL0d~R zIq3=@XiI6&&7Wr(gwtAmW{HNWN}^q5X`g3dM+d|7s3|CSzo*GspJ?{RkQuPkesa!y zlU>Alxak2$O)L9^I0V?wI z&OwLP=Sarq;yUXdoO)5{@lemrAjI>qn_d`SuQ&47f-yN;6-YhhZ8Av38nIvnDg0+Z zCNE?FC){@oG;g&Z-wYJT){xjT-U&4<$bDYPfJ}N28LOD`f}`JoS^W`GPVt28WZ%G} z(l;(LTL&w8rdG!MKU7K$($?AFBh8lM2kI?Kj$D=LA0$7N$obe?CvZG?xHUHD!lHQH zR+{NMK$Yzh1Z`gUH8yB&W0rz$$kX#Jyu-bl`-Y4`YAKt@|1M4g?D0*1$c1|JAi6q> zD)47)^jVAQTheMdW?wif3eKipOY$yeU}a#*;3dI7;`s|c>CSzVuL#T6NHtyxhE#xnj4kBv;3dmhZWkIf_DWviRFVTqfny0#mYbPlM#0FlQ5D51=XEeP zE)bnLBRT8i3eW+hvd-;I{`{!$*>tZ9fe-M+7Tti2uZF_sY}#^=^R%`F5OnR(IM1Rx zWrw1*QKR&59g?8*CGfu@$=xTi*RA6ggQ@RP!haL~#-rKa{9!j=M26yE1?gZyfpsyL zSUVMpKlWDt3iVhhitwT%t&FZ7@uI8i(qbie7Y#QH@olR`UfMk8!%RW_g`XJzWUKCZ zOwNQ6iPWeH{bJE*rJQ0o<^@aw^qjXUY*10R(B7=lIom>o}-%%OFd zZMn*SHq!j^g%KJN*G-qX?Pr!#x4yof+yzW!+qsRzwYU_@g5Js^d$lXq3hlP;^p$X--7B+wcrP(+J|F`mb#?@sU_gI5B+8X`o?f1omZNV71B?&jDnBE%EcXw?&G z7WZUqMTK`5pjna}MDcoeERD5gjb_U=(AsDtW@>EL>j6*W1NcThkox^eZw?#4K-q;1 z)*zfB$KiC!EKX&NgAF9U|Df@Hv7Bo@qK$H}`bk)v=DJ`-B#{*Vzhl4u$d>vSQhup0 z`rFE}L)XW`tfhb*QhfKQ5&a#y@2f?bp08?20%i1v8(+~KEp*%yr4lZk?sMesVA%%U z9OQc(YEQ<Gh9b~cYFRb;8g(5o8DP&J|u&8oU_cF1)aD!`1-_p0v6h8 zH%*^uLndP>4l4q&Z^Z5J*oGYKM$JWh&3ZfEN{uO3F)$J;<9~z4TtwuQaWXrXFIxEtF%t zN0vz*5Q*eQLa>DIzVip)*eU(h=) zhaoWSv1lm8qeNKozZJ0<{ZIpX70&ZFaIDXqHg{@QaC_=mYG#LXzE>iphMfN2U_MU> z`Eh7RP6Cf`X3FYI>**gdVYk47xN54jy1J@qR`h9-y{Psb%H!n@?!WbIeUmUqucGil zJ0210LOBxhySK@;O2JWZ`r3!D;v2V?qKOx<>?-pcmh*euWTFCfe?U7uDqqBvaOdted$A zb|Y6w-BDe)r9cPQK~{tu*Mj#MWr_WY1R5%^*M<3g3vs!EkGanMR>957YkFYCj*Fz}n{~;YlklV1yR>qp*X&UsO48 z*r{}rZYcN96Qq7~_tLmBA&8e>Z#@s7d14^p25U<)U~E{H#S@ZAQ*{Z4=$6} zt&bh@5BBbPqNEW-FaF?b+i}pFXpgbz_2K9IoKMH1m&L=edncFZGRoR|996oypwsCU zUaG59SJ7KysFMhm$78x*>E_(mb@ssU^=!L2`7-*T39)9?$q(Tl8F$wlsaweqbqn(Y zzp3$ECrPqGFfPSxo>C@a$o#fqZPvasmAA?#H`T=nJS}0xI(U)6M*(7_n4-^~T~eAp z{M`4S<@*sQ@?Ac>v#R=-Tl}?LB6|j7xxn#5&vEh~Br*+B(ON}~B`}HW9G%Pj z53$KjL0yzNPnG_Gb5f05dWewiII^)vgxuUDv=ywkhBc!FYD}FGJ7Hdf$r`6GB7sVm z-Dl0EEUMoM5j-sdWza4~?=faUNrbEC1?o=arq*S-8fx&M< zI+{qi4L+w=R~40&)}K`cM46Zhm1i=%`a1t+;zpnB`PJ%_9)MDCj#E{a$hu>kgn2kz2ex(XvyPqLVOG%}-e zbrZ-wid58NLaUO4BC&b%#DmDcG7I%UtT8m_*g0d#<8wq92w(I>t1n})3#h0pXFF_- zei^(rE-?Ljpqx#C?ov ziNktvI+Ya;f1*5<;JZU2BW=QHEEklovf|_jM@^4jQC^AicOv9gzl28&hVB0=%!1) zg8^cvCb{y%lKwe&J)%SI>tM{@T5g%{fF>cZLbi2VTQIW&92jZE81-2x3H+t*D?&(H znWeaqzp{E6Bh7UMij>nNk47iRPX&PUQ0~sw@IiszUM_ZcDvSl!^Kuuo)R9 zn<4LHfO=D{9%fp}d2_5z$*=2%q;I9+B*LW_v3j5?$OhB|nFgrvfn8r%#q9EC_-Q-@ z0mKEDk3qWgxPm+ET(@^Xgn8X(mw$F`izmq0vT5po!ax+hT>ApIeIW1WAb=?+tJ$gv zKsm?{r)NxJEcy}5S=3*pG;mO@RD#pohSlCQ?NGDvL*+4U;pG9$P0!CiKm0EyMgO!6 z46U^U-!b8a;4)|%U4z=8I-l#yx?9A$Xao+YC;~2yvie@}8q7^eqCnL{!ZzSFC~nU| z7SM~FTJf=y0A|Y}iJlRLGVaa0;)dYI4$_>DbgMuA9Htd`K{5xnr#b622nDqh32c3x zO`dN^{qHH0*zRj;iW$t?@}S4q(%#Q$!WaN7==Ok8puKD~@P*3cNM*R9X6++NS{+kA z@h*Lh`eCKyC=D&IYB??IW3n6!gU3CX?iiWyS4IXD;Yf?JgTPTPgYNE(9F-t%+&v;~ zjESF4)?RXmDtj9J8_mQiTE+XhxX!ScLuk2Nx_rt7&1gIUc^nAA+RuD19(I|Q607cG(5I{8_at?}BNcHY`O z8)=r^GRzsLp+-oFf4c2D!YdX4m5G5~OP`3_5@7iWLJo|U)^%n{Y3#Hv)SFN7x<#vN zsX;KB@Mag4iL}WSXO36}Aok-dP`^A^T9c%9d*NRyzz=60(V)o-&g%^7fxpt3rf#Vx zF#eONa9Z}V)$L6N9#pm-VdnNqW+>$cgxi+89>c(~YavoW2K z!mt{Ej#nM(yaZOz8h=+YcX@;=J+HYNw?R|!{eY{I>ALM_Y4&FPV)1Bhy`AhO?fe6F0`(e2~)8-(o{=U(#ejbg$` zb3*dTT42fI_O0wzmWt3dI^XVXeZA?NtusHxsjCXr>~LIPf1`}`9qLoK8?p&E5^+9p)L>B&_U)k6K#Vk$EH;>FAM8Wp^R<$&!ufVqfMOz#+_Q;zcfFyg z-L%7ervnr& zr|6%Q`8!b#G?TB=Jb2<&t?~WNihhYwQ(Qeo6gIxK>{TTl`DYC!@t+QXjDXx9grnA3 zAMVc1`vHy!xtg__EiksIHZ9*ITl{9ewG)ObZSq+0O*p_2EAn3}^a{pZw%i^t^0_A4)aUDvEV^!iJS7FI zDv&bA(UgpZ>^AQ_p+hG{dI2t0)7F*!ybrAdcz6RxqD|lhE9m?X8-eUw8&Es2TMeM{ z)w*_?AzUH2SPgiO=;#27$Z~|U@>Q1A-l!w2oaZ1_(3MxD8r168G+0Y6^xb~}WB{uy za`K(6k^!`yjRnAH-O;X2J3@+A;%^6}FM)q^7A%Nc%V@T*nU!@yT7~dRkXCWVr^iv| z&x&L;3vFOqe2Zgaiby&&g}#+1rKLBwGd;y#Qz}b%rCRS}BHQ=V90HA?#i}L-Lvnmq zKev0jxV2sBCk$_I>(;Jr2IV~+@bGq2JXJrv;+;#&KR?2XsV->N4R|a%HgA-4uU)#i zBT~q$ba*_j4>7M8y*?&HoilXhS#5rTBxuq(qyMI12qaupMkv!iRb9K)J|oU>+ze5MvO$WLxi zUTi~gn&Hstdy+6{M5utjHB{a%>l}V;B+aPP9JM6MdI-;x!o8jRpJ>=#Gs4+q`>e+j z*j*g=9VAmz^hy56p?pY5X_rEyP!5Upi0*-B(fbZ7ky1>3S7?SoV}~4eq|r$?&#nHo zS4~HP*YvJ`bLL4C;2C)fuEDh^fq!5JNtG;ztFQHuI_4ZozmdNZXTQONl{z>i|doK0n$%NbSr7Pu{{`lnR~V(%`8 z5ln>T5h*w@k~y<1VW7C`goq8{{nXy8HmeWX-u>!#*kSGYe&l{<(*}SaXHeSvXA#|* zVH0_3e0YY}c5@CXZw5Bbi}=uL8|Q3X_{k|?hq<~stWM#4!X2y5O+EcyM(Iq5wH6s+ zl~xVm4NX4RV;a`mR9PMM0gJzsg{5h&BEl?n5#>M zTc|8;4hZo2cdD&FVIY$lp29OcC4ekxZ*&tmS5S=q42}}laQVsoBie=w_2kfB7(>&G zv^%=T;!_U>)?)k5G8+Z|R>=>sLZ4W=dosu*zlda^wfDmGGPk=PU{4j5_#Xco;!eU~ zS4*B7n4(Cj8r($1zXgO!50XPShoO-9a2Dr!LLsYM;UQrUYp>AmB1TOQ`?B&JB<)@;C-c9zX!`4o9s~sih69m29 zDAnx;;zcYt<5Rl*%rQi95v}V^(kw|zCIgb_?_KsZB0V9qzj#DHgdiP$v`urUoUiYC z~2y^gU!gE6LIth)p@Xp5NM-_}{GQLIbpzapn*do1{? zpTr?7`MM3qhp3&%CXTY^8QoF+0?a{xa!2sx{Anu2di}?t$oI+bkKF~T>~)_e_4Ik1 zJX{!YwnJxKPR!>l5kZXp_>1M%LZNm#0DDlGv_5s;6y$ z?#K2&_J(()G_6k8$D8L&E8ZQR@9k;c9{;q&eT%zc+Qg~KZSaBd`bL8MqIiLNLUC&E z>+%J|eyI2nz3=W?ZaAFvc~_&+)$$}8;*bDkHGCR0lTIep>y{csBwxu`th@HSZA-Y- z=Y-kVut|Egr6Y|lsIcty*{v`xz8N#gEHz8~rO zUo3Z|dI=dRvU5c!V(B?KROo5m*4x*x)4AaZJ%5b3h625R8!Z*&p*)63(~j=?k-z(= z6l>O7DiPj4{&`r}SU-D2IS(aL5pBVvtWzAO0?+a8{p|RTJw$B-X(z>+z4x6#JPZB` z&a4He?x}x>Ehb!VAYLBu*ozeryhwHHXAh$lFGyBx5N7%p2J??*e;C;+M1DaDBfD^3 z4THTp^6?Uk^N8xc+(6sj+u3fo7}66p6gK)eHg;?@KzycNH>4%OyUE;TQ6D5qv>W>6 z_2X15x!-2@1-E;6oSQZp=;i1eeh0;~CSI$MlE2?h-Q}w-WMD}VtqFV6R-;&Z8Lm}3 zyF1`0@7mZ}@)aSfeFHzb-ZPH;uHupu* zCE+FMxVA6L_GbF8-S871goQ9C#xng%f;|(bZ~%kkF4j}p;4s!D#VK0(vwcm;Rdx%3 z=LzDd97V}~ctg)I*8dOCj!ZEwlc1!0t?L}SR46>0pzz{8t0rPagIHivO#Sk3RWo|a z1NB8f4Zu%KzVW*sJ`_BpH{PpRXpTtrVgo4*Q93JL5oZ&g(D`aCc1uBEMD-_|3Az8@ z@yFdKH3`4XIjl9gqvR%MM{uLsuZVAu(1AEoNLM=GKa`*?ccjvY2t);s6%m` z&%dW}zScdDxqM562=$%H#r^8*w1j!3te))ULV!{I@%F9JTa0_%nR1yXstPa&1=$yz z!{x#ui%+GTNq>l)Cj*0VrZ8=1D|aWkl&w~vmwyrjP(RRfj!M0M`See-x2J2{J(S+6 zc$|-5NTRm~tdSM<;k;Y=4G$6si~OQfQ+EgW*R6bY_mXWu9rEYV3;=O@98dQ5CvyC> z&54D=jp+U!#Q&|=m`kN^bn;o<=W{ud68+KDh@P~gkTy~td9Wt$Wvw*l&{NKZU~HKC zkc#5iQu4TKfZ{06|Ik#YL{44@Z!bHsYC4%}`$0=&7%EY-v?lm`HIryphZTbA`Le>oU4?+q9NX z^no^0g1A`rb3gqSCOiJ(WtD!Py=tG z@n%A`vmQN1&Xf$VSn(m_{;=UPYmYtwDi3^ZcJp0+;WV6$$2vGT%z~TU-e5_pE?TT@ zW&e1Db4V`KM^av1^5Vaj!n;po66qUP8ia3kkHx3@F|1R6EMz?XcD7) z%_bO^EI$k6dcCLLMh@V{m9?KXxg4*%92}ZmGu5;!S$%7^JmlZkOZrfFUU&2t30-Tp zn9m%SXIRt;N!64;dEAg3;2PTO%OB0~?YscJXGJ@PCBpT@Vd4U&8xc z7qJ~oC%B*BdR^ofK35RjY_ll9&9JZT33zD0$ktvsT75CY%;&2smXG= z&6E`NFQ~pKtMs`F&FZ2AyP?297PeAki5=~E4ChIEDl9rcIy%~SSneiT9I9F!jbm-7 zkziM97DvS(g+W8|R+j^{G+oRyDlFo;}^K>OrrNIz{XI_S{elP}A9?nKRrvtaGtAzAhmf-ZKz z0(V^kyl^EFp=-J~DtCh03rg7C75)nFl=A45+XgRCNc8>{Vrqzb^Pb@O&4qA-fs2-+ z9+wDS)Vy_6vZ&ElQ7J(RME3m4NhP7wwLt{Ky&hSqfFyx|IEBCkkvfc6GqXB6A8svf z-!0dhyz(=|`{TA7?Y$vGjc=T9=A5n^tqO!2zJ(GEusMvNpV_+$@7sr8=Q%ZBj7DX%mOF5dOuT^iZq%R(|q_>vtvU%Sc zjhki(5Fjo6bV5k2wEDIuW%V3&f?{h?c8{)?jJ-Kdc{F%W@Y0yC*V&uBRPZpva#s|s zT4k?Ca;*aEVT8!7L7&9=0~K{~I?J~H&_oiFs{Rka9K!29=QsGCQg1TK*O-JQnEp0{ z(mi@Q%Rw%I9U07;L+)&CPz4{o>{bMry4u}M0UEXn3KRZh9*Ldmpsa!bkAV+`iqPvh z5G3@$ImQ3(_pb*z!-J`wdys`7dF{L8f)bP7cuMxOW0f&bJ`ARiodPayELtT7=_v&6 zVtl9}d&4GXXPs0rbD$yH_N-w{UF%ZeW0N+BaQnvUaK~}F?l)2F3WCIRijmc+XAWQ{ z<47avWyMgvXs{2a*j#oIHh*1MTWnCr-x=XZb?QI%&Y!v!8_BtOPIoJp%0*vAS@U!k z4TtQ7p^*C_EX=G;Ba8R~%;y-9i=N!Bl&F*TbA8cKnkzCe6D;Y;v)gf`R29`o3K^4k z|8T@;Qa}?mX6#JJL~`_&-(KL6DK>w5Oa6qbW*y6Q-sS$PaSF5|Qm&~e$mexaw$_U) zzQ{mX?Y4>Agsut#-JC>7ff@FuWhZp3_c~dx@HSZr(>#4D;0UoqJQ+7;MbScd1#Nar ze_k$6CuACa2&mqwP@!Loxcdo>Etn~}7RzQV5@Lz?2=w`t2jets4@|SL_1?w%KIo2C zCSr}F7<^Oqyb<4WS+DUAt^i|<6dlFw7sWRehZ%!e(HJ54SyFzXK>k$alZf;q+pJuL zEiK6roA5+&|Db8e!p}#K$xwe4YE*O2lx7O!c!4ABmDV`^4qQZTOn)~zK8fSbB7dJ^heKncvr(4V+=Qn)s*G|uo$SZylsufjN+ z*9W2d0AFjR0LtPX*dHncmJg=PXy!n5cCwQsqz?+(v0XvgdIKnM?}kB6{$2?-W*b3D zPrN4e2KCNVWv&*G!V;1qr`ZueYi}~o9$tTO74kNjL15FZW zo=>Su*@b!=3?f{t?iDo7TW;(AS4mm+b?VwG%Na7Js zm-Ei#kYw7`@#acN-5OaZD2)6Ka>{u!<5U#*f8&5~BPK>h&bqb$C{NwVMCnxMyY+#Y z%rqBo(R(EkU+Y-S$1p4#*ue-GD#QVQhum1Kj zf%bwXa#0@yC)Vp2I(bAIY3|H}bd$9#BJ2@@_e07#W&Dqv9|v=CPys3DZ6yZxwnvp^ z^-;Eq)lAWZLSd3aYy`o(K8)BjmFDkDie;>c?@+q+-yQTwyh`UU!gyIJ*5Kx6LrTw% zyflhZYZAE$fvwJ(6~FxE0?^{g2a_E{;lZ7OqO9i`z87C{5SA)@2);vNUK*BF42(pm z=N^BF?`;frEwaeHE~H`EisTDPa%))aYriXic8^3#-!iKwJ#6&?F?ci6yYOd4AN>)W z^#%q_C+`Kvu{m@YvKUlyYQfBs&$v#{hXJn(X$9gw)ad@(RMA9P0GFic%iZ`BJ`o0C zBVtbWCwVsbLm}FHLP*6uCj<G-)3nptkD0F#*p};e!lSkiA z&zJ1i6DvGxgUCpk7`nh6PWNuR!yr?EI0E=R<4NOK&%_t@hJiQ3Cx-lz`X-TLH-f|s z2-j;ai}BaD>dhPOKPnbn8(XHs#WuO9yt+hFS;>Bf*04W4k3@W@8hn@o`>hqwD3ZJp zz;?16k#^W#dnnF`kY#LkT6}p2p zpDCV1{xn+&=4=E45)LziJk*~`rM6bVjM4d}dCT&J{GdYC*(`_amC*p}d8I!P!f$z6 z4SX!*Q@Rht6a@8ry%V8^BEP<2Q{(B44(|tqufLECPnaN}kvvamvgdu}+d-Pou)TR0 z7l(C!ZF&^pM5@cVGMasy_sap?E?bvh`!%tEl8BqvC&2$!Da`aB2uQhoTrQ|Epr2dr zfPUj{(RJ3cb*4f75O3DSLYl9{@s$Gty%5^eZ+!D^ncW9%k}=x&vQcRsTMWG#C;pMZ z(b@nqJL<fmhz_yAR0gsb{I4Y!_|NtJyp(AOSTMS3nfqJq~3mseQT` zl~vrw=mFgI#Q`AnD-E=fU1Z-G?6bEbL~q4Lpov~Y6~BhmKoHuQvYLM%W}jA6u{ z=dXcv&4S^MF>VWPFM=4JYfro5|Njx=w(|4fs6aN)^ETW@RJSXkESIb|*-*}hoMZ2J zLIn5|9&`HXo!7(Onrz(*lX>EA*E87(BsKyJor_#KN`6>Ap^W5V*5q0{oyo=7lyvV? zWaPC*5{|EZSg^0i4%7T*13O`CDoJ|=>#5fqls?i3uv4G0Sp|Sd%HrxC+ARmiWMf!p zxAcg>cG1dR-9o3TV+aLoN(M+NTvp0Ye<%Kj6<6g#?rY=+KcM_2=&q567@KT`;RgQz zZ4lFxB#=um`S17J0y#9vPWs624u(Kq49X#pxFdG0{c-#U|LCf@OU@qrtSt9D+uH-e z!2!8>nwDfZFY*`uxsTq$;MO5!iRUFIIB0%40eMaZx+Z+|zQ)XflZ<}yEJs2AhCl@w z(*AT+VfY`e0@ikVF0_)C8;|m@Ac9f=i^LvO{oY#B+uJ!vNnh<$Mj{96*s?l-CU}v72z5L` zG6S6fK@UY}DZVDyY~33$p>lWDoScjg6H(nL=n(c)UjXVZFN&gI`=G` zU0LTUCqDvOBf8RK9zMm(m($&q&Zk%NW^mu3p}(4xJNmJrtjGB?+U#}ULkw<}my{yJ zpB^yegcf2aPLajxf?%m+roA~pVY`T(K9iwO|PG1`vD&$+V?kPd;eRoSTsO? zyARWqtr50s&gPzCJrKIT-!d5G304ei6@l?4%aLjX)&W3;47k{fps29ByEQM0Gsv;{ zlnYI>(qX9bVk|BEvrl>&x)AI*_t*bqP8gzZypM%Oo#ag^=u*_rJ)xuG&XRadRIZ*v zYAxoNh9NZ=6H(!Hb3rP|t(d0mmIex(4(V?0$UUy)Br9nt?RauiMRNar5TM}yU5QeT zkY8+}GmO;eDwaJeV*v$+dr{FxG%|y-K~9Y8B?3s zZ`@s&rs^^xLcPL`<+cb8k~K6P7TX08L@~2!8agK1w3>x7A80Gjh&y#gRO)Xo$=k#E z=8coFH?3xFuFn)Dn1Nl^_E%XCl0h@ceSX)%y28Mf1(z9Xe{EgjLy4Q24!nzN(a? z`1{ogQtew0$C9u0CzPt0>Thx-a;LTvUucH)lraIiL$sUXV- z7x~eq&qEKqTVQ5qZv`9q6?%ljUBLmZu6n_r|Hsx_M@8B7VWR_s4C#Qhbc;%NilBgW zNp}oNw={#K(t?DvbO|zmqKI@1ol;6m%Mj9WHqZM$?|0UB&R?$OQWxI$z4!j@D-S=I zensqUwPufezq)XdeDh`wOV-D)(0%K8zyd_CUMyMsi4}nigWL+;_IY`rI>mA$PSTcAuIhBMirPwN$T zX!5=>@EBA59qu%hd*fVxR74 z^_aZ^M3Ux#K6r#b$axX5sL~M`YWc9&m*$Xq9PsFt_f!;_6>cWG3W4-$lVSA0Z#N>< z>IjA_u7aPpJK(LupoE8nr(yZlOiz~J;#9&-rmFs<61!$-;8y#93@Zt3h{V4;63S0j zYjplWbq*#cMYC9N#zNhdiHe$(WtPi{wXbw6tf-f~tzc3yXNxIb<}Xatjr z)1;|4XH_qYJ$5@a;-IhKjMS%-!JH&GEz|4<=S;t{RS$-v{3b#2Ckkb?Ne%sW|Y z+E*pLGsUV`?Wz3$X!~bjTX8@#+~GK7Z<1-}zCFQJJUWQe-tzz>M z1iw^a2Ac{4gYT}+IoGVpYlekE-S1n3Na#Vhm(E#DB+mv{w9SK+bbkDVGHW5du6eF1 zT9O2XxagYc1QyQFWM-RR^{sLLW&wD5Jf~eBS%cLlUQ+Zhz+_|k@b6$ z+Z&=WNUlMwud6%xXM;dqW7FrMB}ZCT|E7RP)CxQS(h>oy+M>6 z;p(_xt^lfiPH^tqe^y3GIZRAM(0Q5&GAC&U0a4%N5bk-kblBTt3w59;58ww{QRuz5x}QNSR6Jg=^e*W}3zV`T7+YDCv6rnoEIQF*0|WiOnYDDmVQT07$A zPu*YDF^Z&{bYB_@6!!{7IJ2EaTr_MwWovSNMQ*;@`r7=Y=f!TgPNNbV>BOmK;)eH%jH?gvKHN14v zr8K4?bGIn_?l<32f2NM$`N!2P2JupCncb>l0n3S6QH+0CHiR;W;q^0$`%*-OD;AA&f7D5m${ z6|x^IXk!aAKNggh~*;z4O9($mzXS}?S|6sd(I+svU{J*>D_3`qb!{FU4 z^nN5Yzttnei)ilp>R7UCdFBj;uRJPU>W;bN#|}pw`4pS#JZpaYA0M)^>>=G%v3U8M z*c`DhEg5kS^>cGdiCO%>osSG0|FLiU@vE;|LCF;Lbqt%mz$6PxRK7ia?<&rXLmw-1 ze09xvPrNA$bE3ca3`gzjcw3vAF=B6Dw#2?W9L;sPSJhZU9FRQ1`ttzhix}BI<8Wm> zzHt@x8Fu(#zDXxXE1n?$eNmWv%DUp;Bn4NUTO+o_Fyb)a?C-`i)7?ht;a;_e9{^!rYUiYdvo#l(AKg{hte-f7&atnKmlIsZAI|MLL< zGcSX)L5`4{{2I5Cyp{M1o4l%V5A6z0L`2quwcOBFfZdQ!3f;o?$p%Km1rUEQU^7BQ z%YAJzSpZfe0{IA{p0fH`_ugtSI7D8T1MsNdx7dFoD-`Awrz5o(#VRl#(??^MNlGo0 zKm_pxofjM$IbtspzR^IIAx@ATFx%hmjAwMwfv7n5pi?)v!nRnbJk3s#aHQl;3ZLY#?d<{-XZ8#dnd$I&YL0*EVqt1aCIXPU3^a< z5zKO7*HJ9$FXoeBDJ=7}KSeh)zn^a0+mBUG`V7+Zh?{o+K#|UX{BrIF%zKD{!Q`Eg zbq91y2=L;w;3%-ce}@9>{y0K|MzwSblO}vC`w=A#y8B+Z2F(RYfKO||*u&C58yj=? zZoDHjrIZbG-A8O}-&-17#A62Z`kdpGhA|^g=pF{%WzAn?RbdD$aDUW?$Tgb(!n~FL zqvwA+=f6YKd+8yN2%llwbY1yVl$x#|Ct_lg__$&Yz$#xuln{B>6DVZOrv7ZwI=;^E zx0PsQockJZEegwC0-YC5oGy-mpmk6;bEJU>gnypV;uNR?BLNLG<^3C!2Rv;X%9Afo zvk;*{$^d-b70d#5UWE6nk^MpdPP`EDA5axOb8?-VT+t;!O#LwN=!ft{=ovfJL2_4Q zUJ2xGgV-yQYv^9mT?;LKI}s}iv|dfvK(?j*5BqR=*;0#Up=`!wqr*{Sg4N9&ZnL6^ zgvVJSH;|{-lmRKEc2pMW=`)?np!AXbwXwuy-;()h#-h2at3nJzL0Gk>OaOj zoJ|QdDnHtfRKT9ocS^o$BY`uXXd7!S-17TNvlXoM5#GRLTl2rAL|*FueRBW%oI?y- zp&-#fkmQ5r#&ud8(hW4Xwt)({Ti(;pIiZz(82gBnAq*B2chd0ye9AJTM^Esi^L|Wg zU}G8pLT;0{4EiLq`gNhNc|Xr%quRDGph$rp*kx_&B9PWuOTWdM_id_aQ-1AFLgjOj7W)(i7((7qY4c&vVHqhE=ML1RQ!}< zRIPnvkKsRCgO^)^%2*3;n&8P$e7Ir$rr2z+yEJp4XjGkAJE`41T8iy#ZSiGElFW2z z?3Px9Zpw$4=jrQ=x@BZS1&PVpMM(+A$SvJGiTC7Fwa{edX^$S<#xefnQu$ze#>j_W zAI+aFo`$4R4`BY{D{PR3Y*8S!D_A8 z;ixsu+b^$b`ci85+q52k95KP5E$!=__#+p~mej%!Nyo6+l_zwNJ>{j8x6v0g8mDvb zQN@1HLO4~$WT8rG^9}w{9$EGDp{waNm*BIESA6qW{0;*|O{aNhEJV`mk0E^4J7a4M zC4`p_&gWcbt>a?F)R+C4Md=Rw+Q_Vzh`j`)AXn#SNPi!qoST&t!{pPgSyhi2QoJi& z013i!-RM!Fvi;ymB7114_+jcGtx{n0GMGW(rOLmTxqnX>#0~gzNCm=q-T&-xdz&(C z_@`~EY1z-4o5P#(z$UCLwo#Jrn39%m&x3elxZm$6B{)3<0vL?Oh(fW6?#izJepc#A zkfyRr!Jg}fOMs_8ILet5V0C}XzEae3g^Pd26kW6ol0|uFZ6GnI4<>n=Abun3)mqai z{eI~X5<3)EU2PEylf&`6B^Vt_)AG8&LiKIaM*_2Hls$ z4jEsi!-Ui(a<~edi|s62`@ApI9m^7bl-Wxgy%y%I+3AY+WnSJ>)vG|@J`D&F;n7BS z7iB#*JM=4(X+c^N)oZm0$t)GlDX%q9^TPL52F+=0H6u~HrG zzO(sIcs=p_7>`=ri3z&gB|COY$RT@!#e}|<_tC9`KR+dFf$WFkqj#U*k4IaVaW~~A zcJa9+r#-$8f!tNgQyTIob|+H{^rxUGmU{&{S9nnT;DU?WFX*>)!r}uY3gY|vsvwJ( zPOAH{v{;fz!a)>V!{Dv1Q%gZD74vm?OEs?)Es8^hhUGD?@9v#^dHp`b=TEoq=*w%< z6k++|6$-qxk`>G<^spynq?s-uD;SH`jVSi6DHgdqs_>;GiF=CEww_MfJ~U>!y+X&s zAITU}?{v@V&giPhqEXHzFtx_z=~rcs>tbZ3H!D!B+WEDm{7w?ToS-R_1gKMrDO-ZQQ99eUIfuRUrL-NTT6IFfH^{6*)(Y% z&~J0p&WAgnxq9i|RrBZ%f!&4@R2V$F+6UH5qlpwl{|P>c zVDP@{>sCv!3Qz+Ke!Cr1{fuwlzNPdF0wcHW*N&sjAA>gbXU#5KH3NPxWY2+DH9>fx z3191~*Zfl3R?#Q?E2><&eI84TD1h-1wd^~uPcMVVx}X-)u8h?2n9D% zcvu!c`J9+~bSUEwvG)kX^d*U(XngBZm$*i=1&}7&Rw7An1AWx{m$4WyFa{rs z^IZd(O)S=UeKTSGV>o#mu^Tszx^}Im#fbC{3`nk>r z&{K80BKdMZrxp2YSdpHd@^vVA-~AOu9i5ZkXqW1T@zh?JKooNC_ZPcQn_#N14S-{? zWnAZFjc3rf8nKVnY>Pjh?)cdS!)L+di~Aa@xgrNw7W;#5F(i|cm4gQ_+U`x5bq^$w zUc$5b6;{u_*~@GI;mu7%2zoSv!D+@n1-I3}cwp<~%jO4%j27lLM}A~F@kW%lLrl86 zNa&JS&E>_JF{AIG6|r~{n}+n?e|zS}$Ow?cax?MtPfPx5$2$=Fb)Mj;0?Xk$jPz#mA)K zt*=4TdLiiGW!84R$F=RtuTQ`IXbn498RnyN7#7S$82sjLJi~M%3skEpTd0nACef7d zS^6@RU7N`G^?W{FtI{v(0156~-nQi?V^2~YpNQz$ z`t?W(hr%GsbZ#G;vG-@R_I^xmhpGZG<)f$Wo*0+(3pi@A%LX(|t`a=pr}g}H`(BN0K5 zE_%TMJZ=tNh6kz|4@@Tu9!V9Jcc^Jk*BUa%+01e1)g}8w=&lyv9vzGsocTGwDp=YA zN#1vK3rmK`9L?_6lWl@JXv+r!TNdv|>Svs3MZ-^+BYGa#I|j5V9euz28you)5NTB2 zv#^X#*TLxfHLey*lySE#e`rOSs)@@drw2N^yV>AhkPrSuoHtlpge=y;s&4E!nu5gUc{spQ6`O`Mt%fRoscknlTtHU<4(W3-> zzfNgQML1>zeZ|CE&DgoZcT%Xg6{)SIWl77kJ5qin+*e)yrkmDG$d`ZlD#Q*~(8hO> znsM2{S{%jv`yf13`7}z}>`ydl7YDz*UZ1+!Q7F$PCl-08Es@*#Fd!DF(&+QKd4JL6 z<0N*$NO*@%>Wce3m*4@a!F3-fXfe7)(lu+V*&FteQ+zDNYx!~}!|Tfo&z`~8PI6Zv zik_ra-+<$E(r{&RNxazxDRTeb1Z-e`;$$(?Elx&6T|VBk8YR~IkL>DeHSwhFA@$;? z0}#Owt+J!u+bk9!dj`yss`Xk?t4v?fWFmtoviDaYTdrc)Hn|CPnKgF+knqWD<5||c z;}wz}5hCSAaIvc2|1#}52fz`5tGtX=`ay=vEBvFbtD){hR^kK{EF<<7p(_ z-UgW;SGf#=uz(gcOA1UR*68^$*SZy$AtzqPav@%vf(d|ji&E0tMEYg%kB!QBnmzTbiQ32|!2V~f zLzNg_%v$)T(R-*`ntJIODn#(Hwf=a1Pg7lRA{FNZnM%Zr8msbL_ASB3Y`%q! z+w#@;!@nQL(FB^w0UK_O*vN&=XFy?9p(K|$AK_cjQY$gb?|ICs-+Sxxm|0GGbA~wB9wQ+BI0k^p6);Y5}3XX zX>C(f-xW1k&xZ^dnDq^p?jYUIB^=X3rdw&nToWi>Oj`O&@GgeW zQQ8{d0osx?g+w)|AF#o(boTS2?-}Xi3)^M>$eoC*?^dCf2W%Xn^QjlYYpE_UY|68gs{2<A{yYB8(k03(jJ|NlF0e;Sad;a)f+)gmB-3=QgVq}LO+wzv_a?#Vx(-N z$Qcv}zAuIkL{m+93(k_HI^*Q38BY~+J0*k+h6gS)p(i;5=*4>yM)U?=8x|KGLf{qS zdS@OM#Oegy>#zrOeL+CVD=g}@y#$t%vqKITNBJddLTQ-I)<$SXzigfaw!y_u0x*d8b-X-)w6Rsxx!>uyKtWHc{r zKfiJixY16@KD5kTJaYw5iIG1d)W9eN^*^{e(F*v;KnkM>ia&bc zx}|SNYmsZd5&&O0oLiZNmcl^%52OFE?KTT3cjG~gf;LW?jYzcJ+O_w7km%4C;&|&l z*W%S{CCW=GUw)hVC_5-`lGKY~EGAIY(A5S!=~MvGQi=9l2tLX57)X3~TL&?jzHX_L z4^on5aPc9vL^uWQgaW+TYb*E7r~j^xc8OG1YzK{)77q99zixq^x2f<#?UUi+%Ow8z zFd`3)V_a<|ZeKZ-290b~AGLs3E-JjVDi&SWhDw~nJ(VlD%Nu>N8t7Et_)B_7lVRxH z-j}td;DY)iQbfc_PRT1sMqSU?SP)`!jaFan(VP#@TNPC%%!g*dGIRB(^1RxY_h?lxH(4LQnit3H=%Eb#YjJ^ z^j!H~-KR(y2P)ss`w0xkSIl%24HttHkfw`dOxo%(T1C*Y%)X=Y zmitJJ|2t;j;_%GDgav~Pj}&yc8Aau_Ss!;HhPkDIC)utd$lG}Ah?!riF+|io8CB1c zn5rNPf+Wa80)kxiOzY(D-hNS#W098^w%mk~voxIn-44&aA>)l~qjsm}JkpGIm{(C2 z*0fGCN5HjeU>+2Abc$(&^;h}o&3&9`ZBE_% zkT(%$ealjOE|hB@ek4mTovUf12EuSjqbnHuqa2h83@pWGqug5ykG#3gTv&N3pwTCfsn!Uzk2du5#GBRG86#qt zFMNeTd`nyTI@EOWy7Ls=yZ4{krp8NqSBD5g7#8OHqV`(xUGICD7&f4XdvafzVUNdA zjoQ?zZ`pIP4gt6$kRr$_zYGth{wj3`Xt)}cjS0Zv&}Q zgIkoAn({f5i~fGg0&ANKNwdo4LW;zSSD@}s|j$iB%KKY~l)o3aK{ zymLlh?@9;QO`Fzd?mXO<@`8_bK#|smi1|WzLZ9Q&4Js3htFAT6ES5*QG0*mvd+NKO zd1)-T9iN$GKkfAyeRB9Qa7+}3{a)wp>Iu7VHv2*1l%1KLI86wB?7m8C!mxAiJK=mr z&4we^j1}x>J;hvF!smx2yw6SLe@~s4*3<~dEL92mYdpB94cYUwsAAr3-~q6G?yfYS z-@!B5A)CEi-OoWwN3Gmri&zT}7PQgxvKU6o)z+l>2N)(C4Y6C<$7N8BvTSbxb4Aer zo`WQGP~UCm$D*lQiTXKVNedxv%u^2)+!twlgiF^M?Uk&#ij;|Q!nmLTiA#&P<0;90 z+C5$W@sd0@_9+XE4|0B^5+)-aQSIf7r@YOYb4Vp#jKDM}b5%|Ea`NVe(Y{U#`7>Iq z5zun>nZQCP&{T&ZTj~**n8*gHzcYFMnH7hw^r4H!$|!c}J-(%h7ve`p}cz%FdG z@@?ki9r0pEIHzY>d5dchjM@kmqtQXQjp@?n(#~{Uot%w0s6<*+57J$3^6@&ZS4EOl zmQIe$x20XjtRIZ|R+BC@vDF@DHoBo7qOlxpI^s8X9M_5WSP&s-_Jivt6H9=hf3hQ3zz}g%D`cbxXz}yC+wpKZ zVm0+`<_!`r{qr^1apOTxK}PQ@ePeV)iqzaLvDTBY*?qc7P+$4a@)VZN#p*Cb9eJo$ z>74h(rw0u+$66>=o>4LlEUBVN{?<~&6>tMZAYC^rERluvte|6yRncF2T|s30m6_>U zUx_laJE1G^FX@(r?VGL>?1Ae^B< zvE2*p-=!8D_nOyxW@_4QV(H>|Nn@%LK|C(%^sHcN63DlQWrbzc+9TvwZlOMgy)4?M zQGKTBcXe^(Sd@v;ocQS>4ZtKfkA?ra1#2qEuhRFZ0|8;BJI-mTE=Rg|9viB!Q2 zV*>1P{_lByBGsIpP|&yS(MMhR_OH=epDH?elURqAUMo~_4Sdq=g2@kWx&4;{4pI2q zT=DWjc<_@O^Wh!~ZXv;f=*TM8K6Vz~La~Ql@7TMd$hG0jNqfnuJO_!XJlal^3JlVv zYL0pGhl!S_x3ag2x4WaqINwS;$-&Qo1b?^CwxS>6we>k-yS1Ni0Z3D z`>}m&4j*3p^0m8nO}x>7?0SkN#{qMv;w5mG?=UmNKl3Bpu-pLV1X+B_}Cn+brGzwWEPn^jt!5Sv*xFmu2Iu)2RG?R>heeEGz{FUEz zTK}BFvSt0gk@%c^+35bC5O?Y3Y}k1vfA!;K;!sBte;HY#H&_gY(fv=zGVeEEff`97 zkwO)Liie4CS@vG-p_X^{B5KwdF- z5DiztYCWUrGXY9}M<@R;P2bYYR{s_8e3N2Q#k+*=;9unl#b4=iP<+5~DGETh7IGoT zDcRLNavXN3{C(tIlqx0Q`%j8}ts)O=@+$sAuWa1pLOK~=#8>8?=k>;bj?H>|bNQJD zL7pPSn4YcBOroRszJE>CV-}>g#E%yaOTTbW5&-+wU$=^=`G^Rpa z0xM2*E+D#}NvGuxsJ3o;NB`>MsJdkOPrxjo2Z{!6cgD1eFG;#k_yK&KyYDM-hfR?h z*Y1oIdQdccp&Yxi+J>}OI9MHKq^d{xTcc|1asmg?M7K!Z_e(!qTe=}-+BQ(+QWlJ9 ziBye)i?CV2yqoXv7LoAgu8keNtc2baYX-gqyEA_4&Q8{?xKI0v_@7qT=`#Rnto(WT zjf$$`uNQoU8eEN5?wDvT{;8`=(IfVbh^wPu!R+T1>A?WRtlX(+i2Q6P;(T^-BxgJ^ zcaugyXzS~ajL31b`behQz;2*KQ5i^PPdCVuq!?3L6hW#L?sK zf~%#)dxcF!XNj33?>w13fR=pvqYD6!C&KzMwPcbbOEo2X1#^?I`5Z2zAu* zGclIeJ`Cjf@3vfVC_+q=dI0(740g=O{+GrH*Y#g)tW zV3XQu2^SmR=X8?ZG4!_WZZ;iJL+8NZ{HZdBM=w4I@na;_25|_v5!P0GZnd3})aA$` zlbbUuuUt{Qx<-b;_;5uU?D%z1q|QKYtbQxjojFQC58$871(k0MiZ5i-o-+7ykT$g8 zJ{Jxz5G0%_ds>dMoV5)=U@@Lq=>mO}pI1u9*k78?K8e7>!L6TKjP_AyTwOAO9H-&_ zcGaxGgJG4Z$VX~+bUzT0#6lli9Hnyuyg9RrgVay9F1gPx8em2rU`07PmkwJCGP{e9 zA2HFGDADx2+Y`EX(|J6a&=*g9dZl;dp>%C6`2iB&A{_;E*Z$r0$ zOeyKSu!fMfwJ)ubA`|| zh&$eyBVnw1vG^>s@6n3ro$_)OADZX(Ea&ga$w|RWYMM+83?&w+MJ#p2^Nvde0D^*j zvt;PBS2rqk<~Qc?bfo(p5q0vH2NMZ;dY9u9Q@2ujwrH|9L^ZZgk2;2 zb1C5%RqfAyYVU=y4&O}|dWF@bTHkX@`b|SLbUz54lO7;Ht0C^aj+&^UO8Rm8%*tzJ z53;zGx%0m-6DS#=Ky>Ju!$TB$6-Ejg1}erLw#F2&)WOUN(g=H5pqI%p+6(5|yJNTv zVS&>{$2!M)P6@2=VV)$4>biHw%*@AM+=z-qUsgywD$6J)wsnq6R!{s9Tbg7~TQ0z) zZsvaQaNg)5kztu>JvVj_613;uwDmY8$=_mN7qXC!w3|@9HL$Ha4h3NOhw!f;rZlep z30WP|XTX5NX8iwBKje1!%BE>>9c!jh$P(qK2rkVlVVK;n%O`+h&2Jj?^^R5e_aU~2 z@OwUJLxc~R9h*~SwsOhLa2u@|v>y-@uIFec3yd4yj#|WvDb5pR8ff-L z8WfHC+rSXdjWwzolMRPHqwKLeaI}}afP%8MHeO*ua#EKV+q`PJ-*iH2WP$wNh}yU2 zhAq~rfnJVAE5AYw3p$!QEoI~X$aOS3ppH^&|GwJ)lJk5jKC;b}=bT8wUr-#vqr{iI ziBEQmH*Pex0GYcEkj51V_|~x&X6ybfT>coJxmE0AbWv1!YW3P$ob_&jY;L;p9;SgQ zxf{=x$e}*N-AJ+cxgxrsm9Ry}uDh*EhHATEL_okq({zi<=(zZQqO1Q(#DT>34#PZk zC%~AbtGTG!pWsoMxIXl*d6G}A?=5vOIm$+G=HCbSs3pKdYBZPvW+#s_2PeG#Q!Mao*BTwmKp|x3H9$r z^eTl*NM9|vE>>;J}1)tw0%M{@C+l2PGkB zLoRRarAo-FJXqf3@^}EEkh%0It_gkDi@!f$afq-Hf41+Pw;d)U${*7z{s!zkgPy6^ zc%RIX(9x_ca`BP0AG3(NDe%nKxPPQPwn?{5Db;45b5pffE_L2L;X$9suYVGnlK?1e0}ipA9#@3}5XX7M2ZWTW z5vSkJS9odGE`Y$O6%6#5<4NLR_iF{VD>9JXiopQY%#A<0!I!JSt$-4-Zc4aLxMRSD zGgQ1Mmbq59S%S7fA%>gYMPSk=zNTL*lYv? zXiotFFLm`y3XXX}h93jF&b9t3VSxGJ(?ZomemSNpQM3G%5tTyqpd+XCTfrLXrRv{a z842O9H#KT%c>UMjXV*kY9qO3j`mwWxYlm4yMQq^M_Oy^$l8bLBJ?>V5dnHU;DyDkA z5h)1V`ac3ru-RLH>R;k(W4f7)u?fs>>E`a6$er|9ptKb#fB}%Wn1mjH`cu90-{@cRP%xhO4?%i>-Qbc{a z6CloZ+S*@{wS7DK4_Eg(I#1Rodt z>S8DOABkGF&m#UA4=A&x+J{03$GiZK?0^DHqe0NM@-|@Ls7EmDA$BpxKC=3~D_ex| z-OKwC!8(c|UZZCv^+lP=%rCI4Lu@ua>v9xk4!l{SR;npje7-CT$vG@zeJit@p!nif zHhL|>CP%kGqHxjwf4l6p3YfPD*k1ePIEz)&Z>ftdgdukHtwB3V@M%*2r1a(S(&5WF z18?+rZ-s3tkE!GDYa`Q5!21|CsF@B(Yudrjml&`3WP`x<>c-`-T)^8;BY7;Sn(yD{ zw+icb)iHDLVdoB@l^xisk1{kyx`Ds}M_l9cfKwolivV%5wp+k7Ff%8G8iE9`fdvHz zP0Y_B$-lt*n$Yk84rc-|oi_DIfoHk^x`0Lf4=7}BGT9a}VhF)b^mGBpcDrTE`BefS zU(5q`AD7$8S^%u#Q@Sq;He{&J4?1a>#3KRzG71lS_jO@kS$;egF<$U3jyZt$?2m&u zU5nha1o@jELvGqke{x|2RRd%oo)u1ubG(HbbbN(Hio2FC&3t?iExbo0SMmMwRH*JD zVeheGz8^9wQVF|;ygBf@>S{+jUK0<7%@;BDgp1IcV6&{kPy2CDSB2VLYclZ#jpJ_o z;Ihi&3k()zI-$Hb0a7+Htq(2!KK~&ynka!kJZ!_Pf zBPMI4cp)`vJ5=7Zj@zNK&06K&_piAGz=F0uNR0M`fEid8A?X|l6vA%f*SD`B(22BL zU#2tLAy_CAysBrVK2 zT8K>jnS|v^VHC|t@+5wi;k@t)&m(ZSNi!gz;%TbugXmdu`TK%)1a#$*~z#$*FdBGKK3fxjhWQCjGh2SBEuM?e# z5?J>^9FP&U#N3Uh4i~_dCWZg{zK6c|8~PqMji2g{-8Ts>+^}9rApX}rhneBrd-=Cp zzBMPTwoQ?N1}XmNTa*M}RrUL3u|3fAtw_Jut<3Ay{YE)*`8nY*?n_>AZKXrP!ejh2 zHGC{2Kl(WvrZVEcG2u=6#n&<65_0|^HGr)R<4mL z2&kzJYo5ml$V}!&r79yr@y6S4F4S=i!_88BxnQbPv{Dv_&w%i{hDNq^7oYJ)0BYiv z%-;iw#X>V$*5{p?ht-db5s#|h9=%$&S9aLTIBi%j%6LaG5xVDoQ_1z8y>bGyLh(Ht z%B>!fBOHGgVJD}IT~@)liq`o^yri9eenoxde;&_w&nyP=`_XQu-$rSOrql3&p)$pG zuz}z(C}%znE+bCf?|bq}rs%Ye@*E6wY8~jH`W4ue56|l~(ntf^>|y{qb*9{y*TJQQ ztn_^ljDqb}AVwQNdcjoo_hZFG9A8s2XCXM=RpJIVD}iU|)jUw%>}jyi;{Uq8C1Ehn zs*$eibIW%x0aHBP%i*=0m=x&g+T-1a2n>TKDnH<|{nr$LZ>5$}?&gQxZD9#X~qzbsDCnC5UQGlLb|>yGf+AbwhTCE@n_ zl(aNh&zQ{&M)|aSASx53d+$GYP#RCFumr?0+pJ2!O?ajskV7s3bd~G)ZmYg-zhNvi!Do>HNH6Re5Z{WT( zGQD1WRQMKP_xS;q(#{V2#bDT27@n0-`|>?jZ@;p6}5k@t>oq3 zbji>>Hwp^=LSQWc^U`;@*#u_h!wVT%OQv-#c+4Ft{xx1}7 zwPdBlX-@-oRTYqi#7gY4Wf6;(MA;H~8Bgs>bri=aX{J3!yIa7ICsE4En^iEP#dxL_ zdo5QS{sDgY{I$^P4}sR?b@Gu`-lkvbU3NayZt4?I(Qmk6 z<~k_3Gg}Q*`+5uhEr7IoCIhdgKO#t>KTIVcdFd0F-DVvHeIOsr z-Zs&@wUe^fO3X-W2E!pQeHF2mu_~~ZHLJ|N-LG7iUsw%1J?O!$NU&4%$R=}K)}z99 z-TPAwEc1wdp9wxl=Z)tHaer6CKJL>^0wbQFuK>{isbzlu!u+uF-|@}hf)66mz2DY z*7qhoB&H4q;!`I`^;mlQwV~YUAdKgfck!{o!uzmKzjq8bpZcnE*}PTD+K^j0jveyn zAvT$p6d3|r0vI8wb(ex67Cj1x3Ufr#L!_lsyMj}NA+Au(tJ__kAG3`u&cS5%LGAHd zKircwC{zpL!SdAL(|}DRqL5~pbuZiwviT82wm5z|&?Tj9<1gvpa1Z;v|DZ!QQn`q-A2~ah*d`4s8yK5 zs-c|*dS$GDq1#$=0iZvjSfv`a&0$>T2BcE2=)6FteW6%VJ#@BPujB0Ltimn9O{Dmhl^F z;yD~%0?aHVf$Ys^V9PZ8JOREqm#+bo3byc%)w!ph(XdUx11xs$kJo>QtTO_l7exN2 zzr&LEYOg1~t&S|licmNMHP-1Xk^Ro-b#T+Q`{W94B-1o`>k9W#t>1hZe?mQKU^qUb z{n?Y@)XH|=%lW4f8rKQm+Hb!l?~lN-QqoO1JP*NS{wdWHaZxKHOiMlll}9_L0)F)e^!|(mB*yg_A{GDbM1_OX7n(cJG$;;Dnst(#Cu!pQ zmJf|_+K`lV7ew=vBsNL^2o>VmYy18$QODt9v6Ljl&kF3HMGJmtCBKKcZvxL2#^MbiZ#x&_wx_!^z z8Fu%M`Z`KUS+$o zjchpEuP$7JfgXDdGg43BpvW=jwowr8N4bQ`qupNcC=Ar|FZ?)N+91{J*bA&y&$?7W z4$0REVg)NsjUbMf9WA>`u}yCM3m*l4eglG^9^@SYJVmMX09XlSg&R`TojIhgfhf&?U_oTiW5mQU90GrTY(J-!)P5|uPg0nT};VDV~YhUeHz z=7T;Kk?IT#sGFl#%^&S--*spa=Bqp6f$FGy+wUO@`Qx)~!$ zk$aYGnSwGWmiH)5JL386Lgd0Gy{;v3c>7Biz}5QHP|{xR@)}eTdIvke?(tA=C%Rc6 zvHN86>wcAIzKU-lxJ^}Xi!V}hnki#J`q)adMOe&C?7Sz^>ocSK)Ca-t*(U?`2B!=0 z!D4r%CaxbYD{G!KN3!z1$T^*$(7$JuQ3-(BViIh*lI34?@dwH>y{B4Qq-oN2B;_1d z$ciy08jGapbbpAi1Ye{&;xAlm9^%i)Bo`5NOV%q$O>&3Qq@tlHewvXb>l@XOzPZZJ zd=9b%XqceR^|=}e((6l~msC{L29$>2i9}puK!U!u2G|L!C>LC+BaOM}exH2a?bL(e z;#%`X|7kV`lFK&g&F06gfyynFt;MxZ_G^cKJHNxzliWz4kWq+}SU%QL&|iT0c7}P{ zq!ayB!i}u$(=V>D~Ue5%YH{8g528Vj#^vC_-?m|p-qXt@lT(! zNC{^g({5{xEcU02IPIWCxwh1Hs}?srUqrw=I@z5J7_oP)i35v zmrL^FYF328X7(E`ILv4ju7R>!l`qNyxi>1iDTE4P&99KQc#XwU$M8laf=*q-<0Nkq zuY~_}0z8fcodD!jo$q_{XbrcLB5mNl>;H5D@M3Io8WR<;bty@TV)(MOILEojl}lq5 zNIY92*U~nWYz+iPxJ?TtlH45yX{p5xinRr z*dE^I8E{LG{BSX&QcMzOSgsX&ZzNW%^W}+QDE>3sQI04+!HF2qb%pPp3Eym-Dnx1I z{Bo^qPIEksgjAf8UBaTqGPa;Si{v=La0{7^QBRJca z#bz#DO?HI16EhQ6CJO=&r$nviQ$3cNq0Q$&)+!(qlq(f*%vE2C&%4ao?zPF8>H5;C zF3KMT+@2_K73LbPAVc3S^+(0_9VN$E5; z%X3~i28O@gmW$E6YN~bl{@!an6fRTi ziI5SQE{S)7)O52%cc!m=5E7aMu--E*EMb={oP0SJ<$&Ep?gO{_Q)4$N^YW zDkBy<8RQ;cTQ^B$Qw1fl(7slz99Zrflj359Al~VxtnXLvZJqi`Q!7NqCb(6_C}LGo ziMln6Aez(D7ZoFg-#((_3r#Kt8)BEW_UUBry^OrA+R->~(zmXN+4hyybvvrnnbH7I zQ96Ze@8N{MvUGg_dk;-px7#iY!eCevZ_vqWmobj4mV$SxDGE=X&WxoR1XtO**8&rU ztFKZg+N=ax#z8e9QL(2-RB(ONY=TSm>e5Nb|0&_l9+1BCVSc34PhV;JU5 zjx~DD8{iX!a1Zk7nB%ZoNp7FNG`B6Q;QK9jNGTheYY_xY-Bk5UXy_5|*JULo7 zh`jD_th`~xL3*{-hOlWEN=*}X-)lFaf5aeO$nRjg3|QM@Rev?95_dc zRDH)Mgis&Ef3jH@zMbw$Uy|W3IJKVXaYuaZB&x-mClEsviQo7*y-qETWOpbrV0?Q^ zP^3@h({mk5fj$-oJw^90k0QU0A2Hw2kV){EI*`(bkDg2z=oAn5w48ulE~e{4_WJ`O zi`_jghvfzXkXFK*;aKy84(Bpb53e0cYCEZmEN+fA$Y4c z0}?BeDLPZ?ch9%hL##4l`?FtcyjZzDrwd@mS$|g*<^4Ple{@8+n~-dNZ^-=p4339~ zn(=$h=tf{ba_f?eC!EtlmB5+3P+IV3S$-Ct>Ac1|#08y=;k8{3Gk#mF3cLqQ=&_`t zLtDujLR{{o03~rQw#Ug@IF@WKL^4^FL#Ye8aIXy}dMpE#@182z$tn`hBc(*c?|Y4~ z8^4Ktnr^nI-an6}Af9UMd_ukV`NgcR6TLB2`{`rv|A(%(j*F_>!@g%2N*V!?E|G2} zhY|#o7(z;rW)K8LN_qxK>F!cW1f&s_MmnV=R6shEp&Q;c_qoqG_j%su`PYvMvuE$M z*ZN)8^}Tj7#eau7gB{9viD6NexTwj7Mwp$*a3+0jcEp0f4lep)DJ7>Yn>IA~+Qa&A zLIqj8DSh4|T1XezYecSDSjT}Wco#ksfQ}kz_!fGVLW|^;@to!R7tLS%*soig>7X^Y zss2--Ahq!Tx}{8!zfo1wbESF_xT+5w{M7TH@ARduqj%5~3`05+za_9)tG^Wqg=(){ zzte+Bt!);`tKisu*%BJ-%qb~?*Oq7>!+)fMzRv8m{;wp4zR%uhwu^%~;NUR1bdS>R ztQM4>qzX_F>E35}C-&(c&myuO%KbYrmQ0$}tpqlrPB8ZhLHEe?SDb3On%C5~0qt_> zJz;AtIup}LL%)9M+qDG#7sn~}**>MgMlXP~$f>P!n+{|k!kw1&W}PL`o{uCnEgRWC zzjEeyXMf<%1L5ENQEX4c8PLL=GieI9fC1l(D7%0U z?*ucZGYwh4HyZthfbPh2645Gu0A1+57xF-&*k3hS&(#xRp_O_|d6H7B3evUA9!;?^ z+iVUW{MCQ`TzR=U6 zdm4xzBX{z6b-cvx<}P^W8L!GSa8`aCi)G`QInD)V>uT$n>u2?s7X+eSL;oXjVehZ> zUYG`>CYLCdmal;4g~jD}lv@4+m*4SkTz*C2-W!BVmB4ASmd)do>6p8D4i-R#wxv*% z7U0CNktkjd2_*^A8Hc8id%084x%E&c_LRul+KjW*8fLg%Gp(BJdM`Mg3p1`Q+8nzB zAJ$ey+_+5T+;Z%^e5xM@IG9s{>!qy|#|izZF-$TO(HDv*AiGqP*A22~J|;frV8_w< zXt1k;soO5-HSH+q;>`K7JHiqzL-UN%0`*CGvHOnk}NLySut!OjsY;J2!nEIwvQ zEY%ykscz0oe9_Ugr$^A!baG>p?-Z~2s2HElS{l*$rAWhCT9fFj@sa8JEgp#=#Yf#d zEYtGf`I`Wzc43+Kywt)TXed&x3>Dn-n z$@=Ks0b?Qz(8VNTCoE*9#FWfIjQ&l&^F&T1<}4NTw?xS2bzCocMF%ugTEQ5?ACvv5>(~%CdbMm^V?;p)6?Yg)scc~CTpO*WlZ-UVl$ELjXr7D z#lF^3Dl`>~xBv2t-Ru4^ePZxbwyWyDis8Ql`47W@3UK9siUMEaCEIO1L50k&v_!Ub zdp^c{Ccy6TB3_k@{jSQvy@)B*=!5)`D93kHjh}|obeI!4g050?ms9&sUr(#ikY)NJ z>^r>#2<)!i&R?U6-$YHbbIEykZxmXIyGBkYyvgy2kA5ImmGvD~>oW&HbQNiTK(rvZ zx3~Er3>nF#k!rDGGx5Ha^B>~#-z$Fr{s9_e$$V*vf5w%0?;YHNDUw?wf-%3!?H#H6 zBHKK|hOMWK_DbZ+HdhsmMAiUOeLkl9P z?L_i4%_JzQle?}-+py3f`{sN6r=uIx{B)=E4i(CnA!t73EMYf~$ZuM|YsEeO>zVk^ z!jb!0mQ{lrEpQf^1;5Zsdth{}A#I0;IHfRE$0+euNBShK&^Xl;c*}M#ZkHeBk9}qS z7^$7jg*)y=ubu32v`9yZzEPCs*rS)?VIUow*NCk6%7HE;i`Ny(`lXjFJ7sveyQ4F< zSwfx&E|~j)f?teNNwwm$f3NcY(dV7X7iA$ARBDA}X9TSP&v?4_M(cVqHRCIO?{3!s zF*eFO=vudEJR{y3C&I*LUNOJ_9dT@*zqhqZuFYd`>;3noOneAoFd75~O3U{j zK|m%LrT?>W75Zi)?5%YS?OzAV=WyZkOcxBRJc(l`{snCH%R(zTi$4tvdM?Yc_k)%qp8-v zR=Yq*xWGO=hr1Us#+(&jz-%0r5$`v00+?_AW!rs+2@JzfN9`<|iy#V=GYj=1KJ#x- z?~rYoqeN9_PPffgVE^(khB?)rai=s)9&cTJezxBj@*@#99y&x}tER=BNCX~BV~aHL z#W>ETo*TJQrM*>@#>TQ<>-t4ZqdZFe6@Yv(bwj`D=4s8pEzQ^)CO6pI0(e2hv=>?m zgZ&kMmc=vAJxh*go-e$Kq$nC<7q4C8J&+`;dv8dCr};qbbn@!igz^X3 Ele6-jw z$rm|4ymq3|ok#gzy(&1fya_KCccYeYd+fzcwBi)kJ7Af_VF`CuIfWq6es0iDY}37R zwmUA|?(98k+0;Kwc_dRF)&5N}{Oh(2xV8+vGhsqh|Jd^V_Md)s=HXc(RG%hYuNgqp zUCLnP;c733g(wNK^OOCO-MJQERHjjhX0)HbjQVj5ocS`DF168RH+f@*hBJv@oe{WMXGNIM^p97}~8${^n69C`MPhshNE$rj<-N@9vcr z%D{xLCCLRmw;5C6aRN`qf1ZQK0n8SpABSQ;v)Fq3TuCqHH^q{_kl^v~yKlfeJf4$Ax&Gw6nczlDi2fUtZ!mxB8$h=H+xToT5Az4;s-DlazGx-%@Mg#TZUt5Th~B zmj&&eJ5>nYQ=V*tW_O_)5n)FFj9JeodCL!py6)w!mbKXVJfv-KJfQoXOEu0c#@%}T zhP%C)_`Q#@DYBbI;x;Ty+7Auq{>LUJFam2THix+8(cXs*TIyd z&P&p}{DDF*?7lvR0Uy(_;G}m}EbW%dS03uU*^W5Ph{9KHisNci7T4m;&k>Bu!W^@kv(+6SopU^tim@S176Pt6f%Yf zt3N)!NCnQ7wms60Wyn@y(_MUHFfaU2(J$JUNNwfX4*C~_03D!#)0Y1Aog)g8sgZ52 z`r7Lknm^*L<{iYA2ytH0$)X{B+ye>P^5D(UQw+oV6B!3-5wBY1Di{4dS8Tmlpy$C} zLR4&aaBufO|NY1?@!z-Du#2p=v9Yo3fcf-jin+fOfO830f@x@gdxjUis7;ttjT`V` zBlQ8j#l#bMiQ0fyip5BtP{gMSNbjMbq}kTRei>jt2mxIAc|EB7b5gb4djv#)d60js zuIn$&^!fAAKA{4{+=8*Kk`w%eG$_EMXa~q&IzeEx#{lmWQh#$SbA5mpu2)AuNV8lJ zt3A)~wEp#`hdT`%kh<<1{`sLa+vK+~J+=gRw*kn#7O;7IJcL1Ap3WZ3K)Y=^{Q*LR z5SvdBNHc!?I=JndIf@C(41W4)tq=p&ND1qh!2J&&VF{w||}b0ssvdyG;PV)amgeM9wf^qLwy*t7mfg0W_KV1jJ|Rnvr>~O+U_yY6Iy# z2I&`n7*o$JNavYee2;@3W6uqaO~=cYz*$qWOfJrkW6A-$$6^^x;j3@}m@U?}eih=+ z0qag%L>>BbkBc-WU$k7}$y{0$TpPd<6ns-2dGs`uRM8Ix4YOPxb+vpl#=g@mCiWEo z0J;rO2OK4wCoMzq{GVVuVNA$pb^nALp9AYns2)PL*4Sewg(Xbbg7pMglf*0rx01N= z7CBTR3Bk}V;axg=+26dSIYUb`%zNN~MGd_0(k7$I6=>2u;#P$2bF;-L_Q1Z(_p$n} z#|3sPy)!iP-BTJ-H9IKIFg{&9oGBzAgZ%Vhrx}!?cV?+0_==xty?eX1 zWu>*#Ug}?tMI*G3JjOO~w_%BeNui)W{l`x%0A@RG$;!a=i=zYs;r{wKUnHH_O-QN7 z4|hX-lXQX!VLs4E-<`-S?8BRDc0c5YKb_hUuqACSl_zHIZY&32J(U2I(|vXVboJ`Z z&LHER$N}?yqF0lI;j<~a%GVuT8GZEM$q$z25E$8!5RRbDMV!Dtcx*u>hJOi6#8FF7 z$T3*9m^z~vXm2929WCmma&C8^y}ns=#Bcz?+i*AzdlJl&>Yw4eJ-J zaWbK7mzO6u_uJQR^zQ8M#%I_g1T98xSS#AQ)nCxgz9TBcnXD0G-jg1N$AOV|kmKmKjcUJUpLv2W4jF*u?hjvfK@ffaKDifRHoR{mIw6 z3lWL{uFV&c05?LaZO_5=Pz*Byo-kpH7PP|?r9;54Q%JmG-Mw8H z0U7_XNi(=yGwG`bzh`KFQ}rPs-dY0RU^t6sggG*}nZQJVLSudPw%xIOUiB}3f^-xe_?Gh|{*>Q=l@%z5ePLXLT@fCt=maEkus*&T|r~6DdZY z%{hlaO0TJ9-g3Z2v>dqot%lYF9RbFqmGBn&KM7jWJbFWant-GAo`C_ra0jtK-ewGZ zCu}l+&Y+DBYJl~=ZbMzrl^`J2<*_&rM#f;y@{UOz zPnc5D67dpba0Q*UL}$4&=(m0LzcpWsXO{M)WNS$5&toh>ufJdY*6Y|h7 z)={(*k08M9_9}#S-z^PY@o~D+l6e^c?z|!Ke(TtGuaqVRI7cPss4if$0jHB*OxgeP z^ob|174S#$l$KPj-wU?4o`8s-0LE-^OeXL&g@Y-u?)2z2re3{}|9JXt-@FSY9br&Q z(m^oY=)eqT)fHq{d9LO%WogJni9ODk(2++pm&JDSJ=F6`GZ&qNhXe-BDMN0!ucU8~AGDoxG6d5G@4pek&|(SX)18Lk z_3bz3kKx+*F!AVv$=J3gjX5AW_&(QMjjrQ!xO^+m z?{zS>(gs}BW*yWSU-kf=;i3*~WnNuJo;yYUoE#o}IL^=K-${moH5>sOqTWObZ+L_7 zDD&KLo3{exoCMxdQ2x%H_Di<4P)duPM@3(jpY><%9QKgQ&GK~33tO8pKrzNjgY>R% z40gU;vRwuS87pC1nR=*3vO}g;W^UUW52x0 z)y@Dh6$OK`GHw;n?ND;0)5b1L0O#`i{1?ZlCAt(;Q{i0kSfd=@Di$g=i)S7~e!SwCNC z7@4Ks4S@B#c2oPm(}%m29Kssb)$|d)zkL3$^kHYE_+VAKTvE0Y29*$( zk~MpccaqUndSaev=U-qRKRn^ug!MtdJP_INIbyu*K4ld#024asUtYRG;Rzrx3>p5=m*6e-+4*Qb zltGxQ-)V1EXCj+c_oNXNRdjAGcxLn{z4+|mv_Lk(Av*4N`iH^bp*^RM)QXJtD6iWB zgThz9W@Ydb>Bl$05RX+_tHScoE|4K(yQtf!5wh5t0dbQq+VAR)3TS8T&5;+#n~Sby z7kRJhuX*Z>P8IY${OXY-xnXS9&290@$3{g%dQAwzkju|3G{GNy1R@$Rn83my6D=4K z%Y9Zo>4kKHHPz{LiJJ{LNkj=Pem2Sh#QOfDRDYa?$=3`D;>iBTpI`jJI^yaES_#XB zggy%2z0k2E7glrY={{i7 zf5^bPQV_40)!W_Px2Rjz><1DPsB)bZD@lcnWi2Ibyv<;y45Vh!AaDAhzZtlra`ZtJNVVU2h|Utd?sFRVy$*_-cKF zEvYzGl&4S&cuQNU&??dDSxWdLn$AiN*5_f3Ndp)JSGKOOoVTM+zhjGfw(EdtyPK*hP**= zf6%r|l9L2=;=IGkDjS0H5%A1ZTQK_fv%bDje9+d|Cn#g$2domLv8akd;q3S_H`Z>_`2>*op~^n^T?e`I((tE+!a-NpiWq*O@n8h`1e6 z5Gzdscf8|7DxJgT2tgQiE@`YyXIfTiT&vLOpBV}Nm>6S1;S1UQu~B};L=P}e2pQkK zBkw%dx;%s>0-q?eqy_v$U0&e7j0=@a#vOiWJSF4{9tr&6m8=xZbl{!KNka%ut{(_Q z@ZI8Gpi&?^TJa&cMROr&7?Ib|UVYKN(3Cr{(9abp+MkGNWcI}<_#7jLAvlh(?&Ck? zGMmn$GX7`!Q!N2kI$}WbWNP;MDP(mkkVRi5BP+cV)^8TWBL5RV|0o*lB_0k4GxShi zy}$YwQTD4a$zYDW!EJ2bj`@;P5oV79rFjdMEkL8A_CDFzz`|>&j(; zssD6c!3v$t0=<-rO)XS3nY2`x*KN(;2x+Xu4 zOox0t>CnvpGxs|kH}4%k8m+YBP@(oPE*d(Ep`J-;l8Ye5!^p(F0PGAK}98G6*s>Q6Nl%CS6e8bdYx+3&(-P zO?4vVj`QEzxA2aA+84dM!I16+wn5W^gR8a!gTQiZb#A>Zg(xYliZ8p1>nQSYkc57Y z$O<3tSJx-NWVZHno4-gkX2)f8CMs(@kWMCJk^64;CCwHXw;jd#tdlt9AQVa=nWjrt z6OH2R@XXL_8RL-L*8q3%L*>};QLV7`P`X=~bs?nGak@3P^{q}`6jr2SaOO;htWP*G z@yTOa0u7b}NQ7_hK-wn!PiZDB=<~V>zT%*BWVZNAjn6Mm?dQSzQ`zJZW+xc|h8uXW zpGV=su3=MJf0kAVUxI=J%7t1WRNG6jOpZ%`2KAFu$gbmz#nWGA5OwX1iC{(YvyOB4 zPIq2sm-zfKi4CUF?e}!Y5jbtQ*TpdfN|aX8h|COjhVY9Fd+VWD#P&#HbGrb>Xbu%+ zOTVVy|Dlv=C!6I)kd83CTL)zC z8x130hLdhS+l(R%x9XzrxNcHfiOX<3vXY@vwbks6qE4RG-O3wHm#4Cyo974H`{80T zpEm_FcjxDS`uyQJ%=YqFKK^k)sIk!#2XVf_$cNyKFMWB#LXb|E9^X=xG)R@n``0}~ zp8cu>55X$pAk<=IAb%eB(Q}79Ldb#9NMGp_9`L;zTQ`F@Z^1j0%)=4&g$PHSl z7K^VRexao#ABA@peYtRLqQE0GKAHURtod*x%-?2koW z6d?1DX}(w zbvup%EdxV!c6S#jV`qki9e&Li) zUVf~YEDm#k2PHInqsA({*$Mymv7G0{@yg8I(`h}9qw`-92}&c&}?cVUcL>Lzzjo9Kz29bCa@G;e1@!H|#iz@A$ zdeV36JXDx$DF_~<<5^r;6Ws~H6wp=&tK1{-BE^YK(X{Cq6}GuTkxSq9eg{|mAg%-7 z)-6uYk5?&6kKwMx+0pZ0I@T-;b-iSh_ZduYZ&|kayp}3@NtEmI#>WFCND!=O?x*h? zHUp^q&wS6jG;ZE7`L%nuy`%qeG9(ozBJ<=d!o2@k-*+$qc}C#3ohy(ox-@gNo~gp} zD-P6tGul_$Fkfa)nDS|6f0vXQZ1?w`WAwQ7Ye+*%eIl)Ap*1mW7R(W;?vq@`QS zKrcK8nc*0OJ_pkRRHn%3m*h`G&Uzu&6Yn8XXs_pK$!n9GVH}$HD@kUHKM__mf1oZP zXt3Qd_U@ItOstoH4zMHj^rpcF9DS1o7gU)rGca^n+t~;5v&!b1L_@x z7+cZZTG>hT9+C+yEF20o{*lb>`k1AeuE0R0S8nLV*}#+F$Rjb=^h3tp-5&sGFWRVd z<1ExXn;9?UZydZ@BgTrTlQV{KClTd%-`dK1OmQ-xB9Nc<#^tJu;=7{AY&UK_RXSbc zIwB2lH>eiSzt-yJUaHx}K&ODU+(ntFfb{X=tzK;*7R+dib|KkmF$xF&wMiLD4|7?F z!ktt)8$vZvHNQO!FS^Z4HEZ4&_*)1&&tHhgJR>f;`fXY?OT%p4ui85d_3KsTU8EE% zKj%P2y_`k?s+m+#&QH$T8N)iDBj!DKUi9stPbv$M@x= z`_LT+0VuDof>~L1pBFB5KypKhZMAOi0XP28O!!fTC4Rd8<5K1xGxXEJrJfz0U1TO4 zWB9Du)65GTGSp8DGeB_`sKMShZESkf+`*v@#;Q-wcrM$jy>-^ zot8A}KvT4JAx%M_8ZMlWS#(TY0`E_i(z~grx2YMbf>BtA{e@k`ncG9LEc;7&0lsKa ztx+i)y+U8RqNgwm@4Z!fpZ(NIKY-RJ#f-V+>Q1{Qvx@NcL2bZ@t+25z!W-E(DW>+w z<5;S13?Vu1nK6aDCnA=?_@GtIJo!(C$k2MiS)guy9`xd%y8Fz+ zLv2H;<1agP&*V>U@w4(<(g(%^$Odtqi;6-8z{a#cQ0484e;w&G#aWZHgdJls z^`4$-<6nswvqo{=2BHnHh6*x1O-{0vA`_d3I0@+3+@tb|t+7e_c5{1OB-vjHYY=C# zN|w9B2(k@Q3j|76Z|Qcsj3>szr(CkHHkN>U z<9vWa#gv(ROY$o|NsU`F<>uy&2J*ryYg%kb!%veShp7lvr5yF*_zoQHY(&2uWF$Uh ze~LCRtL@x)lgf!?k>z8UQ-s%GvQGf~Tv{#+;WKGgEUEFkIxTfsz5|&a9u%N)W|%D4 zbQDjRANmEFy}$V;YoV)|njpzQa20cc4c<*QezEH*z3gH^Sp~9P{S|b%5G^DAUcu-q zzT6zuir7%52VJQfe4nttpVA^EoaXjf)QQDOzb}{D_a=#prn8)(I*;!$!zMp3IR54F zmGYgJ-^Yn0WL|tjmidb8hRm<_(ZJiqZeCW(=0R}ydR%)m#<4%0AK1?57CZ7HNgs)r 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 NIBWk~@oCS8{}1j)pwj>V diff --git a/usermods/quinled_digquad_preassembled_unofficial_v0.1/platformio_override.ini b/usermods/quinled_digquad_preassembled_unofficial_v0.1/platformio_override.ini deleted file mode 100644 index 6f416668fa..0000000000 --- a/usermods/quinled_digquad_preassembled_unofficial_v0.1/platformio_override.ini +++ /dev/null @@ -1,16 +0,0 @@ -; QuinLED-Dig-Quad Preassembled Unofficial - -[env:QL-DigQuad-Pre-v0.1] -extends = env:esp32dev -build_flags = ${common.build_flags_esp32} - -D ESP32_MULTISTRIP - -D NUM_STRIPS=4 - -D PIXEL_COUNTS="600, 300, 300, 300" - -D DATA_PINS="16,1,3,26" - -D RLYPIN=19 - -D BTNPIN=17 - -D USERMOD_DALLASTEMPERATURE - -D USERMOD_DALLASTEMPERATURE_MEASUREMENT_INTERVAL=10000 -lib_deps = ${env.lib_deps} - milesburton/DallasTemperature@^3.9.0 - OneWire@~2.3.5 \ No newline at end of file diff --git a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h index 7b89c8d7d7..6274abceec 100644 --- a/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h +++ b/usermods/seven_segment_display_reloaded/usermod_seven_segment_reloaded.h @@ -86,7 +86,7 @@ class UsermodSSDR : public Usermod { static const char _str_minBrightness[]; static const char _str_maxBrightness[]; -#ifdef USERMOD_ID_SN_PHOTORESISTOR +#ifdef USERMOD_SN_PHOTORESISTOR Usermod_SN_Photoresistor *ptr; #else void* ptr = nullptr; @@ -371,7 +371,7 @@ class UsermodSSDR : public Usermod { } _setAllFalse(); - #ifdef USERMOD_ID_SN_PHOTORESISTOR + #ifdef USERMOD_SN_PHOTORESISTOR ptr = (Usermod_SN_Photoresistor*) usermods.lookup(USERMOD_ID_SN_PHOTORESISTOR); #endif DEBUG_PRINTLN(F("Setup done")); @@ -391,7 +391,7 @@ class UsermodSSDR : public Usermod { uint16_t brightness = map(lux, 0, 1000, umSSDRBrightnessMin, umSSDRBrightnessMax); if (bri != brightness) { bri = brightness; - colorUpdated(1); + stateUpdated(1); } } umSSDRLastRefresh = millis(); diff --git a/usermods/ssd1306_i2c_oled_u8g2/README.md b/usermods/ssd1306_i2c_oled_u8g2/README.md deleted file mode 100644 index 70919cc54e..0000000000 --- a/usermods/ssd1306_i2c_oled_u8g2/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# SSD1306 128x32 OLED via I2C with u8g2 -This usermod allows to connect 128x32 Oled display to WLED controlled and show -the next information: -- Current SSID -- IP address if obtained - * in AP mode and turned off lightning AP password is shown -- Current effect -- Current palette -- On/Off icon (sun/moon) - -## Hardware -![Hardware connection](assets/hw_connection.png) - -## Requirements -Functionality checked with: -- commit 095429a7df4f9e2b34dd464f7bbfd068df6558eb -- Wemos d1 mini -- PlatformIO -- Generic SSD1306 128x32 I2C OLED display from aliexpress - -### Platformio -Add `U8g2@~2.27.2` dependency to `lib_deps_external` under `[common]` section in `platformio.ini`: -```ini -# platformio.ini -... -[common] -... -lib_deps_external = - ... - U8g2@~2.27.2 -... -``` - -### Arduino IDE -Install library `U8g2 by oliver` in `Tools | Include Library | Manage libraries` menu. \ No newline at end of file diff --git a/usermods/ssd1306_i2c_oled_u8g2/assets/hw_connection.png b/usermods/ssd1306_i2c_oled_u8g2/assets/hw_connection.png deleted file mode 100644 index a0e51b4de4ef2063370c576547954c550d4fea0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34900 zcmbrlbx>Ph^e>7-utIQ8Ah;JTP&7brN-6H8I24EC5+ua}6n9$Otx#No6211tSoeSQc`jr9xg%>nv;{$cnl0OAmdXJAwfazZjbD}!m% z`1rWEgakFqGZj_UhQ@}SpSzTF+!!SsE32yv8m<_HL+s;XB9DW{CPu`BgiJ~nfB!u& z@~SB$EXqi5Pt7fWV0Hn%`o^zhnWXff@`7LySr1n|3SIy9j`pG9AzeM)@W_bf{z(fe zith0rA_{87AB#W0V7Uc(eB2CvUaAs0X|2xA71fojoFW1WUh2Byawf%L0mdBW5pq^O z!m#Mqma0?JQ)gFyCKmVq+}$N0lTg!JiAAlw{k?_NgXL|bT*hxfLe{)G*6$;<5D``@ zJLj%mF1#KIO;4YiMCNKZ)CkI0xF=M;wtdwyvMHxys%c^y^FFGiZBfNL?L&PhK|5n; zdaJ!}qMm0&cz~**gIhpUc0$p#o=xIoNQjMhxuI_d^8Fh*swb{7gG}?>(o$0SX-1(D z-exaJ#x*oVKh;L&lwmaGe^esle$00l!JrWicx-CokLCB`=N*3>m&lZWJCc+1glqL^ zW#%Rpv9Pd(vH{aQA7y0=eJDRZepC-u2S0|42(<2CV1O{xpbGl_OGjM@%WTv1({Fu< zavg4bdMdu4b;Chk4(-AZKt3W8@_~3R9~di8zd6?R%;D?z8n4n+!3n#5Zl_D26zj9m4;ZtSVHuIu{T2ZH>cUEag$%aPYGFP-21E?eswd-ej$K}27t z#=Xq>`NQvT4gDWT&n>xU{o|W;zvajzYN))^U`4`c-QL3^yEa4m3%Z@(FBYT|sC)?2 z+^)!OBCT?{ISAF_boVjH1zibwnvhEtaWk1@%*4P;m$SbYs4e(@5!)#jfGtj&}j zWF6aI)>;)ZviWN5J{m@w%WwEB7#xn1Dq6?fC*HBjw(i-h;o&5P+|6LU;P@F{0G@v)7ZoYjt7jKlIUnJA3N?+jTY%Goir#P zvW2UBuaGt5%r7TO0@866-N80Cw!yw8Oz8nY8TG+%I~xhC3)&|<`0rl9Zr-^wR43sm zjC=};p7~RM$)<&ODl>tYY8cmMCrf*Bb|G;wtBOSsr|WEOA3Z#TVT6?^z{bCa`Sp+Rl&I=haCcKP@EndQ- z0JAg|NjTuD5WY>qi$ArBito6k5+f@qn!~LT%exe*$7y9e7P?@}VKo!T2JWQdyPUib z$~&H9d7=%w+SX5Bl%n7Vu!-MDm}H)ID@m7d(xww^glv=}?FfxSEm$81?*4+-0| z)Pt4NBQWx~k*cJLC00z38(5bVP(~8@Yb-|vEAf4kJ_f^%KTS@~^#Q(wYX6(jc@(TNdRSE&m|fr%{($#@2n!U=NA9o zdkV-WK=tqK2>^47{ZQjxVu$RJ0X8ds;EUF8hhM~j9BL_y+NQesU2fEXI;Y8dy3d{} z@^6+YA#F#|JP=|mKvAg;fRm}1XFoYMQ&joIJZT-G4_O-lSM~K9(FmNwpH;P4-|?Ws z0V>WbuztsYO|EdKk^-{fBukMJDp>0>{#1~o%GBSYQSdUJe+`HK7{lSZ*pL;MpsY%Y z)C*cdtD$mjzRfSJz{)?)gotLRc>Jt+b|hK55(LWyb+dccP6(hqzI>roeOUfISv(Hj zLAP85I|E<{jxfxAjv%ks8)sN zs%SU-%~Ayf_Ev?#`l#P{-%{DbrdcruLe>Yh-WS-vU3uVQ0?tM1ML|VJM6?}43QT43 ze^bIeEzSZkO`M&#C;@J7E$xNLhbNkYRWz*}S zLdWh2Qq@ZMJ!`C;Xqf7mq8T|--E?4h&LcXTWf`Wl$fZj597UXt-M zTn32?RBTOzn^_e(J=s{uIQ;?M+?hz%4B|VV_DEGq!r@&OcTCnrtqXrUb;r9Q_%kxM zhXS47lBep43!r5|RPqY};n>5m1wkSG{G^o)oBEeelot>gZ^K-ekDX)v(F##_x10Xjq zKgg+O7d&}y4Vukm{4MobvU03~X{x<$+V`_|jgf#mC}{h7~!{E#i~gBB~rJvRgh zJ3;;&6icQ_5KPKSKxxScc!~Y@=P*mC5;TkK(MQn_j>8@iFGlNGde2J-uvN@NHzfjO zj9uTz>==eVL{lh?!{rtCYLWi@6z5jRn*{X3CCH=hIcH58Sz_v>IqNxykyDEgtf#H$ z7lUg313+k`)a!hKuS2~3G=r+>9sUH_D2{8OyN6hW1}6Pv7s#q&yF?ThEA6@crqA>b zwzR8bC^+c(ci59+!uR42r+0=^;NQF9w=a58U2?`R2zamPkPd-=*`^N1WIvq(sJ41E z_iB?JM6$vNUM>&FE5i1?Kz+c%ElVXB3_rIPCjBVm9iv*K!76bm?2P(lA@GbU;*f5pO-iCHyb1l`@mgy99bKF@7fv-xC z@}NDTpu6T{jYIBdBsfZF+92{~d3}NF;X<=lP38>{J$+zEugb{Bv){+8*6ocUm)l7_ z;9||#M~R||B%A;(p?`bw@N3OKwx4jL0!}dHgJ874#*1Ny~0Qq3VJ+teg(YV&nT#*fD!~-LoB>FP6n=8xc12I zwqUdtJ^!wkrMdUoejuhRQO}T2?c^H`Ea_``D5Y| zO(GAgABv&i#oWilFtsyI??70yd)73``q27xBMUJHtAt8_U7$;kGWnO+7P4$Q2?NJR zeYas+??gIi@f2H=a7Jc&VZ9)if4P(p){{fFDLv=v(vT#yS{o$ShfjwvBEs8G zfsT#<3v58eAUc3?6r@m%$bCUJF`|zR==k=tCC9`T7O5ai2zR3Zh}UoJr{fK*{g{lN zRqmgm1TJxoUrKMS(f1L76!Ii~b=H$A`n|^?Zlso7sl@##5=;UCN+?9+C%2LU{nhWc zdMx(@lEWsh(&1Y?i+@9sBFo-cf$sa7z*)>05_^A^yJQZxufKl$aoFOB3_I@-l!ngB z7Z24NB4e921~z|7Ep%)<;$!zUD-jcgqiR6p1sO3_A__`ITWZg=WQwD#7U?!5rY~qS zcBW+N6j_T&a_S=C&iS48T97kDW-xBdgvxe$dhCaCnsg!nq&6Ifbhr7a;pm=%Z!0lV z(_IWx5QnA5Er^S3A)~9h9k!quHZ9Zr*pghX&B+aGqjlzi9NqI@hCGIhrD3sv!=b^D zPMQ5?otUiG1@{+~M*RgpU(d|a0xk|D-m}Au-d0A!BlFNsZAhnG`7v7&3vmeEwC#gu zgpOZGJ4MY0?X58abh5v`NPxd&(d2^NWSN$!M7$aAEk(F1f;<>tk_#A`x`KHYsRtlT zi{wLJ>o+vcPWxhDkT|3vC!4ko!HqX3PMcT#3o^OU3Q8&x?a0jmGx?!_}CfkY5T zNh>Q>hC_Rqi6I|;RUtDC8GD;Ceg;c>AY|pB0vL^Y_!rV|oAI2D3dj)-PmlRP9fKc_(^t%Re*~-lU=QEb zuJBGwjrmZtG_y8g!!C2jN)h-fvrw^L5UI=UHTgp62`ylv!&5E_43X|%6CaOR$#wLpei1^lk#z!Oa`+HX`NEA1 z461eE6ZlFQ9uG&bZSHKgnAaNoo|k9!z=mvL`uCN~Z&fP%_EjA&ff<$7e$0N|+BHS~ zvx?=ZCpVCZ3BRF3RZ)HWJ(IZ6NB;Ljr$1Qx#tMr8iSUG^KvNAW;Qd@0l@=TL-7jbT zDk6wLLZ!WQwtWA?H=kJx=b$7}DVtIbU|s@ggJ?KZRrP>0+2Q;io8zgq_^Cc!6m{xq zT-^MF38cPrZreNXr>Q?*_-n~cAJqu{%liPx#{1FZ<}b}KNE;(1;Mtc!OYLVLE7csr zQS3`@GASYAFmFbfUktP+>bv8u1rrcYmN(hg9pX=Z(?1Qbvs!_1p&6Es{2-LG+L~+o5E5*6L^26Ksa;cEf zmtM$nm5<|0W#zu17YEO_4`eNB0AkL$($~yBW5W)0G{1ae8gWhH!470}YW4hVnL%wQ z-OUV%(fKN_v&v-v0H-Y5)88|YYveb1ys=bEfzharX?Gy%zk!H06(c+CkN2<|H zURuPg=#cEA58%|YvilJTabo`{pin#n-Zq35f8;}wRn{dW);&RFYZ5@<<@2-WVyrL5 z{LrpajL!IxFL`eSO?I-g%z>%Y8`{^3E}h)8C+|t3U612M9h0Rra7nXTeyeIeTi!+s1pc&FuLLSG zeu4JRDvF>YVG1ljau^lN0oZ^Au!i6O=|#ZEoA%v9GT2^&Q#%zT ze|9=f1s3F2qU070RY2#W4|mhc3dP+AV2>6w3B`+cOI7GWrD%Z8=Xkl1y6E4{LE3E) zOr}E$m?S3wqzgwG)?NHk+G^U1hJC;VT6Uq?7i*tK56gy$0OB-mNd$qC8i0yM`w7vc z8UVzJj}0wQG(YI5qtZAWUV2!7mVsf6ydpX>L84^?K)?In9`XN!bXAXZXf2egQe}Tv z_?HMQTpZwq=FMJt>z~H|yNTk`=vPj`S0lyUtN*19%s`5dK0c?(NE6C$&jV~QDgnn%zi?r3U1rjBf5QW zdzgzxU1c(@gr8P|Ok<+ya0YV%8o(OfH(x?XkF~YTKa>YoRykMxO`E~@ z#CMOl66gJ?4}&&Y0nM{-8m@d3dr1!4KDR~4xConWkovYG({&XA6hJ$z;F$eq9bNgSG!v?{-tNaA=;PNQ3g{W`=y~jqo4ETIhVBK0*MkxP%C6 zeu^&ht_&0~Nd>krxu(W*B&GVHLligcD*U_lo%@{E^5ObiMZjQtT?A~QD)}sA8uS9W zg3rX%#4sH}|6g@;w33nl={W+>&<7)|<*D}ZEU13Wcg~z%TA^Us;`Gb6)mL(Wj;n+k z1AkW{C&n`D)(=a*>br}iV(41!XhoKSxPQ*5DAS094!b10LzHlPzg8(75*`(mm2H8` zlHBQ;3?pP*mFI9-}$`y763Xh3c1@(X%&SQ|h;0 zsV!8{s~L4NHk7B<|2%;3br)xGS~GCD8Hzscy{J2|gDPOT!0#~xQtHrrwuVD7jgg;P zA|Tv}Gau#%WhYV=orWr;+Azh7i0r3k8xyx7rqZ%2{~T80pO_BSm~TJ0H!Uu8;GCqk z#4(c!%;*U+KkX;22vE+e=INtQoo!XMg^*T+OS((h{g=o_-~_d+)7=>BA{``>{HAXm zo9XPlqz%mU6D)~598|{b7=x~?+p5gF;}UPQJ!u$gJBxoJoy*P58M}w72adw){~IEX zTEBYC*>;uXb=hs$KcHUB=JEDR+JUje8IyzxDYO_`l40RdTrh2UrOG(ei2E|lk6a#0 zjo1Ez9wunZwCdy^3{yNbObM(J09xk8iU%qhn$8KZC3_H|GkFQXVfv@V#Fkl?zrX)` zTllS()S8cWzzahC$(4s(gJ2a1%n$@eY@U0DggnLtXSp~*!T|Aqo&h}R6l1vXQtXm=*?9m4CU}a_mie->}+kf2p@dT~?bO??g7Sg#)a=Z|f z;>#iikcSZ$C8R=kV|T9Ol$&rdu}I<%31YJ-@yLr1`dJBWCum?FemmEN19nCHe};gC zHHTyrJ~NY}eGUWbRD(E?NuvawE7j`BeMR; zj6S=3@Pb(Xy>8AJp>SaZ-1|rWvRVHxrwgWrxcOPIl5JKBZ(#f843tQjX6$I+4|c*Q z^Vp{9F@Me_6R6OSI?pd*-0I7``q@Wa=kxW2Jr%W~YVn;8bb{E1nld@fd=1z ztZNt|CC*{bIO(kj#pH|sRkmaATcryXxs}Sj=~K~|S5cfE0@lWwJ4i1#r;@1!;MxY88H%e~J?B&kK0dVk?p2YRbSKk+Y< zvmezsaYvUc^C0OCK8r1xVI3c8C0-``j)cnB(*w+BvRmSt&z!{BpD9aY6`3kvF-X2} zl#0>ee~yk-u$Xn1_$vmS>0ziyl2VZf8J0J7Dp;mDK0L4+M#wG>`Cv9WK@~^taZ%Rq z#&vkiWFNA=aJGm*5eeM0r!Lw4U_Gcy^OzRzHKQOAigKetB(^9jv5TVy=)3^uEWX^<7fJc)NYcKoy>ncKtY~K5vsXW@MCk2BW zCQJFN|3N&*AmPJQ(h{XXb+eYC{l>E;O3h`_SIlna`Pb3Tb?n?;?jSYo3chOiq$|24 z^7DLKR2vb*L8zwk0+b3&G=)a|B>0Mk7`#o@7K}-NixMuVV>`csbw&V#G(`+G!r26o zwR*(JYr$eyRYw!#O=_Vz2QUX9?ns2j^i(3Ds>6)NiSj?5$@Opp!`r~j=SvXr0g$wI ztut77fVwASfM&r1LRx8GcWR8SnL!)>hv>hm9xSZ6Wn;FaqQ?Z$Ij*Xcv@65?Ym{<+x#(3jqj_7jHW-IG3{nI-Ve_i_15@nxtK-dO+-Q?@iHYBm7T0< zNNeX4L1Z|%XdSV??zKL1x@`A?3ubBa#^vq%ZrqDBGcFDq>J&B0 zr+|!xC?g6Qst{fXr}#bg~wtM|eW?={ZH9vjSRrLQIH=87VR<|Q9E)+C_)wLE4%&t${~ z4!M5d*rdJGHB>)r!vjvl`2Q07x$rzbs&w@D?B^1Pp|5C_**auCX2aRbi5+azlA@ zwf_=BV8f)B5*Ab(+yBH2ROCy@19W=An&%tAr$;zXSAp{?klrYY#S^!#pCk!iFwDwd z1<4fKGjru5!(8yz8XV0h<@xMA8|G|ss;8}o3FSg+vBwQlf{ND{F5$A)IMj+)`c9CD z#6$OsA@04&t}La0W-p)feq+{`R=<)z6?>|^PBQVWekQQ<-U=DZgb9Qr#GtPoY;2mk z8?!Q{g)e`88FfuZ^~ELYrL>l^9}Nbs!>)psTZzvF&s7bGf?l*RHSrGf3;v;|DWg%~jl=F37#Lsy z{XAw^h{_1^BS^F#iiwk>nZ*A+RWPl+RHg8HXB-qU2v5mQZilvyC3ksKaSF1f=27e{A*PP;+NmPk@ zh;s@EXs@e#tDHQy6m_53bUe;~_U+A}?Xyb1)0;PAXEEK~YqEvdh5msa$?a{Dnk9NM zI}EkVU%%R(aYpuxe8YXabgPVXpAV8#Ei^E$dS2dp6ANcCBn;PLOtdZk(2DYkVr{&_Z0Suoo`a z*?e_%Wz?+brJ$usvw*A}{IdD%5*U;fsOFW1c~&4qqR{OiwYA4peIY)Ob7XL{*Z(V7 z&hsq*QOaX|8#v^uAcs=uE6nJ4tNl_$%Nc7*rTa(Pb!8xJA_W4pmstiahjN8mQk;$K z*^2L8hd43hADS*MW^okUMn2z32|lruO<9~l^pyw8D}e&`CJMDFKab`${7Vb*4m<14 z8%$%?_mg;_O?V!;ns+uPIlZ>#rjJ;0FkD|;la0{PBl;8O96GzU2=FHEe0RCEI6EuC zdUKYO!?3ozOj70J-TX{S;ZaRkG-ul^-7gtwn;%nU= zhNRoiPuz_C(}=$_3y`KbX^t7ZsRlo}DlT|A7*#jC7PgAlyw{T7M^)HrZ|@i1^(^1- z7tFqlnfR-6pes2{sxQpw*OHx`MWLO=cxRS^0%NzT?)ZU>!T)m>VBwSe#-BZ$-|`ZR zJ*=u*X97qgdI=pdBZsfD+uOcLJb*)z=|J-kCLqN1=QOA&*K;NG4Me4Me8KDh3?~1s zZA(Y~5h^9EfFPjJqp@~kkH!S>5=%mgoy_*@`sRGUxhm(aO8vgl_j+oy`|do3lA?s{ z$H3eE3|7J&t0a2B-!D~<#B`Wl@y|D8Njl#Z{Z6**qz!3mZ7rikd^@YEzZmV8Gol3| zq~&c0S31t`V3QO68RmzL&;CvwymOSx`GlN>;oM$n)P&$k1Hs3hk-q?2u7+FtmPgo_U9c=ebZ4h{gy@?~K!7G_uU)=XGN11wc zXZ+ATJk)>+=rFS(VT7pVOe%QXe!EH3Gddyn@4DkOe}b6z97Rw29&nQ2w$%f<9UjL5 zW(~YMEfLf9lHwR|$IJW#+j}*WNRbmvYM|A!ygD}pW!xfmW#{wCG0S&$!(BIC_Nbh~ zxUAFv^ktEz+T+fzcuL%<(p}M+rUF#p(bPLI>CmPZKe*y{FT5h>kr^KpaJgeF2x^$_ zOlx}%qHj_pmbdqlu#a?zdgP#Z!fP-N>id{yHl%Gw-<+SiW`A%*?{>W3fCZdjVZ$RN z1KDnoytbiG0yG2nJTABxT-|&{I!R#u0)qE5PpyCOgZoSC-M&0q*xeLky7A>~B?;-s zm3E0jnGr^|9+yWQD``qS z1{$roFmu*PiXxjG6;?>q#U?y7qk$js{^U&RQDWY}x3GbFRHv{mBNmJ@p& z+r@!PkfS5|SL&_TcN3w14^P`dZg(LC1EGKah(tgq->P>81~RVoJx(sR7}M*yFn4uG zYEnO0X9ey_dO)Pa5+%RMjXIX%9dx1!n=PLKD_EOIxyBQ{uf0=tbl`4KhL|SgmAR=K+8crO|huXVV~4jKFiZp#{F=%nH_!e zF#4G0A+^S;)7c?{zGlOw>m>s!_Z5dq?X~1raj4M8Pw_*7Bk%*pkh{x*0!%75)1~~( zP(Kfxa};WlzUC;iw_f_;q}Uz)CX`$*D}$CH=VX6J;9XfmM``?1`c)a?J@LlCU512+ zXcJ4r>#?OYPBKV49qx1b3B+oQQP|r##7pw*eZWT#R9nlP$N0n6trtB^h>;f93(dg; z_zWfL&({4M-JjtUig-zPcVR~ub;1s z?b(JPQZ8q|Ys^AROi7akJ%Vq*xv?hU@`wH?0S{pU;s}4 z(&zinhtjZRvKEP#+uj>SnKkd(L+%jq{h?cTp*`_Ce;zqyavpDz9{qnfU6ww-mLEI! z$Sk#yu#d5`m;OP>pzNO0znJI3vwz(KF|hG;nJf<)!NR*ZqT4RUBUn-Kb{6QUlD(Hs z2q=!PYoqa#C9(SeBXV^2RTh2N%Q~_!;olVQ+2LI3` z@|FPCc+ECve_Qh9O{9oppe$2!W_LiO&h@|L)kGF{c$NGa-CnOGhQCkvWyOAN%PR~` zUa-YY-IGiJ@+Nn`;KO8lFWP%0)&-Ac-DFREDdUdV#(_aU;u+5RDDx^jav6GQ#9Dka z5bK4&%JFvORw*F)Edj>`|IQpA{ZA$1Rculzhigkx7~Uo&2?P!L8P@~XFyQl6?7qHt zs+6pF_nd}0L}k!JSd`x1Px;Rb8jE-<$M*_ldUJ4!vUES?^9~gg4EjxjtzUq{LpNf- zs#~p9#Ic48xihZKz!;E5D{pFF`YM`oMt@m2vZF=%9}2IK0g63mh_v?cLs1_qmOf%8 z)bMmhbK*aoIiBhxW6hW~>P4vv2;O#1de>+=M@lne0YhDX-^d+L^sExGFuhR&lEh56aD=*m`}CBb9AOAuSWRQD_-v2y>LrjTjPmy za=QS(2ARORl3mxau`aiW#HT;+%gTn&7`hFvaDQrkO%+QH)8o=hC~z|9Xew(;JbU4s zWW!D=0%kkU-8g$V-?n_D7X&x^|66_i@LXiRy-lMkcjqkoXLeW&z^pzNw(xe?w2?fqB7*zURcEqKTK8)IFoAN}5f zGkax@jwbhBaH~=G-lSA$$@jYkDD@xC{bu^8mm~T)dvx?L^>x`{(d-bwcwTo+vhURs zQ_eD$VZ5?G*S>$Q6Gx<`pZB`_$*g93&QTH+sScN|G5IZGz|WUnv!8N~MaFnH6W68} zTU%qQFPacLsq`w<=Y3JHQ9qBgHd~%LQY*Qh3=$S=DfjLIIx3RlJW+bL!Sts*4H*Ts zdW9j>;O7PT%nk^Iu-y3j2fv%4za#(7liOKoeR6eZzv~1hkDWI&D#GZasUJH2CR*c> za*~IC<~J@IdnRSwdi$r8X5g*xF4Q?sMM5wv)@C&0*-HLMsSOcFt{N63opVQq0!7aG zg2uf1Nk*+%H{amvHqezQeL`N)ipg^|mDI!6GxDg~2vjX8z$CK>)DXKa7S?NH{KY~| zU{9A8{KLwmW%`2!`{6zTF!JC+t}Ctn%7~wySGc&+`>6?fDLI{Ie4N%G?UV`tpW2Aq^!r~z9M-8P7$9K`7~EiY zoYyE^ca|#Ym9BEwN4@ZzUq!nlqq`|zS?1?;Y~1g+S+k=9U{@ms#evzIVMg(Db`j}( zVk$QH-IIJ3v4sXU%C&)wdoo;diWwTU?dbbvOSPX=4)phqsW@lzUINIL;VAPqy- zz^pRQV2C?_=Sx^sjI2(-mlAIuBk3ROCK91{i!6(2`U?HK*4OIKiGC#wV}~~nQ@)tH zx!pe(^947m7FYH!{iL_DTM;9YIyu%ikNbA-*$_&P$JKW60Rhf!WcX&2g|Adx<4TL9 z4QLs)15K(QRU3NBLo4(va??B;MCAKl@nv`kVC=dC2j4c+CglgOJR2&-Xg(eib|gDH zG2b%Z${Yd&u`BCL6yG&AXeP!{JY--Za}9$=sg^3|H|MKZf=wmRSp~SxRjQw(~ zD2QD>kP(yovA(n0BCK9I%TliI$vEY?>vlJZZuC_REcpk$?cftvtF!Mhyf+f%XJor3 zJjzQj_EK(Tp=-nX%b~TgceBirm%%gM3fz6~H}J*xV{77MSwW=&+5@jsJIEGU*t}-; z)Xt5tkn+Qhws0veI5rbdk z`8q}u=-Gap=Wqo8l9?5|9H~tQh{+QKPk(U2*%>nKTUvcy+}x7)`FG-2VA}W1qX(Zi zq1d7SE(<*5`|AXkFkV_-O9-tvwOk`LNuDa$*N+W)_GOGy#w{-%DL=JA`!72f8Lxuu zaxx$qu20|r0d>Y2)Jw?YD#bqqg?GbqRwj_Wz5?7wuOnesUXT&h$`vd;JSx{a#oD2I zM3%k1i>FJo{^81X>CaZJY;9Z|4wwsyl-5$B|cT8BP|34ci1U;^ZuOLXH5dg$Vs;v#rxLj~L zSRIsp2$6U^Q8buL6&DNt4>nxZOQ8pMe{>Wvt*xgA;`^>!X-V$nGkvzB&KA$s5QbSi zQhhcvMlRes_d8FYoKEOlwqtVelNQ(xZkm63`e8=^k=1KuBl4WMuvczr)J66OtIAb=)_3tS@r6;O>q zS<#t&B(y_^Jp!lez*p+EwsiEW>8BP<<^B(&{!f|TS3Th)E;Wj?u(Ho_4+XrHPNCA-D?2U#>MBIYf0)L5LK&LEAVUL z`^5M979hx4h;m{=!y}T{5Kr|$#?C!0{mb?z71k_oY@l>i0K|nznf8%A5l3o^5s@i^ zXMkn8#AUFB6+2?vY!Cs$JW;0trhv0eEGz{EZMsumxy&o{yS}@o5A-nVl`{I4{(YT| z^fB7T3s^(iLi3l)R8!Uoo3z$aT^NNS65T!(55QMg78iphJA zK=J?tzO6#mC%eTsu3}@pB}v)--u!64P{c+t^vEBL+V~2>>O+Dsuc6m_^+ufpF;AX= zdj*j36b(S;c9Bo`lmPchU|>lQ^MH#Ic{P-rv0`N(pzYRU+Kb3uQK7@< zY$)PRDbbJE=cg}xO8<00L+1_qq=#ofTN>?AMh%WUm`%8kv5bfJ1sK-0H5#->84+qI z+{}!}BeZn#Q_aZCZZ^^y7iTfu(t`s@U}dvEc*(iF4TB2)`Ot2pt6(CF34EzzA@fdr zvOSZXD0altS4s@?@q_Fm6MBnAOl)n<{a&RXDh3Q-B|`+HdSWKMJeD0~TC?&xWN*%S zki~!m8B+mgM8Qg7Rt7dU-mF1azFwk%@K;+jqfzq9XXgT-hEA!4n(C7yP6NgMFezME z?tnY5f+qP_a>!Q)TH>i0pCg|y3R1~5^&~Fg#1|yAou>}W2mJe__lfb=7e)x;9pZ%w z+vJrTg=yAW|qSPZ*5-xZ$ zXf|a#`%329E~% zNb*xuP^8Yw0u^{s9MP25lVL)x$q@0+?sQ30+4zqMgGy}YmjcH;2HYLOT(^_)|{e+1WpzwU)Zc)ak zY=@tYQ5a8Ue;?r=T{g$^HgFitq-xn>AtgJ5d8ZPO2}%W)cjg85kw~ZN)H6$0ue8!7 zawBGw7*ZBT`CjxPMA2`WsH@C&V|-JPxQUUGPzw_UB%K_v2tQ> zy^X{2h7qAGZ<&WKdZbvU- zIWo(Ff`Z+QhLY|f4^}qcZT>77(CX!vZ5&JbVE~Q+mhSmxx8O5NT7K*r{%U9TwaRLo zCW=^;8rU8d?GUq&I-~Bm?d=n93TVe$<}n5Ql>Dnsr6Kd~lGp}7ukm_kax9puvt^o> zO;`+9v$tmh;+)u`Rt>!nutE4&*^rC$Zh-rIUHMm!B-j=JnhZM<*Xy=;vsQ6L zbNmqJ*151>(g_kBefJvnbzQ9|vT*}cqq0Q}qE*eI+&Jcxc zLY7n;h~|2k9z2fdK$1Vq(Fg?Fz;Wlx>Wh_8Hmgi%{hCP0$=L=~pwcKz>pjbs)^=du z=-A;UAKt(Epl@{?wk-A~lK+FDpTP&+ek{$fv~rb*EJO*7*yH5K z{=Uhd$vU5bb)+1xLT0{umP5++Q_6~T%PD>6JU3+eGI=T0#0tkiX&FjZ8fNg^1fS^( zhU2LPqsQ;K04f+V?}D6l#DT-{rPNrkf+oSD(H71vcPfEQDo=*sSC>lCjfKT$Mp2if z*e+#Jo+Wyf`h-!Jo>{hSdSwgtp{p6ZwKGekxd$BVI$tlGQN* zrnP&H_m%2T6f8`0x%b43EYSV@#2ga|@*>}}oXT8^*;M6IPVNP5@n>zGB^$d*&C6pb zI^5kq;c%EF=_A==v{zTm{A-i8?+Tvl-_M|-5r&hA;1;E*`2a{M#Be5tt$a>vJ1{t#Pj>Qc$Rf3W5*!L(IT;#E zHZn6iV$Xls!>D2P9jAQ6Zfx-4Ck|^v>sYd`F=FoF%g&Z&Tk-9KBPp@M6)_v)O&Gf& z)^0r(ArjXAo0T^CVwmX%XON4FL`#FUD(?&b;pARN89IPH3FPUglStOh*DywGpfe10 za5stt1{99QT5ym6N7=tfk!_YFLZh8H6OzXy#Ld^gwZ;r= zfU@h+{mZyF?UFdW;V?+OUnd?y!OX5wd5f>0Zl{+kmkoFri{lp0g9)@xvn3A7Qs;JZ ze?5~NE z>3vUs|EVHE1qL(|aY#9X`nH|lqbTFpZ-|*ZvcvEWB(m@=WWdhcLb(oqdowe8&!mDd zVP-!i#azO^{LDF)MCOvd6a1a^CuroGOb;8RS(?^-O~xz=wN0lzbT8p4finDGkI6!lWgFn*%*acGKDtT^UOSpqA`6_bm^{la&33Tm zUpL!t%nqajj-X~KUq=i9H}xqJQ)@AQ;y2YwK41*#>$!z33M-g;k2j<}wkAO_9t}UX z6&axxXQ?Tk0#BPfTj5#YC;~Me-d86Fc$qyNF(g80Eb&PzDe)eW3d>Bhj+Q~`7`$u;sLitxmtbWQVU{ZYH0G=lo^FEAxe$NJBIf}N??{Bp1oG4)+YrABzvBB(nlLD>HfcNYvzS##kDqM{l`4MSn zi#hVe3fP*oYM-i2+`<5wL2QC<%-uu~8E@kj1_oJceXv*psS5^!PpC*K zLbUgx2O9dY{dl>1H7qxsdeals1!diQyo$*X{8eh`@C@J37bv^gX!SG}4a)Hu7z5<7 zW?(N;ViWQUIA054Y>!UwKh@Tt+!n~T`$BX3fJ7${lkHO{YQ4^mBPUXS?mv7$NQv>E-^1!Q9x$5$2l*0{y1lcp5 zw{If`3t{7<2F0e@{rO;Ev{7>A;w9_4q`8zb#7O)rRZ<=sFw^V33XL`y0@shQh~VvP z3s87a9fM-lqw*~~2BK*W0CIh3*ijds1MhK8h|aFm?f!x;^0qw-kXmqC{qgJLic*U_};I=h*zJPF!s z9lOj1wA|hH(QV**rX>OPT|N{9zt<(?0*08I?nc8jM_@81y46s8Ya4|)l#blri=@#1 zKJw`pD^p;w!kcCe6cS#EyA5!IG)7JP`igXz^SJ87ck?Uq3Cpy$wY69K=7PE{ChqGK zD~v|ThbvGVEN15kNgK}^u9?nvZjCkRFd5pwjw|eWSah7+@3FO?&Ts>OOeksx*>osj zSuct^dchi~@rf3QO5`%I`Tdw%6N=()ON}zyJvx%1miT~y@Ru=MbXWM)RjH`Rq~gHD z`FZ36+d1#EbPPzo^D8q-?p2w*D`JP}|AvI*1V@zT{W;Q~J zdlY}MHf18KA{?IJU*UNST+f}Y>dLC^v0zmUE^!7aEJYJ{{mPrC1>$~%;~@${?wAq> zL&0|ikGC0*r(*e-{qon)!-@TqV)2seH2SFNMW7h4F-@pS69>OIF5tzdxA-KruV4?mp`jA> zv2>jGyL4qLuurfjkY2?T*UuU+wM8hHl-{C0bxACL?&|*O_T)s|jGae~5kYX+J%<5c zP-ay`)|(G{+}Zh;vuS*MJe8!tz%I?U%j1*lP1cQVqk%od#lzQGu6iDNlR;jZIcd|r zv@Wt7)=e9dU?8nU%%r-5!Q8GwkqpicBQl~*9PJOgN|5xhC(e4i@R>Jdzo2Kd6(T0z zV_>jwn2Rol_*Xc#-nRZwUqSy;B82}F|HkX)1`s!;j=@MOA`1k|MQxoEYLiE6r$Q#E zly$vkO?mSL>R8FC=?(q-4&rh6qiRU&LQCNDWQ_4im%1jH5kO3<_>XBAfe~&q>yM=C z?&ldjY{0lc3Ex~hB7A)ODC0F*J@iqQ?(0tY04DaT^LrKjggi~(RqfJB^#$)Gvft%@ zDkION)RWIrf=wAEax$#SWKH)b+4@x362}DLsK-6zjq_nh@5x)o<73l(`$P(Di;TDu zBHFY;AP&WbB(B4dqu7C z4ebGXVO)WpF2C|te66r)#Co{|)6~0(m9Us9q+l*WkhV0VZ-zYJ#zgNgn(;5siPzp@ z&v!*^Q=8=3PWkv9`-Zm1r>?0RVIVjsWHE3J1|4l)d`_#C%?mi+qGJs=hyWn{*QB~) z4gMERR~Z#Y6Kt^%7H4s{#hu_9d~tVz1$P1=Sa4e;xLa^{cXxLS?(PJFz5U)h@8{0h zo|)5A)m3%-*6m&&yqEs@|K|cwGxd1&7N%vDx)3>?{%tN5ZJslB8Rb2n^c$gO`&G6u z1bLFfI`QSMA)ldv+7A3w;IB}>{<_7M#>N&ArsEUNL40|IpfMVQN)2l{N8V1j6oh(USU*4NW$!mD{$r~53|0wOcz5~?(=T@035&TtqOaWeNS6AJ4G9LgIG>wbO9AT50AvaPPXnxhO z&x0~!IV$5)aSE)x2$4^wILT>ABLwd$5i-uuLdG3l1cg-s%XS#WiUlT}#Q;_;DLbxo zAwV+VVVOawA(Ez{MJE+!Bk8MI=HLy0werf}W5oC;Zd^m;0a7K2->qBgFMDC|+JRC> zs2Y`ch9(SLqUi3E(H3% zCIiBmGDZM#eSsou3%q(vrNDPa9?+4R9as@W<(w=bEq=ob33_Yyba&6}y%lw*-~LWT zno$=suvFd+(C^;mxoZCG#ThZM&G9TBB574Gb3E<8K7pKK6Q#9vOCZwjANFZy6dwRo z&5#=G{Z&Wsf`N%I8bW<^KNT!;Gtyoon_;`9j#jzs z(b+qz)AEg;oUz|PwI1|gQbvu`ZMggCZi7+IQRbL~2``;3_b zs4ch1BlKeJFpkLJ&%;h>F0hz2I>$ofy%#EeaE)6=+dm)6B8(Q&Ul_&Q8WMls0+XDp zfm2C3&#6K5p@|gB{(kGedB+#h=SU|MVnoIp5dptMZBPUb zRz*~(tOfyJAu|(l*XvT8x2zwo?++RolZMMGBt=n|_k}{*IJA!Uda+Q@aU!=sbODMB z`;5%n^<)BpHK<@1Eb<6el5xy5IskBwJAd>ao^7N;jNhTW73>ZU1gI09!GsPD!mDQc zgrtCLY98iD0d)O=a()2hqWmq-MJR|%EoM<|E1=Xb*PiNeJ6^8w@48i#(?f>t%<2$* zLyV9ZiIpW)AHN6y^e5)-W|l|a_*^^UhJX%PypY<2 zb3=gAngUA^Q$%YJQ{WGt)gLS=1^>h~a(}f;JnpwBs8?m~95YO4?2+@^b&dR)AyRp8 zi#_@V3}lMeCtum}1>VZp4nF})ildURQq^#r7=cV!j2xgFVh*Hb7c~;9C(TYJ@CIUu z%u0cjAWcpUR_47aAfO+WPstd*RYOYYPiP!OCkLgD1qtD;R>$)r3}oO*fr4^9ANIh% z|DXPK!d$^QQU+_)xy z5Yd;Y`CX2jZc)M4)TJ#!!GVO7G-<=4&Jo{9lk|8xM-1-ozML5Nr`Fzz?F}V{!j|_J z;F#gD0qGSicyCEt7aNwj32Ln_r8MqZoT=2dH=~~sQUc9rg0uq4O9-g%H?GnMN^p7} zjmem_N1suRX~f@E!iT0fmOPVWStXecF};RhiV}UeF>eN?)`=)0?fz0JW@59USNZq5 zd^UxwA@R`6$S)b+1}`&}-;!?`(CzQUfzj_64P9%mT$j;9X_%Q z_V)St1i*l;W-69%j8QVOB5N;K)p}Q`(D2g%r^Y0hqYPymDfZYu1|x=op-|SYtj6Cz zl(MD0lT3h((-9EE$0TiSZG1p26%Ya(`w$oba&l?8(M7ZuK_Ce^T3JD~s533#)PbZ> z60vDgBuwou;d7gBMSlEx|3dPiw^%{Rz=CG{TS<0mVu%X`d*kn0H!Vc?4|y0dDTYE1 zbPCD3kTnOHn87$Rk1iyj;o8e8OZeUsZ(9#U9oH>-)CJl?fl&peJ99AdR_N}b2_z(O zn^iEhWTZ%fRv#Xma*kJ43IqBVJy)c1LsQ%c%?l(=PYArzLcz~z`}>@zhvqgQoqOVMJHKUE6bhKhO7FuY%i%DL?v>CRPqLjH)# zyr{9JCQ2c_Wp8WE51gDiUjabiJ{<%8KYDKJb$}%cl?1H zGyH7`FsEqFDFEG|m!sjVar04P;NtHy~mJ}^Nm$$RtMAY_QT@IxeB-bTus!; zV|!5Tr5rVgY)YtyicU$gO6>@=*%NF0xtr~TkJM$pKIA1HI!{b09hQn$3S`2eyrA7Z;(zFis}| zay!QG03K19pnh3d{Uap72!^cQ*v8|#{7M{3>TvuK zLU!;J?UFcOgG}XtEK!*TW4yFYS$qOgtG_lKl$pDtb>H6*juaA9(?JBeP90*?$ur~p z2f+B*vD;w>_+Z{=v!8`c4c~WqJkTMzQ%7y$wBoF@I4Vt~H58b&V*r4@zZ@w=J_$Y-|+yCS#kr zfEQO2-LUgW;+<;lNk`G)33H)NhKf^w@ffFA7@9q!4KnewcP= zo8p5d?a24%lM+W~pa%~5^`8#{FWJh1zW2Qc3ditB+MpZJO@hnnnD$%sovhn^G`UO zG#|56)Eurr_RMVA%rSULbfA73=Z41eM|A9&tKKmRpu0qW~+_qi1?H~FdBYv; z+n3*R9nq>@U)=H_a$J6Em6!QwICPSx)-u_VP;_0Hv48*p^^rrl?L%w+r!9n-;ov0M zSEk0zA!hY6oFCE?`*Qq4(yVT!d>T4UYg2CKpl9HDmV(mPO>wC7+t_4mZki;4NAxc} z@Qa*V1~e<3{hVz&J>+vMwHzKxaoulBE@S%cR)Mf4^_SmhP8S{^_^71%y}dk~jvWx8 zai!Bcq8W&FkBA+2Zc}zbD?o+{42e=rOiW4d3%+Gfb0;pEfy^{eRhFhBk^gI~%O{0( z^n0>VYrq$pR47k&*8LL8;om@#cl)XMHA@_oR?SsN8~>>ne`osO!qvi`97`((aFEzz6;bI?V3U{F>J zA|ajR&OqHprC};kySO-#1(TJw^C|Mvfh?T`&4Z(0duKf=4JpC;=*mNhXiFoYZhKafte!YV80)Ld|WtwcueKBuUgPKN6+71(d8ou)79{ zAnR$80X!r%G^jskRSw}`E##x#p$<9S>PH`{48~YA<&A*Q`^FShcBYy}L@)s^s2Yez zeKe{YY`2@joLRSXB@{(-C0!XOx?hPaw!=*L5#)5^xe}TfVA&03#Q+-v!1K6&S=bJD zmod-(?8{}9#OPRn?~0#w+~)4orY0win*^Rq(Wy?{m84%+TmNb8@Z*JI1IJ6BY`HNL zkUjt+1_HE9ot=O9_`Gp4IX57tj5~W8G)2d+f32EntJ;|5i~cCxh32CHMxeg_x0YJsCsG$p}#tz1@w&U>^<7ogwH$wdoF1+mbU?0$RH{ij>+I2v@ z@~rp;SJ?oB2iZa7Wp5FQV?WC*lYd9d4ltnM5GmGjhg@*Nt_~cWareFVAE_923ZN={ zJ32$e4tSW$l}XFQ$?}ID2aqJd?MbdpTw1Wrj_$_}%}Q)pT}M*l<7*W?kgd>jVibYr z+}>i5xoUR?p@qOqc6s1<{Ymu9$Z&Ta+N8-e%d4iA_ImB$+jrmk+Ooed-fkOZ7DMtN z{mMG0iK3X=hf~9AwAFuhLk{YnyAP+jOHO-M?Bv|d=AD%QQ++8N){PAdcR%NzRQyVxT=#ILWRh% zQ!3rNe`io~7M(HS(qex8Oqhzqcv#*DOWS?L62_hbT{6-zuXj(Evb%tbj>;cj3mXSI z)@9WI@+o}uf&Rl}_W8Zo>1&<&*%Taz;JZ&n23hHR6$x_7!4#ocsviQj(ZZUh#3`MA zgA|4auhg?Yf6jHxC}52pz~x_&3*!9a+2>37J{0u!jE5~l>L4KqJYcQOVL(_l(*`i2 zct@!W$(rM7Kk_xEUOML2!OEm6&7%_OD$*Zk(II{bz?_Zv6& z=FHw7`g}XvKNarj=yH&w{nnLhXj3Ou`Eipz`qDuA`-ms*L?^ODw?sv7A@9M>&WUIC z?Feh5SMDtJu=%#3@d6|4=qpdIyd^cWonZh)&DuAQ!4hY|0B+f|L^V><$#LAYO6U^^} z(fdHqb6U1XYfyP8J5_kUFT`5Vmne;Cr!kpy-Ez3cD1<*;V%+_uGDf@r$hufb!F@Vb zglqR6wLo-wT2wH~|7VKn-(!8?j1KqhZ*{K*K5R}xYCRCyOqI;ZSF)%sj~9YNn&v!^ zb~oet1edh}jBU&S%zn_#P{v6>*W(JrtvZXk(X<6tO1R*6MxSPCMgk;ByR-^ylgp(x5cq)@Qbm z7Y045%~FtGyU|(Do8@8ETNhnqpt)IT2&%v?U_BhHVfm#}ps_bq1^3T&Sqm4nN$*ru zi0QW$G@<-;-X&!Z4WaG5+#ow=wW!nG+NIw`Z$wicvaZ&59*s)dQ;&AAr*m|en^O`G=Tt=d#SXv9i~>q+~w=rI@)%5^nh$@9IzZKk0Jbp{Jbuz(-WfSFyq7*4h);mz zeUUxgVeYfuiRww=qkQpULEA!NMcP)*Yip@FEf;urFkm^N06)c<$nqy!Y?#OaXDYW> z)v(JF-zDt!J?r<3gG0wZFfR7?iq?Lz((Ci{YIXWOUQ|Bn6f8r-ZjmSfZWBJ8*3tRs zHSlS;l050WR3))aS`7p9O+3WewZ(m>I2rG0P)5SszwL&A{<$dv`Qh#R?$2yW+7;z@ zRl{IZ(tOU&;M~hx9Z%r9Sd0!J|U@Nx8c19Oq%MKYGp=e#=)Voiry)UsMby zI(krL^{qou6xN)GubP9YQw3^G_GmpRDpEUVg3j1v+qyO|EFQ@b*nG@A(|CD_Nzur= z`Z^>qqAA)ZnNxm6Yl5xXfrNlKU#h%6#huYn`wn@Xl8N8){bj#5$N&nsC*wxN|Mbfp z6(4~h%m2WUfr;*7ZU<@v?CFV|bQe4&$wvAb;4?u-3mO~OXWNV*nu)Ic)vMo3Kz4#$ zbbi3;VzX38G5!nvU(K||<-5c>wD@XhcDTLgdR`)M-`>BOmYv+p3M?&Y?GmxIKYyN< z7f6rYu&B3(iZdh#C=7-dh!a3{i2~khS~kSOvZ8D#BJ~(?fRU(C4$|-+rM7e8@k`xo zFL>N+&lEqoI5wCf?p9Fbm}QK!v9}wlVa*IQ>8tX()t08YZuKKX(EP%lnCJTft$Th5 zbQCk9%M=Zn#O(b_#_EzE8IjISTW~XD!W)6L;#$b*QpyB@L2jvm?o{YGaKweU7wg2KRwVBej~QJ3G~KoPaoje6JEY zuja#2H7xDQuw%|K5#1Ny;x@wEmcp2Xh%tsuc~D;#PxI_#VR?|K9K0=1pD(?_dFQYS zN?yvYzrbMqh*)p#8*O-d4g-45Wk2)oq`9WBjLlJ#rYds1)Ha%h$>69eBi=sKui??`dAcB=JMqrO#77*^Gs* zKB0cAP(yh&&3e$oSY+A!WVm1VK5JP$^^W!MogX+Qn{B4~3=NVDtm(y-&b{1{wTWN^ z2e0${KfE`!4Ts6pCgIJf=v|qYUTENE`x6qIX_V;4bVdY>*@ak4rI;g0CAAUo_;AEq z=g5X}jy3!`04Rb6Y&Jtu9Ju2;bqE2YI#Y!V8-8aq2Swh?{6>r<%K9~<KUC@X+3 z`}1BP`?bl6#-h_pBrvi1XGf`sZ%2NUZZfA=N4~Ya1>qTSGZP5RRAkcm!3`JKIPA0DrY3{u|y@XuoiUYzO^1k-5<0QpQjBRUZX zSOq5C$&>YZKtL-gwjW}OPp65w5&M=M=9>kieVTT@6DB4kss=`G%xF_D4Ko_>(#f9% z3GCj1xg95B-CweJgQa%;%Dkcdm14PW&U_Tx?`Na}T;{&8MPr!C+TV}DhI3qlNOn7e zkTCEP>y{p>t;C_SPyP5oo8_cEmQBET-QRxtkoEO}`e_L zsFnLIqNXu%YeVH+)y8gbi@@AquXoWc?}79}k`ov`Z_+R*w-o?bEhwzIlrY+KuWEcE zX9yY~qC@$c4yLhtr-CZz+Ji!-IXwD)7N4M#vW^f&3qEnqgz@0~0*CM=X}c$$sRj9| z+0((j`JG6~{_ye5P@aqZ#q*YSj>O*U@!nk?w8M9PejYFufyRn&?WZ`a;K&;;WmM=L zw6^&4hY|Ya?1EI^R~)!bDuPy%<^ys=5}TPr*bRAe7m19|)r9_^3xFJR#w$F#7y@mP z6!M9*fO4tGMZAylq?Dlf!vdeKyR$phR=YXKBCPILAKP;$A~2Tkf`jtYmXk+7ngx6s zt+~&?5^`4!dx^cC3NsIcoo#70sLhk1TF1v4f3f_wH@t3e^!H_%|kISm|O^(bfR`#)?zT6zW*xdy@VYUo+UxT>u|n z9i1H+|4@|>+G*JGwovZct&s+b=PDUa1I^m;df>TR%%-3e{rF9hH`d(1ub=9!23K-eBMNM^yepJ#bev({P{eo zy#q#_YS_7$S?8Vwr-A0eoFxHpcVi;NKFzkf2w#P}&L;CG_^gvK8@|$n2f2 z)AyuU_uM&mO=gq2vZdhFIgOieD$8ldWDQ{x_`=_2P79xa-axiV653wrjPwXUWQb)e zw%3Cnl!oUPOT8_-)}FORuJ;V>&r@)q#M|yu7)-u?;>6!RvwFlV??({^zWaI|J|{>g zT{wTTVQ>8zh%b|udEO2)5w3_-VZ~9drahL+!mf(L=4?`o!hw!Dvxm#ZIhi>>uQgGz z!eIM%;H~4Y(4oxV<0K5m-Rxbk58q-jmE5Fao>KH{w zPw2)A@Gvl5-!tjb+sW&A?RiR#?_(zSw~cE;#nNtB1x&iUEGcU^@uLq#J&eQ$AbPJI zDVr-#F?2?jf-MD4nF@CNMj_#Ib3+eKeG)(7(-6ZQ32-)Dg@PM=7xElEr33DHxKpRa z7?swtMZ_v(Cw1s(UK1@`h0HB{F=-mD1{gMcR*g{L$8)Lht^Poawxs-#P(so)(HbKe!}7d6S@1ibMgvcEr>yB?q47H zhGYqh$w-)o*w|h__uu0GdFT8q693e0IH6(k?NQ0Xm$f&y|Eo-bJAE!f1OWDzxZh!u zO<;d!aG;FhD$xHx`MRgR>%3Z9;V334B^;B3VIk9da%B5bX=zRQ+1A7l@D|I>3sjGY z-~NmZT9lPSqHP=GC8ok6nN0|8PBaRrERC1R&FuU65UDMbpkoy*Ng>qIY(lL%o*>6j zpv8zQoJnNdD4AQrYmp3YMq^JtM8Yaky^IX%S30+6ZhSv+tSYs76xN zMx3_+(4xFSmSIK~x=e?@a*)JFf>7U=6iCPFl#fuF5fzv@ImhGG>=dH2w43!E%UBdv zWF{@HJB|;b+-HS{V<&yXRw3%t65Z0j@RlELccK@eM72kSl$kOO^E8yUU>=AXJi_!j z>>db`>-RG7`f{bw12Y#KR0RNzPII#CxbOh4TXI_XnNagJHA(A|OdZinuA55-=O&eO zye1!~Pru7Vt5;h`t7C_vt82;;78s|YlNTi+rc}f{W>qz}okXo5Lmc(7RDb`&=j|4{ zPrl82!%Evd;g<>Eq7|t;ulgyHPG=9vLp=@3bia9lnE&3!#v>Bq4P36VqiKmY+>*N= z=`fi8cdpk*vC4q4KT2F!Z5zW?uIOYS@j4&rAhE_{+~Rr_vm&XAcL)fu zRFtNZt!B6gcb>@&%832Yf2*$C+D5vTAr}HIJ!IGB>&&Ji~*C z_gDl-hR><`y1E_gFRH6?c#hb`9Ue|`IvNddUT$XZf0J)fK#h6iy1s)XV%o};m(@#( zLbCuOo&1jx+EQ9%^kjZm1TD+Y(LdwF(1dyS;RA_aA`_+=woin6vUKu+swYE(Jz0^C z2t$*L-kvQfBfcczhRBJ%>Ao1_kM*(tn#IsrhFB-MtunoY_P<^X?ZRI8GkeEWU>@)x z!2tbBR!RmHv3^NH8|V~+&C{jC5TbF2F+t5ugay8*ZG=QLo|3t}a_TBr{<(^D%6sq%fa8`E@kqz zHg?;r_~fmU>}`MJkX|^LN)dbf~EwQ-5%Wm>+f7?8!=UM_+%Jx%e?(rDqwI zwQ$fJvz%MnPtvau$`>cB`m+RL>nQ{;m(WNi_$leAIiCOkf%t`{!GFIN8XybCVhV#@ z;-U+vCmKo_CEBzS2qJ7zQ1rZ+n^#)dN#Hz^L^% z2LixH?5>w>@ttgHFRwBm0vGqzfmpvmN!H}&i^%zOrGrC4V7`a2#42#_xdow9y%x{^Cdp`PUbH7uUE1TBo&yjto8JBlcQjzf^_?c*uK) zHK=>l&MhQitRmSk9HD}*W0~Q+eX4UpYx59^Y`R@Z%CgIgf0sOJvbTG8xF{A&K%Pia z$(zW3({+r;^rMgD6cv+H48d?4cOR^0%fe>_uF*qvH+tOxkpe}mk<*c(Q+=+Ys=4XF zL&a^=K`zDqzyS#dLR!t=aGik5@%h~-aGYnl2c6DmC)A~y)M{*EVwKp0Vj5gJo*@R$ z)(vv_@dl+>l^+d(ihn=f8K{Gj7S@B8PQ;$eue3JH8EHo=T?2x04CY{NwetGev~&A$ za0F^o{UxP1ah{wdz2+|AwvG;A zxWluCm+JCtw8nAHZzd?NoPtY)Nrh=7bFWgrjw5wmw{YdjxB7eoz5N$x41`;L8Wb@o ziq=3B4Vi?Kxdb>`C>7C*z(V_ZOZhA_>e1@5Gr!^I%EJ?wRAb94y>}e>_`ONhI=U9M zc+Ma00y-8wQ$2+WD%vBNe!;fz#0Jom;>trRD?5CgNQ4jc&yXNph94nG z6Q`mE6Q>LZ%N8W0`N;RF6tPrM5UZ!Vo5u-dg?p9Uw=KGy z)(-8ezNu@DClMuDAk2ptEZJ!mOf}Zz?H~LDxYmllYOAqOE^!NV#K1 zSIb#%$x}j{z!*_VvDB{OuaSU*sSJz`c#(_g!4sf;>-p0Jth%NDi~6HA%kUF`th}wr zLm`49=Zo_ZSY+2)tAIvwiMQKMnE6_J4XK(5l=h?dEfrniiU@M`{FT9{Of+F~Bm3uY z<SI=zy8UDva#I<(Z81TD=TWeL;A7s!A)Nns`5sEX6P_Imqx2k>fKvTp>}n`TAVsVF4LO_+@gYnH2zM-#?mow z0we(^GBDu1@D*}Sa#8Zm*LDderF@Ss56`#w$;l%s;h(PSh#|b99Uj!Bn(a6>|1{vx zfmae(e(_G|;j13vcz#Zrt==DAj=Ceh6AjB9MSjvU&$Il#E*?FXjPp_DA2z_pI8#xL zEX-ByNxt^Sbx0kWs9!&*pm*|AaAX{CM1|Z~ik?!vdWT)t?m>E41xwpR4ejHTVLwDg znGi@g*pd(xu4kaG8ObI~D0;0)$(;?xi%i_oZ0eGBL-;~q+-S1nwQN9{D+uajxgsQu zgFU!SR_@LU6fnNAR+1?=!EoHP_$0`dWcc~klOS#&`aqeDt+B7oml#%QzRjrD}D&+<7E z+gYzjmBD#3{cXoCZYh-DldPUH)y#?F&Ew-lI_T9$9iO1xnGp+-f~UEKJoxL^I6eLz zg8e-Z3_RFQ=VvD|bvDI=8y9wC0qlWZ(x{x4jA$_Ve2>DV?kC$i>%-x-dQuuLFdgLw zv<*i03cjQ-`k8WVtef6mx({-Jpsu)v6^MJoGqTrf4Kyu{&!n39LtMuVEazW`0dVkp zi%hjz7S|B=z_q^-;MggBL{;wQt*1F)9W@WrO&&{rJ7gOQY5XzXZZA80R?0!X$WKJF% zDe2u)VR8ZEhQ7OFo%!4y5_G2MT*62SFX~?Twaeqd->dK`41wtIdGQ9o2zJ}3q-lR* z_NX`GsXy5jSK22uXTcU8&6dcx(2Yn7E4eT+)sl*N{`jFC4!hdh8^gGihpv&B;Lw7b zX~AM?0aKs*r z&`tUzzr5bqcCDn|^Y=%NHOjqTzp6tP-an6%ADy%-Q9bhJ5`usLiE#J4xTDIRioV%+s}+W$NMyK9_sMmb za+ne)lq;~(4cX?Rf8D;KVmr$fvaieGrI&+|;lm-zS?Y;D!YAg--lt&)5l~tlf9b8G zhHiv|=zp)R1sNd&A!FXr*u;zxxh#X|>Zo=c-p%&g*vPLhF7yfWP1e@85mj9uC;((Wpq|w1L{jZ0INy%+v4M2blSTdd^2edPGs9& z7S3yfu~E?IenfsxNwI~A(VERFFWc=7+70zeIIzwu&=ZOQn3#0q^G-Z<#9fd zlDD=0Atqj1qt-a%pfJWjS7uZG%lh|0i;y$93!L_AZ7 z$q$`gq}FC*!O>{rAM;cH3bz^QAKzv;1-HrfwP$5UYO;-Gwu#N15@bGnN`QZ~bs~L+ zzvHzOpNjY`lZQY)Pm2c8;P2nT$aI8b3D?z%&TU|sH3ndz)1ySx^E8n9^Ga;Y*>qJ* zEOTZqx*-VLNaCK8$ z(A*xSgIR=kkmWw^iD@=qkO+z`bfR@AH8|kR|KW9T!&XV_WPdXq8KagF2Y(HYReA@7yAITdp6R%r9DT()$Yo zJqYkb5?aVgm55Ps?yginF=)ZJ!d0 z0fqC#+{7=HqjWT9pWT$&gvIj$11eAgeLpExn|#Vx&2!EHW`SJqhRNh0NntuIz7-}# zrc!CfpN;yI5<7o4eL)mXT`8h(kNa#L^3uKcm{iW$F)*|^U``Wa8nzXw$#-+go}}5H z-ok&MymG92;?X=&7iy;O{%+>1y2^u%Q<{yy?#Q@m-%G)GarS3O7nl&sq>^94pA67E zVW3|GR!Y1%+`o%}%KwA_qE{%H(4elbDi}~a_siJs0-c*BMyEDrTDUe^z2@M-SsbMD zh1!JBSWh8i`IR5*SO4)HX#}O1{`}NQuSXQMDp#1oKyZJwj(7Glbj zl1_4b)-7|Q?ybN{mn~JHvTk(zdn#SB8L1LomR45vd*Q?>98Z<%7m95ttisNE?Q~fQ zS@v4?Ht3C<2{!@=ny9`Km&UKZ5m8)Q{qY(K;PzP}>3Dmc@-Dw{3q7eGM?(f?5*zb~ z??g<0k9|CE5=@!)mvVrf>|*WLqD&)QRkdgLs&-$rIQM4p{z~k>Gekb}05y||1=>q) zI1UwXJy-WQ)B?!S!u6EVL;pSzFPz<@vbRaWaeoFIOu^jxP|T#m(o#83#U8B;K}P7< zw5n0f_Tm>;HJQ7R;A zSn0dDWl`FTR}Vu#j{OW$2@L4J9;vf@V**QN*HAis1nw7Dy8d4A56ZgTqjCTZD<;1< zfKGM_!w^p7rKyInm-%D(uplaCpz>odCy@C^%!RnA?4Cz#EFV@~1twq~sN z09cp1q^DH<8>WfM3FPOn)|3{{GPI?{s=>1cgXb%(PoQ^9ip7)wpjw0!;so>ej_g>&)824$$E;}Vs_>zbw(tr%5@v|!;@monT9Dc#-$PvZaq?#y zKLD}hjtB)Mq46Xi8oP-q(XuN76a1GioQsmlsSSn!FxQ_JHs9aKU-6R4d!WmX#L#QZ zc0ILUaADAgX+?H_no}}r6SCO>V2zkeF5@3$77!m6Z!bbpxmTp5i6|J9{)(0|P6bxC zAxnm(h27RJgsMF(y`O!7`l+TfXQ|u*fdZ)ZPsr%5I9xz~6s5m{_Xm5($#1t_qWO@# z9c#b-D)INn`=vLaKlqO?2(byfQSHh-d}Y=I0G*PLfRlS|q|(4u0I`1FC;TrCzEHT} zFdUoex`9H~c~u6T3RswnqmWE@)@6PB?{c|a`U^1t{tvbMLat>@Y_aE`$!&I4|IF&* zi&bE7_%R0)JT$?N7VJXc?tUSJeCC$QErF%2;KxnuAx)vMhoI*4BnF2O8gEPop)+g$ zg@GI(rr@@EgG*LgP7oEsf%7;6>faAaZ)HkWj6~7c#gO`cisc5w(wcFx#Ev#|6z>9U zN4IlYFB$M0S7ETf`~K%d0L?47d49=_)90F?BScho)xS`L0!8r?JO41r7L8<6Bh=;- zDNNWX8L5Euk^!upIr3qqA26u=#X%Q2(50FwRes{Ta_m*T`&bwPqpiEjtmHRltl}j? zY+0xypp#PJgdvQUG$7CVfq#>%vQc3`f97b@*jZBp=|dCJ{K3Cf&@~k$;ex->>q7_7 zTmFrQK(GA@;ekGa9~vW6!Vvy@7}N_$DNVeKMSl~Cvl+EfybI|jU$;}re5QiJs2SEWl0 z^x+rez&@46jt#=M5#Ra74UM9fkg@as2E&ulP?1VQlt~T$yKxgsEJ(~0&+Vjw?G0w> z=>IMP0f7%>3)CY@0$Q2)O_$EdrJ5>>CQ>QZrVF}ltyzmsSrQ zQ&dC`gVAu-ykP8By1wVnA${)ISE+pe&ICv_!)clwmuL_VVQ5nE#FviYF`QP;+ z0H=Yv^v$Rop<)!M%!we$CEaTk!!@XZjs=|(3g@r2F%;Li{Sf*}Zs}fiE2mad3SjXw zL^4qtK+!vg3OI8X|M?x9@)>%Fu10PooT8OYxizzOWG+IWSg=;^c*=>L5p=)-n1GxW zjQzLIn9^kW<&P3*Q6nvCfkKkLUaCjxM7OY%&xMH+NUv|Le-n9uqP6skp%nRNdj97U zNsgpv{BT@BEH0)r~puoWYO7#RXcTi7+LE{aLc9w4LBKw%NBrLmwTCD#vx zx0P#XEu_a)>ovA2M@W1)qrAJR#wP3=*Dz_i38vgGi7i!+9fbP`oR$g({}zzhIqC`g zSH2{ue|Q_o$;cwQC(#5d1;xyAXx&?Bdb#R!+#cL(f*A9san{twU|>G{la&t z`kb4qfd$Yw1be$*Q6R)$s(B+LO7-T=XMm^GLczZ~5kWWJHz&+h{LY}-{GEgxS-syo z8o{|A=};x%?iZv016&j3wHD&ot-WhSt|=)Q)8lL~kOnvKXUlSHzF3Ni$P}op3Vb#V zW%)~jWe-?%Oug2@r86u~U@O=$V|-w;4GV%Ltu!-|?#;g}4S@dj$hno`-1bY;q9{4z z0CPVA3S>4-?D??^6QrOx6IlkH=Om-nHxmuzkn+db(0o82w+qe)b)khuaA*mimmV$u zSwC0Y23!ba#=@oiJa6+q>nh?X?shmPtGMup!z`z0wt!=uBCg7}^CoRo5?Zm$qk_lE z)B61BP)@sE?x@aC(}X9hPhCm2Y-16r|Ov~!m2wy;J$ zePDox$_*IKrFHatxw1?&UXYVfCn0K05hRhQk?(zxg zeD};>*^uG1uT%cXPcFcY!j%Po z*8*Kqr_4C{aQdEm{>N=oj&E9`RH-#Dmk3)I&biBOtSawi;SEvl zyP}uX%7mp<3#V2(Vms z_h`uU?WjE@U)t}&VsxdlA6O&=2*>)nvJ2hRac4TU*X@y8@3y_(DqR{IXIu@t2t^TI(Z;fWq z%$lxX$HbfzkCpAyj9y!Bn$R%s22bh6wJAoD9Lg#V0xBHhQY9vhH~TiL1KVC(ofoA) zl@@)Ot&rNEEn}&6h>bg8?@EoVi^*4Bta{({!upcQMV9p)uY_J#DJedkkk`HF_{jru z>Yx_Z)R%hf2g;>{QXQ1DTE!CD`g_gQE>{k@9A2}tW+6Hg^(|QcdOdK@NO@ss z8Li{=PSKdTA5=(RoAAJxU7n}hI-0K+VM@Q)k6VTuQE+^P!xhT9>Mk9*FKkzqPw|I|GO>z@%q+y zU~{aw-R0oE^Lg_pN=U5&MpUEoqN>RrDZo15fMQ|BefPlTm-CjM^f&^vEOhnjK0ST=iR&iuCRFf?j1;K?y3v?Dtuf1?OjmvYuW^ZkM{CcJ+|5@ zEL^+dZ?)sWr`NYPy9oaO9N7ECd~vzTwC36x$E>QKWfM9c*4wRGxXD(zaKgLS+))vp z_t}I*|Eza64O|(nGNo?6(o?Ys2BLrFyMLYExpj6;+rba34 z8RmgTe~DWM4f|E}Kh diff --git a/usermods/ssd1306_i2c_oled_u8g2/wled06_usermod.ino b/usermods/ssd1306_i2c_oled_u8g2/wled06_usermod.ino deleted file mode 100644 index 8c749603f8..0000000000 --- a/usermods/ssd1306_i2c_oled_u8g2/wled06_usermod.ino +++ /dev/null @@ -1,175 +0,0 @@ -#include // from https://github.com/olikraus/u8g2/ - -//The SCL and SDA pins are defined here. -//Lolin32 boards use SCL=5 SDA=4 -#define U8X8_PIN_SCL 5 -#define U8X8_PIN_SDA 4 - - -// If display does not work or looks corrupted check the -// constructor reference: -// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp -// or check the gallery: -// https://github.com/olikraus/u8g2/wiki/gallery -U8X8_SSD1306_128X32_UNIVISION_HW_I2C u8x8(U8X8_PIN_NONE, U8X8_PIN_SCL, - U8X8_PIN_SDA); // Pins are Reset, SCL, SDA - -// gets called once at boot. Do all initialization that doesn't depend on -// network here -void userSetup() { - u8x8.begin(); - u8x8.setPowerSave(0); - u8x8.setContrast(10); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 - u8x8.setFont(u8x8_font_chroma48medium8_r); - u8x8.drawString(0, 0, "Loading..."); -} - -// gets called every time WiFi is (re-)connected. Initialize own network -// interfaces here -void userConnected() {} - -// needRedraw marks if redraw is required to prevent often redrawing. -bool needRedraw = true; - -// Next variables hold the previous known values to determine if redraw is -// required. -String knownSsid = ""; -IPAddress knownIp; -uint8_t knownBrightness = 0; -uint8_t knownMode = 0; -uint8_t knownPalette = 0; - -long lastUpdate = 0; -long lastRedraw = 0; -bool displayTurnedOff = false; -// How often we are redrawing screen -#define USER_LOOP_REFRESH_RATE_MS 5000 - -void userLoop() { - - // Check if we time interval for redrawing passes. - if (millis() - lastUpdate < USER_LOOP_REFRESH_RATE_MS) { - return; - } - lastUpdate = millis(); - - // Turn off display after 3 minutes with no change. - if(!displayTurnedOff && millis() - lastRedraw > 3*60*1000) { - u8x8.setPowerSave(1); - displayTurnedOff = true; - } - - // Check if values which are shown on display changed from the last time. - if (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) { - needRedraw = true; - } else if (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP())) { - needRedraw = true; - } else if (knownBrightness != bri) { - needRedraw = true; - } else if (knownMode != strip.getMode()) { - needRedraw = true; - } else if (knownPalette != strip.getSegment(0).palette) { - needRedraw = true; - } - - if (!needRedraw) { - return; - } - needRedraw = false; - - if (displayTurnedOff) - { - u8x8.setPowerSave(0); - displayTurnedOff = false; - } - lastRedraw = millis(); - - // Update last known values. - #if defined(ESP8266) - knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID(); - #else - knownSsid = WiFi.SSID(); - #endif - knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); - knownBrightness = bri; - knownMode = strip.getMode(); - knownPalette = strip.getSegment(0).palette; - - u8x8.clear(); - u8x8.setFont(u8x8_font_chroma48medium8_r); - - // First row with Wifi name - u8x8.setCursor(1, 0); - u8x8.print(knownSsid.substring(0, u8x8.getCols() > 1 ? u8x8.getCols() - 2 : 0)); - // Print `~` char to indicate that SSID is longer, than owr dicplay - if (knownSsid.length() > u8x8.getCols()) - u8x8.print("~"); - - // Second row with IP or Psssword - u8x8.setCursor(1, 1); - // Print password in AP mode and if led is OFF. - if (apActive && bri == 0) - u8x8.print(apPass); - else - u8x8.print(knownIp); - - // Third row with mode name - u8x8.setCursor(2, 2); - uint8_t qComma = 0; - bool insideQuotes = false; - uint8_t printedChars = 0; - char singleJsonSymbol; - // Find the mode name in JSON - for (size_t i = 0; i < strlen_P(JSON_mode_names); i++) { - singleJsonSymbol = pgm_read_byte_near(JSON_mode_names + i); - switch (singleJsonSymbol) { - case '"': - insideQuotes = !insideQuotes; - break; - case '[': - case ']': - break; - case ',': - qComma++; - default: - if (!insideQuotes || (qComma != knownMode)) - break; - u8x8.print(singleJsonSymbol); - printedChars++; - } - if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2)) - break; - } - // Fourth row with palette name - u8x8.setCursor(2, 3); - qComma = 0; - insideQuotes = false; - printedChars = 0; - // Looking for palette name in JSON. - for (size_t i = 0; i < strlen_P(JSON_palette_names); i++) { - singleJsonSymbol = pgm_read_byte_near(JSON_palette_names + i); - switch (singleJsonSymbol) { - case '"': - insideQuotes = !insideQuotes; - break; - case '[': - case ']': - break; - case ',': - qComma++; - default: - if (!insideQuotes || (qComma != knownPalette)) - break; - u8x8.print(singleJsonSymbol); - printedChars++; - } - if ((qComma > knownMode) || (printedChars > u8x8.getCols() - 2)) - break; - } - - u8x8.setFont(u8x8_font_open_iconic_embedded_1x1); - u8x8.drawGlyph(0, 0, 80); // wifi icon - u8x8.drawGlyph(0, 1, 68); // home icon - u8x8.setFont(u8x8_font_open_iconic_weather_2x2); - u8x8.drawGlyph(0, 2, 66 + (bri > 0 ? 3 : 0)); // sun/moon icon -} diff --git a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h index 67c78feed1..08d551be02 100644 --- a/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h +++ b/usermods/stairway_wipe_basic/stairway-wipe-usermod-v2.h @@ -111,7 +111,7 @@ class StairwayWipeUsermod : public Usermod { transitionDelayTemp = 4000; //fade out slowly #endif bri = 0; - colorUpdated(CALL_MODE_NOTIFICATION); + stateUpdated(CALL_MODE_NOTIFICATION); wipeState = 0; userVar0 = 0; previousUserVar0 = 0; diff --git a/usermods/stairway_wipe_basic/wled06_usermod.ino b/usermods/stairway_wipe_basic/wled06_usermod.ino index a0dcc3bb21..eeece4438a 100644 --- a/usermods/stairway_wipe_basic/wled06_usermod.ino +++ b/usermods/stairway_wipe_basic/wled06_usermod.ino @@ -104,7 +104,7 @@ void turnOff() transitionDelayTemp = 4000; //fade out slowly #endif bri = 0; - colorUpdated(CALL_MODE_NOTIFICATION); + stateUpdated(CALL_MODE_NOTIFICATION); wipeState = 0; userVar0 = 0; previousUserVar0 = 0; diff --git a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h index f2864362c9..c289cc32ad 100644 --- a/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h +++ b/usermods/usermod_v2_auto_save/usermod_v2_auto_save.h @@ -64,7 +64,7 @@ class AutoSaveUsermod : public Usermod { PSTR("~ %02d-%02d %02d:%02d:%02d ~"), month(localTime), day(localTime), hour(localTime), minute(localTime), second(localTime)); - savePreset(autoSavePreset, true, presetNameBuffer); + savePreset(autoSavePreset, presetNameBuffer); } void inline displayOverlay() { @@ -91,8 +91,8 @@ class AutoSaveUsermod : public Usermod { knownBrightness = bri; knownEffectSpeed = effectSpeed; knownEffectIntensity = effectIntensity; - knownMode = strip.getMode(); - knownPalette = strip.getSegment(0).palette; + knownMode = strip.getMainSegment().mode; + knownPalette = strip.getMainSegment().palette; } // gets called every time WiFi is (re-)connected. Initialize own network @@ -106,8 +106,8 @@ class AutoSaveUsermod : public Usermod { if (!autoSaveAfterSec || !enabled || strip.isUpdating() || currentPreset>0) return; // setting 0 as autosave seconds disables autosave unsigned long now = millis(); - uint8_t currentMode = strip.getMode(); - uint8_t currentPalette = strip.getSegment(0).palette; + uint8_t currentMode = strip.getMainSegment().mode; + uint8_t currentPalette = strip.getMainSegment().palette; unsigned long wouldAutoSaveAfter = now + autoSaveAfterSec*1000; if (knownBrightness != bri) { diff --git a/usermods/usermod_v2_four_line_display/readme.md b/usermods/usermod_v2_four_line_display/readme.md index 367f3d7ac5..47518be905 100644 --- a/usermods/usermod_v2_four_line_display/readme.md +++ b/usermods/usermod_v2_four_line_display/readme.md @@ -31,9 +31,33 @@ This usermod requires the `U8g2` and `Wire` libraries. See the `platformio_override.ini.sample` found in the Rotary Encoder UI usermod folder for how to include these using `platformio_override.ini`. +## Configuration + +* `enabled` - enable/disable usermod +* `pin` - GPIO pins used for display; I2C displays use Clk & Data; SPI displays can use SCK, MOSI, CS, DC & RST +* `type` - display type in numeric format + * 1 = I2C SSD1306 128x32 + * 2 = I2C SH1106 128x32 + * 3 = I2C SSD1306 128x64 (4 double-height lines) + * 4 = I2C SSD1305 128x32 + * 5 = I2C SSD1305 128x64 (4 double-height lines) + * 6 = SPI SSD1306 128x32 + * 7 = SPI SSD1306 128x64 (4 double-height lines) +* `contrast` - set display contrast (higher contrast may reduce display lifetime) +* `refreshRateSec` - time in seconds for display refresh +* `screenTimeOutSec` - screen saver time-out in seconds +* `flip` - flip/rotate display 180° +* `sleepMode` - enable/disable screen saver +* `clockMode` - enable/disable clock display in screen saver mode +* `i2c-freq-kHz` - I2C clock frequency in kHz (may help reduce dropped frames, range: 400-3400) + ## Change Log 2021-02 * First public release + 2021-04 -* Adaptation for runtime configuration. \ No newline at end of file +* Adaptation for runtime configuration. + +2021-11 +* Added configuration option description. \ No newline at end of file diff --git a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h index 4f172c10d7..f8c3d17d43 100644 --- a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h +++ b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h @@ -26,6 +26,10 @@ //The SCL and SDA pins are defined here. #ifdef ARDUINO_ARCH_ESP32 + #define HW_PIN_SCL 22 + #define HW_PIN_SDA 21 + #define HW_PIN_CLOCKSPI 18 + #define HW_PIN_DATASPI 23 #ifndef FLD_PIN_SCL #define FLD_PIN_SCL 22 #endif @@ -48,6 +52,10 @@ #define FLD_PIN_RESET 26 #endif #else + #define HW_PIN_SCL 5 + #define HW_PIN_SDA 4 + #define HW_PIN_CLOCKSPI 14 + #define HW_PIN_DATASPI 13 #ifndef FLD_PIN_SCL #define FLD_PIN_SCL 5 #endif @@ -71,6 +79,14 @@ #endif #endif +#ifndef FLD_TYPE + #ifndef FLD_SPI_DEFAULT + #define FLD_TYPE SSD1306 + #else + #define FLD_TYPE SSD1306_SPI + #endif +#endif + // When to time out to the clock or blank the screen // if SLEEP_MODE_ENABLED. #define SCREEN_TIMEOUT_MS 60*1000 // 1 min @@ -129,11 +145,11 @@ class FourLineDisplayUsermod : public Usermod { #ifndef FLD_SPI_DEFAULT int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000) - DisplayType type = SSD1306; // display type #else int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST - DisplayType type = SSD1306_SPI; // display type + uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz) #endif + DisplayType type = FLD_TYPE; // display type bool flip = false; // flip display 180° uint8_t contrast = 10; // screen contrast uint8_t lineHeight = 1; // 1 row or 2 rows @@ -143,6 +159,7 @@ class FourLineDisplayUsermod : public Usermod { bool clockMode = false; // display clock bool forceAutoRedraw = false; // WLEDSR: force rotating of variables in display, even if strip.isUpdating, this can cause led stutter, this should not be necessary if display is fast enough... bool noAutoRedraw = false; // WLEDSR: never do auto Redraw, only when variable changes or rotary is pressed (in case redraw causes stutter on leds, should not be needed with spi displays) + bool enabled = true; // Next variables hold the previous known values to determine if redraw is // required. @@ -198,73 +215,56 @@ class FourLineDisplayUsermod : public Usermod { Wire.begin(FLD_PIN_SDA, FLD_PIN_SCL); //increase speed to run display Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties - if (type == NONE) {enabled = false; return;} - if (type == SSD1306_SPI || type == SSD1306_SPI64 || type == SH1106_SPI) { - PinManagerPinType pins[5] = { { ioPin[0], true }, { ioPin[1], true}, { ioPin[2], true }, { ioPin[3], true}, { ioPin[4], true }}; - if (!pinManager.allocateMultiplePins(pins, 5, PinOwner::UM_FourLineDisplay)) { type=NONE; return; } + if (type == NONE || !enabled) return; + + bool isHW; + PinOwner po = PinOwner::UM_FourLineDisplay; + if (type == SSD1306_SPI || type == SSD1306_SPI64) { + isHW = (ioPin[0]==HW_PIN_CLOCKSPI && ioPin[1]==HW_PIN_DATASPI); + PinManagerPinType pins[5] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true }, { ioPin[3], true }, { ioPin[4], true }}; + if (!pinManager.allocateMultiplePins(pins, 5, po)) { type=NONE; return; } } else { - PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true} }; - if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::UM_FourLineDisplay)) { type=NONE; return; } + isHW = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA); + PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; + if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins + if (!pinManager.allocateMultiplePins(pins, 2, po)) { type=NONE; return; } } + DEBUG_PRINTLN(F("Allocating display.")); switch (type) { case SSD1306: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 1; break; case SH1106: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + if (!isHW) u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 2; break; case SSD1306_64: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 2; break; case SSD1305: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 1; break; case SSD1305_64: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA lineHeight = 2; break; case SSD1306_SPI: - if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); - else - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); + else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset lineHeight = 1; break; case SSD1306_SPI64: - if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); - else - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); + else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset lineHeight = 2; break; case SH1106_SPI: @@ -277,9 +277,10 @@ class FourLineDisplayUsermod : public Usermod { default: u8x8 = nullptr; } + if (nullptr == u8x8) { DEBUG_PRINTLN(F("Display init failed.")); - for (byte i=0; i<5 && ioPin[i]>=0; i++) pinManager.deallocatePin(ioPin[i], PinOwner::UM_FourLineDisplay); + pinManager.deallocateMultiplePins((const uint8_t*)ioPin, (type == SSD1306_SPI || type == SSD1306_SPI64) ? 5 : 2, po); type = NONE; enabled = false; return; @@ -287,7 +288,7 @@ class FourLineDisplayUsermod : public Usermod { initDone = true; DEBUG_PRINTLN(F("Starting display.")); - if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too + /*if (!(type == SSD1306_SPI || type == SSD1306_SPI64))*/ u8x8->setBusClock(ioFrequency); // can be used for SPI too u8x8->begin(); setFlipMode(flip); setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 @@ -303,7 +304,8 @@ class FourLineDisplayUsermod : public Usermod { * Da loop. */ void loop() { - if (!enabled) return; + if (!enabled || millis() - lastUpdate < (clockMode?1000:refreshRate) || strip.isUpdating()) return; + lastUpdate = millis(); // WWLEDSR: redraw if // -- timer and (forcedAutoUpdate or strip idle) and autoRedraw @@ -312,51 +314,48 @@ class FourLineDisplayUsermod : public Usermod { // OR // -- sleepmode and screentimeout // Note wakeDispay (used by rotaty) triggers its own redraw - if (millis() - lastUpdate >= (clockMode?1000:refreshRate)) { - lastUpdate = millis(); - if ( ((forceAutoRedraw || !strip.isUpdating()) && !noAutoRedraw) || checkChangedType() != FLD_LINE_NULL || (sleepMode && (millis() - lastRedraw > screenTimeout))) - redraw(false); - } + if ( ((forceAutoRedraw || !strip.isUpdating()) && !noAutoRedraw) || checkChangedType() != FLD_LINE_NULL || (sleepMode && (millis() - lastRedraw > screenTimeout))) + redraw(false); } /** * Wrappers for screen drawing */ void setFlipMode(uint8_t mode) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setFlipMode(mode); } void setContrast(uint8_t contrast) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setContrast(contrast); } void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setFont(u8x8_font_chroma48medium8_r); if (!ignoreLH && lineHeight==2) u8x8->draw1x2String(col, row, string); else u8x8->drawString(col, row, string); } void draw2x2String(uint8_t col, uint8_t row, const char *string) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setFont(u8x8_font_chroma48medium8_r); u8x8->draw2x2String(col, row, string); } void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setFont(font); if (!ignoreLH && lineHeight==2) u8x8->draw1x2Glyph(col, row, glyph); else u8x8->drawGlyph(col, row, glyph); } uint8_t getCols() { - if (type==NONE) return 0; + if (type==NONE || !enabled) return 0; return u8x8->getCols(); } void clear() { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->clear(); } void setPowerSave(uint8_t save) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setPowerSave(save); } @@ -411,8 +410,7 @@ class FourLineDisplayUsermod : public Usermod { static bool showName = false; unsigned long now = millis(); - if (type==NONE) return; - + if (type == NONE || !enabled) return; if (overlayUntil > 0) { if (now >= overlayUntil) { // Time to display the overlay has elapsed. @@ -426,14 +424,17 @@ class FourLineDisplayUsermod : public Usermod { } // Check if values which are shown on display changed from the last time. - Line4Type changed = checkChangedType(); - if (forceRedraw || changed != FLD_LINE_NULL) { - knownHour = 99; // force time update - if (changed != FLD_LINE_OTHER) //not ip or ssid - lineType = changed; //WLEDSR: Always show last changed value - clear(); - } - else if (!displayTurnedOff && ((now - lastRedraw)/1000)%5 == 0) { //WLEDSR: remove if sleepMode, as rotating should take place independent of sleepmode + if (forceRedraw || + (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) || + (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : Network.localIP())) || + (knownBrightness != bri) || + (knownEffectSpeed != effectSpeed) || + (knownEffectIntensity != effectIntensity) || + (knownMode != strip.getMainSegment().mode) || + (knownPalette != strip.getMainSegment().palette)) { + knownHour = 99; // force time update + lastRedraw = now; // update lastRedraw marker + } else if (sleepMode && !displayTurnedOff && ((now - lastRedraw)/1000)%5 == 0) { // change line every 5s showName = !showName; switch (lineType) { @@ -512,8 +513,8 @@ class FourLineDisplayUsermod : public Usermod { knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : Network.localIP(); knownBrightness = bri; - knownMode = strip.getMode(); - knownPalette = strip.getSegment(0).palette; + knownMode = strip.getMainSegment().mode; + knownPalette = strip.getMainSegment().palette; knownEffectSpeed = effectSpeed; knownEffectIntensity = effectIntensity; knownEffectCustom1 = effectCustom1; //WLEDSR @@ -605,6 +606,7 @@ class FourLineDisplayUsermod : public Usermod { //WLEDSR: Use custom slidernames void drawLine(uint8_t line, Line4Type lineType) { char lineBuffer[LINE_BUFFER_SIZE]; + uint8_t printedChars; switch(lineType) { case FLD_LINE_BRIGHTNESS: sprintf_P(lineBuffer, PSTR("Brightness %3d"), bri); @@ -635,10 +637,16 @@ class FourLineDisplayUsermod : public Usermod { drawString(1, line*lineHeight, lineBuffer); break; case FLD_LINE_MODE: - showCurrentEffectOrPalette(knownMode, JSON_mode_names, line); + printedChars = extractModeName(knownMode, JSON_mode_names, lineBuffer, LINE_BUFFER_SIZE-1); + for (;printedChars < getCols()-2 && printedChars < LINE_BUFFER_SIZE-3; printedChars++) lineBuffer[printedChars]=' '; + lineBuffer[printedChars] = 0; + drawString(2, line*lineHeight, lineBuffer); break; case FLD_LINE_PALETTE: - showCurrentEffectOrPalette(knownPalette, JSON_palette_names, line); + printedChars = extractModeName(knownPalette, JSON_palette_names, lineBuffer, LINE_BUFFER_SIZE-1); + for (;printedChars < getCols()-2 && printedChars < LINE_BUFFER_SIZE-3; printedChars++) lineBuffer[printedChars]=' '; + lineBuffer[printedChars] = 0; + drawString(2, line*lineHeight, lineBuffer); break; case FLD_LINE_SQUELCH: sprintf_P(lineBuffer, PSTR("Squelch %3d"), soundSquelch); @@ -779,6 +787,7 @@ class FourLineDisplayUsermod : public Usermod { * to wake up the screen. */ bool wakeDisplay() { + if (type == NONE || !enabled) return false; knownHour = 99; if (displayTurnedOff) { // Turn the display back on @@ -798,6 +807,8 @@ class FourLineDisplayUsermod : public Usermod { * Clears the screen and prints on the middle two lines. */ void overlay(const char* line1, const char *line2, long showHowLong) { + if (type == NONE || !enabled) return; + if (displayTurnedOff) { // Turn the display back on (includes clear()) sleepOrClock(false); @@ -859,6 +870,7 @@ class FourLineDisplayUsermod : public Usermod { * the useAMPM configuration. */ void showTime(bool fullScreen = true) { + if (type == NONE || !enabled) return; char lineBuffer[LINE_BUFFER_SIZE]; updateLocalTime(); @@ -952,11 +964,12 @@ class FourLineDisplayUsermod : public Usermod { */ void addToConfig(JsonObject& root) { JsonObject top = root.createNestedObject(FPSTR(_name)); - top[FPSTR(_enabled)] = enabled; + top[FPSTR(_enabled)] = enabled; JsonArray io_pin = top.createNestedArray("pin"); for (byte i=0; i<5; i++) io_pin.add(ioPin[i]); - top["help4PinTypes"] = F("Clk,Data,CS,DC,RST"); // help for Settings page + top["help4Pins"] = F("Clk,Data,CS,DC,RST"); // help for Settings page top["type"] = type; + top["help4Type"] = F("1=SSD1306,2=SH1106,3=SSD1306_128x64,4=SSD1305,5=SSD1305_128x64,6=SSD1306_SPI,7=SSD1306_SPI_128x64"); // help for Settings page top[FPSTR(_flip)] = (bool) flip; top[FPSTR(_contrast)] = contrast; top[FPSTR(_refreshRate)] = refreshRate/1000; @@ -1001,6 +1014,10 @@ class FourLineDisplayUsermod : public Usermod { forceAutoRedraw = top[FPSTR(_forceAutoRedraw)] | forceAutoRedraw; noAutoRedraw = top[FPSTR(_noAutoRedraw)] | noAutoRedraw; ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency + if (newType == SSD1306_SPI || newType == SSD1306_SPI64) + ioFrequency = min(20000, max(500, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency + else + ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency DEBUG_PRINT(FPSTR(_name)); if (!initDone) { @@ -1015,10 +1032,10 @@ class FourLineDisplayUsermod : public Usermod { for (byte i=0; i<5; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } if (pinsChanged || type!=newType) { if (type != NONE) delete u8x8; - for (byte i=0; i<5; i++) { - if (ioPin[i]>=0) pinManager.deallocatePin(ioPin[i], PinOwner::UM_FourLineDisplay); - ioPin[i] = newPin[i]; - } + PinOwner po = PinOwner::UM_FourLineDisplay; + if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins + pinManager.deallocateMultiplePins((const uint8_t *)ioPin, (type == SSD1306_SPI || type == SSD1306_SPI64) ? 5 : 2, po); + for (byte i=0; i<5; i++) ioPin[i] = newPin[i]; if (ioPin[0]<0 || ioPin[1]<0) { // data & clock must be > -1 type = NONE; enabled = false; diff --git a/usermods/usermod_v2_four_line_display_ALT/4LD_wled_fonts.c b/usermods/usermod_v2_four_line_display_ALT/4LD_wled_fonts.c new file mode 100644 index 0000000000..5495f91947 --- /dev/null +++ b/usermods/usermod_v2_four_line_display_ALT/4LD_wled_fonts.c @@ -0,0 +1,477 @@ +#pragma once + +//WLED custom fonts, curtesy of @Benji (https://github.com/Proto-molecule) + + +/* + Fontname: wled_logo_akemi_4x4 + Copyright: Benji (https://github.com/proto-molecule) + Glyphs: 3/3 + BBX Build Mode: 3 + * this logo ...WLED/images/wled_logo_akemi.png + * encode map = 1, 2, 3 +*/ +const uint8_t u8x8_wled_logo_akemi_4x4[388] U8X8_FONT_SECTION("u8x8_wled_logo_akemi_4x4") = + "\1\3\4\4\0\0\0\0\0\0\0\0\0\340\360\10\350\10\350\210\270\210\350\210\270\350\10\360\340\0\0\0" + "\0\0\200\200\0\0@\340\300\340@\0\0\377\377\377\377\377\377\37\37\207\207\371\371\371\377\377\377\0\0\374" + "\374\7\7\371\0\0\6\4\15\34x\340\200\177\177\377\351yy\376\356\357\217\177\177\177o\377\377\0\70\77" + "\277\376~\71\0\0\0\0\0\0\0\1\3\3\3\1\0\0\37\77\353\365\77\37\0\0\0\0\5\7\2\3" + "\7\4\0\0\300\300\300\300\200\200\200\0\0\0\0\0\0\0\200\200\300\300\300\300\200\200\0\0\0\0\0\0" + "\0\200\200\300\371\37\37\371\371\7\7\377\374\0\0\0\374\377\377\37\37\341\341\377\377\377\377\374\0\0\0\374" + "\377\7\7\231\371\376>\371\371>~\377\277\70\0\270\377\177\77\376\376\71\371\371\71\177\377\277\70\0\70\377" + "\177>\376\371\377\377\0\77\77\0\0\4\7\2\7\5\0\0\0\377\377\0\77\77\0\0\0\5\7\2\7\5" + "\0\0\377\377\300\300\300\200\200\0\0\0\0\0\0\0\200\200\300\300\300\300\300\200\200\0\0\0\0\0\0\0" + "\0\0\0\0\231\231\231\371\377\377\374\0\0\0\374\377\347\347\371\1\1\371\371\7\7\377\374\0\0\0@\340" + "\300\340@\0\71\371\371\71\177\377\277\70\0\70\277\377\177\71\371\370\70\371\371~\376\377\77\70\200\340x\34" + "\15\4\6\0\0\77\77\0\0\0\5\7\2\7\5\0\0\0\377\377\0\77\77\0\0\1\3\3\1\1\0\0" + "\0\0\0"; + + +/* + Fontname: wled_logo_akemi_5x5 + Copyright: Benji (https://github.com/proto-molecule) + Glyphs: 3/3 + BBX Build Mode: 3 + * this logo ...WLED/images/wled_logo_akemi.png + * encoded = 1, 2, 3 +*/ +/* +const uint8_t u8x8_wled_logo_akemi_5x5[604] U8X8_FONT_SECTION("u8x8_wled_logo_akemi_5x5") = + "\1\3\5\5\0\0\0\0\0\0\0\0\0\0\0\0\340\340\374\14\354\14\354\14|\14\354\14||\14\354" + "\14\374\340\340\0\0\0\0\0\0\0\200\0\0\0\200\200\0\200\200\0\0\0\0\377\377\377\376\377\376\377\377" + "\377\377\77\77\307\307\307\307\306\377\377\377\0\0\0\360\374>\77\307\0\0\61cg\357\347\303\301\200\0\0" + "\377\377\377\317\317\317\317\360\360\360\374\374\377\377\377\377\377\377\377\377\0\0\200\377\377\340\340\37\0\0\0\0" + "\0\0\1\3\17\77\374\360\357\357\177\36\14\17\357\377\376\376>\376\360\357\17\17\14>\177o\340\300\343c" + "{\77\17\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\17\37\37\362\375\37\37\17\0\0" + "\0\0\1\1\1\0\1\1\1\0\0\0\200\300\300\300\300\200\200\0\0\0\0\0\0\0\0\0\0\0\200\200" + "\300\300\300\300\200\200\0\0\0\0\0\0\0\0\0\0\0\0\200\200\307\307\377\377\307\307\307\77>\374\360\0" + "\0\0\360\374\376\377\377\377\7\7\7\377\377\377\377\376\374\360\0\0\0\0\360\374\36\37\37\343\37\37\340\340" + "\37\37\37\340\340\377\377\200\0\200\377\377\377\340\340\340\37\37\37\37\37\37\37\377\377\377\200\0\0\200\377\377" + "\340\340\340\34\377\377\3\3\377\377\3\17\77{\343\303\300\303\343s\77\37\3\377\377\3\3\377\377\3\17\77" + "{\343\303\300\300\343{\37\17\3\377\377\377\377\0\0\37\37\0\0\1\1\1\1\0\1\1\1\1\0\0\377" + "\377\0\0\37\37\0\0\1\1\1\1\0\0\1\1\1\0\0\377\377\300\300\300\200\200\0\0\0\0\0\0\0" + "\0\0\0\0\200\200\300\300\300\300\200\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\343\343\343\343" + "\343\377\376\374\360\0\0\0\360\374\376\77\77\307\307\7\7\307\307\307\77>\374\360\0\0\0\0\0\200\200\0" + "\200\200\0\0\34\34\34\37\37\377\377\377\377\200\0\200\377\377\377\377\37\37\37\0\0\37\37\37\340\340\377\377" + "\200\0\0\0\1\303\347\357gc\61\0\3\3\377\377\3\7\37\177s\343\300\303s{\37\17\7\3\377\377" + "\3\3\377\377\3\37\77scp<\36\17\3\1\0\0\0\0\0\0\0\37\37\0\0\0\1\1\1\0\1" + "\1\1\0\0\0\0\377\377\0\0\37\37\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; +*/ + +/* + Fontname: wled_logo_2x2 + Copyright: Benji (https://github.com/proto-molecule) + Glyphs: 4/4 + BBX Build Mode: 3 + * this logo https://cdn.discordapp.com/attachments/706623245935444088/927361780613799956/wled_scaled.png + * encode map = 1, 2, 3, 4 +*/ +const uint8_t u8x8_wled_logo_2x2[133] U8X8_FONT_SECTION("u8x8_wled_logo_2x2") = + "\1\4\2\2\0\0\0\0\0\200\200\360\360\16\16\16\16\0\0\0\340\340\340\340\340\37\37\1\1\0\0\0" + "\0\0\0\0\360\360\16\16\16\200\200\16\16\16\360\360\0\0\0\200\37\37\340\340\340\37\37\340\340\340\37\37" + "\0\0\0\37\200~~\0\0\0\0\0\0\0\360\360\216\216\216\216\37\340\340\340\340\340\340\340\0\0\37\37" + "\343\343\343\343\16\16\0\0ppp\16\16\376\376\16\16\16\360\360\340\340\0\0\0\0\0\340\340\377\377\340" + "\340\340\37\37"; + + +/* + Fontname: wled_logo_4x4 + Copyright: Created with Fony 1.4.7 + Glyphs: 4/4 + BBX Build Mode: 3 + * this logo https://cdn.discordapp.com/attachments/706623245935444088/927361780613799956/wled_scaled.png + * encode map = 1, 2, 3, 4 +*/ +/* +const uint8_t u8x8_wled_logo_4x4[517] U8X8_FONT_SECTION("u8x8_wled_logo_4x4") = + "\1\4\4\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\374\374\374\374\374\374\374\374\374" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\300\300\300\300\300\377\377\377\377\377\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\17\17\17\17\17\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\370\370\370\370\370\370\370\370\370\7\7\7\7\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\374\374\374\374\374\0\0\0\0\0\374\374\374\374\374\0\0\0\0\0\0\0" + "\0\0\0\0\0\377\377\377\377\377\0\0\0\0\0\300\300\300\300\300\0\0\0\0\0\377\377\377\377\377\0\0" + "\0\0\300\300\0\377\377\377\377\377\0\0\0\0\0\377\377\377\377\377\0\0\0\0\0\377\377\377\377\377\0\0" + "\0\0\377\377\0\7\7\7\7\7\370\370\370\370\370\7\7\7\7\7\370\370\370\370\370\7\7\7\7\7\0\0" + "\0\0\7\7\0\0\0\374\374\374\374\374\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\374\374\374" + "\374\374\374\374\300\300\300\77\77\77\77\77\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\300\300\300" + "\300\300\300\300\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\37\37\37" + "\37\37\37\37\7\7\7\370\370\370\370\370\370\370\370\370\370\370\370\370\0\0\0\0\7\7\7\7\7\370\370\370" + "\370\370\370\370\374\374\374\374\374\374\0\0\0\0\0\0\0\0\374\374\374\374\374\374\374\374\374\374\374\374\374\374" + "\0\0\0\0\300\300\0\0\0\0\0\0\0\77\77\77\77\77\0\0\0\0\377\377\377\377\377\0\0\0\0\377" + "\377\377\377\377\37\37\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\0\0\0\0\377" + "\377\377\377\377\370\370\370\370\370\370\0\0\0\0\0\0\0\0\370\370\370\370\377\377\377\377\377\370\370\370\370\377" + "\7\7\7\7"; +*/ + + +/* + Fontname: 4LineDisplay_WLED_icons_1x + Copyright: Benji (https://github.com/proto-molecule) + Glyphs: 13/13 + BBX Build Mode: 3 + * 1 = sun + * 2 = skip forward + * 3 = fire + * 4 = custom palette + * 5 = puzzle piece + * 6 = moon + * 7 = brush + * 8 = contrast + * 9 = power-standby + * 10 = star + * 11 = heart + * 12 = Akemi + *----------- + * 20 = wifi + * 21 = media-play +*/ +const uint8_t u8x8_4LineDisplay_WLED_icons_1x1[172] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_1x1") = + "\1\25\1\1\0B\30<<\30B\0~<\30\0~<\30\0p\374\77\216\340\370\360\0||>\36\14\64 \336\67" + ";\336 \64\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\2\1\11\311" + "\311\1\2\0\0~<<\30\30\0"; + + +/* + Fontname: 4LineDisplay_WLED_icons_2x1 + Copyright: Benji (https://github.com/proto-molecule) + Glyphs: 11/11 + BBX Build Mode: 3 + * 1 = sun + * 2 = skip forward + * 3 = fire + * 4 = custom palette + * 5 = puzzle piece + * 6 = moon + * 7 = brush + * 8 = contrast + * 9 = power-standby + * 10 = star + * 11 = heart + * 12 = Akemi +*/ +const uint8_t u8x8_4LineDisplay_WLED_icons_2x1[196] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_2x1") = + "\1\14\2\1\20\20BB\30\30<\275\275<\30\30BB\20\20\377~<<\70\30\20\0\377~<<" + "\70\30\20\0\60p\370\374\77>\236\214\300\340\370\360\360\340\0\0\34" + "\66\66<\34\374\374\374\374~\77\77~\374\374\374\374 pp \30<~~\377\370\360\360\340\340\340\340" + "@@ \0\200\300\340\360\360p`\10\34\34\16\6\6\3\0\0\70|~\376\376\377\377\377\201\201\203\202" + "\302Fl\70\70xL\204\200\200\217\217\200\200\204Lx\70\0\0\10\10\30\330x|\77\77|x\330\30" + "\10\10\0\0\14\36\37\77\77\177~\374\374~\177\77\77\37\36\14\24\64 \60>\26\367\33\375\36>\60" + " \64\24"; + + +/* + Fontname: 4LineDisplay_WLED_icons_2x + Copyright: + Glyphs: 11/11 + BBX Build Mode: 3 + * 1 = sun + * 2 = skip forward + * 3 = fire + * 4 = custom palette + * 5 = puzzle piece + * 6 = moon + * 7 = brush + * 8 = contrast + * 9 = power-standby + * 10 = star + * 11 = heart + * 12 = Akemi +*/ +const uint8_t u8x8_4LineDisplay_WLED_icons_2x2[389] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_2x2") = + "\1\14\2\2\200\200\14\14\300\340\360\363\363\360\340\300\14\14\200\200\1\1\60\60\3\7\17\317\317\17\7\3" + "\60\60\1\1\374\370\360\340\340\300\200\0\374\370\360\340\340\300\200\0\77\37\17\7\7\3\1\0\77\37\17\7" + "\7\3\1\0\0\200\340\360\377\376\374\360\0\0\300\200\0\0\0\0\17\77\177\377\17\7\301\340\370\374\377\377" + "\377|\0\0\360\370\234\236\376\363\363\377\377\363\363\376><\370\360\3\17\77yy\377\377\377\377\317\17\17" + "\17\17\7\3\360\360\360\360\366\377\377\366\360\360\360\360\0\0\0\0\377\377\377\377\237\17\17\237\377\377\377\377" + "\6\17\17\6\340\370\374\376\377\340\200\0\0\0\0\0\0\0\0\0\3\17\37\77\177\177\177\377\376|||" + "\70\30\14\0\0\0\0\0\0\0\0``\360\370|<\36\7\2\0\300\360\376\377\177\77\36\0\1\1\0" + "\0\0\0\0\340\370\374\376\376\377\377\377\3\3\7\6\16<\370\340\7\37\77\177\177\377\377\377\300\300\340`" + "p<\37\7\300\340p\30\0\0\377\377\0\0\30p\340\300\0\0\17\37\70`\340\300\300\300\300\340`\70" + "\37\17\0\0\0@\300\300\300\300\340\374\374\340\300\300\300\300@\0\0\0\0\1s\77\37\17\17\37\77s" + "\1\0\0\0\360\370\374\374\374\374\370\360\360\370\374\374\374\374\370\360\0\1\3\7\17\37\77\177\177\77\37\17" + "\7\3\1\0\200\200\0\0\0\360\370\374<\334\330\360\0\0\200\200\2\2\14\30\24\37\6~\7\177\7\37" + "\24\30\16\2"; + +/* + Fontname: 4LineDisplay_WLED_icons_3x + Copyright: Benji (https://github.com/proto-molecule) + Glyphs: 11/11 + BBX Build Mode: 3 + * 1 = sun + * 2 = skip forward + * 3 = fire + * 4 = custom palette + * 5 = puzzle piece + * 6 = moon + * 7 = brush + * 8 = contrast + * 9 = power-standby + * 10 = star + * 11 = heart + * 12 = Akemi +*/ +const uint8_t u8x8_4LineDisplay_WLED_icons_3x3[868] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_3x3") = + "\1\14\3\3\0\0\34\34\34\0\200\300\300\340\347\347\347\340\300\300\200\0\34\34\34\0\0\0\34\34\34\0" + "\0>\377\377\377\377\377\377\377\377\377\377\377>\0\0\34\34\34\0\0\0\16\16\16\0\0\1\1\3ss" + "s\3\1\1\0\0\34\34\34\0\0\0\370\360\340\300\300\200\0\0\0\0\0\0\370\360\340\300\300\200\0\0" + "\0\0\0\0\377\377\377\377\377\377\377\376~<\70\20\377\377\377\377\377\377\377\376~<\70\20\37\17\17\7" + "\3\1\1\0\0\0\0\0\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\300\361\376\374\370\360\300" + "\0\0\0\0\0\0\0\0\0\0\0\0\300\370\374\376\377\377\377\377\377\177\77\17\6\0\200\342\374\370\360\340" + "\200\0\0\0\1\17\37\77\177\377\7\3\0\200\360\370\374\376\377\377\377\377\377\377\77\0\0\0\0\200\340\360" + "\370\370\374\316\206\206\317\377\377\377\317\206\206\316\374\374\370\360\340\200<\377\377\371\360py\377\377\377\377\377" + "\377\377\377\377\377\377\363\341\341\363\377\177\0\1\7\17\34\70x|\377\377\377\377\367\363c\3\3\3\3\1" + "\1\1\0\0\300\300\300\300\300\300\300\316\377\377\377\316\300\300\300\300\300\300\0\0\0\0\0\0\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\300\300\340\340\340\300\377\377\377\377\377\377\377\307\3\3\3\307" + "\377\377\377\377\377\377\1\1\3\3\3\1\0\300\340\370\374\374\376\377\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0>\377\377\377\377\377\377\377\377\374\360\340\300\300\200\200\0\0\0\0\0\0\200\200\0\1\7\17" + "\37\37\77\177\177\177\177\377\377\377\177\177\177\77\77\37\17\7\3\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\200\200\300\340\340\360\370\374|>\17\6\0\0\0\0\0\340\340\360\360\360\342\303\7\17\37\77\37\7\3\1" + "\0\0\0\0\0\200\340\360\377\377\377\377\177\77\37\17\0\0\0\0\0\0\0\0\0\0\0\0\0\200\340\360" + "\370\374\374\376\376\376\377\377\7\7\7\6\16\16\34\70\360\340\300\0|\377\377\377\377\377\377\377\377\377\377\377" + "\0\0\0\0\0\0\0\0\0\377\377\377\0\3\7\17\37\77\177\177\377\377\377\377\340\340\340\340pp\70<" + "\37\17\3\0\0\0\200\300\340\340\300\0\0\377\377\377\0\0\300\340\340\300\200\0\0\0\0\0\370\376\377\17" + "\3\0\0\0\0\17\17\17\0\0\0\0\0\3\17\377\376\370\0\0\0\7\17\37~\376\376\377\377\377\377\377\376\376~>\36\16\6\6\2\0\0\0\0" + "\0\300x<\37\17\17\7\3\7\17\17\37>\177\177\377\377\377\377\377\377\371p\60\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0<\376\377\377\377\377\376<\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0" + "\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377~~\377\377" + "\377\377~<\377\377\377\377\377\377\377\377\303\1\0\0\0\0\1\303\377\377\377\377\377\377\377\377\0\0\0\0" + "\0\0\0\0\0\0\200\340\360\370\374\374\376\376\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\370\377\377\377\377\377\377\377\377\377\376\360\300\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\7\77\377\377\377\377\377\377\377\377\377\377\377\377\377\376\374\370\370\360\360\360\340\340\340\340\340\340" + "\340\340\60\0\0\0\0\1\3\7\17\37\37\77\77\77\177\177\177\177\177\177\177\177\77\77\77\37\37\17\7\3" + "\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\200\300\340\340\360\370\374\374" + "~\77\16\4\0\0\0\0\0\0\0\0\0\0\0\0\0\0\30\34>~\377\377\377\377\177\77\37\7\3\0" + "\0\0\0\0\0\0\0\0\0\360\374\376\377\377\377\377\377\376\374\370\0\0\0\3\3\1\0\0\0\0\0\0" + "\0\0\0\0@@\340\370\374\377\377\377\177\177\177\77\37\17\7\1\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\200\300\340\360\370\374\374\376\376\376\377\377\377\377\17\17\17\37\36\36>|\374\370\360\340" + "\300\200\0\0\360\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\1\3\37" + "\377\377\376\360\17\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\200\300\370" + "\377\377\177\17\0\0\1\3\7\17\37\77\77\177\177\177\377\377\377\377\360\360\360\370xx|>\77\37\17\7" + "\3\1\0\0\0\0\0\0\0\200\300\200\0\0\0\0\377\377\377\377\0\0\0\0\200\300\200\0\0\0\0\0" + "\0\0\0\0\300\360\374\376\177\37\7\3\3\0\0\0\377\377\377\377\0\0\0\3\3\7\37\177\376\374\360\300" + "\0\0\0\0\77\377\377\377\340\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\340\377\377\377\77" + "\0\0\0\0\0\0\3\7\17\37><|x\370\360\360\360\360\360\360\370x|<>\37\17\7\3\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\340\374\374\340\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\20\60p\360\360\360\360\360\360\360\360\370\377\377\377\377\377\377\370\360\360\360\360\360\360\360\360" + "p\60\20\0\0\0\0\0\0\0\1\3\7\317\377\377\377\377\377\377\377\377\377\377\377\377\317\7\3\1\0\0" + "\0\0\0\0\0\0\0\0\0\0\0p>\37\17\17\7\3\1\0\0\1\3\7\17\17\37>p\0\0\0" + "\0\0\0\0\0\200\300\340\340\360\360\360\360\360\360\340\340\300\200\0\0\200\300\340\340\360\360\360\360\360\360\340" + "\340\300\200\0~\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377~\0\1\3\7\17\37\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\17" + "\7\3\1\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37\77\177\177\77\37\17\7\3\1\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\300\340\340\360\360\360\360\340\340\300\200\0\0\0\0\0\0" + "\0\0\0\0\0@\340\300\340@\0\0\0\376\377\377\177\177\177\237\207\347\371\371\371\377\376\0\0\0\0@" + "\340\300\340@\2\4\4\35x\340\200\0\30\237\377\177\36\376\376\37\37\377\377\37\177\377\237\30\0\200\340x" + "\34\5\4\2\0\0\0\0\0\1\3\3\3\1\0\0\0\17\17\0\0\17\17\0\0\0\1\3\3\3\1\0" + "\0\0\0"; +*/ + +/* + Fontname: 4LineDisplay_WLED_icons_6x + Copyright: Benji (https://github.com/proto-molecule) + Glyphs: 11/11 + BBX Build Mode: 3 + * 1 = sun + * 2 = skip forward + * 3 = fire + * 4 = custom palette + * 5 = puzzle piece + * 6 = moon + * 7 = brush + * 8 = contrast + * 9 = power-standby + * 10 = star + * 11 = heart + * 12 = Akemi +*/ +// you can replace this (wasteful) font by using 3x3 variant with draw2x2Glyph() +const uint8_t u8x8_4LineDisplay_WLED_icons_6x6[3460] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_6x6") = + "\1\14\6\6\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\36\77\77\77\77\36\0" + "\0\0\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\0\0\0\7\17\17\17\17\7" + "\0\0\0\0\200\300\340\340\340\360\360\360\360\360\360\340\340\340\300\200\0\0\0\0\7\17\17\17\17\7\0\0" + "\0\0\0\0\300\340\340\340\340\300\0\0\0\0\0\0\340\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\376\374\340\0\0\0\0\0\0\300\340\340\340\340\300\3\7\7\7\7\3\0\0\0\0\0\0" + "\7\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\7\0\0\0\0\0\0\3\7" + "\7\7\7\3\0\0\0\0\0\0\340\360\360\360\360\340\0\0\0\0\1\3\7\7\7\17\17\17\17\17\17\7" + "\7\7\3\1\0\0\0\0\340\360\360\360\360\340\0\0\0\0\0\0\0\0\0\0\0\0\1\3\3\3\3\1" + "\0\0\0\0\0\0\0\0\0x\374\374\374\374x\0\0\0\0\0\0\0\0\0\1\3\3\3\3\1\0\0" + "\0\0\0\0\300\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\200\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\376\376\374\370\360\360\340\300\200" + "\200\0\0\0\0\0\0\0\0\0\0\0\377\377\377\376\376\374\370\360\360\340\300\200\200\0\0\0\0\0\0\0" + "\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\177\77\77\37\17\7\7\3\1\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\77\37\17\7" + "\7\3\1\0\377\377\377\177\177\77\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\377\377\377\177" + "\177\77\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\376\374\374\370\360\340\300\200\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\340\360\374" + "\377\377\377\377\377\377\377\377\377\376\370\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\300\340\360\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37\0\0\0\0" + "\0\0\4\370\360\360\340\300\200\0\0\0\0\0\0\0\0\0\0\0\370\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\177\77\37\7\3\0\0\0\0\0\200\300\360\374\377\377\377\377\377\377\377\376\370\340\0\0\0" + "\0\0\0\0\3\37\177\377\377\377\377\377\377\377\377\377\77\17\7\1\0\0\0\0\0\200\300\360\370\374\376\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\1\3\7\17\37\77\77\177\200" + "\0\0\0\0\0\0\340\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\17\1\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\200\300\340\340\360\360\370|<>>>~\377\377\377\377\377\377\377\177" + "\77\36\36\36\36<|\370\370\360\360\340\340\200\0\0\0\0\0\0\0\0\300\360\374\376\377\377\377\377\377\377" + "\377\360\340\300\300\300\300\340\360\377\377\377\377\377\377\370\360\340\340\340\340\360\370\377\377\377\377\377\377\377\377\377" + "\374\360\340\200\360\377\377\377\377\377\207\3\1\1\1\1\3\207\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\207\3\1\1\1\1\3\207\377\377\377\377\377\17\377\377\377\377\377\377\377\376~>>" + "\77\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\376\377\377\377" + "\177\77\37\7\0\0\3\17\77\177\377\377\360\340\300\300\300\300\340\360\377\377\377\377\377\377\377\377\377\377\77\17" + "\17\7\7\7\7\7\7\7\7\7\3\3\3\3\1\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37" + "\37\77\77\177\177\177\377\377\377\377\377\377\377\377\377~\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\370\374\376\377\377\377\377\377\377\376\374\360\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\360\360\360\360\360\360\360\360\360\360\360" + "\360\363\377\377\377\377\377\377\377\377\363\360\360\360\360\360\360\360\360\360\360\360\360\360\0\0\0\0\0\0\0\0" + "\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\374\376\376\377\377\377\377" + "\377\376\374\360\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\17\17\17\17\17\17\37\77\177\377\377\377\377" + "\377\377\377\377\377\377\377\377\3\3\7\7\17\17\17\17\7\7\3\0\377\377\377\377\377\377\377\377\377\377\377\377" + "\360\300\0\0\0\0\0\0\0\0\300\360\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\200\300\340\360\360\370\374\374\376\376\7\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\360\374\376\377\377\377\377\377\377\377" + "\377\377\377\340\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\360\300\200\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\17\177\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\376\374\370\360\360\340\340\300\300\300\200\200\200\200\0\0\0\0\0\0\200\200" + "\200\200\0\0\0\0\1\7\37\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\7\1\0\0\0\0\0\0\0\0\0\0\1\3\3\7" + "\17\17\37\37\37\77\77\77\77\177\177\177\177\177\177\77\77\77\77\37\37\37\17\17\7\3\3\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\200\200\300\340\360\360\370\374\374\376\377~\34\10\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\200\300\300\340\360\360\370\374\376\376\377\377\377\377\377\377\177\77\17\7\3" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\6\17\17\37\77\177\377" + "\377\377\377\377\377\377\77\37\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\370\374\376" + "\376\377\377\377\377\377\377\376\376\374\370\340\0\0\0\0\3\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\200\360\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\17\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`px\374\376\377\377\377\377\377\377" + "\177\177\177\77\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\200\300\340\360\360\370\374\374\374\376\376\376\377\377\377\377\377\77\77\77\77" + "\177~~\376\374\374\374\370\360\360\340\300\200\0\0\0\0\0\0\0\0\0\340\360\374\376\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\1\1\3\7\17\37\177\377\377\376\374" + "\360\340\0\0\370\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\1\17\377\377\377\377\377\370\37\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\360\377\377" + "\377\377\377\37\0\0\7\17\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0" + "\0\0\0\0\0\200\200\300\340\360\370\376\377\377\177\77\17\7\0\0\0\0\0\0\0\0\0\1\3\7\17\17" + "\37\77\77\77\177\177\177\377\377\377\377\377\374\374\374\374\376~~\177\77\77\77\37\17\17\7\3\1\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\300\340\360\370\374\376\376|" + "x \0\0\0\0\377\377\377\377\377\377\0\0\0\0 x|\376\376\374\370\360\340\300\200\0\0\0\0\0" + "\0\0\0\0\300\370\376\377\377\377\177\17\7\1\0\0\0\0\0\0\0\0\377\377\377\377\377\377\0\0\0\0" + "\0\0\0\0\1\7\37\177\377\377\377\376\370\200\0\0\0\0\0\0\177\377\377\377\377\377\200\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\377\377\377\377\377\177\0\0" + "\0\0\0\0\0\7\37\177\377\377\377\374\370\340\300\200\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\200\200\300\340\370\374\377\377\377\177\37\7\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37\37\77" + "\77\177~~~\374\374\374\374\374\374\374\374~~~\177\77\77\37\37\17\7\3\1\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\340\374\374\340\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\300\370\377\377\377\377\377\377\370\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\4\14\34<<|\374\374\374\374\374\374\374\374\374\374\374\376\377\377\377\377\377\377\377\377\377" + "\377\376\374\374\374\374\374\374\374\374\374\374\374|<<\34\14\4\0\0\0\0\0\0\0\0\0\1\3\3\7" + "\17\37\77\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\77\37\17\7\3\3\1\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\370\377\377\377\377\377\377\177\77\37\17\17\37\77\177" + "\377\377\377\377\377\377\370\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0p>" + "\37\17\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\17\37>p\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\200\200\200\300\300\300\300\300\300\200\200\200\0\0\0\0\0\0\0\0\0\0" + "\0\0\200\200\200\300\300\300\300\300\300\200\200\200\0\0\0\0\0\0\200\360\370\374\376\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\376\374\370\360\200\200\360\370\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376" + "\374\370\360\200\37\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37\0\0\1\3\7\17\37\77\177\377\377\377" + "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\17\7" + "\3\1\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37\77\177\377\377\377\377\377\377\377\377\377\377\377" + "\377\377\377\177\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\1\3\7\17\37\77\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\300\300\300\300\300\300" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\340\370\370\376\376\377\377\377\377\377\377\377\377\77\77\77>\376\370\370\340\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0 p\360\340\360p \0\0\0\0\0\0\377\377\377\377\177\177\177\177\177\207\207\340\340\377" + "\377\377\377\377\377\377\377\0\0\0\0\0 p\360\340\360p \0\6\4\14\14\15|x\360\200\200\0\0" + "pp\177\177\377\377\374|\374\374\374\177\177\177\377\377\377\177\377\377\377\377\177pp\0\0\200\200\360x}" + "\14\14\4\6\0\0\0\0\0\0\0\3\37\37|ppp\34\34\37\3\3\0\377\377\377\0\0\0\377\377" + "\377\0\3\3\37\37\34ppp~\37\37\3\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\7\7\7\0\0\0\7\7\7\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0"; + + + +/* + Fontname: akemi_8x8 + Copyright: Benji (https://github.com/proto-molecule) + Glyphs: 1/1 + BBX Build Mode: 3 + * 12 = Akemi +*/ +/* +const uint8_t u8x8_akemi_8x8[516] U8X8_FONT_SECTION("u8x8_akemi_8x8") = + "\14\14\10\10\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\200\200\200\200\200\200\200\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\340\340\370\370\376\376\376\376" + "\377\377\377\377\377\377\377\377\376\376\376\376\370\370\340\340\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\376\377\377\377\377\377\377\377\377" + "\377\377\377\377\37\37\37\343\343\343\343\343\343\377\377\377\376\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\30\30~~\370\370~~\30\30\0\0\0\0\0\0\0\377\377\377\377\377\77\77\77\77\77" + "\77\300\300\300\370\370\370\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\30\0f\0\200\0\0" + "\0\0\0\0\6\6\30\30\30\31\371\370\370\340\340\0\0\0\0\0\340\340\377\377\377\377\377\376\376\376\376\376" + "\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\371\346\346\6\6\6\6\6\0\340\340\340\341\0\0" + "\0\0\0\0\0\0\0\0\0\0\1\1\37\37\377\376\376\340\340\200\201\201\341\341\177\177\37\37\1\1\377\377" + "\377\377\1\1\1\1\377\377\377\377\1\1\37\37\177\177\341\341\201\201\200\200\370\370\376\376\37\37\1\1\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\1\7\7\7\7\7\7\1\1\0\0\0\0\0\0\377\377" + "\377\377\0\0\0\0\377\377\377\377\0\0\0\0\0\0\1\1\7\7\7\7\7\7\1\1\0\0\0\0\0\0" + "\0\0\0"; +*/ \ No newline at end of file diff --git a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h index 3dcb5af6aa..383accc52c 100644 --- a/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h +++ b/usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h @@ -2,6 +2,7 @@ #include "wled.h" #include // from https://github.com/olikraus/u8g2/ +#include "4LD_wled_fonts.c" // // Insired by the usermod_v2_four_line_display @@ -25,6 +26,10 @@ //The SCL and SDA pins are defined here. #ifdef ARDUINO_ARCH_ESP32 + #define HW_PIN_SCL 22 + #define HW_PIN_SDA 21 + #define HW_PIN_CLOCKSPI 18 + #define HW_PIN_DATASPI 23 #ifndef FLD_PIN_SCL #define FLD_PIN_SCL 22 #endif @@ -47,6 +52,10 @@ #define FLD_PIN_RESET 26 #endif #else + #define HW_PIN_SCL 5 + #define HW_PIN_SDA 4 + #define HW_PIN_CLOCKSPI 14 + #define HW_PIN_DATASPI 13 #ifndef FLD_PIN_SCL #define FLD_PIN_SCL 5 #endif @@ -70,15 +79,20 @@ #endif #endif +#ifndef FLD_TYPE + #ifndef FLD_SPI_DEFAULT + #define FLD_TYPE SSD1306 + #else + #define FLD_TYPE SSD1306_SPI + #endif +#endif + // When to time out to the clock or blank the screen // if SLEEP_MODE_ENABLED. #define SCREEN_TIMEOUT_MS 60*1000 // 1 min -#define TIME_INDENT 0 -#define DATE_INDENT 2 - // Minimum time between redrawing screen in ms -#define USER_LOOP_REFRESH_RATE_MS 100 +#define USER_LOOP_REFRESH_RATE_MS 1000 // Extra char (+1) for null #define LINE_BUFFER_SIZE 16+1 @@ -96,172 +110,47 @@ typedef enum { SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI } DisplayType; -/* - Fontname: benji_custom_icons_1x - Copyright: - Glyphs: 1/1 - BBX Build Mode: 3 - * 4 = custom palette -*/ -const uint8_t u8x8_font_benji_custom_icons_1x1[13] U8X8_FONT_SECTION("u8x8_font_benji_custom_icons_1x1") = - "\4\4\1\1<\370\360\3\17\77yy\377\377\377\377\317\17\17" - "\17\17\7\3\360\360\360\360\366\377\377\366\360\360\360\360\0\0\0\0\377\377\377\377\237\17\17\237\377\377\377\377" - "\6\17\17\6\340\370\374\376\377\340\200\0\0\0\0\0\0\0\0\0\3\17\37\77\177\177\177\377\376|||" - "\70\30\14\0\0\0\0\0\0\0\0``\360\370|<\36\7\2\0\300\360\376\377\177\77\36\0\1\1\0" - "\0\0\0\0\200\200\14\14\300\340\360\363\363\360\340\300\14\14\200\200\1\1\60\60\3\4\10\310\310\10\4\3" - "\60\60\1\1"; - -/* - Fontname: benji_custom_icons_6x - Copyright: - Glyphs: 8/8 - BBX Build Mode: 3 - // 6x6 icons libraries take up a lot of memory thus all the icons uses are consolidated into a single library - // these are just the required icons stripped from the U8x8 libraries in addition to a few new custom icons - * 1 = sun - * 2 = skip forward - * 3 = fire - * 4 = custom palette - * 5 = puzzle piece - * 6 = moon - * 7 = brush - * 8 = custom saturation -*/ -const uint8_t u8x8_font_benji_custom_icons_6x6[2308] U8X8_FONT_SECTION("u8x8_font_benji_custom_icons_6x6") = - "\1\10\6\6\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\36\77\77\77\77\36\0" - "\0\0\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\0\0\0\7\17\17\17\17\7" - "\0\0\0\0\200\300\340\340\340\360\360\360\360\360\360\340\340\340\300\200\0\0\0\0\7\17\17\17\17\7\0\0" - "\0\0\0\0\300\340\340\340\340\300\0\0\0\0\0\0\340\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377" - "\377\377\377\377\377\376\374\340\0\0\0\0\0\0\300\340\340\340\340\300\3\7\7\7\7\3\0\0\0\0\0\0" - "\7\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\7\0\0\0\0\0\0\3\7" - "\7\7\7\3\0\0\0\0\0\0\340\360\360\360\360\340\0\0\0\0\1\3\7\7\7\17\17\17\17\17\17\7" - "\7\7\3\1\0\0\0\0\340\360\360\360\360\340\0\0\0\0\0\0\0\0\0\0\0\0\1\3\3\3\3\1" - "\0\0\0\0\0\0\0\0\0x\374\374\374\374x\0\0\0\0\0\0\0\0\0\1\3\3\3\3\1\0\0" - "\0\0\0\0\300\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\200\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\376\376\374\370\360\360\340\300\200" - "\200\0\0\0\0\0\0\0\0\0\0\0\377\377\377\376\376\374\370\360\360\340\300\200\200\0\0\0\0\0\0\0" - "\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377" - "\377\377\377\377\377\377\377\377\377\377\376\374\374\370\360\340\340\300\200\0\377\377\377\377\377\377\377\377\377\377\377\377" - "\377\377\177\77\77\37\17\7\7\3\1\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\77\37\17\7" - "\7\3\1\0\377\377\377\177\177\77\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\377\377\377\177" - "\177\77\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\376\374\374\370\360\340\300\200\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\200\340\360\374" - "\377\377\377\377\377\377\377\377\377\376\370\300\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\300\340\360\374\376\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\37\0\0\0\0" - "\0\0\4\370\360\360\340\300\200\0\0\0\0\0\0\0\0\0\0\0\370\377\377\377\377\377\377\377\377\377\377\377" - "\377\377\377\377\377\177\77\37\7\3\0\0\0\0\0\200\300\360\374\377\377\377\377\377\377\377\376\370\340\0\0\0" - "\0\0\0\0\3\37\177\377\377\377\377\377\377\377\377\377\77\17\7\1\0\0\0\0\0\200\300\360\370\374\376\377" - "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\1\3\7\17\37\77\77\177\200" - "\0\0\0\0\0\0\340\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\17\1\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\200\300\340\340\360\360\370|<>>>~\377\377\377\377\377\377\377\177" - "\77\36\36\36\36<|\370\370\360\360\340\340\200\0\0\0\0\0\0\0\0\300\360\374\376\377\377\377\377\377\377" - "\377\360\340\300\300\300\300\340\360\377\377\377\377\377\377\370\360\340\340\340\340\360\370\377\377\377\377\377\377\377\377\377" - "\374\360\340\200\360\377\377\377\377\377\207\3\1\1\1\1\3\207\377\377\377\377\377\377\377\377\377\377\377\377\377\377" - "\377\377\377\377\377\377\377\207\3\1\1\1\1\3\207\377\377\377\377\377\17\377\377\377\377\377\377\377\376~>>" - "\77\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\376\376\376\376\377\377\377" - "\177\77\37\7\0\0\3\17\77\177\377\377\360\340\300\300\300\300\340\360\377\377\377\377\377\377\377\377\377\377\77\17" - "\17\7\7\7\7\7\7\7\7\7\3\3\3\3\1\0\0\0\0\0\0\0\0\0\0\0\0\1\3\7\17\37" - "\37\77\77\177\177\177\377\377\377\377\377\377\377\377\377~\30\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\370\374\376\377\377\377\377\377\377\376\374\360\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\360\360\360\360\360\360\360\360\360\360\360\360" - "\360\363\377\377\377\377\377\377\377\377\363\360\360\360\360\360\360\360\360\360\360\360\360\360\0\0\0\0\0\0\0\0" - "\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" - "\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0\0\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377" - "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\374\376\376\377\377\377\377" - "\377\376\374\360\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\17\17\17\17\17\17\37\77\177\377\377\377\377" - "\377\377\377\377\377\377\377\377\3\3\7\7\17\17\17\17\7\7\3\0\377\377\377\377\377\377\377\377\377\377\377\377" - "\360\300\0\0\0\0\0\0\0\0\300\360\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\200\300\340\360\360\370\374\374\376\376\7\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\360\374\376\377\377\377\377\377\377\377" - "\377\377\377\340\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\374\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\374\360\300\200\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\17\177\377\377\377\377\377\377\377\377\377\377" - "\377\377\377\377\377\377\377\377\377\377\376\374\370\360\360\340\340\300\300\300\200\200\200\200\0\0\0\0\0\0\200\200" - "\200\200\0\0\0\0\1\7\37\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377" - "\377\377\377\377\377\377\377\377\377\377\377\377\377\177\77\37\7\1\0\0\0\0\0\0\0\0\0\0\1\3\3\7" - "\17\17\37\37\37\77\77\77\77\177\177\177\177\177\177\77\77\77\77\37\37\37\17\17\7\3\3\1\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\200\200\300\340\360\360\370\374\374\376\377~\34\10\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\200\300\300\340\360\360\370\374\376\376\377\377\377\377\377\377\177\77\17\7\3" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\4\6\17\17\37\77\177\377" - "\377\377\377\377\377\377\77\37\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\370\374\376" - "\376\377\377\377\377\377\377\376\376\374\370\340\0\0\0\0\3\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\200\360\377\377\377\377\377\377\377\377\377\377\377\377\377\377\177\17\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0`px\374\376\377\377\377\377\377\377" - "\177\177\177\77\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\0\0\0\200\300\300\200\0\0\0\0\0\0\0\0\0\14\36\77\77\36\14\0\0" - "\0\0\0\0\0\0\0\200\300\300\200\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\3\7\17\17\7\3" - "\0\200\300\340\360\360\370\370\370\374\374\374\374\370\370\370\360\360\340\300\200\0\3\7\17\17\7\3\0\0\0\0" - "\0\0\0\0\300\340\360\360\340\300\0\0\0\0\340\374\377\177\177\177\177\177\177\177\177\177\177\177\177\177\177\177" - "\177\177\177\177\177\377\374\340\0\0\0\0\300\340\360\360\340\300\0\0\0\1\3\3\1\0\0\0\0\0\1\17" - "\77\177\370\340\300\200\200\0\0\0\0\0\0\0\0\200\200\300\340\370\177\77\17\1\0\0\0\0\0\1\3\3" - "\1\0\0\0\0\0\0\0\0\0\60x\374\374x\60\0\0\0\1\3\3\7\7\7\16\16\16\16\7\7\7" - "\3\3\1\0\0\0\60x\374\374x\60\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0\0\0\0\0\0\14\36\77\77\36\14\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - "\0\0\0"; class FourLineDisplayUsermod : public Usermod { private: bool initDone = false; - unsigned long lastTime = 0; // HW interface & configuration U8X8 *u8x8 = nullptr; // pointer to U8X8 display object + #ifndef FLD_SPI_DEFAULT int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000) - DisplayType type = SSD1306_64; // display type #else int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST - DisplayType type = SSD1306_SPI; // display type + uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz) #endif + + DisplayType type = FLD_TYPE; // display type bool flip = false; // flip display 180° uint8_t contrast = 10; // screen contrast uint8_t lineHeight = 1; // 1 row or 2 rows - uint32_t refreshRate = USER_LOOP_REFRESH_RATE_MS; // in ms + uint16_t refreshRate = USER_LOOP_REFRESH_RATE_MS; // in ms uint32_t screenTimeout = SCREEN_TIMEOUT_MS; // in ms bool sleepMode = true; // allow screen sleep? bool clockMode = false; // display clock - - // needRedraw marks if redraw is required to prevent often redrawing. - bool needRedraw = true; + bool showSeconds = true; // display clock with seconds + bool enabled = true; + bool contrastFix = false; // Next variables hold the previous known values to determine if redraw is // required. - String knownSsid = ""; - IPAddress knownIp; + String knownSsid = apSSID; + IPAddress knownIp = IPAddress(4, 3, 2, 1); uint8_t knownBrightness = 0; uint8_t knownEffectSpeed = 0; uint8_t knownEffectIntensity = 0; uint8_t knownMode = 0; uint8_t knownPalette = 0; uint8_t knownMinute = 99; + uint8_t knownHour = 99; byte brightness100; byte fxspeed100; byte fxintensity100; @@ -270,22 +159,26 @@ class FourLineDisplayUsermod : public Usermod { bool powerON = true; bool displayTurnedOff = false; - unsigned long lastUpdate = 0; + unsigned long nextUpdate = 0; unsigned long lastRedraw = 0; unsigned long overlayUntil = 0; + // Set to 2 or 3 to mark lines 2 or 3. Other values ignored. - byte markLineNum = 0; - byte markColNum = 0; + byte markLineNum = 255; + byte markColNum = 255; // strings to reduce flash memory usage (used more than twice) static const char _name[]; + static const char _enabled[]; static const char _contrast[]; static const char _refreshRate[]; static const char _screenTimeOut[]; static const char _flip[]; static const char _sleepMode[]; static const char _clockMode[]; + static const char _showSeconds[]; static const char _busClkFrequency[]; + static const char _contrastFix[]; // If display does not work or looks corrupted check the // constructor reference: @@ -293,154 +186,189 @@ class FourLineDisplayUsermod : public Usermod { // or check the gallery: // https://github.com/olikraus/u8g2/wiki/gallery + // some displays need this to properly apply contrast + void setVcomh(bool highContrast) { + u8x8_t *u8x8_struct = u8x8->getU8x8(); + u8x8_cad_StartTransfer(u8x8_struct); + u8x8_cad_SendCmd(u8x8_struct, 0x0db); //address of value + u8x8_cad_SendArg(u8x8_struct, highContrast ? 0x000 : 0x040); //value 0 for fix, reboot resets default back to 64 + u8x8_cad_EndTransfer(u8x8_struct); + } + public: // gets called once at boot. Do all initialization that doesn't depend on // network here void setup() { - if (type == NONE) return; - if (type == SSD1306_SPI || type == SSD1306_SPI64) { - PinManagerPinType pins[5] = { { ioPin[0], true }, { ioPin[1], true}, { ioPin[2], true }, { ioPin[3], true}, { ioPin[4], true }}; - if (!pinManager.allocateMultiplePins(pins, 5, PinOwner::UM_FourLineDisplay)) { type=NONE; return; } + if (type == NONE || !enabled) return; + + bool isHW, isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64); + PinOwner po = PinOwner::UM_FourLineDisplay; + if (isSPI) { + isHW = (ioPin[0]==HW_PIN_CLOCKSPI && ioPin[1]==HW_PIN_DATASPI); + PinManagerPinType pins[5] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true }, { ioPin[3], true }, { ioPin[4], true }}; + if (!pinManager.allocateMultiplePins(pins, 5, po)) { type=NONE; return; } } else { - PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true} }; - if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::UM_FourLineDisplay)) { type=NONE; return; } + isHW = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA); + PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; + if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins + if (!pinManager.allocateMultiplePins(pins, 2, po)) { type=NONE; return; } } + DEBUG_PRINTLN(F("Allocating display.")); +/* +// At some point it may be good to not new/delete U8X8 object but use this instead +// (does not currently work) +//------------------------------------------------------------------------------- switch (type) { case SSD1306: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 1; + u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino); break; case SH1106: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 2; + u8x8_Setup(u8x8.getU8x8(), u8x8_d_sh1106_128x64_winstar, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino); break; case SSD1306_64: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 2; + u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino); break; case SSD1305: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 1; + u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1305_128x32_adafruit, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino); break; case SSD1305_64: - #ifdef ESP8266 - if (!(ioPin[0]==5 && ioPin[1]==4)) - u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else - #endif - u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 2; + u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1305_128x64_adafruit, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino); break; case SSD1306_SPI: - if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); - else - u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset - lineHeight = 1; + u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_001, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino); break; case SSD1306_SPI64: - if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); - else - u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset - lineHeight = 2; + u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino); + break; + default: + type = NONE; + return; + } + if (isSPI) { + if (!isHW) u8x8_SetPin_4Wire_SW_SPI(u8x8.getU8x8(), ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); + else u8x8_SetPin_4Wire_HW_SPI(u8x8.getU8x8(), ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset + } else { + if (!isHW) u8x8_SetPin_SW_I2C(u8x8.getU8x8(), ioPin[0], ioPin[1], U8X8_PIN_NONE); // SCL, SDA, reset + else u8x8_SetPin_HW_I2C(u8x8.getU8x8(), U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + } +*/ + switch (type) { + case SSD1306: + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + break; + case SH1106: + if (!isHW) u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + break; + case SSD1306_64: + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + break; + case SSD1305: + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + break; + case SSD1305_64: + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset + else u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA + break; + case SSD1306_SPI: + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); + else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset + break; + case SSD1306_SPI64: + if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); + else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset break; default: u8x8 = nullptr; } + if (nullptr == u8x8) { DEBUG_PRINTLN(F("Display init failed.")); - for (byte i=0; i<5 && ioPin[i]>=0; i++) pinManager.deallocatePin(ioPin[i], PinOwner::UM_FourLineDisplay); + pinManager.deallocateMultiplePins((const uint8_t*)ioPin, isSPI ? 5 : 2, po); type = NONE; return; } - initDone = true; + lineHeight = u8x8->getRows() > 4 ? 2 : 1; DEBUG_PRINTLN(F("Starting display.")); - if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too + u8x8->setBusClock(ioFrequency); // can be used for SPI too u8x8->begin(); setFlipMode(flip); + setVcomh(contrastFix); setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 setPowerSave(0); - drawString(0, 0, "Loading..."); + //drawString(0, 0, "Loading..."); + overlayLogo(3500); + initDone = true; } // gets called every time WiFi is (re-)connected. Initialize own network // interfaces here - void connected() {} + void connected() { + knownSsid = WiFi.SSID(); //apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() : + knownIp = Network.localIP(); //apActive ? IPAddress(4, 3, 2, 1) : Network.localIP(); + networkOverlay(PSTR("NETWORK INFO"),7000); + } /** * Da loop. */ void loop() { - if (displayTurnedOff && millis() - lastUpdate < 1000) { - return; - }else if (millis() - lastUpdate < refreshRate){ - return;} + if (!enabled || strip.isUpdating()) return; + unsigned long now = millis(); + if (now < nextUpdate) return; + nextUpdate = now + ((displayTurnedOff && clockMode && showSeconds) ? 1000 : refreshRate); redraw(false); - lastUpdate = millis(); } /** * Wrappers for screen drawing */ void setFlipMode(uint8_t mode) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setFlipMode(mode); } void setContrast(uint8_t contrast) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setContrast(contrast); } void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setFont(u8x8_font_chroma48medium8_r); if (!ignoreLH && lineHeight==2) u8x8->draw1x2String(col, row, string); else u8x8->drawString(col, row, string); } void draw2x2String(uint8_t col, uint8_t row, const char *string) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setFont(u8x8_font_chroma48medium8_r); u8x8->draw2x2String(col, row, string); } void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setFont(font); if (!ignoreLH && lineHeight==2) u8x8->draw1x2Glyph(col, row, glyph); else u8x8->drawGlyph(col, row, glyph); } + void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font) { + if (type == NONE || !enabled) return; + u8x8->setFont(font); + u8x8->draw2x2Glyph(col, row, glyph); + } uint8_t getCols() { - if (type==NONE) return 0; + if (type==NONE || !enabled) return 0; return u8x8->getCols(); } void clear() { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->clear(); } void setPowerSave(uint8_t save) { - if (type==NONE) return; + if (type == NONE || !enabled) return; u8x8->setPowerSave(save); } @@ -451,99 +379,104 @@ class FourLineDisplayUsermod : public Usermod { } //function to update lastredraw - void updateRedrawTime(){ - lastRedraw = millis(); - } + void updateRedrawTime() { + lastRedraw = millis(); + } /** * Redraw the screen (but only if things have changed * or if forceRedraw). */ void redraw(bool forceRedraw) { - if (type==NONE) return; - if (overlayUntil > 0) { - if (millis() >= overlayUntil) { - // Time to display the overlay has elapsed. - overlayUntil = 0; - forceRedraw = true; - } else { - // We are still displaying the overlay - // Don't redraw. - return; - } + bool needRedraw = false; + unsigned long now = millis(); + + if (type == NONE || !enabled) return; + if (overlayUntil > 0) { + if (now >= overlayUntil) { + // Time to display the overlay has elapsed. + overlayUntil = 0; + forceRedraw = true; + } else { + // We are still displaying the overlay + // Don't redraw. + return; } + } + + if (apActive && WLED_WIFI_CONFIGURED && now<15000) { + knownSsid = apSSID; + networkOverlay(PSTR("NETWORK INFO"),30000); + return; + } - // Check if values which are shown on display changed from the last time. if (forceRedraw) { - needRedraw = true; + needRedraw = true; + clear(); } else if ((bri == 0 && powerON) || (bri > 0 && !powerON)) { //trigger power icon - powerON = !powerON; - drawStatusIcons(); - lastRedraw = millis(); + powerON = !powerON; + drawStatusIcons(); + return; } else if (knownnightlight != nightlightActive) { //trigger moon icon - knownnightlight = nightlightActive; - drawStatusIcons(); - if (knownnightlight) overlay(" Timer On", 1000, 6); - lastRedraw = millis(); - }else if (wificonnected != interfacesInited){ //trigger wifi icon - wificonnected = interfacesInited; - drawStatusIcons(); - lastRedraw = millis(); - } else if (knownMode != effectCurrent) { - knownMode = effectCurrent; - if(displayTurnedOff)needRedraw = true; - else showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); - } else if (knownPalette != effectPalette) { - knownPalette = effectPalette; - if(displayTurnedOff)needRedraw = true; - else showCurrentEffectOrPalette(knownPalette, JSON_palette_names, 2); + knownnightlight = nightlightActive; + drawStatusIcons(); + if (knownnightlight) { + String timer = PSTR("Timer On"); + center(timer,LINE_BUFFER_SIZE-1); + overlay(timer.c_str(), 2500, 6); + } + return; + } else if (wificonnected != interfacesInited) { //trigger wifi icon + wificonnected = interfacesInited; + drawStatusIcons(); + return; + } else if (knownMode != effectCurrent || knownPalette != effectPalette) { + if (displayTurnedOff) needRedraw = true; + else { + if (knownPalette != effectPalette) { showCurrentEffectOrPalette(effectPalette, JSON_palette_names, 2); knownPalette = effectPalette; } + if (knownMode != effectCurrent) { showCurrentEffectOrPalette(effectCurrent, JSON_mode_names, 3); knownMode = effectCurrent; } + lastRedraw = now; + return; + } } else if (knownBrightness != bri) { - if(displayTurnedOff && nightlightActive){needRedraw = false; knownBrightness = bri;} - else if(displayTurnedOff)needRedraw = true; - else updateBrightness(); + if (displayTurnedOff && nightlightActive) { knownBrightness = bri; } + else if (!displayTurnedOff) { updateBrightness(); lastRedraw = now; return; } } else if (knownEffectSpeed != effectSpeed) { - if(displayTurnedOff)needRedraw = true; - else updateSpeed(); + if (displayTurnedOff) needRedraw = true; + else { updateSpeed(); lastRedraw = now; return; } } else if (knownEffectIntensity != effectIntensity) { - if(displayTurnedOff)needRedraw = true; - else updateIntensity(); + if (displayTurnedOff) needRedraw = true; + else { updateIntensity(); lastRedraw = now; return; } } - if (!needRedraw) { // Nothing to change. // Turn off display after 1 minutes with no change. - if(sleepMode && !displayTurnedOff && (millis() - lastRedraw > screenTimeout)) { + if (sleepMode && !displayTurnedOff && (millis() - lastRedraw > screenTimeout)) { // We will still check if there is a change in redraw() // and turn it back on if it changed. + clear(); sleepOrClock(true); - } else if (displayTurnedOff && clockMode) { + } else if (displayTurnedOff && ntpEnabled) { showTime(); } return; - } else { - clear(); } - needRedraw = false; - lastRedraw = millis(); + lastRedraw = now; - if (displayTurnedOff) { - // Turn the display back on - sleepOrClock(false); - } + // Turn the display back on + wakeDisplay(); // Update last known values. - knownSsid = apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() : - knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); - knownBrightness = bri; - knownMode = effectCurrent; - knownPalette = effectPalette; - knownEffectSpeed = effectSpeed; + knownBrightness = bri; + knownMode = effectCurrent; + knownPalette = effectPalette; + knownEffectSpeed = effectSpeed; knownEffectIntensity = effectIntensity; - knownnightlight = nightlightActive; - wificonnected = interfacesInited; + knownnightlight = nightlightActive; + wificonnected = interfacesInited; // Do the actual drawing // First row: Icons @@ -563,57 +496,63 @@ class FourLineDisplayUsermod : public Usermod { showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); //Effect Mode info } - void updateBrightness(){ + void updateBrightness() { knownBrightness = bri; - if(overlayUntil == 0){ - brightness100 = (((float)(bri)/255)*100); - char lineBuffer[4]; - sprintf_P(lineBuffer, PSTR("%-3d"), brightness100); - drawString(1, lineHeight, lineBuffer); - lastRedraw = millis();} + if (overlayUntil == 0) { + brightness100 = ((uint16_t)bri*100)/255; + char lineBuffer[4]; + sprintf_P(lineBuffer, PSTR("%-3d"), brightness100); + drawString(1, lineHeight, lineBuffer); + //lastRedraw = millis(); + } } - void updateSpeed(){ + void updateSpeed() { knownEffectSpeed = effectSpeed; - if(overlayUntil == 0){ - fxspeed100 = (((float)(effectSpeed)/255)*100); - char lineBuffer[4]; - sprintf_P(lineBuffer, PSTR("%-3d"), fxspeed100); - drawString(5, lineHeight, lineBuffer); - lastRedraw = millis();} + if (overlayUntil == 0) { + fxspeed100 = ((uint16_t)effectSpeed*100)/255; + char lineBuffer[4]; + sprintf_P(lineBuffer, PSTR("%-3d"), fxspeed100); + drawString(5, lineHeight, lineBuffer); + //lastRedraw = millis(); + } } - void updateIntensity(){ + void updateIntensity() { knownEffectIntensity = effectIntensity; - if(overlayUntil == 0){ - fxintensity100 = (((float)(effectIntensity)/255)*100); - char lineBuffer[4]; - sprintf_P(lineBuffer, PSTR("%-3d"), fxintensity100); - drawString(9, lineHeight, lineBuffer); - lastRedraw = millis();} - } - - void draw2x2GlyphIcons(){ - if(lineHeight == 2){ - drawGlyph(1, 0, 1, u8x8_font_benji_custom_icons_2x2, true);//brightness icon - drawGlyph(5, 0, 2, u8x8_font_benji_custom_icons_2x2, true);//speed icon - drawGlyph(9, 0, 3, u8x8_font_benji_custom_icons_2x2, true);//intensity icon - drawGlyph(14, 2*lineHeight, 4, u8x8_font_benji_custom_icons_2x2, true);//palette icon - drawGlyph(14, 3*lineHeight, 5, u8x8_font_benji_custom_icons_2x2, true);//effect icon + if (overlayUntil == 0) { + fxintensity100 = ((uint16_t)effectIntensity*100)/255; + char lineBuffer[4]; + sprintf_P(lineBuffer, PSTR("%-3d"), fxintensity100); + drawString(9, lineHeight, lineBuffer); + //lastRedraw = millis(); } - else{ - drawGlyph(2, 0, 69, u8x8_font_open_iconic_weather_1x1);//brightness icon - drawGlyph(6, 0, 72, u8x8_font_open_iconic_play_1x1);//speed icon - drawGlyph(10, 0, 78, u8x8_font_open_iconic_thing_1x1);//intensity icon - drawGlyph(15, 2*lineHeight, 4, u8x8_font_benji_custom_icons_1x1);//palette icon - drawGlyph(15, 3*lineHeight, 70, u8x8_font_open_iconic_thing_1x1);//effect icon + } + + void draw2x2GlyphIcons() { + if (lineHeight == 2) { + drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x2, true); //brightness icon + drawGlyph( 5, 0, 2, u8x8_4LineDisplay_WLED_icons_2x2, true); //speed icon + drawGlyph( 9, 0, 3, u8x8_4LineDisplay_WLED_icons_2x2, true); //intensity icon + drawGlyph(14, 2*lineHeight, 4, u8x8_4LineDisplay_WLED_icons_2x2, true); //palette icon + drawGlyph(14, 3*lineHeight, 5, u8x8_4LineDisplay_WLED_icons_2x2, true); //effect icon + } else { + drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x1); //brightness icon + drawGlyph( 5, 0, 2, u8x8_4LineDisplay_WLED_icons_2x1); //speed icon + drawGlyph( 9, 0, 3, u8x8_4LineDisplay_WLED_icons_2x1); //intensity icon + drawGlyph(15, 2, 4, u8x8_4LineDisplay_WLED_icons_1x1); //palette icon + drawGlyph(15, 3, 5, u8x8_4LineDisplay_WLED_icons_1x1); //effect icon } } - void drawStatusIcons(){ - drawGlyph(14, 0, 80 + (wificonnected?0:1), u8x8_font_open_iconic_embedded_1x1, true); // wifi icon - drawGlyph(15, 0, 78 + (bri > 0 ? 0 : 3), u8x8_font_open_iconic_embedded_1x1, true); // power icon - drawGlyph(13, 0, 66 + (nightlightActive?0:4), u8x8_font_open_iconic_weather_1x1, true); // moon icon for nighlight mode + void drawStatusIcons() { + uint8_t col = 15; + uint8_t row = 0; + drawGlyph(col, row, (wificonnected ? 20 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // wifi icon + if (lineHeight==2) { col--; } else { row++; } + drawGlyph(col, row, (bri > 0 ? 9 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // power icon + if (lineHeight==2) { col--; } else { col = row = 0; } + drawGlyph(col, row, (nightlightActive ? 6 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // moon icon for nighlight mode } /** @@ -622,99 +561,69 @@ class FourLineDisplayUsermod : public Usermod { * pass line and colum info */ void setMarkLine(byte newMarkLineNum, byte newMarkColNum) { - markLineNum = newMarkLineNum; - markColNum = newMarkColNum; + markLineNum = newMarkLineNum; + markColNum = newMarkColNum; } //Draw the arrow for the current setting beiong changed - void drawArrow(){ - if(markColNum != 255 && markLineNum !=255)drawGlyph(markColNum, markLineNum*lineHeight, 69, u8x8_font_open_iconic_play_1x1); + void drawArrow() { + if (markColNum != 255 && markLineNum !=255) drawGlyph(markColNum, markLineNum*lineHeight, 21, u8x8_4LineDisplay_WLED_icons_1x1); } //Display the current effect or palette (desiredEntry) // on the appropriate line (row). void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) { - knownMode = effectCurrent; - knownPalette = effectPalette; - if(overlayUntil == 0){ - char lineBuffer[MAX_JSON_CHARS]; + char lineBuffer[MAX_JSON_CHARS]; + if (overlayUntil == 0) { + // Find the mode name in JSON + uint8_t printedChars = extractModeName(inputEffPal, qstring, lineBuffer, MAX_JSON_CHARS-1); + if (lineBuffer[0]=='*' && lineBuffer[1]==' ') { + // remove "* " from dynamic palettes + for (byte i=2; i<=printedChars; i++) lineBuffer[i-2] = lineBuffer[i]; //include '\0' + printedChars -= 2; + } + if (lineHeight == 2) { // use this code for 8 line display char smallBuffer1[MAX_MODE_LINE_SPACE]; char smallBuffer2[MAX_MODE_LINE_SPACE]; - char smallBuffer3[MAX_MODE_LINE_SPACE+1]; - uint8_t qComma = 0; - bool insideQuotes = false; - bool spaceHit = false; - uint8_t printedChars = 0; uint8_t smallChars1 = 0; uint8_t smallChars2 = 0; - uint8_t smallChars3 = 0; - uint8_t totalCount = 0; - char singleJsonSymbol; - - // Find the mode name in JSON - for (size_t i = 0; i < strlen_P(qstring); i++) { //find and get the full text for printing - singleJsonSymbol = pgm_read_byte_near(qstring + i); - if (singleJsonSymbol == '\0') break; - switch (singleJsonSymbol) { - case '"': - insideQuotes = !insideQuotes; - break; - case '[': - case ']': - break; - case ',': - qComma++; - default: - if (!insideQuotes || (qComma != inputEffPal)) break; - lineBuffer[printedChars++] = singleJsonSymbol; - totalCount++; - } - if ((qComma > inputEffPal)) break; - } - - if(lineHeight ==2){ // use this code for 8 line display - if(printedChars < (MAX_MODE_LINE_SPACE)){ // use big font if the text fits - for (;printedChars < (MAX_MODE_LINE_SPACE-1); printedChars++) {lineBuffer[printedChars]=' '; } - lineBuffer[printedChars] = 0; - drawString(1, row*lineHeight, lineBuffer); - lastRedraw = millis(); - }else{ // for long names divide the text into 2 lines and print them small - for (uint8_t i = 0; i < printedChars; i++){ - switch (lineBuffer[i]){ - case ' ': - if(i > 4 && !spaceHit) { - spaceHit = true; - break;} - if(!spaceHit) smallBuffer1[smallChars1++] = lineBuffer[i]; - if (spaceHit) smallBuffer2[smallChars2++] = lineBuffer[i]; - break; - default: - if(!spaceHit) smallBuffer1[smallChars1++] = lineBuffer[i]; - if (spaceHit) smallBuffer2[smallChars2++] = lineBuffer[i]; + if (printedChars < MAX_MODE_LINE_SPACE) { // use big font if the text fits + while (printedChars < (MAX_MODE_LINE_SPACE-1)) lineBuffer[printedChars++]=' '; + lineBuffer[printedChars] = 0; + drawString(1, row*lineHeight, lineBuffer); + } else { // for long names divide the text into 2 lines and print them small + bool spaceHit = false; + for (uint8_t i = 0; i < printedChars; i++) { + switch (lineBuffer[i]) { + case ' ': + if (i > 4 && !spaceHit) { + spaceHit = true; break; } - } - for (; smallChars1 < (MAX_MODE_LINE_SPACE-1); smallChars1++) smallBuffer1[smallChars1]=' '; - smallBuffer1[smallChars1] = 0; - drawString(1, row*lineHeight, smallBuffer1, true); - for (; smallChars2 < (MAX_MODE_LINE_SPACE-1); smallChars2++) smallBuffer2[smallChars2]=' '; - smallBuffer2[smallChars2] = 0; - drawString(1, row*lineHeight+1, smallBuffer2, true); - lastRedraw = millis(); + if (spaceHit) smallBuffer2[smallChars2++] = lineBuffer[i]; + else smallBuffer1[smallChars1++] = lineBuffer[i]; + break; + default: + if (spaceHit) smallBuffer2[smallChars2++] = lineBuffer[i]; + else smallBuffer1[smallChars1++] = lineBuffer[i]; + break; + } } + while (smallChars1 < (MAX_MODE_LINE_SPACE-1)) smallBuffer1[smallChars1++]=' '; + smallBuffer1[smallChars1] = 0; + drawString(1, row*lineHeight, smallBuffer1, true); + while (smallChars2 < (MAX_MODE_LINE_SPACE-1)) smallBuffer2[smallChars2++]=' '; + smallBuffer2[smallChars2] = 0; + drawString(1, row*lineHeight+1, smallBuffer2, true); } - else{ // use this code for 4 ling displays - if (printedChars > MAX_MODE_LINE_SPACE) printedChars = MAX_MODE_LINE_SPACE; - for (uint8_t i = 0; i < printedChars; i++){ - smallBuffer3[smallChars3++] = lineBuffer[i]; - } - - for (; smallChars3 < (MAX_MODE_LINE_SPACE); smallChars3++) smallBuffer3[smallChars3]=' '; - smallBuffer3[smallChars3] = 0; - drawString(1, row*lineHeight, smallBuffer3, true); - lastRedraw = millis(); - } - } + } else { // use this code for 4 ling displays + char smallBuffer3[MAX_MODE_LINE_SPACE+1]; // uses 1x1 icon for mode/palette + uint8_t smallChars3 = 0; + for (uint8_t i = 0; i < MAX_MODE_LINE_SPACE; i++) smallBuffer3[smallChars3++] = (i >= printedChars) ? ' ' : lineBuffer[i]; + smallBuffer3[smallChars3] = 0; + drawString(1, row*lineHeight, smallBuffer3, true); + } + } } /** @@ -724,60 +633,147 @@ class FourLineDisplayUsermod : public Usermod { * to wake up the screen. */ bool wakeDisplay() { - //knownHour = 99; + if (type == NONE || !enabled) return false; if (displayTurnedOff) { + clear(); // Turn the display back on sleepOrClock(false); - redraw(true); + //lastRedraw = millis(); return true; } return false; } /** - * Allows you to show one line and a glyph as overlay for a - * period of time. + * Allows you to show one line and a glyph as overlay for a period of time. * Clears the screen and prints. + * Used in Rotary Encoder usermod. */ void overlay(const char* line1, long showHowLong, byte glyphType) { - if (displayTurnedOff) { - // Turn the display back on - sleepOrClock(false); - } + // Turn the display back on + if (!wakeDisplay()) clear(); + // Print the overlay + if (glyphType>0 && glyphType<255) { + if (lineHeight == 2) drawGlyph(5, 0, glyphType, u8x8_4LineDisplay_WLED_icons_6x6, true); // use 3x3 font with draw2x2Glyph() if flash runs short and comment out 6x6 font + else drawGlyph(6, 0, glyphType, u8x8_4LineDisplay_WLED_icons_3x3, true); + } + if (line1) { + String buf = line1; + center(buf, getCols()); + drawString(0, (glyphType<255?3:0)*lineHeight, buf.c_str()); + } + overlayUntil = millis() + showHowLong; + } - // Print the overlay - clear(); - if (glyphType > 0){ - if ( lineHeight == 2) drawGlyph(5, 0, glyphType, u8x8_font_benji_custom_icons_6x6, true); - else drawGlyph(7, lineHeight, glyphType, u8x8_font_benji_custom_icons_2x2, true); - } - if (line1) drawString(0, 3*lineHeight, line1); - overlayUntil = millis() + showHowLong; + /** + * Allows you to show Akemi WLED logo overlay for a period of time. + * Clears the screen and prints. + */ + void overlayLogo(long showHowLong) { + // Turn the display back on + if (!wakeDisplay()) clear(); + // Print the overlay + if (lineHeight == 2) { + //add a bit of randomness + switch (millis()%3) { + case 0: + //WLED + draw2x2Glyph( 0, 2, 1, u8x8_wled_logo_2x2); + draw2x2Glyph( 4, 2, 2, u8x8_wled_logo_2x2); + draw2x2Glyph( 8, 2, 3, u8x8_wled_logo_2x2); + draw2x2Glyph(12, 2, 4, u8x8_wled_logo_2x2); + break; + case 1: + //WLED Akemi + drawGlyph( 2, 2, 1, u8x8_wled_logo_akemi_4x4, true); + drawGlyph( 6, 2, 2, u8x8_wled_logo_akemi_4x4, true); + drawGlyph(10, 2, 3, u8x8_wled_logo_akemi_4x4, true); + break; + case 2: + //Akemi + //draw2x2Glyph( 5, 0, 12, u8x8_4LineDisplay_WLED_icons_3x3); // use this if flash runs short and comment out 6x6 font + drawGlyph( 5, 0, 12, u8x8_4LineDisplay_WLED_icons_6x6, true); + drawString(6, 6, "WLED"); + break; + } + } else { + switch (millis()%3) { + case 0: + //WLED + draw2x2Glyph( 0, 0, 1, u8x8_wled_logo_2x2); + draw2x2Glyph( 4, 0, 2, u8x8_wled_logo_2x2); + draw2x2Glyph( 8, 0, 3, u8x8_wled_logo_2x2); + draw2x2Glyph(12, 0, 4, u8x8_wled_logo_2x2); + break; + case 1: + //WLED Akemi + drawGlyph( 2, 0, 1, u8x8_wled_logo_akemi_4x4); + drawGlyph( 6, 0, 2, u8x8_wled_logo_akemi_4x4); + drawGlyph(10, 0, 3, u8x8_wled_logo_akemi_4x4); + break; + case 2: + //Akemi + //drawGlyph( 6, 0, 12, u8x8_4LineDisplay_WLED_icons_4x4); // a bit nicer, but uses extra 1.5k flash + draw2x2Glyph( 6, 0, 12, u8x8_4LineDisplay_WLED_icons_2x2); + break; + } + } + overlayUntil = millis() + showHowLong; + } + + /** + * Allows you to show two lines as overlay for a period of time. + * Clears the screen and prints. + * Used in Auto Save usermod + */ + void overlay(const char* line1, const char* line2, long showHowLong) { + // Turn the display back on + if (!wakeDisplay()) clear(); + // Print the overlay + if (line1) { + String buf = line1; + center(buf, getCols()); + drawString(0, 1*lineHeight, buf.c_str()); + } + if (line2) { + String buf = line2; + center(buf, getCols()); + drawString(0, 2*lineHeight, buf.c_str()); + } + overlayUntil = millis() + showHowLong; } void networkOverlay(const char* line1, long showHowLong) { - if (displayTurnedOff) { - // Turn the display back on - sleepOrClock(false); - } + String line; + // Turn the display back on + if (!wakeDisplay()) clear(); // Print the overlay - clear(); - // First row string - if (line1) drawString(0, 0, line1); + if (line1) { + line = line1; + center(line, getCols()); + drawString(0, 0, line.c_str()); + } // Second row with Wifi name - String ssidString = knownSsid.substring(0, getCols() > 1 ? getCols() - 2 : 0); // - drawString(0, lineHeight, ssidString.c_str()); + line = knownSsid.substring(0, getCols() > 1 ? getCols() - 2 : 0); + if (line.length() < getCols()) center(line, getCols()); + drawString(0, lineHeight, line.c_str()); // Print `~` char to indicate that SSID is longer, than our display - if (knownSsid.length() > getCols()) { - drawString(getCols() - 1, 0, "~"); - } - // Third row with IP and Psssword in AP Mode - drawString(0, lineHeight*2, (knownIp.toString()).c_str()); - if (apActive) { - String appassword = apPass; - drawString(0, lineHeight*3, appassword.c_str()); - } - overlayUntil = millis() + showHowLong; + if (knownSsid.length() > getCols()) { + drawString(getCols() - 1, 0, "~"); + } + // Third row with IP and Password in AP Mode + line = knownIp.toString(); + center(line, getCols()); + drawString(0, lineHeight*2, line.c_str()); + line = ""; + if (apActive) { + line = apPass; + } else if (strcmp(serverDescription, "WLED") != 0) { + line = serverDescription; + } + center(line, getCols()); + drawString(0, lineHeight*3, line.c_str()); + overlayUntil = millis() + showHowLong; } @@ -786,16 +782,15 @@ class FourLineDisplayUsermod : public Usermod { */ void sleepOrClock(bool enabled) { if (enabled) { - if (clockMode) { - clear(); - knownMinute = 99; - showTime(); - }else setPowerSave(1); displayTurnedOff = true; - } - else { - setPowerSave(0); + if (clockMode && ntpEnabled) { + knownMinute = knownHour = 99; + showTime(); + } else + setPowerSave(1); + } else { displayTurnedOff = false; + setPowerSave(0); } } @@ -805,31 +800,120 @@ class FourLineDisplayUsermod : public Usermod { * the useAMPM configuration. */ void showTime() { - if(knownMinute != minute(localTime)){ //only redraw clock if it has changed + if (type == NONE || !enabled || !displayTurnedOff) return; + char lineBuffer[LINE_BUFFER_SIZE]; + static byte lastSecond; + byte secondCurrent = second(localTime); + byte minuteCurrent = minute(localTime); + byte hourCurrent = hour(localTime); + + if (knownMinute != minuteCurrent) { //only redraw clock if it has changed + //updateLocalTime(); + byte AmPmHour = hourCurrent; + boolean isitAM = true; + if (useAMPM) { + if (AmPmHour > 11) { AmPmHour -= 12; isitAM = false; } + if (AmPmHour == 0) { AmPmHour = 12; } + } + if (knownHour != hourCurrent) { + // only update date when hour changes + sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime)); + draw2x2String(2, lineHeight==1 ? 0 : lineHeight, lineBuffer); // adjust for 8 line displays, draw month and day + } + sprintf_P(lineBuffer,PSTR("%2d:%02d"), (useAMPM ? AmPmHour : hourCurrent), minuteCurrent); + draw2x2String(2, lineHeight*2, lineBuffer); //draw hour, min. blink ":" depending on odd/even seconds + if (useAMPM) drawString(12, lineHeight*2, (isitAM ? "AM" : "PM"), true); //draw am/pm if using 12 time + + drawStatusIcons(); //icons power, wifi, timer, etc - //updateLocalTime(); - byte AmPmHour = hour(localTime); - boolean isitAM = true; - if (useAMPM) { - if (AmPmHour > 11) AmPmHour -= 12; - if (AmPmHour == 0) AmPmHour = 12; - if (hour(localTime) > 11) isitAM = false; + knownMinute = minuteCurrent; + knownHour = hourCurrent; + } else { + if (secondCurrent == lastSecond) return; + } + if (showSeconds) { + lastSecond = secondCurrent; + draw2x2String(6, lineHeight*2, secondCurrent%2 ? " " : ":"); + sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent); + drawString(12, lineHeight*2+1, lineBuffer, true); // even with double sized rows print seconds in 1 line } - clear(); - drawStatusIcons(); //icons power, wifi, timer, etc + } - sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(month(localTime)), day(localTime)); - draw2x2String(DATE_INDENT, lineHeight==1 ? 0 : lineHeight, lineBuffer); // adjust for 8 line displays, draw month and day + /** + * handleButton() can be used to override default button behaviour. Returning true + * will prevent button working in a default way. + * Replicating button.cpp + */ + bool handleButton(uint8_t b) { + yield(); + if (!enabled + || b // butto 0 only + || buttonType[b] == BTN_TYPE_SWITCH + || buttonType[b] == BTN_TYPE_NONE + || buttonType[b] == BTN_TYPE_RESERVED + || buttonType[b] == BTN_TYPE_PIR_SENSOR + || buttonType[b] == BTN_TYPE_ANALOG + || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) { + return false; + } - sprintf_P(lineBuffer,PSTR("%2d:%02d"), (useAMPM ? AmPmHour : hour(localTime)), minute(localTime)); - draw2x2String(TIME_INDENT+2, lineHeight*2, lineBuffer); //draw hour, min. blink ":" depending on odd/even seconds + unsigned long now = millis(); + static bool buttonPressedBefore = false; + static bool buttonLongPressed = false; + static unsigned long buttonPressedTime = 0; + static unsigned long buttonWaitTime = 0; + bool handled = true; + + //momentary button logic + if (isButtonPressed(b)) { //pressed + + if (!buttonPressedBefore) buttonPressedTime = now; + buttonPressedBefore = true; + + if (now - buttonPressedTime > 600) { //long press + buttonLongPressed = true; + //TODO: handleButton() handles button 0 without preset in a different way for double click + //so we need to override with same behaviour + longPressAction(0); + //handled = false; + } - if (useAMPM) drawString(12, lineHeight*2, (isitAM ? "AM" : "PM"), true); //draw am/pm if using 12 time - knownMinute = minute(localTime); + } else if (!isButtonPressed(b) && buttonPressedBefore) { //released + + long dur = now - buttonPressedTime; + if (dur < 50) { + buttonPressedBefore = false; + return true; + } //too short "press", debounce + + bool doublePress = buttonWaitTime; //did we have short press before? + buttonWaitTime = 0; + + if (!buttonLongPressed) { //short press + // if this is second release within 350ms it is a double press (buttonWaitTime!=0) + //TODO: handleButton() handles button 0 without preset in a different way for double click + if (doublePress) { + networkOverlay(PSTR("NETWORK INFO"),7000); + handled = true; + } else { + buttonWaitTime = now; + } + } + buttonPressedBefore = false; + buttonLongPressed = false; } + // if 350ms elapsed since last press/release it is a short press + if (buttonWaitTime && now - buttonWaitTime > 350 && !buttonPressedBefore) { + buttonWaitTime = 0; + //TODO: handleButton() handles button 0 without preset in a different way for double click + //so we need to override with same behaviour + shortPressAction(0); + //handled = false; + } + return handled; } - + /* * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. @@ -873,16 +957,20 @@ class FourLineDisplayUsermod : public Usermod { */ void addToConfig(JsonObject& root) { JsonObject top = root.createNestedObject(FPSTR(_name)); + top[FPSTR(_enabled)] = enabled; JsonArray io_pin = top.createNestedArray("pin"); for (byte i=0; i<5; i++) io_pin.add(ioPin[i]); - top["help4PinTypes"] = F("Clk,Data,CS,DC,RST"); // help for Settings page + top["help4Pins"] = F("Clk,Data,CS,DC,RST"); // help for Settings page top["type"] = type; + top["help4Type"] = F("1=SSD1306,2=SH1106,3=SSD1306_128x64,4=SSD1305,5=SSD1305_128x64,6=SSD1306_SPI,7=SSD1306_SPI_128x64"); // help for Settings page top[FPSTR(_flip)] = (bool) flip; top[FPSTR(_contrast)] = contrast; - top[FPSTR(_refreshRate)] = refreshRate/10; + top[FPSTR(_contrastFix)] = (bool) contrastFix; + top[FPSTR(_refreshRate)] = refreshRate; top[FPSTR(_screenTimeOut)] = screenTimeout/1000; top[FPSTR(_sleepMode)] = (bool) sleepMode; top[FPSTR(_clockMode)] = (bool) clockMode; + top[FPSTR(_showSeconds)] = (bool) showSeconds; top[FPSTR(_busClkFrequency)] = ioFrequency/1000; DEBUG_PRINTLN(F("4 Line Display config saved.")); } @@ -907,15 +995,22 @@ class FourLineDisplayUsermod : public Usermod { return false; } + enabled = top[FPSTR(_enabled)] | enabled; newType = top["type"] | newType; for (byte i=0; i<5; i++) newPin[i] = top["pin"][i] | ioPin[i]; flip = top[FPSTR(_flip)] | flip; contrast = top[FPSTR(_contrast)] | contrast; - refreshRate = (top[FPSTR(_refreshRate)] | refreshRate/10) * 10; + refreshRate = top[FPSTR(_refreshRate)] | refreshRate; + refreshRate = min(5000, max(250, (int)refreshRate)); screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000; sleepMode = top[FPSTR(_sleepMode)] | sleepMode; clockMode = top[FPSTR(_clockMode)] | clockMode; - ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency + showSeconds = top[FPSTR(_showSeconds)] | showSeconds; + contrastFix = top[FPSTR(_contrastFix)] | contrastFix; + if (newType == SSD1306_SPI || newType == SSD1306_SPI64) + ioFrequency = min(20000, max(500, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency + else + ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency DEBUG_PRINT(FPSTR(_name)); if (!initDone) { @@ -930,24 +1025,28 @@ class FourLineDisplayUsermod : public Usermod { for (byte i=0; i<5; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } if (pinsChanged || type!=newType) { if (type != NONE) delete u8x8; - for (byte i=0; i<5; i++) { - if (ioPin[i]>=0) pinManager.deallocatePin(ioPin[i], PinOwner::UM_FourLineDisplay); - ioPin[i] = newPin[i]; - } + PinOwner po = PinOwner::UM_FourLineDisplay; + if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins + pinManager.deallocateMultiplePins((const uint8_t *)ioPin, (type == SSD1306_SPI || type == SSD1306_SPI64) ? 5 : 2, po); + for (byte i=0; i<5; i++) ioPin[i] = newPin[i]; if (ioPin[0]<0 || ioPin[1]<0) { // data & clock must be > -1 type = NONE; return true; } else type = newType; setup(); needsRedraw |= true; + } else { + u8x8->setBusClock(ioFrequency); // can be used for SPI too + setVcomh(contrastFix); + setContrast(contrast); + setFlipMode(flip); } - if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too - setContrast(contrast); - setFlipMode(flip); + knownHour = 99; if (needsRedraw && !wakeDisplay()) redraw(true); + else overlayLogo(3500); } // use "return !top["newestParameter"].isNull();" when updating Usermod with new features - return !(top[_busClkFrequency]).isNull(); + return !top[FPSTR(_contrastFix)].isNull(); } /* @@ -960,11 +1059,14 @@ class FourLineDisplayUsermod : public Usermod { }; // strings to reduce flash memory usage (used more than twice) -const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay"; -const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast"; -const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRate0.01Sec"; -const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec"; -const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip"; -const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode"; -const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode"; +const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay"; +const char FourLineDisplayUsermod::_enabled[] PROGMEM = "enabled"; +const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast"; +const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRate-ms"; +const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec"; +const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip"; +const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode"; +const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode"; +const char FourLineDisplayUsermod::_showSeconds[] PROGMEM = "showSeconds"; const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz"; +const char FourLineDisplayUsermod::_contrastFix[] PROGMEM = "contrastFix"; diff --git a/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h b/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h index 5ba19ebea7..0953be6a20 100644 --- a/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h +++ b/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h @@ -359,11 +359,8 @@ class RotaryEncoderUIUsermod : public Usermod { } void lampUdated() { - strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectCustom1, effectCustom2, effectCustom3, effectPalette); - //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) - // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa - colorUpdated(CALL_MODE_DIRECT_CHANGE); - updateInterfaces(CALL_MODE_DIRECT_CHANGE); + colorUpdated(CALL_MODE_BUTTON); + updateInterfaces(CALL_MODE_BUTTON); } void changeBrightness(bool increase) { diff --git a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h index 625af0af35..4629f547a7 100644 --- a/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h +++ b/usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h @@ -19,17 +19,20 @@ // Change between modes by pressing a button. // // Dependencies -// * This usermod REQURES the ModeSortUsermod // * This Usermod works best coupled with // FourLineDisplayUsermod. // -// If FourLineDisplayUsermod is used the folowing options are also inabled +// If FourLineDisplayUsermod is used the folowing options are also enabled // // * main color // * saturation of main color // * display network (long press buttion) // +#ifdef USERMOD_MODE_SORT + #error "Usermod Mode Sort is no longer required. Remove -D USERMOD_MODE_SORT from platformio.ini" +#endif + #ifndef ENCODER_DT_PIN #define ENCODER_DT_PIN 18 #endif @@ -44,27 +47,90 @@ // The last UI state, remove color and saturation option if diplay not active(too many options) #ifdef USERMOD_FOUR_LINE_DISPLAY - #define LAST_UI_STATE 6 + #define LAST_UI_STATE 8 #else #define LAST_UI_STATE 4 #endif +// Number of modes at the start of the list to not sort +#define MODE_SORT_SKIP_COUNT 1 + +// Which list is being sorted +static char **listBeingSorted; + +/** + * Modes and palettes are stored as strings that + * end in a quote character. Compare two of them. + * We are comparing directly within either + * JSON_mode_names or JSON_palette_names. + */ +static int re_qstringCmp(const void *ap, const void *bp) { + char *a = listBeingSorted[*((byte *)ap)]; + char *b = listBeingSorted[*((byte *)bp)]; + int i = 0; + do { + char aVal = pgm_read_byte_near(a + i); + if (aVal >= 97 && aVal <= 122) { + // Lowercase + aVal -= 32; + } + char bVal = pgm_read_byte_near(b + i); + if (bVal >= 97 && bVal <= 122) { + // Lowercase + bVal -= 32; + } + // Relly we shouldn't ever get to '\0' + if (aVal == '"' || bVal == '"' || aVal == '\0' || bVal == '\0') { + // We're done. one is a substring of the other + // or something happenend and the quote didn't stop us. + if (aVal == bVal) { + // Same value, probably shouldn't happen + // with this dataset + return 0; + } + else if (aVal == '"' || aVal == '\0') { + return -1; + } + else { + return 1; + } + } + if (aVal == bVal) { + // Same characters. Move to the next. + i++; + continue; + } + // We're done + if (aVal < bVal) { + return -1; + } + else { + return 1; + } + } while (true); + // We shouldn't get here. + return 0; +} + class RotaryEncoderUIUsermod : public Usermod { private: - int fadeAmount = 5; // Amount to change every step (brightness) - unsigned long currentTime; + int8_t fadeAmount = 5; // Amount to change every step (brightness) unsigned long loopTime; - unsigned long buttonHoldTIme; + + unsigned long buttonPressedTime = 0; + unsigned long buttonWaitTime = 0; + bool buttonPressedBefore = false; + bool buttonLongPressed = false; + int8_t pinA = ENCODER_DT_PIN; // DT from encoder int8_t pinB = ENCODER_CLK_PIN; // CLK from encoder int8_t pinC = ENCODER_SW_PIN; // SW from encoder - unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed - unsigned char button_state = HIGH; - unsigned char prev_button_state = HIGH; - bool networkShown = false; - uint16_t currentHue1 = 6425; // default reboot color - byte currentSat1 = 255; + + unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed, ... + + uint16_t currentHue1 = 16; // default boot color + byte currentSat1 = 255; #ifdef USERMOD_FOUR_LINE_DISPLAY FourLineDisplayUsermod *display; @@ -72,7 +138,16 @@ class RotaryEncoderUIUsermod : public Usermod { void* display = nullptr; #endif + // Pointers the start of the mode names within JSON_mode_names + char **modes_qstrings = nullptr; + + // Array of mode indexes in alphabetical order. byte *modes_alpha_indexes = nullptr; + + // Pointers the start of the palette names within JSON_palette_names + char **palettes_qstrings = nullptr; + + // Array of palette indexes in alphabetical order. byte *palettes_alpha_indexes = nullptr; unsigned char Enc_A; @@ -85,6 +160,14 @@ class RotaryEncoderUIUsermod : public Usermod { uint8_t knownMode = 0; uint8_t knownPalette = 0; + uint8_t currentCCT = 128; + bool isRgbw = false; + + byte presetHigh = 0; + byte presetLow = 0; + + bool applyToAll = true; + bool initDone = false; bool enabled = true; @@ -94,14 +177,94 @@ class RotaryEncoderUIUsermod : public Usermod { static const char _DT_pin[]; static const char _CLK_pin[]; static const char _SW_pin[]; + static const char _presetHigh[]; + static const char _presetLow[]; + static const char _applyToAll[]; + + /** + * Sort the modes and palettes to the index arrays + * modes_alpha_indexes and palettes_alpha_indexes. + */ + void sortModesAndPalettes() { + modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount()); + modes_alpha_indexes = re_initIndexArray(strip.getModeCount()); + re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT); + + palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount()); + palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount()); + + // How many palette names start with '*' and should not be sorted? + // (Also skipping the first one, 'Default'). + int skipPaletteCount = 1; + while (pgm_read_byte_near(palettes_qstrings[skipPaletteCount++]) == '*') ; + re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount); + } + + byte *re_initIndexArray(int numModes) { + byte *indexes = (byte *)malloc(sizeof(byte) * numModes); + for (byte i = 0; i < numModes; i++) { + indexes[i] = i; + } + return indexes; + } + + /** + * Return an array of mode or palette names from the JSON string. + * They don't end in '\0', they end in '"'. + */ + char **re_findModeStrings(const char json[], int numModes) { + char **modeStrings = (char **)malloc(sizeof(char *) * numModes); + uint8_t modeIndex = 0; + bool insideQuotes = false; + // advance past the mark for markLineNum that may exist. + char singleJsonSymbol; + + // Find the mode name in JSON + bool complete = false; + for (size_t i = 0; i < strlen_P(json); i++) { + singleJsonSymbol = pgm_read_byte_near(json + i); + if (singleJsonSymbol == '\0') break; + switch (singleJsonSymbol) { + case '"': + insideQuotes = !insideQuotes; + if (insideQuotes) { + // We have a new mode or palette + modeStrings[modeIndex] = (char *)(json + i + 1); + } + break; + case '[': + break; + case ']': + if (!insideQuotes) complete = true; + break; + case ',': + if (!insideQuotes) modeIndex++; + default: + if (!insideQuotes) break; + } + if (complete) break; + } + return modeStrings; + } + + /** + * Sort either the modes or the palettes using quicksort. + */ + void re_sortModes(char **modeNames, byte *indexes, int count, int numSkip) { + listBeingSorted = modeNames; + qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp); + listBeingSorted = nullptr; + } + public: /* - * setup() is called once at boot. WiFi is not yet connected at this point. - * You can use it to initialize variables, sensors or similar. - */ + * setup() is called once at boot. WiFi is not yet connected at this point. + * You can use it to initialize variables, sensors or similar. + */ void setup() { + DEBUG_PRINTLN(F("Usermod Rotary Encoder init.")); PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } }; if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) { // BUG: configuring this usermod with conflicting pins @@ -117,12 +280,17 @@ class RotaryEncoderUIUsermod : public Usermod { pinMode(pinA, INPUT_PULLUP); pinMode(pinB, INPUT_PULLUP); pinMode(pinC, INPUT_PULLUP); - currentTime = millis(); - loopTime = currentTime; + loopTime = millis(); - ModeSortUsermod *modeSortUsermod = (ModeSortUsermod*) usermods.lookup(USERMOD_ID_MODE_SORT); - modes_alpha_indexes = modeSortUsermod->getModesAlphaIndexes(); - palettes_alpha_indexes = modeSortUsermod->getPalettesAlphaIndexes(); + for (uint8_t s = 0; s < busses.getNumBusses(); s++) { + Bus *bus = busses.getBus(s); + if (!bus || bus->getLength()==0) break; + isRgbw |= bus->isRgbw(); + } + + currentCCT = (approximateKelvinFromRGB(RGBW32(col[0], col[1], col[2], col[3])) - 1900) >> 5; + + if (!initDone) sortModesAndPalettes(); #ifdef USERMOD_FOUR_LINE_DISPLAY // This Usermod uses FourLineDisplayUsermod for the best experience. @@ -140,91 +308,87 @@ class RotaryEncoderUIUsermod : public Usermod { } /* - * connected() is called every time the WiFi is (re)connected - * Use it to initialize network interfaces - */ + * connected() is called every time the WiFi is (re)connected + * Use it to initialize network interfaces + */ void connected() { //Serial.println("Connected to WiFi!"); } /* - * loop() is called continuously. Here you can check for events, read sensors, etc. - * - * Tips: - * 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection. - * Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker. - * - * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. - * Instead, use a timer check as shown here. - */ + * loop() is called continuously. Here you can check for events, read sensors, etc. + * + * Tips: + * 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection. + * Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker. + * + * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. + * Instead, use a timer check as shown here. + */ void loop() { - currentTime = millis(); // get the current elapsed time + if (!enabled || strip.isUpdating()) return; + unsigned long currentTime = millis(); // get the current elapsed time // Initialize effectCurrentIndex and effectPaletteIndex to // current state. We do it here as (at least) effectCurrent // is not yet initialized when setup is called. if (!currentEffectAndPaletteInitialized) { - findCurrentEffectAndPalette();} + findCurrentEffectAndPalette(); + } - if(modes_alpha_indexes[effectCurrentIndex] != effectCurrent - || palettes_alpha_indexes[effectPaletteIndex] != effectPalette){ + if (modes_alpha_indexes[effectCurrentIndex] != effectCurrent || palettes_alpha_indexes[effectPaletteIndex] != effectPalette) { currentEffectAndPaletteInitialized = false; - } + } if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz { - button_state = digitalRead(pinC); - if (prev_button_state != button_state) - { - if (button_state == HIGH && (millis()-buttonHoldTIme < 3000)) - { - prev_button_state = button_state; - - char newState = select_state + 1; - if (newState > LAST_UI_STATE) newState = 0; - - bool changedState = true; - if (display != nullptr) { - switch(newState) { - case 0: - changedState = changeState(" Brightness", 1, 0, 1); - break; - case 1: - changedState = changeState(" Speed", 1, 4, 2); - break; - case 2: - changedState = changeState(" Intensity", 1 ,8, 3); - break; - case 3: - changedState = changeState(" Color Palette", 2, 0, 4); - break; - case 4: - changedState = changeState(" Effect", 3, 0, 5); - break; - case 5: - changedState = changeState(" Main Color", 255, 255, 7); - break; - case 6: - changedState = changeState(" Saturation", 255, 255, 8); - break; - } - } - if (changedState) { - select_state = newState; + loopTime = currentTime; // Updates loopTime + + bool buttonPressed = !digitalRead(pinC); //0=pressed, 1=released + if (buttonPressed) { + if (!buttonPressedBefore) buttonPressedTime = currentTime; + buttonPressedBefore = true; + if (currentTime-buttonPressedTime > 3000) { + if (!buttonLongPressed) displayNetworkInfo(); //long press for network info + buttonLongPressed = true; + } + } else if (!buttonPressed && buttonPressedBefore) { + bool doublePress = buttonWaitTime; + buttonWaitTime = 0; + if (!buttonLongPressed) { + if (doublePress) { + toggleOnOff(); + lampUdated(); + } else { + buttonWaitTime = currentTime; } } - else - { - prev_button_state = button_state; - networkShown = false; - if(!prev_button_state)buttonHoldTIme = millis(); + buttonLongPressed = false; + buttonPressedBefore = false; + } + if (buttonWaitTime && currentTime-buttonWaitTime>350 && !buttonPressedBefore) { //same speed as in button.cpp + buttonWaitTime = 0; + char newState = select_state + 1; + bool changedState = true; + if (newState > LAST_UI_STATE || (newState == 8 && presetHigh==0 && presetLow == 0)) newState = 0; + if (display != nullptr) { + switch (newState) { + case 0: changedState = changeState(PSTR("Brightness"), 1, 0, 1); break; //1 = sun + case 1: changedState = changeState(PSTR("Speed"), 1, 4, 2); break; //2 = skip forward + case 2: changedState = changeState(PSTR("Intensity"), 1, 8, 3); break; //3 = fire + case 3: changedState = changeState(PSTR("Color Palette"), 2, 0, 4); break; //4 = custom palette + case 4: changedState = changeState(PSTR("Effect"), 3, 0, 5); break; //5 = puzzle piece + case 5: changedState = changeState(PSTR("Main Color"), 255, 255, 7); break; //7 = brush + case 6: changedState = changeState(PSTR("Saturation"), 255, 255, 8); break; //8 = contrast + case 7: changedState = changeState(PSTR("CCT"), 255, 255, 10); break; //10 = star + case 8: changedState = changeState(PSTR("Preset"), 255, 255, 11); break; //11 = heart + } } + if (changedState) select_state = newState; } - - if (!prev_button_state && (millis()-buttonHoldTIme > 3000) && !networkShown) displayNetworkInfo(); //long press for network info Enc_A = digitalRead(pinA); // Read encoder pins Enc_B = digitalRead(pinB); @@ -233,65 +397,39 @@ class RotaryEncoderUIUsermod : public Usermod { if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse { // B is high so clockwise switch(select_state) { - case 0: - changeBrightness(true); - break; - case 1: - changeEffectSpeed(true); - break; - case 2: - changeEffectIntensity(true); - break; - case 3: - changePalette(true); - break; - case 4: - changeEffect(true); - break; - case 5: - changeHue(true); - break; - case 6: - changeSat(true); - break; + case 0: changeBrightness(true); break; + case 1: changeEffectSpeed(true); break; + case 2: changeEffectIntensity(true); break; + case 3: changePalette(true); break; + case 4: changeEffect(true); break; + case 5: changeHue(true); break; + case 6: changeSat(true); break; + case 7: changeCCT(true); break; + case 8: changePreset(true); break; } } else if (Enc_B == HIGH) { // B is low so counter-clockwise switch(select_state) { - case 0: - changeBrightness(false); - break; - case 1: - changeEffectSpeed(false); - break; - case 2: - changeEffectIntensity(false); - break; - case 3: - changePalette(false); - break; - case 4: - changeEffect(false); - break; - case 5: - changeHue(false); - break; - case 6: - changeSat(false); - break; + case 0: changeBrightness(false); break; + case 1: changeEffectSpeed(false); break; + case 2: changeEffectIntensity(false); break; + case 3: changePalette(false); break; + case 4: changeEffect(false); break; + case 5: changeHue(false); break; + case 6: changeSat(false); break; + case 7: changeCCT(false); break; + case 8: changePreset(false); break; } } } Enc_A_prev = Enc_A; // Store value of A for next time - loopTime = currentTime; // Updates loopTime } } - void displayNetworkInfo(){ + void displayNetworkInfo() { #ifdef USERMOD_FOUR_LINE_DISPLAY - display->networkOverlay(" NETWORK INFO", 15000); - networkShown = true; + display->networkOverlay(PSTR("NETWORK INFO"), 10000); #endif } @@ -313,180 +451,292 @@ class RotaryEncoderUIUsermod : public Usermod { } boolean changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) { - #ifdef USERMOD_FOUR_LINE_DISPLAY - if (display != nullptr) { - if (display->wakeDisplay()) { - // Throw away wake up input - return false; - } - display->overlay(stateName, 750, glyph); - display->setMarkLine(markedLine, markedCol); - } - #endif - return true; + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display != nullptr) { + if (display->wakeDisplay()) { + // Throw away wake up input + display->redraw(true); + return false; + } + display->overlay(stateName, 750, glyph); + display->setMarkLine(markedLine, markedCol); + } + #endif + return true; } void lampUdated() { - //bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette); //call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification) // 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa - colorUpdated(CALL_MODE_DIRECT_CHANGE); - updateInterfaces(CALL_MODE_DIRECT_CHANGE); + //setValuesFromFirstSelectedSeg(); //to make transition work on main segment (should no longer be required) + stateUpdated(CALL_MODE_BUTTON); + updateInterfaces(CALL_MODE_BUTTON); } void changeBrightness(bool increase) { - #ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } - #endif - if (increase) bri = (bri + fadeAmount <= 255) ? (bri + fadeAmount) : 255; - else bri = (bri - fadeAmount >= 0) ? (bri - fadeAmount) : 0; - lampUdated(); - #ifdef USERMOD_FOUR_LINE_DISPLAY - display->updateBrightness(); - #endif + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0); + lampUdated(); + #ifdef USERMOD_FOUR_LINE_DISPLAY + display->updateBrightness(); + #endif } void changeEffect(bool increase) { - #ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } - #endif - if (increase) effectCurrentIndex = (effectCurrentIndex + 1 >= strip.getModeCount()) ? 0 : (effectCurrentIndex + 1); - else effectCurrentIndex = (effectCurrentIndex - 1 < 0) ? (strip.getModeCount() - 1) : (effectCurrentIndex - 1); - effectCurrent = modes_alpha_indexes[effectCurrentIndex]; - lampUdated(); - #ifdef USERMOD_FOUR_LINE_DISPLAY - display->showCurrentEffectOrPalette(effectCurrent, JSON_mode_names, 3); - #endif + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + effectCurrentIndex = max(min((increase ? effectCurrentIndex+1 : effectCurrentIndex-1), strip.getModeCount()-1), 0); + effectCurrent = modes_alpha_indexes[effectCurrentIndex]; + stateChanged = true; + if (applyToAll) { + for (byte i=0; ishowCurrentEffectOrPalette(effectCurrent, JSON_mode_names, 3); + #endif } void changeEffectSpeed(bool increase) { - #ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } - #endif - if (increase) effectSpeed = (effectSpeed + fadeAmount <= 255) ? (effectSpeed + fadeAmount) : 255; - else effectSpeed = (effectSpeed - fadeAmount >= 0) ? (effectSpeed - fadeAmount) : 0; - lampUdated(); - #ifdef USERMOD_FOUR_LINE_DISPLAY - display->updateSpeed(); - #endif + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + effectSpeed = max(min((increase ? effectSpeed+fadeAmount : effectSpeed-fadeAmount), 255), 0); + stateChanged = true; + if (applyToAll) { + for (byte i=0; iupdateSpeed(); + #endif } void changeEffectIntensity(bool increase) { - #ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } - #endif - if (increase) effectIntensity = (effectIntensity + fadeAmount <= 255) ? (effectIntensity + fadeAmount) : 255; - else effectIntensity = (effectIntensity - fadeAmount >= 0) ? (effectIntensity - fadeAmount) : 0; - lampUdated(); - #ifdef USERMOD_FOUR_LINE_DISPLAY - display->updateIntensity(); - #endif + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + effectIntensity = max(min((increase ? effectIntensity+fadeAmount : effectIntensity-fadeAmount), 255), 0); + stateChanged = true; + if (applyToAll) { + for (byte i=0; iupdateIntensity(); + #endif } void changePalette(bool increase) { - #ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } - #endif - if (increase) effectPaletteIndex = (effectPaletteIndex + 1 >= strip.getPaletteCount()) ? 0 : (effectPaletteIndex + 1); - else effectPaletteIndex = (effectPaletteIndex - 1 < 0) ? (strip.getPaletteCount() - 1) : (effectPaletteIndex - 1); - effectPalette = palettes_alpha_indexes[effectPaletteIndex]; - lampUdated(); - #ifdef USERMOD_FOUR_LINE_DISPLAY - display->showCurrentEffectOrPalette(effectPalette, JSON_palette_names, 2); - #endif + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + effectPaletteIndex = max(min((increase ? effectPaletteIndex+1 : effectPaletteIndex-1), strip.getPaletteCount()-1), 0); + effectPalette = palettes_alpha_indexes[effectPaletteIndex]; + stateChanged = true; + if (applyToAll) { + for (byte i=0; ishowCurrentEffectOrPalette(effectPalette, JSON_palette_names, 2); + #endif } void changeHue(bool increase){ - #ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } - #endif - - if(increase) currentHue1 += 321; - else currentHue1 -= 321; - colorHStoRGB(currentHue1, currentSat1, col); - lampUdated(); - #ifdef USERMOD_FOUR_LINE_DISPLAY - display->updateRedrawTime(); - #endif + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + currentHue1 = max(min((increase ? currentHue1+fadeAmount : currentHue1-fadeAmount), 255), 0); + colorHStoRGB(currentHue1*256, currentSat1, col); + stateChanged = true; + if (applyToAll) { + for (byte i=0; iwakeDisplay()) { - // Throw away wake up input - return; - } - #endif - - if(increase) currentSat1 = (currentSat1 + 5 <= 255 ? (currentSat1 + 5) : 255); - else currentSat1 = (currentSat1 - 5 >= 0 ? (currentSat1 - 5) : 0); - colorHStoRGB(currentHue1, currentSat1, col); - lampUdated(); - #ifdef USERMOD_FOUR_LINE_DISPLAY - display->updateRedrawTime(); - #endif + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0); + colorHStoRGB(currentHue1*256, currentSat1, col); + if (applyToAll) { + for (byte i=0; iwakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + if (presetHigh && presetLow && presetHigh > presetLow) { + String apireq = F("win&PL=~"); + if (!increase) apireq += '-'; + apireq += F("&P1="); + apireq += presetLow; + apireq += F("&P2="); + apireq += presetHigh; + handleSet(nullptr, apireq, false); + lampUdated(); + } + } + + void changeCCT(bool increase){ + #ifdef USERMOD_FOUR_LINE_DISPLAY + if (display && display->wakeDisplay()) { + display->redraw(true); + // Throw away wake up input + return; + } + display->updateRedrawTime(); + #endif + currentCCT = max(min((increase ? currentCCT+fadeAmount : currentCCT-fadeAmount), 255), 0); +// if (applyToAll) { + for (byte i=0; i 0; i--) { - setPixelColor( i, getPixelColor( i - 1)); - } - - if(SEGENV.step == 0) { - SEGENV.aux0 = get_random_wheel_index(SEGENV.aux0); - setPixelColor(0, color_wheel(SEGENV.aux0)); - } - - SEGENV.step++; - if (SEGENV.step > (uint8_t)((255-SEGMENT.intensity) >> 4)) - { - SEGENV.step = 0; + if (SEGENV.call == 0) SEGENV.aux0 = random16(); // random seed for PRNG on start + + uint8_t zoneSize = ((255-SEGMENT.intensity) >> 4) +1; + uint16_t PRNG16 = SEGENV.aux0; + + uint8_t z = it % zoneSize; + bool nzone = (!z && it != SEGENV.aux1); + for (uint16_t i=SEGLEN-1; i > 0; i--) { + if (nzone || z >= zoneSize) { + uint8_t lastrand = PRNG16 >> 8; + int16_t diff = 0; + while (abs(diff) < 42) { // make sure the difference between adjacent colors is big enough + PRNG16 = (uint16_t)(PRNG16 * 2053) + 13849; // next zone, next 'random' number + diff = (PRNG16 >> 8) - lastrand; + } + if (nzone) { + SEGENV.aux0 = PRNG16; // save next starting seed + nzone = false; + } + z = 0; + } + setPixelColor(i, color_wheel(PRNG16 >> 8)); + z++; } SEGENV.aux1 = it; @@ -1593,26 +1601,36 @@ uint16_t WS2812FX::mode_dual_larson_scanner(void){ /* - * Running random pixels + * Running random pixels ("Stream 2") * Custom mode by Keith Lord: https://github.com/kitesurfer1404/WS2812FX/blob/master/src/custom/RandomChase.h */ uint16_t WS2812FX::mode_random_chase(void) { + if (SEGENV.call == 0) { + SEGENV.step = RGBW32(random8(), random8(), random8(), 0); + SEGENV.aux0 = random16(); + } + uint16_t prevSeed = random16_get_seed(); // save seed so we can restore it at the end of the function uint32_t cycleTime = 25 + (3 * (uint32_t)(255 - SEGMENT.speed)); uint32_t it = now / cycleTime; - if (SEGENV.step == it) return FRAMETIME; + uint32_t color = SEGENV.step; + random16_set_seed(SEGENV.aux0); for(uint16_t i = SEGLEN -1; i > 0; i--) { - setPixelColor(i, getPixelColor(i-1)); + uint8_t r = random8(6) != 0 ? (color >> 16 & 0xFF) : random8(); + uint8_t g = random8(6) != 0 ? (color >> 8 & 0xFF) : random8(); + uint8_t b = random8(6) != 0 ? (color & 0xFF) : random8(); + color = RGBW32(r, g, b, 0); + setPixelColor(i, r, g, b); + if (i == SEGLEN -1 && SEGENV.aux1 != (it & 0xFFFF)) { //new first color in next frame + SEGENV.step = color; + SEGENV.aux0 = random16_get_seed(); + } } - uint32_t color = getPixelColor(0); - if (SEGLEN > 1) color = getPixelColor( 1); - uint8_t r = random8(6) != 0 ? (color >> 16 & 0xFF) : random8(); - uint8_t g = random8(6) != 0 ? (color >> 8 & 0xFF) : random8(); - uint8_t b = random8(6) != 0 ? (color & 0xFF) : random8(); - setPixelColor(0, r, g, b); - SEGENV.step = it; + SEGENV.aux1 = it & 0xFFFF; + + random16_set_seed(prevSeed); // restore original seed so other effects can use "random" PRNG return FRAMETIME; } @@ -2098,7 +2116,7 @@ uint16_t WS2812FX::mode_colortwinkle() } } } - return FRAMETIME; + return FRAMETIME_FIXED; } @@ -2336,7 +2354,7 @@ uint16_t WS2812FX::mode_ripple_rainbow(void) { // incandescent bulbs change color as they get dim down. #define COOL_LIKE_INCANDESCENT 1 -CRGB WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) +CRGB IRAM_ATTR WS2812FX::twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) { // Overall twinkle speed (changed) uint16_t ticks = ms / SEGENV.aux0; @@ -2774,16 +2792,9 @@ uint16_t WS2812FX::mode_popcorn(void) { if (numPopcorn == 0) numPopcorn = 1; for(uint8_t i = 0; i < numPopcorn; i++) { - bool isActive = popcorn[i].pos >= 0.0f; - - if (isActive) { // if kernel is active, update its position + if (popcorn[i].pos >= 0.0f) { // if kernel is active, update its position popcorn[i].pos += popcorn[i].vel; popcorn[i].vel += gravity; - uint32_t col = color_wheel(popcorn[i].colIndex); - if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) col = SEGCOLOR(popcorn[i].colIndex); - - uint16_t ledIndex = popcorn[i].pos; - if (ledIndex < SEGLEN) setPixelColor(ledIndex, col); } else { // if kernel is inactive, randomly pop it if (random8() < 2) { // POP!!! popcorn[i].pos = 0.01f; @@ -2802,6 +2813,13 @@ uint16_t WS2812FX::mode_popcorn(void) { } } } + if (popcorn[i].pos >= 0.0f) { // draw now active popcorn (either active before or just popped) + uint32_t col = color_wheel(popcorn[i].colIndex); + if (!SEGMENT.palette && popcorn[i].colIndex < NUM_COLORS) col = SEGCOLOR(popcorn[i].colIndex); + + uint16_t ledIndex = popcorn[i].pos; + if (ledIndex < SEGLEN) setPixelColor(ledIndex, col); + } } return FRAMETIME; @@ -2884,7 +2902,7 @@ uint16_t WS2812FX::candle(bool multi) } } - return FRAMETIME; + return FRAMETIME_FIXED; } uint16_t WS2812FX::mode_candle() diff --git a/wled00/FX.h b/wled00/FX.h index 74663d96f1..842aefa309 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -48,7 +48,8 @@ /* Not used in all effects yet */ #define WLED_FPS 42 -#define FRAMETIME (1000/WLED_FPS) +#define FRAMETIME_FIXED (1000/WLED_FPS) +#define FRAMETIME _frametime /* each segment uses 52 bytes of SRAM memory, so if you're application fails because of insufficient memory, decreasing MAX_NUM_SEGMENTS may help */ @@ -71,7 +72,7 @@ #define FAIR_DATA_PER_SEG (MAX_SEGMENT_DATA / MAX_NUM_SEGMENTS) #define LED_SKIP_AMOUNT 1 -#define MIN_SHOW_DELAY 15 +#define MIN_SHOW_DELAY (_frametime < 16 ? 8 : 15) #define NUM_COLORS 3 /* number of colors per segment */ #define SEGMENT _segments[_segment_index] @@ -80,7 +81,6 @@ #define SEGLEN _virtualSegmentLength #define SEGACT SEGMENT.stop #define SPEED_FORMULA_L 5U + (50U*(255U - SEGMENT.speed))/SEGLEN -#define RESET_RUNTIME memset(_segment_runtimes, 0, sizeof(_segment_runtimes)) // some common colors #define RED (uint32_t)0xFF0000 @@ -316,7 +316,7 @@ #define floatNull -32768 //WLEDSR Custom Effects /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// End of Audio Reactive fork (WLEDSR) // +// End of Audio Reactive fork (WLEDSR) // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class WS2812FX { @@ -333,7 +333,7 @@ class WS2812FX { // FastLED array, so we can refer to leds[i] instead of getPixel() and setPixel() CRGB leds[MAX_LEDS+1]; // See const.h for a value of 1500. The plus 1 is just in case we go over with XY(). - typedef struct Segment { // 30 (32 in memory?) bytes + typedef struct Segment { // 31 (32 in memory) bytes uint16_t start; uint16_t stop; //segment invalid if stop == 0 uint16_t offset; @@ -349,7 +349,8 @@ class WS2812FX { uint8_t opacity; uint32_t colors[NUM_COLORS]; uint8_t cct; //0==1900K, 255==10091K - uint16_t width; // WLEDSRewowi20210624: add width/height and startX/Y stopX/Y for 2D segments + uint8_t _capabilities; + uint16_t width; // WLEDSR ewowi20210624: add width/height and startX/Y stopX/Y for 2D segments uint16_t height; // WLEDSR uint16_t startX; // WLEDSR uint16_t startY; // WLEDSR @@ -430,30 +431,10 @@ class WS2812FX { vLength = (vLength + 1) /2; // divide by 2 if mirror, leave at least a single LED return vLength; } - uint8_t differs(Segment& b) { - uint8_t d = 0; - if (start != b.start) d |= SEG_DIFFERS_BOUNDS; - if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS; - if (offset != b.offset) d |= SEG_DIFFERS_GSO; - if (grouping != b.grouping) d |= SEG_DIFFERS_GSO; - if (spacing != b.spacing) d |= SEG_DIFFERS_GSO; - if (opacity != b.opacity) d |= SEG_DIFFERS_BRI; - if (mode != b.mode) d |= SEG_DIFFERS_FX; - if (speed != b.speed) d |= SEG_DIFFERS_FX; - if (intensity != b.intensity) d |= SEG_DIFFERS_FX; - if (custom2 != b.custom2) d |= SEG_DIFFERS_FX; - if (custom1 != b.custom1) d |= SEG_DIFFERS_FX; - if (custom3 != b.custom3) d |= SEG_DIFFERS_FX; - if (palette != b.palette) d |= SEG_DIFFERS_FX; - - if ((options & 0b00101111) != (b.options & 0b00101111)) d |= SEG_DIFFERS_OPT; - for (uint8_t i = 0; i < NUM_COLORS; i++) - { - if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL; - } - return d; - } + uint8_t differs(Segment& b); + inline uint8_t getLightCapabilities() {return _capabilities;} + void refreshLightCapabilities(); } segment; // segment runtime parameters @@ -507,8 +488,9 @@ class WS2812FX { * Flags that before the next effect is calculated, * the internal segment state should be reset. * Call resetIfRequired before calling the next effect function. + * Safe to call from interrupts and network requests. */ - inline void reset() { _requiresReset = true; } + inline void markForReset() { _requiresReset = true; } private: uint16_t _dataLen = 0; bool _requiresReset = false; @@ -836,7 +818,8 @@ class WS2812FX { setMode(uint8_t segid, uint8_t m), setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), setColor(uint8_t slot, uint32_t c), - setBrightness(uint8_t b), + setCCT(uint16_t k), + setBrightness(uint8_t b, bool direct = false), setRange(uint16_t i, uint16_t i2, uint32_t col), setShowCallback(show_callback cb), setTransition(uint16_t t), @@ -845,48 +828,54 @@ class WS2812FX { trigger(void), setReset(uint8_t n), setSegment(uint8_t n, uint16_t start, uint16_t stop, uint8_t grouping = 0, uint8_t spacing = 0, uint16_t offset = UINT16_MAX), + setMainSegmentId(uint8_t n), restartRuntime(), resetSegments(), - makeAutoSegments(), + makeAutoSegments(bool forceReset = false), fixInvalidSegments(), setPixelColor(uint16_t n, uint32_t c), setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0), show(void), - setPixelSegment(uint8_t n), + setTargetFps(uint8_t fps), deserializeMap(uint8_t n=0); bool - isRgbw = false, - isOffRefreshRequred = false, //periodic refresh is required for the strip to remain off. gammaCorrectBri = false, gammaCorrectCol = true, - applyToAllSelected = true, - setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t p), //WLEDSR: add c1,c2,c3 + // REMOVED IN 7b969bb + // applyToAllSelected = true, + // setEffectConfig(uint8_t m, uint8_t s, uint8_t i, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t p), //WLEDSR: add c1,c2,c3 checkSegmentAlignment(void), - hasCCTBus(void), + hasRGBWBus(void), + hasCCTBus(void), // return true if the strip is being sent pixel updates isUpdating(void); uint8_t - mainSegment = 0, paletteFade = 0, paletteBlend = 0, milliampsPerLed = 55, - cctBlending = 0, + autoWhiteMode = RGBW_MODE_DUAL, + cctBlending = 0, getBrightness(void), - getMode(void), - getSpeed(void), getModeCount(void), getPaletteCount(void), getMaxSegments(void), getActiveSegmentsNum(void), - //getFirstSelectedSegment(void), + getFirstSelectedSegId(void), getMainSegmentId(void), + getLastActiveSegmentId(void), + getTargetFps(void), + setPixelSegment(uint8_t n), gamma8(uint8_t), gamma8_cal(uint8_t, float), - sin_gap(uint16_t), get_random_wheel_index(uint8_t); + inline uint8_t sin_gap(uint16_t in) { + if (in & 0x100) return 0; + return sin8(in + 192); // correct phase shift of sine so that it starts and stops at 0 + } + int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec); @@ -907,14 +896,12 @@ class WS2812FX { currentColor(uint32_t colorNew, uint8_t tNr), gamma32(uint32_t), getLastShow(void), - getPixelColor(uint16_t), - getColor(void); - - WS2812FX::Segment& - getSegment(uint8_t n); + getPixelColor(uint16_t); - WS2812FX::Segment_runtime - getSegmentRuntime(void); + WS2812FX::Segment + &getSegment(uint8_t n), + &getFirstSelectedSeg(void), + &getMainSegment(void); WS2812FX::Segment* getSegments(void); @@ -1177,9 +1164,13 @@ class WS2812FX { uint16_t _usedSegmentData = 0; uint16_t _transitionDur = 750; + uint8_t _targetFps = 42; + uint16_t _frametime = (1000/42); uint16_t _cumulativeFps = 2; bool + _isOffRefreshRequired = false, //periodic refresh is required for the strip to remain off. + _hasWhiteChannel = false, _triggered; mode_ptr _mode[MODE_COUNT]; // SRAM footprint: 4 bytes per element @@ -1226,12 +1217,16 @@ class WS2812FX { uint32_t _colors_t[3]; uint8_t _bri_t; + bool _no_rgb = false; + uint8_t _segment_index = 0; uint8_t _segment_index_palette_last = 99; + uint8_t _mainSegment; + segment _segments[MAX_NUM_SEGMENTS] = { // SRAM footprint: 27 bytes per element //WLEDSR: add f1,2,3 - // start, stop, offset, speed, intensity, custom1, custom2, custom3, palette, mode, options, grouping, spacing, opacity (unused), color[] - {0, 7, 0, DEFAULT_SPEED, DEFAULT_INTENSITY, DEFAULT_Custom1, DEFAULT_Custom2, DEFAULT_Custom3, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}} + // start, stop, offset, speed, intensity, custom1, custom2, custom3, palette, mode, options, grouping, spacing, opacity (unused), color[], capabilities + {0, 7, 0, DEFAULT_SPEED, DEFAULT_INTENSITY, DEFAULT_Custom1, DEFAULT_Custom2, DEFAULT_Custom3, 0, DEFAULT_MODE, NO_OPTIONS, 1, 0, 255, {DEFAULT_COLOR}, 0} }; segment_runtime _segment_runtimes[MAX_NUM_SEGMENTS]; // SRAM footprint: 28 bytes per element friend class Segment_runtime; @@ -1242,6 +1237,10 @@ class WS2812FX { uint16_t realPixelIndex(uint16_t i), transitionProgress(uint8_t tNr); + + public: + inline bool hasWhiteChannel(void) {return _hasWhiteChannel;} + inline bool isOffRefreshRequired(void) {return _isOffRefreshRequired;} }; //10 names per line diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 6ebfc46f6e..f7511f02fc 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -67,8 +67,13 @@ //do not call this method from system context (network callback) void WS2812FX::finalizeInit(void) { - RESET_RUNTIME; - isRgbw = isOffRefreshRequred = false; + //reset segment runtimes + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { + _segment_runtimes[i].markForReset(); + _segment_runtimes[i].resetIfRequired(); + } + + _hasWhiteChannel = _isOffRefreshRequired = false; //if busses failed to load, add default (fresh install, FS issue, ...) if (busses.getNumBusses() == 0) { @@ -93,9 +98,9 @@ void WS2812FX::finalizeInit(void) if (bus == nullptr) continue; if (bus->getStart() + bus->getLength() > MAX_LEDS) break; //RGBW mode is enabled if at least one of the strips is RGBW - isRgbw |= bus->isRgbw(); + _hasWhiteChannel |= bus->isRgbw(); //refresh is required to remain off if at least one of the strips requires the refresh. - isOffRefreshRequred |= bus->isOffRefreshRequired(); + _isOffRefreshRequired |= bus->isOffRefreshRequired(); uint16_t busEnd = bus->getStart() + bus->getLength(); if (busEnd > _length) _length = busEnd; #ifdef ESP8266 @@ -131,7 +136,8 @@ void WS2812FX::service() { if (!SEGMENT.isActive()) continue; - if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) //last is temporary + // last condition ensures all solid segments are updated at the same time + if(nowUp > SEGENV.next_time || _triggered || (doShow && SEGMENT.mode == 0)) { if (SEGMENT.grouping == 0) SEGMENT.grouping = 1; //sanity check doShow = true; @@ -150,7 +156,9 @@ void WS2812FX::service() { _colors_t[slot] = transitions[t].currentColor(SEGMENT.colors[slot]); } if (!cctFromRgb || correctWB) busses.setSegmentCCT(_cct_t, correctWB); - for (uint8_t c = 0; c < 3; c++) _colors_t[c] = gamma32(_colors_t[c]); + for (uint8_t c = 0; c < NUM_COLORS; c++) { + _colors_t[c] = gamma32(_colors_t[c]); + } handle_palette(); //WLEDSR: swap width and height if rotated if (IS_ROTATED2D && stripOrMatrixPanel == 1) {//matrix @@ -165,7 +173,14 @@ void WS2812FX::service() { delay = (this->*_mode[SEGMENT.mode])(); //effect function else delay = (this->*_mode[FX_MODE_BLINK])(); //WLEDSR: blink if mode has not been activated + + // if segment is not RGB capable, force None auto white mode + // If not RGB capable, also treat palette as if default (0), as palettes set white channel to 0 + _no_rgb = !(SEGMENT.getLightCapabilities() & 0x01); + if (_no_rgb) Bus::setAutoWhiteMode(RGBW_MODE_MANUAL_ONLY); + delay = (this->*_mode[SEGMENT.mode])(); //effect function if (SEGMENT.mode != FX_MODE_HALLOWEEN_EYES) SEGENV.call++; + Bus::setAutoWhiteMode(strip.autoWhiteMode); } SEGENV.next_time = nowUp + delay; @@ -180,12 +195,12 @@ void WS2812FX::service() { _triggered = false; } -void WS2812FX::setPixelColor(uint16_t n, uint32_t c) { +void IRAM_ATTR WS2812FX::setPixelColor(uint16_t n, uint32_t c) { setPixelColor(n, R(c), G(c), B(c), W(c)); } // used to map from segment index to logical pixel, taking into account grouping, offsets, reverse and mirroring -uint16_t WS2812FX::realPixelIndex(uint16_t i) { // ewowi20210703: will not map to physical pixel index but to rotated and mirrored logical pixel index as matrix panels will require mapping. +uint16_t IRAM_ATTR WS2812FX::realPixelIndex(uint16_t i) { // ewowi20210703: will not map to physical pixel index but to rotated and mirrored logical pixel index as matrix panels will require mapping. // Mapping is done in logicalToPhysical below. Function will not be renamed to keep it consistent with Aircoookie int16_t iGroup = i * SEGMENT.groupLength(); @@ -234,7 +249,7 @@ uint16_t WS2812FX::realPixelIndex(uint16_t i) { // ewowi20210703: will not map t return realIndex; } -void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) +void IRAM_ATTR WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w) { if (SEGLEN) {//from segment uint16_t realIndex = realPixelIndex(i); // ewowi20210624: from segment index to logical index @@ -399,6 +414,15 @@ uint16_t WS2812FX::getFps() { return _cumulativeFps +1; } +uint8_t WS2812FX::getTargetFps() { + return _targetFps; +} + +void WS2812FX::setTargetFps(uint8_t fps) { + if (fps > 0 && fps <= 120) _targetFps = fps; + _frametime = 1000 / _targetFps; +} + /** * Forces the next frame to be computed on all active segments. */ @@ -413,7 +437,7 @@ void WS2812FX::setMode(uint8_t segid, uint8_t m) { if (_segments[segid].mode != m) { - _segment_runtimes[segid].reset(); + _segment_runtimes[segid].markForReset(); _segments[segid].mode = m; } } @@ -428,8 +452,8 @@ uint8_t WS2812FX::getPaletteCount() return 13 + GRADIENT_PALETTE_COUNT; } -//TODO effect transitions - +// REMOVED IN 7b969bb +/* //TODO effect transitions bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t p) { Segment& seg = _segments[getMainSegmentId()]; @@ -466,34 +490,34 @@ bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t c1, uin if (seg.mode != modePrev || seg.speed != speedPrev || seg.intensity != intensityPrev || seg.custom1 != custom1Prev || seg.custom2 != custom2Prev || seg.custom3 != custom3Prev || seg.palette != palettePrev) return true; return false; -} +} */ void WS2812FX::setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w) { setColor(slot, RGBW32(r, g, b, w)); } +//applies to all active and selected segments void WS2812FX::setColor(uint8_t slot, uint32_t c) { if (slot >= NUM_COLORS) return; - bool applied = false; - - if (applyToAllSelected) { - for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) - { - if (_segments[i].isSelected()) { - _segments[i].setColor(slot, c, i); - applied = true; - } + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) + { + if (_segments[i].isActive() && _segments[i].isSelected()) { + _segments[i].setColor(slot, c, i); } } +} - if (!applyToAllSelected || !applied) { - uint8_t mainseg = getMainSegmentId(); - _segments[mainseg].setColor(slot, c, mainseg); +void WS2812FX::setCCT(uint16_t k) { + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) + { + if (_segments[i].isActive() && _segments[i].isSelected()) { + _segments[i].setCCT(k, i); + } } } -void WS2812FX::setBrightness(uint8_t b) { +void WS2812FX::setBrightness(uint8_t b, bool direct) { if (gammaCorrectBri) b = gamma8(b); if (_brightness == b) return; _brightness = b; @@ -503,16 +527,13 @@ void WS2812FX::setBrightness(uint8_t b) { _segments[i].setOption(SEG_OPTION_FREEZE, false); } } - unsigned long t = millis(); - if (_segment_runtimes[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon -} - -uint8_t WS2812FX::getMode(void) { - return _segments[getMainSegmentId()].mode; -} - -uint8_t WS2812FX::getSpeed(void) { - return _segments[getMainSegmentId()].speed; + if (direct) { + // would be dangerous if applied immediately (could exceed ABL), but will not output until the next show() + busses.setBrightness(b); + } else { + unsigned long t = millis(); + if (_segment_runtimes[0].next_time > t + 22 && t - _lastShow > MIN_SHOW_DELAY) show(); //apply brightness change immediately if no refresh soon + } } uint8_t WS2812FX::getBrightness(void) { @@ -523,24 +544,38 @@ uint8_t WS2812FX::getMaxSegments(void) { return MAX_NUM_SEGMENTS; } -/*uint8_t WS2812FX::getFirstSelectedSegment(void) +uint8_t WS2812FX::getFirstSelectedSegId(void) { for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { if (_segments[i].isActive() && _segments[i].isSelected()) return i; } - for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //if none selected, get first active + // if none selected, use the main segment + return getMainSegmentId(); +} + +void WS2812FX::setMainSegmentId(uint8_t n) { + if (n >= MAX_NUM_SEGMENTS) return; + //use supplied n if active, or first active + if (_segments[n].isActive()) { + _mainSegment = n; return; + } + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { - if (_segments[i].isActive()) return i; + if (_segments[i].isActive()) { + _mainSegment = i; return; + } } - return 0; -}*/ + _mainSegment = 0; + return; +} uint8_t WS2812FX::getMainSegmentId(void) { - if (mainSegment >= MAX_NUM_SEGMENTS) return 0; - if (_segments[mainSegment].isActive()) return mainSegment; - for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) //get first active - { + return _mainSegment; +} + +uint8_t WS2812FX::getLastActiveSegmentId(void) { + for (uint8_t i = MAX_NUM_SEGMENTS -1; i > 0; i--) { if (_segments[i].isActive()) return i; } return 0; @@ -555,10 +590,6 @@ uint8_t WS2812FX::getActiveSegmentsNum(void) { return c; } -uint32_t WS2812FX::getColor(void) { - return _segments[getMainSegmentId()].colors[0]; -} - uint32_t WS2812FX::getPixelColor(uint16_t i) { i = realPixelIndex(i); @@ -580,8 +611,12 @@ WS2812FX::Segment& WS2812FX::getSegment(uint8_t id) { return _segments[id]; } -WS2812FX::Segment_runtime WS2812FX::getSegmentRuntime(void) { - return SEGENV; +WS2812FX::Segment& WS2812FX::getFirstSelectedSeg(void) { + return _segments[getFirstSelectedSegId()]; +} + +WS2812FX::Segment& WS2812FX::getMainSegment(void) { + return _segments[getMainSegmentId()]; } WS2812FX::Segment* WS2812FX::getSegments(void) { @@ -606,6 +641,84 @@ uint16_t WS2812FX::getLengthPhysical(void) { return len; } +uint8_t WS2812FX::Segment::differs(Segment& b) { + uint8_t d = 0; + if (start != b.start) d |= SEG_DIFFERS_BOUNDS; + if (stop != b.stop) d |= SEG_DIFFERS_BOUNDS; + if (offset != b.offset) d |= SEG_DIFFERS_GSO; + if (grouping != b.grouping) d |= SEG_DIFFERS_GSO; + if (spacing != b.spacing) d |= SEG_DIFFERS_GSO; + if (opacity != b.opacity) d |= SEG_DIFFERS_BRI; + if (mode != b.mode) d |= SEG_DIFFERS_FX; + if (speed != b.speed) d |= SEG_DIFFERS_FX; + if (intensity != b.intensity) d |= SEG_DIFFERS_FX; + if (palette != b.palette) d |= SEG_DIFFERS_FX; + + if ((options & 0b00101110) != (b.options & 0b00101110)) d |= SEG_DIFFERS_OPT; + if ((options & 0x01) != (b.options & 0x01)) d |= SEG_DIFFERS_SEL; + + for (uint8_t i = 0; i < NUM_COLORS; i++) + { + if (colors[i] != b.colors[i]) d |= SEG_DIFFERS_COL; + } + + return d; +} + +void WS2812FX::Segment::refreshLightCapabilities() { + if (!isActive()) { + _capabilities = 0; return; + } + uint8_t capabilities = 0; + uint8_t awm = instance->autoWhiteMode; + bool whiteSlider = (awm == RGBW_MODE_DUAL || awm == RGBW_MODE_MANUAL_ONLY); + bool segHasValidBus = false; + + for (uint8_t b = 0; b < busses.getNumBusses(); b++) { + Bus *bus = busses.getBus(b); + if (bus == nullptr || bus->getLength()==0) break; + if (bus->getStart() >= stop) continue; + if (bus->getStart() + bus->getLength() <= start) continue; + + segHasValidBus = true; + uint8_t type = bus->getType(); + if (type != TYPE_ANALOG_1CH && (cctFromRgb || type != TYPE_ANALOG_2CH)) + { + capabilities |= 0x01; // segment supports RGB (full color) + } + if (bus->isRgbw() && whiteSlider) capabilities |= 0x02; // segment supports white channel + if (!cctFromRgb) { + switch (type) { + case TYPE_ANALOG_5CH: + case TYPE_ANALOG_2CH: + capabilities |= 0x04; //segment supports white CCT + } + } + if (correctWB && type != TYPE_ANALOG_1CH) capabilities |= 0x04; //white balance correction (uses CCT slider) + } + // if seg has any bus, but no bus has RGB, it by definition supports white (at least for now) + // In case of no RGB, disregard auto white mode and always show a white slider + if (segHasValidBus && !(capabilities & 0x01)) capabilities |= 0x02; // segment supports white channel + _capabilities = capabilities; +} + +//used for JSON API info.leds.rgbw. Little practical use, deprecate with info.leds.rgbw. +//returns if there is an RGBW bus (supports RGB and White, not only white) +//not influenced by auto-white mode, also true if white slider does not affect output white channel +bool WS2812FX::hasRGBWBus(void) { + for (uint8_t b = 0; b < busses.getNumBusses(); b++) { + Bus *bus = busses.getBus(b); + if (bus == nullptr || bus->getLength()==0) break; + switch (bus->getType()) { + case TYPE_SK6812_RGBW: + case TYPE_TM1814: + case TYPE_ANALOG_4CH: + return true; + } + } + return false; +} + // WLEDSR: calculate 2D segment variables using start/stop of segment using the x/y coordinnates of start and stop to determine topleft (startX/Y) and bottomright (stopXY) of the segment void WS2812FX::set2DSegment(uint8_t n) { Segment& seg = _segments[n]; @@ -685,7 +798,8 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, Segment& seg = _segments[n]; //return if neither bounds nor grouping have changed - if (seg.start == i1 && seg.stop == i2 + bool boundsUnchanged = (seg.start == i1 && seg.stop == i2); + if (boundsUnchanged && (!grouping || (seg.grouping == grouping && seg.spacing == spacing)) && (offset == UINT16_MAX || offset == seg.offset)) return; @@ -697,17 +811,8 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, delete[] seg.name; seg.name = nullptr; } - if (n == mainSegment) //if main segment is deleted, set first active as main segment - { - for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) - { - if (_segments[i].isActive()) { - mainSegment = i; - return; - } - } - mainSegment = 0; //should not happen (always at least one active segment) - } + // if main segment is deleted, set first active as main segment + if (n == _mainSegment) setMainSegmentId(0); return; } if (i1 < _length) seg.start = i1; @@ -721,22 +826,23 @@ void WS2812FX::setSegment(uint8_t n, uint16_t i1, uint16_t i2, uint8_t grouping, seg.spacing = spacing; } if (offset < UINT16_MAX) seg.offset = offset; - _segment_runtimes[n].reset(); + _segment_runtimes[n].markForReset(); + if (!boundsUnchanged) seg.refreshLightCapabilities(); } void WS2812FX::restartRuntime() { for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { - _segment_runtimes[i].reset(); + _segment_runtimes[i].markForReset(); } } void WS2812FX::setReset(uint8_t n) { - _segment_runtimes[n].reset(); + _segment_runtimes[n].markForReset(); } void WS2812FX::resetSegments() { for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) if (_segments[i].name) delete[] _segments[i].name; - mainSegment = 0; + _mainSegment = 0; memset(_segments, 0, sizeof(_segments)); //memset(_segment_runtimes, 0, sizeof(_segment_runtimes)); _segment_index = 0; @@ -761,12 +867,12 @@ void WS2812FX::resetSegments() { _segments[i].cct = 127; _segments[i].speed = DEFAULT_SPEED; _segments[i].intensity = DEFAULT_INTENSITY; - _segment_runtimes[i].reset(); + _segment_runtimes[i].markForReset(); } - _segment_runtimes[0].reset(); + _segment_runtimes[0].markForReset(); } -void WS2812FX::makeAutoSegments() { +void WS2812FX::makeAutoSegments(bool forceReset) { if (autoSegments) { //make one segment per bus uint16_t segStarts[MAX_NUM_SEGMENTS] = {0}; uint16_t segStops [MAX_NUM_SEGMENTS] = {0}; @@ -792,9 +898,15 @@ void WS2812FX::makeAutoSegments() { setSegment(i, segStarts[i], segStops[i]); } } else { - //expand the main seg to the entire length, but only if there are no other segments + //expand the main seg to the entire length, but only if there are no other segments, or reset is forced uint8_t mainSeg = getMainSegmentId(); + if (forceReset) { + for (uint8_t i = 0; i < MAX_NUM_SEGMENTS; i++) { + setSegment(i, 0, 0); + } + } + if (getActiveSegmentsNum() < 2) { setSegment(mainSeg, 0, _length); } @@ -809,6 +921,8 @@ void WS2812FX::fixInvalidSegments() { { if (_segments[i].start >= _length) setSegment(i, 0, 0); if (_segments[i].stop > _length) setSegment(i, _segments[i].start, _length); + // this is always called as the last step after finalizeInit(), update covered bus types + getSegment(i).refreshLightCapabilities(); } } @@ -829,36 +943,16 @@ bool WS2812FX::checkSegmentAlignment() { } //After this function is called, setPixelColor() will use that segment (offsets, grouping, ... will apply) -//Note: If called in an interrupt (e.g. JSON API), it must be reset with "setPixelColor(255)", +//Note: If called in an interrupt (e.g. JSON API), original segment must be restored, //otherwise it can lead to a crash on ESP32 because _segment_index is modified while in use by the main thread -#ifdef ARDUINO_ARCH_ESP32 -uint8_t _segment_index_prev = 0; -uint16_t _virtualSegmentLength_prev = 0; -bool _ps_set = false; -#endif - -void WS2812FX::setPixelSegment(uint8_t n) +uint8_t WS2812FX::setPixelSegment(uint8_t n) { + uint8_t prevSegId = _segment_index; if (n < MAX_NUM_SEGMENTS) { - #ifdef ARDUINO_ARCH_ESP32 - if (!_ps_set) { - _segment_index_prev = _segment_index; - _virtualSegmentLength_prev = _virtualSegmentLength; - _ps_set = true; - } - #endif _segment_index = n; _virtualSegmentLength = SEGMENT.virtualLength(); - } else { - _virtualSegmentLength = 0; - #ifdef ARDUINO_ARCH_ESP32 - if (_ps_set) { - _segment_index = _segment_index_prev; - _virtualSegmentLength = _virtualSegmentLength_prev; - _ps_set = false; - } - #endif } + return prevSegId; } void WS2812FX::setRange(uint16_t i, uint16_t i2, uint32_t col) @@ -897,7 +991,7 @@ void WS2812FX::setTransitionMode(bool t) /* * color blend function */ -uint32_t WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) { +uint32_t IRAM_ATTR WS2812FX::color_blend(uint32_t color1, uint32_t color2, uint16_t blend, bool b16) { if(blend == 0) return color1; uint16_t blendmax = b16 ? 0xFFFF : 0xFF; if(blend == blendmax) return color2; @@ -1027,18 +1121,12 @@ void WS2812FX::blur(uint8_t blur_amount) } } -uint16_t WS2812FX::triwave16(uint16_t in) +uint16_t IRAM_ATTR WS2812FX::triwave16(uint16_t in) { if (in < 0x8000) return in *2; return 0xFFFF - (in - 0x8000)*2; } -uint8_t WS2812FX::sin_gap(uint16_t in) { - if (in & 0x100) return 0; - //if (in > 255) return 0; - return sin8(in + 192); //correct phase shift of sine so that it starts and stops at 0 -} - /* * Generates a tristate square wave w/ attac & decay * @param x input value 0-255 @@ -1100,13 +1188,13 @@ uint8_t WS2812FX::get_random_wheel_index(uint8_t pos) { } -uint32_t WS2812FX::crgb_to_col(CRGB fastled) +uint32_t IRAM_ATTR WS2812FX::crgb_to_col(CRGB fastled) { return RGBW32(fastled.red, fastled.green, fastled.blue, 0); } -CRGB WS2812FX::col_to_crgb(uint32_t color) +CRGB IRAM_ATTR WS2812FX::col_to_crgb(uint32_t color) { CRGB fastled_col; fastled_col.red = R(color); @@ -1229,24 +1317,19 @@ void WS2812FX::handle_palette(void) * @param pbri Value to scale the brightness of the returned color by. Default is 255. (no scaling) * @returns Single color from palette */ -uint32_t WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) +uint32_t IRAM_ATTR WS2812FX::color_from_palette(uint16_t i, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri) { - if (SEGMENT.palette == 0 && mcol < 3) { + if ((SEGMENT.palette == 0 && mcol < 3) || _no_rgb) { uint32_t color = SEGCOLOR(mcol); - if (pbri != 255) { - CRGB crgb_color = col_to_crgb(color); - crgb_color.nscale8_video(pbri); - return crgb_to_col(crgb_color); - } else { - return color; - } + if (pbri == 255) return color; + return RGBW32(scale8_video(R(color),pbri), scale8_video(G(color),pbri), scale8_video(B(color),pbri), scale8_video(W(color),pbri)); } uint8_t paletteIndex = i; if (mapping && SEGLEN > 1) paletteIndex = (i*255)/(SEGLEN -1); if (!wrap) paletteIndex = scale8(paletteIndex, 240); //cut off blend at palette "end" CRGB fastled_col; - fastled_col = ColorFromPalette( currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND); + fastled_col = ColorFromPalette(currentPalette, paletteIndex, pbri, (paletteBlend == 3)? NOBLEND:LINEARBLEND); return crgb_to_col(fastled_col); } diff --git a/wled00/alexa.cpp b/wled00/alexa.cpp index 097ef2ac73..e41b7e3fb8 100644 --- a/wled00/alexa.cpp +++ b/wled00/alexa.cpp @@ -44,7 +44,7 @@ void onAlexaChange(EspalexaDevice* dev) if (bri == 0) { bri = briLast; - colorUpdated(CALL_MODE_ALEXA); + stateUpdated(CALL_MODE_ALEXA); } } else { applyPreset(macroAlexaOn, CALL_MODE_ALEXA); @@ -58,7 +58,7 @@ void onAlexaChange(EspalexaDevice* dev) { briLast = bri; bri = 0; - colorUpdated(CALL_MODE_ALEXA); + stateUpdated(CALL_MODE_ALEXA); } } else { applyPreset(macroAlexaOff, CALL_MODE_ALEXA); @@ -67,43 +67,37 @@ void onAlexaChange(EspalexaDevice* dev) } else if (m == EspalexaDeviceProperty::bri) { bri = espalexaDevice->getValue(); - colorUpdated(CALL_MODE_ALEXA); + stateUpdated(CALL_MODE_ALEXA); } else //color { if (espalexaDevice->getColorMode() == EspalexaColorMode::ct) //shade of white { + byte rgbw[4]; uint16_t ct = espalexaDevice->getCt(); if (!ct) return; uint16_t k = 1000000 / ct; //mireds to kelvin if (strip.hasCCTBus()) { - uint8_t segid = strip.getMainSegmentId(); - WS2812FX::Segment& seg = strip.getSegment(segid); - uint8_t cctPrev = seg.cct; - seg.setCCT(k, segid); - if (seg.cct != cctPrev) effectChanged = true; //send UDP - col[0]= 0; col[1]= 0; col[2]= 0; col[3]= 255; - } else if (strip.isRgbw) { + strip.setCCT(k); + rgbw[0]= 0; rgbw[1]= 0; rgbw[2]= 0; rgbw[3]= 255; + } else if (strip.hasWhiteChannel()) { switch (ct) { //these values empirically look good on RGBW - case 199: col[0]=255; col[1]=255; col[2]=255; col[3]=255; break; - case 234: col[0]=127; col[1]=127; col[2]=127; col[3]=255; break; - case 284: col[0]= 0; col[1]= 0; col[2]= 0; col[3]=255; break; - case 350: col[0]=130; col[1]= 90; col[2]= 0; col[3]=255; break; - case 383: col[0]=255; col[1]=153; col[2]= 0; col[3]=255; break; - default : colorKtoRGB(k, col); + case 199: rgbw[0]=255; rgbw[1]=255; rgbw[2]=255; rgbw[3]=255; break; + case 234: rgbw[0]=127; rgbw[1]=127; rgbw[2]=127; rgbw[3]=255; break; + case 284: rgbw[0]= 0; rgbw[1]= 0; rgbw[2]= 0; rgbw[3]=255; break; + case 350: rgbw[0]=130; rgbw[1]= 90; rgbw[2]= 0; rgbw[3]=255; break; + case 383: rgbw[0]=255; rgbw[1]=153; rgbw[2]= 0; rgbw[3]=255; break; + default : colorKtoRGB(k, rgbw); } } else { - colorKtoRGB(k, col); + colorKtoRGB(k, rgbw); } + strip.setColor(0, rgbw[0], rgbw[1], rgbw[2], rgbw[3]); } else { uint32_t color = espalexaDevice->getRGB(); - - col[0] = ((color >> 16) & 0xFF); - col[1] = ((color >> 8) & 0xFF); - col[2] = ( color & 0xFF); - col[3] = 0; + strip.setColor(0, color); } - colorUpdated(CALL_MODE_ALEXA); + stateUpdated(CALL_MODE_ALEXA); } } diff --git a/wled00/blynk.cpp b/wled00/blynk.cpp index ce39044877..b1619d816e 100644 --- a/wled00/blynk.cpp +++ b/wled00/blynk.cpp @@ -44,27 +44,27 @@ void updateBlynk() BLYNK_WRITE(V0) { bri = param.asInt();//bri - colorUpdated(CALL_MODE_BLYNK); + stateUpdated(CALL_MODE_BLYNK); } BLYNK_WRITE(V1) { blHue = param.asInt();//hue - colorHStoRGB(blHue*10,blSat,(false)? colSec:col); + colorHStoRGB(blHue*10,blSat,col); colorUpdated(CALL_MODE_BLYNK); } BLYNK_WRITE(V2) { blSat = param.asInt();//sat - colorHStoRGB(blHue*10,blSat,(false)? colSec:col); + colorHStoRGB(blHue*10,blSat,col); colorUpdated(CALL_MODE_BLYNK); } BLYNK_WRITE(V3) { bool on = (param.asInt()>0); - if (!on != !bri) {toggleOnOff(); colorUpdated(CALL_MODE_BLYNK);} + if (!on != !bri) {toggleOnOff(); stateUpdated(CALL_MODE_BLYNK);} } BLYNK_WRITE(V4) diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index b1f36c8d94..7e065f8fa2 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -73,6 +73,62 @@ struct BusConfig { } }; +// Defines an LED Strip and its color ordering. +struct ColorOrderMapEntry { + uint16_t start; + uint16_t len; + uint8_t colorOrder; +}; + +struct ColorOrderMap { + void add(uint16_t start, uint16_t len, uint8_t colorOrder) { + if (_count >= WLED_MAX_COLOR_ORDER_MAPPINGS) { + return; + } + if (len == 0) { + return; + } + if (colorOrder > COL_ORDER_MAX) { + return; + } + _mappings[_count].start = start; + _mappings[_count].len = len; + _mappings[_count].colorOrder = colorOrder; + _count++; + } + + uint8_t count() const { + return _count; + } + + void reset() { + _count = 0; + memset(_mappings, 0, sizeof(_mappings)); + } + + const ColorOrderMapEntry* get(uint8_t n) const { + if (n > _count) { + return nullptr; + } + return &(_mappings[n]); + } + + inline uint8_t IRAM_ATTR getPixelColorOrder(uint16_t pix, uint8_t defaultColorOrder) const { + if (_count == 0) return defaultColorOrder; + + for (uint8_t i = 0; i < _count; i++) { + if (pix >= _mappings[i].start && pix < (_mappings[i].start + _mappings[i].len)) { + return _mappings[i].colorOrder; + } + } + return defaultColorOrder; + } + + private: + uint8_t _count; + ColorOrderMapEntry _mappings[WLED_MAX_COLOR_ORDER_MAPPINGS]; +}; + //parent class of BusDigital, BusPwm, and BusNetwork class Bus { public: @@ -151,7 +207,7 @@ class Bus { class BusDigital : public Bus { public: - BusDigital(BusConfig &bc, uint8_t nr) : Bus(bc.type, bc.start) { + BusDigital(BusConfig &bc, uint8_t nr, const ColorOrderMap &com) : Bus(bc.type, bc.start), _colorOrderMap(com) { if (!IS_DIGITAL(bc.type) || !bc.count) return; if (!pinManager.allocatePin(bc.pins[0], true, PinOwner::BusDigital)) return; _pins[0] = bc.pins[0]; @@ -196,7 +252,7 @@ class BusDigital : public Bus { //TODO only show if no new show due in the next 50ms void setStatusPixel(uint32_t c) { if (_skip && canShow()) { - PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrder); + PolyBus::setPixelColor(_busPtr, _iType, 0, c, _colorOrderMap.getPixelColorOrder(_start, _colorOrder)); PolyBus::show(_busPtr, _iType); } } @@ -206,13 +262,13 @@ class BusDigital : public Bus { if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT if (reversed) pix = _len - pix -1; else pix += _skip; - PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrder); + PolyBus::setPixelColor(_busPtr, _iType, pix, c, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder)); } uint32_t getPixelColor(uint16_t pix) { if (reversed) pix = _len - pix -1; else pix += _skip; - return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrder); + return PolyBus::getPixelColor(_busPtr, _iType, pix, _colorOrderMap.getPixelColorOrder(pix+_start, _colorOrder)); } inline uint8_t getColorOrder() { @@ -262,6 +318,7 @@ class BusDigital : public Bus { uint8_t _iType = I_NONE; uint8_t _skip = 0; void * _busPtr = nullptr; + const ColorOrderMap &_colorOrderMap; }; @@ -287,7 +344,7 @@ class BusPwm : public Bus { if (!pinManager.allocatePin(currentPin, true, PinOwner::BusPwm)) { deallocatePins(); return; } - _pins[i] = currentPin; // store only after allocatePin() succeeds + _pins[i] = currentPin; //store only after allocatePin() succeeds #ifdef ESP8266 pinMode(_pins[i], OUTPUT); #else @@ -396,7 +453,7 @@ class BusPwm : public Bus { private: uint8_t _pins[5] = {255, 255, 255, 255, 255}; - uint8_t _data[5] = {255, 255, 255, 255, 255}; + uint8_t _data[5] = {0}; #ifdef ARDUINO_ARCH_ESP32 uint8_t _ledcStart = 255; #endif @@ -554,7 +611,7 @@ class BusManager { if (bc.type >= TYPE_NET_DDP_RGB && bc.type < 96) { busses[numBusses] = new BusNetwork(bc); } else if (IS_DIGITAL(bc.type)) { - busses[numBusses] = new BusDigital(bc, numBusses); + busses[numBusses] = new BusDigital(bc, numBusses, colorOrderMap); } else { busses[numBusses] = new BusPwm(bc); } @@ -582,7 +639,7 @@ class BusManager { } } - void setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1) { + void IRAM_ATTR setPixelColor(uint16_t pix, uint32_t c, int16_t cct=-1) { for (uint8_t i = 0; i < numBusses; i++) { Bus* b = busses[i]; uint16_t bstart = b->getStart(); @@ -639,8 +696,17 @@ class BusManager { return len; } + void updateColorOrderMap(const ColorOrderMap &com) { + memcpy(&colorOrderMap, &com, sizeof(ColorOrderMap)); + } + + const ColorOrderMap& getColorOrderMap() const { + return colorOrderMap; + } + private: uint8_t numBusses = 0; Bus* busses[WLED_MAX_BUSSES]; + ColorOrderMap colorOrderMap; }; #endif diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index a762143f07..95549cb08a 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -98,26 +98,34 @@ #ifdef ARDUINO_ARCH_ESP32 //RGB #define B_32_RN_NEO_3 NeoPixelBrightnessBus +#ifndef CONFIG_IDF_TARGET_ESP32C3 #define B_32_I0_NEO_3 NeoPixelBrightnessBus -#ifndef CONFIG_IDF_TARGET_ESP32S2 +#endif +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) #define B_32_I1_NEO_3 NeoPixelBrightnessBus #endif //RGBW #define B_32_RN_NEO_4 NeoPixelBrightnessBus +#ifndef CONFIG_IDF_TARGET_ESP32C3 #define B_32_I0_NEO_4 NeoPixelBrightnessBus -#ifndef CONFIG_IDF_TARGET_ESP32S2 +#endif +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) #define B_32_I1_NEO_4 NeoPixelBrightnessBus #endif //400Kbps #define B_32_RN_400_3 NeoPixelBrightnessBus +#ifndef CONFIG_IDF_TARGET_ESP32C3 #define B_32_I0_400_3 NeoPixelBrightnessBus -#ifndef CONFIG_IDF_TARGET_ESP32S2 +#endif +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) #define B_32_I1_400_3 NeoPixelBrightnessBus #endif //TM1814 (RGBW) #define B_32_RN_TM1_4 NeoPixelBrightnessBus +#ifndef CONFIG_IDF_TARGET_ESP32C3 #define B_32_I0_TM1_4 NeoPixelBrightnessBus -#ifndef CONFIG_IDF_TARGET_ESP32S2 +#endif +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) #define B_32_I1_TM1_4 NeoPixelBrightnessBus #endif //Bit Bang theoratically possible, but very undesirable and not needed (no pin restrictions on RMT and I2S) @@ -125,7 +133,7 @@ #endif //APA102 -#define B_HS_DOT_3 NeoPixelBrightnessBus //hardware SPI +#define B_HS_DOT_3 NeoPixelBrightnessBus //hardware SPI #define B_SS_DOT_3 NeoPixelBrightnessBus //soft SPI //LPD8806 @@ -181,23 +189,31 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->Begin(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_3: (static_cast(busPtr))->Begin(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_3: (static_cast(busPtr))->Begin(); break; #endif case I_32_RN_NEO_4: (static_cast(busPtr))->Begin(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_4: (static_cast(busPtr))->Begin(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_4: (static_cast(busPtr))->Begin(); break; #endif case I_32_RN_400_3: (static_cast(busPtr))->Begin(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_400_3: (static_cast(busPtr))->Begin(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_400_3: (static_cast(busPtr))->Begin(); break; #endif case I_32_RN_TM1_4: beginTM1814(busPtr); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_TM1_4: beginTM1814(busPtr); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_TM1_4: beginTM1814(busPtr); break; #endif // ESP32 can (and should, to avoid inadvertantly driving the chip select signal) specify the pins used for SPI, but only in begin() @@ -236,23 +252,31 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: busPtr = new B_32_RN_NEO_3(len, pins[0], (NeoBusChannel)channel); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_3: busPtr = new B_32_I0_NEO_3(len, pins[0]); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_3: busPtr = new B_32_I1_NEO_3(len, pins[0]); break; #endif case I_32_RN_NEO_4: busPtr = new B_32_RN_NEO_4(len, pins[0], (NeoBusChannel)channel); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_4: busPtr = new B_32_I0_NEO_4(len, pins[0]); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_4: busPtr = new B_32_I1_NEO_4(len, pins[0]); break; #endif case I_32_RN_400_3: busPtr = new B_32_RN_400_3(len, pins[0], (NeoBusChannel)channel); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_400_3: busPtr = new B_32_I0_400_3(len, pins[0]); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_400_3: busPtr = new B_32_I1_400_3(len, pins[0]); break; #endif case I_32_RN_TM1_4: busPtr = new B_32_RN_TM1_4(len, pins[0], (NeoBusChannel)channel); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_TM1_4: busPtr = new B_32_I0_TM1_4(len, pins[0]); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_TM1_4: busPtr = new B_32_I1_TM1_4(len, pins[0]); break; #endif #endif @@ -292,23 +316,31 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->Show(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_3: (static_cast(busPtr))->Show(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_3: (static_cast(busPtr))->Show(); break; #endif case I_32_RN_NEO_4: (static_cast(busPtr))->Show(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_4: (static_cast(busPtr))->Show(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_4: (static_cast(busPtr))->Show(); break; #endif case I_32_RN_400_3: (static_cast(busPtr))->Show(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_400_3: (static_cast(busPtr))->Show(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_400_3: (static_cast(busPtr))->Show(); break; #endif case I_32_RN_TM1_4: (static_cast(busPtr))->Show(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_TM1_4: (static_cast(busPtr))->Show(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_TM1_4: (static_cast(busPtr))->Show(); break; #endif #endif @@ -345,23 +377,31 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: return (static_cast(busPtr))->CanShow(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_3: return (static_cast(busPtr))->CanShow(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_3: return (static_cast(busPtr))->CanShow(); break; #endif case I_32_RN_NEO_4: return (static_cast(busPtr))->CanShow(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_4: return (static_cast(busPtr))->CanShow(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_4: return (static_cast(busPtr))->CanShow(); break; #endif case I_32_RN_400_3: return (static_cast(busPtr))->CanShow(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_400_3: return (static_cast(busPtr))->CanShow(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_400_3: return (static_cast(busPtr))->CanShow(); break; #endif case I_32_RN_TM1_4: return (static_cast(busPtr))->CanShow(); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_TM1_4: return (static_cast(busPtr))->CanShow(); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_TM1_4: return (static_cast(busPtr))->CanShow(); break; #endif #endif @@ -422,23 +462,31 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; #endif case I_32_RN_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; #endif case I_32_RN_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_400_3: (static_cast(busPtr))->SetPixelColor(pix, RgbColor(col.R,col.G,col.B)); break; #endif case I_32_RN_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_TM1_4: (static_cast(busPtr))->SetPixelColor(pix, col); break; #endif #endif @@ -475,23 +523,31 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_3: (static_cast(busPtr))->SetBrightness(b); break; #endif case I_32_RN_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_4: (static_cast(busPtr))->SetBrightness(b); break; #endif case I_32_RN_400_3: (static_cast(busPtr))->SetBrightness(b); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_400_3: (static_cast(busPtr))->SetBrightness(b); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_400_3: (static_cast(busPtr))->SetBrightness(b); break; #endif case I_32_RN_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_TM1_4: (static_cast(busPtr))->SetBrightness(b); break; #endif #endif @@ -529,23 +585,31 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; #endif case I_32_RN_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; #endif case I_32_RN_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_400_3: col = (static_cast(busPtr))->GetPixelColor(pix); break; #endif case I_32_RN_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_TM1_4: col = (static_cast(busPtr))->GetPixelColor(pix); break; #endif #endif @@ -600,23 +664,31 @@ class PolyBus { #endif #ifdef ARDUINO_ARCH_ESP32 case I_32_RN_NEO_3: delete (static_cast(busPtr)); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_3: delete (static_cast(busPtr)); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_3: delete (static_cast(busPtr)); break; #endif case I_32_RN_NEO_4: delete (static_cast(busPtr)); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_NEO_4: delete (static_cast(busPtr)); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_NEO_4: delete (static_cast(busPtr)); break; #endif case I_32_RN_400_3: delete (static_cast(busPtr)); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_400_3: delete (static_cast(busPtr)); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_400_3: delete (static_cast(busPtr)); break; #endif case I_32_RN_TM1_4: delete (static_cast(busPtr)); break; + #ifndef CONFIG_IDF_TARGET_ESP32C3 case I_32_I0_TM1_4: delete (static_cast(busPtr)); break; - #ifndef CONFIG_IDF_TARGET_ESP32S2 + #endif + #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) case I_32_I1_TM1_4: delete (static_cast(busPtr)); break; #endif #endif @@ -692,4 +764,4 @@ class PolyBus { } }; -#endif \ No newline at end of file +#endif diff --git a/wled00/button.cpp b/wled00/button.cpp index aaeb3dc602..31d3022c89 100644 --- a/wled00/button.cpp +++ b/wled00/button.cpp @@ -4,11 +4,12 @@ * Physical IO */ -#define WLED_DEBOUNCE_THRESHOLD 50 //only consider button input of at least 50ms as valid (debouncing) -#define WLED_LONG_PRESS 600 //long press if button is released after held for at least 600ms -#define WLED_DOUBLE_PRESS 350 //double press if another press within 350ms after a short press -#define WLED_LONG_REPEATED_ACTION 300 //how often a repeated action (e.g. dimming) is fired on long press on button IDs >0 -#define WLED_LONG_AP 6000 //how long the button needs to be held to activate WLED-AP +#define WLED_DEBOUNCE_THRESHOLD 50 // only consider button input of at least 50ms as valid (debouncing) +#define WLED_LONG_PRESS 600 // long press if button is released after held for at least 600ms +#define WLED_DOUBLE_PRESS 350 // double press if another press within 350ms after a short press +#define WLED_LONG_REPEATED_ACTION 300 // how often a repeated action (e.g. dimming) is fired on long press on button IDs >0 +#define WLED_LONG_AP 5000 // how long button 0 needs to be held to activate WLED-AP +#define WLED_LONG_FACTORY_RESET 10000 // how long button 0 needs to be held to trigger a factory reset static const char _mqtt_topic_button[] PROGMEM = "%s/button/%d"; // optimize flash usage @@ -16,8 +17,8 @@ void shortPressAction(uint8_t b) { if (!macroButton[b]) { switch (b) { - case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break; - default: ++effectCurrent %= strip.getModeCount(); colorUpdated(CALL_MODE_BUTTON); break; + case 0: toggleOnOff(); stateUpdated(CALL_MODE_BUTTON); break; + case 1: ++effectCurrent %= strip.getModeCount(); colorUpdated(CALL_MODE_BUTTON); break; } } else { applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); @@ -35,8 +36,8 @@ void longPressAction(uint8_t b) { if (!macroLongPress[b]) { switch (b) { - case 0: _setRandomColor(false,true); break; - default: bri += 8; colorUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action + case 0: setRandomColor(col); colorUpdated(CALL_MODE_BUTTON); break; + case 1: bri += 8; stateUpdated(CALL_MODE_BUTTON); buttonPressedTime[b] = millis(); break; // repeatable action } } else { applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); @@ -55,7 +56,7 @@ void doublePressAction(uint8_t b) if (!macroDoublePress[b]) { switch (b) { //case 0: toggleOnOff(); colorUpdated(CALL_MODE_BUTTON); break; //instant short press on button 0 if no macro set - default: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break; + case 1: ++effectPalette %= strip.getPaletteCount(); colorUpdated(CALL_MODE_BUTTON); break; } } else { applyPreset(macroDoublePress[b], CALL_MODE_BUTTON_PRESET); @@ -72,21 +73,23 @@ void doublePressAction(uint8_t b) bool isButtonPressed(uint8_t i) { if (btnPin[i]<0) return false; + uint8_t pin = btnPin[i]; + switch (buttonType[i]) { case BTN_TYPE_NONE: case BTN_TYPE_RESERVED: break; case BTN_TYPE_PUSH: case BTN_TYPE_SWITCH: - if (digitalRead(btnPin[i]) == LOW) return true; + if (digitalRead(pin) == LOW) return true; break; case BTN_TYPE_PUSH_ACT_HIGH: case BTN_TYPE_PIR_SENSOR: - if (digitalRead(btnPin[i]) == HIGH) return true; + if (digitalRead(pin) == HIGH) return true; break; case BTN_TYPE_TOUCH: - #ifdef ARDUINO_ARCH_ESP32 - if (touchRead(btnPin[i]) <= touchThreshold) return true; + #if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) + if (touchRead(pin) <= touchThreshold) return true; #endif break; } @@ -107,12 +110,12 @@ void handleSwitch(uint8_t b) if (!buttonPressedBefore[b]) { // on -> off if (macroButton[b]) applyPreset(macroButton[b], CALL_MODE_BUTTON_PRESET); else { //turn on - if (!bri) {toggleOnOff(); colorUpdated(CALL_MODE_BUTTON);} + if (!bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);} } } else { // off -> on if (macroLongPress[b]) applyPreset(macroLongPress[b], CALL_MODE_BUTTON_PRESET); else { //turn off - if (bri) {toggleOnOff(); colorUpdated(CALL_MODE_BUTTON);} + if (bri) {toggleOnOff(); stateUpdated(CALL_MODE_BUTTON);} } } @@ -159,36 +162,17 @@ void handleAnalog(uint8_t b) } else if (macroDoublePress[b] == 249) { // effect speed effectSpeed = aRead; - effectChanged = true; - for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { - WS2812FX::Segment& seg = strip.getSegment(i); - if (!seg.isSelected()) continue; - seg.speed = effectSpeed; - } } else if (macroDoublePress[b] == 248) { // effect intensity effectIntensity = aRead; - effectChanged = true; - for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { - WS2812FX::Segment& seg = strip.getSegment(i); - if (!seg.isSelected()) continue; - seg.intensity = effectIntensity; - } } else if (macroDoublePress[b] == 247) { // selected palette effectPalette = map(aRead, 0, 252, 0, strip.getPaletteCount()-1); - effectChanged = true; - for (uint8_t i = 0; i < strip.getMaxSegments(); i++) { - WS2812FX::Segment& seg = strip.getSegment(i); - if (!seg.isSelected()) continue; - seg.palette = effectPalette; - } } else if (macroDoublePress[b] == 200) { // primary color, hue, full saturation colorHStoRGB(aRead*256,255,col); } else { // otherwise use "double press" for segment selection - //uint8_t mainSeg = strip.getMainSegmentId(); WS2812FX::Segment& seg = strip.getSegment(macroDoublePress[b]); if (aRead == 0) { seg.setOption(SEG_OPTION_ON, 0); // off @@ -210,6 +194,7 @@ void handleAnalog(uint8_t b) void handleButton() { static unsigned long lastRead = 0UL; + bool analog = false; for (uint8_t b=0; b 250) { // button is not a button but a potentiometer - if (b+1 == WLED_MAX_BUTTONS) lastRead = millis(); + analog = true; handleAnalog(b); continue; } @@ -252,10 +237,16 @@ void handleButton() bool doublePress = buttonWaitTime[b]; //did we have a short press before? buttonWaitTime[b] = 0; - if (b == 0 && dur > WLED_LONG_AP) { //long press on button 0 (when released) - WLED::instance().initAP(true); + if (b == 0 && dur > WLED_LONG_AP) { // long press on button 0 (when released) + if (dur > WLED_LONG_FACTORY_RESET) { // factory reset if pressed > 10 seconds + WLED_FS.format(); + clearEEPROM(); + doReboot = true; + } else { + WLED::instance().initAP(true); + } } else if (!buttonLongPressed[b]) { //short press - if (b == 0 && !macroDoublePress[b]) { //don't wait for double press on button 0 if no double press macro set + if (b != 1 && !macroDoublePress[b]) { //don't wait for double press on buttons without a default action if no double press macro set shortPressAction(b); } else { //double press if less than 350 ms between current press and previous short press release (buttonWaitTime!=0) if (doublePress) { @@ -275,6 +266,7 @@ void handleButton() shortPressAction(b); } } + if (analog) lastRead = millis(); } void handleIO() @@ -300,7 +292,7 @@ void handleIO() // turn off built-in LED if strip is turned off // this will break digital bus so will need to be reinitialised on On PinOwner ledPinOwner = pinManager.getPinOwner(LED_BUILTIN); - if (!strip.isOffRefreshRequred && (ledPinOwner == PinOwner::None || ledPinOwner == PinOwner::BusDigital)) { + if (!strip.isOffRefreshRequired() && (ledPinOwner == PinOwner::None || ledPinOwner == PinOwner::BusDigital)) { pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); } @@ -312,4 +304,4 @@ void handleIO() } offMode = true; } -} +} \ No newline at end of file diff --git a/wled00/cfg.cpp b/wled00/cfg.cpp index 1cf8fc293b..a54152dcb5 100644 --- a/wled00/cfg.cpp +++ b/wled00/cfg.cpp @@ -79,15 +79,18 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { JsonObject hw = doc[F("hw")]; // initialize LED pins and lengths prior to other HW (except for ethernet) - JsonObject hw_led = hw[F("led")]; + JsonObject hw_led = hw["led"]; CJSON(strip.ablMilliampsMax, hw_led[F("maxpwr")]); CJSON(strip.milliampsPerLed, hw_led[F("ledma")]); - Bus::setAutoWhiteMode(hw_led[F("rgbwm")] | Bus::getAutoWhiteMode()); + CJSON(strip.autoWhiteMode, hw_led[F("rgbwm")]); + Bus::setAutoWhiteMode(strip.autoWhiteMode); + strip.fixInvalidSegments(); // refreshes segment light capabilities (in case auto white mode changed) CJSON(correctWB, hw_led["cct"]); CJSON(cctFromRgb, hw_led[F("cr")]); - CJSON(strip.cctBlending, hw_led[F("cb")]); - Bus::setCCTBlend(strip.cctBlending); + CJSON(strip.cctBlending, hw_led[F("cb")]); + Bus::setCCTBlend(strip.cctBlending); + strip.setTargetFps(hw_led["fps"]); //NOP if 0, default 42 FPS // 2D Matrix Settings CJSON(strip.stripOrMatrixPanel, hw_led[F("somp")]); @@ -111,7 +114,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (fromFS || !ins.isNull()) { uint8_t s = 0; // bus iterator - busses.removeAll(); + if (fromFS) busses.removeAll(); // can't safely manipulate busses directly in network callback uint32_t mem = 0; for (JsonObject elm : ins) { if (s >= WLED_MAX_BUSSES) break; @@ -125,7 +128,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (i>4) break; } - uint16_t length = elm[F("len")] | 1; + uint16_t length = elm["len"] | 1; uint8_t colorOrder = (int)elm[F("order")]; uint8_t skipFirst = elm[F("skip")]; uint16_t start = elm["start"] | 0; @@ -133,16 +136,38 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { uint8_t ledType = elm["type"] | TYPE_WS2812_RGB; bool reversed = elm["rev"]; bool refresh = elm["ref"] | false; - ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh + ledType |= refresh << 7; // hack bit 7 to indicate strip requires off refresh s++; - BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst); - mem += BusManager::memUsage(bc); - if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip() + if (fromFS) { + BusConfig bc = BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst); + mem += BusManager::memUsage(bc); + if (mem <= MAX_LED_MEMORY && busses.getNumBusses() <= WLED_MAX_BUSSES) busses.add(bc); // finalization will be done in WLED::beginStrip() + } else { + if (busConfigs[s] != nullptr) delete busConfigs[s]; + busConfigs[s] = new BusConfig(ledType, pins, start, length, colorOrder, reversed, skipFirst); + doInitBusses = true; + } } // finalization done in beginStrip() } if (hw_led["rev"]) busses.getBus(0)->reversed = true; //set 0.11 global reversed setting for first bus + // read color order map configuration + JsonArray hw_com = hw[F("com")]; + if (!hw_com.isNull()) { + ColorOrderMap com = {}; + uint8_t s = 0; + for (JsonObject entry : hw_com) { + if (s > WLED_MAX_COLOR_ORDER_MAPPINGS) break; + uint16_t start = entry["start"] | 0; + uint16_t len = entry["len"] | 0; + uint8_t colorOrder = (int)entry[F("order")]; + com.add(start, len, colorOrder); + s++; + } + busses.updateColorOrderMap(com); + } + // read multiple button configuration JsonObject btn_obj = hw["btn"]; JsonArray hw_btn_ins = btn_obj[F("ins")]; @@ -200,6 +225,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { } } CJSON(irEnabled, hw["ir"]["type"]); + CJSON(irApplyToAllSelected, hw["ir"]["sel"]); JsonObject relay = hw[F("relay")]; int hw_relay_pin = relay["pin"] | -2; @@ -215,6 +241,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { rlyMde = !relay["rev"]; } + CJSON(serialBaud, hw[F("baud")]); + if (serialBaud < 96 || serialBaud > 15000) serialBaud = 1152; + updateBaudRate(serialBaud *100); + // Sound Reactive Pin Config JsonObject analogmic = hw[F("analogmic")]; // analog mic JsonObject @@ -268,22 +298,22 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { if (light_gc_col > 1.5) strip.gammaCorrectCol = true; else if (light_gc_col > 0.5) strip.gammaCorrectCol = false; - JsonObject light_tr = light[F("tr")]; - CJSON(fadeTransition, light_tr[F("mode")]); + JsonObject light_tr = light["tr"]; + CJSON(fadeTransition, light_tr["mode"]); int tdd = light_tr["dur"] | -1; if (tdd >= 0) transitionDelayDefault = tdd * 100; CJSON(strip.paletteFade, light_tr["pal"]); JsonObject light_nl = light["nl"]; - CJSON(nightlightMode, light_nl[F("mode")]); + CJSON(nightlightMode, light_nl["mode"]); byte prev = nightlightDelayMinsDefault; - CJSON(nightlightDelayMinsDefault, light_nl[F("dur")]); + CJSON(nightlightDelayMinsDefault, light_nl["dur"]); if (nightlightDelayMinsDefault != prev) nightlightDelayMins = nightlightDelayMinsDefault; CJSON(nightlightTargetBri, light_nl[F("tbri")]); CJSON(macroNl, light_nl["macro"]); - JsonObject def = doc[F("def")]; + JsonObject def = doc["def"]; CJSON(bootPreset, def["ps"]); CJSON(turnOnAtBoot, def["on"]); // true CJSON(briS, def["bri"]); // 128 @@ -291,7 +321,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { // if == interfaces JsonObject interfaces = doc["if"]; - JsonObject if_sync = interfaces[F("sync")]; + JsonObject if_sync = interfaces["sync"]; CJSON(udpPort, if_sync[F("port0")]); // 21324 CJSON(udpPort2, if_sync[F("port1")]); // 65506 @@ -300,8 +330,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(receiveNotificationColor, if_sync_recv["col"]); CJSON(receiveNotificationEffects, if_sync_recv["fx"]); CJSON(receiveGroups, if_sync_recv["grp"]); + CJSON(receiveSegmentOptions, if_sync_recv["seg"]); + CJSON(receiveSegmentBounds, if_sync_recv["sb"]); //! following line might be a problem if called after boot - receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects); + receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions); JsonObject if_sync_send = if_sync["send"]; prev = notifyDirectDefault; @@ -328,7 +360,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(e131Universe, if_live_dmx[F("uni")]); CJSON(e131SkipOutOfSequence, if_live_dmx[F("seqskip")]); CJSON(DMXAddress, if_live_dmx[F("addr")]); - CJSON(DMXMode, if_live_dmx[F("mode")]); + CJSON(DMXMode, if_live_dmx["mode"]); tdd = if_live[F("timeout")] | -1; if (tdd >= 0) realtimeTimeoutMs = tdd * 100; @@ -394,10 +426,8 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { // ol == overlay JsonObject ol = doc[F("ol")]; - prev = overlayDefault; - CJSON(overlayDefault ,ol[F("clock")]); // 0 + CJSON(overlayCurrent ,ol[F("clock")]); // 0 CJSON(countdownMode, ol[F("cntdwn")]); - if (prev != overlayDefault) overlayCurrent = overlayDefault; CJSON(overlayMin, ol["min"]); CJSON(overlayMax, ol[F("max")]); @@ -427,7 +457,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { CJSON(timerMinutes[it], timer["min"]); CJSON(timerMacro[it], timer["macro"]); - byte dowPrev = timerWeekday[it]; + byte dowPrev = timerWeekday[it]; //note: act is currently only 0 or 1. //the reason we are not using bool is that the on-disk type in 0.11.0 was already int int actPrev = timerWeekday[it] & 0x01; @@ -437,7 +467,17 @@ bool deserializeConfig(JsonObject doc, bool fromFS) { int act = timer["en"] | actPrev; if (act) timerWeekday[it]++; } - + if (it<8) { + JsonObject start = timer["start"]; + byte startm = start["mon"]; + if (startm) timerMonth[it] = (startm << 4); + CJSON(timerDay[it], start["day"]); + JsonObject end = timer["end"]; + CJSON(timerDayEnd[it], end["day"]); + byte endm = end["mon"]; + if (startm) timerMonth[it] += endm & 0x0F; + if (!(timerMonth[it] & 0x0F)) timerMonth[it] += 12; //default end month to 12 + } it++; } @@ -617,8 +657,9 @@ void serializeConfig() { hw_led[F("ledma")] = strip.milliampsPerLed; hw_led["cct"] = correctWB; hw_led[F("cr")] = cctFromRgb; - hw_led[F("cb")] = strip.cctBlending; - hw_led[F("rgbwm")] = Bus::getAutoWhiteMode(); + hw_led[F("cb")] = strip.cctBlending; + hw_led["fps"] = strip.getTargetFps(); + hw_led[F("rgbwm")] = strip.autoWhiteMode; // 2D Matrix Settings hw_led[F("somp")] = strip.stripOrMatrixPanel; @@ -644,7 +685,7 @@ void serializeConfig() { if (!bus || bus->getLength()==0) break; JsonObject ins = hw_led_ins.createNestedObject(); ins["start"] = bus->getStart(); - ins[F("len")] = bus->getLength(); + ins["len"] = bus->getLength(); JsonArray ins_pin = ins.createNestedArray("pin"); uint8_t pins[5]; uint8_t nPins = bus->getPins(pins); @@ -654,7 +695,19 @@ void serializeConfig() { ins[F("skip")] = bus->skippedLeds(); ins["type"] = bus->getType() & 0x7F; ins["ref"] = bus->isOffRefreshRequired(); - ins[F("rgbw")] = bus->isRgbw(); + //ins[F("rgbw")] = bus->isRgbw(); + } + + JsonArray hw_com = hw.createNestedArray(F("com")); + const ColorOrderMap& com = busses.getColorOrderMap(); + for (uint8_t s = 0; s < com.count(); s++) { + const ColorOrderMapEntry *entry = com.get(s); + if (!entry) break; + + JsonObject co = hw_com.createNestedObject(); + co["start"] = entry->start; + co["len"] = entry->len; + co[F("order")] = entry->colorOrder; } // button(s) @@ -680,11 +733,14 @@ void serializeConfig() { JsonObject hw_ir = hw.createNestedObject("ir"); hw_ir["pin"] = irPin; hw_ir["type"] = irEnabled; // the byte 'irEnabled' does contain the IR-Remote Type ( 0=disabled ) + hw_ir["sel"] = irApplyToAllSelected; JsonObject hw_relay = hw.createNestedObject(F("relay")); hw_relay["pin"] = rlyPin; hw_relay["rev"] = !rlyMde; + hw[F("baud")] = serialBaud; + //JsonObject hw_status = hw.createNestedObject("status"); //hw_status["pin"] = -1; @@ -710,12 +766,12 @@ void serializeConfig() { light_gc["col"] = (strip.gammaCorrectCol) ? 2.8 : 1.0; JsonObject light_tr = light.createNestedObject("tr"); - light_tr[F("mode")] = fadeTransition; + light_tr["mode"] = fadeTransition; light_tr["dur"] = transitionDelayDefault / 100; light_tr["pal"] = strip.paletteFade; JsonObject light_nl = light.createNestedObject("nl"); - light_nl[F("mode")] = nightlightMode; + light_nl["mode"] = nightlightMode; light_nl["dur"] = nightlightDelayMinsDefault; light_nl[F("tbri")] = nightlightTargetBri; light_nl["macro"] = macroNl; @@ -734,8 +790,10 @@ void serializeConfig() { JsonObject if_sync_recv = if_sync.createNestedObject("recv"); if_sync_recv["bri"] = receiveNotificationBrightness; if_sync_recv["col"] = receiveNotificationColor; - if_sync_recv["fx"] = receiveNotificationEffects; + if_sync_recv["fx"] = receiveNotificationEffects; if_sync_recv["grp"] = receiveGroups; + if_sync_recv["seg"] = receiveSegmentOptions; + if_sync_recv["sb"] = receiveSegmentBounds; JsonObject if_sync_send = if_sync.createNestedObject("send"); if_sync_send[F("dir")] = notifyDirect; @@ -759,7 +817,7 @@ void serializeConfig() { if_live_dmx[F("uni")] = e131Universe; if_live_dmx[F("seqskip")] = e131SkipOutOfSequence; if_live_dmx[F("addr")] = DMXAddress; - if_live_dmx[F("mode")] = DMXMode; + if_live_dmx["mode"] = DMXMode; if_live[F("timeout")] = realtimeTimeoutMs / 100; if_live[F("maxbri")] = arlsForceMaxBri; @@ -821,7 +879,7 @@ void serializeConfig() { if_ntp[F("lt")] = latitude; JsonObject ol = doc.createNestedObject("ol"); - ol[F("clock")] = overlayDefault; + ol[F("clock")] = overlayCurrent; ol[F("cntdwn")] = countdownMode; ol["min"] = overlayMin; @@ -848,6 +906,14 @@ void serializeConfig() { timers_ins0["min"] = timerMinutes[i]; timers_ins0["macro"] = timerMacro[i]; timers_ins0[F("dow")] = timerWeekday[i] >> 1; + if (i<8) { + JsonObject start = timers_ins0.createNestedObject("start"); + start["mon"] = (timerMonth[i] >> 4) & 0xF; + start["day"] = timerDay[i]; + JsonObject end = timers_ins0.createNestedObject("end"); + end["mon"] = timerMonth[i] & 0xF; + end["day"] = timerDayEnd[i]; + } } JsonObject ota = doc.createNestedObject("ota"); diff --git a/wled00/colors.cpp b/wled00/colors.cpp index 424c991651..25cce032ef 100644 --- a/wled00/colors.cpp +++ b/wled00/colors.cpp @@ -4,36 +4,10 @@ * Color conversion methods */ -void colorFromUint32(uint32_t in, bool secondary) +void setRandomColor(byte* rgb) { - byte *_col = secondary ? colSec : col; - _col[0] = R(in); - _col[1] = G(in); - _col[2] = B(in); - _col[3] = W(in); -} - -//load a color without affecting the white channel -void colorFromUint24(uint32_t in, bool secondary) -{ - byte *_col = secondary ? colSec : col; - _col[0] = R(in); - _col[1] = G(in); - _col[2] = B(in); -} - -//store color components in uint32_t -uint32_t colorFromRgbw(byte* rgbw) { - return RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]); -} - -//relatively change white brightness, minumum A=5 -void relativeChangeWhite(int8_t amount, byte lowerBoundary) -{ - int16_t new_val = (int16_t) col[3] + amount; - if (new_val > 0xFF) new_val = 0xFF; - else if (new_val < lowerBoundary) new_val = lowerBoundary; - col[3] = new_val; + lastRandomIndex = strip.get_random_wheel_index(lastRandomIndex); + colorHStoRGB(lastRandomIndex*256,255,rgb); } void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb @@ -259,7 +233,7 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb) rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B rgbw[3] = W(rgb); - return colorFromRgbw(rgbw); + return RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]); } //approximates a Kelvin color temperature from an RGB color. @@ -299,4 +273,4 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) { uint16_t k = 8080 + (225-r) *86; return (k > 10091) ? 10091 : k; } -} \ No newline at end of file +} diff --git a/wled00/const.h b/wled00/const.h index 93c5dc672e..0b907e7111 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -39,6 +39,12 @@ #endif #endif +#ifdef ESP8266 +#define WLED_MAX_COLOR_ORDER_MAPPINGS 5 +#else +#define WLED_MAX_COLOR_ORDER_MAPPINGS 10 +#endif + //Usermod IDs #define USERMOD_ID_RESERVED 0 //Unused. Might indicate no usermod present #define USERMOD_ID_UNSPECIFIED 1 //Default value for a general user mod that does not specify a custom ID @@ -65,6 +71,7 @@ #define USERMOD_RGB_ROTARY_ENCODER 22 //Usermod "rgb-rotary-encoder.h" #define USERMOD_ID_QUINLED_AN_PENTA 23 //Usermod "quinled-an-penta.h" #define USERMOD_ID_SSDR 24 //Usermod "usermod_v2_seven_segment_display_reloaded.h" +#define USERMOD_ID_CRONIXIE 25 //Usermod "usermod_cronixie.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot @@ -170,6 +177,7 @@ #define COL_ORDER_RBG 3 #define COL_ORDER_BGR 4 #define COL_ORDER_GBR 5 +#define COL_ORDER_MAX 5 //Button type @@ -221,6 +229,7 @@ #define SEG_DIFFERS_FX 0x08 #define SEG_DIFFERS_BOUNDS 0x10 #define SEG_DIFFERS_GSO 0x20 +#define SEG_DIFFERS_SEL 0x80 //Playlist option byte #define PL_OPTION_SHUFFLE 0x01 @@ -307,7 +316,7 @@ // Size of buffer for API JSON object (increase for more segments) #ifdef ESP8266 - #define JSON_BUFFER_SIZE 9216 + #define JSON_BUFFER_SIZE 10240 #else #define JSON_BUFFER_SIZE 20480 #endif @@ -346,4 +355,6 @@ #define DEFAULT_LED_COUNT 30 #endif +#define INTERFACE_UPDATE_COOLDOWN 2000 //time in ms to wait between websockets, alexa, and MQTT updates + #endif diff --git a/wled00/data/index.css b/wled00/data/index.css index 23c4a75820..0421f4426f 100644 --- a/wled00/data/index.css +++ b/wled00/data/index.css @@ -45,12 +45,10 @@ body { text-align: center; -webkit-touch-callout: none; -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; - scrollbar-width: 6px; - scrollbar-color: var(--c-sb) transparent; + scrollbar-width: 6px; + scrollbar-color: var(--c-sb) transparent; } html, @@ -93,7 +91,7 @@ button { bottom: calc(var(--bh) + 6px); right: 4px; color: var(--c-6); - cursor: pointer; + cursor: pointer; writing-mode: vertical-rl; } @@ -128,11 +126,6 @@ button { width: 100%; } -.segt { - table-layout: fixed; - width: 76%; -} - .segtd { text-align: center; text-transform: uppercase; @@ -167,25 +160,25 @@ button { } .edit-icon { - position: absolute; - right: -26px; - top: 10px; - display: none; + position: absolute; + right: -26px; + top: 10px; + display: none; } .search-icon { - position: absolute; - left: 8px; - top: 10px; - pointer-events: none; + position: absolute; + left: 8px; + top: 10px; + pointer-events: none; } .search-cancel-icon { - position: absolute; - right: 8px; - top: 9px; - cursor: pointer; - display: none; + position: absolute; + right: 8px; + top: 9px; + cursor: pointer; + display: none; } .flr { @@ -286,7 +279,7 @@ button { padding-top: 0; margin-top: 11px; height: calc(100% - 11px); - -webkit-overflow-scrolling: touch; + -webkit-overflow-scrolling: touch; } .smooth { transition: transform calc(var(--f, 1)*.5s) ease-out } @@ -294,6 +287,7 @@ button { .tab-label { margin: 0 0 -5px 0; padding-bottom: 4px; + display: var(--bhd); } .overlay { @@ -334,7 +328,7 @@ Effect Speed */ #fxb0 { margin-bottom: 2px; - filter: drop-shadow(0 0 1px #000); + filter: drop-shadow(0 0 1px #000); } .first { @@ -383,6 +377,10 @@ Effect Speed */ overflow: auto; } +.modal button:hover { + background-color: var(--c-4); +} + #info { z-index: 3; } @@ -392,7 +390,7 @@ Effect Speed */ } #ndlt { - margin: 12px 0; + margin: 12px 0; } .valtd i { @@ -429,7 +427,7 @@ Effect Speed */ } #kn td { - padding-bottom: 12px; + padding-bottom: 12px; } #lv { @@ -468,27 +466,27 @@ img { border-radius: 17px; pointer-events: none; z-index: -1; - --bg: var(--c-f); + --bg: var(--c-f); } #rwrap .sliderdisplay { --bg: #f00; } #gwrap .sliderdisplay { --bg: #0f0; } #bwrap .sliderdisplay { --bg: #00f; } #wbal .sliderdisplay, #kwrap .sliderdisplay { - background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); + background: linear-gradient(90deg, #ff8f1f 0%, #fff 50%, #cbdbff); } .sliderbubble { - width: 36px; - line-height: 24px; - background: var(--c-3); - position: absolute; - transform: translateX(-50%); - border-radius: 12px; - margin-left: 12px; - margin-top: 3px; - padding: 0px; - display: inline; + width: 36px; + line-height: 24px; + background: var(--c-3); + position: absolute; + transform: translateX(-50%); + border-radius: 12px; + margin-left: 12px; + margin-top: 3px; + padding: 0px; + display: inline; } .hidden { @@ -539,29 +537,30 @@ input[type=range]:active + .sliderbubble { display: inline; transform: translateX(-50%); } -#wwrap, #wbal { +/* hide color controls until enabled in updateUI() */ +#pwrap, #wwrap, #wbal, #rgbwrap, #palwrap { display: none; } /* Modified for WLEDSR */ +/* Slider wrapper div */ .sliderwrap { height: 31px; width: 240px; position: relative; } +/* Segment power button + brightness slider wrapper div */ .sbs { margin: 0px -20px 5px -6px; } +/* Segment brightness slider wrapper div */ .sws { - width: 230px; -} - -.sis { - width: 214px !important; + margin-left: -7px; } +/* Dynamically hide brightness slider label */ .hd { display: var(--bhd); } @@ -576,10 +575,6 @@ input[type=range]:active + .sliderbubble { width: 260px; } -#rgbwrap { - display: none; -} - .btn { padding: 8px; margin: 10px; @@ -587,14 +582,22 @@ input[type=range]:active + .sliderbubble { font-size: 19px; background-color: var(--c-3); color: var(--c-f); - cursor: pointer; + cursor: pointer; border: 0px solid white; border-radius: 25px; transition-duration: 0.5s; - -webkit-backface-visibility: hidden; - -webkit-transform:translate3d(0,0,0); + /*-webkit-backface-visibility: hidden; + -webkit-transform:translate3d(0,0,0);*/ } +/* Small round button (color selectors, icon-only round buttons) */ +.xxs { + width: 40px; + height: 40px; + margin: 6px; +} + +/* Segments/presets auxiliary buttons (Add segment, Create preset, ...) */ .btn-s { width: 276px; background-color: var(--c-2); @@ -606,60 +609,80 @@ input[type=range]:active + .sliderbubble { margin: 0px 8px 4px 0; vertical-align: middle; } -.btna-icon { - margin: 0px; -} + +/* Wide button used in presets (Save, playlist test, delete) */ .btn-p { width: 216px; } -.btn-xs { - width: 39px; - margin: 2px 0 0 0; + +/* Delete preset from playlist button */ +.btn-pl-del { + margin: 0 0 0 3px; } + +/* Add preset to playlist "+" button */ .btn-pl-add { - margin-left: 9px; + margin: 3px 0 0 8px; } - +/* Quick color select buttons wrapper div */ #qcs-w { margin-top: 10px; + display: none; } + +/* Quick color select buttons */ .qcs { padding: 14px; margin: 2px; border-radius: 14px; display: inline-block; } + +/* Quick color select Black button (has white border) */ .qcsb { padding: 13px; border: 1px solid var(--c-f); } + +/* Hex color input wrapper div */ #hexw { margin-top: 5px; display: none; } + +/* Transition time input */ #tt { - text-align: center; + text-align: center; } +/* Color slot select buttons (1,2,3) */ .cl { - width: 42px; + width: 38.5px; + height: 38.5px; + margin: 7px; + background-color: #000; + box-shadow: 0 0 0 1.5px #fff; +} +.selected.cl { + box-shadow: 0 0 0 5px #fff; } +/* Playlist preset select */ .sel-pl { - width: 192px; - background-position: 168px 16px; - margin: 8px 7px 0 0; + width: 192px; + background-position: 168px 16px; + margin: 8px 3px 0 0; } +/* Playlist end preset select */ .sel-ple { width: 216px; - background-position: 192px 16px; + background-position: 192px 16px; } select { -webkit-appearance: none; - -moz-appearance: none; appearance: none; background: url("data:image/svg+xml;utf8,") no-repeat; background-size: 12px; @@ -690,7 +713,6 @@ input[type=number], input[type=text] { outline: none; width: 50px; -webkit-appearance: textfield; - -moz-appearance: textfield; appearance: textfield; } @@ -715,7 +737,7 @@ textarea { } ::selection { - background: var(--c-b); + background: var(--c-b); } input[type=text] { @@ -723,18 +745,18 @@ input[type=text] { text-align: center; } -.ptxt { - width: 200px !important; - margin: 26px 0 6px 12px !important; +input[type=text].ptxt { + width: 200px; + margin: 26px 0 6px 12px; } -.stxt { - display: none; - margin-top: 6px !important; +input[type=text].stxt { + display: none; + margin-top: 6px; } -.qltxt { - width: 50px !important; +input[type=text].qltxt { + width: 50px; } input[type=number]:focus, input[type=text]:focus { @@ -763,42 +785,50 @@ input[type=number]::-webkit-outer-spin-button { } .segn { - border-radius: 5px !important; + border-radius: 5px !important; margin: 3px 0 6px 0 !important; } -.segname { +.pname, .plname, .segname { position: absolute; - top: 0px; left: 50%; - padding: 9px 0; transform: translateX(-50%); white-space: nowrap; cursor: pointer; } .segntxt { - max-width: 160px; - overflow: hidden; - text-overflow: clip; + max-width: 160px; + overflow: hidden; + text-overflow: clip; } -.pname { +.segname { + top: 0px; + padding: 9px 0; +} +.pname, .plname { width: 208px; padding: 8px 0; text-align: center; overflow: hidden; text-overflow: clip; } +.pname { + top: 1px; +} +.plname { + top:0; +} .pid { - position: absolute; - top: 0px; - left: 0px; - padding: 11px 0px 0px 11px; - font-size: 16px; - width: 20px; - text-align: center; + position: absolute; + top: 0px; + left: 0px; + padding: 11px 0px 0px 11px; + font-size: 16px; + width: 20px; + text-align: center; color: var(--c-b); } @@ -810,11 +840,7 @@ input[type=number]::-webkit-outer-spin-button { padding: 6px 0 0 0; } -.xxs { - width: 40px; - margin: 6px; -} - +/* Quick preset select buttons */ .psts { background-color: var(--c-3); color: var(--c-f); @@ -823,20 +849,17 @@ input[type=number]::-webkit-outer-spin-button { height: 40px; } +/* Segment apply button (checkmark) */ .cnf { color: var(--c-f); cursor: pointer; background: var(--c-3); border-radius: 5px; + padding: 8.5px 21px 5px; + display: inline; } -.cnf-s { - /* position: absolute; WLEDSR removed as causes segment save button to move out of table */ - bottom: 100px; - right: 23px; - padding: 7px 22px; -} - +/* Segment power button icon */ .pwr { color: var(--c-6); transform: translate(2px, 3px); @@ -847,17 +870,10 @@ input[type=number]::-webkit-outer-spin-button { color: var(--c-f); } -.half { - padding: 7.5px; - bottom: 35px; -} - .del { position: absolute; bottom: 8px; right: 8px; - color: var(--c-f); - cursor: pointer; } .check, .radio { @@ -881,9 +897,9 @@ input[type=number]::-webkit-outer-spin-button { } .fxchkl { - position: absolute; - top: 0px; - left: 8px; + position: absolute; + top: 0px; + left: 8px; } .check input, .radio input { @@ -896,19 +912,22 @@ input[type=number]::-webkit-outer-spin-button { .checkmark, .radiomark { position: absolute; - bottom: 0; left: 0; - height: 25px; - width: 25px; - background-color: var(--c-3); + height: 24px; + width: 24px; + background-color: var(--c-4); border-radius: 10px; + /*border: 1px solid var(--c-2);*/ +} + +.checkmark { + top: 6px; } .radiomark { - height: 24px; - width: 24px; border-radius: 50%; - background-color: transparent; + background-color: transparent; + top: 7px; } .schk { @@ -930,7 +949,7 @@ input[type=number]::-webkit-outer-spin-button { .check:hover input ~ .checkmark { - background-color: var(--c-4); + background-color: var(--c-5); } .check input:checked ~ .checkmark { @@ -948,8 +967,8 @@ input[type=number]::-webkit-outer-spin-button { } .check .checkmark:after { - left: 9px; - top: 5px; + left: 8px; + top: 4px; width: 5px; height: 10px; border: solid var(--c-f); @@ -979,7 +998,7 @@ input[type=number]::-webkit-outer-spin-button { margin-bottom: 5px; } -.seg { +.seg, .pres { position: relative; display: inline-block; padding: 8px; @@ -992,29 +1011,41 @@ input[type=number]::-webkit-outer-spin-button { border-radius: 20px; text-align: left; transition: background-color 0.5s; - filter: brightness(1); + filter: brightness(1); /* required for slider background to render? */ +} + +.selected { + background-color: var(--c-4); +} +/* "selected" CSS class is applied to the segment when it is the main segment. + By default, do not highlight. Can be overridden by skin.css */ +.selected.seg { + background-color: var(--c-2); /* var(--c-4); */ +} +.selected .checkmark, .selected .radiokmark { + background-color: var(--c-4); /* var(--c-6); */ } .list { position: relative; transition: background-color 0.5s; - margin: auto auto 10px; - padding-bottom: 10px; - width: 230px; + margin: auto auto 10px; + padding-bottom: 10px; + width: 230px; } .lstI { - position: sticky; - overflow: hidden; + position: sticky; + overflow: hidden; } .fxbtn { - margin: 20px auto; - padding: 8px 0; + margin: 20px auto; + padding: 8px 0; } .lstI:hover { - background: var(--c-4); + background: var(--c-4); } .lstI:last-child { @@ -1053,26 +1084,26 @@ input[type=number]::-webkit-outer-spin-button { margin: 3px 0; white-space: nowrap; cursor: pointer; - font-size: 19px; + font-size: 19px; } .lstIprev { width: 220px; height: 5px; margin: auto; - position: absolute; - bottom: 0px; - left: 5px; + position: absolute; + bottom: 0px; + left: 5px; } input[type="text"].search { display: block; width: 230px; box-sizing: border-box; - padding: 8px 8px 9px 38px; - margin: 6px auto 0 auto; + padding: 8px 8px 9px 38px; + margin: 6px auto 0 auto; text-align: left; - background-color: var(--c-3); + background-color: var(--c-3); } input[type="text"].search:focus { @@ -1110,9 +1141,13 @@ input[type="text"].search:not(:placeholder-shown) { } .hrz { - width: auto; - height: 2px; - background-color: var(--c-b); + width: auto; + height: 2px; + background-color: var(--c-b); +} + +.no-margin { + margin: 0; } ::-webkit-scrollbar { @@ -1132,8 +1167,8 @@ input[type="text"].search:not(:placeholder-shown) { @media all and (max-width: 335px) { .sliderbubble { - display: none; - } + display: none; + } } @media all and (max-width: 550px) and (min-width: 374px) { @@ -1158,6 +1193,6 @@ input[type="text"].search:not(:placeholder-shown) { @media all and (max-width: 1249px) { #buttonPcm { - display: none; + display: none; } } diff --git a/wled00/data/index.htm b/wled00/data/index.htm index e8f5070d2c..26f45cd64f 100644 --- a/wled00/data/index.htm +++ b/wled00/data/index.htm @@ -44,13 +44,15 @@

-
-
-
- -
-

-
+
+
+
+
+ +
+

+
+
@@ -106,35 +108,29 @@

- - + +
-

- - Color palette -

-
-
-
- -
- - Default - -
-
-
-
- - Loading... - +
+

+ + Color palette +

+
+
+
+ +
+ + Default + +
-
@@ -142,7 +138,7 @@

Effect speed

- +
@@ -260,7 +256,6 @@
For best performance, it is recommended to turn off the streaming source when not in use.
-
diff --git a/wled00/data/index.js b/wled00/data/index.js index 0ec8c856a4..7c7a568823 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -1,16 +1,17 @@ //page js var loc = false, locip; var noNewSegs = false; -var isOn = false, nlA = false, isLv = false, isInfo = false, isCEEditor = false, isNodes = false, syncSend = false, syncTglRecv = true, isRgbw = false; +var isOn = false, nlA = false, isLv = false, isInfo = false, isCEEditor = false, isNodes = false, syncSend = false, syncTglRecv = true; +var hasWhite = false, hasRGB = false, hasCCT = false; var whites = [0,0,0]; -var selColors; +var colors = [[0,0,0],[0,0,0],[0,0,0]]; var expanded = [false]; var powered = [true]; var nlDur = 60, nlTar = 0; var nlMode = false; var selectedFx = -1; //WLEDSR: used by togglePcMode, init to nonexisting effect var sliderControl = ""; //WLEDSR: used by togglePcMode -var csel = 0; +var csel = 0; // selected color slot (0-2) var currentPreset = -1; var lastUpdate = 0; var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0; @@ -41,14 +42,14 @@ var hol = [ var cpick = new iro.ColorPicker("#picker", { width: 260, wheelLightness: false, - wheelAngle: 270, - wheelDirection: "clockwise", - layout: [ - { - component: iro.ui.Wheel, - options: {} - } - ] + wheelAngle: 270, + wheelDirection: "clockwise", + layout: [ + { + component: iro.ui.Wheel, + options: {} + } + ] }); function handleVisibilityChange() { @@ -61,27 +62,48 @@ function sCol(na, col) { d.documentElement.style.setProperty(na, col); } +function isRgbBlack(a, s) { + return (a[s][0] == 0 && a[s][1] == 0 && a[s][2] == 0); +} + +// returns RGB color from a given slot s 0-2 from color array a +function rgbStr(a, s) { + return "rgb(" + a[s][0] + "," + a[s][1] + "," + a[s][2] + ")"; +} + +// brightness approximation for selecting white as text color if background bri < 127, and black if higher +function rgbBri(a, s) { + var R = a[s][0], G = a[s][1], B = a[s][2]; + return 0.2126*R + 0.7152*G + 0.0722*B; +} + +// sets background of color slot selectors +function setCSL(s) { + var cd = d.getElementsByClassName('cl')[s]; + var w = whites[s]; + if (hasRGB && !isRgbBlack(colors, s)) { + cd.style.background = rgbStr(colors, s); + cd.style.color = rgbBri(colors, s) > 127 ? "#000":"#fff"; + if (hasWhite && w > 0) { + cd.style.background = `linear-gradient(180deg, ${rgbStr(colors, s)} 30%, ${rgbStr([[w,w,w]], 0)})`; + } + } else { + if (!hasWhite) w = 0; + cd.style.background = rgbStr([[w,w,w]], 0); + cd.style.color = w > 127 ? "#000":"#fff"; + } +} + function applyCfg() { cTheme(cfg.theme.base === "light"); var bg = cfg.theme.color.bg; if (bg) sCol('--c-1', bg); - var ccfg = cfg.comp.colors; - d.getElementById('hexw').style.display = ccfg.hex ? "block":"none"; - d.getElementById('picker').style.display = ccfg.picker ? "block":"none"; - d.getElementById('vwrap').style.display = ccfg.picker ? "block":"none"; - d.getElementById('kwrap').style.display = ccfg.picker ? "block":"none"; - d.getElementById('rgbwrap').style.display = ccfg.rgb ? "block":"none"; - d.getElementById('qcs-w').style.display = ccfg.quick ? "block":"none"; + if (lastinfo.leds) updateUI(); // update component visibility var l = cfg.comp.labels; - var e = d.querySelectorAll('.tab-label'); - for (var i=0; i 10) hasBackup = true; } catch (e) { - } - var cn = `
`; - if (empty) - cn += `You have no presets yet!`; - else - cn += `Sorry, there was an issue loading your presets!`; - - if (hasBackup) { - cn += `

`; - if (empty) - cn += `However, there is backup preset data of a previous installation available.
- (Saving a preset will hide this and overwrite the backup)`; - else - cn += `Here is a backup of the last known good state:`; - cn += `
- `; - } - cn += `
`; - d.getElementById('pcont').innerHTML = cn; - if (hasBackup) d.getElementById('bck').value = bckstr; + } + var cn = `
`; + if (empty) + cn += `You have no presets yet!`; + else + cn += `Sorry, there was an issue loading your presets!`; + + if (hasBackup) { + cn += `

`; + if (empty) + cn += `However, there is backup preset data of a previous installation available.
+ (Saving a preset will hide this and overwrite the backup)`; + else + cn += `Here is a backup of the last known good state:`; + cn += `
+ `; + } + cn += `
`; + d.getElementById('pcont').innerHTML = cn; + if (hasBackup) d.getElementById('bck').value = bckstr; } function loadPresets(callback = null) @@ -478,9 +498,9 @@ function populatePresets(fromls) if (qll) pQL.push([i, qll]); is.push(i); - cn += `
`; + cn += `
`; if (cfg.comp.pid) cn += `
${i}
`; - cn += `
${isPlaylist(i)?"":""}${pName(i)}
+ cn += `
${isPlaylist(i)?"":""}${pName(i)}

`; @@ -523,7 +543,7 @@ function populateInfo(i) urows += inforow(k,val); } } - } + } var vcn = "Kuuhaku"; if (i.ver.startsWith("0.13.")) vcn = "Toki"; @@ -576,7 +596,7 @@ function populateSegments(s)
- +
@@ -587,8 +607,8 @@ function populateSegments(s) Offset - - + + @@ -599,13 +619,12 @@ function populateSegments(s) Apply - - - + + +
- `; + +
+ + +
`; // WLEDSR Custom Effects if (inst.fx == 187) @@ -696,35 +719,34 @@ function populateEffects(effects) function populatePalettes(palettes) { - palettes.shift(); // remove default - for (let i = 0; i < palettes.length; i++) { - palettes[i] = { - "id": parseInt(i)+1, - "name": palettes[i] - }; - } - palettes.sort(compare); - - palettes.unshift({ - "id": 0, - "name": "Default", - "class": "sticky" - }); + palettes.shift(); //remove default + for (let i = 0; i < palettes.length; i++) { + palettes[i] = { + "id": parseInt(i)+1, + "name": palettes[i] + }; + } + palettes.sort(compare); - var html = ``; - for (let i = 0; i < palettes.length; i++) { - html += generateListItemHtml( - 'palette', - palettes[i].id, - palettes[i].name, - 'setPalette', - `
`, - palettes[i].class, - ); - } + palettes.unshift({ + "id": 0, + "name": "Default", + "class": "sticky" + }); - pallist.innerHTML=html; + var html = ``; + for (let i = 0; i < palettes.length; i++) { + html += generateListItemHtml( + 'palette', + palettes[i].id, + palettes[i].name, + 'setPalette', + `
`, + palettes[i].class, + ); + } + pallist.innerHTML=html; } function redrawPalPrev() @@ -758,36 +780,36 @@ function genPalPrevCss(id) } } - var gradient = []; - for (let j = 0; j < paletteData.length; j++) { - const element = paletteData[j]; - let r; - let g; - let b; - let index = false; - if (Array.isArray(element)) { - index = element[0]/255*100; - r = element[1]; - g = element[2]; - b = element[3]; - } else if (element == 'r') { - r = Math.random() * 255; - g = Math.random() * 255; - b = Math.random() * 255; - } else { - if (selColors) { - let pos = element[1] - 1; - r = selColors[pos][0]; - g = selColors[pos][1]; - b = selColors[pos][2]; - } - } - if (index === false) { - index = j / paletteData.length * 100; - } + var gradient = []; + for (let j = 0; j < paletteData.length; j++) { + const element = paletteData[j]; + let r; + let g; + let b; + let index = false; + if (Array.isArray(element)) { + index = element[0]/255*100; + r = element[1]; + g = element[2]; + b = element[3]; + } else if (element == 'r') { + r = Math.random() * 255; + g = Math.random() * 255; + b = Math.random() * 255; + } else { + if (colors) { + let pos = element[1] - 1; + r = colors[pos][0]; + g = colors[pos][1]; + b = colors[pos][2]; + } + } + if (index === false) { + index = j / paletteData.length * 100; + } - gradient.push(`rgb(${r},${g},${b}) ${index}%`); - } + gradient.push(`rgb(${r},${g},${b}) ${index}%`); + } return `background: linear-gradient(to right,${gradient.join()});`; } @@ -808,40 +830,40 @@ function generateListItemHtml(listName, id, name, clickAction, extraHtml = '', e } function btype(b){ - switch (b) { - case 32: return "ESP32"; - case 82: return "ESP8266"; - } - return "?"; + switch (b) { + case 32: return "ESP32"; + case 82: return "ESP8266"; + } + return "?"; } function bname(o){ - if (o.name=="WLED") return o.ip; - return o.name; + if (o.name=="WLED") return o.ip; + return o.name; } function populateNodes(i,n) { - var cn=""; - var urows=""; - var nnodes = 0; - if (n.nodes) { - n.nodes.sort((a,b) => (a.name).localeCompare(b.name)); - for (var x=0;x${bname(o)}`; - urows += inforow(url,`${btype(o.type)}
${o.vid==0?"N/A":o.vid}`); - nnodes++; - } - } - } - if (i.ndc < 0) cn += `Instance List is disabled.`; - else if (nnodes == 0) cn += `No other instances found.`; - cn += ` - ${urows} - ${inforow("Current instance:",i.name)} -
`; - d.getElementById('kn').innerHTML = cn; + var cn=""; + var urows=""; + var nnodes = 0; + if (n.nodes) { + n.nodes.sort((a,b) => (a.name).localeCompare(b.name)); + for (var x=0;x${bname(o)}`; + urows += inforow(url,`${btype(o.type)}
${o.vid==0?"N/A":o.vid}`); + nnodes++; + } + } + } + if (i.ndc < 0) cn += `Instance List is disabled.`; + else if (nnodes == 0) cn += `No other instances found.`; + cn += ` +${urows} +${inforow("Current instance:",i.name)} +
`; + d.getElementById('kn').innerHTML = cn; } function loadNodes() @@ -926,20 +948,21 @@ function updateLen(s) // updates background color of currently selected preset function updatePA() { - var ps = d.getElementsByClassName("seg"); // reset all preset buttons - for (let i = 0; i < ps.length; i++) { - ps[i].style.backgroundColor = "var(--c-2)"; + var ps = d.getElementsByClassName("pres"); //reset all preset buttons + for (var i of ps) { + i.classList.remove("selected"); } - ps = d.getElementsByClassName("psts"); // reset all quick selectors - for (let i = 0; i < ps.length; i++) { - ps[i].style.backgroundColor = "var(--c-2)"; + ps = d.getElementsByClassName("psts"); //reset all quick selectors + for (var i of ps) { + i.classList.remove("selected"); } if (currentPreset > 0) { var acv = d.getElementById(`p${currentPreset}o`); if (acv && !expanded[currentPreset+100]) - acv.style.background = "var(--c-6)"; // highlight current preset + acv.classList.add("selected"); acv = d.getElementById(`p${currentPreset}qlb`); - if (acv) acv.style.background = "var(--c-6)"; // highlight quick selector + if (acv) + acv.classList.add("selected"); } } @@ -955,9 +978,15 @@ function updateUI() updateTrail(d.getElementById('sliderCustom1')); updateTrail(d.getElementById('sliderCustom2')); updateTrail(d.getElementById('sliderCustom3')); - d.getElementById('wwrap').style.display = (isRgbw) ? "block":"none"; - d.getElementById('wbal').style.display = (lastinfo.leds.cct) ? "block":"none"; - d.getElementById('kwrap').style.display = (lastinfo.leds.cct) ? "none":"block"; + d.getElementById('wwrap').style.display = (hasWhite) ? "block":"none"; + d.getElementById('wbal').style.display = (hasCCT) ? "block":"none"; + var ccfg = cfg.comp.colors; + d.getElementById('hexw').style.display = ccfg.hex ? "block":"none"; + d.getElementById('pwrap').style.display = (hasRGB && ccfg.picker) ? "block":"none"; + d.getElementById('kwrap').style.display = (hasRGB && !hasCCT && ccfg.picker) ? "block":"none"; + d.getElementById('rgbwrap').style.display = (hasRGB && ccfg.rgb) ? "block":"none"; + d.getElementById('qcs-w').style.display = (hasRGB && ccfg.quick) ? "block":"none"; + d.getElementById('palwrap').style.display = hasRGB ? "block":"none"; updatePA(); updatePSliders(); @@ -977,15 +1006,30 @@ function compare(a, b) { } function cmpP(a, b) { if (!a[1].n) return (a[0] > b[0]); - return a[1].n.localeCompare(b[1].n,undefined, {numeric: true}); + //return a[1].n.localeCompare(b[1].n,undefined, {numeric: true}); + // sort playlists first, followed by presets with characters and last presets with special 1st character + const c = a[1].n.charCodeAt(0); + const d = b[1].n.charCodeAt(0); + if ((c>47 && c<58) || (c>64 && c<91) || (c>96 && c<123) || c>255) x = '='; else x = '>'; + if ((d>47 && d<58) || (d>64 && d<91) || (d>96 && d<123) || d>255) y = '='; else y = '>'; + const n = (a[1].playlist ? '<' : x) + a[1].n; + return n.localeCompare((b[1].playlist ? '<' : y) + b[1].n, undefined, {numeric: true}); +} + +//forces a WebSockets reconnect if timeout (error toast), or successful HTTP response to JSON request +function reconnectWS() { + if (ws) ws.close(); + ws = null; + if (lastinfo && lastinfo.ws > -1) setTimeout(makeWS,500); } function makeWS() { if (ws) return; - ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws'); + ws = new WebSocket((window.location.protocol == 'https:'?'wss':'ws')+'://'+(loc?locip:window.location.hostname)+'/ws'); + ws.binaryType = "arraybuffer"; ws.onmessage = function(event) { + if (event.data instanceof ArrayBuffer) return; //liveview packet var json = JSON.parse(event.data); - if (json.leds) return; //liveview packet clearTimeout(jsonTimeout); jsonTimeout = null; clearErrorToast(); @@ -1000,9 +1044,16 @@ function makeWS() { displayRover(info, s); readState(json.state); }; - ws.onclose = function(event) { - d.getElementById('connind').style.backgroundColor = "#831"; - } + ws.onclose = (e)=>{ + //if there is already a new web socket open, do not null ws + if (ws && ws.readyState === WebSocket.OPEN) return; + + d.getElementById('connind').style.backgroundColor = "#831"; + ws = null; + } + ws.onopen = (e)=>{ + reqsLegal = true; + } } function readState(s,command=false) { @@ -1017,27 +1068,45 @@ function readState(s,command=false) { tr = s.transition; d.getElementById('tt').value = tr/10; - var selc=0; var ind=0; populateSegments(s); + var selc=0; + var sellvl=0; // 0: selc is invalid, 1: selc is mainseg, 2: selc is first selected + hasRGB = hasWhite = hasCCT = false; for (let i = 0; i < (s.seg||[]).length; i++) { - if(s.seg[i].sel) {selc = ind; break;} ind++; + if (sellvl == 0 && s.seg[i].id == s.mainseg) { + selc = i; + sellvl = 1; + } + if (s.seg[i].sel) { + if (sellvl < 2) selc = i; // get first selected segment + sellvl = 2; + var lc = lastinfo.leds.seglc[s.seg[i].id]; + hasRGB |= lc & 0x01; + hasWhite |= lc & 0x02; + hasCCT |= lc & 0x04; + } } var i=s.seg[selc]; + if (sellvl == 1) { + var lc = lastinfo.leds.seglc[i.id]; + hasRGB = lc & 0x01; + hasWhite = lc & 0x02; + hasCCT = lc & 0x04; + } if (!i) { showToast('No Segments!', true); updateUI(); return; } - selColors = i.col; - var cd = d.getElementById('csl').children; - for (let e = 2; e >= 0; e--) + colors = i.col; + for (let e = 0; e < 3; e++) { - cd[e].style.backgroundColor = "rgb(" + i.col[e][0] + "," + i.col[e][1] + "," + i.col[e][2] + ")"; - if (isRgbw) whites[e] = parseInt(i.col[e][3]); - selectSlot(csel); + if (i.col[e].length > 3) whites[e] = parseInt(i.col[e][3]); + setCSL(e); } + selectSlot(csel); if (i.cct != null && i.cct>=0) d.getElementById("sliderA").value = i.cct; d.getElementById('sliderSpeed').value = i.sx; @@ -1307,6 +1376,7 @@ function requestJson(command, rinfo = true) { return; } var s = json; + if (reqsLegal && !ws) reconnectWS(); if (!command || rinfo) { //we have info object if (!rinfo) { //entire JSON (on load) @@ -1322,7 +1392,7 @@ function requestJson(command, rinfo = true) { }); },25); - reqsLegal = true; + reqsLegal = true; } var info = json.info; @@ -1338,7 +1408,6 @@ function requestJson(command, rinfo = true) { name = "(L) " + name; } d.title = name; - isRgbw = info.leds.wv; ledCount = info.leds.count; syncTglRecv = info.str; maxSeg = info.leds.maxseg; @@ -1355,7 +1424,7 @@ function requestJson(command, rinfo = true) { displayRover(info, s); } - readState(s,command); + readState(s,command); }) .catch(function (error) { showToast(error, true); @@ -1453,9 +1522,9 @@ function makeSeg() { Apply - - - + + +
${ledCount - ns} LED${ledCount - ns >1 ? "s":""}
@@ -1555,8 +1624,8 @@ function plR(p) { } function makeP(i,pl) { - var content = ""; - if (pl) { + var content = ""; + if (pl) { var rep = plJson[i].repeat ? plJson[i].repeat : 0; content = `
Playlist Entries
@@ -1580,7 +1649,7 @@ function makeP(i,pl) {
`; } - else content = `