From 6e2e94da557a3acb760b0b4e1fdbf15f13195e97 Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Sun, 29 Dec 2024 17:01:07 +0100 Subject: [PATCH 01/19] Update devices.js --- lib/devices.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/devices.js b/lib/devices.js index f0b0cd6a..0bf84130 100644 --- a/lib/devices.js +++ b/lib/devices.js @@ -656,9 +656,12 @@ const devices = [ models: ['WXKG02LM', 'WXKG02LM_rev2'], icon: 'img/86sw2.png', states: [ - states.left_click, states.right_click, states.both_click, - states.left_click_long, states.left_click_double, states.right_click_long, states.right_click_double, - states.both_click_long, states.both_click_double, states.voltage, states.battery +// states.left_click, states.right_click, states.both_click, +// states.left_click_long, states.left_click_double, states.right_click_long, states.right_click_double, +// states.both_click_long, states.both_click_double, states.voltage, states.battery + states.lumi_left_click, states.lumi_right_click, states.lumi_both_click, + states.lumi_left_click_long, states.lumi_right_click_long, states.lumi_left_click_double, states.lumi_right_click_double, + states.lumi_both_click_long, states.lumi_both_click_double, states.voltage, states.battery ], }, { From 9d2260ce15ce1fdc098bdc486d41585bac32cc92 Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Tue, 31 Dec 2024 18:43:41 +0100 Subject: [PATCH 02/19] Bump version to 1.11.0 --- package-lock.json | 8 ++++---- package.json | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d37b2a4..f6e38ee4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "iobroker.zigbee", - "version": "1.10.13", + "version": "1.11.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "iobroker.zigbee", - "version": "1.10.13", + "version": "1.11.0", "license": "MIT", "dependencies": { "@iobroker/adapter-core": "^3.2.2", @@ -16,8 +16,8 @@ "tar": "^7.4.3", "typescript": "^5.6.3", "uri-js": "^4.4.1", - "zigbee-herdsman": "2.1.4", - "zigbee-herdsman-converters": "21.9.2" + "zigbee-herdsman": "3.2.0", + "zigbee-herdsman-converters": "21.11.0" }, "devDependencies": { "@alcalzone/release-script": "^3.8.0", diff --git a/package.json b/package.json index 5ba78191..6ccccd7d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iobroker.zigbee", - "version": "1.10.14", + "version": "1.11.0", "author": { "name": "Kirov Ilya", "email": "kirovilya@gmail.com" @@ -28,8 +28,8 @@ "ajv": "^8.17.1", "uri-js": "^4.4.1", "typescript": "^5.6.3", - "zigbee-herdsman": "2.1.9", - "zigbee-herdsman-converters": "21.9.2" + "zigbee-herdsman": "3.2.0", + "zigbee-herdsman-converters": "21.11.0" }, "description": "Zigbee devices", "devDependencies": { From b72b302dcf28521ceb9c7661492004325564956d Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Thu, 2 Jan 2025 14:05:01 +0100 Subject: [PATCH 03/19] Test fix _release --- lib/statescontroller.js | 94 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 83 insertions(+), 11 deletions(-) diff --git a/lib/statescontroller.js b/lib/statescontroller.js index e16c75db..4c73344c 100644 --- a/lib/statescontroller.js +++ b/lib/statescontroller.js @@ -598,13 +598,12 @@ class StatesController extends EventEmitter { async publishToState(devId, model, payload) { const devStates = await this.getDevStates(`0x${devId}`, model); - let has_debug = false; - if (this.checkDebugDevice(devId)) + + const has_elevated_debug = (this.checkDebugDevice(devId) && !payload.hasOwnProperty('msg_from_zigbee')); + + if (has_elevated_debug) { - if (!payload.hasOwnProperty('msg_from_zigbee')) { - this.warn(`ELEVATED I1: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`); - has_debug = true; - } + this.warn(`ELEVATED I1: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`); } if (!devStates) { if (has_debug) this.error(`ELEVATED IE2: no device states for device ${devId} type '${model}'`) @@ -613,31 +612,49 @@ class StatesController extends EventEmitter { // find states for payload let has_published = false; + let extra_payload = undefined; + if (payload.hasOwnProperty('action') && typeof payload.action == 'string' && payload.action.endsWith('_release') { + extra_payload = {'action': payload.action.replace('_release')}; + } + if (devStates.states !== undefined) { try { const states = statesMapping.commonStates.concat( devStates.states.filter(statedesc => payload.hasOwnProperty(statedesc.prop || statedesc.id)) ); - + + let extra_states = {}; for (const stateInd in states) { const statedesc = states[stateInd]; let value; + let extra_value = undefined; if (statedesc.getter) { value = statedesc.getter(payload); } else { value = payload[statedesc.prop || statedesc.id]; } + if (extra_payload) { + if (statedesc.getter) { + extra_value = statedesc.getter(extra_payload); + } + } // checking value if (value === undefined || value === null) { + if (extra_value != undefined && extra_value != null) { + extra_states[stateID] = {'statedesc': statedesc, 'value':extra_value}; + } continue; } let stateID = statedesc.id; - if (has_debug && statedesc.id !== 'msg_from_zigbee') { + if (has_elevated_debug && statedesc.id !== 'msg_from_zigbee') { this.warn(`ELEVATED I2: value generated '${JSON.stringify(value)}' from device ${devId} for '${statedesc.name}'`); } + this.TriggerStateUpdate(devId, statedesc, value); + +/* const common = { name: statedesc.name, type: statedesc.type, @@ -673,23 +690,78 @@ class StatesController extends EventEmitter { this.updateState(devId, stateID, value, common); } } +*/ + has_published = true; + } + if (!has_published && extra_states != {}) { + foreach (candidateID in extra_states) { + const candidate = extra_states[candidateID]; + if (candidate) { + if (has_elevated_debug) { + this.warn(`ELEVATED I2a: value generated '${JSON.stringify(candidate.value)}' from device ${devId} for candidate '${candidate.statedesc.name}'`); + } + TriggerStateUpdatea(devId, candidate.statedesc, candidate.value); + } + } has_published = true; } } catch (e) { this.debug(`No states in device ${devId} : payload ${JSON.stringify(payload)}`); - if (has_debug) + if (has_elevated_debug) this.error(`ELEVATED IE3: error when enumerating states of ${devId} for payload ${JSON.stringify(payload)}, ${(e ? e.name : 'undefined')} (${(e ? e.message : '')}).`); } - if (!has_published && has_debug) { + if (!has_published && has_elevated_debug) { this.error(`ELEVATED IE4: No value published for device ${devId}`); } } else { - if (has_debug) + if (has_elevated_debug) this.error(`ELEVATED IE5: No states matching the payload ${JSON.stringify(payload)} for device ${devId}`); } } + + async TriggerStateUpdate(devId, statedesc, value) + { + const common = { + name: statedesc.name, + type: statedesc.type, + unit: statedesc.unit, + read: statedesc.read, + write: statedesc.write, + icon: statedesc.icon, + role: statedesc.role, + min: statedesc.min, + max: statedesc.max, + }; + + let stateID = statedesc.id; + + if (typeof value === 'object' && value.hasOwnProperty('stateid')) { + stateID = `${stateID}.${value.stateid}`; + if (value.hasOwnProperty('unit')) { + common.unit = value.unit; + } + common.name = value.name ? value.name : value.stateid; + common.role = value.role ? `value.${value.role}` : 'number'; + value = value.value; + } + + // if needs to return value to back after timeout + if (statedesc.isEvent) { + this.updateStateWithTimeout(devId, statedesc.id, value, common, 300, !value); + } else { + if (statedesc.prepublish) { + this.collectOptions(devId, model, options => + statedesc.prepublish(devId, value, newvalue => + this.updateState(devId, stateID, newvalue, common), options) + ); + } else { + this.updateState(devId, stateID, value, common); + } + } + + } } module.exports = StatesController; From 3b0264eca0a98fcdc5de95e29a4f5af59e6a5a2a Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Thu, 2 Jan 2025 14:20:19 +0100 Subject: [PATCH 04/19] Update statescontroller.js bugfix --- lib/statescontroller.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/statescontroller.js b/lib/statescontroller.js index 4c73344c..145cc19d 100644 --- a/lib/statescontroller.js +++ b/lib/statescontroller.js @@ -613,7 +613,7 @@ class StatesController extends EventEmitter { let has_published = false; let extra_payload = undefined; - if (payload.hasOwnProperty('action') && typeof payload.action == 'string' && payload.action.endsWith('_release') { + if (payload.hasOwnProperty('action') && typeof payload.action == 'string' && payload.action.endsWith('_release')) { extra_payload = {'action': payload.action.replace('_release')}; } @@ -622,7 +622,7 @@ class StatesController extends EventEmitter { const states = statesMapping.commonStates.concat( devStates.states.filter(statedesc => payload.hasOwnProperty(statedesc.prop || statedesc.id)) ); - + let extra_states = {}; for (const stateInd in states) { const statedesc = states[stateInd]; @@ -636,13 +636,13 @@ class StatesController extends EventEmitter { if (extra_payload) { if (statedesc.getter) { extra_value = statedesc.getter(extra_payload); - } + } } // checking value if (value === undefined || value === null) { if (extra_value != undefined && extra_value != null) { extra_states[stateID] = {'statedesc': statedesc, 'value':extra_value}; - } + } continue; } @@ -694,7 +694,7 @@ class StatesController extends EventEmitter { has_published = true; } if (!has_published && extra_states != {}) { - foreach (candidateID in extra_states) { + for (candidateID in extra_states) { const candidate = extra_states[candidateID]; if (candidate) { if (has_elevated_debug) { From 55125d5820472e54d05d143e041fd5173af367da Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Fri, 3 Jan 2025 10:52:51 +0100 Subject: [PATCH 05/19] Test Deactivate map and ping --- lib/zbDeviceAvailability.js | 4 +++- lib/zigbeecontroller.js | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/zbDeviceAvailability.js b/lib/zbDeviceAvailability.js index 70389589..8a3b3e69 100644 --- a/lib/zbDeviceAvailability.js +++ b/lib/zbDeviceAvailability.js @@ -49,7 +49,7 @@ class DeviceAvailability extends BaseExtension { }); this.startDevicePingQueue = []; // simple fifo array for starting device pings this.startDevicePingTimeout = null; // handle for the timeout which empties the queue - this.startDevicePingDelay = 200; // 200 ms delay between starting the ping timeout + this.startDevicePingDelay = 2000; // 200 ms delay between starting the ping timeout this.name = 'DeviceAvailability'; this.elevate_debug = false; } @@ -74,6 +74,8 @@ class DeviceAvailability extends BaseExtension { } isPingable(device) { + return false; + if (this.active_ping) { if (this.forced_ping && forcedPingable.find(d => d && d.hasOwnProperty('zigbeeModel') && d.zigbeeModel.includes(device.modelID))) { return true; diff --git a/lib/zigbeecontroller.js b/lib/zigbeecontroller.js index c5c8271a..fb3d5635 100644 --- a/lib/zigbeecontroller.js +++ b/lib/zigbeecontroller.js @@ -715,6 +715,7 @@ class ZigbeeController extends EventEmitter { } async getMap(callback) { +/* try { const devices = this.herdsman.getDevices(true); const lqis = []; @@ -790,6 +791,8 @@ class ZigbeeController extends EventEmitter { this.sendError(error); this.debug(`Failed to get map: ${safeJsonStringify(error.stack)}`); } + */ + this.error('Map currently not supported'); } async publish(deviceID, cid, cmd, zclData, cfg, ep, type, callback, zclSeqNum) { From ad35f53f4a117558591afb9b7386d6c9ee3b4d03 Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Fri, 3 Jan 2025 10:58:08 +0100 Subject: [PATCH 06/19] Revert "Update statescontroller.js" This reverts commit 3b0264eca0a98fcdc5de95e29a4f5af59e6a5a2a. --- lib/statescontroller.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/statescontroller.js b/lib/statescontroller.js index 145cc19d..4c73344c 100644 --- a/lib/statescontroller.js +++ b/lib/statescontroller.js @@ -613,7 +613,7 @@ class StatesController extends EventEmitter { let has_published = false; let extra_payload = undefined; - if (payload.hasOwnProperty('action') && typeof payload.action == 'string' && payload.action.endsWith('_release')) { + if (payload.hasOwnProperty('action') && typeof payload.action == 'string' && payload.action.endsWith('_release') { extra_payload = {'action': payload.action.replace('_release')}; } @@ -622,7 +622,7 @@ class StatesController extends EventEmitter { const states = statesMapping.commonStates.concat( devStates.states.filter(statedesc => payload.hasOwnProperty(statedesc.prop || statedesc.id)) ); - + let extra_states = {}; for (const stateInd in states) { const statedesc = states[stateInd]; @@ -636,13 +636,13 @@ class StatesController extends EventEmitter { if (extra_payload) { if (statedesc.getter) { extra_value = statedesc.getter(extra_payload); - } + } } // checking value if (value === undefined || value === null) { if (extra_value != undefined && extra_value != null) { extra_states[stateID] = {'statedesc': statedesc, 'value':extra_value}; - } + } continue; } @@ -694,7 +694,7 @@ class StatesController extends EventEmitter { has_published = true; } if (!has_published && extra_states != {}) { - for (candidateID in extra_states) { + foreach (candidateID in extra_states) { const candidate = extra_states[candidateID]; if (candidate) { if (has_elevated_debug) { From 8c4f43139121de649a0b7f565847e5792d225112 Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:10:10 +0100 Subject: [PATCH 07/19] revert and fix --- lib/statescontroller.js | 83 +++-------------------------------------- main.js | 16 +++++--- 2 files changed, 16 insertions(+), 83 deletions(-) diff --git a/lib/statescontroller.js b/lib/statescontroller.js index 4c73344c..0bdc8e30 100644 --- a/lib/statescontroller.js +++ b/lib/statescontroller.js @@ -603,27 +603,21 @@ class StatesController extends EventEmitter { if (has_elevated_debug) { - this.warn(`ELEVATED I1: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`); + this.warn(`ELEVATED I01: message received '${JSON.stringify(payload)}' from device ${devId} type '${model}'`); } if (!devStates) { - if (has_debug) this.error(`ELEVATED IE2: no device states for device ${devId} type '${model}'`) + if (has_debug) this.error(`ELEVATED IE02: no device states for device ${devId} type '${model}'`) return; } // find states for payload let has_published = false; - let extra_payload = undefined; - if (payload.hasOwnProperty('action') && typeof payload.action == 'string' && payload.action.endsWith('_release') { - extra_payload = {'action': payload.action.replace('_release')}; - } - if (devStates.states !== undefined) { try { const states = statesMapping.commonStates.concat( devStates.states.filter(statedesc => payload.hasOwnProperty(statedesc.prop || statedesc.id)) ); - let extra_states = {}; for (const stateInd in states) { const statedesc = states[stateInd]; let value; @@ -633,28 +627,17 @@ class StatesController extends EventEmitter { } else { value = payload[statedesc.prop || statedesc.id]; } - if (extra_payload) { - if (statedesc.getter) { - extra_value = statedesc.getter(extra_payload); - } - } // checking value if (value === undefined || value === null) { - if (extra_value != undefined && extra_value != null) { - extra_states[stateID] = {'statedesc': statedesc, 'value':extra_value}; - } continue; } let stateID = statedesc.id; if (has_elevated_debug && statedesc.id !== 'msg_from_zigbee') { - this.warn(`ELEVATED I2: value generated '${JSON.stringify(value)}' from device ${devId} for '${statedesc.name}'`); + this.warn(`ELEVATED I02: value generated '${JSON.stringify(value)}' from device ${devId} for '${statedesc.name}'`); } - this.TriggerStateUpdate(devId, statedesc, value); - -/* const common = { name: statedesc.name, type: statedesc.type, @@ -690,78 +673,24 @@ class StatesController extends EventEmitter { this.updateState(devId, stateID, value, common); } } -*/ - has_published = true; - } - if (!has_published && extra_states != {}) { - foreach (candidateID in extra_states) { - const candidate = extra_states[candidateID]; - if (candidate) { - if (has_elevated_debug) { - this.warn(`ELEVATED I2a: value generated '${JSON.stringify(candidate.value)}' from device ${devId} for candidate '${candidate.statedesc.name}'`); - } - TriggerStateUpdatea(devId, candidate.statedesc, candidate.value); - } - } has_published = true; } } catch (e) { this.debug(`No states in device ${devId} : payload ${JSON.stringify(payload)}`); if (has_elevated_debug) - this.error(`ELEVATED IE3: error when enumerating states of ${devId} for payload ${JSON.stringify(payload)}, ${(e ? e.name : 'undefined')} (${(e ? e.message : '')}).`); + this.error(`ELEVATED IE03: error when enumerating states of ${devId} for payload ${JSON.stringify(payload)}, ${(e ? e.name : 'undefined')} (${(e ? e.message : '')}).`); } if (!has_published && has_elevated_debug) { - this.error(`ELEVATED IE4: No value published for device ${devId}`); + this.error(`ELEVATED IE04: No value published for device ${devId}`); } } else { if (has_elevated_debug) - this.error(`ELEVATED IE5: No states matching the payload ${JSON.stringify(payload)} for device ${devId}`); + this.error(`ELEVATED IE05: No states matching the payload ${JSON.stringify(payload)} for device ${devId}`); } } - async TriggerStateUpdate(devId, statedesc, value) - { - const common = { - name: statedesc.name, - type: statedesc.type, - unit: statedesc.unit, - read: statedesc.read, - write: statedesc.write, - icon: statedesc.icon, - role: statedesc.role, - min: statedesc.min, - max: statedesc.max, - }; - - let stateID = statedesc.id; - - if (typeof value === 'object' && value.hasOwnProperty('stateid')) { - stateID = `${stateID}.${value.stateid}`; - if (value.hasOwnProperty('unit')) { - common.unit = value.unit; - } - common.name = value.name ? value.name : value.stateid; - common.role = value.role ? `value.${value.role}` : 'number'; - value = value.value; - } - - // if needs to return value to back after timeout - if (statedesc.isEvent) { - this.updateStateWithTimeout(devId, statedesc.id, value, common, 300, !value); - } else { - if (statedesc.prepublish) { - this.collectOptions(devId, model, options => - statedesc.prepublish(devId, value, newvalue => - this.updateState(devId, stateID, newvalue, common), options) - ); - } else { - this.updateState(devId, stateID, value, common); - } - } - - } } module.exports = StatesController; diff --git a/main.js b/main.js index b95d9b35..3ad09659 100644 --- a/main.js +++ b/main.js @@ -477,7 +477,7 @@ class Zigbee extends utils.Adapter { shortMessage.device = device.ieeeAddr; shortMessage.meta = undefined; shortMessage.endpoint = (message.endpoint.ID ? message.endpoint.ID: -1); - this.log.warn(`ELEVATED I0: Zigbee Event of Type ${type} from device ${safeJsonStringify(device.ieeeAddr)}, incoming event: ${safeJsonStringify(shortMessage)}`); + this.log.warn(`ELEVATED I00: Zigbee Event of Type ${type} from device ${safeJsonStringify(device.ieeeAddr)}, incoming event: ${safeJsonStringify(shortMessage)}`); } // this assigment give possibility to use iobroker logger in code of the converters, via meta.logger meta.logger = this.log; @@ -561,7 +561,7 @@ class Zigbee extends utils.Adapter { if (type !== 'readResponse') { this.log.debug(`No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`); if (has_elevated_debug) - this.log.warn(`ELEVATED IE0: No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`); + this.log.warn(`ELEVATED IE00: No converter available for '${mappedModel.model}' '${devId}' with cluster '${cluster}' and type '${type}'`); } return; } @@ -643,7 +643,7 @@ class Zigbee extends utils.Adapter { if (!mappedModel) { this.log.debug(`No mapped model for ${model}`); - if (has_elevated_debug) this.log.warn(`ELEVATED O2: No mapped model for ${model}`) + if (has_elevated_debug) this.log.warn(`ELEVATED O02: No mapped model for ${model}`) return; } @@ -715,6 +715,7 @@ class Zigbee extends utils.Adapter { } let converter = undefined; + let msg_counter = 0; for (const c of mappedModel.toZigbee) { if (!c.hasOwnProperty('convertSet')) continue; @@ -725,21 +726,24 @@ class Zigbee extends utils.Adapter { { converter = c; if (has_elevated_debug) - this.log.warn(`ELEVATED O3A: Setting converter to keyless converter for ${deviceId} of type ${model}`) + this.log.warn(`ELEVATED O3.${msg_counter}: Setting converter to keyless converter for ${deviceId} of type ${model}`) this.log.debug('setting converter to keyless converter') + msg_counter++; } else { - if (has_elevated_debug) this.log.warn(`ELEVATED O3B: ignoring keyless converter for ${deviceId} of type ${model}`) + if (has_elevated_debug) this.log.warn(`ELEVATED O3.${msg_counter}: ignoring keyless converter for ${deviceId} of type ${model}`) this.log.debug('ignoring keyless converter') + msg_counter++; } continue; } if (c.key.includes(stateDesc.prop) || c.key.includes(stateDesc.setattr) || c.key.includes(stateDesc.id)) { this.log.debug(`${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`) - if (has_elevated_debug) this.log.warn(`ELEVATED O3C: ${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`) + if (has_elevated_debug) this.log.warn(`ELEVATED O3.${msg_counter}: ${(converter===undefined?'Setting':'Overriding')}' converter to converter with key(s)'${JSON.stringify(c.key)}}`) converter = c; + msg_counter++; } } if (converter === undefined) { From 13fde33de6ef4a5a91cbf897030707154089ee3d Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Sat, 4 Jan 2025 16:43:19 +0100 Subject: [PATCH 08/19] Fix Pairing --- lib/exclude.js | 26 ++++++++++++++++++++++++++ lib/statescontroller.js | 2 +- lib/zigbeecontroller.js | 29 +++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/lib/exclude.js b/lib/exclude.js index c2714f1d..cc655bd1 100644 --- a/lib/exclude.js +++ b/lib/exclude.js @@ -117,8 +117,34 @@ class Exclude { } } +/* + async moveExcludeStorage() + { + try { + const states = await this.adapter.getStatesOf('exclude') + for (const state of states) { + this.adapter.setObjectNotExists( "info.exclude.".concat(state.id), + { + type: 'state', + common: {name: exclude_mod}, + }, + () => this.adapter.setState(stateId, exclude_mod, true, () => + callback()), + ); + + } + + } + catch (error) { + this.error(`Failed to getExclude ${error.stack}`) + + } + } +*/ getExclude(callback) { try { + + const exclude = []; this.adapter.getStatesOf('exclude', (err, states) => { if (!err && states) { diff --git a/lib/statescontroller.js b/lib/statescontroller.js index 0bdc8e30..9e5bde34 100644 --- a/lib/statescontroller.js +++ b/lib/statescontroller.js @@ -334,7 +334,7 @@ class StatesController extends EventEmitter { this.info(`keeping disconnected state ${JSON.stringify(statename)} of ${devId} `); } else { this.info(`deleting disconnected state ${JSON.stringify(statename)} of ${devId} `); - this.adapter.deleteState(devId, null, state._id); + this.deleteObj(devId.concat('.',statename)); } } else { this.debug(`keeping connecte state ${JSON.stringify(statename)} of ${devId} `); diff --git a/lib/zigbeecontroller.js b/lib/zigbeecontroller.js index fb3d5635..d856a419 100644 --- a/lib/zigbeecontroller.js +++ b/lib/zigbeecontroller.js @@ -129,6 +129,7 @@ class ZigbeeController extends EventEmitter { this.herdsman.on('deviceJoined', this.handleDeviceJoined.bind(this)); this.herdsman.on('deviceLeave', this.handleDeviceLeave.bind(this)); this.herdsman.on('message', this.handleMessage.bind(this)); + this.herdsman.on('permitJoinChanged', this.handlePermitJoinChanged.bind(this)); await this.herdsman.start(); @@ -503,6 +504,13 @@ class ZigbeeController extends EventEmitter { // Permit join async permitJoin(permitTime, devid, failure) { + try { + await this.herdsman.permitJoin(permitTime); + } catch (e) { + this.sendError(e); + this.error(`Failed to open the network: ${e.stack}`); + } + /* let permitDev; if (isFunction(devid) && !isFunction(failure)) { failure = devid; @@ -524,13 +532,18 @@ class ZigbeeController extends EventEmitter { if (permitTime && !this.herdsman.getPermitJoin()) { clearInterval(this._permitJoinInterval); this._permitJoinTime = permitTime; - await this.herdsman.permitJoin(true, permitDev, this._permitJoinTime); + await this.herdsman.adapter.permitJoin(this._permitJoinTime); + await this.herdsman.greenPower.permitJoin(this._permitJoinTime); + + //await this.herdsman.permitJoin(true, permitDev, this._permitJoinTime); this._permitJoinInterval = setInterval(async () => { this.emit('pairing', 'Pairing time left', this._permitJoinTime); if (this._permitJoinTime === 0) { this.info('Zigbee: stop joining'); clearInterval(this._permitJoinInterval); - await this.herdsman.permitJoin(false); + //await this.herdsman.permitJoin(false); + await this.herdsman.adapter.permitJoin(0); + await this.herdsman.greenPower.permitJoin(0); } this._permitJoinTime -= 1; }, 1000); @@ -546,6 +559,18 @@ class ZigbeeController extends EventEmitter { this.sendError(e); this.error(`Failed to open the network: ${e.stack}`); } + */ + } + + async handlePermitJoinChanged(data) + { + try { + this.warn(`Error in PermitJoinChanged: ${JSON.Stringify(error.message)}`); + } + catch (error) { + this.error(`Error in PermitJoinChanged: ${error.message}`); + } + } // Remove device From 8bb5a2edc0c7c0c9b7b33693a209bce8c7e2ce76 Mon Sep 17 00:00:00 2001 From: asgothian <45667167+asgothian@users.noreply.github.com> Date: Tue, 7 Jan 2025 11:36:17 +0100 Subject: [PATCH 09/19] 1.11.1 * (asgothian) Fix Pairing * (asgothian) change ping * (asgothian) delay map generation until refresh is activated * (asgothian) remove bindings tab from zigbee tab * (asgothian) reorder tabs in configuration * (asgothian) remove binding tab from configuration * (asgothian) remove map from configuration * (asgothian) add debug to zigbee tab (work in progress) --- README.md | 11 ++++++ admin/admin.js | 2 +- admin/index_m.html | 10 ++--- admin/tab_m.html | 5 ++- lib/utils.js | 2 +- lib/zbDeviceAvailability.js | 11 ++++-- lib/zigbeecontroller.js | 77 +++++++++++-------------------------- package-lock.json | 4 +- package.json | 2 +- 9 files changed, 52 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index f981fdbe..0fde76ae 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,17 @@ You can thank the authors by these links: ----------------------------------------------------------------------------------------------------- ## Changelog +### 1.11.1 (2025-01-02) +* (asgothian) Fix Pairing +* (asgothian) change ping +* (asgothian) delay map generation until refresh is activated +* (asgothian) remove bindings tab from zigbee tab +* (asgothian) reorder tabs in configuration +* (asgothian) remove binding tab from configuration +* (asgothian) remove map from configuration +* (asgothian) add debug to zigbee tab (work in progress) +* (asgothian) Herdsman 3.2.0, Converters 21.11.0 + ### 1.10.14 (2025-01-01) * (arteck) Herdsman 2.1.9, Converters 20.58.0 * (asgothian) Fix: Aqara T1M (CL-L02D) diff --git a/admin/admin.js b/admin/admin.js index 0ff0c4bd..a3b7698e 100644 --- a/admin/admin.js +++ b/admin/admin.js @@ -848,7 +848,7 @@ function load(settings, onChange) { //dialog = new MatDialog({EndingTop: '50%'}); getDevices(); - getMap(); + //getMap(); //addCard(); // Signal to admin, that no changes yet diff --git a/admin/index_m.html b/admin/index_m.html index 82fa0c52..7492c9ac 100644 --- a/admin/index_m.html +++ b/admin/index_m.html @@ -690,13 +690,11 @@
9psTEZV)kx*yyH>a@Pw#Dv4UW0mA_v++$9z z?bYj|@dt6)n^N?aq(8B-Ans~K`D@1(85!o%x47B`ux3<7xd+*}k)f@-XcdLEyphL= zV;Bk{_2;*eZ`K6Up6lsY>N@AQ3J|G+cY@}R;x{}VVAo^y5EMspTibs^XEDs&C<5T)x zWR%NzmQLy$8wQ)q_ZSf5Fn-A=a9{z+u1?=iqm>NJO{q Dy_O>E5I@NpJdNvgXaXZ7qXUP!hSX#`Pd9(+K^(^Jp^MawQa#Hf^hZ=u`~ zK^#$1@b|!=|4c;p#juwB9;aT8tlPm=T*+7h`QimUA_e`RcJA$1C$ZN%l%HCk&L;V3 zwWgTVH$PUhXQDVgQzf%r_k)#EXX`ms7p)aBtB_Wi(C((u2PfHl^RQ-ueK=`;ZOFeM zm#)l0>o&ddTxRXJk8vTy-272|+MduQr9#9pYkIloOVEH=h8^lY^^?ltQ@TmOugIrU z!{A+V;Et~MJ?%|ztc`fS@kR)~u8tMG{KHK^K!RF~Js=liUaz~@tM<|pxZ|+eW=;KZ zJh7_4CE1s$= AwL`j-DPMT<*#2sNxBTT@ z3^i<%I=zG{voX&@lY8+IPN&&?+ih=@J=gl{#b?g|EG*gU0zVLaSWYU*Gl$RE#G}}G zp13fMQSh|?m^2#fuN_yO CmgZIn8Yo2Wzt6WuWIO5b;04E zLs4Hz@1v`pU~aHoR?9xSnlX`1iJm_``@Ugpf8ufqZ^Rag@j4mUcj!AvYBg@HW@Jq$ z<2kamc0jM+3TiJXq_-q1>>o#n%!kh|jymi6HW}3vEjH+&sBvgcg~flN`m*1ZK;WtY zk3z9|- RCCkLRiNT~@6v_Wg)A1Ma!^$pj^}fC6jVwDOv)b3 zFGnP2-aZ8nN;&Z$RmR4+t@zju)~5Q;IIuVRiihrI&d2vWEqDy>PqO-a9=exA?2%F{ zMnrsn_}=)vfLF32nd1gC6e_Dz^u>||6F1gYE^lns$!eR7!iLoh40SQ|=>@swSYKYx zZB&V2l+k_h8vU5umwW7-WY_#+?CtxP-ad|r6I+ule_V^~n8O_e?QO@+jH%KgaV1(x zZ2rv$i``$j6H+^+I3hrHB*Pf}5g1yUiJTXMtmQ2sYG|B~4xi>9v+^vRIQWVAYwEvy zm9M3dGHq%=r&{ueQ@o7-RrZGGi_l>;Yj7JzHfSwLfzcQuOC~|7FR&Q zSlO}xxF5rRiDf(H_8&F!H?;HBetDO`7{*+gr6@4K=_g*epb`Jnz|32dA>d!YRvw?O z+wFjO5TE9LBSrkOC#D EtXhS?)wM8=fv)h4RObihg7(d@N~>j~ zt9_Wwe#IY7E*wAq8}a5Q)Sc4W?AA50x+^$?wWwv4+fomLG1kc%%Is!K50+LkAQVVx zQkl gz;5!AXnw_w({IH6DYmfF z7Xo2rK_gduD`f;rXkA(f4-e 6_@>$IfZdy3%RhAl~3@PzH7GW~mS zeHZW5d)8U&T (V)^I!k{o0DE%iM46>{*-yqsTefo=|ii1t5FCwBM>LXegYLz z8cfB`Y7N#PuFn7w&f$R-)Jd W$=)F}8F*I}@ znRN&Cw-r}^ Eoxxg39wm4EWG26@g0x=cfDBrcs^6Asn3`uHd?oPGfga`>Z>E8f zK3~7sE^!zSearM;5yY#iCl{PQFhyL{Z>p2Xa}43ws?E;;;fw>?3iJ+KaFG`81ysb- z2s(HWVv9vHS #>5-8+h^`XJa?2l}_Y>5ptr2If+X!t1F*e zKUkee9h lACD^VM-mQc&(5g2*5w-TsYI(BhXb3rpMU>;7 yr9AnRZ7L46(? TWAKiPYbvc9ZCBQuw gXvB7^+(pyUr(SM-5L)cq-Ulv#Z`1Lhj#;rqk&lp@7mWc z9&XRdm_b?(sh0FVGcyMDvs>J s#eR>)ffzWxeyR zS?$F R|CSYP|D(jss8EYRU7#O;C|w<*%NLS4!taXY)5? zoAg5Qz+lmSYo?(^!8<_hHgJX4qiO*fyg$=MUr|Y+@{$eL_jxE!osIEv`jE-;>|Rrg zd=&JH^BqrH`6dKRjvF<-;%@lTvh`}DE7~#BK>17f$<+$F9qhI3lcOcW){}iQ{cv|U zupllB{sGFx;=<3tMv02S9IiC e29bXhZI`-glhuwG*2?LgN0; z_d3LAN?}fslH3CS@M)6I8|n7!I~ Xd)CWy^8;Kol~lmTWk3d7%)6zX#SkrjS%YMwU6eNZpn%gf?F2 z-f4AdcEpORu`S(8_`cj(-EpmG84W5nTbC;~n^|su0yMbgU24+Dbva0WDVjlXLFdv> zWWuU~w`N+@)ZWI$aXV)R$|5y|FY&l`VRk=|9!_Sqdk5b~TdtRB`J5G@G<4np!mhQq zIc5c;I>3Ra>{tR spG5o#^verfqa8fufPKOU!rfRP=;>`9{UWIvue;={7Xj%K z9J;{(%k7a8DTF%PbP1O?Cy|(ceZ0SV(wI{f{}Yl|uYXqSjuM-ZYoM)GGT;rIN0&^U z;A1+6vk`6Bs;e3R7yhgo+O>tCMqxbimY9}dhAe&(ka8`8zkAL;`dsd6L))d>#UK`? z&Rm3+`|N Bo<4Dv=x5u71X@o?Av0xvKZgOBR((Om_KYpW|5=I#J^05>jJTPD1 z%js;EY1Uj{&saVFFt&xCq}Myp`^F>o9-?+Nc?9?HN+N6vd-KKTAzI`3VPeu>0E+Ey zq&RP%Mw5Rmg;qx8CuKGoRfrh%-I3rnZ%`Qcv63AqRPE11TD`Y#`^6jZ#XZ=3+C9 b$0a^#vy6`kx==eX+#n8YB)Pd`%d6AImR?dvt|1@i->!1 zS}ob{@MTum_A70MOSwh*FOB5nv92^dv4_?^DKLBGE_F%l QZCq``tW+ `Wb` lppt6INE(D;W9}!xEHVsl)8DN@oNL@Y(C>hsrN8Piu z$7pkJahyej2q=X70}E*s<>0uCradAj4Mq(^K_uhJ^C(hCb(C%s?Zdh5or--Wn#0zw zMh74>d**76 YJ*&) zB-)_MfH)$Ihc5;8@38tu2RrLSJ}0pEz2^|O?Deq+`vnhbyFqJfyzk$x7`jVMl%x{n zb0g@7xvd9|^AVG?vubkZd0j=iRh)HcPq%D-+Jz@w(!#>hF1h8W1! QqtR8P-1O*Ct*qG6{V+J3de OE2j*byX94B9VWp+L9CD` z<)iMiPw>iC#WpW`2_Ty79^hwtOX5}wqa%w@%5rhHu$XYIn7CSo0BWx+d3td>ZwHR~ zl&QF~1ZWO=Uw;WVulm9~LMd$?TUoE0cd3AKF=hxGwO
WL+ aMQjGIt3Fx@aWMW}w zZxC`<0``^h8p!1jskbC?x^J0Dg|-XEcz2}=bX{+om8qXVxHHa7=;ol@jMl%I*W2z% zVW!>vAIO2*cXnu9s0$Zo&DoVzS-ZR8mH!8__rK!y=I6my-Q7F>|04LpF~_G6pSS2; zklSYlaPWGNwpEaeQ;@3?D!`R-Fv-GXZ%V=B7~2dEQ-UifA><@rFeMml{iICb{{{H? bxp=xg{_g=fdBAc;0F$n^fmXSOW7K~D K4f1qsm**Xr6l->XQHkY00-9 z3w!rAapt;iG~vG6D-Bl^G~Uvdn^~IEnug2Mwz=Z~bO#GW1Y?p6%ovX&E2OtlVopdk zPh=&GmZg6G#hNjdl`(oVg-NknhNoNk72~H|oC7pTu!Os-wzj+LzV2(S1FF=jtBZQ? zSihyqEb&Xn*cXi4jNGHx9#%5Jx89?OkE8DOhX7iD1RWR$ e|rUjUU3;{oi#X? zE7!0%5hB!U#DPmVeviJ+%KjzZzegZGzD9#ZPly( @!n1Z=Z;c$rSgb>u z=5=|~T_I-U`z}?>e{vACSFKDZj}mP72_W@$9~P`b*5$OgNcRH!_3{@9^yM@r#Pq*M8_8R$p6aW?$zxq z@`y7);z%TC6_CP0Z8#VRFhPbQ(A8>YM(o|{{f!$C$mLce2O;J7!DJgYo*Z8Elv+*c zo}olteEd*83cDAjb>)_Dc9F8RTQS>0;3PaX&H~r#o}-3u( 1mEpD5yh$q(o}t3AT1A)hI}OtCO{=1J%HB9 z5sJVbQ<~hPUR=yXEdFsRmsU7oAQ`!Cs}MoRL1uCiEj7}@arB;BS)Ag)>j=!)OS!@~ zAor|N8DCLXg~yCF7;)I*M>%z9k^zZ}vf$7i*XD3664U~3g2X1+L*$^6tGP5c*8J~1 z{xoe5uXjmtMr;gAlDP`E7Sr}S5eG{`Zd$eSA2P4qb`NI)SKkoik)1DWhN 4W;|IBJRk@=Zu)Oszyx^howW z7^G+ClF_Bv(C&kS8MwEy6p$&N-YuTpEe>&o*pBbIRyAFNi3MmF6dp~zr(fXV5p=(J zJX)(q*3T8sBpGjMqQfdf2MZt0OqJbl;K&fZd|t!D(~h?aGWZS$*%Fe~g8#u6hQtv8 zwI3SHD(YIa)##AYyLBbjDzw5QtEhHHO|fbs;$+45D=tMf>_%qo;YvS3^qB^o3>}z^ zWR9CVA(ysy$K`fzZlUY<1%Es*C`S!{*Sb#6x;Bk2cI=QC1|a~n)HbUuMuagTcHGtc zGM3zs1Q7qLoJ3t==im91S Z60w5B){DcKKA9+Cm4%DS z;P}v(6#e!O!L?lWn!_ysQ~o*+0k5Cd%8X*Z852ADA93yKfwl^>C%~xTwTbM=VDQ z?Z15Jd}DScoJnM9X_*H2eMRivZ<@fau9=402-J2wp^9uUb^B6W>FzlHUeqyej~yNkgV_Y?fpgR=%-rguIsMk0t!MOh2pP_>(PM7VRjPv(5^zP3 zM&K)?rC<4dNy(`*64G)1iCy;pf>JO#v>kDnKW>cy_?03K{hvqV8OP-BkTZ~5k8&FL zTIG-jB&NLwG|SK4+$j}2yWOn1ocuZ3JE$k@*8`|uALJUqk_rmMA*-D?=u7(k@aSlc zc-~iP_%LDdST}EqtfFz+Gsnvn!=-j_+O};|KR=?#$Vd}w$Swm>8W3t~`-opxu`+pa ze+HY=pzX}KE`1n@)xifiy(2)E$f=71{TG^!KM2}?5!4ph4&4=YnjF=!M)(OS#8;r> z)XmTp;xxG#o7zdf<(f-~TG=^_)c2Bd?T`) wKj*Dlf8=k|7wC@Qz$|Yzc3N&$cIb@5tX+?ET?|P z2cAyUDoEmRzB8Z)-f}(2O#81*A6gvsi9Xyz6c=P>X7%vR2z(IO-~OUYt8IoySjbi& zy7z_Moi=8k*tvSEWrfYB>ei-xu-*!gl%J>j#CYZ{>T>G~Aq_Ig$?)O|lsJvlu2?S| z^ K9Zo+n8@j~8mCHH!# zz (j1gxAn@}_Vxqf)|X)F(?LbJO%LCXq33)3 zk@v9a?uHqaJ-WHsZgqN~8v$aq#q#Vwj`eRFqXOVl=5tFcednr&t9@mQ;TssksT2#& z_$f9GYqy}Adzy7Yr)9hdfPt0OqrfCuGL2b&5>%rMN*`apGuW=-Y-`)-52ZJA{E5 zkTgXl?;1U&6l#sZ08Y%%(RNlH@v1>QlQ>ELF)|00?(-1ge9?WIeJ3h@7R?W1MW(Kz znhVEYy{kgjvMHz_EI= ;7{E6DZD|-W(7_J3149u+$5`PQZ?$`l*ZQv4mS1|hCn;+s<0zl zfVX1;UPE~C7fY%Z5e9mu|9g{ZYXTGnnuHyS$;`$Of;^-(SVlb6Vm?n}Kzjkb>95~c zt{R@d$E0893rwRscJ_a?Gjx~=(|vxqN~&Ha30dSgP27M`(tZ?ot`a3H3+Z!x#7b;q z>3G=rss-5@*66fLkwgBQG8rb^0EZQWB2cBNvgsI{S*C2Rjsac`5esXJb<3AD_S>=$ ztEtZ5%Fnj^ hA!f~bG272KU2cC!mm z)Ue<7p;F5%$PX!Fwog^qn)YTL9eBqo6S6we7*PIuq-gu*yd2Aq^U!Zj6m~~5tq1>v zsEZF|^(H>q={YdOcvc~l@=zm;C45q&Q66OCY>PiD-WuRu;TtTO_|D#x2LE-Wb)98y zqSVyx`b;!+qc@TUB2hBlVOR2r)91m0{RKzP;%@%p?qVmMsV#eu;7r61$<<}u6kFuL z--!uiB+jh5!aMnYfs104dp1|jysKw7{`63S2a^hfKfUrKzT$IZHe$tHgZyj>X>weI zdJvEDuhD&nT67amG{?A^ws*AC96?TV0|WubmR+qVE@dg57|tS%|Ggk*&+Dgg8qVUq zm{^k&{-N&`ef a*HE{&Dcmx_RyBipB*mrG2{R4b`K>jC5H& zeD+`7WpOyrqB`amw)>oC*yH|VhnL36@tYZ15h94^B~z*4^O~*O$n490o*==|;O)PD z9MLM}bVLa!JKogS_cOpAtTyRh=_a-RS0CtNc!=>&xYLIqg}!z#0}FQelHhvY15ANu zso9_Q(6~8N)nQ2rGF8>m649qbZKQ^tD4S*(o-ej8NzDJ+w3?s~!q3mBf!9WP^tbD= z@1Il7<+ABOW6;sA5N;#738@5zz-QPXQpS=hYYOjwZ#;301%P%?rOzV}v}f&N;aJ8B zJf~=EWp!GG5F*Xc^SuK@Z9 +{MNrIQneOczYv`Jxl36+aNP)*1t z+osu_Kz _*vrx5&%DUE1&F&8Q zi_2Ikxpkr2*Tu7cb+WRzwA-)n1gO`rcn e+WT(7Be4A7Sl?#iG!jo^B?Xl^N%@k z8bu#4Lva3Ey6U&%cDH?KmiK`W;c8yp-D~xBWWv29l3F3HJV0UrKPQo+=x;Rj+IyAO zV(yA(_f4b6I{wImm2)OE7#q?U;$X`{d9BO>bbp8;g)jdMPJgUJ@ED2|R;34g;MOu* zkGGg|!f_yGP7c0L4%=?U#M&O%5>KkCy(mskPpyY|J583F-6;heR-}t2QROnlrryKC z>2urFz_#ESpX*CeyGyU|YO+*|i=^KYyFVxYdgUA4vJ6I^B4tF6{BcrcS^q06=SJc{ z23OzR2?|qw(?ztU7XHz7Gh)&gw195so~Eq*9_SHyOVEaY{ai*(@e9(BtbaVEYsEg) zq5`41%P>l**_y}u{fm`9FXl#jUoD~cIzXmNdPcVon*b>hpr7sw7e=-tPR9@_%4T8*J0 z^Vfp{o`tlb<8t~pve6Y#dUU;Ajb{yWANi7wihEY+FiffgI2q7iNo{<*N_YwG6Bsf> z9>@Y7Uq ~lXPgLKpA zl{MlRn5(6waRR~jlEkelv(>{mGaa)L @L!Nw%l%H=1&c@{R>(vULtHYQ7V(pbno2E!X%6uKOYlLy8j(9c}q4p@0 zUh5_n?^- 8@*ART{91*1$NNGf7ra&Z{z$QstdjdZEw8jOX2+B@Bumgkb^{wR@<#i z? gs1b%yo$76ZEiZM z=W(ddo6BVH8&*TXh5x!KdLVF85~$_7u;OpvM{c89QUpE2sONqGyYt#1_u=WooT`gS z#k!bg>NkC9>~PkKce55Q9j>&ni}lCddEF@5x;cfWd^QuQg1H?{96S2q9rC1WV;br0 zAM-k2jO;~Tm3&vhOxGIMb4_WCo2%6YxvOz~hg`~D9Rs1DX&x)C_DZ14XQ|zvw!t3J zantHOrk6WzXYy6I|2b#-Pi+o^%?G;QohBx?_u(6Y^lt8$vrtn3f ArM4-X^F9`}puQY8(B>TXT%D-pm%#n52PRmNURit4(YtDa&a zqtxG?q=c#m jyC_?nLVW_m >%u(7}jaF*?f9a=BNRy>i=Jl^j0iAP#mBkxR2NwSI@FAofTuGaXNYyz*Z zbq$(aaCvxm9uq%evcXDlSUDBZlCIRn8ks1a#_``;Uq}_dpM6+Ccpv)TA#NGHrQiOq z!A; ?%NF2Yj3tI@NK6%=6F)Z4k>-U*`z!Zi0vWU&oExiku-Wantjgk%fN z#c^DF?<9Jgvr08rf788f-OubZ2pI50Bajf{# ~Q1<+c;s<2I8xt^ms!KT=1}sPCkUK_be?A3g-pF&h-Z)3dF-SUR?% ziWdxxHe-eTbw#c@YmXqCwnBQ_2?TuA7O*e_-=L|gbn=+p;daD+aBx6!Vh8Q)E}XWI zbochxAf;f|?FH{NdOFDIp*p(+R`KA(2oemC4?+erA}!z*kLkkU?RPBy>?b(I&z>E6 zVyTsp%*__B8FJDz^GhXwlGQ3guGXJt_d9EsuLs%EuC)@EuLXq>R|;j%;tbWUc}k>N z%1@H@LCix*iqM%92+|8p(gR8@lp}KXMA*(>J9bI76BV&T&|%Wqb&HD?`O~GHurICP ze;V5-0EZ^w7_qd}v9xrDPn}MUOjl{R#ZJ^P{Wg$Ic|Gszbtbra8}qIzyMPiFMPPl^ zMvS=p$dL0KGx%1h+_cemhmX?8rH }s+qT%nWeq!SK}=qtEy8nP&hfoWd@q}ZQnZnEX4K^mjGW0 z>*2+Q0tAF@JX54D#E^V8_&egnA}r=d0Kpqzh `CgKYMS+64`*YEGv{uQ(y=?x41Jv~B3A&x_Cyf8NMQraCwr=u$=lS_L z@JjECm2HvCGH)1cds`Z(uDlN`o!X6Urnj+ zhs;ZOH}G@4b%d0wIYqMkUjM`ObBs^S 4jCB MVt*^5H|Lu;X1EPgZgircmYr7i^)R|TA z$0~tI_#5hvf2WIgg=HIrT}Wl Au(=@9u%;QjtnICHG)W5%(7qy5D3b|`x=G)`XZXOVjQ)l>qiCBkO)Im^ z7YU1^eDtusMYIwq7UQqXfvRs4CY1fwQ2|^WnqUuT0og&Bcn`J11CG1>vLrZE$H1ub zZk-{mj0#3t&HgH$$#EHt29Ql-MyW&UQ`@|+CGo~0t_H48cR5AfuQ?wb8KXC17qMCs zJAc6ZZ}DXLcjI!|s}qIz?MJJfLG8Q{f~+@L*b<-X>g{g57jQcYiUE?&)0XO>95CgA zGKa@@g X>h)f0cE?x!zdm^Ex2knYt-w!$cRD(%=SuuoK zU?rfTdo(@(4z1_><;Lx}oCH;k)e-Y3=_QR2#uMK|2bG3M`xfY;*>daDo7m>oNv+!W z{2m}bO)dGd!m^qTcs%Kd1(q >d9S^GJv816-A@+@OhfcK^bE)C6p-xzG*k zNvD1lrJPbSM`pRQcBw_VkzjH~{7P})u$N*6ih{J!Q<6~0c}X=*s>cgi>Sj%|Vz1GS z6mZGD`z16AkjF M(C+vi+=8G}`;he& zy35z;#56B!s-vb0pDz9Ir53*%k3IU+PrELeAF@?r1>+Hj^eV$G<6Ad}qqv2+E?OBm zFNu^moSSA&Pr2iiV2JDJMg7GjlY#@a?JVf7QoX`gj$|1NRteWk;b40DUqxny %(HnH5+ a1V`J$mlAo< z4De0)7}W}hn91o6F4LaL ) zSSFQ-UABKOUu3cmIqQEvdps$AAI*tq_C~ftq>sOdjGCo~)r9~`NW*azZL(d@tS}e> zstDI=k(-IzEWT#|nf#uJi}`W>o-#I5Qt29oF$>B$5qDBSI}y*lX-~lEU>fyY;42#d zlLE@kq`+obcpBNdV5c{&Q8%&Q8AYCC1PY1RE3!JfCLZy!**SdZth@~`!cl`i#bh9? zA4*kVi(wp@!1?)z{l$=*_-)rIvXmke=`Q$a3>2q~XN*JgU*v!w9D9CbGX6IY_qYC! z)Lv-dC0`aDBYCOrf*u7bh(9lMv&MbPh?d`%#7u^+SG@G9B8@{hckZM49x-8b*==*p zNXTa`>5)~+WO0FV# Ov4(y9E*C{w*WQtR7ZDslSj)Y{jUefP7QpQ* zVjEWcs1IB2IoNStKQGZS6b%aL#ViON-zPFD1F>P65uh?X1{=m4T8C9hp=ZPU7v%qE z>kGftA`j9S>wyGR@i_r Gn 9^^UhATL$Y73?Fx zeg#nd;f5LrF#w~FL5&xkd F8K-C^)*L*d|0I2g`I2b!J-66G+YP{TZt(d>_gCp@YH=RMnHke4i^ z7GAzS1dbe-B6psG91u;kRS1Zkhn+p=E!Fcei``sCbgz~J6JoTS6S9C83piByr+9s% zB*ghd$uA@@wrq54kN-qdd+d8VtghUL=@=OFG@Wi&wNw+dQ=o2mU#$iaS2i_$@=|+M zGTn7D@yO`DYg^4>N+^Of1~n&rfNwC>^`+F(%-o 2RQ<}NwM<$e|_^2 zFDYD`Uw|L^v1sz%rjSqH@?BJDpr_q91w*Ajx7t31+Q5CoOt}t>0R0PoHUsNh(eCd{ zD#rrQPYh#?fySvqYK5Uer}dt5r^d>pIePi4N-Z4k(O{3=cnv_-a!;hH%s9-z8M6cg z{sQWQz$=ZQY9qApbuwDtGu)M{PU5QN-FG$?RJK;5YkN)3uw w( 9Duezktyhe8d%70XGI@TD_FmYMKCCap(yJ942kkatcaNTw9PwGHT6M?tLuZc9c z4f;yi@j77OdmPbV2#7Y*D#t_noo)o#{K;iADV)Jj{r*A^w2Z3SZMPhLXETdxN;*bD zk<)d2L!2D+3UBN_*rUyKobs}>$uT4b7V()-If+Q5G0Df{WKGQXo?7{z|Gln5VszZ5 zh%`$6{70o%zg<4KRxI8pP^atr&unFYy7Q^@=>fS{fSW8vXn}-nv|d>#%%w|eBNNq; zQ9`={=MNxfK@-$PAA63j_?{>qlJViZl?Cjs#nR+~zG-|p`((xEAj-0cNd|ybk0NXt zXNW?rJlYYZi5#|_6RjXu8Lh>8PEs{X%gS>3c!F4C#`e!mUUU-sSQm2bT#^uCp;p@m z)&3$GJY5)~Z|rehD1J!tKqKM4$`mqeT3#e^R4Vxc$f99qvAOZIe2sx=8LsKCv>8cd zQJgOHs$%vPS+6yJy5}vOW-S`?w_`5ZB&^Hzzb)AAoWB7_j@L@q%z_(9=lqBKbbDV} z1idgA7k_!vr!KqwUaYygiS;KO6}^0HgnS@AI P7Umto6mG}R5tQQuEW=5eEeBhq^+Hg^p}4KyHhG2}ktp@-O8 ztGV=^)b;yKTCX&zmR=Q>eN{X&aiPe4g3tbzh3ebHhUK$(Y|W3|7T*KhHp4<&kuf+? zG1O@s<|6EJ1%HhjS=~y>p8bCINgD49r%}&BD$mup@ZtKc!voks+z0M##j(D0jW6hK zPdNDe`PEK0vEzM0>}Lx$Xf(6Dja*{5l$qxXl}VmfN%K5O^J@0U6weZ)ie>wTwDyVO z*#` |PKYj?^zAt^LZ+t&oGU4dOS%oDIZI#{V^ W7ef}FNjM13y3 z5&iqZyD6!ey{R=;RrU2)WqkI_Z9z=G#xlM!9-$Ycx^7E0MQ(eG*%US+_B+!O_0AW9 zPHjv4?VZZ+Df5TiUa3mfqW_!g6fMkcWo=l|i1=I~E^dP;6Sc1Me(-E^VwfQGQ?F9? z>Y|T*4`*bH69+B4vy6$Jd}M >&pF*r(AI0pk#GckX z831ob1%CIZ;q-XCt;4IL@qHWnUrX1AKWf<9RAY5?(R{cjci0k%O? P#f5 z7IcW2$VBxrh$dbzkc+C6Z|m%JA#RoyN_AmBdVyyDs1hXbe$GUR{ml=||Mp=64J(VX z|Cln0i>G+gH+y>JVZ)#{_HPEoqt^1Y?AP3J7WO-8d<-21! u^-WS?eOC2vd>4DUy~P=(^>?tmp+Omeo`-)KHB2+#r;xY z(CKdM|Af}>jD&wyz|nGFBsp1|Yti0pk^ALh`p&tRi4Hh}Bk0iE#2CHfF+AIB7J5Yl zq6N*3 eOACB@ z5+U^`#fm9D)|<;X#x%b-E=h-TxTuGPr*OVHg?!&~;{&BkQFgp)>hhJ=`kDaGaMZbc zvTe0^)#PwbkmY~ytnIdS_PEpA!OVGsp2MguFeF3 !i|&ia2jOO#u8AyfZ2PHNujg&@^< zh)oEbkwG~5_4d3TzU>FG(78g)E }agallg4Z`|xjZKUYYn}YnJQ}l4kqo_RvUCv?J%PoW(%pJ-8jW6m z7)CNhQHq!!c18O!ddqbXVQHCR$Hd9Ato9p`WQs4xE6s=RoKNY=K&CqZ;fY+9Vi6Pb z`+jF#bTJwL;8oqx_{PkU_&C;!|{ z4iA@cJ}W%^<><-DuX g2L@bHO@9_)9KbF%@UfM3mHG}vL#wE2vtYEH8mY3CB9h-1wDQ3s-1<2KP=4V> zkBw;B)%#0vsgmiw`BO?K%MXOnUQYz<4f@L#8^(%f9sf*V2DimBRfR`IezB(G{E4BT z{;~T~K 0r{gvU)B)nUh?oOu)MohD;Je7KxL!z(Rb$LrZ?AEuG~eN()_I5=6%@_4Ic-R4+X zhcEPPcTG&4Rq<`;@)RSD51JNHV_uZ|lkQ9%zdIhMk^e`Fs=wSoz;_DwJo0UgZ=)gG z-`;&LqH19XQDX*sNPRT1`@6Q2!@$CV@l5P>p_U|Hk~-@nmFV}IUKomO2CZJW+asC1 zizsNJZMmkPu@~z|<=J+;*n_5>V_`W34q1BYGcwYgjYpfQOa@2&GBE+rXhfDoYIp@M z@oUO%Y=Lr31&MPVluZ*g49QyRJr(Wkpk!YZiX0ayWmhf|{|KXzaU?&cV%JYW>1 r3K zfv8WBvKr0Qh`Iu=mn!9EpzIkHWCnurAE6v^ bc-ILIZNE>KVU!y6ka& z3GsZD|2 AJ>8g}W(;SbptdzZr# C*#`8 zvcN{Ko=DFYj6t6W^_r8u24``JXW`};R$rOn29HA|WIlrp__oO_+Lxa1#}fQDYI{+7 z53=9R<<+1H0(iP7p`5 fry<@!NdJ9^=x3`>8E?dK7wP32GTLM% z__IF$kJu9DS0#KvGKhcgJK1-c7~YJh5*xooE_ZCY>@Ze7N9TMrN7uxScU6yRa-&Av z^$9p$PdxS67Oq$;qrC^Gr|SzkKQM3@w?&17c(x!Pym#E{*^Wf8gpy vqxx`+a>nmP>np&!0^wVb;?Vv-vQ1 z+(Gelp7rEhc ;`CWCW`d)t*v?25P7Y xbswm7wYPfWh``&q49R4HET@Fx@>tZ zgi`rygmv)?lNWa7*7EPGb-?5oKQiif3@*6yKC1#ujo$(y!bovJEI@%yk}2j0%G5EP ztNs0s`mm9s`%tN;(RG&yRhI>hOq}swmppHDJZ9+fdeZ6_%;buuWCt)%vVrtH+CrJ7 z;+ar_y`7TR!O)3#yUW@Vt?I;CknF0shO|6g9BO+c93wenH{V!*yr7U3(|nxrkjj)w zZGt}BZfKy1pjV^ylY+lzS)V^>F%X-bnH6+pQxyQi&ng52>2UMzJ)bJF#XTvr$oYuX zd9XcHs8GznEic$mA9{W5iPB9Q{*ki0+5J_N9-$-ZO(gx|%$wv Ui9F%0o$ mU;S3SV=6al4EMiXtXK=WL`Xg&c0BI# zG-&bxUC!EGU2Vj2?Z_U9?DJBl p|D(Aa`K}*2*yuc)4qBq36GK3{pu5|~wS50)7sLk& 0`qs)8Po<3Kda*eLHSUETg_^UR?Hf2_zJDNZ*P)8APIXPrL zvvAvX*j{G+aO;=`(n3v_Q2F*VN-Ejn6=nnJ9=SL^3ET$ZS;6|#Z{(N#Mli7)^hJ~t zrW3lb#8=X(UDvC&bWRCHbQwSY_44AkN6sg$8If0;p1oWO#x$pW-{LJHqei-JiXn>8 zMAFq}BqV4-WjyQ8XczmFtn#ng{~83ZZOV+`qd)%;y2k+F8D{o-&=-#;<|tpQJM^P; zXg_B>`yraq?19VKdiE%->?O*U7{EIyk=0MIMK$;(fn9hpHm_iD-xP-8!t- - zP__v#+TFcC8CdBOreC8n)R76JL(|8s_=}!XVV3N?Vdr?4o*NV`73Gn@2?R`af@nj9 z`!8cw0 4<;i=mH{ny>sFO5C<*AlP3X3rJ2 7zREmY@ zz7i)2JYxSGD>r>7KGb$W`XS{k>xq;UK%j5VFPj0KswO}^h{pFRvY);?xwJ+elSB5& zK&&FDMBSP2%^$GI=7tXlte+Stwq*hY)`{$iba?Ou-zt!F$A_5WOZjCekq-x$3iKS^ zE@Vi6Ll*!{DhM9fA{phdfoI>(jINe7tn?8he5f-=__apMO}B=0gC$A(AU~YEpUgnf zAc~|pzIg`9;BUFZ!~2zsyAMky-;fs}&Q{`F-{vRUl4X?sZG;EvSYjV!dpMDF1|#rK zpWpjk(-DkP%#=50URXA1TQ;CkLZa^jR}_nHc=zZa^iPDX$9}d?Ysq~l!)RPU oURB+I-%&cpnXq|tt9Qr#>Qa8&A*IT zxJ9uViexQt==mBuI+&H^HR>Eu1j8J!83VrblG@C}-o( 2W6{p$JpTBMW=<)XhHjbf)=Z z%xHm=Uw$8=It1;@cu4Nfn2uu34=U)zHF`Oq&ZenC%zpkU;#0_XHE4liZg!@;e?;D^ z*`~N6KG>8D9Ycn=KT$hOAab_t_GP*68P|_ij%4kTcW!P((!spSTo5MI+|wp`3$ZA* zmBBP@_q@jPdT74T_JCI&`p>N4comWnE+0Es5n(DmZ**lNWMoOF{Ki~2lvjD&ns*?v zg9(}S>vxw}$4-F}P1P8ONV((;5wcJ7b2c|K*ZQ?tm(C`GSqCX@YPybzsX-MTQTD~h zh;)iFOLXzmN%2oLR$52;6~4qMan^Qw#LUTw1a;DCaW`jiKM zx7-hdKnaPn;j{BC#_$(pDP%b!5^Uh69{}bqLBj-HS!aPFxx~8$R!vG~84Q_j15t8k zAn_K?5X!9GSmd!CDOiCIY2paZRm}P5ie(4l&ykv9&E`|1p=`d!ZkxDTdd<1!em{~e z*G#jTK#b^LUTnyzOMn>Z=tv}6KnPG;IGIy?CnQpj(atO25)WSZzQ VD^ml}!Rgitl|r!e*74e;K~ycskd;_JgLey3ABBM_w*!N_bNyP|tR!WqM5S z(s!i1e3cTJiTFfWZq&J-E^xGVOKUPlyV})s+URxutcy+}o(Yy3z!ge;?iB>resRPN zX9n7Jf)KYmSb4lbNvv6`Tv8f95m~kok_>f*=L`8ap3wcuMDGCxBag2Me*R!HM+iFi z!4vV 1}kyEY6n)9YM;%wbLrI2ohpaAuYqfK*FL{u*VR4> zeXC8Il-r6&5ywtLeGp!1zPmHkdyM2SUyfT3k-%a5J<*7 b9R6abujK H `U1}96LX!N}0FuJ|i zo%`!j<#sGGV%&yNkCkoEJ~Cr|wqbl7Z P1$UpNnITu|+=HN+prUkWlOO7C^irllfr#;a=gmu^Sw5e^G%?^Wu@?TP*)C__(mR zr&zu`5^0d&+;rX@n~L@6Nj0z8JoZNgEh;90xN)F*8F%pk&@0Dpo*kd=-?H42*I*d1 z1Wtk+F(Wt(CEk)e&y(UnZ`vMh`r>f%P82QS<2O9AvQW G+>>R2>39O$O-!W41txaH5VkkGUX!TK%O_Pc)7{P{&eQ zCx2?-o{UxKCecZXXC@RsTckjW&MGkDR=S$aqBTg`xqP|$jU3G)Ou}`Jo}Ll}6%Ttm z!l2f~3Q(f;crN5!Wz^*xgn!iRN}Z=@JAPx_Ka?)sL+pP>5$}hRnmEnA@&yf-5xwj& z=SH^-)S`i46!Ik=GR9!n={Fqub3{)ff1!@w&MrpZv 7wHl8)>7CAJjd%WAR zy0e!*L#c9D27`*?)eHFXsb<+G=X>0Yi+1QZT_wsGyZ=RA)i*xEKhtAOr89pGLvkda zlAjX#m?oQxBEy0XFuq#a9xoL*T0ZoprER(77|9Zj^{Uw-qvXNoU<&VqWpwsXtuvuf z=O2_i_you!?*=&y9%eKB5=VI7SI^<19^vB-33flZ)fSRw`yFSTd`ImDTTHiJq@YTi z1r^H2*J>0rvp|mf+ZDa=v!%Y**fnw!OS4%-RH(4COLj8lK|*~B8>)yTk|QC08e;lF zq!7faLj(2ItjCOh&62nb@X{~j 1@m$T4?-yWtoREBC#;M;Ks7ZV?iLX@{9-pp zP?V|@d$Gq}yB$Obeu^749A~MZl0}esVj6u;V{e}&5PBaS{Q`AV7!@L!us-niCk3~I ziE!~(x3z?~We{=2Lv6>(ou7WAi$=32#iPjDd!ZmmHw4}G1xk^+aA9MRrYjcl8QuJT z^1(;~XT%llJ65{vHV)kRX@??NK-1sxZS=snqW&C3%+58se397LHR+B(G6I2KMnsJo z`P=ubA9<&QpdV;!hXfnkh{Tc3;$euZVMN#Y?rdef8_3x?^5_oSXTIYiY{KtZ*B;2H zP%ggeU650VFX5O0egc2<2QL{TC$E~hXiJwKujr{>=g`k;vP>1qdq3J4L76u0aigYO z{Pwgp4baRFkT^dr FEJI6{p%9;`Qy+5hxxm9!_H^EI}!Azm$D%X;D>}Qw8WnGj>%=W_y z8(3o3;GWX~!DE-XPGf-Z`+Uo?H-!PwzGS<(%Css!(dvkpB3AD`<@DN}+uCyuktnpb z%TYfUA=?TPnc}Q0mL~g-^3RWC@=^Vjgl9i|%I?`yqDFbHumPTAt J`jSrD*q`Nm!kMSM|4eXP}Ipu1co6FtzW@RS+@WwGy>#xhS$=SH2*RqJ)6 z! #`nW9om-^dZPU0rK~vFO__Z>Sr6dAk2D2-R9`uh|e^&K}Ya zGMwCldCDlz;fH?=KcyE;VZ@>-fHGD}D9}<|{~t-`9nRMKzwv}1_9k|W7DZ9iUbS2M zV{fHumr{FgYE!kT-KxE6uNt-Y-b&QoL5$z={asi7PEO8w&hxy-eZSs& !$}RL&K|w{7?!Zj+bA#4$c1)xr?0EcVJx7bh-PJlw&jN1qy=5bs lGg>01-F{YeP+mU4< z@HXU&ruu@ob#gI&REhL>!hcg(WS^i$Q%sdT2opbS$+MUokaD!Bpk&YG3}#D5-|6l% z>I;h7+*q%gaZH{MT=|Q`$Lkl~S2F&m4_fpK?(GjRH-r-A!9mQ&PcVuH`}Hu{MNoj0 zqJ8e4+XLV={Od9&UtB>q_a7;3XdkKs^NMW&6^lwgyrb*WFR3YaOwZ+;H?Rva7s`C0 z_gu-7pp9p&gk|*%$)-up?4X|NqiM_b>hH#b=lEKsW9~wu`avdDEMYmtowLnU!jT+@ z_6#}RpH6GWygIj8m*V8EWpCs$P5T|)@3fxNUHze gYhi>pw<$EnGt3Hza)L|zbl8JtfG!81n=QF!OdgTh`wjXYrTQ?|&E249 zeS<)@4r||q1-=kS#>D)}2aa+e>+yYu5Bf1mATNM<`V#PcB kA86Dd`fGjTYafiu!&^3JLX-k=nnJX3n#0IvDt=^a?Xdl z=`V%t#n6gwZA@&y_Y3ye#SSp6^>em!Ig?ynSZT`>AN7<}7i9t|NTY>-GRvV|N~|F5 zUl9R8Gt?Ib=rQv6avM2kA|OOs+-f+UG1<-*A9^Y*CA 8b=8c+biT3dJ(@`Fc|E z-xDmEjZT^A&WSO?a9r)~6K~?i7g=kbbB7nl8SNKzkDl *}-!gRZ(7`PzZP*D>qrRVUVmmYXk>p&%#$gdI)nO9~q3+wf4$^y&$5 zEt)dPSK@B}+pwD|-g{;y7jK1Uy@^-<`NX`{%zcN;x5Fe8) hTQyNqW^41z^!*V#YA$-X~10I$n^H-DOjNy zfmrqf^uB _PNx z_JAppl u!#6JR^56f-bf`!0lt@hAm2iBqIbNz;{PUmo1vXT{Yi*)ykT?qE0 z{q~UGR+LmPc)#3>1yzZp3@FR^(KiE>GCQe18*tGQgQ`< D%e3d*eSJ)$sy6jO(V9=Had(19S6}IqJTe2pebGn?7w%yk;pr19IoD>UI zS>mPF)V%ZROl^4z?glHG>DVL!EE8$KE8gGD4k*f|XmVeLEIm<@R@F96^e-NA@zZHX znKU{x1=V2!hhDE`$t;aylbMaZ%bl+-UPe;zfISFrns@mqtS3AwEVNp6b@i|$!+H8H z`7 ujTo&PL6xfNn`H!%aS$b3-VMmtxooy$&8yMUhrzVQ{DA`Qq7tZ)3f`Ffq?jpJ4Cb z-lexfQr1Fi#ccZ=^`a&`I}2F6MLj&!Hw^a;J=Q*sh;C&$TeN^bcwIalv;O pb2tjqibE8Xpd zu4&Jf3*vZfMf`UwSZpg_d=ju3@HBe8Z8hN=9K>z7Z+@7Rr2AvR6c6p-lLie)KY5OC z&Gj>rq7$4CW{uR-KHJN8`1zb9zR2b|v%Pxh^qOarrn9Nm`q_>f&(C9BS *Ke>L~meTvKZ)NzbNY%OJj&W6P zjmlYmOEp!mC60|H$gaI5iK6HRY9%G%R|}=4ox8hChbxVNCLaK+HNPR(lr26d7Z;V< zcYDA3I_5m4#|@j>p`FgI(W?vh##uLWFz7OR1!1xN@x7EWOfrgzMM>lpTFDEZ2#!q< zd(Mh(?E!hOZ^@~`e|E%CFWbJ2Gwed6slAi4{fYHUB=VD*FrqAA@*+zSN1S|H@00kY z%eFUJ{ccP3^wYb6xNiLD6R3VHTfTVlB45b($Cu#FOcpa+s%5{Bm@ c@zg z9ka^lCk`Em+LvxNs3oVzAo^jwwQ5r&4$CtOk}vrW8OkWo3y-ys)xfh*z80K)CU{=- zWn$~I_4}OrD+z^2{;$M=KV+SxX`{ycr19iG)9{X8=_0jd8Gk_XsH?!4a~g?HOJ-l) z&gr&Ar|Hlk4_Bl~6yO+3Z7#D9=QqQqsxQutz^SYOVgX`k0(*?Zb%tb+s1SABr_zAx zrqG;<{La~BQUMqAgx$&Ogx^hq_K9>QAUO^FXI!2I );}5%9F4^z=?#eEh9s4QKbhJ 5-&|d~ zn{@Yff8yli)Ued|_qppubQv5A%dLfH817u$C{8BF@b<2*c)^PQv>O}h-&b^ZJZOWA zJw<@_w(8z1y^G5?3FmYlNT8~XCk&F88lO6CCH)hBtzNegj&dk=sP`9-ZRh;0i=$a) z!pThz; $4qIhtjB?L_os)lSgv)CuToWDdL=4+WjJ__Kp~ zM0^gQLLK?gKVl9m#jsn}6XX3k-y&8&Q!BIt>2wNoPfoE>mweDi856wSG^=w3f5~Uq zM%o0fVXMhDp?UIB>@j&(xo{kB^Yo$PIZE2QaTrek2POC0vAy;15AFC{q1Lrl*6}a} zb$MH2GBWn_{A9 Gce_c_<4!KpX+-A9RhA4^U5?{&(N*z$dD%Ts zwPlQ# Ds)QKqSaM!4k*R1z8o%8x%?>% z)WxyjgUE|Nv_{{$t}|!<8a=Ui_mr*dr17h%eDQ40owvL5wlee}oQJ1!s1Tx2Mb{I; z|K_YL(lr%`42nr+^m1SPwfw;w|KAg#WmilT9lO|WtD$9@G%f2jXQ2I1 nXdd2})Dx9nW9>2!gp(%^yNa ze3rc(smU?J9Ww=GIu>+NBBFfE4PT|89p6K$Jn2ARJs)gy<4_d!!^oXEe|5n6Ul}`2<#cm%H?Zmb2BrA~#E^z?aJ1m5Oy+O1Bx3#GdAGA(m#^G@ zr@@4he|eyP8Hu4_p%^xqWY_^nXe75H9@J?QT#C!X^Hhem4>%5Ghd(UsW%Cz0O^nLW z#eVx+LCRcBnolhH`Oc%SeY*Hp|DA3)lZtm!*}F<}ASff?Zog#`$qJ9~qVtF%x{)yB z5*k#;^^pKrGIlk?+jXPHjZA{!0Qm(Z_U?Cp%fCtN-V7cAdEqh!uXal_TMWMJg9XqE z;#wlsR{}T0K{M`-1>NYP?F*B2* u19G_ 2C6sQ`X=@9r ztH#AoScU(5GP*S$w2$(ktL55 gGi_%|(X$;hiI9+xcS7ikE#K z%cCUG7R`*06_QNjBe)jg=D{JVQ`5H}sGX0krl5V3FNa3IWhA!S=ta>iT;x6floEfy zEd-^&j5R&pDawH?R(U9;Ah*&N(Lnkmoaqly`z4H(6zQ;0)7GHIOT7A*3|-Z710BPL zNRyWKwi8sFpSi=z;pxz08Bz5G7^L2xItIS=K7nJ9;IA!}5Q;*gaPF0oz5lSH8h)_eE&8;a7cg z@?j%$H;l4t^MS75%wD-6y<8?ik;7#diHyI_;$3modSb%^pW@CkkK_(jyRWmfc#qmL z7G_roKd#^eXT2NAwLJiQj&!{hir`Q N7gMVWELfRt2iC+Xjg#yw- K!GF_VS*<^8}I1V~N=d_SJmH?>#kze%jMs*cVQA_5ek{#?+Od7YXQ19zUQ zOQRb0hROf%9+Puj6@ e(HHtk*-^#7zCMN3CNp1%*9{UHalHcdxwPq?(`9uXL z3}(SQ>$thQ^=8N3fiafJ>E0Nqf2LCve1BpgHPdy88ebb(_P*487%+{`kO%s=HX(oT zUcMB3boCnd#nXT7yC^A>AN4AoaQ1(g{7J*ZKbB ~Aa8n5sQAXqztinX%iyzna-V%E z*7R7)PaACs=**21iX9;P7K)MdB&g792RT}n<+&M(C||m_@L#X^qjH)o1Jo-vCpfL+=xj?{j5byZoM&sB2ZM>ujvDZApBD9k*}5 z9qi8!=T&_&q39r?FT;#BsoPs|xGvhP5LNMZi_j)9l_An3`b*~-^#b7%G0DRUie8pq zm2Q{}#?4_Py_j8JwAqlp`c<79`}S^I6W4^gDJgzW#$4|z?oTA2eJ+y)9_+Z(vBaw2 zMHdGE2#rlkqq+*@UTI&`_f3C#j $AKdYu$G;xR z_$R!HVmP2~J$=0bZvXqO`|IhgRVcqN)=1V#n=}}GpxKmJEalz7d)Jy_)40Ax zNj)>b `UexF7PqAtvqOm??=IIEw z<9P4%!2-Q*ON0h =(0`5rEBz~WX{;|vPiB9qx^*;RaM-E)eWYp?|t)B>2(VTc~Vb?tA zb>*~)1YhmLmE51m{r?6oy2XpYrc6QBu|OfkRB^09Rfd)abM1@=l5Z;!^?G0@^f(I2 z?W#(iI7fFH5L=D9`;4GTWa2*MZeY8RBeSYuvdW|L?g?mGmRU`o;0+r5pGRjoX4v03 zq!LK=E!ifVKj#^4IKsxL$tioIGoYFuL(%+hUB}m@`3wcRZ3c~itwG1d3E<9up}?ss zKckZ->qbksmahs~vU5(6v+(cTcBc8Y>!-RXu<$|PL3+gh+pS=mLvfn @cwO=)N4rhByF`N#udMzU{XLwEuw^F+S7|LPvkYzHo*3RjV& z{nE7BIr4`Et-~4u9?3H9S)48Z#ybf#HkX^*P4-NLkaY%JzZMP%CH9e64PLD#tg-pc z92|ocWt`7%_Xy5p8jl`hlm62_wvVA&_dkDBccS)N{l$b;7{PHH!xB;Eo;N@4sZh;d zJZ48JM`QO2bI6Euv8y{R{szR}|0$;*tW%a${ zScuh+8IXD#`m56UuG21(o2=*2yo%AC3bP;9dRx71^C!<
HY`thpv` z5kgUHv4D_1xvACB6}hr}-+uG{L6YTZLI#3NMiYP>|7SgPX<^yxvN(E7)h+FEJ)Ino zk#Q!}r_ONj(!nni7x&Csz%b$leJBJB;El_qO`Lxhkl7Rpz4NiH-v4ipm~3zk^hlLK z; pd`W_3sR4IVB|NntMam`pO3fQZ5O6ENJeiv&+p z&o{cu1@@v-d*x@EL+wDL@$JDrj>Oe5bv0-3(X3fyLKP#%%Ztj(_4%Gcf3J&;>-PE< ze)snWLqEivfN&s=21i?7a=Bt&fizy~m`wg9$Vz05PA%N;br?&>D|UewCX0pGPiZcL z{fd fWup-2H$Rg+zV{{x9=5u1Ghk&&Xid+qk|`h0Jq6RCD7sspH) zfU1cp3dQphqub29-l6^U6mh>^IQ^wv>A _1i5;kj=st& zML&juNzP6KtZ5)3LYIf;X{@Z@&K*IUPe0en^f*dZ6mK;%O#6!5RFnFDDC2slZzwkP zII+#?a}FpB>@$H=@)oSOPsYZj@lM*C`?*m#lgV(z@W1{ya?pGRvh@i;=se27pw k)2kkkRsS%4qKe{+^OUfsaTtCu8uX)a+Z>c*ecR`IEvbbF*4x>jry_%li?g&u8@h za$Y TeX+0md5EoH(_dtD}|foi<>DLQLOuc%qa445M~zrLh*^tk}| zPu@K?fIkelr?RjB>K7>X(Old+x;9Y*xW`RDaqL}W pSg*YV=%>RiB}512HmSC z{kge)be}A!ePe_$TH>HVn6(v^zxd;XqT=-{15fL{TPp}B&ii~Z{3Q{xkGGDNa`+6; z^VkS{(lD23GzL|xLsk7{&Ab-O^x_9aL(*dJMaQbd^WVG~grimSW3q>;wztzh`NM#5 zOb!CxP^zdGpWkkm$fB!K%0hSepBs6; IShiKk4wf94GAzD-pUIVEzQ z1%A3KhCOsUe%Ng=4?FVIOU>y!xIkHt)FxN~d-aX0o1O0-^4a!kj}+QAn0?7nfTq2^ zw&h$GAS)Hc`vF;%1#-bU?g>=%chEJ2H{c{xnIeXD?_^M1T^7=toyy+FU*_Nb3<_am z)Am?S62CZECGTn8y0q?JL{4f~F0S^ s zv7l?fk*99AtV#W5INe{H-8VdK^}Rf&+QL7e?2`G)T28&twGpNoxc1kajX=v4qWs}x zv03E|&K3F}rFY@wY@(jcnW2F}NU=Cx9uy82z|2^FE)pyet&__G_b}+uU)aC&ssQOJ zzF_`p3Ir>^))Io4bkRHhqr?+d3zA7MXB}_5oFdjof+!pUr`fYMM|Vne{cguooU6Z) zefb`BVmD!1KW6 ANyXiTMAE6#=_{)BKv;H&4DKnB6d z3w2JO6JAY*Wi>>Yfv|^QD&(DCg|iBXX&|PY`a5xI=0g5m=)JpV8zHSgfAi-^=p%gF zkwA$IjAyM`5(dOB=2f%p9nn<~Jm?|*93<;+9{dVC5kw$F60nDnBzFVnJS!Soau z6nLiN$J(4YGYdY_A3rCsVZ5DHKbW*W&Ph%k{PTgz#o$iV)HU}AN|uD?E>S$>T_X4+ z3&}v4BJq$>H2&UD`)D3J`_3b#ljVaHv2 =*XzF6&Fd8(*V1nl^$-r z{ZWYd+=UoB7b#Fdk?{D7iAHP9h!*vvL@zA*&++lPjJ< E1#-tD30S(O% zpS7;M2`FoM>YLX;9!H6XCMqBqK}g?jMrMZr)YJjvjx~m*4ch2r`C 303AAih6>CD zug@z08R-_dW)oYz&q`9g+SOqpdDs$PwNmnJrG!z588R#)MFFwW3+_N-ah#ofFcxt? zJSxvJz6%GvRoT$R0Ta |%I+GR9iqVWI;+#p{RG zNlf#APIdBQR#N&ODmOheBugWtHT&2WkaTJQl;w@XJ1n!8a2`7*&LQsKl-!x9i<(l7 zhqyF@s|?Vg^prdhYQ<7gd-@T0a}(hOlzk@G@s0t{QcT$jfO*75gL!qJ9ZFAp6 +Pa-2sL4Ni99o z@?ip}7LokQ(C|0nlYo}{nLGMXye58OvBr*X6&rcJig9cQA_ToMzkN4#^)GO&?!TrI zqR!BJ!rR8I&vA(BF#|Q %$7GWNLnb>aY`h438PA751ON9p2oC>KZIH>b3aQLAKq<0l9sh;1 z2TWSue}0+kBaqvoQ+)eGn9{tUI#r>yZMkJ2Nh{%@g#M()-pQ@G{v*A+VAWv@t%K`t zD*0IgMgB}e9udC)_jiXVo3q8q!HkJrLs@Vy2U7&UqRmkKqMm;x7_Hyna)aeg1f4tN zb(zK7yOzzB#N+@VB~*9~f|@y9o2lqQ^sn1p|`!@9e@l8_GI#XNIy zIm8c3 2T~uIvz5&R*brb